diff --git a/local/recipes/libs/cairo/recipe.toml b/local/recipes/libs/cairo/recipe.toml index 5dc76add5a..1bcff13fcc 100644 --- a/local/recipes/libs/cairo/recipe.toml +++ b/local/recipes/libs/cairo/recipe.toml @@ -3,9 +3,14 @@ name = "cairo" version = "1.18.4" [source] -tar = "https://www.cairographics.org/releases/cairo-1.18.4.tar.xz" -blake3 = "b9fa14e02f85ec4e72396c62236c98502d04dbbdf8daf01ab9557a1c7aa7106e" -patches = ["redox.patch"] +# Vendored local fork (full-fork model): builds from the committed source/ +# tree (offline, reproducible). source/ = pristine upstream + the patches below +# BAKED IN. .patch files kept tracked so a version bump can re-apply them via +# sync-recipe-source.sh. +# upstream: https://www.cairographics.org/releases/cairo-1.18.4.tar.xz +# blake3: b9fa14e02f85ec4e72396c62236c98502d04dbbdf8daf01ab9557a1c7aa7106e +# patch (baked): redox.patch +path = "source" [build] dependencies = [ diff --git a/local/recipes/libs/cairo/source.tar b/local/recipes/libs/cairo/source.tar new file mode 100644 index 0000000000..4a31803c0b Binary files /dev/null and b/local/recipes/libs/cairo/source.tar differ diff --git a/local/recipes/libs/cairo/source/.gitignore b/local/recipes/libs/cairo/source/.gitignore new file mode 100644 index 0000000000..794b542e2c --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitignore @@ -0,0 +1,41 @@ +.deps +.libs +.perf +.idea +cairo-*.*.* +manual-*.*.* +ChangeLog* +Makefile +Makefile.in +aclocal.m4 +autom4te.cache +confdefs.h +config.cache +config.h +config.h.in +config.status +configure +configure.scan +conftest.c +conftest.err +conftest.i +doltcompile +doltlibtool +gtk-doc.make +libtool +releases +stamp-h +stamp-h1 +stamp-h.in +compile_commands.json +*~ +.*.sw? +*.la +*.lo +*.log +*.orig +*.rej +*-uninstalled.pc +.vimrc +gtk-doc.m4 +/builddir diff --git a/local/recipes/libs/cairo/source/.gitlab-ci.yml b/local/recipes/libs/cairo/source/.gitlab-ci.yml new file mode 100644 index 0000000000..3c26742a96 --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci.yml @@ -0,0 +1,537 @@ +# -*- indent-tabs-mode: nil -*- +include: + - template: 'Workflows/Branch-Pipelines.gitlab-ci.yml' + - project: 'freedesktop/ci-templates' + ref: '98b1218f146a1ec96d65e3ce0041f9a6ec5cb5e6' + file: '/templates/fedora.yml' + +# From https://gitlab.freedesktop.org/freedesktop/ci-templates/-/blob/master/src/gitlab-ci.tmpl +workflow: + rules: + - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' + - if: '$CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS' + when: never + - if: $CI_COMMIT_BRANCH + +variables: + FDO_UPSTREAM_REPO: 'cairo/cairo' + FDO_DISTRIBUTION_VERSION: '40' + FDO_DISTRIBUTION_TAG: '2024-07-26-coverage.0' + + # TODO: should probably get its own image at some point instead of reusing the GStreamer one + # See https://gitlab.freedesktop.org/gstreamer/gstreamer/-/blob/main/.gitlab-image-tags.yml for latest + # (This one is from the lastest stable branch since it's likely to stay around unchanged for longer) + WINDOWS_IMAGE: "registry.freedesktop.org/gstreamer/gstreamer/amd64/windows:2024-03-05.0-1.24" + + DEFAULT_MESON_ARGS: > + --default-library=both + + RUST_STABLE: "1.80.0" + RUSTUP_VERSION: "1.27.1" + +stages: + - prep + - build + - test + - analysis + - deploy + +# Global CI policy: This can be used to configure global behaviour our our jobs +default: + retry: + max: 2 + when: + - 'runner_system_failure' + - 'stuck_or_timeout_failure' + - 'scheduler_failure' + - 'api_failure' + interruptible: true + +.ccache_setup: + variables: + CCACHE_BASEDIR: "$CI_PROJECT_DIR" + CCACHE_DIR: "$CI_PROJECT_DIR/ccache" + CC: "ccache gcc" + CXX: "ccache g++" + before_script: + - mkdir -p ccache + - ccache --show-stats + cache: + # Each job will have it's own cache + key: "$CI_JOB_NAME" + paths: + - ccache/ + +fedora image: + extends: + - '.fdo.container-build@fedora' + stage: 'prep' + variables: + FDO_DISTRIBUTION_PACKAGES: > + meson + ninja-build + ccache + gcc + g++ + zlib-devel + expat-devel + libpng-devel + fontconfig-devel + freetype-devel + libX11-devel + libXrender-devel + glib2-devel + librsvg2-devel + gtk2-devel + poppler-glib-devel + libspectre-devel + ghostscript + pixman-devel + systemd-devel + systemd-udev + expat-devel + which + diffutils + xorg-x11-server-Xvfb + dejavu-sans-fonts + dejavu-sans-mono-fonts + dejavu-serif-fonts + google-noto-emoji-color-fonts + google-noto-sans-vf-fonts + fonttools + util-linux + poppler-utils + clang + clang-analyzer + clang-tools-extra + compiler-rt + libasan + libubsan + llvm + wget + FDO_DISTRIBUTION_EXEC: >- + bash .gitlab-ci/install-rust.sh --rustup-version ${RUSTUP_VERSION} \ + --stable ${RUST_STABLE} \ + --arch x86_64-unknown-linux-gnu && + bash .gitlab-ci/install-rust-tools.sh && + bash .gitlab-ci/install-grcov.sh && + rm -rf /root/.cargo /root/.cache # cleanup compilation dirs; binaries are installed now + +.build fedora: + extends: + - '.fdo.distribution-image@fedora' + - '.ccache_setup' + stage: 'build' + variables: + MESON_ARGS: > + ${DEFAULT_MESON_ARGS} + ${EXTRA_MESON_ARGS} + --werror + CFLAGS: '-Wno-error=deprecated-declarations' + script: + - meson setup ${MESON_ARGS} builddir + - meson compile -C builddir + + # Run test scripts + - mkdir builddir/src/.libs + - touch builddir/src/.libs/libfoo.so + # Run all the tests, except for the big test executable which + # gets run separately + - meson test -C builddir --no-suite=slow --print-errorlogs + + - meson install -C builddir + artifacts: + expire_in: "7 days" + when: "always" + paths: + - "*" + +fedora build shared: + extends: + - '.build fedora' + variables: + EXTRA_MESON_ARGS: '--default-library=shared' + +fedora build static: + extends: + - '.build fedora' + variables: + EXTRA_MESON_ARGS: '--default-library=static' + +fedora build clang: + extends: + - '.build fedora' + variables: + EXTRA_MESON_ARGS: '--default-library=shared' + script: + - export CC=clang + - meson setup ${MESON_ARGS} builddir + - meson compile -C builddir + +.test fedora: + dependencies: + - 'fedora build shared' + needs: + - 'fedora build shared' + extends: + - '.fdo.distribution-image@fedora' + - '.ccache_setup' + stage: 'test' + artifacts: + when: 'always' + expire_in: "7 days" + paths: + - builddir/meson-logs/* + - builddir/test/*.log + - builddir/test/pdiff/*.log + - builddir/test/output + exclude: + - "builddir/test/**/*.cs" + - "builddir/test/**/*.trace" + +fedora build check-refs.sh: + extends: '.test fedora' + script: + # Check for duplicate reference images + - ./test/check-refs.sh "$(pwd)/builddir/test/pdiff/perceptualdiff" + +test fedora pdf: + extends: '.test fedora' + script: + - export CAIRO_TEST_IGNORE_pdf_argb32=$(tr '\n' ',' < .gitlab-ci/ignore-pdf-argb32.txt) + - export CAIRO_TEST_IGNORE_pdf_rgb24=$(tr '\n' ',' < .gitlab-ci/ignore-pdf-rgb24.txt) + - export CAIRO_TEST_TARGET=pdf + - export srcdir=../../test + - (cd builddir/test && xvfb-run ./cairo-test-suite) + +test fedora ps2: + extends: '.test fedora' + script: + - export CAIRO_TEST_IGNORE_ps2_argb32=$(tr '\n' ',' < .gitlab-ci/ignore-ps2-argb32.txt) + - export CAIRO_TEST_IGNORE_ps2_rgb24=$(tr '\n' ',' < .gitlab-ci/ignore-ps2-rgb24.txt) + - export CAIRO_TEST_TARGET=ps2 + - export CAIRO_TEST_UGLY_HACK_TO_IGNORE_PS_FAILURES=1 + - export srcdir=../../test + - (cd builddir/test && xvfb-run ./cairo-test-suite) + +test fedora ps3: + extends: '.test fedora' + script: + - export CAIRO_TEST_IGNORE_ps3_argb32=$(tr '\n' ',' < .gitlab-ci/ignore-ps3-argb32.txt) + - export CAIRO_TEST_IGNORE_ps3_rgb24=$(tr '\n' ',' < .gitlab-ci/ignore-ps3-rgb24.txt) + - export CAIRO_TEST_TARGET=ps3 + - export CAIRO_TEST_UGLY_HACK_TO_IGNORE_PS_FAILURES=1 + - export srcdir=../../test + - (cd builddir/test && xvfb-run ./cairo-test-suite) + +test fedora script: + extends: '.test fedora' + script: + - export CAIRO_TEST_UGLY_HACK_TO_SOMETIMES_IGNORE_SCRIPT_XCB_HUGE_IMAGE_SHM=1 + - export CAIRO_TEST_IGNORE_script_argb32=$(tr '\n' ',' < .gitlab-ci/ignore-script-argb32.txt) + - export CAIRO_TEST_TARGET=script + - export srcdir=../../test + - (cd builddir/test && xvfb-run ./cairo-test-suite) + +test fedora image: + extends: '.test fedora' + script: + - export CAIRO_TEST_IGNORE_image_argb32=$(tr '\n' ',' < .gitlab-ci/ignore-image-argb32.txt) + - export CAIRO_TEST_IGNORE_image_rgb24=$(tr '\n' ',' < .gitlab-ci/ignore-image-rgb24.txt) + - export CAIRO_TEST_IGNORE_image16_rgb24=$(tr '\n' ',' < .gitlab-ci/ignore-image16-rgb24.txt) + - export CAIRO_TEST_TARGET=image,image16 + - export srcdir=../../test + - (cd builddir/test && xvfb-run ./cairo-test-suite) + +test fedora recording: + extends: '.test fedora' + script: + - export CAIRO_TEST_IGNORE_recording_argb32=$(tr '\n' ',' < .gitlab-ci/ignore-recording-argb32.txt) + - export CAIRO_TEST_IGNORE_recording_rgb24=$(tr '\n' ',' < .gitlab-ci/ignore-recording-rgb24.txt) + - export CAIRO_TEST_TARGET=recording + - export srcdir=../../test + - (cd builddir/test && xvfb-run ./cairo-test-suite) + +test fedora svg: + extends: '.test fedora' + script: + - export CAIRO_TEST_IGNORE_svg11_argb32=$(tr '\n' ',' < .gitlab-ci/ignore-svg11-argb32.txt) + - export CAIRO_TEST_IGNORE_svg11_rgb24=$(tr '\n' ',' < .gitlab-ci/ignore-svg11-rgb24.txt) + - export CAIRO_TEST_TARGET=svg11 + - export CAIRO_BOILERPLATE_OPEN_NO_DAEMON=1 + - export CAIRO_BOILERPLATE_DO_NOT_CRASH_ON_ANY2PPM_ERROR=1 + - export ANY2PPM="timeout 3m ./any2ppm" + - ulimit -S -s 131072 + - export srcdir=../../test + - (cd builddir/test && xvfb-run ./cairo-test-suite) + +test fedora xcb: + extends: '.test fedora' + script: + - export CAIRO_TEST_IGNORE_xcb_argb32=$(tr '\n' ',' < .gitlab-ci/ignore-xcb-argb32.txt) + - export CAIRO_TEST_IGNORE_xcb_rgb24=$(tr '\n' ',' < .gitlab-ci/ignore-xcb-rgb24.txt) + - export CAIRO_TEST_IGNORE_xcb_window_rgb24=$(tr '\n' ',' < .gitlab-ci/ignore-xcb-window-rgb24.txt) + - export CAIRO_TEST_IGNORE_xcb_window__rgb24=$(tr '\n' ',' < '.gitlab-ci/ignore-xcb-window&-rgb24.txt') + - export CAIRO_TEST_IGNORE_xcb_render_0_0_argb32=$(tr '\n' ',' < .gitlab-ci/ignore-xcb-render-0-0-argb32.txt) + - export CAIRO_TEST_IGNORE_xcb_render_0_0_rgb24=$(tr '\n' ',' < .gitlab-ci/ignore-xcb-render-0-0-rgb24.txt) + - export CAIRO_TEST_IGNORE_xcb_fallback_rgb24=$(tr '\n' ',' < .gitlab-ci/ignore-xcb-fallback-rgb24.txt) + - export CAIRO_TEST_TARGET="xcb,xcb-window,xcb-window&,xcb-render-0_0,xcb-fallback" + - export srcdir=../../test + - (cd builddir/test && xvfb-run ./cairo-test-suite) + +test fedora xlib: + extends: '.test fedora' + script: + - export CAIRO_TEST_IGNORE_xlib_argb32=$(tr '\n' ',' < .gitlab-ci/ignore-xlib-argb32.txt) + - export CAIRO_TEST_IGNORE_xlib_rgb24=$(tr '\n' ',' < .gitlab-ci/ignore-xlib-rgb24.txt) + - export CAIRO_TEST_IGNORE_xlib_window_rgb24=$(tr '\n' ',' < .gitlab-ci/ignore-xlib-window-rgb24.txt) + - export CAIRO_TEST_IGNORE_xlib_render_0_0_rgb24=$(tr '\n' ',' < .gitlab-ci/ignore-xlib-render-0-0-rgb24.txt) + - export CAIRO_TEST_IGNORE_xlib_fallback_rgb24=$(tr '\n' ',' < .gitlab-ci/ignore-xlib-fallback-rgb24.txt) + - export CAIRO_TEST_TARGET="xlib,xlib-window,xlib-render-0_0,xlib-fallback" + - export srcdir=../../test + - (cd builddir/test && xvfb-run ./cairo-test-suite) + +mingw-32 build: + extends: + - '.fdo.distribution-image@fedora' + stage: 'build' + before_script: + - dnf install -y 'dnf-command(builddep)' + - dnf builddep -y mingw32-cairo + - dnf install -y mingw32-gcc-c++ + script: + - mkdir builddir + - cd builddir + # Test building with FreeType enabled and Fontconfig disabled + - mingw32-meson --default-library=both -Dfontconfig=disabled + - ninja install + artifacts: + expire_in: "7 days" + when: "always" + paths: + - 'builddir/meson-logs/' + +mingw-64 build: + extends: + - '.fdo.distribution-image@fedora' + stage: 'build' + before_script: + - dnf install -y 'dnf-command(builddep)' + - dnf builddep -y mingw64-cairo + - dnf install -y mingw64-gcc-c++ + script: + - mkdir builddir + - cd builddir + - mingw64-meson --default-library=both + - ninja install + artifacts: + expire_in: "7 days" + when: "always" + paths: + - 'builddir/meson-logs/' + +# Based on https://gitlab.freedesktop.org/gstreamer/gstreamer/-/blob/main/.gitlab-ci.yml (.build windows) +.build windows: + image: $WINDOWS_IMAGE + stage: 'build' + tags: + - 'docker' + - 'windows' + - '2022' + timeout: '30min' + variables: + MESON_ARGS: > + ${DEFAULT_MESON_ARGS} + -Dfontconfig=enabled + -Dfreetype=enabled + -Dglib=enabled + -Dzlib=enabled + ${EXTRA_MESON_ARGS} + before_script: + # Make sure meson is up to date, latest fontconfig requires a newer Meson than what's on the image + - pip3 install -U meson + script: + # Make sure powershell exists on errors + # https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_preference_variables?view=powershell-6 + - $ErrorActionPreference = "Stop" + + # Copy GLib from existing subproject cache to avoid downloading it + # FIXME: no longer cached in GStreamer image, using tarball for now + #- cd $env:CI_PROJECT_DIR + #- cp -r C:/subprojects/glib subprojects/ + + # For some reason, options are separated by newline instead of space, so we + # have to replace them first. + - $env:MESON_ARGS = $env:MESON_ARGS.replace("`n"," ") + + # Gitlab executes PowerShell in docker, but VsDevCmd.bat is a batch script. + # Environment variables substitutions is done by PowerShell before calling + # cmd.exe, that's why we use $env:FOO instead of %FOO% + - cmd.exe /C "C:\BuildTools\Common7\Tools\VsDevCmd.bat -host_arch=amd64 -arch=$env:ARCH && + meson subprojects update --reset && + meson build $env:MESON_ARGS && + ninja -C build" + artifacts: + expire_in: "7 days" + when: "always" + paths: + - 'build/meson-logs/' + +vs2019 shared amd64: + extends: '.build windows' + variables: + ARCH: 'amd64' + EXTRA_MESON_ARGS: '--default-library=shared' + +vs2019 static amd64: + extends: '.build windows' + variables: + ARCH: 'amd64' + EXTRA_MESON_ARGS: '--default-library=static' + +vs2019 shared x86: + extends: '.build windows' + variables: + ARCH: 'x86' + EXTRA_MESON_ARGS: '--default-library=shared' + +android arm64 fedora: + # TODO: should probably build our own image here some day + # See https://gitlab.freedesktop.org/gstreamer/gstreamer/container_registry/7689 for current images + image: 'registry.freedesktop.org/gstreamer/gstreamer/amd64/android-fedora:2020-10-22.0-master' + stage: 'build' + artifacts: + name: "${CI_JOB_NAME}_${CI_COMMIT_SHA}" + expire_in: '5 days' + when: 'always' + paths: + - "build/meson-logs/*.txt" + before_script: + - dnf install -y python3-pip gcc ninja-build gperf + - pip3 install --user meson + script: + - export PATH="$HOME/.local/bin:$PATH" + - | + cat > android-cross-file.txt < + --buildtype=debug + script: + - meson setup ${MESON_ARGS} _scan_build . + - ninja -C _scan_build scan-build + artifacts: + name: "cairo-${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}" + when: always + paths: + - "_scan_build/meson-logs/scanbuild" + +coverage: + stage: 'analysis' + extends: + - '.fdo.distribution-image@fedora' + needs: + - job: 'fedora image' + artifacts: false + script: + - source ./.gitlab-ci/env.sh + - bash -x ./.gitlab-ci/build-with-coverage.sh + - bash -x ./.gitlab-ci/gen-coverage.sh + coverage: '/Coverage: \d+\.\d+/' + artifacts: + name: "cairo-${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}" + expire_in: 2 days + when: always + reports: + coverage_report: + coverage_format: cobertura + path: public/coverage.xml + paths: + - "_build/meson-logs" + - public + +pages: + stage: 'deploy' + needs: + - job: coverage + script: + - mkdir -p public + - cp .gitlab-ci/pages-index.html public/index.html + artifacts: + paths: + - public + expire_in: 1 day + rules: + # Restrict to the main branch so not every branch tries to deploy the web site + - if: ($CI_DEFAULT_BRANCH == $CI_COMMIT_BRANCH) diff --git a/local/recipes/libs/cairo/source/.gitlab-ci/build-with-coverage.sh b/local/recipes/libs/cairo/source/.gitlab-ci/build-with-coverage.sh new file mode 100644 index 0000000000..ed867986d2 --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci/build-with-coverage.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +set -eux -o pipefail + +export CFLAGS="-coverage -ftest-coverage -fprofile-arcs" + +export CAIRO_TEST_IGNORE_image_argb32=$(tr '\n' ',' < .gitlab-ci/ignore-image-argb32.txt) +export CAIRO_TEST_IGNORE_image_rgb24=$(tr '\n' ',' < .gitlab-ci/ignore-image-rgb24.txt) +export CAIRO_TEST_IGNORE_image16_rgb24=$(tr '\n' ',' < .gitlab-ci/ignore-image16-rgb24.txt) +export CAIRO_TEST_TARGET=image,image16 + +meson setup --buildtype=debug _build . +meson compile -C _build + +export srcdir=../../test +cd _build/test +xvfb-run ./cairo-test-suite diff --git a/local/recipes/libs/cairo/source/.gitlab-ci/env.sh b/local/recipes/libs/cairo/source/.gitlab-ci/env.sh new file mode 100644 index 0000000000..b5761529f8 --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci/env.sh @@ -0,0 +1,2 @@ +export RUSTUP_HOME='/usr/local/rustup' +export PATH=$PATH:/usr/local/cargo/bin diff --git a/local/recipes/libs/cairo/source/.gitlab-ci/gen-coverage.sh b/local/recipes/libs/cairo/source/.gitlab-ci/gen-coverage.sh new file mode 100644 index 0000000000..cfc78e2407 --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci/gen-coverage.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +set -eux -o pipefail + +mkdir -p public +grcov _build --source-dir ./ --prefix-dir ../ --output-type cobertura --branch --ignore-not-existing -o public/coverage.xml +grcov _build --source-dir ./ --prefix-dir ../ --output-type html --branch --ignore-not-existing -o public/coverage + +# Print "Coverage: 42.42" so .gitlab-ci.yml will pick it up with a regex +# +# We scrape this from the HTML report, not the JSON summary, because coverage.json +# uses no decimal places, just something like "42%". + +grep -Eo 'abbr title.* %' public/coverage/index.html | head -n 1 | grep -Eo '[0-9.]+ %' | grep -Eo '[0-9.]+' | awk '{ print "Coverage:", $1 }' diff --git a/local/recipes/libs/cairo/source/.gitlab-ci/ignore-image-argb32.txt b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-image-argb32.txt new file mode 100644 index 0000000000..c5b96d732d --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-image-argb32.txt @@ -0,0 +1,21 @@ +clip-text +culled-glyphs +ft-show-glyphs-positioning +ft-text-vertical-layout-type1 +ft-text-vertical-layout-type3 +halo-transform +overlapping-glyphs +record1414x-select-font-face +record1414x-text-transform +show-glyphs-advance +subsurface +subsurface-scale +text-antialias-subpixel +text-antialias-subpixel-bgr +text-antialias-subpixel-rgb +text-antialias-subpixel-vbgr +text-antialias-subpixel-vrgb +text-pattern +text-rotate +text-unhinted-metrics +user-font-mask diff --git a/local/recipes/libs/cairo/source/.gitlab-ci/ignore-image-rgb24.txt b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-image-rgb24.txt new file mode 100644 index 0000000000..3c90818b90 --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-image-rgb24.txt @@ -0,0 +1,73 @@ +a1-clip-fill-rule +big-empty-box +big-empty-triangle +big-little-box +bitmap-font +bug-361 +bug-431 +bug-source-cu +clip-device-offset +clip-fill-rule-pixel-aligned +clip-text +culled-glyphs +dash-zero-length +degenerate-path +device-offset +device-offset-positive +extended-blend-alpha-mask +fill-and-stroke +fill-empty +fill-missed-stop +finer-grained-fallbacks +ft-color-font +ft-show-glyphs-positioning +ft-text-vertical-layout-type1 +ft-text-vertical-layout-type3 +gradient-alpha +gradient-constant-alpha +gradient-zero-stops +gradient-zero-stops-mask +halo-transform +image-surface-source +linear-gradient-one-stop +mask-ctm +mask-surface-ctm +new-sub-path +nil-surface +overlapping-boxes +overlapping-glyphs +pass-through +pdf-surface-source +pixman-downscale-best-24 +pixman-rotate +ps-surface-source +radial-gradient-source +record1414x-select-font-face +record1414x-text-transform +record-neg-extents-bounded +record-neg-extents-unbounded +record-replay-extend-none +record-replay-extend-pad +record-replay-extend-reflect +record-replay-extend-repeat +rel-path +scale-source-surface-paint +set-source +shifted-operator +show-glyphs-advance +source-surface-scale-paint +subsurface +subsurface-outside-target +subsurface-scale +text-antialias-subpixel +text-antialias-subpixel-bgr +text-antialias-subpixel-rgb +text-antialias-subpixel-vbgr +text-antialias-subpixel-vrgb +text-pattern +text-rotate +text-unhinted-metrics +thin-lines +user-font-mask +xcb-surface-source +xlib-surface-source diff --git a/local/recipes/libs/cairo/source/.gitlab-ci/ignore-image16-rgb24.txt b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-image16-rgb24.txt new file mode 100644 index 0000000000..418275a30b --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-image16-rgb24.txt @@ -0,0 +1,283 @@ +a1-bug +a1-clip-fill-rule +a1-tiger +aliasing +arc-direction +arc-looping-dash +big-empty-box +big-empty-triangle +big-line +big-little-box +bitmap-font +bug-84115 +bug-bo-ricotz +bug-extents +bug-image-compositor +bug-seams +bug-source-cu +bug-spline +caps +caps-05 +caps-2 +caps-joins-2 +caps-joins-alpha +caps-joins-curve +caps-tails-curve +clear-source +clip-device-offset +clip-disjoint +clip-disjoint-quad +clip-fill +clip-fill-eo-unbounded +clip-fill-nz-unbounded +clip-fill-rule-pixel-aligned +clip-image +clip-intersect +clip-operator +clip-push-group +clip-shape +clip-stroke +clip-stroke-unbounded +clip-text +clip-twice +close-path-current-point +copy-path +coverage-abutting +coverage-column-triangles +coverage-intersecting-quads +coverage-intersecting-triangles +coverage-rectangles +coverage-rhombus +coverage-row-triangles +coverage-triangles +culled-glyphs +dash-caps-joins +dash-curve +dash-scale +dash-state +dash-zero-length +degenerate-arc +degenerate-curve-to +degenerate-path +degenerate-pen +degenerate-rel-curve-to +device-offset +device-offset-positive +drunkard-tails +extended-blend +extended-blend-alpha +extended-blend-alpha-mask +extended-blend-mask +extended-blend-solid +extended-blend-solid-alpha +extend-pad-border +fallback +fill-alpha +fill-alpha-pattern +fill-and-stroke +fill-and-stroke-alpha +fill-and-stroke-alpha-add +fill-degenerate-sort-order +fill-empty +fill-image +fill-missed-stop +fill-rule +filter-bilinear-extents +finer-grained-fallbacks +font-matrix-translation +ft-show-glyphs-positioning +ft-show-glyphs-table +ft-text-vertical-layout-type1 +ft-text-vertical-layout-type3 +glyph-cache-pressure +gradient-alpha +gradient-constant-alpha +gradient-zero-stops +gradient-zero-stops-mask +group-unaligned +halo +halo-transform +hatchings +huge-linear +huge-radial +inverse-text +joins +joins-loop +joins-retrace +joins-star +large-font +large-twin-antialias-mixed +leaky-dashed-stroke +linear-gradient +linear-gradient-one-stop +linear-gradient-reflect +linear-gradient-subset +line-width-overlap-offset +line-width-scale +long-dashed-lines +mask +mask-alpha +mask-ctm +mask-surface-ctm +mask-transformed-image +mask-transformed-similar +mesh-pattern +mesh-pattern-conical +mesh-pattern-control-points +mesh-pattern-fold +mesh-pattern-overlap +mesh-pattern-transformed +new-sub-path +nil-surface +operator-source +over-around-source +overlapping-boxes +overlapping-dash-caps +overlapping-glyphs +paint-source-alpha +paint-with-alpha +paint-with-alpha-clip +paint-with-alpha-clip-mask +partial-coverage-reference +partial-coverage-three-quarter-reference +pass-through +path-append +path-stroke-twice +pdf-isolated-group +pixman-downscale-best-24 +pixman-downscale-best-96 +pixman-downscale-bilinear-96 +pixman-downscale-fast-96 +pixman-downscale-good-96 +pixman-downscale-nearest-96 +pixman-rotate +pthread-same-source +pthread-show-text +push-group +push-group-color +radial-gradient +radial-gradient-mask +radial-gradient-mask-source +radial-gradient-source +random-clip +random-intersections-curves-eo +random-intersections-curves-nz +random-intersections-eo +random-intersections-nonzero +raster-source +record1414x-fill-alpha +record1414x-paint-alpha +record1414x-paint-alpha-clip +record1414x-paint-alpha-clip-mask +record1414x-select-font-face +record1414x-text-transform +record2x-fill-alpha +record2x-paint-alpha +record2x-paint-alpha-clip +record2x-paint-alpha-clip-mask +record2x-select-font-face +record2x-text-transform +record90-fill-alpha +record90-paint-alpha +record90-paint-alpha-clip +record90-paint-alpha-clip-mask +record90-select-font-face +record90-text-transform +record-fill-alpha +recordflip-fill-alpha +recordflip-paint-alpha +recordflip-paint-alpha-clip +recordflip-paint-alpha-clip-mask +recordflip-select-font-face +recordflip-text-transform +recordflip-whole-fill-alpha +recordflip-whole-paint-alpha +recordflip-whole-paint-alpha-clip +recordflip-whole-paint-alpha-clip-mask +recordflip-whole-select-font-face +recordflip-whole-text-transform +recording-surface-extend-none +recording-surface-extend-reflect +recording-surface-extend-repeat +recording-surface-over +recording-surface-source +record-mesh +record-neg-extents-bounded +record-neg-extents-unbounded +record-paint-alpha +record-paint-alpha-clip +record-paint-alpha-clip-mask +record-replay-extend-none +record-replay-extend-pad +record-replay-extend-reflect +record-replay-extend-repeat +record-select-font-face +record-text-transform +rectilinear-dash-scale-unaligned +reflected-stroke +rel-path +rotate-clip-image-surface-paint +rotated-clip +rounded-rectangle-fill +rounded-rectangle-stroke +scale-offset-image +scale-offset-similar +scale-source-surface-paint +select-font-face +set-source +shape-general-convex +shape-sierpinski +shifted-operator +show-glyphs-advance +show-text-current-point +simple-edge +smask +smask-fill +smask-mask +smask-paint +smask-stroke +smask-text +source-surface-scale-paint +spline-decomposition +stroke-ctm-caps +stroke-image +stroke-pattern +subsurface +subsurface-outside-target +subsurface-scale +surface-pattern +surface-pattern-operator +surface-pattern-scale-down +surface-pattern-scale-up +text-antialias-gray +text-antialias-subpixel +text-antialias-subpixel-bgr +text-antialias-subpixel-rgb +text-antialias-subpixel-vbgr +text-antialias-subpixel-vrgb +text-glyph-range +text-pattern +text-rotate +text-transform +text-unhinted-metrics +thin-lines +tiger +tighten-bounds +transforms +trap-clip +twin +twin-antialias-gray +twin-antialias-mixed +twin-antialias-subpixel +unbounded-operator +unclosed-strokes +user-font +user-font-mask +user-font-proxy +user-font-rescale +world-map +world-map-fill +world-map-stroke +xcb-huge-image-shm +xcb-huge-subimage +xcomposite-projection diff --git a/local/recipes/libs/cairo/source/.gitlab-ci/ignore-pdf-argb32.txt b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-pdf-argb32.txt new file mode 100644 index 0000000000..b3be4e9aea --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-pdf-argb32.txt @@ -0,0 +1,49 @@ +bug-image-compositor +clear-source +clip-operator +clip-text +culled-glyphs +extended-blend +extended-blend-solid +fallback +filter-bilinear-extents +filter-nearest-offset +filter-nearest-transformed +ft-show-glyphs-positioning +ft-text-vertical-layout-type1 +ft-text-vertical-layout-type3 +halo-transform +huge-linear +huge-radial +linear-gradient-reflect +mask +overlapping-glyphs +pixman-downscale-best-95 +pixman-downscale-fast-95 +pixman-downscale-nearest-95 +pthread-same-source +pthread-show-text +radial-gradient +radial-gradient-mask +radial-gradient-mask-source +radial-gradient-one-stop +radial-gradient-source +record1414x-select-font-face +record1414x-text-transform +record2x-text-transform +record-replay-extend-reflect +rectilinear-dash +rectilinear-stroke +rotate-clip-image-surface-paint +rotate-image-surface-paint +show-glyphs-advance +smask-text +surface-pattern +surface-pattern-operator +surface-pattern-scale-down +text-pattern +text-rotate +text-unhinted-metrics +thin-lines +twin +user-font-rescale diff --git a/local/recipes/libs/cairo/source/.gitlab-ci/ignore-pdf-rgb24.txt b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-pdf-rgb24.txt new file mode 100644 index 0000000000..d0e31a95d5 --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-pdf-rgb24.txt @@ -0,0 +1,88 @@ +big-empty-box +big-empty-triangle +big-little-box +bitmap-font +bug-361 +bug-image-compositor +clear-source +clip-device-offset +clip-fill-rule-pixel-aligned +clip-text +culled-glyphs +device-offset +device-offset-positive +extended-blend-alpha-mask +fill-empty +filter-bilinear-extents +filter-nearest-offset +filter-nearest-transformed +ft-color-font +ft-show-glyphs-positioning +ft-text-vertical-layout-type1 +ft-text-vertical-layout-type3 +gradient-zero-stops +gradient-zero-stops-mask +halo-transform +huge-linear +huge-radial +image-surface-source +linear-gradient-one-stop +linear-gradient-reflect +mask +mask-ctm +mask-surface-ctm +nil-surface +overlapping-boxes +overlapping-glyphs +pass-through +pdf-surface-source +pixman-downscale-best-95 +pixman-downscale-fast-95 +pixman-downscale-nearest-95 +pixman-rotate +ps-surface-source +pthread-same-source +pthread-show-text +radial-gradient +radial-gradient-mask +radial-gradient-mask-source +radial-gradient-one-stop +radial-gradient-source +random-intersections-curves-eo +random-intersections-curves-nz +record1414x-paint-alpha +record1414x-paint-alpha-clip +record1414x-paint-alpha-clip-mask +record1414x-select-font-face +record1414x-text-transform +record2x-paint-alpha-clip-mask +record2x-select-font-face +record2x-text-transform +record90-paint-alpha-clip +record90-select-font-face +recordflip-select-font-face +recordflip-whole-select-font-face +recordflip-whole-self-intersecting +recordflip-whole-text-transform +record-paint-alpha-clip +record-replay-extend-pad +record-select-font-face +rectilinear-dash +rectilinear-stroke +rel-path +rotate-clip-image-surface-paint +rotate-image-surface-paint +set-source +show-glyphs-advance +smask-text +source-surface-scale-paint +surface-pattern +surface-pattern-scale-down +text-pattern +text-rotate +text-unhinted-metrics +thin-lines +twin +user-font-rescale +xcb-surface-source +xlib-surface-source diff --git a/local/recipes/libs/cairo/source/.gitlab-ci/ignore-ps2-argb32.txt b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-ps2-argb32.txt new file mode 100644 index 0000000000..75c599fc40 --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-ps2-argb32.txt @@ -0,0 +1,207 @@ +arc-direction +arc-looping-dash +bug-448 +bug-51910 +bug-bo-ricotz +bug-extents +bug-spline +caps +caps-05 +caps-1 +caps-2 +caps-joins +caps-joins-05 +caps-joins-1 +caps-joins-2 +caps-joins-curve +caps-sub-paths +caps-tails-curve +clear-source +clip-complex-bug61592 +clip-disjoint +clip-fill +clip-fill-rule +clip-group-shapes-circles +clip-image +clip-nesting +clip-push-group +clip-rotate-image-surface-paint +clip-shape +clip-stroke +clip-text +clip-twice +clip-unbounded +close-path +close-path-current-point +copy-path +culled-glyphs +curve-to-as-line-to +dash-caps-joins +dash-curve +dash-infinite-loop +dash-no-dash +dash-offset +dash-offset-negative +dash-scale +dash-state +dash-zero-length +degenerate-arc +degenerate-curve-to +degenerate-dash +degenerate-path +degenerate-pen +degenerate-rel-curve-to +degenerate-solid-dash +drunkard-tails +extend-reflect +extend-reflect-similar +extended-blend +extended-blend-alpha-mask +extended-blend-solid +fallback +fill-and-stroke +fill-degenerate-sort-order +fill-image +fill-rule +filter-nearest-offset +finer-grained-fallbacks +font-matrix-translation +ft-color-font +ft-text-vertical-layout-type1 +ft-text-vertical-layout-type3 +group-unaligned +hairline +hairline-anisotropic +hairline-anisotropic-incorrect +hairline-big +hairline-scaled +halo +halo-transform +horizontal-clip +inverse-text +joins +joins-loop +joins-retrace +joins-star +large-font +leaky-dash +leaky-dashed-rectangle +leaky-dashed-stroke +leaky-polygon +line-width +line-width-large-overlap-dashed +line-width-overlap +line-width-overlap-dashed +line-width-overlap-flipped +line-width-overlap-flopped +line-width-overlap-offset +line-width-scale +line-width-tolerance +long-dashed-lines +miter-precision +new-sub-path +operator-www +over-above-source +over-around-source +over-below-source +over-between-source +overlapping-glyphs +path-append +path-stroke-twice +pixman-downscale-fast-95 +pixman-downscale-nearest-95 +pixman-rotate +pthread-same-source +radial-gradient +radial-gradient-mask +radial-gradient-mask-source +random-clip +random-intersections-curves-eo +random-intersections-curves-nz +random-intersections-eo +random-intersections-nonzero +record-extend-reflect +record-neg-extents-bounded +record-neg-extents-unbounded +record-replay-extend-reflect +record-replay-extend-repeat +record-select-font-face +record-self-intersecting +record-text-transform +record1414x-fill-alpha +record1414x-select-font-face +record1414x-self-intersecting +record1414x-text-transform +record2x-select-font-face +record2x-self-intersecting +record2x-text-transform +record90-select-font-face +record90-self-intersecting +record90-text-transform +recordflip-select-font-face +recordflip-self-intersecting +recordflip-text-transform +recordflip-whole-select-font-face +recordflip-whole-self-intersecting +recordflip-whole-text-transform +rectilinear-dash +rectilinear-dash-scale +rectilinear-dash-scale-unaligned +rectilinear-grid +rectilinear-miter-limit +rectilinear-stroke +reflected-stroke +rotate-clip-image-surface-paint +rotate-image-surface-paint +rotate-stroke-box +rotated-clip +round-join-bug-520-bevel +round-join-bug-520-round +rounded-rectangle-fill +rounded-rectangle-stroke +scale-offset-image +scale-offset-similar +self-copy-overlap +stroke-ctm-caps +stroke-clipped +stroke-image +stroke-open-box +select-font-face +self-copy-overlap +self-intersecting +shape-general-convex +shape-sierpinski +show-glyphs-advance +show-text-current-point +smask +smask-text +smp-glyph +spline-decomposition +stroke-clipped +stroke-ctm-caps +stroke-image +stroke-open-box +surface-pattern +surface-pattern-scale-down +surface-pattern-scale-down-extend-reflect +surface-pattern-scale-up +text-glyph-range +text-pattern +text-rotate +text-transform +text-unhinted-metrics +thin-lines +tiger +transforms +trap-clip +twin +unclosed-strokes +user-font +user-font-color +user-font-mask +user-font-proxy +user-font-rescale +user-font-subpixel +world-map +world-map-fill +world-map-stroke diff --git a/local/recipes/libs/cairo/source/.gitlab-ci/ignore-ps2-rgb24.txt b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-ps2-rgb24.txt new file mode 100644 index 0000000000..0ca0b8b45a --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-ps2-rgb24.txt @@ -0,0 +1,197 @@ +arc-direction +arc-looping-dash +bug-361 +bug-431 +bug-448 +bug-51910 +bug-bo-ricotz +bug-extents +bug-spline +caps +caps-05 +caps-1 +caps-2 +caps-joins +caps-joins-05 +caps-joins-1 +caps-joins-2 +caps-joins-curve +caps-sub-paths +caps-tails-curve +clear-source +clip-complex-bug61592 +clip-fill +clip-fill-rule +clip-group-shapes-circles +clip-image +clip-nesting +clip-push-group +clip-rotate-image-surface-paint +clip-shape +clip-stroke +clip-text +clip-twice +close-path +close-path-current-point +copy-path +culled-glyphs +curve-to-as-line-to +dash-caps-joins +dash-curve +dash-infinite-loop +dash-no-dash +dash-offset +dash-offset-negative +dash-scale +dash-state +dash-zero-length +degenerate-arc +degenerate-curve-to +degenerate-dash +degenerate-path +degenerate-pen +degenerate-rel-curve-to +degenerate-solid-dash +drunkard-tails +extend-reflect +extend-reflect-similar +extended-blend-alpha-mask +fill-and-stroke +fill-degenerate-sort-order +fill-image +fill-rule +filter-nearest-offset +font-matrix-translation +ft-color-font +ft-text-vertical-layout-type1 +ft-text-vertical-layout-type3 +gradient-constant-alpha +gradient-zero-stops +group-unaligned +hairline +hairline-anisotropic +hairline-anisotropic-incorrect +hairline-big +hairline-scaled +halo +halo-transform +horizontal-clip +image-surface-source +inverse-text +joins +joins-loop +joins-retrace +joins-star +large-font +leaky-dash +leaky-dashed-rectangle +leaky-dashed-stroke +leaky-polygon +line-width +line-width-large-overlap-dashed +line-width-overlap +line-width-overlap-dashed +line-width-overlap-flipped +line-width-overlap-flopped +line-width-overlap-offset +line-width-scale +line-width-tolerance +long-dashed-lines +miter-precision +new-sub-path +overlapping-glyphs +path-append +path-stroke-twice +pdf-surface-source +pixman-downscale-fast-95 +pixman-downscale-nearest-95 +pixman-rotate +ps-surface-source +pthread-same-source +radial-gradient-source +random-intersections-curves-eo +random-intersections-curves-nz +random-intersections-eo +random-intersections-nonzero +record-extend-reflect +record-neg-extents-bounded +record-neg-extents-unbounded +record-replay-extend-reflect +record-replay-extend-repeat +record-select-font-face +record-self-intersecting +record-text-transform +record1414x-fill-alpha +record1414x-select-font-face +record1414x-self-intersecting +record1414x-text-transform +record2x-select-font-face +record2x-self-intersecting +record2x-text-transform +record90-select-font-face +record90-self-intersecting +record90-text-transform +recordflip-select-font-face +recordflip-self-intersecting +recordflip-text-transform +recordflip-whole-select-font-face +recordflip-whole-self-intersecting +recordflip-whole-text-transform +rectilinear-dash +rectilinear-dash-scale +rectilinear-dash-scale-unaligned +rectilinear-grid +rectilinear-miter-limit +rectilinear-stroke +reflected-stroke +rel-path +rotate-clip-image-surface-paint +rotate-image-surface-paint +rotate-stroke-box +round-join-bug-520-bevel +round-join-bug-520-round +rounded-rectangle-fill +rounded-rectangle-stroke +scale-offset-image +scale-offset-similar +scale-source-surface-paint +select-font-face +self-intersecting +set-source +shape-general-convex +shape-sierpinski +show-glyphs-advance +show-text-current-point +smask +smask-text +smp-glyph +source-surface-scale-paint +spline-decomposition +stroke-clipped +stroke-ctm-caps +stroke-image +stroke-open-box +surface-pattern +surface-pattern-scale-down +surface-pattern-scale-down-extend-reflect +surface-pattern-scale-up +text-glyph-range +text-pattern +text-rotate +text-transform +text-unhinted-metrics +thin-lines +tiger +transforms +twin +unclosed-strokes +user-font +user-font-mask +user-font-proxy +user-font-rescale +user-font-subpixel +world-map +world-map-fill +world-map-stroke +xcb-surface-source +xlib-surface-source diff --git a/local/recipes/libs/cairo/source/.gitlab-ci/ignore-ps3-argb32.txt b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-ps3-argb32.txt new file mode 100644 index 0000000000..d59940c9ce --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-ps3-argb32.txt @@ -0,0 +1,216 @@ +arc-direction +arc-looping-dash +bug-448 +bug-51910 +bug-bo-ricotz +bug-extents +bug-image-compositor +bug-spline +caps +caps-05 +caps-1 +caps-2 +caps-joins +caps-joins-05 +caps-joins-1 +caps-joins-2 +caps-joins-curve +caps-sub-paths +caps-tails-curve +clear-source +clip-complex-bug61592 +clip-disjoint +clip-fill +clip-fill-rule +clip-group-shapes-circles +clip-image +clip-nesting +clip-push-group +clip-rotate-image-surface-paint +clip-shape +clip-stroke +clip-text +clip-twice +clip-unbounded +close-path +close-path-current-point +copy-path +culled-glyphs +curve-to-as-line-to +dash-caps-joins +dash-curve +dash-infinite-loop +dash-no-dash +dash-offset +dash-offset-negative +dash-scale +dash-state +dash-zero-length +degenerate-arc +degenerate-curve-to +degenerate-dash +degenerate-path +degenerate-pen +degenerate-rel-curve-to +degenerate-solid-dash +drunkard-tails +extend-reflect +extend-reflect-similar +extended-blend +extended-blend-alpha-mask +extended-blend-solid +fallback +fill-and-stroke +fill-degenerate-sort-order +fill-image +fill-rule +filter-nearest-offset +filter-nearest-transformed +finer-grained-fallbacks +font-matrix-translation +ft-text-vertical-layout-type1 +ft-text-vertical-layout-type3 +gradient-constant-alpha +group-unaligned +hairline +hairline-anisotropic +hairline-anisotropic-incorrect +hairline-big +hairline-scaled +halo +halo-transform +horizontal-clip +inverse-text +joins +joins-loop +joins-retrace +joins-star +large-font +leaky-dash +leaky-dashed-rectangle +leaky-dashed-stroke +leaky-polygon +line-width +line-width-large-overlap-dashed +line-width-overlap +line-width-overlap-dashed +line-width-overlap-flipped +line-width-overlap-flopped +line-width-overlap-offset +line-width-scale +line-width-tolerance +linear-gradient +linear-gradient-reflect +linear-gradient-subset +long-dashed-lines +mask-transformed-image +mesh-pattern-conical +mesh-pattern-control-points +mesh-pattern-fold +mesh-pattern-overlap +miter-precision +new-sub-path +operator-www +over-around-source +over-below-source +overlapping-glyphs +path-append +path-stroke-twice +pixman-downscale-fast-95 +pixman-downscale-nearest-95 +pixman-rotate +pthread-same-source +push-group-color +radial-gradient +radial-gradient-mask +radial-gradient-mask-source +radial-gradient-one-stop +random-clip +random-intersections-curves-eo +random-intersections-curves-nz +random-intersections-eo +random-intersections-nonzero +record-extend-reflect +record-neg-extents-bounded +record-neg-extents-unbounded +record-replay-extend-reflect +record-replay-extend-repeat +record-select-font-face +record-self-intersecting +record-text-transform +record1414x-fill-alpha +record1414x-select-font-face +record1414x-self-intersecting +record1414x-text-transform +record2x-select-font-face +record2x-self-intersecting +record2x-text-transform +record90-select-font-face +record90-self-intersecting +record90-text-transform +recordflip-select-font-face +recordflip-self-intersecting +recordflip-text-transform +recordflip-whole-select-font-face +recordflip-whole-self-intersecting +recordflip-whole-text-transform +rectilinear-dash +rectilinear-dash-scale +rectilinear-dash-scale-unaligned +rectilinear-grid +rectilinear-miter-limit +rectilinear-stroke +reflected-stroke +rotate-clip-image-surface-paint +rotate-image-surface-paint +rotate-stroke-box +rotated-clip +round-join-bug-520-bevel +round-join-bug-520-round +rounded-rectangle-fill +rounded-rectangle-stroke +scale-offset-image +scale-offset-similar +self-copy-overlap +stroke-ctm-caps +stroke-clipped +stroke-image +stroke-open-box +select-font-face +self-copy-overlap +self-intersecting +shape-general-convex +shape-sierpinski +show-glyphs-advance +show-text-current-point +smask +smask-text +smp-glyph +spline-decomposition +stroke-clipped +stroke-ctm-caps +stroke-image +stroke-open-box +surface-pattern +surface-pattern-scale-down +surface-pattern-scale-down-extend-reflect +surface-pattern-scale-up +text-glyph-range +text-pattern +text-rotate +text-transform +text-unhinted-metrics +thin-lines +tiger +transforms +trap-clip +twin +unclosed-strokes +user-font +user-font-mask +user-font-proxy +user-font-rescale +user-font-subpixel +world-map +world-map-fill +world-map-stroke diff --git a/local/recipes/libs/cairo/source/.gitlab-ci/ignore-ps3-rgb24.txt b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-ps3-rgb24.txt new file mode 100644 index 0000000000..70584a89e5 --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-ps3-rgb24.txt @@ -0,0 +1,208 @@ +arc-direction +arc-looping-dash +bug-361 +bug-431 +bug-448 +bug-51910 +bug-bo-ricotz +bug-extents +bug-image-compositor +bug-spline +caps +caps-05 +caps-1 +caps-2 +caps-joins +caps-joins-05 +caps-joins-1 +caps-joins-2 +caps-joins-curve +caps-sub-paths +caps-tails-curve +clear-source +clip-complex-bug61592 +clip-fill +clip-fill-rule +clip-group-shapes-circles +clip-image +clip-nesting +clip-push-group +clip-rotate-image-surface-paint +clip-shape +clip-stroke +clip-text +clip-twice +close-path +close-path-current-point +copy-path +culled-glyphs +curve-to-as-line-to +dash-caps-joins +dash-curve +dash-infinite-loop +dash-no-dash +dash-offset +dash-offset-negative +dash-scale +dash-state +dash-zero-length +degenerate-arc +degenerate-curve-to +degenerate-dash +degenerate-path +degenerate-pen +degenerate-rel-curve-to +degenerate-solid-dash +drunkard-tails +extend-reflect +extend-reflect-similar +extended-blend-alpha-mask +fill-and-stroke +fill-degenerate-sort-order +fill-image +fill-rule +filter-nearest-offset +filter-nearest-transformed +font-matrix-translation +ft-text-vertical-layout-type1 +ft-text-vertical-layout-type3 +gradient-zero-stops +group-unaligned +hairline +hairline-anisotropic +hairline-anisotropic-incorrect +hairline-big +hairline-scaled +halo +halo-transform +horizontal-clip +image-surface-source +inverse-text +joins +joins-loop +joins-retrace +joins-star +large-font +leaky-dash +leaky-dashed-rectangle +leaky-dashed-stroke +leaky-polygon +line-width +line-width-large-overlap-dashed +line-width-overlap +line-width-overlap-dashed +line-width-overlap-flipped +line-width-overlap-flopped +line-width-overlap-offset +line-width-scale +line-width-tolerance +linear-gradient +linear-gradient-reflect +linear-gradient-subset +long-dashed-lines +mask-transformed-image +mesh-pattern-conical +mesh-pattern-control-points +mesh-pattern-fold +mesh-pattern-overlap +miter-precision +new-sub-path +overlapping-glyphs +path-append +path-stroke-twice +pdf-surface-source +pixman-downscale-fast-95 +pixman-downscale-nearest-95 +pixman-rotate +ps-surface-source +pthread-same-source +push-group-color +radial-gradient-one-stop +radial-gradient-source +random-intersections-curves-eo +random-intersections-curves-nz +random-intersections-eo +random-intersections-nonzero +record-extend-reflect +record-neg-extents-bounded +record-neg-extents-unbounded +record-replay-extend-reflect +record-replay-extend-repeat +record-select-font-face +record-self-intersecting +record-text-transform +record1414x-fill-alpha +record1414x-select-font-face +record1414x-self-intersecting +record1414x-text-transform +record2x-select-font-face +record2x-self-intersecting +record2x-text-transform +record90-select-font-face +record90-self-intersecting +record90-text-transform +recordflip-select-font-face +recordflip-self-intersecting +recordflip-text-transform +recordflip-whole-select-font-face +recordflip-whole-self-intersecting +recordflip-whole-text-transform +rectilinear-dash +rectilinear-dash-scale +rectilinear-dash-scale-unaligned +rectilinear-grid +rectilinear-miter-limit +rectilinear-stroke +reflected-stroke +rel-path +rotate-clip-image-surface-paint +rotate-image-surface-paint +rotate-stroke-box +round-join-bug-520-bevel +round-join-bug-520-round +rounded-rectangle-fill +rounded-rectangle-stroke +scale-offset-image +scale-offset-similar +scale-source-surface-paint +select-font-face +self-intersecting +set-source +shape-general-convex +shape-sierpinski +show-glyphs-advance +show-text-current-point +smask +smask-text +smp-glyph +source-surface-scale-paint +spline-decomposition +stroke-clipped +stroke-ctm-caps +stroke-image +stroke-open-box +surface-pattern +surface-pattern-scale-down +surface-pattern-scale-down-extend-reflect +surface-pattern-scale-up +text-glyph-range +text-pattern +text-rotate +text-transform +text-unhinted-metrics +thin-lines +tiger +transforms +trap-clip +twin +unclosed-strokes +user-font +user-font-mask +user-font-proxy +user-font-rescale +user-font-subpixel +world-map +world-map-fill +world-map-stroke +xcb-surface-source +xlib-surface-source diff --git a/local/recipes/libs/cairo/source/.gitlab-ci/ignore-quartz-argb32.txt b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-quartz-argb32.txt new file mode 100644 index 0000000000..fb30f4bb00 --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-quartz-argb32.txt @@ -0,0 +1,52 @@ +bug-361 +bug-431 +bug-image-compositor +clip-operator +coverage-rhombus +culled-glyphs +extended-blend-alpha +extended-blend-alpha-mask +extended-blend-mask +extended-blend-solid-alpha +fallback +ft-show-glyphs-positioning +ft-text-vertical-layout-type1 +ft-text-vertical-layout-type3 +operator-www +radial-gradient +radial-gradient-mask +radial-gradient-mask-source +radial-gradient-source +record1414x-select-font-face +record1414x-text-transform +record2x-paint-alpha-clip-mask +record2x-select-font-face +record2x-text-transform +record90-fill-alpha +record90-select-font-face +record90-text-transform +record-fill-alpha +recordflip-select-font-face +recordflip-text-transform +recordflip-whole-select-font-face +recordflip-whole-text-transform +record-mesh +record-neg-extents-bounded +record-paint-alpha-clip-mask +record-replay-extend-pad +record-replay-extend-reflect +record-replay-extend-repeat +record-select-font-face +record-text-transform +simple-edge +subsurface +subsurface-outside-target +subsurface-scale +surface-pattern +text-antialias-subpixel +text-antialias-subpixel-bgr +text-antialias-subpixel-rgb +text-antialias-subpixel-vbgr +text-antialias-subpixel-vrgb +text-unhinted-metrics +user-font-proxy diff --git a/local/recipes/libs/cairo/source/.gitlab-ci/ignore-quartz-rgb24.txt b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-quartz-rgb24.txt new file mode 100644 index 0000000000..92416e16b7 --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-quartz-rgb24.txt @@ -0,0 +1,83 @@ +a1-clip-fill-rule +big-empty-box +big-empty-triangle +big-little-box +bitmap-font +bug-361 +bug-431 +bug-448 +bug-image-compositor +bug-source-cu +clip-device-offset +clip-fill-rule-pixel-aligned +coverage-rhombus +culled-glyphs +device-offset +device-offset-positive +extended-blend-alpha-mask +extended-blend-mask +fill-and-stroke +fill-empty +fill-missed-stop +ft-show-glyphs-positioning +ft-text-vertical-layout-type1 +ft-text-vertical-layout-type3 +gradient-alpha +gradient-constant-alpha +gradient-zero-stops +gradient-zero-stops-mask +hatchings +image-surface-source +linear-gradient-one-stop +mask-ctm +mask-surface-ctm +nil-surface +operator-www +overlapping-boxes +pass-through +pdf-surface-source +ps-surface-source +quartz-surface-source +radial-gradient +radial-gradient-mask +radial-gradient-mask-source +radial-gradient-source +record1414x-select-font-face +record1414x-text-transform +record2x-paint-alpha-clip-mask +record2x-select-font-face +record2x-text-transform +record90-fill-alpha +record90-select-font-face +record90-text-transform +record-fill-alpha +recordflip-select-font-face +recordflip-text-transform +recordflip-whole-select-font-face +recordflip-whole-text-transform +record-mesh +record-neg-extents-bounded +record-neg-extents-unbounded +record-paint-alpha-clip-mask +record-replay-extend-none +record-replay-extend-pad +record-replay-extend-reflect +record-replay-extend-repeat +record-select-font-face +record-text-transform +rel-path +scale-source-surface-paint +set-source +shifted-operator +simple-edge +source-surface-scale-paint +subsurface +subsurface-scale +text-antialias-subpixel +text-antialias-subpixel-bgr +text-antialias-subpixel-rgb +text-antialias-subpixel-vbgr +text-antialias-subpixel-vrgb +text-unhinted-metrics +thin-lines +user-font-proxy diff --git a/local/recipes/libs/cairo/source/.gitlab-ci/ignore-recording-argb32.txt b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-recording-argb32.txt new file mode 100644 index 0000000000..2697bd99cd --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-recording-argb32.txt @@ -0,0 +1,35 @@ +bug-source-cu +clear-source +clip-text +coverage-rectangles +culled-glyphs +finer-grained-fallbacks +ft-show-glyphs-positioning +ft-text-vertical-layout-type1 +ft-text-vertical-layout-type3 +halo-transform +overlapping-glyphs +pthread-same-source +record1414x-fill-alpha +record1414x-select-font-face +record1414x-text-transform +record2x-fill-alpha +record2x-paint-alpha-clip-mask +record2x-text-transform +recording-surface-extend-none +recording-surface-extend-reflect +recording-surface-extend-repeat +recording-surface-over +recording-surface-source +scale-offset-similar +show-glyphs-advance +subsurface +subsurface-scale +text-antialias-subpixel +text-antialias-subpixel-bgr +text-antialias-subpixel-rgb +text-antialias-subpixel-vbgr +text-antialias-subpixel-vrgb +text-pattern +text-rotate +text-unhinted-metrics diff --git a/local/recipes/libs/cairo/source/.gitlab-ci/ignore-recording-rgb24.txt b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-recording-rgb24.txt new file mode 100644 index 0000000000..cd1173b821 --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-recording-rgb24.txt @@ -0,0 +1,85 @@ +a1-clip-fill-rule +alpha-similar +big-empty-box +big-empty-triangle +big-little-box +bitmap-font +bug-361 +bug-431 +bug-source-cu +clear-source +clip-device-offset +clip-fill-rule-pixel-aligned +clip-text +coverage-rectangles +culled-glyphs +dash-zero-length +degenerate-path +device-offset +device-offset-positive +extended-blend-alpha-mask +fill-and-stroke +fill-empty +fill-missed-stop +finer-grained-fallbacks +ft-color-font +ft-show-glyphs-positioning +ft-text-vertical-layout-type1 +ft-text-vertical-layout-type3 +gradient-alpha +gradient-constant-alpha +gradient-zero-stops +gradient-zero-stops-mask +halo-transform +image-surface-source +linear-gradient-one-stop +mask-ctm +mask-surface-ctm +new-sub-path +nil-surface +overlapping-boxes +overlapping-glyphs +pass-through +pdf-surface-source +pixman-downscale-best-24 +pixman-rotate +ps-surface-source +pthread-same-source +radial-gradient-source +record1414x-fill-alpha +record1414x-select-font-face +record1414x-text-transform +record2x-fill-alpha +record2x-paint-alpha-clip-mask +record2x-text-transform +recording-surface-extend-none +recording-surface-extend-reflect +recording-surface-extend-repeat +recording-surface-over +recording-surface-source +record-neg-extents-bounded +record-neg-extents-unbounded +record-replay-extend-none +record-replay-extend-pad +record-replay-extend-reflect +record-replay-extend-repeat +rel-path +scale-offset-similar +scale-source-surface-paint +set-source +show-glyphs-advance +source-surface-scale-paint +subsurface +subsurface-outside-target +subsurface-scale +text-antialias-subpixel +text-antialias-subpixel-bgr +text-antialias-subpixel-rgb +text-antialias-subpixel-vbgr +text-antialias-subpixel-vrgb +text-pattern +text-rotate +text-unhinted-metrics +thin-lines +xcb-surface-source +xlib-surface-source diff --git a/local/recipes/libs/cairo/source/.gitlab-ci/ignore-script-argb32.txt b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-script-argb32.txt new file mode 100644 index 0000000000..e78be546f7 --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-script-argb32.txt @@ -0,0 +1,85 @@ +a1-fill +bilevel-image +bitmap-font +clear-source +clip-device-offset +clip-text +composite-integer-translate-over-repeat +coverage-abutting +coverage-intersecting-triangles +coverage-rectangles +culled-glyphs +device-offset-scale +ft-show-glyphs-positioning +ft-text-antialias-none +ft-text-vertical-layout-type1 +ft-text-vertical-layout-type3 +halo-transform +image-surface-source +large-source +large-twin-antialias-mixed +leaky-dashed-rectangle +linear-gradient-reflect +map-all-to-image +map-bit-to-image +map-to-image-fill +negative-stride-image +overlapping-glyphs +paint-source-alpha +pdf-surface-source +ps-surface-source +pthread-show-text +push-group-color +radial-gradient +radial-gradient-mask +radial-gradient-mask-source +radial-gradient-source +record1414x-select-font-face +record1414x-text-transform +record2x-select-font-face +record2x-text-transform +record90-select-font-face +record90-text-transform +recordflip-select-font-face +recordflip-text-transform +recordflip-whole-select-font-face +recordflip-whole-text-transform +recording-surface-extend-none +recording-surface-extend-reflect +recording-surface-extend-repeat +recording-surface-over +recording-surface-source +record-neg-extents-bounded +record-replay-extend-none +record-replay-extend-pad +record-replay-extend-reflect +record-replay-extend-repeat +record-select-font-face +record-text-transform +scale-offset-image +scale-offset-similar +show-glyphs-advance +smask +smask-text +stride-12-image +subsurface +subsurface-scale +text-antialias-subpixel +text-antialias-subpixel-bgr +text-antialias-subpixel-rgb +text-antialias-subpixel-vbgr +text-antialias-subpixel-vrgb +text-pattern +text-rotate +text-unhinted-metrics +twin +twin-antialias-gray +twin-antialias-mixed +twin-antialias-none +twin-antialias-subpixel +user-font +user-font-proxy +user-font-rescale +xcb-stress-cache +xcb-surface-source +xlib-surface-source diff --git a/local/recipes/libs/cairo/source/.gitlab-ci/ignore-svg11-argb32.txt b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-svg11-argb32.txt new file mode 100644 index 0000000000..2f53dd3403 --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-svg11-argb32.txt @@ -0,0 +1,52 @@ +alpha-similar +clear-source +clip-operator +clip-text +culled-glyphs +extended-blend-solid +extended-blend-solid-alpha +filter-bilinear-extents +filter-nearest-offset +filter-nearest-transformed +ft-show-glyphs-positioning +ft-text-vertical-layout-type1 +ft-text-vertical-layout-type3 +halo-transform +linear-gradient-reflect +operator-alpha-alpha +overlapping-glyphs +paint-source-alpha +paint-with-alpha +paint-with-alpha-clip +paint-with-alpha-clip-mask +record1414x-paint-alpha +record1414x-paint-alpha-clip +record1414x-paint-alpha-clip-mask +record1414x-select-font-face +record1414x-text-transform +record2x-paint-alpha +record2x-paint-alpha-clip +record2x-paint-alpha-clip-mask +record90-paint-alpha-clip +record90-paint-alpha-clip-mask +recordflip-paint-alpha +recordflip-paint-alpha-clip +recordflip-paint-alpha-clip-mask +recordflip-whole-paint-alpha +recordflip-whole-paint-alpha-clip +recordflip-whole-paint-alpha-clip-mask +record-paint-alpha +record-paint-alpha-clip +record-paint-alpha-clip-mask +scale-offset-image +scale-source-surface-paint +show-glyphs-advance +surface-pattern +surface-pattern-operator +surface-pattern-scale-up +text-pattern +text-rotate +text-unhinted-metrics +tighten-bounds +unbounded-operator +user-font-color diff --git a/local/recipes/libs/cairo/source/.gitlab-ci/ignore-svg11-rgb24.txt b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-svg11-rgb24.txt new file mode 100644 index 0000000000..44ddbff0e8 --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-svg11-rgb24.txt @@ -0,0 +1,109 @@ +alpha-similar +big-empty-box +big-empty-triangle +big-little-box +bitmap-font +bug-361 +bug-source-cu +clear-source +clip-device-offset +clip-fill-eo-unbounded +clip-fill-nz-unbounded +clip-fill-rule-pixel-aligned +clip-operator +clip-stroke-unbounded +clip-text +culled-glyphs +dash-zero-length +degenerate-path +device-offset +device-offset-positive +extended-blend-alpha-mask +extended-blend-solid +extended-blend-solid-alpha +fill-and-stroke +fill-empty +fill-missed-stop +filter-bilinear-extents +filter-nearest-offset +filter-nearest-transformed +finer-grained-fallbacks +ft-color-font +ft-show-glyphs-positioning +ft-text-vertical-layout-type1 +ft-text-vertical-layout-type3 +gradient-alpha +gradient-constant-alpha +gradient-zero-stops +gradient-zero-stops-mask +halo-transform +image-surface-source +linear-gradient-one-stop +linear-gradient-reflect +mask-ctm +mask-surface-ctm +new-sub-path +nil-surface +operator-alpha-alpha +operator-source +overlapping-boxes +overlapping-glyphs +paint-source-alpha +paint-with-alpha +paint-with-alpha-clip +paint-with-alpha-clip-mask +pass-through +pdf-surface-source +pixman-rotate +ps-surface-source +radial-gradient-mask-source +radial-gradient-source +record1414x-paint +record1414x-paint-alpha +record1414x-paint-alpha-clip +record1414x-paint-alpha-clip-mask +record1414x-paint-alpha-solid-clip +record1414x-select-font-face +record1414x-self-intersecting +record1414x-text-transform +record2x-paint-alpha +record2x-paint-alpha-clip +record2x-paint-alpha-clip-mask +record90-paint-alpha-clip +record90-paint-alpha-clip-mask +recordflip-paint-alpha +recordflip-paint-alpha-clip +recordflip-paint-alpha-clip-mask +recordflip-whole-paint-alpha +recordflip-whole-paint-alpha-clip +recordflip-whole-paint-alpha-clip-mask +recording-surface-extend-none +recording-surface-extend-reflect +recording-surface-over +recording-surface-source +record-neg-extents-bounded +record-neg-extents-unbounded +record-paint-alpha +record-paint-alpha-clip +record-paint-alpha-clip-mask +record-replay-extend-none +record-replay-extend-pad +record-replay-extend-reflect +rel-path +scale-offset-image +scale-source-surface-paint +set-source +show-glyphs-advance +source-surface-scale-paint +surface-pattern +surface-pattern-operator +surface-pattern-scale-up +text-pattern +text-rotate +text-unhinted-metrics +thin-lines +tighten-bounds +unbounded-operator +xcb-surface-source +xlib-surface-source +user-font-color diff --git a/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xcb-argb32.txt b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xcb-argb32.txt new file mode 100644 index 0000000000..18cfefded8 --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xcb-argb32.txt @@ -0,0 +1,56 @@ +a1-tiger +bug-spline +clip-operator +coverage-column-triangles +coverage-intersecting-quads +coverage-intersecting-triangles +coverage-rectangles +coverage-rhombus +coverage-row-triangles +coverage-triangles +culled-glyphs +fill-image +ft-text-vertical-layout-type1 +halo +halo-transform +hatchings +operator-source +overlapping-boxes +radial-gradient +radial-gradient-mask +radial-gradient-mask-source +radial-gradient-source +radial-outer-focus +random-clip +record1414x-fill-alpha +record1414x-self-intersecting +record2x-fill-alpha +record2x-paint-alpha-clip-mask +record90-paint-alpha-clip +record90-paint-alpha-solid-clip +record90-self-intersecting +recordflip-paint-alpha-clip-mask +recordflip-self-intersecting +recordflip-whole-fill-alpha +recordflip-whole-paint-alpha-clip-mask +recordflip-whole-self-intersecting +recording-surface-extend-pad +recording-surface-extend-repeat +record-neg-extents-bounded +record-neg-extents-unbounded +record-replay-extend-pad +record-replay-extend-reflect +record-replay-extend-repeat +record-self-intersecting +rotated-clip +simple-edge +stroke-clipped +stroke-image +text-antialias-subpixel-vbgr +text-antialias-subpixel-vrgb +text-rotate +tighten-bounds +twin-antialias-none +unantialiased-shapes +user-font +user-font-proxy diff --git a/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xcb-fallback-rgb24.txt b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xcb-fallback-rgb24.txt new file mode 100644 index 0000000000..842796fa65 --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xcb-fallback-rgb24.txt @@ -0,0 +1,71 @@ +a1-clip-fill-rule +alpha-similar +big-empty-box +big-empty-triangle +big-little-box +bitmap-font +bug-361 +bug-431 +clip-device-offset +clip-fill-rule-pixel-aligned +clip-text +coverage-intersecting-triangles +culled-glyphs +dash-zero-length +degenerate-path +device-offset +device-offset-positive +extended-blend-alpha-mask +fill-and-stroke +fill-empty +fill-missed-stop +finer-grained-fallbacks +ft-color-font +ft-show-glyphs-positioning +ft-text-vertical-layout-type1 +ft-text-vertical-layout-type3 +gradient-alpha +gradient-constant-alpha +gradient-zero-stops +gradient-zero-stops-mask +halo-transform +image-surface-source +linear-gradient-one-stop +mask-ctm +mask-surface-ctm +new-sub-path +nil-surface +overlapping-boxes +overlapping-glyphs +pass-through +pdf-surface-source +pixman-downscale-best-24 +pixman-rotate +ps-surface-source +record1414x-select-font-face +record1414x-text-transform +record-neg-extents-bounded +record-neg-extents-unbounded +record-replay-extend-none +record-replay-extend-pad +record-replay-extend-reflect +record-replay-extend-repeat +rel-path +scale-source-surface-paint +set-source +show-glyphs-advance +source-surface-scale-paint +subsurface +subsurface-outside-target +subsurface-scale +text-antialias-subpixel +text-antialias-subpixel-bgr +text-antialias-subpixel-rgb +text-antialias-subpixel-vbgr +text-antialias-subpixel-vrgb +text-pattern +text-rotate +text-unhinted-metrics +thin-lines +xcb-surface-source +xlib-surface-source diff --git a/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xcb-render-0-0-argb32.txt b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xcb-render-0-0-argb32.txt new file mode 100644 index 0000000000..9e9fbc37c2 --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xcb-render-0-0-argb32.txt @@ -0,0 +1,30 @@ +clip-disjoint-hatching +clip-fill-eo-unbounded +clip-fill-nz-unbounded +clip-operator +clip-polygons +clip-shape +clip-stroke-unbounded +clip-twice +coverage-intersecting-triangles +culled-glyphs +ft-text-vertical-layout-type1 +hatchings +radial-gradient +radial-gradient-mask +radial-gradient-mask-source +radial-gradient-source +random-clip +record1414x-select-font-face +record1414x-text-transform +record-neg-extents-bounded +record-paint-alpha-solid-clip +record-replay-extend-reflect +record-replay-extend-repeat +rotated-clip +text-antialias-subpixel +text-antialias-subpixel-bgr +text-antialias-subpixel-rgb +text-antialias-subpixel-vbgr +text-antialias-subpixel-vrgb +trap-clip diff --git a/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xcb-render-0-0-rgb24.txt b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xcb-render-0-0-rgb24.txt new file mode 100644 index 0000000000..070e45b6c3 --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xcb-render-0-0-rgb24.txt @@ -0,0 +1,78 @@ +a1-clip-fill-rule +alpha-similar +big-empty-box +big-empty-triangle +big-little-box +bitmap-font +bug-361 +bug-431 +bug-source-cu +clip-device-offset +clip-disjoint-hatching +clip-fill-eo-unbounded +clip-fill-nz-unbounded +clip-fill-rule-pixel-aligned +clip-operator +clip-polygons +clip-shape +clip-stroke-unbounded +coverage-intersecting-triangles +culled-glyphs +dash-zero-length +degenerate-path +device-offset +device-offset-positive +extended-blend-alpha-mask +fill-and-stroke +fill-empty +fill-missed-stop +finer-grained-fallbacks +ft-color-font +ft-text-vertical-layout-type1 +gradient-alpha +gradient-constant-alpha +gradient-zero-stops +gradient-zero-stops-mask +hatchings +image-surface-source +linear-gradient-one-stop +mask-ctm +mask-surface-ctm +new-sub-path +nil-surface +overlapping-boxes +overlapping-glyphs +pass-through +pdf-surface-source +pixman-downscale-best-24 +pixman-rotate +ps-surface-source +radial-gradient +radial-gradient-mask +radial-gradient-mask-source +radial-gradient-source +random-clip +record1414x-select-font-face +record1414x-text-transform +record-neg-extents-bounded +record-neg-extents-unbounded +record-paint-alpha-solid-clip +record-replay-extend-none +record-replay-extend-pad +record-replay-extend-reflect +record-replay-extend-repeat +rel-path +rotated-clip +scale-source-surface-paint +set-source +source-surface-scale-paint +subsurface-outside-target +text-antialias-subpixel +text-antialias-subpixel-bgr +text-antialias-subpixel-rgb +text-antialias-subpixel-vbgr +text-antialias-subpixel-vrgb +text-pattern +thin-lines +xcb-surface-source +xlib-surface-source diff --git a/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xcb-rgb24.txt b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xcb-rgb24.txt new file mode 100644 index 0000000000..c725bedb90 --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xcb-rgb24.txt @@ -0,0 +1,95 @@ +a1-clip-fill-rule +a1-tiger +alpha-similar +big-empty-box +big-empty-triangle +big-little-box +bitmap-font +bug-431 +bug-spline +clip-device-offset +clip-fill-rule-pixel-aligned +clip-operator +coverage-column-triangles +coverage-intersecting-quads +coverage-intersecting-triangles +coverage-rectangles +coverage-rhombus +coverage-row-triangles +coverage-triangles +culled-glyphs +device-offset +device-offset-positive +extended-blend-alpha-mask +fill-empty +fill-image +ft-color-font +ft-text-vertical-layout-type1 +gradient-alpha +gradient-constant-alpha +gradient-zero-stops +gradient-zero-stops-mask +halo +halo-transform +hatchings +image-surface-source +linear-gradient-one-stop +mask-ctm +mask-surface-ctm +nil-surface +operator-source +overlapping-boxes +pass-through +pdf-surface-source +pixman-downscale-best-24 +pixman-rotate +ps-surface-source +radial-gradient +radial-gradient-mask +radial-gradient-mask-source +radial-gradient-source +radial-outer-focus +random-clip +record1414x-fill-alpha +record1414x-self-intersecting +record2x-fill-alpha +record2x-paint-alpha-clip-mask +record90-paint-alpha-clip +record90-paint-alpha-solid-clip +record90-self-intersecting +recordflip-paint-alpha-clip-mask +recordflip-self-intersecting +recordflip-whole-fill-alpha +recordflip-whole-paint-alpha-clip-mask +recordflip-whole-self-intersecting +recording-surface-extend-pad +record-neg-extents-bounded +record-neg-extents-unbounded +record-replay-extend-none +record-replay-extend-pad +record-replay-extend-reflect +record-replay-extend-repeat +record-self-intersecting +rotated-clip +scale-source-surface-paint +set-source +simple-edge +source-surface-scale-paint +stroke-clipped +stroke-image +subsurface-outside-target +text-antialias-subpixel +text-antialias-subpixel-bgr +text-antialias-subpixel-rgb +text-antialias-subpixel-vbgr +text-antialias-subpixel-vrgb +text-pattern +text-rotate +thin-lines +tighten-bounds +twin-antialias-none +unantialiased-shapes +user-font +user-font-proxy +xcb-surface-source +xlib-surface-source diff --git a/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xcb-window&-rgb24.txt b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xcb-window&-rgb24.txt new file mode 100644 index 0000000000..7e6febe3b1 --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xcb-window&-rgb24.txt @@ -0,0 +1,85 @@ +a1-clip-fill-rule +alpha-similar +big-empty-box +big-empty-triangle +big-little-box +bitmap-font +bug-431 +bug-spline +clip-device-offset +clip-fill-rule-pixel-aligned +clip-operator +coverage-column-triangles +coverage-intersecting-quads +coverage-intersecting-triangles +coverage-rectangles +coverage-row-triangles +coverage-triangles +culled-glyphs +device-offset +device-offset-positive +extended-blend-alpha-mask +fill-empty +fill-image +ft-color-font +ft-text-vertical-layout-type1 +gradient-alpha +gradient-constant-alpha +gradient-zero-stops +gradient-zero-stops-mask +halo +halo-transform +image-surface-source +linear-gradient-one-stop +mask-ctm +mask-surface-ctm +nil-surface +operator-source +overlapping-boxes +pass-through +pdf-surface-source +pixman-downscale-best-24 +pixman-rotate +ps-surface-source +radial-outer-focus +record1414x-fill-alpha +record1414x-self-intersecting +record2x-fill-alpha +record2x-paint-alpha-clip-mask +record90-paint-alpha-clip +record90-paint-alpha-solid-clip +record90-self-intersecting +recordflip-paint-alpha-clip-mask +recordflip-self-intersecting +recordflip-whole-fill-alpha +recordflip-whole-paint-alpha-clip-mask +recordflip-whole-self-intersecting +recording-surface-extend-pad +record-neg-extents-bounded +record-neg-extents-unbounded +record-replay-extend-none +record-replay-extend-pad +record-replay-extend-reflect +record-replay-extend-repeat +record-self-intersecting +rotated-clip +scale-source-surface-paint +set-source +simple-edge +source-surface-scale-paint +stroke-clipped +stroke-image +subsurface-outside-target +text-antialias-subpixel +text-antialias-subpixel-bgr +text-antialias-subpixel-rgb +text-antialias-subpixel-vbgr +text-antialias-subpixel-vrgb +text-pattern +text-rotate +thin-lines +tighten-bounds +twin-antialias-none +unantialiased-shapes +xcb-surface-source +xlib-surface-source diff --git a/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xcb-window-rgb24.txt b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xcb-window-rgb24.txt new file mode 100644 index 0000000000..6f27c97b18 --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xcb-window-rgb24.txt @@ -0,0 +1,87 @@ +a1-clip-fill-rule +alpha-similar +big-empty-box +big-empty-triangle +big-little-box +bitmap-font +bug-431 +bug-spline +clip-device-offset +clip-fill-rule-pixel-aligned +clip-operator +coverage-column-triangles +coverage-intersecting-quads +coverage-intersecting-triangles +coverage-rectangles +coverage-row-triangles +coverage-triangles +culled-glyphs +device-offset +device-offset-positive +extended-blend-alpha-mask +fill-empty +fill-image +ft-color-font +ft-text-vertical-layout-type1 +gradient-alpha +gradient-constant-alpha +gradient-zero-stops +gradient-zero-stops-mask +halo +halo-transform +image-surface-source +linear-gradient-one-stop +mask-ctm +mask-surface-ctm +nil-surface +operator-source +overlapping-boxes +pass-through +pdf-surface-source +pixman-downscale-best-24 +pixman-rotate +ps-surface-source +push-group +push-group-color +radial-outer-focus +record1414x-fill-alpha +record1414x-self-intersecting +record2x-fill-alpha +record2x-paint-alpha-clip-mask +record90-paint-alpha-clip +record90-paint-alpha-solid-clip +record90-self-intersecting +recordflip-paint-alpha-clip-mask +recordflip-self-intersecting +recordflip-whole-fill-alpha +recordflip-whole-paint-alpha-clip-mask +recordflip-whole-self-intersecting +recording-surface-extend-pad +record-neg-extents-bounded +record-neg-extents-unbounded +record-replay-extend-none +record-replay-extend-pad +record-replay-extend-reflect +record-replay-extend-repeat +record-self-intersecting +rotated-clip +scale-source-surface-paint +set-source +simple-edge +source-surface-scale-paint +stroke-clipped +stroke-image +subsurface-outside-target +text-antialias-subpixel +text-antialias-subpixel-bgr +text-antialias-subpixel-rgb +text-antialias-subpixel-vbgr +text-antialias-subpixel-vrgb +text-pattern +text-rotate +thin-lines +tighten-bounds +twin-antialias-none +unantialiased-shapes +xcb-surface-source +xlib-surface-source diff --git a/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xlib-argb32.txt b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xlib-argb32.txt new file mode 100644 index 0000000000..098259fc72 --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xlib-argb32.txt @@ -0,0 +1,127 @@ +aliasing +arc-looping-dash +bug-84115 +bug-extents +bug-image-compositor +bug-spline +caps-joins-curve +clip-disjoint +clip-operator +clip-shape +clip-stroke +clip-stroke-unbounded +clip-text +close-path-current-point +coverage-column-triangles +coverage-rhombus +culled-glyphs +dash-caps-joins +dash-curve +dash-scale +degenerate-curve-to +degenerate-pen +degenerate-rel-curve-to +drunkard-tails +extended-blend-alpha-mask +fill-and-stroke +fill-and-stroke-alpha +fill-and-stroke-alpha-add +fill-image +ft-show-glyphs-positioning +ft-text-vertical-layout-type1 +ft-text-vertical-layout-type3 +halo +halo-transform +hatchings +joins +joins-loop +joins-retrace +large-twin-antialias-mixed +leaky-dashed-stroke +line-width-scale +line-width-tolerance +long-dashed-lines +new-sub-path +operator-source +overlapping-boxes +overlapping-dash-caps +overlapping-glyphs +path-stroke-twice +pthread-show-text +radial-gradient +radial-gradient-mask +radial-gradient-mask-source +radial-gradient-source +radial-outer-focus +random-clip +random-intersections-curves-eo +random-intersections-curves-nz +random-intersections-eo +random-intersections-nonzero +record1414x-fill-alpha +record1414x-select-font-face +record1414x-self-intersecting +record1414x-text-transform +record2x-fill-alpha +record2x-paint-alpha-clip-mask +record2x-select-font-face +record2x-text-transform +record90-paint-alpha-clip +record90-paint-alpha-solid-clip +record90-select-font-face +record90-self-intersecting +record90-text-transform +recordflip-paint-alpha-clip-mask +recordflip-select-font-face +recordflip-self-intersecting +recordflip-text-transform +recordflip-whole-fill-alpha +recordflip-whole-paint-alpha-clip-mask +recordflip-whole-select-font-face +recordflip-whole-self-intersecting +recordflip-whole-text-transform +recording-surface-extend-pad +recording-surface-extend-repeat +record-neg-extents-bounded +record-neg-extents-unbounded +record-replay-extend-none +record-replay-extend-pad +record-replay-extend-reflect +record-replay-extend-repeat +record-select-font-face +record-self-intersecting +record-text-transform +reflected-stroke +rel-path +rounded-rectangle-stroke +scale-offset-image +scale-offset-similar +shape-general-convex +shape-sierpinski +show-glyphs-advance +simple-edge +smask +smask-stroke +smask-text +spline-decomposition +stroke-clipped +stroke-image +stroke-pattern +subsurface +subsurface-scale +text-antialias-subpixel-vbgr +text-antialias-subpixel-vrgb +text-pattern +text-rotate +text-unhinted-metrics +tighten-bounds +twin +twin-antialias-gray +twin-antialias-mixed +twin-antialias-none +twin-antialias-subpixel +unclosed-strokes +user-font +user-font-proxy +world-map +world-map-stroke diff --git a/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xlib-fallback-rgb24.txt b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xlib-fallback-rgb24.txt new file mode 100644 index 0000000000..6c9360def8 --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xlib-fallback-rgb24.txt @@ -0,0 +1,87 @@ +a1-clip-fill-rule +alpha-similar +big-empty-box +big-empty-triangle +big-little-box +bitmap-font +bug-361 +bug-431 +bug-seams +clip-device-offset +clip-fill-rule-pixel-aligned +clip-text +culled-glyphs +dash-zero-length +degenerate-path +device-offset +device-offset-positive +extended-blend-alpha-mask +fallback +fill-and-stroke +fill-empty +fill-missed-stop +finer-grained-fallbacks +ft-color-font +ft-show-glyphs-positioning +ft-text-vertical-layout-type1 +ft-text-vertical-layout-type3 +gradient-alpha +gradient-constant-alpha +gradient-zero-stops +gradient-zero-stops-mask +halo-transform +image-surface-source +large-twin-antialias-mixed +linear-gradient-one-stop +mask-ctm +mask-surface-ctm +new-sub-path +nil-surface +over-above-source +over-around-source +over-between-source +overlapping-boxes +overlapping-glyphs +pass-through +pdf-surface-source +pixman-downscale-best-24 +pixman-rotate +ps-surface-source +pthread-show-text +pthread-similar +push-group-color +record1414x-select-font-face +record1414x-text-transform +record-neg-extents-bounded +record-neg-extents-unbounded +record-replay-extend-none +record-replay-extend-pad +record-replay-extend-reflect +record-replay-extend-repeat +rel-path +scale-source-surface-paint +set-source +shifted-operator +show-glyphs-advance +smask +smask-text +source-surface-scale-paint +subsurface +subsurface-outside-target +subsurface-scale +surface-pattern-scale-down-extend-none +text-antialias-subpixel +text-antialias-subpixel-bgr +text-antialias-subpixel-rgb +text-antialias-subpixel-vbgr +text-antialias-subpixel-vrgb +text-pattern +text-rotate +text-unhinted-metrics +thin-lines +twin-antialias-gray +twin-antialias-mixed +twin-antialias-none +twin-antialias-subpixel +xcb-surface-source +xlib-surface-source diff --git a/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xlib-render-0-0-rgb24.txt b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xlib-render-0-0-rgb24.txt new file mode 100644 index 0000000000..bc4e4e21c5 --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xlib-render-0-0-rgb24.txt @@ -0,0 +1,94 @@ +a1-clip-fill-rule +alpha-similar +big-empty-box +big-empty-triangle +big-little-box +bitmap-font +bug-361 +bug-431 +bug-source-cu +clip-device-offset +clip-fill-rule-pixel-aligned +clip-operator +clipped-group +clip-text +coverage-intersecting-triangles +culled-glyphs +curve-to-as-line-to +degenerate-path +device-offset +device-offset-positive +extended-blend-alpha-mask +fill-and-stroke +fill-and-stroke-alpha +fill-and-stroke-alpha-add +fill-empty +fill-missed-stop +finer-grained-fallbacks +ft-color-font +ft-show-glyphs-positioning +ft-text-vertical-layout-type1 +ft-text-vertical-layout-type3 +gradient-alpha +gradient-constant-alpha +gradient-zero-stops +gradient-zero-stops-mask +halo-transform +horizontal-clip +image-surface-source +large-twin-antialias-mixed +leaky-polygon +linear-gradient-one-stop +mask +mask-ctm +mask-surface-ctm +new-sub-path +nil-surface +operator-clear +operator-source +overlapping-boxes +overlapping-glyphs +pass-through +pdf-surface-source +pixman-downscale-best-24 +pixman-rotate +ps-surface-source +pthread-show-text +radial-gradient-source +radial-outer-focus +record1414x-select-font-face +record1414x-text-transform +record-neg-extents-bounded +record-neg-extents-unbounded +record-replay-extend-none +record-replay-extend-pad +record-replay-extend-reflect +record-replay-extend-repeat +rectilinear-stroke +rel-path +scale-source-surface-paint +set-source +show-glyphs-advance +smask +smask-text +source-surface-scale-paint +subsurface +subsurface-outside-target +subsurface-scale +surface-pattern-operator +text-antialias-subpixel +text-antialias-subpixel-bgr +text-antialias-subpixel-rgb +text-antialias-subpixel-vbgr +text-antialias-subpixel-vrgb +text-pattern +text-rotate +text-unhinted-metrics +thin-lines +twin-antialias-gray +twin-antialias-mixed +twin-antialias-none +twin-antialias-subpixel +unbounded-operator +xcb-surface-source +xlib-surface-source diff --git a/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xlib-rgb24.txt b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xlib-rgb24.txt new file mode 100644 index 0000000000..e7d8b13a56 --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xlib-rgb24.txt @@ -0,0 +1,163 @@ +a1-clip-fill-rule +aliasing +alpha-similar +arc-looping-dash +big-empty-box +big-empty-triangle +big-little-box +bitmap-font +bug-84115 +bug-extents +bug-image-compositor +bug-spline +caps-joins-curve +clip-device-offset +clip-disjoint +clip-fill-rule-pixel-aligned +clip-operator +clip-shape +clip-stroke +clip-stroke-unbounded +clip-text +close-path-current-point +coverage-column-triangles +coverage-rhombus +culled-glyphs +dash-caps-joins +dash-curve +dash-scale +degenerate-curve-to +degenerate-pen +degenerate-rel-curve-to +device-offset +device-offset-positive +drunkard-tails +extended-blend-alpha-mask +fill-and-stroke +fill-and-stroke-alpha +fill-and-stroke-alpha-add +fill-empty +fill-image +ft-color-font +ft-show-glyphs-positioning +ft-text-vertical-layout-type1 +ft-text-vertical-layout-type3 +gradient-alpha +gradient-constant-alpha +gradient-zero-stops +gradient-zero-stops-mask +halo +halo-transform +hatchings +image-surface-source +joins +joins-loop +joins-retrace +large-twin-antialias-mixed +leaky-dashed-stroke +linear-gradient-one-stop +line-width-scale +line-width-tolerance +long-dashed-lines +mask-ctm +mask-surface-ctm +new-sub-path +nil-surface +operator-source +overlapping-boxes +overlapping-dash-caps +overlapping-glyphs +pass-through +path-stroke-twice +pdf-surface-source +pixman-downscale-best-24 +pixman-rotate +ps-surface-source +pthread-show-text +radial-gradient +radial-gradient-mask +radial-gradient-mask-source +radial-gradient-source +radial-outer-focus +random-clip +random-intersections-curves-eo +random-intersections-curves-nz +random-intersections-eo +random-intersections-nonzero +record1414x-fill-alpha +record1414x-select-font-face +record1414x-self-intersecting +record1414x-text-transform +record2x-fill-alpha +record2x-paint-alpha-clip-mask +record2x-select-font-face +record2x-text-transform +record90-paint-alpha-clip +record90-paint-alpha-solid-clip +record90-select-font-face +record90-self-intersecting +record90-text-transform +recordflip-paint-alpha-clip-mask +recordflip-select-font-face +recordflip-self-intersecting +recordflip-text-transform +recordflip-whole-fill-alpha +recordflip-whole-paint-alpha-clip-mask +recordflip-whole-select-font-face +recordflip-whole-self-intersecting +recordflip-whole-text-transform +recording-surface-extend-pad +record-neg-extents-bounded +record-neg-extents-unbounded +record-replay-extend-none +record-replay-extend-pad +record-replay-extend-reflect +record-replay-extend-repeat +record-select-font-face +record-self-intersecting +record-text-transform +reflected-stroke +rel-path +rounded-rectangle-stroke +scale-offset-image +scale-offset-similar +scale-source-surface-paint +set-source +shape-general-convex +shape-sierpinski +shifted-operator +show-glyphs-advance +simple-edge +smask +smask-stroke +smask-text +source-surface-scale-paint +spline-decomposition +stroke-clipped +stroke-image +stroke-pattern +subsurface +subsurface-outside-target +subsurface-scale +text-antialias-subpixel +text-antialias-subpixel-bgr +text-antialias-subpixel-rgb +text-antialias-subpixel-vbgr +text-antialias-subpixel-vrgb +text-pattern +text-rotate +text-unhinted-metrics +thin-lines +tighten-bounds +twin +twin-antialias-gray +twin-antialias-mixed +twin-antialias-none +twin-antialias-subpixel +unclosed-strokes +user-font +user-font-proxy +world-map +world-map-stroke +xcb-surface-source +xlib-surface-source diff --git a/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xlib-window-rgb24.txt b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xlib-window-rgb24.txt new file mode 100644 index 0000000000..18f75875f6 --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci/ignore-xlib-window-rgb24.txt @@ -0,0 +1,149 @@ +a1-clip-fill-rule +aliasing +alpha-similar +arc-looping-dash +big-empty-box +big-empty-triangle +big-little-box +bitmap-font +bug-extents +bug-spline +caps-joins-curve +clip-device-offset +clip-disjoint +clip-fill-rule-pixel-aligned +clip-operator +clip-shape +clip-stroke +clip-stroke-unbounded +clip-text +close-path-current-point +coverage-column-triangles +coverage-intersecting-quads +coverage-intersecting-triangles +coverage-rectangles +coverage-row-triangles +coverage-triangles +culled-glyphs +dash-caps-joins +dash-scale +degenerate-curve-to +degenerate-pen +degenerate-rel-curve-to +device-offset +device-offset-positive +drunkard-tails +extended-blend-alpha-mask +fill-and-stroke +fill-and-stroke-alpha +fill-and-stroke-alpha-add +fill-empty +fill-image +ft-color-font +ft-show-glyphs-positioning +ft-text-vertical-layout-type1 +ft-text-vertical-layout-type3 +gradient-alpha +gradient-constant-alpha +gradient-zero-stops +gradient-zero-stops-mask +halo +halo-transform +image-surface-source +joins +joins-loop +joins-retrace +large-twin-antialias-mixed +leaky-dashed-stroke +linear-gradient-one-stop +line-width-scale +line-width-tolerance +long-dashed-lines +mask-ctm +mask-surface-ctm +new-sub-path +nil-surface +operator-source +overlapping-boxes +overlapping-dash-caps +overlapping-glyphs +pass-through +path-stroke-twice +pdf-surface-source +pixman-downscale-best-24 +pixman-rotate +ps-surface-source +pthread-show-text +radial-outer-focus +record1414x-fill-alpha +record1414x-select-font-face +record1414x-self-intersecting +record1414x-text-transform +record2x-fill-alpha +record2x-paint-alpha-clip-mask +record2x-select-font-face +record2x-text-transform +record90-paint-alpha-clip +record90-paint-alpha-solid-clip +record90-select-font-face +record90-self-intersecting +record90-text-transform +recordflip-paint-alpha-clip-mask +recordflip-select-font-face +recordflip-self-intersecting +recordflip-text-transform +recordflip-whole-fill-alpha +recordflip-whole-paint-alpha-clip-mask +recordflip-whole-select-font-face +recordflip-whole-self-intersecting +recordflip-whole-text-transform +recording-surface-extend-pad +record-neg-extents-bounded +record-neg-extents-unbounded +record-replay-extend-none +record-replay-extend-pad +record-replay-extend-reflect +record-replay-extend-repeat +record-select-font-face +record-self-intersecting +record-text-transform +reflected-stroke +rel-path +rounded-rectangle-stroke +scale-offset-image +scale-offset-similar +scale-source-surface-paint +set-source +shape-general-convex +shifted-operator +show-glyphs-advance +simple-edge +smask +smask-stroke +smask-text +source-surface-scale-paint +spline-decomposition +stroke-clipped +stroke-image +stroke-pattern +subsurface +subsurface-outside-target +subsurface-scale +text-antialias-subpixel +text-antialias-subpixel-bgr +text-antialias-subpixel-rgb +text-antialias-subpixel-vbgr +text-antialias-subpixel-vrgb +text-pattern +text-rotate +text-unhinted-metrics +thin-lines +tighten-bounds +twin +twin-antialias-gray +twin-antialias-mixed +twin-antialias-none +twin-antialias-subpixel +unclosed-strokes +xcb-surface-source +xlib-surface-source diff --git a/local/recipes/libs/cairo/source/.gitlab-ci/install-grcov.sh b/local/recipes/libs/cairo/source/.gitlab-ci/install-grcov.sh new file mode 100644 index 0000000000..43edaa73f6 --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci/install-grcov.sh @@ -0,0 +1,8 @@ +source ./.gitlab-ci/env.sh + +set -eu +export CARGO_HOME='/usr/local/cargo' + +# Coverage tools +cargo install grcov +rustup component add llvm-tools-preview diff --git a/local/recipes/libs/cairo/source/.gitlab-ci/install-rust-tools.sh b/local/recipes/libs/cairo/source/.gitlab-ci/install-rust-tools.sh new file mode 100644 index 0000000000..23e55f4d92 --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci/install-rust-tools.sh @@ -0,0 +1,11 @@ +source ./.gitlab-ci/env.sh + +set -eu +export CARGO_HOME='/usr/local/cargo' + +rustup component add clippy +rustup component add rustfmt +# cargo install --force cargo-c +cargo install --version ^1.0 gitlab_clippy +cargo install --force cargo-deny +# cargo install --force cargo-outdated diff --git a/local/recipes/libs/cairo/source/.gitlab-ci/install-rust.sh b/local/recipes/libs/cairo/source/.gitlab-ci/install-rust.sh new file mode 100644 index 0000000000..93cdb4abd6 --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci/install-rust.sh @@ -0,0 +1,92 @@ +#!/bin/bash + +set -o errexit -o pipefail -o noclobber -o nounset + +source ./.gitlab-ci/env.sh + +export CARGO_HOME='/usr/local/cargo' + +PARSED=$(getopt --options '' --longoptions 'rustup-version:,stable:,minimum:,nightly,arch:' --name "$0" -- "$@") +if [ $? -ne 0 ]; then + echo 'Terminating...' >&2 + exit 1 +fi + +eval set -- "$PARSED" +unset PARSED + +RUSTUP_VERSION= +STABLE= +MINIMUM= +NIGHTLY= +ARCH= + +while true; do + case "$1" in + '--rustup-version') + RUSTUP_VERSION=$2 + shift 2 + ;; + + '--stable') + STABLE=$2 + shift 2 + ;; + + '--minimum') + MINIMUM=$2 + shift 2 + ;; + + '--nightly') + NIGHTLY=1 + shift 1 + ;; + + '--arch') + ARCH=$2 + shift 2 + ;; + + '--') + shift + break + ;; + + *) + echo "Programming error" + exit 3 + ;; + esac +done + +if [ -z "$RUSTUP_VERSION" ]; then + echo "missing --rustup-version argument" + exit 1 +fi + +if [ -z "$STABLE" ]; then + echo "missing --stable argument, please pass the stable version of rustc you want" + exit 1 +fi + +if [ -z "$ARCH" ]; then + echo "missing --arch argument, please pass an architecture triple like x86_64-unknown-linux-gnu" + exit 1 +fi + +RUSTUP_URL=https://static.rust-lang.org/rustup/archive/$RUSTUP_VERSION/$ARCH/rustup-init +wget $RUSTUP_URL + +chmod +x rustup-init +./rustup-init -y --no-modify-path --profile minimal --default-toolchain $STABLE +rm rustup-init +chmod -R a+w $RUSTUP_HOME $CARGO_HOME + +if [ -n "$MINIMUM" ]; then + rustup toolchain install $MINIMUM +fi + +if [ -n "$NIGHTLY" ]; then + rustup toolchain install nightly +fi diff --git a/local/recipes/libs/cairo/source/.gitlab-ci/pages-index.html b/local/recipes/libs/cairo/source/.gitlab-ci/pages-index.html new file mode 100644 index 0000000000..9a6aba58a0 --- /dev/null +++ b/local/recipes/libs/cairo/source/.gitlab-ci/pages-index.html @@ -0,0 +1,13 @@ + + + Cairo's development pages + + + +

Cairo's development pages

+ + + + diff --git a/local/recipes/libs/cairo/source/.redbear-src-version b/local/recipes/libs/cairo/source/.redbear-src-version new file mode 100644 index 0000000000..3a33ec3510 --- /dev/null +++ b/local/recipes/libs/cairo/source/.redbear-src-version @@ -0,0 +1 @@ +cairo-1.18.4.tar.xz diff --git a/local/recipes/libs/cairo/source/AUTHORS b/local/recipes/libs/cairo/source/AUTHORS new file mode 100644 index 0000000000..fe5a883e8b --- /dev/null +++ b/local/recipes/libs/cairo/source/AUTHORS @@ -0,0 +1,115 @@ +Josh Aas Memory leak fix for quartz backend +Daniel Amelang Many (magic) floating-point optimizations +Shawn T. Amundson Build fix +Olivier Andrieu PNG backend +Peter Dennis Bartok Bug fix for clipping +Dave Beckett Build fixes, Debian packaging +Kai-Uwe Behrmann SVG bug fixes +Christian Biesinger BeOS backend +Billy Biggs Pixman code merge. Optimization. Fixes for subtle rendering bugs. +Hans Breuer win32 bug fixes, build fixes, and improvements +Brian Cameron Flag bug in Sun's X server +Carlos Garcia Campos libspectre integration into the test-suite +Andrea Canciani Bugs, quartz backend improvements and type 6/7 patterns. +Damien Carbery Build fixes +Andrew Chant Adding const where needed +Steve Chaplin Bug fixes for PNG reading +Tomasz Cholewo Bug fixes +Manu Cornet SVG build fix +Frederic Crozat Fix test suite for OPD platforms (IA64 or PPC64) +Julien Danjou XCB fixes +Radek Doulík Bug report and test case +John Ehresman Build fixes for win32 +John Ellson First font/glyph extents functions +Michael Emmel DirectFB backend +Miklós Erdélyi Fix typo leading to a crash +Behdad Esfahbod Huge piles of bug fixes, improvements, and general maintenance +Gilles Espinasse Font related fixes +Larry Ewing Test case for group-clip +Brian Ewins ATSUI maintenance (first success at making it really work) +Bertram Felgenhauer Fixes for subtle arithmetic errors +Damian Frank Build system improvements for win32 +Bdale Garbee Provided essential support for cairo architecture sessions +Jens Granseuer Fixes to generate proper compiler flags +Laxmi Harikumar Build fix +J. Ali Harlow win32 backend updates +Bryce Harrington Test cases, bug/typo fixes +Mathias Hasselmann Significant reduction of calls to malloc +Richard Henderson "slim" macros for better shared libraries +James Henstridge Build fixes related to freetype +Graydon Hoare Support for non-render X server, first real text support +Thomas Hunger Initial version of cairo_in_stroke/fill +Thomas Jaeger Extended repeat modes for X +Björn Lindqvist Performance test cases +Kristian Høgsberg PDF backend, PS backend with meta-surfaces +Amaury Jacquot Documentation review, application testing +Adrian Johnson PDF backend improvement +Michael Johnson Bug fix for pre-C99 compilers +Jonathon Jongsma Fix documentation typos +Øyvind Kolås OpenVG backend, Bug fixes. Better default values. +Martin Kretzschmar Arithmetic fix for 64-bit architectures +Mathieu Lacage several bug/typo fixes +Dominic Lachowicz PDF conformance fix, fix image surface to zero out contents +Alexander Larsson Profiling and performance fixes. +Sylvestre Ledru Static analysis fixes. +Tor Lillqvist win32 build fixes, build scripts +Jinghua Luo Add bitmap glyph transformation, many freetype and glitz fixes +Luke-Jr Build fix for cross-compiling +Kjartan Maraas Several fixes for sparse, lots of debug help for multi-thread bugs +Nis Martensen Bug fix for sub paths +Jordi Mas Bug fix for cairo_show_text +Nicholas Miell Fixes for linking bugs on AMD64 +Eugeniy Meshcheryakov PS/PDF font subsetting improvements +Zakharov Mikhail Build fix for HP-UX +Christopher (Monty) Montgomery Performance fix (subimage_copy), multi-thread testing +Tim Mooney Fix test suite to compile with Solaris compiler +Jeff Muizelaar Patient, painful, pixman code merge. Many fixes for intricacies of dashing. +Yevgen Muntyan win32 build fix +Ravi Nanjundappa Static analysis fixes, test cases, skia backend update/fixes +Declan Naughton Fix documentation typos +Peter Nilsson Glitz backend +Henning Noren Fix memory leak +Geoff Norton Build fixes +Robert O'Callahan Const-correctness fixes, several new API functions for completeness (and to help mozilla) +Ian Osgood XCB backend maintenance +Benjamin Otte Refinements to cairo/perf timing, OpenGL backend fixups, random fixes +Mike Owens Bug fixes +Emmanuel Pacaud SVG backend +Keith Packard Original concept, polygon tessellation, dashing, font metrics rewrite +Stuart Parmenter Original GDI+ backend, win32 fixes +Alfred Peng Fixes for Sun compilers and for a memory leak +Christof Petig Build fixes related to freetype +Joonas Pihlaja Huge improvements to the tessellator performance +Mart Raudsepp Build fixes +David Reveman New pattern API, glitz backend +Calum Robinson Quartz backend +Pavel Roskin Several cleanups to eliminate warnings +Tim Rowley Quartz/ATSUI fixes, X server workarounds, win32 glyph path support, test case to expose gradient regression +Soeren Sandmann Lots of MMX love for pixman compositing +Uli Schlachter Some more XCB fixes +Torsten Schönfeld Build fixes +Jamey Sharp Surface/font backend virtualization, XCB backend +Jason Dorje Short Build fixes and bug fixes +Jeff Smith Fixes for intricacies of stroking code +Travis Spencer XCB backend fix +Bill Spitzak Build fix to find Xrender.h without xrender.pc, downscaling support +Zhe Su Add support for fontconfig's embeddedbitmap option +Owen Taylor Font rewrite, documentation, win32 backend +Pierre Tardy EGL support and testing, OpenVG backend +Karl Tomlinson Optimisation and obscure bug fixes (mozilla) +Alp Toker Fix several code/comment typos +Malcolm Tredinnick Documentation fixes +David Turner Optimize gradient calculations +Kalle Vahlman Allow perf reports to be compared across different platforms +Sasha Vasko Build fix to compile without xlib backend +Vladimir Vukicevic Quartz backend rewrite, win32/quartz maintenance +Jonathan Watt win32 fixes +Peter Weilbacher OS/2 backend +Dan Williams Implement MMX function to help OLPC +Chris Wilson Large-scale robustness improvements, (warn_unsed_result and malloc failure injection) +Carl Worth Original library, support for paths, images +Richard D. Worth Build fixes for cygwin +Kent Worsnop Fix PDF dashing bug +Dave Yeo Build fix for win32 + +(please let us know if we have missed anyone) diff --git a/local/recipes/libs/cairo/source/BUGS b/local/recipes/libs/cairo/source/BUGS new file mode 100644 index 0000000000..a2631e9f49 --- /dev/null +++ b/local/recipes/libs/cairo/source/BUGS @@ -0,0 +1,84 @@ +If you find a bug in cairo we would love to hear about it. We're also +trying to make cairo better, and learning about the bugs that users +encounter is an essential part of that. So we really appreciate the +extra effort users put in to providing high-quality bug reports. + +There are two acceptable ways to report cairo bugs, and you can choose +which you prefer: + +1) Gitlab bug tracking database: + + You can use the following web interface to report new bugs, follow + up on previous bug reports, and search for existing, known + bugs: + + https://gitlab.freedesktop.org/cairo/cairo/-/issues + + It is necessary to go through a quick account creation process, + (with email address verification), in order to be able to report + new bugs in gitlab. We apologize for any inconvenience that might + cause, and hope it won't prevent you from reporting bugs. + +2) Cairo mailing list: + + For people who cannot stand the gitlab interface, you can just + send an email to cairo mailing list (cairo@cairographics.org). The + mailing list only allows posting from subscribers, so use the + following page for subscription instructions: + + https://cairographics.org/lists + + Again, we apologize for any inconvenience this subscription step + might cause, but we've found it necessary to require this in order + to enjoy spam-free discussions on the list. + + If you don't actually _want_ to be a subscriber to the mailing + list, but just want to be able to send a message, the easiest thing + to do is to go through the subscription process, and then use the + preferences page to disable message delivery to your address. + +Which of the above you use to report bugs depends on your own +preferences. Some people find just typing an email message much easier +than using the web-based forms on gitlab. Others greatly prefer the +ability to check back on a specific bug entry in gitlab without +having to ask on the mailing list if an issue has been resolved. + +Regardless of which method you use, here are some general tips that +will help you improve the quality of your bug report, (which will help +in getting the bug fixed sooner): + +1) Check to see if the bug has been reported already. It's pretty easy + to run a search or two against the cairo product in the gitlab + database. Another place to look for known bugs is the cairo ROADMAP: + + https://cairographics.org/ROADMAP + + which shows a planned schedule of releases and which bug fixes are + being planned for each release. + +2) Provide an accurate description of the bug with detailed steps for + how we can reproduce the problem. + +3) If possible provide a minimal test case demonstrating the bug. A + great test case would be a minimal self-contained function in C or + python or whatever language you are using for cairo. The function + might accept nothing more than a cairo context, (cairo_t* in C). + +4) If you feel like being particularly helpful, you could craft this + minimal test case in the form necessary for cairo's test + suite. This isn't much more work than writing a minimal + function. Just look at the cairo/test/README file and imitate the + style of existing test cases. + + If you do submit a test case, be sure to include Copyright + information, (with the standard MIT licensing blurb if you want us + to include your test in the test case). Also, including a reference + image showing the expected result will be extremely useful. + +5) Finally, the best bug report also comes attached with a patch to + cairo to fix the bug. So send this too if you have it! Otherwise, + don't worry about it and we'll try to fix cairo when we can. + +Thanks, and have fun with cairo! + +-Carl diff --git a/local/recipes/libs/cairo/source/CODING_STYLE b/local/recipes/libs/cairo/source/CODING_STYLE new file mode 100644 index 0000000000..7e96c36d1a --- /dev/null +++ b/local/recipes/libs/cairo/source/CODING_STYLE @@ -0,0 +1,292 @@ +Cairo coding style. + +This document is intended to be a short description of the preferred +coding style for the cairo source code. Good style requires good +taste, which means this can't all be reduced to automated rules, and +there are exceptions. + +We want the code to be easy to understand and maintain, and consistent +style plays an important part in that, even if some of the specific +details seem trivial. If nothing else, this document gives a place to +put consistent answers for issues that would otherwise be arbitrary. + +Most of the guidelines here are demonstrated by examples, (which means +this document is quicker to read than it might appear given its +length). Most of the examples are positive examples that you should +imitate. The few negative examples are clearly marked with a comment +of /* Yuck! */. Please don't submit code to cairo that looks like any +of these. + +Indentation +----------- +Each new level is indented 4 more spaces than the previous level: + + if (condition) + do_something (); + +This may be achieved with space characters or a combination of tab +characters and space characters. It may not be achieved with tab +characters exclusively (see below). + +Tab characters +-------------- +The tab character must always be interpreted according to its +traditional meaning: + + Advance to the next column which is a multiple of 8. + +With this definition, even levels of indentation can be achieved with +a sequence of tab characters, while odd levels of indentation may +begin with a sequence of tab character but must end with 4 space +characters. + +Some programmers have been misled by certain text editors into +thinking that 4-space indentation can be achieved with tab characters +exclusively by changing the meaning of tab character to be "advance to +the next column which is a multiple of 4". Code formatted in this way, +making an assumption of a fictitious 4-character-tab will not be +accepted into cairo. + +The rationale here is that tabs are used in the code for lining things +up other than indentation, (see the Whitespace section below), and +changing the interpretation of tab from its traditional meaning will +break this alignment. + +Braces +------ +Most of the code in cairo uses bracing in the style of K&R: + + if (condition) { + do_this (); + do_that (); + } else { + do_the_other (); + } + +but some of the code uses an alternate style: + + if (condition) + { + do_this (); + do_that (); + } + else + { + do_the_other (); + } + +and that seems just fine. We won't lay down any strict rule on this +point, (though there should be some local consistency). If you came +here hoping to find some guidance, then use the first form above. + +If all of the substatements of an if statement are single statements, +the optional braces should not usually appear: + + if (condition) + do_this (); + else + do_that (); + +But the braces are mandatory when mixing single statement and compound +statements in the various clauses. For example, do not do this: + + if (condition) { + do_this (); + do_that (); + } else /* Yuck! */ + do_the_other (); + +And of course, there are exceptions for when the code just looks +better with the braces: + + if (condition) { + /* Note that we have to be careful here. */ + do_something_dangerous (with_care); + } + + if (condition && + other_condition && + yet_another) + { + do_something (); + } + +And note that this last example also shows a situation in which the +opening brace really needs to be on its own line. The following looks awful: + + if (condition && + other_condition && + yet_another) { /* Yuck! */ + do_something (); + } + +As we said above, legible code that is easy to understand and maintain +is the goal, not adherence to strict rules. + +Whitespace +---------- +Separate logically distinct chunks with a single newline. This +obviously applies between functions, but also applies within a +function or block and can even be used to good effect within a +structure definition: + + struct _cairo_gstate { + cairo_operator_t op; + + double tolerance; + + /* stroke style */ + double line_width; + cairo_line_cap_t line_cap; + cairo_line_join_t line_join; + double miter_limit; + + cairo_fill_rule_t fill_rule; + + double *dash; + int num_dashes; + double dash_offset; + + ... + } + +Use a single space before a left parenthesis, except where the +standard will not allow it, (eg. when defining a parameterized macro). + +Don't eliminate newlines just because things would still fit on one +line. This breaks the expected visual structure of the code making it +much harder to read and understand: + + if (condition) foo (); else bar (); /* Yuck! */ + +Do eliminate trailing whitespace (space or tab characters) on any +line. Also, avoid putting initial or final blank lines into any file, +and never use multiple blank lines instead of a single blank line. + +Do enable the default git pre-commit hook that detect trailing +whitespace for you and help you to avoid corrupting cairo's tree with +it. Do that as follows: + + chmod a+x .git/hooks/pre-commit + +You might also find the git-stripspace utility helpful which acts as a +filter to remove trailing whitespace as well as initial, final, and +duplicate blank lines. + +As a special case of the bracing and whitespace guidelines, function +definitions should always take the following form: + + void + my_function (argument) + { + do_my_things (); + } + +And function prototypes should similarly have the return type (and +associated specifiers and qualifiers) on a line above the function, so +that the function name is flush left. + +Break up long lines (> ~80 characters) and use whitespace to align +things nicely. For example the arguments in a long list to a function +call should all be aligned with each other: + + align_function_arguments (argument_the_first, + argument_the_second, + argument_the_third); + +And as a special rule, in a function prototype, (as well as in the +definition), whitespace should be inserted between the parameter types +and names so that the names are aligned: + + void + align_parameter_names_in_prototypes (const char *char_star_arg, + int int_arg, + double *double_star_arg, + double double_arg); + +Note that parameters with a * prefix are aligned one character to the +left so that the actual names are aligned. + +Managing nested blocks +---------------------- +Long blocks that are deeply nested make the code very hard to +read. Fortunately such blocks often indicate logically distinct chunks +of functionality that are begging to be split into their own +functions. Please listen to the blocks when they beg. + +In other cases, gratuitous nesting comes about because the primary +functionality gets buried in a nested block rather than living at the +primary level where it belongs. Consider the following: + + foo = malloc (sizeof (foo_t)); + if (foo) { /* Yuck! */ + ... + /* lots of code to initialize foo */ + ... + return SUCCESS; + } + return FAILURE; + +This kind of gratuitous nesting can be avoided by following a pattern +of handling exceptional cases early and returning: + + foo = malloc (sizeof (foo_t)); + if (foo == NULL) + return FAILURE; + + ... + /* lots of code to initialize foo */ + ... + return SUCCESS; + +The return statement is often the best thing to use in a pattern like +this. If it's not available due to additional nesting above which +require some cleanup after the current block, then consider splitting +the current block into a new function before using goto. + +Memory allocation +----------------- + +Because much of cairo's data consists of dynamically allocated arrays, +it's very easy to introduce integer overflow issues whenever malloc() +is called. Use the _cairo_malloc2(), _cairo_malloc3(), and +_cairo_malloc2_add1 macros to avoid these cases; these macros check +for overflow and will return NULL in that case. + + malloc (n * size) => _cairo_malloc_ab (n, size) + e.g. malloc (num_elts * sizeof(some_type)) => + _cairo_malloc2 (num_elts, sizeof(some_type)) + + malloc (a * b * size) => _cairo_malloc_abc (a, b, size) + e.g. malloc (width * height * 4) => + _cairo_malloc3 (width, height, 4) + + malloc (n * size + k) => _cairo_malloc_ab_plus_c (n, size, k) + e.g. malloc (num * sizeof(entry) + sizeof(header)) => + _cairo_malloc2k (num, sizeof(entry), sizeof(header)) + +In general, be wary of performing any arithmetic operations in an +argument to malloc. You should explicitly check for integer overflow +yourself in any more complex situations. + +Mode lines +---------- + +So given the rules above, what is the best way to simplify one's life as +a code monkey? Get your editor to do most of the tedious work of +beautifying your code! + +As a reward for reading this far, here are some mode lines for the more +popular editors: +/* + * vim:sw=4:sts=4:ts=8:tw=78:fo=tcroq:cindent:cino=\:0,(0 + * vim:isk=a-z,A-Z,48-57,_,.,-,> + * -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- + */ + + +TODO +---- + +Write rules for common editors to use this style. Also cleanup/unify +the modelines in the source files. diff --git a/local/recipes/libs/cairo/source/COPYING b/local/recipes/libs/cairo/source/COPYING new file mode 100644 index 0000000000..f54969f1c9 --- /dev/null +++ b/local/recipes/libs/cairo/source/COPYING @@ -0,0 +1,33 @@ +Cairo is free software. + +Every source file in the implementation[*] of cairo is available to be +redistributed and/or modified under the terms of either the GNU Lesser +General Public License (LGPL) version 2.1 or the Mozilla Public +License (MPL) version 1.1. Some files are available under more +liberal terms, but we believe that in all cases, each file may be used +under either the LGPL or the MPL. + +See the following files in this directory for the precise terms and +conditions of either license: + + COPYING-LGPL-2.1 + COPYING-MPL-1.1 + +Please see each file in the implementation for copyright and licensing +information, (in the opening comment of each file). + +[*] The implementation of cairo is contained entirely within the "src" +directory of the cairo source distribution. There are other components +of the cairo source distribution (such as the "test", "util", and "perf") +that are auxiliary to the library itself. None of the source code in these +directories contributes to a build of the cairo library itself, (libcairo.so +or cairo.dll or similar). + +These auxiliary components are also free software, but may be under +different license terms than cairo itself. For example, most of the +test cases in the perf and test directories are made available under +an MIT license to simplify any use of this code for reference purposes +in using cairo itself. Other files might be available under the GNU +General Public License (GPL), for example. Again, please see the COPYING +file under each directory and the opening comment of each file for copyright +and licensing information. diff --git a/local/recipes/libs/cairo/source/COPYING-LGPL-2.1 b/local/recipes/libs/cairo/source/COPYING-LGPL-2.1 new file mode 100644 index 0000000000..f1ed6182c5 --- /dev/null +++ b/local/recipes/libs/cairo/source/COPYING-LGPL-2.1 @@ -0,0 +1,510 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations +below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it +becomes a de-facto standard. To achieve this, non-free programs must +be allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control +compilation and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least + three years, to give the same user the materials specified in + Subsection 6a, above, for a charge no more than the cost of + performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply, and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License +may add an explicit geographical distribution limitation excluding those +countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms +of the ordinary General Public License). + + To apply these terms, attach the following notices to the library. +It is safest to attach them to the start of each source file to most +effectively convey the exclusion of warranty; and each file should +have at least the "copyright" line and a pointer to where the full +notice is found. + + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or +your school, if any, to sign a "copyright disclaimer" for the library, +if necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James + Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/local/recipes/libs/cairo/source/COPYING-MPL-1.1 b/local/recipes/libs/cairo/source/COPYING-MPL-1.1 new file mode 100644 index 0000000000..7714141d15 --- /dev/null +++ b/local/recipes/libs/cairo/source/COPYING-MPL-1.1 @@ -0,0 +1,470 @@ + MOZILLA PUBLIC LICENSE + Version 1.1 + + --------------- + +1. Definitions. + + 1.0.1. "Commercial Use" means distribution or otherwise making the + Covered Code available to a third party. + + 1.1. "Contributor" means each entity that creates or contributes to + the creation of Modifications. + + 1.2. "Contributor Version" means the combination of the Original + Code, prior Modifications used by a Contributor, and the Modifications + made by that particular Contributor. + + 1.3. "Covered Code" means the Original Code or Modifications or the + combination of the Original Code and Modifications, in each case + including portions thereof. + + 1.4. "Electronic Distribution Mechanism" means a mechanism generally + accepted in the software development community for the electronic + transfer of data. + + 1.5. "Executable" means Covered Code in any form other than Source + Code. + + 1.6. "Initial Developer" means the individual or entity identified + as the Initial Developer in the Source Code notice required by Exhibit + A. + + 1.7. "Larger Work" means a work which combines Covered Code or + portions thereof with code not governed by the terms of this License. + + 1.8. "License" means this document. + + 1.8.1. "Licensable" means having the right to grant, to the maximum + extent possible, whether at the time of the initial grant or + subsequently acquired, any and all of the rights conveyed herein. + + 1.9. "Modifications" means any addition to or deletion from the + substance or structure of either the Original Code or any previous + Modifications. When Covered Code is released as a series of files, a + Modification is: + A. Any addition to or deletion from the contents of a file + containing Original Code or previous Modifications. + + B. Any new file that contains any part of the Original Code or + previous Modifications. + + 1.10. "Original Code" means Source Code of computer software code + which is described in the Source Code notice required by Exhibit A as + Original Code, and which, at the time of its release under this + License is not already Covered Code governed by this License. + + 1.10.1. "Patent Claims" means any patent claim(s), now owned or + hereafter acquired, including without limitation, method, process, + and apparatus claims, in any patent Licensable by grantor. + + 1.11. "Source Code" means the preferred form of the Covered Code for + making modifications to it, including all modules it contains, plus + any associated interface definition files, scripts used to control + compilation and installation of an Executable, or source code + differential comparisons against either the Original Code or another + well known, available Covered Code of the Contributor's choice. The + Source Code can be in a compressed or archival form, provided the + appropriate decompression or de-archiving software is widely available + for no charge. + + 1.12. "You" (or "Your") means an individual or a legal entity + exercising rights under, and complying with all of the terms of, this + License or a future version of this License issued under Section 6.1. + For legal entities, "You" includes any entity which controls, is + controlled by, or is under common control with You. For purposes of + this definition, "control" means (a) the power, direct or indirect, + to cause the direction or management of such entity, whether by + contract or otherwise, or (b) ownership of more than fifty percent + (50%) of the outstanding shares or beneficial ownership of such + entity. + +2. Source Code License. + + 2.1. The Initial Developer Grant. + The Initial Developer hereby grants You a world-wide, royalty-free, + non-exclusive license, subject to third party intellectual property + claims: + (a) under intellectual property rights (other than patent or + trademark) Licensable by Initial Developer to use, reproduce, + modify, display, perform, sublicense and distribute the Original + Code (or portions thereof) with or without Modifications, and/or + as part of a Larger Work; and + + (b) under Patents Claims infringed by the making, using or + selling of Original Code, to make, have made, use, practice, + sell, and offer for sale, and/or otherwise dispose of the + Original Code (or portions thereof). + + (c) the licenses granted in this Section 2.1(a) and (b) are + effective on the date Initial Developer first distributes + Original Code under the terms of this License. + + (d) Notwithstanding Section 2.1(b) above, no patent license is + granted: 1) for code that You delete from the Original Code; 2) + separate from the Original Code; or 3) for infringements caused + by: i) the modification of the Original Code or ii) the + combination of the Original Code with other software or devices. + + 2.2. Contributor Grant. + Subject to third party intellectual property claims, each Contributor + hereby grants You a world-wide, royalty-free, non-exclusive license + + (a) under intellectual property rights (other than patent or + trademark) Licensable by Contributor, to use, reproduce, modify, + display, perform, sublicense and distribute the Modifications + created by such Contributor (or portions thereof) either on an + unmodified basis, with other Modifications, as Covered Code + and/or as part of a Larger Work; and + + (b) under Patent Claims infringed by the making, using, or + selling of Modifications made by that Contributor either alone + and/or in combination with its Contributor Version (or portions + of such combination), to make, use, sell, offer for sale, have + made, and/or otherwise dispose of: 1) Modifications made by that + Contributor (or portions thereof); and 2) the combination of + Modifications made by that Contributor with its Contributor + Version (or portions of such combination). + + (c) the licenses granted in Sections 2.2(a) and 2.2(b) are + effective on the date Contributor first makes Commercial Use of + the Covered Code. + + (d) Notwithstanding Section 2.2(b) above, no patent license is + granted: 1) for any code that Contributor has deleted from the + Contributor Version; 2) separate from the Contributor Version; + 3) for infringements caused by: i) third party modifications of + Contributor Version or ii) the combination of Modifications made + by that Contributor with other software (except as part of the + Contributor Version) or other devices; or 4) under Patent Claims + infringed by Covered Code in the absence of Modifications made by + that Contributor. + +3. Distribution Obligations. + + 3.1. Application of License. + The Modifications which You create or to which You contribute are + governed by the terms of this License, including without limitation + Section 2.2. The Source Code version of Covered Code may be + distributed only under the terms of this License or a future version + of this License released under Section 6.1, and You must include a + copy of this License with every copy of the Source Code You + distribute. You may not offer or impose any terms on any Source Code + version that alters or restricts the applicable version of this + License or the recipients' rights hereunder. However, You may include + an additional document offering the additional rights described in + Section 3.5. + + 3.2. Availability of Source Code. + Any Modification which You create or to which You contribute must be + made available in Source Code form under the terms of this License + either on the same media as an Executable version or via an accepted + Electronic Distribution Mechanism to anyone to whom you made an + Executable version available; and if made available via Electronic + Distribution Mechanism, must remain available for at least twelve (12) + months after the date it initially became available, or at least six + (6) months after a subsequent version of that particular Modification + has been made available to such recipients. You are responsible for + ensuring that the Source Code version remains available even if the + Electronic Distribution Mechanism is maintained by a third party. + + 3.3. Description of Modifications. + You must cause all Covered Code to which You contribute to contain a + file documenting the changes You made to create that Covered Code and + the date of any change. You must include a prominent statement that + the Modification is derived, directly or indirectly, from Original + Code provided by the Initial Developer and including the name of the + Initial Developer in (a) the Source Code, and (b) in any notice in an + Executable version or related documentation in which You describe the + origin or ownership of the Covered Code. + + 3.4. Intellectual Property Matters + (a) Third Party Claims. + If Contributor has knowledge that a license under a third party's + intellectual property rights is required to exercise the rights + granted by such Contributor under Sections 2.1 or 2.2, + Contributor must include a text file with the Source Code + distribution titled "LEGAL" which describes the claim and the + party making the claim in sufficient detail that a recipient will + know whom to contact. If Contributor obtains such knowledge after + the Modification is made available as described in Section 3.2, + Contributor shall promptly modify the LEGAL file in all copies + Contributor makes available thereafter and shall take other steps + (such as notifying appropriate mailing lists or newsgroups) + reasonably calculated to inform those who received the Covered + Code that new knowledge has been obtained. + + (b) Contributor APIs. + If Contributor's Modifications include an application programming + interface and Contributor has knowledge of patent licenses which + are reasonably necessary to implement that API, Contributor must + also include this information in the LEGAL file. + + (c) Representations. + Contributor represents that, except as disclosed pursuant to + Section 3.4(a) above, Contributor believes that Contributor's + Modifications are Contributor's original creation(s) and/or + Contributor has sufficient rights to grant the rights conveyed by + this License. + + 3.5. Required Notices. + You must duplicate the notice in Exhibit A in each file of the Source + Code. If it is not possible to put such notice in a particular Source + Code file due to its structure, then You must include such notice in a + location (such as a relevant directory) where a user would be likely + to look for such a notice. If You created one or more Modification(s) + You may add your name as a Contributor to the notice described in + Exhibit A. You must also duplicate this License in any documentation + for the Source Code where You describe recipients' rights or ownership + rights relating to Covered Code. You may choose to offer, and to + charge a fee for, warranty, support, indemnity or liability + obligations to one or more recipients of Covered Code. However, You + may do so only on Your own behalf, and not on behalf of the Initial + Developer or any Contributor. You must make it absolutely clear than + any such warranty, support, indemnity or liability obligation is + offered by You alone, and You hereby agree to indemnify the Initial + Developer and every Contributor for any liability incurred by the + Initial Developer or such Contributor as a result of warranty, + support, indemnity or liability terms You offer. + + 3.6. Distribution of Executable Versions. + You may distribute Covered Code in Executable form only if the + requirements of Section 3.1-3.5 have been met for that Covered Code, + and if You include a notice stating that the Source Code version of + the Covered Code is available under the terms of this License, + including a description of how and where You have fulfilled the + obligations of Section 3.2. The notice must be conspicuously included + in any notice in an Executable version, related documentation or + collateral in which You describe recipients' rights relating to the + Covered Code. You may distribute the Executable version of Covered + Code or ownership rights under a license of Your choice, which may + contain terms different from this License, provided that You are in + compliance with the terms of this License and that the license for the + Executable version does not attempt to limit or alter the recipient's + rights in the Source Code version from the rights set forth in this + License. If You distribute the Executable version under a different + license You must make it absolutely clear that any terms which differ + from this License are offered by You alone, not by the Initial + Developer or any Contributor. You hereby agree to indemnify the + Initial Developer and every Contributor for any liability incurred by + the Initial Developer or such Contributor as a result of any such + terms You offer. + + 3.7. Larger Works. + You may create a Larger Work by combining Covered Code with other code + not governed by the terms of this License and distribute the Larger + Work as a single product. In such a case, You must make sure the + requirements of this License are fulfilled for the Covered Code. + +4. Inability to Comply Due to Statute or Regulation. + + If it is impossible for You to comply with any of the terms of this + License with respect to some or all of the Covered Code due to + statute, judicial order, or regulation then You must: (a) comply with + the terms of this License to the maximum extent possible; and (b) + describe the limitations and the code they affect. Such description + must be included in the LEGAL file described in Section 3.4 and must + be included with all distributions of the Source Code. Except to the + extent prohibited by statute or regulation, such description must be + sufficiently detailed for a recipient of ordinary skill to be able to + understand it. + +5. Application of this License. + + This License applies to code to which the Initial Developer has + attached the notice in Exhibit A and to related Covered Code. + +6. Versions of the License. + + 6.1. New Versions. + Netscape Communications Corporation ("Netscape") may publish revised + and/or new versions of the License from time to time. Each version + will be given a distinguishing version number. + + 6.2. Effect of New Versions. + Once Covered Code has been published under a particular version of the + License, You may always continue to use it under the terms of that + version. You may also choose to use such Covered Code under the terms + of any subsequent version of the License published by Netscape. No one + other than Netscape has the right to modify the terms applicable to + Covered Code created under this License. + + 6.3. Derivative Works. + If You create or use a modified version of this License (which you may + only do in order to apply it to code which is not already Covered Code + governed by this License), You must (a) rename Your license so that + the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape", + "MPL", "NPL" or any confusingly similar phrase do not appear in your + license (except to note that your license differs from this License) + and (b) otherwise make it clear that Your version of the license + contains terms which differ from the Mozilla Public License and + Netscape Public License. (Filling in the name of the Initial + Developer, Original Code or Contributor in the notice described in + Exhibit A shall not of themselves be deemed to be modifications of + this License.) + +7. DISCLAIMER OF WARRANTY. + + COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF + DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. + THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE + IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, + YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE + COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER + OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF + ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. + +8. TERMINATION. + + 8.1. This License and the rights granted hereunder will terminate + automatically if You fail to comply with terms herein and fail to cure + such breach within 30 days of becoming aware of the breach. All + sublicenses to the Covered Code which are properly granted shall + survive any termination of this License. Provisions which, by their + nature, must remain in effect beyond the termination of this License + shall survive. + + 8.2. If You initiate litigation by asserting a patent infringement + claim (excluding declatory judgment actions) against Initial Developer + or a Contributor (the Initial Developer or Contributor against whom + You file such action is referred to as "Participant") alleging that: + + (a) such Participant's Contributor Version directly or indirectly + infringes any patent, then any and all rights granted by such + Participant to You under Sections 2.1 and/or 2.2 of this License + shall, upon 60 days notice from Participant terminate prospectively, + unless if within 60 days after receipt of notice You either: (i) + agree in writing to pay Participant a mutually agreeable reasonable + royalty for Your past and future use of Modifications made by such + Participant, or (ii) withdraw Your litigation claim with respect to + the Contributor Version against such Participant. If within 60 days + of notice, a reasonable royalty and payment arrangement are not + mutually agreed upon in writing by the parties or the litigation claim + is not withdrawn, the rights granted by Participant to You under + Sections 2.1 and/or 2.2 automatically terminate at the expiration of + the 60 day notice period specified above. + + (b) any software, hardware, or device, other than such Participant's + Contributor Version, directly or indirectly infringes any patent, then + any rights granted to You by such Participant under Sections 2.1(b) + and 2.2(b) are revoked effective as of the date You first made, used, + sold, distributed, or had made, Modifications made by that + Participant. + + 8.3. If You assert a patent infringement claim against Participant + alleging that such Participant's Contributor Version directly or + indirectly infringes any patent where such claim is resolved (such as + by license or settlement) prior to the initiation of patent + infringement litigation, then the reasonable value of the licenses + granted by such Participant under Sections 2.1 or 2.2 shall be taken + into account in determining the amount or value of any payment or + license. + + 8.4. In the event of termination under Sections 8.1 or 8.2 above, + all end user license agreements (excluding distributors and resellers) + which have been validly granted by You or any distributor hereunder + prior to termination shall survive termination. + +9. LIMITATION OF LIABILITY. + + UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT + (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL + DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, + OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR + ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY + CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, + WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER + COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN + INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF + LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY + RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW + PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE + EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO + THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. + +10. U.S. GOVERNMENT END USERS. + + The Covered Code is a "commercial item," as that term is defined in + 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer + software" and "commercial computer software documentation," as such + terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 + C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), + all U.S. Government End Users acquire Covered Code with only those + rights set forth herein. + +11. MISCELLANEOUS. + + This License represents the complete agreement concerning subject + matter hereof. If any provision of this License is held to be + unenforceable, such provision shall be reformed only to the extent + necessary to make it enforceable. This License shall be governed by + California law provisions (except to the extent applicable law, if + any, provides otherwise), excluding its conflict-of-law provisions. + With respect to disputes in which at least one party is a citizen of, + or an entity chartered or registered to do business in the United + States of America, any litigation relating to this License shall be + subject to the jurisdiction of the Federal Courts of the Northern + District of California, with venue lying in Santa Clara County, + California, with the losing party responsible for costs, including + without limitation, court costs and reasonable attorneys' fees and + expenses. The application of the United Nations Convention on + Contracts for the International Sale of Goods is expressly excluded. + Any law or regulation which provides that the language of a contract + shall be construed against the drafter shall not apply to this + License. + +12. RESPONSIBILITY FOR CLAIMS. + + As between Initial Developer and the Contributors, each party is + responsible for claims and damages arising, directly or indirectly, + out of its utilization of rights under this License and You agree to + work with Initial Developer and Contributors to distribute such + responsibility on an equitable basis. Nothing herein is intended or + shall be deemed to constitute any admission of liability. + +13. MULTIPLE-LICENSED CODE. + + Initial Developer may designate portions of the Covered Code as + "Multiple-Licensed". "Multiple-Licensed" means that the Initial + Developer permits you to utilize portions of the Covered Code under + Your choice of the NPL or the alternative licenses, if any, specified + by the Initial Developer in the file described in Exhibit A. + +EXHIBIT A -Mozilla Public License. + + ``The contents of this file are subject to the Mozilla Public License + Version 1.1 (the "License"); you may not use this file except in + compliance with the License. You may obtain a copy of the License at + http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the + License for the specific language governing rights and limitations + under the License. + + The Original Code is ______________________________________. + + The Initial Developer of the Original Code is ________________________. + Portions created by ______________________ are Copyright (C) ______ + _______________________. All Rights Reserved. + + Contributor(s): ______________________________________. + + Alternatively, the contents of this file may be used under the terms + of the _____ license (the "[___] License"), in which case the + provisions of [______] License are applicable instead of those + above. If you wish to allow use of your version of this file only + under the terms of the [____] License and not to allow others to use + your version of this file under the MPL, indicate your decision by + deleting the provisions above and replace them with the notice and + other provisions required by the [___] License. If you do not delete + the provisions above, a recipient may use your version of this file + under either the MPL or the [___] License." + + [NOTE: The text of this Exhibit A may differ slightly from the text of + the notices in the Source Code files of the Original Code. You should + use the text of this Exhibit A rather than the text found in the + Original Code Source Code for Your Modifications.] + diff --git a/local/recipes/libs/cairo/source/HACKING b/local/recipes/libs/cairo/source/HACKING new file mode 100644 index 0000000000..b771e58139 --- /dev/null +++ b/local/recipes/libs/cairo/source/HACKING @@ -0,0 +1,185 @@ +Hacking Cairo +============= + +This is a high-level guide to how the cairo distribution is organized +and how to get started hacking on it. Make sure you read through the +file README before continuing. + + +Coding Style +------------ + +The easiest way to write code in the cairo style is to follow code close +to the place you are hacking, but if you want a written down set of +rules, see file CODING_STYLE. + +Files for backends that depend on languages other than C (C++ or +Objective C for example) may use features specific to those languages. +For example, "//" comments are allowed, though discouraged, in those files. + + +Contact +------- + +Various ways to get in touch with other cairo developers and maintainers +have been enumerated at: + + https://cairographics.org/contact/ + +Most of that information is also reflected in the following sections. + + +Mailing Lists +------------- + +There are various mailing lists that are useful when developing cairo +code. A complete list is always available at: + + https://cairographics.org/lists/ + +It is recommended that cairo developers subscribe to all those lists. +The cairo list by itself generates much more traffic than the others +combined, so developers and contributors should not be intimidated by +the -commit and -bugs lists. + + +Bug Tracking System +------------------- + +We use a standard gitlab bug tracking system available at: + + https://gitlab.freedesktop.org/cairo/cairo/-/issues + +See file named BUGS for detailed information on reporting bugs. In short, +for straight bug reports, it's best to report them there such that they +are not lost or forgotten. For discussion of new features or +complicated issues, use the mailing list. + + +IRC +--- + +It's a great idea to hang around the cairo IRC channel if you have any +interest in cairo. We use the #cairo channel on irc.freenode.net. + +Make sure you introduce yourself if your nick is not easy to match to +the name you use on the mailing list. + + +Version Control System +---------------------- + +We use /git/ for version control. See: + + https://cairographics.org/download/ + +For more information on using git, see: + + https://freedesktop.org/wiki/Infrastructure/git/ + + +Build System +------------ + +We use the autotools build system with cairo, but with various +customizations and advanced features. Reading configure.in is your +best bet to understanding it, or just ask on IRC. + +To bootstrap the build system run ./autogen.sh. After that the +regular "./configure; make; make install" sequence can be used. +See file named INSTALL for more details. + +There is limited support for a win32 build system. +See README.win32 and Makefile.win32 files in various directories. + + +ChangeLog +--------- + +We generate ChangeLog files automatically from the git commit log. +No manual ChangeLog writing is necessary. + + +Copyrights and Licensing +------------------------ + +The cairo library is dual-licensed under LGPL and MPL. See the file +named COPYING for details. The test suites are more liberal, and are +allowed to include GPL code. + +When writing new code, update the file headers to add your (or your +employers) copyright line and contributor line. If adding new files +or splitting a file, copy the file header from other files. + + +Source Code +----------- + +The library source code and headers live in the src/ directory. +See src/README for more information. + + +Regression Test Suite +--------------------- + +Cairo has a fairly extensive regression-testing suite. Indeed, without +these tests it would be impossible to make a cairo release without +introducing tens of regressions. We still manage to introduce +regressions with each release even with the hundreds of tests we already +have. + +The regression test suite is located under the test/ directory. +See test/README for more information. + + +Performance Test Suite +---------------------- + +There is a performance test suite located under the perf/ directory. +A collection of traces of real-world behavior are also available in the +cairo-traces repository, which can be used in isolation or hooked in +with the main performance test suite. See perf/README for more +information. + + +Boilerplate +----------- + +The cairo-boilerplate is a small private library used by the regression +and performance test suites. It includes the boilerplace code needed +to initialize various backends for the test suites, as well as allow +tweaking some of the internal workings of the backends for more testing. + +The boilerplate code is localted under the boilerplate/ directory. +See boilerplate/README for more information. + + +Documentation +------------- + +Cairo uses the gtk-doc system for reference API documentation. + +The reference documentation is located under doc/public. +See doc/public/README for more information. + +For more documentation including frequently asked questions, tutorials, +samples, roadmap, todo list, etc visit: + + https://cairographics.org/documentation/ + +Some of those should gradually be moved to doc/. + + +Utilities +--------- + +We have developed several utilities useful for writing cairo or code +that uses cairo. These tools can be found under the util/ directory. +See util/README for more information. + + +Releasing +--------- + +Now you are a cairo maintainer, so what? See file named RELEASING. + diff --git a/local/recipes/libs/cairo/source/INSTALL b/local/recipes/libs/cairo/source/INSTALL new file mode 100644 index 0000000000..2229680496 --- /dev/null +++ b/local/recipes/libs/cairo/source/INSTALL @@ -0,0 +1,47 @@ +Installation Instructions +========================= + +Requirements +------------ +As well as the requirements listed in README, the meson build also requires: + meson (http://mesonbuild.com) + ninja (http://ninja-build.org) + +Basic Installation +------------------ + meson setup $builddir + ninja -C $builddir + ninja -C $builddir install + +where $builddir is the name of the directory where the build artifacts +will be written to. + +Some of the common options that can be used with "meson setup" include: + +Set the install prefix. + --prefix= + +Set the build type. Some common build types include "debug" and "release" + --buildtype= + +Compiler and linker flags can be set with the CFLAGS and LDFLAGS +environment variables. + +Configuring cairo backends +-------------------------- +After running "meson build", "meson configure" can be used to display +or modify the build configuration. + +eg + + Display configuration: + meson configure $builddir + + Enable pdf and disable ps: + meson configure $builddir -Dpdf=enabled -Dps=disabled + +The "-D" options can also be used with "meson setup" + +Tests +----- +Refer to test/README diff --git a/local/recipes/libs/cairo/source/NEWS b/local/recipes/libs/cairo/source/NEWS new file mode 100644 index 0000000000..71bec98740 --- /dev/null +++ b/local/recipes/libs/cairo/source/NEWS @@ -0,0 +1,8349 @@ +Release 1.18.4 (2025-03-08 Emmanuele Bassi ) +============================================================== + +A new stable release. + +The dependency on LZO has been made optional through a build time +configuration toggle. [!580] + +You can build Cairo against a Freetype installation that does not have the +FT_Color type. [#792] + +Cairo tests now build on Solaris 11.4 with GCC 14. [!599] + +The DirectWrite backend now builds on MINGW 11. [!600] + +Thanks to Luca Bacci, the DirectWrite backend now supports font +variations and proper glyph coverage. [#877, !602] + +Support for Windows 98 has been removed. The minimum requirement for +Windows is now Vista. + +Release 1.18.2 (2024-09-01 Emmanuele Bassi ) +============================================================== + +A new stable release. + +The malloc-stats code has been removed from the tests directory [#640]; the +canonical location for it is: https://github.com/behdad/malloc-stats + +Cairo now requires a version of pixman equal to, or newer than, 0.40. [!522] + +There have been multiple build fixes for newer versions of GCC [!525, !542]; +for MSVC [#808]; for Solaris [!540]; and on macOS 10.7 [#810]. + +PNG errors caused by loading malformed data are correctly propagated to +callers, so they can handle the case. [!524] + +Both stroke and fill colors are now set when showing glyphs on a PDF +surface. [#813] + +All the font options are copied when creating a fallback font object. [#819] + +When drawing text on macOS, Cairo now tries harder to select the appropriate +font name. [#811] + +Cairo now prefers the COLRv1 table inside a font, if one is available. [!537] + +Cairo requires a C11 toolchain when building. [!479] + +Release 1.18.0 (2023-09-20 Emmanuele Bassi ) +============================================================== + +The first stable cairo release in five years should be cause for celebration. + +All the API added in the 1.17 development cycle is now considered stable, and +will not change. + +Many thanks to all the contributors for this release. + +The cairo-sphinx tool has been removed; we could not find any instruction on +how to use it, and no user answered our call for help. If you were using +cairo-sphinx, please reach out to the cairo maintainers. + +Cairo now implements Type 3 color fonts for PDF. Thanks to Adrian Johnson for +his work on this feature. + +Khaled Hosny contributed multiple documentation fixes, to ensure that the +cairo API reference is up to date. Khaled also fixed multiple compiler +warnings generated when building cairo. + +The XML surface has been removed; it was disabled by default when building +cairo, and we could not find any downstream distributor that would enable +it. + +The Tee surface is now automatically enabled. Downstream distributors of +cairo have been enabling for years it in order to build Firefox. + +Fujii Hironori and Adrian Johnson fixed multiple issues with the DWrite +font backend. + +John Ralls improved the Quartz surface; mainly, Quartz surfaces now use +the main display ColorSpace, speeding up rendering operations. + +Cairo now hides all private symbols by default on every platform; the old +"slim" symbols hack to alias internally used symbols has been dropped, in +favor of using `-Bsymbolic-functions` with toolchains that support it. + +Uli Schlachter fixed multiple memory leaks in the code base and test suite, +and helped with many reviews and general maintenance. + +Marc Jeanmougin added new API to expose the Pixman dithering filter to cairo +patterns; this is currently implemented only for image surfaces. + +Release 1.17.8 (2023-01-30 Emmanuele Bassi ) +============================================================== + +A new cairo snapshot! And it only took less than one year, this time! + +Many thanks to everyone who contributed to cairo, and especially +to (in no particular order): + +- Adrian Johnson +- Khaled Hosny +- Behdad Esfahbod +- Matthias Clasen +- Uli Schlachter +- Manuel Stoeckl +- Fujii Hironori +- Tim-Philipp Müller +- Luca Bacci +- Caolán McNamara +- John Ralls + +In a continuing effort to reduce the amount of legacy code, and increase +the long-term maintainability of cairo, the following backends have been +removed: + +- GL and GLES drawing + +Additionally, cairo's Autotools build system has been removed; from now on, +cairo will only support the Meson build system. While the end result should +be identical, further testing is appreciated. + +In this snapshot, cairo gained support for rendering COLRv1 fonts, and +rendering SVG and COLRv1 fonts with custom palettes. + +Support for macOS and Windows has been improved, with lots of build and bug +fixes. + +Lots of safety issues have been fixed, with array bounds checking and +plugging memory leaks, as well as fixes for bugs identified via fuzzying. + +This is going to be the last snapshot of the 1.17 development cycle; we only +expect minor bug fixing and improvements until the 1.18.0 release. + +Release 1.17.6 (2022-03-18 Emmanuele Bassi ) +============================================================== + +I spy with my little eye… a cairo snapshot! + +First of all, many, many thanks to everyone who contributed to cairo +during this development cycle. A special thank you goes to: + +- Adrian Johnson +- Uli Schlachter + +for their tireless efforts in ensuring that the lights are still on +in the cairo project. + +This snapshot sees the removal of the following backends and platform +support: + +- Qt4 +- BeOS +- OS/2 +- DirectFB +- DRM +- Cogl +- OpenVG + +Thanks to all past contributors for their work on them. If you were using +any of these backends then you will need to stick to cairo 1.16. + +To offset the removal of the backends above, Adrian Johnson landed the +DWrite font rendering backend on Windows. + +There have been multiple improvements in the Quartz backend, courtesy of +John Ralls. + +Tim-Philipp Müller has kept the Meson build in top shape. + +This snapshot is going to be the **last** release of cairo with the +Autotools build system. The Meson build has seen many improvements and +it is considerably easier to maintain and faster to build. + +Release 1.17.4 (2020-11-27 Bryce Harrington ) +======================================================================== + +Thank you to the many people who have contributed the large number of +bug fixes and refinements since 1.17.2. + +A particularly noteworthy improvement in this release is the addition of +the meson build system as an alternative to autotools. Autotools is +still used for producing the releases, so will be the default in the +tarball and presumably will still be preferred by distro packagers of +Cairo. It should be possible to build the release tarball using meson, +but as this is new functionality consider it still a work in progress. +The meson configuration has striven to track the autotools +implementation but be aware there may still be some differences between +the two. + +Continuous Integration configurations have been added that enable +testing on a variety of platforms including Fedora, Windows MSVC, etc. +This work has helped in identifying updates and fixes including +adjusting to changes in API calls in dependencies like rsvg and +fontconfig, and to fix platform-specific build issues. + +The cogl Cairo backend underwent significant development this cycle. +Cogl provides GPU accelerated drawing support. The development work +includes implementation of core functionality, performance +optimizations, and stabilization. + +Subpixel positioning support allows improved glyph outlines with the +FreeType font backend. + +For a complete log of changes, please see + + https://cairographics.org/releases/ChangeLog.1.17.4 + +[On a personal note, this will be my last release for Cairo. My Cairo +time availability has been non-existent (particularly this crazy past +year). The release process is well documented and hopefully will help +whomever picks up the baton from here.] + + +Release 1.17.2 (2019-01-31 Bryce Harrington ) +======================================================================== +This snapshot provides the new support for writing floating point +formats as 16 bpc PNGs, with support for RGBA128F and RGB96F formats. +This new feature increases Cairo's pixman version requirement to 0.36.0. + +Beyond this are a range of bugfixes and some work on establishing CI for +Cairo. + +For a complete log of changes, please see + + https://cairographics.org/releases/ChangeLog.1.17.2 + +API Changes +----------- +None + +Dependency Changes +------------------ +pixman 0.36.0 + + +Release 1.16.0 (2018-10-19 Bryce Harrington ) +======================================================================== +This new stable release incorporates a number of improvements made in +the four years since 1.14.0. + +Of particular note is a wealth of work by Adrian Johnson to enhance PDF +functionality, including restoring support for MacOSX 10.4, metadata, +hyperlinks, and more. + +Much attention also went into fonts, including new colored emoji glyph +support, variable fonts, and fixes for various font idiosyncrasies. + +Other noteworthy changes include GLESv3 support for the cairo_gl +backend, tracking of SVG units in generated SVG documents, and cleanups +for numerous test failures and related issues in the PDF and Postscript +backends. + +For a complete log of changes, please see + + https://cairographics.org/releases/ChangeLog.1.16.0 + +Features and Enhancements +------------------------- +* Add support for OpenGL ES 3.0 to the gl backend. +* The PDF backend has gained support for a range of widely used + features, including thumbnails, page labels, metadata, document + outlines, structured text, hyperlinks, and tags. Tags permit adding + logical info such as headings, tables, figures, etc. that facilitates + indexing, accessibility, text reflow, searching, and extraction of the + tagged items to other software. For details on this new PDF + functionality, see: + https://lists.cairographics.org/archives/cairo/2016-June/027427.html +* Variable font support. Variable fonts are single font files with + various typography characteristics, such as weight or slant, that users + of the font can adjust between two points. Effectively this enables a + single font to behave as multiple fonts. +* Restore MacOSX 10.4 support. Cairo had dropped 10.4 support when + moving to the CoreText API. Now we automatically detect which API to + use via dynamic linking, so can resume supporting this older version + of MacOSX. +* Support colored emoji glyphs, stored as PNG images in OpenType fonts. +* Skia backend is removed +* Use Reusable streams for forms in Level 3 Postscript. +* Add CAIRO_MIME_TYPE_EPS mime type for embedding EPS files. +* Add CCITT_FAX mime type for PDF and PS surfaces +* svg: add a new function to specify the SVG document unit + (Bug #90166) +* Use UTF-8 filenames on Windows + + +API Changes +----------- +Several new APIs were added. No existing APIs were altered. + +New PDF functionality: + + * cairo_pdf_surface_add_outline + * cairo_pdf_surface_set_metadata + * cairo_pdf_surface_set_page_label + * cairo_pdf_surface_set_thumbnail_size + * cairo_tag_begin + * cairo_tag_end + * CAIRO_STATUS_TAG_ERROR + +New error status items for problems relating to PDF tagging: + + * CAIRO_STATUS_WIN32_GDI_ERROR + * CAIRO_STATUS_FREETYPE_ERROR + * CAIRO_STATUS_PNG_ERROR + + New error status items for handling of GDI, libfreetype, and libpng + errors, respectively. + + +Setting up Win32 surfaces for HDC with alpha channels: + + * cairo_win32_surface_create_with_format + + New API for added PDF functionality (see above), and new error + status item for problems relating to PDF tagging. + +Variable fonts: + + * cairo_font_options_get_variations + * cairo_font_options_set_variations + +Tracking units in SVG documents: + + * cairo_svg_surface_set_document_unit + * cairo_svg_surface_get_document_unit + + + +Dependency Changes +------------------ +None + + +Performance Optimizations +------------------------- +None + + +Notable Bug Fixes +----------------- +* Fix thin lines that don't show up when printing in Inkscape due to + overly aggressive culling. + (Bug #77298) +* Fix playback of recording surfaces into PDF surfaces, where objects + with negative coordinates were not getting drawn. To address this, + the coordinate systems for PDF and PS have been changed to match + cairo's coordinate system. This allows recording surfaces to be + emitted in cairo coordinates, and results in the same origin being + used for all operations when using the recording surface XObject. + Test cases for PDF and PS have also been updated accordingly. + (Bug #89232) +* Fix "invalidfont" error on some printers when printing PDFs with + embedded fonts that have glyphs (such as spaces) with + num_contours == 0. (Bug #79897) +* Fix missing glyphs such as thin dashes, which get scaled to 0 in + userspace and thus have their drawing operations culled. (Bug #94615) +* Fix other oddities caused by variously idiosyncratic fonts. +* Fix a data race in freed_pool discovered by Firefox's cairo usage. + The patch adads atomic int load and store functions, with relaxed + memory ordering. (Bug #90318) +* Handle SOURCE and CLEAR operators when painting color glyphs. + (Bug #102661) +* Fix falling back to system font with PDFs using certain embedded + fonts, due to truncated font names. + (Bug #103249) +* Prevent curved strokes in small ctms from being culled from vector + surfaces + (Bug #103071) +* Fix assertion hit with PDFs using Type 4 fonts rendered with user + fonts, due to error when destroying glyph page. + (Bug #103335) +* Prevent invalid ptr access for > 4GB images. + (Bug #98165) +* pdf: Fix internal links pointing to other pages, by pre-calculating + page heights so that link positions can be calculated more accurately. +* Fix error reporting in the xcb backend if fallback fails. Instead of + returning NULL when the X11 server can't do some operation, return a + surface in an error state. +* Clarify documentation regarding device scale inheritance and the units + used in cairo_surface_create_similar_image. + (Bug #99094) +* Call XSync in the xlib backend before setting the error handler to + ignore errors for certain requests, to make sure all pending errors + are handled first. +* Fix regression with text containing space character on Win32. + (Bug: https://gitlab.freedesktop.org/cairo/cairo/issues/339) + +For a more comprehensive listing of fixed bugs, see the release notes for the +individual 1.15.x releases. + + +Release 1.15.14 (2018-09-19 Bryce Harrington ) +============================================================================ +We're nearly ready to finalize the 1.16.0 release, so this snapshot +can be considered a beta for 1.16. + +The most notable change this release is a performance optimization for +windows, discussed below. Other than that, much of the development +focus was on final polish and stability as we prepare for 1.16. + +Some attention went into getting the testsuite passing at least for the +image backend. The Cairo testsuite depends on external software like +Pixman, and changes in the rendering behavior of these dependencies +change test behavior, leading to false positives. + +Results from the Coverity static testing tool were also reviewed. Most +of the issues flagged were false positives, but there were several +legitimate problems found and fixed. + +For a complete log of changes, please see + + https://cairographics.org/releases/ChangeLog.1.15.14 + +Features and Enhancements +------------------------- +* Add more FreeeType font color conversions to support COLR/CPAL +* Update test reference images against current pixman + +API Changes +----------- +None + +Dependency Changes +------------------ +None + +Performance Optimizations +------------------------- +Vasily Galkin introduced a Win32 performance optimization for +CAIRO_OPERATOR_SOURCE when copying data from a backbuffer to an argb32 +surface corresponding to a Win32 DC. With this, argb32 drawing should +perform as fast as typical dibsection-buffered GDI drawing. See the +Cairo mailing list for April 2018 for data and discussion of the +performance improvements. + + +Bug Fixes +--------- +* Fix crash when rendering Microsoft's Segoe UI Emoji Regular font. +* Fix build breakage with glesv3 enabled due to non-existant glesv3.pc. +* Fix memory leaks found by Coverity +* Fix incorrect null ptr handling found by Coverity +* Fix test compilation when font-config is disabled +* Use _cairo_malloc instead of malloc (Bug #101547) (CVE-2017-9814) +* Fix assertion failure in the freetype backend (Bug #105746) + + +Release 1.15.12 (2018-04-04 Bryce Harrington ) +======================================================================== +The main focus for this release is the addition of Variable Font +support. Variable fonts are single font files with various typography +characteristics, such as weight or slant, that users of the font can +adjust between two points. Effectively this enables a single font to +behave as multiple fonts. + +The Skia backend is disabled in this release, due to severe bitrot, and +will be removed in future releases. Contact the cairo team if you have +a need of this backend. + +For a complete log of changes, please see + + https://cairographics.org/releases/ChangeLog.1.15.12 + +Features and Enhancements +------------------------- +* Variable font support +* Skia backend is disabled + +API Changes +----------- +* cairo_font_options_get_variations() and + cairo_font_options_set_variations() are added. + +Dependency Changes +------------------ +None + +Performance Optimizations +------------------------- +None + +Bug Fixes +--------- +* Fix errors in csi-trace --help and --version options +* Fix a 'memory leak' in the image compositor, with + pixman_glyph_cache_t. +* Fix access of uninitialized memory found by valgrind + (Bug #91271) +* Fix improper initialization of memory in + _cairo_ft_font_face_create_for_pattern() + (Bug #105084) +* Fix multi-monitor virtual desktop with negative coords on Win32 + (Bug #100793) +* Fix issues occurring with older FreeType versions. + + +Release 1.15.10 (2017-12-07 Bryce Harrington ) +======================================================================== +This release adds GLESv3 support to the cairo_gl backend, adds +tracking of SVG units in generated svg documents, and cleans up numerous +test failures and related issues in the PDF and Postscript backends. + +For a complete log of changes, please see + + https://cairographics.org/releases/ChangeLog.1.15.10 + +Features and Enhancements +------------------------- +* Add support for OpenGL ES 3.0 to the gl backend. +* Use Reusable streams for forms in Level 3 Postscript. +* Add CAIRO_MIME_TYPE_EPS mime type for embedding EPS files. +* Add CCITT_FAX mime type for PDF and PS surfaces +* svg: add a new function to specify the SVG document unit + (Bug #90166) +* Use UTF-8 filenames on Windows + +API Changes +----------- +* cairo_svg_surface_set_document_unit() and + cairo_svg_surface_get_document_unit() + +Dependency Changes +------------------ +None + +Performance Optimizations +------------------------- +None + +Bug Fixes +--------- +* Fix regression in gles version detection +* Fix undefined-behavior with integer math. +* Handle SOURCE and CLEAR operators when painting color glyphs. + (Bug #102661) +* Convert images to rgba or a8 formats when uploading with GLESv2 +* Use _WIN32 instead of windows.h to check for windows build. +* Fix sigabrt printing documents with fonts lacking the mandatory .nodef + glyph. + (Bug #102922) +* Prevent curved strokes in small ctms from being culled from vector + surfaces + (Bug #103071) +* Fix painting an unbounded recording surface with the SVG backend. +* Fix falling back to system font with PDFs using certain embedded + fonts, due to truncated font names. + (Bug #103249) +* Fix handling of truetype fonts with excessively long font names + (Bug #103249) +* Fix race conditions with cairo_mask_compositor_t + (Bug #103037) +* Fix build error with util/font-view +* Fix assertion hit with PDFs using Type 4 fonts rendered with user + fonts, due to error when destroying glyph page. + (Bug #103335) +* Set default creation date for PDFs +* Prevent invalid ptr access for > 4GB images. + (Bug #98165) +* Prevent self-copy infinite loop in Postscript surface. +* Fix padded image crash in Postscript surface. +* Fix annotation bugs in PDFs and related memory leaks +* Fix test failures and other assorted issues in ps and pdf code. +* Fix code generation when using GCC legacy atomic operations + (Bug #103559) +* Fix various compilation warnings and errors. +* Fix various distcheck errors with private symbols, doxygen formatting, + etc. + +Release 1.15.8 (2017-08-29 Bryce Harrington ) +======================================================================== +This small snapshot provides new colored emoji glyph support, and a +handful of minor fixes. + +For a complete log of changes, please see + + https://cairographics.org/releases/ChangeLog.1.15.8 + +Features and Enhancements +------------------------- +* Support colored emoji glyphs, stored as PNG images in OpenType fonts. + + +API Changes +----------- +None + +Dependency Changes +------------------ +None + +Performance Optimizations +------------------------- +None + +Bug Fixes +--------- + +* pdf: Fix internal links pointing to other pages, by pre-calculating + page heights so that link positions can be calculated more accurately. + +* image: Fix crash on negative lengths + +* win32: Fix initialization of mutexes for static builds + +* pdf: Don't emit /PageLabel dict when no labels defined + +* font: Fix color font loading on big-endian systems + +* font: Fix color font support infinite-loop with empty glyphs + +* Fix off by one check in cairo-image-info.c + + + +Release 1.15.6 (2017-06-13 Bryce Harrington ) +======================================================================== +This new snapshot incorporates changes over the past half-year since the +1.15.4 snapshot, including all the fixes from the 1.14 release series. + +The PDF code continues to be enhanced, and we're restored MacOSX 10.4 +support. Font-related fixes and improved error handling for X round out +the release. + +For a complete log of changes, please see + + https://cairographics.org/releases/ChangeLog.1.15.6 + + +Features and Enhancements +------------------------- +* Detect if variable fonts have synthesized bold/italic or non-default + variants, and use a fallback font where needed. + +* Restore MacOSX 10.4 support. Cairo had dropped 10.4 support when + moving to the CoreText API. Now we automatically detect which API to + use via dynamic linking, so can resume supporting this older version + of MacOSX. + + +API Changes +----------- +None + +Dependency Changes +------------------ +None + +Performance Optimizations +------------------------- +None + +Bug Fixes +--------- +* Fix error reporting in the xcb backend if fallback fails. Instead of + returning NULL when the X11 server can't do some operation, return a + surface in an error state. + +* Call XSync in the xlib backend before setting the error handler to + ignore errors for certain requests, to make sure all pending errors + are handled first. + +* Fix text-glyph-range for quartz-font. Use 0xFFFF instead of 0 for + invalid index tracking. + +* Fix handling of Supplementary Multilingual Plane (SMP) Unicode + characters in quartz-font. + +* Fix various issues in the drm backend including updating API usage and + general code cleanup. + +* Clarify documentation regarding device scale inheritance and the units + used in cairo_surface_create_similar_image. + Bug #99094. + + +Release 1.15.4 (2016-12-9 Bryce Harrington ) +======================================================================= +This new snapshot incorporates changes over the past year since the +1.15.2 snapshot, including all the fixes from the 1.14 release series. + +Of particular note in this snapshot is a wealth of work by Adrian +Johnson to enhance PDF support, as well as numerous bug fixes provided +by him and other contributors. + +For a complete log of changes since the last release, please see: + + https://cairographics.org/releases/ChangeLog.1.15.4 + +Features +-------- +* The PDF backend has gained support for a range of widely used + features, including thumbnails, page labels, metadata, document + outlines, structured text, hyperlinks, and tags. Tags permit adding + logical info such as headings, tables, figures, etc. that facilitates + indexing, accessibility, text reflow, searching, and extraction of the + tagged items to other software. For details on this new PDF + functionality, see: + + https://lists.cairographics.org/archives/cairo/2016-June/027427.html + + +API Changes +----------- + + cairo_win32_surface_create_with_format + + Added a cairo API to set up Win32 surfaces for HDC with alpha channels. + + cairo_pdf_surface_add_outline + cairo_pdf_surface_set_metadata + cairo_pdf_surface_set_page_label + cairo_pdf_surface_set_thumbnail_size + cairo_tag_begin + cairo_tag_end + CAIRO_STATUS_TAG_ERROR + + New API for added PDF functionality (see above), and new error + status item for problems relating to PDF tagging. + + CAIRO_STATUS_WIN32_GDI_ERROR + CAIRO_STATUS_FREETYPE_ERROR + CAIRO_STATUS_PNG_ERROR + + New error status items for handling of GDI, libfreetype, and libpng + errors, respectively. + +Dependency Changes +------------------ +None + +Performance Optimizations +------------------------- +None + +Bug Fixes +--------- +* Bug fixes from 1.15.2 (see the 1.15.2 NEWS for details) + +* Fix playback of recording surfaces into PDF surfaces, where objects + with negative coordinates were not getting drawn. To address this, + the coordinate systems for PDF and PS have been changed to match + cairo's coordinate system. This allows recording surfaces to be + emitted in cairo coordinates, and results in the same origin being + used for all operations when using the recording surface XObject. + Test cases for PDF and PS have also been updated accordingly. + (Bug #89232) + +* Fix "invalidfont" error on some printers when printing PDFs with + embedded fonts that have glyphs (such as spaces) with + num_contours == 0. (Bug #79897) + +* Fix missing glyphs such as thin dashes, which get scaled to 0 in + userspace and thus have their drawing operations culled. (Bug #94615) + +* Fix other oddities caused by variously idiosyncratic fonts. + +* Fix deadlock when destruction of a scaled font indirectly triggers + destruction of a second scaled font, causing the global cache to be + locked twice. (Bug #93891) + +* Fix X errors reported to applications when shmdt() is called before + the Attach request is processed, due to missing xcb and xlib calls. + +* Fix random failure in record-paint-alpha-clip-mast test case, caused + by an incorrect assumption that a deferred clear can be skipped. + (Bug #84330) + +* Fix crash when dealing with an XShmGetImage() failure, caused by a + double free in _get_image_surface(). (Bug #91967) + +* Fix invalid execution of ASCII85 data by the PS interpreter that the + image operator didn't use, by flushing the extraneous data after + drawing the image. (Bug #84811) + +* Fix decoding of Adobe Photoshop's inverted CMYK JPEG files in PDF + export. + +* Fix unbounded surface assertion in win32-print code. + +* Fix a data race in freed_pool discovered by Firefox's cairo usage. + The patch adads atomic int load and store functions, with relaxed + memory ordering. (Bug #90318) + +* Cleanup debugging text sent to stdout instead of log. (Bug #95227) + +* Fix build issue when using non-GNU strings utility. (Bug #88639) + +* Fix build of cairo modules as regular modules, not as versioned shared + libraries. (Bug #29319) + +* Fix build on win32 using gcc 5.4. + +* Fix build of script backend to require zlib. + +* Update test suite reference images using Debian Jessie 64-bit and + poppler current as of June, 2016. + +* Various improvements to documentation and tests, compiler warning + fixes, and an assortment of code refactoring and cleanup. + + +Release 1.15.2 (2015-12-10 Bryce Harrington ) +======================================================================== +This release is largely a rollup to include a variety of fixes that +didn't make the cut for the stable 1.14.2 and 1.14.4 releases, as well +as all the fixes from those releases. Notably this includes a highly +requested new API for Win32 surfaces. + +For a complete log of changes since the last release, please see: + + https://cairographics.org/releases/ChangeLog.1.15.2 + +Features +-------- +None + +API Changes +----------- + + cairo_win32_surface_create_with_format + + Added a cairo API to set up Win32 surfaces for HDC with alpha channels. + +Dependency Changes +------------------ +None + +Performance Optimizations +------------------------- +None + +Bug Fixes +--------- +* All the bug fixes from 1.14.2, 1.14.4, and 1.14.6 + +* Fix xcb/xlib compilation and calls. Make image boxes behave when SHM + is not available. + +* Fix various issues with printing and transparent images on Win32. + +* Fix thin lines that don't show up when printing in Inkscape due to + overly aggressive culling. + (Bug #77298) + +* Fix broken printing via pdf when glyph 0 is used for rendering, + resulting in missing spaces and letters. + (Bug #89082) + +* Fix crash for certain glyphs in opentype fonts. + (Bug #91902) + +* Fix incorrect rendering of SVG paths with more than one subpath. If + more than one trap is passed in then it's guaranteed that the returned + traps will have their left edge to the left of their right edge, but + if only one trap is passed in then the function always returns without + doing anything. + (Bug #90984) + +* Improve rendering with Quartz to better match pixman's blending and + filtering behavior. + + +Release 1.14.6 (2015-12-09 Bryce Harrington ) +======================================================================== +Simple bugfix release to fix one Windows issue. + +For a complete log of changes since 1.14.4, please see: + + https://cairographics.org/releases/ChangeLog.1.14.6 + +Features +-------- +None + +API Changes +----------- +None + +Dependency Changes +------------------ +None + +Performance Optimizations +------------------------- +None + +Bug Fixes +--------- +* Fix failure on Windows due to reference of the function + cairo_win32_surface_create_with_format(), which isn't included in the + 1.14.4 release. (Bug #92771) + + +Release 1.14.4 (2015-10-28 Bryce Harrington ) +======================================================================== +Just in time for Halloween we see another bug-fix release for Cairo. +This brings a few dozen straightforward bug fixes with no API changes. + +In addition, this includes a typical assortment of fixes to tests, +cleanup of warnings and memory leaks, correction of misspellings, +updates to documentation, etc. + +For a complete log of changes since 1.14.2, please see: + + https://cairographics.org/releases/ChangeLog.cairo-1.14.4 + +Features +-------- +None + +API Changes +----------- +None + +Dependency Changes +------------------ +None + +Performance Optimizations +------------------------- +None + +Bug Fixes +--------- +* Avoid appending empty slots to user data arrays. Fixes a memory + consumption regression since commit 9341c254a. + +* Return a better error (file-not-found) when setting up pango on + devices where the font files don't have read permissions. + +* Fix regression in the font size of canvas text in Inkscape when + compiled with the Quartz backend. (Bug #84324) + +* Fix _cairo_gl_shader_bind_matrix() to maintain compatibility with + OpenGL ES 2.0. Manually transpose the matrix. + +* Fix incorrect font descriptor conversion when the font matrix yy is + negative. (Bug #90538) + +* Fix crash when using a complex path for clip and stroke due to + discarding the intersection exactly at the top edge. + (Bug #74779) + +* Fix cairo_get_locale_decimal_point() on Android + +* Fix compilation problem on AIX due to conflicting usage of symbol + 'jmpbuf'. (Bug #89339) + +* Fix broken rendering with XCB due to snapshotting of uploaded part of + surfaces. (Bug #67505) + +* Fix loss of alpha when copying a mask for a cairo recording surface, + resulting in a double copy. (Bugs #73038, #73901) + +* Fix incorrect recording of certain paths with script surfaces. + (Bug #91054) + +* Fix typo in definition of MAYBE_WARN in configure script. + (Bug #89750) + +* Fix use of filename variable after it's been freed. + (Bug #91206) + +* Fix out of bounds access when printing pattern. + (Bug #91266) + +* Fix incorrect size calculation in glyph cache unlocking for Cairo GL + compositor. + (Bug #91321) + +* Fix memory leak in _cairo_gl_pattern_texture_setup() + (Bug #91537) + +* Fix transparent images in win32-print. + (Bug #91835) + +* Fix _put_shm_image_boxes and _put_image_boxes when no SHM available + with XCB. + + +Release 1.14.2 (2015-03-09 Bryce Harrington ) +==================================================================== +This release provides collected bug fixes, along with one feature +enhancement for the xcb backend, and a small performance improvement for +fonts. + +The running theme of the bug fixes is platform-specific issues, both +build and run-time. Platforms with fixes include Sparc, AIX, Windows +(mingw), and Windows (MSVC8). Memory leaks, valgrind issues, and PDF +issues round out our list. + +It's come to light that changes in cairo 1.14 resulted in breakage on +MacOS X 10.4. We've not yet determined whether to fix up the support, +or excise the 10.4-specific code and support only OS X 10.5 or newer. +Meantime, we'll only advertise cairo as working on OS X 10.5. + +Features +-------- + * Improve xcb's handling of per-screen subpixel ordering. If no + Xft.rgba property is specified, default to the screen's subpixel + order. + +API Changes +----------- +None + +Dependency Changes +------------------ +None + +Performance Optimizations +------------------------- + * Improve performance of cpu_to_be32 and be32_to_cpu, making truetype + subsetting of large fonts run about 15% faster. + +Bug Fixes +--------- + * Fix unaligned access on sparc with the compact font format (CFF). + Unlike truetype, all data in CFF is not aligned. + (Debian bug #712836) + * Fix unaligned access on sparc with tor-scan-converter's memory pool. + * Fix crash when loading a PDF with a transformed image. + (fdo bug #85151) + * Fix regression on mingw for bigendian test due to removal of file + extension for executables. + (fdo bug #85120) + * Fix handling of backslash in PDF interpreter + (fdo bug #85662) + * Fix crash in xlib and xcb renderers when swapping a 0-sized glyph + * Fix bug with RTL text in PDF operators + (fdo bug #86461) + * Fix compilation 'cairo-path-stroke-traps.c' with MSVC8 + (fdo bug #84908) + * Fix crash in _fill_xrgb32_lerp_opaque_spans when a span length is + negative. + * Fix valgrind error by releasing pattern created by + cairo_pattern_create_rgb(). + * Fix valgrind errors when running cairo-test-suite. + * Fix memory leak in recording surface replays + (fdo bug #87898) + * Fix destruction of fonts in api-special-cases test. + (fdo bug #87567) + * Fix duplicated surface push on similar-image, preventing trivial GTK3 + program traces from being replayable, with an error message about + invalid values for the size of the input. + (fdo bug #73580) + * Fix crash when win32 surface's image size does not cover the entire + surface. + (fdo bug #53121) + * Fix crash due to obsolete CGFontGetGlyphPath call + (fdo bug #84324) + * Fix several build issues on AIX + (fdo bugs #89338, #89340, #89356, #89354) + * Fix various documentation warnings and errors + + +Release 1.14.0 (2014-10-13 Bryce Harrington ) +==================================================================== +Hard to believe it's been over a year since our last release, but it's +not for lack of activity. This release includes contributions of a wide +assortment of bug fixes, build system improvements, warnings cleanups, +codebase refactoring, test suite repairs, and static analysis work. + +This release is lighter on features (compared with 1.12.10) but includes +a highly demanded rehaul of our image downscaling functionality, which +solves a serious problem experienced by Inkscape users when shrinking +embedded bitmaps in SVG files. The new scaling algorithms are used by +the image backend and by other backends as needed for fallbacks. + + +Features +-------- + + Filtering improvements for the image backend, in particular + down-scaling of images produces filtered images that depend on all the + pixels of the source. When using the image backend you get the + following settings: + + CAIRO_FILTER_GOOD: uses a box filter for scales less than .75 in + either direction. For scales larger than this, the same filter as + CAIRO_FILTER_BILINEAR is used. + + CAIRO_FILTER_BEST: uses a Catmull-Rom filter always. When upscaling + more than 2x this will produce anti-aliased square pixels, similar + to OS/X. + + CAIRO_FILTER_GAUSSIAN: uses PIXMAN_FILTER_BEST, which in current + pixman is the same as BILINEAR. (This is subject to change in the + future). + + xlib and xcb also use the image fallback for GOOD/BEST filters, but + note that other backends do not implement these filtering fixes yet, + however other actions may cause them to use an image fallback which + will cause these filters to be used. + + Improve handling of device transformation and scaling, allowing Cairo + to now support scaling at a device level, permitting easier, more + transparent HiDPI support. + + Support JBIG2 mime data in PDF. This allows embedding of more + compressed JPEG formats within PDF, rather than including the full + uncompressed image. Also, reduce the number of transparency groups + used by PDF to keep the file size small and viewing/printing of the + PDF fast. + + Expand the embedding section to include stencil mask support. + + Reorder font declarations to be in natural order. + + Update the Skia backend to build against current Skia (as of June + 2014). + + Drop Link-Time Optimization (LTO) support from build system. This + seems to have caused much trouble for unclear benefit, and most + distros are reverting or disabling it anyway. + + Optimize VBO size on GL to 1M and to 16k for EGL. This improves + (theoretical) performance for desktop GLX use cases while avoiding + hitting VBO memory size limitations on embedded devices. + +API Changes +----------- + + cairo_surface_set_device_scale, cairo_surface_get_device_scale: + + Sets a scale that is multiplied to the device coordinates + determined by the CTM when drawing to @surface. One common use for + this is to render to very high resolution display devices at a scale + factor, so that code that assumes 1 pixel will be a certain size + will still work. + + cairo_egl_device_get_display, cairo_egl_device_get_context: + + Support get/set of EGLContext and EGLDisplay for egl-based cairo + devices, similar to GLX. + +Dependency Changes +------------------ + + Cairo now requires glib 2.14 for its gobject helper functions, + and pixman 0.30 for downscaling. + + +Bug fixes +--------- + + Don't embed CMYK Jpeg images in svg. + + Fix tests to place output in proper location. + + Fix determination of alpha for all surfaces when recording. + + Extend oversize check to cairo_gl_surface_create_for_texture, so an + error surface is returned if the texture is too large to render to. + + Fix embedding of mime data in PDF and PS files. + + Remove useless error handling in *_reply() functions in XCB. + + Fix a double-free exposed by multithreaded apps creating and + destroying the same font concurrently. + https://bugs.freedesktop.org/show_bug.cgi?id=69470 + + Fix corrupt stacks produced by bugs in operand emission for trace. + + Fix out of bounds array access in format cache for xlib + + Don't rename glyphs used by seac operator. This can cause certain + combined characters to use their decorations (e.g. umlauts on ö) to be + lost during printing of PDFs using evince. + https://bugs.freedesktop.org/show_bug.cgi?id=70364 + + Fix crash on calling cairo_create with a finished surface + + Fix SSIZE_T definition problem when making with MSYS on Windows7 + + Fix one off issue in gl context cleanup + + Fix usage of CAIRO_STACK_ARRAY_LENGTH + + Fix rectangle stroke with non rectilinear pen + + Fix imagemask with pattern source failure on some printers. This bug + could cause files converted using pdftops to fail for example on Ricoh + printers, or opening in Adobe Distiller on Windows. + https://bugs.freedesktop.org/show_bug.cgi?id=69485 + + Fix whitespace in font names + + Fix page size in generated PDFs. When printing using pdftocairo on + larger page sizes, such as 11x17, the image would be cropped to letter + size. + https://bugs.freedesktop.org/show_bug.cgi?id=73452 + + Fix path-currentpoint test by preserving current-point in + copy_path()/append_path() sequence + + Fix generation of HTML in code docs for + cairo-format-stride-for-width. Raw HTML code was being passed + to the browser, instead of displaying normally. + https://bugs.freedesktop.org/show_bug.cgi?id=63257 + + Fix spelling of "tessellator" throughout code. We're using the + American rather than British spelling of this word. + https://bugs.freedesktop.org/show_bug.cgi?id=50411 + + Fix crash in pixman_image_composite32 + + Fix crash when trying to modify a (const) all-clipped cairo_clip_t + https://bugs.freedesktop.org/show_bug.cgi?id=75819 + + Add check_composite method to all compositors, to fix crashes in the + test suite. + + Fix crash in Firefox when scrolling on certain pages. + + Fix memory leaks found by static analysis. + + Fix build of any2ppm if fork is not available. + + Fix broken build for Qt backend, due to missing libstdc++. + + Fix typo in two cairo_uint128 functions. Fixes potential build issues + on systems without a uint128 type. + + Fix build when --enable-pdf=no + + Fix cache_frozen assertions for Win32 print. + + Correctly check for xcb image surface for inplace upload + + Fix webkit-based web browser crashes due to empty boxes by skipping + over them when tesselating. + + Make pixman, libpng, and zlib paths commandline configurable for win32 + builds. + + Fix image scale on Win32 when GDI scale is not identity. + + Fix float endian configure test when using clang -O4 + + Fix compilation with Android bionic libc + + Don't try to build util/sphinx on Windows + + Fix loss of precision when emitting joins. This was caused by + discrepancies in line gradients when passing trapezoids around. + + Fix loss of precision and associated rendering issues in + cairo-tor-scan-converter from projection onto sample grid. + + Fix pixman oversampling of neighbouring edges within a cell by + eliminating self-intersections for the pixman traps compositor. + + Fix multi-line string splitting in PDFs + + Various cleanups and fixes to warnings, documentation, tests, and + build system. Improve error handling and return value checks. + Cleanup XFAIL tests and reference images. Cover recently added + functionality. + + +Release 1.12.16 (2013-08-21 Chris Wilson ) +=================================================================== +Thanks to everybody who reported a bug and helped us develop a fix, +we have amassed quite a few bug fixes. There are still more outstanding +bugs that seek attention and a little bit of TLC, but this release has +been delayed long enough... + +Bug fixes +--------- + + Set the correct orientation for simple boxes with a negative scale + factor. + + Fix the creation of the shading dictionary in PDF. + + Fix a crash in PDF when incorporating an image with CAIRO_EXTEND_PAD. + https://bugs.freedesktop.org/show_bug.cgi?id=61451 + + Avoid upscaling bitmap fonts if possible. + + Fix an assertion failure within the mempool allocator for shared memory. + + Fix allocation size for CFF subsets. + + Export cairo_matrix_t for GObject bindings. + + Fix a double free in the Quartz backend. + https://bugs.freedesktop.org/show_bug.cgi?id=62885 + + Fix origin of GDI StretchBlits for the Windows backend + https://bugs.freedesktop.org/show_bug.cgi?id=61876 + + Fix error propagation for requests to create a similar surface with + negative size. + https://bugs.freedesktop.org/show_bug.cgi?id=63196 + + Fix complex clipping of trapezoids with regions + https://bugzilla.gnome.org/show_bug.cgi?id=697357 + + Stop leaking the image data when loading PNGs + + Fix unbounded operations with a clip mask through the span compositor + https://bugs.freedesktop.org/show_bug.cgi?id=61592 + + Add missing checks before rendering to a finished surface - so we return + an error rather than hit an assert. + https://bugs.freedesktop.org/show_bug.cgi?id=68014 + + Prevent an assertion failure when creating similar GL surfaces larger + than supported by hardware. + + Prevent a double free of a similar image under Windows. + https://bugs.freedesktop.org/show_bug.cgi?id=63787 + + +Release 1.12.14 (2013-02-10 Chris Wilson ) +=================================================================== +In the last week we had a few more bugs reported and promptly resolved. +As these are a combination of regressions and stability issues, it is +time for a prompt update and release. Many thanks to everyone for +testing and reporting issues, and helping to make Cairo better. + +Bug fixes +--------- + + Prevent user callbacks accessing user-data during destroy to prevent + use-after-free bugs. + https://bugzilla.mozilla.org/show_bug.cgi?id=722975 + + Use standard names for glyphs in subset fonts (PDF). + https://bugs.freedesktop.org/show_bug.cgi?id=60248 + + Fix detection of Win98. The logic for detecting Win98 (and its broken + AlphaBlend()) was inverted, disabling AlphaBlend() for everyone. + + Prevent numeric overflow from extrapolating polygon edges to the clip + boundary and causing severe render artifacts. + https://bugs.freedesktop.org/show_bug.cgi?id=60489 + + Fix computation of glyph string coordinates when breaking up runs + for xlib. + + Fix an assertion in the win32 backend for failing to clear its + similar-images. + https://bugs.freedesktop.org/show_bug.cgi?id=60519 + + +Release 1.12.12 (2013-01-31 Chris Wilson ) +=================================================================== +The goal of this release is to fix the synchronisation problems that +were exhibited in the SHM transport for cairo-xlib. This cropped up +any place that tried to rapidly push fresh pixel data to the X server +through an ordinary image surface, such as gimp-2.9 and evince. + +Bug fixes +--------- + + Avoid replacing the entire image when uploading subimages + https://bugs.freedesktop.org/show_bug.cgi?id=59635 + + Force synchronisation for scratch SHM image buffers, so that we do + not overwrite data as it is being read by X. + https://bugs.freedesktop.org/show_bug.cgi?id=59635 (also) + + Fix typos in detecting multisampling for the GL (MSAA) backend. + + Fix a memory leak in the GL (MSAA) backend. + + Fix a reference counting bug when mapping a GL surface to an image. + + +Release 1.12.10 (2013-01-16 Chris Wilson ) +=================================================================== +A heap of bug fixes everywhere, and the gradual completion of the MSAA +backend for cairo-gl. Perhaps the most noteworthy set of the bugfixes +was the crusage lead by Behdad Eshfabod to make font handling by +pango/cairo/fontconfig fully threadsafe. This testing revealed a couple +of races that needed fixing in Cairo's scaled-font and glyph cache. + +Bug fixes +--------- + + Append coincident elements to the recording's surface bbtree so that + the list is not corrupted and the overlapping elements lost. + + Fix cairo-trace to correctly record map-to-image/unmap-image and then + replay them. + + Ignore MappingNotifies when running the XCB testsuite as they are sent + to all clients when the keyboard changes. The testsuite would detect + the unexpected event and complain. + + Handle very large images in the XCB backend. + + Fix a memory leak in the xlib/shm layer, and prevent use of the SHM + surfaces after the display is closed. + https://bugs.freedesktop.org/show_bug.cgi?id=58253 + + Handle resizing of bitmap fonts, in preparation for a fix to + fontconfig to correctly pass on the user request for scaling. + + Always include subroutine 4 (hint replacement idion) when subsetting + type 1 fonts in order to prevent a crash in cgpdftops on Mac OS/X + + Fix a couple of typos in the cairo-gobject.h header files for + introspection. + + Prevent a mutex deadlock when freeing a scaled-glyph containing a + recording-surface that itself references another scaled-glyph. + https://bugs.freedesktop.org/show_bug.cgi?id=54950 + + Make scaled-font cache actually thread-safe and prevent + use-after-frees. + + Restore support for older versions of XRender. A couple of typos and a + few forgotten chunks prevented the xlib compositor from running + correctly with XRender < 0.10. Note that there are still a few + regressions remaining. + + +Release 1.12.8 (2012-11-24 Chris Wilson ) +=================================================================== +Another couple of weeks and a few more bugs have been found and fixed, +it is time to push the next point release. Many thanks to everyone who +reported their issues and helped us track down the bugs and helped +testing the fixes. + +Bug fixes +--------- + + Expand the sanity checking for broken combinations of XSendEvent and + ShmCompletionEvent. + + Notice that "The X.Org Foundation" sometimes also identifies itself + as "The Xorg Foundation". + + Handle various ages of libXext and its Shm headers. + + Fix the invalid clipping of the source drawable when using SHM + transport to upload images. + https://bugs.freedesktop.org/show_bug.cgi?id=56547 + + Handle all Type1 postscript operators for better font compatibility. + https://bugs.freedesktop.org/show_bug.cgi?id=56265 + + Fix a couple of memory leaks in Type1 font subsetting + https://bugs.freedesktop.org/show_bug.cgi?id=56566 + + Tighten the evaluation of the start/stop pen vertices, and catch a few + instances where we would use a fan instead of a bevel. + https://bugs.freedesktop.org/show_bug.cgi?id=56432 + + Fix assumption that geometric clipping always succeeds with the + span-compositor. + https://bugs.freedesktop.org/show_bug.cgi?id=56574 + + Fix call to spline intersection when evaluating whether a stoke is + visible. + + Remember to copy inferior sources when using SHM to readback the + surface for use as a source. + +Release 1.12.6 (2012-10-22 Chris Wilson ) +=================================================================== +Thanks to everyone who download cairo-1.12.4 and gave us their feedback. +It truly was invaluable and has helped us to fix many portability issues +that crept in with some of the new features. This release aims to fix +those stability issues and run on a wider range of systems. + +Bug fixes +--------- + + Fix the recording surface to actually snapshot the source and so fix + PDF drawing. + + Calling XSendEvent with an XShmCompletionEvent is incompatabile with + older Xorg servers. + + Reorder CloseDisplay chain so that XShm is not reinstantiated after + shutdown, causing a potential crash if the Display was immediately + recreated using the same memory address. + + Make sure that the Xserver has attached to the SHM segment before + deleting it from the global namespace on systems that do not support + deferred deletion. + + Type1 subsetting support for PDF (and PS) was once again improved to + work with a larger number of PDF readers. + + GLESv2 build fixes and improved support for embedded GPUs. + + Tweak the invisible pen detection for applications that are currently + using too large values for geometric tolerance. + + A build fix for older freetype libraries. + + +Release 1.12.4 (2012-10-05 Chris Wilson ) +=================================================================== +More bugs, and more importantly, more fixes. On the cairo-gl side, we +have refinements to the MSAA compositor which enables hardware +acceleration of comparatively low-quality antialiasing - which is useful +in animations and on very high density screens. For cairo-xlib, we have +finally enabled SHM transport for image transfers to and from the X +server. A long standing required feature, SHM transport offers a notable +reduction in rendering latency by reducing the number of copies +required to upload image data - given hardware and driver support, +cairo-xlib can now perform zero copy uploads onto the GPU. And as usual +Adrian Johnson has been very busy fixing many different corner cases in +cairo-pdf, improving opacity groups and font subsetting. Last, but not +least, for cairo-image Søren Sandmann Pedersen added support for +rendering glyphs to pixman and using that from within cairo. The new +glyph rendering facility reduces the overhead for setting up the +compositing operation, improving glyph thoughput for the image backend +by a factor of about 4. And before he did so, he also fixed up a few +bugs in the existing glyph rendering code. So many thanks to Andrea +Canciani, Adrian Johnson, Chuanbo Weng, Dongyeon Kim, Henry Song, Martin +Robinson, Søren Sandmann Pedersen and Uli Schlachter for their +contributions, finding and fixing bugs. + +Bug fixes +--------- + + Interior boxes were being dropped when amalgamating regions during + tessellation. + https://bugs.freedesktop.org/show_bug.cgi?id=49446 + + Allow building without gtk-doc installed + + Invalid edge generation whilst reducing complex polygons. + https://bugs.freedesktop.org/show_bug.cgi?id=50852 + + Stroking around tight cusps + + Use locale correct formats for reading font subsetting and valid + buffers. + https://bugs.freedesktop.org/show_bug.cgi?id=51443 + + Ensure that the type1 subset includes all the glyph encodings + https://bugs.freedesktop.org/show_bug.cgi?id=53040 + + Upload the whole source for a repeating pattern. + https://bugs.freedesktop.org/show_bug.cgi?id=51910 + + Fix damage tracking to handle continuation chunks correctly and so + prevent crashes on win32. + https://bugs.freedesktop.org/show_bug.cgi?id=53384 + + Avoid emitting miter joins for degenerate line segments + https://bugzilla.mozilla.org/show_bug.cgi?id=407107 + + Convert the relative path semgents into the backend coordinates + and then back again to user coordinates (cairo_copy_path, + cairo_append_path) + https://bugs.freedesktop.org/show_bug.cgi?id=54732 + + Fix extents computations for a degenerate path consisting only of a + move-to + https://bugs.freedesktop.org/show_bug.cgi?id=54549 + + Prevent crashing on a degenerate project edge after polygon + intersection + https://bugs.freedesktop.org/show_bug.cgi?id=54822 + + + +Release 1.12.2 (2012-04-29 Chris Wilson ) +=================================================================== +After such a long gestation period for the release of Cairo 1.12, we +inevitably accumulated a few bugs that were flushed out by broadening the +test base. Thanks to everybody who tried the release, apologies to any one +unfortunate enough to encounter a bug and many thanks for reporting it. As +a result Adrian Johnson, Alexandros Frantzis, Andrea Canciani, Kalev +Lember, Maarten Bosman, Marcus Meissner, Nis Martensen and Uli Schlachter +have squashed many more bugs and improved the documentation. I would +strongly recommend everyone to upgrade to cairo-1.12.2. +-Chris + +Bug fixes +--------- + + Allow applications to create 0x0 xlib surfaces, such as used by LibreOffice. + https://bugs.freedesktop.org/show_bug.cgi?id=49118 + + Trim composite extents for SOURCE/CLEAR operators to the mask. + + Use fallback fonts in PDF for unhandled computed glyph widths + https://bugs.freedesktop.org/show_bug.cgi?id=48349 + + Handle snapshots of recording surfaces for analysing pattern extents. + Fixes a regression of reporting the PDF bounding box as being the page size. + + Fix allocation size for PDF pattern ids. + Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=49089 + + Fix emission of rectilinear dashed segments, with and without scaling, and + application of degenerate line joins. + + Clamp unbounded fixup polygons to the clip extents. + + Prevent infinite loop due to rounding errors whilst incrementing along dashes. + + Prevent overflow for inline a8 span filling. + + Miscellaneous build fixes for Cygwin on Windows and Solaris. + +Release 1.12.0 (2012-03-23 Chris Wilson ) +=================================================================== +It's taken over 18 months, but the wait is finally over. A new cairo release! +We are pleased to announce a new stable release of Cairo that brings many +new features and performance improvements, all whilst maintaining +compatibility with cairo-1.0 and all releases since. We recommend anyone +using a previous release of Cairo to upgrade to 1.12.0. + +The major feature of this release is the introduction of a new procedural +pattern; the mesh gradient. This, albeit complex, gradient is constructed +from a set of cubic Bezier patches and is a superset of all other gradient +surfaces which allows for the construction of incredibily detailed patterns. +In PDF parlance, the mesh gradient corresponds with type 7 patterns. Many +thanks to Andrea Canciani for bringing this to Cairo, and for his work on +making gradient handling robust. + +Not content with just adding another procedural pattern, Cairo 1.12 also +adds new API to create a callback pattern, +cairo_pattern_create_raster_source, that allows the application to +provide the pixel data for the region of interest at the time of +rendering. This can be used for instance, by an application to decode +compressed images on demand and to keep a cache of those decompressed +images, independently of Cairo. When combined with the recording +surface, it should form a useful basis for a deferred renderer. + +With the release of cairo-1.12, we also introduce a new supported +backend for interoperating with X using XCB. Uli Schlachter, also +maintainer of awesome and contributor to libxcb, has volunteered to +maintain cairo-xcb for us. Thanks Uli! + +For cairo-1.12, we have also added some common API to address any +surface as an image and so allow direct modification of the raster data. +Previously, only the Quartz and Win32 backends supported a very narrow +interface to allow for efficient pixel upload. Now with +cairo_surface_create_similar_image, cairo_surface_map_to_image, and +cairo_surface_unmap_image, Cairo exports a consistent method for +treating those surfaces as an image and so allow modification inplace. +These are the same routines used internally, and should support +efficient transfer or direct mapping of the target surfaces as +applicable. + +Another focus over the past year has been to address many performance +issues, without sacrificing the composition model. To accomplish the +goal, once again the rasterisation pipeline was overhauled and made +explicit, giving the backends the freedom to implement their own +specific pipeline whilst also providing a library of common routines +from which to build the pipeline. For instance, this allows the image +backend and the gl backend to composite scan line primitives inplace, +and to then implement custom fallbacks to catch the corner cases that do +not map onto their fastest paths. Similarly, this allows for the Xlib +backend to implement trapezoidation without compromising the other +backends, yet still allow for the pipeline to be used elsewhere for +testing and fallbacks. Clipping was once again overhauled, so that the +common cases for the raster pipelines could be captured and processed +with fast paths with the emphasis on performing geometric clipping to +reduce the frequency of using multi-pass clipmasks. Stroking was made +faster, both by providing specialised fast-paths for simple, yet frequent, +cases (such as stroking around a rectangle) and by reducing the number +of edges generated by the general stroker. + +As part of the focus on performance, Cairo 1.12 introduces some +antialias hints (NONE, FAST, GOOD, BEST) that are interpolated by the +rasterisers to fine tune their performance versus quality. Cairo 1.12 +also introduces a new observation architecture, +cairo_surface_observer_t, which can be used to analyse the amount of +time consumed by drawing commands and help identify inefficiencies in +both Cairo and the application. + +Last, but by no means least, the OpenGL backend has seen significant +work including the port to GLESv2 and the exploitation of advanced +hardware features. Interesting times. + +As always, I would like to thank everyone who contributed to Cairo, +not only through writing code, but also submitting documentation, bug +reports, suggestions and generally having fun with Cairo! In particular +though this release could not have happened without the efforts of +Adrian Johnson, Alexandros Frantiz, Andrea Canicani, Martin Robinson, +Nis Martensen, and Uli Schlachter. Thanks. +-Chris + +Snapshot 1.11.4 (2012-13-12) +============================ +The cairo community is pleased to finally announce the long aniticpated +release candidate for 1.12, 1.11.4, of the cairo graphics library. This +is the first major update to cairo in over a year and brings a large +number of new features; undoubtably a few bugs as well. + +While many people have contributed and have helped to test the release, +providing feedback on 1.10 and suggesting improvements, this release +is the result of a few persevering souls who deserve recognition for their +outstanding contributions: Andrea Canciani (all round bug fixing, +performance tuning and master of the gradients), Adrian Johnson (PDF +supremo) and Uli Schlachter (who stepped forward as maintainer for the +XCB backend). + +Major additions since 1.11.2: + + * cairo_surface_map_to_image API for pixel level access to any surface + + * New antialias hints to control the trade-off between speed and quality + + * A callback pattern, cairo_pattern_create_raster_source, for lazy + decoding of image data. + + * cairo_surface_observer_t, a new type of surface to gather performance + statistics + + * XCB as a supported backend + + * A rewritten compositor pipeline for performance improvements for, but not + limited to, the xlib and image backends. + From ION and PineView through to SandyBridge, every machine I have shows + across the board performance improvement on the cairo-traces: + + i5-2520m gnome-system-monitor: 5.97x speedup + pnv gnome-system-monitor: 4.86x speedup + i5-2520m firefox-asteroids: 4.66x speedup + pnv firefox-asteroids: 4.43x speedup + image firefox-canvas: 3.82x speedup + i5-2520m firefox-canvas-alpha: 3.49x speedup + image firefox-asteroids: 2.87x speedup + pnv firefox-talos-svg: 2.83x speedup + ion grads-heat-map: 2.75x speedup + pnv firefox-canvas-alpha: 2.66x speedup + image gnome-system-monitor: 2.66x speedup + image swfdec-giant-steps: 2.46x speedup + image firefox-canvas-alpha: 2.14x speedup + i5-2520m firefox-talos-svg: 2.03x speedup + image grads-heat-map: 2.02x speedup + ion gnome-system-monitor: 2.00x speedup + pnv firefox-particles: 1.99x speedup + i5-2520m grads-heat-map: 1.96x speedup + pnv firefox-canvas: 1.92x speedup + ion firefox-particles: 1.80x speedup + image poppler-reseau: 1.77x speedup + pnv xfce4-terminal-a1: 1.72x speedup + image firefox-talos-svg: 1.65x speedup + pnv grads-heat-map: 1.63x speedup + i5-2520m firefox-canvas: 1.63x speedup + pnv swfdec-youtube: 1.62x speedup + image ocitysmap: 1.59x speedup + i5-2520m firefox-fishbowl: 1.56x speedup + i5-2520m poppler-reseau: 1.50x speedup + i5-2520m evolution: 1.50x speedup + i5-2520m midori-zoomed: 1.43x speedup + pnv firefox-planet-gnome: 1.42x speedup + i5-2520m firefox-talos-gfx: 1.41x speedup + i5-2520m gvim: 1.41x speedup + pnv ocitysmap: 1.37x speedup + image poppler: 1.31x speedup + ion firefox-canvas-alpha: 1.35x speedup + ion firefox-talos-svg: 1.34x speedup + i5-2520m ocitysmap: 1.32x speedup + pnv poppler-reseau: 1.31x speedup + i5-2520m firefox-planet-gnome: 1.31x speedup + pnv firefox-fishbowl: 1.30x speedup + pnv evolution: 1.28x speedup + image gvim: 1.27x speedup + i5-2520m swfdec-youtube: 1.25x speedup + pnv gnome-terminal-vim: 1.27x speedup + pnv gvim: 1.25x speedup + image firefox-planet-gnome: 1.25x speedup + image swfdec-youtube: 1.25x speedup + ... + +And a plethora of minor improvements everywhere! +-Chris + +Snapshot 1.11.2 (2011-01-23) +=========================== + +In this first snapshot along the way to cairo-1.12.0, we are very excited +to announce the introduction of Bezier surface gradients, known as type +6/7 gradients in PS/PDF parlance. This is the culmination of much work by +the dynamic duo: Adrian Johnson and Andrea Canciani. Thanks guys! + +Also, I want to warmly welcome Uli Schlachter who recently joined the +Cairo community on a mission. That mission is to make cairo-xcb a +supported backend for 1.12. And for this snapshot he has made great +strides in fixing all the bugs I had left behind. Thanks Uli! + +And we have also seen a new contributor, Alexandros Frantzis, who has +begun bringing up cairo-gl for GLESv2 devices. Thanks Alex! + +And lastly, I must also thank Adrian and Andrea for the vast numbers of +bugs that they have tackled between them, fixing all those little corner +cases that lie hidden until too late. + +API additions: + +The ability to construct piece-wise Bezier surface gradients: + + cairo_pattern_create_mesh + + constructs a pattern of type CAIRO_PATTERN_TYPE_MESH using + + cairo_pattern_mesh_begin_patch + cairo_pattern_mesh_end_patch + cairo_pattern_mesh_curve_to + cairo_pattern_mesh_line_to + cairo_pattern_mesh_move_to + cairo_pattern_mesh_set_control_point + cairo_pattern_mesh_set_corner_color_rgb + cairo_pattern_mesh_set_corner_color_rgba + cairo_pattern_mesh_get_patch_count + cairo_pattern_mesh_get_path + cairo_pattern_mesh_get_corner_color_rgba + cairo_pattern_mesh_get_control_point + +The introduction of a unique ID accessible via the mime data type: + CAIRO_MIME_TYPE_UNIQUE_ID + + + + + +Release 1.10.2 (2010-12-25 Chris Wilson ) +=================================================================== +The cairo community is pleased to announce the 1.10.2 release of the +cairo graphics library. This is the first update to cairo's stable 1.10 +series and contains a large number of bug fixes. + +While many people have contributed and have help to test the release, +2 people deserve special recognition for their efforts in tracking down +and fixing bugs, Andrea Canciani and Adrian Johnson. Thanks to their +tremendous efforts, and of all cairo contributors, it is much +appreciated. + +We recommend everyone upgrade to cairo 1.10.2 and hope that everyone +will continue to have lots of fun with cairo! + +-Chris + +Bug fixes +--------- + + Fix embedding of grayscale jpegs in PS. + https://bugs.freedesktop.org/show_bug.cgi?id=31632 + + Fix the reported path of extents containing a curve. + + Fix the compositing of unaligned boxes. + + Reset the clipper in PDF upon finish. + + Fix degenerates arcs to become a degenerate line. + + Build support for autoconf 2.67 + + Fix painting of transformed patterns in PS + + Fix the EPS bounding box for PS + https://bugs.freedesktop.org/show_bug.cgi?id=24688 + + Fix the missing content for EPS + https://bugs.freedesktop.org/show_bug.cgi?id=24688 + + Fix regression upon changing page size in PS/PDF + https://bugs.freedesktop.org/show_bug.cgi?id=24691 + + Only use ActualText with PDF-1.5 documents + + Fix the bbox for type1 fallbacks. + + Reset the color after ending the context in PDF + https://bugs.freedesktop.org/show_bug.cgi?id=31140 + + Fix the advance of subsetted type1 fonts + https://bugs.freedesktop.org/show_bug.cgi?id=31062 + + Fix handling of EXTEND_NONE gradients for PDF + + Restrict in-place optimisation for a8 image masks with SOURCE + + +Release 1.10.0 (2010-09-06 Chris Wilson ) +=================================================================== +The cairo community is astounded (and flabbergast) to finally announce +the 1.10.0 release of the cairo graphics library. This is a major update +to cairo, with new features and enhanced functionality which maintains +compatibility for applications written using any previous major cairo +release, (1.8, 1.6, 1.4, 1.2, or 1.0). We recommend that anybody using +a previous version of cairo upgrade to cairo 1.10.0. + +One of the more interesting departures for cairo for this release is the +inclusion of a tracing utility, cairo-trace. cairo-trace generates a +human-readable, replayable, compact representation of the sequences of +drawing commands made by an application. This can be used to inspecting +applications to understand issues and as a means for profiling +real-world usage of cairo. + +The traces generated by cairo-trace have been collected in + + git://git.cairographics.org/git/cairo-traces + +and have driven the performance tuning of cairo over the last couple of +years. In particular, the image backend is much faster with a new +polygon rasterisation and a complete overhaul of the tessellator. Not +only is this faster, but also eliminates visual artifacts from +self-intersecting strokes. Not only has cairo-trace been driving +performance improvements within cairo, but as a repeatable means of +driving complex graphics it has been used to tune OpenGL, DDX, and +pixman. + +Cairo's API has been extended to better support printing, notably +through the ability to include a single compressed representation of an +image for patterns used throughout a document, leading to dramatic file +size reductions. Also the meta-surface used to record the vector +commands compromising a drawing sequence is now exposed as a +CAIRO_SURFACE_TYPE_RECORDING, along with a new surface that is a child of a +larger surface, CAIRO_SURFACE_TYPE_SUBSURFACE. One typical usage of a +subsurface would be as a source glyph in a texture atlas, or as a +restricted subwindow within a canvas. + +Cairo's API has also resurrected the RGB16 format from the past as +the prevalence of 16-bit framebuffers has not diminished and is a +fore-taste of the extended format support we anticipate in the future. +Increasing cairo's utility, we introduce the cairo_region_t for handling +sets of pixel aligned rectangles commonly used in graphics applications. +This is a merger of the GdkRegion and the pixman_region_t, hopefully +providing the utility of the former with the speed of the latter. + +Furthermore cairo has been reworked to interoperate more closely with +various acceleration architectures, gaining the ability to share +those hardware resources through the new cairo_device_t. For instance, +with the new OpenGL backend that supersedes the Glitz backend, hardware +and rendering operations can be shared between a classic OpenGL +application mixing libVA for the hardware assisted video decode with +cairo for high quality overlays all within the same OpenGL canvas. + +Many thanks for the hard work of Adrian Johnson, Andrea Canciani, Behdad +Esfahbod, Benjamin Otte, Carl Worth, Carlos Garcia Campos, Chris Wilson, +Eric Anholt, Jeff Muizelaar, Karl Tomlinson, M Joonas Pihlaja, Søren +Sandmann Pedersen and many others that have contributed over the last +couple of years to cairo. Thank you all! + +Snapshot 1.9.14 (2010-07-26) +============================ + + A quiet couple of weeks, hopefully Cairo is seeing widescale deployment and + we are being to see the results of the stabilisation effort. Clipping bugs + seems to have been the order of the last couple of weeks, with a couple + reported and duly fixed. Thank you Igor Nikitin and Karl Tomlinsion for + finding those regressions. At this point all that seems to remain to do is + to fix the outstanding regressions in the PDF backend... + +Bugs fixes +---------- + + Clip doesn't work for text on the image backend + https://bugs.freedesktop.org/show_bug.cgi?id=29008 + + Add explicit dependency for cxx + https://bugs.freedesktop.org/show_bug.cgi?id=29114 + + Fix regressions in reporting clip extents + https://bugs.freedesktop.org/show_bug.cgi?id=29120 + https://bugs.freedesktop.org/show_bug.cgi?id=29121 + https://bugs.freedesktop.org/show_bug.cgi?id=29122 + https://bugs.freedesktop.org/show_bug.cgi?id=29124 + https://bugs.freedesktop.org/show_bug.cgi?id=29125 + + +Snapshot 1.9.12 (2010-07-12) +============================ + + A couple of weeks spent fixing those annoying bugs and cleaning up the build + system; the list of outstanding tasks to complete for the stable release is + finally shrinking. The chief bug fixer has been Benjamin Otte who not only + made sure that the public API is consistent and being tested for its + consistency, but also ensured that the documentation was up-to-date and + spent time clarifying cases where even the Cairo developers have come + unstuck in the past. Many thanks, Benjamin. However, he was not alone, + as Andrea Canciani continued his fine work in isolating broken corner cases + and proceeding to fix them, and tidying up the quartz backend. And last, but + definitely not least, M Joonas Pihlaja tried building Cairo across a + perverse range of systems and fixed up all the loose bits of code that came + unravelled. Thanks everybody! + +API Changes +----------- + + cairo_surface_set_mime_data, cairo_surface_get_mime_data: + + The length parameter is now an unsigned long (as opposed to an unsigned + int). The parameter is intended to be an equivalent to a size_t without + requiring POSIX types and be large enough to store the size of the + largest possible allocation. + + cairo_gl_surface_create_for_texture: + + This a new surface constructor for cairo-gl that explicitly enables + render-to-texture for foreign, i.e. application, textures. + + cairo_region_xor, cairo_region_xor_rectangle + + A couple of utility routines add to the region handling interface for + the purpose of replacing existing GdkRegion functionality. + +Bugs fixes +---------- + + https://bugs.launchpad.net/ubuntu/+source/cairo/+bug/600622 + + Inkscape was caught in the act of attempting to modify a finished surface. + Unfortunately, we had the ordering of our guards and assertions wrong and + so an ordinary application error was triggering an assert in Cairo. This + lead Benjamin to add a test case to ensure that the entire public API + could handle erroneous input and then proceeded to fix a whole slew of + uncovered bugs. + + + https://bugs.freedesktop.org/show_bug.cgi?id=28888 + + A regression introduced by the special casing of uploading images to an + xlib surface in-place which was ignoring the translation applied to the + image. + + +Snapshot 1.9.10 (2010-06-26) +============================ + + The first "quick" snapshot in the run up to the stable release. The + last snapshot was picked up by the bleeding edge distributions and so the + bug reports have to started to roll in. The most frequent of these are the + introduction of rendering errors by applications that modify a surface + without subsequently calling cairo_surface_mark_dirty(). Make sure the + application developers are aware of increased reliance on strict use of the + Cairo API before 1.10 is released! + + The usual slew of bugs reported and we would like to thank Zoxc for + contributing the WGL interface for cairo-gl, and finding more build + failures on win32. And it just wouldn't be a 1.9 snapshot unless + Benjamin Otte improved the error handling within cairo-gl, as well as + isolating and fixing some more errors in the test suite. The biggest bug of + the snapshot turned out to be a major sign extension issue that had lain + hidden for many years and was suddenly exposed by incorrectly rounding + rectangles when performing non-antialiased rendering. Also to the relief + of many we have included the downstream patch to honour the user's LCD + filtering preferences for subpixel rendering of fonts. The interface + remains private for the time being, whilst the proposed public API is + finalized. + +API changes +----------- + None. + +Snapshot 1.9.8 (2010-06-12) +=========================== + + One major API changes since the last snapshot, and a whole slew of bugs + fixed and inconsistencies eliminated. Far too many bugs fixed to + individually identify. We need to thank Benjamin Otte for his fantastic + work on the cairo-gl backend making it faster and more robust, Andrea + Canciani for finding so many bugs and developing test cases for them, as + well fixing them. And last but not least we must all thank Adrian Johnson for + continuing to eliminate bugs and improving the PostScript and PDF backends. + + This snapshot represents almost 4 months of bug fixing, bringing Cairo to + a point where we consider it almost ready to be a candidate for release. + There are a few known bugs left to be fixed, being tracked in + https://bugs.freedesktop.org/show_bug.cgi?id=24384, so please give Cairo a + whirl and report any regressions. The plan is to release a new snapshot + every other week leading to a 1.10 release with a target date of + 2010-08-16. + +API additions +------------- + CAIRO_FORMAT_RGB16_565 + + 16 bit devices still remain popular, and so with great demand, + CAIRO_FORMAT_RGB16_565 has been restored enabling applications to create + and use 16 bit images as sources and render targets. + + cairo_surface_create_for_rectangle() + + It is common practice to cut an image up into many smaller pieces and use + each of those as a source - a technique called texture atlasing. + cairo_surface_create_for_rectangle() extends Cairo to directly support use + of these subregions of another cairo_surface_t both as a source and as a + render target. + + cairo_region_create() + cairo_region_create_rectangle() + cairo_region_create_rectangles() + cairo_region_copy() + cairo_region_reference() + cairo_region_destroy() + cairo_region_equal() + cairo_region_status() + cairo_region_get_extents() + cairo_region_num_rectangles() + cairo_region_get_rectangle() + cairo_region_is_empty() + cairo_region_contains_rectangle() + cairo_region_contains_point() + cairo_region_translate() + cairo_region_subtract() + cairo_region_subtract_rectangle() + cairo_region_intersect() + cairo_region_intersect_rectangle() + cairo_region_union() + cairo_region_union_rectangle() + + The Cairo region API was actually added a couple of snapshots ago, but we + forgot to mention it at the time. A simple API for the handling of + rectangular pixel-aligned regions by Soeren Sandmann. + + +Backend-specific improvements +----------------------------- +cairo-gl + + Benjamin Otte made more than 200 commits in which he refactored the cairo-gl + backend, reducing a lot of code duplication and enabled him to begin working + on improving performance by reducing state changes and associated overhead. + +cairo-xlib + + Access to the underlying connection to the Display is now thread-safe + enabling cairo-xlib to be used in a multi-threaded application without fear + of random corruption. Thanks Benjamin Otte! + + cairo-xlib will now attempt to use PolyModeImprecise when compositing + trapezoids (i.e. a fill or a stroke operation with a non-trivial path) which + should allow hardware drivers more scope for accelerating the operation at + the cost of potentially incurring minute rendering errors. The mode can be + forced back to PolyModePrecise by setting the antialias parameter to + CAIRO_ANTIALIAS_SUBPIXEL. + +cairo-svg + + A notable improvement was contributed by Alexander Shulgin to enable SVG to + reference external image through the use an extended MIME data type. + +Snapshot 1.9.6 (2010-02-19) +=========================== +API additions +------------- + Add cairo_device_t + + The device is a generic method for accessing the underlying interface + with the native graphics subsystem, typically the X connection or + perhaps the GL context. By exposing a cairo_device_t on a surface and + its various methods we enable finer control over interoperability with + external interactions of the device by applications. The use case in + mind is, for example, a multi-threaded gstreamer which needs to serialise + its own direct access to the device along with Cairo's across many + threads. + + Secondly, the cairo_device_t is a unifying API for the mismash of + backend specific methods for controlling creation of surfaces with + explicit devices and a convenient hook for debugging and introspection. + + The principal components of the API are the memory management of: + + cairo_device_reference(), + cairo_device_finish() and + cairo_device_destroy(); + + along with a pair of routines for serialising interaction: + + cairo_device_acquire() and + cairo_device_release() + + and a method to flush any outstanding accesses: + + cairo_device_flush(). + + The device for a particular surface may be retrieved using: + + cairo_surface_get_device(). + + The device returned is owned by the surface. + +API changes (to API new in the cairo 1.9.x series) +-------------------------------------------------- + cairo_recording_surface_create() + cairo_recording_surface_ink_extents() + + These are the replacement names for the functions previously named + cairo_meta_surface_create and cairo_meta_surface_ink_extents. + + cairo_surface_set_mime_data + + This interface is now changed such that the MIME data will be + detached if the surface is modified at all. This guarantees that + the MIME data will not become out of synch due to surface + modifications, and also means that for the MIME data to be useful, + it must be set after all modifications to the surface are + complete. + +API removal (of experiment API) +------------------------------- + The cairo-glitz backend is removed entirely, (in favor of the new + cairo-gl backend). See below for more on cairo-gl. + +Generic fixes +------------- + + Many improvements for drawing of dashed strokes + + Fix incorrect handling of negative offset + Faster computation of first dash (avoids near-infinite looping) + Approximate extremely fine dash patterns with appropriate alpha value + + Optimize spans-based renderers for repeated rows, (such as in a rounded rectangle) + +Backend-specific improvements +----------------------------- +cairo-drm + + This is a new, direct-rendering backend that supports Intel graphics + chipsets in the i915 and i965 families. It's still experimental and + will likely remain that way for a while. It's already got extremely + good performance on the hardware it supports, so if nothing else + provides a working proof and performance target for the cairo-gl + work for Intel graphics. + +cairo-gl + + Start using GLSL to accelerate many operations. Many thanks to Eric + Anholt and T. Zachary Laine for this work. For the first time, we + have what looks like what will be a very compelling OpenGL-based + backend for cairo (in terms of both quality and performance). + + See this writeup from Eric for more details on recent progress of + cairo-gl (which he presented at FOSDEM 2010): + + http://anholt.livejournal.com/42146.html + +cairo-image + + The image backend is made dramatically faster (3-5 times faster for + benchmarks consisting primarily of glyph rendering). + +cairo-quartz fixes: + + Many fixes from Robert O'Callahan and Andrea Canciani including: + + Fixed gradient pattern painting + Improved A8 image handling + Fixes for "unbounded" and other compositing operators + +cairo-pdf fixes: + + Improvements to embedding of JPEG and JPEG2000 data. + +cairo-ps fixes: + + Fix printing of rotated user fonts. + +Snapshot 1.9.4 (2009-10-15) +=========================== +API additions: + + cairo_meta_surface_create() + cairo_meta_surface_ink_extents() + + Finally exporting the internal meta-surface so that applications + have a method to record and replay a sequence of drawing commands. + + cairo_in_clip() + + Determines whether a given point is inside the current clip. + ??? Should this be called cairo_in_paint() instead? in-clip is the test + that is performed, but in-paint would be similar to in-fill and in-stroke. + +New utilities: + + cairo-test-trace + + A companion to cairo-perf-trace, this utility replays a trace against + multiple targets in parallel and looks for differences in the output, + and then records any drawing commands that cause a failure. + Future plans: + Further minimisation of the fail trace using "delta debugging". + More control over test/reference targets. + +Backend improvements: + + xlib + + Server-side gradients. The theory is that we can offload computation + of gradients to the GPU and avoid pushing large images over the + connection. Even if the driver has to fallback and use pixman to render + a temporary source, it should be able to do so in a more efficient manner + than Cairo itself. However, cairo-perf suggests otherwise: + + On tiny, Celeron/i915: + + before: firefox-20090601 211.585 + after: firefox-20090601 270.939 + + and on tiger, CoreDuo/nvidia: + + before: firefox-20090601 70.143 + after: firefox-20090601 87.326 + + In particular, looking at tiny: + + xlib-rgba paint-with-alpha_linear-rgba_over-512 47.11 (47.16 0.05%) -> 123.42 (123.72 0.13%): 2.62x slowdown + █▋ + xlib-rgba paint-with-alpha_linear3-rgba_over-512 47.27 (47.32 0.04%) -> 123.78 (124.04 0.13%): 2.62x slowdown + █▋ + + +New experimental backends: + + QT + + OpenVG - The initial work was done by Øyvind Kolås, and made ready for + inclusion by Pierre Tardy. + + OpenGL - An advanced OpenGL compositor. The aim is to write a integrate + directed rendering using OpenGL at a high-level into Cairo. In + contrast to the previous attempt using Glitz which tried to + implement the RENDER protocol on top of OpenGL, using the + high-level interface should permit greater flexibility and + more offloading onto the GPU. + The initial work on the backend was performed by Eric Anholt. + +Long standing bugs fixed: + + Self-intersecting strokes. + + A long standing bug where the coverage from overlapping semi-opaque + strokes (including neighbouring edges) was simply summed in lieu of + a costly global calculation has been fixed (by performing the costly + global calculation!) In order to mitigate the extra cost, the + tessellator has been overhauled and tune, which handles the fallback + for when we are unable to use the new span rasteriser on the stroke + (e.g. when using the current RENDER protocol). The large number of + pixel artifacts that implementing self-intersection elimination + removes is ample justification for the potential performance + regression. If you unfortunately do suffer a substantial performance + regression in your application, please consider obtaining a + cairo-trace and submitting it to us for analysis and inclusion into + our performance suite. + +Special thanks: + + To the AuroraUX team for providing access to one of their OpenSolaris + machines for cairo and pixman development. http://www.auroraux.org/ + +Snapshot 1.9.2 (2009-06-12) +=========================== +API additions: + + cairo_surface_set_mime_data() + cairo_surface_get_mime_data() + + Should this take unsigned int, unsigned long or size_t for the length + parameter? (Some datasets may be >4GiB in size.) + + Associate an alternate, compressed, representation for a surface. + Currently: + "image/jp2" (JPEG2000) is understood by PDF >= 1.5 + "image/jpeg" is understood by PDF,PS,SVG,win32-printing. + "image/png" is understood by SVG. + + cairo_pdf_version_t + cairo_pdf_surface_restrict_to_version() + cairo_pdf_get_versions() + cairo_pdf_version_to_string() + + Similar to restrict to version and level found in SVG and PS, + these limit the features used in the output to comply with the PDF + specification for that version. + + CAIRO_STATUS_INVALID_SIZE + Indicates that the request surface size is not supported by the + backend. This generally indicates that the request is too large. + + CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED + Indicates that a required callback for a user-font was not implemented. + + CAIRO_STATUS_LAST_STATUS + This is a special value to indicate the number of status values enumerated + at compile time. (This may differ to the number known at run-time.) + + The built-in twin font is now called "@cairo:" and supports a limited set + of options like "@cairo:mono". Where are these specified? + + cairo_in_fill() now uses HTML Canvas semantics, all edges are inside. + +New experimental backends: + + CairoScript + +New utility: + + cairo-trace and cairo-perf-trace + + cairo-trace generates a human-readable, replayable, compact(-ish!) + representation of the sequences of drawing commands made by an + application. + + Under the util/cairo-script directory is a library to replay traces. + + perf/cairo-perf-trace replays traces against multiple backends + and makes useful benchmark reports. This is integrated with + 'make perf'. You may collect your own traces or take advantage + of traces collected by the community: + + git://git.cairographics.org/git/cairo-traces + + (Put this into perf/cairo-traces to run these as part of "make perf".) + + There is additional WIP in building a debugging tool for cairo applications + based on CairoScript (currently very preliminary, mostly serves to show + that GtkSourceView is too slow) : + + people.freedesktop.org:~ickle/sphinx + +Test suite overhaul: + + The test suite is undergoing an overhaul, primarily to improve its speed + and utility. (Expect more changes in the near future to improve XFAIL + handling.) + +Optimisations: + polygon rasterisation! Joonas implemented the Tor polygon scan converter, + on typical geometry is about 30% faster for the image backend. + + Bovine Polaroids! For those not in on the joke, this is the long + awaited "copy-on-write snapshot" or "COW snapshot" support. The + user-visible feature is that including the same image multiple times + into a PDF file should result in only a single instance of that + image in the final output. This is unlike previous versions of cairo + which would generate very large PDF files with multiple copies of + the same image. Adrian says that the PDF is not quite working as + well as it should yet, so we hope for further improvements before + cairo 1.10. + +Bug fixes: + + EXTEND_PAD. + + Better handling of large scale-factors on image patterns. + + Emit /Interpolate for PS,PDF images. + + Global glyph cache - cap on the total number of inactive glyphs, + should prove fairer for fonts with larger glyph sets. + + Compilation without fontconfig + + Improved handling of low-bitdepth sources (e.g. copying the contents + of 16-bit xserver windows) + +Regressions: + + cairo_traps_extract_region >10x slower. Fix pending. + +Still to come: + + Region tracking API (ssp) for damage tracking, hit testing etc + mime-surface + + An expiremental OpenGL backend? + + Tweaks to tessellator, allocations of patterns, delayed + initialisation of the xlib backend (reduce the cairo overhead of + render_bench by ~80%). + + +Release 1.8.8 (2009-06-16 Chris Wilson ) +================================================================== +The cairo community is pleased to announce the 1.8.8 release of the +cairo graphics library. This is the fourth update to cairo's stable +1.8 series and contains a small number of bug fixes (in particular a +few corrections to the documentation and a few fixes in the FreeType font +backend). This is being released just over six months after cairo 1.8.6. + +We recommend that everyone using cairo upgrade to 1.8.8. + +-Chris + +Build fixes +----------- +There were reports of incompatibilities with the autotools bundled in with +the 1.8.6 tarball. This release has been built with automake-1.10.2 and +autoconf-2.63. + +The configure check for FreeType has been improved: + + typo in check for version of freetype in configure script + https://bugs.freedesktop.org/show_bug.cgi?id=19283 + +Compilation on 64-bit MacOS/X fixes: + + Cannot build cairo_quartz_font_face_create_for_atsu_font_id on 64-bit Mac OS X + https://bugs.freedesktop.org/show_bug.cgi?id=15702 + +Bug fixes +--------- +Uninitialised status return within _cairo_clip_intersect_mask(). This caused +random crashes and general mayhem as an error could be generated causing all +rendering to the context to stop. + +Avoid transforming nearly-degenerate matrices into degenerate matrices: + + Painting stops in this case, using -moz-transform: scale, rotate and video + https://bugzilla.mozilla.org/show_bug.cgi?id=467423 + +A few FreeType font handling bugs were fixed: + + Rendering with PANGO_GRAVITY_EAST leads to different results with image and pdf + https://bugs.freedesktop.org/show_bug.cgi?id=21985 + + Don't call FT_Done_Face() on faces we did not create + + zombie ft_font_face / ft_unscaled_font mutual referencing problems + https://bugs.freedesktop.org/show_bug.cgi?id=21706 + +Ensure win32 font backend sets the return value to -1 (indicating the absent +glyph) if the font index lookup for the unicode character fails. And +similarly fix a bug where a fatal error was raised for an invalid glyph. + + cairo_scaled_font_glyph_extents breaks with invalid glyph id + https://bugs.freedesktop.org/show_bug.cgi?id=20255 + +Various improvements to the documentation, reported by Truc Troung: + + https://bugs.freedesktop.org/show_bug.cgi?id=20095 + https://bugs.freedesktop.org/show_bug.cgi?id=20154 + https://bugs.freedesktop.org/show_bug.cgi?id=20180 + https://bugs.freedesktop.org/show_bug.cgi?id=20183 + https://bugs.freedesktop.org/show_bug.cgi?id=20182 + https://bugs.freedesktop.org/show_bug.cgi?id=20441 + + +Release 1.8.6 (2008-12-13 Chris Wilson ) +================================================================== +The cairo community is pleased to announce the 1.8.6 release of the +cairo graphics library. This is the third update to cairo's stable +1.8 series and contains a small number of bug fixes (in particular a +few fixes for failures of cairo 1.8.4 on Quartz and PDF, and build fixes for +a couple of backends). This is being released just under a month after +cairo 1.8.4. + +We recommend that everyone using cairo upgrade to 1.8.6. + +-Chris + +Build fixes +----------- +Fix build of DirectFB backend with debugging enabled: + + Bug in _cairo_directfb_surface_release_source_image function + https://bugs.freedesktop.org/show_bug.cgi?id=18322 + +Fix build on OS/2. + +Bug fixes +--------- +Workaround a mis-compilation of cairo_matrix_invert() that generated invalid +matrices and triggered assertion failures later. The issue was reported by +Peter Hercek. + +Invalid computation of the modulus: + + https://bugzilla.mozilla.org/show_bug.cgi?id=466258 + +Invalid referencing of patterns in the Quartz backend: + + Failed assertion `CAIRO_REFERENCE_COUNT_HAS_REFERENCE + (&pattern->ref_count)' when using cairo quartz backend + https://bugs.freedesktop.org/show_bug.cgi?id=18632 + +Invalid references to glyphs after early culling, causing segmentation faults +in the PDF backend: + + https://lists.cairographics.org/archives/cairo/2008-December/015976.html + +Check for XRender in the XCB backend, or else we may attempt an invalid memory +access: + + XCB backend fails with missing render. + https://bugs.freedesktop.org/show_bug.cgi?id=18588 + +Release 1.8.4 (2008-11-14 Carl Worth ) +========================================================= +The cairo community is pleased to announce the 1.8.4 release of the +cairo graphics library. This is the second update to cairo's stable +1.8 series and contains a small number of bug fixes, (in particular a +few fixes for build failures of cairo 1.8.2 on various systems). This +is being released just over two weeks after cairo 1.8.2. + +We recommend that everyone using cairo upgrade to 1.8.4. + +-Carl + +Build fixes +----------- +Fix build with older XRender that doesn't define RepeatNone: + + Build of xlib backend fails against old XRender (RepeatNone undeclared) + https://bugs.freedesktop.org/show_bug.cgi?id=18385 + +Fix build with bash version <= 3.0: + + doltlibtool broken on linux with bash 3.00.0 + https://bugs.freedesktop.org/show_bug.cgi?id=18363 + +Bug fixes +--------- +Avoid triggering a bug in X.org server 6.9 resulting in a hung machine +requiring a reboot: + + https://bugs.freedesktop.org/show_bug.cgi?id=15628#c2 + +Fix display of user fonts as exercised by proposed support for type3 +fonts in poppler (unsigned promotion fixes): + + Use cairo user-font for Type 3 fonts + https://lists.freedesktop.org/archives/poppler/2008-October/004181.html + +Avoid miscomputing size of fallback images required when rendering +with CLEAR, IN, or SOURCE operator to vector surfaces, (PS, PDF, SVG, +etc.). + +Be more tolerant of broken fonts when subsetting type1 fonts: + + Error handling in cairo_type1_font_subset_get_glyph_names_and_widths + https://lists.cairographics.org/archives/cairo/2008-October/015569.html + +Fix cairo_fill_extents, cairo_stroke_extents, cairo_path_extents, to +correctly allow NULL parameters as documented. + +Fix potential crash on emitting a type3 glyph after having drawn text +paths from the same font, (for example with cairo_text_path). + +Release 1.8.2 (2008-10-29 Carl Worth ) +========================================================= +The cairo community is pleased to announce the 1.8.2 release of the +cairo graphics library. This is the first update to cairo's stable 1.8 +series and contains a large number of bug fixes. It is being released +just over one month since cairo 1.8.0. + +This release consists primarily of bug fixes, but there is one notable +new feature, (the ability to build cairo without an external font +backend), and there are a few optimizations as well. See below for +details on these changes and the most important bug fixes. + +While many people have contributed to this release, Chris Wilson +deserves particular mention. He has contributed well over twice as +many changes to cairo since 1.8.0 than everyone else combined. We +greatly appreciate the tremendous efforts of Chris and all cairo +contributors. + +We recommend everyone upgrade to cairo 1.8.2 and hope that everyone +will have lots of fun with cairo! + +-Carl + +New feature +----------- +It is now possible to build cairo without any font backend, (such as +freetype, win32 or quartz). This is most useful when the application +provides custom font rendering through the user-font API. But in the +case where no external font backend is available, and no user-font is +provided, cairo will render with a failsafe font, (a stroked font +covering visible ASCII character). (Behdad Esfahbod) + +Optimizations +------------- +Dramatically speed up compilation with dolt (removes much of the +libtool overhead) (Behdad Esfahbod with thanks to Josh Triplett). + +Several minor optimizations to tessellator (special-cased comparisons, +faster insert for skiplist, etc.) (Chris Wilson). + +Optimize away fractional translation component when doing +EXTEND_NEAREST filtering, (for better performance). + +General bug fixes +----------------- +Allow cloning sub-regions of similar surfaces to fix this bug +(Chris Wilson): + + Crafted gif file will crash firefox + [XError: 'BadAlloc (insufficient resources for operation)'] + https://bugzilla.mozilla.org/show_bug.cgi?id=424333 + +Fix some matrix confusion to fix this regression (Chris Wilson): + + Translucent star exports in a wrong way to PDF + https://bugs.launchpad.net/inkscape/+bug/234546 + +Fix some long-standing bugs with respect to properly computing the +extents of transformed, filtered surfaces (Owen Taylor, Carl Worth, +and Chris Wilson): + + Bad clipping with EXTEND_NONE + https://bugs.freedesktop.org/show_bug.cgi?id=15349 + + Improve filtering handling in cairo-pattern.c + https://bugs.freedesktop.org/show_bug.cgi?id=15367 + + Many thanks to Chris Wilson for digging out and cleaning up + these fixes. + +Fix compilation on Solaris 10 (Chris Wilson): + + Cairo requires -DREENTRANT (along with -D_POSIX_THREAD_SEMANTICS) + to compile on Solaris 10 with pthreads + https://bugs.freedesktop.org/show_bug.cgi?id=18010 + +Fix very old bug causing dashes to be rendered at the wrong length in +fallback images (Adrian Johnson) + + Dashed strokes too long in fallback images + https://bugs.freedesktop.org/show_bug.cgi?id=9189 + +Fix broken dashing when a dashed path starts outside the clip region +(Chris Wilson). + +Avoid range overflow when computing large patterns (Benjamin Otte and +Chris Wilson). + +Avoid crashing due to an invalid font with an incorrect entry in its +CMAP table (Adrian Johnson). + +Fix bugs in computing maximum size of text requests that can be sent +with the Render extension, (avoiding potential crashes when rendering +large amounts of text) (Behdad Esfahbod and Chris Wilson). + +Fix rendering of operators unbounded by the mask (Chris Wilson). + +Fix compilation on systems without compiler support for a native +64-bit type (Chris Wilson). + +Fix several cases of missing error-status propagation. (Chris Wilson, +doing the work he seems to never tire of). + +Fix several locking issues found with the lockdep valgrind skin (Chris +Wilson). + +Backend-specific bug fixes +-------------------------- +xlib: Avoid crash due to attempting XRender calls on pixmaps with +formats not supported by the Render extension (Chris Wilson): + + XRender crashes due to NULL pointer from Cairo on SGI O2 + https://bugs.freedesktop.org/show_bug.cgi?id=11734 + +xlib: Add support for XImages with depth of 4, 20, 24, or 28 bits +(Chris Wilson): + + cairo doesn't support 24 bits per pixel mode on X11 + https://bugs.freedesktop.org/show_bug.cgi?id=9102 + +xlib: Avoid mistakenly considering two surfaces as similar just +because their depths match (while their Render formats do not) (Karl +Tomlinson). + +ps: Fix slight mis-scaling of bitmapped fonts (Adrian Johnson) + +svg: Correctly emit comp-op for paint, mask, and show_glyphs +operations (Emmanuel Pacaud). + +svg: Use finer-grained fallbacks for SVG 1.2 (as PS and PDF backends +have been doing since 1.6.0) (Chris Wilson). + +win32: Fallback to DIB if DDB create fails for +cairo_surface_create_similar (Vladimir Vukicevic). + +win32: Fix compatibility with Windows Mobile (Vladimir Vukicevic). + +win32: Fix static builds to not do __declspec(dllimport) on public +functions. This requires the user to set a CAIRO_WIN32_STATIC_BUILD +environment variable when compiling (Behdad Esfahbod). + +Release 1.8.0 (2008-09-25 Carl Worth ) +========================================================= +The cairo community is happy (and relieved) to announce the 1.8.0 +release of the cairo graphics library. This is a major update to +cairo, with new features and enhanced functionality which maintains +compatibility for applications written using any previous major cairo +release, (1.6, 1.4, 1.2, or 1.0). We recommend that anybody using a +previous version of cairo upgrade to cairo 1.8.0. + +The dominant theme of this release is improvements to cairo's ability +to handle text. The highlights include a new "user fonts" feature as +well as a new cairo_show_text_glyphs API which allows glyphs to be +embedded in PDF output along with their original text, (for searching, +selection, and copy-and-paste). Another major feature is a revamp of +cairo's build system making it much easier to build cairo on various +platforms. + +See below for more details. + +User fonts +---------- +This new API allows the user of cairo API to provide drawings for +glyphs in a font. A common use for this is implementing fonts in +non-standard formats, like SVG fonts and Flash fonts. This API can +also be used by applications to provide custom glyph shapes for fonts +while still getting access to cairo's glyph caches. See +test/user-font.c and test/user-font-proxy.c for usage examples. This +is based on early work by Kristian Høgsberg. Thanks Kristian! + +This new API consists of the following functions (and corresponding +_get functions): + + cairo_user_font_face_create + + cairo_user_font_face_set_init_func + cairo_user_font_face_set_render_glyph_func + cairo_user_font_face_set_text_to_glyphs_func + cairo_user_font_face_set_unicode_to_glyph_func + +An additional, new API is + + cairo_scaled_font_text_to_glyphs + +We were previously reluctant to provide this function as +text-to-glyphs support in cairo was limited to "toy" font +functionality, not really interesting for real-world text +processing. However, with user fonts landing, this API is needed to +expose full access to how user fonts convert text to glyphs. This is +expected to be used by text toolkits like Pango, as well as "proxy" +user-font implementations. + +cairo_show_text_glyphs +---------------------- +This new API allows the caller of cairo to provide text data +corresponding to glyphs being drawn. The PDF backend implements this +new API so that complex text can be copied out of cairo's PDF output +correctly and reliably, (assuming the user of cairo calls +cairo_show_text_glyphs). The cairo_show_text_glyphs API is definitely +the most daunting API to debut in cairo. It is anticipated that pango +(and similar high-level text libraries) will be the primary users of +this API. In fact, pango 1.22 already uses cairo_show_text_glyphs. +Behdad was the architect and implementor of this effort. Thanks, +Behdad! + +The cairo_show_text_glyphs API includes the following new functions: + + cairo_show_text_glyphs + + cairo_glyph_allocate + cairo_glyph_free + + cairo_text_cluster_allocate + cairo_text_cluster_free + + cairo_surface_has_show_text_glyphs + +Build system revamp +------------------- +The primary goal of the revamp is to make the build system less +fragile, (particularly for non-Linux platforms). For example, now +people building on win32 will no longer need to maintain a +platform-specific list of files to be built. See the new README.win32 +for details. Also, the .so file will now be installed with a different +naming scheme, (for example, 1.7.6 will install with a .10800 +suffix). Many thanks to Behdad and his small army of helpers! + +Assorted API additions +---------------------- +For API completeness, several missing "getter" functions were added: + + cairo_scaled_font_get_scale_matrix + + cairo_surface_get_fallback_resolution + + cairo_toy_font_face_create + cairo_toy_font_face_get_family + cairo_toy_font_face_get_slant + cairo_toy_font_face_get_weight + +The new cairo_toy_font_face functions provide access to functionality +and settings provided by cairo_select_font_face(). Thanks Behdad! + +cairo-ps/cairo-pdf: More efficient output +----------------------------------------- +Adrian Johnson has been busy fixing all kinds of bugs in PS and PDF +backends, as well making them generate much more compact output by +avoiding things like re-emitting the color or linestyle on every +drawing operation. Thanks Adrian! + +cairo-xlib: dithering +--------------------- +Dithering: Cairo now does simple dithering when rendering to legacy X +servers. This is most visible with 8-bit visuals. Thanks Behdad! + +cairo-xlib: Avoid rendering glyphs out of surface bounds +-------------------------------------------------------- +This seemingly harmless optimization exposed a bug in OpenOffice.org 3 +versions where OO.o was passing bogus surface extents to cairo, +resulting in no text rendered in OO.o. Please contact your +distribution's OO.o maintainers if you see this bug and point them to +the following URL: + + https://bugs.freedesktop.org/show_bug.cgi?id=16209 + +cairo-xlib: Improved performance with X server without Render +------------------------------------------------------------- +Cairo now performs better on remote X servers that lack the Render +extension by being smarter about using X core protocol facilities +instead of falling back to doing all rendering on the client side. + +cairo-ft: respecting FC_FT_FACE +------------------------------- +Previously it was impossible to instruct cairo to do emboldening on a +font face object created from an FT_Face. Cairo now respects and uses +the FC_FT_FACE fontconfig pattern element, so emboldening can be +achieved by using cairo_ft_font_face_create_for_pattern() and a +carefully crafted pattern using FC_FT_FACE and FC_EMBOLDEN. Thanks +Behdad! + +cairo-directfb: backend improvements +------------------------------------ +The directfb backend, though still unsupported, has seen a good deal +of improvements. Thanks Vlad! + +Bug fixing and optimizations +---------------------------- +xlib: Faster bookkeeping (Karl Tomlinson) + https://bugzilla.mozilla.org/show_bug.cgi?id=453199#c5 + +PS: Fix gradients with non-constant alpha (Chris Wilson) + +Fix deadlock in user-font code (Richard Hughes and Behdad Esfahbod) + https://bugs.freedesktop.org/show_bug.cgi?id=16819 + +Countless other bugs have been fixed and optimizations made, many of +them thanks to Chris Wilson. Thanks Chris and others! + +Note also that the code that had been in cairo 1.7.x calling into +freetype's optional lcd_filter function was removed from cairo before +the 1.8.0 release. We do expect this code to come back in some form in +the future. + +Snapshot 1.7.6 (2008-09-17 Carl Worth ) +========================================================== +The cairo community is happy to announce the 1.7.6 snapshot of the +cairo graphics library. This is a "release candidate" for the upcoming +1.8.0 release, so we will greatly appreciate any reports of problems +in this release, and no major changes are currently planned before +1.8. + +Notable changes in 1.7.6 +------------------------ +The largest number of changes since 1.7.4 did not change the +implementation of cairo itself, but instead revamped cairo's build +system. The primary goal of the revamp is to make the build system +less fragile, (particularly for non-Linux platforms). For example, now +people building on win32 will no longer need to maintain a +platform-specific list of files to be built. Also, the .so file will +now be installed with a different naming scheme, (for example, 1.7.6 +will install with a .10706 suffix). Much thanks, Behdad! + +And, as usual, Chris Wilson has made another large round of robustness +improvements, (eliminating dead code, fixing propagation of error +status values, test suite improvements, etc. etc.). Thanks as always, +Chris! + +API changes since 1.7.4 +----------------------- +There have been a few changes of API that was new during the 1.7 +series: + +* Remove cairo_font_options_set_lcd_filter + and cairo_font_options_get_lcd_filter + + Motivation: At the Cairo Summit, this API was determined to be too + specific to the freetype font backend to be in the general + API. A similar API with a cairo_ft prefix might be introduced + in the future. Note that cairo will still respect the + corresponding fontconfig settings for these options. + +* Replace cairo_has_show_glyphs + with cairo_surface_has_show_glyphs + + Motivation: This really is a surface-specific interface, and the + convenience function on the cairo_t is not obviously + necessary. An application can easily call: + + cairo_surface_has_show_glyphs (cairo_get_target (cr)); + + as needed. + +* Add cairo_text_cluster_flags_t + to cairo_show_text_glyphs + cairo_scaled_font_text_to_glyphs + cairo_user_scaled_font_text_to_glyphs_func_t + + Motivation: This flag, (and specifically the + CAIRO_TEXT_CLUSTER_FLAG_BACKWARD value), replaces the + cairo_bool_t backward argument in each of the above + interfaces. This leads to more readable user code, and also + allows future extensibility. + +As always, there are no changes to any API from any major cairo +release, (1.0.x, 1.2.x, 1.4.x, 1.6.x). Cairo maintains the same +compatibility promise it always has. + +Bug fixes since 1.7.4 +--------------------- +xlib: Faster bookkeeping (Karl Tomlinson) + https://bugzilla.mozilla.org/show_bug.cgi?id=453199#c5 + +PS: Fix gradients with non-constant alpha (Chris Wilson) + +Fix deadlock in user-font code (Richard Hughes and Behdad Esfahbod) + https://bugs.freedesktop.org/show_bug.cgi?id=16819 + +Several other minor fixes. + +Snapshot 1.7.4 (2008-08-11 Behdad Esfahbod ) +=============================================================== +The cairo community is embarrassed to announce availability of the 1.7.4 +snapshot of the cairo graphics library. This is a followup release to the +1.7.2 snapshot to ship a tarball that can actually be built. The only +change since 1.7.4 is including the missing header file +cairo-user-font-private.h in the distribution. + +Snapshot 1.7.2 (2008-08-11 Behdad Esfahbod ) +=============================================================== +The cairo community is finally ready to announce availability of the 1.7.2 +snapshot of the cairo graphics library. This is embarrassingly the first +snapshot in the 1.7 unstable series of cairo, leading to the eventual release +of cairo 1.8, currently planned for late September. + +This snapshot comes four months after the 1.6.4 release. We have done a +really bad job on getting development snapshots out this cycle, but +hopefully all the API changes for 1.8 are now finished and the remaining +weeks will be spent on bug-fixing. There is more than 400 commits worth +of changes in this snapshot, and those can use some testing. Read on! + +Text, text, and more text! +-------------------------- +The dominant theme of this release, and 1.8 in general, is improvements +around cairo text API. Here is a high-level list of changes with text +handling: + +User fonts +---------- +This is new API allowing the user of cairo API to provide drawings for glyphs +in a font. This is most useful in implementing fonts in non-standard formats, +like SVG fonts and Flash fonts, but can also be used by games and other +applications to draw "funky" fonts. See test/user-font.c and +test/user-font-proxy.c for usage examples. This is based on early work by +Kristian Høgsberg. Thanks Kristian! + +show_text_glyphs +---------------- +This new API allows the caller of cairo to mark text glyphs with their +original text. The PDF backend implements this new API and latest Pango +master uses it. The result is (when bugs are fixed) that complex text can be +copied out of pangocairo's PDF output correctly and reliably. There are bugs +to fix though. A few poppler bugs, and some more in cairo and pango. + +To test show_text_glyph, just grab pango master and this cairo snapshot and +print text in gedit. Open in acroread or evince, select all, copy, paste +in gedit and compare. The Arabic text with diacritic marks is particularly +showing bad. Try with pango/pango-view/HELLO.txt if you are brave +enough. The Indic text is showing improvements, but is still coming out +buggy. + +LCD subpixel filtering using FreeType +------------------------------------- +FreeType 2.3.5 added support for various LCD subpixel filtering, and +fontconfig 2.6.0 added support for configuring LCD filter on a font by font +basis. Cairo now relies on FreeType and fontconfig for subpixel filtering. +This work is based on David Turner's original patch to cairo, maintained +and tested by Sylvain Pasche and others. Thanks all! + +Toy font face constructor and getter +------------------------------------ +Mostly for API completion, but also useful for higher level (like Pango) to +hook into what the user has set using cairo_select_font_face(), making that +toy API a bit more useful. + +FreeType: respecting FC_FT_FACE +------------------------------- +Previously it was impossible to instruct cairo to do emboldening on a font +face object created from an FT_Face. Cairo now respects and uses the +FC_FT_FACE fontconfig pattern element, so emboldening can be achieved by +using cairo_ft_font_face_create_for_pattern() and a carefully crafted pattern +using FC_FT_FACE and FC_EMBOLDEN. + + +PS/PDF: More efficient output +----------------------------- +Adrian Johnson has been busy fixing all kinds of bugs in PS and PDF +backends, as well making them generate much more compact output by avoiding +things like re-emitting the color or linestyle on every drawing operation. +Thanks Adrian! + + +Xlib: Dithering +--------------- +Cairo now does simple dithering when rendering to legacy X servers. This is +mostly visible with 8-bit visuals. + +Xlib: Avoid rendering glyphs out of surface bounds +-------------------------------------------------- +This seemingly harmless change manifested a bug with OpenOffice.org 3 versions +where OO.o was passing bogus surface extents to cairo, resulting in no text +rendered in OO.o. Please contact your distro's OO.o maintainers if you see +this bug and point them to the following URL: + + https://bugs.freedesktop.org/show_bug.cgi?id=16209 + +Xlib: Improved performance with Xrender-less X servers +------------------------------------------------------ +Cairo now performs better on remote, Xrender-less X servers by being smarter +about using X core protocol facilities instead of falling back to doing all +rendering on the client side. + + +Directfb: backend improvements +------------------------------ +The directfb backend, though still unsupported, has seen a good deal of +improvements. Thanks Vlad! + + +Bug fixing and optimizations +---------------------------- +Countless bugs have been fixed and optimizations made, many of them thanks to +Chris Wilson. Thanks Chris! + + +API additions +------------- + +cairo_show_text_glyphs + + This is a new text rendering API. Being a more advanced version of + cairo_show_glyphs(), it is aimed for use by higher-level text toolkits like + Pango, and enables better text extraction from output generated by backends + like PDF and SVG. The PDF backend already implements it, and the upcoming + Pango release will use it. + + To make that API work, a bunch of other additions were made: + +cairo_glyph_allocate +cairo_glyph_free +cairo_text_cluster_t +cairo_text_cluster_allocate +cairo_text_cluster_free +cairo_surface_has_show_text_glyphs + + +cairo_user_font_face_create + + This is the "user" font face constructor, accompanied by a variety of method + signatures, getters, and setters for a callback-based font backend: + +CAIRO_FONT_TYPE_USER +cairo_user_scaled_font_init_func_t +cairo_user_scaled_font_render_glyph_func_t +cairo_user_scaled_font_text_to_glyphs_func_t +cairo_user_scaled_font_unicode_to_glyph_func_t +cairo_user_font_face_set_init_func +cairo_user_font_face_set_render_glyph_func +cairo_user_font_face_set_text_to_glyphs_func +cairo_user_font_face_set_unicode_to_glyph_func +cairo_user_font_face_get_init_func +cairo_user_font_face_get_render_glyph_func +cairo_user_font_face_get_text_to_glyphs_func +cairo_user_font_face_get_unicode_to_glyph_func + + +cairo_scaled_font_text_to_glyphs + + We were previously reluctant to provide this function as text-to-glyphs + support in cairo was limited to "toy" font functionality, not really + interesting for real-world text processing. However, with user-fonts + landing, this API is needed to expose full access to how user-fonts + convert text to glyphs. This is expected to be used by text toolkits like + Pango, as well as "proxy" user-font implementations. + + +cairo_lcd_filter_t +cairo_font_options_set_lcd_filter +cairo_font_options_get_lcd_filter + + These add the possibility to choose between various available LCD subpixel + filters. The available filter values are modelled after what FreeType + provides. + + +cairo_toy_font_face_create +cairo_toy_font_face_get_family +cairo_toy_font_face_get_slant +cairo_toy_font_face_get_weight + + These provide access to functionality and settings provided by + cairo_select_font_face(). + + +cairo_scaled_font_get_scale_matrix +cairo_surface_get_fallback_resolution + + For API completeness. + + +Various new values for cairo_status_t enum + + +Known issues: + +- Type3 fonts generated by cairo's PDF backend may show up in poppler/Evince + in a different color than expected. This is fixed in poppler master branch. + This mostly affects cairo user fonts. The test case test/user-font.c + demonstrates this. + +- User fonts using other fonts in their rendering are currently embedded in + PDF as fallback bitmap glyphs. This will be (hopefully) fixed before 1.8. + The test case test/user-font-proxy.c demonstrates this. + + +Release 1.6.4 (2008-04-11 Carl Worth ) +========================================================= +The cairo community is wildly embarrassed to announce the 1.6.4 +release of the cairo graphics library. This release reverts the xlib +locking change introduced in 1.6.4, (and the application crashes that +it caused). The community would be glad to sack its current release +manager and is accepting applications for someone who could do the job +with more discipline. + +Revert 'add missing locking in cairo-xlib' +------------------------------------------ +This change was introduced in cairo 1.6.2, but also introduced a bug +which causes many cairo-xlib applications to crash, (with a +segmentation fault inside of XSetClipMask). Instead of attempting +another fix for the broken fix, the change in 1.6.2 has been +reverted. The original bug which the change was addressing has been +present since at least cairo 1.4, so it is not expected that leaving +this bug unfixed will cause any new problems for applications moving +from cairo 1.4 to cairo 1.6. + +At this point, the code of cairo 1.6.4 differs from cairo 1.6.0 only +in the fix for the PostScript-printer crashes. + +Tweak build to avoid linking with g++ +------------------------------------- +Cairo 1.6.4 avoids a quirk in automake that was causing the cairo +library to be linked with g++ and linked against libstdc++ even when +only C source files were compiled for the library. + +Release 1.6.2 (2008-04-11 Carl Worth ) +========================================================= +The cairo community is pleased (but somewhat sheepish) to announce the +1.6.2 release of the cairo graphics library. This is an update to +yesterday's 1.6.0 release with an important fix to prevent cairo's +PostScript output from crashing some printers. This release also +includes a locking fix for cairo's xlib backend to improve thread +safety. There are no changes beyond these two fixes. + +Fix for PostScript printer crash +-------------------------------- +Adrian Johnson discovered that cairo 1.6.0 was being a bit hard on +PostScript printers, by changing the font matrix very frequently. This +causes some PostScript interpreters to allocate new font objects every +few glyphs, eventually exhausting available resources. The fix +involves leaving translational components of the font matrix as zero, +so that the PostScript interpreter sees an identical font matrix +repeatedly, and can more easily share internal font object resources. + +This fix has been tested to resolve the bugs posted here, (for both +Xerox and Dell printers): + + Printing some PDFs from evince is crashing our Xerox printer + https://bugs.freedesktop.org/show_bug.cgi?id=15348 + + Cairo-generated postscript blocks Dell 5100cn + https://bugs.freedesktop.org/show_bug.cgi?id=15445 + +Add missing locking in cairo-xlib +--------------------------------- +Chris Wilson noticed that cairo 1.6.0 was manipulating an internal +cache of GC object within cairo's Xlib backend without proper +locking. The missing locking could cause failures for multi-threaded +applications. He fixed this in 1.6.2 by adding the missing locks. + +Release 1.6.0 (2008-04-10 Carl Worth ) +========================================================= +The cairo community is quite pleased to announce the 1.6.0 release of +the cairo graphics library. This is a major update to cairo, with new +features and enhanced functionality which maintains compatibility for +applications written using cairo 1.4, 1.2, or 1.0. We recommend that +anybody using a previous version of cairo upgrade to cairo 1.6.0. + +The most significant new features in this release are dramatically +improved PDF and PostScript[*] output, support for arbitrary X server +visuals (including PseudoColor), a new Quartz backend, and and a new +"win32 printing" backend. See below for more details on these and +other new features. + +New dependency on external pixman library (Thanks, Søren!) +---------------------------------------------------------- +As of cairo 1.6, cairo now depends on the pixman library, for which +the latest release can be obtained alongside cairo: + + https://cairographics.org/releases/pixman-0.10.0.tar.gz + +This library provides all software rendering for cairo, (the +implementation of the image backend as well as any image fallbacks +required for other backends). This is the same code that was +previously included as part of cairo itself, but is now an external +library so that it can be shared by both cairo and by the X server, +(which is where the code originated). + +Improved PDF, PostScript, and SVG output (Thanks, Adrian!) +---------------------------------------------------------- +Users of the cairo-pdf, cairo-ps, and cairo-svg should see a dramatic +improvement from cairo 1.2/1.4 to 1.6. With this release there are now +almost no operations that will result in unnecessary rasterization in +the PDF and PostScript. Rasterized "image fallbacks" are restricted +only to minimal portions of the document where something is being +drawn with cairo that is beyond the native capabilities of the +document, (this is rare for PDF or SVG, but occurs when blending +translucent objects for PostScript). + +This means that the final output will be of higher quality, and will +also be much smaller, and therefore will print more quickly. The +machinery for doing analysis and minimal fallbacks also benefits the +win32-printing surface described below. + +In addition to doing less rasterization, the PostScript and PDF output +also has several other improvements to make the output more efficient +and more compatible with specifications. + +[*] Note: Just before this release, a bug has been reported that the +PostScript output from cairo can crash some printers, (so far the +following models have been reported as problematic Xerox Workcentre +7228 or 7328 and Dell 5100cn). We will implement a workaround as soon +as we can learn exactly what in cairo's output these printers object +to, (and we could use help from users that have access to misbehaving +printers). This bug is being tracked here: + + Printing some PDFs from evince is crashing our Xerox printer + https://bugs.freedesktop.org/show_bug.cgi?id=15348 + +New support for arbitrary X server visuals (Thanks, Keith and Behdad!) +---------------------------------------------------------------------- +As of cairo 1.6, cairo should now work with an arbitrary TrueColor or +8-bit PseudoColor X server visual. Previous versions of cairo did not +support these X servers and refused to draw anything. We're pleased to +announce that this limitation has been lifted and people stuck with +ancient display systems need no longer be stuck with ancient software +just because of cairo. + +New, supported Quartz backend for Mac OS X (Thanks, Brian and Vladimir!) +------------------------------------------------------------------------ +As of cairo 1.6, the cairo-quartz backend is now marked as "supported" +rather than "experimental" as in previous cairo releases. Its API now +has guarantees of API stability into future cairo releases, and its +output quality is comparable to other backends. There have been +significant improvements to cairo-quartz since 1.4. It now uses many +fewer image fallbacks, (meaning better performance), and has greatly +improved text rendering. + +New, "win32 printing" backend (Thanks, Adrian and Vladimir!) +------------------------------------------------------------ +A new win32-printing surface has been added with an interface very +similar to the original win32 surface, (both accept an HDC +parameter). But this new surface should only be called with a printing +DC, and will result in all drawing commands being stored into a +meta-surface and emitted after each page is complete. This allows +cairo to analyze the contents, (as it does with PDF, PostScript, and +SVG backends), and to do minimal image-based fallbacks as +necessary. The analysis keeps things as efficient as possible, while +the presence of fallbacks, (when necessary), ensure the consistent, +high-quality output expected from cairo. + +Robustness fixes (Thanks, Chris!) +--------------------------------- +There has been a tremendous number of improvements to cairo's +robustness. Areas that have been improved include: + + * Proper reporting of errors + + * Responding correctly to invalid input + + * Avoiding integer overflows + + * Avoiding memory leaks on error-recovery paths + + * Making reference counting thread safe + + * Exhaustive testing of memory allocation points + +Other fixes (Thanks, everybody!) +-------------------------------- +Cairo's internal fixed-point representation has been changed from +16.16 to 24.8. This has a direct impact on applications as it allows +much larger objects to be drawn before internal limits in cairo make +the drawing not work. + +The CAIRO_EXTEND_PAD mode is now fully supported by surface +patterns. This mode allows applications to use cairo_rectangle and +cairo_fill to draw scaled images with high-quality bilinear filtering +for the internal of the image, but without any objectionably blurry +edges, (as would happen with the default EXTEND_NONE and cairo_paint). + +Rendering with CAIRO_ANTIALIAS_NONE has been fixed to be more +predictable, (previously image rendering and geometry rendering would +be slightly misaligned with respect to each other). + +The reference manual at https://cairographics.org/manual now documents +100% of the functions and types in cairo's public API. + +API additions +------------- +Several small features have been added to cairo with new API functions: + +cairo_format_stride_for_width + + Must be called to compute a properly aligned stride value before + calling cairo_image_surface_create_for_data. + +cairo_has_current_point + + Allows querying if there is a current point defined for the + current path. + +cairo_path_extents + + Allows querying for path extents, (independent of any fill or + stroke parameters). + +cairo_surface_copy_page +cairo_surface_show_page + + Allow beginning a new document page without requiring a cairo_t + object. + +cairo_ps_surface_restrict_to_level +cairo_ps_get_levels +cairo_ps_level_to_string +cairo_ps_surface_set_eps + + Allow controlling the Post PostScript level, (2 or 3), to + target, as well as to generate Encapsulated PostScript (EPS). + +cairo_quartz_font_face_create_for_cgfont + + Create a quartz-specific cairo_font_face_t from a CGFontRef. + +cairo_win32_font_face_create_for_logfontw_hfont + + Create a win32-specific cairo_font_face from a LOGFONTW and an + HFONT together. + +Thanks, Everyone! +----------------- +I've accounted for 32 distinct people with attributed code added to +cairo between 1.4.14 and 1.6.0, (their names are below). That's an +impressive number, but there are certainly dozens more that +contributed with testing, suggestions, clarifying questions, and +encouragement. I'm grateful for the friendships that have developed as +we have worked on cairo together. Thanks to everyone for making this +all so much fun! + +Adrian Johnson, Alp Toker, Antoine Azar, Behdad Esfahbod, +Benjamin Otte, Bernardo Innocenti, Bertram Felgenhauer, +Boying Lu, Brian Ewins, Carl Worth, Chris Heath, Chris Wilson, +Claudio Ciccani, Emmanuel Pacaud, Jeff Muizelaar, Jeremy Huddleston, +Jim Meyering, Jinghua Luo, Jody Goldberg, Jonathan Gramain, +Keith Packard, Ken Herron, Kouhei Sutou, Kristian Høgsberg, +Larry Ewing, Martin Ejdestig, Nis Martensen, Peter Weilbacher, +Richard Hult, Shailendra Jain, Søren Sandmann Pedersen, +Vladimir Vukicevic + +Snapshot 1.5.20 (2008-04-04 Carl Worth ) +=========================================================== +This is the tenth snapshot in cairo's unstable 1.5 series. It comes +just two days (and only one working day) after the 1.5.18 +snapshot. The quick snapshot is due to two embarrassing bugs (both +affecting cairo-xlib) that had been introduced in the 1.5.18 +snapshot. The fixes for these are described below along with a few +other fixes, (which hopefully aren't introducing new bugs this time). + +cairo-xlib +---------- +Revert fix from 1.5.18 to allow pattern expansion based on the filter +mode. This fix seemed so boring, (the use case it addresses is almost +never used in practice), that it didn't even get mentioned in the +1.5.18 release notes. However, the "fix" happened to break rendering +that is always used resulting in corrupt image rendering in mozilla, +evolution, and probably everything else that uses cairo. + +Fix to avoid BadMatch errors in cairo_surface_create_similar. These +were introduced, (inadvertently, of course), as part of the fix in +1.5.18 for creating similar surfaces without the Render +extension. Again, thanks to mozilla, (and Vladimir Vukicevic in +particular), for noticing our mistake. + +general +------- +Correctly handle an in-error surface in +cairo_surface_write_to_png. Previously this function would cause an +assertion failure if you gave it a finished surface. Now it cleanly +returns a CAIRO_STATUS_SURFACE_FINISHED result instead. + +Avoid potentially infinite wandering through memory inside +_cairo_hull_prev_valid. Thanks to Jonathan Watt for noticing this +problem: + + https://bugzilla.mozilla.org/show_bug.cgi?id=306649#c21 + +cairo-pdf +--------- +Fix generation of "soft" masks made by drawing to a similar surface +and then calling cairo_mask_surface() with it. + +cairo-svg +--------- +Fix for code that uses cairo_mask() on an intermediate surface which +is later passed to cairo_mask_surface(). + +Snapshot 1.5.18 (2008-04-05 Carl Worth ) +=========================================================== +This is the ninth snapshot in cairo's unstable 1.5 series. It comes +just 4 days after the 1.5.16 snapshot. We had hoped to not need +another snapshot before the final 1.6.0 release, but several critical +bugs were found and fixed in the last few days, so we thought it +important to let people test the fixes with this snapshot. See below +for details. + +documentation +------------- +The README now lists necessary dependencies. + +Various graphics state defaults are now documented, (source pattern is +opaque black, line width is 2.0, line join is miter, line cap is butt, +miter limit is 10.0, etc.). + +general +------- +Several cleanups have been made along many error-path returns, +(carefully propagating up the original error status values, cleaning +up memory leaks during error recovery, etc.). This is yet another in +Chris "ickle" Wilson's long series of error-handling cleanups during +the 1.5 series. + +Avoid undesired clipping when drawing scaled surface patterns with +bilinear filtering. + +cairo-pdf +--------- +Fix emission of 1-bit alpha masks in PDF output. + +Fix a bug that would cause glyphs to be misplaced along the Y axis: + + http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=%23474136 + + Originally, an issue about a crash, but later leading to the + misplaced glyphs issue being discovered. + +cairo-ps +-------- +Fix misplaced glyphs in cairo's PostScript output. + + This issue occurs when consecutive glyphs are placed far + apart. This case is exercised by the new ft-show-glyphs-table test + case, which was originally inspired by the Debian bug #23474136 + mentioned above. + +Fix more misplaced glyphs in cairo's PostScript output: + + The issue here showed up under very particular circumstance, (when + converting a PDF file with a CFF font with CID Identity-H encoding + and using glyph 0, (defined by the CFF specification as .notdef) + as a space instead). More concretely, this problem appeared when + converting the UbuntuDesktop.pdf file mentioned in this bug + report: + + https://bugs.freedesktop.org/show_bug.cgi?id=15348#c3 + + As usual with arcane font-encoding-specific bugs like this, many + thanks to Adrian Johnson for his magical ability to dive into + specifications and emerge almost instantaneously with fixes. And + thanks to Sebastien Bacher for bringing the bug to our attention. + +cairo-xlib +---------- +Fix serious failure on X servers without the Render extension. + + Since the 1.5.14 snapshot (with support for PseudoColor visuals), + any application attempting to create a "similar" xlib surface would + fail on an X server without the Render extension. Thanks to + Frederic Crozat for pointing out that cairo's test suite was + entirely failing when run against Xvfb. + +Avoid crashing cairo-xlib applications for too-large glyphs + + Naively sending glyphs of any size to the X server will eventually + violate the X limit on maximum request sizes. We now properly + detect when a glyph would be too large and use existing fallbacks + to render the glyph rather than trying to send it to the X server. + +Enable the buggy_repeat workaround for Xorg servers < 1.4 + + We have determined that Xorg 1.3.0 (as packaged in Fedora 8 at + least) has a bug that can result in an X server crash when cairo + uses certain X Render repeat operations, (as exercised by cairo's + extend-reflect test). We avoid this crash by using fallbacks + whenever a repeating surface is needed for any Xorg server with a + version less than 1.4. This is slower, but should prevent the + crash. + + (Meanwhile, there appears to be a separate bug where some X + servers or specific X-server drivers will use random pixmap data + when asked to draw a repeating surface. The buggy_repeat + workaround would also avoid those problems, but we have not yet + characterized whether the new "version < 1.4" is a good + characterization of those problems or not.) + +cairo-quartz-font +----------------- +Implement cairo_font_extents for this backend. + +The cairo-quartz-font implementation added in the 1.5.14 snapshot was +entirely missing support for the cairo_font_extents function. Thanks to +Richard Hult for pointing out this obvious shortcoming, (and obvious +lack of coverage in our test suite): + + CGFont backend returns 0 font extents + https://bugs.freedesktop.org/show_bug.cgi?id=15319 + +Snapshot 1.5.16 (2008-04-01 Carl Worth ) +=========================================================== +This is the eighth snapshot in cairo's unstable 1.5 series. It comes +less than two weeks after the 1.5.14 snapshot and it really is a +legitimate snapshot, (in spite of sharing this date with that of many +bogus announcements). The major change in this snapshot is that the +cairo-quartz backend is now officially "supported", including new API +to construct a font face from a CGFontRef . Also several bug fixes +have been fixed in many backends. See below for details. + +general +------- +Cairo now depends on pixman 0.10.0 which was recently released. The +latest pixman release can always be found alongside cairo releases at: + + https://cairographics.org/releases + +Increase the precision of color stops for gradients. This fixes a +regression in gradient rendering that had been present since the +1.5.12 snapshot. + +paginated (all of ps, pdf, svg, and win32-printing) +--------------------------------------------------- +Fix assertion failure when some drawing elements are outside the page +boundaries, (this bug was noticed when using Inkscape to print a +drawing with landscape orientation to a portrait-oriented piece of +paper). + +cairo-ps +-------- +Fix of bug causing incorrect glyph positioning. + +Fix handling of CAIRO_OPERATOR_SOURCE. + +cairo-pdf +--------- +More reduction of unnecessary digits of precision in PDF output. + +Fix handling of CAIRO_OPERATOR_SOURCE. + +cairo-svg +--------- +Fix bug in usage of libpng that was preventing cairo_mask from working +with the svg backend. + +Fix transformation of source pattern for cairo_stroke(). + +cairo-win32-printing +-------------------- +Fix fallback resolution, (thanks again to inkscape users/developers +for helping us find this one). + +cairo-quartz +------------ +Mark the cairo-quartz backend as "supported" rather than +"experimental". This means the following: + + * The backend will now be built by default (if possible). + + * We are committing that the backend-specific API (as published in + cairo-quartz.h) are stable and will be supported in all future + cairo 1.x releases. + + * We are committing that the output quality of this backend + compares favorably with other cairo backends, (and that quality + is ensured by good results from the cairo test suite). + + * We recommend that distributions build and distribute this + backend when possible. + +Note that the cairo_quartz_image API (in cairo-quartz-image.h) is +still experimental, will not build by default, (pass +--enable-quartz-image to configure to build it), and may see API +changes before it is marked as "supported" in a future release. + +Put the CAIRO_FONT_TYPE_ATSUI name back into +cairo-deprecated.h. Without this, the cairo 1.5.14 snapshot broke all +builds for applications using the C++ cairomm bindings (and perhaps +others) which have the CAIRO_FONT_TYPE_ATSUI name in their header +files. This breakage happened even for applications not using +cairo-quartz at all. + + Note: Even though the CAIRO_FONT_TYPE_ATSUI name is provided to + avoid this build breakage, we still recommend that bindings and + applications move to the new, and more accurate, + CAIRO_FONT_TYPE_QUARTZ name. + +Replace the implementation of cairo-quartz-font to use CFFont instead +of ATSUI. The CGFont API is a better fit than ATSUI, and this new +implementation is also more correct than the old one as well. + +This also adds the following new API call: + + cairo_public cairo_font_face_t * + cairo_quartz_font_face_create_for_cgfont (CGFontRef font); + +The previous cairo_quartz_font_face_create_for_atsu_font_id function +continues to exist and is part of the supported API going +forward. (However, the old name of that same function, which was +cairo_atsui_font_face_create_for_atsu_font_id is officially +deprecated. Any source code using the old name should be updated to +use the new name.) + +Fix transformation of source pattern for cairo_stroke(). + +cairo-win32 +----------- +Avoid crash in create_similar is cairo_win32_surface_create fails. + +Snapshot 1.5.14 (2008-03-20 Carl Worth ) +=========================================================== +This is the seventh snapshot in cairo's unstable 1.5 series. It comes +3 weeks after the 1.5.12 snapshot. This snapshot includes support for +arbitrary X server visuals, (including PseudoColor), which was the +final remaining cairo-specific item on the cairo 1.6 roadmap. It also +includes a huge number of improvements to the cairo-quartz backend. So +this is effectively a cairo 1.6 release candidate. We expect very few +changes from now until 1.6 and only for specific bug fixes. + +API Change +---------- +Rename ATSUI font backend to Quartz font backend. This affects the +following usage: + + --enable-atsui -> --enable-quartz-font + CAIRO_HAS_ATSUI_FONT -> CAIRO_HAS_QUARTZ_FONT + CAIRO_FONT_TYPE_ATSUI -> CAIRO_FONT_TYPE_QUARTZ + + cairo_atsui_font_face_create_for_atsu_font_id -> + cairo_quartz_font_font_create_for_atsu_font_id + +This API change is justified by the cairo-quartz backend still be +marked as "experimental" rather than "supported", (though this is one +step toward making the change to "supported" before 1.6). Cairo will +still provide ABI compatibility with the old symbol name, however. + +paginated (all of ps, pdf, svg, and win32-printing) +--------------------------------------------------- +Optimize by not analyzing an image surface for transparency more than +once, (previously all images were analyzed twice). + +cairo-ps and cairo-pdf +---------------------- +Avoiding emitting a matrix into the stroke output when unnecessary, +(making output size more efficient). + +Reduce rounding error of path shapes by factoring large scale factors +out of the path matrix, (ensuring that a fixed-number of printed +digits for path coordinates contains as much information as possible). + +Reduce excess digits for text position coordinates. This makes the +output file size much smaller without making the result any less +correct. + +cairo-ps +-------- +Eliminate bug causing extraneous text repetition on Linux PostScript +output in some cases. + + See: Mozilla Bug 419917 – Printed page contents are reflected + inside bordered tables (Linux-only) + + https://bugzilla.mozilla.org/show_bug.cgi?id=419917 + +Optimize output when EXTEND_PAD is used. + +cairo-pdf +--------- +Fix to not use fill-stroke operator with transparent fill, (else PDF +output doesn't match the cairo-defined correct result). See: + + https://bugs.launchpad.net/inkscape/+bug/202096 + +cairo-svg +--------- +Fix stroke of path with a non-solid-color source pattern: + + https://bugs.freedesktop.org/show_bug.cgi?id=14556 + +cairo-quartz +------------ +Fix text rendering with gradient or image source pattern. + +Handling antialiasing correctly for cairo_stroke(), cairo_clip(), and +cairo_show_text()/cairo_show_glyphs(). + +Correctly handle gradients with non-identity transformations: + + Fixes https://bugs.freedesktop.org/show_bug.cgi?id=14248 + +Add native implementation of REPEAT and REFLECT extend modes for +gradients. + +Fix implementation for the "unbounded" operators, (CAIRO_OPERATOR_OUT, +_IN, _DEST_IN, and _DEST_ATOP). + +Correctly handle endiannees in multi-architecture compiles on Mac OS +X. + +Avoid behavior which would cause Core Graphics to print warnings to +the console in some cases. + +cairo-win32 +----------- +Fix handling of miter limit. + +cairo-win32-printing +-------------------- +Fix to not use a 1bpp temporary surface in some cases while printing, +(so grayscale data is preserved rather than just becoming black and +white). + +cairo-xlib +---------- +Add support for rendering to arbitrary TrueColor X server +visuals. This fixes at least the following bugs: + + cairo doesn't support 8-bit truecolor visuals + https://bugs.freedesktop.org/show_bug.cgi?id=7735 + + cairo doesn't support 655 xlib format + https://bugs.freedesktop.org/show_bug.cgi?id=9719 + +Add support for rendering to 8-bit PseudoColor X server visuals. This +fixes the following bug: + + Cairo doesn't support 8-bit pseudocolor visuals + https://bugs.freedesktop.org/show_bug.cgi?id=4945 + +Snapshot 1.5.12 (2008-02-28 Carl Worth ) +=========================================================== +This is the sixth snapshot in cairo's unstable 1.5 series. It comes 1 +week after the 1.5.10 snapshot. This snapshot includes the +long-awaited change from 16.16 to 24.8 fixed-point values, (see below +for why you should care). It also includes several backend-specific +bug fixes. + +24.8 fixed-point format +----------------------- +Cairo has always converted path coordinates to a fixed-point +representation very early in its processing. Historically, this has +been a 32-bit representation with 16 bits of integer for the +device-pixel grid and 16 bits of sub-pixel positioning. The choice of +16 bits for the integer coordinate space was based on the 16-bit limit +for X Window drawables. + +This 16-bit limit has proven problematic for many applications. It's +an especially vexing problem when targeting non-X backends that don't +have any 16-bit restriction. But even when targeting cairo-xlib, it's +often desirable to draw a large shape, (say a background rectangle), +that extends beyond the surface bounds and expect it to fill the +surface completely, (rather than overflowing and triggering random +behavior). + +Meanwhile, nobody has ever really needed 16 bits of sub-pixel +precision. + +With this snapshot, the fixed-point system is still in place and is +still using a 32-bit representation, (future versions of cairo might +move entirely to floating-point when targeting PDF output for +example). But the representation now provides 24 bits of pixel +addressing and only 8 bits of sub-pixel positioning. This should give +a much less stifling space to many applications. + +However, the underlying pixman library still has 16-bit limitations in +many places, (it has its roots in the X server as well). Until those +are also fixed, applications targeting cairo image surfaces, or +hitting software fallbacks when targeting other surfaces will still +encounter problems with device-space values needing more than 16 +integer bits. + +generic fixes +------------- +Add a few tests to the test suite to increase coverage. + +Cleanup a few error-handling paths, (propagate error correctly). + +cairo-ft +-------- +Fix handling of font sizes smaller than 1 device pixel. + +cairo-pdf +--------- +Fix to properly save/restore clip when analyzing meta-surface +patterns, (fixing a couple of test-suite failures). + +Implement native support for CAIRO_OPERATOR_SOURCE when the source +pattern is opaque. + +Emit rectangles as PDF rectangles ("re" operator) rather than as +general paths. + +cairo-ps +-------- +Fix to work properly with the 16.16->24.8 change. + +cairo-svg +--------- +Fix CAIRO_EXTEND_REFLECT by using an image fallback, (there's no +direct SVG support for reflected patterns). + +Fix the use of alpha-only masks, (such as CAIRO_FORMAT_A8). + +cairo-quartz +------------ +Add new API for efficiently using image data as a source: + + cairo_surface_t * + cairo_quartz_image_surface_create (cairo_surface_t *image_surface); + + cairo_surface_t * + cairo_quartz_image_surface_get_image (cairo_surface_t *surface); + +For full documentation, see: + + https://cairographics.org/manual/cairo-Quartz-Surfaces.html#cairo-quartz-image-surface-create + +Several fixes for cairo_mask(). + +cairo-atsui +----------- +Change default from from Monaco to Helvetica to be more consistent +with other font backends. + +Snapshot 1.5.10 (2008-02-20 Carl Worth ) +=========================================================== +This is the fifth snapshot in cairo's unstable 1.5 series. It comes 3 +weeks after the 1.5.8 snapshot. This snapshot adds one new API +function, (cairo_has_current_point), and the usual mix of +improvements, (more efficient PostScript/PDF output, optimized +stroking), and fixes (more robust error-handling, etc.). See below for +details. + +New API +------- +Add a new function to query if there is a current point: + + cairo_bool_t + cairo_has_current_point (cairo_t *cr); + +There is no current point immediately after cairo_create(), nor after +cairo_new_path() or cairo_new_sub_path(). There is a current point +after any of the path-creation functions, (cairo_move_to, +cairo_line_to, cairo_curve_to, etc.). + +With this new function, we also revert the change of the return type +of cairo_get_current_point from cairo 1.5.8, (it's now a void function +again). + +Optimizations +------------- +Optimize stroking code to avoid repeated calculation of redundant +values, (particularly significant for very large, offscreen paths). + +General fixes +------------- +Patch a few more potential buffer overruns, (due to integer +overflow). + +Many fixes and improvements to cairo's error-handling, (ensure that +correct error values are returned, clean up memory leaks on +error-handling paths, etc.). + +Fix a potential infinite loop when stroking a spline with a pen that +has been transformed to a line segment. + +Remove treating NULL as a synonym for a valid cairo_font_options_t* +with default values, (a change that had been introduced as of cairo +1.5.8). + +Remove the altered handling of tolerance and fallback-resolution that +had been introduced as of cairo 1.5.4. + +cairo-xlib +---------- +Pass the original Drawable, (as opposed to the root window), to +XCreatePixmap when creating a similar surface. This gives the X server +more information so that it can be clever and efficient. + +cairo-pdf +--------- +Fix the rendering of repeating and reflecting patterns. + +Ensure miter limit is always >= 1, (smaller limits are not meaningful, +but they can cause some PDF viewers to fail to display pages). + +Generate more efficient output when the same path is used for both +fill and stroke. + +cairo-ps +-------- +Start sharing much of the cairo-pdf code rather than implementing very +similar code in cairo-ps. + +Implement native support for repeating and reflecting linear +gradients. + +Implement reflected surface patterns. + +Ensure miter limit is always >= 1, (smaller limits are not meaningful, +but they can cause some PostScript viewers to crash). + +Generate PostScript that will perform more efficiently and use less +memory on printers, (use currentfile instead of a giant string array +for image data, and avoid using PostScript patterns for paint() and +fill() when possible). + +cairo-svg +--------- +Avoid unnecessary rasterization when copying a "similar" surface to +another svg surface, (allow the SOURCE operator to be implemented with +all-vector operations if there are no underlying objects). + +cairo-atsui +----------- +Eliminate infinite loop when attempting to render an empty string. + +Snapshot 1.5.8 (2008-01-30 Carl Worth ) +========================================================== +This is the fourth snapshot in cairo's unstable 1.5 series. It comes 2 +weeks after the 1.5.6 snapshot. It adds a few new API functions. Most +notably all callers of cairo_image_surface_create_for_data should now +be calling cairo_format_stride_for_width to compute a legal stride +value. See below for more details. + +New API in cairo 1.5.8 +---------------------- +We've added a new function that should be called to compute a legal +stride value before allocating data to be used with +cairo_image_surface_create_for_data: + + int + cairo_format_stride_for_width (cairo_format_t format, + int width); + +We've also added a new cairo_path_extents function that can be used to +compute a bounding box for geometry such as a single line segment, +(contrast with cairo_path_extents and cairo_stroke_extents): + + void + cairo_path_extents (cairo_t *cr, + double *x1, double *y1, + double *x2, double *y2); + +And finally, we've added a function to allow for querying the +XRenderPictFormat of a cairo-xlib surface: + + XRenderPictFormat * + cairo_xlib_surface_get_xrender_format (cairo_surface_t *surface); + +API changes +----------- +Fix return types of cairo_surface_show_page and +cairo_surface_copy_page. This is an API change to functions that are +new in the 1.5 series, so not an API break compared to any stable +cairo release, (1.0.x, 1.2.x, 1.4.x). + +Change the return type of cairo_get_current_point() from void to +cairo_status_t. This allows the caller to receive a +CAIRO_STATUS_NO_CURRENT_POINT value to distinguish the a current point +at the origin from no current point existing. + +Performance improvement +----------------------- +Improve performance of clipping by using an optimized code path +internally, (with the ADD operator instead of IN). + +General bug fixes +----------------- +Fix various cairo_*_extents functions to initialize the return-value +variables even in the case of a cairo_t in error. + +Treat NULL as a legitimate value for cairo_font_options_t*. [NOTE: +On discussion afterwards, we decided against this change so it has +been removed as of cairo 1.5.10.] + +Fix rendering with CAIRO_ANTIALIAS_NONE to be more predictable, (that +is, to avoid seams appearing when geometry and imagery share an +identical edge). Portions of this fix are in the pixman library and +will appear in a future release of that library. + +Avoid triggering an error for a font size of 0. + +Miscellaneous changes +--------------------- +Require pixman >= 0.9.6. + +There has been a tremendous amount improvement to cairo's +documentation. We're delighted that 100% of the public API has at +least some documentation in the API reference manual. Many thanks to +Behdad Esfahbod and Nis Martensen for leading this effort. + +cairo-pdf and cairo-ps +---------------------- +Eliminate failure when a Type 1 font is embedded with an explicit +glyph 0. + +cairo-pdf +--------- +Implement a more correct and more efficient approach for patterns with +an extend mode of CAIRO_EXTEND_REFLECT. + +cairo-ps +-------- +Fix image masks to properly pack and pad mask bits. + +cairo-quartz +------------ +Take care to only use DrawTiledImage for integer-aligned images, (and +use slower paths to get the correct result in other cases). + +cairo-win32 +----------- +Fix for older versions of mingw. + +Improve the handling of the clipping with the win32 and win32-printing +surfaces. + +Fix rendering of non black/white text. + +Snapshot 1.5.6 (2008-01-15 Carl Worth ) +========================================================== +This is the third snapshot in cairo's unstable 1.5 series. It comes +about 6 weeks after the 1.5.4 snapshot. The only API addition compared +to 1.5.4 is very minor, (a new value CAIRO_STATUS_TEMP_FILE_ERROR). +The remainder of the changes are the usual accumulation of bug fixes +and improvements. See below for details. + +General bug fixes +----------------- +Fix handling of fonts that contain a mixture of outline and bitmapped +glyphs. There was a change in this handling in 1.5.4 that improved +some cases and also regressed other cases. Now, all cases should be +handled quite well. + +Fix alignment issues that were causing SIGBUS failures on SPARC. + +Fix a regression (which first appeared in 1.5.2) where stroking under +a large scale would sometimes incorrectly replace a miter join with a +bevel join. (Thanks to Keith Packard.) + +Fix reporting of zero-sized extents to be {0,0} rather than +{INT_MAX,INT_MIN}. This avoids several integer overflow and +allocations of massive regions in some cases. + +Fix failures of gradients with no stops, (quartz, ps, and pdf). + +Fix handling of Type 1 fonts on Windows platforms. + +Fix handling of Type 1 fonts with no specific family name in the font +itself, (generate a CairoFont-x-y name). + +Handle NULL string values in cairo_show_text, cairo_show_glyphs, and +friends. + +Many robustness improvements along error-handling paths, (thanks as +always, to Chris "ickle" Wilson). + +Various other minor fixes. + +Paginated backends (PDF/PostScript/win32-printing) +-------------------------------------------------- +Avoid unnecessary rasterization when using a paginated surface as a +source, (such as drawing from one pdf surface to another). + +Fix replaying of paginated surface with more than one level of push/pop +group. + +cairo-xlib +---------- +Fix xlib backend to not consider recent X server release as having a +buggy repeat implementation in the Render extension. + +cairo-pdf +--------- +Fix PDF output to avoid triggering very slow rendering in PDF viewers, +(avoid starting and stopping the content stream for each pattern +emission). + +Support CAIRO_OPERATOR_SOURCE in cases where there is nothing below +the object being drawn. + +Fix to avoid seams appearing between multiple fallback regions. + +cairo-ps (PostScript) +--------------------- +Use correct bounding box in Type 3 fonts. + +Fix several bugs in cairo's PostScript output. These include making +the PostScript output more compatible with recent versions of +ghostscript that are more strict about Type 3 fonts, for +example. + +Fix for win32 to not attempt to create temporary files in the root +directory, (where the user may not have write permission). + +Avoid generating Level 3 PostScript if Level 2 is sufficient. Also, +add code in output documents to alert the user if Level 3 PostScript +is handed to a device that cannot handle PostScript beyond Level +2. + +cairo-directfb +-------------- +Various performance optimizations. + +Fixed support for small surfaces (less than 8x8). + +Provide support for environment variables CAIRO_DIRECTFB_NO_ACCEL to +disable acceleration and CAIRO_DIRECTFB_ARGB_FONT to enable ARGB fonts +instead of A8. + +cairo-os2 +--------- +Allow OS/2 APIs instead of C library allocation functions. + +Snapshot 1.5.4 (2007-12-05 Carl Worth ) +========================================================== +This is the second snapshot in cairo's unstable 1.5 series. It comes +just over 1 month after the 1.5.2 snapshot. There are no API changes +or additions in 1.5.4 compared to 1.5.2, but there are several bug +fixes, and some optimizations. Most of these apply to particular +backends. See below for details. + +General improvements +-------------------- +Use less memory for spline approximation calculations. + +Change how the tolerance value is interpreted with regard to +fallback-resolution. [Note: On further discussion, we decided against +this change for now. It is removed as of cairo 1.5.10.] + +Fix precision of floating-point values in vector-output backends to +avoid rounding errors with very small numbers. + +Xlib improvements +----------------- +Fix bug in glyph rendering with xlib, (due to everything being clipped +out). This was a regression in the 1.5.2 snapshot that was visible in +the GIMP, for example. See: + + cairo 1.5.2 causes font problems in GIMP 2.4 status bar and evolution 2.12.1 + https://bugs.freedesktop.org/show_bug.cgi?id=13084 + +PostScript improvements +----------------------- +Fix bug leading to invalid PostScript files when rendering +text, (need "0 0 xyshow" instead of "0 xyshow"). + +Fix many issues with Type 3 fonts, including making the resulting text +extractable. + +Quartz improvements +------------------- +Fix font metrics height value for ATSUI, (helps webkit on GTK+ OS X +layout nicely). + +Fix gradients. + +Fix EXTEND_NONE mode for patterns. + +Fix cairo_quartz_surface_create to properly clear the new surface +in cairo_quartz_surface_create. + +Fix to correctly handle 0x0 sized surfaces. + +Optimize drawing of EXTEND_REPEAT patterns for OS X 10.5. + +Snapshot 1.5.2 (2007-10-30 Carl Worth ) +========================================================== +This is the first snapshot in cairo's unstable 1.5 series. It comes 4 +months after the 1.4.10 release. This snapshot includes significant +improvements to PDF and PostScript output, which is one of the things +in which we're most interested in getting feedback. There are a couple +of minor API additions, and several optimizations, (primarily in the +"print/vector" backends). And there are dozens of bug fixes and +robustness improvements. + +New dependency on external pixman library +----------------------------------------- +A significant change in this snapshot compared to all previous cairo +releases is that cairo now depends on an external "pixman" library for +its software rendering. Previously this same code was compiled +internally as part of cairo, but now the code is separate so that both +cairo and the X server can now share common code, (thanks very much to +Søren Sandmann for his work on separating pixman and maintaining it). + +So users will need to acquire and build pixman before being able to +build cairo. The current release is 0.9.6 and can be obtained from +here: + + https://cairographics.org/releases/pixman-0.9.6.tar.gz + + which can be verified with: + + https://cairographics.org/releases/pixman-0.9.6.tar.gz.sha1 + 66f01a682c64403a3d7a855ba5aa609ed93bcb9e pixman-0.9.6.tar.gz + + https://cairographics.org/releases/pixman-0.9.6.tar.gz.sha1.asc + (signed by Carl Worth) + +Major PDF/PostScript improvements +--------------------------------- +Adrian Johnson has done some long-awaited work to make cairo's PDF and +PostScript output more interesting than ever before. First, many +operations that previously triggered image fallbacks will now be +rendered as native vectors. These operations include: + + PDF: cairo_push_group, cairo_surface_create_similar, + cairo_mask, A8/A1 surface sources, repeating/reflecting linear + gradients. + + PostScript: cairo_push_group, cairo_surface_create_similar, + gradients, bilevel alpha masks, (for example, all values either 0 or + 255 for an A8 mask). + +Not only that, but when an image fallback is required, it will now be +limited to only the necessary region. For example, a tiny translucent +image overlaying a small portion of text would previously caused an +entire PostScript page to be rendered as a giant image. Now, the +majority of that page will be nice text, and there will only be a tiny +image in the output. + +Additionally, the PostScript output now carefully encodes text so that +if it is subsequently converted to PDF, the text will be +selectable. + +This is very exciting progress, and we're hoping to hear from users +during the 1.5 series about how things have improved, (for example, +inkscape users doing cairo-based PDF export: please let us know how +things look). And feel free to pass your thanks along to Adrian for his excellent work. + +NOTE: This much improved PDF output makes more sophisticated use of +functionality in the PDF specification. This means that cairo's output +will sometimes expose bugs in some free software PDF viewers, (evince, +poppler, and xpdf, for example), that are not yet ready for such PDF +files. We're working with the poppler maintainers to get these bugs +fixed as quickly as possible. In the meantime, please double-check +with other PDF viewers if cairo-generated PDF files are not being +rendered correctly. It may be due to a bug in the viewer rather than +in the PDF file that cairo has created. + +Robustness improvements +----------------------- +Chris Wilson has made the largest contribution by far to cairo 1.5.2, +(in number of commits). His more than 150 commits include a huge +number of fixes to increase cairo's robustness. These fixes make cairo +more robust against invalid and degenerate input, (NaN, empty path, +etc.), against size-0 malloc calls, against memory leaks on +error-recovery paths, and against other failures during error +handling. He also implemented atomic operations to cairo, and used +them to fix cairo's previously non-thread-safe reference counting, +again improving robustness. + +Chris has put a tremendous amount of time and effort into writing +analysis tools for this work, and in running those tools and fixing +the problems they report. We're very grateful for this work, and hope +that all cairo users appreciate the more robust implementation that +results from it. + +This work is largely thankless, so it might make sense to notice +sometime that cairo has been running quite smoothly for you, and when +you do, send a quick "thank you" off to Chris Wilson, since it +is all definitely running smoother thanks to his work. + +New API +------- +There are no major additions to cairo's core API. The only new, +generic functions are: + + void + cairo_surface_copy_page (cairo_surface_t *surface); + + void + cairo_surface_show_page (cairo_surface_t *surface); + +which can now be used much more conveniently than the existing +cairo_copy_page and cairo_show_page functions in some +situations. These functions act identically, but require only a +cairo_surface_t* and not a cairo_t*. + +All other API additions are specific to particular backends. + +New cairo-win32 API (new font face function and "win32 printing" surface) +------------------------------------------------------------------------- +There is a new function for creating a win32 font face for both a +logfontw and an hfont together. This complements the existing +functions for creating a font face from one or the other: + + cairo_font_face_t * + cairo_win32_font_face_create_for_logfontw_hfont (LOGFONTW *logfont, + HFONT font); + +There is also a new "win32 printing" surface: + + cairo_surface_t * + cairo_win32_printing_surface_create (HDC hdc); + +This interface looks identical to the original +cairo_win32_surface_create, (both accept and HDC), but the behavior of +this new surface is very different. It should only be called with a +printing DC, and will result in all drawing commands being stored into +a meta-surface and emitted after each page is complete, with analysis +to do as minimal image-based fallbacks as necessary. The behavior and +implementation shares much with the PDF and PostScript backends. + +New cairo-ps API (EPS and PostScript level control) +--------------------------------------------------- +An often requested feature has been the ability to generate +Encapsulated PostScript (EPS) with cairo. We have that now with the +following very simple API. Just do cairo_ps_surface_create as usual +then call this function with a true value: + + void + cairo_ps_surface_set_eps (cairo_surface_t *surface, + cairo_bool_t eps); + +[NOTE: As always with snapshots, it's possible---though not very +likely---that the API could still be modified before a final +release. For example, this is the first public cairo function that +accepts a Boolean parameter. I'm generally opposed to Boolean +parameters, but this is probably the one case where I'm willing to +accept one, (namely a "set" function that accepts a single Boolean).] + +Also, it is now possible to control what PostScript level to target, +(either level 2 or level 3), with the following new API: + + typedef enum _cairo_ps_level { + CAIRO_PS_LEVEL_2, + CAIRO_PS_LEVEL_3 + } cairo_ps_level_t; + + void + cairo_ps_surface_restrict_to_level (cairo_surface_t *surface, + cairo_ps_level_t level); + + void + cairo_ps_get_levels (cairo_ps_level_t const **levels, + int *num_levels); + + const char * + cairo_ps_level_to_string (cairo_ps_level_t level); + +Improvement for cairo-quartz +---------------------------- +Brian Ewins had contributed several improvements to cairo-quartz. These +include an implementation of EXTEND_NONE for linear and radial +gradients, (so this extend mode will no longer trigger image fallbacks +for these gradients), as well as native surface-mask clipping, (only +on OS X 10.4+ where the CGContextClipToMask function is available). + +He also fixed a semantic mismatch between cairo and quartz for dashing +with an odd number of entries in the dash array. + +We're grateful for Brian since not many quartz-specific improvements +to cairo would be happening without him. + +Optimizations +------------- +Optimize SVG output for when the same path is both filled and stroked, +and avoid unnecessary identity matrix in SVG output. (Emmanuel Pacaud). + +Optimize PS output to take less space (Ken Herron). + +Make PS output more compliant with DSC recommendations (avoid initclip +and copy_page) (Adrian Johnson). + +Make PDF output more compact (Adrian Johnson). + +Release glyph surfaces after uploading them to the X server, (should +save some memory for many xlib-using cairo application). (Behdad +Esfahbod). + +Optimize cairo-win32 to use fewer GDI objects (Vladimir Vukicevic). + +win32-printing: Avoid falling back to images when alpha == 255 +everywhere. (Adrian Johnson). + +win32-printing: Avoid falling back for cairo_push_group and +cairo_surface_create_similar. (Adrian Johnson) + +Bug fixes +--------- +Avoid potential integer overflows when allocating large buffers +(Vladimir Vukicevic). + +Preparations to allow the 16.16 fixed-point format to change to +24.8 (Vladimir Vukicevic). + +Fix bugs for unsupported X server visuals (rgb565, rgb555, bgr888, and +abgr8888). (Carl Worth and Vladimir Vukicevic) + +Fix bugs in PDF gradients (Adrian Johnson). + +Fix cairo-xlib to build without requiring Xrender header +files (Behdad Esfahbod). + +Make cairo more resilient in the case of glyphs not being available in +the current font. (Behdad Esfahbod) + +Prevent crashes when both atsui and ft font backends are compiled in +(Brian Ewins). + +Make font subsetting code more robust against fonts that don't include +optional tables (Adrian Johnson). + +Fix CFF subsetting bug, (which manifested by generating PDF files that +Apple's Preview viewer could not read) (Adrian Johnson). + +Fixed error handling for quartz and ATSUI backends (Brian Ewins). + +Avoid rounding problems by pre-transforming to avoid integer-only +restrictions on transformation in GDI (Adrian Johnson). + +Fixed an obscure bug (#7245) computing extents for some stroked +paths (Carl Worth). + +Fix crashes due to extreme transformation of the pen, (seems to show +up in many .swf files for some reason) (Carl Worth). + +Release 1.4.10 (2007-06-27 Carl Worth ) +========================================================== +This is the fifth update in cairo's stable 1.4 series. It comes +roughly three weeks after the 1.4.8 release. The most significant +change in this release is a fix to avoid an X error in certain cases, +(that were causing OpenOffice.org to crash in Fedora). There is also a +semantic change to include child window contents when using an xlib +surface as a source, an optimization when drawing many rectangles, and +several minor fixes. + +Eliminate X errors that were killing OO.o (Chris Wilson) +-------------------------------------------------------- +Cairo is fixed to avoid the X errors propagated when cleaning up +Render Pictures after the application had already destroyed the +Drawable they reference. (It would be nice if the X server wouldn't +complain that some cleanup work is already done, but there you have +it.) This fixes the bug causing OpenOffice.org to crash as described +here: + + XError on right click menus in OOo. + https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=243811 + +Use IncludeInferiors when using xlib surface as a source (Ryan Lortie) +---------------------------------------------------------------------- +When an xlib surface is used as the source of a draw operation the +contents of child windows are now included in the source data. The +semantics of drawing to xlib surfaces are unchanged (ie: draws are +still clipped by child windows overlapping the destination window). + +Optimize drawing of many rectangles (Vladimir Vukicevic) +-------------------------------------------------------- +Avoid O(N*N) loop when filling many axis-aligned rectangles, (either +many rectangles as separate sub-paths or due to dashing). + +Miscellaneous fixes +------------------- +Fix cairo-perf on Solaris by linking to librt. (Behdad Esfahbod) + +Fix make check for systems that require executable files to have a +particular extension. (Behdad Esfahbod) + +Eliminate some warnings in cairo-quartz. (Brian Ewins) + +Fix build-breaking typo for cairo-directfb. (Chris Wilson) + +Release 1.4.8 (2007-06-07 Carl Worth ) +========================================================= +This is the fourth update in cairo's stable 1.4 series. It comes just +over five weeks after the 1.4.6 release. This release includes a +thread-safe surface-cache for solid patterns which significantly +improves text rendering with the xlib backend. Also, dozens of error +paths in cairo have been fixed thanks to extensive fault-injection +testing by Chris Wilson. + +Surface cache for solid patterns +-------------------------------- +Originally written by Jorn Baayen, the introduction of a small cache +for surfaces created for solid patterns improves performance +dramatically. For example, this reduces the volume of X requests +during text rendering to the same level as Xft. + +This cache first made its appearance in a 1.3.x snapshot, but was +removed before appearing in any previous major release due to +complications with multi-threaded programs. For example, programs like +evince that would carefully restrict usage of cairo-xlib to a single +thread were unpleasantly surprised to find that using cairo-image in a +separate thread could trigger X requests. + +Behdad Esfahbod designed a fix which was implemented by Chris +Wilson. Now, the necessary X requests are queued up until the next +time the application directly operates on an xlib surface. + +Improved error handling paths +------------------------------ +Chris Wilson continued the excellent work he started in cairo 1.4.4 to +make cairo much more robust against out-of-memory and other errors. He +applied his memory allocation fault injection cairo's main test suite, +(previously he had applied it to cairo's performance suite). + +Chris's testing found dozens of bugs which he fixed. Many of these +bugs had perhaps never been hit by any users. But at least one was +hit by the gnome-about program which resulted in dozens of duplicated +bug reports against that program: + + https://bugzilla.gnome.org/show_bug.cgi?id=431990 + +We were very pleasantly surprised to see this bug get fixed as a +side-effect of Chris's work. Well done, Chris! + +Other fixes +----------- +Cleanup of mutex declarations (Behdad Esfahbod) + +Remove unnecessary clip region from SVG output (Emmanuel Pacaud) + +Remove Xsun from the buggy_repeat blacklist (Elaine Xiong) + +ATSUI: Fix glyph measurement: faster and more correct (Brian Ewins) + +Quartz: fixed 'extend' behaviour for patterns, improved pattern performance, +and a few smaller correctness fixes. (Brian Ewins, Vladimir Vukicevic) + +Release 1.4.6 (2007-05-01 Carl Worth ) +========================================================= +This is the third update in cairo's stable 1.4 series. It comes a +little less than three weeks since the 1.4.4 release. This release +fixes the broken mutex initialization that made cairo 1.4.4 unusable +on win32, OS/2, and BeOS systems. This release also adds significant +improvements to cairo's PDF backend, (native gradients!), and a couple +of performance optimizations, (one of which is very significant for +users of the xlib backend). See below for more details. + +Repaired mutex initialization +----------------------------- +We apologize that cairo 1.4.4 did little more than crash on many +platforms which are less-frequently used by the most regular cairo +maintainers, (win32, OS/2, and BeOS). The mutex initialization +problems that caused those crashes should be fixed now. And to avoid +similar problems in the future, we've now started posting pre-release +snapshots to get better testing, (subscribe to cairo@cairographics.org +if you're interested in getting notified of those and testing them). + +PDF Improvements +---------------- +Thanks to Adrian Johnson, (cairo PDF hacker extraordinaire), we have +several improvements to cairo's PDF backend to announce: + +Native gradients: + + As of cairo 1.4.6, cairo will now generate native PDF gradients in + many cases, (previously, the presence of a gradient on any page + would force rasterized output for that page). Currently, only + gradients with extend types of PAD (the default) or NONE will + generate native PDF gradients---others will still trigger + rasterization, (but look for support for other extend modes in a + future release). Many thanks to Miklós Erdélyi as well, who did the + initial work for this support. + +Better compatibility with PDF viewers: + + The PDF output from cairo should now be displayed correctly by a + wider range of PDF viewers. Adrian tested cairo's PDF output against + many PDF viewers, identified a common bug in many of those viewers + (ignoring the CTM matrix in some cases), and modified cairo's output + to avoid triggering that bugs (pre-transforming coordinates and + using an identity matrix). + +Better OpenType/CFF subsetting: + + Cairo will now embed CFF and TrueType fonts as CID fonts. + +Performance optimizations +------------------------- +Faster cairo_paint_with_alpha: + + The cairo_paint_with_alpha call is used to apply a uniform alpha + mask to a pattern. For example, it can be used to gradually fade an + image out or in. Jeff Muizelaar fixed some missing/broken + optimizations within the implementation of this function resulting + in cairo_paint_with_alpha being up to 4 times faster when using + cairo's image backend. + +Optimize rendering of "off-screen" geometry: + + Something that applications often do is to ask cairo to render + things that are either partially or wholly outside the current clip + region. Since 1.4.0 the image backend has been fixed to not waste + too much time in this case. But other backends have still been + suffering. + + In particular, the xlib backend has often performed quite badly in + this situation. This is due to a bug in the implementation of + trapezoid rasterization in many X servers. + + Now, in cairo 1.4.6 there is a higher-level fix for this + situation. Cairo now eliminates or clips trapezoids that are wholly + or partially outside the clip region before handing the trapezoids + to the backend. This means that the X server's performance bug is + avoided in almost all cases. + + The net result is that doing an extreme zoom-in of vector-based + objects drawn with cairo might have previously brought the X server + to its knees as it allocated buffers large enough to fit all of the + geometry, (whether visible or not). But now the memory usage should + be bounded and performance should be dramatically better. + +Miscellaneous +------------- +Behdad contributed an impressively long series of changes that +organizes cairo's internals in several ways that will be very +beneficial to cairo developers. Thanks, Behdad! + +Behdad has also provided a utility for generating malloc statistics, +(which was used during the great malloc purges of 1.4.2 and +1.4.4). This utility isn't specific to cairo so may be of benefit to +others. It is found in cairo/util/malloc-stats.c and here are Behdad's +notes on using it: + + To build, do: + + make malloc-stats.so + + inside util/, and to use, run: + + LD_PRELOAD=malloc-stats.so some-program + + For binaries managed by libtool, eg, cairo-perf, do: + + ../libtool --mode=execute /bin/true ./cairo-perf + LD_PRELOAD="../util/malloc-stats.so" .libs/lt-cairo-perf + +Finally, the cairo-perf-diff-files utility was enhanced to allow for +generating performance reports from several runs of the same backend +while some system variables were changed. For example, this is now +being used to allow cairo-perf to measure the performance of various +different acceleration architectures and configuration options of the +X.org X server. + +Release 1.4.4 (2007-04-13 Carl Worth ) +========================================================= +This is the second update release in cairo's stable 1.4 series. It +comes just less than a month after 1.4.2. The changes since 1.4.2 +consist primarily of bug fixes, but also include at least one +optimization. See below for details. + +Of all the work that went into the 1.4.4 release + +There have been lots of individuals doing lots of great work on cairo, +but two efforts during the 1.4.4 series deserve particular mention: + +Internal cleanup of error handling, (Chris Wilson) +-------------------------------------------------- +Chris contributed a tremendous series of patches (74 patches!) to +improve cairo's handling of out-of-memory and other errors. He began +by adding gcc's warn_unused_attribute to as many functions as +possible, and then launched into the ambitious efforts of adding +correct code to quiet the dozens of resulting warnings. + +Chris also wrote a custom valgrind skin to systematically inject +malloc failures into cairo, and did all the work necessary to verify +that cairo's performance test suite runs to completion without +crashing. + +The end result is a much more robust implementation. Previously, many +error conditions would have gone unnoticed and would have led to +assertion failures, segmentation faults, or other harder-to-diagnose +problems. Now, more than ever, cairo should cleanly let the user know +of problems through cairo_status and other similar status +functions. Well done, Chris! + +More malloc reduction, (Mathias Hasselmann) +------------------------------------------- +After 1.4.0, Behdad launched an effort to chase down excessive calls +to malloc within the implementation of cairo. He fixed a lot of +malloc-happy objects for 1.4.2, but one of the worst offenders, +(pixman regions), was left around. Mathias contributed an excellent +series of 15 patches to finish off this effort. + +The end result is a cairo that calls malloc much less often than it +did before. Compared to 1.4.2, 55% of the calls to malloc have been +eliminate, (and 60% have been eliminated compared to 1.4.0). Well +done, Mathias! + +Other improvements since 1.4.2 +------------------------------ +• Centralize mutex declarations (will reduce future build breaks), + (Mathias Hasselmann) + +• Reduce malloc by caching recently freed pattern objects (Chris + Wilson) + +• Fix some broken composite operations (David Reveman) + https://bugs.freedesktop.org/show_bug.cgi?id=5777 + +Backend-specific fixes +---------------------- +PDF: + • Use TJ operator for more compact representation of glyphs (Adrian + Johnson) + + • Fix glyph positioning bug when glyphs are not horizontal + https://lists.freedesktop.org/archives/cairo/2007-April/010337.html + +win32: + • Fix crash when rendering with bitmap fonts (Carl Worth) + https://bugzilla.mozilla.org/show_bug.cgi?id=376498 + +xlib: + • Turn metrics-hinting on by default (Behdad Esfahbod) + + • Fix edge-effect problem with transformed images drawn to xlib + (Behdad Esfahbod) + https://bugs.freedesktop.org/show_bug.cgi?id=10508 + + • Avoid dereferencing a NULL screen. (Chris Wilson) + https://bugs.freedesktop.org/show_bug.cgi?id=10517 + +Quartz/ATSUI: + • Fix scaling of glyph surfaces + (Brian Ewins) + https://bugs.freedesktop.org/show_bug.cgi?id=9568 + + • Fix compilation failure when both xlib and quartz enabled + (Brian Ewins) + + • Fix rounding bug leading to incorrectly positioned glyphs + (Robert O'Callahan) + https://bugs.freedesktop.org/show_bug.cgi?id=10531 + +Release 1.4.2 (2007-03-19 Carl Worth ) +========================================================= +This is the first update release in cairo's stable 1.4 series. It +comes just less than 2 weeks after 1.4.0. We hadn't anticipated an +update this early, but we've managed to collect some important fixes +that we wanted to get out to cairo users as soon as possible, (6 fixes +for crashes, 1 case where graphical elements would not be drawn at +all, a handful of backend-specific bugs, and several important build +fixes). + +There's almost nothing but bug fixes in this release, (see below one +optimization that Behdad did sneak in), so we recommend that everyone +upgrade to this release when possible. + +Thanks to the many people that worked to fix these bugs, and those +that did the work to report them and to test the fixes, (wherever +possible both names are credited below). + +Critical fixes +-------------- +• Fix a crash due to a LOCK vs. UNLOCK typo (M. Drochner fixing Carl + Worth's embarrassing typo). + + https://bugs.freedesktop.org/show_bug.cgi?id=10235 + +• Fix potential buffer overflow, which on some systems with a checking + variant of snprintf would lead to a crash (Adrian Johnson, Stanislav + Brabec, and sangu). + + https://bugs.freedesktop.org/show_bug.cgi?id=10267 + https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=232576 + +• Fix a crash in cairo_stroke_extents or cairo_in_stroke when line + width is 0.0. (Carl Worth and Sebastien Bacher) + + https://bugs.freedesktop.org/show_bug.cgi?id=10231 + +• Fix a crash on certain combinations of X server/video drivers (Carl + Worth and Tomas Carnecky). + + https://bugs.freedesktop.org/show_bug.cgi?id=10250 + +• Fix a crash due to mishandling of invalid user input (Carl Worth and + Alexander Darovsky). + + https://bugs.freedesktop.org/show_bug.cgi?id=9844 + +• xlib: Cleanup server-side glyph caches on XCloseDisplay. This + eliminated a crash detected by the perf suite, (and that + applications could have run into as well). (Chris Wilson) + +Other bug fixes +--------------- +• Fix for some geometry which simply disappeared under some + transformations---a stroked line with an extreme skew in X, for + example (Carl Worth and Jonathan Watt). + + https://bugzilla.mozilla.org/show_bug.cgi?id=373632 + +• SVG: Fix radial gradients for CAIRO_EXTEND_REFLECT and when r0 > r1 + (Emmanuel Pacaud). + +• PDF: Set page group color space to DeviceRGB. + + This fixes incorrect (muddy) transparent colors when rendering cairo + PDF output in some viewers. (Adrian Johnson, Adam Goode, and + MenTaLguY). + + https://lists.freedesktop.org/archives/cairo/2006-November/008551.html + +• win32: Return correct metrics when hinting is off, and fix font + descent computation (Behdad Esfahbod). + +• quartz: Fix glyph interfaces to correctly return user-space rather + than device-space coordinates (Brian Ewins). + + https://bugs.freedesktop.org/show_bug.cgi?id=9568 + +• xcb: Fix parameter-order confusion with xcb_create_pixmap, which now + makes all tests that pass with xlib now pass with xcb (Carl Worth, + Jamey Sharp). + +• Fix some memory leaks in the perf suite (Chris Wilson). + +• Fix perf suite to consider changes in pixman/src (Mathias + Hasselmann). + +Build fixes +----------- +• Don't include pre-generated cairo-features.h file. This was causing + build failures when building with the directfb backend enabled + (Behdad Esfahbod). + + https://bugs.freedesktop.org/show_bug.cgi?id=10189 + +• Eliminate use of maintainer mode from cairo's automake/configure + script. This means that updates to files such as Makefile.am will + take effect, (by rerunning automake and friends as necessary) when + invoking make rather than being silently ignored. (Behdad Esfahbod) + +• Don't compile cairo-deflate-stream.c, which depends on zlib, unless + building the pdf backend which requires it. (Carl Worth, Tor + Lillqvist) + + https://bugs.freedesktop.org/show_bug.cgi?id=10202 + +• Don't make the ps backend link against zlib anymore, since it + doesn't require it (Carl Worth). + +• Use "find !" rather than "find -not" for better portability (Thomas + Klausner). + + https://bugs.freedesktop.org/show_bug.cgi?id=10226 + +• Don't use unsupported visibility attribute "hidden" on Solaris + (Gilles Dauphin, Thomas Klausner). + + https://bugs.freedesktop.org/show_bug.cgi?id=10227 + +Optimization +------------ +• It was Behdad that suggested we focus strictly on bug fixes now that + we shipped so many performance improvements in 1.4.0, but it was + also Behdad that got distracted by the chance to remove a lot of + mallocs from cairo. Paths, gstates, trapezoids, splines, polygons, + and gradient color stops will now use small, stack-allocated buffers + in the most common cases rather than calling malloc as + often. (Behdad Esfahbod). And look for more from Mathias Hasselmann + soon. + +Release 1.4.0 (2007-03-06 Carl Worth ) +========================================================= +The many people[*] who have been working hard on cairo are very +pleased to announce the long-awaited release of cairo 1.4. This +release comes 4 months after the last stable update release (1.2.6) +and 9 months since the initial release of 1.2.0. + +The release notes below are intended to capture the highlights of the +changes that have occurred from the 1.2 series to the new 1.4.0 +release. + +Performance improvements +------------------------ +Within the cairo project, the last 6 months or so has seen an intense +effort focusing on the performance of cairo itself. That effort has +paid off considerably, as can be seen in the following highlights of +some of the performance differences from cairo 1.2.6 to cairo 1.4.0. + +(Note: The performance results reported here were measured on an x86 +laptop. Many of the improvements in 1.4---particular those involving +text rendering---are even more dramatic on embedded platforms without +hardware floating-point units. Such devices played an important part +of many of the optimizations that found their way into cairo over the +last few months.) + +• Dramatic improvement when drawing objects that are mostly off-screen + with the image backend (with the xlib backend this case is still + slow due to an X server bug): + + image-rgba long-lines-uncropped-100 479.64 -> 4.98: 96.24x speedup + ███████████████████████████████████████████████▋ + +• Dramatic improvement when copying a small fraction of an image + surface to an xlib surface: + + xlib-rgba subimage_copy-512 3.93 -> 0.07: 54.52x speedup + ██████████████████████████▊ + +• Dramatic improvement to tessellation speed for complex objects: + + image-rgb tessellate-256-100 874.16 -> 34.79: 25.13x speedup + ████████████■+ xlib-rgba zrusin_another_fill-415 148.40 -> 13.85: 10.72x speedup + ████▉ + xlib-rgb world_map-800 680.20 -> 345.54: 1.97x speedup + ▌ + +• Dramatic improvement to the speed of stroking rectilinear shapes, + (such as the outline of a rectangle or "box"): + + image-rgb box-outline-stroke-100 0.18 -> 0.01: 24.22x speedup + ███████████▋ + xlib-rgb box-outline-stroke-100 0.46 -> 0.06: 8.05x speedup + ███▌ + + +• Dramatic improvements to text rendering speeds: + + xlib-rgba text_image_rgba_over-256 63.12 -> 9.61: 6.57x speedup + ██▊ + +• 3x improvements to floating-point to fixed-point conversion speeds: + + image-rgba pattern_create_radial-16 9.29 -> 3.44: 2.70x speedup + ▉ + +• 2x improvements to linear gradient computation: + + image-rgb paint_linear_rgb_source-512 26.22 -> 11.61: 2.26x speedup + ▋ + +• 2x improvement to a case common in PDF rendering: + + image-rgb unaligned_clip-100 0.10 -> 0.06: 1.81x speedup + ■+ +• 1.3x improvement to rectangle filling speed (note: this improvement + is new since 1.3.16---previously this test case was a 1.3x slowdown + compared to 1.2.6): + + image-rgba rectangles-512 6.19 -> 4.37: 1.42x speedup + ▎ + xlib-rgba rectangles-512 7.48 -> 5.58: 1.34x speedup + ■+ +NOTE: In spite of our best efforts, there are some measurable +performance regressions in 1.4 compared to 1.2. It appears that the +primary problem is the increased overhead of the new tessellator when +drawing many, very simple shapes. The following test cases capture +some of that slowdown: + + image-rgba mosaic_tessellate_lines-800 11.03 -> 14.29: 1.30x slowdown + ■+ image-rgba box-outline-fill-100 0.01 -> 0.01: 1.26x slowdown + ■+ image-rgba fill_solid_rgb_over-64 0.20 -> 0.22: 1.12x slowdown + + image-rgba fill_image_rgba_over-64 0.23 -> 0.25: 1.10x slowdown + + xlib-rgb paint_image_rgba_source-256 3.24 -> 3.47: 1.07x slowdown + +We did put some special effort into eliminating this slowdown for the +very common case of drawing axis-aligned rectangles with an identity +matrix (see the box-outline-stroke and rectangles speedup numbers +above). Eliminating the rest of this slowdown will be a worthwhile +project going forward. + +Also note that the "box-outline-fill" case is a slowdown while +"box-outline-stroke" is a (huge) speedup. These two test cases +resulted from the fact that some GTK+ theme authors were filling +between two rectangles to avoid slow performance from the more natural +means of achieving the same shape by stroking a single rectangle. With +1.4 that workaround should definitely be eliminated as it will now +cause things to perform more slowly. + +Greatly improved PDF output +--------------------------- +We are very happy to be able to announce that cairo-generated PDF +output will now have text that can be selected, cut-and-pasted, and +searched with most capable PDF viewer applications. This is something +that was not ever possible with cairo 1.2. + +Also, the PDF output now has much more compact encoding of text than +before. Cairo is now much more careful to not embed multiple copies of +the same font at different sizes. It also compresses text and font +streams within the PDF output. + +API additions +------------- +There are several new functions available in 1.4 that were not +available in 1.2. Curiously, almost all of the new functions simply +allow the user to query state that has been set in cairo (many new +"get" functions) rather than providing any fundamentally new +operations. The new functionality is: + +• Getting information about the current clip region + + cairo_clip_extents + cairo_copy_clip_rectangle_list + cairo_rectangle_list_destroy + +• Getting information about the current dash setting + + cairo_get_dash_count + cairo_get_dash + +• Getting information from a pattern + + cairo_pattern_get_rgba + cairo_pattern_get_surface + cairo_pattern_get_color_stop_rgba + cairo_pattern_get_color_stop_count + cairo_pattern_get_linear_points + cairo_pattern_get_radial_circles + +• Getting the current scaled font + + cairo_get_scaled_font + +• Getting reference counts + + cairo_get_reference_count + cairo_surface_get_reference_count + cairo_pattern_get_reference_count + cairo_font_face_get_reference_count + cairo_scaled_font_get_reference_count + +• Setting/getting user data on objects + + cairo_set_user_data + cairo_get_user_data + cairo_pattern_set_user_data + cairo_pattern_get_user_data + cairo_scaled_font_set_user_data + cairo_scaled_font_get_user_data + +• New cairo-win32 functions: + + cairo_win32_surface_create_with_ddb + cairo_win32_surface_get_image + cairo_win32_scaled_font_get_logical_to_device + cairo_win32_scaled_font_get_device_to_logical + +API deprecation +--------------- +The CAIRO_FORMAT_RGB16_565 enum value has been deprecated. It never +worked as a format value for cairo_image_surface_create, and it wasn't +necessary for supporting 16-bit 565 X server visuals. + +A sampling of bug fixes in cairo 1.4 +------------------------------------ + • Fixed radial gradients + • Fixed dashing (degenerate and "leaky" cases) + • Fixed transformed images in PDF/PS output (eliminate bogus repeating) + • Eliminate errors from CAIRO_EXTEND_REFLECT and CAIRO_EXTEND_PAD + • cairo_show_page no longer needed for single-page output + • SVG: Fix bug preventing text from appearing in many viewers + • cairo-ft: Return correct metrics when hinting is off + • Eliminate crash in cairo_create_similar if nil surface is returned + • Eliminate crash after INVALID_RESTORE error + • Fix many bugs related to multi-threaded use and locking + • Fix for glyph spacing 32 times larger than desired (cairo-win32) + • Fixed several problems in cairo-atsui (assertion failures) + • Fix PDF output to avoid problems when printing from Acrobat Reader + • Fix segfault on Mac OS X (measuring a zero-length string) + • Fix text extents to not include the size of non-inked characters + • Fix for glyph cache race condition in glitz backend (Jinghua Luo) + • Fix make check to work on OPD platforms (IA64 or PPC64) + • Fix compilation problems of cairo "wideint" code on some platforms + • Many, many others... + +Experimental backends (quartz, XCB, OS/2, BeOS, directfb) +--------------------------------------------------------- +None of cairo's experimental backends are graduating to "supported" +status with 1.4.0, but two of them in particular (quartz and xcb), are +very close. + +The quartz baceknd has been entirely rewritten and is now much more +efficient. The XCB backend has been updated to track the latest XCB +API (which recently had a 1.0 release). + +We hope to see these backends become supported in a future release, +(once they are passing all the tests in cairo's test suite). + +The experimental OS/2 backend is new in cairo 1.4 compared to cairo +1.2. + +Documentation improvements +-------------------------- +We have added documentation for several functions and types that +were previously undocumented, and improved documentation on other +ones. As of this release, there remain only two undocumented +symbols: cairo_filter_t and cairo_operator_t. + +[*]Thanks to everyone +--------------------- +I've accounted for 41 distinct people with attributed code added to +cairo between 1.2.6 and 1.4.0, (their names are below). That's an +impressive number, but there are certainly dozens more that +contributed with testing, suggestions, clarifying questions, and +encouragement. I'm grateful for the friendships that have developed as +we have worked on cairo together. Thanks to everyone for making this +all so much fun! + +Adrian Johnson, Alfred Peng, Alp Toker, Behdad Esfahbod, +Benjamin Otte, Brian Ewins, Carl Worth, Christian Biesinger, +Christopher (Monty) Montgomery, Daniel Amelang, Dan Williams, +Dave Yeo, David Turner, Emmanuel Pacaud, Eugeniy Meshcheryakov, +Frederic Crozat, Hans Breuer, Ian Osgood, Jamey Sharp, Jeff Muizelaar, +Jeff Smith, Jinghua Luo, Jonathan Watt, Joonas Pihlaja, Jorn Baayen, +Kalle Vahlman, Kjartan Maraas, Kristian Høgsberg, M Joonas Pihlaja, +Mathias Hasselmann, Mathieu Lacage, Michael Emmel, Nicholas Miell, +Pavel Roskin, Peter Weilbacher, Robert O'Callahan, +Soren Sandmann Pedersen, Stuart Parmenter, T Rowley, +Vladimir Vukicevic + +Snapshot 1.3.16 (2007-03-02 Carl Worth ) +=========================================================== +New API functions +----------------- +A few new public functions have been added to the cairo API since the +1.3.14 snapshot. These include a function to query the current scaled +font: + + cairo_get_scaled_font + +New functions to query the reference count of all cairo objects: + + cairo_get_reference_count + + cairo_surface_get_reference_count + cairo_pattern_get_reference_count + + cairo_font_face_get_reference_count + cairo_scaled_font_get_reference_count + +And new functions to allow the use of user_data with any cairo object, +(previously these were only available on cairo_surface_t and +cairo_font_face_t objects): + + cairo_set_user_data + cairo_get_user_data + + cairo_pattern_set_user_data + cairo_pattern_get_user_data + + cairo_scaled_font_set_user_data + cairo_scaled_font_get_user_data + +Usability improvement for PDF/PS/SVG generation +----------------------------------------------- +In previous versions of cairo, generating single-page output with the +cairo-pdf, cairo-ps, or cairo-svg backends required a final call to +cairo_show_page. This was often quite confusing as people would port +functional code from a non-paginated backend and be totally mystified +as to why the output was blank until they learned to add this call. + +Now that call to cairo_show_page is optional, (it will be generated +implicitly if the user does not call it). So cairo_show_page is only +needed to explicitly separate multiple pages. + +Greatly improved PDF output +--------------------------- +We are very happy to be able to announce that cairo-generated PDF +output will now have text that can be selected, cut-and-paste, and +searched with most capable PDF viewer applications. This is something +that was not ever possible with cairo 1.2. + +Also, the PDF output now has much more compact encoding of text than +before. Cairo is now much more careful to not embed multiple copies of +the same font at different sizes. It also compresses text and font +streams within the PDF output. + +Major bug fixes +--------------- + • Fixed radial gradients + + The rendering of radial gradients has been greatly improved. In + the cairo 1.2 series, there was a serious regression affecting + radial gradients---results would be very incorrect unless one of + the gradient circles had a radius of 0.0 and a center point within + the other circle. These bugs have now been fixed. + + • Fixed dashing + + Several fixes have been made to the implementation of dashed + stroking. Previously, some dashed, stroked rectangles would + mis-render and fill half of the rectangle with a large triangular + shape. This bug has now been fixed. + + • Fixed transformed images in PDF/PS output + + In previous versions of cairo, painting with an image-based source + surface pattern to the PDF or PS backends would cause many kinds + of incorrect results. One of the most common problems was that an + image would be repeated many times even when the user had + explicitly requested no repetition with CAIRO_EXTEND_NONE. These + bugs have now been fixed. + + • Eliminate errors from CAIRO_EXTEND_REFLECT and CAIRO_EXTEND_PAD + + In the 1.2 version of cairo any use of CAIRO_EXTEND_REFLECT or + CAIRO_EXTEND_PAD with a surface-based pattern resulted in an + error, (cairo would stop rendering). This bug has now been + fixed. + + Now, CAIRO_EXTEND_REFLECT should work properly with surface + patterns. + + CAIRO_EXTEND_PAD is still not working correctly, but it will now + simply behave as CAIRO_EXTEND_NONE rather than triggering the + error. + +New rewrite of quartz backend (still experimental) +-------------------------------------------------- +Cairo's quartz backend has been entirely rewritten and is now much +more efficient. This backend is still marked as experimental, not +supported, but it is now much closer to becoming an officially +supported backend. (For people that used the experimental nquartz +backend in previous snapshots, that implementation has now been +renamed from "nquartz" to "quartz" and has replaced the old quartz +backend.) + +Documentation improvements +-------------------------- +We have added documentation for several functions and types that +were previously undocumented, and improved documentation on other +ones. As of this release, there remain only two undocumented +symbols: cairo_filter_t and cairo_operator_t. + +Other bug fixes +--------------- + • cairo-svg: Fix bug that was preventing text from appearing in many + viewers + + • cairo-ft: Return correct metrics when hinting is off + + • Cairo 1.3.14 deadlocks in cairo_scaled_font_glyph_extents or + _cairo_ft_unscaled_font_lock_face + + https://bugs.freedesktop.org/show_bug.cgi?id=10035 + + • cairo crashes in cairo_create_similar if nil surface returned by + other->backend->create_similar + + https://bugs.freedesktop.org/show_bug.cgi?id=9844 + + • evolution crash in _cairo_gstate_backend_to_user() + https://bugs.freedesktop.org/show_bug.cgi?id=9906 + + • Fix memory leak in rectilinear stroking code + +Things not in this release +-------------------------- + • Solid-surface-pattern cache: This patch had been applied during + the 1.3.x series, but it was reverted due to some inter-thread + problems it caused. The patch is interesting since it made a big + benefit for text rendering performance---so we'll work to bring a + corrected version of this patch back as soon as possible. + +Snapshot 1.3.14 (2006-02-13 Carl Worth ) +=========================================================== +This is the seventh development snapshot in the 1.3 series, (and there +likely won't be many more before the 1.4.0 release). It comes just +over 3 weeks after the 1.3.12 snapshot. + +Since we're so close to the 1.4.0 release, there are not a lot of new +features nor even a lot of new performance improvements in this +snapshot. Instead, there are a great number of bug fixes. Some are +long-standing bugs that we're glad to say goodbye to, and several are +fixes for regressions that were introduced as part of the optimization +efforts during the 1.3.x series. + +PDF text selection fixed +------------------------ +The inability to correctly select text in cairo-generated PDF has been +a defect ever since the initial support for the PDF backend in the +cairo 1.2.0 release. With the 1.3.14 snapshot, in most situations, and +with most PDF viewer applications, the PDF generated by cairo will +allow text to be correctly selected for copy-and-paste, (as well as +searching). + +We're very excited about this new functionality, (and very grateful to +Adrian Johnson, Behdad Esfahbod, and others that have put a lot of +work into this lately). Please test this new ability and give feedback +on the cairo@cairographics.org list. + +Many thread-safety issues fixed +------------------------------- +We've discovered that no release of cairo has ever provided safe text +rendering from a multi-threaded application. With the 1.3.14 snapshot +a huge number of the bugs in this area have been fixed, and multiple +application dvelopers have now reported success at writing +multi-threaded applications with cairo. + +Other fixes +----------- +Fixed a bug that was causing glyph spacing to be 32 times larger than +desired when using cairo-win32. + +Fixed a regression in the rendering of linear gradients that had been +present since the 1.3.8 snapshot. + +Fixed several problems in cairo-atsui that were leading to assertion +failures when rendering text. + +Fix corrupted results when rendering a transformed source image +surface to an xlib surface. This was a regression that had been +present since the 1.3.2 snapshot. + +Fixed PDF output to prevent problems printing from some versions of +Acrobat Reader, (a single glyph was being substituted for every +glyph). + +And many other fixes as well, (see the logs for details). + +Snapshot 1.3.12 (2007-01-20 Carl Worth ) +=========================================================== +The relentless march toward the cairo 1.4 release continues, (even if +slightly late out of the starting blocks in 2007). This is the sixth +development snapshot in the 1.3 series. It comes 4 weeks after the +1.3.10 snapshot. + +Performance +----------- +As usual, this snapshot has some fun performance improvements to show +off: + +image-rgba long-lines-uncropped-100 470.08 -> 4.95: 94.91x speedup +███████████████████████████████████████████████ +image-rgb long-lines-uncropped-100 461.60 -> 4.96: 93.02x speedup +██████████████████████████████████████████████ + +This 100x improvement, (and yes, that's 100x, not 100%), in the image +backend occurs when drawing large shapes where only a fraction of the +shape actually appears in the final result, (the rest being outside +the bounds of the destination surface). Many applications should see +speedups here, and the actual amount of speedup depends on the ratio +of non-visible to visible portions of geometry. + +[Note: There remains a similar performance bug when drawing mostly +non-visible objects with the xlib backend. This is due to a similar +bug in the X server itself, but we hope a future cairo snapshot will +workaround that bug to get a similar speedup with the xlib backend.] + +image-rgba unaligned_clip-100 0.09 -> 0.06: 1.67x speedup +■+image-rgb unaligned_clip-100 0.09 -> 0.06: 1.66x speedup +■+ +This speedup is due to further MMX optimization by Soeren Sandmann for +a case commonly hit when rendering PDF files, (and thanks to Jeff +Muizelaar for writing code to extract the test case for us). + +There's another MMX optimization in this snapshot (without a fancy +speedup chart) by Dan Williams which improves compositing performance +specifically for the OLPC machine. + +Thanks to Adrian Johnson, cairo's PDF output is now much more +efficient in the way it encodes text output. By reducing redundant +information and adding compression to text output streams, Adrian +achieved a ~25x improvement in the efficiency of encoding text in PDF +files, (was ~45 bytes per glyph and is now ~1.6 bytes per glyph). + +Bug fixes +--------- +In addition to those performance improvements, this snapshot includes +several bug fixes: + + * A huge number of bug fixes for cairo-atsui text rendering, (for mac + OS X). These bugs affect font selection, glyph positioning, glyph + rendering, etc. One noteworthy bug fixes is that + cairo_select_font_face will no longer arbitrarily select bold nor + italic when not requested, (at least not when using a standard CSS2 + font family name such as "serif", "sans-serif", "monospace", etc.). + All these fixes are thanks to Brian Ewins who continues to do a + great job as the new cairo-atsui maintainer. + + * Fix PDF output so that images that are scaled down no longer + mysteriously repeat (Carl Worth). + + * Fix segfault on Mac OS X dues to attempt to measure extents of a + zero-length string (Behdad Esfahbod). + + * Fix text extents to not include the size of initial/trailing + non-inked characters (Behdad Esfahbod). + +API tweaks +---------- +Three functions have had API changes to improve consistency. Note that +the API functions being changed here are all functions that were +introduced as new functions during these 1.3.x snapshots. As always, +there will not be any API changes to functions included in a major +release (1.2.x, 1.4.x, etc.) of cairo. + +The changes are as follows: + + * Rename of cairo_copy_clip_rectangles to cairo_copy_clip_rectangle_list. + + * Change cairo_get_dash_count to return an int rather than accepting a + pointer to an int for the return value. + + * Change cairo_get_dash to have a void return type rather than + returning cairo_status_t. + +It's possible there will be one more round of changes to these +functions, (and perhaps cairo_get_color_stop as well), as we seek to +establish a unifying convention for returning lists of values. + +Snapshot 1.3.10 (2006-12-23 Carl Worth ) +=========================================================== +Santa Claus is coming just a little bit early this year, and he's +bringing a shiny new cairo snapshot for all the good little boys and +girls to play with. + +This is the fifth development snapshot in the 1.3 series. It comes 9 +days after the 1.3.8 snapshot, and still well within our goal of +having a new snapshot every week, (though don't expect one next +week---we'll all be too stuffed with sugar plums). + +Speaking of sugar plums, there's a sweet treat waiting in this cairo +snapshot---greatly improved performance for stroking rectilinear +shapes, like the ever common rectangle: + +image-rgb box-outline-stroke-100 0.18 -> 0.01: 25.58x speedup +████████████████████████▋ +image-rgba box-outline-stroke-100 0.18 -> 0.01: 25.57x speedup +████████████████████████▋ +xlib-rgb box-outline-stroke-100 0.49 -> 0.06: 8.67x speedup +███████▋ +xlib-rgba box-outline-stroke-100 0.22 -> 0.04: 5.39x speedup +████■+ +In past releases of cairo, some people had noticed that using +cairo_stroke to draw rectilinear shapes could be awfully slow. Many +people had worked around this by using cairo_fill with a more complex +path and gotten a 5-15x performance benefit from that. + +If you're one of those people, please rip that workaround out, as now +the more natural use of cairo_stroke should be 1.2-2x faster than the +unnatural use of cairo_fill. + +And if you hadn't ever implemented that workaround, then you just +might get to see your stroked rectangles now get drawn 5-25x faster. + +Beyond that performance fix, there are a handful of bug fixes in this +snapshot: + + * Fix for glyph cache race condition in glitz backend (Jinghua Luo) + + * Many fixes for ATSUI text rendering (Brian Ewins) + + * Un-break recent optimization-triggered regression in rendering text + with a translation in the font matrix (Behdad Esfahbod) + + * Fix make check to work on OPD platforms (IA64 or PPC64) + (Frederic Crozat) + + * Fix a couple of character spacing issues on Windows + (Jonathan Watt) + +Have fun with that, everybody, and we'll be back for more in the new +year, (with a plan to add the last of our performance improvements in +this round, fix a few bad, lingering bugs, and then finish off a nice, +stable 1.4 release before the end of January). + +-Carl + +Snapshot 1.3.8 (2006-12-14 Carl Worth ) +========================================================== +This is the fourth development snapshot in the 1.3 series. It comes +just slightly more than one week after the 1.3.6 snapshot. + +After the bug fixes in 1.3.6, we're back to our original program of +weekly snapshots, each one faster than the one from the week +before. Cairo 1.3.8 brings a 2x improvement in the speed of rendering +linear gradients (thanks to David Turner), and a significant reduction +in X traffic when rendering text (thanks to Xan Lopez and Behdad +Esfahbod), making cairo behave very much like Xft does. + +A few other things in the 1.3.8 snapshot worth noting include a more +forgiving image comparator in the test suite, (using the "perceptual +diff" metric and GPL implementation by Hector Yee[*]), a bug fix for +broken linking on x86_64 (thanks to M Joonas Pihlaja) and an even +better implementation of _cairo_lround, (not faster, but supporting a +more complete input range), from Daniel Amelang. + +[*] http://pdiff.sourceforge.net/ + +Snapshot 1.3.6 (2006-12-06 Carl Worth ) +========================================================== +This is the third development snapshot in the 1.3 series. It comes two +weeks after the 1.3.4 snapshot. + +We don't have fancy performance charts this week as the primary +changes in this snapshot are bug fixes. The performance work continues +and the next snapshot (planned for one week from today) should include +several improvements. The bug fixes in this snapshot include: + + * Fix undesirable rounding in glyph positioning (Dan Amelang) + + This bug was noticed by several users, most commonly by seeing + improper text spacing or scrambled glyphs as drawn by nautilus. For + example: + + Update to cairo-1.3.4 worsen font rendering + https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=217819 + + * Fix reduced range of valid input coordinates to tessellator + (M Joonas Pihlaja) + + This bug was causing lots of assertion failures in mozilla as + mentioned here: + + CAIRO_BO_GUARD_BITS and coordinate space? + https://lists.freedesktop.org/archives/cairo/2006-December/008743.html + + * Fix several regressions in new tessellator (M Joonas Pihlaja) + + Joonas just had a good eye for detail here. I don't think any + external cairo users had noticed any of these bugs yet. + + * Fix compilation problems of cairo "wideint" code on some platforms + (Mathieu Lacage) + + * Fix failed configure due to broken grep (Dan Amelang) + + This bug was reported here: + + AX_C_FLOAT_WORDS_BIGENDIAN doesn't work because grep doesn't + work with binary file + https://bugs.freedesktop.org/show_bug.cgi?id=9124 + + * Remove the pkg-config minimum version requirement (Behdad Esfahbod) + + Some systems ship with pkg-config 0.15 and there was really no good + reason for cairo to insist on having version 0.19 before it would + build. + +There is also one new (but inert) feature in this snapshot. There's a +new option that can be passed to cairo's configure script: + + --disable-some-floating-point + + Disable certain code paths that rely heavily on double precision + floating-point calculation. This option can improve + performance on systems without a double precision floating-point + unit, but might degrade performance on those that do. + +As of this snapshot, this option does not make any change to cairo, +but it is possible that future versions of cairo will respect this +option and change the implementation of various functions as +appropriate. + +Snapshot 1.3.4 (2006-11-22 Carl Worth ) +========================================================== +This is the second development snapshot in the 1.3 series. It comes +one week after the 1.3.2 snapshot. + +This snapshot has a couple of significant performance improvements, +and also adds new support for producing multi-page SVG output, (when +targeting SVG 1.2)---thanks to Emmanuel Pacaud. The details of the +performance improvements are as follows: + +1. The long-awaited "new tessellator". + + The credit for this being an improvement goes to Joonas Pihlaja. He + took my really slow code and really put it through its paces to get + the dramatic performance improvement seen below (up to 38x faster + on realistic cases, and more than 10x faster for the zrusin_another + test). + + His own writeup of the work he did is quite thorough, but more than + can be quoted here. Please see his post for the interesting details: + + https://lists.freedesktop.org/archives/cairo/2006-November/008483.html + + (Though note that this snapshot also includes some additional, + significant improvements that were only sketched out in that + email---see "Generating fewer trapezoids"). + +2. More floating-point improvements + + Daniel Amelang continues to work the magic he began in the 1.3.2 + snapshot. This time he short-circuits floating-point + transformations by identity matrices and applies the earlier + floating-to-fixed-point technique to the problem of rounding. + + The improvements here will primarily benefit text performance, and + will benefit platforms without hardware floating-point more than + those that have it, (some text tests show 20% improvement on an x86 + machine and closer to 80% improvement on arm). + +The performance chart comparing 1.3.2 to 1.3.4 really speaks for +itself, (this is on an x86 laptop). This is quite a lot of progress +for one week: + + xlib-rgb stroke_similar_rgba_over-256 74.99 1.45% -> 2.03 68.38%: 36.86x speedup +███████████████████████████████████▉ + xlib-rgb stroke_similar_rgba_source-256 78.23 1.43% -> 3.30 67.05%: 23.71x speedup +██████████████████████▊ + xlib-rgba tessellate-256-100 820.42 0.15% -> 35.06 2.84%: 23.40x speedup +██████████████████████■+image-rgba tessellate-256-100 819.55 0.32% -> 35.04 3.56%: 23.39x speedup +██████████████████████■+ xlib-rgb stroke_image_rgba_over-256 78.10 1.43% -> 4.33 65.56%: 18.04x speedup +█████████████████ + xlib-rgb stroke_image_rgba_source-256 80.11 1.63% -> 5.75 63.99%: 13.94x speedup +█████████████ + xlib-rgba zrusin_another_tessellate-415 89.22 0.35% -> 8.38 5.23%: 10.65x speedup +█████████▋ +image-rgba zrusin_another_tessellate-415 87.38 0.89% -> 8.37 5.22%: 10.44x speedup +█████████■+image-rgba zrusin_another_fill-415 117.67 1.34% -> 12.88 2.77%: 9.14x speedup +████████■+ xlib-rgba zrusin_another_fill-415 140.52 1.57% -> 15.79 2.88%: 8.90x speedup +███████▉ +image-rgba tessellate-64-100 9.68 3.42% -> 1.42 0.60%: 6.82x speedup +█████▉ + xlib-rgba tessellate-64-100 9.78 4.35% -> 1.45 0.83%: 6.72x speedup +█████▊ + xlib-rgb stroke_linear_rgba_over-256 46.01 2.44% -> 7.74 54.51%: 5.94x speedup +█████ + xlib-rgb stroke_linear_rgba_source-256 48.09 2.15% -> 9.14 53.00%: 5.26x speedup +████▎ + xlib-rgb stroke_radial_rgba_over-256 50.96 2.34% -> 12.46 47.99%: 4.09x speedup +███■+ xlib-rgb stroke_radial_rgba_source-256 53.06 1.57% -> 13.96 46.57%: 3.80x speedup +██▊ +image-rgba paint_similar_rgba_source-256 0.12 1.57% -> 0.08 9.92%: 1.42x speedup +■+image-rgba paint_image_rgba_source-256 0.12 2.49% -> 0.08 10.70%: 1.41x speedup +■+image-rgba world_map-800 356.28 0.46% -> 275.72 1.15%: 1.29x speedup +▎ + xlib-rgba world_map-800 456.81 0.39% -> 357.95 1.39%: 1.28x speedup +▎ +image-rgb tessellate-16-100 0.09 0.57% -> 0.07 3.43%: 1.23x speedup +▎ +image-rgba tessellate-16-100 0.09 0.06% -> 0.07 2.46%: 1.23x speedup +▎ +image-rgba text_solid_rgb_over-256 5.39 4.01% -> 4.47 0.70%: 1.21x speedup +▎ +image-rgba text_solid_rgba_over-256 5.37 0.82% -> 4.45 0.75%: 1.21x speedup +▎ +image-rgba text_image_rgb_over-64 0.78 0.10% -> 0.65 0.74%: 1.20x speedup +▎ +image-rgba text_image_rgba_over-64 0.78 0.29% -> 0.65 0.68%: 1.19x speedup +▎ +image-rgb text_solid_rgb_over-64 0.76 2.45% -> 0.63 0.81%: 1.19x speedup +▎ +image-rgba text_solid_rgba_over-64 0.76 0.33% -> 0.64 0.66%: 1.19x speedup +▎ +image-rgba text_similar_rgba_over-256 5.99 4.72% -> 5.04 1.09%: 1.19x speedup +▎ + +We should point out that there is some potential for slowdown in this +snapshot. The following are the worst slowdowns reported by the cairo +performance suite when comparing 1.3.2 to 1.3.4: + +image-rgba subimage_copy-256 0.01 0.87% -> 0.01 3.61%: 1.45x slowdown +▌ + xlib-rgb paint_solid_rgb_over-256 0.31 10.23% -> 0.38 0.33%: 1.26x slowdown +▎ +image-rgba box-outline-fill-100 0.01 0.30% -> 0.01 2.52%: 1.21x slowdown +▎ +image-rgba fill_solid_rgb_over-64 0.20 1.22% -> 0.22 1.59%: 1.12x slowdown +■+image-rgb fill_similar_rgb_over-64 0.21 1.04% -> 0.24 1.06%: 1.11x slowdown +■+image-rgba fill_image_rgb_over-64 0.21 1.19% -> 0.24 0.72%: 1.11x slowdown +■+image-rgba fill_similar_rgb_over-64 0.21 0.18% -> 0.24 0.30%: 1.11x slowdown +■+image-rgb fill_solid_rgba_over-64 0.22 1.66% -> 0.24 1.15%: 1.11x slowdown +■+image-rgb fill_image_rgb_over-64 0.21 0.14% -> 0.24 0.80%: 1.11x slowdown +■+image-rgba fill_image_rgba_over-64 0.22 1.34% -> 0.25 0.20%: 1.11x slowdown +■+image-rgba fill_solid_rgba_over-64 0.22 1.48% -> 0.24 0.95%: 1.11x slowdown +■+image-rgb fill_similar_rgba_over-64 0.22 1.13% -> 0.25 1.25%: 1.10x slowdown +■+ +The 45% slowdown for subimage_copy is an extreme case. It's unlikely +to hit many applications unless they often use cairo_rectangle; +cairo_fill to copy a single pixel at a time. In any case, it shows a +worst-case impact of the overhead of the new tessellator. The other +slowdowns (~ 10%) are probably more realistic, and still very +concerning. + +We will work to ensure that performance regressions like these are not +present from one major release of cairo to the next, (for example, +from 1.2 to 1.4). + +But we're putting this 1.3.4 snapshot out there now, even with this +potential slowdown so that people can experiment with it. If you've +got complex geometry, we hope you will see some benefit from the new +tessellator. If you've got primarily simple geometry, we hope things +won't slowdown too much, but please let us know what slowdown you see, +if any, so we can calibrate our performance suite against real-world +impacts. + +Thanks, and have fun with cairo! + +Snapshot 1.3.2 (2006-11-14 Carl Worth ) +========================================================== +This is the first development snapshot since the 1.2 stable series +branched off shortly after the 1.2.4 release in August 2006. + +This snapshot includes all the bug fixes from the 1.2.6 release, +(since they originated here on the 1.3 branch first and were +cherry-picked over to 1.2). But more importantly, it contains some new +API in preparation for a future 1.4 release, and most importantly, it +contains several performance improvements. + +The bug fixes will not be reviewed here, as most of them are already +described in the 1.2.6 release notes. But details for the new API and +some performance improvements are included here. + +As with all snapshots, this is experimental code, and the new API +added here is still experimental and is not guaranteed to appear +unchanged in any future release of cairo. + +API additions +------------- +Several new API additions are available in this release. There is a +common theme among all the additions in that they allow cairo to +advertise information about its state that it was refusing to +volunteer earlier. So this isn't groundbreaking new functionality, but +it is essential for easily achieving several tasks. + +The new functions can be divided into three categories: + + Getting information about the current clip region + ------------------------------------------------- + cairo_clip_extents + cairo_copy_clip_rectangles + cairo_rectangle_list_destroy + + Getting information about the current dash setting + -------------------------------------------------- + cairo_get_dash_count + cairo_get_dash + + Getting information from a pattern + ---------------------------------- + cairo_pattern_get_rgba + cairo_pattern_get_surface + cairo_pattern_get_color_stop_rgba + cairo_pattern_get_color_stop_count + cairo_pattern_get_linear_points + cairo_pattern_get_radial_circles + +In each of these areas, we have new API for providing a list of +uniform values from cairo. The closest thing we had to this before was +cairo_copy_path, (which is rather unique in providing a list of +non-uniform data). + +The copy_clip_rectangles/rectangle_list_destroy functions follow a +style similar to that of cairo_copy_path. Meanwhile, the dash and +pattern color stop functions introduce a new style in which there is a +single call to return the number of elements available (get_dash_count +and get_color_stop_count) and then a function to be called once to get +each element (get_dash and get_color_stop_rgba). + +I'm interested in hearing feedback from users of these new API +functions, particularly from people writing language bindings. One +open question is whether the clip "getter" functionality should adopt +a style similar to that of the new dash and color_stop interfaces. + +API deprecation +--------------- +The CAIRO_FORMAT_RGB16_565 enum value has been deprecated. It never +worked as a format value for cairo_image_surface_create, and it wasn't +necessary for supporting 16-bit 565 X server visuals. + +XCB backend changes +------------------- +The XCB backend has been updated to track the latest XCB API (which +recently had a 1.0 release). + +New quartz backend +------------------ +Vladimir Vukicevic has written a new "native quartz" backend which +will eventually replace the current "image-surface wrapping" quartz +backend. For now, both backends are available, (the old one is +"quartz" and the new one is "nquartz"). But it is anticipated that the +new backend will replace the old one and take on the "quartz" name +before this backend is marked as supported in a release of cairo. + +New OS/2 backend +---------------- +Doodle and Peter Weilbacher have contributed a new, experimental +backend for using cairo on OS/2 systems. + +Performance improvements +------------------------ +Here are some highlights from cairo's performance suite showing +improvements from cairo 1.2.6 to cairo 1.3.2. The command used to +generate this data is: + + ./cairo-perf-diff 1.2.6 HEAD + +available in the perf/ directory of a recent checkout of cairo's +source, (the cairo-perf-diff script does require a git checkout and +will not work from a tar file---though ./cairo-perf can still be used +to generate a single report there and ./cairo-perf-diff-files can be +used to compare two reports). + +Results are described below both for an x86 laptop (with an old Radeon +video card, recent X.org build, XAA, free software drivers), as well +as for a Nokia 770. First the x86 results with comments on each, (all +times are reported in milliseconds). + +Copying subsets of an image surface to an xlib surface (much faster) +-------------------------------------------------------------------- + xlib-rgba subimage_copy-512 10.50 -> : 53.97x speedup +█████████████████████████████████████████████████████ + +Thanks to Christopher (Monty) Montgomery for this big performance +improvement. Any application which has a large image surface and is +copying small pieces of it at a time to an xlib surface, (imagine an +application that loads a single image containing all the "sprites" for +that application), will benefit from this fix. The larger the ratio of +the image surface to the portion being copied, the larger the benefit. + +Floating-point conversion (3x faster) +------------------------------------- + xlib-rgba pattern_create_radial-16 27.75 -> 3.93 : 2.94x speedup +██ +image-rgb pattern_create_radial-16 26.06 -> 3.74 : 2.90x speedup +█▉ + +Thanks to Daniel Amelang, (and others who had contributed the idea +earlier), for this nice improvement in the speed of converting +floating-point values to fixed-point. + +Text rendering (1.3 - 2x faster) +------------------------------ + xlib-rgba text_image_rgba_source-256 319.73 -> 62.40 : 2.13x speedup +█■+image-rgb text_solid_rgba_over-64 2.85 -> 0.88 : 1.35x speedup +■+ +I don't think we've ever set out to improve text performance +specifically, but we did it a bit anyway. I believe the extra +improvement in the xlib backend is due to Monty's image copying fix +above, and the rest is due to the floating-point conversion speedup. + +Thin stroke improvements (1.5x faster) +--------------------------------------------- +image-rgb world_map-800 1641.09 -> 414.77 : 1.65x speedup +▋ + xlib-rgba world_map-800 1939.66 -> 529.94 : 1.52x speedup +▌ + +The most modest stuff to announce in this release is the 50% +improvement I made in the world_map case. This is in improvement that +should help basically anything that is doing strokes with many +straight line segments, (and the thinner the better, since that makes +tessellation dominate rasterization). The fixes here are to use a +custom quadrilateral tessellator rather than the generic tessellator +for straight line segments and the miter joins. + +Performance results from the Nokia 770 +-------------------------------------- + xlib-rgba subimage_copy-512 55.88 -> 2.04 : 27.34x speedup +██████████████████████████■+ xlib-rgb text_image_rgb_over-256 1487.58 -> 294.43 : 5.05x speedup +████ +image-rgb pattern_create_radial-16 187.13 -> 91.86 : 2.04x speedup +█ + xlib-rgba world_map-800 21261.41 -> 15628.02 : 1.36x speedup +■+ +Here we see that the subimage_copy improvement was only about half as +large as the corresponding improvement on my laptop, (27x faster +compared to 54x) and the floating-point conversion fix also was quite +as significant, (2x compared to 3x). Oddly the improvement to text +rendering performance was more than twice as good (5x compared to +2x). I don't know what the reason for that is, but I don't think it's +anything anybody should complain about. + +Release 1.2.6 (2006-11-02 Behdad Esfahbod ) +============================================================== +This is the third bug fix release in the 1.2 series, coming less than +two months after the 1.2.4 release made on August 18. + +The 1.2.4 release turned out to be a pretty solid one, except for a crash +bug when forwarding an X connection where the client and the server have +varying byte orders, eg. from a PPC to an i686. Other than that, various +other small bugs have been fixed. + +Various improvements have been made in the testing infrastructure to prevent +false positives, and to make sure the generated cairo shared object behaves as +expected in terms of exported symbols and relocations. + +There were a total of 89 changes since 1.2.4. The following list the most +important ones: + +Common fixes +------------ +- Avoid unsigned loop control variable to eliminate infinite, + memory-scribbling loop. (#7593) +- Fix cairo_image_surface_create to report INVALID_FORMAT errors. + Previously the detected error was being lost and a nil surface was + returned that erroneously reported CAIRO_STATUS_NO_MEMORY. +- Change _cairo_color_compute_shorts to not rely on any particular + floating-point epsilon value. (#7497) +- Fix infinite-join test case (bug #8379) +- Pass correct surface to create_similar in _cairo_clip_init_deep_copy(). + +PS/PDF fixes +------------ +- Fix Type 1 embedding in PDF. +- Correct the value of /LastChar in the PDF Type 1 font dictionary. +- Improve error checking in TrueType subsetting. +- Compute right index when looking up left side bearing. (bug #8180) +- Correct an unsigned to signed conversion problem in truetype subsetting + bbox. +- Type1 subsetting: Don't put .notdef in Encoding when there are 256 glyphs. +- Add cairo version to PS header / PDF document info dictionary. +- Set CTM before path construction. + +Win32 fixes +----------- +- Get correct unhinted outlines on win32. (bug 7603) +- Make cairo as a win32 static library possible. +- Use CAIRO_FORMAT_RGB24 for BITSPIXEL==32 surfaces too. + +Build system fixes +------------------ +- Define WINVER if it's not defined. (bug 6456) +- Fix the AMD64 final link by removing SLIM from pixman. +- Misc win32 compilation fixes. +- Add Sun Pro C definition of pixman_private. +- Use pixman_private consistently as prefix not suffix. +- Added three tests check-plt.sh, check-def.sh, and check-header.sh that check + that the shared object, the .def file, and the public headers agree about + the exported symbols. +- Require pkg-config 0.19. (#8686) + + +Release 1.2.4 (2006-08-18 Carl Worth ) +========================================================= +This is the second bug fix release in the 1.2 series, coming less than +two weeks after the 1.2.2 release made on August 8. + +The big motivation for a quick release was that there were a log of +build system snags that people ran into with the 1.2.2 release. But, +by the time we got those all done, we found that we had a bunch of +fixes for cairo's rendering as well. So there's a lot of goodness in +here for such a short time period. + +Rendering fixes +--------------- +Fix image surfaces to not be clipped when used as a source (Vladimir Vukicevic) +https://gitweb.freedesktop.org/?p=cairo;a=commit;h=72e25648c4c4bc82ddd938aa4e05887a293f0d8b + +Fix a couple of corner cases in dashing degenerate paths (Jeff Muizelaar) +https://gitweb.freedesktop.org/?p=cairo;a=commit;h=fbb1758ba8384650157b2bbbc93d161b0c2a05f0 + +Fix support for type1 fonts on win32 (Adrian Johnson) +https://gitweb.freedesktop.org/?p=cairo;a=commit;h=da1019c9138695cb838a54f8b871bbfd0e8996d7 + +Fix assertion failure when rotating bitmap fonts (Carl Worth) +https://gitweb.freedesktop.org/?p=cairo;a=commit;h=0bfa6d4f33b8ddb5dc55bbe419c15df4af856ff9 + +Fix assertion failure when calling cairo_text_path with bitmap fonts (Carl Worth) +https://gitweb.freedesktop.org/?p=cairo;a=commit;h=9878a033531e6b96b5f27e69e10e90dee7440cd9 + +Fix mis-handling of cairo_close_path in some situations (Tim Rowley, Carl Worth) +https://gitweb.freedesktop.org/?p=cairo;a=commit;h=53f74e59faf1af78f2f0741ccf1f23aa5dad4efc + +Respect font_matrix translation in _cairo_gstate_glyph_path (Behdad Esfahbod) +https://gitweb.freedesktop.org/?p=cairo;a=commit;h=f183b835b111d23e838889178aa8106ec84663b3 + +Fix vertical metrics adjustment to work with non-identity shapes (Behdad Esfahbod) +https://gitweb.freedesktop.org/?p=cairo;a=commit;h=b7bc263842a798d657a95e539e1693372448837f + +[PS] Set correct ImageMatrix in _cairo_ps_surface_emit_bitmap_glyph_data (Behdad Esfahbod) +https://gitweb.freedesktop.org/?p=cairo;a=commit;h=d47388ad759b0a1a0869655a87d9b5eb6ae2445d + +Build system fixes +------------------ +Fix xlib detection to prefer pkg-config to avoid false libXt dependency (Behdad Esfahbod) +https://gitweb.freedesktop.org/?p=cairo;a=commit;h=0e78e7144353703cbd28aae6a67cd9ca261f1d68 + +Fix typos causing win32 build problem with PS,PDF, and SVG backends (Behdad Esfahbod) +https://gitweb.freedesktop.org/?p=cairo;a=commit;h=aea83b908d020e26732753830bb3056e6702a774 + +Fix configure cache to not use stale results (Behdad Esfahbod) +https://gitweb.freedesktop.org/?p=cairo;a=commit;h=6d0e3260444a2d5b6fb0cb223ac79f1c0e7b3a6e + +Fix to not pass unsupported warning options to the compiler (Jens Granseuer) +https://gitweb.freedesktop.org/?p=cairo;a=commit;h=97524a8fdb899de1ae4a3e920fb7bda6d76c5571 + +Fix to allow env. variables such as png_REQUIRES to override configure detection (Jens Granseuer) +https://gitweb.freedesktop.org/?p=cairo;a=commit;h=abd16e47d6331bd3811c908e524b4dcb6bd23bf0 + +Fix test suite to not use an old system cairo when converting svg2png (Behdad Esfahbod) +https://gitweb.freedesktop.org/?p=cairo;a=commit;h=6122cc85c8f71b1ba2df3ab86907768edebe1781 + +Fix test suite to not require signal.h to be present (Behdad Esfahbod) +https://gitweb.freedesktop.org/?p=cairo;a=commit;h=6f8cf53b1e1ccdbe1ab6a275656b19c6e5120e40 + +Code cleanups +------------- +Many useful warnings cleanups from sparse, valgrind, and careful eyes +(Kjartan Maraas, Pavel Roskin) + +Release 1.2.2 (2006-08-08 Carl Worth ) +========================================================= +This is the first bug fix release in the 1.2 series since the original +1.2.0 release made six weeks ago. + +There were some very serious bugs in the 1.2.0 release, (see below), +so everybody is encouraged to upgrade from 1.2.0 to 1.2.2. The 1.2.2 +release maintains source and binary compatibility with 1.2.0 and does +not make any API additions. + +Fix crashes with BGR X servers +------------------------------ +With cairo 1.2.0 many people reported problems with all cairo-using +programs, (including all GTK+ programs with GTK+ >= 2.8) immediately +crashing with a complaint about an unsupported image format. This bug +affected X servers that do not provide the Render extension and that +provide a visual with BGR rather than RGB channel order. + +report: https://bugs.freedesktop.org/show_bug.cgi?id=7294 +fix: https://gitweb.freedesktop.org/?p=cairo;a=commit;h=9ae66174e774b57f16ad791452ed44efc2770a59 + +Fix the "disappearing text" bug +------------------------------- +With cairo 1.2.0 many people reported that text would disappear from +applications, sometimes reappearing with mouse motion or +selection. The text would disappear after the first space in a string +of text. This bug was caused by an underlying bug in (very common) X +servers, and only affected text rendered without antialiasing, (either +a bitmap font or a vector font with antialiasing disabled). The bug +was also exacerbated by a KDE migration bug that caused antialiasing +to be disabled more than desired. + +report: https://bugs.freedesktop.org/show_bug.cgi?id=7494 +fix: https://gitweb.freedesktop.org/?p=cairo;a=commit;h=456cdb3058f3b416109a9600167cd8842300ae14 +see also: +Xorg: https://bugs.freedesktop.org/show_bug.cgi?id=7681 +KDE: http://qa.mandriva.com/show_bug.cgi?id=23990 + +Fix broken image fallback scaling (aka. "broken printing") +---------------------------------------------------------- +The various "print" backends, (pdf, ps, and svg), sometimes fallback +to using image-based rendering for some operations. In cairo 1.2.0 +these image fallbacks were scaled improperly. Applications using cairo +can influence the resolution of the image fallbacks with +cairo_surface_set_fallback_resolution. With the bug, any value other +than 72.0 would lead to incorrect results, (larger values would lead +to increasingly shrunken output). + +report: https://bugs.freedesktop.org/show_bug.cgi?id=7533 +fix: https://gitweb.freedesktop.org/?p=cairo;a=commit;h=1feb4291cf7813494355459bb547eec604c54ffb + +Fix inadvertent semantic change of font matrix translation (Behdad Esfahbod) +---------------------------------------------------------------------------- +The 1.2.0 release introduced an inadvertent change to how the +translation components of a font matrix are interpreted. In the 1.0 +series, font matrix translation could be used to offset the glyph +origin, (though glyph metrics were reported incorrectly in +1.0). However in 1.2.0, the translation was applied to the advance +values between each glyph. The 1.2.0 behavior is fairly useless in +practice, and it was not intentional to introduce a semantic +change. With 1.2.2 we return to the 1.0 semantics, with a much better +implementation that provides correct glyph metrics. + +fix: https://gitweb.freedesktop.org/?p=cairo;a=commit;h=84840e6bba6e72aa88fad7a0ee929e8955ba9051 + +Fix create_similar to preserve fallback resolution and font options (Behdad Esfahbod) +------------------------------------------------------------------------------------- +There has been a long-standing issue with cairo_surface_create_similar +such that font options and other settings from the original +destination surface would not be preserved to the intermediate +"similar" surface. This could result in incorrect rendering +(particularly with respect to text hinting/antialiasing) with +fallbacks, for example. + +report: https://bugs.freedesktop.org/show_bug.cgi?id=4106 +fixes: https://gitweb.freedesktop.org/?p=cairo;a=commit;h=9fcb3c32c1f16fe6ab913e27eb54d18b7d9a06b0 + https://gitweb.freedesktop.org/?p=cairo;a=commit;h=bdb4e1edadb78a2118ff70b28163f8bd4317f1ec + +xlib: Fix text performance regression from 1.0 to 1.2.0 (Vladimir Vukicevic) +---------------------------------------------------------------------------- +Several people noticed that upgrading from cairo 1.0 to cairo 1.2.0 +caused a significant performance regression when using the xlib +backend. This performance regression was particularly noticeable when +doing lots of text rendering and when using a high-latency connection +to the X server, (such as a remote X server over an ssh +connection). The slowdown was identified and fixed in 1.2.2. + +report: https://bugs.freedesktop.org/show_bug.cgi?id=7514 +fix: https://gitweb.freedesktop.org/?p=cairo;a=commit;h=b7191885c88068dad57d68ced69a752d1162b12c + +PDF: Eliminate dependency on FreeType library dependency (Adrian Johnson) +------------------------------------------------------------------------- +The cairo 1.2 series adds a supported pdf backend to cairo. In cairo +1.2.0 this backend required the freetype library, which was an +undesirable dependency on systems such as win32, (cairo is designed to +always prefer the "native" font system). As of cairo 1.2.2 the +freetype library is not required to use the pdf backend on the win32 +platform. + +report: https://bugs.freedesktop.org/show_bug.cgi?id=7538 +fix: https://gitweb.freedesktop.org/?p=cairo;a=commit;h=a0989f427be87c60415963dd6822b3c5c3781691 + +PDF: Fix broken output on amd64 (Adrian Johnson) +------------------------------------------------ +report: https://bugzilla.gnome.org/show_bug.cgi?id=349826 +fix: https://gitweb.freedesktop.org/?p=cairo;a=commit;h=f4b12e497b7ac282b2f6831b8fb68deebc412e60 + +PS: Fix broken output for truetype fonts > 64k (Adrian Johnson) +--------------------------------------------------------------- +fix: https://gitweb.freedesktop.org/?p=cairo;a=commit;h=067d97eb1793a6b0d0dddfbd0b54117844511a94 + +PDF: Fix so that dashing doesn't get stuck on (Kent Worsnop) +------------------------------------------------------------ +Kent notices that with the PDF backend in cairo 1.2.0 as soon as a +stroke was performed with dashing, all subsequent strokes would also +be dashed. There was no way to turn dashing off again. + +fix: https://gitweb.freedesktop.org/?p=cairo;a=commit;h=778c4730a86296bf0a71080cf7008d7291792256 + +Fix memory leaks in failure paths in gradient creation (Alfred Peng) +-------------------------------------------------------------------- +fix: https://gitweb.freedesktop.org/?p=cairo;a=commit;h=db06681b487873788b51a6766894fc619eb8d8f2 + +Fix memory leak in _cairo_surface_show_glyphs (Chris Wilson) +------------------------------------------------------------ +report: https://bugs.freedesktop.org/show_bug.cgi?id=7766 +fix: https://gitweb.freedesktop.org/?p=cairo;a=commit;h=e2fddcccb43d06486d3680a19cfdd5a54963fcbd + +Solaris: Add definition of cairo_private for some Sun compilers (Alfred Peng) +----------------------------------------------------------------------------- +report: https://bugzilla.mozilla.org/show_bug.cgi?id=341874 +fix: https://gitweb.freedesktop.org/?p=cairo;a=commit;h=04757a3aa8deeff3265719ebe01b021638990ec6 + +Solaris: Change version number of Sun's Xorg server with buggy repeat (Brian Cameron) +------------------------------------------------------------------------------------- +report: https://bugs.freedesktop.org/show_bug.cgi?id=7483 +fix: https://gitweb.freedesktop.org/?p=cairo;a=commit;h=e0ad1aa995bcec4246c0b8ab0d5a5a79871ce235 + +Various memory leak fixes +------------------------- +Fix memory leak in _cairo_surface_show_glyphs (bug 7766) +Fix file handle leak in failure path (bug 7616) +Fix some memory leaks in the test cases. +Fix some memory leaks in font subsetting code used in print backends. + +Documentation improvements (Behdad Esfahbod) +-------------------------------------------- +Added new documentation for several functions (cairo_show_page, +cairo_copy_page, cairo_in_stroke, cairo_in_fill). + +Fixed some syntax errors that were preventing some existing +documentation from being published. + +Fixed several minor typographical errors. + +Added an index for new symbols in 1.2. + +Release 1.2.0 (2006-06-27 Carl Worth ) +========================================================= +This is the culmination of the work that has gone on within the 1.1 +branch of cairo. + +There has been one API addition since the cairo 1.1.10 snapshot: + + cairo_xlib_surface_get_width + cairo_xlib_surface_get_height + +There's also a new feature without any API change: + + Dots can now be drawn by using CAIRO_LINE_CAP_ROUND with + degenerate sub-paths, (cairo_move_to() followed by either + cairo_close_path() or a cairo_line_to() to the same location). + +And at least the following bugs have been fixed: + + 6759 fontconfig option AntiAlias doesn't work in cairo 1.1.2 + 6955 Some characters aren't displayed when using xlib (cache u... + 7268 positive device_offset values don't work as source + * PDF emit_glyph function needs to support bitmapped glyphs + * PS emit_glyph function needs to support bitmapped glyphs + * SVG emit_glyph function needs to support bitmapped glyphs + * PDF: minefield page one is falling back unnecessarily + * PS/PDF: Fix broken placement for vertical glyphs + * PS: Fix to not draw BUTT-capped zero-length dash segments + * Do device offset before float->fixed conversion + https://bugzilla.gnome.org/show_bug.cgi?id=332266 + * PS: Fix source surfaces with transformations + * PS: Fix to not draw BUTT-capped degenerate sub-paths + * PS: Don't walk off end of array when printing "~>" + * Fix some memory leaks in the test suite rig + * SVG: Fix memory leak when using cairo_mask + * Fix EXTEND_REFLECT and EXTEND_PAD to not crash (though these are + still not yet fully implemented for surface patterns). + +This has been a tremendous effort by everyone, and I'm proud to have +been a part of it. Congratulations to all contributors to cairo! + +Snapshot 1.1.10 (2006-06-16 Carl Worth ) +=========================================================== +This is the fifth in a series of snapshots working toward the 1.2 +release of cairo. + +The primary motivation for this snapshot is to fix a long-standing bug +that had long been silent, but as of the 1.1.8 snapshot started +causing crashes when run against 16-bit depth X servers, (often Xvnc +or Xnest). The fix for this adds a new CAIRO_FORMAT_RGB16_565 to the +API. + +This snapshot also includes a rewrite of cairo's SVG backend to +eliminate the dependency on libxml2. With this in place, cairo 1.2 +will not depend on any libraries that cairo 1.0 did not. + +As usual, there are also a few fixes for minor bugs. + +Snapshot 1.1.8 (2006-06-14 Carl Worth ) +========================================================== +This is the fourth in a series of snapshots working toward the 1.2 +release of cairo. At this point, all major features of the 1.2 release +are in place, leaving just a few bug fixes left. + +In particular, there well be no additional API changes between this +1.1.8 snapshot and the 1.2 release. + +The announcement for 1.1.6 mentioned several API changes being +considered. Only one of these changes was actually implemented +(set_dpi -> fallback_resolution). This change does introduce one +source-level incompatibility with respect to previous 1.1.x snapshots, +so see below for details. + +Here is an abbreviated summary of changes since the 1.1.6 snapshot: + +** API Change ** +---------------- +According to the plan mentioned in the 1.1.6 notes, one source-level +incompatible change has been implemented. The following three +functions have been removed from cairo's API: + + cairo_pdf_surface_set_dpi + cairo_ps_surface_set_dpi + cairo_svg_surface_set_dpi + +and in their place the following function has been added: + + cairo_surface_set_fallback_resolution + +The signature and semantics of the function remains the same, so it is +a simple matter of changing the name of the function when calling +it. As a transition mechanism, this snapshot will (on many systems) +build to include the old symbols so that code previously compiled will +still run. However, all source code using the old names must be +updated before it will compile. And the upcoming 1.2 release is not +anticipated to include the old symbols. + +Finally, it should be pointed out that the old symbols never existed +in the supported API of any stable release of cairo. (In the stable +1.0 releases the PDF, PS, and SVG backends were advertised as +experimental and unstable.) + +And, as always, cairo continues to maintain source and binary +compatibility between major releases. So applications compiled against +supported backends in a stable release of cairo (1.0.4 say) will +continue to compile and run without modification against new major +releases (1.2.0 say) without modification. + +API additions +------------- +The following new functions have been added to cairo's API: + + cairo_surface_get_content + cairo_debug_reset_static_data + cairo_image_surface_get_data + cairo_image_surface_get_format + cairo_image_surface_get_stride + cairo_win32_font_face_create_for_hfont + +New, backend-specific pkg-config files +-------------------------------------- +In addition to the original cairo.pc file, cairo will also now install +a pkg-config files for each configured backend, (for example +cairo-pdf.pc, cairo-svg.pc, cairo-xlib.pc, cairo-win32.pc, etc.) this +also includes optional font backends (such as cairo-ft.pc) and the +optional png functionality (cairo-png.pc). + +These new pkg-config files should be very convenient for allowing +cairo-using code to easily check for the existing of optional +functionality in cairo without having to write complex rules to grub +through cairo header files or the compiled library looking for +symbols. + +Printing backend (PS, PDF, and SVG) +----------------------------------- +Improving the quality of the "printing" backends has been a priority +of the development between cairo 1.1.6 and cairo 1.1.8. + +The big improvement here is in the area of text output. Previously, at +best, text was output as paths without taking advantage of any font +support available in the output file format. + +Now, at the minimum text paths will be shared by using type3 fonts +(for PS and PDF---and similarly, defs for SVG). Also, if possible, +type3 and truetype fonts will be embedded in PostScript and PDF +output. There are still some known bugs with this, (for example, +selecting text in a cairo-generated PDF file with an embedded truetype +font does not work). So there will be some more changes in this area +before cairo 1.2, but do try test this feature out as it exists so +far. + +Many thanks to Kristian Høgsberg for the truetype and type1 font +embedding. + +win32 backend +------------- +Performance improvements by preferring GDI over pixman rendering when possible. +Fixes for text rendering. + +xlib backend +------------ +Fix potentially big performance bug by making xlib's create_similar +try harder to create a pixmap of a depth matching that of the screen. + +Bug fixes +--------- +Among various other fixes, the following bugs listed in bugzilla have +been fixed: + + Bug 2488: Patch to fix pixman samping location bug (#2488). + https://bugs.freedesktop.org/show_bug.cgi?id=2488 + + Bug 4196: undef MIN an MAX before defining to avoid duplicate definition + https://bugs.freedesktop.org/show_bug.cgi?id=4196 + + Bug 4723: configure.in: Fix m4 quoting when examining pkg-config version + https://bugs.freedesktop.org/show_bug.cgi?id=4723 + + Bug 4882: Flag Sun's X server has having buggy_repeat. + https://bugs.freedesktop.org/show_bug.cgi?id=4882 + + Bug 5306: test/pdf2png: Add missing include of stdio.h + https://bugs.freedesktop.org/show_bug.cgi?id=5306 + + Bug 7075: Fix make clean to remove cairo.def + https://bugs.freedesktop.org/show_bug.cgi?id=7075 + +(Many thanks to Behdad Esfahbod for helping us track down and fix many +of these.) + +Snapshot 1.1.6 (2006-05-04 Carl Worth ) +========================================================== +This is the third in a series of snapshots working toward the imminent +1.2 release of cairo. For a list of items still needing work on the +cairo 1.2 roadmap, please see: + + https://cairographics.org/ROADMAP + +As can be seen in that list, there are no longer any API additions +left on the roadmap. Instead, there is a feature (PDF type 3 fonts) a +performance optimization (X server gradients) and a list of bug +fixes. This gives us a fair amount of freedom to cut the 1.2 release +at almost any point by deciding to defer remaining bug fixes to +subsequent maintenance releases such as 1.2.2 and 1.2.4. + +Before we will do that, we must first be wiling to commit to all the +new API additions. As a heads-up, there are a couple of potential API +changes being considered. (Note that these are changes to new API +introduced during 1.1 so these will not introduce API +incompatibilities compared to the stable 1.0 series). The changes +being considered are: + + cairo_get_group_target: may acquire x and y offset return + parameters. May also be eliminated in favor of + cairo_get_target assuming its role + + cairo_pdf_surface_set_dpi: + cairo_ps_surface_set_dpi: + cairo_svg_surface_set_dpi: These functions may be removed in favor + of a new cairo_surface_set_fallback_resolution + +Additionally there is the possibility of a slight change in the +semantics of cairo_set_line_width. We believe the current behavior of the sequence: + + cairo_set_line_width; ... change CTM ...; cairo_stroke; + +is buggy. It is currently behaving the same as: + + ... change CTM ...; cairo_set_line_width; cairo_stroke; + +We are considering fixing this bug before 1.2 with the hope that +nobody is already relying on the buggy behavior described here. Do +shout if you suspect you might be in that position. + +The items included in this snapshot (since the 1.1.4 snapshot) are +described below. + +API additions +------------- +The long-awaited group-rendering support is now available with the +following function calls: + + cairo_push_group + cairo_push_group_with_content + cairo_pop_group + cairo_pop_group_to_source + cairo_get_group_target + +This API provides a much more convenient mechanism for doing rendering +to an intermediate surface without the need to manually create a +temporary cairo_surface_t and a temporary cairo_t and clean them up +afterwards. + +Add the following missing get function to complement +cairo_surface_set_device_offset: + + cairo_surface_get_device_offset + +PDF backend (API addition) +-------------------------- +The PDF backend now provides for per-page size changes, (similar to +what the PostScript backend got in the 1.1.4 snapshot). The new API +is: + + cairo_pdf_surface_set_size + +Xlib backend (API additions) +---------------------------- +The following functions have been added to allow the extraction of +Xlib surface: + + cairo_xlib_surface_get_display + cairo_xlib_surface_get_drawable + cairo_xlib_surface_get_screen + cairo_xlib_surface_get_visual + cairo_xlib_surface_get_depth + +XCB backend (experimental) +-------------------------- +Update backend so that it now compiles with the recent XCB 0.9 release. + +Bug fixes and memory leak cleanup +--------------------------------- +Various little things, nothing too significant though. + +Snapshot 1.1.4 (2006-05-03 Carl Worth ) +========================================================== +This is the second in a series of snapshots working toward the +upcoming 1.2 release of cairo. For a list of items still needing work +on the cairo 1.2 roadmap, please see: + + https://cairographics.org/ROADMAP + +The items included in this snapshot (since the 1.1.2 snapshot) are +described below. + +PostScript backend: new printing-oriented API +--------------------------------------------- +We anticipate that with cairo 1.2, toolkits will begin to use cairo +for printing on systems that use PostScript as the spool format. To +support this use case, we have added 4 new function calls that are +specific to the PostScript backend: + + cairo_ps_surface_set_size + cairo_ps_surface_dsc_comment + cairo_ps_surface_dsc_begin_setup + cairo_ps_surface_dsc_begin_page_setup + +These functions allow variation of the page size/orientation from one +page to the next in the PostScript output. They also allow the toolkit +to provide per-document and per-page printer control options in a +device-independent way, (for example, by using PPD options and +emitting them as DSC comments into the PostScript output). This should +allow toolkits to provide very fine-grained control of many options +available in printers, (media size, media type, tray selection, etc.). + +SVG backend: builds by default, version control +----------------------------------------------- +The SVG backend continues to see major improvements. It is expected +that the SVG backend will be a supported backend in the 1.2 +release. This backend will now be built by default if its dependencies +(freetype and libxml2) are met. + +Additionally, the SVG backend now has flexibility with regard to what +version of SVG it targets. It will target SVG 1.1 by default, which +will require image fallbacks for some of the "fancier" cairo +compositing operators. Or with the following new function calls: + + cairo_svg_surface_restrict_to_version + cairo_svg_get_versions + cairo_svg_version_to_string + +it can be made to target SVG 1.2 in which there is native support for +these compositing operators. + +Bug fixes +--------- +At least the following bugs have been fixed since the 1.1.2 snapshot: + +crash at XRenderAddGlyphs +https://bugs.freedesktop.org/show_bug.cgi?id=4705 + +Can't build cairo-1.1.2 on opensolaris due to " void function cannot return value" +https://bugs.freedesktop.org/show_bug.cgi?id=6792 + +Missing out-of-memory check at gfx/cairo/cairo/src/cairo-atsui-font.c:185 +https://bugzilla.mozilla.org/show_bug.cgi?id=336129 + +A couple of memory leaks. + +Snapshot 1.1.2 (2006-04-25 Carl Worth ) +========================================================== +This is the first in a series of snapshots working toward the upcoming +1.2 release of cairo. (Subsequent snapshot will use successive even +numbers for the third digit, 1.1.4, 1.1.6, etc.) This snapshot is +backwards-compatible with the 1.0 series---it makes a few API +additions but does not remove any API. + +PostScript and PDF backends are no longer "experimental" +-------------------------------------------------------- +The major theme of the 1.2 release is improved PostScript and PDF +backends for cairo. Unlike the 1.0 series, in the 1.2 series these +backends will not be marked as experimental and will be enabled by +default. We encourage people to test this snapshot and the PS/PDF +backends in particular as much as possible. + +The PostScript and PDF output is not yet ideal. + + * One major problem with the PostScript output is that image + fallbacks are used more often than strictly necessary, and the + image fallbacks are at a lower resolution than desired, (the + cairo_ps_surface_set_dpi call is ignored). + + * The major drawback of the current PDF backend implementation is + its text support. Every glyph is represented by a filled path in + the PDF file. The causes file sizes to be much larger and + rendering to be much slower than desired. + +It is anticipated that both of these shortcomings will see some +improvements before the final 1.2 release. + +In spite of those shortcomings, we hope that the PS and PDF backends +will yield faithful results for pretty much any cairo operations you +can throw at them. Please let us know if you are getting obviously +"different" results from the PS/PDF backends than from the image or +xlib backends. + +Other new experimental backends +------------------------------- +This snapshot includes three new backends that did not exist in the +1.0 series: + + * beos backend + + * directfb backend + + * svg backend + +These are all currently marked "experimental" and are disabled by +default. But the SVG backend in particular has seen a lot of recent +development and is very close to passing the entire cairo test +suite. It is possible that this backend will become a fully supported +backend by the time of the cairo 1.2 release. + +Public API additions +-------------------- +There have been a few new API functions added to cairo, including: + +New get_type functions for querying sub-types of object: + + cairo_surface_get_type + cairo_pattern_get_type + cairo_font_face_get_type + cairo_scaled_font_get_type + +More convenience in working with cairo_scaled_font_t with new getter +functions: + + cairo_scaled_font_get_font_face + cairo_scaled_font_get_font_matrix + cairo_scaled_font_get_ctm + cairo_scaled_font_get_font_options + +As well as a convenience function for setting a scaled font into a +cairo context: + + cairo_set_scaled_font + +and a function to allow text extents to be queried directly from a +scaled font, (without requiring a cairo_surface_t or a cairo_t): + + cairo_scaled_font_text_extents + +These new scaled font functions were motivated by the needs of the +pango library. + +Finally, a new path-construction function was added which clears the +current point in preparation for a new sub path. This makes cairo_arc +easier to use in some situations: + + cairo_new_sub_path + +Before the 1.2 release is final we do still plan a few more API +additions specifically motivated by the needs of Mozilla/Firefox. + +Optimizations and bug fixes +--------------------------- +Shortly after the 1.0 maintenance series branched off the mainline +there was a major rework of the cairo font internals. This should +provide some good performance benefits, but it's also another area +people should look at closely for potential regressions. + +There has not yet been any widespread, systematic optimization of +cairo, but various performance improvements have been made, (and some +of them are fairly significant). So if some things seem faster than +1.0 then things are good. If there are any performance regressions +compared to 1.0 then there is a real problem and we would like to hear +about that. + +There has been a huge number of bug fixes---too many to mention in +detail. Again, things should be better, and never worse compared to +1.0. Please let us know if your testing shows otherwise. + +Release 1.0.2 (2005-10-03 Carl Worth ) +========================================================= +For each bug number XXXX below, see: + + https://bugs.freedesktop.org/show_bug.cgi?id=XXXX + +for more details. + +General bug fixes +----------------- + * 4408 - Add support for dashing of stroked curves + (Carl Worth) + + * 4409 - Fix dashing so that each dash is capped on both ends + (Carl Worth) + + * 4414 - Prevent SIGILL failures (proper use of -mmmx and -msse flags) + (Sebastien Bacher, Billy Biggs) + + * 4299 - Fix crashes with text display in multi-threaded program + (Alexey Shabalin, Carl Worth) + + * 4401 - Do not use sincos function since it is buggy on some platforms) + (Tim Mooney, Carl Worth) + + * 4245 - Fix several bugs in the test suite exposed by amd64 systems + (Seemant Kulleen, Carl Worth) + + * 4321 - Add missing byteswapping on GetImage/PutImage + (Sjoerd Simons, Owen Taylor) + + * 4220 - Make the check for rectangular trapezoids simpler and more accurate + (Richard Stellingwerff, Owen Taylor) + + * 4260 - Add missing channel-order swapping for antialised fonts + (Barbie LeVile, Owen Taylor) + + * 4283 - Fix compilation failure with aggressive inlining (gcc -O3) + (Marco Manfredini, Owen Taylor) + + * 4208 - Fix some warnings from sparse + (Kjartan Maraas, Billy Biggs) + + * 4269 - Fix to not crash when compiled with -fomit-frame-pointer + (Ronald Wahl, Owen Taylor) + + * 4263 - Improve performance for vertical gradients + (Richard Stellingwerff, Owen Taylor) + + * 4231 + * 4298 - Accommodate gentoo and Mandriva versions in X server vendor string check + (Billy Biggs, Frederic Crozat, Owen Taylor) + +win32-specific fixes +-------------------- + * 4599 - Fix "missing wedges" on some stroked paths (win32) + (Tim Rowley, Jonathan Watt, Bertram Felgenhauer, Carl Worth, Keith Packard) + + * 4612 - Fix disappearing text if first character out of surface (win32) + (Tim Rowley) + + * 4602 - Fix shutdown of cairo from failing intermediate, size-0 bitmaps (win32) + Aka. the "white rectangles" bug from mozilla-svg testing + (Tim Rowley) + + * Various portability improvements for win32 + (Hans Breuer, Owen Taylor, Carl Worth) + + * 4593 - Fix font sizes to match user expectations (win32) + (Tor Lillqvist, Owen Taylor) + + * 3927 - Fix to report metrics of size 0 for glyph-not-available (win32) + (Hans Breuer, Owen Taylor, Tor Lillqvist) + + * Add locking primitives for win32 + (Hans Breuer) + +xlib-specific fixes +------------------- + * Fix crash from size-0 pixmap due to empty clip region (xlib) + (Radek Doulík, Carl Worth) + +Release 1.0.0 (2005-08-24 Carl Worth ) +========================================================= +Experimental backends +--------------------- + * The Glitz, PS, PDF, Quartz, and XCB backends have been declared + experimental, and are not part of the API guarantees that accompany + this release. They are not built by default, even when the required + libraries are available, and must be enabled explicitly with + --enable-ps, --enable-pdf, --enable-quartz or --enable-xcb. + + It is very painful for us to be pushing out a major release without + these backends enabled. There has been a tremendous amount of work + put into each one and all are quite functional to some + extent. However, each also has some limitations. And none of these + backends have been tested to the level of completeness and + correctness that we expect from cairo backends. + + We do encourage people to experiment with these backends and report + success, failure, or means of improving them. + +Operator behavior +----------------- + * Prior to 0.9.0 the SOURCE, CLEAR and a number of other operators + behaved in an inconsistent and buggy fashion and could affect areas + outside the clip mask. In 0.9.0, these six "unbounded" operators + were fixed to consistently clear areas outside the shape but within + the clip mask. This is useful behavior for an operator such as IN, + but not what was expected for SOURCE and CLEAR. So, in this release + the behavior of SOURCE and CLEAR has been changed again. They now + affect areas only within both the source and shape. We can write + the new operators as: + + SOURCE: dest' = (mask IN clip) ? source : dest + CLEAR: dest' = (mask IN clip) ? 0 : dest + +Behavior and API changes +------------------------ + * Setting the filter on a gradient pattern would change the + interpolation between color stops away from the normal linear + interpolation. This dubious behavior has been removed. + + * The CAIRO_CONTENT_VALID() and CAIRO_FORMAT_VALID() macros -- + implementation details that leaked into cairo.h -- have been moved + into an internal header. + + * The cairo_show_text function now advances the current point + according to the total advance values of the string. + +API additions +------------- + * cairo_set_dash can now detect error and can set + CAIRO_STATUS_INVALID_DASH. + +Features +-------- + * When compiled against recent versions of fontconfig and FreeType, + artificial bold fonts can now be turned on from fonts.conf using + the FC_EMBOLDEN fontconfig key. + +Optimization +------------ + * The compositing code from the 'xserver' code tree has now been + completely merged into libpixman. This includes MMX optimization of + common operations. + + * The image transformation code in libpixman has been improved and + now performs significantly faster. + +Bug fixes +--------- + * Several crashes related to corruption in the font caches have been + fixed. + + * All test cases now match pixel-for-pixel on x86 and PPC; this + required fixing bugs in the compositing, stroking, and pattern + rendering code. + + * Negative dash offsets have been fixed to work correctly. + + * The stroking of paths with multiple subpaths has now been fixed to + apply caps to all subpaths rather than just the last one. + + * Many build fixes for better portability on various systems. + + * Lots of other bug fixes, but we're too tired to describe them in + more detail here. + +Release 0.9.2 (2005-08-13 Carl Worth ) +========================================================= +Release numbering +----------------- + * You will notice that this release jumped from 0.9.0 to 0.9.2. We've + decided to use an odd micro version number (eg. 0.9.1) to indicate + in-progress development between releases. As soon as 0.9.2 is + tagged, the version will be incremented in CVS to 0.9.3 where it + will stay until just before 0.9.4 is built, uploaded, and tagged. + + So, even-micro == a released version, odd-micro == something in-between. + +Libpixman dependency dropped +---------------------------- + * As of this release, the dependency on an external libpixman has + been dropped. Instead, the code from libpixman needed for cairo has + been incorporated into the cairo source tree. The motivation for + this change is that while cairo's API is stable and ready to be + maintained after the 1.0 release, libpixman's API is not, so we do + not want to expose it at this time. + + Also, the incorporation of libpixman into cairo also renames all + previously-public libpixman symbols in order to avoid any conflict + with a future release of libpixman + +API additions +------------- + * Macros and functions have been added so that the version of cairo + can be queried at either compile-time or at run-time. The version + is made available as both a human-readable string and as a single + integer: + + CAIRO_VERSION_STRING eg. "0.9.2" + CAIRO_VERSION eg. 000902 + + const char* + cairo_version_string (void); /* eg. "0.9.2" */ + + int + cairo_version (void); /* eg. 000902 */ + + A macro is provided to convert a three-part component version into + the encoded single-integer form: + + CAIRO_VERSION_ENCODE(X,Y,Z) + + For example, the CAIRO_VERSION value of 000902 is obtained as + CAIRO_VERSION_ENCODE(0,9,2). The intent is to make version + comparisons easy, either at compile-time: + + #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(0,9,2) + ... + #endif + + Or at run-time: + + if (cairo_version() >= CAIRO_VERSION_ENCODE(0,9,2)) { /* ... */ } + +Thread safety +------------- + * This release adds pthread-based locking (when available) to make + the caches used by cairo safe for threaded programs. Some may + remember a failed experiment with this locking between the 0.5.1 + and 0.5.2 snapshots, (where even single-threaded programs that + linked with -lpthread would deadlock). We believe that that problem + has been fixed, so we are looking forward to testing and reports + from users with threaded applications. + +Bug fixes +--------- + * The XCB and Quartz backends failed to compiled in the 0.9.0 release + due to minor syntax errors. These have now been fixed. + + * Various crashes in glitz and pixman due to size 0 glyphs have been + fixed. + +Release 0.9.0 (2005-08-08 Carl Worth ) +========================================================= +Soname change +------------- + * In all prior snapshots, the libtool library versioning was set to + 1:0:0. As this release is intended to mark the beginning of + backwards-compatible releases, the versioning has been incremented + to 2:0:0. You will notice that the numeric extension on the + installed library filename will change similarly. + + This change will also require all cairo-using applications to be + recompiled. We recognize that this may cause some frustration since + this release is backwards-compatible with 0.6.0 and in that sense + "shouldn't" require re-compilation. However, since all historical + snapshots have used the same 1:0:0 version in spite of incompatible + API changes between them, it was essential that the upcoming 1.0 + release series have distinct library versioning. + + All future releases will use the library versioning to properly + indicate compatibility between releases. So, any application + re-compiled now to work with the 0.9.0 will not need to be + recompiled when a compatible 1.0 release of cairo is made in the + future. + +API additions +------------- + * Add new function calls to set/get the current antialiasing mode in + the graphics state: + + cairo_set_antialias + cairo_get_antialias + + This call accepts the same modes recently added for font options + (NONE or GRAY) but affects the rendering of geometry other than + text. The intent of this call is to enable more precise control of + which pixels are affected by each operation, for example to allow + for full-scene antialiasing for seam-free rendering. It is not + expected that non-antialiased rendering will perform better than + anti-aliased rendering. + + * Three new functions were added to provide support for mixed cairo- + and non-cairo drawing to the same surface: + + cairo_surface_mark_dirty + cairo_surface_mark_dirty_rectangle + cairo_surface_flush + + * The return type of the several "reference" functions was change, + (API compatibly), from void to the same type as the argument. The + affected functions are: + + cairo_font_face_reference + cairo_scaled_font_reference + cairo_pattern_reference + cairo_surface_reference + cairo_reference + + This allows a convenient way to assign and reference in a single + statement. + +Semantic changes +---------------- + * The behavior of cairo_set_source with a pattern with a non-identity + matrix was previously not well-defined. The new behavior is as + follows: + + The pattern's transformation matrix will be locked to the + user space in effect at the time of cairo_set_source(). This means + that further modifications of the CTM will not affect the source + pattern. + +cairo-win32 +----------- + * Some portability improvements, (eg. workaround for missing stdint.h). + +cairo-ft +-------- + * Updated to allow compilation with older versions of freetype. + +Bug fixes +--------- + * Fix the unbounded operators to actually produce a correct result, + (previously the results were artificially restricted to the + bounding box of whatever shape was being drawn rather than + extending out infinitely). The fixed operators are: + + CAIRO_OPERATOR_CLEAR + CAIRO_OPERATOR_SOURCE + CAIRO_OPERATOR_OUT + CAIRO_OPERATOR_IN + CAIRO_OPERATOR_DEST_IN + CAIRO_OPERATOR_DEST_ATOP + + * Fix cairo_mask and cairo_mask_surface to transform the mask by the + current transformation matrix (CTM). + + * Fix cairo_set_source to lock the CTM used to transform the pattern. + + * Workaround for X server Render bug involving repeating patterns + with a general transformation matrix. + + * cairo_get_font_face fixed to return a "nil" font face object rather + than NULL on error. + + * cairo_set_font_face fixed to not crash if given a NULL font face, + (which is the documented interface for restoring the default font + face). + + * Fix xlib glyphset caching to not try to free a NULL glyph. + +Snapshot 0.6.0 (2005-07-28 Carl Worth ) +========================================================== +API changes +----------- +* The prototypes of the following functions have changed: + + cairo_xlib_surface_create_with_xrender_format + cairo_xlib_surface_create_for_bitmap + + A Screen* parameter has been added to each. This allows the cairo + xlib backend to work correctly with multi-head X servers. + +* The following function has been modified: + + cairo_scaled_font_create + + to accept a cairo_font_options_t*. See below fore more details. + +* All opaque, reference-counted cairo objects have now been moved to a + standard error-handling scheme. The new objects to receive this + treatment are cairo_font_face_t, cairo_scaled_font_t, and + cairo_surface_t. (Previous snapshots already provided this scheme + for cairo_t, cairo_path_t, and cairo_pattern_t.) + + This changes two functions to have a return type of void rather than + cairo_status_t: + + cairo_scaled_font_extent + cairo_surface_finish + + And significantly, none of the create functions for any of the + objects listed above will return NULL. The pointer returned from any + function will now always be a valid pointer and should always be + passed to the corresponding destroy function when finished + + The simplest strategy for porting code is to switch from: + + object = cairo__create (); + if (object == NULL) + goto BAILOUT; + + /* act on object */ + + cairo__destroy (object); + + to: + + object = cairo__create (); + if (cairo__status (object)) + goto BAILOUT; + + /* act on object */ + + cairo__destroy (object); + + But significantly, it is not required to check for an error status + before the "act on object" portions of the code above. All + operations on an object with an error status are, by definition, + no-ops without side effect. So new code might be written in an + easier-to-read style of: + + object = cairo__create (); + + /* act on object */ + + cairo__destroy (object); + + with cairo__status checks placed only at strategic + locations. For example, passing an error object to another object, + (eg. cairo_set_source with an in-error pattern), will propagate the + error to the subsequent object (eg. the cairo_t). This means that + error checking can often be deferred even beyond the destruction of + a temporary object. + +API additions +------------- +* New functions for checking the status of objects that have been + switched to the common error-handling scheme: + + cairo_font_face_status + cairo_scaled_font_status + cairo_surface_status + +* The _cairo_error function which was added in 0.5.1 has now been made + much more useful. In 0.5.1 only errors on cairo_t objects passed + through _cairo_error. Now, an error on any object should pass + through _cairo_error making it much more reliable as a debugging + mechanism for finding when an error first occurs. + +* Added new font options support with a myriad of functions: + + cairo_font_options_create + cairo_font_options_copy + cairo_font_options_destroy + + cairo_font_options_status + + cairo_font_options_merge + cairo_font_options_equal + cairo_font_options_hash + + cairo_font_options_set_antialias + cairo_font_options_get_antialias + cairo_font_options_set_subpixel_order + cairo_font_options_get_subpixel_order + cairo_font_options_set_hint_style + cairo_font_options_get_hint_style + cairo_font_options_set_hint_metrics + cairo_font_options_get_hint_metrics + + cairo_surface_get_font_options + + cairo_ft_font_options_substitute + + cairo_set_font_options + cairo_get_font_options + + This new font options support allows the application to have much + more fine-grained control over how fonts are rendered. + Significantly, it also allows surface backends to have some + influence over the process. For example, the xlib backend now + queries existing Xft properties to set font option defaults. + +* New function: + + cairo_xlib_surface_set_drawable + + which allows the target drawable for an xlib cairo_surface_t to be + changed to another with the same format, screen, and display. This + is necessary in certain double-buffering techniques. + +New features +------------ +* Sub-pixel text antialiasing is now supported. + +Bug fixes +--------- +* Fixed assertion failure in cairo_surface_create_similar when + application commits an error by passing a cairo_format_t rather than + a cairo_content_t. + +* Avoid division by zero in various places (cairo-ft). + +* Fix infinite loop when using non-default visuals (cairo-xlib). + +* Eliminate segfault in cairo_image_surface_create_from_png_stream. + +* Prevent errant sign-extension of masks on 64-bit architectures + (cairo-xlib and cairo-xcb). + +* Other miscellaneous fixes. + +Snapshot 0.5.2 (2005-07-18 Carl Worth ) +========================================================== +API changes +----------- +* New functions for creating patterns of a single color: + + cairo_pattern_create_rgb + cairo_pattern_create_rgba + +* Change cairo_surface_create_similar to accept a new type of + cairo_content_t rather than cairo_format_t: + + typedef enum _cairo_content { + CAIRO_CONTENT_COLOR = 0x1000, + CAIRO_CONTENT_ALPHA = 0x2000, + CAIRO_CONTENT_COLOR_ALPHA = 0x3000 + } cairo_content_t; + +* Add new CAIRO_FORMAT_VALID and CAIRO_CONTENT_VALID macros. + +* Remove unused status value: + + CAIRO_STATUS_NO_TARGET_SURFACE + +* Add new status values: + + CAIRO_STATUS_INVALID_STATUS + +* Require libpixman >= 0.1.5 (for necessary bug fixes) + +Bug fixes +--------- +* Fix cairo_surface_write_to_png for RGB24 images. + +* Fix broken metrics and rendering for bitmap fonts. Add mostly + useless bitmap glyph transformation. + +* Fix glyph caches to not eject entries that might be immediately + needed, (fixing intermittent crashes when rendering text). + +* Fix all memory leaks found by running "make check-valgrind". + +ATSUI backend changes +--------------------- +* Allow building against < 10.3 SDK. + +* Prevent crash on empty strings. + +Glitz backend changes +--------------------- +* Require glitz >= 0.4.4. + +* Use frame buffer objects instead of pbuffers for accelerated + offscreen drawing. + +* Minor improvement to gradient pattern creation. + +PostScript backend fixes +------------------------ +* Rewrite of the PS backend to generate more interesting output that + the old big-image implementation. + +Win32 backend fixes +------------------- +* Implement glyph path support. + +* Fix swap of blue and green values in the fill_rectangles path. + +Xlib backend fixes +------------------ +* Add optimization to use XCopyArea rather than XRenderComposite when + transforming only with an integer translation, and using SOURCE + operator or OVER with a source pattern without alpha. + +Snapshot 0.5.1 (2005-06-20 Carl Worth ) +========================================================== +API changes +----------- +* Removed cairo_status_string(cairo_t*) and add + cairo_status_to_string(cairo_status_t) in its place. Code using + cairo_status_string can be ported forward as follows: + + cairo_status (cr); + -> + cairo_status_to_string (cairo_status (cr)); + +* Removed the BAD_NESTING restriction which means that two different + cairo_t objects can now interleave drawing to the same + cairo_surface_t without causing an error. + +* The following functions which previously had a return type of + cairo_status_t now have a return type of void: + + cairo_pattern_add_color_stop_rgba + cairo_pattern_set_matrix + cairo_pattern_get_matrix + cairo_pattern_set_extend + cairo_pattern_set_filter + + See discussion of cairo_pattern_status below for more details. + +API additions +------------- +* Improved error handling: + + cairo_status_t + cairo_pattern_status (cairo_pattern_t *pattern); + + This snapshot expands the status-based error handling scheme from + cairo_t to cairo_path_t and cairo_pattern_t. It also expands the + scheme so that object-creating functions, (cairo_create, + cairo_pattern_create_*, cairo_copy_path_*), are now guaranteed to + not return NULL. Instead, in the case of out-of-memory these + functions will return a static object with + status==CAIRO_STATUS_NO_MEMORY. The status can be checked with the + functions cairo_status and cairo_pattern_status, or by direct + inspection of the new status field in cairo_path_t. + + Please note that some objects, including cairo_surface_t and all of + the font-related objects have not been converted to this + error-handling scheme. + +* In addition to the above changes, a new private function has been added: + + _cairo_error + + This function can be used to set a breakpoint in a debugger to make + it easier to find programming error in cairo-using code. (Currently, + _cairo_error is called when any error is detected within a cairo_t + context, but is not called for non-cairo_t errors such as for + cairo_path_t and cairo_pattern_t). + +* Fixed cairo_path_data_t so that its enum is visible to C++ code, (as + cairo_path_data_type_t). + +Performance improvements +------------------------ +* Made a minor performance improvement for clipping, (restrict clip + surface to the new intersected bounds). + +* Optimize rendering of a solid source pattern with a pixel-aligned + rectangular path to use backend clipping rather than rasterization + and backend compositing. + +* Optimize cairo_paint_with_alpha to defer to cairo_paint when alpha + is 1.0. + +Bug fixes +--------- +* Fixed memory leak in cairo_copy_path. + +* A build fix for non-srcdir builds. + +PDF backend fixes +----------------- +* New support for path-based clipping. + +* Fix for text rotated to angles other than multiples of π/2. + +Win32 backend fixes +------------------- +* Fix for text extents. + +Xlib backend +------------ +* Implemented a complex workaround for X server bug[*] related to + Render-based compositing with untransformed, repeating source + pictures. The workaround uses core Xlib when possible for + performance, (ie. with CAIRO_OPERATOR_SOURCE or CAIRO_OPERATOR_OVER + with an opaque source surface), and falls back to the pixman + image-based compositing otherwise. + + [*] https://bugs.freedesktop.org/show_bug.cgi?id=3566 + +* Various bug fixes, particularly in the fallback paths. + +Snapshot 0.5.0 (2005-05-17 Carl Worth ) +========================================================== +This is a pretty big, and fairly significant snapshot. It represents +between 2 and 3 months of solid work from a lot of people on improving +the API as much as possible. I'd like to express my appreciation and +congratulations to everyone who has worked on the big API Shakeup, +(whether in email battles over names, or fixing my silly bugs). + +This snapshot will require some effort on the part of users, since +there are a _lot_ of API changes (ie. no cairo program ever written is +safe --- they're all broken now in at least one way). But, in spite of +that, we do encourage everyone to move their code to this snapshot as +soon as possible. And we're doing everything we can think of to make +the transition as smooth as possible. + +The idea behind 0.5 is that we've tried to make every good API change +we could want now, and get them all done with. That is, between now +and the 1.0 release of cairo, we expect very few new API changes, +(though some will certainly sneak in). We will have some significant +additions, but the pain of moving code from cairo 0.4 to cairo 0.5 +should be a one time experience, and things should be much smoother as +we continue to move toward cairo 1.0. + +And with so many changes coming out for the first time in this 0.5 +release, we really do need a lot of people trying this out to make +sure the ideas are solid before we freeze the API in preparation for +the 1.0 release. + +OK, enough introduction. Here is a (not-quite-complete) description of +the API removals, changes and additions in this snapshot, (compared to +0.4.0) + +API removals +============ +The following public functions have been removed: + +- cairo_set_target_* + + This is a big change. See the description of cairo_create in + the API changes section for how to deal with this. + +- cairo_set_alpha + + Alpha blending hasn't gone away; there's just a much more + unified rendering model now. Almost all uses of + cairo_set_alpha will be trivially replaced with + cairo_set_source_rgba and a few others will be replaced just + as easily with cairo_paint_with_alpha. + +- cairo_show_surface + + Another useful function that we realized was muddling up the + rendering model. The replacement is quite easy: + cairo_set_source_surface and cairo_paint. + +- cairo_matrix_create +- cairo_matrix_destroy +- cairo_matrix_copy +- cairo_matrix_get_affine + + These functions supported an opaque cairo_matrix_t. We now + have an exposed cairo_matrix_t structure, so these can be + dropped. + +- cairo_surface_set_repeat +- cairo_surface_set_matrix +- cairo_surface_set_filter + + These properties don't belong on surfaces. If you were using + them, you'll just want to instead use + cairo_pattern_create_for_surface and then set these properties + on the pattern. + +- cairo_copy + + This was a confusing function and hopefully nobody will miss + it. But if you really don't find cairo_save/restore adequate, + let us know and we have another idea for a potential + replacement. + +And while we're on the subject of removals, we carefully tightened up +the cairo header files so they no longer gratuitously include header +files that are not strictly necessary, (stdio.h, stdint.h, pixman.h, +Xrender.h, etc. and their dependencies). This may lead to some +surprising errors, so keep your eyes open for that. + +API changes +=========== +Here are some of the API changes that have occurred: + +~ cairo_create(void) -> cairo_create(cairo_surface_t *) + + This is the big change that breaks every program. The ability + to re-target a cairo_t was not particularly useful, but it did + introduce a lot of muddy semantic questions. To eliminate + that, cairo_create now requires its target surface to be + passed in at creation time. This isn't too hard to cope with + as the typical first operation after cairo_create was often + cairo_set_target_foo. So the order of those two swap and the + application instead has cairo_foo_surface_create, then + cairo_create. + +~ cairo_current_* -> cairo_get_* + + We had a strange mixture of cairo_get and cairo_current + functions. They've all been standardized on cairo_get, (though + note one is cairo_get_current_point). + +~ CAIRO_OPERATOR_SRC -> CAIRO_OPERATOR_SOURCE +~ CAIRO_OPERATOR_OVER_REVERSE -> CAIRO_OPERATOR_DEST_OVER + + Many of the cairo_operator_t symbolic values were renamed to + reduce the amount of abbreviation. The confusing "OP_REVERSE" + naming was also changed to use "DEST_OP" instead which is + easier to read and has wider acceptance in other + libraries/languages. + +~ cairo_set_pattern -> cairo_set_source +~ cairo_set_rgb_color -> cairo_set_source_rgb + + All of the various functions that changed the source + color/pattern were unified to use cairo_set_source names to + make the relation more clear. + +~ cairo_transform_point -> cairo_user_to_device +~ cairo_transform_distance -> cairo_user_to_device_distance +~ cairo_inverse_transform_point -> cairo_device_to_user +~ cairo_inverse_transform_distance -> cairo_device_to_user_distance + + These names just seemed a lot more clear. + +~ cairo_init_clip -> cairo_reset_clip +~ cairo_concat_matrix -> cairo_transform + + More abbreviation elimination + +~ cairo_current_path -> cairo_copy_path +~ cairo_current_path_flat -> cairo_copy_path_flat + + The former mechanism for examining the current path was a + function that required 3 or 4 callbacks. This was more + complexity than warranted in most situations. The new + cairo_copy_path function copies the current path into an + exposed data structure, and the documentation provides a + convenient idiom for navigating the path data. + +API additions +------------- ++ cairo_paint + + A generalized version of the painting operators cairo_stroke + and cairo_fill. The cairo_paint call applies the source paint + everywhere within the current clip region. Very useful for + clearing a surface to a solid color, or painting an image, + (see cairo_set_source_surface). + ++ cairo_paint_with_alpha + + Like cairo_paint but applying some alpha to the source, + (making the source paint translucent, eg. to blend an image on + top of another). + ++ cairo_mask + + A more generalized version of cairo_paint_with_alpha which + allows a pattern to specify the amount of translucence at each + point rather than using a constant value everywhere. + ++ cairo_mask_surface + + A convenience function on cairo_mask for when the mask pattern + is already contained within a surface. + ++ cairo_surface_set_user_data ++ cairo_surface_get_user_data ++ cairo_font_face_set_user_data ++ cairo_font_face_get_user_data + + Associate arbitrary data with a surface or font face for later + retrieval. Get notified when a surface or font face object is + destroyed. + ++ cairo_surface_finish + + Allows the user to instruct cairo to finish all of its + operations for a given surface. This provides a safe point for + doing things such as flushing and closing files that the + surface may have had open for writing. + ++ cairo_fill_preserve ++ cairo_stroke_preserve ++ cairo_clip_preserve + + One interesting change in cairo is that the path is no longer + part of the graphics state managed by + cairo_save/restore. This allows functions to construct paths + without interfering with the graphics state. But it prevents + the traditional idiom for fill-and-stroke: + + cairo_save; cairo_fill; cairo_restore; cairo_stroke + + Instead we know have alternate versions cairo cairo_fill, + cairo_stroke, and cairo_clip that preserve the current path + rather than consuming it. So the idiom now becomes simply: + + cairo_fill_preserve; cairo_stroke + ++ cairo_surface_write_to_png ++ cairo_surface_write_to_png_stream + + In place of a single PNG backend, now a surface created + through any backend (except PDF currently) can be written out + to a PNG image. + ++ cairo_image_surface_create_from_png ++ cairo_image_surface_create_from_png_stream + + And its just as easy to load a PNG image into a surface as well. + ++ cairo_append_path + + With the new, exposed path data structure, it's now possible + to append bulk path data to the current path, (rather than + issuing a long sequence of cairo_move_to/line_to/curve_to + function calls). + +Xlib and XCB backends +--------------------- + +Any cairo_format_t and Colormap arguments have been dropped from +cairo_xlib_surface_create. There are also two new +cairo_xlib|xcb_surface_create functions: + + cairo_xlib|xcb_surface_create_for_bitmap + (Particular for creating A1 surfaces) + cairo_xlib|xcb_surface_create_with_xrender_format + (For any other surface types, not described by a Visual*) + +All of these surface create functions now accept width and height. In +addition, there are new cairo_xlib|xcb_surface_set_size functions +which must be called each time a window that is underlying a surface +changes size. + +Print backends (PS and PDF) +--------------------------- +The old FILE* based interfaces have been eliminated. In their place we +have two different functions. One accepts a simple const char +*filename. The other is a more general function which accepts a +callback write function and a void* closure. This should allow the +flexibility needed to hook up with various stream object in many +languages. + +In addition, when specifying the surface size during construction, the +units are now device-space units (ie. points) rather than inches. This +provides consistency with all the other surface types and also makes +it much easier to reason about the size of the surface when drawing to +it with the default identity matrix. + +Finally, the DPI parameters, which are only needed to control the +quality of fallbacks, have been made optional. Nothing is required +during surface_create (300 DPI is assumed) and +cairo_ps|pdf_surface_set_dpi can be used to set alternate values if +needed. + +Font system +----------- +Owen very graciously listened to feedback after the big font rework he +had done for 0.4, and came up with way to improve it even more. In 0.4 +there was a cairo_font_t that was always pre-scaled. Now, there is an +unscaled cairo_font_face_t which is easier to construct, (eg. no +scaling matrix required) and work with, (it can be scaled and +transformed after being set on the graphics state). And the font size +manipulation functions are much easier. You can set an explicit size +and read/modify/write the font matrix with: + + cairo_set_font_size + cairo_get_font_matrix + cairo_set_font_matrix + +(Previously you could only multiply in a scale factor or a matrix.) A +pleasant side effect is that we can (and do) now have a default font +size that is reasonable, as opposed to the old default height of one +device-space unit which was useless until scaled. + +Of course, the old pre-scaled font had allowed some performance +benefits when getting many metrics for a font. Those benefits are +still made available through the new cairo_scaled_font_t. And a +cairo_font_face_t can be "promoted" to a cairo_scaled_font_t by +suppling a font_matrix and the desired CTM. + +Quartz backend +-------------- +Tim Rowley put in the work to bring the Quartz backend back after it +had been disabled in the 0.4.0 snapshot. He was not able to bring back +the function that allows one to create a cairo_font_t from an ATSUI +style: + + cairo_font_t * + cairo_atsui_font_create (ATSUStyle style); + +because he didn't have a test case for it. If you care about this +function, please provide a fairly minimal test and we'll try to bring +it back in an upcoming snapshot. + +Snapshot 0.4.0 (2005-03-08 Carl Worth ) +========================================================== +New documentation +----------------- +Owen Taylor has converted cairo's documentation system to gtk-doc and +has begun some long-needed work on the documentation, which can now be +viewed online here: + + https://cairographics.org/manual/ + +New backend: win32 +------------------ +This is the first snapshot to include a functional win32 backend, +(thanks to Owen Taylor). The interface is as follows: + + #include + + void + cairo_set_target_win32 (cairo_t *cr, + HDC hdc); + + cairo_surface_t * + cairo_win32_surface_create (HDC hdc); + + cairo_font_t * + cairo_win32_font_create_for_logfontw (LOGFONTW *logfont, + cairo_matrix_t *scale); + + cairo_status_t + cairo_win32_font_select_font (cairo_font_t *font, + HDC hdc); + + void + cairo_win32_font_done_font (cairo_font_t *font); + + double + cairo_win32_font_get_scale_factor (cairo_font_t *font); + +And see also the documentation at: + +https://cairographics.org/manual/cairo-Microsoft-Windows-Backend.html + +Disabled backend: quartz +------------------------ +Unfortunately, the quartz backend code is currently out of date with +respect to some recent backend interface changes. So, the quartz +backend is disabled in this snapshot. + +If the quartz backend is brought up-to-date before the next snapshot, +we would be glad to make a 0.4.1 snapshot that re-enables it, (we do +not expect many more big backend interface changes). + +API Changes +----------- +The font system has been revamped, (as Owen Taylor's work with +integrating pango and cairo gave us the first serious usage of the +non-toy font API). + +One fundamental, user-visible change is that the cairo_font_t object +now represents a font that is scaled to a particular device +resolution. Further changes are described below. + + cairo.h + ------- + Removed cairo_font_set_transform and cairo_font_current_transform. + + Added cairo_font_extents and cairo_font_glyph_extents. See + documentation for details: + + https://cairographics.org/manual/cairo-cairo-t.html#cairo-font-extents + + cairo-ft.h + ---------- + The cairo_ft_font API changed considerably. Please see the + documentation for details: + + https://cairographics.org/manual/cairo-FreeType-Fonts.html + +Performance +----------- +Make the fast-path clipping (pixel-aligned rectangles) faster. + +Add optimization for applying a constant alpha to a pattern. + +Optimize gradients that are horizontal or vertical in device space. + +Xlib: When RENDER is not available, use image surfaces for +intermediate surfaces rather than xlib surfaces. + +Backend-specific changes +------------------------ + Glitz + ----- + Major update to glitz backend. The output quality should now be just + as good as the image and xlib backends. + + Track changes to glitz 0.4.0. + + PDF + --- + Various improvements to produce more conformant output. + +Internals +--------- +David Reveman contributed a large re-work of the cairo_pattern_t +implementation, providing cleaner code and more optimization +opportunities. + + Backend interface changes + ------------------------- + Rework backend interface to accept patterns, not surfaces for source + and mask. + + Remove set_matrix, set_filter, and set_repeat functions. + + More sophisticated backend interface for image fallbacks, + ({acquire,release}_{source,dest}_image() and clone_similar). + +Bug fixes +--------- +Only install header files for backends that have been compiled. + +Fixed some rounding errors leading to incorrectly placed glyphs. + +Many other minor fixes. + +Snapshot 0.3.0 (2005-01-21 Carl Worth ) +========================================================== +Major API changes +----------------- +1) The public header files will no longer be directly installed into + the system include directory. They will now be installed in a + subdirectory named "cairo", (eg. in /usr/include/cairo rather than + in /usr/include). + + As always, the easiest way for applications to discover the + location of the header file is to let pkg-config generate the + necessary -I CFLAGS and -L/-l LDFLAGS. For example: + + cc `pkg-config --cflags --libs cairo` -o foo foo.c + + IMPORTANT: Users with old versions of cairo installed will need to + manually remove cairo.h and cairo-features.h from the + system include directories in order to prevent the old + headers from being used in preference to the new ones. + +2) The backend-specific portions of the old monolithic cairo.h have + been split out into individual public header files. The new files + are: + + cairo-atsui.h + cairo-ft.h + cairo-glitz.h + cairo-pdf.h + cairo-png.h + cairo-ps.h + cairo-quartz.h + cairo-xcb.h + cairo-xlib.h + + Applications will need to be modified to explicitly include the new + header files where appropriate. + +3) There are two new graphics backends in this snapshot, a PDF + backend, and a Quartz backend. There is also one new font backend, + ATSUI. + +PDF backend +----------- +Kristian Høgsberg has contributed a new backend to allow cairo-based +applications to generate PDF output. The interface for creating a PDF +surface is similar to that of the PS backend, as can be seen in +cairo-pdf.h: + + void + cairo_set_target_pdf (cairo_t *cr, + FILE *file, + double width_inches, + double height_inches, + double x_pixels_per_inch, + double y_pixels_per_inch); + + cairo_surface_t * + cairo_pdf_surface_create (FILE *file, + double width_inches, + double height_inches, + double x_pixels_per_inch, + double y_pixels_per_inch); + +Once a PDF surface has been created, applications can draw to it as +any other cairo surface. + +This code is still a bit rough around the edges, and does not yet +support clipping, surface patterns, or transparent gradients. Text +only works with TrueType fonts at this point and only black text is +supported. Also, the size of the generated PDF files is currently +quite big. + +Kristian is still actively developing this backend, so watch this +space for future progress. + +Quartz backend +-------------- +Calum Robinson has contributed a new backend to allow cairo +applications to target native Mac OS X windows through the Quartz +API. Geoff Norton integrated this backend into the current +configure-based build system, while Calum also provided Xcode build +support in the separate "macosx" module available in CVS. + +The new interface, available in cairo-quartz.h, is as follows: + + void + cairo_set_target_quartz_context (cairo_t *cr, + CGContextRef context, + int width, + int height); + + cairo_surface_t * + cairo_quartz_surface_create (CGContextRef context, + int width, + int height); + +There is an example program available in CVS in cairo-demo/quartz. It +is a port of Keith Packard's fdclock program originally written for +the xlib backend. A screenshot of this program running on Mac OS X is +available here: + + https://cairographics.org/~cworth/images/fdclock-quartz.png + +ATSUI font backend +------------------ +This new font backend complements the Quartz backend by allowing +applications to use native font selection on Mac OS X. The interface +is a single new function: + + cairo_font_t * + cairo_atsui_font_create (ATSUStyle style); + +Minor API changes +----------------- +Prototype for non-existent function "cairo_ft_font_destroy" removed. + +Now depends on libpixman 0.1.2 or newer, (0.1.3 is being released +concurrently and has some useful performance improvements). + +Default paint color is now opaque black, (was opaque white). Default +background color is transparent (as before). + +Renamed "struct cairo" to "struct _cairo" to free up the word "cairo" +from the C++ identifier name space. + +Functions returning multiple return values through provided pointers, +(cairo_matrix_get_affine, cairo_current_point, and +cairo_current_color_rgb), will now accept NULL for values the user +wants to ignore. + +CAIRO_HAS_FREETYPE_FONT has now been renamed to CAIRO_HAS_FT_FONT. + +Performance improvements +------------------------ +Alexander Larsson provided some fantastic performance improvements +yielding a 10000% performance improvement in his application, (when +also including his performance work in libpixman-0.1.3). These include + + * Fixed handling of cache misses. + + * Creating intermediate clip surfaces at the minimal size required. + + * Eliminating roundtrips when creating intermediate Xlib surfaces. + +Implementation +-------------- +Major re-work of font metrics system by Keith Packard. Font metrics +should now be much more reliable. + +Glitz backend +------------- +Updated for glitz-0.3.0. +Bug fixes in reference counting. + +Test suite +---------- +New tests for cache crashing, rotating text, improper filling of +complex polygons, and leaky rasterization. + +Bug fixes +--------- +Fixed assertion failure when selecting the same font multiple times in +sequence. + +Fixed reference counting so cache_destroy functions work. + +Remove unintended copyright statement from files generated with +PostScript backend. + +Fixed to eliminate new warnings from gcc 3.4 and gcc 4. + +Snapshot 0.2.0 (2004-10-27 Carl Worth ) +=========================================================== +New license: LGPL/MPL +--------------------- +The most significant news with this release is that the license of +cairo has changed. It is now dual-licensed under the LGPL and the +MPL. For details see the COPYING file as well as COPYING-LGPL-2.1 and +COPYING-MPL-1.1. + +I express my thanks to everyone involved in the license change process +for their patience and support! + +New font and glyph internals +---------------------------- +Graydon Hoare has put a tremendous amount of work into new internals +for handling fonts and glyphs, including caches where appropriate. +This work has no impact on the user-level API, but should result in +great performance improvements for applications using text. + +New test suite +-------------- +This snapshot of cairo includes a (small) test suite in +cairo/test. The tests can be run with "make check". The test suite was +designed to make it very easy to add new tests, and we hope to see +many contributions here. As you find bugs, please try adding a minimal +test case to the suite, and submit it with the bug report to the +cairo@cairographics.org mailing list. This will make it much easier +for us to track progress in fixing bugs. + +New name for glitz backend +-------------------------- +The gl backend has now been renamed to the glitz backend. This means +that the following names have changed: + + CAIRO_HAS_GL_SURFACE -> CAIRO_HAS_GLITZ_SURFACE + cairo_set_target_gl -> cairo_set_target_glitz + cairo_gl_surface_create -> cairo_glitz_surface_create + +This change obviously breaks backwards compatibility for applications +using the old gl backend. + +Up-to-date with latest glitz snapshots +-------------------------------------- +This snapshot of cairo is now up to date with the latest glitz +snapshot, (currently 0.2.3). We know that the latest cairo and glitz +snapshots have been incompatible for a very long time. We've finally +fixed that now and we're determined to not let that happen again. + +Revert some tessellation regression bugs +---------------------------------------- +People that have been seeing some tessellation bugs, (eg. leaked +fills), in the CVS version of cairo may have better luck with this +release. A change since the last snapshot was identified to trigger +some of these bugs and was reverted before making the snapshot. The +behavior should be the same as the previous (0.1.23) snapshot. + +Miscellaneous changes +--------------------- +Changed CAIRO_FILTER_DEFAULT to CAIRO_FILTER_BEST to make gradients +easier. + +Track XCB API change regarding iterators. + +Various bug fixes +----------------- +Fix calculation of required number of vertices for pen. + +Fix to avoid zero-dimensioned pixmaps. + +Fix broken sort of pen vertices. + +Fix bug when cairo_show_text called with a NULL string. + +Fix clipping bugs. + +Fix bug in computing image length with XCB. + +Fix infinite loop bug in cairo_arc. + +Fix memory management interactions with libpixman. + +Snapshot 0.1.23 (2004-05-11 Carl Worth ) +======================================================== +Fixes for gcc 3.4 +----------------- +Fix prototype mismatches so that cairo can be built by gcc 3.4. + +Updates to track glitz +---------------------- +Various fixes to support the latest glitz snapshot (0.1.2). + +Gradient updates +---------------- +Radial gradients now support both inner and outer circles. +Transformed linear gradients are now properly handled. +Fixes for extend type reflect. + +Glitz updates +------------- +Converted shading routines to use fixed point values and introduced a +shading operator structure for more efficient shading calculations. +Support compositing with mask surface when mask is solid or +multi-texturing is available. + +PNG backend cleanups +-------------------- +Fix output to properly compensate for pre-multiplied alpha format in cairo. +Add support for A8 and A1 image formats. + +Bug fixes +--------- +Avoid crash or infinite loop on null strings and degeneratively short +splines. + +New? bugs in cairo_clip +----------------------- +There are some fairly serious bugs in cairo_clip. It is sometimes +causing an incorrect result. And even when it does work, it is +sometimes so slow as to be unusable. Some of these bugs may not be +new, (indeed cairo_clip has only ever had a braindead-slow +implementation), but I think they're worth mentioning here. + +Snapshot 0.1.22 (2004-04-16 Carl Worth ) +======================================================== +Cairo was updated to track the changes in libpixman, and now depends +on libpixman version 0.1.1. + +Snapshot 0.1.21 (2004-04-09 David Reveman ) +============================================================= +New OpenGL backend +------------------ +The OpenGL backend provides hardware accelerated output for +X11 and OS X. The significant new functions are: + + cairo_set_target_gl + cairo_gl_surface_create + +Automatic detection of available backends +----------------------------------------- +The configure script now automatically detect what backends are +available, (use ./configure --disable-`backend' to prevent +compilation of specific backends). + +Snapshot 0.1.20 (2004-04-06 Carl Worth ) +======================================================== +New pattern API +--------------- +David Reveman has contributed a new pattern API which enable linear +and radial gradient patterns in addition to the original surface-based +patterns. The significant new top-level functions are: + + cairo_pattern_create_linear + cairo_pattern_create_radial + cairo_pattern_create_for_surface + cairo_pattern_add_color_stop + cairo_set_pattern + +Any code using the old cairo_set_pattern, (which accepted a +cairo_surface_t rather than a cairo_pattern_t), will need to be +updated. + +Update to XCB backend +--------------------- +The XCB backend is now enabled by default, (use ./configure +--disable-xcb to turn it off). + +Faster clipping +--------------- +Graydon Hoare has added optimizations that make cairo_clip much faster +when the path is a pixel-aligned, rectangular region. + +Bug fixes. + +Snapshot 0.1.19 (2004-02-24 Carl Worth ) +======================================================== +New PNG backend +--------------- +Olivier Andrieu contributed a new PNG backend. It builds on the +existing image backend to make it easy to render "directly" to a +.png file. The user never needs to deal with the actual image +buffer. The significant new functions are: + + cairo_set_target_png + cairo_png_surface_create + +The PNG backend is not enabled by default so that by default there is +not a new dependency on libpng. Use ./configure --enable-png to enable +this backend. + +Snapshot 0.1.18 (2004-02-17 Carl Worth ) +======================================================== +Path query functionality +------------------------ +It's now possible to query the current path. The two new functions +are: + + cairo_current_path + cairo_current_path_flat + +Each function accepts a number of callback functions that will be +called for each element in the path (move_to, line_to, curve_to, +close_path). The cairo_current_path_flat function does not accept a +curve_to callback. Instead, all curved portions of the path will be +converted to line segments, (within the current tolerance value). This +can be handy for doing things like text-on-path without having to +manually interpolate Bézier splines. + +New XCB backend +--------------- +Jamey Sharp has contributed a second X backend that uses the new, lean +XCB library rather than Xlib. It cannot currently be compiled at the +same time as the Xlib backend. See ./configure --enable-xcb. + +Build fixes for cygwin. + +Bug fixes. + +Snapshot 0.1.17 (2003-12-16 Carl Worth ) +======================================================== + +Better text support +------------------- +This snapshot provides much better text support by implementing the +following four functions: + + cairo_text_extents + cairo_glyph_extents + cairo_text_path + cairo_glyph_path + +The text/glyph_extents functions can be used to determine the bounding +box (and advance) for text as if drawn by show_text/glyphs. + +The text/glyph_path objects functions place text shapes on the current +path, where they can be subsequently manipulated. For example, +following these functions with cairo_stroke allows outline text to be +drawn. Calling cairo_clip allows clipping to a text-shaped region. + +Combined dependencies +--------------------- +The cairo core now depends only on the libpixman library. This single +library replaces the three previous libraries libic, libpixregion, and +slim. Thanks to Dave Beckett for all of +the heavy lifting with this renaming effort. + +Conditional compilation of backends +----------------------------------- +Cairo now allows optional backends to be disabled at compile time. The +following options may now be passed to the configure script: + + --disable-xlib + --disable-ps + +Note that the first option is a change from the old --without-x option +which will no longer have any effect. + +OS X supported - several byte-order issues resolved +--------------------------------------------------- +Cairo has now been successfully compiled under OS X. Testing revealed +that there were some byte-order problems in the PostScript backend and +the PNG generation in the demos. These have now been resolved. + +2003-10 +======= +Graydon Hoare implemented the first real text +support using FreeType/fontconfig, (previous versions of cairo used +Xft and could only draw text when using an X backend). + +2003-09 +======= +Graydon Hoare added the first real support for +running cairo with a non-render-aware X server. + +Jamey Sharp virtualized the backend font and +surface interfaces in September, 2003. + +2003-06 +======= +Xr is renamed cairo to avoid confusion since it no longer had a strict +dependence on X. + +2003-05 +======= +A new image surface backend is added to Xr. Keith Packard + wrote the image compositing code in libic that is +used for the image_surface backend. This code was originally written +as the software fallback for the render extension within the X +server. + +2002-06 +======= +Carl Worth wrote the first lines of Xr, after Keith +Packard proposed the plan for a stateful drawing +library in C providing a PostScript-like rendering model. + + LocalWords: mutex BeOS extraordinaire distro's URL lcd bool tarball diff --git a/local/recipes/libs/cairo/source/README.md b/local/recipes/libs/cairo/source/README.md new file mode 100644 index 0000000000..2bd26068b0 --- /dev/null +++ b/local/recipes/libs/cairo/source/README.md @@ -0,0 +1,176 @@ +# Cairo: Multi-platform 2D graphics library + + + +What is cairo +------------- + +Cairo is a 2D graphics library with support for multiple output +devices. Currently supported output targets include the X Window +System (via both Xlib and XCB), quartz, win32, and image buffers, +as well as PDF, PostScript, and SVG file output. + +Cairo is designed to produce consistent output on all output media +while taking advantage of display hardware acceleration when available +(for example, through the X Render Extension). + +The cairo API provides operations similar to the drawing operators of +PostScript and PDF. Operations in cairo include stroking and filling +cubic Bézier splines, transforming and compositing translucent images, +and antialiased text rendering. All drawing operations can be +transformed by any affine transformation (scale, rotation, shear, +etc.). + +Cairo has been designed to let you draw anything you want in a modern +2D graphical user interface. At the same time, the cairo API has been +designed to be as fun and easy to learn as possible. If you're not +having fun while programming with cairo, then we have failed +somewhere---let us know and we'll try to fix it next time around. + +Cairo is free software and is available to be redistributed and/or +modified under the terms of either the GNU Lesser General Public +License (LGPL) version 2.1 or the Mozilla Public License (MPL) version +1.1. + +Where to get more information about cairo +----------------------------------------- + +The primary source of information about cairo is its website: + +- + +The latest versions of cairo can always be found at: + +- + +Documentation on using cairo and frequently-asked questions: + +- +- + +Mailing lists for contacting cairo users and developers: + +- + +Roadmap and unscheduled things to do, (please feel free to help out): + +- https://cairographics.org/roadmap +- https://cairographics.org/todo + +Dependencies +------------ + +The set of libraries needed to compile cairo depends on which backends are +enabled when cairo is configured. So look at the list below to determine +which dependencies are needed for the backends of interest. + +For the surface backends, we have both "supported" and "experimental" +backends. Further, the supported backends can be divided into the "standard" +backends which can be easily built on any platform, and the "platform" +backends which depend on some underlying platform-specific system, (such as +the X Window System or some other window system). + +As an example, for a standard Linux build similar to what's shipped by your +distro, (with image, png, pdf, PostScript, svg, and xlib surface backends, +and the freetype font backend), the following sample commands will install +necessary dependencies: + +- Debian (and similar): + - `apt-get build-dep cairo` + +- Fedora (and similar): + - `dnf builddep cairo` + +Technically you probably don't need pixman from the distribution since if +you're manually compiling Cairo you probably want an updated pixman as well. +However, if you follow the default settings and install pixman to +/usr/local, your Cairo build should properly use it in preference to the +system pixman. + + +### Supported, "standard" surface backends + +#### image backend (required) + +- [pixman](https://cairographics.org/releases) >= 0.30.0 + +#### PNG support (preferred) + +- [libpng](http://www.libpng.org/pub/png/libpng.html) + +#### PDF backend + +- [zlib](http://www.gzip.org/zlib) + +#### PostScript backend + +- [zlib](http://www.gzip.org/zlib) + +#### SVG backend + +- none + +### Supported, "platform" surface backends + +#### Xlib backend + +- [X11](https://freedesktop.org/Software/xlibs) + +#### xlib-xrender backend + +- [Xrender](https://freedesktop.org/Software/xlibs) >= 0.6 + +#### Quartz backend + +- macOS >= 10.4 with Xcode >= 2.5 + +#### Windows backend + +- Microsoft Windows Vista or newer. + +#### XCB backend + +- [XCB](https://xcb.freedesktop.org) + +### Font backends (required) + +#### freetype font backend + +- [freetype](https://freetype.org) >= 2.1.9 +- [fontconfig](https://www.freedesktop.org/wiki/Software/fontconfig/) + +#### Quartz-font backend + +- MacOS X >= 10.4 with Xcode >= 2.5 + +#### Windows GDI font backend + +- Microsoft Windows 2000 or newer + +#### Windows DirectWrite font backend + +- Microsoft Windows 7 or newer + +Compiling +--------- + +See the [`INSTALL`](./INSTALL) document for build instructions. + +Licensing +--------- + +Cairo is released under the terms of either the GNU Lesser General Public +License version 2.1, or the terms of the Mozilla Public License version 1.1. + +See the [`COPYING`](./COPYING) document for more information. + +History +------- + +Cairo was originally developed by Carl Worth and Keith +Packard . Many thanks are due to Lyle Ramshaw without +whose patient help our ignorance would be much more apparent. + +Since the original development, many more people have contributed to cairo. +See the [`AUTHORS`](./AUTHORS) document for as complete a list as we've been +able to compile so far. diff --git a/local/recipes/libs/cairo/source/boilerplate/.gitignore b/local/recipes/libs/cairo/source/boilerplate/.gitignore new file mode 100644 index 0000000000..90b333133a --- /dev/null +++ b/local/recipes/libs/cairo/source/boilerplate/.gitignore @@ -0,0 +1,25 @@ +TAGS +tags +Makefile +Makefile.in +Makefile.am.features +#Makefile.win32.features +*.lo +*.la +*.exe +*.manifest +*.o +*.gcda +*.gcno +*.obj +*.ilk +*.suo +*.lib +*.pdb +*.trs +*~ +.*.sw? +check-link +cairo-boilerplate-constructors.c +cairo-boilerplate-constructors +make-cairo-boilerplate-constructors diff --git a/local/recipes/libs/cairo/source/boilerplate/README b/local/recipes/libs/cairo/source/boilerplate/README new file mode 100644 index 0000000000..2a27c415cf --- /dev/null +++ b/local/recipes/libs/cairo/source/boilerplate/README @@ -0,0 +1,14 @@ +This directory provides code that is common to both of cairo's tests +suites: + + * The test suite for correctness in test/ + * The test suite for performance in perf/ + +We call it boilerplate as it consists primarily of the boilerplate +code necessary for initializing a backend in order to create a surface +for that backend. + +The code here just might be useful for someone looking to get started +writing cairo code to use a particular backend, (but there are no +promises that the boilerplate code found here for any particular +backend is exemplary). diff --git a/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-getopt.c b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-getopt.c new file mode 100644 index 0000000000..53b150c29c --- /dev/null +++ b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-getopt.c @@ -0,0 +1,247 @@ +/***************************************************************************** +* getopt.c - competent and free getopt library. +* $Header: /cvsroot/freegetopt/freegetopt/getopt.c,v 1.2 2003/10/26 03:10:20 vindaci Exp $ +* +* Copyright (c)2002-2003 Mark K. Kim +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in +* the documentation and/or other materials provided with the +* distribution. +* +* * Neither the original author of this software nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +* DAMAGE. +*/ +#include +#include +#include +#include "cairo-boilerplate-getopt.h" + + +char* optarg = NULL; +int optind = 0; +int opterr = 1; +int optopt = '?'; + + +static char** prev_argv = NULL; /* Keep a copy of argv and argc to */ +static int prev_argc = 0; /* tell if getopt params change */ +static int argv_index = 0; /* Option we're checking */ +static int argv_index2 = 0; /* Option argument we're checking */ +static int opt_offset = 0; /* Index into compounded "-option" */ +static int dashdash = 0; /* True if "--" option reached */ +static int nonopt = 0; /* How many nonopts we've found */ + +static void increment_index(void) +{ + /* Move onto the next option */ + if(argv_index < argv_index2) + { + while(prev_argv[++argv_index] && prev_argv[argv_index][0] != '-' + && argv_index < argv_index2+1); + } + else argv_index++; + opt_offset = 1; +} + + +/* +* Permutes argv[] so that the argument currently being processed is moved +* to the end. +*/ +static int permute_argv_once(void) +{ + /* Movability check */ + if(argv_index + nonopt >= prev_argc) return 1; + /* Move the current option to the end, bring the others to front */ + else + { + char* tmp = prev_argv[argv_index]; + + /* Move the data */ + memmove(&prev_argv[argv_index], &prev_argv[argv_index+1], + sizeof(char**) * (prev_argc - argv_index - 1)); + prev_argv[prev_argc - 1] = tmp; + + nonopt++; + return 0; + } +} + + +int _cairo_getopt(int argc, char** argv, const char* optstr) +{ + int c = 0; + + /* If we have new argv, reinitialize */ + if(prev_argv != argv || prev_argc != argc) + { + /* Initialize variables */ + prev_argv = argv; + prev_argc = argc; + argv_index = 1; + argv_index2 = 1; + opt_offset = 1; + dashdash = 0; + nonopt = 0; + } + + /* Jump point in case we want to ignore the current argv_index */ + getopt_top: + + /* Misc. initializations */ + optarg = NULL; + + /* Dash-dash check */ + if(argv[argv_index] && !strcmp(argv[argv_index], "--")) + { + dashdash = 1; + increment_index(); + } + + /* If we're at the end of argv, that's it. */ + if(argv[argv_index] == NULL) + { + c = -1; + } + /* Are we looking at a string? Single dash is also a string */ + else if(dashdash || argv[argv_index][0] != '-' || !strcmp(argv[argv_index], "-")) + { + /* If we want a string... */ + if(optstr[0] == '-') + { + c = 1; + optarg = argv[argv_index]; + increment_index(); + } + /* If we really don't want it (we're in POSIX mode), we're done */ + else if(optstr[0] == '+' || getenv("POSIXLY_CORRECT")) + { + c = -1; + + /* Everything else is a non-opt argument */ + nonopt = argc - argv_index; + } + /* If we mildly don't want it, then move it back */ + else + { + if(!permute_argv_once()) goto getopt_top; + else c = -1; + } + } + /* Otherwise we're looking at an option */ + else + { + char* opt_ptr = NULL; + + /* Grab the option */ + c = argv[argv_index][opt_offset++]; + + /* Is the option in the optstr? */ + if(optstr[0] == '-') opt_ptr = strchr(optstr+1, c); + else opt_ptr = strchr(optstr, c); + /* Invalid argument */ + if(!opt_ptr) + { + if(opterr) + { + fprintf(stderr, "%s: invalid option -- %c\n", argv[0], c); + } + + optopt = c; + c = '?'; + + /* Move onto the next option */ + increment_index(); + } + /* Option takes argument */ + else if(opt_ptr[1] == ':') + { + /* ie, -oARGUMENT, -xxxoARGUMENT, etc. */ + if(argv[argv_index][opt_offset] != '\0') + { + optarg = &argv[argv_index][opt_offset]; + increment_index(); + } + /* ie, -o ARGUMENT (only if it's a required argument) */ + else if(opt_ptr[2] != ':') + { + /* One of those "you're not expected to understand this" moment */ + if(argv_index2 < argv_index) argv_index2 = argv_index; + while(argv[++argv_index2] && argv[argv_index2][0] == '-'); + optarg = argv[argv_index2]; + + /* Don't cross into the non-option argument list */ + if(argv_index2 + nonopt >= prev_argc) optarg = NULL; + + /* Move onto the next option */ + increment_index(); + } + else + { + /* Move onto the next option */ + increment_index(); + } + + /* In case we got no argument for an option with required argument */ + if(optarg == NULL && opt_ptr[2] != ':') + { + optopt = c; + c = '?'; + + if(opterr) + { + fprintf(stderr,"%s: option requires an argument -- %c\n", + argv[0], optopt); + } + } + } + /* Option does not take argument */ + else + { + /* Next argv_index */ + if(argv[argv_index][opt_offset] == '\0') + { + increment_index(); + } + } + } + + /* Calculate optind */ + if(c == -1) + { + optind = argc - nonopt; + } + else + { + optind = argv_index; + } + + return c; +} + + +/* vim:ts=3 +*/ diff --git a/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-getopt.h b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-getopt.h new file mode 100644 index 0000000000..74bce14c75 --- /dev/null +++ b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-getopt.h @@ -0,0 +1,63 @@ +/***************************************************************************** +* getopt.h - competent and free getopt library. +* $Header: /cvsroot/freegetopt/freegetopt/getopt.h,v 1.2 2003/10/26 03:10:20 vindaci Exp $ +* +* Copyright (c)2002-2003 Mark K. Kim +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in +* the documentation and/or other materials provided with the +* distribution. +* +* * Neither the original author of this software nor the names of its +* contributors may be used to endorse or promote products derived +* from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +* DAMAGE. +*/ +#ifndef GETOPT_H_ +#define GETOPT_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + + +extern char* optarg; +extern int optind; +extern int opterr; +extern int optopt; + +int _cairo_getopt(int argc, char** argv, const char* optstr); + + +#ifdef __cplusplus +} +#endif + + +#endif /* GETOPT_H_ */ + + +/* vim:ts=3 +*/ diff --git a/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-pdf.c b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-pdf.c new file mode 100644 index 0000000000..4669040b93 --- /dev/null +++ b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-pdf.c @@ -0,0 +1,288 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright © 2004,2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-boilerplate-private.h" + +#if CAIRO_CAN_TEST_PDF_SURFACE + +#include +#include +#include + +#if HAVE_SIGNAL_H +#include +#endif + +#if HAVE_SYS_WAIT_H +#include +#endif + +#if ! CAIRO_HAS_RECORDING_SURFACE +#define CAIRO_SURFACE_TYPE_RECORDING CAIRO_INTERNAL_SURFACE_TYPE_RECORDING +#endif + +static const cairo_user_data_key_t pdf_closure_key; + +typedef struct _pdf_target_closure +{ + char *filename; + int width; + int height; + cairo_surface_t *target; +} pdf_target_closure_t; + +static cairo_surface_t * +_cairo_boilerplate_pdf_create_surface (const char *name, + cairo_content_t content, + double width, + double height, + double max_width, + double max_height, + cairo_boilerplate_mode_t mode, + void **closure) +{ + pdf_target_closure_t *ptc; + cairo_surface_t *surface; + cairo_status_t status; + + /* Sanitize back to a real cairo_content_t value. */ + if (content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED) + content = CAIRO_CONTENT_COLOR_ALPHA; + + *closure = ptc = xmalloc (sizeof (pdf_target_closure_t)); + + ptc->width = ceil (width); + ptc->height = ceil (height); + + xasprintf (&ptc->filename, "%s.out.pdf", name); + xunlink (ptc->filename); + + surface = cairo_pdf_surface_create (ptc->filename, width, height); + if (cairo_surface_status (surface)) + goto CLEANUP_FILENAME; + + cairo_pdf_surface_set_metadata (surface, CAIRO_PDF_METADATA_CREATE_DATE, NULL); + cairo_surface_set_fallback_resolution (surface, 72., 72.); + + if (content == CAIRO_CONTENT_COLOR) { + ptc->target = surface; + surface = cairo_surface_create_similar (ptc->target, + CAIRO_CONTENT_COLOR, + ptc->width, ptc->height); + if (cairo_surface_status (surface)) + goto CLEANUP_TARGET; + } else { + ptc->target = NULL; + } + + status = cairo_surface_set_user_data (surface, &pdf_closure_key, ptc, NULL); + if (status == CAIRO_STATUS_SUCCESS) + return surface; + + cairo_surface_destroy (surface); + surface = cairo_boilerplate_surface_create_in_error (status); + + CLEANUP_TARGET: + cairo_surface_destroy (ptc->target); + CLEANUP_FILENAME: + free (ptc->filename); + free (ptc); + return surface; +} + +static cairo_status_t +_cairo_boilerplate_pdf_finish_surface (cairo_surface_t *surface) +{ + pdf_target_closure_t *ptc = cairo_surface_get_user_data (surface, + &pdf_closure_key); + cairo_status_t status; + + if (ptc->target) { + /* Both surface and ptc->target were originally created at the + * same dimensions. We want a 1:1 copy here, so we first clear any + * device offset and scale on surface. + * + * In a more realistic use case of device offsets, the target of + * this copying would be of a different size than the source, and + * the offset would be desirable during the copy operation. */ + double x_offset, y_offset; + double x_scale, y_scale; + cairo_surface_get_device_offset (surface, &x_offset, &y_offset); + cairo_surface_get_device_scale (surface, &x_scale, &y_scale); + cairo_surface_set_device_offset (surface, 0, 0); + cairo_surface_set_device_scale (surface, 1, 1); + cairo_t *cr; + cr = cairo_create (ptc->target); + cairo_set_source_surface (cr, surface, 0, 0); + cairo_paint (cr); + cairo_show_page (cr); + status = cairo_status (cr); + cairo_destroy (cr); + cairo_surface_set_device_offset (surface, x_offset, y_offset); + cairo_surface_set_device_scale (surface, x_scale, y_scale); + + if (status) + return status; + + cairo_surface_finish (surface); + status = cairo_surface_status (surface); + if (status) + return status; + + surface = ptc->target; + } + + cairo_surface_finish (surface); + status = cairo_surface_status (surface); + if (status) + return status; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_boilerplate_pdf_surface_write_to_png (cairo_surface_t *surface, + const char *filename) +{ + pdf_target_closure_t *ptc = cairo_surface_get_user_data (surface, &pdf_closure_key); + char command[4096]; + int exitstatus; + + sprintf (command, "./pdf2png %s %s 1", + ptc->filename, filename); + + exitstatus = system (command); +#if _XOPEN_SOURCE && HAVE_SIGNAL_H + if (WIFSIGNALED (exitstatus)) + raise (WTERMSIG (exitstatus)); +#endif + if (exitstatus) + return CAIRO_STATUS_WRITE_ERROR; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_surface_t * +_cairo_boilerplate_pdf_convert_to_image (cairo_surface_t *surface, + int page) +{ + pdf_target_closure_t *ptc = cairo_surface_get_user_data (surface, + &pdf_closure_key); + + return cairo_boilerplate_convert_to_image (ptc->filename, page+1); +} + +static cairo_surface_t * +_cairo_boilerplate_pdf_get_image_surface (cairo_surface_t *surface, + int page, + int width, + int height) +{ + cairo_surface_t *image; + double x_offset, y_offset; + double x_scale, y_scale; + + image = _cairo_boilerplate_pdf_convert_to_image (surface, page); + cairo_surface_get_device_offset (surface, &x_offset, &y_offset); + cairo_surface_get_device_scale (surface, &x_scale, &y_scale); + cairo_surface_set_device_offset (image, x_offset, y_offset); + cairo_surface_set_device_scale (image, x_scale, y_scale); + surface = _cairo_boilerplate_get_image_surface (image, 0, width, height); + cairo_surface_destroy (image); + + return surface; +} + +static void +_cairo_boilerplate_pdf_cleanup (void *closure) +{ + pdf_target_closure_t *ptc = closure; + if (ptc->target) { + cairo_surface_finish (ptc->target); + cairo_surface_destroy (ptc->target); + } + free (ptc->filename); + free (ptc); +} + +static void +_cairo_boilerplate_pdf_force_fallbacks (cairo_surface_t *abstract_surface, + double x_pixels_per_inch, + double y_pixels_per_inch) +{ + pdf_target_closure_t *ptc = cairo_surface_get_user_data (abstract_surface, + &pdf_closure_key); + + cairo_paginated_surface_t *paginated; + cairo_pdf_surface_t *surface; + + if (ptc->target) + abstract_surface = ptc->target; + + paginated = (cairo_paginated_surface_t*) abstract_surface; + surface = (cairo_pdf_surface_t*) paginated->target; + surface->force_fallbacks = TRUE; + cairo_surface_set_fallback_resolution (&paginated->base, + x_pixels_per_inch, + y_pixels_per_inch); +} + +static const cairo_boilerplate_target_t targets[] = { + { + "pdf", "pdf", ".pdf", NULL, + CAIRO_SURFACE_TYPE_PDF, + CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED, 0, + "cairo_pdf_surface_create", + _cairo_boilerplate_pdf_create_surface, + cairo_surface_create_similar, + _cairo_boilerplate_pdf_force_fallbacks, + _cairo_boilerplate_pdf_finish_surface, + _cairo_boilerplate_pdf_get_image_surface, + _cairo_boilerplate_pdf_surface_write_to_png, + _cairo_boilerplate_pdf_cleanup, + NULL, NULL, FALSE, TRUE, TRUE + }, + { + "pdf", "pdf", ".pdf", NULL, + CAIRO_SURFACE_TYPE_RECORDING, CAIRO_CONTENT_COLOR, 0, + "cairo_pdf_surface_create", + _cairo_boilerplate_pdf_create_surface, + cairo_surface_create_similar, + _cairo_boilerplate_pdf_force_fallbacks, + _cairo_boilerplate_pdf_finish_surface, + _cairo_boilerplate_pdf_get_image_surface, + _cairo_boilerplate_pdf_surface_write_to_png, + _cairo_boilerplate_pdf_cleanup, + NULL, NULL, FALSE, TRUE, TRUE + }, +}; +CAIRO_BOILERPLATE (pdf, targets) + +#else + +CAIRO_NO_BOILERPLATE (pdf) + +#endif diff --git a/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-private.h b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-private.h new file mode 100644 index 0000000000..d16a645b2a --- /dev/null +++ b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-private.h @@ -0,0 +1,53 @@ +/* + * Copyright © 2009 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#ifndef _CAIRO_BOILERPLATE_PRIVATE_H_ +#define _CAIRO_BOILERPLATE_PRIVATE_H_ + +#include "cairo-boilerplate.h" + +CAIRO_BEGIN_DECLS + +void +_cairo_boilerplate_register_all (void); + +void +_cairo_boilerplate_register_backend (const cairo_boilerplate_target_t *targets, + unsigned int count); + +#define CAIRO_BOILERPLATE(name__, targets__) \ +void _register_##name__ (void); \ +void _register_##name__ (void) { \ + _cairo_boilerplate_register_backend (targets__, \ + ARRAY_LENGTH(targets__)); \ +} + +#define CAIRO_NO_BOILERPLATE(name__) \ +void _register_##name__ (void); \ +void _register_##name__ (void) { } + +CAIRO_END_DECLS + +#endif /* _CAIRO_BOILERPLATE_PRIVATE_H_ */ diff --git a/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-ps.c b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-ps.c new file mode 100644 index 0000000000..73546046e7 --- /dev/null +++ b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-ps.c @@ -0,0 +1,388 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright © 2004,2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-boilerplate-private.h" + +#if CAIRO_CAN_TEST_PS_SURFACE + +#include + +#include +#include + +#if HAVE_SIGNAL_H +#include +#endif + +#if HAVE_SYS_WAIT_H +#include +#endif + +#if ! CAIRO_HAS_RECORDING_SURFACE +#define CAIRO_SURFACE_TYPE_RECORDING CAIRO_INTERNAL_SURFACE_TYPE_RECORDING +#endif + +static const cairo_user_data_key_t ps_closure_key; + +typedef struct _ps_target_closure { + char *filename; + int width; + int height; + cairo_surface_t *target; + cairo_ps_level_t level; +} ps_target_closure_t; + +static cairo_status_t +_cairo_boilerplate_ps_surface_set_creation_date (cairo_surface_t *abstract_surface, + time_t date) +{ + cairo_paginated_surface_t *paginated = (cairo_paginated_surface_t*) abstract_surface; + cairo_ps_surface_t *surface; + + if (cairo_surface_get_type (abstract_surface) != CAIRO_SURFACE_TYPE_PS) + return CAIRO_STATUS_SURFACE_TYPE_MISMATCH; + + surface = (cairo_ps_surface_t*) paginated->target; + + surface->has_creation_date = TRUE; + surface->creation_date = date; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_surface_t * +_cairo_boilerplate_ps_create_surface (const char *name, + cairo_content_t content, + cairo_ps_level_t level, + double width, + double height, + double max_width, + double max_height, + cairo_boilerplate_mode_t mode, + void **closure) +{ + ps_target_closure_t *ptc; + cairo_surface_t *surface; + cairo_status_t status; + + /* Sanitize back to a real cairo_content_t value. */ + if (content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED) + content = CAIRO_CONTENT_COLOR_ALPHA; + + *closure = ptc = xmalloc (sizeof (ps_target_closure_t)); + + xasprintf (&ptc->filename, "%s.out.ps", name); + xunlink (ptc->filename); + + ptc->level = level; + ptc->width = ceil (width); + ptc->height = ceil (height); + + surface = cairo_ps_surface_create (ptc->filename, width, height); + if (cairo_surface_status (surface)) + goto CLEANUP_FILENAME; + + cairo_ps_surface_restrict_to_level (surface, level); + _cairo_boilerplate_ps_surface_set_creation_date (surface, 0); + cairo_surface_set_fallback_resolution (surface, 72., 72.); + + if (content == CAIRO_CONTENT_COLOR) { + ptc->target = surface; + surface = cairo_surface_create_similar (ptc->target, + CAIRO_CONTENT_COLOR, + ptc->width, ptc->height); + if (cairo_surface_status (surface)) + goto CLEANUP_TARGET; + } else { + ptc->target = NULL; + } + + status = cairo_surface_set_user_data (surface, &ps_closure_key, ptc, NULL); + if (status == CAIRO_STATUS_SUCCESS) + return surface; + + cairo_surface_destroy (surface); + surface = cairo_boilerplate_surface_create_in_error (status); + + CLEANUP_TARGET: + cairo_surface_destroy (ptc->target); + CLEANUP_FILENAME: + free (ptc->filename); + free (ptc); + return surface; +} + +static cairo_surface_t * +_cairo_boilerplate_ps2_create_surface (const char *name, + cairo_content_t content, + double width, + double height, + double max_width, + double max_height, + cairo_boilerplate_mode_t mode, + void **closure) +{ + return _cairo_boilerplate_ps_create_surface (name, content, + CAIRO_PS_LEVEL_2, + width, height, + max_width, max_height, + mode, + closure); +} + +static cairo_surface_t * +_cairo_boilerplate_ps3_create_surface (const char *name, + cairo_content_t content, + double width, + double height, + double max_width, + double max_height, + cairo_boilerplate_mode_t mode, + void **closure) +{ + return _cairo_boilerplate_ps_create_surface (name, content, + CAIRO_PS_LEVEL_3, + width, height, + max_width, max_height, + mode, + closure); +} + +static cairo_status_t +_cairo_boilerplate_ps_finish_surface (cairo_surface_t *surface) +{ + ps_target_closure_t *ptc = cairo_surface_get_user_data (surface, + &ps_closure_key); + cairo_status_t status; + + if (ptc->target) { + /* Both surface and ptc->target were originally created at the + * same dimensions. We want a 1:1 copy here, so we first clear any + * device offset and scale on surface. + * + * In a more realistic use case of device offsets, the target of + * this copying would be of a different size than the source, and + * the offset would be desirable during the copy operation. */ + double x_offset, y_offset; + double x_scale, y_scale; + cairo_surface_get_device_offset (surface, &x_offset, &y_offset); + cairo_surface_get_device_scale (surface, &x_scale, &y_scale); + cairo_surface_set_device_offset (surface, 0, 0); + cairo_surface_set_device_scale (surface, 1, 1); + cairo_t *cr; + cr = cairo_create (ptc->target); + cairo_set_source_surface (cr, surface, 0, 0); + cairo_paint (cr); + cairo_show_page (cr); + status = cairo_status (cr); + cairo_destroy (cr); + cairo_surface_set_device_offset (surface, x_offset, y_offset); + cairo_surface_set_device_scale (surface, x_scale, y_scale); + + if (status) + return status; + + cairo_surface_finish (surface); + status = cairo_surface_status (surface); + if (status) + return status; + + surface = ptc->target; + } + + cairo_surface_finish (surface); + return cairo_surface_status (surface); +} + +static cairo_status_t +_cairo_boilerplate_ps_surface_write_to_png (cairo_surface_t *surface, + const char *filename) +{ + ps_target_closure_t *ptc = cairo_surface_get_user_data (surface, + &ps_closure_key); + char command[4096]; + int exitstatus; + + sprintf (command, "gs -q -r72 -g%dx%d -dSAFER -dBATCH -dNOPAUSE -sDEVICE=pngalpha -sOutputFile=%s %s", + ptc->width, ptc->height, filename, + ptc->filename); + exitstatus = system (command); +#if _XOPEN_SOURCE && HAVE_SIGNAL_H + if (WIFSIGNALED (exitstatus)) + raise (WTERMSIG (exitstatus)); +#endif + if (exitstatus) + return CAIRO_STATUS_WRITE_ERROR; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_surface_t * +_cairo_boilerplate_ps_get_image_surface (cairo_surface_t *surface, + int page, + int width, + int height) +{ + ps_target_closure_t *ptc = cairo_surface_get_user_data (surface, + &ps_closure_key); + double x_offset, y_offset; + double x_scale, y_scale; + char *filename; + cairo_status_t status; + + if (page == 0) + xasprintf (&filename, "%s.png", ptc->filename); + else + xasprintf (&filename, "%s-%%05d.png", ptc->filename); + status = _cairo_boilerplate_ps_surface_write_to_png (surface, filename); + if (status) + return cairo_boilerplate_surface_create_in_error (status); + + if (page != 0) { + free (filename); + xasprintf (&filename, "%s-%05d.png", ptc->filename, page); + } + cairo_surface_t *converted = cairo_boilerplate_get_image_surface_from_png (filename, + ptc->width, + ptc->height, + ptc->target == NULL); + + remove (filename); + free (filename); + + cairo_surface_t *image = cairo_image_surface_create(ptc->target ? CAIRO_FORMAT_RGB24 : CAIRO_FORMAT_ARGB32, + width, + height); + cairo_surface_get_device_offset (surface, &x_offset, &y_offset); + cairo_surface_get_device_scale (surface, &x_scale, &y_scale); + cairo_surface_set_device_offset (converted, x_offset, y_offset); + cairo_surface_set_device_scale (converted, x_scale, y_scale); + cairo_t *cr = cairo_create (image); + cairo_set_source_surface (cr, converted, 0, 0); + cairo_paint (cr); + cairo_destroy (cr); + cairo_surface_destroy (converted); + + return image; +} + +static void +_cairo_boilerplate_ps_cleanup (void *closure) +{ + ps_target_closure_t *ptc = closure; + if (ptc->target) { + cairo_surface_finish (ptc->target); + cairo_surface_destroy (ptc->target); + } + free (ptc->filename); + free (ptc); +} + +static void +_cairo_boilerplate_ps_force_fallbacks (cairo_surface_t *abstract_surface, + double x_pixels_per_inch, + double y_pixels_per_inch) +{ + ps_target_closure_t *ptc = cairo_surface_get_user_data (abstract_surface, + &ps_closure_key); + + cairo_paginated_surface_t *paginated; + cairo_ps_surface_t *surface; + + if (ptc->target) + abstract_surface = ptc->target; + + paginated = (cairo_paginated_surface_t*) abstract_surface; + surface = (cairo_ps_surface_t*) paginated->target; + surface->force_fallbacks = TRUE; + cairo_surface_set_fallback_resolution (&paginated->base, + x_pixels_per_inch, + y_pixels_per_inch); +} + +static const cairo_boilerplate_target_t targets[] = { + { + "ps2", "ps", ".ps", NULL, + CAIRO_SURFACE_TYPE_PS, + CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED, 0, + "cairo_ps_surface_create", + _cairo_boilerplate_ps2_create_surface, + cairo_surface_create_similar, + _cairo_boilerplate_ps_force_fallbacks, + _cairo_boilerplate_ps_finish_surface, + _cairo_boilerplate_ps_get_image_surface, + _cairo_boilerplate_ps_surface_write_to_png, + _cairo_boilerplate_ps_cleanup, + NULL, NULL, FALSE, TRUE, TRUE + }, + { + "ps2", "ps", ".ps", NULL, + CAIRO_SURFACE_TYPE_RECORDING, CAIRO_CONTENT_COLOR, 0, + "cairo_ps_surface_create", + _cairo_boilerplate_ps2_create_surface, + cairo_surface_create_similar, + _cairo_boilerplate_ps_force_fallbacks, + _cairo_boilerplate_ps_finish_surface, + _cairo_boilerplate_ps_get_image_surface, + _cairo_boilerplate_ps_surface_write_to_png, + _cairo_boilerplate_ps_cleanup, + NULL, NULL, FALSE, TRUE, TRUE + }, + { + "ps3", "ps", ".ps", NULL, + CAIRO_SURFACE_TYPE_PS, + CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED, 0, + "cairo_ps_surface_create", + _cairo_boilerplate_ps3_create_surface, + cairo_surface_create_similar, + _cairo_boilerplate_ps_force_fallbacks, + _cairo_boilerplate_ps_finish_surface, + _cairo_boilerplate_ps_get_image_surface, + _cairo_boilerplate_ps_surface_write_to_png, + _cairo_boilerplate_ps_cleanup, + NULL, NULL, FALSE, TRUE, TRUE + }, + { + "ps3", "ps", ".ps", NULL, + CAIRO_SURFACE_TYPE_RECORDING, CAIRO_CONTENT_COLOR, 0, + "cairo_ps_surface_create", + _cairo_boilerplate_ps3_create_surface, + cairo_surface_create_similar, + _cairo_boilerplate_ps_force_fallbacks, + _cairo_boilerplate_ps_finish_surface, + _cairo_boilerplate_ps_get_image_surface, + _cairo_boilerplate_ps_surface_write_to_png, + _cairo_boilerplate_ps_cleanup, + NULL, NULL, FALSE, TRUE, TRUE + }, +}; +CAIRO_BOILERPLATE (ps, targets) + +#else + +CAIRO_NO_BOILERPLATE (ps) + +#endif diff --git a/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-quartz.c b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-quartz.c new file mode 100644 index 0000000000..dd2452c0a7 --- /dev/null +++ b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-quartz.c @@ -0,0 +1,152 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright © 2004,2007 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-boilerplate-private.h" + +#include + +#include + +#ifndef RTLD_DEFAULT +#define RTLD_DEFAULT ((void *) 0) +#endif + +/* + * macOS Private functions + */ +typedef enum { + kCGContextTypeUnknown, + kCGContextTypePDF, + kCGContextTypePostScript, + kCGContextTypeWindow, + kCGContextTypeBitmap, + kCGContextTypeGL, + kCGContextTypeDisplayList, + kCGContextTypeKSeparation, + kCGContextTypeIOSurface, + kCGContextTypeCount +} CGContextType; + + +static unsigned int (*CGContextGetTypePtr) (CGContextRef) = NULL; +static void +quartz_ensure_symbols (void) +{ + static cairo_bool_t symbol_lookup_done = FALSE; + if (!symbol_lookup_done) { + CGContextGetTypePtr = dlsym (RTLD_DEFAULT, "CGContextGetType"); + symbol_lookup_done = TRUE; + } +} + +static cairo_surface_t * +_cairo_boilerplate_quartz_create_surface (const char *name, + cairo_content_t content, + double width, + double height, + double max_width, + double max_height, + cairo_boilerplate_mode_t mode, + void **closure) +{ + cairo_format_t format; + + format = cairo_boilerplate_format_from_content (content); + + *closure = NULL; + + return cairo_quartz_surface_create (format, width, height); +} + +static bool +cg_context_is_bitmap (CGContextRef context) +{ + quartz_ensure_symbols (); + + if (likely (CGContextGetTypePtr)) { + return CGContextGetTypePtr (context) == kCGContextTypeBitmap; + } + + return CGBitmapContextGetBitsPerPixel (context) != 0; +} + +static cairo_status_t +_cairo_boilerplate_quartz_surface_to_png (cairo_surface_t *surface, + const char *dest) +{ + CGContextRef context = cairo_quartz_surface_get_cg_context (surface); + if (!context || !cg_context_is_bitmap (context)) { + return CAIRO_STATUS_SURFACE_TYPE_MISMATCH; + } + + CGImageRef image = CGBitmapContextCreateImage (context); + CFStringRef png_utti = CFSTR("public.png"); + CFStringRef path; + CFURLRef url; + + CGImageDestinationRef image_dest; + + path = CFStringCreateWithCString (NULL, dest, kCFStringEncodingUTF8); + url = CFURLCreateWithFileSystemPath (NULL, path, kCFURLPOSIXPathStyle, FALSE); + image_dest = CGImageDestinationCreateWithURL (url, png_utti, 1, NULL); + + CGImageDestinationAddImage (image_dest, image, NULL); + CGImageDestinationFinalize (image_dest); + + CFRelease (url); + CFRelease (path); + + CGImageRelease (image); + return CAIRO_STATUS_SUCCESS; +} + +static const cairo_boilerplate_target_t targets[] = { + { + "quartz", "quartz", NULL, NULL, + CAIRO_SURFACE_TYPE_QUARTZ, CAIRO_CONTENT_COLOR_ALPHA, 0, + "cairo_quartz_surface_create", + _cairo_boilerplate_quartz_create_surface, + cairo_surface_create_similar, + NULL, NULL, + _cairo_boilerplate_get_image_surface, + _cairo_boilerplate_quartz_surface_to_png, + NULL, NULL, NULL, + TRUE, FALSE, FALSE + }, + { + "quartz", "quartz", NULL, NULL, + CAIRO_SURFACE_TYPE_QUARTZ, CAIRO_CONTENT_COLOR, 0, + "cairo_quartz_surface_create", + _cairo_boilerplate_quartz_create_surface, + cairo_surface_create_similar, + NULL, NULL, + _cairo_boilerplate_get_image_surface, + _cairo_boilerplate_quartz_surface_to_png, + NULL, NULL, NULL, + FALSE, FALSE, FALSE + }, +}; +CAIRO_BOILERPLATE (quartz, targets) diff --git a/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-scaled-font.h b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-scaled-font.h new file mode 100644 index 0000000000..a7ba2fede9 --- /dev/null +++ b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-scaled-font.h @@ -0,0 +1,34 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright © 2007 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Behdad Esfahbod + */ + +#ifndef _CAIRO_BOILERPLATE_SCALED_FONT_H_ +#define _CAIRO_BOILERPLATE_SCALED_FONT_H_ + +void +cairo_boilerplate_scaled_font_set_max_glyphs_cached (cairo_scaled_font_t *scaled_font, + int max_glyphs); + +#endif diff --git a/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-script.c b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-script.c new file mode 100644 index 0000000000..da8ae3bbd5 --- /dev/null +++ b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-script.c @@ -0,0 +1,141 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright © Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-boilerplate-private.h" + +#include "cairo-script.h" + +static cairo_user_data_key_t script_closure_key; + +typedef struct _script_target_closure { + char *filename; + double width; + double height; +} script_target_closure_t; + +static cairo_surface_t * +_cairo_boilerplate_script_create_surface (const char *name, + cairo_content_t content, + double width, + double height, + double max_width, + double max_height, + cairo_boilerplate_mode_t mode, + void **closure) +{ + script_target_closure_t *ptc; + cairo_device_t *ctx; + cairo_surface_t *surface; + cairo_status_t status; + + *closure = ptc = xmalloc (sizeof (script_target_closure_t)); + + ptc->width = width; + ptc->height = height; + + xasprintf (&ptc->filename, "%s.out.cs", name); + xunlink (ptc->filename); + + ctx = cairo_script_create (ptc->filename); + surface = cairo_script_surface_create (ctx, content, width, height); + cairo_device_destroy (ctx); + + status = cairo_surface_set_user_data (surface, + &script_closure_key, ptc, NULL); + if (status == CAIRO_STATUS_SUCCESS) + return surface; + + cairo_surface_destroy (surface); + surface = cairo_boilerplate_surface_create_in_error (status); + + free (ptc->filename); + free (ptc); + return surface; +} + +static cairo_status_t +_cairo_boilerplate_script_finish_surface (cairo_surface_t *surface) +{ + cairo_surface_finish (surface); + return cairo_surface_status (surface); +} + +static cairo_status_t +_cairo_boilerplate_script_surface_write_to_png (cairo_surface_t *surface, + const char *filename) +{ + return CAIRO_STATUS_WRITE_ERROR; +} + +static cairo_surface_t * +_cairo_boilerplate_script_convert_to_image (cairo_surface_t *surface, + int page) +{ + script_target_closure_t *ptc = cairo_surface_get_user_data (surface, + &script_closure_key); + return cairo_boilerplate_convert_to_image (ptc->filename, page); +} + +static cairo_surface_t * +_cairo_boilerplate_script_get_image_surface (cairo_surface_t *surface, + int page, + int width, + int height) +{ + cairo_surface_t *image; + + image = _cairo_boilerplate_script_convert_to_image (surface, page); + cairo_surface_set_device_offset (image, + cairo_image_surface_get_width (image) - width, + cairo_image_surface_get_height (image) - height); + surface = _cairo_boilerplate_get_image_surface (image, 0, width, height); + cairo_surface_destroy (image); + + return surface; +} + +static void +_cairo_boilerplate_script_cleanup (void *closure) +{ + script_target_closure_t *ptc = closure; + free (ptc->filename); + free (ptc); +} + +static const cairo_boilerplate_target_t target[] = {{ + "script", "script", ".cs", NULL, + CAIRO_SURFACE_TYPE_SCRIPT, CAIRO_CONTENT_COLOR_ALPHA, 0, + "cairo_script_surface_create", + _cairo_boilerplate_script_create_surface, + cairo_surface_create_similar, + NULL, + _cairo_boilerplate_script_finish_surface, + _cairo_boilerplate_script_get_image_surface, + _cairo_boilerplate_script_surface_write_to_png, + _cairo_boilerplate_script_cleanup, + NULL, NULL, FALSE, FALSE, FALSE +}}; +CAIRO_BOILERPLATE (script, target) diff --git a/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-svg.c b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-svg.c new file mode 100644 index 0000000000..0c9a3833ee --- /dev/null +++ b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-svg.c @@ -0,0 +1,305 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright © 2004,2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-boilerplate-private.h" + +#if CAIRO_CAN_TEST_SVG_SURFACE + +#include +#include +#include + +#if HAVE_SIGNAL_H +#include +#include +#endif + +#if HAVE_SYS_WAIT_H +#include +#endif + +#if ! CAIRO_HAS_RECORDING_SURFACE +#define CAIRO_SURFACE_TYPE_RECORDING CAIRO_INTERNAL_SURFACE_TYPE_RECORDING +#endif + +static const cairo_user_data_key_t svg_closure_key; + +typedef struct _svg_target_closure { + char *filename; + int width, height; + cairo_surface_t *target; +} svg_target_closure_t; + +static cairo_surface_t * +_cairo_boilerplate_svg_create_surface (const char *name, + cairo_content_t content, + cairo_svg_version_t version, + double width, + double height, + double max_width, + double max_height, + cairo_boilerplate_mode_t mode, + void **closure) +{ + svg_target_closure_t *ptc; + cairo_surface_t *surface; + cairo_status_t status; + + *closure = ptc = xmalloc (sizeof (svg_target_closure_t)); + + ptc->width = ceil (width); + ptc->height = ceil (height); + + xasprintf (&ptc->filename, "%s.out.svg", name); + xunlink (ptc->filename); + + surface = cairo_svg_surface_create (ptc->filename, width, height); + if (cairo_surface_status (surface)) + goto CLEANUP_FILENAME; + + cairo_svg_surface_restrict_to_version (surface, version); + cairo_surface_set_fallback_resolution (surface, 72., 72.); + + if (content == CAIRO_CONTENT_COLOR) { + ptc->target = surface; + surface = cairo_surface_create_similar (ptc->target, + CAIRO_CONTENT_COLOR, + ptc->width, ptc->height); + if (cairo_surface_status (surface)) + goto CLEANUP_TARGET; + } else + ptc->target = NULL; + + status = cairo_surface_set_user_data (surface, &svg_closure_key, ptc, NULL); + if (status == CAIRO_STATUS_SUCCESS) + return surface; + + cairo_surface_destroy (surface); + surface = cairo_boilerplate_surface_create_in_error (status); + + CLEANUP_TARGET: + cairo_surface_destroy (ptc->target); + CLEANUP_FILENAME: + free (ptc->filename); + free (ptc); + return surface; +} + +static cairo_surface_t * +_cairo_boilerplate_svg11_create_surface (const char *name, + cairo_content_t content, + double width, + double height, + double max_width, + double max_height, + cairo_boilerplate_mode_t mode, + void **closure) +{ + /* current default, but be explicit in case the default changes */ + return _cairo_boilerplate_svg_create_surface (name, content, + CAIRO_SVG_VERSION_1_1, + width, height, + max_width, max_height, + mode, + closure); +} + +static cairo_status_t +_cairo_boilerplate_svg_finish_surface (cairo_surface_t *surface) +{ + svg_target_closure_t *ptc = cairo_surface_get_user_data (surface, + &svg_closure_key); + cairo_status_t status; + + if (ptc->target) { + /* Both surface and ptc->target were originally created at the + * same dimensions. We want a 1:1 copy here, so we first clear any + * device offset and scale on surface. + * + * In a more realistic use case of device offsets, the target of + * this copying would be of a different size than the source, and + * the offset would be desirable during the copy operation. */ + double x_offset, y_offset; + double x_scale, y_scale; + cairo_surface_get_device_offset (surface, &x_offset, &y_offset); + cairo_surface_get_device_scale (surface, &x_scale, &y_scale); + cairo_surface_set_device_offset (surface, 0, 0); + cairo_surface_set_device_scale (surface, 1, 1); + cairo_t *cr; + cr = cairo_create (ptc->target); + cairo_set_source_surface (cr, surface, 0, 0); + cairo_paint (cr); + cairo_show_page (cr); + status = cairo_status (cr); + cairo_destroy (cr); + cairo_surface_set_device_offset (surface, x_offset, y_offset); + cairo_surface_set_device_scale (surface, x_scale, y_scale); + + if (status) + return status; + + cairo_surface_finish (surface); + status = cairo_surface_status (surface); + if (status) + return status; + + surface = ptc->target; + } + + cairo_surface_finish (surface); + status = cairo_surface_status (surface); + if (status) + return status; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_boilerplate_svg_surface_write_to_png (cairo_surface_t *surface, + const char *filename) +{ + svg_target_closure_t *ptc = cairo_surface_get_user_data (surface, + &svg_closure_key); + char command[4096]; + int exitstatus; + + sprintf (command, "./svg2png %s %s", + ptc->filename, filename); + + exitstatus = system (command); +#if _XOPEN_SOURCE && HAVE_SIGNAL_H + if (WIFSIGNALED (exitstatus)) + raise (WTERMSIG (exitstatus)); +#endif + if (exitstatus) + return CAIRO_STATUS_WRITE_ERROR; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_surface_t * +_cairo_boilerplate_svg_convert_to_image (cairo_surface_t *surface) +{ + svg_target_closure_t *ptc = cairo_surface_get_user_data (surface, + &svg_closure_key); + + return cairo_boilerplate_convert_to_image (ptc->filename, 0); +} + +static cairo_surface_t * +_cairo_boilerplate_svg_get_image_surface (cairo_surface_t *surface, + int page, + int width, + int height) +{ + cairo_surface_t *image; + double x_offset, y_offset; + double x_scale, y_scale; + + if (page != 0) + return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + + image = _cairo_boilerplate_svg_convert_to_image (surface); + cairo_surface_get_device_offset (surface, &x_offset, &y_offset); + cairo_surface_get_device_scale (surface, &x_scale, &y_scale); + cairo_surface_set_device_offset (image, x_offset, y_offset); + cairo_surface_set_device_scale (image, x_scale, y_scale); + surface = _cairo_boilerplate_get_image_surface (image, 0, width, height); + cairo_surface_destroy (image); + + return surface; +} + +static void +_cairo_boilerplate_svg_cleanup (void *closure) +{ + svg_target_closure_t *ptc = closure; + if (ptc->target != NULL) { + cairo_surface_finish (ptc->target); + cairo_surface_destroy (ptc->target); + } + free (ptc->filename); + free (ptc); +} + +static void +_cairo_boilerplate_svg_force_fallbacks (cairo_surface_t *abstract_surface, + double x_pixels_per_inch, + double y_pixels_per_inch) +{ + svg_target_closure_t *ptc = cairo_surface_get_user_data (abstract_surface, + &svg_closure_key); + + if (ptc->target) + abstract_surface = ptc->target; + + cairo_paginated_surface_t *paginated = (cairo_paginated_surface_t*) abstract_surface; + _cairo_svg_surface_set_force_fallbacks (paginated->target, TRUE); + cairo_surface_set_fallback_resolution (&paginated->base, + x_pixels_per_inch, + y_pixels_per_inch); +} + +static const cairo_boilerplate_target_t targets[] = { + /* It seems we should be able to round-trip SVG content perfectly + * through librsvg and cairo, but for some mysterious reason, some + * systems get an error of 1 for some pixels on some of the text + * tests. XXX: I'd still like to chase these down at some point. + * For now just set the svg error tolerance to 1. */ + { + "svg11", "svg", ".svg", NULL, + CAIRO_SURFACE_TYPE_SVG, CAIRO_CONTENT_COLOR_ALPHA, 1, + "cairo_svg_surface_create", + _cairo_boilerplate_svg11_create_surface, + cairo_surface_create_similar, + _cairo_boilerplate_svg_force_fallbacks, + _cairo_boilerplate_svg_finish_surface, + _cairo_boilerplate_svg_get_image_surface, + _cairo_boilerplate_svg_surface_write_to_png, + _cairo_boilerplate_svg_cleanup, + NULL, NULL, FALSE, TRUE, TRUE + }, + { + "svg11", "svg", ".svg", NULL, + CAIRO_SURFACE_TYPE_RECORDING, CAIRO_CONTENT_COLOR, 1, + "cairo_svg_surface_create", + _cairo_boilerplate_svg11_create_surface, + cairo_surface_create_similar, + _cairo_boilerplate_svg_force_fallbacks, + _cairo_boilerplate_svg_finish_surface, + _cairo_boilerplate_svg_get_image_surface, + _cairo_boilerplate_svg_surface_write_to_png, + _cairo_boilerplate_svg_cleanup, + NULL, NULL, FALSE, TRUE, TRUE + }, +}; +CAIRO_BOILERPLATE (svg, targets) + +#else + +CAIRO_NO_BOILERPLATE (svg) + +#endif diff --git a/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-system.c b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-system.c new file mode 100644 index 0000000000..e9bcd78c51 --- /dev/null +++ b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-system.c @@ -0,0 +1,164 @@ +/* + * Copyright © 2004 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-boilerplate.h" +#include "cairo-boilerplate-system.h" + +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include + +void * +xmalloc (size_t size) +{ + void *buf; + + if (size == 0) + return NULL; + + buf = malloc (size); + if (buf == NULL) { + fprintf (stderr, "Error: Out of memory. Exiting.\n"); + exit (1); + } + + return buf; +} + +void * +xcalloc (size_t nmemb, + size_t size) +{ + void *buf; + + if (nmemb == 0 || size == 0) + return NULL; + + buf = calloc (nmemb, size); + if (buf == NULL) { + fprintf (stderr, "Error: Out of memory. Exiting\n"); + exit (1); + } + + return buf; +} + +void * +xrealloc (void *buf, + size_t size) +{ + buf = realloc (buf, size); + if (buf == NULL && size != 0) { + fprintf (stderr, "Error: Out of memory. Exiting\n"); + exit (1); + } + + return buf; +} + +void +xasprintf (char **strp, + const char *fmt, + ...) +{ +#ifdef HAVE_VASPRINTF + va_list va; + int ret; + + va_start (va, fmt); + ret = vasprintf (strp, fmt, va); + va_end (va); + + if (ret < 0) { + fprintf (stderr, "Error: Out of memory. Exiting.\n"); + exit (1); + } +#else /* !HAVE_VASNPRINTF */ +#define BUF_SIZE 1024 + va_list va; + char buffer[BUF_SIZE]; + int ret, len; + + va_start (va, fmt); + ret = vsnprintf (buffer, sizeof (buffer), fmt, va); + va_end (va); + + if (ret < 0) { + fprintf (stderr, "Failure in vsnprintf\n"); + exit (1); + } + + len = (ret + sizeof (int)) & -sizeof (int); + *strp = malloc (len); + if (*strp == NULL) { + fprintf (stderr, "Out of memory\n"); + exit (1); + } + + if ((unsigned) ret < sizeof (buffer)) { + memcpy (*strp, buffer, ret); + } else { + va_start (va, fmt); + ret = vsnprintf (*strp, len, fmt, va); + va_end (va); + + if (ret >= len) { + free (*strp); + fprintf (stderr, "Overflowed dynamic buffer\n"); + exit (1); + } + } + memset (*strp + ret, 0, len-ret); +#endif /* !HAVE_VASNPRINTF */ +} + +void +xunlink (const char *pathname) +{ + if (unlink (pathname) < 0 && errno != ENOENT) { + fprintf (stderr, "Error: Cannot remove %s: %s\n", + pathname, strerror (errno)); + exit (1); + } +} + +char * +xstrdup (const char *str) +{ + if (str == NULL) + return NULL; + + str = strdup (str); + if (str == NULL) { + fprintf (stderr, "Error: Out of memory. Exiting.\n"); + exit (1); + } + + return (char *) str; +} diff --git a/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-system.h b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-system.h new file mode 100644 index 0000000000..28165671b3 --- /dev/null +++ b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-system.h @@ -0,0 +1,59 @@ +/* + * Copyright © 2004 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#ifndef _XMALLOC_H_ +#define _XMALLOC_H_ + +#include "cairo-boilerplate.h" + +#define xmalloc cairo_boilerplate_xmalloc +void * +xmalloc (size_t size); + +#define xcalloc cairo_boilerplate_xcalloc +void * +xcalloc (size_t nmemb, + size_t size); + +#define xrealloc cairo_boilerplate_xrealloc +void * +xrealloc (void *buf, + size_t size); + +#define xasprintf cairo_boilerplate_xasprintf +void +xasprintf (char **strp, + const char *fmt, + ...) CAIRO_BOILERPLATE_PRINTF_FORMAT(2, 3); + +#define xunlink cairo_boilerplate_xunlink +void +xunlink (const char *path); + +#define xstrdup cairo_boilerplate_xstrdup +char * +xstrdup (const char *str); + +#endif diff --git a/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-test-surfaces.c b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-test-surfaces.c new file mode 100644 index 0000000000..64e6697836 --- /dev/null +++ b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-test-surfaces.c @@ -0,0 +1,460 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright © 2004,2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-boilerplate-private.h" + +#include + +#include +#include +#if CAIRO_HAS_TEST_PAGINATED_SURFACE +#include +#endif + +static cairo_surface_t * +_cairo_boilerplate_test_base_compositor_create_surface (const char *name, + cairo_content_t content, + double width, + double height, + double max_width, + double max_height, + cairo_boilerplate_mode_t mode, + void **closure) +{ + *closure = NULL; + return _cairo_test_base_compositor_surface_create (content, ceil (width), ceil (height)); +} + + +static cairo_surface_t * +_cairo_boilerplate_test_fallback_compositor_create_surface (const char *name, + cairo_content_t content, + double width, + double height, + double max_width, + double max_height, + cairo_boilerplate_mode_t mode, + void **closure) +{ + *closure = NULL; + return _cairo_test_fallback_compositor_surface_create (content, ceil (width), ceil (height)); +} + +static cairo_surface_t * +_cairo_boilerplate_test_mask_compositor_create_surface (const char *name, + cairo_content_t content, + double width, + double height, + double max_width, + double max_height, + cairo_boilerplate_mode_t mode, + void **closure) +{ + *closure = NULL; + return _cairo_test_mask_compositor_surface_create (content, ceil (width), ceil (height)); +} + + +static cairo_surface_t * +_cairo_boilerplate_test_traps_compositor_create_surface (const char *name, + cairo_content_t content, + double width, + double height, + double max_width, + double max_height, + cairo_boilerplate_mode_t mode, + void **closure) +{ + *closure = NULL; + return _cairo_test_traps_compositor_surface_create (content, ceil (width), ceil (height)); +} + +static cairo_surface_t * +_cairo_boilerplate_test_spans_compositor_create_surface (const char *name, + cairo_content_t content, + double width, + double height, + double max_width, + double max_height, + cairo_boilerplate_mode_t mode, + void **closure) +{ + *closure = NULL; + return _cairo_test_spans_compositor_surface_create (content, ceil (width), ceil (height)); +} + +static cairo_surface_t * +_cairo_boilerplate_test_no_fallback_compositor_create_surface (const char *name, + cairo_content_t content, + double width, + double height, + double max_width, + double max_height, + cairo_boilerplate_mode_t mode, + void **closure) +{ + if (mode == CAIRO_BOILERPLATE_MODE_TEST) + return NULL; + + *closure = NULL; + return _cairo_test_no_fallback_compositor_surface_create (content, ceil (width), ceil (height)); +} + +static cairo_surface_t * +_cairo_boilerplate_test_no_traps_compositor_create_surface (const char *name, + cairo_content_t content, + double width, + double height, + double max_width, + double max_height, + cairo_boilerplate_mode_t mode, + void **closure) +{ + if (mode == CAIRO_BOILERPLATE_MODE_TEST) + return NULL; + + *closure = NULL; + return _cairo_test_no_traps_compositor_surface_create (content, ceil (width), ceil (height)); +} + +static cairo_surface_t * +_cairo_boilerplate_test_no_spans_compositor_create_surface (const char *name, + cairo_content_t content, + double width, + double height, + double max_width, + double max_height, + cairo_boilerplate_mode_t mode, + void **closure) +{ + if (mode == CAIRO_BOILERPLATE_MODE_TEST) + return NULL; + + *closure = NULL; + return _cairo_test_no_spans_compositor_surface_create (content, ceil (width), ceil (height)); +} + +#if CAIRO_HAS_TEST_PAGINATED_SURFACE +static const cairo_user_data_key_t test_paginated_closure_key; + +typedef struct { + cairo_surface_t *target; +} test_paginated_closure_t; + +static cairo_surface_t * +_cairo_boilerplate_test_paginated_create_surface (const char *name, + cairo_content_t content, + double width, + double height, + double max_width, + double max_height, + cairo_boilerplate_mode_t mode, + void **closure) +{ + test_paginated_closure_t *tpc; + cairo_format_t format; + cairo_surface_t *surface; + cairo_status_t status; + + *closure = tpc = xmalloc (sizeof (test_paginated_closure_t)); + + format = cairo_boilerplate_format_from_content (content); + tpc->target = cairo_image_surface_create (format, + ceil (width), ceil (height)); + + surface = _cairo_test_paginated_surface_create (tpc->target); + if (cairo_surface_status (surface)) + goto CLEANUP; + + status = cairo_surface_set_user_data (surface, + &test_paginated_closure_key, + tpc, NULL); + if (status == CAIRO_STATUS_SUCCESS) + return surface; + + cairo_surface_destroy (surface); + surface = cairo_boilerplate_surface_create_in_error (status); + + cairo_surface_destroy (tpc->target); + + CLEANUP: + free (tpc); + return surface; +} + +/* The only reason we go through all these machinations to write a PNG + * image is to _really ensure_ that the data actually landed in our + * buffer through the paginated surface to the test_paginated_surface. + * + * If we didn't implement this function then the default + * cairo_surface_write_to_png would result in the paginated_surface's + * acquire_source_image function replaying the recording-surface to an + * intermediate image surface. And in that case the + * test_paginated_surface would not be involved and wouldn't be + * tested. + */ +static cairo_status_t +_cairo_boilerplate_test_paginated_surface_write_to_png (cairo_surface_t *surface, + const char *filename) +{ + test_paginated_closure_t *tpc; + cairo_status_t status; + + /* show page first. the automatic show_page is too late for us */ + cairo_surface_show_page (surface); + status = cairo_surface_status (surface); + if (status) + return status; + + tpc = cairo_surface_get_user_data (surface, &test_paginated_closure_key); + return cairo_surface_write_to_png (tpc->target, filename); +} + +static cairo_surface_t * +_cairo_boilerplate_test_paginated_get_image_surface (cairo_surface_t *surface, + int page, + int width, + int height) +{ + test_paginated_closure_t *tpc; + cairo_status_t status; + + /* XXX separate finish as per PDF */ + if (page != 0) + return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + + /* show page first. the automatic show_page is too late for us */ + cairo_surface_show_page (surface); + status = cairo_surface_status (surface); + if (status) + return cairo_boilerplate_surface_create_in_error (status); + + tpc = cairo_surface_get_user_data (surface, &test_paginated_closure_key); + return _cairo_boilerplate_get_image_surface (tpc->target, 0, width, height); +} + +static void +_cairo_boilerplate_test_paginated_cleanup (void *closure) +{ + test_paginated_closure_t *tpc = closure; + + cairo_surface_destroy (tpc->target); + free (tpc); +} +#endif + +static const cairo_boilerplate_target_t targets[] = { + { + "test-base", "base", NULL, NULL, + CAIRO_SURFACE_TYPE_IMAGE, + CAIRO_CONTENT_COLOR_ALPHA, 0, + "_cairo_test_base_compositor_surface_create", + _cairo_boilerplate_test_base_compositor_create_surface, + cairo_surface_create_similar, + NULL, NULL, + _cairo_boilerplate_get_image_surface, + cairo_surface_write_to_png, + NULL, NULL, NULL, TRUE, FALSE, FALSE + }, + { + "test-base", "base", NULL, NULL, + CAIRO_SURFACE_TYPE_IMAGE, + CAIRO_CONTENT_COLOR, 0, + "_cairo_test_base_compositor_surface_create", + _cairo_boilerplate_test_base_compositor_create_surface, + cairo_surface_create_similar, + NULL, NULL, + _cairo_boilerplate_get_image_surface, + cairo_surface_write_to_png, + NULL, NULL, NULL, FALSE, FALSE, FALSE + }, + + { + "test-fallback", "image", NULL, NULL, + CAIRO_SURFACE_TYPE_IMAGE, + CAIRO_CONTENT_COLOR_ALPHA, 0, + "_cairo_test_fallback_compositor_surface_create", + _cairo_boilerplate_test_fallback_compositor_create_surface, + cairo_surface_create_similar, + NULL, NULL, + _cairo_boilerplate_get_image_surface, + cairo_surface_write_to_png, + NULL, NULL, NULL, FALSE, FALSE, FALSE + }, + { + "test-fallback", "image", NULL, NULL, + CAIRO_SURFACE_TYPE_IMAGE, + CAIRO_CONTENT_COLOR, 0, + "_cairo_test_fallback_compositor_surface_create", + _cairo_boilerplate_test_fallback_compositor_create_surface, + cairo_surface_create_similar, + NULL, NULL, + _cairo_boilerplate_get_image_surface, + cairo_surface_write_to_png, + NULL, NULL, NULL, FALSE, FALSE, FALSE + }, + + { + "test-mask", "mask", NULL, NULL, + CAIRO_SURFACE_TYPE_IMAGE, + CAIRO_CONTENT_COLOR_ALPHA, 0, + "_cairo_test_mask_compositor_surface_create", + _cairo_boilerplate_test_mask_compositor_create_surface, + cairo_surface_create_similar, + NULL, NULL, + _cairo_boilerplate_get_image_surface, + cairo_surface_write_to_png, + NULL, NULL, NULL, TRUE, FALSE, FALSE + }, + { + "test-mask", "mask", NULL, NULL, + CAIRO_SURFACE_TYPE_IMAGE, + CAIRO_CONTENT_COLOR, 0, + "_cairo_test_mask_compositor_surface_create", + _cairo_boilerplate_test_mask_compositor_create_surface, + cairo_surface_create_similar, + NULL, NULL, + _cairo_boilerplate_get_image_surface, + cairo_surface_write_to_png, + NULL, NULL, NULL, FALSE, FALSE, FALSE + }, + + { + "test-traps", "traps", NULL, NULL, + CAIRO_SURFACE_TYPE_IMAGE, + CAIRO_CONTENT_COLOR_ALPHA, 0, + "_cairo_test_traps_compositor_surface_create", + _cairo_boilerplate_test_traps_compositor_create_surface, + cairo_surface_create_similar, + NULL, NULL, + _cairo_boilerplate_get_image_surface, + cairo_surface_write_to_png, + NULL, NULL, NULL, TRUE, FALSE, FALSE + }, + { + "test-traps", "traps", NULL, NULL, + CAIRO_SURFACE_TYPE_IMAGE, + CAIRO_CONTENT_COLOR, 0, + "_cairo_test_traps_compositor_surface_create", + _cairo_boilerplate_test_traps_compositor_create_surface, + cairo_surface_create_similar, + NULL, NULL, + _cairo_boilerplate_get_image_surface, + cairo_surface_write_to_png, + NULL, NULL, NULL, FALSE, FALSE, FALSE + }, + + { + "test-spans", "spans", NULL, NULL, + CAIRO_SURFACE_TYPE_IMAGE, + CAIRO_CONTENT_COLOR_ALPHA, 0, + "_cairo_test_spans_compositor_surface_create", + _cairo_boilerplate_test_spans_compositor_create_surface, + cairo_surface_create_similar, + NULL, NULL, + _cairo_boilerplate_get_image_surface, + cairo_surface_write_to_png, + NULL, NULL, NULL, TRUE, FALSE, FALSE + }, + { + "test-spans", "spans", NULL, NULL, + CAIRO_SURFACE_TYPE_IMAGE, + CAIRO_CONTENT_COLOR, 0, + "_cairo_test_spans_compositor_surface_create", + _cairo_boilerplate_test_spans_compositor_create_surface, + cairo_surface_create_similar, + NULL, NULL, + _cairo_boilerplate_get_image_surface, + cairo_surface_write_to_png, + NULL, NULL, NULL, FALSE, FALSE, FALSE + }, + + { + "no-fallback", "image", NULL, NULL, + CAIRO_SURFACE_TYPE_IMAGE, + CAIRO_CONTENT_COLOR_ALPHA, 0, + "_cairo_test_no_fallback_compositor_surface_create", + _cairo_boilerplate_test_no_fallback_compositor_create_surface, + cairo_surface_create_similar, + NULL, NULL, + _cairo_boilerplate_get_image_surface, + cairo_surface_write_to_png, + NULL, NULL, NULL, FALSE, FALSE, FALSE + }, + { + "no-traps", "traps", NULL, NULL, + CAIRO_SURFACE_TYPE_IMAGE, + CAIRO_CONTENT_COLOR_ALPHA, 0, + "_cairo_test_no_traps_compositor_surface_create", + _cairo_boilerplate_test_no_traps_compositor_create_surface, + cairo_surface_create_similar, + NULL, NULL, + _cairo_boilerplate_get_image_surface, + cairo_surface_write_to_png, + NULL, NULL, NULL, TRUE, FALSE, FALSE + }, + { + "no-spans", "spans", NULL, NULL, + CAIRO_SURFACE_TYPE_IMAGE, + CAIRO_CONTENT_COLOR_ALPHA, 0, + "_cairo_test_no_spans_compositor_surface_create", + _cairo_boilerplate_test_no_spans_compositor_create_surface, + cairo_surface_create_similar, + NULL, NULL, + _cairo_boilerplate_get_image_surface, + cairo_surface_write_to_png, + NULL, NULL, NULL, TRUE, FALSE, FALSE + }, +#if CAIRO_HAS_TEST_PAGINATED_SURFACE + { + "test-paginated", "image", NULL, NULL, + CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED, + CAIRO_CONTENT_COLOR_ALPHA, 0, + "_cairo_test_paginated_surface_create", + _cairo_boilerplate_test_paginated_create_surface, + cairo_surface_create_similar, + NULL, NULL, + _cairo_boilerplate_test_paginated_get_image_surface, + _cairo_boilerplate_test_paginated_surface_write_to_png, + _cairo_boilerplate_test_paginated_cleanup, + NULL, NULL, FALSE, TRUE, FALSE + }, + { + "test-paginated", "image", NULL, NULL, + CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED, + CAIRO_CONTENT_COLOR, 0, + "_cairo_test_paginated_surface_create", + _cairo_boilerplate_test_paginated_create_surface, + cairo_surface_create_similar, + NULL, NULL, + _cairo_boilerplate_test_paginated_get_image_surface, + _cairo_boilerplate_test_paginated_surface_write_to_png, + _cairo_boilerplate_test_paginated_cleanup, + NULL, NULL, FALSE, TRUE, FALSE + }, +#endif +}; +CAIRO_BOILERPLATE (test, targets) diff --git a/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-win32-printing.c b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-win32-printing.c new file mode 100644 index 0000000000..9177480fc5 --- /dev/null +++ b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-win32-printing.c @@ -0,0 +1,361 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright © 2004,2006 Red Hat, Inc. + * Copyright © 2007, Adrian Johnson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Carl D. Worth + * Adrian Johnson + */ + +#include "cairo-boilerplate-private.h" +#include "cairo-malloc-private.h" + +#if CAIRO_CAN_TEST_WIN32_PRINTING_SURFACE + +#include +#include + +#include + +static cairo_user_data_key_t win32_closure_key; + +typedef struct _win32_target_closure { + char *filename; + int width; + int height; + cairo_surface_t *target; + HDC dc; + int left_margin; + int bottom_margin; +} win32_target_closure_t; + +static cairo_bool_t +printer_is_postscript_level_3 (HDC dc) +{ + DWORD word; + INT ps_feature, ps_level; + + word = PSIDENT_GDICENTRIC; + if (ExtEscape (dc, POSTSCRIPT_IDENTIFY, sizeof(DWORD), (char *)&word, 0, (char *)NULL) <= 0) + return FALSE; + + ps_feature = FEATURESETTING_PSLEVEL; + if (ExtEscape (dc, GET_PS_FEATURESETTING, sizeof(INT), + (char *)&ps_feature, sizeof(INT), (char *)&ps_level) <= 0) + return FALSE; + + if (ps_level >= 3) + return TRUE; + + return FALSE; +} + +static void +create_printer_dc (win32_target_closure_t *ptc) +{ + char *printer_name; + DWORD size; + int x_dpi, y_dpi, left_margin, top_margin, page_height, printable_height; + XFORM xform; + + ptc->dc = NULL; + GetDefaultPrinter (NULL, &size); + printer_name = _cairo_malloc (size); + + if (printer_name == NULL) + return; + + if (GetDefaultPrinter (printer_name, &size) == 0) { + free (printer_name); + return; + } + + /* printf("\nPrinting to : %s\n", printer_name); */ + ptc->dc = CreateDC (NULL, printer_name, NULL, NULL); + free (printer_name); + + if (!printer_is_postscript_level_3 (ptc->dc)) { + printf("The default printer driver must be a color PostScript level 3 printer\n"); + ptc->dc = NULL; + return; + } + + /* The printer device units on win32 are 1 unit == 1 dot and the + * origin is the start of the printable area. We transform the + * coordinate space to 1 unit is 1 point as expected by the + * tests. As the page size is larger than the test surface, the + * origin is translated down so that the each test is drawn at the + * bottom left corner of the page. This is because the bottom left + * corner of the PNG image that ghostscript creates is positioned + * at origin of the PS coordinates (ie the bottom left of the + * page). The left and bottom margins are stored in + * win32_target_closure as size of the PNG image needs to be + * increased because the test output is offset from the bottom + * left by the non printable margins. After the PNG is created the + * margins will be chopped off so the image matches the reference + * image. + */ + printable_height = GetDeviceCaps (ptc->dc, VERTRES); + x_dpi = GetDeviceCaps (ptc->dc, LOGPIXELSX); + y_dpi = GetDeviceCaps (ptc->dc, LOGPIXELSY); + left_margin = GetDeviceCaps (ptc->dc, PHYSICALOFFSETX); + top_margin = GetDeviceCaps (ptc->dc, PHYSICALOFFSETY); + page_height = GetDeviceCaps (ptc->dc, PHYSICALHEIGHT); + + SetGraphicsMode (ptc->dc, GM_ADVANCED); + xform.eM11 = x_dpi/72.0; + xform.eM12 = 0; + xform.eM21 = 0; + xform.eM22 = y_dpi/72.0; + xform.eDx = 0; + xform.eDy = printable_height - ptc->height*y_dpi/72.0; + if (!SetWorldTransform (ptc->dc, &xform)) { + fprintf (stderr, "%s:%s\n", "cairo-boilerplate-win32-printing", "SetWorldTransform"); + return; + } + + ptc->left_margin = 72.0*left_margin/x_dpi; + ptc->bottom_margin = 72.0*(page_height - printable_height - top_margin)/y_dpi; +} + +static cairo_surface_t * +_cairo_boilerplate_win32_printing_create_surface (const char *name, + cairo_content_t content, + double width, + double height, + double max_width, + double max_height, + cairo_boilerplate_mode_t mode, + void **closure) +{ + win32_target_closure_t *ptc; + cairo_surface_t *surface; + DOCINFO di; + + if (content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED) + content = CAIRO_CONTENT_COLOR_ALPHA; + + *closure = ptc = xmalloc (sizeof (win32_target_closure_t)); + + xasprintf (&ptc->filename, "%s.out.ps", name); + xunlink (ptc->filename); + + memset (&di, 0, sizeof (DOCINFO)); + di.cbSize = sizeof (DOCINFO); + di.lpszDocName = ptc->filename; + di.lpszOutput = ptc->filename; + + ptc->width = width; + ptc->height = height; + + create_printer_dc (ptc); + if (ptc->dc == NULL) { + printf("\nFailed to create printer\n"); + free (ptc->filename); + free (ptc); + return NULL; + } + StartDoc (ptc->dc, &di); + StartPage (ptc->dc); + surface = cairo_win32_printing_surface_create (ptc->dc); + if (cairo_surface_status (surface)) { + free (ptc->filename); + free (ptc); + return NULL; + } + cairo_surface_set_fallback_resolution (surface, 72., 72.); + + if (content == CAIRO_CONTENT_COLOR) { + ptc->target = surface; + surface = cairo_surface_create_similar (ptc->target, + CAIRO_CONTENT_COLOR, + width, height); + } else { + ptc->target = NULL; + } + + if (cairo_surface_set_user_data (surface, + &win32_closure_key, + ptc, + NULL) != CAIRO_STATUS_SUCCESS) { + cairo_surface_destroy (surface); + if (ptc->target != NULL) + cairo_surface_destroy (ptc->target); + free (ptc->filename); + free (ptc); + return NULL; + } + + return surface; +} + +static cairo_status_t +_cairo_boilerplate_win32_printing_surface_write_to_png (cairo_surface_t *surface, + const char *filename) +{ + win32_target_closure_t *ptc = cairo_surface_get_user_data (surface, &win32_closure_key); + char command[4096]; + cairo_surface_t *src_image, *dst_image; + cairo_t *cr; + cairo_status_t status; + + if (ptc->target) { + /* Both surface and ptc->target were originally created at the + * same dimensions. We want a 1:1 copy here, so we first clear any + * device offset and scale on surface. + * + * In a more realistic use case of device offsets, the target of + * this copying would be of a different size than the source, and + * the offset would be desirable during the copy operation. */ + double x_offset, y_offset; + double x_scale, y_scale; + cairo_surface_get_device_offset (surface, &x_offset, &y_offset); + cairo_surface_get_device_scale (surface, &x_scale, &y_scale); + cairo_surface_set_device_offset (surface, 0, 0); + cairo_surface_set_device_scale (surface, 1, 1); + cairo_t *cr; + cr = cairo_create (ptc->target); + cairo_set_source_surface (cr, surface, 0, 0); + cairo_paint (cr); + cairo_show_page (cr); + cairo_destroy (cr); + cairo_surface_set_device_offset (surface, x_offset, y_offset); + cairo_surface_set_device_scale (surface, x_scale, y_scale); + + cairo_surface_finish (surface); + surface = ptc->target; + } + + cairo_surface_finish (surface); + EndPage (ptc->dc); + EndDoc (ptc->dc); + sprintf (command, "gs -q -r72 -g%dx%d -dSAFER -dBATCH -dNOPAUSE -sDEVICE=pngalpha -sOutputFile=%s %s", + ptc->width + ptc->left_margin, ptc->height + ptc->bottom_margin, filename, ptc->filename); + + if (system (command) != 0) + return CAIRO_STATUS_WRITE_ERROR; + + /* Create a new image from the ghostscript image that has the + * left and bottom margins removed */ + + src_image = cairo_image_surface_create_from_png (filename); + status = cairo_surface_status (src_image); + if (status) + return status; + + dst_image = cairo_image_surface_create (CAIRO_FORMAT_RGB24, + ptc->width, + ptc->height); + cr = cairo_create (dst_image); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_surface (cr, src_image, -ptc->left_margin, 0); + cairo_paint (cr); + cairo_destroy (cr); + + cairo_surface_write_to_png (dst_image, filename); + status = cairo_surface_status (dst_image); + if (status) + return status; + + cairo_surface_destroy (src_image); + cairo_surface_destroy (dst_image); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_surface_t * +_cairo_boilerplate_win32_printing_get_image_surface (cairo_surface_t *surface, + int page, + int width, + int height) +{ + win32_target_closure_t *ptc = cairo_surface_get_user_data (surface, + &win32_closure_key); + char *filename; + cairo_status_t status; + + /* XXX test paginated interface */ + if (page != 0) + return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + + xasprintf (&filename, "%s.png", ptc->filename); + status = _cairo_boilerplate_win32_printing_surface_write_to_png (surface, filename); + if (status) + return cairo_boilerplate_surface_create_in_error (status); + + surface = cairo_boilerplate_get_image_surface_from_png (filename, + width, + height, + ptc->target == NULL); + + remove (filename); + free (filename); + + return surface; +} + +static void +_cairo_boilerplate_win32_printing_cleanup (void *closure) +{ + win32_target_closure_t *ptc = closure; + + if (ptc->target) + cairo_surface_destroy (ptc->target); + free (ptc->filename); + free (ptc); + DeleteDC (ptc->dc); +} + +static const cairo_boilerplate_target_t targets[] = { + { + "win32-printing", "win32", ".ps", NULL, + CAIRO_SURFACE_TYPE_WIN32_PRINTING, + CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED, 0, + "cairo_win32_printing_surface_create", + _cairo_boilerplate_win32_printing_create_surface, + cairo_surface_create_similar, + NULL, NULL, + _cairo_boilerplate_win32_printing_get_image_surface, + _cairo_boilerplate_win32_printing_surface_write_to_png, + _cairo_boilerplate_win32_printing_cleanup, + NULL, NULL, FALSE, TRUE, TRUE + }, + { + "win32-printing", "win32", ".ps", NULL, + CAIRO_SURFACE_TYPE_RECORDING, CAIRO_CONTENT_COLOR, 0, + "cairo_win32_printing_surface_create", + _cairo_boilerplate_win32_printing_create_surface, + cairo_surface_create_similar, + NULL, NULL, + _cairo_boilerplate_win32_printing_get_image_surface, + _cairo_boilerplate_win32_printing_surface_write_to_png, + _cairo_boilerplate_win32_printing_cleanup, + NULL, NULL, FALSE, TRUE, TRUE + }, +}; +CAIRO_BOILERPLATE (win32_printing, targets) + +#else + +CAIRO_NO_BOILERPLATE (win32_printing) + +#endif diff --git a/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-win32.c b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-win32.c new file mode 100644 index 0000000000..4b3eda9dda --- /dev/null +++ b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-win32.c @@ -0,0 +1,294 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright © 2004,2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-boilerplate-private.h" + +#include + +#include +#include + +static const cairo_user_data_key_t win32_closure_key; + +typedef struct _win32_target_closure { + HWND wnd; + HDC dc; + ATOM bpl_atom; + cairo_surface_t *surface; +} win32_target_closure_t; + +static void +_cairo_boilerplate_win32_cleanup_window_surface (void *closure) +{ + win32_target_closure_t *win32tc = closure; + + if (win32tc != NULL) + { + if (win32tc->wnd != NULL && + ReleaseDC (win32tc->wnd, win32tc->dc) != 1) + fprintf (stderr, + "Failed to release DC of a test window when cleaning up.\n"); + if (win32tc->wnd != NULL && + DestroyWindow (win32tc->wnd) == 0) + fprintf (stderr, + "Failed to destroy a test window when cleaning up, GLE is %lu.\n", + GetLastError ()); + if (win32tc->bpl_atom != 0 && + UnregisterClassA ((LPCSTR) MAKELPARAM (win32tc->bpl_atom, 0), GetModuleHandle (NULL)) == 0 && + GetLastError () != ERROR_CLASS_DOES_NOT_EXIST) + fprintf (stderr, + "Failed to unregister boilerplate window class, GLE is %lu.\n", + GetLastError ()); + + free (win32tc); + } +} + +static win32_target_closure_t * +_cairo_boilerplate_win32_create_window (int width, + int height) +{ + WNDCLASSEXA wincl; + win32_target_closure_t *win32tc; + LPCSTR window_class_name; + + ZeroMemory (&wincl, sizeof (WNDCLASSEXA)); + wincl.cbSize = sizeof (WNDCLASSEXA); + wincl.hInstance = GetModuleHandle (0); + wincl.lpszClassName = "cairo_boilerplate_win32_dummy"; + wincl.lpfnWndProc = DefWindowProcA; + wincl.style = CS_OWNDC; + + win32tc = calloc (1, sizeof (win32_target_closure_t)); + + if (win32tc == NULL) + { + int error = errno; + fprintf (stderr, "Ran out of memory: %d.\n", error); + return NULL; + } + + ZeroMemory (win32tc, sizeof (win32_target_closure_t)); + + win32tc->bpl_atom = RegisterClassExA (&wincl); + + if (win32tc->bpl_atom == 0 && GetLastError () != ERROR_CLASS_ALREADY_EXISTS) + { + fprintf (stderr, + "Failed to register a boilerplate window class, GLE is %lu.\n", + GetLastError ()); + _cairo_boilerplate_win32_cleanup_window_surface (win32tc); + return NULL; + } + + if (win32tc->bpl_atom == 0) + window_class_name = wincl.lpszClassName; + else + window_class_name = (LPCSTR) MAKELPARAM (win32tc->bpl_atom, 0); + + win32tc->wnd = CreateWindowExA (WS_EX_TOOLWINDOW, + window_class_name, + 0, + WS_POPUP, + 0, + 0, + width, + height, + 0, + 0, + 0, + 0); + + if (win32tc->wnd == NULL) + { + fprintf (stderr, + "Failed to create a test window, GLE is %lu.\n", + GetLastError ()); + _cairo_boilerplate_win32_cleanup_window_surface (win32tc); + return NULL; + } + + win32tc->dc = GetDC (win32tc->wnd); + + if (win32tc->dc == NULL) + { + fprintf (stderr, "Failed to get test window DC.\n"); + _cairo_boilerplate_win32_cleanup_window_surface (win32tc); + return NULL; + } + + SetWindowPos (win32tc->wnd, + HWND_BOTTOM, + INT_MIN, + INT_MIN, + width, + height, + SWP_NOACTIVATE | SWP_SHOWWINDOW); + + return win32tc; +} + +static cairo_surface_t * +_cairo_boilerplate_win32_create_window_surface (const char *name, + cairo_content_t content, + double width, + double height, + double max_width, + double max_height, + cairo_boilerplate_mode_t mode, + void **closure) +{ + win32_target_closure_t *win32tc; + cairo_surface_t *surface; + cairo_format_t format; + cairo_status_t status; + + win32tc = _cairo_boilerplate_win32_create_window (width, height); + + if (win32tc == NULL) + return NULL; + + format = cairo_boilerplate_format_from_content (content); + + surface = cairo_win32_surface_create_with_format (win32tc->dc, format); + + win32tc->surface = surface; + + status = cairo_surface_status (surface); + + if (status != CAIRO_STATUS_SUCCESS) + { + fprintf (stderr, + "Failed to create the test surface: %s [%d].\n", + cairo_status_to_string (status), status); + _cairo_boilerplate_win32_cleanup_window_surface (win32tc); + return NULL; + } + + status = cairo_surface_set_user_data (surface, &win32_closure_key, win32tc, NULL); + + if (status != CAIRO_STATUS_SUCCESS) + { + fprintf (stderr, + "Failed to set surface userdata: %s [%d].\n", + cairo_status_to_string (status), status); + + cairo_surface_destroy (surface); + _cairo_boilerplate_win32_cleanup_window_surface (win32tc); + + return NULL; + } + + *closure = win32tc; + + return surface; +} + +static cairo_surface_t * +_cairo_boilerplate_win32_create_dib_surface (const char *name, + cairo_content_t content, + double width, + double height, + double max_width, + double max_height, + cairo_boilerplate_mode_t mode, + void **closure) +{ + cairo_format_t format; + + format = cairo_boilerplate_format_from_content (content); + + *closure = NULL; + + return cairo_win32_surface_create_with_dib (format, width, height); +} + +static const cairo_boilerplate_target_t targets[] = { + { + "win32", "win32", NULL, NULL, + CAIRO_SURFACE_TYPE_WIN32, CAIRO_CONTENT_COLOR, 0, + "cairo_win32_surface_create_with_dib", + _cairo_boilerplate_win32_create_dib_surface, + cairo_surface_create_similar, + NULL, + NULL, + _cairo_boilerplate_get_image_surface, + cairo_surface_write_to_png, + NULL, + NULL, + NULL, + TRUE, FALSE, FALSE + }, + /* Testing the win32 surface isn't interesting, since for + * ARGB images it just chains to the image backend + */ + { + "win32", "win32", NULL, NULL, + CAIRO_SURFACE_TYPE_WIN32, CAIRO_CONTENT_COLOR_ALPHA, 0, + "cairo_win32_surface_create_with_dib", + _cairo_boilerplate_win32_create_dib_surface, + cairo_surface_create_similar, + NULL, + NULL, + _cairo_boilerplate_get_image_surface, + cairo_surface_write_to_png, + NULL, + NULL, + NULL, + FALSE, FALSE, FALSE + }, + { + "win32-window-color", "win32", NULL, NULL, + CAIRO_SURFACE_TYPE_WIN32, CAIRO_CONTENT_COLOR, 1, + "cairo_win32_surface_create", + _cairo_boilerplate_win32_create_window_surface, + cairo_surface_create_similar, + NULL, + NULL, + _cairo_boilerplate_get_image_surface, + cairo_surface_write_to_png, + _cairo_boilerplate_win32_cleanup_window_surface, + NULL, + NULL, + FALSE, FALSE, FALSE + }, + { + "win32-window-coloralpha", "win32", NULL, NULL, + CAIRO_SURFACE_TYPE_WIN32, CAIRO_CONTENT_COLOR_ALPHA, 1, + "cairo_win32_surface_create_with_format", + _cairo_boilerplate_win32_create_window_surface, + cairo_surface_create_similar, + NULL, + NULL, + _cairo_boilerplate_get_image_surface, + cairo_surface_write_to_png, + _cairo_boilerplate_win32_cleanup_window_surface, + NULL, + NULL, + FALSE, FALSE, FALSE + }, +}; +CAIRO_BOILERPLATE (win32, targets) diff --git a/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-xcb.c b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-xcb.c new file mode 100644 index 0000000000..d54c0b54b0 --- /dev/null +++ b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-xcb.c @@ -0,0 +1,885 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright © 2004,2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-boilerplate-private.h" +#include "cairo-malloc-private.h" + +#include + +#include + +/* Errors have response_type == 0 */ +#define CAIRO_XCB_ERROR 0 + +static const cairo_user_data_key_t xcb_closure_key; + +typedef struct _xcb_target_closure { + xcb_connection_t *c; + cairo_device_t *device; + uint32_t drawable; + cairo_bool_t is_pixmap; + cairo_surface_t *surface; +} xcb_target_closure_t; + +static cairo_status_t +_cairo_boilerplate_xcb_handle_errors (xcb_target_closure_t *xtc) +{ + xcb_generic_event_t *ev = NULL; + + /* Ignore all MappingNotify events; those might happen without us causing them */ + do { + free(ev); + ev = xcb_poll_for_event(xtc->c); + } while (ev != NULL && ev->response_type == XCB_MAPPING_NOTIFY); + + if (ev != NULL) { + if (ev->response_type == CAIRO_XCB_ERROR) { + xcb_generic_error_t *error = (xcb_generic_error_t *) ev; + + fprintf (stderr, + "Detected error during xcb run: error=%d, " + "seqno=0x%02x, major=%d, minor=%d\n", + error->error_code, error->sequence, + error->major_code, error->minor_code); + } else { + fprintf (stderr, + "Detected unexpected event during xcb run: type=%d, seqno=0x%02x\n", + ev->response_type, ev->sequence); + } + free (ev); + + /* Silently discard all following errors */ + while ((ev = xcb_poll_for_event (xtc->c)) != NULL) + free (ev); + + return CAIRO_STATUS_WRITE_ERROR; + } + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_boilerplate_xcb_sync_server (xcb_target_closure_t *xtc) +{ + free (xcb_get_input_focus_reply (xtc->c, + xcb_get_input_focus (xtc->c), NULL)); +} + +static void +_cairo_boilerplate_xcb_setup_test_surface (cairo_surface_t *surface) +{ + + /* For testing purposes, tell the X server to strictly adhere to the + * Render specification. + */ + cairo_xcb_device_debug_set_precision(cairo_surface_get_device(surface), + XCB_RENDER_POLY_MODE_PRECISE); +} + +static void +_cairo_boilerplate_xcb_cleanup (void *closure) +{ + xcb_target_closure_t *xtc = closure; + cairo_status_t status; + + cairo_surface_finish (xtc->surface); + if (xtc->is_pixmap) + xcb_free_pixmap (xtc->c, xtc->drawable); + else + xcb_destroy_window (xtc->c, xtc->drawable); + cairo_surface_destroy (xtc->surface); + + cairo_device_finish (xtc->device); + cairo_device_destroy (xtc->device); + + /* First synchronize with the X server to make sure there are no more errors + * in-flight which we would miss otherwise */ + _cairo_boilerplate_xcb_sync_server (xtc); + status = _cairo_boilerplate_xcb_handle_errors (xtc); + assert (status == CAIRO_STATUS_SUCCESS); + + xcb_disconnect (xtc->c); + + free (xtc); +} + +static void +_cairo_boilerplate_xcb_synchronize (void *closure) +{ + xcb_target_closure_t *xtc = closure; + cairo_status_t status; + free (xcb_get_image_reply (xtc->c, + xcb_get_image (xtc->c, XCB_IMAGE_FORMAT_Z_PIXMAP, + xtc->drawable, 0, 0, 1, 1, /* AllPlanes */ -1), + 0)); + + status = _cairo_boilerplate_xcb_handle_errors (xtc); + assert (status == CAIRO_STATUS_SUCCESS); +} + +static xcb_render_pictforminfo_t * +find_depth (xcb_connection_t *connection, + int depth, + void **formats_out) +{ + xcb_render_query_pict_formats_reply_t *formats; + xcb_render_query_pict_formats_cookie_t cookie; + xcb_render_pictforminfo_iterator_t i; + + cookie = xcb_render_query_pict_formats (connection); + xcb_flush (connection); + + formats = xcb_render_query_pict_formats_reply (connection, cookie, 0); + if (formats == NULL) + return NULL; + + for (i = xcb_render_query_pict_formats_formats_iterator (formats); + i.rem; + xcb_render_pictforminfo_next (&i)) + { + if (XCB_RENDER_PICT_TYPE_DIRECT != i.data->type) + continue; + + if (depth != i.data->depth) + continue; + + *formats_out = formats; + return i.data; + } + + free (formats); + return NULL; +} + +static const cairo_user_data_key_t key; +static const cairo_user_data_key_t key2; + +struct similar { + xcb_connection_t *connection; + xcb_drawable_t pixmap; +}; + +static void _destroy_similar (void *closure) +{ + struct similar *similar = closure; + + xcb_free_pixmap (similar->connection, similar->pixmap); + free (similar); +} + +struct xcb_info { + xcb_render_query_pict_formats_reply_t *formats; + xcb_render_pictforminfo_t *render_format[3]; +}; + +static cairo_surface_t * +_cairo_boilerplate_xcb_create_similar (cairo_surface_t *other, + cairo_content_t content, + int width, int height) +{ + cairo_device_t *device = cairo_surface_get_device (other); + struct xcb_info *info = cairo_device_get_user_data (device, &key); + xcb_screen_t *root; + cairo_surface_t *surface; + struct similar *similar; + xcb_render_pictforminfo_t *render_format; + int depth; + + similar = _cairo_malloc (sizeof (*similar)); + + switch (content) { + default: + case CAIRO_CONTENT_COLOR_ALPHA: + depth = 32; + render_format = info->render_format[0]; + break; + case CAIRO_CONTENT_COLOR: + depth = 24; + render_format = info->render_format[1]; + break; + case CAIRO_CONTENT_ALPHA: + depth = 8; + render_format = info->render_format[2]; + break; + } + + similar->connection = + cairo_xcb_device_get_connection (cairo_surface_get_device(other)); + similar->pixmap = xcb_generate_id (similar->connection); + + root = xcb_setup_roots_iterator(xcb_get_setup(similar->connection)).data; + xcb_create_pixmap (similar->connection, depth, + similar->pixmap, root->root, + width, height); + + surface = cairo_xcb_surface_create_with_xrender_format (similar->connection, + root, + similar->pixmap, + render_format, + width, height); + cairo_surface_set_user_data (surface, &key, similar, _destroy_similar); + + return surface; +} + +static cairo_surface_t * +_cairo_boilerplate_xcb_create_surface (const char *name, + cairo_content_t content, + double width, + double height, + double max_width, + double max_height, + cairo_boilerplate_mode_t mode, + void **closure) +{ + xcb_screen_t *root; + xcb_target_closure_t *xtc; + xcb_connection_t *c; + xcb_render_query_pict_formats_cookie_t formats_cookie; + xcb_render_pictforminfo_t *render_format; + xcb_render_pictforminfo_iterator_t i; + struct xcb_info *info; + int depth; + xcb_void_cookie_t cookie; + cairo_surface_t *surface; + cairo_status_t status; + + *closure = xtc = xmalloc (sizeof (xcb_target_closure_t)); + info = xcalloc (1, sizeof (struct xcb_info)); + + if (width == 0) + width = 1; + if (height == 0) + height = 1; + + xtc->c = c = xcb_connect(NULL,NULL); + if (c == NULL || xcb_connection_has_error(c)) { + free (xtc); + free (info); + return NULL; + } + + root = xcb_setup_roots_iterator(xcb_get_setup(c)).data; + formats_cookie = xcb_render_query_pict_formats (c); + + xtc->surface = NULL; + xtc->is_pixmap = TRUE; + xtc->drawable = xcb_generate_id (c); + switch (content) { + case CAIRO_CONTENT_COLOR: + depth = 24; + break; + + case CAIRO_CONTENT_COLOR_ALPHA: + depth = 32; + break; + + case CAIRO_CONTENT_ALPHA: /* would be XCB_PICT_STANDARD_A_8 */ + default: + xcb_disconnect (c); + free (xtc); + return NULL; + } + + cookie = xcb_create_pixmap_checked (c, depth, + xtc->drawable, root->root, + width, height); + + /* slow, but sure */ + if (xcb_request_check (c, cookie) != NULL) { + xcb_disconnect (c); + free (xtc); + free (info); + return NULL; + } + + info->formats = xcb_render_query_pict_formats_reply (c, formats_cookie, 0); + if (info->formats == NULL) { + xcb_disconnect (c); + free (xtc); + free (info); + return NULL; + } + + for (i = xcb_render_query_pict_formats_formats_iterator (info->formats); + i.rem; + xcb_render_pictforminfo_next (&i)) + { + if (XCB_RENDER_PICT_TYPE_DIRECT != i.data->type) + continue; + + if (i.data->depth == 32) { + if (info->render_format[0] == 0) + info->render_format[0] = i.data; + } else if (i.data->depth == 24) { + if (info->render_format[1] == 0) + info->render_format[1] = i.data; + } else if (i.data->depth == 8) { + if (info->render_format[2] == 0) + info->render_format[2] = i.data; + } + } + + assert (info->render_format[0]); + assert (info->render_format[1]); + assert (info->render_format[2]); + + switch (content) { + default: + case CAIRO_CONTENT_COLOR_ALPHA: + render_format = info->render_format[0]; + break; + + case CAIRO_CONTENT_COLOR: + render_format = info->render_format[1]; + break; + + case CAIRO_CONTENT_ALPHA: /* would be XCB_PICT_STANDARD_A_8 */ + render_format = info->render_format[2]; + break; + } + + surface = cairo_xcb_surface_create_with_xrender_format (c, root, + xtc->drawable, + render_format, + width, height); + cairo_device_set_user_data (cairo_surface_get_device (surface), &key, info, free); + cairo_device_set_user_data (cairo_surface_get_device (surface), &key2, info->formats, free); + if (mode != CAIRO_BOILERPLATE_MODE_PERF) + _cairo_boilerplate_xcb_setup_test_surface(surface); + + xtc->device = cairo_device_reference (cairo_surface_get_device (surface)); + status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL); + if (status == CAIRO_STATUS_SUCCESS) + return surface; + + cairo_surface_destroy (surface); + + _cairo_boilerplate_xcb_cleanup (xtc); + return cairo_boilerplate_surface_create_in_error (status); +} + +static xcb_visualtype_t * +lookup_visual (xcb_screen_t *s, + xcb_visualid_t visual) +{ + xcb_depth_iterator_t d; + + d = xcb_screen_allowed_depths_iterator (s); + for (; d.rem; xcb_depth_next (&d)) { + xcb_visualtype_iterator_t v = xcb_depth_visuals_iterator (d.data); + for (; v.rem; xcb_visualtype_next (&v)) { + if (v.data->visual_id == visual) + return v.data; + } + } + + return 0; +} + +static cairo_surface_t * +_cairo_boilerplate_xcb_create_window (const char *name, + cairo_content_t content, + double width, + double height, + double max_width, + double max_height, + cairo_boilerplate_mode_t mode, + void **closure) +{ + xcb_target_closure_t *xtc; + xcb_connection_t *c; + xcb_screen_t *s; + xcb_void_cookie_t cookie; + cairo_surface_t *surface; + cairo_status_t status; + uint32_t values[] = { 1 }; + + *closure = xtc = xmalloc (sizeof (xcb_target_closure_t)); + + if (width == 0) + width = 1; + if (height == 0) + height = 1; + + xtc->c = c = xcb_connect(NULL,NULL); + if (xcb_connection_has_error(c)) { + free (xtc); + return NULL; + } + + xtc->surface = NULL; + + s = xcb_setup_roots_iterator (xcb_get_setup (c)).data; + if (width > s->width_in_pixels || height > s->height_in_pixels) { + xcb_disconnect (c); + free (xtc); + return NULL; + } + + xtc->is_pixmap = FALSE; + xtc->drawable = xcb_generate_id (c); + cookie = xcb_create_window_checked (c, + s->root_depth, + xtc->drawable, + s->root, + 0, 0, width, height, 0, + XCB_WINDOW_CLASS_INPUT_OUTPUT, + s->root_visual, + XCB_CW_OVERRIDE_REDIRECT, + values); + xcb_map_window (c, xtc->drawable); + + /* slow, but sure */ + if (xcb_request_check (c, cookie) != NULL) { + xcb_disconnect (c); + free (xtc); + return NULL; + } + + surface = cairo_xcb_surface_create (c, + xtc->drawable, + lookup_visual (s, s->root_visual), + width, height); + + xtc->device = cairo_device_reference (cairo_surface_get_device (surface)); + status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL); + if (status == CAIRO_STATUS_SUCCESS) + return surface; + + cairo_surface_destroy (surface); + + _cairo_boilerplate_xcb_cleanup (xtc); + return cairo_boilerplate_surface_create_in_error (status); +} + +static cairo_surface_t * +_cairo_boilerplate_xcb_create_window_db (const char *name, + cairo_content_t content, + double width, + double height, + double max_width, + double max_height, + cairo_boilerplate_mode_t mode, + void **closure) +{ + xcb_target_closure_t *xtc; + xcb_connection_t *c; + xcb_screen_t *s; + xcb_void_cookie_t cookie; + cairo_surface_t *surface; + cairo_status_t status; + uint32_t values[] = { 1 }; + + *closure = xtc = xmalloc (sizeof (xcb_target_closure_t)); + + if (width == 0) + width = 1; + if (height == 0) + height = 1; + + xtc->c = c = xcb_connect(NULL,NULL); + if (xcb_connection_has_error(c)) { + free (xtc); + return NULL; + } + + xtc->surface = NULL; + + s = xcb_setup_roots_iterator (xcb_get_setup (c)).data; + if (width > s->width_in_pixels || height > s->height_in_pixels) { + xcb_disconnect (c); + free (xtc); + return NULL; + } + + xtc->is_pixmap = FALSE; + xtc->drawable = xcb_generate_id (c); + cookie = xcb_create_window_checked (c, + s->root_depth, + xtc->drawable, + s->root, + 0, 0, width, height, 0, + XCB_WINDOW_CLASS_INPUT_OUTPUT, + s->root_visual, + XCB_CW_OVERRIDE_REDIRECT, + values); + xcb_map_window (c, xtc->drawable); + + /* slow, but sure */ + if (xcb_request_check (c, cookie) != NULL) { + xcb_disconnect (c); + free (xtc); + return NULL; + } + + xtc->surface = cairo_xcb_surface_create (c, + xtc->drawable, + lookup_visual (s, s->root_visual), + width, height); + surface = cairo_surface_create_similar (xtc->surface, content, width, height); + + xtc->device = cairo_device_reference (cairo_surface_get_device (surface)); + status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL); + if (status == CAIRO_STATUS_SUCCESS) + return surface; + + cairo_surface_destroy (surface); + + _cairo_boilerplate_xcb_cleanup (xtc); + return cairo_boilerplate_surface_create_in_error (status); +} + +static cairo_surface_t * +_cairo_boilerplate_xcb_create_render_0_0 (const char *name, + cairo_content_t content, + double width, + double height, + double max_width, + double max_height, + cairo_boilerplate_mode_t mode, + void **closure) +{ + xcb_screen_t *root; + xcb_target_closure_t *xtc; + xcb_connection_t *c; + xcb_render_pictforminfo_t *render_format; + int depth; + xcb_void_cookie_t cookie; + cairo_surface_t *surface; + cairo_status_t status; + void *formats; + + *closure = xtc = xmalloc (sizeof (xcb_target_closure_t)); + + if (width == 0) + width = 1; + if (height == 0) + height = 1; + + xtc->c = c = xcb_connect(NULL,NULL); + if (xcb_connection_has_error(c)) { + free (xtc); + return NULL; + } + + root = xcb_setup_roots_iterator(xcb_get_setup(c)).data; + + xtc->surface = NULL; + xtc->is_pixmap = TRUE; + xtc->drawable = xcb_generate_id (c); + switch (content) { + case CAIRO_CONTENT_COLOR: + depth = 24; + cookie = xcb_create_pixmap_checked (c, depth, + xtc->drawable, root->root, + width, height); + break; + + case CAIRO_CONTENT_COLOR_ALPHA: + depth = 32; + cookie = xcb_create_pixmap_checked (c, depth, + xtc->drawable, root->root, + width, height); + break; + + case CAIRO_CONTENT_ALPHA: /* would be XCB_PICT_STANDARD_A_8 */ + default: + xcb_disconnect (c); + free (xtc); + return NULL; + } + + /* slow, but sure */ + if (xcb_request_check (c, cookie) != NULL) { + xcb_disconnect (c); + free (xtc); + return NULL; + } + xcb_flush (c); + + render_format = find_depth (c, depth, &formats); + if (render_format == NULL) { + xcb_disconnect (c); + free (xtc); + return NULL; + } + + surface = cairo_xcb_surface_create_with_xrender_format (c, root, + xtc->drawable, + render_format, + width, height); + free (formats); + if (cairo_surface_status (surface)) { + xcb_disconnect (c); + free (xtc); + return surface; + } + + xtc->device = cairo_device_reference (cairo_surface_get_device (surface)); + cairo_xcb_device_debug_cap_xrender_version (xtc->device, 0, 0); + + assert (cairo_surface_get_device (surface) == xtc->device); + + status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL); + if (status == CAIRO_STATUS_SUCCESS) + return surface; + + cairo_surface_destroy (surface); + + _cairo_boilerplate_xcb_cleanup (xtc); + return cairo_boilerplate_surface_create_in_error (status); +} + +static cairo_surface_t * +_cairo_boilerplate_xcb_create_fallback (const char *name, + cairo_content_t content, + double width, + double height, + double max_width, + double max_height, + cairo_boilerplate_mode_t mode, + void **closure) +{ + xcb_target_closure_t *xtc; + xcb_connection_t *c; + xcb_screen_t *s; + xcb_void_cookie_t cookie; + cairo_surface_t *surface; + cairo_status_t status; + uint32_t values[] = { 1 }; + + *closure = xtc = xmalloc (sizeof (xcb_target_closure_t)); + + if (width == 0) + width = 1; + if (height == 0) + height = 1; + + xtc->c = c = xcb_connect (NULL,NULL); + if (xcb_connection_has_error(c)) { + free (xtc); + return NULL; + } + + s = xcb_setup_roots_iterator (xcb_get_setup (c)).data; + if (width > s->width_in_pixels || height > s->height_in_pixels) { + xcb_disconnect (c); + free (xtc); + return NULL; + } + + xtc->surface = NULL; + xtc->is_pixmap = FALSE; + xtc->drawable = xcb_generate_id (c); + cookie = xcb_create_window_checked (c, + s->root_depth, + xtc->drawable, + s->root, + 0, 0, width, height, 0, + XCB_WINDOW_CLASS_INPUT_OUTPUT, + s->root_visual, + XCB_CW_OVERRIDE_REDIRECT, + values); + xcb_map_window (c, xtc->drawable); + + /* slow, but sure */ + if (xcb_request_check (c, cookie) != NULL) { + xcb_disconnect (c); + free (xtc); + return NULL; + } + + surface = cairo_xcb_surface_create (c, + xtc->drawable, + lookup_visual (s, s->root_visual), + width, height); + if (cairo_surface_status (surface)) { + xcb_disconnect (c); + free (xtc); + return surface; + } + + cairo_xcb_device_debug_cap_xrender_version (cairo_surface_get_device (surface), + -1, -1); + + xtc->device = cairo_device_reference (cairo_surface_get_device (surface)); + status = cairo_surface_set_user_data (surface, &xcb_closure_key, xtc, NULL); + if (status == CAIRO_STATUS_SUCCESS) + return surface; + + cairo_surface_destroy (surface); + + _cairo_boilerplate_xcb_cleanup (xtc); + return cairo_boilerplate_surface_create_in_error (status); +} + +static cairo_status_t +_cairo_boilerplate_xcb_finish_surface (cairo_surface_t *surface) +{ + xcb_target_closure_t *xtc = cairo_surface_get_user_data (surface, + &xcb_closure_key); + cairo_status_t status; + + if (xtc->surface != NULL) { + cairo_t *cr; + + cr = cairo_create (xtc->surface); + cairo_set_source_surface (cr, surface, 0, 0); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_paint (cr); + cairo_destroy (cr); + + surface = xtc->surface; + } + + cairo_surface_flush (surface); + if (cairo_surface_status (surface)) + return cairo_surface_status (surface); + + /* First synchronize with the X server to make sure there are no more errors + * in-flight which we would miss otherwise */ + _cairo_boilerplate_xcb_sync_server (xtc); + status = _cairo_boilerplate_xcb_handle_errors (xtc); + if (status) + return status; + + if (xcb_connection_has_error (xtc->c)) + return CAIRO_STATUS_WRITE_ERROR; + + return CAIRO_STATUS_SUCCESS; +} + +static const cairo_boilerplate_target_t targets[] = { + /* Acceleration architectures may make the results differ by a + * bit, so we set the error tolerance to 1. */ + { + "xcb", "traps", NULL, NULL, + CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR_ALPHA, 1, + "cairo_xcb_surface_create_with_xrender_format", + _cairo_boilerplate_xcb_create_surface, + _cairo_boilerplate_xcb_create_similar, + NULL, + _cairo_boilerplate_xcb_finish_surface, + _cairo_boilerplate_get_image_surface, + cairo_surface_write_to_png, + _cairo_boilerplate_xcb_cleanup, + _cairo_boilerplate_xcb_synchronize, + NULL, + TRUE, FALSE, FALSE + }, + { + "xcb", "traps", NULL, NULL, + CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR, 1, + "cairo_xcb_surface_create_with_xrender_format", + _cairo_boilerplate_xcb_create_surface, + _cairo_boilerplate_xcb_create_similar, + NULL, + _cairo_boilerplate_xcb_finish_surface, + _cairo_boilerplate_get_image_surface, + cairo_surface_write_to_png, + _cairo_boilerplate_xcb_cleanup, + _cairo_boilerplate_xcb_synchronize, + NULL, + FALSE, FALSE, FALSE + }, + { + "xcb-window", "traps", NULL, NULL, + CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR, 1, + "cairo_xcb_surface_create_with_xrender_format", + _cairo_boilerplate_xcb_create_window, + _cairo_boilerplate_xcb_create_similar, + NULL, + _cairo_boilerplate_xcb_finish_surface, + _cairo_boilerplate_get_image_surface, + cairo_surface_write_to_png, + _cairo_boilerplate_xcb_cleanup, + _cairo_boilerplate_xcb_synchronize, + NULL, + FALSE, FALSE, FALSE + }, + { + "xcb-window&", "traps", NULL, NULL, + CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR, 1, + "cairo_xcb_surface_create_with_xrender_format", + _cairo_boilerplate_xcb_create_window_db, + _cairo_boilerplate_xcb_create_similar, + NULL, + _cairo_boilerplate_xcb_finish_surface, + _cairo_boilerplate_get_image_surface, + cairo_surface_write_to_png, + _cairo_boilerplate_xcb_cleanup, + _cairo_boilerplate_xcb_synchronize, + NULL, + FALSE, FALSE, FALSE + }, + { + "xcb-render-0_0", "xlib-fallback", NULL, NULL, + CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR_ALPHA, 1, + "cairo_xcb_surface_create_with_xrender_format", + _cairo_boilerplate_xcb_create_render_0_0, + cairo_surface_create_similar, + NULL, + _cairo_boilerplate_xcb_finish_surface, + _cairo_boilerplate_get_image_surface, + cairo_surface_write_to_png, + _cairo_boilerplate_xcb_cleanup, + _cairo_boilerplate_xcb_synchronize, + NULL, + FALSE, FALSE, FALSE + }, + { + "xcb-render-0_0", "xlib-fallback", NULL, NULL, + CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR, 1, + "cairo_xcb_surface_create_with_xrender_format", + _cairo_boilerplate_xcb_create_render_0_0, + cairo_surface_create_similar, + NULL, + _cairo_boilerplate_xcb_finish_surface, + _cairo_boilerplate_get_image_surface, + cairo_surface_write_to_png, + _cairo_boilerplate_xcb_cleanup, + _cairo_boilerplate_xcb_synchronize, + NULL, + FALSE, FALSE, FALSE + }, + { + "xcb-fallback", "xlib-fallback", NULL, NULL, + CAIRO_SURFACE_TYPE_XCB, CAIRO_CONTENT_COLOR, 1, + "cairo_xcb_surface_create_with_xrender_format", + _cairo_boilerplate_xcb_create_fallback, + cairo_surface_create_similar, + NULL, + _cairo_boilerplate_xcb_finish_surface, + _cairo_boilerplate_get_image_surface, + cairo_surface_write_to_png, + _cairo_boilerplate_xcb_cleanup, + _cairo_boilerplate_xcb_synchronize, + NULL, + FALSE, FALSE, FALSE + }, +}; +CAIRO_BOILERPLATE (xcb, targets) diff --git a/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-xlib.c b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-xlib.c new file mode 100644 index 0000000000..5d2498ccd8 --- /dev/null +++ b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-xlib.c @@ -0,0 +1,639 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright © 2004,2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-boilerplate-private.h" +#include "cairo-boilerplate-xlib.h" +#include "cairo-malloc-private.h" + +#include +#if CAIRO_HAS_XLIB_XRENDER_SURFACE +#include +#endif + +#include /* for XDestroyImage */ + +#if !CAIRO_HAS_XLIB_XRENDER_SURFACE +#define PolyModePrecise 0 +#endif + +static const cairo_user_data_key_t key; + +typedef struct _xlib_target_closure { + Display *dpy; + Drawable drawable; + cairo_bool_t drawable_is_pixmap; +} xlib_target_closure_t; + +static void +_cairo_boilerplate_xlib_cleanup (void *closure) +{ + xlib_target_closure_t *xtc = closure; + + if (xtc->drawable) { + if (xtc->drawable_is_pixmap) + XFreePixmap (xtc->dpy, xtc->drawable); + else + XDestroyWindow (xtc->dpy, xtc->drawable); + } + XCloseDisplay (xtc->dpy); + free (xtc); +} + +static void +_cairo_boilerplate_xlib_synchronize (void *closure) +{ + xlib_target_closure_t *xtc = closure; + XImage *ximage; + + ximage = XGetImage (xtc->dpy, xtc->drawable, + 0, 0, 1, 1, AllPlanes, ZPixmap); + if (ximage != NULL) + XDestroyImage (ximage); +} + +static cairo_bool_t +_cairo_boilerplate_xlib_check_screen_size (Display *dpy, + int screen, + int width, + int height) +{ + Screen *scr = XScreenOfDisplay (dpy, screen); + return width <= WidthOfScreen (scr) && height <= HeightOfScreen (scr); +} + +static void +_cairo_boilerplate_xlib_setup_test_surface (cairo_surface_t *surface) +{ + + /* For testing purposes, tell the X server to strictly adhere to the + * Render specification. + */ + cairo_xlib_device_debug_set_precision(cairo_surface_get_device(surface), + PolyModePrecise); +} + + +#if CAIRO_HAS_XLIB_XRENDER_SURFACE +/* For the xlib backend we distinguish between TEST and PERF mode in a + * couple of ways. + * + * For TEST, we always test against pixmaps of depth 32 (for + * COLOR_ALPHA) or 24 (for COLOR) and we use XSynchronize to make it + * easier to debug problems. + * + * For PERF, we test against 32-bit pixmaps for COLOR_ALPHA, but for + * COLOR we test against _windows_ at the depth of the default visual. + * For obvious reasons, we don't use XSynchronize. + */ +static cairo_surface_t * +_cairo_boilerplate_xlib_test_create_surface (Display *dpy, + cairo_content_t content, + int width, + int height, + xlib_target_closure_t *xtc) +{ + XRenderPictFormat *xrender_format; + cairo_surface_t *surface; + + /* This kills performance, but it makes debugging much + * easier. That's why we have it here when in TEST mode, but not + * over in PERF mode. */ + XSynchronize (xtc->dpy, 1); + + /* XXX: Currently we don't do any xlib testing when the X server + * doesn't have the Render extension. We could do better here, + * (perhaps by converting the tests from ARGB32 to RGB24). One + * step better would be to always test the non-Render fallbacks + * for each test even if the server does have the Render + * extension. That would probably be through another + * cairo_boilerplate_target which would use an extended version of + * cairo_test_xlib_disable_render. */ + switch (content) { + case CAIRO_CONTENT_COLOR_ALPHA: + xrender_format = XRenderFindStandardFormat (dpy, PictStandardARGB32); + break; + case CAIRO_CONTENT_COLOR: + xrender_format = XRenderFindStandardFormat (dpy, PictStandardRGB24); + break; + case CAIRO_CONTENT_ALPHA: + default: + CAIRO_BOILERPLATE_DEBUG (("Invalid content for xlib test: %d\n", content)); + return NULL; + } + if (xrender_format == NULL) { + CAIRO_BOILERPLATE_DEBUG (("X server does not have the Render extension.\n")); + return NULL; + } + + xtc->drawable = XCreatePixmap (dpy, DefaultRootWindow (dpy), + width, height, xrender_format->depth); + xtc->drawable_is_pixmap = TRUE; + + surface = cairo_xlib_surface_create_with_xrender_format (dpy, xtc->drawable, + DefaultScreenOfDisplay (dpy), + xrender_format, + width, height); + + _cairo_boilerplate_xlib_setup_test_surface(surface); + + return surface; +} + +static cairo_surface_t * +_cairo_boilerplate_xlib_perf_create_surface (Display *dpy, + cairo_content_t content, + int width, + int height, + xlib_target_closure_t *xtc) +{ + XSetWindowAttributes attr; + XRenderPictFormat *xrender_format; + Visual *visual; + + switch (content) { + case CAIRO_CONTENT_COLOR_ALPHA: + xrender_format = XRenderFindStandardFormat (dpy, PictStandardARGB32); + if (xrender_format == NULL) { + CAIRO_BOILERPLATE_DEBUG (("X server does not have the Render extension.\n")); + return NULL; + } + + xtc->drawable = XCreatePixmap (dpy, DefaultRootWindow (dpy), + width, height, xrender_format->depth); + xtc->drawable_is_pixmap = TRUE; + break; + + case CAIRO_CONTENT_COLOR: + if (! _cairo_boilerplate_xlib_check_screen_size (dpy, + DefaultScreen (dpy), + width, height)) { + CAIRO_BOILERPLATE_DEBUG (("Surface is larger than the Screen.\n")); + return NULL; + } + + visual = DefaultVisual (dpy, DefaultScreen (dpy)); + xrender_format = XRenderFindVisualFormat (dpy, visual); + if (xrender_format == NULL) { + CAIRO_BOILERPLATE_DEBUG (("X server does not have the Render extension.\n")); + return NULL; + } + + attr.override_redirect = True; + xtc->drawable = XCreateWindow (dpy, DefaultRootWindow (dpy), 0, 0, + width, height, 0, xrender_format->depth, + InputOutput, visual, CWOverrideRedirect, &attr); + XMapWindow (dpy, xtc->drawable); + xtc->drawable_is_pixmap = FALSE; + break; + + case CAIRO_CONTENT_ALPHA: + default: + CAIRO_BOILERPLATE_DEBUG (("Invalid content for xlib test: %d\n", content)); + return NULL; + } + + return cairo_xlib_surface_create_with_xrender_format (dpy, xtc->drawable, + DefaultScreenOfDisplay (dpy), + xrender_format, + width, height); +} + +struct similar { + Display *dpy; + Pixmap pixmap; +}; + +static void _destroy_similar (void *closure) +{ + struct similar *similar = closure; + + XFreePixmap (similar->dpy, similar->pixmap); + free (similar); +} + +static cairo_surface_t * +_cairo_boilerplate_xlib_create_similar (cairo_surface_t *other, + cairo_content_t content, + int width, + int height) +{ + XRenderPictFormat *xrender_format; + uint32_t format; + struct similar *similar; + cairo_surface_t *surface; + + similar = _cairo_malloc (sizeof (*similar)); + similar->dpy = cairo_xlib_surface_get_display (other); + + switch (content) { + case CAIRO_CONTENT_COLOR: + format = PictStandardRGB24; + break; + case CAIRO_CONTENT_ALPHA: + format = PictStandardA8; + break; + case CAIRO_CONTENT_COLOR_ALPHA: + default: + format = PictStandardARGB32; + break; + } + + xrender_format = XRenderFindStandardFormat (similar->dpy, format); + similar->pixmap = XCreatePixmap (similar->dpy, + DefaultRootWindow (similar->dpy), + width, height, + xrender_format->depth); + + surface = + cairo_xlib_surface_create_with_xrender_format (similar->dpy, + similar->pixmap, + DefaultScreenOfDisplay (similar->dpy), + xrender_format, + width, height); + + cairo_surface_set_user_data (surface, &key, similar, _destroy_similar); + + return surface; +} + +static cairo_surface_t * +_cairo_boilerplate_xlib_create_surface (const char *name, + cairo_content_t content, + double width, + double height, + double max_width, + double max_height, + cairo_boilerplate_mode_t mode, + void **closure) +{ + xlib_target_closure_t *xtc; + Display *dpy; + cairo_surface_t *surface; + + *closure = xtc = xcalloc (1, sizeof (xlib_target_closure_t)); + + width = ceil (width); + if (width < 1) + width = 1; + + height = ceil (height); + if (height < 1) + height = 1; + + xtc->dpy = dpy = XOpenDisplay (NULL); + if (xtc->dpy == NULL) { + free (xtc); + CAIRO_BOILERPLATE_DEBUG (("Failed to open display: %s\n", XDisplayName(0))); + return NULL; + } + + if (mode == CAIRO_BOILERPLATE_MODE_TEST) + surface = _cairo_boilerplate_xlib_test_create_surface (dpy, content, width, height, xtc); + else /* mode == CAIRO_BOILERPLATE_MODE_PERF */ + surface = _cairo_boilerplate_xlib_perf_create_surface (dpy, content, width, height, xtc); + + if (surface == NULL || cairo_surface_status (surface)) + _cairo_boilerplate_xlib_cleanup (xtc); + + return surface; +} + +static cairo_surface_t * +_cairo_boilerplate_xlib_render_0_0_create_surface (const char *name, + cairo_content_t content, + double width, + double height, + double max_width, + double max_height, + cairo_boilerplate_mode_t mode, + void **closure) +{ + xlib_target_closure_t *xtc; + Display *dpy; + int screen; + Pixmap pixmap; + cairo_surface_t *surface, *dummy; + + *closure = xtc = xcalloc (1, sizeof (xlib_target_closure_t)); + + width = ceil (width); + if (width < 1) + width = 1; + + height = ceil (height); + if (height < 1) + height = 1; + + xtc->dpy = dpy = XOpenDisplay (NULL); + if (xtc->dpy == NULL) { + free (xtc); + CAIRO_BOILERPLATE_DEBUG (("Failed to open display: %s\n", XDisplayName(0))); + return NULL; + } + + + screen = DefaultScreen (dpy); + pixmap = XCreatePixmap (dpy, DefaultRootWindow (dpy), 1, 1, + DefaultDepth (dpy, screen)); + dummy = cairo_xlib_surface_create (dpy, pixmap, + DefaultVisual (dpy, screen), + 1, 1); + cairo_xlib_device_debug_cap_xrender_version (cairo_surface_get_device (dummy), + 0, 0); + + if (mode == CAIRO_BOILERPLATE_MODE_TEST) + surface = _cairo_boilerplate_xlib_test_create_surface (dpy, content, width, height, xtc); + else /* mode == CAIRO_BOILERPLATE_MODE_PERF */ + surface = _cairo_boilerplate_xlib_perf_create_surface (dpy, content, width, height, xtc); + + cairo_surface_destroy (dummy); + XFreePixmap (dpy, pixmap); + + if (surface == NULL || cairo_surface_status (surface)) + _cairo_boilerplate_xlib_cleanup (xtc); + + return surface; +} + +static cairo_surface_t * +_cairo_boilerplate_xlib_window_create_surface (const char *name, + cairo_content_t content, + double width, + double height, + double max_width, + double max_height, + cairo_boilerplate_mode_t mode, + void **closure) +{ + xlib_target_closure_t *xtc; + Display *dpy; + int screen; + XSetWindowAttributes attr; + cairo_surface_t *surface; + + /* We're not yet bothering to support perf mode for the + * xlib-fallback surface. */ + if (mode == CAIRO_BOILERPLATE_MODE_PERF) + return NULL; + + /* We also don't support drawing with destination-alpha in the + * xlib-fallback surface. */ + if (content == CAIRO_CONTENT_COLOR_ALPHA) + return NULL; + + *closure = xtc = xmalloc (sizeof (xlib_target_closure_t)); + + width = ceil (width); + if (width < 1) + width = 1; + + height = ceil (height); + if (height < 1) + height = 1; + + xtc->dpy = dpy = XOpenDisplay (NULL); + if (xtc->dpy == NULL) { + CAIRO_BOILERPLATE_DEBUG (("Failed to open display: %s\n", XDisplayName(0))); + free (xtc); + return NULL; + } + + /* This kills performance, but it makes debugging much + * easier. That's why we have it here only after explicitly not + * supporting PERF mode.*/ + XSynchronize (dpy, 1); + + screen = DefaultScreen (dpy); + if (! _cairo_boilerplate_xlib_check_screen_size (dpy, screen, + width, height)) { + CAIRO_BOILERPLATE_DEBUG (("Surface is larger than the Screen.\n")); + XCloseDisplay (dpy); + free (xtc); + return NULL; + } + + attr.override_redirect = True; + xtc->drawable = XCreateWindow (dpy, DefaultRootWindow (dpy), + 0, 0, + width, height, 0, + DefaultDepth (dpy, screen), + InputOutput, + DefaultVisual (dpy, screen), + CWOverrideRedirect, &attr); + XMapWindow (dpy, xtc->drawable); + xtc->drawable_is_pixmap = FALSE; + + surface = cairo_xlib_surface_create (dpy, xtc->drawable, + DefaultVisual (dpy, screen), + width, height); + if (cairo_surface_status (surface)) + _cairo_boilerplate_xlib_cleanup (xtc); + + _cairo_boilerplate_xlib_setup_test_surface(surface); + + return surface; +} +#endif + + +#if CAIRO_HAS_XLIB_SURFACE +/* The xlib-fallback target differs from the xlib target in two ways: + * + * 1. It creates its surfaces without relying on the Render extension + * + * 2. It disables use of the Render extension for its surfaces + * + * This provides testing of the non-Render fallback paths we have in + * cairo-xlib-surface.c + */ +static cairo_surface_t * +_cairo_boilerplate_xlib_fallback_create_surface (const char *name, + cairo_content_t content, + double width, + double height, + double max_width, + double max_height, + cairo_boilerplate_mode_t mode, + void **closure) +{ + xlib_target_closure_t *xtc; + Display *dpy; + int screen; + XSetWindowAttributes attr; + cairo_surface_t *surface, *dummy; + + /* We're not yet bothering to support perf mode for the + * xlib-fallback surface. */ + if (mode == CAIRO_BOILERPLATE_MODE_PERF) + return NULL; + + /* We also don't support drawing with destination-alpha in the + * xlib-fallback surface. */ + if (content == CAIRO_CONTENT_COLOR_ALPHA) + return NULL; + + *closure = xtc = xmalloc (sizeof (xlib_target_closure_t)); + + width = ceil (width); + if (width < 1) + width = 1; + + height = ceil (height); + if (height < 1) + height = 1; + + xtc->dpy = dpy = XOpenDisplay (NULL); + if (xtc->dpy == NULL) { + CAIRO_BOILERPLATE_DEBUG (("Failed to open display: %s\n", XDisplayName(0))); + free (xtc); + return NULL; + } + + /* This kills performance, but it makes debugging much + * easier. That's why we have it here only after explicitly not + * supporting PERF mode.*/ + XSynchronize (dpy, 1); + + screen = DefaultScreen (dpy); + if (! _cairo_boilerplate_xlib_check_screen_size (dpy, screen, + width, height)) { + CAIRO_BOILERPLATE_DEBUG (("Surface is larger than the Screen.\n")); + XCloseDisplay (dpy); + free (xtc); + return NULL; + } + + attr.override_redirect = True; + xtc->drawable = XCreateWindow (dpy, DefaultRootWindow (dpy), + 0, 0, + width, height, 0, + DefaultDepth (dpy, screen), + InputOutput, + DefaultVisual (dpy, screen), + CWOverrideRedirect, &attr); + XMapWindow (dpy, xtc->drawable); + xtc->drawable_is_pixmap = FALSE; + + dummy = cairo_xlib_surface_create (dpy, xtc->drawable, + DefaultVisual (dpy, screen), + width, height); + cairo_xlib_device_debug_cap_xrender_version (cairo_surface_get_device (dummy), + -1, -1); + + surface = cairo_xlib_surface_create (dpy, xtc->drawable, + DefaultVisual (dpy, screen), + width, height); + cairo_surface_destroy (dummy); + if (cairo_surface_status (surface)) + _cairo_boilerplate_xlib_cleanup (xtc); + + _cairo_boilerplate_xlib_setup_test_surface(surface); + + return surface; +} +#endif + +static const cairo_boilerplate_target_t targets[] = { +#if CAIRO_HAS_XLIB_XRENDER_SURFACE + /* Acceleration architectures may make the results differ by a + * bit, so we set the error tolerance to 1. */ + { + "xlib", "traps", NULL, "xlib-fallback", + CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR_ALPHA, 1, + "cairo_xlib_surface_create_with_xrender_format", + _cairo_boilerplate_xlib_create_surface, + _cairo_boilerplate_xlib_create_similar, + NULL, NULL, + _cairo_boilerplate_get_image_surface, + cairo_surface_write_to_png, + _cairo_boilerplate_xlib_cleanup, + _cairo_boilerplate_xlib_synchronize, + NULL, + TRUE, FALSE, FALSE + }, + { + "xlib", "traps", NULL, "xlib-fallback", + CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR, 1, + "cairo_xlib_surface_create_with_xrender_format", + _cairo_boilerplate_xlib_create_surface, + _cairo_boilerplate_xlib_create_similar, + NULL, NULL, + _cairo_boilerplate_get_image_surface, + cairo_surface_write_to_png, + _cairo_boilerplate_xlib_cleanup, + _cairo_boilerplate_xlib_synchronize, + NULL, + FALSE, FALSE, FALSE + }, + { + "xlib-window", "traps", NULL, NULL, + CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR, 1, + "cairo_xlib_surface_create", + _cairo_boilerplate_xlib_window_create_surface, + cairo_surface_create_similar, + NULL, NULL, + _cairo_boilerplate_get_image_surface, + cairo_surface_write_to_png, + _cairo_boilerplate_xlib_cleanup, + _cairo_boilerplate_xlib_synchronize, + NULL, + FALSE, FALSE, FALSE + }, + { + "xlib-render-0_0", "mask", NULL, NULL, + CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR, 1, + "cairo_xlib_surface_create", + _cairo_boilerplate_xlib_render_0_0_create_surface, + cairo_surface_create_similar, + NULL, NULL, + _cairo_boilerplate_get_image_surface, + cairo_surface_write_to_png, + _cairo_boilerplate_xlib_cleanup, + _cairo_boilerplate_xlib_synchronize, + NULL, + FALSE, FALSE, FALSE + }, +#endif +#if CAIRO_HAS_XLIB_SURFACE + /* This is a fallback surface which uses xlib fallbacks instead of + * the Render extension. */ + { + "xlib-fallback", "image", NULL, NULL, + CAIRO_SURFACE_TYPE_XLIB, CAIRO_CONTENT_COLOR, 1, + "cairo_xlib_surface_create", + _cairo_boilerplate_xlib_fallback_create_surface, + cairo_surface_create_similar, + NULL, NULL, + _cairo_boilerplate_get_image_surface, + cairo_surface_write_to_png, + _cairo_boilerplate_xlib_cleanup, + _cairo_boilerplate_xlib_synchronize, + NULL, + FALSE, FALSE, FALSE + }, +#endif +}; +CAIRO_BOILERPLATE (xlib, targets) diff --git a/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-xlib.h b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-xlib.h new file mode 100644 index 0000000000..9a63918121 --- /dev/null +++ b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate-xlib.h @@ -0,0 +1,33 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright © 2007 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Behdad Esfahbod + */ + +#ifndef _CAIRO_BOILERPLATE_XLIB_H_ +#define _CAIRO_BOILERPLATE_XLIB_H_ + +cairo_status_t +cairo_boilerplate_xlib_surface_disable_render (cairo_surface_t *surface); + +#endif diff --git a/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate.c b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate.c new file mode 100644 index 0000000000..a3e710f083 --- /dev/null +++ b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate.c @@ -0,0 +1,1106 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright © 2004,2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-boilerplate-private.h" +#include "cairo-boilerplate-scaled-font.h" +#include "cairo-malloc-private.h" + +#include + +#include +#include +#include + +#if CAIRO_HAS_SCRIPT_SURFACE +#include +#endif + +#include +#include +#include +#include + +#if HAVE_DLFCN_H +#include +#endif + +#if HAVE_UNISTD_H && HAVE_FCNTL_H && HAVE_SIGNAL_H && HAVE_SYS_STAT_H && HAVE_SYS_SOCKET_H && HAVE_SYS_UN_H +#include +#include +#include +#include +#include +#include + +#define HAS_DAEMON 1 +#define SOCKET_PATH "./.any2ppm" +#endif + +cairo_content_t +cairo_boilerplate_content (cairo_content_t content) +{ + if (content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED) + content = CAIRO_CONTENT_COLOR_ALPHA; + + return content; +} + +const char * +cairo_boilerplate_content_name (cairo_content_t content) +{ + /* For the purpose of the content name, we don't distinguish the + * flattened content value. + */ + switch (cairo_boilerplate_content (content)) { + case CAIRO_CONTENT_COLOR: + return "rgb24"; + case CAIRO_CONTENT_COLOR_ALPHA: + return "argb32"; + case CAIRO_CONTENT_ALPHA: + default: + assert (0); /* not reached */ + return "---"; + } +} + +static const char * +_cairo_boilerplate_content_visible_name (cairo_content_t content) +{ + switch (cairo_boilerplate_content (content)) { + case CAIRO_CONTENT_COLOR: + return "rgb"; + case CAIRO_CONTENT_COLOR_ALPHA: + return "rgba"; + case CAIRO_CONTENT_ALPHA: + return "a"; + default: + assert (0); /* not reached */ + return "---"; + } +} + +cairo_format_t +cairo_boilerplate_format_from_content (cairo_content_t content) +{ + cairo_format_t format; + + switch (content) { + case CAIRO_CONTENT_COLOR: + format = CAIRO_FORMAT_RGB24; + break; + case CAIRO_CONTENT_COLOR_ALPHA: + format = CAIRO_FORMAT_ARGB32; + break; + case CAIRO_CONTENT_ALPHA: + format = CAIRO_FORMAT_A8; + break; + default: + assert (0); /* not reached */ + format = CAIRO_FORMAT_INVALID; + break; + } + + return format; +} + +static cairo_surface_t * +_cairo_boilerplate_image_create_surface (const char *name, + cairo_content_t content, + double width, + double height, + double max_width, + double max_height, + cairo_boilerplate_mode_t mode, + void **closure) +{ + cairo_format_t format; + + *closure = NULL; + + if (content == CAIRO_CONTENT_COLOR_ALPHA) { + format = CAIRO_FORMAT_ARGB32; + } else if (content == CAIRO_CONTENT_COLOR) { + format = CAIRO_FORMAT_RGB24; + } else { + assert (0); /* not reached */ + return NULL; + } + + return cairo_image_surface_create (format, ceil (width), ceil (height)); +} + +static const cairo_user_data_key_t key; + +static cairo_surface_t * +_cairo_boilerplate_image_create_similar (cairo_surface_t *other, + cairo_content_t content, + int width, int height) +{ + cairo_format_t format; + cairo_surface_t *surface; + int stride; + void *ptr; + + switch (content) { + case CAIRO_CONTENT_ALPHA: + format = CAIRO_FORMAT_A8; + break; + case CAIRO_CONTENT_COLOR: + format = CAIRO_FORMAT_RGB24; + break; + case CAIRO_CONTENT_COLOR_ALPHA: + default: + format = CAIRO_FORMAT_ARGB32; + break; + } + + stride = cairo_format_stride_for_width(format, width); + ptr = _cairo_malloc (stride * height); + + surface = cairo_image_surface_create_for_data (ptr, format, + width, height, stride); + cairo_surface_set_user_data (surface, &key, ptr, free); + + return surface; +} + +static cairo_surface_t * +_cairo_boilerplate_image16_create_surface (const char *name, + cairo_content_t content, + double width, + double height, + double max_width, + double max_height, + cairo_boilerplate_mode_t mode, + void **closure) +{ + *closure = NULL; + + /* XXX force CAIRO_CONTENT_COLOR */ + return cairo_image_surface_create (CAIRO_FORMAT_RGB16_565, ceil (width), ceil (height)); +} + +static cairo_surface_t * +_cairo_boilerplate_image16_create_similar (cairo_surface_t *other, + cairo_content_t content, + int width, int height) +{ + cairo_format_t format; + cairo_surface_t *surface; + int stride; + void *ptr; + + switch (content) { + case CAIRO_CONTENT_ALPHA: + format = CAIRO_FORMAT_A8; + break; + case CAIRO_CONTENT_COLOR: + format = CAIRO_FORMAT_RGB16_565; + break; + case CAIRO_CONTENT_COLOR_ALPHA: + default: + format = CAIRO_FORMAT_ARGB32; + break; + } + + stride = cairo_format_stride_for_width(format, width); + ptr = _cairo_malloc (stride * height); + + surface = cairo_image_surface_create_for_data (ptr, format, + width, height, stride); + cairo_surface_set_user_data (surface, &key, ptr, free); + + return surface; +} + +static char * +_cairo_boilerplate_image_describe (void *closure) +{ + char *s; + + xasprintf (&s, "pixman %s", pixman_version_string ()); + + return s; +} + +#if CAIRO_HAS_RECORDING_SURFACE +static cairo_surface_t * +_cairo_boilerplate_recording_create_surface (const char *name, + cairo_content_t content, + double width, + double height, + double max_width, + double max_height, + cairo_boilerplate_mode_t mode, + void **closure) +{ + cairo_rectangle_t extents; + + extents.x = 0; + extents.y = 0; + extents.width = width; + extents.height = height; + return *closure = cairo_surface_reference (cairo_recording_surface_create (content, &extents)); +} + +static void +_cairo_boilerplate_recording_surface_cleanup (void *closure) +{ + cairo_surface_finish (closure); + cairo_surface_destroy (closure); +} +#endif + +const cairo_user_data_key_t cairo_boilerplate_output_basename_key; + +cairo_surface_t * +_cairo_boilerplate_get_image_surface (cairo_surface_t *src, + int page, + int width, + int height) +{ + cairo_surface_t *surface, *image; + cairo_t *cr; + cairo_status_t status; + cairo_format_t format; + + if (cairo_surface_status (src)) + return cairo_surface_reference (src); + + if (page != 0) + return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + + /* extract sub-surface */ + switch (cairo_surface_get_content (src)) { + case CAIRO_CONTENT_ALPHA: + format = CAIRO_FORMAT_A8; + break; + case CAIRO_CONTENT_COLOR: + format = CAIRO_FORMAT_RGB24; + break; + default: + case CAIRO_CONTENT_COLOR_ALPHA: + format = CAIRO_FORMAT_ARGB32; + break; + } + surface = cairo_image_surface_create (format, width, height); + assert (cairo_surface_get_content (surface) == cairo_surface_get_content (src)); + image = cairo_surface_reference (surface); + + /* open a logging channel (only interesting for recording surfaces) */ +#if CAIRO_HAS_SCRIPT_SURFACE && CAIRO_HAS_RECORDING_SURFACE + if (cairo_surface_get_type (src) == CAIRO_SURFACE_TYPE_RECORDING) { + const char *test_name; + + test_name = cairo_surface_get_user_data (src, + &cairo_boilerplate_output_basename_key); + if (test_name != NULL) { + cairo_device_t *ctx; + char *filename; + + cairo_surface_destroy (surface); + + xasprintf (&filename, "%s.out.trace", test_name); + ctx = cairo_script_create (filename); + surface = cairo_script_surface_create_for_target (ctx, image); + cairo_device_destroy (ctx); + free (filename); + } + } +#endif + + cr = cairo_create (surface); + cairo_surface_destroy (surface); + cairo_set_source_surface (cr, src, 0, 0); + cairo_paint (cr); + + status = cairo_status (cr); + if (status) { + cairo_surface_destroy (image); + image = cairo_surface_reference (cairo_get_target (cr)); + } + cairo_destroy (cr); + + return image; +} + +cairo_surface_t * +cairo_boilerplate_get_image_surface_from_png (const char *filename, + int width, + int height, + cairo_bool_t flatten) +{ + cairo_surface_t *surface; + + surface = cairo_image_surface_create_from_png (filename); + if (cairo_surface_status (surface)) + return surface; + + if (flatten) { + cairo_t *cr; + cairo_surface_t *flattened; + + flattened = cairo_image_surface_create (cairo_image_surface_get_format (surface), + width, + height); + cr = cairo_create (flattened); + cairo_surface_destroy (flattened); + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_set_source_surface (cr, surface, + width - cairo_image_surface_get_width (surface), + height - cairo_image_surface_get_height (surface)); + cairo_paint (cr); + + cairo_surface_destroy (surface); + surface = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + } else if (cairo_image_surface_get_width (surface) != width || + cairo_image_surface_get_height (surface) != height) + { + cairo_t *cr; + cairo_surface_t *sub; + + sub = cairo_image_surface_create (cairo_image_surface_get_format (surface), + width, + height); + cr = cairo_create (sub); + cairo_surface_destroy (sub); + + cairo_set_source_surface (cr, surface, + width - cairo_image_surface_get_width (surface), + height - cairo_image_surface_get_height (surface)); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_paint (cr); + + cairo_surface_destroy (surface); + surface = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + } + + return surface; +} + +static const cairo_boilerplate_target_t builtin_targets[] = { + /* I'm uncompromising about leaving the image backend as 0 + * for tolerance. There shouldn't ever be anything that is out of + * our control here. */ + { + "image", "image", NULL, NULL, + CAIRO_SURFACE_TYPE_IMAGE, CAIRO_CONTENT_COLOR_ALPHA, 0, + NULL, + _cairo_boilerplate_image_create_surface, + _cairo_boilerplate_image_create_similar, + NULL, NULL, + _cairo_boilerplate_get_image_surface, + cairo_surface_write_to_png, + NULL, NULL, + _cairo_boilerplate_image_describe, + TRUE, FALSE, FALSE + }, + { + "image", "image", NULL, NULL, + CAIRO_SURFACE_TYPE_IMAGE, CAIRO_CONTENT_COLOR, 0, + NULL, + _cairo_boilerplate_image_create_surface, + _cairo_boilerplate_image_create_similar, + NULL, NULL, + _cairo_boilerplate_get_image_surface, + cairo_surface_write_to_png, + NULL, NULL, + _cairo_boilerplate_image_describe, + FALSE, FALSE, FALSE + }, + { + "image16", "image", NULL, NULL, + CAIRO_SURFACE_TYPE_IMAGE, CAIRO_CONTENT_COLOR, 0, + NULL, + _cairo_boilerplate_image16_create_surface, + _cairo_boilerplate_image16_create_similar, + NULL, NULL, + _cairo_boilerplate_get_image_surface, + cairo_surface_write_to_png, + NULL, NULL, + _cairo_boilerplate_image_describe, + TRUE, FALSE, FALSE + }, +#if CAIRO_HAS_RECORDING_SURFACE + { + "recording", "image", NULL, NULL, + CAIRO_SURFACE_TYPE_RECORDING, CAIRO_CONTENT_COLOR_ALPHA, 0, + "cairo_recording_surface_create", + _cairo_boilerplate_recording_create_surface, + cairo_surface_create_similar, + NULL, NULL, + _cairo_boilerplate_get_image_surface, + cairo_surface_write_to_png, + _cairo_boilerplate_recording_surface_cleanup, + NULL, NULL, + FALSE, FALSE, TRUE + }, + { + "recording", "image", NULL, NULL, + CAIRO_SURFACE_TYPE_RECORDING, CAIRO_CONTENT_COLOR, 0, + "cairo_recording_surface_create", + _cairo_boilerplate_recording_create_surface, + cairo_surface_create_similar, + NULL, NULL, + _cairo_boilerplate_get_image_surface, + cairo_surface_write_to_png, + _cairo_boilerplate_recording_surface_cleanup, + NULL, NULL, + FALSE, FALSE, TRUE + }, +#endif +}; +CAIRO_BOILERPLATE (builtin, builtin_targets) + +static struct cairo_boilerplate_target_list { + struct cairo_boilerplate_target_list *next; + const cairo_boilerplate_target_t *target; +} *cairo_boilerplate_targets; + +static cairo_bool_t +probe_target (const cairo_boilerplate_target_t *target) +{ + if (target->probe == NULL) + return TRUE; + +#if HAVE_DLSYM + return dlsym (NULL, target->probe) != NULL; +#else + return TRUE; +#endif +} + +void +_cairo_boilerplate_register_backend (const cairo_boilerplate_target_t *targets, + unsigned int count) +{ + targets += count; + while (count--) { + struct cairo_boilerplate_target_list *list; + + --targets; + if (! probe_target (targets)) + continue; + + list = xmalloc (sizeof (*list)); + list->next = cairo_boilerplate_targets; + list->target = targets; + cairo_boilerplate_targets = list; + } +} + +static cairo_bool_t +_cairo_boilerplate_target_format_matches_name (const cairo_boilerplate_target_t *target, + const char *tcontent_name, + const char *tcontent_end) +{ + char const *content_name; + const char *content_end = tcontent_end; + size_t content_len; + + content_name = _cairo_boilerplate_content_visible_name (target->content); + if (tcontent_end) + content_len = content_end - tcontent_name; + else + content_len = strlen(tcontent_name); + if (strlen(content_name) != content_len) + return FALSE; + if (0 == strncmp (content_name, tcontent_name, content_len)) + return TRUE; + + return FALSE; +} + +static cairo_bool_t +_cairo_boilerplate_target_matches_name (const cairo_boilerplate_target_t *target, + const char *tname, + const char *end) +{ + char const *content_name; + const char *content_start = strpbrk (tname, "."); + const char *content_end = end; + size_t name_len; + size_t content_len; + + if (content_start >= end) + content_start = NULL; + if (content_start != NULL) + end = content_start++; + + name_len = end - tname; + + /* Check name. */ + if (! (name_len == 1 && 0 == strncmp (tname, "?", 1))) { /* wildcard? */ + if (0 != strncmp (target->name, tname, name_len)) /* exact match? */ + return FALSE; + if (_cairo_isalnum (target->name[name_len])) + return FALSE; + } + + /* Check optional content. */ + if (content_start == NULL) /* none given? */ + return TRUE; + + /* Exact content match? */ + content_name = _cairo_boilerplate_content_visible_name (target->content); + content_len = content_end - content_start; + if (strlen(content_name) != content_len) + return FALSE; + if (0 == strncmp (content_name, content_start, content_len)) + return TRUE; + + return FALSE; +} + +const cairo_boilerplate_target_t ** +cairo_boilerplate_get_targets (int *pnum_targets, + cairo_bool_t *plimited_targets) +{ + size_t i, num_targets; + cairo_bool_t limited_targets = FALSE; + const char *tname; + const cairo_boilerplate_target_t **targets_to_test; + struct cairo_boilerplate_target_list *list; + + if (cairo_boilerplate_targets == NULL) + _cairo_boilerplate_register_all (); + + if ((tname = getenv ("CAIRO_TEST_TARGET")) != NULL && *tname) { + /* check the list of targets specified by the user */ + limited_targets = TRUE; + + num_targets = 0; + targets_to_test = NULL; + + while (*tname) { + int found = 0; + const char *end = strpbrk (tname, " \t\r\n;:,"); + if (!end) + end = tname + strlen (tname); + + if (end == tname) { + tname = end + 1; + continue; + } + + for (list = cairo_boilerplate_targets; + list != NULL; + list = list->next) + { + const cairo_boilerplate_target_t *target = list->target; + const char *tcontent_name; + const char *tcontent_end; + if (_cairo_boilerplate_target_matches_name (target, tname, end)) { + if ((tcontent_name = getenv ("CAIRO_TEST_TARGET_FORMAT")) != NULL && *tcontent_name) { + while(tcontent_name) { + tcontent_end = strpbrk (tcontent_name, " \t\r\n;:,"); + if (tcontent_end == tcontent_name) { + tcontent_name = tcontent_end + 1; + continue; + } + if(_cairo_boilerplate_target_format_matches_name (target, + tcontent_name, tcontent_end)) { + /* realloc isn't exactly the best thing here, but meh. */ + targets_to_test = xrealloc (targets_to_test, + sizeof(cairo_boilerplate_target_t *) * (num_targets+1)); + targets_to_test[num_targets++] = target; + found = 1; + } + + if (tcontent_end) + tcontent_end++; + tcontent_name = tcontent_end; + } + } else { + /* realloc isn't exactly the best thing here, but meh. */ + targets_to_test = xrealloc (targets_to_test, + sizeof(cairo_boilerplate_target_t *) * (num_targets+1)); + targets_to_test[num_targets++] = target; + found = 1; + } + } + } + + if (!found) { + const char *last_name = NULL; + + fprintf (stderr, "Cannot find target '%.*s'.\n", + (int)(end - tname), tname); + fprintf (stderr, "Known targets:"); + for (list = cairo_boilerplate_targets; + list != NULL; + list = list->next) + { + const cairo_boilerplate_target_t *target = list->target; + if (last_name != NULL) { + if (strcmp (target->name, last_name) == 0) { + /* filter out repeats that differ in content */ + continue; + } + fprintf (stderr, ","); + } + fprintf (stderr, " %s", target->name); + last_name = target->name; + } + fprintf (stderr, "\n"); + exit(-1); + } + + if (*end) + end++; + tname = end; + } + } else { + int found = 0; + int not_found_targets = 0; + num_targets = 0; + targets_to_test = xmalloc (sizeof(cairo_boilerplate_target_t*) * num_targets); + for (list = cairo_boilerplate_targets; list != NULL; list = list->next) + { + const cairo_boilerplate_target_t *target = list->target; + const char *tcontent_name; + const char *tcontent_end; + if ((tcontent_name = getenv ("CAIRO_TEST_TARGET_FORMAT")) != NULL && *tcontent_name) { + while(tcontent_name) { + tcontent_end = strpbrk (tcontent_name, " \t\r\n;:,"); + if (tcontent_end == tcontent_name) { + tcontent_name = tcontent_end + 1; + continue; + } + if (_cairo_boilerplate_target_format_matches_name (target, + tcontent_name, tcontent_end)) { + /* realloc isn't exactly the best thing here, but meh. */ + targets_to_test = xrealloc (targets_to_test, + sizeof(cairo_boilerplate_target_t *) * (num_targets+1)); + targets_to_test[num_targets++] = target; + found =1; + } + else + { + not_found_targets++; + } + + if (tcontent_end) + tcontent_end++; + + tcontent_name = tcontent_end; + } + } + else + { + num_targets++; + } + } + if (!found) + { + /* check all compiled in targets */ + num_targets = num_targets + not_found_targets; + targets_to_test = xrealloc (targets_to_test, + sizeof(cairo_boilerplate_target_t*) * num_targets); + num_targets = 0; + for (list = cairo_boilerplate_targets; + list != NULL; + list = list->next) + { + const cairo_boilerplate_target_t *target = list->target; + targets_to_test[num_targets++] = target; + } + } + + } + + /* exclude targets as specified by the user */ + if ((tname = getenv ("CAIRO_TEST_TARGET_EXCLUDE")) != NULL && *tname) { + limited_targets = TRUE; + + while (*tname) { + int j; + const char *end = strpbrk (tname, " \t\r\n;:,"); + if (!end) + end = tname + strlen (tname); + + if (end == tname) { + tname = end + 1; + continue; + } + + for (i = j = 0; i < num_targets; i++) { + const cairo_boilerplate_target_t *target = targets_to_test[i]; + if (! _cairo_boilerplate_target_matches_name (target, + tname, end)) + { + targets_to_test[j++] = targets_to_test[i]; + } + } + num_targets = j; + + if (*end) + end++; + tname = end; + } + } + + if (pnum_targets) + *pnum_targets = num_targets; + + if (plimited_targets) + *plimited_targets = limited_targets; + + return targets_to_test; +} + +const cairo_boilerplate_target_t * +cairo_boilerplate_get_image_target (cairo_content_t content) +{ + if (cairo_boilerplate_targets == NULL) + _cairo_boilerplate_register_all (); + + switch (content) { + case CAIRO_CONTENT_COLOR: + return &builtin_targets[1]; + case CAIRO_CONTENT_COLOR_ALPHA: + return &builtin_targets[0]; + case CAIRO_CONTENT_ALPHA: + default: + return NULL; + } +} + +const cairo_boilerplate_target_t * +cairo_boilerplate_get_target_by_name (const char *name, + cairo_content_t content) +{ + struct cairo_boilerplate_target_list *list; + + if (cairo_boilerplate_targets == NULL) + _cairo_boilerplate_register_all (); + + /* first return an exact match */ + for (list = cairo_boilerplate_targets; list != NULL; list = list->next) { + const cairo_boilerplate_target_t *target = list->target; + if (strcmp (target->name, name) == 0 && + target->content == content) + { + return target; + } + } + + /* otherwise just return a match that may differ in content */ + for (list = cairo_boilerplate_targets; list != NULL; list = list->next) { + const cairo_boilerplate_target_t *target = list->target; + if (strcmp (target->name, name) == 0) + return target; + } + + return NULL; +} + +void +cairo_boilerplate_free_targets (const cairo_boilerplate_target_t **targets) +{ + free (targets); +} + +cairo_surface_t * +cairo_boilerplate_surface_create_in_error (cairo_status_t status) +{ + cairo_surface_t *surface = NULL; + int loop = 5; + + do { + cairo_surface_t *intermediate; + cairo_t *cr; + cairo_path_t path; + + intermediate = cairo_image_surface_create (CAIRO_FORMAT_A8, 0, 0); + cr = cairo_create (intermediate); + cairo_surface_destroy (intermediate); + + path.status = status; + cairo_append_path (cr, &path); + + cairo_surface_destroy (surface); + surface = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + } while (cairo_surface_status (surface) != status && --loop); + + return surface; +} + +void +cairo_boilerplate_scaled_font_set_max_glyphs_cached (cairo_scaled_font_t *scaled_font, + int max_glyphs) +{ + /* XXX CAIRO_DEBUG */ +} + +#if HAS_DAEMON +static int +any2ppm_daemon_exists (void) +{ + struct stat st; + int fd; + char buf[80]; + int pid; + int ret; + + if (stat (SOCKET_PATH, &st) < 0) + return 0; + + fd = open (SOCKET_PATH ".pid", O_RDONLY); + if (fd < 0) + return 0; + + pid = 0; + ret = read (fd, buf, sizeof (buf) - 1); + if (ret > 0) { + buf[ret] = '\0'; + pid = atoi (buf); + } + close (fd); + + return pid > 0 && kill (pid, 0) != -1; +} +#endif + +FILE * +cairo_boilerplate_open_any2ppm (const char *filename, + int page, + unsigned int flags, + int (**close_cb) (FILE *)) +{ + char command[4096]; + const char *any2ppm; +#if HAS_DAEMON + int sk; + struct sockaddr_un addr; + int len; +#endif + + any2ppm = getenv ("ANY2PPM"); + if (any2ppm == NULL) + any2ppm = "./any2ppm"; + +#if HAS_DAEMON + if (flags & CAIRO_BOILERPLATE_OPEN_NO_DAEMON) + goto POPEN; + + if (! any2ppm_daemon_exists ()) { + if (system (any2ppm) != 0) + goto POPEN; + } + + sk = socket (PF_UNIX, SOCK_STREAM, 0); + if (sk == -1) + goto POPEN; + + memset (&addr, 0, sizeof (addr)); + addr.sun_family = AF_UNIX; + strcpy (addr.sun_path, SOCKET_PATH); + + if (connect (sk, (struct sockaddr *) &addr, sizeof (addr)) == -1) { + close (sk); + goto POPEN; + } + + len = sprintf (command, "%s %d\n", filename, page); + if (write (sk, command, len) != len) { + close (sk); + goto POPEN; + } + + *close_cb = fclose; + return fdopen (sk, "rb"); + +POPEN: +#endif + + *close_cb = pclose; + sprintf (command, "%s %s %d", any2ppm, filename, page); + return popen (command, "r"); +} + +static cairo_bool_t +freadn (unsigned char *buf, + int len, + FILE *file) +{ + int ret; + + while (len) { + ret = fread (buf, 1, len, file); + if (ret != len) { + if (ferror (file) || feof (file)) + return FALSE; + } + len -= ret; + buf += len; + } + + return TRUE; +} + +cairo_surface_t * +cairo_boilerplate_image_surface_create_from_ppm_stream (FILE *file) +{ + char format; + int width, height; + ptrdiff_t stride; + int x, y; + unsigned char *data; + cairo_surface_t *image = NULL; + + if (fscanf (file, "P%c %d %d 255\n", &format, &width, &height) != 3) + goto FAIL; + + switch (format) { + case '7': /* XXX */ + image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); + break; + case '6': + image = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height); + break; + case '5': + image = cairo_image_surface_create (CAIRO_FORMAT_A8, width, height); + break; + default: + goto FAIL; + } + if (cairo_surface_status (image)) + return image; + + data = cairo_image_surface_get_data (image); + stride = cairo_image_surface_get_stride (image); + for (y = 0; y < height; y++) { + unsigned char *buf = data + y*stride; + switch (format) { + case '7': + if (! freadn (buf, 4 * width, file)) + goto FAIL; + break; + case '6': + if (! freadn (buf, 3*width, file)) + goto FAIL; + buf += 3*width; + for (x = width; x--; ) { + buf -= 3; + ((uint32_t *) (data + y*stride))[x] = + (buf[0] << 16) | (buf[1] << 8) | (buf[2] << 0); + } + break; + case '5': + if (! freadn (buf, width, file)) + goto FAIL; + break; + } + } + cairo_surface_mark_dirty (image); + + return image; + +FAIL: + cairo_surface_destroy (image); + return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_READ_ERROR); +} + +cairo_surface_t * +cairo_boilerplate_convert_to_image (const char *filename, + int page) +{ + FILE *file; + unsigned int flags = 0; + cairo_surface_t *image; + int (*close_cb) (FILE *); + int ret; + + if (getenv ("CAIRO_BOILERPLATE_OPEN_NO_DAEMON") != NULL) { + flags |= CAIRO_BOILERPLATE_OPEN_NO_DAEMON; + } + + RETRY: + file = cairo_boilerplate_open_any2ppm (filename, page, flags, &close_cb); + if (file == NULL) { + switch (errno) { + case ENOMEM: + return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_NO_MEMORY); + default: + return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_READ_ERROR); + } + } + + image = cairo_boilerplate_image_surface_create_from_ppm_stream (file); + ret = close_cb (file); + /* check for fatal errors from the interpreter */ + if (ret) { /* any2pmm should never die... */ + cairo_surface_destroy (image); + if (getenv ("CAIRO_BOILERPLATE_DO_NOT_CRASH_ON_ANY2PPM_ERROR") != NULL) { + return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_WRITE_ERROR); + } else { + return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_INVALID_STATUS); + } + } + + if (ret == 0 && cairo_surface_status (image) == CAIRO_STATUS_READ_ERROR) { + if (flags == 0) { + /* Try again in a standalone process. */ + cairo_surface_destroy (image); + flags = CAIRO_BOILERPLATE_OPEN_NO_DAEMON; + goto RETRY; + } + } + + return image; +} + +int +cairo_boilerplate_version (void) +{ + return CAIRO_VERSION; +} + +const char* +cairo_boilerplate_version_string (void) +{ + return CAIRO_VERSION_STRING; +} + +void +cairo_boilerplate_fini (void) +{ + while (cairo_boilerplate_targets != NULL) { + struct cairo_boilerplate_target_list *next; + + next = cairo_boilerplate_targets->next; + + free (cairo_boilerplate_targets); + cairo_boilerplate_targets = next; + } +} diff --git a/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate.h b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate.h new file mode 100644 index 0000000000..736534eafb --- /dev/null +++ b/local/recipes/libs/cairo/source/boilerplate/cairo-boilerplate.h @@ -0,0 +1,255 @@ +/* + * Copyright © 2004,2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#ifndef _CAIRO_BOILERPLATE_H_ +#define _CAIRO_BOILERPLATE_H_ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "cairo-compiler-private.h" + +#if HAVE_STDINT_H +# include +#elif HAVE_INTTYPES_H +# include +#elif HAVE_SYS_INT_TYPES_H +# include +#elif defined(_MSC_VER) +# include + typedef __int8 int8_t; + typedef unsigned __int8 uint8_t; + typedef __int16 int16_t; + typedef unsigned __int16 uint16_t; + typedef __int32 int32_t; + typedef unsigned __int32 uint32_t; + typedef __int64 int64_t; + typedef unsigned __int64 uint64_t; +#else +#error Cannot find definitions for fixed-width integral types (uint8_t, uint32_t, etc.) +#endif + +#ifndef HAVE_UINT64_T +# define HAVE_UINT64_T 1 +#endif +#ifndef INT16_MIN +# define INT16_MIN (-32767-1) +#endif +#ifndef INT16_MAX +# define INT16_MAX (32767) +#endif +#ifndef UINT16_MAX +# define UINT16_MAX (65535) +#endif + +#ifndef CAIRO_BOILERPLATE_DEBUG +#define CAIRO_BOILERPLATE_DEBUG(x) +#endif + +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4) +#ifdef __MINGW32__ +#define CAIRO_BOILERPLATE_PRINTF_FORMAT(fmt_index, va_index) \ + __attribute__((__format__(__MINGW_PRINTF_FORMAT, fmt_index, va_index))) +#else +#define CAIRO_BOILERPLATE_PRINTF_FORMAT(fmt_index, va_index) \ + __attribute__((__format__(__printf__, fmt_index, va_index))) +#endif +#else +#define CAIRO_BOILERPLATE_PRINTF_FORMAT(fmt_index, va_index) +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#ifndef ARRAY_LENGTH +#define ARRAY_LENGTH(__array) ((int) (sizeof (__array) / sizeof (__array[0]))) +#endif + +CAIRO_BEGIN_DECLS + +/* A fake format we use for the flattened ARGB output of the PS and + * PDF surfaces. */ +#define CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED ((unsigned int) -1) + +extern const cairo_user_data_key_t cairo_boilerplate_output_basename_key; + +cairo_content_t +cairo_boilerplate_content (cairo_content_t content); + +const char * +cairo_boilerplate_content_name (cairo_content_t content); + +cairo_format_t +cairo_boilerplate_format_from_content (cairo_content_t content); + +typedef enum { + CAIRO_BOILERPLATE_MODE_TEST, + CAIRO_BOILERPLATE_MODE_PERF, + + /* This will allow running performance test with threads. The + * GL backend is very slow on some drivers when run with thread + * awareness turned on. */ + CAIRO_BOILERPLATE_MODE_PERF_THREADS, +} cairo_boilerplate_mode_t; + +typedef cairo_surface_t * +(*cairo_boilerplate_create_surface_t) (const char *name, + cairo_content_t content, + double width, + double height, + double max_width, + double max_height, + cairo_boilerplate_mode_t mode, + void **closure); + +typedef cairo_surface_t * +(*cairo_boilerplate_create_similar_t) (cairo_surface_t *other, + cairo_content_t content, + int width, + int height); + +typedef void +(*cairo_boilerplate_force_fallbacks_t) (cairo_surface_t *surface, + double x_pixels_per_inch, + double y_pixels_per_inch); + +typedef cairo_status_t +(*cairo_boilerplate_finish_surface_t) (cairo_surface_t *surface); + +typedef cairo_surface_t * +(*cairo_boilerplate_get_image_surface_t) (cairo_surface_t *surface, + int page, + int width, + int height); + +typedef cairo_status_t +(*cairo_boilerplate_write_to_png_t) (cairo_surface_t *surface, + const char *filename); + +typedef void +(*cairo_boilerplate_cleanup_t) (void *closure); + +typedef void +(*cairo_boilerplate_wait_t) (void *closure); + +typedef char * +(*cairo_boilerplate_describe_t) (void *closure); + +typedef struct _cairo_boilerplate_target { + const char *name; + const char *basename; + const char *file_extension; + const char *reference_target; + cairo_surface_type_t expected_type; + cairo_content_t content; + unsigned int error_tolerance; + const char *probe; /* runtime dl check */ + cairo_boilerplate_create_surface_t create_surface; + cairo_boilerplate_create_similar_t create_similar; + cairo_boilerplate_force_fallbacks_t force_fallbacks; + cairo_boilerplate_finish_surface_t finish_surface; + cairo_boilerplate_get_image_surface_t get_image_surface; + cairo_boilerplate_write_to_png_t write_to_png; + cairo_boilerplate_cleanup_t cleanup; + cairo_boilerplate_wait_t synchronize; + cairo_boilerplate_describe_t describe; + cairo_bool_t is_measurable; + cairo_bool_t is_vector; + cairo_bool_t is_recording; +} cairo_boilerplate_target_t; + +const cairo_boilerplate_target_t * +cairo_boilerplate_get_image_target (cairo_content_t content); + +const cairo_boilerplate_target_t * +cairo_boilerplate_get_target_by_name (const char *name, + cairo_content_t content); + +const cairo_boilerplate_target_t ** +cairo_boilerplate_get_targets (int *num_targets, + cairo_bool_t *limited_targets); + +void +cairo_boilerplate_free_targets (const cairo_boilerplate_target_t **targets); + +cairo_surface_t * +_cairo_boilerplate_get_image_surface (cairo_surface_t *src, + int page, + int width, + int height); +cairo_surface_t * +cairo_boilerplate_get_image_surface_from_png (const char *filename, + int width, + int height, + cairo_bool_t flatten); + +cairo_surface_t * +cairo_boilerplate_surface_create_in_error (cairo_status_t status); + +enum { + CAIRO_BOILERPLATE_OPEN_NO_DAEMON = 0x1, +}; + +FILE * +cairo_boilerplate_open_any2ppm (const char *filename, + int page, + unsigned int flags, + int (**close_cb) (FILE *)); + +cairo_surface_t * +cairo_boilerplate_image_surface_create_from_ppm_stream (FILE *file); + +cairo_surface_t * +cairo_boilerplate_convert_to_image (const char *filename, + int page); + +int +cairo_boilerplate_version (void); + +const char* +cairo_boilerplate_version_string (void); + +void +cairo_boilerplate_fini (void); + +#include "cairo-boilerplate-system.h" + +CAIRO_END_DECLS + +#endif diff --git a/local/recipes/libs/cairo/source/boilerplate/make-cairo-boilerplate-constructors.py b/local/recipes/libs/cairo/source/boilerplate/make-cairo-boilerplate-constructors.py new file mode 100644 index 0000000000..40198ed1a1 --- /dev/null +++ b/local/recipes/libs/cairo/source/boilerplate/make-cairo-boilerplate-constructors.py @@ -0,0 +1,38 @@ +# IMPORTANT: Keep in sync with make-cairo-boilerplate-constructors.sh +# and test/make-cairo-test-constructors.py! +import argparse +import sys +import re + +if __name__=='__main__': + parser = argparse.ArgumentParser() + parser.add_argument('output') + parser.add_argument('input', nargs='+') + args = parser.parse_args() + + boilerplate_names = [] + + match_boilerplate_line = re.compile(r'^CAIRO_BOILERPLATE.*') + match_boilerplate_name = re.compile(r'^CAIRO_BOILERPLATE.*\((.*),.*') + + for fname in args.input: + with open(fname, 'r', encoding='utf-8') as f: + for l in f.readlines(): + if match_boilerplate_line.match(l): + boilerplate_names.append(match_boilerplate_name.match(l).group(1)) + + with open(args.output, 'w', encoding='utf-8') as f: + f.write('/* WARNING: Autogenerated file - see %s! */\n\n' % sys.argv[0]) + f.write('#include "cairo-boilerplate-private.h"\n\n') + f.write('void _cairo_boilerplate_register_all (void);\n\n') + + for boilerplate_name in boilerplate_names: + f.write('extern void _register_%s (void);\n' % boilerplate_name) + + f.write('\nvoid\n') + f.write('_cairo_boilerplate_register_all (void)\n') + f.write('{\n') + + for boilerplate_name in boilerplate_names: + f.write(' _register_%s ();\n' % boilerplate_name) + f.write('}\n') diff --git a/local/recipes/libs/cairo/source/boilerplate/make-cairo-boilerplate-constructors.sh b/local/recipes/libs/cairo/source/boilerplate/make-cairo-boilerplate-constructors.sh new file mode 100644 index 0000000000..1503e99707 --- /dev/null +++ b/local/recipes/libs/cairo/source/boilerplate/make-cairo-boilerplate-constructors.sh @@ -0,0 +1,31 @@ +#! /bin/sh +# +# IMPORTANT: Keep in sync with make-cairo-boilerplate-constructors.py! + +if test $# -eq 0; then + echo "$0: no input files." >&2 + exit 0 +fi + +cat < + +Hobby's primary contribution in that paper is his "tolerance square" +algorithm for robustness against edges being "bent" due to restricting +intersection coordinates to the grid available by finite-precision +arithmetic. This is one algorithm we have not implemented yet. + +We use a data-structure called Skiplists in the our implementation of +Bentley-Ottmann: + +- W. Pugh, Skip Lists: a Probabilistic Alternative to Balanced Trees, + Communications of the ACM, vol. 33, no. 6, pp.668-676, 1990. + + +The random number generator used in our skip list implementation is a very +small generator by Hars and Petruska. The generator is based on an +invertable function on Z_{2^32} with full period and is described in + +- Hars L. and Petruska G., + Pseudorandom Recursions: Small and Fast Pseurodandom + Number Generators for Embedded Applications, + Hindawi Publishing Corporation + EURASIP Journal on Embedded Systems + Volume 2007, Article ID 98417, 13 pages + doi:10.1155/2007/98417 + + +From the result of the intersection-finding pass, we are currently computing +a tessellation of trapezoids, (the exact manner is undergoing some work +right now with some important speedup), but we may want to rasterize +directly from those edges at some point. + +Given the set of tessellated trapezoids, we currently execute a +straightforward, (and slow), point-sampled rasterization, (and currently +with a near-pessimal regular 15x17 grid). + +We've now computed a mask which gets fed along with the source and +destination into cairo's fundamental rendering equation. The most basic form +of this equation is: + + destination = (source IN mask) OP destination + +with the restriction that no part of the destination outside the current +clip region is affected. In this equation, IN refers to the Porter-Duff "in" +operation, while OP refers to a any user-selected Porter-Duff operator: + +- T. Porter & T. Duff, Compositing Digital Images Computer + Graphics Volume 18, Number 3 July 1984 pp 253-259 + diff --git a/local/recipes/libs/cairo/source/doc/public/.gitignore b/local/recipes/libs/cairo/source/doc/public/.gitignore new file mode 100644 index 0000000000..881463af0a --- /dev/null +++ b/local/recipes/libs/cairo/source/doc/public/.gitignore @@ -0,0 +1,21 @@ +*.stamp +Makefile +Makefile.in +cairo-decl-list.txt +cairo-decl.txt +cairo-docs.sgml +cairo-undeclared.txt +cairo-undocumented.txt +cairo-unused.txt +cairo.hierarchy +cairo.interfaces +cairo.prerequisites +cairo.args +cairo.signals +html +xml +tmpl +version.xml +*~ +*.bak +*.trs diff --git a/local/recipes/libs/cairo/source/doc/public/README b/local/recipes/libs/cairo/source/doc/public/README new file mode 100644 index 0000000000..f3d157b1a9 --- /dev/null +++ b/local/recipes/libs/cairo/source/doc/public/README @@ -0,0 +1,37 @@ +Cairo Reference Documentation +============================= + +The API documentation is generated using gtk-doc. + + +Building +-------- + +The documentation is not built by default. To build it you need to +configure with gtk-doc enabled (--enable-gtk-doc), and run: + + make doc + + +Adding New API +-------------- + +When adding new symbols and macros to the public API, modify +cairo-section.txt and add new symbols to the right place. + +When adding whole new features, you also need to modify cairo-docs.xml +and add a new file under tmpl/. Beware that the files are tmpl/ are +both manually edited AND modified by gtk-doc, gathering documentation +stub from source files. + + +Tests +----- + +There are some tests in this directory, ensuring proper documentation +syntax as well as checking that all public symbols are fully documented. + +After adding any new API, just run: + + make check + diff --git a/local/recipes/libs/cairo/source/doc/public/cairo-docs.xml b/local/recipes/libs/cairo/source/doc/public/cairo-docs.xml new file mode 100644 index 0000000000..6bfbddf64b --- /dev/null +++ b/local/recipes/libs/cairo/source/doc/public/cairo-docs.xml @@ -0,0 +1,109 @@ + + +]> + +Cairo: A Vector Graphics Library + + Cairo: A Vector Graphics Library + for Cairo &version; + + + Drawing + + + + + + + + + + + Fonts + + + + + + + + + + + Surfaces + + + + + + + + + + + + + + + + + + + Utilities + + + + + + + Index + + + + + Index of new symbols in 1.0 + + + + Index of new symbols in 1.2 + + + + Index of new symbols in 1.4 + + + + Index of new symbols in 1.6 + + + + Index of new symbols in 1.8 + + + + Index of new symbols in 1.10 + + + + Index of new symbols in 1.12 + + + + Index of new symbols in 1.14 + + + + Index of new symbols in 1.16 + + + + Index of new symbols in 1.18 + + + + diff --git a/local/recipes/libs/cairo/source/doc/public/cairo-overrides.txt b/local/recipes/libs/cairo/source/doc/public/cairo-overrides.txt new file mode 100644 index 0000000000..dd80844923 --- /dev/null +++ b/local/recipes/libs/cairo/source/doc/public/cairo-overrides.txt @@ -0,0 +1,124 @@ + +CAIRO_HAS_FT_FONT +#define CAIRO_HAS_FT_FONT + + + +CAIRO_HAS_FC_FONT +#define CAIRO_HAS_FC_FONT + + + +CAIRO_HAS_PNG_FUNCTIONS +#define CAIRO_HAS_PNG_FUNCTIONS + + + +CAIRO_HAS_SVG_SURFACE +#define CAIRO_HAS_SVG_SURFACE + + + +CAIRO_HAS_PDF_SURFACE +#define CAIRO_HAS_PDF_SURFACE + + + +CAIRO_HAS_PS_SURFACE +#define CAIRO_HAS_PS_SURFACE + + + +CAIRO_HAS_SCRIPT_SURFACE +#define CAIRO_HAS_SCRIPT_SURFACE + + + +CAIRO_HAS_XLIB_SURFACE +#define CAIRO_HAS_XLIB_SURFACE + + + +CAIRO_HAS_XLIB_XRENDER_SURFACE +#define CAIRO_HAS_XLIB_XRENDER_SURFACE + + + +CAIRO_HAS_XCB_SURFACE +#define CAIRO_HAS_XCB_SURFACE + + + +CAIRO_HAS_XLIB_XCB_FUNCTIONS +#define CAIRO_HAS_XLIB_XCB_FUNCTIONS + + + +CAIRO_HAS_XCB_SHM_FUNCTIONS +#define CAIRO_HAS_XCB_SHM_FUNCTIONS + + + +CAIRO_HAS_QUARTZ_SURFACE +#define CAIRO_HAS_QUARTZ_SURFACE + + + +CAIRO_HAS_QUARTZ_IMAGE_SURFACE +#define CAIRO_HAS_QUARTZ_IMAGE_SURFACE + + + +CAIRO_HAS_QUARTZ_FONT +#define CAIRO_HAS_QUARTZ_FONT + + + +CAIRO_HAS_WIN32_SURFACE +#define CAIRO_HAS_WIN32_SURFACE + + + +CAIRO_HAS_WIN32_FONT +#define CAIRO_HAS_WIN32_FONT + + + +CAIRO_HAS_DWRITE_FONT +#define CAIRO_HAS_DWRITE_FONT + + + +CAIRO_HAS_GOBJECT_FUNCTIONS +#define CAIRO_HAS_GOBJECT_FUNCTIONS + + + +CAIRO_HAS_IMAGE_SURFACE +#define CAIRO_HAS_IMAGE_SURFACE + + + +CAIRO_HAS_USER_FONT +#define CAIRO_HAS_USER_FONT + + + +CAIRO_HAS_MIME_SURFACE +#define CAIRO_HAS_MIME_SURFACE + + + +CAIRO_HAS_RECORDING_SURFACE +#define CAIRO_HAS_RECORDING_SURFACE + + + +CAIRO_HAS_OBSERVER_SURFACE +#define CAIRO_HAS_OBSERVER_SURFACE + + + +CAIRO_HAS_TEE_SURFACE +#define CAIRO_HAS_TEE_SURFACE + diff --git a/local/recipes/libs/cairo/source/doc/public/cairo-sections.txt b/local/recipes/libs/cairo/source/doc/public/cairo-sections.txt new file mode 100644 index 0000000000..52bbbb2310 --- /dev/null +++ b/local/recipes/libs/cairo/source/doc/public/cairo-sections.txt @@ -0,0 +1,791 @@ +
+cairo-ft +CAIRO_HAS_FT_FONT +CAIRO_HAS_FC_FONT +cairo_ft_font_face_create_for_ft_face +cairo_ft_font_face_create_for_pattern +cairo_ft_font_options_substitute +cairo_ft_scaled_font_lock_face +cairo_ft_scaled_font_unlock_face +cairo_ft_synthesize_t +cairo_ft_font_face_get_synthesize +cairo_ft_font_face_set_synthesize +cairo_ft_font_face_unset_synthesize +
+ +
+cairo-win32-fonts +CAIRO_HAS_WIN32_FONT +cairo_win32_font_face_create_for_logfontw +cairo_win32_font_face_create_for_hfont +cairo_win32_font_face_create_for_logfontw_hfont +cairo_win32_scaled_font_select_font +cairo_win32_scaled_font_done_font +cairo_win32_scaled_font_get_metrics_factor +cairo_win32_scaled_font_get_logical_to_device +cairo_win32_scaled_font_get_device_to_logical +
+ +
+cairo-dwrite-fonts +CAIRO_HAS_DWRITE_FONT +cairo_dwrite_font_face_create_for_dwrite_fontface +cairo_dwrite_font_face_get_rendering_params +cairo_dwrite_font_face_set_rendering_params +cairo_dwrite_font_face_get_measuring_mode +cairo_dwrite_font_face_set_measuring_mode +
+ +
+cairo-quartz-fonts +CAIRO_HAS_QUARTZ_FONT +cairo_quartz_font_face_create_for_cgfont +cairo_quartz_font_face_create_for_atsu_font_id +
+ +
+cairo-user-fonts +CAIRO_HAS_USER_FONT +cairo_user_scaled_font_init_func_t +cairo_user_scaled_font_render_glyph_func_t +cairo_user_scaled_font_text_to_glyphs_func_t +cairo_user_scaled_font_unicode_to_glyph_func_t +cairo_user_font_face_create +cairo_user_font_face_set_init_func +cairo_user_font_face_get_init_func +cairo_user_font_face_set_render_glyph_func +cairo_user_font_face_get_render_glyph_func +cairo_user_font_face_set_render_color_glyph_func +cairo_user_font_face_get_render_color_glyph_func +cairo_user_font_face_set_unicode_to_glyph_func +cairo_user_font_face_get_unicode_to_glyph_func +cairo_user_font_face_set_text_to_glyphs_func +cairo_user_font_face_get_text_to_glyphs_func +cairo_user_scaled_font_get_foreground_marker +cairo_user_scaled_font_get_foreground_source +
+ +
+cairo-image +CAIRO_HAS_IMAGE_SURFACE +cairo_format_t +cairo_format_stride_for_width +cairo_image_surface_create +cairo_image_surface_create_for_data +cairo_image_surface_get_data +cairo_image_surface_get_format +cairo_image_surface_get_width +cairo_image_surface_get_height +cairo_image_surface_get_stride +
+ +
+cairo-pdf +CAIRO_HAS_PDF_SURFACE +CAIRO_PDF_OUTLINE_ROOT +cairo_pdf_outline_flags_t +cairo_pdf_metadata_t +cairo_pdf_surface_create +cairo_pdf_surface_create_for_stream +cairo_pdf_surface_restrict_to_version +cairo_pdf_version_t +cairo_pdf_get_versions +cairo_pdf_version_to_string +cairo_pdf_surface_set_size +cairo_pdf_surface_add_outline +cairo_pdf_surface_set_metadata +cairo_pdf_surface_set_custom_metadata +cairo_pdf_surface_set_page_label +cairo_pdf_surface_set_thumbnail_size +
+ +
+cairo-png +CAIRO_HAS_PNG_FUNCTIONS +cairo_image_surface_create_from_png +cairo_read_func_t +cairo_image_surface_create_from_png_stream +cairo_surface_write_to_png +cairo_write_func_t +cairo_surface_write_to_png_stream +
+ +
+cairo-ps +CAIRO_HAS_PS_SURFACE +cairo_ps_surface_create +cairo_ps_surface_create_for_stream +cairo_ps_surface_restrict_to_level +cairo_ps_level_t +cairo_ps_get_levels +cairo_ps_level_to_string +cairo_ps_surface_set_eps +cairo_ps_surface_get_eps +cairo_ps_surface_set_size +cairo_ps_surface_dsc_begin_setup +cairo_ps_surface_dsc_begin_page_setup +cairo_ps_surface_dsc_comment +
+ +
+cairo-recording +CAIRO_HAS_RECORDING_SURFACE +cairo_recording_surface_create +cairo_recording_surface_ink_extents +cairo_recording_surface_get_extents +
+ +
+cairo-win32 +CAIRO_HAS_WIN32_SURFACE +cairo_win32_surface_create +cairo_win32_surface_create_with_dib +cairo_win32_surface_create_with_ddb +cairo_win32_surface_create_with_format +cairo_win32_printing_surface_create +cairo_win32_surface_get_dc +cairo_win32_surface_get_image + +SB_NONE +SHADEBLENDCAPS +WIN32_FONT_LOGICAL_SCALE +cairo_win32_device_t +cairo_win32_display_surface_t +cairo_win32_printing_surface_t +cairo_win32_surface_t +to_win32_device +to_win32_device_from_surface +to_win32_display_surface +to_win32_printing_surface +to_win32_surface +
+ +
+cairo-quartz +CAIRO_HAS_QUARTZ_SURFACE +CAIRO_HAS_QUARTZ_IMAGE_SURFACE +cairo_quartz_surface_create +cairo_quartz_surface_create_for_cg_context +cairo_quartz_surface_get_cg_context +cairo_quartz_image_surface_create +cairo_quartz_image_surface_get_image +
+ +
+cairo-xlib +CAIRO_HAS_XLIB_SURFACE +CAIRO_HAS_XLIB_XCB_FUNCTIONS +cairo_xlib_surface_create +cairo_xlib_surface_create_for_bitmap +cairo_xlib_surface_set_size +cairo_xlib_surface_get_display +cairo_xlib_surface_get_screen +cairo_xlib_surface_set_drawable +cairo_xlib_surface_get_drawable +cairo_xlib_surface_get_visual +cairo_xlib_surface_get_width +cairo_xlib_surface_get_height +cairo_xlib_surface_get_depth +cairo_xlib_device_debug_cap_xrender_version +cairo_xlib_device_debug_get_precision +cairo_xlib_device_debug_set_precision +
+ +
+cairo-xlib-xrender +CAIRO_HAS_XLIB_XRENDER_SURFACE +cairo_xlib_surface_create_with_xrender_format +cairo_xlib_surface_get_xrender_format +
+ +
+cairo-xcb +CAIRO_HAS_XCB_SURFACE +CAIRO_HAS_XCB_SHM_FUNCTIONS +cairo_xcb_surface_create +cairo_xcb_surface_create_for_bitmap +cairo_xcb_surface_create_with_xrender_format +cairo_xcb_surface_set_size +cairo_xcb_surface_set_drawable +cairo_xcb_device_get_connection +cairo_xcb_device_debug_cap_xrender_version +cairo_xcb_device_debug_cap_xshm_version +cairo_xcb_device_debug_get_precision +cairo_xcb_device_debug_set_precision +
+ +
+cairo-svg +CAIRO_HAS_SVG_SURFACE +cairo_svg_surface_create +cairo_svg_surface_create_for_stream +cairo_svg_surface_get_document_unit +cairo_svg_surface_set_document_unit +cairo_svg_surface_restrict_to_version +cairo_svg_version_t +cairo_svg_get_versions +cairo_svg_version_to_string +cairo_svg_unit_t +
+ +
+cairo-device +cairo_device_t +cairo_device_reference +cairo_device_destroy +cairo_device_status +cairo_device_finish +cairo_device_flush +cairo_device_type_t +cairo_device_get_type +cairo_device_get_reference_count +cairo_device_set_user_data +cairo_device_get_user_data +cairo_device_acquire +cairo_device_release +cairo_device_observer_elapsed +cairo_device_observer_fill_elapsed +cairo_device_observer_glyphs_elapsed +cairo_device_observer_mask_elapsed +cairo_device_observer_paint_elapsed +cairo_device_observer_print +cairo_device_observer_stroke_elapsed +
+ +
+cairo-surface +CAIRO_HAS_MIME_SURFACE +CAIRO_MIME_TYPE_CCITT_FAX +CAIRO_MIME_TYPE_CCITT_FAX_PARAMS +CAIRO_MIME_TYPE_EPS +CAIRO_MIME_TYPE_EPS_PARAMS +CAIRO_MIME_TYPE_JBIG2 +CAIRO_MIME_TYPE_JBIG2_GLOBAL +CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID +CAIRO_MIME_TYPE_JP2 +CAIRO_MIME_TYPE_JPEG +CAIRO_MIME_TYPE_PNG +CAIRO_MIME_TYPE_URI +CAIRO_MIME_TYPE_UNIQUE_ID +cairo_surface_t +cairo_content_t +cairo_surface_create_similar +cairo_surface_create_similar_image +cairo_surface_create_for_rectangle +cairo_surface_reference +cairo_surface_destroy +cairo_surface_status +cairo_surface_finish +cairo_surface_flush +cairo_surface_get_device +cairo_surface_get_font_options +cairo_surface_get_content +cairo_surface_mark_dirty +cairo_surface_mark_dirty_rectangle +cairo_surface_set_device_offset +cairo_surface_get_device_offset +cairo_surface_get_device_scale +cairo_surface_set_device_scale +cairo_surface_set_fallback_resolution +cairo_surface_get_fallback_resolution +cairo_surface_type_t +cairo_surface_get_type +cairo_surface_get_reference_count +cairo_surface_set_user_data +cairo_surface_get_user_data +cairo_surface_copy_page +cairo_surface_show_page +cairo_surface_has_show_text_glyphs +cairo_surface_set_mime_data +cairo_surface_get_mime_data +cairo_surface_supports_mime_type +cairo_surface_map_to_image +cairo_surface_unmap_image +
+ +
+cairo-surface-observer +CAIRO_HAS_OBSERVER_SURFACE +cairo_surface_create_observer +cairo_surface_observer_add_fill_callback +cairo_surface_observer_add_finish_callback +cairo_surface_observer_add_flush_callback +cairo_surface_observer_add_glyphs_callback +cairo_surface_observer_add_mask_callback +cairo_surface_observer_add_paint_callback +cairo_surface_observer_add_stroke_callback +cairo_surface_observer_callback_t +cairo_surface_observer_elapsed +cairo_surface_observer_mode_t +cairo_surface_observer_print +
+ +
+cairo-version +CAIRO_VERSION +CAIRO_VERSION_MAJOR +CAIRO_VERSION_MINOR +CAIRO_VERSION_MICRO +CAIRO_VERSION_STRING +CAIRO_VERSION_ENCODE +CAIRO_VERSION_STRINGIZE +cairo_version +cairo_version_string + +CAIRO_VERSION_STRINGIZE_ +
+ +
+cairo-region +cairo_region_t +cairo_region_create +cairo_region_create_rectangle +cairo_region_create_rectangles +cairo_region_copy +cairo_region_reference +cairo_region_destroy +cairo_region_status +cairo_region_get_extents +cairo_region_num_rectangles +cairo_region_get_rectangle +cairo_region_is_empty +cairo_region_contains_point +cairo_region_overlap_t +cairo_region_contains_rectangle +cairo_region_equal +cairo_region_translate +cairo_region_intersect +cairo_region_intersect_rectangle +cairo_region_subtract +cairo_region_subtract_rectangle +cairo_region_union +cairo_region_union_rectangle +cairo_region_xor +cairo_region_xor_rectangle +
+ +
+cairo-pattern +cairo_pattern_t +cairo_pattern_add_color_stop_rgb +cairo_pattern_add_color_stop_rgba +cairo_pattern_get_color_stop_count +cairo_pattern_get_color_stop_rgba +cairo_pattern_create_rgb +cairo_pattern_create_rgba +cairo_pattern_get_rgba +cairo_pattern_create_for_surface +cairo_pattern_get_surface +cairo_pattern_create_linear +cairo_pattern_get_linear_points +cairo_pattern_create_radial +cairo_pattern_get_radial_circles +cairo_pattern_create_mesh +cairo_mesh_pattern_begin_patch +cairo_mesh_pattern_end_patch +cairo_mesh_pattern_move_to +cairo_mesh_pattern_line_to +cairo_mesh_pattern_curve_to +cairo_mesh_pattern_set_control_point +cairo_mesh_pattern_set_corner_color_rgb +cairo_mesh_pattern_set_corner_color_rgba +cairo_mesh_pattern_get_patch_count +cairo_mesh_pattern_get_path +cairo_mesh_pattern_get_control_point +cairo_mesh_pattern_get_corner_color_rgba +cairo_pattern_reference +cairo_pattern_destroy +cairo_pattern_status +cairo_extend_t +cairo_pattern_set_extend +cairo_pattern_get_extend +cairo_filter_t +cairo_pattern_set_filter +cairo_pattern_get_filter +cairo_pattern_set_matrix +cairo_pattern_get_matrix +cairo_pattern_type_t +cairo_pattern_get_type +cairo_pattern_get_reference_count +cairo_pattern_set_user_data +cairo_pattern_get_user_data +cairo_dither_t +cairo_pattern_set_dither +cairo_pattern_get_dither +
+ +
+cairo-raster-source +cairo_pattern_create_raster_source +cairo_raster_source_pattern_set_callback_data +cairo_raster_source_pattern_get_callback_data +cairo_raster_source_pattern_set_acquire +cairo_raster_source_pattern_get_acquire +cairo_raster_source_pattern_set_snapshot +cairo_raster_source_pattern_get_snapshot +cairo_raster_source_pattern_set_copy +cairo_raster_source_pattern_get_copy +cairo_raster_source_pattern_set_finish +cairo_raster_source_pattern_get_finish +cairo_raster_source_acquire_func_t +cairo_raster_source_release_func_t +cairo_raster_source_snapshot_func_t +cairo_raster_source_copy_func_t +cairo_raster_source_finish_func_t +
+ +
+cairo-tag +CAIRO_TAG_DEST +CAIRO_TAG_LINK +CAIRO_TAG_CONTENT +CAIRO_TAG_CONTENT_REF +cairo_tag_begin +cairo_tag_end +
+ +
+cairo-matrix +cairo_matrix_t +cairo_matrix_init +cairo_matrix_init_identity +cairo_matrix_init_translate +cairo_matrix_init_scale +cairo_matrix_init_rotate +cairo_matrix_translate +cairo_matrix_scale +cairo_matrix_rotate +cairo_matrix_invert +cairo_matrix_multiply +cairo_matrix_transform_distance +cairo_matrix_transform_point +
+ +
+cairo-status +cairo_status_t +cairo_status_to_string +cairo_debug_reset_static_data +
+ +
+cairo-font-face +cairo_font_face_t +cairo_font_face_reference +cairo_font_face_destroy +cairo_font_face_status +cairo_font_type_t +cairo_font_face_get_type +cairo_font_face_get_reference_count +cairo_font_face_set_user_data +cairo_font_face_get_user_data +
+ +
+cairo-scaled-font +cairo_scaled_font_t +cairo_scaled_font_create +cairo_scaled_font_reference +cairo_scaled_font_destroy +cairo_scaled_font_status +cairo_font_extents_t +cairo_scaled_font_extents +cairo_text_extents_t +cairo_scaled_font_text_extents +cairo_scaled_font_glyph_extents +cairo_scaled_font_text_to_glyphs +cairo_scaled_font_get_font_face +cairo_scaled_font_get_font_options +cairo_scaled_font_get_font_matrix +cairo_scaled_font_get_ctm +cairo_scaled_font_get_scale_matrix +cairo_scaled_font_get_type +cairo_scaled_font_get_reference_count +cairo_scaled_font_set_user_data +cairo_scaled_font_get_user_data +
+ +
+cairo-font-options +cairo_font_options_t +cairo_font_options_create +cairo_font_options_copy +cairo_font_options_destroy +cairo_font_options_status +cairo_font_options_merge +cairo_font_options_hash +cairo_font_options_equal +cairo_font_options_set_antialias +cairo_font_options_get_antialias +cairo_subpixel_order_t +cairo_font_options_set_subpixel_order +cairo_font_options_get_subpixel_order +cairo_hint_style_t +cairo_font_options_set_hint_style +cairo_font_options_get_hint_style +cairo_hint_metrics_t +cairo_font_options_set_hint_metrics +cairo_font_options_get_hint_metrics +cairo_font_options_get_variations +cairo_font_options_set_variations +cairo_color_mode_t +cairo_font_options_set_color_mode +cairo_font_options_get_color_mode +CAIRO_COLOR_PALETTE_DEFAULT +cairo_font_options_set_color_palette +cairo_font_options_get_color_palette +cairo_font_options_set_custom_palette_color +cairo_font_options_get_custom_palette_color +
+ +
+cairo-types +cairo_bool_t +cairo_user_data_key_t +cairo_destroy_func_t +cairo_rectangle_int_t +
+ +
+cairo-transforms +cairo_translate +cairo_scale +cairo_rotate +cairo_transform +cairo_set_matrix +cairo_get_matrix +cairo_identity_matrix +cairo_user_to_device +cairo_user_to_device_distance +cairo_device_to_user +cairo_device_to_user_distance +
+ + +
+cairo-paths +cairo_path_t +cairo_path_data_t +cairo_path_data_type_t +cairo_copy_path +cairo_copy_path_flat +cairo_path_destroy +cairo_append_path +cairo_has_current_point +cairo_get_current_point +cairo_new_path +cairo_new_sub_path +cairo_close_path +cairo_arc +cairo_arc_negative +cairo_curve_to +cairo_line_to +cairo_move_to +cairo_rectangle +cairo_glyph_path +cairo_text_path +cairo_rel_curve_to +cairo_rel_line_to +cairo_rel_move_to +cairo_path_extents +
+ +
+cairo-text +cairo_glyph_t +cairo_font_slant_t +cairo_font_weight_t +cairo_text_cluster_t +cairo_text_cluster_flags_t +cairo_select_font_face +cairo_set_font_size +cairo_set_font_matrix +cairo_get_font_matrix +cairo_set_font_options +cairo_get_font_options +cairo_set_font_face +cairo_get_font_face +cairo_set_scaled_font +cairo_get_scaled_font +cairo_show_text +cairo_show_glyphs +cairo_show_text_glyphs +cairo_font_extents +cairo_text_extents +cairo_glyph_extents +cairo_toy_font_face_create +cairo_toy_font_face_get_family +cairo_toy_font_face_get_slant +cairo_toy_font_face_get_weight +cairo_glyph_allocate +cairo_glyph_free +cairo_text_cluster_allocate +cairo_text_cluster_free +
+ +
+cairo +cairo_t +cairo_create +cairo_reference +cairo_destroy +cairo_status +cairo_save +cairo_restore +cairo_get_target +cairo_push_group +cairo_push_group_with_content +cairo_pop_group +cairo_pop_group_to_source +cairo_get_group_target +cairo_set_source_rgb +cairo_set_source_rgba +cairo_set_source +cairo_set_source_surface +cairo_get_source +cairo_antialias_t +cairo_set_antialias +cairo_get_antialias +cairo_set_dash +cairo_get_dash_count +cairo_get_dash +cairo_fill_rule_t +cairo_set_fill_rule +cairo_get_fill_rule +cairo_line_cap_t +cairo_set_line_cap +cairo_get_line_cap +cairo_line_join_t +cairo_set_line_join +cairo_get_line_join +cairo_set_line_width +cairo_get_line_width +cairo_set_miter_limit +cairo_get_miter_limit +cairo_operator_t +cairo_set_operator +cairo_get_operator +cairo_set_tolerance +cairo_get_tolerance +cairo_clip +cairo_clip_preserve +cairo_clip_extents +cairo_in_clip +cairo_reset_clip +cairo_rectangle_t +cairo_rectangle_list_t +cairo_rectangle_list_destroy +cairo_copy_clip_rectangle_list +cairo_fill +cairo_fill_preserve +cairo_fill_extents +cairo_in_fill +cairo_mask +cairo_mask_surface +cairo_paint +cairo_paint_with_alpha +cairo_stroke +cairo_stroke_preserve +cairo_stroke_extents +cairo_in_stroke +cairo_copy_page +cairo_show_page +cairo_get_reference_count +cairo_set_user_data +cairo_get_user_data +cairo_set_hairline +cairo_get_hairline + +cairo_public +CAIRO_BEGIN_DECLS +CAIRO_END_DECLS +cairo_current_font_extents +cairo_get_font_extents +cairo_current_operator +cairo_current_tolerance +cairo_current_point +cairo_current_fill_rule +cairo_current_line_width +cairo_current_line_cap +cairo_current_line_join +cairo_current_miter_limit +cairo_current_matrix +cairo_current_target_surface +cairo_get_status +cairo_concat_matrix +cairo_scale_font +cairo_select_font +cairo_transform_font +cairo_transform_point +cairo_transform_distance +cairo_inverse_transform_point +cairo_inverse_transform_distance +cairo_init_clip +cairo_surface_create_for_image +cairo_default_matrix +cairo_matrix_set_affine +cairo_matrix_set_identity +cairo_pattern_add_color_stop +cairo_set_rgb_color +cairo_set_pattern +cairo_xlib_surface_create_for_pixmap_with_visual +cairo_xlib_surface_create_for_window_with_visual +cairo_xcb_surface_create_for_pixmap_with_visual +cairo_xcb_surface_create_for_window_with_visual +cairo_ps_surface_set_dpi +cairo_pdf_surface_set_dpi +cairo_svg_surface_set_dpi +cairo_current_path +cairo_current_path_flat +cairo_get_path +cairo_get_path_flat +cairo_set_alpha +cairo_show_surface +cairo_copy +cairo_surface_set_repeat +cairo_surface_set_matrix +cairo_surface_get_matrix +cairo_surface_set_filter +cairo_surface_get_filter +cairo_matrix_create +cairo_matrix_destroy +cairo_matrix_copy +cairo_matrix_get_affine +cairo_set_target_surface +cairo_set_target_image +cairo_set_target_pdf +cairo_set_target_png +cairo_set_target_ps +cairo_set_target_quartz +cairo_set_target_win32 +cairo_set_target_xcb +cairo_set_target_drawable +cairo_get_status_string +cairo_status_string +CAIRO_FONT_TYPE_ATSUI +cairo_atsui_font_face_create_for_atsu_font_id +CAIRO_HAS_GOBJECT_FUNCTIONS +
+ +
+cairo-script +CAIRO_HAS_SCRIPT_SURFACE +cairo_script_create +cairo_script_create_for_stream +cairo_script_from_recording_surface +cairo_script_get_mode +cairo_script_mode_t +cairo_script_set_mode +cairo_script_surface_create +cairo_script_surface_create_for_target +cairo_script_write_comment +
+ +
+cairo-tee +CAIRO_HAS_TEE_SURFACE +cairo_tee_surface_create +cairo_tee_surface_add +cairo_tee_surface_index +cairo_tee_surface_remove +
diff --git a/local/recipes/libs/cairo/source/doc/public/cairo.types b/local/recipes/libs/cairo/source/doc/public/cairo.types new file mode 100644 index 0000000000..e69de29bb2 diff --git a/local/recipes/libs/cairo/source/doc/public/check-doc-coverage.sh b/local/recipes/libs/cairo/source/doc/public/check-doc-coverage.sh new file mode 100755 index 0000000000..648ca1212e --- /dev/null +++ b/local/recipes/libs/cairo/source/doc/public/check-doc-coverage.sh @@ -0,0 +1,54 @@ +#!/bin/sh + +LC_ALL=C +export LC_ALL + +if test -z "$DOC_MODULE"; then + # extract from Makefile + eval `grep '^DOC_MODULE' Makefile | sed 's/ //g'` + if test -z "$DOC_MODULE"; then + echo Failed extracting DOC_MODULE from Makefile 1>&2 + echo Try setting DOC_MODULE env var manually 1>&2 + exit 1 + fi +fi + +if test -n "$REPORT_FILES"; then + $MAKE $REPORT_FILES || exit 1 +fi + +test -z "$srcdir" && srcdir=. +stat=0 + +if test -f "$DOC_MODULE-undeclared.txt"; then + undeclared=`cat "$DOC_MODULE-undeclared.txt"` + if test -n "$undeclared"; then + echo "*** ERROR: Undeclared documentation symbols:" 1>&2 + cat "$DOC_MODULE-undeclared.txt" 1>&2 + stat=1 + fi +fi >&2 +if test -f "$DOC_MODULE-unused.txt"; then + unused=`cat "$DOC_MODULE-unused.txt"` + if test -n "$unused"; then + echo "*** ERROR: Unused documented symbols:" 1>&2 + cat "$DOC_MODULE-unused.txt" 1>&2 + stat=1 + fi +fi >&2 +if test -f "$DOC_MODULE-undocumented.txt"; then + if grep '^0 symbols incomplete' "$DOC_MODULE-undocumented.txt" >/dev/null && + grep '^0 not documented' "$DOC_MODULE-undocumented.txt" >/dev/null; then + : + else + echo "*** ERROR: Incomplete or undocumented symbols:" 1>&2 + cat "$DOC_MODULE-undocumented.txt" 1>&2 + stat=1 + fi +fi >&2 + +if test $stat != 0; then + echo "*** IGNORING ERROR ***" +fi +#exit $stat +exit 0 diff --git a/local/recipes/libs/cairo/source/doc/public/check-doc-syntax.sh b/local/recipes/libs/cairo/source/doc/public/check-doc-syntax.sh new file mode 100755 index 0000000000..129065d2ac --- /dev/null +++ b/local/recipes/libs/cairo/source/doc/public/check-doc-syntax.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +LC_ALL=C +export LC_ALL + +test -z "$srcdir" && srcdir=. +test -z "$top_srcdir" && top_srcdir=$srcdir/../.. + +SGML_DOCS=true +FILES=`echo $srcdir/tmpl/*.sgml` + +. "$top_srcdir/src/check-doc-syntax.sh" diff --git a/local/recipes/libs/cairo/source/doc/public/language-bindings.xml b/local/recipes/libs/cairo/source/doc/public/language-bindings.xml new file mode 100644 index 0000000000..1d04ec0186 --- /dev/null +++ b/local/recipes/libs/cairo/source/doc/public/language-bindings.xml @@ -0,0 +1,734 @@ + + Creating a language binding for cairo + + While cairo is implemented and C, and has a C API, it is expected + that many users of cairo will be using it from languages other + than C. The glue that connects the core cairo library to another + language is known as a language + binding. This appendix attempts to collect together + issues that come up when creating a language bindings for cairo + and present standardized solutions to promote consistency among + the different language bindings. + + + General considerations + + The naming of the central cairo_t type is a + special exception. The object is “a cairo context†not “a + cairoâ€, and names such as cairo_t rather than + cairo_context_t and + cairo_set_source() rather than + cairo_context_set_source() are simply + abbreviations to make the C API more palatable. In languages + which have object-oriented syntax, this abbreviation is much + less useful. In fact, if ‘Cairo’ is used as a namespace, then + in many languages, you'd end up with a ridiculous type name + like ‘Cairo.Cairo’. For this reason, and for inter-language + consistency all object-oriented languages should name this + type as if it were cairo_context_t. + + + The punctuation and casing of the type names and + method names of cairo should be changed to match the general + convention of the language. In Java, where type names are written + in StudlyCaps and method names in javaCaps, cairo_font_extents_t + will become FontExtents and + cairo_set_source(cr,source), + cr.setSource(source). + As compared to changing the punctuation, and casing, much + more reluctance should be used in changing the method names + themselves. Even if get is usually omitted from getters in + your language, you shouldn't bind cairo_get_source() as + cr.source(). + + + + Memory management + + The objects in cairo can roughly be divided into two types: + reference-counted, opaque types like + cairo_surface_t + and plain structures like + cairo_glyph_t. + cairo_path_t + and + cairo_path_data_t + are special cases and are treated separately in this appendix. + + + Refcounted opaque types all have a + ..._reference() + function to increase the refcount by one and a + ..._destroy() to decrease the refcount + by one. These should not be exposed to the user of the language + binding, but rather used to implement memory management within + the language binding. The simplest way to do memory management + for a language binding is to treat the language binding object + as a simple handle to the cairo object. The language binding + object references the cairo object, and unreferences it when + finalized. This is the recommended method, though there are + a couple of caveats to be noted: + + + + + Equality won't work as expected. You can have two language + objects for the same cairo and they won't necessarily + compare equal. If the language allows customizing the + equality operation, then this is fixable by comparing + the underlying pointers. It also can be fixed by creating + at most one language object per cairo object, and + uniquifying via a pin table (a hash + table that goes from cairo object to language object). + For cairo_surface_t you can use also + cairo_surface_set_user_data() + instead of a separate pin table. + + + + + Derivation from the language object doesn't work because + you can lose the language object while keeping the Cairo + object. Code like: + + +public class MySurface (ImageSurface) { + public MySurface (width, height) { + super (Format.ARGB32, width, height); + } + public int get42 () { + return 42; + } +} + + cr = Cairo(MySurface(width, height)); + surface = cr.getTarget(); + + + Can result in surface containing an + ImageSurface not a MySurface. + This is not easily fixable without creating memory leaks, + and it's probably best to simply forbid deriving from the + language objects. + + + + + When a plain structure is used as a return value from cairo, + this is done by passing it as a “out parameterâ€. + + +cairo_font_extents_t extents; + +cairo_font_extents (cr, &extents); + + In a language binding, this should typically be treated + as a return value: + + +FontExtents extents = cr.fontExtents (); + + A language binding has a choice in how it implements the + language objects for plain structures. It can use a pure + language object with fields corresponding to those of the C + structure, and convert from and to the C structure when calling + cairo functions or converting cairo return values. Or it + can keep a pointer to the C structure internally and wrap + it inside a language object much like occurs for refcounted + objects. The choice should be invisible to the user: they should + be able to imagine that it is implemented as a pure language + object. + + + + Multiple return values + + There are a number of functions in the cairo API that have + multiple out parameters or + in-out parameters. In some languages + these can be translated into multiple return values. In Python, + what is: + + +cairo_user_to_device (cr, &x, &y); + + can by mapped to: + + +(x, y) = cr.user_to_device (cr, x, y); + + but many languages don't have provisions for multiple return + values, so it is necessary to introduce auxiliary types. + Most of the functions that require the auxiliary types + require a type that would, in C, look like + + +typedef struct _cairo_point cairo_point_t; +struct _cairo_point { + double x; + double y; +} + + The same type should be used both for functions that use a pair + of coordinates as an absolute position, and functions that use + a pair of coordinates as a displacement. While an argument could + be made that having a separate “distance†type is more correct, + it is more likely just to confuse users. + + +void +cairo_user_to_device (cairo_t *cr, double *x, double *y); + +void +cairo_user_to_device_distance (cairo_t *cr, double *dx, double *dy); + +void +cairo_device_to_user (cairo_t *cr, double *x, double *y); + +void +cairo_device_to_user_distance (cairo_t *cr, double *dx, double *dy); + +void +cairo_matrix_transform_distance (cairo_matrix_t *matrix, double *dx, double *dy); + +void +cairo_matrix_transform_point (cairo_matrix_t *matrix, double *x, double *y); + +void +cairo_get_current_point (cairo_t *cr, double *x, double *y); + + + There are also a couple of functions that return four values + representing a rectangle. These should be mapped to a + “rectangle†type that looks like: + + +typedef struct _cairo_rectangle cairo_rectangle_t; +struct _cairo_rectangle { + double x; + double y; + double width; + double height; +} + + The C function returns the rectangle as a set of two points to + facilitate rounding to integral extents, but this isn't worth + adding a “box†type to go along with the more obvious + “rectangle†representation. + + + Q: Would it make sense here to define a standard + cairo_rectangle_round() method + that language bindings should map? + + +void +cairo_stroke_extents (cairo_t *cr, + double *x1, double *y1, + double *x2, double *y2); + +void +cairo_fill_extents (cairo_t *cr, + double *x1, double *y1, + double *x2, double *y2); + + + + Overloading and optional arguments + + Function overloading (having a several variants of a function + with the same name and different arguments) is a language + feature available in many languages but not in C. + + + In general, language binding authors should use restraint in + combining functions in the cairo API via function + overloading. What may seem like an obvious overload now may + turn out to be strange with future additions to cairo. + It might seem logical to make + cairo_set_source_rgb() + an overload of cairo_set_source(), but future plans to add + cairo_set_source_rgb_premultiplied(), + which will also take three doubles make this a bad idea. For + this reason, only the following pairs of functions should + be combined via overloading + + +void +cairo_set_source (cairo_t *cr, cairo_pattern_t *source); + +void +cairo_set_source_surface (cairo_t *cr, + cairo_surface_t *source, + double surface_x, + double surface_y); + +void +cairo_mask (cairo_t *cr, + cairo_pattern_t *pattern); + +void +cairo_mask_surface (cairo_t *cr, + cairo_surface_t *surface, + double surface_x, + double surface_y); + +cairo_surface_t * +cairo_image_surface_create (cairo_format_t format, + int width, + int height); +cairo_surface_t * +cairo_image_surface_create_for_data (unsigned char *data, + cairo_format_t format, + int width, + int height, + int stride); + +cairo_status_t +cairo_surface_write_to_png (cairo_surface_t *surface, + const char *filename); + +cairo_status_t +cairo_surface_write_to_png_stream (cairo_surface_t *surface, + cairo_write_func_t write_func, + void *closure); + +cairo_surface_t * +cairo_image_surface_create_from_png (const char *filename); + +cairo_surface_t * +cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func, + void *closure); + + + Note that there are cases where all constructors for a type + aren't overloaded together. For example + cairo_image_surface_create_from_png() + should not be overloaded together with + cairo_image_surface_create(). + In such cases, the remaining constructors will typically need to + be bound as static methods. In Java, for example, we might have: + + +Surface surface1 = ImageSurface(Format.RGB24, 100, 100); +Surface surface2 = ImageSurface.createFromPNG("camera.png"); + + Some other overloads that add combinations not found in C may be + convenient for users for language bindings that provide + cairo_point_t and cairo_rectangle_t + types, for example: + + +void +cairo_move_to (cairo_t *cr, + cairo_point_t *point); +void +cairo_rectangle (cairo_t *cr, + cairo_rectangle_t *rectangle); + + + + Streams and File I/O + + Various places in the cairo API deal with reading and writing + data, whether from and to files, or to other sources and + destinations. In these cases, what is typically provided in the + C API is a simple version that just takes a filename, and a + complex version that takes a callback function. + An example is the PNG handling functions: + + +cairo_surface_t * +cairo_image_surface_create_from_png (const char *filename); + +cairo_surface_t * +cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func, + void *closure); + +cairo_status_t +cairo_surface_write_to_png (cairo_surface_t *surface, + const char *filename); + +cairo_status_t +cairo_surface_write_to_png_stream (cairo_surface_t *surface, + cairo_write_func_t write_func, + void *closure); + + The expectation is that the filename version will be mapped + literally in the language binding, but the callback version + will be mapped to a version that takes a language stream + object. For example, in Java, the four functions above + might be mapped to: + + +static public ImageSurface createFromPNG (String filename) throws IOException; +static public ImageSurface createFromPNG (InputStream stream) throws IOException; +public void writeToPNG (String filename) throws IOException; +public void writeToPNG (OutputStream stream) throws IOException; + + + In many cases, it will be better to + implement the filename version internally + using the stream version, rather than building it on top of the + filename version in C. The reason for this is that will + naturally give a more standard handling of file errors for + the language, as seen in the above Java example, where + createFromPNG() is marked as raising + an exception. Propagating exceptions from inside the callback + function to the caller will pose a challenge to the language + binding implementor, since an exception must not propagate + through the Cairo code. A technique that will be useful in + some cases is to catch the exception in the callback, + store the exception object inside a structure pointed to by + closure, and then rethrow it once + the function returns. + + + I'm not sure how to handle this for + cairo_pdf_surface_create_for_stream(). + Other than keep a “exception to rethrow†thread-specific + variable + that is checked after every call to a Cairo + function. + + + + Error handling + + The error handling approach in C for Cairo has multiple + elements: + + + + When a method on an object fails, the object is put into + an error state. Subsequent operations on the object do + nothing. The status of the object can be queried with + a function like status(). + + + Constructors, rather than + returning NULL on out-of-memory failure, + return a special singleton object on which all + operations do nothing. Retrieving the status of the + singleton object returns CAIRO_STATUS_NO_MEMORY + + + + Errors propagate from object to object. Setting a pattern + in an out-of-memory state as the source of a + cairo_t puts the type into an error state. + + + + A language binding could copy the C approach, and for a + language without exceptions, this is likely the right thing + to do. However, for a language with exceptions, exposing + a completely different style of error handling for cairo + would be strange. So, instead, status should be checked + after every call to cairo, and exceptions thrown as necessary. + + + One problem that can arise with this, in languages + where handling exceptions is mandatory (like Java), is that almost + every cairo function can result in a status being set, + usually because of an out-of-memory condition. This could make + cairo hard to use. To resolve this problem, let's classify then + cairo status codes: + + +/* Memory */ +CAIRO_STATUS_NO_MEMORY, + +/* Programmer error */ +CAIRO_STATUS_INVALID_RESTORE +CAIRO_STATUS_INVALID_POP_GROUP +CAIRO_STATUS_NO_CURRENT_POINT +CAIRO_STATUS_INVALID_MATRIX +CAIRO_STATUS_NO_TARGET_SURFACE +CAIRO_STATUS_INVALID_STRING +CAIRO_STATUS_SURFACE_FINISHED +CAIRO_STATUS_BAD_NESTING + +/* Language binding implementation */ +CAIRO_STATUS_NULL_POINTER +CAIRO_STATUS_INVALID_PATH_DATA +CAIRO_STATUS_SURFACE_TYPE_MISMATCH + +/* Other */ +CAIRO_STATUS_READ_ERROR +CAIRO_STATUS_WRITE_ERROR + + + If we look at these, the + CAIRO_STATUS_NO_MEMORY + should map to the native out-of-memory exception, which could + happen at any point in any case. Most of the others indicate + programmer error, and handling them in user code would be + silly. These should be mapped into whatever the language uses + for assertion failures, rather than errors that are normally + handled. (In Java, a subclass of Error rather than Exception, + perhaps.) And CAIRO_STATUS_READ_ERROR, + and CAIRO_STATUS_WRITE_ERROR can occur + only in very specific places. (In fact, as described + in , these errors may be + mapped into the language's native I/O error types.) + So, there really aren't exceptions that the programmer must + handle at most points in the Cairo API. + + + + Patterns + + The cairo C API allows for creating a number of different types + of patterns. All of these different types of patterns map to + cairo_pattern_t + in C, but in an object oriented language, there should instead + be a hierarchy of types. (The functions that should map to + constructors or static methods for the various types are listed + after the type, methods on that type are listed below. Note that + cairo_pattern_create_rgb() and cairo_pattern_create_rgba() + should not be overloaded with each other as a SolidPattern() + constructor, but should appear as static methods instead. This + is to maintain code clarity by making it clear how the arguments + relate to color components.) + + +cairo_pattern_t + cairo_pattern_set_matrix() + cairo_pattern_get_matrix() + cairo_solid_pattern_t (cairo_pattern_create_rgb() and cairo_pattern_create_rgba()) + cairo_surface_pattern_t (cairo_pattern_create_for_surface()) + cairo_pattern_set_extend() + cairo_pattern_get_extend() + cairo_pattern_set_filter() + cairo_pattern_get_filter() + cairo_gradient_t + cairo_pattern_add_color_stop_rgb() + cairo_pattern_add_color_stop_rgba() + cairo_linear_gradient_t (cairo_pattern_create_linear()) + cairo_radial_gradient_t (cairo_pattern_create_radial()) + cairo_mesh_t (cairo_pattern_create_mesh()) + cairo_mesh_pattern_begin_patch() + cairo_mesh_pattern_end_patch() + cairo_mesh_pattern_move_to() + cairo_mesh_pattern_line_to() + cairo_mesh_pattern_curve_to() + cairo_mesh_pattern_set_control_point() + cairo_mesh_pattern_set_corner_color_rgb() + cairo_mesh_pattern_set_corner_color_rgba() + cairo_mesh_pattern_get_patch_count() + cairo_mesh_pattern_get_path() + cairo_mesh_pattern_get_control_point() + cairo_mesh_pattern_get_corner_color_rgba() + + + + + + Surfaces + + Like patterns, surfaces, which use only the + cairo_surface_t + type in the C API should be broken up into a hierarchy of types + in a language binding. + + +cairo_surface_t + cairo_image_surface_t + cairo_atsui_surface_t + cairo_win32_surface_t + cairo_xlib_surface_t + + + Unlike patterns, the constructors and methods on these types are + clearly named, and can be trivially associated with the + appropriate subtype. Many language bindings will want to avoid + binding the platform-specific subtypes at all, since the + methods on these types are not useful without passing in native + C types. Unless there is a language binding for Xlib available, + there is no way to represent a XLib Display * in + that language. + + + This doesn't mean that platform-specific surface types can't + be used in a language binding that doesn't bind the constructor. + A very common situation is to use a cairo language binding in + combination with a binding for a higher level system like + the GTK+ widget + toolkit. In such a situation, the higher level toolkit provides + ways to get references to platform specific surfaces. + + + The cairo_surface_set_user_data(), + and cairo_surface_get_user_data() + methods are provided for use in language bindings, and should + not be directly exposed to applications. One example of the use + of these functions in a language binding is creating a binding for: + + +cairo_surface_t * +cairo_image_surface_create_for_data (unsigned char *data, + cairo_format_t format, + int width, + int height, + int stride); + + + The memory block passed in for data must be + kept around until the surface is destroyed, so the language + binding must have some way of determining when that happens. The + way to do this is to use the destroy + argument to cairo_surface_set_user_data(). + + + Some languages may not have a suitable “pointer to a block of + data†type to pass in for data. And even + where a language does have such a type, the user will be + frequently able to cause the backing store to be reallocated + to a different location or truncated. Should we recommend a + standard type name and binding for a buffer object here? + + + + Fonts + + Fonts are once more an area where there is a hierarchy of types: + + +cairo_font_face_t + cairo_ft_font_face_t + cairo_win32_font_face_t +cairo_scaled_font_t + cairo_ft_scaled_font_t + cairo_win32_scaled_font_t + + + The methods on the subtypes are, however, not useful without + bindings for fontconfig and FreeType or for the Win32 GDI, + so most language bindings will choose not to bind these + types. + + + The cairo_font_face_set_user_data(), + and cairo_font_face_get_user_data() + methods are provided for use in language bindings, and should + not be directly exposed to applications. + + + + cairo_path_t + + The cairo_path_t type is one + area in which most language bindings will differ significantly + from the C API. The C API for cairo_path_t is + designed for efficiency and to avoid auxiliary objects that + would be have to be manually memory managed by the + application. However, + a language binding should not present cairo_path_t as an + array, but rather as an opaque that can be iterated + over. Different languages have quite different conventions for + how iterators work, so it is impossible to give an exact + specification for how this API should work, but the type names + and methods should be similar to the language's mapping of the following: + + +typedef struct cairo_path_iterator cairo_path_iterator_t; +typedef struct cairo_path_element cairo_path_element_t; + +cairo_path_iterator_t * +cairo_path_get_iterator (cairo_path_t *path); + +cairo_bool_t +cairo_path_iterator_has_next (cairo_path_iterator_t *iterator); + +cairo_path_element_t * +cairo_path_iterator_next (cairo_path_iterator_t *iterator); + +cairo_path_element_type_t +cairo_path_element_get_type (cairo_path_element_t *element); + +void +cairo_path_element_get_point (cairo_path_element_t *element, + int index, + double *x, + double *y); + + + The above is written using the Java conventions for + iterators. To illustrate how the API for PathIterator might + depend on the native iteration conventions of the API, examine + three versions of the loop, first written in a hypothetical Java + binding: + + +PathIterator iter = cr.copyPath().iterator(); +while (cr.hasNext()) { + PathElement element = iter.next(); + if (element.getType() == PathElementType.MOVE_TO) { + Point p = element.getPoint(0); + doMoveTo (p.x, p.y); + } +} + + And then in a hypothetical C++ binding: + + +Path path = cr.copyPath(); +for (PathIterator iter = path.begin(); iter != path.end(); iter++) { + PathElement element = *iter; + if (element.getType() == PathElementType.MOVE_TO) { + Point p = element.getPoint(0); + doMoveTo (p.x, p.y); + } +} + + And then finally in a Python binding: + + +for element in cr.copy_path(): + if element.getType == cairo.PATH_ELEMENT_MOVE_TO: + (x, y) = element.getPoint(0) + doMoveTo (x, y); + + While many of the API elements stay the same in the three + examples, the exact iteration mechanism is quite different, to + match how users of the language would expect to iterate over + a container. + + + You should not present an API for mutating or for creating new + cairo_path_t objects. In the future, these + guidelines may be extended to present an API for creating a + cairo_path_t from scratch for use with + cairo_append_path() + but the current expectation is that cairo_append_path() will + mostly be used with paths from + cairo_copy_path(). + + + + diff --git a/local/recipes/libs/cairo/source/doc/public/meson.build b/local/recipes/libs/cairo/source/doc/public/meson.build new file mode 100644 index 0000000000..278ef47034 --- /dev/null +++ b/local/recipes/libs/cairo/source/doc/public/meson.build @@ -0,0 +1,156 @@ +gnome = import('gnome') + +ignore_headers = [ + # Sub-directories + 'win32', + + # Internal headers + 'cairoint.h', + 'cairo-features.h', + 'cairo-features-win32.h', + + # Inlined API + 'cairo-box-inline.h', + 'cairo-clip-inline.h', + 'cairo-combsort-inline.h', + 'cairo-contour-inline.h', + 'cairo-error-inline.h', + 'cairo-image-surface-inline.h', + 'cairo-line-inline.h', + 'cairo-list-inline.h', + 'cairo-pattern-inline.h', + 'cairo-recording-surface-inline.h', + 'cairo-surface-inline.h', + 'cairo-surface-observer-inline.h', + 'cairo-surface-snapshot-inline.h', + 'cairo-surface-subsurface-inline.h', + + # Private headers + 'cairo-analysis-surface-private.h', + 'cairo-arc-private.h', + 'cairo-array-private.h', + 'cairo-atomic-private.h', + 'cairo-backend-private.h', + 'cairo-boxes-private.h', + 'cairo-cache-private.h', + 'cairo-clip-private.h', + 'cairo-compiler-private.h', + 'cairo-composite-rectangles-private.h', + 'cairo-compositor-private.h', + 'cairo-contour-private.h', + 'cairo-damage-private.h', + 'cairo-default-context-private.h', + 'cairo-deprecated.h', + 'cairo-device-private.h', + 'cairo-error-private.h', + 'cairo-fixed-private.h', + 'cairo-fixed-type-private.h', + 'cairo-fontconfig-private.h', + 'cairo-freed-pool-private.h', + 'cairo-freelist-private.h', + 'cairo-freelist-type-private.h', + 'cairo-ft-private.h', + 'cairo-gstate-private.h', + 'cairo-hash-private.h', + 'cairo-image-info-private.h', + 'cairo-image-surface-private.h', + 'cairo-line-private.h', + 'cairo-list-private.h', + 'cairo-malloc-private.h', + 'cairo-mempool-private.h', + 'cairo-mutex-impl-private.h', + 'cairo-mutex-list-private.h', + 'cairo-mutex-private.h', + 'cairo-mutex-type-private.h', + 'cairo-output-stream-private.h', + 'cairo-paginated-private.h', + 'cairo-paginated-surface-private.h', + 'cairo-path-fixed-private.h', + 'cairo-path-private.h', + 'cairo-pattern-private.h', + 'cairo-pdf-operators-private.h', + 'cairo-pdf-shading-private.h', + 'cairo-pdf-surface-private.h', + 'cairo-pixman-private.h', + 'cairo-private.h', + 'cairo-ps-surface-private.h', + 'cairo-quartz-private.h', + 'cairo-recording-surface-private.h', + 'cairo-reference-count-private.h', + 'cairo-region-private.h', + 'cairo-rtree-private.h', + 'cairo-scaled-font-private.h', + 'cairo-scaled-font-subsets-private.h', + 'cairo-script-private.h', + 'cairo-slope-private.h', + 'cairo-spans-compositor-private.h', + 'cairo-spans-private.h', + 'cairo-stroke-dash-private.h', + 'cairo-surface-backend-private.h', + 'cairo-surface-clipper-private.h', + 'cairo-surface-fallback-private.h', + 'cairo-surface-observer-private.h', + 'cairo-surface-offset-private.h', + 'cairo-surface-private.h', + 'cairo-surface-snapshot-private.h', + 'cairo-surface-subsurface-private.h', + 'cairo-surface-wrapper-private.h', + 'cairo-svg-surface-private.h', + 'cairo-tag-attributes-private.h', + 'cairo-tag-stack-private.h', + 'cairo-time-private.h', + 'cairo-traps-private.h', + 'cairo-tristrip-private.h', + 'cairo-truetype-subset-private.h', + 'cairo-type1-private.h', + 'cairo-type3-glyph-surface-private.h', + 'cairo-types-private.h', + 'cairo-user-font-private.h', + 'cairo-wideint-private.h', + 'cairo-wideint-type-private.h', + 'cairo-xcb-private.h', + 'cairo-xlib-private.h', + 'cairo-xlib-surface-private.h', + 'cairo-xlib-xrender-private.h', + 'test-compositor-surface-private.h', +] + +ignore_decorators = [ + 'cairo_public', + 'cairo_private', +] + +docpath = get_option('prefix') / get_option('datadir') / 'gtk-doc/html' +version_conf = configuration_data() +version_conf.set('CAIRO_VERSION', meson.project_version()) +configure_file( + input: 'version.xml.in', + output: 'version.xml', + configuration: version_conf +) + +gnome.gtkdoc('cairo', + main_xml: 'cairo-docs.xml', + namespace: 'cairo', + mode: 'sgml', + src_dir: doc_srcdir, + dependencies: libcairo_dep, + scan_args: [ + '--ignore-decorators=' + '|'.join(ignore_decorators), + '--ignore-headers=' + ' '.join(ignore_headers), + ], + mkdb_args: ['--source-suffixes=h,c,cpp'], + content_files: [ + 'language-bindings.xml', + ], + expand_content_files: [ + 'language-bindings.xml', + ], + html_assets: [ + ], + fixxref_args: [ + '--html-dir=' + docpath, + ], + install: true, + check: true, +) diff --git a/local/recipes/libs/cairo/source/doc/public/version.xml.in b/local/recipes/libs/cairo/source/doc/public/version.xml.in new file mode 100644 index 0000000000..6bd185791f --- /dev/null +++ b/local/recipes/libs/cairo/source/doc/public/version.xml.in @@ -0,0 +1 @@ +@CAIRO_VERSION@ diff --git a/local/recipes/libs/cairo/source/doc/releasing.md b/local/recipes/libs/cairo/source/doc/releasing.md new file mode 100644 index 0000000000..ab5abb62bc --- /dev/null +++ b/local/recipes/libs/cairo/source/doc/releasing.md @@ -0,0 +1,175 @@ +# Releasing Cairo + +Here are the steps to follow to create a new cairo release: + +## 0. Decide type of release and checkout the appropriate branch + +The Cairo project makes three types of releases: Development snapshot +releases, stable minor releases, and stable micro (aka "point") releases. +Micro releases should be only bugfixes and no API additions. If there are +API additions consider making a Minor release. Snapshot releases can be +done of the current development tree between Minor releases, as desired. + +For stable releases (both minor and micro), the work should be done on the +given release branch. E.g. for 1.14.12, check out the 1.14 branch via "git +checkout origin/1.14 -b 1.14". + +## 1. Ensure that there are no local, uncommitted/unpushed mods + +You're probably in a good state if both "git diff HEAD" and "git log +master..origin/master" give no output. + +## 2. Verify that the code passes `meson dist` + +First, make sure you have 'nm' and 'readelf' commands in `PATH`. this +should be OK with any Linux distro. + +Running "meson dist" should result in no warnings or errors and end with a +message of the form: + + Created source/cairo/_build/meson-dist/cairo-1.17.8.tar.xz + +If the test suite does not pass, you can use: + + meson dist --no-tests + +But this should only be allowed for development snapshots. Please, always +check the state of the CI pipeline on GitLab. + +## 3. Decide what the new version number for the release will be. + +Cairo uses even numbers for official releases, and odd numbers for +development snapshots. Thus, for a Minor release it would be: + + LAST_RELEASE="X.Y.Z" # e.g. 1.12.0 + THIS_RELEASE="X.Y+2.0" # e.g. 1.14.0 + +While for a Micro release the version numbers should be: + + LAST_RELEASE="X.Y.Z" # e.g. 1.14.0 + THIS_RELEASE="X.Y.Z+2" # e.g. 1.14.2 + +Snapshots are similar but have odd minor versions. Also, the first snapshot +release in a new series will be .2 rather than .0, e.g.: + + LAST_RELEASE="X.Y.Z" # e.g. 1.14.0 + THIS_RELEASE="X.Y+1.0" # e.g. 1.15.2 + +and subsequent snapshots in that series are just normal micro releases: + + LAST_RELEASE="X.Y.Z" # e.g. 1.15.2 + THIS_RELEASE="X.Y.Z+2" # e.g. 1.15.4 + +## 4. Fill out an entry in the NEWS file + +Sift through the logs since the last release. This is most easily done with +a command such as: + + git log --stat ${LAST_RELEASE}.. + +Summarize major changes briefly in a style similar to other entries in NEWS. +Take special care to note any additions in the API. These should be easy to +find by noting modifications to .h files in the log command above. And more +specifically, the following command will show each patch that has changed a +public header file since the given version: + +``` +find src/ -name '*.h' ! -name '*-private.h' \ + ! -name 'cairoint.h' ! -name 'cairo-*features*.h' | \ + xargs git diff ${LAST_RELEASE}.. -- +``` + + +## 5. Increment `CAIRO_VERSION_{MINOR|MICRO}` in `src/cairo-version.h`: + +If there are backward-incompatible changes in the API, stop now and don't +release. Go back and fix the API instead. Cairo is intended to remain +backwards-compatible as far as API. + +So `CAIRO_VERSION_MAJOR` will not be incremented unless we come up with a +new versioning scheme to take advantage of it. + +If there are API additions, then increment `CAIRO_VERSION_MINOR` and reset +`CAIRO_VERSION_MICRO` to 0. **NOTE**: The minor version is only incremented +for releases, not for snapshots. + +Otherwise, (i.e. there are only bug fixes), increment `CAIRO_VERSION_MICRO` +to the next larger (even) number. + +## 6. For Minor releases, add an index entry to `doc/public/cairo-docs.xml` + +Towards the end of the file, add a new section for the stable release. +It'll look something like: + +```xml + + Index of new symbols in X.Y + + +``` + +## 7. Commit the changes to `NEWS` and `src/cairo-version.h` + +It's especially important to mention the new version number in your commit +log. + +## 8. Generate the release archive + +The `meson dist` command will: + + * Generate the final tar file + * Generate an sha1sum file + +Once you have the release archive you will need to: + + * Sign the sha1sum using your GPG setup (asks for your GPG password) + * `scp` the three files to appear on https://cairographics.org/releases + * Generate a versioned manual and upload it to appear as both: + - `https://cairographics.org/manual-${THIS_RELEASE}` + - `https://cairographics.org/manual` + * Place local copies of the three files in the releases directory + * Create a `LATEST-{package_version}` file (after deleting any old one) + * Tag the entire source tree with a `${THIS_RELEASE}` tag, and sign the + tag with your GPG key (asks for your GPG password, and you may need to + set `GIT_COMMITTER_NAME` and `GIT_COMMITTER_EMAIL` to match your + public-key's setting or this fails.) + * Provide some text for the release announcement (see below). + +## 9. Update master (or the stable branch) version number. + +For Micro releases (X.Y.Z+2), increment `CAIRO_VERSION_MICRO` to the next +larger (odd) number in `src/cairo-version.h`. + + DEVEL_VERSION="X.Y.Z+1" # e.g. 1.15.10 -> 1.15.11 + +For Minor releases (X.Y.0), increment `CAIRO_VERSION_MINOR` to the next +larger (odd) number, and set `CAIRO_VERSION_MICRO` to 1. + + DEVEL_VERSION="X.Y.Z+1" # e.g. 1.16.0 -> 1.17.1 + +Then, commit: + + git commit src/cairo-version.h -m "Bump version for ${DEVEL_VERSION}" + +## 9. Push the new tag out + +Use: + + git push --atomic origin master ${THIS_RELEASE} + +to ensure that both the tag and the latest changes in your tree are uploaded +at the same time. + +## 10. Send out an announcement message. + +Send a message to cairo-announce@cairographics.org and CC +cairo@cairographics.org, and ftp-release@lists.freedesktop.org (pr@lwn.net +as well for major releases) to announce the release, adding the excerpt from +NEWS and the shortlog of all changes since last release, generated by: + + git shortlog ${LAST_RELEASE}... + +## 11. Add the announcement to the website + +Add a new entry in the `news` directory. It will automatically get indexed +onto the homepage when the site refreshes. diff --git a/local/recipes/libs/cairo/source/doc/tutorial/slides/.gitignore b/local/recipes/libs/cairo/source/doc/tutorial/slides/.gitignore new file mode 100644 index 0000000000..72a67a02c8 --- /dev/null +++ b/local/recipes/libs/cairo/source/doc/tutorial/slides/.gitignore @@ -0,0 +1,7 @@ +tutorial-???.html +tutorial-???.png +tutorial-???.svg +tutorial-index.xml +tutorial.pdf +index.html +*~ diff --git a/local/recipes/libs/cairo/source/doc/tutorial/slides/cairo-blank.svg b/local/recipes/libs/cairo/source/doc/tutorial/slides/cairo-blank.svg new file mode 100644 index 0000000000..a338ee1b2d --- /dev/null +++ b/local/recipes/libs/cairo/source/doc/tutorial/slides/cairo-blank.svg @@ -0,0 +1,477 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + g> + + + + + + + + + Slide Title + + + + + + Slide content + + + + https://cairographics.org + + + diff --git a/local/recipes/libs/cairo/source/doc/tutorial/slides/cairo-code.svg b/local/recipes/libs/cairo/source/doc/tutorial/slides/cairo-code.svg new file mode 100644 index 0000000000..2204ffc924 --- /dev/null +++ b/local/recipes/libs/cairo/source/doc/tutorial/slides/cairo-code.svg @@ -0,0 +1,913 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + g> + + > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Presentation Sub-title + + + + + + + + Slide Title + + + + + + Slide content + + + + https://cairographics.org + + + diff --git a/local/recipes/libs/cairo/source/doc/tutorial/slides/cairo-large-content.svg b/local/recipes/libs/cairo/source/doc/tutorial/slides/cairo-large-content.svg new file mode 100644 index 0000000000..5acf4c9374 --- /dev/null +++ b/local/recipes/libs/cairo/source/doc/tutorial/slides/cairo-large-content.svg @@ -0,0 +1,899 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + g> + + > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Slide Title + + + + + + Slide content + + + + + diff --git a/local/recipes/libs/cairo/source/doc/tutorial/slides/cairo-separator.svg b/local/recipes/libs/cairo/source/doc/tutorial/slides/cairo-separator.svg new file mode 100644 index 0000000000..816223218b --- /dev/null +++ b/local/recipes/libs/cairo/source/doc/tutorial/slides/cairo-separator.svg @@ -0,0 +1,909 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + g> + + > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Presentation Sub-title + + + + + + Slide Title + + + + + Slide content + + + + https://cairographics.org + + + diff --git a/local/recipes/libs/cairo/source/doc/tutorial/slides/cairo-title.svg b/local/recipes/libs/cairo/source/doc/tutorial/slides/cairo-title.svg new file mode 100644 index 0000000000..31b14f83b8 --- /dev/null +++ b/local/recipes/libs/cairo/source/doc/tutorial/slides/cairo-title.svg @@ -0,0 +1,898 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + g> + + > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Presentation Title + + + + + Slide content + + + + + + diff --git a/local/recipes/libs/cairo/source/doc/tutorial/slides/cairo.svg b/local/recipes/libs/cairo/source/doc/tutorial/slides/cairo.svg new file mode 100644 index 0000000000..5823c29c17 --- /dev/null +++ b/local/recipes/libs/cairo/source/doc/tutorial/slides/cairo.svg @@ -0,0 +1,898 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + g> + + > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Presentation Sub-title + + + + + + + + Really long slide title so you can see + + + + + + Slide content + + + + https://cairographics.org + + + diff --git a/local/recipes/libs/cairo/source/doc/tutorial/slides/circle-cairo-large.png b/local/recipes/libs/cairo/source/doc/tutorial/slides/circle-cairo-large.png new file mode 100644 index 0000000000..a08e1193a1 Binary files /dev/null and b/local/recipes/libs/cairo/source/doc/tutorial/slides/circle-cairo-large.png differ diff --git a/local/recipes/libs/cairo/source/doc/tutorial/slides/circle-cairo.png b/local/recipes/libs/cairo/source/doc/tutorial/slides/circle-cairo.png new file mode 100644 index 0000000000..f5d8cd438c Binary files /dev/null and b/local/recipes/libs/cairo/source/doc/tutorial/slides/circle-cairo.png differ diff --git a/local/recipes/libs/cairo/source/doc/tutorial/slides/circle-ooo-large.png b/local/recipes/libs/cairo/source/doc/tutorial/slides/circle-ooo-large.png new file mode 100644 index 0000000000..dfa40997f6 Binary files /dev/null and b/local/recipes/libs/cairo/source/doc/tutorial/slides/circle-ooo-large.png differ diff --git a/local/recipes/libs/cairo/source/doc/tutorial/slides/circle-ooo.png b/local/recipes/libs/cairo/source/doc/tutorial/slides/circle-ooo.png new file mode 100644 index 0000000000..eb90666e6a Binary files /dev/null and b/local/recipes/libs/cairo/source/doc/tutorial/slides/circle-ooo.png differ diff --git a/local/recipes/libs/cairo/source/doc/tutorial/slides/expander-fuzzy-large.png b/local/recipes/libs/cairo/source/doc/tutorial/slides/expander-fuzzy-large.png new file mode 100644 index 0000000000..3a485da6a8 Binary files /dev/null and b/local/recipes/libs/cairo/source/doc/tutorial/slides/expander-fuzzy-large.png differ diff --git a/local/recipes/libs/cairo/source/doc/tutorial/slides/expander-fuzzy.png b/local/recipes/libs/cairo/source/doc/tutorial/slides/expander-fuzzy.png new file mode 100644 index 0000000000..b01fd636e0 Binary files /dev/null and b/local/recipes/libs/cairo/source/doc/tutorial/slides/expander-fuzzy.png differ diff --git a/local/recipes/libs/cairo/source/doc/tutorial/slides/expander-sharp-large.png b/local/recipes/libs/cairo/source/doc/tutorial/slides/expander-sharp-large.png new file mode 100644 index 0000000000..f97fa06a4a Binary files /dev/null and b/local/recipes/libs/cairo/source/doc/tutorial/slides/expander-sharp-large.png differ diff --git a/local/recipes/libs/cairo/source/doc/tutorial/slides/expander-sharp.png b/local/recipes/libs/cairo/source/doc/tutorial/slides/expander-sharp.png new file mode 100644 index 0000000000..40759aef70 Binary files /dev/null and b/local/recipes/libs/cairo/source/doc/tutorial/slides/expander-sharp.png differ diff --git a/local/recipes/libs/cairo/source/doc/tutorial/slides/fuzzies.svg b/local/recipes/libs/cairo/source/doc/tutorial/slides/fuzzies.svg new file mode 100644 index 0000000000..df12b8a719 --- /dev/null +++ b/local/recipes/libs/cairo/source/doc/tutorial/slides/fuzzies.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/local/recipes/libs/cairo/source/doc/tutorial/slides/jaggies.svg b/local/recipes/libs/cairo/source/doc/tutorial/slides/jaggies.svg new file mode 100644 index 0000000000..e99d07ba5e --- /dev/null +++ b/local/recipes/libs/cairo/source/doc/tutorial/slides/jaggies.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/local/recipes/libs/cairo/source/doc/tutorial/slides/rendering-model.png b/local/recipes/libs/cairo/source/doc/tutorial/slides/rendering-model.png new file mode 100644 index 0000000000..900898417c Binary files /dev/null and b/local/recipes/libs/cairo/source/doc/tutorial/slides/rendering-model.png differ diff --git a/local/recipes/libs/cairo/source/doc/tutorial/slides/tutorial.xml b/local/recipes/libs/cairo/source/doc/tutorial/slides/tutorial.xml new file mode 100644 index 0000000000..17470d464c --- /dev/null +++ b/local/recipes/libs/cairo/source/doc/tutorial/slides/tutorial.xml @@ -0,0 +1,535 @@ + + + + + + + + https://cairographics.org/tutorial + +
  • wget https://cairographics.org/cairo-tutorial.tar.gz
  • +
  • tar xzf cairo-tutorial.tar.gz
  • +
  • cd cairo-tutorial
  • +
  • make
  • +
  • cat README
  • + + IRC: irc.freenode.net #cairo +
    + + + Carl Worth + Red Hat, Inc. + + linux.conf.au + 2006-01-26 + https://cairographics.org + + + + Jaggies + Fuzzies + Fireworks + + + + + + + + + + + + + + +
  • Let application authors know there are options
  • +
  • Learn to use cairo—patch the applications
  • +
  • Write your own cairo-using applications
  • +
    + + + Various shell cairo programs + + + + #include <cairo.h> + #include <cairo-xlib.h> + int main (void) { + Display *dpy = XOpenDisplay (0); + Window w = XCreateSimpleWindow (dpy,RootWindow (dpy, 0), + 0, 0, WIDTH, HEIGHT, 0, 0, WhitePixel (dpy, 0)); + cairo_surface_t *surface = cairo_xlib_surface_create (dpy, w, + DefaultVisual (dpy, DefaultScreen (dpy)), + WIDTH, HEIGHT); + XEvent ev; + XSelectInput (dpy, w, ExposureMask); + XMapWindow (dpy, w); + while (XNextEvent (dpy, &ev) == 0) + if (ev.type == Expose && !ev.xexpose.count) { + cairo_t *cr = cairo_create (surface); + draw (cr); + cairo_destroy (cr); + } + } + + + + #include <gtk/gtk.h> + static gboolean + handle_expose (GtkWidget *widget, GdkEventExpose *event, gpointer data) { + cairo_t *cr = gdk_cairo_create (widget->window); + draw (cr); + cairo_destroy (cr); + return FALSE; + } + int main (int argc, char **argv) { + GtkWidget *window, *drawing_area; + gtk_init (&argc, &argv); + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_default_size (GTK_WINDOW (window), WIDTH, HEIGHT); + drawing_area = gtk_drawing_area_new (); + gtk_container_add (GTK_CONTAINER (window), drawing_area); + g_signal_connect (drawing_area, "expose-event", + G_CALLBACK (handle_expose), NULL); + gtk_widget_show_all (window); gtk_main (); + } + + + + #include <cairo.h> + + int main (void) + { + cairo_surface_t *surface; + cairo_t *cr; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + WIDTH, HEIGHT); + cr = cairo_create (surface); + draw (cr); + cairo_surface_write_to_png (surface, "foo.png"); + + cairo_surface_destroy (surface); + cairo_destroy (cr); + + return 0; + } + + + + #include <cairo.h> + #include <cairo-pdf.h> + int main (void) + { + cairo_surface_t *surface; + cairo_t *cr; + + surface = cairo_pdf_surface_create ("foo.pdf", WIDTH, HEIGHT); + + cr = cairo_create (surface); + draw (cr); + cairo_show_page (cr); + + cairo_surface_destroy (surface); + cairo_destroy (cr); + + return 0; + } + + + + #!/usr/bin/env python + import gtk + import cairo + + def expose (widget, event): + cr = widget.window.cairo_create () + draw (cr) + + win = gtk.Window () + win.connect ('destroy', gtk.main_quit) + win.set_default_size(WIDTH, HEIGHT) + drawingarea = gtk.DrawingArea () + win.add (drawingarea) + drawingarea.connect ('expose_event', expose) + win.show_all () + gtk.main () + + + + #!/usr/bin/env python + import cairo + + surface = cairo.ImageSurface (cairo.FORMAT_ARGB32, WIDTH, HEIGHT) + cr = cairo.Context (surface) + + draw (cr) + + surface.write_to_png ('foo.png') + + + + autoimport Cairo; + + cairo_t cr = new (WIDTH, HEIGHT); + draw (cr); + + + +
  • C++ (cairomm)
  • +
  • Haskell (hscairo)
  • +
  • Java (CairoJava, cairo-java)
  • +
  • Common Lisp (cl-cairo)
  • +
  • Nickle (cairo-5c)
  • +
  • Objective Caml (cairo-ocaml)
  • +
  • perl (cairo-perl)
  • +
  • python (pycairo)
  • +
  • ruby (rcairo)
  • +
  • squeak (cairo-squeak)
  • +
    + + + + https://cairographics.org/tutorial + https://cairographics.org/cairo-tutorial.tar.gz +
  • tar xzf cairo-tutorial.tar.gz
  • +
  • cd cairo-tutorial
  • +
  • make
  • +
  • cat README
  • + IRC: irc.freenode.net #cairo +
    + + + + + + + + + Here comes the fun part + + + +
      +
    • Paths
    • +
        +
      • construction
      • +
      • filling, stroking
      • +
      +
    • Images
    • +
        +
      • loading from disk
      • +
      • using as source
      • +
      • transforming/filtering
      • +
      +
    • Text
    • +
        +
      • “Toy†API
      • +
      • “Full†API
      • +
      +
    +
    + + +
      +
    • Paths
    • +
        +
      • cairo_stroke
      • +
      • cairo_fill
      • +
      +
    • Images
    • +
        +
      • cairo_paint
      • +
      • cairo_mask
      • +
      • cairo_paint_with_alpha
      • +
      +
    • Text
    • +
        +
      • cairo_show_text (“toyâ€)
      • +
      • cairo_show_glyphs (“fullâ€)
      • +
      +
    +
    + + +
      +
    • Paths consist of lines and splines:
    • +
        +
      • cairo_move_to
      • + start new sub path, set current point +
      • cairo_line_to
      • + add line segment to path +
      • cairo_curve_to
      • + add Bézier spline to path +
      • cairo_close_path
      • + add line segment to last move_to point +
      +
    +
    + + +
      +
    • cairo_stroke
    • +
        +
      • Paints the path itself as stroked by a pen
      • +
      • Controlled by various stroke parameters:
      • +
          +
        • cairo_set_line_width
        • +
        • cairo_set_line_cap
        • +
        • cairo_set_line_join
        • +
        • cairo_set_miter_limit
        • +
        • cairo_set_dash
        • +
        +
      +
    +
    + + + + + + + + +
      +
    • CAIRO_LINE_CAP_BUTT
    • +
    • CAIRO_LINE_CAP_ROUND
    • +
    • CAIRO_LINE_CAP_SQUARE
    • +
    +
    + + +
      +
    • CAIRO_LINE_JOIN_BEVEL
    • +
    • CAIRO_LINE_JOIN_ROUND
    • +
    • CAIRO_LINE_JOIN_MITER
    • +
    +
    + + +
  • Adds a line segment (if necessary) to the
  • + start of the path +
  • Draws a join from that line to the first
  • + element of the path +
    + + + + + +
      +
    • Paints the “inside†of the path
    • +
    • Two different ways to determine inside-ness
    • +
        +
      • cairo_set_fill_rule:
      • + CAIRO_FILL_RULE_WINDING + CAIRO_FILL_RULE_EVEN_ODD +
      +
    +
    + + + + + +
  • To test a point for inside-ness, imagine a ray
  • + from the point and extending to infinity + (any direction) and examine path crossings +
  • EVEN_ODD counts crossings and fills when odd
  • +
  • WINDING counts up/down for left/right crossings
  • + and fills when the final number is not zero +
    + + + + + +
  • All drawing occurs with the source pattern
  • +
  • Uniform-color sources can be set
  • + with or without alpha: +
      +
    • cairo_set_source_rgb
    • +
    • cairo_set_source_rgba
    • +
    +
    + + + + + +
  • cairo_stroke and cairo_fill consume the path
  • +
  • Variants are available to preserve the path:
  • +
      +
    • cairo_stroke_preserve
    • +
    • cairo_fill_preserve
    • +
    +
  • This is a variation from PostScript and PDF
  • +
      +
    • The cairo approach differs in different ways
    • +
    • We think this way is better (of course)
    • +
    +
    + + + + + +
      +
    • cairo_rectangle
    • +
    • cairo_arc
    • +
    • cairo_text_path
    • +
    • cairo_glyph_path
    • +
    • Relative-coordinate variants:
    • +
        +
      • cairo_rel_move_to
      • +
      • cairo_rel_line_to
      • +
      • cairo_rel_curve_to
      • +
      +
    +
    + + + + + + + + +
      +
    • Single matrix combines rotation, translation,
    • + scale and shear +
    • Non-projective transformations
    • +
        +
      • Pen doesn't change shape along the stroke
      • +
      +
    • Transformations are cumulative
    • +
        +
      • translate, scale != scale, translate
      • +
      +
    +
    + + + + + +
      +
    • cairo_save and cairo_restore
    • +
    • Very useful for bracketing function bodies
    • +
    • Eliminates graphics state side effects
    • + +
    • NOTE: Path is not part of graphics state
    • +
        +
      • Path is not affected by cairo_save/restore
      • +
      • Useful for path-generating functions
      • +
      +
    +
    + + +
  • cairo_clip
  • +
  • Intersects path with current clip to further
  • + restrict drawing +
  • Pixel-aligned clipping is much faster
  • +
  • cairo_clip_preserve is available as well
  • +
    + + +
      +
    • Surface patterns
    • +
        +
      • Image from disk
      • +
      • Results of cairo drawing
      • +
      +
    • Gradient patterns
    • +
        +
      • linear gradients
      • +
      • radial gradients
      • +
      +
    +
    + + + + + + + + + + + + + + + + + + + + +
      +
    • “Toy†API:
    • +
        +
      • Useful for demos like we are writing today
      • +
      • No real layout—not useful for the majority
      • + of writing systems in the world +
      +
    • “Full†API:
    • +
        +
      • User must do OS-dependent font selection
      • +
      • User must access font glyph IDs directly
      • +
      • User must do all text layout
      • +
      +
    +
    + + +
      +
    • Simple font selection
    • +
        +
      • family, weight, slant
      • +
      • OS independent
      • +
      • No font listing support
      • +
      +
    • UTF-8 text drawing and extents functions
    • +
    • Still supports full font transformations
    • +
    + + + + + +
  • Just use pango
  • +
    + + +
  • C has no exceptions
  • +
  • Checking each return is tedious
  • +
  • C programmers rarely bother
  • +
  • Lots of broken programs result
  • +
    + + +
  • Cairo stores status value when error occurs
  • +
  • API “shuts down†when an error occurs
  • +
  • All cairo functions are benign
  • + (and well defined) after any error. +
  • cairo_status can be called when convenient
  • +
  • Error status values propagate across objects
  • +
    + + + + +
    +
    diff --git a/local/recipes/libs/cairo/source/doc/tutorial/src/.gitignore b/local/recipes/libs/cairo/source/doc/tutorial/src/.gitignore new file mode 100644 index 0000000000..68af59e732 --- /dev/null +++ b/local/recipes/libs/cairo/source/doc/tutorial/src/.gitignore @@ -0,0 +1,8 @@ +*-gtk +*-pdf +*-png +*-xlib +*.pdf +*.png +*.o +*~ diff --git a/local/recipes/libs/cairo/source/doc/tutorial/src/README b/local/recipes/libs/cairo/source/doc/tutorial/src/README new file mode 100644 index 0000000000..4ce16d2f57 --- /dev/null +++ b/local/recipes/libs/cairo/source/doc/tutorial/src/README @@ -0,0 +1,66 @@ +Welcome to the cairo tutorial: + ++--------------------------------+ +| How to Recognize Ugly Graphics | +|(and what you can do about them)| ++--------------------------------+ + +This directory is your personal playground for following along with +the examples. In order for you to make use of these files you will +need to have cairo and its header files installed. You can find +instructions for doing this at: + + https://cairographics.org/tutorial + +Notice that there are a few .c files in this directory. + +You should start out by just typing "make" which will turn each .c +file into several different programs. Go ahead and run each of the +programs and see what they do. Some of them will open up new X windows +while others will simply write their output to files (such .png or +.pdf). + +After you play with those a bit, go ahead and take a look at the +contents of the .c files. You'll see that each file contains a draw() +function that does all of the drawing. + +You might be surprised to notice that there is no main() function in +any of the files. Instead, main is hidden away by means of +cairo-tutorial.h. This rather non-conventional style is used to allow +you to focus on the actual drawing code involved in using cairo, while +not having to worry about the setup semantics. We don't recommend that +you follow this style for real projects. + +As you follow along during the tutorial and get some ideas for things +to draw, you'll want to start making your own .c files. You can copy +an existing file or make your own by following this simple minimal +template: + + #include "cairo-tutorial.h" + + static void + draw (cairo_t *cr, int width, int height) + { + /* Put your drawing code here. */ + } + +Any new file you create will automatically get picked up by the +Makefile so that "make" will compile your file into several different +programs, just like the existing examples. + +If you'd like to control the initial size of the output, you may +define WIDTH and HEIGHT before including cairo-tutorial.h like so: + + #define WIDTH 100 + #define HEIGHT 100 + + #include "cairo-tutorial.h" + +If you would like to change the set of cairo-backend target programs +that are compiled, you may edit the "all" target in the Makefile. + +Have fun! + +-Carl Worth + +cworth@redhat.com diff --git a/local/recipes/libs/cairo/source/doc/tutorial/src/circle.c b/local/recipes/libs/cairo/source/doc/tutorial/src/circle.c new file mode 100644 index 0000000000..6bd02e8ba5 --- /dev/null +++ b/local/recipes/libs/cairo/source/doc/tutorial/src/circle.c @@ -0,0 +1,22 @@ +#include "cairo-tutorial.h" + +static void +draw (cairo_t *cr, int width, int height) +{ + int radius; + + if (width < height) + radius = width/2 - 4; + else + radius = height/2 - 4; + + cairo_move_to (cr, width/2 + radius, height/2); + cairo_arc (cr, width/2, height/2, radius, + 0.0, 2 * M_PI); + + cairo_set_source_rgb (cr, 0.6, 0.8, 1.0); + cairo_fill_preserve (cr); + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_stroke (cr); +} diff --git a/local/recipes/libs/cairo/source/doc/tutorial/src/include/cairo-tutorial-gtk.h b/local/recipes/libs/cairo/source/doc/tutorial/src/include/cairo-tutorial-gtk.h new file mode 100644 index 0000000000..60516a3562 --- /dev/null +++ b/local/recipes/libs/cairo/source/doc/tutorial/src/include/cairo-tutorial-gtk.h @@ -0,0 +1,133 @@ +/* cairo-tutorial-gtk.h - a tutorial framework for cairo with gtk+ + * + * Copyright © 2005, Carl Worth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. + */ + +#include +#include + +#include + +#ifndef WIDTH +#define WIDTH 400 +#endif + +#ifndef HEIGHT +#define HEIGHT 400 +#endif + +static void +draw (cairo_t *cr, int width, int height); + +#if ! GTK_CHECK_VERSION(2,7,0) +/* copied from gtk+/gdk/gdkcairo.c and gtk+/gdk/x11/gdkdrawable-x11.c + * gdk_cairo_create() which is available in 2.7.0 and later. + */ +static cairo_t * +gdk_cairo_create (GdkDrawable *drawable) +{ + int width, height; + cairo_t *cr = NULL; + cairo_surface_t *surface = NULL; + GdkVisual *visual = gdk_drawable_get_visual (drawable); + + gdk_drawable_get_size (drawable, &width, &height); + if (visual) + surface = cairo_xlib_surface_create (GDK_DRAWABLE_XDISPLAY (drawable), + GDK_DRAWABLE_XID (drawable), + GDK_VISUAL_XVISUAL (visual), + width, height); + else if (gdk_drawable_get_depth (drawable) == 1) + surface = cairo_xlib_surface_create_for_bitmap + (GDK_PIXMAP_XDISPLAY (drawable), + GDK_PIXMAP_XID (drawable), + GDK_SCREEN_XSCREEN (gdk_drawable_get_screen (drawable)), + width, height); + else { + g_warning ("Using Cairo rendering requires the drawable argument to\n" + "have a specified colormap. All windows have a colormap,\n" + "however, pixmaps only have colormap by default if they\n" + "were created with a non-NULL window argument. Otherwise\n" + "a colormap must be set on them with " + "gdk_drawable_set_colormap"); + return NULL; + } + if (surface) { + cr = cairo_create (surface); + cairo_surface_destroy (surface); + } + return cr; +} +#endif + +static gboolean +handle_expose (GtkWidget *widget, + GdkEventExpose *event, + gpointer data) +{ + cairo_t *cr; + + cr = gdk_cairo_create (widget->window); + + draw (cr, widget->allocation.width, widget->allocation.height); + + cairo_destroy (cr); + + return FALSE; +} + +static gboolean +handle_key_press (GtkWidget *widget, + GdkEventKey *event, + gpointer data) +{ + if ((event->keyval == GDK_Q || + event->keyval == GDK_q) && (event->state & GDK_CONTROL_MASK)) + gtk_main_quit (); + + return FALSE; +} + +int +main (int argc, char **argv) +{ + GtkWidget *window, *drawing_area; + + gtk_init (&argc, &argv); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_window_set_default_size (GTK_WINDOW (window), WIDTH, HEIGHT); + gtk_window_set_title (GTK_WINDOW (window), "cairo demo"); + + g_signal_connect (window, "destroy", + G_CALLBACK (gtk_main_quit), NULL); + + drawing_area = gtk_drawing_area_new (); + gtk_container_add (GTK_CONTAINER (window), drawing_area); + + g_signal_connect (drawing_area, "expose-event", + G_CALLBACK (handle_expose), NULL); + + g_signal_connect (window, "key-press-event", + G_CALLBACK (handle_key_press), NULL); + + gtk_widget_show_all (window); + + gtk_main (); + + return 0; +} diff --git a/local/recipes/libs/cairo/source/doc/tutorial/src/include/cairo-tutorial-pdf.h b/local/recipes/libs/cairo/source/doc/tutorial/src/include/cairo-tutorial-pdf.h new file mode 100644 index 0000000000..00d0f188e5 --- /dev/null +++ b/local/recipes/libs/cairo/source/doc/tutorial/src/include/cairo-tutorial-pdf.h @@ -0,0 +1,74 @@ +/* cairo-tutorial-png.h - a tutorial framework for cairo to write a PNG image + * + * Copyright © 2005, Carl Worth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. + */ + +#include +#include + +#include +#include +#include +#include + +#ifndef WIDTH +#define WIDTH 400 +#endif + +#ifndef HEIGHT +#define HEIGHT 400 +#endif + +static void +draw (cairo_t *cr, int width, int height); + +int +main (int argc, char **argv) +{ + cairo_surface_t *surface; + cairo_t *cr; + char *filename, *dash; + + filename = strdup (argv[0]); + assert (filename != NULL); + + dash = strrchr (filename, '-'); + + if (strcmp (dash, "-pdf") == 0) { + *dash = '.'; + } else { + char *new_filename; + new_filename = malloc (strlen (filename) + 5); + sprintf (new_filename, "%s.pdf", filename); + free (filename); + filename = new_filename; + } + + surface = cairo_pdf_surface_create (filename, WIDTH, HEIGHT); + + cr = cairo_create (surface); + + draw (cr, WIDTH, HEIGHT); + + cairo_show_page (cr); + + cairo_surface_destroy (surface); + cairo_destroy (cr); + + free (filename); + + return 0; +} diff --git a/local/recipes/libs/cairo/source/doc/tutorial/src/include/cairo-tutorial-png.h b/local/recipes/libs/cairo/source/doc/tutorial/src/include/cairo-tutorial-png.h new file mode 100644 index 0000000000..428baf2940 --- /dev/null +++ b/local/recipes/libs/cairo/source/doc/tutorial/src/include/cairo-tutorial-png.h @@ -0,0 +1,74 @@ +/* cairo-tutorial-png.h - a tutorial framework for cairo to write a PNG image + * + * Copyright © 2005, Carl Worth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. + */ + +#include + +#include +#include +#include +#include + +#ifndef WIDTH +#define WIDTH 400 +#endif + +#ifndef HEIGHT +#define HEIGHT 400 +#endif + +static void +draw (cairo_t *cr, int width, int height); + +int +main (int argc, char **argv) +{ + cairo_surface_t *surface; + cairo_t *cr; + char *filename, *dash; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + WIDTH, HEIGHT); + + cr = cairo_create (surface); + + draw (cr, WIDTH, HEIGHT); + + filename = strdup (argv[0]); + assert (filename != NULL); + + dash = strrchr (filename, '-'); + + if (strcmp (dash, "-png") == 0) { + *dash = '.'; + } else { + char *new_filename; + new_filename = malloc (strlen (filename) + 5); + sprintf (new_filename, "%s.png", filename); + free (filename); + filename = new_filename; + } + + cairo_surface_write_to_png (surface, filename); + + free (filename); + + cairo_surface_destroy (surface); + cairo_destroy (cr); + + return 0; +} diff --git a/local/recipes/libs/cairo/source/doc/tutorial/src/include/cairo-tutorial-xlib.h b/local/recipes/libs/cairo/source/doc/tutorial/src/include/cairo-tutorial-xlib.h new file mode 100644 index 0000000000..5e78d03548 --- /dev/null +++ b/local/recipes/libs/cairo/source/doc/tutorial/src/include/cairo-tutorial-xlib.h @@ -0,0 +1,251 @@ +/* cairo-tutorial-xlib.h - a tutorial framework for cairo with xlib + * + * Copyright © 2005, Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef WIDTH +#define WIDTH 400 +#endif + +#ifndef HEIGHT +#define HEIGHT 400 +#endif + +#ifndef DEFAULT_VISUAL +#define DEFAULT_VISUAL 0 +#endif + +static void +Usage (char *program) +{ + fprintf (stderr, "Usage: %s\n", program); + fprintf (stderr, "\t-display \n"); + fprintf (stderr, "\t-geometry \n"); + exit (1); +} + +char *dpy_name; +VisualID vid = DEFAULT_VISUAL; +Colormap colormap; +Visual *visual; +int depth; +unsigned int width = WIDTH, height = HEIGHT; +Window win; +Pixmap pix; +GC gc; + +static void +draw (cairo_t *cr, int width, int height); + +static void +draw_to_pixmap (Display *dpy, Pixmap pix) +{ + cairo_surface_t *surface; + cairo_t *cr; + + surface = cairo_xlib_surface_create (dpy, pix, visual, + width, height); + cr = cairo_create (surface); + + draw (cr, width, height); + + cairo_destroy (cr); + cairo_surface_destroy (surface); +} + +static void +handle_configure (Display *dpy, XConfigureEvent *cev) +{ + width = cev->width; + height = cev->height; + + XFreePixmap(dpy, pix); + pix = XCreatePixmap(dpy, win, width, height, depth); + XFillRectangle(dpy, pix, gc, 0, 0, width, height); + draw_to_pixmap (dpy, pix); +} + +static void +handle_expose (Display *dpy, XExposeEvent *eev) +{ + XCopyArea (dpy, pix, win, gc, + eev->x, eev->y, + eev->width, eev->height, + eev->x, eev->y); +} + +int +main (argc, argv) + int argc; + char **argv; +{ + Display *dpy; + Window root = 0; + char **init_argv = argv; + XSetWindowAttributes attr; + int scr; + int x = 0, y = 0; + int geometryMask; + int border_width = 1; + XSizeHints sizeHints; + XWMHints wmHints; + XClassHint classHints; + XEvent ev; + XEvent eev; + int HasExpose = 0; + int sync = 0; + XTextProperty wm_name, icon_name; + Atom wm_delete_window; + unsigned long gc_mask; + XGCValues gcv; + char quit_string[10]; + unsigned long window_mask; + int has_colormap = 0; + + wm_name.value = (unsigned char *) argv[0]; + wm_name.encoding = XA_STRING; + wm_name.format = 8; + wm_name.nitems = strlen (argv[0]) + 1; + icon_name = wm_name; + gc_mask = 0; + while (*++argv) { + if (!strcmp (*argv, "-display")) + dpy_name = *++argv; + else if (!strcmp (*argv, "-visual")) + vid = strtol(*++argv, NULL, 0); + else if (!strcmp (*argv, "-geometry")) + geometryMask = XParseGeometry (*++argv, &x, &y, &width, &height); + else if (!strcmp (*argv, "-sync")) + sync = 1; + else if (!strcmp (*argv, "-bw")) + border_width = strtol(*++argv, NULL, 0); + else if (!strcmp (*argv, "-root")) + root = strtol (*++argv, NULL, 0); + else + Usage (*init_argv); + } + sizeHints.flags = 0; + wmHints.flags = InputHint; + wmHints.input = True; + classHints.res_name = init_argv[0]; + classHints.res_class = init_argv[0]; + dpy = XOpenDisplay (dpy_name); + if (!dpy) { + fprintf (stderr, "Error: failed to open display: %s\n", + XDisplayName (dpy_name)); + exit (1); + } + if (sync) + XSynchronize (dpy, sync); + scr = DefaultScreen (dpy); + if (!root) + root = RootWindow (dpy, scr); + window_mask = CWBackPixel|CWBorderPixel|CWEventMask; + if (!has_colormap) + colormap = DefaultColormap (dpy, scr); + else + { + window_mask |= CWColormap; + attr.colormap = colormap; + } + visual = DefaultVisual (dpy, scr); + depth = DefaultDepth (dpy, scr); + if (vid) + { + XVisualInfo vi, *vi_ret; + int n; + + vi.visualid = vid; + vi.screen = scr; + vi_ret = XGetVisualInfo (dpy, VisualIDMask|VisualScreenMask, + &vi, &n); + if (vi_ret) + { + visual = vi_ret->visual; + if (!has_colormap) + { + colormap = XCreateColormap (dpy, root, visual, AllocNone); + window_mask |= CWColormap; + attr.colormap = colormap; + } + depth = vi_ret->depth; + } + } + attr.background_pixel = WhitePixel (dpy, scr); + attr.border_pixel = 0; + attr.event_mask = ExposureMask|KeyPressMask|KeyReleaseMask|StructureNotifyMask; + wm_delete_window = XInternAtom(dpy, "WM_DELETE_WINDOW", False); + win = XCreateWindow (dpy, root, x, y, width, height, border_width, + depth, InputOutput, + visual, + window_mask, + &attr); + pix = XCreatePixmap (dpy, win, width, height, depth); + gcv.foreground = WhitePixel (dpy, scr); + gc = XCreateGC (dpy, pix, GCForeground, &gcv); + XFillRectangle(dpy, pix, gc, 0, 0, width, height); + draw_to_pixmap (dpy, pix); + XSetWMProperties (dpy, win, + &wm_name, &icon_name, + init_argv, argc, + &sizeHints, &wmHints, 0); + XSetWMProtocols (dpy, win, &wm_delete_window, 1); + XMapWindow (dpy, win); + for (;;) { + XNextEvent (dpy, &ev); + if (HasExpose && ev.type != Expose) { + HasExpose = 0; + handle_expose (dpy, &eev.xexpose); + } + switch (ev.type) { + case ConfigureNotify: + handle_configure (dpy, &ev.xconfigure); + break; + case Expose: + if (QLength(dpy)) { + eev = ev; + HasExpose = 1; + } else if (ev.xexpose.count == 0) { + handle_expose (dpy, &ev.xexpose); + } + break; + case KeyPress: + if (XLookupString ((XKeyEvent *) &ev, quit_string, sizeof (quit_string), 0, 0) == 1) { + switch (quit_string[0]) { + case 'q': + exit (0); + case 'c': + XClearArea (dpy, ev.xkey.window, 0, 0, 0, 0, True); + break; + } + } + break; + case ClientMessage: + exit (0); + } + } +} diff --git a/local/recipes/libs/cairo/source/doc/tutorial/src/include/cairo-tutorial.h b/local/recipes/libs/cairo/source/doc/tutorial/src/include/cairo-tutorial.h new file mode 100644 index 0000000000..ec738e915e --- /dev/null +++ b/local/recipes/libs/cairo/source/doc/tutorial/src/include/cairo-tutorial.h @@ -0,0 +1,40 @@ +/* cairo-tutorial-gtk.h - a tutorial framework for cairo + * + * Copyright © 2005, Carl Worth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. + */ + +#include +#include + +/* The application program may override these before including + * cairo-tutorial.h in order to get a window of a different size. */ +#ifndef WIDTH +#define WIDTH 400 +#endif + +#ifndef HEIGHT +#define HEIGHT 400 +#endif + +#ifdef CAIRO_TUTORIAL_GTK +#include "cairo-tutorial-gtk.h" +#elif CAIRO_TUTORIAL_XLIB +#include "cairo-tutorial-xlib.h" +#elif CAIRO_TUTORIAL_PDF +#include "cairo-tutorial-pdf.h" +#elif CAIRO_TUTORIAL_PNG +#include "cairo-tutorial-png.h" +#endif diff --git a/local/recipes/libs/cairo/source/doc/tutorial/src/lca.c b/local/recipes/libs/cairo/source/doc/tutorial/src/lca.c new file mode 100644 index 0000000000..0b131afaf6 --- /dev/null +++ b/local/recipes/libs/cairo/source/doc/tutorial/src/lca.c @@ -0,0 +1,32 @@ +#define WIDTH 750 +#define HEIGHT 360 + +#include "cairo-tutorial.h" + +static void +draw (cairo_t *cr, int width, int height) +{ + cairo_save (cr); + + cairo_translate (cr, 60, 60); + cairo_scale (cr, 3, 3); + + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); + cairo_set_line_width (cr, 20); + + /* L */ + cairo_move_to (cr, 0, 0); + cairo_line_to (cr, 0, 80); + cairo_line_to (cr, 50, 80); + + /* C */ + cairo_move_to (cr, 110 + 40 * cos (M_PI / 3), 40 + 40 * sin(M_PI / 3)); + cairo_arc (cr, 110, 40, 40, M_PI / 3, -M_PI / 3); + + /* A */ + cairo_move_to (cr, 160, 80); + cairo_curve_to (cr, 160, -30, 210, -30, 210, 80); + + cairo_stroke (cr); +} diff --git a/local/recipes/libs/cairo/source/doc/tutorial/src/singular.c b/local/recipes/libs/cairo/source/doc/tutorial/src/singular.c new file mode 100644 index 0000000000..958b2b0472 --- /dev/null +++ b/local/recipes/libs/cairo/source/doc/tutorial/src/singular.c @@ -0,0 +1,162 @@ +/** + * Uses Singular values of transformation matrix to find the length of the + * major and minor axes of the scaled pen. + * + * Put this file in cairo/doc/tutorial/src and type "make" + */ + +#define WIDTH 300 +#define HEIGHT 300 + +#include "cairo-tutorial.h" + +#include + +/* + * Finds the singular values of the non-translation part of matrix. + * + * Let M be the cairo transformation matrix in question: + * + * ⌈xx xy⌉ + * M = |yx yy| + * ⌊x0 y0⌋ + * + * The non-translation part is: + * + * A = ⌈xx xy⌉ + * ⌊yx yy⌋ + * + * The non-zero singular values of A are the square roots of the non-zero + * eigenvalues of A⺠A, where A⺠is A-transpose. + * + * A⺠A = ⌈xx yx⌉⌈xx xy⌉ = ⌈xx²+yx² xx*xy+yx*yy⌉ + * ⌊xy yy⌋⌊yx yy⌋ ⌊xx*xy+yx*yy xy²+yy²⌋ + * + * Name those: + * + * B = A⺠A = ⌈a k⌉ + * ⌊k b⌋ + * + * The eigenvalues of B satisfy: + * + * λ² - (a+b).λ + a.b - k² = 0 + * + * The eigenvalues are: + * __________________ + * (a+b) ± √(a+b)² - 4(a.b-k²) + * λ = --------------------------- + * 2 + * that simplifies to: + * _______________ + * λ = (a+b)/2 ± √((a-b)/2)² + k² + * + * And the Singular values are the root of λs. + * + */ +static void +get_singular_values (const cairo_matrix_t *matrix, + double *major, + double *minor) +{ + double xx = matrix->xx, xy = matrix->xy; + double yx = matrix->yx, yy = matrix->yy; + + double a = xx*xx+yx*yx; + double b = xy*xy+yy*yy; + double k = xx*xy+yx*yy; + + double f = (a+b) * .5; + double g = (a-b) * .5; + double delta = sqrt (g*g + k*k); + + if (major) + *major = sqrt (f + delta); + if (minor) + *minor = sqrt (f - delta); +} + +/* + * Finds the length of the major and minor axes of the pen for a cairo_t, + * identified by the current transformation matrix and line width. + * + * Returned values are in device units. + */ +static void +get_pen_axes (cairo_t *cr, + double *major, + double *minor) +{ + double width; + cairo_matrix_t matrix; + + width = cairo_get_line_width (cr); + cairo_get_matrix (cr, &matrix); + + get_singular_values (&matrix, major, minor); + + if (major) + *major *= width; + if (minor) + *minor *= width; +} + +static void +draw (cairo_t *cr, int width, int height) +{ + double major_width, minor_width; + + /* clear background */ + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + +#define W width +#define H height +#define B ((width+height)/16) + + /* the spline we want to stroke */ + cairo_move_to (cr, W-B, B); + cairo_curve_to (cr, -W, B, + 2*W, H-B, + B, H-B); + + /* the effect is show better with round caps */ + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + + /* set the skewed pen */ + cairo_rotate (cr, +.7); + cairo_scale (cr, .5, 2.); + cairo_rotate (cr, -.7); + cairo_set_line_width (cr, B); + + get_pen_axes (cr, &major_width, &minor_width); + + /* stroke with "major" pen in translucent red */ + cairo_save (cr); + cairo_identity_matrix (cr); + cairo_set_line_width (cr, major_width); + cairo_set_source_rgba (cr, 1.0, 0.0, 0.0, .9); + cairo_stroke_preserve (cr); + cairo_restore (cr); + + /* stroke with skewed pen in translucent black */ + cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, .9); + cairo_stroke_preserve (cr); + + /* stroke with "minor" pen in translucent yellow */ + cairo_save (cr); + cairo_identity_matrix (cr); + cairo_set_line_width (cr, minor_width); + cairo_set_source_rgba (cr, 1.0, 1.0, 0.0, .9); + cairo_stroke_preserve (cr); + cairo_restore (cr); + + /* stroke with hairline in black */ + cairo_save (cr); + cairo_identity_matrix (cr); + cairo_set_line_width (cr, 1); + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_stroke_preserve (cr); + cairo_restore (cr); + + cairo_new_path (cr); +} diff --git a/local/recipes/libs/cairo/source/doc/tutorial/src/twin.c b/local/recipes/libs/cairo/source/doc/tutorial/src/twin.c new file mode 100644 index 0000000000..14347bac2d --- /dev/null +++ b/local/recipes/libs/cairo/source/doc/tutorial/src/twin.c @@ -0,0 +1,39 @@ +/** + * Put this file in cairo/doc/tutorial/src and type "make" + */ + +#define WIDTH 1350 +#define HEIGHT 900 + +#include "cairo-tutorial.h" + + +static void +draw (cairo_t *cr, int width, int height) +{ + int i, j, h; + unsigned char s[2] = {0, 0}; + + /* clear background */ + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_select_font_face (cr, + "@cairo:", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + + h = 2; + for (i = 8; i < 48; i >= 24 ? i+=3 : i++) { + cairo_set_font_size (cr, i); + for (j = 33; j < 128; j++) { + if (j == 33 || (j == 80 && i > 24)) { + h += i + 2; + cairo_move_to (cr, 10, h); + } + s[0] = j; + cairo_show_text (cr, (const char *) s); + } + } +} diff --git a/local/recipes/libs/cairo/source/meson-cc-tests/atomic-ops-c11.c b/local/recipes/libs/cairo/source/meson-cc-tests/atomic-ops-c11.c new file mode 100644 index 0000000000..4d60e998f6 --- /dev/null +++ b/local/recipes/libs/cairo/source/meson-cc-tests/atomic-ops-c11.c @@ -0,0 +1,12 @@ +#include +#include + +/* We require lock free atomics for int and pointers as cairo assumes + * an int* can be cast to cairo_atomic_int_t* + */ +_Static_assert (ATOMIC_INT_LOCK_FREE == 2, "Lock free atomics not supported"); +_Static_assert (ATOMIC_POINTER_LOCK_FREE == 2, "Lock free atomics not supported"); + +int atomic_add(atomic_int *i) { return atomic_fetch_add_explicit(i, 1, memory_order_seq_cst); } +int atomic_cmpxchg(atomic_int *i, int j, int k) { return atomic_compare_exchange_strong_explicit (i, &j, k, memory_order_seq_cst, memory_order_seq_cst); } +int main(void) { return 0; } diff --git a/local/recipes/libs/cairo/source/meson-cc-tests/atomic-ops-cxx11.c b/local/recipes/libs/cairo/source/meson-cc-tests/atomic-ops-cxx11.c new file mode 100644 index 0000000000..aeef0d849c --- /dev/null +++ b/local/recipes/libs/cairo/source/meson-cc-tests/atomic-ops-cxx11.c @@ -0,0 +1,3 @@ +int atomic_add(int i) { return __atomic_fetch_add(&i, 1, __ATOMIC_SEQ_CST); } +int atomic_cmpxchg(int i, int j, int k) { return __atomic_compare_exchange_n(&i, &j, k, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); } +int main(void) { return 0; } diff --git a/local/recipes/libs/cairo/source/meson-cc-tests/atomic-ops-gcc-legacy.c b/local/recipes/libs/cairo/source/meson-cc-tests/atomic-ops-gcc-legacy.c new file mode 100644 index 0000000000..99331968dd --- /dev/null +++ b/local/recipes/libs/cairo/source/meson-cc-tests/atomic-ops-gcc-legacy.c @@ -0,0 +1,3 @@ +int atomic_add(int i) { return __sync_fetch_and_add (&i, 1); } +int atomic_cmpxchg(int i, int j, int k) { return __sync_val_compare_and_swap (&i, j, k); } +int main(void) { return 0; } diff --git a/local/recipes/libs/cairo/source/meson-cc-tests/bfd-section-flags.c b/local/recipes/libs/cairo/source/meson-cc-tests/bfd-section-flags.c new file mode 100644 index 0000000000..b58118d06f --- /dev/null +++ b/local/recipes/libs/cairo/source/meson-cc-tests/bfd-section-flags.c @@ -0,0 +1,9 @@ +#include + +int +f (asection *s) +{ + return bfd_section_flags(s) == 0; +} + +int main (void) { return 0; } diff --git a/local/recipes/libs/cairo/source/meson-cc-tests/check-unused-result.c b/local/recipes/libs/cairo/source/meson-cc-tests/check-unused-result.c new file mode 100644 index 0000000000..ce7279ec8b --- /dev/null +++ b/local/recipes/libs/cairo/source/meson-cc-tests/check-unused-result.c @@ -0,0 +1,9 @@ +__attribute__((__warn_unused_result__)) void f (void) {} +__attribute__((__warn_unused_result__)) int g; + +int main(int c, char **v) +{ + (void)c; + (void)v; + return 0; +} diff --git a/local/recipes/libs/cairo/source/meson-cc-tests/fuzzer.c b/local/recipes/libs/cairo/source/meson-cc-tests/fuzzer.c new file mode 100644 index 0000000000..0ae4a3101a --- /dev/null +++ b/local/recipes/libs/cairo/source/meson-cc-tests/fuzzer.c @@ -0,0 +1,7 @@ +#include +#include + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + return 0; +} diff --git a/local/recipes/libs/cairo/source/meson-cc-tests/ipc_rmid_deferred_release.c b/local/recipes/libs/cairo/source/meson-cc-tests/ipc_rmid_deferred_release.c new file mode 100644 index 0000000000..2c9290d253 --- /dev/null +++ b/local/recipes/libs/cairo/source/meson-cc-tests/ipc_rmid_deferred_release.c @@ -0,0 +1,18 @@ +#include +#include +#include +int main() +{ + char *shmaddr; + int id = shmget (IPC_PRIVATE, 4, IPC_CREAT | 0600); + if (id == -1) return 2; + shmaddr = shmat (id, 0, 0); + shmctl (id, IPC_RMID, 0); + if ((char*) shmat (id, 0, 0) == (char*) -1) { + shmdt (shmaddr); + return 1; + } + shmdt (shmaddr); + shmdt (shmaddr); + return 0; +} diff --git a/local/recipes/libs/cairo/source/meson-cc-tests/mkdir-variant-1.c b/local/recipes/libs/cairo/source/meson-cc-tests/mkdir-variant-1.c new file mode 100644 index 0000000000..88910d1076 --- /dev/null +++ b/local/recipes/libs/cairo/source/meson-cc-tests/mkdir-variant-1.c @@ -0,0 +1,12 @@ +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_IO_H +#include +#endif + +int main(int ac, char **av) +{ + mkdir("hello.world"); + return 0; +} diff --git a/local/recipes/libs/cairo/source/meson-cc-tests/mkdir-variant-2.c b/local/recipes/libs/cairo/source/meson-cc-tests/mkdir-variant-2.c new file mode 100644 index 0000000000..d0ab7b298d --- /dev/null +++ b/local/recipes/libs/cairo/source/meson-cc-tests/mkdir-variant-2.c @@ -0,0 +1,12 @@ +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_IO_H +#include +#endif + +int main(int ac, char **av) +{ + mkdir("hello.world", 0777); + return 0; +} diff --git a/local/recipes/libs/cairo/source/meson-cc-tests/pthread.c b/local/recipes/libs/cairo/source/meson-cc-tests/pthread.c new file mode 100644 index 0000000000..035cb3a94d --- /dev/null +++ b/local/recipes/libs/cairo/source/meson-cc-tests/pthread.c @@ -0,0 +1,35 @@ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE /* for PTHREAD_MUTEX_INITIALIZER under linux */ +#endif +#include + +pthread_mutex_t test_mutex_initializer = PTHREAD_MUTEX_INITIALIZER; +int test_mutex (void) +{ + int x = 0; + pthread_mutex_t mutex; + x |= pthread_mutex_init (&mutex, NULL); + x |= pthread_mutex_lock (&mutex); + x |= pthread_mutex_unlock (&mutex); + x |= pthread_mutex_destroy (&mutex); + return 0; +} + +int test_mutex_attr (void) +{ + int x = 0; + pthread_mutexattr_t attr; + pthread_mutex_t mutex; + x |= pthread_mutexattr_init (&attr); + x |= pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE); + x |= pthread_mutex_init (&mutex, &attr); + x |= pthread_mutex_lock (&mutex); + x |= pthread_mutex_unlock (&mutex); + x |= pthread_mutex_destroy (&mutex); + x |= pthread_mutexattr_destroy (&attr); + return x; +} + +int main(void) { + return 0; +} diff --git a/local/recipes/libs/cairo/source/meson.build b/local/recipes/libs/cairo/source/meson.build new file mode 100644 index 0000000000..1fb1f5317c --- /dev/null +++ b/local/recipes/libs/cairo/source/meson.build @@ -0,0 +1,864 @@ +project('cairo', 'c', + meson_version: '>= 1.3.0', + version: run_command(find_program('version.py'), check: true).stdout().strip(), + default_options: ['c_std=gnu11,c11', + 'cpp_std=gnu++11,c++11', + 'warning_level=2'], +) + +freetype_required_version = '>= 23.0.17' # Release version 2.10 +freetype_colrv1_required_version = '>= 25.0.19' # Release version 2.13 +fontconfig_required_version = '>= 2.13.0' +libpng_required_version = '>= 1.4.0' +xrender_required_version = '>= 0.6' +xcb_required_version = '>= 1.6' +xcb_render_required_version = '>= 1.6' +libudev_required_version = '>= 136' +glib_required_version = '>= 2.14' + +# library versioning +version_arr = meson.project_version().split('.') +cairo_version_major = version_arr[0].to_int() +cairo_version_minor = version_arr[1].to_int() +cairo_version_micro = version_arr[2].to_int() + +# The libtool shared library version stuff. +# Try and maintain compatibility with the previous library versioning. +cairo_version_sonum = cairo_version_major + 1 +cairo_version = cairo_version_major * 10000 + cairo_version_minor * 100 + cairo_version_micro + +if cairo_version_minor % 2 == 1 + # unstable release + cairo_libversion = '@0@.@1@.0'.format(cairo_version_sonum, cairo_version) +else + # stable release + cairo_libversion = '@0@.@1@.@2@'.format(cairo_version_sonum, cairo_version, cairo_version_micro) +endif + +conf = configuration_data() + +cc = meson.get_compiler('c') + +# Compiler flags +cflags = [] +if cc.get_id() != 'msvc' + cflags += [ + '-Wmissing-declarations', + '-Werror-implicit-function-declaration', + '-Wpointer-arith', + '-Wwrite-strings', + '-Wsign-compare', + '-Wpacked', + '-Wswitch-enum', + '-Wmissing-format-attribute', + '-Wvolatile-register-var', + '-Wstrict-aliasing=2', + '-Winit-self', + '-Wunsafe-loop-optimizations', + '-Wno-missing-field-initializers', + '-Wno-unused-parameter', + '-Wno-attributes', + '-Wno-long-long', + '-Winline' + ] + + cflags += ['-Wno-unused-but-set-variable', + '-Wno-enum-conversion' + ] + + cflags += [ + '-fno-strict-aliasing', + '-fno-common' + ] + + if get_option('optimization') in ['1', '2', '3'] + cflags += '-Wp,-D_FORTIFY_SOURCE=2' + endif + + supported_cflags = cc.get_supported_arguments(cflags) + add_project_arguments(supported_cflags, language: 'c') + + # We only wish to enable attribute(warn_unused_result) if we can prevent + # gcc from generating thousands of warnings about the misapplication of the + # attribute to void functions and variables. + warn_unused_result = '' + if supported_cflags.contains('-Wno-attributes') + if cc.compiles(files('meson-cc-tests/check-unused-result.c'), args : ['-Wno-attributes', '-Werror']) + warn_unused_result = '__attribute__((__warn_unused_result__))' + endif + endif + conf.set('WARN_UNUSED_RESULT', warn_unused_result) +endif + +if cc.get_id() == 'msvc' + # Basic usage in the cairo type system that causes spammy and useless warnings + add_project_arguments('/wd4244', '/wd4146', + # Don't warn about double -> float truncation + '/wd4305', + language : 'c') +endif + +add_project_arguments('-D_GNU_SOURCE', language: 'c') + +pkgmod = import('pkgconfig') +python3 = import('python').find_installation() + +check_sizeofs = [ + ['void *', {'conf-name': 'SIZEOF_VOID_P'}], + ['int'], + ['long'], + ['long long'], + ['size_t'], +] + +check_headers = [ + ['stdint.h'], + ['inttypes.h'], + ['sys/int_types.h'], + ['fcntl.h'], + ['unistd.h'], + ['signal.h'], + ['sys/stat.h'], + ['sys/socket.h'], + ['poll.h'], + ['sys/poll.h'], + ['sys/un.h'], + ['sched.h', {'check-funcs': ['sched_getaffinity']}], + ['sys/mman.h', {'check-funcs': ['mmap']}], + ['time.h', {'check-funcs': ['clock_gettime']}], + ['libgen.h'], + ['byteswap.h'], + ['signal.h'], + ['setjmp.h'], + ['fenv.h'], + ['sys/wait.h'], + ['sys/stat.h'], + ['io.h'], + ['fenv.h', {'check-funcs': ['feenableexcept', 'fedisableexcept', 'feclearexcept']}], + ['xlocale.h'], + ['sys/ioctl.h'], + ['intsafe.h'], + ['alloca.h'], + ['termios.h'], +] + +check_types = [ + ['uint64_t', {'headers': ['stdint.h']}], + ['uint128_t', {'headers': ['stdint.h']}], + ['__uint128_t'] +] + +check_funcs = [ + 'alarm', + 'ctime_r', + 'localtime_r', + 'gmtime_r', + 'drand48', + 'flockfile', + 'funlockfile', + 'getline', + 'link', + 'fork', + 'waitpid', + 'raise', + 'newlocale', + 'strtod_l', +] + +check_thread_flags = [ + [['-D_REENTRANT'], ['-lpthread']], + [['-pthread'], []], + [['-D_REENTRANT'], [], {'real': false}], +] + +m_dep = cc.find_library('m', required: false) +# Used in util +gtk_dep = dependency('gtk+-2.0', required: get_option('gtk2-utils')) + +deps = [m_dep] +test_deps = [] +internal_deps = [] +extra_link_args = [] + +extra_link_args += cc.get_supported_link_arguments([ + '-Wl,-Bsymbolic-functions', +]) + +if host_machine.endian() == 'big' + conf.set('WORDS_BIGENDIAN', 1) +endif + +float_order = cc.get_define('__FLOAT_WORD_ORDER__') +if float_order != '' + if float_order == cc.get_define('__ORDER_BIG_ENDIAN__') + conf.set('FLOAT_WORDS_BIGENDIAN', 1) + endif +else + # Assume same as platform endian + if host_machine.endian() == 'big' + conf.set('FLOAT_WORDS_BIGENDIAN', 1) + endif +endif + +lzo_dep = dependency('lzo2', required: get_option('lzo')) +if lzo_dep.found() + conf.set('HAVE_LZO', 1) +endif + +dl_dep = cc.find_library('dl', required: false) +if dl_dep.found() and cc.has_function('dlsym', dependencies: [dl_dep]) + deps += [dl_dep] + conf.set('CAIRO_HAS_DLSYM', 1) +elif cc.has_function('dlsym') + conf.set('CAIRO_HAS_DLSYM', 1) +elif cc.has_function('dlsym', prefix: '#include ') + conf.set('CAIRO_HAS_DLSYM', 1) +endif + +feature_conf = configuration_data() + +# Array of dictionaries, used to generate per-feature pc files +# Mandatory keys: name, description +# Optional keys: requires, libs +built_features = [] + +zlib_dep = dependency('zlib', + required: get_option('zlib'), + fallback : ['zlib', 'zlib_dep'], +) +if zlib_dep.found() + if zlib_dep.type_name() == 'internal' + internal_deps += [zlib_dep] + else + deps += [zlib_dep] + endif + conf.set('HAVE_ZLIB', 1) +endif + +png_dep = dependency('libpng', + required: get_option('png'), + version: libpng_required_version, + fallback: ['libpng', 'libpng_dep'] +) +if png_dep.found() + feature_conf.set('CAIRO_HAS_SVG_SURFACE', 1) + feature_conf.set('CAIRO_HAS_PNG_FUNCTIONS', 1) + built_features += [ + { + 'name': 'cairo-png', + 'description': 'PNG functions', + 'deps': [png_dep], + }, + { + 'name': 'cairo-svg', + 'description': 'SVG surface backend', + 'deps': [png_dep], + } + ] + + if png_dep.type_name() == 'internal' + internal_deps += [png_dep] + else + deps += [png_dep] + endif +endif + +# Disable fontconfig by default on platforms where it is optional +fontconfig_option = get_option('fontconfig') +fontconfig_required = host_machine.system() not in ['windows', 'darwin'] +fontconfig_option = fontconfig_option.disable_auto_if(not fontconfig_required) + +fontconfig_dep = dependency('fontconfig', + required: fontconfig_option, + version: fontconfig_required_version, + fallback: ['fontconfig', 'fontconfig_dep'], +) +if fontconfig_dep.found() + fc_check_funcs = [ + 'FcInit', + 'FcFini' + ] + + if fontconfig_dep.type_name() == 'internal' + foreach func : fc_check_funcs + conf.set('HAVE_@0@'.format(func.to_upper()), 1) + endforeach + internal_deps += [fontconfig_dep] + else + check_funcs += fc_check_funcs + deps += [fontconfig_dep] + endif + + feature_conf.set('CAIRO_HAS_FC_FONT', 1) + built_features += [{ + 'name': 'cairo-fc', + 'description': 'Fontconfig font backend', + 'deps': [fontconfig_dep], + }] +endif + +ttx = find_program('ttx', required: false) + +# Disable FreeType by default on platforms where it is optional +freetype_option = get_option('freetype') +freetype_required = host_machine.system() not in ['windows', 'darwin'] +freetype_option = freetype_option.disable_auto_if(not freetype_required) + +freetype_dep = dependency('freetype2', + required: freetype_option, + version: freetype_required_version, + fallback: ['freetype2', 'freetype_dep'], +) +if freetype_dep.found() + feature_conf.set('CAIRO_HAS_FT_FONT', 1) + built_features += [{ + 'name': 'cairo-ft', + 'description': 'FreeType font backend', + 'deps': [freetype_dep], + # cairo-ft.h includes fontconfig.h so it needs its cflags + 'compile-deps': [fontconfig_dep.partial_dependency(compile_args: true, includes: true)], + }] + + if freetype_dep.type_name() == 'internal' + if freetype_dep.version().version_compare(freetype_colrv1_required_version) + conf.set('HAVE_FT_SVG_DOCUMENT', 1) + conf.set('HAVE_FT_LOAD_NO_SVG', 1) + conf.set('HAVE_FT_COLR_V1', 1) + endif + internal_deps += [freetype_dep] + else + if png_dep.found() and \ + cc.has_type('FT_SVG_Document', dependencies: freetype_dep, prefix: '#include ') + conf.set('HAVE_FT_SVG_DOCUMENT', 1) + if ttx.found() + conf.set('CAIRO_CAN_TEST_TTX_FONT', 1) + endif + endif + if cc.has_define('FT_LOAD_NO_SVG', dependencies: freetype_dep, prefix: '#include ') + conf.set('HAVE_FT_LOAD_NO_SVG', 1) + endif + if freetype_dep.version().version_compare(freetype_colrv1_required_version) and \ + cc.has_function('FT_Get_Color_Glyph_Paint', dependencies: freetype_dep) + conf.set('HAVE_FT_COLR_V1', 1) + endif + deps += [freetype_dep] + endif +endif + +x11_dep = dependency('x11', required: get_option('xlib')) +xext_dep = dependency('xext', required: get_option('xlib')) +if x11_dep.found() and xext_dep.found() + feature_conf.set('CAIRO_HAS_XLIB_SURFACE', 1) + built_features += [{ + 'name': 'cairo-xlib', + 'description': 'Xlib surface backend', + 'deps': [x11_dep, xext_dep], + }] + + extra_headers = ['X11/Xlibint.h', 'X11/Xproto.h'] + check_headers += [ + ['X11/extensions/XShm.h', {'extra-headers': extra_headers}], + ['X11/extensions/shmproto.h', {'extra-headers': extra_headers}], + ['X11/extensions/shmstr.h', {'extra-headers': extra_headers}], + ] + deps += [x11_dep, xext_dep] + + # Can skip the run check by providing the result in a cross file or + # native file as bool property value. + prop = meson.get_external_property('ipc_rmid_deferred_release', meson.is_cross_build() ? 'false' : 'auto') + # We don't know the type of prop (bool, string) but need to differentiate + # between a set value (bool) or the fallback value (string), so convert to + # a string and check the string value. + prop_str = '@0@'.format(prop) + if prop_str in ['true', 'false'] + ipc_rmid_deferred_release = (prop_str == 'true') + message('IPC_RMID_DEFERRED_RELEASE:', ipc_rmid_deferred_release) + elif prop_str == 'auto' + res = cc.run(files('meson-cc-tests/ipc_rmid_deferred_release.c'), + dependencies: [x11_dep, xext_dep], + name: 'shmctl IPC_RMID allowes subsequent attaches') + + ipc_rmid_deferred_release = (res.returncode() == 0) + else + error('Unexpected value for external property ipc_rmid_deferred_release: @0@'.format(prop_str)) + endif + + conf.set10('IPC_RMID_DEFERRED_RELEASE', ipc_rmid_deferred_release) +endif + +if feature_conf.get('CAIRO_HAS_XLIB_SURFACE', 0) == 1 + xrender_dep = dependency('xrender', required: get_option('xlib'), + version: xrender_required_version) + + if xrender_dep.found() + check_funcs += [ + 'XRenderCreateSolidFill', + 'XRenderCreateLinearGradient', + 'XRenderCreateRadialGradient', + 'XRenderCreateConicalGradient', + ] + + deps += [xrender_dep] + + built_features += [{ + 'name': 'cairo-xlib-xrender', + 'description': 'Xlib Xrender surface backend', + 'deps': [xrender_dep], + }] + feature_conf.set('CAIRO_HAS_XLIB_XRENDER_SURFACE', 1) + endif +endif + +xcb_dep = dependency('xcb', required: get_option('xcb'), + version: xcb_required_version) +xcb_render_dep = dependency('xcb-render', required: get_option('xcb'), + version: xcb_render_required_version) +if xcb_dep.found() and xcb_render_dep.found() + feature_conf.set('CAIRO_HAS_XCB_SURFACE', 1) + built_features += [{ + 'name': 'cairo-xcb', + 'description': 'XCB surface backend', + 'deps': [xcb_dep, xcb_render_dep], + }] + + deps += [xcb_dep, xcb_render_dep] +endif + +if feature_conf.get('CAIRO_HAS_XCB_SURFACE', 0) == 1 and feature_conf.get('CAIRO_HAS_XLIB_SURFACE', 0) == 1 + x11xcb_dep = dependency('x11-xcb', required: get_option('xlib-xcb')) + if x11xcb_dep.found() + deps += [x11xcb_dep] + feature_conf.set('CAIRO_HAS_XLIB_XCB_FUNCTIONS', 1) + built_features += [{ + 'name': 'cairo-xlib-xcb', + 'description': 'Xlib/XCB functions', + 'deps': [x11xcb_dep], + }] + endif +endif + +if feature_conf.get('CAIRO_HAS_XCB_SURFACE', 0) == 1 + xcbshm_dep = dependency('xcb-shm', required: get_option('xcb')) + if xcbshm_dep.found() + #feature_conf.set('CAIRO_HAS_XCB_SHM_FUNCTIONS', 1) + #deps += [xcbshm_dep] + #built_features += [{ + # 'name': 'cairo-xcb-shm', + # 'description': 'XCB/SHM functions', + # 'deps': [xcbshm_dep], + #}] + endif +endif + +if host_machine.system() == 'darwin' and not get_option('quartz').disabled() + quartz_deps = dependency('appleframeworks', modules : ['CoreFoundation', 'ApplicationServices'], required: get_option('quartz')) + + if quartz_deps.found() + deps += [quartz_deps] + + feature_conf.set('CAIRO_HAS_QUARTZ_SURFACE', 1) + feature_conf.set('CAIRO_HAS_QUARTZ_IMAGE_SURFACE', 1) + + built_features += [ + { + 'name': 'cairo-quartz', + 'description': 'Quartz surface backend', + 'deps': quartz_deps, + }, + { + 'name': 'cairo-quartz-image', + 'description': 'Quartz Image surface backend', + 'deps': quartz_deps, + }] + compiler = meson.get_compiler('c') + if compiler.has_function('CTFontDrawGlyphs', prefix: '#include ', + dependencies: quartz_deps) + built_features += [ + { + 'name': 'cairo-quartz-font', + 'description': 'Quartz font backend', + 'deps': quartz_deps, + }] + feature_conf.set('CAIRO_HAS_QUARTZ_FONT', 1) + endif + endif +endif + +if host_machine.system() == 'windows' + add_languages('cpp', native: false) + + add_project_arguments('-DWIN32_LEAN_AND_MEAN', '-DNOMINMAX', language: ['c', 'cpp']) + + win32_extra_deps = [ + cc.find_library('gdi32'), + cc.find_library('msimg32'), + ] + + deps += win32_extra_deps + + feature_conf.set('CAIRO_HAS_WIN32_SURFACE', 1) + feature_conf.set('CAIRO_HAS_WIN32_FONT', 1) + + built_features += [ + { + 'name': 'cairo-win32', + 'description': 'Microsoft Windows surface backend', + 'deps': win32_extra_deps, + }, + { + 'name': 'cairo-win32-font', + 'description': 'Microsoft Windows font backend', + 'deps': win32_extra_deps, + } + ] + + cpp_compiler = meson.get_compiler('cpp') + d2d_dep = cpp_compiler.find_library('d2d1', required: get_option('dwrite')) + dwrite_dep = cpp_compiler.find_library('dwrite', required: get_option('dwrite')) + d2d_header = cpp_compiler.has_header('d2d1.h') + d2d_3_header = cpp_compiler.has_header('d2d1_3.h') + dwrite_header = cpp_compiler.has_header('dwrite.h') + wincodec_dep = cpp_compiler.find_library('windowscodecs', required: get_option('dwrite')) + wincodec_header = cpp_compiler.has_header('wincodec.h') + + if d2d_dep.found() and dwrite_dep.found() and d2d_header and dwrite_header and wincodec_dep.found() and wincodec_header + feature_conf.set('CAIRO_HAS_DWRITE_FONT', 1) + built_features += [{ + 'name': 'cairo-dwrite-font', + 'description': 'Microsoft Windows DWrite font backend', + 'deps': [dwrite_dep, d2d_dep, wincodec_dep], + }] + deps += [dwrite_dep, d2d_dep, wincodec_dep] + + if cpp_compiler.has_header('d2d1_3.h') + conf.set('HAVE_D2D1_3_H', 1) + endif + + add_project_arguments('-DWINVER=_WIN32_WINNT_WIN10', '-D_WIN32_WINNT=_WIN32_WINNT_WIN10', '-DNTDDI_VERSION=NTDDI_WIN10_RS3', language: ['c', 'cpp']) + else + add_project_arguments('-DWINVER=_WIN32_WINNT_WIN2K', '-D_WIN32_WINNT=_WIN32_WINNT_WIN2K', language: ['c', 'cpp']) + endif +endif + +gobject_dep = dependency('gobject-2.0', + required: get_option('glib'), + fallback: ['glib', 'libgobject_dep'] +) +glib_dep = dependency('glib-2.0', + required: get_option('glib'), + version: glib_required_version, + fallback: ['glib', 'libglib_dep'], +) +if gobject_dep.found() and glib_dep.found() + feature_conf.set('CAIRO_HAS_GOBJECT_FUNCTIONS', 1) +endif + +if zlib_dep.found() + feature_conf.set('CAIRO_HAS_SCRIPT_SURFACE', 1) + built_features += [{ + 'name': 'cairo-script', + 'description': 'script surface backend', + 'deps': [zlib_dep], + }] +endif + +if zlib_dep.found() + feature_conf.set('CAIRO_HAS_PS_SURFACE', 1) + built_features += [{ + 'name': 'cairo-ps', + 'description': 'PostScript surface backend', + 'deps': [zlib_dep], + }] +endif + +if zlib_dep.found() + feature_conf.set('CAIRO_HAS_PDF_SURFACE', 1) + built_features += [{ + 'name': 'cairo-pdf', + 'description': 'PDF surface backend', + 'deps': [zlib_dep], + }] +endif + +if zlib_dep.found() + conf.set('CAIRO_HAS_INTERPRETER', 1) +endif + +bfd_dep = cc.find_library('bfd', has_headers: ['bfd.h'], required: get_option('symbol-lookup')) +if bfd_dep.found() and \ + cc.has_function('bfd_openr', dependencies: [bfd_dep]) and \ + cc.links(files('meson-cc-tests/bfd-section-flags.c'), name: 'bfd_section_flags', dependencies: bfd_dep) + conf.set('HAVE_BFD', 1) + deps += [bfd_dep] +elif get_option('symbol-lookup').enabled() + error('symbol lookup via bfd was enabled via options but is not available (bfd might be too old)') +endif + +if conf.get('HAVE_BFD', 0) == 1 + conf.set('CAIRO_HAS_SYMBOL_LOOKUP', 1) +endif + +if feature_conf.get('CAIRO_HAS_PS_SURFACE', 0) == 1 + gs = find_program('gs', required: get_option('tests')) + libspectre_dep = dependency('libspectre', version: '>= 0.2.0', + required: get_option('spectre')) + if gs.found() and libspectre_dep.found() + conf.set('CAIRO_CAN_TEST_PS_SURFACE', 1) + endif + + if libspectre_dep.found() + conf.set('CAIRO_HAS_SPECTRE', 1) + test_deps += [libspectre_dep] + endif +endif + +if feature_conf.get('CAIRO_HAS_PDF_SURFACE', 0) == 1 + poppler_dep = dependency('poppler-glib', version: '>= 0.17.4', + required: get_option('tests')) + if poppler_dep.found() and cc.has_function('poppler_page_render', dependencies: [poppler_dep]) + conf.set('CAIRO_CAN_TEST_PDF_SURFACE', 1) + test_deps += [poppler_dep] + endif +endif + +if feature_conf.get('CAIRO_HAS_SVG_SURFACE', 0) == 1 + librsvg_dep = dependency('librsvg-2.0', version: '>= 2.35.0', + required: get_option('tests')) + if librsvg_dep.found() + conf.set('CAIRO_CAN_TEST_SVG_SURFACE', 1) + test_deps += [librsvg_dep] + endif +endif + +pixman_dep = dependency('pixman-1', + version: '>= 0.40.0', + fallback: ['pixman', 'idep_pixman'], +) +if pixman_dep.found() + feature_conf.set('CAIRO_HAS_IMAGE_SURFACE', 1) + conf.set('HAS_PIXMAN_GLYPHS', 1) + if pixman_dep.version().version_compare('>= 0.42.3') + conf.set('HAS_PIXMAN_r8g8b8_sRGB', 1) + endif + if pixman_dep.type_name() == 'internal' + internal_deps += [pixman_dep] + else + deps += [pixman_dep] + endif +endif + +feature_conf.set('CAIRO_FEATURES_H', true) +feature_conf.set('CAIRO_HAS_USER_FONT', 1) + +feature_conf.set('CAIRO_HAS_MIME_SURFACE', 1) +feature_conf.set('CAIRO_HAS_RECORDING_SURFACE', 1) +feature_conf.set('CAIRO_HAS_OBSERVER_SURFACE', 1) + +if not get_option('tee').disabled() + feature_conf.set('CAIRO_HAS_TEE_SURFACE', 1) + built_features += [{ + 'name': 'cairo-tee', + 'description': 'Tee surface backend', + }] +endif + +incbase = include_directories('.') + +foreach check : check_sizeofs + type = check[0] + opts = check.length() > 1 ? check[1] : {} + + conf_name = opts.get('conf-name', 'SIZEOF_@0@'.format(type.underscorify().to_upper())) + + conf.set(conf_name, cc.sizeof(type)) +endforeach + +foreach check : check_headers + name = check[0] + opts = check.length() > 1 ? check[1] : {} + prefix = '' + + foreach header : opts.get('extra-headers', []) + prefix += '#include <@0@>\n'.format(header) + endforeach + + if cc.has_header(name, prefix: prefix) + conf.set('HAVE_@0@'.format(name.to_upper().underscorify()), 1) + check_funcs += check.length() > 1 ? check[1].get('check-funcs', []) : [] + endif +endforeach + +foreach check : check_types + name = check[0] + opts = check.length() > 1 ? check[1] : {} + prefix = '' + + foreach header : opts.get('headers', []) + prefix += '#include <@0@>\n'.format(header) + endforeach + + if cc.has_type(name, prefix: prefix) + conf.set('HAVE_@0@'.format(name.to_upper()), 1) + endif +endforeach + +foreach name : check_funcs + if cc.has_function(name, dependencies: deps) + conf.set('HAVE_@0@'.format(name.to_upper()), 1) + endif +endforeach + +conf.set('HAVE_STRNDUP', cc.has_function('strndup', prefix : '#include ')) + +pthread_c_args = [] +pthread_link_args = [] + +foreach thread_flags : check_thread_flags + if not conf.has('CAIRO_HAS_PTHREAD') + cflags = thread_flags[0] + lflags = thread_flags[1] + real_pthread = thread_flags.length() > 2 ? thread_flags[2].get('real', true) : true + + if cc.links(files('meson-cc-tests/pthread.c'), args: cflags + lflags, name: 'pthreads') + conf.set('CAIRO_HAS_PTHREAD', 1) + if real_pthread + conf.set('CAIRO_HAS_REAL_PTHREAD', 1) + endif + pthread_c_args = cflags + pthread_link_args = lflags + endif + endif +endforeach + +extra_link_args += pthread_link_args + +# Atomics are an optional feature in C11. Also need to check that C11 atomics are lock free. +# Windows can't use C11 atomics as some files are compiled with C++. +if host_machine.system() != 'windows' + if cc.links(files('meson-cc-tests/atomic-ops-c11.c'), name: 'Atomic ops: c11') + conf.set('HAVE_C11_ATOMIC_PRIMITIVES', 1) + elif cc.links(files('meson-cc-tests/atomic-ops-cxx11.c'), name: 'Atomic ops: cxx11') + conf.set('HAVE_CXX11_ATOMIC_PRIMITIVES', 1) + elif cc.links(files('meson-cc-tests/atomic-ops-gcc-legacy.c'), name: 'Atomic ops: gcc legacy') + conf.set('HAVE_GCC_LEGACY_ATOMICS', 1) + elif cc.has_header('atomic_ops.h') + conf.set('HAVE_LIB_ATOMIC_OPS', 1) + elif cc.has_header('libkern/OSAtomic.h') + conf.set('HAVE_OS_ATOMIC_OPS', 1) + else + warning('Atomic ops not supported.') + endif +endif + +test_mkdir_c_args = [] +if conf.get('HAVE_SYS_STAT_H', 0) == 1 + test_mkdir_c_args += ['-DHAVE_SYS_STAT_H'] +endif + +if conf.get('HAVE_IO_H', 0) == 1 + test_mkdir_c_args += ['-DHAVE_IO_H'] +endif + +if cc.links(files('meson-cc-tests/mkdir-variant-1.c'), args: test_mkdir_c_args) + conf.set('HAVE_MKDIR', 1) +elif cc.links(files('meson-cc-tests/mkdir-variant-2.c'), args: test_mkdir_c_args) + conf.set('HAVE_MKDIR', 2) +else + conf.set('HAVE_MKDIR', 0) +endif + +if not ['x86', 'x86_64'].contains(host_machine.cpu_family()) + conf.set('ATOMIC_OP_NEEDS_MEMORY_BARRIER', 1) +endif + +have_ld_preload = ['linux', 'freebsd', 'darwin', 'dragonfly', 'sunos'].contains(host_machine.system()) + +if have_ld_preload and zlib_dep.found() and conf.get('CAIRO_HAS_REAL_PTHREAD', 0) == 1 and conf.get('CAIRO_HAS_DLSYM', 0) == 1 + conf.set('CAIRO_HAS_TRACE', 1) +endif + +rt_dep = cc.find_library('rt', required: false) +have_shm = false +if rt_dep.found() and cc.has_function('shm_open', dependencies: [rt_dep]) + have_shm = true +endif + +# This to make sure we don't run checks against internal deps +deps += internal_deps + +subdir('src') + +if feature_conf.get('CAIRO_HAS_PNG_FUNCTIONS', 0) == 1 + subdir('boilerplate') +else + cairoboilerplate_dep = dependency('', required: false) +endif + +subdir('util') + +if not get_option('tests').disabled() and feature_conf.get('CAIRO_HAS_PNG_FUNCTIONS', 0) == 1 + subdir('test') + subdir('perf') +endif + +if get_option('gtk_doc') + doc_srcdir = include_directories('src') + subdir('doc/public') +endif + +configure_file(output: 'config.h', configuration: conf) + +foreach feature: built_features + feature_deps = feature.get('deps', []) + feature_libs = feature.get('libs', []) + feature_compile_deps = feature.get('compile-deps', []) + pkgmod.generate(libraries: [libcairo, feature_deps, feature_libs], + name: feature['name'], + description: feature['description'] + ' for cairo graphics library', + ) + meson.override_dependency(feature['name'], + declare_dependency(dependencies: [libcairo_dep, feature_deps, feature_compile_deps], + link_args: feature_libs, + ) + ) +endforeach + +# summary +summary({ + 'Image': true, + 'Recording': true, + 'Observer': true, + 'Mime': true, + 'Tee': feature_conf.get('CAIRO_HAS_TEE_SURFACE', 0) == 1, + 'Xlib': feature_conf.get('CAIRO_HAS_XLIB_SURFACE', 0) == 1, + 'Xlib Xrender': feature_conf.get('CAIRO_HAS_XLIB_XRENDER_SURFACE', 0) == 1, + 'Quartz': feature_conf.get('CAIRO_HAS_QUARTZ_SURFACE', 0) == 1, + 'Quartz-image': feature_conf.get('CAIRO_HAS_QUARTZ_IMAGE_SURFACE', 0) == 1, + 'XCB': feature_conf.get('CAIRO_HAS_XCB_SURFACE', 0) == 1, + 'Win32': feature_conf.get('CAIRO_HAS_WIN32_SURFACE', 0) == 1, + 'CairoScript': feature_conf.get('CAIRO_HAS_SCRIPT_SURFACE', 0) == 1, + 'PostScript': feature_conf.get('CAIRO_HAS_PS_SURFACE', 0) == 1, + 'PDF': feature_conf.get('CAIRO_HAS_PDF_SURFACE', 0) == 1, + 'SVG': feature_conf.get('CAIRO_HAS_SVG_SURFACE', 0) == 1, + }, section: 'Surface Backends', bool_yn: true) + +summary({ + 'User': true, + 'FreeType': feature_conf.get('CAIRO_HAS_FT_FONT', 0) == 1, + 'Fontconfig': feature_conf.get('CAIRO_HAS_FC_FONT', 0) == 1, + 'Win32': feature_conf.get('CAIRO_HAS_WIN32_FONT', 0) == 1, + 'Win32 DWrite': feature_conf.get('CAIRO_HAS_DWRITE_FONT', 0) == 1, + 'Quartz': feature_conf.get('CAIRO_HAS_QUARTZ_FONT', 0) == 1, + }, section: 'Font Backends', bool_yn: true) + +summary({ + 'PNG functions': feature_conf.get('CAIRO_HAS_PNG_FUNCTIONS', 0) == 1, + 'X11-xcb': feature_conf.get('CAIRO_HAS_XLIB_XCB_FUNCTIONS', 0) == 1, + 'XCB-shm': feature_conf.get('CAIRO_HAS_XCB_SHM_FUNCTIONS', 0) == 1, + }, section: 'Functions', bool_yn: true) + +summary({ + 'cairo-trace:': conf.get('CAIRO_HAS_TRACE', 0) == 1, + 'cairo-script-interpreter': conf.get('CAIRO_HAS_INTERPRETER', 0) == 1, + 'API reference': get_option('gtk_doc'), + }, section: 'Features and Utilities', bool_yn: true) diff --git a/local/recipes/libs/cairo/source/meson.options b/local/recipes/libs/cairo/source/meson.options new file mode 100644 index 0000000000..8aa6814bb3 --- /dev/null +++ b/local/recipes/libs/cairo/source/meson.options @@ -0,0 +1,30 @@ +# Cairo font backends +option('dwrite', type : 'feature', value : 'auto') +option('fontconfig', type : 'feature', value : 'auto') +option('freetype', type : 'feature', value : 'auto') + +# Cairo surface backends +option('png', type : 'feature', value : 'auto') # png and svg surfaces +option('quartz', type : 'feature', value : 'auto') +option('tee', type : 'feature', value : 'auto') +option('xcb', type : 'feature', value : 'auto') +option('xlib', type : 'feature', value : 'auto') +option('xlib-xcb', type : 'feature', value : 'disabled') +option('zlib', type : 'feature', value : 'auto') # script, ps, pdf, xml surfaces + +# Tests +option('tests', type : 'feature', value : 'auto') + +# Util deps +option('lzo', type : 'feature', value : 'auto') +option('gtk2-utils', type : 'feature', value : 'disabled') + +# Misc deps +option('glib', type : 'feature', value : 'auto') +option('spectre', type : 'feature', value : 'auto') +option('symbol-lookup', type: 'feature', value : 'auto', + description: 'Symbol lookup in debug utils via binutils/bfd') + +# Documentation +option('gtk_doc', type : 'boolean', value : false, + description: 'Build the Cairo API reference (depends on gtk-doc)') diff --git a/local/recipes/libs/cairo/source/perf/.gitignore b/local/recipes/libs/cairo/source/perf/.gitignore new file mode 100644 index 0000000000..02af7a93cd --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/.gitignore @@ -0,0 +1,30 @@ +TAGS +tags +cairo-analyse-trace +cairo-perf +cairo-perf-micro +cairo-perf-print +cairo-perf-trace +cairo-perf-chart +cairo-perf-compare-backends +cairo-perf-diff-files +cairo-perf-graph-files +cairo-traces +valgrind-log +callgrind.out.* +index.html +*.png +*.perf +*.o +*.gcda +*.gcno +*.exe +*.manifest +*.obj +*.ilk +*.suo +*.lib +*.pdb +*~ +.*.sw? +*.data diff --git a/local/recipes/libs/cairo/source/perf/COPYING b/local/recipes/libs/cairo/source/perf/COPYING new file mode 100644 index 0000000000..17754cf7b2 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/COPYING @@ -0,0 +1,5 @@ +Cairo is free software. + +These tests are mainly available under a liberal MIT license to simplify +any use of the code for reference purposes. Please check the opening comment +of each file for copyright and licensing information. diff --git a/local/recipes/libs/cairo/source/perf/README b/local/recipes/libs/cairo/source/perf/README new file mode 100644 index 0000000000..1b1c19a1f4 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/README @@ -0,0 +1,239 @@ +This is cairo's micro-benchmark performance test suite. + +One of the simplest ways to run this performance suite is: + + make perf + +which will give a report of the speed of each individual test. See +more details on other options for running the suite below. + +A macro test suite (with full traces and more intensive benchmarks) is +also available; for this, see https://cgit.freedesktop.org/cairo-traces. +The macro-benchmarks are better measures of actual real-world +performance, and should be preferred over the micro-benchmarks (and over +make perf) for identifying performance regressions or improvements. If +you copy or symlink this repository at cairo/perf/cairo-traces, then +make perf will run those tests as well. + +Running the micro-benchmarks +---------------------------- +The micro-benchmark performance suite is composed of a series of +hand-written, short, synthetic tests that measure the speed of doing a +simple operation such as painting a surface or showing glyphs. These aim +to give very good feedback on whether a performance related patch is +successful without causing any performance degradations elsewhere. + +The micro-benchmarks are compiled into a single executable called +cairo-perf-micro, which is what "make perf" executes. Some +examples of running it: + + # Report on all tests with default number of iterations: + ./cairo-perf-micro + + # Report on 100 iterations of all gradient tests: + ./cairo-perf-micro -i 100 gradient + + # Generate raw results for 10 iterations into cairo.perf + ./cairo-perf-micro -r -i 10 > cairo.perf + # Append 10 more iterations of the paint test + ./cairo-perf-micro -r -i 10 paint >> cairo.perf + +Raw results aren't useful for reading directly, but are quite useful +when using cairo-perf-diff to compare separate runs (see more +below). The advantage of using the raw mode is that test runs can be +generated incrementally and appended to existing reports. + +Generating comparisons of separate runs +--------------------------------------- +It's often useful to generate a chart showing the comparison of two +separate runs of the cairo performance suite, (for example, after +applying a patch intended to improve cairo's performance). The +cairo-perf-diff script can be used to compare two report files +generated by cairo-perf. + +Again, by way of example: + + # Show performance changes from cairo-orig.perf to cairo-patched.perf + ./cairo-perf-diff cairo-orig.perf cairo-patched.perf + +This will work whether the data files were generate in raw mode (with +cairo-perf -r) or cooked, (cairo-perf without -r). + +Finally, in its most powerful mode, cairo-perf-diff accepts two git +revisions and will do all the work of checking each revision out, +building it, running cairo-perf for each revision, and finally +generating the report. Obviously, this mode only works if you are +using cairo within a git repository, (and not from a tar file). Using +this mode is as simple as passing the git revisions to be compared to +cairo-perf-diff: + + # Compare cairo 1.2.6 to cairo 1.4.0 + ./cairo-perf-diff 1.2.6 1.4.0 + + # Measure the impact of the latest commit + ./cairo-perf-diff HEAD~1 HEAD + +As a convenience, this common desire to measure a single commit is +supported by passing a single revision to cairo-perf-diff, in which +case it will compare it to the immediately preceding commit. So for +example: + + # Measure the impact of the latest commit + ./cairo-perf-diff HEAD + + # Measure the impact of an arbitrary commit by SHA-1 + ./cairo-perf-diff aa883123d2af90 + +Also, when passing git revisions to cairo-perf-diff like this, it will +automatically cache results and re-use them rather than re-running +cairo-perf over and over on the same versions. This means that if you +ask for a report that you've generated in the past, cairo-perf-diff +should return it immediately. + +Now, sometimes it is desirable to generate more iterations rather than +re-using cached results. In this case, the -f flag can be used to +force cairo-perf-diff to generate additional results in addition to +what has been cached: + + # Measure the impact of latest commit (force more measurement) + ./cairo-perf-diff -f + +And finally, the -f mode is most useful in conjunction with the -- +option to cairo-perf-diff which allows you to pass options to the +underlying cairo-perf runs. This allows you to restrict the additional +test runs to a limited subset of the tests. + +For example, a frequently used trick is to first generate a chart with +a very small number of iterations for all tests: + + ./cairo-perf-diff HEAD + +Then, if any of the results look suspicious, (say there's a slowdown +reported in the text tests, but you think the text test shouldn't be +affected), then you can force more iterations to be tested for only +those tests: + + ./cairo-perf-diff -f HEAD -- text + +Generating comparisons of different backends +-------------------------------------------- +An alternate question that is often asked is, "how does the speed of one +backend compare to another?". cairo-perf-compare-backends can read files +generated by cairo-perf and produces a comparison of the backends for every +test. + +Again, by way of example: + + # Show relative performance of the backends + ./cairo-perf-compare-backends cairo.perf + +This will work whether the data files were generate in raw mode (with +cairo-perf -r) or cooked, (cairo-perf without -r). + + +Creating a new performance test +------------------------------- +This is where we could use everybody's help. If you have encountered a +sequence of cairo operations that are slower than you would like, then +please provide a performance test. Writing a test is very simple, it +requires you to write only a small C file with a couple of functions, +one of which exercises the cairo calls of interest. + +Here is the basic structure of a performance test file: + + /* Copyright © 2006 Kind Cairo User + * + * ... Licensing information here ... + * Please copy the MIT blurb as in other tests + */ + + #include "cairo-perf.h" + + static cairo_time_t + do_my_new_test (cairo_t *cr, int width, int height) + { + cairo_perf_timer_start (); + + /* Make the cairo calls to be measured */ + + cairo_perf_timer_stop (); + + return cairo_perf_timer_elapsed (); + } + + void + my_new_test (cairo_perf_t *perf, cairo_t *cr, int width, int height) + { + /* First do any setup for which the execution time should not + * be measured. For example, this might include loading + * images from disk, creating patterns, etc. */ + + /* Then launch the actual performance testing. */ + cairo_perf_run (perf, "my_new_test", do_my_new_test); + + /* Finally, perform any cleanup from the setup above. */ + } + +That's really all there is to writing a new test. The first function +above is the one that does the real work and returns a timing +number. The second function is the one that will be called by the +performance test rig (see below for how to accomplish that), and +allows for multiple performance cases to be written in one file, +(simply call cairo_perf_run once for each case, passing the +appropriate callback function to each). + +We go through this dance of indirectly calling your own function +through cairo_perf_run so that cairo_perf_run can call your function +many times and measure statistical properties over the many runs. + +Finally, to fully integrate your new test case you just need to add +your new test to three different lists. (TODO: We should set this up +better so that the lists are maintained automatically---computed from +the list of files in cairo/perf, for example). Here's what needs to be +added: + + 1. Makefile.am: Add the new file name to the cairo_perf_SOURCES list + + 2. cairo-perf.h: Add a new CAIRO_PERF_DECL line with the name of your + function, (my_new_test in the example above) + + 3. cairo-perf-micro.c: Add a new row to the list at the end of the + file. A typical entry would look like: + + { my_new_test, 16, 64 } + + The last two numbers are a minimum and a maximum image size at + which your test should be exercised. If these values are the same, + then only that size will be used. If they are different, then + intermediate sizes will be used by doubling. So in the example + above, three tests would be performed at sizes of 16x16, 32x32 and + 64x64. + + +How to run cairo-perf-diff on WINDOWS +------------------------------------- +This section explains the specifics of running cairo-perf-diff under +win32 plateforms. It assumes that you have installed a UNIX-like shell +environment such as MSYS (distributed as part of MinGW). + + 1. From your Mingw32 window, be sure to have all of your MSVC environ- + ment variables set up for proper compilation using 'make' + + 2. Add the %GitBaseDir%/Git/bin path to your environment, replacing the + %GitBaseDir% by whatever directory your Git version is installed to. + + 3. Comment out the "UNSET CDPATH" line in the git-sh-setup script + (located inside the ...Git/bin directory) by putting a "#" at the + beginning of the line. + +you should be ready to go ! + +From your mingw32 window, go to your cairo/perf directory and run the +cairo-perf-diff script with the right arguments. + +Thanks for your contributions and have fun with cairo! + +TODO +---- +Add a control language for crafting and running small sets of micro +benchmarks. diff --git a/local/recipes/libs/cairo/source/perf/cairo-analyse-trace.c b/local/recipes/libs/cairo/source/perf/cairo-analyse-trace.c new file mode 100644 index 0000000000..dda33a2e03 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/cairo-analyse-trace.c @@ -0,0 +1,590 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright © 2006 Mozilla Corporation + * Copyright © 2006 Red Hat, Inc. + * Copyright © 2009 Chris Wilson + * Copyright © 2011 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * the authors not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. The authors make no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Vladimir Vukicevic + * Carl Worth + * Chris Wilson + */ + +#include "config.h" + +#include "cairo-perf.h" +#include "cairo-stats.h" + +#include "cairo-boilerplate-getopt.h" +#include +#include "cairo-missing.h" + +/* rudely reuse bits of the library... */ +#include "../src/cairo-error-private.h" + +/* For basename */ +#ifdef HAVE_LIBGEN_H +#include +#endif +#include /* isspace() */ + +#include +#include + +#ifdef _MSC_VER +#include "dirent-win32.h" + +static char * +basename_no_ext (char *path) +{ + static char name[_MAX_FNAME + 1]; + + _splitpath (path, NULL, NULL, name, NULL); + + name[_MAX_FNAME] = '\0'; + + return name; +} + + +#else +#include + +static char * +basename_no_ext (char *path) +{ + char *dot, *name; + + name = basename (path); + + dot = strchr (name, '.'); + if (dot) + *dot = '\0'; + + return name; +} + +#endif + +#if HAVE_UNISTD_H +#include +#endif + +#include + +#if HAVE_FCFINI +#include +#endif + +struct trace { + const cairo_boilerplate_target_t *target; + void *closure; + cairo_surface_t *surface; +}; + +cairo_bool_t +cairo_perf_can_run (cairo_perf_t *perf, + const char *name, + cairo_bool_t *is_explicit) +{ + unsigned int i; + char *copy, *dot; + cairo_bool_t ret; + + if (is_explicit) + *is_explicit = FALSE; + + if (perf->exact_names) { + if (is_explicit) + *is_explicit = TRUE; + return TRUE; + } + + if (perf->num_names == 0 && perf->num_exclude_names == 0) + return TRUE; + + copy = xstrdup (name); + dot = strchr (copy, '.'); + if (dot != NULL) + *dot = '\0'; + + if (perf->num_names) { + ret = TRUE; + for (i = 0; i < perf->num_names; i++) + if (strstr (copy, perf->names[i])) { + if (is_explicit) + *is_explicit = strcmp (copy, perf->names[i]) == 0; + goto check_exclude; + } + + ret = FALSE; + goto done; + } + +check_exclude: + if (perf->num_exclude_names) { + ret = FALSE; + for (i = 0; i < perf->num_exclude_names; i++) + if (strstr (copy, perf->exclude_names[i])) { + if (is_explicit) + *is_explicit = strcmp (copy, perf->exclude_names[i]) == 0; + goto done; + } + + ret = TRUE; + goto done; + } + +done: + free (copy); + + return ret; +} + +static cairo_surface_t * +surface_create (void *closure, + cairo_content_t content, + double width, + double height, + long uid) +{ + struct trace *args = closure; + return cairo_surface_create_similar (args->surface, content, width, height); +} + +static int user_interrupt; + +static void +interrupt (int sig) +{ + if (user_interrupt) { + signal (sig, SIG_DFL); + raise (sig); + } + + user_interrupt = 1; +} + +static void +describe (cairo_perf_t *perf, + void *closure) +{ + char *description = NULL; + + if (perf->has_described_backend) + return; + perf->has_described_backend = TRUE; + + if (perf->target->describe) + description = perf->target->describe (closure); + + if (description == NULL) + return; + + free (description); +} + +static void +execute (cairo_perf_t *perf, + struct trace *args, + const char *trace) +{ + char *trace_cpy, *name; + const cairo_script_interpreter_hooks_t hooks = { + .closure = args, + .surface_create = surface_create, + }; + + trace_cpy = xstrdup (trace); + name = basename_no_ext (trace_cpy); + + if (perf->list_only) { + printf ("%s\n", name); + free (trace_cpy); + return; + } + + describe (perf, args->closure); + + { + cairo_script_interpreter_t *csi; + cairo_status_t status; + unsigned int line_no; + + csi = cairo_script_interpreter_create (); + cairo_script_interpreter_install_hooks (csi, &hooks); + + cairo_script_interpreter_run (csi, trace); + + cairo_script_interpreter_finish (csi); + + line_no = cairo_script_interpreter_get_line_number (csi); + status = cairo_script_interpreter_destroy (csi); + if (status) { + /* XXXX cairo_status_to_string is just wrong! */ + fprintf (stderr, "Error during replay, line %d: %s\n", + line_no, cairo_status_to_string (status)); + } + } + user_interrupt = 0; + + free (trace_cpy); +} + +static void +usage (const char *argv0) +{ + fprintf (stderr, +"Usage: %s [-l] [-i iterations] [-x exclude-file] [test-names ... | traces ...]\n" +"\n" +"Run the cairo trace analysis suite over the given tests (all by default)\n" +"The command-line arguments are interpreted as follows:\n" +"\n" +" -i iterations; specify the number of iterations per test case\n" +" -l list only; just list selected test case names without executing\n" +" -x exclude; specify a file to read a list of traces to exclude\n" +"\n" +"If test names are given they are used as sub-string matches so a command\n" +"such as \"%s firefox\" can be used to run all firefox traces.\n" +"Alternatively, you can specify a list of filenames to execute.\n", + argv0, argv0); +} + +static cairo_bool_t +read_excludes (cairo_perf_t *perf, + const char *filename) +{ + FILE *file; + char *line = NULL; + size_t line_size = 0; + char *s, *t; + + file = fopen (filename, "r"); + if (file == NULL) + return FALSE; + + while (getline (&line, &line_size, file) != -1) { + /* terminate the line at a comment marker '#' */ + s = strchr (line, '#'); + if (s) + *s = '\0'; + + /* whitespace delimits */ + s = line; + while (*s != '\0' && isspace ((unsigned char)*s)) + s++; + + t = s; + while (*t != '\0' && ! isspace ((unsigned char)*t)) + t++; + + if (s != t) { + int i = perf->num_exclude_names; + perf->exclude_names = xrealloc (perf->exclude_names, + sizeof (char *) * (i+1)); + perf->exclude_names[i] = strndup (s, t-s); + perf->num_exclude_names++; + } + } + free (line); + + fclose (file); + + return TRUE; +} + +static void +parse_options (cairo_perf_t *perf, + int argc, + char *argv[]) +{ + char *end; + int c; + + perf->list_only = FALSE; + perf->names = NULL; + perf->num_names = 0; + perf->exclude_names = NULL; + perf->num_exclude_names = 0; + + while (1) { + c = _cairo_getopt (argc, argv, "i:lx:"); + if (c == -1) + break; + + switch (c) { + case 'i': + perf->exact_iterations = TRUE; + perf->iterations = strtoul (optarg, &end, 10); + if (*end != '\0') { + fprintf (stderr, "Invalid argument for -i (not an integer): %s\n", + optarg); + exit (1); + } + break; + case 'l': + perf->list_only = TRUE; + break; + case 'x': + if (! read_excludes (perf, optarg)) { + fprintf (stderr, "Invalid argument for -x (not readable file): %s\n", + optarg); + exit (1); + } + break; + default: + fprintf (stderr, "Internal error: unhandled option: %c\n", c); + /* fall-through */ + case '?': + usage (argv[0]); + exit (1); + } + } + + if (optind < argc) { + perf->names = &argv[optind]; + perf->num_names = argc - optind; + } +} + +static void +cairo_perf_fini (cairo_perf_t *perf) +{ + cairo_boilerplate_free_targets (perf->targets); + cairo_boilerplate_fini (); + + cairo_debug_reset_static_data (); +#if HAVE_FCFINI + FcFini (); +#endif +} + +static cairo_bool_t +have_trace_filenames (cairo_perf_t *perf) +{ + unsigned int i; + + if (perf->num_names == 0) + return FALSE; + +#if HAVE_UNISTD_H + for (i = 0; i < perf->num_names; i++) + if (access (perf->names[i], R_OK) == 0) + return TRUE; +#endif + + return FALSE; +} + +static cairo_status_t +print (void *closure, const unsigned char *data, unsigned int length) +{ + fwrite (data, length, 1, closure); + return CAIRO_STATUS_SUCCESS; +} + +static void +cairo_perf_trace (cairo_perf_t *perf, + const cairo_boilerplate_target_t *target, + const char *trace) +{ + struct trace args; + cairo_surface_t *real; + + args.target = target; + real = target->create_surface (NULL, + CAIRO_CONTENT_COLOR_ALPHA, + 1, 1, + 1, 1, + CAIRO_BOILERPLATE_MODE_PERF, + &args.closure); + args.surface = + cairo_surface_create_observer (real, + CAIRO_SURFACE_OBSERVER_RECORD_OPERATIONS); + cairo_surface_destroy (real); + if (cairo_surface_status (args.surface)) { + fprintf (stderr, + "Error: Failed to create target surface: %s\n", + target->name); + return; + } + + printf ("Observing '%s'...", trace); + fflush (stdout); + + execute (perf, &args, trace); + + printf ("\n"); + cairo_device_observer_print (cairo_surface_get_device (args.surface), + print, stdout); + fflush (stdout); + + cairo_surface_destroy (args.surface); + + if (target->cleanup) + target->cleanup (args.closure); +} + +static void +warn_no_traces (const char *message, + const char *trace_dir) +{ + fprintf (stderr, +"Error: %s '%s'.\n" +"Have you cloned the cairo-traces repository and uncompressed the traces?\n" +" git clone git://anongit.freedesktop.org/cairo-traces\n" +" cd cairo-traces && make\n" +"Or set the env.var CAIRO_TRACE_DIR to point to your traces?\n", + message, trace_dir); +} + +static int +cairo_perf_trace_dir (cairo_perf_t *perf, + const cairo_boilerplate_target_t *target, + const char *dirname) +{ + DIR *dir; + struct dirent *de; + int num_traces = 0; + cairo_bool_t force; + cairo_bool_t is_explicit; + + dir = opendir (dirname); + if (dir == NULL) + return 0; + + force = FALSE; + if (cairo_perf_can_run (perf, dirname, &is_explicit)) + force = is_explicit; + + while ((de = readdir (dir)) != NULL) { + char *trace; + struct stat st; + + if (de->d_name[0] == '.') + continue; + + xasprintf (&trace, "%s/%s", dirname, de->d_name); + if (stat (trace, &st) != 0) + goto next; + + if (S_ISDIR(st.st_mode)) { + num_traces += cairo_perf_trace_dir (perf, target, trace); + } else { + const char *dot; + + dot = strrchr (de->d_name, '.'); + if (dot == NULL) + goto next; + if (strcmp (dot, ".trace")) + goto next; + + num_traces++; + if (!force && ! cairo_perf_can_run (perf, de->d_name, NULL)) + goto next; + + cairo_perf_trace (perf, target, trace); + } +next: + free (trace); + + } + closedir (dir); + + return num_traces; +} + +int +main (int argc, + char *argv[]) +{ + cairo_perf_t perf; + const char *trace_dir = "cairo-traces:/usr/src/cairo-traces:/usr/share/cairo-traces"; + unsigned int n; + int i; + + parse_options (&perf, argc, argv); + + signal (SIGINT, interrupt); + + if (getenv ("CAIRO_TRACE_DIR") != NULL) + trace_dir = getenv ("CAIRO_TRACE_DIR"); + + perf.targets = cairo_boilerplate_get_targets (&perf.num_targets, NULL); + + /* do we have a list of filenames? */ + perf.exact_names = have_trace_filenames (&perf); + + for (i = 0; i < perf.num_targets; i++) { + const cairo_boilerplate_target_t *target = perf.targets[i]; + + if (! perf.list_only && ! target->is_measurable) + continue; + + perf.target = target; + perf.has_described_backend = FALSE; + + if (perf.exact_names) { + for (n = 0; n < perf.num_names; n++) { + struct stat st; + + if (stat (perf.names[n], &st) == 0) { + if (S_ISDIR (st.st_mode)) { + cairo_perf_trace_dir (&perf, target, perf.names[n]); + } else + cairo_perf_trace (&perf, target, perf.names[n]); + } + } + } else { + int num_traces = 0; + const char *dir; + + dir = trace_dir; + do { + char buf[1024]; + const char *end = strchr (dir, ':'); + if (end != NULL) { + memcpy (buf, dir, end-dir); + buf[end-dir] = '\0'; + end++; + + dir = buf; + } + + num_traces += cairo_perf_trace_dir (&perf, target, dir); + dir = end; + } while (dir != NULL); + + if (num_traces == 0) { + warn_no_traces ("Found no traces in", trace_dir); + return 1; + } + } + + if (perf.list_only) + break; + } + + cairo_perf_fini (&perf); + + return 0; +} diff --git a/local/recipes/libs/cairo/source/perf/cairo-perf-chart.c b/local/recipes/libs/cairo/source/perf/cairo-perf-chart.c new file mode 100644 index 0000000000..9ccb9b42ec --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/cairo-perf-chart.c @@ -0,0 +1,1113 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * Copyright © 2009 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of the + * copyright holders not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * + * Authors: Carl Worth + * Chris Wilson + */ + +#include "cairo-perf.h" + +#include +#include +#include +#include +#include +#include +#include + +struct chart { + cairo_perf_report_t *reports; + const char **names; + + cairo_t *cr; + int width, height; + int num_tests, num_reports; + double min_value, max_value; + double *average; + + cairo_bool_t use_html; + cairo_bool_t relative; +}; +struct color { + double red, green, blue; +}; + +#define FONT_SIZE 12 +#define PAD (4) + +static double +to_factor (double x) +{ +#if 1 + if (x > 1.) + return (x-1) * 100.; + else + return (1. - 1./x) * 100.; +#else + return log (x); +#endif +} + +static int +_double_cmp (const void *_a, + const void *_b) +{ + const double *a = _a; + const double *b = _b; + + if (*a > *b) + return 1; + if (*a < *b) + return -1; + return 0; +} + +static void +trim_outliers (double *values, + int num_values, + double *min, + double *max) +{ + double q1, q3, iqr; + double outlier_min, outlier_max; + int i; + + /* First, identify any outliers, using the definition of "mild + * outliers" from: + * + * http://en.wikipedia.org/wiki/Outliers + * + * Which is that outliers are any values less than Q1 - 1.5 * IQR + * or greater than Q3 + 1.5 * IQR where Q1 and Q3 are the first + * and third quartiles and IQR is the inter-quartile range (Q3 - + * Q1). + */ + qsort (values, num_values, + sizeof (double), _double_cmp); + + q1 = values[1*num_values / 6]; + q3 = values[5*num_values / 6]; + + iqr = q3 - q1; + + outlier_min = q1 - 3 * iqr; + outlier_max = q3 + 3 * iqr; + + i = 0; + while (i < num_values && values[i] < outlier_min) + i++; + if (i == num_values) + return; + + *min = values[i]; + + while (i < num_values && values[i] <= outlier_max) + i++; + + *max = values[i-1]; +} + +static void +find_ranges (struct chart *chart) +{ + test_report_t **tests, *min_test; + double *values; + int num_values, size_values; + double min = 0, max = 0; + double test_time; + int seen_non_null; + int num_tests = 0; + double slow_sum = 0, fast_sum = 0, sum = 0; + int slow_count = 0, fast_count = 0; + int *count; + int i; + + num_values = 0; + size_values = 64; + values = xmalloc (size_values * sizeof (double)); + + chart->average = xmalloc(chart->num_reports * sizeof(double)); + count = xmalloc(chart->num_reports * sizeof(int)); + for (i = 0; i < chart->num_reports; i++) { + chart->average[i] = 0; + count[i] = 0; + } + + tests = xmalloc (chart->num_reports * sizeof (test_report_t *)); + for (i = 0; i < chart->num_reports; i++) + tests[i] = chart->reports[i].tests; + + while (1) { + /* We expect iterations values of 0 when multiple raw reports + * for the same test have been condensed into the stats of the + * first. So we just skip these later reports that have no + * stats. */ + seen_non_null = 0; + for (i = 0; i < chart->num_reports; i++) { + while (tests[i]->name && tests[i]->stats.iterations == 0) + tests[i]++; + if (tests[i]->name) + seen_non_null++; + } + if (! seen_non_null) + break; + + num_tests++; + + /* Find the minimum of all current tests, (we have to do this + * in case some reports don't have a particular test). */ + for (i = 0; i < chart->num_reports; i++) { + if (tests[i]->name) { + min_test = tests[i]; + break; + } + } + for (++i; i < chart->num_reports; i++) { + if (tests[i]->name && test_report_cmp_name (tests[i], min_test) < 0) + min_test = tests[i]; + } + + test_time = 0; + for (i = 0; i < chart->num_reports; i++) { + double report_time = HUGE_VAL; + + while (tests[i]->name && + test_report_cmp_name (tests[i], min_test) == 0) + { + double time = tests[i]->stats.min_ticks; + if (time < report_time) { + time /= tests[i]->stats.ticks_per_ms; + if (time < report_time) + report_time = time; + } + tests[i]++; + } + + if (report_time != HUGE_VAL) { + if (test_time == 0) + test_time = report_time; + + chart->average[i] += report_time / test_time; + count[i]++; + + if (chart->relative) { + if (test_time != report_time) { + double v = to_factor (test_time / report_time); + if (num_values == size_values) { + size_values *= 2; + values = xrealloc (values, + size_values * sizeof (double)); + } + values[num_values++] = v; + if (v < min) + min = v; + if (v > max) + max = v; + if (v > 0) + fast_sum += v/100, fast_count++; + else + slow_sum += v/100, slow_count++; + sum += v/100; + printf ("%s %d: %f\n", min_test->name, num_values, v); + } + } else { + if (report_time < min) + min = report_time; + if (report_time > max) + max = report_time; + } + } + } + } + + for (i = 0; i < chart->num_reports; i++) { + if (count[i]) + chart->average[i] = count[i] / chart->average[i]; + else + chart->average[i] = 1.; + } + + if (chart->relative) + trim_outliers (values, num_values, &min, &max); + chart->min_value = min; + chart->max_value = max; + chart->num_tests = num_tests + !!chart->relative; + + free (values); + free (tests); + free (count); + + printf ("%d: slow[%d] average: %f, fast[%d] average: %f, %f\n", + num_values, slow_count, slow_sum / slow_count, fast_count, fast_sum / fast_count, sum / num_values); +} + +#define SET_COLOR(C, R, G, B) (C)->red = (R), (C)->green = (G), (C)->blue = (B) +static void +hsv_to_rgb (double h, + double s, + double v, + struct color *color) +{ + double m, n, f; + int i; + + while (h < 0) + h += 6.; + while (h > 6.) + h -= 6.; + + if (s < 0.) + s = 0.; + if (s > 1.) + s = 1.; + + if (v < 0.) + v = 0.; + if (v > 1.) + v = 1.; + + i = floor (h); + f = h - i; + if ((i & 1) == 0) + f = 1 - f; + + m = v * (1 - s); + n = v * (1 - s * f); + switch(i){ + default: + case 6: + case 0: SET_COLOR (color, v, n, m); break; + case 1: SET_COLOR (color, n, v, m); break; + case 2: SET_COLOR (color, m, v, n); break; + case 3: SET_COLOR (color, m, n, v); break; + case 4: SET_COLOR (color, n, m, v); break; + case 5: SET_COLOR (color, v, m, n); break; + } +} + +static void set_report_color (struct chart *chart, int report) +{ + struct color color; + + hsv_to_rgb (6. / chart->num_reports * report, .7, .7, &color); + cairo_set_source_rgb (chart->cr, color.red, color.green, color.blue); +} + +static void set_report_gradient (struct chart *chart, int report, + double x, double y, double w, double h) +{ + struct color color; + cairo_pattern_t *p; + + hsv_to_rgb (6. / chart->num_reports * report, .7, .7, &color); + + p = cairo_pattern_create_linear (x, 0, x+w, 0); + cairo_pattern_add_color_stop_rgba (p, 0.0, + color.red, color.green, color.blue, + .50); + cairo_pattern_add_color_stop_rgba (p, 0.5, + color.red, color.green, color.blue, + .50); + cairo_pattern_add_color_stop_rgba (p, 1.0, + color.red, color.green, color.blue, + 1.0); + cairo_set_source (chart->cr, p); + cairo_pattern_destroy (p); +} + +static void +test_background (struct chart *c, + int test) +{ + double dx, x; + + dx = c->width / (double) c->num_tests; + x = dx * test; + + if (test & 1) + cairo_set_source_rgba (c->cr, .2, .2, .2, .2); + else + cairo_set_source_rgba (c->cr, .8, .8, .8, .2); + + cairo_rectangle (c->cr, floor (x), 0, + floor (dx + x) - floor (x), c->height); + cairo_fill (c->cr); +} + +static void +add_chart (struct chart *c, + int test, + int report, + double value) +{ + double dx, dy, x; + + if (fabs (value) < 0.1) + return; + + if (c->relative) { + cairo_text_extents_t extents; + char buf[80]; + double y; + + dy = (c->height/2. - PAD) / MAX (-c->min_value, c->max_value); + /* the first report is always skipped, as it is used as the baseline */ + dx = c->width / (double) (c->num_tests * c->num_reports); + x = dx * (c->num_reports * test + report - .5); + + cairo_rectangle (c->cr, + floor (x), c->height / 2., + floor (x + dx) - floor (x), + ceil (-dy*value - c->height/2.) + c->height/2.); + if (dx < 5) { + set_report_color (c, report); + cairo_fill (c->cr); + } else { + set_report_gradient (c, report, + floor (x), c->height / 2., + floor (x + dx) - floor (x), + ceil (-dy*value - c->height/2.) + c->height/2.); + + cairo_fill_preserve (c->cr); + cairo_save (c->cr); + cairo_clip_preserve (c->cr); + set_report_color (c, report); + cairo_stroke (c->cr); + cairo_restore (c->cr); + } + + /* Skip the label if the difference between the two is less than 0.1% */ + if (fabs (value) < 0.1) + return; + + cairo_save (c->cr); + cairo_set_font_size (c->cr, dx - 2); + + if (value < 0) { + sprintf (buf, "%.1f", -value/100 + 1); + } else { + sprintf (buf, "%.1f", value/100 + 1); + } + cairo_text_extents (c->cr, buf, &extents); + + /* will it be clipped? */ + y = -dy * value; + if (y < -c->height/2) { + y = -c->height/2; + } else if (y > c->height/2) { + y = c->height/2; + } + + if (y < 0) { + if (y > -extents.width - 6) + y -= extents.width + 6; + } else { + if (y < extents.width + 6) + y += extents.width + 6; + } + + cairo_translate (c->cr, + floor (x) + (floor (x + dx) - floor (x))/2, + floor (y) + c->height/2.); + cairo_rotate (c->cr, -M_PI/2); + if (y < 0) { + cairo_move_to (c->cr, -extents.x_bearing -extents.width - 4, -extents.y_bearing/2); + } else { + cairo_move_to (c->cr, 2, -extents.y_bearing/2); + } + + cairo_set_source_rgb (c->cr, .95, .95, .95); + cairo_show_text (c->cr, buf); + cairo_restore (c->cr); + } else { + dy = (c->height - PAD) / c->max_value; + dx = c->width / (double) (c->num_tests * (c->num_reports+1)); + x = dx * ((c->num_reports+1) * test + report + .5); + + cairo_rectangle (c->cr, + floor (x), c->height, + floor (x + dx) - floor (x), + floor (c->height - dy*value) - c->height); + if (dx < 5) { + set_report_color (c, report); + cairo_fill (c->cr); + } else { + set_report_gradient (c, report, + floor (x), c->height, + floor (x + dx) - floor (x), + floor (c->height - dy*value) - c->height); + cairo_fill_preserve (c->cr); + cairo_save (c->cr); + cairo_clip_preserve (c->cr); + set_report_color (c, report); + cairo_stroke (c->cr); + cairo_restore (c->cr); + } + } +} + +static void +add_average (struct chart *c, + int test, + int report, + double value) +{ + double dx, dy, x; + cairo_text_extents_t extents; + char buf[80]; + double y; + + if (fabs (value) < 0.1) + return; + + dy = (c->height/2. - PAD) / MAX (-c->min_value, c->max_value); + /* the first report is always skipped, as it is used as the baseline */ + dx = c->width / (double) (c->num_tests * c->num_reports); + x = dx * (c->num_reports * test + report - .5); + + cairo_rectangle (c->cr, + floor (x), c->height / 2., + floor (x + dx) - floor (x), + ceil (-dy*value - c->height/2.) + c->height/2.); + if (dx < 5) { + set_report_color (c, report); + cairo_fill (c->cr); + } else { + set_report_gradient (c, report, + floor (x), c->height / 2., + floor (x + dx) - floor (x), + ceil (-dy*value - c->height/2.) + c->height/2.); + + cairo_fill_preserve (c->cr); + cairo_save (c->cr); + cairo_clip_preserve (c->cr); + set_report_color (c, report); + cairo_stroke (c->cr); + cairo_restore (c->cr); + } + + /* Skip the label if the difference between the two is less than 0.1% */ + if (fabs (value) < 0.1) + return; + + cairo_save (c->cr); + cairo_set_font_size (c->cr, dx - 2); + + if (value < 0) { + sprintf (buf, "%.1f", -value/100 + 1); + } else { + sprintf (buf, "%.1f", value/100 + 1); + } + cairo_text_extents (c->cr, buf, &extents); + + /* will it be clipped? */ + y = -dy * value; + if (y < -c->height/2) { + y = -c->height/2; + } else if (y > c->height/2) { + y = c->height/2; + } + + if (y < 0) { + if (y > -extents.width - 6) + y -= extents.width + 6; + } else { + if (y < extents.width + 6) + y += extents.width + 6; + } + + cairo_translate (c->cr, + floor (x) + (floor (x + dx) - floor (x))/2, + floor (y) + c->height/2.); + cairo_rotate (c->cr, -M_PI/2); + if (y < 0) { + cairo_move_to (c->cr, -extents.x_bearing -extents.width - 4, -extents.y_bearing/2); + } else { + cairo_move_to (c->cr, 2, -extents.y_bearing/2); + } + + cairo_set_source_rgb (c->cr, .95, .95, .95); + cairo_show_text (c->cr, buf); + cairo_restore (c->cr); +} + +static void +add_label (struct chart *c, + int test, + const char *label) +{ + cairo_text_extents_t extents; + double dx, x; + + cairo_save (c->cr); + dx = c->width / (double) c->num_tests; + if (dx / 2 - PAD < 4) + return; + cairo_set_font_size (c->cr, dx / 2 - PAD); + cairo_text_extents (c->cr, label, &extents); + + cairo_set_source_rgb (c->cr, .5, .5, .5); + + x = (test + .5) * dx; + cairo_save (c->cr); + cairo_translate (c->cr, x, c->height - PAD / 2); + cairo_rotate (c->cr, -M_PI/2); + cairo_move_to (c->cr, 0, -extents.y_bearing/2); + cairo_show_text (c->cr, label); + cairo_restore (c->cr); + + cairo_save (c->cr); + cairo_translate (c->cr, x, PAD / 2); + cairo_rotate (c->cr, -M_PI/2); + cairo_move_to (c->cr, -extents.width, -extents.y_bearing/2); + cairo_show_text (c->cr, label); + cairo_restore (c->cr); + + cairo_restore (c->cr); +} + +static void +add_base_line (struct chart *c) +{ + double y; + + cairo_save (c->cr); + cairo_set_line_width (c->cr, 2.); + if (c->relative) { + y = c->height / 2.; + } else { + y = c->height; + } + cairo_move_to (c->cr, 0, y); + cairo_line_to (c->cr, c->width, y); + cairo_set_source_rgb (c->cr, 1, 1, 1); + cairo_stroke (c->cr); + cairo_restore (c->cr); +} + +static void +add_absolute_lines (struct chart *c) +{ + const double dashes[] = { 2, 4 }; + const double vlog_steps[] = { 10, 5, 4, 3, 2, 1, .5, .4, .3, .2, .1}; + double v, y, dy; + unsigned int i; + char buf[80]; + cairo_text_extents_t extents; + + v = c->max_value / 2.; + + for (i = 0; i < sizeof (vlog_steps) / sizeof (vlog_steps[0]); i++) { + double vlog = log (v) / log (vlog_steps[i]); + if (vlog > 1) { + v = pow (vlog_steps[i], floor (vlog)); + goto done; + } + } + return; +done: + + dy = (c->height - PAD) / c->max_value; + + cairo_save (c->cr); + cairo_set_line_width (c->cr, 1.); + cairo_set_dash (c->cr, dashes, sizeof (dashes) / sizeof (dashes[0]), 0); + + i = 0; + do { + y = c->height - ++i * v * dy; + if (y < PAD) + break; + + cairo_set_font_size (c->cr, 8); + + sprintf (buf, "%.0fs", i*v/1000); + cairo_text_extents (c->cr, buf, &extents); + + cairo_set_source_rgba (c->cr, .75, 0, 0, .95); + cairo_move_to (c->cr, 1-extents.x_bearing, floor (y) - (extents.height/2 + extents.y_bearing) + .5); + cairo_show_text (c->cr, buf); + + cairo_move_to (c->cr, c->width-extents.width-1, floor (y) - (extents.height/2 + extents.y_bearing) + .5); + cairo_show_text (c->cr, buf); + + cairo_set_source_rgba (c->cr, .75, 0, 0, .5); + cairo_move_to (c->cr, + ceil (extents.width + extents.x_bearing + 2), + floor (y) + .5); + cairo_line_to (c->cr, + floor (c->width - (extents.width + extents.x_bearing + 2)), + floor (y) + .5); + cairo_stroke (c->cr); + } while (1); + + cairo_restore (c->cr); +} + +static void +add_relative_lines (struct chart *c) +{ + const double dashes[] = { 2, 4 }; + const double v_steps[] = { 10, 5, 1, .5, .1, .05, .01}; + const int precision_steps[] = { 0, 0, 0, 1, 1, 2, 2}; + int precision; + double v, y, dy, mid; + unsigned int i; + char buf[80]; + cairo_text_extents_t extents; + + v = MAX (-c->min_value, c->max_value) / 200; + + for (i = 0; i < sizeof (v_steps) / sizeof (v_steps[0]); i++) { + if (v > v_steps[i]) { + v = v_steps[i]; + precision = precision_steps[i]; + goto done; + } + } + return; +done: + + mid = c->height/2.; + dy = (mid - PAD) / MAX (-c->min_value, c->max_value); + + cairo_save (c->cr); + cairo_set_line_width (c->cr, 1.); + cairo_set_dash (c->cr, dashes, sizeof (dashes) / sizeof (dashes[0]), 0); + cairo_set_font_size (c->cr, 8); + + i = 0; + do { + y = ++i * v * dy * 100; + if (y > mid) + break; + + sprintf (buf, "%.*fx", precision, i*v + 1); + cairo_text_extents (c->cr, buf, &extents); + + cairo_set_source_rgba (c->cr, .75, 0, 0, .95); + cairo_move_to (c->cr, 1-extents.x_bearing, floor (mid + y) - (extents.height/2 + extents.y_bearing) + .5); + cairo_show_text (c->cr, buf); + + cairo_move_to (c->cr, c->width-extents.width-1, floor (mid + y) - (extents.height/2 + extents.y_bearing) + .5); + cairo_show_text (c->cr, buf); + + cairo_set_source_rgba (c->cr, 0, .75, 0, .95); + cairo_move_to (c->cr, 1-extents.x_bearing, ceil (mid - y) - (extents.height/2 + extents.y_bearing) + .5); + cairo_show_text (c->cr, buf); + + cairo_move_to (c->cr, c->width-extents.width-1, ceil (mid - y) - (extents.height/2 + extents.y_bearing) + .5); + cairo_show_text (c->cr, buf); + + /* trim the dashes to no obscure the labels */ + cairo_set_source_rgba (c->cr, .75, 0, 0, .5); + cairo_move_to (c->cr, + ceil (extents.width + extents.x_bearing + 2), + floor (mid + y) + .5); + cairo_line_to (c->cr, + floor (c->width - (extents.width + 2)), + floor (mid + y) + .5); + cairo_stroke (c->cr); + + cairo_set_source_rgba (c->cr, 0, .75, 0, .5); + cairo_move_to (c->cr, + ceil (extents.width + extents.x_bearing + 2), + ceil (mid - y) + .5); + cairo_line_to (c->cr, + floor (c->width - (extents.width + 2)), + ceil (mid - y) + .5); + cairo_stroke (c->cr); + + } while (1); + + cairo_restore (c->cr); +} + +static void +add_slower_faster_guide (struct chart *c) +{ + cairo_text_extents_t extents; + + cairo_save (c->cr); + + cairo_set_font_size (c->cr, FONT_SIZE); + + cairo_text_extents (c->cr, "FASTER", &extents); + cairo_set_source_rgba (c->cr, 0, .75, 0, .5); + cairo_move_to (c->cr, + c->width/4. - extents.width/2. + extents.x_bearing, + 1 - extents.y_bearing); + cairo_show_text (c->cr, "FASTER"); + cairo_move_to (c->cr, + 3*c->width/4. - extents.width/2. + extents.x_bearing, + 1 - extents.y_bearing); + cairo_show_text (c->cr, "FASTER"); + + cairo_text_extents (c->cr, "SLOWER", &extents); + cairo_set_source_rgba (c->cr, .75, 0, 0, .5); + cairo_move_to (c->cr, + c->width/4. - extents.width/2. + extents.x_bearing, + c->height - 1); + cairo_show_text (c->cr, "SLOWER"); + cairo_move_to (c->cr, + 3*c->width/4. - extents.width/2. + extents.x_bearing, + c->height - 1); + cairo_show_text (c->cr, "SLOWER"); + + cairo_restore (c->cr); +} + +static void +cairo_perf_reports_compare (struct chart *chart, + cairo_bool_t print) +{ + test_report_t **tests, *min_test; + double test_time, best_time; + int num_test = 0; + int seen_non_null; + int i; + + tests = xmalloc (chart->num_reports * sizeof (test_report_t *)); + for (i = 0; i < chart->num_reports; i++) + tests[i] = chart->reports[i].tests; + + if (print) { + if (chart->use_html) { + printf ("\n"); + printf (""); + for (i = 0; i < chart->num_reports; i++) { + printf ("", chart->names[i] ? chart->names[i] : ""); + } + printf ("\n"); + } + } + + while (1) { + /* We expect iterations values of 0 when multiple raw reports + * for the same test have been condensed into the stats of the + * first. So we just skip these later reports that have no + * stats. */ + seen_non_null = 0; + for (i = 0; i < chart->num_reports; i++) { + while (tests[i]->name && tests[i]->stats.iterations == 0) + tests[i]++; + if (tests[i]->name) + seen_non_null++; + } + if (! seen_non_null) + break; + + /* Find the minimum of all current tests, (we have to do this + * in case some reports don't have a particular test). */ + for (i = 0; i < chart->num_reports; i++) { + if (tests[i]->name) { + min_test = tests[i]; + break; + } + } + for (++i; i < chart->num_reports; i++) { + if (tests[i]->name && test_report_cmp_name (tests[i], min_test) < 0) + min_test = tests[i]; + } + + add_label (chart, num_test, min_test->name); + if (print) { + if (chart->use_html) { + printf ("", min_test->name); + } else { + if (min_test->size) { + printf ("%16s, size %4d:\n", + min_test->name, + min_test->size); + } else { + printf ("%26s:", + min_test->name); + } + } + } + + test_time = 0; + best_time = HUGE_VAL; + for (i = 0; i < chart->num_reports; i++) { + test_report_t *initial = tests[i]; + double report_time = HUGE_VAL; + + while (tests[i]->name && + test_report_cmp_name (tests[i], min_test) == 0) + { + double time = tests[i]->stats.min_ticks; + if (time < report_time) { + time /= tests[i]->stats.ticks_per_ms; + if (time < report_time) + report_time = time; + } + tests[i]++; + } + + if (test_time == 0 && report_time != HUGE_VAL) + test_time = report_time; + if (report_time < best_time) + best_time = report_time; + + tests[i] = initial; + } + + for (i = 0; i < chart->num_reports; i++) { + double report_time = HUGE_VAL; + + while (tests[i]->name && + test_report_cmp_name (tests[i], min_test) == 0) + { + double time = tests[i]->stats.min_ticks; + if (time > 0) { + time /= tests[i]->stats.ticks_per_ms; + if (time < report_time) + report_time = time; + } + tests[i]++; + } + + if (print) { + if (chart->use_html) { + if (report_time < HUGE_VAL) { + if (report_time / best_time < 1.01) { + printf ("", report_time/1000); + } else { + printf ("", report_time/1000); + } + } else { + printf (""); + } + } else { + if (report_time < HUGE_VAL) + printf (" %6.1f", report_time/1000); + else + printf (" ---"); + } + } + + if (report_time < HUGE_VAL) { + if (chart->relative) { + add_chart (chart, num_test, i, + to_factor (test_time / report_time)); + } else { + add_chart (chart, num_test, i, report_time); + } + } + } + + if (print) { + if (chart->use_html) { + printf ("\n"); + } else { + printf ("\n"); + } + } + + num_test++; + } + if (chart->relative) { + add_label (chart, num_test, "(geometric mean)"); + for (i = 0; i < chart->num_reports; i++) + add_average (chart, num_test, i, to_factor (chart->average[i])); + } + free (tests); + + if (print) { + if (chart->use_html) + printf ("
    %s
    %s%.1f%.1f
    \n"); + + printf ("\n"); + for (i = 0; i < chart->num_reports; i++) { + if (chart->names[i]) { + printf ("[%s] %s\n", + chart->names[i], chart->reports[i].configuration); + } else { + printf ("[%d] %s\n", + i, chart->reports[i].configuration); + } + } + } +} + +static void +add_legend (struct chart *chart) +{ + cairo_text_extents_t extents; + const char *str; + int i, x, y; + + cairo_set_font_size (chart->cr, FONT_SIZE); + + x = PAD; + y = chart->height + PAD; + for (i = chart->relative; i < chart->num_reports; i++) { + str = chart->names[i] ? + chart->names[i] : chart->reports[i].configuration; + + set_report_color (chart, i); + + cairo_rectangle (chart->cr, x, y + 6, 8, 8); + cairo_fill (chart->cr); + + cairo_set_source_rgb (chart->cr, 1, 1, 1); + cairo_move_to (chart->cr, x + 10, y + FONT_SIZE + PAD / 2.); + cairo_text_extents (chart->cr, str, &extents); + cairo_show_text (chart->cr, str); + + x += 10 + 2 * PAD + ceil (extents.width); + } + + if (chart->relative) { + char buf[80]; + + str = chart->names[0] ? + chart->names[0] : chart->reports[0].configuration; + + sprintf (buf, "(relative to %s)", str); + cairo_text_extents (chart->cr, buf, &extents); + + cairo_set_source_rgb (chart->cr, 1, 1, 1); + cairo_move_to (chart->cr, + chart->width - 1 - extents.width, + y + FONT_SIZE + PAD / 2.); + cairo_show_text (chart->cr, buf); + } +} + +static void +usage (void) +{ + printf("Usage:\n"); + printf(" cairo-perf-chart [OPTION...] ...\n"); + printf("\n"); + printf("Help Options:\n"); + printf(" --help, --?\tShow help options\n"); + printf("\n"); + printf("Application Options:\n"); + printf(" --html\tOutput an HTML table comparing the results\n"); + printf(" --height=\tSet the height of the output graph"\ + " (default 480)\n"); + printf(" --width=\tSet the width of the output graph"\ + " (default 640)\n"); + printf(" --name\tSet the name of graph series."\ + " This only sets the name for the\n\t\tfirst result file."\ + " The graph series is usually set using the\n\t\tfile name for"\ + " the results file.\n"); + printf("\n"); + printf("Example:\n"); + printf(" cairo-perf-chart --width=1024 --height=768 run1 run2 run3\n"); + return; +} + +int +main (int argc, + const char *argv[]) +{ + cairo_surface_t *surface; + struct chart chart; + test_report_t *t; + int i; + + chart.use_html = 0; + chart.width = 640; + chart.height = 480; + + chart.reports = xcalloc (argc-1, sizeof (cairo_perf_report_t)); + chart.names = xcalloc (argc-1, sizeof (cairo_perf_report_t)); + + chart.num_reports = 0; + for (i = 1; i < argc; i++) { + if (strcmp (argv[i], "--html") == 0) { + chart.use_html = 1; + } else if (strncmp (argv[i], "--width=", 8) == 0) { + chart.width = atoi (argv[i] + 8); + } else if (strncmp (argv[i], "--height=", 9) == 0) { + chart.height = atoi (argv[i] + 9); + } else if (strcmp (argv[i], "--name") == 0) { + if (i + 1 < argc) + chart.names[chart.num_reports] = argv[++i]; + } else if (strncmp (argv[i], "--name=", 7) == 0) { + chart.names[chart.num_reports] = argv[i] + 7; + } else if ((strcmp (argv[i], "--help") == 0) || + (strcmp (argv[i], "--?") == 0)) { + usage(); + return 0; + } else { + cairo_perf_report_load (&chart.reports[chart.num_reports++], + argv[i], i, + test_report_cmp_name); + } + } + + for (chart.relative = 0; chart.relative <= 1; chart.relative++) { + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + chart.width, + chart.height + (FONT_SIZE + PAD) + 2*PAD); + chart.cr = cairo_create (surface); + cairo_surface_destroy (surface); + + cairo_set_source_rgb (chart.cr, 0, 0, 0); + cairo_paint (chart.cr); + + find_ranges (&chart); + + for (i = 0; i < chart.num_tests; i++) + test_background (&chart, i); + if (chart.relative) { + add_relative_lines (&chart); + add_slower_faster_guide (&chart); + } else + add_absolute_lines (&chart); + + cairo_save (chart.cr); + cairo_rectangle (chart.cr, 0, 0, chart.width, chart.height); + cairo_clip (chart.cr); + cairo_perf_reports_compare (&chart, !chart.relative); + cairo_restore (chart.cr); + + add_base_line (&chart); + add_legend (&chart); + + cairo_surface_write_to_png (cairo_get_target (chart.cr), + chart.relative ? "relative.png" : "absolute.png"); + cairo_destroy (chart.cr); + } + + /* Pointless memory cleanup, (would be a great place for talloc) */ + for (i = 0; i < chart.num_reports; i++) { + for (t = chart.reports[i].tests; t->name; t++) { + free (t->samples); + free (t->backend); + free (t->name); + } + free (chart.reports[i].tests); + free (chart.reports[i].configuration); + } + free (chart.names); + free (chart.reports); + + return 0; +} diff --git a/local/recipes/libs/cairo/source/perf/cairo-perf-compare-backends.c b/local/recipes/libs/cairo/source/perf/cairo-perf-compare-backends.c new file mode 100644 index 0000000000..ff7359e1a0 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/cairo-perf-compare-backends.c @@ -0,0 +1,398 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * Copyright © 2009 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of the + * copyright holders not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * + * Authors: Carl Worth + * Chris Wilson + */ + +#include "cairo-perf.h" + +#include +#include +#include +#include +#include +#include +#include + +typedef struct _cairo_perf_report_options { + double min_change; + int use_utf; + int print_change_bars; +} cairo_perf_report_options_t; + +typedef struct _cairo_perf_diff_files_args { + const char **filenames; + int num_filenames; + cairo_perf_report_options_t options; +} cairo_perf_diff_files_args_t; + +static int +test_diff_cmp (const void *a, + const void *b) +{ + const test_diff_t *a_diff = a; + const test_diff_t *b_diff = b; + + /* Reverse sort by magnitude of change so larger changes come + * first */ + if (a_diff->change > b_diff->change) + return -1; + + if (a_diff->change < b_diff->change) + return 1; + + return 0; +} + +#define CHANGE_BAR_WIDTH 70 +static void +print_change_bar (double change, + double max_change, + int use_utf) +{ + int units_per_cell = ceil (max_change / CHANGE_BAR_WIDTH); + static char const *ascii_boxes[8] = { + "****","***" ,"***", "**", + "**", "*", "*", "" + }; + static char const *utf_boxes[8] = { + "â–ˆ", "â–‰", "â–Š", "â–‹", + "â–Œ", "â–", "â–Ž", "â–" + }; + char const **boxes = use_utf ? utf_boxes : ascii_boxes; + + /* For a 1.0x speedup we want a zero-size bar to show "no + * change". */ + change -= 1.0; + + while (change > units_per_cell) { + printf ("%s", boxes[0]); + change -= units_per_cell; + } + + change /= units_per_cell; + + if (change > 7.5/8.0) + printf ("%s", boxes[0]); + else if (change > 6.5/8.0) + printf ("%s", boxes[1]); + else if (change > 5.5/8.0) + printf ("%s", boxes[2]); + else if (change > 4.5/8.0) + printf ("%s", boxes[3]); + else if (change > 3.5/8.0) + printf ("%s", boxes[4]); + else if (change > 2.5/8.0) + printf ("%s", boxes[5]); + else if (change > 1.5/8.0) + printf ("%s", boxes[6]); + else if (change > 0.5/8.0) + printf ("%s", boxes[7]); +} + +static void +test_diff_print (test_diff_t *diff, + double max_change, + cairo_perf_report_options_t *options) +{ + int i; + double test_time; + double change; + + if (diff->tests[0]->size != 0) { + printf ("(%s, size: %d)\n", + diff->tests[0]->name, + diff->tests[0]->size); + } else { + printf ("(%s)\n", diff->tests[0]->name); + } + + for (i = 0; i < diff->num_tests; i++) { + test_time = diff->tests[i]->stats.min_ticks; + test_time /= diff->tests[i]->stats.ticks_per_ms; + change = diff->max / test_time; + printf ("%8s-%s-%s\t%6.2f: %5.2fx ", + diff->tests[i]->backend, + diff->tests[i]->content, + diff->tests[i]->configuration, + diff->tests[i]->stats.min_ticks / diff->tests[i]->stats.ticks_per_ms, + change); + + if (options->print_change_bars) + print_change_bar (change, max_change, options->use_utf); + printf ("\n"); + } + + printf("\n"); +} + +static void +cairo_perf_reports_compare (cairo_perf_report_t *reports, + int num_reports, + cairo_perf_report_options_t *options) +{ + int i; + test_report_t **tests, *min_test; + test_diff_t *diff, *diffs; + int num_diffs, max_diffs; + double max_change; + double test_time; + int seen_non_null; + + tests = xmalloc (num_reports * sizeof (test_report_t *)); + + max_diffs = reports[0].tests_count; + for (i = 0; i < num_reports; i++) { + tests[i] = reports[i].tests; + if (reports[i].tests_count > max_diffs) + max_diffs = reports[i].tests_count; + } + + diff = diffs = xmalloc (max_diffs * sizeof (test_diff_t)); + + num_diffs = 0; + while (1) { + int num_tests; + + /* We expect iterations values of 0 when multiple raw reports + * for the same test have been condensed into the stats of the + * first. So we just skip these later reports that have no + * stats. */ + seen_non_null = 0; + for (i = 0; i < num_reports; i++) { + while (tests[i]->name && tests[i]->stats.iterations == 0) + tests[i]++; + if (tests[i]->name) + seen_non_null++; + } + if (! seen_non_null) + break; + + /* Find the minimum of all current tests, (we have to do this + * in case some reports don't have a particular test). */ + for (i = 0; i < num_reports; i++) { + if (tests[i]->name) { + min_test = tests[i]; + break; + } + } + for (++i; i < num_reports; i++) { + if (tests[i]->name && test_report_cmp_name (tests[i], min_test) < 0) + min_test = tests[i]; + } + + num_tests = 0; + for (i = 0; i < num_reports; i++) { + test_report_t *test; + int n = 0; + + test = tests[i]; + while (test[n].name && + test_report_cmp_name (&test[n], min_test) == 0) + { + n++; + } + + num_tests += n; + } + + /* For each report that has the current test, record it into + * the diff structure. */ + diff->num_tests = 0; + diff->tests = xmalloc (num_tests * sizeof (test_diff_t)); + for (i = 0; i < num_reports; i++) { + while (tests[i]->name && + test_report_cmp_name (tests[i], min_test) == 0) + { + test_time = tests[i]->stats.min_ticks; + if (test_time > 0) { + test_time /= tests[i]->stats.ticks_per_ms; + if (diff->num_tests == 0) { + diff->min = test_time; + diff->max = test_time; + } else { + if (test_time < diff->min) + diff->min = test_time; + if (test_time > diff->max) + diff->max = test_time; + } + diff->tests[diff->num_tests++] = tests[i]; + } + tests[i]++; + } + } + diff->change = diff->max / diff->min; + + diff++; + num_diffs++; + } + if (num_diffs == 0) + goto DONE; + + qsort (diffs, num_diffs, sizeof (test_diff_t), test_diff_cmp); + + max_change = 1.0; + for (i = 0; i < num_diffs; i++) { + if (fabs (diffs[i].change) > max_change) + max_change = fabs (diffs[i].change); + } + + for (i = 0; i < num_diffs; i++) { + diff = &diffs[i]; + + /* Discard as uninteresting a change which is less than the + * minimum change required, (default may be overridden on + * command-line). */ + if (fabs (diff->change) - 1.0 < options->min_change) + continue; + + test_diff_print (diff, max_change, options); + } + + for (i = 0; i < num_diffs; i++) + free (diffs[i].tests); + DONE: + free (diffs); + free (tests); +} + +static void +usage (const char *argv0) +{ + char const *basename = strrchr(argv0, '/'); + basename = basename ? basename+1 : argv0; + fprintf (stderr, + "Usage: %s [options] file [...]\n\n", + basename); + fprintf (stderr, + "Computes significant performance differences for cairo performance reports.\n" + "Each file should be the output of the cairo-perf program (or \"make perf\").\n" + "The following options are available:\n" + "\n" + "--no-utf Use ascii stars instead of utf-8 change bars.\n" + " Four stars are printed per factor of speedup.\n" + "\n" + "--no-bars Don't display change bars at all.\n\n" + "\n" + "--use-ms Use milliseconds to calculate differences.\n" + " (instead of ticks which are hardware dependent)\n" + "\n" + "--min-change threshold[%%]\n" + " Suppress all changes below the given threshold.\n" + " The default threshold of 0.05 or 5%% ignores any\n" + " speedup or slowdown of 1.05 or less. A threshold\n" + " of 0 will cause all output to be reported.\n" + ); + exit(1); +} + +static void +parse_args (int argc, + char const **argv, + cairo_perf_diff_files_args_t *args) +{ + int i; + + for (i = 1; i < argc; i++) { + if (strcmp (argv[i], "--no-utf") == 0) { + args->options.use_utf = 0; + } + else if (strcmp (argv[i], "--no-bars") == 0) { + args->options.print_change_bars = 0; + } + else if (strcmp (argv[i], "--min-change") == 0) { + char *end = NULL; + i++; + if (i >= argc) + usage (argv[0]); + args->options.min_change = strtod (argv[i], &end); + if (*end) { + if (*end == '%') { + args->options.min_change /= 100; + } else { + usage (argv[0]); + } + } + } + else { + args->num_filenames++; + args->filenames = xrealloc (args->filenames, + args->num_filenames * sizeof (char *)); + args->filenames[args->num_filenames - 1] = argv[i]; + } + } +} + +int +main (int argc, + const char *argv[]) +{ + cairo_perf_diff_files_args_t args = { + NULL, /* filenames */ + 0, /* num_filenames */ + { + 0.05, /* min change */ + 1, /* use UTF-8? */ + 1, /* display change bars? */ + } + }; + cairo_perf_report_t *reports; + test_report_t *t; + int i; + + parse_args (argc, argv, &args); + + if (args.num_filenames) { + reports = xcalloc (args.num_filenames, sizeof (cairo_perf_report_t)); + for (i = 0; i < args.num_filenames; i++) { + cairo_perf_report_load (&reports[i], args.filenames[i], i, + test_report_cmp_name); + printf ("loaded: %s, %d tests\n", + args.filenames[i], reports[i].tests_count); + } + } else { + args.num_filenames = 1; + reports = xcalloc (args.num_filenames, sizeof (cairo_perf_report_t)); + cairo_perf_report_load (&reports[0], NULL, 0, test_report_cmp_name); + } + + cairo_perf_reports_compare (reports, args.num_filenames, &args.options); + + /* Pointless memory cleanup, (would be a great place for talloc) */ + free (args.filenames); + for (i = 0; i < args.num_filenames; i++) { + for (t = reports[i].tests; t->name; t++) { + free (t->samples); + free (t->backend); + free (t->name); + } + free (reports[i].tests); + free (reports[i].configuration); + } + free (reports); + + return 0; +} diff --git a/local/recipes/libs/cairo/source/perf/cairo-perf-diff b/local/recipes/libs/cairo/source/perf/cairo-perf-diff new file mode 100755 index 0000000000..5a4b7b3869 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/cairo-perf-diff @@ -0,0 +1,255 @@ +#!/bin/sh +set -e + +usage() { + argv0=`basename $0` + + cat >&2 << END +Usage: +For comparing files created my cairo-perf: + + $argv0 old.perf new.perf + +For comparing (cached) performance of revisions: + + $argv0 [OPTIONS] [-- cairo-perf options] + $argv0 [OPTIONS] [-- cairo-perf-options] + +If given a single revision, compares its results to that of its +(first-parent) predecessor. Otherwise compares the two given revisions. +The revisions can be any revision accepted by git. For example: + + $argv0 HEAD # Show impact of latest commit + $argv0 1.2.0 1.2.4 # Compare performance of 1.2.0 to 1.2.4 + +Options: + +-f, --force + Forces cairo-perf-diff to re-run performance tests + even if cached performance data is available. + +-h, --html + With this option performance changes are summarized + as HTML table. + +-t, --trace + Compare performance using trace replays instead of + microbenchmarks. + +Additional options can be passed the child cairo-perf process +by separating them with a double hyphen (--). For example, to +examine what the impact of the latest change is on the stroke +test you might use: + + $argv0 HEAD -- stroke + +The performance results are cached in .perf next to the .git directory. + +Set CAIRO_AUTOGEN_OPTIONS to pass options to autogen for both +builds. +END + + exit 1 +} + +benchmark="cairo-perf-micro" + +# First, pull off any known options +while true; do + case $1 in + -f|--force) force_cairo_perf="true";; + -h|--html) html_output="$2"; shift ;; + -t|--trace) benchmark="cairo-perf-trace";; + *) break;; + esac + + shift +done + +# Then if anything is left that still looks like an option, (begins +# with a dash), give usage to catch --help or any other -garbage +if [ $# -eq 0 ] || [ "`echo "$1" | sed 's/^-//'`" != "$1" ]; then + usage +fi + +# Finally, pick up the actual revision arguments +if [ $# -eq 1 ] || [ "$2" = "--" ]; then + old="$1^" + new="$1" + shift 1 +else + old="$1" + new="$2" + shift 2 +fi + +# And post-finally, pass anything after -- on to cairo-perf +CAIRO_PERF_OPTIONS="-r -i 10" +if [ $# -gt 0 ]; then + if [ "$1" = "--" ]; then + shift 1 + CAIRO_PERF_OPTIONS="$CAIRO_PERF_OPTIONS $@" + else + usage + fi +fi + +git_setup() { + SUBDIRECTORY_OK='Yes' + . "$(git --exec-path)/git-sh-setup" + CAIRO_DIR=`dirname $GIT_DIR` + if [ "$CAIRO_DIR" = "." ]; then + CAIRO_DIR=`pwd` + fi + CAIRO_PERF_DIR=$CAIRO_DIR/.perf +} + +rev2sha() { + rev=$1 + git rev-parse --verify $rev || ( echo "Cannot resolve $rev as a git object" && exit 1 ) +} + +cpu_count() { + test -f /proc/cpuinfo && + grep -c '^processor[[:blank:]]\+:' /proc/cpuinfo || + echo 1 +} + +# We cache performance output based on a two-part name capturing the +# current performance test suite and the library being tested. We +# capture these as the tree object of the perf directory in HEAD and +# the tree object of the src directory of the revision being tested. +# +# This way, whenever the performance suite is updated, cached output +# from old versions of the suite are automatically invalidated. Also, +# if a commit just changes things outside of the src tree, (say it +# changes the "test" test suite, or README or configure.in, or +# whatever), cairo-perf-diff will be smart enough to still use cached +# results from a run with an equivalent src tree. +rev2perf() { + rev=$1 + sha=`rev2sha $rev` + src_tree_sha=`rev2sha $rev:src` + perf_tree_sha=`rev2sha HEAD:perf` + script_tree_sha=`rev2sha HEAD:util/cairo-script` + echo "$CAIRO_PERF_DIR/${sha}-${perf_tree_sha}-${script_tree_sha}-${src_tree_sha}.perf" +} +rev2perf_glob() { + rev=$1 + src_tree_sha=`rev2sha $rev:src` + perf_tree_sha=`rev2sha HEAD:perf` + script_tree_sha=`rev2sha HEAD:util/cairo-script` + echo "$CAIRO_PERF_DIR/*-${perf_tree_sha}-${script_tree_sha}-${src_tree_sha}.perf" +} + +build() { + build_dir=$1 + sha=$2 + + if [ ! -d $build_dir ]; then + git clone -s $CAIRO_DIR $build_dir + (cd $build_dir; git checkout -b tmp-cairo-perf-diff $sha) + fi + cd $build_dir + + git checkout tmp-cairo-perf-diff + git reset --hard $sha + + if [ -z "$MAKEFLAGS" ]; then + CPU_COUNT=`cpu_count` + export MAKEFLAGS="-j`expr $CPU_COUNT + 1`" + fi + + if [ ! -e Makefile ]; then + ./autogen.sh $CAIRO_AUTOGEN_OPTIONS + fi + + for file in $boilerplate_files; do + rsync $CAIRO_DIR/$file boilerplate + done + for file in $perf_files; do + rsync $CAIRO_DIR/$file perf + done + for file in $script_files; do + rsync $CAIRO_DIR/$file util/cairo-script + done + + make || (rm config.cache && make) + (cd boilerplate && make libcairoboilerplate.la) + + cd perf + make ${benchmark} +} + +# Usage: run_cairo_perf_if_not_cached +# The argument must be a valid git ref-spec that can +# be resolved to a commit. The suffix is just something +# unique so that build directories can be separated for +# multiple calls to this function. +run_cairo_perf_if_not_cached() { + rev=$1 + build_dir="build-$2" + + owd=`pwd` + sha=`rev2sha $rev` + perf=`rev2perf $rev` + glob=`rev2perf_glob $rev` + if [ -e $glob ] && [ "$force_cairo_perf" != "true" ]; then + return 0 + fi + if [ ! -d $CAIRO_PERF_DIR ]; then + echo "Creating new perf cache in $CAIRO_PERF_DIR" + mkdir $CAIRO_PERF_DIR + fi + + cd $CAIRO_DIR + boilerplate_files=`git ls-tree --name-only HEAD boilerplate/*` + perf_files=`git ls-tree --name-only HEAD perf/*` + script_files=`git ls-tree --name-only HEAD util/cairo-script/*` + cd $CAIRO_PERF_DIR + + build $build_dir $sha || { + rm -rf $build_dir + build $build_dir $sha || exit 1 + } + + echo "Running \"cairo-perf $CAIRO_PERF_OPTIONS\" against $rev. Results will be cached in:" + { ./$benchmark $CAIRO_PERF_OPTIONS || echo "*** Performance test crashed"; } >> $perf + + cd $owd +} + +git_setup + +if [ -e ./cairo-perf-diff-files ]; then + bindir="." +else + bindir=$CAIRO_DIR/perf + + # Build cairo-perf-diff-files if not available + if [ ! -e $bindir/cairo-perf-diff-files ]; then + echo "Building cairo-perf-diff-files" + if [ "x$OS" = "xWindows_NT" ]; then + make -f Makefile.win32 -C $bindir cairo-perf-diff-files CFG=debug + else + make -C $bindir cairo-perf-diff-files + fi + fi +fi + +if [ ! -e $old ]; then + run_cairo_perf_if_not_cached $old old + old=`rev2perf $old` +fi + +if [ ! -e $new ]; then + run_cairo_perf_if_not_cached $new new + new=`rev2perf $new` +fi + +if [ -z "$html_output" ]; then + $bindir/cairo-perf-diff-files $old $new +else + $bindir/cairo-perf-diff-files $old $new | + $CAIRO_DIR/perf/make-html.py > $html_output +fi diff --git a/local/recipes/libs/cairo/source/perf/cairo-perf-diff-files.c b/local/recipes/libs/cairo/source/perf/cairo-perf-diff-files.c new file mode 100644 index 0000000000..4d3ff7a678 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/cairo-perf-diff-files.c @@ -0,0 +1,506 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of the + * copyright holders not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * + * Authors: Carl Worth + */ + +#include "cairo-perf.h" + +#include +#include +#include +#include +#include +#include +#include + +typedef struct _cairo_perf_report_options { + double min_change; + int use_utf; + int print_change_bars; + int use_ticks; +} cairo_perf_report_options_t; + +typedef struct _cairo_perf_diff_files_args { + const char **filenames; + int num_filenames; + cairo_perf_report_options_t options; +} cairo_perf_diff_files_args_t; + +static int +test_diff_cmp_speedup_before_slowdown (const void *a, + const void *b) +{ + const test_diff_t *a_diff = a; + const test_diff_t *b_diff = b; + + /* First make all speedups come before all slowdowns. */ + if (a_diff->change > 0 && b_diff->change < 0) + return -1; + if (a_diff->change < 0 && b_diff->change > 0) + return 1; + + if (a_diff->change == b_diff->change) + return 0; + + /* Large speedups come first. */ + if (a_diff->change > 0) { + if (a_diff->change > b_diff->change) + return -1; + else + return 1; + } + + /* Large slowdowns come last. */ + if (a_diff->change < 0) { + if (a_diff->change < b_diff->change) + return 1; + else + return -1; + } + + return 0; +} + +static int +test_diff_cmp (const void *a, + const void *b) +{ + const test_diff_t *a_diff = a; + const test_diff_t *b_diff = b; + + /* Reverse sort by magnitude of change so larger changes come + * first */ + if (a_diff->change > b_diff->change) + return -1; + + if (a_diff->change < b_diff->change) + return 1; + + return 0; +} + +#define CHANGE_BAR_WIDTH 70 +static void +print_change_bar (double change, + double max_change, + int use_utf) +{ + int units_per_cell = ceil (max_change / CHANGE_BAR_WIDTH); + static char const *ascii_boxes[8] = { + "****","***" ,"***", "**", + "**", "*", "*", "" + }; + static char const *utf_boxes[8] = { + "â–ˆ", "â–‰", "â–Š", "â–‹", + "â–Œ", "â–", "â–Ž", "â–" + }; + char const **boxes = use_utf ? utf_boxes : ascii_boxes; + + /* For a 1.0x speedup we want a zero-size bar to show "no + * change". */ + change -= 1.0; + + while (change > units_per_cell) { + printf ("%s", boxes[0]); + change -= units_per_cell; + } + + change /= units_per_cell; + + if (change > 7.5/8.0) + printf ("%s", boxes[0]); + else if (change > 6.5/8.0) + printf ("%s", boxes[1]); + else if (change > 5.5/8.0) + printf ("%s", boxes[2]); + else if (change > 4.5/8.0) + printf ("%s", boxes[3]); + else if (change > 3.5/8.0) + printf ("%s", boxes[4]); + else if (change > 2.5/8.0) + printf ("%s", boxes[5]); + else if (change > 1.5/8.0) + printf ("%s", boxes[6]); + else if (change > 0.5/8.0) + printf ("%s", boxes[7]); + + printf ("\n"); +} + +static void +test_diff_print_binary (test_diff_t *diff, + double max_change, + cairo_perf_report_options_t *options) +{ + if (diff->tests[0]->size) + printf ("%5s-%-4s %26s-%-3d", + diff->tests[0]->backend, diff->tests[0]->content, + diff->tests[0]->name, diff->tests[0]->size); + else + printf ("%5s %26s", diff->tests[0]->backend, diff->tests[0]->name); + + printf (" %6.2f (%.2f %4.2f%%) -> %6.2f (%.2f %4.2f%%): %5.2fx ", + diff->tests[0]->stats.min_ticks / diff->tests[0]->stats.ticks_per_ms, + diff->tests[0]->stats.median_ticks / diff->tests[0]->stats.ticks_per_ms, + diff->tests[0]->stats.std_dev * 100, + diff->tests[1]->stats.min_ticks / diff->tests[1]->stats.ticks_per_ms, + diff->tests[1]->stats.median_ticks / diff->tests[1]->stats.ticks_per_ms, + diff->tests[1]->stats.std_dev * 100, + fabs (diff->change)); + + if (diff->change > 1.0) + printf ("speedup\n"); + else + printf ("slowdown\n"); + + if (options->print_change_bars) + print_change_bar (fabs (diff->change), max_change, + options->use_utf); +} + +static void +test_diff_print_multi (test_diff_t *diff, + double max_change, + cairo_perf_report_options_t *options) +{ + int i; + double test_time; + double change; + + if (diff->tests[0]->size) { + printf ("%s (backend: %s-%s, size: %d)\n", + diff->tests[0]->name, + diff->tests[0]->backend, + diff->tests[0]->content, + diff->tests[0]->size); + } else { + printf ("%s (backend: %s)\n", + diff->tests[0]->name, + diff->tests[0]->backend); + } + + for (i = 0; i < diff->num_tests; i++) { + test_time = diff->tests[i]->stats.min_ticks; + if (! options->use_ticks) + test_time /= diff->tests[i]->stats.ticks_per_ms; + change = diff->max / test_time; + printf ("[%d] %6.2f: %5.2fx ", + diff->tests[i]->fileno, + diff->tests[i]->stats.min_ticks / diff->tests[i]->stats.ticks_per_ms, + change); + + if (options->print_change_bars) + print_change_bar (change, max_change, options->use_utf); + else + printf("\n"); + } + + printf("\n"); +} + +static void +cairo_perf_reports_compare (cairo_perf_report_t *reports, + int num_reports, + cairo_perf_report_options_t *options) +{ + int i; + test_report_t **tests, *min_test; + test_diff_t *diff, *diffs; + int num_diffs, max_diffs; + double max_change; + double test_time; + int seen_non_null; + cairo_bool_t printed_speedup = FALSE; + cairo_bool_t printed_slowdown = FALSE; + + assert (num_reports >= 2); + + tests = xmalloc (num_reports * sizeof (test_report_t *)); + + max_diffs = reports[0].tests_count; + for (i = 0; i < num_reports; i++) { + tests[i] = reports[i].tests; + if (reports[i].tests_count > max_diffs) + max_diffs = reports[i].tests_count; + } + + diff = diffs = xmalloc (max_diffs * sizeof (test_diff_t)); + + num_diffs = 0; + while (1) { + /* We expect iterations values of 0 when multiple raw reports + * for the same test have been condensed into the stats of the + * first. So we just skip these later reports that have no + * stats. */ + seen_non_null = 0; + for (i = 0; i < num_reports; i++) { + while (tests[i]->name && tests[i]->stats.iterations == 0) + tests[i]++; + if (tests[i]->name) + seen_non_null++; + } + + if (seen_non_null < 2) + break; + + /* Find the minimum of all current tests, (we have to do this + * in case some reports don't have a particular test). */ + for (i = 0; i < num_reports; i++) { + if (tests[i]->name) { + min_test = tests[i]; + break; + } + } + for (++i; i < num_reports; i++) { + if (tests[i]->name && + test_report_cmp_backend_then_name (tests[i], min_test) < 0) + { + min_test = tests[i]; + } + } + + /* For each report that has the current test, record it into + * the diff structure. */ + diff->num_tests = 0; + diff->tests = xmalloc (num_reports * sizeof (test_diff_t)); + for (i = 0; i < num_reports; i++) { + if (tests[i]->name && + test_report_cmp_backend_then_name (tests[i], min_test) == 0) + { + test_time = tests[i]->stats.min_ticks; + if (! options->use_ticks) + test_time /= tests[i]->stats.ticks_per_ms; + if (diff->num_tests == 0) { + diff->min = test_time; + diff->max = test_time; + } else { + if (test_time < diff->min) + diff->min = test_time; + if (test_time > diff->max) + diff->max = test_time; + } + diff->tests[diff->num_tests++] = tests[i]; + tests[i]++; + } + } + diff->change = diff->max / diff->min; + + if (num_reports == 2) { + double old_time, new_time; + if (diff->num_tests == 1) { + printf ("Only in %s: %s %s\n", + diff->tests[0]->configuration, + diff->tests[0]->backend, + diff->tests[0]->name); + continue; + } + old_time = diff->tests[0]->stats.min_ticks; + new_time = diff->tests[1]->stats.min_ticks; + if (! options->use_ticks) { + old_time /= diff->tests[0]->stats.ticks_per_ms; + new_time /= diff->tests[1]->stats.ticks_per_ms; + } + diff->change = old_time / new_time; + if (diff->change < 1.0) + diff->change = - 1.0 / diff->change; + } + + diff++; + num_diffs++; + } + if (num_diffs == 0) + goto DONE; + + if (num_reports == 2) + qsort (diffs, num_diffs, sizeof (test_diff_t), + test_diff_cmp_speedup_before_slowdown); + else + qsort (diffs, num_diffs, sizeof (test_diff_t), test_diff_cmp); + + max_change = 1.0; + for (i = 0; i < num_diffs; i++) { + if (fabs (diffs[i].change) > max_change) + max_change = fabs (diffs[i].change); + } + + if (num_reports == 2) + printf ("old: %s\n" + "new: %s\n", + diffs->tests[0]->configuration, + diffs->tests[1]->configuration); + + for (i = 0; i < num_diffs; i++) { + diff = &diffs[i]; + + /* Discard as uninteresting a change which is less than the + * minimum change required, (default may be overridden on + * command-line). */ + if (fabs (diff->change) - 1.0 < options->min_change) + continue; + + if (num_reports == 2) { + if (diff->change > 1.0 && ! printed_speedup) { + printf ("Speedups\n" + "========\n"); + printed_speedup = TRUE; + } + if (diff->change < 1.0 && ! printed_slowdown) { + printf ("Slowdowns\n" + "=========\n"); + printed_slowdown = TRUE; + } + test_diff_print_binary (diff, max_change, options); + } else { + test_diff_print_multi (diff, max_change, options); + } + } + + DONE: + for (i = 0; i < num_diffs; i++) + free (diffs[i].tests); + free (diffs); + free (tests); +} + +static void +usage (const char *argv0) +{ + char const *basename = strrchr(argv0, '/'); + basename = basename ? basename+1 : argv0; + fprintf (stderr, + "Usage: %s [options] file1 file2 [...]\n\n", + basename); + fprintf (stderr, + "Computes significant performance differences for cairo performance reports.\n" + "Each file should be the output of the cairo-perf program (or \"make perf\").\n" + "The following options are available:\n" + "\n" + "--no-utf Use ascii stars instead of utf-8 change bars.\n" + " Four stars are printed per factor of speedup.\n" + "\n" + "--no-bars Don't display change bars at all.\n\n" + "\n" + "--use-ms Use milliseconds to calculate differences.\n" + " (instead of ticks which are hardware dependent)\n" + "\n" + "--min-change threshold[%%]\n" + " Suppress all changes below the given threshold.\n" + " The default threshold of 0.05 or 5%% ignores any\n" + " speedup or slowdown of 1.05 or less. A threshold\n" + " of 0 will cause all output to be reported.\n" + ); + exit(1); +} + +static void +parse_args (int argc, + char const **argv, + cairo_perf_diff_files_args_t *args) +{ + int i; + + for (i = 1; i < argc; i++) { + if (strcmp (argv[i], "--no-utf") == 0) { + args->options.use_utf = 0; + } + else if (strcmp (argv[i], "--no-bars") == 0) { + args->options.print_change_bars = 0; + } + else if (strcmp (argv[i], "--use-ms") == 0) { + /* default */ + } + else if (strcmp (argv[i], "--use-ticks") == 0) { + args->options.use_ticks = 1; + } + else if (strcmp (argv[i], "--min-change") == 0) { + char *end = NULL; + i++; + if (i >= argc) + usage (argv[0]); + args->options.min_change = strtod (argv[i], &end); + if (*end) { + if (*end == '%') { + args->options.min_change /= 100; + } else { + usage (argv[0]); + } + } + } + else { + args->num_filenames++; + args->filenames = xrealloc (args->filenames, + args->num_filenames * sizeof (char *)); + args->filenames[args->num_filenames - 1] = argv[i]; + } + } +} + +int +main (int argc, + const char *argv[]) +{ + cairo_perf_diff_files_args_t args = { + NULL, /* filenames */ + 0, /* num_filenames */ + { + 0.05, /* min change */ + 1, /* use UTF-8? */ + 1, /* display change bars? */ + } + }; + cairo_perf_report_t *reports; + test_report_t *t; + int i; + + parse_args (argc, argv, &args); + + if (args.num_filenames < 2) + usage (argv[0]); + + reports = xmalloc (args.num_filenames * sizeof (cairo_perf_report_t)); + + for (i = 0; i < args.num_filenames; i++ ) { + cairo_perf_report_load (&reports[i], args.filenames[i], i, NULL); + printf ("[%d] %s\n", i, args.filenames[i]); + } + printf ("\n"); + + cairo_perf_reports_compare (reports, args.num_filenames, &args.options); + + /* Pointless memory cleanup, (would be a great place for talloc) */ + free (args.filenames); + for (i = 0; i < args.num_filenames; i++) { + for (t = reports[i].tests; t->name; t++) { + free (t->samples); + free (t->backend); + free (t->name); + } + free (reports[i].tests); + free (reports[i].configuration); + } + free (reports); + + return 0; +} diff --git a/local/recipes/libs/cairo/source/perf/cairo-perf-graph b/local/recipes/libs/cairo/source/perf/cairo-perf-graph new file mode 100755 index 0000000000..a167351fc3 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/cairo-perf-graph @@ -0,0 +1,206 @@ +#!/bin/sh +set -e + +### +### XXX Source common functions from cairo-perf-diff +### + +usage() { + argv0=`basename $0` + + cat >&2 << END +Usage: +As opposed to its sibling, cairo-perf-diff, cairo-perf-graph targets +reviewing changes between series by graphically comparing the performance +at each commit. + +The two revisions can be any revision accepted by git. For example: + + $argv0 1.2.0 1.2.4 # Compare performance of 1.2.0 to 1.2.4 + +Options: + +-f, --force + Forces cairo-perf-diff to re-run performance tests + even if cached performance data is available. + +-h, --html + With this option performance changes are summarized + as HTML table. + +Additional options can be passed the child cairo-perf process +by separating them with a double hyphen (--). For example, to +examine what the impact of the latest change is on the stroke +test you might use: + + $argv0 HEAD -- stroke + +The performance results are cached in .perf next to the .git directory. + +Set CAIRO_AUTOGEN_OPTIONS to pass options to autogen for both +builds. +END + + exit 1 +} + +# First, pull off any known options +while true; do + case $1 in + -f|--force) force_cairo_perf="true";; + -h|--html) html_output="true";; + -s|--show) show_only="true";; + *) break;; + esac + + shift +done + +# Then if anything is left that still looks like an option, (begins +# with a dash), give usage to catch --help or any other -garbage +if [ $# -eq 0 ] || [ "`echo "$1" | sed 's/^-//'`" != "$1" ]; then + usage +fi + +# Finally, pick up the actual revision arguments +old="$1" +new="$2" +shift 2 + +# And post-finally, pass anything after -- on to cairo-perf +CAIRO_PERF_OPTIONS="-r -i 25" +if [ $# -gt 0 ]; then + if [ "$1" = "--" ]; then + shift 1 + CAIRO_PERF_OPTIONS="$CAIRO_PERF_OPTIONS $@" + else + usage + fi +fi + +git_setup() { + SUBDIRECTORY_OK='Yes' + . "$(git --exec-path)/git-sh-setup" + CAIRO_DIR=`dirname $GIT_DIR` + if [ "$CAIRO_DIR" = "." ]; then + CAIRO_DIR=`pwd` + fi + CAIRO_PERF_DIR=$CAIRO_DIR/.perf +} + +rev2sha() { + rev=$1 + git rev-parse --verify $rev || ( echo "Cannot resolve $rev as a git object" && exit 1 ) +} + +cpu_count() { + test -f /proc/cpuinfo && + grep -c '^processor[[:blank:]]\+:' /proc/cpuinfo || + echo 1 +} + +# We cache performance output based on a two-part name capturing the +# current performance test suite and the library being tested. We +# capture these as the tree object of the perf directory in HEAD and +# the tree object of the src directory of the revision being tested. +# +# This way, whenever the performance suite is updated, cached output +# from old versions of the suite are automatically invalidated. Also, +# if a commit just changes things outside of the src tree, (say it +# changes the "test" test suite, or README or configure.in, or +# whatever), cairo-perf-diff will be smart enough to still use cached +# results from a run with an equivalent src tree. +rev2perf() { + rev=$1 + sha=`rev2sha $rev` + src_tree_sha=`rev2sha $rev:src` + perf_tree_sha=`rev2sha HEAD:perf` + echo "$CAIRO_PERF_DIR/${sha}-${perf_tree_sha}-${src_tree_sha}.perf" +} +rev2perf_glob() { + rev=$1 + src_tree_sha=`rev2sha $rev:src` + perf_tree_sha=`rev2sha HEAD:perf` + echo "$CAIRO_PERF_DIR/*-${perf_tree_sha}-${src_tree_sha}.perf" +} + +# Usage: run_cairo_perf_if_not_cached +# The argument must be a valid git ref-spec that can +# be resolved to a commit. The suffix is just something +# unique so that build directories can be separated for +# multiple calls to this function. +run_cairo_perf_if_not_cached() { + rev=$1 + build_dir="build-$2" + + owd=`pwd` + sha=`rev2sha $rev` + perf=`rev2perf $rev` + glob=`rev2perf_glob $rev` + if [ -e $glob ] && [ "$force_cairo_perf" != "true" ] || [ -n "$show_only" ]; then + return 0 + fi + if [ ! -d $CAIRO_PERF_DIR ]; then + echo "Creating new perf cache in $CAIRO_PERF_DIR" + mkdir $CAIRO_PERF_DIR + fi + + cd $CAIRO_DIR + boilerplate_files=`git ls-tree --name-only HEAD boilerplate/*` + perf_files=`git ls-tree --name-only HEAD perf/*` + cd $CAIRO_PERF_DIR + + if [ ! -d $build_dir ]; then + git clone -s $CAIRO_DIR $build_dir + (cd $build_dir; git checkout -b tmp-cairo-perf-diff $sha) + fi + cd $build_dir + + git checkout tmp-cairo-perf-diff + git reset --hard $sha + + if [ -z "$MAKEFLAGS" ]; then + CPU_COUNT=`cpu_count` + export MAKEFLAGS="-j`expr $CPU_COUNT + 1`" + fi + + if [ ! -e Makefile ]; then + CFLAGS="-O2" ./autogen.sh $CAIRO_AUTOGEN_OPTIONS + fi + make CFLAGS="-O2" || (rm config.cache && make CFLAGS="-O2") + for file in $boilerplate_files; do + rsync $CAIRO_DIR/$file boilerplate + done + (cd boilerplate; make) + for file in $perf_files; do + rsync $CAIRO_DIR/$file perf + done + cd perf; + make cairo-perf || exit 1 + echo "Running \"cairo-perf $CAIRO_PERF_OPTIONS\" against $rev. Results will be cached in:" + echo "$perf" + (./cairo-perf $CAIRO_PERF_OPTIONS || echo "*** Performance test crashed") >> $perf + cd $owd +} + +git_setup + +# Build cairo-perf-graph-files if not available +if [ ! -e $CAIRO_DIR/perf/cairo-perf-graph-files ]; then + echo "Building cairo-perf-graph-files" + if [ "x$OS" = "xWindows_NT" ]; then + make -f Makefile.win32 -C $CAIRO_DIR/perf/ cairo-perf-graph-files CFG=debug + else + make -C $CAIRO_DIR/perf/ cairo-perf-graph-files + fi +fi + +revs="" +for rev in `git rev-list --reverse $old..$new`; do + run_cairo_perf_if_not_cached $rev rev + perf=`rev2perf $rev` + [ -e "$perf" ] && revs="$revs $perf" +done + +exec $CAIRO_DIR/perf/cairo-perf-graph-files $revs +#exec $CAIRO_DIR/libtool --mode=execute gdb --args $CAIRO_DIR/perf/cairo-perf-graph-files $revs diff --git a/local/recipes/libs/cairo/source/perf/cairo-perf-graph-files.c b/local/recipes/libs/cairo/source/perf/cairo-perf-graph-files.c new file mode 100644 index 0000000000..9a2a325e63 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/cairo-perf-graph-files.c @@ -0,0 +1,617 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of the + * copyright holders not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * + * Authors: Chris Wilson + */ + +#define GLIB_DISABLE_DEPRECATION_WARNINGS + +#include "cairo-perf.h" +#include "cairo-perf-graph.h" + +#include +#include +#include + +#ifdef G_OS_UNIX +#include +#include +#endif + +#include + +static void +usage (const char *argv0) +{ + char const *basename = strrchr (argv0, '/'); + basename = basename ? basename+1 : argv0; + g_printerr ("Usage: %s [options] file1 file2 [...]\n\n", basename); + g_printerr ("Draws a graph illustrating the change in performance over a series.\n"); + exit(1); +} + +enum { + CASE_SHOWN, + CASE_INCONSISTENT, + CASE_BACKEND, + CASE_CONTENT, + CASE_NAME, + CASE_SIZE, + CASE_FG_COLOR, + CASE_DATA, + CASE_NCOLS +}; + +static GtkTreeStore * +cases_to_store (test_case_t *cases) +{ + GtkTreeStore *store; + GtkTreeIter backend_iter; + GtkTreeIter content_iter; + const char *backend = NULL; + const char *content = NULL; + + store = gtk_tree_store_new (CASE_NCOLS, + G_TYPE_BOOLEAN, /* shown */ + G_TYPE_BOOLEAN, /* inconsistent */ + G_TYPE_STRING, /* backend */ + G_TYPE_STRING, /* content */ + G_TYPE_STRING, /* name */ + G_TYPE_INT, /* size */ + GDK_TYPE_COLOR, /* fg color */ + G_TYPE_POINTER); /* data */ + while (cases->backend != NULL) { + GtkTreeIter iter; + + if (backend == NULL || strcmp (backend, cases->backend)) { + gtk_tree_store_append (store, &backend_iter, NULL); + gtk_tree_store_set (store, &backend_iter, + CASE_SHOWN, TRUE, + CASE_BACKEND, cases->backend, + -1); + backend = cases->backend; + content = NULL; + } + if (content == NULL || strcmp (content, cases->content)) { + gtk_tree_store_append (store, &content_iter, &backend_iter); + gtk_tree_store_set (store, &content_iter, + CASE_SHOWN, TRUE, + CASE_BACKEND, cases->backend, + CASE_CONTENT, cases->content, + -1); + content = cases->content; + } + + gtk_tree_store_append (store, &iter, &content_iter); + gtk_tree_store_set (store, &iter, + CASE_SHOWN, TRUE, + CASE_BACKEND, cases->backend, + CASE_CONTENT, cases->content, + CASE_NAME, cases->name, + CASE_SIZE, cases->size, + CASE_FG_COLOR, &cases->color, + CASE_DATA, cases, + -1); + cases++; + } + + return store; +} + +struct _app_data { + GtkWidget *window; + + test_case_t *cases; + cairo_perf_report_t *reports; + int num_reports; + + GtkTreeStore *case_store; + + GIOChannel *git_io; + GtkTextBuffer *git_buffer; + + GtkWidget *gv; +}; + +static void +recurse_set_shown (GtkTreeModel *model, + GtkTreeIter *parent, + gboolean shown) +{ + GtkTreeIter iter; + + if (gtk_tree_model_iter_children (model, &iter, parent)) do { + test_case_t *c; + + gtk_tree_model_get (model, &iter, CASE_DATA, &c, -1); + if (c == NULL) { + recurse_set_shown (model, &iter, shown); + } else if (shown != c->shown) { + c->shown = shown; + gtk_tree_store_set (GTK_TREE_STORE (model), &iter, + CASE_SHOWN, shown, + CASE_INCONSISTENT, FALSE, + -1); + } + } while (gtk_tree_model_iter_next (model, &iter)); +} + +static gboolean +children_consistent (GtkTreeModel *model, + GtkTreeIter *parent) +{ + GtkTreeIter iter; + gboolean first = TRUE; + gboolean first_active; + + if (gtk_tree_model_iter_children (model, &iter, parent)) do { + gboolean active, inconsistent; + + gtk_tree_model_get (model, &iter, + CASE_INCONSISTENT, &inconsistent, + CASE_SHOWN, &active, + -1); + if (inconsistent) + return FALSE; + + if (first) { + first_active = active; + first = FALSE; + } else if (active != first_active) + return FALSE; + } while (gtk_tree_model_iter_next (model, &iter)); + + return TRUE; +} + +static void +check_consistent (GtkTreeModel *model, + GtkTreeIter *child) +{ + GtkTreeIter parent; + + if (gtk_tree_model_iter_parent (model, &parent, child)) { + gtk_tree_store_set (GTK_TREE_STORE (model), &parent, + CASE_INCONSISTENT, + ! children_consistent (model, &parent), + -1); + check_consistent (model, &parent); + } +} + +static void +show_case_toggled (GtkCellRendererToggle *cell, + gchar *str, + struct _app_data *app) +{ + GtkTreeModel *model; + GtkTreePath *path; + GtkTreeIter iter; + test_case_t *c; + gboolean active; + + active = ! gtk_cell_renderer_toggle_get_active (cell); + + model = GTK_TREE_MODEL (app->case_store); + + path = gtk_tree_path_new_from_string (str); + gtk_tree_model_get_iter (model, &iter, path); + gtk_tree_path_free (path); + + gtk_tree_store_set (app->case_store, &iter, + CASE_SHOWN, active, + CASE_INCONSISTENT, FALSE, + -1); + gtk_tree_model_get (model, &iter, CASE_DATA, &c, -1); + if (c != NULL) { + if (active == c->shown) + return; + + c->shown = active; + } else { + recurse_set_shown (model, &iter, active); + } + check_consistent (model, &iter); + + graph_view_update_visible ((GraphView *) app->gv); +} + +#ifdef G_OS_UNIX + +static gboolean +git_read (GIOChannel *io, + GIOCondition cond, + struct _app_data *app) +{ + int fd; + + fd = g_io_channel_unix_get_fd (io); + do { + char buf[4096]; + int len; + GtkTextIter end; + + len = read (fd, buf, sizeof (buf)); + if (len <= 0) { + int err = len ? errno : 0; + switch (err) { + case EAGAIN: + case EINTR: + return TRUE; + default: + g_io_channel_unref (app->git_io); + app->git_io = NULL; + return FALSE; + } + } + + gtk_text_buffer_get_end_iter (app->git_buffer, &end); + gtk_text_buffer_insert (app->git_buffer, &end, buf, len); + } while (TRUE); +} + +static void +do_git (struct _app_data *app, + char **argv) +{ + gint output; + GError *error = NULL; + GtkTextIter start, stop; + long flags; + + if (! g_spawn_async_with_pipes (NULL, argv, NULL, + G_SPAWN_SEARCH_PATH | + G_SPAWN_STDERR_TO_DEV_NULL | + G_SPAWN_FILE_AND_ARGV_ZERO, + NULL, NULL, NULL, + NULL, &output, NULL, + &error)) + { + g_error ("spawn failed: %s", error->message); + } + + if (app->git_io) { + g_io_channel_shutdown (app->git_io, FALSE, NULL); + g_io_channel_unref (app->git_io); + } + + gtk_text_buffer_get_bounds (app->git_buffer, &start, &stop); + gtk_text_buffer_delete (app->git_buffer, &start, &stop); + + flags = fcntl (output, F_GETFL); + if ((flags & O_NONBLOCK) == 0) + fcntl (output, F_SETFL, flags | O_NONBLOCK); + + app->git_io = g_io_channel_unix_new (output); + g_io_add_watch (app->git_io, G_IO_IN | G_IO_HUP, (GIOFunc) git_read, app); +} + +#endif + +static void +gv_report_selected (GraphView *gv, + int i, + struct _app_data *app) +{ + cairo_perf_report_t *report; + char *hyphen; + + if (i == -1) + return; + + report = &app->reports[i]; + hyphen = strchr (report->configuration, '-'); + if (hyphen != NULL) { + int len = hyphen - report->configuration; + char *id = g_malloc (len + 1); + char *argv[5]; + + memcpy (id, report->configuration, len); + id[len] = '\0'; + + argv[0] = (char *) "git"; + argv[1] = (char *) "git"; + argv[2] = (char *) "show"; + argv[3] = id; + argv[4] = NULL; + +#ifdef G_OS_UNIX + do_git (app, argv); +#else + g_print ("id: %s\n", id); +#endif + g_free (id); + } +} + +static GtkWidget * +window_create (test_case_t *cases, + cairo_perf_report_t *reports, + int num_reports) +{ + GtkWidget *window, *table, *w; + GtkWidget *tv, *sw; + GtkTreeStore *store; + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; + struct _app_data *data; + + + data = g_new0 (struct _app_data, 1); + data->cases = cases; + data->reports = reports; + data->num_reports = num_reports; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (window), "Cairo Performance Graph"); + g_object_set_data_full (G_OBJECT (window), + "app-data", data, (GDestroyNotify)g_free); + + data->window = window; + + table = gtk_table_new (2, 2, FALSE); + + /* legend & show/hide lines (categorised) */ + tv = gtk_tree_view_new (); + store = cases_to_store (cases); + data->case_store = store; + gtk_tree_view_set_model (GTK_TREE_VIEW (tv), GTK_TREE_MODEL (store)); + + renderer = gtk_cell_renderer_toggle_new (); + column = gtk_tree_view_column_new_with_attributes (NULL, + renderer, + "active", CASE_SHOWN, + "inconsistent", CASE_INCONSISTENT, + NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (tv), column); + g_signal_connect (renderer, "toggled", + G_CALLBACK (show_case_toggled), data); + + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes ("Backend", + renderer, + "text", CASE_BACKEND, + NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (tv), column); + + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes ("Content", + renderer, + "text", CASE_CONTENT, + NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (tv), column); + + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes ("Test", + renderer, + "text", CASE_NAME, + "foreground-gdk", CASE_FG_COLOR, + NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (tv), column); + + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes ("Size", + renderer, + "text", CASE_SIZE, + NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (tv), column); + + gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (tv), TRUE); + g_object_unref (store); + + sw = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), + GTK_POLICY_NEVER, + GTK_POLICY_AUTOMATIC); + gtk_container_add (GTK_CONTAINER (sw), tv); + gtk_widget_show (tv); + gtk_table_attach (GTK_TABLE (table), sw, + 0, 1, 0, 2, + GTK_FILL, GTK_FILL, + 4, 4); + gtk_widget_show (sw); + + /* the performance chart */ + w = graph_view_new (); + data->gv = w; + g_signal_connect (w, "report-selected", + G_CALLBACK (gv_report_selected), data); + graph_view_set_reports ((GraphView *)w, cases, reports, num_reports); + gtk_table_attach (GTK_TABLE (table), w, + 1, 2, 0, 1, + GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, + 4, 4); + gtk_widget_show (w); + + /* interesting information - presumably the commit log */ + w = gtk_text_view_new (); + data->git_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (w)); + sw = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), + GTK_POLICY_NEVER, + GTK_POLICY_AUTOMATIC); + gtk_container_add (GTK_CONTAINER (sw), w); + gtk_widget_show (w); + gtk_table_attach (GTK_TABLE (table), sw, + 1, 2, 1, 2, + GTK_FILL, GTK_FILL | GTK_EXPAND, + 4, 4); + gtk_widget_show (sw); + + gtk_container_add (GTK_CONTAINER (window), table); + gtk_widget_show (table); + + return window; +} + +static void +name_to_color (const char *name, + GdkColor *color) +{ + gint v = g_str_hash (name); + + color->red = ((v >> 0) & 0xff) / 384. * 0xffff; + color->green = ((v >> 8) & 0xff) / 384. * 0xffff; + color->blue = ((v >> 16) & 0xff) / 384. * 0xffff; +} + +static test_case_t * +test_cases_from_reports (cairo_perf_report_t *reports, + int num_reports) +{ + test_case_t *cases, *c; + test_report_t **tests; + int i, j; + int num_tests; + + num_tests = 0; + for (i = 0; i < num_reports; i++) { + for (j = 0; reports[i].tests[j].name != NULL; j++) + ; + if (j > num_tests) + num_tests = j; + } + + cases = xcalloc (num_tests+1, sizeof (test_case_t)); + tests = xmalloc (num_reports * sizeof (test_report_t *)); + for (i = 0; i < num_reports; i++) + tests[i] = reports[i].tests; + + c = cases; + while (1) { + int seen_non_null; + test_report_t *min_test; + + /* We expect iterations values of 0 when multiple raw reports + * for the same test have been condensed into the stats of the + * first. So we just skip these later reports that have no + * stats. */ + seen_non_null = 0; + for (i = 0; i < num_reports; i++) { + while (tests[i]->name && tests[i]->stats.iterations == 0) + tests[i]++; + if (tests[i]->name) + seen_non_null++; + } + + if (seen_non_null < 2) + break; + + /* Find the minimum of all current tests, (we have to do this + * in case some reports don't have a particular test). */ + for (i = 0; i < num_reports; i++) { + if (tests[i]->name) { + min_test = tests[i]; + break; + } + } + for (++i; i < num_reports; i++) { + if (tests[i]->name && + test_report_cmp_backend_then_name (tests[i], min_test) < 0) + { + min_test = tests[i]; + } + } + + c->min_test = min_test; + c->backend = min_test->backend; + c->content = min_test->content; + c->name = min_test->name; + c->size = min_test->size; + c->baseline = min_test->stats.min_ticks; + c->min = c->max = 1.; + c->shown = TRUE; + name_to_color (c->name, &c->color); + + for (i = 0; i < num_reports; i++) { + if (tests[i]->name && + test_report_cmp_backend_then_name (tests[i], min_test) == 0) + { + tests[i]++; + break; + } + } + + for (++i; i < num_reports; i++) { + if (tests[i]->name && + test_report_cmp_backend_then_name (tests[i], min_test) == 0) + { + double v = tests[i]->stats.min_ticks / c->baseline; + if (v < c->min) + c->min = v; + if (v > c->max) + c->max = v; + tests[i]++; + } + } + + c++; + } + free (tests); + + return cases; +} +int +main (int argc, + char *argv[]) +{ + cairo_perf_report_t *reports; + test_case_t *cases; + test_report_t *t; + int i; + GtkWidget *window; + + gtk_init (&argc, &argv); + + if (argc < 3) + usage (argv[0]); + + reports = xmalloc ((argc-1) * sizeof (cairo_perf_report_t)); + for (i = 1; i < argc; i++ ) + cairo_perf_report_load (&reports[i-1], argv[i], i, NULL); + + cases = test_cases_from_reports (reports, argc-1); + + window = window_create (cases, reports, argc-1); + g_signal_connect (window, "delete-event", + G_CALLBACK (gtk_main_quit), NULL); + gtk_widget_show (window); + + gtk_main (); + + /* Pointless memory cleanup, (would be a great place for talloc) */ + free (cases); + for (i = 0; i < argc-1; i++) { + for (t = reports[i].tests; t->name; t++) { + free (t->samples); + free (t->backend); + free (t->name); + } + free (reports[i].tests); + free (reports[i].configuration); + } + free (reports); + + return 0; +} diff --git a/local/recipes/libs/cairo/source/perf/cairo-perf-graph-widget.c b/local/recipes/libs/cairo/source/perf/cairo-perf-graph-widget.c new file mode 100644 index 0000000000..9da0abbfee --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/cairo-perf-graph-widget.c @@ -0,0 +1,604 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of the + * copyright holders not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * + * Authors: Chris Wilson + */ + +#define GLIB_DISABLE_DEPRECATION_WARNINGS + +#include "cairo-perf.h" +#include "cairo-perf-graph.h" + +#include + +struct _GraphView { + GtkWidget widget; + + test_case_t *cases; + cairo_perf_report_t *reports; + int num_reports; + double ymin, ymax; + + int selected_report; +}; + +typedef struct _GraphViewClass { + GtkWidgetClass parent_class; +} GraphViewClass; + +static GType graph_view_get_type (void); + +enum { + REPORT_SELECTED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +G_DEFINE_TYPE (GraphView, graph_view, GTK_TYPE_WIDGET) + +static void +draw_baseline_performance (test_case_t *cases, + cairo_perf_report_t *reports, + int num_reports, + cairo_t *cr, + const cairo_matrix_t *m) +{ + test_report_t **tests; + double dots[2] = { 0, 1.}; + int i; + + tests = xmalloc (num_reports * sizeof (test_report_t *)); + for (i = 0; i < num_reports; i++) + tests[i] = reports[i].tests; + + while (cases->backend != NULL) { + test_report_t *min_test; + double baseline, last_y; + double x, y; + + if (! cases->shown) { + cases++; + continue; + } + + min_test = cases->min_test; + + for (i = 0; i < num_reports; i++) { + while (tests[i]->name && + test_report_cmp_backend_then_name (tests[i], min_test) < 0) + { + tests[i]++; + } + } + + /* first the stroke */ + cairo_save (cr); + cairo_set_line_width (cr, 2.); + gdk_cairo_set_source_color (cr, &cases->color); + for (i = 0; i < num_reports; i++) { + if (tests[i]->name && + test_report_cmp_backend_then_name (tests[i], min_test) == 0) + { + baseline = tests[i]->stats.min_ticks; + + x = i; y = 0; + cairo_matrix_transform_point (m, &x, &y); + x = floor (x); + y = floor (y); + cairo_move_to (cr, x, y); + last_y = y; + break; + } + } + + for (++i; i < num_reports; i++) { + if (tests[i]->name && + test_report_cmp_backend_then_name (tests[i], min_test) == 0) + { + x = i, y = tests[i]->stats.min_ticks / baseline; + + if (y < 1.) + y = -1./y + 1; + else + y -= 1; + + cairo_matrix_transform_point (m, &x, &y); + x = floor (x); + y = floor (y); + cairo_line_to (cr, x, last_y); + cairo_line_to (cr, x, y); + last_y = y; + } + } + { + x = num_reports, y = 0; + cairo_matrix_transform_point (m, &x, &y); + x = floor (x); + cairo_line_to (cr, x, last_y); + } + + cairo_set_line_width (cr, 1.); + cairo_stroke (cr); + + /* then draw the points */ + for (i = 0; i < num_reports; i++) { + if (tests[i]->name && + test_report_cmp_backend_then_name (tests[i], min_test) == 0) + { + baseline = tests[i]->stats.min_ticks; + + x = i; y = 0; + cairo_matrix_transform_point (m, &x, &y); + x = floor (x); + y = floor (y); + cairo_move_to (cr, x, y); + cairo_close_path (cr); + last_y = y; + + tests[i]++; + break; + } + } + + for (++i; i < num_reports; i++) { + if (tests[i]->name && + test_report_cmp_backend_then_name (tests[i], min_test) == 0) + { + x = i, y = tests[i]->stats.min_ticks / baseline; + + if (y < 1.) + y = -1./y + 1; + else + y -= 1; + + cairo_matrix_transform_point (m, &x, &y); + x = floor (x); + y = floor (y); + cairo_move_to (cr, x, last_y); + cairo_close_path (cr); + cairo_move_to (cr, x, y); + cairo_close_path (cr); + last_y = y; + + tests[i]++; + } + } + { + x = num_reports, y = 0; + cairo_matrix_transform_point (m, &x, &y); + x = floor (x); + cairo_move_to (cr, x, last_y); + cairo_close_path (cr); + } + cairo_set_source_rgba (cr, 0, 0, 0, .5); + cairo_set_dash (cr, dots, 2, 0.); + cairo_set_line_width (cr, 3.); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + cairo_stroke (cr); + cairo_restore (cr); + + cases++; + } + free (tests); +} + +static void +draw_hline (cairo_t *cr, + const cairo_matrix_t *m, + double y0, + double xmin, + double xmax) +{ + double x, y; + double py_offset; + + py_offset = fmod (cairo_get_line_width (cr) / 2., 1.); + + x = xmin; y = y0; + cairo_matrix_transform_point (m, &x, &y); + cairo_move_to (cr, floor (x), floor (y) + py_offset); + + x = xmax; y = y0; + cairo_matrix_transform_point (m, &x, &y); + cairo_line_to (cr, ceil (x), floor (y) + py_offset); + + cairo_stroke (cr); +} + +static void +draw_label (cairo_t *cr, + const cairo_matrix_t *m, + double y0, + double xmin, + double xmax) +{ + double x, y; + char buf[80]; + cairo_text_extents_t extents; + + snprintf (buf, sizeof (buf), "%.0fx", fabs (y0)); + cairo_text_extents (cr, buf, &extents); + + x = xmin; y = y0; + cairo_matrix_transform_point (m, &x, &y); + cairo_move_to (cr, + x - extents.width - 4, + y - (extents.height/2. + extents.y_bearing)); + cairo_show_text (cr, buf); + + + snprintf (buf, sizeof (buf), "%.0fx", fabs (y0)); + cairo_text_extents (cr, buf, &extents); + + x = xmax; y = y0; + cairo_matrix_transform_point (m, &x, &y); + cairo_move_to (cr, + x + 4, + y - (extents.height/2. + extents.y_bearing)); + cairo_show_text (cr, buf); +} + +#define ALIGN_X(v) ((v)<<0) +#define ALIGN_Y(v) ((v)<<2) +static void +draw_rotated_label (cairo_t *cr, + const char *text, + double x, + double y, + double angle, + int align) +{ + cairo_text_extents_t extents; + + cairo_text_extents (cr, text, &extents); + + cairo_save (cr); { + cairo_translate (cr, x, y); + cairo_rotate (cr, angle); + switch (align) { + case ALIGN_X(0) | ALIGN_Y(0): + cairo_move_to (cr, + -extents.x_bearing, + -extents.y_bearing); + break; + case ALIGN_X(0) | ALIGN_Y(1): + cairo_move_to (cr, + -extents.x_bearing, + - (extents.height/2. + extents.y_bearing)); + break; + case ALIGN_X(0) | ALIGN_Y(2): + cairo_move_to (cr, + -extents.x_bearing, + - (extents.height + extents.y_bearing)); + break; + + case ALIGN_X(1) | ALIGN_Y(0): + cairo_move_to (cr, + - (extents.width/2. + extents.x_bearing), + -extents.y_bearing); + break; + case ALIGN_X(1) | ALIGN_Y(1): + cairo_move_to (cr, + - (extents.width/2. + extents.x_bearing), + - (extents.height/2. + extents.y_bearing)); + break; + case ALIGN_X(1) | ALIGN_Y(2): + cairo_move_to (cr, + - (extents.width/2. + extents.x_bearing), + - (extents.height + extents.y_bearing)); + break; + + case ALIGN_X(2) | ALIGN_Y(0): + cairo_move_to (cr, + - (extents.width + extents.x_bearing), + -extents.y_bearing); + break; + case ALIGN_X(2) | ALIGN_Y(1): + cairo_move_to (cr, + - (extents.width + extents.x_bearing), + - (extents.height/2. + extents.y_bearing)); + break; + case ALIGN_X(2) | ALIGN_Y(2): + cairo_move_to (cr, + - (extents.width + extents.x_bearing), + - (extents.height + extents.y_bearing)); + break; + } + cairo_show_text (cr, text); + } cairo_restore (cr); +} + +#define PAD 36 +static void +graph_view_draw (GraphView *self, + cairo_t *cr) +{ + cairo_matrix_t m; + const double dash[2] = {4, 4}; + double range; + int i; + + if (self->widget.allocation.width < 4 *PAD) + return; + if (self->widget.allocation.height < 3 *PAD) + return; + + range = floor (self->ymax+1) - ceil (self->ymin-1); + + cairo_matrix_init_translate (&m, PAD, self->widget.allocation.height - PAD); + cairo_matrix_scale (&m, + (self->widget.allocation.width-2*PAD)/(self->num_reports), + -(self->widget.allocation.height-2*PAD)/range); + cairo_matrix_translate (&m, 0, floor (self->ymax+1)); + + if (self->selected_report != -1) { + cairo_save (cr); { + double x0, x1, y; + x0 = self->selected_report; y = 0; + cairo_matrix_transform_point (&m, &x0, &y); + x0 = floor (x0); + x1 = self->selected_report + 1; y = 0; + cairo_matrix_transform_point (&m, &x1, &y); + x1 = ceil (x1); + y = (x1 - x0) / 8; + y = MIN (y, PAD / 2); + x0 -= y; + x1 += y; + cairo_rectangle (cr, x0, PAD/2, x1-x0, self->widget.allocation.height-2*PAD + PAD); + gdk_cairo_set_source_color (cr, &self->widget.style->base[GTK_STATE_SELECTED]); + cairo_fill (cr); + } cairo_restore (cr); + } + + cairo_save (cr); { + cairo_pattern_t *linear; + double x, y; + + gdk_cairo_set_source_color (cr, + &self->widget.style->fg[GTK_WIDGET_STATE (self)]); + cairo_set_line_width (cr, 2.); + draw_hline (cr, &m, 0, 0, self->num_reports); + + cairo_set_line_width (cr, 1.); + cairo_set_dash (cr, NULL, 0, 0); + + for (i = ceil (self->ymin-1); i <= floor (self->ymax+1); i++) { + if (i != 0) + draw_hline (cr, &m, i, 0, self->num_reports); + } + + cairo_set_font_size (cr, 11); + + linear = cairo_pattern_create_linear (0, PAD, 0, self->widget.allocation.height-2*PAD); + cairo_pattern_add_color_stop_rgb (linear, 0, 0, 1, 0); + cairo_pattern_add_color_stop_rgb (linear, 1, 1, 0, 0); + cairo_set_source (cr, linear); + cairo_pattern_destroy (linear); + + for (i = ceil (self->ymin-1); i <= floor (self->ymax+1); i++) { + if (i != 0) + draw_label (cr, &m, i, 0, self->num_reports); + } + + x = 0, y = floor (self->ymax+1); + cairo_matrix_transform_point (&m, &x, &y); + draw_rotated_label (cr, "Faster", x - 7, y + 14, + 270./360 * 2 * G_PI, + ALIGN_X(2) | ALIGN_Y(1)); + x = self->num_reports, y = floor (self->ymax+1); + cairo_matrix_transform_point (&m, &x, &y); + draw_rotated_label (cr, "Faster", x + 11, y + 14, + 270./360 * 2 * G_PI, + ALIGN_X(2) | ALIGN_Y(1)); + + x = 0, y = ceil (self->ymin-1); + cairo_matrix_transform_point (&m, &x, &y); + draw_rotated_label (cr, "Slower", x - 7, y - 14, + 90./360 * 2 * G_PI, + ALIGN_X(2) | ALIGN_Y(1)); + x = self->num_reports, y = ceil (self->ymin-1); + cairo_matrix_transform_point (&m, &x, &y); + draw_rotated_label (cr, "Slower", x + 11, y - 14, + 90./360 * 2 * G_PI, + ALIGN_X(2) | ALIGN_Y(1)); + } cairo_restore (cr); + + draw_baseline_performance (self->cases, + self->reports, self->num_reports, + cr, &m); + + cairo_save (cr); { + cairo_set_source_rgb (cr, 0.7, 0.7, 0.7); + cairo_set_line_width (cr, 1.); + cairo_set_dash (cr, dash, 2, 0); + draw_hline (cr, &m, 0, 0, self->num_reports); + } cairo_restore (cr); +} + +static gboolean +graph_view_expose (GtkWidget *w, + GdkEventExpose *ev) +{ + GraphView *self = (GraphView *) w; + cairo_t *cr; + + cr = gdk_cairo_create (w->window); + gdk_cairo_set_source_color (cr, &w->style->base[GTK_WIDGET_STATE (w)]); + cairo_paint (cr); + + graph_view_draw (self, cr); + + cairo_destroy (cr); + + return FALSE; +} + +static gboolean +graph_view_button_press (GtkWidget *w, + GdkEventButton *ev) +{ + GraphView *self = (GraphView *) w; + cairo_matrix_t m; + double x,y; + int i; + + cairo_matrix_init_translate (&m, PAD, self->widget.allocation.height-PAD); + cairo_matrix_scale (&m, (self->widget.allocation.width-2*PAD)/self->num_reports, -(self->widget.allocation.height-2*PAD)/(self->ymax - self->ymin)); + cairo_matrix_translate (&m, 0, -self->ymin); + cairo_matrix_invert (&m); + + x = ev->x; + y = ev->y; + cairo_matrix_transform_point (&m, &x, &y); + + i = floor (x); + if (i < 0 || i >= self->num_reports) + i = -1; + + if (i != self->selected_report) { + self->selected_report = i; + gtk_widget_queue_draw (w); + + g_signal_emit (w, signals[REPORT_SELECTED], 0, i); + } + + return FALSE; +} + +static gboolean +graph_view_button_release (GtkWidget *w, + GdkEventButton *ev) +{ + return FALSE; +} + +static void +graph_view_realize (GtkWidget *widget) +{ + GdkWindowAttr attributes; + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget) | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_EXPOSURE_MASK; + + widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), + &attributes, + GDK_WA_X | GDK_WA_Y | + GDK_WA_VISUAL | GDK_WA_COLORMAP); + gdk_window_set_user_data (widget->window, widget); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); +} + +static void +graph_view_finalize (GObject *obj) +{ + G_OBJECT_CLASS (graph_view_parent_class)->finalize (obj); +} + +static void +graph_view_class_init (GraphViewClass *klass) +{ + GObjectClass *object_class = (GObjectClass *) klass; + GtkWidgetClass *widget_class = (GtkWidgetClass *) klass; + + object_class->finalize = graph_view_finalize; + + widget_class->realize = graph_view_realize; + widget_class->expose_event = graph_view_expose; + widget_class->button_press_event = graph_view_button_press; + widget_class->button_release_event = graph_view_button_release; + + signals[REPORT_SELECTED] = + g_signal_new ("report-selected", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST, + 0,//G_STRUCT_OFFSET (GraphView, report_selected), + NULL, NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, 1, G_TYPE_INT); +} + +static void +graph_view_init (GraphView *self) +{ + self->selected_report = -1; +} + +GtkWidget * +graph_view_new (void) +{ + return g_object_new (graph_view_get_type (), NULL); +} + +void +graph_view_update_visible (GraphView *gv) +{ + double min, max; + test_case_t *cases; + + cases = gv->cases; + + min = max = 1.; + while (cases->name != NULL) { + if (cases->shown) { + if (cases->min < min) + min = cases->min; + if (cases->max > max) + max = cases->max; + } + cases++; + } + gv->ymin = -1/min + 1; + gv->ymax = max - 1; + + gtk_widget_queue_draw (&gv->widget); +} + +void +graph_view_set_reports (GraphView *gv, + test_case_t *cases, + cairo_perf_report_t *reports, + int num_reports) +{ + /* XXX ownership? */ + gv->cases = cases; + gv->reports = reports; + gv->num_reports = num_reports; + + graph_view_update_visible (gv); +} diff --git a/local/recipes/libs/cairo/source/perf/cairo-perf-graph.h b/local/recipes/libs/cairo/source/perf/cairo-perf-graph.h new file mode 100644 index 0000000000..4cb62165f8 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/cairo-perf-graph.h @@ -0,0 +1,63 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of the + * copyright holders not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * + * Authors: Chris Wilson + */ + +#ifndef CAIRO_PERF_GRAPH_H +#define CAIRO_PERF_GRAPH_H + +#include + +#include "cairo-perf.h" + +typedef struct _test_case { + const char *backend; + const char *content; + const char *name; + int size; + + test_report_t *min_test; + + cairo_bool_t shown; + double baseline; + double min, max; + GdkColor color; +} test_case_t; + +typedef struct _GraphView GraphView; + +GtkWidget * +graph_view_new (void); + +void +graph_view_set_reports (GraphView *gv, + test_case_t *tests, + cairo_perf_report_t *reports, + int num_reports); + +void +graph_view_update_visible (GraphView *gv); + +#endif diff --git a/local/recipes/libs/cairo/source/perf/cairo-perf-micro.c b/local/recipes/libs/cairo/source/perf/cairo-perf-micro.c new file mode 100644 index 0000000000..618272ec56 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/cairo-perf-micro.c @@ -0,0 +1,592 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright © 2006 Mozilla Corporation + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * the authors not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. The authors make no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Vladimir Vukicevic + * Carl Worth + */ + +#include "config.h" + +#include "cairo-perf.h" +#include "cairo-stats.h" + +#include "cairo-boilerplate-getopt.h" + +/* For basename */ +#ifdef HAVE_LIBGEN_H +#include +#endif + +#if HAVE_FCFINI +#include +#endif + +#ifdef HAVE_SCHED_H +#include +#endif + +#define CAIRO_PERF_ITERATIONS_DEFAULT 100 +#define CAIRO_PERF_LOW_STD_DEV 0.03 +#define CAIRO_PERF_STABLE_STD_DEV_COUNT 5 +#define CAIRO_PERF_ITERATION_MS_DEFAULT 2000 +#define CAIRO_PERF_ITERATION_MS_FAST 5 + +typedef struct _cairo_perf_case { + CAIRO_PERF_RUN_DECL (*run); + cairo_bool_t (*enabled) (cairo_perf_t *perf); + unsigned int min_size; + unsigned int max_size; +} cairo_perf_case_t; + +const cairo_perf_case_t perf_cases[]; + +static const char * +_content_to_string (cairo_content_t content, + cairo_bool_t similar) +{ + switch (content|similar) { + case CAIRO_CONTENT_COLOR: + return "rgb"; + case CAIRO_CONTENT_COLOR|1: + return "rgb&"; + case CAIRO_CONTENT_ALPHA: + return "a"; + case CAIRO_CONTENT_ALPHA|1: + return "a&"; + case CAIRO_CONTENT_COLOR_ALPHA: + return "rgba"; + case CAIRO_CONTENT_COLOR_ALPHA|1: + return "rgba&"; + default: + return ""; + } +} + +static cairo_bool_t +cairo_perf_has_similar (cairo_perf_t *perf) +{ + cairo_surface_t *target; + + if (getenv ("CAIRO_TEST_SIMILAR") == NULL) + return FALSE; + + /* exclude the image backend */ + target = cairo_get_target (perf->cr); + if (cairo_surface_get_type (target) == CAIRO_SURFACE_TYPE_IMAGE) + return FALSE; + + return TRUE; +} + +cairo_bool_t +cairo_perf_can_run (cairo_perf_t *perf, + const char *name, + cairo_bool_t *is_explicit) +{ + unsigned int i; + + if (is_explicit) + *is_explicit = FALSE; + + if (perf->num_names == 0) + return TRUE; + + for (i = 0; i < perf->num_names; i++) { + if (strstr (name, perf->names[i])) { + if (is_explicit) + *is_explicit = FALSE; + return TRUE; + } + } + + return FALSE; +} + +static unsigned +cairo_perf_calibrate (cairo_perf_t *perf, + cairo_perf_func_t perf_func) +{ + cairo_time_t calibration, calibration_max; + unsigned loops, min_loops; + + min_loops = 1; + calibration = perf_func (perf->cr, perf->size, perf->size, min_loops); + + if (!perf->fast_and_sloppy) { + calibration_max = _cairo_time_from_s (perf->ms_per_iteration * 0.0001 / 4); + while (calibration < calibration_max) { + min_loops *= 2; + calibration = perf_func (perf->cr, perf->size, perf->size, min_loops); + } + } + + /* XXX + * Compute the number of loops required for the timing + * interval to be perf->ms_per_iteration milliseconds. This + * helps to eliminate sampling variance due to timing and + * other systematic errors. However, it also hides + * synchronisation overhead as we attempt to process a large + * batch of identical operations in a single shot. This can be + * considered both good and bad... It would be good to perform + * a more rigorous analysis of the synchronisation overhead, + * that is to estimate the time for loop=0. + */ + loops = _cairo_time_from_s (perf->ms_per_iteration * 0.001 * min_loops / calibration); + min_loops = perf->fast_and_sloppy ? 1 : 10; + if (loops < min_loops) + loops = min_loops; + + return loops; +} + +void +cairo_perf_run (cairo_perf_t *perf, + const char *name, + cairo_perf_func_t perf_func, + cairo_count_func_t count_func) +{ + static cairo_bool_t first_run = TRUE; + unsigned int i, similar, similar_iters; + cairo_time_t *times; + cairo_stats_t stats = {0.0, 0.0}; + int low_std_dev_count; + + if (perf->list_only) { + printf ("%s\n", name); + return; + } + + if (first_run) { + if (perf->raw) { + printf ("[ # ] %s.%-s %s %s %s ...\n", + "backend", "content", "test-size", "ticks-per-ms", "time(ticks)"); + } + + if (perf->summary) { + fprintf (perf->summary, + "[ # ] %8s.%-4s %28s %8s %8s %5s %5s %s %s\n", + "backend", "content", "test-size", "min(ticks)", "min(ms)", "median(ms)", + "stddev.", "iterations", "overhead"); + } + first_run = FALSE; + } + + times = perf->times; + + if (getenv ("CAIRO_PERF_OUTPUT") != NULL) { /* check output */ + char *filename; + cairo_status_t status; + + xasprintf (&filename, "%s.%s.%s.%d.out.png", + name, perf->target->name, + _content_to_string (perf->target->content, 0), + perf->size); + cairo_save (perf->cr); + perf_func (perf->cr, perf->size, perf->size, 1); + cairo_restore (perf->cr); + status = cairo_surface_write_to_png (cairo_get_target (perf->cr), filename); + if (status) { + fprintf (stderr, "Failed to generate output check '%s': %s\n", + filename, cairo_status_to_string (status)); + return; + } + + free (filename); + } + + if (cairo_perf_has_similar (perf)) + similar_iters = 2; + else + similar_iters = 1; + + for (similar = 0; similar < similar_iters; similar++) { + unsigned loops; + + if (perf->summary) { + fprintf (perf->summary, + "[%3d] %8s.%-5s %26s.%-3d ", + perf->test_number, perf->target->name, + _content_to_string (perf->target->content, similar), + name, perf->size); + fflush (perf->summary); + } + + /* We run one iteration in advance to warm caches and calibrate. */ + cairo_perf_yield (); + if (similar) + cairo_push_group_with_content (perf->cr, + cairo_boilerplate_content (perf->target->content)); + else + cairo_save (perf->cr); + perf_func (perf->cr, perf->size, perf->size, 1); + loops = cairo_perf_calibrate (perf, perf_func); + if (similar) + cairo_pattern_destroy (cairo_pop_group (perf->cr)); + else + cairo_restore (perf->cr); + + low_std_dev_count = 0; + for (i =0; i < perf->iterations; i++) { + cairo_perf_yield (); + if (similar) + cairo_push_group_with_content (perf->cr, + cairo_boilerplate_content (perf->target->content)); + else + cairo_save (perf->cr); + times[i] = perf_func (perf->cr, perf->size, perf->size, loops) ; + if (similar) + cairo_pattern_destroy (cairo_pop_group (perf->cr)); + else + cairo_restore (perf->cr); + if (perf->raw) { + if (i == 0) + printf ("[*] %s.%s %s.%d %g", + perf->target->name, + _content_to_string (perf->target->content, similar), + name, perf->size, + _cairo_time_to_double (_cairo_time_from_s (1.)) / 1000.); + printf (" %lld", (long long) (times[i] / (double) loops)); + } else if (! perf->exact_iterations) { + if (i > 0) { + _cairo_stats_compute (&stats, times, i+1); + + if (stats.std_dev <= CAIRO_PERF_LOW_STD_DEV) { + low_std_dev_count++; + if (low_std_dev_count >= CAIRO_PERF_STABLE_STD_DEV_COUNT) + break; + } else { + low_std_dev_count = 0; + } + } + } + } + + if (perf->raw) + printf ("\n"); + + if (perf->summary) { + _cairo_stats_compute (&stats, times, i); + if (count_func != NULL) { + double count = count_func (perf->cr, perf->size, perf->size); + fprintf (perf->summary, + "%.3f [%10lld/%d] %#8.3f %#8.3f %#5.2f%% %3d: %.2f\n", + stats.min_ticks /(double) loops, + (long long) stats.min_ticks, loops, + _cairo_time_to_s (stats.min_ticks) * 1000.0 / loops, + _cairo_time_to_s (stats.median_ticks) * 1000.0 / loops, + stats.std_dev * 100.0, stats.iterations, + count / _cairo_time_to_s (stats.min_ticks)); + } else { + fprintf (perf->summary, + "%.3f [%10lld/%d] %#8.3f %#8.3f %#5.2f%% %3d\n", + stats.min_ticks /(double) loops, + (long long) stats.min_ticks, loops, + _cairo_time_to_s (stats.min_ticks) * 1000.0 / loops, + _cairo_time_to_s (stats.median_ticks) * 1000.0 / loops, + stats.std_dev * 100.0, stats.iterations); + } + fflush (perf->summary); + } + + perf->test_number++; + } +} + +static void +usage (const char *argv0) +{ + fprintf (stderr, +"Usage: %s [-flrv] [-i iterations] [test-names ...]\n" +"\n" +"Run the cairo performance test suite over the given tests (all by default)\n" +"The command-line arguments are interpreted as follows:\n" +"\n" +" -f fast; faster, less accurate\n" +" -i iterations; specify the number of iterations per test case\n" +" -l list only; just list selected test case names without executing\n" +" -r raw; display each time measurement instead of summary statistics\n" +" -v verbose; in raw mode also show the summaries\n" +"\n" +"If test names are given they are used as sub-string matches so a command\n" +"such as \"%s text\" can be used to run all text test cases.\n", + argv0, argv0); +} + +static void +parse_options (cairo_perf_t *perf, + int argc, + char *argv[]) +{ + int c; + const char *iters; + const char *ms = NULL; + char *end; + int verbose = 0; + + if ((iters = getenv("CAIRO_PERF_ITERATIONS")) && *iters) + perf->iterations = strtol(iters, NULL, 0); + else + perf->iterations = CAIRO_PERF_ITERATIONS_DEFAULT; + perf->exact_iterations = 0; + + perf->fast_and_sloppy = FALSE; + perf->ms_per_iteration = CAIRO_PERF_ITERATION_MS_DEFAULT; + if ((ms = getenv("CAIRO_PERF_ITERATION_MS")) && *ms) { + perf->ms_per_iteration = atof(ms); + } + + perf->raw = FALSE; + perf->list_only = FALSE; + perf->names = NULL; + perf->num_names = 0; + perf->summary = stdout; + + while (1) { + c = _cairo_getopt (argc, argv, "fi:lrv"); + if (c == -1) + break; + + switch (c) { + case 'f': + perf->fast_and_sloppy = TRUE; + if (ms == NULL) + perf->ms_per_iteration = CAIRO_PERF_ITERATION_MS_FAST; + break; + case 'i': + perf->exact_iterations = TRUE; + perf->iterations = strtoul (optarg, &end, 10); + if (*end != '\0') { + fprintf (stderr, "Invalid argument for -i (not an integer): %s\n", + optarg); + exit (1); + } + break; + case 'l': + perf->list_only = TRUE; + break; + case 'r': + perf->raw = TRUE; + perf->summary = NULL; + break; + case 'v': + verbose = 1; + break; + default: + fprintf (stderr, "Internal error: unhandled option: %c\n", c); + /* fall-through */ + case '?': + usage (argv[0]); + exit (1); + } + } + + if (verbose && perf->summary == NULL) + perf->summary = stderr; + + if (optind < argc) { + perf->names = &argv[optind]; + perf->num_names = argc - optind; + } +} + +static int +check_cpu_affinity (void) +{ +#ifdef HAVE_SCHED_GETAFFINITY + + cpu_set_t affinity; + int i, cpu_count; + + if (sched_getaffinity(0, sizeof(affinity), &affinity)) { + perror("sched_getaffinity"); + return -1; + } + + for(i = 0, cpu_count = 0; i < CPU_SETSIZE; ++i) { + if (CPU_ISSET(i, &affinity)) + ++cpu_count; + } + + if (cpu_count > 1) { + fputs( + "WARNING: cairo-perf has not been bound to a single CPU.\n", + stderr); + return -1; + } + + return 0; +#else + fputs( + "WARNING: Cannot check CPU affinity for this platform.\n", + stderr); + return -1; +#endif +} + +static void +cairo_perf_fini (cairo_perf_t *perf) +{ + cairo_boilerplate_free_targets (perf->targets); + cairo_boilerplate_fini (); + + free (perf->times); + cairo_debug_reset_static_data (); +#if HAVE_FCFINI + FcFini (); +#endif +} + + +int +main (int argc, + char *argv[]) +{ + int i, j; + cairo_perf_t perf; + cairo_surface_t *surface; + + parse_options (&perf, argc, argv); + + if (check_cpu_affinity()) { + fputs( + "NOTICE: cairo-perf and the X server should be bound to CPUs (either the same\n" + "or separate) on SMP systems. Not doing so causes random results when the X\n" + "server is moved to or from cairo-perf's CPU during the benchmarks:\n" + "\n" + " $ sudo taskset -cp 0 $(pidof X)\n" + " $ taskset -cp 1 $$\n" + "\n" + "See taskset(1) for information about changing CPU affinity.\n", + stderr); + } + + perf.targets = cairo_boilerplate_get_targets (&perf.num_targets, NULL); + perf.times = xmalloc (perf.iterations * sizeof (cairo_time_t)); + + for (i = 0; i < perf.num_targets; i++) { + const cairo_boilerplate_target_t *target = perf.targets[i]; + + if (! target->is_measurable) + continue; + + perf.target = target; + perf.test_number = 0; + + for (j = 0; perf_cases[j].run; j++) { + const cairo_perf_case_t *perf_case = &perf_cases[j]; + + if (! perf_case->enabled (&perf)) + continue; + + for (perf.size = perf_case->min_size; + perf.size <= perf_case->max_size; + perf.size *= 2) + { + void *closure; + + surface = (target->create_surface) (NULL, + target->content, + perf.size, perf.size, + perf.size, perf.size, + CAIRO_BOILERPLATE_MODE_PERF, + &closure); + if (surface == NULL) { + fprintf (stderr, + "Error: Failed to create target surface: %s\n", + target->name); + continue; + } + + cairo_perf_timer_set_synchronize (target->synchronize, closure); + + perf.cr = cairo_create (surface); + + perf_case->run (&perf, perf.cr, perf.size, perf.size); + + if (cairo_status (perf.cr)) { + fprintf (stderr, "Error: Test left cairo in an error state: %s\n", + cairo_status_to_string (cairo_status (perf.cr))); + } + + cairo_destroy (perf.cr); + cairo_surface_destroy (surface); + + if (target->cleanup) + target->cleanup (closure); + } + } + } + + cairo_perf_fini (&perf); + + return 0; +} + +#define FUNC(f) f, f##_enabled +const cairo_perf_case_t perf_cases[] = { + { FUNC(pixel), 1, 1 }, + { FUNC(a1_pixel), 1, 1 }, + { FUNC(paint), 64, 512}, + { FUNC(paint_with_alpha), 64, 512}, + { FUNC(fill), 64, 512}, + { FUNC(stroke), 64, 512}, + { FUNC(text), 64, 512}, + { FUNC(glyphs), 64, 512}, + { FUNC(mask), 64, 512}, + { FUNC(line), 32, 512}, + { FUNC(a1_line), 32, 512}, + { FUNC(curve), 32, 512}, + { FUNC(a1_curve), 32, 512}, + { FUNC(disjoint), 64, 512}, + { FUNC(hatching), 64, 512}, + { FUNC(tessellate), 100, 100}, + { FUNC(subimage_copy), 16, 512}, + { FUNC(hash_table), 16, 16}, + { FUNC(pattern_create_radial), 16, 16}, + { FUNC(zrusin), 415, 415}, + { FUNC(world_map), 800, 800}, + { FUNC(box_outline), 100, 100}, + { FUNC(mosaic), 800, 800 }, + { FUNC(long_lines), 100, 100}, + { FUNC(unaligned_clip), 100, 100}, + { FUNC(rectangles), 512, 512}, + { FUNC(rounded_rectangles), 512, 512}, + { FUNC(long_dashed_lines), 512, 512}, + { FUNC(composite_checker), 16, 512}, + { FUNC(twin), 800, 800}, + { FUNC(dragon), 1024, 1024 }, + { FUNC(sierpinski), 32, 1024 }, + { FUNC(pythagoras_tree), 768, 768 }, + { FUNC(intersections), 512, 512 }, + { FUNC(many_strokes), 32, 512 }, + { FUNC(wide_strokes), 32, 512 }, + { FUNC(many_fills), 32, 512 }, + { FUNC(wide_fills), 32, 512 }, + { FUNC(many_curves), 32, 512 }, + { FUNC(spiral), 512, 512 }, + { FUNC(wave), 500, 500 }, + { FUNC(fill_clip), 16, 512 }, + { FUNC(tiger), 16, 1024 }, + { NULL } +}; diff --git a/local/recipes/libs/cairo/source/perf/cairo-perf-print.c b/local/recipes/libs/cairo/source/perf/cairo-perf-print.c new file mode 100644 index 0000000000..e9c493fa30 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/cairo-perf-print.c @@ -0,0 +1,140 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * Copyright © 2009 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of the + * copyright holders not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * + * Authors: Carl Worth + * Chris Wilson + */ + +#include "config.h" + +#include "cairo-perf.h" +#include "cairo-stats.h" + +#include + +#if HAVE_UNISTD_H && HAVE_SYS_IOCTL_H +#define USE_TERMINAL_SIZE 1 +#else +#define USE_TERMINAL_SIZE 0 +#endif + +#if USE_TERMINAL_SIZE +#include +#include +#if HAVE_TERMIOS_H +#include +#endif +#endif + +static void +report_print (const cairo_perf_report_t *report, + int show_histogram) +{ + const test_report_t *test; + cairo_histogram_t h; + + if (show_histogram) { + int num_rows = 23; + int num_cols = 80; + +#if USE_TERMINAL_SIZE + int fd = fileno(stdout); + if (isatty(fd)) { + struct winsize ws; + + if(ioctl(fd, TIOCGWINSZ, &ws) == 0 ) { + num_rows = ws.ws_row - 1; + num_cols = ws.ws_col; + } + } +#endif + + if (!_cairo_histogram_init (&h, num_cols, num_rows)) + show_histogram = 0; + } + + for (test = report->tests; test->name != NULL; test++) { + if (test->stats.iterations == 0) + continue; + + if (show_histogram) { + const cairo_time_t *values; + int num_values; + + if (show_histogram > 1) { + values = test->stats.values; + num_values = test->stats.iterations; + } else { + values = test->samples; + num_values = test->samples_count; + } + + if (_cairo_histogram_compute (&h, values, num_values)) + _cairo_histogram_printf (&h, stdout); + } + + if (test->size) { + printf ("%5s-%-4s %26s-%-3d ", + test->backend, test->content, + test->name, test->size); + } else { + printf ("%5s %26s ", test->backend, test->name); + } + printf("%6.2f %4.2f%% (%d/%d)\n", + test->stats.median_ticks / test->stats.ticks_per_ms, + test->stats.std_dev * 100, + test->stats.iterations, test->samples_count); + } + + if (show_histogram) + _cairo_histogram_fini (&h); +} + +int +main (int argc, + const char *argv[]) +{ + cairo_bool_t show_histogram = 0; + int i; + + for (i = 1; i < argc; i++ ) { + cairo_perf_report_t report; + + if (strcmp(argv[i], "--histogram") == 0) { + show_histogram = 1; + continue; + } + + if (strcmp(argv[i], "--short-histogram") == 0) { + show_histogram = 2; + continue; + } + + cairo_perf_report_load (&report, argv[i], i, NULL); + report_print (&report, show_histogram); + } + + return 0; +} diff --git a/local/recipes/libs/cairo/source/perf/cairo-perf-report.c b/local/recipes/libs/cairo/source/perf/cairo-perf-report.c new file mode 100644 index 0000000000..163368fee1 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/cairo-perf-report.c @@ -0,0 +1,458 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of the + * copyright holders not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * + * Authors: Carl Worth + */ + +#include "config.h" + +#define _GETDELIM 1/* for getline() on AIX */ + +#include "cairo-perf.h" +#include "cairo-missing.h" +#include "cairo-stats.h" +#include "cairo-ctype-inline.h" + +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_LIBGEN_H +#include +#endif + +#ifdef _MSC_VER +#if _MSC_VER < 1800 +static long long +strtoll (const char *nptr, + char **endptr, + int base); +#endif + +static char * +basename (char *path); +#endif + +/* Ad-hoc parsing, macros with a strong dependence on the calling + * context, and plenty of other ugliness is here. But at least it's + * not perl... */ +#define parse_error(...) fprintf(stderr, __VA_ARGS__); return TEST_REPORT_STATUS_ERROR; +#define skip_char(c) \ +do { \ + if (*s && *s == (c)) { \ + s++; \ + } else { \ + parse_error ("expected '%c' but found '%c'", c, *s); \ + } \ +} while (0) +#define skip_space() while (*s && (*s == ' ' || *s == '\t')) s++; +#define parse_int(result) \ +do { \ + (result) = strtol (s, &end, 10); \ + if (*s && end != s) { \ + s = end; \ + } else { \ + parse_error("expected integer but found %s", s); \ + } \ +} while (0) +#define parse_long_long(result) \ +do { \ + (result) = strtoll (s, &end, 10); \ + if (*s && end != s) { \ + s = end; \ + } else { \ + parse_error("expected integer but found %s", s); \ + } \ +} while (0) +#define parse_double(result) \ +do { \ + (result) = strtod (s, &end); \ + if (*s && end != s) { \ + s = end; \ + } else { \ + parse_error("expected floating-point value but found %s", s); \ + } \ +} while (0) +/* Here a string is simply a sequence of non-whitespace */ +#define parse_string(result) \ +do { \ + for (end = s; *end; end++) \ + if (_cairo_isspace (*end)) \ + break; \ + (result) = strndup (s, end - s); \ + if ((result) == NULL) { \ + fprintf (stderr, "Out of memory.\n"); \ + exit (1); \ + } \ + s = end; \ +} while (0) + +static test_report_status_t +test_report_parse (test_report_t *report, + int fileno, + char *line, + char *configuration) +{ + char *end; + char *s = line; + cairo_bool_t is_raw = FALSE; + double min_time, median_time; + + /* The code here looks funny unless you understand that these are + * all macro calls, (and then the code just looks sick). */ + if (*s == '\n') + return TEST_REPORT_STATUS_COMMENT; + + skip_char ('['); + skip_space (); + if (*s == '#') + return TEST_REPORT_STATUS_COMMENT; + if (*s == '*') { + s++; + is_raw = TRUE; + } else { + parse_int (report->id); + } + skip_char (']'); + + skip_space (); + + report->fileno = fileno; + report->configuration = configuration; + parse_string (report->backend); + end = strrchr (report->backend, '.'); + if (end) + *end++ = '\0'; + report->content = end ? end : xstrdup ("???"); + + skip_space (); + + parse_string (report->name); + end = strrchr (report->name, '.'); + if (end) + *end++ = '\0'; + report->size = end ? atoi (end) : 0; + + skip_space (); + + report->samples = NULL; + report->samples_size = 0; + report->samples_count = 0; + + if (is_raw) { + parse_double (report->stats.ticks_per_ms); + skip_space (); + + report->samples_size = 5; + report->samples = xmalloc (report->samples_size * sizeof (cairo_time_t)); + report->stats.min_ticks = 0; + do { + if (report->samples_count == report->samples_size) { + report->samples_size *= 2; + report->samples = xrealloc (report->samples, + report->samples_size * sizeof (cairo_time_t)); + } + parse_long_long (report->samples[report->samples_count]); + if (report->samples_count == 0) { + report->stats.min_ticks = + report->samples[report->samples_count]; + } else if (report->stats.min_ticks > + report->samples[report->samples_count]){ + report->stats.min_ticks = + report->samples[report->samples_count]; + } + report->samples_count++; + skip_space (); + } while (*s && *s != '\n'); + report->stats.iterations = 0; + if (*s) skip_char ('\n'); + } else { + parse_double (report->stats.min_ticks); + skip_space (); + + parse_double (min_time); + report->stats.ticks_per_ms = report->stats.min_ticks / min_time; + + skip_space (); + + parse_double (median_time); + report->stats.median_ticks = median_time * report->stats.ticks_per_ms; + + skip_space (); + + parse_double (report->stats.std_dev); + report->stats.std_dev /= 100.0; + skip_char ('%'); + + skip_space (); + + parse_int (report->stats.iterations); + + skip_space (); + skip_char ('\n'); + } + + return TEST_REPORT_STATUS_SUCCESS; +} + +/* We provide hereafter a win32 implementation of the basename + * and strtoll functions which are not available otherwise. + * The basename function is fully compliant to its GNU specs. + */ +#ifdef _MSC_VER + +#if _MSC_VER < 1800 +long long +strtoll (const char *nptr, + char **endptr, + int base) +{ + return _atoi64(nptr); +} +#endif + +static char * +basename (char *path) +{ + char *end, *s; + + end = (path + strlen(path) - 1); + while (end && (end >= path + 1) && (*end == '/')) { + *end = '\0'; + end--; + } + + s = strrchr(path, '/'); + if (s) { + if (s == end) { + return s; + } else { + return s+1; + } + } else { + return path; + } +} +#endif /* ifndef _MSC_VER */ + +int +test_report_cmp_backend_then_name (const void *a, + const void *b) +{ + const test_report_t *a_test = a; + const test_report_t *b_test = b; + + int cmp; + + cmp = strcmp (a_test->backend, b_test->backend); + if (cmp) + return cmp; + + cmp = strcmp (a_test->content, b_test->content); + if (cmp) + return cmp; + + /* A NULL name is a list-termination marker, so force it last. */ + if (a_test->name == NULL) + if (b_test->name == NULL) + return 0; + else + return 1; + else if (b_test->name == NULL) + return -1; + + cmp = strcmp (a_test->name, b_test->name); + if (cmp) + return cmp; + + if (a_test->size < b_test->size) + return -1; + if (a_test->size > b_test->size) + return 1; + + return 0; +} + +int +test_report_cmp_name (const void *a, + const void *b) +{ + const test_report_t *a_test = a; + const test_report_t *b_test = b; + + int cmp; + + /* A NULL name is a list-termination marker, so force it last. */ + if (a_test->name == NULL) + if (b_test->name == NULL) + return 0; + else + return 1; + else if (b_test->name == NULL) + return -1; + + cmp = strcmp (a_test->name, b_test->name); + if (cmp) + return cmp; + + if (a_test->size < b_test->size) + return -1; + if (a_test->size > b_test->size) + return 1; + + return 0; +} + +void +cairo_perf_report_sort_and_compute_stats (cairo_perf_report_t *report, + int (*cmp) (const void*, const void*)) +{ + test_report_t *base, *next, *last, *t; + + if (cmp == NULL) + cmp = test_report_cmp_backend_then_name; + + /* First we sort, since the diff needs both lists in the same + * order */ + qsort (report->tests, report->tests_count, sizeof (test_report_t), cmp); + + /* The sorting also brings all related raw reports together so we + * can condense them and compute the stats. + */ + base = &report->tests[0]; + last = &report->tests[report->tests_count - 1]; + while (base <= last) { + next = base+1; + if (next <= last) { + while (next <= last && + test_report_cmp_backend_then_name (base, next) == 0) + { + next++; + } + if (next != base) { + unsigned int new_samples_count = base->samples_count; + for (t = base + 1; t < next; t++) + new_samples_count += t->samples_count; + if (new_samples_count > base->samples_size) { + base->samples_size = new_samples_count; + base->samples = xrealloc (base->samples, + base->samples_size * sizeof (cairo_time_t)); + } + for (t = base + 1; t < next; t++) { + memcpy (&base->samples[base->samples_count], t->samples, + t->samples_count * sizeof (cairo_time_t)); + base->samples_count += t->samples_count; + } + } + } + if (base->samples) + _cairo_stats_compute (&base->stats, base->samples, base->samples_count); + base = next; + } +} + +void +cairo_perf_report_load (cairo_perf_report_t *report, + const char *filename, int id, + int (*cmp) (const void *, const void *)) +{ + FILE *file; + test_report_status_t status; + int line_number = 0; + char *line = NULL; + size_t line_size = 0; + char *configuration; + char *dot; + char *baseName; + const char *name; + + name = filename; + if (name == NULL) + name = "stdin"; + + configuration = xstrdup (name); + baseName = basename (configuration); + report->configuration = xstrdup (baseName); + free (configuration); + + dot = strrchr (report->configuration, '.'); + if (dot) + *dot = '\0'; + + report->name = name; + report->tests_size = 16; + report->tests = xmalloc (report->tests_size * sizeof (test_report_t)); + report->tests_count = 0; + report->fileno = id; + + if (filename == NULL) { + file = stdin; + } else { + file = fopen (filename, "r"); + if (file == NULL) { + fprintf (stderr, "Failed to open %s: %s\n", + filename, strerror (errno)); + exit (1); + } + } + + while (1) { + if (report->tests_count == report->tests_size) { + report->tests_size *= 2; + report->tests = xrealloc (report->tests, + report->tests_size * sizeof (test_report_t)); + } + + line_number++; + if (getline (&line, &line_size, file) == -1) + break; + + status = test_report_parse (&report->tests[report->tests_count], + id, line, report->configuration); + if (status == TEST_REPORT_STATUS_ERROR) + fprintf (stderr, "Ignoring unrecognized line %d of %s:\n%s", + line_number, filename, line); + if (status == TEST_REPORT_STATUS_SUCCESS) + report->tests_count++; + /* Do nothing on TEST_REPORT_STATUS_COMMENT */ + } + + free (line); + + if (filename != NULL) + fclose (file); + + cairo_perf_report_sort_and_compute_stats (report, cmp); + + /* Add one final report with a NULL name to terminate the list. */ + if (report->tests_count == report->tests_size) { + report->tests_size *= 2; + report->tests = xrealloc (report->tests, + report->tests_size * sizeof (test_report_t)); + } + report->tests[report->tests_count].name = NULL; +} diff --git a/local/recipes/libs/cairo/source/perf/cairo-perf-trace.c b/local/recipes/libs/cairo/source/perf/cairo-perf-trace.c new file mode 100644 index 0000000000..991a8a5e0f --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/cairo-perf-trace.c @@ -0,0 +1,1065 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright © 2006 Mozilla Corporation + * Copyright © 2006 Red Hat, Inc. + * Copyright © 2009 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * the authors not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. The authors make no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Vladimir Vukicevic + * Carl Worth + * Chris Wilson + */ + +#include "config.h" + +#include "cairo-missing.h" +#include "cairo-perf.h" +#include "cairo-stats.h" + +#include "cairo-boilerplate-getopt.h" +#include +#include /* for INTERNAL_SURFACE_TYPE */ + +/* rudely reuse bits of the library... */ +#include "../src/cairo-hash-private.h" +#include "../src/cairo-error-private.h" + +/* For basename */ +#ifdef HAVE_LIBGEN_H +#include +#endif +#include /* isspace() */ + +#include +#include + +#ifdef _MSC_VER +#include "dirent-win32.h" + +static char * +basename_no_ext (char *path) +{ + static char name[_MAX_FNAME + 1]; + + _splitpath (path, NULL, NULL, name, NULL); + + name[_MAX_FNAME] = '\0'; + + return name; +} + + +#else +#include + +static char * +basename_no_ext (char *path) +{ + char *dot, *name; + + name = basename (path); + + dot = strrchr (name, '.'); + if (dot) + *dot = '\0'; + + return name; +} + +#endif + +#if HAVE_UNISTD_H +#include +#endif + +#include + +#if HAVE_FCFINI +#include +#endif + +#define CAIRO_PERF_ITERATIONS_DEFAULT 15 +#define CAIRO_PERF_LOW_STD_DEV 0.05 +#define CAIRO_PERF_MIN_STD_DEV_COUNT 3 +#define CAIRO_PERF_STABLE_STD_DEV_COUNT 3 + +struct trace { + const cairo_boilerplate_target_t *target; + void *closure; + cairo_surface_t *surface; + cairo_bool_t observe; + int tile_size; +}; + +cairo_bool_t +cairo_perf_can_run (cairo_perf_t *perf, + const char *name, + cairo_bool_t *is_explicit) +{ + unsigned int i; + char *copy, *dot; + cairo_bool_t ret; + + if (is_explicit) + *is_explicit = FALSE; + + if (perf->exact_names) { + if (is_explicit) + *is_explicit = TRUE; + return TRUE; + } + + if (perf->num_names == 0 && perf->num_exclude_names == 0) + return TRUE; + + copy = xstrdup (name); + dot = strrchr (copy, '.'); + if (dot != NULL) + *dot = '\0'; + + if (perf->num_names) { + ret = TRUE; + for (i = 0; i < perf->num_names; i++) + if (strstr (copy, perf->names[i])) { + if (is_explicit) + *is_explicit = strcmp (copy, perf->names[i]) == 0; + goto check_exclude; + } + + ret = FALSE; + goto done; + } + +check_exclude: + if (perf->num_exclude_names) { + ret = FALSE; + for (i = 0; i < perf->num_exclude_names; i++) + if (strstr (copy, perf->exclude_names[i])) { + if (is_explicit) + *is_explicit = strcmp (copy, perf->exclude_names[i]) == 0; + goto done; + } + + ret = TRUE; + goto done; + } + +done: + free (copy); + + return ret; +} + +static void +fill_surface (cairo_surface_t *surface) +{ + cairo_t *cr = cairo_create (surface); + /* This needs to be an operation that the backends can't optimise away */ + cairo_set_source_rgba (cr, 0.5, 0.5, 0.5, 0.5); + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_paint (cr); + cairo_destroy (cr); +} + +struct scache { + cairo_hash_entry_t entry; + cairo_content_t content; + int width, height; + cairo_surface_t *surface; +}; + +static cairo_hash_table_t *surface_cache; +static cairo_surface_t *surface_holdovers[16]; + +static cairo_bool_t +scache_equal (const void *A, + const void *B) +{ + const struct scache *a = A, *b = B; + return a->entry.hash == b->entry.hash; +} + +static void +scache_mark_active (cairo_surface_t *surface) +{ + cairo_surface_t *t0, *t1; + unsigned n; + + if (surface_cache == NULL) + return; + + t0 = cairo_surface_reference (surface); + for (n = 0; n < ARRAY_LENGTH (surface_holdovers); n++) { + if (surface_holdovers[n] == surface) { + surface_holdovers[n] = t0; + t0 = surface; + break; + } + + t1 = surface_holdovers[n]; + surface_holdovers[n] = t0; + t0 = t1; + } + cairo_surface_destroy (t0); +} + +static void +scache_clear (void) +{ + unsigned n; + + if (surface_cache == NULL) + return; + + for (n = 0; n < ARRAY_LENGTH (surface_holdovers); n++) { + cairo_surface_destroy (surface_holdovers[n]); + surface_holdovers[n] = NULL; + } +} + +static void +scache_remove (void *closure) +{ + _cairo_hash_table_remove (surface_cache, closure); + free (closure); +} + +static cairo_surface_t * +_similar_surface_create (void *closure, + cairo_content_t content, + double width, + double height, + long uid) +{ + struct trace *args = closure; + cairo_surface_t *surface; + struct scache skey, *s; + + if (args->observe) + return cairo_surface_create_similar (args->surface, + content, width, height); + + if (uid == 0 || surface_cache == NULL) + return args->target->create_similar (args->surface, content, width, height); + + skey.entry.hash = uid; + s = _cairo_hash_table_lookup (surface_cache, &skey.entry); + if (s != NULL) { + if (s->content == content && + s->width == width && + s->height == height) + { + return cairo_surface_reference (s->surface); + } + + /* The surface has been resized, allow the original entry to expire + * as it becomes inactive. + */ + } + + surface = args->target->create_similar (args->surface, content, width, height); + s = malloc (sizeof (struct scache)); + if (s == NULL) + return surface; + + s->entry.hash = uid; + s->content = content; + s->width = width; + s->height = height; + s->surface = surface; + if (_cairo_hash_table_insert (surface_cache, &s->entry)) { + free (s); + } else if (cairo_surface_set_user_data + (surface, + (const cairo_user_data_key_t *) &surface_cache, + s, scache_remove)) + { + scache_remove (s); + } + + return surface; +} + +static cairo_surface_t * +_source_image_create (void *closure, + cairo_format_t format, + int width, + int height, + long uid) +{ + struct trace *args = closure; + + return cairo_surface_create_similar_image (args->surface, + format, width, height); +} + +static cairo_t * +_context_create (void *closure, + cairo_surface_t *surface) +{ + scache_mark_active (surface); + return cairo_create (surface); +} + +static int user_interrupt; + +static void +interrupt (int sig) +{ + if (user_interrupt) { + signal (sig, SIG_DFL); + raise (sig); + } + + user_interrupt = 1; +} + +static void +describe (cairo_perf_t *perf, + void *closure) +{ + char *description = NULL; + + if (perf->has_described_backend) + return; + perf->has_described_backend = TRUE; + + if (perf->target->describe) + description = perf->target->describe (closure); + + if (description == NULL) + return; + + if (perf->raw) { + printf ("[ # ] %s: %s\n", perf->target->name, description); + } + + if (perf->summary) { + fprintf (perf->summary, + "[ # ] %8s: %s\n", + perf->target->name, + description); + } + + free (description); +} + +static void +usage (const char *argv0) +{ + fprintf (stderr, +"Usage: %s [-clrsv] [-i iterations] [-t tile-size] [-x exclude-file] [test-names ... | traces ...]\n" +"\n" +"Run the cairo performance test suite over the given tests (all by default)\n" +"The command-line arguments are interpreted as follows:\n" +"\n" +" -c use surface cache; keep a cache of surfaces to be reused\n" +" -i iterations; specify the number of iterations per test case\n" +" -l list only; just list selected test case names without executing\n" +" -r raw; display each time measurement instead of summary statistics\n" +" -s sync; only sum the elapsed time of the individual operations\n" +" -t tile size; draw to tiled surfaces\n" +" -v verbose; in raw mode also show the summaries\n" +" -x exclude; specify a file to read a list of traces to exclude\n" +"\n" +"If test names are given they are used as sub-string matches so a command\n" +"such as \"%s firefox\" can be used to run all firefox traces.\n" +"Alternatively, you can specify a list of filenames to execute.\n", + argv0, argv0); +} + +static cairo_bool_t +read_excludes (cairo_perf_t *perf, + const char *filename) +{ + FILE *file; + char *line = NULL; + size_t line_size = 0; + char *s, *t; + + file = fopen (filename, "r"); + if (file == NULL) + return FALSE; + + while (getline (&line, &line_size, file) != -1) { + /* terminate the line at a comment marker '#' */ + s = strchr (line, '#'); + if (s) + *s = '\0'; + + /* whitespace delimits */ + s = line; + while (*s != '\0' && isspace ((unsigned char)*s)) + s++; + + t = s; + while (*t != '\0' && ! isspace ((unsigned char)*t)) + t++; + + if (s != t) { + int i = perf->num_exclude_names; + perf->exclude_names = xrealloc (perf->exclude_names, + sizeof (char *) * (i+1)); + perf->exclude_names[i] = strndup (s, t-s); + perf->num_exclude_names++; + } + } + free (line); + + fclose (file); + + return TRUE; +} + +static void +parse_options (cairo_perf_t *perf, + int argc, + char *argv[]) +{ + int c; + const char *iters; + char *end; + int verbose = 0; + int use_surface_cache = 0; + + if ((iters = getenv ("CAIRO_PERF_ITERATIONS")) && *iters) + perf->iterations = strtol (iters, NULL, 0); + else + perf->iterations = CAIRO_PERF_ITERATIONS_DEFAULT; + perf->exact_iterations = 0; + + perf->raw = FALSE; + perf->observe = FALSE; + perf->list_only = FALSE; + perf->tile_size = 0; + perf->names = NULL; + perf->num_names = 0; + perf->summary = stdout; + perf->summary_continuous = FALSE; + perf->exclude_names = NULL; + perf->num_exclude_names = 0; + + while (1) { + c = _cairo_getopt (argc, argv, "ci:lrst:vx:"); + if (c == -1) + break; + + switch (c) { + case 'c': + use_surface_cache = 1; + break; + case 'i': + perf->exact_iterations = TRUE; + perf->iterations = strtoul (optarg, &end, 10); + if (*end != '\0') { + fprintf (stderr, "Invalid argument for -i (not an integer): %s\n", + optarg); + exit (1); + } + break; + case 'l': + perf->list_only = TRUE; + break; + case 'r': + perf->raw = TRUE; + perf->summary = NULL; + break; + case 's': + perf->observe = TRUE; + break; + case 't': + perf->tile_size = strtoul (optarg, &end, 10); + if (*end != '\0') { + fprintf (stderr, "Invalid argument for -t (not an integer): %s\n", + optarg); + exit (1); + } + break; + case 'v': + verbose = 1; + break; + case 'x': + if (! read_excludes (perf, optarg)) { + fprintf (stderr, "Invalid argument for -x (not readable file): %s\n", + optarg); + exit (1); + } + break; + default: + fprintf (stderr, "Internal error: unhandled option: %c\n", c); + /* fall-through */ + case '?': + usage (argv[0]); + exit (1); + } + } + + if (perf->observe && perf->tile_size) { + fprintf (stderr, "Can't mix observer and tiling. Sorry.\n"); + exit (1); + } + + if (verbose && perf->summary == NULL) + perf->summary = stderr; +#if HAVE_UNISTD_H + if (perf->summary && isatty (fileno (perf->summary))) + perf->summary_continuous = TRUE; +#endif + + if (optind < argc) { + perf->names = &argv[optind]; + perf->num_names = argc - optind; + } + + if (use_surface_cache) + surface_cache = _cairo_hash_table_create (scache_equal); +} + +static void +cairo_perf_fini (cairo_perf_t *perf) +{ + cairo_boilerplate_free_targets (perf->targets); + cairo_boilerplate_fini (); + + free (perf->times); + cairo_debug_reset_static_data (); +#if HAVE_FCFINI + FcFini (); +#endif +} + +static cairo_bool_t +have_trace_filenames (cairo_perf_t *perf) +{ + unsigned int i; + + if (perf->num_names == 0) + return FALSE; + +#if HAVE_UNISTD_H + for (i = 0; i < perf->num_names; i++) + if (access (perf->names[i], R_OK) == 0) + return TRUE; +#endif + + return FALSE; +} + +static void +_tiling_surface_finish (cairo_surface_t *observer, + cairo_surface_t *target, + void *closure) +{ + struct trace *args = closure; + cairo_surface_t *surface; + cairo_content_t content; + cairo_rectangle_t r; + int width, height; + int x, y, w, h; + + cairo_recording_surface_get_extents (target, &r); + w = r.width; + h = r.height; + + content = cairo_surface_get_content (target); + + for (y = 0; y < h; y += args->tile_size) { + height = args->tile_size; + if (y + height > h) + height = h - y; + + for (x = 0; x < w; x += args->tile_size) { + cairo_t *cr; + + width = args->tile_size; + if (x + width > w) + width = w - x; + + /* XXX to correctly observe the playback we would need + * to replay the target onto the observer directly. + */ + surface = args->target->create_similar (args->surface, + content, width, height); + + cr = cairo_create (surface); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_surface (cr, target, -x, -y); + cairo_paint (cr); + cairo_destroy (cr); + + cairo_surface_destroy (surface); + } + } +} + +static cairo_surface_t * +_tiling_surface_create (void *closure, + cairo_content_t content, + double width, + double height, + long uid) +{ + cairo_rectangle_t r; + cairo_surface_t *surface, *observer; + + r.x = r.y = 0; + r.width = width; + r.height = height; + + surface = cairo_recording_surface_create (content, &r); + observer = cairo_surface_create_observer (surface, + CAIRO_SURFACE_OBSERVER_NORMAL); + cairo_surface_destroy (surface); + + cairo_surface_observer_add_finish_callback (observer, + _tiling_surface_finish, + closure); + + return observer; +} + +static void +cairo_perf_trace (cairo_perf_t *perf, + const cairo_boilerplate_target_t *target, + const char *trace) +{ + static cairo_bool_t first_run = TRUE; + unsigned int i; + cairo_time_t *times, *paint, *mask, *fill, *stroke, *glyphs; + cairo_stats_t stats = {0.0, 0.0}; + struct trace args = { target }; + int low_std_dev_count; + char *trace_cpy, *name; + const cairo_script_interpreter_hooks_t hooks = { + &args, + perf->tile_size ? _tiling_surface_create : _similar_surface_create, + NULL, /* surface_destroy */ + _context_create, + NULL, /* context_destroy */ + NULL, /* show_page */ + NULL, /* copy_page */ + _source_image_create, + }; + + args.tile_size = perf->tile_size; + args.observe = perf->observe; + + trace_cpy = xstrdup (trace); + name = basename_no_ext (trace_cpy); + + if (perf->list_only) { + printf ("%s\n", name); + free (trace_cpy); + return; + } + + if (first_run) { + if (perf->raw) { + printf ("[ # ] %s.%-s %s %s %s ...\n", + "backend", "content", "test-size", "ticks-per-ms", "time(ticks)"); + } + + if (perf->summary) { + if (perf->observe) { + fprintf (perf->summary, + "[ # ] %8s %28s %9s %9s %9s %9s %9s %9s %5s\n", + "backend", "test", + "total(s)", "paint(s)", "mask(s)", "fill(s)", "stroke(s)", "glyphs(s)", + "count"); + } else { + fprintf (perf->summary, + "[ # ] %8s %28s %8s %5s %5s %s\n", + "backend", "test", "min(s)", "median(s)", + "stddev.", "count"); + } + } + first_run = FALSE; + } + + times = perf->times; + paint = times + perf->iterations; + mask = paint + perf->iterations; + stroke = mask + perf->iterations; + fill = stroke + perf->iterations; + glyphs = fill + perf->iterations; + + low_std_dev_count = 0; + for (i = 0; i < perf->iterations && ! user_interrupt; i++) { + cairo_script_interpreter_t *csi; + cairo_status_t status; + unsigned int line_no; + + args.surface = target->create_surface (NULL, + CAIRO_CONTENT_COLOR_ALPHA, + 1, 1, + 1, 1, + CAIRO_BOILERPLATE_MODE_PERF, + &args.closure); + fill_surface(args.surface); /* remove any clear flags */ + + if (perf->observe) { + cairo_surface_t *obs; + obs = cairo_surface_create_observer (args.surface, + CAIRO_SURFACE_OBSERVER_NORMAL); + cairo_surface_destroy (args.surface); + args.surface = obs; + } + if (cairo_surface_status (args.surface)) { + fprintf (stderr, + "Error: Failed to create target surface: %s\n", + target->name); + return; + } + + cairo_perf_timer_set_synchronize (target->synchronize, args.closure); + + if (i == 0) { + describe (perf, args.closure); + if (perf->summary) { + fprintf (perf->summary, + "[%3d] %8s %28s ", + perf->test_number, + perf->target->name, + name); + fflush (perf->summary); + } + } + + csi = cairo_script_interpreter_create (); + cairo_script_interpreter_install_hooks (csi, &hooks); + + if (! perf->observe) { + cairo_perf_yield (); + cairo_perf_timer_start (); + } + + cairo_script_interpreter_run (csi, trace); + line_no = cairo_script_interpreter_get_line_number (csi); + + /* Finish before querying timings in case we are using an intermediate + * target and so need to destroy all surfaces before rendering + * commences. + */ + cairo_script_interpreter_finish (csi); + + if (perf->observe) { + cairo_device_t *observer = cairo_surface_get_device (args.surface); + times[i] = _cairo_time_from_s (1.e-9 * cairo_device_observer_elapsed (observer)); + paint[i] = _cairo_time_from_s (1.e-9 * cairo_device_observer_paint_elapsed (observer)); + mask[i] = _cairo_time_from_s (1.e-9 * cairo_device_observer_mask_elapsed (observer)); + stroke[i] = _cairo_time_from_s (1.e-9 * cairo_device_observer_stroke_elapsed (observer)); + fill[i] = _cairo_time_from_s (1.e-9 * cairo_device_observer_fill_elapsed (observer)); + glyphs[i] = _cairo_time_from_s (1.e-9 * cairo_device_observer_glyphs_elapsed (observer)); + } else { + fill_surface (args.surface); /* queue a write to the sync'ed surface */ + cairo_perf_timer_stop (); + times[i] = cairo_perf_timer_elapsed (); + } + + scache_clear (); + + cairo_surface_destroy (args.surface); + + if (target->cleanup) + target->cleanup (args.closure); + + status = cairo_script_interpreter_destroy (csi); + if (status) { + if (perf->summary) { + fprintf (perf->summary, "Error during replay, line %d: %s\n", + line_no, + cairo_status_to_string (status)); + } + goto out; + } + + if (perf->raw) { + if (i == 0) + printf ("[*] %s.%s %s.%d %g", + perf->target->name, + "rgba", + name, + 0, + _cairo_time_to_double (_cairo_time_from_s (1)) / 1000.); + printf (" %lld", (long long) times[i]); + fflush (stdout); + } else if (! perf->exact_iterations) { + if (i > CAIRO_PERF_MIN_STD_DEV_COUNT) { + _cairo_stats_compute (&stats, times, i+1); + + if (stats.std_dev <= CAIRO_PERF_LOW_STD_DEV) { + if (++low_std_dev_count >= CAIRO_PERF_STABLE_STD_DEV_COUNT) + break; + } else { + low_std_dev_count = 0; + } + } + } + + if (perf->summary && perf->summary_continuous) { + _cairo_stats_compute (&stats, times, i+1); + + fprintf (perf->summary, + "\r[%3d] %8s %28s ", + perf->test_number, + perf->target->name, + name); + if (perf->observe) { + fprintf (perf->summary, + " %#9.3f", _cairo_time_to_s (stats.median_ticks)); + + _cairo_stats_compute (&stats, paint, i+1); + fprintf (perf->summary, + " %#9.3f", _cairo_time_to_s (stats.median_ticks)); + + _cairo_stats_compute (&stats, mask, i+1); + fprintf (perf->summary, + " %#9.3f", _cairo_time_to_s (stats.median_ticks)); + + _cairo_stats_compute (&stats, fill, i+1); + fprintf (perf->summary, + " %#9.3f", _cairo_time_to_s (stats.median_ticks)); + + _cairo_stats_compute (&stats, stroke, i+1); + fprintf (perf->summary, + " %#9.3f", _cairo_time_to_s (stats.median_ticks)); + + _cairo_stats_compute (&stats, glyphs, i+1); + fprintf (perf->summary, + " %#9.3f", _cairo_time_to_s (stats.median_ticks)); + + fprintf (perf->summary, + " %5d", i+1); + } else { + fprintf (perf->summary, + "%#8.3f %#8.3f %#6.2f%% %4d/%d", + _cairo_time_to_s (stats.min_ticks), + _cairo_time_to_s (stats.median_ticks), + stats.std_dev * 100.0, + stats.iterations, i+1); + } + fflush (perf->summary); + } + } + user_interrupt = 0; + + if (perf->summary) { + _cairo_stats_compute (&stats, times, i); + if (perf->summary_continuous) { + fprintf (perf->summary, + "\r[%3d] %8s %28s ", + perf->test_number, + perf->target->name, + name); + } + if (perf->observe) { + fprintf (perf->summary, + " %#9.3f", _cairo_time_to_s (stats.median_ticks)); + + _cairo_stats_compute (&stats, paint, i); + fprintf (perf->summary, + " %#9.3f", _cairo_time_to_s (stats.median_ticks)); + + _cairo_stats_compute (&stats, mask, i); + fprintf (perf->summary, + " %#9.3f", _cairo_time_to_s (stats.median_ticks)); + + _cairo_stats_compute (&stats, fill, i); + fprintf (perf->summary, + " %#9.3f", _cairo_time_to_s (stats.median_ticks)); + + _cairo_stats_compute (&stats, stroke, i); + fprintf (perf->summary, + " %#9.3f", _cairo_time_to_s (stats.median_ticks)); + + _cairo_stats_compute (&stats, glyphs, i); + fprintf (perf->summary, + " %#9.3f", _cairo_time_to_s (stats.median_ticks)); + + fprintf (perf->summary, + " %5d\n", i); + } else { + fprintf (perf->summary, + "%#8.3f %#8.3f %#6.2f%% %4d/%d\n", + _cairo_time_to_s (stats.min_ticks), + _cairo_time_to_s (stats.median_ticks), + stats.std_dev * 100.0, + stats.iterations, i); + } + fflush (perf->summary); + } + +out: + if (perf->raw) { + printf ("\n"); + fflush (stdout); + } + + perf->test_number++; + free (trace_cpy); +} + +static void +warn_no_traces (const char *message, + const char *trace_dir) +{ + fprintf (stderr, +"Error: %s '%s'.\n" +"Have you cloned the cairo-traces repository and uncompressed the traces?\n" +" git clone git://anongit.freedesktop.org/cairo-traces\n" +" cd cairo-traces && make\n" +"Or set the env.var CAIRO_TRACE_DIR to point to your traces?\n", + message, trace_dir); +} + +static int +cairo_perf_trace_dir (cairo_perf_t *perf, + const cairo_boilerplate_target_t *target, + const char *dirname) +{ + DIR *dir; + struct dirent *de; + int num_traces = 0; + cairo_bool_t force; + cairo_bool_t is_explicit; + + dir = opendir (dirname); + if (dir == NULL) + return 0; + + force = FALSE; + if (cairo_perf_can_run (perf, dirname, &is_explicit)) + force = is_explicit; + + while ((de = readdir (dir)) != NULL) { + char *trace; + struct stat st; + + if (de->d_name[0] == '.') + continue; + + xasprintf (&trace, "%s/%s", dirname, de->d_name); + if (stat (trace, &st) != 0) + goto next; + + if (S_ISDIR(st.st_mode)) { + num_traces += cairo_perf_trace_dir (perf, target, trace); + } else { + const char *dot; + + dot = strrchr (de->d_name, '.'); + if (dot == NULL) + goto next; + if (strcmp (dot, ".trace")) + goto next; + + num_traces++; + if (!force && ! cairo_perf_can_run (perf, de->d_name, NULL)) + goto next; + + cairo_perf_trace (perf, target, trace); + } +next: + free (trace); + + } + closedir (dir); + + return num_traces; +} + +int +main (int argc, + char *argv[]) +{ + cairo_perf_t perf; + const char *trace_dir = "cairo-traces:/usr/src/cairo-traces:/usr/share/cairo-traces"; + unsigned int n; + int i; + + parse_options (&perf, argc, argv); + + signal (SIGINT, interrupt); + + if (getenv ("CAIRO_TRACE_DIR") != NULL) + trace_dir = getenv ("CAIRO_TRACE_DIR"); + + perf.targets = cairo_boilerplate_get_targets (&perf.num_targets, NULL); + perf.times = xmalloc (6 * perf.iterations * sizeof (cairo_time_t)); + + /* do we have a list of filenames? */ + perf.exact_names = have_trace_filenames (&perf); + + for (i = 0; i < perf.num_targets; i++) { + const cairo_boilerplate_target_t *target = perf.targets[i]; + + if (! perf.list_only && ! target->is_measurable) + continue; + + perf.target = target; + perf.test_number = 0; + perf.has_described_backend = FALSE; + + if (perf.exact_names) { + for (n = 0; n < perf.num_names; n++) { + struct stat st; + + if (stat (perf.names[n], &st) == 0) { + if (S_ISDIR (st.st_mode)) { + cairo_perf_trace_dir (&perf, target, perf.names[n]); + } else + cairo_perf_trace (&perf, target, perf.names[n]); + } + } + } else { + int num_traces = 0; + const char *dir; + + dir = trace_dir; + do { + char buf[1024]; + const char *end = strchr (dir, ':'); + if (end != NULL) { + memcpy (buf, dir, end-dir); + buf[end-dir] = '\0'; + end++; + + dir = buf; + } + + num_traces += cairo_perf_trace_dir (&perf, target, dir); + dir = end; + } while (dir != NULL); + + if (num_traces == 0) { + warn_no_traces ("Found no traces in", trace_dir); + return 1; + } + } + + if (perf.list_only) + break; + } + + cairo_perf_fini (&perf); + + return 0; +} diff --git a/local/recipes/libs/cairo/source/perf/cairo-perf.c b/local/recipes/libs/cairo/source/perf/cairo-perf.c new file mode 100644 index 0000000000..244d6cb744 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/cairo-perf.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2007 Netlabs + * Copyright (c) 2006 Mozilla Corporation + * Copyright (c) 2006 Red Hat, Inc. + * Copyright (c) 2011 Andrea Canciani + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * the authors not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. The authors make no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Peter Weilbacher + * Vladimir Vukicevic (win32/linux code) + * Carl Worth (win32/linux code) + * Andrea Canciani + */ + +#include "cairo-perf.h" +#include "../src/cairo-time-private.h" + +#if HAVE_UNISTD_H +#include +#endif + +#if defined(_WIN32) +#include +#elif defined(_POSIX_PRIORITY_SCHEDULING) +#include +#endif + + +/* timers */ +static cairo_time_t timer; +static cairo_perf_timer_synchronize_t cairo_perf_timer_synchronize = NULL; +static void *cairo_perf_timer_synchronize_closure = NULL; + +void +cairo_perf_timer_set_synchronize (cairo_perf_timer_synchronize_t synchronize, + void *closure) +{ + cairo_perf_timer_synchronize = synchronize; + cairo_perf_timer_synchronize_closure = closure; +} + +void +cairo_perf_timer_start (void) +{ + timer = _cairo_time_get (); +} + +void +cairo_perf_timer_stop (void) +{ + if (cairo_perf_timer_synchronize) + cairo_perf_timer_synchronize (cairo_perf_timer_synchronize_closure); + + timer = _cairo_time_get_delta (timer); +} + +cairo_time_t +cairo_perf_timer_elapsed (void) +{ + return timer; +} + +void +cairo_perf_yield (void) +{ + /* try to deactivate this thread until the scheduler calls it again */ + +#if defined(_WIN32) + SleepEx(0, TRUE); +#elif defined(_POSIX_PRIORITY_SCHEDULING) + sched_yield (); +#else + sleep (0); +#endif +} diff --git a/local/recipes/libs/cairo/source/perf/cairo-perf.h b/local/recipes/libs/cairo/source/perf/cairo-perf.h new file mode 100644 index 0000000000..eb53d13c27 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/cairo-perf.h @@ -0,0 +1,250 @@ +/* + * Copyright © 2006 Mozilla Corporation + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * the authors not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. The authors make no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Vladimir Vukicevic + * Carl Worth + */ + +#ifndef _CAIRO_PERF_H_ +#define _CAIRO_PERF_H_ + +#include "cairo-boilerplate.h" +#include "../src/cairo-time-private.h" +#include + +typedef struct _cairo_stats { + cairo_time_t min_ticks; + cairo_time_t median_ticks; + double ticks_per_ms; + double std_dev; + int iterations; + cairo_time_t *values; +} cairo_stats_t; + +typedef struct _cairo_histogram { + int width, height, max_count; + int num_columns, num_rows; + cairo_time_t min_value, max_value; + int *columns; +} cairo_histogram_t; + + +/* timers */ + +void +cairo_perf_timer_start (void); + +void +cairo_perf_timer_stop (void); + +typedef void +(*cairo_perf_timer_synchronize_t) (void *closure); + +void +cairo_perf_timer_set_synchronize (cairo_perf_timer_synchronize_t synchronize, + void *closure); + +cairo_time_t +cairo_perf_timer_elapsed (void); + +/* yield */ + +void +cairo_perf_yield (void); + +/* running a test case */ +typedef struct _cairo_perf { + FILE *summary; + cairo_bool_t summary_continuous; + + /* Options from command-line */ + unsigned int iterations; + cairo_bool_t exact_iterations; + cairo_bool_t raw; + cairo_bool_t list_only; + cairo_bool_t observe; + char **names; + unsigned int num_names; + char **exclude_names; + unsigned int num_exclude_names; + cairo_bool_t exact_names; + + double ms_per_iteration; + cairo_bool_t fast_and_sloppy; + + unsigned int tile_size; + + /* Stuff used internally */ + cairo_time_t *times; + const cairo_boilerplate_target_t **targets; + int num_targets; + const cairo_boilerplate_target_t *target; + cairo_bool_t has_described_backend; + unsigned int test_number; + unsigned int size; + cairo_t *cr; +} cairo_perf_t; + +typedef cairo_time_t +(*cairo_perf_func_t) (cairo_t *cr, int width, int height, int loops); + +typedef double +(*cairo_count_func_t) (cairo_t *cr, int width, int height); + +cairo_bool_t +cairo_perf_can_run (cairo_perf_t *perf, + const char *name, + cairo_bool_t *is_explicit); + +void +cairo_perf_run (cairo_perf_t *perf, + const char *name, + cairo_perf_func_t perf_func, + cairo_count_func_t count_func); + +void +cairo_perf_cover_sources_and_operators (cairo_perf_t *perf, + const char *name, + cairo_perf_func_t perf_func, + cairo_count_func_t count_func); + +/* reporter convenience routines */ + +typedef struct _test_report { + int id; + int fileno; + const char *configuration; + char *backend; + char *content; + char *name; + int size; + + /* The samples only exists for "raw" reports */ + cairo_time_t *samples; + unsigned int samples_size; + unsigned int samples_count; + + /* The stats are either read directly or computed from samples. + * If the stats have not yet been computed from samples, then + * iterations will be 0. */ + cairo_stats_t stats; +} test_report_t; + +typedef struct _test_diff { + test_report_t **tests; + int num_tests; + double min; + double max; + double change; +} test_diff_t; + +typedef struct _cairo_perf_report { + char *configuration; + const char *name; + int fileno; + test_report_t *tests; + int tests_size; + int tests_count; +} cairo_perf_report_t; + +typedef enum { + TEST_REPORT_STATUS_SUCCESS, + TEST_REPORT_STATUS_COMMENT, + TEST_REPORT_STATUS_ERROR +} test_report_status_t; + +void +cairo_perf_report_load (cairo_perf_report_t *report, + const char *filename, int id, + int (*cmp) (const void *, const void *)); + +void +cairo_perf_report_sort_and_compute_stats (cairo_perf_report_t *report, + int (*cmp) (const void *, const void *)); + +int +test_report_cmp_backend_then_name (const void *a, + const void *b); + +int +test_report_cmp_name (const void *a, + const void *b); + +#define CAIRO_PERF_ENABLED_DECL(func) cairo_bool_t (func ## _enabled) (cairo_perf_t *perf) +#define CAIRO_PERF_RUN_DECL(func) void (func) (cairo_perf_t *perf, cairo_t *cr, int width, int height) + +#define CAIRO_PERF_DECL(func) CAIRO_PERF_RUN_DECL(func); CAIRO_PERF_ENABLED_DECL(func) + +#ifndef MIN +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef MAX +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + +CAIRO_PERF_DECL (fill); +CAIRO_PERF_DECL (paint); +CAIRO_PERF_DECL (paint_with_alpha); +CAIRO_PERF_DECL (mask); +CAIRO_PERF_DECL (stroke); +CAIRO_PERF_DECL (subimage_copy); +CAIRO_PERF_DECL (disjoint); +CAIRO_PERF_DECL (hatching); +CAIRO_PERF_DECL (tessellate); +CAIRO_PERF_DECL (text); +CAIRO_PERF_DECL (glyphs); +CAIRO_PERF_DECL (hash_table); +CAIRO_PERF_DECL (pattern_create_radial); +CAIRO_PERF_DECL (zrusin); +CAIRO_PERF_DECL (world_map); +CAIRO_PERF_DECL (box_outline); +CAIRO_PERF_DECL (mosaic); +CAIRO_PERF_DECL (long_lines); +CAIRO_PERF_DECL (unaligned_clip); +CAIRO_PERF_DECL (rectangles); +CAIRO_PERF_DECL (rounded_rectangles); +CAIRO_PERF_DECL (long_dashed_lines); +CAIRO_PERF_DECL (composite_checker); +CAIRO_PERF_DECL (twin); +CAIRO_PERF_DECL (dragon); +CAIRO_PERF_DECL (pythagoras_tree); +CAIRO_PERF_DECL (intersections); +CAIRO_PERF_DECL (spiral); +CAIRO_PERF_DECL (wave); +CAIRO_PERF_DECL (many_strokes); +CAIRO_PERF_DECL (wide_strokes); +CAIRO_PERF_DECL (many_fills); +CAIRO_PERF_DECL (wide_fills); +CAIRO_PERF_DECL (many_curves); +CAIRO_PERF_DECL (curve); +CAIRO_PERF_DECL (a1_curve); +CAIRO_PERF_DECL (line); +CAIRO_PERF_DECL (a1_line); +CAIRO_PERF_DECL (pixel); +CAIRO_PERF_DECL (a1_pixel); +CAIRO_PERF_DECL (sierpinski); +CAIRO_PERF_DECL (fill_clip); +CAIRO_PERF_DECL (tiger); + +#endif diff --git a/local/recipes/libs/cairo/source/perf/cairo-stats.c b/local/recipes/libs/cairo/source/perf/cairo-stats.c new file mode 100644 index 0000000000..aee9fe8b56 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/cairo-stats.c @@ -0,0 +1,182 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * the authors not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. The authors make no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Carl Worth + */ + +#include "cairo-stats.h" + +#include + +void +_cairo_stats_compute (cairo_stats_t *stats, + cairo_time_t *values, + int num_values) +{ + cairo_time_t sum, mean, q1, q3, iqr; + cairo_time_t outlier_min, outlier_max; + int i, min_valid, num_valid; + double s; + + assert (num_values > 0); + + if (num_values == 1) { + stats->min_ticks = stats->median_ticks = values[0]; + stats->std_dev = 0; + stats->iterations = 1; + stats->values = values; + return; + } + + /* First, identify any outliers, using the definition of "mild + * outliers" from: + * + * http://en.wikipedia.org/wiki/Outliers + * + * Which is that outliers are any values less than Q1 - 1.5 * IQR + * or greater than Q3 + 1.5 * IQR where Q1 and Q3 are the first + * and third quartiles and IQR is the inter-quartile range (Q3 - + * Q1). + */ + num_valid = num_values; + do { + num_values = num_valid; + qsort (values, num_values, sizeof (cairo_time_t), _cairo_time_cmp); + + q1 = values[1*num_values/4]; + q3 = values[3*num_values/4]; + + /* XXX assumes we have native uint64_t */ + iqr = q3 - q1; + outlier_min = q1 - 3 * iqr / 2; + outlier_max = q3 + 3 * iqr / 2; + + for (i = 0; i < num_values && values[i] < outlier_min; i++) + ; + min_valid = i; + + for (i = 0; i < num_values && values[i] <= outlier_max; i++) + ; + num_valid = i - min_valid; + assert(num_valid); + values += min_valid; + } while (num_valid != num_values); + + stats->values = values; + stats->iterations = num_valid; + stats->min_ticks = values[0]; + stats->median_ticks = values[num_valid / 2]; + + sum = 0; + for (i = 0; i < num_valid; i++) + sum = _cairo_time_add (sum, values[i]); + mean = sum / num_valid; + + /* Let's use a normalized std. deviation for easier comparison. */ + s = 0; + for (i = 0; i < num_valid; i++) { + double delta = (values[i] - mean) / (double)mean; + s += delta * delta; + } + stats->std_dev = sqrt(s / num_valid); +} + +cairo_bool_t +_cairo_histogram_init (cairo_histogram_t *h, + int width, int height) +{ + h->width = width; + h->height = height; + if (h->width < 2 || h->height < 1) + return FALSE; + + h->num_columns = width - 2; + h->num_rows = height - 1; + h->columns = malloc (sizeof(int)*h->num_columns); + return h->columns != NULL; +} + +cairo_bool_t +_cairo_histogram_compute (cairo_histogram_t *h, + const cairo_time_t *values, + int num_values) +{ + cairo_time_t delta; + int i; + + if (num_values == 0) + return FALSE; + + h->min_value = values[0]; + h->max_value = values[0]; + + for (i = 1; i < num_values; i++) { + if (values[i] < h->min_value) + h->min_value = values[i]; + if (values[i] > h->max_value) + h->max_value = values[i]; + } + + delta = h->max_value - h->min_value; + if (delta == 0) + return FALSE; + + memset(h->columns, 0, sizeof(int)*h->num_columns); + h->max_count = 0; + + for (i = 0; i < num_values; i++) { + int count = h->columns[(values[i] - h->min_value) * (h->num_columns - 1) / delta]++; + if (count > h->max_count) + h->max_count = count; + } + + return TRUE; +} + +void +_cairo_histogram_printf (cairo_histogram_t *h, + FILE *file) +{ + int x, y, num_rows; + + num_rows = h->num_rows; + if (h->max_count < num_rows) + num_rows = h->max_count; + for (y = 0; y < num_rows; y++) { + int min_count = ((num_rows - y - 1) * h->max_count) / num_rows + h->max_count / (2*num_rows); + fprintf (file, "|"); + for (x = 0; x < h->num_columns; x++) + fprintf (file, "%c", h->columns[x] > min_count ? 'x' : ' '); + fprintf (file, "|\n"); + } + + fprintf(file, "."); + for (x = 0; x < h->num_columns; x++) + fprintf (file, "-"); + fprintf (file, ".\n"); +} + +void +_cairo_histogram_fini (cairo_histogram_t *h) +{ + free(h->columns); +} diff --git a/local/recipes/libs/cairo/source/perf/cairo-stats.h b/local/recipes/libs/cairo/source/perf/cairo-stats.h new file mode 100644 index 0000000000..2b32d67ae3 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/cairo-stats.h @@ -0,0 +1,52 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * the authors not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. The authors make no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Carl Worth + */ + +#ifndef _CAIRO_STATS_H_ +#define _CAIRO_STATS_H_ + +#include "cairo-perf.h" + +void +_cairo_stats_compute (cairo_stats_t *stats, + cairo_time_t *values, + int num_values); + +cairo_bool_t +_cairo_histogram_init (cairo_histogram_t *h, + int width, int height); + +cairo_bool_t +_cairo_histogram_compute (cairo_histogram_t *h, + const cairo_time_t *values, + int num_values); + +void +_cairo_histogram_printf (cairo_histogram_t *h, + FILE *file); + +void +_cairo_histogram_fini (cairo_histogram_t *h); + +#endif /* _CAIRO_STATS_H_ */ diff --git a/local/recipes/libs/cairo/source/perf/dirent-win32.h b/local/recipes/libs/cairo/source/perf/dirent-win32.h new file mode 100644 index 0000000000..435a6cfa2d --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/dirent-win32.h @@ -0,0 +1,101 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright 2011 Andrea Canciani + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * the authors not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. The authors make no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Andrea Canciani + */ + +#include "cairo-compiler-private.h" + +#include + +#define stat _stat + +#define S_ISDIR(s) ((s) & _S_IFDIR) + +struct dirent { + ino_t d_ino; + char d_name[FILENAME_MAX + 1]; +}; + +typedef struct _DIR { + HANDLE handle; + cairo_bool_t has_next; + WIN32_FIND_DATA data; + struct dirent de; +} DIR; + +static DIR * +opendir(const char *dirname) +{ + DIR *dirp; + + dirp = malloc (sizeof (*dirp)); + if (unlikely (dirp == NULL)) + return NULL; + + dirp->handle = FindFirstFile(dirname, &dirp->data); + + if (unlikely (dirp->handle == INVALID_HANDLE_VALUE)) { + free (dirp); + return NULL; + } + + memcpy (dirp->de.d_name, dirp->data.cFileName, + sizeof (dirp->data.cFileName)); + dirp->de.d_name[FILENAME_MAX] = '\0'; + + dirp->has_next = TRUE; + + return dirp; +} + +static int +closedir(DIR *dirp) +{ + int ret; + + ret = ! FindClose (dirp->handle); + + free (dirp); + + /* TODO: set errno */ + + return ret; +} + +static struct dirent * +readdir(DIR *dirp) +{ + if (! dirp->has_next) + return NULL; + + /* COMPILE_TIME_ASSERT (FILENAME_MAX == sizeof (dirp->data.cFileName)); */ + + memcpy (dirp->de.d_name, dirp->data.cFileName, + sizeof (dirp->data.cFileName)); + dirp->de.d_name[FILENAME_MAX] = '\0'; + + dirp->has_next = FindNextFile (dirp->handle, &dirp->data); + + return &dirp->de; +} diff --git a/local/recipes/libs/cairo/source/perf/meson.build b/local/recipes/libs/cairo/source/perf/meson.build new file mode 100644 index 0000000000..d26dd69234 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/meson.build @@ -0,0 +1,94 @@ +incmicro = include_directories('.') + +subdir('micro') + +gtk2_dep = dependency('gtk+-2.0', required: false) + +libcairoperf = static_library('cairoperf', + [ + 'cairo-perf.c', + 'cairo-perf-report.c', + 'cairo-stats.c', + '../src/cairo-time.c', + 'cairo-perf.h', + 'cairo-stats.h', + ], + include_directories: [incbase, incsrc], + dependencies: [pixman_dep, libcairomissing_dep, cairoboilerplate_dep], +) +libcairoperf_dep = declare_dependency( + link_with: libcairoperf, +) + + +analyse_trace = executable('cairo-analyse-trace', + [ + 'cairo-analyse-trace.c', + '../src/cairo-error.c', + ], + include_directories: [incbase], + dependencies: [pixman_dep, fontconfig_dep, libcairo_dep, cairoboilerplate_dep, + libcairoscript_dep, libcairomissing_dep], +) + +perf_trace = executable('cairo-perf-trace', + [ + 'cairo-perf-trace.c', + '../src/cairo-error.c', + '../src/cairo-hash.c', + ], + include_directories: [incbase, incsrc], + dependencies: [pixman_dep, fontconfig_dep, libcairoperf_dep, libcairoscript_dep, + cairoboilerplate_dep, libcairomissing_dep], +) + +micro = executable('cairo-perf-micro', + [ 'cairo-perf-micro.c', ], + include_directories: [incbase, incsrc], + dependencies: [fontconfig_dep, libcairoperf_dep, libcairoperfmicro_dep, + cairoboilerplate_dep, libcairomissing_dep], +) + +diff_files = executable('cairo-perf-diff-files', + [ + 'cairo-perf-diff-files.c', + ], + include_directories: [incbase, incsrc], + dependencies: [libcairoperf_dep, cairoboilerplate_dep], +) + +print = executable('cairo-perf-print', + [ + 'cairo-perf-print.c', + ], + include_directories: [incbase, incsrc], + dependencies: [libcairoperf_dep, cairoboilerplate_dep], +) + +chart = executable('cairo-perf-chart', + [ + 'cairo-perf-chart.c', + ], + include_directories: [incbase, incsrc], + dependencies: [libcairoperf_dep, cairoboilerplate_dep], +) + +compare_backends = executable('cairo-perf-compare-backends', + [ + 'cairo-perf-compare-backends.c', + ], + include_directories: [incbase, incsrc], + dependencies: [libcairoperf_dep, cairoboilerplate_dep], +) + +if gtk2_dep.found() + graph_files = executable('cairo-perf-graph', + [ + 'cairo-perf-graph-files.c', + 'cairo-perf-graph-widget.c', + 'cairo-perf-graph.h', + ], + include_directories: [incbase, incsrc], + dependencies: [gtk2_dep, libcairo_dep, cairoboilerplate_dep, libcairoperf_dep], + ) +endif diff --git a/local/recipes/libs/cairo/source/perf/micro/a1-curve.c b/local/recipes/libs/cairo/source/perf/micro/a1-curve.c new file mode 100644 index 0000000000..594c46d5c8 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/a1-curve.c @@ -0,0 +1,112 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-perf.h" + +static uint32_t state; + +static double +uniform_random (double minval, double maxval) +{ + static uint32_t const poly = 0x9a795537U; + uint32_t n = 32; + while (n-->0) + state = 2*state < state ? (2*state ^ poly) : 2*state; + return minval + state * (maxval - minval) / 4294967296.0; +} + +static cairo_time_t +do_curve_stroke (cairo_t *cr, int width, int height, int loops) +{ + state = 0xc0ffee; + cairo_set_line_width (cr, 2.); + cairo_perf_timer_start (); + + while (loops--) { + double x1 = uniform_random (0, width); + double x2 = uniform_random (0, width); + double x3 = uniform_random (0, width); + double y1 = uniform_random (0, height); + double y2 = uniform_random (0, height); + double y3 = uniform_random (0, height); + cairo_move_to (cr, uniform_random (0, width), uniform_random (0, height)); + cairo_curve_to (cr, x1, y1, x2, y2, x3, y3); + cairo_stroke(cr); + } + + cairo_perf_timer_stop (); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_curve_fill (cairo_t *cr, int width, int height, int loops) +{ + state = 0xc0ffee; + cairo_perf_timer_start (); + + while (loops--) { + double x0 = uniform_random (0, width); + double x1 = uniform_random (0, width); + double x2 = uniform_random (0, width); + double x3 = uniform_random (0, width); + double xm = uniform_random (0, width); + double xn = uniform_random (0, width); + double y0 = uniform_random (0, height); + double y1 = uniform_random (0, height); + double y2 = uniform_random (0, height); + double y3 = uniform_random (0, height); + double ym = uniform_random (0, height); + double yn = uniform_random (0, height); + + cairo_move_to (cr, xm, ym); + cairo_curve_to (cr, x1, y1, x2, y2, xn, yn); + cairo_curve_to (cr, x3, y3, x0, y0, xm, ym); + cairo_close_path (cr); + + cairo_fill(cr); + } + + cairo_perf_timer_stop (); + + return cairo_perf_timer_elapsed (); +} + +cairo_bool_t +a1_curve_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "a1-curve", NULL); +} + +void +a1_curve (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1., 1., 1.); + cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); + + cairo_perf_run (perf, "a1-curve-stroked", do_curve_stroke, NULL); + cairo_perf_run (perf, "a1-curve-filled", do_curve_fill, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/a1-line.c b/local/recipes/libs/cairo/source/perf/micro/a1-line.c new file mode 100644 index 0000000000..ae86602125 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/a1-line.c @@ -0,0 +1,223 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-perf.h" + +static cairo_time_t +horizontal (cairo_t *cr, int width, int height, int loops) +{ + double h = height/2 + .5; + + cairo_move_to (cr, 0, h); + cairo_line_to (cr, width, h); + + cairo_perf_timer_start (); + + while (loops--) + cairo_stroke_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +horizontal_hair (cairo_t *cr, int width, int height, int loops) +{ + cairo_set_line_width (cr, 1.); + return horizontal (cr, width, height, loops); +} + +static cairo_time_t +horizontal_wide (cairo_t *cr, int width, int height, int loops) +{ + cairo_set_line_width (cr, 5.); + return horizontal (cr, width, height, loops); +} + +static cairo_time_t +nearly_horizontal (cairo_t *cr, int width, int height, int loops) +{ + double h = height/2; + + cairo_move_to (cr, 0, h); + cairo_line_to (cr, width, h+1); + + cairo_perf_timer_start (); + + while (loops--) + cairo_stroke_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +nearly_horizontal_hair (cairo_t *cr, int width, int height, int loops) +{ + cairo_set_line_width (cr, 1.); + return nearly_horizontal (cr, width, height, loops); +} + +static cairo_time_t +nearly_horizontal_wide (cairo_t *cr, int width, int height, int loops) +{ + cairo_set_line_width (cr, 5.); + return nearly_horizontal (cr, width, height, loops); +} + + +static cairo_time_t +vertical (cairo_t *cr, int width, int height, int loops) +{ + double w = width/2 + .5; + + cairo_move_to (cr, w, 0); + cairo_line_to (cr, w, height); + + cairo_perf_timer_start (); + + while (loops--) + cairo_stroke_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +vertical_hair (cairo_t *cr, int width, int height, int loops) +{ + cairo_set_line_width (cr, 1.); + return vertical (cr, width, height, loops); +} + +static cairo_time_t +vertical_wide (cairo_t *cr, int width, int height, int loops) +{ + cairo_set_line_width (cr, 5.); + return vertical (cr, width, height, loops); +} + +static cairo_time_t +nearly_vertical (cairo_t *cr, int width, int height, int loops) +{ + double w = width/2; + + cairo_move_to (cr, w, 0); + cairo_line_to (cr, w+1, height); + + cairo_perf_timer_start (); + + while (loops--) + cairo_stroke_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +nearly_vertical_hair (cairo_t *cr, int width, int height, int loops) +{ + cairo_set_line_width (cr, 1.); + return nearly_vertical (cr, width, height, loops); +} + +static cairo_time_t +nearly_vertical_wide (cairo_t *cr, int width, int height, int loops) +{ + cairo_set_line_width (cr, 5.); + return nearly_vertical (cr, width, height, loops); +} + + +static cairo_time_t +diagonal (cairo_t *cr, int width, int height, int loops) +{ + cairo_move_to (cr, 0, 0); + cairo_line_to (cr, width, height); + + cairo_perf_timer_start (); + + while (loops--) + cairo_stroke_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +diagonal_hair (cairo_t *cr, int width, int height, int loops) +{ + cairo_set_line_width (cr, 1.); + return diagonal (cr, width, height, loops); +} + +static cairo_time_t +diagonal_wide (cairo_t *cr, int width, int height, int loops) +{ + cairo_set_line_width (cr, 5.); + return diagonal (cr, width, height, loops); +} + +cairo_bool_t +a1_line_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "a1-line", NULL); +} + +void +a1_line (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1., 1., 1.); + cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); + + cairo_perf_run (perf, "a1-line-hh", horizontal_hair, NULL); + cairo_perf_run (perf, "a1-line-hw", horizontal_wide, NULL); + cairo_perf_run (perf, "a1-line-nhh", nearly_horizontal_hair, NULL); + cairo_perf_run (perf, "a1-line-nhw", nearly_horizontal_wide, NULL); + + cairo_perf_run (perf, "a1-line-vh", vertical_hair, NULL); + cairo_perf_run (perf, "a1-line-vw", vertical_wide, NULL); + cairo_perf_run (perf, "a1-line-nvh", nearly_vertical_hair, NULL); + cairo_perf_run (perf, "a1-line-nvw", nearly_vertical_wide, NULL); + + cairo_perf_run (perf, "a1-line-dh", diagonal_hair, NULL); + cairo_perf_run (perf, "a1-line-dw", diagonal_wide, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/box-outline.c b/local/recipes/libs/cairo/source/perf/micro/box-outline.c new file mode 100644 index 0000000000..1e654eb954 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/box-outline.c @@ -0,0 +1,215 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * + * 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: Carl D. Worth + */ + +#include "cairo-perf.h" + +/* This test case is designed to illustrate a performance bug that + * exists in cairo in which using cairo_stroke is much slower than + * cairo_fill to draw an identical figure, (and in particular a figure + * that is much more natural to draw with cairo_stroke). The figure is + * a 100x100 square outline 1-pixel wide, nicely pixel aligned. + * + * The performance bug should affect any path whose resulting contour + * consists only of pixel-aligned horizontal and vertical elements. + * + * Initial testing on on machine shows stroke as 5x slower than fill + * for the xlib backend and 16x slower for the image backend. + */ + +static cairo_time_t +box_outline_stroke (cairo_t *cr, int width, int height, int loops) +{ + cairo_set_source_rgb (cr, 0, 0, 1); /* blue */ + cairo_paint (cr); + + cairo_rectangle (cr, + 1.5, 1.5, + width - 3, height - 3); + cairo_set_line_width (cr, 1.0); + cairo_set_source_rgb (cr, 1, 0, 0); /* red */ + + cairo_perf_timer_start (); + + while (loops--) + cairo_stroke_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +box_outline_alpha_stroke (cairo_t *cr, int width, int height, int loops) +{ + cairo_set_source_rgb (cr, 0, 0, 1); /* blue */ + cairo_paint (cr); + + cairo_rectangle (cr, + 1.5, 1.5, + width - 3, height - 3); + cairo_set_line_width (cr, 1.0); + cairo_set_source_rgba (cr, 1, 0, 0, .5); /* red */ + + cairo_perf_timer_start (); + + while (loops--) + cairo_stroke_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +box_outline_aa_stroke (cairo_t *cr, int width, int height, int loops) +{ + cairo_set_source_rgb (cr, 0, 0, 1); /* blue */ + cairo_paint (cr); + + cairo_translate (cr, .5, .5); + cairo_rectangle (cr, + 1.5, 1.5, + width - 3, height - 3); + cairo_set_line_width (cr, 1.0); + cairo_set_source_rgb (cr, 1, 0, 0); /* red */ + + cairo_perf_timer_start (); + + while (loops--) + cairo_stroke_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +box_outline_fill (cairo_t *cr, int width, int height, int loops) +{ + cairo_set_source_rgb (cr, 0, 0, 1); /* blue */ + cairo_paint (cr); + + cairo_rectangle (cr, + 1.0, 1.0, + width - 2, height - 2); + cairo_rectangle (cr, + 2.0, 2.0, + width - 4, height - 4); + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + cairo_set_source_rgb (cr, 0, 1, 0); /* green */ + + cairo_perf_timer_start (); + + while (loops--) + cairo_fill_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +box_outline_alpha_fill (cairo_t *cr, int width, int height, int loops) +{ + cairo_set_source_rgb (cr, 0, 0, 1); /* blue */ + cairo_paint (cr); + + cairo_rectangle (cr, + 1.0, 1.0, + width - 2, height - 2); + cairo_rectangle (cr, + 2.0, 2.0, + width - 4, height - 4); + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + cairo_set_source_rgba (cr, 0, 1, 0, .5); /* green */ + + cairo_perf_timer_start (); + + while (loops--) + cairo_fill_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +box_outline_aa_fill (cairo_t *cr, int width, int height, int loops) +{ + cairo_set_source_rgb (cr, 0, 0, 1); /* blue */ + cairo_paint (cr); + + cairo_translate (cr, .5, .5); + cairo_rectangle (cr, + 1.0, 1.0, + width - 2, height - 2); + cairo_rectangle (cr, + 2.0, 2.0, + width - 4, height - 4); + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + cairo_set_source_rgb (cr, 0, 1, 0); /* green */ + + cairo_perf_timer_start (); + + while (loops--) + cairo_fill_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +cairo_bool_t +box_outline_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "box-outline", NULL); +} + +void +box_outline (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_perf_run (perf, "box-outline-stroke", box_outline_stroke, NULL); + cairo_perf_run (perf, "box-outline-fill", box_outline_fill, NULL); + + cairo_perf_run (perf, "box-outline-alpha-stroke", box_outline_alpha_stroke, NULL); + cairo_perf_run (perf, "box-outline-alpha-fill", box_outline_alpha_fill, NULL); + + cairo_perf_run (perf, "box-outline-aa-stroke", box_outline_aa_stroke, NULL); + cairo_perf_run (perf, "box-outline-aa-fill", box_outline_aa_fill, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/cairo-perf-cover.c b/local/recipes/libs/cairo/source/perf/micro/cairo-perf-cover.c new file mode 100644 index 0000000000..c2499021fa --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/cairo-perf-cover.c @@ -0,0 +1,339 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-perf.h" + +static void +init_and_set_source_surface (cairo_t *cr, + cairo_surface_t *source, + int width, + int height) +{ + cairo_t *cr2; + + /* Fill it with something known */ + cr2 = cairo_create (source); + cairo_set_operator (cr2, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgb (cr2, 0, 0, 1); /* blue */ + cairo_paint (cr2); + + cairo_set_source_rgba (cr2, 1, 0, 0, 0.5); /* 50% red */ + cairo_new_path (cr2); + cairo_rectangle (cr2, 0, 0, width/2.0, height/2.0); + cairo_rectangle (cr2, width/2.0, height/2.0, width/2.0, height/2.0); + cairo_fill (cr2); + + cairo_set_source_surface (cr, cairo_get_target (cr2), 0, 0); + cairo_destroy (cr2); +} + +static void +set_source_solid_rgb (cairo_t *cr, + int width, + int height) +{ + cairo_set_source_rgb (cr, 0.2, 0.6, 0.9); +} + +static void +set_source_solid_rgba (cairo_t *cr, + int width, + int height) +{ + cairo_set_source_rgba (cr, 0.2, 0.6, 0.9, 0.7); +} + +static void +set_source_image_surface_rgb (cairo_t *cr, + int width, + int height) +{ + cairo_surface_t *source; + + source = cairo_image_surface_create (CAIRO_FORMAT_RGB24, + width, height); + init_and_set_source_surface (cr, source, width, height); + + cairo_surface_destroy (source); +} + +static void +set_source_image_surface_rgba (cairo_t *cr, + int width, + int height) +{ + cairo_surface_t *source; + + source = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + width, height); + init_and_set_source_surface (cr, source, width, height); + + cairo_surface_destroy (source); +} + +static void +set_source_image_surface_rgba_mag (cairo_t *cr, + int width, + int height) +{ + cairo_surface_t *source; + + source = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + width/2, height/2); + cairo_scale(cr, 2.1, 2.1); + init_and_set_source_surface (cr, source, width/2, height/2); + cairo_scale(cr, 1/2.1, 1/2.1); + + cairo_surface_destroy (source); +} + +static void +set_source_image_surface_rgba_min (cairo_t *cr, + int width, + int height) +{ + cairo_surface_t *source; + + source = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + width*2, height*2); + cairo_scale(cr, 1/1.9, 1/1.9); + init_and_set_source_surface (cr, source, width*2, height*2); + cairo_scale(cr, 1.9, 1.9); + + cairo_surface_destroy (source); +} + +static void +set_source_similar_surface_rgb (cairo_t *cr, + int width, + int height) +{ + cairo_surface_t *source; + + source = cairo_surface_create_similar (cairo_get_group_target (cr), + CAIRO_CONTENT_COLOR, + width, height); + init_and_set_source_surface (cr, source, width, height); + + cairo_surface_destroy (source); +} + +static void +set_source_similar_surface_rgba (cairo_t *cr, + int width, + int height) +{ + cairo_surface_t *source; + + source = cairo_surface_create_similar (cairo_get_group_target (cr), + CAIRO_CONTENT_COLOR_ALPHA, + width, height); + init_and_set_source_surface (cr, source, width, height); + + cairo_surface_destroy (source); +} + +static void +set_source_similar_surface_rgba_mag (cairo_t *cr, + int width, + int height) +{ + cairo_surface_t *source; + + source = cairo_surface_create_similar (cairo_get_group_target (cr), + CAIRO_CONTENT_COLOR_ALPHA, + width/2, height/2); + cairo_scale(cr, 2.1, 2.1); + init_and_set_source_surface (cr, source, width/2, height/2); + cairo_scale(cr, 1/2.1, 1/2.1); + + cairo_surface_destroy (source); +} + +static void +set_source_similar_surface_rgba_min (cairo_t *cr, + int width, + int height) +{ + cairo_surface_t *source; + + source = cairo_surface_create_similar (cairo_get_group_target (cr), + CAIRO_CONTENT_COLOR_ALPHA, + width*2, height*2); + cairo_scale(cr, 1/1.9, 1/1.9); + init_and_set_source_surface (cr, source, width*2, height*2); + cairo_scale(cr, 1.9, 1.9); + + cairo_surface_destroy (source); +} + +static void +set_source_linear_rgb (cairo_t *cr, + int width, + int height) +{ + cairo_pattern_t *linear; + + linear = cairo_pattern_create_linear (0.0, 0.0, width, height); + cairo_pattern_add_color_stop_rgb (linear, 0.0, 1, 0, 0); /* red */ + cairo_pattern_add_color_stop_rgb (linear, 1.0, 0, 0, 1); /* blue */ + + cairo_set_source (cr, linear); + + cairo_pattern_destroy (linear); +} + +static void +set_source_linear_rgba (cairo_t *cr, + int width, + int height) +{ + cairo_pattern_t *linear; + + linear = cairo_pattern_create_linear (0.0, 0.0, width, height); + cairo_pattern_add_color_stop_rgba (linear, 0.0, 1, 0, 0, 0.5); /* 50% red */ + cairo_pattern_add_color_stop_rgba (linear, 1.0, 0, 0, 1, 0.0); /* 0% blue */ + + cairo_set_source (cr, linear); + + cairo_pattern_destroy (linear); +} + +static void +set_source_linear3_rgb (cairo_t *cr, + int width, + int height) +{ + cairo_pattern_t *linear; + + linear = cairo_pattern_create_linear (0.0, 0.0, width, height); + cairo_pattern_add_color_stop_rgb (linear, 0.0, 1, 0, 0); /* red */ + cairo_pattern_add_color_stop_rgb (linear, 0.5, 0, 1, 0); /* green */ + cairo_pattern_add_color_stop_rgb (linear, 1.0, 0, 0, 1); /* blue */ + + cairo_set_source (cr, linear); + + cairo_pattern_destroy (linear); +} + +static void +set_source_linear3_rgba (cairo_t *cr, + int width, + int height) +{ + cairo_pattern_t *linear; + + linear = cairo_pattern_create_linear (0.0, 0.0, width, height); + cairo_pattern_add_color_stop_rgba (linear, 0.0, 1, 0, 0, 0.5); /* 50% red */ + cairo_pattern_add_color_stop_rgba (linear, 0.5, 0, 1, 0, 0.0); /* 0% green */ + cairo_pattern_add_color_stop_rgba (linear, 1.0, 0, 0, 1, 0.5); /* 50% blue */ + + cairo_set_source (cr, linear); + + cairo_pattern_destroy (linear); +} + +static void +set_source_radial_rgb (cairo_t *cr, + int width, + int height) +{ + cairo_pattern_t *radial; + + radial = cairo_pattern_create_radial (width/2.0, height/2.0, 0.0, + width/2.0, height/2.0, width/2.0); + cairo_pattern_add_color_stop_rgb (radial, 0.0, 1, 0, 0); /* red */ + cairo_pattern_add_color_stop_rgb (radial, 1.0, 0, 0, 1); /* blue */ + + cairo_set_source (cr, radial); + + cairo_pattern_destroy (radial); +} + +static void +set_source_radial_rgba (cairo_t *cr, + int width, + int height) +{ + cairo_pattern_t *radial; + + radial = cairo_pattern_create_radial (width/2.0, height/2.0, 0.0, + width/2.0, height/2.0, width/2.0); + cairo_pattern_add_color_stop_rgba (radial, 0.0, 1, 0, 0, 0.5); /* 50% red */ + cairo_pattern_add_color_stop_rgba (radial, 1.0, 0, 0, 1, 0.0); /* 0% blue */ + + cairo_set_source (cr, radial); + + cairo_pattern_destroy (radial); +} + +typedef void (*set_source_func_t) (cairo_t *cr, int width, int height); + +void +cairo_perf_cover_sources_and_operators (cairo_perf_t *perf, + const char *name, + cairo_perf_func_t perf_func, + cairo_count_func_t count_func) +{ + unsigned int i, j; + char *expanded_name; + + struct { set_source_func_t set_source; const char *name; } sources[] = { + { set_source_solid_rgb, "solid-rgb" }, + { set_source_solid_rgba, "solid-rgba" }, + { set_source_image_surface_rgb, "image-rgb" }, + { set_source_image_surface_rgba, "image-rgba" }, + { set_source_image_surface_rgba_mag, "image-rgba-mag" }, + { set_source_image_surface_rgba_min, "image-rgba-min" }, + { set_source_similar_surface_rgb, "similar-rgb" }, + { set_source_similar_surface_rgba, "similar-rgba" }, + { set_source_similar_surface_rgba_mag, "similar-rgba-mag" }, + { set_source_similar_surface_rgba_min, "similar-rgba-min" }, + { set_source_linear_rgb, "linear-rgb" }, + { set_source_linear_rgba, "linear-rgba" }, + { set_source_linear3_rgb, "linear3-rgb" }, + { set_source_linear3_rgba, "linear3-rgba" }, + { set_source_radial_rgb, "radial-rgb" }, + { set_source_radial_rgba, "radial-rgba" } + }; + + struct { cairo_operator_t op; const char *name; } operators[] = { + { CAIRO_OPERATOR_OVER, "over" }, + { CAIRO_OPERATOR_SOURCE, "source" } + }; + + for (i = 0; i < ARRAY_LENGTH (sources); i++) { + (sources[i].set_source) (perf->cr, perf->size, perf->size); + + for (j = 0; j < ARRAY_LENGTH (operators); j++) { + cairo_set_operator (perf->cr, operators[j].op); + + xasprintf (&expanded_name, "%s_%s_%s", + name, sources[i].name, operators[j].name); + cairo_perf_run (perf, expanded_name, perf_func, count_func); + free (expanded_name); + } + } +} diff --git a/local/recipes/libs/cairo/source/perf/micro/composite-checker.c b/local/recipes/libs/cairo/source/perf/micro/composite-checker.c new file mode 100644 index 0000000000..d6d17ab638 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/composite-checker.c @@ -0,0 +1,117 @@ +/* + * Copyright © 2007 Björn Lindqvist + * + * 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: Björn Lindqvist + */ + +#include "cairo-perf.h" + +/* This test case measures how much time cairo takes to render the + * equivalent of the following gdk-pixbuf operation: + * + * gdk_pixbuf_composite_color(dest, + * 0, 0, DST_SIZE, DST_SIZE, + * 0, 0, + * SCALE, SCALE, + * gdk.INTERP_NEAREST, + * 255, + * 0, 0, + * 8, 0x33333333, 0x88888888); + * + * Cairo is (at the time of writing) about 2-3 times as slow as + * gdk-pixbuf. + */ +#define PAT_SIZE 16 +#define SRC_SIZE 64 + +static cairo_pattern_t *checkerboard = NULL; +static cairo_pattern_t *src_pattern = NULL; + +static cairo_time_t +do_composite_checker (cairo_t *cr, + int width, + int height, + int loops) +{ + /* Compute zoom so that the src_pattern covers the whole output image. */ + double xscale = width / (double) SRC_SIZE; + double yscale = height / (double) SRC_SIZE; + + cairo_perf_timer_start (); + + while (loops--) { + /* Fill the surface with our background. */ + cairo_identity_matrix (cr); + cairo_set_source (cr, checkerboard); + cairo_paint (cr); + + /* Draw the scaled image on top. */ + cairo_scale (cr, xscale, yscale); + cairo_set_source (cr, src_pattern); + cairo_paint (cr); + } + + cairo_perf_timer_stop (); + return cairo_perf_timer_elapsed (); +} + +cairo_bool_t +composite_checker_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "composite-checker", NULL); +} + +void +composite_checker (cairo_perf_t *perf, + cairo_t *cr, + int width, + int height) +{ + cairo_surface_t *image; + + /* Create the checker pattern. We don't actually need to draw + * anything on it since that wouldn't affect performance. + */ + image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + PAT_SIZE, + PAT_SIZE); + checkerboard = cairo_pattern_create_for_surface (image); + cairo_pattern_set_filter (checkerboard, CAIRO_FILTER_NEAREST); + cairo_pattern_set_extend (checkerboard, CAIRO_EXTEND_REPEAT); + cairo_surface_destroy (image); + + /* Create the image source pattern. Again we use the NEAREST + * filtering which should be fastest. + */ + image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + SRC_SIZE, + SRC_SIZE); + src_pattern = cairo_pattern_create_for_surface (image); + cairo_pattern_set_filter (src_pattern, CAIRO_FILTER_NEAREST); + cairo_surface_destroy (image); + + cairo_perf_run (perf, "composite-checker", do_composite_checker, NULL); + + cairo_pattern_destroy (checkerboard); + cairo_pattern_destroy (src_pattern); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/curve.c b/local/recipes/libs/cairo/source/perf/micro/curve.c new file mode 100644 index 0000000000..3b5a163422 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/curve.c @@ -0,0 +1,111 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-perf.h" + +static uint32_t state; + +static double +uniform_random (double minval, double maxval) +{ + static uint32_t const poly = 0x9a795537U; + uint32_t n = 32; + while (n-->0) + state = 2*state < state ? (2*state ^ poly) : 2*state; + return minval + state * (maxval - minval) / 4294967296.0; +} + +static cairo_time_t +do_curve_stroke (cairo_t *cr, int width, int height, int loops) +{ + state = 0xc0ffee; + cairo_set_line_width (cr, 2.); + cairo_perf_timer_start (); + + while (loops--) { + double x1 = uniform_random (0, width); + double x2 = uniform_random (0, width); + double x3 = uniform_random (0, width); + double y1 = uniform_random (0, height); + double y2 = uniform_random (0, height); + double y3 = uniform_random (0, height); + cairo_move_to (cr, uniform_random (0, width), uniform_random (0, height)); + cairo_curve_to (cr, x1, y1, x2, y2, x3, y3); + cairo_stroke(cr); + } + + cairo_perf_timer_stop (); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_curve_fill (cairo_t *cr, int width, int height, int loops) +{ + state = 0xc0ffee; + cairo_perf_timer_start (); + + while (loops--) { + double x0 = uniform_random (0, width); + double x1 = uniform_random (0, width); + double x2 = uniform_random (0, width); + double x3 = uniform_random (0, width); + double xm = uniform_random (0, width); + double xn = uniform_random (0, width); + double y0 = uniform_random (0, height); + double y1 = uniform_random (0, height); + double y2 = uniform_random (0, height); + double y3 = uniform_random (0, height); + double ym = uniform_random (0, height); + double yn = uniform_random (0, height); + + cairo_move_to (cr, xm, ym); + cairo_curve_to (cr, x1, y1, x2, y2, xn, yn); + cairo_curve_to (cr, x3, y3, x0, y0, xm, ym); + cairo_close_path (cr); + + cairo_fill(cr); + } + + cairo_perf_timer_stop (); + + return cairo_perf_timer_elapsed (); +} + +cairo_bool_t +curve_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "curve", NULL); +} + +void +curve (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1., 1., 1.); + + cairo_perf_run (perf, "curve-stroked", do_curve_stroke, NULL); + cairo_perf_run (perf, "curve-filled", do_curve_fill, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/disjoint.c b/local/recipes/libs/cairo/source/perf/micro/disjoint.c new file mode 100644 index 0000000000..847860c7e9 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/disjoint.c @@ -0,0 +1,101 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright (c) 2011 Intel Corporation + * + * 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. + */ +#include "cairo-perf.h" +#include + +#define STEP 5 + +static void path (cairo_t *cr, int width, int height) +{ + int i; + + cairo_rectangle (cr, 0, 0, width, height); + cairo_clip (cr); + + cairo_translate (cr, width/2, height/2); + cairo_rotate (cr, M_PI/4); + cairo_translate (cr, -width/2, -height/2); + + for (i = 0; i < width; i += STEP) { + cairo_rectangle (cr, i, -2, 1, height+4); + cairo_rectangle (cr, -2, i, width+4, 1); + } +} + +static void clip (cairo_t *cr, int width, int height) +{ + int i, j; + + for (j = 0; j < height; j += 2*STEP) { + for (i = 0; i < width; i += 2*STEP) + cairo_rectangle (cr, i, j, STEP, STEP); + + j += 2*STEP; + for (i = 0; i < width; i += 2*STEP) + cairo_rectangle (cr, i+STEP/2, j, STEP, STEP); + } + + cairo_clip (cr); +} + +static cairo_time_t +draw (cairo_t *cr, int width, int height, int loops) +{ + cairo_save (cr); + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + cairo_set_source_rgb (cr, 1, 0, 0); + + cairo_perf_timer_start (); + while (loops--) { + cairo_save (cr); + clip (cr, width, height); + path (cr, width, height); + cairo_fill (cr); + cairo_restore (cr); + } + cairo_perf_timer_stop (); + + cairo_restore (cr); + + return cairo_perf_timer_elapsed (); +} + +cairo_bool_t +disjoint_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "disjoint", NULL); +} + +void +disjoint (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + if (! cairo_perf_can_run (perf, "disjoint", NULL)) + return; + + cairo_perf_run (perf, "disjoint", draw, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/dragon.c b/local/recipes/libs/cairo/source/perf/micro/dragon.c new file mode 100644 index 0000000000..aa5daf534d --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/dragon.c @@ -0,0 +1,277 @@ +/* + * Copyright © 2007 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + * + * Inspiration (and path!) taken from + * http://labs.trolltech.com/blogs/2007/08/31/rasterizing-dragons/ + */ + +#include "cairo-perf.h" + +static inline int +next_pot (int v) +{ + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + return v; +} + +static cairo_bool_t +direction (int i) +{ + int pivot, np2; + + if (i < 2) + return TRUE; + + np2 = next_pot (i + 1); + if (np2 == i + 1) + return TRUE; + + pivot = np2 / 2 - 1; + return ! direction (2 * pivot - i); +} + +static void +path (cairo_t *cr, int step, int dir, int iterations) +{ + double dx, dy; + int i; + + switch (dir) { + default: + case 0: dx = step; dy = 0; break; + case 1: dx = -step; dy = 0; break; + case 2: dx = 0; dy = step; break; + case 3: dx = 0; dy = -step; break; + } + + for (i = 0; i < iterations; i++) { + cairo_rel_line_to (cr, dx, dy); + + if (direction (i)) { + double t = dx; + dx = dy; + dy = -t; + } else { + double t = dx; + dx = -dy; + dy = t; + } + } +} + +static cairo_time_t +do_dragon (cairo_t *cr, int width, int height, int loops) +{ + cairo_pattern_t *pattern; + double cx, cy, r; + + cx = cy = .5 * MAX (width, height); + r = .5 * MIN (width, height); + + cairo_perf_timer_start (); + + while (loops--) { + pattern = cairo_pattern_create_radial (cx, cy, 0., cx, cy, r); + cairo_pattern_add_color_stop_rgb (pattern, 0., .0, .0, .0); + cairo_pattern_add_color_stop_rgb (pattern, 0.25, .5, .4, .4); + cairo_pattern_add_color_stop_rgb (pattern, .5, .8, .8, .9); + cairo_pattern_add_color_stop_rgb (pattern, 1., .9, .9, 1.); + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + cairo_paint (cr); + + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); + cairo_set_line_width (cr, 4.); + + cairo_move_to (cr, cx, cy); + path (cr, 12, 0, 2048); + pattern = cairo_pattern_create_radial (cx, cy, 0., cx, cy, r); + cairo_pattern_add_color_stop_rgb (pattern, 0., 1., 1., 1.); + cairo_pattern_add_color_stop_rgb (pattern, 1., 0., 0., 0.); + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + cairo_stroke(cr); + + cairo_move_to (cr, cx, cy); + path (cr, 12, 1, 2048); + pattern = cairo_pattern_create_radial (cx, cy, 0., cx, cy, r); + cairo_pattern_add_color_stop_rgb (pattern, 1., 1., 1., 0.); + cairo_pattern_add_color_stop_rgb (pattern, 0., 1., 0., 0.); + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + cairo_stroke(cr); + + cairo_move_to (cr, cx, cy); + path (cr, 12, 2, 2048); + pattern = cairo_pattern_create_radial (cx, cy, 0., cx, cy, r); + cairo_pattern_add_color_stop_rgb (pattern, 1., 0., 1., 1.); + cairo_pattern_add_color_stop_rgb (pattern, 0., 0., 1., 0.); + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + cairo_stroke(cr); + + cairo_move_to (cr, cx, cy); + path (cr, 12, 3, 2048); + pattern = cairo_pattern_create_radial (cx, cy, 0., cx, cy, r); + cairo_pattern_add_color_stop_rgb (pattern, 1., 1., 0., 1.); + cairo_pattern_add_color_stop_rgb (pattern, 0., 0., 0., 1.); + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + cairo_stroke(cr); + } + + cairo_perf_timer_stop (); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_dragon_solid (cairo_t *cr, int width, int height, int loops) +{ + double cx, cy; + + cx = cy = .5 * MAX (width, height); + + cairo_perf_timer_start (); + + while (loops--) { + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + cairo_set_line_width (cr, 4.); + + cairo_move_to (cr, cx, cy); + path (cr, 12, 0, 2048); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_stroke(cr); + + cairo_move_to (cr, cx, cy); + path (cr, 12, 1, 2048); + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_stroke(cr); + + cairo_move_to (cr, cx, cy); + path (cr, 12, 2, 2048); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_stroke(cr); + + cairo_move_to (cr, cx, cy); + path (cr, 12, 3, 2048); + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_stroke(cr); + } + + cairo_perf_timer_stop (); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_dragon_solid_unaligned (cairo_t *cr, int width, int height, int loops) +{ + cairo_translate (cr, 0.01, 0.01); + return do_dragon_solid (cr, width, height, loops); +} + +static cairo_time_t +do_dragon_solid_aligned_clip (cairo_t *cr, int width, int height, int loops) +{ + cairo_reset_clip (cr); + cairo_rectangle (cr, 10, 10, width/2 + 10, height/2 + 10); + cairo_rectangle (cr, width/2-20, height/2-20, width/2 + 10, height/2 + 10); + cairo_clip (cr); + + return do_dragon_solid (cr, width, height, loops); +} + +static cairo_time_t +do_dragon_unaligned_solid_aligned_clip (cairo_t *cr, int width, int height, int loops) +{ + cairo_translate (cr, 0.01, 0.01); + cairo_reset_clip (cr); + cairo_rectangle (cr, 10, 10, width/2 + 10, height/2 + 10); + cairo_rectangle (cr, width/2-20, height/2-20, width/2 + 10, height/2 + 10); + cairo_clip (cr); + + return do_dragon_solid (cr, width, height, loops); +} + +static cairo_time_t +do_dragon_solid_unaligned_clip (cairo_t *cr, int width, int height, int loops) +{ + cairo_reset_clip (cr); + cairo_rectangle (cr, 10.5, 10.5, width/2 + 10, height/2 + 10); + cairo_rectangle (cr, width/2-20, height/2-20, width/2 + 9.5, height/2 + 9.5); + cairo_clip (cr); + + return do_dragon_solid (cr, width, height, loops); +} + +static cairo_time_t +do_dragon_unaligned_solid_unaligned_clip (cairo_t *cr, int width, int height, int loops) +{ + cairo_translate (cr, 0.01, 0.01); + cairo_reset_clip (cr); + cairo_rectangle (cr, 10.5, 10.5, width/2 + 10, height/2 + 10); + cairo_rectangle (cr, width/2-20, height/2-20, width/2 + 9.5, height/2 + 9.5); + cairo_clip (cr); + + return do_dragon_solid (cr, width, height, loops); +} + +static cairo_time_t +do_dragon_solid_circle_clip (cairo_t *cr, int width, int height, int loops) +{ + cairo_reset_clip (cr); + cairo_arc (cr, width/2., height/2., MIN (width, height)/2. - 10, 0, 2 * M_PI); + cairo_clip (cr); + + return do_dragon_solid (cr, width, height, loops); +} + +cairo_bool_t +dragon_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "dragon", NULL); +} + +void +dragon (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_perf_run (perf, "dragon-solid", do_dragon_solid, NULL); + cairo_perf_run (perf, "dragon-unaligned-solid", do_dragon_solid_unaligned, NULL); + cairo_perf_run (perf, "dragon-solid-aligned-clip", do_dragon_solid_aligned_clip, NULL); + cairo_perf_run (perf, "dragon-unaligned-solid-aligned-clip", do_dragon_unaligned_solid_aligned_clip, NULL); + cairo_perf_run (perf, "dragon-solid-unaligned-clip", do_dragon_solid_unaligned_clip, NULL); + cairo_perf_run (perf, "dragon-unaligned-solid-unaligned-clip", do_dragon_unaligned_solid_unaligned_clip, NULL); + cairo_perf_run (perf, "dragon-solid-circle-clip", do_dragon_solid_circle_clip, NULL); + cairo_perf_run (perf, "dragon", do_dragon, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/fill-clip.c b/local/recipes/libs/cairo/source/perf/micro/fill-clip.c new file mode 100644 index 0000000000..f9802705f4 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/fill-clip.c @@ -0,0 +1,128 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +/* Compares the overhead for WebKit's drawRect() */ + +#include "cairo-perf.h" + +#include + +static cairo_time_t +clip_paint (cairo_t *cr, int width, int height, int loops) +{ + int x = width/4, w = width/2; + int y = height/4, h = height/2; + + cairo_perf_timer_start (); + + while (loops--) { + cairo_reset_clip (cr); + cairo_rectangle (cr, x, y, w, h); + cairo_clip (cr); + cairo_paint (cr); + } + + cairo_perf_timer_stop (); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +rect_fill (cairo_t *cr, int width, int height, int loops) +{ + int x = width/4, w = width/2; + int y = height/4, h = height/2; + + cairo_perf_timer_start (); + + while (loops--) { + cairo_rectangle (cr, x, y, w, h); + cairo_fill (cr); + } + + cairo_perf_timer_stop (); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +direct (cairo_t *cr, int width, int height, int loops) +{ + int x = width/4, w = width/2; + int y = height/4, h = height/2; + cairo_surface_t *surface, *image; + uint8_t *data; + int stride, bpp; + + + surface = cairo_get_target (cr); + image = cairo_surface_map_to_image (surface, NULL); + data = cairo_image_surface_get_data (image); + stride = cairo_image_surface_get_stride (image); + + switch (cairo_image_surface_get_format (image)) { + default: + case CAIRO_FORMAT_INVALID: + case CAIRO_FORMAT_A1: bpp = 0; break; + case CAIRO_FORMAT_A8: bpp = 8; break; + case CAIRO_FORMAT_RGB16_565: bpp = 16; break; + case CAIRO_FORMAT_RGB24: + case CAIRO_FORMAT_RGB30: + case CAIRO_FORMAT_ARGB32: bpp = 32; break; + case CAIRO_FORMAT_RGB96F: bpp = 96; break; + case CAIRO_FORMAT_RGBA128F: bpp = 128; break; + } + + cairo_perf_timer_start (); + + while (loops--) { + pixman_fill ((uint32_t *)data, stride / sizeof(uint32_t), bpp, + x, y, w, h, + -1); + } + + cairo_perf_timer_stop (); + + cairo_surface_unmap_image (surface, image); + + return cairo_perf_timer_elapsed (); +} + +cairo_bool_t +fill_clip_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "fillclip", NULL); +} + +void +fill_clip (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1., 1., 1.); + + cairo_perf_run (perf, "fillclip-clip", clip_paint, NULL); + cairo_perf_run (perf, "fillclip-fill", rect_fill, NULL); + cairo_perf_run (perf, "fillclip-direct", direct, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/fill.c b/local/recipes/libs/cairo/source/perf/micro/fill.c new file mode 100644 index 0000000000..d356c26d5c --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/fill.c @@ -0,0 +1,122 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-perf.h" + +static cairo_time_t +do_fill (cairo_t *cr, int width, int height, int loops) +{ + cairo_arc (cr, + width/2.0, height/2.0, + width/3.0, + 0, 2 * M_PI); + + cairo_perf_timer_start (); + + while (loops--) + cairo_fill_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_fill_annuli (cairo_t *cr, int width, int height, int loops) +{ + cairo_new_sub_path (cr); + cairo_arc (cr, + width/2.0, height/2.0, + width/3.0, + 0, 2 * M_PI); + + cairo_new_sub_path (cr); + cairo_arc_negative (cr, + width/2.0, height/2.0, + width/4.0, + 2 * M_PI, 0); + + cairo_new_sub_path (cr); + cairo_arc (cr, + width/2.0, height/2.0, + width/6.0, + 0, 2 * M_PI); + + cairo_new_sub_path (cr); + cairo_arc_negative (cr, + width/2.0, height/2.0, + width/8.0, + 2 * M_PI, 0); + + cairo_perf_timer_start (); + + while (loops--) + cairo_fill_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_fill_eo_noaa (cairo_t *cr, int width, int height, int loops) +{ + cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + + cairo_arc (cr, + width/2.0, height/2.0, + width/3.0, + 0, 2 * M_PI); + + cairo_perf_timer_start (); + + while (loops--) + cairo_fill_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +cairo_bool_t +fill_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "fill", NULL); +} + +void +fill (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_perf_cover_sources_and_operators (perf, "fill", do_fill, NULL); + cairo_perf_cover_sources_and_operators (perf, "fill-annuli", do_fill_annuli, NULL); + cairo_perf_cover_sources_and_operators (perf, "fill-eo-noaa", do_fill_eo_noaa, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/glyphs.c b/local/recipes/libs/cairo/source/perf/micro/glyphs.c new file mode 100644 index 0000000000..5f088b29e3 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/glyphs.c @@ -0,0 +1,202 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * Copyright © 2009 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + * Chris Wilson + */ + +#include "cairo-perf.h" + +static cairo_time_t +do_glyphs (double font_size, + cairo_antialias_t antialias, + cairo_t *cr, int width, int height, int loops) +{ + const char text[] = "the jay, pig, fox, zebra and my wolves quack"; + cairo_scaled_font_t *scaled_font; + cairo_glyph_t *glyphs = NULL, *glyphs_copy; + cairo_text_extents_t extents; + cairo_font_options_t *options; + cairo_status_t status; + double x, y; + int num_glyphs, n; + + options = cairo_font_options_create (); + cairo_font_options_set_antialias (options, antialias); + cairo_set_font_options (cr, options); + cairo_font_options_destroy (options); + + cairo_select_font_face (cr, + "@cairo:", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (cr, font_size); + scaled_font = cairo_get_scaled_font (cr); + status = cairo_scaled_font_text_to_glyphs (scaled_font, 0., 0., + text, -1, + &glyphs, &num_glyphs, + NULL, NULL, + NULL); + if (status) + return 0; + + glyphs_copy = cairo_glyph_allocate (num_glyphs); + if (glyphs_copy == NULL) { + cairo_glyph_free (glyphs); + return 0; + } + + cairo_scaled_font_glyph_extents (scaled_font, + glyphs, num_glyphs, + &extents); + + cairo_perf_timer_start (); + + while (loops--) { + y = 0; + do { + x = 0; + do { + for (n = 0; n < num_glyphs; n++) { + glyphs_copy[n] = glyphs[n]; + glyphs_copy[n].x += x; + glyphs_copy[n].y += y; + } + cairo_show_glyphs (cr, glyphs_copy, num_glyphs); + + x += extents.width; + } while (x < width); + y += extents.height; + } while (y < height); + } + + cairo_perf_timer_stop (); + + cairo_glyph_free (glyphs); + cairo_glyph_free (glyphs_copy); + + return cairo_perf_timer_elapsed (); +} + +static double +count_glyphs (double font_size, + cairo_antialias_t antialias, + cairo_t *cr, int width, int height) +{ + const char text[] = "the jay, pig, fox, zebra and my wolves quack"; + cairo_scaled_font_t *scaled_font; + cairo_glyph_t *glyphs = NULL; + cairo_text_extents_t extents; + cairo_font_options_t *options; + cairo_status_t status; + int num_glyphs; + int glyphs_per_line, lines_per_loop; + + options = cairo_font_options_create (); + cairo_font_options_set_antialias (options, antialias); + cairo_set_font_options (cr, options); + cairo_font_options_destroy (options); + + cairo_select_font_face (cr, + "@cairo:", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (cr, font_size); + scaled_font = cairo_get_scaled_font (cr); + status = cairo_scaled_font_text_to_glyphs (scaled_font, 0., 0., + text, -1, + &glyphs, &num_glyphs, + NULL, NULL, + NULL); + if (status) + return 0; + + cairo_scaled_font_glyph_extents (scaled_font, + glyphs, num_glyphs, + &extents); + cairo_glyph_free (glyphs); + + glyphs_per_line = num_glyphs * width / extents.width + 1; + lines_per_loop = height / extents.height + 1; + return glyphs_per_line * lines_per_loop / 1000.; /* kiloglyphs */ +} + +#define DECL(name,size, aa) \ +static cairo_time_t \ +do_glyphs##name (cairo_t *cr, int width, int height, int loops) \ +{ \ + return do_glyphs (size, aa, cr, width, height, loops); \ +} \ +\ +static double \ +count_glyphs##name (cairo_t *cr, int width, int height) \ +{ \ + return count_glyphs (size, aa, cr, width, height); \ +} + +DECL(8, 8, CAIRO_ANTIALIAS_GRAY) +DECL(10, 10, CAIRO_ANTIALIAS_GRAY) +DECL(12, 12, CAIRO_ANTIALIAS_GRAY) +DECL(16, 16, CAIRO_ANTIALIAS_GRAY) +DECL(20, 20, CAIRO_ANTIALIAS_GRAY) +DECL(24, 24, CAIRO_ANTIALIAS_GRAY) +DECL(32, 32, CAIRO_ANTIALIAS_GRAY) +DECL(40, 40, CAIRO_ANTIALIAS_GRAY) +DECL(48, 48, CAIRO_ANTIALIAS_GRAY) + +DECL(8ca, 8, CAIRO_ANTIALIAS_SUBPIXEL) +DECL(48ca, 48, CAIRO_ANTIALIAS_SUBPIXEL) + +DECL(8mono, 8, CAIRO_ANTIALIAS_NONE) +DECL(48mono, 48, CAIRO_ANTIALIAS_NONE) + +cairo_bool_t +glyphs_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "glyphs", NULL); +} + +void +glyphs (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_perf_cover_sources_and_operators (perf, "glyphs8mono", do_glyphs8mono, count_glyphs8mono); + cairo_perf_cover_sources_and_operators (perf, "glyphs8", do_glyphs8, count_glyphs8); + cairo_perf_cover_sources_and_operators (perf, "glyphs8ca", do_glyphs8ca, count_glyphs8ca); + + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_set_source_rgb (cr, 0, 0, 0); + + cairo_perf_run (perf, "glyphs8", do_glyphs8, count_glyphs8); + cairo_perf_run (perf, "glyphs10", do_glyphs10, count_glyphs10); + cairo_perf_run (perf, "glyphs12", do_glyphs12, count_glyphs12); + cairo_perf_run (perf, "glyphs16", do_glyphs16, count_glyphs16); + cairo_perf_run (perf, "glyphs20", do_glyphs20, count_glyphs20); + cairo_perf_run (perf, "glyphs24", do_glyphs24, count_glyphs24); + cairo_perf_run (perf, "glyphs32", do_glyphs32, count_glyphs32); + cairo_perf_run (perf, "glyphs40", do_glyphs40, count_glyphs40); + cairo_perf_run (perf, "glyphs48", do_glyphs48, count_glyphs48); + + cairo_perf_cover_sources_and_operators (perf, "glyphs48mono", do_glyphs48mono, count_glyphs48mono); + cairo_perf_cover_sources_and_operators (perf, "glyphs48", do_glyphs48, count_glyphs48); + cairo_perf_cover_sources_and_operators (perf, "glyphs48ca", do_glyphs48ca, count_glyphs48ca); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/hash-table.c b/local/recipes/libs/cairo/source/perf/micro/hash-table.c new file mode 100644 index 0000000000..d16291770e --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/hash-table.c @@ -0,0 +1,115 @@ +/* + * Copyright © 2011 Andrea Canciani + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Andrea Canciani + */ + +#include "cairo-perf.h" + +#define ITER 1000 +#define HOLDOVERS 256 +#define LIVE_ENTRIES 257 +#define ACTIVE_FONTS (LIVE_ENTRIES - HOLDOVERS - 1) + +/* + * The original implementation of hash tables was very inefficient, as + * pointed out in https://bugs.freedesktop.org/show_bug.cgi?id=17399 + * + * This benchmark tries to fill up the scaled_font_map hash table to + * show the O(n) behavior. + */ + +static cairo_time_t +do_hash_table (cairo_t *cr, int width, int height, int loops) +{ + /* + * Microsoft C Compiler complains that: + * error C2466: cannot allocate an array of constant size 0 + * so we add an unused element to make it happy + */ + cairo_scaled_font_t *active_fonts[ACTIVE_FONTS + 1]; + cairo_matrix_t m; + int i; + + cairo_matrix_init_identity (&m); + + /* Touch HOLDOVERS scaled fonts to fill up the holdover list. */ + for (i = 0; i < HOLDOVERS; i++) { + m.yy = m.xx * (i + 1); + cairo_set_font_matrix (cr, &m); + cairo_get_scaled_font (cr); + } + + /* + * Reference some scaled fonts so that they will be kept in the + * scaled fonts map. We want LIVE_ENTRIES elements in the font + * map, but cairo keeps HOLDOVERS recently used fonts in it and we + * will be activating a new font in the cr context, so we just + * keep references to ACTIVE_FONTS fonts. + * + * Note: setting LIVE_ENTRIES == HOLDOVERS+1 means that we keep no + * font in active_fonts and the slowness is caused by the holdover + * fonts only. + */ + for (i = 0; i < ACTIVE_FONTS; i++) { + cairo_scaled_font_t *scaled_font; + + m.yy = m.xx * (i + 1); + cairo_set_font_matrix (cr, &m); + + scaled_font = cairo_get_scaled_font (cr); + active_fonts[i] = cairo_scaled_font_reference (scaled_font); + } + + cairo_perf_timer_start (); + + while (loops--) { + m.xx += 1.0; + + /* Generate ITER new scaled fonts per loop */ + for (i = 0; i < ITER; i++) { + m.yy = m.xx * (i + 1); + cairo_set_font_matrix (cr, &m); + cairo_get_scaled_font (cr); + } + } + + cairo_perf_timer_stop (); + + for (i = 0; i < ACTIVE_FONTS; i++) + cairo_scaled_font_destroy (active_fonts[i]); + + return cairo_perf_timer_elapsed (); +} + +cairo_bool_t +hash_table_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "hash-table", NULL); +} + +void +hash_table (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_perf_cover_sources_and_operators (perf, "hash-table", + do_hash_table, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/hatching.c b/local/recipes/libs/cairo/source/perf/micro/hatching.c new file mode 100644 index 0000000000..d1d9fb8a6f --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/hatching.c @@ -0,0 +1,202 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright (c) 2011 Intel Corporation + * + * 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. + */ +#include "cairo-perf.h" +#include + + +#define STEP 5 +#define WIDTH 100 +#define HEIGHT 100 + +static void path (cairo_t *cr, unsigned int width, unsigned int height) +{ + unsigned int i; + + for (i = 0; i < width+1; i += STEP) { + cairo_rectangle (cr, i-1, -1, 2, height+2); + cairo_rectangle (cr, -1, i-1, width+2, 2); + } +} + +static void aa (cairo_t *cr) +{ + cairo_set_antialias (cr, CAIRO_ANTIALIAS_DEFAULT); +} + +static void mono (cairo_t *cr) +{ + cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); +} + +static void aligned (cairo_t *cr, int width, int height) +{ +} + +static void misaligned (cairo_t *cr, int width, int height) +{ + cairo_translate (cr, 0.25, 0.25); +} + +static void rotated (cairo_t *cr, int width, int height) +{ + cairo_translate (cr, width/2, height/2); + cairo_rotate (cr, M_PI/4); + cairo_translate (cr, -width/2, -height/2); +} + +static void clip (cairo_t *cr) +{ + cairo_clip (cr); + cairo_paint (cr); +} + +static void clip_alpha (cairo_t *cr) +{ + cairo_clip (cr); + cairo_paint_with_alpha (cr, .5); +} + +static cairo_time_t +draw (cairo_t *cr, + void (*prepare) (cairo_t *cr), + void (*transform) (cairo_t *cr, int width, int height), + void (*op) (cairo_t *cr), + int width, int height, int loops) +{ + cairo_save (cr); + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + cairo_set_source_rgb (cr, 1, 0, 0); + + prepare (cr); + + cairo_perf_timer_start (); + while (loops--) { + cairo_save (cr); + transform (cr, width, height); + path (cr, width, height); + op (cr); + cairo_restore (cr); + } + cairo_perf_timer_stop (); + + cairo_restore (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +draw_aligned_aa (cairo_t *cr, int width, int height, int loops) +{ + return draw(cr, aa, aligned, cairo_fill, + width, height, loops); +} + +static cairo_time_t +draw_misaligned_aa (cairo_t *cr, int width, int height, int loops) +{ + return draw(cr, aa, misaligned, cairo_fill, + width, height, loops); +} + +static cairo_time_t +draw_rotated_aa (cairo_t *cr, int width, int height, int loops) +{ + return draw(cr, aa, rotated, cairo_fill, + width, height, loops); +} + +static cairo_time_t +draw_aligned_mono (cairo_t *cr, int width, int height, int loops) +{ + return draw(cr, mono, aligned, cairo_fill, + width, height, loops); +} + +static cairo_time_t +draw_misaligned_mono (cairo_t *cr, int width, int height, int loops) +{ + return draw(cr, mono, misaligned, cairo_fill, + width, height, loops); +} + +static cairo_time_t +draw_rotated_mono (cairo_t *cr, int width, int height, int loops) +{ + return draw(cr, mono, rotated, cairo_fill, + width, height, loops); +} + +#define F(name, op,transform,aa) \ +static cairo_time_t \ +draw_##name (cairo_t *cr, int width, int height, int loops) \ +{ return draw(cr, (aa), (transform), (op), width, height, loops); } + +F(clip_aligned, clip, aligned, aa) +F(clip_misaligned, clip, misaligned, aa) +F(clip_rotated, clip, rotated, aa) +F(clip_aligned_mono, clip, aligned, mono) +F(clip_misaligned_mono, clip, misaligned, mono) +F(clip_rotated_mono, clip, rotated, mono) + +F(clip_alpha_aligned, clip_alpha, aligned, aa) +F(clip_alpha_misaligned, clip_alpha, misaligned, aa) +F(clip_alpha_rotated, clip_alpha, rotated, aa) +F(clip_alpha_aligned_mono, clip_alpha, aligned, mono) +F(clip_alpha_misaligned_mono, clip_alpha, misaligned, mono) +F(clip_alpha_rotated_mono, clip_alpha, rotated, mono) + +cairo_bool_t +hatching_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "hatching", NULL); +} + +void +hatching (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_perf_run (perf, "hatching-aligned-aa", draw_aligned_aa, NULL); + cairo_perf_run (perf, "hatching-misaligned-aa", draw_misaligned_aa, NULL); + cairo_perf_run (perf, "hatching-rotated-aa", draw_rotated_aa, NULL); + cairo_perf_run (perf, "hatching-aligned-mono", draw_aligned_mono, NULL); + cairo_perf_run (perf, "hatching-misaligned-mono", draw_misaligned_mono, NULL); + cairo_perf_run (perf, "hatching-rotated-mono", draw_rotated_mono, NULL); + + cairo_perf_run (perf, "hatching-clip-aligned-aa", draw_clip_aligned, NULL); + cairo_perf_run (perf, "hatching-clip-misaligned-aa", draw_clip_misaligned, NULL); + cairo_perf_run (perf, "hatching-clip-rotated-aa", draw_clip_rotated, NULL); + cairo_perf_run (perf, "hatching-clip-aligned-mono", draw_clip_aligned_mono, NULL); + cairo_perf_run (perf, "hatching-clip-misaligned-mono", draw_clip_misaligned_mono, NULL); + cairo_perf_run (perf, "hatching-clip-rotated-mono", draw_clip_rotated_mono, NULL); + + cairo_perf_run (perf, "hatching-clip-alpha-aligned-aa", draw_clip_alpha_aligned, NULL); + cairo_perf_run (perf, "hatching-clip-alpha-misaligned-aa", draw_clip_alpha_misaligned, NULL); + cairo_perf_run (perf, "hatching-clip-alpha-rotated-aa", draw_clip_alpha_rotated, NULL); + cairo_perf_run (perf, "hatching-clip-alpha-aligned-mono", draw_clip_alpha_aligned_mono, NULL); + cairo_perf_run (perf, "hatching-clip-alpha-misaligned-mono", draw_clip_alpha_misaligned_mono, NULL); + cairo_perf_run (perf, "hatching-clip-alpha-rotated-mono", draw_clip_alpha_rotated_mono, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/intersections.c b/local/recipes/libs/cairo/source/perf/micro/intersections.c new file mode 100644 index 0000000000..57931faf8c --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/intersections.c @@ -0,0 +1,160 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright (c) 2008 M Joonas Pihlaja + * + * 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. + */ +#include "cairo-perf.h" + +#define NUM_SEGMENTS 256 + +static unsigned state; +static double +uniform_random (double minval, double maxval) +{ + static unsigned const poly = 0x9a795537U; + unsigned n = 32; + while (n-->0) + state = 2*state < state ? (2*state ^ poly) : 2*state; + return minval + state * (maxval - minval) / 4294967296.0; +} + +static cairo_time_t +draw_random (cairo_t *cr, cairo_fill_rule_t fill_rule, + int width, int height, int loops) +{ + double x[NUM_SEGMENTS]; + double y[NUM_SEGMENTS]; + int i; + + cairo_save (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + for (i = 0; i < NUM_SEGMENTS; i++) { + x[i] = uniform_random (0, width); + y[i] = uniform_random (0, height); + } + + state = 0x12345678; + cairo_translate (cr, 1, 1); + cairo_set_fill_rule (cr, fill_rule); + cairo_set_source_rgb (cr, 1, 0, 0); + + cairo_new_path (cr); + cairo_move_to (cr, 0, 0); + for (i = 0; i < NUM_SEGMENTS; i++) + cairo_line_to (cr, x[i], y[i]); + cairo_close_path (cr); + + cairo_perf_timer_start (); + while (loops--) + cairo_fill_preserve (cr); + cairo_perf_timer_stop (); + + cairo_restore (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +draw_random_curve (cairo_t *cr, cairo_fill_rule_t fill_rule, + int width, int height, int loops) +{ + double x[3*NUM_SEGMENTS]; + double y[3*NUM_SEGMENTS]; + int i; + + cairo_save (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + for (i = 0; i < 3*NUM_SEGMENTS; i++) { + x[i] = uniform_random (0, width); + y[i] = uniform_random (0, height); + } + + state = 0x12345678; + cairo_translate (cr, 1, 1); + cairo_set_fill_rule (cr, fill_rule); + cairo_set_source_rgb (cr, 1, 0, 0); + + cairo_new_path (cr); + cairo_move_to (cr, 0, 0); + for (i = 0; i < NUM_SEGMENTS; i++) { + cairo_curve_to (cr, + x[3*i+0], y[3*i+0], + x[3*i+1], y[3*i+1], + x[3*i+2], y[3*i+2]); + } + cairo_close_path (cr); + + cairo_perf_timer_start (); + while (loops--) + cairo_fill_preserve (cr); + cairo_perf_timer_stop (); + + cairo_restore (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +random_eo (cairo_t *cr, int width, int height, int loops) +{ + return draw_random (cr, CAIRO_FILL_RULE_EVEN_ODD, width, height, loops); +} + +static cairo_time_t +random_nz (cairo_t *cr, int width, int height, int loops) +{ + return draw_random (cr, CAIRO_FILL_RULE_WINDING, width, height, loops); +} + +static cairo_time_t +random_curve_eo (cairo_t *cr, int width, int height, int loops) +{ + return draw_random_curve (cr, CAIRO_FILL_RULE_EVEN_ODD, width, height, loops); +} + +static cairo_time_t +random_curve_nz (cairo_t *cr, int width, int height, int loops) +{ + return draw_random_curve (cr, CAIRO_FILL_RULE_WINDING, width, height, loops); +} + +cairo_bool_t +intersections_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "intersections", NULL); +} + +void +intersections (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_perf_run (perf, "intersections-nz-fill", random_nz, NULL); + cairo_perf_run (perf, "intersections-eo-fill", random_eo, NULL); + + cairo_perf_run (perf, "intersections-nz-curve-fill", random_curve_nz, NULL); + cairo_perf_run (perf, "intersections-eo-curve-fill", random_curve_eo, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/line.c b/local/recipes/libs/cairo/source/perf/micro/line.c new file mode 100644 index 0000000000..3ed5f8dacf --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/line.c @@ -0,0 +1,222 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-perf.h" + +static cairo_time_t +horizontal (cairo_t *cr, int width, int height, int loops) +{ + double h = height/2 + .5; + + cairo_move_to (cr, 0, h); + cairo_line_to (cr, width, h); + + cairo_perf_timer_start (); + + while (loops--) + cairo_stroke_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +horizontal_hair (cairo_t *cr, int width, int height, int loops) +{ + cairo_set_line_width (cr, 1.); + return horizontal (cr, width, height, loops); +} + +static cairo_time_t +horizontal_wide (cairo_t *cr, int width, int height, int loops) +{ + cairo_set_line_width (cr, 5.); + return horizontal (cr, width, height, loops); +} + +static cairo_time_t +nearly_horizontal (cairo_t *cr, int width, int height, int loops) +{ + double h = height/2; + + cairo_move_to (cr, 0, h); + cairo_line_to (cr, width, h+1); + + cairo_perf_timer_start (); + + while (loops--) + cairo_stroke_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +nearly_horizontal_hair (cairo_t *cr, int width, int height, int loops) +{ + cairo_set_line_width (cr, 1.); + return nearly_horizontal (cr, width, height, loops); +} + +static cairo_time_t +nearly_horizontal_wide (cairo_t *cr, int width, int height, int loops) +{ + cairo_set_line_width (cr, 5.); + return nearly_horizontal (cr, width, height, loops); +} + + +static cairo_time_t +vertical (cairo_t *cr, int width, int height, int loops) +{ + double w = width/2 + .5; + + cairo_move_to (cr, w, 0); + cairo_line_to (cr, w, height); + + cairo_perf_timer_start (); + + while (loops--) + cairo_stroke_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +vertical_hair (cairo_t *cr, int width, int height, int loops) +{ + cairo_set_line_width (cr, 1.); + return vertical (cr, width, height, loops); +} + +static cairo_time_t +vertical_wide (cairo_t *cr, int width, int height, int loops) +{ + cairo_set_line_width (cr, 5.); + return vertical (cr, width, height, loops); +} + +static cairo_time_t +nearly_vertical (cairo_t *cr, int width, int height, int loops) +{ + double w = width/2; + + cairo_move_to (cr, w, 0); + cairo_line_to (cr, w+1, height); + + cairo_perf_timer_start (); + + while (loops--) + cairo_stroke_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +nearly_vertical_hair (cairo_t *cr, int width, int height, int loops) +{ + cairo_set_line_width (cr, 1.); + return nearly_vertical (cr, width, height, loops); +} + +static cairo_time_t +nearly_vertical_wide (cairo_t *cr, int width, int height, int loops) +{ + cairo_set_line_width (cr, 5.); + return nearly_vertical (cr, width, height, loops); +} + + +static cairo_time_t +diagonal (cairo_t *cr, int width, int height, int loops) +{ + cairo_move_to (cr, 0, 0); + cairo_line_to (cr, width, height); + + cairo_perf_timer_start (); + + while (loops--) + cairo_stroke_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +diagonal_hair (cairo_t *cr, int width, int height, int loops) +{ + cairo_set_line_width (cr, 1.); + return diagonal (cr, width, height, loops); +} + +static cairo_time_t +diagonal_wide (cairo_t *cr, int width, int height, int loops) +{ + cairo_set_line_width (cr, 5.); + return diagonal (cr, width, height, loops); +} + +cairo_bool_t +line_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "line", NULL); +} + +void +line (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1., 1., 1.); + + cairo_perf_run (perf, "line-hh", horizontal_hair, NULL); + cairo_perf_run (perf, "line-hw", horizontal_wide, NULL); + cairo_perf_run (perf, "line-nhh", nearly_horizontal_hair, NULL); + cairo_perf_run (perf, "line-nhw", nearly_horizontal_wide, NULL); + + cairo_perf_run (perf, "line-vh", vertical_hair, NULL); + cairo_perf_run (perf, "line-vw", vertical_wide, NULL); + cairo_perf_run (perf, "line-nvh", nearly_vertical_hair, NULL); + cairo_perf_run (perf, "line-nvw", nearly_vertical_wide, NULL); + + cairo_perf_run (perf, "line-dh", diagonal_hair, NULL); + cairo_perf_run (perf, "line-dw", diagonal_wide, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/long-dashed-lines.c b/local/recipes/libs/cairo/source/perf/micro/long-dashed-lines.c new file mode 100644 index 0000000000..ba66a4af42 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/long-dashed-lines.c @@ -0,0 +1,74 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* + * Copyright © 2007 Mozilla Corporation + * + * 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: Vladimir Vukicevic + */ + +#include "cairo-perf.h" + +static cairo_time_t +do_long_dashed_lines (cairo_t *cr, int width, int height, int loops) +{ + double dash[2] = { 2.0, 2.0 }; + int i; + + cairo_save (cr); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); + cairo_set_dash (cr, dash, 2, 0.0); + + cairo_new_path (cr); + cairo_set_line_width (cr, 1.0); + + for (i = 0; i < height-1; i++) { + double y0 = (double) i + 0.5; + cairo_move_to (cr, 0.0, y0); + cairo_line_to (cr, width, y0); + } + + cairo_perf_timer_start (); + + while (loops--) + cairo_stroke_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_restore (cr); + + return cairo_perf_timer_elapsed (); +} + +cairo_bool_t +long_dashed_lines_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "long-dashed-lines", NULL); +} + +void +long_dashed_lines (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_perf_run (perf, "long-dashed-lines", do_long_dashed_lines, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/long-lines.c b/local/recipes/libs/cairo/source/perf/micro/long-lines.c new file mode 100644 index 0000000000..7bfe624cbb --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/long-lines.c @@ -0,0 +1,148 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * 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: Carl D. Worth + */ + +#include "cairo-perf.h" + +/* This test case is designed to illustrate a performance bug in + * drawing very long lines, where most of the line is out of bounds of + * the destination surface, (but some portion of the line is + * visible). These results are in the "long-lines-uncropped" report. + * + * For comparison, this test also renders the visible portions of the + * same lines, (this is the "long-lines-cropped" report). + */ + +typedef enum { + LONG_LINES_CROPPED = 0x1, + LONG_LINES_ONCE = 0x2, +} long_lines_crop_t; +#define NUM_LINES 20 +#define LONG_FACTOR 50.0 + +static cairo_time_t +do_long_lines (cairo_t *cr, int width, int height, int loops, long_lines_crop_t crop) +{ + int i; + double x, y, dx, dy, min_x, min_y, max_x, max_y; + double outer_width, outer_height; + + cairo_save (cr); + + cairo_translate (cr, width / 2, height / 2); + + if (crop & LONG_LINES_CROPPED) { + outer_width = width; + outer_height = height; + cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); /* green */ + } else { + outer_width = LONG_FACTOR * width; + outer_height = LONG_FACTOR * height; + cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); /* red */ + } + + min_x = x = - outer_width / 2.0; + min_y = y = - outer_height / 2.0; + max_x = outer_width / 2.0; + max_y = outer_height / 2.0; + dx = outer_width / NUM_LINES; + dy = outer_height / NUM_LINES; + + cairo_perf_timer_start (); + + while (loops--) { + for (i = 0; i <= NUM_LINES; i++) { + cairo_move_to (cr, 0, 0); + cairo_line_to (cr, x, min_y); + if ((crop & LONG_LINES_ONCE) == 0) + cairo_stroke (cr); + + cairo_move_to (cr, 0, 0); + cairo_line_to (cr, x, max_y); + if ((crop & LONG_LINES_ONCE) == 0) + cairo_stroke (cr); + + cairo_move_to (cr, 0, 0); + cairo_line_to (cr, min_x, y); + if ((crop & LONG_LINES_ONCE) == 0) + cairo_stroke (cr); + + cairo_move_to (cr, 0, 0); + cairo_line_to (cr, max_x, y); + if ((crop & LONG_LINES_ONCE) == 0) + cairo_stroke (cr); + + x += dx; + y += dy; + } + if (crop & LONG_LINES_ONCE) + cairo_stroke (cr); + } + + cairo_perf_timer_stop (); + + cairo_restore (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +long_lines_uncropped (cairo_t *cr, int width, int height, int loops) +{ + return do_long_lines (cr, width, height, loops, 0); +} + +static cairo_time_t +long_lines_uncropped_once (cairo_t *cr, int width, int height, int loops) +{ + return do_long_lines (cr, width, height, loops, LONG_LINES_ONCE); +} + +static cairo_time_t +long_lines_cropped (cairo_t *cr, int width, int height, int loops) +{ + return do_long_lines (cr, width, height, loops, LONG_LINES_CROPPED); +} + +static cairo_time_t +long_lines_cropped_once (cairo_t *cr, int width, int height, int loops) +{ + return do_long_lines (cr, width, height, loops, LONG_LINES_CROPPED | LONG_LINES_ONCE); +} + +cairo_bool_t +long_lines_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "long-lines", NULL); +} + +void +long_lines (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_perf_run (perf, "long-lines-uncropped", long_lines_uncropped, NULL); + cairo_perf_run (perf, "long-lines-uncropped-once", long_lines_uncropped_once, NULL); + cairo_perf_run (perf, "long-lines-cropped", long_lines_cropped, NULL); + cairo_perf_run (perf, "long-lines-cropped-once", long_lines_cropped_once, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/many-curves.c b/local/recipes/libs/cairo/source/perf/micro/many-curves.c new file mode 100644 index 0000000000..f985d349a6 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/many-curves.c @@ -0,0 +1,135 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-perf.h" + +static uint32_t state; + +static double +uniform_random (double minval, double maxval) +{ + static uint32_t const poly = 0x9a795537U; + uint32_t n = 32; + while (n-->0) + state = 2*state < state ? (2*state ^ poly) : 2*state; + return minval + state * (maxval - minval) / 4294967296.0; +} + +static cairo_time_t +do_many_curves_stroked (cairo_t *cr, int width, int height, int loops) +{ + int count; + + state = 0xc0ffee; + cairo_move_to (cr, uniform_random (0, width), uniform_random (0, height)); + for (count = 0; count < 1000; count++) { + double x1 = uniform_random (0, width); + double x2 = uniform_random (0, width); + double x3 = uniform_random (0, width); + double y1 = uniform_random (0, height); + double y2 = uniform_random (0, height); + double y3 = uniform_random (0, height); + cairo_curve_to (cr, x1, y1, x2, y2, x3, y3); + } + + cairo_perf_timer_start (); + + while (loops--) + cairo_stroke_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_many_curves_hair_stroked (cairo_t *cr, int width, int height, int loops) +{ + cairo_set_line_width (cr, 1.); + return do_many_curves_stroked (cr, width, height, loops); +} + +static cairo_time_t +do_many_curves_wide_stroked (cairo_t *cr, int width, int height, int loops) +{ + cairo_set_line_width (cr, 5.); + return do_many_curves_stroked (cr, width, height, loops); +} + +static cairo_time_t +do_many_curves_filled (cairo_t *cr, int width, int height, int loops) +{ + int count; + + state = 0xc0ffee; + for (count = 0; count < 1000; count++) { + double x0 = uniform_random (0, width); + double x1 = uniform_random (0, width); + double x2 = uniform_random (0, width); + double x3 = uniform_random (0, width); + double xm = uniform_random (0, width); + double xn = uniform_random (0, width); + double y0 = uniform_random (0, height); + double y1 = uniform_random (0, height); + double y2 = uniform_random (0, height); + double y3 = uniform_random (0, height); + double ym = uniform_random (0, height); + double yn = uniform_random (0, height); + cairo_move_to (cr, xm, ym); + cairo_curve_to (cr, x1, y1, x2, y2, xn, yn); + cairo_curve_to (cr, x3, y3, x0, y0, xm, ym); + cairo_close_path (cr); + } + + cairo_perf_timer_start (); + + while (loops--) + cairo_fill_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +cairo_bool_t +many_curves_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "many-curves", NULL); +} + +void +many_curves (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1., 1., 1.); + + cairo_perf_run (perf, "many-curves-hair-stroked", do_many_curves_hair_stroked, NULL); + cairo_perf_run (perf, "many-curves-wide-stroked", do_many_curves_wide_stroked, NULL); + cairo_perf_run (perf, "many-curves-filled", do_many_curves_filled, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/many-fills.c b/local/recipes/libs/cairo/source/perf/micro/many-fills.c new file mode 100644 index 0000000000..9d3fd64357 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/many-fills.c @@ -0,0 +1,187 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + + +/* This is a variant on many strokes where we precompute + * a simplified stroke-to-path. + * When we have a real stroke-to-path, it would useful to compare the cost + * of stroking vs filling the "identical" paths. + */ + +#include "cairo-perf.h" + +static uint32_t state; + +static double +uniform_random (double minval, double maxval) +{ + static uint32_t const poly = 0x9a795537U; + uint32_t n = 32; + while (n-->0) + state = 2*state < state ? (2*state ^ poly) : 2*state; + return minval + state * (maxval - minval) / 4294967296.0; +} + +static cairo_time_t +do_many_fills_ha (cairo_t *cr, int width, int height, int loops) +{ + int count; + + state = 0xc0ffee; + for (count = 0; count < 1000; count++) { + double y = floor (uniform_random (0, height)); + double x = floor (uniform_random (0, width)); + cairo_rectangle (cr, x, y, ceil (uniform_random (0, width)) - x, 1); + } + + cairo_perf_timer_start (); + + while (loops--) + cairo_fill_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_many_fills_h (cairo_t *cr, int width, int height, int loops) +{ + int count; + + state = 0xc0ffee; + for (count = 0; count < 1000; count++) { + double y = uniform_random (0, height); + double x = uniform_random (0, width); + cairo_rectangle (cr, x, y, uniform_random (0, width) - x, 1); + } + + cairo_perf_timer_start (); + + while (loops--) + cairo_fill_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_many_fills_va (cairo_t *cr, int width, int height, int loops) +{ + int count; + + state = 0xc0ffee; + for (count = 0; count < 1000; count++) { + double x = floor (uniform_random (0, width)); + double y = floor (uniform_random (0, height)); + cairo_rectangle (cr, x, y, 1, ceil (uniform_random (0, height) - y)); + } + + cairo_perf_timer_start (); + + while (loops--) + cairo_fill_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_many_fills_v (cairo_t *cr, int width, int height, int loops) +{ + int count; + + state = 0xc0ffee; + for (count = 0; count < 1000; count++) { + double x = uniform_random (0, width); + double y = uniform_random (0, height); + cairo_rectangle (cr, x, y, 1, uniform_random (0, height) - y); + } + + cairo_perf_timer_start (); + + while (loops--) + cairo_fill_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_many_fills (cairo_t *cr, int width, int height, int loops) +{ + int count; + + /* lots and lots of overlapping stroke-like fills */ + state = 0xc0ffee; + for (count = 0; count < 1000; count++) { + cairo_save (cr); + cairo_translate (cr, + uniform_random (0, width), + uniform_random (0, height)); + cairo_rotate (cr, uniform_random (-M_PI,M_PI)); + cairo_rectangle (cr, 0, 0, uniform_random (0, width), 1); + cairo_restore (cr); + } + + cairo_perf_timer_start (); + + while (loops--) + cairo_fill_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +cairo_bool_t +many_fills_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "many-fills", NULL); +} + +void +many_fills (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_perf_run (perf, "many-fills-halign", do_many_fills_ha, NULL); + cairo_perf_run (perf, "many-fills-valign", do_many_fills_va, NULL); + cairo_perf_run (perf, "many-fills-horizontal", do_many_fills_h, NULL); + cairo_perf_run (perf, "many-fills-vertical", do_many_fills_v, NULL); + cairo_perf_run (perf, "many-fills-random", do_many_fills, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/many-strokes.c b/local/recipes/libs/cairo/source/perf/micro/many-strokes.c new file mode 100644 index 0000000000..9aeb393dee --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/many-strokes.c @@ -0,0 +1,186 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-perf.h" + +static uint32_t state; + +static double +uniform_random (double minval, double maxval) +{ + static uint32_t const poly = 0x9a795537U; + uint32_t n = 32; + while (n-->0) + state = 2*state < state ? (2*state ^ poly) : 2*state; + return minval + state * (maxval - minval) / 4294967296.0; +} + +static cairo_time_t +do_many_strokes_ha (cairo_t *cr, int width, int height, int loops) +{ + int count; + + state = 0xc0ffee; + for (count = 0; count < 1000; count++) { + double h = floor (uniform_random (0, height)) + .5; + cairo_move_to (cr, floor (uniform_random (0, width)), h); + cairo_line_to (cr, ceil (uniform_random (0, width)), h); + } + + cairo_set_line_width (cr, 1.); + + cairo_perf_timer_start (); + + while (loops--) + cairo_stroke_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_many_strokes_h (cairo_t *cr, int width, int height, int loops) +{ + int count; + + state = 0xc0ffee; + for (count = 0; count < 1000; count++) { + double h = uniform_random (0, height); + cairo_move_to (cr, uniform_random (0, width), h); + cairo_line_to (cr, uniform_random (0, width), h); + } + + cairo_set_line_width (cr, 1.); + + cairo_perf_timer_start (); + + while (loops--) + cairo_stroke_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_many_strokes_va (cairo_t *cr, int width, int height, int loops) +{ + int count; + + state = 0xc0ffee; + for (count = 0; count < 1000; count++) { + double v = floor (uniform_random (0, width)) + .5; + cairo_move_to (cr, v, floor (uniform_random (0, height))); + cairo_line_to (cr, v, ceil (uniform_random (0, height))); + } + + cairo_set_line_width (cr, 1.); + + cairo_perf_timer_start (); + + while (loops--) + cairo_stroke_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_many_strokes_v (cairo_t *cr, int width, int height, int loops) +{ + int count; + + state = 0xc0ffee; + for (count = 0; count < 1000; count++) { + double v = uniform_random (0, width); + cairo_move_to (cr, v, uniform_random (0, height)); + cairo_line_to (cr, v, uniform_random (0, height)); + } + + cairo_set_line_width (cr, 1.); + + cairo_perf_timer_start (); + + while (loops--) + cairo_stroke_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_many_strokes (cairo_t *cr, int width, int height, int loops) +{ + int count; + + /* lots and lots of overlapping strokes */ + state = 0xc0ffee; + for (count = 0; count < 1000; count++) { + cairo_line_to (cr, + uniform_random (0, width), + uniform_random (0, height)); + } + + cairo_set_line_width (cr, 1.); + + cairo_perf_timer_start (); + + while (loops--) + cairo_stroke_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +cairo_bool_t +many_strokes_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "many-strokes", NULL); +} + +void +many_strokes (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_perf_run (perf, "many-strokes-halign", do_many_strokes_ha, NULL); + cairo_perf_run (perf, "many-strokes-valign", do_many_strokes_va, NULL); + cairo_perf_run (perf, "many-strokes-horizontal", do_many_strokes_h, NULL); + cairo_perf_run (perf, "many-strokes-vertical", do_many_strokes_v, NULL); + cairo_perf_run (perf, "many-strokes-random", do_many_strokes, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/mask.c b/local/recipes/libs/cairo/source/perf/micro/mask.c new file mode 100644 index 0000000000..11a3ba730a --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/mask.c @@ -0,0 +1,305 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * Copyright © 2009 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + * Chris Wilson + */ + +#include "cairo-perf.h" + +static cairo_time_t +do_mask_solid (cairo_t *cr, int width, int height, int loops) +{ + cairo_pattern_t *mask; + + mask = cairo_pattern_create_rgba (0, 0, 0, .5); + + cairo_perf_timer_start (); + + while (loops--) + cairo_mask (cr, mask); + + cairo_perf_timer_stop (); + + cairo_pattern_destroy (mask); + + return cairo_perf_timer_elapsed (); +} + +static cairo_surface_t * +init_surface (cairo_surface_t *surface, int width, int height) +{ + cairo_t *cr; + + cr = cairo_create (surface); + cairo_surface_destroy (surface); + + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgb (cr, 0, 0, 0); /* back */ + cairo_paint (cr); + + cairo_set_source_rgba (cr, 1, 1, 1, 0.5); /* 50% */ + cairo_new_path (cr); + cairo_rectangle (cr, 0, 0, width/2.0, height/2.0); + cairo_rectangle (cr, width/2.0, height/2.0, width/2.0, height/2.0); + cairo_fill (cr); + + surface = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + + return surface; +} + +static cairo_time_t +do_mask_image (cairo_t *cr, int width, int height, int loops) +{ + cairo_surface_t *surface; + cairo_pattern_t *mask; + + surface = cairo_image_surface_create (CAIRO_FORMAT_A8, width, height); + mask = cairo_pattern_create_for_surface (init_surface (surface, + width, + height)); + cairo_surface_destroy (surface); + + cairo_perf_timer_start (); + + while (loops--) + cairo_mask (cr, mask); + + cairo_perf_timer_stop (); + + cairo_pattern_destroy (mask); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_mask_image_half (cairo_t *cr, int width, int height, int loops) +{ + cairo_surface_t *surface; + cairo_pattern_t *mask; + cairo_matrix_t matrix; + + surface = cairo_image_surface_create (CAIRO_FORMAT_A8, width, height); + mask = cairo_pattern_create_for_surface (init_surface (surface, + width, + height)); + cairo_surface_destroy (surface); + cairo_matrix_init_scale (&matrix, .5, .5); + cairo_pattern_set_matrix (mask, &matrix); + + cairo_perf_timer_start (); + + while (loops--) + cairo_mask (cr, mask); + + cairo_perf_timer_stop (); + + cairo_pattern_destroy (mask); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_mask_image_double (cairo_t *cr, int width, int height, int loops) +{ + cairo_surface_t *surface; + cairo_pattern_t *mask; + cairo_matrix_t matrix; + + surface = cairo_image_surface_create (CAIRO_FORMAT_A8, width, height); + mask = cairo_pattern_create_for_surface (init_surface (surface, + width, + height)); + cairo_surface_destroy (surface); + cairo_matrix_init_scale (&matrix, 2., 2.); + cairo_pattern_set_matrix (mask, &matrix); + + cairo_perf_timer_start (); + + while (loops--) + cairo_mask (cr, mask); + + cairo_perf_timer_stop (); + + cairo_pattern_destroy (mask); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_mask_similar (cairo_t *cr, int width, int height, int loops) +{ + cairo_surface_t *surface; + cairo_pattern_t *mask; + + surface = cairo_surface_create_similar (cairo_get_group_target (cr), + CAIRO_CONTENT_ALPHA, width, height); + mask = cairo_pattern_create_for_surface (init_surface (surface, + width, + height)); + cairo_surface_destroy (surface); + + cairo_perf_timer_start (); + + while (loops--) + cairo_mask (cr, mask); + + cairo_perf_timer_stop (); + + cairo_pattern_destroy (mask); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_mask_similar_half (cairo_t *cr, int width, int height, int loops) +{ + cairo_surface_t *surface; + cairo_pattern_t *mask; + cairo_matrix_t matrix; + + surface = cairo_surface_create_similar (cairo_get_group_target (cr), + CAIRO_CONTENT_ALPHA, width, height); + mask = cairo_pattern_create_for_surface (init_surface (surface, + width, + height)); + cairo_surface_destroy (surface); + cairo_matrix_init_scale (&matrix, .5, .5); + cairo_pattern_set_matrix (mask, &matrix); + + cairo_perf_timer_start (); + + while (loops--) + cairo_mask (cr, mask); + + cairo_perf_timer_stop (); + + cairo_pattern_destroy (mask); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_mask_similar_double (cairo_t *cr, int width, int height, int loops) +{ + cairo_surface_t *surface; + cairo_pattern_t *mask; + cairo_matrix_t matrix; + + surface = cairo_surface_create_similar (cairo_get_group_target (cr), + CAIRO_CONTENT_ALPHA, width, height); + mask = cairo_pattern_create_for_surface (init_surface (surface, + width, + height)); + cairo_surface_destroy (surface); + cairo_matrix_init_scale (&matrix, 2., 2.); + cairo_pattern_set_matrix (mask, &matrix); + + cairo_perf_timer_start (); + + while (loops--) + cairo_mask (cr, mask); + + cairo_perf_timer_stop (); + + cairo_pattern_destroy (mask); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_mask_linear (cairo_t *cr, int width, int height, int loops) +{ + cairo_pattern_t *mask; + + mask = cairo_pattern_create_linear (0.0, 0.0, width, height); + cairo_pattern_add_color_stop_rgba (mask, 0.0, 0, 0, 0, 0.5); /* 50% */ + cairo_pattern_add_color_stop_rgba (mask, 0.0, 0, 0, 0, 1.0); /* 100% */ + + cairo_perf_timer_start (); + + while (loops--) + cairo_mask (cr, mask); + + cairo_perf_timer_stop (); + + cairo_pattern_destroy (mask); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_mask_radial (cairo_t *cr, int width, int height, int loops) +{ + cairo_pattern_t *mask; + + mask = cairo_pattern_create_radial (width/2.0, height/2.0, 0.0, + width/2.0, height/2.0, width/2.0); + cairo_pattern_add_color_stop_rgba (mask, 0.0, 0, 0, 0, 0.5); /* 50% */ + cairo_pattern_add_color_stop_rgba (mask, 0.0, 0, 0, 0, 1.0); /* 100% */ + + cairo_perf_timer_start (); + + while (loops--) + cairo_mask (cr, mask); + + cairo_perf_timer_stop (); + + cairo_pattern_destroy (mask); + + return cairo_perf_timer_elapsed (); +} + +cairo_bool_t +mask_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "mask", NULL); +} + +void +mask (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + if (! cairo_perf_can_run (perf, "mask", NULL)) + return; + + cairo_perf_cover_sources_and_operators (perf, "mask-solid", + do_mask_solid, NULL); + cairo_perf_cover_sources_and_operators (perf, "mask-image", + do_mask_image, NULL); + cairo_perf_cover_sources_and_operators (perf, "mask-image-half", + do_mask_image_half, NULL); + cairo_perf_cover_sources_and_operators (perf, "mask-image-double", + do_mask_image_double, NULL); + cairo_perf_cover_sources_and_operators (perf, "mask-similar", + do_mask_similar, NULL); + cairo_perf_cover_sources_and_operators (perf, "mask-similar-half", + do_mask_similar_half, NULL); + cairo_perf_cover_sources_and_operators (perf, "mask-similar-double", + do_mask_similar_double, NULL); + cairo_perf_cover_sources_and_operators (perf, "mask-linear", + do_mask_linear, NULL); + cairo_perf_cover_sources_and_operators (perf, "mask-radial", + do_mask_radial, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/meson.build b/local/recipes/libs/cairo/source/perf/micro/meson.build new file mode 100644 index 0000000000..8802f4c45d --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/meson.build @@ -0,0 +1,60 @@ +perf_micro_sources = [ + 'cairo-perf-cover.c', + 'box-outline.c', + 'composite-checker.c', + 'disjoint.c', + 'fill.c', + 'hatching.c', + 'hash-table.c', + 'line.c', + 'a1-line.c', + 'long-lines.c', + 'mosaic.c', + 'paint.c', + 'paint-with-alpha.c', + 'mask.c', + 'pattern_create_radial.c', + 'rectangles.c', + 'rounded-rectangles.c', + 'stroke.c', + 'subimage_copy.c', + 'tessellate.c', + 'text.c', + 'tiger.c', + 'glyphs.c', + 'twin.c', + 'unaligned-clip.c', + 'wave.c', + 'world-map.c', + 'zrusin.c', + 'long-dashed-lines.c', + 'dragon.c', + 'pythagoras-tree.c', + 'intersections.c', + 'many-strokes.c', + 'wide-strokes.c', + 'many-fills.c', + 'wide-fills.c', + 'many-curves.c', + 'curve.c', + 'a1-curve.c', + 'spiral.c', + 'pixel.c', + 'sierpinski.c', + 'fill-clip.c', +] + +perf_micro_headers = [ + 'mosaic.h', + 'world-map.h', + 'zrusin-another.h', +] + +libcairoperfmicro = static_library('cairo-perf-micro', + perf_micro_sources + perf_micro_headers, + include_directories: [incbase, incsrc, incmicro], + dependencies: [pixman_dep, cairoboilerplate_dep], +) +libcairoperfmicro_dep = declare_dependency( + link_with: libcairoperfmicro, +) diff --git a/local/recipes/libs/cairo/source/perf/micro/mosaic.c b/local/recipes/libs/cairo/source/perf/micro/mosaic.c new file mode 100644 index 0000000000..ed30ae5554 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/mosaic.c @@ -0,0 +1,176 @@ +/* + * Copyright © 2006 Joonas Pihlaja + * + * 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: Joonas Pihlaja + */ +#include "cairo-perf.h" + +/* Options passed in flags to mosaic_perform(): */ +#define MOSAIC_FILL 1 /* do rasterise */ +#define MOSAIC_TESSELLATE 0 /* just tessellate */ +#define MOSAIC_CURVE_TO 2 /* use curve bounded regions */ +#define MOSAIC_LINE_TO 0 /* use line bounded regions */ + +struct mosaic_region { + unsigned rgb; /* colour of this region in 0xRRGGBB format */ + unsigned ncurves; /* number of boundary curves. */ +}; + +struct mosaic_region_iter { + int do_curves; + struct mosaic_region const *region; + double const *points; +}; + +#include "mosaic.h" + +static void +mosaic_region_iter_init (struct mosaic_region_iter *iter, int do_curves) +{ + iter->region = mosaic_regions; + iter->points = mosaic_curve_points; + iter->do_curves = do_curves; +} + +/* Create the next closed region as a path. */ +static int +mosaic_next_path (cairo_t *cr, struct mosaic_region_iter *iter) +{ + double const *points = iter->points; + unsigned i; + unsigned ncurves = iter->region->ncurves; + if (0 == ncurves) { + return 0; + } + + cairo_new_path (cr); + cairo_move_to (cr, points[0], points[1]); + points += 2; + for (i=0; i < ncurves; i++, points += 6) { + if (iter->do_curves) { + cairo_curve_to (cr, + points[0], points[1], + points[2], points[3], + points[4], points[5]); + } + else { + cairo_line_to (cr, + points[4], points[5]); + } + } + cairo_close_path (cr); + { + unsigned rgb = iter->region->rgb; + double r = ((rgb >> 16) & 255) / 255.0; + double g = ((rgb >> 8) & 255) / 255.0; + double b = ((rgb >> 0) & 255) / 255.0; + cairo_set_source_rgb (cr, r, g, b); + } + + iter->points = iter->points + 2*(1 + 3*iter->region->ncurves); + iter->region++; + return 1; +} + +static cairo_time_t +mosaic_perform(cairo_t *cr, unsigned flags, int width, int height, int loops) +{ + struct mosaic_region_iter iter; + + /* Scale to fit the window.*/ + double minx = -40.7; + double maxx = 955.1; + double miny = -88.4; + double maxy = 884.5; + + cairo_identity_matrix (cr); + + if (flags & MOSAIC_FILL) { + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_rectangle (cr, 0, 0, width, height); + cairo_fill (cr); + } + + cairo_scale (cr, width / (maxx - minx) , height / (maxy - miny)); + cairo_translate (cr, -minx, -miny); + + /* Iterate over all closed regions in the mosaic filling or + * tessellating them as dictated by the flags. */ + + cairo_perf_timer_start (); + while (loops--) { + mosaic_region_iter_init (&iter, flags & MOSAIC_CURVE_TO); + while (mosaic_next_path (cr, &iter)) { + if (flags & MOSAIC_FILL) { + cairo_fill (cr); + } + else { + double x, y; + cairo_get_current_point (cr, &x, &y); + cairo_in_fill (cr, x, y); + } + } + } + cairo_perf_timer_stop (); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +mosaic_fill_curves (cairo_t *cr, int width, int height, int loops) +{ + return mosaic_perform (cr, MOSAIC_FILL | MOSAIC_CURVE_TO, width, height, loops); +} + +static cairo_time_t +mosaic_fill_lines (cairo_t *cr, int width, int height, int loops) +{ + return mosaic_perform (cr, MOSAIC_FILL | MOSAIC_LINE_TO, width, height, loops); +} + +static cairo_time_t +mosaic_tessellate_lines (cairo_t *cr, int width, int height, int loops) +{ + return mosaic_perform (cr, MOSAIC_TESSELLATE | MOSAIC_LINE_TO, width, height, loops); +} + +static cairo_time_t +mosaic_tessellate_curves (cairo_t *cr, int width, int height, int loops) +{ + return mosaic_perform (cr, MOSAIC_TESSELLATE | MOSAIC_CURVE_TO, width, height, loops); +} + +cairo_bool_t +mosaic_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "mosaic", NULL); +} + +void +mosaic (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_perf_run (perf, "mosaic-fill-curves", mosaic_fill_curves, NULL); + cairo_perf_run (perf, "mosaic-fill-lines", mosaic_fill_lines, NULL); + cairo_perf_run (perf, "mosaic-tessellate-curves", mosaic_tessellate_curves, NULL); + cairo_perf_run (perf, "mosaic-tessellate-lines", mosaic_tessellate_lines, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/mosaic.h b/local/recipes/libs/cairo/source/perf/micro/mosaic.h new file mode 100644 index 0000000000..e106864a31 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/mosaic.h @@ -0,0 +1,4387 @@ +/* Synthesised data. */ +static struct mosaic_region const mosaic_regions[] = { +{0xef55b4,7},{0xf93bc6,11},{0xf28085,5},{0x92acbc,7}, +{0x85c3b1,7},{0xc3bc79,5},{0xd09d8d,5},{0xa788cb,8}, +{0xeff90f,14},{0x976ef2,4},{0xf230d8,5},{0xe226ef,6}, +{0xf49571,9},{0xcb6cc1,4},{0xc8af80,5},{0xf71ce7,8}, +{0xd38b9a,6},{0xf70ff2,8},{0xec907e,4},{0xf44abc,5}, +{0xf42bd8,7},{0xcbbc71,5},{0xf7a45f,5},{0xb15aec,3}, +{0xfc6995,9},{0x42bef9,7},{0x83afc6,5},{0xbe9f9a,6}, +{0x95ef76,6},{0xfcc33b,20},{0xbc5ae2,5},{0x69f997,7}, +{0x9f69f2,7},{0x79bec3,7},{0xda3de2,6},{0x76dda7,6}, +{0xc888aa,7},{0xd871b1,9},{0xda29f7,14},{0xe03dda,9}, +{0xec29e2,5},{0xd82bf4,6},{0x8b8de2,6},{0xf7af52,3}, +{0x9f69f2,7},{0xf46c9a,9},{0xf74fb1,5},{0x21eaef,9}, +{0xea769a,8},{0x0feffc,5},{0xdada45,8},{0xafce7b,6}, +{0x48bef4,6},{0x9a79e5,3},{0xe2fc1c,7},{0xc3be76,9}, +{0xb9c37e,5},{0xc6b183,10},{0xa2acac,3},{0xc395a2,4}, +{0xbc88b4,7},{0xeaf41c,5},{0xea24ea,4},{0xd038f2,5}, +{0x5ae2bc,9},{0xdac15f,8},{0x5fe5b4,6},{0xce5ad3,15}, +{0xf419ec,4},{0xa7bc97,11},{0xea4ac3,6},{0xd02ef9,5}, +{0xb995aa,5},{0xef808b,6},{0xe22bea,34},{0xe24fc6,4}, +{0xef12f9,7},{0x7b9de0,8},{0x85ec85,4},{0xfc7e80,12}, +{0x9a85d8,5},{0xfc00fc,7},{0x9d90ce,5},{0xf4be45,9}, +{0xe5e52e,3},{0xfc0cef,7},{0xd83be5,8},{0x4dc6e5,5}, +{0xacda73,9},{0x4fc8e0,6},{0xbc88b6,4},{0xb4bc8b,6}, +{0xec45c6,8},{0x71d3b6,4},{0xe73dd5,5},{0x21fcda,4}, +{0xe055c6,9},{0x3becd0,8},{0x57e0c1,5},{0x71bec8,9}, +{0x8be28b,4},{0x4dddd0,9},{0xda9a85,6},{0xaa6ce2,4}, +{0x5ad5cb,9},{0x67f49d,12},{0xfc07f7,9},{0x42c8ec,16}, +{0xefc148,4},{0xda6eb1,7},{0x55bee7,4},{0xd33bea,6}, +{0x809fd8,14},{0xd82ef2,4},{0x21ddfc,5},{0x83e097,7}, +{0x8bcba2,9},{0xd864bc,8},{0xa7d87b,6},{0xc3a78d,6}, +{0xb9a79a,8},{0xd59590,3},{0xfc0af2,6},{0xe52be7,7}, +{0xce52d8,5},{0xe22bea,4},{0xe719f7,5},{0x909fcb,3}, +{0xa7da76,6},{0xdd38e5,4},{0xfc55aa,6},{0x19f2ef,6}, +{0x83da9d,5},{0x9fc892,6},{0xe51ef4,9},{0xce3dec,5}, +{0xea3dd0,7},{0x4ad3dd,6},{0x6ea2e7,5},{0xf92bd3,4}, +{0xc34aea,8},{0x2eddef,4},{0xe7799a,8},{0xe5799a,11}, +{0xe224f2,3},{0xf90af7,6},{0x61a2f4,6},{0xb67ec6,13}, +{0xe75cb4,7},{0xfcb945,16},{0xd3b173,7},{0xfc00fc,6}, +{0xd5ef33,5},{0x699df4,9},{0xf707f9,4},{0xdaea33,6}, +{0xe2dd38,3},{0xf2d036,5},{0xf248c1,6},{0xeaf21c,5}, +{0xec40cb,7},{0xf24abc,5},{0xf42bd8,4},{0xa757f9,5}, +{0xd02ef9,6},{0xfc0cf2,7},{0xb16cda,5},{0xea36d8,8}, +{0xd036f4,7},{0xb648fc,3},{0xea4dc1,4},{0x64c8cb,7}, +{0xfc05f7,3},{0xfc00fc,4},{0xf4a75f,6},{0xc85ad5,5}, +{0xd873ac,5},{0xd5a77b,11},{0xe7c84a,4},{0xec19f4,7}, +{0xc864ce,7},{0xcece5c,5},{0xe08b8d,5},{0xd84dd3,3}, +{0x07f9f7,9},{0x5cefac,3},{0xfc02f9,4},{0xd048e0,8}, +{0xef55b6,4},{0xa269ec,7},{0xec12f9,3},{0xd380a4,11}, +{0x5fcbd0,6},{0x90c1a7,5},{0x95dd85,5},{0xceda4f,9}, +{0x4fb9f2,14},{0xb65aea,7},{0xea838d,5},{0xf917ea,4}, +{0xc833fc,9},{0xe252c3,9},{0xef0ffc,7},{0x1cf2ec,9}, +{0x9f6cef,4},{0xf73dc6,12},{0x90b6b4,5},{0xb44ff7,7}, +{0xea2be2,12},{0xd02efc,17},{0xa276e2,4},{0x79c1c1,3}, +{0xc855dd,9},{0xb1d571,8},{0xb645fc,6},{0xd03bef,6}, +{0x42eccb,9},{0xea67aa,5},{0x9079ef,6},{0x9de773,7}, +{0xe55abc,6},{0xf421e5,3},{0x5cf9a4,6},{0xc373c1,5}, +{0x5fe2b6,4},{0xea24ec,6},{0x9af967,4},{0xf7be45,5}, +{0xd333f4,5},{0xc6d061,8},{0xb96cd3,8},{0xda64b9,6}, +{0xe79779,4},{0xac67e7,6},{0xcb67c8,4},{0xa45cf7,3}, +{0xd3859f,3},{0xd857c8,4},{0x42c1f7,8},{0xaf61e7,6}, +{0xea14fc,6},{0xda33ea,10},{0x5af2af,5},{0xbe40f9,3}, +{0x9de773,3},{0xe72be5,4},{0x4ae7c6,5},{0xaa88c8,8}, +{0x36f9cb,3},{0xc1a790,8},{0xf905fc,5},{0xbcaa95,6}, +{0x839dda,3},{0xfc00fc,6},{0xb6d86c,3},{0xdd40da,6}, +{0xb46cda,7},{0x839fd5,4},{0xc167d3,13},{0xf20ff7,9}, +{0xe024f4,9},{0xf41ee5,4},{0x909ad0,10},{0xb1d376,8}, +{0xce2efc,5},{0x29d5f9,7},{0xd0b96e,6},{0xdd69b4,5}, +{0xfc05f7,5},{0xdd26f7,4},{0xea1eef,6},{0xb64df7,9}, +{0x21e5f2,3},{0x4fd8d0,6},{0xd345e0,7},{0xfc00fc,3}, +{0xe569ac,5},{0xecb655,11},{0xfc5aa2,9},{0xb4d571,7}, +{0xaa57f7,6},{0xfc00fc,7},{0xe729ea,10},{0xea24ea,11}, +{0xb14df9,5},{0xf707fc,7},{0x5cd8c3,5},{0xea17f9,9}, +{0xc3d364,6},{0xa77ed3,4},{0x9569f9,8},{0x0ff4f4,4}, +{0xbc9aa4,7},{0xc140f7,10},{0xf705fc,8},{0xb44df9,4}, +{0xa479dd,5},{0xf705fc,5},{0xce8d9d,5},{0xf905f9,5}, +{0xdd2bef,7},{0xea14f9,5},{0xddbc61,5},{0xc13dfc,8}, +{0x79c8b6,10},{0xf79a67,6},{0xb4a79f,12},{0x97a7bc,7}, +{0xb9c17e,4},{0xf430d5,3},{0x2ee0ea,7},{0xf919e7,4}, +{0xeada33,9},{0xa2da7e,7},{0x8bec80,6},{0xf412f4,5}, +{0xa767ec,3},{0xd824fc,7},{0xe224f2,3},{0xfc07f7,4}, +{0xfc00fc,3},{0xe55cb6,8},{0xf9768b,7},{0xe5b45f,3}, +{0xd5978b,4},{0xf917e7,5},{0xf70ff4,7},{0x95e283,6}, +{0xb4b98d,5},{0xc83bf4,8},{0x9f88d3,7},{0xa473e0,9}, +{0x9569fc,10},{0x926cf9,7},{0xef14f4,7},{0xf7679a,4}, +{0xaa80ce,9},{0x45f9b9,5},{0xb4a2a2,10},{0xac88c6,5}, +{0xe75ab6,6},{0xa2fc5a,3},{0xc65cd8,7},{0x64e0b6,5}, +{0xfc6992,7},{0xf717ec,4},{0xf438ce,10},{0xf755ac,4}, +{0xf7aa57,6},{0xb9b688,3},{0xcb4de2,4},{0xf9f70a,9}, +{0x92d392,8},{0xef2be0,7},{0x92a7be,4},{0xa276e2,4}, +{0xc34fe5,5},{0xd5c164,9},{0xf219ec,4},{0xef5aaf,8}, +{0xa7c68d,6},{0xd369bc,7},{0xf912ef,4},{0xb9b48b,6}, +{0x3bc6f9,6},{0xe54ac8,5},{0xf71ce7,9},{0xbc4def,8}, +{0xe271a7,3},{0xcbc16e,5},{0x3dfcc1,3},{0x97bea2,7}, +{0xaaa4aa,13},{0x73ef95,5},{0xf74fb1,4},{0xc148ef,17}, +{0xfc26d8,4},{0xfc02fc,6},{0xb1da6c,6},{0xd5d84d,7}, +{0xf96c95,5},{0xf90fef,3},{0xea7b92,7},{0xbc4def,4}, +{0xf2a264,8},{0x40dadd,12},{0xf214f4,4},{0x38c3fc,3}, +{0xf705fc,7},{0xa29db9,3},{0xaaf25f,4},{0xdd9a83,12}, +{0xc188b1,6},{0xa27bda,9},{0x36dde5,4},{0x85bcb9,7}, +{0xfc00fc,5},{0xe76ca4,4},{0x95b6ac,6},{0xb6d071,7}, +{0xc857d8,3},{0xfc2bd3,4},{0xfc5aa4,4},{0xf417ec,5}, +{0xb471d3,7},{0x92b1b6,4},{0x6c90fc,7},{0x5abce2,7}, +{0xcb55d8,3},{0xce30f9,5},{0xea7b95,3},{0xec17f7,6}, +{0xf70ff4,3},{0xaa73dd,9},{0x9d69f4,3},{0xb457ef,6}, +{0xf236d0,6},{0x64e0b4,7},{0xddcb52,4},{0xd0d355,7}, +{0x5fd5c3,6},{0xf42bd8,12},{0x55e2c1,4},{0xb1b492,4}, +{0xdd4dd0,4},{0xbc88b6,3},{0xea21ec,4},{0xf7649d,8}, +{0xb16cda,3},{0x9fa4b6,8},{0xea17f9,4},{0x1efce0,3}, +{0xbec179,7},{0xbeb18b,6},{0x9da4b6,6},{0x48b4fc,4}, +{0x7bfc83,14},{0xacf25c,10},{0xe0d842,4},{0xf9768b,5}, +{0xf90ff2,7},{0xfc00fc,8},{0xf20ff7,5},{0xec7e90,7}, +{0xbc42f9,3},{0xf712ef,5},{0xf902fc,6},{0xf77e83,7}, +{0xb1b197,5},{0xda6cb4,7},{0xf4a264,7},{0xa78dc6,6}, +{0xf21cea,4},{0xa48dc8,6},{0x6997f9,5},{0x67d3be,5}, +{0x4ad0e0,6},{0xcbbe6e,6},{0xcb76b6,10},{0xd030f9,6}, +{0xa29fb6,6},{0xda24fc,5},{0xf4bc48,3},{0xd0909a,6}, +{0xf252b6,8},{0x6cb4da,4},{0xdd40dd,11},{0x8b71fc,9}, +{0x80c8af,7},{0xb15fe7,4},{0x79ef90,6},{0x71b1d8,7}, +{0x61a4f2,9},{0x42dadd,6},{0xaf4ffc,3},{0x9a79e7,5}, +{0xea17f7,6},{0xc89f92,4},{0xb6d869,12},{0xda2eef,4}, +{0xf72ed5,6},{0xe057c3,6},{0xb6b190,6},{0xda48d5,5}, +{0xe0a476,3},{0xfce01c,6},{0x9dbe9f,13},{0xafce7e,4}, +{0xf905fc,6},{0xfc0cef,5},{0x9facaf,6},{0xb6af95,6}, +{0x52ced8,6},{0xd373b4,3},{0xce5cd0,8},{0xe752c1,5}, +{0xf7ac55,8},{0x7bbec1,6},{0xb4d571,4},{0xf90af7,5}, +{0xc833fc,7},{0xbe4dec,8},{0x92beaa,8},{0xfcb945,7}, +{0xc1d067,3},{0xdd45d8,7},{0xceb971,3},{0xf44ab9,4}, +{0xbeac8d,4},{0xf2af5a,15},{0xe05ac1,11},{0xd38b9d,4}, +{0xec0ffc,4},{0x80ec8d,7},{0xd0af7b,6},{0xef5cac,5}, +{0xdaa776,4},{0xd052d8,5},{0xb461e5,8},{0xef8388,7}, +{0xbea297,8},{0xce83a7,5},{0xda2ef2,3},{0x73b6ce,5}, +{0x83ec8b,9},{0xc840f2,7},{0xfc4faf,8},{0xfc14e7,4}, +{0xe742d0,9},{0x52aff7,4},{0xf214f4,4},{0x26f7da,5}, +{0xf2b94d,6},{0xe02eea,6},{0x76fc85,3},{0x858de7,4}, +{0xbc97a4,6},{0xd8aa79,4},{0x9d73ea,4},{0xdda279,5}, +{0xafc385,7},{0x33dde7,6},{0x64acea,8},{0xacce80,7}, +{0xef26e2,7},{0xb957e7,4},{0xdad548,4},{0xaf57f4,5}, +{0x9f73e5,3},{0xeae02e,7},{0xf70af7,8},{0xfc00fc,4}, +{0xea6ca4,6},{0x8885ec,3},{0xe23dda,4},{0xb461e5,10}, +{0xdd928b,6},{0x76cbb6,7},{0xfc00fc,5},{0xce8d9d,8}, +{0xafb692,12},{0xe79083,7},{0xfc0af2,3},{0xf926d8,8}, +{0xe219fc,5},{0xe7bc55,5},{0xcebc6e,3},{0xda73aa,4}, +{0xfc00fc,4},{0x52dace,5},{0xbcd864,6},{0x67e7ac,4}, +{0x33f9cb,3},{0x8bafc1,11},{0xd871af,6},{0xe78390,10}, +{0xb688bc,8},{0x5addc1,6},{0xf2d036,4},{0xf70ff2,9}, +{0xf4ea19,9},{0xfc02f9,6},{0x839fd8,3},{0xdd4dce,5}, +{0xec3dce,6},{0xcea783,6},{0xcbe745,5},{0xc1b483,7}, +{0x799fe0,5},{0xd340e7,7},{0x29ddf2,3},{0x73daac,6}, +{0xea33da,5},{0xe224f2,3},{0xd34fd5,5},{0xe245d3,8}, +{0xfc1edd,10},{0x3bf2cb,4},{0xdd9f7e,26},{0xe02eec,5}, +{0xf47195,4},{0xa461f4,5},{0x3ddae0,3},{0xaf5fea,6}, +{0xbccb73,6},{0xea26ea,8},{0xd82bf7,6},{0xac6ce0,7}, +{0xe524ef,4},{0xb6da69,6},{0xf224e2,5},{0xb95ce5,7}, +{0x73a4e0,7},{0xa4e076,7},{0xfc02f9,8},{0xec1eec,4}, +{0xf7da29,6},{0xc369ce,6},{0xd5c65c,9},{0xe51ef4,4}, +{0xf2a264,4},{0x809ddd,5},{0xd045e2,7},{0xaac888,6}, +{0xb44af9,3},{0xd84ad8,7},{0xf4ef14,5},{0x3bf7c8,5}, +{0xe730e0,4},{0x97b6ac,7},{0x8bda95,5},{0x88ec83,8}, +{0xece529,8},{0x9a80dd,10},{0xf412f4,7},{0x36efd5,6}, +{0xf95ca4,9},{0xd838e7,6},{0x9a69f7,7},{0xf730d3,4}, +{0xd526fc,5},{0x9f76e2,6},{0xe28395,8},{0xecaa61,6}, +{0x4ff4b4,7},{0xd079af,7},{0xa469ea,10},{0xfc21da,7}, +{0xb471d5,6},{0x7b88f7,4},{0xfc6797,4},{0x9daab4,5}, +{0x29f2dd,7},{0x8388ec,7},{0x4df9b1,4},{0xeaf21e,5}, +{0xf4c340,10},{0xf212f7,3},{0xf407fc,5},{0x4fb9ef,9}, +{0xd3b471,6},{0xef4dbe,12},{0x4af4bc,7},{0xe224f2,6}, +{0x36d0f2,8},{0xf707fc,4},{0xfc8d71,9},{0x95bea4,6}, +{0x90ef7b,4},{0x5adac6,5},{0x97b9a7,4},{0xc3c671,6}, +{0xfc12ec,5},{0xea1ef2,5},{0x8dd09d,4},{0xd82bf7,7}, +{0xb18dbc,7},{0xbc64da,6},{0xf28d7b,4},{0xef19ef,5}, +{0xc1e555,6},{0xfc3bc3,6},{0x9f88d3,5},{0xc3ec48,9}, +{0xc8979a,5},{0x5cc6d8,4},{0xf78080,6},{0xb17bcb,8}, +{0xea12fc,6},{0xc195a2,7},{0xef33d8,3},{0xa783ce,3}, +{0xf40af9,5},{0xa288d0,6},{0xf248be,4},{0x14e7fc,5}, +{0x83d3a4,8},{0xb4cb79,6},{0xbc7ebe,3},{0xfc8873,6}, +{0xe038e0,6},{0xc3ef48,6},{0xa25afc,10},{0xc1a792,6}, +{0x8d90dd,9},{0xc1be7b,5},{0x8bec80,5},{0xa4ef64,5}, +{0x38f7c8,11},{0xaf6eda,4},{0xd073b4,5},{0x79ceb4,7}, +{0xd5e540,6},{0xfc0fec,5},{0xf917ea,7},{0x64c8cb,4}, +{0x69e7a7,6},{0xa77ed3,5},{0xe52be7,6},{0x5aaaf4,7}, +{0xcb85a7,5},{0x8392e2,4},{0x5cb4ea,6},{0xe729e7,6}, +{0xc873bc,5},{0xeabc52,7},{0xf438ce,7},{0xea48c8,5}, +{0xef17f4,4},{0xfc00fc,6},{0xf97b85,14},{0x67ace7,3}, +{0xf452b1,7},{0xe2e038,4},{0xa4a7af,5},{0xddb469,3}, +{0xf21cec,7},{0x7bbec1,3},{0xda38e5,8},{0xc6a292,9}, +{0x6ecebc,9},{0x8dda90,4},{0xf921e0,8},{0xc88da4,5}, +{0x92aabc,4},{0x9a9dc3,5},{0x8dd895,4},{0x64d3c3,9}, +{0xa2f95f,7},{0xdd36e5,8},{0x83e790,11},{0xef26e2,5}, +{0xef55b4,9},{0x5fc3d8,6},{0xfc57a4,7},{0x9785dd,5}, +{0x809ddd,4},{0xc66cc8,8},{0xf236d3,5},{0xd338ef,6}, +{0xd8839f,4},{0xef30d8,3},{0x9a9ac6,5},{0xfc05f9,11}, +{0x958bda,11},{0xf902fc,8},{0xbe42f9,4},{0xbce557,6}, +{0xef4fb9,6},{0xf9af52,5},{0x97d38d,5},{0xf902fc,7}, +{0xf4a261,4},{0xd88897,7},{0x92e77e,7},{0x6c9df2,6}, +{0xce85a4,4},{0x9ae07e,8},{0xb1f255,8},{0xc6929f,6}, +{0xf2af5a,10},{0xe2977e,5},{0xe5cb4a,5},{0xfc14e7,3}, +{0xc14aef,3},{0xaff257,3},{0xe21cf9,11},{0xd05ccb,5}, +{0xf2ec1c,8},{0xb4b98b,9},{0xc183b6,3},{0xb455f2,7}, +{0x83aace,4},{0xe51cf9,4},{0xdd4fce,4},{0xb47ec8,3}, +{0x92da8b,4},{0xecb952,4},{0xf70af7,6},{0x7bbcc1,6}, +{0xf40cf9,5},{0xe2ce48,5},{0xf7b14f,5},{0xdd40da,4}, +{0x4fb9f2,7},{0x6eb1da,5},{0x9d90ce,6},{0xcb55d8,5}, +{0xd02efc,8},{0xd36eb9,6},{0xfc0cef,5},{0xe071aa,9}, +{0xe7ac67,3},{0xf4f40f,6},{0xe267af,4},{0xc3da5c,5}, +{0xb945fc,4},{0xeada33,6},{0x7197f2,7},{0xfc00fc,8}, +{0xd09d8d,5},{0x6e9fea,8},{0xd3a77e,4},{0xaa5ff2,6}, +{0xe269ac,5},{0xf426e0,6},{0xfc00fc,5},{0xec6ca2,10}, +{0xc638fc,7},{0xe54fc6,5},{0x5ac6da,3},{0xce67c6,6}, +{0xbe42f9,5},{0xce38f2,5},{0xbe5ae2,3},{0xd3ec38,8}, +{0x8b76f7,8},{0xb180c8,4},{0xd538ec,4},{0xddef2b,9}, +{0xf9c838,5},{0xf457ac,4},{0xf95aa7,7},{0xaf69e0,9}, +{0x67efa2,5},{0xa280d8,4},{0xa7d57b,7},{0xcbaf7e,4}, +{0x837bf9,4},{0xddc15c,6},{0xe221f4,3},{0xc6b480,5}, +{0xbc90af,10},{0x4dd3da,4},{0xbcb983,4},{0xe77997,7}, +{0xe05fb9,9},{0xc1b980,8},{0xdd55c6,7},{0xaf97b1,9}, +{0xec838b,4},{0xc39d9a,9},{0x6c97f7,5},{0xf7b44f,3}, +{0xb69fa4,7},{0x90ea7e,7},{0xe067b1,5},{0xd5cb5a,4}, +{0xc19a9f,8},{0xac67e7,8},{0xcee745,4},{0xf436d0,4}, +{0x73b1d5,7},{0xd3d84f,5},{0xdd42d8,5},{0xea907e,6}, +{0xc83bf4,7},{0xd84fd3,6},{0xe28890,3},{0x38e2e0,8}, +{0xec67a7,6},{0xcbc16e,8},{0x4ab1fc,7},{0x92d590,3}, +{0xaad876,4},{0xb683c1,4},{0xaa55f9,5},{0xea24ea,6}, +{0xf90fef,6},{0xf738c8,3},{0xcb5ad5,7},{0xec21ec,5}, +{0xce61c8,3},{0xa76ce7,3},{0xf41ee5,7},{0xcebe6c,3}, +{0x57dac6,9},{0xf46e97,3},{0x8be08d,7},{0xc148ef,9}, +{0xf926da,8},{0xe029ef,6},{0xfc00fc,5},{0x3dcbf2,4}, +{0xef0ffc,5},{0x95b6ac,9},{0x7be59a,5},{0xda2ef2,8}, +{0xda30ef,5},{0xfc24d8,3},{0x73d3b4,3},{0xddf229,4}, +{0x8883ef,5},{0x5aefaf,6},{0x9797cb,6},{0xcbc16c,5}, +{0xef19f2,5},{0xd3bc6c,3},{0xda5cc3,8},{0x52f9ac,7}, +{0xa7c888,4},{0x69d8b6,7},{0xbc45f7,7},{0xfc02fc,4}, +{0xb4b195,6},{0xe58d85,4},{0x9776ea,6},{0xf255b1,6}, +{0x76dda7,3},{0xe55ab9,8},{0xe230e7,5},{0x3bd0ec,5}, +{0xe219fc,6},{0xcbac83,5},{0xe548ce,7},{0xdd5cbe,3}, +{0xf412f4,5},{0xf9738d,9},{0xdd40da,4},{0x90c6a2,10}, +{0xe038e2,4},{0x6eddaf,8},{0xf23dcb,12},{0xec4fbc,6}, +{0xc8d35c,6},{0xf238d0,6},{0x90cb9f,6},{0xa46ee5,5}, +{0xaf8bbe,5},{0xc1a495,5},{0xc679b9,4},{0xec29e2,6}, +{0xf9649d,6},{0xf924da,6},{0xe224f2,5},{0x8d71f9,7}, +{0xf2cb3d,5},{0xb6cb79,4},{0xa4dd76,6},{0xe52ee5,3}, +{0xaa8bc3,3},{0x838dea,7},{0xf9ea17,5},{0x88c8aa,6}, +{0x73e0a7,5},{0xd09595,6},{0xf7d82b,10},{0xec7397,4}, +{0xfc02fc,7},{0xf72ed3,5},{0xd03dec,4},{0x80cbaf,5}, +{0xf921dd,7},{0x9fcb90,8},{0xbe95a7,4},{0x69eaa4,8}, +{0xf20ff7,5},{0x69e7a7,9},{0xf924da,3},{0xecdd30,6}, +{0xc1d861,4},{0xb967d8,5},{0xb157ef,6},{0xb9bc85,5}, +{0xb192b4,8},{0xda38e5,3},{0xea1eef,6},{0x12f7ef,4}, +{0x6e90f9,6},{0xd573b1,6},{0xdd24f7,5},{0xd5d055,7}, +{0xc86ec1,4},{0xf21ee7,7},{0xa261f4,6},{0xe555c1,4}, +{0xf78b79,6},{0xf78080,5},{0x80b4c3,7},{0xf414ef,4}, +{0xf70ff2,6},{0xea52bc,6},{0xd04ddd,7},{0xf90af4,5}, +{0xe78b88,4},{0xf29f67,6},{0x79b6c8,4},{0xa48dc8,5}, +{0x5fa4f4,4},{0xea14fc,3},{0xf23bcb,7},{0xf738cb,5}, +{0x4fb1f9,3},{0x5ae2bc,7},{0xfcac4f,5},{0xa283d3,7}, +{0xef24e7,7},{0xe5e52e,4},{0x929ace,4},{0xcb36f9,8}, +{0xea21ef,5},{0xf2d038,6},{0x48d8d8,4},{0xec40ce,6}, +{0xf90af7,5},{0xf921dd,7},{0xd8e042,5},{0x21ddf9,4}, +{0x5fb9e2,8},{0xf72ed3,4},{0xfc2ed0,5},{0xf712ef,6}, +{0x57d8cb,5},{0x19fce2,9},{0xe7f71c,9},{0x7be59a,4}, +{0x6cfc90,5},{0xec3bd0,5},{0xea26e7,8},{0x36d5ec,5}, +{0xac76d8,3},{0xa4a4b1,3},{0xef12f7,4},{0x6eb9d3,6}, +{0xe714fc,5},{0xe224f2,5},{0x3bead5,4},{0x8de783,9}, +{0x40d5e2,8},{0x9764fc,7},{0xf705fc,3},{0x8d88e2,8}, +{0xe269ac,6},{0xda33ec,7},{0xd03bec,3},{0xbe6cd0,6}, +{0x8bf479,5},{0xf912ec,8},{0xe5b461,7},{0xaf5aef,6}, +{0xc34fe5,7},{0xd038ef,6},{0x38f9c8,7},{0xf43dc6,3}, +{0xceb973,5},{0xe526ec,4},{0xf902fc,7},{0xbc48f7,4}, +{0,0} +}; + +static double const mosaic_curve_points[] = { +20.3, 216.5, 27.0, 209.8, 17.4, 200.0, 14.5, 183.5, 14.2, 181.8, +13.5, 181.6, 13.9, 180.0, 28.3, 126.1, 29.2, 126.3, 44.2, 72.5, +44.4, 71.7, 44.2, 70.8, 44.2, 70.8, 44.2, 70.8, 44.4, 71.7, +44.2, 72.5, 36.1, 121.4, 36.0, 121.3, 27.9, 170.2, 24.1, 193.3, +33.8, 203.1, 20.3, 216.5, 82.6, 583.9, 82.5, 583.6, 84.3, 583.3, +84.2, 583.1, 88.1, 600.0, 87.2, 600.2, 90.2, 617.3, 92.4, 630.1, +92.4, 630.1, 94.7, 642.9, 96.8, 655.3, 96.8, 655.3, 99.0, 667.8, +100.0, 673.7, 100.1, 673.7, 101.1, 679.7, 107.4, 716.3, 107.3, 716.3, +113.7, 752.9, 115.3, 762.1, 117.1, 771.4, 117.1, 771.4, 117.1, 771.4, +115.3, 762.1, 113.7, 752.9, 108.9, 726.8, 108.9, 726.8, 104.1, 700.7, +97.1, 662.7, 97.1, 662.7, 90.1, 624.8, 86.3, 604.3, 85.5, 604.5, +82.6, 583.9, 37.6, 265.6, 38.8, 286.4, 41.0, 287.6, 36.1, 307.5, +38.5, 298.0, 34.3, 297.0, 32.5, 286.5, 26.4, 251.5, 21.6, 251.7, +20.3, 216.5, 33.8, 203.1, 24.1, 193.3, 27.9, 170.2, 43.4, 214.1, +34.7, 217.8, 37.6, 265.6, 27.9, 170.2, 36.0, 121.3, 36.1, 121.4, +44.2, 72.5, 43.5, 76.1, 44.0, 76.2, 43.9, 79.8, 43.7, 85.4, +43.7, 85.4, 43.5, 91.0, 41.9, 137.6, 41.9, 137.6, 40.3, 184.2, +39.2, 217.8, 39.2, 217.8, 38.1, 251.5, 37.8, 258.5, 36.7, 258.7, +37.6, 265.6, 34.7, 217.8, 43.4, 214.1, 27.9, 170.2, -16.2, 299.0, +-16.2, 299.0, -15.8, 297.4, -15.4, 295.8, -10.3, 274.5, -10.2, 274.5, +-5.1, 253.1, -1.7, 238.6, -1.9, 238.6, 1.6, 224.2, 2.5, 220.5, +2.8, 220.6, 3.6, 216.9, -0.6, 235.0, -0.7, 235.0, -5.1, 253.1, +-10.2, 274.5, -10.3, 274.5, -15.4, 295.8, -15.8, 297.4, -16.2, 299.0, +-16.2, 299.0, 242.4, -11.8, 258.9, -17.0, 261.0, -11.0, 277.2, -16.9, +183.6, 17.7, 182.4, 14.3, 87.6, 45.5, 87.3, 45.5, 87.3, 45.5, +87.1, 45.6, 71.7, 49.5, 71.2, 48.0, 56.4, 53.5, 148.8, 19.4, +148.5, 18.2, 242.4, -11.8, 56.4, 53.5, 52.5, 54.8, 51.1, 57.0, +48.5, 55.6, 47.9, 55.2, 48.4, 50.6, 50.0, 50.0, 134.7, 18.5, +135.0, 19.0, 221.1, -8.6, 231.2, -11.9, 232.5, -8.1, 242.4, -11.8, +148.5, 18.2, 148.8, 19.4, 56.4, 53.5, 194.7, 17.8, 158.4, 27.2, +158.4, 27.2, 122.0, 36.6, 117.5, 37.7, 117.5, 37.7, 112.9, 38.9, +100.2, 42.2, 100.2, 42.2, 87.6, 45.5, 87.3, 45.5, 87.3, 45.5, +87.1, 45.6, 182.1, 14.3, 181.1, 10.8, 277.2, -16.9, 303.4, -24.5, +307.1, -14.6, 331.7, -25.0, 266.4, 2.6, 263.7, -3.7, 195.7, 17.5, +195.2, 17.7, 195.2, 17.7, 194.7, 17.8, 331.7, -25.0, 364.2, -33.4, +365.0, -31.6, 398.6, -34.9, 387.8, -33.8, 388.0, -32.1, 377.4, -29.4, +370.0, -27.5, 370.0, -27.5, 362.6, -25.6, 362.3, -25.5, 362.3, -25.5, +362.0, -25.4, 355.9, -23.9, 355.9, -23.9, 349.8, -22.3, 341.8, -20.2, +341.8, -20.2, 333.7, -18.1, 318.3, -14.2, 318.3, -14.2, 303.0, -10.2, +300.6, -9.6, 300.6, -9.6, 298.2, -9.0, 281.5, -4.7, 281.5, -4.7, +264.9, -0.3, 254.1, 2.4, 254.1, 2.4, 243.2, 5.2, 227.9, 9.2, +227.9, 9.2, 212.6, 13.1, 204.2, 15.3, 204.2, 15.3, 195.7, 17.5, +195.2, 17.7, 195.2, 17.7, 194.7, 17.8, 263.2, -3.6, 262.3, -7.1, +331.7, -25.0, -5.1, 253.1, -0.7, 235.0, -0.6, 235.0, 3.6, 216.9, +7.2, 203.0, 5.7, 202.2, 11.4, 189.1, 6.4, 200.6, 8.2, 201.4, +5.0, 213.7, -0.0, 233.4, 2.9, 234.7, -5.1, 253.1, 0.7, 536.2, +13.6, 573.8, 15.5, 574.7, 18.7, 614.1, 18.8, 616.3, 7.9, 620.2, +7.3, 619.4, -4.6, 602.1, -1.2, 599.1, -6.2, 577.9, -16.0, 536.4, +-28.8, 533.6, -22.2, 494.1, -25.4, 512.7, -6.9, 513.8, 0.7, 536.2, +-22.2, 494.1, -26.0, 485.6, -28.6, 477.0, -25.8, 475.4, -22.7, 473.6, +-14.7, 479.5, -10.5, 487.2, -3.6, 500.3, -7.1, 502.1, -3.7, 517.0, +-2.5, 522.1, -2.5, 522.1, -1.4, 527.1, -0.3, 531.7, -1.6, 532.5, +0.7, 536.2, -6.9, 513.8, -25.4, 512.7, -22.2, 494.1, 19.0, 510.1, +21.7, 515.4, 24.2, 514.1, 29.4, 518.2, 30.9, 519.3, 30.9, 519.3, +32.3, 520.4, 56.0, 538.7, 58.2, 536.4, 79.7, 557.1, 82.9, 560.1, +80.6, 562.5, 81.6, 567.8, 82.9, 575.5, 83.7, 575.4, 84.2, 583.1, +84.3, 583.3, 82.5, 583.6, 82.6, 583.9, 75.0, 587.4, 75.2, 587.9, +67.4, 591.0, 67.4, 591.1, 67.2, 590.6, 66.9, 590.2, 42.9, 550.1, +40.5, 551.4, 19.0, 510.1, 121.8, 800.9, 121.7, 801.1, 122.3, 801.2, +122.4, 801.6, 123.7, 808.3, 126.5, 809.3, 124.7, 815.1, 125.1, 813.8, +120.1, 813.3, 119.5, 810.6, 118.6, 806.2, 120.3, 805.6, 121.8, 800.9, +0.7, 495.9, 3.7, 500.5, 5.2, 499.5, 9.8, 503.0, 14.4, 506.5, +15.9, 505.5, 19.0, 510.1, 40.5, 551.4, 42.9, 550.1, 66.9, 590.2, +63.6, 584.5, 63.1, 584.8, 59.4, 579.4, 30.0, 537.7, 28.5, 538.7, +0.7, 495.9, 113.7, 752.9, 115.3, 762.1, 117.1, 771.4, 117.1, 771.4, +117.4, 773.4, 117.4, 773.4, 117.8, 775.3, 120.1, 788.5, 120.3, 788.4, +122.4, 801.6, 122.3, 801.2, 121.7, 801.1, 121.8, 800.9, 121.4, 800.4, +121.4, 800.4, 121.0, 799.9, 120.6, 799.4, 120.6, 799.4, 120.3, 798.9, +95.0, 767.1, 74.8, 770.0, 69.8, 735.3, 71.5, 747.0, 95.6, 739.1, +113.7, 752.9, 69.8, 735.3, 69.0, 734.9, 68.4, 733.7, 68.5, 733.6, +75.3, 725.8, 76.1, 726.5, 83.8, 719.4, 89.1, 714.5, 89.1, 714.5, +94.4, 709.6, 99.2, 705.1, 104.9, 702.6, 104.1, 700.7, 108.9, 726.8, +108.9, 726.8, 113.7, 752.9, 95.6, 739.1, 71.5, 747.0, 69.8, 735.3, +19.0, 613.9, 22.4, 604.2, 32.4, 607.6, 45.7, 601.3, 56.0, 596.4, +56.0, 596.4, 66.3, 591.6, 66.9, 591.3, 66.9, 591.3, 67.4, 591.0, +75.2, 587.9, 75.0, 587.4, 82.6, 583.9, 85.5, 604.5, 86.3, 604.3, +90.1, 624.8, 90.1, 624.5, 88.9, 624.6, 87.8, 624.5, 64.0, 620.8, +64.0, 620.8, 40.2, 617.2, 29.6, 615.5, 19.7, 612.1, 19.0, 613.9, +121.0, 799.9, 121.4, 800.4, 121.4, 800.4, 121.8, 800.9, 120.3, 805.6, +118.6, 806.2, 119.5, 810.6, 108.1, 806.7, 98.9, 800.6, 99.9, 793.4, +99.6, 795.2, 110.5, 796.3, 121.0, 799.9, 191.6, 801.6, 213.6, 817.8, +197.0, 840.4, 202.3, 879.2, 202.4, 880.2, 203.0, 880.7, 202.6, 881.2, +202.1, 881.7, 201.1, 881.7, 200.4, 881.1, 187.5, 870.7, 176.8, 871.5, +175.5, 859.3, 172.4, 831.7, 200.2, 807.9, 191.6, 801.6, 32.3, 520.4, +30.9, 519.3, 30.9, 519.3, 29.4, 518.2, 27.6, 505.3, 28.9, 505.1, +28.3, 492.1, 26.0, 440.3, 25.5, 440.3, 23.7, 388.5, 24.2, 405.2, +24.7, 405.2, 25.8, 421.8, 27.0, 439.3, 27.0, 439.3, 28.1, 456.8, +29.1, 470.9, 29.1, 470.9, 30.0, 485.1, 31.1, 502.7, 32.6, 502.7, +32.3, 520.4, -3.7, 517.0, -7.1, 502.1, -3.6, 500.3, -10.5, 487.2, +-10.8, 490.3, -6.1, 490.7, -1.6, 494.1, -0.5, 495.0, -0.1, 494.8, +0.7, 495.9, 28.5, 538.7, 30.0, 537.7, 59.4, 579.4, 64.3, 555.8, +22.9, 552.0, -3.7, 517.0, 83.8, 719.4, 76.1, 726.5, 75.3, 725.8, +68.5, 733.6, 49.9, 724.3, 45.1, 717.9, 40.0, 697.6, 42.0, 705.5, +51.1, 703.2, 62.2, 708.7, 69.0, 712.1, 69.0, 712.1, 75.8, 715.5, +79.8, 717.4, 83.9, 719.1, 83.8, 719.4, 69.7, 767.2, 66.2, 756.5, +57.4, 760.4, 50.0, 750.0, 44.4, 742.1, 50.3, 736.4, 43.7, 730.7, +60.1, 745.0, 63.1, 746.8, 69.7, 767.2, 943.6, 608.8, 941.3, 609.3, +947.5, 623.9, 942.6, 627.8, 892.0, 668.3, 889.0, 665.2, 832.4, 697.7, +848.6, 688.4, 847.2, 685.9, 861.9, 674.1, 867.3, 669.8, 867.3, 669.8, +872.6, 665.6, 875.3, 663.4, 875.3, 663.4, 878.0, 661.2, 891.5, 650.5, +891.5, 650.5, 904.9, 639.8, 906.2, 638.7, 906.2, 638.7, 907.5, 637.7, +909.8, 635.8, 909.8, 635.8, 912.2, 633.9, 927.9, 621.4, 926.1, 612.3, +943.6, 608.8, 743.8, 661.6, 749.6, 670.9, 741.5, 681.2, 747.9, 684.8, +733.2, 676.6, 737.6, 668.6, 727.2, 652.4, 722.1, 644.3, 722.1, 644.3, +716.9, 636.3, 711.2, 627.4, 711.2, 627.4, 705.5, 618.5, 701.1, 611.6, +695.6, 610.5, 696.7, 604.7, 695.8, 609.3, 701.3, 610.3, 706.0, 615.9, +724.9, 638.7, 728.6, 636.5, 743.8, 661.6, 947.6, 328.1, 940.6, 361.9, +953.7, 364.0, 954.4, 400.0, 955.1, 438.8, 952.6, 438.9, 950.4, 477.7, +950.5, 475.0, 950.3, 475.0, 950.3, 472.2, 949.8, 448.4, 949.8, 448.4, +949.4, 424.6, 948.5, 376.3, 938.1, 374.2, 947.6, 328.1, 846.3, 117.0, +890.0, 147.0, 890.5, 146.4, 933.3, 177.7, 934.1, 178.3, 932.8, 180.3, +933.6, 180.8, 919.3, 171.9, 920.0, 170.9, 906.3, 160.9, 890.8, 149.6, +890.8, 149.6, 875.3, 138.2, 872.0, 135.8, 872.0, 135.8, 868.7, 133.4, +857.5, 125.2, 857.7, 124.9, 846.3, 117.0, 408.1, 154.0, 408.9, 154.9, +409.6, 155.6, 409.4, 156.0, 393.6, 178.5, 392.8, 177.9, 376.1, 199.9, +371.9, 205.6, 372.2, 205.9, 367.6, 211.2, 370.8, 207.5, 370.5, 207.2, +373.3, 203.2, 390.6, 178.7, 390.6, 178.7, 407.9, 154.3, 408.0, 154.2, +408.2, 154.1, 408.1, 154.0, 142.2, 652.8, 141.2, 609.9, 142.1, 609.9, +142.0, 567.0, 142.0, 543.5, 142.0, 543.5, 141.9, 520.0, 141.9, 517.7, +141.9, 517.7, 141.9, 515.4, 141.9, 494.5, 141.9, 494.5, 141.9, 473.6, +141.9, 472.3, 141.9, 472.3, 141.9, 471.0, 141.8, 468.7, 141.8, 468.7, +141.8, 466.3, 141.8, 452.9, 141.5, 452.9, 141.8, 439.5, 141.8, 441.3, +142.0, 441.3, 142.3, 443.2, 144.2, 457.2, 144.2, 457.2, 146.2, 471.3, +146.6, 474.8, 146.6, 474.8, 147.1, 478.3, 147.4, 480.0, 147.4, 480.0, +147.6, 481.7, 148.8, 490.4, 148.8, 490.4, 150.0, 499.1, 150.2, 500.3, +150.2, 500.3, 150.3, 501.5, 153.2, 522.1, 153.2, 522.1, 156.0, 542.8, +156.8, 548.2, 156.8, 548.2, 157.5, 553.7, 157.8, 556.1, 158.5, 556.2, +158.2, 558.4, 155.4, 578.7, 154.7, 578.6, 151.3, 598.8, 147.6, 620.7, +147.6, 620.7, 143.9, 642.6, 143.9, 642.7, 143.9, 642.7, 143.9, 642.7, +143.1, 647.7, 142.1, 647.8, 142.2, 652.8, -1.6, 494.1, -6.1, 490.7, +-10.8, 490.3, -10.5, 487.2, -14.7, 479.5, -22.7, 473.6, -25.8, 475.4, +-37.3, 443.0, -39.2, 441.2, -38.9, 407.2, -39.0, 422.7, -32.2, 422.8, +-25.5, 438.4, -13.6, 466.3, -10.5, 465.3, -1.6, 494.1, 15.1, 196.4, +24.9, 282.2, 18.9, 282.9, 22.8, 369.5, 22.8, 369.5, 22.8, 369.6, +22.8, 369.6, 19.8, 367.5, 17.9, 368.2, 16.8, 365.3, 14.8, 360.0, +16.8, 359.2, 16.7, 353.2, 16.6, 347.1, 16.6, 347.1, 16.6, 341.0, +16.4, 326.7, 16.4, 326.7, 16.3, 312.3, 15.7, 254.3, 21.6, 253.7, +15.1, 196.4, -1.4, 527.1, -2.5, 522.1, -2.5, 522.1, -3.7, 517.0, +22.9, 552.0, 64.3, 555.8, 59.4, 579.4, 63.1, 584.8, 63.6, 584.5, +66.9, 590.2, 67.2, 590.6, 67.4, 591.1, 67.4, 591.0, 66.9, 591.3, +66.9, 591.3, 66.3, 591.6, 44.0, 571.1, 44.3, 570.7, 22.4, 549.7, +10.5, 538.4, 8.8, 539.8, -1.4, 527.1, 87.8, 624.5, 88.9, 624.6, +90.1, 624.5, 90.1, 624.8, 97.1, 662.7, 97.1, 662.7, 104.1, 700.7, +104.9, 702.6, 99.2, 705.1, 94.4, 709.6, 91.2, 708.1, 93.8, 702.6, +93.3, 695.5, 92.9, 690.2, 92.9, 690.2, 92.5, 684.9, 91.2, 668.6, +91.2, 668.6, 89.9, 652.3, 88.9, 638.4, 87.7, 638.4, 87.8, 624.5, +120.3, 798.9, 120.6, 799.4, 120.6, 799.4, 121.0, 799.9, 110.5, 796.3, +99.6, 795.2, 99.9, 793.4, 83.2, 782.8, 82.9, 782.0, 69.7, 767.2, +63.1, 746.8, 60.1, 745.0, 43.7, 730.7, 42.4, 728.8, 43.7, 727.6, +42.2, 726.3, 82.0, 761.7, 81.3, 762.5, 120.3, 798.9, 42.2, 726.3, +28.8, 709.3, 29.6, 704.7, 27.9, 682.3, 28.5, 690.4, 33.9, 690.0, +40.0, 697.6, 45.1, 717.9, 49.9, 724.3, 68.5, 733.6, 68.4, 733.7, +69.0, 734.9, 69.8, 735.3, 74.8, 770.0, 95.0, 767.1, 120.3, 798.9, +81.3, 762.5, 82.0, 761.7, 42.2, 726.3, 703.4, 562.7, 701.7, 552.1, +711.8, 549.5, 722.0, 537.9, 721.3, 538.6, 722.2, 539.4, 722.5, 540.9, +723.8, 548.1, 723.8, 548.1, 725.0, 555.3, 730.5, 586.1, 730.5, 586.1, +735.9, 616.8, 737.4, 625.4, 738.6, 625.3, 739.0, 634.0, 738.8, 631.5, +737.7, 631.5, 736.5, 629.0, 719.9, 595.9, 708.9, 597.6, 703.4, 562.7, +539.8, 359.6, 539.7, 358.7, 539.2, 358.7, 538.6, 357.9, 519.1, 327.4, +519.1, 327.4, 499.6, 296.9, 492.6, 286.0, 492.4, 286.2, 485.7, 275.1, +486.0, 275.6, 486.2, 275.5, 486.8, 275.9, 488.5, 277.1, 488.5, 277.1, +490.3, 278.3, 512.4, 293.3, 515.9, 289.9, 534.6, 308.4, 538.8, 312.6, +535.4, 316.0, 536.1, 323.7, 536.4, 326.7, 536.4, 326.7, 536.7, 329.8, +538.3, 344.7, 538.8, 344.7, 539.8, 359.6, 672.2, 402.1, 674.0, 400.5, +680.5, 407.7, 688.8, 413.4, 692.6, 416.0, 692.6, 416.0, 696.4, 418.5, +698.9, 420.3, 700.7, 419.7, 701.5, 422.0, 705.6, 434.7, 703.8, 435.3, +706.2, 448.6, 706.9, 452.6, 706.9, 452.6, 707.6, 456.6, 710.3, 471.8, +713.6, 472.0, 713.0, 487.0, 713.1, 483.1, 709.8, 483.0, 706.7, 478.9, +704.9, 476.6, 704.9, 476.6, 703.1, 474.3, 701.9, 472.8, 701.9, 472.8, +700.8, 471.3, 696.3, 465.5, 696.3, 465.5, 691.8, 459.8, 689.2, 456.4, +689.2, 456.4, 686.6, 453.1, 678.3, 442.4, 678.3, 442.4, 669.9, 431.6, +669.6, 431.2, 669.3, 431.2, 669.3, 430.8, 670.4, 416.4, 664.2, 409.2, +672.2, 402.1, 669.3, 430.8, 662.6, 432.2, 659.8, 418.7, 650.4, 406.5, +639.5, 392.5, 639.5, 392.5, 628.6, 378.5, 623.6, 372.1, 625.2, 368.3, +618.6, 365.6, 636.3, 372.9, 634.8, 376.6, 650.9, 387.6, 657.0, 391.8, +657.0, 391.8, 663.1, 395.9, 666.5, 398.2, 666.5, 398.2, 669.9, 400.6, +670.3, 400.8, 670.3, 400.8, 670.6, 401.0, 671.4, 401.6, 672.2, 401.6, +672.2, 402.1, 664.2, 409.2, 670.4, 416.4, 669.3, 430.8, 150.3, 501.5, +150.2, 500.3, 150.2, 500.3, 150.0, 499.1, 164.5, 478.5, 165.2, 479.0, +180.4, 458.9, 203.0, 428.9, 200.5, 426.6, 225.7, 398.9, 203.9, 422.9, +206.4, 425.2, 187.1, 451.5, 168.7, 476.5, 169.4, 477.1, 150.3, 501.5, +198.1, 70.3, 213.7, 72.4, 227.1, 73.6, 228.3, 81.5, 229.1, 86.3, +215.3, 88.6, 202.2, 95.7, 194.5, 100.0, 194.5, 100.0, 186.7, 104.2, +177.5, 109.3, 170.2, 107.4, 168.4, 114.3, 173.7, 93.6, 181.1, 95.5, +193.8, 76.7, 195.9, 73.5, 196.4, 70.1, 198.1, 70.3, 140.7, 133.4, +137.8, 135.0, 133.7, 132.2, 133.2, 133.5, 134.7, 129.7, 137.9, 130.9, +142.6, 128.4, 147.4, 125.8, 147.4, 125.8, 152.1, 123.1, 160.3, 118.7, +160.3, 118.7, 168.4, 114.3, 170.2, 107.4, 177.5, 109.3, 186.7, 104.2, +164.3, 119.7, 164.5, 120.3, 140.7, 133.4, 134.9, 228.4, 136.6, 240.3, +129.2, 247.8, 116.4, 255.3, 118.9, 253.8, 111.2, 244.9, 114.4, 240.4, +120.5, 231.5, 135.5, 232.9, 134.9, 228.4, 151.3, 598.8, 154.7, 578.6, +155.4, 578.7, 158.2, 558.4, 157.7, 560.5, 158.5, 560.6, 158.8, 562.8, +161.6, 583.3, 161.6, 583.3, 164.4, 603.8, 165.1, 609.2, 165.1, 609.2, +165.9, 614.5, 169.9, 643.5, 169.9, 643.5, 173.9, 672.6, 174.5, 677.0, +173.8, 677.2, 175.1, 681.5, 162.5, 640.3, 157.1, 641.0, 151.3, 598.8, +141.4, 568.5, 141.4, 567.7, 142.1, 567.7, 142.0, 567.0, 142.1, 609.9, +141.2, 609.9, 142.2, 652.8, 142.4, 726.7, 142.4, 726.7, 142.5, 800.7, +142.5, 811.8, 142.5, 811.8, 142.6, 822.9, 142.6, 826.8, 142.7, 830.7, +142.6, 830.7, 138.4, 830.8, 134.1, 827.1, 133.9, 823.2, 131.5, 765.1, +135.6, 765.0, 137.3, 706.8, 137.6, 699.6, 137.6, 699.6, 137.8, 692.5, +139.6, 630.5, 139.3, 630.5, 141.4, 568.5, 94.7, 642.9, 92.4, 630.1, +92.4, 630.1, 90.2, 617.3, 90.6, 608.0, 93.4, 608.1, 96.7, 598.9, +98.3, 594.2, 99.8, 594.3, 100.0, 589.5, 98.9, 614.8, 97.5, 614.8, +95.0, 640.0, 94.8, 641.5, 94.4, 641.6, 94.7, 642.9, 118.9, 272.9, +120.5, 292.1, 121.5, 292.0, 124.1, 311.0, 126.7, 329.9, 126.7, 329.9, +129.3, 348.8, 135.5, 394.1, 136.9, 394.0, 141.8, 439.5, 141.5, 452.9, +141.8, 452.9, 141.8, 466.3, 142.0, 464.7, 139.8, 464.7, 139.2, 462.7, +138.1, 459.0, 138.8, 458.8, 138.4, 454.9, 135.2, 425.6, 135.2, 425.6, +132.1, 396.2, 130.6, 382.7, 130.6, 382.7, 129.2, 369.3, 124.0, 321.1, +123.1, 321.2, 118.9, 272.9, 44.2, 353.6, 40.0, 349.1, 42.9, 346.4, +41.7, 339.3, 40.6, 332.9, 43.2, 329.6, 39.5, 326.5, 51.9, 336.6, +49.3, 339.9, 59.1, 353.3, 60.0, 354.6, 60.0, 354.6, 60.9, 355.8, +66.5, 363.4, 66.5, 363.4, 72.1, 371.0, 73.1, 372.4, 73.1, 372.4, +74.1, 373.8, 74.2, 373.9, 74.1, 374.0, 74.3, 374.1, 59.2, 363.9, +56.3, 366.5, 44.2, 353.6, -15.4, 295.8, -10.3, 274.5, -10.2, 274.5, +-5.1, 253.1, 2.9, 234.7, -0.0, 233.4, 5.0, 213.7, 2.7, 222.5, +2.8, 222.5, 0.6, 231.3, -3.2, 247.1, -3.2, 247.2, -7.1, 263.0, +-11.2, 279.4, -12.0, 279.2, -15.4, 295.8, 22.8, 369.5, 18.9, 282.9, +24.9, 282.2, 15.1, 196.4, 14.8, 189.9, 16.1, 189.6, 14.5, 183.5, +17.4, 200.0, 27.0, 209.8, 20.3, 216.5, 21.6, 251.7, 26.4, 251.5, +32.5, 286.5, 33.4, 293.8, 31.6, 294.0, 30.7, 301.5, 30.7, 301.8, +30.7, 301.8, 30.7, 302.0, 29.9, 308.7, 29.9, 308.7, 29.1, 315.3, +26.0, 342.4, 19.7, 343.1, 22.8, 369.5, 78.4, 549.9, 78.8, 550.4, +78.6, 550.6, 78.7, 551.4, 79.2, 554.2, 78.0, 556.0, 79.7, 557.1, +58.2, 536.4, 56.0, 538.7, 32.3, 520.4, 32.6, 502.7, 31.1, 502.7, +30.0, 485.1, 30.0, 486.7, 31.2, 486.7, 32.4, 488.3, 55.4, 519.1, +55.7, 518.9, 78.4, 549.9, 45.7, 601.3, 32.4, 607.6, 22.4, 604.2, +19.0, 613.9, 18.8, 614.0, 18.6, 614.0, 18.7, 614.1, 15.5, 574.7, +13.6, 573.8, 0.7, 536.2, -1.6, 532.5, -0.3, 531.7, -1.4, 527.1, +8.8, 539.8, 10.5, 538.4, 22.4, 549.7, 37.4, 573.4, 47.0, 576.2, +45.7, 601.3, 22.4, 549.7, 44.3, 570.7, 44.0, 571.1, 66.3, 591.6, +56.0, 596.4, 56.0, 596.4, 45.7, 601.3, 47.0, 576.2, 37.4, 573.4, +22.4, 549.7, 62.2, 708.7, 51.1, 703.2, 42.0, 705.5, 40.0, 697.6, +33.9, 690.0, 28.5, 690.4, 27.9, 682.3, 21.2, 668.6, 25.2, 654.1, +18.3, 653.0, 32.9, 655.3, 30.8, 668.9, 43.3, 684.7, 49.6, 692.7, +49.6, 692.7, 55.9, 700.7, 56.1, 701.0, 56.1, 701.0, 56.3, 701.2, +59.3, 705.0, 58.6, 707.9, 62.2, 708.7, 773.1, 619.7, 757.0, 625.1, +754.8, 618.3, 736.4, 616.8, 736.2, 616.8, 735.9, 616.9, 735.9, 616.8, +730.5, 586.1, 730.5, 586.1, 725.0, 555.3, 725.3, 557.0, 726.8, 556.9, +728.5, 558.4, 734.7, 564.0, 734.7, 564.0, 741.0, 569.6, 750.7, 578.2, +750.7, 578.2, 760.4, 586.8, 768.9, 594.4, 768.9, 594.4, 777.5, 602.0, +778.0, 602.4, 778.5, 602.6, 778.4, 602.8, 776.3, 611.4, 778.0, 618.1, +773.1, 619.7, 778.4, 602.8, 780.2, 601.8, 783.2, 607.1, 787.9, 611.3, +791.7, 614.6, 792.8, 613.9, 795.5, 618.0, 796.2, 619.0, 795.2, 621.3, +794.7, 621.4, 784.0, 622.2, 778.2, 625.5, 773.1, 619.7, 778.0, 618.1, +776.3, 611.4, 778.4, 602.8, 767.2, 714.9, 766.5, 712.4, 765.7, 712.6, +764.3, 710.3, 759.7, 703.1, 759.7, 703.1, 755.2, 696.0, 751.5, 690.4, +750.0, 690.9, 747.9, 684.8, 741.5, 681.2, 749.6, 670.9, 743.8, 661.6, +741.7, 649.6, 741.7, 649.6, 739.6, 637.7, 739.3, 635.8, 739.3, 635.8, +739.0, 634.0, 738.6, 625.3, 737.4, 625.4, 735.9, 616.8, 735.9, 616.9, +736.2, 616.8, 736.4, 616.8, 741.7, 632.9, 741.5, 633.0, 746.6, 649.2, +756.9, 682.0, 757.7, 681.8, 767.2, 714.9, 787.2, 480.4, 785.4, 487.8, +809.3, 488.9, 823.0, 504.7, 825.6, 507.8, 817.7, 516.8, 819.7, 518.2, +799.8, 504.6, 783.7, 494.5, 787.2, 480.4, 760.1, 584.4, 760.7, 585.0, +759.7, 586.2, 760.4, 586.8, 750.7, 578.2, 750.7, 578.2, 741.0, 569.6, +744.4, 572.8, 744.8, 572.5, 748.5, 575.4, 754.3, 579.9, 754.8, 579.3, +760.1, 584.4, 781.1, 677.4, 781.0, 677.3, 781.2, 676.2, 781.4, 676.2, +796.6, 675.2, 796.6, 675.8, 811.9, 675.4, 814.5, 675.3, 814.5, 675.3, +817.1, 675.3, 839.5, 674.7, 855.1, 664.1, 861.9, 674.1, 847.2, 685.9, +848.6, 688.4, 832.4, 697.7, 829.2, 700.2, 827.7, 703.0, 825.4, 702.1, +802.0, 692.9, 803.0, 690.2, 781.1, 677.4, 825.4, 702.1, 824.6, 718.3, +804.0, 723.6, 778.2, 732.1, 776.6, 732.6, 771.7, 726.6, 770.7, 720.3, +769.6, 713.9, 772.4, 713.4, 774.0, 706.6, 777.6, 692.0, 776.3, 677.8, +781.1, 677.4, 803.0, 690.2, 802.0, 692.9, 825.4, 702.1, 736.5, 629.0, +737.7, 631.5, 738.8, 631.5, 739.0, 634.0, 739.3, 635.8, 739.3, 635.8, +739.6, 637.7, 737.6, 633.7, 738.1, 633.5, 736.6, 629.3, 736.5, 629.2, +736.6, 629.2, 736.5, 629.0, 939.3, 263.2, 939.2, 262.7, 941.3, 262.5, +941.3, 262.2, 945.5, 295.0, 945.9, 295.1, 947.6, 328.1, 938.1, 374.2, +948.5, 376.3, 949.4, 424.6, 949.3, 413.7, 948.7, 413.7, 948.0, 402.8, +943.6, 333.0, 942.6, 333.0, 939.3, 263.2, 933.8, 398.2, 945.1, 423.2, +939.9, 425.5, 945.9, 452.8, 948.1, 462.5, 948.5, 462.5, 950.3, 472.2, +950.3, 475.0, 950.5, 475.0, 950.4, 477.7, 949.9, 489.9, 944.7, 492.2, +949.1, 502.2, 932.5, 464.7, 937.5, 462.4, 926.0, 422.7, 923.8, 415.2, +923.8, 415.2, 921.6, 407.7, 920.4, 403.4, 920.4, 403.4, 919.1, 399.2, +916.7, 390.9, 916.1, 382.5, 914.3, 382.6, 923.5, 382.0, 929.2, 388.1, +933.8, 398.2, 924.1, 500.9, 935.4, 520.1, 931.7, 522.3, 939.4, 543.8, +942.7, 553.0, 944.8, 552.8, 946.0, 562.3, 947.5, 574.7, 945.5, 574.9, +944.7, 587.6, 944.7, 587.5, 944.5, 587.5, 944.3, 587.3, 934.6, 580.7, +934.6, 580.7, 924.9, 574.1, 919.9, 570.7, 915.1, 570.9, 915.0, 567.3, +913.8, 541.2, 918.6, 541.0, 922.2, 514.6, 923.1, 507.7, 926.8, 505.5, +924.1, 500.9, 926.0, 422.7, 937.5, 462.4, 932.5, 464.7, 949.1, 502.2, +953.3, 531.4, 952.7, 533.4, 946.0, 562.3, 944.8, 552.8, 942.7, 553.0, +939.4, 543.8, 934.7, 516.5, 936.3, 516.2, 933.3, 488.7, 932.5, 482.0, +932.5, 482.0, 931.8, 475.4, 928.9, 449.0, 938.8, 442.6, 926.0, 422.7, +669.9, 400.6, 666.5, 398.2, 666.5, 398.2, 663.1, 395.9, 663.0, 395.4, +665.6, 394.7, 668.1, 393.5, 684.8, 385.5, 684.8, 385.5, 701.4, 377.5, +711.7, 372.6, 711.7, 372.6, 722.0, 367.6, 725.4, 366.0, 725.4, 366.0, +728.7, 364.4, 730.3, 363.7, 730.3, 363.7, 731.8, 362.9, 732.7, 362.5, +732.7, 362.5, 733.6, 362.1, 740.2, 358.9, 740.2, 358.9, 746.8, 355.7, +750.9, 353.7, 750.9, 353.7, 755.0, 351.7, 767.9, 345.5, 767.9, 345.5, +780.8, 339.3, 815.8, 322.6, 815.8, 322.7, 850.7, 305.9, 851.2, 305.7, +851.6, 305.3, 851.6, 305.3, 851.6, 305.3, 851.2, 305.7, 850.7, 305.9, +805.7, 329.5, 805.7, 329.5, 760.6, 353.1, 715.3, 376.8, 716.7, 380.0, +669.9, 400.6, 676.7, 19.0, 678.1, 20.5, 689.6, 2.0, 699.1, 3.6, +713.8, 6.3, 713.2, 14.6, 725.3, 27.5, 724.0, 26.2, 723.0, 27.1, +720.8, 26.7, 698.7, 22.8, 689.0, 32.0, 676.7, 19.0, 446.7, 132.3, +433.1, 136.8, 432.6, 135.3, 418.6, 138.4, 413.9, 139.4, 413.9, 139.4, +409.3, 140.3, 408.6, 140.5, 408.6, 140.5, 408.0, 140.6, 404.3, 141.4, +404.3, 142.2, 400.6, 142.2, 400.0, 142.2, 399.3, 141.0, 399.5, 140.5, +401.5, 136.3, 401.3, 134.8, 405.1, 132.7, 408.4, 130.9, 409.4, 132.7, +413.7, 132.6, 414.0, 132.6, 414.0, 132.6, 414.2, 132.6, 424.1, 132.5, +424.1, 132.5, 434.0, 132.5, 435.4, 132.4, 435.4, 132.4, 436.8, 132.4, +441.7, 132.4, 442.2, 133.8, 446.7, 132.3, 359.9, 57.9, 372.4, 77.4, +383.0, 94.8, 375.4, 102.9, 379.1, 99.0, 363.7, 84.6, 352.0, 66.3, +345.7, 56.6, 345.7, 56.6, 339.5, 46.8, 338.4, 45.2, 338.4, 45.2, +337.4, 43.5, 327.7, 28.4, 331.8, 22.0, 318.0, 13.2, 343.0, 29.2, +343.7, 32.5, 359.9, 57.9, 318.0, 13.2, 309.1, 2.6, 299.8, -3.8, +303.0, -10.2, 318.3, -14.2, 318.3, -14.2, 333.7, -18.1, 336.3, -17.9, +335.7, -12.3, 337.7, -6.6, 348.8, 25.7, 370.5, 47.3, 359.9, 57.9, +343.7, 32.5, 343.0, 29.2, 318.0, 13.2, 393.4, 131.0, 382.3, 118.8, +382.3, 117.9, 375.4, 102.9, 383.0, 94.8, 372.4, 77.4, 359.9, 57.9, +370.5, 47.3, 348.8, 25.7, 337.7, -6.6, 365.8, 53.1, 362.5, 54.7, +387.3, 116.0, 390.3, 123.5, 388.3, 125.4, 393.4, 131.0, 290.4, 2.4, +289.0, 0.5, 293.4, -4.2, 298.2, -9.0, 300.6, -9.6, 300.6, -9.6, +303.0, -10.2, 299.8, -3.8, 309.1, 2.6, 318.0, 13.2, 331.8, 22.0, +327.7, 28.4, 337.4, 43.5, 336.2, 41.4, 335.5, 41.8, 333.5, 40.1, +311.9, 21.3, 306.7, 25.1, 290.4, 2.4, 432.1, 236.3, 431.1, 225.7, +431.2, 225.7, 430.8, 215.1, 431.0, 219.5, 431.2, 219.5, 431.6, 223.8, +431.8, 226.0, 431.8, 226.0, 432.0, 228.2, 435.6, 267.5, 435.6, 267.5, +439.3, 306.7, 441.3, 329.1, 441.3, 329.1, 443.4, 351.4, 443.9, 357.8, +443.9, 357.8, 444.5, 364.1, 444.8, 366.7, 444.8, 366.7, 445.0, 369.4, +446.9, 389.4, 446.9, 389.4, 448.7, 409.5, 452.1, 447.0, 452.1, 447.0, +455.6, 484.5, 456.5, 494.1, 456.5, 494.1, 457.3, 503.6, 461.1, 544.5, +461.1, 544.5, 464.8, 585.3, 466.5, 603.5, 466.6, 603.5, 468.2, 621.6, +469.3, 634.5, 469.2, 634.5, 470.3, 647.3, 471.5, 660.3, 471.7, 660.3, +472.9, 673.2, 473.3, 677.4, 473.3, 677.4, 473.7, 681.5, 473.9, 684.3, +474.0, 684.3, 474.2, 687.1, 474.9, 695.0, 474.8, 695.0, 475.5, 702.9, +476.7, 715.9, 476.8, 715.9, 478.0, 728.9, 480.1, 750.5, 480.0, 750.5, +482.0, 772.1, 482.3, 775.1, 482.3, 775.1, 482.5, 778.1, 483.9, 793.3, +485.3, 808.6, 485.3, 808.6, 485.3, 808.6, 483.9, 793.3, 482.5, 778.1, +482.3, 775.1, 482.3, 775.1, 482.0, 772.1, 480.0, 750.5, 480.1, 750.5, +478.0, 728.9, 476.8, 715.9, 476.7, 715.9, 475.5, 702.9, 472.9, 675.1, +472.9, 675.1, 470.3, 647.3, 469.3, 635.9, 469.4, 635.9, 468.4, 624.5, +468.3, 623.1, 468.3, 623.1, 468.2, 621.6, 466.6, 603.5, 466.5, 603.5, +464.8, 585.3, 461.1, 544.5, 461.1, 544.5, 457.3, 503.6, 456.5, 494.1, +456.5, 494.1, 455.6, 484.5, 452.1, 447.0, 452.1, 447.0, 448.7, 409.5, +446.9, 389.4, 446.9, 389.4, 445.0, 369.4, 438.6, 302.8, 438.2, 302.9, +432.1, 236.3, 431.6, 223.8, 431.2, 219.5, 431.0, 219.5, 430.8, 215.1, +429.9, 201.0, 423.5, 197.5, 429.1, 186.9, 427.2, 190.5, 437.8, 193.7, +438.3, 201.1, 439.0, 212.2, 437.1, 213.6, 431.6, 223.8, 94.7, 97.2, +96.3, 96.3, 94.0, 92.2, 93.3, 87.3, 91.4, 73.5, 91.4, 73.5, +89.5, 59.8, 88.5, 52.6, 84.6, 48.1, 87.6, 45.5, 100.2, 42.2, +100.2, 42.2, 112.9, 38.9, 122.8, 39.1, 132.9, 43.7, 132.6, 46.2, +130.6, 63.5, 120.5, 62.4, 108.5, 78.6, 101.6, 87.9, 103.9, 91.9, +94.7, 97.2, 236.1, 70.1, 237.2, 70.5, 237.2, 74.9, 235.3, 77.7, +233.3, 80.6, 231.3, 82.1, 228.3, 81.5, 227.1, 73.6, 213.7, 72.4, +198.1, 70.3, 187.3, 66.3, 178.2, 59.9, 176.5, 62.4, 179.9, 57.6, +189.0, 64.0, 201.4, 65.6, 203.1, 65.8, 203.1, 65.8, 204.7, 66.0, +207.8, 66.4, 207.8, 66.4, 210.8, 66.8, 223.5, 68.4, 225.0, 65.1, +236.1, 70.1, 239.1, 42.7, 241.4, 39.6, 239.6, 38.3, 240.1, 33.8, +241.7, 19.5, 235.9, 15.3, 243.2, 5.2, 254.1, 2.4, 254.1, 2.4, +264.9, -0.3, 262.4, 22.3, 253.8, 22.5, 239.1, 42.7, 264.9, -0.3, +281.5, -4.7, 281.5, -4.7, 298.2, -9.0, 293.4, -4.2, 289.0, 0.5, +290.4, 2.4, 281.5, 15.3, 281.5, 15.3, 272.6, 28.3, 271.6, 29.7, +271.6, 29.7, 270.6, 31.1, 270.6, 31.2, 270.6, 31.2, 270.6, 31.2, +267.6, 35.6, 267.6, 35.6, 264.6, 39.9, 257.8, 49.7, 257.8, 49.7, +251.1, 59.5, 245.9, 67.1, 246.6, 67.8, 240.6, 74.8, 238.8, 76.9, +235.8, 78.2, 235.3, 77.7, 237.2, 74.9, 237.2, 70.5, 236.1, 70.1, +237.6, 56.4, 234.1, 55.0, 239.1, 42.7, 253.8, 22.5, 262.4, 22.3, +264.9, -0.3, 202.2, 95.7, 215.3, 88.6, 229.1, 86.3, 228.3, 81.5, +231.3, 82.1, 233.3, 80.6, 235.3, 77.7, 235.8, 78.2, 238.8, 76.9, +240.6, 74.8, 223.0, 102.9, 229.0, 115.3, 202.9, 129.5, 209.8, 125.8, +195.3, 108.8, 202.2, 95.7, 202.9, 129.5, 202.9, 131.1, 202.0, 132.5, +200.8, 132.6, 185.0, 134.2, 184.8, 132.8, 168.8, 133.0, 156.7, 133.2, +156.7, 133.2, 144.7, 133.3, 142.7, 133.4, 142.0, 132.4, 140.7, 133.4, +164.5, 120.3, 164.3, 119.7, 186.7, 104.2, 194.5, 100.0, 194.5, 100.0, +202.2, 95.7, 195.3, 108.8, 209.8, 125.8, 202.9, 129.5, 167.7, 180.7, +147.7, 192.0, 153.2, 201.8, 138.8, 222.8, 136.8, 225.6, 137.5, 226.5, +134.9, 228.4, 135.5, 232.9, 120.5, 231.5, 114.4, 240.4, 114.8, 240.2, +113.1, 237.7, 113.9, 236.9, 139.8, 207.9, 135.3, 199.1, 167.7, 180.7, +143.9, 642.6, 147.6, 620.7, 147.6, 620.7, 151.3, 598.8, 157.1, 641.0, +162.5, 640.3, 175.1, 681.5, 177.5, 690.6, 176.4, 690.9, 177.7, 700.4, +179.3, 711.9, 179.3, 711.9, 180.9, 723.4, 182.7, 737.0, 182.7, 737.0, +184.6, 750.6, 184.7, 751.0, 184.6, 751.1, 184.7, 751.5, 171.2, 715.6, +171.3, 715.6, 157.8, 679.7, 156.0, 674.9, 156.0, 674.9, 154.3, 670.2, +149.1, 656.4, 144.5, 656.6, 143.9, 642.6, 125.1, 606.5, 125.7, 587.3, +144.0, 585.9, 141.4, 568.5, 139.3, 630.5, 139.6, 630.5, 137.8, 692.5, +152.3, 658.4, 123.9, 649.3, 125.1, 606.5, 95.0, 640.0, 97.5, 614.8, +98.9, 614.8, 100.0, 589.5, 104.7, 567.6, 107.5, 568.2, 115.1, 546.9, +120.5, 531.4, 124.2, 531.8, 126.0, 515.9, 122.8, 543.6, 119.2, 543.2, +112.4, 570.4, 108.5, 585.7, 108.5, 585.7, 104.7, 601.1, 102.4, 610.2, +102.4, 610.2, 100.1, 619.4, 97.5, 629.7, 94.9, 629.7, 95.0, 640.0, +10.6, 447.0, 22.3, 456.0, 16.9, 463.2, 23.2, 479.3, 25.8, 485.7, +27.2, 485.5, 28.3, 492.1, 28.9, 505.1, 27.6, 505.3, 29.4, 518.2, +24.2, 514.1, 21.7, 515.4, 19.0, 510.1, 15.9, 505.5, 14.4, 506.5, +9.8, 503.0, 7.7, 499.0, 9.9, 497.9, 9.9, 492.8, 10.1, 481.1, +10.1, 481.1, 10.2, 469.4, 10.4, 458.2, 15.8, 451.1, 10.6, 447.0, +-22.1, 363.9, -22.7, 362.5, -22.7, 362.5, -23.3, 361.1, -25.7, 355.0, +-26.1, 355.1, -28.1, 348.9, -28.3, 348.1, -27.4, 347.8, -27.6, 347.1, +-24.5, 355.0, -25.0, 355.2, -22.3, 363.3, -22.2, 363.6, -22.2, 363.6, +-22.1, 363.9, -24.7, 334.6, -20.5, 316.8, -20.4, 316.8, -16.2, 299.0, +-16.2, 299.0, -15.8, 297.4, -15.4, 295.8, -12.0, 279.2, -11.2, 279.4, +-7.1, 263.0, -3.2, 247.2, -3.2, 247.1, 0.6, 231.3, -3.2, 247.1, +-3.2, 247.2, -7.1, 263.0, -11.2, 279.4, -12.0, 279.2, -15.4, 295.8, +-15.8, 297.4, -16.2, 299.0, -16.2, 299.0, -19.1, 311.6, -19.1, 311.6, +-22.1, 324.1, -23.3, 329.4, -23.4, 329.3, -24.7, 334.6, 30.7, 301.5, +31.6, 294.0, 33.4, 293.8, 32.5, 286.5, 34.3, 297.0, 38.5, 298.0, +36.1, 307.5, 37.1, 313.2, 37.1, 313.2, 38.1, 318.9, 38.5, 321.0, +38.5, 321.0, 38.9, 323.2, 39.0, 324.0, 38.9, 324.0, 39.1, 324.7, +34.8, 313.2, 32.8, 313.5, 30.7, 301.5, 77.0, 541.9, 79.2, 544.8, +76.2, 547.2, 78.4, 549.9, 55.7, 518.9, 55.4, 519.1, 32.4, 488.3, +38.9, 497.4, 39.6, 496.9, 46.7, 505.5, 61.9, 523.7, 63.3, 522.7, +77.0, 541.9, 774.0, 706.6, 772.4, 713.4, 769.6, 713.9, 770.7, 720.3, +770.8, 720.0, 770.4, 719.9, 770.2, 719.5, 768.7, 717.2, 768.1, 717.4, +767.2, 714.9, 757.7, 681.8, 756.9, 682.0, 746.6, 649.2, 747.7, 652.9, +748.3, 652.7, 750.0, 656.2, 762.0, 681.4, 765.5, 680.3, 774.0, 706.6, +745.8, 465.5, 745.6, 465.3, 745.7, 465.1, 745.7, 464.8, 744.9, 457.9, +747.0, 452.1, 744.0, 451.0, 767.8, 459.9, 767.8, 463.2, 787.2, 480.4, +783.7, 494.5, 799.8, 504.6, 819.7, 518.2, 820.2, 518.7, 819.5, 519.3, +819.2, 520.3, 818.8, 522.1, 819.5, 522.9, 818.4, 523.8, 818.2, 523.9, +817.5, 523.1, 816.7, 522.4, 781.2, 494.0, 781.1, 494.2, 745.8, 465.5, +728.5, 558.4, 726.8, 556.9, 725.3, 557.0, 725.0, 555.3, 723.8, 548.1, +723.8, 548.1, 722.5, 540.9, 722.7, 542.5, 723.0, 542.4, 723.5, 543.9, +726.0, 551.2, 727.5, 551.0, 728.5, 558.4, 811.9, 675.4, 796.6, 675.8, +796.6, 675.2, 781.4, 676.2, 776.8, 671.7, 782.5, 663.2, 787.3, 651.6, +787.0, 652.4, 788.9, 653.1, 790.4, 654.6, 797.3, 661.3, 797.3, 661.3, +804.3, 668.0, 808.1, 671.7, 809.7, 676.2, 811.9, 675.4, 736.6, 629.3, +738.1, 633.5, 737.6, 633.7, 739.6, 637.7, 741.7, 649.6, 741.7, 649.6, +743.8, 661.6, 728.6, 636.5, 724.9, 638.7, 706.0, 615.9, 708.2, 625.6, +722.7, 620.4, 736.6, 629.3, 706.0, 615.9, 701.3, 610.3, 695.8, 609.3, +696.7, 604.7, 696.3, 604.2, 696.3, 604.1, 696.0, 603.6, 690.6, 595.2, +687.4, 596.0, 685.3, 586.9, 684.6, 584.2, 687.8, 583.4, 690.4, 580.0, +694.8, 574.1, 694.8, 574.1, 699.3, 568.1, 701.3, 565.4, 704.0, 563.8, +703.4, 562.7, 708.9, 597.6, 719.9, 595.9, 736.5, 629.0, 736.6, 629.2, +736.5, 629.2, 736.6, 629.3, 722.7, 620.4, 708.2, 625.6, 706.0, 615.9, +628.6, 378.5, 639.5, 392.5, 639.5, 392.5, 650.4, 406.5, 654.9, 441.5, +646.0, 442.7, 641.6, 478.9, 641.5, 479.0, 641.5, 479.0, 641.5, 479.0, +641.1, 482.9, 641.1, 482.9, 640.6, 486.8, 639.5, 496.1, 635.1, 498.0, +638.3, 505.4, 632.9, 492.8, 637.2, 490.9, 636.1, 476.4, 634.1, 450.4, +634.1, 450.4, 632.1, 424.4, 630.4, 401.5, 618.0, 388.9, 628.6, 378.5, +641.6, 478.9, 646.0, 442.7, 654.9, 441.5, 650.4, 406.5, 659.8, 418.7, +662.6, 432.2, 669.3, 430.8, 669.3, 431.2, 669.6, 431.2, 669.9, 431.6, +665.0, 440.8, 664.6, 440.6, 659.2, 449.5, 650.4, 464.2, 639.0, 466.5, +641.6, 478.9, 914.0, 381.7, 920.2, 370.0, 908.9, 364.0, 903.7, 346.4, +903.5, 345.5, 903.5, 345.5, 903.2, 344.7, 896.6, 321.9, 896.6, 321.9, +890.0, 299.2, 888.4, 293.8, 888.2, 293.8, 886.8, 288.4, 886.8, 288.3, +887.1, 288.3, 887.3, 288.2, 895.2, 284.4, 895.2, 284.4, 903.1, 280.6, +905.1, 279.6, 907.3, 278.8, 907.2, 278.6, 914.2, 299.5, 915.4, 300.0, +916.8, 321.8, 918.8, 351.5, 926.7, 357.7, 914.0, 381.7, 916.8, 321.8, +940.6, 341.7, 935.4, 360.4, 933.8, 398.2, 929.2, 388.1, 923.5, 382.0, +914.3, 382.6, 914.0, 382.4, 914.0, 382.1, 914.0, 381.7, 926.7, 357.7, +918.8, 351.5, 916.8, 321.8, 869.9, 395.5, 869.6, 395.5, 869.6, 393.4, +869.3, 391.2, 866.2, 370.9, 866.2, 370.9, 863.2, 350.6, 862.8, 348.1, +862.8, 348.1, 862.4, 345.6, 861.4, 338.7, 861.4, 338.7, 860.4, 331.9, +859.2, 323.7, 857.8, 323.7, 858.0, 315.5, 857.9, 319.1, 859.2, 319.2, +860.5, 322.8, 865.3, 336.2, 868.2, 335.8, 870.1, 349.6, 872.9, 370.0, +870.0, 370.4, 869.9, 391.2, 869.9, 393.4, 869.9, 395.5, 869.9, 395.5, +860.5, 322.8, 859.2, 319.2, 857.9, 319.1, 858.0, 315.5, 856.6, 309.4, +853.5, 305.6, 856.1, 303.1, 867.9, 292.0, 870.8, 290.2, 886.8, 288.4, +888.2, 293.8, 888.4, 293.8, 890.0, 299.2, 887.6, 305.1, 884.3, 303.7, +878.7, 308.3, 869.6, 315.5, 870.9, 319.1, 860.5, 322.8, 694.7, 409.5, +693.6, 408.7, 690.9, 414.1, 688.8, 413.4, 680.5, 407.7, 674.0, 400.5, +672.2, 402.1, 672.2, 401.6, 671.4, 401.6, 670.6, 401.0, 682.8, 405.0, +684.5, 402.5, 694.7, 409.5, 860.4, 331.9, 861.4, 338.7, 861.4, 338.7, +862.4, 345.6, 858.9, 351.0, 855.0, 348.4, 847.6, 351.2, 844.2, 352.5, +844.2, 352.5, 840.8, 353.8, 820.4, 361.5, 820.4, 361.5, 799.9, 369.3, +792.1, 372.2, 792.1, 372.2, 784.2, 375.2, 782.6, 375.8, 782.5, 375.6, +781.0, 376.4, 805.0, 362.6, 805.1, 362.9, 829.3, 349.3, 835.8, 345.6, +835.8, 345.6, 842.4, 342.0, 851.4, 336.9, 852.6, 330.4, 860.4, 331.9, +625.4, 361.6, 634.8, 368.9, 633.8, 370.2, 642.2, 378.7, 646.5, 383.2, +645.7, 384.7, 650.9, 387.6, 634.8, 376.6, 636.3, 372.9, 618.6, 365.6, +607.2, 357.8, 607.2, 357.8, 595.7, 350.0, 591.1, 346.9, 591.1, 346.9, +586.5, 343.8, 560.5, 326.1, 560.5, 326.1, 534.6, 308.4, 515.9, 289.9, +512.4, 293.3, 490.3, 278.3, 494.6, 281.3, 494.8, 281.0, 499.3, 283.8, +500.2, 284.4, 500.2, 284.4, 501.2, 285.0, 543.6, 311.2, 543.6, 311.2, +586.0, 337.3, 592.2, 341.2, 592.2, 341.2, 598.4, 345.0, 611.9, 353.3, +612.9, 352.0, 625.4, 361.6, 251.1, 59.5, 257.8, 49.7, 257.8, 49.7, +264.6, 39.9, 245.2, 81.7, 243.4, 80.9, 222.1, 121.8, 201.5, 161.7, +201.5, 161.7, 180.9, 201.5, 171.0, 220.5, 170.9, 220.4, 161.1, 239.4, +158.7, 243.9, 156.5, 248.6, 156.5, 248.6, 156.5, 248.6, 158.7, 243.9, +161.1, 239.4, 180.0, 201.5, 180.0, 201.5, 199.0, 163.7, 219.1, 123.5, +219.1, 123.5, 239.2, 83.3, 245.2, 71.4, 244.4, 70.9, 251.1, 59.5, +474.9, 881.8, 473.8, 882.9, 470.8, 882.1, 470.7, 882.0, 466.7, 848.4, +468.7, 848.1, 466.7, 814.3, 465.8, 799.3, 465.8, 799.3, 464.9, 784.3, +463.3, 759.1, 463.2, 759.1, 461.7, 734.0, 460.1, 708.3, 460.2, 708.3, +458.7, 682.6, 457.9, 669.3, 457.9, 669.3, 457.1, 655.9, 455.3, 625.3, +455.3, 625.3, 453.5, 594.6, 453.1, 588.3, 453.1, 588.3, 452.8, 581.9, +452.6, 578.7, 452.6, 578.7, 452.4, 575.5, 451.9, 567.7, 451.9, 567.7, +451.5, 559.9, 449.9, 533.5, 450.3, 533.5, 448.3, 507.2, 454.4, 587.2, +454.0, 587.3, 459.7, 667.4, 462.4, 705.5, 462.4, 705.5, 465.1, 743.6, +468.5, 791.8, 468.5, 791.8, 471.9, 840.0, 473.3, 859.1, 473.3, 859.1, +474.7, 878.3, 474.8, 880.1, 475.7, 881.1, 474.9, 881.8, 140.0, 48.9, +137.3, 46.4, 136.3, 47.5, 132.6, 46.2, 132.9, 43.7, 122.8, 39.1, +112.9, 38.9, 117.5, 37.7, 117.5, 37.7, 122.0, 36.6, 132.0, 40.2, +132.1, 41.6, 140.0, 48.9, 168.8, 133.0, 184.8, 132.8, 185.0, 134.2, +200.8, 132.6, 200.1, 132.2, 196.4, 139.0, 192.0, 145.4, 182.2, 159.7, +183.0, 160.3, 172.4, 174.0, 173.0, 173.1, 172.2, 172.5, 172.1, 171.1, +171.0, 158.5, 171.0, 158.5, 169.9, 145.9, 169.7, 143.6, 169.7, 143.6, +169.5, 141.3, 169.2, 137.2, 168.1, 133.2, 168.8, 133.0, 142.5, 800.7, +142.4, 726.7, 142.4, 726.7, 142.2, 652.8, 142.1, 647.8, 143.1, 647.7, +143.9, 642.7, 144.9, 660.2, 143.8, 660.2, 143.6, 677.7, 143.1, 739.2, +139.1, 739.4, 142.5, 800.7, 112.4, 570.4, 119.2, 543.2, 122.8, 543.6, +126.0, 515.9, 127.1, 511.9, 127.4, 512.0, 128.8, 508.0, 135.1, 490.1, +135.1, 490.1, 141.5, 472.1, 141.7, 471.6, 142.0, 471.5, 141.9, 471.0, +141.9, 472.3, 141.9, 472.3, 141.9, 473.6, 127.5, 522.1, 130.1, 523.1, +112.4, 570.4, 132.1, 396.2, 135.2, 425.6, 135.2, 425.6, 138.4, 454.9, +109.9, 423.8, 122.8, 412.0, 107.3, 369.1, 106.3, 366.5, 106.3, 366.5, +105.4, 363.9, 98.1, 343.8, 98.1, 343.8, 90.8, 323.7, 84.3, 305.5, +84.3, 305.5, 77.7, 287.3, 72.4, 272.6, 72.4, 272.6, 67.0, 257.9, +64.0, 249.4, 64.0, 249.4, 60.9, 240.9, 58.1, 233.2, 58.4, 225.5, +55.3, 225.4, 59.1, 225.6, 58.8, 233.2, 62.3, 240.9, 63.3, 243.2, +63.3, 243.2, 64.3, 245.5, 70.8, 259.9, 70.8, 259.9, 77.2, 274.3, +90.8, 304.5, 90.8, 304.5, 104.4, 334.7, 106.6, 339.6, 106.6, 339.6, +108.8, 344.5, 120.5, 370.3, 124.8, 369.2, 132.1, 396.2, 73.9, 510.3, +74.7, 516.4, 72.5, 516.8, 73.7, 522.7, 63.8, 473.9, 62.6, 474.0, +56.6, 424.6, 60.5, 456.8, 63.0, 456.5, 69.5, 488.4, 71.7, 499.4, +72.6, 499.3, 73.9, 510.3, -25.5, 438.4, -32.2, 422.8, -39.0, 422.7, +-38.9, 407.2, -40.1, 403.8, -40.7, 403.4, -40.2, 400.0, -38.5, 387.8, +-34.0, 376.1, -34.5, 375.9, -29.2, 377.4, -32.6, 389.3, -30.6, 402.7, +-28.1, 420.5, -20.0, 435.3, -25.5, 438.4, 22.8, 369.7, 23.3, 379.1, +23.2, 379.1, 23.7, 388.5, 25.5, 440.3, 26.0, 440.3, 28.3, 492.1, +27.2, 485.5, 25.8, 485.7, 23.2, 479.3, 22.2, 474.7, 23.2, 474.4, +23.2, 469.6, 23.1, 435.6, 23.1, 435.6, 22.9, 401.7, 22.9, 387.5, +22.9, 387.5, 22.8, 373.4, 22.8, 371.5, 22.9, 371.5, 22.8, 369.7, +-7.1, 263.0, -3.2, 247.2, -3.2, 247.1, 0.6, 231.3, 2.8, 222.5, +2.7, 222.5, 5.0, 213.7, 8.2, 201.4, 6.4, 200.6, 11.4, 189.1, +12.6, 184.6, 11.6, 184.0, 13.9, 180.0, 13.5, 181.6, 14.2, 181.8, +14.5, 183.5, 16.1, 189.6, 14.8, 189.9, 15.1, 196.4, 21.6, 253.7, +15.7, 254.3, 16.3, 312.3, 18.3, 298.8, 9.2, 297.5, 2.2, 282.6, +-2.5, 272.8, -6.8, 272.9, -7.1, 263.0, 25.8, 421.8, 24.7, 405.2, +24.2, 405.2, 23.7, 388.5, 23.2, 379.1, 23.3, 379.1, 22.8, 369.7, +22.8, 369.7, 22.8, 369.7, 22.8, 369.6, 22.8, 369.6, 22.8, 369.5, +22.8, 369.5, 19.7, 343.1, 26.0, 342.4, 29.1, 315.3, 35.6, 352.4, +27.9, 353.7, 26.8, 392.2, 26.7, 393.2, 26.7, 393.2, 26.7, 394.2, +26.2, 408.0, 20.2, 411.2, 25.8, 421.8, 55.5, 418.2, 55.0, 421.2, +56.0, 421.4, 56.6, 424.6, 62.6, 474.0, 63.8, 473.9, 73.7, 522.7, +75.4, 532.3, 71.5, 538.3, 77.0, 541.9, 63.3, 522.7, 61.9, 523.7, +46.7, 505.5, 40.6, 486.7, 48.9, 484.0, 51.0, 462.5, 53.2, 440.3, +52.2, 440.2, 55.5, 418.2, 40.2, 617.2, 64.0, 620.8, 64.0, 620.8, +87.8, 624.5, 87.7, 638.4, 88.9, 638.4, 89.9, 652.3, 89.9, 652.3, +89.7, 652.3, 89.4, 652.2, 80.8, 650.5, 80.8, 650.5, 72.2, 648.9, +62.8, 647.0, 59.0, 650.8, 53.4, 645.1, 43.1, 634.9, 38.9, 618.0, +40.2, 617.2, 53.4, 645.1, 53.2, 643.6, 47.9, 644.1, 42.5, 643.0, +35.6, 641.6, 35.6, 641.6, 28.8, 640.3, 21.0, 638.8, 17.9, 641.9, +13.1, 637.2, 7.2, 631.4, 5.5, 627.2, 7.3, 619.4, 7.9, 620.2, +18.8, 616.3, 18.7, 614.1, 18.6, 614.0, 18.8, 614.0, 19.0, 613.9, +19.7, 612.1, 29.6, 615.5, 40.2, 617.2, 38.9, 618.0, 43.1, 634.9, +53.4, 645.1, 75.8, 715.5, 69.0, 712.1, 69.0, 712.1, 62.2, 708.7, +58.6, 707.9, 59.3, 705.0, 56.3, 701.2, 67.0, 706.5, 68.6, 706.3, +75.8, 715.5, 789.1, 644.2, 787.8, 644.4, 788.2, 647.9, 787.3, 651.6, +782.5, 663.2, 776.8, 671.7, 781.4, 676.2, 781.2, 676.2, 781.0, 677.3, +781.1, 677.4, 776.3, 677.8, 777.6, 692.0, 774.0, 706.6, 765.5, 680.3, +762.0, 681.4, 750.0, 656.2, 752.4, 646.1, 769.1, 646.7, 789.1, 644.2, +750.0, 656.2, 748.3, 652.7, 747.7, 652.9, 746.6, 649.2, 741.5, 633.0, +741.7, 632.9, 736.4, 616.8, 754.8, 618.3, 757.0, 625.1, 773.1, 619.7, +778.2, 625.5, 784.0, 622.2, 794.7, 621.4, 794.7, 621.4, 794.2, 623.3, +793.8, 625.1, 791.5, 634.7, 795.2, 639.9, 789.1, 644.2, 769.1, 646.7, +752.4, 646.1, 750.0, 656.2, 748.1, 484.6, 742.7, 479.3, 750.7, 468.2, +745.8, 465.5, 781.1, 494.2, 781.2, 494.0, 816.7, 522.4, 809.9, 516.5, +808.6, 518.0, 800.5, 513.5, 793.3, 509.5, 793.3, 509.5, 786.1, 505.6, +767.1, 495.1, 762.9, 499.3, 748.1, 484.6, 907.8, 630.0, 907.7, 629.7, +907.1, 629.8, 907.1, 629.4, 904.8, 615.5, 904.2, 615.5, 903.1, 601.5, +903.9, 612.2, 904.8, 612.1, 906.6, 622.8, 907.2, 626.4, 907.5, 626.4, +907.8, 630.0, 595.7, 350.0, 607.2, 357.8, 607.2, 357.8, 618.6, 365.6, +625.2, 368.3, 623.6, 372.1, 628.6, 378.5, 618.0, 388.9, 630.4, 401.5, +632.1, 424.4, 604.2, 402.0, 614.7, 388.9, 597.3, 353.4, 596.5, 351.7, +597.0, 350.8, 595.7, 350.0, 659.2, 449.5, 664.6, 440.6, 665.0, 440.8, +669.9, 431.6, 678.3, 442.4, 678.3, 442.4, 686.6, 453.1, 683.8, 457.8, +665.3, 457.3, 659.2, 449.5, 948.0, 402.8, 948.7, 413.7, 949.3, 413.7, +949.4, 424.6, 949.8, 448.4, 949.8, 448.4, 950.3, 472.2, 948.5, 462.5, +948.1, 462.5, 945.9, 452.8, 942.7, 430.1, 943.4, 430.0, 940.8, 407.3, +937.7, 379.2, 924.2, 357.6, 934.6, 351.1, 927.8, 355.4, 942.7, 376.7, +948.0, 402.8, 934.6, 351.1, 927.7, 310.9, 923.3, 310.1, 925.5, 269.8, +925.6, 266.1, 939.6, 265.2, 939.3, 263.2, 942.6, 333.0, 943.6, 333.0, +948.0, 402.8, 942.7, 376.7, 927.8, 355.4, 934.6, 351.1, 914.7, 275.0, +914.5, 273.9, 918.0, 273.4, 921.4, 271.7, 923.2, 270.9, 923.2, 270.9, +925.0, 270.0, 925.2, 269.9, 925.5, 269.9, 925.5, 269.8, 923.3, 310.1, +927.7, 310.9, 934.6, 351.1, 924.2, 357.6, 937.7, 379.2, 940.8, 407.3, +923.8, 342.2, 924.2, 341.6, 914.7, 275.0, 940.8, 407.3, 943.4, 430.0, +942.7, 430.1, 945.9, 452.8, 939.9, 425.5, 945.1, 423.2, 933.8, 398.2, +935.4, 360.4, 940.6, 341.7, 916.8, 321.8, 915.4, 300.0, 914.2, 299.5, +907.2, 278.6, 907.1, 277.0, 914.9, 275.8, 914.7, 275.0, 924.2, 341.6, +923.8, 342.2, 940.8, 407.3, 760.6, 353.1, 805.7, 329.5, 805.7, 329.5, +850.7, 305.9, 823.3, 315.5, 825.7, 322.5, 800.7, 339.1, 776.8, 355.0, +776.8, 355.0, 752.8, 370.9, 744.0, 376.7, 738.7, 374.4, 735.2, 382.6, +742.6, 365.5, 745.0, 363.5, 760.6, 353.1, 735.2, 382.6, 717.6, 397.7, +715.7, 395.5, 696.2, 408.5, 695.5, 409.0, 695.3, 409.6, 694.7, 409.5, +684.5, 402.5, 682.8, 405.0, 670.6, 401.0, 670.3, 400.8, 670.3, 400.8, +669.9, 400.6, 716.7, 380.0, 715.3, 376.8, 760.6, 353.1, 745.0, 363.5, +742.6, 365.5, 735.2, 382.6, 829.3, 349.3, 805.1, 362.9, 805.0, 362.6, +781.0, 376.4, 775.0, 379.5, 774.6, 378.8, 768.3, 381.2, 766.2, 382.0, +766.2, 382.0, 764.0, 382.8, 751.7, 387.5, 751.7, 387.5, 739.4, 392.2, +727.0, 396.9, 727.0, 396.9, 714.5, 401.6, 705.4, 405.0, 702.9, 402.3, +696.2, 408.5, 715.7, 395.5, 717.6, 397.7, 735.2, 382.6, 738.7, 374.4, +744.0, 376.7, 752.8, 370.9, 790.2, 357.7, 794.5, 342.5, 829.3, 349.3, +823.9, 404.0, 808.4, 391.3, 812.1, 386.9, 800.2, 369.8, 800.1, 369.5, +800.0, 369.2, 799.9, 369.3, 820.4, 361.5, 820.4, 361.5, 840.8, 353.8, +846.5, 358.5, 834.3, 373.1, 827.8, 392.5, 825.8, 398.3, 822.2, 402.7, +823.9, 404.0, 520.2, 128.3, 522.8, 135.7, 526.6, 134.1, 530.8, 141.2, +541.2, 158.9, 540.1, 159.5, 549.5, 177.8, 563.9, 205.9, 566.4, 204.8, +578.3, 234.0, 576.1, 228.6, 572.1, 230.5, 569.0, 225.3, 554.9, 201.4, +556.5, 200.5, 544.1, 175.8, 542.3, 172.2, 542.3, 172.2, 540.5, 168.7, +530.3, 148.5, 527.6, 149.4, 520.2, 128.3, 649.0, 299.7, 641.0, 276.2, +628.3, 280.5, 607.6, 261.2, 603.6, 257.5, 603.6, 257.5, 599.6, 253.8, +588.9, 243.9, 586.1, 245.8, 578.3, 234.0, 566.4, 204.8, 563.9, 205.9, +549.5, 177.8, 581.3, 186.8, 575.0, 209.0, 600.5, 240.3, 624.8, 270.0, +637.5, 265.7, 649.0, 299.7, 621.3, 242.7, 629.3, 253.2, 624.4, 257.5, +633.4, 266.7, 601.5, 234.1, 604.4, 231.3, 575.4, 195.8, 570.5, 189.8, +571.2, 189.2, 565.6, 183.9, 578.8, 196.4, 578.2, 197.1, 590.7, 210.4, +606.0, 226.5, 607.9, 225.1, 621.3, 242.7, 607.6, 261.2, 628.3, 280.5, +641.0, 276.2, 649.0, 299.7, 666.4, 315.9, 667.6, 314.8, 683.8, 332.1, +680.1, 328.1, 678.1, 330.1, 674.0, 326.3, 640.0, 294.7, 639.4, 295.1, +607.6, 261.2, 538.5, 273.3, 548.2, 283.1, 548.2, 283.1, 557.8, 293.0, +582.8, 318.3, 582.8, 318.3, 607.8, 343.7, 616.6, 352.7, 617.9, 362.6, +625.4, 361.6, 612.9, 352.0, 611.9, 353.3, 598.4, 345.0, 568.0, 314.6, +570.6, 312.1, 542.8, 279.0, 542.2, 278.3, 542.2, 278.2, 541.6, 277.4, +540.5, 275.8, 540.5, 275.8, 539.3, 274.3, 538.9, 273.8, 538.9, 273.7, +538.5, 273.3, 671.6, 22.5, 673.6, 20.2, 674.3, 18.8, 676.7, 19.0, +689.0, 32.0, 698.7, 22.8, 720.8, 26.7, 691.3, 60.0, 674.9, 71.6, +633.3, 68.0, 650.3, 69.5, 651.8, 44.7, 671.6, 22.5, 633.3, 68.0, +619.2, 79.9, 616.0, 76.2, 598.7, 84.3, 570.9, 97.4, 571.6, 99.2, +543.0, 110.6, 550.9, 107.4, 550.2, 105.6, 557.4, 100.7, 560.1, 98.9, +560.1, 98.9, 562.7, 97.1, 566.7, 94.4, 566.7, 94.4, 570.6, 91.6, +605.0, 68.1, 605.0, 68.1, 639.3, 44.6, 655.4, 33.6, 667.9, 36.8, +671.6, 22.5, 651.8, 44.7, 650.3, 69.5, 633.3, 68.0, 623.1, 94.6, +622.0, 94.0, 621.5, 95.0, 619.9, 95.3, 615.1, 96.3, 615.1, 96.3, +610.4, 97.3, 600.3, 99.5, 600.3, 99.5, 590.2, 101.6, 580.0, 103.8, +580.0, 103.8, 569.8, 106.0, 569.2, 106.1, 569.2, 106.1, 568.7, 106.2, +561.4, 107.8, 561.4, 107.8, 554.1, 109.4, 547.3, 110.8, 547.4, 111.5, +540.5, 112.3, 541.8, 112.1, 541.7, 111.2, 543.0, 110.6, 571.6, 99.2, +570.9, 97.4, 598.7, 84.3, 599.2, 84.1, 599.4, 84.6, 600.1, 84.9, +611.6, 89.7, 612.1, 88.8, 623.1, 94.6, 528.8, -39.2, 527.3, -47.3, +543.8, -57.6, 542.7, -58.6, 554.3, -47.9, 557.9, -30.8, 549.9, -19.7, +550.9, -21.1, 530.9, -27.9, 528.8, -39.2, 686.9, -7.4, 688.8, -8.6, +700.2, 0.9, 699.1, 3.6, 689.6, 2.0, 678.1, 20.5, 676.7, 19.0, +674.3, 18.8, 673.6, 20.2, 671.6, 22.5, 667.9, 36.8, 655.4, 33.6, +639.3, 44.6, 643.9, 42.0, 643.1, 40.5, 646.9, 36.3, 666.9, 14.4, +662.7, 7.7, 686.9, -7.4, 432.7, -43.8, 494.1, -60.9, 493.9, -61.6, +555.8, -76.8, 554.4, -76.4, 555.1, -74.3, 553.5, -73.6, 548.9, -71.4, +548.5, -72.3, 543.4, -71.1, 508.4, -62.5, 508.4, -62.5, 473.5, -53.9, +471.6, -53.4, 471.6, -53.4, 469.8, -53.0, 451.2, -48.4, 451.1, -48.9, +432.7, -43.8, 223.1, 199.1, 223.1, 199.1, 232.3, 166.6, 241.5, 134.0, +245.6, 119.3, 245.6, 119.3, 249.8, 104.6, 253.8, 90.4, 253.9, 90.4, +257.9, 76.1, 260.2, 67.8, 260.2, 67.8, 262.6, 59.6, 266.1, 47.2, +266.1, 47.2, 269.6, 34.9, 270.1, 33.1, 270.0, 33.1, 270.6, 31.2, +270.6, 31.2, 270.6, 31.2, 270.6, 31.1, 270.1, 33.0, 270.1, 33.0, +269.6, 34.9, 266.1, 47.2, 266.1, 47.2, 262.6, 59.6, 260.2, 67.8, +260.2, 67.8, 257.9, 76.1, 253.9, 90.4, 253.8, 90.4, 249.8, 104.6, +245.6, 119.3, 245.6, 119.3, 241.5, 134.0, 232.3, 166.6, 223.1, 199.1, +223.1, 199.1, 149.0, 461.3, 149.0, 461.3, 149.7, 458.6, 150.5, 455.9, +178.7, 356.3, 175.0, 355.1, 206.8, 256.7, 206.6, 257.2, 214.0, 259.0, +213.8, 260.1, 210.0, 283.9, 206.3, 283.4, 198.8, 306.6, 194.5, 320.1, +194.5, 320.1, 190.1, 333.6, 170.3, 394.7, 170.2, 394.7, 150.5, 455.9, +149.7, 458.6, 149.0, 461.3, 149.0, 461.3, 238.0, 140.7, 239.4, 137.2, +240.6, 137.6, 241.5, 134.0, 232.3, 166.6, 223.1, 199.1, 223.1, 199.1, +215.0, 227.9, 215.1, 227.9, 206.8, 256.7, 194.4, 299.9, 194.2, 299.8, +181.8, 343.0, 179.0, 352.7, 179.1, 352.8, 176.4, 362.5, 165.4, 402.3, +165.4, 402.3, 154.3, 442.2, 152.4, 449.0, 150.5, 455.9, 150.5, 455.9, +150.5, 455.9, 152.4, 449.0, 154.3, 442.2, 165.4, 402.3, 165.4, 402.3, +176.4, 362.5, 179.1, 352.8, 179.0, 352.7, 181.8, 343.0, 189.6, 315.0, +189.6, 315.0, 197.4, 286.9, 200.1, 277.3, 200.1, 277.3, 202.7, 267.7, +214.8, 224.2, 214.8, 224.2, 226.9, 180.6, 231.1, 165.6, 231.1, 165.6, +235.3, 150.5, 235.5, 149.5, 235.5, 149.5, 235.8, 148.5, 236.9, 144.6, +236.5, 144.5, 238.0, 140.7, 222.1, 121.8, 243.4, 80.9, 245.2, 81.7, +264.6, 39.9, 267.6, 35.6, 267.6, 35.6, 270.6, 31.2, 269.1, 45.7, +266.6, 45.4, 262.6, 59.6, 260.2, 67.8, 260.2, 67.8, 257.9, 76.1, +253.9, 90.4, 253.8, 90.4, 249.8, 104.6, 247.0, 109.7, 244.2, 108.1, +238.5, 111.6, 230.3, 116.7, 224.7, 114.7, 222.1, 121.8, 161.1, 239.4, +158.7, 243.9, 156.5, 248.6, 156.5, 248.6, 156.0, 249.5, 156.0, 249.5, +155.5, 250.4, 147.2, 266.5, 138.9, 282.6, 138.9, 282.6, 138.9, 282.6, +147.2, 266.5, 155.5, 250.4, 156.0, 249.5, 156.0, 249.5, 156.5, 248.6, +156.5, 248.6, 158.7, 243.9, 161.1, 239.4, 464.8, 585.3, 461.1, 544.5, +461.1, 544.5, 457.3, 503.6, 457.3, 502.5, 458.0, 502.4, 458.7, 501.2, +460.2, 498.5, 460.2, 498.5, 461.7, 495.7, 462.7, 493.9, 463.8, 493.9, +463.8, 492.1, 465.4, 538.7, 484.5, 550.0, 464.8, 585.3, 209.1, 647.2, +209.1, 646.8, 209.3, 646.8, 209.5, 646.5, 212.6, 641.2, 212.6, 641.2, +215.7, 636.0, 218.1, 631.9, 217.3, 628.6, 220.5, 627.8, 219.5, 628.1, +220.3, 631.4, 220.0, 634.9, 219.1, 648.1, 219.1, 648.1, 218.1, 661.3, +214.3, 713.1, 225.7, 716.7, 210.6, 764.9, 221.5, 730.2, 210.1, 726.6, +209.6, 688.4, 209.5, 676.0, 209.5, 676.0, 209.3, 663.7, 209.2, 655.4, +209.0, 655.4, 209.1, 647.2, 466.7, 814.3, 468.7, 848.1, 466.7, 848.4, +470.7, 882.0, 470.1, 884.5, 460.2, 884.2, 450.3, 882.5, 450.5, 882.6, +450.8, 880.6, 451.3, 878.7, 459.0, 846.5, 464.5, 813.9, 466.7, 814.3, +131.9, 102.5, 132.2, 103.4, 132.6, 103.2, 133.3, 103.9, 134.2, 104.8, +134.2, 104.8, 135.1, 105.7, 136.0, 106.7, 136.0, 106.7, 136.9, 107.6, +144.5, 115.4, 149.7, 114.0, 152.1, 123.1, 147.4, 125.8, 147.4, 125.8, +142.6, 128.4, 133.5, 119.1, 136.9, 115.6, 131.9, 102.5, 172.1, 171.1, +172.2, 172.5, 173.0, 173.1, 172.4, 174.0, 172.0, 175.3, 170.6, 175.3, +170.7, 176.4, 170.5, 173.8, 170.6, 173.2, 172.1, 171.1, 188.5, 778.9, +183.6, 784.8, 193.4, 790.8, 191.6, 801.6, 200.2, 807.9, 172.4, 831.7, +175.5, 859.3, 176.2, 858.1, 164.7, 854.8, 164.5, 849.8, 163.8, 836.8, +169.0, 836.5, 173.5, 823.2, 181.0, 801.1, 174.5, 795.6, 188.5, 778.9, +124.4, 697.1, 123.6, 699.9, 136.9, 701.5, 137.3, 706.8, 135.6, 765.0, +131.5, 765.1, 133.9, 823.2, 134.3, 819.7, 127.4, 820.2, 124.7, 815.1, +126.5, 809.3, 123.7, 808.3, 122.4, 801.6, 120.3, 788.4, 120.1, 788.5, +117.8, 775.3, 118.5, 736.2, 113.8, 734.1, 124.4, 697.1, 117.8, 775.3, +117.4, 773.4, 117.4, 773.4, 117.1, 771.4, 109.1, 725.5, 98.5, 724.9, +101.1, 679.7, 100.7, 686.7, 111.3, 687.3, 121.5, 694.9, 123.0, 696.0, +124.5, 696.1, 124.4, 697.1, 113.8, 734.1, 118.5, 736.2, 117.8, 775.3, +113.5, 633.8, 113.4, 625.4, 117.1, 625.4, 120.7, 617.0, 122.9, 611.8, +126.2, 611.0, 125.1, 606.5, 123.9, 649.3, 152.3, 658.4, 137.8, 692.5, +137.6, 699.6, 137.6, 699.6, 137.3, 706.8, 136.9, 701.5, 123.6, 699.9, +124.4, 697.1, 124.5, 696.1, 123.0, 696.0, 121.5, 694.9, 116.3, 664.6, +113.8, 664.4, 113.5, 633.8, 121.5, 694.9, 111.3, 687.3, 100.7, 686.7, +101.1, 679.7, 100.1, 673.7, 100.0, 673.7, 99.0, 667.8, 98.9, 666.1, +99.7, 666.1, 100.4, 664.5, 107.0, 649.1, 118.6, 641.1, 113.5, 633.8, +113.8, 664.4, 116.3, 664.6, 121.5, 694.9, 104.7, 601.1, 108.5, 585.7, +108.5, 585.7, 112.4, 570.4, 130.1, 523.1, 127.5, 522.1, 141.9, 473.6, +141.9, 494.5, 141.9, 494.5, 141.9, 515.4, 129.0, 559.9, 126.7, 560.0, +104.7, 601.1, 74.1, 373.8, 73.1, 372.4, 73.1, 372.4, 72.1, 371.0, +72.8, 344.1, 73.9, 344.1, 75.7, 317.2, 75.8, 314.6, 76.0, 314.7, +76.0, 312.1, 75.6, 328.2, 75.5, 328.2, 75.0, 344.2, 74.5, 359.0, +75.7, 359.1, 74.1, 373.8, 38.1, 251.5, 39.2, 217.8, 39.2, 217.8, +40.3, 184.2, 38.1, 193.9, 44.4, 195.3, 48.4, 206.4, 49.9, 210.5, +49.9, 210.5, 51.4, 214.6, 53.3, 220.0, 53.3, 220.0, 55.3, 225.4, +58.4, 225.5, 58.1, 233.2, 60.9, 240.9, 55.0, 249.8, 37.7, 250.5, +38.1, 251.5, 69.5, 488.4, 63.0, 456.5, 60.5, 456.8, 56.6, 424.6, +56.0, 421.4, 55.0, 421.2, 55.5, 418.2, 52.4, 400.5, 52.4, 400.5, +49.3, 382.8, 48.7, 379.6, 48.7, 379.6, 48.2, 376.4, 46.4, 366.3, +46.6, 366.3, 44.6, 356.3, 49.8, 382.7, 49.6, 382.7, 54.6, 409.2, +62.0, 448.8, 64.4, 448.5, 69.5, 488.4, 104.4, 482.2, 105.1, 470.7, +92.8, 469.9, 81.3, 457.6, 78.2, 454.3, 75.5, 454.7, 75.1, 451.0, +72.7, 430.8, 69.3, 428.3, 75.8, 409.9, 73.3, 416.9, 79.5, 419.1, +83.1, 428.3, 93.7, 455.2, 106.0, 456.0, 104.4, 482.2, 9.9, 492.8, +9.9, 497.9, 7.7, 499.0, 9.8, 503.0, 5.2, 499.5, 3.7, 500.5, +0.7, 495.9, -0.1, 494.8, -0.5, 495.0, -1.6, 494.1, -10.5, 465.3, +-13.6, 466.3, -25.5, 438.4, -20.0, 435.3, -28.1, 420.5, -30.6, 402.7, +-30.4, 406.9, -28.8, 406.8, -27.0, 410.9, -26.2, 412.5, -26.2, 412.5, +-25.5, 414.1, -7.8, 453.5, -6.0, 452.8, 9.9, 492.8, 23.2, 469.6, +23.2, 474.4, 22.2, 474.7, 23.2, 479.3, 16.9, 463.2, 22.3, 456.0, +10.6, 447.0, -2.7, 413.2, -2.5, 413.1, -15.8, 379.3, -17.1, 376.1, +-18.6, 372.9, -18.6, 372.9, -18.6, 372.9, -17.1, 376.1, -15.8, 379.3, +-10.6, 391.4, -10.6, 391.4, -5.3, 403.6, 8.9, 436.6, 10.5, 436.0, +23.2, 469.6, 16.7, 353.2, 16.8, 359.2, 14.8, 360.0, 16.8, 365.3, +9.7, 365.8, 1.8, 359.9, 1.7, 354.3, 1.7, 353.8, 12.1, 349.8, +16.7, 353.2, 26.7, 394.2, 27.9, 354.8, 27.4, 354.7, 29.1, 315.3, +29.9, 308.7, 29.9, 308.7, 30.7, 302.0, 29.3, 347.1, 28.7, 347.1, +26.8, 392.2, 26.7, 393.2, 26.7, 393.2, 26.7, 394.2, 51.0, 462.5, +48.9, 484.0, 40.6, 486.7, 46.7, 505.5, 39.6, 496.9, 38.9, 497.4, +32.4, 488.3, 31.2, 486.7, 30.0, 486.7, 30.0, 485.1, 29.1, 470.9, +29.1, 470.9, 28.1, 456.8, 34.9, 416.1, 36.8, 416.2, 48.2, 376.4, +48.7, 379.6, 48.7, 379.6, 49.3, 382.8, 50.6, 422.6, 51.9, 422.7, +51.0, 462.5, 49.3, 382.8, 52.4, 400.5, 52.4, 400.5, 55.5, 418.2, +52.2, 440.2, 53.2, 440.3, 51.0, 462.5, 51.9, 422.7, 50.6, 422.6, +49.3, 382.8, 43.3, 684.7, 30.8, 668.9, 32.9, 655.3, 18.3, 653.0, +14.0, 646.2, 10.3, 640.7, 13.1, 637.2, 17.9, 641.9, 21.0, 638.8, +28.8, 640.3, 40.9, 659.4, 51.2, 675.0, 43.3, 684.7, 713.3, 489.1, +712.7, 488.6, 713.1, 488.1, 713.0, 487.0, 713.6, 472.0, 710.3, 471.8, +707.6, 456.6, 726.2, 469.7, 719.9, 478.6, 732.3, 500.6, 732.8, 501.5, +732.5, 501.9, 733.3, 502.3, 728.0, 499.4, 728.2, 499.0, 723.2, 495.6, +718.2, 492.3, 717.8, 492.9, 713.3, 489.1, 752.2, 518.9, 756.0, 528.8, +751.3, 539.8, 754.8, 540.6, 745.8, 538.6, 748.0, 528.5, 741.2, 516.5, +739.2, 512.8, 736.7, 509.4, 737.1, 509.1, 738.4, 508.1, 740.9, 511.5, +744.7, 514.0, 748.4, 516.4, 750.9, 515.5, 752.2, 518.9, 839.3, 624.0, +867.6, 630.5, 867.6, 630.8, 895.8, 637.6, 900.4, 638.7, 903.8, 641.2, +904.9, 639.8, 891.5, 650.5, 891.5, 650.5, 878.0, 661.2, 856.0, 656.1, +859.1, 643.0, 840.1, 624.8, 839.7, 624.4, 839.8, 624.1, 839.3, 624.0, +835.3, 566.8, 835.3, 566.8, 836.0, 567.4, 836.7, 568.0, 857.1, 585.8, +857.1, 585.8, 877.5, 603.6, 892.3, 616.5, 892.3, 616.5, 907.1, 629.4, +907.1, 629.8, 907.7, 629.7, 907.8, 630.0, 910.0, 632.0, 912.3, 632.1, +912.2, 633.9, 909.8, 635.8, 909.8, 635.8, 907.5, 637.7, 884.6, 619.5, +886.4, 617.2, 865.4, 596.6, 865.0, 596.2, 865.1, 596.1, 864.8, 595.8, +852.2, 583.3, 852.1, 583.4, 839.5, 570.9, 838.1, 569.5, 838.2, 569.5, +836.7, 568.0, 836.0, 567.4, 835.3, 566.8, 835.3, 566.8, 845.9, 561.2, +855.0, 547.1, 858.7, 547.4, 874.5, 539.8, 876.3, 539.0, 881.2, 544.2, +881.1, 544.3, 877.6, 549.8, 874.2, 547.6, 867.3, 550.9, 856.6, 556.1, +851.4, 552.7, 845.9, 561.2, 819.2, 520.3, 819.5, 519.3, 820.2, 518.7, +819.7, 518.2, 817.7, 516.8, 825.6, 507.8, 823.0, 504.7, 839.9, 508.5, +838.4, 515.2, 853.8, 525.7, 864.1, 532.8, 875.5, 535.3, 874.5, 539.8, +858.7, 547.4, 855.0, 547.1, 845.9, 561.2, 842.7, 563.6, 839.5, 565.7, +839.6, 565.9, 826.2, 545.2, 828.8, 543.4, 819.2, 520.3, 839.6, 565.9, +839.8, 566.4, 838.3, 567.7, 836.7, 568.0, 836.0, 567.4, 835.3, 566.8, +835.3, 566.8, 824.6, 557.5, 824.6, 557.5, 813.9, 548.1, 813.3, 547.6, +812.6, 547.5, 812.7, 547.1, 814.9, 535.3, 815.5, 535.4, 818.4, 523.8, +819.5, 522.9, 818.8, 522.1, 819.2, 520.3, 828.8, 543.4, 826.2, 545.2, +839.6, 565.9, 906.6, 622.8, 904.8, 612.1, 903.9, 612.2, 903.1, 601.5, +900.4, 583.4, 900.5, 583.4, 897.9, 565.3, 897.9, 565.1, 897.9, 565.1, +897.9, 564.9, 899.5, 575.6, 899.5, 575.6, 901.1, 586.3, 903.8, 604.5, +904.2, 604.5, 906.6, 622.8, 597.3, 353.4, 614.7, 388.9, 604.2, 402.0, +632.1, 424.4, 634.1, 450.4, 634.1, 450.4, 636.1, 476.4, 636.0, 474.9, +635.6, 474.9, 635.2, 473.4, 630.7, 459.4, 630.7, 459.4, 626.3, 445.3, +611.8, 399.4, 586.5, 392.3, 597.3, 353.4, 690.4, 580.0, 687.8, 583.4, +684.6, 584.2, 685.3, 586.9, 684.2, 587.1, 681.3, 582.6, 682.0, 581.7, +683.9, 579.2, 689.6, 578.7, 690.4, 580.0, 911.3, 564.9, 903.7, 560.0, +903.9, 559.8, 896.4, 554.7, 894.9, 553.7, 894.4, 554.0, 893.3, 552.6, +892.7, 551.8, 893.2, 551.5, 893.0, 550.3, 892.0, 543.8, 892.0, 543.8, +891.0, 537.3, 890.9, 536.6, 891.2, 536.4, 890.9, 536.0, 895.6, 542.1, +895.3, 542.3, 899.8, 548.7, 905.1, 556.1, 905.1, 556.1, 910.3, 563.5, +910.4, 563.6, 910.4, 563.6, 910.5, 563.7, 910.9, 564.3, 910.8, 564.5, +911.3, 564.9, 881.4, 472.9, 881.6, 434.2, 875.4, 434.2, 869.9, 395.5, +869.9, 395.5, 869.9, 393.4, 869.9, 391.2, 876.0, 432.0, 881.6, 432.1, +881.4, 472.9, 921.6, 407.7, 923.8, 415.2, 923.8, 415.2, 926.0, 422.7, +938.8, 442.6, 928.9, 449.0, 931.8, 475.4, 930.9, 463.2, 930.0, 463.3, +928.2, 451.2, 924.9, 429.4, 923.3, 429.6, 921.6, 407.7, 903.7, 346.4, +908.9, 364.0, 920.2, 370.0, 914.0, 381.7, 914.0, 382.1, 914.0, 382.4, +914.3, 382.6, 916.1, 382.5, 916.7, 390.9, 919.1, 399.2, 917.7, 404.6, +913.4, 403.5, 907.7, 407.8, 901.1, 412.8, 896.0, 419.1, 894.4, 417.8, +884.3, 409.7, 889.3, 403.4, 884.2, 389.0, 883.6, 387.4, 882.6, 387.0, +883.1, 385.9, 892.3, 365.7, 890.9, 348.1, 903.7, 346.4, 842.4, 342.0, +835.8, 345.6, 835.8, 345.6, 829.3, 349.3, 794.5, 342.5, 790.2, 357.7, +752.8, 370.9, 776.8, 355.0, 776.8, 355.0, 800.7, 339.1, 819.2, 333.1, +823.5, 335.2, 842.4, 342.0, 800.7, 339.1, 825.7, 322.5, 823.3, 315.5, +850.7, 305.9, 851.2, 305.7, 851.6, 305.3, 851.6, 305.3, 853.8, 304.2, +856.0, 302.9, 856.1, 303.1, 853.5, 305.6, 856.6, 309.4, 858.0, 315.5, +857.8, 323.7, 859.2, 323.7, 860.4, 331.9, 852.6, 330.4, 851.4, 336.9, +842.4, 342.0, 823.5, 335.2, 819.2, 333.1, 800.7, 339.1, 847.6, 351.2, +855.0, 348.4, 858.9, 351.0, 862.4, 345.6, 862.8, 348.1, 862.8, 348.1, +863.2, 350.6, 856.3, 353.2, 847.8, 352.0, 847.6, 351.2, 765.4, 446.9, +783.7, 457.2, 781.5, 461.2, 797.5, 475.5, 815.2, 491.3, 815.2, 491.3, +832.8, 507.0, 837.8, 511.5, 837.8, 511.5, 842.9, 516.0, 848.3, 520.8, +847.5, 522.2, 853.8, 525.7, 838.4, 515.2, 839.9, 508.5, 823.0, 504.7, +809.3, 488.9, 785.4, 487.8, 787.2, 480.4, 767.8, 463.2, 767.8, 459.9, +744.0, 451.0, 728.2, 440.2, 728.2, 440.2, 712.4, 429.4, 706.9, 425.7, +706.9, 425.7, 701.5, 422.0, 700.7, 419.7, 698.9, 420.3, 696.4, 418.5, +731.1, 432.1, 733.1, 428.7, 765.4, 446.9, 696.4, 418.5, 692.6, 416.0, +692.6, 416.0, 688.8, 413.4, 690.9, 414.1, 693.6, 408.7, 694.7, 409.5, +695.3, 409.6, 695.5, 409.0, 696.2, 408.5, 702.9, 402.3, 705.4, 405.0, +714.5, 401.6, 743.6, 417.7, 763.2, 449.1, 765.4, 446.9, 733.1, 428.7, +731.1, 432.1, 696.4, 418.5, 493.2, 122.4, 496.6, 123.8, 497.6, 121.5, +502.0, 120.5, 507.0, 119.4, 507.6, 117.2, 512.1, 118.4, 515.0, 119.1, +517.6, 122.8, 516.9, 124.3, 516.4, 125.4, 513.3, 124.0, 509.6, 123.7, +501.4, 123.1, 500.4, 125.4, 493.2, 122.4, 600.5, 240.3, 575.0, 209.0, +581.3, 186.8, 549.5, 177.8, 540.1, 159.5, 541.2, 158.9, 530.8, 141.2, +553.1, 149.7, 548.2, 162.6, 565.6, 183.9, 571.2, 189.2, 570.5, 189.8, +575.4, 195.8, 588.8, 217.5, 581.6, 227.2, 600.5, 240.3, 575.4, 195.8, +604.4, 231.3, 601.5, 234.1, 633.4, 266.7, 639.4, 274.1, 639.4, 274.1, +645.4, 281.4, 659.5, 298.6, 659.5, 298.6, 673.5, 315.8, 673.6, 315.8, +673.6, 315.8, 673.6, 315.9, 685.1, 330.0, 687.0, 328.8, 696.7, 344.0, +692.1, 336.9, 690.2, 338.1, 683.8, 332.1, 667.6, 314.8, 666.4, 315.9, +649.0, 299.7, 637.5, 265.7, 624.8, 270.0, 600.5, 240.3, 581.6, 227.2, +588.8, 217.5, 575.4, 195.8, 903.1, 280.6, 895.2, 284.4, 895.2, 284.4, +887.3, 288.2, 883.2, 288.4, 883.0, 285.2, 878.8, 282.3, 854.6, 265.6, +854.6, 265.6, 830.4, 249.0, 825.3, 245.5, 825.3, 245.5, 820.2, 241.9, +794.8, 224.5, 794.8, 224.5, 769.5, 207.0, 768.4, 206.2, 768.4, 206.2, +767.2, 205.4, 760.5, 200.8, 761.2, 199.3, 753.8, 196.2, 766.9, 201.7, +766.2, 203.2, 778.7, 210.2, 792.9, 218.3, 792.9, 218.3, 807.2, 226.4, +812.6, 229.4, 812.6, 229.4, 817.9, 232.4, 842.6, 246.4, 842.6, 246.4, +867.2, 260.3, 875.7, 265.1, 875.7, 265.1, 884.2, 269.9, 892.2, 274.4, +892.2, 274.4, 900.1, 278.9, 901.6, 279.7, 902.5, 281.0, 903.1, 280.6, +517.7, 117.1, 520.7, 121.1, 529.1, 114.7, 540.5, 112.3, 547.4, 111.5, +547.3, 110.8, 554.1, 109.4, 555.5, 109.5, 555.2, 111.7, 556.4, 114.1, +567.2, 135.5, 567.2, 135.5, 578.0, 156.8, 579.1, 158.9, 579.1, 158.9, +580.1, 161.0, 582.9, 166.5, 581.2, 168.9, 585.7, 172.0, 550.0, 147.0, +543.3, 151.0, 517.7, 117.1, 599.6, 253.8, 603.6, 257.5, 603.6, 257.5, +607.6, 261.2, 639.4, 295.1, 640.0, 294.7, 674.0, 326.3, 671.5, 323.8, +670.3, 325.0, 667.7, 322.6, 653.1, 308.9, 653.6, 308.4, 639.5, 294.1, +619.6, 274.0, 619.4, 274.2, 599.6, 253.8, 701.4, 377.5, 684.8, 385.5, +684.8, 385.5, 668.1, 393.5, 665.9, 393.6, 665.6, 386.2, 663.1, 378.8, +655.2, 355.4, 654.4, 331.7, 647.2, 331.9, 673.6, 331.1, 691.7, 348.8, +701.4, 377.5, 439.9, 203.6, 440.2, 203.0, 439.1, 202.4, 438.3, 201.1, +437.8, 193.7, 427.2, 190.5, 429.1, 186.9, 422.4, 176.3, 422.4, 176.3, +415.7, 165.8, 412.5, 160.9, 412.5, 160.9, 409.4, 156.0, 409.6, 155.6, +408.9, 154.9, 408.1, 154.0, 404.3, 148.1, 400.6, 148.2, 400.6, 142.2, +404.3, 142.2, 404.3, 141.4, 408.0, 140.6, 430.6, 159.3, 436.6, 157.6, +449.3, 182.6, 452.6, 189.1, 445.7, 193.8, 439.9, 203.6, 600.1, 84.9, +599.4, 84.6, 599.2, 84.1, 598.7, 84.3, 616.0, 76.2, 619.2, 79.9, +633.3, 68.0, 674.9, 71.6, 691.3, 60.0, 720.8, 26.7, 723.0, 27.1, +724.0, 26.2, 725.3, 27.5, 726.3, 27.9, 726.7, 29.3, 727.1, 29.1, +715.7, 35.3, 715.2, 34.3, 703.4, 39.5, 701.1, 40.5, 701.1, 40.5, +698.9, 41.5, 662.7, 57.4, 662.7, 57.4, 626.5, 73.3, 613.3, 79.1, +613.5, 79.6, 600.1, 84.9, 557.4, 100.7, 550.2, 105.6, 550.9, 107.4, +543.0, 110.6, 541.7, 111.2, 541.8, 112.1, 540.5, 112.3, 529.1, 114.7, +520.7, 121.1, 517.7, 117.1, 514.9, 117.8, 514.9, 117.8, 512.1, 118.4, +507.6, 117.2, 507.0, 119.4, 502.0, 120.5, 503.0, 121.8, 506.6, 118.9, +511.2, 117.2, 534.3, 109.0, 533.6, 105.7, 557.4, 100.7, 387.3, 116.0, +362.5, 54.7, 365.8, 53.1, 337.7, -6.6, 335.7, -12.3, 336.3, -17.9, +333.7, -18.1, 341.8, -20.2, 341.8, -20.2, 349.8, -22.3, 351.7, -22.3, +352.8, -20.5, 353.5, -18.0, 364.2, 19.6, 363.0, 19.9, 372.6, 57.9, +374.7, 66.1, 374.7, 66.1, 376.8, 74.3, 379.0, 83.0, 379.0, 83.0, +381.2, 91.7, 383.3, 100.2, 383.3, 100.2, 385.5, 108.7, 386.4, 112.4, +385.9, 112.6, 387.3, 116.0, 428.6, -42.8, 428.6, -42.8, 430.6, -43.3, +432.7, -43.8, 451.1, -48.9, 451.2, -48.4, 469.8, -53.0, 451.2, -48.4, +451.1, -48.9, 432.7, -43.8, 430.6, -43.3, 428.6, -42.8, 428.6, -42.8, +215.0, 260.7, 214.8, 260.9, 214.4, 260.4, 213.8, 260.1, 214.0, 259.0, +206.6, 257.2, 206.8, 256.7, 215.1, 227.9, 215.0, 227.9, 223.1, 199.1, +223.1, 199.1, 232.3, 166.6, 241.5, 134.0, 245.6, 119.3, 245.6, 119.3, +249.8, 104.6, 253.8, 90.4, 253.9, 90.4, 257.9, 76.1, 257.0, 79.3, +257.2, 79.3, 256.4, 82.5, 248.0, 118.7, 248.0, 118.7, 239.6, 154.9, +232.4, 185.6, 232.4, 185.6, 225.3, 216.3, 225.1, 217.0, 225.1, 217.0, +225.0, 217.7, 220.2, 238.1, 220.2, 238.1, 215.5, 258.6, 215.2, 259.7, +215.6, 260.1, 215.0, 260.7, 142.3, 443.2, 142.0, 441.3, 141.8, 441.3, +141.8, 439.5, 136.9, 394.0, 135.5, 394.1, 129.3, 348.8, 129.9, 332.1, +133.8, 320.3, 146.4, 316.0, 141.9, 317.5, 146.0, 329.6, 145.6, 343.2, +143.9, 393.2, 144.3, 393.2, 142.3, 443.2, 192.0, 145.4, 196.4, 139.0, +200.1, 132.2, 200.8, 132.6, 202.0, 132.5, 202.9, 131.1, 202.9, 129.5, +229.0, 115.3, 223.0, 102.9, 240.6, 74.8, 246.6, 67.8, 245.9, 67.1, +251.1, 59.5, 244.4, 70.9, 245.2, 71.4, 239.2, 83.3, 236.4, 88.2, +235.7, 87.8, 232.3, 92.4, 212.1, 118.9, 212.5, 119.2, 192.0, 145.4, +470.3, 647.3, 471.5, 660.3, 471.7, 660.3, 472.9, 673.2, 473.3, 677.4, +473.3, 677.4, 473.7, 681.5, 473.9, 684.3, 474.0, 684.3, 474.2, 687.1, +474.9, 695.0, 474.8, 695.0, 475.5, 702.9, 468.6, 699.9, 471.3, 693.5, +467.1, 684.1, 466.6, 682.9, 466.6, 682.9, 466.1, 681.7, 464.4, 678.0, +464.4, 678.0, 462.8, 674.3, 461.2, 670.9, 460.0, 671.0, 459.7, 667.4, +454.0, 587.3, 454.4, 587.2, 448.3, 507.2, 447.9, 501.2, 448.0, 501.2, +447.6, 495.3, 446.7, 480.6, 448.0, 480.4, 445.8, 465.9, 459.4, 556.4, +458.5, 556.6, 470.3, 647.3, 445.8, 465.9, 444.2, 452.7, 445.1, 452.6, +444.3, 439.3, 443.4, 424.6, 443.4, 424.6, 442.5, 409.9, 442.2, 404.5, +442.2, 404.5, 441.8, 399.1, 440.9, 383.7, 440.9, 383.7, 440.0, 368.4, +440.0, 367.4, 440.0, 367.4, 439.9, 366.4, 436.0, 301.4, 432.8, 301.4, +432.1, 236.3, 432.5, 271.5, 435.8, 271.5, 439.3, 306.7, 441.3, 329.1, +441.3, 329.1, 443.4, 351.4, 443.9, 357.8, 443.9, 357.8, 444.5, 364.1, +444.8, 366.7, 444.8, 366.7, 445.0, 369.4, 446.9, 389.4, 446.9, 389.4, +448.7, 409.5, 452.1, 447.0, 452.1, 447.0, 455.6, 484.5, 456.5, 494.1, +456.5, 494.1, 457.3, 503.6, 461.1, 544.5, 461.1, 544.5, 464.8, 585.3, +466.5, 603.5, 466.6, 603.5, 468.2, 621.6, 469.3, 634.5, 469.2, 634.5, +470.3, 647.3, 458.5, 556.6, 459.4, 556.4, 445.8, 465.9, 465.1, 743.6, +462.4, 705.5, 462.4, 705.5, 459.7, 667.4, 460.0, 671.0, 461.2, 670.9, +462.8, 674.3, 463.8, 680.1, 463.0, 680.2, 463.2, 686.2, 464.1, 714.9, +459.9, 715.7, 465.1, 743.6, 519.2, 392.8, 519.8, 404.6, 512.4, 405.1, +505.5, 417.3, 505.6, 417.1, 505.4, 417.0, 505.5, 416.9, 512.2, 404.8, +519.7, 404.5, 519.2, 392.8, 210.2, 770.6, 213.3, 782.9, 209.2, 783.9, +208.2, 797.2, 205.3, 838.2, 215.2, 875.8, 202.3, 879.2, 197.0, 840.4, +213.6, 817.8, 191.6, 801.6, 193.4, 790.8, 183.6, 784.8, 188.5, 778.9, +187.3, 770.3, 187.3, 770.3, 186.1, 761.7, 185.4, 756.6, 185.4, 756.6, +184.7, 751.5, 184.6, 751.1, 184.7, 751.0, 184.6, 750.6, 192.1, 756.1, +191.9, 756.3, 199.2, 762.1, 204.7, 766.3, 208.8, 765.3, 210.2, 770.6, +156.0, 542.8, 153.2, 522.1, 153.2, 522.1, 150.3, 501.5, 169.4, 477.1, +168.7, 476.5, 187.1, 451.5, 174.1, 457.5, 180.4, 471.0, 173.8, 490.6, +173.3, 491.8, 173.3, 491.8, 172.9, 493.1, 172.9, 493.2, 172.9, 493.2, +172.8, 493.4, 170.6, 500.0, 170.6, 500.0, 168.3, 506.7, 165.8, 514.0, +165.8, 514.0, 163.3, 521.4, 159.6, 532.1, 152.2, 536.9, 156.0, 542.8, +224.3, 529.2, 225.0, 523.0, 227.6, 517.0, 228.5, 517.2, 229.2, 517.3, +228.1, 523.5, 227.6, 529.8, 227.1, 537.3, 227.1, 537.3, 226.5, 544.9, +223.5, 586.4, 225.4, 586.6, 220.5, 627.8, 217.3, 628.6, 218.1, 631.9, +215.7, 636.0, 217.8, 582.5, 218.6, 582.4, 224.3, 529.2, 348.9, 883.3, +337.1, 885.5, 330.9, 889.1, 324.4, 882.9, 320.9, 879.5, 326.7, 873.5, +329.0, 864.1, 329.5, 862.2, 329.5, 862.2, 329.9, 860.4, 336.9, 831.8, +354.5, 813.4, 343.8, 803.1, 363.8, 822.4, 346.2, 840.7, 348.6, 878.3, +348.7, 880.8, 349.2, 883.2, 348.9, 883.3, 415.7, 165.8, 422.4, 176.3, +422.4, 176.3, 429.1, 186.9, 423.5, 197.5, 429.9, 201.0, 430.8, 215.1, +431.2, 225.7, 431.1, 225.7, 432.1, 236.3, 432.8, 301.4, 436.0, 301.4, +439.9, 366.4, 439.3, 344.4, 437.2, 344.4, 434.6, 322.4, 429.7, 281.8, +429.7, 281.8, 424.8, 241.2, 422.1, 218.7, 422.1, 218.7, 419.4, 196.3, +417.8, 183.6, 417.8, 183.6, 416.3, 171.0, 416.0, 168.4, 417.1, 167.5, +415.7, 165.8, 101.2, 144.6, 99.2, 144.7, 92.1, 120.2, 94.7, 97.2, +103.9, 91.9, 101.6, 87.9, 108.5, 78.6, 110.8, 77.7, 113.0, 83.2, +117.6, 87.9, 121.3, 91.7, 125.8, 93.0, 125.1, 95.6, 117.7, 121.4, +114.4, 143.8, 101.2, 144.6, 125.1, 95.6, 124.6, 96.2, 129.7, 98.4, +131.9, 102.5, 136.9, 115.6, 133.5, 119.1, 142.6, 128.4, 137.9, 130.9, +134.7, 129.7, 133.2, 133.5, 117.6, 142.0, 118.6, 144.8, 102.0, 150.6, +102.6, 150.4, 100.2, 147.0, 101.2, 144.6, 114.4, 143.8, 117.7, 121.4, +125.1, 95.6, 117.6, 87.9, 113.0, 83.2, 110.8, 77.7, 108.5, 78.6, +120.5, 62.4, 130.6, 63.5, 132.6, 46.2, 136.3, 47.5, 137.3, 46.4, +140.0, 48.9, 141.8, 49.5, 141.8, 49.5, 143.5, 50.2, 158.4, 55.7, +158.7, 55.1, 173.3, 61.2, 173.1, 61.1, 172.9, 61.9, 172.3, 62.2, +145.1, 75.3, 146.4, 80.5, 117.6, 87.9, 172.3, 62.2, 164.6, 64.4, +165.9, 69.1, 159.4, 76.0, 146.4, 90.0, 147.1, 90.7, 133.3, 103.9, +132.6, 103.2, 132.2, 103.4, 131.9, 102.5, 129.7, 98.4, 124.6, 96.2, +125.1, 95.6, 125.8, 93.0, 121.3, 91.7, 117.6, 87.9, 146.4, 80.5, +145.1, 75.3, 172.3, 62.2, 135.1, 105.7, 134.2, 104.8, 134.2, 104.8, +133.3, 103.9, 147.1, 90.7, 146.4, 90.0, 159.4, 76.0, 160.9, 77.5, +148.2, 91.7, 135.1, 105.7, 143.5, 50.2, 141.8, 49.5, 141.8, 49.5, +140.0, 48.9, 132.1, 41.6, 132.0, 40.2, 122.0, 36.6, 158.4, 27.2, +158.4, 27.2, 194.7, 17.8, 195.2, 17.7, 195.2, 17.7, 195.7, 17.5, +195.6, 18.0, 195.1, 17.9, 194.6, 18.2, 169.0, 34.2, 169.7, 35.4, +143.5, 50.2, 210.8, 66.8, 207.8, 66.4, 207.8, 66.4, 204.7, 66.0, +205.6, 39.5, 199.5, 33.8, 212.6, 13.1, 227.9, 9.2, 227.9, 9.2, +243.2, 5.2, 235.9, 15.3, 241.7, 19.5, 240.1, 33.8, 230.1, 52.8, +227.1, 52.1, 210.8, 66.8, 240.1, 33.8, 239.6, 38.3, 241.4, 39.6, +239.1, 42.7, 234.1, 55.0, 237.6, 56.4, 236.1, 70.1, 225.0, 65.1, +223.5, 68.4, 210.8, 66.8, 227.1, 52.1, 230.1, 52.8, 240.1, 33.8, +169.9, 145.9, 171.0, 158.5, 171.0, 158.5, 172.1, 171.1, 170.6, 173.2, +170.5, 173.8, 170.7, 176.4, 169.6, 178.8, 169.5, 178.8, 167.7, 180.7, +135.3, 199.1, 139.8, 207.9, 113.9, 236.9, 114.0, 236.7, 113.7, 236.5, +113.8, 236.3, 141.7, 191.0, 135.0, 185.0, 169.9, 145.9, 142.6, 822.9, +142.5, 811.8, 142.5, 811.8, 142.5, 800.7, 139.1, 739.4, 143.1, 739.2, +143.6, 677.7, 143.1, 739.2, 139.1, 739.4, 142.5, 800.7, 142.5, 811.8, +142.5, 811.8, 142.6, 822.9, 100.4, 664.5, 99.7, 666.1, 98.9, 666.1, +99.0, 667.8, 96.8, 655.3, 96.8, 655.3, 94.7, 642.9, 94.4, 641.6, +94.8, 641.5, 95.0, 640.0, 94.9, 629.7, 97.5, 629.7, 100.1, 619.4, +104.9, 640.9, 100.9, 641.9, 100.4, 664.5, 107.3, 369.1, 122.8, 412.0, +109.9, 423.8, 138.4, 454.9, 138.8, 458.8, 138.1, 459.0, 139.2, 462.7, +139.3, 461.7, 138.0, 461.7, 137.6, 460.5, 133.2, 448.6, 133.6, 448.4, +129.6, 436.3, 118.4, 402.7, 122.3, 400.9, 107.3, 369.1, 38.1, 318.9, +37.1, 313.2, 37.1, 313.2, 36.1, 307.5, 41.0, 287.6, 38.8, 286.4, +37.6, 265.6, 36.7, 258.7, 37.8, 258.5, 38.1, 251.5, 37.7, 250.5, +55.0, 249.8, 60.9, 240.9, 64.0, 249.4, 64.0, 249.4, 67.0, 257.9, +67.4, 260.4, 65.7, 260.7, 64.4, 263.4, 62.8, 266.8, 62.8, 266.8, +61.2, 270.1, 49.7, 294.5, 53.0, 296.7, 38.1, 318.9, 75.3, 375.5, +75.1, 375.7, 76.4, 376.3, 76.5, 377.0, 76.7, 393.4, 76.1, 393.5, +75.8, 409.9, 69.3, 428.3, 72.7, 430.8, 75.1, 451.0, 74.5, 479.7, +74.5, 479.7, 74.0, 508.4, 74.0, 509.4, 73.7, 509.4, 73.9, 510.3, +72.6, 499.3, 71.7, 499.4, 69.5, 488.4, 64.4, 448.5, 62.0, 448.8, +54.6, 409.2, 55.5, 391.8, 64.2, 391.8, 75.3, 375.5, 54.6, 409.2, +49.6, 382.7, 49.8, 382.7, 44.6, 356.3, 44.4, 354.9, 44.9, 354.0, +44.2, 353.6, 59.7, 362.8, 59.2, 363.6, 74.1, 373.8, 74.2, 373.9, +74.1, 374.0, 74.3, 374.1, 74.8, 374.8, 75.5, 375.2, 75.3, 375.5, +64.2, 391.8, 55.5, 391.8, 54.6, 409.2, 124.4, 503.4, 112.1, 498.8, +111.2, 494.5, 104.4, 482.2, 106.0, 456.0, 93.7, 455.2, 83.1, 428.3, +106.5, 437.0, 99.0, 457.2, 114.9, 486.1, 119.6, 494.7, 117.4, 500.8, +124.4, 503.4, 81.3, 457.6, 92.8, 469.9, 105.1, 470.7, 104.4, 482.2, +111.2, 494.5, 112.1, 498.8, 124.4, 503.4, 124.6, 503.6, 124.8, 503.8, +124.8, 503.8, 118.5, 510.7, 114.8, 518.5, 111.8, 517.1, 102.1, 512.9, +105.6, 505.0, 99.3, 492.8, 90.3, 475.2, 76.1, 468.4, 81.3, 457.6, +96.7, 598.9, 93.4, 608.1, 90.6, 608.0, 90.2, 617.3, 87.2, 600.2, +88.1, 600.0, 84.2, 583.1, 83.7, 575.4, 82.9, 575.5, 81.6, 567.8, +92.0, 581.1, 93.8, 582.6, 96.7, 598.9, 10.2, 469.4, 10.1, 481.1, +10.1, 481.1, 9.9, 492.8, -6.0, 452.8, -7.8, 453.5, -25.5, 414.1, +-25.9, 441.5, -3.1, 439.7, 10.2, 469.4, 22.9, 401.7, 23.1, 435.6, +23.1, 435.6, 23.2, 469.6, 10.5, 436.0, 8.9, 436.6, -5.3, 403.6, +-5.3, 402.7, 21.1, 397.3, 22.9, 401.7, 16.6, 341.0, 16.6, 347.1, +16.6, 347.1, 16.7, 353.2, 12.1, 349.8, 1.7, 353.8, 1.7, 354.3, +-2.9, 353.3, -5.9, 347.4, -6.7, 348.2, 1.5, 340.8, 6.2, 338.8, +16.6, 341.0, 41.7, 339.3, 42.9, 346.4, 40.0, 349.1, 44.2, 353.6, +44.9, 354.0, 44.4, 354.9, 44.6, 356.3, 46.6, 366.3, 46.4, 366.3, +48.2, 376.4, 36.8, 416.2, 34.9, 416.1, 28.1, 456.8, 27.0, 439.3, +27.0, 439.3, 25.8, 421.8, 20.2, 411.2, 26.2, 408.0, 26.7, 394.2, +26.7, 393.2, 26.7, 393.2, 26.8, 392.2, 34.0, 365.7, 30.5, 364.1, +41.7, 339.3, 26.8, 392.2, 28.7, 347.1, 29.3, 347.1, 30.7, 302.0, +30.7, 301.8, 30.7, 301.8, 30.7, 301.5, 32.8, 313.5, 34.8, 313.2, +39.1, 324.7, 39.4, 325.6, 39.3, 325.6, 39.5, 326.5, 43.2, 329.6, +40.6, 332.9, 41.7, 339.3, 30.5, 364.1, 34.0, 365.7, 26.8, 392.2, +55.9, 700.7, 49.6, 692.7, 49.6, 692.7, 43.3, 684.7, 51.2, 675.0, +40.9, 659.4, 28.8, 640.3, 35.6, 641.6, 35.6, 641.6, 42.5, 643.0, +49.8, 654.0, 45.7, 656.7, 48.9, 670.5, 49.3, 672.3, 49.3, 672.3, +49.7, 674.1, 52.8, 687.4, 61.0, 692.4, 55.9, 700.7, 782.5, 583.1, +784.1, 591.8, 781.5, 601.4, 777.5, 602.0, 768.9, 594.4, 768.9, 594.4, +760.4, 586.8, 759.7, 586.2, 760.7, 585.0, 760.1, 584.4, 759.3, 578.0, +759.3, 578.0, 758.5, 571.7, 756.7, 556.1, 756.7, 556.1, 754.8, 540.6, +751.3, 539.8, 756.0, 528.8, 752.2, 518.9, 751.4, 512.5, 751.4, 512.5, +750.7, 506.1, 750.4, 503.8, 751.0, 503.5, 750.1, 501.5, 758.6, 521.0, +758.0, 521.3, 765.8, 541.1, 774.1, 562.1, 778.3, 561.3, 782.5, 583.1, +797.6, 609.5, 797.4, 609.5, 797.2, 611.1, 796.8, 612.7, 796.7, 613.2, +796.7, 613.2, 796.5, 613.7, 796.0, 615.9, 795.4, 618.0, 795.5, 618.0, +792.8, 613.9, 791.7, 614.6, 787.9, 611.3, 788.4, 609.3, 793.0, 608.8, +797.6, 609.5, 741.2, 516.5, 748.0, 528.5, 745.8, 538.6, 754.8, 540.6, +756.7, 556.1, 756.7, 556.1, 758.5, 571.7, 744.7, 547.0, 744.6, 544.7, +741.2, 516.5, 712.4, 429.4, 728.2, 440.2, 728.2, 440.2, 744.0, 451.0, +747.0, 452.1, 744.9, 457.9, 745.7, 464.8, 726.1, 451.4, 714.7, 448.8, +712.4, 429.4, 790.4, 654.6, 788.9, 653.1, 787.0, 652.4, 787.3, 651.6, +788.2, 647.9, 787.8, 644.4, 789.1, 644.2, 795.2, 639.9, 791.5, 634.7, +793.8, 625.1, 795.5, 639.4, 793.9, 640.3, 790.4, 654.6, 864.8, 595.8, +886.2, 616.7, 887.3, 615.6, 907.5, 637.7, 906.2, 638.7, 906.2, 638.7, +904.9, 639.8, 903.8, 641.2, 900.4, 638.7, 895.8, 637.6, 878.7, 618.8, +880.6, 617.1, 865.4, 596.6, 865.0, 596.2, 865.1, 596.1, 864.8, 595.8, +867.3, 550.9, 874.2, 547.6, 877.6, 549.8, 881.1, 544.3, 882.5, 544.0, +882.9, 545.5, 884.7, 546.7, 889.0, 549.7, 889.0, 549.7, 893.3, 552.6, +894.4, 554.0, 894.9, 553.7, 896.4, 554.7, 898.2, 559.5, 897.2, 559.8, +897.9, 564.9, 897.9, 565.1, 897.9, 565.1, 897.9, 565.3, 887.3, 560.5, +887.4, 560.3, 876.8, 555.4, 872.1, 553.1, 867.2, 551.2, 867.3, 550.9, +944.3, 587.3, 944.5, 587.5, 944.7, 587.5, 944.7, 587.6, 944.5, 594.2, +941.1, 599.0, 944.0, 600.9, 941.0, 598.8, 944.0, 594.1, 944.3, 587.3, +699.3, 568.1, 694.8, 574.1, 694.8, 574.1, 690.4, 580.0, 689.6, 578.7, +683.9, 579.2, 682.0, 581.7, 676.7, 578.5, 678.1, 576.1, 674.6, 570.2, +674.6, 570.3, 674.8, 570.2, 675.1, 570.2, 678.1, 569.9, 678.1, 569.9, +681.0, 569.7, 683.3, 569.5, 683.3, 569.5, 685.5, 569.3, 689.4, 569.0, +689.4, 569.0, 693.3, 568.6, 696.3, 568.4, 699.0, 569.1, 699.3, 568.1, +902.2, 454.4, 901.6, 452.4, 906.3, 450.0, 905.6, 449.0, 911.4, 456.8, +909.0, 458.6, 912.4, 468.1, 913.8, 472.2, 916.2, 472.8, 915.3, 476.2, +915.9, 473.9, 913.5, 473.3, 911.8, 470.4, 907.0, 462.4, 904.7, 463.1, +902.2, 454.4, 904.5, 446.0, 904.0, 446.7, 905.9, 447.7, 905.6, 449.0, +906.3, 450.0, 901.6, 452.4, 902.2, 454.4, 895.7, 464.8, 895.7, 464.8, +889.2, 475.3, 886.7, 479.4, 886.2, 479.1, 884.2, 483.4, 888.4, 474.4, +888.9, 474.6, 893.7, 465.8, 899.1, 455.9, 898.0, 455.1, 904.5, 446.0, +928.2, 451.2, 930.0, 463.3, 930.9, 463.2, 931.8, 475.4, 932.5, 482.0, +932.5, 482.0, 933.3, 488.7, 930.5, 470.0, 930.2, 470.0, 928.2, 451.2, +903.2, 344.7, 903.5, 345.5, 903.5, 345.5, 903.7, 346.4, 890.9, 348.1, +892.3, 365.7, 883.1, 385.9, 878.4, 386.3, 876.6, 367.7, 870.1, 349.6, +868.2, 335.8, 865.3, 336.2, 860.5, 322.8, 870.9, 319.1, 869.6, 315.5, +878.7, 308.3, 895.8, 317.0, 891.2, 326.3, 903.2, 344.7, 878.7, 308.3, +884.3, 303.7, 887.6, 305.1, 890.0, 299.2, 896.6, 321.9, 896.6, 321.9, +903.2, 344.7, 891.2, 326.3, 895.8, 317.0, 878.7, 308.3, 881.9, 476.0, +884.0, 479.6, 882.6, 480.5, 883.2, 484.9, 883.7, 488.2, 882.5, 489.1, +884.2, 491.5, 852.8, 448.7, 850.1, 450.0, 823.9, 404.0, 822.2, 402.7, +825.8, 398.3, 827.8, 392.5, 836.4, 396.3, 833.9, 401.9, 840.0, 411.3, +860.9, 443.7, 862.4, 442.8, 881.9, 476.0, 818.3, 452.4, 792.2, 417.7, +787.3, 419.8, 768.3, 381.2, 774.6, 378.8, 775.0, 379.5, 781.0, 376.4, +782.5, 375.6, 782.6, 375.8, 784.2, 375.2, 788.2, 380.2, 786.9, 381.2, +789.5, 387.2, 790.0, 388.3, 790.0, 388.3, 790.5, 389.3, 801.8, 415.0, +801.8, 415.0, 813.2, 440.7, 815.7, 446.5, 814.6, 447.4, 818.3, 452.4, +466.5, 128.1, 478.5, 122.4, 479.7, 123.8, 493.2, 122.4, 500.4, 125.4, +501.4, 123.1, 509.6, 123.7, 499.2, 128.7, 497.4, 124.9, 485.3, 126.2, +475.9, 127.1, 474.5, 124.3, 466.5, 128.1, 585.0, 128.1, 613.5, 142.1, +613.5, 142.1, 641.9, 156.2, 676.6, 173.2, 676.6, 173.2, 711.3, 190.3, +757.7, 213.1, 757.7, 213.1, 804.0, 236.0, 817.2, 242.5, 818.0, 241.3, +830.4, 249.0, 854.6, 265.6, 854.6, 265.6, 878.8, 282.3, 875.3, 279.8, +874.9, 280.3, 871.1, 278.3, 836.2, 260.0, 836.2, 260.0, 801.3, 241.7, +762.4, 221.2, 762.4, 221.2, 723.5, 200.8, 706.2, 191.7, 706.2, 191.7, +689.0, 182.7, 673.1, 174.3, 673.1, 174.3, 657.2, 166.0, 632.0, 152.8, +632.0, 152.8, 606.8, 139.6, 596.9, 134.4, 596.9, 134.4, 587.0, 129.2, +586.0, 128.7, 586.0, 128.6, 585.0, 128.1, 641.9, 156.2, 613.0, 150.9, +614.5, 142.7, 587.0, 129.2, 586.0, 128.7, 586.0, 128.6, 585.0, 128.1, +580.8, 126.0, 580.8, 126.0, 576.5, 124.0, 566.5, 119.0, 565.8, 120.1, +556.4, 114.1, 555.2, 111.7, 555.5, 109.5, 554.1, 109.4, 561.4, 107.8, +561.4, 107.8, 568.7, 106.2, 569.6, 106.1, 569.7, 106.9, 570.7, 107.6, +589.3, 120.3, 589.3, 120.3, 607.9, 133.0, 624.9, 144.6, 623.4, 152.8, +641.9, 156.2, 590.7, 210.4, 578.2, 197.1, 578.8, 196.4, 565.6, 183.9, +548.2, 162.6, 553.1, 149.7, 530.8, 141.2, 526.6, 134.1, 522.8, 135.7, +520.2, 128.3, 518.5, 126.3, 518.5, 126.3, 516.9, 124.3, 517.6, 122.8, +515.0, 119.1, 512.1, 118.4, 514.9, 117.8, 514.9, 117.8, 517.7, 117.1, +543.3, 151.0, 550.0, 147.0, 585.7, 172.0, 592.1, 178.0, 592.9, 180.0, +594.1, 188.7, 595.5, 199.2, 590.6, 210.4, 590.7, 210.4, 594.1, 188.7, +611.0, 203.2, 605.0, 210.3, 615.8, 231.9, 618.6, 237.3, 617.0, 239.1, +621.3, 242.7, 607.9, 225.1, 606.0, 226.5, 590.7, 210.4, 590.6, 210.4, +595.5, 199.2, 594.1, 188.7, 639.5, 294.1, 653.6, 308.4, 653.1, 308.9, +667.7, 322.6, 668.5, 315.8, 652.9, 313.9, 638.2, 305.2, 631.6, 301.3, +631.6, 301.3, 625.1, 297.5, 617.2, 292.8, 617.2, 292.8, 609.4, 288.2, +606.9, 286.8, 606.9, 286.8, 604.4, 285.3, 563.4, 261.1, 563.4, 261.1, +522.4, 236.9, 515.1, 232.6, 515.4, 231.9, 507.7, 228.3, 542.5, 244.8, +542.1, 245.5, 576.5, 262.7, 583.2, 266.0, 583.2, 266.0, 589.9, 269.3, +614.7, 281.7, 616.9, 278.6, 639.5, 294.1, 645.5, 326.8, 643.2, 325.5, +644.4, 323.5, 643.3, 320.2, 640.7, 312.7, 641.4, 305.5, 638.2, 305.2, +652.9, 313.9, 668.5, 315.8, 667.7, 322.6, 670.3, 325.0, 671.5, 323.8, +674.0, 326.3, 678.1, 330.1, 680.1, 328.1, 683.8, 332.1, 690.2, 338.1, +692.1, 336.9, 696.7, 344.0, 707.9, 354.5, 705.9, 360.5, 719.2, 365.0, +680.3, 351.9, 681.2, 347.8, 645.5, 326.8, 719.2, 365.0, 720.8, 365.9, +721.7, 367.9, 722.0, 367.6, 711.7, 372.6, 711.7, 372.6, 701.4, 377.5, +691.7, 348.8, 673.6, 331.1, 647.2, 331.9, 645.5, 330.3, 647.2, 327.6, +645.5, 326.8, 681.2, 347.8, 680.3, 351.9, 719.2, 365.0, 557.8, 293.0, +554.0, 281.8, 548.5, 283.7, 539.3, 274.3, 538.9, 273.8, 538.9, 273.7, +538.5, 273.3, 507.0, 241.3, 500.5, 245.8, 475.5, 209.3, 485.1, 223.3, +491.6, 218.8, 507.7, 228.3, 515.4, 231.9, 515.1, 232.6, 522.4, 236.9, +528.3, 242.6, 526.9, 244.1, 531.4, 251.2, 544.6, 272.1, 550.1, 270.2, +557.8, 293.0, 642.2, 378.7, 633.8, 370.2, 634.8, 368.9, 625.4, 361.6, +617.9, 362.6, 616.6, 352.7, 607.8, 343.7, 603.3, 334.3, 607.1, 332.5, +606.5, 321.3, 605.9, 310.6, 602.1, 301.3, 605.3, 300.0, 605.8, 299.8, +609.5, 309.1, 613.8, 318.3, 628.0, 348.5, 633.7, 347.0, 642.2, 378.7, +539.3, 274.3, 568.9, 309.5, 571.0, 308.0, 598.4, 345.0, 592.2, 341.2, +592.2, 341.2, 586.0, 337.3, 562.7, 309.6, 564.4, 308.2, 542.8, 279.0, +542.2, 278.3, 542.2, 278.2, 541.6, 277.4, 540.5, 275.8, 540.5, 275.8, +539.3, 274.3, 752.7, 51.9, 761.8, 53.9, 768.8, 63.8, 769.2, 63.4, +761.8, 72.8, 753.9, 66.6, 738.7, 69.9, 734.5, 70.8, 731.7, 69.2, +730.2, 71.7, 735.2, 63.3, 738.0, 64.9, 745.7, 58.1, 749.2, 55.0, +750.0, 51.3, 752.7, 51.9, 646.9, 36.3, 643.1, 40.5, 643.9, 42.0, +639.3, 44.6, 605.0, 68.1, 605.0, 68.1, 570.6, 91.6, 571.5, 91.2, +568.6, 86.9, 569.6, 86.2, 606.8, 59.2, 607.4, 59.9, 646.9, 36.3, +570.6, -20.1, 571.5, -18.3, 569.8, -17.4, 568.9, -14.7, 563.3, 3.6, +558.4, 22.2, 557.7, 22.0, 548.9, 19.7, 553.8, 1.1, 549.9, -19.7, +557.9, -30.8, 554.3, -47.9, 542.7, -58.6, 542.5, -60.0, 545.4, -61.3, +545.1, -61.8, 559.4, -42.1, 559.6, -41.9, 570.6, -20.1, 545.1, -61.8, +544.5, -62.9, 546.5, -63.9, 548.0, -65.9, 548.5, -66.6, 548.5, -66.6, +549.1, -67.4, 551.3, -70.5, 551.3, -70.5, 553.5, -73.6, 555.1, -74.3, +554.4, -76.4, 555.8, -76.8, 573.0, -82.6, 573.8, -87.4, 590.9, -86.2, +589.5, -86.3, 589.1, -80.4, 587.3, -74.6, 582.2, -57.8, 582.2, -57.8, +577.0, -41.0, 573.8, -30.5, 568.1, -21.8, 570.6, -20.1, 559.6, -41.9, +559.4, -42.1, 545.1, -61.8, 372.6, 57.9, 363.0, 19.9, 364.2, 19.6, +353.5, -18.0, 364.4, -22.7, 397.1, 8.3, 406.0, 43.4, 406.7, 46.2, +376.1, 61.9, 372.6, 57.9, 413.0, -8.1, 406.0, -8.8, 406.1, -14.5, +400.1, -21.7, 400.6, -21.2, 401.0, -21.6, 402.0, -21.5, 407.8, -20.9, +407.8, -20.9, 413.6, -20.3, 432.0, -18.4, 432.0, -18.4, 450.5, -16.5, +460.8, -15.4, 461.5, -12.2, 471.0, -14.3, 442.7, -8.0, 441.4, -5.2, +413.0, -8.1, 376.9, -24.1, 383.0, -17.7, 390.0, -26.2, 400.1, -21.7, +406.1, -14.5, 406.0, -8.8, 413.0, -8.1, 426.1, 5.7, 426.1, 5.7, +439.2, 19.5, 452.4, 33.4, 452.6, 33.3, 465.6, 47.3, 464.7, 46.3, +464.5, 46.4, 463.4, 45.6, 462.7, 45.0, 462.7, 45.0, 462.0, 44.4, +419.5, 10.2, 413.9, 15.4, 376.9, -24.1, 543.4, -71.1, 548.5, -72.3, +548.9, -71.4, 553.5, -73.6, 551.3, -70.5, 551.3, -70.5, 549.1, -67.4, +546.8, -66.8, 543.5, -71.2, 543.4, -71.1, 198.8, 306.6, 206.3, 283.4, +210.0, 283.9, 213.8, 260.1, 214.4, 260.4, 214.8, 260.9, 215.0, 260.7, +220.4, 263.4, 226.1, 264.6, 225.8, 266.0, 222.7, 280.5, 217.0, 279.3, +208.2, 292.5, 203.5, 299.5, 200.1, 299.0, 198.8, 306.6, 147.1, 478.3, +146.6, 474.8, 146.6, 474.8, 146.2, 471.3, 146.7, 466.2, 147.4, 466.2, +149.0, 461.3, 169.4, 397.4, 166.0, 396.1, 190.1, 333.6, 191.7, 329.4, +197.8, 326.4, 200.5, 328.0, 201.3, 328.4, 198.8, 332.8, 197.1, 337.6, +193.8, 346.9, 193.8, 346.9, 190.4, 356.3, 186.4, 367.7, 186.4, 367.7, +182.4, 379.0, 167.7, 420.4, 167.8, 420.5, 153.1, 461.8, 153.0, 462.3, +152.8, 462.2, 152.7, 462.6, 150.9, 467.6, 150.9, 467.6, 149.2, 472.6, +148.1, 475.5, 146.9, 478.2, 147.1, 478.3, 154.3, 442.2, 152.4, 449.0, +150.5, 455.9, 150.5, 455.9, 149.7, 458.6, 149.0, 461.3, 149.0, 461.3, +147.4, 466.2, 146.7, 466.2, 146.2, 471.3, 144.2, 457.2, 144.2, 457.2, +142.3, 443.2, 144.3, 393.2, 143.9, 393.2, 145.6, 343.2, 145.5, 345.7, +145.8, 345.7, 146.0, 348.1, 147.8, 368.2, 147.8, 368.2, 149.5, 388.3, +149.9, 392.5, 149.9, 392.5, 150.3, 396.7, 152.3, 419.4, 154.2, 419.4, +154.3, 442.2, 179.6, 252.5, 179.3, 254.6, 178.6, 254.5, 177.5, 256.5, +176.7, 258.1, 176.2, 259.8, 175.9, 259.7, 165.2, 256.7, 165.2, 255.9, +155.5, 250.4, 156.0, 249.5, 156.0, 249.5, 156.5, 248.6, 168.7, 225.0, +162.9, 207.3, 180.9, 201.5, 174.6, 203.5, 180.4, 221.2, 179.9, 241.0, +179.8, 246.7, 180.5, 246.8, 179.6, 252.5, 158.1, 293.8, 157.1, 294.1, +157.4, 294.9, 156.8, 296.1, 151.6, 306.0, 151.6, 306.0, 146.4, 316.0, +133.8, 320.3, 129.9, 332.1, 129.3, 348.8, 126.7, 329.9, 126.7, 329.9, +124.1, 311.0, 124.0, 309.1, 124.5, 307.9, 126.2, 307.0, 141.5, 299.2, +141.8, 299.5, 158.1, 293.8, 126.2, 307.0, 128.3, 307.6, 131.2, 297.3, +136.3, 287.5, 137.6, 285.0, 137.6, 285.0, 138.9, 282.6, 138.9, 282.6, +147.2, 266.5, 155.5, 250.4, 165.2, 255.9, 165.2, 256.7, 175.9, 259.7, +178.1, 263.9, 172.0, 267.1, 168.1, 274.5, 163.1, 284.1, 165.8, 287.7, +158.1, 293.8, 141.8, 299.5, 141.5, 299.2, 126.2, 307.0, 136.3, 287.5, +131.2, 297.3, 128.3, 307.6, 126.2, 307.0, 124.5, 307.9, 124.0, 309.1, +124.1, 311.0, 121.5, 292.0, 120.5, 292.1, 118.9, 272.9, 118.7, 271.9, +118.7, 271.9, 118.6, 270.9, 117.5, 263.1, 114.0, 261.7, 116.4, 255.3, +129.2, 247.8, 136.6, 240.3, 134.9, 228.4, 137.5, 226.5, 136.8, 225.6, +138.8, 222.8, 141.1, 225.7, 138.6, 227.7, 138.4, 232.7, 137.5, 255.7, +137.5, 255.7, 136.6, 278.7, 136.5, 283.1, 137.7, 283.6, 136.3, 287.5, +467.1, 684.1, 471.3, 693.5, 468.6, 699.9, 475.5, 702.9, 476.7, 715.9, +476.8, 715.9, 478.0, 728.9, 480.1, 750.5, 480.0, 750.5, 482.0, 772.1, +482.3, 775.1, 482.3, 775.1, 482.5, 778.1, 483.9, 793.3, 485.3, 808.6, +485.3, 808.6, 486.4, 819.9, 486.4, 819.9, 487.4, 831.1, 488.3, 840.2, +487.8, 840.3, 489.1, 849.3, 483.2, 808.5, 483.6, 808.5, 478.2, 767.6, +477.9, 765.3, 477.9, 765.2, 477.6, 762.9, 474.2, 737.2, 474.2, 737.2, +470.8, 711.5, 469.0, 697.8, 461.8, 693.8, 467.1, 684.1, 537.5, 359.8, +537.4, 359.8, 528.4, 376.3, 519.2, 392.8, 519.7, 404.5, 512.2, 404.8, +505.5, 416.9, 507.3, 414.7, 505.3, 413.0, 505.1, 409.1, 504.5, 396.8, +498.4, 392.8, 503.9, 384.4, 514.7, 368.1, 529.8, 355.6, 537.5, 359.8, +503.9, 384.4, 505.6, 383.9, 503.6, 377.8, 503.3, 371.1, 503.1, 368.1, +503.1, 368.1, 503.0, 365.1, 501.6, 337.8, 501.6, 337.8, 500.3, 310.6, +500.0, 303.7, 503.1, 301.2, 499.6, 296.9, 519.1, 327.4, 519.1, 327.4, +538.6, 357.9, 538.9, 358.3, 538.4, 359.2, 537.5, 359.8, 529.8, 355.6, +514.7, 368.1, 503.9, 384.4, 481.0, 448.9, 480.0, 450.8, 484.4, 452.5, +484.1, 455.6, 483.6, 460.0, 481.8, 459.8, 479.4, 464.0, 471.6, 478.1, +471.6, 478.1, 463.8, 492.1, 463.8, 493.9, 462.7, 493.9, 461.7, 495.7, +471.1, 472.2, 468.8, 470.9, 481.0, 448.9, 505.1, 409.1, 505.3, 413.0, +507.3, 414.7, 505.5, 416.9, 505.4, 417.0, 505.6, 417.1, 505.5, 417.3, +495.2, 435.9, 495.2, 435.8, 484.8, 454.4, 484.4, 455.0, 483.9, 455.4, +484.1, 455.6, 484.4, 452.5, 480.0, 450.8, 481.0, 448.9, 480.5, 447.8, +480.5, 447.8, 480.0, 446.7, 467.1, 418.0, 463.1, 419.2, 454.1, 389.4, +455.0, 392.5, 459.0, 391.3, 463.9, 393.2, 484.5, 401.1, 486.1, 398.3, +505.1, 409.1, 180.9, 723.4, 179.3, 711.9, 179.3, 711.9, 177.7, 700.4, +188.2, 671.9, 189.3, 670.2, 209.1, 647.2, 209.0, 655.4, 209.2, 655.4, +209.3, 663.7, 208.7, 667.8, 207.4, 667.6, 205.6, 671.5, 199.2, 685.0, +199.2, 685.0, 192.8, 698.4, 186.8, 710.9, 188.3, 722.5, 180.9, 723.4, +157.5, 553.7, 156.8, 548.2, 156.8, 548.2, 156.0, 542.8, 152.2, 536.9, +159.6, 532.1, 163.3, 521.4, 165.9, 522.6, 161.2, 532.8, 159.2, 544.2, +158.4, 549.0, 156.4, 553.2, 157.5, 553.7, 209.5, 646.5, 209.3, 646.8, +209.1, 646.8, 209.1, 647.2, 189.3, 670.2, 188.2, 671.9, 177.7, 700.4, +176.4, 690.9, 177.5, 690.6, 175.1, 681.5, 173.8, 677.2, 174.5, 677.0, +173.9, 672.6, 177.4, 657.8, 178.9, 658.2, 184.0, 643.8, 187.0, 635.3, +187.0, 635.3, 189.9, 626.9, 194.9, 612.9, 204.3, 603.4, 199.8, 598.9, +214.1, 613.2, 204.9, 622.6, 209.5, 646.5, 199.8, 598.9, 204.3, 563.1, +235.1, 554.2, 224.3, 529.2, 218.6, 582.4, 217.8, 582.5, 215.7, 636.0, +212.6, 641.2, 212.6, 641.2, 209.5, 646.5, 204.9, 622.6, 214.1, 613.2, +199.8, 598.9, 464.9, 784.3, 465.8, 799.3, 465.8, 799.3, 466.7, 814.3, +464.5, 813.9, 459.0, 846.5, 451.3, 878.7, 452.4, 874.2, 451.9, 874.1, +452.6, 869.4, 453.3, 865.0, 453.3, 865.0, 453.9, 860.5, 457.1, 838.5, +457.1, 838.5, 460.2, 816.6, 462.5, 801.0, 462.5, 801.0, 464.7, 785.5, +464.8, 784.9, 464.9, 784.9, 464.9, 784.3, 387.9, 282.3, 363.9, 266.8, +367.7, 256.8, 355.0, 227.9, 354.1, 225.8, 357.9, 224.1, 360.7, 220.3, +361.3, 219.5, 361.3, 219.5, 361.9, 218.8, 364.7, 215.0, 364.7, 215.0, +367.6, 211.2, 372.2, 205.9, 371.9, 205.6, 376.1, 199.9, 376.0, 199.9, +376.8, 204.7, 377.5, 209.4, 377.6, 210.3, 377.6, 210.3, 377.8, 211.3, +380.0, 227.2, 380.0, 227.2, 382.3, 243.1, 382.5, 244.4, 382.5, 244.4, +382.7, 245.8, 385.3, 264.0, 377.8, 275.8, 387.9, 282.3, 136.9, 107.6, +136.0, 106.7, 136.0, 106.7, 135.1, 105.7, 148.2, 91.7, 160.9, 77.5, +159.4, 76.0, 165.9, 69.1, 164.6, 64.4, 172.3, 62.2, 172.9, 61.9, +173.1, 61.1, 173.3, 61.2, 174.9, 61.2, 174.9, 61.8, 176.5, 62.4, +178.2, 59.9, 187.3, 66.3, 198.1, 70.3, 196.4, 70.1, 195.9, 73.5, +193.8, 76.7, 166.2, 93.6, 165.9, 93.3, 136.9, 107.6, 193.8, 76.7, +181.1, 95.5, 173.7, 93.6, 168.4, 114.3, 160.3, 118.7, 160.3, 118.7, +152.1, 123.1, 149.7, 114.0, 144.5, 115.4, 136.9, 107.6, 165.9, 93.3, +166.2, 93.6, 193.8, 76.7, 194.6, 18.2, 195.1, 17.9, 195.6, 18.0, +195.7, 17.5, 204.2, 15.3, 204.2, 15.3, 212.6, 13.1, 199.5, 33.8, +205.6, 39.5, 204.7, 66.0, 203.1, 65.8, 203.1, 65.8, 201.4, 65.6, +196.5, 42.2, 197.4, 42.0, 194.6, 18.2, 201.4, 65.6, 189.0, 64.0, +179.9, 57.6, 176.5, 62.4, 174.9, 61.8, 174.9, 61.2, 173.3, 61.2, +158.7, 55.1, 158.4, 55.7, 143.5, 50.2, 169.7, 35.4, 169.0, 34.2, +194.6, 18.2, 197.4, 42.0, 196.5, 42.2, 201.4, 65.6, 169.5, 141.3, +169.7, 143.6, 169.7, 143.6, 169.9, 145.9, 135.0, 185.0, 141.7, 191.0, +113.8, 236.3, 122.6, 230.0, 103.4, 212.0, 107.5, 190.5, 109.2, 182.0, +116.5, 183.4, 125.4, 176.3, 147.5, 158.8, 146.3, 157.1, 169.5, 141.3, +157.8, 679.7, 171.7, 714.9, 171.3, 715.1, 184.6, 750.6, 184.7, 751.0, +184.6, 751.1, 184.7, 751.5, 185.4, 756.6, 185.4, 756.6, 186.1, 761.7, +175.0, 733.1, 176.1, 732.7, 166.1, 703.6, 162.0, 691.7, 162.5, 691.5, +157.8, 679.7, 120.7, 617.0, 117.1, 625.4, 113.4, 625.4, 113.5, 633.8, +118.6, 641.1, 107.0, 649.1, 100.4, 664.5, 100.9, 641.9, 104.9, 640.9, +100.1, 619.4, 102.4, 610.2, 102.4, 610.2, 104.7, 601.1, 126.7, 560.0, +129.0, 559.9, 141.9, 515.4, 141.9, 517.7, 141.9, 517.7, 141.9, 520.0, +131.8, 568.6, 132.7, 568.8, 120.7, 617.0, 141.9, 520.0, 142.0, 543.5, +142.0, 543.5, 142.0, 567.0, 142.1, 567.7, 141.4, 567.7, 141.4, 568.5, +144.0, 585.9, 125.7, 587.3, 125.1, 606.5, 126.2, 611.0, 122.9, 611.8, +120.7, 617.0, 132.7, 568.8, 131.8, 568.6, 141.9, 520.0, 69.2, 152.0, +67.3, 142.3, 67.1, 140.6, 70.8, 131.7, 69.4, 135.0, 72.3, 136.2, +73.9, 140.7, 79.7, 157.5, 83.2, 157.1, 85.5, 174.4, 84.6, 167.9, +81.1, 168.4, 76.7, 162.3, 73.0, 157.2, 70.3, 157.7, 69.2, 152.0, +67.4, 174.6, 67.4, 174.8, 67.4, 174.8, 67.4, 175.0, 67.2, 178.0, +67.2, 178.0, 66.9, 181.0, 64.6, 210.9, 69.8, 212.3, 62.3, 240.9, +58.8, 233.2, 59.1, 225.6, 55.3, 225.4, 53.3, 220.0, 53.3, 220.0, +51.4, 214.6, 54.3, 199.5, 57.2, 200.1, 63.0, 185.6, 63.0, 185.5, +63.0, 185.5, 63.0, 185.5, 65.2, 180.0, 65.2, 180.0, 67.4, 174.6, +55.5, 87.2, 51.3, 86.0, 53.0, 79.9, 50.5, 72.6, 49.1, 68.4, +49.1, 68.4, 47.6, 64.1, 47.2, 62.9, 46.6, 62.8, 46.8, 61.7, +47.1, 58.6, 46.5, 57.3, 48.5, 55.6, 51.1, 57.0, 52.5, 54.8, +56.4, 53.5, 71.2, 48.0, 71.7, 49.5, 87.1, 45.6, 87.3, 45.5, +87.3, 45.5, 87.6, 45.5, 84.6, 48.1, 88.5, 52.6, 89.5, 59.8, +88.8, 71.2, 92.0, 76.9, 85.1, 82.4, 75.0, 90.6, 68.6, 90.9, +55.5, 87.2, 85.1, 82.4, 93.5, 106.7, 82.1, 112.3, 73.9, 140.7, +72.3, 136.2, 69.4, 135.0, 70.8, 131.7, 65.7, 116.8, 65.7, 116.8, +60.6, 101.9, 58.2, 95.1, 58.2, 95.1, 55.9, 88.2, 55.7, 87.7, +55.6, 87.2, 55.5, 87.2, 68.6, 90.9, 75.0, 90.6, 85.1, 82.4, +93.3, 87.3, 94.0, 92.2, 96.3, 96.3, 94.7, 97.2, 92.1, 120.2, +99.2, 144.7, 101.2, 144.6, 100.2, 147.0, 102.6, 150.4, 102.0, 150.6, +104.8, 170.5, 104.8, 170.5, 107.5, 190.5, 103.4, 212.0, 122.6, 230.0, +113.8, 236.3, 113.7, 236.5, 114.0, 236.7, 113.9, 236.9, 113.1, 237.7, +114.8, 240.2, 114.4, 240.4, 111.2, 244.9, 118.9, 253.8, 116.4, 255.3, +114.0, 261.7, 117.5, 263.1, 118.6, 270.9, 119.2, 266.7, 117.0, 266.4, +115.5, 261.9, 104.1, 228.6, 97.0, 229.5, 92.6, 195.2, 85.9, 142.1, +92.2, 141.2, 93.3, 87.3, 92.6, 195.2, 92.7, 191.9, 91.4, 191.9, +90.3, 188.5, 87.9, 181.5, 87.9, 181.5, 85.5, 174.4, 83.2, 157.1, +79.7, 157.5, 73.9, 140.7, 82.1, 112.3, 93.5, 106.7, 85.1, 82.4, +92.0, 76.9, 88.8, 71.2, 89.5, 59.8, 91.4, 73.5, 91.4, 73.5, +93.3, 87.3, 92.2, 141.2, 85.9, 142.1, 92.6, 195.2, 75.0, 344.2, +75.5, 328.2, 75.6, 328.2, 76.0, 312.1, 76.6, 299.7, 83.2, 291.6, +77.7, 287.3, 84.3, 305.5, 84.3, 305.5, 90.8, 323.7, 90.3, 334.3, +75.0, 344.2, 75.0, 344.2, 75.7, 317.2, 73.9, 344.1, 72.8, 344.1, +72.1, 371.0, 66.5, 363.4, 66.5, 363.4, 60.9, 355.8, 62.3, 336.1, +82.3, 326.3, 75.7, 317.2, 114.9, 486.1, 99.0, 457.2, 106.5, 437.0, +83.1, 428.3, 79.5, 419.1, 73.3, 416.9, 75.8, 409.9, 76.1, 393.5, +76.7, 393.4, 76.5, 377.0, 75.7, 380.0, 79.3, 381.0, 82.2, 384.9, +82.6, 385.4, 82.7, 385.3, 82.9, 385.9, 88.9, 404.1, 88.8, 404.2, +94.6, 422.5, 104.7, 454.3, 119.4, 483.8, 114.9, 486.1, 74.0, 508.4, +74.5, 479.7, 74.5, 479.7, 75.1, 451.0, 75.5, 454.7, 78.2, 454.3, +81.3, 457.6, 76.1, 468.4, 90.3, 475.2, 99.3, 492.8, 97.9, 502.2, +73.8, 508.0, 74.0, 508.4, 99.3, 492.8, 105.6, 505.0, 102.1, 512.9, +111.8, 517.1, 106.8, 534.3, 97.8, 531.6, 83.8, 546.1, 81.2, 548.7, +81.6, 549.3, 78.7, 551.4, 78.6, 550.6, 78.8, 550.4, 78.4, 549.9, +76.2, 547.2, 79.2, 544.8, 77.0, 541.9, 71.5, 538.3, 75.4, 532.3, +73.7, 522.7, 72.5, 516.8, 74.7, 516.4, 73.9, 510.3, 73.7, 509.4, +74.0, 509.4, 74.0, 508.4, 73.8, 508.0, 97.9, 502.2, 99.3, 492.8, +115.1, 546.9, 107.5, 568.2, 104.7, 567.6, 100.0, 589.5, 99.8, 594.3, +98.3, 594.2, 96.7, 598.9, 93.8, 582.6, 92.0, 581.1, 81.6, 567.8, +80.6, 562.5, 82.9, 560.1, 79.7, 557.1, 78.0, 556.0, 79.2, 554.2, +78.7, 551.4, 81.6, 549.3, 81.2, 548.7, 83.8, 546.1, 99.1, 544.2, +113.0, 541.4, 115.1, 546.9, 83.8, 546.1, 97.8, 531.6, 106.8, 534.3, +111.8, 517.1, 114.8, 518.5, 118.5, 510.7, 124.8, 503.8, 125.4, 503.4, +128.5, 505.7, 128.8, 508.0, 127.4, 512.0, 127.1, 511.9, 126.0, 515.9, +124.2, 531.8, 120.5, 531.4, 115.1, 546.9, 113.0, 541.4, 99.1, 544.2, +83.8, 546.1, -27.0, 410.9, -28.8, 406.8, -30.4, 406.9, -30.6, 402.7, +-32.6, 389.3, -29.2, 377.4, -34.5, 375.9, -34.7, 373.3, -32.7, 373.0, +-33.2, 370.6, -29.2, 388.7, -30.4, 389.0, -27.5, 407.4, -27.2, 409.2, +-27.8, 409.6, -27.0, 410.9, -22.3, 363.3, -25.0, 355.2, -24.5, 355.0, +-27.6, 347.1, -27.8, 346.5, -27.1, 346.3, -27.3, 345.7, -24.5, 354.4, +-20.5, 355.6, -22.3, 363.3, 2.2, 282.6, 9.2, 297.5, 18.3, 298.8, +16.3, 312.3, 16.4, 326.7, 16.4, 326.7, 16.6, 341.0, 6.2, 338.8, +1.5, 340.8, -6.7, 348.2, -16.5, 346.7, -15.9, 341.8, -24.8, 335.0, +-24.8, 335.0, -24.7, 334.8, -24.7, 334.6, -23.4, 329.3, -23.3, 329.4, +-22.1, 324.1, -11.1, 302.8, -14.7, 287.8, 2.2, 282.6, -22.1, 324.1, +-32.6, 302.0, -22.3, 289.0, -7.1, 263.0, -6.8, 272.9, -2.5, 272.8, +2.2, 282.6, -14.7, 287.8, -11.1, 302.8, -22.1, 324.1, 48.9, 670.5, +45.7, 656.7, 49.8, 654.0, 42.5, 643.0, 47.9, 644.1, 53.2, 643.6, +53.4, 645.1, 59.0, 650.8, 62.8, 647.0, 72.2, 648.9, 70.0, 661.3, +58.1, 672.3, 48.9, 670.5, 749.0, 492.6, 747.0, 491.5, 749.8, 485.2, +748.1, 484.6, 762.9, 499.3, 767.1, 495.1, 786.1, 505.6, 785.1, 497.0, +766.0, 502.0, 749.0, 492.6, 804.0, 583.1, 804.0, 596.3, 804.0, 598.2, +797.6, 609.5, 793.0, 608.8, 788.4, 609.3, 787.9, 611.3, 783.2, 607.1, +780.2, 601.8, 778.4, 602.8, 778.5, 602.6, 778.0, 602.4, 777.5, 602.0, +781.5, 601.4, 784.1, 591.8, 782.5, 583.1, 787.8, 562.4, 787.8, 562.4, +793.2, 541.7, 795.3, 533.5, 799.3, 532.4, 797.4, 525.2, 804.7, 553.1, +803.9, 554.2, 804.0, 583.1, 797.4, 525.2, 797.1, 519.5, 798.1, 513.8, +800.5, 513.5, 808.6, 518.0, 809.9, 516.5, 816.7, 522.4, 817.5, 523.1, +818.2, 523.9, 818.4, 523.8, 815.5, 535.4, 814.9, 535.3, 812.7, 547.1, +810.7, 555.2, 810.7, 555.2, 808.8, 563.4, 806.4, 573.2, 801.5, 574.7, +804.0, 583.1, 803.9, 554.2, 804.7, 553.1, 797.4, 525.2, 713.5, 490.2, +713.2, 490.0, 713.6, 489.3, 713.3, 489.1, 717.8, 492.9, 718.2, 492.3, +723.2, 495.6, 722.6, 492.1, 718.1, 493.2, 713.5, 490.2, 744.7, 514.0, +740.9, 511.5, 738.4, 508.1, 737.1, 509.1, 734.5, 506.4, 735.2, 505.7, +733.3, 502.3, 732.5, 501.9, 732.8, 501.5, 732.3, 500.6, 738.7, 507.1, +740.3, 506.3, 744.7, 514.0, 840.1, 624.8, 859.1, 643.0, 856.0, 656.1, +878.0, 661.2, 875.3, 663.4, 875.3, 663.4, 872.6, 665.6, 862.1, 657.6, +864.1, 655.0, 855.7, 644.3, 849.0, 635.9, 849.0, 635.9, 842.2, 627.4, +841.2, 626.1, 841.3, 625.9, 840.1, 624.8, 839.5, 570.9, 839.5, 570.9, +847.4, 578.7, 855.2, 586.5, 855.4, 586.6, 855.4, 586.6, 855.5, 586.8, +860.1, 591.3, 860.2, 591.2, 864.8, 595.8, 865.1, 596.1, 865.0, 596.2, +865.4, 596.6, 860.4, 591.7, 860.4, 591.7, 855.5, 586.8, 855.4, 586.6, +855.4, 586.6, 855.2, 586.5, 847.4, 578.7, 839.5, 570.9, 839.5, 570.9, +877.5, 603.6, 857.1, 585.8, 857.1, 585.8, 836.7, 568.0, 838.3, 567.7, +839.8, 566.4, 839.6, 565.9, 839.5, 565.7, 842.7, 563.6, 845.9, 561.2, +851.4, 552.7, 856.6, 556.1, 867.3, 550.9, 867.2, 551.2, 872.1, 553.1, +876.8, 555.4, 881.3, 578.7, 884.1, 601.5, 877.5, 603.6, 876.8, 555.4, +887.4, 560.3, 887.3, 560.5, 897.9, 565.3, 900.5, 583.4, 900.4, 583.4, +903.1, 601.5, 904.2, 615.5, 904.8, 615.5, 907.1, 629.4, 892.3, 616.5, +892.3, 616.5, 877.5, 603.6, 884.1, 601.5, 881.3, 578.7, 876.8, 555.4, +924.9, 574.1, 934.6, 580.7, 934.6, 580.7, 944.3, 587.3, 944.0, 594.1, +941.0, 598.8, 944.0, 600.9, 943.8, 604.9, 945.7, 606.7, 943.6, 608.8, +926.1, 612.3, 927.9, 621.4, 912.2, 633.9, 912.3, 632.1, 910.0, 632.0, +907.8, 630.0, 907.5, 626.4, 907.2, 626.4, 906.6, 622.8, 904.2, 604.5, +903.8, 604.5, 901.1, 586.3, 904.6, 577.0, 913.1, 573.8, 924.9, 574.1, +901.1, 586.3, 896.6, 584.8, 899.5, 575.8, 897.9, 565.3, 897.9, 565.1, +897.9, 565.1, 897.9, 564.9, 897.2, 559.8, 898.2, 559.5, 896.4, 554.7, +903.9, 559.8, 903.7, 560.0, 911.3, 564.9, 913.1, 566.1, 913.1, 566.1, +915.0, 567.3, 915.1, 570.9, 919.9, 570.7, 924.9, 574.1, 913.1, 573.8, +904.6, 577.0, 901.1, 586.3, 556.4, 358.5, 563.7, 373.2, 565.8, 372.2, +575.2, 385.9, 582.9, 397.1, 582.9, 397.1, 590.6, 408.4, 612.9, 440.9, +613.2, 440.7, 635.2, 473.4, 635.6, 474.9, 636.0, 474.9, 636.1, 476.4, +637.2, 490.9, 632.9, 492.8, 638.3, 505.4, 638.4, 507.7, 638.1, 507.7, +637.8, 510.0, 637.6, 511.1, 638.0, 511.3, 637.5, 512.3, 637.6, 512.1, +637.2, 511.8, 636.9, 511.4, 596.6, 435.0, 594.5, 436.0, 556.4, 358.5, +636.9, 511.4, 631.2, 500.0, 630.0, 500.6, 623.1, 489.8, 602.2, 457.1, +602.2, 457.1, 581.3, 424.5, 580.7, 423.6, 580.7, 423.6, 580.1, 422.7, +576.4, 416.8, 576.4, 416.8, 572.6, 410.9, 568.0, 403.6, 568.0, 403.6, +563.3, 396.4, 554.4, 382.5, 554.4, 382.5, 545.5, 368.5, 542.6, 364.1, +540.9, 364.5, 539.8, 359.6, 538.8, 344.7, 538.3, 344.7, 536.7, 329.8, +545.6, 329.2, 548.0, 343.3, 556.4, 358.5, 594.5, 436.0, 596.6, 435.0, +636.9, 511.4, 675.1, 570.2, 674.8, 570.2, 674.6, 570.3, 674.6, 570.2, +665.5, 556.2, 665.7, 556.0, 656.7, 541.9, 653.1, 536.2, 653.0, 536.3, +649.4, 530.7, 645.6, 524.9, 641.9, 519.1, 641.9, 519.1, 641.9, 519.1, +645.6, 524.9, 649.4, 530.7, 653.0, 536.3, 653.1, 536.2, 656.7, 541.9, +665.9, 556.0, 666.1, 555.9, 675.1, 570.2, 899.8, 548.7, 895.3, 542.3, +895.6, 542.1, 890.9, 536.0, 885.0, 514.4, 887.5, 513.7, 884.2, 491.5, +882.5, 489.1, 883.7, 488.2, 883.2, 484.9, 883.2, 484.2, 883.7, 484.2, +884.2, 483.4, 886.2, 479.1, 886.7, 479.4, 889.2, 475.3, 894.8, 486.7, +891.1, 488.4, 893.0, 501.6, 896.4, 525.1, 901.3, 525.5, 899.8, 548.7, +884.2, 389.0, 889.3, 403.4, 884.3, 409.7, 894.4, 417.8, 899.5, 431.9, +904.7, 432.0, 904.5, 446.0, 898.0, 455.1, 899.1, 455.9, 893.7, 465.8, +881.0, 430.2, 883.6, 427.3, 884.2, 389.0, 893.7, 465.8, 888.9, 474.6, +888.4, 474.4, 884.2, 483.4, 883.7, 484.2, 883.2, 484.2, 883.2, 484.9, +882.6, 480.5, 884.0, 479.6, 881.9, 476.0, 881.7, 474.5, 881.7, 474.5, +881.4, 472.9, 881.6, 432.1, 876.0, 432.0, 869.9, 391.2, 870.0, 370.4, +872.9, 370.0, 870.1, 349.6, 876.6, 367.7, 878.4, 386.3, 883.1, 385.9, +882.6, 387.0, 883.6, 387.4, 884.2, 389.0, 883.6, 427.3, 881.0, 430.2, +893.7, 465.8, 912.4, 468.1, 909.0, 458.6, 911.4, 456.8, 905.6, 449.0, +905.9, 447.7, 904.0, 446.7, 904.5, 446.0, 904.7, 432.0, 899.5, 431.9, +894.4, 417.8, 896.0, 419.1, 901.1, 412.8, 907.7, 407.8, 917.5, 435.3, +913.9, 438.2, 912.4, 468.1, 907.7, 407.8, 913.4, 403.5, 917.7, 404.6, +919.1, 399.2, 920.4, 403.4, 920.4, 403.4, 921.6, 407.7, 923.3, 429.6, +924.9, 429.4, 928.2, 451.2, 930.2, 470.0, 930.5, 470.0, 933.3, 488.7, +936.3, 516.2, 934.7, 516.5, 939.4, 543.8, 931.7, 522.3, 935.4, 520.1, +924.1, 500.9, 921.1, 492.4, 921.1, 492.4, 918.1, 484.0, 916.7, 480.1, +916.7, 480.1, 915.3, 476.2, 916.2, 472.8, 913.8, 472.2, 912.4, 468.1, +913.9, 438.2, 917.5, 435.3, 907.7, 407.8, 869.3, 391.2, 869.6, 393.4, +869.6, 395.5, 869.9, 395.5, 875.4, 434.2, 881.6, 434.2, 881.4, 472.9, +881.7, 474.5, 881.7, 474.5, 881.9, 476.0, 862.4, 442.8, 860.9, 443.7, +840.0, 411.3, 838.8, 403.6, 853.7, 399.5, 869.3, 391.2, 840.0, 411.3, +833.9, 401.9, 836.4, 396.3, 827.8, 392.5, 834.3, 373.1, 846.5, 358.5, +840.8, 353.8, 844.2, 352.5, 844.2, 352.5, 847.6, 351.2, 847.8, 352.0, +856.3, 353.2, 863.2, 350.6, 866.2, 370.9, 866.2, 370.9, 869.3, 391.2, +853.7, 399.5, 838.8, 403.6, 840.0, 411.3, 797.4, 463.4, 818.1, 481.9, +832.6, 485.1, 832.8, 507.0, 815.2, 491.3, 815.2, 491.3, 797.5, 475.5, +794.5, 471.9, 800.4, 466.1, 797.4, 463.4, 797.5, 475.5, 781.5, 461.2, +783.7, 457.2, 765.4, 446.9, 763.2, 449.1, 743.6, 417.7, 714.5, 401.6, +727.0, 396.9, 727.0, 396.9, 739.4, 392.2, 746.0, 393.0, 745.1, 399.2, +750.9, 406.3, 764.3, 422.8, 764.3, 422.8, 777.8, 439.4, 787.6, 451.4, +790.1, 450.1, 797.4, 463.4, 800.4, 466.1, 794.5, 471.9, 797.5, 475.5, +764.0, 382.8, 766.2, 382.0, 766.2, 382.0, 768.3, 381.2, 787.3, 419.8, +792.2, 417.7, 818.3, 452.4, 839.0, 481.8, 837.6, 483.0, 859.8, 511.3, +811.2, 449.2, 812.7, 448.1, 765.5, 384.9, 764.8, 383.9, 763.8, 383.1, +764.0, 382.8, 875.4, 533.5, 871.8, 528.1, 871.7, 528.3, 868.0, 523.0, +863.9, 517.2, 863.9, 517.2, 859.8, 511.3, 837.6, 483.0, 839.0, 481.8, +818.3, 452.4, 814.6, 447.4, 815.7, 446.5, 813.2, 440.7, 831.1, 465.0, +830.0, 465.8, 846.8, 490.9, 848.1, 492.9, 848.1, 492.9, 849.5, 494.8, +862.4, 514.2, 862.6, 514.1, 875.4, 533.5, 544.1, 175.8, 556.5, 200.5, +554.9, 201.4, 569.0, 225.3, 561.9, 229.4, 547.8, 205.6, 526.7, 186.0, +525.3, 184.7, 524.4, 183.1, 523.9, 183.4, 533.0, 178.0, 540.5, 172.5, +544.1, 175.8, 526.7, 186.0, 547.8, 205.6, 561.9, 229.4, 569.0, 225.3, +572.1, 230.5, 576.1, 228.6, 578.3, 234.0, 586.1, 245.8, 588.9, 243.9, +599.6, 253.8, 619.4, 274.2, 619.6, 274.0, 639.5, 294.1, 616.9, 278.6, +614.7, 281.7, 589.9, 269.3, 577.6, 260.4, 580.3, 256.7, 570.7, 244.0, +560.1, 230.0, 560.1, 230.0, 549.5, 216.0, 544.8, 209.8, 544.8, 209.8, +540.0, 203.6, 538.5, 201.6, 538.5, 201.6, 537.0, 199.6, 531.9, 192.8, +533.2, 191.2, 526.7, 186.0, 606.5, 321.3, 607.1, 332.5, 603.3, 334.3, +607.8, 343.7, 582.8, 318.3, 582.8, 318.3, 557.8, 293.0, 550.1, 270.2, +544.6, 272.1, 531.4, 251.2, 574.7, 276.3, 574.1, 282.0, 606.5, 321.3, +531.4, 251.2, 526.9, 244.1, 528.3, 242.6, 522.4, 236.9, 563.4, 261.1, +563.4, 261.1, 604.4, 285.3, 606.6, 286.8, 604.7, 289.6, 604.9, 294.0, +605.1, 297.0, 605.1, 297.0, 605.3, 300.0, 602.1, 301.3, 605.9, 310.6, +606.5, 321.3, 574.1, 282.0, 574.7, 276.3, 531.4, 251.2, 604.9, 294.0, +604.7, 289.6, 606.6, 286.8, 604.4, 285.3, 606.9, 286.8, 606.9, 286.8, +609.4, 288.2, 609.6, 291.0, 605.3, 294.2, 604.9, 294.0, 542.8, 279.0, +564.4, 308.2, 562.7, 309.6, 586.0, 337.3, 543.6, 311.2, 543.6, 311.2, +501.2, 285.0, 505.9, 288.8, 510.0, 283.7, 518.8, 282.5, 530.8, 280.7, +536.5, 273.8, 542.8, 279.0, 567.3, 73.7, 569.0, 78.4, 568.2, 78.7, +569.1, 83.6, 569.4, 84.9, 569.4, 84.9, 569.6, 86.2, 568.6, 86.9, +571.5, 91.2, 570.6, 91.6, 566.7, 94.4, 566.7, 94.4, 562.7, 97.1, +561.8, 97.0, 561.9, 94.1, 561.1, 91.2, 553.1, 61.2, 553.1, 61.2, +545.1, 31.1, 543.1, 23.6, 543.1, 23.6, 541.1, 16.0, 535.7, -4.2, +538.8, -5.6, 530.3, -24.4, 551.9, 23.2, 549.6, 24.4, 567.3, 73.7, +530.3, -24.4, 529.7, -26.0, 529.8, -26.1, 529.4, -27.8, 528.2, -32.2, +527.2, -32.2, 527.0, -36.7, 526.9, -37.9, 528.8, -39.2, 528.8, -39.2, +530.9, -27.9, 550.9, -21.1, 549.9, -19.7, 553.8, 1.1, 548.9, 19.7, +557.7, 22.0, 560.4, 36.7, 560.4, 36.7, 563.1, 51.4, 565.2, 62.6, +562.9, 63.6, 567.3, 73.7, 549.6, 24.4, 551.9, 23.2, 530.3, -24.4, +682.2, -11.8, 682.8, -12.2, 687.1, -7.7, 686.9, -7.4, 662.7, 7.7, +666.9, 14.4, 646.9, 36.3, 607.4, 59.9, 606.8, 59.2, 569.6, 86.2, +569.4, 84.9, 569.4, 84.9, 569.1, 83.6, 588.0, 66.3, 588.8, 67.1, +608.4, 50.5, 624.1, 37.2, 624.1, 37.2, 639.9, 23.9, 661.0, 6.1, +659.3, 3.5, 682.2, -11.8, 376.8, 74.3, 374.7, 66.1, 374.7, 66.1, +372.6, 57.9, 376.1, 61.9, 406.7, 46.2, 406.0, 43.4, 413.5, 43.8, +421.0, 59.2, 420.2, 60.1, 406.4, 74.7, 398.1, 75.3, 376.8, 74.3, +439.2, 19.5, 426.1, 5.7, 426.1, 5.7, 413.0, -8.1, 441.4, -5.2, +442.7, -8.0, 471.0, -14.3, 488.5, -14.8, 498.8, -2.9, 506.1, -10.7, +482.9, 14.0, 473.1, 18.6, 439.2, 19.5, 506.1, -10.7, 506.9, -11.0, +507.9, -10.1, 508.1, -10.5, 487.9, 19.2, 487.4, 18.9, 466.1, 47.9, +466.2, 47.8, 465.9, 47.6, 465.6, 47.3, 452.6, 33.3, 452.4, 33.4, +439.2, 19.5, 473.1, 18.6, 482.9, 14.0, 506.1, -10.7, 424.5, 65.0, +422.7, 62.3, 422.4, 62.5, 420.2, 60.1, 421.0, 59.2, 413.5, 43.8, +406.0, 43.4, 397.1, 8.3, 364.4, -22.7, 353.5, -18.0, 352.8, -20.5, +351.7, -22.3, 349.8, -22.3, 355.9, -23.9, 355.9, -23.9, 362.0, -25.4, +371.9, -18.7, 369.3, -14.8, 376.6, -4.2, 383.0, 5.0, 383.0, 5.0, +389.3, 14.2, 396.6, 24.7, 396.6, 24.7, 403.8, 35.1, 414.2, 50.1, +414.5, 49.8, 424.5, 65.0, 414.0, -38.8, 421.4, -40.7, 421.3, -40.9, +428.6, -42.8, 449.2, -48.0, 449.2, -47.9, 469.8, -53.0, 471.6, -53.4, +471.6, -53.4, 473.5, -53.9, 443.7, -46.3, 443.8, -46.2, 414.0, -38.8, +208.2, 292.5, 217.0, 279.3, 222.7, 280.5, 225.8, 266.0, 239.8, 263.1, +242.0, 274.1, 258.3, 282.1, 260.9, 283.4, 260.9, 283.4, 263.4, 284.6, +267.9, 286.8, 272.4, 286.8, 272.4, 289.1, 272.4, 291.5, 267.9, 291.5, +263.4, 293.9, 252.2, 300.0, 252.2, 300.0, 241.0, 306.0, 240.2, 306.5, +239.9, 307.2, 239.3, 307.0, 223.5, 300.4, 211.9, 303.7, 208.2, 292.5, +239.3, 307.0, 240.1, 309.9, 227.5, 313.4, 215.6, 319.8, 208.1, 323.9, +208.1, 323.9, 200.5, 328.0, 197.8, 326.4, 191.7, 329.4, 190.1, 333.6, +194.5, 320.1, 194.5, 320.1, 198.8, 306.6, 200.1, 299.0, 203.5, 299.5, +208.2, 292.5, 211.9, 303.7, 223.5, 300.4, 239.3, 307.0, 238.5, 111.6, +244.2, 108.1, 247.0, 109.7, 249.8, 104.6, 245.6, 119.3, 245.6, 119.3, +241.5, 134.0, 240.6, 137.6, 239.4, 137.2, 238.0, 140.7, 230.1, 155.8, +230.1, 155.8, 222.2, 171.0, 200.9, 211.7, 203.3, 213.2, 179.6, 252.5, +180.5, 246.8, 179.8, 246.7, 179.9, 241.0, 207.3, 175.5, 206.2, 174.7, +238.5, 111.6, 179.9, 241.0, 180.4, 221.2, 174.6, 203.5, 180.9, 201.5, +201.5, 161.7, 201.5, 161.7, 222.1, 121.8, 224.7, 114.7, 230.3, 116.7, +238.5, 111.6, 206.2, 174.7, 207.3, 175.5, 179.9, 241.0, 199.0, 163.7, +180.0, 201.5, 180.0, 201.5, 161.1, 239.4, 150.1, 261.1, 150.0, 261.0, +138.9, 282.6, 137.6, 285.0, 137.6, 285.0, 136.3, 287.5, 137.7, 283.6, +136.5, 283.1, 136.6, 278.7, 146.3, 257.4, 147.8, 258.1, 159.0, 237.4, +179.0, 200.6, 206.9, 171.3, 199.0, 163.7, 477.6, 762.9, 483.4, 806.1, +483.5, 806.0, 489.1, 849.3, 489.8, 854.9, 489.6, 854.9, 490.1, 860.6, +490.8, 868.4, 490.2, 868.5, 491.6, 876.2, 489.4, 864.4, 490.1, 864.3, +488.6, 852.4, 483.4, 810.0, 483.4, 810.0, 478.2, 767.6, 477.9, 765.3, +477.9, 765.2, 477.6, 762.9, 491.9, 847.9, 491.7, 854.3, 493.4, 859.1, +490.1, 860.6, 489.6, 854.9, 489.8, 854.9, 489.1, 849.3, 487.8, 840.3, +488.3, 840.2, 487.4, 831.1, 485.8, 836.4, 489.1, 837.4, 490.8, 843.6, +491.4, 845.8, 492.0, 845.8, 491.9, 847.9, 501.5, 451.5, 496.1, 456.3, +485.1, 452.0, 484.8, 454.4, 495.2, 435.8, 495.2, 435.9, 505.5, 417.3, +512.4, 405.1, 519.8, 404.6, 519.2, 392.8, 528.4, 376.3, 537.4, 359.8, +537.5, 359.8, 538.4, 359.2, 538.9, 358.3, 538.6, 357.9, 539.2, 358.7, +539.7, 358.7, 539.8, 359.6, 540.9, 364.5, 542.6, 364.1, 545.5, 368.5, +533.3, 400.4, 529.4, 398.9, 513.3, 429.3, 507.4, 440.4, 510.3, 443.7, +501.5, 451.5, 468.2, 621.6, 466.6, 603.5, 466.5, 603.5, 464.8, 585.3, +484.5, 550.0, 465.4, 538.7, 463.8, 492.1, 471.6, 478.1, 471.6, 478.1, +479.4, 464.0, 488.2, 493.2, 477.1, 496.5, 474.8, 529.0, 474.7, 530.5, +474.7, 530.5, 474.6, 531.9, 472.3, 563.6, 472.3, 563.6, 470.1, 595.2, +469.2, 607.8, 469.2, 607.8, 468.3, 620.3, 468.2, 621.0, 468.1, 621.0, +468.2, 621.6, 458.7, 501.2, 458.0, 502.4, 457.3, 502.5, 457.3, 503.6, +456.5, 494.1, 456.5, 494.1, 455.6, 484.5, 452.4, 490.2, 457.9, 492.8, +458.7, 501.2, 480.2, 266.5, 481.8, 271.2, 482.9, 270.8, 485.7, 275.1, +492.4, 286.2, 492.6, 286.0, 499.6, 296.9, 503.1, 301.2, 500.0, 303.7, +500.3, 310.6, 492.2, 303.8, 495.4, 300.0, 490.6, 289.4, 485.4, 277.9, +484.3, 278.3, 480.2, 266.5, 205.6, 671.5, 207.4, 667.6, 208.7, 667.8, +209.3, 663.7, 209.5, 676.0, 209.5, 676.0, 209.6, 688.4, 212.5, 682.3, +205.7, 680.0, 205.6, 671.5, 173.8, 490.6, 180.4, 471.0, 174.1, 457.5, +187.1, 451.5, 206.4, 425.2, 203.9, 422.9, 225.7, 398.9, 231.9, 390.5, +230.2, 388.0, 238.3, 382.2, 236.2, 383.7, 239.4, 387.0, 237.7, 390.2, +229.6, 406.0, 228.1, 405.3, 218.5, 420.3, 211.9, 430.8, 211.9, 430.8, +205.2, 441.3, 189.5, 466.0, 196.2, 478.0, 173.8, 490.6, 434.6, 322.4, +437.2, 344.4, 439.3, 344.4, 439.9, 366.4, 440.0, 367.4, 440.0, 367.4, +440.0, 368.4, 432.0, 356.0, 432.4, 355.7, 424.7, 343.1, 424.2, 342.3, +424.2, 342.3, 423.8, 341.6, 419.6, 334.6, 419.6, 334.6, 415.3, 327.6, +405.7, 311.6, 405.7, 311.6, 396.0, 295.6, 392.0, 289.0, 389.9, 289.5, +387.9, 282.3, 377.8, 275.8, 385.3, 264.0, 382.7, 245.8, 379.9, 250.3, +390.0, 256.5, 397.3, 267.3, 407.0, 281.7, 407.0, 281.7, 416.8, 296.1, +417.2, 296.7, 417.2, 296.7, 417.5, 297.2, 420.5, 301.6, 420.5, 301.6, +423.4, 305.9, 429.0, 314.1, 432.1, 313.3, 434.6, 322.4, 209.1, 881.3, +209.0, 881.8, 205.6, 882.1, 202.6, 881.2, 203.0, 880.7, 202.4, 880.2, +202.3, 879.2, 215.2, 875.8, 205.3, 838.2, 208.2, 797.2, 203.1, 821.6, +208.5, 822.8, 208.8, 848.4, 209.0, 864.8, 212.1, 865.4, 209.1, 881.3, +322.4, 303.2, 317.5, 312.0, 320.3, 313.4, 316.6, 322.9, 314.1, 329.5, +313.2, 329.1, 309.8, 335.3, 309.5, 336.0, 309.4, 336.0, 309.1, 336.7, +315.6, 319.9, 313.8, 318.9, 322.4, 303.2, 309.8, 335.3, 313.2, 329.1, +314.1, 329.5, 316.6, 322.9, 311.6, 347.8, 309.5, 347.3, 302.4, 371.7, +301.0, 376.6, 301.0, 376.6, 299.6, 381.6, 296.0, 393.7, 296.0, 393.7, +292.5, 405.8, 292.3, 406.5, 292.3, 406.5, 292.1, 407.2, 291.4, 409.5, +291.4, 409.5, 290.7, 411.9, 283.9, 435.5, 283.9, 435.5, 277.0, 459.0, +274.5, 467.6, 274.5, 467.6, 272.0, 476.1, 270.8, 480.4, 270.8, 480.4, +269.5, 484.6, 256.2, 529.7, 256.2, 529.6, 242.9, 574.7, 241.7, 578.5, +241.8, 578.5, 240.7, 582.4, 236.3, 598.2, 231.9, 614.0, 231.9, 614.0, +231.9, 614.0, 236.3, 598.2, 240.7, 582.4, 241.8, 578.5, 241.7, 578.5, +242.9, 574.7, 267.7, 486.1, 267.8, 486.1, 292.4, 397.5, 300.9, 367.2, +300.6, 367.1, 309.1, 336.7, 309.4, 336.0, 309.5, 336.0, 309.8, 335.3, +144.7, 133.3, 156.7, 133.2, 156.7, 133.2, 168.8, 133.0, 168.1, 133.2, +169.2, 137.2, 169.5, 141.3, 146.3, 157.1, 147.5, 158.8, 125.4, 176.3, +127.9, 177.1, 129.1, 148.9, 144.7, 133.3, 125.4, 176.3, 116.5, 183.4, +109.2, 182.0, 107.5, 190.5, 104.8, 170.5, 104.8, 170.5, 102.0, 150.6, +118.6, 144.8, 117.6, 142.0, 133.2, 133.5, 133.7, 132.2, 137.8, 135.0, +140.7, 133.4, 142.0, 132.4, 142.7, 133.4, 144.7, 133.3, 129.1, 148.9, +127.9, 177.1, 125.4, 176.3, 115.5, 261.9, 117.0, 266.4, 119.2, 266.7, +118.6, 270.9, 118.7, 271.9, 118.7, 271.9, 118.9, 272.9, 123.6, 317.8, +123.5, 317.8, 128.3, 362.6, 128.7, 366.0, 129.2, 369.3, 129.2, 369.3, +129.2, 369.3, 128.7, 366.0, 128.3, 362.6, 121.9, 312.3, 120.9, 312.4, +115.5, 261.9, 60.6, 101.9, 65.7, 116.8, 65.7, 116.8, 70.8, 131.7, +67.1, 140.6, 67.3, 142.3, 69.2, 152.0, 68.3, 163.3, 69.5, 163.5, +67.4, 174.6, 65.2, 180.0, 65.2, 180.0, 63.0, 185.5, 63.2, 185.1, +63.0, 185.0, 63.0, 184.6, 62.5, 168.3, 62.5, 168.3, 62.1, 152.1, +61.3, 127.0, 51.6, 122.9, 60.6, 101.9, 129.6, 436.3, 133.6, 448.4, +133.2, 448.6, 137.6, 460.5, 122.5, 453.7, 126.3, 445.1, 115.1, 429.8, +105.8, 417.1, 108.9, 409.5, 96.5, 404.4, 115.6, 412.2, 112.5, 419.8, +128.4, 435.2, 129.0, 435.8, 129.3, 435.7, 129.6, 436.3, 38.9, 323.2, +38.5, 321.0, 38.5, 321.0, 38.1, 318.9, 53.0, 296.7, 49.7, 294.5, +61.2, 270.1, 65.4, 294.0, 51.2, 297.2, 38.9, 323.2, 115.1, 429.8, +126.3, 445.1, 122.5, 453.7, 137.6, 460.5, 138.0, 461.7, 139.3, 461.7, +139.2, 462.7, 139.8, 464.7, 142.0, 464.7, 141.8, 466.3, 141.8, 468.7, +141.8, 468.7, 141.9, 471.0, 142.0, 471.5, 141.7, 471.6, 141.5, 472.1, +130.0, 454.6, 130.4, 454.3, 119.3, 436.5, 117.2, 433.1, 117.5, 432.9, +115.1, 429.8, -27.5, 407.4, -30.4, 389.0, -29.2, 388.7, -33.2, 370.6, +-33.3, 359.7, -34.8, 355.3, -28.1, 348.9, -26.1, 355.1, -25.7, 355.0, +-23.3, 361.1, -23.0, 384.2, -14.8, 395.3, -27.5, 407.4, -23.3, 361.1, +-22.7, 362.5, -22.7, 362.5, -22.1, 363.9, -20.4, 368.4, -20.4, 368.4, +-18.6, 372.9, -4.0, 410.0, -0.8, 409.0, 10.6, 447.0, 15.8, 451.1, +10.4, 458.2, 10.2, 469.4, -3.1, 439.7, -25.9, 441.5, -25.5, 414.1, +-26.2, 412.5, -26.2, 412.5, -27.0, 410.9, -27.8, 409.6, -27.2, 409.2, +-27.5, 407.4, -14.8, 395.3, -23.0, 384.2, -23.3, 361.1, -15.8, 379.3, +-17.1, 376.1, -18.6, 372.9, -18.6, 372.9, -20.4, 368.4, -20.4, 368.4, +-22.1, 363.9, -22.2, 363.6, -22.2, 363.6, -22.3, 363.3, -20.5, 355.6, +-24.5, 354.4, -27.3, 345.7, -27.8, 340.5, -25.4, 335.0, -24.8, 335.0, +-15.9, 341.8, -16.5, 346.7, -6.7, 348.2, -5.9, 347.4, -2.9, 353.3, +1.7, 354.3, 1.8, 359.9, 9.7, 365.8, 16.8, 365.3, 17.9, 368.2, +19.8, 367.5, 22.8, 369.6, 22.8, 369.7, 22.8, 369.7, 22.8, 369.7, +22.9, 371.5, 22.8, 371.5, 22.8, 373.4, 3.9, 378.1, 3.5, 379.5, +-15.8, 379.3, 22.8, 373.4, 22.9, 387.5, 22.9, 387.5, 22.9, 401.7, +21.1, 397.3, -5.3, 402.7, -5.3, 403.6, -10.6, 391.4, -10.6, 391.4, +-15.8, 379.3, 3.5, 379.5, 3.9, 378.1, 22.8, 373.4, 89.4, 652.2, +89.7, 652.3, 89.9, 652.3, 89.9, 652.3, 91.2, 668.6, 91.2, 668.6, +92.5, 684.9, 87.9, 684.0, 90.7, 668.6, 89.4, 652.2, 765.8, 541.1, +758.0, 521.3, 758.6, 521.0, 750.1, 501.5, 748.7, 497.4, 750.1, 492.7, +749.0, 492.6, 766.0, 502.0, 785.1, 497.0, 786.1, 505.6, 793.3, 509.5, +793.3, 509.5, 800.5, 513.5, 798.1, 513.8, 797.1, 519.5, 797.4, 525.2, +799.3, 532.4, 795.3, 533.5, 793.2, 541.7, 782.4, 547.1, 773.3, 548.1, +765.8, 541.1, 793.2, 541.7, 787.8, 562.4, 787.8, 562.4, 782.5, 583.1, +778.3, 561.3, 774.1, 562.1, 765.8, 541.1, 773.3, 548.1, 782.4, 547.1, +793.2, 541.7, 748.5, 575.4, 744.8, 572.5, 744.4, 572.8, 741.0, 569.6, +734.7, 564.0, 734.7, 564.0, 728.5, 558.4, 727.5, 551.0, 726.0, 551.2, +723.5, 543.9, 738.5, 556.7, 737.2, 558.8, 748.5, 575.4, 723.5, 543.9, +723.0, 542.4, 722.7, 542.5, 722.5, 540.9, 722.2, 539.4, 721.3, 538.6, +722.0, 537.9, 720.3, 528.5, 720.3, 528.5, 718.6, 519.2, 716.1, 504.7, +710.9, 503.7, 713.5, 490.2, 718.1, 493.2, 722.6, 492.1, 723.2, 495.6, +728.2, 499.0, 728.0, 499.4, 733.3, 502.3, 735.2, 505.7, 734.5, 506.4, +737.1, 509.1, 736.7, 509.4, 739.2, 512.8, 741.2, 516.5, 744.6, 544.7, +744.7, 547.0, 758.5, 571.7, 759.3, 578.0, 759.3, 578.0, 760.1, 584.4, +754.8, 579.3, 754.3, 579.9, 748.5, 575.4, 737.2, 558.8, 738.5, 556.7, +723.5, 543.9, 750.7, 506.1, 751.4, 512.5, 751.4, 512.5, 752.2, 518.9, +750.9, 515.5, 748.4, 516.4, 744.7, 514.0, 740.3, 506.3, 738.7, 507.1, +732.3, 500.6, 719.9, 478.6, 726.2, 469.7, 707.6, 456.6, 706.9, 452.6, +706.9, 452.6, 706.2, 448.6, 730.0, 476.0, 730.8, 475.8, 750.7, 506.1, +706.2, 448.6, 703.8, 435.3, 705.6, 434.7, 701.5, 422.0, 706.9, 425.7, +706.9, 425.7, 712.4, 429.4, 714.7, 448.8, 726.1, 451.4, 745.7, 464.8, +745.7, 465.1, 745.6, 465.3, 745.8, 465.5, 750.7, 468.2, 742.7, 479.3, +748.1, 484.6, 749.8, 485.2, 747.0, 491.5, 749.0, 492.6, 750.1, 492.7, +748.7, 497.4, 750.1, 501.5, 751.0, 503.5, 750.4, 503.8, 750.7, 506.1, +730.8, 475.8, 730.0, 476.0, 706.2, 448.6, 835.7, 623.1, 836.7, 624.3, +837.6, 623.4, 839.3, 624.0, 839.8, 624.1, 839.7, 624.4, 840.1, 624.8, +841.3, 625.9, 841.2, 626.1, 842.2, 627.4, 838.6, 626.1, 838.1, 626.0, +835.7, 623.1, 855.5, 586.8, 860.4, 591.7, 860.4, 591.7, 865.4, 596.6, +880.6, 617.1, 878.7, 618.8, 895.8, 637.6, 867.6, 630.8, 867.6, 630.5, +839.3, 624.0, 837.6, 623.4, 836.7, 624.3, 835.7, 623.1, 831.7, 622.2, +828.2, 620.5, 827.8, 621.3, 835.7, 605.4, 839.2, 607.1, 850.6, 593.0, +853.0, 589.9, 853.9, 586.4, 855.5, 586.8, 575.2, 385.9, 565.8, 372.2, +563.7, 373.2, 556.4, 358.5, 548.0, 343.3, 545.6, 329.2, 536.7, 329.8, +536.4, 326.7, 536.4, 326.7, 536.1, 323.7, 544.7, 334.1, 543.4, 335.2, +550.6, 346.8, 562.9, 366.3, 565.0, 365.3, 575.2, 385.9, 626.3, 445.3, +630.7, 459.4, 630.7, 459.4, 635.2, 473.4, 613.2, 440.7, 612.9, 440.9, +590.6, 408.4, 585.9, 399.5, 595.0, 392.5, 589.2, 386.5, 612.9, 411.0, +610.1, 414.7, 626.3, 445.3, 589.2, 386.5, 586.2, 380.6, 588.8, 379.2, +588.3, 372.0, 587.4, 357.9, 582.3, 356.2, 586.5, 343.8, 591.1, 346.9, +591.1, 346.9, 595.7, 350.0, 597.0, 350.8, 596.5, 351.7, 597.3, 353.4, +586.5, 392.3, 611.8, 399.4, 626.3, 445.3, 610.1, 414.7, 612.9, 411.0, +589.2, 386.5, 718.6, 519.2, 720.3, 528.5, 720.3, 528.5, 722.0, 537.9, +711.8, 549.5, 701.7, 552.1, 703.4, 562.7, 704.0, 563.8, 701.3, 565.4, +699.3, 568.1, 699.0, 569.1, 696.3, 568.4, 693.3, 568.6, 692.5, 565.5, +695.3, 564.7, 697.3, 560.8, 700.6, 554.3, 700.6, 554.3, 704.0, 547.8, +711.3, 533.5, 707.0, 525.6, 718.6, 519.2, 910.3, 563.5, 905.1, 556.1, +905.1, 556.1, 899.8, 548.7, 901.3, 525.5, 896.4, 525.1, 893.0, 501.6, +910.5, 526.3, 905.8, 531.9, 910.3, 563.5, 842.9, 516.0, 837.8, 511.5, +837.8, 511.5, 832.8, 507.0, 832.6, 485.1, 818.1, 481.9, 797.4, 463.4, +790.1, 450.1, 787.6, 451.4, 777.8, 439.4, 810.7, 477.4, 811.2, 477.0, +842.9, 516.0, 846.8, 490.9, 830.0, 465.8, 831.1, 465.0, 813.2, 440.7, +801.8, 415.0, 801.8, 415.0, 790.5, 389.3, 819.3, 429.5, 814.6, 432.8, +838.7, 476.3, 842.8, 483.6, 842.0, 484.2, 846.8, 490.9, 485.3, 126.2, +497.4, 124.9, 499.2, 128.7, 509.6, 123.7, 513.3, 124.0, 516.4, 125.4, +516.9, 124.3, 518.5, 126.3, 518.5, 126.3, 520.2, 128.3, 527.6, 149.4, +530.3, 148.5, 540.5, 168.7, 511.7, 166.9, 504.0, 153.5, 485.3, 126.2, +540.5, 168.7, 542.3, 172.2, 542.3, 172.2, 544.1, 175.8, 540.5, 172.5, +533.0, 178.0, 523.9, 183.4, 497.6, 169.5, 501.3, 162.4, 478.7, 141.4, +471.8, 134.9, 471.2, 135.4, 464.8, 128.5, 465.1, 128.8, 465.7, 128.2, +466.5, 128.1, 474.5, 124.3, 475.9, 127.1, 485.3, 126.2, 504.0, 153.5, +511.7, 166.9, 540.5, 168.7, 804.5, 87.9, 824.8, 103.2, 825.5, 102.3, +846.3, 117.0, 857.7, 124.9, 857.5, 125.2, 868.7, 133.4, 863.2, 129.3, +863.1, 129.5, 857.5, 125.5, 831.0, 106.7, 830.4, 107.5, 804.5, 87.9, +936.1, 245.9, 931.1, 239.5, 929.4, 240.9, 922.7, 235.8, 918.0, 232.3, +918.1, 232.3, 913.4, 228.8, 876.6, 201.0, 876.6, 201.0, 839.8, 173.3, +834.8, 169.5, 834.0, 165.0, 829.8, 165.7, 840.9, 163.7, 841.7, 168.3, +853.6, 170.8, 864.6, 173.1, 868.4, 168.9, 875.6, 175.5, 909.7, 206.5, +907.6, 209.3, 936.1, 245.9, 686.0, 149.5, 684.1, 135.7, 669.1, 137.8, +652.1, 126.1, 638.8, 117.0, 638.8, 117.0, 625.6, 107.8, 618.0, 102.6, +613.6, 104.6, 610.4, 97.3, 615.1, 96.3, 615.1, 96.3, 619.9, 95.3, +629.9, 99.9, 628.7, 102.5, 637.5, 109.8, 644.5, 115.4, 644.5, 115.4, +651.4, 121.1, 668.7, 135.3, 683.8, 133.2, 686.0, 149.5, 576.5, 124.0, +580.8, 126.0, 580.8, 126.0, 585.0, 128.1, 586.0, 128.6, 586.0, 128.7, +587.0, 129.2, 581.8, 126.6, 581.7, 126.7, 576.5, 124.0, 795.1, 271.6, +794.1, 271.2, 796.8, 263.4, 798.5, 255.3, 799.9, 248.5, 802.0, 241.9, +801.3, 241.7, 836.2, 260.0, 836.2, 260.0, 871.1, 278.3, 867.9, 276.4, +867.0, 277.9, 862.9, 277.6, 829.0, 274.6, 826.3, 282.4, 795.1, 271.6, +820.2, 241.9, 825.3, 245.5, 825.3, 245.5, 830.4, 249.0, 818.0, 241.3, +817.2, 242.5, 804.0, 236.0, 810.9, 240.7, 812.5, 238.1, 820.2, 241.9, +707.8, 186.5, 709.9, 187.9, 709.2, 189.3, 711.3, 190.3, 676.6, 173.2, +676.6, 173.2, 641.9, 156.2, 623.4, 152.8, 624.9, 144.6, 607.9, 133.0, +634.7, 139.2, 633.0, 146.5, 658.2, 159.9, 674.4, 168.6, 674.4, 168.6, +690.7, 177.3, 699.2, 181.9, 699.6, 181.4, 707.8, 186.5, 625.1, 297.5, +631.6, 301.3, 631.6, 301.3, 638.2, 305.2, 641.4, 305.5, 640.7, 312.7, +643.3, 320.2, 631.5, 313.3, 629.5, 310.4, 625.1, 297.5, 444.3, 210.5, +441.2, 208.2, 439.3, 206.5, 439.9, 203.6, 441.9, 192.6, 444.6, 193.1, +449.3, 182.6, 449.3, 182.6, 449.3, 182.6, 449.3, 182.6, 449.3, 182.6, +449.3, 182.6, 449.3, 182.6, 462.4, 196.0, 462.4, 196.0, 475.5, 209.3, +500.5, 245.8, 507.0, 241.3, 538.5, 273.3, 538.9, 273.7, 538.9, 273.8, +539.3, 274.3, 540.5, 275.8, 540.5, 275.8, 541.6, 277.4, 492.6, 244.5, +492.1, 245.1, 444.3, 210.5, 626.5, 73.3, 662.7, 57.4, 662.7, 57.4, +698.9, 41.5, 692.2, 43.1, 696.0, 54.8, 688.7, 58.0, 659.8, 70.7, +638.4, 53.9, 626.5, 73.3, 688.7, 58.0, 684.0, 56.9, 681.7, 71.7, +672.7, 84.0, 671.9, 85.1, 670.9, 84.4, 669.1, 84.8, 646.1, 89.7, +646.1, 94.6, 623.1, 94.6, 612.1, 88.8, 611.6, 89.7, 600.1, 84.9, +613.5, 79.6, 613.3, 79.1, 626.5, 73.3, 638.4, 53.9, 659.8, 70.7, +688.7, 58.0, 682.9, 81.8, 678.3, 83.9, 673.3, 81.8, 672.7, 84.0, +681.7, 71.7, 684.0, 56.9, 688.7, 58.0, 696.0, 54.8, 692.2, 43.1, +698.9, 41.5, 701.1, 40.5, 701.1, 40.5, 703.4, 39.5, 695.5, 59.7, +693.9, 59.1, 684.5, 78.6, 683.7, 80.2, 684.2, 81.2, 682.9, 81.8, +438.1, 128.0, 441.8, 124.7, 441.4, 124.4, 444.8, 120.8, 470.4, 92.8, +470.4, 92.8, 496.1, 64.9, 506.3, 53.8, 506.3, 53.8, 516.5, 42.7, +528.8, 29.4, 525.8, 22.1, 541.1, 16.0, 543.1, 23.6, 543.1, 23.6, +545.1, 31.1, 545.2, 32.4, 543.6, 32.5, 542.1, 33.9, 490.1, 80.9, +490.4, 81.3, 438.1, 128.0, 444.8, 120.8, 441.4, 124.4, 441.8, 124.7, +438.1, 128.0, 436.1, 130.2, 436.4, 132.0, 434.0, 132.5, 424.1, 132.5, +424.1, 132.5, 414.2, 132.6, 424.2, 121.8, 428.9, 123.9, 444.8, 120.8, +428.3, 100.5, 430.0, 102.1, 417.9, 114.9, 407.5, 129.4, 406.3, 131.1, +406.3, 131.1, 405.1, 132.7, 401.3, 134.8, 401.5, 136.3, 399.5, 140.5, +395.8, 140.0, 395.9, 136.0, 393.4, 131.0, 388.3, 125.4, 390.3, 123.5, +387.3, 116.0, 385.9, 112.6, 386.4, 112.4, 385.5, 108.7, 405.6, 101.1, +419.0, 91.7, 428.3, 100.5, 376.6, -4.2, 369.3, -14.8, 371.9, -18.7, +362.0, -25.4, 362.3, -25.5, 362.3, -25.5, 362.6, -25.6, 369.8, -25.0, +371.8, -27.7, 376.9, -24.1, 413.9, 15.4, 419.5, 10.2, 462.0, 44.4, +443.6, 22.3, 435.3, 29.2, 408.7, 14.0, 392.6, 4.9, 390.5, 7.5, +376.6, -4.2, 354.9, 111.6, 352.6, 104.8, 354.4, 104.1, 353.9, 96.6, +353.5, 89.0, 353.5, 89.0, 353.0, 81.4, 352.5, 73.8, 356.0, 70.2, +352.0, 66.3, 363.7, 84.6, 379.1, 99.0, 375.4, 102.9, 382.3, 117.9, +382.3, 118.8, 393.4, 131.0, 395.9, 136.0, 395.8, 140.0, 399.5, 140.5, +399.3, 141.0, 400.0, 142.2, 400.6, 142.2, 400.6, 148.2, 404.3, 148.1, +408.1, 154.0, 408.2, 154.1, 408.0, 154.2, 407.9, 154.3, 404.6, 151.9, +404.7, 151.7, 401.4, 149.1, 381.1, 132.7, 381.1, 132.7, 360.7, 116.3, +357.8, 114.0, 355.9, 114.6, 354.9, 111.6, 354.1, 229.1, 355.0, 230.2, +349.9, 234.6, 345.7, 240.1, 343.2, 243.5, 340.1, 246.3, 340.6, 246.9, +334.1, 239.5, 330.2, 231.4, 333.8, 226.6, 336.9, 222.5, 349.0, 223.4, +354.1, 229.1, 180.4, 458.9, 165.2, 479.0, 164.5, 478.5, 150.0, 499.1, +148.8, 490.4, 148.8, 490.4, 147.6, 481.7, 151.1, 474.2, 155.4, 476.2, +163.2, 470.8, 171.8, 464.8, 176.5, 467.1, 180.4, 458.9, 215.6, 319.8, +227.5, 313.4, 240.1, 309.9, 239.3, 307.0, 239.9, 307.2, 240.2, 306.5, +241.0, 306.0, 240.7, 308.1, 240.5, 309.0, 238.9, 309.9, 227.8, 315.9, +216.7, 313.2, 215.6, 319.8, 222.2, 171.0, 230.1, 155.8, 230.1, 155.8, +238.0, 140.7, 236.5, 144.5, 236.9, 144.6, 235.8, 148.5, 229.8, 160.1, +225.6, 158.8, 222.2, 171.0, 176.4, 362.5, 165.4, 402.3, 165.4, 402.3, +154.3, 442.2, 154.2, 419.4, 152.3, 419.4, 150.3, 396.7, 150.3, 396.6, +150.3, 396.6, 150.4, 396.6, 163.4, 379.5, 177.8, 378.3, 176.4, 362.5, +138.4, 232.7, 138.6, 227.7, 141.1, 225.7, 138.8, 222.8, 153.2, 201.8, +147.7, 192.0, 167.7, 180.7, 169.5, 178.8, 169.6, 178.8, 170.7, 176.4, +170.6, 175.3, 172.0, 175.3, 172.4, 174.0, 183.0, 160.3, 182.2, 159.7, +192.0, 145.4, 212.5, 119.2, 212.1, 118.9, 232.3, 92.4, 204.5, 142.4, +200.4, 140.1, 168.4, 187.8, 153.4, 210.2, 155.7, 212.2, 138.4, 232.7, +470.8, 711.5, 474.2, 737.2, 474.2, 737.2, 477.6, 762.9, 477.9, 765.2, +477.9, 765.3, 478.2, 767.6, 474.5, 739.6, 474.2, 739.6, 470.8, 711.5, +498.0, 805.1, 500.3, 782.9, 501.2, 783.0, 504.3, 760.8, 504.4, 760.3, +504.4, 760.3, 504.4, 759.9, 513.1, 698.6, 512.1, 698.4, 521.8, 637.3, +523.2, 628.6, 524.2, 628.7, 526.6, 620.2, 535.0, 590.1, 535.0, 590.1, +543.4, 560.1, 544.6, 555.9, 545.0, 555.9, 545.8, 551.6, 524.2, 668.1, +523.8, 668.0, 501.9, 784.4, 500.0, 794.8, 499.1, 794.7, 498.0, 805.1, +504.3, 760.8, 501.2, 783.0, 500.3, 782.9, 498.0, 805.1, 495.0, 826.5, +495.9, 826.7, 491.9, 847.9, 492.0, 845.8, 491.4, 845.8, 490.8, 843.6, +496.7, 802.1, 496.6, 802.0, 504.3, 760.8, 580.1, 422.7, 580.7, 423.6, +580.7, 423.6, 581.3, 424.5, 581.4, 425.1, 580.6, 425.6, 580.8, 426.0, +580.0, 424.7, 579.7, 424.1, 580.1, 422.7, 448.7, 409.5, 446.9, 389.4, +446.9, 389.4, 445.0, 369.4, 445.1, 370.9, 445.7, 370.9, 446.4, 372.4, +447.4, 374.6, 447.4, 374.6, 448.4, 376.8, 449.8, 380.1, 449.8, 380.1, +451.3, 383.3, 452.7, 386.4, 452.7, 386.4, 454.1, 389.4, 463.1, 419.2, +467.1, 418.0, 480.0, 446.7, 483.6, 433.2, 458.4, 430.8, 448.7, 409.5, +480.0, 446.7, 480.5, 447.8, 480.5, 447.8, 481.0, 448.9, 468.8, 470.9, +471.1, 472.2, 461.7, 495.7, 460.2, 498.5, 460.2, 498.5, 458.7, 501.2, +457.9, 492.8, 452.4, 490.2, 455.6, 484.5, 452.1, 447.0, 452.1, 447.0, +448.7, 409.5, 458.4, 430.8, 483.6, 433.2, 480.0, 446.7, 192.8, 698.4, +199.2, 685.0, 199.2, 685.0, 205.6, 671.5, 205.7, 680.0, 212.5, 682.3, +209.6, 688.4, 210.1, 726.6, 221.5, 730.2, 210.6, 764.9, 210.6, 767.8, +209.7, 770.5, 210.2, 770.6, 208.8, 765.3, 204.7, 766.3, 199.2, 762.1, +191.8, 731.2, 190.6, 729.9, 192.8, 698.4, 199.2, 762.1, 191.9, 756.3, +192.1, 756.1, 184.6, 750.6, 182.7, 737.0, 182.7, 737.0, 180.9, 723.4, +188.3, 722.5, 186.8, 710.9, 192.8, 698.4, 190.6, 729.9, 191.8, 731.2, +199.2, 762.1, 236.2, 411.3, 233.8, 419.9, 235.6, 420.4, 234.9, 429.5, +234.5, 434.5, 234.5, 434.5, 234.2, 439.5, 233.2, 453.4, 233.2, 453.4, +232.2, 467.3, 231.7, 473.0, 231.7, 473.0, 231.3, 478.7, 229.9, 497.9, +231.2, 498.1, 228.5, 517.2, 227.6, 517.0, 225.0, 523.0, 224.3, 529.2, +235.1, 554.2, 204.3, 563.1, 199.8, 598.9, 204.3, 603.4, 194.9, 612.9, +189.9, 626.9, 193.1, 620.6, 191.5, 619.8, 193.0, 612.6, 197.7, 591.0, +197.7, 591.0, 202.3, 569.3, 204.0, 561.3, 204.0, 561.3, 205.8, 553.2, +209.1, 537.8, 209.1, 537.8, 212.4, 522.3, 218.1, 495.7, 218.1, 495.7, +223.8, 469.2, 230.0, 440.3, 228.3, 439.8, 236.2, 411.3, 348.6, 878.3, +346.2, 840.7, 363.8, 822.4, 343.8, 803.1, 345.5, 776.0, 350.3, 776.3, +356.8, 749.4, 361.1, 731.7, 358.3, 730.5, 365.4, 714.0, 361.6, 722.8, +364.4, 724.0, 363.4, 734.1, 362.4, 743.8, 362.4, 743.8, 361.4, 753.6, +360.9, 758.8, 360.9, 758.8, 360.3, 764.1, 360.0, 767.1, 360.0, 767.1, +359.7, 770.2, 359.2, 775.3, 359.1, 775.3, 358.6, 780.4, 354.5, 820.5, +354.5, 820.5, 350.4, 860.7, 349.5, 869.5, 347.6, 869.7, 348.6, 878.3, +424.8, 241.2, 429.7, 281.8, 429.7, 281.8, 434.6, 322.4, 432.1, 313.3, +429.0, 314.1, 423.4, 305.9, 419.6, 275.8, 424.1, 275.2, 424.7, 244.6, +424.8, 242.9, 425.0, 242.8, 424.8, 241.2, 278.9, 391.8, 258.1, 432.7, +256.9, 432.0, 234.8, 472.2, 233.1, 475.5, 230.4, 476.9, 231.3, 478.7, +231.7, 473.0, 231.7, 473.0, 232.2, 467.3, 244.9, 442.6, 246.9, 443.6, +261.6, 419.8, 270.2, 405.8, 271.4, 406.4, 278.9, 391.8, 142.6, 812.3, +142.0, 745.0, 143.1, 745.0, 143.6, 677.7, 143.8, 660.2, 144.9, 660.2, +143.9, 642.7, 143.9, 642.7, 143.9, 642.7, 143.9, 642.6, 144.5, 656.6, +149.1, 656.4, 154.3, 670.2, 155.2, 672.8, 155.2, 673.1, 155.0, 675.9, +150.4, 732.9, 149.8, 732.8, 144.7, 789.8, 143.7, 801.1, 142.5, 801.1, +142.6, 812.3, 166.1, 703.6, 176.1, 732.7, 175.0, 733.1, 186.1, 761.7, +187.3, 770.3, 187.3, 770.3, 188.5, 778.9, 183.8, 801.5, 180.9, 800.9, +173.4, 823.0, 173.4, 823.1, 173.5, 823.2, 173.5, 823.2, 173.5, 823.2, +173.4, 823.1, 173.4, 823.0, 171.5, 807.5, 171.5, 807.5, 169.5, 791.9, +165.2, 757.5, 162.3, 757.6, 160.9, 723.1, 160.5, 713.5, 169.8, 709.3, +166.1, 703.6, 160.9, 723.1, 152.3, 701.7, 157.9, 699.5, 155.0, 675.9, +155.2, 673.1, 155.2, 672.8, 154.3, 670.2, 156.0, 674.9, 156.0, 674.9, +157.8, 679.7, 162.5, 691.5, 162.0, 691.7, 166.1, 703.6, 169.8, 709.3, +160.5, 713.5, 160.9, 723.1, 90.3, 188.5, 91.4, 191.9, 92.7, 191.9, +92.6, 195.2, 97.0, 229.5, 104.1, 228.6, 115.5, 261.9, 120.9, 312.4, +121.9, 312.3, 128.3, 362.6, 127.0, 342.9, 124.1, 343.2, 119.8, 323.7, +119.2, 321.0, 119.2, 321.0, 118.7, 318.3, 114.6, 299.8, 114.6, 299.8, +110.6, 281.3, 100.4, 234.9, 100.0, 235.0, 90.3, 188.5, 55.9, 88.2, +58.2, 95.1, 58.2, 95.1, 60.6, 101.9, 51.6, 122.9, 61.3, 127.0, +62.1, 152.1, 51.9, 122.6, 56.8, 120.2, 55.9, 88.2, 128.4, 435.2, +112.5, 419.8, 115.6, 412.2, 96.5, 404.4, 88.8, 396.0, 89.7, 395.1, +82.9, 385.9, 82.7, 385.3, 82.6, 385.4, 82.2, 384.9, 88.2, 391.3, +88.1, 391.4, 94.0, 397.8, 111.2, 416.5, 120.2, 413.2, 128.4, 435.2, +59.1, 353.3, 49.3, 339.9, 51.9, 336.6, 39.5, 326.5, 39.3, 325.6, +39.4, 325.6, 39.1, 324.7, 38.9, 324.0, 39.0, 324.0, 38.9, 323.2, +51.2, 297.2, 65.4, 294.0, 61.2, 270.1, 62.8, 266.8, 62.8, 266.8, +64.4, 263.4, 63.2, 308.4, 74.8, 313.5, 59.1, 353.3, 64.4, 263.4, +65.7, 260.7, 67.4, 260.4, 67.0, 257.9, 72.4, 272.6, 72.4, 272.6, +77.7, 287.3, 83.2, 291.6, 76.6, 299.7, 76.0, 312.1, 76.0, 314.7, +75.8, 314.6, 75.7, 317.2, 82.3, 326.3, 62.3, 336.1, 60.9, 355.8, +60.0, 354.6, 60.0, 354.6, 59.1, 353.3, 74.8, 313.5, 63.2, 308.4, +64.4, 263.4, 94.6, 422.5, 88.8, 404.2, 88.9, 404.1, 82.9, 385.9, +89.7, 395.1, 88.8, 396.0, 96.5, 404.4, 108.9, 409.5, 105.8, 417.1, +115.1, 429.8, 117.5, 432.9, 117.2, 433.1, 119.3, 436.5, 106.1, 431.9, +102.1, 433.0, 94.6, 422.5, 119.3, 436.5, 130.4, 454.3, 130.0, 454.6, +141.5, 472.1, 135.1, 490.1, 135.1, 490.1, 128.8, 508.0, 128.5, 505.7, +125.4, 503.4, 124.8, 503.8, 124.8, 503.8, 124.6, 503.6, 124.4, 503.4, +117.4, 500.8, 119.6, 494.7, 114.9, 486.1, 119.4, 483.8, 104.7, 454.3, +94.6, 422.5, 102.1, 433.0, 106.1, 431.9, 119.3, 436.5, 93.3, 695.5, +93.8, 702.6, 91.2, 708.1, 94.4, 709.6, 89.1, 714.5, 89.1, 714.5, +83.8, 719.4, 83.9, 719.1, 79.8, 717.4, 75.8, 715.5, 68.6, 706.3, +67.0, 706.5, 56.3, 701.2, 56.1, 701.0, 56.1, 701.0, 55.9, 700.7, +61.0, 692.4, 52.8, 687.4, 49.7, 674.1, 69.7, 671.4, 74.7, 680.8, +93.3, 695.5, 49.7, 674.1, 49.3, 672.3, 49.3, 672.3, 48.9, 670.5, +58.1, 672.3, 70.0, 661.3, 72.2, 648.9, 80.8, 650.5, 80.8, 650.5, +89.4, 652.2, 90.7, 668.6, 87.9, 684.0, 92.5, 684.9, 92.9, 690.2, +92.9, 690.2, 93.3, 695.5, 74.7, 680.8, 69.7, 671.4, 49.7, 674.1, +855.7, 644.3, 864.1, 655.0, 862.1, 657.6, 872.6, 665.6, 867.3, 669.8, +867.3, 669.8, 861.9, 674.1, 855.1, 664.1, 839.5, 674.7, 817.1, 675.3, +814.8, 664.3, 834.4, 648.1, 855.7, 644.3, 850.6, 593.0, 839.2, 607.1, +835.7, 605.4, 827.8, 621.3, 824.4, 623.7, 821.5, 619.7, 815.2, 618.2, +805.9, 616.0, 805.7, 616.5, 796.5, 613.7, 796.7, 613.2, 796.7, 613.2, +796.8, 612.7, 806.7, 608.6, 806.9, 609.0, 817.0, 605.3, 833.8, 599.1, +848.1, 589.4, 850.6, 593.0, 550.6, 346.8, 543.4, 335.2, 544.7, 334.1, +536.1, 323.7, 535.4, 316.0, 538.8, 312.6, 534.6, 308.4, 560.5, 326.1, +560.5, 326.1, 586.5, 343.8, 582.3, 356.2, 587.4, 357.9, 588.3, 372.0, +570.6, 373.5, 567.0, 362.0, 550.6, 346.8, 588.3, 372.0, 588.8, 379.2, +586.2, 380.6, 589.2, 386.5, 595.0, 392.5, 585.9, 399.5, 590.6, 408.4, +582.9, 397.1, 582.9, 397.1, 575.2, 385.9, 565.0, 365.3, 562.9, 366.3, +550.6, 346.8, 567.0, 362.0, 570.6, 373.5, 588.3, 372.0, 706.7, 478.9, +709.8, 483.0, 713.1, 483.1, 713.0, 487.0, 713.1, 488.1, 712.7, 488.6, +713.3, 489.1, 713.6, 489.3, 713.2, 490.0, 713.5, 490.2, 710.9, 503.7, +716.1, 504.7, 718.6, 519.2, 707.0, 525.6, 711.3, 533.5, 704.0, 547.8, +694.7, 516.5, 701.7, 512.8, 706.7, 478.9, 922.2, 514.6, 918.6, 541.0, +913.8, 541.2, 915.0, 567.3, 913.1, 566.1, 913.1, 566.1, 911.3, 564.9, +910.8, 564.5, 910.9, 564.3, 910.5, 563.7, 912.9, 551.4, 913.4, 551.5, +916.3, 539.2, 916.9, 536.7, 916.9, 536.7, 917.5, 534.2, 919.9, 524.4, +921.4, 524.5, 922.2, 514.6, 868.0, 523.0, 871.7, 528.3, 871.8, 528.1, +875.4, 533.5, 880.0, 540.1, 880.9, 539.6, 884.7, 546.7, 882.9, 545.5, +882.5, 544.0, 881.1, 544.3, 881.2, 544.2, 876.3, 539.0, 874.5, 539.8, +875.5, 535.3, 864.1, 532.8, 853.8, 525.7, 847.5, 522.2, 848.3, 520.8, +842.9, 516.0, 811.2, 477.0, 810.7, 477.4, 777.8, 439.4, 764.3, 422.8, +764.3, 422.8, 750.9, 406.3, 794.4, 444.7, 792.0, 447.3, 833.2, 488.3, +850.6, 505.7, 851.2, 505.1, 868.0, 523.0, 800.2, 369.8, 812.1, 386.9, +808.4, 391.3, 823.9, 404.0, 850.1, 450.0, 852.8, 448.7, 884.2, 491.5, +887.5, 513.7, 885.0, 514.4, 890.9, 536.0, 891.2, 536.4, 890.9, 536.6, +891.0, 537.3, 856.2, 473.4, 856.3, 473.3, 821.7, 409.3, 810.9, 389.5, +794.8, 382.7, 800.2, 369.8, 906.3, 160.9, 920.0, 170.9, 919.3, 171.9, +933.6, 180.8, 935.5, 182.7, 933.6, 187.9, 934.2, 187.9, 907.8, 185.9, +908.1, 182.4, 882.0, 176.8, 878.8, 176.1, 878.8, 176.1, 875.6, 175.5, +868.4, 168.9, 864.6, 173.1, 853.6, 170.8, 877.1, 159.7, 881.0, 157.7, +906.3, 160.9, 938.0, 227.0, 943.7, 234.1, 941.1, 238.1, 940.0, 248.8, +940.2, 247.6, 937.7, 247.7, 936.1, 245.9, 907.6, 209.3, 909.7, 206.5, +875.6, 175.5, 878.8, 176.1, 878.8, 176.1, 882.0, 176.8, 910.9, 200.7, +914.7, 198.1, 938.0, 227.0, 882.0, 176.8, 908.1, 182.4, 907.8, 185.9, +934.2, 187.9, 945.0, 197.5, 932.2, 225.8, 938.0, 227.0, 914.7, 198.1, +910.9, 200.7, 882.0, 176.8, 913.4, 228.8, 924.8, 237.3, 924.8, 237.3, +936.1, 245.9, 937.7, 247.7, 940.2, 247.6, 940.0, 248.8, 940.1, 248.9, +940.0, 249.0, 940.1, 249.1, 934.5, 244.9, 934.5, 244.9, 929.0, 240.6, +925.8, 238.2, 925.8, 238.2, 922.7, 235.8, 918.0, 232.3, 918.1, 232.3, +913.4, 228.8, 681.9, 99.4, 674.2, 94.0, 674.0, 93.0, 669.1, 84.8, +670.9, 84.4, 671.9, 85.1, 672.7, 84.0, 673.3, 81.8, 678.3, 83.9, +682.9, 81.8, 696.7, 78.9, 697.8, 73.4, 710.6, 75.9, 721.9, 78.2, +720.8, 83.6, 731.1, 91.4, 735.2, 94.5, 735.9, 98.2, 739.3, 97.6, +715.3, 102.1, 714.6, 98.4, 689.9, 99.1, 685.9, 99.3, 684.6, 101.2, +681.9, 99.4, 767.4, 197.3, 774.3, 201.8, 772.5, 209.7, 778.7, 210.2, +766.2, 203.2, 766.9, 201.7, 753.8, 196.2, 720.3, 174.2, 722.5, 153.6, +687.8, 150.7, 729.3, 154.2, 728.8, 172.1, 767.4, 197.3, 862.9, 277.6, +867.0, 277.9, 867.9, 276.4, 871.1, 278.3, 874.9, 280.3, 875.3, 279.8, +878.8, 282.3, 883.0, 285.2, 883.2, 288.4, 887.3, 288.2, 887.1, 288.3, +886.8, 288.3, 886.8, 288.4, 870.8, 290.2, 867.9, 292.0, 856.1, 303.1, +856.0, 302.9, 853.8, 304.2, 851.6, 305.3, 816.2, 322.3, 817.1, 324.5, +780.8, 339.3, 782.3, 338.7, 780.3, 335.4, 782.0, 333.8, 789.5, 326.7, +790.6, 327.8, 799.3, 321.8, 802.4, 319.6, 802.4, 319.6, 805.6, 317.4, +834.2, 297.5, 833.0, 295.4, 862.9, 277.6, 657.9, 132.4, 654.5, 130.0, +655.6, 128.2, 652.1, 126.1, 669.1, 137.8, 684.1, 135.7, 686.0, 149.5, +686.9, 150.1, 686.9, 150.1, 687.8, 150.7, 720.3, 173.2, 720.2, 173.3, +752.8, 195.8, 753.2, 196.1, 753.4, 195.9, 753.8, 196.2, 761.2, 199.3, +760.5, 200.8, 767.2, 205.4, 764.9, 203.8, 764.9, 203.9, 762.5, 202.3, +757.6, 199.0, 757.6, 199.0, 752.8, 195.8, 705.4, 164.1, 704.8, 164.9, +657.9, 132.4, 625.6, 107.8, 638.8, 117.0, 638.8, 117.0, 652.1, 126.1, +655.6, 128.2, 654.5, 130.0, 657.9, 132.4, 661.1, 135.9, 661.1, 135.9, +664.3, 139.4, 666.3, 141.5, 666.0, 142.0, 668.3, 143.7, 662.0, 139.2, +662.4, 138.7, 656.5, 133.7, 646.2, 125.1, 646.2, 125.1, 635.9, 116.5, +630.8, 112.2, 631.3, 111.2, 625.6, 107.8, 529.6, 223.2, 534.4, 238.6, +552.7, 230.3, 570.7, 244.0, 580.3, 256.7, 577.6, 260.4, 589.9, 269.3, +583.2, 266.0, 583.2, 266.0, 576.5, 262.7, 552.2, 244.1, 537.3, 247.9, +529.6, 223.2, 576.5, 262.7, 542.1, 245.5, 542.5, 244.8, 507.7, 228.3, +491.6, 218.8, 485.1, 223.3, 475.5, 209.3, 462.4, 196.0, 462.4, 196.0, +449.3, 182.6, 451.0, 184.5, 451.8, 183.9, 454.2, 185.1, 491.9, 204.2, +494.1, 200.7, 529.6, 223.2, 537.3, 247.9, 552.2, 244.1, 576.5, 262.7, +454.2, 185.1, 451.8, 183.9, 451.0, 184.5, 449.3, 182.6, 449.3, 182.6, +449.3, 182.6, 449.3, 182.6, 436.6, 157.6, 430.6, 159.3, 408.0, 140.6, +408.6, 140.5, 408.6, 140.5, 409.3, 140.3, 415.1, 145.5, 414.8, 145.9, +420.4, 151.4, 434.4, 165.4, 434.4, 165.4, 448.4, 179.4, 451.3, 182.2, +453.2, 181.7, 454.2, 185.1, 613.8, 318.3, 609.5, 309.1, 605.8, 299.8, +605.3, 300.0, 605.1, 297.0, 605.1, 297.0, 604.9, 294.0, 605.3, 294.2, +609.6, 291.0, 609.4, 288.2, 617.2, 292.8, 617.2, 292.8, 625.1, 297.5, +629.5, 310.4, 631.5, 313.3, 643.3, 320.2, 644.4, 323.5, 643.2, 325.5, +645.5, 326.8, 647.2, 327.6, 645.5, 330.3, 647.2, 331.9, 654.4, 331.7, +655.2, 355.4, 663.1, 378.8, 631.4, 365.8, 636.9, 349.7, 613.8, 318.3, +663.1, 378.8, 665.6, 386.2, 665.9, 393.6, 668.1, 393.5, 665.6, 394.7, +663.0, 395.4, 663.1, 395.9, 657.0, 391.8, 657.0, 391.8, 650.9, 387.6, +645.7, 384.7, 646.5, 383.2, 642.2, 378.7, 633.7, 347.0, 628.0, 348.5, +613.8, 318.3, 636.9, 349.7, 631.4, 365.8, 663.1, 378.8, 499.3, 283.8, +494.8, 281.0, 494.6, 281.3, 490.3, 278.3, 488.5, 277.1, 488.5, 277.1, +486.8, 275.9, 493.1, 279.8, 493.2, 279.7, 499.3, 283.8, 745.7, 58.1, +738.0, 64.9, 735.2, 63.3, 730.2, 71.7, 721.6, 76.1, 720.4, 73.8, +710.6, 75.9, 697.8, 73.4, 696.7, 78.9, 682.9, 81.8, 684.2, 81.2, +683.7, 80.2, 684.5, 78.6, 714.6, 67.2, 714.3, 62.8, 745.7, 58.1, +684.5, 78.6, 693.9, 59.1, 695.5, 59.7, 703.4, 39.5, 715.2, 34.3, +715.7, 35.3, 727.1, 29.1, 740.2, 32.1, 738.4, 39.7, 750.0, 50.0, +751.2, 51.1, 752.8, 51.7, 752.7, 51.9, 750.0, 51.3, 749.2, 55.0, +745.7, 58.1, 714.3, 62.8, 714.6, 67.2, 684.5, 78.6, 542.1, 33.9, +543.6, 32.5, 545.2, 32.4, 545.1, 31.1, 553.1, 61.2, 553.1, 61.2, +561.1, 91.2, 561.8, 66.9, 553.0, 66.6, 544.8, 42.1, 543.5, 38.0, +542.0, 37.9, 542.1, 33.9, 407.5, 129.4, 417.9, 114.9, 430.0, 102.1, +428.3, 100.5, 434.4, 92.1, 434.4, 92.1, 440.4, 83.6, 447.0, 74.6, +447.0, 74.6, 453.5, 65.5, 459.8, 56.7, 459.8, 56.7, 466.1, 47.9, +487.4, 18.9, 487.9, 19.2, 508.1, -10.5, 509.0, -11.6, 509.0, -11.6, +509.8, -12.8, 518.4, -24.7, 515.8, -28.1, 527.0, -36.7, 527.2, -32.2, +528.2, -32.2, 529.4, -27.8, 519.7, -10.1, 516.9, -11.6, 504.3, 4.5, +492.4, 20.0, 492.4, 20.0, 480.4, 35.4, 462.3, 58.7, 462.3, 58.7, +444.3, 82.0, 425.9, 105.7, 427.1, 106.7, 407.5, 129.4, 638.1, -51.9, +648.3, -56.7, 681.7, -32.3, 682.2, -11.8, 659.3, 3.5, 661.0, 6.1, +639.9, 23.9, 642.7, 22.6, 639.7, 16.2, 639.5, 8.4, 638.8, -21.7, +627.0, -46.6, 638.1, -51.9, 590.4, 20.7, 590.0, 21.0, 591.9, 23.2, +593.4, 25.8, 600.9, 38.2, 611.7, 42.7, 608.4, 50.5, 588.8, 67.1, +588.0, 66.3, 569.1, 83.6, 568.2, 78.7, 569.0, 78.4, 567.3, 73.7, +562.9, 63.6, 565.2, 62.6, 563.1, 51.4, 570.9, 33.5, 574.9, 33.8, +590.4, 20.7, 563.1, 51.4, 560.4, 36.7, 560.4, 36.7, 557.7, 22.0, +558.4, 22.2, 563.3, 3.6, 568.9, -14.7, 567.4, -13.1, 573.7, -6.8, +578.5, 1.0, 583.6, 9.6, 583.6, 9.6, 588.8, 18.1, 589.6, 19.4, +590.7, 20.3, 590.4, 20.7, 574.9, 33.8, 570.9, 33.5, 563.1, 51.4, +381.2, 91.7, 379.0, 83.0, 379.0, 83.0, 376.8, 74.3, 398.1, 75.3, +406.4, 74.7, 420.2, 60.1, 422.4, 62.5, 422.7, 62.3, 424.5, 65.0, +424.7, 65.3, 424.7, 65.3, 424.9, 65.5, 429.1, 70.4, 432.4, 75.9, +433.3, 75.3, 410.5, 89.0, 407.1, 92.2, 381.2, 91.7, 433.3, 75.3, +436.2, 74.9, 441.1, 80.3, 440.4, 83.6, 434.4, 92.1, 434.4, 92.1, +428.3, 100.5, 419.0, 91.7, 405.6, 101.1, 385.5, 108.7, 383.3, 100.2, +383.3, 100.2, 381.2, 91.7, 407.1, 92.2, 410.5, 89.0, 433.3, 75.3, +389.3, 14.2, 383.0, 5.0, 383.0, 5.0, 376.6, -4.2, 390.5, 7.5, +392.6, 4.9, 408.7, 14.0, 405.6, 9.6, 396.6, 18.3, 389.3, 14.2, +436.9, -32.1, 422.6, -36.7, 419.5, -26.5, 402.0, -21.5, 401.0, -21.6, +400.6, -21.2, 400.1, -21.7, 390.0, -26.2, 383.0, -17.7, 376.9, -24.1, +371.8, -27.7, 369.8, -25.0, 362.6, -25.6, 370.0, -27.5, 370.0, -27.5, +377.4, -29.4, 407.0, -32.0, 410.3, -40.7, 436.9, -32.1, 377.4, -29.4, +388.0, -32.1, 387.8, -33.8, 398.6, -34.9, 399.3, -35.1, 399.3, -34.9, +400.0, -35.1, 407.0, -36.9, 407.0, -37.0, 414.0, -38.8, 441.9, -46.0, +441.9, -45.9, 469.8, -53.0, 471.6, -53.4, 471.6, -53.4, 473.5, -53.9, +508.4, -62.5, 508.4, -62.5, 543.4, -71.1, 543.5, -71.2, 546.8, -66.8, +549.1, -67.4, 548.5, -66.6, 548.5, -66.6, 548.0, -65.9, 523.9, -58.0, +523.8, -58.5, 499.5, -51.2, 493.8, -49.4, 493.8, -49.4, 488.0, -47.7, +474.0, -43.4, 474.0, -43.4, 460.0, -39.1, 448.4, -35.6, 448.7, -33.5, +436.9, -32.1, 410.3, -40.7, 407.0, -32.0, 377.4, -29.4, 413.6, -20.3, +407.8, -20.9, 407.8, -20.9, 402.0, -21.5, 419.5, -26.5, 422.6, -36.7, +436.9, -32.1, 448.7, -33.5, 448.4, -35.6, 460.0, -39.1, 437.7, -27.9, +437.4, -27.6, 413.6, -20.3, 262.6, 59.6, 266.1, 47.2, 266.1, 47.2, +269.6, 34.9, 275.0, 35.4, 273.9, 47.9, 278.3, 61.0, 280.9, 68.7, +282.6, 68.5, 283.5, 76.5, 283.3, 74.8, 281.6, 75.0, 279.7, 73.4, +278.0, 72.0, 278.0, 72.0, 276.3, 70.7, 269.4, 65.1, 263.8, 66.2, +262.6, 59.6, 258.3, 282.1, 242.0, 274.1, 239.8, 263.1, 225.8, 266.0, +226.1, 264.6, 220.4, 263.4, 215.0, 260.7, 215.6, 260.1, 215.2, 259.7, +215.5, 258.6, 231.4, 266.1, 230.9, 267.1, 246.4, 275.6, 252.4, 278.8, +252.2, 279.3, 258.3, 282.1, 328.2, 263.3, 327.4, 271.4, 317.3, 278.9, +316.7, 278.6, 304.2, 270.5, 309.3, 262.4, 302.0, 246.3, 292.6, 225.6, +289.8, 226.5, 283.1, 204.9, 281.7, 200.4, 287.8, 196.8, 285.8, 194.3, +306.2, 219.1, 302.8, 221.9, 319.8, 249.5, 324.0, 256.4, 328.9, 256.9, +328.2, 263.3, 302.0, 246.3, 309.3, 262.4, 304.2, 270.5, 316.7, 278.6, +317.4, 281.6, 313.8, 282.4, 310.9, 286.3, 304.9, 294.2, 305.5, 301.5, +298.9, 302.1, 287.0, 303.2, 286.3, 295.9, 273.8, 289.7, 273.2, 289.5, +272.7, 289.1, 272.7, 289.2, 286.8, 267.4, 283.3, 250.8, 302.0, 246.3, +272.7, 289.2, 272.7, 289.2, 272.6, 289.1, 272.4, 289.1, 272.4, 286.8, +267.9, 286.8, 263.4, 284.6, 262.5, 271.2, 266.8, 270.9, 270.2, 257.1, +276.7, 231.0, 269.4, 209.6, 283.1, 204.9, 289.8, 226.5, 292.6, 225.6, +302.0, 246.3, 283.3, 250.8, 286.8, 267.4, 272.7, 289.2, 355.1, 114.2, +354.4, 113.6, 355.4, 111.8, 354.9, 111.6, 355.9, 114.6, 357.8, 114.0, +360.7, 116.3, 360.6, 115.1, 357.3, 116.0, 355.1, 114.2, 290.3, 313.5, +264.4, 347.9, 264.3, 347.9, 238.3, 382.2, 230.2, 388.0, 231.9, 390.5, +225.7, 398.9, 200.5, 426.6, 203.0, 428.9, 180.4, 458.9, 176.5, 467.1, +171.8, 464.8, 163.2, 470.8, 180.2, 443.2, 183.7, 445.4, 204.3, 420.0, +243.4, 371.5, 243.4, 371.5, 282.5, 323.1, 284.3, 320.9, 284.3, 320.9, +286.0, 318.8, 288.1, 316.1, 288.2, 316.2, 290.3, 313.5, 176.4, 420.6, +168.2, 442.5, 164.8, 441.2, 153.1, 461.8, 153.0, 462.3, 152.8, 462.2, +152.7, 462.6, 167.5, 420.8, 166.8, 420.5, 182.4, 379.0, 181.0, 382.6, +181.8, 382.9, 181.3, 386.7, 178.8, 403.7, 182.3, 404.9, 176.4, 420.6, +177.5, 256.5, 178.6, 254.5, 179.3, 254.6, 179.6, 252.5, 203.3, 213.2, +200.9, 211.7, 222.2, 171.0, 225.6, 158.8, 229.8, 160.1, 235.8, 148.5, +235.5, 149.5, 235.5, 149.5, 235.3, 150.5, 230.0, 160.7, 229.8, 160.6, +224.3, 170.6, 214.9, 187.9, 214.9, 187.9, 205.5, 205.2, 192.6, 228.8, +192.5, 228.8, 179.6, 252.5, 179.3, 254.6, 178.6, 254.5, 177.5, 256.5, +146.0, 348.1, 145.8, 345.7, 145.5, 345.7, 145.6, 343.2, 146.0, 329.6, +141.9, 317.5, 146.4, 316.0, 151.6, 306.0, 151.6, 306.0, 156.8, 296.1, +155.4, 298.3, 156.2, 298.9, 155.7, 301.6, 154.8, 305.8, 154.8, 305.8, +154.0, 309.9, 150.0, 329.0, 150.8, 329.2, 146.0, 348.1, 159.0, 237.4, +147.8, 258.1, 146.3, 257.4, 136.6, 278.7, 137.5, 255.7, 137.5, 255.7, +138.4, 232.7, 155.7, 212.2, 153.4, 210.2, 168.4, 187.8, 169.4, 188.0, +167.3, 213.8, 159.0, 237.4, 168.4, 187.8, 200.4, 140.1, 204.5, 142.4, +232.3, 92.4, 235.7, 87.8, 236.4, 88.2, 239.2, 83.3, 219.1, 123.5, +219.1, 123.5, 199.0, 163.7, 206.9, 171.3, 179.0, 200.6, 159.0, 237.4, +167.3, 213.8, 169.4, 188.0, 168.4, 187.8, 471.9, 840.0, 468.5, 791.8, +468.5, 791.8, 465.1, 743.6, 463.7, 718.3, 464.4, 718.2, 463.6, 692.9, +463.5, 690.2, 463.4, 690.2, 463.3, 687.6, 463.2, 686.9, 463.2, 686.2, +463.2, 686.2, 463.2, 686.2, 463.2, 686.9, 463.3, 687.6, 463.4, 690.2, +463.5, 690.2, 463.6, 692.9, 467.8, 766.4, 469.7, 766.4, 471.9, 840.0, +704.6, 772.1, 709.6, 768.3, 709.0, 767.6, 713.4, 763.0, 716.6, 759.7, +716.6, 759.7, 719.8, 756.4, 725.4, 750.5, 725.4, 750.5, 731.1, 744.7, +735.2, 740.4, 735.2, 740.4, 739.3, 736.1, 751.8, 723.2, 750.1, 721.0, +764.3, 710.3, 765.7, 712.6, 766.5, 712.4, 767.2, 714.9, 768.1, 717.4, +768.7, 717.2, 770.2, 719.5, 739.2, 747.8, 738.0, 746.6, 704.6, 772.1, +530.8, 680.6, 529.6, 688.2, 529.9, 688.2, 529.0, 695.8, 526.4, 716.5, +526.4, 716.5, 523.8, 737.3, 519.5, 772.2, 519.5, 772.2, 515.2, 807.1, +512.6, 828.3, 512.6, 828.3, 510.0, 849.6, 508.0, 865.3, 511.1, 866.3, +506.1, 880.9, 505.7, 882.1, 499.2, 880.7, 499.2, 881.1, 505.3, 820.4, +508.7, 820.8, 518.2, 760.4, 524.5, 720.5, 524.2, 720.5, 530.8, 680.6, +504.4, 759.9, 504.4, 760.3, 504.4, 760.3, 504.3, 760.8, 496.6, 802.0, +496.7, 802.1, 490.8, 843.6, 489.1, 837.4, 485.8, 836.4, 487.4, 831.1, +486.4, 819.9, 486.4, 819.9, 485.3, 808.6, 485.3, 808.6, 483.9, 793.3, +482.5, 778.1, 485.1, 756.8, 480.5, 747.8, 494.2, 736.4, 491.4, 738.7, +499.5, 748.0, 504.4, 759.9, 494.2, 736.4, 501.4, 685.9, 537.8, 673.8, +521.8, 637.3, 512.1, 698.4, 513.1, 698.6, 504.4, 759.9, 499.5, 748.0, +491.4, 738.7, 494.2, 736.4, 572.6, 410.9, 576.4, 416.8, 576.4, 416.8, +580.1, 422.7, 579.7, 424.1, 580.0, 424.7, 580.8, 426.0, 580.2, 430.4, +579.6, 430.3, 578.5, 434.6, 577.9, 436.5, 578.4, 438.1, 577.4, 438.4, +563.8, 442.5, 563.3, 440.9, 549.3, 443.3, 545.6, 443.9, 543.5, 442.4, +541.9, 444.6, 555.1, 426.2, 553.8, 421.7, 572.6, 410.9, 482.0, 772.1, +480.0, 750.5, 480.1, 750.5, 478.0, 728.9, 478.3, 721.1, 484.7, 720.8, +484.0, 713.4, 486.7, 742.4, 492.0, 746.3, 482.0, 772.1, 446.9, 345.2, +448.3, 351.9, 446.0, 352.4, 445.1, 359.6, 444.8, 361.9, 444.1, 362.0, +444.5, 364.1, 443.9, 357.8, 443.9, 357.8, 443.4, 351.4, 443.8, 348.2, +447.5, 347.8, 446.9, 345.2, 406.2, 718.4, 412.9, 726.6, 407.7, 747.1, +403.8, 747.8, 396.2, 749.3, 393.5, 735.4, 383.3, 722.9, 376.1, 714.2, +374.3, 704.6, 369.0, 705.6, 385.7, 702.3, 395.6, 705.4, 406.2, 718.4, +451.5, 559.9, 451.9, 567.7, 451.9, 567.7, 452.4, 575.5, 452.6, 578.7, +452.6, 578.7, 452.8, 581.9, 453.1, 588.3, 453.1, 588.3, 453.5, 594.6, +455.3, 625.3, 455.3, 625.3, 457.1, 655.9, 457.9, 669.3, 457.9, 669.3, +458.7, 682.6, 460.2, 708.3, 460.1, 708.3, 461.7, 734.0, 463.2, 759.1, +463.3, 759.1, 464.9, 784.3, 464.9, 784.9, 464.8, 784.9, 464.7, 785.5, +463.1, 759.8, 463.2, 759.7, 461.7, 734.0, 460.1, 708.3, 460.2, 708.3, +458.7, 682.6, 457.9, 669.3, 457.9, 669.3, 457.1, 655.9, 455.3, 625.3, +455.3, 625.3, 453.5, 594.6, 453.1, 588.3, 453.1, 588.3, 452.8, 581.9, +452.6, 578.7, 452.6, 578.7, 452.4, 575.5, 451.9, 567.7, 451.9, 567.7, +451.5, 559.9, 358.6, 780.4, 359.1, 775.3, 359.2, 775.3, 359.7, 770.2, +360.0, 767.1, 360.0, 767.1, 360.3, 764.1, 360.9, 758.8, 360.9, 758.8, +361.4, 753.6, 362.4, 743.8, 362.4, 743.8, 363.4, 734.1, 364.4, 724.0, +361.6, 722.8, 365.4, 714.0, 365.5, 713.7, 365.5, 713.7, 365.5, 713.5, +364.5, 723.8, 364.5, 723.8, 363.4, 734.1, 362.4, 743.8, 362.4, 743.8, +361.4, 753.6, 360.9, 758.8, 360.9, 758.8, 360.3, 764.1, 360.0, 767.1, +360.0, 767.1, 359.7, 770.2, 359.2, 775.3, 359.1, 775.3, 358.6, 780.4, +419.4, 196.3, 422.1, 218.7, 422.1, 218.7, 424.8, 241.2, 425.0, 242.8, +424.8, 242.9, 424.7, 244.6, 423.4, 234.8, 423.6, 234.8, 422.5, 225.0, +421.0, 210.6, 421.3, 210.6, 419.4, 196.3, 356.8, 749.4, 350.3, 776.3, +345.5, 776.0, 343.8, 803.1, 354.5, 813.4, 336.9, 831.8, 329.9, 860.4, +330.6, 857.7, 330.0, 857.6, 330.6, 854.9, 343.4, 802.1, 343.4, 802.1, +356.8, 749.4, 369.0, 519.0, 376.4, 514.0, 386.1, 528.3, 403.2, 537.7, +403.4, 537.8, 403.4, 537.8, 403.6, 538.0, 405.6, 539.1, 407.7, 539.3, +407.6, 540.2, 405.2, 559.0, 409.8, 571.4, 398.6, 577.3, 394.5, 579.5, +387.8, 566.8, 377.0, 556.3, 376.7, 556.1, 376.5, 556.1, 376.5, 555.8, +372.5, 537.4, 363.0, 523.0, 369.0, 519.0, 376.5, 555.8, 376.3, 552.5, +373.2, 552.6, 370.0, 549.5, 362.3, 542.1, 362.3, 542.1, 354.7, 534.6, +341.8, 522.1, 341.8, 522.1, 329.0, 509.6, 314.1, 495.1, 316.5, 484.7, +299.2, 480.6, 336.5, 489.3, 341.5, 492.2, 369.0, 519.0, 363.0, 523.0, +372.5, 537.4, 376.5, 555.8, 403.2, 537.7, 386.1, 528.3, 376.4, 514.0, +369.0, 519.0, 341.5, 492.2, 336.5, 489.3, 299.2, 480.6, 295.0, 478.2, +296.3, 475.1, 292.1, 473.7, 302.0, 476.9, 301.3, 479.0, 310.5, 484.3, +356.8, 511.0, 357.2, 510.5, 403.2, 537.7, 324.0, 409.5, 317.7, 409.2, +311.5, 396.8, 312.2, 396.0, 316.9, 390.7, 323.6, 396.7, 334.9, 397.3, +338.5, 397.5, 340.5, 399.4, 342.0, 397.7, 335.1, 405.5, 332.6, 410.0, +324.0, 409.5, 278.7, 425.6, 285.6, 411.6, 288.9, 412.4, 292.4, 397.5, +267.8, 486.1, 267.7, 486.1, 242.9, 574.7, 250.8, 548.1, 249.4, 547.7, +255.8, 520.7, 267.2, 473.2, 267.2, 473.2, 278.6, 425.7, 278.7, 425.6, +278.7, 425.6, 278.7, 425.6, 278.6, 425.7, 275.1, 429.0, 276.4, 430.3, +274.1, 435.0, 273.4, 436.3, 273.4, 436.3, 272.8, 437.6, 262.3, 459.0, +262.3, 459.0, 251.8, 480.4, 239.7, 505.1, 242.2, 506.7, 227.6, 529.8, +228.1, 523.5, 229.2, 517.3, 228.5, 517.2, 231.2, 498.1, 229.9, 497.9, +231.3, 478.7, 230.4, 476.9, 233.1, 475.5, 234.8, 472.2, 256.1, 448.4, +255.5, 447.6, 278.6, 425.7, 234.8, 472.2, 256.9, 432.0, 258.1, 432.7, +278.9, 391.8, 294.0, 364.3, 294.0, 364.3, 309.1, 336.7, 309.4, 336.0, +309.5, 336.0, 309.8, 335.3, 301.3, 366.5, 302.9, 367.1, 292.4, 397.5, +288.9, 412.4, 285.6, 411.6, 278.7, 425.6, 278.7, 425.6, 278.7, 425.6, +278.6, 425.7, 255.5, 447.6, 256.1, 448.4, 234.8, 472.2, 173.4, 823.0, +173.4, 823.1, 173.5, 823.2, 173.5, 823.2, 169.0, 836.5, 163.8, 836.8, +164.5, 849.8, 156.3, 851.7, 151.6, 841.8, 142.6, 830.7, 142.7, 830.7, +142.6, 826.8, 142.6, 822.9, 142.6, 817.6, 142.3, 817.6, 142.6, 812.3, +142.5, 801.1, 143.7, 801.1, 144.7, 789.8, 143.9, 791.3, 147.5, 793.0, +150.3, 796.2, 161.8, 809.6, 161.9, 809.6, 173.4, 823.0, 119.8, 323.7, +124.1, 343.2, 127.0, 342.9, 128.3, 362.6, 128.7, 366.0, 129.2, 369.3, +129.2, 369.3, 130.6, 382.7, 130.6, 382.7, 132.1, 396.2, 124.8, 369.2, +120.5, 370.3, 108.8, 344.5, 107.3, 335.3, 122.1, 325.8, 119.8, 323.7, +63.0, 185.6, 57.2, 200.1, 54.3, 199.5, 51.4, 214.6, 49.9, 210.5, +49.9, 210.5, 48.4, 206.4, 53.0, 194.9, 65.5, 192.5, 63.0, 185.6, +105.4, 363.9, 106.3, 366.5, 106.3, 366.5, 107.3, 369.1, 122.3, 400.9, +118.4, 402.7, 129.6, 436.3, 129.3, 435.7, 129.0, 435.8, 128.4, 435.2, +120.2, 413.2, 111.2, 416.5, 94.0, 397.8, 89.6, 384.1, 97.9, 380.0, +105.4, 363.9, 94.0, 397.8, 88.1, 391.4, 88.2, 391.3, 82.2, 384.9, +79.3, 381.0, 75.7, 380.0, 76.5, 377.0, 76.4, 376.3, 75.1, 375.7, +75.3, 375.5, 75.5, 375.2, 74.8, 374.8, 74.3, 374.1, 74.1, 374.0, +74.2, 373.9, 74.1, 373.8, 75.7, 359.1, 74.5, 359.0, 75.0, 344.2, +75.0, 344.2, 90.3, 334.3, 90.8, 323.7, 98.1, 343.8, 98.1, 343.8, +105.4, 363.9, 97.9, 380.0, 89.6, 384.1, 94.0, 397.8, 804.3, 668.0, +797.3, 661.3, 797.3, 661.3, 790.4, 654.6, 793.9, 640.3, 795.5, 639.4, +793.8, 625.1, 794.2, 623.3, 794.7, 621.4, 794.7, 621.4, 795.2, 621.3, +796.2, 619.0, 795.5, 618.0, 795.4, 618.0, 796.0, 615.9, 796.5, 613.7, +805.7, 616.5, 805.9, 616.0, 815.2, 618.2, 818.6, 641.9, 817.6, 648.5, +804.3, 668.0, 815.2, 618.2, 821.5, 619.7, 824.4, 623.7, 827.8, 621.3, +828.2, 620.5, 831.7, 622.2, 835.7, 623.1, 838.1, 626.0, 838.6, 626.1, +842.2, 627.4, 849.0, 635.9, 849.0, 635.9, 855.7, 644.3, 834.4, 648.1, +814.8, 664.3, 817.1, 675.3, 814.5, 675.3, 814.5, 675.3, 811.9, 675.4, +809.7, 676.2, 808.1, 671.7, 804.3, 668.0, 817.6, 648.5, 818.6, 641.9, +815.2, 618.2, 813.9, 548.1, 824.6, 557.5, 824.6, 557.5, 835.3, 566.8, +837.5, 568.8, 837.4, 568.9, 839.5, 570.9, 839.5, 570.9, 847.4, 578.7, +855.2, 586.5, 834.2, 567.7, 833.9, 567.9, 813.9, 548.1, 703.1, 474.3, +704.9, 476.6, 704.9, 476.6, 706.7, 478.9, 701.7, 512.8, 694.7, 516.5, +704.0, 547.8, 700.6, 554.3, 700.6, 554.3, 697.3, 560.8, 694.3, 542.7, +698.6, 542.0, 699.8, 523.1, 700.3, 515.6, 700.3, 515.6, 700.8, 508.2, +701.6, 497.2, 701.6, 497.2, 702.3, 486.2, 702.5, 483.1, 702.5, 483.1, +702.7, 480.0, 702.8, 478.7, 702.8, 478.7, 702.9, 477.3, 703.0, 475.8, +703.5, 474.5, 703.1, 474.3, 918.1, 484.0, 921.1, 492.4, 921.1, 492.4, +924.1, 500.9, 926.8, 505.5, 923.1, 507.7, 922.2, 514.6, 921.4, 524.5, +919.9, 524.4, 917.5, 534.2, 914.2, 509.6, 913.3, 508.2, 918.1, 484.0, +765.5, 384.9, 812.7, 448.1, 811.2, 449.2, 859.8, 511.3, 863.9, 517.2, +863.9, 517.2, 868.0, 523.0, 851.2, 505.1, 850.6, 505.7, 833.2, 488.3, +796.5, 438.8, 810.5, 423.8, 765.5, 384.9, 833.2, 488.3, 792.0, 447.3, +794.4, 444.7, 750.9, 406.3, 745.1, 399.2, 746.0, 393.0, 739.4, 392.2, +751.7, 387.5, 751.7, 387.5, 764.0, 382.8, 763.8, 383.1, 764.8, 383.9, +765.5, 384.9, 810.5, 423.8, 796.5, 438.8, 833.2, 488.3, 789.5, 387.2, +786.9, 381.2, 788.2, 380.2, 784.2, 375.2, 792.1, 372.2, 792.1, 372.2, +799.9, 369.3, 800.0, 369.2, 800.1, 369.5, 800.2, 369.8, 794.8, 382.7, +810.9, 389.5, 821.7, 409.3, 820.1, 403.3, 814.9, 404.7, 808.2, 400.0, +798.9, 393.6, 797.2, 395.2, 789.5, 387.2, 875.3, 138.2, 890.8, 149.6, +890.8, 149.6, 906.3, 160.9, 881.0, 157.7, 877.1, 159.7, 853.6, 170.8, +841.7, 168.3, 840.9, 163.7, 829.8, 165.7, 822.6, 162.9, 818.5, 154.8, +816.9, 156.1, 832.1, 143.9, 836.9, 149.9, 857.0, 143.8, 866.1, 141.0, +868.0, 135.7, 875.3, 138.2, 839.8, 173.3, 876.6, 201.0, 876.6, 201.0, +913.4, 228.8, 918.1, 232.3, 918.0, 232.3, 922.7, 235.8, 881.2, 204.6, +881.1, 204.8, 839.8, 173.3, 774.9, 157.7, 800.5, 192.0, 799.6, 193.6, +817.9, 232.4, 812.6, 229.4, 812.6, 229.4, 807.2, 226.4, 799.9, 216.7, +801.9, 215.2, 796.7, 204.0, 785.8, 180.8, 789.9, 177.8, 774.9, 157.7, +742.1, 168.4, 748.6, 172.2, 747.3, 174.3, 752.5, 180.3, 759.9, 188.8, +758.0, 193.0, 767.4, 197.3, 728.8, 172.1, 729.3, 154.2, 687.8, 150.7, +686.9, 150.1, 686.9, 150.1, 686.0, 149.5, 683.8, 133.2, 668.7, 135.3, +651.4, 121.1, 699.3, 137.2, 698.0, 142.6, 742.1, 168.4, 799.3, 321.8, +790.6, 327.8, 789.5, 326.7, 782.0, 333.8, 782.8, 333.4, 782.3, 332.4, +782.6, 330.9, 783.7, 325.5, 781.7, 321.8, 784.9, 320.1, 790.0, 317.2, +799.1, 322.4, 799.3, 321.8, 664.3, 139.4, 661.1, 135.9, 661.1, 135.9, +657.9, 132.4, 704.8, 164.9, 705.4, 164.1, 752.8, 195.8, 716.3, 163.2, +711.0, 169.1, 669.2, 142.5, 666.8, 140.9, 666.5, 141.3, 664.3, 139.4, +658.2, 159.9, 633.0, 146.5, 634.7, 139.2, 607.9, 133.0, 589.3, 120.3, +589.3, 120.3, 570.7, 107.6, 572.4, 108.8, 572.5, 108.7, 574.2, 109.7, +593.2, 121.1, 593.2, 121.1, 612.2, 132.4, 635.2, 146.2, 637.3, 162.6, +658.2, 159.9, 549.5, 216.0, 560.1, 230.0, 560.1, 230.0, 570.7, 244.0, +552.7, 230.3, 534.4, 238.6, 529.6, 223.2, 494.1, 200.7, 491.9, 204.2, +454.2, 185.1, 453.2, 181.7, 451.3, 182.2, 448.4, 179.4, 466.8, 183.8, +466.3, 185.9, 484.2, 192.4, 511.4, 202.2, 511.4, 202.2, 538.5, 212.0, +544.0, 214.0, 545.7, 212.3, 549.5, 216.0, 468.4, 248.2, 463.1, 244.0, +464.6, 242.2, 460.7, 236.1, 452.5, 223.3, 456.0, 216.4, 444.3, 210.5, +492.1, 245.1, 492.6, 244.5, 541.6, 277.4, 542.2, 278.2, 542.2, 278.3, +542.8, 279.0, 536.5, 273.8, 530.8, 280.7, 518.8, 282.5, 491.3, 271.0, +492.2, 267.1, 468.4, 248.2, 518.8, 282.5, 510.0, 283.7, 505.9, 288.8, +501.2, 285.0, 500.2, 284.4, 500.2, 284.4, 499.3, 283.8, 493.2, 279.7, +493.1, 279.8, 486.8, 275.9, 486.2, 275.5, 486.0, 275.6, 485.7, 275.1, +482.9, 270.8, 481.8, 271.2, 480.2, 266.5, 477.7, 262.6, 477.7, 262.6, +475.1, 258.7, 471.8, 253.4, 473.2, 250.8, 468.4, 248.2, 492.2, 267.1, +491.3, 271.0, 518.8, 282.5, 504.3, 4.5, 516.9, -11.6, 519.7, -10.1, +529.4, -27.8, 529.8, -26.1, 529.7, -26.0, 530.3, -24.4, 538.8, -5.6, +535.7, -4.2, 541.1, 16.0, 525.8, 22.1, 528.8, 29.4, 516.5, 42.7, +516.9, 42.3, 516.0, 41.4, 515.6, 40.0, 510.5, 23.9, 510.5, 23.9, +505.4, 7.7, 504.9, 6.1, 503.8, 5.4, 504.3, 4.5, 639.5, 8.4, +639.7, 16.2, 642.7, 22.6, 639.9, 23.9, 624.1, 37.2, 624.1, 37.2, +608.4, 50.5, 611.7, 42.7, 600.9, 38.2, 593.4, 25.8, 593.3, 25.3, +597.4, 24.3, 601.4, 22.8, 610.8, 19.2, 610.8, 19.2, 620.2, 15.7, +624.8, 14.0, 624.8, 14.0, 629.3, 12.3, 634.4, 10.4, 638.2, 7.0, +639.5, 8.4, 453.5, 65.5, 447.0, 74.6, 447.0, 74.6, 440.4, 83.6, +441.1, 80.3, 436.2, 74.9, 433.3, 75.3, 432.4, 75.9, 429.1, 70.4, +424.9, 65.5, 436.5, 59.9, 447.5, 58.4, 453.5, 65.5, 450.5, -16.5, +432.0, -18.4, 432.0, -18.4, 413.6, -20.3, 437.4, -27.6, 437.7, -27.9, +460.0, -39.1, 474.0, -43.4, 474.0, -43.4, 488.0, -47.7, 479.7, -27.7, +472.1, -24.4, 450.5, -16.5, 265.1, 182.1, 248.9, 202.2, 226.0, 217.1, +225.3, 216.3, 232.4, 185.6, 232.4, 185.6, 239.6, 154.9, 239.5, 155.4, +240.3, 155.6, 240.9, 156.3, 249.7, 165.6, 249.7, 165.6, 258.5, 175.0, +261.8, 178.5, 265.5, 181.5, 265.1, 182.1, 286.3, 163.8, 287.4, 159.2, +290.1, 157.2, 295.2, 156.1, 293.8, 156.4, 295.6, 160.6, 293.7, 162.2, +291.1, 164.4, 286.7, 162.2, 286.3, 163.8, 319.8, 249.5, 302.8, 221.9, +306.2, 219.1, 285.8, 194.3, 281.7, 180.7, 289.7, 178.2, 293.7, 162.2, +295.6, 160.6, 293.8, 156.4, 295.2, 156.1, 298.4, 143.3, 298.4, 143.3, +301.6, 130.4, 301.6, 130.4, 301.5, 130.3, 301.5, 130.3, 301.5, 130.3, +301.6, 130.4, 301.6, 130.4, 310.7, 190.0, 333.2, 195.5, 319.8, 249.5, +301.6, 130.4, 302.9, 144.6, 306.2, 144.2, 310.9, 158.1, 320.4, 186.5, +320.4, 186.5, 329.9, 214.9, 331.8, 220.7, 331.8, 220.7, 333.8, 226.6, +330.2, 231.4, 334.1, 239.5, 340.6, 246.9, 340.9, 248.6, 339.1, 248.9, +337.6, 250.9, 332.9, 257.1, 332.4, 263.6, 328.2, 263.3, 328.9, 256.9, +324.0, 256.4, 319.8, 249.5, 333.2, 195.5, 310.7, 190.0, 301.6, 130.4, +356.7, 139.2, 350.2, 134.3, 353.0, 126.2, 355.1, 114.2, 357.3, 116.0, +360.6, 115.1, 360.7, 116.3, 381.1, 132.7, 381.1, 132.7, 401.4, 149.1, +401.6, 148.1, 373.4, 151.7, 356.7, 139.2, 299.7, 125.0, 289.1, 108.1, +282.8, 103.1, 286.7, 86.0, 287.4, 82.9, 297.8, 85.2, 308.9, 84.4, +315.9, 83.9, 321.9, 81.1, 323.0, 83.4, 325.0, 87.7, 319.0, 90.5, +315.0, 97.6, 310.1, 106.4, 310.1, 106.4, 305.2, 115.3, 302.5, 120.1, +298.3, 122.7, 299.7, 125.0, 181.3, 386.7, 181.8, 382.9, 181.0, 382.6, +182.4, 379.0, 186.4, 367.7, 186.4, 367.7, 190.4, 356.3, 188.2, 371.8, +186.6, 371.8, 181.3, 386.7, 224.3, 170.6, 229.8, 160.6, 230.0, 160.7, +235.3, 150.5, 231.1, 165.6, 231.1, 165.6, 226.9, 180.6, 227.0, 180.2, +226.8, 180.1, 226.7, 179.6, 225.5, 175.1, 223.2, 174.4, 224.3, 170.6, +155.7, 301.6, 156.2, 298.9, 155.4, 298.3, 156.8, 296.1, 157.4, 294.9, +157.1, 294.1, 158.1, 293.8, 165.8, 287.7, 163.1, 284.1, 168.1, 274.5, +182.5, 266.1, 189.3, 262.0, 202.7, 267.7, 200.1, 277.3, 200.1, 277.3, +197.4, 286.9, 194.8, 290.7, 192.0, 288.8, 186.7, 290.7, 179.3, 293.3, +179.3, 293.3, 172.0, 295.9, 171.2, 296.2, 171.2, 296.2, 170.5, 296.4, +164.9, 298.4, 164.9, 298.4, 159.2, 300.4, 157.5, 301.0, 155.8, 301.9, +155.7, 301.6, 474.7, 878.3, 473.3, 859.1, 473.3, 859.1, 471.9, 840.0, +469.7, 766.4, 467.8, 766.4, 463.6, 692.9, 463.5, 690.2, 463.4, 690.2, +463.3, 687.6, 463.4, 690.2, 463.5, 690.2, 463.6, 692.9, 467.8, 766.4, +469.7, 766.4, 471.9, 840.0, 473.3, 859.1, 473.3, 859.1, 474.7, 878.3, +703.6, 773.3, 704.1, 772.7, 704.0, 772.6, 704.6, 772.1, 738.0, 746.6, +739.2, 747.8, 770.2, 719.5, 770.4, 719.9, 770.8, 720.0, 770.7, 720.3, +771.7, 726.6, 776.6, 732.6, 778.2, 732.1, 769.4, 744.7, 763.0, 739.6, +750.0, 750.0, 696.0, 793.3, 704.4, 809.3, 644.3, 839.4, 681.2, 820.9, +673.9, 806.3, 703.6, 773.3, 644.3, 839.4, 633.2, 850.9, 632.6, 850.6, +619.8, 860.2, 624.5, 856.6, 623.9, 855.9, 628.1, 851.5, 661.0, 817.4, +661.0, 817.4, 693.8, 783.4, 698.7, 778.3, 698.9, 778.5, 703.6, 773.3, +673.9, 806.3, 681.2, 820.9, 644.3, 839.4, 518.2, 760.4, 508.7, 820.8, +505.3, 820.4, 499.2, 881.1, 499.0, 882.0, 494.5, 882.9, 492.0, 881.3, +490.7, 880.5, 491.8, 878.8, 491.6, 876.2, 490.2, 868.5, 490.8, 868.4, +490.1, 860.6, 493.4, 859.1, 491.7, 854.3, 491.9, 847.9, 495.9, 826.7, +495.0, 826.5, 498.0, 805.1, 499.1, 794.7, 500.0, 794.8, 501.9, 784.4, +507.8, 771.4, 517.9, 772.6, 518.2, 760.4, 501.9, 784.4, 516.1, 671.5, +522.3, 672.2, 543.4, 560.1, 544.6, 555.9, 545.0, 555.9, 545.8, 551.6, +546.7, 548.5, 546.1, 548.2, 547.5, 545.3, 546.7, 546.9, 547.3, 547.2, +547.1, 549.0, 545.2, 564.5, 545.2, 564.5, 543.2, 580.0, 542.6, 585.6, +542.6, 585.6, 541.9, 591.3, 540.1, 605.1, 540.1, 605.1, 538.4, 619.0, +537.3, 627.8, 537.3, 627.8, 536.3, 636.7, 533.8, 656.3, 533.8, 656.3, +531.4, 675.9, 531.1, 678.3, 531.2, 678.3, 530.8, 680.6, 524.2, 720.5, +524.5, 720.5, 518.2, 760.4, 517.9, 772.6, 507.8, 771.4, 501.9, 784.4, +563.3, 396.4, 568.0, 403.6, 568.0, 403.6, 572.6, 410.9, 553.8, 421.7, +555.1, 426.2, 541.9, 444.6, 541.1, 445.4, 540.4, 444.8, 539.0, 445.1, +528.2, 446.9, 528.2, 446.9, 517.4, 448.8, 509.5, 450.2, 501.5, 451.9, +501.5, 451.5, 510.3, 443.7, 507.4, 440.4, 513.3, 429.3, 535.4, 409.6, +535.8, 404.9, 563.3, 396.4, 513.3, 429.3, 529.4, 398.9, 533.3, 400.4, +545.5, 368.5, 554.4, 382.5, 554.4, 382.5, 563.3, 396.4, 535.8, 404.9, +535.4, 409.6, 513.3, 429.3, 526.6, 620.2, 524.2, 628.7, 523.2, 628.6, +521.8, 637.3, 537.8, 673.8, 501.4, 685.9, 494.2, 736.4, 480.5, 747.8, +485.1, 756.8, 482.5, 778.1, 482.3, 775.1, 482.3, 775.1, 482.0, 772.1, +492.0, 746.3, 486.7, 742.4, 484.0, 713.4, 490.1, 684.0, 495.0, 685.1, +506.0, 656.7, 507.2, 653.4, 506.8, 653.2, 508.5, 650.2, 517.1, 634.9, +514.4, 631.9, 526.6, 620.2, 508.5, 650.2, 506.3, 648.9, 514.9, 633.7, +521.3, 617.1, 524.2, 609.7, 524.2, 609.7, 527.1, 602.3, 535.2, 581.2, +542.9, 581.4, 543.4, 560.1, 535.0, 590.1, 535.0, 590.1, 526.6, 620.2, +514.4, 631.9, 517.1, 634.9, 508.5, 650.2, 451.2, 311.6, 452.2, 312.4, +450.9, 313.9, 450.6, 316.3, 448.7, 330.7, 449.8, 331.0, 446.9, 345.2, +447.5, 347.8, 443.8, 348.2, 443.4, 351.4, 441.3, 329.1, 441.3, 329.1, +439.3, 306.7, 439.0, 307.9, 446.5, 307.6, 451.2, 311.6, 490.6, 289.4, +495.4, 300.0, 492.2, 303.8, 500.3, 310.6, 501.6, 337.8, 501.6, 337.8, +503.0, 365.1, 487.6, 331.4, 492.5, 327.4, 490.6, 289.4, 453.6, 292.6, +451.1, 287.9, 456.2, 280.0, 455.2, 279.7, 461.1, 281.5, 459.3, 287.6, +463.5, 295.5, 465.0, 298.4, 464.4, 300.7, 466.5, 301.3, 459.4, 299.2, +456.8, 298.7, 453.6, 292.6, 184.0, 643.8, 178.9, 658.2, 177.4, 657.8, +173.9, 672.6, 169.9, 643.5, 169.9, 643.5, 165.9, 614.5, 163.2, 624.8, +174.0, 627.6, 182.2, 640.8, 183.1, 642.3, 184.3, 642.6, 184.0, 643.8, +218.5, 420.3, 228.1, 405.3, 229.6, 406.0, 237.7, 390.2, 232.9, 392.7, +238.0, 401.0, 236.2, 411.3, 228.3, 439.8, 230.0, 440.3, 223.8, 469.2, +233.1, 461.9, 221.4, 447.0, 219.0, 424.9, 218.8, 422.6, 217.7, 422.0, +218.5, 420.3, 421.1, 484.6, 422.3, 473.1, 423.9, 473.2, 426.6, 461.9, +427.4, 458.4, 428.0, 458.4, 428.3, 454.9, 425.3, 497.4, 424.7, 497.4, +421.2, 539.9, 420.9, 543.2, 420.6, 543.2, 420.6, 546.5, 420.4, 532.8, +420.7, 532.8, 420.8, 519.2, 421.0, 501.9, 419.4, 501.7, 421.1, 484.6, +422.5, 225.0, 423.6, 234.8, 423.4, 234.8, 424.7, 244.6, 424.1, 275.2, +419.6, 275.8, 423.4, 305.9, 420.5, 301.6, 420.5, 301.6, 417.5, 297.2, +417.2, 261.1, 417.7, 260.8, 422.5, 225.0, 355.0, 647.4, 355.7, 641.6, +358.4, 641.9, 358.8, 636.1, 356.5, 665.5, 360.6, 667.3, 351.3, 694.7, +358.7, 672.9, 352.0, 670.9, 355.0, 647.4, 376.3, 669.4, 377.1, 669.7, +372.0, 686.8, 367.8, 704.1, 366.7, 708.8, 366.7, 708.8, 365.5, 713.5, +365.5, 713.7, 365.5, 713.7, 365.4, 714.0, 358.3, 730.5, 361.1, 731.7, +356.8, 749.4, 343.4, 802.1, 343.4, 802.1, 330.6, 854.9, 337.9, 833.6, +333.6, 832.1, 336.5, 809.4, 337.2, 803.9, 337.2, 803.9, 337.9, 798.5, +338.4, 794.6, 338.4, 794.6, 338.9, 790.7, 339.9, 783.2, 339.9, 783.2, +340.8, 775.8, 345.8, 737.4, 338.7, 735.0, 350.7, 699.0, 356.4, 681.9, +368.6, 667.1, 376.3, 669.4, 292.5, 405.8, 296.0, 393.7, 296.0, 393.7, +299.6, 381.6, 301.7, 380.5, 305.9, 388.8, 312.2, 396.0, 311.5, 396.8, +317.7, 409.2, 324.0, 409.5, 326.5, 412.4, 326.5, 412.4, 329.1, 415.3, +332.3, 419.0, 331.6, 421.7, 335.5, 422.7, 313.3, 417.0, 306.0, 421.3, +292.5, 405.8, 302.4, 371.7, 309.5, 347.3, 311.6, 347.8, 316.6, 322.9, +320.3, 313.4, 317.5, 312.0, 322.4, 303.2, 327.4, 285.8, 327.4, 285.8, +332.5, 268.4, 332.7, 267.9, 333.0, 267.6, 332.8, 267.4, 338.5, 275.2, +344.3, 276.1, 343.5, 283.5, 341.6, 301.3, 335.5, 300.7, 327.5, 317.9, +326.6, 319.9, 326.6, 319.9, 325.6, 322.0, 319.1, 335.8, 319.1, 335.8, +312.7, 349.7, 310.3, 354.7, 310.3, 354.7, 308.0, 359.7, 305.2, 365.7, +303.9, 365.4, 302.4, 371.7, 420.4, 487.6, 421.6, 491.2, 419.3, 491.9, +418.3, 496.3, 418.2, 496.3, 418.2, 496.3, 418.2, 496.4, 416.2, 504.6, +411.6, 510.8, 414.3, 512.8, 385.3, 491.1, 389.9, 484.9, 365.6, 457.1, +362.0, 453.0, 362.0, 453.0, 358.5, 448.9, 350.7, 440.1, 352.6, 437.1, +343.0, 431.2, 380.2, 454.0, 378.3, 457.0, 413.7, 482.7, 417.0, 485.2, +419.3, 484.4, 420.4, 487.6, 303.1, 319.5, 315.6, 292.9, 311.4, 286.3, +332.5, 268.4, 327.4, 285.8, 327.4, 285.8, 322.4, 303.2, 313.8, 318.9, +315.6, 319.9, 309.1, 336.7, 294.0, 364.3, 294.0, 364.3, 278.9, 391.8, +271.4, 406.4, 270.2, 405.8, 261.6, 419.8, 278.8, 368.5, 280.1, 368.6, +303.1, 319.5, 261.6, 419.8, 246.9, 443.6, 244.9, 442.6, 232.2, 467.3, +233.2, 453.4, 233.2, 453.4, 234.2, 439.5, 264.1, 377.3, 252.0, 356.3, +303.1, 319.5, 280.1, 368.6, 278.8, 368.5, 261.6, 419.8, 234.9, 429.5, +235.6, 420.4, 233.8, 419.9, 236.2, 411.3, 238.0, 401.0, 232.9, 392.7, +237.7, 390.2, 239.4, 387.0, 236.2, 383.7, 238.3, 382.2, 258.8, 351.6, +260.3, 352.6, 282.5, 323.1, 284.3, 320.9, 284.3, 320.9, 286.0, 318.8, +288.1, 316.1, 288.2, 316.2, 290.3, 313.5, 294.6, 307.8, 294.6, 307.8, +298.9, 302.1, 305.5, 301.5, 304.9, 294.2, 310.9, 286.3, 274.5, 358.7, +276.4, 360.0, 234.9, 429.5, 310.9, 286.3, 313.8, 282.4, 317.4, 281.6, +316.7, 278.6, 317.3, 278.9, 327.4, 271.4, 328.2, 263.3, 332.4, 263.6, +332.9, 257.1, 337.6, 250.9, 340.4, 253.4, 335.2, 259.1, 332.8, 267.4, +333.0, 267.6, 332.7, 267.9, 332.5, 268.4, 311.4, 286.3, 315.6, 292.9, +303.1, 319.5, 252.0, 356.3, 264.1, 377.3, 234.2, 439.5, 234.5, 434.5, +234.5, 434.5, 234.9, 429.5, 276.4, 360.0, 274.5, 358.7, 310.9, 286.3, +240.7, 582.4, 236.3, 598.2, 231.9, 614.0, 231.9, 614.0, 226.4, 633.0, +226.3, 633.0, 220.8, 652.1, 219.4, 656.7, 217.9, 656.8, 218.1, 661.3, +219.1, 648.1, 219.1, 648.1, 220.0, 634.9, 225.6, 614.0, 228.0, 614.6, +236.0, 594.4, 238.4, 588.4, 239.4, 588.6, 240.7, 582.4, 169.5, 791.9, +171.5, 807.5, 171.5, 807.5, 173.4, 823.0, 161.9, 809.6, 161.8, 809.6, +150.3, 796.2, 150.1, 795.3, 166.5, 788.4, 169.5, 791.9, 150.3, 796.2, +147.5, 793.0, 143.9, 791.3, 144.7, 789.8, 149.8, 732.8, 150.4, 732.9, +155.0, 675.9, 157.9, 699.5, 152.3, 701.7, 160.9, 723.1, 162.3, 757.6, +165.2, 757.5, 169.5, 791.9, 166.5, 788.4, 150.1, 795.3, 150.3, 796.2, +76.7, 162.3, 81.1, 168.4, 84.6, 167.9, 85.5, 174.4, 87.9, 181.5, +87.9, 181.5, 90.3, 188.5, 100.0, 235.0, 100.4, 234.9, 110.6, 281.3, +108.8, 272.7, 108.2, 272.8, 105.7, 264.3, 104.5, 259.8, 104.5, 259.8, +103.2, 255.3, 89.9, 208.8, 87.0, 209.4, 76.7, 162.3, 50.5, 72.6, +53.0, 79.9, 51.3, 86.0, 55.5, 87.2, 55.6, 87.2, 55.7, 87.7, +55.9, 88.2, 56.8, 120.2, 51.9, 122.6, 62.1, 152.1, 62.5, 168.3, +62.5, 168.3, 63.0, 184.6, 66.0, 173.1, 61.6, 171.9, 60.2, 159.3, +55.4, 116.0, 53.3, 116.1, 50.5, 72.6, 817.0, 605.3, 806.9, 609.0, +806.7, 608.6, 796.8, 612.7, 797.2, 611.1, 797.4, 609.5, 797.6, 609.5, +804.0, 598.2, 804.0, 596.3, 804.0, 583.1, 801.5, 574.7, 806.4, 573.2, +808.8, 563.4, 819.0, 580.8, 821.5, 586.4, 817.0, 605.3, 808.8, 563.4, +810.7, 555.2, 810.7, 555.2, 812.7, 547.1, 812.6, 547.5, 813.3, 547.6, +813.9, 548.1, 833.9, 567.9, 834.2, 567.7, 855.2, 586.5, 855.4, 586.6, +855.4, 586.6, 855.5, 586.8, 853.9, 586.4, 853.0, 589.9, 850.6, 593.0, +848.1, 589.4, 833.8, 599.1, 817.0, 605.3, 821.5, 586.4, 819.0, 580.8, +808.8, 563.4, 911.8, 470.4, 913.5, 473.3, 915.9, 473.9, 915.3, 476.2, +916.7, 480.1, 916.7, 480.1, 918.1, 484.0, 913.3, 508.2, 914.2, 509.6, +917.5, 534.2, 916.9, 536.7, 916.9, 536.7, 916.3, 539.2, 913.2, 504.9, +912.4, 504.8, 911.8, 470.4, 916.3, 539.2, 913.4, 551.5, 912.9, 551.4, +910.5, 563.7, 910.4, 563.6, 910.4, 563.6, 910.3, 563.5, 905.8, 531.9, +910.5, 526.3, 893.0, 501.6, 891.1, 488.4, 894.8, 486.7, 889.2, 475.3, +895.7, 464.8, 895.7, 464.8, 902.2, 454.4, 904.7, 463.1, 907.0, 462.4, +911.8, 470.4, 912.4, 504.8, 913.2, 504.9, 916.3, 539.2, 849.5, 494.8, +848.1, 492.9, 848.1, 492.9, 846.8, 490.9, 842.0, 484.2, 842.8, 483.6, +838.7, 476.3, 844.7, 485.2, 844.3, 485.5, 849.5, 494.8, 738.7, 69.9, +753.9, 66.6, 761.8, 72.8, 769.2, 63.4, 788.7, 68.7, 786.9, 75.6, +804.5, 87.9, 830.4, 107.5, 831.0, 106.7, 857.5, 125.5, 854.9, 123.5, +854.5, 124.1, 851.4, 122.6, 813.2, 104.8, 813.2, 104.8, 775.0, 86.9, +756.8, 78.4, 741.7, 82.2, 738.7, 69.9, 760.7, 133.2, 746.8, 120.3, +752.8, 100.3, 740.9, 98.7, 768.4, 102.3, 766.4, 118.0, 791.8, 137.2, +792.9, 137.9, 792.8, 138.7, 793.9, 138.7, 788.0, 138.5, 788.0, 137.7, +782.2, 136.8, 771.4, 135.0, 767.4, 139.3, 760.7, 133.2, 684.7, 102.6, +683.4, 102.7, 682.1, 99.2, 681.9, 99.4, 684.6, 101.2, 685.9, 99.3, +689.9, 99.1, 689.7, 98.8, 687.4, 102.5, 684.7, 102.6, 705.7, 126.7, +727.5, 138.7, 723.1, 146.6, 740.5, 166.5, 741.3, 167.5, 741.1, 167.9, +742.1, 168.4, 698.0, 142.6, 699.3, 137.2, 651.4, 121.1, 644.5, 115.4, +644.5, 115.4, 637.5, 109.8, 672.1, 113.3, 676.0, 110.3, 705.7, 126.7, +637.5, 109.8, 628.7, 102.5, 629.9, 99.9, 619.9, 95.3, 621.5, 95.0, +622.0, 94.0, 623.1, 94.6, 646.1, 94.6, 646.1, 89.7, 669.1, 84.8, +674.0, 93.0, 674.2, 94.0, 681.9, 99.4, 682.1, 99.2, 683.4, 102.7, +684.7, 102.6, 692.8, 111.8, 692.8, 111.8, 700.8, 121.1, 703.3, 123.9, +702.9, 126.2, 705.7, 126.7, 676.0, 110.3, 672.1, 113.3, 637.5, 109.8, +629.3, 214.7, 629.4, 214.6, 627.9, 213.2, 626.6, 211.7, 620.0, 204.5, +620.0, 204.5, 613.4, 197.3, 608.6, 192.1, 608.6, 192.1, 603.8, 186.8, +591.9, 173.9, 591.5, 174.3, 580.1, 161.0, 579.1, 158.9, 579.1, 158.9, +578.0, 156.8, 578.1, 157.0, 578.3, 156.9, 578.7, 157.1, 580.9, 157.7, +580.9, 157.7, 583.1, 158.4, 618.0, 168.9, 623.6, 160.4, 653.0, 179.5, +652.8, 179.4, 647.2, 188.0, 641.5, 196.5, 635.4, 205.6, 636.9, 207.0, +629.3, 214.7, 689.0, 182.7, 706.2, 191.7, 706.2, 191.7, 723.5, 200.8, +715.9, 194.0, 712.7, 197.5, 701.9, 194.3, 698.4, 193.2, 697.4, 194.4, +695.0, 192.2, 691.0, 188.6, 693.0, 183.9, 689.0, 182.7, 626.8, 212.0, +626.7, 211.8, 626.7, 211.8, 626.6, 211.7, 627.9, 213.2, 629.4, 214.6, +629.3, 214.7, 633.7, 219.4, 633.7, 219.4, 638.0, 224.2, 638.4, 224.6, +638.4, 224.6, 638.7, 224.9, 645.6, 232.5, 645.6, 232.5, 652.5, 240.0, +665.2, 253.8, 665.2, 253.8, 677.8, 267.5, 681.5, 271.6, 681.5, 271.6, +685.2, 275.6, 685.8, 276.2, 685.8, 276.2, 686.3, 276.8, 688.5, 279.2, +688.5, 279.2, 690.7, 281.6, 697.1, 288.6, 697.1, 288.6, 703.6, 295.6, +710.4, 303.0, 710.4, 303.0, 717.1, 310.4, 720.6, 314.2, 720.6, 314.2, +724.0, 317.9, 730.1, 324.6, 736.2, 331.2, 736.2, 331.2, 736.2, 331.2, +730.1, 324.6, 724.0, 317.9, 720.6, 314.2, 720.6, 314.2, 717.1, 310.4, +710.4, 303.0, 710.4, 303.0, 703.6, 295.6, 697.1, 288.6, 697.1, 288.6, +690.7, 281.6, 688.5, 279.2, 688.5, 279.2, 686.3, 276.8, 685.8, 276.2, +685.8, 276.2, 685.2, 275.6, 681.5, 271.6, 681.5, 271.6, 677.8, 267.5, +665.2, 253.8, 665.2, 253.8, 652.5, 240.0, 645.6, 232.5, 645.6, 232.5, +638.7, 224.9, 638.4, 224.6, 638.4, 224.6, 638.0, 224.2, 633.7, 219.4, +633.7, 219.4, 629.3, 214.7, 628.1, 213.3, 628.0, 213.3, 626.8, 212.0, +626.8, 212.0, 626.8, 212.0, 626.8, 212.0, 645.8, 239.4, 690.1, 300.2, +690.2, 300.2, 731.8, 362.9, 730.3, 363.7, 730.3, 363.7, 728.7, 364.4, +716.2, 348.6, 717.6, 347.6, 706.4, 330.7, 696.0, 315.0, 696.0, 315.0, +685.6, 299.3, 665.7, 269.4, 667.0, 268.4, 645.8, 239.4, 792.6, 283.1, +791.4, 277.9, 793.4, 271.7, 795.1, 271.6, 826.3, 282.4, 829.0, 274.6, +862.9, 277.6, 833.0, 295.4, 834.2, 297.5, 805.6, 317.4, 800.5, 317.8, +796.7, 300.8, 792.6, 283.1, 805.6, 317.4, 802.4, 319.6, 802.4, 319.6, +799.3, 321.8, 799.1, 322.4, 790.0, 317.2, 784.9, 320.1, 784.8, 320.1, +785.1, 318.9, 785.4, 317.7, 789.0, 300.4, 788.8, 283.1, 792.6, 283.1, +796.7, 300.8, 800.5, 317.8, 805.6, 317.4, 669.2, 142.5, 711.0, 169.1, +716.3, 163.2, 752.8, 195.8, 757.6, 199.0, 757.6, 199.0, 762.5, 202.3, +715.8, 172.5, 715.3, 173.2, 669.2, 142.5, 656.5, 133.7, 662.4, 138.7, +662.0, 139.2, 668.3, 143.7, 682.3, 157.8, 681.8, 158.3, 695.4, 173.0, +701.6, 179.8, 707.8, 186.6, 707.8, 186.5, 699.6, 181.4, 699.2, 181.9, +690.7, 177.3, 677.9, 165.3, 679.7, 163.4, 668.8, 149.5, 662.6, 141.6, +657.2, 142.1, 656.5, 133.7, 484.2, 192.4, 466.3, 185.9, 466.8, 183.8, +448.4, 179.4, 434.4, 165.4, 434.4, 165.4, 420.4, 151.4, 423.0, 154.3, +423.8, 153.6, 427.2, 155.8, 427.8, 156.2, 427.8, 156.2, 428.4, 156.5, +441.0, 164.6, 441.0, 164.6, 453.6, 172.7, 468.9, 182.5, 483.2, 193.7, +484.2, 192.4, 511.2, 117.2, 506.6, 118.9, 503.0, 121.8, 502.0, 120.5, +497.6, 121.5, 496.6, 123.8, 493.2, 122.4, 479.7, 123.8, 478.5, 122.4, +466.5, 128.1, 465.7, 128.2, 465.1, 128.8, 464.8, 128.5, 464.3, 128.6, +464.0, 128.4, 463.7, 128.7, 497.3, 92.4, 497.5, 92.6, 531.3, 56.5, +537.7, 49.7, 541.4, 50.9, 544.1, 42.8, 531.4, 81.3, 530.5, 81.6, +511.2, 117.2, 544.1, 42.8, 544.3, 42.4, 544.9, 42.3, 544.8, 42.1, +553.0, 66.6, 561.8, 66.9, 561.1, 91.2, 561.9, 94.1, 561.8, 97.0, +562.7, 97.1, 560.1, 98.9, 560.1, 98.9, 557.4, 100.7, 533.6, 105.7, +534.3, 109.0, 511.2, 117.2, 530.5, 81.6, 531.4, 81.3, 544.1, 42.8, +436.8, 132.4, 435.4, 132.4, 435.4, 132.4, 434.0, 132.5, 436.4, 132.0, +436.1, 130.2, 438.1, 128.0, 490.4, 81.3, 490.1, 80.9, 542.1, 33.9, +542.0, 37.9, 543.5, 38.0, 544.8, 42.1, 544.9, 42.3, 544.3, 42.4, +544.1, 42.8, 541.4, 50.9, 537.7, 49.7, 531.3, 56.5, 484.8, 95.3, +484.6, 95.1, 436.8, 132.4, 531.3, 56.5, 497.5, 92.6, 497.3, 92.4, +463.7, 128.7, 458.1, 133.7, 455.3, 131.1, 446.7, 132.3, 442.2, 133.8, +441.7, 132.4, 436.8, 132.4, 484.6, 95.1, 484.8, 95.3, 531.3, 56.5, +612.3, -75.3, 626.2, -73.9, 633.4, -66.3, 638.1, -51.9, 627.0, -46.6, +638.8, -21.7, 639.5, 8.4, 638.2, 7.0, 634.4, 10.4, 629.3, 12.3, +619.7, -9.4, 624.7, -11.6, 620.1, -35.4, 618.2, -44.7, 618.2, -44.7, +616.4, -54.1, 614.4, -64.7, 615.4, -75.0, 612.3, -75.3, 403.8, 35.1, +396.6, 24.7, 396.6, 24.7, 389.3, 14.2, 396.6, 18.3, 405.6, 9.6, +408.7, 14.0, 435.3, 29.2, 443.6, 22.3, 462.0, 44.4, 462.7, 45.0, +462.7, 45.0, 463.4, 45.6, 433.6, 40.8, 431.0, 46.6, 403.8, 35.1, +463.4, 45.6, 464.5, 46.4, 464.7, 46.3, 465.6, 47.3, 465.9, 47.6, +466.2, 47.8, 466.1, 47.9, 459.8, 56.7, 459.8, 56.7, 453.5, 65.5, +447.5, 58.4, 436.5, 59.9, 424.9, 65.5, 424.7, 65.3, 424.7, 65.3, +424.5, 65.0, 414.5, 49.8, 414.2, 50.1, 403.8, 35.1, 431.0, 46.6, +433.6, 40.8, 463.4, 45.6, 509.8, -12.8, 509.0, -11.6, 509.0, -11.6, +508.1, -10.5, 507.9, -10.1, 506.9, -11.0, 506.1, -10.7, 498.8, -2.9, +488.5, -14.8, 471.0, -14.3, 461.5, -12.2, 460.8, -15.4, 450.5, -16.5, +472.1, -24.4, 479.7, -27.7, 488.0, -47.7, 493.8, -49.4, 493.8, -49.4, +499.5, -51.2, 509.6, -35.0, 505.7, -32.2, 509.8, -12.8, 499.5, -51.2, +523.8, -58.5, 523.9, -58.0, 548.0, -65.9, 546.5, -63.9, 544.5, -62.9, +545.1, -61.8, 545.4, -61.3, 542.5, -60.0, 542.7, -58.6, 543.8, -57.6, +527.3, -47.3, 528.8, -39.2, 528.8, -39.2, 526.9, -37.9, 527.0, -36.7, +515.8, -28.1, 518.4, -24.7, 509.8, -12.8, 505.7, -32.2, 509.6, -35.0, +499.5, -51.2, 284.2, 78.5, 283.5, 81.8, 285.4, 82.2, 286.7, 86.0, +282.8, 103.1, 289.1, 108.1, 299.7, 125.0, 300.6, 127.6, 301.9, 127.8, +301.5, 130.3, 299.6, 143.4, 300.6, 144.3, 295.2, 156.1, 290.1, 157.2, +287.4, 159.2, 286.3, 163.8, 280.3, 169.0, 280.3, 169.0, 274.3, 174.1, +271.1, 176.8, 268.3, 176.5, 268.0, 179.5, 273.3, 128.7, 274.2, 128.6, +284.2, 78.5, 373.3, 203.2, 370.5, 207.2, 370.8, 207.5, 367.6, 211.2, +364.7, 215.0, 364.7, 215.0, 361.9, 218.8, 356.5, 189.2, 344.2, 177.1, +358.0, 158.3, 349.9, 169.3, 369.1, 180.1, 373.3, 203.2, 358.0, 158.3, +356.2, 151.9, 357.5, 151.5, 357.1, 144.7, 356.9, 141.9, 357.2, 139.2, +356.7, 139.2, 373.4, 151.7, 401.6, 148.1, 401.4, 149.1, 404.7, 151.7, +404.6, 151.9, 407.9, 154.3, 390.6, 178.7, 390.6, 178.7, 373.3, 203.2, +369.1, 180.1, 349.9, 169.3, 358.0, 158.3, 308.9, 84.4, 297.8, 85.2, +287.4, 82.9, 286.7, 86.0, 285.4, 82.2, 283.5, 81.8, 284.2, 78.5, +283.8, 77.5, 283.8, 77.5, 283.5, 76.5, 282.6, 68.5, 280.9, 68.7, +278.3, 61.0, 282.4, 55.0, 292.3, 52.8, 297.3, 56.6, 307.6, 64.5, +312.6, 74.0, 308.9, 84.4, 297.3, 56.6, 297.3, 55.1, 303.3, 55.2, +309.4, 53.8, 320.2, 51.3, 320.2, 51.3, 331.0, 48.8, 335.2, 47.8, +337.5, 45.1, 339.5, 46.8, 345.7, 56.6, 345.7, 56.6, 352.0, 66.3, +356.0, 70.2, 352.5, 73.8, 353.0, 81.4, 343.1, 87.8, 339.5, 82.3, +326.0, 83.2, 324.5, 83.3, 324.5, 83.3, 323.0, 83.4, 321.9, 81.1, +315.9, 83.9, 308.9, 84.4, 312.6, 74.0, 307.6, 64.5, 297.3, 56.6, +333.5, 40.1, 335.5, 41.8, 336.2, 41.4, 337.4, 43.5, 338.4, 45.2, +338.4, 45.2, 339.5, 46.8, 337.5, 45.1, 335.2, 47.8, 331.0, 48.8, +329.4, 47.0, 330.6, 42.5, 333.5, 40.1, 273.8, 289.7, 286.3, 295.9, +287.0, 303.2, 298.9, 302.1, 294.6, 307.8, 294.6, 307.8, 290.3, 313.5, +288.2, 316.2, 288.1, 316.1, 286.0, 318.8, 277.3, 306.1, 269.1, 295.9, +273.8, 289.7, 204.3, 420.0, 183.7, 445.4, 180.2, 443.2, 163.2, 470.8, +155.4, 476.2, 151.1, 474.2, 147.6, 481.7, 147.4, 480.0, 147.4, 480.0, +147.1, 478.3, 146.9, 478.2, 148.1, 475.5, 149.2, 472.6, 175.8, 445.4, +173.8, 423.9, 204.3, 420.0, 213.9, 354.1, 211.2, 376.4, 202.0, 375.3, +190.1, 396.4, 185.5, 404.4, 185.5, 404.4, 181.0, 412.4, 178.7, 416.5, +176.4, 416.5, 176.4, 420.6, 182.3, 404.9, 178.8, 403.7, 181.3, 386.7, +186.6, 371.8, 188.2, 371.8, 190.4, 356.3, 193.8, 346.9, 193.8, 346.9, +197.1, 337.6, 204.7, 336.9, 214.8, 347.0, 213.9, 354.1, 197.1, 337.6, +198.8, 332.8, 201.3, 328.4, 200.5, 328.0, 208.1, 323.9, 208.1, 323.9, +215.6, 319.8, 216.7, 313.2, 227.8, 315.9, 238.9, 309.9, 237.8, 332.4, +226.4, 331.9, 214.0, 353.9, 214.0, 354.0, 213.9, 354.1, 213.9, 354.1, +214.8, 347.0, 204.7, 336.9, 197.1, 337.6, 205.5, 205.2, 214.9, 187.9, +214.9, 187.9, 224.3, 170.6, 223.2, 174.4, 225.5, 175.1, 226.7, 179.6, +218.9, 193.9, 203.1, 195.7, 205.5, 205.2, 226.7, 179.6, 226.8, 180.1, +227.0, 180.2, 226.9, 180.6, 214.8, 224.2, 214.8, 224.2, 202.7, 267.7, +189.3, 262.0, 182.5, 266.1, 168.1, 274.5, 172.0, 267.1, 178.1, 263.9, +175.9, 259.7, 176.2, 259.8, 176.7, 258.1, 177.5, 256.5, 191.5, 230.8, +189.8, 229.7, 205.5, 205.2, 203.1, 195.7, 218.9, 193.9, 226.7, 179.6, +186.7, 290.7, 192.0, 288.8, 194.8, 290.7, 197.4, 286.9, 189.6, 315.0, +189.6, 315.0, 181.8, 343.0, 182.1, 342.0, 181.9, 342.0, 182.0, 340.9, +183.7, 322.7, 183.7, 322.7, 185.4, 304.5, 186.1, 297.6, 183.3, 295.7, +186.7, 290.7, 463.6, 692.9, 463.5, 690.2, 463.4, 690.2, 463.3, 687.6, +463.2, 686.9, 463.2, 686.2, 463.2, 686.2, 463.0, 680.2, 463.8, 680.1, +462.8, 674.3, 464.4, 678.0, 464.4, 678.0, 466.1, 681.7, 466.3, 687.2, +466.0, 687.8, 463.6, 692.9, 578.5, 434.6, 579.6, 430.3, 580.2, 430.4, +580.8, 426.0, 580.6, 425.6, 581.4, 425.1, 581.3, 424.5, 602.2, 457.1, +602.2, 457.1, 623.1, 489.8, 628.7, 470.0, 598.0, 464.0, 578.5, 434.6, +673.6, 757.7, 672.3, 759.2, 679.5, 765.3, 685.5, 772.8, 689.7, 778.1, +694.9, 781.9, 693.8, 783.4, 661.0, 817.4, 661.0, 817.4, 628.1, 851.5, +629.8, 849.8, 629.2, 849.3, 630.3, 847.0, 634.0, 839.4, 634.0, 839.4, +637.6, 831.9, 639.3, 828.4, 639.3, 828.4, 641.0, 824.9, 657.3, 791.3, +650.1, 785.2, 673.6, 757.7, 491.4, 532.6, 491.9, 530.4, 503.1, 533.1, +514.8, 533.6, 520.0, 533.8, 525.1, 533.3, 525.2, 534.0, 525.8, 540.2, +520.7, 540.8, 516.3, 547.5, 512.5, 553.3, 509.0, 559.2, 508.7, 559.0, +496.5, 551.7, 488.9, 543.1, 491.4, 532.6, 474.8, 529.0, 477.1, 496.5, +488.2, 493.2, 479.4, 464.0, 481.8, 459.8, 483.6, 460.0, 484.1, 455.6, +483.9, 455.4, 484.4, 455.0, 484.8, 454.4, 485.1, 452.0, 496.1, 456.3, +501.5, 451.5, 501.5, 451.9, 509.5, 450.2, 517.4, 448.8, 517.2, 464.4, +509.2, 464.3, 501.0, 479.8, 499.7, 482.2, 499.7, 482.2, 498.4, 484.5, +486.6, 506.8, 469.2, 522.9, 474.8, 529.0, 527.1, 602.3, 524.2, 609.7, +524.2, 609.7, 521.3, 617.1, 515.0, 592.1, 519.4, 590.9, 517.5, 564.7, +517.0, 557.6, 517.0, 557.6, 516.5, 550.4, 516.4, 549.0, 515.7, 548.6, +516.3, 547.5, 520.7, 540.8, 525.8, 540.2, 525.2, 534.0, 536.3, 517.1, +536.3, 517.1, 547.5, 500.3, 551.2, 494.6, 553.7, 495.1, 555.0, 488.9, +543.5, 546.1, 541.9, 545.8, 527.1, 602.3, 555.0, 488.9, 555.3, 487.8, +555.7, 487.9, 556.3, 486.9, 562.9, 477.0, 563.1, 466.9, 569.4, 467.1, +566.8, 467.0, 566.6, 477.0, 563.8, 487.0, 562.8, 490.6, 562.8, 490.6, +561.8, 494.2, 556.7, 512.6, 556.7, 512.6, 551.5, 531.1, 549.5, 538.2, +549.5, 538.2, 547.5, 545.3, 546.1, 548.2, 546.7, 548.5, 545.8, 551.6, +545.0, 555.9, 544.6, 555.9, 543.4, 560.1, 542.9, 581.4, 535.2, 581.2, +527.1, 602.3, 541.9, 545.8, 543.5, 546.1, 555.0, 488.9, 432.0, 228.2, +431.8, 226.0, 431.8, 226.0, 431.6, 223.8, 437.1, 213.6, 439.0, 212.2, +438.3, 201.1, 439.1, 202.4, 440.2, 203.0, 439.9, 203.6, 439.3, 206.5, +441.2, 208.2, 444.3, 210.5, 456.0, 216.4, 452.5, 223.3, 460.7, 236.1, +464.0, 254.6, 453.1, 274.4, 455.8, 275.1, 438.7, 270.4, 443.2, 252.0, +432.0, 228.2, 455.8, 275.1, 456.6, 276.9, 455.5, 277.4, 455.2, 279.7, +456.2, 280.0, 451.1, 287.9, 453.6, 292.6, 452.4, 302.1, 456.5, 306.3, +451.2, 311.6, 446.5, 307.6, 439.0, 307.9, 439.3, 306.7, 435.6, 267.5, +435.6, 267.5, 432.0, 228.2, 443.2, 252.0, 438.7, 270.4, 455.8, 275.1, +475.1, 258.7, 477.7, 262.6, 477.7, 262.6, 480.2, 266.5, 484.3, 278.3, +485.4, 277.9, 490.6, 289.4, 492.5, 327.4, 487.6, 331.4, 503.0, 365.1, +503.1, 368.1, 503.1, 368.1, 503.3, 371.1, 497.3, 363.5, 498.7, 362.4, +494.1, 353.7, 486.4, 339.0, 486.4, 339.0, 478.6, 324.2, 472.6, 312.8, +472.6, 312.8, 466.5, 301.3, 464.4, 300.7, 465.0, 298.4, 463.5, 295.5, +467.3, 276.7, 465.7, 275.0, 475.1, 258.7, 463.5, 295.5, 459.3, 287.6, +461.1, 281.5, 455.2, 279.7, 455.5, 277.4, 456.6, 276.9, 455.8, 275.1, +453.1, 274.4, 464.0, 254.6, 460.7, 236.1, 464.6, 242.2, 463.1, 244.0, +468.4, 248.2, 473.2, 250.8, 471.8, 253.4, 475.1, 258.7, 465.7, 275.0, +467.3, 276.7, 463.5, 295.5, 494.1, 353.7, 498.7, 362.4, 497.3, 363.5, +503.3, 371.1, 503.6, 377.8, 505.6, 383.9, 503.9, 384.4, 498.4, 392.8, +504.5, 396.8, 505.1, 409.1, 486.1, 398.3, 484.5, 401.1, 463.9, 393.2, +464.2, 393.4, 466.8, 389.5, 469.6, 385.7, 480.9, 370.9, 480.9, 370.9, +492.2, 356.2, 493.2, 355.0, 494.4, 354.1, 494.1, 353.7, 185.8, 516.6, +187.6, 526.3, 190.7, 525.7, 195.7, 534.8, 200.7, 544.0, 203.9, 543.4, +205.8, 553.2, 204.0, 561.3, 204.0, 561.3, 202.3, 569.3, 189.3, 545.5, +190.9, 543.6, 185.8, 516.6, 195.7, 534.8, 190.7, 525.7, 187.6, 526.3, +185.8, 516.6, 179.3, 504.9, 178.5, 505.2, 172.9, 493.1, 173.3, 491.8, +173.3, 491.8, 173.8, 490.6, 196.2, 478.0, 189.5, 466.0, 205.2, 441.3, +222.8, 476.9, 207.3, 489.8, 195.7, 534.8, 418.3, 496.3, 419.3, 491.9, +421.6, 491.2, 420.4, 487.6, 420.7, 486.1, 421.1, 486.1, 421.1, 484.6, +419.4, 501.7, 421.0, 501.9, 420.8, 519.2, 421.1, 514.2, 420.3, 514.1, +419.7, 509.1, 419.0, 502.7, 419.0, 502.7, 418.3, 496.4, 418.3, 496.3, +418.3, 496.3, 418.3, 496.3, 412.4, 667.3, 410.4, 684.4, 413.1, 685.3, +407.6, 701.4, 411.8, 689.1, 408.8, 688.1, 409.9, 674.8, 410.7, 664.7, +410.7, 664.7, 411.6, 654.6, 415.4, 609.0, 415.4, 609.0, 419.2, 563.4, +419.9, 555.0, 419.9, 555.0, 420.6, 546.5, 420.6, 543.2, 420.9, 543.2, +421.2, 539.9, 417.4, 595.7, 417.3, 595.6, 413.5, 651.4, 413.0, 659.4, +413.3, 659.4, 412.4, 667.3, 427.3, 776.5, 428.0, 780.3, 430.1, 779.9, +433.0, 783.4, 446.6, 800.0, 455.1, 797.7, 460.2, 816.6, 457.1, 838.5, +457.1, 838.5, 453.9, 860.5, 455.4, 855.6, 452.0, 854.6, 450.1, 848.6, +444.2, 830.0, 444.2, 830.0, 438.3, 811.3, 432.8, 793.9, 430.7, 794.3, +427.3, 776.5, 406.6, 883.8, 406.0, 882.6, 403.3, 884.1, 400.0, 884.0, +374.4, 883.8, 374.2, 886.1, 348.9, 883.3, 349.2, 883.2, 348.7, 880.8, +348.6, 878.3, 347.6, 869.7, 349.5, 869.5, 350.4, 860.7, 355.0, 857.9, +358.6, 864.1, 366.8, 867.4, 382.6, 873.9, 382.6, 873.9, 398.3, 880.4, +402.4, 882.1, 405.1, 880.8, 406.6, 883.8, 377.5, 209.4, 376.8, 204.7, +376.0, 199.9, 376.1, 199.9, 392.8, 177.9, 393.6, 178.5, 409.4, 156.0, +412.5, 160.9, 412.5, 160.9, 415.7, 165.8, 417.1, 167.5, 416.0, 168.4, +416.3, 171.0, 416.3, 171.1, 416.1, 171.1, 416.0, 171.3, 413.9, 173.3, +413.9, 173.3, 411.9, 175.4, 394.7, 192.4, 397.1, 195.9, 377.5, 209.4, +225.8, 746.3, 226.0, 752.9, 224.7, 752.9, 223.6, 759.5, 217.9, 793.6, +217.9, 793.6, 212.2, 827.7, 210.5, 838.1, 207.5, 838.4, 208.8, 848.4, +208.5, 822.8, 203.1, 821.6, 208.2, 797.2, 209.2, 783.9, 213.3, 782.9, +210.2, 770.6, 209.7, 770.5, 210.6, 767.8, 210.6, 764.9, 225.7, 716.7, +214.3, 713.1, 218.1, 661.3, 217.9, 656.8, 219.4, 656.7, 220.8, 652.1, +223.9, 661.3, 221.3, 662.2, 221.9, 672.3, 223.8, 709.3, 225.1, 709.3, +225.8, 746.3, 377.7, 663.3, 378.7, 665.6, 378.0, 667.1, 376.3, 669.4, +368.6, 667.1, 356.4, 681.9, 350.7, 699.0, 351.9, 697.8, 351.0, 696.9, +351.3, 694.7, 360.6, 667.3, 356.5, 665.5, 358.8, 636.1, 359.1, 633.6, +359.1, 633.6, 359.5, 631.2, 359.5, 631.2, 359.5, 631.2, 359.5, 631.2, +368.6, 647.3, 370.4, 646.5, 377.7, 663.3, 365.6, 457.1, 389.9, 484.9, +385.3, 491.1, 414.3, 512.8, 419.1, 522.3, 413.0, 527.4, 407.6, 540.2, +407.7, 539.3, 405.6, 539.1, 403.6, 538.0, 401.5, 535.4, 402.1, 534.9, +400.7, 531.7, 387.8, 504.4, 387.8, 504.4, 374.9, 477.0, 370.3, 467.0, +373.1, 463.9, 365.6, 457.1, 396.0, 295.6, 405.7, 311.6, 405.7, 311.6, +415.3, 327.6, 415.1, 326.1, 403.1, 330.3, 400.9, 326.8, 393.5, 314.7, +398.5, 311.6, 396.1, 296.5, 396.1, 296.0, 396.2, 296.0, 396.0, 295.6, +429.5, 402.8, 428.6, 401.2, 424.0, 404.3, 422.4, 402.4, 409.9, 388.2, +410.4, 387.3, 401.3, 370.6, 404.8, 377.1, 406.3, 376.3, 411.3, 382.1, +420.4, 392.5, 423.1, 391.0, 429.5, 402.8, 327.5, 317.9, 335.5, 300.7, +341.6, 301.3, 343.5, 283.5, 344.7, 282.9, 350.0, 293.2, 356.4, 303.0, +363.8, 314.1, 363.8, 314.1, 371.2, 325.2, 376.4, 333.1, 375.3, 339.9, +381.6, 341.0, 353.4, 336.2, 341.1, 338.4, 327.5, 317.9, 413.7, 482.7, +378.3, 457.0, 380.2, 454.0, 343.0, 431.2, 338.6, 427.9, 339.3, 427.0, +335.5, 422.7, 331.6, 421.7, 332.3, 419.0, 329.1, 415.3, 342.3, 424.3, +341.6, 425.3, 354.1, 435.3, 359.8, 439.8, 359.8, 439.8, 365.4, 444.3, +366.7, 445.3, 366.7, 445.3, 367.9, 446.3, 390.8, 464.5, 388.8, 467.8, +413.7, 482.7, 274.1, 435.0, 276.4, 430.3, 275.1, 429.0, 278.6, 425.7, +278.7, 425.6, 278.7, 425.6, 278.7, 425.6, 268.4, 467.8, 268.3, 467.8, +258.1, 510.1, 256.8, 515.4, 255.8, 520.7, 255.8, 520.7, 255.8, 520.7, +256.8, 515.4, 258.1, 510.1, 259.6, 503.2, 259.6, 503.2, 261.0, 496.3, +267.6, 465.7, 266.5, 465.4, 274.1, 435.0, 64.3, 245.5, 63.3, 243.2, +63.3, 243.2, 62.3, 240.9, 69.8, 212.3, 64.6, 210.9, 66.9, 181.0, +65.6, 193.9, 66.4, 193.9, 65.9, 206.9, 65.1, 226.2, 66.4, 226.4, +64.3, 245.5, 43.9, 79.8, 44.0, 76.2, 43.5, 76.1, 44.2, 72.5, +44.4, 71.7, 44.2, 70.8, 44.2, 70.8, 45.3, 66.2, 44.7, 65.8, +46.8, 61.7, 46.6, 62.8, 47.2, 62.9, 47.6, 64.1, 46.3, 72.1, +46.9, 72.5, 43.9, 79.8, 649.4, 530.7, 645.6, 524.9, 641.9, 519.1, +641.9, 519.1, 639.7, 515.7, 639.7, 515.7, 637.5, 512.3, 637.5, 512.3, +637.5, 512.3, 637.5, 512.3, 638.0, 511.3, 637.6, 511.1, 637.8, 510.0, +652.4, 503.5, 652.8, 504.4, 667.8, 498.9, 677.4, 495.4, 677.4, 495.4, +687.0, 491.8, 694.7, 489.0, 700.5, 484.1, 702.3, 486.2, 701.6, 497.2, +701.6, 497.2, 700.8, 508.2, 698.8, 512.4, 695.2, 510.7, 689.5, 513.1, +669.4, 521.9, 670.2, 528.0, 649.4, 530.7, 700.8, 471.3, 701.9, 472.8, +701.9, 472.8, 703.1, 474.3, 703.5, 474.5, 703.0, 475.8, 702.9, 477.3, +701.0, 474.9, 700.6, 474.2, 700.8, 471.3, 808.2, 400.0, 814.9, 404.7, +820.1, 403.3, 821.7, 409.3, 859.1, 470.9, 856.4, 472.5, 890.9, 536.0, +891.2, 536.4, 890.9, 536.6, 891.0, 537.3, 892.0, 543.8, 892.0, 543.8, +893.0, 550.3, 848.4, 476.5, 847.1, 476.9, 808.2, 400.0, 893.0, 550.3, +893.2, 551.5, 892.7, 551.8, 893.3, 552.6, 889.0, 549.7, 889.0, 549.7, +884.7, 546.7, 880.9, 539.6, 880.0, 540.1, 875.4, 533.5, 862.6, 514.1, +862.4, 514.2, 849.5, 494.8, 844.3, 485.5, 844.7, 485.2, 838.7, 476.3, +814.6, 432.8, 819.3, 429.5, 790.5, 389.3, 790.0, 388.3, 790.0, 388.3, +789.5, 387.2, 797.2, 395.2, 798.9, 393.6, 808.2, 400.0, 847.1, 476.9, +848.4, 476.5, 893.0, 550.3, 731.1, 91.4, 720.8, 83.6, 721.9, 78.2, +710.6, 75.9, 720.4, 73.8, 721.6, 76.1, 730.2, 71.7, 731.7, 69.2, +734.5, 70.8, 738.7, 69.9, 741.7, 82.2, 756.8, 78.4, 775.0, 86.9, +771.2, 83.6, 767.7, 87.7, 760.4, 88.4, 745.7, 89.9, 744.5, 94.7, +731.1, 91.4, 782.2, 136.8, 788.0, 137.7, 788.0, 138.5, 793.9, 138.7, +800.7, 141.9, 800.0, 143.3, 806.2, 148.0, 811.6, 152.0, 811.6, 152.0, +816.9, 156.1, 818.5, 154.8, 822.6, 162.9, 829.8, 165.7, 834.0, 165.0, +834.8, 169.5, 839.8, 173.3, 876.6, 201.0, 876.6, 201.0, 913.4, 228.8, +918.1, 232.3, 918.0, 232.3, 922.7, 235.8, 925.8, 238.2, 925.8, 238.2, +929.0, 240.6, 912.7, 229.3, 912.8, 229.1, 896.6, 217.7, 896.5, 217.6, +896.4, 217.7, 896.3, 217.7, 858.2, 190.7, 858.3, 190.6, 820.2, 163.7, +801.2, 150.2, 798.9, 152.6, 782.2, 136.8, 782.6, 330.9, 782.3, 332.4, +782.8, 333.4, 782.0, 333.8, 780.3, 335.4, 782.3, 338.7, 780.8, 339.3, +767.9, 345.5, 767.9, 345.5, 755.0, 351.7, 744.1, 349.8, 745.6, 341.5, +736.2, 331.2, 736.2, 331.2, 730.1, 324.6, 724.0, 317.9, 748.1, 316.3, +748.5, 323.3, 773.0, 328.8, 777.8, 329.9, 778.5, 328.6, 782.6, 330.9, +578.7, 157.1, 578.3, 156.9, 578.1, 157.0, 578.0, 156.8, 567.2, 135.5, +567.2, 135.5, 556.4, 114.1, 565.8, 120.1, 566.5, 119.0, 576.5, 124.0, +581.7, 126.7, 581.8, 126.6, 587.0, 129.2, 596.9, 134.4, 596.9, 134.4, +606.8, 139.6, 603.3, 151.5, 592.9, 148.5, 578.7, 157.1, 690.7, 281.6, +697.1, 288.6, 697.1, 288.6, 703.6, 295.6, 710.4, 303.0, 710.4, 303.0, +717.1, 310.4, 720.6, 314.2, 720.6, 314.2, 724.0, 317.9, 730.1, 324.6, +736.2, 331.2, 736.2, 331.2, 745.6, 341.5, 744.1, 349.8, 755.0, 351.7, +750.9, 353.7, 750.9, 353.7, 746.8, 355.7, 734.4, 346.0, 737.0, 342.8, +727.2, 329.8, 708.9, 305.7, 707.9, 306.5, 690.7, 281.6, 645.4, 281.4, +639.4, 274.1, 639.4, 274.1, 633.4, 266.7, 624.4, 257.5, 629.3, 253.2, +621.3, 242.7, 617.0, 239.1, 618.6, 237.3, 615.8, 231.9, 631.1, 256.4, +632.5, 255.7, 645.4, 281.4, 695.4, 173.0, 681.8, 158.3, 682.3, 157.8, +668.3, 143.7, 666.0, 142.0, 666.3, 141.5, 664.3, 139.4, 666.5, 141.3, +666.8, 140.9, 669.2, 142.5, 711.0, 169.1, 716.3, 163.2, 752.8, 195.8, +753.2, 196.1, 753.4, 195.9, 753.8, 196.2, 758.2, 199.1, 758.1, 199.2, +762.5, 202.3, 764.9, 203.9, 764.9, 203.8, 767.2, 205.4, 768.4, 206.2, +768.4, 206.2, 769.5, 207.0, 732.3, 190.2, 729.6, 194.5, 695.4, 173.0, +769.5, 207.0, 794.8, 224.5, 794.8, 224.5, 820.2, 241.9, 812.5, 238.1, +810.9, 240.7, 804.0, 236.0, 757.7, 213.1, 757.7, 213.1, 711.3, 190.3, +709.2, 189.3, 709.9, 187.9, 707.8, 186.5, 707.8, 186.6, 701.6, 179.8, +695.4, 173.0, 729.6, 194.5, 732.3, 190.2, 769.5, 207.0, 574.2, 109.7, +572.5, 108.7, 572.4, 108.8, 570.7, 107.6, 569.7, 106.9, 569.6, 106.1, +568.7, 106.2, 569.2, 106.1, 569.2, 106.1, 569.8, 106.0, 572.2, 107.5, +572.8, 107.4, 574.2, 109.7, 538.5, 212.0, 511.4, 202.2, 511.4, 202.2, +484.2, 192.4, 483.2, 193.7, 468.9, 182.5, 453.6, 172.7, 477.3, 175.2, +476.5, 183.3, 499.3, 193.9, 505.2, 196.6, 505.2, 196.6, 511.1, 199.4, +524.8, 205.7, 524.1, 208.3, 538.5, 212.0, 480.4, 35.4, 492.4, 20.0, +492.4, 20.0, 504.3, 4.5, 503.8, 5.4, 504.9, 6.1, 505.4, 7.7, +500.4, 15.2, 499.3, 14.5, 493.2, 21.2, 486.8, 28.3, 485.7, 27.5, +480.4, 35.4, 413.7, 132.6, 409.4, 132.7, 408.4, 130.9, 405.1, 132.7, +406.3, 131.1, 406.3, 131.1, 407.5, 129.4, 427.1, 106.7, 425.9, 105.7, +444.3, 82.0, 453.8, 73.5, 465.3, 82.3, 470.6, 73.3, 450.2, 107.6, +442.5, 103.1, 414.2, 132.6, 414.0, 132.6, 414.0, 132.6, 413.7, 132.6, +470.6, 73.3, 480.3, 65.3, 491.4, 73.5, 496.1, 64.9, 470.4, 92.8, +470.4, 92.8, 444.8, 120.8, 428.9, 123.9, 424.2, 121.8, 414.2, 132.6, +414.0, 132.6, 414.0, 132.6, 413.7, 132.6, 442.0, 102.8, 439.1, 99.2, +470.6, 73.3, 578.5, 1.0, 573.7, -6.8, 567.4, -13.1, 568.9, -14.7, +569.8, -17.4, 571.5, -18.3, 570.6, -20.1, 568.1, -21.8, 573.8, -30.5, +577.0, -41.0, 574.6, -40.2, 577.3, -31.7, 577.7, -22.4, 578.1, -10.7, +584.0, -3.9, 578.5, 1.0, 240.9, 156.3, 240.3, 155.6, 239.5, 155.4, +239.6, 154.9, 248.0, 118.7, 248.0, 118.7, 256.4, 82.5, 253.0, 96.4, +253.5, 96.5, 250.6, 110.4, 245.7, 133.4, 246.6, 133.6, 240.9, 156.3, +254.9, 243.8, 255.7, 242.2, 250.0, 239.5, 245.2, 235.3, 235.1, 226.5, +234.7, 226.9, 225.0, 217.7, 225.1, 217.0, 225.1, 217.0, 225.3, 216.3, +226.0, 217.1, 248.9, 202.2, 265.1, 182.1, 266.6, 180.8, 266.6, 180.8, +268.0, 179.5, 268.3, 176.5, 271.1, 176.8, 274.3, 174.1, 267.1, 209.5, +270.2, 211.6, 254.9, 243.8, 274.3, 174.1, 280.3, 169.0, 280.3, 169.0, +286.3, 163.8, 286.7, 162.2, 291.1, 164.4, 293.7, 162.2, 289.7, 178.2, +281.7, 180.7, 285.8, 194.3, 287.8, 196.8, 281.7, 200.4, 283.1, 204.9, +269.4, 209.6, 276.7, 231.0, 270.2, 257.1, 270.8, 256.4, 254.6, 250.1, +254.9, 243.8, 270.2, 211.6, 267.1, 209.5, 274.3, 174.1, 245.2, 235.3, +250.0, 239.5, 255.7, 242.2, 254.9, 243.8, 254.6, 250.1, 270.8, 256.4, +270.2, 257.1, 266.8, 270.9, 262.5, 271.2, 263.4, 284.6, 260.9, 283.4, +260.9, 283.4, 258.3, 282.1, 252.2, 279.3, 252.4, 278.8, 246.4, 275.6, +241.1, 256.7, 240.2, 253.9, 245.2, 235.3, 246.4, 275.6, 230.9, 267.1, +231.4, 266.1, 215.5, 258.6, 220.2, 238.1, 220.2, 238.1, 225.0, 217.7, +234.7, 226.9, 235.1, 226.5, 245.2, 235.3, 240.2, 253.9, 241.1, 256.7, +246.4, 275.6, 357.1, 144.7, 357.5, 151.5, 356.2, 151.9, 358.0, 158.3, +344.2, 177.1, 356.5, 189.2, 361.9, 218.8, 361.3, 219.5, 361.3, 219.5, +360.7, 220.3, 355.7, 209.1, 352.7, 208.9, 352.1, 197.2, 350.9, 171.1, +353.2, 170.7, 357.1, 144.7, 310.9, 158.1, 306.2, 144.2, 302.9, 144.6, +301.6, 130.4, 301.6, 130.4, 301.5, 130.3, 301.5, 130.3, 301.9, 127.8, +300.6, 127.6, 299.7, 125.0, 298.3, 122.7, 302.5, 120.1, 305.2, 115.3, +310.9, 124.6, 306.7, 127.1, 308.3, 138.9, 309.6, 148.5, 305.7, 151.6, +310.9, 158.1, 309.4, 53.8, 303.3, 55.2, 297.3, 55.1, 297.3, 56.6, +292.3, 52.8, 282.4, 55.0, 278.3, 61.0, 273.9, 47.9, 275.0, 35.4, +269.6, 34.9, 270.1, 33.0, 270.1, 33.0, 270.6, 31.1, 271.6, 29.7, +271.6, 29.7, 272.6, 28.3, 291.9, 39.5, 295.2, 37.4, 309.4, 53.8, +272.6, 28.3, 281.5, 15.3, 281.5, 15.3, 290.4, 2.4, 306.7, 25.1, +311.9, 21.3, 333.5, 40.1, 330.6, 42.5, 329.4, 47.0, 331.0, 48.8, +320.2, 51.3, 320.2, 51.3, 309.4, 53.8, 295.2, 37.4, 291.9, 39.5, +272.6, 28.3, 263.4, 293.9, 267.9, 291.5, 272.4, 291.5, 272.4, 289.1, +272.6, 289.1, 272.7, 289.2, 272.7, 289.2, 272.7, 289.1, 273.2, 289.5, +273.8, 289.7, 269.1, 295.9, 277.3, 306.1, 286.0, 318.8, 284.3, 320.9, +284.3, 320.9, 282.5, 323.1, 275.2, 330.1, 274.9, 329.8, 267.3, 336.5, +265.5, 338.1, 265.4, 339.8, 263.7, 339.6, 263.6, 339.6, 263.7, 337.9, +263.7, 336.2, 263.6, 315.1, 259.6, 314.3, 263.4, 293.9, 153.1, 461.8, +164.8, 441.2, 168.2, 442.5, 176.4, 420.6, 176.4, 416.5, 178.7, 416.5, +181.0, 412.4, 186.9, 405.9, 190.4, 408.1, 194.2, 400.8, 180.4, 426.9, +177.6, 425.5, 161.0, 450.1, 157.1, 456.0, 156.4, 455.6, 153.1, 461.8, +149.5, 388.3, 147.8, 368.2, 147.8, 368.2, 146.0, 348.1, 150.8, 329.2, +150.0, 329.0, 154.0, 309.9, 158.2, 344.5, 152.0, 345.3, 150.0, 380.7, +149.8, 384.5, 149.1, 384.6, 149.5, 388.3, 488.6, 852.4, 490.1, 864.3, +489.4, 864.4, 491.6, 876.2, 491.8, 878.8, 490.7, 880.5, 492.0, 881.3, +484.3, 884.0, 483.2, 883.3, 474.9, 881.8, 475.7, 881.1, 474.8, 880.1, +474.7, 878.3, 473.9, 865.1, 467.8, 861.9, 473.1, 852.0, 474.8, 848.9, +485.7, 848.5, 488.6, 852.4, 473.1, 852.0, 460.8, 773.6, 466.9, 772.5, +463.6, 692.9, 466.0, 687.8, 466.3, 687.2, 466.1, 681.7, 466.6, 682.9, +466.6, 682.9, 467.1, 684.1, 461.8, 693.8, 469.0, 697.8, 470.8, 711.5, +474.2, 737.2, 474.2, 737.2, 477.6, 762.9, 477.9, 765.2, 477.9, 765.3, +478.2, 767.6, 483.4, 810.0, 483.4, 810.0, 488.6, 852.4, 485.7, 848.5, +474.8, 848.9, 473.1, 852.0, 580.6, 496.9, 580.8, 495.0, 576.3, 494.4, +572.1, 491.9, 568.0, 489.5, 564.1, 489.9, 563.8, 487.0, 566.6, 477.0, +566.8, 467.0, 569.4, 467.1, 572.1, 457.2, 568.4, 453.0, 574.9, 447.3, +572.0, 449.9, 575.7, 454.1, 576.4, 460.9, 578.5, 478.9, 583.0, 479.5, +580.6, 496.9, 570.5, 776.6, 568.1, 777.6, 568.6, 778.9, 566.7, 781.1, +553.8, 796.7, 553.8, 796.7, 540.9, 812.3, 525.4, 830.9, 521.3, 851.8, +510.0, 849.6, 512.6, 828.3, 512.6, 828.3, 515.2, 807.1, 515.6, 805.4, +517.5, 805.8, 519.9, 804.5, 533.1, 797.2, 533.1, 797.2, 546.4, 789.9, +558.4, 783.3, 557.9, 782.0, 570.5, 776.6, 538.4, 619.0, 540.1, 605.1, +540.1, 605.1, 541.9, 591.3, 541.1, 592.1, 553.2, 598.7, 552.4, 604.6, +551.4, 612.5, 537.6, 618.0, 538.4, 619.0, 476.1, 608.4, 475.7, 614.6, +466.7, 616.9, 468.3, 620.3, 469.2, 607.8, 469.2, 607.8, 470.1, 595.2, +468.0, 598.4, 476.6, 602.1, 476.1, 608.4, 470.1, 595.2, 472.3, 563.6, +472.3, 563.6, 474.6, 531.9, 475.4, 529.7, 486.1, 528.4, 491.4, 532.6, +488.9, 543.1, 496.5, 551.7, 508.7, 559.0, 503.3, 585.9, 497.1, 588.7, +476.1, 608.4, 476.6, 602.1, 468.0, 598.4, 470.1, 595.2, 549.3, 443.3, +563.3, 440.9, 563.8, 442.5, 577.4, 438.4, 576.8, 438.4, 576.1, 442.9, +574.9, 447.3, 568.4, 453.0, 572.1, 457.2, 569.4, 467.1, 563.1, 466.9, +562.9, 477.0, 556.3, 486.9, 544.2, 472.5, 552.8, 465.2, 549.3, 443.5, +549.3, 443.4, 549.3, 443.3, 549.3, 443.3, 516.5, 550.4, 517.0, 557.6, +517.0, 557.6, 517.5, 564.7, 517.6, 565.4, 517.1, 566.1, 517.0, 566.1, +516.8, 566.1, 517.0, 565.3, 517.0, 564.6, 516.7, 557.5, 518.6, 551.0, +516.5, 550.4, 474.2, 687.1, 474.0, 684.3, 473.9, 684.3, 473.7, 681.5, +492.4, 628.3, 493.5, 628.7, 513.3, 575.9, 514.3, 573.4, 514.3, 573.5, +515.2, 571.0, 505.3, 599.1, 505.3, 599.1, 495.3, 627.2, 484.8, 657.2, +485.9, 657.6, 474.2, 687.1, 450.6, 316.3, 450.9, 313.9, 452.2, 312.4, +451.2, 311.6, 456.5, 306.3, 452.4, 302.1, 453.6, 292.6, 456.8, 298.7, +459.4, 299.2, 466.5, 301.3, 472.6, 312.8, 472.6, 312.8, 478.6, 324.2, +478.7, 323.4, 471.0, 322.1, 463.3, 319.9, 461.5, 319.4, 461.5, 319.4, +459.7, 318.9, 458.1, 318.4, 458.1, 318.4, 456.6, 318.0, 453.6, 317.2, +452.2, 318.3, 450.6, 316.3, 193.0, 612.6, 191.5, 619.8, 193.1, 620.6, +189.9, 626.9, 187.0, 635.3, 187.0, 635.3, 184.0, 643.8, 184.3, 642.6, +183.1, 642.3, 182.2, 640.8, 182.7, 636.7, 183.7, 636.8, 185.3, 632.9, +188.4, 624.7, 188.4, 624.7, 191.5, 616.5, 192.3, 614.5, 192.7, 614.6, +193.0, 612.6, 219.0, 424.9, 221.4, 447.0, 233.1, 461.9, 223.8, 469.2, +218.1, 495.7, 218.1, 495.7, 212.4, 522.3, 207.3, 474.5, 208.9, 472.1, +219.0, 424.9, 212.4, 522.3, 209.1, 537.8, 209.1, 537.8, 205.8, 553.2, +203.9, 543.4, 200.7, 544.0, 195.7, 534.8, 207.3, 489.8, 222.8, 476.9, +205.2, 441.3, 211.9, 430.8, 211.9, 430.8, 218.5, 420.3, 217.7, 422.0, +218.8, 422.6, 219.0, 424.9, 208.9, 472.1, 207.3, 474.5, 212.4, 522.3, +461.7, 734.0, 463.2, 759.7, 463.1, 759.8, 464.7, 785.5, 462.5, 801.0, +462.5, 801.0, 460.2, 816.6, 455.1, 797.7, 446.6, 800.0, 433.0, 783.4, +430.7, 774.5, 439.5, 772.2, 446.0, 761.1, 450.1, 753.9, 450.1, 753.9, +454.2, 746.8, 458.0, 740.4, 463.1, 739.0, 461.7, 734.0, 447.6, 495.3, +448.0, 501.2, 447.9, 501.2, 448.3, 507.2, 450.3, 533.5, 449.9, 533.5, +451.5, 559.9, 451.9, 567.7, 451.9, 567.7, 452.4, 575.5, 451.9, 567.7, +451.9, 567.7, 451.5, 559.9, 449.9, 533.5, 450.3, 533.5, 448.3, 507.2, +447.9, 501.2, 448.0, 501.2, 447.6, 495.3, 413.5, 651.4, 420.1, 608.0, +416.2, 607.4, 419.2, 563.4, 419.9, 555.0, 419.9, 555.0, 420.6, 546.5, +420.6, 543.2, 420.9, 543.2, 421.2, 539.9, 424.7, 497.4, 425.3, 497.4, +428.3, 454.9, 429.0, 448.0, 429.9, 448.1, 431.6, 441.3, 431.6, 441.3, +431.6, 441.3, 431.6, 441.3, 436.2, 422.4, 436.2, 422.4, 440.8, 403.5, +441.3, 401.3, 442.4, 401.0, 441.8, 399.1, 442.2, 404.5, 442.2, 404.5, +442.5, 409.9, 428.9, 530.8, 431.7, 531.2, 413.5, 651.4, 442.5, 409.9, +443.4, 424.6, 443.4, 424.6, 444.3, 439.3, 444.3, 445.8, 443.4, 445.8, +442.5, 452.2, 432.1, 526.1, 432.1, 526.1, 421.8, 600.0, 417.1, 633.6, +417.8, 633.8, 412.4, 667.3, 413.3, 659.4, 413.0, 659.4, 413.5, 651.4, +431.7, 531.2, 428.9, 530.8, 442.5, 409.9, 383.3, 722.9, 393.5, 735.4, +396.2, 749.3, 403.8, 747.8, 409.1, 754.3, 409.1, 754.3, 414.4, 760.8, +416.7, 763.5, 416.7, 763.5, 418.9, 766.3, 423.1, 771.4, 424.8, 770.6, +427.3, 776.5, 434.5, 793.1, 432.8, 793.9, 438.3, 811.2, 438.3, 811.3, +438.3, 811.3, 438.3, 811.3, 438.3, 811.3, 438.3, 811.3, 438.3, 811.2, +420.6, 782.9, 420.6, 782.9, 403.0, 754.5, 393.1, 738.7, 381.6, 737.4, +383.3, 722.9, 366.8, 867.4, 358.6, 864.1, 355.0, 857.9, 350.4, 860.7, +354.5, 820.5, 354.5, 820.5, 358.6, 780.4, 359.1, 775.3, 359.2, 775.3, +359.7, 770.2, 363.7, 811.1, 362.7, 811.2, 365.7, 852.2, 366.3, 859.8, +369.6, 865.9, 366.8, 867.4, 377.8, 211.3, 377.6, 210.3, 377.6, 210.3, +377.5, 209.4, 397.1, 195.9, 394.7, 192.4, 411.9, 175.4, 400.3, 185.7, +401.1, 186.7, 390.4, 198.0, 389.4, 199.1, 389.4, 199.1, 388.3, 200.2, +383.0, 205.7, 383.6, 206.3, 377.8, 211.3, 239.8, 662.8, 239.0, 701.7, +233.3, 701.6, 226.8, 740.4, 226.3, 743.4, 225.6, 743.4, 225.8, 746.3, +225.1, 709.3, 223.8, 709.3, 221.9, 672.3, 221.9, 670.5, 225.1, 670.6, +228.3, 668.9, 234.0, 665.8, 239.7, 665.9, 239.8, 662.8, 223.6, 759.5, +224.7, 752.9, 226.0, 752.9, 225.8, 746.3, 225.6, 743.4, 226.3, 743.4, +226.8, 740.4, 243.2, 724.1, 244.4, 725.4, 262.0, 710.4, 263.0, 709.5, +263.0, 709.5, 264.0, 708.7, 312.0, 667.8, 311.7, 667.4, 360.0, 626.8, +359.6, 627.2, 360.2, 627.9, 359.8, 628.3, 353.5, 635.0, 353.1, 634.7, +346.4, 641.2, 315.7, 670.8, 315.7, 670.8, 284.9, 700.5, 262.0, 722.6, +262.0, 722.6, 239.0, 744.7, 237.6, 746.0, 237.6, 746.0, 236.2, 747.4, +229.9, 753.5, 229.3, 760.1, 223.6, 759.5, 285.2, 852.2, 296.7, 804.1, +297.5, 803.6, 317.2, 758.2, 316.2, 760.6, 323.3, 763.1, 322.6, 766.3, +318.0, 785.6, 314.5, 784.8, 306.5, 803.3, 295.8, 827.8, 291.3, 826.7, +285.2, 852.2, 349.9, 662.3, 350.7, 654.7, 355.3, 654.7, 355.0, 647.4, +352.0, 670.9, 358.7, 672.9, 351.3, 694.7, 351.0, 696.9, 351.9, 697.8, +350.7, 699.0, 338.7, 735.0, 345.8, 737.4, 340.8, 775.8, 339.6, 719.2, +343.7, 718.9, 349.9, 662.3, 340.8, 775.8, 339.9, 783.2, 339.9, 783.2, +338.9, 790.7, 327.5, 784.7, 330.7, 778.5, 322.6, 766.3, 323.3, 763.1, +316.2, 760.6, 317.2, 758.2, 319.6, 741.4, 322.8, 741.8, 328.4, 725.4, +338.4, 696.1, 338.4, 696.1, 348.4, 666.8, 349.1, 664.5, 349.7, 664.6, +349.9, 662.3, 343.7, 718.9, 339.6, 719.2, 340.8, 775.8, 385.0, 633.5, +387.8, 636.1, 383.1, 641.1, 381.3, 648.8, 380.1, 653.4, 380.1, 653.4, +379.0, 658.0, 378.4, 660.7, 376.7, 661.9, 377.7, 663.3, 370.4, 646.5, +368.6, 647.3, 359.5, 631.2, 359.8, 632.0, 361.1, 631.4, 362.7, 631.5, +373.8, 632.5, 378.5, 627.5, 385.0, 633.5, 400.7, 531.7, 402.1, 534.9, +401.5, 535.4, 403.6, 538.0, 403.4, 537.8, 403.4, 537.8, 403.2, 537.7, +357.2, 510.5, 356.8, 511.0, 310.5, 484.3, 343.2, 510.4, 348.2, 504.2, +386.0, 524.0, 393.3, 527.9, 394.3, 526.7, 400.7, 531.7, 356.4, 303.0, +350.0, 293.2, 344.7, 282.9, 343.5, 283.5, 344.3, 276.1, 338.5, 275.2, +332.8, 267.4, 335.2, 259.1, 340.4, 253.4, 337.6, 250.9, 339.1, 248.9, +340.9, 248.6, 340.6, 246.9, 340.1, 246.3, 343.2, 243.5, 345.7, 240.1, +353.6, 266.3, 350.3, 267.3, 355.0, 294.4, 355.7, 298.7, 353.9, 300.6, +356.4, 303.0, 384.0, 325.9, 390.1, 329.9, 392.4, 326.4, 400.9, 326.8, +403.1, 330.3, 415.1, 326.1, 415.3, 327.6, 419.6, 334.6, 419.6, 334.6, +423.8, 341.6, 403.5, 340.5, 401.6, 337.3, 384.0, 325.9, 354.1, 435.3, +341.6, 425.3, 342.3, 424.3, 329.1, 415.3, 326.5, 412.4, 326.5, 412.4, +324.0, 409.5, 332.6, 410.0, 335.1, 405.5, 342.0, 397.7, 367.3, 394.6, +370.0, 392.8, 393.7, 400.8, 390.0, 399.5, 387.8, 405.9, 381.9, 411.1, +368.0, 423.2, 368.9, 434.1, 354.1, 435.3, 272.8, 437.6, 273.4, 436.3, +273.4, 436.3, 274.1, 435.0, 268.9, 461.0, 268.4, 460.9, 262.9, 486.8, +261.9, 491.5, 261.0, 496.3, 261.0, 496.3, 261.0, 496.3, 261.9, 491.5, +262.9, 486.8, 267.9, 462.2, 267.5, 462.1, 272.8, 437.6, 67.4, 175.0, +67.4, 174.8, 67.4, 174.8, 67.4, 174.6, 69.5, 163.5, 68.3, 163.3, +69.2, 152.0, 70.3, 157.7, 73.0, 157.2, 76.7, 162.3, 87.0, 209.4, +89.9, 208.8, 103.2, 255.3, 115.4, 232.0, 85.9, 216.5, 68.6, 177.8, +68.0, 176.4, 67.9, 176.4, 67.4, 175.0, 60.2, 159.3, 61.6, 171.9, +66.0, 173.1, 63.0, 184.6, 63.0, 185.0, 63.2, 185.1, 63.0, 185.5, +63.0, 185.5, 63.0, 185.5, 63.0, 185.6, 65.5, 192.5, 53.0, 194.9, +48.4, 206.4, 44.4, 195.3, 38.1, 193.9, 40.3, 184.2, 41.9, 137.6, +41.9, 137.6, 43.5, 91.0, 30.1, 107.8, 53.0, 124.9, 60.2, 159.3, +43.5, 91.0, 43.7, 85.4, 43.7, 85.4, 43.9, 79.8, 46.9, 72.5, +46.3, 72.1, 47.6, 64.1, 49.1, 68.4, 49.1, 68.4, 50.5, 72.6, +53.3, 116.1, 55.4, 116.0, 60.2, 159.3, 53.0, 124.9, 30.1, 107.8, +43.5, 91.0, 681.0, 569.7, 678.1, 569.9, 678.1, 569.9, 675.1, 570.2, +666.1, 555.9, 665.9, 556.0, 656.7, 541.9, 658.6, 545.0, 659.2, 544.7, +661.6, 547.5, 671.3, 558.6, 673.6, 557.2, 681.0, 569.7, 641.5, 479.0, +641.5, 479.0, 641.5, 479.0, 641.6, 478.9, 639.0, 466.5, 650.4, 464.2, +659.2, 449.5, 665.3, 457.3, 683.8, 457.8, 686.6, 453.1, 689.2, 456.4, +689.2, 456.4, 691.8, 459.8, 668.7, 472.9, 666.6, 469.3, 641.6, 478.9, +641.5, 479.0, 641.5, 479.0, 641.5, 479.0, 791.8, 137.2, 766.4, 118.0, +768.4, 102.3, 740.9, 98.7, 740.1, 98.2, 740.1, 98.2, 739.3, 97.6, +735.9, 98.2, 735.2, 94.5, 731.1, 91.4, 744.5, 94.7, 745.7, 89.9, +760.4, 88.4, 777.7, 99.6, 772.6, 107.4, 784.9, 126.3, 788.4, 131.7, +786.9, 134.1, 791.8, 137.2, 796.7, 204.0, 801.9, 215.2, 799.9, 216.7, +807.2, 226.4, 792.9, 218.3, 792.9, 218.3, 778.7, 210.2, 772.5, 209.7, +774.3, 201.8, 767.4, 197.3, 758.0, 193.0, 759.9, 188.8, 752.5, 180.3, +776.1, 185.6, 777.9, 188.2, 796.7, 204.0, 752.5, 180.3, 747.3, 174.3, +748.6, 172.2, 742.1, 168.4, 741.1, 167.9, 741.3, 167.5, 740.5, 166.5, +752.1, 153.2, 750.4, 148.0, 765.4, 141.4, 766.1, 141.1, 768.7, 147.1, +772.0, 152.8, 773.5, 155.3, 773.6, 155.2, 774.9, 157.7, 789.9, 177.8, +785.8, 180.8, 796.7, 204.0, 777.9, 188.2, 776.1, 185.6, 752.5, 180.3, +700.8, 121.1, 692.8, 111.8, 692.8, 111.8, 684.7, 102.6, 687.4, 102.5, +689.7, 98.8, 689.9, 99.1, 714.6, 98.4, 715.3, 102.1, 739.3, 97.6, +740.1, 98.2, 740.1, 98.2, 740.9, 98.7, 752.8, 100.3, 746.8, 120.3, +760.7, 133.2, 761.0, 133.7, 760.9, 134.2, 761.4, 134.3, 731.0, 128.2, +729.0, 132.7, 700.8, 121.1, 761.4, 134.3, 764.2, 135.2, 766.5, 139.8, +765.4, 141.4, 750.4, 148.0, 752.1, 153.2, 740.5, 166.5, 723.1, 146.6, +727.5, 138.7, 705.7, 126.7, 702.9, 126.2, 703.3, 123.9, 700.8, 121.1, +729.0, 132.7, 731.0, 128.2, 761.4, 134.3, 583.1, 158.4, 580.9, 157.7, +580.9, 157.7, 578.7, 157.1, 592.9, 148.5, 603.3, 151.5, 606.8, 139.6, +632.0, 152.8, 632.0, 152.8, 657.2, 166.0, 636.3, 182.6, 620.1, 162.6, +583.1, 158.4, 657.2, 166.0, 673.1, 174.3, 673.1, 174.3, 689.0, 182.7, +693.0, 183.9, 691.0, 188.6, 695.0, 192.2, 690.8, 194.8, 687.8, 190.0, +680.7, 187.9, 666.8, 183.7, 666.8, 183.7, 653.0, 179.5, 623.6, 160.4, +618.0, 168.9, 583.1, 158.4, 620.1, 162.6, 636.3, 182.6, 657.2, 166.0, +733.6, 362.1, 732.7, 362.5, 732.7, 362.5, 731.8, 362.9, 690.2, 300.2, +690.1, 300.2, 645.8, 239.4, 637.4, 227.1, 637.8, 226.9, 629.3, 214.7, +628.1, 213.3, 628.0, 213.3, 626.8, 212.0, 626.8, 212.0, 626.8, 212.0, +626.8, 212.0, 632.4, 218.1, 632.4, 218.1, 638.0, 224.2, 638.4, 224.6, +638.4, 224.6, 638.7, 224.9, 645.6, 232.5, 645.6, 232.5, 652.5, 240.0, +665.2, 253.8, 665.2, 253.8, 677.8, 267.5, 681.5, 271.6, 681.5, 271.6, +685.2, 275.6, 685.8, 276.2, 685.8, 276.2, 686.3, 276.8, 688.5, 279.2, +688.5, 279.2, 690.7, 281.6, 707.9, 306.5, 708.9, 305.7, 727.2, 329.8, +734.6, 343.7, 731.3, 345.8, 733.6, 362.1, 727.2, 329.8, 737.0, 342.8, +734.4, 346.0, 746.8, 355.7, 740.2, 358.9, 740.2, 358.9, 733.6, 362.1, +731.3, 345.8, 734.6, 343.7, 727.2, 329.8, 706.4, 330.7, 717.6, 347.6, +716.2, 348.6, 728.7, 364.4, 725.4, 366.0, 725.4, 366.0, 722.0, 367.6, +721.7, 367.9, 720.8, 365.9, 719.2, 365.0, 705.9, 360.5, 707.9, 354.5, +696.7, 344.0, 687.0, 328.8, 685.1, 330.0, 673.6, 315.9, 675.5, 321.6, +681.7, 319.5, 689.7, 323.2, 698.1, 326.9, 700.6, 324.6, 706.4, 330.7, +668.8, 149.5, 679.7, 163.4, 677.9, 165.3, 690.7, 177.3, 674.4, 168.6, +674.4, 168.6, 658.2, 159.9, 637.3, 162.6, 635.2, 146.2, 612.2, 132.4, +622.3, 122.5, 643.8, 135.2, 668.8, 149.5, 540.0, 203.6, 544.8, 209.8, +544.8, 209.8, 549.5, 216.0, 545.7, 212.3, 544.0, 214.0, 538.5, 212.0, +524.1, 208.3, 524.8, 205.7, 511.1, 199.4, 515.0, 201.9, 516.3, 200.1, +521.4, 200.9, 530.7, 202.2, 532.3, 199.4, 540.0, 203.6, 493.2, 21.2, +499.3, 14.5, 500.4, 15.2, 505.4, 7.7, 510.5, 23.9, 510.5, 23.9, +515.6, 40.0, 515.2, 40.4, 496.9, 33.0, 493.2, 21.2, 515.6, 40.0, +516.0, 41.4, 516.9, 42.3, 516.5, 42.7, 506.3, 53.8, 506.3, 53.8, +496.1, 64.9, 491.4, 73.5, 480.3, 65.3, 470.6, 73.3, 465.3, 82.3, +453.8, 73.5, 444.3, 82.0, 462.3, 58.7, 462.3, 58.7, 480.4, 35.4, +485.7, 27.5, 486.8, 28.3, 493.2, 21.2, 496.9, 33.0, 515.2, 40.4, +515.6, 40.0, 587.3, -74.6, 589.1, -80.4, 589.5, -86.3, 590.9, -86.2, +592.6, -88.4, 597.0, -86.2, 597.6, -88.0, 595.3, -80.4, 593.8, -76.3, +587.3, -74.6, 279.7, 73.4, 281.6, 75.0, 283.3, 74.8, 283.5, 76.5, +283.8, 77.5, 283.8, 77.5, 284.2, 78.5, 274.2, 128.6, 273.3, 128.7, +268.0, 179.5, 266.6, 180.8, 266.6, 180.8, 265.1, 182.1, 265.5, 181.5, +261.8, 178.5, 258.5, 175.0, 257.9, 162.7, 261.1, 162.6, 263.7, 150.1, +265.7, 140.4, 265.7, 140.4, 267.7, 130.7, 273.7, 102.0, 271.5, 101.4, +279.7, 73.4, 353.9, 96.6, 354.4, 104.1, 352.6, 104.8, 354.9, 111.6, +355.4, 111.8, 354.4, 113.6, 355.1, 114.2, 353.0, 126.2, 350.2, 134.3, +356.7, 139.2, 357.2, 139.2, 356.9, 141.9, 357.1, 144.7, 353.2, 170.7, +350.9, 171.1, 352.1, 197.2, 352.7, 194.0, 350.3, 193.8, 349.5, 190.1, +349.1, 188.4, 349.6, 188.2, 349.7, 186.4, 350.0, 180.1, 350.0, 180.1, +350.3, 173.8, 352.1, 135.2, 351.1, 135.1, 353.9, 96.6, 336.8, 156.0, +346.6, 170.8, 343.1, 173.1, 349.5, 190.1, 350.3, 193.8, 352.7, 194.0, +352.1, 197.2, 352.7, 208.9, 355.7, 209.1, 360.7, 220.3, 357.9, 224.1, +354.1, 225.8, 355.0, 227.9, 354.5, 228.5, 354.5, 229.1, 354.1, 229.1, +349.0, 223.4, 336.9, 222.5, 333.8, 226.6, 331.8, 220.7, 331.8, 220.7, +329.9, 214.9, 330.5, 191.8, 332.6, 191.9, 335.3, 168.8, 336.0, 162.4, +339.5, 160.1, 336.8, 156.0, 197.4, 398.0, 197.4, 397.9, 195.8, 399.4, +194.2, 400.8, 190.4, 408.1, 186.9, 405.9, 181.0, 412.4, 185.5, 404.4, +185.5, 404.4, 190.1, 396.4, 191.7, 394.9, 195.3, 395.7, 197.4, 398.0, +267.3, 336.5, 274.9, 329.8, 275.2, 330.1, 282.5, 323.1, 243.4, 371.5, +243.4, 371.5, 204.3, 420.0, 173.8, 423.9, 175.8, 445.4, 149.2, 472.6, +150.9, 467.6, 150.9, 467.6, 152.7, 462.6, 152.8, 462.2, 153.0, 462.3, +153.1, 461.8, 156.4, 455.6, 157.1, 456.0, 161.0, 450.1, 211.6, 394.2, +212.2, 394.7, 263.7, 339.6, 265.4, 339.8, 265.5, 338.1, 267.3, 336.5, +161.0, 450.1, 177.6, 425.5, 180.4, 426.9, 194.2, 400.8, 195.8, 399.4, +197.4, 397.9, 197.4, 398.0, 230.6, 368.8, 230.6, 368.8, 263.7, 339.6, +265.4, 339.8, 265.5, 338.1, 267.3, 336.5, 214.3, 393.5, 219.1, 399.0, +161.0, 450.1, 182.0, 340.9, 181.9, 342.0, 182.1, 342.0, 181.8, 343.0, +179.0, 352.7, 179.1, 352.8, 176.4, 362.5, 177.8, 378.3, 163.4, 379.5, +150.4, 396.6, 158.1, 366.7, 165.8, 368.5, 182.0, 340.9, 606.6, 614.7, +613.0, 605.6, 611.2, 604.3, 615.8, 594.0, 621.3, 581.5, 619.6, 580.4, +626.8, 569.1, 625.3, 571.4, 628.0, 572.7, 627.2, 575.8, 626.3, 579.7, +625.3, 579.5, 623.3, 583.1, 615.0, 598.9, 616.8, 600.2, 606.6, 614.7, +755.2, 696.0, 759.7, 703.1, 759.7, 703.1, 764.3, 710.3, 750.1, 721.0, +751.8, 723.2, 739.3, 736.1, 743.2, 733.3, 741.4, 730.8, 743.5, 725.6, +749.3, 710.8, 744.3, 704.0, 755.2, 696.0, 615.8, 594.0, 611.2, 604.3, +613.0, 605.6, 606.6, 614.7, 598.3, 633.5, 603.5, 638.6, 590.1, 652.2, +590.7, 651.6, 585.5, 646.4, 580.9, 640.6, 579.6, 639.0, 579.6, 639.0, +578.3, 637.3, 577.2, 636.0, 576.0, 635.8, 576.1, 634.6, 576.4, 631.8, +577.6, 632.0, 579.1, 629.3, 579.9, 628.0, 579.9, 628.0, 580.6, 626.7, +586.2, 616.8, 583.9, 614.2, 591.8, 606.9, 601.4, 597.9, 609.1, 590.4, +615.8, 594.0, 591.8, 606.9, 587.9, 600.6, 599.4, 593.4, 607.0, 580.0, +621.3, 554.7, 618.1, 552.2, 635.6, 529.4, 635.9, 529.0, 641.7, 530.6, +642.5, 533.4, 643.4, 536.7, 640.7, 537.4, 639.0, 541.4, 632.9, 555.2, +632.9, 555.2, 626.8, 569.1, 619.6, 580.4, 621.3, 581.5, 615.8, 594.0, +609.1, 590.4, 601.4, 597.9, 591.8, 606.9, 576.4, 460.9, 575.7, 454.1, +572.0, 449.9, 574.9, 447.3, 576.1, 442.9, 576.8, 438.4, 577.4, 438.4, +578.4, 438.1, 577.9, 436.5, 578.5, 434.6, 598.0, 464.0, 628.7, 470.0, +623.1, 489.8, 630.0, 500.6, 631.2, 500.0, 636.9, 511.4, 637.2, 511.8, +637.6, 512.1, 637.5, 512.3, 637.5, 512.3, 637.5, 512.3, 637.5, 512.3, +607.0, 486.6, 604.0, 489.4, 576.4, 460.9, 637.5, 512.3, 639.7, 515.7, +639.7, 515.7, 641.9, 519.1, 649.1, 530.3, 655.8, 530.1, 656.3, 541.6, +656.1, 537.2, 649.4, 537.5, 642.5, 533.4, 641.7, 530.6, 635.9, 529.0, +635.6, 529.4, 620.6, 520.5, 620.6, 520.5, 605.6, 511.6, 602.6, 509.9, +602.6, 509.9, 599.7, 508.2, 590.1, 502.5, 584.7, 505.2, 580.6, 496.9, +583.0, 479.5, 578.5, 478.9, 576.4, 460.9, 610.9, 469.7, 606.8, 486.0, +636.9, 511.4, 637.2, 511.8, 637.6, 512.1, 637.5, 512.3, 637.5, 512.3, +637.5, 512.3, 637.5, 512.3, 573.7, 767.7, 573.8, 767.6, 575.8, 769.6, +575.5, 770.6, 574.2, 774.0, 573.6, 774.5, 570.5, 776.6, 557.9, 782.0, +558.4, 783.3, 546.4, 789.9, 553.7, 788.1, 552.8, 784.7, 559.2, 779.4, +566.5, 773.6, 565.6, 772.1, 573.7, 767.7, 595.9, 745.9, 603.8, 735.1, +604.5, 735.6, 613.0, 725.3, 621.9, 714.5, 620.4, 712.7, 630.9, 703.8, +630.8, 703.8, 632.3, 705.6, 633.8, 707.5, 634.9, 708.8, 636.2, 709.4, +635.9, 710.2, 634.5, 713.3, 633.1, 712.6, 630.4, 715.1, 623.2, 721.6, +623.2, 721.6, 616.0, 728.0, 609.7, 733.6, 609.7, 733.6, 603.4, 739.3, +602.5, 740.0, 602.5, 740.0, 601.6, 740.8, 598.8, 743.4, 598.1, 742.9, +595.9, 745.9, 545.8, 831.4, 545.8, 831.4, 550.9, 851.6, 556.0, 871.7, +556.0, 871.9, 556.0, 871.9, 556.1, 872.2, 556.7, 874.7, 556.7, 874.7, +557.4, 877.2, 557.6, 878.3, 557.7, 879.4, 557.9, 879.4, 539.7, 881.0, +522.2, 884.3, 521.2, 880.5, 516.2, 860.4, 528.4, 835.8, 545.8, 831.4, +521.2, 880.5, 518.2, 884.3, 506.9, 883.2, 506.1, 880.9, 511.1, 866.3, +508.0, 865.3, 510.0, 849.6, 521.3, 851.8, 525.4, 830.9, 540.9, 812.3, +538.9, 813.6, 542.7, 819.2, 544.4, 826.1, 544.5, 826.3, 544.5, 826.3, +544.5, 826.6, 545.2, 829.0, 546.6, 829.6, 545.8, 831.4, 528.4, 835.8, +516.2, 860.4, 521.2, 880.5, 501.0, 479.8, 509.2, 464.3, 517.2, 464.4, +517.4, 448.8, 528.2, 446.9, 528.2, 446.9, 539.0, 445.1, 538.5, 445.1, +538.5, 445.4, 538.1, 445.8, 529.7, 453.6, 529.7, 453.6, 521.2, 461.3, +511.1, 470.5, 499.2, 474.1, 501.0, 479.8, 513.3, 575.9, 493.5, 628.7, +492.4, 628.3, 473.7, 681.5, 473.3, 677.4, 473.3, 677.4, 472.9, 673.2, +478.0, 656.7, 479.6, 657.2, 486.2, 641.2, 499.8, 608.6, 502.9, 609.6, +513.3, 575.9, 495.3, 627.2, 497.7, 601.0, 504.3, 601.6, 513.3, 575.9, +514.3, 573.4, 514.3, 573.5, 515.2, 571.0, 516.1, 568.5, 516.1, 568.5, +517.0, 566.1, 517.1, 566.1, 517.6, 565.4, 517.5, 564.7, 519.4, 590.9, +515.0, 592.1, 521.3, 617.1, 514.9, 633.7, 506.3, 648.9, 508.5, 650.2, +506.8, 653.2, 507.2, 653.4, 506.0, 656.7, 498.3, 643.3, 494.0, 641.4, +495.3, 627.2, 506.0, 656.7, 495.0, 685.1, 490.1, 684.0, 484.0, 713.4, +484.7, 720.8, 478.3, 721.1, 478.0, 728.9, 471.0, 709.9, 470.8, 707.1, +474.2, 687.1, 485.9, 657.6, 484.8, 657.2, 495.3, 627.2, 494.0, 641.4, +498.3, 643.3, 506.0, 656.7, 445.1, 359.6, 446.0, 352.4, 448.3, 351.9, +446.9, 345.2, 449.8, 331.0, 448.7, 330.7, 450.6, 316.3, 452.2, 318.3, +453.6, 317.2, 456.6, 318.0, 457.2, 318.6, 456.1, 319.7, 455.6, 321.4, +451.7, 335.6, 451.7, 335.6, 447.8, 349.9, 446.4, 354.8, 444.3, 355.2, +445.1, 359.6, 158.8, 562.8, 158.5, 560.6, 157.7, 560.5, 158.2, 558.4, +158.5, 556.2, 157.8, 556.1, 157.5, 553.7, 156.4, 553.2, 158.4, 549.0, +159.2, 544.2, 160.5, 553.3, 159.4, 553.5, 158.8, 562.8, 418.2, 496.4, +418.2, 496.3, 418.2, 496.3, 418.3, 496.3, 418.3, 496.3, 418.3, 496.3, +418.3, 496.4, 418.3, 496.4, 418.2, 496.4, 418.2, 496.4, 379.0, 658.0, +380.1, 653.4, 380.1, 653.4, 381.3, 648.8, 391.3, 646.7, 392.2, 650.9, +403.1, 653.0, 407.3, 653.8, 411.0, 652.7, 411.6, 654.6, 410.7, 664.7, +410.7, 664.7, 409.9, 674.8, 395.5, 676.3, 391.6, 669.5, 379.0, 658.0, +409.9, 674.8, 408.8, 688.1, 411.8, 689.1, 407.6, 701.4, 407.5, 703.4, +407.5, 703.4, 407.3, 705.4, 406.9, 710.5, 406.9, 710.5, 406.5, 715.6, +406.4, 715.7, 406.4, 715.7, 406.4, 715.8, 406.3, 717.1, 406.0, 718.3, +406.2, 718.4, 395.6, 705.4, 385.7, 702.3, 369.0, 705.6, 368.3, 705.3, +367.7, 704.7, 367.8, 704.1, 372.0, 686.8, 377.1, 669.7, 376.3, 669.4, +378.0, 667.1, 378.7, 665.6, 377.7, 663.3, 376.7, 661.9, 378.4, 660.7, +379.0, 658.0, 391.6, 669.5, 395.5, 676.3, 409.9, 674.8, 442.5, 452.2, +443.4, 445.8, 444.3, 445.8, 444.3, 439.3, 445.1, 452.6, 444.2, 452.7, +445.8, 465.9, 448.0, 480.4, 446.7, 480.6, 447.6, 495.3, 448.0, 501.2, +447.9, 501.2, 448.3, 507.2, 450.3, 533.5, 449.9, 533.5, 451.5, 559.9, +451.9, 567.7, 451.9, 567.7, 452.4, 575.5, 452.6, 578.7, 452.6, 578.7, +452.8, 581.9, 452.2, 585.4, 451.5, 585.3, 450.2, 588.8, 447.3, 596.8, +443.2, 597.4, 444.3, 604.8, 439.9, 575.1, 444.0, 574.5, 443.6, 544.2, +443.0, 498.2, 442.2, 498.2, 442.5, 452.2, 363.4, 734.1, 364.4, 724.0, +361.6, 722.8, 365.4, 714.0, 365.5, 713.7, 365.5, 713.7, 365.5, 713.5, +366.7, 708.8, 366.7, 708.8, 367.8, 704.1, 367.7, 704.7, 368.3, 705.3, +369.0, 705.6, 374.3, 704.6, 376.1, 714.2, 383.3, 722.9, 381.6, 737.4, +393.1, 738.7, 403.0, 754.5, 402.3, 755.6, 388.1, 746.8, 373.2, 739.2, +368.3, 736.6, 364.5, 737.8, 363.4, 734.1, 382.3, 243.1, 380.0, 227.2, +380.0, 227.2, 377.8, 211.3, 383.6, 206.3, 383.0, 205.7, 388.3, 200.2, +392.4, 214.6, 386.1, 216.4, 383.8, 232.7, 383.0, 237.9, 381.0, 238.5, +382.3, 243.1, 262.2, 528.4, 258.2, 543.6, 259.6, 544.0, 257.0, 559.6, +255.0, 571.8, 255.0, 571.8, 252.9, 584.1, 247.6, 616.0, 247.6, 616.0, +242.3, 647.9, 241.0, 655.3, 243.6, 657.0, 239.8, 662.8, 239.7, 665.9, +234.0, 665.8, 228.3, 668.9, 240.2, 597.8, 243.9, 598.3, 262.2, 528.4, +228.3, 668.9, 225.1, 670.6, 221.9, 670.5, 221.9, 672.3, 221.3, 662.2, +223.9, 661.3, 220.8, 652.1, 226.3, 633.0, 226.4, 633.0, 231.9, 614.0, +250.7, 549.3, 247.1, 548.0, 269.5, 484.6, 262.2, 505.2, 267.1, 506.8, +262.2, 528.4, 243.9, 598.3, 240.2, 597.8, 228.3, 668.9, 212.2, 827.7, +217.9, 793.6, 217.9, 793.6, 223.6, 759.5, 229.3, 760.1, 229.9, 753.5, +236.2, 747.4, 233.8, 748.3, 235.0, 751.5, 233.8, 755.6, 232.7, 759.2, +232.7, 759.2, 231.7, 762.7, 221.9, 795.2, 209.5, 826.6, 212.2, 827.7, +252.9, 584.1, 255.0, 571.8, 255.0, 571.8, 257.0, 559.6, 255.6, 564.2, +257.2, 564.7, 257.4, 569.9, 257.5, 573.8, 257.5, 573.8, 257.6, 577.7, +258.6, 606.4, 272.9, 617.1, 259.5, 635.1, 270.6, 620.2, 253.8, 609.7, +252.9, 584.1, 354.7, 534.6, 362.3, 542.1, 362.3, 542.1, 370.0, 549.5, +371.9, 552.9, 369.4, 554.3, 368.8, 559.1, 364.9, 589.4, 368.6, 590.3, +361.0, 619.6, 363.8, 608.6, 360.1, 607.6, 359.2, 595.6, 358.0, 579.6, +358.0, 579.6, 356.8, 563.5, 356.1, 553.6, 356.1, 553.6, 355.4, 543.6, +355.0, 539.1, 356.5, 535.4, 354.7, 534.6, 368.8, 559.1, 369.4, 554.3, +371.9, 552.9, 370.0, 549.5, 373.2, 552.6, 376.3, 552.5, 376.5, 555.8, +376.5, 556.1, 376.7, 556.1, 377.0, 556.3, 373.0, 558.1, 370.2, 560.5, +368.8, 559.1, 386.0, 524.0, 348.2, 504.2, 343.2, 510.4, 310.5, 484.3, +301.3, 479.0, 302.0, 476.9, 292.1, 473.7, 287.7, 470.6, 288.2, 469.9, +284.3, 466.1, 282.0, 463.9, 282.5, 463.1, 279.8, 461.8, 294.6, 469.4, +294.1, 470.2, 308.5, 478.6, 314.9, 482.3, 314.9, 482.3, 321.3, 486.1, +353.7, 505.1, 351.5, 518.3, 386.0, 524.0, 355.0, 294.4, 350.3, 267.3, +353.6, 266.3, 345.7, 240.1, 349.9, 234.6, 355.0, 230.2, 354.1, 229.1, +354.5, 229.1, 354.5, 228.5, 355.0, 227.9, 367.7, 256.8, 363.9, 266.8, +387.9, 282.3, 389.9, 289.5, 392.0, 289.0, 396.0, 295.6, 396.2, 296.0, +396.1, 296.0, 396.1, 296.5, 375.5, 295.8, 364.6, 305.2, 355.0, 294.4, +396.1, 296.5, 398.5, 311.6, 393.5, 314.7, 400.9, 326.8, 392.4, 326.4, +390.1, 329.9, 384.0, 325.9, 377.6, 325.6, 375.1, 328.5, 371.2, 325.2, +363.8, 314.1, 363.8, 314.1, 356.4, 303.0, 353.9, 300.6, 355.7, 298.7, +355.0, 294.4, 364.6, 305.2, 375.5, 295.8, 396.1, 296.5, 437.6, 403.3, +437.5, 403.4, 432.1, 404.9, 429.5, 402.8, 423.1, 391.0, 420.4, 392.5, +411.3, 382.1, 410.7, 388.7, 420.7, 389.6, 430.0, 397.2, 433.8, 400.3, +437.8, 400.6, 437.6, 403.3, 325.6, 322.0, 326.6, 319.9, 326.6, 319.9, +327.5, 317.9, 341.1, 338.4, 353.4, 336.2, 381.6, 341.0, 386.2, 343.5, +389.5, 348.0, 388.2, 350.8, 383.4, 361.2, 378.8, 359.0, 369.4, 367.2, +365.1, 371.0, 364.9, 374.9, 360.7, 374.8, 357.9, 374.7, 358.1, 370.8, +355.4, 366.8, 346.5, 353.4, 346.5, 353.4, 337.7, 340.1, 331.6, 331.0, +330.1, 331.7, 325.6, 322.0, 420.5, 402.3, 415.5, 395.5, 407.1, 401.5, +393.7, 400.8, 370.0, 392.8, 367.3, 394.6, 342.0, 397.7, 340.5, 399.4, +338.5, 397.5, 334.9, 397.3, 334.6, 396.8, 337.2, 395.3, 339.5, 393.3, +341.5, 391.6, 341.5, 391.6, 343.5, 389.8, 352.1, 382.3, 352.1, 382.3, +360.7, 374.8, 364.9, 374.9, 365.1, 371.0, 369.4, 367.2, 397.1, 380.0, +403.3, 378.7, 420.5, 402.3, 369.4, 367.2, 378.8, 359.0, 383.4, 361.2, +388.2, 350.8, 388.6, 350.6, 390.1, 353.7, 392.0, 356.6, 396.6, 363.6, +396.6, 363.6, 401.3, 370.6, 410.4, 387.3, 409.9, 388.2, 422.4, 402.4, +422.1, 402.0, 421.2, 402.8, 420.5, 402.3, 403.3, 378.7, 397.1, 380.0, +369.4, 367.2, 381.9, 411.1, 387.8, 405.9, 390.0, 399.5, 393.7, 400.8, +407.1, 401.5, 415.5, 395.5, 420.5, 402.3, 421.2, 402.8, 422.1, 402.0, +422.4, 402.4, 424.0, 404.3, 428.6, 401.2, 429.5, 402.8, 432.1, 404.9, +437.5, 403.4, 437.6, 403.3, 439.2, 403.4, 440.7, 403.7, 440.8, 403.5, +436.2, 422.4, 436.2, 422.4, 431.6, 441.3, 431.6, 441.2, 431.5, 441.2, +431.3, 441.1, 421.1, 434.9, 421.1, 434.9, 410.9, 428.7, 396.4, 419.9, +389.8, 423.9, 381.9, 411.1, 226.5, 544.9, 227.1, 537.3, 227.1, 537.3, +227.6, 529.8, 242.2, 506.7, 239.7, 505.1, 251.8, 480.4, 251.0, 482.0, +251.2, 482.0, 250.5, 483.7, 242.6, 503.9, 242.6, 503.9, 234.6, 524.2, +230.6, 534.6, 234.1, 539.0, 226.5, 544.9, 68.6, 177.8, 85.9, 216.5, +115.4, 232.0, 103.2, 255.3, 104.5, 259.8, 104.5, 259.8, 105.7, 264.3, +105.7, 264.1, 105.7, 264.1, 105.6, 264.0, 103.7, 259.7, 103.7, 259.7, +101.9, 255.4, 85.3, 216.6, 82.1, 176.7, 68.6, 177.8, 685.5, 569.3, +683.3, 569.5, 683.3, 569.5, 681.0, 569.7, 673.6, 557.2, 671.3, 558.6, +661.6, 547.5, 672.6, 546.6, 674.9, 557.2, 685.5, 569.3, 702.7, 480.0, +702.5, 483.1, 702.5, 483.1, 702.3, 486.2, 700.5, 484.1, 694.7, 489.0, +687.0, 491.8, 687.5, 485.4, 693.9, 483.3, 702.7, 480.0, 857.0, 143.8, +836.9, 149.9, 832.1, 143.9, 816.9, 156.1, 811.6, 152.0, 811.6, 152.0, +806.2, 148.0, 830.0, 140.7, 841.8, 132.4, 857.0, 143.8, 792.8, 174.5, +792.8, 174.5, 795.0, 176.8, 797.2, 179.1, 799.7, 181.7, 799.7, 181.7, +802.1, 184.2, 802.4, 184.5, 802.4, 184.5, 802.7, 184.8, 809.4, 191.8, +809.4, 191.8, 816.1, 198.8, 816.8, 199.5, 816.8, 199.5, 817.5, 200.3, +850.9, 235.1, 853.6, 232.9, 884.2, 269.9, 875.7, 265.1, 875.7, 265.1, +867.2, 260.3, 832.9, 224.5, 835.0, 222.5, 802.7, 184.8, 802.4, 184.5, +802.4, 184.5, 802.1, 184.2, 799.7, 181.7, 799.7, 181.7, 797.2, 179.1, +795.0, 176.8, 792.8, 174.5, 792.8, 174.5, 867.2, 260.3, 842.6, 246.4, +842.6, 246.4, 817.9, 232.4, 799.6, 193.6, 800.5, 192.0, 774.9, 157.7, +773.6, 155.2, 773.5, 155.3, 772.0, 152.8, 783.0, 163.0, 782.9, 163.3, +792.8, 174.5, 830.4, 217.0, 845.6, 210.6, 867.2, 260.3, 797.2, 179.1, +795.0, 176.8, 792.8, 174.5, 792.8, 174.5, 782.9, 163.3, 783.0, 163.0, +772.0, 152.8, 768.7, 147.1, 766.1, 141.1, 765.4, 141.4, 766.5, 139.8, +764.2, 135.2, 761.4, 134.3, 760.9, 134.2, 761.0, 133.7, 760.7, 133.2, +767.4, 139.3, 771.4, 135.0, 782.2, 136.8, 798.9, 152.6, 801.2, 150.2, +820.2, 163.7, 821.3, 166.9, 809.8, 174.1, 797.2, 179.1, 701.9, 194.3, +712.7, 197.5, 715.9, 194.0, 723.5, 200.8, 762.4, 221.2, 762.4, 221.2, +801.3, 241.7, 802.0, 241.9, 799.9, 248.5, 798.5, 255.3, 795.0, 256.8, +792.7, 251.7, 787.0, 248.0, 786.8, 247.9, 786.8, 247.9, 786.5, 247.7, +784.3, 246.3, 784.3, 246.3, 782.1, 244.9, 769.7, 237.1, 769.7, 237.1, +757.4, 229.3, 757.4, 229.3, 757.4, 229.3, 757.4, 229.3, 729.6, 211.8, +726.8, 215.2, 701.9, 194.3, 626.8, 212.0, 636.0, 225.9, 636.5, 225.5, +645.8, 239.4, 667.0, 268.4, 665.7, 269.4, 685.6, 299.3, 655.5, 256.1, +655.9, 255.9, 626.8, 212.0, 635.9, 116.5, 646.2, 125.1, 646.2, 125.1, +656.5, 133.7, 657.2, 142.1, 662.6, 141.6, 668.8, 149.5, 643.8, 135.2, +622.3, 122.5, 612.2, 132.4, 593.2, 121.1, 593.2, 121.1, 574.2, 109.7, +572.8, 107.4, 572.2, 107.5, 569.8, 106.0, 580.0, 103.8, 580.0, 103.8, +590.2, 101.6, 613.7, 105.4, 614.5, 106.1, 635.9, 116.5, 590.2, 101.6, +600.3, 99.5, 600.3, 99.5, 610.4, 97.3, 613.6, 104.6, 618.0, 102.6, +625.6, 107.8, 631.3, 111.2, 630.8, 112.2, 635.9, 116.5, 614.5, 106.1, +613.7, 105.4, 590.2, 101.6, 499.3, 193.9, 476.5, 183.3, 477.3, 175.2, +453.6, 172.7, 441.0, 164.6, 441.0, 164.6, 428.4, 156.5, 457.3, 169.0, +456.3, 171.2, 484.2, 186.0, 491.8, 189.9, 491.5, 190.5, 499.3, 193.9, +601.4, 22.8, 597.4, 24.3, 593.3, 25.3, 593.4, 25.8, 591.9, 23.2, +590.0, 21.0, 590.4, 20.7, 590.7, 20.3, 589.6, 19.4, 588.8, 18.1, +595.3, 19.3, 598.7, 18.3, 601.4, 22.8, 276.3, 70.7, 278.0, 72.0, +278.0, 72.0, 279.7, 73.4, 271.5, 101.4, 273.7, 102.0, 267.7, 130.7, +255.6, 120.9, 270.1, 100.3, 276.3, 70.7, 349.7, 186.4, 349.6, 188.2, +349.1, 188.4, 349.5, 190.1, 343.1, 173.1, 346.6, 170.8, 336.8, 156.0, +330.5, 139.2, 331.3, 138.9, 324.3, 122.5, 337.7, 154.1, 337.7, 154.2, +349.7, 186.4, 335.3, 168.8, 332.6, 191.9, 330.5, 191.8, 329.9, 214.9, +320.4, 186.5, 320.4, 186.5, 310.9, 158.1, 305.7, 151.6, 309.6, 148.5, +308.3, 138.9, 325.1, 146.3, 330.3, 151.4, 335.3, 168.8, 308.3, 138.9, +306.7, 127.1, 310.9, 124.6, 305.2, 115.3, 310.1, 106.4, 310.1, 106.4, +315.0, 97.6, 323.2, 100.7, 319.7, 110.0, 324.3, 122.5, 331.3, 138.9, +330.5, 139.2, 336.8, 156.0, 339.5, 160.1, 336.0, 162.4, 335.3, 168.8, +330.3, 151.4, 325.1, 146.3, 308.3, 138.9, 263.7, 336.2, 263.7, 337.9, +263.6, 339.6, 263.7, 339.6, 230.6, 368.8, 230.6, 368.8, 197.4, 398.0, +195.3, 395.7, 191.7, 394.9, 190.1, 396.4, 202.0, 375.3, 211.2, 376.4, +213.9, 354.1, 213.9, 354.1, 214.0, 354.0, 214.0, 353.9, 238.8, 344.9, +238.4, 343.4, 263.7, 336.2, 214.0, 353.9, 226.4, 331.9, 237.8, 332.4, +238.9, 309.9, 240.5, 309.0, 240.7, 308.1, 241.0, 306.0, 252.2, 300.0, +252.2, 300.0, 263.4, 293.9, 259.6, 314.3, 263.6, 315.1, 263.7, 336.2, +238.4, 343.4, 238.8, 344.9, 214.0, 353.9, 150.0, 380.7, 152.0, 345.3, +158.2, 344.5, 154.0, 309.9, 154.8, 305.8, 154.8, 305.8, 155.7, 301.6, +155.8, 301.9, 157.5, 301.0, 159.2, 300.4, 157.2, 333.4, 155.5, 333.2, +151.7, 366.1, 150.8, 373.4, 150.3, 373.4, 150.0, 380.7, 591.4, 653.9, +591.6, 653.5, 589.9, 652.7, 590.1, 652.2, 603.5, 638.6, 598.3, 633.5, +606.6, 614.7, 616.8, 600.2, 615.0, 598.9, 623.3, 583.1, 612.9, 586.0, +616.4, 598.5, 609.4, 614.0, 600.4, 633.9, 601.3, 634.3, 591.4, 653.9, +607.0, 580.0, 599.4, 593.4, 587.9, 600.6, 591.8, 606.9, 583.9, 614.2, +586.2, 616.8, 580.6, 626.7, 575.6, 621.5, 580.0, 612.0, 586.2, 601.1, +593.2, 588.6, 607.2, 580.2, 607.0, 580.0, 586.2, 601.1, 582.8, 599.4, +589.3, 586.8, 592.4, 572.5, 593.4, 567.5, 593.4, 567.5, 594.5, 562.6, +599.8, 538.4, 599.8, 538.4, 605.0, 514.1, 605.3, 512.9, 605.8, 511.8, +605.6, 511.6, 620.6, 520.5, 620.6, 520.5, 635.6, 529.4, 618.1, 552.2, +621.3, 554.7, 607.0, 580.0, 607.2, 580.2, 593.2, 588.6, 586.2, 601.1, +523.8, 737.3, 526.4, 716.5, 526.4, 716.5, 529.0, 695.8, 528.6, 697.6, +530.3, 697.9, 531.6, 700.1, 538.0, 710.4, 538.1, 710.3, 544.4, 720.7, +544.4, 720.7, 544.4, 720.7, 544.4, 720.7, 534.1, 729.0, 523.0, 735.9, +523.8, 737.3, 573.1, 676.7, 567.3, 670.3, 574.9, 663.4, 576.6, 650.0, +576.6, 649.8, 576.6, 649.8, 576.7, 649.6, 577.5, 643.4, 575.7, 642.6, +578.3, 637.3, 579.6, 639.0, 579.6, 639.0, 580.9, 640.6, 581.0, 646.3, +579.7, 646.3, 578.4, 652.1, 575.8, 664.4, 568.2, 671.3, 573.1, 676.7, +536.3, 636.7, 537.3, 627.8, 537.3, 627.8, 538.4, 619.0, 537.6, 618.0, +551.4, 612.5, 552.4, 604.6, 552.6, 604.5, 553.8, 606.4, 555.2, 608.1, +563.2, 618.2, 573.3, 624.9, 571.1, 628.3, 563.9, 639.2, 551.3, 641.0, +536.3, 636.7, 549.3, 443.5, 552.8, 465.2, 544.2, 472.5, 556.3, 486.9, +555.7, 487.9, 555.3, 487.8, 555.0, 488.9, 553.7, 495.1, 551.2, 494.6, +547.5, 500.3, 547.7, 500.0, 547.5, 499.8, 547.5, 499.4, 547.6, 497.4, +547.6, 497.4, 547.6, 495.4, 547.8, 490.8, 547.8, 490.8, 547.9, 486.2, +548.0, 483.4, 548.0, 483.4, 548.1, 480.6, 548.7, 462.0, 557.9, 450.1, +549.3, 443.5, 517.0, 564.6, 517.0, 565.3, 516.8, 566.1, 517.0, 566.1, +516.1, 568.5, 516.1, 568.5, 515.2, 571.0, 514.3, 573.5, 514.3, 573.4, +513.3, 575.9, 502.9, 609.6, 499.8, 608.6, 486.2, 641.2, 493.4, 624.6, +492.9, 624.4, 499.7, 607.6, 508.3, 586.1, 508.0, 586.0, 517.0, 564.6, +469.6, 385.7, 466.8, 389.5, 464.2, 393.4, 463.9, 393.2, 459.0, 391.3, +455.0, 392.5, 454.1, 389.4, 452.7, 386.4, 452.7, 386.4, 451.3, 383.3, +452.5, 381.9, 454.8, 383.8, 458.3, 384.2, 463.9, 385.0, 467.7, 382.6, +469.6, 385.7, 396.3, 586.8, 397.2, 582.8, 397.3, 582.8, 398.2, 578.9, +398.4, 578.1, 398.4, 578.1, 398.6, 577.3, 409.8, 571.4, 405.2, 559.0, +407.6, 540.2, 413.0, 527.4, 419.1, 522.3, 414.3, 512.8, 411.6, 510.8, +416.2, 504.6, 418.2, 496.4, 418.2, 496.4, 418.3, 496.4, 418.3, 496.4, +419.0, 502.7, 419.0, 502.7, 419.7, 509.1, 410.4, 547.4, 408.3, 546.9, +396.9, 584.7, 396.6, 585.7, 396.5, 585.7, 396.3, 586.8, 406.5, 715.6, +406.9, 710.5, 406.9, 710.5, 407.3, 705.4, 414.6, 682.2, 422.2, 683.1, +424.1, 659.7, 421.7, 688.2, 416.6, 688.1, 406.5, 715.6, 425.5, 707.4, +429.7, 691.9, 428.8, 691.6, 432.1, 675.9, 441.2, 632.3, 440.7, 632.2, +450.2, 588.8, 451.5, 585.3, 452.2, 585.4, 452.8, 581.9, 453.1, 588.3, +453.1, 588.3, 453.5, 594.6, 451.7, 607.4, 450.4, 607.2, 447.3, 619.8, +436.4, 663.6, 437.3, 663.9, 425.5, 707.4, 421.8, 600.0, 432.1, 526.1, +432.1, 526.1, 442.5, 452.2, 442.2, 498.2, 443.0, 498.2, 443.6, 544.2, +443.5, 549.1, 441.7, 549.1, 439.7, 554.0, 430.8, 577.0, 422.4, 576.8, +421.8, 600.0, 450.1, 848.6, 452.0, 854.6, 455.4, 855.6, 453.9, 860.5, +453.3, 865.0, 453.3, 865.0, 452.6, 869.4, 442.1, 862.3, 444.4, 858.9, +436.1, 848.5, 428.4, 838.7, 428.5, 829.0, 420.7, 828.9, 435.5, 829.1, +437.5, 836.6, 450.1, 848.6, 365.7, 852.2, 362.7, 811.2, 363.7, 811.1, +359.7, 770.2, 360.0, 767.1, 360.0, 767.1, 360.3, 764.1, 361.6, 774.6, +361.0, 774.7, 361.6, 785.4, 363.7, 818.8, 361.5, 819.0, 365.7, 852.2, +444.9, 882.7, 427.4, 888.3, 425.7, 884.8, 406.6, 883.8, 405.1, 880.8, +402.4, 882.1, 398.3, 880.4, 394.0, 872.0, 396.6, 870.7, 395.0, 861.0, +392.2, 844.6, 396.7, 830.6, 389.3, 828.2, 417.3, 837.2, 412.8, 851.2, +436.3, 874.3, 440.6, 878.5, 442.2, 883.6, 444.9, 882.7, 416.0, 171.3, +416.1, 171.1, 416.3, 171.1, 416.3, 171.0, 417.8, 183.6, 417.8, 183.6, +419.4, 196.3, 421.3, 210.6, 421.0, 210.6, 422.5, 225.0, 417.7, 260.8, +417.2, 261.1, 417.5, 297.2, 417.2, 296.7, 417.2, 296.7, 416.8, 296.1, +416.0, 242.1, 416.4, 242.1, 416.1, 188.1, 416.0, 179.7, 415.9, 179.7, +416.0, 171.3, 346.4, 641.2, 353.1, 634.7, 353.5, 635.0, 359.8, 628.3, +359.0, 628.9, 359.6, 629.7, 359.5, 631.2, 359.1, 633.6, 359.1, 633.6, +358.8, 636.1, 358.4, 641.9, 355.7, 641.6, 355.0, 647.4, 355.3, 654.7, +350.7, 654.7, 349.9, 662.3, 349.7, 664.6, 349.1, 664.5, 348.4, 666.8, +346.5, 658.6, 347.7, 658.4, 347.1, 650.0, 346.8, 645.6, 344.6, 644.3, +346.4, 641.2, 261.3, 688.3, 264.5, 698.4, 267.0, 702.9, 262.0, 710.4, +244.4, 725.4, 243.2, 724.1, 226.8, 740.4, 233.3, 701.6, 239.0, 701.7, +239.8, 662.8, 243.6, 657.0, 241.0, 655.3, 242.3, 647.9, 256.2, 664.4, +254.6, 667.2, 261.3, 688.3, 242.3, 647.9, 247.6, 616.0, 247.6, 616.0, +252.9, 584.1, 253.8, 609.7, 270.6, 620.2, 259.5, 635.1, 259.7, 636.7, +259.6, 636.7, 259.6, 638.3, 260.0, 649.2, 260.0, 649.2, 260.4, 660.1, +260.4, 662.7, 260.4, 662.7, 260.5, 665.3, 260.8, 672.8, 260.8, 672.8, +261.0, 680.4, 261.2, 684.4, 259.5, 685.3, 261.3, 688.3, 254.6, 667.2, +256.2, 664.4, 242.3, 647.9, 306.5, 803.3, 314.5, 784.8, 318.0, 785.6, +322.6, 766.3, 330.7, 778.5, 327.5, 784.7, 338.9, 790.7, 338.4, 794.6, +338.4, 794.6, 337.9, 798.5, 323.4, 804.1, 308.4, 807.4, 306.5, 803.3, +337.9, 798.5, 337.2, 803.9, 337.2, 803.9, 336.5, 809.4, 321.1, 829.8, +319.0, 828.2, 301.5, 847.1, 290.0, 859.4, 292.5, 867.4, 278.5, 871.8, +284.4, 870.0, 281.3, 861.8, 285.2, 852.2, 291.3, 826.7, 295.8, 827.8, +306.5, 803.3, 308.4, 807.4, 323.4, 804.1, 337.9, 798.5, 301.5, 847.1, +319.0, 828.2, 321.1, 829.8, 336.5, 809.4, 333.6, 832.1, 337.9, 833.6, +330.6, 854.9, 330.0, 857.6, 330.6, 857.7, 329.9, 860.4, 329.5, 862.2, +329.5, 862.2, 329.0, 864.1, 314.4, 857.3, 300.6, 853.6, 301.5, 847.1, +329.0, 864.1, 326.7, 873.5, 320.9, 879.5, 324.4, 882.9, 302.3, 890.3, +299.7, 883.1, 275.0, 882.2, 275.2, 882.2, 275.2, 881.7, 275.3, 881.2, +276.9, 876.5, 275.7, 875.5, 278.5, 871.8, 292.5, 867.4, 290.0, 859.4, +301.5, 847.1, 300.6, 853.6, 314.4, 857.3, 329.0, 864.1, 398.2, 578.9, +397.3, 582.8, 397.2, 582.8, 396.3, 586.8, 394.8, 593.0, 394.8, 593.0, +393.3, 599.3, 389.1, 616.4, 395.5, 622.4, 385.0, 633.5, 378.5, 627.5, +373.8, 632.5, 362.7, 631.5, 369.7, 602.6, 379.2, 604.2, 398.2, 578.9, +362.7, 631.5, 361.1, 631.4, 359.8, 632.0, 359.5, 631.2, 359.5, 631.2, +359.5, 631.2, 359.5, 631.2, 359.6, 629.7, 359.0, 628.9, 359.8, 628.3, +360.2, 627.9, 359.6, 627.2, 360.0, 626.8, 360.5, 623.2, 360.5, 623.2, +361.0, 619.6, 368.6, 590.3, 364.9, 589.4, 368.8, 559.1, 370.2, 560.5, +373.0, 558.1, 377.0, 556.3, 387.8, 566.8, 394.5, 579.5, 398.6, 577.3, +398.4, 578.1, 398.4, 578.1, 398.2, 578.9, 379.2, 604.2, 369.7, 602.6, +362.7, 631.5, 374.9, 477.0, 387.8, 504.4, 387.8, 504.4, 400.7, 531.7, +394.3, 526.7, 393.3, 527.9, 386.0, 524.0, 351.5, 518.3, 353.7, 505.1, +321.3, 486.1, 322.1, 486.6, 322.6, 485.9, 323.8, 485.7, 332.3, 484.2, +332.3, 484.2, 340.7, 482.8, 347.2, 481.7, 347.2, 481.7, 353.6, 480.6, +364.3, 478.8, 371.0, 472.7, 374.9, 477.0, 430.0, 397.2, 420.7, 389.6, +410.7, 388.7, 411.3, 382.1, 406.3, 376.3, 404.8, 377.1, 401.3, 370.6, +396.6, 363.6, 396.6, 363.6, 392.0, 356.6, 406.4, 368.4, 404.9, 370.3, +417.7, 384.1, 423.9, 390.6, 422.5, 394.9, 430.0, 397.2, 312.7, 349.7, +319.1, 335.8, 319.1, 335.8, 325.6, 322.0, 330.1, 331.7, 331.6, 331.0, +337.7, 340.1, 333.6, 348.9, 314.3, 352.2, 312.7, 349.7, 426.6, 461.9, +423.9, 473.2, 422.3, 473.1, 421.1, 484.6, 421.1, 486.1, 420.7, 486.1, +420.4, 487.6, 419.3, 484.4, 417.0, 485.2, 413.7, 482.7, 388.8, 467.8, +390.8, 464.5, 367.9, 446.3, 367.7, 447.2, 393.4, 453.0, 418.9, 459.8, +422.7, 460.9, 426.5, 460.5, 426.6, 461.9, 236.0, 594.4, 228.0, 614.6, +225.6, 614.0, 220.0, 634.9, 220.3, 631.4, 219.5, 628.1, 220.5, 627.8, +225.4, 586.6, 223.5, 586.4, 226.5, 544.9, 234.1, 539.0, 230.6, 534.6, +234.6, 524.2, 241.1, 558.2, 240.5, 560.0, 236.0, 594.4, 77.2, 274.3, +70.8, 259.9, 70.8, 259.9, 64.3, 245.5, 66.4, 226.4, 65.1, 226.2, +65.9, 206.9, 64.9, 213.5, 67.1, 213.8, 68.2, 220.7, 71.9, 242.5, +71.9, 242.5, 75.5, 264.2, 76.4, 269.2, 74.8, 270.2, 77.2, 274.3, +689.5, 513.1, 695.2, 510.7, 698.8, 512.4, 700.8, 508.2, 700.3, 515.6, +700.3, 515.6, 699.8, 523.1, 697.3, 524.2, 689.2, 517.7, 689.5, 513.1, +699.8, 523.1, 698.6, 542.0, 694.3, 542.7, 697.3, 560.8, 695.3, 564.7, +692.5, 565.5, 693.3, 568.6, 689.4, 569.0, 689.4, 569.0, 685.5, 569.3, +674.9, 557.2, 672.6, 546.6, 661.6, 547.5, 659.2, 544.7, 658.6, 545.0, +656.7, 541.9, 653.1, 536.2, 653.0, 536.3, 649.4, 530.7, 670.2, 528.0, +669.4, 521.9, 689.5, 513.1, 689.2, 517.7, 697.3, 524.2, 699.8, 523.1, +640.6, 486.8, 641.1, 482.9, 641.1, 482.9, 641.5, 479.0, 665.1, 466.5, +665.8, 463.1, 691.8, 459.8, 696.3, 465.5, 696.3, 465.5, 700.8, 471.3, +700.6, 474.2, 701.0, 474.9, 702.9, 477.3, 702.8, 478.7, 702.8, 478.7, +702.7, 480.0, 693.9, 483.3, 687.5, 485.4, 687.0, 491.8, 677.4, 495.4, +677.4, 495.4, 667.8, 498.9, 653.7, 497.4, 652.1, 495.6, 640.6, 486.8, +667.8, 498.9, 652.8, 504.4, 652.4, 503.5, 637.8, 510.0, 638.1, 507.7, +638.4, 507.7, 638.3, 505.4, 635.1, 498.0, 639.5, 496.1, 640.6, 486.8, +652.1, 495.6, 653.7, 497.4, 667.8, 498.9, 784.9, 126.3, 772.6, 107.4, +777.7, 99.6, 760.4, 88.4, 767.7, 87.7, 771.2, 83.6, 775.0, 86.9, +813.2, 104.8, 813.2, 104.8, 851.4, 122.6, 849.9, 116.6, 813.4, 137.1, +784.9, 126.3, 851.4, 122.6, 854.5, 124.1, 854.9, 123.5, 857.5, 125.5, +863.1, 129.5, 863.2, 129.3, 868.7, 133.4, 872.0, 135.8, 872.0, 135.8, +875.3, 138.2, 868.0, 135.7, 866.1, 141.0, 857.0, 143.8, 841.8, 132.4, +830.0, 140.7, 806.2, 148.0, 800.0, 143.3, 800.7, 141.9, 793.9, 138.7, +792.8, 138.7, 792.9, 137.9, 791.8, 137.2, 786.9, 134.1, 788.4, 131.7, +784.9, 126.3, 813.4, 137.1, 849.9, 116.6, 851.4, 122.6, 921.4, 271.7, +918.0, 273.4, 914.5, 273.9, 914.7, 275.0, 914.9, 275.8, 907.1, 277.0, +907.2, 278.6, 907.3, 278.8, 905.1, 279.6, 903.1, 280.6, 902.5, 281.0, +901.6, 279.7, 900.1, 278.9, 910.2, 274.1, 910.6, 274.7, 921.4, 271.7, +773.0, 328.8, 748.5, 323.3, 748.1, 316.3, 724.0, 317.9, 720.6, 314.2, +720.6, 314.2, 717.1, 310.4, 741.1, 315.2, 740.5, 318.1, 763.9, 325.8, +768.5, 327.3, 768.4, 327.9, 773.0, 328.8, 787.0, 248.0, 792.7, 251.7, +795.0, 256.8, 798.5, 255.3, 796.8, 263.4, 794.1, 271.2, 795.1, 271.6, +793.4, 271.7, 791.4, 277.9, 792.6, 283.1, 788.8, 283.1, 789.0, 300.4, +785.4, 317.7, 785.5, 317.1, 784.0, 316.8, 784.0, 315.9, 783.8, 302.9, +784.5, 302.9, 785.1, 289.9, 786.1, 269.0, 779.8, 266.6, 787.0, 248.0, +673.5, 315.8, 659.5, 298.6, 659.5, 298.6, 645.4, 281.4, 632.5, 255.7, +631.1, 256.4, 615.8, 231.9, 605.0, 210.3, 611.0, 203.2, 594.1, 188.7, +592.9, 180.0, 592.1, 178.0, 585.7, 172.0, 581.2, 168.9, 582.9, 166.5, +580.1, 161.0, 591.5, 174.3, 591.9, 173.9, 603.8, 186.8, 616.0, 204.4, +614.0, 205.7, 624.2, 224.7, 638.5, 251.0, 638.5, 251.0, 652.8, 277.4, +663.2, 296.6, 673.6, 315.7, 673.5, 315.8, 478.7, 141.4, 501.3, 162.4, +497.6, 169.5, 523.9, 183.4, 524.4, 183.1, 525.3, 184.7, 526.7, 186.0, +533.2, 191.2, 531.9, 192.8, 537.0, 199.6, 526.3, 193.5, 528.0, 190.6, +519.0, 181.6, 498.8, 161.5, 503.0, 150.3, 478.7, 141.4, 620.1, -35.4, +624.7, -11.6, 619.7, -9.4, 629.3, 12.3, 624.8, 14.0, 624.8, 14.0, +620.2, 15.7, 617.8, 13.9, 620.2, 10.6, 620.2, 5.5, 620.1, -14.9, +629.9, -28.1, 620.1, -35.4, 250.6, 110.4, 253.5, 96.5, 253.0, 96.4, +256.4, 82.5, 257.2, 79.3, 257.0, 79.3, 257.9, 76.1, 260.2, 67.8, +260.2, 67.8, 262.6, 59.6, 263.8, 66.2, 269.4, 65.1, 276.3, 70.7, +270.1, 100.3, 255.6, 120.9, 267.7, 130.7, 265.7, 140.4, 265.7, 140.4, +263.7, 150.1, 251.1, 135.4, 252.7, 130.8, 250.6, 110.4, 263.7, 150.1, +261.1, 162.6, 257.9, 162.7, 258.5, 175.0, 249.7, 165.6, 249.7, 165.6, +240.9, 156.3, 246.6, 133.6, 245.7, 133.4, 250.6, 110.4, 252.7, 130.8, +251.1, 135.4, 263.7, 150.1, 326.0, 83.2, 339.5, 82.3, 343.1, 87.8, +353.0, 81.4, 353.5, 89.0, 353.5, 89.0, 353.9, 96.6, 351.1, 135.1, +352.1, 135.2, 350.3, 173.8, 322.8, 160.6, 324.7, 128.1, 326.0, 83.2, +350.3, 173.8, 350.0, 180.1, 350.0, 180.1, 349.7, 186.4, 337.7, 154.2, +337.7, 154.1, 324.3, 122.5, 319.7, 110.0, 323.2, 100.7, 315.0, 97.6, +319.0, 90.5, 325.0, 87.7, 323.0, 83.4, 324.5, 83.3, 324.5, 83.3, +326.0, 83.2, 324.7, 128.1, 322.8, 160.6, 350.3, 173.8, 172.0, 295.9, +179.3, 293.3, 179.3, 293.3, 186.7, 290.7, 183.3, 295.7, 186.1, 297.6, +185.4, 304.5, 180.8, 306.1, 171.6, 299.5, 172.0, 295.9, 602.3, 667.7, +604.0, 664.1, 590.6, 659.9, 591.4, 653.9, 601.3, 634.3, 600.4, 633.9, +609.4, 614.0, 609.2, 614.5, 609.3, 614.5, 609.3, 615.1, 609.3, 615.2, +609.3, 615.2, 609.2, 615.2, 605.8, 641.4, 612.9, 644.7, 602.3, 667.7, +662.7, 698.1, 662.6, 699.1, 661.9, 699.0, 661.0, 700.0, 658.8, 702.5, +658.8, 702.5, 656.6, 705.1, 654.4, 707.5, 654.4, 707.5, 652.3, 710.0, +647.9, 714.9, 648.2, 719.6, 643.6, 719.9, 640.3, 720.1, 637.3, 715.8, +636.4, 710.8, 632.1, 687.1, 631.2, 686.3, 633.1, 662.4, 632.8, 666.0, +636.4, 666.3, 639.6, 670.2, 647.5, 679.7, 647.5, 679.7, 655.4, 689.2, +658.3, 692.8, 658.3, 692.8, 661.2, 696.3, 661.9, 697.2, 662.7, 697.2, +662.7, 698.1, 555.2, 608.1, 553.8, 606.4, 552.6, 604.5, 552.4, 604.6, +553.2, 598.7, 541.1, 592.1, 541.9, 591.3, 542.6, 585.6, 542.6, 585.6, +543.2, 580.0, 552.4, 591.6, 549.9, 593.8, 555.2, 608.1, 561.8, 494.2, +562.8, 490.6, 562.8, 490.6, 563.8, 487.0, 564.1, 489.9, 568.0, 489.5, +572.1, 491.9, 572.1, 492.7, 568.0, 492.8, 564.0, 493.7, 562.9, 493.9, +561.8, 493.9, 561.8, 494.2, 544.4, 720.7, 544.4, 720.7, 544.4, 720.7, +544.4, 720.7, 549.1, 728.1, 549.1, 728.1, 553.7, 735.5, 558.5, 743.3, +558.5, 743.3, 563.4, 751.1, 568.5, 759.4, 574.8, 760.3, 573.7, 767.7, +565.6, 772.1, 566.5, 773.6, 559.2, 779.4, 548.5, 769.2, 554.9, 762.5, +550.7, 745.6, 547.5, 733.2, 547.5, 733.2, 544.4, 720.7, 589.1, 754.2, +588.6, 757.8, 586.3, 757.5, 583.5, 760.9, 579.5, 765.7, 580.5, 767.1, +575.5, 770.6, 575.8, 769.6, 573.8, 767.6, 573.7, 767.7, 574.8, 760.3, +568.5, 759.4, 563.4, 751.1, 563.1, 714.0, 567.5, 713.8, 573.1, 676.7, +568.2, 671.3, 575.8, 664.4, 578.4, 652.1, 575.3, 653.6, 579.5, 662.6, +580.6, 673.2, 583.7, 702.7, 583.7, 702.7, 586.8, 732.3, 587.9, 743.2, +590.3, 743.5, 589.1, 754.2, 531.4, 675.9, 533.8, 656.3, 533.8, 656.3, +536.3, 636.7, 551.3, 641.0, 563.9, 639.2, 571.1, 628.3, 572.8, 628.1, +573.1, 630.7, 575.0, 633.2, 575.6, 633.9, 575.6, 633.9, 576.1, 634.6, +576.0, 635.8, 577.2, 636.0, 578.3, 637.3, 575.7, 642.6, 577.5, 643.4, +576.7, 649.6, 571.0, 656.4, 568.5, 654.3, 560.3, 659.1, 545.9, 667.5, +535.0, 679.2, 531.4, 675.9, 630.3, 847.0, 629.2, 849.3, 629.8, 849.8, +628.1, 851.5, 623.9, 855.9, 624.5, 856.6, 619.8, 860.2, 609.4, 869.5, +610.7, 874.4, 598.4, 878.2, 579.8, 884.0, 578.1, 879.9, 557.9, 879.4, +557.7, 879.4, 557.6, 878.3, 557.4, 877.2, 591.6, 861.8, 592.0, 862.9, +626.7, 848.5, 628.5, 847.7, 630.3, 846.9, 630.3, 847.0, 538.1, 445.8, +538.5, 445.4, 538.5, 445.1, 539.0, 445.1, 540.4, 444.8, 541.1, 445.4, +541.9, 444.6, 543.5, 442.4, 545.6, 443.9, 549.3, 443.3, 549.3, 443.3, +549.3, 443.4, 549.3, 443.5, 557.9, 450.1, 548.7, 462.0, 548.1, 480.6, +548.3, 478.7, 547.6, 478.7, 547.0, 476.8, 544.5, 467.9, 544.5, 467.9, +541.9, 459.0, 540.7, 454.7, 540.7, 454.7, 539.5, 450.4, 538.8, 448.1, +538.4, 448.1, 538.1, 445.8, 499.7, 607.6, 492.9, 624.4, 493.4, 624.6, +486.2, 641.2, 479.6, 657.2, 478.0, 656.7, 472.9, 673.2, 459.6, 660.6, +460.3, 644.6, 468.4, 624.5, 473.6, 611.8, 495.6, 603.8, 499.7, 607.6, +468.4, 624.5, 468.3, 623.1, 468.3, 623.1, 468.2, 621.6, 468.1, 621.0, +468.2, 621.0, 468.3, 620.3, 466.7, 616.9, 475.7, 614.6, 476.1, 608.4, +497.1, 588.7, 503.3, 585.9, 508.7, 559.0, 509.0, 559.2, 512.5, 553.3, +516.3, 547.5, 515.7, 548.6, 516.4, 549.0, 516.5, 550.4, 518.6, 551.0, +516.7, 557.5, 517.0, 564.6, 508.0, 586.0, 508.3, 586.1, 499.7, 607.6, +495.6, 603.8, 473.6, 611.8, 468.4, 624.5, 446.4, 372.4, 445.7, 370.9, +445.1, 370.9, 445.0, 369.4, 444.8, 366.7, 444.8, 366.7, 444.5, 364.1, +444.1, 362.0, 444.8, 361.9, 445.1, 359.6, 444.3, 355.2, 446.4, 354.8, +447.8, 349.9, 448.9, 361.0, 448.0, 361.3, 446.4, 372.4, 191.5, 616.5, +188.4, 624.7, 188.4, 624.7, 185.3, 632.9, 179.2, 628.3, 179.6, 619.8, +183.2, 610.3, 182.7, 611.6, 191.2, 613.0, 191.5, 616.5, 183.2, 610.3, +174.4, 552.3, 178.0, 551.8, 172.8, 493.4, 172.9, 493.2, 172.9, 493.2, +172.9, 493.1, 178.5, 505.2, 179.3, 504.9, 185.8, 516.6, 190.9, 543.6, +189.3, 545.5, 202.3, 569.3, 197.7, 591.0, 197.7, 591.0, 193.0, 612.6, +192.7, 614.6, 192.3, 614.5, 191.5, 616.5, 191.2, 613.0, 182.7, 611.6, +183.2, 610.3, 168.3, 506.7, 170.6, 500.0, 170.6, 500.0, 172.8, 493.4, +178.0, 551.8, 174.4, 552.3, 183.2, 610.3, 179.6, 619.8, 179.2, 628.3, +185.3, 632.9, 183.7, 636.8, 182.7, 636.7, 182.2, 640.8, 174.0, 627.6, +163.2, 624.8, 165.9, 614.5, 165.1, 609.2, 165.1, 609.2, 164.4, 603.8, +165.5, 555.2, 164.6, 555.1, 168.3, 506.7, 164.4, 603.8, 161.6, 583.3, +161.6, 583.3, 158.8, 562.8, 159.4, 553.5, 160.5, 553.3, 159.2, 544.2, +161.2, 532.8, 165.9, 522.6, 163.3, 521.4, 165.8, 514.0, 165.8, 514.0, +168.3, 506.7, 164.6, 555.1, 165.5, 555.2, 164.4, 603.8, 403.1, 653.0, +392.2, 650.9, 391.3, 646.7, 381.3, 648.8, 383.1, 641.1, 387.8, 636.1, +385.0, 633.5, 395.5, 622.4, 389.1, 616.4, 393.3, 599.3, 408.9, 616.2, +408.9, 628.7, 403.1, 653.0, 406.4, 715.8, 406.4, 715.7, 406.4, 715.7, +406.5, 715.6, 416.6, 688.1, 421.7, 688.2, 424.1, 659.7, 430.8, 639.9, +431.3, 640.1, 438.6, 620.5, 441.4, 612.6, 441.4, 612.6, 444.3, 604.8, +443.2, 597.4, 447.3, 596.8, 450.2, 588.8, 440.7, 632.2, 441.2, 632.3, +432.1, 675.9, 424.6, 697.5, 419.2, 695.7, 406.5, 715.6, 406.4, 715.7, +406.4, 715.7, 406.4, 715.8, 432.1, 675.9, 428.8, 691.6, 429.7, 691.9, +425.5, 707.4, 421.8, 725.3, 421.8, 725.3, 418.1, 743.1, 416.7, 749.7, +416.7, 749.7, 415.4, 756.3, 414.9, 758.5, 413.6, 760.2, 414.4, 760.8, +409.1, 754.3, 409.1, 754.3, 403.8, 747.8, 407.7, 747.1, 412.9, 726.6, +406.2, 718.4, 406.0, 718.3, 406.3, 717.1, 406.4, 715.8, 418.8, 695.5, +414.0, 683.8, 432.1, 675.9, 458.7, 682.6, 460.2, 708.3, 460.1, 708.3, +461.7, 734.0, 463.1, 739.0, 458.0, 740.4, 454.2, 746.8, 450.4, 731.2, +455.4, 730.0, 456.6, 713.1, 457.6, 697.9, 462.2, 696.8, 458.7, 682.6, +439.7, 554.0, 441.7, 549.1, 443.5, 549.1, 443.6, 544.2, 444.0, 574.5, +439.9, 575.1, 444.3, 604.8, 441.4, 612.6, 441.4, 612.6, 438.6, 620.5, +435.6, 587.6, 437.6, 587.1, 439.7, 554.0, 438.6, 620.5, 431.3, 640.1, +430.8, 639.9, 424.1, 659.7, 422.2, 683.1, 414.6, 682.2, 407.3, 705.4, +407.5, 703.4, 407.5, 703.4, 407.6, 701.4, 413.1, 685.3, 410.4, 684.4, +412.4, 667.3, 417.8, 633.8, 417.1, 633.6, 421.8, 600.0, 422.4, 576.8, +430.8, 577.0, 439.7, 554.0, 437.6, 587.1, 435.6, 587.6, 438.6, 620.5, +392.3, 792.8, 390.7, 784.7, 386.5, 785.5, 380.8, 778.2, 371.1, 765.9, +366.9, 767.5, 361.4, 753.6, 362.4, 743.8, 362.4, 743.8, 363.4, 734.1, +364.5, 737.8, 368.3, 736.6, 373.2, 739.2, 385.7, 764.5, 386.9, 765.2, +392.3, 792.8, 395.0, 861.0, 396.6, 870.7, 394.0, 872.0, 398.3, 880.4, +382.6, 873.9, 382.6, 873.9, 366.8, 867.4, 369.6, 865.9, 366.3, 859.8, +365.7, 852.2, 361.5, 819.0, 363.7, 818.8, 361.6, 785.4, 387.3, 793.1, +380.1, 822.5, 395.0, 861.0, 361.6, 785.4, 361.0, 774.7, 361.6, 774.6, +360.3, 764.1, 360.9, 758.8, 360.9, 758.8, 361.4, 753.6, 366.9, 767.5, +371.1, 765.9, 380.8, 778.2, 389.5, 801.5, 385.1, 803.2, 389.3, 828.2, +396.7, 830.6, 392.2, 844.6, 395.0, 861.0, 380.1, 822.5, 387.3, 793.1, +361.6, 785.4, 436.3, 874.3, 412.8, 851.2, 417.3, 837.2, 389.3, 828.2, +385.1, 803.2, 389.5, 801.5, 380.8, 778.2, 386.5, 785.5, 390.7, 784.7, +392.3, 792.8, 393.5, 794.3, 393.5, 794.3, 394.7, 795.9, 407.7, 812.4, +407.7, 812.4, 420.7, 828.9, 428.5, 829.0, 428.4, 838.7, 436.1, 848.5, +440.1, 860.0, 431.5, 872.2, 436.3, 874.3, 436.1, 848.5, 444.4, 858.9, +442.1, 862.3, 452.6, 869.4, 451.9, 874.1, 452.4, 874.2, 451.3, 878.7, +450.8, 880.6, 450.5, 882.6, 450.3, 882.5, 448.4, 883.8, 446.9, 883.9, +444.9, 882.7, 442.2, 883.6, 440.6, 878.5, 436.3, 874.3, 431.5, 872.2, +440.1, 860.0, 436.1, 848.5, 383.8, 232.7, 386.1, 216.4, 392.4, 214.6, +388.3, 200.2, 389.4, 199.1, 389.4, 199.1, 390.4, 198.0, 388.0, 215.4, +394.0, 221.9, 383.8, 232.7, 284.3, 466.1, 288.2, 469.9, 287.7, 470.6, +292.1, 473.7, 296.3, 475.1, 295.0, 478.2, 299.2, 480.6, 316.5, 484.7, +314.1, 495.1, 329.0, 509.6, 330.1, 511.2, 327.3, 513.3, 325.6, 516.9, +320.7, 527.7, 323.9, 534.9, 315.8, 538.5, 315.8, 538.5, 312.6, 531.3, +309.5, 524.1, 301.1, 504.9, 301.1, 504.9, 292.8, 485.6, 288.5, 475.9, +284.9, 476.1, 284.3, 466.1, 358.5, 448.9, 362.0, 453.0, 362.0, 453.0, +365.6, 457.1, 373.1, 463.9, 370.3, 467.0, 374.9, 477.0, 371.0, 472.7, +364.3, 478.8, 353.6, 480.6, 349.6, 477.1, 355.1, 470.8, 356.6, 461.0, +357.2, 457.1, 357.2, 457.1, 357.8, 453.2, 358.1, 451.1, 359.1, 449.2, +358.5, 448.9, 417.7, 384.1, 404.9, 370.3, 406.4, 368.4, 392.0, 356.6, +390.1, 353.7, 388.6, 350.6, 388.2, 350.8, 389.5, 348.0, 386.2, 343.5, +381.6, 341.0, 375.3, 339.9, 376.4, 333.1, 371.2, 325.2, 375.1, 328.5, +377.6, 325.6, 384.0, 325.9, 401.6, 337.3, 403.5, 340.5, 423.8, 341.6, +424.2, 342.3, 424.2, 342.3, 424.7, 343.1, 421.8, 363.6, 427.9, 379.8, +417.7, 384.1, 424.7, 343.1, 432.4, 355.7, 432.0, 356.0, 440.0, 368.4, +440.9, 383.7, 440.9, 383.7, 441.8, 399.1, 442.4, 401.0, 441.3, 401.3, +440.8, 403.5, 440.7, 403.7, 439.2, 403.4, 437.6, 403.3, 437.8, 400.6, +433.8, 400.3, 430.0, 397.2, 422.5, 394.9, 423.9, 390.6, 417.7, 384.1, +427.9, 379.8, 421.8, 363.6, 424.7, 343.1, 355.4, 366.8, 358.1, 370.8, +357.9, 374.7, 360.7, 374.8, 352.1, 382.3, 352.1, 382.3, 343.5, 389.8, +340.0, 384.6, 346.3, 374.7, 355.4, 366.8, 418.9, 459.8, 393.4, 453.0, +367.7, 447.2, 367.9, 446.3, 366.7, 445.3, 366.7, 445.3, 365.4, 444.3, +365.4, 444.7, 366.6, 444.6, 367.8, 445.0, 393.3, 452.4, 417.7, 449.6, +418.9, 459.8, 262.9, 486.8, 261.9, 491.5, 261.0, 496.3, 261.0, 496.3, +259.6, 503.2, 259.6, 503.2, 258.1, 510.1, 259.7, 503.9, 259.4, 503.9, +260.7, 497.6, 261.8, 492.2, 261.5, 492.1, 262.9, 486.8, 118.7, 318.3, +119.2, 321.0, 119.2, 321.0, 119.8, 323.7, 122.1, 325.8, 107.3, 335.3, +108.8, 344.5, 106.6, 339.6, 106.6, 339.6, 104.4, 334.7, 106.1, 328.2, +109.4, 329.0, 114.3, 323.3, 116.5, 320.8, 116.7, 318.2, 118.7, 318.3, +925.0, 270.0, 923.2, 270.9, 923.2, 270.9, 921.4, 271.7, 910.6, 274.7, +910.2, 274.1, 900.1, 278.9, 892.2, 274.4, 892.2, 274.4, 884.2, 269.9, +853.6, 232.9, 850.9, 235.1, 817.5, 200.3, 861.1, 193.4, 867.2, 232.5, +916.9, 264.8, 921.0, 267.4, 922.6, 266.3, 925.0, 270.0, 704.8, 239.4, +704.8, 239.2, 714.5, 236.3, 722.0, 239.1, 727.1, 241.1, 726.0, 244.0, +729.9, 248.9, 747.4, 270.5, 766.2, 271.9, 764.8, 292.2, 765.0, 289.6, +744.5, 291.9, 727.4, 284.4, 723.0, 282.4, 724.6, 278.8, 721.8, 273.1, +713.3, 256.2, 704.7, 256.2, 704.8, 239.4, 666.3, 239.8, 663.2, 236.4, +657.8, 242.9, 652.5, 240.0, 645.6, 232.5, 645.6, 232.5, 638.7, 224.9, +652.4, 224.8, 656.3, 228.9, 666.3, 239.8, 773.6, 303.1, 775.2, 302.3, +778.8, 309.5, 784.0, 315.9, 784.0, 316.8, 785.5, 317.1, 785.4, 317.7, +785.1, 318.9, 784.8, 320.1, 784.9, 320.1, 781.7, 321.8, 783.7, 325.5, +782.6, 330.9, 778.5, 328.6, 777.8, 329.9, 773.0, 328.8, 768.4, 327.9, +768.5, 327.3, 763.9, 325.8, 764.2, 314.4, 765.2, 307.2, 773.6, 303.1, +697.2, 208.4, 686.5, 202.6, 682.2, 199.0, 680.7, 187.9, 687.8, 190.0, +690.8, 194.8, 695.0, 192.2, 697.4, 194.4, 698.4, 193.2, 701.9, 194.3, +726.8, 215.2, 729.6, 211.8, 757.4, 229.3, 757.5, 228.9, 724.9, 223.3, +697.2, 208.4, 624.2, 224.7, 614.0, 205.7, 616.0, 204.4, 603.8, 186.8, +608.6, 192.1, 608.6, 192.1, 613.4, 197.3, 620.3, 210.2, 614.9, 214.5, +624.2, 224.7, 484.2, 186.0, 456.3, 171.2, 457.3, 169.0, 428.4, 156.5, +427.8, 156.2, 427.8, 156.2, 427.2, 155.8, 455.7, 170.8, 457.2, 168.6, +484.2, 186.0, 620.2, 5.5, 620.2, 10.6, 617.8, 13.9, 620.2, 15.7, +610.8, 19.2, 610.8, 19.2, 601.4, 22.8, 598.7, 18.3, 595.3, 19.3, +588.8, 18.1, 583.6, 9.6, 583.6, 9.6, 578.5, 1.0, 584.0, -3.9, +578.1, -10.7, 577.7, -22.4, 577.6, -21.7, 578.8, -21.6, 580.0, -20.8, +600.1, -7.7, 602.6, -10.4, 620.2, 5.5, 151.7, 366.1, 155.5, 333.2, +157.2, 333.4, 159.2, 300.4, 164.9, 298.4, 164.9, 298.4, 170.5, 296.4, +166.4, 331.9, 170.9, 359.3, 151.7, 366.1, 170.5, 296.4, 171.2, 296.2, +171.2, 296.2, 172.0, 295.9, 171.6, 299.5, 180.8, 306.1, 185.4, 304.5, +183.7, 322.7, 183.7, 322.7, 182.0, 340.9, 165.8, 368.5, 158.1, 366.7, +150.4, 396.6, 150.3, 396.6, 150.3, 396.6, 150.3, 396.7, 149.9, 392.5, +149.9, 392.5, 149.5, 388.3, 149.1, 384.6, 149.8, 384.5, 150.0, 380.7, +150.3, 373.4, 150.8, 373.4, 151.7, 366.1, 170.9, 359.3, 166.4, 331.9, +170.5, 296.4, 618.3, 687.8, 619.4, 679.0, 603.6, 678.6, 602.3, 667.7, +612.9, 644.7, 605.8, 641.4, 609.2, 615.2, 628.7, 639.7, 622.9, 652.7, +618.3, 687.8, 705.5, 618.5, 711.2, 627.4, 711.2, 627.4, 716.9, 636.3, +710.2, 655.5, 702.4, 652.8, 687.9, 669.3, 675.3, 683.7, 676.1, 684.5, +662.7, 698.1, 662.7, 697.2, 661.9, 697.2, 661.2, 696.3, 664.7, 687.9, +665.7, 688.3, 670.2, 680.4, 674.1, 673.6, 674.1, 673.6, 678.0, 666.8, +691.7, 642.6, 685.3, 634.3, 705.5, 618.5, 743.5, 725.6, 741.4, 730.8, +743.2, 733.3, 739.3, 736.1, 735.2, 740.4, 735.2, 740.4, 731.1, 744.7, +721.4, 738.3, 724.7, 733.4, 718.2, 722.2, 717.3, 720.6, 717.3, 720.6, +716.3, 718.9, 710.1, 708.1, 710.1, 708.1, 703.9, 697.2, 703.3, 696.1, +703.6, 695.6, 702.6, 694.9, 712.2, 701.4, 711.9, 701.9, 721.2, 708.8, +730.6, 715.9, 730.6, 715.9, 739.9, 722.9, 741.7, 724.2, 743.6, 724.3, +743.5, 725.6, 685.5, 772.8, 679.5, 765.3, 672.3, 759.2, 673.6, 757.7, +672.1, 756.0, 672.1, 756.0, 670.7, 754.2, 667.7, 750.4, 667.7, 750.4, +664.7, 746.6, 664.1, 745.8, 664.1, 745.8, 663.5, 745.0, 653.5, 732.4, +648.2, 734.2, 643.6, 719.9, 648.2, 719.6, 647.9, 714.9, 652.3, 710.0, +670.8, 731.5, 665.9, 735.7, 679.5, 761.5, 682.5, 767.1, 680.8, 769.9, +685.5, 772.8, 575.0, 633.2, 573.1, 630.7, 572.8, 628.1, 571.1, 628.3, +573.3, 624.9, 563.2, 618.2, 555.2, 608.1, 549.9, 593.8, 552.4, 591.6, +543.2, 580.0, 545.2, 564.5, 545.2, 564.5, 547.1, 549.0, 544.2, 551.1, +550.9, 560.4, 554.6, 571.8, 564.8, 602.5, 566.0, 602.2, 575.0, 633.2, +552.2, 531.6, 552.3, 531.5, 551.5, 531.2, 551.5, 531.1, 556.7, 512.6, +556.7, 512.6, 561.8, 494.2, 561.8, 493.9, 562.9, 493.9, 564.0, 493.7, +563.0, 500.5, 561.9, 500.3, 559.9, 507.0, 556.0, 519.3, 556.4, 519.4, +552.2, 531.6, 550.7, 745.6, 554.9, 762.5, 548.5, 769.2, 559.2, 779.4, +552.8, 784.7, 553.7, 788.1, 546.4, 789.9, 533.1, 797.2, 533.1, 797.2, +519.9, 804.5, 522.8, 773.9, 526.4, 761.1, 550.7, 745.6, 519.9, 804.5, +517.5, 805.8, 515.6, 805.4, 515.2, 807.1, 519.5, 772.2, 519.5, 772.2, +523.8, 737.3, 523.0, 735.9, 534.1, 729.0, 544.4, 720.7, 547.5, 733.2, +547.5, 733.2, 550.7, 745.6, 526.4, 761.1, 522.8, 773.9, 519.9, 804.5, +580.6, 673.2, 579.5, 662.6, 575.3, 653.6, 578.4, 652.1, 579.7, 646.3, +581.0, 646.3, 580.9, 640.6, 585.5, 646.4, 590.7, 651.6, 590.1, 652.2, +589.9, 652.7, 591.6, 653.5, 591.4, 653.9, 590.6, 659.9, 604.0, 664.1, +602.3, 667.7, 603.6, 678.6, 619.4, 679.0, 618.3, 687.8, 618.4, 688.0, +618.4, 688.2, 618.6, 688.3, 602.2, 681.9, 602.3, 681.8, 586.0, 675.3, +583.3, 674.2, 581.2, 674.9, 580.6, 673.2, 531.6, 700.1, 530.3, 697.9, +528.6, 697.6, 529.0, 695.8, 529.9, 688.2, 529.6, 688.2, 530.8, 680.6, +531.2, 678.3, 531.1, 678.3, 531.4, 675.9, 535.0, 679.2, 545.9, 667.5, +560.3, 659.1, 560.5, 679.5, 547.8, 681.1, 531.6, 700.1, 611.2, 757.1, +629.3, 783.0, 624.2, 786.6, 637.1, 816.1, 639.1, 820.5, 640.9, 820.5, +641.0, 824.9, 639.3, 828.4, 639.3, 828.4, 637.6, 831.9, 624.6, 834.2, +616.6, 837.5, 610.6, 830.4, 603.2, 821.6, 610.7, 815.3, 610.8, 800.2, +610.9, 794.7, 610.9, 794.7, 610.9, 789.2, 611.0, 784.0, 611.0, 784.0, +611.0, 778.7, 611.1, 767.9, 616.2, 764.3, 611.2, 757.1, 670.7, 754.2, +672.1, 756.0, 672.1, 756.0, 673.6, 757.7, 650.1, 785.2, 657.3, 791.3, +641.0, 824.9, 640.9, 820.5, 639.1, 820.5, 637.1, 816.1, 641.6, 801.5, +644.6, 802.4, 652.0, 788.7, 661.4, 771.4, 659.6, 770.2, 670.7, 754.2, +626.7, 848.5, 592.0, 862.9, 591.6, 861.8, 557.4, 877.2, 556.7, 874.7, +556.7, 874.7, 556.1, 872.2, 590.4, 857.9, 627.4, 851.2, 626.7, 848.5, +547.0, 476.8, 547.6, 478.7, 548.3, 478.7, 548.1, 480.6, 548.0, 483.4, +548.0, 483.4, 547.9, 486.2, 546.7, 481.7, 546.9, 481.5, 547.0, 476.8, +492.2, 356.2, 480.9, 370.9, 480.9, 370.9, 469.6, 385.7, 467.7, 382.6, +463.9, 385.0, 458.3, 384.2, 462.7, 374.2, 467.7, 376.4, 477.2, 368.6, +484.7, 362.4, 488.7, 364.1, 492.2, 356.2, 396.9, 584.7, 408.3, 546.9, +410.4, 547.4, 419.7, 509.1, 420.3, 514.1, 421.1, 514.2, 420.8, 519.2, +420.7, 532.8, 420.4, 532.8, 420.6, 546.5, 419.9, 555.0, 419.9, 555.0, +419.2, 563.4, 411.4, 576.1, 397.0, 574.0, 396.9, 584.7, 419.2, 563.4, +415.4, 609.0, 415.4, 609.0, 411.6, 654.6, 411.0, 652.7, 407.3, 653.8, +403.1, 653.0, 408.9, 628.7, 408.9, 616.2, 393.3, 599.3, 394.8, 593.0, +394.8, 593.0, 396.3, 586.8, 396.5, 585.7, 396.6, 585.7, 396.9, 584.7, +397.0, 574.0, 411.4, 576.1, 419.2, 563.4, 418.1, 743.1, 421.8, 725.3, +421.8, 725.3, 425.5, 707.4, 433.4, 674.3, 434.0, 674.4, 442.2, 641.3, +444.8, 630.6, 447.3, 619.8, 447.3, 619.8, 447.3, 619.8, 444.8, 630.6, +442.2, 641.3, 435.7, 668.8, 435.7, 668.8, 429.2, 696.3, 423.6, 719.7, +425.6, 720.3, 418.1, 743.1, 394.7, 795.9, 393.5, 794.3, 393.5, 794.3, +392.3, 792.8, 386.9, 765.2, 385.7, 764.5, 373.2, 739.2, 388.1, 746.8, +402.3, 755.6, 403.0, 754.5, 420.6, 782.9, 420.6, 782.9, 438.3, 811.2, +438.9, 808.0, 416.1, 804.5, 394.7, 795.9, 438.3, 811.2, 438.3, 811.3, +438.3, 811.3, 438.3, 811.3, 444.2, 830.0, 444.2, 830.0, 450.1, 848.6, +437.5, 836.6, 435.5, 829.1, 420.7, 828.9, 407.7, 812.4, 407.7, 812.4, +394.7, 795.9, 416.1, 804.5, 438.9, 808.0, 438.3, 811.2, 416.1, 188.1, +416.4, 242.1, 416.0, 242.1, 416.8, 296.1, 407.0, 281.7, 407.0, 281.7, +397.3, 267.3, 397.0, 227.8, 431.5, 210.9, 416.1, 188.1, 397.3, 267.3, +390.0, 256.5, 379.9, 250.3, 382.7, 245.8, 382.5, 244.4, 382.5, 244.4, +382.3, 243.1, 381.0, 238.5, 383.0, 237.9, 383.8, 232.7, 394.0, 221.9, +388.0, 215.4, 390.4, 198.0, 401.1, 186.7, 400.3, 185.7, 411.9, 175.4, +413.9, 173.3, 413.9, 173.3, 416.0, 171.3, 415.9, 179.7, 416.0, 179.7, +416.1, 188.1, 431.5, 210.9, 397.0, 227.8, 397.3, 267.3, 275.3, 881.2, +275.2, 881.7, 275.2, 882.2, 275.0, 882.2, 263.9, 882.6, 255.8, 887.0, +252.7, 881.9, 240.2, 861.3, 244.8, 856.5, 243.7, 830.9, 244.0, 836.8, +247.3, 836.7, 251.0, 842.4, 255.4, 849.5, 255.4, 849.5, 259.8, 856.5, +264.9, 864.6, 264.9, 864.6, 270.1, 872.8, 272.7, 877.0, 273.1, 876.8, +275.3, 881.2, 239.4, 806.4, 234.4, 814.0, 241.5, 818.6, 243.7, 830.9, +244.8, 856.5, 240.2, 861.3, 252.7, 881.9, 246.6, 891.2, 211.6, 885.1, +210.9, 881.3, 205.0, 847.4, 218.0, 839.2, 239.4, 806.4, 210.9, 881.3, +210.8, 881.6, 209.1, 881.3, 209.1, 881.3, 212.1, 865.4, 209.0, 864.8, +208.8, 848.4, 207.5, 838.4, 210.5, 838.1, 212.2, 827.7, 209.5, 826.6, +221.9, 795.2, 231.7, 762.7, 223.7, 770.7, 235.1, 782.2, 238.5, 801.7, +239.0, 804.0, 240.0, 804.4, 239.4, 806.4, 218.0, 839.2, 205.0, 847.4, +210.9, 881.3, 359.2, 595.6, 360.1, 607.6, 363.8, 608.6, 361.0, 619.6, +360.5, 623.2, 360.5, 623.2, 360.0, 626.8, 311.7, 667.4, 312.0, 667.8, +264.0, 708.7, 275.7, 699.7, 273.7, 697.1, 283.5, 685.5, 292.3, 675.0, +292.3, 675.0, 301.1, 664.5, 313.0, 650.4, 313.0, 650.4, 324.9, 636.3, +342.0, 615.9, 337.3, 605.7, 359.2, 595.6, 355.4, 543.6, 356.1, 553.6, +356.1, 553.6, 356.8, 563.5, 339.0, 591.0, 311.6, 612.4, 311.1, 611.9, +307.1, 608.3, 329.4, 583.6, 347.8, 555.3, 351.6, 549.5, 356.2, 544.4, +355.4, 543.6, 257.4, 569.9, 257.2, 564.7, 255.6, 564.2, 257.0, 559.6, +259.6, 544.0, 258.2, 543.6, 262.2, 528.4, 267.1, 506.8, 262.2, 505.2, +269.5, 484.6, 270.8, 480.4, 270.8, 480.4, 272.0, 476.1, 273.8, 480.1, +271.2, 481.3, 270.4, 486.5, 263.9, 528.2, 265.0, 528.4, 257.4, 569.9, +279.0, 460.9, 279.1, 460.5, 278.2, 460.2, 277.5, 459.5, 277.2, 459.3, +277.0, 459.2, 277.0, 459.0, 283.9, 435.5, 283.9, 435.5, 290.7, 411.9, +300.0, 420.9, 285.7, 436.7, 279.0, 460.9, 308.0, 359.7, 310.3, 354.7, +310.3, 354.7, 312.7, 349.7, 314.3, 352.2, 333.6, 348.9, 337.7, 340.1, +346.5, 353.4, 346.5, 353.4, 355.4, 366.8, 346.3, 374.7, 340.0, 384.6, +343.5, 389.8, 341.5, 391.6, 341.5, 391.6, 339.5, 393.3, 322.1, 378.5, +319.9, 378.9, 308.0, 359.7, 339.5, 393.3, 337.2, 395.3, 334.6, 396.8, +334.9, 397.3, 323.6, 396.7, 316.9, 390.7, 312.2, 396.0, 305.9, 388.8, +301.7, 380.5, 299.6, 381.6, 301.0, 376.6, 301.0, 376.6, 302.4, 371.7, +303.9, 365.4, 305.2, 365.7, 308.0, 359.7, 319.9, 378.9, 322.1, 378.5, +339.5, 393.3, 431.3, 441.1, 431.5, 441.2, 431.6, 441.2, 431.6, 441.3, +431.6, 441.3, 431.6, 441.3, 431.6, 441.3, 431.5, 441.2, 431.3, 441.1, +431.3, 441.1, 260.7, 497.6, 259.4, 503.9, 259.7, 503.9, 258.1, 510.1, +256.8, 515.4, 255.8, 520.7, 255.8, 520.7, 249.4, 547.7, 250.8, 548.1, +242.9, 574.7, 241.7, 578.5, 241.8, 578.5, 240.7, 582.4, 239.4, 588.6, +238.4, 588.4, 236.0, 594.4, 240.5, 560.0, 241.1, 558.2, 234.6, 524.2, +242.6, 503.9, 242.6, 503.9, 250.5, 483.7, 249.5, 484.7, 258.5, 489.8, +260.7, 497.6, 250.5, 483.7, 251.2, 482.0, 251.0, 482.0, 251.8, 480.4, +262.3, 459.0, 262.3, 459.0, 272.8, 437.6, 267.5, 462.1, 267.9, 462.2, +262.9, 486.8, 261.5, 492.1, 261.8, 492.2, 260.7, 497.6, 258.5, 489.8, +249.5, 484.7, 250.5, 483.7, 114.3, 323.3, 109.4, 329.0, 106.1, 328.2, +104.4, 334.7, 90.8, 304.5, 90.8, 304.5, 77.2, 274.3, 74.8, 270.2, +76.4, 269.2, 75.5, 264.2, 92.4, 285.4, 90.4, 286.9, 105.3, 309.6, +109.8, 316.5, 114.5, 316.6, 114.3, 323.3, 721.8, 273.1, 724.6, 278.8, +723.0, 282.4, 727.4, 284.4, 727.4, 284.5, 723.5, 283.6, 719.5, 282.8, +717.0, 282.2, 717.0, 282.2, 714.4, 281.7, 699.8, 278.7, 698.9, 280.9, +685.2, 275.6, 681.5, 271.6, 681.5, 271.6, 677.8, 267.5, 699.5, 266.0, +701.2, 266.2, 721.8, 273.1, 677.8, 267.5, 665.2, 253.8, 665.2, 253.8, +652.5, 240.0, 657.8, 242.9, 663.2, 236.4, 666.3, 239.8, 685.6, 239.6, +690.8, 230.9, 704.8, 239.4, 704.7, 256.2, 713.3, 256.2, 721.8, 273.1, +701.2, 266.2, 699.5, 266.0, 677.8, 267.5, 641.5, 196.5, 647.2, 188.0, +652.8, 179.4, 653.0, 179.5, 666.8, 183.7, 666.8, 183.7, 680.7, 187.9, +682.2, 199.0, 686.5, 202.6, 697.2, 208.4, 705.9, 219.2, 705.9, 219.2, +714.6, 230.0, 715.2, 230.7, 715.9, 231.3, 715.8, 231.4, 715.7, 231.6, +715.0, 231.0, 714.1, 230.6, 677.8, 213.5, 671.3, 221.4, 641.5, 196.5, +686.3, 276.8, 685.8, 276.2, 685.8, 276.2, 685.2, 275.6, 698.9, 280.9, +699.8, 278.7, 714.4, 281.7, 706.7, 273.4, 700.2, 279.7, 686.3, 276.8, +714.6, 230.0, 705.9, 219.2, 705.9, 219.2, 697.2, 208.4, 724.9, 223.3, +757.5, 228.9, 757.4, 229.3, 757.4, 229.3, 757.4, 229.3, 757.4, 229.3, +741.4, 229.6, 741.4, 229.6, 725.3, 229.8, 720.0, 229.9, 718.0, 232.5, +714.6, 230.0, 652.8, 277.4, 638.5, 251.0, 638.5, 251.0, 624.2, 224.7, +614.9, 214.5, 620.3, 210.2, 613.4, 197.3, 620.0, 204.5, 620.0, 204.5, +626.6, 211.7, 626.7, 211.8, 626.7, 211.8, 626.8, 212.0, 626.8, 212.0, +626.8, 212.0, 626.8, 212.0, 655.9, 255.9, 655.5, 256.1, 685.6, 299.3, +696.0, 315.0, 696.0, 315.0, 706.4, 330.7, 700.6, 324.6, 698.1, 326.9, +689.7, 323.2, 669.0, 302.6, 669.0, 301.8, 652.8, 277.4, 689.7, 323.2, +681.7, 319.5, 675.5, 321.6, 673.6, 315.9, 673.6, 315.8, 673.6, 315.8, +673.5, 315.8, 673.6, 315.7, 663.2, 296.6, 652.8, 277.4, 669.0, 301.8, +669.0, 302.6, 689.7, 323.2, 521.4, 200.9, 516.3, 200.1, 515.0, 201.9, +511.1, 199.4, 505.2, 196.6, 505.2, 196.6, 499.3, 193.9, 491.5, 190.5, +491.8, 189.9, 484.2, 186.0, 456.3, 171.2, 457.3, 169.0, 428.4, 156.5, +427.8, 156.2, 427.8, 156.2, 427.2, 155.8, 423.8, 153.6, 423.0, 154.3, +420.4, 151.4, 414.8, 145.9, 415.1, 145.5, 409.3, 140.3, 413.9, 139.4, +413.9, 139.4, 418.6, 138.4, 425.7, 140.2, 425.1, 142.3, 431.7, 146.3, +476.5, 173.6, 477.8, 171.7, 521.4, 200.9, 616.4, -54.1, 618.2, -44.7, +618.2, -44.7, 620.1, -35.4, 629.9, -28.1, 620.1, -14.9, 620.2, 5.5, +602.6, -10.4, 600.1, -7.7, 580.0, -20.8, 579.0, -36.3, 595.0, -46.3, +616.4, -54.1, 580.0, -20.8, 578.8, -21.6, 577.6, -21.7, 577.7, -22.4, +577.3, -31.7, 574.6, -40.2, 577.0, -41.0, 582.2, -57.8, 582.2, -57.8, +587.3, -74.6, 593.8, -76.3, 595.3, -80.4, 597.6, -88.0, 597.7, -88.2, +598.1, -88.3, 598.2, -88.1, 605.5, -82.0, 608.1, -83.2, 612.3, -75.3, +615.4, -75.0, 614.4, -64.7, 616.4, -54.1, 595.0, -46.3, 579.0, -36.3, +580.0, -20.8, 609.3, 615.1, 609.3, 614.5, 609.2, 614.5, 609.4, 614.0, +616.4, 598.5, 612.9, 586.0, 623.3, 583.1, 625.3, 579.5, 626.3, 579.7, +627.2, 575.8, 627.0, 576.2, 627.3, 576.4, 627.3, 576.9, 628.7, 597.0, +628.7, 597.0, 630.0, 617.0, 631.0, 631.0, 631.0, 631.0, 631.9, 644.9, +632.5, 653.6, 632.6, 653.6, 633.1, 662.4, 634.6, 686.3, 634.3, 686.3, +635.9, 710.2, 635.9, 710.5, 636.4, 710.8, 636.4, 710.8, 636.4, 710.8, +635.9, 710.5, 635.9, 710.2, 636.2, 709.4, 634.9, 708.8, 633.8, 707.5, +620.9, 661.5, 621.3, 661.4, 609.3, 615.1, 633.8, 707.5, 632.3, 705.6, +630.8, 703.8, 630.9, 703.8, 624.7, 696.0, 624.7, 696.0, 618.6, 688.3, +618.4, 688.2, 618.4, 688.0, 618.3, 687.8, 622.9, 652.7, 628.7, 639.7, +609.2, 615.2, 609.3, 615.2, 609.3, 615.2, 609.3, 615.1, 621.3, 661.4, +620.9, 661.5, 633.8, 707.5, 696.0, 603.6, 696.3, 604.1, 696.3, 604.2, +696.7, 604.7, 695.6, 610.5, 701.1, 611.6, 705.5, 618.5, 685.3, 634.3, +691.7, 642.6, 678.0, 666.8, 683.9, 659.1, 680.8, 656.7, 683.7, 646.7, +686.2, 637.8, 686.2, 637.8, 688.7, 629.0, 692.4, 616.3, 691.9, 616.1, +696.0, 603.6, 727.2, 652.4, 737.6, 668.6, 733.2, 676.6, 747.9, 684.8, +750.0, 690.9, 751.5, 690.4, 755.2, 696.0, 744.3, 704.0, 749.3, 710.8, +743.5, 725.6, 743.6, 724.3, 741.7, 724.2, 739.9, 722.9, 734.8, 702.4, +736.2, 702.0, 732.4, 681.1, 729.8, 666.8, 732.9, 653.7, 727.2, 652.4, +679.5, 761.5, 665.9, 735.7, 670.8, 731.5, 652.3, 710.0, 654.4, 707.5, +654.4, 707.5, 656.6, 705.1, 664.6, 716.4, 661.9, 718.3, 667.3, 731.5, +671.8, 742.5, 671.8, 742.5, 676.3, 753.6, 677.2, 755.8, 677.2, 755.8, +678.1, 758.1, 678.8, 759.8, 678.6, 759.8, 679.5, 761.5, 579.1, 629.3, +577.6, 632.0, 576.4, 631.8, 576.1, 634.6, 575.6, 633.9, 575.6, 633.9, +575.0, 633.2, 566.0, 602.2, 564.8, 602.5, 554.6, 571.8, 558.1, 584.8, +560.0, 584.3, 565.3, 596.8, 572.2, 613.1, 574.3, 612.5, 579.1, 629.3, +559.9, 507.0, 561.9, 500.3, 563.0, 500.5, 564.0, 493.7, 568.0, 492.8, +572.1, 492.7, 572.1, 491.9, 576.3, 494.4, 580.8, 495.0, 580.6, 496.9, +584.7, 505.2, 590.1, 502.5, 599.7, 508.2, 583.8, 515.9, 577.2, 514.0, +559.9, 507.0, 613.0, 725.3, 604.5, 735.6, 603.8, 735.1, 595.9, 745.9, +592.5, 750.0, 588.2, 752.9, 589.1, 754.2, 590.3, 743.5, 587.9, 743.2, +586.8, 732.3, 588.7, 728.1, 593.8, 730.4, 600.8, 728.6, 606.9, 726.9, +612.1, 728.4, 613.0, 725.3, 576.6, 650.0, 574.9, 663.4, 567.3, 670.3, +573.1, 676.7, 567.5, 713.8, 563.1, 714.0, 563.4, 751.1, 558.5, 743.3, +558.5, 743.3, 553.7, 735.5, 559.4, 692.0, 562.7, 692.0, 576.6, 650.0, +553.7, 735.5, 549.1, 728.1, 549.1, 728.1, 544.4, 720.7, 538.1, 710.3, +538.0, 710.4, 531.6, 700.1, 547.8, 681.1, 560.5, 679.5, 560.3, 659.1, +568.5, 654.3, 571.0, 656.4, 576.7, 649.6, 576.6, 649.8, 576.6, 649.8, +576.6, 650.0, 562.7, 692.0, 559.4, 692.0, 553.7, 735.5, 601.6, 740.8, +602.5, 740.0, 602.5, 740.0, 603.4, 739.3, 608.2, 747.5, 607.2, 748.1, +611.1, 756.9, 611.2, 757.0, 611.2, 757.0, 611.2, 757.1, 616.2, 764.3, +611.1, 767.9, 611.0, 778.7, 611.9, 774.5, 609.9, 774.1, 608.7, 769.4, +605.2, 755.1, 604.2, 755.3, 601.6, 740.8, 630.4, 715.1, 633.1, 712.6, +634.5, 713.3, 635.9, 710.2, 635.9, 710.5, 636.4, 710.8, 636.4, 710.8, +637.3, 715.8, 640.3, 720.1, 643.6, 719.9, 648.2, 734.2, 653.5, 732.4, +663.5, 745.0, 660.2, 736.0, 655.5, 737.8, 647.5, 730.5, 638.9, 722.8, +635.8, 724.6, 630.4, 715.1, 556.0, 871.7, 550.9, 851.6, 545.8, 831.4, +545.8, 831.4, 546.6, 829.6, 545.2, 829.0, 544.5, 826.6, 554.0, 824.7, +563.2, 824.2, 564.4, 827.7, 569.6, 842.9, 560.9, 845.9, 557.4, 864.1, +556.7, 867.9, 554.8, 868.6, 556.0, 871.7, 514.8, 533.6, 503.1, 533.1, +491.9, 530.4, 491.4, 532.6, 486.1, 528.4, 475.4, 529.7, 474.6, 531.9, +474.7, 530.5, 474.7, 530.5, 474.8, 529.0, 469.2, 522.9, 486.6, 506.8, +498.4, 484.5, 495.6, 487.0, 501.4, 493.6, 504.5, 502.6, 508.3, 514.0, +508.3, 514.0, 512.1, 525.5, 513.5, 529.6, 514.9, 533.6, 514.8, 533.6, +448.4, 376.8, 447.4, 374.6, 447.4, 374.6, 446.4, 372.4, 448.0, 361.3, +448.9, 361.0, 447.8, 349.9, 451.7, 335.6, 451.7, 335.6, 455.6, 321.4, +462.3, 334.2, 453.4, 338.8, 451.1, 356.2, 449.7, 366.5, 451.2, 367.0, +448.4, 376.8, 442.2, 641.3, 444.8, 630.6, 447.3, 619.8, 447.3, 619.8, +450.4, 607.2, 451.7, 607.4, 453.5, 594.6, 455.3, 625.3, 455.3, 625.3, +457.1, 655.9, 458.4, 650.7, 444.6, 650.0, 442.2, 641.3, 305.5, 617.8, +304.9, 615.7, 308.3, 614.8, 311.1, 611.9, 311.6, 612.4, 339.0, 591.0, +356.8, 563.5, 358.0, 579.6, 358.0, 579.6, 359.2, 595.6, 337.3, 605.7, +342.0, 615.9, 324.9, 636.3, 323.8, 637.1, 319.9, 631.5, 314.9, 626.8, +310.2, 622.3, 306.8, 623.1, 305.5, 617.8, 273.1, 632.1, 273.6, 645.9, +270.9, 655.3, 260.4, 660.1, 260.0, 649.2, 260.0, 649.2, 259.6, 638.3, +262.0, 633.2, 273.2, 635.0, 273.1, 632.1, 356.6, 461.0, 355.1, 470.8, +349.6, 477.1, 353.6, 480.6, 347.2, 481.7, 347.2, 481.7, 340.7, 482.8, +342.5, 471.0, 347.1, 462.7, 356.6, 461.0, 410.9, 428.7, 421.1, 434.9, +421.1, 434.9, 431.3, 441.1, 431.3, 441.1, 431.5, 441.2, 431.6, 441.3, +429.9, 448.1, 429.0, 448.0, 428.3, 454.9, 428.0, 458.4, 427.4, 458.4, +426.6, 461.9, 426.5, 460.5, 422.7, 460.9, 418.9, 459.8, 417.7, 449.6, +393.3, 452.4, 367.8, 445.0, 367.1, 442.5, 388.9, 430.0, 410.9, 428.7, +367.8, 445.0, 366.6, 444.6, 365.4, 444.7, 365.4, 444.3, 359.8, 439.8, +359.8, 439.8, 354.1, 435.3, 368.9, 434.1, 368.0, 423.2, 381.9, 411.1, +389.8, 423.9, 396.4, 419.9, 410.9, 428.7, 388.9, 430.0, 367.1, 442.5, +367.8, 445.0, 68.2, 220.7, 67.1, 213.8, 64.9, 213.5, 65.9, 206.9, +66.4, 193.9, 65.6, 193.9, 66.9, 181.0, 67.2, 178.0, 67.2, 178.0, +67.4, 175.0, 67.9, 176.4, 68.0, 176.4, 68.6, 177.8, 82.1, 176.7, +85.3, 216.6, 101.9, 255.4, 102.1, 238.2, 82.5, 239.9, 68.2, 220.7, +819.3, 199.5, 818.6, 198.6, 817.2, 199.7, 816.1, 198.8, 809.4, 191.8, +809.4, 191.8, 802.7, 184.8, 805.2, 187.7, 805.6, 187.3, 808.4, 189.9, +810.7, 191.9, 810.7, 191.9, 813.0, 194.0, 816.1, 196.8, 817.1, 196.1, +819.3, 199.5, 916.9, 264.8, 867.2, 232.5, 861.1, 193.4, 817.5, 200.3, +816.8, 199.5, 816.8, 199.5, 816.1, 198.8, 817.2, 199.7, 818.6, 198.6, +819.3, 199.5, 857.7, 208.5, 857.7, 208.3, 896.1, 217.4, 896.2, 217.4, +896.3, 217.5, 896.3, 217.7, 906.7, 241.2, 902.2, 261.5, 916.9, 264.8, +896.3, 217.7, 896.4, 217.7, 896.5, 217.6, 896.6, 217.7, 912.8, 229.1, +912.7, 229.3, 929.0, 240.6, 934.5, 244.9, 934.5, 244.9, 940.1, 249.1, +943.0, 254.3, 941.7, 255.7, 941.3, 262.2, 941.3, 262.5, 939.2, 262.7, +939.3, 263.2, 939.6, 265.2, 925.6, 266.1, 925.5, 269.8, 925.5, 269.9, +925.2, 269.9, 925.0, 270.0, 922.6, 266.3, 921.0, 267.4, 916.9, 264.8, +904.8, 242.3, 906.9, 241.2, 896.6, 217.7, 896.5, 217.6, 896.4, 217.7, +896.3, 217.7, 638.0, 224.2, 633.7, 219.4, 633.7, 219.4, 629.3, 214.7, +636.9, 207.0, 635.4, 205.6, 641.5, 196.5, 671.3, 221.4, 677.8, 213.5, +714.1, 230.6, 713.9, 232.2, 675.4, 231.2, 638.0, 224.2, 714.1, 230.6, +715.0, 231.0, 715.7, 231.6, 715.8, 231.4, 719.2, 235.0, 721.8, 239.3, +722.0, 239.1, 714.5, 236.3, 704.8, 239.2, 704.8, 239.4, 690.8, 230.9, +685.6, 239.6, 666.3, 239.8, 656.3, 228.9, 652.4, 224.8, 638.7, 224.9, +638.4, 224.6, 638.4, 224.6, 638.0, 224.2, 675.4, 231.2, 713.9, 232.2, +714.1, 230.6, 719.5, 282.8, 723.5, 283.6, 727.4, 284.5, 727.4, 284.4, +744.5, 291.9, 765.0, 289.6, 764.8, 292.2, 770.3, 294.4, 771.1, 303.5, +773.3, 302.8, 766.0, 305.3, 763.9, 299.3, 754.4, 295.7, 737.0, 289.2, +736.7, 290.0, 719.5, 282.8, 725.3, 229.8, 741.4, 229.6, 741.4, 229.6, +757.4, 229.3, 769.7, 237.1, 769.7, 237.1, 782.1, 244.9, 778.4, 241.6, +776.7, 243.5, 771.3, 242.0, 748.3, 235.9, 740.9, 244.0, 725.3, 229.8, +519.0, 181.6, 528.0, 190.6, 526.3, 193.5, 537.0, 199.6, 538.5, 201.6, +538.5, 201.6, 540.0, 203.6, 532.3, 199.4, 530.7, 202.2, 521.4, 200.9, +477.8, 171.7, 476.5, 173.6, 431.7, 146.3, 434.6, 169.1, 477.1, 160.4, +519.0, 181.6, 431.7, 146.3, 425.1, 142.3, 425.7, 140.2, 418.6, 138.4, +432.6, 135.3, 433.1, 136.8, 446.7, 132.3, 455.3, 131.1, 458.1, 133.7, +463.7, 128.7, 464.0, 128.4, 464.3, 128.6, 464.8, 128.5, 471.2, 135.4, +471.8, 134.9, 478.7, 141.4, 503.0, 150.3, 498.8, 161.5, 519.0, 181.6, +477.1, 160.4, 434.6, 169.1, 431.7, 146.3, 662.2, 550.8, 669.9, 559.1, +668.4, 560.5, 674.6, 570.2, 678.1, 576.1, 676.7, 578.5, 682.0, 581.7, +681.3, 582.6, 684.2, 587.1, 685.3, 586.9, 687.4, 596.0, 690.6, 595.2, +696.0, 603.6, 691.9, 616.1, 692.4, 616.3, 688.7, 629.0, 673.2, 615.5, +681.1, 606.5, 673.4, 583.9, 669.5, 572.2, 669.5, 572.2, 665.5, 560.5, +663.8, 555.6, 665.4, 554.2, 662.2, 550.8, 721.2, 708.8, 711.9, 701.9, +712.2, 701.4, 702.6, 694.9, 693.5, 684.1, 688.8, 682.7, 688.3, 669.9, +688.6, 678.5, 695.3, 678.2, 702.3, 686.5, 711.7, 697.7, 720.7, 697.3, +721.2, 708.8, 661.0, 700.0, 661.9, 699.0, 662.6, 699.1, 662.7, 698.1, +676.1, 684.5, 675.3, 683.7, 687.9, 669.3, 687.9, 669.4, 688.1, 669.6, +688.3, 669.9, 688.8, 682.7, 693.5, 684.1, 702.6, 694.9, 703.6, 695.6, +703.3, 696.1, 703.9, 697.2, 692.5, 699.2, 692.3, 698.0, 680.6, 698.7, +675.1, 699.1, 675.1, 699.1, 669.6, 699.4, 665.3, 699.7, 665.1, 700.8, +661.0, 700.0, 592.4, 572.5, 589.3, 586.8, 582.8, 599.4, 586.2, 601.1, +580.0, 612.0, 575.6, 621.5, 580.6, 626.7, 579.9, 628.0, 579.9, 628.0, +579.1, 629.3, 574.3, 612.5, 572.2, 613.1, 565.3, 596.8, 568.7, 582.3, +581.8, 570.3, 592.4, 572.5, 565.3, 596.8, 560.0, 584.3, 558.1, 584.8, +554.6, 571.8, 550.9, 560.4, 544.2, 551.1, 547.1, 549.0, 547.3, 547.2, +546.7, 546.9, 547.5, 545.3, 549.5, 538.2, 549.5, 538.2, 551.5, 531.1, +551.5, 531.2, 552.3, 531.5, 552.2, 531.6, 554.8, 533.5, 554.8, 533.5, +557.4, 535.4, 576.0, 549.0, 579.0, 546.1, 594.5, 562.6, 593.4, 567.5, +593.4, 567.5, 592.4, 572.5, 581.8, 570.3, 568.7, 582.3, 565.3, 596.8, +605.0, 514.1, 599.8, 538.4, 599.8, 538.4, 594.5, 562.6, 579.0, 546.1, +576.0, 549.0, 557.4, 535.4, 560.7, 520.3, 594.6, 506.5, 605.0, 514.1, +557.4, 535.4, 554.8, 533.5, 554.8, 533.5, 552.2, 531.6, 556.4, 519.4, +556.0, 519.3, 559.9, 507.0, 577.2, 514.0, 583.8, 515.9, 599.7, 508.2, +602.6, 509.9, 602.6, 509.9, 605.6, 511.6, 605.8, 511.8, 605.3, 512.9, +605.0, 514.1, 594.6, 506.5, 560.7, 520.3, 557.4, 535.4, 600.8, 728.6, +593.8, 730.4, 588.7, 728.1, 586.8, 732.3, 583.7, 702.7, 583.7, 702.7, +580.6, 673.2, 581.2, 674.9, 583.3, 674.2, 586.0, 675.3, 595.4, 701.2, +600.4, 701.8, 600.8, 728.6, 586.0, 675.3, 602.3, 681.8, 602.2, 681.9, +618.6, 688.3, 624.7, 696.0, 624.7, 696.0, 630.9, 703.8, 620.4, 712.7, +621.9, 714.5, 613.0, 725.3, 612.1, 728.4, 606.9, 726.9, 600.8, 728.6, +600.4, 701.8, 595.4, 701.2, 586.0, 675.3, 610.8, 800.2, 610.7, 815.3, +603.2, 821.6, 610.6, 830.4, 610.6, 830.5, 608.9, 830.3, 607.3, 830.2, +585.8, 828.9, 585.8, 828.9, 564.4, 827.7, 563.2, 824.2, 554.0, 824.7, +544.5, 826.6, 544.5, 826.3, 544.5, 826.3, 544.4, 826.1, 577.5, 812.9, +578.6, 798.2, 610.8, 800.2, 611.1, 756.9, 607.2, 748.1, 608.2, 747.5, +603.4, 739.3, 609.7, 733.6, 609.7, 733.6, 616.0, 728.0, 614.4, 728.3, +615.2, 732.7, 614.4, 737.3, 614.3, 737.8, 614.3, 737.8, 614.2, 738.3, +612.7, 747.6, 613.5, 756.7, 611.1, 756.9, 607.3, 830.2, 608.9, 830.3, +610.6, 830.5, 610.6, 830.4, 616.6, 837.5, 624.6, 834.2, 637.6, 831.9, +634.0, 839.4, 634.0, 839.4, 630.3, 847.0, 630.3, 846.9, 628.5, 847.7, +626.7, 848.5, 627.4, 851.2, 590.4, 857.9, 556.1, 872.2, 556.0, 871.9, +556.0, 871.9, 556.0, 871.7, 554.8, 868.6, 556.7, 867.9, 557.4, 864.1, +580.8, 845.2, 581.8, 846.3, 607.3, 830.2, 557.4, 864.1, 560.9, 845.9, +569.6, 842.9, 564.4, 827.7, 585.8, 828.9, 585.8, 828.9, 607.3, 830.2, +581.8, 846.3, 580.8, 845.2, 557.4, 864.1, 547.5, 499.4, 547.5, 499.8, +547.7, 500.0, 547.5, 500.3, 536.3, 517.1, 536.3, 517.1, 525.2, 534.0, +525.1, 533.3, 520.0, 533.8, 514.8, 533.6, 514.9, 533.6, 513.5, 529.6, +512.1, 525.5, 518.9, 516.3, 521.8, 518.4, 531.4, 511.3, 539.5, 505.4, +539.3, 505.1, 547.5, 499.4, 451.1, 356.2, 453.4, 338.8, 462.3, 334.2, +455.6, 321.4, 456.1, 319.7, 457.2, 318.6, 456.6, 318.0, 458.1, 318.4, +458.1, 318.4, 459.7, 318.9, 457.0, 337.8, 462.6, 349.1, 451.1, 356.2, +429.2, 696.3, 435.7, 668.8, 435.7, 668.8, 442.2, 641.3, 444.6, 650.0, +458.4, 650.7, 457.1, 655.9, 457.9, 669.3, 457.9, 669.3, 458.7, 682.6, +462.2, 696.8, 457.6, 697.9, 456.6, 713.1, 453.4, 715.7, 446.3, 706.8, +436.1, 700.5, 432.6, 698.4, 429.0, 698.0, 429.2, 696.3, 347.1, 650.0, +347.7, 658.4, 346.5, 658.6, 348.4, 666.8, 338.4, 696.1, 338.4, 696.1, +328.4, 725.4, 328.1, 726.3, 328.0, 726.3, 327.5, 727.1, 325.7, 730.5, +324.9, 730.3, 324.0, 733.9, 334.6, 692.0, 335.4, 692.2, 346.9, 650.6, +347.0, 650.3, 347.1, 650.3, 347.1, 650.0, 270.1, 872.8, 264.9, 864.6, +264.9, 864.6, 259.8, 856.5, 259.4, 855.5, 260.7, 854.9, 261.5, 853.3, +292.7, 793.6, 292.7, 793.6, 324.0, 733.9, 324.9, 730.3, 325.7, 730.5, +327.5, 727.1, 299.2, 800.1, 306.2, 803.8, 270.1, 872.8, 327.5, 727.1, +328.0, 726.3, 328.1, 726.3, 328.4, 725.4, 322.8, 741.8, 319.6, 741.4, +317.2, 758.2, 297.5, 803.6, 296.7, 804.1, 285.2, 852.2, 281.3, 861.8, +284.4, 870.0, 278.5, 871.8, 275.7, 875.5, 276.9, 876.5, 275.3, 881.2, +273.1, 876.8, 272.7, 877.0, 270.1, 872.8, 306.2, 803.8, 299.2, 800.1, +327.5, 727.1, 314.9, 626.8, 319.9, 631.5, 323.8, 637.1, 324.9, 636.3, +313.0, 650.4, 313.0, 650.4, 301.1, 664.5, 306.3, 660.7, 303.8, 657.3, +306.4, 650.2, 310.6, 638.5, 306.5, 633.0, 314.9, 626.8, 347.1, 555.7, +347.3, 561.2, 337.1, 561.5, 327.0, 567.2, 310.5, 576.7, 311.8, 580.6, +294.0, 586.2, 297.6, 585.1, 296.3, 581.2, 298.6, 576.2, 300.9, 571.2, +300.9, 571.2, 303.2, 566.1, 309.5, 552.3, 309.5, 552.3, 315.8, 538.5, +323.9, 534.9, 320.7, 527.7, 325.6, 516.9, 342.1, 525.9, 346.6, 536.0, +347.1, 555.7, 325.6, 516.9, 327.3, 513.3, 330.1, 511.2, 329.0, 509.6, +341.8, 522.1, 341.8, 522.1, 354.7, 534.6, 356.5, 535.4, 355.0, 539.1, +355.4, 543.6, 356.2, 544.4, 351.6, 549.5, 347.8, 555.3, 347.6, 555.6, +347.1, 555.7, 347.1, 555.7, 346.6, 536.0, 342.1, 525.9, 325.6, 516.9, +278.9, 619.5, 273.7, 609.2, 282.3, 599.0, 294.0, 586.2, 311.8, 580.6, +310.5, 576.7, 327.0, 567.2, 330.2, 573.7, 313.3, 582.2, 299.5, 597.1, +289.2, 608.3, 276.5, 614.7, 278.9, 619.5, 308.5, 478.6, 294.1, 470.2, +294.6, 469.4, 279.8, 461.8, 279.3, 461.5, 278.9, 461.2, 279.0, 460.9, +285.7, 436.7, 300.0, 420.9, 290.7, 411.9, 291.4, 409.5, 291.4, 409.5, +292.1, 407.2, 292.0, 407.2, 292.6, 409.2, 293.0, 411.3, 300.8, 444.9, +316.2, 449.0, 308.5, 478.6, 105.3, 309.6, 90.4, 286.9, 92.4, 285.4, +75.5, 264.2, 71.9, 242.5, 71.9, 242.5, 68.2, 220.7, 82.5, 239.9, +102.1, 238.2, 101.9, 255.4, 103.7, 259.7, 103.7, 259.7, 105.6, 264.0, +107.0, 286.7, 105.6, 309.6, 105.3, 309.6, 105.6, 264.0, 105.7, 264.1, +105.7, 264.1, 105.7, 264.3, 108.2, 272.8, 108.8, 272.7, 110.6, 281.3, +114.6, 299.8, 114.6, 299.8, 118.7, 318.3, 116.7, 318.2, 116.5, 320.8, +114.3, 323.3, 114.5, 316.6, 109.8, 316.5, 105.3, 309.6, 102.1, 287.5, +105.6, 287.0, 105.7, 264.3, 105.7, 264.1, 105.7, 264.1, 105.6, 264.0, +813.0, 194.0, 807.8, 189.4, 807.8, 189.4, 802.7, 184.8, 802.4, 184.5, +802.4, 184.5, 802.1, 184.2, 805.3, 187.0, 805.3, 187.0, 808.4, 189.9, +810.7, 191.9, 810.7, 191.9, 813.0, 194.0, 703.6, 295.6, 697.1, 288.6, +697.1, 288.6, 690.7, 281.6, 688.5, 279.2, 688.5, 279.2, 686.3, 276.8, +700.2, 279.7, 706.7, 273.4, 714.4, 281.7, 717.0, 282.2, 717.0, 282.2, +719.5, 282.8, 736.7, 290.0, 737.0, 289.2, 754.4, 295.7, 739.0, 308.1, +727.8, 301.0, 703.6, 295.6, 754.4, 295.7, 763.9, 299.3, 766.0, 305.3, +773.3, 302.8, 773.5, 302.8, 773.7, 303.0, 773.6, 303.1, 765.2, 307.2, +764.2, 314.4, 763.9, 325.8, 740.5, 318.1, 741.1, 315.2, 717.1, 310.4, +710.4, 303.0, 710.4, 303.0, 703.6, 295.6, 727.8, 301.0, 739.0, 308.1, +754.4, 295.7, 729.9, 248.9, 726.0, 244.0, 727.1, 241.1, 722.0, 239.1, +721.8, 239.3, 719.2, 235.0, 715.8, 231.4, 715.9, 231.3, 715.2, 230.7, +714.6, 230.0, 718.0, 232.5, 720.0, 229.9, 725.3, 229.8, 740.9, 244.0, +748.3, 235.9, 771.3, 242.0, 765.5, 235.9, 756.5, 244.5, 741.7, 247.0, +735.8, 247.9, 734.7, 250.8, 729.9, 248.9, 627.3, 576.9, 627.3, 576.4, +627.0, 576.2, 627.2, 575.8, 628.0, 572.7, 625.3, 571.4, 626.8, 569.1, +632.9, 555.2, 632.9, 555.2, 639.0, 541.4, 632.2, 549.5, 635.4, 552.2, +631.9, 562.9, 629.6, 569.9, 629.8, 570.0, 627.3, 576.9, 732.4, 681.1, +736.2, 702.0, 734.8, 702.4, 739.9, 722.9, 730.6, 715.9, 730.6, 715.9, +721.2, 708.8, 720.7, 697.3, 711.7, 697.7, 702.3, 686.5, 705.4, 678.9, +726.0, 674.9, 732.4, 681.1, 702.3, 686.5, 695.3, 678.2, 688.6, 678.5, +688.3, 669.9, 688.1, 669.6, 687.9, 669.4, 687.9, 669.3, 702.4, 652.8, +710.2, 655.5, 716.9, 636.3, 722.1, 644.3, 722.1, 644.3, 727.2, 652.4, +732.9, 653.7, 729.8, 666.8, 732.4, 681.1, 726.0, 674.9, 705.4, 678.9, +702.3, 686.5, 667.3, 731.5, 661.9, 718.3, 664.6, 716.4, 656.6, 705.1, +658.8, 702.5, 658.8, 702.5, 661.0, 700.0, 665.1, 700.8, 665.3, 699.7, +669.6, 699.4, 672.6, 714.6, 674.1, 728.5, 667.3, 731.5, 583.5, 760.9, +586.3, 757.5, 588.6, 757.8, 589.1, 754.2, 588.2, 752.9, 592.5, 750.0, +595.9, 745.9, 598.1, 742.9, 598.8, 743.4, 601.6, 740.8, 604.2, 755.3, +605.2, 755.1, 608.7, 769.4, 605.2, 773.4, 593.4, 768.6, 583.5, 760.9, +647.5, 730.5, 655.5, 737.8, 660.2, 736.0, 663.5, 745.0, 664.1, 745.8, +664.1, 745.8, 664.7, 746.6, 662.4, 744.7, 662.5, 744.5, 660.3, 742.5, +653.9, 736.5, 654.3, 736.0, 647.5, 730.5, 521.2, 461.3, 529.7, 453.6, +529.7, 453.6, 538.1, 445.8, 538.4, 448.1, 538.8, 448.1, 539.5, 450.4, +531.8, 457.4, 520.4, 458.7, 521.2, 461.3, 477.2, 368.6, 467.7, 376.4, +462.7, 374.2, 458.3, 384.2, 454.8, 383.8, 452.5, 381.9, 451.3, 383.3, +449.8, 380.1, 449.8, 380.1, 448.4, 376.8, 451.2, 367.0, 449.7, 366.5, +451.1, 356.2, 462.6, 349.1, 457.0, 337.8, 459.7, 318.9, 461.5, 319.4, +461.5, 319.4, 463.3, 319.9, 471.7, 343.7, 479.1, 344.9, 477.2, 368.6, +463.3, 319.9, 471.0, 322.1, 478.7, 323.4, 478.6, 324.2, 486.4, 339.0, +486.4, 339.0, 494.1, 353.7, 494.4, 354.1, 493.2, 355.0, 492.2, 356.2, +488.7, 364.1, 484.7, 362.4, 477.2, 368.6, 479.1, 344.9, 471.7, 343.7, +463.3, 319.9, 418.9, 766.3, 416.7, 763.5, 416.7, 763.5, 414.4, 760.8, +413.6, 760.2, 414.9, 758.5, 415.4, 756.3, 418.5, 760.1, 419.8, 761.8, +418.9, 766.3, 238.5, 801.7, 235.1, 782.2, 223.7, 770.7, 231.7, 762.7, +232.7, 759.2, 232.7, 759.2, 233.8, 755.6, 236.8, 761.2, 234.5, 762.4, +235.2, 769.2, 235.4, 771.3, 235.4, 771.3, 235.6, 773.3, 236.2, 779.1, +236.2, 779.1, 236.8, 784.9, 237.4, 790.6, 237.4, 790.6, 238.0, 796.2, +238.3, 799.0, 238.0, 799.0, 238.5, 801.7, 283.5, 685.5, 273.7, 697.1, +275.7, 699.7, 264.0, 708.7, 263.0, 709.5, 263.0, 709.5, 262.0, 710.4, +267.0, 702.9, 264.5, 698.4, 261.3, 688.3, 259.5, 685.3, 261.2, 684.4, +261.0, 680.4, 271.8, 679.0, 283.1, 681.8, 283.5, 685.5, 297.7, 626.0, +292.4, 638.3, 287.9, 636.3, 278.2, 646.7, 269.3, 656.0, 270.6, 657.7, +260.5, 665.3, 260.4, 662.7, 260.4, 662.7, 260.4, 660.1, 270.9, 655.3, +273.6, 645.9, 273.1, 632.1, 276.0, 625.8, 274.8, 624.9, 278.9, 619.5, +276.5, 614.7, 289.2, 608.3, 299.5, 597.1, 303.2, 598.4, 303.1, 613.5, +297.7, 626.0, 299.5, 597.1, 313.3, 582.2, 330.2, 573.7, 327.0, 567.2, +337.1, 561.5, 347.3, 561.2, 347.1, 555.7, 347.1, 555.7, 347.6, 555.6, +347.8, 555.3, 329.4, 583.6, 307.1, 608.3, 311.1, 611.9, 308.3, 614.8, +304.9, 615.7, 305.5, 617.8, 301.6, 621.9, 296.9, 623.2, 297.7, 626.0, +303.1, 613.5, 303.2, 598.4, 299.5, 597.1, 270.4, 486.5, 271.2, 481.3, +273.8, 480.1, 272.0, 476.1, 274.5, 467.6, 274.5, 467.6, 277.0, 459.0, +277.0, 459.2, 277.2, 459.3, 277.5, 459.5, 274.2, 473.1, 274.7, 473.3, +270.4, 486.5, 273.8, 561.0, 276.9, 540.3, 287.9, 535.6, 309.5, 524.1, +312.6, 531.3, 315.8, 538.5, 315.8, 538.5, 309.5, 552.3, 309.5, 552.3, +303.2, 566.1, 292.8, 571.7, 273.8, 561.4, 273.8, 561.0, 293.0, 411.3, +292.6, 409.2, 292.0, 407.2, 292.1, 407.2, 292.3, 406.5, 292.3, 406.5, +292.5, 405.8, 306.0, 421.3, 313.3, 417.0, 335.5, 422.7, 339.3, 427.0, +338.6, 427.9, 343.0, 431.2, 352.6, 437.1, 350.7, 440.1, 358.5, 448.9, +359.1, 449.2, 358.1, 451.1, 357.8, 453.2, 346.9, 448.6, 347.8, 446.7, +337.7, 440.2, 315.4, 425.7, 314.6, 426.8, 293.0, 411.3, 808.4, 189.9, +805.3, 187.0, 805.3, 187.0, 802.1, 184.2, 799.7, 181.7, 799.7, 181.7, +797.2, 179.1, 809.8, 174.1, 821.3, 166.9, 820.2, 163.7, 862.2, 179.9, +899.8, 209.2, 896.1, 217.4, 893.9, 222.3, 851.7, 205.1, 808.4, 189.9, +896.1, 217.4, 896.4, 217.5, 896.4, 217.5, 896.6, 217.7, 896.5, 217.6, +896.4, 217.7, 896.3, 217.7, 857.8, 208.6, 857.3, 210.4, 819.3, 199.5, +817.1, 196.1, 816.1, 196.8, 813.0, 194.0, 810.7, 191.9, 810.7, 191.9, +808.4, 189.9, 851.7, 205.1, 893.9, 222.3, 896.1, 217.4, 786.5, 247.7, +786.8, 247.9, 786.8, 247.9, 787.0, 248.0, 779.8, 266.6, 786.1, 269.0, +785.1, 289.9, 785.8, 278.9, 785.5, 278.9, 785.9, 267.8, 786.2, 257.8, +786.0, 257.7, 786.5, 247.7, 676.3, 753.6, 671.8, 742.5, 671.8, 742.5, +667.3, 731.5, 674.1, 728.5, 672.6, 714.6, 669.6, 699.4, 675.1, 699.1, +675.1, 699.1, 680.6, 698.7, 684.3, 705.4, 679.9, 707.8, 679.2, 716.9, +679.2, 717.0, 679.2, 717.0, 679.2, 717.0, 677.7, 735.3, 685.8, 742.0, +676.3, 753.6, 610.9, 789.2, 610.9, 794.7, 610.9, 794.7, 610.8, 800.2, +578.6, 798.2, 577.5, 812.9, 544.4, 826.1, 542.7, 819.2, 538.9, 813.6, +540.9, 812.3, 553.8, 796.7, 553.8, 796.7, 566.7, 781.1, 585.5, 775.0, +590.8, 780.5, 610.9, 789.2, 566.7, 781.1, 568.6, 778.9, 568.1, 777.6, +570.5, 776.6, 573.6, 774.5, 574.2, 774.0, 575.5, 770.6, 580.5, 767.1, +579.5, 765.7, 583.5, 760.9, 593.4, 768.6, 605.2, 773.4, 608.7, 769.4, +609.9, 774.1, 611.9, 774.5, 611.0, 778.7, 611.0, 784.0, 611.0, 784.0, +610.9, 789.2, 590.8, 780.5, 585.5, 775.0, 566.7, 781.1, 614.4, 737.3, +615.2, 732.7, 614.4, 728.3, 616.0, 728.0, 623.2, 721.6, 623.2, 721.6, +630.4, 715.1, 635.8, 724.6, 638.9, 722.8, 647.5, 730.5, 654.3, 736.0, +653.9, 736.5, 660.3, 742.5, 638.8, 746.9, 635.9, 744.3, 614.4, 737.3, +547.6, 495.4, 547.6, 497.4, 547.6, 497.4, 547.5, 499.4, 539.3, 505.1, +539.5, 505.4, 531.4, 511.3, 537.2, 509.1, 536.2, 506.6, 541.1, 501.8, +544.4, 498.6, 543.7, 496.9, 547.6, 495.4, 446.0, 761.1, 439.5, 772.2, +430.7, 774.5, 433.0, 783.4, 430.1, 779.9, 428.0, 780.3, 427.3, 776.5, +424.8, 770.6, 423.1, 771.4, 418.9, 766.3, 419.8, 761.8, 418.5, 760.1, +415.4, 756.3, 416.7, 749.7, 416.7, 749.7, 418.1, 743.1, 425.6, 720.3, +423.6, 719.7, 429.2, 696.3, 429.0, 698.0, 432.6, 698.4, 436.1, 700.5, +443.7, 730.1, 447.1, 731.0, 446.0, 761.1, 436.1, 700.5, 446.3, 706.8, +453.4, 715.7, 456.6, 713.1, 455.4, 730.0, 450.4, 731.2, 454.2, 746.8, +450.1, 753.9, 450.1, 753.9, 446.0, 761.1, 447.1, 731.0, 443.7, 730.1, +436.1, 700.5, 278.2, 646.7, 287.9, 636.3, 292.4, 638.3, 297.7, 626.0, +296.9, 623.2, 301.6, 621.9, 305.5, 617.8, 306.8, 623.1, 310.2, 622.3, +314.9, 626.8, 306.5, 633.0, 310.6, 638.5, 306.4, 650.2, 296.2, 655.7, +280.3, 652.7, 278.2, 646.7, 306.4, 650.2, 303.8, 657.3, 306.3, 660.7, +301.1, 664.5, 292.3, 675.0, 292.3, 675.0, 283.5, 685.5, 283.1, 681.8, +271.8, 679.0, 261.0, 680.4, 260.8, 672.8, 260.8, 672.8, 260.5, 665.3, +270.6, 657.7, 269.3, 656.0, 278.2, 646.7, 280.3, 652.7, 296.2, 655.7, +306.4, 650.2, 292.8, 485.6, 301.1, 504.9, 301.1, 504.9, 309.5, 524.1, +287.9, 535.6, 276.9, 540.3, 273.8, 561.0, 268.3, 566.7, 268.3, 566.7, +262.7, 572.5, 261.5, 573.7, 260.9, 573.4, 260.4, 574.9, 275.9, 530.0, +262.6, 516.8, 292.8, 485.6, 260.4, 574.9, 259.7, 576.6, 257.4, 577.3, +257.6, 577.7, 257.5, 573.8, 257.5, 573.8, 257.4, 569.9, 265.0, 528.4, +263.9, 528.2, 270.4, 486.5, 274.7, 473.3, 274.2, 473.1, 277.5, 459.5, +278.2, 460.2, 279.1, 460.5, 279.0, 460.9, 278.9, 461.2, 279.3, 461.5, +279.8, 461.8, 282.5, 463.1, 282.0, 463.9, 284.3, 466.1, 284.9, 476.1, +288.5, 475.9, 292.8, 485.6, 262.6, 516.8, 275.9, 530.0, 260.4, 574.9, +298.6, 576.2, 296.3, 581.2, 297.6, 585.1, 294.0, 586.2, 282.3, 599.0, +273.7, 609.2, 278.9, 619.5, 274.8, 624.9, 276.0, 625.8, 273.1, 632.1, +273.2, 635.0, 262.0, 633.2, 259.6, 638.3, 259.6, 636.7, 259.7, 636.7, +259.5, 635.1, 272.9, 617.1, 258.6, 606.4, 257.6, 577.7, 257.4, 577.3, +259.7, 576.6, 260.4, 574.9, 260.9, 573.4, 261.5, 573.7, 262.7, 572.5, +280.7, 573.1, 282.9, 569.3, 298.6, 576.2, 262.7, 572.5, 268.3, 566.7, +268.3, 566.7, 273.8, 561.0, 273.8, 561.4, 292.8, 571.7, 303.2, 566.1, +300.9, 571.2, 300.9, 571.2, 298.6, 576.2, 282.9, 569.3, 280.7, 573.1, +262.7, 572.5, 337.7, 440.2, 347.8, 446.7, 346.9, 448.6, 357.8, 453.2, +357.2, 457.1, 357.2, 457.1, 356.6, 461.0, 347.1, 462.7, 342.5, 471.0, +340.7, 482.8, 332.3, 484.2, 332.3, 484.2, 323.8, 485.7, 322.2, 463.5, +322.7, 454.5, 337.7, 440.2, 323.8, 485.7, 322.6, 485.9, 322.1, 486.6, +321.3, 486.1, 314.9, 482.3, 314.9, 482.3, 308.5, 478.6, 316.2, 449.0, +300.8, 444.9, 293.0, 411.3, 314.6, 426.8, 315.4, 425.7, 337.7, 440.2, +322.7, 454.5, 322.2, 463.5, 323.8, 485.7, 785.9, 267.8, 785.5, 278.9, +785.8, 278.9, 785.1, 289.9, 784.5, 302.9, 783.8, 302.9, 784.0, 315.9, +778.8, 309.5, 775.2, 302.3, 773.6, 303.1, 773.7, 303.0, 773.5, 302.8, +773.3, 302.8, 771.1, 303.5, 770.3, 294.4, 764.8, 292.2, 766.2, 271.9, +747.4, 270.5, 729.9, 248.9, 734.7, 250.8, 735.8, 247.9, 741.7, 247.0, +764.7, 254.7, 769.5, 251.6, 785.9, 267.8, 741.7, 247.0, 756.5, 244.5, +765.5, 235.9, 771.3, 242.0, 776.7, 243.5, 778.4, 241.6, 782.1, 244.9, +784.3, 246.3, 784.3, 246.3, 786.5, 247.7, 786.0, 257.7, 786.2, 257.8, +785.9, 267.8, 769.5, 251.6, 764.7, 254.7, 741.7, 247.0, 630.0, 617.0, +628.7, 597.0, 628.7, 597.0, 627.3, 576.9, 629.8, 570.0, 629.6, 569.9, +631.9, 562.9, 633.7, 589.8, 638.1, 592.3, 630.0, 617.0, 673.4, 583.9, +681.1, 606.5, 673.2, 615.5, 688.7, 629.0, 686.2, 637.8, 686.2, 637.8, +683.7, 646.7, 673.6, 617.0, 665.6, 611.6, 673.4, 583.9, 678.1, 758.1, +677.2, 755.8, 677.2, 755.8, 676.3, 753.6, 685.8, 742.0, 677.7, 735.3, +679.2, 717.0, 670.4, 723.5, 678.7, 734.6, 678.3, 752.1, 678.2, 755.1, +679.6, 757.0, 678.1, 758.1, 614.2, 738.3, 614.3, 737.8, 614.3, 737.8, +614.4, 737.3, 635.9, 744.3, 638.8, 746.9, 660.3, 742.5, 662.5, 744.5, +662.4, 744.7, 664.7, 746.6, 667.7, 750.4, 667.7, 750.4, 670.7, 754.2, +659.6, 770.2, 661.4, 771.4, 652.0, 788.7, 627.9, 781.9, 632.9, 763.7, +614.2, 738.3, 652.0, 788.7, 644.6, 802.4, 641.6, 801.5, 637.1, 816.1, +624.2, 786.6, 629.3, 783.0, 611.2, 757.1, 611.2, 757.0, 611.2, 757.0, +611.1, 756.9, 613.5, 756.7, 612.7, 747.6, 614.2, 738.3, 632.9, 763.7, +627.9, 781.9, 652.0, 788.7, 541.1, 501.8, 536.2, 506.6, 537.2, 509.1, +531.4, 511.3, 521.8, 518.4, 518.9, 516.3, 512.1, 525.5, 508.3, 514.0, +508.3, 514.0, 504.5, 502.6, 509.2, 496.3, 517.1, 502.3, 529.8, 502.0, +535.4, 501.9, 540.9, 501.0, 541.1, 501.8, 235.2, 769.2, 234.5, 762.4, +236.8, 761.2, 233.8, 755.6, 235.0, 751.5, 233.8, 748.3, 236.2, 747.4, +237.6, 746.0, 237.6, 746.0, 239.0, 744.7, 238.4, 757.0, 240.3, 758.5, +235.2, 769.2, 238.0, 796.2, 237.4, 790.6, 237.4, 790.6, 236.8, 784.9, +241.5, 774.8, 244.1, 776.0, 251.5, 767.1, 255.0, 762.8, 255.0, 762.8, +258.5, 758.5, 296.1, 712.6, 296.1, 712.7, 333.7, 666.8, 334.2, 666.2, +334.6, 665.6, 334.6, 665.6, 334.6, 665.6, 334.2, 666.2, 333.7, 666.8, +306.0, 704.2, 306.0, 704.2, 278.3, 741.7, 270.2, 752.7, 270.2, 752.7, +262.0, 763.8, 250.0, 780.0, 253.0, 783.6, 238.0, 796.2, 660.5, 548.2, +660.2, 549.1, 661.6, 549.4, 662.2, 550.8, 665.4, 554.2, 663.8, 555.6, +665.5, 560.5, 664.0, 575.9, 661.9, 575.7, 658.3, 591.0, 652.1, 617.1, +652.1, 617.1, 646.0, 643.2, 642.8, 656.7, 646.9, 659.5, 639.6, 670.2, +636.4, 666.3, 632.8, 666.0, 633.1, 662.4, 632.6, 653.6, 632.5, 653.6, +631.9, 644.9, 643.7, 595.9, 645.0, 596.2, 660.5, 548.2, 631.9, 644.9, +631.0, 631.0, 631.0, 631.0, 630.0, 617.0, 638.1, 592.3, 633.7, 589.8, +631.9, 562.9, 635.4, 552.2, 632.2, 549.5, 639.0, 541.4, 640.7, 537.4, +643.4, 536.7, 642.5, 533.4, 649.4, 537.5, 656.1, 537.2, 656.3, 541.6, +659.1, 543.9, 661.1, 545.5, 660.5, 548.2, 645.0, 596.2, 643.7, 595.9, +631.9, 644.9, 655.4, 689.2, 647.5, 679.7, 647.5, 679.7, 639.6, 670.2, +646.9, 659.5, 642.8, 656.7, 646.0, 643.2, 659.2, 659.2, 660.3, 668.5, +655.4, 689.2, 679.2, 716.9, 679.9, 707.8, 684.3, 705.4, 680.6, 698.7, +692.3, 698.0, 692.5, 699.2, 703.9, 697.2, 710.1, 708.1, 710.1, 708.1, +716.3, 718.9, 705.5, 727.6, 697.8, 717.9, 679.2, 716.9, 679.2, 717.0, +679.2, 717.0, 679.2, 717.0, 679.2, 717.0, 679.2, 717.0, 679.2, 716.9, +679.2, 717.0, 679.2, 717.0, 679.2, 717.0, 679.2, 717.0, 679.2, 717.0, +679.2, 716.9, 541.9, 459.0, 544.5, 467.9, 544.5, 467.9, 547.0, 476.8, +546.9, 481.5, 546.7, 481.7, 547.9, 486.2, 547.8, 490.8, 547.8, 490.8, +547.6, 495.4, 543.7, 496.9, 544.4, 498.6, 541.1, 501.8, 540.9, 501.0, +535.4, 501.9, 529.8, 502.0, 530.2, 480.4, 530.0, 476.5, 541.9, 459.0, +529.8, 502.0, 517.1, 502.3, 509.2, 496.3, 504.5, 502.6, 501.4, 493.6, +495.6, 487.0, 498.4, 484.5, 499.7, 482.2, 499.7, 482.2, 501.0, 479.8, +499.2, 474.1, 511.1, 470.5, 521.2, 461.3, 520.4, 458.7, 531.8, 457.4, +539.5, 450.4, 540.7, 454.7, 540.7, 454.7, 541.9, 459.0, 530.0, 476.5, +530.2, 480.4, 529.8, 502.0, 251.5, 767.1, 244.1, 776.0, 241.5, 774.8, +236.8, 784.9, 236.2, 779.1, 236.2, 779.1, 235.6, 773.3, 240.3, 767.5, +251.7, 769.3, 251.5, 767.1, 658.3, 591.0, 661.9, 575.7, 664.0, 575.9, +665.5, 560.5, 669.5, 572.2, 669.5, 572.2, 673.4, 583.9, 665.6, 611.6, +673.6, 617.0, 683.7, 646.7, 680.8, 656.7, 683.9, 659.1, 678.0, 666.8, +674.1, 673.6, 674.1, 673.6, 670.2, 680.4, 659.0, 637.1, 660.1, 635.9, +658.3, 591.0, 670.2, 680.4, 665.7, 688.3, 664.7, 687.9, 661.2, 696.3, +658.3, 692.8, 658.3, 692.8, 655.4, 689.2, 660.3, 668.5, 659.2, 659.2, +646.0, 643.2, 652.1, 617.1, 652.1, 617.1, 658.3, 591.0, 660.1, 635.9, +659.0, 637.1, 670.2, 680.4, 713.4, 763.0, 709.0, 767.6, 709.6, 768.3, +704.6, 772.1, 704.0, 772.6, 704.1, 772.7, 703.6, 773.3, 698.9, 778.5, +698.7, 778.3, 693.8, 783.4, 694.9, 781.9, 689.7, 778.1, 685.5, 772.8, +680.8, 769.9, 682.5, 767.1, 679.5, 761.5, 678.6, 759.8, 678.8, 759.8, +678.1, 758.1, 679.6, 757.0, 678.2, 755.1, 678.3, 752.1, 696.3, 754.7, +699.7, 752.5, 713.4, 763.0, 284.9, 700.5, 315.7, 670.8, 315.7, 670.8, +346.4, 641.2, 344.6, 644.3, 346.8, 645.6, 347.1, 650.0, 347.1, 650.3, +347.0, 650.3, 346.9, 650.6, 345.3, 652.8, 345.2, 652.7, 343.5, 654.8, +339.0, 660.2, 339.0, 660.2, 334.6, 665.6, 296.6, 712.0, 305.8, 725.3, +258.5, 758.5, 281.0, 742.7, 266.3, 725.4, 284.9, 700.5, 258.5, 758.5, +255.0, 762.8, 255.0, 762.8, 251.5, 767.1, 251.7, 769.3, 240.3, 767.5, +235.6, 773.3, 235.4, 771.3, 235.4, 771.3, 235.2, 769.2, 240.3, 758.5, +238.4, 757.0, 239.0, 744.7, 262.0, 722.6, 262.0, 722.6, 284.9, 700.5, +266.3, 725.4, 281.0, 742.7, 258.5, 758.5, 262.0, 763.8, 270.2, 752.7, +270.2, 752.7, 278.3, 741.7, 282.8, 773.8, 273.3, 775.1, 268.2, 808.5, +264.9, 830.4, 264.9, 830.4, 261.6, 852.3, 261.6, 852.8, 261.7, 852.9, +261.5, 853.3, 260.7, 854.9, 259.4, 855.5, 259.8, 856.5, 255.4, 849.5, +255.4, 849.5, 251.0, 842.4, 251.9, 803.0, 251.7, 801.8, 262.0, 763.8, +251.0, 842.4, 247.3, 836.7, 244.0, 836.8, 243.7, 830.9, 241.5, 818.6, +234.4, 814.0, 239.4, 806.4, 240.0, 804.4, 239.0, 804.0, 238.5, 801.7, +238.0, 799.0, 238.3, 799.0, 238.0, 796.2, 253.0, 783.6, 250.0, 780.0, +262.0, 763.8, 251.7, 801.8, 251.9, 803.0, 251.0, 842.4, 719.8, 756.4, +716.6, 759.7, 716.6, 759.7, 713.4, 763.0, 699.7, 752.5, 696.3, 754.7, +678.3, 752.1, 678.7, 734.6, 670.4, 723.5, 679.2, 717.0, 679.2, 717.0, +679.2, 717.0, 679.2, 716.9, 697.8, 717.9, 705.5, 727.6, 716.3, 718.9, +717.3, 720.6, 717.3, 720.6, 718.2, 722.2, 719.8, 739.2, 721.7, 739.6, +719.8, 756.4, 718.2, 722.2, 724.7, 733.4, 721.4, 738.3, 731.1, 744.7, +725.4, 750.5, 725.4, 750.5, 719.8, 756.4, 721.7, 739.6, 719.8, 739.2, +718.2, 722.2, 333.7, 666.8, 334.2, 666.2, 334.6, 665.6, 334.6, 665.6, +339.0, 660.2, 339.0, 660.2, 343.5, 654.8, 342.0, 665.7, 338.4, 665.2, +333.3, 675.6, 324.0, 694.6, 315.7, 694.2, 314.7, 713.7, 315.9, 689.8, +324.0, 690.2, 333.7, 666.8, 314.7, 713.7, 292.5, 761.6, 305.7, 779.6, +268.2, 808.5, 273.3, 775.1, 282.8, 773.8, 278.3, 741.7, 306.0, 704.2, +306.0, 704.2, 333.7, 666.8, 324.0, 690.2, 315.9, 689.8, 314.7, 713.7, +333.3, 675.6, 338.4, 665.2, 342.0, 665.7, 343.5, 654.8, 345.2, 652.7, +345.3, 652.8, 346.9, 650.6, 335.4, 692.2, 334.6, 692.0, 324.0, 733.9, +298.0, 795.3, 292.6, 793.0, 261.6, 852.3, 261.6, 852.8, 261.7, 852.9, +261.5, 853.3, 261.7, 852.9, 261.6, 852.8, 261.6, 852.3, 297.4, 763.9, +296.8, 763.7, 333.3, 675.6, 261.6, 852.3, 264.9, 830.4, 264.9, 830.4, +268.2, 808.5, 305.7, 779.6, 292.5, 761.6, 314.7, 713.7, 315.7, 694.2, +324.0, 694.6, 333.3, 675.6, 296.8, 763.7, 297.4, 763.9, 261.6, 852.3 +}; diff --git a/local/recipes/libs/cairo/source/perf/micro/paint-with-alpha.c b/local/recipes/libs/cairo/source/perf/micro/paint-with-alpha.c new file mode 100644 index 0000000000..047e35c433 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/paint-with-alpha.c @@ -0,0 +1,59 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-perf.h" + +static cairo_time_t +do_paint_with_alpha (cairo_t *cr, int width, int height, int loops) +{ + cairo_perf_timer_start (); + + while (loops--) + cairo_paint_with_alpha (cr, 0.5); + + cairo_perf_timer_stop (); + + return cairo_perf_timer_elapsed (); +} + +static double +count_paint_with_alpha (cairo_t *cr, int width, int height) +{ + return width * height / 1e6; /* Mpix/s */ +} + +cairo_bool_t +paint_with_alpha_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "paint-with-alpha", NULL); +} + +void +paint_with_alpha (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_perf_cover_sources_and_operators (perf, "paint-with-alpha", + do_paint_with_alpha, + count_paint_with_alpha); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/paint.c b/local/recipes/libs/cairo/source/perf/micro/paint.c new file mode 100644 index 0000000000..2a59a45e09 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/paint.c @@ -0,0 +1,57 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-perf.h" + +static cairo_time_t +do_paint (cairo_t *cr, int width, int height, int loops) +{ + cairo_perf_timer_start (); + + while (loops--) + cairo_paint (cr); + + cairo_perf_timer_stop (); + + return cairo_perf_timer_elapsed (); +} + +static double +count_paint (cairo_t *cr, int width, int height) +{ + return width * height / 1e6; /* Mpix/s */ +} + +cairo_bool_t +paint_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "paint", NULL); +} + +void +paint (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_perf_cover_sources_and_operators (perf, "paint", do_paint, count_paint); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/pattern_create_radial.c b/local/recipes/libs/cairo/source/perf/micro/pattern_create_radial.c new file mode 100644 index 0000000000..3915efb9a2 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/pattern_create_radial.c @@ -0,0 +1,106 @@ +/* + * Copyright © 2006 Dan Amelang + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * the authors not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. The authors make no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Dan Amelang + * + * This test was originally created to test _cairo_fixed_from_double. + * cairo_pattern_create_radial was selected as the entry point into + * cairo as it makes several calls to _cairo_fixed_from_double and + * presents a somewhat realistic use-case (although the RADIALS_COUNT + * isn't very realistic). + */ +#include "cairo-perf.h" +#include + +#define RADIALS_COUNT (10000) + +static struct +{ + double cx0; + double cy0; + double radius0; + double cx1; + double cy1; + double radius1; +} radials[RADIALS_COUNT]; + +static double +generate_double_in_range (double min, double max) +{ + double d; + + d = rand () / (double) RAND_MAX; + d *= max - min; + d += min; + + return d; +} + +static cairo_time_t +do_pattern_create_radial (cairo_t *cr, int width, int height, int loops) +{ + cairo_perf_timer_start (); + + while (loops--) { + cairo_pattern_t *pattern; + int i; + + for (i = 0; i < RADIALS_COUNT; i++) { + pattern = + cairo_pattern_create_radial (radials[i].cx0, radials[i].cy0, + radials[i].radius0, + radials[i].cx1, radials[i].cy1, + radials[i].radius1); + cairo_pattern_destroy (pattern); + } + } + + cairo_perf_timer_stop (); + + return cairo_perf_timer_elapsed (); +} + +cairo_bool_t +pattern_create_radial_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "pattern-create-radial", NULL); +} + +void +pattern_create_radial (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + int i; + + srand (time (0)); + for (i = 0; i < RADIALS_COUNT; i++) + { + radials[i].cx0 = generate_double_in_range (-50000.0, 50000.0); + radials[i].cy0 = generate_double_in_range (-50000.0, 50000.0); + radials[i].radius0 = generate_double_in_range (0.0, 1000.0); + radials[i].cx1 = generate_double_in_range (-50000.0, 50000.0); + radials[i].cy1 = generate_double_in_range (-50000.0, 50000.0); + radials[i].radius1 = generate_double_in_range (0.0, 1000.0); + } + + cairo_perf_run (perf, "pattern-create-radial", + do_pattern_create_radial, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/pixel.c b/local/recipes/libs/cairo/source/perf/micro/pixel.c new file mode 100644 index 0000000000..85a42e4427 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/pixel.c @@ -0,0 +1,239 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +/* Measure the overhead in setting a single pixel */ + +#include "cairo-perf.h" + +#include + +static cairo_time_t +pixel_direct (cairo_t *cr, int width, int height, int loops) +{ + cairo_surface_t *surface, *image; + uint32_t *data; + int stride, bpp; + + surface = cairo_get_target (cr); + image = cairo_surface_map_to_image (surface, NULL); + data = (uint32_t *) cairo_image_surface_get_data (image); + stride = cairo_image_surface_get_stride (image) / sizeof (uint32_t); + + switch (cairo_image_surface_get_format (image)) { + default: + case CAIRO_FORMAT_INVALID: + case CAIRO_FORMAT_A1: bpp = 0; break; + case CAIRO_FORMAT_A8: bpp = 8; break; + case CAIRO_FORMAT_RGB16_565: bpp = 16; break; + case CAIRO_FORMAT_RGB24: + case CAIRO_FORMAT_RGB30: + case CAIRO_FORMAT_ARGB32: bpp = 32; break; + case CAIRO_FORMAT_RGB96F: bpp = 96; break; + case CAIRO_FORMAT_RGBA128F: bpp = 128; break; + } + + cairo_perf_timer_start (); + + while (loops--) + pixman_fill (data, stride, bpp, 0, 0, 1, 1, -1); + + cairo_perf_timer_stop (); + + cairo_surface_unmap_image (surface, image); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +pixel_paint (cairo_t *cr, int width, int height, int loops) +{ + cairo_perf_timer_start (); + + while (loops--) + cairo_paint (cr); + + cairo_perf_timer_stop (); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +pixel_mask (cairo_t *cr, int width, int height, int loops) +{ + cairo_surface_t *mask; + cairo_t *cr2; + + mask = cairo_surface_create_similar (cairo_get_target (cr), + CAIRO_CONTENT_ALPHA, + 1, 1); + cr2 = cairo_create (mask); + cairo_set_source_rgb (cr2, 1,1,1); + cairo_paint (cr2); + cairo_destroy (cr2); + + cairo_perf_timer_start (); + + while (loops--) + cairo_mask_surface (cr, mask, 0, 0); + + cairo_perf_timer_stop (); + + cairo_surface_destroy (mask); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +pixel_rectangle (cairo_t *cr, int width, int height, int loops) +{ + cairo_new_path (cr); + cairo_rectangle (cr, 0, 0, 1, 1); + + cairo_perf_timer_start (); + + while (loops--) + cairo_fill_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +pixel_subrectangle (cairo_t *cr, int width, int height, int loops) +{ + cairo_new_path (cr); + cairo_rectangle (cr, 0.1, 0.1, .8, .8); + + cairo_perf_timer_start (); + + while (loops--) + cairo_fill_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +pixel_triangle (cairo_t *cr, int width, int height, int loops) +{ + cairo_new_path (cr); + cairo_move_to (cr, 0, 0); + cairo_line_to (cr, 1, 1); + cairo_line_to (cr, 0, 1); + + cairo_perf_timer_start (); + + while (loops--) + cairo_fill_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +pixel_circle (cairo_t *cr, int width, int height, int loops) +{ + cairo_new_path (cr); + cairo_arc (cr, 0.5, 0.5, 0.5, 0, 2 * M_PI); + + cairo_perf_timer_start (); + + while (loops--) + cairo_fill_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +pixel_stroke (cairo_t *cr, int width, int height, int loops) +{ + cairo_set_line_width (cr, 1.); + cairo_new_path (cr); + cairo_move_to (cr, 0, 0.5); + cairo_line_to (cr, 1, 0.5); + + cairo_perf_timer_start (); + + while (loops--) + cairo_stroke_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + return cairo_perf_timer_elapsed (); +} + +cairo_bool_t +pixel_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "pixel", NULL); +} + +void +pixel (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1., 1., 1.); + + cairo_perf_run (perf, "pixel-direct", pixel_direct, NULL); + cairo_perf_run (perf, "pixel-paint", pixel_paint, NULL); + cairo_perf_run (perf, "pixel-mask", pixel_mask, NULL); + cairo_perf_run (perf, "pixel-rectangle", pixel_rectangle, NULL); + cairo_perf_run (perf, "pixel-subrectangle", pixel_subrectangle, NULL); + cairo_perf_run (perf, "pixel-triangle", pixel_triangle, NULL); + cairo_perf_run (perf, "pixel-circle", pixel_circle, NULL); + cairo_perf_run (perf, "pixel-stroke", pixel_stroke, NULL); +} + +cairo_bool_t +a1_pixel_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "a1-pixel", NULL); +} + +void +a1_pixel (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1., 1., 1.); + cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); + + cairo_perf_run (perf, "a1-pixel-direct", pixel_direct, NULL); + cairo_perf_run (perf, "a1-pixel-paint", pixel_paint, NULL); + cairo_perf_run (perf, "a1-pixel-mask", pixel_mask, NULL); + cairo_perf_run (perf, "a1-pixel-rectangle", pixel_rectangle, NULL); + cairo_perf_run (perf, "a1-pixel-subrectangle", pixel_subrectangle, NULL); + cairo_perf_run (perf, "a1-pixel-triangle", pixel_triangle, NULL); + cairo_perf_run (perf, "a1-pixel-circle", pixel_circle, NULL); + cairo_perf_run (perf, "a1-pixel-stroke", pixel_stroke, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/pythagoras-tree.c b/local/recipes/libs/cairo/source/perf/micro/pythagoras-tree.c new file mode 100644 index 0000000000..9d3ca1155a --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/pythagoras-tree.c @@ -0,0 +1,95 @@ +/* + * Copyright © 2007 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-perf.h" +#define _USE_MATH_DEFINES /* for M_SQRT2 on win32 */ +#include + +static void +add_rectangle (cairo_t *cr, double size) +{ + double x, y; + + if (size < 1) + return; + + cairo_get_current_point (cr, &x, &y); + + cairo_rel_move_to (cr, -size/2., -size/2.); + cairo_rel_line_to (cr, size, 0); + cairo_rel_line_to (cr, 0, size); + cairo_rel_line_to (cr, -size, 0); + cairo_close_path (cr); + + cairo_save (cr); + cairo_translate (cr, -size/2., size); + cairo_move_to (cr, x, y); + cairo_rotate (cr, M_PI/4); + add_rectangle (cr, size / M_SQRT2); + cairo_restore (cr); + + cairo_save (cr); + cairo_translate (cr, size/2., size); + cairo_move_to (cr, x, y); + cairo_rotate (cr, -M_PI/4); + add_rectangle (cr, size / M_SQRT2); + cairo_restore (cr); +} + +static cairo_time_t +do_pythagoras_tree (cairo_t *cr, int width, int height, int loops) +{ + double size = 128; + + cairo_perf_timer_start (); + + while (loops--) { + cairo_save (cr); + cairo_translate (cr, 0, height); + cairo_scale (cr, 1, -1); + + cairo_move_to (cr, width/2, size/2); + add_rectangle (cr, size); + cairo_set_source_rgb (cr, 0., 0., 0.); + cairo_fill (cr); + cairo_restore (cr); + } + + cairo_perf_timer_stop (); + + return cairo_perf_timer_elapsed (); +} + +cairo_bool_t +pythagoras_tree_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "pythagoras-tree", NULL); +} + +void +pythagoras_tree (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_perf_run (perf, "pythagoras-tree", do_pythagoras_tree, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/rectangles.c b/local/recipes/libs/cairo/source/perf/micro/rectangles.c new file mode 100644 index 0000000000..9228a4efa9 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/rectangles.c @@ -0,0 +1,121 @@ +/* + * Copyright © 2006 Dan Amelang + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * the authors not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. The authors make no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Dan Amelang + */ +#include "cairo-perf.h" + +#if 0 +#define MODE cairo_perf_run +#else +#define MODE cairo_perf_cover_sources_and_operators +#endif + +#define RECTANGLE_COUNT (1000) + +static struct { + double x; + double y; + double width; + double height; +} rects[RECTANGLE_COUNT]; + +static cairo_time_t +do_rectangles (cairo_t *cr, int width, int height, int loops) +{ + int i; + + cairo_perf_timer_start (); + + while (loops--) { + for (i = 0; i < RECTANGLE_COUNT; i++) { + cairo_rectangle (cr, rects[i].x, rects[i].y, + rects[i].width, rects[i].height); + cairo_fill (cr); + } + } + + cairo_perf_timer_stop (); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_rectangles_once (cairo_t *cr, int width, int height, int loops) +{ + int i; + + cairo_perf_timer_start (); + + while (loops--) { + for (i = 0; i < RECTANGLE_COUNT; i++) { + cairo_rectangle (cr, rects[i].x, rects[i].y, + rects[i].width, rects[i].height); + } + + cairo_fill (cr); + } + + cairo_perf_timer_stop (); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_rectangle (cairo_t *cr, int width, int height, int loops) +{ + cairo_perf_timer_start (); + + while (loops--) { + cairo_rectangle (cr, 0, 0, width, height); + cairo_fill (cr); + } + + cairo_perf_timer_stop (); + + return cairo_perf_timer_elapsed (); +} + +cairo_bool_t +rectangles_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "rectangles", NULL); +} + +void +rectangles (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + int i; + + srand (8478232); + for (i = 0; i < RECTANGLE_COUNT; i++) + { + rects[i].x = rand () % width; + rects[i].y = rand () % height; + rects[i].width = (rand () % (width / 10)) + 1; + rects[i].height = (rand () % (height / 10)) + 1; + } + + MODE (perf, "one-rectangle", do_rectangle, NULL); + MODE (perf, "rectangles", do_rectangles, NULL); + MODE (perf, "rectangles-once", do_rectangles_once, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/rounded-rectangles.c b/local/recipes/libs/cairo/source/perf/micro/rounded-rectangles.c new file mode 100644 index 0000000000..1e432dd1fa --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/rounded-rectangles.c @@ -0,0 +1,144 @@ +/* + * Copyright © 2005 Owen Taylor + * Copyright © 2007 Dan Amelang + * Copyright © 2007 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * the authors not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. The authors make no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Chris Wilson + */ + +/* This perf case is derived from the bug report + * Gradient on 'rounded rectangle' MUCH slower than normal rectangle + * https://bugs.freedesktop.org/show_bug.cgi?id=4263. + */ + +#include "cairo-perf.h" + +#define RECTANGLE_COUNT (1000) + +#if 0 +#define MODE cairo_perf_run +#else +#define MODE cairo_perf_cover_sources_and_operators +#endif + +static struct +{ + double x; + double y; + double width; + double height; +} rects[RECTANGLE_COUNT]; + +static void +rounded_rectangle (cairo_t *cr, + double x, double y, double w, double h, + double radius) +{ + cairo_move_to (cr, x+radius, y); + cairo_arc (cr, x+w-radius, y+radius, radius, M_PI + M_PI / 2, M_PI * 2 ); + cairo_arc (cr, x+w-radius, y+h-radius, radius, 0, M_PI / 2 ); + cairo_arc (cr, x+radius, y+h-radius, radius, M_PI/2, M_PI ); + cairo_arc (cr, x+radius, y+radius, radius, M_PI, 270 * M_PI / 180); +} + +static cairo_time_t +do_rectangle (cairo_t *cr, int width, int height, int loops) +{ + cairo_perf_timer_start (); + + while (loops--) { + rounded_rectangle (cr, 0, 0, width, height, 3.0); + cairo_fill (cr); + } + + cairo_perf_timer_stop (); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_rectangles (cairo_t *cr, int width, int height, int loops) +{ + int i; + + cairo_perf_timer_start (); + + while (loops--) { + for (i = 0; i < RECTANGLE_COUNT; i++) { + rounded_rectangle (cr, + rects[i].x, rects[i].y, + rects[i].width, rects[i].height, + 3.0); + cairo_fill (cr); + } + } + + cairo_perf_timer_stop (); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_rectangles_once (cairo_t *cr, int width, int height, int loops) +{ + int i; + + cairo_perf_timer_start (); + + while (loops--) { + for (i = 0; i < RECTANGLE_COUNT; i++) { + rounded_rectangle (cr, + rects[i].x, rects[i].y, + rects[i].width, rects[i].height, + 3.0); + } + cairo_fill (cr); + } + + cairo_perf_timer_stop (); + + return cairo_perf_timer_elapsed (); +} + +cairo_bool_t +rounded_rectangles_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "rounded-rectangles", NULL); +} + +void +rounded_rectangles (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + int i; + + srand (8478232); + for (i = 0; i < RECTANGLE_COUNT; i++) { + rects[i].x = rand () % width; + rects[i].y = rand () % height; + rects[i].width = (rand () % (width / 10)) + 1; + rects[i].height = (rand () % (height / 10)) + 1; + } + + MODE (perf, "one-rounded-rectangle", do_rectangle, NULL); + MODE (perf, "rounded-rectangles", do_rectangles, NULL); + MODE (perf, "rounded-rectangles-once", do_rectangles_once, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/sierpinski.c b/local/recipes/libs/cairo/source/perf/micro/sierpinski.c new file mode 100644 index 0000000000..c6f5fadc23 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/sierpinski.c @@ -0,0 +1,94 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-perf.h" + +static const double m_1_sqrt_3 = 0.577359269; + +static void +T (cairo_t *cr, int size) +{ + cairo_move_to (cr, 0, 0); + cairo_line_to (cr, size, 0); + cairo_line_to (cr, size/2, size*m_1_sqrt_3); + + size /= 2; + if (size >= 4) { + T (cr, size); + cairo_save (cr); { + cairo_translate (cr, size, 0); + T (cr, size); + } cairo_restore (cr); + cairo_save (cr); { + cairo_translate (cr, size/2, size*m_1_sqrt_3); + T (cr, size); + } cairo_restore (cr); + } +} + +static cairo_time_t +draw (cairo_t *cr, int width, int height, int loops) +{ + int t_height = height/2; + int t_width = t_height / m_1_sqrt_3; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_set_line_width (cr, 1.); + + cairo_perf_timer_start (); + + while (loops--) { + cairo_save (cr); + T (cr, t_width); + + cairo_translate (cr, 0, height); + cairo_scale (cr, 1, -1); + + T (cr, t_width); + + cairo_stroke (cr); + cairo_restore (cr); + } + + cairo_perf_timer_stop (); + + return cairo_perf_timer_elapsed (); +} + +cairo_bool_t +sierpinski_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "sierpinski", NULL); +} + +void +sierpinski (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_perf_run (perf, "sierpinski", draw, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/spiral.c b/local/recipes/libs/cairo/source/perf/micro/spiral.c new file mode 100644 index 0000000000..5db62b0d79 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/spiral.c @@ -0,0 +1,352 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright (c) 2008 M Joonas Pihlaja + * + * 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. + */ +#include "cairo-perf.h" +#include + +#define MAX_SEGMENTS 2560 + +typedef enum { + PIXALIGN, /* pixel aligned path */ + NONALIGN /* unaligned path. */ +} align_t; + +typedef enum { + RECTCLOSE, /* keeps the path rectilinear */ + DIAGCLOSE /* forces a diagonal */ +} close_t; + +static cairo_time_t +draw_spiral (cairo_t *cr, + cairo_fill_rule_t fill_rule, + align_t align, + close_t close, + int width, int height, int loops) +{ + int i; + int n=0; + double x[MAX_SEGMENTS]; + double y[MAX_SEGMENTS]; + int step = 3; + int side = width < height ? width : height; + + assert(5*(side/step/2+1)+2 < MAX_SEGMENTS); + +#define L(x_,y_) (x[n] = (x_), y[n] = (y_), n++) +#define M(x_,y_) L(x_,y_) +#define v(t) L(x[n-1], y[n-1] + (t)) +#define h(t) L(x[n-1] + (t), y[n-1]) + + switch (align) { + case PIXALIGN: M(0,0); break; + case NONALIGN: M(0.1415926, 0.7182818); break; + } + + while (side >= step && side >= 0) { + v(side); + h(side); + v(-side); + h(-side+step); + v(step); + side -= 2*step; + } + + switch (close) { + case RECTCLOSE: L(x[n-1],y[0]); break; + case DIAGCLOSE: L(x[0],y[0]); break; + } + + assert(n < MAX_SEGMENTS); + + cairo_save (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + cairo_translate (cr, 1, 1); + cairo_set_fill_rule (cr, fill_rule); + cairo_set_source_rgb (cr, 1, 0, 0); + + cairo_new_path (cr); + cairo_move_to (cr, x[0], y[0]); + for (i = 1; i < n; i++) { + cairo_line_to (cr, x[i], y[i]); + } + cairo_close_path (cr); + + cairo_perf_timer_start (); + while (loops--) + cairo_fill_preserve (cr); + cairo_perf_timer_stop (); + + cairo_restore (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +draw_spiral_box (cairo_t *cr, + cairo_fill_rule_t fill_rule, + align_t align, + int width, int height, int loops) +{ + const int step = 3; + int side = (width < height ? width : height) - 2; + + cairo_save (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_set_fill_rule (cr, fill_rule); + cairo_translate (cr, 1, 1); + if (align == NONALIGN) + cairo_translate (cr, 0.1415926, 0.7182818); + + cairo_new_path (cr); + while (side >= step) { + cairo_rectangle (cr, 0, 0, side, side); + cairo_translate (cr, step, step); + side -= 2*step; + } + + cairo_perf_timer_start (); + while (loops--) + cairo_fill_preserve (cr); + cairo_perf_timer_stop (); + + cairo_restore (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +draw_spiral_stroke (cairo_t *cr, + align_t align, + int width, int height, int loops) +{ + const int step = 3; + int side = width < height ? width : height; + + cairo_save (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + cairo_translate (cr, 1, 1); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_set_line_width (cr, 4.); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + + cairo_new_path (cr); + switch (align) { + case PIXALIGN: cairo_move_to (cr, 0,0); break; + case NONALIGN: cairo_move_to (cr, 0.1415926, 0.7182818); break; + } + while (side >= step) { + cairo_rel_line_to (cr, 0, side); + side -= step; + if (side <= 0) + break; + + cairo_rel_line_to (cr, side, 0); + side -= step; + if (side <= 0) + break; + + cairo_rel_line_to (cr, 0, -side); + side -= step; + if (side <= 0) + break; + + cairo_rel_line_to (cr, -side, 0); + side -= step; + if (side <= 0) + break; + } + + cairo_perf_timer_start (); + while (loops--) + cairo_stroke_preserve (cr); + cairo_perf_timer_stop (); + + cairo_restore (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +draw_spiral_eo_pa_re (cairo_t *cr, int width, int height, int loops) +{ + return draw_spiral (cr, + CAIRO_FILL_RULE_EVEN_ODD, + PIXALIGN, + RECTCLOSE, + width, height, loops); +} + +static cairo_time_t +draw_spiral_nz_pa_re (cairo_t *cr, int width, int height, int loops) +{ + return draw_spiral (cr, + CAIRO_FILL_RULE_WINDING, + PIXALIGN, + RECTCLOSE, + width, height, loops); +} + +static cairo_time_t +draw_spiral_eo_na_re (cairo_t *cr, int width, int height, int loops) +{ + return draw_spiral (cr, + CAIRO_FILL_RULE_EVEN_ODD, + NONALIGN, + RECTCLOSE, + width, height, loops); +} + +static cairo_time_t +draw_spiral_nz_na_re (cairo_t *cr, int width, int height, int loops) +{ + return draw_spiral (cr, + CAIRO_FILL_RULE_WINDING, + NONALIGN, + RECTCLOSE, + width, height, loops); +} + +static cairo_time_t +draw_spiral_eo_pa_di (cairo_t *cr, int width, int height, int loops) +{ + return draw_spiral (cr, + CAIRO_FILL_RULE_EVEN_ODD, + PIXALIGN, + DIAGCLOSE, + width, height, loops); +} + +static cairo_time_t +draw_spiral_nz_pa_di (cairo_t *cr, int width, int height, int loops) +{ + return draw_spiral (cr, + CAIRO_FILL_RULE_WINDING, + PIXALIGN, + DIAGCLOSE, + width, height, loops); +} + +static cairo_time_t +draw_spiral_eo_na_di (cairo_t *cr, int width, int height, int loops) +{ + return draw_spiral (cr, + CAIRO_FILL_RULE_EVEN_ODD, + NONALIGN, + DIAGCLOSE, + width, height, loops); +} + +static cairo_time_t +draw_spiral_nz_na_di (cairo_t *cr, int width, int height, int loops) +{ + return draw_spiral (cr, + CAIRO_FILL_RULE_WINDING, + NONALIGN, + DIAGCLOSE, + width, height, loops); +} + +static cairo_time_t +draw_spiral_nz_pa_box (cairo_t *cr, int width, int height, int loops) +{ + return draw_spiral_box (cr, + CAIRO_FILL_RULE_WINDING, PIXALIGN, + width, height, loops); +} + +static cairo_time_t +draw_spiral_nz_na_box (cairo_t *cr, int width, int height, int loops) +{ + return draw_spiral_box (cr, + CAIRO_FILL_RULE_WINDING, NONALIGN, + width, height, loops); +} + + +static cairo_time_t +draw_spiral_eo_pa_box (cairo_t *cr, int width, int height, int loops) +{ + return draw_spiral_box (cr, + CAIRO_FILL_RULE_EVEN_ODD, PIXALIGN, + width, height, loops); +} + +static cairo_time_t +draw_spiral_eo_na_box (cairo_t *cr, int width, int height, int loops) +{ + return draw_spiral_box (cr, + CAIRO_FILL_RULE_EVEN_ODD, NONALIGN, + width, height, loops); +} + +static cairo_time_t +draw_spiral_stroke_pa (cairo_t *cr, int width, int height, int loops) +{ + return draw_spiral_stroke (cr, + PIXALIGN, + width, height, loops); +} + +static cairo_time_t +draw_spiral_stroke_na (cairo_t *cr, int width, int height, int loops) +{ + return draw_spiral_stroke (cr, + NONALIGN, + width, height, loops); +} + +cairo_bool_t +spiral_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "spiral", NULL); +} + +void +spiral (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_perf_run (perf, "spiral-box-nonalign-evenodd-fill", draw_spiral_eo_na_box, NULL); + cairo_perf_run (perf, "spiral-box-nonalign-nonzero-fill", draw_spiral_nz_na_box, NULL); + cairo_perf_run (perf, "spiral-box-pixalign-evenodd-fill", draw_spiral_eo_pa_box, NULL); + cairo_perf_run (perf, "spiral-box-pixalign-nonzero-fill", draw_spiral_nz_pa_box, NULL); + cairo_perf_run (perf, "spiral-diag-nonalign-evenodd-fill", draw_spiral_eo_na_di, NULL); + cairo_perf_run (perf, "spiral-diag-nonalign-nonzero-fill", draw_spiral_nz_na_di, NULL); + cairo_perf_run (perf, "spiral-diag-pixalign-evenodd-fill", draw_spiral_eo_pa_di, NULL); + cairo_perf_run (perf, "spiral-diag-pixalign-nonzero-fill", draw_spiral_nz_pa_di, NULL); + cairo_perf_run (perf, "spiral-rect-nonalign-evenodd-fill", draw_spiral_eo_na_re, NULL); + cairo_perf_run (perf, "spiral-rect-nonalign-nonzero-fill", draw_spiral_nz_na_re, NULL); + cairo_perf_run (perf, "spiral-rect-pixalign-evenodd-fill", draw_spiral_eo_pa_re, NULL); + cairo_perf_run (perf, "spiral-rect-pixalign-nonzero-fill", draw_spiral_nz_pa_re, NULL); + cairo_perf_run (perf, "spiral-nonalign-stroke", draw_spiral_stroke_na, NULL); + cairo_perf_run (perf, "spiral-pixalign-stroke", draw_spiral_stroke_pa, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/stroke.c b/local/recipes/libs/cairo/source/perf/micro/stroke.c new file mode 100644 index 0000000000..4b29547709 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/stroke.c @@ -0,0 +1,100 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-perf.h" + +static cairo_time_t +do_stroke (cairo_t *cr, int width, int height, int loops) +{ + cairo_arc (cr, + width/2.0, height/2.0, + width/3.0, + 0, 2 * M_PI); + cairo_close_path (cr); + + cairo_set_line_width (cr, width/5.0); + + cairo_perf_timer_start (); + + while (loops--) + cairo_stroke_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static void +rounded_rectangle (cairo_t *cr, + double x, double y, double w, double h, + double radius) +{ + cairo_move_to (cr, x+radius, y); + cairo_arc (cr, x+w-radius, y+radius, radius, M_PI + M_PI / 2, M_PI * 2 ); + cairo_arc (cr, x+w-radius, y+h-radius, radius, 0, M_PI / 2 ); + cairo_arc (cr, x+radius, y+h-radius, radius, M_PI/2, M_PI ); + cairo_arc (cr, x+radius, y+radius, radius, M_PI, 270 * M_PI / 180); +} + +static cairo_time_t +do_strokes (cairo_t *cr, int width, int height, int loops) +{ + /* a pair of overlapping rectangles */ + rounded_rectangle (cr, + 2, 2, width/2. + 10, height/2. + 10, + 10); + rounded_rectangle (cr, + width/2. - 10, height/2. - 10, + width/2. - 2, height/2. - 2, + 10); + + cairo_set_line_width (cr, 2.); + + cairo_perf_timer_start (); + + while (loops--) + cairo_stroke_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +cairo_bool_t +stroke_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "stroke", NULL); +} + +void +stroke (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_perf_cover_sources_and_operators (perf, "stroke", do_stroke, NULL); + cairo_perf_cover_sources_and_operators (perf, "strokes", do_strokes, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/subimage_copy.c b/local/recipes/libs/cairo/source/perf/micro/subimage_copy.c new file mode 100644 index 0000000000..e749c062fb --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/subimage_copy.c @@ -0,0 +1,80 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-perf.h" + +/* This case exposes a performance bug found by Christopher "Monty" + * Montgomery in that copying a tiny portion of an image surface to an + * X surface causes the entire image surface to be copied to an + * intermediate surface. + * + * If the performance bug is fixed, then the time this test takes + * should be independent of the source and destination surface sizes. + */ + +static cairo_time_t +do_subimage_copy (cairo_t *cr, int width, int height, int loops) +{ + cairo_rectangle (cr, 2, 2, 4, 4); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + + cairo_perf_timer_start (); + + while (loops--) + cairo_fill_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +cairo_bool_t +subimage_copy_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "subimage-copy", NULL); +} + +void +subimage_copy (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_surface_t *image; + cairo_t *cr2; + + cairo_set_source_rgb (cr, 0, 0, 1); /* blue */ + cairo_paint (cr); + + image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); + cr2 = cairo_create (image); + cairo_set_source_rgb (cr2, 1, 0, 0); /* red */ + cairo_paint (cr2); + cairo_destroy (cr2); + + cairo_set_source_surface (cr, image, 0, 0); + cairo_surface_destroy (image); + + cairo_perf_run (perf, "subimage-copy", do_subimage_copy, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/tessellate.c b/local/recipes/libs/cairo/source/perf/micro/tessellate.c new file mode 100644 index 0000000000..b6277fe635 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/tessellate.c @@ -0,0 +1,181 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-perf.h" + +typedef struct { + double x; + double y; +} point_t; + +point_t points[300] = { + {39.4383,84.0188}, {79.844,78.3099}, {19.7551,91.1647}, {76.823,33.5223}, {55.397,27.7775}, + {62.8871,47.7397}, {51.3401,36.4784}, {91.6195,95.223}, {71.7297,63.5712}, {60.6969,14.1603}, + {24.2887,1.63006}, {80.4177,13.7232}, {40.0944,15.6679}, {10.8809,12.979}, {21.8257,99.8925}, + {83.9112,51.2932}, {29.6032,61.264}, {52.4287,63.7552}, {97.2775,49.3583}, {77.1358,29.2517}, + {76.9914,52.6745}, {89.1529,40.0229}, {35.2458,28.3315}, {91.9026,80.7725}, {94.9327,6.97553}, + {8.60558,52.5995}, {66.3227,19.2214}, {34.8893,89.0233}, {2.0023,6.41713}, {6.30958,45.7702}, + {97.0634,23.828}, {85.092,90.2208}, {53.976,26.6666}, {76.0249,37.5207}, {66.7724,51.2535}, + {3.92803,53.1606}, {93.1835,43.7638}, {72.0952,93.081}, {73.8534,28.4293}, {35.4049,63.9979}, + {16.5974,68.7861}, {88.0075,44.0105}, {33.0337,82.9201}, {89.3372,22.8968}, {68.667,35.036}, + {58.864,95.6468}, {85.8676,65.7304}, {92.397,43.956}, {81.4767,39.8437}, {91.0972,68.4219}, + + {21.5825,48.2491}, {92.0128,95.0252}, {88.1062,14.766}, {43.1953,64.1081}, {28.1059,61.9596}, + {30.7458,78.6002}, {22.6107,44.7034}, {27.6235,18.7533}, {41.6501,55.6444}, {90.6804,16.9607}, + {12.6075,10.3171}, {76.0475,49.5444}, {93.5004,98.4752}, {38.3188,68.4445}, {36.8664,74.9771}, + {23.2262,29.416}, {24.4413,58.4489}, {73.2149,15.239}, {79.347,12.5475}, {74.5071,16.4102}, + {95.0104,7.45298}, {52.1563,5.25293}, {24.0062,17.6211}, {73.2654,79.7798}, {96.7405,65.6564}, + {75.9735,63.9458}, {13.4902,9.34805}, {7.82321,52.021}, {20.4655,6.99064}, {81.9677,46.142}, + {75.5581,57.3319}, {15.7807,5.19388}, {20.4329,99.9994}, {12.5468,88.9956}, {5.40576,99.7799}, + {7.23288,87.054}, {92.3069,0.416161}, {18.0372,59.3892}, {39.169,16.3131}, {81.9695,91.3027}, + {55.2485,35.9095}, {45.2576,57.943}, {9.96401,68.7387}, {75.7294,53.0808}, {99.2228,30.4295}, + {87.7614,57.6971}, {62.891,74.7809}, {74.7803,3.54209}, {92.5377,83.3239}, {83.1038,87.3271}, + + {74.3811,97.9434}, {98.3596,90.3366}, {49.7259,66.688}, {83.0012,16.3968}, {7.69947,88.8949}, + {24.8044,64.9707}, {22.9137,62.948}, {31.6867,70.062}, {23.1428,32.8777}, {63.3072,7.4161}, + {65.1132,22.3656}, {97.1466,51.0686}, {54.6107,28.0042}, {11.3281,71.9269}, {59.254,47.1483}, + {45.0918,94.4318}, {84.7684,33.6351}, {0.323146,43.4513}, {59.8481,34.4943}, {23.3892,83.3243}, + {48.295,67.5476}, {30.4956,48.1936}, {18.2556,71.2087}, {4.08643,62.1823}, {69.5984,41.3984}, + {63.764,67.3936}, {18.4622,34.7116}, {62.7158,60.9106}, {32.8374,73.0729}, {20.2213,74.0438}, + {68.4757,92.0914}, {25.7265,65.313}, {8.76436,53.2441}, {87.7384,26.0497}, {9.37402,68.6125}, + {36.1601,11.1276}, {59.3211,57.6691}, {28.8778,66.6557}, {28.8379,77.5767}, {18.9751,32.9642}, + {0.357857,98.4363}, {33.1479,82.7391}, {43.6497,18.8201}, {91.893,95.8637}, {69.9075,76.4871}, + {68.5786,12.1143}, {77.4273,38.3832}, {91.6273,94.3051}, {20.3548,86.1917}, {54.8042,79.3657}, + + {90.4932,29.7288}, {87.3979,90.9643}, {57.62,49.8144}, {27.3911,16.2757}, {49.2399,86.4579}, + {84.8942,46.3662}, {29.1053,49.5977}, {68.4178,18.0421}, {13.9058,72.755}, {49.2422,60.3109}, + {72.4252,83.8134}, {22.1966,17.8208}, {12.1259,49.8525}, {36.0443,13.8238}, {93.1895,32.4807}, + {62.2095,90.8485}, {81.8128,83.6828}, {33.4972,49.6074}, {65.8831,39.4327}, {25.8906,60.8883}, + {7.2545,15.123}, {64.7207,10.7848}, {28.827,36.3598}, {9.11486,33.1386}, {93.4495,42.7328}, + {26.5461,58.357}, {76.1778,65.8747}, {15.7272,48.7427}, {62.5665,88.3037}, {20.7844,51.7715}, + {42.6199,55.7561}, {39.4388,82.9939}, {32.6013,24.4327}, {63.8654,72.936}, {33.8243,98.4845}, + {13.6075,89.756}, {0.540855,41.0788}, {77.4386,78.3282}, {11.4668,29.3678}, {72.1006,86.5535}, + {44.9105,4.91625}, {70.7909,98.6467}, {47.3894,21.0883}, {9.39195,86.5181}, {38.2896,9.95593}, + {65.712,30.1763}, {13.1702,80.9095}, {5.34223,5.15083}, {78.0868,45.7716}, {44.256,69.2076}, + + {58.9637,11.9111}, {52.9899,57.8635}, {36.1917,59.5045}, {88.8723,30.4285}, {16.982,47.6585}, + {52.5747,60.9729}, {59.6196,61.8925}, {82.9808,23.3656}, {9.88374,7.00902}, {16.965,92.3728}, + {22.5491,48.1733}, {29.0829,82.6769}, {87.8278,35.7193}, {81.4909,34.4251}, {3.63274,65.9146}, + {77.8257,25.7469}, {83.6104,62.5964}, {22.1009,30.8157}, {61.2442,19.8021}, {67.4605,10.9733}, + {71.9462,78.2262}, {40.1188,20.0352}, {43.4009,31.5658}, {38.5748,23.0996}, {15.4724,53.2846}, + {1.45793,55.5398}, {38.2167,38.0215}, {73.7408,30.5408}, {64.9659,26.0445}, {91.9591,55.2316}, + {80.9785,68.5986}, {31.195,69.7848}, {0.600477,64.5889}, {84.391,53.296}, {64.2693,61.8447}, + {40.0709,51.8515}, {71.8867,36.2154}, {67.7812,80.1897}, {3.28927,15.2876}, {68.5722,6.35606}, + {61.8958,18.7616}, {56.7831,70.0301}, {0.570914,0.112548}, {26.157,30.5239}, {85.7555,65.5368}, + {34.1354,18.1161}, {87.9009,66.7341}, {31.323,65.3305}, {18.6265,88.5014}, {50.3461,15.7139}, + + {67.5654,82.8957}, {19.1112,90.417}, {70.6067,39.4521}, {54.7397,86.8924}, {93.2485,73.8959}, + {92.6576,23.3119}, {93.342,55.1443}, {55.2568,49.4407}, {79.9646,93.9129}, {59.4497,81.4139}, + {99.53,65.7201}, {32.4541,93.5852}, {58.9157,87.4309}, {75.9324,63.7771}, {79.491,77.5421}, + {60.4379,26.2785}, {16.6955,47.0564}, {86.5086,79.549}, {66.4414,87.3021}, {61.1981,41.2483}, + {64.5601,59.6899}, {14.8342,53.8557}, {3.29634,57.9022}, {51.8151,70.091}, {51.5049,83.2609}, + {48.981,11.2648}, {4.84997,51.0349}, {38.4658,81.4351}, {45.2122,63.7656}, {41.3078,14.3982}, + {40.6767,24.7033}, {71.7597,1.74566}, {81.2947,57.3721}, {44.6743,58.2682}, {99.5165,47.7361}, + {7.42604,5.87232}, {59.728,64.0766}, {21.9788,22.2602}, {92.3513,63.0243}, {46.2852,73.7939}, + {85.0586,43.8562}, {94.8911,95.2662}, {76.7014,89.9086}, {53.6742,33.3569}, {47.7551,21.9136}, + {46.6169,94.982}, {96.7277,88.4318}, {45.8039,18.3765}, {76.6448,78.0224}, {25.7585,90.4782} +}; + +static cairo_time_t +do_tessellate (cairo_t *cr, int num_points, int loops) +{ + int i; + + for (i=0; i < num_points; i++) + cairo_line_to (cr, points[i].x, points[i].y); + + cairo_perf_timer_start (); + + /* We'd like to measure just tessellation without + * rasterization. For now, we can do that with cairo_in_fill. But + * we'll have to be careful since cairo_in_fill might eventually + * be optimized to have an implementation that doesn't necessarily + * include tessellation. */ + while (loops--) + cairo_in_fill (cr, 50, 50); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +tessellate_16 (cairo_t *cr, int width, int height, int loops) +{ + return do_tessellate (cr, 16, loops); +} + +static cairo_time_t +tessellate_64 (cairo_t *cr, int width, int height, int loops) +{ + return do_tessellate (cr, 64, loops); +} + +static cairo_time_t +tessellate_256 (cairo_t *cr, int width, int height, int loops) +{ + return do_tessellate (cr, 256, loops); +} + +cairo_bool_t +tessellate_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "tessellate", NULL); +} + +void +tessellate (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_perf_run (perf, "tessellate-16", tessellate_16, NULL); + cairo_perf_run (perf, "tessellate-64", tessellate_64, NULL); + cairo_perf_run (perf, "tessellate-256", tessellate_256, NULL); +} + +#if 0 +double +rand_within (double range) +{ + return range * (rand() / (RAND_MAX + 1.0)); +} + +int +main (void) +{ +#define SIZE 100 + int i; + + printf ("point_t points[] = {\n"); + + for (i=0; i < 1000; i++) { + printf (" {%g,%g},", rand_within (SIZE), rand_within (SIZE)); + if (i % 5 == 4) + printf ("\n"); + } + + printf ("};\n"); +} +#endif diff --git a/local/recipes/libs/cairo/source/perf/micro/text.c b/local/recipes/libs/cairo/source/perf/micro/text.c new file mode 100644 index 0000000000..cdb319936d --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/text.c @@ -0,0 +1,69 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-perf.h" + +static cairo_time_t +do_text (cairo_t *cr, int width, int height, int loops) +{ + const char text[] = "the jay, pig, fox, zebra and my wolves quack"; + int len = strlen (text); + double x, y; + int i = 0, j = 0; + + cairo_set_font_size (cr, 9); + + cairo_perf_timer_start (); + + while (loops--) { + do { + cairo_move_to (cr, 0, j++ * 10); + cairo_show_text (cr, text + i); + cairo_get_current_point (cr, &x, &y); + while (x < width && cairo_status (cr) == CAIRO_STATUS_SUCCESS) { + cairo_show_text (cr, text); + cairo_get_current_point (cr, &x, &y); + } + if (++i >= len) + i = 0; + } while (y < height && cairo_status (cr) == CAIRO_STATUS_SUCCESS); + } + + cairo_perf_timer_stop (); + + return cairo_perf_timer_elapsed (); +} + +cairo_bool_t +text_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "text", NULL); +} + +void +text (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_perf_cover_sources_and_operators (perf, "text", do_text, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/tiger.c b/local/recipes/libs/cairo/source/perf/micro/tiger.c new file mode 100644 index 0000000000..9e7a9419af --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/tiger.c @@ -0,0 +1,115 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-perf.h" + +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "../../test/tiger.inc" + +static cairo_time_t +do_tiger (cairo_t *cr, int width, int height, int loops) +{ + unsigned int i; + + cairo_perf_timer_start (); + + while (loops--) { + cairo_identity_matrix (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgba (cr, 0.1, 0.2, 0.3, 1.0); + cairo_paint (cr); + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + + cairo_translate (cr, width/2, height/2); + cairo_scale (cr, .85 * width/500, .85 * height/500); + + for (i = 0; i < sizeof (tiger_commands)/sizeof(tiger_commands[0]);i++) { + const struct command *cmd = &tiger_commands[i]; + switch (cmd->type) { + case 'm': + cairo_move_to (cr, cmd->x0, cmd->y0); + break; + case 'l': + cairo_line_to (cr, cmd->x0, cmd->y0); + break; + case 'c': + cairo_curve_to (cr, + cmd->x0, cmd->y0, + cmd->x1, cmd->y1, + cmd->x2, cmd->y2); + break; + case 'f': + cairo_set_source_rgba (cr, + cmd->x0, cmd->y0, cmd->x1, cmd->y1); + cairo_fill (cr); + break; + } + } + } + + cairo_perf_timer_stop (); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_mono_tiger (cairo_t *cr, int width, int height, int loops) +{ + cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); + return do_tiger (cr, width, height, loops); +} + +static cairo_time_t +do_fast_tiger (cairo_t *cr, int width, int height, int loops) +{ + cairo_set_antialias (cr, CAIRO_ANTIALIAS_FAST); + return do_tiger (cr, width, height, loops); +} + +static cairo_time_t +do_best_tiger (cairo_t *cr, int width, int height, int loops) +{ + cairo_set_antialias (cr, CAIRO_ANTIALIAS_BEST); + return do_tiger (cr, width, height, loops); +} + +cairo_bool_t +tiger_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "tiger", NULL); +} + +void +tiger (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_perf_run (perf, "tiger-mono", do_mono_tiger, NULL); + cairo_perf_run (perf, "tiger-fast", do_fast_tiger, NULL); + cairo_perf_run (perf, "tiger-best", do_best_tiger, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/twin.c b/local/recipes/libs/cairo/source/perf/micro/twin.c new file mode 100644 index 0000000000..99433bd65c --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/twin.c @@ -0,0 +1,59 @@ +#define WIDTH 1350 +#define HEIGHT 900 + +#include "cairo-perf.h" + +static cairo_time_t +do_twin (cairo_t *cr, + int width, + int height, + int loops) +{ + int i, j, h; + unsigned char s[2] = {0, 0}; + + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + + cairo_select_font_face (cr, + "@cairo:", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + + cairo_perf_timer_start (); + + while (loops--) { + h = 2; + for (i = 8; i < 48; i >= 24 ? i+=3 : i++) { + cairo_set_font_size (cr, i); + for (j = 33; j < 128; j++) { + if (j == 33 || (j == 80 && i > 24)) { + h += i + 2; + cairo_move_to (cr, 10, h); + } + s[0] = j; + cairo_text_path (cr, (const char *) s); + } + } + cairo_fill (cr); + } + + cairo_perf_timer_stop (); + return cairo_perf_timer_elapsed (); +} + +cairo_bool_t +twin_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "twin", NULL); +} + +void +twin (cairo_perf_t *perf, + cairo_t *cr, + int width, + int height) +{ + cairo_perf_run (perf, "twin", do_twin, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/unaligned-clip.c b/local/recipes/libs/cairo/source/perf/micro/unaligned-clip.c new file mode 100644 index 0000000000..41e327f1e7 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/unaligned-clip.c @@ -0,0 +1,73 @@ +/* + * Copyright © 2006 Jeff Muizelaar + * Copyright © 2006 Red Hat, Inc. + * + * 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. + * + * Authors: Jeff Muizelaar + * Carl Worth + */ + +#include "cairo-perf.h" + +static cairo_time_t +do_unaligned_clip (cairo_t *cr, int width, int height, int loops) +{ + cairo_perf_timer_start (); + + while (loops--) { + cairo_save (cr); + + /* First a triangular clip that obviously isn't along device-pixel + * boundaries. */ + cairo_move_to (cr, 50, 50); + cairo_line_to (cr, 50, 90); + cairo_line_to (cr, 90, 90); + cairo_close_path (cr); + cairo_clip (cr); + + /* Then a rectangular clip that would be but for the non-integer + * scaling. */ + cairo_scale (cr, 1.1, 1.1); + cairo_rectangle (cr, 55, 55, 35, 35); + cairo_clip (cr); + + /* And paint something to force the clip to be evaluated. */ + cairo_paint (cr); + + cairo_restore (cr); + } + cairo_perf_timer_stop (); + + return cairo_perf_timer_elapsed (); +} + +cairo_bool_t +unaligned_clip_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "unaligned-clip", NULL); +} + +void +unaligned_clip (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_perf_run (perf, "unaligned-clip", do_unaligned_clip, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/wave.c b/local/recipes/libs/cairo/source/perf/micro/wave.c new file mode 100644 index 0000000000..f6e6f74a38 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/wave.c @@ -0,0 +1,115 @@ +/* + * Copyright 2011 Red Hat Inc. + * + * 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: Benjamin Otte + */ + +#include "cairo-perf.h" + +static cairo_surface_t * +generate_random_waveform(cairo_t *target, int width, int height) +{ + cairo_surface_t *surface; + cairo_t *cr; + int i, r; + + srand (0xdeadbeef); + + surface = cairo_surface_create_similar (cairo_get_target (target), + CAIRO_CONTENT_ALPHA, + width, height); + cr = cairo_create (surface); + + r = height / 2; + + for (i = 0; i < width; i++) + { + r += rand () % (height / 4) - (height / 8); + if (r < 0) + r = 0; + else if (r > height) + r = height; + cairo_rectangle (cr, i, (height - r) / 2, 1, r); + } + cairo_fill (cr); + cairo_destroy (cr); + + return surface; +} + +static cairo_time_t +do_wave (cairo_t *cr, int width, int height, int loops) +{ + cairo_surface_t *wave; + cairo_pattern_t *mask; + + wave = generate_random_waveform (cr, width, height); + + cairo_perf_timer_start (); + + while (loops--) { + /* paint outline (and contents) */ + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_mask_surface (cr, wave, 0, 0); + + /* overdraw inline */ + /* first, create a mask */ + cairo_push_group_with_content (cr, CAIRO_CONTENT_ALPHA); + cairo_set_source_surface (cr, wave, 0, 0); + cairo_paint (cr); + cairo_set_operator (cr, CAIRO_OPERATOR_IN); + cairo_set_source_surface (cr, wave, 1, 0); + cairo_paint (cr); + cairo_set_source_surface (cr, wave, -1, 0); + cairo_paint (cr); + cairo_set_source_surface (cr, wave, 0, 1); + cairo_paint (cr); + cairo_set_source_surface (cr, wave, 0, -1); + cairo_paint (cr); + mask = cairo_pop_group (cr); + + /* second, paint the mask */ + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_mask (cr, mask); + + cairo_pattern_destroy (mask); + } + + cairo_perf_timer_stop (); + + cairo_surface_destroy (wave); + + return cairo_perf_timer_elapsed (); +} + +cairo_bool_t +wave_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "wave", NULL); +} + +void +wave (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_perf_run (perf, "wave", do_wave, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/wide-fills.c b/local/recipes/libs/cairo/source/perf/micro/wide-fills.c new file mode 100644 index 0000000000..0747e6e679 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/wide-fills.c @@ -0,0 +1,187 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + + +/* This is a variant on wide strokes where we precompute + * a simplified stroke-to-path. + * When we have a real stroke-to-path, it would useful to compare the cost + * of stroking vs filling the "identical" paths. + */ + +#include "cairo-perf.h" + +static uint32_t state; + +static double +uniform_random (double minval, double maxval) +{ + static uint32_t const poly = 0x9a795537U; + uint32_t n = 32; + while (n-->0) + state = 2*state < state ? (2*state ^ poly) : 2*state; + return minval + state * (maxval - minval) / 4294967296.0; +} + +static cairo_time_t +do_wide_fills_ha (cairo_t *cr, int width, int height, int loops) +{ + int count; + + state = 0xc0ffee; + for (count = 0; count < 1000; count++) { + double y = floor (uniform_random (0, height)); + double x = floor (uniform_random (0, width)); + cairo_rectangle (cr, x, y, ceil (uniform_random (0, width)) - x, 5); + } + + cairo_perf_timer_start (); + + while (loops--) + cairo_fill_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_wide_fills_h (cairo_t *cr, int width, int height, int loops) +{ + int count; + + state = 0xc0ffee; + for (count = 0; count < 1000; count++) { + double y = uniform_random (0, height); + double x = uniform_random (0, width); + cairo_rectangle (cr, x, y, uniform_random (0, width) - x, 5); + } + + cairo_perf_timer_start (); + + while (loops--) + cairo_fill_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_wide_fills_va (cairo_t *cr, int width, int height, int loops) +{ + int count; + + state = 0xc0ffee; + for (count = 0; count < 1000; count++) { + double x = floor (uniform_random (0, width)); + double y = floor (uniform_random (0, height)); + cairo_rectangle (cr, x, y, 5, ceil (uniform_random (0, height) - y)); + } + + cairo_perf_timer_start (); + + while (loops--) + cairo_fill_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_wide_fills_v (cairo_t *cr, int width, int height, int loops) +{ + int count; + + state = 0xc0ffee; + for (count = 0; count < 1000; count++) { + double x = uniform_random (0, width); + double y = uniform_random (0, height); + cairo_rectangle (cr, x, y, 5, uniform_random (0, height) - y); + } + + cairo_perf_timer_start (); + + while (loops--) + cairo_fill_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_wide_fills (cairo_t *cr, int width, int height, int loops) +{ + int count; + + /* lots and lots of overlapping stroke-like fills */ + state = 0xc0ffee; + for (count = 0; count < 1000; count++) { + cairo_save (cr); + cairo_translate (cr, + uniform_random (0, width), + uniform_random (0, height)); + cairo_rotate (cr, uniform_random (-M_PI,M_PI)); + cairo_rectangle (cr, 0, 0, uniform_random (0, width), 5); + cairo_restore (cr); + } + + cairo_perf_timer_start (); + + while (loops--) + cairo_fill_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +cairo_bool_t +wide_fills_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "wide-fills", NULL); +} + +void +wide_fills (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_perf_run (perf, "wide-fills-halign", do_wide_fills_ha, NULL); + cairo_perf_run (perf, "wide-fills-valign", do_wide_fills_va, NULL); + cairo_perf_run (perf, "wide-fills-horizontal", do_wide_fills_h, NULL); + cairo_perf_run (perf, "wide-fills-vertical", do_wide_fills_v, NULL); + cairo_perf_run (perf, "wide-fills-random", do_wide_fills, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/wide-strokes.c b/local/recipes/libs/cairo/source/perf/micro/wide-strokes.c new file mode 100644 index 0000000000..1413091482 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/wide-strokes.c @@ -0,0 +1,188 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-perf.h" + +static uint32_t state; + +static double +uniform_random (double minval, double maxval) +{ + static uint32_t const poly = 0x9a795537U; + uint32_t n = 32; + while (n-->0) + state = 2*state < state ? (2*state ^ poly) : 2*state; + return minval + state * (maxval - minval) / 4294967296.0; +} + +static cairo_time_t +do_wide_strokes_ha (cairo_t *cr, int width, int height, int loops) +{ + int count; + + state = 0xc0ffee; + for (count = 0; count < 1000; count++) { + double h = floor (uniform_random (0, height)); + cairo_move_to (cr, floor (uniform_random (0, width)), h); + cairo_line_to (cr, ceil (uniform_random (0, width)), h); + } + + cairo_set_line_width (cr, 5.); + + cairo_perf_timer_start (); + + while (loops--) + cairo_stroke_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_wide_strokes_h (cairo_t *cr, int width, int height, int loops) +{ + int count; + + state = 0xc0ffee; + for (count = 0; count < 1000; count++) { + double h = uniform_random (0, height); + cairo_move_to (cr, uniform_random (0, width), h); + cairo_line_to (cr, uniform_random (0, width), h); + } + + cairo_set_line_width (cr, 5.); + + cairo_perf_timer_start (); + + while (loops--) + cairo_stroke_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_wide_strokes_va (cairo_t *cr, int width, int height, int loops) +{ + int count; + + state = 0xc0ffee; + for (count = 0; count < 1000; count++) { + double v = floor (uniform_random (0, width)); + cairo_move_to (cr, v, floor (uniform_random (0, height))); + cairo_line_to (cr, v, ceil (uniform_random (0, height))); + } + + cairo_set_line_width (cr, 5.); + + cairo_perf_timer_start (); + + while (loops--) + cairo_stroke_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_wide_strokes_v (cairo_t *cr, int width, int height, int loops) +{ + int count; + + state = 0xc0ffee; + for (count = 0; count < 1000; count++) { + double v = uniform_random (0, width); + cairo_move_to (cr, v, uniform_random (0, height)); + cairo_line_to (cr, v, uniform_random (0, height)); + } + + cairo_set_line_width (cr, 5.); + + cairo_perf_timer_start (); + + while (loops--) + cairo_stroke_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_wide_strokes (cairo_t *cr, int width, int height, int loops) +{ + int count; + + /* lots and lots of overlapping strokes */ + state = 0xc0ffee; + for (count = 0; count < 1000; count++) { + cairo_line_to (cr, + uniform_random (0, width), + uniform_random (0, height)); + } + + cairo_set_line_width (cr, 5.); + + cairo_perf_timer_start (); + + while (loops--) + cairo_stroke_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +cairo_bool_t +wide_strokes_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "wide-strokes", NULL); +} + +void +wide_strokes (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1., 1., 1.); + + cairo_perf_run (perf, "wide-strokes-halign", do_wide_strokes_ha, NULL); + cairo_perf_run (perf, "wide-strokes-valign", do_wide_strokes_va, NULL); + cairo_perf_run (perf, "wide-strokes-horizontal", do_wide_strokes_h, NULL); + cairo_perf_run (perf, "wide-strokes-vertical", do_wide_strokes_v, NULL); + cairo_perf_run (perf, "wide-strokes-random", do_wide_strokes, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/world-map.c b/local/recipes/libs/cairo/source/perf/micro/world-map.c new file mode 100644 index 0000000000..ff22eebf33 --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/world-map.c @@ -0,0 +1,149 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * 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: Carl D. Worth + */ + +#include "cairo-perf.h" + +#ifdef HAVE_UNISTD_H +#include +#endif + +typedef enum { + WM_NEW_PATH, + WM_MOVE_TO, + WM_LINE_TO, + WM_HLINE_TO, + WM_VLINE_TO, + WM_REL_LINE_TO, + WM_END +} wm_type_t; + +typedef struct _wm_element { + wm_type_t type; + double x; + double y; +} wm_element_t; + +#include "world-map.h" + +enum { + STROKE = 1, + FILL = 2, +}; + +static cairo_time_t +do_world_map (cairo_t *cr, int width, int height, int loops, int mode) +{ + const wm_element_t *e; + double cx, cy; + + cairo_set_line_width (cr, 0.2); + + cairo_perf_timer_start (); + + while (loops--) { + cairo_set_source_rgb (cr, .68, .85, .90); /* lightblue */ + cairo_rectangle (cr, 0, 0, 800, 400); + cairo_fill (cr); + + e = &countries[0]; + while (1) { + switch (e->type) { + case WM_NEW_PATH: + case WM_END: + if (mode & FILL) { + cairo_set_source_rgb (cr, .75, .75, .75); /* silver */ + cairo_fill_preserve (cr); + } + if (mode & STROKE) { + cairo_set_source_rgb (cr, .50, .50, .50); /* gray */ + cairo_stroke (cr); + } + cairo_new_path (cr); + cairo_move_to (cr, e->x, e->y); + break; + case WM_MOVE_TO: + cairo_close_path (cr); + cairo_move_to (cr, e->x, e->y); + break; + case WM_LINE_TO: + cairo_line_to (cr, e->x, e->y); + break; + case WM_HLINE_TO: + cairo_get_current_point (cr, &cx, &cy); + cairo_line_to (cr, e->x, cy); + break; + case WM_VLINE_TO: + cairo_get_current_point (cr, &cx, &cy); + cairo_line_to (cr, cx, e->y); + break; + case WM_REL_LINE_TO: + cairo_rel_line_to (cr, e->x, e->y); + break; + } + if (e->type == WM_END) + break; + e++; + } + + cairo_new_path (cr); + } + + cairo_perf_timer_stop (); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +do_world_map_stroke (cairo_t *cr, int width, int height, int loops) +{ + return do_world_map (cr, width, height, loops, STROKE); +} + +static cairo_time_t +do_world_map_fill (cairo_t *cr, int width, int height, int loops) +{ + return do_world_map (cr, width, height, loops, FILL); +} + +static cairo_time_t +do_world_map_both (cairo_t *cr, int width, int height, int loops) +{ + return do_world_map (cr, width, height, loops, FILL | STROKE); +} + +cairo_bool_t +world_map_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "world-map", NULL); +} + +void +world_map (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + cairo_perf_run (perf, "world-map-stroke", do_world_map_stroke, NULL); + cairo_perf_run (perf, "world-map-fill", do_world_map_fill, NULL); + cairo_perf_run (perf, "world-map", do_world_map_both, NULL); +} diff --git a/local/recipes/libs/cairo/source/perf/micro/world-map.h b/local/recipes/libs/cairo/source/perf/micro/world-map.h new file mode 100644 index 0000000000..af58b80f1c --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/world-map.h @@ -0,0 +1,196 @@ +/* The data for this test case was provided by Gary Nicholson + * who originally created an interactive SVG map + * of the world as can be seen here: + * + * http://www.wherearewe.co.nz/svg.html + * + * The data is used here by permission from Gary given on 2006-11-08: + * + * Thanks for asking, I don't need any attribution if you are + * only using the vectors and not the entire map with + * interactivity etc. So feel free to do what you wish with + * the data. + */ + +#define N(x,y) { WM_NEW_PATH, x, y } +#define M(x,y) { WM_MOVE_TO, x, y } +#define L(x,y) { WM_LINE_TO, x, y } +#define H(x,y) { WM_HLINE_TO, x, y } +#define V(x,y) { WM_VLINE_TO, x, y } +#define l(x,y) { WM_REL_LINE_TO, x, y } +#define E(x,y) { WM_END, x, y } + +static const wm_element_t countries[] = { +N(413.519,90.071),l(.136,-.348),l(-.31,-.204),l(-.017,-.327),l(.213,-.322),l(.245,-.147),l(.142,-.08),l(.225,.072),l(.062,.301),l(.41,.312),l(.466,.096),l(-.044,.288),l(-.248,.144),l(.074,.353),l(-.145,-.063),l(-.568,-.011),l(-.642,-.063), +N(421.683,94.397),l(.193,.336),l(-.266,.274),l(.214,.288),l(-.09,.192),l(.622,.062),l(.008,.144),l(.55,.242),l(.579,-.332),l(.215,.117),l(-.029,.171),l(-.126,.309),l(.112,.212),l(-.038,.192),l(-.315,-.051),l(-.176,-.162),l(-.283,.091),l(-.081,.273),l(.244,.131),l(-.228,.415),l(-.244,-.333),l(-.469,.05),l(-.071,.122),l(-.216,.03),l(-.23,-.142),l(-.143,-.354),l(-.371,.081),l(.019,.333),l(-.425,.384),l(-.018,.535),l(-.285,.151),l(-.385,-.312),l(.098,-.182),l(-.311,-.071),l(-.534,-.363),l(-.016,-.415),l(-.777,.404),l(.103,.212),l(-.349,.432),l(-.275,.16),l(-.629,-.168),l(-.627,.204),l(-.599,-.062),l(-.102,-.424),l(-.312,-.806),l(-.616,.147),l(-.854,.668),l(-.369,-.111),l(.238,-.226),l(.013,-.322),l(-.08,-.137),l(.089,-.294),l(.718,-.418),l(-.038,-.315),l(.575,-.24),l(.012,-.076),l(.528,-.494),l(.173,-.035),l(-.116,-.089),l(-.153,-.028),l(.221,-.302),l(.446,.007),l(-.005,.096),l(.473,.007),l(.385,-.309),l(.271,.089),l(.272,-.117),l(.271,.096),l(.567,-.158),l(.278,.11),l(.354,-.021),l(-.179,-.199),l(.709,-.199),l(.017,.151),l(.199,-.014),l(.149,.089),l(.852,.007),l(.664,.261), +N(421.394,104.558),l(.104,.175),l(.04,.256),l(-.06,.475),l(.118,.054),l(.062,.333),l(-.076,.795),l(-.211,.327),l(-.118,.724),l(-.292,.501),l(-.298,-.043),l(-.057,-.196),l(-.41,-.076),l(-.227,-.152),l(.284,-.207),l(-.07,-.076),l(-.437,-.098),l(.257,-.332),l(-.11,-.071),l(-.291,.071),l(-.053,-.147),l(.115,-.022),l(.175,-.158),l(-.094,-.153),l(-.257,-.082),l(.015,-.164),l(.247,-.12),l(-.284,-.218),l(.241,-.284),l(.6,-.305),l(.27,-.022),l(.04,-.125),l(.292,-.043),l(.195,.104),l(.096,-.142),l(-.022,-.344),l(.072,-.224),l(.143,-.011),M(396.323,103.853),l(.375,-.122),l(.411,-.365),l(.549,-2.299),l(.397,-.091),l(-.21,-.29),l(-.226,.259),l(.125,-1.144),l(.223,-.826),l(.115,.153),l(.496,.306),l(.191,.382),l(.191,.229),l(-.281,-.673),l(-.63,-.582),l(-.242,-.233),l(.024,-.249),l(.359,-.477),l(-.202,-.375),l(-.2,-.274),l(-.326,-.216),l(-.685,-.1),l(-.515,-.571),l(-.416,-.323),l(.278,-.426),l(-.233,-.181),l(-.343,-.131),l(-.511,-.142),l(-.184,-.173),l(.247,-.376),l(-.329,-.173),l(-.509,.179),l(-.489,-.249),l(-.824,-.251),l(-.619,-.181),l(-.325,.014),l(-.215,-.25),l(-.91,.167),l(-.059,-.25),l(-.265,-.125),l(-.367,-.042),l(-.056,-.104),l(.861,-.083),l(-.085,-.229),l(-.526,-.104),l(.442,-.104),l(.086,-.205),l(-.275,.017),l(-.263,-.021),l(-.417,.083),l(.04,-.438),l(.303,.012),l(.305,-.146),l(.526,-.088),l(.562,-.174),l(.215,.188),l(.18,-.167),l(.474,.063),l(.112,-.26),l(.272,-.059),l(.764,-.078),l(.393,.366),l(.275,.26),l(.342,.083),l(.652,-.271),l(.317,.167),l(.276,-.127),l(.457,-.124),l(.029,.23),l(.591,-.065),l(.3,-.103),l(-.265,-.188),l(-.028,-.251),l(.056,-.345),l(-.037,-.428),l(-.131,.021),l(-.562,-.682),l(-.11,-.407),l(.927,.126),l(.607,-.105),l(-.084,.397),l(.248,.419),l(.342,-.146),l(1.241,.104),l(.501,.146),l(.079,-.014),l(.525,-.093),l(.662,-.27),l(-.534,-.124),l(.055,-.204),l(.166,-.175),l(.753,-.322),l(.756,-.181),l(.902,-.215),l(.314,-.235),l(.302,-.264),l(-.053,-.775),l(.135,-.542),l(.521,-.25),l(.46,-.16),l(.916,-.092),l(.177,-.096),l(.208,.447),l(.311,.335),l(.266,.127),l(.141,-.071),l(.41,-.208),l(.153,.17),l(.202,.458),l(.194,.133),l(.518,-.012),l(.159,.301),l(.259,-.012),l(.576,.048),l(.375,.168),l(-.159,.241),l(.091,.175),l(-.072,.198),l(.285,.122),l(.406,-.075),l(.446,-.035),l(.193,-.313),l(.245,-.072),l(-.119,.373),l(.146,.18),l(-.039,.228),l(.529,.048),l(.341,.192),l(.371,.204),l(.127,.228),l(.694,-.174),l(.079,.114),l(.642,.063),l(.568,.011),l(.145,.063),l(.428,.319),l(.337,.277),l(.395,-.055),l(.045,.145),l(.689,-.062),l(.072,-.048),l(.233,.007),l(.095,.186),l(.456,.09),l(.479,-.014),l(.605,.193),l(-.954,.806),l(-.054,.213),l(-.054,.358),l(-.321,.372),l(-.075,.295),l(.091,.076),l(-.216,.701),l(.135,.233),l(-.385,.309),l(-.473,-.007),l(.005,-.096),L(415.96,94.5),l(-.221,.302),l(.153,.028),l(.116,.089),l(-.173,.035),l(-.528,.494),l(-.012,.076),l(-.575,.24),l(.038,.315),l(-.718,.418),l(-.089,.294),l(.08,.137),l(-.013,.322),l(-.238,.226),l(.369,.111),l(.854,-.668),l(.616,-.147),l(.312,.806),l(.102,.424),l(-.624,.301),l(.532,.344),l(.025,.292),l(.43,.192),l(-.199,.272),l(-.541,.353),l(-.183,-.111),l(-.437,.186),l(.352,.358),l(.616,.191),l(.135,.331),l(-.175,.01),l(-.315,.371),l(.193,.442),l(.754,.391),l(.849,-.07),l(.062,.281),l(-.146,.469),l(-.346,.23),l(-.221,.215),l(-.833,.488),l(-.889,.659),l(-.427,.087),l(-.318,.043),l(-.798,.159),l(-.405,-.028),l(-.471,-.156),l(-.851,-.499),l(-.315,-.085),l(-.354,.029),l(-.231,.072),l(-.511,-.056),l(-.752,-.313),l(-.602,.044),l(-.731,.345),l(-.357,.258),l(-.555,.559),l(-.147,.386),l(.099,.514),l(.091,.379),l(-.334,-.091),l(-.75,.137),l(-.039,.136),l(-.485,-.015),l(-.427,-.197),l(-.395,.167),l(-.261,-.015),l(-.036,-.152),l(-.335,-.091),l(-.206,.03),l(-.374,.076),l(-.187,-.076),l(-.035,-.289),l(-.091,-.213),l(-1.252,-.304),l(-.355,0),l(.017,.319),l(-.542,-.015),l(-.337,.061),l(-.037,-.122),l(-.767,.03),l(-.084,-.114),l(-.028,-.038),l(-.431,-.152),l(-.131,.076),l(-.262,-.03),l(-.056,.076),l(-.507,-.395),l(-.15,.061),l(-1.088,-.334),l(-.112,.106),l(-.15,-.03),l(-.094,-.106),l(.205,-.243),l(-.058,-.122),l(-.469,.03),l(-.472,-.243), +N(681.312,116.395),l(.235,-.171),l(.283,-.256),l(.633,-.738),l(.315,-.157),l(.595,.011),l(.579,.068),l(.511,.096),l(.309,-.115),l(.571,-.678),l(.682,.621),l(1.178,1.611),l(.329,.495),l(.269,.664),l(.002,.75),l(-.034,.947),l(-.129,.637),l(.143,.113),l(.5,-.043),l(-.121,.41),l(-.282,.523),l(-.5,.75),l(-.316,.312),l(-.243,.043),l(-.567,-.211),l(-.256,.1),l(-.607,.58),l(-.431,-.083),l(-.289,-.225),l(-.544,.1),l(-.526,.199),l(-1.188,.835),l(-.462,.043),l(-.46,.312),l(-.055,-.564),l(-.056,-.324),l(-.163,-.705),l(-.137,-.395),l(.167,-.453),l(.499,-.468),l(0,-.353),l(.226,-.425),l(-.044,-.141),l(-.378,-.311),l(-.095,-.296),l(.015,-.467),l(-.087,-.339),l(-.289,-.126),l(-.603,-.084),l(.654,-.411),l(.303,-.114),l(.654,.268),l(.254,-.241),l(-.029,-.283),l(-.764,-.89),l(-.113,-.311),l(-.137,-.105), +N(475.646,121.847),l(-.018,.175),l(.338,.391),l(-.295,-.009),l(-.132,.108),l(-.104,-.059),l(-.327,-.021),l(-.121,.33),l(-.783,.257),l(-.384,.046),l(-.099,.053),l(0,.21),l(-.217,.006),l(-.072,-.192),l(-.402,.023),l(-.547,-.146),l(-.191,-.087),l(0,-.21),l(-.161,-.105),l(-.122,-.403),l(.082,-.035),l(.12,.1),l(.147,-.006),l(.405,-.304),l(.253,-.006),l(.328,.092),l(.077,-.086),l(.088,-.286),l(-.053,-.175),l(.627,.093),l(.658,.027),l(.367,-.056),l(.818,-.233),l(.689,-.304),l(.535,-.158),l(-.475,.295),l(-.436,.231),l(-.596,.444), +N(704.404,117.274),l(.197,-.099),l(1.108,-.271),l(.057,.354),l(-.481,.284),l(-.232,.241),l(-.068,.453),l(.139,.367),l(.291,.056),l(.221,-.114),l(.418,-.354),l(.24,-.085),l(1.656,-.697),l(.389,-.213),l(.46,-.326),l(.349,-.638),l(.76,-.412),l(.347,-.327),l(.191,-.269),l(.142,-.51),l(.538,-.582),l(-.01,-.142),l(.344,-.567),l(.159,-.468),l(.139,-.609),l(-.043,-.467),l(-.33,-.198),l(-.128,-.24),l(.234,-.213),l(.166,-.284),l(-.155,-1.023),l(.544,-.343),l(.176,-.242),l(.327,-.328),l(.192,0),l(.21,.355),l(.199,.227),l(.303,-.058),l(.799,-.257),l(-.169,-.526),l(-.311,-.028),l(-.36,-.312),l(.694,-.415),l(.441,.156),l(.336,.227),l(.025,.199),l(-.016,.868),l(.058,.611),l(.22,.127),l(.243,.312),l(.717,1.432),l(.001,.496),l(-.246,.709),l(-.709,.766),l(-.226,.439),l(.064,.368),l(-.15,.071),l(-.737,.285),l(-.161,.113),l(-.164,.199),l(-.174,.453),l(.02,.396),l(.094,.254),l(.131,.792),l(-.04,.693),l(-.686,.751),l(-.242,.736),l(.02,.707),l(.198,.296),l(.422,.353),l(-.617,.298),l(-.193,.127),l(-.166,.17),l(-.174,.834),l(-1.081,.439),l(-.094,-.282),l(.294,-.665),l(.184,-.523),l(-.198,-.126),l(-.514,.241),l(-.578,.623),l(-.476,.001),l(-.346,.312),l(-.066,.748),l(-.354,.269),l(-.188,-.028),l(-.066,-.155),l(.003,-.606),l(-.149,-.155),l(-.211,.042),l(-.309,.156),l(-.344,.311),l(-.325,.523),l(-.866,-.055),l(-.505,.057),l(-.631,.1),l(-.458,-.549),l(-.685,-.323),l(-.26,.254),l(-.067,.184),l(-.177,.353),l(.037,.056),l(.417,.197),l(.416,.323),l(-.293,.198),l(-.829,.129),l(-.433,.241),l(-.463,.622),l(-.522,.847),l(-.688,-.365),l(-.565,-.21),l(-.285,-.197),l(-.014,-.169),l(-.194,-.818),l(.099,-.155),l(.495,-.325),l(.179,-.269),l(-.067,-.282),l(-.18,-.042),l(-.601,.17),l(-.341,-.028),l(-.789,-.167),l(-.475,.128),l(-.427,.227),l(-.437,.184),l(-.269,-.098),l(-.256,-.027),l(-1.647,.398),l(-.814,.298),l(-.21,-.31),l(-.452,-.042),l(-.413,.438),l(-.006,.635),l(-.756,-.238),l(-.579,-.055),l(-1.1,.073),l(-.267,-.14),l(.072,-.339),l(.179,-.283),l(.483,.013),l(.499,-.114),l(.751,-.467),l(2.201,-1.953),l(.28,-.015),l(.427,-.128),l(.056,.424),l(.495,-.128),l(1.278,-.257),l(.933,-.058),l(1.183,-.172),l(.892,-.256),l(.068,.452),l(.377,.268),l(.167,-.085),l(.654,-.199),l(.446,-.34),l(-.003,-.353),l(.114,-.467),l(.465,-.51),l(.698,-.581),l(.371,-.453),l(-.062,-1.117),l(.182,-.213),M(695.464,127.756),l(-.292,-.197),l(-.223,-.268),l(-.101,-.381),l(-.177,-.395),l(-.492,-.535),l(.731,-.382),l(.287,-.269),l(.456,-.593),l(.409,.253),l(.615,-.015),l(.483,-.185),l(.311,-.339),l(.451,-.311),l(.454,-.029),l(.316,.169),l(.862,.224),l(.153,.254),l(-.1,.127),l(-.102,.423),l(-.292,.24),l(-.864,.876),l(-.181,-.211),l(-.424,-.295),l(-.467,-.042),l(-.612,.213),l(-.193,.184),l(-.245,.495),l(-.165,.508),l(-.153,.212),l(-.448,.269),M(691.12,131.448),l(-.366,-.042),l(-.056,-.141),l(.268,-.537),l(.128,-.593),l(-.334,-.112),l(-.239,.198),l(-.155,.466),l(-.381,.452),l(-.326,-.211),l(-.059,-.211),l(.322,-.466),l(.032,-.296),l(-.356,-.917),l(.169,-.113),l(.687,-.58),l(.083,-.141),l(.034,-.466),l(-.532,-.789),l(-.333,-.042),l(-.162,.269),l(-.419,.495),l(-.249,-.112),l(-.23,-.508),l(-.376,-.267),l(-.261,-.366),l(.41,-.325),l(.733,.083),l(.706,-.171),l(.315,-.466),l(.241,-.283),l(.484,-.058),l(.478,.056),l(.249,.38),l(.27,.168),l(.43,.084),l(.628,-.213),l(.225,.395),l(-.569,.438),l(.405,.239),l(.443,.437),l(.079,.254),l(-.596,.58),l(-.242,.41),l(-.104,.367),l(-.085,.621),l(-.109,.649),l(-.242,.353),l(-.194,.099),l(-.165,.071),l(-.197,.184),l(-.479,.678),M(711.938,108.369),l(-.222,-.241),l(-.077,-.271),l(.325,-.642),l(-.055,-.342),l(-.549,-.198),l(-.168,-.171),l(-.146,-.812),l(.583,-.386),l(.522,-.172),l(.646,-.373),l(.037,-.356),l(-.318,-.285),l(.277,-.3),l(.224,-.015),l(.661,.427),l(.373,.085),l(.532,-.201),l(-.004,-1.186),l(.455,-.187),l(.45,-.244),l(.074,-.743),l(.007,-.844),l(-.398,-.758),l(-.098,-.473),l(.166,-.216),l(.618,-.346),l(.063,.072),l(.507,.43),l(.904,.816),l(1.07,.842),l(1.083,.684),l(.627,.285),l(.528,.17),l(1.02,.198),l(.282,.042),l(.304,-.086),l(.866,-.66),l(.461,-.144),l(.002,.1),l(-.308,.358),l(-.335,.558),l(.198,.414),l(.469,.599),l(.197,.356),l(-.561,.272),l(-.447,.244),l(-.534,.158),l(-.365,.015),l(-.488,-.199),l(-.453,.015),l(-.363,.144),l(-.345,.229),l(-.754,.786),l(-.396,.5),l(-.26,.599),l(-.4,-.07),l(-.425,-.241),l(-2.031,-.965),l(-.461,-.085),l(-.72,.044),l(-1.038,.587),l(-.153,-.299),l(-.372,-.356),l(-.339,.029),l(-.266,.115),l(-.439,.272),l(.049,.299),l(1.16,.497),l(.56,.298),l(.302,.27),l(-.391,.214),l(-.303,.029),l(-.305,-.128),l(-.261,.043),l(-.324,.314),l(-.388,.471),l(-.347,.114), +N(597.917,139.685),l(1.251,-1.545),l(.609,-.539),l(.348,-.239),l(.149,-.103),l(.417,-.016),l(.309,.294),l(.479,.208),l(1.659,.047),l(.371,.041),l(.312,.209),l(.329,.619),l(-.07,.156),l(.042,.24),l(.326,.294),l(.313,.069),l(.258,.238),l(.017,.282),l(-.217,.58),l(-.624,.06),l(-1.036,.062),l(-1.238,-.063),l(-.335,-.125),l(-.301,-.055),l(-.531,.313),l(-.544,.074),l(-.085,-.021),l(-.869,-.214),l(-.559,-.081),l(-.637,-.18),l(-.235,-.493),l(.092,-.113), +N(362.764,152.723),l(.072,-.625),l(.395,-.876),l(.52,-.552),l(.488,-.566),l(.244,-.509),l(1.175,-2.559),l(.238,-.241),l(1.404,-1.175),l(.345,-.495),l(.051,-.918),l(.305,-1.088),l(.651,-1.075),l(.399,-.34),l(.404,-.198),l(.838,-.51),l(.361,-.495),l(.334,-.777),l(.428,-.851),l(1.635,-.04),l(2.511,0),l(2.677,-.001),l(1.718,.004),l(1.42,-.008),l(.027,.876),l(-.03,1.752),l(.002,.65),l(-.104,.396),l(-.56,-.011),l(-6.005,-.022),l(-.557,.074),l(-.047,.509),l(-.07,2.261),l(-.099,2.6),l(-.144,.128),l(-.809,.287),l(-.726,.315),l(-.575,.427),l(-.249,.383),l(-.01,.707),l(.164,1.539),l(.051,1.102),l(-.212,-.027),l(-.732,.033),l(-2.396,-.014),l(-5.055,-.056),l(-.474,-.013), +N(514.551,145.841),l(-.374,.027),l(-.336,-.083),l(-.008,-.615),l(-.153,-.437),l(-.108,-.791),l(.187,-.607),l(.188,-.11),l(-.059,-.187),l(.177,-.607),l(.33,-.269),l(.312,.083),l(.069,.315),l(.26,.093),l(.063,.199),l(.116,.326),l(-.106,.42),l(.031,.708),l(.118,.254),l(-.104,.381),l(-.327,.467),l(-.275,.433), +N(514.177,145.868),l(.374,-.027),l(.008,.288),l(.361,.14),l(.153,.128),l(.186,-.093),l(-.046,.443),l(.397,.001),l(.402,.127),l(.687,-.093),l(.103,-.21),l(.183,-.058),l(.218,.117),l(.424,-.042),l(.595,.112),l(.224,-.035),l(.079,-.105),l(1.358,.222),l(.732,-.14),l(-.022,-.292),l(.225,.175),l(.375,-.016),l(.157,-.099),l(.312,-.422),l(.232,-.073),l(.267,-.495),l(.131,-.297),l(.711,-.637),l(.813,-.889),l(.163,.105),l(.229,-.178),l(.85,-.708),l(.313,-.433),l(.15,.161),l(-.248,.42),l(-.107,.299),l(-.004,.176),l(.099,.064),l(.121,-.024),l(.454,.042),l(.09,.324),l(.001,.508),l(-.003,.358),l(-.49,.034),l(-.401,-.083),l(-.107,.396),l(.073,1.326),l(-.199,.34),l(-.536,.596),l(.003,.946),l(.024,2.075),l(.063,.183),l(-.152,.057),l(-.584,.469),l(-.839,-.108),l(-3.387,-.446),l(-3.362,-.375),l(-.261,-.902),l(-.548,-1.154),l(-1.043,-2.198), +N(668.627,151.365),l(-.102,-.056),l(-.107,-.325),l(-.922,-1.212),l(-.332,-.987),l(-.03,-.438),l(.156,-.749),l(.546,-.792),l(1.312,-1.852),l(.259,-.184),l(.425,-.128),l(.229,-.184),l(.358,-.227),l(.228,.127),l(.554,.394),l(-.334,.424),l(-.084,.142),l(.023,.31),l(-.067,.622),l(-.203,.296),l(-.182,.354),l(-.065,.692),l(-.1,.494),l(-.317,.805),l(-.473,.707),l(-.417,.833),l(-.014,.353),l(-.114,.438),l(-.228,.142), +N(389.765,144.543),l(.1,.084),l(.895,.531),l(2.054,1.344),l(.811,.575),l(3.283,2.241),l(1.924,1.26),l(1.292,.824),l(.397,.253),l(2.472,1.469),l(.181,.253),l(-.096,.396),l(.082,.183),l(.393,.28),l(1.111,1.039),l(.229,.027),l(.47,-.314),l(.588,.562),l(.375,.167),l(.748,.024),l(.309,.111),l(.277,.352),l(.099,.522),l(-.161,.679),l(.146,.564),l(2.176,-.408),l(.064,1.017),l(.034,2.203),l(.001,.96),l(-.08,.89),l(-.145,.919),l(-.434,1.246),l(-.596,.794),l(-.339,.271),l(-.29,.129),l(-2.533,.085),l(-1.808,.124),l(-.209,.072),l(-.562,.427),l(-.579,.272),l(-.678,-.053),l(-.581,-.081),l(-1.062,-.173),l(-.36,-.059),l(-.356,-.125),l(-.37,.073),l(-1.22,.713),l(-.947,.458),l(-.304,.228),l(-.314,.793),l(-.274,-.027),l(-.324,-.182),l(-.518,-.209),l(-.272,.101),l(-.638,.625),l(-.492,.667),l(-.393,.822),l(-.174,.227),l(-.45,.102),l(-.551,-.364),l(-.293,-.281),l(-.273,.058),l(-.397,.384),l(-.355,1.217),l(-.292,1.047),l(-.317,.369),l(-.543,.271),l(-.448,.158),l(-.257,.016),l(-.141,.255),l(.058,.749),l(-.133,.876),l(-.261,.92),l(-.172,.326),l(-.046,.156),l(-.08,.043),l(-.159,.1),l(-.604,.399),l(-.352,.059),l(-.148,-.239),l(-.117,-.381),l(-.004,-.297),l(-.147,-.211),l(-.257,-.041),l(-.239,.114),l(-.571,.483),l(-.362,.469),l(-.35,.228),l(-.455,-.436),l(-.566,-.321),l(-.352,.059),l(-.522,.54),l(-.559,-.901),l(-.194,-1.143),l(-.349,-.718),l(-.474,-.478),l(-.265,-.451),l(-.271,-.832),l(-.022,-.339),l(-.246,-.281),l(-.323,-.055),l(-.684,.428),l(-.3,.327),l(-.43,.243),l(-.565,-.152),l(-.356,-.153),l(-.338,-.026),l(-.475,.413),l(-.252,.256),l(-.536,-.265),l(-.882,-.715),l(-.18,-.183),l(-.113,-.028),l(.062,-.142),l(.004,-.565),l(-.082,-.833),l(-.265,-.337),l(-.554,-.322),l(-.181,-.197),l(-.22,-.479),l(-.144,-.663),l(-.251,-1.1),l(.057,-.339),l(.506,-.399),l(.332,-.284),l(.018,-.607),l(.181,-.552),l(.252,-.256),l(.402,-.073),l(.261,.111),l(.568,.83),l(.214,.168),l(.454,.082),l(.107,-.269),l(-.055,-.296),l(.06,-.212),l(.535,.124),l(.713,.137),l(.485,.054),l(.387,-.031),l(.945,-.344),l(1.953,-.026),l(6.457,-.01),l(.379,-1.613),l(-.724,-.787),l(-.186,-1.468),l(-.202,-2.386),l(-.325,-2.753),l(-.178,-1.736),l(-.19,-1.468),l(-.908,-7.962),l(-.049,-.776),l(3.231,-.089),l(.523,-.13), +N(525.37,142.384),l(.312,-.429),l(.155,-.17),l(.084,.833),l(-.423,.707),l(-.118,.156),l(-.121,.024),l(-.099,-.064),l(.004,-.176),l(.107,-.299),l(.248,-.42),l(-.15,-.161),M(525.923,144.712),l(0,.22),l(.456,.762),l(.408,.465),l(.782,.634),l(.677,.394),l(1.008,.52),l(.392,.154),l(.277,.014),l(.576,-.029),l(.364,.112),l(.873,.973),l(.518,.648),l(.46,.422),l(.81,.365),l(.025,.212),l(-.67,1.06),l(-.615,.721),l(-.883,.807),l(-.776,1.541),l(-.242,.142),l(-.562,-.083),l(-.235,-.084),l(-.252,.071),l(-.278,.509),l(-.062,1.115),l(.001,.791),l(.134,.621),l(-.403,.142),l(-1.046,.073),l(-.627,.27),l(-.367,.283),l(-.29,.495),l(-.131,.551),l(-.204,.283),l(-.444,.255),l(-.544,.1),l(-.292,0),l(-.386,-.042),l(-.326,.029),l(-.382,.283),l(-.22,.297),l(-.125,.508),l(.003,.353),l(-.091,.311),l(-.631,.396),l(-.344,.043),l(-.776,-.21),l(-.717,.058),l(-.896,.27),l(-.768,.298),l(-.283,.099),l(-.416,.145),l(-.241,-.306),l(-.483,-.689),l(.006,-.296),l(-.127,-.253),l(-.933,-1.364),l(-.604,-.971),l(-.226,-.634),l(-.092,-.663),l(1.691,-.815),l(2.35,-1.213),l(5.346,-2.982),l(-.155,-1.453),l(-.581,-.914),l(-.063,-.183),l(-.024,-2.075),l(-.003,-.946),l(.536,-.596),l(.199,-.34),l(-.073,-1.326),l(.107,-.396),l(.401,.083),l(.49,-.034), +N(405.733,173.04),l(-.568,-.971),l(-.562,-.025),l(-.37,.044),l(-.516,-.181),l(-.97,-.757),l(-.114,-.226),l(.335,-.439),l(-.018,-.212),l(-.179,-.268),l(-.502,-.42),l(-.389,-.266),l(-.422,-.492),l(-.426,-.93),l(-.019,-.396),l(.173,-.665),l(.581,.081),l(.678,.053),l(.579,-.272),l(.562,-.427),l(.209,-.072),l(1.808,-.124),l(2.533,-.085),l(.29,-.129),l(.339,-.271),l(.596,-.794),l(.434,-1.246),l(.145,-.919),l(.08,-.89),l(-.001,-.96),l(-.034,-2.203),l(-.064,-1.017),l(1.672,-.321),l(1.82,-.364),l(3.084,-2.617),l(.834,-.655),l(2.308,-1.454),l(1.607,-.956),l(4.012,-2.241),l(1.632,-.843),l(.265,-.186),l(.832,.137),l(1.646,.442),l(1.008,.333),l(.258,.182),l(1.192,.911),l(.231,-.157),l(1.519,-.729),l(.364,2.145),l(.169,1.298),l(.42,1.028),l(.554,.802),l(.703,.604),l(-.388,.722),l(-.265,.99),l(-.168,1.088),l(-.084,.989),l(.022,.537),l(-.062,.707),l(-.019,1.045),l(-.034,1.088),l(-.056,.466),l(-2.43,2.613),l(-.591,.78),l(-.87,1.333),l(-.572,.794),l(-.007,.678),l(.123,.719),l(.014,.269),l(-.951,.034),l(-.437,.2),l(-.453,.299),l(-.761,.697),l(-.259,.058),l(-.609,-.208),l(-.724,-.193),l(-.884,-.221),l(-.531,-.04),l(-.709,.047),l(-.628,.103),l(-.774,.287),l(-.403,.327),l(-.629,.399),l(-.273,.059),l(-.934,.005),l(-.965,-.277),l(-1.173,-.742),l(-.354,-.083),l(-.467,.116),l(-1.337,.544),l(-.37,.002),l(-.209,-.098),l(-1.095,-1.223),l(-.821,-.277),l(-1.111,-.121),l(-1.174,.108),l(-1.064,.188),l(-.676,.4),l(-.687,1.614),l(-.353,.482),l(-.158,.849),l(-.092,.961),l(-.902,-.503),l(-.727,-.589),l(-.339,-.28),l(-.321,.073),l(-.577,.3), +N(431.763,171.063),l(-.351,-.407),l(-.575,-.52),l(-.173,-.394),l(-.014,-.269),l(-.123,-.719),l(.007,-.678),l(.572,-.794),l(.87,-1.333),l(.591,-.78),l(2.43,-2.613),l(.056,-.466),l(.034,-1.088),l(.019,-1.045),l(.062,-.707),l(-.022,-.537),l(.084,-.989),l(.168,-1.088),l(.265,-.99),l(.388,-.722),l(-.703,-.604),l(-.554,-.802),l(-.42,-1.028),l(-.169,-1.298),l(-.364,-2.145),l(1.818,-.858),l(.41,-.059),l(5.231,2.554),l(4.941,2.372),l(5.577,2.792),l(1.981,.963),l(-.02,1.045),l(-.016,.946),l(-.036,.636),l(.085,2.5),l(-.038,.749),l(.036,1.002),l(.031,1.229),l(-.04,.283),l(-.839,-.009),l(-1.245,.05),l(-.229,.143),l(-.417,1.245),l(-.583,.809),l(-.122,.438),l(.131,.677),l(-.149,.212),l(-.718,.428),l(-.053,.24),l(.342,.662),l(-.087,.34),l(-.542,.596),l(-.316,.609),l(.219,.352),l(.517,-.088),l(.338,.012),l(.141,.225),l(.221,1.228),l(.137,.522),l(.155,.295),l(.444,.407),l(.266,.465),l(.026,.367),l(-.15,.425),l(-.559,-.208),l(-.321,-.012),l(-.322,.086),l(-.939,.613),l(-.372,.228),l(-.165,.382),l(-.005,.41),l(-.196,.284),l(-2.649,2.275),l(-.386,.087),l(-2.181,.055),l(-.434,.059),l(-.209,.199),l(-.117,.806),l(-.646,1.176),l(-.258,.143),l(-.368,.031),l(-.881,-.009),l(-.818,.273),l(-.754,.386),l(-.466,.271),l(-.224,.03),l(-.225,-.069),l(-.494,-.661),l(-1.363,.686),l(-.449,.158),l(-.24,-.027),l(-.096,-.084),l(-.208,-.183),l(-.382,-1.057),l(-.638,-1.07),l(-1.343,-1.179),l(-1.088,-1.067),l(.323,-.539),l(.29,-.312),l(.24,-.1),l(.481,.082),l(1.187,.191),l(.674,-.032),l(.225,-.143),l(-.047,-.127),l(-.208,-.21),l(-.381,-.633),l(-.205,-.578),l(-.169,-1.228),l(.134,-.651),l(-.119,-1.2),l(-.395,-.887),l(-.923,-1.238),l(-.208,-.083),l(-.627,-.109), +N(627.173,150.012),l(.483,-.229),l(.515,-.13),l(.341,.012),l(.597,.392),l(.325,.097),l(.584,-.413),l(.332,-.115),l(1.595,-.052),l(.807,-.117),l(.341,-.157),l(.696,-.554),l(.521,-.328),l(.298,-.101),l(.623,.575),l(.771,.235),l(.66,.053),l(.777,-.047),l(.237,.21),l(.056,.38),l(-.472,.75),l(.096,.521),l(.273,.365),l(.943,.615),l(.621,.166),l(.909,.107),l(.197,.143),l(-.19,.132),l(-.826,.482),l(.106,.465),l(-.203,.212),l(-1.261,-.054),l(-.136,.198),l(.057,.395),l(-.283,.382),l(-.585,.792),l(-.221,.142),l(-.533,.241),l(-.171,.127),l(-.27,.396),l(-.303,.932),l(-.388,.975),l(.268,.225),l(.469,.563),l(1.112,1.071),l(.023,.24),l(.042,.522),l(.087,.254),l(.42,.493),l(1.096,.83),l(1.282,1.296),l(.26,.197),l(.636,.069),l(.313,.38),l(.282,1.016),l(.302,.578),l(.638,.605),l(.293,.663),l(.341,1.382),l(.524,2.809),l(-.295,.438),l(-.235,.495),l(.05,.819),l(-.095,.41),l(.056,.664),l(-.027,.099),l(-.364,.551),l(-.447,.439),l(-.254,.127),l(-.509,.1),l(-.419,.17),l(-.501,.354),l(-.591,.622),l(-.579,.354),l(-.325,.043),l(-.512,-.197),l(-.404,-.31),l(-.179,-.141),l(-.153,.424),l(.051,.494),l(.048,.353),l(-.205,.721),l(-.388,.424),l(-.326,.071),l(-.235,-.07),l(-.246,.481),l(-.427,.326),l(-.523,.142),l(-.417,.213),l(-.459,.565),l(-.196,.269),l(-.406,.297),l(-.264,.099),l(-.365,-.042),l(.078,-.861),l(.1,-1.313),l(.151,-.494),l(.215,-.283),l(-.02,-.353),l(-.475,-.437),l(-.749,-.238),l(-.091,-.066),l(.3,-.289),l(.646,-.229),l(.915,-.528),l(.599,-.229),l(.497,.011),l(.688,.194),l(.17,-.27),l(-.03,-.197),l(-.568,-.435),l(-.216,-.422),l(.234,-.425),l(.99,-.571),l(.521,-.229),l(.932,-.443),l(.599,-.187),l(.385,-.285),l(.217,-.509),l(-.054,-1.073),l(.05,-.424),l(.076,-.367),l(-.455,-1.014),l(-.029,-.663),l(.215,-.905),l(.155,-.918),l(-.064,-.578),l(-.214,-.437),l(-.529,-.477),l(-.072,-.282),l(.226,-.439),l(-.136,-.395),l(-.358,-.308),l(-.685,-.391),l(-.471,-.52),l(-.57,-.914),l(-1.683,-2.121),l(-.698,-.772),l(-.637,-.646),l(-.632,-.476),l(-1.234,-.741),l(-.162,-.098),l(-.043,-.494),l(.277,-.369),l(.311,-.101),l(.476,.068),l(.287,-.058),l(.261,-.185),l(.255,-.326),l(-.009,-.508),l(-.87,-.968),l(-.434,-.675),l(-.262,-.083),l(-.39,.171),l(-.509,.483),l(-.287,.058),l(-.47,-.195),l(-.607,-.434),l(-.334,-.689),l(-.338,-.929),l(-.543,-.604),l(-.613,-.575),l(-.45,-.745), +N(217.961,150.385),l(.304,-.043),l(.84,-.27),l(-.17,-.254),l(-.312,-.112),l(-.369,-.056),l(-.651,.016),l(-.497,-.042),l(-.645,.157),l(-1.193,.92),l(-.371,.029),l(-.653,.001),l(-.211,.113),l(-.189,.452),l(-.396,.284),l(-.32,.043),l(-.786,.086),l(.259,-.325),l(.473,-.312),l(-.128,-.593),l(.282,-.382),l(.114,-.099),l(1.258,-.61),l(1.625,-.47),l(1.164,-.087),l(.842,-.157),l(.825,.041),l(.566,-.044),l(.73,.168),l(.848,.083),l(.603,.197),l(.557,.112),l(.477,.013),l(.499,.268),l(.573,.536),l(.382,.253),l(.581,.168),l(.768,.111),l(1.229,.351),l(1.02,.492),l(.453,.31),l(.374,.55),l(.33,.141),l(.479,.041),l(1.704,.519),l(1.018,.167),l(.327,.239),l(-.344,.58),l(.233,.155),l(.559,.042),l(.756,-.072),l(.495,.168),l(.507,.38),l(.591,.281),l(.381,.296),l(-.233,.085),l(-.981,.087),l(-1.15,.398),l(-.626,.058),l(-1.054,-.209),l(-.9,-.041),l(-.934,.186),l(-.943,.115),l(-.484,.029),l(-.449,-.07),l(.353,-.382),l(.728,-.623),l(.173,-.396),L(229,154.204),l(-.181,-.127),l(-.622,-.14),l(-.7,.001),l(-.603,-.112),l(-.651,-.338),l(-.141,-.748),l(-.258,-.536),l(-.218,-.155),l(-.396,-.027),l(-1.005,.044),l(-.836,-.139),l(-.621,-.225),l(-.956,-.493),l(-.739,-.238),l(-.615,-.069),l(-1.154,-.068),l(-.489,-.098),l(-.855,-.352), +N(634.036,168.444),l(.808,-.64),l(.121,-.438),l(-.002,-.945),l(-.157,-.507),l(-.419,-.703),l(-.979,-1.279),l(-.255,-.464),l(-.107,-.366),l(-.058,-1.524),l(-.435,-.632),l(-.688,-.659),l(-.285,-.535),l(-.052,-.282),l(-.266,-.153),l(-.893,-.192),l(-.403,-.012),l(-.286,.453),l(-.2,.538),l(-.543,.257),l(-.223,.072),l(-.59,-.265),l(-.835,-.348),l(-.346,.03),l(-1.173,1.178),l(-.37,.411),l(-.481,-.138),l(-.145,-.324),l(.027,-.494),l(.117,-.438),l(.528,-1.569),l(.085,-.41),l(-.249,-1.311),l(-.045,-.113),l(-.414,.045),l(-.489,.2),l(-.423,.003),l(-.186,-.154),l(-.066,-.367),l(.106,-.805),l(-.01,-.423),l(-.118,-.168),l(-.295,-.182),l(-.541,-.166),l(.193,-.185),l(.582,-.455),l(.442,-.581),l(.53,-.61),l(.502,-.355),l(.178,.196),l(.321,.21),l(.769,.08),l(.266,-.213),l(.109,-.339),l(-.119,-.521),l(-.228,-.366),l(-.138,-.592),l(.043,-.325),l(.24,-.241),l(.679,-.314),l(.45,.745),l(.613,.575),l(.543,.604),l(.338,.929),l(.334,.689),l(.607,.434),l(.47,.195),l(.287,-.058),l(.509,-.483),l(.39,-.171),l(.262,.083),l(.434,.675),l(.87,.968),l(.009,.508),l(-.255,.326),l(-.261,.185),l(-.287,.058),l(-.476,-.068),l(-.311,.101),l(-.277,.369),l(.043,.494),l(.162,.098),l(1.234,.741),l(.632,.476),l(.637,.646),l(.698,.772),l(1.683,2.121),l(.57,.914),l(.471,.52),l(.685,.391),l(.358,.308),l(.136,.395),l(-.226,.439),l(.072,.282),l(.529,.477),l(.214,.437),l(.064,.578),l(-.155,.918),l(-.209,.114),l(-.975,.429),l(-.3,.072),l(-.373,-.351),l(-.444,-.181),l(-.476,.186),l(-.392,.285),l(.107,.296),l(.187,.182),l(.103,.211),l(-.095,.24),l(-.248,.058),l(-.469,-.251),l(-.341,-.111),l(-.736,-.165),l(-.533,-.251), +N(60.074,72.607),l(-.099,.228),l(-.491,.472),l(-.395,.183),l(-.462,.062),L(58,73.461),l(-.961,-.362),l(-.153,-.197),l(.169,-.289),l(.54,-.274),l(.341,-.32),l(.716,.364),l(.3,.091),l(.465,-.26),l(.215,-.213),l(.064,-.366),l(.485,-.047),l(1.107,.135),l(.536,.334),l(.133,.213),l(-.756,.062),l(-.429,0),l(-.59,.184),l(-.11,.092),M(40.092,77.571),l(-.729,-.029),l(-.097,-.24),l(.011,-.3),l(.802,-.243),l(.326,-.211),l(.593,-.423),l(.448,-.137),l(.646,-.077),l(1.427,.253),l(.711,.24),l(-.079,.211),l(-.303,.046),l(-.754,-.074),l(-.496,.031),l(-1.077,.183),l(-.269,.226),l(-1.161,.543),M(38.426,77.979),l(-.515,-.209),l(-.139,-.285),l(.381,-.227),l(.674,.27),l(.093,.195),l(-.122,.15),l(-.372,.105),M(37.896,78.449),l(-.256,.084),l(-.558,.151),l(-1.109,-.058),l(-.387,.135),l(-.398,.434),l(-.31,.15),l(-.854,-.207),l(-.135,-.224),l(.497,-.359),l(.5,-.315),l(.955,-.166),l(.863,-.346),l(.39,.089),l(.461,.224),l(.341,.409),M(29.628,81.29),l(-.168,-.594),l(-.324,-.476),l(.839,-.136),l(.424,.088),l(.436,.238),l(-.244,.268),l(-.26,.06),l(-.073,.297),l(-.22,.09),l(-.412,.164),M(27.543,81.591),l(-.39,.031),l(-.741,.165),l(-.311,-.133),l(-.088,-.178),l(.104,-.119),l(.336,-.268),l(.294,-.09),l(.584,.222),l(.212,.371),M(54.394,157.986),l(-.559,-.356),l(-.044,-.884),l(-.243,-.677),l(.482,-.402),l(-.035,-.2),l(-.156,-.26),l(.052,-.149),l(.173,-.046),l(.354,.158),l(.652,.279),l(.593,.425),l(-.015,.275),l(.238,.046),l(.12,.287),l(.306,.149),l(-.062,.161),L(56,156.933),l(-.172,.204),l(-.766,.195),l(-.374,.23),l(-.295,.425),M(23.015,59.92),l(-1.613,-.646),l(-.75,-.205),l(-.792,-.062),l(-.9,.065),l(-.291,-.095),l(-.431,-.222),l(.179,-.287),l(.516,-.049),l(1.135,.221),l(.579,-.001),l(.543,-.081),l(.538,-.001),l(.828,.285),l(1.725,.362),l(.429,.237),l(.046,.111),l(-.569,-.03),l(-.646,.033),l(-.527,.365),M(99.855,70.993),l(.467,.929),l(-.071,.167),l(-.879,-.272),l(-.621,-.075),l(.067,.441),l(-.056,.228),l(-.935,-.607),L(97.03,71.41),l(.396,-.458),l(.263,-.153),l(.612,-.078),l(.784,.38),l(.771,-.108),M(100.975,73.606),l(.128,.272),l(-.086,.273),l(-.318,.483),l(-.559,-.815),l(-.597,-.909),l(-.04,-.228),l(.095,-.213),l(.407,.029),l(.568,.197),l(.402,.91),M(106.858,78.207),l(-1.872,-1.166),l(-.566,-.555),l(.01,-.467),l(-.559,-.843),l(.071,-.106),l(.456,.06),l(.274,.256),l(1.165,.48),l(.086,.196),l(-.059,.136),l(-.149,.226),l(.296,.436),l(.839,.374),l(.007,.974),M(140.191,127.819),l(-.043,-.094),l(-.198,-.36),l(-.049,-.067),l(-.032,.042),l(-.028,.05),l(-.04,-.092),l(.002,-.664),l(-.331,-.604),l(-.472,-.451),l(-.661,-.451),l(-.512,-.197),l(-.114,-.052),l(-.145,.034),l(.002,.092),l(-.088,.025),l(-.1,-.042),l(-.146,-.143),l(.076,-.076),l(-.073,-.202),l(-.228,-.252),l(-.283,-.025),l(-.312,.084),l(-.932,-.336),l(-.286,-.328),l(-.428,-.244),l(-.383,.042),l(-.932,-.16),l(-.721,.051),l(-.12,-.185),l(-.234,-.067),l(-.046,-.177),l(.094,-.117),l(-.157,-.504),l(.133,-.464),l(-.227,-.096),l(-.127,.008),l(-.249,-.134),l(0,-.101),l(.075,-.093),l(-.029,-.219),l(-.347,-.185),l(-.254,-.286),l(-.415,-.219),l(-.391,-.623),l(-.202,-.076),l(-.203,-.311),l(-.409,-.219),l(-.156,-.529),l(-.002,-.227),l(.178,.007),l(.147,-.164),l(.029,-.326),l(-.208,-.251),l(-.192,-.045),l(-.22,.037),l(-.303,-.126),l(-.535,-.514),l(.078,-.21),l(-.091,-.312),l(-.129,-.067),l(-.044,-.463),l(.058,-.152),l(.119,-.025),l(.099,.067),l(.073,.076),l(-.086,.101),l(.153,.202),l(.285,.126),l(.116,.118),l(.203,.017),l(-.385,-.564),l(-.183,-.144),l(-.021,-.236),l(-.184,-.109),l(-.051,-.344),l(-.13,.006),l(-.011,.144),l(.048,.446),l(-.093,.017),l(-.293,-.194),l(-.119,.042),l(-.516,-.404),l(-.136,-.363),l(-.377,-.514),l(-.531,-.379),l(-.624,-.583),l(-.123,-.142),l(.114,-.101),l(-.327,-.751),l(.161,-.43),l(-.254,-.479),l(-.22,-.355),l(-.738,-.782),l(-.104,-.299),l(.099,-.627),l(.252,-.628),l(.166,-.357),l(.059,-.856),l(-.215,-.785),l(-.692,-1.486),l(-.153,-.916),l(.096,-.287),l(.231,-.244),l(.402,-.201),l(.365,-.717),l(-.365,-.573),l(-.066,-.33),l(.424,-1.593),l(.153,-.575),l(.061,-.634),l(.091,-.778),l(.019,-.179),l(-.153,-.16),l(.08,-.231),l(-.103,-.167),l(.157,-.077),l(-.03,-.186),l(-.046,-.186),l(-.031,-.103),l(-.004,-.058),l(.322,.096),l(.209,-.019),l(.062,-.097),l(-.211,.006),l(-.614,-.122),l(.062,-.707),l(-.103,-.328),l(.017,-.277),l(.587,-.225),l(-.345,-.019),l(-.16,-.142),l(-.129,0),l(-.053,.045),l(.042,.116),l(-.12,.052),l(-.133,-.979),l(-.927,-1.463),l(-.017,-.465),l(.129,-.131),l(.544,.086),l(.632,.217),l(.785,.114),l(.641,.028),l(.546,-.044),l(.415,.086),l(.547,.318),l(.039,.435),l(-.42,.407),l(-.413,.347),l(.532,.146),l(.184,.188),l(.251,.169),l(.029,-.228),l(.161,-.232),l(.393,-.305),l(.21,-.581),l(.102,-.465),l(-.064,-.421),l(-.356,-.958),l(-.158,-.305),l(-.655,-.516),l(.194,.013),l(2.579,.001),l(1.335,.022),l(4.588,-.025),l(3.938,.008),l(2.87,-.001),l(1.687,.006),l(5.117,-.028),l(.74,.011),l(4.13,.021),l(1.089,-.035),l(3.821,.023),l(.875,-.005),l(3.617,-.004),l(4.84,.018),l(.601,-.003),l(2.935,.014),l(2.131,-.012),l(2.781,.029),l(2.915,-.016),l(2.105,.003),l(1.348,-.007),l(2.798,.029),l(2.687,-.029),l(.68,.003),l(-.387,-.588),l(-.131,-.347),l(.501,-.036),l(.896,.748),l(.279,.371),l(.468,.46),l(.833,.451),l(.518,-.076),l(1.425,.208),l(.02,.185),l(.271,-.012),l(.338,.48),l(.16,-.247),l(.502,.013),l(.241,.271),l(.469,.086),l(.064,.185),l(.506,.098),l(.573,-.141),l(.219,-.06),l(.412,-.191),l(.373,-.075),l(.028,.282),l(.197,.116),l(.855,-.083),l(.474,.041),l(.156,.115),l(.196,.144),l(.542,-.049),l(.707,.074),l(1.469,-.592),l(.805,-.189),l(.797,.227),l(.977,.386),l(3.975,1.576),l(2.15,1.061),l(.101,.429),l(.46,.465),l(.628,-.024),l(.178,.135),l(.184,.294),l(.916,.181),l(.307,.235),l(-.11,.318),l(.26,.33),l(2.529,1.05),l(.876,3.16),l(.054,.545),l(-.028,.746),l(-.377,.576),l(-.294,.544),l(-.264,.433),l(-.414,.294),l(-.707,.525),l(-.044,.218),l(.012,.33),l(.371,.427),l(.497,.169),l(.573,.068),l(.524,-.117),l(.925,-.506),l(.939,-.478),l(.88,-.262),l(.919,-.062),l(.944,-.163),l(1.464,-.452),l(.875,-.427),l(-.047,-.362),l(-.16,-.471),l(-.018,-.319),l(.162,-.375),l(.47,-.203),l(.93,-.091),l(1.123,.01),l(1.305,.138),l(1.156,-.197),l(.44,-.275),l(.163,-.512),l(.146,-.434),l(.545,-.164),l(1.754,-.814),l(.534,-.305),l(.968,-.523),l(1.76,-.009),l(2.508,.029),l(1.855,.004),l(1.093,.095),l(.174,-.375),l(.363,-.435),l(.402,-.06),l(1.161,.124),l(1.139,-1.45),l(1.139,-2.22),l(.514,-.626),l(.632,-.526),l(.273,.085),l(.505,.36),l(.381,.085),l(.41,-.176),l(.771,.025),l(.488,.288),l(.174,.274),l(.31,2.819),l(-.077,.229),l(.606,.231),l(.224,0),l(.042,.154),l(-.143,.069),l(.02,.256),l(-.192,.077),l(.16,.291),l(.188,-.153),l(.349,.495),l(-.268,.281),l(.299,-.04),l(.171,.093),l(-.511,.374),l(-.509,.093),l(-.297,-.12),l(-.013,.253),l(-.138,.067),l(-.077,-.107),l(-.231,-.08),l(-.277,.133),l(-.101,.28),l(-.171,-.013),l(-.15,.16),l(-.175,-.347),l(-.746,.28),l(-.204,-.093),l(.12,.413),l(-.666,-.213),l(.199,-.48),l(-.149,-.04),l(-.364,.52),l(-.332,.56),l(-.342,.333),l(-.324,-.227),l(-.249,.439),l(-.346,-.08),l(.122,-.307),l(-.325,.253),l(.165,.16),l(-.326,.293),l(-.318,-.133),l(.105,-.226),l(-.654,.253),l(.065,.359),l(-.264,.04),l(-.161,.373),l(-.352,.106),l(-.333,.679),l(-.404,.505),l(.173,.146),l(.068,.212),l(.168,.053),l(.083,-.08),l(.169,.013),l(-.122,.146),l(-.547,.106),l(.053,.093),l(-.392,.292),l(-.068,.159),l(.337,.027),l(.282,.093),l(.599,.704),l(.055,.398),l(.399,.106),l(.691,-.239),l(-.022,-.186),l(-.14,-.027),l(-.254,-.279),l(-.097,-.04),l(-.009,-.066),l(.196,0),l(.23,.133),l(.218,.358),l(.031,.425),l(-1.599,.292),l(-.032,-.385),l(-.124,-.066),l(-.109,.226),l(-.164,.04),l(-.03,.093),l(-.105,-.106),l(-.159,.266),l(-.164,.04),l(-.294,.04),l(-.045,-.332),l(.198,-.332),l(-.443,.119),l(-.154,-.146),l(-.082,.252),l(-.087,.664),l(-1.429,.132),l(-1.694,.159),l(-1.182,.345),l(-.787,.358),l(-.097,.212),l(-.32,.053),l(-.144,.172),l(-.032,-.04),l(.308,-.756),l(.024,-.106),l(-.071,.027),l(-.41,.994),l(-.079,-.08),l(-.406,.292),l(.218,.318),l(.553,.093),l(-.46,1.515),l(-.302,.429),l(-.259,-.092),l(.043,.251),l(-.062,.185),l(-.237,.145),l(-.462,.501),l(-.292,.304),l(-.167,.026),l(-.075,-.119),l(.177,-.31),l(-.113,-.178),l(-.43,.013),l(-.447,-.343),l(-.148,-.053),l(-.329,-.541),l(.315,-.257),l(.151,-.245),l(-.271,.119),l(-.362,.37),l(.489,.845),l(.033,.356),l(.387,.581),l(.28,.066),l(.104,.765),l(-.101,.238),l(-.151,.23),l(-.125,-.013),l(-.487,.666),l(-.396,.798),l(.034,.053),l(-.13,.132),l(-.107,-.125),l(-.374,.725),l(.026,.125),l(-.226,.04),l(-.137,-.263),l(.342,-.864),l(.195,-.29),l(.247,-.119),l(.061,-.237),l(-.093,-.059),l(-.374,.119),l(.226,-.383),l(-.218,.04),l(-.176,-.093),l(.012,-.191),l(.242,-.04),l(-.077,-.33),l(-.439,.296),l(-.241,-.204),l(-.157,.053),l(-.23,-.396),l(.355,-.171),l(.357,-.053),l(-.005,-.06),l(-.604,-.316),l(-.092,.165),l(-.072,0),l(.107,-.323),l(.089,-.02),l(.21,.159),l(.131,-.06),l(-.098,-.224),l(-.353,-.066),l(-.065,-.112),l(.096,-.112),l(.336,.02),l(.193,-.284),l(-.281,.046),l(-.158,-.059),l(.241,-.37),l(.652,-.152),l(-.328,-.06),l(.146,-.409),l(-.28,.093),l(-.096,.132),l(.11,.079),l(-.315,.191),l(-.035,-.224),l(-.093,.053),l(.051,.224),l(-.081,.086),l(-.051,-.158),l(-.097,-.066),l(-.103,.416),l(-.447,-.079),l(.402,.501),l(-.294,.666),l(.07,.237),l(.272,.488),l(-.055,.139),l(-.466,-.317),l(-.1,-.211),l(.026,.205),l(.174,.218),l(.421,.237),l(.132,.508),l(-.631,-.402),l(-.354,-.007),l(-.118,-.283),l(-.155,-.053),l(.066,.25),l(-.541,-.323),l(-.33,.04),l(.015,-.29),l(.427,-.323),l(-.428,.079),l(-.19,.468),l(.204,.231),l(.457,.046),l(.202,.25),l(.954,.297),l(-.047,.092),l(.554,.165),l(.158,.132),l(-.22,.468),l(-.227,.06),l(-1.042,-.804),l(.708,.811),l(.626,.171),l(-.248,.092),l(.323,.079),l(-.045,.079),l(.061,.06),l(-.034,.25),l(-.312,-.191),l(-.071,.073),l(.104,.211),l(-.216,.02),l(-.656,-.56),l(-.023,.026),l(.419,.475),l(.309,.158),l(.182,-.026),l(.191,.21),l(.018,.31),l(-.298,.059),l(-.492,-.534),l(-.474,-.198),l(-.199,.16),l(.046,.044),l(.44,.145),l(.488,.382),l(-.047,.237),l(.442,-.033),l(.031,-.119),l(.748,.119),l(.151,.382),l(.406,1.212),l(.448,.803),l(-.14,-.092),l(-.262,-.349),l(-.059,-.132),l(-.359,-1.172),l(-.147,-.277),l(-.056,.31),l(.135,0),l(.034,.198),l(-.292,-.066),l(.173,.283),l(.144,.099),l(.228,.58),l(-.144,-.053),l(-.211,-.382),l(.002,.224),l(-.52,-.303),l(-.06,.059),l(.266,.303),l(-.247,.119),l(-.526,-.204),l(.225,.204),l(-.375,.211),l(-.173,-.02),l(-.251,-.21),l(-.024,-.217),l(.083,-.158),l(-.081,-.053),l(-.091,.204),l(.044,.23),l(.116,.211),l(-.107,.158),l(.894,.02),l(.571,-.145),l(.125,.165),l(-.113,.191),l(-.072,.369),l(.14,.066),l(.092,-.257),l(.135,-.369),l(.18,-.105),l(.266,.31),l(.047,.296),l(-.166,.25),l(-.163,-.013),l(-.063,-.099),l(-.316,.474),l(-.254,.197),l(-.483,-.053),l(-.203,-.065),l(-.147,-.066),l(-.136,-.245),l(-.151,.014),l(.141,.244),l(-.075,.013),l(-.538,-.125),l(-.436,-.151),l(.162,.185),l(.269,.026),l(.833,.335),l(-.034,.119),l(-.396,.145),l(.247,.007),l(-.19,.25),l(-.281,.138),l(-.149,0),l(-.481,-.375),l(.242,.395),l(.43,.164),l(.302,-.171),l(.292,.026),l(.11,-.204),l(.04,.178),l(.217,.04),l(.048,.079),l(-.428,.322),l(-.013,.085),l(-.261,.072),l(-1.498,.214),l(-.865,.895),l(-.487,.609),l(-.13,.127),l(-.935,.143),l(-.528,.128),l(-.617,.241),l(-.678,.539),l(-.225,.424),l(-.096,.354),l(-.819,.694),l(-.693,.383),l(-.429,.199),l(-.797,.086),l(-.35,.58),l(-.177,.198),l(-.809,1.125),l(-.273,.781),l(-.459,1.249),l(.236,1.455),l(.387,.925),l(.456,.873),l(.934,1.562),l(.352,1.746),l(.486,1.194),l(-.075,.092),l(.287,.276),l(.123,.333),l(.062,.827),l(-.301,1.536),l(-.064,.278),l(-.31,.415),l(.108,.424),l(-.02,.252),l(-.393,.551),l(-.017,-.092),l(.129,-.241),l(-.025,-.138),l(-.256,.035),l(-.38,.137),l(-.291,-.126),l(-.509,.138),l(-.12,-.329),l(.014,-.233),l(-.567,-1.068),l(-.764,-.138),l(-.204,-.352),l(-.113,-.819),l(-.423,-.229),l(-.144,-.702),l(-.373,.093),l(-.608,-1.08),l(-.375,-.482),l(.296,0),l(.375,-.438),l(.048,-.226),l(-.167,-.226),l(-.471,.407),l(-.277,-.208),l(.126,-.573),l(.147,-.758),l(.158,-1.043),l(-.293,-.452),l(-.258,-.169),l(-.496,-.126),l(-.832,-.987),l(-.875,-.804),l(-.528,-.168),l(-.43,.072),l(-.536,.298),l(-.456,.354),l(-1.202,.299),l(-.273,-.213),l(-.131,-.62),l(-.253,-.254),l(-.264,-.113),l(-.752,-.069),l(-.516,-.296),l(-.22,-.233),l(-.504,.138),l(-1.052,.115),l(-.653,-.184),l(-.047,.298),l(-.64,.099),l(-.183,0),l(-.578,-.926),l(-.238,.781),l(-.447,-.135),l(-.65,.001),l(-1.328,-.04),l(-.672,.439),l(-.39,.055),l(-1,-.459),l(-.096,.009),l(-.142,.014),l(-.362,.528),l(.201,.229),l(.303,0),l(.211,0),l(.537,-.207),l(.406,.092),l(.676,.482),l(-.68,.373),l(.02,.254),l(.263,.353),l(.593,.146),l(.229,.217),l(.35,.334),l(-.533,.136),l(-.503,-.084),l(-.276,-.419),l(-.79,-.271),l(-.224,-.211),l(-.265,-.056),l(-.013,.02),l(-.209,.32),l(.209,.154),l(.248,.183),l(-.248,.179),l(-.069,.05),l(-.447,-.459),l(-.476,.192),l(-.287,.291),l(-1.025,-.472),l(-.419,-.494),l(-1.16,-.642),l(-.615,.066),l(.554,.393),l(-.307,.187),l(-1.17,-.083),l(-.886,-.252),l(-.896,-.168),l(-1.547,.173),l(-.632,.328),l(-.392,-.015),l(-.433,-.031),l(-.135,-.49),l(-.333,.057),l(-.112,.184),l(.474,.731),l(-.877,.64),l(-.808,.577),l(-.915,.317),l(-.419,.043),l(-.414,-.056),l(-.728,-.111),l(-.126,.198),l(.437,.437),l(-.239,.396),l(-.327,.199),l(-.631,.114),l(-.737,.27),l(-.268,.17),l(.558,.352),l(.111,.169),l(-.659,.694),l(-.154,.297),l(-.012,.848),l(.144,.636),l(.271,.762),l(.425,.903),l(-.347,-.119),l(-.816,-.377),l(-.296,.001),l(-.416,.116),l(-.264,-.069),l(-1.029,-.56),l(-.921,-.32),l(-.375,-.365),l(-.336,-.592),l(-.332,-.932),l(-.078,-.467),l(-.268,-.253),l(-.657,-.576),l(-.845,-1.042),l(-.744,-1.227),l(-.663,-1.029),l(-.363,-.366),l(-.412,-.252),l(-.783,-.321),l(-.475,-.082),l(-.643,.018),l(-.468,.201),l(-.576,.541),l(-.418,.413),l(-.283,.37),l(-.416,.158),l(-.501,-.011),l(-.337,-.069),l(-1.104,-.503),l(-1.092,-.659),l(-.445,-.549),l(-.318,-.847),l(-.284,-.678),l(-.179,-.226),l(-.708,-.491),l(-.837,-.519),l(-.766,-.632),l(-.631,-.662),l(-.209,-.112),l(-1.892,-.046),l(-1.858,-.003),l(-.096,.892),l(-.213,.101),l(-1.867,.011),l(-.966,-.037),l(-1.544,-.02),l(-1.662,-.019),l(-.338,-.055),l(-3.516,-1.112),l(-2.811,-.933),l(-1.186,-.39),l(-.267,-.154),l(-.316,-.31),l(-2.381,.084),l(-2.367,.155),l(-.34,.017),M(49.818,152.776),l(-.122,.086),l(-.279,.03),l(-.111,-.131),l(-.177,-.005),l(-.324,.051),l(-.304,-.39),l(-.071,-.263),l(.339,-.01),l(.299,-.253),l(.188,.218),l(.106,.294),l(.223,.096),l(.233,.279),M(52.785,154.312),l(-.155,-.081),l(-.085,-.356),l(-.461,-.321),l(.095,-.229),l(.143,-.058),l(.366,.209),l(.344,.055),l(.616,.356),l(-.005,.172),l(-.294,.184),l(-.563,.069),M(111.683,77.224),l(-.138,.415),l(-.45,.067),l(-.324,.113),l(-.295,.247),l(-.321,-.137),l(-.185,-.21),l(.087,-.443),l(.086,-.443),l(-.438,-.675),l(-.463,-.319),l(-.199,-.271),l(-1.281,.055),l(-.437,.098),l(-.153,.161),l(-.496,.097),l(-.019,-.193),l(-.034,-.432),l(.212,-.272),l(.184,-.212),l(-.378,-.347),l(-.641,-.438),l(-.693,-.696),l(-.723,-.317),l(-.453,-.136),l(.132,-.35),l(-.569,-.592),l(-.099,-.213),l(.371,-.229),l(-.068,-.122),l(-.301,-.152),l(-.445,-.076),l(-.392,-.274),l(-.237,-.259),l(-.57,-.305),l(-1,-.411),l(-.479,-.765),l(-.217,-.583),l(-.367,-.399),l(-.357,.016),l(-.101,.814),l(.42,.873),l(.104,.306),l(-.047,.153),l(-.701,-.136),l(-.272,-.076),l(-.511,-.504),l(-.4,-.459),l(-.537,.139),l(-1.219,-.228),l(1.263,.718),l(.032,.214),l(-1.62,.171),l(-1.093,-.35),l(-1.388,-.948),l(-.543,-.292),l(-.664,-.043),l(-.079,0),l(-.933,-.213),l(-1.3,-.536),l(.928,-.248),l(.135,-.169),L(90.8,67.129),l(-.384,-.153),l(-.792,.156),l(-.454,.14),l(-.656,.017),l(-1.058,-.06),l(-1.068,-.245),l(.027,-.247),l(-.148,-.186),l(-.325,-.108),l(-.359,.016),l(-.47,.202),l(-1.036,.049),l(-1.465,-.122),L(80.46,66.64),l(-.786,-.091),l(-.248,-.108),l(-.651,-.387),l(-.427,-.527),l(-.301,.218),l(-.788,.157),l(-.89,-.293),l(-.234,-.326),l(-.417,-.139),l(-.872,-.248),l(-1.538,-.23),l(-.817,-.248),l(-.671,-.342),l(-.553,.235),l(-.675,.079),l(.06,.437),l(-.193,.062),l(-.389,.25),l(-.249,.405),l(1.119,.293),l(.174,.294),l(-.096,.388),l(-.428,.449),l(-.458,.001),l(-.804,-.214),l(-.586,-.061),l(-.568,.094),l(-.978,.603),l(-1.066,.217),l(-.936,.448),l(-1.035,.448),l(-1.095,.109),l(.178,-.308),l(.063,-.123),l(.72,-.401),l(-.093,-.385),l(-.655,-.523),l(.004,-.108),L(64.1,66.19),l(.411,-.482),l(.157,-.42),l(.736,-.312),l(.87,-.235),l(1.165,-.018),l(1.085,.123),l(.239,-.156),l(-1.239,-.466),l(-.971,-.389),l(-1.043,.049),l(-.226,.219),l(-.449,.095),l(-.573,.438),l(-.865,.375),l(-1.019,.282),L(61.553,65.9),l(-.406,.094),l(-.298,.14),l(.131,.325),l(-.177,.526),l(-.563,.34),l(-.564,.078),L(59,67.544),l(-.592,.278),l(-.681,.601),l(-.035,.292),l(.38,.168),l(.36,.03),l(.667,.106),l(.465,.229),l(-.075,.184),l(-.43,.338),l(-.625,.2),l(-.557,.277),l(-.423,.398),l(-.544,.383),l(-.675,.093),l(-1.434,.308),l(-.678,.397),l(-1.036,.337),l(-.7,.367),l(.52,.5),l(-.1,.167),l(-1.106,.412),l(-.897,.153),l(-.778,.168),L(49.51,74.19),l(-1.214,.456),L(48.1,74.828),l(-.274,.394),l(-.753,.439),l(-1.193,.229),l(-1.234,.184),l(-.973,-.345),l(.001,-.181),l(.332,-.348),l(.763,-.273),l(.306,-.212),l(.445,-.364),l(1.171,-.441),l(1.403,.073),l(-.12,-.212),l(.02,-.516),l(.47,-.304),l(.725,-.291),l(.754,-.366),l(.266,-.214),l(.002,-.731),l(.246,-.749),l(.693,-.49),l(.194,-.398),l(.034,-.412),l(-.633,.122),l(-1.251,.186),l(-.676,-.029),l(-.5,-.597),l(-.266,.062),l(-.613,.216),l(-.136,.23),l(.239,.352),l(.021,.352),l(-.169,.046),L(47,70.115),l(-.567,-.32),l(-.487,-.397),l(-.509,-.291),l(-.56,-.03),l(-.812,-.106),l(-.91,.094),l(.028,.138),l(-.644,.338),l(-1.175,.14),l(-.649,-.09),l(-.064,-.123),l(-.082,-.107),l(-.125,-1.028),l(.3,-.508),l(-.142,-.431),l(-.864,-1.002),l(-1.43,.437),l(-.738,.078),l(-.406,.202),l(-1.091,.094),l(-.4,-.23),l(-.394,-.355),l(-.466,-.325),l(-1.007,-.463),l(-.179,-.28),l(.292,-.171),l(.337,-.437),l(.704,.139),l(1.312,.309),l(.69,.03),l(.238,-.234),l(-.375,-.482),l(-.458,-.264),l(-.363,0),l(-.541,.22),l(-.528,-.015),l(-1.342,-.513),l(-.623,-.186),l(-.197,.016),l(-.858,-.029),l(-.024,-.078),l(-.623,-.985),l(.79,-.19),l(.071,-.456),l(.495,-.221),l(.102,-.299),l(.227,-.347),l(.893,-.491),l(.337,-.38),l(.386,-.301),l(.527,-.476),l(.39,-.175),l(.719,.109),l(.98,.268),l(.485,.094),l(.752,-.144),l(.427,-.254),l(.675,-.429),l(1.252,-.257),l(.774,-.033),l(.955,-.049),l(.354,-.175),l(.187,-.478),l(-.259,-.669),l(-.814,-.686),l(.026,-.096),l(.927,-.034),l(.343,-.256),l(-.25,-.384),l(-.497,-.256),l(-.367,-.08),l(-1.88,.389),L(39.33,56.53),l(-.534,.289),l(-.496,.065),l(-1.907,-.333),l(-.848,-.031),L(34.8,56.49),l(-1.27,.162),l(-1.265,-.029),l(-1.349,-.174),l(-.53,-.207),l(-.183,-.788),l(.144,-.146),l(.636,-.033),l(1.008,-.002),l(.446,-.179),l(-1.057,-.241),l(-1.912,-.304),L(28.13,54.31),l(-1.285,-.208),l(.219,-.114),l(.781,-.262),l(1.568,-.214),l(1.325,-.328),l(.958,-.214),l(1.058,-.361),l(.953,-.23),l(1.399,-.281),l(1.513,.128),l(-.158,.523),l(.023,.277),l(1.051,.161),l(1.359,.095),l(1.074,-.019),l(.657,-.099),l(.784,-.246),l(.55,-.295),l(.262,-.083),l(.752,.064),l(.751,.113),l(1.021,-.051),l(.2,-.327),l(.007,-.18),l(-.689,-.064),l(-1.946,-.292),l(-1.283,-.047),l(-.312,-.755),l(-1.473,-.162),l(-.96,-.031),l(-1.573,-.096),l(-.194,-.511),l(-.484,-.312),l(-1.042,-.461),l(-.512,-.148),l(-2.66,-.659),l(-2.008,-.545),l(.317,-.167),l(.812,-.402),l(.086,-.485),l(2.136,-.054),l(.99,-.069),l(1.829,-.288),l(.784,-.354),l(.452,-.623),l(.788,-.575),l(.616,-.525),l(.818,-.41),l(.742,-.224),l(1.066,-.104),l(1.133,-.241),l(1.047,-.036),l(1.804,.065),l(.146,-.188),l(-.156,-.205),L(44.47,42.83),l(.018,-.206),l(1.936,-.089),l(1.143,.032),l(.974,-.054),l(1.344,-.14),l(1.098,-.416),l(.918,-.417),l(.957,-.019),l(.282,.051),l(.675,.241),l(.156,.172),l(-.383,.139),l(.017,.344),l(1.049,.136),l(.424,.034),l(.536,-.293),l(.297,-.208),l(1.419,.187),l(1.534,.049),l(1.062,.049),l(.715,.033),l(.711,.257),l(.359,.274),l(.783,.358),l(.494,.085),l(.421,-.086),l(1.292,.117),l(1.124,.015),l(1.556,-.054),l(1.449,-.088),l(1.213,.1),l(1.377,.254),l(.883,.118),l(3.424,.13),l(1.279,.168),l(.743,.169),l(2.027,-.038),l(2.339,-.141),l(1.123,.236),l(2.441,.791),l(1.206,.301),l(.227,.008),l(.102,.483),l(-.003,2.855),l(.039,2.259),l(.052,2.335),l(.129,2.796),l(-.026,2.183),l(-.043,4.334),l(.026,2.167),l(.089,1.046),l(.196,.279),l(.84,.074),l(2.424,-.122),l(.739,.059),l(.332,.388),l(.173,.387),l(.348,.292),l(2.162,1.318),l(.945,.673),l(.238,-.325),l(.848,-.205),l(1.225,-.67),l(.731,-.498),l(.495,-.126),l(.832,.073),l(.316,.199),l(.371,.492),l(.35,.322),l(2.048,1.175),l(.814,.58),l(1.769,1.768),l(1.67,1.882),l(.512,.393),l(.189,.029),l(.98,.314),l(2.025,.763),l(.402,.255),l(-.163,.788),l(.393,.777), +N(643.755,159.873),l(-1.092,-.52),l(-.637,-.337),l(-.203,-1.284),l(.036,-.282),l(.24,-.241),l(.42,-.241),l(.721,-.623),l(.493,.056),l(.049,-.17),l(.24,-.396),l(.239,.028),l(.573,.225),l(.321,-.312),l(.439,-.001),l(.798,-.171),l(.596,.69),l(-.163,.17),l(-.443,.354),l(-.412,.538),l(-.285,.734),l(.14,.296),l(-.22,.311),l(-.292,.085),l(-1.026,.383),l(-.532,.707),M(627.173,150.012),l(-.679,.314),l(-.24,.241),l(-.043,.325),l(.138,.592),l(.228,.366),l(.119,.521),l(-.109,.339),l(-.266,.213),l(-.769,-.08),l(-.321,-.21),l(-.178,-.196),l(-.153,-.239),l(-.111,-.38),l(-.628,.413),l(-.647,.159),l(-.246,-.083),l(-.378,-.266),l(-.341,-.746),l(-.291,-.379),l(-.481,.045),l(-.507,.003),l(-.228,-.098),l(-.117,-.352),l(.729,-1.584),l(-.033,-.268),l(-.521,-.096),l(-.554,.074),l(-.202,-.324),l(-.277,-1.762),l(-.156,-.126),l(-.479,.017),l(-.771,.089),l(-.819,.442),l(-.312,.086),l(-.216,-.069),l(0,-.268),l(.224,-.58),l(-.163,-.705),l(-.075,-.465),l(.617,-.85),l(.191,-.198),l(.487,-.271),l(.611,-.525),l(.429,-.722),l(.353,-.862),l(-.02,-.875),l(-.195,-1.649),l(-.146,-.14),l(-.504,.031),l(-.287,-.041),l(-.217,-.309),l(-.243,-.901),l(-.397,-.435),l(-.504,-.279),l(-.277,.044),l(-.306,.34),l(-.001,.127),l(-.624,-.081),l(-.73,-.179),l(-.657,-.081),l(-.3,-.055),l(-.102,-.056),l(.138,-.269),l(.354,-.454),l(-.046,-.38),l(-.716,-.715),l(-.455,-.392),l(-1.377,.84),l(-.377,.044),l(-.975,-.319),l(-.286,-.167),l(-.355,.087),l(-.546,.299),l(-1.105,.726),l(-.829,.258),l(-.543,.37),l(-1.123,1.107),l(-.397,.27),l(-.714,.216),l(-.784,.033),l(-.189,.1),l(-.329,-.619),l(-.312,-.209),l(-.371,-.041),l(-1.659,-.047),L(601,137.538),l(-.309,-.294),l(-.417,.016),l(-.149,.103),l(-.348,.239),l(-.609,.539),l(-1.251,1.545),l(-.212,-.662),l(.052,-.861),l(-.139,-.183),l(-.231,-.069),l(-.471,.102),l(-.345,.129),l(-.655,-.159),l(-.339,.281),l(-.341,-.116),l(-.849,.066),l(-.319,-.364),l(-.63,-.281),l(-.407,0),l(-.08,.331),l(-.271,.083),l(-.685,-.38),l(.01,.364),l(-.237,.099),l(-.141,-.463),l(-.54,-.496),l(-.365,.066),l(-.935,-.066),l(-.014,-.265),l(.175,-.396),l(-.326,-.017),l(-.333,.248),l(-1.451,-.893),l(.069,-.281),l(-.178,-.38),l(-.289,-.166),l(-.71,.116),l(-.158,.166),l(-.657,-.794),l(-.454,-.281),l(-.15,.132),l(-.472,-.215),l(-.726,-.595),l(-.867,-.264),l(-.132,-.612),l(-1.079,-.199),l(-.186,.182),l(-.275,-.066),l(-.134,.513),l(-.276,.314),l(-.299,-.05),l(-.24,-.43),l(-.859,-.596),l(-.154,.066),l(-.756,-.248),l(.116,-.364),l(-1.078,-.579),l(-.363,.116),l(-.772,-.843),l(-.383,-.248),l(-.477,.314),l(-.198,-.066),l(-.099,-.43),l(.215,-.215),l(-.272,-.364),l(.104,-.446),l(-.579,-.595),l(-.157,-.694),l(.785,-.198),l(.033,.364),l(.337,.264),l(.368,-.049),l(.376,-.281),l(.578,-.364),l(-.367,-.694),l(.104,-.414),l(-.68,-.099),l(-.044,-.182),l(-.092,-.078),l(-.718,-.096),l(-.294,-.221),l(-.037,-.552),l(-.073,-.589),l(.184,-.184),l(.331,-.221),l(-.221,-.258),l(-.441,-.405),l(-.81,-.11),l(-.221,-.515),l(-.441,-1.03),l(0,-.515),l(-.502,.152),l(-.147,-.126),l(-.305,-.111),l(-1.337,-.104),l(-.565,-.436),l(-.178,-.09),l(-.104,-.199),l(-.239,0),l(-.52,.196),l(-.252,-.281),l(-.198,-.218),l(-.301,-.07),l(.312,-.516),l(-.007,-.501),l(-.213,-.247),l(-.373,-.323),l(-.625,.009),l(-.282,.128),l(-.004,-.456),l(-.554,-.117),l(-.296,-.047),l(-.281,.21),l(-.105,-.112),l(-.313,-.14),l(-.048,-.088),l(-.236,-.012),l(-.01,-.269),l(.574,.059),l(.192,-.145),l(.354,-.136),l(.08,-.249),l(.181,-.185),l(-.2,-.163),l(.152,-.36),l(-.245,-.237),l(.126,-.428),l(-.049,-.123),l(-.152,-.012),l(-.028,-.246),l(.009,-.284),l(-.295,-.494),l(-.273,-.154),l(-.692,-.039),l(-.22,-.06),l(-.229,.162),l(-.463,.045),l(-.325,-.394),l(-.077,-.305),l(.207,-.223),l(-.023,-1.031),l(.011,-.069),l(.139,-.739),l(.129,-.213),l(.274,-.186),l(1.422,-.704),l(1.737,-.734),l(.359,-.03),l(.06,.071),l(.183,.567),l(.344,.055),l(.507,-.145),l(.885,-.132),l(.268,-.243),l(.463,-.784),l(.467,-.472),l(.238,-.03),l(1.248,.235),l(.459,-.017),l(.478,-.102),l(.646,-.345),l(.638,-.701),l(.405,-.301),l(.445,-.145),l(1.338,-.349),l(.97,-.219),l(.325,-.187),l(.051,-.157),l(-.031,-.194),l(-.139,-.86),l(.02,-.399),l(.32,-.401),l(.705,-.546),l(.222,-.33),l(-.119,-.47),l(-.29,-.441),l(-.345,-.627),l(-.03,-1.357),l(-.483,-.141),l(-.366,.06),l(-.232,-.185),l(.068,-.215),l(.215,-.302),l(.393,-.188),l(1.799,-.254),l(1.082,-.207),l(.35,-.06),l(.5,.184),l(1.133,.238),l(.394,-.074),l(.231,-.145),l(.156,-.245),l(-.126,-.286),l(-.622,-.514),l(.137,-.418),l(.286,-.605),l(.438,-.794),l(.516,-1.141),l(.427,-.507),l(1.096,.254),l(.721,.141),l(.594,.141),l(1.402,.079),l(.718,-.062),l(.417,-.103),l(.444,-.392),l(.157,-.39),l(-.213,-.707),l(-.097,-.75),l(.34,-.581),l(.428,-.277),l(1.199,-.093),l(.289,-.06),l(.306,-.219),l(.035,-.478),l(.011,-.275),l(.279,-.262),l(.542,-.148),l(.551,-.034),l(.228,-.014),l(.569,-.003),l(.244,-.074),l(.062,.145),l(.131,.405),l(.24,.563),l(.371,.433),l(1.301,.745),l(.834,.415),l(.614,.069),l(.731,.167),l(.633,.144),l(.354,.143),l(.568,.618),l(1.07,1.451),l(.401,.66),l(-.215,.447),l(-.237,.75),l(-.214,.389),l(-.369,.347),l(-.035,.129),l(.105,.43),l(.233,.229),l(.724,.312),l(1.062,.181),l(1.505,.021),l(.995,.038),l(.668,.083),l(.998,.224),l(.632,.268),l(1.645,.806),l(.839,.31),l(.744,.096),l(.105,.542),l(1.571,2.161),l(.467,.439),l(.444,.254),l(1.979,.018),l(1.241,.207),l(.802,.109),l(1.165,.022),l(2.861,-.059),l(.937,.023),l(1.164,.022),l(1.69,.119),l(.521,.168),l(.815,.551),l(1.006,.365),l(1.599,.433),l(.929,.123),l(.663,-.061),l(.61,.067),l(.253,.297),l(.433,.197),l(.481,-.017),l(.686,-.289),l(1.44,-.534),l(.303,-.101),l(.736,-.274),l(.816,-.289),l(1.204,-.349),l(1.339,-.007),l(1.514,-.065),l(.987,.08),l(.651,-.061),l(1.941,-.737),l(.265,-.172),l(1.111,-1.046),l(.67,-.389),l(1.265,-.292),l(.326,-.259),l(.123,-.271),l(-.188,-.228),l(-.599,-.411),l(-.389,-.569),l(-.003,-.343),l(.214,-.401),l(.539,-.589),l(.457,-.231),l(.316,-.073),l(.718,.154),l(.668,.382),l(.592,.125),l(.982,-.005),l(.744,-.047),l(.742,-.433),l(1.192,-.91),l(.224,.013),l(.438,.012),l(.624,.054),l(.896,-.134),l(.638,-.248),l(.347,-.188),l(.241,-.216),l(.312,-.82),l(.363,-.333),l(.47,-.204),l(.464,-.045),l(.483,.127),l(.353,-.189),l(.831,-.278),l(.539,-.146),l(.937,-.221),l(.854,-.033),l(.432,.099),l(1.074,.008),l(.464,.127),l(.414,-.218),l(.107,-.217),l(-.048,-.273),l(-.599,-.501),l(-.879,-.99),l(-.797,-.5),l(-.538,-.199),l(-.928,-.212),l(-.438,.002),l(-1.191,.786),l(-.292,-.07),l(-.431,-.416),l(-.317,-.085),l(-.576,.018),l(-.754,.062),l(-.929,.395),l(-.342,.045),l(-.051,-.029),l(-.269,-.836),l(.381,-.58),l(1.224,-1.959),l(.687,-1.207),l(.295,-.31),l(.046,.018),l(.452,.172),l(1.126,.574),l(.343,-.016),l(.438,-.089),l(2.44,-.752),l(.779,-.339),l(.123,-.233),l(-.056,-.306),l(-.35,-.348),l(-.062,-.146),l(.103,-.249),l(.422,-.426),l(.416,-.543),l(.667,-.779),l(.599,-.545),l(1.371,-.608),l(.167,-.794),l(-.107,-.249),l(-.465,-.306),l(-.558,-.026),l(-.822,.078),l(.119,-.25),l(.375,-.282),l(1.193,-.787),l(.478,-.165),l(.602,-.136),l(1.854,-.143),l(.836,-.123),l(1.203,-.109),l(.917,-.049),l(1.148,.215),l(1.037,.481),l(.683,.188),l(1.386,-.125),l(.539,.026),l(.763,.467),l(.742,.952),l(1.087,2.384),l(.94,1.588),l(.927,1.903),l(.436,.389),l(.507,.2),l(1.247,.341),l(1.523,.253),l(2.659,.839),l(.205,.144),l(.297,.866),l(.44,1.283),l(.261,.446),l(.68,-.033),l(.649,-.018),l(1.657,-.052),l(.604,-.22),l(.953,-.308),l(1.357,-.31),l(1.181,-.208),l(.902,-.034),l(.246,.114),l(.064,.259),l(.116,.389),l(.017,.504),l(-.566,.407),l(-.66,.393),l(-.291,.707),l(-.278,.893),l(-.538,1.066),l(-.627,1.08),l(-.329,.432),l(-.551,.69),l(-.47,.347),l(-.547,-.098),l(-.679,-.225),l(-.685,-.24),l(-.396,-.041),l(-1.664,.982),l(-.048,.557),l(.332,.897),l(.062,.656),l(-.006,.613),l(-.025,.385),l(-.097,.128),l(.112,.299),l(-.156,.329),l(-.511,.43),l(-1.252,.462),l(-.111,.058),l(-.579,-.68),l(-.247,.001),l(-.253,.129),l(-.383,.358),l(-.23,.713),l(-.955,.532),l(-.62,.259),l(-.538,.017),l(-.452,-.054),l(-.333,-.126),l(-.392,.059),l(-.273,.243),l(-.025,.342),l(.508,.765),l(.046,.113),l(-.527,.159),l(-.975,.048),l(-.508,-.153),l(-.493,-.253),l(-.273,-.396),l(-.448,.017),l(-.386,.13),l(-.686,1.027),l(-.636,.543),l(-1.032,.545),l(-1.533,.604),l(-.52,.329),l(-.415,.442),l(-.379,.528),l(-.066,-.092),l(-.417,.171),l(-1.222,.13),l(-.728,.171),l(-2.248,.925),l(-.632,.37),l(-.566,.469),l(-.604,.271),l(-.336,.015),l(.13,-.255),l(.862,-.682),l(.33,-.354),l(-.47,-.113),l(-.37,.072),l(-.153,-.297),l(.058,-.156),l(.953,-.781),l(.269,-.384),l(.55,-.413),l(.159,-.2),l(-.057,-.298),l(-.73,-.553),l(-.727,-.283),l(-.131,-.014),l(-.628,.03),l(-.166,.015),l(-.494,.371),l(-1.146,1.183),l(-.355,.157),l(-.643,.086),l(-.613,.243),l(-.36,.199),L(665.49,112),l(-.136,.411),l(-.131,.255),l(-.251,.255),l(-.437,.128),l(-.493,-.013),l(-.326,.27),l(-.307,.114),l(-.455,-.565),l(-.355,-.014),l(-.349,.128),l(-.396,.638),l(-.301,.694),l(.088,.34),l(.245,.368),l(.558,.268),l(.8,.268),l(1.21,-.045),l(.29,.254),l(-.019,.538),l(-.123,.581),l(.057,.538),l(.261,.283),l(.733,.069),l(.698,-.157),l(.76,-.525),l(.509,-.497),l(.552,-.228),l(.534,-.128),l(.287,.07),l(.895,.621),l(.543,.197),l(1.023,-.087),l(.361,.027),l(.471,.141),l(.274,0),l(-.248,.708),l(-.057,.552),l(-.612,-.197),l(-.297,-.084),l(-.525,.058),l(-1.677,.555),l(-.707,.44),l(-.072,.735),l(-.522,.157),l(-.146,-.113),l(-.017,-.269),l(-.127,-.084),l(-.501,.114),l(.138,.466),l(-.152,.368),l(-.485,.496),l(-1.397,1.119),l(-.126,.226),l(.039,.55),l(.62,.225),l(.712,.492),l(.785,.521),l(.391,.535),l(.424,1.241),l(.668,.647),l(.175,.437),l(-.13,.677),l(.172,.183),l(.694,.295),l(.399,.592),l(.562,.253),l(.272,.268),l(.087,.31),l(-.049,.155),l(-.789,.369),l(.088,.07),l(.425,.31),l(.314,.79),l(-.019,.296),l(-.141,.184),l(-.534,.043),l(-.651,.213),l(-.948,.552),l(-.849,.213),l(-.629,.297),l(.72,.21),l(.378,.056),l(.944,-.425),l(.488,-.058),l(.162,.056),l(.524,.592),l(.387,.168),l(.456,.027),l(.009,.155),l(-.231,.311),l(-.382,.227),l(-.304,.241),l(.11,.155),l(.326,-.029),l(.202,.084),l(-.184,.325),l(-.298,.749),l(-.192,.649),l(.028,.353),l(-.22,.452),l(-.209,.127),l(-.35,-.338),l(-.146,.142),l(-.569,.763),l(-.401,.622),l(-.215,.622),l(-.127,.296),l(-.595,.425),l(-.251,.438),l(-.254,.184),l(-.569,.029),l(-.382,.227),l(.279,.719),l(-.264,.508),l(.076,.593),l(-.093,.269),l(-.207,.269),l(-.532,.199),l(-.161,.282),l(-.174,.396),l(-.294,.636),l(-.626,.354),l(-.412,.495),l(-.492,-.14),l(-.443,-.069),l(-.142,.113),l(-.145,.198),l(.118,.833),l(-.213,.142),l(-.772,.651),l(-.356,.127),l(-.628,.171),l(-.563,.467),l(-.571,.213),l(-.107,.113),l(-.008,.48),l(-.133,.156),l(-.568,.058),l(-.5,.114),l(-.341,.438),l(-.364,-.126),l(-.52,-.168),l(-.274,.057),l(-.315,.326),l(-.435,.198),l(-.643,.1),l(-.047,-.465),l(-.52,.057),l(-.699,.213),l(-.32,.198),l(-.285,-.042),l(-.401,-.493),l(-.163,-.155),l(-.191,.283),l(.095,.169),l(-.045,.212),l(-.047,.691),l(-.209,.297),l(-.416,.114),l(-.501,-.182),l(-.123,.282),l(-.001,.24),l(-.146,.155),l(-.615,.058),l(-.366,.114),l(-.596,.043),l(-.463,-.211),l(-.217,.1),l(-.439,.48),l(-.227,.071),l(-.774,-.041),l(-.747,.227),l(-.406,.326),l(-.451,-.027),l(-.277,-.084),l(-.011,.057),l(-.069,.353),l(-.29,.396),l(.011,.113),l(.48,.634),l(.269,.126),l(.043,.198),l(-.36,.269),l(-.763,.157),l(-.481,-.719),l(-.241,-.691),l(.012,-.395),l(.396,-.777),l(-.015,-.169),l(-.587,-.253),l(-.226,.071),l(-.206,.297),l(-.454,.072),l(-.676,-.21),l(-.574,-.733),l(-.196,.085),l(-.017,.169),l(-.159,.396),l(-.27,.128),l(-.332,-.056),l(-.481,.043),l(-.055,.038),l(-.197,-.143),l(-.909,-.107),l(-.621,-.166),l(-.943,-.615),l(-.273,-.365),l(-.096,-.521),l(.472,-.75),l(-.056,-.38),l(-.237,-.21),l(-.777,.047),l(-.66,-.053),l(-.771,-.235),l(-.623,-.575),l(-.298,.101),l(-.521,.328),l(-.696,.554),l(-.341,.157),l(-.807,.117),l(-1.595,.052),l(-.332,.115),l(-.584,.413),l(-.325,-.097),l(-.597,-.392),l(-.341,-.012),l(-.515,.13),l(-.483,.229), +N(241.073,156.152),l(.017,.52),l(.098,1.215),l(.012,.212),l(-.379,.455),l(-.011,.17),l(.485,1.358),l(-.669,-.577),l(-.445,-.056),l(-.761,.143),l(-.877,-.012),l(-.666,-.14),l(-.574,-.056),l(-.474,.1),l(-.378,.354),l(-.135,-.042),l(-.993,-.549),l(-.171,-.325),l(.04,-.198),l(.269,-.184),l(1.051,.097),l(.631,.111),l(1.125,.167),l(.654,.041),l(.61,-.185),l(.386,-.156),l(-.198,-.155),l(-.692,-.464),l(-.136,-.296),l(.184,-.707),l(-.202,-.296),l(-.394,-.154),l(-.913,-.14),l(-.305,-.211),l(.04,-.184),l(.119,-.085),l(.344,-.1),l(.724,-.058),l(.781,.125),l(1.081,.294),l(.576,.056),l(.147,-.089), +N(241.295,160.082),l(-.485,-1.358),l(.011,-.17),l(.379,-.455),l(-.012,-.212),l(-.098,-1.215),l(-.017,-.52),l(.503,-.279),l(.393,.14),l(.342,0),l(.384,-.17),l(.369,-.043),l(.14,.198),l(.177,.112),l(1,.309),l(.657,-.072),l(.213,.395),l(.335,.338),l(.528,.324),l(.335,.084),l(.643,.21),l(.916,.45),l(.399,.352),l(.231,.311),l(-.191,.17),l(-.144,.297),l(-.314,.368),l(-.238,-.098),l(-.476,-.592),l(-.378,-.042),l(-.788,.058),l(-.288,-.098),l(-.373,0),l(-.329,.1),l(-.763,.539),l(-.396,-.056),l(-.319,-.494),l(-.166,-.028),l(-.155,.057),l(-.658,.326),l(-.344,.778),l(-.41,.65),l(-.289,-.112),l(-.325,-.551), +N(668.053,167.796),l(-.131,-.099),l(-.74,-.732),l(-.444,-1.255),l(.037,-.424),l(.054,-.706),l(-.292,-.465),l(.18,-.382),l(.978,.704),l(.202,-.424),l(.023,-.41),l(-.101,-.438),l(-.026,-.579),l(.145,-.438),l(.025,-.664),l(.082,-.861),l(.074,-.636),l(.38,-.862),l(.188,-.127),l(.337,-.142),l(.523,.055),l(1.21,.52),l(.576,.042),l(.188,-.212),l(.277,-.17),l(.199,.141),l(.018,.396),l(-.266,.438),l(-.045,.48),l(.14,.79),l(.541,.394),l(.182,.325),l(-.427,1.271),l(-.31,.467),l(-.834,.608),l(-.555,.312),l(-.082,.099),l(.003,.268),l(-.078,.565),l(-.28,.424),l(.127,.211),l(.35,.733),l(.345,1.101),l(.26,.62),l(.093,.028),l(.451,.324),l(.296,.07),l(.161,-.325),l(.485,-.537),l(.197,-.029),l(.418,.112),l(.226,.211),l(.179,.635),l(.286,.353),l(.326,.084),l(.505,-.58),l(.621,.267),l(.141,.028),l(.078,.127),l(-.168,.156),l(-.378,.156),l(-.208,.212),l(.936,1.226),l(-.315,.184),l(-.568,-.196),l(-.404,-.098),l(-.094,-.48),l(-.229,-.31),l(-.599,-.535),l(-.753,-.577),l(-.258,0),l(-.099,.226),l(.371,.776),l(-.218,.283),l(-.727,-.775),l(-.982,-.548),l(-.309,.015),l(-.344,.142),l(-.182,.255),l(-.14,.071),l(-.395,.057),l(-.322,-.225),l(-.591,-.366),l(-.195,-.423),l(.64,-.608),l(.323,.211),l(.358,.084),l(.4,-.199),l(-.151,-.169),l(-.713,-.295),l(-.422,-.395),l(-.522,-.168),l(-.239,.607),M(669.676,172.974),l(-.452,-.366),l(-.349,-.408),l(-.051,-.226),l(-.364,-1.114),l(-.459,-.521),l(.685,-.058),l(.868,.012),l(.314,.169),l(.274,.451),l(.028,.861),l(-.097,.48),l(-.214,.283),l(-.185,.438),M(679.073,175.368),l(-.562,-.267),l(-.178,-.254),l(-.237,-.169),l(-.064,-.127),l(.139,-.339),l(-.091,-.423),l(-.55,-.352),l(-.662,-.479),l(-.147,-.466),l(.513,-.1),l(1.017,-.143),l(.371,.112),l(.283,.409),l(.069,.818),l(.123,.805),l(.257,.79),l(-.112,.127),l(-.167,.057),M(671.406,176.824),l(.022,-.353),l(.186,-1.342),l(.061,-1.172),l(.482,.395),l(.576,.281),l(.366,.028),l(.634,-.185),l(.027,.438),l(-.079,.396),l(-.24,.269),l(-.184,.198),l(-.908,.651),l(-.943,.397),M(664.721,177.812),l(-.366,-.027),l(.127,-.297),l(.202,-.099),l(.314,-.396),l(.265,-.523),l(.082,-.607),l(.138,-.509),l(.326,-.184),l(.14,.183),l(-.16,.283),l(.276,.55),l(.212,.564),l(-.108,.113),l(-.664,.354),l(-.406,.368),l(-.377,.227),M(673.781,179.981),l(-.385,-.366),l(-.828,-.591),l(-.206,-.38),l(.099,-.368),l(.565,-.213),l(.22,-.269),l(.487,-1.822),l(.438,-.185),l(.271,.028),l(.113,.126),l(.049,.282),l(-.373,.905),l(-.089,.226),l(-.315,1.413),l(.165,.296),l(.214,.465),l(-.213,.41),l(-.212,.043),M(661.179,181.308),l(-.317,-.042),l(.215,-.48),l(.343,-.467),l(.35,-.34),l(.592,-.354),l(.636,-.496),l(.933,-1.089),l(.11,.55),l(-.118,.424),l(-.267,.297),l(-.24,.184),l(-.516,.213),l(-.172,.127),l(-.244,.622),l(-.327,.269),l(-.591,.171),l(-.386,.41),M(680.678,185.402),l(-.201,-.098),l(-.098,-.438),l(-.361,-.748),l(-.297,-.112),l(-.381,.608),l(-.361,.82),l(.246,.38),l(.166,.395),l(.148,.677),l(-.158,.495),l(-.383,.509),l(-.305,-.253),l(-.176,-.268),l(.201,-.41),l(-.076,-.325),l(-.363,-.07),l(-.361,.665),l(-.173,-.056),l(-1.114,-.619),l(-.557,-.549),l(-.206,-.508),l(-.037,-.635),l(.466,-.905),l(-.108,-.479),l(-.466,-.409),l(-.778,-.295),l(-.292,.043),l(-.062,.17),l(-.129,.226),l(-.5,.255),l(-.661,.058),l(-.027,-.494),l(-.174,-.24),l(-.399,.199),l(-.504,.961),l(-.525,.863),l(-.219,-.084),l(-.119,-.127),l(-.034,-.197),l(.054,-.311),l(.359,-.749),l(.185,-.537),l(.263,-.283),l(.383,-.184),l(.564,-.044),l(.219,-.127),l(.134,-.466),l(.205,-.156),l(.549,-.241),l(.777,-.101),l(.292,.353),l(.102,.72),l(.317,-.156),l(.485,-.058),l(.207,-.184),l(.207,-.565),l(.358,-.255),l(.479,.21),l(.186,.084),l(.158,-1.087),l(.29,-.015),l(.264,.465),l(.315,-.481),l(.205,-.142),l(.392,.098),l(.133,-.227),l(-.048,-.706),l(-.172,-.564),l(.146,-.353),l(.413,.549),l(.711,.803),l(.229,.48),l(.083,.324),l(-.336,.735),l(.237,.226),l(.537,-.1),l(.076,.423),l(-.114,.424),l(.056,.692),l(.207,.437),l(-.002,.438),l(-.111,.424),l(-.283,.579),l(-.332,.622), +N(251.898,160.229),l(-.547,-.112),l(-.073,-.212),l(.051,-.551),l(-.109,-.24),l(.11,-.17),l(.235,-.071),l(.543,.069),l(.404,-.015),l(1.505,.11),l(.393,.168),l(.113,.141),l(-.188,.354),l(-.07,.099),l(-.283,.227),l(-.335,.043),l(-.739,-.083),l(-.657,.072),l(-.354,.17), +N(228.82,160.519),l(-.299,-.056),l(-.693,-.224),l(-.229,-.268),l(-.47,-.366),l(-.465,-.084),l(-.142,-.211),l(.53,-.284),l(.704,-.072),l(1.364,.251),l(.97,.351),l(.651,.267),l(.279,.282),l(-.04,.198),l(-.332,.071),l(-.751,-.295),l(-.543,.058),l(-.227,.255),l(-.308,.128), +N(400.72,175.499),l(-.595,-.119),l(-.161,-.032),l(-.976,.458),l(-1.429,-.006),l(-.867,-.037),l(-2.119,.041),l(-.271,.157),l(-.125,.34),l(.261,1.934),l(.02,.41),l(-.191,.17),l(-.63,-.434),l(-.644,-.166),l(-.769,.075),l(-.608,.159),l(-.446,.257),l(-.368,.115),l(-.354,-.083),l(-.452,-.223),l(-.52,-.562),l(-.15,-.465),l(-.308,-.252),l(-.545,.003),l(-.259,-.168),l(.08,-.043),l(.046,-.156),l(.172,-.326),l(.261,-.92),l(.133,-.876),l(-.058,-.749),l(.141,-.255),l(.257,-.016),l(.448,-.158),l(.543,-.271),l(.317,-.369),l(.292,-1.047),l(.355,-1.217),l(.397,-.384),l(.273,-.058),l(.293,.281),l(.551,.364),l(.45,-.102),l(.174,-.227),l(.393,-.822),l(.492,-.667),l(.638,-.625),l(.272,-.101),l(.518,.209),l(.324,.182),l(.274,.027),l(.314,-.793),l(.304,-.228),l(.947,-.458),l(1.22,-.713),l(.37,-.073),l(.356,.125),l(.36,.059),l(1.062,.173),l(-.173,.665),l(.019,.396),l(.426,.93),l(.422,.492),l(.389,.266),l(.502,.42),l(.179,.268),l(.018,.212),l(-.335,.439),l(.114,.226),l(.97,.757),l(.516,.181),l(.37,-.044),l(.562,.025),l(.568,.971),l(.131,.367),l(-.237,.764),l(-.415,.468),l(-.337,.158),l(-.739,-.095),l(-.418,.045),l(-.415,.271),l(-.366,.553),l(-.24,.157),l(-.062,.142),l(-.29,-.041),l(-.611,-.166),l(-1.013,-.163), +N(209.823,175.47),l(-.388,-.645),l(-.932,-.888),l(-1.003,-1.085),l(-.837,-.817),l(-.723,-.464),l(-.196,-.183),l(-.023,-.226),l(.625,-.03),l(1.001,-.125),l(.29,-.143),l(.293,-.412),l(.005,-.961),l(.882,-.034),l(.513,-.583),l(.725,.42),l(1.207,-.997),l(.503,-.794),l(.294,-.242),l(.259,.013),l(.328,.182),l(.463,.097),l(.248,-.086),l(.424,-.229),l(1.425,-.486),l(.23,.519),l(.038,.339),l(-.057,.509),l(-.214,.707),l(-.543,.806),l(-.1,.749),l(.042,.904),l(-.245,1.13),l(-.188,.735),l(-.101,1.385),l(.031,.55),l(.184,.466),l(.188,.363),l(-.281,.274),l(-.767,-.149),l(-.241,-.46),l(-.285,.077),l(-.394,-.107),l(-.603,.25),l(-1.651,-.599),l(-.43,.271), +N(634.036,168.444),l(.533,.251),l(.736,.165),l(.341,.111),l(.469,.251),l(.248,-.058),l(.095,-.24),l(-.103,-.211),l(-.187,-.182),l(-.107,-.296),l(.392,-.285),l(.476,-.186),l(.444,.181),l(.373,.351),l(.3,-.072),l(.975,-.429),l(.209,-.114),l(-.215,.905),l(.029,.663),l(.455,1.014),l(-.076,.367),l(-.05,.424),l(.054,1.073),l(-.217,.509),l(-.385,.285),l(-.599,.187),l(-.932,.443),l(-.521,.229),l(-.99,.571),l(-.234,.425),l(.216,.422),l(.568,.435),l(.03,.197),l(-.17,.27),l(-.688,-.194),l(-.497,-.011),l(-.599,.229),l(-.915,.528),l(-.646,.229),l(-.3,.289),l(-.256,-.188),l(-.248,-.268),l(-.35,-.042),l(-.382,.142),l(-.205,-.042),l(-.293,.043),l(-.183,-.113),l(.142,-.311),l(.182,-.226),l(-.04,-.254),l(-.283,-.395),l(-.277,.043),l(-.462,.298),l(-.339,.015),l(-.171,-1.044),l(-.649,-1.488),l(.146,-.176),l(-.16,-.479),l(-.487,-.717),l(-.219,-.648),l(-.026,-.635),l(.076,-.382),l(.146,-.297),l(.92,-1.233),l(.521,-.441),l(.383,-.101),l(1.172,-.091),l(.798,.066),l(.558,-.074),l(.575,.039),l(.599,.109),l(.301,.167), +N(214.474,175.913),l(.821,.884),l(.385,.623),l(.314,.322),l(.225,.046),l(.465,.645),l(.441,.352),l(-.014,.006),l(-.074,.123),l(-.478,-.184),l(-.219,.205),l(-.014,.321),l(0,.58),l(.507,.307),l(-.396,.368),l(.125,.532),l(-.374,.369),l(.243,.184),l(-.204,.609),l(.003,-.466),l(-.296,-.307),l(.01,-.568),l(-.377,-.148),l(-.238,-.102),l(-.111,.082),l(.325,.41),l(.084,.225),l(-.113,.062),l(-.726,-.299),l(-.13,-.282),l(.251,-.339),l(.04,-.382),l(-.182,-.338),l(-.486,-.324),l(-.695,-.287),l(-.079,-.144),l(-.689,-.103),l(-.316,-.327),l(.007,-.421),l(-.146,-.255),l(-.249,-.098),l(-.576,-.353),l(-.416,-.266),l(.225,.512),l(.086,.222),l(.422,.044),l(.181,.266),l(-.544,.573),l(-.144,-.262),l(-.356,-.282),l(-.561,-.211),l(-.323,-.239),l(-.147,-.24),l(-.104,-.494),l(.128,-.421),l(.332,-.225),l(-.008,-.389),l(-.554,-.225),l(.363,-.123),l(-.057,-.227),l(-.238,.017),l(.43,-.271),l(1.651,.599),l(.603,-.25),l(.394,.107),l(.285,-.077),l(.241,.46),l(.767,.149),l(.281,-.274), +N(436.304,195.359),l(-.209,-.451),l(-.194,-.804),l(-.498,-.802),l(-1.217,-1.236),l(-.112,-.324),l(-.064,-.791),l(-.432,-.605),l(-.4,-.661),l(-.207,-.592),l(-.273,-1.185),l(-.112,-.776),l(.064,-.424),l(.144,-.198),l(.528,-.399),l(.4,-.511),l(.866,-1.743),l(.354,-.327),l(.208,-.114),l(.096,.084),l(.24,.027),l(.449,-.158),l(1.363,-.686),l(.494,.661),l(.225,.069),l(.224,-.03),l(.466,-.271),l(.754,-.386),l(.818,-.273),l(.881,.009),l(.368,-.031),l(.258,-.143),l(.646,-1.176),l(.117,-.806),l(.209,-.199),l(.434,-.059),l(2.181,-.055),l(.386,-.087),l(2.649,-2.275),l(.196,-.284),l(.005,-.41),l(.165,-.382),l(.372,-.228),l(.939,-.613),l(.322,-.086),l(.321,.012),l(.559,.208),l(1.342,1.673),l(.347,.549),l(.122,.536),l(-.416,1.472),l(.01,.664),l(.158,.211),l(.802,-.019),l(.272,-.001),l(.207,.126),l(.252,.493),l(.223,.225),l(.797,.447),l(.799,.235),l(.351,.196),l(.223,.267),l(-.148,.481),l(.173,.395),l(.445,.351),l(.558,.378),l(.717,.434),l(.207,.168),l(.206,.366),l(.059,.72),l(.285,.436),l(.367,.224),l(.814,.165),l(.558,.477),l(.157,.352),l(-.083,.679),l(.031,.07),l(-.496,.145),l(-.962,.344),l(-.319,-.026),l(-.287,-.167),l(-.687,-.264),l(-1.15,-.361),l(-.4,.13),l(-.082,.551),l(-.13,.241),l(-.256,.058),l(-.399,-.026),l(-.862,-.207),l(-.593,.102),l(-.93,.373),l(-.93,.486),l(-.271,.016),l(-.559,-.35),l(-.383,-.153),l(-.353,.186),l(-.677,1.36),l(-.176,.157),l(-.591,-.067),l(-1.934,-.511),l(-1.422,-.189),l(-.512,-.322),l(-.159,-.239),l(-.334,-.394),l(-.75,-.518),l(-.432,-.167),l(-.479,.06),l(-.529,.3),l(-.353,.341),l(-.785,.979),l(-.097,.297),l(.096,.452),l(-.017,.353),l(-.063,.594),l(-.16,.058),l(-.751,.287),l(-.895,-.093),l(-.624,-.138),l(-.367,-.054),l(-.975,.175),l(-.479,.102),l(-.255,.228),l(-.222,1.287),l(-.158,.523),l(-.365,.497),l(-.303,.312), +N(371.324,180.419),l(1.088,-1.235),l(.643,-.866),l(.238,-.157),l(.594,.039),l(1.137,-.148),l(.466,.04),l(.42,.224),l(.456,.421),l(.475,.619),l(.252,.761),l(.165,1.369),l(.26,.656),l(-.259,.502),l(-1.184,1.151),l(-.63,.724),l(-.285,.256),l(-.061,.103),l(-.631,-.523),l(-.661,-.408),l(-.483,-.196),l(-.033,-.141),l(.061,-.297),l(-.05,-.184),l(-.531,-.21),l(-.792,-.549),l(-.389,-.366),l(-.375,-.465),l(.494,-.241),l(.174,-.227),l(-.034,-.155),l(-.484,-.211),l(-.065,-.113),l(.022,-.173), +N(579.606,186.906),l(-.493,-.083),l(-.265,-.197),l(-.21,-.353),l(-.246,-.621),l(-.361,-1.256),l(-.034,-.649),l(.005,-.763),l(-.02,-.904),l(-.24,-.696),l(.188,-.513),l(-.298,-.35),l(.068,-.28),l(.423,.023),l(.349,-.43),l(.053,-.367),l(.226,-.369),l(-.152,-.537),l(.529,.48),l(.699,.38),l(.234,.395),l(.549,.776),l(.175,.324),l(-.099,.339),l(.024,.141),l(.592,.338),l(.266,.733),l(.798,1.368),l(.136,.508),l(-.193,.735),l(-.397,.679),l(-.369,.396),l(-.514,.425),l(-.78,.284),l(-.642,.043), +N(217.111,178.792),l(.52,.307),l(.195,.512),l(.02,.374),l(.363,.155),l(.628,.024),l(.244,-.205),l(.398,.43),l(.726,.082),l(.458,-.083),l(1.348,-.751),l(.514,-.046),l(1.387,-.921),l(.373,.144),l(.742,.069),l(.071,.156),l(.789,-.017),l(.767,.21),l(.666,.38),l(.644,.563),l(.406,.666),l(.084,.327),l(.228,.149),l(.509,1.038),l(-.322,.062),l(-.094,.43),l(-.584,.409),l(-.085,-.307),l(-.19,-.082),l(.045,.45),l(-.228,.082),l(-.256,.753),l(-.378,-.825),l(-.441,-.762),l(-.137,-.452),l(.179,-.24),l(.22,-.085),l(.786,.125),l(-.336,-.193),l(-.125,-.164),l(-.096,-.471),l(-.309,.307),l(-.439,.041),l(-.244,-.378),l(-.031,-.269),l(-.193,-.282),l(-.132,.151),l(-.226,-.287),l(-.11,.102),l(-.132,-.266),l(-.456,-.192),l(-.562,-.013),l(-.499,.241),l(-.382,.108),l(-.07,.359),l(.081,.234),l(-.529,.318),l(-.374,.184),l(-.335,.029),l(-.345,.41),l(.049,.296),l(.316,.297),l(.464,.43),l(.178,.386),l(-.011,.146),l(-.281,.081),l(-.243,-.042),l(-.431,.391),l(-.568,.105),l(-.339,-.042),l(-.189,-.146),l(.108,-.164),l(-.349,-.833),l(-.244,-.353),l(-.177,.674),l(-.812,-.409),l(-.227,-.757),l(-.207,.041),l(-.96,-.123),l(-.434,-.266),l(-.599,0),l(-.314,.113),l(-.361,.495),l(.204,-.609),l(-.243,-.184),l(.374,-.369),l(-.125,-.532),l(.396,-.368),l(-.507,-.307),l(0,-.58),l(.014,-.321),l(.219,-.205),l(.478,.184),l(.074,-.123), +N(266.015,188.956),l(-.503,-.647),l(-.732,-.745),l(-.324,-.521),l(.071,-.212),l(.395,-.539),l(-.008,-.58),l(.061,-.452),l(1.032,-.19),l(.41,-.144),l(.308,-.299),l(-.141,-.282),l(-.62,-.604),l(-.074,-.212),l(.101,-.255),l(1.655,-1.239),l(.061,-.41),l(-.095,-.296),l(.072,.049),l(.496,.338),l(.856,.521),l(.695,.521),l(.587,.663),l(.128,.409),l(-.036,.734),l(.148,.945),l(.298,-.593),l(.22,-.099),l(.6,.182),l(.101,.127),l(.507,.295),l(.708,.549),l(.401,.493),l(.374,.649),l(-.015,.339),l(-.142,.496),l(-.082,.862),l(-.183,.27),l(-1.131,.091),l(-.169,.17),l(.078,.777),l(-.095,.467),l(-.328,.694),l(.571,.831),l(.532,.675),l(.561,.067),l(.185,.295),l(.246,.832),l(.49,1.127),l(.332,.563),l(-.06,.212),l(-.943,-.022),l(-.934,.429),l(-1,.331),l(-.505,.314),l(-.694,.513),l(-.686,.075),l(-.613,-.392),l(-1.103,-.897),l(-.15,-.296),l(-.008,-.396),l(.072,-.354),l(-.167,-.31),l(-.281,-.394),l(-.156,-.465),l(.213,-.962),l(.547,-1.416),l(.179,-.368),l(-.435,-.958),l(-.533,-.138),l(-.304,.001),l(.452,-1.09),l(-.04,-.212),l(-.26,-.111),l(-.516,-.124),l(-.302,.058),l(-.375,.257), +N(377.518,182.142),l(.193,-.376),l(.252,-.242),l(.367,-.143),l(.528,-.046),l(.338,.097),l(.165,.366),l(.22,.846),l(.009,.65),l(-.044,.283),l(.277,.323),l(.404,.322),l(.321,.026),l(.756,-.922),l(.143,-.086),l(.337,.097),l(.339,.224),l(-.062,.17),l(.119,.55),l(-.059,.438),l(-.501,.865),l(.05,.183),l(.194,.183),l(.369,.097),l(.592,-.032),l(1.264,1.334),l(.131,.282),l(-.059,.452),l(-.247,.849),l(-.105,.565),l(-.041,.919),l(-1.513,-.643),l(-1.221,-.619),l(-1.012,-.562),l(-.403,-.423),l(-1.129,-1.113),l(-1.111,-.76),l(-.723,-.337),l(-.901,-.535),l(-.66,-.548),l(.061,-.103),l(.285,-.256),l(.63,-.724),l(1.184,-1.151),l(.259,-.502), +N(429.505,210.684),l(.484,.336),l(.177,.013),l(.443,-.271),l(.327,-.581),l(1.495,-.532),l(.054,.424),l(.042,.664),l(.147,.211),l(.57,-.328),l(.554,-.399),l(.931,-.811),l(.364,-.229),l(1.025,-.938),l(.086,-.706),l(-.122,-.72),l(.074,-.396),l(.193,-1.159),l(.343,-.751),l(.47,-.836),l(.41,-.454),l(.809,-.599),l(.525,-.229),l(.459,-.427),l(.139,-.523),l(.169,-.708),l(.115,-.61),l(.254,-1.342),l(.196,-2.021),l(.156,-.764),l(.094,-.551),l(.349,-.821),l(.558,-.837),l(.398,-1.203),l(.031,-.156),l(-.128,-.197),l(.16,-.058),l(.063,-.594),l(.017,-.353),l(-.096,-.452),l(.097,-.297),l(.785,-.979),l(.353,-.341),l(.529,-.3),l(.479,-.06),l(.432,.167),l(.75,.518),l(.334,.394),l(.159,.239),l(.512,.322),l(1.422,.189),l(1.934,.511),l(.591,.067),l(.176,-.157),l(.677,-1.36),l(.353,-.186),l(.383,.153),l(.559,.35),l(.271,-.016),l(.93,-.486),l(.93,-.373),l(.593,-.102),l(.862,.207),l(.399,.026),l(.256,-.058),l(.13,-.241),l(.082,-.551),l(.4,-.13),l(1.15,.361),l(.687,.264),l(.287,.167),l(.319,.026),l(.962,-.344),l(.496,-.145),l(.143,.239),l(.795,.772),l(.348,.493),l(.525,.477),l(.366,.195),l(.352,-.016),l(.258,-.242),l(.529,-.37),l(.384,.012),l(.684,.631),l(.16,-.1),l(.436,-.582),l(.258,-.157),l(.207,.083),l(1.032,.926),l(1.288,1.32),l(.063,.028),l(.159,.183),l(-.018,.424),l(-.26,1.88),l(.128,.253),l(.191,.027),l(.479,.04),l(.271,.182),l(.111,.31),l(-.191,.453),l(-1.195,1.066),l(-1.241,.996),l(-.255,.284),l(-.395,.681),l(-.217,1.02),l(-.107,.507),l(.021,.593),l(-.025,.734),l(.057,.748),l(-.076,.27),l(-.188,.298),l(-.426,.412),l(-.301,.171),l(-.269,.256),l(-.122,.425),l(-.49,1.358),l(.197,.338),l(.689,.999),l(.087,.381),l(-.04,.438),l(.014,.636),l(.237,.634),l(.017,1.329),l(-.064,.762),l(.425,1.439),l(-.102,.848),l(.122,.693),l(.486,.631),l(.936,.898),l(.428,.78),l(.689,1.804),l(-.563,.068),l(-3.015,.499),l(-.347,.214),l(-.154,.198),l(-.797,1.276),l(-.029,.622),l(.372,2.088),l(-.377,1.175),l(-.3,1.02),l(.043,.296),l(.456,.605),l(.837,.843),l(.445,.279),l(.515,.012),l(.448,-.455),l(.362,-.186),l(.136,.183),l(.032,.791),l(.028,1.427),l(-.041,.551),l(-.371,-.012),l(-1.355,-.091),l(-.348,-.21),l(-.381,-.647),l(-.561,-.731),l(-.416,-.351),l(-.477,-.252),l(-.895,-.263),l(-.38,-.28),l(-.728,-1.423),l(-.212,.354),l(-.522,.682),l(-.366,.087),l(-.325,-.111),l(-.922,-.164),l(-.925,-.249),l(-.489,-.194),l(-.58,-1.014),l(-.175,.071),l(-1.146,.289),l(-.195,-.056),l(-.172,-.352),l(-.365,-.379),l(-.678,-.096),l(-1.24,-.147),l(-.991,.146),l(-.859,.26),l(-.61,.004),l(-.199,-.197),l(-.007,-.254),l(.198,-.905),l(.003,-.466),l(-.306,-.62),l(-.844,-.998),l(-.117,-.211),l(-.021,-.212),l(.296,-1.033),l(.07,-1.06),l(-.109,-.607),l(-.303,-.605),l(.057,-.354),l(.177,-.693),l(-.052,-.183),l(-.322,-.098),l(-1.231,.093),l(-.88,.019),l(-.212,-.168),l(.055,-.48),l(-.181,-.225),l(-2.016,.082),l(-.112,.001),l(-.089,.354),l(.027,.593),l(-.286,.892),l(-.184,.411),l(-.993,.006),l(-.899,-.122),l(-1.021,.246),l(-.88,.034),l(-.292,-.168),l(-.64,-.787),l(-.597,-1.07),l(-.537,-1.409),l(-.059,-.579),l(-.121,-.521),l(-.082,-.127),l(-.321,-.111),l(-.385,-.012),l(-1.104,-.008),l(-.88,.034),l(-.624,.003),l(-1.312,-.048),l(-.945,-.052),l(-.783,.02),l(-.432,.03),l(-.318,.101),l(-.896,.062),l(-.699,.314),l(-.56,.06),l(-.112,-.013),l(-.322,-.922),l(.012,-.053),l(.74,-.3),l(-.017,-.085),l(.1,-.89),l(.094,-.143),l(.317,-.199),l(.583,-.568), +N(468.568,202.653),l(1.277,-.05),l(4.659,0),l(1.448,-.033),l(4.663,2.568),l(3.553,1.984),l(.137,.381),l(-.116,.552),l(.07,.239),l(2.427,1.752),l(1.067,.807),l(-.237,.427),l(-.419,1.329),l(-.137,1.017),l(.109,.551),l(.665,.987),l(.768,.577),l(-.024,.282),l(-.263,.354),l(-.371,1.046),l(.037,.17),l(.306,.041),l(.118,.226),l(-.172,.692),l(-.019,.946),l(.411,1.793),l(.18,.564),l(.401,.465),l(.823,.55),l(.396,.268),l(.177,.228),l(-1.157,.836),l(-.515,.342),l(-1.218,.402),l(-1.243,.559),l(-.448,.031),l(-.646,-.42),l(-.276,-.083),l(-.21,.326),l(-.543,.766),l(-.396,.144),l(-.42,-.054),l(-.964,.006),l(-.963,.02),l(-.512,-.294),l(-.323,-.394),l(-.229,-.083),l(-.123,.128),l(-.643,.356),l(-.526,.088),l(-1.019,-.149),l(-.898,-.018),l(-.196,-.559),l(-.135,-.766),l(-.053,-.584),l(-.135,-.946),l(-.448,-.841),l(-.663,-.538),l(-1.014,-.107),l(-.223,.016),l(-.385,-.407),l(-.732,-.349),l(-1.574,-.57),l(-1.269,-.6),l(-.729,-.265),l(-.263,-.21),l(-.703,-.641),l(-.689,-1.804),l(-.428,-.78),l(-.936,-.898),l(-.486,-.631),l(-.122,-.693),l(.102,-.848),l(-.425,-1.439),l(.064,-.762),l(1.252,-.348),l(.388,-.539),l(.645,-1.204),l(.687,-.853),l(.346,-.271),l(.044,-.212),l(-.148,-.239),l(-.273,-.125),l(-.401,-.068),l(-.211,-.211),l(.158,-.976),l(.304,-.016),l(.396,-.158),l(.142,-.17),l(.104,-.481),l(-.167,-.493),l(-.364,-.888),l(-.121,-.748), +N(464.786,206.235),l(-.197,-.338),l(.49,-1.358),l(.122,-.425),l(.269,-.256),l(.301,-.171),l(.426,-.412),l(.064,.042),l(.546,.223),l(.431,-.045),l(.458,-.427),l(.554,-.398),l(.319,-.017),l(.121,.748),l(.364,.888),l(.167,.493),l(-.104,.481),l(-.142,.17),l(-.396,.158),l(-.304,.016),l(-.559,.031),l(-.508,.159),l(-.391,.567),l(-.158,.085),l(-.396,.13),l(-.789,-.32),l(-.688,-.024), +N(465.79,210.652),l(-.017,-1.329),l(-.237,-.634),l(-.014,-.636),l(.04,-.438),l(-.087,-.381),l(-.689,-.999),l(.688,.024),l(.789,.32),l(.396,-.13),l(.158,-.085),l(.391,-.567),l(.508,-.159),l(.559,-.031),l(-.158,.976),l(.211,.211),l(.401,.068),l(.273,.125),l(.148,.239),l(-.044,.212),l(-.346,.271),l(-.687,.853),l(-.645,1.204),l(-.388,.539),l(-1.252,.348), +N(427.243,211.207),l(.536,-.414),l(.68,-.513),l(.351,-.13),l(.695,.533),l(-.583,.568),l(-.317,.199),l(-.094,.143),l(-.1,.89),l(.017,.085),l(-.74,.3),l(.143,-.625),l(-.082,-.24),l(-.505,-.796),M(427.998,213.843),l(.112,.013),l(.56,-.06),l(.699,-.314),l(.896,-.062),l(.318,-.101),l(.432,-.03),l(.783,-.02),l(.945,.052),l(1.312,.048),l(.624,-.003),l(.88,-.034),l(1.104,.008),l(.385,.012),l(.321,.111),l(.082,.127),l(.121,.521),l(.059,.579),l(.537,1.409),l(.597,1.07),l(.64,.787),l(.292,.168),l(.88,-.034),l(1.021,-.246),l(.899,.122),l(.993,-.006),l(.184,-.411),l(.286,-.892),l(-.027,-.593),l(.089,-.354),l(.112,-.001),l(2.016,-.082),l(.181,.225),l(-.055,.48),l(.212,.168),l(.88,-.019),l(1.231,-.093),l(.322,.098),l(.052,.183),l(-.177,.693),l(-.057,.354),l(.303,.605),l(.109,.607),l(-.07,1.06),l(-.296,1.033),l(.021,.212),l(.117,.211),l(.844,.998),l(.306,.62),l(-.003,.466),l(-.198,.905),l(.007,.254),l(.199,.197),l(.61,-.004),l(.859,-.26),l(.991,-.146),l(1.24,.147),l(-.214,1.344),l(.195,1.059),l(.269,.323),l(.089,.254),l(-.132,.368),l(-.436,.44),l(-.124,.594),l(-.125,.086),l(-.517,-.04),l(-3.408,.091),l(-.051,.877),l(.015,1.342),l(-.024,3.249),l(.017,.848),l(.023,.594),l(.099,.438),l(.308,.394),l(.471,.436),l(1.354,1.391),l(.611,.632),l(-.93,.218),l(-1.96,.379),l(-1.044,.203),l(-.717,-.08),l(-1.164,.063),l(-.408,-.083),l(-.349,-.21),l(-2.024,.026),l(-.697,-.024),l(-.622,-.151),l(-.401,-.322),l(-.305,-.366),l(-.408,-.096),l(-.989,-.023),l(-2.59,.016),l(-1.636,-.019),l(-.631,-.011),l(-1.296,-.006),l(-2.201,.013),l(-.636,-.151),l(-.463,-.309),l(-.45,-.478),l(-.294,-.083),l(-.499,.088),l(-.591,.286),l(-.778,.513),l(-.758,-.462),l(-.352,.144),l(-.248,.197),l(.048,-1.809),l(-.017,-.805),l(-.029,-.649),l(.397,-.34),l(.221,-.269),l(.26,-.707),l(.163,-.734),l(.184,-1.398),l(.239,-.976),l(.321,-.918),l(.584,-.665),l(.183,-.565),l(.268,-.354),l(.64,-.228),l(.268,-.325),l(.423,-.679),l(.364,-1.201),l(.053,-.664),l(-.046,-.848),l(-.191,-.959),l(-.201,-.536),l(-.492,-.705),l(-.476,-.776),l(-.268,-.775),l(.139,-.495),l(.476,-.382),l(.158,-.156),l(.107,-.424),l(-.006,-.479),l(-.199,-.579),l(-.489,-.69),l(-.441,-.733),l(-.203,-1.031),l(-.181,-.423),l(-.276,-.366),l(-.666,-.974),l(-.072,-.15), +N(452.198,239.34),l(-.611,-.632),l(-1.354,-1.391),l(-.471,-.436),l(-.308,-.394),l(-.099,-.438),l(-.023,-.594),l(-.017,-.848),l(.024,-3.249),l(-.015,-1.342),l(.051,-.877),l(3.408,-.091),l(.517,.04),l(.125,-.086),l(.124,-.594),l(.436,-.44),l(.132,-.368),l(-.089,-.254),l(-.269,-.323),l(-.195,-1.059),l(.214,-1.344),l(.678,.096),l(.365,.379),l(.172,.352),l(.195,.056),l(1.146,-.289),l(.175,-.071),l(.58,1.014),l(.489,.194),l(.925,.249),l(.922,.164),l(.325,.111),l(.366,-.087),l(.522,-.682),l(.212,-.354),l(.728,1.423),l(.38,.28),l(.895,.263),l(.477,.252),l(.416,.351),l(.561,.731),l(.381,.647),l(.348,.21),l(1.355,.091),l(.371,.012),l(.041,-.551),l(-.028,-1.427),l(-.032,-.791),l(-.136,-.183),l(-.362,.186),l(-.448,.455),l(-.515,-.012),l(-.445,-.279),l(-.837,-.843),l(-.456,-.605),l(-.043,-.296),l(.3,-1.02),l(.377,-1.175),l(-.372,-2.088),l(.029,-.622),l(.797,-1.276),l(.154,-.198),l(.347,-.214),l(3.015,-.499),l(.563,-.068),l(.703,.641),l(.263,.21),l(.729,.265),l(1.269,.6),l(1.574,.57),l(.732,.349),l(.385,.407),l(.559,.887),l(.434,.859),l(.013,.324),l(-.183,.27),l(-.709,.344),l(-.011,.127),l(.04,.594),l(-.091,1.682),l(.08,.353),l(.216,.168),l(.511,.266),l(.072,.197),l(-.197,.241),l(-.472,.258),l(-.792,.259),l(-.146,.34),l(-.094,.764),l(-.3,.807),l(.2,.479),l(.261,.408),l(.394,.125),l(-1.264,.53),l(-1.696,.575),l(-.932,.4),l(-2.165,.578),l(-.187,.128),l(-.009,.495),l(.152,.465),l(.087,.438),l(-.505,-.096),l(-.999,.049),l(-.794,.259),l(-.636,.54),l(-.312,.539),l(-.019,.579),l(-.168,.199),l(-.285,.114),l(-.999,.062),l(-.621,.202),l(-.306,.341),l(-.777,.937),l(-.562,.738),l(-.825,.951),l(-.354,.045),l(-.803,-.165),l(-.421,-.309),l(-.334,.129),l(-.521,.286),l(-.404,.017),l(-.594,-.209),l(-.264,-.097),l(-.154,-.169),l(-.163,-.027),l(-.187,-.154),l(-.456,-.393),l(-.294,-.055),l(-1.089,-.093),l(-.086,-.099),l(-.165,-.056),l(-1.845,.364), +N(477.231,225.874),l(-.224,1.184),l(-.107,.48),l(.252,.917),l(.177,1.017),l(.149,.408),l(.238,.268),l(.803,.588),l(1.189,1.166),l(.454,.661),l(.14,.48),l(-.155,2.346),l(-.04,.41),l(-.214,.213),l(-.432,.073),l(-.322,.017),l(-.229,.213),l(-.076,.622),l(.08,.509),l(.029,.479),l(-.096,.283),l(-.185,-.111),l(-.562,-.463),l(-.763,-1.112),l(-.484,-.548),l(-.234,-.423),l(.036,-.212),l(.499,-.61),l(.116,-.227),l(.025,-.693),l(-.1,-.96),l(-.22,-.479),l(-.261,-.056),l(-.674,.061),l(-.702,.132),l(-.27,-.211),l(-.343,-.407),l(-.382,-.549),l(-.195,-.041),l(-.394,-.125),l(-.261,-.408),l(-.2,-.479),l(.3,-.807),l(.094,-.764),l(.146,-.34),l(.792,-.259),l(.472,-.258),l(.197,-.241),l(-.072,-.197),l(-.511,-.266),l(-.216,-.168),l(-.08,-.353),l(.091,-1.682),l(-.04,-.594),l(.011,-.127),l(.709,-.344),l(.183,-.27),l(-.013,-.324),l(-.434,-.859),l(-.559,-.887),l(.223,-.016),l(1.014,.107),l(.663,.538),l(.448,.841),l(.135,.946),l(.053,.584),l(.135,.766),l(.196,.559), +N(245.934,224.314),l(.939,.136),l(1.122,.304),l(.355,-.03),l(.946,-.824),l(.336,.026),l(.48,.025),l(.415,-.243),l(1.471,-1.109),l(.874,-.485),l(.36,-.158),l(.934,-.076),l(1.283,.021),l(.045,.748),l(-.079,.621),l(-.064,.622),l(.036,.818),l(.141,.635),l(.335,.591),l(.813,.928),l(1.1,.939),l(.316,.097),l(.787,.023),l(.355,-.03),l(.676,.25),l(.688,.307),l(.75,.603),l(.3,.098),l(.882,.037),l(.096,.014),l(.385,.774),l(.398,.308),l(.22,.084),l(1.148,-.077),l(.636,.123),l(.537,.166),l(.403,.237),l(.085,.169),l(-.038,.565),l(.203,1.029),l(.03,.706),l(.138,2.032),l(.249,.944),l(.153,.112),l(.967,.036),l(.5,.012),l(1.615,.019),l(.693,.024),l(.042,.296),l(-.261,.835),l(.067,.563),l(.436,.407),l(.73,.362),l(.316,.479),l(.307,.774),l(.022,.494),l(-.185,1.173),l(-.238,.834),l(-.38,.765),l(-.421,.666),l(-.089,-.084),l(-1.952,-.991),l(-.352,-.054),l(-.928,.02),l(-.843,-.01),l(-.126,.128),l(-1.076,.204),l(-1.104,.162),l(-.784,.202),l(-.33,.044),l(-.332,.383),l(-.698,1.105),l(-.278,.341),l(-.133,.509),l(.016,.635),l(-.385,1.188),l(-.395,1.104),l(-.149,.325),l(-.592,-.109),l(-1.33,-.077),l(-.686,.004),l(-1.034,1.784),l(-.416,-1.084),l(-.341,-.309),l(-.37,-.195),l(-.531,-.067),l(-.527,.045),l(-.901,.034),l(-.615,-.194),l(-.193,-.169),l(-.322,-.181),l(-.292,.27),l(-2.026,2.087),l(-1.047,.006),l(-.272,-.182),l(-.397,-2.144),l(-.278,-.973),l(-.212,-.563),l(-.769,-1.11),l(-.249,-.676),l(.04,-.354),l(.437,-1.555),l(-.017,-.282),l(-.761,-.744),l(-.25,-.521),l(-.193,-1.213),l(-.304,-.647),l(-.555,-.745),l(-.152,-.253),l(-.018,-.142),l(-.132,-.295),l(-.049,-.48),l(.12,-.227),l(.723,-.61),l(.285,-.439),l(-.015,-.522),l(-.604,-1.168),l(-.022,-.48),l(.159,-.34),l(.21,-.368),l(-.347,-.845),l(.102,-.452),l(.532,-.582),l(.221,-.34),l(.156,-.34),l(-.236,-.902),l(-.057,-.522),l(.143,-.848),l(.15,-.523),l(.437,-.736),l(-.08,-.24),l(-.922,-1.646),l(-1.109,-1.843), +N(473.575,260.04),l(-1.331,.011),l(-.192,.058),l(-.068,-.382),l(-.261,-.889),l(.071,-.495),l(-.075,-.296),l(-.095,-.324),l(.03,-.806),l(.057,-1.301),l(-.072,-.763),l(-.147,-.678),l(-.33,-.944),l(-.441,-.689),l(-.181,-.946),l(-.295,-1.199),l(-.159,-.183),l(.448,-.384),l(.396,-.412),l(1.68,-1.706),l(.114,-.227),l(-.09,-.367),l(.075,-.834),l(.229,-.481),l(.736,-.683),l(.205,-.341),l(.168,-.41),l(-.594,-.845),l(-.118,-.805),l(-.113,-.494),l(.128,-.283),l(.448,-.596),l(.201,-.411),l(-.132,-.805),l(-.086,-1.144),l(-.031,-.791),l(-.178,-.818),l(-.441,-.379),l(-.515,-.224),l(-1.167,-.347),l(-1.042,-.445),l(-.658,-.223),l(-1.438,-.006),l(-.137,-.14),l(-.025,-.495),l(-.011,-.212),l(-.087,-.438),l(-.152,-.465),l(.009,-.495),l(.187,-.128),l(2.165,-.578),l(.932,-.4),l(1.696,-.575),l(1.264,-.53),l(.195,.041),l(.382,.549),l(.343,.407),l(.27,.211),l(.702,-.132),l(.674,-.061),l(.261,.056),l(.22,.479),l(.1,.96),l(-.025,.693),l(-.116,.227),l(-.499,.61),l(-.036,.212),l(.234,.423),l(.484,.548),l(.763,1.112),l(.562,.463),l(.185,.111),l(.096,-.283),l(-.029,-.479),l(-.08,-.509),l(.076,-.622),l(.229,-.213),l(.322,-.017),l(.432,-.073),l(.214,-.213),l(.04,-.41),l(.155,-2.346),l(-.14,-.48),l(-.454,-.661),l(-1.189,-1.166),l(-.803,-.588),l(-.238,-.268),l(-.149,-.408),l(-.177,-1.017),l(-.252,-.917),l(.107,-.48),l(.224,-1.184),l(.898,.018),l(1.019,.149),l(.526,-.088),l(.643,-.356),l(.123,-.128),l(.229,.083),l(.323,.394),l(.512,.294),l(.963,-.02),l(.964,-.006),l(.42,.054),l(.396,-.144),l(.543,-.766),l(.21,-.326),l(.276,.083),l(.646,.42),l(.448,-.031),l(1.243,-.559),l(1.218,-.402),l(.515,-.342),l(1.157,-.836),l(.128,.167),l(.212,.479),l(-.185,.579),l(-.302,.453),l(-.198,.255),l(.181,.451),l(.129,.72),l(-.012,.466),l(.182,1.115),l(-.101,.58),l(-.258,.325),l(.374,.705),l(.154,.494),l(-.006,1.115),l(-.004,.819),l(.043,.184),l(.185,.127),l(.327,.084),l(.015,.269),l(-.165,.494),l(-.563,.58),l(.184,.381),l(-.08,.283),l(-.418,.565),l(-.802,.906),l(-.512,.622),l(-.72,.651),l(-1.36,.751),l(-1.48,.653),l(-.73,.228),l(-1.308,.582),l(-.852,.637),l(-1.286,1.443),l(-.886,.85),l(-1.193,.878),l(-1.181,.836),l(-.268,.128),l(-.035,.96),l(-.083,.495),l(.058,.127),l(.719,.535),l(.188,.381),l(-.166,.452),l(-.085,.184),l(.461,1.511),l(.071,.564),l(.06,.155),l(.246,.014),l(.171,-.128),l(.141,-.085),l(.043,.607),l(-.234,2.218),l(-.284,.82),l(.325,.196),l(.152,.057),l(-.025,.325),l(-.157,.311),l(-.516,.566),l(-.699,.538),l(-.664,.34),l(-1.266,.412),l(-.796,.312),l(-.688,.228),l(-.895,.524),l(-.652,.665),l(-.337,.51),l(.292,.338),l(.589,.338),l(.045,.325),l(-.149,1.022), +N(499.85,236.166),l(.544,-.071),l(.622,-.369),l(.18,.028),l(.346,.098),l(.269,-.085),l(.396,-.368),l(.911,-.143),l(.311,.281),l(.305,-.028),l(.101,-.185),l(-.171,-.366),l(.771,-.539),l(.423,-.198),l(.322,.226),l(.389,-.213),l(-.308,-.494),l(.207,-.282),l(.505,-.425),l(.229,.296),l(.229,.056),l(.558,-.594),l(-.158,-.197),l(-.253,-.409),l(.094,-.297),l(.243,.014),l(.27,-.071),l(.172,-.34),l(-.297,-.875),l(.06,-.339),l(.255,-.043),l(.117,.07),l(.253,.438),l(.28,.099),l(.2,-.41),l(.692,-.524),l(.235,-.367),l(.134,-.452),l(.168,-.692),l(-.133,-.354),l(.003,-.226),l(.537,-.468),l(.356,.324),l(.455,.648),l(.612,.281),l(.141,.198),l(.213,.847),l(.294,1.821),l(.093,.663),l(.231,.791),l(.391,.733),l(.163,.466),l(-.038,.367),l(-.069,.155),l(-.058,.099),l(-.537,.807),l(-.22,-.127),l(-.189,-.366),l(-.555,-.748),l(-.297,.143),l(-.05,.424),l(.193,.875),l(.396,.521),l(.079,.396),l(-.307,.636),l(-.746,1.005),l(-.045,.452),l(.041,.89),l(-.18,.946),l(-.709,2.12),l(-.825,2.572),l(-1.254,3.788),l(-1.324,4.48),l(-.518,1.568),l(-.188,.255),l(-.508,.637),l(-.2,.113),l(-1.369,.102),l(-.999,.327),l(-.474,.468),l(-.813,.086),l(-.363,-.465),l(-.196,-.142),l(-.546,-.182),l(-.37,.071),l(-.269,-.057),l(-.863,-.718),l(-.104,-.24),l(-.02,-.565),l(-.104,-.239),l(-.46,-.366),l(-.124,-.282),l(.001,-.721),l(.345,-1.088),l(-.094,-.325),l(-.287,-.479),l(-.62,-.931),l(-.189,-.494),l(.075,-.664),l(.391,-1.37),l(.228,-.213),l(.474,-.185),l(.768,-1.371),l(.686,-1.174),l(.104,-.325),l(.151,-1.103),l(-.11,-.353),l(-.278,-.226),l(-.354,-.366),l(.066,-.184),l(.252,-.509),l(-.521,-.861),l(-.117,-.677),l(-.069,-.494),l(-.231,-.721),l(.024,-.112),l(.517,-.693),l(.362,-.594),l(.163,-.438),l(.007,-1.073),l(.484,-.016), +N(468.138,234.908),l(.011,.212),l(.025,.495),l(.137,.14),l(1.438,.006),l(.658,.223),l(1.042,.445),l(1.167,.347),l(.515,.224),l(.441,.379),l(.178,.818),l(.031,.791),l(.086,1.144),l(.132,.805),l(-.201,.411),l(-.448,.596),l(-.128,.283),l(.113,.494),l(.118,.805),l(.594,.845),l(-.168,.41),l(-.205,.341),l(-.736,.683),l(-.229,.481),l(-.075,.834),l(.09,.367),l(-.114,.227),l(-1.68,1.706),l(-.396,.412),l(-.448,.384),l(-.342,-.225),l(-.547,-.124),l(-.442,-.025),l(-.529,.145),l(-.31,.016),l(-.99,-.403),l(-.597,-.139),l(-.72,-.023),l(-.067,-.042),l(-.186,-.098),l(-.306,-.451),l(-.479,-.35),l(-.549,-.167),l(-.938,-.136),l(-.352,-.153),l(-.524,-.873),l(-.163,-.564),l(.032,-.565),l(-.127,-.239),l(-.78,.019),l(-.201,-.098),l(-.109,-.211),l(.051,-.537),l(-.106,-.169),l(-.552,-.266),l(-.533,-.223),l(-.57,-.321),l(-.563,-.491),l(-.377,-.662),l(-.246,-.96),l(-.469,-.604),l(-.43,-.478),l(-.267,-.451),l(.103,-.227),l(.594,.209),l(.404,-.017),l(.521,-.286),l(.334,-.129),l(.421,.309),l(.803,.165),l(.354,-.045),l(.825,-.951),l(.562,-.738),l(.777,-.937),l(.306,-.341),l(.621,-.202),l(.999,-.062),l(.285,-.114),l(.168,-.199),l(.019,-.579),l(.312,-.539),l(.636,-.54),l(.794,-.259),l(.999,-.049),l(.505,.096), +N(444.673,255.519),l(-.006,3.434),l(.031,1.894),l(.025,2.246),l(-.057,.205),l(-.454,.318),l(-.545,.302),l(-.581,.498),l(-.427,.034),l(-.581,-.166),l(-.745,-.042),l(-.892,.048),l(-.517,-.039),l(-.296,-.212),l(-.055,-.528),l(-.042,-.345),l(-.193,-.222),l(-.637,-.348),l(-.329,-.127),l(-.335,.116),l(-.109,.217),l(-.317,.416),l(-.584,.27),l(-.152,.068),l(-.458,-.491),l(-1.041,-1.001),l(-.458,-.606),l(-.359,-1.03),l(-.345,-.72),l(-.136,-.493),l(.12,-.269),l(.053,-.34),l(-.458,-.719),l(-.231,-.861),l(.148,-.861),l(-.002,-.48),l(-.537,-1.326),l(-.496,-2.244),l(.772,-.02),l(.04,-.678),l(-.077,-.749),l(-.456,-.006),l(.016,-.06),l(-.099,-.522),l(-.26,-.508),l(-1.018,-1.283),l(-.343,-.55),l(-1.102,-2.158),l(-.841,-1.623),l(-.9,-1.509),l(-.988,-1.269),l(-.511,-1.044),l(-.122,-.396),l(-.045,-.551),l(.015,-.578),l(.248,-.197),l(.352,-.144),l(.758,.462),l(.778,-.513),l(.591,-.286),l(.499,-.088),l(.294,.083),l(.45,.478),l(.463,.309),l(.636,.151),l(2.201,-.013),l(1.296,.006),l(.631,.011),l(1.636,.019),l(2.59,-.016),l(.989,.023),l(.408,.096),l(.305,.366),l(.401,.322),l(.622,.151),l(.697,.024),l(2.024,-.026),l(.349,.21),l(.408,.083),l(1.164,-.063),l(.717,.08),l(1.044,-.203),l(1.96,-.379),l(.93,-.218),l(1.845,-.364),l(.165,.056),l(.086,.099),l(1.089,.093),l(.294,.055),l(.456,.393),l(-.811,.315),l(-.891,.02),l(-.284,.143),l(-.993,.938),l(-.209,.029),l(-.62,-.773),l(-1.048,.134),l(-2.962,.47),l(-1.183,.021),l(.005,1.215),l(-.007,1.286),l(-.025,.876),l(-.043,1.201),l(.002,3.561),l(-.586,.046),l(-1.564,.052),l(-.146,.028),l(-.106,2.657),l(-.009,1.201),l(.013,1.624),l(.007,.806), +N(248.453,316.576),l(-.306,.101),l(-.892,-.087),l(-.538,-.293),l(-.236,-.015),l(-.311,.163),l(-.418,.398),l(-.498,.192),l(-1.156,.091),l(-.349,.09),l(-.358,.207),l(-.267,.621),l(-.114,.341),l(.06,.532),l(-.163,.622),l(-.104,.148),l(-.453,.031),l(-.534,.104),l(-.956,-.413),l(.667,-.639),l(.326,-.444),l(.582,-.4),l(.025,-.147),l(-.372,-.177),l(-.273,-.117),l(-1.353,.534),l(-1.01,-.013),l(-.545,.163),l(-.202,-.339),l(.128,-.192),l(.959,-.268),l(.266,.028),l(.792,-.208),l(.441,-.118),l(-.605,-.162),l(-.582,.002),l(-.77,.001),l(-.014,-.413),l(.265,-.31),l(-.007,-.191),l(-.446,-.073),l(-.356,-.44),l(-.66,.384),l(-.669,-.175),l(.292,-.53),l(.041,-.177),l(-.378,.045),l(-.361,.147),l(-.416,-.396),l(-.215,-.117),l(.413,-.279),l(.114,-.177),l(-.091,-.278),l(-.053,-.073),l(-.351,.03),l(-.773,-.424),l(-.135,-.059),l(.844,-.192),l(.253,-.161),l(.1,-.294),l(.396,-.366),l(.049,-.234),l(-.641,.06),l(-.257,.104),l(-.312,-.073),l(-.256,-.672),l(.573,-.395),l(-.565,-.378),l(-.12,-.421),l(.757,-.452),l(-.14,-.421),l(-.686,.422),l(-.091,-1.523),l(.399,-.596),l(-.185,-.825),l(.013,-.218),l(.593,.014),l(.41,.245),l(.711,.071),l(.171,-.246),l(.002,-.159),l(-.896,-.447),l(-.867,.146),l(-.317,-.173),l(-.536,.059),l(-.017,-.231),l(.339,-.333),l(.025,-.246),l(-.067,-.087),l(.186,-.202),l(.536,.014),l(.229,-.377),l(.01,-.216),l(-.722,-.389),l(-.354,-.129),l(-.886,.045),l(-.332,-.101),l(-.024,-.49),l(-.939,.16),l(-.115,-.101),l(.122,-.145),l(1.032,-.521),l(.251,-.116),l(.4,-.404),l(.266,-.389),l(.833,-.06),l(.268,.201),l(.059,.346),l(-.648,.202),l(-.323,.274),l(.11,.505),l(.117,.058),l(.191,-.102),l(.268,-.39),l(.183,-.087),l(.242,.101),l(-.037,.317),l(.057,.504),l(.886,-.996),l(.161,-.678),l(.056,-.647),l(.237,-.375),l(.079,-.058),l(.631,-.217),l(-.201,-.071),l(-.438,-.143),l(-.056,-.158),l(.101,-.273),l(.246,-.072),l(.571,-.245),l(.599,-.431),l(.271,-.459),l(-.061,-.229),l(-.394,-.157),l(-.662,-.399),l(-.053,-.372),l(.139,-.243),l(.105,-.458),l(-.06,-.828),l(.366,-.33),l(.676,-.272),l(-.431,-.585),l(-.053,-.784),l(.133,-.158),l(.554,-.157),l(.054,-.314),l(-.116,-.285),l(-.317,-.085),l(-.272,-.198),l(.233,-.329),l(.087,-.313),l(-.401,-.185),l(-.274,-.014),l(-.161,.101),l(-.476,.414),l(-.548,.058),l(-.087,.001),l(-.289,-.199),l(-.16,-.484),l(-.399,-.726),l(-.133,-.697),l(.188,-.911),l(.137,-.413),l(.722,-.739),l(.535,-.767),l(-.006,-.326),l(-.544,-1.757),l(.001,-.608),l(.088,-.567),l(-.076,-.438),l(-.528,-.891),l(-.04,-.298),l(.236,-.198),l(.499,.098),l(.182,-.085),l(.2,-.142),l(.097,-.143),l(.41,-1.288),l(.252,-.481),l(.304,-.935),l(.18,-.65),l(.664,-.808),l(.363,-.722),l(.201,-.636),l(.252,-.946),l(.311,-.691),l(.187,-.128),l(.273,-.382),l(.013,-.296),l(-.312,-.847),l(.082,-.184),l(.455,-.452),l(.206,-.339),l(.028,-.24),l(-.093,-.226),l(-.166,-.805),l(-.292,-2.088),l(-.098,-.86),l(.031,-.565),l(.412,-.565),l(.37,-.537),l(.207,-.564),l(.007,-.734),l(-.339,-.521),l(-.098,-.409),l(.295,-.96),l(.218,-.941),l(.127,-.556),l(.461,-.594),l(.171,-.918),l(.243,-.975),l(.126,-.805),l(.082,-.565),l(-.063,-1.087),l(.422,-.664),l(.211,-.494),l(-.221,-.932),l(-.048,-.833),l(.148,-.24),l(-.022,-.917),l(.229,-.607),l(-.124,-.297),l(-.365,-.084),l(.06,-.324),l(-.046,-.396),l(.223,-.198),l(.402,-.198),l(.137,-.424),l(-.008,-.819),l(.093,-.593),l(.182,-.918),l(-.004,-2.344),l(-.172,-2.074),l(-.042,-1.539),l(-.194,-.974),l(-.15,-.387),l(.852,-.275),l(.259,-.298),l(.228,-.933),l(.15,-.199),l(.586,-.187),l(.152,.253),l(.555,.745),l(.304,.647),l(.193,1.213),l(.25,.521),l(.761,.744),l(.017,.282),l(-.437,1.555),l(-.04,.354),l(.249,.676),l(.769,1.11),l(.212,.563),l(.278,.973),l(.397,2.144),l(.272,.182),l(1.047,-.006),l(.107,.056),l(.212,.14),l(.161,.154),l(-.093,.636),l(-.541,1.457),l(-.36,.256),l(-1.346,.53),l(-.819,.372),l(-.204,.312),l(.25,.817),l(-.421,.722),l(-.007,.579),l(.113,.437),l(.34,.449),l(.03,.226),l(-.273,.369),l(-.161,.382),l(.114,.507),l(.53,.477),l(.011,.227),l(-.152,.311),l(-.333,.017),l(-.791,.089),l(-.329,.835),l(-.464,.835),l(-.608,.694),l(-.282,.439),l(-.823,1.839),l(.167,1.466),l(.054,.762),l(-.124,.185),l(-.492,.271),l(-.292,.34),l(-.388,1.201),l(-.156,.961),l(.285,.633),l(.408,1.154),l(.784,2.816),l(.055,.69),l(-.075,.41),l(-1.083,1.854),l(-.319,.595),l(.088,.409),l(.189,1.06),l(-.078,.325),l(-1.334,1.11),l(-.231,.312),l(-.142,1.075),l(.014,1.16),l(.249,1.103),l(.437,.932),l(-.202,.143),l(-.951,.529),l(-.126,.17),l(-.053,.312),l(-.511,2.427),l(-.316,.541),l(-.1,.37),l(.123,1.835),l(.231,.867),l(.012,.427),l(-.596,.317),l(-.172,.172),l(-.106,.271),l(.094,1.226),l(.125,.128),l(.555,.111),l(.088,.655),l(-.191,1.458),l(.252,.585),l(.26,.185),l(.789,.11),l(.302,.17),l(-.007,.186),l(-.245,.202),l(-.322,.13),l(-.726,.033),l(-.757,.146),l(.176,.171),l(.586,.298),l(.552,.385),l(.017,.216),l(-.767,.794),l(-.059,1.094),l(.158,1.035),l(-.216,.896),l(-.212,.434),l(-.226,.262),l(-.598,.161),l(-.28,.219),l(-.249,.781),l(.446,.648),l(-.069,.188),l(-.296,1.218),l(-.307,.263),l(-1.729,1.01),l(-.271,.292),l(-.037,.45),l(.28,1.309),l(.508,1.123),l(.218,.043),l(.961,-.283),l(.654,-.121),l(.187,.248),l(.231,2.285),l(.778,.568),l(.669,.041),l(1.41,-.052),l(2.827,.132),l(.841,.217),l(1.385,.36),l(.286,.039),M(236.642,296.773),l(-.394,-.113),l(-.43,-.028),l(-.21,-.171),l(-.133,-.229),l(.21,-.457),l(.15,-.657),l(-.087,-.514),l(.011,-.414),l(.364,-.728),l(.817,-.116),l(.36,.327),l(.044,.328),l(-.688,.443),l(-.146,.229),l(.493,.771),l(-.194,1.058),l(-.167,.271),M(238.177,317.937),l(-.445,-.177),l(.083,-.842),l(-.849,.075),l(-.073,-.368),l(.218,-.354),l(.823,.102),l(.508,-.207),l(.205,.103),l(.054,.812),l(-.267,.34),l(-.257,.518),M(247.801,322.062),l(-1.033,.102),l(-.467,-.118),l(-.55,-.237),l(-.42,.001),l(-.481,.104),l(-.935,.226),l(-.496,.03),l(.125,-.343),l(.202,-.312),l(-.104,-.312),l(.906,-.15),l(1.434,.058),l(.433,.323),l(.706,-.007),l(-.622,-.689),l(-.307,-.163),l(-.56,-.117),l(-.178,-.089),l(-.188,.03),l(-.338,-.341),l(-.229,-.4),l(1.611,-.581),l(-.044,-.296),l(-.165,-.147),l(-1.819,.285),l(-.292,-.222),l(.263,-.474),l(.146,-.163),l(1.074,-.52),l(.868,-.637),l(.414,.28),l(1.153,.062),l(-.008,1.144),l(-.098,3.675), +N(456.133,239.67),l(.187,.154),l(.163,.027),l(.154,.169),l(.264,.097),l(-.103,.227),l(.267,.451),l(.43,.478),l(.469,.604),l(.246,.96),l(.377,.662),l(.563,.491),l(.57,.321),l(.533,.223),l(.552,.266),l(.106,.169),l(-.051,.537),l(.109,.211),l(.201,.098),l(.78,-.019),l(.127,.239),l(-.032,.565),l(.163,.564),l(.524,.873),l(.352,.153),l(.938,.136),l(.549,.167),l(.479,.35),l(.306,.451),l(.186,.098),l(-.317,.411),l(-.388,.327),l(-.507,.243),l(-.747,.075),l(-.304,.115),l(-.7,.823),l(-.586,.583),l(-.362,.229),l(-.747,.357),l(-.388,.355),l(-.107,.636),l(-.222,.666),l(-.247,.241),l(-.634,.357),l(-.98,.33),l(-.249,.214),l(-.217,.708),l(-.345,.963),l(-.288,.354),l(-.237,.129),l(-.584,.116),l(-.43,-.026),l(-.473,.06),l(-.511,-.011),l(-.819,-.193),l(-.744,-.32),l(-.979,-.645),l(-.545,-.039),l(-.333,.186),l(-.084,.24),l(-.585,1.134),l(-.382,.469),l(-.651,.625),l(-.632,.428),l(-.8,.372),l(-.823,.033),l(-.854,.047),l(-.368,-.097),l(-.11,-.183),l(.003,-.48),l(.243,-.609),l(.166,-.538),l(-.21,-.762),l(-.547,-.943),l(-.716,-.787),l(-.528,-.067),l(-.007,-.806),l(-.013,-1.624),l(.009,-1.201),l(.106,-2.657),l(.146,-.028),l(1.564,-.052),l(.586,-.046),l(-.002,-3.561),l(.043,-1.201),l(.025,-.876),l(.007,-1.286),l(-.005,-1.215),l(1.183,-.021),l(2.962,-.47),l(1.048,-.134),l(.62,.773),l(.209,-.029),l(.993,-.938),l(.284,-.143),l(.891,-.02),l(.811,-.315), +N(279.288,257.295),l(.02,.239),l(-.544,1.57),l(-.375,.468),l(-1.007,.74),l(-.301,.27),l(-.352,.51),l(-.609,-.363),l(-.35,-.097),l(-.235,.029),l(-.387,.172),l(-.745,.131),l(-.71,.005),l(-.564,-.096),l(-.992,-.333),l(-.607,-.025),l(-1.187,.332),l(-.19,-.056),l(.064,-.212),l(.425,-.426),l(.486,-.398),l(.11,-.198),l(-.21,-.619),l(.048,-.227),l(.625,-.851),l(.617,-1.203),l(.018,-.268),l(-.939,-.503),l(-.65,-.18),l(-1.448,-.697),l(-1.632,-1.106),l(-.671,-.307),l(-1.173,-.204),l(-.498,-.237),l(-.835,-.588),l(-.576,-.562),l(-1.271,-1.376),l(-.782,-.913),l(-.225,-.337),l(-.19,-.056),l(.149,-.325),l(.395,-1.104),l(.385,-1.188),l(-.016,-.635),l(.133,-.509),l(.278,-.341),l(.698,-1.105),l(.332,-.383),l(.33,-.044),l(.784,-.202),l(1.104,-.162),l(1.076,-.204),l(.126,-.128),l(.843,.01),l(.928,-.02),l(.352,.054),l(1.952,.991),l(.089,.084),l(.253,.408),l(.084,.663),l(.521,.872),l(.104,.959),l(-.132,.862),l(-.086,.721),l(-.006,.72),l(.372,.04),l(.818,.15),l(.925,.221),l(.346,-.03),l(.709,-.413),l(.115,-.001),l(.724,.278),l(.843,.404),l(.121,.437),l(.487,2.524),l(.254,.563),l(.224,.055),l(1.29,-.445),l(.234,.112),l(.491,.336),l(.019,.141),l(-.321,.75),l(-.298,.835),l(-.222,.819),l(-.027,.777),l(.063,.423), +N(444.673,255.519),l(.528,.067),l(.716,.787),l(.547,.943),l(.21,.762),l(-.166,.538),l(-.243,.609),l(-.003,.48),l(.11,.183),l(.368,.097),l(.854,-.047),l(.823,-.033),l(.8,-.372),l(.632,-.428),l(.651,-.625),l(.382,-.469),l(.585,-1.134),l(.084,-.24),l(.333,-.186),l(.545,.039),l(.979,.645),l(.744,.32),l(.819,.193),l(.511,.011),l(.473,-.06),l(.43,.026),l(.584,-.116),l(.237,-.129),l(.288,-.354),l(.345,-.963),l(.217,-.708),l(.249,-.214),l(.98,-.33),l(.634,-.357),l(.247,-.241),l(.222,-.666),l(.107,-.636),l(.388,-.355),l(.747,-.357),l(.362,-.229),l(.586,-.583),l(.7,-.823),l(.304,-.115),l(.747,-.075),l(.507,-.243),l(.388,-.327),l(.317,-.411),l(.067,.042),l(.72,.023),l(.597,.139),l(.99,.403),l(.31,-.016),l(.529,-.145),l(.442,.025),l(.547,.124),l(.342,.225),l(.159,.183),l(.295,1.199),l(.181,.946),l(.441,.689),l(.33,.944),l(.147,.678),l(.072,.763),l(-.057,1.301),l(-.03,.806),l(.095,.324),l(-1.449,-.585),l(-.279,.199),l(-.657,.979),l(-.28,.567),l(-.005,.325),l(.39,.676),l(.307,.465),l(.458,.322),l(.671,.109),l(.595,-.004),l(.076,-.594),l(.064,-.198),l(.312,-.186),l(.131,-.015),l(.192,-.058),l(1.331,-.011),l(-.182,1.195),l(-.352,.849),l(-.182,.184),l(-.404,.1),l(-.093,.24),l(.199,.536),l(-.104,.467),l(-.248,.354),l(-.569,.453),l(-.923,.581),l(-.591,.75),l(-1.383,1.98),l(-.631,.834),l(-1.242,1.373),l(-1.193,1.062),l(-.829,.863),l(-1.434,1.034),l(-1.379,1.091),l(-.552,.382),l(-.989,.638),l(-.676,.298),l(-.782,.101),l(-.98,-.012),l(-.549,.071),l(-.132,.354),l(.013,.127),l(-.109,.085),l(-.449,-.098),l(-.553,-.126),l(-.303,.015),l(-.25,.198),l(-.272,.312),l(-.226,.113),l(-.36,-.056),l(-.768,-.408),l(-.759,-.168),l(-.542,-.013),l(-.31,.113),l(-.38,.27),l(-.482,-.099),l(-.645,-.21),l(-.295,.1),l(-.638,.043),l(-.589,.214),l(-.729,.538),l(-.72,.086),l(-.44,-.013),l(-.667,-.084),l(-.738,.072),l(-.575,.199),l(-.827,.82),l(-1.251,-.576),l(-.092,-.509),l(-.218,-.183),l(-.479,-.056),l(-.28,.085),l(-.257,-.479),l(-.343,-.056),l(-.149,.255),l(-.035,.197),l(-.312,-.112),l(-.119,-.226),l(.267,-.495),l(.103,-.424),l(-.857,-1.354),l(-.323,-.282),l(-.134,-.226),l(.173,-.17),l(.636,-.044),l(.172,-.424),l(.06,-.819),l(-.163,-.663),l(-.186,-.522),l(-.61,-1.143),l(-.75,-1.029),l(-.472,-.903),l(-.612,-1.383),l(-.646,-1.467),l(-.573,-.818),l(-.436,-.467),l(.152,-.068),l(.584,-.27),l(.317,-.416),l(.109,-.217),l(.335,-.116),l(.329,.127),l(.637,.348),l(.193,.222),l(.042,.345),l(.055,.528),l(.296,.212),l(.517,.039),l(.892,-.048),l(.745,.042),l(.581,.166),l(.427,-.034),l(.581,-.498),l(.545,-.302),l(.454,-.318),l(.057,-.205),l(-.025,-2.246),l(-.031,-1.894),l(.006,-3.434),M(462.462,268.501),l(.412,-.044),l(.194,-.553),l(.633,-.343),l(1.035,-.303),l(.263,-.199),l(.582,-1.007),l(.268,-.326),l(.143,-.241),l(-.104,-.226),l(-.967,-.744),l(-.33,-.337),l(-.422,-.266),l(-.308,.086),l(-.995,.359),l(-.65,.329),l(-.513,.567),l(-.275,.44),l(-.691,.611),l(.12,.409),l(.582,.858),l(.285,.366),l(.739,.561),M(432.955,250.661),l(.456,.006),l(.077,.749),l(-.04,.678),l(-.772,.02),l(-.078,-.354),l(-.028,-.396),l(.285,-.297),l(.101,-.406), +N(471.719,258.047),l(.075,.296),l(-.071,.495),l(.261,.889),l(.068,.382),l(-.131,.015),l(-.312,.186),l(-.064,.198),l(-.076,.594),l(-.595,.004),l(-.671,-.109),l(-.458,-.322),l(-.307,-.465),l(-.39,-.676),l(.005,-.325),l(.28,-.567),l(.657,-.979),l(.279,-.199),l(1.449,.585), +N(462.462,268.501),l(-.739,-.561),l(-.285,-.366),l(-.582,-.858),l(-.12,-.409),l(.691,-.611),l(.275,-.44),l(.513,-.567),l(.65,-.329),l(.995,-.359),l(.308,-.086),l(.422,.266),l(.33,.337),l(.967,.744),l(.104,.226),l(-.143,.241),l(-.268,.326),l(-.582,1.007),l(-.263,.199),l(-1.035,.303),l(-.633,.343),l(-.194,.553),l(-.412,.044), +N(790.15,283.022),l(.738,.197),l(.008,-.227),l(-.242,-.524),l(.052,-.284),l(.233,.014),l(.389,.17),l(.37,.751),l(.277,.964),l(.48,.17),l(1.753,.691),l(.506,.113),l(.37,-.072),l(.699,-.483),l(.885,-.343),l(.4,.027),l(.329,.17),l(.066,.454),l(-.022,.198),l(-.402,1.236),l(-.283,.072),l(-.761,.058),l(-.035,.683),l(-.124,.156),l(-.424,.029),l(-.746,.016),l(-.432,.2),l(-.271,.284),l(.041,.384),l(.254,.525),l(-.002,.213),l(-.151,.199),l(-.646,.515),l(-.898,1.129),l(-.847,1.058),l(-.756,.587),l(-.68,.316),l(-.337,-.171),l(-.47,-.313),l(-.237,-.328),l(.056,-.314),l(.288,-.386),l(.307,-.671),l(.398,-.5),l(-.031,-.343),l(-.271,-.128),l(-.761,-.582),l(-.421,-.185),l(-.593,-.184),l(-.98,-.452),l(-.306,-.256),l(-.11,-.17),l(.081,-.128),l(.419,-.157),l(1.389,-.685),l(.209,-.512),l(-.078,-.695),l(.087,-.312),l(.396,-.441),l(.032,-.383),l(-.482,-.837),l(.081,-.567),l(-.156,-.311),l(-.479,-.655),l(-.574,-.678),l(.102,-.164),l(-.145,-.304),l(-.291,-.351),l(-.336,-.188),l(-.29,-.163),l(.117,.233),l(.497,.515),l(.049,.141),l(-.169,0),l(-.211,-.281),l(-.525,-.631),l(-.622,-.771),l(-.518,-.561),l(.001,-.117),l(-.268,-.257),l(.04,-.141),l(.013,-.14),l(-.048,-.188),l(-.197,-.396),l(-.379,-.42),l(-.347,-.257),l(.163,-.046),l(.205,.093),l(.358,-.047),l(.131,-.093),l(.084,.28),l(-.149,.187),l(.186,.303),l(.177,.21),l(.167,.116),l(.228,.164),l(.041,-.141),l(.269,.023),l(.519,.257),l(.42,.117),l(.274,.07),l(.128,.257),l(-.011,.141),l(.185,.023),l(.146,-.188),l(.185,.023),l(-.022,.164),l(.227,.351),l(.249,.187),l(.233,.28),l(-.18,.023),l(-.076,.164),l(.093,.163),l(-.242,-.023),l(-.175,-.047),l(.143,.117),l(.251,.188),l(.23,.233),l(.352,.28),l(.063,.234),l(.019,.21),l(-.261,-.047),l(.096,.164),l(.239,.351),l(.256,.188),l(-.292,.023),l(-.226,0),l(-.205,-.047),l(-.006,.141),l(.306,.14),l(.324,.164),l(-.09,.211),l(.205,.046),l(.265,-.023),l(.226,0),l(.223,.141),l(-.114,.07),l(-.031,.141),l(.025,.141),l(.136,.06),M(782.939,297.694),l(-.088,.158),l(-.558,.13),l(-.309,.288),l(-.322,.101),l(-.246,.244),l(-.692,-.242),l(-.16,.086),l(.15,.216),l(.429,.415),l(-.141,.173),l(.02,.259),l(-.064,.431),l(-.218,-.071),l(-.976,-.099),l(.418,.229),l(.449,.244),l(-.278,.49),l(-.427,.896),l(-.212,.549),l(-.418,.318),l(-.673,.349),l(-.171,.246),l(-.259,.145),l(-.581,.233),l(-.593,.406),l(-.398,.015),l(-1.156,-.258),l(-.628,.112),l(-.585,-.442),l(-.812,-.158),l(-.373,-.066),l(-.162,-.308),l(-.467,-.098),l(-.24,.142),l(-.062,.168),l(-.78,.095),l(-.214,-.166),l(-.515,-.095),l(-.146,-.286),l(.432,-.089),l(-.223,-.216),l(.328,-.116),l(.322,-.001),l(-.452,-.482),l(.82,.266),l(-.464,-.576),l(.121,-.145),l(.946,.156),l(.082,-.13),l(-.141,-.173),l(-.201,-.216),l(-.06,-.288),l(.283,-.303),l(.569,-.246),l(.328,-.374),l(.561,-.375),l(.102,-.302),l(.998,-.575),l(1.106,-.275),l(.713,-.331),l(.544,-.36),l(.377,-.101),l(.685,-.575),l(.066,-.272),l(.48,-.302),l(.373,-.015),l(.787,-.331),l(.664,-.402),l(.126,-.215),l(-.008,-.172),l(.266,-.144),l(.448,-.302),l(-.109,-.501),l(.076,-.214),l(.166,-.44),l(.306,.048),l(.066,-.152),l(.58,-.259),l(.444,-.272),l(.137,-.285),l(.131,-1.187),l(.512,-.647),l(.372,.047),l(.365,.165),l(.032,.259),l(.337,.06),l(.187,.186),l(.231,.799),l(.312,.242),l(.973,-.645),l(.426,-.029),l(.367,.113),l(.222,.5),l(-.197,.399),l(.299,.429),l(.066,.271),l(-.611,.659),l(-.261,.401),l(-.476,.358),l(-.868,.746),l(-.578,.359),l(-.295,.13),l(-.236,.258),l(-.389,.159),l(-.271,.258),l(.416,.407),l(.428,.047),l(.421,.289),l(-.276,.113),l(-.484,.07),l(-.503,-.296),l(-.488,.131),l(-.352,.158), +N(247.899,318.387),l(.008,-1.144),l(.821,.289),l(.06,.206),l(-.354,.312),l(-.534,.337),M(248.453,316.576),l(-.286,-.039),l(-1.385,-.36),l(-.841,-.217),l(-2.827,-.132),l(-1.41,.052),l(-.669,-.041),l(-.778,-.568),l(-.231,-2.285),l(-.187,-.248),l(-.654,.121),l(-.961,.283),l(-.218,-.043),l(-.508,-1.123),l(-.28,-1.309),l(.037,-.45),l(.271,-.292),l(1.729,-1.01),l(.307,-.263),l(.296,-1.218),l(.069,-.188),l(-.446,-.648),l(.249,-.781),l(.28,-.219),l(.598,-.161),l(.226,-.262),l(.212,-.434),l(.216,-.896),l(-.158,-1.035),l(.059,-1.094),l(.767,-.794),l(-.017,-.216),l(-.552,-.385),l(-.586,-.298),l(-.176,-.171),l(.757,-.146),l(.726,-.033),l(.322,-.13),l(.245,-.202),l(.007,-.186),l(-.302,-.17),l(-.789,-.11),l(-.26,-.185),l(-.252,-.585),l(.191,-1.458),l(-.088,-.655),l(-.555,-.111),l(-.125,-.128),l(-.094,-1.226),l(.106,-.271),l(.172,-.172),l(.596,-.317),l(-.012,-.427),l(-.231,-.867),l(-.123,-1.835),l(.1,-.37),l(.316,-.541),l(.511,-2.427),l(.053,-.312),l(.126,-.17),l(.951,-.529),l(.202,-.143),l(-.437,-.932),l(-.249,-1.103),l(-.014,-1.16),l(.142,-1.075),l(.231,-.312),l(1.334,-1.11),l(.078,-.325),l(-.189,-1.06),l(-.088,-.409),l(.319,-.595),l(1.083,-1.854),l(.075,-.41),l(-.055,-.69),l(-.784,-2.816),l(-.408,-1.154),l(-.285,-.633),l(.156,-.961),l(.388,-1.201),l(.292,-.34),l(.492,-.271),l(.124,-.185),l(-.054,-.762),l(-.167,-1.466),l(.823,-1.839),l(.282,-.439),l(.608,-.694),l(.464,-.835),l(.329,-.835),l(.791,-.089),l(.333,-.017),l(.152,-.311),l(-.011,-.227),l(-.53,-.477),l(-.114,-.507),l(.161,-.382),l(.273,-.369),l(-.03,-.226),l(-.34,-.449),l(-.113,-.437),l(.007,-.579),l(.421,-.722),l(-.25,-.817),l(.204,-.312),l(.819,-.372),l(1.346,-.53),l(.36,-.256),l(.541,-1.457),l(.093,-.636),l(-.161,-.154),l(-.212,-.14),l(-.107,-.056),l(2.026,-2.087),l(.292,-.27),l(.322,.181),l(.193,.169),l(.615,.194),l(.901,-.034),l(.527,-.045),l(.531,.067),l(.37,.195),l(.341,.309),l(.416,1.084),l(1.034,-1.784),l(.686,-.004),l(1.33,.077),l(.592,.109),l(.19,.056),l(.225,.337),l(.782,.913),l(1.271,1.376),l(.576,.562),l(.835,.588),l(.498,.237),l(1.173,.204),l(.671,.307),l(1.632,1.106),l(1.448,.697),l(.65,.18),l(.939,.503),l(-.018,.268),l(-.617,1.203),l(-.625,.851),l(-.048,.227),l(.21,.619),l(-.11,.198),l(-.486,.398),l(-.425,.426),l(-.064,.212),l(.19,.056),l(1.187,-.332),l(.607,.025),l(.992,.333),l(.564,.096),l(.71,-.005),l(.745,-.131),l(.387,-.172),l(.235,-.029),l(.35,.097),l(.609,.363),l(.352,-.51),l(.301,-.27),l(1.007,-.74),l(.375,-.468),l(.544,-1.57),l(-.02,-.239),l(.957,-.161),l(.462,-.017),l(.206,.196),l(.517,1.154),l(-.094,1.638),l(-.161,.467),l(-.521,.313),l(-1.754,.744),l(-.348,.242),l(-1.633,1.448),l(-1.435,1.363),l(-1.805,1.816),l(-.833,.88),l(-.214,.27),l(-.443,.524),l(-.065,.452),l(-.595,2.359),l(-.103,.522),l(.049,.847),l(.168,.986),l(-.118,.325),l(-.48,.524),l(-.24,.495),l(-.011,.522),l(.194,.577),l(-.054,.338),l(-.162,.273),l(-.26,.325),l(.015,.226),l(.924,.831),l(.68,.281),l(.715,.281),l(.283,.169),l(.281,.325),l(-.025,.325),l(-.362,.523),l(-.043,.396),l(.105,.339),l(.174,.269),l(.466,.325),l(.522,.168),l(.109,.113),l(.226,.892),l(-.308,.481),l(-.75,.937),l(-.729,.766),l(-.313,.737),l(-.368,.284),l(-.832,.342),l(-1.04,.342),l(-1.92,.401),l(-1.795,.188),l(-1.361,.116),l(-.945,.044),l(-1.175,-.11),l(-.934,-.226),l(-.128,.199),l(.036,.808),l(.322,.312),l(.308,.184),l(-.09,.298),l(-.381,.624),l(-.345,.498),l(-.069,.385),l(.392,.682),l(.066,.285),l(-.208,.214),l(-.105,.057),l(-1.251,.473),l(-1.137,.116),l(-.814,-.069),l(-.967,-.34),l(-1.47,-.396),l(-.246,.057),l(-.23,.271),l(.041,.598),l(.429,.684),l(.037,.398),l(-.242,.643),l(.092,.385),l(.773,.54),l(.796,.084),l(.369,-.2),l(-.387,-.398),l(.872,-.188),l(.383,-.043),l(.234,1.041),l(.052,.3),l(-.144,.157),l(-.299,.101),l(-.448,.072),l(-.261,-.157),l(-.104,-.299),l(-.115,-.071),l(-1.046,.073),l(-.67,.201),l(-.212,.101),l(.151,.214),l(.591,.07),l(.47,.113),l(.452,.113),l(.06,.028),l(-.864,.388),l(-.776,.287),l(-.577,.602),l(.003,.414),l(.161,.787),l(-.081,.258),l(-.815,.817),l(.022,.215),l(.423,.371),l(-.491,.116),l(-1.194,.088),l(-.48,.087),l(-.632,.246),l(-.619,.389),l(-.56,.548),l(-.549,.821),l(-.052,.389),l(.061,.375),l(.312,.591),l(.48,.446),l(.98,.633),l(.657,.244),l(.97,.143),l(.362,.086),l(.14,.274),l(-.151,.796),l(-.128,.348),l(-.342,.464),l(-.189,.145),l(-1.08,.524),l(-1.541,.814),l(-.712,.698),l(-.179,.276),l(-.093,.45),l(.111,.523),l(-.169,.451),l(-.239,.32),l(-.97,.454),l(-.969,.25),l(-.421,.221),l(-.323,.396),l(-.226,.791),l(-.054,.514),l(.2,.777),l(.547,.896),l(.699,.779),l(.235,.339),l(-.101,.032),M(247.899,318.387),l(.18,.182),l(.148,.073),l(.607,-.075),l(.344,.133),l(.648,.725),l(.908,.665),l(.993,.756),l(.525,.222),l(.73,.37),l(.246,.074),l(.42,-.001),l(.483,.163),l(1.283,.027),l(.142,-.016),l(-.006,.224),l(-.19,.209),l(-.492,.06),l(-1.198,.092),l(-.777,.196),l(-.364,0),l(-1.179,-.355),l(-.753,-.088),l(-1.15,-.027),l(-.814,-.014),l(-.831,.081),l(.098,-3.675), +N(346.758,54.457),l(.127,-.162),l(.42,-.179),l(.894,.015),l(.674,-.098),l(-.354,-.227),l(-.405,-.34),l(.317,-.342),l(.277,0),l(.956,.42),l(.67,.048),l(.3,-.163),l(-.191,-.26),l(-.625,-.373),l(.366,-.245),l(1.037,.226),l(.957,.08),l(.746,.275),l(.446,.551),l(-.119,.405),l(-.441,.292),l(.922,.806),l(.553,-.356),l(.352,-.13),l(.63,-.114),l(.49,-.179),l(.061,-.21),l(-.169,-.778),l(.542,-.245),l(.501,.454),l(.426,.307),l(.489,.209),l(.215,.016),l(.185,-.13),l(-.264,-.454),l(.243,-.163),l(.27,-.033),l(.817,-.164),l(.683,.438),l(.536,.242),l(.542,.063),l(.05,-.178),l(-.358,-.535),l(1.006,.145),l(1.439,.079),l(.787,-.115),l(.427,-.229),l(-.021,-.716),l(1.167,.08),l(.635,.471),l(1.118,.323),l(.683,.015),l(.273,.243),l(-.252,.552),l(.786,.29),l(1.674,.159),l(.127,.145),l(.143,.548),l(-.07,.387),l(-.152,.256),l(-.152,.256),l(-.443,.129),l(-.815,.018),l(-.195,.096),l(-.04,.431),l(-.515,.463),l(-.497,.16),l(-.568,-.031),l(-.422,-.159),l(-.817,.495),l(-.539,.144),l(-1.46,.463),l(-.853,.113),l(-.726,.001),l(-.771,.097),l(-.784,.587),l(-.473,.127),l(-1.078,.097),l(-.709,-.03),l(-1.316,-.171),l(-.608,-.142),l(-1.283,-.489),l(-1.058,-.093),l(-.443,.064),l(-1.041,-.014),l(-1.834,-.124),l(-.297,-.206),l(.434,-.191),l(1.127,-.352),l(.701,-.59),l(-.818,-.015),l(-.51,-.126),l(-.428,-.398),l(-.253,-.095),l(-.358,.081),l(-1.564,.115),l(-.557,.033),l(-.37,-.223),l(.141,-.192),l(.388,-.129),l(.669,-.097),l(.794,-.017),l(.729,-.114),l(1.049,-.098),l(.376,-.194),l(.178,-.322),l(-.144,-.258),l(-.358,-.177),l(-.426,-.015),l(-.478,-.145),l(-1.005,-.047),l(-.821,.099),l(-.424,.162),l(-.676,.082),l(-1.041,-.272),l(-.16,-.21), +N(462.829,67.958),l(.145,.053),l(.16,.131),l(-.043,.174),l(-.175,.044),l(-.189,0),l(-.116,0),l(-.088,.043),l(-.058,.131),l(-.175,.277),l(-.219,.204),l(-.319,.131),l(-.204,.131),l(-.088,.16),l(.029,.16),l(.131,.437),l(.073,.189),l(.029,.16),l(-.175,.131),l(0,.175),l(.175,.233),l(.203,.087),l(.088,.073),l(0,.073),l(.015,.087),l(.043,.146),l(.175,.043),l(.059,.059),l(-.175,.073),l(-.262,.043),l(-.16,.058),l(-.059,.102),l(-.087,.116),l(-.131,0),L(461.402,72),l(-.015,.087),l(-.116,.058),l(.081,.106),l(-.125,.025),l(-.087,-.015),l(-.306,-.043),l(-.16,-.058),l(-.175,-.073),l(-.204,-.044),l(-.131,.102),l(-.204,-.029),l(-.131,.044),l(-.16,.087),l(-.146,.014),l(-.146,-.087),l(-.116,-.029),l(-.175,0),l(-.204,-.117),l(-.116,-.174),l(-.203,-.117),l(-.146,-.043),l(-.072,-.117),l(-.189,0),l(-.247,-.043),l(-.204,-.117),l(-.029,0),l(-.276,-.014),l(-.102,-.102),l(-.248,-.043),l(-.116,-.102),l(-.189,-.087),l(0,.073),l(-.116,.087),l(-.131,-.058),l(-.015,-.073),l(-.087,-.029),l(-.103,0),l(-.276,.117),l(-.102,.029),l(-.131,.015),l(-.219,.015),l(-.146,.043),l(-.262,.029),l(-.276,.087),l(-.116,.102),l(-.087,0),l(.156,-.19),l(-.003,-.351),l(.183,-.238),l(-.368,-.21),l(-.605,.437),l(-.334,-.251),l(-.527,-.038),l(.043,-.942),l(-.396,.188),l(-.336,-.415),l(.158,-.202),l(-.209,-.254),l(.265,-.074),l(-.092,-.252),l(.344,-.042),l(1.026,-.084),l(-.006,-.132),l(.561,-.108),l(.133,-.188),l(.436,.101),l(.074,-.113),l(.317,.05),l(.083,-.215),l(1.104,.193),l(.446,-.294),l(.091,.165),l(.514,-.089),l(1.383,.029),l(1.152,.167),l(.305,.12),l(.592,-.045),l(.971,.09),l(.426,-.108),l(.271,-.24),l(-.006,-.009), +N(461.353,72.251),l(.37,-.004),l(-.015,.116),l(0,.117),l(.232,.073),l(.204,.087),l(.087,.073),l(.204,.058),l(-.015,.087),l(-.029,.116),l(-.015,.087),l(-.102,.073),l(-.087,.015),l(-.103,.029),l(.131,.087),l(-.072,.131),l(.029,.117),l(-.073,.087),l(-.102,.073),l(-.044,.102),l(.204,-.059),l(.146,-.015),l(.131,.073),l(.087,.014),l(.073,.044),l(-.059,.087),l(-.043,.073),l(.116,.102),l(.131,.058),l(.029,.16),l(.146,.102),l(.16,.043),l(-.059,.087),l(.131,.117),l(-.015,.189),l(.088,.233),l(-.044,.087),l(-.015,.117),l(-.061,.042),l(-.241,.044),l(-.24,.051),l(-.12,.12),l(-.223,.034),l(-.137,.154),l(-.137,.085),l(-.069,.103),l(-.068,.206),l(-.188,.035),l(-.239,-.035),l(-.24,-.034),l(-.325,-.034),l(-.359,0),l(-.172,.068),l(-.103,.137),l(-.223,.085),l(-.154,0),l(-.103,-.017),l(-.086,.052),l(-.377,-.035),l(-.273,-.068),l(-.154,-.171),l(-.138,-.154),l(-.325,-.137),l(-.497,-.223),l(-.342,-.24),l(-.377,-.034),l(-.583,-.035),l(-.325,-.12),l(-.291,-.188),l(-.086,-.257),l(-.188,.017),l(-.171,.068),l(-.36,.171),l(-.394,.017),l(-.24,0),l(-.273,.085),l(-.24,-.085),l(-.309,-.103),l(-.6,-.017),l(-.291,.069),l(-.359,-.069),l(-.291,-.051),l(-.154,.034),l(-.274,.069),l(-.103,-.052),l(-.12,-.137),l(-.154,0),l(-.257,.068),l(-.188,0),l(-.754,-.017),l(-.445,-.085),l(-.754,.171),l(-.599,.154),l(-.429,.103),l(-.257,.137),l(-.052,.188),l(-.526,.026),l(-.065,-.059),l(.073,-.837),l(.035,-.302),l(.127,-.167),l(.672,-.379),l(.034,-.717),l(.267,-.162),l(.267,-.273),l(.217,-.203),l(.296,-.026),l(1.056,-.199),l(.166,-.046),l(.162,-.066),l(.29,0),l(.049,.237),l(.657,.388),l(.422,.162),l(.23,.473),l(.091,.15),l(.441,.196),l(.785,.059),l(.868,-.244),l(.24,-.122),l(.178,-.288),l(-.052,-.394),l(-.193,-.869),l(.198,-.243),l(.045,-.055),l(.087,0),l(.116,-.102),l(.276,-.087),l(.262,-.029),l(.146,-.043),l(.219,-.015),l(.131,-.015),l(.102,-.029),l(.276,-.117),l(.103,0),l(.087,.029),l(.015,.073),l(.131,.058),l(.116,-.087),l(0,-.073),l(.189,.087),l(.116,.102),l(.248,.043),l(.102,.102),l(.276,.014),l(.029,0),l(.204,.117),l(.247,.043),l(.189,0),l(.072,.117),l(.146,.043),l(.203,.117),l(.116,.174),l(.204,.117),l(.175,0),l(.116,.029),l(.146,.087),l(.146,-.014),l(.16,-.087),l(.131,-.044),l(.204,.029),l(.131,-.102),l(.204,.044),l(.175,.073),l(.16,.058),l(.306,.043),l(.087,.015),l(.125,-.025), +N(451.02,79.165),l(-.029,-.038),l(-.034,-.137),l(-.018,-.171),l(.068,-.206),l(.068,-.154),l(.224,-.12),l(-.052,-.12),l(-.018,-.137),l(-.171,-.069),l(-.188,-.034),l(-.103,-.103),l(-.086,-.137),l(-.223,.017),l(-.257,0),l(-.445,0),l(-.223,.051),l(-.086,-.103),l(-.514,-.068),l(-.257,-.069),l(-.223,-.12),l(-.24,0),l(-.086,-.052),l(-.051,-.154),l(-.12,.034),l(-.353,.096),l(-.043,-.077),l(.128,-.012),l(.034,-.183),l(-.439,-.646),l(-.008,-.14),l(-.042,-.727),l(-.112,-.102),l(.526,-.026),l(.052,-.188),l(.257,-.137),l(.429,-.103),l(.599,-.154),l(.754,-.171),l(.445,.085),l(.754,.017),l(.188,0),l(.257,-.068),l(.154,0),l(.12,.137),l(.103,.052),l(.274,-.069),l(.154,-.034),l(.291,.051),l(.359,.069),l(.291,-.069),l(.6,.017),l(.309,.103),l(.24,.085),l(.273,-.085),l(.24,0),l(.394,-.017),l(.36,-.171),l(.171,-.068),l(.188,-.017),l(.086,.257),l(.291,.188),l(.325,.12),l(.583,.035),l(.377,.034),l(.342,.24),l(.497,.223),l(.325,.137),l(.138,.154),l(.154,.171),l(.273,.068),l(.377,.035),l(-.017,.171),l(-.086,.154),l(-.034,.12),l(-.12,.137),l(-.086,.137),l(.343,.034),l(.274,.052),l(.085,.051),l(-.119,.051),l(-.086,0),l(-.103,.154),l(-.018,.154),l(-.171,.017),l(-.12,-.086),l(-.12,.051),l(-.239,-.034),l(-.154,.034),l(-.086,.154),l(-.103,.154),l(-.257,.068),l(-.429,0),l(-.137,.137),l(-.12,.12),l(-.034,.154),l(-.086,.171),l(.103,.171),l(-.068,.137),l(-.239,.154),l(0,.137),l(-.068,.085),l(-.069,.137),l(.172,.034),l(.205,0),l(.138,.206),l(-.086,.188),l(-.274,.017),l(-.223,-.068),l(0,-.154),l(-.034,-.085),l(-.086,-.069),l(-.171,.051),l(-.12,.086),l(-.291,-.034),l(-.068,.137),l(-.24,.12),l(-.154,0),l(-.188,-.034),l(-.273,.103),l(.086,.171),l(-.069,.12),l(-.171,.034),l(-.137,-.034),l(-.206,.051),l(-.377,.154),l(-.291,0),l(-.068,-.103),l(-.12,-.051),l(-.239,.051),l(-.377,.017),l(-.24,.034),l(-.291,-.034),l(-.154,.034),l(-.093,-.035),l(-.09,-.171),l(-.016,-.029),l(-.099,-.186),l(-.284,-.487),l(-.679,-.243),l(-.04,-.014),l(-.641,.021), +N(452.867,80.273),l(.093,.035),l(.154,-.034),l(.291,.034),l(.24,-.034),l(.377,-.017),l(.239,-.051),l(.12,.051),l(.068,.103),l(.291,0),l(.377,-.154),l(.206,-.051),l(.137,.034),l(.171,-.034),l(.069,-.12),l(-.086,-.171),l(.273,-.103),l(.188,.034),l(.154,0),l(.24,-.12),l(.068,-.137),l(.291,.034),l(.12,-.086),l(.171,-.051),l(.086,.069),l(.034,.085),l(0,.154),l(.223,.068),l(.274,-.017),l(.086,-.188),l(-.138,-.206),l(-.205,0),l(-.172,-.034),l(.069,-.137),l(.068,-.085),l(0,-.137),l(.239,-.154),l(.068,-.137),l(-.103,-.171),l(.086,-.171),l(.034,-.154),l(.12,-.12),l(.137,-.137),l(.429,0),l(.257,-.068),l(.103,-.154),l(.086,-.154),l(.154,-.034),l(.239,.034),l(.12,-.051),l(.12,.086),l(.171,-.017),l(.018,-.154),l(.103,-.154),l(.086,0),l(.119,-.051),l(-.085,-.051),l(-.274,-.052),l(-.343,-.034),l(.086,-.137),l(.12,-.137),l(.034,-.12),l(.086,-.154),l(.017,-.171),l(.086,-.052),l(.103,.017),l(.154,0),l(.223,-.085),l(.103,-.137),l(.172,-.068),l(.359,0),l(.325,.034),l(.24,.034),l(.239,.035),l(.188,-.035),l(.068,-.206),l(.069,-.103),l(.137,-.085),l(.137,-.154),l(.223,-.034),l(.12,-.12),l(.24,-.051),l(.241,-.044),l(.165,.147),l(.229,.066),l(.197,-.131),l(.181,.016),l(.312,.033),l(.132,.148),l(.082,.148),l(.197,-.033),l(.214,-.065),l(.361,-.049),l(.312,.049),l(.296,.065),l(.147,.017),l(0,.115),l(-.164,.099),l(-.017,.099),l(.065,.148),l(.164,.148),l(.197,0),l(.214,-.197),l(.279,-.016),l(.165,0),l(.147,-.099),l(.23,-.083),l(.131,.049),l(.099,.049),l(.247,-.049),l(.542,.115),l(.132,.131),l(.279,.099),l(.099,.099),l(.147,.099),l(.165,.033),l(.147,-.033),l(.049,.115),l(-.065,.115),l(0,.083),l(-.033,.164),l(-.131,.165),l(.197,.247),l(.147,.099),l(.05,.164),l(-.066,.131),l(-.114,0),l(0,.083),l(-.115,.082),l(-.099,.049),l(-.033,.165),l(-.049,.147),l(.345,.049),l(.132,.181),l(.082,.115),l(.181,-.049),l(.132,.033),l(-.099,.115),l(-.066,.131),l(.017,.099),l(.214,.017),l(.164,.263),l(.115,.23),l(.443,.213),l(.23,.066),l(.279,.082),l(.164,.099),l(.066,.148),l(-.099,.197),l(-.066,.181),l(.182,.066),l(.361,-.066),l(.378,.066),l(.361,.099),l(.263,.066),l(-.032,.065),l(-.066,.049),l(-.082,.017),l(.099,.181),l(.296,.148),l(.279,.066),l(.033,.131),l(-.065,.164),l(-.296,0),l(-.148,.083),l(-.049,.065),l(-.444,.247),l(-.525,.099),l(-.51,-.016),l(-.197,-.132),l(-.328,-.049),l(-.362,.017),l(-.131,.165),l(-.099,.131),l(.017,.164),l(.279,.263),l(.296,.164),l(0,.165),l(-.132,.066),l(.099,.148),l(.147,.131),l(-.082,.099),l(.033,.164),l(.033,.23),l(-.033,.099),l(.164,.082),l(.082,.115),l(.165,.066),l(.002,.142),l(-.519,-.005),l(-.522,.056),l(-.112,.131),l(-.205,-.056),l(-.187,-.037),l(-.336,.075),l(-.057,.13),l(-.111,.112),l(-.317,.187),l(-.188,.261),l(-.261,.224),l(-.057,.206),l(.243,.205),l(.056,.149),l(-.131,.206),l(-.261,-.019),l(-.149,-.056),l(-.149,-.206),l(-.112,-.056),l(-.187,-.075),l(-.224,-.037),l(-.225,.037),l(-.242,.075),l(-.299,.019),l(-.149,-.131),l(-.224,.075),l(-.188,.093),l(-.316,.056),l(-.188,-.056),l(-.037,-.205),l(-.112,-.131),l(-.168,-.131),l(-.13,.038),l(-.131,.075),l(-.168,0),l(-.299,.149),l(-.131,.149),l(-.168,0),l(-.094,-.187),l(-.13,-.075),l(-.206,0),l(-.224,.112),l(-.131,-.187),l(-.224,-.093),l(-.131,.112),l(-.354,.056),l(-.262,-.112),l(-.112,0),l(-.019,.205),l(-.168,.093),l(-.093,-.056),l(.056,-.224),l(-.243,-.038),l(-.187,-.056),l(-.541,.112),l(0,-.149),l(-.187,0),l(.019,-.224),l(-.28,-.037),l(-.242,.075),l(-.523,-.112),l(-.578,-.056),l(-.075,-.056),l(-.522,0),l(-.205,-.168),l(-.262,.019),l(-.522,-.093),l(-.467,.075),l(-.485,0),l(-.354,-.056),l(-.355,.056),l(-.354,.056),l(-.485,-.038),l(-.485,.019),l(-.205,.187),l(-.037,.168),l(-.374,.168),l(-.373,.206),l(-.112,-.112),l(-.261,0),l(-.374,-.019),l(-.037,.131),l(0,.045),l(-.126,-.137),l(.315,-.752),l(-.013,-.25),l(-.218,-.146),l(-.149,-.176),l(-.421,-.146),l(-.289,-.012),l(.128,-.292),l(.291,-.328),l(.571,-.244),l(.44,-.03),l(.263,-.208),l(.023,-.236),l(-.172,-.502),l(-.615,-1.5),l(-.16,-.302), +N(400.125,81.146),l(.633,.305),l(.208,.207),l(.208,.37),l(-.038,.193),l(-.545,.563),l(.714,.176),l(.396,-.311),l(.527,-.119),l(.602,.028),l(.807,.176),l(.467,.354),l(.235,.752),l(-.077,.221),l(-.322,.414),l(-1.068,.473),l(-.767,.561),l(-.96,.237),l(1.223,.167),l(.501,.043),l(.354,-.104),l(.39,.117),l(-.066,.516),l(-.997,.308),l(.005,.199),l(-.479,-.084),l(-1.068,.443),l(-.879,-.142),l(-.293,-.048),l(-1.119,.211),l(-.587,-.211),l(-.598,.112),l(-1.584,.141),l(.137,.295),l(-.907,-.168),l(-.264,.168),l(-.911,-.337),l(-.334,.143),l(-.913,.089),l(-.093,.569),l(-.337,.316),l(-.37,.042),l(-.272,-.252),l(-.53,-.172),l(-.135,.151),l(-.527,-.077),l(-.948,.324),l(-.701,.552),l(-.326,-.231),l(-.775,-.147),l(1.2,-.472),l(.492,-.476),l(.447,-.097),l(.468,-.388),l(.118,-.485),l(.242,.063),l(.367,-.211),l(-.008,-.274),l(1.013,-.105),l(.76,.119),l(.927,.007),l(.073,-.338),l(.308,-.142),l(.321,-.556),l(-.939,.394),l(-.725,.016),l(-1.467,-.482),l(-1.866,-.055),l(-.399,-.191),l(-.156,-.162),l(.417,-.325),l(.983,-.194),l(.721,-.237),l(.38,-.384),l(.066,-.827),l(-.119,-.192),l(-.713,.046),l(-.34,-.044),l(.288,-.355),l(.387,-.223),l(.802,-.253),l(1.394,-.062),l(.922,-.076),l(-.316,-.548),l(.172,-.683),l(.253,-.461),l(-.045,-.312),l(-.834,.061),l(-.484,-.296),l(-.2,-.312),l(.309,-.507),l(.617,-.433),l(-.347,-.104),l(-.596,-.088),l(-.735,.3),l(-.476,.061),l(-.753,-.222),l(-.088,.194),l(-.222,.194),l(-.672,-.103),l(-.464,-.133),l(.1,-.343),l(.348,-.36),l(.604,-.706),l(-.293,-.134),l(-.305,-.39),l(.028,-.24),l(.304,-.106),l(.3,-.196),l(-.194,-.496),l(-.306,.076),l(-.636,.453),l(-.442,.031),l(-.526,.287),l(-.14,-.421),l(.302,-.527),l(.438,-.559),l(.065,-.257),l(-.417,-.195),l(-.196,-.045),l(-.218,.302),l(-.394,.257),l(-.493,-.165),l(.299,-.575),l(.54,-.455),l(.09,-.136),l(-.225,-.575),l(.366,-.092),l(.225,-.197),l(-.672,-.515),l(.432,-.351),l(.752,.151),l(.387,-.092),l(-.645,-.759),l(.975,-.169),l(-.457,-.502),l(.416,-.382),l(.924,.365),l(.824,-.093),l(.686,-.139),l(.867,-.047),l(.612,.014),l(.303,.259),l(-.307,.29),l(-1.726,.704),l(-.46,.274),l(-.218,.441),l(.222,.182),l(.784,.029),l(.877,-.078),l(.685,-.001),l(.53,.075),l(1.563,-.064),l(.458,.378),l(-.363,.425),l(-.212,.323),l(.098,.112),l(-.565,.66),l(-.226,.111),l(-.339,.437),l(-.696,.261),l(-.382,.038),l(.451,.186),l(.508,.167),l(-.116,.015),l(-.272,.19),l(-.61,.052),l(-.275,.196),l(-1.337,-.025),l(.404,.223),l(.302,0),l(.492,.093),l(.432,-.006),l(.519,-.223),l(.413,-.025),l(.449,.161),l(.656,.164),l(.673,.566),l(.496,.228),l(.118,.165),l(-.067,.238),l(.312,.78),l(.371,.536),l(.438,.189),l(.714,.107),l(.59,.549),l(.688,.593),l(.135,.52),l(-.188,.49),l(.257,.124),M(387.915,77.13),l(-.128,-.325),l(.149,-.335),l(.38,-.089),l(.079,.501),l(-.307,.251),l(-.173,-.003),M(386.786,80.184),l(-.178,-.272),l(-.967,.072),l(.123,-.256),l(-.364,-.15),l(-.26,-.257),l(-.335,-.107),l(-.253,.364),l(-.751,.257),l(-.778,-.192),l(-.401,-.278),l(-.101,-.278),l(.86,-.278),l(-.483,-.257),l(.817,-.107),l(.385,-.484),l(-.029,-.235),l(.449,-.09),l(.508,-.15),l(.781,-.077),l(.424,.044),l(.389,.104),l(.362,-.046),l(.218,.149),l(.519,.791),l(.047,.179),l(-.081,.298),l(.308,.446),l(-.155,.328),l(-.402,.328),l(-.354,.12),l(-.299,.038), +N(578.943,106.217),l(-.41,-.375),l(-.466,-.098),l(-.663,0),l(-.196,-.27),l(-.27,-.147),l(-.147,-.344),l(-.564,.049),l(-.981,-.246),l(-.662,.074),l(-1.35,-.024),l(-.662,-.098),l(-.712,-.221),l(-.785,.147),l(-.761,0),l(-.858,.024),l(-.441,.27),l(-.54,-.098),l(-.908,-.196),l(-.735,-.246),l(-.761,-.27),l(-.589,-.074),l(-.688,.123),l(-.466,.368),l(-.245,.736),l(.024,.442),l(-.344,-.123),l(-.81,-.123),l(-.688,-.196),l(-.883,-.245),l(-.883,-.147),l(-.663,.098),l(-.736,.123),l(-.318,.368),l(-.393,.442),l(.044,.273),l(-.322,.031),l(-.377,.377),l(-.283,-.126),l(-.22,.063),l(-.346,.283),l(-.534,.471),l(-.755,.189),l(-.943,.377),l(-.282,.188),l(-.221,.472),l(-.439,.188),l(-.504,.44),l(.157,.409),l(-.125,.188),l(-.66,0),l(-.44,-.346),l(.062,-.283),l(-.062,-.283),l(-.44,-.314),l(-.346,0),l(-1.006,.094),l(-.691,.032),l(-.503,-.063),l(-.346,-1.069),l(-.221,-.817),l(-1.006,0),l(-.031,-.754),l(.188,-.409),l(.031,-1.038),l(-.66,.314),l(-.66,-1.006),l(-.597,-.22),l(-.724,-.723),l(-1.1,.409),l(-2.767,-.188),l(-2.578,.346),l(-2.012,-1.666),l(-5.722,-2.986),l(-5.658,1.289),l(-.056,8.174),l(-.158,-.014),l(-.341,.106),l(-.489,.043),l(-.447,-.255),l(-.638,-.703),l(-.256,-.511),l(-.617,-.383),l(-.681,-.383),l(-.512,-.234),l(-.979,.085),l(-1.277,.298),l(-.937,.532),l(-.529,.453),l(.092,-.399),l(-.06,-.18),l(-.12,-.12),l(.14,-.26),l(.2,-.2),l(.14,-.32),l(.04,-.3),l(.18,-.2),l(-.159,-.24),l(-.4,-.16),l(-.459,.06),l(-.18,-.16),l(-.3,.06),l(-.2,.04),l(-.199,-.18),l(-.221,-.32),l(-.319,-.28),l(-.34,0),l(-.359,.02),l(0,-.2),l(.08,-.28),l(-.2,-.379),l(-.239,-.12),l(-.2,-.24),l(-.399,-.799),l(-.08,-.28),l(-.56,-.12),l(-.699,-.08),l(-.14,-.16),l(.02,-.439),l(.16,-.12),l(.3,-.06),l(.399,.02),l(.34,.02),l(.479,.14),l(.539,.18),l(.18,-.08),l(.36,-.08),l(-.2,-.16),l(-.26,-.12),l(-.399,-.2),l(-.2,-.24),l(.26,-.36),l(.28,-.04),l(.08,-.26),l(.18,-.299),l(.12,-.14),l(.26,.04),l(.319,-.08),l(.16,-.1),l(.339,.12),l(.24,0),l(1.119,-.04),l(.999,.14),l(.499,.02),l(-.159,-.08),l(-.34,-.2),l(-.479,-.12),l(-.021,-.3),l(.2,-.2),l(.279,-.22),l(.221,-.28),l(.119,-.52),l(.12,-.28),l(-.16,-.24),l(-.14,-.16),l(.1,-.2),l(.26,-.2),l(-.119,-.12),l(-.101,-.3),l(-.359,-.12),l(-.359,-.04),l(-.68,-.1),l(-.2,.16),l(-.199,.08),l(-.52,.08),l(-.46,-.12),l(-.319,-.26),l(-.26,-.06),l(-.68,-.12),l(-.56,.06),l(-.659,.319),l(-.42,.02),l(-.799,.5),l(-.72,.28),l(-.499,.06),l(-.42,-.02),l(-.279,.24),l(-.213,.18),l(-.616,-.19),l(-.857,-.377),l(-.068,-.308),l(.343,-.103),l(.309,.103),l(.445,.103),l(.138,-.103),l(-.96,-1.131),l(-.343,-.514),l(-.479,-.206),l(-.515,-.445),l(-.514,-.034),l(-.343,.034),l(-.583,-.206),l(-.103,.343),l(-.514,-.514),l(.068,-.309),l(-.138,-.377),l(-1.37,-.343),l(.65,-1.165),l(.446,-.274),l(.239,-.206),l(-.239,-.274),l(-.343,-.171),l(.205,-1.303),l(.823,-.137),l(.343,-.549),l(.103,-.308),l(.411,-.069),l(.514,.24),l(.48,.548),l(.514,.411),l(.651,0),l(.411,-.24),l(.068,-.446),l(-.171,-.411),l(-.068,-.445),l(.479,-.206),l(.891,-.411),l(.172,-.24),l(.309,-.309),l(.514,-.171),l(.549,-.068),l(.788,-.377),l(.548,-.343),l(.515,-.309),l(.651,.069),l(.479,0),l(.309,.274),l(.651,-.137),l(.273,-.137),l(.617,-.24),l(.411,.069),l(.411,.514),l(.788,.035),l(.617,-.069),l(.96,.171),l(0,.343),l(.582,.206),l(.789,.343),l(.411,.274),l(.068,.583),l(.274,.137),l(.239,-.274),l(-.205,-.48),l(-.034,-.24),l(.72,.068),l(.582,.548),l(.686,.137),l(.411,.24),l(.686,-.171),l(.274,-.274),l(.377,-.343),l(.514,-.377),l(.823,.068),l(.65,.035),l(.651,.411),l(.617,-.068),l(.137,-.412),l(1.062,-.103),l(.754,.103),l(.274,.548),l(.926,.309),l(.754,.137),l(.411,.171),l(.651,-.343),l(.171,-.309),l(.24,0),l(.343,.343),l(.959,.034),l(1.577,-.411),l(.137,-.309),l(.138,-.686),l(-.24,-.24),l(-1.165,-.171),l(-.274,-.308),l(-.651,-.069),l(-.377,-.137),l(.068,-.171),l(-.377,-.137),l(-.239,0),l(-.164,-.274),l(.467,-.067),l(.735,-.368),l(.588,-.147),l(.331,-.294),l(-.441,-.478),l(-.146,-.257),l(.662,-.515),l(.698,-.184),l(1.103,.147),l(.515,-.073),l(.11,-.257),l(-.956,-.294),l(-1.065,-.11),l(0,-.331),l(.294,-.074),l(-.294,-.221),l(-.074,-.441),l(.185,-.515),l(.33,-.074),l(1.066,.147),l(.515,0),l(.772,0),l(.368,-.184),l(1.396,-.405),l(1.029,-.037),l(.735,-.11),l(1.545,-.11),l(.588,-.073),l(.331,.073),l(.221,-.331),l(.625,-.331),l(1.177,-.037),l(2.021,-.405),l(1.876,-.073),l(.625,-.074),l(.367,-.368),V(0,77.39),l(.515,-.037),l(.589,-.184),l(.11,-.221),l(.735,-.037),l(.919,.147),l(.515,.11),l(.772,.257),l(.625,-.11),l(.882,-.037),l(.368,.404),l(-.037,.331),l(.147,.221),l(.515,.22),l(-.11,.331),l(-.147,.257),l(.073,.331),l(-.33,.037),l(.184,.257),l(.478,.074),l(.295,-.147),l(.44,.11),l(.368,-.147),l(.367,.074),l(.331,-.221),l(.294,.11),l(.295,.368),l(.367,.221),l(.147,-.147),l(.184,-.147),l(.478,.037),l(.405,.294),l(.478,.11),l(.441,-.221),l(.367,0),l(-.146,.294),l(-.441,.184),l(-.331,.441),l(.331,.184),l(.441,-.11),l(.771,-.073),l(.441,.037),l(.552,.184),l(.294,-.294),l(.772,-.441),l(1.103,-.257),l(.956,-.515),l(.772,-.221),l(.515,-.22),l(.809,-.074),l(0,.441),l(-.515,.11),l(-.11,.368),l(1.104,.588),l(.809,.294),l(1.287,.772),l(1.066,1.029),l(1.69,2.133),l(.846,.882),l(1.104,1.434),l(.515,-.257),l(.331,-.257),l(.367,-.515),l(.92,0),l(.367,.331),l(0,.368),l(.478,0),l(.258,.257),l(.184,.184),l(.589,0),l(.992,0),l(.993,-.221),l(.771,-.221),l(.993,-.037),l(.698,.441),l(.772,.588),l(.331,.625),l(.956,.147),l(.588,.552),l(.662,.699),l(.882,.073),l(.993,.074),l(.478,-.368),l(.625,-.184),l(-.073,.331),l(.441,.331),l(.294,.478),l(.589,0),l(.064,.145),l(-.551,.034),l(-.542,.148),l(-.279,.262),l(-.011,.275),l(-.035,.478),l(-.306,.219),l(-.289,.06),l(-1.199,.093),l(-.428,.277),l(-.34,.581),l(.097,.75),l(.213,.707),l(-.157,.39),l(-.444,.392),l(-.417,.103),l(-.718,.062),l(-1.402,-.079),l(-.594,-.141),l(-.721,-.141),l(-1.096,-.254),l(-.427,.507),l(-.516,1.141),L(584.2,97.43),l(-.286,.605),l(-.137,.418),l(.622,.514),l(.126,.286),l(-.156,.245),l(-.231,.145),l(-.394,.074),l(-1.133,-.238),l(-.5,-.184),l(-.35,.06),l(-1.082,.207),l(-1.799,.254),l(-.393,.188),l(-.215,.302),l(-.068,.215),l(.232,.185),l(.366,-.06),l(.483,.141),l(.03,1.357),l(.345,.627),l(.29,.441),l(.119,.47),l(-.222,.33),l(-.705,.546),l(-.32,.401),l(-.02,.399),l(.139,.86), +N(386.786,80.184),l(-.304,.038),l(-.223,.09),l(.241,.252),l(.361,.771),l(.287,1.213),l(-.061,.281),l(-.359,.341),l(-.242,.414),l(-.145,.473),l(-.185,.044),l(-.284,-.058),l(-.616,.031),l(-.15,.212),l(-.913,.042),l(-.84,.132),l(-.247,.144),l(-.661,.286),l(-.903,.498),l(-.628,.035),l(-.879,.283),l(-1.28,.084),l(.053,-.378),l(-.089,-.441),l(-.848,.1),l(-.171,-.487),l(.734,-.254),l(-1.186,-.021),l(.062,-.233),l(1.286,.027),l(.198,-.104),l(.039,-.222),l(.107,-.31),l(.515,-.134),l(.692,-.031),l(.13,-.281),l(-1.07,.099),l(.387,-.437),l(-.187,-.159),l(.481,-.468),l(.694,-.011),l(.163,-.089),l(-.174,-.311),l(-.348,.177),l(-.309,-.131),l(-.319,.03),l(-.391,-.177),l(-.414,.001),l(-.182,.106),L(378,81.478),l(.309,-.306),l(-.29,-.142),l(.759,-.126),l(-.139,-.301),l(.391,-.235),l(-.481,-.214),l(-.59,.128),L(378,79.792),l(.38,-.268),l(.215,-.16),l(.928,.187),l(.336,-.075),l(.527,.038),l(1.102,.123),l(-.214,-.358),L(382.132,79),l(.198,-.321),l(-1.373,0),l(.154,-.15),l(.569,-.107),l(.061,-.29),l(.291,-.479),l(.505,-.181),l(.804,-.169),l(.22,.302),l(.354,.149),l(.156,-.031),l(.029,.235),l(-.385,.484),l(-.817,.107),l(.483,.257),l(-.86,.278),l(.101,.278),l(.401,.278),l(.778,.192),l(.751,-.257),l(.253,-.364),l(.335,.107),l(.26,.257),l(.364,.15),l(-.123,.256),l(.967,-.072),l(.178,.272), +N(452.998,85.535),V(0,85.49),l(.037,-.131),l(.374,.019),l(.261,0),l(.112,.112),l(.373,-.206),l(.374,-.168),l(.037,-.168),l(.205,-.187),l(.485,-.019),l(.485,.038),l(.354,-.056),l(.355,-.056),l(.354,.056),l(.485,0),l(.467,-.075),l(.522,.093),l(.262,-.019),l(.205,.168),l(.522,0),l(.075,.056),l(.578,.056),l(.523,.112),l(.242,-.075),l(.28,.037),l(-.019,.224),l(.187,0),l(0,.149),l(.541,-.112),l(.187,.056),l(.243,.038),l(-.056,.224),l(.093,.056),l(.168,-.093),l(.019,-.205),l(.112,0),l(.262,.112),l(.354,-.056),l(.131,-.112),l(.224,.093),l(.131,.187),l(.224,-.112),l(.206,0),l(.13,.075),l(.094,.187),l(.168,0),l(.131,-.149),l(.299,-.149),l(.168,0),l(.131,-.075),l(.13,-.038),l(.168,.131),l(.112,.131),l(.037,.205),l(.188,.056),l(.316,-.056),l(.188,-.093),l(.224,-.075),l(.149,.131),l(.299,-.019),l(.242,-.075),l(.225,-.037),l(.224,.037),l(.187,.075),l(.112,.056),l(.149,.206),l(.149,.056),l(.261,.019),l(.131,-.206),l(-.056,-.149),l(-.243,-.205),l(.057,-.206),l(.261,-.224),l(.188,-.261),l(.317,-.187),l(.111,-.112),l(.057,-.13),l(.336,-.075),l(.187,.037),l(.205,.056),l(.112,-.131),l(.522,-.056),l(.519,.005),l(.357,.089),l(.469,.022),l(.313,-.156),l(.179,-.291),l(.134,-.268),l(.536,.246),l(.536,-.022),l(.67,-.223),l(.692,.112),l(.514,-.134),l(.201,.268),l(.312,.134),l(.246,.335),l(.134,.201),l(.246,.156),l(.312,.156),l(0,.268),l(-.312,-.022),l(-.312,.134),l(.134,.291),l(.111,.357),l(.269,.29),l(.647,0),l(.156,.112),l(.514,-.067),l(.38,.022),l(0,.312),l(.402,0),l(0,.357),l(.224,.268),l(.089,.246),l(-.089,.179),l(.089,.224),l(.179,.089),l(.291,.29),l(.268,-.179),l(.47,-.067),l(.268,.067),l(.469,.291),l(.201,-.067),l(.179,.022),l(.179,.156),l(.425,-.112),l(.312,-.112),l(.269,0),l(.536,-.134),l(.357,-.067),l(.111,.156),l(.268,.179),l(0,.134),l(.201,.179),l(.022,.134),l(.402,.044),l(.179,.179),l(.224,.112),l(.29,-.134),l(.045,-.157),l(.224,-.067),l(.29,.268),l(.425,.067),l(.469,.112),l(.268,.112),l(.357,-.067),l(.201,.179),l(.291,.089),l(.469,.022),l(.111,.224),l(.357,.156),l(.269,0),l(.134,-.044),l(.201,-.089),l(.156,.089),l(-.089,.111),l(-.022,.179),l(.111,.089),l(.09,.179),l(-.045,.224),l(-.201,.089),l(-.156,.067),l(-.357,.201),l(-.312,.044),l(.223,.246),l(.269,.089),l(.29,.044),l(-.134,.156),l(-.312,0),l(-.246,0),l(-.045,.179),l(-.044,.224),l(.156,.067),l(.179,.067),l(.044,.134),l(.045,.179),l(.09,.201),l(.066,.067),l(-.156,.491),l(-.156,.291),l(0,.156),l(-.335,.134),l(-.805,-.157),l(-.736,.045),l(-.269,0),l(-.022,.179),l(-.223,.179),l(-.38,.134),l(-.357,.022),l(-.224,.089),l(-.09,.514),l(0,.224),l(-.021,.112),l(-.012,.126),l(-.779,.104),l(-.971,.06),l(-.511,.405),l(-.729,.189),l(-1.135,.075),l(-1.119,.248),l(-.502,.318),l(-.463,.059),l(-.453,-.316),l(-.369,.621),l(-.31,.188),l(-.477,.044),l(-.438,-.057),l(-.959,.031),l(-.5,.16),l(.641,.287),l(1.957,1.004),l(.053,.172),l(-.093,.188),l(.163,.244),l(.562,.042),l(.511,-.13),l(.675,-.146),l(1.052,.013),l(.439,.114),l(-.235,.259),l(-.106,.245),l(-.228,.144),l(-.578,.116),l(-.31,.029),l(-.591,-.157),l(-.473,.044),l(-.71,.489),l(-1.007,.045),l(-.538,.188),l(-.527,.488),l(-.269,.101),l(-.786,-.07),l(-.588,-.171),l(.364,-.746),l(-.096,-.416),l(-.264,-.287),l(-.854,-.286),l(-.193,-.014),l(-.629,.016),l(-.151,.043),l(-.16,-.187),l(.887,-.505),l(.644,-.261),l(.772,-.188),l(.221,-.116),l(-.246,-.46),l(-.435,-.071),l(-.799,.044),l(-1.015,.045),l(-.698,-.1),l(-.195,-.101),l(-.418,-.432),l(.584,-.405),l(-.528,-.605),l(-.378,.361),l(-.541,.001),l(-1.001,.146),l(-.565,.131),l(-.694,.722),l(-1.003,.867),l(-.754,.203),l(-.223,.044),l(-.287,.504),l(.079,.158),l(.178,.093),l(-.706,-.131),l(-.665,.261),l(-.457,0),l(-.033,.189),l(-.609,-.047),l(-.398,-.166),l(-.119,-.249),l(-.15,.02),l(.055,-.077),l(.102,-.025),l(.126,.013),l(.113,.013),l(.189,0),l(.088,-.114),l(0,-.088),l(-.063,-.113),l(.025,-.113),l(.126,-.063),l(.051,-.063),l(.075,-.013),l(.089,-.025),l(.088,-.063),l(.089,-.088),l(.024,-.126),l(-.013,-.114),l(.14,-.013),l(.29,-.063),l(.075,-.076),l(-.025,-.088),l(-.062,-.088),l(.126,-.114),l(.037,-.063),l(-.012,-.088),l(-.114,-.113),l(.051,-.101),l(-.088,-.151),l(-.063,-.101),l(.202,-.151),l(.239,-.025),l(.126,-.088),l(.113,.025),l(.013,.088),l(-.013,.214),l(.063,.013),l(.113,0),V(0,96.92),l(-.013,-.063),l(.101,.038),l(.063,.051),l(.025,-.076),l(.075,-.038),l(.139,-.012),l(0,.075),l(.089,.063),l(.075,0),l(.126,.164),l(.076,-.076),l(.075,-.076),l(.013,-.05),l(.101,-.025),l(.177,0),l(-.037,.189),l(.176,.025),l(.038,-.038),l(.038,-.038),l(.139,.013),l(.227,0),l(.038,-.025),l(.075,-.076),l(-.126,-.013),l(-.164,-.126),l(-.101,-.051),l(-.075,-.05),l(.013,-.038),l(.101,-.063),l(-.025,-.113),l(.038,-.101),l(-.013,-.126),l(-.051,-.139),l(-.101,-.063),l(-.177,-.076),l(-.075,0),l(-.151,-.126),l(-.151,-.063),l(-.151,-.038),l(.051,-.151),l(.037,-.088),l(-.037,-.051),l(-.127,.038),l(-.062,-.114),l(.113,-.038),l(-.013,-.189),l(.089,-.075),l(-.025,-.101),l(-.038,-.088),l(-.113,0),l(-.102,.05),l(-.088,.051),l(-.113,-.088),l(-.089,-.101),l(-.188,-.101),l(-.139,-.025),l(-.102,-.139),l(-.05,-.139),l(.177,-.139),l(0,-.189),l(.024,-.114),l(.051,-.05),l(-.126,-.063),l(.164,-.151),l(-.113,-.025),l(-.076,-.063),l(-.062,-.126),l(-.14,-.013),l(-.062,.101),l(-.126,-.025),l(-.215,-.025),l(-.126,-.189),l(-.05,-.189),l(-.417,-.075),l(-.277,.012),l(-.062,.051),l(-.076,.101),l(-.062,-.05),l(0,-.076),l(-.089,-.025),l(-.101,.038),l(.038,-.05),l(.088,-.101),l(-.025,-.063),l(-.113,0),l(-.177,.038),l(-.126,-.025),l(-.101,.013),l(-.076,-.076),l(-.05,-.063),l(-.101,-.063),l(-.151,-.013),l(-.139,-.05),l(-.14,-.126),l(-.214,-.088),l(-.038,-.013),l(-.126,.025),l(-.05,.025),l(-.114,-.051),l(-.088,-.025),l(-.139,.025),l(-.177,.051),l(-.177,-.025),l(-.062,.038),l(-.126,.114),l(-.202,0),l(-.265,-.038),l(-.126,.051),l(-.315,-.114),l(-.088,.101),l(.012,.113),l(-.126,0),l(-.075,-.063),l(-.126,.114),l(-.06,.052),l(-.634,.08),l(-.151,.311),l(-.278,.178),l(-1.992,.191),l(-.186,.215),l(-.243,.119),l(-.339,.06),l(-.188,-.227),l(-.327,.004),l(-.025,-.231),l(-.363,.045),l(-1.115,-.066),l(-.958,-.193),l(-.241,.107),l(-.787,-.121),l(-.136,.085),l(-.678,-.387),l(-.554,-.2),l(-.668,-.301),l(-.166,.015),l(1.047,-1.471),l(.653,.018),l(-.349,-.383),l(-.044,-.552),l(.082,-.306),l(1.509,-1.218),l(.599,-.398),l(.286,-.181),l(.429,-.013),l(.255,-.24),l(.009,-.314),l(-.328,-.302),l(.085,-.133),l(.298,-.048),l(-.316,-.193),l(-.816,-.835),l(.074,-.242),l(-.161,-.175), +N(660.044,89.132),l(-.295,.31),l(-.687,1.207),l(-1.224,1.959),l(-.381,.58),l(.269,.836),l(.051,.029),l(.342,-.045),l(.929,-.395),l(.754,-.062),l(.576,-.018),l(.317,.085),l(.431,.416),l(.292,.07),l(1.191,-.786),l(.438,-.002),l(.928,.212),l(.538,.199),l(.797,.5),l(.879,.99),l(.599,.501),l(.048,.273),l(-.107,.217),l(-.414,.218),l(-.464,-.127),l(-1.074,-.008),l(-.432,-.099),l(-.854,.033),l(-.937,.221),l(-.539,.146),l(-.831,.278),l(-.353,.189),l(-.483,-.127),l(-.464,.045),l(-.47,.204),l(-.363,.333),l(-.312,.82),l(-.241,.216),l(-.347,.188),l(-.638,.248),l(-.896,.134),l(-.624,-.054),l(-.438,-.012),l(-.224,-.013),l(-1.192,.91),l(-.742,.433),l(-.744,.047),l(-.982,.005),l(-.592,-.125),l(-.668,-.382),l(-.718,-.154),l(-.316,.073),l(-.457,.231),l(-.539,.589),l(-.214,.401),l(.003,.343),l(.389,.569),l(.599,.411),l(.188,.228),l(-.123,.271),l(-.326,.259),l(-1.265,.292),l(-.67,.389),l(-1.111,1.046),l(-.265,.172),l(-1.941,.737),l(-.651,.061),l(-.987,-.08),l(-1.514,.065),l(-1.339,.007),l(-1.204,.349),l(-.816,.289),l(-.736,.274),l(-.303,.101),l(-1.44,.534),l(-.686,.289),l(-.481,.017),l(-.433,-.197),l(-.253,-.297),l(-.61,-.067),l(-.663,.061),l(-.929,-.123),l(-1.599,-.433),l(-1.006,-.365),l(-.815,-.551),l(-.521,-.168),l(-1.69,-.119),l(-1.164,-.022),l(-.937,-.023),l(-2.861,.059),l(-1.165,-.022),l(-.802,-.109),l(-1.241,-.207),l(-1.979,-.018),l(-.444,-.254),l(-.467,-.439),l(-1.571,-2.161),l(-.105,-.542),l(-.744,-.096),l(-.839,-.31),l(-1.645,-.806),l(-.632,-.268),l(-.998,-.224),l(-.668,-.083),l(-.995,-.038),l(-1.505,-.021),l(-1.062,-.181),l(-.724,-.312),l(-.233,-.229),l(-.105,-.43),l(.035,-.129),l(.369,-.347),l(.214,-.389),l(.237,-.75),l(.215,-.447),l(-.401,-.66),l(-1.07,-1.451),l(-.568,-.618),l(-.354,-.143),l(-.633,-.144),l(-.731,-.167),l(-.614,-.069),l(-.834,-.415),l(-1.301,-.745),l(-.371,-.433),l(-.24,-.563),l(-.131,-.405),l(-.062,-.145),l(.154,-.044),l(.799,-.425),l(.599,-.207),l(1.387,-.08),l(.603,-.148),l(.727,-.381),l(.017,-.012),l(.971,-.692),l(.787,-.398),l(1.143,-.341),l(1.512,-.476),l(.84,-.18),l(.953,.097),l(.932,.156),l(1.842,.122),l(.831,.083),l(.694,.755),l(.393,.406),l(.699,.113),l(1.458,-.008),l(.719,.083),l(.85,-.004),l(.875,.068),l(.312,.114),l(.576,.186),l(.562,-.018),l(.755,-.28),l(.31,-.162),l(.744,-.572),l(.163,-.526),l(-.116,-.204),l(-.396,-.304),l(-.409,-.86),l(.098,-.293),l(.905,-.839),l(1.269,-.96),l(.84,.201),l(1.028,.098),l(1.036,.185),l(1.748,.328),l(.702,.231),l(.989,.317),l(.767,.143),l(.145,.204),l(.004,.541),l(.182,.481),l(.408,.451),l(.421,.333),l(1.643,.531),l(.673,.113),l(2.48,-.538),l(.796,-.077),l(1.172,.037),l(1.423,.022),l(.769,.229),l(1.333,.75),l(.623,.331),l(1.132,.313),l(.812,.373),l(1.318,.254),l(.905,.241),l(.984,.082),l(.739,.039),l(1.602,-.11),l(1.018,-.063),l(.532,-.075),l(.867,-.106),l(1.147,-.136),l(.526,-.163),l(.604,-.264),l(.447,-.394),l(.755,-.498),l(1.165,-.487),l(.333,-.002),l(.609,-.047),l(.74,.156),l(.751,.506),l(.34,.129),l(.86,.169),l(1.228,-.297),l(.622,-.018),l(.431,.168), +N(406.183,86.551),l(1.051,-.494),l(.485,-.089),l(.574,.087),l(.465,-.016),l(.209,-.147),l(.477,.098),l(.407,.042),l(.52,-.034),l(-.025,-.157),l(.307,.012),l(.307,0),l(.267,-.182),l(.313,.242),l(.173,-.121),l(.228,.061),l(.292,.375),l(.535,-.109),l(.754,.375),l(-.11,.423),l(-.172,.097),l(.001,.338),l(.672,-.024),l(.344,.177),l(.282,.365),l(.038,.468),l(-.422,.376),l(-.225,-.072),l(-.142,.08),l(-.245,.147),l(-.213,.322),l(.017,.327),l(.31,.204),l(-.136,.348),l(-.079,-.114),l(-.694,.174),l(-.127,-.228),l(-.371,-.204),l(-.341,-.192),l(-.529,-.048),l(.039,-.228),l(-.146,-.18),l(.119,-.373),l(-.245,.072),l(-.193,.313),l(-.446,.035),l(-.406,.075),l(-.285,-.122),l(.072,-.198),l(-.091,-.175),l(.159,-.241),l(-.375,-.168),l(-.576,-.048),l(-.259,.012),l(-.159,-.301),l(-.518,.012),l(-.194,-.133),l(-.202,-.458),l(-.153,-.17),l(-.41,.208),l(-.141,.071),l(-.266,-.127),l(-.311,-.335),l(-.208,-.447), +N(438.22,91.952),l(.039,-.044),l(.065,-.105),l(.014,-.131),l(.092,-.066),l(.146,-.119),l(.026,-.04),l(.171,-.053),l(.093,-.026),l(.092,.053),l(.132,.053),l(.158,0),l(.065,-.026),l(.093,0),l(.065,.026),l(.065,.026),l(.093,-.026),l(.145,-.04),l(.132,0),l(.118,-.053),l(.079,-.053),l(.066,-.026),l(.105,-.026),l(.039,0),l(.053,-.079),l(.04,-.092),l(.079,-.079),l(.092,.026),l(.105,-.04),l(.145,-.066),l(.053,-.105),l(.053,-.079),l(.026,-.132),l(.026,-.092),l(.053,-.092),l(.118,-.013),l(.105,-.013),l(.132,-.079),l(.119,-.053),l(.118,-.092),l(.053,-.079),l(.132,-.066),l(.065,-.04),L(442,89.998),l(.145,.013),l(.105,.026),l(.066,-.04),l(.065,-.066),l(.071,.012),l(.285,.041),l(.03,.228),l(.43,-.048),l(.183,-.24),l(.193,.016),l(.062,-.112),l(.261,-.024),l(.194,.24),l(.073,.169),l(.331,-.025),l(.066,.18),l(-.026,.083),l(.003,.204),l(.389,-.083),l(.18,.12),l(.149,-.135),l(.104,-.177),l(.558,-.204),l(.168,.056),l(.483,-.046),l(.46,.254),l(.373,-.18),l(.073,-.137),l(.508,.041),l(.561,-.076),l(.129,.13),l(.703,.186),l(.104,.216),l(.424,.101),l(.831,.33),l(-1.047,1.471),l(-.629,.076),l(-.437,-.143),l(-.534,-.359),l(-1.062,.035),l(-.717,.047),l(-1.024,.759),L(444.857,93),l(-.59,-.072),l(-.499,.061),l(-.761,.134),l(-.255,.001),l(-.334,.568),l(-1.651,-.036),l(-.414,-.027),l(-.617,-.17),l(-.399,-.172),l(-.245,.146),l(-.761,-.547),l(-.155,-.26),l(.097,-.581),l(-.053,-.093), +N(442.391,98.111),l(-.589,.203),l(-.433,.031),l(-.668,.047),l(-.58,-.098),l(-1.116,-.671),l(-1.412,-.612),l(-.215,-.197),l(-.364,-.333),l(-.304,-.59),l(.346,-.299),l(.154,-.294),l(-.204,-.188),l(.04,-.375),l(.409,-.062),l(.157,-.206),l(-.136,-.196),l(-.452,-.063),l(.223,-.197),l(.325,0),l(.164,.134),l(.701,-.054),l(.019,-.367),l(.636,-.291),l(.245,-.146),l(.399,.172),l(.617,.17),l(.414,.027),l(1.651,.036),l(.334,-.568),l(.255,-.001),l(.761,-.134),l(.499,-.061),l(.59,.072),l(.427,-.063),l(1.024,-.759),l(.717,-.047),l(1.062,-.035),l(.534,.359),l(.437,.143),l(.629,-.076),l(.166,-.015),l(.668,.301),l(.554,.2),l(.678,.387),l(-.45,.338),l(-1.125,.267),l(-.581,.408),l(-.968,1.451),l(-.63,.84),l(-.753,.567),l(-.361,.16),l(-.724,.047),l(-.264,.103),l(-.176,-.002),l(-.907,-.067),l(-.889,.077),l(-1.535,.529), +N(459.717,92.836),l(.06,-.052),l(.126,-.114),l(.075,.063),l(.126,0),l(-.012,-.113),l(.088,-.101),l(.315,.114),l(.126,-.051),l(.265,.038),l(.202,0),l(.126,-.114),l(.062,-.038),l(.177,.025),l(.177,-.051),l(.139,-.025),l(.088,.025),l(.114,.051),l(.05,-.025),l(.126,-.025),l(.038,.013),l(.214,.088),l(.14,.126),l(.139,.05),l(.151,.013),l(.101,.063),l(.05,.063),l(.076,.076),l(.101,-.013),l(.126,.025),l(.177,-.038),l(.113,0),l(.025,.063),l(-.088,.101),l(-.038,.05),l(.101,-.038),l(.089,.025),l(0,.076),l(.062,.05),l(.076,-.101),l(.062,-.051),l(.277,-.012),l(.417,.075),l(.05,.189),l(.126,.189),l(.215,.025),l(.126,.025),l(.062,-.101),l(.14,.013),l(.062,.126),l(.076,.063),l(.113,.025),l(-.164,.151),l(.126,.063),l(-.051,.05),l(-.024,.114),l(0,.189),l(-.177,.139),l(.05,.139),l(.102,.139),l(.139,.025),l(.188,.101),l(.089,.101),l(.113,.088),l(.088,-.051),l(.102,-.05),l(.113,0),l(.038,.088),l(.025,.101),l(-.089,.075),l(.013,.189),l(-.113,.038),l(.062,.114),l(.127,-.038),l(.037,.051),l(-.037,.088),l(-.051,.151),l(.151,.038),l(.151,.063),l(.151,.126),l(.075,0),l(.177,.076),l(.101,.063),l(.051,.139),l(.013,.126),l(-.038,.101),l(.025,.113),l(-.101,.063),l(-.013,.038),l(.075,.05),l(.101,.051),l(.164,.126),l(.126,.013),l(-.075,.076),l(-.038,.025),l(-.227,0),l(-.139,-.013),l(-.038,.038),l(-.038,.038),l(-.176,-.025),l(.037,-.189),l(-.177,0),l(-.101,.025),l(-.013,.05),l(-.075,.076),l(-.076,.076),l(-.126,-.164),l(-.075,0),l(-.089,-.063),l(0,-.075),l(-.139,.012),l(-.075,.038),l(-.025,.076),l(-.063,-.051),l(-.101,-.038),l(.013,.063),l(0,.088),l(-.113,0),l(-.063,-.013),l(.013,-.214),l(-.013,-.088),l(-.113,-.025),l(-.126,.088),l(-.239,.025),l(-.202,.151),l(.063,.101),l(.088,.151),l(-.051,.101),l(.114,.113),l(.012,.088),l(-.037,.063),l(-.126,.114),l(.062,.088),l(.025,.088),l(-.075,.076),l(-.29,.063),l(-.14,.013),l(.013,.114),l(-.024,.126),l(-.089,.088),l(-.088,.063),l(-.089,.025),l(-.075,.013),l(-.051,.063),l(-.126,.063),l(-.025,.113),l(.063,.113),l(0,.088),l(-.088,.114),l(-.189,0),l(-.113,-.013),l(-.126,-.013),l(-.102,.025),l(-.055,.077),l(-.03,.004),l(-.062,-.237),l(-.218,-.106),l(.16,-.071),l(-.021,-.267),l(-.104,-.561),l(.323,-.978),l(.027,-.404),l(-.353,-.856),l(-.604,-.286),l(-1.037,-1.119),L(460.567,93),l(-.626,-.191),l(-.225,.028), +N(445.722,97.573),l(.176,.002),l(.264,-.103),l(.724,-.047),l(.361,-.16),l(.753,-.567),l(.63,-.84),l(.968,-1.451),l(.581,-.408),l(1.125,-.267),l(.45,-.338),l(.136,-.085),l(.787,.121),l(.241,-.107),l(.958,.193),l(1.115,.066),l(.363,-.045),l(.025,.231),l(.327,-.004),l(.188,.227),l(.339,-.06),l(.243,-.119),l(.186,-.215),l(1.992,-.191),l(.278,-.178),l(.151,-.311),l(.634,-.08),l(.225,-.028),L(460.567,93),l(.767,1.17),l(1.037,1.119),l(.604,.286),l(.353,.856),l(-.027,.404),l(-.323,.978),l(.104,.561),l(.021,.267),l(-.16,.071),l(.218,.106),l(.062,.237),l(.03,-.004),l(.15,-.02),l(.119,.249),l(.398,.166),l(.609,.047),l(.033,-.189),l(.457,0),l(.665,-.261),l(.706,.131),l(.149,.079),l(.062,.259),l(-.293,.446),l(-.27,.316),l(-.436,.044),l(-.382,.043),l(-.382,.245),l(-.515,.617),l(-.252,.645),l(-.096,.787),l(-.044,.223),l(-.671,-.12),l(-1.346,-.336),l(-.514,-.226),l(-.295,-.042),l(-.671,-.369),l(-.562,-.04),l(-.618,.218),l(-1.904,.771),l(-.38,.059),l(-1.385,-.35),l(-.3,-.013),l(-.69,.261),l(-.34,.031),l(-1.151,-.395),l(-.506,-.002),l(-.771,.189),l(-.266,.023),l(-.048,-.189),l(.234,-.318),l(-.352,-.106),l(-.392,-.204),l(-.418,-.186),l(-.146,-.33),l(.32,-.201),l(.351,.012),l(-.114,-.13),l(-.625,-.248),l(-.253,.13),l(-.215,.283),l(-.147,.118),l(-.414,-.239),l(-.194,-.139),l(-.594,-.059),l(-.02,-.189),l(-.234,0),l(-.245,-.036),l(-.052,-.165),l(.178,-.094),l(.271,-.071),l(-.239,-.083),l(-.183,-.059),l(.124,-.146),l(.19,-.127),l(-.069,-.142),l(-.306,-.118),l(-.555,-.141),l(-.712,-.471),l(.058,-.088),l(-.104,-.119),l(.075,-.356),l(-.202,-.036),l(-.19,-.237),l(-.569,-.178),l(-.054,-.309), +N(420.177,113.472),l(-.274,-.042),l(-.253,-.155),l(-.367,-.325),l(-.096,-.213),l(.202,-.738),l(.097,-.681),l(-.046,-.583),l(-.133,-.569),l(-.503,-.44),l(-.094,-.271),l(.181,-.157),l(.366,-.015),l(.801,-.001),l(.339,-.172),l(.861,-.543),l(.633,.625),l(.451,.754),l(-.014,.271),l(-.204,.285),l(-.145,.484),l(.149,.894),l(-.11,.525),l(-.377,.695),l(-.405,-.198),l(-.52,.03),l(-.143,.1),l(-.149,.27),l(-.248,.17),M(433.783,118.446),l(-.712,-.084),l(-.902,-.607),l(-.772,-.239),l(-1.904,-.817),l(-.833,-.126),l(-.232,-.127),l(-.173,-.283),l(.139,-.34),l(.328,-.34),l(.264,-.1),l(.629,.112),l(.569,-.341),l(.68,.424),l(.403,.141),l(.722,-.016),l(1.403,-.187),l(1.38,-.329),l(.148,.085),l(.043,.127),l(-.112,.127),l(-.536,.823),l(-.153,.497),l(.009,.382),l(.411,.509),l(-.179,.128),l(-.43,.567),l(-.188,.015),M(431.244,98.829),l(-.281,-.329),l(-.242,-.027),l(-.281,.196),l(-.156,-.125),l(-.47,-.071),l(-.114,.32),l(-.458,.054),l(-1.001,.364),l(.078,-.151),l(-.452,.133),l(-.063,.249),l(-.157,.044),l(-.01,.125),l(.303,.08),l(.021,.302),l(.193,.119),l(.253,.236),l(-.104,.213),l(-.449,.254),l(.016,.272),l(.143,.554),l(.783,.814),l(2.008,.889),l(.29,.357),l(.134,.558),l(.274,.557),l(.395,.585),l(.694,.57),l(.254,.274),l(.446,.195),l(.041,.21),l(.408,.167),l(1.17,.255),l(1.254,-.105),l(.388,.141),l(.024,.212),l(-.465,.247),l(-.258,.294),l(.262,.213),l(.954,.283),l(1.168,.411),l(.829,.366),l(1.589,.739),l(.058,.185),l(.719,.458),l(.31,.475),l(-.198,.435),l(-.152,.337),l(-.455,-.281),l(-.318,-.167),l(-.109,-.486),l(-.263,-.17),l(-.512,-.099),l(-.483,-.009),l(-.439,-.236),l(.086,-.217),l(-.353,-.065),l(-.301,.098),l(-.232,.262),l(-.259,.399),l(-.273,.208),l(.043,.271),l(-.197,.303),l(-.007,.298),l(.76,.342),l(.611,.271),l(-.093,.314),l(.03,.432),l(.133,.142),l(-.191,.238),l(-.659,-.024),l(-.41,.219),l(-.202,.228),l(.11,.595),l(-.536,.303),l(-.617,.866),l(-.595,.048),l(-.167,-.071),l(-.184,-.14),l(-.002,-.508),l(.364,-.141),l(.317,-.542),l(-.236,-.184),l(.361,-.249),l(.361,.074),l(.133,-.17),l(-.077,-.34),l(-.211,-.181),l(-.206,-.924),l(-.367,-.516),l(-.15,-.607),l(-.201,-.352),l(-.334,.058),l(-.187,.171),l(-.899,-.496),l(-.286,-.065),l(.208,-.291),l(-.092,-.398),l(-.461,-.34),l(-.909,.247),l(.034,-.109),l(.322,-.194),l(-.276,-.27),l(-.29,-.003),l(-.42,.19),l(-.242,-.512),l(-.198,-.207),l(-.124,-.228),l(-.663,-.241),l(-.505,-.027),l(-.654,-.127),l(-.745,-.355),l(-.548,-.441),l(-.959,-.612),l(-1.036,-.826),l(-.872,-.384),l(-.805,-.67),l(-.566,-.856),l(-.434,-1.043),l(-.347,-.443),l(-.505,-.457),l(-.483,-.243),l(-1.188,-.341),l(-.579,-.142),l(-.5,.044),l(-1.078,.647),l(-.46,.359),l(-.646,.173),l(-.303,.043),l(.146,-.469),l(-.062,-.281),l(-.849,.07),l(-.754,-.391),l(-.193,-.442),l(.315,-.371),l(.175,-.01),l(-.135,-.331),l(-.616,-.191),l(-.352,-.358),l(.437,-.186),l(.183,.111),l(.541,-.353),l(.199,-.272),l(-.43,-.192),l(-.025,-.292),l(-.532,-.344),l(.624,-.301),l(.599,.062),l(.627,-.204),l(.629,.168),l(.275,-.16),l(.349,-.432),l(-.103,-.212),l(.777,-.404),l(.016,.415),l(.534,.363),l(.311,.071),l(-.098,.182),l(.385,.312),l(.285,-.151),l(.018,-.535),l(.425,-.384),l(-.019,-.333),l(.371,-.081),l(.143,.354),l(.23,.142),l(.216,-.03),l(.071,-.122),l(.469,-.05),l(.244,.333),l(.228,-.415),l(-.244,-.131),l(.081,-.273),l(.283,-.091),l(.176,.162),l(.315,.051),l(.038,-.192),l(-.112,-.212),l(.126,-.309),l(.631,.171),l(.597,.034),l(.329,-.411),l(.366,-.096),l(.183,.083),l(.445,-.11),l(.301,.103),l(.856,-.227),l(.023,.363),l(.318,.096),l(.32,.391),l(1.311,.247),l(.894,.082),l(.478,.112),l(.116,.199),l(-.614,.303),l(.098,.151),l(.297,.002),l(.187,.185),l(-.367,.285),l(.336,.089),l(-.127,.361),l(.36,.11),l(.284,.198),l(-.056,.214), +N(430.73,96.731),l(1.04,.065),l(.179,.107),l(.612,-.009),l(.287,.152),l(.646,-.5),l(.566,-.107),l(.85,.08),l(.298,-.196),l(.89,.116),l(-.082,-.393),l(.693,-.157),l(.304,.59),l(.364,.333),l(-.035,-.009),l(-.1,-.073),l(-.145,-.036),l(-.172,0),l(-.145,.009),l(-.055,.063),l(0,.072),l(.019,.09),l(.009,.082),l(-.063,.009),l(-.136,-.009),l(-.108,-.036),l(-.091,.063),l(-.045,.082),l(-.081,.063),l(-.082,.045),l(-.081,.009),l(-.163,.036),l(-.117,.036),l(-.108,.036),l(-.055,.045),l(-.153,-.009),l(-.127,.072),l(-.063,.054),l(-.018,.082),l(.036,.072),l(.081,.054),l(.063,.055),l(.045,.045),l(.019,.063),l(.018,.09),l(-.036,.108),l(-.018,.063),l(-.046,.1),l(-.108,0),l(-.081,-.009),l(-.091,.027),l(-.108,.009),l(-.117,.054),l(-.091,.018),l(-.081,.027),l(-.1,.045),l(-.055,.063),l(-.036,.027),l(.055,.018),l(.063,.009),l(.026,.027),l(.037,.072),l(-.046,.063),l(-.027,.009),l(-.081,.027),l(-.009,.045),l(.045,.081),l(0,.072),l(.045,.1),l(-.054,.072),l(-.063,-.018),l(-.1,.045),l(-.117,.018),l(-.127,-.036),l(-.063,-.027),l(-.1,-.063),l(-.099,0),l(-.063,-.027),l(-.118,-.045),l(-.018,.045),l(-.027,.045),l(-.1,.027),l(-.136,0),l(-.054,-.045),l(-.072,-.063),l(-.127,-.018),l(-.019,-.09),l(-.026,-.018),l(-.063,-.054),l(-.055,-.027),l(-.018,-.054),l(-.01,-.054),l(-.036,-.009),l(-.063,.018),l(-.036,.054),l(-.009,.027),l(-.054,.063),l(-.019,.018),l(-.018,.081),l(-.063,.045),l(-.046,.018),l(-.062,.054),l(-.036,.009),l(-.254,0),l(-.108,-.027),l(-.108,.027),l(-.145,.009),l(-.1,-.009),l(-.1,-.036),l(-.045,-.019),l(-.055,0),l(0,.037),l(0,.036),l(-.045,.027),l(-.045,.018),l(-.136,-.009),l(-.027,-.036),l(-.108,.018),l(-.019,.018),l(-.136,.018),l(-.063,.018),l(-.126,.018),l(-.272,-.063),l(.428,-.077),l(.113,-.16),l(.056,-.214),l(-.284,-.198),l(-.36,-.11),l(.127,-.361),l(-.336,-.089),l(.367,-.285),l(-.187,-.185),l(-.297,-.002),l(-.098,-.151),l(.614,-.303),l(-.116,-.199), +N(439.573,104.709),l(-1.051,-.672),l(-.185,-.222),l(-.783,-.149),l(-.203,-.159),l(-.403,-.115),l(-.683,.177),l(-.326,-.486),l(-1.112,-.627),l(-.584,-.678),l(.277,.007),l(.608,.016),l(-.583,-.221),l(-.659,-.469),l(-.183,-.407),l(.086,-.452),l(-.289,-.336),l(-.646,-.418),l(-.378,-.126),l(-.258,.579),l(-.142,.116),l(.03,.15),l(-.284,.106),l(-.154,.248),l(-.213,.053),l(-.496,-.647),l(-.063,-.286),l(-.259,-.612),l(.065,-.012),l(.272,.063),l(.126,-.018),l(.063,-.018),l(.136,-.018),l(.019,-.018),l(.108,-.018),l(.027,.036),l(.136,.009),l(.045,-.018),l(.045,-.027),l(0,-.036),l(0,-.037),l(.055,0),l(.045,.019),l(.1,.036),l(.1,.009),l(.145,-.009),l(.108,-.027),l(.108,.027),l(.254,0),l(.036,-.009),l(.062,-.054),l(.046,-.018),l(.063,-.045),l(.018,-.081),l(.019,-.018),l(.054,-.063),l(.009,-.027),l(.036,-.054),l(.063,-.018),l(.036,.009),l(.01,.054),l(.018,.054),l(.055,.027),l(.063,.054),l(.026,.018),l(.019,.09),l(.127,.018),l(.072,.063),l(.054,.045),l(.136,0),l(.1,-.027),l(.027,-.045),l(.018,-.045),l(.118,.045),l(.063,.027),l(.099,0),l(.1,.063),l(.063,.027),l(.127,.036),l(.117,-.018),l(.1,-.045),l(.063,.018),l(.054,-.072),l(-.045,-.1),l(0,-.072),l(-.045,-.081),l(.009,-.045),l(.081,-.027),l(.027,-.009),l(.046,-.063),l(-.037,-.072),l(-.026,-.027),l(-.063,-.009),l(-.055,-.018),l(.036,-.027),l(.055,-.063),l(.1,-.045),l(.081,-.027),l(.091,-.018),l(.117,-.054),l(.108,-.009),l(.091,-.027),l(.081,.009),l(.108,0),l(.046,-.1),l(.018,-.063),l(.036,-.108),l(-.018,-.09),l(-.019,-.063),l(-.045,-.045),l(-.063,-.055),l(-.081,-.054),l(-.036,-.072),l(.018,-.082),l(.063,-.054),l(.127,-.072),l(.153,.009),l(.055,-.045),l(.108,-.036),l(.117,-.036),l(.163,-.036),l(.081,-.009),l(.082,-.045),l(.081,-.063),l(.045,-.082),l(.091,-.063),l(.108,.036),l(.136,.009),l(.063,-.009),l(-.009,-.082),l(-.019,-.09),l(0,-.072),l(.055,-.063),l(.145,-.009),l(.172,0),l(.145,.036),l(.1,.073),l(.035,.009),l(.215,.197),l(1.412,.612),l(1.116,.671),l(.58,.098),l(.668,-.047),l(.433,-.031),l(.589,-.203),l(.201,.142),l(.056,.089),l(.022,.112),l(-.022,.078),l(.045,.044),l(.011,.067),l(-.078,.056),l(-.011,.146),l(.078,.067),l(.145,-.034),l(.101,.034),l(.045,.089),l(-.078,.011),l(-.056,-.022),l(-.022,.078),l(.033,.1),l(-.045,.034),l(-.044,.022),l(.066,.111),l(.168,-.022),l(.033,.078),l(.123,.1),l(.122,0),l(.101,0),l(.09,.078),l(.122,.011),l(.134,0),l(.012,.078),l(-.033,.056),l(-.135,-.011),l(-.089,-.034),l(-.067,.022),l(-.078,-.011),l(-.066,-.045),l(-.056,-.011),l(-.045,.011),l(.033,.067),l(-.101,.089),l(-.078,0),l(0,.156),l(.045,.067),l(-.033,.078),l(.022,.078),l(.011,.078),l(-.089,.033),l(-.09,-.033),l(-.056,.067),l(.078,.089),l(-.078,.011),l(-.189,.022),l(-.201,-.022),l(-.145,-.123),l(.056,-.101),l(-.045,-.089),l(-.123,-.011),l(-.022,-.112),l(-.145,-.056),l(-.146,-.045),l(-.101,.089),l(-.1,-.011),l(-.156,-.078),l(-.067,-.022),l(-.146,0),l(-.156,-.045),l(-.111,.067),l(-.134,.045),l(-.134,-.045),l(-.111,-.067),l(-.112,0),l(-.122,.089),l(-.168,.078),l(-.156,-.067),l(-.268,-.089),l(-.179,.011),l(-.156,.011),l(-.189,-.056),l(-.168,-.011),l(-.156,-.089),l(-.089,.078),l(-.111,.022),l(-.057,-.056),l(-.234,-.078),l(-.156,-.056),l(-.134,-.045),l(-.089,-.011),l(-.134,.123),l(-.112,-.011),l(-.223,-.022),l(-.168,-.033),l(-.212,.022),l(-.101,.111),l(-.145,.145),l(-.123,.201),l(-.201,-.022),l(-.256,-.134),l(-.156,-.19),l(-.101,-.111),l(-.312,-.034),l(-.123,.044),l(-.089,.179),l(-.045,.167),l(.045,.134),l(0,.078),l(.033,.212),l(-.123,.067),l(.022,.089),l(.134,.078),l(.09,.089),l(.122,.034),l(.101,.033),l(.179,.179),l(.146,.234),l(.089,.134),l(.022,.123),l(.156,.111),l(-.078,.056),l(-.012,.1),l(.022,.146),l(.168,-.011),l(.089,.111),l(.056,.123),l(.112,.111),l(.167,.045),l(.167,.033),l(.369,.357),l(.021,.167),l(.078,.044),l(.213,.078),l(.379,.357),l(.224,.123),l(.223,.067),l(.101,.056),l(0,.112),l(.078,.279),l(.201,.078),l(.189,.167),l(.146,.112),l(.245,.123),l(.067,.212),l(-.284,.083),M(439.792,104.833),l(.132,-.118),l(.134,.011),l(.123,.034),l(.045,.078),l(.066,.089),l(.146,.089),l(.179,.078),l(.212,.011),l(.312,.257),l(.045,.067),l(.134,-.033),l(.123,.022),l(.089,.034),l(.062,.063),l(.005,.004),l(-.022,.089),l(.033,.078),l(.082,.072),l(.029,.092),l(-.002,.1),l(-.589,-.367),l(-.549,-.371),l(-.789,-.378), +N(451.009,101.725),l(-.328,.346),l(-.383,.374),l(-.18,.302),l(.056,.271),l(1.326,1.122),l(.028,.2),l(-.302,.302),l(-.762,.333),l(-.246,.301),l(-.008,.514),l(-.013,.208),l(-.058,-.017),l(-.072,.029),l(-.16,.022),l(-.145,.021),l(-.116,.022),l(-.058,.015),l(-.102,-.051),l(-.087,.043),l(-.088,.021),l(-.102,-.043),l(-.064,-.021),l(-.131,.116),l(-.087,.08),l(-.152,-.015),l(-.196,-.007),l(-.064,.007),l(-.175,-.043),l(-.152,.087),l(-.151,.102),l(-.109,.058),l(.059,.072),l(-.029,.058),l(-.116,0),l(-.094,-.109),l(-.131,-.058),l(-.087,-.073),l(-.08,.065),l(-.116,.058),l(-.246,.058),l(-.225,.058),l(-.088,.058),l(-.058,.167),l(.029,.13),l(-.029,.072),l(-.072,.087),l(-.188,0),l(-.14,-.049),l(-.018,-.109),l(-.733,-.866),l(-.382,-.369),l(-.058,-.004),l(.109,-.286),l(0,-.067),l(-.078,-.067),l(-.101,0),l(-.056,-.056),l(.022,-.089),l(.111,-.033),l(.146,.011),l(.167,.033),l(.057,-.033),l(.021,-.067),l(.09,-.044),l(.134,-.022),l(.089,-.011),l(-.011,-.089),l(-.101,-.101),l(-.167,-.067),l(-.134,-.045),l(-.057,-.044),l(-.111,.022),l(-.078,-.045),l(-.033,-.067),l(-.123,-.101),l(-.078,-.1),l(-.066,-.022),l(-.067,.044),l(-.078,-.011),l(-.101,-.056),l(-.279,-.078),l(-.078,-.022),l(-.056,-.033),l(-.167,-.134),l(-.101,-.146),l(-.111,-.111),l(-.168,-.078),l(-.156,-.101),l(-.223,-.056),l(0,-.101),l(.179,-.101),l(.089,-.111),l(.078,-.011),l(.067,.034),l(.078,.044),l(.1,.022),l(.045,-.022),l(.012,-.134),l(.011,-.19),l(-.134,-.145),l(-.179,-.19),l(-.212,-.134),l(-.101,-.145),l(.101,.022),l(.101,.011),l(.145,.056),l(.224,.044),l(.134,-.078),l(.089,-.056),l(.067,-.078),l(-.089,-.044),l(-.135,-.022),l(-.089,-.089),l(-.123,-.078),l(-.156,-.089),l(-.033,-.101),l(-.045,-.1),l(-.212,.011),l(-.167,-.056),l(-.078,-.1),l(-.022,-.134),l(.078,-.067),l(0,-.089),l(-.033,-.1),l(.056,-.056),l(.066,-.078),l(.156,-.156),l(.156,-.223),l(.034,-.167),l(.056,-.1),l(-.022,-.067),l(-.123,-.022),l(-.179,-.011),l(-.156,0),l(-.212,.112),l(-.078,-.089),l(.056,-.067),l(.09,.033),l(.089,-.033),l(-.011,-.078),l(-.022,-.078),l(.033,-.078),l(-.045,-.067),l(0,-.156),l(.078,0),l(.101,-.089),l(-.033,-.067),l(.045,-.011),l(.056,.011),l(.066,.045),l(.078,.011),l(.067,-.022),l(.089,.034),l(.135,.011),l(.033,-.056),l(-.012,-.078),l(-.134,0),l(-.122,-.011),l(-.09,-.078),l(-.101,0),l(-.122,0),l(-.123,-.1),l(-.033,-.078),l(-.168,.022),l(-.066,-.111),l(.044,-.022),l(.045,-.034),l(-.033,-.1),l(.022,-.078),l(.056,.022),l(.078,-.011),l(-.045,-.089),l(-.101,-.034),l(-.145,.034),l(-.078,-.067),l(.011,-.146),l(.078,-.056),l(-.011,-.067),l(-.045,-.044),l(.022,-.078),l(-.022,-.112),l(-.056,-.089),l(-.201,-.142),l(1.535,-.529),l(.889,-.077),l(.907,.067),l(.054,.309),l(.569,.178),l(.19,.237),l(.202,.036),l(-.075,.356),l(.104,.119),l(-.058,.088),l(.712,.471),l(.555,.141),l(.306,.118),l(.069,.142),l(-.19,.127),l(-.124,.146),l(.183,.059),l(.239,.083),l(-.271,.071),l(-.178,.094),l(.052,.165),l(.245,.036),l(.234,0),l(.02,.189),l(.594,.059),l(.194,.139),l(.414,.239),l(.147,-.118),l(.215,-.283),l(.253,-.13),l(.625,.248),l(.114,.13),l(-.351,-.012),l(-.32,.201),l(.146,.33),l(.418,.186), +N(551.198,117.997),l(-.351,-.48),l(-.236,-.126),l(-1.217,-.05),l(-.646,-.011),l(-.096,-.016),l(.091,-.726),l(-.062,-.503),l(.157,-.251),l(.062,-.22),l(-.503,-.094),l(-.534,-.283),l(-.566,-.189),l(-.471,.063),l(-.378,-.251),l(-1.132,-.597),l(-.565,-.22),l(-.943,-.597),l(-.314,.063),l(-1.006,-.503),l(-.377,-.44),l(-1.194,-.597),l(-1.384,-.975),l(0,-.283),l(-.188,-.44),l(-.283,-.188),l(-.408,-.597),l(-.126,-.566),l(-.22,-.377),l(-.881,-.251),l(-.188,.157),l(-.439,.063),l(-.535,-.126),l(-.439,.032),l(-.503,.094),l(-.314,-.157),l(-.691,-.314),l(.094,-.22),l(.157,-.188),l(-.188,-.22),l(.031,-.188),l(.188,-.157),l(-.439,-.283),l(0,-.22),l(-.032,-.22),l(-.251,-.22),l(-.534,-.094),l(-.692,-.095),l(-.22,-.314),l(-.346,-.032),l(-.629,-.377),l(-.472,-.095),l(-.188,.063),l(-.565,.157),l(.251,.251),l(.188,.377),l(-.597,-.283),l(-.283,0),l(-.126,.126),l(-.22,.346),l(-.283,.126),l(-.629,0),l(-.503,.251),l(-.503,.409),l(-.062,.628),l(.314,.409),l(-.126,.314),l(-1.383,.032),l(-1.03,-.063),l(.056,-8.174),l(5.658,-1.289),l(5.722,2.986),l(2.012,1.666),l(2.578,-.346),l(2.767,.188),l(1.1,-.409),l(.724,.723),l(.597,.22),l(.66,1.006),l(.66,-.314),l(-.031,1.038),l(-.188,.409),l(.031,.754),l(1.006,0),l(.221,.817),l(.346,1.069),l(.503,.063),l(.691,-.032),l(1.006,-.094),l(.346,0),l(.44,.314),l(.062,.283),l(-.062,.283),l(.44,.346),l(.66,0),l(.125,-.188),l(-.157,-.409),l(.504,-.44),l(.439,-.188),l(.221,-.472),l(.282,-.188),l(.943,-.377),l(.755,-.189),l(.534,-.471),l(.346,-.283),l(.22,-.063),l(.283,.126),l(.377,-.377),l(.322,-.031),l(.349,-.126),l(.441,.246),l(-.368,.172),l(-.368,.171),l(-.221,.049),l(-.073,.196),l(-.295,.049),l(-.294,.172),l(-.196,.147),l(-.441,.295),l(-.172,.098),l(-.024,.123),l(.294,.049),l(.295,.074),l(.146,.123),l(.418,-.147),l(.098,.221),l(.172,.221),l(.368,.27),l(.589,0),l(.393,0),l(.049,-.393),l(.221,.049),l(.196,-.196),l(.024,-.245),l(.196,.098),l(.196,.172),l(.172,.294),l(.049,.147),l(.393,.024),l(.147,-.024),l(.073,.246),l(.025,.098),l(.343,-.025),l(.319,.147),l(.245,.196),l(.516,.074),l(.466,.024),l(.172,.123),l(-.49,.221),l(-.197,.147),l(-.221,.147),l(-.49,-.024),l(-.245,-.049),l(.049,.171),l(0,.147),l(-.319,0),l(-.172,.049),l(-.343,.196),l(-.221,.196),l(-.271,.049),l(-.221,.196),l(-.245,-.147),l(-.319,-.098),l(-.294,-.098),l(-.221,.025),l(-.246,.073),l(-.318,-.073),l(-.042,.098),l(-.345,-.005),l(-.409,.031),l(-.188,-.283),l(-.251,-.063),l(-.126,-.188),l(.251,-.126),l(.409,-.346),l(.188,-.22),l(-.252,-.251),l(-.439,-.377),l(-.221,.251),l(-.471,.346),l(-.692,.188),l(-.22,.157),l(-.252,-.22),l(-.22,-.157),l(-.346,0),l(.031,.22),l(-.283,.314),l(.189,.314),l(-.032,.346),l(-.062,.126),l(-.472,-.095),l(-.565,.095),l(-.503,.094),l(.251,.125),l(.534,-.031),l(.126,.094),l(-.251,.063),l(-.188,.063),l(-.032,.346),l(-.188,0),l(-.251,.157),l(-.063,.409),l(-.282,.188),l(-1.069,-.094),l(-.629,-.126),l(-.472,.283),l(-.125,.471),l(.251,.283),l(.346,.188),l(.157,.157),l(.44,.032),l(.346,0),l(.126,.22),l(-.126,.22),l(-.031,.472),l(.126,.409),l(.471,.314),l(.126,.283),l(-.157,.22),l(-.503,.346),l(-.283,.503),l(-.377,.377),l(.063,.377),l(-.375,.843), +N(439.792,104.833),l(-.113,-.054),l(-.105,-.07),l(.284,-.083),l(-.067,-.212),l(-.245,-.123),l(-.146,-.112),l(-.189,-.167),l(-.201,-.078),l(-.078,-.279),l(0,-.112),l(-.101,-.056),l(-.223,-.067),l(-.224,-.123),l(-.379,-.357),l(-.213,-.078),l(-.078,-.044),l(-.021,-.167),l(-.369,-.357),l(-.167,-.033),l(-.167,-.045),l(-.112,-.111),l(-.056,-.123),l(-.089,-.111),l(-.168,.011),l(-.022,-.146),l(.012,-.1),l(.078,-.056),l(-.156,-.111),l(-.022,-.123),l(-.089,-.134),l(-.146,-.234),l(-.179,-.179),l(-.101,-.033),l(-.122,-.034),l(-.09,-.089),l(-.134,-.078),l(-.022,-.089),l(.123,-.067),l(-.033,-.212),l(0,-.078),l(-.045,-.134),l(.045,-.167),l(.089,-.179),l(.123,-.044),l(.312,.034),l(.101,.111),l(.156,.19),l(.256,.134),l(.201,.022),l(.123,-.201),l(.145,-.145),l(.101,-.111),l(.212,-.022),l(.168,.033),l(.223,.022),l(.112,.011),l(.134,-.123),l(.089,.011),l(.134,.045),l(.156,.056),l(.234,.078),l(.057,.056),l(.111,-.022),l(.089,-.078),l(.156,.089),l(.168,.011),l(.189,.056),l(.156,-.011),l(.179,-.011),l(.268,.089),l(.156,.067),l(.168,-.078),l(.122,-.089),l(.112,0),l(.111,.067),l(.134,.045),l(.134,-.045),l(.111,-.067),l(.156,.045),l(.146,0),l(.067,.022),l(.156,.078),l(.1,.011),l(.101,-.089),l(.146,.045),l(.145,.056),l(.022,.112),l(.123,.011),l(.045,.089),l(-.056,.101),l(.145,.123),l(.201,.022),l(.189,-.022),l(.078,-.011),l(.212,-.112),l(.156,0),l(.179,.011),l(.123,.022),l(.022,.067),l(-.056,.1),l(-.034,.167),l(-.156,.223),l(-.156,.156),l(-.066,.078),l(-.056,.056),l(.033,.1),l(0,.089),l(-.078,.067),l(.022,.134),l(.078,.1),l(.167,.056),l(.212,-.011),l(.045,.1),l(.033,.101),l(.156,.089),l(.123,.078),l(.089,.089),l(.135,.022),l(.089,.044),l(-.067,.078),l(-.089,.056),l(-.134,.078),l(-.224,-.044),l(-.145,-.056),l(-.101,-.011),l(-.101,-.022),l(.101,.145),l(.212,.134),l(.179,.19),l(.134,.145),l(-.011,.19),l(-.012,.134),l(-.045,.022),l(-.1,-.022),l(-.078,-.044),l(-.067,-.034),l(-.078,.011),l(-.089,.111),l(-.179,.101),l(-.056,-.033),l(-.156,.056),l(-.112,-.022),l(-.066,-.044),l(-.112,.033),l(-.078,.056),l(.012,.078),l(.089,.1),l(.123,.167),l(.056,.101),l(-.056,.101),l(-.111,0),l(-.09,-.056),l(-.056,-.089),l(-.056,-.044),l(-.123,-.011),l(-.122,.056),l(-.168,.078),l(-.045,.101),l(-.044,.089),l(-.112,.101),l(.034,.089),l(.011,.1),L(442,104.458),l(-.134,.011),l(-.111,.022),l(-.101,.089),l(-.012,.134),l(.012,.112),l(.011,.145),l(.012,.044),l(.066,.112),l(.078,.089),l(.045,.101),l(-.09,.089),l(-.183,.108),l(-.062,-.063),l(-.089,-.034),l(-.123,-.022),l(-.134,.033),l(-.045,-.067),l(-.312,-.257),l(-.212,-.011),l(-.179,-.078),l(-.146,-.089),l(-.066,-.089),l(-.045,-.078),l(-.123,-.034),l(-.134,-.011),l(-.132,.118), +N(450.198,105.998),l(.013,-.208),l(.008,-.514),l(.246,-.301),l(.762,-.333),l(.302,-.302),l(-.028,-.2),l(-1.326,-1.122),l(-.056,-.271),l(.18,-.302),l(.383,-.374),l(.328,-.346),l(.392,.204),l(.352,.106),l(-.234,.318),l(.048,.189),l(.266,-.023),l(.771,-.189),l(.506,.002),l(1.151,.395),l(.34,-.031),l(.69,-.261),l(.3,.013),l(1.385,.35),l(.38,-.059),l(1.904,-.771),l(.618,-.218),l(.562,.04),l(.671,.369),l(.295,.042),l(.514,.226),l(1.346,.336),l(.671,.12),l(-.066,.335),l(-.077,.258),l(-.261,.086),l(-.313,-.028),l(-.339,.129),l(-.327,.73),l(-.039,.586),l(-.075,.143),l(-.404,.115),l(-.338,.372),l(-.017,.257),l(.252,-.036),l(.255,.224),l(.033,.154),l(.391,.375),l(.01,.223),l(-1.333,-.005),l(-.527,-.111),l(-.497,.045),l(-.629,.374),l(-.498,.445),l(-.363,-.026),l(-.344,.216),l(.097,.327),l(-.086,.257),l(-1.117,.277),l(-.388,.031),l(-.619,-.21),l(-1.473,-.505),l(-.584,.06),l(-.799,.261),l(-1.855,.195),l(-.09,.029),l(-.047,-.199),l(.104,-.3),l(.006,-.499),l(-.225,-.469),l(-.358,-.383),l(-.666,-.296),l(-.134,-.213),l(.007,-.106), +N(381.009,107),l(-.121,-.278),l(.138,-.4),l(.343,-.5),l(-.358,-.471),l(-.304,-.428),l(-.514,-.07),l(-.164,-.1),l(-.053,-.329),l(.163,-.243),l(.409,-.272),l(.365,-.101),l(.563,-.03),l(.634,-.03),l(.133,-.172),l(.068,-.415),l(.535,-.273),l(.763,.042),l(1.078,.37),l(.763,.07),l(.756,-.087),l(.577,-.173),l(.508,-.144),l(.354,-.001),l(.629,.285),l(.694,.156),l(.939,.084),l(1.538,.04),l(.583,.027),l(.957,.141),l(.491,-.158),l(.419,-.229),l(.531,.027),l(.891,.47),l(.67,-.016),l(.335,.062),l(.472,.243),l(.469,-.03),l(.058,.122),l(-.205,.243),l(.094,.106),l(.15,.03),l(.112,-.106),l(1.088,.334),l(.15,-.061),l(.507,.395),l(.056,-.076),l(.262,.03),l(.131,-.076),l(.431,.152),l(.028,.038),l(.084,.114),l(.767,-.03),l(.037,.122),l(.337,-.061),l(.542,.015),l(-.017,-.319),l(.355,0),l(1.252,.304),l(.091,.213),l(.035,.289),l(.187,.076),l(.374,-.076),l(.206,-.03),l(.335,.091),l(.036,.152),l(.261,.015),l(.395,-.167),l(.427,.197),l(.485,.015),l(.039,-.136),l(.75,-.137),l(.334,.091),l(-.001,.088),l(-.001,.463),l(.156,.1),l(-.062,.485),l(-1.112,.528),l(-.95,.385),l(-.267,.328),l(-1.046,.198),l(-.664,.116),l(-.96,.301),l(-.323,.326),l(-.053,.2),l(.261,.128),l(-.088,.157),l(-.628,.143),l(-.594,.783),l(-.886,.787),l(-.096,.192),l(-.18,.361),l(-.245,.45),l(.353,.827),l(.072,.111),l(.084,.13),l(.648,.295),l(.103,.185),l(-.621,.327),l(-.215,.105),l(-.515,.252),l(-.286,.479),l(-.224,.085),l(-.461,.926),l(.155,.322),l(-.257,.099),l(-.992,.049),l(-.581,.242),l(-.425,.327),l(-.274,.757),l(-.663,.496),l(-.258,-.213),l(-.599,.028),l(-.305,.27),l(-.342,0),l(-.121,-.113),l(-3.282,.042),l(-.69,.524),l(-1.021,.17),l(-.35,.382),l(-.028,.283),l(-.083,.085),l(-.073,-.212),l(-.068,-.014),l(.005,.241),l(-.389,.127),l(-.421,-.142),l(-.788,-.467),l(-.224,-.382),l(.036,-.262),l(-.345,-.113),l(-.125,-.213),l(.175,-.163),l(-.468,-.51),l(-.702,-.284),L(385,117.498),l(-.484,-.135),l(-.586,.039),l(.008,-.018),l(.304,-.951),l(.242,-.37),l(.884,-.643),l(-.408,-.31),l(-.812,-.123),l(.17,-.455),l(.506,-.655),l(.347,-.371),l(-.163,-.198),l(-.455,-.551),l(-.488,-.494),l(.288,-.129),l(.482,-.045),l(.458,-.229),l(.043,-.199),l(-.057,-.938),l(.132,-.983),l(-.072,-.456),l(.051,-.442),l(.084,-.072),l(1.234,-.506),l(.288,-.216),l(-.062,-.242),l(-.842,-.495),l(-.15,-.242),l(-.272,-.227),l(-.335,-.055),l(-.531,.26),L(382.981,107),l(-.531,-.439),l(-.55,.188),L(381.009,107), +N(489.685,103.693),l(.112,-.309),l(.26,-.166),l(.284,.047),l(.07,.047),l(.402,.023),l(.449,.023),l(.283,.095),l(.284,.142),l(.188,.094),l(.189,.047),l(.331,0),l(.213,0),l(.212,.166),l(.261,.095),l(.307,.071),l(.355,.047),l(.307,0),l(.426,-.095),l(.544,0),l(.401,.166),l(.189,0),l(.283,-.047),l(.354,.166),l(.095,.142),l(.284,.213),l(.52,.118),l(.354,.071),l(.236,.118),l(.308,.119),l(-.142,.118),l(-.048,.118),l(.261,.118),l(.212,.071),l(.261,-.118),l(.283,0),l(.166,-.166),l(.094,-.095),l(.213,-.071),l(.354,0),l(.261,.071),l(.188,.142),l(.142,-.166),l(.095,-.071),l(.118,0),l(.236,.118),l(.143,.094),l(.212,0),l(.189,.118),l(.213,.166),l(.378,0),l(.354,.024),l(.118,.142),l(-.118,.189),l(-.118,.307),l(.354,.284),l(.284,.166),l(.26,.094),l(.284,.047),l(.236,-.023),l(.236,.071),l(.126,.189),l(-.268,.189),l(-.143,.142),l(-.095,.071),l(.143,.26),l(.213,.307),l(.614,.166),l(.118,.213),l(-.095,.331),l(-.236,.095),l(-.236,.047),l(-.26,-.189),l(-.143,-.071),l(-.188,-.023),l(-.284,.047),l(-.638,-.189),l(-.189,-.213),l(-.331,-.189),l(-.473,-.024),l(-.236,0),l(-.418,.308),l(-.291,.094),l(-.378,.047),l(-.591,.095),l(-.592,-.047),l(-.401,.118),l(-.426,.023),l(-.308,.095),l(-.307,-.024),l(-.377,.108),l(-.031,-.028),l(-1.326,-1.018),l(-.41,-.041),l(-.761,.36),l(-.226,.072),l(-.491,-.068),l(-1.212,-.082),l(.083,-.065),l(.322,-.585),l(.032,-.143),l(-.064,-.728),l(-.331,-1.084),l(-.206,-.399),l(-.639,-.513),l(-.341,-.128),l(-.916,-.155),l(-.679,-.271),l(-.341,-.243), +N(443.617,107.095),l(-.065,-.035),l(-.435,-.156),l(-.017,-.15),l(-.501,-.485),l(-.848,-.3),l(-.033,-.021),l(.002,-.1),l(-.029,-.092),l(-.082,-.072),l(-.033,-.078),l(.022,-.089),l(-.005,-.004),l(.183,-.108),l(.09,-.089),l(-.045,-.101),l(-.078,-.089),l(-.066,-.112),l(-.012,-.044),l(-.011,-.145),l(-.012,-.112),l(.012,-.134),l(.101,-.089),l(.111,-.022),l(.134,-.011),l(.056,-.056),l(-.011,-.1),l(-.034,-.089),l(.112,-.101),l(.044,-.089),l(.045,-.101),l(.168,-.078),l(.122,-.056),l(.123,.011),l(.056,.044),l(.056,.089),l(.09,.056),l(.111,0),l(.056,-.101),l(-.056,-.101),l(-.123,-.167),l(-.089,-.1),l(-.012,-.078),l(.078,-.056),l(.112,-.033),l(.066,.044),l(.112,.022),l(.156,-.056),l(.056,.033),l(0,.101),l(.223,.056),l(.156,.101),l(.168,.078),l(.111,.111),l(.101,.146),l(.167,.134),l(.056,.033),l(.078,.022),l(.279,.078),l(.101,.056),l(.078,.011),l(.067,-.044),l(.066,.022),l(.078,.1),l(.123,.101),l(.033,.067),l(.078,.045),l(.111,-.022),l(.057,.044),l(.134,.045),l(.167,.067),l(.101,.101),l(.011,.089),l(-.089,.011),l(-.134,.022),l(-.09,.044),l(-.021,.067),l(-.057,.033),l(-.167,-.033),l(-.146,-.011),l(-.111,.033),l(-.022,.089),l(.056,.056),l(.101,0),l(.078,.067),l(0,.067),l(-.109,.286),l(-.361,-.022),l(-.727,-.11),l(-.273,.273),l(-.279,.515),l(.133,.427),l(-.002,.342), +N(558.52,110.652),l(.042,-.098),l(.318,.073),l(.246,-.073),l(.221,-.025),l(.294,.098),l(.319,.098),l(.245,.147),l(.221,-.196),l(.271,-.049),l(.221,-.196),l(.343,-.196),l(.172,-.049),l(.319,0),l(0,-.147),l(-.049,-.171),l(.245,.049),l(.49,.024),l(.221,-.147),l(.197,-.147),l(.49,-.221),l(-.172,-.123),l(-.466,-.024),l(-.516,-.074),l(-.245,-.196),l(-.319,-.147),l(-.343,.025),l(-.025,-.098),l(-.073,-.246),l(-.147,.024),l(-.393,-.024),l(-.049,-.147),l(-.172,-.294),l(-.196,-.172),l(-.196,-.098),l(-.024,.245),l(-.196,.196),l(-.221,-.049),l(-.049,.393),l(-.393,0),l(-.589,0),l(-.368,-.27),l(-.172,-.221),l(-.098,-.221),l(-.418,.147),l(-.146,-.123),l(-.295,-.074),l(-.294,-.049),l(.024,-.123),l(.172,-.098),l(.441,-.295),l(.196,-.147),l(.294,-.172),l(.295,-.049),l(.073,-.196),l(.221,-.049),l(.368,-.171),l(.368,-.172),l(-.441,-.246),l(-.349,.126),l(-.044,-.273),l(.393,-.442),l(.318,-.368),l(.736,-.123),l(.663,-.098),l(.883,.147),l(.883,.245),l(.688,.196),l(.81,.123),l(.344,.123),l(-.024,-.442),l(.245,-.736),l(.466,-.368),l(.688,-.123),l(.589,.074),l(.761,.27),l(.735,.246),l(.908,.196),l(.54,.098),l(.441,-.27),l(.858,-.024),l(.761,0),l(.785,-.147),l(.712,.221),l(.662,.098),l(1.35,.024),l(.662,-.074),l(.981,.246),l(.564,-.049),l(.147,.344),l(.27,.147),l(.196,.27),l(.663,0),l(.466,.098),l(.41,.375),l(.031,.194),l(-.051,.157),l(-.325,.187),l(-.97,.219),l(-1.338,.349),l(-.445,.145),l(-.405,.301),l(-.638,.701),l(-.646,.345),l(-.478,.102),l(-.459,.017),l(-1.248,-.235),l(-.238,.03),l(-.467,.472),l(-.463,.784),l(-.268,.243),l(-.885,.132),l(-.507,.145),l(-.344,-.055),l(-.183,-.567),l(-.06,-.071),l(-.359,.03),l(-1.737,.734),l(-1.422,.704),l(-.274,.186),l(-.129,.213),l(-.139,.739),l(-.196,-.073),l(-.344,.098),l(-.344,.171),l(-.539,0),l(-.663,-.073),l(-.834,.221),l(-.172,.147),l(-.196,0),l(-.172,-.319),l(-.368,.024),l(-.318,.172),l(-.074,-.221),l(-.049,-.172),l(-.122,.024),l(-.319,-.123),l(-.049,-.147),l(-.221,-.024),l(-.442,.123),l(-.343,.049),l(.024,.221),l(-.295,.049),l(-.393,-.074),l(-.073,-.196),l(-.147,-.123),l(-.368,-.098),l(-.49,.147),l(-.196,-.073),l(-.688,.024),l(-.564,0),l(-.589,.024),l(-.122,-.098),l(-.049,-.147),l(-.099,-.27),l(.099,-.245),l(.196,-.196),l(.098,.221),l(.196,-.074),l(-.049,-.196),l(.098,-.27),l(.123,0),l(.981,-.196),l(.515,.147),l(.516,.196),l(.099,.172),l(.196,0),l(.024,-.246),l(.441,-.196),l(.302,-.147), +N(685.343,114.455),l(-.571,.678),l(-.309,.115),l(-.511,-.096),l(-.579,-.068),l(-.595,-.011),l(-.315,.157),l(-.633,.738),l(-.283,.256),l(-.235,.171),l(-.268,-.206),l(-.35,.34),l(-.319,.199),l(-.373,-.608),l(-.398,-.112),l(-.649,.78),l(-.195,-.382),l(-.232,-.254),l(-.683,-.367),l(-.169,-.453),l(.095,-.312),l(.429,-.411),l(.754,-.229),l(.056,-.269),l(-.591,-.282),l(.407,-.879),l(.189,-.34),l(-.199,-.269),l(-.632,-.296),l(-.139,0),l(-.381,.029),l(-.312,.143),l(-.234,-.07),l(-.52,-.368),l(-.167,-.233),l(.379,-.528),l(.415,-.442),l(.52,-.329),l(1.533,-.604),l(1.032,-.545),l(.636,-.543),l(.686,-1.027),l(.386,-.13),l(.448,-.017),l(.273,.396),l(.493,.253),l(.508,.153),l(.975,-.048),l(.527,-.159),l(-.046,-.113),l(-.508,-.765),l(.025,-.342),l(.273,-.243),l(.392,-.059),l(.333,.126),l(.452,.054),l(.538,-.017),l(.62,-.259),l(.955,-.532),l(.23,-.713),l(.383,-.358),l(.253,-.129),l(.247,-.001),l(.579,.68),l(.298,.439),l(.167,.393),l(-1.356,.923),l(-.408,.457),l(-.112,.414),l(.09,.427),l(-.154,.456),l(-.187,.868),l(-.668,.115),l(-.36,.229),l(-.497,.385),l(-.766,.641),l(-.468,.214),l(-.678,.03),l(-.577,.199),l(-.265,.228),l(-.248,.312),l(-.364,.893),l(.284,.326),l(1.225,.847),l(.419,.354), +N(536.625,121.017),l(-.078,-.028),l(-.15,-.692),l(-.01,-.565),l(-.038,-.848),l(-.185,-.211),l(-.787,.075),l(-.696,-.01),l(-.655,-.506),l(-1.803,-1.362),l(-.597,-.336),l(-.66,-.167),l(-.5,-.054),l(-.788,-.066),l(-.822,-.335),l(-.708,-.251),l(-.402,-.437),l(-1.055,-.107),l(-.519,-.054),l(-.343,.129),l(-.517,.343),l(-.333,.03),l(-.78,-.038),l(-.609,.032),l(-.413,.144),l(-.476,.328),l(-.621,.654),l(-.466,.3),l(-.562,.13),l(-.441,-.025),l(-.066,-.376),l(-.128,-.681),l(-.106,-.447),l(.128,-.298),l(0,-.383),l(0,-.532),l(.106,-.191),l(.106,-.298),l(.085,-.234),l(-.085,-.212),l(-.256,-.128),l(-.319,-.191),l(-.213,-.255),l(-.042,-.149),l(-.171,0),l(-.191,-.042),l(-.361,-.106),l(-.191,.192),l(-.086,-.234),l(.086,-.106),l(.148,-.255),l(.128,.106),l(.383,-.042),l(.426,.085),l(.128,.021),l(.043,-.128),l(-.319,-.213),l(-.256,-.021),l(-.085,-.277),l(.17,-.255),l(.213,-.191),l(-.404,-.042),l(-.319,.085),l(-.383,0),l(-.319,-.085),l(-.128,.149),l(-.17,-.255),l(-.149,-.298),l(0,-.34),l(-.042,-.298),l(.17,-.213),l(.106,-.319),l(.043,-.255),l(.105,-.277),l(.086,-.234),l(.213,.34),l(.063,.128),l(.17,.17),l(.405,-.085),l(.383,.128),l(.106,-.149),l(-.021,-.149),l(.106,0),l(.148,.021),l(.064,.319),l(.106,.191),l(.298,-.021),l(.298,-.063),l(.256,-.106),l(.233,.085),l(.192,.064),l(.085,-.128),l(-.149,-.191),l(-.042,-.213),l(.191,-.042),l(.106,.149),l(.233,.085),l(.256,-.085),l(.213,-.064),l(.021,-.234),l(-.171,-.341),l(-.34,-.234),l(-.532,-.319),l(-.426,-.213),l(-.063,-.319),l(-.043,-.34),l(-.213,-.17),l(0,-.213),l(0,-.213),l(-.085,-.127),l(-.554,-.064),l(-.617,.085),l(-.426,.021),l(-.446,.127),l(-.192,.277),l(-.085,.298),l(.128,.192),l(-.063,.276),l(-.086,.405),l(.064,.234),l(.021,.298),l(-.256,-.553),l(-.361,-.319),l(.042,-.17),l(-.063,-.191),l(-.274,-.143),l(.529,-.453),l(.937,-.532),l(1.277,-.298),l(.979,-.085),l(.512,.234),l(.681,.383),l(.617,.383),l(.256,.511),l(.638,.703),l(.447,.255),l(.489,-.043),l(.341,-.106),l(.158,.014),l(1.03,.063),l(1.383,-.032),l(.126,-.314),l(-.314,-.409),l(.062,-.628),l(.503,-.409),l(.503,-.251),l(.629,0),l(.283,-.126),l(.22,-.346),l(.126,-.126),l(.283,0),l(.597,.283),l(-.188,-.377),l(-.251,-.251),l(.565,-.157),l(.188,-.063),l(.472,.095),l(.629,.377),l(.346,.032),l(.22,.314),l(.692,.095),l(.534,.094),l(.251,.22),l(.032,.22),l(0,.22),l(.439,.283),l(-.188,.157),l(-.031,.188),l(.188,.22),l(-.157,.188),l(-.094,.22),l(.691,.314),l(.314,.157),l(.503,-.094),l(.439,-.032),l(.535,.126),l(.439,-.063),l(.188,-.157),l(.881,.251),l(.22,.377),l(.126,.566),l(.408,.597),l(.283,.188),l(.188,.44),l(0,.283),l(1.384,.975),l(1.194,.597),l(.377,.44),l(1.006,.503),l(.314,-.063),l(.943,.597),l(.565,.22),l(1.132,.597),l(.378,.251),l(.471,-.063),l(.566,.189),l(.534,.283),l(.503,.094),l(-.062,.22),l(-.157,.251),l(.062,.503),l(-.091,.726),l(-1.454,-.244),l(-.565,-.294),l(-.445,.356),l(-.417,.2),l(-1.135,.205),l(-.432,.809),l(-.203,.991),l(-.103,.128),l(-.508,.243),l(-1.985,.689),l(-.568,.159),l(-.119,.199),l(-.001,.466),l(-.22,.199),l(-.636,.3),l(-.534,.031),l(-.573,-.082),l(-.999,-.348),l(-.937,-.193),l(-.193,-.112), +N(445.294,112.196),l(-.07,-.115),l(-.138,-.469),l(-.5,-.452),l(-.966,-.541),l(.024,-.141),l(.23,.062),l(.023,-.237),l(-.345,-.414),l(.418,-.616),l(-.182,-.22),l(.188,-.563),l(-.251,-.282),l(.182,-.396),l(.268,-.079),l(-.027,-.45),l(-.331,-.081),l(-.2,-.107),l(.002,-.342),l(-.133,-.427),l(.279,-.515),l(.273,-.273),l(.727,.11),l(.361,.022),l(.058,.004),l(.382,.369),l(.733,.866),l(.018,.109),l(.035,.218),l(-.132,.429),l(.074,.641),l(.298,.668),l(.722,.608),l(-.09,.029),l(-.449,.842),l(-.402,.386),l(-.496,.472),l(-.583,.884), +N(451.512,108.463),l(-.507,.16),l(-.532,.245),l(-.622,-.054),l(-.361,-.041),l(-.365,.159),l(-.395,.429),l(-.606,.146),l(-.809,.076),l(-.722,-.608),l(-.298,-.668),l(-.074,-.641),l(.132,-.429),l(-.035,-.218),l(.14,.049),l(.188,0),l(.072,-.087),l(.029,-.072),l(-.029,-.13),l(.058,-.167),l(.088,-.058),l(.225,-.058),l(.246,-.058),l(.116,-.058),l(.08,-.065),l(.087,.073),l(.131,.058),l(.094,.109),l(.116,0),l(.029,-.058),l(-.059,-.072),l(.109,-.058),l(.151,-.102),l(.152,-.087),l(.175,.043),l(.064,-.007),l(.196,.007),l(.152,.015),l(.087,-.08),l(.131,-.116),l(.064,.021),l(.102,.043),l(.088,-.021),l(.087,-.043),l(.102,.051),l(.058,-.015),l(.116,-.022),l(.145,-.021),l(.16,-.022),l(.072,-.029),l(.058,.017),l(-.007,.106),l(.134,.213),l(.666,.296),l(.358,.383),l(.225,.469),l(-.006,.499),l(-.104,.3),l(.047,.199), +N(383.93,117.402),l(-.249,.101),l(-.517,.291),l(-.439,.052),l(-.548,-.178),l(-.58,0),l(-.28,-.073),l(-.719,.292),l(-.058,-.177),l(.389,-1.012),l(-.021,-.856),l(-.182,-.115),l(.244,-.542),l(-.054,-.397),l(.13,-.114),l(-.144,-.141),l(-.375,.085),l(-.476,.097),l(-.108,-.449),l(.48,-.052),l(.283,-.22),l(-.042,-.17),l(-.178,-.226),l(-.3,.417),l(-.413,.136),l(-.357,-.042),l(-.059,-.188),l(.198,-.397),l(.138,-.616),l(-.039,-.303),l(.258,-.114),l(.403,-.503),l(.45,-1.098),l(-.12,-.115),l(.612,-1.783),l(-.35,-.924),l(-.007,-.42),l(-.146,-.378),l(.255,-.271),l(.891,-.251),l(.55,-.188),l(.531,.439),l(1.822,.047),l(.531,-.26),l(.335,.055),l(.272,.227),l(.15,.242),l(.842,.495),l(.062,.242),l(-.288,.216),l(-1.234,.506),l(-.084,.072),l(-.051,.442),l(.072,.456),l(-.132,.983),l(.057,.938),l(-.043,.199),l(-.458,.229),l(-.482,.045),l(-.288,.129),l(.488,.494),l(.455,.551),l(.163,.198),l(-.347,.371),l(-.506,.655),l(-.17,.455),l(.812,.123),l(.408,.31),l(-.884,.643),l(-.242,.37),l(-.304,.951),l(-.008,.018), +N(500.121,117.572),l(-.407,-.016),l(-.433,.388),l(-.164,.126),l(-.318,-.105),l(-.102,-.269),l(.03,-.259),l(-.274,-.151),l(-.366,-.082),l(-.244,.234),l(-.343,-.023),l(-.811,-.153),l(-.364,.032),l(-.304,-.16),l(-.437,.094),l(-.266,.143),l(-.23,.043),l(-.064,-.245),l(-.207,-.023),l(-.24,.292),l(-.693,.304),l(-1.185,.224),l(-.711,-.039),l(-.747,-.123),l(-.439,.073),l(-1.498,.673),l(-.567,.13),l(-1.104,.176),l(-.556,-.153),l(-1.532,-.444),l(-.278,.03),l(-.929,.373),l(-.746,.075),l(-.575,-.025),l(-.777,-.166),l(-.222,.001),l(-.142,-.035),l(-.055,.319),l(.102,.452),l(.243,.423),l(-.627,.127),l(-.156,.374),l(-.2,.169),l(-.171,-.041),l(-.114,.127),l(-.39,-.125),l(-.311,.001),l(-.245,-.459),l(-.119,-.093),l(.097,-.175),l(.242,-.197),l(.617,-.403),l(.021,-.175),l(-.049,-.134),l(-.279,-.28),l(-.146,-.053),l(-.487,.368),l(-.23,.041),l(-.137,.064),l(.092,.041),l(-.118,.216),l(-.172,.023),l(-.063,-.047),l(-.076,.088),l(-.297,.058),l(-.332,-.222),l(-.447,-.198),l(-.461,-.157),l(-.395,.046),l(-.849,.548),l(-.337,.286),l(.006,.204),l(-.141,.046),l(-.122,.07),l(-.005,.082),l(-.179,-.169),l(-.604,.206),l(-.689,.185),l(-.594,-.013),l(-.587,-.07),l(-.678,-.267),l(-.963,-.819),l(-1.181,-.479),l(-1.034,-.182),l(-.692,.072),l(-.119,.255),l(-.097,.609),l(-.053,.411),l(-.173,.156),l(-.256,0),l(-.253,-.155),l(-1.12,.243),l(-.423,-.027),l(-.386,-.183),l(-.657,-1.159),l(-.42,.354),l(-.764,-.451),l(-.451,.057),l(-.562,.412),l(-.227,-.382),l(.066,-.127),l(.242,-.17),l(-.116,-.17),l(-.989,-.012),l(-.545,-.013),l(-.088,-.269),l(.571,-.199),l(-.074,-.241),l(-.284,-.198),l(-.454,-.07),l(-.084,-.297),l(.041,-.34),l(.087,-.284),l(-.089,-.255),l(-.396,-.126),l(-.627,-.353),l(-.371,.086),l(-.265,-.084),l(-.004,-.255),l(.171,-.501),l(.131,.059),l(.478,.311),l(.567,-.271),l(-.396,-.283),l(.021,-.124),l(-.296,-.128),l(.03,-.128),l(.571,-.159),l(.152,-.113),l(-.068,-.142),l(-.149,-.088),l(-.337,-.035),l(.01,-.187),l(.18,-.07),l(-.163,-.164),l(-.198,-.117),l(-.009,-.152),l(-.227,-.012),l(.263,-.181),l(.296,-.275),l(.161,-.035),l(.07,-.16),l(-.341,-.042),l(-.573,.12),l(-.905,.164),l(-.166,-.035),l(.046,-.33),l(.127,-.125),l(-.003,-.199),l(-.029,-.286),l(.13,-.264),l(.299,.012),l(.184,-.41),l(.175,-.023),l(.63,-.422),l(.514,.012),l(.133,-.129),l(.479,-.047),l(.128,.211),l(.268,.102),l(.169,.028),l(.529,.022),l(.147,-.129),l(-.067,-.129),l(-.269,-.129),l(.286,-.094),l(.324,.036),l(.117,.082),l(-.219,.223),l(.213,-.026),l(1.053,-.073),l(.619,.042),l(.379,.046),l(.279,.047),l(.155,-.176),l(-.086,-.094),l(-.468,-.035),l(-.212,-.118),l(.275,-.212),l(1.386,-.151),l(.417,-.012),l(.377,-.117),l(-.442,-.012),l(-.592,.023),l(-.215,0),l(-.068,-.146),l(-.611,-.382),l(.325,-.528),l(.926,.14),l(1.244,.048),l(.264,-.117),l(1.086,.321),l(1.051,-.031),l(.414,-.243),l(-.041,-.27),l(.624,-.244),l(.455,-.214),l(1.218,-.573),l(.598,-.215),l(1.039,-.23),l(.889,-.073),l(.758,.07),l(.905,.126),l(.798,.041),l(.753,-.372),l(.216,.527),l(.416,.298),l(.278,.099),l(.592,.013),l(.622,-.144),l(.453,.74),l(.492,.255),l(.574,-.172),l(.391,.056),l(.968,.582),l(1.265,.04),l(1.094,.197),l(.749,-.001),l(1.084,-.272),l(.514,-.044),l(.651,.141),l(.764,.098),l(.787,-.016),l(.554,-.144),l(1.518,-.573),l(.424,-.335),l(1.212,.082),l(.491,.068),l(.226,-.072),l(.761,-.36),l(.41,.041),l(1.326,1.018),l(.031,.028),l(.795,.722),l(.026,.199),l(-.421,.813),l(.033,.412),l(.284,.211),l(1.413,.12),l(.492,.451),l(-.072,.211),l(-.409,-.023),l(-.231,.141),l(-.009,.433),l(-.584,.267),l(-.039,.27),l(.264,.67),l(-.122,.375),l(.224,.492),l(.09,.117),l(.106,-.105),l(.288,.203),l(.039,.207),l(-.229,.281),l(-.287,.535),l(-.06,.128),l(.213,.14),l(.424,.111),l(-.145,.245),l(.099,.421),l(.42,.374),l(.275,.035),l(.023,.308),M(462.617,106.804),l(.241,.211),l(-.019,.287),l(.115,.285),l(.077,.071),l(.593,.355),l(.819,.241),l(.605,.155),l(.152,.121),L(464.943,109),l(-.304,.166),l(-.515,-.072),l(-.94,-.246),l(-.326,.07),l(-.209,.152),l(-1.019,-.012),l(-.357,.384),l(-.109,.273),l(-.833,.316),l(-.612,.282),l(-.222,.258),l(-.307,.152),l(-.268,.293),l(-.255,.082),l(.164,-.258),l(.019,-.141),l(-.062,-.176),l(.584,-.293),l(.22,-.141),l(-.226,-.191),l(-.082,.015),l(-.653,-.056),l(-.229,-.148),l(.326,-.546),l(.387,-.558),l(.678,-.631),l(-.127,-.227),l(-.427,-.197),l(-.105,0),l(.498,-.445),l(.629,-.374),l(.497,-.045),l(.527,.111),l(1.333,.005), +N(509.077,114.955),l(-.72,-.317),l(-.268,.016),l(-.356,-.433),l(-.374,-.105),l(-.13,-.363),l(.532,-.27),l(.095,-.222),l(-.43,-.176),l(-.027,-.188),l(.63,-.129),l(.094,-.155),l(-.061,-.113),l(-.487,-.21),l(-.351,-.281),l(-.306,-.166),l(-.456,.234),l(-1.058,.492),l(-.374,.445),l(-.642,.188),l(-.254,.255),l(-.014,-.027),l(.094,-.118),l(-.094,-.213),l(-.189,-.071),l(.26,-.095),l(.166,-.047),l(-.261,-.189),l(-.236,-.236),l(.236,-.118),l(.095,-.189),l(-.283,-.047),l(-.354,-.024),l(-.284,-.118),l(-.213,-.212),l(-.236,-.024),l(-.26,-.354),l(-.283,-.142),l(-.048,-.094),l(.166,0),l(.378,0),l(.165,-.236),l(0,-.236),l(-.213,-.024),l(-.188,-.142),l(-.544,-.331),l(-.283,-.354),l(.047,-.284),l(.402,-.142),l(-.119,-.236),l(-.212,-.166),l(-.426,-.071),l(-.284,-.095),l(.071,-.094),l(.071,-.118),l(-.284,-.095),l(-.087,-.212),l(.418,-.308),l(.236,0),l(.473,.024),l(.331,.189),l(.189,.213),l(.638,.189),l(.284,-.047),l(.188,.023),l(.143,.071),l(.26,.189),l(.236,-.047),l(.236,-.095),l(.095,-.331),l(-.118,-.213),l(-.614,-.166),l(-.213,-.307),l(-.143,-.26),l(.095,-.071),l(.143,-.142),l(.268,-.189),l(.229,-.023),l(.023,.166),l(.213,-.047),l(.189,0),l(.142,.189),l(.473,.284),l(.095,.118),l(.118,0),l(.283,.284),l(0,.308),l(.591,.094),l(.449,.142),l(.379,-.047),l(.165,-.213),l(.308,-.331),l(.283,-.094),l(.496,-.284),l(.292,-.449),l(.465,.331),l(.236,.378),l(.26,.189),l(.284,.307),l(.095,.52),l(.142,.236),l(.283,.26),l(.284,.165),l(0,.166),l(.449,.236),l(.473,-.047),l(.378,.071),l(.284,.166),l(.236,.189),l(.095,.189),l(0,.142),l(-.355,-.142),l(-.401,-.047),l(-.213,0),l(-.26,.047),l(-.142,.118),l(-.402,.071),l(-.213,.142),l(-.047,.189),l(-.023,.473),l(-.118,.26),l(-.095,.236),l(-.095,.378),l(.213,.236),l(-.023,.189),l(-.237,-.071),l(-.094,.095),l(-.071,.331),l(-.071,.26),l(-.118,-.047),l(-.094,-.236),l(-.143,-.095),l(-.165,.095),l(-.047,.307),l(.07,.166),l(-.118,.118),l(-.118,.095),l(.095,.26),l(-.363,.91),M(499.844,111.738),l(.709,.061),l(.142,-.047),l(.26,-.071),l(.236,.236),l(.071,.166),l(.378,.142),l(.213,.071),l(.308,-.118),l(.52,0),l(-.071,.213),l(.024,.236),l(.118,.023),l(.331,.166),l(-.071,.236),l(.421,.763),l(-.009,.001),l(-.253,-.133),l(-.416,.038),l(-.512,-.025),l(-.421,-.125),l(-.335,-.211),l(-.294,-.402),l(-.551,-.223),l(-.281,-.417),l(-.265,-.381),l(-.252,-.197), +N(455.452,122.442),l(.049,-.209),l(-.057,-.128),l(-.812,-.256),l(-.691,-.006),l(-.506,-.116),l(-.484,.017),l(-.121,-.046),l(-.103,-.093),l(.139,-.56),l(.315,-.005),l(-.005,-.088),l(-.009,-.122),l(.069,-.07),l(.083,.157),l(.021,.146),l(.303,.021),l(.172,.055),l(.184,-.076),l(-.014,-.082),l(.108,-.029),l(.157,.105),l(-.037,.093),l(-.099,.006),l(-.04,.053),l(.088,.023),l(.144,.035),l(.094,.046),l(.021,.128),l(.353,.041),l(.846,-.122),l(.509,.016),l(.035,.13),l(.192,.035),l(.608,.064),l(.307,.051),l(.358,-.121),l(.09,.05),l(-.101,.312),l(.163,.11),l(.105,0),l(.325,-.169),l(.286,-.058),l(.078,.052),l(.154,-.07),l(.232,-.146),l(-.083,.187),l(.015,.186),l(-.183,.268),l(-.582,-.046),l(-.349,.081),l(-.335,-.017),l(-1.994,.169),M(445.294,112.196),l(.583,-.884),l(.496,-.472),l(.402,-.386),l(.449,-.842),l(.09,-.029),l(.809,-.076),l(.606,-.146),l(.395,-.429),l(.365,-.159),l(.361,.041),l(.622,.054),l(.532,-.245),l(.507,-.16),l(.09,-.029),l(1.855,-.195),l(.799,-.261),l(.584,-.06),l(1.473,.505),l(.619,.21),l(.388,-.031),l(1.117,-.277),l(.086,-.257),l(-.097,-.327),l(.344,-.216),l(.363,.026),l(.105,0),l(.427,.197),l(.127,.227),l(-.678,.631),l(-.387,.558),l(-.326,.546),l(-.062,-.407),l(-.794,-.056),l(-.743,-.041),l(-.566,-.125),l(-.062,-.144),l(-.459,.186),l(-.248,.123),l(-.403,.012),l(-.031,-.247),l(-.335,.029),l(-.301,.314),l(-.431,.186),l(-.31,.03),l(-.306,-.159),l(-.252,.07),l(-.004,.133),l(.169,.185),l(.169,.34),l(.308,.059),l(.826,.609),l(-.166,.07),l(-.369,-.258),l(-.015,-.105),l(-.276,-.082),l(-.331,-.105),l(-.116,.099),l(-.211,.007),l(.069,.129),l(-.016,.129),l(.338,.164),l(.145,-.012),l(.114,.234),l(-.03,.129),l(-.245,.023),l(-.445,-.457),l(-.341,-.141),l(-.207,-.059),l(-.128,-.012),l(.003,.094),l(-.075,.035),l(.138,.164),l(.102,.105),l(.154,.141),l(.193,.059),l(.153,.035),l(.103,.094),l(-.093,.058),l(-.494,-.046),l(-.253,-.035),l(.035,-.176),l(-.137,-.293),l(-.164,-.188),l(-.401,-.108),l(-.472,-.373),l(.258,-.118),l(.025,-.136),l(-.053,-.122),l(-.182,-.035),l(-.153,.199),l(-.465,.176),l(.245,.224),l(-.25,.371),l(-.05,.249),l(.13,.121),l(.065,.172),l(.311,.338),l(.133,.036),l(.131,.479),l(.579,.421),l(.359,.467),l(-.172,.14),l(-.237,.082),l(.106,-.187),l(-.121,-.187),l(-.142,-.128),l(-.139,-.035),l(-.151,-.047),l(-.29,.175),l(.102,.188),l(.153,.081),l(.08,.316),l(-.193,.187),l(-.652,.141),l(.248,.046),l(.27,.14),l(.391,.058),l(.188,.222),l(.257,-.012),l(.155,.012),l(.048,.126),l(.367,.269),l(.306,.014),l(.138,.292),l(.282,.012),l(.27,0),l(.348,.303),l(.015,.128),l(-.193,.082),l(.238,.782),l(-.153,.175),l(-.185,0),l(-.226,-.385),l(-.222,-.047),l(-.207,-.278),l(-.101,-.142),l(-.17,0),l(-.496,.14),l(-.479,.105),l(-.184,.128),l(.315,.093),l(.013,.188),l(.007,.291),l(.229,.117),l(.153,-.026),l(.225,-.079),l(-.021,.198),l(.235,.175),l(-.519,.093),l(.002,.117),l(-.169,.062),l(-.309,-.086),l(.121,-.21),l(-.186,-.086),l(-.508,-.056),l(-.158,-.092),l(-.008,.206),l(.194,.453),l(.193,.17),l(-.045,.163),l(.209,.204),l(.213,.96),l(-.688,-.31),l(-.331,.071),l(-.298,.439),l(-.442,-.735),l(-.46,-.367),l(-.452,.44),l(-.428,-.353),l(-.127,-.297),l(.212,-.425),l(-.028,-.241),l(-.215,-.269),l(-.491,-.424),l(-.167,-.226),l(.017,-.17),l(.471,-.61),l(.609,.098),l(.425,-.298),l(.202,.042),l(1.668,.663),l(.337,-.1),l(.483,-.355),l(-.266,-.049),l(-.27,-.056),l(-1.204,-.493),l(-1.127,-.083),l(-.367,.058),l(-.66,.058),l(-.427,.143),l(-.89,-1.118),l(.269,-.1),l(.253,.056),l(.218,-.114),l(.122,-.185),l(-.339,-.24),l(-.235,.114),l(-.496,-.042),l(-1.035,-.721),l(-.199,-.325), +N(504.136,113.458),l(-.327,.328),l(-.377,.03),l(-.421,-.763),l(.071,-.236),l(-.331,-.166),l(-.118,-.023),l(-.024,-.236),l(.071,-.213),l(-.52,0),l(-.308,.118),l(-.213,-.071),l(-.378,-.142),l(-.071,-.166),l(-.236,-.236),l(-.26,.071),l(-.142,.047),l(-.709,-.061),l(-.492,-.451),l(-1.413,-.12),l(-.284,-.211),l(-.033,-.412),l(.421,-.813),l(-.026,-.199),l(-.795,-.722),l(.377,-.108),l(.307,.024),l(.308,-.095),l(.426,-.023),l(.401,-.118),l(.592,.047),l(.591,-.095),l(.378,-.047),l(.291,-.094),l(.087,.212),l(.284,.095),l(-.071,.118),l(-.071,.094),l(.284,.095),l(.426,.071),l(.212,.166),l(.119,.236),l(-.402,.142),l(-.047,.284),l(.283,.354),l(.544,.331),l(.188,.142),l(.213,.024),l(0,.236),l(-.165,.236),l(-.378,0),l(-.166,0),l(.048,.094),l(.283,.142),l(.26,.354),l(.236,.024),l(.213,.212),l(.284,.118),l(.354,.024),l(.283,.047),l(-.095,.189),l(-.236,.118),l(.236,.236),l(.261,.189),l(-.166,.047),l(-.26,.095),l(.189,.071),l(.094,.213),l(-.094,.118),l(.014,.027), +N(566.651,117.4),l(-.565,-.153),l(-.496,-.054),l(-.264,-.151),l(-.564,.227),l(-.974,.147),l(-.137,-.059),l(.129,-.176),l(-.198,-.077),l(-.678,.03),l(-.739,.315),l(-.592,.486),l(-.589,.064),l(-.745,.495),l(-.351,.03),l(-.368,-.026),l(-.128,-.084),l(-.164,-.409),l(-.199,-.521),l(.185,-.444),l(.099,-.775),l(.029,-.255),l(-.17,-.187),l(-.484,.093),l(.156,-.597),l(-.576,-.45),l(-.153,-.056),l(-.384,.016),l(-.286,.162),l(-.134,.363),l(-.435,.428),l(-.049,.425),l(.006,.255),l(-.208,.228),l(-.442,.158),l(-.133,-.013),l(-.587,-.152),l(-.292,.058),l(-.073,.185),l(.007,.311),l(-.3,.313),l(-.21,.128),l(-.381,.016),l(-.63,-.237),l(-.325,.001),l(-.581,.286),l(-.58,.343),l(-.485,.144),l(-.245,-.041),l(-.129,-.141),l(-.04,-.055),l(.375,-.843),l(-.063,-.377),l(.377,-.377),l(.283,-.503),l(.503,-.346),l(.157,-.22),l(-.126,-.283),l(-.471,-.314),l(-.126,-.409),l(.031,-.472),l(.126,-.22),l(-.126,-.22),l(-.346,0),l(-.44,-.032),l(-.157,-.157),l(-.346,-.188),l(-.251,-.283),l(.125,-.471),l(.472,-.283),l(.629,.126),l(1.069,.094),l(.282,-.188),l(.063,-.409),l(.251,-.157),l(.188,0),l(.032,-.346),l(.188,-.063),l(.251,-.063),l(-.126,-.094),l(-.534,.031),l(-.251,-.125),l(.503,-.094),l(.565,-.095),l(.472,.095),l(.062,-.126),l(.032,-.346),l(-.189,-.314),l(.283,-.314),l(-.031,-.22),l(.346,0),l(.22,.157),l(.252,.22),l(.22,-.157),l(.692,-.188),l(.471,-.346),l(.221,-.251),l(.439,.377),l(.252,.251),l(-.188,.22),l(-.409,.346),l(-.251,.126),l(.126,.188),l(.251,.063),l(.188,.283),l(.409,-.031),l(.345,.005),l(-.302,.147),l(-.441,.196),l(-.024,.246),l(-.196,0),l(-.099,-.172),l(-.516,-.196),l(-.515,-.147),l(-.981,.196),l(-.123,0),l(-.098,.27),l(.049,.196),l(-.196,.074),l(-.098,-.221),l(-.196,.196),l(-.099,.245),l(.099,.27),l(.049,.147),l(.122,.098),l(.589,-.024),l(.564,0),l(.688,-.024),l(.196,.073),l(.49,-.147),l(.368,.098),l(.147,.123),l(.073,.196),l(.393,.074),l(.295,-.049),l(-.024,-.221),l(.343,-.049),l(.442,-.123),l(.221,.024),l(.049,.147),l(.319,.123),l(.122,-.024),l(.049,.172),l(.074,.221),l(.318,-.172),l(.368,-.024),l(.172,.319),l(.196,0),l(.172,-.147),l(.834,-.221),l(.663,.073),l(.539,0),l(.344,-.171),l(.344,-.098),l(.196,.073),l(-.011,.069),l(.023,1.031),l(-.207,.223),l(.077,.305),l(.325,.394),l(.463,-.045),l(.229,-.162),l(.22,.06),l(.692,.039),l(.273,.154),l(.295,.494),l(-.009,.284),l(.028,.246),l(.152,.012),l(.049,.123),l(-.126,.428),l(.245,.237),l(-.152,.36),l(.2,.163),l(-.181,.185),l(-.08,.249),l(-.354,.136), +N(500.121,117.572),l(-.023,-.308),l(-.275,-.035),l(-.42,-.374),l(-.099,-.421),l(.145,-.245),l(-.424,-.111),l(-.213,-.14),l(.06,-.128),l(.287,-.535),l(.229,-.281),l(-.039,-.207),l(-.288,-.203),l(-.106,.105),l(-.09,-.117),l(-.224,-.492),l(.122,-.375),l(-.264,-.67),l(.039,-.27),l(.584,-.267),l(.009,-.433),l(.231,-.141),l(.409,.023),l(.072,-.211),l(.252,.197),l(.265,.381),l(.281,.417),l(.551,.223),l(.294,.402),l(.335,.211),l(.421,.125),l(.512,.025),l(.416,-.038),l(.253,.133),l(.009,-.001),l(.377,-.03),l(.327,-.328),l(.254,-.255),l(.642,-.188),l(.374,-.445),l(1.058,-.492),l(.456,-.234),l(.306,.166),l(.351,.281),l(.487,.21),l(.061,.113),l(-.094,.155),l(-.63,.129),l(.027,.188),l(.43,.176),l(-.095,.222),l(-.532,.27),l(.13,.363),l(.374,.105),l(.356,.433),l(.268,-.016),l(.72,.317),l(.015,.007),l(-.05,.707),l(-.143,.581),l(.205,.48),l(.494,.252),l(.925,.235),l(.827,.052),l(.424,.097),l(.162,.282),l(.312,.451),l(.687,.463),l(1.902,.513),l(.841,.052),l(.438,-.059),l(1.354,-.262),l(1.192,-.148),l(1.469,-.079),l(.41,-.229),l(.185,-.354),l(-.131,-.905),l(.015,0),l(.441,.025),l(.562,-.13),l(.466,-.3),l(.621,-.654),l(.476,-.328),l(.413,-.144),l(.609,-.032),l(.78,.038),l(.333,-.03),l(.517,-.343),l(.343,-.129),l(.519,.054),l(1.055,.107),l(.402,.437),l(.708,.251),l(.822,.335),l(.788,.066),l(.5,.054),l(.66,.167),l(.597,.336),l(1.803,1.362),l(.655,.506),l(.696,.01),l(.787,-.075),l(.185,.211),l(.038,.848),l(.01,.565),l(.15,.692),l(.078,.028),l(-.145,.241),l(-.084,.339),l(-.246,.807),l(-.49,1.272),l(-.222,.297),l(-.596,.384),l(-.016,.141),l(.119,.663),l(.096,.098),l(.738,.235),l(.026,.183),l(-.661,.935),l(-.034,.155),l(.254,1.085),l(.167,1.283),l(.143,.775),l(.191,.21),l(.209,.041),l(1.198,.275),l(.401,.167),l(.144,.366),l(.046,.437),l(-.425,.553),l(-.853,.795),l(-.853,1.034),l(.802,1.083),l(.71,1.068),l(.353,.464),l(.695,.391),l(1.144,.388),l(.409,.224),l(.168,.38),l(.111,1.34),l(.185,.394),l(.652,.053),l(.186,.281),l(-.036,.974),l(-.188,.255),l(-.209,.072),l(-1,.077),l(-.697,.258),l(-.794,.47),l(-.285,.383),l(-.31,.792),l(-.049,.354),l(-.182,.954),l(-.502,.028),l(-1.079,-.153),l(-.236,-.197),l(-.605,-.253),l(-.403,-.056),l(-1.43,.003),l(-.783,-.041),l(-.602,.072),l(-.475,-.38),l(-.163,-.126),l(-.835,-.026),l(-.576,.001),l(-.465,.014),l(-.212,-.239),l(-.756,-.125),l(-.305,-.183),l(-.162,-.014),l(-.021,-.5),l(-.295,-.128),l(-.103,-.514),l(-.292,-.349),l(-.013,-.639),l(-.309,-.493),l(-.237,.012),l(-.035,-.181),l(-.526,-.126),l(-.807,-.013),l(-.374,.017),l(-.209,.222),l(-.329,.018),l(-.517,.075),l(-.188,.364),l(-.538,.138),l(-.383,.443),l(-.368,.283),l(-.253,.043),l(-1.292,-.689),l(-.958,-.104),l(-.562,-.359),l(-1.088,-.317),l(-.247,-.301),l(-.324,-.282),l(-.497,-.592),l(-.997,-.436),l(-.584,-.083),l(-.194,-.028),l(-.58,-.465),l(-.596,-1.058),l(-.635,-1.114),l(-.209,-.268),l(.005,-.593),l(-.767,-.761),l(-.506,-.719),l(-.921,.143),l(-.46,-.042),l(-.13,-.126),l(-.291,-.056),l(-.191,-.268),l(-.029,-.565),l(-.448,.1),l(-.166,.099),l(-.32,.678),l(-.195,.184),l(-.355,.012),l(-.014,-.12),l(-.351,-.224),l(-.686,-.546),l(.064,-.212),l(-.007,-.395),l(-.164,-.465),l(-.215,-.013),l(-.551,.003),l(-.034,-.325),l(.055,-.579),l(.197,-.622),l(.014,-.508),l(-.112,-.239),l(-.29,-.28),l(-.774,-.603),l(-.436,-.209),l(-1.242,-.925),l(-.533,-.025),l(-.321,.115),L(503,127.106),l(.033,-.819),l(-1.02,-.954),l(-.312,-.351),l(-.002,-.184),l(.133,-.875),l(.235,-.763),l(1.142,-.98),l(-.422,-.761),l(.013,-.254),l(.468,-.596),l(-1.067,-.107),l(-.761,-.208),l(-.065,-.198),l(-.563,-1.086),l(-.69,-1.397), +N(535.734,133.791),l(.853,-1.034),l(.853,-.795),l(.425,-.553),l(-.046,-.437),l(-.144,-.366),l(-.401,-.167),l(-1.198,-.275),l(-.209,-.041),l(-.191,-.21),l(-.143,-.775),l(-.167,-1.283),l(-.254,-1.085),l(.034,-.155),l(.661,-.935),l(-.026,-.183),l(-.738,-.235),l(-.096,-.098),l(-.119,-.663),l(.016,-.141),l(.596,-.384),l(.222,-.297),l(.49,-1.272),l(.246,-.807),l(.084,-.339),l(.145,-.241),l(.193,.112),l(.937,.193),l(.999,.348),l(.573,.082),l(.534,-.031),l(.636,-.3),l(.22,-.199),l(.001,-.466),l(.119,-.199),l(.568,-.159),l(1.985,-.689),l(.508,-.243),l(.103,-.128),l(.203,-.991),l(.432,-.809),l(1.135,-.205),l(.417,-.2),l(.445,-.356),l(.565,.294),l(1.454,.244),l(.096,.016),l(.646,.011),l(1.217,.05),l(.236,.126),l(.351,.48),l(.04,.055),l(.129,.141),l(.245,.041),l(.485,-.144),l(.58,-.343),l(.581,-.286),l(.325,-.001),l(.63,.237),l(.381,-.016),l(.21,-.128),l(.3,-.313),l(-.007,-.311),l(.073,-.185),l(.292,-.058),l(.587,.152),l(.133,.013),l(.442,-.158),l(.208,-.228),l(-.006,-.255),l(.049,-.425),l(.435,-.428),l(.134,-.363),l(.286,-.162),l(.384,-.016),l(.153,.056),l(.576,.45),l(-.156,.597),l(.484,-.093),l(.17,.187),l(-.029,.255),l(-.099,.775),l(-.185,.444),l(.199,.521),l(.164,.409),l(.128,.084),l(.368,.026),l(.351,-.03),l(.745,-.495),l(.589,-.064),l(.592,-.486),l(.739,-.315),l(.678,-.03),l(.198,.077),l(-.129,.176),l(.137,.059),l(.974,-.147),l(.564,-.227),l(.264,.151),l(.496,.054),l(.565,.153),l(-.192,.145),l(-.574,-.059),l(.01,.269),l(.236,.012),l(.048,.088),l(-.148,.142),l(-.358,.004),l(-.455,.297),l(-.332,-.005),l(-.338,.179),l(-.647,-.144),l(-1.345,.012),l(-1.148,.152),l(-.53,.292),l(-.272,.19),l(-.559,.395),l(-.246,-.023),l(-.258,.214),l(-.464,.413),l(.01,.32),l(.411,.271),l(.01,.336),l(.232,.171),l(-.119,.483),l(.198,.477),l(-.324,.426),l(-.524,.355),l(-.4,.341),l(-.13,.283),l(.223,.478),l(.033,.31),l(-.289,.255),l(-.513,.215),l(-.698,-.039),l(-.997,-.122),l(-.355,.129),l(.35,.336),l(.365,.407),l(.129,.281),l(.088,.437),l(-.199,.255),l(-.315,.115),l(-.513,.031),l(-.416,.115),l(-.292,.228),l(-.224,.424),l(-.288,.834),l(-.139,1.214),l(-.021,.084),l(-.34,.383),l(-.237,.086),l(-1.001,-.375),l(-.562,-.025),l(-.559,.243),l(-.362,.271),l(-.321,.693),l(-.254,.086),l(-.516,-.082),l(-.644,-.039),l(-.283,.072),l(-.597,.441),l(-.412,.369),l(-.188,.34),l(-.232,.876),l(-.099,.903),l(-.069,.184),l(-.247,.156),l(-1.066,.274),l(-1.183,.19),l(-.964,.175),l(-1.234,.12),l(-1.005,-.135),l(-.349,.002),l(-1.187,.218),l(-.742,-.024),l(-.541,-.039),l(-.854,-.235),l(-1.069,-.248),l(-.63,-.194),l(-.887,-.32), +N(486.696,126.295),l(5.257,-2.711),l(.589,-2.701),l(-.024,-.467),l(-.187,-.508),l(.009,-.255),l(.23,-.355),l(.31,-.214),l(.866,-.174),l(.457,-.371),l(.944,-.883),l(-.059,-.24),l(.23,-.043),l(.266,-.143),l(.437,-.094),l(.304,.16),l(.364,-.032),l(.811,.153),l(.343,.023),l(.244,-.234),l(.366,.082),l(.274,.151),l(-.03,.259),l(.102,.269),l(.318,.105),l(.164,-.126),l(.433,-.388),l(.407,.016),l(.69,1.397),l(.563,1.086),l(.065,.198),l(.761,.208),l(1.067,.107),l(-.468,.596),l(-.013,.254),l(.422,.761),l(-1.142,.98),l(-.235,.763),l(-.133,.875),l(.002,.184),l(.312,.351),l(1.02,.954),L(503,127.106),l(.075,.155),l(.321,-.115),l(.533,.025),l(1.242,.925),l(.436,.209),l(.774,.603),l(.29,.28),l(.112,.239),l(-.014,.508),l(-.197,.622),l(-.055,.579),l(.034,.325),l(.551,-.003),l(.215,.013),l(.164,.465),l(.007,.395),l(-.064,.212),l(.686,.546),l(.351,.224),l(.014,.12),l(-.096,.003),l(-.664,.101),l(-.408,-.056),l(-.157,.057),l(-.103,.127),l(-1.271,.044),l(-.518,.13),l(-.343,.693),l(-.463,.609),l(-.521,.568),l(-4.048,-.132),l(-1.557,-.697),l(-.812,-.277),l(-.118,-.253),l(-.047,-.818),l(.118,-.396),l(-.135,-.366),l(-.973,.048),l(-.141,-.07),l(-.399,-.633),l(-.258,-.196),l(-2.44,-1.101),l(-1.14,-.473),l(-2.034,-.934),l(-.757,-.222),l(-1.129,-.459),l(-.093,-.056),l(-.093,-.056),l(-.311,-.69),l(-.87,-1.632), +N(479.916,127.377),l(-.082,-.085),l(.047,-.122),l(-.021,-.183),l(-.201,-.128),l(-.183,-.346),l(.398,-.209),l(.041,-.099),l(.526,-.396),l(-.048,-.058),l(-.223,-.099),l(.077,-.151),l(.298,-.25),l(.599,-.006),l(-.14,-.146),l(-.035,-.046),l(.078,-.111),l(.177,-.163),l(.169,-.116),l(.299,-.239),l(-.068,-.058),l(.023,-.163),l(-.09,-.047),l(-.031,-.221),l(-.241,-.157),l(-.222,-.058),l(.204,-.204),l(-.125,-.052),l(-.053,-.116),l(-.12,.058),l(-.335,.052),l(-.388,-.023),l(-.225,-.564),l(.129,-.593),l(.072,-.064),l(-.1,-.507),l(-.42,-.326),l(.126,-.093),l(.036,-.152),l(.117,-.128),l(-.093,-.222),l(.107,-.012),l(.259,-.32),l(-.061,-.112),l(.311,-.001),l(.39,.125),l(.114,-.127),l(.171,.041),l(.2,-.169),l(.156,-.374),l(.627,-.127),l(-.243,-.423),l(-.102,-.452),l(.055,-.319),l(.142,.035),l(.222,-.001),l(.777,.166),l(.575,.025),l(.746,-.075),l(.929,-.373),l(.278,-.03),l(1.532,.444),l(.556,.153),l(1.104,-.176),l(.567,-.13),l(1.498,-.673),l(.439,-.073),l(.747,.123),l(.711,.039),l(1.185,-.224),l(.693,-.304),l(.24,-.292),l(.207,.023),l(.064,.245),l(.059,.24),l(-.944,.883),l(-.457,.371),l(-.866,.174),l(-.31,.214),l(-.23,.355),l(-.009,.255),l(.187,.508),l(.024,.467),l(-.589,2.701),l(-5.257,2.711),l(-.161,.071),l(-2.96,1.541),l(-1.139,.656),l(-.253,.016),l(-.365,-.167),l(-1.902,-1.034), +N(426.068,126.434),l(-.093,.981),l(.064,.564),l(-.093,.269),l(-.802,.428),l(-.579,.314),l(-1.473,1.138),l(-.126,.354),l(.274,.973),l(-.147,.537),l(-.155,.227),l(-.864,.598),l(-.22,.143),l(-.564,-1.536),l(-.699,-2.242),l(-.323,-.464),l(-.363,-.252),l(-.432,-.181),l(-.484,-.831),l(-.225,-.465),l(-.363,-.28),l(-.452,-.097),l(-.336,-.774),l(-.301,-.888),l(.112,-.509),l(1,-.853),l(.414,-.355),l(.163,-.411),l(.048,-.537),l(-.052,-.594),l(-.026,-.892),l(-.012,-1.429),l(.114,-.439),l(.685,-.627),l(.012,-.184),l(.508,-.185),l(.633,-.455),l(.591,-.228),l(.703,-.016),l(.643,.183),l(.247,.212),l(.059,.241),l(.25,.538),l(.27,.084),l(.417,-.171),l(.584,-.44),l(.401,-.17),l(.034,.354),l(-.265,.567),l(-.638,.511),l(-.275,.468),l(.005,.283),l(.202,.438),l(.508,.466),l(.351,.127),l(.303,.848),l(-.094,.212),l(-.541,.764),l(-.59,.34),l(-1.017,.92),l(-.216,.339),l(.287,.451),l(.587,.55),l(.528,.295),l(.284,.056),l(.396,-.227),l(.316,.084),l(.244,.635),l(.582,.239), +N(381.402,139.704),l(-.027,-.876),l(.069,-2.006),l(.037,-.382),l(.686,-.314),l(1.512,-.998),l(.963,-.542),l(1.265,.078),l(.397,-.059),l(.181,-.693),l(.864,-.033),l(.777,-.174),l(.527,-.229),l(.524,-.356),l(.484,-.652),l(1.109,-.332),l(1.52,-.701),l(.129,-.227),l(-.296,-.62),l(-.025,-.396),l(.079,-.227),l(.265,-.114),l(1.186,-.12),l(.381,-.186),l(.309,-.553),l(1.022,.022),l(.67,-.018),l(1.826,.004),l(.34,-1.033),l(-.07,-.211),l(-.507,-.322),L(397,126.646),l(-.158,-.465),l(.016,-1.271),l(.022,-.833),l(-.165,-.889),l(-.189,-.211),l(-.563,-.279),l(-.259,-.508),l(.351,0),l(.66,-.143),l(.541,-.256),l(.369,-.566),l(.405,-.312),l(.509,-.086),l(.407,-.157),l(.679,-.27),l(.324,.226),l(.176,.017),l(.249,.024),l(.238,-.142),l(.407,-.51),l(.613,-.426),l(.682,-.355),l(.614,-.171),l(1.16,-.116),l(1.587,-.06),l(.513,-.072),l(.634,-.312),l(.578,.211),l(.564,-.072),l(.585,-.313),l(.343,-.1),l(.939,.012),l(.513,-.015),l(.307,.056),l(.221,.042),l(.322,.113),l(.816,.168),l(.529,-.015),l(.772,-.171),l(.705,-.2),l(.612,-.554),l(.994,.508),l(.339,.099),l(.312,-.143),l(.314,-.241),l(.228,-.156),l(.528,.042),l(.388,.197),l(.162,.269),l(.269,.126),l(.516,-.086),l(1.093,-.158),l(-.012,.184),l(-.685,.627),l(-.114,.439),l(.012,1.429),l(.026,.892),l(.052,.594),l(-.048,.537),l(-.163,.411),l(-.414,.355),l(-1,.853),l(-.112,.509),l(.301,.888),l(.336,.774),l(.452,.097),l(.363,.28),l(.225,.465),l(.484,.831),l(.432,.181),l(.363,.252),l(.323,.464),l(.699,2.242),l(.564,1.536),l(-.204,.156),l(-.241,.383),l(.88,1.605),l(.147,.833),l(.052,.691),l(-.1,.862),l(.101,.748),l(-.16,.622),l(-.158,.495),l(.457,1.156),l(-.061,.664),l(-.086,.17),l(-.666,.47),l(-.249,.128),l(-.152,.283),l(1.272,1.702),l(.249,.917),l(.562,.873),l(.244,.154),l(.544,-.201),l(.702,.165),l(1.028,.347),l(.178,.168),l(.86,1.506),l(.098,.07),l(-.265,.186),l(-1.632,.843),l(-4.012,2.241),l(-1.607,.956),l(-2.308,1.454),l(-.834,.655),l(-3.084,2.617),l(-1.82,.364),l(-1.672,.321),l(-2.176,.408),l(-.146,-.564),l(.161,-.679),l(-.099,-.522),l(-.277,-.352),l(-.309,-.111),l(-.748,-.024),l(-.375,-.167),l(-.588,-.562),l(-.47,.314),l(-.229,-.027),l(-1.111,-1.039),l(-.393,-.28),l(-.082,-.183),l(.096,-.396),l(-.181,-.253),l(-2.472,-1.469),l(-.397,-.253),l(-1.292,-.824),l(-1.924,-1.26),l(-3.283,-2.241),l(-.811,-.575),l(-2.054,-1.344),l(-.895,-.531),l(-.1,-.084),l(-1.414,-.91),l(-4.12,-2.42),l(-2.829,-1.509), +N(395.704,122.189),l(.259,.508),l(.563,.279),l(.189,.211),l(.165,.889),l(-.022,.833),l(-.016,1.271),l(.158,.465),l(.598,.788),l(.507,.322),l(.07,.211),l(-.34,1.033),l(-1.826,-.004),l(-.67,.018),l(-1.022,-.022),l(-.309,.553),l(-.381,.186),l(-1.186,.12),l(-.265,.114),l(-.079,.227),l(.025,.396),l(.296,.62),l(-.129,.227),l(-1.52,.701),l(-1.109,.332),l(-.484,.652),l(-.524,.356),l(-.527,.229),l(-.777,.174),l(-.864,.033),l(-.181,.693),l(-.397,.059),l(-1.265,-.078),l(-.963,.542),l(-1.512,.998),l(-.686,.314),l(-.037,.382),l(-.069,2.006),l(-1.42,.008),l(-1.718,-.004),l(-2.677,.001),l(-2.511,0),l(-1.635,.04),l(.141,-.28),l(.431,-.411),l(.427,-.085),l(1.296,-.285),l(1.143,-.455),l(.453,-.312),l(1.147,-.85),l(1.149,-.878),l(1.043,-1.104),l(.46,-.693),l(.133,-.509),l(-.05,-.494),l(-.427,-.776),l(-.09,-.678),l(.099,-.508),l(.396,-.636),l(.706,-.863),l(.211,-.65),l(-.063,-.367),l(.071,-.353),l(1.285,-1.203),l(.724,-.481),l(.916,-.327),l(1.266,-.469),l(.73,-.397),l(.558,-.552),l(.537,-.736),l(.466,-.905),l(.829,-1.925),l(.269,-.128),l(.54,-.171),l(.19,.127),l(.684,.848),l(.138,.099),l(1.148,.507),l(.661,-.001),l(.595,.042),l(1.304,-.074),l(.522,-.228),l(.437,-.27),l(.398,.551),l(.256,.099),l(.798,.097),l(.361,0), +N(480.248,123.437),l(.388,.023),l(.335,-.052),l(.12,-.058),l(.053,.116),l(.125,.052),l(-.204,.204),l(.222,.058),l(.241,.157),l(.031,.221),l(.09,.047),l(-.023,.163),l(.068,.058),l(-.299,.239),l(-.169,.116),l(-.177,.163),l(-.078,.111),l(.035,.046),l(.14,.146),l(-.599,.006),l(-.298,.25),l(-.077,.151),l(.223,.099),l(.048,.058),l(-.526,.396),l(-.041,.099),l(-.398,.209),l(-.07,-.023),l(-.088,.041),l(-.067,.193),l(-.009,.167),l(-.355,.07),l(-.07,-.099),l(-.151,-.022),l(-.372,.051),l(.26,-.291),l(.097,-.361),l(.169,-.227),l(.328,-.681),l(-.017,-.232),l(.181,0),l(.138,-.192),l(.072,-.32),l(.018,-.32),l(.409,-.431),l(.232,-.07),l(.116,-.174),l(-.048,-.157), +N(184.444,142.729),l(-.367,.82),l(-.518,.821),l(-.186,.763),l(-.179,1.159),l(.017,1.851),l(-.133,1.187),l(-.016,1.13),l(.564,1.737),l(.275,.805),l(.624,.945),l(.76,.903),l(.191,.452),l(.481,.521),l(.529,.974),l(.729,1.228),l(.375,.296),l(.677,.069),l(.436,-.015),l(.577,.154),l(.593,.451),l(.503,.508),l(.773,.069),l(1.016,-.242),l(1.55,-.456),l(1.396,-.3),l(.803,-.157),l(-.02,.542),l(.838,.223),l(.264,-.286),l(.293,-.199),l(-.104,-.247),l(-.393,-.175),l(1.073,-.62),l(.633,-.62),l(.086,-.827),l(.498,-.429),l(-.094,-.477),l(.092,-1.145),l(.254,-.699),l(.625,-.334),l(.164,-.043),l(.757,-.198),l(.701,-.1),l(1.088,-.229),l(1.016,-.37),l(.594,-.058),l(.499,.056),l(1.139,.181),l(.502,-.194),l(.378,.093),l(.62,.507),l(.047,.297),l(-.079,.424),l(-.298,.382),l(-.541,.496),l(-.433,.425),l(-.317,.445),l(-.02,.7),l(-.254,.297),l(-.188,.354),l(.155,.155),l(.337,-.138),l(-.101,.652),l(-.262,1.196),L(205.356,159),l(-.062,.24),l(-.34,-.534),l(-.167,-.452),l(-.072,-.155),l(-.386,.34),l(-.02,.549),l(-.437,.016),l(-.178,.447),l(-.599,.857),l(-.386,-.27),l(-.278,.095),l(.025,.329),l(-2.332,-.006),l(-1.792,-.005),l(-.04,1.24),l(-.999,.032),l(.396,.223),l(.495,.541),l(.624,.231),l(.359,.69),l(.532,.223),l(-.211,.683),l(-1.762,-.007),l(-1.06,.007),l(-1.076,1.812),l(.305,.397),l(-.207,.238),l(.054,.553),l(.044,.454),l(-.704,-.555),l(-.952,-.888),l(-.956,-.761),l(-1.069,-.859),l(-.534,-.352),l(-.053,-.071),l(-.639,-.252),l(-1.048,-.21),l(-.657,.044),l(-.817,.397),l(-1.1,.567),l(-.756,.256),l(-.931,-.069),l(-.724,-.21),l(-.48,-.197),l(-1.305,-.195),l(-.588,-.267),l(-.644,-.422),l(-.935,-.521),l(-.785,-.267),l(-1.711,-.392),l(-.963,-.365),l(-.722,-.366),l(-1.074,-.436),l(-.592,-.352),l(-1.123,-1),l(-.207,-.07),l(-.606,.058),l(-.689,-.14),l(-1.835,-.575),l(-.565,-.536),l(-.503,-.634),l(-.495,-.395),l(-1.049,-.577),l(-.619,-.267),l(-.5,-.494),l(-.742,-.987),l(-.363,-.55),l(-.038,-.113),l(.15,-.155),l(.504,-.086),l(.18,-.17),l(.047,-.184),l(-.331,-.367),l(.457,-.679),l(.041,-.381),l(-.172,-.466),l(-.744,-.959),l(.121,-.297),l(.146,-.17),l(-.07,-.268),l(-.665,-.62),l(-1.495,-1.777),l(-.546,-.493),l(-.963,-1.058),l(-.474,-.522),l(-.815,-.578),l(-.322,-.197),l(-.158,-.268),l(-.058,-.48),l(-.144,-.183),l(-.329,-.197),l(-.609,-.197),l(-.408,-.31),l(-.366,-.522),l(-.271,-.028),l(-.414,.114),l(-.238,-.155),l(-.163,-.367),l(-.005,-.325),l(.459,-.736),l(-.126,-.339),l(-.751,-.62),l(-.439,.255),l(-.375,-.621),l(-.118,-.353),l(-.359,-.211),l(-.61,-.168),l(-.319,-.296),l(-.125,-.254),l(.05,-.381),l(.084,-.269),l(-.185,-.226),l(-.561,-.21),l(-.46,-.098),l(-.46,-.253),l(-.935,-.86),l(-.478,-.706),l(-.281,-.551),l(-.646,-.832),l(-.736,-1.073),l(-.184,-.423),l(-.38,-.678),l(-.242,-.338),l(-.152,-.452),l(.042,-.509),l(.032,-.311),l(-.56,-.239),l(-.795,-.196),l(-.06,-.452),l(-.128,-.155),l(-.458,-.183),l(-.289,.326),l(-.251,.043),l(-1.43,-.647),l(-.285,1.004),l(-.045,.438),l(.033,.084),l(.265,.339),l(.264,.296),l(.028,1.046),l(.088,.509),l(.51,.677),l(.143,.169),l(.643,.267),l(.601,.536),l(.525,.663),l(.602,1.214),l(.44,.282),l(.328,.042),l(.237,.169),l(.325,1.398),l(.102,.169),l(.246,.155),l(.497,.056),l(.133,.056),l(.215,.438),l(.161,.65),l(.445,.79),l(.49,-.071),l(.223,-.142),l(.245,.452),l(.344,1.469),l(.531,1.059),l(.649,1.2),l(.069,.593),l(-.014,.522),l(.26,.353),l(.378,.154),l(.389,-.17),l(.234,-.198),l(.588,.804),l(.258,.579),l(.464,.253),l(.281,.014),l(.133,.311),l(-.196,.537),l(-.136,.127),l(-.691,.595),l(-.254,-.042),l(-.251,-.409),l(-.24,-.734),l(-.617,-.578),l(-.625,-.309),l(-.516,-.479),l(-.834,-.507),l(-1.143,-.986),l(-.416,-.451),l(-.162,-.269),l(.216,-.989),l(-.035,-.254),l(-.488,-1.002),l(-.238,-.381),l(-.327,-.282),l(-.44,-.098),l(-.5,-.31),l(-.675,-.677),l(-.305,.142),l(-.363,-.056),l(-1.262,-.746),l(-.722,-.31),l(-.896,-.973),l(-.139,-.127),l(-.246,-.254),l(.679,.15),l(.599,.013),l(.588,-.284),l(.244,-.326),l(.093,-.636),l(-.01,-.184),l(-.458,-.635),l(-.466,-.452),l(-1.1,-.888),l(-.986,-.493),l(-.402,-.338),l(-.203,-.522),l(-.272,-.649),l(-.091,-.155),l(-.447,-.126),l(-.15,-.353),l(-.026,-.594),l(-.203,-.395),l(-.623,-.734),l(-.434,-.706),l(-.003,-.254),l(.212,-.382),l(-.777,-.62),l(-.254,-.325),l(-.22,-.485),l(.34,-.017),l(2.367,-.155),l(2.381,-.084),l(.316,.31),l(.267,.154),l(1.186,.39),l(2.811,.933),l(3.516,1.112),l(.338,.055),l(1.662,.019),l(1.544,.02),l(.966,.037),l(1.867,-.011),l(.213,-.101),l(.096,-.892),l(1.858,.003),l(1.892,.046),l(.209,.112),l(.631,.662),l(.766,.632),l(.837,.519),l(.708,.491),l(.179,.226),l(.284,.678),l(.318,.847),l(.445,.549),l(1.092,.659),l(1.104,.503),l(.337,.069),l(.501,.011),l(.416,-.158),l(.283,-.37),l(.418,-.413),l(.576,-.541),l(.468,-.201),l(.643,-.018),l(.475,.082),l(.783,.321),l(.412,.252),l(.363,.366),l(.663,1.029),l(.744,1.227),l(.845,1.042),l(.657,.576),l(.268,.253),l(.078,.467),l(.332,.932),l(.336,.592),l(.375,.365),l(.921,.32),l(1.029,.56),l(.264,.069),l(.416,-.116),l(.296,-.001),l(.816,.377),l(.347,.119), +N(507.047,133.665),l(.055,.197),l(.134,.691),l(-.336,-.028),l(-.513,.513),l(.421,.194),l(.418,-.206),l(.306,.021),l(.698,1.84),l(-.644,.044),l(-1.07,-.05),l(-.185,-.239),l(-.334,-.619),l(-.408,-.054),l(-1.657,-.259),l(.521,-.568),l(.463,-.609),l(.343,-.693),l(.518,-.13),l(1.271,-.044), +N(606.155,150.953),l(.595,.152),l(.255,.14),l(.25,-.129),l(.273,-.368),l(.015,-.678),l(-.152,-.93),l(.228,-.185),l(.401,-.144),l(.191,-.354),l(-.146,-1.594),l(.133,-.283),l(.811,.32),l(.391,.11),l(.309,.013),l(.17,-.128),l(1.148,-2.25),l(0,-.324),l(-.192,-.408),l(.045,-.212),l(.938,-1.134),l(.136,-.382),l(-.057,-.761),l(.197,-.354),l(1.446,-.883),l(.719,-.512),l(.312,-.129),l(.558,.082),l(.853,.221),l(.295,-.058),l(-.184,-.718),l(.072,-.283),l(.596,-.582),l(.112,-.24),l(.018,-.508),l(.001,-.127),l(.306,-.34),l(.277,-.044),l(.504,.279),l(.397,.435),l(.243,.901),l(.217,.309),l(.287,.041),l(.504,-.031),l(.146,.14),l(.195,1.649),l(.02,.875),l(-.353,.862),l(-.429,.722),l(-.611,.525),l(-.487,.271),l(-.191,.198),l(-.617,.85),l(.075,.465),l(.163,.705),l(-.224,.58),l(0,.268),l(.216,.069),l(.312,-.086),l(.819,-.442),l(.771,-.089),l(.479,-.017),l(.156,.126),l(.277,1.762),l(.202,.324),l(.554,-.074),l(.521,.096),l(.033,.268),l(-.729,1.584),l(.117,.352),l(.228,.098),l(.507,-.003),l(.481,-.045),l(.291,.379),l(.341,.746),l(.378,.266),l(.246,.083),l(.647,-.159),l(.628,-.413),l(.111,.38),l(.153,.239),l(-.502,.355),l(-.53,.61),l(-.442,.581),l(-.582,.455),l(-.193,.185),l(-.08,.085),l(-.158,.071),l(-.645,.06),l(-.436,.172),l(-.528,.342),l(-.394,.595),l(-1.078,.316),l(-.62,.018),l(-.474,-.082),l(-.362,.411),l(-.143,.368),l(-.036,.819),l(-.114,.509),l(.064,.409),l(-.086,.24),l(-.163,.001),l(-.588,.131),l(.739,.884),l(.069,.183),l(.112,.875),l(.254,.14),l(1.091,.953),l(.148,.324),l(.646,1.041),l(.163,.338),l(-.194,.241),l(-.451,.229),l(-.128,.226),l(.231,1.185),l(-.171,.198),l(-.812,.428),l(.178,.38),l(.6,1.436),l(.54,.477),l(.606,.604),l(.203,.479),l(.088,.663),l(-.086,.636),l(.006,.254),l(.488,1.183),l(.586,1.225),l(-.077,.297),l(-1.011,1.559),l(-1.01,1.7),l(-.098,.374),l(-.359,-.181),l(-.075,-.805),l(.461,-.665),l(.174,-.495),l(.122,-.777),l(.287,-.466),l(-.512,-.027),l(-.104,-.084),l(-.004,-.282),l(.195,-.509),l(-.177,-1.524),l(-.246,-.832),l(-.639,-1.185),l(-.488,-1.312),l(-.347,-.846),l(-.179,-.875),l(-.174,-1.736),l(-.117,-.677),l(-.034,-.564),l(-.051,-.212),l(-.344,-.084),l(-.148,-.098),l(-.304,-.917),l(-.516,-.677),l(-.226,-.225),l(-.247,.029),l(-.081,.988),l(-.158,.424),l(-.43,.41),l(-.59,.284),l(-1.089,.511),l(-.359,.622),l(-.298,.297),l(-.196,.142),l(-.237,-.282),l(-.007,-.438),l(-.212,.015),l(-.338,.354),l(-.321,-.013),l(-.166,-.211),l(.147,-.495),l(-.001,-.113),l(-.621,.171),l(-.276,.127),l(-.247,.283),l(-.355,-.126),l(-.002,-.466),l(.553,-1.54),l(.162,-.791),l(.001,-.889),l(-.101,-1.059),l(-.384,-.973),l(-.431,-1.072),l(-.196,-.296),l(-.281,.537),l(-.32,-.126),l(-.526,-.366),l(.482,-.17),l(.312,-.015),l(-.149,-.479),l(-.054,-.268),l(-.684,-.775),l(-.182,-.183),l(-.19,-.028),l(-.407,.1),l(-.38,-.267),l(.086,-.438),l(-.026,-.141),l(-.209,-.112),l(-.365,.043),l(-.577,-.465),l(-.504,-.606),l(-.117,-.244),l(.252,-.341),l(.801,-.527),l(-.194,-1.607), +N(605.297,153.429),l(-.126,-.264),l(-.269,-.55),l(-.223,-1.213),l(-.611,-1.41),l(-.357,-.395),l(-.73,.354),l(-.393,0),l(-.034,-.084),l(-.242,-.211),l(-.356,-.592),l(-.124,-.042),l(-.152,.127),l(-.026,.537),l(.374,.79),l(-.006,.424),l(-.143,.169),l(-.455,.086),l(-.235,.537),l(-.261,.1),l(-.255,-.437),l(-.311,-.395),l(-.073,-.057),l(-.163,.669),l(-.28,.249),l(-.203,.043),l(-.271,-.536),l(-.495,.636),l(-.359,-.265),l(-.147,-.532),l(-.402,-1.775),l(-.325,-1.409),l(-.352,-.45),l(-.04,-.254),l(.505,-.765),l(.029,-.269),l(-.193,-.21),l(-1.042,-.431),l(-.339,-.323),l(.548,-.61),l(.4,-.299),l(.502,-.13),l(.382,-.101),l(.047,-.155),l(-.126,-.112),l(-1.224,-.938),l(-.494,-.237),l(-.083,-.155),l(.124,-.283),l(.555,-.525),l(.234,-.171),l(1.252,.303),l(.339,.266),l(.372,.266),l(.489,-.06),l(.417,.054),l(.129,.324),l(.053,.479),l(.079,.719),l(.095,.099),l(.537,.109),l(.547,.053),l(.916,-.062),l(.559,-.003),l(2.473,.198),l(.111,.098),l(.057,.127),l(-.012,.79),l(-.159,.34),l(-.938,.767),l(-.498,.13),l(-.651,.356),l(-.131,.283),l(.009,.522),l(.001,.381),l(.23,.281),l(.249,.267),l(.529,.448),l(.224,-.354),l(.395,-1.159),l(.281,-.115),l(.4,-.044),l(.064,.578),l(.627,2.479),l(.037,.466),l(.194,1.607),l(-.801,.527),l(-.252,.341), +N(627.408,186.411),l(-.086,.337),l(-.495,.35),l(-.11,.575),l(-.644,.089),l(-.05,-.478),l(-.309,-.163),l(-.279,.28),l(-.244,.394),l(-.204,-.083),l(-.118,-.239),l(.213,-.398),l(-.041,-.21),l(-.055,-.226),l(-.261,-.238),l(-.447,-.119),l(-.106,-.466),l(-.571,.013),l(-.448,.17),l(.013,-.104),l(.128,-.297),l(-.15,-.183),l(-.411,.212),l(-.301,-.07),l(-.38,-.38),l(-.116,-.508),l(.064,-.282),l(-.151,-.438),l(-.229,-.169),l(-.388,.043),l(-.39,-.719),l(-.209,-.508),l(-.3,-.324),l(-.311,-.155),l(-.456,-.395),l(-.343,.1),l(-.218,.142),l(-.216,-.381),l(-.04,-.607),l(.163,-.749),l(.559,-1.738),l(.29,-.848),l(-.087,-.044),l(.098,-.374),l(1.01,-1.7),l(1.011,-1.559),l(.077,-.297),l(-.586,-1.225),l(-.488,-1.183),l(-.006,-.254),l(.086,-.636),l(-.088,-.663),l(-.203,-.479),l(-.606,-.604),l(-.54,-.477),l(-.6,-1.436),l(-.178,-.38),l(.812,-.428),l(.171,-.198),l(-.231,-1.185),l(.128,-.226),l(.451,-.229),l(.194,-.241),l(-.163,-.338),l(-.646,-1.041),l(-.148,-.324),l(-1.091,-.953),l(-.254,-.14),l(-.112,-.875),l(-.069,-.183),l(-.739,-.884),l(.588,-.131),l(.163,-.001),l(.086,-.24),l(-.064,-.409),l(.114,-.509),l(.036,-.819),l(.143,-.368),l(.362,-.411),l(.474,.082),l(.62,-.018),l(1.078,-.316),l(.394,-.595),l(.528,-.342),l(.436,-.172),l(.645,-.06),l(.158,-.071),l(.08,-.085),l(.541,.166),l(.295,.182),l(.118,.168),l(.01,.423),l(-.106,.805),l(.066,.367),l(.186,.154),l(.423,-.003),l(.489,-.2),l(.414,-.045),l(.045,.113),l(.249,1.311),l(-.085,.41),l(-.528,1.569),l(-.117,.438),l(-.027,.494),l(.145,.324),l(.481,.138),l(.37,-.411),l(1.173,-1.178),l(.346,-.03),l(.835,.348),l(.59,.265),l(.223,-.072),l(.543,-.257),l(.2,-.538),l(.286,-.453),l(.403,.012),l(.893,.192),l(.266,.153),l(.052,.282),l(.285,.535),l(.688,.659),l(.435,.632),l(.058,1.524),l(.107,.366),l(.255,.464),l(.979,1.279),l(.419,.703),l(.157,.507),l(.002,.945),l(-.121,.438),l(-.808,.64),l(-.301,-.167),l(-.599,-.109),l(-.575,-.039),l(-.558,.074),l(-.798,-.066),l(-1.172,.091),l(-.383,.101),l(-.521,.441),l(-.92,1.233),l(-.146,.297),l(-.076,.382),l(.026,.635),l(.219,.648),l(.487,.717),l(.16,.479),l(-.146,.176),l(-.026,-.063),l(-.286,-.183),l(-.458,-.084),l(-.9,-.887),l(-.434,-.154),l(-.304,-.014),l(-.572,.227),l(-.391,-.112),l(-.29,-.141),l(-.337,-.014),l(0,-.282),l(.19,-1.243),l(-.107,-.184),l(-.719,-.055),l(-.248,-.084),l(-.521,.043),l(-.443,.212),l(-.244,.297),l(.207,.593),l(-.103,.339),l(-.318,.707),l(.083,.579),l(.054,.41),l(-.293,.664),l(-.583,1.187),l(-.7,1.682),l(-.255,1.314),l(.104,1.171),l(.172,.296),l(.229,.169),l(.55,-.072),l(.396,-.142),l(.252,.07),l(.135,.353),l(.009,.325),l(-.08,.466),l(.141,.282),l(.178,.211),l(.271,-.094),l(.17,.46),l(.209,.974),l(-.032,.254),l(.127,.737),l(.434,.871),l(.167,.155),l(.801,.281),l(.539,.112),l(.467,-.058),l(.294,.197),l(.266,.612),l(.664,.544),l(.212,.145), +N(204.31,158.989),l(-.175,.412),l(.612,-.173),l(.026,.429),l(-.419,1.241),l(.178,.269),l(-.237,.795),l(.189,.318),l(-.092,.397),l(-.358,.875),l(-.3,.35),l(-.36,.032),l(-.054,.286),l(-.388,.238),l(0,.286),l(-.69,.016),l(.215,-4.297),l(-.025,-.329),l(.278,-.095),l(.386,.27),l(.599,-.857),l(.178,-.447),l(.437,-.016), +N(200.276,169.481),l(-.151,-.056),l(-.928,-.342),l(-.614,.032),l(-.766,-.032),l(-.608,-.239),l(-.909,-.656),l(-.513,-.419),l(-.044,-.454),l(-.054,-.553),l(.207,-.238),l(-.305,-.397),l(1.076,-1.812),l(1.06,-.007),l(1.762,.007),l(.211,-.683),l(-.532,-.223),l(-.359,-.69),l(-.624,-.231),l(-.495,-.541),l(-.396,-.223),l(.999,-.032),l(.04,-1.24),l(1.792,.005),l(2.332,.006),l(-.215,4.297),l(.69,-.016),l(.303,.095),l(.311,.302),l(.14,-.191),l(-.066,-.381),l(.336,.157),l(.458,.367),l(-1.507,1.208),l(-.499,.238),l(-.177,.493),l(.162,.604),l(-.438,.302),l(-.467,.048),l(-.043,.254),l(.164,.159),l(-.351,.111),l(-.184,.302),l(-.22,-.016),l(-.565,.461),l(-.012,.223), +N(204.413,165.093),l(.312,-.03),l(.612,-.27),l(.639,-.058),l(.743,.126),l(.478,.069),l(1.443,.04),l(.699,-.228),l(.379,-.199),l(.567,.267),l(.788,-.03),l(.763,-.101),l(.63,-.001),l(.5,.126),l(.564,.253),l(-.038,.353),l(-.102,.226),l(.228,.282),l(.787,.238),l(.557,.069),l(.244,.524),l(-1.425,.486),l(-.424,.229),l(-.248,.086),l(-.463,-.097),l(-.328,-.182),l(-.259,-.013),l(-.294,.242),l(-.503,.794),l(-1.207,.997),l(-.725,-.42),l(-.513,.583),l(-.882,.034),l(-.005,.961),l(-.293,.412),l(-.29,.143),l(-1.001,.125),l(-.311,-.661),l(-.025,-.085),l(-.478,-.3),l(.085,-.731),l(-.128,-.175),l(-.272,0),l(-.541,-.276),l(-.433,.34),l(-.365,-.016),l(-.066,-.271),l(-.565,-.35),l(-.409,-.08),l(-.208,-.418),l(-.677,-.17),l(.438,-.302),l(-.162,-.604),l(.177,-.493),l(.499,-.238),l(1.507,-1.208), +N(205.532,170.085),l(.035,.076),l(-.203,.057),l(.01,.265),l(-.237,.334),l(-.68,-.046),l(-.853,-.139),l(-1.697,-.505),l(-1.305,-.435),l(-.325,-.21),l(.012,-.223),l(.565,-.461),l(.22,.016),l(.184,-.302),l(.351,-.111),l(-.164,-.159),l(.043,-.254),l(.467,-.048),l(.677,.17),l(.208,.418),l(.409,.08),l(.565,.35),l(.066,.271),l(.365,.016),l(.433,-.34),l(.541,.276),l(.272,0),l(.128,.175),l(-.085,.731), +N(242.38,173.617),l(-.128,-.105),l(-.84,.171),l(-.534,.156),l(-.414,.2),l(-.056,.288),l(.048,.497),l(-.129,.396),l(-.227,-.027),l(-.381,.059),l(-.99,1.758),l(-.172,.722),l(-.241,.722),l(-.709,1.191),l(.402,.025),l(.234,-.1),l(.384,-.017),l(.31,.606),l(.855,1.45),l(.103,.395),l(-.226,1.132),l(.099,.353),l(.401,.309),l(.429,.548),l(.397,.252),l(.496,-.017),l(1.163,-.12),l(1.167,-.05),l(.521,.181),l(.64,.321),l(.188,.253),l(.847,.998),l(.554,.576),l(.144,0),l(.522,-.13),l(.76,-.174),l(1.99,-.224),l(.644,.081),l(-.409,.525),l(-.085,1.004),l(-.379,.511),l(-.147,.326),l(.026,.254),l(.035,.438),l(.048,.367),l(.162,.804),l(.447,.789),l(.256,.437),l(.486,.647),l(.121,.282),l(-.731,.612),l(-.479,.526),l(.51,.491),l(.797,1.182),l(-.52,.286),l(-.834,.57),l(-.412,.158),l(-.463,.017),l(-2.812,-.082),l(-.64,-.024),l(-.042,.325),l(-.013,1.031),l(.178,.154),l(.896,.122),l(.177,.084),l(.293,.408),l(.052,.367),l(-.384,-.04),l(-.417,-.11),l(-.687,.032),l(-.493,.187),l(-.111,.085),l(-.001,1.071),l(0,.554),l(.192,.197),l(.688,.363),l(.192,.183),l(-.031,.777),l(.399,.562),l(.031,.212),l(-.326,1.428),l(-.706,4.411),l(-.073,.382),l(-.133,.198),l(-.156,-.14),l(-.575,-.703),l(-.237,-.126),l(-.161,.058),l(-.448,.031),l(1.155,-1.956),l(.035,-.198),l(-.127,-.069),l(-1.299,-.84),l(-.509,-.209),l(-.708,.442),l(-.397,-.182),l(-.523,-.421),l(-.452,.427),l(-.337,.157),l(-.496,.031),l(-1.038,-.008),l(-.573,-.152),l(-.092,-.281),l(.004,-.396),l(-.173,-.296),l(-.479,-.039),l(-.366,-.14),l(-.078,-.282),l(-.251,-.761),l(-.988,-.672),l(-.526,-.364),l(-.208,-.62),l(-.208,-.324),l(-.513,-.435),l(-.897,-.418),l(-.927,-.107),l(-.081,-.112),l(-.269,-.162),l(-.197,-.118),l(-.709,-.631),l(-.128,-.056),l(-.89,.401),l(-.67,.061),l(-.977,-.277),l(-.355,-.309),l(-.166,-.493),l(-.227,-.225),l(-1.432,-.656),l(-1.496,-.803),l(.033,-.068),l(-.117,-.311),l(-.181,-.282),l(.108,-.212),l(.509,-.114),l(.465,.112),l(.186,-.325),l(-.348,-.564),l(.086,-.424),l(.314,-.227),l(.878,-.058),l(.193,.042),l(.41,-.227),l(.445,-.679),l(.45,-.961),l(.651,-1.061),l(-.122,-.268),l(-.56,-.408),l(-.071,-.184),l(.306,-.721),l(.089,-.523),l(-.149,-.861),l(-.371,-.86),l(.085,-.254),l(.49,-.143),l(.135,-.212),l(-.088,-.198),l(-.565,-.479),l(-.042,-.226),l(.103,-.198),l(.242,-.326),l(.036,-.254),l(-.173,-.282),l(-.739,-.719),l(-.364,-.396),l(.256,-.753),l(.228,-.082),l(-.045,-.45),l(.19,.082),l(.085,.307),l(.584,-.409),l(.094,-.43),l(.322,-.062),l(-.509,-1.038),l(-.228,-.149),l(-.084,-.327),l(.142,.075),l(.42,.338),l(.397,.507),l(.22,.508),l(.235,.197),l(.199,-.17),l(.147,-.241),l(-.332,-.776),l(.02,-.212),l(.176,-.297),l(.445,-.34),l(.399,-.297),l(.501,-.736),l(.327,-.156),l(.684,-.101),l(.217,-.382),l(-.104,-.381),l(.174,-.777),l(.067,-.65),l(.207,-.48),l(.498,-.439),l(.429,-.283),l(.592,-.242),l(.113,0),l(.374,.206),l(.22,.443),l(.281,-.34),l(.031,-.438),l(.199,-.551),l(.22,-.071),l(.267,.126),l(.855,.041),l(.562,-.001),l(.623,-.27),l(.237,-.254),l(.476,-.298),l(.848,-.256),l(.435,-.396),l(.278,-.551),l(.333,-.255),l(.469,-.17),l(.58,.013),l(.526,.338),l(.155,.126),l(.155,.339),l(-.285,.332), +N(408.6,174.04),l(-.062,.777),l(.164,.762),l(.388,.718),l(-.316,.962),l(-.19,.566),l(-.223,.298),l(-.656,.414),l(-.095,.34),l(.116,.592),l(-.078,.368),l(-.433,.13),l(-.257,.03),l(-.237,.397),l(.002,.381),l(.003,.48),l(-.012,.876),l(-.09,.989),l(.217,1.439),l(-.121,1.188),l(.006,.234),l(-.333,.015),l(-1.232,.144),l(-.669,.052),l(-.106,-.205),l(-.295,-1.072),l(.188,-.708),l(.026,-.833),l(-.036,-.537),l(-.135,-.974),l(-.006,-.862),l(-.035,-.522),l(.013,-.579),l(-.442,-1.311),l(-.164,-.691),l(-.403,-.323),l(-.468,-.294),l(-.18,-.395),l(.141,-.594),l(.046,-.424),l(.062,-.142),l(.24,-.157),l(.366,-.553),l(.415,-.271),l(.418,-.045),l(.739,.095),l(.337,-.158),l(.415,-.468),l(.237,-.764),l(-.131,-.367),l(.577,-.3),l(.321,-.073),l(.339,.28),l(.727,.589),l(.902,.503), +N(394.266,178.814),l(.191,-.17),l(-.02,-.41),l(-.261,-1.934),l(.125,-.34),l(.271,-.157),l(2.119,-.041),l(.867,.037),l(1.429,.006),l(.976,-.458),l(.161,.032),l(.595,.119),l(-.25,.849),l(.05,.254),l(.633,.915),l(.244,.451),l(-.188,.721),l(.02,.396),l(.265,1.114),l(.181,.592),l(.503,.788),l(.032,.155),l(-.286,.242),l(-.174,.382),l(.01,1.314),l(-.011,.72),l(.021,.551),l(.18,.479),l(.468,.577),l(.752,.608),l(-.503,.682),l(-.304,.099),l(-.593,-.013),l(-.992,.144),l(-.463,.185),l(-.188,.098),l(-.898,.469),l(-1.263,.398),l(-.942,.412),l(-.958,.567),l(-.578,-.324),l(-.945,-.436),l(-.074,-.124),l(-.066,-.741),l(-.554,-1.155),l(-.263,-.747),l(-.103,-.706),l(.327,-1.005),l(.437,-1.274),l(.521,-.851),l(.203,-.595),l(-.334,-1.438),l(-.189,-1.285),l(-.178,-.154), +N(400.72,175.499),l(1.013,.163),l(.611,.166),l(.29,.041),l(-.046,.424),l(-.141,.594),l(.18,.395),l(.468,.294),l(.403,.323),l(.164,.691),l(.442,1.311),l(-.013,.579),l(.035,.522),l(.006,.862),l(.135,.974),l(.036,.537),l(-.026,.833),l(-.188,.708),l(.295,1.072),l(.106,.205),l(-.452,.035),l(-.479,.128),l(-.368,.212),l(-.023,.04),l(-.752,-.608),l(-.468,-.577),l(-.18,-.479),l(-.021,-.551),l(.011,-.72),l(-.01,-1.314),l(.174,-.382),l(.286,-.242),l(-.032,-.155),l(-.503,-.788),l(-.181,-.592),l(-.265,-1.114),l(-.02,-.396),l(.188,-.721),l(-.244,-.451),l(-.633,-.915),l(-.05,-.254),l(.25,-.849), +N(383.772,190.418),l(.041,-.919),l(.105,-.565),l(.247,-.849),l(.059,-.452),l(-.131,-.282),l(-1.264,-1.334),l(-.592,.032),l(-.369,-.097),l(-.194,-.183),l(-.05,-.183),l(.501,-.865),l(.059,-.438),l(-.119,-.55),l(.062,-.17),l(.047,-.099),l(.602,-.554),l(.188,-.354),l(-.179,-.21),l(-.296,-.549),l(.03,-.127),l(.158,-.199),l(.304,-.03),l(.548,.223),l(.304,.012),l(.19,-.143),l(-.051,-.226),l(-.648,-.561),l(-.309,-.351),l(.332,-.37),l(.125,-.283),l(-.197,-.31),l(-.695,-.405),l(-.214,-.409),l(.264,-.623),l(.379,-.397),l(.522,-.54),l(.352,-.059),l(.566,.321),l(.455,.436),l(.35,-.228),l(.362,-.469),l(.571,-.483),l(.239,-.114),l(.257,.041),l(.147,.211),l(.004,.297),l(.117,.381),l(.148,.239),l(.352,-.059),l(.604,-.399),l(.159,-.1),l(.259,.168),l(.545,-.003),l(.308,.252),l(.15,.465),l(.52,.562),l(.452,.223),l(.354,.083),l(.368,-.115),l(.446,-.257),l(.608,-.159),l(.769,-.075),l(.644,.166),l(.63,.434),l(.178,.154),l(.189,1.285),l(.334,1.438),l(-.203,.595),l(-.521,.851),l(-.437,1.274),l(-.327,1.005),l(.103,.706),l(.263,.747),l(.554,1.155),l(.066,.741),l(-.119,-.201),l(-.289,-.197),l(-.208,.015),l(-.143,.24),l(-.096,.042),l(-.48,-.027),l(-.705,-.167),l(-.608,-.083),l(-2.352,.062),l(-1.279,.243),l(-.575,.199),l(-1.07,.369),l(-1.739,.781),l(-.701,.425),l(-.256,-.013),l(-.075,-.032), +N(627.408,186.411),l(.035,.024),l(.523,.098),l(1.061,1.198),l(.693,.916),l(.506,.762),l(.081,.579),l(-.023,.805),l(-.134,.862),l(.07,1.073),l(-.07,.636),l(.097,.494),l(.196,.381),l(.53,.493),l(.338,.536),l(.705,1.608),l(.062,.127),l(-.366,-.069),l(-.895,-.055),l(-.401,.142),l(-.175,-.07),l(-.521,-.437),l(-.885,-.605),l(-.6,-.337),l(-1.231,-.675),l(-1.02,-.732),l(-.217,-.254),l(-.16,-.988),l(-.438,-.691),l(-.895,-.817),l(-.195,-.663),l(.039,-.494),l(.03,-.283),l(-.107,-.409),l(-.399,-.634),l(-.347,-1.849),l(-.188,-.72),l(.043,-.362),l(.448,-.17),l(.571,-.013),l(.106,.466),l(.447,.119),l(.261,.238),l(.055,.226),l(.041,.21),l(-.213,.398),l(.118,.239),l(.204,.083),l(.244,-.394),l(.279,-.28),l(.309,.163),l(.05,.478),l(.644,-.089),l(.11,-.575),l(.495,-.35),l(.086,-.337),M(643.95,196.042),l(.081,.044),l(.375,.408),l(.397,.141),l(.861,.083),l(.413,.168),l(.761,.436),l(.335,.042),l(.337,-.1),l(-.503,-.535),l(.169,-.551),l(.365,-.608),l(.528,-1.258),l(.584,-.27),l(1.481,-.342),l(1.018,-.299),l(.428,-.326),l(.524,-1.021),l(.523,-.323),l(.87,-1.117),l(.22,-.212),l(.244,-.147),l(.112,-.068),l(.084,.126),l(.062,.37),l(.234,-.012),l(.111,.259),l(.309,.271),l(.383,-.271),l(1.234,-.42),l(-.025,-.086),l(-.197,-.197),l(.013,-.247),l(.024,-.111),l(-.148,-.444),l(-.11,-.174),l(.167,-.042),l(.188,.143),l(.085,-.016),l(.449,-.084),l(.161,-.283),l(-.036,-.24),l(-.478,-.366),l(.197,-.396),l(.436,-.071),l(.511,.041),l(.154,-.605),l(.408,-.313),l(.284,-.48),l(.531,-.58),l(.498,-1.032),l(.075,-.17),l(.322,.465),l(.33,.098),l(.315,-.424),l(.305,.494),l(.351,.282),l(.402,.211),l(.075,.338),l(-.182,.354),l(-.234,.452),l(.037,.198),l(.631,-.128),l(.472,-.128),l(.115,.226),l(-.349,.495),l(.742,-.1),l(.357,-.085),l(.269,.056),l(1.035,.662),l(.345,.14),l(.1,.24),l(-.158,.269),l(-.201,.155),l(-.44,.143),l(-.594,.029),l(-.683,-.083),l(-.355,.311),l(.096,.254),l(.888,.69),l(-.161,.311),l(-.458,.199),l(-.646,.1),l(-.518,.114),l(-.067,.15),l(-.182,-.09),l(-.753,-.292),l(-.446,-.04),l(-.624,.018),l(-.651,-.081),l(-.748,-.081),l(-.464,.017),l(-.247,.157),l(-.381,.638),l(-.119,.565),l(.106,.988),l(-.22,.383),l(-.646,.244),l(-.218,.34),l(.076,.748),l(-.928,1.785),l(-.387,.299),l(-.864,.175),l(-.465,.172),l(-.467,.356),l(-.287,.03),l(-.559,-.152),l(-.524,-.223),l(-.557,-.251),l(-.431,-.11),l(-.479,.074),l(-.531,.441),l(-.403,.525),l(-.528,.342),l(-.399,.172),l(-.543,-.11),l(-.526,-.223),l(-.255,.001),l(-.928,.416),l(-.446,-.28),l(-.304,-.083),l(-1,-.983),l(-.253,-.295),l(-.288,-.792), +N(274.556,195.884),l(.06,-.212),l(-.332,-.563),l(-.49,-1.127),l(-.246,-.832),l(-.185,-.295),l(-.561,-.067),l(-.532,-.675),l(-.571,-.831),l(.328,-.694),l(.095,-.467),l(-.078,-.777),l(.169,-.17),l(1.131,-.091),l(.183,-.27),l(.082,-.862),l(.142,-.496),l(.015,-.339),l(.326,-.312),l(.382,-.057),l(1.392,.463),l(.465,.042),l(.083,-.41),l(.141,-.085),l(.337,.027),l(.833,.012),l(.863,-.03),l(.723,.069),l(.63,.182),l(.999,.427),l(-.647,.876),l(-.391,.751),l(-.137,.594),l(.094,.381),l(.134,.635),l(.086,.664),l(.521,.844),l(.029,.438),l(-.424,1.472),l(-.489,.963),l(-1.05,-.488),l(-.319,.001),l(-.534,.385),l(-.398,.059),l(-.418,-.139),l(-.642,-.124),l(-.172,.156),l(-.2,.326),l(.611,1.014),l(-.528,-.054),l(-1.108,-.276),l(-.4,-.04), +N(285.859,190.719),l(.015,.422),l(-1.102,1.646),l(-.427,.765),l(-.439,.992),l(-.464,.681),l(-.299,.214),l(-.56,-.025),l(-1.11,-.389),l(-.882,.613),l(-.225,-.069),l(-.649,-.505),l(.489,-.963),l(.424,-1.472),l(-.029,-.438),l(-.521,-.844),l(-.086,-.664),l(-.134,-.635),l(-.094,-.381),l(.137,-.594),l(.391,-.751),l(.647,-.876),l(.218,.093),l(1.033,.294),l(.55,.196),l(.799,.549),l(1.264,1.084),l(.545,.564),l(.317,.465),l(.193,.028), +N(429.505,210.684),l(-.695,-.533),l(-.351,.13),l(-.68,.513),l(-.536,.414),l(-.112,-.177),l(-.392,-.86),l(-1.381,-1.344),l(.184,-.295),l(.413,-.229),l(.803,.307),l(.343,-.681),l(-.052,-.296),l(-.274,-.253),l(-.39,-.521),l(-.116,-.366),l(.058,-.495),l(.127,-.1),l(.909,-.146),l(.604,-.243),l(.125,-.213),l(.167,-.807),l(.174,-.185),l(.239,-.029),l(.193,.14),l(.341,.479),l(.405,.521),l(.386,.195),l(.287,-.016),l(.188,-.228),l(.362,-.482),l(.29,.253),l(.167,.578),l(.146,.112),l(.304,.068),l(.255,-.114),l(.184,-.68),l(.243,-1.089),l(.131,-1.229),l(.229,-1.047),l(-.114,-.338),l(-.161,-.127),l(-.384,-.082),l(-.528,-.208),l(-.242,-.31),l(-.132,-.437),l(.008,-.109),l(.021,-.3),l(.157,-.284),l(.492,-.398),l(.556,-.441),l(.094,-.354),l(-.389,-.902),l(-.369,-.322),l(-.592,-.067),l(-.939,.5),l(-.463,-.025),l(-.146,-.253),l(-.068,-.734),l(.077,-.679),l(.396,-.468),l(.56,.109),l(.863,.023),l(.878,-.076),l(.271,.055),l(.479,.04),l(.56,.124),l(.576,.194),l(.864,.334),l(.863,.292),l(.271,-.086),l(-.1,-.861),l(.159,-.185),l(.303,-.312),l(.365,-.497),l(.158,-.523),l(.222,-1.287),l(.255,-.228),l(.479,-.102),l(.975,-.175),l(.367,.054),l(.624,.138),l(.895,.093),l(.751,-.287),l(.128,.197),l(-.031,.156),l(-.398,1.203),l(-.558,.837),l(-.349,.821),l(-.094,.551),l(-.156,.764),l(-.196,2.021),l(-.254,1.342),l(-.115,.61),l(-.169,.708),l(-.139,.523),l(-.459,.427),l(-.525,.229),l(-.809,.599),l(-.41,.454),l(-.47,.836),l(-.343,.751),l(-.193,1.159),l(-.074,.396),l(.122,.72),l(-.086,.706),l(-1.025,.938),l(-.364,.229),l(-.931,.811),l(-.554,.399),l(-.57,.328),l(-.147,-.211),l(-.042,-.664),l(-.054,-.424),l(-1.495,.532),l(-.327,.581),l(-.443,.271),l(-.177,-.013),l(-.484,-.336), +N(425.506,195.522),l(.045,-.495),l(.88,.093),l(1.773,.088),l(.831,.038),l(1.022,.149),l(-.396,.468),l(-.077,.679),l(.068,.734),l(.146,.253),l(.463,.025),l(.939,-.5),l(.592,.067),l(.369,.322),l(.389,.902),l(-.094,.354),l(-.556,.441),l(-.492,.398),l(-.157,.284),l(-.021,.3),l(-.008,.109),l(.132,.437),l(.242,.31),l(.528,.208),l(.384,.082),l(.161,.127),l(.114,.338),l(-.229,1.047),l(-.131,1.229),l(-.243,1.089),l(-.184,.68),l(-.255,.114),l(-.304,-.068),l(-.146,-.112),l(-.167,-.578),l(-.29,-.253),l(-.362,.482),l(-.188,.228),l(-.287,.016),l(-.386,-.195),l(-.405,-.521),l(-.341,-.479),l(-.193,-.14),l(-.239,.029),l(-.174,.185),l(-.167,.807),l(-.125,.213),l(-.604,.243),l(-.909,.146),l(-.127,.1),l(-.058,.495),l(.116,.366),l(.39,.521),l(.274,.253),l(.052,.296),l(-.343,.681),l(-.803,-.307),l(-.413,.229),l(-.184,.295),l(-.038,-.037),l(-.563,-.493),l(-.532,-.55),l(-.259,-.466),l(-1.318,-1.169),l(.286,-.312),l(-.369,-.281),l(-.528,-.056),l(-.918,-1.438),l(.382,-.297),l(.111,-.1),l(-.321,-.395),l(-.464,-.14),l(-.29,-.564),l(-.369,-.451),l(.319,-.17),l(.541,-.411),l(.223,-.396),l(.291,-.976),l(.089,-.295),l(.415,.07),l(.495,.013),l(-.064,-.211),l(-.56,-.352),l(-.561,-.451),l(.208,-.042),l(.271,-.128),l(.142,-.617),l(.83,-.043),l(.927,.008),l(1.245,.021),l(.575,-.032),l(-.001,-.155),l(-.02,-.551),l(-.026,-1.836), +N(422.536,195.513),l(1.005,-.007),l(1.965,.017),l(.026,1.836),l(.02,.551),l(.001,.155),l(-.575,.032),l(-1.245,-.021),l(-.927,-.008),l(-.83,.043),l(.033,-.146),l(-.049,-.297),l(-.144,-.084),l(-.416,-.098),l(.287,-.467),l(.447,-.523),l(.335,-.58),l(.066,-.403),M(419.636,193.273),l(-.484,-.049),l(-.049,-.218),l(.049,-.291),l(.242,-.097),l(.024,-.146),l(0,-.291),l(.17,-.097),l(.169,-.121),l(.219,.048),l(.218,.048),l(.097,.194),l(-.193,.169),l(-.146,.243),l(-.17,.339),l(-.146,.267), +N(222.291,207.801),l(.188,-.126),l(.264,-.312),l(.585,-1.061),l(.038,-.269),l(-.209,-.733),l(.058,-.391),l(-.478,.617),l(-.732,.623),l(-.333,-.098),l(-.601,-.324),l(-.408,-.408),l(.389,-.283),l(.1,-.24),l(-.167,-.579),l(.005,-.438),l(.133,-.466),l(-.109,-.282),l(-.362,-.649),l(.193,-.17),l(.48,-.198),l(.721,-.454),l(-.319,-.395),l(0,-.226),l(.175,-.354),l(.497,-.462),l(.157,-.146),l(.14,-.848),l(-.116,-.452),l(-.082,-.184),l(.11,-.226),l(.686,-.101),l(.891,-.341),l(.396,-.241),l(.474,-.382),l(.09,-.186),l(1.496,.803),l(1.432,.656),l(.227,.225),l(.166,.493),l(.355,.309),l(.977,.277),l(.67,-.061),l(.89,-.401),l(.128,.056),l(.709,.631),l(.197,.118),l(.269,.162),l(.081,.112),l(.387,.76),l(.321,.789),l(-.08,.255),l(-.352,.384),l(-.547,1.147),l(-.533,.779),l(-.71,.725),l(-1.001,.755),l(-.336,.087),l(-1.028,.303),l(-.901,.358),l(-.809,.499),l(-.59,.653),l(-.284,.51),l(-.987,2.506),l(-.267,.312),l(-.242,.072),l(-.398,-.068),l(-.398,-.491),l(-.191,-.479),l(-.312,-.252),l(-.815,.005),l(-.444,-.11),l(-.105,-.197),l(-.097,-.494),l(.233,-.34),l(.029,-.495),l(.005,-.569), +N(245.934,224.314),l(1.109,1.843),l(.922,1.646),l(.08,.24),l(-.437,.736),l(-.15,.523),l(-.143,.848),l(.057,.522),l(.236,.902),l(-.156,.34),l(-.221,.34),l(-.532,.582),l(-.102,.452),l(.347,.845),l(-.21,.368),l(-.159,.34),l(.022,.48),l(.604,1.168),l(.015,.522),l(-.285,.439),l(-.723,.61),l(-.12,.227),l(.049,.48),l(.132,.295),l(.018,.142),l(-.586,.187),l(-.15,.199),l(-.228,.933),l(-.259,.298),l(-.852,.275),l(-.201,-.517),l(-.289,-.31),l(-1.422,-.618),l(-.313,-.239),l(-.233,-.678),l(-.315,-.38),l(-.559,-.225),l(-.504,-.281),l(-.489,-.254),l(-.616,-.309),l(-.873,-.464),l(-.673,-.366),l(-.866,-.379),l(-.838,-.337),l(-1.271,-.845),l(-1.354,-.985),l(-1.232,-1.099),l(-.594,-.705),l(-.42,-.677),l(.008,-.438),l(0,-.903),l(-.269,-.606),l(-.781,-1.043),l(-1.389,-2.778),l(-.285,-.268),l(-.467,-.211),l(-.074,-.085),l(.055,-.536),l(-.02,-.396),l(-.149,-.396),l(-1.208,-2.199),l(-.997,-1.961),l(-.688,-1.27),l(-1.365,-1.917),l(-.272,-.353),l(-.598,-.973),l(-.462,-.423),l(-.75,-.437),l(-.914,-.365),l(-.61,-.365),l(.119,-.17),l(.181,-.113),l(.609,-.029),l(.144,-.41),l(-.118,-.282),l(-.592,-.874),l(-.353,-.437),l(-.258,-.72),l(.01,-.24),l(.244,-.523),l(.582,-.622),l(1.02,-.878),l(.47,-.198),l(.317,-.214),l(-.005,.569),l(-.029,.495),l(-.233,.34),l(.097,.494),l(.105,.197),l(.444,.11),l(.815,-.005),l(.312,.252),l(.191,.479),l(.398,.491),l(.398,.068),l(.242,-.072),l(.267,-.312),l(.987,-2.506),l(.284,-.51),l(.59,-.653),l(.809,-.499),l(.901,-.358),l(1.028,-.303),l(.336,-.087),l(1.001,-.755),l(.71,-.725),l(.533,-.779),l(.547,-1.147),l(.352,-.384),l(.08,-.255),l(-.321,-.789),l(-.387,-.76),l(.927,.107),l(.897,.418),l(.513,.435),l(.208,.324),l(.208,.62),l(.526,.364),l(.988,.672),l(.251,.761),l(.078,.282),l(.366,.14),l(.479,.039),l(.173,.296),l(-.004,.396),l(.092,.281),l(.573,.152),l(1.038,.008),l(.496,-.031),l(.337,-.157),l(.452,-.427),l(.523,.421),l(.397,.182),l(.708,-.442),l(.509,.209),l(1.299,.84),l(.127,.069),l(-.035,.198),l(-1.155,1.956),l(.448,-.031),l(.161,-.058),l(.237,.126),l(.575,.703),l(.156,.14),l(.136,.324),l(-.341,.186),l(-.793,-.235),l(-.493,-.096),l(-.322,.072),l(-.604,.441),l(-.371,.115),l(-.669,-.066),l(-1.895,.773),l(-.701,.442),l(-.372,.172),l(-.599,1.415),l(-.319,.511),l(-.021,.155),l(.277,.86),l(.012,.112),l(-.625,.498),l(-.62,.328),l(-.349,.342),l(-.247,.622),l(.106,.564),l(.619,.957),l(1.333,2.166),l(.106,.127),l(-.247,.495),l(-.208,.312),l(1.085,.12),l(.415,.04),l(.312,.182),l(.241,.323),l(.096,.663),l(1.843,.032),l(.762,-.499),l(.648,-.484),l(.326,-.114),l(-.059,1.511),l(-.098,1.173),l(.108,.353),l(.317,.337),l(.285,.068),l(.358,-.072),l(.786,-.259),l(.42,-.045), +N(279.288,257.295),l(-.063,-.423),l(.027,-.777),l(.222,-.819),l(.298,-.835),l(.321,-.75),l(-.019,-.141),l(-.491,-.336),l(-.234,-.112),l(-1.29,.445),l(-.224,-.055),l(-.254,-.563),l(-.487,-2.524),l(-.121,-.437),l(-.843,-.404),l(-.724,-.278),l(-.115,.001),l(-.709,.413),l(-.346,.03),l(-.925,-.221),l(-.818,-.15),l(-.372,-.04),l(.006,-.72),l(.086,-.721),l(.132,-.862),l(-.104,-.959),l(-.521,-.872),l(-.084,-.663),l(-.253,-.408),l(.421,-.666),l(.38,-.765),l(.238,-.834),l(.185,-1.173),l(-.022,-.494),l(-.307,-.774),l(-.316,-.479),l(-.73,-.362),l(-.436,-.407),l(-.067,-.563),l(.261,-.835),l(-.042,-.296),l(-.693,-.024),l(-1.615,-.019),l(-.5,-.012),l(-.967,-.036),l(-.153,-.112),l(-.249,-.944),l(-.138,-2.032),l(-.03,-.706),l(-.203,-1.029),l(.038,-.565),l(-.085,-.169),l(-.403,-.237),l(-.537,-.166),l(-.636,-.123),l(-1.148,.077),l(-.22,-.084),l(-.398,-.308),l(-.385,-.774),l(-.096,-.014),l(-.882,-.037),l(-.3,-.098),l(-.75,-.603),l(-.688,-.307),l(-.676,-.25),l(-.355,.03),l(-.787,-.023),l(-.316,-.097),l(-1.1,-.939),l(-.813,-.928),l(-.335,-.591),l(-.141,-.635),l(-.036,-.818),l(.064,-.622),l(.079,-.621),l(-.045,-.748),l(-1.283,-.021),l(-.934,.076),l(-.36,.158),l(-.874,.485),l(-1.471,1.109),l(-.415,.243),l(-.48,-.025),l(-.336,-.026),l(-.946,.824),l(-.355,.03),l(-1.122,-.304),l(-.939,-.136),l(-.42,.045),l(-.786,.259),l(-.358,.072),l(-.285,-.068),l(-.317,-.337),l(-.108,-.353),l(.098,-1.173),l(.059,-1.511),l(-.326,.114),l(-.648,.484),l(-.762,.499),l(-1.843,-.032),l(-.096,-.663),l(-.241,-.323),l(-.312,-.182),l(-.415,-.04),l(-1.085,-.12),l(.208,-.312),l(.247,-.495),l(-.106,-.127),l(-1.333,-2.166),l(-.619,-.957),l(-.106,-.564),l(.247,-.622),l(.349,-.342),l(.62,-.328),l(.625,-.498),l(-.012,-.112),l(-.277,-.86),l(.021,-.155),l(.319,-.511),l(.599,-1.415),l(.372,-.172),l(.701,-.442),l(1.895,-.773),l(.669,.066),l(.371,-.115),l(.604,-.441),l(.322,-.072),l(.493,.096),l(.793,.235),l(.341,-.186),l(-.136,-.324),l(.133,-.198),l(.073,-.382),l(.706,-4.411),l(.326,-1.428),l(-.031,-.212),l(-.399,-.562),l(.031,-.777),l(-.192,-.183),l(-.688,-.363),l(-.192,-.197),l(0,-.554),l(.001,-1.071),l(.111,-.085),l(.493,-.187),l(.687,-.032),l(.417,.11),l(.384,.04),l(-.052,-.367),l(-.293,-.408),l(-.177,-.084),l(-.896,-.122),l(-.178,-.154),l(.013,-1.031),l(.042,-.325),l(.64,.024),l(2.812,.082),l(.463,-.017),l(.412,-.158),l(.834,-.57),l(.52,-.286),l(.148,.168),l(.138,.437),l(.161,.861),l(.088,.452),l(.199,.437),l(.432,.054),l(.694,.546),l(.482,.223),l(.414,-.073),l(.757,-.697),l(.083,.183),l(.186,.776),l(.271,-.016),l(.645,-.739),l(.74,-.654),l(.554,-.286),l(.652,-.173),l(.235,-.213),l(.259,-.666),l(.203,-.199),l(.652,-.131),l(.569,-.272),l(.265,-.27),l(-.15,-.253),l(-.434,-.125),l(-.96,-.051),l(-.166,-.239),l(-.079,-.55),l(-.302,-1.524),l(-.391,-.69),l(-.616,-.688),l(.041,-.184),l(.159,-.029),l(.309,.125),l(.896,.461),l(.385,.04),l(1.149,-.035),l(.344,.224),l(.628,.618),l(.348,-.115),l(.232,-1.117),l(.284,-.115),l(.465,.054),l(.557,-.074),l(.807,-.23),l(1.74,-.9),l(.592,-.385),l(.163,-.326),l(-.103,-.169),l(.375,-.257),l(.302,-.058),l(.516,.124),l(.26,.111),l(.04,.212),l(-.452,1.09),l(.304,-.001),l(.533,.138),l(.435,.958),l(-.179,.368),l(-.547,1.416),l(-.213,.962),l(.156,.465),l(.281,.394),l(.167,.31),l(-.072,.354),l(.008,.396),l(.15,.296),l(1.103,.897),l(.613,.392),l(.686,-.075),l(.694,-.513),l(.505,-.314),l(1,-.331),l(.934,-.429),l(.943,.022),l(.4,.04),l(1.108,.276),l(.528,.054),l(-.611,-1.014),l(.2,-.326),l(.172,-.156),l(.642,.124),l(.418,.139),l(.398,-.059),l(.534,-.385),l(.319,-.001),l(1.05,.488),l(.649,.505),l(.225,.069),l(.882,-.613),l(1.11,.389),l(.56,.025),l(.299,-.214),l(.464,-.681),l(.439,-.992),l(.427,-.765),l(1.102,-1.646),l(-.015,-.422),l(.409,-.241),l(.276,.141),l(.235,.423),l(.164,.791),l(.414,1.34),l(.108,.607),l(.472,1.383),l(.296,.55),l(.324,.324),l(.978,.21),l(.196,.338),l(.038,.551),l(-.045,.254),l(-.524,.354),l(-.933,1.414),l(-.238,.325),l(-.51,.411),l(-.41,.231),l(-.244,.138),l(-.798,.778),l(-.544,.947),l(-.419,1.018),l(-.402,.453),l(.271,.112),l(.512,-.072),l(.497,-.198),l(1.202,-.709),l(.112,-.028),l(.299,.889),l(.442,.818),l(.255,.112),l(.287,.07),l(1.135,-.031),l(.592,-.058),l(.737,-.298),l(-.277,.679),l(-.017,.584),l(.448,-.557),l(1.254,-1.006),l(.289,-.156),l(.306,-.382),l(.499,-.933),l(.272,-.396),l(.256,-.099),l(1.006,-.003),l(.352,-.198),l(.175,0),l(.687,.549),l(.654,.267),l(.32,-.028),l(.814,.28),l(1.069,.45),l(.334,.281),l(.269,.593),l(.08,.028),l(.176,-.015),l(.402,-.354),l(.319,.042),l(.302,.254),l(.538,.789),l(.205,.396),l(-.13,.254),l(-.308,.41),l(-.116,.424),l(.091,.466),l(.171,.396),l(.825,-.821),l(.369,-.156),l(.609,-.156),l(.995,-.454),l(.224,-.028),l(.367,.069),l(.764,.38),l(.907,.436),l(.462,.098),l(1.117,.167),l(1.118,.083),l(.464,-.058),l(.48,-.029),l(.577,-.171),l(.416,-.016),l(1.131,.351),l(.731,.408),l(.762,.479),l(.586,.437),l(1.595,1.395),l(.742,.662),l(.821,.605),l(.41,.338),l(.477,.196),l(.734,.168),l(1.247,.097),l(.912,.04),l(.445,.197),l(.265,.465),l(.087,.607),l(.592,2.004),l(.268,1.143),l(.062,.988),l(-.076,.579),l(-.179,.904),l(-.243,.848),l(-.559,1.301),l(-.518,.849),l(-1.347,1.175),l(-1.388,1.288),l(-.44,.198),l(-.354,.043),l(-.39,.637),l(-.094,.396),l(-.012,.353),l(-.504,1.074),l(-.6,.976),l(-.8,1.104),l(-.266,.212),l(-.194,.015),l(-.079,-.423),l(-.278,-.296),l(-.367,-.084),l(-.064,.79),l(-.538,1.64),l(-.049,.734),l(-.077,.607),l(.318,2.738),l(.078,.988),l(-.577,2.543),l(-.039,.663),l(.14,.649),l(.043,.085),l(-.759,.495),l(-.404,.51),l(-.261,.791),l(-.04,.367),l(.245,1.468),l(-.106,.367),l(-.214,.283),l(-.676,.608),l(-.752,1.498),l(-1.01,1.4),l(-.201,.537),l(-.055,.311),l(.144,.945),l(-1.203,.37),l(-.544,.283),l(-.355,.368),l(-.084,.466),l(.021,.367),l(-.401,.114),l(-.864,-.041),l(-.979,.172),l(-.654,.001),l(-.764,-.055),l(-.465,-.112),l(-.922,.072),l(-.736,.002),l(-.214,.607),l(-.295,.198),l(-.795,.312),l(-.481,.453),l(-.21,.354),l(-.747,-.267),l(-.35,.071),l(-.563,.255),l(-1.864,1.232),l(-.528,.396),l(-.725,.383),l(-.616,.438),l(-.532,.679),l(-.486,.241),l(-.567,.072),l(-.278,-.014),l(.006,.24),l(.336,.225),l(.12,.536),l(-.111,.537),l(-.099,.282),l(-.282,.156),l(-.084,.155),l(.384,.648),l(.036,1.186),l(.05,1.045),l(-.057,.311),l(-.11,.594),l(-.198,.621),l(-.464,.735),l(-.566,.495),l(-.788,.524),l(-.866,1.046),l(-.208,.396),l(-.476,1.145),l(-.499,.933),l(-.75,1.004),l(-.69,.623),l(-.801,.78),l(.321,-.808),l(.436,-.594),l(.629,-.566),l(.605,-1.158),l(-.06,-.254),l(-.356,.142),l(-.397,-.014),l(-.633,-.21),l(-.075,.155),l(.002,.297),l(-.401,1.215),l(-.349,.48),l(-.661,.438),l(-.317,.283),l(-.225,.424),l(-.013,.354),l(-.448,1.709),l(-.481,.763),l(-.787,.934),l(-1.076,.979),l(-.101,-.313),l(-.258,-.746),l(.103,-.269),l(.634,-.766),l(.017,-.269),l(-.333,-.379),l(-.163,-.027),l(-.131,-.197),l(-.853,-1.109),l(-.474,-.435),l(-.999,-.587),l(-.55,-.194),l(-.617,-.194),l(-.432,-.576),l(-.365,-.393),l(-.693,.427),l(-.27,.016),l(-.232,-.38),l(-.59,-.814),l(-.379,-.407),l(-.47,-.364),l(-.266,-.098),l(-.25,.101),l(-1.042,.246),l(-.55,.003),l(.214,-.27),l(.833,-.88),l(1.805,-1.816),l(1.435,-1.363),l(1.633,-1.448),l(.348,-.242),l(1.754,-.744),l(.521,-.313),l(.161,-.467),l(.094,-1.638),l(-.517,-1.154),l(-.206,-.196),l(-.462,.017),l(-.957,.161),M(288.966,203.943),l(-.558,-.125),l(-.301,-.536),l(-.078,-.382),l(.16,-.197),l(-.094,-.636),l(.048,-.381),l(.208,-1.018),l(.176,-.099),l(.479,-.058),l(.879,.097),l(1.007,.11),l(.479,-.199),l(.368,.028),l(.479,.168),l(.479,.083),l(.319,.155),l(-.335,.538),l(-.193,.946),l(-.257,.494),l(-.289,.312),l(-.561,.326),l(-.464,.171),l(-.527,.015),l(-.783,.016),l(-.641,.171), +N(732.92,214.323),l(-.164,-.24),l(-.225,-.197),l(-.379,-.126),l(-.416,.198),l(-.399,-.38),l(-.287,-.184),l(-.659,-.238),l(-.243,-.239),l(.156,-.255),l(.29,.027),l(.731,-.058),l(.538,.126),l(.743,.083),l(.523,-.058),l(.258,-.185),l(.232,-.509),l(.056,.099),l(.351,.395),l(.286,.184),l(.241,.014),l(.961,-.2),l(.366,-.227),l(.361,-.722),l(.241,-.212),l(.653,-.029),l(.263,-.128),l(.04,-.282),l(-.064,-.565),l(-.043,-.536),l(.495,.196),l(.404,.056),l(.324,-.354),l(.318,.578),l(.077,.353),l(-.196,.495),l(-.099,.184),l(-.509,.044),l(-.159,.226),l(.061,.17),l(.437,.479),l(-.308,.354),l(-.264,.113),l(-.742,-.083),l(-.416,.001),l(-.091,.269),l(-.408,.495),l(-.275,.156),l(-.973,.426),l(-.484,.143),l(-.798,.029),l(-.807,.115),M(713.795,220.696),l(.031,-3.438),l(-.046,-.805),l(-.431,-1.368),l(.44,-.822),l(-.169,-7.966),l(2.581,.802),l(.85,.337),l(1.04,.295),l(1.254,.378),l(.848,.507),l(.613,.323),l(.597,.084),l(.38,-.058),l(.26,.508),l(.274,.254),l(.635,.352),l(.687,.395),l(.779,.718),l(-.3,.947),l(.033,.226),l(.305,.226),l(.665,.111),l(1.887,.787),l(.354,.027),l(.72,.183),l(.181,.254),l(.413,.535),l(.211,.579),l(-.166,.113),l(-1.114,.073),l(-.563,.156),l(-.098,.155),l(.047,.339),l(.589,.987),l(.5,.521),l(1.464,1),l(.218,.847),l(.725,1.044),l(.288,.141),l(.304,-.015),l(.712,-.086),l(.338,.013),l(.087,.198),l(-.354,.551),l(.218,.212),l(.401,.141),l(.423,.041),l(.63,.168),l(.096,.127),l(-.031,.142),l(-.648,.213),l(.287,.24),l(1.064,.28),l(.538,.295),l(.235,.763),l(-.064,.226),l(-1.094,-.012),l(-.215,-.154),l(-.146,-.466),l(-.126,-.099),l(-1.011,-.111),l(-1.063,-.266),l(-.644,-.126),l(-.752,.016),l(-.774,-.026),l(-.573,-.211),l(-.494,-.352),l(-.223,-.522),l(-.24,-.268),l(-.726,-.31),l(-.472,-.338),l(-.135,-.197),l(-1.089,-1.608),l(-.613,-.817),l(-.454,-.056),l(-1.524,-.336),l(-.671,-.31),l(-.55,-.055),l(-.415,.185),l(-.394,.071),l(-.78,-.45),l(.282,.762),l(-.027,.212),l(-.249,.071),l(-.382,-.126),l(-.311,.1),l(.296,.395),l(-.116,.113),l(-1.037,.045),l(-1.125,-.182),l(-.478,.029),l(.237,.127),l(.24,.154),l(.642,.169),l(.662,.352),l(.404,.338),l(.219,.395),l(-.411,.199),l(-.739,.425),l(-.458,.213),l(-.668,-.097),l(-1.801,-.039),l(-1.219,-.092), +N(726.605,297.247),l(-.479,-.229),l(-1.179,-.471),l(-.543,-.371),l(-.508,-.715),l(-.477,-.558),l(-.216,-.414),l(.264,-.044),l(.169,.1),l(.421,.171),l(.129,-.143),l(-.209,-.387),l(-.703,-.699),l(-.617,-.713),l(-.149,-.257),l(-.375,-.956),l(-.008,-.67),l(.177,-.044),l(1.004,.312),l(1.476,.354),l(1.089,.369),l(.797,-.03),l(.463,-.144),l(.382,-.115),l(.373,-.058),l(.684,.027),l(.306,-.301),l(.716,-.244),l(.475,.385),l(-.009,.1),l(.128,.8),l(-.009,.686),l(-.751,1.503),l(-.124,.758),l(-.245,.315),l(-.943,.26),l(-.553,.388),l(-.49,.689),l(-.189,.272),l(-.274,.072),M(716.883,224.344),l(.682,.394),l(.233,.509),l(.047,.649),l(.118,.678),l(.256,.197),l(.42,.013),l(.102,.24),l(-.45,.919),l(.715,.338),l(.175,.282),l(.147,.593),l(.08,1.3),l(.144,.621),l(.456,1.157),l(.293,.268),l(.422,.014),l(.328,-.312),l(.384,-.185),l(.32,.663),l(.363,.127),l(.563,.408),l(.385,.154),l(.144,.155),l(.002,.41),l(.083,.96),l(.275,.776),l(-.046,1.06),l(.279,.24),l(.93,1.325),l(.276,.706),l(.055,.777),l(-.209,.876),l(.403,.649),l(.275,.833),l(.204,.353),l(1.395,.803),l(.285,.154),l(.744,.111),l(.402,.649),l(.843,.535),l(.483,.169),l(1.141,.068),l(.117,.197),L(731,245.42),l(-.273,.565),l(.309,.424),l(.879,.479),l(.22,.564),l(.469,1.342),l(.211,.748),l(.112,.396),l(.252,.311),l(.771,.352),l(-.021,-.127),l(-.141,-.777),l(.913,.507),l(.567,.154),l(.184,.127),l(.136,.296),l(.106,1.752),l(.884,.762),l(.573,.323),l(.604,.154),l(.287,.296),l(.244,.579),l(.229,.424),l(.545,.168),l(.176,.297),l(.007,.269),l(.19,.536),l(.106,.113),l(.506,.126),l(.156,.112),l(.162,.354),l(.366,1.327),l(.026,.876),l(.013,.862),l(-.132,.41),l(-.181,.325),l(.778,1.271),l(.223,.48),l(.181,.833),l(.034,.749),l(-.293,.708),l(-.353,1.668),l(-.585,1.755),l(.137,.791),l(-.065,.806),l(-.306,.778),l(-.661,.977),l(-.203,.665),l(-.598,.821),l(-.45,.185),l(-.465,.1),l(-.423,.468),l(-.466,.68),l(-.328,1.527),l(-.477,.638),l(-.34,.495),l(.014,.65),l(-.208,.539),l(-.331,.312),l(-.601,.341),l(-.27,.326),l(-.3,1.021),l(-.169,1.049),l(-.079,.937),l(.021,.666),l(-.283,.64),l(-.322,.354),l(-.463,.3),l(-.754,.101),l(-1.158,.087),l(-.82,.03),l(-.527,.157),l(-.516,.299),l(-1.529,.94),l(-.443,.129),l(-.214,.284),l(-.346,.071),l(-.528,.059),l(-.286,-.014),l(.295,.368),l(.209,.27),l(-1.315,-.665),l(-.885,-.353),l(.003,-.469),l(-.073,-.156),l(-.56,-.467),l(-.628,-.368),l(-.421,-.014),l(-.485,.172),l(-.335,.242),l(.748,.467),l(-.97,.243),l(-.929,.428),l(-.953,.442),l(-.222,.028),l(-.604,-.226),l(-.886,-.438),l(-.67,-.226),l(-1.086,-.311),l(-.51,-.041),l(-.239,.156),l(-.044,.113),l(-.716,-.169),l(-.751,-.353),l(-.522,-.298),l(-.896,-.82),l(-.526,-.34),l(-.422,-.879),l(.09,-1.035),l(-.082,-.411),l(-.184,-.495),l(-.664,-.736),l(-.141,-.523),l(-.029,-.425),l(-.534,-.014),l(-.786,.398),l(-.597,.114),l(-.34,.058),l(-.178,-.07),l(-.167,-.17),l(.517,-.454),l(.233,-.567),l(.073,-.821),l(-.253,-.324),l(-.536,-.593),l(-.247,-.353),l(-.485,.735),l(-.443,1.431),l(-.19,.113),l(-.796,.002),l(-.199,.156),l(-.196,.015),l(-.255,.028),l(.198,-.396),l(.081,-.396),l(.079,-.1),l(.634,.041),l(.242,-.142),l(.126,-.255),l(-.105,-1.004),l(.454,-.835),l(.328,-.453),l(.091,-.396),l(.018,-.409),l(.151,-.128),l(.245,-.015),l(.218,-.354),l(-.052,-.227),l(-.323,-.494),l(-.338,-.494),l(-.107,.707),l(-.288,.255),l(-.518,.299),l(-.311,.467),l(-.086,.155),l(-.189,.467),l(-.281,.326),l(-.747,.242),l(-.735,.481),l(-.653,.567),l(-.36,.693),l(-.514,.808),l(-.41,-.339),l(-.38,-1.328),l(-.263,-.579),l(-.19,-.325),l(-.688,-.79),l(-.297,-.734),l(-.176,-.212),l(-.704,.072),l(-.235,-.099),l(-.139,-.24),l(-.085,-.269),l(.334,-.34),l(-.047,-.297),l(-.346,-.395),l(-.543,-.494),l(-.266,-.098),l(-.83,.157),l(-.486,-.07),l(-.95,-.549),l(-.274,-.014),l(-.438,.17),l(-.433,-.027),l(-.421,-.183),l(-.662,-.521),l(-.921,-.437),l(-.218,.001),l(-.723,.213),l(-1.282,.088),l(-.669,.001),l(-1.764,.061),l(-.611,.129),l(-.656,.213),l(-.989,.44),l(-.972,.256),l(-1.039,.257),l(-1.503,.088),l(-.794,-.013),l(-.383,.044),l(-.927,.284),l(-.993,.469),l(-.773,.397),l(-.538,.143),l(-.431,.085),l(-.361,.199),l(-.615,.693),l(-.774,1.02),l(-.588,.284),l(-.766,-.013),l(-.547,-.013),l(-.927,.143),l(-.4,.185),l(-.663,-.395),l(-.294,-.084),l(-.734,.016),l(-1.572,.173),l(-.938,.157),l(-.459,-.041),l(-.672,.044),l(-.398,.227),l(-.583,.793),l(-.344,.128),l(-.958,-.125),l(-.158,.057),l(-.57,.708),l(-.465,.368),l(-.919,.271),l(-.586,.086),l(-1.516,-.082),l(-.638,-.055),l(-.688,-.197),l(-.633,-.366),l(-.778,-.677),l(-.74,-.353),l(-.374,-.041),l(-.151,-.07),l(-.19,-1.229),l(.055,-.255),l(.489,.112),l(.45,-.086),l(.332,-.425),l(.197,-.467),l(.267,-1.357),l(-.043,-1.215),l(-.156,-.622),l(-.258,-.593),l(-1.117,-1.906),l(-.208,-.635),l(-.144,-.834),l(.027,-.989),l(-.16,-.692),l(-.467,-1.072),l(-.663,-.945),l(-.603,-.734),l(-.214,-.254),l(.128,-.904),l(-.215,-.536),l(-.733,-1.115),l(-.972,-1.018),l(-.273,-.583),l(.126,-.233),l(.188,.187),l(.152,.443),l(.183,.163),l(.235,.35),l(.327,.188),l(.354,.023),l(-.348,-1.144),l(-.437,-.396),l(-.226,-.326),l(.08,-.304),l(.748,.84),l(.495,.979),l(.477,.065),l(-.099,-.555),l(.289,-.039),l(.004,-.564),l(-.282,-.48),l(-1.03,-1.368),l(-.354,-.691),l(-.119,-.579),l(-.038,-.734),l(.355,-.595),l(.323,-.523),l(.21,-.664),l(-.083,-1.031),l(-.254,-.635),l(.033,-.368),l(.438,-.692),l(.109,-.325),l(.064,-.156),l(.271,.649),l(.011,.424),l(.105,.184),l(.35,.027),l(.171,-.113),l(.187,-.565),l(.141,-.48),l(.765,-.468),l(1.22,-.624),l(.484,-.326),l(.676,-.581),l(.585,-.467),l(.632,-.327),l(.79,-.114),l(.697,-.016),l(.7,-.002),l(.431,-.043),l(.352,-.185),l(.474,-.453),l(.494,-.128),l(.929,-.072),l(.279,-.143),l(.291,-.551),l(.158,-.1),l(.444,.027),l(.877,.224),l(.626,-.043),l(.911,-.299),l(1.084,-.469),l(.359,-.213),l(.716,-.665),l(.427,-.58),l(.29,-.622),l(.132,-.297),l(.41,-.369),l(.968,-.651),l(.079,-.17),l(-.067,-.409),l(-.242,-.805),l(-.016,-.495),l(1.063,-1.118),l(.387,-.692),l(.291,.169),l(.341,.437),l(.619,1.355),l(.262,.253),l(.177,-.579),l(.021,-.466),l(.436,.238),l(.272,.07),l(.189,-.607),l(-.06,-.142),l(-.563,-.238),l(-.175,-.24),l(.007,-.565),l(.044,-.112),l(.897,.04),l(.661,.253),l(.642,-.029),l(.334,-.029),l(.289,.074),l(-.699,-.455),l(-.431,-.141),l(.128,-.537),l(-.07,-.296),l(.135,-.509),l(.422,-.354),l(.165,-.07),l(.732,.394),l(.202,-.043),l(-.112,-.452),l(.11,-.48),l(.146,-.367),l(-.041,-.522),l(.358,-.171),l(.4,-.113),l(.813,.04),l(.529,-1.088),l(.371,-.298),l(.35,.169),l(.268,.451),l(.265,-.552),l(.222,-.227),l(.197,-.48),l(.695,.62),l(.513,.084),l(.293,.211),l(.331,.536),l(.632,.592),l(.122,.706),l(-.072,.594),l(.181,.197),l(.256,-.283),l(.462,-.679),l(.155,-.128),l(1.16,.082),l(.479,.155),l(.637,.492),l(.332,.141),l(.156,-.48),l(.302,-.297),l(.022,-.24),l(-.266,-.324),l(-.601,-.395),l(-.079,-.184),l(.008,-.24),l(.145,-.099),l(.604,-.538),l(.007,-.452),l(.191,-.213),l(.518,-.283),l(.268,-.241),l(.151,-.269),l(-.094,-.184),l(.003,-.296),l(.512,-.863),l(.121,-.057),l(.317,-.029),l(.397,-.029),l(.248,-.17),l(-.205,-.409),l(.377,-.396),l(.344,-.071),l(.793,.366),l(.616,-.072),l(1.291,-.088),l(.512,-.128),l(.232,-.17),l(.04,-.057),l(-.077,-.197),l(-.2,-.734),l(-.248,-.282),l(-.471,-.268),l(-.374,.086),l(-.244,-.141),l(.035,-.212),l(.367,-.143),l(.396,-.043),l(.617,.521),l(.255,.099),l(.34,-.1),l(.364,.31),l(.676,.465),l(.36,.154),l(1.297,.294),l(.591,.084),l(.413,-.143),l(.372,.014),l(.396,.606),l(.419,.112),l(.141,-.029),l(.562,-.438),l(.454,.027),l(.652,.38),l(.331,.479),l(.46,-.143),l(.122,-.791),l(.181,-.085),l(.455,.465),l(.337,.099),l(.152,.154),l(-.436,.411),l(-.126,.424),l(-.176,.212),l(-.011,.438),l(-.12,.255),l(-.513,.015),l(-.51,.228),l(-.396,.34),l(-.004,.551),l(.301,.353),l(-.187,.692),l(-.381,.58),l(-.559,.481),l(-.155,.48),l(.063,.17),l(.469,.437),l(1.038,.619),l(.81,.677),l(.508,.606),l(.246,.099),l(.349,-.114),l(.264,.027),l(.782,.352),l(.742,.465),l(.434,.451),l(.679,.535),l(.335,.127),l(.442,.027),l(.784,.182),l(.25,.184),l(.218,.621),l(.167,.169),l(.507,.31),l(.76,.423),l(.537,.154),l(.422,-.072),l(.414,-.17),l(.603,-.199),l(.208,-.156),l(.736,-1.344),l(.403,-1.131),l(.194,-1.314),l(.259,-.721),l(.43,-.679),l(-.131,-.424),l(-.409,-.621),l(.022,-.311),l(.236,-.637),l(.187,-.48),l(-.164,-.282),l(-.183,-.395),l(.088,-.692),l(.104,-1.004),l(.225,-.297),l(.329,-.156),l(.158,-.311),l(-.534,-.521),l(.033,-.198),l(.576,-.947),l(.312,-.934),l(.072,-.833),l(.191,-.241),l(.279,-.297), +N(270.934,276.123),l(.054,-.338),l(-.194,-.577),l(.011,-.522),l(.24,-.495),l(.48,-.524),l(.118,-.325),l(-.168,-.986),l(-.049,-.847),l(.103,-.522),l(.595,-2.359),l(.065,-.452),l(.443,-.524),l(.55,-.003),l(1.042,-.246),l(.25,-.101),l(.266,.098),l(.47,.364),l(.379,.407),l(.59,.814),l(.232,.38),l(.27,-.016),l(.693,-.427),l(.365,.393),l(.432,.576),l(.617,.194),l(.55,.194),l(.999,.587),l(.474,.435),l(.853,1.109),l(.131,.197),l(.163,.027),l(.333,.379),l(-.017,.269),l(-.634,.766),l(-.103,.269),l(.258,.746),l(.101,.313),l(-.059,.053),l(-.803,1.103),l(-.625,.552),l(-.775,.454),l(-.441,.156),l(-.818,.1),l(-.874,-.337),l(-.551,.044),l(-.551,.114),l(-.64,.283),l(-.38,-.042),l(-.846,-.676),l(-.637,-.252),l(-.76,-.154),l(-.469,.128),l(-.507,.072),l(-.327,-.127),l(-.548,-.563),l(-.354,-.159), +N(418.763,73.869),l(.391,-.499),l(.389,-.262),l(.283,.081),l(.663,-.062),l(.762,-.075),l(.324,-.137),l(.891,-.787),l(.979,-.2),l(.224,.025),l(.198,-.219),l(.175,.032),l(-.349,.531),l(.11,.106),l(.026,.481),l(-.288,.156),l(-.17,.368),l(-1.675,.069),l(-.376,-.106),l(-.428,.031),l(-.14,-.062),l(-.239,.081),l(-.275,.031),l(-.153,.417),l(-.249,.218),l(-.353,.118),l(-.08,.112),l(-.229,-.155),l(-.411,-.292),M(421.68,78.002),l(-1.839,.129),l(-.116,-.016),l(.064,-.404),l(-.19,-.638),l(-.174,.015),l(-.36,-.293),l(-.233,.184),l(-.398,-.172),l(.2,-.355),l(.434,-.293),l(-.007,-.181),l(-.445,-.541),l(.018,-.256),l(.131,-.498),l(.279,-.106),l(.318,.15),l(.495,.12),l(.43,-.574),l(.299,-.091),l(.296,.437),l(.391,-.046),l(.022,-.528),l(.107,-.363),l(1.032,-.017),l(.848,.089),l(.03,.544),l(.187,.301),l(1.138,.058),l(.14,.166),l(-.307,.604),l(-.565,.142),l(-.119,-.261),l(-.331,.031),l(-.263,.136),l(.121,.278),l(-.184,.414),l(-.312,.077),l(-.069,.244),l(-.635,.035),l(.157,.229),l(-.291,.094),l(-.191,.24),l(-.061,.285),l(.003,.21),l(-.215,.338),l(.166,.084),M(427.177,77.967),l(-.139,-.149),l(-.312,-.344),l(-.405,.031),l(-.665,-.059),l(-.123,-.329),l(-.285,-.66),l(.433,-.091),l(.603,-.467),l(.356,.495),l(.521,.179),l(.2,-.271),l(.078,-.586),l(.333,-.046),l(.459,.044),l(.056,.571),l(-.134,.36),l(-.144,.09),l(-.413,.286),l(.603,.299),l(-.285,.166),l(-.499,.39),l(-.238,.09), +N(417.259,94.301),l(-.135,-.233),l(.216,-.701),l(-.091,-.076),l(.075,-.295),l(.321,-.372),l(.054,-.358),l(.054,-.213),l(.954,-.806),l(-.605,-.193),l(-.479,.014),l(-.456,-.09),l(-.095,-.186),l(-.233,-.007),l(-.072,.048),l(-.689,.062),l(-.045,-.145),l(-.395,.055),l(-.337,-.277),l(-.428,-.319),l(-.074,-.353),l(.248,-.144),l(.044,-.288),l(-.466,-.096),l(-.41,-.312),l(-.062,-.301),l(.422,-.376),l(-.038,-.468),l(-.282,-.365),l(-.344,-.177),l(.165,-.278),l(-.143,-.217),l(-.182,-.037),l(.08,-.097),l(.235,-.133),l(.236,-.133),l(-.193,-.121),l(.201,-.275),l(.095,-.148),l(-.152,-.292),l(-.082,-.265),l(-.376,-.182),l(.07,-.182),l(.341,-.078),l(.175,-.092),l(.378,.134),l(.664,-.151),l(.32,-.152),l(.128,-.376),l(.412,-.207),l(.003,-.328),l(-.16,-.17),l(-.188,.061),l(-.44,-.134),l(.029,-.184),l(.113,-.181),l(.571,.036),l(.084,-.401),l(.345,-.361),l(-.151,-.438),l(.066,-.147),l(-.465,-.192),l(.126,-.43),l(.285,-.181),l(.371,-.028),l(1.12,-.062),l(.293,-.012),l(.095,.16),l(.195,.271),l(-.155,.158),l(.324,.113),l(.148,-.068),l(.042,-.192),l(-.159,-.204),l(.259,.012),l(.437,.169),l(-.163,-.362),l(.247,-.419),l(.687,.113),l(.614,-.091),l(-.596,-.17),l(-.084,-.227),l(.282,-.102),l(-.252,-.114),l(-.12,-.147),l(.166,-.08),l(.068,-.136),l(-.675,.08),l(-.06,-.182),l(.664,-.125),l(.218,-.193),l(-.464,-.42),l(-.324,-.341),l(.045,-.28),l(.116,.016),l(1.839,-.129),l(.254,.13),l(.565,.341),l(.271,.297),l(-.02,.228),l(-.252,.175),l(.445,-.05),l(.171,.216),l(.157,-.078),l(.283,.021),l(.235,.156),l(.45,.073),l(.866,-.121),l(.077,.208),l(-.07,.149),l(-.057,.125),l(-.665,.295),l(.316,.193),l(.649,-.136),l(.113,.182),l(.457,-.006),l(.349,-.391),l(1.059,-.136),l(.602,-.234),l(.757,-.266),l(.249,.113),l(.396,-.17),l(.184,.182),l(.085,.159),l(.634,.29),l(.182,.074),l(.526,-.12),l(.156,.12),l(.059,.34),l(.036,.227),l(.154,.102),l(.354,.125),l(.372,-.022),l(.028,.13),l(.201,.025),l(.319,.835),l(-.219,.52),l(-.391,.147),l(-.051,.328),l(.391,.102),l(.683,.429),l(-.217,.395),l(.094,.18),l(.312,.146),l(-.021,.304),l(.131,.102),l(-.118,.292),l(-.214,.124),l(-.007,.191),l(.325,.27),l(-.114,.258),l(.468,.188),l(.281,.485),l(-.435,.698),l(-.142,.115),l(-.344,-.072),l(-.031,-.278),l(-.308,-.121),l(-.436,.072),l(.282,.218),l(-.254,.084),l(-.284,.097),l(-.524,.048),l(-.124,.169),l(-.735,.024),l(-.112,.217),l(-.176,-.072),l(-.358,.061),l(-.097,.229),l(-.382,.012),l(-.078,.181),l(-.442,0),l(-.422,.201),l(-.293,-.033),l(-.26,.181),l(-.243,.168),l(.037,.056),l(.258,.378),l(.413,.098),l(-.155,.25),l(-.08,.406),l(.159,.085),l(.036,.233),l(.244,.173),l(.478,.265),l(.188,-.072),l(.573,.515),l(.431,.17),l(.184,.201),l(.219,-.084),l(.165,.18),l(.207,.036),l(.447,.633),l(-.682,.26),l(-.437,-.151),l(-.132,.027),l(-.039,.337),l(-.162,.172),l(-.968,.295),l(-.364,.227),l(.538,.571),l(-.197,.295),l(.334,.014),l(.056,.158),l(-.098,.343),l(-.082,.055),l(-.441,-.178),l(.049,-.165),l(-.146,-.117),l(-.564,.062),l(-.195,-.138),l(-.433,.035),l(-.092,.178),l(-1.25,.035),l(-.125,.171),l(-.319,.014),l(-.044,.13),L(425.4,94.7),l(-.594,.021),l(-.059,-.144),l(-.093,-.145),l(-.493,-.089),l(-.262,.055),l(-.237,-.041),l(.032,.274),l(-.452,.343),l(-.215,0),l(.078,-.195),l(-.26,-.039),l(.011,-.165),l(-.194,-.048),l(-.104,-.137),l(-.249,-.007),l(-.096,-.11),l(-.164,.137),l(-.368,-.014),l(-.664,-.261),l(-.852,-.007),l(-.149,-.089),l(-.199,.014),l(-.017,-.151),l(-.709,.199),l(.179,.199),l(-.354,.021),l(-.278,-.11),l(-.567,.158),l(-.271,-.096),l(-.272,.117),l(-.271,-.089),M(432.012,80.473),l(-.171,-.038),l(-.088,-.049),l(-.447,.08),l(-.111,-.264),l(.002,-.213),l(.647,.281),l(.168,.203), +N(450.734,91.05),l(-.831,-.33),l(-.424,-.101),l(-.104,-.216),l(-.703,-.186),l(-.129,-.13),l(-.561,.076),l(-.508,-.041),l(-.073,.137),l(-.373,.18),l(-.46,-.254),l(-.483,.046),l(-.168,-.056),l(-.558,.204),l(-.104,.177),l(-.149,.135),l(-.18,-.12),l(-.389,.083),l(-.003,-.204),l(.026,-.083),l(-.066,-.18),l(-.331,.025),l(-.073,-.169),l(-.194,-.24),l(-.261,.024),l(-.062,.112),l(-.193,-.016),l(-.183,.24),l(-.43,.048),l(-.03,-.228),l(-.285,-.041),l(-.105,-.331),l(-.382,-.096),l(-.188,-.208),l(.02,-.249),l(-.802,-.132),l(-.311,-.181),l(-.368,.161),l(-.293,-.013),l(-.013,-.221),l(.001,-.253),l(-.329,.084),l(.181,-.283),l(-.709,.005),l(-.258,-.121),l(-.509,-.193),l(-.286,-.024),l(-.003,.145),l(.282,.302),l(-.41,.12),l(-.22,.187),l(-.318,-.072),l(-.296,-.38),l(-.55,-.247),l(.224,-.211),l(.208,-.024),l(.099,-.121),l(-.199,-.181),l(-.257,-.024),l(-.061,.066),l(-.466,.066),l(.005,-.169),l(-.278,.037),l(-.132,-.181),l(-.568,-.054),l(-.201,-.025),l(-.363,-.163),l(-.093,-.26),l(-.211,-.091),l(-.361,.018),l(-.063,.084),l(.062,.073),l(-.024,.151),l(-.375,0),l(.435,-.698),l(-.281,-.485),l(-.468,-.188),l(.114,-.258),l(-.325,-.27),l(.007,-.191),l(.214,-.124),l(.118,-.292),l(-.131,-.102),l(.021,-.304),l(-.312,-.146),l(-.094,-.18),l(.217,-.395),l(-.683,-.429),l(-.391,-.102),l(.051,-.328),l(.391,-.147),l(.219,-.52),l(-.319,-.835),l(.34,.043),l(.23,.125),l(-.093,-.193),l(.156,-.153),l(-.019,-.147),l(-.166,-.13),l(-.021,-.129),l(-.012,-.075),l(.93,-.154),l(.431,-.051),l(.516,-.152),l(1.304,-.128),l(.48,-.158),l(.797,-.479),l(1.117,-.298),l(1.515,-.303),l(1.382,-.086),l(1.067,.417),l(-.882,-.294),l(-.054,.147),l(.256,.172),l(.132,.466),l(.355,.135),l(.648,.061),l(.645,-.11),l(1.063,-.409),l(.054,.004),l(-.978,.417),l(-.19,.11),l(-.004,.123),l(.218,.012),l(.286,-.123),l(.613,-.208),l(.543,-.253),l(.842,.006),l(2.246,.115),l(2.96,-.101),l(.641,-.021),l(.04,.014),l(.679,.243),l(.284,.487),l(.099,.186),l(.016,.029),l(.09,.171),l(.16,.302),l(.615,1.5),l(.172,.502),l(-.023,.236),l(-.263,.208),l(-.44,.03),l(-.571,.244),l(-.291,.328),l(-.128,.292),l(.289,.012),l(.421,.146),l(.149,.176),l(.218,.146),l(.013,.25),l(-.315,.752),l(.126,.137),l(.161,.175),l(-.074,.242),l(.816,.835),l(.316,.193),l(-.298,.048),l(-.085,.133),l(.328,.302),l(-.009,.314),l(-.255,.24),l(-.429,.013),l(-.286,.181),l(-.599,.398),l(-1.509,1.218),l(-.082,.306),l(.044,.552),l(.349,.383),l(-.653,-.018),M(431.844,80.27),l(.232,.024),l(.069,.208),l(-.134,-.029),l(-.168,-.203),M(432.739,80.361),l(-.03,.129),l(-.278,-.024),l(-.191,.03),l(-.046,-.208),l(.174,-.012),l(.266,0),l(.106,.085), +N(416.488,81.945),l(.151,.438),l(-.345,.361),l(-.084,.401),l(-.571,-.036),l(-.113,.181),l(-.029,.184),l(.44,.134),l(.188,-.061),l(.16,.17),l(-.003,.328),l(-.412,.207),l(-.128,.376),l(-.32,.152),l(-.664,.151),l(-.378,-.134),l(-.175,.092),l(-.341,.078),l(-.07,.182),l(.376,.182),l(.082,.265),l(.152,.292),l(-.095,.148),l(-.201,.275),l(.193,.121),l(-.236,.133),l(-.235,.133),l(-.08,.097),l(.182,.037),l(.143,.217),l(-.165,.278),l(-.672,.024),l(-.001,-.338),l(.172,-.097),l(.11,-.423),l(-.754,-.375),l(-.535,.109),l(-.292,-.375),l(-.228,-.061),l(-.173,.121),l(-.313,-.242),l(-.267,.182),l(-.307,0),l(-.307,-.012),l(.025,.157),l(-.52,.034),l(-.407,-.042),l(-.477,-.098),l(-.07,-.162),l(-.496,-.264),l(.795,-.472),l(.858,-.621),l(.273,-.354),l(.563,-1.167),l(.173,-.104),l(.644,-.12),l(.367,.251),l(.136,.268),l(-.28,.203),l(-.228,-.056),l(.066,.496),l(-.191,.124),l(1.163,.225),l(.225,-.236),l(.406,-.113),l(.134,-.417),l(-.458,-.022),l(-.123,-.124),l(-.02,-.203),l(.236,-.158),l(-.171,-.023),l(-.558,-.067),l(.072,-.328),l(-.034,-.13),l(-.023,-.034),l(.128,-.283),l(.572,-.198),l(.709,-.238),l(.654,.03),l(1.089,-.151),l(.245,.275),l(.329,.045),l(.076,.181),l(.259,0), +N(431.57,91.965),l(-.447,-.633),l(-.207,-.036),l(-.165,-.18),l(-.219,.084),L(430.349,91),l(-.431,-.17),l(-.573,-.515),l(-.188,.072),l(-.478,-.265),l(-.244,-.173),l(-.036,-.233),l(-.159,-.085),l(.08,-.406),l(.155,-.25),l(-.413,-.098),l(-.258,-.378),l(-.037,-.056),l(.243,-.168),l(.26,-.181),l(.293,.033),l(.422,-.201),l(.442,0),l(.078,-.181),l(.382,-.012),l(.097,-.229),l(.358,-.061),l(.176,.072),l(.112,-.217),l(.735,-.024),l(.124,-.169),l(.524,-.048),l(.284,-.097),l(.254,-.084),l(-.282,-.218),l(.436,-.072),l(.308,.121),l(.031,.278),l(.344,.072),l(.142,-.115),l(.375,0),l(.024,-.151),l(-.062,-.073),l(.063,-.084),l(.361,-.018),l(.211,.091),l(.093,.26),l(.363,.163),l(.201,.025),l(.568,.054),l(.132,.181),l(.278,-.037),l(-.005,.169),l(.466,-.066),l(.061,-.066),l(.257,.024),l(.199,.181),l(-.099,.121),l(-.208,.024),l(-.224,.211),l(.55,.247),l(.296,.38),l(.318,.072),l(.22,-.187),l(.41,-.12),l(-.282,-.302),l(.003,-.145),l(.286,.024),l(.509,.193),l(.258,.121),l(.709,-.005),l(-.181,.283),l(.329,-.084),l(-.001,.253),l(.013,.221),l(.293,.013),l(.368,-.161),l(.311,.181),l(.802,.132),l(-.02,.249),l(.188,.208),l(.382,.096),l(.105,.331),l(-.071,-.012),l(-.065,.066),l(-.066,.04),l(-.105,-.026),L(442,89.998),l(-.119,.013),l(-.065,.04),l(-.132,.066),l(-.053,.079),l(-.118,.092),l(-.119,.053),l(-.132,.079),l(-.105,.013),l(-.118,.013),l(-.053,.092),l(-.026,.092),l(-.026,.132),l(-.053,.079),l(-.053,.105),l(-.145,.066),l(-.105,.04),l(-.092,-.026),l(-.079,.079),l(-.04,.092),l(-.053,.079),l(-.039,0),l(-.105,.026),l(-.066,.026),l(-.079,.053),l(-.118,.053),l(-.132,0),l(-.145,.04),l(-.093,.026),l(-.065,-.026),l(-.065,-.026),l(-.093,0),l(-.065,.026),l(-.158,0),l(-.132,-.053),l(-.092,-.053),l(-.093,.026),l(-.171,.053),l(-.026,.04),l(-.146,.119),l(-.092,.066),l(-.014,.131),l(-.065,.105),l(-.039,.044),l(-.055,-.095),l(-.545,-.2),l(-1.332,.181),l(-1.019,-.227),l(-1.374,-.341),l(-.746,.773),l(-.598,.163),l(-.483,-.099),l(-.354,-.129),l(-.145,-.014), +N(421.683,94.397),l(.368,.014),l(.164,-.137),l(.096,.11),l(.249,.007),l(.104,.137),l(.194,.048),l(-.011,.165),l(.26,.039),l(-.078,.195),l(.215,0),l(.452,-.343),l(-.032,-.274),l(.237,.041),l(.262,-.055),l(.493,.089),l(.093,.145),l(.059,.144),L(425.4,94.7),l(.377,-.103),l(.044,-.13),l(.319,-.014),l(.125,-.171),l(1.25,-.035),l(.092,-.178),l(.433,-.035),l(.195,.138),l(.564,-.062),l(.146,.117),l(-.049,.165),l(.441,.178),l(.082,-.055),l(.098,-.343),l(-.056,-.158),l(-.334,-.014),l(.197,-.295),l(-.538,-.571),l(.364,-.227),l(.968,-.295),l(.162,-.172),l(.039,-.337),l(.132,-.027),l(.437,.151),l(.682,-.26),l(.145,.014),l(.354,.129),l(.483,.099),l(.598,-.163),l(.746,-.773),l(1.374,.341),l(1.019,.227),l(1.332,-.181),l(.545,.2),l(.055,.095),l(.053,.093),l(-.097,.581),l(.155,.26),l(.761,.547),l(-.636,.291),l(-.019,.367),l(-.701,.054),l(-.164,-.134),l(-.325,0),l(-.223,.197),l(.452,.063),l(.136,.196),l(-.157,.206),l(-.409,.062),l(-.04,.375),l(.204,.188),l(-.154,.294),l(-.346,.299),l(-.693,.157),l(.082,.393),l(-.89,-.116),l(-.298,.196),l(-.85,-.08),l(-.566,.107),l(-.646,.5),l(-.287,-.152),l(-.612,.009),l(-.179,-.107),l(-1.04,-.065),l(-.478,-.112),l(-.894,-.082),l(-1.311,-.247),l(-.32,-.391),l(-.318,-.096),l(-.023,-.363),l(-.856,.227),l(-.301,-.103),l(-.445,.11),l(-.183,-.083),l(-.366,.096),l(-.329,.411),l(-.597,-.034),l(-.631,-.171),l(.029,-.171),l(-.215,-.117),l(-.579,.332),l(-.55,-.242),l(-.008,-.144),l(-.622,-.062),l(.09,-.192),l(-.214,-.288),l(.266,-.274),l(-.193,-.336), +N(431.763,171.063),l(-.067,.354),l(.091,.72),l(.108,.508),l(.225,.168),l(.562,.11),l(.144,.183),l(.077,.353),l(-.089,1.116),l(-.146,.227),l(-.274,.171),l(-.885,.217),l(-.291,.256),l(-.664,1.275),l(-.503,1.203),l(-.243,1.004),l(-.354,.129),l(-.369,.03),l(-.129,.354),l(-.146,1.229),l(-.192,.312),l(-.385,.045),l(-.257,.284),l(-.417,.836),l(-.944,2.223),l(-.304,.624),l(-.352,.496),l(-.368,.355),l(-.239,.114),l(-.145,-.056),l(-.722,-.97),l(-.145,-.14),l(-1.104,-.05),l(-.272,.03),l(-1.31,1.265),l(-.941,.839),l(-.495,.526),l(.02,.974),l(-.189,.552),l(-.376,.686),l(-.188,-.119),l(-.224,-.042),l(-.176,-.127),l(-.145,.212),l(.144,.296),l(-.063,.127),l(-.353,.198),l(-.56,.03),l(-.977,.101),l(-.607,-.267),l(-.288,.043),l(-.271,.368),l(-.177,.113),l(-.432,-.07),l(-1.247,-.011),l(-.528,-.225),l(-.543,-.451),l(-.416,-.72),l(-.192,-.649),l(.048,-.254),l(.208,-.254),l(-.144,-.296),l(-.513,-.069),l(-.128,-.254),l(-.464,-.55),l(-.561,-.465),l(-.608,-.253),l(-.641,-.253),l(-.272,-.31),l(-.513,.072),l(-.24,.297),l(-.336,.071),l(-.881,.044),l(-.659,.03),l(-.006,-.234),l(.121,-1.188),l(-.217,-1.439),l(.09,-.989),l(.012,-.876),l(-.003,-.48),l(-.002,-.381),l(.237,-.397),l(.257,-.03),l(.433,-.13),l(.078,-.368),l(-.116,-.592),l(.095,-.34),l(.656,-.414),l(.223,-.298),l(.19,-.566),l(.316,-.962),l(-.388,-.718),l(-.164,-.762),l(.062,-.777),l(.092,-.961),l(.158,-.849),l(.353,-.482),l(.687,-1.614),l(.676,-.4),l(1.064,-.188),l(1.174,-.108),l(1.111,.121),l(.821,.277),l(1.095,1.223),l(.209,.098),l(.37,-.002),l(1.337,-.544),l(.467,-.116),l(.354,.083),l(1.173,.742),l(.965,.277),l(.934,-.005),l(.273,-.059),l(.629,-.399),l(.403,-.327),l(.774,-.287),l(.628,-.103),l(.709,-.047),l(.531,.04),l(.884,.221),l(.724,.193),l(.609,.208),l(.259,-.058),l(.761,-.697),l(.453,-.299),l(.437,-.2),l(.951,-.034),l(.173,.394),l(.575,.52),l(.351,.407), +N(425.506,195.522),l(-1.965,-.017),l(-1.005,.007),l(.029,-.176),l(-.208,-.536),l(.271,-.989),l(-.159,-.72),l(-.191,-.522),l(-.399,-.649),l(.433,-.396),l(-.287,-.367),l(-.24,-.056),l(-.576,.058),l(-.559,-.268),l(-.176,-.324),l(-.063,-.537),l(-.111,-.211),l(-.527,-.14),l(-.101,-.064),l(.376,-.686),l(.189,-.552),l(-.02,-.974),l(.495,-.526),l(.941,-.839),l(1.31,-1.265),l(.272,-.03),l(1.104,.05),l(.145,.14),l(.722,.97),l(.145,.056),l(.239,-.114),l(.368,-.355),l(.352,-.496),l(.304,-.624),l(.944,-2.223),l(.417,-.836),l(.257,-.284),l(.385,-.045),l(.192,-.312),l(.146,-1.229),l(.129,-.354),l(.369,-.03),l(.354,-.129),l(.243,-1.004),l(.503,-1.203),l(.664,-1.275),l(.291,-.256),l(.885,-.217),l(.274,-.171),l(.146,-.227),l(.089,-1.116),l(-.077,-.353),l(-.144,-.183),l(-.562,-.11),l(-.225,-.168),l(-.108,-.508),l(-.091,-.72),l(.067,-.354),l(.627,.109),l(.208,.083),l(.923,1.238),l(.395,.887),l(.119,1.2),l(-.134,.651),l(.169,1.228),l(.205,.578),l(.381,.633),l(.208,.21),l(.047,.127),l(-.225,.143),l(-.674,.032),l(-1.187,-.191),l(-.481,-.082),l(-.24,.1),l(-.29,.312),l(-.323,.539),l(1.088,1.067),l(1.343,1.179),l(.638,1.07),l(.382,1.057),l(.208,.183),l(-.208,.114),l(-.354,.327),l(-.866,1.743),l(-.4,.511),l(-.528,.399),l(-.144,.198),l(-.064,.424),l(.112,.776),l(.273,1.185),l(.207,.592),l(.4,.661),l(.432,.605),l(.064,.791),l(.112,.324),l(1.217,1.236),l(.498,.802),l(.194,.804),l(.209,.451),l(-.159,.185),l(.1,.861),l(-.271,.086),l(-.863,-.292),l(-.864,-.334),l(-.576,-.194),l(-.56,-.124),l(-.479,-.04),l(-.271,-.055),l(-.878,.076),l(-.863,-.023),l(-.56,-.109),l(-1.022,-.149),l(-.831,-.038),l(-1.773,-.088),l(-.88,-.093),l(-.045,.495), +N(551.793,147.278),l(-.788,-.111),l(-.458,-.253),l(-.379,-.367),l(-.248,-1.101),l(-.112,-.141),l(-.342,-.141),l(-.662,-.083),l(-.105,-.07),l(-.014,-.268),l(.116,-.466),l(-.178,-.451),l(-.418,-.38),l(-.294,-.013),l(-1.181,.412),l(-1.229,.087),l(-.81,.143),l(-.947,.073),l(-.415,-.083),l(-.263,-.226),l(-.135,-.197),l(-.909,.143),l(-.548,.382),l(-.856,.016),l(-1.264,-.011),l(-.691,.128),l(-.723,.115),l(-.541,.03),l(.182,-.954),l(.049,-.354),l(.31,-.792),l(.285,-.383),l(.794,-.47),l(.697,-.258),l(1,-.077),l(.209,-.072),l(.188,-.255),l(.036,-.974),l(-.186,-.281),l(-.652,-.053),l(-.185,-.394),l(-.111,-1.34),l(-.168,-.38),l(-.409,-.224),l(-1.144,-.388),l(-.695,-.391),l(-.353,-.464),l(-.71,-1.068),l(-.802,-1.083),l(.887,.32),l(.63,.194),l(1.069,.248),l(.854,.235),l(.541,.039),l(.742,.024),l(1.187,-.218),l(.349,-.002),l(1.005,.135),l(1.234,-.12),l(.964,-.175),l(1.183,-.19),l(1.066,-.274),l(.247,-.156),l(.069,-.184),l(.099,-.903),l(.232,-.876),l(.188,-.34),l(.412,-.369),l(.597,-.441),l(.283,-.072),l(.644,.039),l(.516,.082),l(.254,-.086),l(.321,-.693),l(.362,-.271),l(.559,-.243),l(.562,.025),l(1.001,.375),l(.237,-.086),l(.34,-.383),l(.021,-.084),l(.139,-1.214),l(.288,-.834),l(.224,-.424),l(.292,-.228),l(.416,-.115),l(.513,-.031),l(.315,-.115),l(.199,-.255),l(-.088,-.437),l(-.129,-.281),L(556.193,125),l(-.35,-.336),l(.355,-.129),l(.997,.122),l(.698,.039),l(.513,-.215),l(.289,-.255),l(-.033,-.31),l(-.223,-.478),l(.13,-.283),l(.4,-.341),l(.524,-.355),l(.324,-.426),l(-.198,-.477),l(.119,-.483),l(-.232,-.171),l(-.01,-.336),l(-.411,-.271),l(-.01,-.32),l(.464,-.413),l(.258,-.214),l(.246,.023),l(.559,-.395),l(.272,-.19),l(.53,-.292),l(1.148,-.152),l(1.345,-.012),l(.647,.144),l(.338,-.179),l(.332,.005),l(.455,-.297),l(.358,-.004),l(.148,-.142),l(.313,.14),l(.105,.112),l(.281,-.21),l(.296,.047),l(.554,.117),l(.004,.456),l(.282,-.128),l(.625,-.009),l(.373,.323),l(.213,.247),l(.007,.501),l(-.312,.516),l(.301,.07),l(.198,.218),l(.252,.281),l(.52,-.196),l(.239,0),l(.104,.199),l(.178,.09),l(.565,.436),l(1.337,.104),l(.305,.111),l(.147,.126),l(-.207,.084),l(-.688,.37),l(-.411,.232),l(-.155,.43),l(-.071,.479),l(-.234,.116),l(-.125,-.179),l(-.621,-.102),l(-.438,.132),l(-.271,.298),l(-.262,-.116),l(-.557,.265),l(-.928,-.149),l(-.568,-.138),l(-1.708,-.325),l(-.894,.265),l(-.38,.611),l(.09,.166),l(.336,0),l(.047,.314),l(-.202,.149),l(.101,.199),l(.598,-.017),l(-.002,.347),l(-.384,.099),l(-.139,.413),l(.389,.232),l(-.116,.479),l(-.215,.132),l(.089,.248),l(.606,.298),l(-.003,.532),l(.782,-.003),l(-.039,.43),l(.188,.248),l(.702,-.05),l(.668,.377),l(.012,.211),l(-.2,.255),l(-.504,.2),l(-.643,.196),l(-.517,.248),l(.032,.366),l(.188,.377),l(-.237,.977),l(-1.512,1.503),l(.261,.38),l(-.358,.281),l(-.609,.133),l(-.353,.467),l(-.509,1.216),l(-.478,.547),l(-1.193,.496),l(-.177,.364),l(-.277,.481),l(-.563,.61),l(-.076,.38),l(-.71,.259),l(-.734,-.011),l(-.895,.314),l(-.361,-.094),l(-.158,-.518),l(-.207,-.132),l(-.404,.083),l(-.535,.463),l(-.144,.446),l(-.979,.893),l(-.186,.543),l(-.079,.269),l(.116,.38),l(.541,.163),l(.504,.085),l(.425,.014),l(-.114,.689),l(-.154,.735),l(.412,.411),l(.33,.099),l(.537,-.099),l(.112,.441),l(.216,.507),l(.654,1.333),l(-.232,.149),l(.241,.463),l(-.317,.066),l(-.15,.248),l(-.55,.083),l(-.145,-.335),l(-.183,-.062),l(-.78,.215),l(-.2,.331),l(-.735,-.099),l(-.229,-.149),l(-.835,-.021),l(-.835,-.009),l(-.259,-.052),l(.015,.728),l(-.866,.017),l(-.296,.431),l(-.37,.036), +N(606.155,150.953),l(-.037,-.466),l(-.627,-2.479),l(-.064,-.578),l(-.4,.044),l(-.281,.115),l(-.395,1.159),l(-.224,.354),l(-.529,-.448),l(-.249,-.267),l(-.23,-.281),l(-.001,-.381),l(-.009,-.522),l(.131,-.283),l(.651,-.356),l(.498,-.13),l(.938,-.767),l(.159,-.34),l(.012,-.79),l(-.057,-.127),l(-.111,-.098),l(-2.473,-.198),l(-.559,.003),l(-.916,.062),l(-.547,-.053),l(-.537,-.109),l(-.095,-.099),l(-.079,-.719),l(-.053,-.479),l(-.129,-.324),l(-.417,-.054),l(-.489,.06),l(-.372,-.266),l(-.339,-.266),l(-1.252,-.303),l(-.234,.171),l(-.555,.525),l(-.124,.283),l(.083,.155),l(.494,.237),l(1.224,.938),l(.126,.112),l(-.047,.155),l(-.382,.101),l(-.502,.13),l(-.4,.299),l(-.548,.61),l(.339,.323),l(1.042,.431),l(.193,.21),l(-.029,.269),l(-.505,.765),l(.04,.254),l(.352,.45),l(.325,1.409),l(.402,1.775),l(.147,.532),l(-.172,.322),l(.068,.183),l(-.321,.071),l(-.35,-.056),l(-.148,-.706),l(-.198,-.084),l(-.253,.354),l(-.171,.354),l(-.172,.057),l(-.115,-.099),l(-.28,-.592),l(-.152,-.169),l(-.412,.537),l(-.504,.298),l(-.992,.397),l(-.571,.213),l(-.264,.226),l(-.05,.113),l(.106,.579),l(.183,.409),l(-.336,.495),l(-.305,.332),l(-.013,.257),l(-.548,.415),l(-.593,.467),l(-.467,.185),l(-.432,.057),l(-.746,.206),l(-.591,.362),l(-.459,.58),l(-.551,.552),l(-.88,1.061),l(-.611,.552),l(-.673,.276),l(-.675,.829),l(-.676,.467),l(-.728,.368),l(-.452,.241),l(-.427,.312),l(-.192,.509),l(-.073,.466),l(-.341,.41),l(-.649,.298),l(-.428,.058),l(-.506,-.098),l(-.258,.269),l(-.366,.887),l(-.277,.23),l(-.505,-.253),l(-.614,.142),l(-.354,.283),l(-.304,.565),l(-.165,.48),l(-.005,.508),l(.166,1.539),l(.018,.805),l(-.208,.495),l(.227,.324),l(.315,.423),l(-.015,.508),l(-.199,.607),l(-.669,1.611),l(-.341,.834),l(-.13,.636),l(.047,.649),l(.21,1.764),l(-.081,.24),l(-.643,.001),l(-.433,-.013),l(-.186,.142),l(-.334,.961),l(-.324,.594),l(.025,.127),l(.493,.352),l(-.805,.327),l(-.306,.015),l(-.77,.284),l(-.295,.41),l(-.101,.692),l(-.157,.255),l(-.367,.283),l(-.526,.255),l(-.099,.057),l(-.066,.042),l(-.231,.156),l(-.145,0),l(-.174,-.056),l(-1.417,-1.451),l(-.092,-.395),l(-.276,-.522),l(-.34,-1.397),l(-.689,-1.792),l(-.94,-1.933),l(-.979,-1.508),l(-.554,-1.722),l(-.507,-1.792),l(-.738,-1.636),l(-.82,-1.42),l(-.424,-.737),l(-.598,-1.439),l(-.363,-1.157),l(-.767,-3.274),l(-.469,-2.695),l(-.157,-1.566),l(-.051,-.24),l(.232,-.565),l(.546,-.834),l(.007,-.311),l(-.404,-.281),l(-.367,-.437),l(-.113,-.635),l(-.108,-.917),l(.065,-.622),l(-.837,.03),l(-.19,.212),l(-.235,.424),l(.009,.183),l(.276,.254),l(.074,.183),l(-.073,.438),l(-.301,.438),l(-.503,.368),l(-.812,.369),l(-.504,.114),l(-.617,.255),l(-.377,.015),l(-.861,-.281),l(-.572,-.38),l(-1.018,-1),l(-1.391,-1.268),l(-.516,-.705),l(.267,-.043),l(1.062,.125),l(.615,-.086),l(.443,-.142),l(.461,-.283),l(.521,-.608),l(-.067,-.24),l(-.156,.071),l(-.587,.114),l(-.847,-.026),l(-.607,-.112),l(-.632,-.132),l(-.5,-.218),l(-.203,-.07),l(-.929,-.661),l(-.668,-.775),l(-.057,-.197),l(.37,-.036),l(.296,-.431),l(.866,-.017),l(-.015,-.728),l(.259,.052),l(.835,.009),l(.835,.021),l(.229,.149),l(.735,.099),l(.2,-.331),l(.78,-.215),l(.183,.062),l(.145,.335),l(.55,-.083),l(.15,-.248),l(.317,-.066),l(-.241,-.463),l(.232,-.149),l(-.654,-1.333),l(-.216,-.507),l(-.112,-.441),L(557,143.058),l(-.33,-.099),l(-.412,-.411),l(.154,-.735),l(.114,-.689),l(-.425,-.014),l(-.504,-.085),l(-.541,-.163),l(-.116,-.38),l(.079,-.269),l(.186,-.543),l(.979,-.893),l(.144,-.446),l(.535,-.463),l(.404,-.083),l(.207,.132),l(.158,.518),l(.361,.094),l(.895,-.314),l(.734,.011),l(.71,-.259),l(.076,-.38),l(.563,-.61),l(.277,-.481),l(.177,-.364),l(1.193,-.496),l(.478,-.547),l(.509,-1.216),l(.353,-.467),l(.609,-.133),l(.358,-.281),l(-.261,-.38),l(1.512,-1.503),l(.237,-.977),l(-.188,-.377),l(-.032,-.366),l(.517,-.248),l(.643,-.196),l(.504,-.2),l(.2,-.255),l(-.012,-.211),l(-.668,-.377),l(-.702,.05),l(-.188,-.248),l(.039,-.43),l(-.782,.003),l(.003,-.532),l(-.606,-.298),l(-.089,-.248),l(.215,-.132),l(.116,-.479),l(-.389,-.232),l(.139,-.413),l(.384,-.099),l(.002,-.347),l(-.598,.017),l(-.101,-.199),l(.202,-.149),l(-.047,-.314),l(-.336,0),l(-.09,-.166),l(.38,-.611),l(.894,-.265),l(1.708,.325),l(.568,.138),l(.928,.149),l(.557,-.265),l(.262,.116),l(.271,-.298),l(.438,-.132),l(.621,.102),l(.125,.179),l(.234,-.116),l(.071,-.479),l(.155,-.43),l(.411,-.232),l(.688,-.37),l(.207,-.084),l(.502,-.152),l(0,.515),l(.441,1.03),l(.221,.515),l(.81,.11),l(.441,.405),l(.221,.258),l(-.331,.221),l(-.184,.184),l(.073,.589),l(.037,.552),l(.294,.221),l(.718,.096),l(.092,.078),l(.044,.182),l(.68,.099),l(-.104,.414),l(.367,.694),l(-.578,.364),l(-.376,.281),l(-.368,.049),l(-.337,-.264),l(-.033,-.364),l(-.785,.198),l(.157,.694),l(.579,.595),l(-.104,.446),l(.272,.364),l(-.215,.215),l(.099,.43),l(.198,.066),l(.477,-.314),l(.383,.248),l(.772,.843),l(.363,-.116),l(1.078,.579),l(-.116,.364),l(.756,.248),l(.154,-.066),l(.859,.596),l(-1.07,.909),l(-.281,.116),l(.008,.364),l(-.221,.265),l(.04,.396),l(-.309,.397),l(-.218,.43),l(.039,.248),l(.63,.38),l(.466,-.083),l(.665,.479),l(.704,.149),l(.305,.529),l(1.242,.678),l(.231,-.166),l(1.027,.595),l(.538,-.066),l(.182,.397),l(.835,.166),l(.304,.198),l(.15,-.066),l(.087,-.215),l(.503,0),l(.482,.265),l(.582,-.347),l(.494,.298),l(.643,.066),l(.142,.231),l(-.101,.446),l(.663,.149),l(.286,.281),l(.618,.265),l(.584,-.281),l(.313,.066),l(-.034,.331),l(.312,.248),l(.379,-.231),l(.721,.148),l(.847,.364),l(.606,-.297),l(.268,.364),l(.399,.116),l(.357,-.132),l(.271,.083),l(.687,-.132),l(.336,.05),l(.311,-.694),l(-.429,-.827),l(.07,-.876),l(.318,-.761),l(-.037,-.022),l(.345,-.129),l(.471,-.102),l(.231,.069),l(.139,.183),l(-.052,.861),l(.212,.662),l(-.092,.113),l(.235,.493),l(.637,.18),l(.559,.081),l(.869,.214),l(.085,.021),l(.544,-.074),l(.531,-.313),l(.301,.055),l(.335,.125),l(1.238,.063),l(1.036,-.062),l(.624,-.06),l(.217,-.58),l(-.017,-.282),l(-.258,-.238),l(-.313,-.069),l(-.326,-.294),l(-.042,-.24),l(.07,-.156),l(.189,-.1),l(.784,-.033),l(.714,-.216),l(.397,-.27),l(1.123,-1.107),l(.543,-.37),l(.829,-.258),l(1.105,-.726),l(.546,-.299),l(.355,-.087),l(.286,.167),l(.975,.319),l(.377,-.044),l(1.377,-.84),l(.455,.392),l(.716,.715),l(.046,.38),l(-.354,.454),l(-.138,.269),l(.102,.056),l(.3,.055),l(.657,.081),l(.73,.179),l(.624,.081),l(-.018,.508),l(-.112,.24),l(-.596,.582),l(-.072,.283),l(.184,.718),l(-.295,.058),l(-.853,-.221),l(-.558,-.082),l(-.312,.129),l(-.719,.512),l(-1.446,.883),l(-.197,.354),l(.057,.761),l(-.136,.382),l(-.938,1.134),l(-.045,.212),l(.192,.408),l(0,.324),l(-1.148,2.25),l(-.17,.128),l(-.309,-.013),l(-.391,-.11),l(-.811,-.32),l(-.133,.283),l(.146,1.594),l(-.191,.354),l(-.401,.144),l(-.228,.185),l(.152,.93),l(-.015,.678),l(-.273,.368),l(-.25,.129),l(-.255,-.14),l(-.595,-.152), +N(478.516,135.173),l(.052,-.292),l(-.049,-.169),l(-.197,-.107),l(.107,-.175),l(.292,-.919),l(-.015,-.818),l(.517,-1.09),l(.3,-.891),l(-.004,-.409),l(.133,-.283),l(.07,-.749),l(.033,-.847),l(.062,-.174),l(.026,-.278),l(-.065,-.411),l(.037,-.119),l(.102,-.063),l(1.902,1.034),l(.365,.167),l(.253,-.016),l(1.139,-.656),l(2.96,-1.541),l(.161,-.071),l(.87,1.632),l(.311,.69),l(.093,.056),l(-.46,.44),l(-.257,.171),l(-.97,.26),l(-2.586,.622),l(-.646,.229),l(1.146,1.32),l(.698,.885),l(-.765,.724),l(-.456,.37),l(-.24,.072),l(-1.249,.332),l(-.462,.61),l(-.975,.782),l(-2.079,-.299),l(-.154,-.017), +N(456.028,151.46),l(-.021,1.003),l(.033,3.078),l(-.088,.17),l(-1.561,-.019),l(-.52,-.011),l(-.073,1.13),l(-1.981,-.963),l(-5.577,-2.792),l(-4.941,-2.372),l(-5.231,-2.554),l(-.41,.059),l(-1.818,.858),l(-1.519,.729),l(-.231,.157),l(-1.192,-.911),l(-.258,-.182),l(-1.008,-.333),l(-1.646,-.442),l(-.832,-.137),l(-.098,-.07),l(-.86,-1.506),l(-.178,-.168),l(-1.028,-.347),l(-.702,-.165),l(-.544,.201),l(-.244,-.154),l(-.562,-.873),l(-.249,-.917),l(-1.272,-1.702),l(.152,-.283),l(.249,-.128),l(.666,-.47),l(.086,-.17),l(.061,-.664),l(-.457,-1.156),l(.158,-.495),l(.16,-.622),l(-.101,-.748),l(.1,-.862),l(-.052,-.691),l(-.147,-.833),l(-.88,-1.605),l(.241,-.383),l(.204,-.156),l(.22,-.143),l(.864,-.598),l(.155,-.227),l(.147,-.537),l(-.274,-.973),l(.126,-.354),l(1.473,-1.138),l(.579,-.314),l(.802,-.428),l(.093,-.269),l(-.064,-.564),l(.093,-.981),l(1.436,.59),l(.995,.309),l(.521,.013),l(.863,-.129),l(.604,.027),l(1.552,.223),l(.614,.479),l(.794,.224),l(.486,-.001),l(.342,.197),l(.173,.226),l(.26,.819),l(.39,.564),l(.688,.591),l(.378,.126),l(.678,.14),l(1.031,.083),l(.447,.07),l(.973,.224),l(.639,.224),l(.552,.281),l(1.289,.788),l(.84,.464),l(.465,.013),l(.441,-.128),l(.758,-.411),l(.706,-.623),l(.3,-.523),l(0,-.254),l(-.276,-.621),l(-.112,-.579),l(.044,-.41),l(.237,-.537),l(.661,-.58),l(.333,-.198),l(.554,-.241),l(.644,-.298),l(1.376,-.413),l(1.205,.054),l(.728,.154),l(.844,.365),l(.188,.169),l(.043,.508),l(.281,.253),l(.301,.014),l(.945,.125),l(.712,.309),l(.45,.027),l(1.286,.04),l(.302,.197),l(.068,.381),l(.276,.296),l(-.099,.208),l(-.369,.228),l(-.21,.34),l(.354,1.283),l(-.231,.425),l(-.322,.553),l(-.056,.311),l(.185,.945),l(.388,.916),l(.042,.367),l(-.015,.988),l(-.019,3.869),l(-.016,1.468),l(-.008,2.048),l(-.001,.692),l(.045,2.81),l(-.021,1.342),l(.011,2.612), +N(478.212,134.714),l(-.834,-1.746),l(-.796,-1.944),l(-.124,-.289),l(.109,-.066),l(.679,-.851),l(.219,-.438),l(.183,-.507),l(.171,-.566),l(.188,-.822),l(.116,.018),l(.137,-.093),l(.006,-.204),l(.028,-.315),l(.372,-.051),l(.151,.022),l(.07,.099),l(.355,-.07),l(.009,-.167),l(.067,-.193),l(.088,-.041),l(.07,.023),l(.183,.346),l(.201,.128),l(.021,.183),l(-.047,.122),l(.082,.085),l(-.102,.063),l(-.037,.119),l(.065,.411),l(-.026,.278),l(-.062,.174),l(-.033,.847),l(-.07,.749),l(-.133,.283),l(.004,.409),l(-.3,.891),l(-.517,1.09),l(.015,.818),l(-.292,.919),l(-.107,.175),l(-.067,.068),l(-.042,.042), +N(495.751,163.817),l(-.03,-.184),l(-.112,-.537),l(-.508,-.945),l(-.73,-.987),l(-.438,-.493),l(-.846,-.69),l(-.51,-.875),l(-.814,-1.876),l(-.474,-.889),l(-.28,-.409),l(-.794,-.507),l(-1.271,-.689),l(-.527,-.634),l(-.8,-1.17),l(-.081,-.96),l(-.061,-.776),l(-.002,-.89),l(-.104,-.381),l(-.312,-.663),l(-.944,-1.65),l(-.357,-.494),l(-.758,-.62),l(-.459,-.225),l(-.499,-.126),l(-.308,-.282),l(-.483,-.578),l(.149,-.692),l(-.111,-.437),l(-.474,-.818),l(-.747,-1.072),l(-.793,-.902),l(-1.069,-1.494),l(-.525,-.931),l(-.352,-.479),l(-.722,-.761),l(-.524,-.056),l(-.248,0),l(.077,-.296),l(.193,-.283),l(.311,-1.314),l(.104,-.583),l(.154,.017),l(2.079,.299),l(.975,-.782),l(.462,-.61),l(1.249,-.332),l(.24,-.072),l(.456,-.37),l(.765,-.724),l(-.698,-.885),l(-1.146,-1.32),l(.646,-.229),l(2.586,-.622),l(.97,-.26),l(.257,-.171),l(.46,-.44),l(.093,.056),l(1.129,.459),l(.757,.222),l(2.034,.934),l(1.14,.473),l(2.44,1.101),l(.258,.196),l(.399,.633),l(.141,.07),l(.973,-.048),l(.135,.366),l(-.118,.396),l(.047,.818),l(.118,.253),l(.812,.277),l(1.557,.697),l(4.048,.132),l(1.657,.259),l(.408,.054),l(.334,.619),l(.185,.239),l(1.07,.05),l(.644,-.044),l(.043,.121),l(.277,.648),l(.365,.494),l(.178,.663),l(.052,.113),l(.615,-.029),l(.248,.126),l(-.204,.237),l(.194,.187),l(.184,.282),l(.234,.067),l(.234,.27),l(.886,.168),l(.423,.437),l(-.07,.28),l(-.235,.035),l(-.111,.25),l(.316,.381),l(-.188,.593),l(-.122,.198),l(.165,.268),l(.302,.666),l(.149,-.117),l(.372,.282),l(.105,.616),l(.422,.696),l(-.028,.423),l(.222,.268),l(.16,.197),l(.287,.084),l(.136,-.007),l(.336,.083),l(1.043,2.198),l(.548,1.154),l(.261,.902),l(3.362,.375),l(3.387,.446),l(.839,.108),l(.584,-.469),l(.152,-.057),l(.581,.914),l(.155,1.453),l(-5.346,2.982),l(-2.35,1.213),l(-1.691,.815),l(-.169,.085),l(-1.148,.346),l(-3.097,1.035),l(-4.618,1.566),l(-.484,.229),l(-.041,.127),l(-.383,.397),l(-1.907,2.271),l(-2.042,2.667),l(-1.302,-2.703),l(-1.211,-2.45),l(-.452,-.012),l(-.715,.047),l(-.446,-.125),l(-.671,-.151),l(-.216,.1),l(-.174,.185),l(-.11,.495),l(.041,.678),l(-.113,.565),l(-.692,.563), +N(476.458,130.735),l(.124,.289),l(.796,1.944),l(.834,1.746),l(-.38,.381),l(-.479,1.145),l(-.334,1.413),l(-.171,.593),l(-.18,.156),l(-.407,-.07),l(-.448,-.521),l(-.782,-.676),l(-.386,-.494),l(-.338,-.988),l(-.521,-.45),l(-.289,-.621),l(-.17,-.479),l(-.198,-.353),l(-.466,.17),l(-.267,.523),l(.604,1.34),l(.131,.381),l(.634,.86),l(.933,1.042),l(.473,1.199),l(.526,.973),l(.277,.818),l(.391,.465),l(.912,1.735),l(1.072,1.904),l(.428,.705),l(.586,.549),l(.451,.352),l(.151,.183),l(-.241,.17),l(-.285,.1),l(-.043,.155),l(.238,1.087),l(.252,.467),l(.127,.238),l(.812,.591),l(.397,.168),l(.406,.521),l(.416,.38),l(.311,.56),l(-10.382,-.006),l(-2.138,-.001),l(-2.774,.002),l(-2.513,.015),l(-2.268,-.029),l(-1.664,.01),l(-1.241,.007),l(-1.614,-.019),l(-.914,.005),l(-.819,.089),l(-.011,-2.612),l(.021,-1.342),l(-.045,-2.81),l(.001,-.692),l(.008,-2.048),l(.016,-1.468),l(.019,-3.869),l(.015,-.988),l(-.042,-.367),l(-.388,-.916),l(-.185,-.945),l(.056,-.311),l(.322,-.553),l(.231,-.425),l(-.354,-1.283),l(.21,-.34),l(.369,-.228),l(.099,-.208),l(.337,.168),l(.553,-.015),l(.628,-.1),l(.786,-.001),l(1.513,.293),l(.587,.115),l(.779,.122),l(.721,.154),l(.348,.409),l(.4,0),l(.928,.083),l(.998,.394),l(.628,.069),l(.245,-.127),l(.72,-.538),l(.925,-.397),l(.837,-.186),l(.78,-.27),l(.375,-.072),l(.346,.056),l(.535,-.001),l(.723,.126),l(.202,.465),l(.596,.366),l(.518,-.156),l(.64,.267),l(.382,.027),l(.561,-.401),l(.241,.179),l(.277,.056),l(.674,.13),l(.338,-.062),l(.46,-.165),l(.51,-.308), +N(580.625,132.873),l(.24,.43),l(.299,.05),l(.276,-.314),l(.134,-.513),l(.275,.066),l(.186,-.182),l(1.079,.199),l(.132,.612),l(.867,.264),l(.726,.595),l(.472,.215),l(.15,-.132),l(.454,.281),l(.657,.794),l(.158,-.166),l(.71,-.116),l(.289,.166),l(.178,.38),l(-.069,.281),l(1.451,.893),l(.333,-.248),l(.326,.017),l(-.175,.396),l(.014,.265),l(.935,.066),l(.365,-.066),l(.54,.496),l(.141,.463),l(.237,-.099),l(-.01,-.364),l(.685,.38),l(.271,-.083),l(.08,-.331),l(.407,0),l(.63,.281),l(.319,.364),l(.849,-.066),l(.341,.116),l(.339,-.281),l(.655,.159),l(.037,.022),l(-.318,.761),l(-.07,.876),l(.429,.827),l(-.311,.694),l(-.336,-.05),l(-.687,.132),l(-.271,-.083),l(-.357,.132),l(-.399,-.116),l(-.268,-.364),l(-.606,.297),l(-.847,-.364),l(-.721,-.148),l(-.379,.231),l(-.312,-.248),l(.034,-.331),l(-.313,-.066),l(-.584,.281),l(-.618,-.265),l(-.286,-.281),l(-.663,-.149),l(.101,-.446),l(-.142,-.231),l(-.643,-.066),l(-.494,-.298),l(-.582,.347),l(-.482,-.265),l(-.503,0),l(-.087,.215),l(-.15,.066),l(-.304,-.198),l(-.835,-.166),l(-.182,-.397),l(-.538,.066),l(-1.027,-.595),l(-.231,.166),l(-1.242,-.678),l(-.305,-.529),l(-.704,-.149),l(-.665,-.479),l(-.466,.083),l(-.63,-.38),l(-.039,-.248),l(.218,-.43),l(.309,-.397),l(-.04,-.396),l(.221,-.265),l(-.008,-.364),l(.281,-.116),l(1.07,-.909), +N(374.125,167.166),l(-1.41,-.924),l(-.661,-.604),l(-.537,-.788),l(-.292,-.662),l(-.15,-.183),l(-.312,-.154),l(-.567,-.053),l(-.655,-.307),l(-.695,-.561),l(-.604,-.194),l(-.567,-.025),l(-1.209,.12),l(-1.821,.194),l(-.523,.417),l(.06,-.502),l(.563,-1.301),l(.188,-.819),l(.13,-1.13),l(-.162,-1.101),l(-.3,-.791),l(-.624,-.747),l(.267,-.283),l(.182,-.424),l(.067,-.975),l(-.065,-.537),l(-.174,-.353),l(-.808,-.817),l(-.297,-.112),l(-.393,.438),l(-.055,-.197),l(-.013,-.381),l(.08,-.689),l(.474,.013),l(5.055,.056),l(2.396,.014),l(.732,-.033),l(.212,.027),l(-.051,-1.102),l(-.164,-1.539),l(.01,-.707),l(.249,-.383),l(.575,-.427),l(.726,-.315),l(.809,-.287),l(.144,-.128),l(.099,-2.6),l(.07,-2.261),l(.047,-.509),l(.557,-.074),l(6.005,.022),l(.56,.011),l(.104,-.396),l(-.002,-.65),l(.03,-1.752),l(2.829,1.509),l(4.12,2.42),l(1.414,.91),l(-.523,.13),l(-3.231,.089),l(.049,.776),l(.908,7.962),l(.19,1.468),l(.178,1.736),l(.325,2.753),l(.202,2.386),l(.186,1.468),l(.724,.787),l(-.379,1.613),l(-6.457,.01),l(-1.953,.026),l(-.945,.344),l(-.387,.031),l(-.485,-.054),l(-.713,-.137),l(-.535,-.124),l(-.06,.212),l(.055,.296),l(-.107,.269),l(-.454,-.082),l(-.214,-.168),l(-.568,-.83),l(-.261,-.111),l(-.402,.073),l(-.252,.256),l(-.181,.552),l(-.018,.607),l(-.332,.284), +N(476.114,191.139),l(-.563,.54),l(-.626,.314),l(-.367,.016),l(-.303,-.196),l(-.303,-.097),l(-.88,.132),l(-.881,.33),l(-.911,.048),l(-.942,-.234),l(-.495,-.011),l(-.464,.087),l(-.496,.229),l(-1.288,-1.32),l(-1.032,-.926),l(-.207,-.083),l(-.258,.157),l(-.436,.582),l(-.16,.1),l(-.684,-.631),l(-.384,-.012),l(-.529,.37),l(-.258,.242),l(-.352,.016),l(-.366,-.195),l(-.525,-.477),l(-.348,-.493),l(-.795,-.772),l(-.143,-.239),l(-.031,-.07),l(.083,-.679),l(-.157,-.352),l(-.558,-.477),l(-.814,-.165),l(-.367,-.224),l(-.285,-.436),l(-.059,-.72),l(-.206,-.366),l(-.207,-.168),l(-.717,-.434),l(-.558,-.378),l(-.445,-.351),l(-.173,-.395),l(.148,-.481),l(-.223,-.267),l(-.351,-.196),l(-.799,-.235),l(-.797,-.447),l(-.223,-.225),l(-.252,-.493),l(-.207,-.126),l(-.272,.001),l(-.802,.019),l(-.158,-.211),l(-.01,-.664),l(.416,-1.472),l(-.122,-.536),l(-.347,-.549),l(-1.342,-1.673),l(.15,-.425),l(-.026,-.367),l(-.266,-.465),l(-.444,-.407),l(-.155,-.295),l(-.137,-.522),l(-.221,-1.228),l(-.141,-.225),l(-.338,-.012),l(-.517,.088),l(-.219,-.352),l(.316,-.609),l(.542,-.596),l(.087,-.34),l(-.342,-.662),l(.053,-.24),l(.718,-.428),l(.149,-.212),l(-.131,-.677),l(.122,-.438),l(.583,-.809),l(.417,-1.245),l(.229,-.143),l(1.245,-.05),l(.839,.009),l(.04,-.283),l(-.031,-1.229),l(-.036,-1.002),l(.038,-.749),l(-.085,-2.5),l(.036,-.636),l(.016,-.946),l(.02,-1.045),l(.073,-1.13),l(.52,.011),l(1.561,.019),l(.088,-.17),l(-.033,-3.078),l(.021,-1.003),l(.819,-.089),l(.914,-.005),l(1.614,.019),l(1.241,-.007),l(1.664,-.01),l(2.268,.029),l(2.513,-.015),l(2.774,-.002),l(2.138,.001),l(10.382,.006),l(.229,.414),l(.499,1.115),l(.281,3.501),l(.319,1.637),l(.182,.211),l(.625,.394),l(.595,.366),l(.617,.507),l(.491,.197),l(.254,.223),l(-.238,.199),l(-.277,.327),l(-.306,.566),l(-.369,.242),l(-.511,.172),l(-.427,.116),l(-.153,.142),l(-.235,.496),l(-.348,.171),l(-.73,.033),l(-.204,.552),l(-.038,.452),l(-.202,.862),l(-.242,.722),l(-.541,1.302),l(-.068,.495),l(.092,.903),l(-.013,.679),l(-.001,.083),l(-.148,.947),l(-.398,1.231),l(-.214,1.061),l(-1.04,.331),l(-.414,.37),l(-.693,1.134),l(-.154,.34),l(-.191,1.088),l(-.141,1.074),l(-.197,.185),l(-.274,.044),l(-.431,-.096),l(-.259,.072),l(-.163,.114),l(-.187,1.103),l(-.115,.933),l(-.2,1.272),l(.039,.522),l(-.229,1.159),l(-.469,.299),l(-.288,-.012),l(-.928,-.122),l(-.321,.03),l(-.188,.806),l(-.054,.466),l(.094,.141),l(.479,.11),l(.734,.123),l(.334,.167),l(.805,.913),l(1.06,1.067),l(.751,1.464),l(.345,.732),l(.348,.421),l(.462,.28),l(.415,.097),l(.269,.309),l(.117,.988),l(-.034,.17),l(-.018,.141),l(-.079,-.028),l(-.464,.017),l(-1.009,.133),l(-.832,.005),l(-.671,-.052),l(-.291,.327),l(-.678,.795), +N(518.402,163.079),l(-.282,.097),l(-.538,.27),l(-.656,.566),l(-.265,.297),l(-.166,.508),l(-.062,.41),l(-.41,.326),l(-1.418,.652),l(-2.27,.641),l(-1.285,.412),l(-.843,.312),l(-.356,.297),l(-.473,.622),l(-.436,.269),l(-.506,.114),l(-.593,-.069),l(-.521,.072),l(-.83,.439),l(-.65,.396),l(-.956,.397),l(-.752,.199),l(-1.16,.003),l(-.562,-.013),l(-.297,.128),l(-.386,.312),l(-.272,.297),l(-.45,.312),l(-.511,.241),l(-.389,.043),l(-.239,-.042),l(-.535,.411),l(-.839,.058),l(-.494,-.112),l(-.623,-.437),l(-.17,-.155),l(-.317,-.437),l(-.084,-.254),l(.18,-.721),l(-.081,-.635),l(-.312,-.507),l(-.341,-1.171),l(-.572,-1.919),l(-.072,-.438),l(.268,-.707),l(-.124,-.748),l(.692,-.563),l(.113,-.565),l(-.041,-.678),l(.11,-.495),l(.174,-.185),l(.216,-.1),l(.671,.151),l(.446,.125),l(.715,-.047),l(.452,.012),l(1.211,2.45),l(1.302,2.703),l(2.042,-2.667),l(1.907,-2.271),l(.383,-.397),l(.041,-.127),l(.484,-.229),l(4.618,-1.566),l(3.097,-1.035),l(1.148,-.346),l(.169,-.085),l(.092,.663),l(.226,.634),l(.604,.971),l(.933,1.364),l(.127,.253),l(-.006,.296),l(.483,.689),l(.241,.306), +N(494.64,172.627),l(-.261,-.166),l(-.476,-.633),l(-.475,-.159),l(-.437,-.911),l(-1.267,-.792),l(-.277,-.594),l(-.673,-.673),l(-.594,-.119),l(-.871,-.554),l(-.555,.079),l(-.158,-.158),l(-.237,.04),l(-.277,-.198),l(-.356,.159),l(-.476,.079),l(-.277,-.436),l(-.158,.237),l(-.436,.198),l(-.792,.079),l(-.554,-.594),l(-.238,0),l(-.396,-.317),l(-.832,1.663),l(-.436,-.871),l(-.475,.079),l(-.277,.356),l(-.396,-.08),l(-.349,.041),l(.013,-.679),l(-.092,-.903),l(.068,-.495),l(.541,-1.302),l(.242,-.722),l(.202,-.862),l(.038,-.452),l(.204,-.552),l(.73,-.033),l(.348,-.171),l(.235,-.496),l(.153,-.142),l(.427,-.116),l(.511,-.172),l(.369,-.242),l(.306,-.566),l(.277,-.327),l(.238,-.199),l(.098,.129),l(.718,2.102),l(.442,1.623),l(.689,1.919),l(.618,.832),l(.205,-.212),l(-.072,-.479),l(.093,-.226),l(.31,.253),l(.4,.677),l(.384,.395),l(.534,-.043),l(.242,.014),l(1.338,1.282),l(.809,.916),l(.124,.099),l(.706,.055),l(.618,.874),l(.021,.24),l(-.025,.198),l(.118,.212),l(.507,.182),l(.915,.869),l(-.075,.094),l(-.529,.78),l(-.331,-.182),l(-.396,-.125),l(-.214,.114),l(-.055,.085), +N(370.147,172.035),l(-2.301,-.043),l(-1.045,.006),l(-.505,.384),l(-.51,.187),l(-.74,-.024),l(-.819,.047),l(-.463,.139),l(-.009,-.003),l(-.278,-.226),l(-.169,-.409),l(.104,-.424),l(-.095,-.55),l(-.018,-.198),l(.001,-.046),l(1.695,.014),l(0,-.434),l(.155,0),l(.341,-.016),l(.186,-.077),l(.248,.062),l(.294,-.046),l(.124,-.093),l(.016,-.263),l(.077,-.078),l(.14,-.016),l(.155,.155),l(.232,.124),l(.356,.108),l(.046,.108),l(.139,.047),l(.217,-.031),l(.263,.108),l(.186,.17),l(.434,0),l(.186,-.108),l(.263,-.108),l(.279,0),l(.108,-.124),l(.016,-.124),l(-.155,-.217),l(-.202,-.077),l(-.201,.031),l(-.294,.093),l(-.108,.093),l(-.248,.062),l(-.279,-.186),l(-.031,-.186),l(-.186,-.108),l(-.17,-.015),l(-.186,.124),l(-.139,-.108),l(-.108,-.217),l(-.155,-.108),l(-.201,.031),l(-.17,-.062),l(-.387,.17),l(-.108,-.108),l(-.155,.046),l(-.202,.124),l(-.093,.294),l(-1.664,0),l(-.007,-.067),l(-.028,-.269),l(-.377,-.268),l(-.068,-.155),l(-.057,-.367),l(-.386,-.635),l(-.399,-.494),l(-.379,-.31),l(-.472,-.183),l(.54,-.34),l(.723,-.75),l(.588,-1.004),l(.334,-.82),l(.099,-.826),l(.523,-.417),l(1.821,-.194),l(1.209,-.12),l(.567,.025),l(.604,.194),l(.695,.561),l(.655,.307),l(.567,.053),l(.312,.154),l(.15,.183),l(.292,.662),l(.537,.788),l(.661,.604),l(1.41,.924),l(-.506,.399),l(-.057,.339),l(.251,1.1),l(.144,.663),l(.22,.479),l(.181,.197),l(.554,.322),l(.265,.337),l(.082,.833),l(-.004,.565),l(-.062,.142),l(-.146,-.042),l(-.963,.091),l(-.658,.074),l(-.725,-.081),l(-.503,-.209),l(-.795,-.32),l(-1.255,-.021), +N(495.973,175.881),l(-.363,.807),l(.083,.409),l(.428,.732),l(.587,.844),l(.732,.801),l(.596,.547),l(.634,.321),l(.54,.209),l(4.26,1.443),l(1.447,.472),l(1.875,-.04),l(.236,.154),l(-4.087,4.205),l(-1.562,1.69),l(-.813,.909),l(-.8,.004),l(-1.693,-.046),l(-.626,.088),l(-.562,.215),l(-.388,.214),l(-.502,.497),l(-.294,.426),l(-.337,.115),l(-1.216,.078),l(-.305,.101),l(-.453,.511),l(-1.103,-.106),l(-.461,-.181),l(-.46,-.336),l(-.271,-.098),l(-.852,.358),l(-.675,.343),l(-.258,.199),l(-.71,.753),l(-.16,.114),l(-.847,-.094),l(-.67,-.193),l(-1.373,-.133),l(-.335,-.041),l(-2.353,-1.525),l(-.604,-.293),l(-.749,-.193),l(-1.054,-.149),l(-.319,-.069),l(.018,-.141),l(.034,-.17),l(-.117,-.988),l(-.269,-.309),l(-.415,-.097),l(-.462,-.28),l(-.348,-.421),l(-.345,-.732),l(-.751,-1.464),l(-1.06,-1.067),l(-.805,-.913),l(-.334,-.167),l(-.734,-.123),l(-.479,-.11),l(-.094,-.141),l(.054,-.466),l(.188,-.806),l(.321,-.03),l(.928,.122),l(.288,.012),l(.469,-.299),l(.229,-1.159),l(-.039,-.522),l(.2,-1.272),l(.115,-.933),l(.187,-1.103),l(.163,-.114),l(.259,-.072),l(.431,.096),l(.274,-.044),l(.197,-.185),l(.141,-1.074),l(.191,-1.088),l(.154,-.34),l(.693,-1.134),l(.414,-.37),l(1.04,-.331),l(.214,-1.061),l(.398,-1.231),l(.148,-.947),l(.001,-.083),l(.349,-.041),l(.396,.08),l(.277,-.356),l(.475,-.079),l(.436,.871),l(.832,-1.663),l(.396,.317),l(.238,0),l(.554,.594),l(.792,-.079),l(.436,-.198),l(.158,-.237),l(.277,.436),l(.476,-.079),l(.356,-.159),l(.277,.198),l(.237,-.04),l(.158,.158),l(.555,-.079),l(.871,.554),l(.594,.119),l(.673,.673),l(.277,.594),l(1.267,.792),l(.437,.911),l(.475,.159),l(.476,.633),l(.261,.166),l(-.594,.921),l(-.488,.61),l(-.105,.254),l(-.029,.396),l(.202,1.157),l(.5,-.074),l(.892,-.246),l(.4,.04),l(.556,.195), +N(364.011,169.929),l(1.664,0),l(.093,-.294),l(.202,-.124),l(.155,-.046),l(.108,.108),l(.387,-.17),l(.17,.062),l(.201,-.031),l(.155,.108),l(.108,.217),l(.139,.108),l(.186,-.124),l(.17,.015),l(.186,.108),l(.031,.186),l(.279,.186),l(.248,-.062),l(.108,-.093),l(.294,-.093),l(.201,-.031),l(.202,.077),l(.155,.217),l(-.016,.124),l(-.108,.124),l(-.279,0),l(-.263,.108),l(-.186,.108),l(-.434,0),l(-.186,-.17),l(-.263,-.108),l(-.217,.031),l(-.139,-.047),l(-.046,-.108),l(-.356,-.108),l(-.232,-.124),l(-.155,-.155),l(-.14,.016),l(-.077,.078),l(-.016,.263),l(-.124,.093),l(-.294,.046),l(-.248,-.062),l(-.186,.077),l(-.341,.016),l(-.155,0),l(0,.434),l(-1.695,-.014),l(.019,-.477),l(.173,-.198),l(.434,-.058),l(.093,-.155),l(-.006,-.059), +N(495.973,175.881),l(-.556,-.195),l(-.4,-.04),l(-.892,.246),l(-.5,.074),l(-.202,-1.157),l(.029,-.396),l(.105,-.254),l(.488,-.61),l(.594,-.921),l(.055,-.085),l(.214,-.114),l(.396,.125),l(.331,.182),l(.529,-.78),l(.075,-.094),l(.627,.596),l(.285,.465),l(.036,.282),l(-.118,.113),l(-.361,.185),l(-.438,.1),l(-.56,.312),l(-.566,.467),l(.253,.127),l(.645,-.058),l(.321,.013),l(.434,.124),l(-.114,.26),l(-.37,.468),l(-.34,.567), +N(363.763,172.732),l(.463,-.139),l(.819,-.047),l(.74,.024),l(.51,-.187),l(.505,-.384),l(1.045,-.006),l(2.301,.043),l(-.111,.792),l(.115,.847),l(-.186,.312),l(-.333,.186),l(-.513,.031),l(-.401,.017),l(-.381,.186),l(-.789,.64),l(-.321,.372),l(-.047,-.126),l(-.192,0),l(-.501,-.14),l(-.165,-.254),l(.121,-.41),l(.33,-.438),l(.253,-.212),l(-.131,-.141),l(-.372,-.112),l(-.498,.015),l(-.415,.17),l(-.161,0),l(-.616,-.281),l(-.36,-.296),l(-.069,-.24),l(-.323,-.084),l(-.316,-.137), +N(383.005,177.596),l(-.379,.397),l(-.264,.623),l(.214,.409),l(.695,.405),l(.197,.31),l(-.125,.283),l(-.332,.37),l(.309,.351),l(.648,.561),l(.051,.226),l(-.19,.143),l(-.304,-.012),l(-.548,-.223),l(-.304,.03),l(-.158,.199),l(-.03,.127),l(.296,.549),l(.179,.21),l(-.188,.354),l(-.602,.554),l(-.047,.099),l(-.339,-.224),l(-.337,-.097),l(-.143,.086),l(-.756,.922),l(-.321,-.026),l(-.404,-.322),l(-.277,-.323),l(.044,-.283),l(-.009,-.65),l(-.22,-.846),l(-.165,-.366),l(-.338,-.097),l(-.528,.046),l(-.367,.143),l(-.252,.242),l(-.193,.376),l(-.26,-.656),l(-.165,-1.369),l(-.252,-.761),l(-.475,-.619),l(-.456,-.421),l(-.42,-.224),l(-.466,-.04),l(-1.137,.148),l(-.594,-.039),l(-.238,.157),l(-.643,.866),l(-1.088,1.235),l(.051,-.392),l(-.312,-.55),l(-.764,-.775),l(-.122,-.649),l(-.84,-.366),l(-.908,-.563),l(-.277,-.296),l(.09,-.396),l(-.053,-.311),l(-.547,-.041),l(-.323,-.098),l(-.115,-.155),l(.059,-.311),l(-.038,-.1),l(.321,-.372),l(.789,-.64),l(.381,-.186),l(.401,-.017),l(.513,-.031),l(.333,-.186),l(.186,-.312),l(-.115,-.847),l(.111,-.792),l(1.255,.021),l(.795,.32),l(.503,.209),l(.725,.081),l(.658,-.074),l(.963,-.091),l(.146,.042),l(.113,.028),l(.18,.183),l(.882,.715),l(.536,.265),l(.252,-.256),l(.475,-.413),l(.338,.026),l(.356,.153),l(.565,.152),l(.43,-.243),l(.3,-.327),l(.684,-.428),l(.323,.055),l(.246,.281),l(.022,.339),l(.271,.832),l(.265,.451),l(.474,.478),l(.349,.718),l(.194,1.143),l(.559,.901), +N(266.015,188.956),l(.103,.169),l(-.163,.326),l(-.592,.385),l(-1.74,.9),l(-.807,.23),l(-.557,.074),l(-.465,-.054),l(-.284,.115),l(-.232,1.117),l(-.348,.115),l(-.628,-.618),l(-.344,-.224),l(-1.149,.035),l(-.385,-.04),l(-.896,-.461),l(-.309,-.125),l(-.159,.029),l(-.041,.184),l(.616,.688),l(.391,.69),l(.302,1.524),l(.079,.55),l(.166,.239),l(.96,.051),l(.434,.125),l(.15,.253),l(-.265,.27),l(-.569,.272),l(-.652,.131),l(-.203,.199),l(-.259,.666),l(-.235,.213),l(-.652,.173),l(-.554,.286),l(-.74,.654),l(-.645,.739),l(-.271,.016),l(-.186,-.776),l(-.083,-.183),l(-.757,.697),l(-.414,.073),l(-.482,-.223),l(-.694,-.546),l(-.432,-.054),l(-.199,-.437),l(-.088,-.452),l(-.161,-.861),l(-.138,-.437),l(-.148,-.168),l(-.797,-1.182),l(-.51,-.491),l(.479,-.526),l(.731,-.612),l(-.121,-.282),l(-.486,-.647),l(-.256,-.437),l(-.447,-.789),l(-.162,-.804),l(-.048,-.367),l(-.035,-.438),l(-.026,-.254),l(.147,-.326),l(.379,-.511),l(.085,-1.004),l(.409,-.525),l(-.644,-.081),l(-1.99,.224),l(-.76,.174),l(-.522,.13),l(-.144,0),l(-.554,-.576),l(-.847,-.998),l(-.188,-.253),l(-.64,-.321),l(-.521,-.181),l(-1.167,.05),l(-1.163,.12),l(-.496,.017),l(-.397,-.252),l(-.429,-.548),l(-.401,-.309),l(-.099,-.353),l(.226,-1.132),l(-.103,-.395),l(-.855,-1.45),l(-.31,-.606),l(-.384,.017),l(-.234,.1),l(-.402,-.025),l(.709,-1.191),l(.241,-.722),l(.172,-.722),l(.99,-1.758),l(.381,-.059),l(.227,.027),l(.129,-.396),l(-.048,-.497),l(.056,-.288),l(.414,-.2),l(.534,-.156),l(.84,-.171),l(.128,.105),l(-.9,.151),l(-.731,.312),l(-.145,.212),l(.19,.607),l(.142,.407),l(.224,.126),l(-.043,.145),l(.153,.579),l(-.135,.367),l(-.327,.364),l(-.348,.824),l(-.137,.368),l(.253,.479),l(.288,.253),l(.25,.72),l(.341,.353),l(.523,-.114),l(.184,-.156),l(.419,-.255),l(.12,-.142),l(.066,-.523),l(-.167,-.649),l(-.21,-.282),l(-.438,-.804),l(-.136,-.135),l(-.118,-.395),l(-.247,-.18),l(.239,-.099),l(.095,-.251),l(-.204,-.144),l(1,-.379),l(1.085,-.327),l(.998,-.272),l(.086,-.225),l(.69,-.086),l(.143,-.008),l(-.042,-.157),l(-.055,-.198),l(-.125,-.036),l(-.039,-.108),l(-.128,-.072),l(-.226,.071),l(-.156,.027),l(-.229,-.012),l(-.315,-.55),l(.109,-.254),l(.337,-.213),l(.367,-.043),l(.09,.112),l(.14,.368),l(.186,.162),l(-.001,.148),l(.026,.193),l(.068,.09),l(.004,.198),l(.253,.258),l(.329,-.02),l(.699,.111),l(.455,.07),l(.593,.196),l(.323,.254),l(.393,.564),l(.156,.635),l(.358,.324),l(.359,.084),l(1.02,-.129),l(.928,-.059),l(.59,-.058),l(.799,-.059),l(.714,.125),l(.4,.479),l(.267,.169),l(.578,.253),l(.49,.14),l(1.094,.04),l(.382,-.057),l(.388,-.227),l(1.042,-.807),l(.47,-.185),l(.453,.042),l(.959,-.073),l(1.152,-.073),l(.919,.055),l(.248,.112),l(-.056,.141),l(-.294,.185),l(-.854,-.041),l(-.433,.015),l(-.083,.212),l(.059,.184),l(.593,.253),l(.609,.535),l(.195,.649),l(.246,-.523),l(.185,-.142),l(.415,.253),l(.483,.027),l(.374,.098),l(.258,.338),l(.918,.394),l(.464,.295),l(-.729,.496),l(-.161,.65),l(-.214,.226),l(-1.055,.417),l(.5,.064),l(.598,.098),l(.368,-.029),l(.33,-.142),l(.929,-.03),l(.725,.083),l(.84,.274),l(.095,.296),l(-.061,.41),l(-1.655,1.239),l(-.101,.255),l(.074,.212),l(.62,.604),l(.141,.282),l(-.308,.299),l(-.41,.144),l(-1.032,.19),l(-.061,.452),l(.008,.58),l(-.395,.539),l(-.071,.212),l(.324,.521),l(.732,.745),l(.503,.647), +N(493.044,204.258),l(-1.223,-1.771),l(-.027,-.932),l(-.03,-1.43),l(-.042,-2.045),l(-.003,-1.017),l(0,-.438),l(.016,-.848),l(.004,-1.215),l(.002,-.508),l(1.649,-2.467),l(.453,-.511),l(.305,-.101),l(1.216,-.078),l(.337,-.115),l(.294,-.426),l(.502,-.497),l(.388,-.214),l(.562,-.215),l(.626,-.088),l(1.693,.046),l(.8,-.004),l(.813,-.909),l(1.562,-1.69),l(4.087,-4.205),l(-.236,-.154),l(-1.875,.04),l(-1.447,-.472),l(-4.26,-1.443),l(-.54,-.209),l(-.634,-.321),l(-.596,-.547),l(-.732,-.801),l(-.587,-.844),l(-.428,-.732),l(-.083,-.409),l(.363,-.807),l(.34,-.567),l(.37,-.468),l(.114,-.26),l(.154,.044),l(.935,1.142),l(.586,.62),l(.243,.381),l(.265,.211),l(.372,-.071),l(.417,-.001),l(.465,.027),l(.372,-.071),l(.572,-.27),l(.836,-.425),l(.585,-.157),l(.397,.098),l(.76,.267),l(.549,-.072),l(.56,-.326),l(.779,-.566),l(.247,-.127),l(.447,.041),l(.479,.098),l(.419,-.043),l(1.195,-.482),l(.288,.027),l(.682,.196),l(.74,-.03),l(.764,-.185),l(.964,-.327),l(.9,-.666),l(.47,-.382),l(.604,.154),l(.391,.211),l(.08,.014),l(.147,.268),l(-.414,.919),l(.021,.564),l(.132,.621),l(-.165,.452),l(-.375,.509),l(-.028,.678),l(-.047,.833),l(-.163,.509),l(-1.264,2.262),l(-.842,.792),l(-.122,.311),l(.102,.353),l(-.893,1.569),l(-.834,1.272),l(-.214,.947),l(-.351,.636),l(-.712,1.117),l(-.874,1.188),l(-1.159,1.498),l(-.384,.439),l(-2.274,2.504),l(-1.82,1.557),l(-2.164,1.121),l(-.593,.382),l(-1.28,1.09),l(-1.74,1.755),l(-.06,.061),l(-1.055,1.1),l(-1.235,1.569),l(-.615,.835),l(.1,.353),l(-.094,.276), +N(264.768,176.039),l(-.128,.225),l(-.115,.067),l(-.029,.135),l(.039,.25),l(-.058,.086),l(.125,.376),l(-.039,.424),l(-.453,.154),l(-.135,-.01),l(-.144,.039),l(-.482,-.039),l(-.192,.039),l(-.087,-.048),l(-.356,0),l(-.02,-.058),l(.039,-.067),l(.202,-.029),l(.222,-.135),l(.019,-.087),l(.106,.02),l(.154,.01),l(.135,-.145),l(-.096,-.279),l(.048,-.125),l(.029,-.183),l(-.067,-.125),l(-.097,-.135),l(-.279,-.048),l(.116,-.096),l(.164,-.019),l(.231,-.029),l(.115,-.087),l(.385,.02),l(.106,-.039),l(.299,-.067),l(.244,.006), +N(654.075,190.187),l(.206,-.125),l(.63,-.114),l(.656,-.938),l(.241,-.07),l(-.069,.268),l(.122,.087),l(.187,-.046),l(.11,.174),l(.148,.444),l(-.024,.111),l(-.013,.247),l(.197,.197),l(.025,.086),l(-1.234,.42),l(-.383,.271),l(-.309,-.271),l(-.111,-.259),l(-.234,.012),l(-.062,-.37),l(-.084,-.126), +N(493.044,204.258),l(-.602,.389),l(-.557,.171),l(-.385,-.112),l(-.086,.777),l(-.282,.367),l(-.67,.115),l(-.394,.382),l(-.088,.48),l(.006,.353),l(-.356,.622),l(-.964,1.358),l(.092,.536),l(-.337,.65),l(-.25,.255),l(-.334,.1),l(-.084,.152),l(-1.067,-.807),l(-2.427,-1.752),l(-.07,-.239),l(.116,-.552),l(-.137,-.381),l(-3.553,-1.984),l(-4.663,-2.568),l(-1.448,.033),l(1.144,-2.479),l(.105,-.229),l(.656,-.835),l(.985,-.938),l(.477,-.525),l(.43,-.695),l(.143,-.566),l(-.048,-.664),l(-.223,-.606),l(-.224,-.352),l(-.732,-1.069),l(-.174,-.465),l(-.027,-.861),l(-.126,-.226),l(-.477,-.463),l(-.3,-.493),l(.678,-.795),l(.291,-.327),l(.671,.052),l(.832,-.005),l(1.009,-.133),l(.464,-.017),l(.079,.028),l(.319,.069),l(1.054,.149),l(.749,.193),l(.604,.293),l(2.353,1.525),l(.335,.041),l(1.373,.133),l(.67,.193),l(.847,.094),l(.16,-.114),l(.71,-.753),l(.258,-.199),l(.675,-.343),l(.852,-.358),l(.271,.098),l(.46,.336),l(.461,.181),l(1.103,.106),l(-1.649,2.467),l(-.002,.508),l(-.004,1.215),l(-.016,.848),l(0,.438),l(.003,1.017),l(.042,2.045),l(.03,1.43),l(.027,.932),l(1.223,1.771), +N(466.196,203.275),l(.188,-.298),l(.076,-.27),l(-.057,-.748),l(.025,-.734),l(-.021,-.593),l(.107,-.507),l(.217,-1.02),l(.395,-.681),l(.255,-.284),l(1.241,-.996),l(1.195,-1.066),l(.191,-.453),l(-.111,-.31),l(-.271,-.182),l(-.479,-.04),l(-.191,-.027),l(-.128,-.253),l(.26,-1.88),l(.018,-.424),l(-.159,-.183),l(-.063,-.028),l(.496,-.229),l(.464,-.087),l(.495,.011),l(.942,.234),l(.911,-.048),l(.881,-.33),l(.88,-.132),l(.303,.097),l(.303,.196),l(.367,-.016),l(.626,-.314),l(.563,-.54),l(.3,.493),l(.477,.463),l(.126,.226),l(.027,.861),l(.174,.465),l(.732,1.069),l(.224,.352),l(.223,.606),l(.048,.664),l(-.143,.566),l(-.43,.695),l(-.477,.525),l(-.985,.938),l(-.656,.835),l(-.105,.229),l(-1.144,2.479),l(-4.659,0),l(-1.277,.05),l(-.319,.017),l(-.554,.398),l(-.458,.427),l(-.431,.045),l(-.546,-.223),l(-.064,-.042), +N(713.621,206.298),l(.169,7.966),l(-.44,.822),l(.431,1.368),l(.046,.805),l(-.031,3.438),l(-.515,-.512),l(-.927,-.888),l(-.716,-.902),l(-.406,-.056),l(-.776,.101),l(-.739,.143),l(-.434,-.013),l(.091,-.382),l(.435,-.65),l(.006,-.283),l(-.561,-.521),l(-.565,-.775),l(.028,-.226),l(.442,.111),l(.236,-.042),l(.135,-.113),l(-.467,-.409),l(-.595,-.408),l(-.287,-.381),l(-.275,-.648),l(-1.053,-1.693),l(-.508,-.394),l(-.467,-.282),l(-.604,-.196),l(-1.983,-.603),l(-1.26,-.379),l(-.613,-.069),l(-.705,-.238),l(-.63,-.323),l(.072,-.34),l(-.098,-.268),l(-.193,-.028),l(-.617,.101),l(-.389,-.07),l(-.412,-.196),l(-.408,-.395),l(-.209,-.579),l(.133,-.494),l(-.155,-.226),l(-.187,.113),l(-.234,.396),l(-.122,.664),l(-.251,.608),l(-.334,.269),l(-.696,.354),l(-.155,-.169),l(-.331,-.677),l(.022,-.155),l(.384,-.27),l(-.152,-.424),l(-.173,-.239),l(-.564,-.395),l(-.707,-.394),l(-.338,-.056),l(-.059,-.212),l(.038,-.226),l(.413,-.044),l(.388,.084),l(.603,.239),l(.158,-.029),l(.368,-.34),l(.525,-.41),l(.146,.056),l(.3,.269),l(1.021,-.045),l(.139,-.128),l(.09,-.522),l(-.063,-.409),l(-.238,.028),l(-.345,.199),l(-.604,.071),l(-.656,-.041),l(-.766,.044),l(-1.026,-.082),l(-.411,-.31),l(-.135,-.197),l(-.148,-.664),l(-.202,-.338),l(-.42,-.155),l(-1.249,-.124),l(.265,-.297),l(.058,-.255),l(.004,-.593),l(.463,-.029),l(.92,-.411),l(.49,-.383),l(.444,-.283),l(.352,.027),l(.4,.069),l(1.494,.646),l(.515,.169),l(.913,.153),l(.382,.705),l(.138,.396),l(-.283,.749),l(-.067,.381),l(.221,.381),l(.115,.494),l(.115,.48),l(.215,.521),l(.186,.197),l(.197,.127),l(.226,-.65),l(.085,.113),l(.087,.141),l(.309,1.073),l(.169,.169),l(.234,.183),l(.294,.112),l(.354,.056),l(.58,-.198),l(.504,-.439),l(1.192,-1.853),l(.352,-.015),l(1.078,-.215),l(.378,-.142),l(.045,-.085),l(.014,-.509),l(.219,-.17),l(1.1,-.609),l(.335,-.043),l(1.732,.759),l(2.129,.941),l(1.54,.52),l(1.299,.404),M(691.208,208.707),l(-.388,-.069),l(-.693,-.38),l(-.852,-.647),l(-.295,-.141),l(-.414,.028),l(-.059,.1),l(.024,.452),l(-.206,.028),l(-1.014,-.407),l(-.258,-.353),l(-.582,.199),l(-.289,.269),l(-.326,.185),l(-.186,-.184),l(-.312,-.451),l(-.245,-.451),l(.246,-.198),l(.303,-.029),l(.274,.056),l(1.104,.04),l(.574,.31),l(.319,-.015),l(.544,-.326),l(.414,-.015),l(.534,.126),l(.857,.21),l(.499,.395),l(.293,.395),l(.179,.621),l(-.049,.254),M(682.045,208.699),l(-.419,-.056),l(-.715,-.493),l(-.232,-.451),l(.146,-.283),l(.603,-.1),l(.766,-.044),l(.246,.126),l(.256,.311),l(.313,.197),l(.108,.226),l(-.067,.226),l(-.125,.057),l(-.879,.285),M(707.635,219.095),l(-1.11,-.209),l(.589,-1.032),l(.56,-.708),l(.407,-.269),l(.427,-.072),l(.527,.338),l(.198,.24),l(-.11,.184),l(-.324,.637),l(-.256,.17),l(-.638,.693),l(-.27,.028),M(673.797,218.703),l(-.562,.257),l(.034,.233),l(-.886,.326),l(-.582,.274),l(-.339,-.041),l(-.453,.325),l(-.504,-.069),l(-.427,-.112),l(-.378,.255),l(-.3,.058),l(-.358,-.07),l(-.58,-.196),l(-1.046,-.04),l(-.316,.043),l(-.211,-.564),l(.027,-.24),l(.383,-.198),l(.672,-.199),l(.528,-.016),l(1.142,.407),l(.445,.324),l(.338,.013),l(.326,-.297),l(.464,-.016),l(.429,-.071),l(.414,.187),l(.467,-.116),l(-.072,-.222),l(.421,-.187),l(.404,-.233),l(.094,-.151),l(-.076,-.117),l(-.184,.023),l(.116,-.198),l(.16,.012),l(.22,.094),l(.177,.221),l(.013,.304),M(662.661,219.065),l(-.312,-.099),l(-.203,-.127),l(-.062,-.169),l(.03,-.212),l(.256,-.198),l(.315,-.036),l(.17,.092),l(.053,.212),l(.182,.098),l(.305,-.145),l(.34,.105),l(.104,.151),l(-.012,.451),l(.183,-.148),l(.163,-.304),l(.318,-.029),l(.229,.226),l(.021,.424),l(.181,-.036),l(.062,.104),l(-.025,.397),l(-.316,-.211),l(-.311,-.058),l(-.141,.058),l(.072,.155),l(-.852,.157),l(-.143,-.091),l(.097,-.268),l(-.085,-.059),l(-.308,.269),l(-.229,.256),l(-.296,-.046),l(-.63,.225),l(-.624,.199),l(-.357,-.051),l(-.31,.123),l(-.392,-.07),l(-.103,-.07),l(-.202,-.123),l(-.063,-.279),l(.143,-.261),l(-.08,-.253),l(.193,-.115),l(.23,-.113),l(.233,-.156),l(.224,.07),l(.61,.013),l(.4,.104),l(.089,.28),l(.291,.109),l(.294,.056),l(.189,-.259),l(.29,-.012),l(.051,-.187),l(-.263,-.15),M(656.294,219.602),l(-.393,-.282),l(-.855,-.449),l(-.118,-.269),l(.417,-.001),l(.514,-.185),l(.462,-.029),l(.925,.521),l(-.338,.17),l(-.232,.1),l(-.381,.425),M(631.053,200.125),l(-.061,.225),l(-.413,.439),l(-.204,.41),l(-.381,.354),l(.164,.353),l(.162,.169),l(.806,.493),l(.832,.055),l(.241,.112),l(.151,.381),l(.128,.763),l(-.007,.409),l(.267,.423),l(.212,.127),l(.544,.041),l(-.45,.933),l(.151,.212),l(.703,-.453),l(.824,.252),l(.177,.042),l(.265,.254),l(.144,.438),l(.698,.676),l(-.515,1.979),l(-.04,.452),l(.23,.946),l(-.021,.438),l(.021,.664),l(-.002,.268),l(-.149,1.06),l(-.087,.156),l(-.107,.07),l(-.367,-.253),l(-.381,-.522),l(-.261,-.084),l(-.262,.481),l(-.081,.268),l(-1.043,-.619),l(-.219,.086),l(.394,.747),l(-.163,.213),l(-.204,-.197),l(-1.343,-1.424),l(-.775,-.761),l(-1.011,-.859),l(-1.348,-.958),l(-.391,-.451),l(-.199,-.493),l(-.191,-.339),l(-1.003,-.633),l(-.697,-.677),l(-1.186,-1.509),l(-.074,-.353),l(.039,-.339),l(-.324,-.875),l(-.841,-1.467),l(-.667,-1.044),l(-.612,-.775),l(-.369,-.301),l(-.287,-.234),l(-.64,-.295),l(-.254,-.748),l(-.688,-1.806),l(.067,-.24),l(-.107,-.311),l(-.157,-.197),l(-.662,-.507),l(-.711,-.394),l(-.539,-.21),l(-.317,-.099),l(-.119,-.353),l(-.077,-.734),l(-.18,-.409),l(-.386,-.479),l(-.818,-.831),l(-.368,-.423),l(-.725,.128),l(-.613,-.676),l(-.646,-.606),l(-.593,-.69),l(-.562,-.945),l(-.229,-.635),l(-.032,-.367),l(.057,-.198),l(.149,-.113),l(.401,-.043),l(.364,.098),l(.25,.126),l(.632,.563),l(.361,.155),l(.922,.153),l(.335,.027),l(.548,-.1),l(.454,-.142),l(.4,-.015),l(.323,.31),l(.919,1.156),l(.513,.31),l(.058,.155),l(-.12,.537),l(1.066,.916),l(.749,.493),l(1.175,.689),l(.678,.323),l(.139,.169),l(.03,.593),l(-.02,.155),l(.573,.055),l(.745,.944),l(.612,.55),l(.271,-.015),l(.004,-.198),l(-.123,-.226),l(.069,-.24),l(.507,.21),l(.479,.804),l(.441,.38),l(.446,.056),l(.429,.197),l(.314,.366),l(.28,.734),l(.316,.437),l(.431,.268),l(.511,.126),l(.767,.083),l(.431,.154),l(.494,.38),l(.576,.606),l(-.019,.071),M(684.201,200.125),l(-.007,-.172),l(-.414,-1.058),l(.18,-.551),l(-.078,-.141),l(-.141,-.296),l(.036,-.325),l(.286,-.89),l(.514,-.82),l(.263,.367),l(.152,.353),l(-.054,.283),l(-.246,.396),l(-.361,.763),l(.061,.325),l(.19,.141),l(.097,-.141),l(.436,-.411),l(.135,-.522),l(.179,-.142),l(.806,-.412),l(.141,.141),l(-.052,.254),l(.104,.55),l(-.354,.212),l(-.467,.354),l(-.162,.311),l(.159,.099),l(.446,.126),l(.398,.211),l(-.016,.141),l(.159,.353),l(-.688,-.154),l(-.431,-.154),l(-.367,-.042),l(-.304,.156),l(-.08,.438),l(.049,.258),l(.131,.688),l(.341,.62),l(.405,.438),l(.196,.282),l(-.156,.212),l(-.26,-.211),l(-.664,-.648),l(-.55,-.733),l(-.002,-.396),l(-.011,-.251),M(637.361,207.144),l(-.863,-.394),l(-.377,-.239),l(-.205,-.367),l(-.045,-.367),l(-.156,-.395),l(-.507,-.395),l(-.291,-.099),l(-.446,.029),l(-.116,-.141),l(.271,-.65),l(.234,-.24),l(.509,.55),l(.148,-.467),l(.313,-.269),l(.072,.395),l(.312,.89),l(.648,.817),l(.698,.31),l(-.265,.184),l(-.118,.283),l(.183,.564),M(634.321,215.345),l(-.091,-.187),l(.316,-.023),l(.402,.093),l(.369,-.129),l(.068,-.524),l(.018,-.14),l(.309,.057),l(-.043,-.5),l(.222,-.235),l(.093,-.277),l(.202,.121),l(.631,.112),l(.474,-.047),l(.237,.443),l(.524,-.089),l(.158,-.297),l(.022,-.244),l(.259,.116),l(.618,.168),l(.411,.438),l(.338,-.046),l(.204,.271),l(.446,-.029),l(.453,-.185),l(.302,.211),l(.369,.522),l(.179,.521),l(.884,.041),l(.462,.188),l(.49,-.077),l(1.435,.124),l(.479,-.029),l(.34,-.17),l(.213,-.65),l(.271,-.269),l(.447,-.015),l(.223,.211),l(.289,.494),l(.633,.125),l(.53,.027),l(.774,.083),l(.796,.153),l(.289,.24),l(.293,.288),l(-.08,.445),l(.275,.466),l(.119,.099),l(.877,.352),l(.422,.069),l(.658,.013),l(.45,-.185),l(.415,-.015),l(.628,.238),l(.048,.197),l(-.255,.425),l(-.152,.494),l(.578,.776),l(-.499,-.211),l(-.802,-.196),l(-.599,-.253),l(-.891,-.309),l(-.528,.001),l(-.589,.256),l(-.348,.057),l(-.714,-.098),l(-1.454,-.138),l(-1.47,-.138),l(-.805,-.253),l(-.839,-.479),l(-1.099,-.336),l(-1.125,-.267),l(-.948,-.04),l(-.556,.298),l(-.445,.043),l(-.957,-.153),l(-.805,-.492),l(-.357,-.07),l(-1.606,-.066),l(-.363,-.155),l(.055,-.141),l(.448,-.468),l(-.402,-.267),l(-.551,-.099),l(-.506,-.14),l(-.307,-.027),l(-1.261,-.121),M(675.004,223.092),l(.249,-.494),l(.023,-.537),l(.113,-.312),l(.674,-.481),l(1.447,-.624),l(.662,-.454),l(.36,-.607),l(.466,-.157),l(1.578,-.102),l(.91,-.214),l(.541,-.044),l(.869,-.143),l(.118,.07),l(.099,.197),l(-.237,.212),l(-.36,.256),l(-1.609,.61),l(-1.369,.44),l(-.713,.256),l(-.606,.354),l(-1.09,.963),l(-.653,.481),l(-.439,.086),l(-.552,.228),l(-.48,.015),M(667.866,223.149),l(-.217,-.069),l(-.917,-.605),l(-.8,-.45),l(-.347,-.099),l(-.493,-.126),l(-.292,-.197),l(.108,-.212),l(.371,-.142),l(.992,-.03),l(.502,-.114),l(.35,.296),l(1.147,.746),l(.265,.381),l(-.125,.325),l(-.246,.24),l(-.299,.057),M(661.819,191.241),l(-.041,.09),l(.319,.691),l(-.23,.142),l(-.546,.043),l(-.579,.086),l(.198,.226),l(.115,.296),l(-.169,.226),l(.216,.211),l(.235,.112),l(.546,.832),l(.536,.747),l(.043,.198),l(-.338,.721),l(.075,.226),l(.406,.465),l(.743,.45),l(.6,.493),l(.551,.761),l(-.465,.17),l(-.75,-.026),l(-.797,-.238),l(-.337,.1),l(-.387,.467),l(-.354,.918),l(-.08,.476),l(-.046,.272),l(.132,.649),l(.116,.424),l(-.133,.848),l(-.256,0),l(-.466,-.154),l(-1.037,.963),l(-.433,.65),l(-.751,.608),l(.443,.381),l(.06,.396),l(.17,.296),l(-.685,.058),l(.452,.578),l(.009,.212),l(-.103,.227),l(-.547,.665),l(-.206,.396),l(-.127,.354),l(-.529,.594),l(-1.294,.61),l(-.607,.284),l(-.292,.198),l(-.194,-.311),l(.024,-.424),l(-.33,-.804),l(-.306,-.381),l(-.265,-.184),l(-.286,.029),l(-.503,.523),l(-.302,.029),l(-.328,-.508),l(-.313,-.197),l(-.437,-.112),l(-.387,-.451),l(-.342,-.154),l(-.35,.806),l(-.135,.198),l(-.381,.058),l(-.356,-.112),l(-.442,.128),l(-.318,.354),l(-.364,.071),l(-.059,-.551),l(.034,-.311),l(-.314,-1.03),l(-.336,.396),l(-1.42,.44),l(-.321,-.408),l(-.639,.015),l(-.281,.156),l(-.303,.029),l(-.058,-.649),l(-.022,-.65),l(-.267,-1.411),l(-.012,-.48),l(-.352,-.747),l(-.406,-.409),l(-.79,-.422),l(-.146,-.141),l(.555,-.354),l(-.531,-.38),l(-.258,-.296),l(.188,-.735),l(-.074,-.128),l(-.278,-.478),l(-.352,-.296),l(.065,-.466),l(-.125,-.593),l(.182,-.65),l(.133,-.353),l(.424,-.58),l(.303,-.806),l(.318,.028),l(.204,.11),l(.288,.792),l(.253,.295),l(1,.983),l(.304,.083),l(.446,.28),l(.928,-.416),l(.255,-.001),l(.526,.223),l(.543,.11),l(.399,-.172),l(.528,-.342),l(.403,-.525),l(.531,-.441),l(.479,-.074),l(.431,.11),l(.557,.251),l(.524,.223),l(.559,.152),l(.287,-.03),l(.467,-.356),l(.465,-.172),l(.864,-.175),l(.387,-.299),l(.928,-1.785),l(-.076,-.748),l(.218,-.34),l(.646,-.244),l(.22,-.383),l(-.106,-.988),l(.119,-.565),l(.381,-.638),l(.247,-.157),l(.464,-.017),l(.748,.081),l(.651,.081),l(.624,-.018),l(.446,.04),l(.753,.292),l(.182,.09),M(666.561,200.125),l(.012,-.049),l(.48,-1.188),l(.434,-.41),l(.289,-.142),l(.429,.338),l(.29,-.311),l(.162,-.325),l(.293,-.481),l(.496,-.058),l(.605,.14),l(.729,.535),l(.447,.027),l(.863,-.044),l(.478,.168),l(.749,.267),l(.577,-.227),l(1.853,.081),l(.72,-.128),l(.627,-.354),l(.211,-.283),l(-.156,-.268),l(.196,-.283),l(.388,-.241),l(.295,-.41),l(.289,-.057),l(.075,.24),l(-.073,.537),l(-.117,.311),l(-.081,.127),l(-.082,.127),l(-.969,1.259),l(-.416,.396),l(-.464,.1),l(-1.23,.229),l(-.495,-.069),l(-.591,-.422),l(-1.149,-.068),l(-1.151,.059),l(-.878,-.041),l(-1.039,.045),l(-.575,-.083),l(-.671,.029),l(-.415,.1),l(-.433,.368),l(-.259,.461),l(-.154,.274),l(-.187,.721),l(.068,.48),l(.263,.494),l(.194,.183),l(.403,.226),l(.259,.196),l(.221,.607),l(.179,.154),l(.226,.042),l(.815,.026),l(.249,-.269),l(.652,-.976),l(.385,.056),l(.307,.183),l(.496,.041),l(.363,-.227),l(.669,-.156),l(.62,-.143),l(.268,-.298),l(.271,-.057),l(.466,.196),l(.131,.212),l(-.083,.734),l(-.469,-.267),l(-.544,-.042),l(-.361,.298),l(-.389,.523),l(-.438,.425),l(-1.059,.439),l(-.214,.325),l(-.143,.029),l(-.241,-.042),l(-.468,-.126),l(-.03,.056),l(.025,.312),l(.212,.126),l(.676,.578),l(.467,.521),l(.854,1.24),l(-.097,.325),l(-.156,.679),l(.102,.409),l(.447,.535),l(.555,.438),l(.062,.226),l(-.045,.282),l(-.436,-.056),l(-.652,.059),l(-.412,.297),l(-.224,.692),l(-.498,-.026),l(-.461,-.183),l(-.107,-.17),l(.052,-.649),l(.204,-.58),l(-.978,-.845),l(-.417,-.31),l(-.174,-.269),l(.036,-.24),l(.284,-.396),l(.116,-.579),l(-.165,-.494),l(-.737,-.055),l(-.503,.213),l(-.494,.396),l(.16,.353),l(.143,.932),l(-.068,.509),l(-.236,1.145),l(.363,.903),l(-.01,.311),l(-.377,.636),l(-.019,.227),l(.275,.564),l(-.726,.171),l(-.513,.241),l(-.476,.071),l(-.245,-.324),l(-.16,-.522),l(.156,-.325),l(.181,-.466),l(.069,-.876),l(.06,-1.073),l(-.125,-.509),l(.029,-.339),l(-.213,-.395),l(-.311,-.127),l(-.391,.171),l(-.574,.029),l(.011,-.41),l(-.25,-1.284),l(.131,-.311),l(.491,-.524),l(.469,-.777),l(.161,-.48),l(-.089,-.918),l(-.006,-.254),l(.087,-.452),l(.339,-.721),l(.447,-.058),l(-.043,-.861),l(.254,-1.053), +N(341.05,41.069),l(2.084,.272),l(.344,.361),l(-.869,.174),l(-.541,.139),l(-1.678,.106),l(-1.159,.037),l(-.689,.156),l(-.372,.224),l(-.308,.6),l(-.361,.376),l(1.05,.39),l(.971,.168),l(2.117,.064),l(.601,-.001),l(1.775,-.242),l(1.93,-.038),l(.866,.135),l(.933,.219),l(.417,.135),l(.284,-.018),l(1.001,-.002),l(1.277,.032),l(.615,.05),l(-1.277,.626),l(-1.583,.457),l(-1.976,.523),l(-.556,-.016),l(-.695,-.116),l(-.951,.671),l(-1.061,.503),l(-1.246,.452),l(-1.125,.296),l(-.211,.056),l(-2.212,.054),l(-.525,.134),l(-.502,.001),l(-.982,.201),l(-.665,.167),l(-.528,.051),l(-.946,-.413),l(-.375,.05),l(-.69,.913),l(-.958,.118),l(-.631,-.065),l(-.743,-.197),l(-.622,-.463),l(-.854,-.43),l(-.647,-.215),l(-.109,0),l(.008,.2),l(.707,1.043),l(-.192,.249),l(-.319,.017),l(-.69,.249),l(-.84,.249),l(-.573,.38),l(-1,.906),l(-.657,.657),l(-1.051,.851),l(-.776,.262),l(-1.034,.083),l(-1.023,-.275),l(-.148,.554),l(-.438,.569),l(-.783,.277),l(-.992,-.095),l(-.616,.05),l(-1.18,.439),l(.942,-1.723),l(-.121,.017),l(-.795,-.015),l(-1.055,-.177),l(.26,.423),l(-.026,.455),l(-.386,.407),l(-.794,.39),l(-1.16,.164),l(-.973,.002),l(-1.255,.083),l(.467,.403),l(.212,.403),l(-.09,.387),l(-.379,.097),l(-.321,-.063),l(-.47,.033),l(-1.792,-.157),l(.517,.32),l(.765,.462),l(.295,.351),l(-.01,.224),l(-.26,.176),l(-1.197,.034),l(-1.051,.129),l(.844,.413),l(.47,.126),l(.448,.222),l(.389,.333),l(-.554,.461),l(-.285,.111),l(-.599,-.094),l(-.478,.096),l(.345,.474),l(-.009,.127),L(308.501,60),l(-.486,-.125),l(-.583,-.062),l(.026,.158),l(.255,.457),l(-.101,.347),l(-.288,0),l(-.656,-.093),l(-.089,-.016),l(-.979,.112),l(-1.081,.018),l(.682,.487),l(1.108,.391),l(.331,.204),l(-.077,1.035),l(-.382,.938),l(-.427,.094),l(-.815,-.061),l(.489,.591),l(-.016,.498),l(.156,.233),l(-.068,.373),l(-.316,.062),l(-.495,-.03),l(-.771,.079),l(.762,.386),l(.427,.603),l(-.117,.447),l(-.287,.031),l(-.967,-.26),l(-1.052,-.508),l(-.498,.294),l(-.425,.602),l(-.635,-.599),l(.158,-.573),l(-.387,-.201),l(-1.124,-.184),l(-.577,-.309),l(.04,-.187),l(.253,-.249),l(.066,-.218),l(-.325,-.28),l(-.366,-.186),l(-.668,.359),l(-.276,.016),l(-.3,.141),l(-.444,-.046),l(-.98,.064),l(-.417,.017),l(-.571,.296),l(-.476,.28),l(-.426,-.403),l(-.104,-.357),l(-.222,-.217),l(-.513,-.233),l(-.817,-.232),l(-.772,-.389),l(-.517,-.781),l(.07,-.737),l(-.199,-.156),l(-.434,-.094),l(-.467,.048),l(-.97,-.266),l(-.108,-.094),l(-.138,-.236),l(.14,-.457),l(.459,-.395),l(.071,-.269),l(-.258,-.062),l(-.551,-.031),l(-.542,-.094),l(-.278,-.221),l(-.058,-.633),l(-.458,-.126),l(-.616,.049),l(-.589,-.57),l(.023,-.191),l(.198,-.254),l(.618,-.367),l(1.22,-.337),l(.405,-.304),l(.476,-.128),l(.051,-.383),l(-.277,-.287),l(-.473,.097),l(-.921,.082),l(-.493,.097),l(-.635,.416),l(-.538,.129),l(-.63,.304),l(-.339,-.318),l(.038,-.623),l(-.114,-.784),l(-.206,-.451),l(.015,-.355),l(-.243,-.323),l(-.504,.082),l(-.271,-.032),l(-.666,-.355),l(-.594,-.485),l(-.013,-.357),l(.842,-.538),l(.265,.019),l(-.556,-.189),l(-1.083,.064),l(-.103,-.284),l(.383,-.176),l(.677,-.03),l(.586,-.052),l(.456,-.087),l(.322,-.672),l(-1.208,-.047),l(-.572,.05),l(-.362,-.032),l(-.29,-.163),l(-.116,-.197),l(.223,-.28),l(.218,-.008),l(.18,-.16),l(.427,-.055),l(-.375,-.188),l(-.552,.073),l(-.22,-.248),l(.057,-.188),l(.073,-.132),l(.259,0),l(.309,-.099),l(.827,-.25),l(1.218,.081),l(.854,.163),l(.776,.032),l(.378,.131),l(.927,.146),l(1.027,.097),l(-.031,-.363),l(.299,-.545),l(-.298,-.182),l(-1.02,-.263),l(-1.356,-.312),l(-.903,-.164),l(-1.592,-.33),l(-.354,-.116),l(.336,-.35),l(.788,-.001),l(1.462,.363),l(1.034,.048),l(.463,-.067),l(.114,-.067),l(.088,-.6),l(.088,-.301),l(.595,-.034),l(.528,.116),l(.227,-.101),l(-.027,-.351),l(-.195,-.184),l(-.891,-.317),l(.162,-.437),l(.528,-.455),l(-.258,-.286),l(-1.21,-.167),l(-1.154,.002),l(-1.178,-.286),l(-1.649,-.49),l(-.78,-.101),l(-.903,-.05),l(-.76,-.34),l(-.811,-.477),l(.156,-.035),l(.323,-.155),l(.605,-.001),l(.572,-.019),l(2.085,.305),l(.716,.033),l(1.249,.306),l(1.451,.458),l(.729,.169),l(.056,-.307),l(-.311,-.426),l(-.86,-.546),l(-.172,-.446),l(-.603,-.446),l(-.485,-.051),l(-.677,-.24),l(.361,-.277),l(.542,-.139),L(285.644,41),l(-.704,-.241),l(-1.101,-.015),l(-.625,-.086),l(-1.132,-.327),l(-.88,.608),l(-.324,.156),l(-.274,.294),l(-.875,.243),l(-1.402,-.066),l(-1.031,-.343),l(-.306,-.242),l(-.027,-.294),l(.438,-.313),l(.293,-.645),l(-.152,-1.259),l(.582,-.054),l(.691,.192),l(.372,-.124),l(.151,-.334),l(-.383,-.369),l(-.933,-.545),l(-.452,-.141),l(-.946,-.796),l(-.895,-.925),l(-1.105,-1.289),l(-.578,-.485),l(-1.855,-.379),l(-.667,-.255),l(-.291,-.202),l(-.052,-.701),l(-.904,-.406),l(-.962,-.109),l(-1.589,-.165),l(-1.928,-.425),l(-1.903,-.333),l(-2.133,-.183),l(-.997,-.054),l(-1.632,-.035),l(-.785,.189),l(-1.043,.096),l(-.806,.188),l(-1.419,.152),l(-1.228,-.166),l(-1.46,-.296),l(.319,.747),l(-.051,.093),l(-1.051,-.017),l(-1.294,-.184),l(-3.168,-.611),l(1.538,-.566),l(.463,-.114),l(-.092,-.226),l(-.423,-.169),l(-1.067,-.017),l(-2.21,-.015),l(-.812,-.074),l(-.629,-.018),l(-1.238,-.434),l(-.87,-.208),l(.587,-.306),l(1.257,-.041),l(3.036,.147),l(2.025,.034),l(1.343,.017),l(2.117,-.157),l(1.055,-.212),l(.292,-.096),l(.054,-.345),l(-.627,-.287),l(-.82,-.21),l(-1.217,.156),l(-1.11,.252),l(-1.31,.021),l(-1.138,-.113),l(-.753,.078),l(-.879,.098),l(-.68,-.056),l(-.857,-.19),l(-.664,-.365),l(-.816,-.191),l(-.662,-.057),l(-.726,.059),l(-.486,-.076),l(-1.416,-.481),l(-.044,-.35),l(.36,-.45),l(.81,-.119),l(1.235,-.1),l(1.517,-.14),l(2.074,-.161),l(1.29,-.081),l(.951,-.396),l(1.089,-.259),l(.843,-.081),l(2.478,-.005),l(1.101,-.101),l(1.942,.036),l(.402,-.139),l(.31,-.199),l(.609,-.16),l(.202,-.658),l(.276,-.501),l(.116,-.101),l(-.89,-.228),l(-1.947,-.039),l(-1.155,.194),l(-.959,-.125),l(-1.243,-.383),l(.595,-.781),l(1.38,-.332),l(2.845,-.359),l(1.407,-.225),l(1.962,-.249),l(2.112,-.162),l(1.163,.087),l(1.213,-.07),l(1.319,-.07),l(.345,-.181),l(.011,-.226),l(-.357,-.753),l(-.022,-.208),l(.522,-.14),l(1.886,-.05),l(1.526,.205),l(2.141,.41),l(1.296,.226),l(.802,.181),l(.823,-.275),l(-1.657,-.525),l(-.697,-.509),l(.167,-.047),l(2.2,-.122),l(1.166,-.12),l(1.854,-.216),l(2.52,-.195),l(.73,.069),l(1.064,.116),l(.232,1.738),l(.913,-.162),l(.539,-.322),l(.432,-1),l(1.003,.021),l(2.004,.323),l(1.858,.414),l(1.529,.25),l(.205,-.3),l(-.644,-.3),l(-.816,-.537),l(-.894,-.4),l(.295,-.287),l(.742,.022),l(1.758,.02),l(1.136,.212),l(2.754,.373),l(1.284,.279),l(2.109,.322),l(1.878,.274),l(1.872,.204),l(.8,-.209),l(.816,-1.483),l(-.326,-.191),l(-1.292,-.334),l(-1.176,-.533),l(.708,-.247),l(2.404,-.005),l(2.962,-.328),l(1.329,-.077),l(1.527,.17),l(2.221,.488),l(1.567,.167),l(2.005,.142),l(.3,-.761),l(-.3,-.472),l(2.646,-.206),l(2.021,-.08),l(2.589,.095),l(1.989,.146),l(1.886,-.18),l(2.367,-.207),l(2.043,-.005),l(1.859,.223),l(1.825,-.055),l(1.315,.072),l(.619,.099),l(.55,-.102),l(1.946,.146),l(1.707,.046),l(1.673,.096),l(2.438,.761),l(1.368,.241),l(1.345,-.076),l(1.118,.168),l(2.594,.237),l(.445,.408),l(-.304,.12),l(-.492,.192),l(-1.683,.146),l(-2.303,.124),l(-1.152,.121),l(-1.233,.05),l(-1.469,-.068),l(-2.831,-.064),l(-2.22,-.066),l(-1.389,.168),l(-1.614,.027),l(-1.933,.027),l(-1.16,.026),l(-1.485,.168),l(-.444,.118),l(-1.322,.213),l(-.335,.464),l(.743,.251),l(2.551,-.281),l(1.367,-.072),l(3.912,.038),l(2.223,-.12),l(2.331,-.005),l(.997,-.025),l(.93,.067),l(1.77,.434),l(.671,.09),l(1.087,-.186),l(1.663,-.21),l(1.536,-.281),l(1.964,-.144),l(.59,.462),l(-.566,.482),l(-2.316,.639),l(-.973,.338),l(-1.281,.734),l(.12,.307),l(.319,.152),l(.796,-.089),l(.477,-.044),l(1.616,-.553),l(1.766,-.537),l(1.413,-.385),l(1.706,-.32),l(.775,-.207),l(1.662,-.163),l(1.618,.111),l(1.391,.065),l(1.497,-.3),l(.703,-.324),l(1.129,-.234),l(2.148,-.004),l(1.672,.112),l(1.097,.044),l(1.197,.136),l(1.135,.228),l(1.107,.112),l(.316,.25),l(-.181,.273),l(-1.97,.252),l(-1.491,.138),l(-1.245,.494),l(-.557,.289),l(-1.604,.355),l(-1.57,.548),l(-1.063,.089),l(-.918,-.042),l(-1.592,.047),l(-2.213,-.039),l(-1.491,.198),l(-.731,.217),l(-.495,.535),l(.166,.322),l(1.949,-.305),l(1.581,-.046),l(1.856,.101),l(.003,.42),l(-.743,.241),l(-2.388,.124),l(-.463,.14),l(-.213,.199),l(-.156,.595),l(-.471,.71),l(-.678,.158),l(-1.06,-.077),l(-.742,.041),l(-.837,.9),l(-.987,1.087),l(-.15,.347),l(.454,.307),l(.403,.095),l(.602,-.481),l(.743,-.368),l(.856,-.041),l(2.345,.266),l(.353,.096),l(.262,.288),l(-.059,.211),l(-1.234,-.074),l(-.673,-.018),l(-.512,.097),l(-.136,.191),l(.29,.286),l(1.756,.188),l(.557,.132),l(1.802,-.137),l(.526,.208),l(.214,.323),l(-.049,.436),l(-.256,.133),l(-1.835,-.186),l(-1.653,-.054),l(-.781,-.074),l(-1.295,.078),l(-1.382,.475),l(-.823,-.13),l(-.49,-.15),l(-1.06,.04),l(-.283,.377),l(1.393,.599),l(1.187,.222),l(1.298,.128),l(1.665,.072),l(.696,.148),l(.551,.482),l(.272,.444),l(.014,.554),l(-.434,.405),l(-.384,.074),l(-1.292,-.181),l(-.82,-.109),l(-.372,.111),l(.023,.55),l(.118,.236),l(.426,.162),l(.618,.089),l(.723,.215),l(.914,.142),l(.752,.16),l(.383,.376),l(-.338,.233),l(-.832,.145),l(-.647,.126),l(-1.747,-.032),l(-1.176,-.087),l(-1.624,-.086),l(-.592,.448),l(.551,.195),l(1.396,.051),l(1.052,.158),l(.724,.248),l(.088,.319),l(-.035,.549),l(-.13,-.005),l(-1.092,-.045),l(-1.247,.108),l(-.596,.266),l(-1.246,.02),l(-1.225,-.139),l(-1.497,-.404),l(-.922,-.478),l(-.373,-.07),l(-1.094,.286),L(345,36.811),l(-1.084,.09),l(-.589,.178),l(-1.451,-.033),l(-.913,-.087),l(-.969,.143),l(-.395,.125),l(-.174,.283),l(.006,.141),l(.354,.527),l(.71,.245),l(1.284,.05),l(1.515,.26),l(1.567,-.056),l(1.323,.54),l(.758,.226),l(.482,.226),l(1.196,.329),l(1.252,.38),l(.376,.276),l(.483,.898),l(.892,-.208),l(.278,-.139),l(.397,.207),l(.298,.43),l(.071,.344),l(.198,1.164),l(-.169,.205),l(-.371,.12),l(-.541,-.101),l(-.546,-.119),l(-.917,.002),l(-1.041,.036),l(-1.488,-.27),l(-.637,-.409),l(-.415,-.634),l(-.354,-.274),l(-1.17,-.566),l(-.84,-.292),l(-.748,-.137),l(-1.095,-.084),l(-.521,.14),l(-.962,.105),M(351.365,40.026),l(-1.527,-.537),l(-.96,-.225),l(-.712,-.156),l(-.159,-.069),l(-.314,-.419),l(1.483,-.038),l(.893,.139),l(1.064,.26),l(.819,.296),l(.162,.488),l(-.215,.209),l(-.533,.053),M(281.574,46.135),l(-.568,-.133),l(-.707,-.318),l(-.801,-.183),l(-.197,-.101),l(-.25,-.218),l(-.08,-.844),l(.287,-.34),l(.368,-.018),l(.646,.135),l(1.157,.066),l(1.287,.27),l(.748,.269),l(.595,.1),l(.777,.217),l(.603,.335),l(-.144,.202),l(-.112,.034),l(-.543,.051),l(-.774,.035),l(-.77,.186),l(-1.009,.153),l(-.511,.102), +N(105.98,81.688),l(-.952,-.826),l(-.198,-.342),l(-.024,-.476),l(.095,-.104),l(.408,.044),l(.312,-.045),l(.781,.177),l(.658,-.076),l(.28,.119),l(.138,.163),l(-.234,.224),l(-.173,.565),l(-.028,.312),l(-.581,.075),l(-.483,.19),M(125.24,92.375),l(-1.312,-.288),l(-1.345,-.434),l(-.218,-.174),l(.061,-.189),l(.376,-.466),l(-1.023,.002),l(-.413,.248),l(-.299,-.072),l(-.416,-.188),l(.166,-.452),l(-.487,-.334),l(-.269,-.014),l(-.735,-.086),l(-.226,-.262),l(.317,-.292),l(-.976,-.524),l(-.556,.118),l(-.386,-.102),l(-.852,-.511),l(-1.277,-.863),l(-.219,-.235),l(.02,-.117),l(.962,-.12),l(.337,.043),l(1.979,.598),l(.981,.204),l(1.772,.202),l(.385,.263),l(.618,.526),l(.426,.642),l(.433,.422),l(.362,.189),l(1.587,.536),l(.316,.203),l(.48,.756),l(.116,.407),l(-.279,.349),l(-.407,.016),M(271.379,92.089),l(-1.202,-.23),l(.641,-.743),l(.358,-.161),l(.279,.058),l(.292,0),l(.355,-.263),l(-.697,-.653),l(.079,-.219),L(272,89.003),l(1.121,-1.35),l(1.454,-1.31),l(.725,-.442),l(.496,-.192),l(1.315,-.194),l(.198,.073),l(.11,.221),l(-.299,.221),l(-.582,.03),l(-.242,.133),l(.349,.44),l(-.755,.78),l(-1.226,1.438),l(-.271,.526),l(.113,.291),l(.11,0),l(.428,-.176),l(.483,-.555),l(.458,-.191),l(1.115,.305),l(-.896,.687),l(.261,.203),l(.229,.072),l(1.423,.565),l(.758,-.03),l(.325,-.408),l(.309,-.059),l(.718,.057),l(.826,.202),l(.616,.231),l(-.297,.292),l(-.373,.233),l(-.708,.467),l(.339,.333),l(.477,.362),l(.26,.014),l(.417,-.161),l(.464,-.132),l(.278,.116),l(.02,.16),l(-.254,.262),l(-.404,.248),l(-.892,.104),L(280.84,93),l(.273,.362),l(.124,.405),l(.28,.231),l(.183,-.203),l(.309,-.262),l(.527,.159),l(-.099,.449),l(.149,.275),l(.716,.028),l(.085,-.015),l(.015,.203),l(-.168,.304),l(-.25,.652),l(-.34,.651),l(-.222,-.072),l(-.71,-.128),l(-.301,-.144),l(-.042,-.651),l(-.601,.406),l(-.374,.015),l(-.095,-.274),l(.497,-.652),l(.011,-.333),l(-.421,-.478),l(-.279,-.072),l(-.388,.392),l(-.423,.291),l(-.365,.146),l(-.435,.204),l(-.552,.536),l(-.496,.334),l(-.881,-.042),l(-.222,-.217),l(.165,-.145),l(1.229,-.408),l(.466,-.522),l(.632,-.363),l(-.699,-.129),l(-.601,-.057),l(-.322,.464),l(-.412,.015),l(-.13,-.159),l(.04,-.493),l(-.757,.016),l(-.148,.29),l(-.41,.218),l(-1.052,.045),l(-.709,-.057),l(-1.139,-.186),l(-1.012,-.085),l(-1.355,.061),l(-1.014,.147),l(-.145,-.188),l(-.215,-.463),l(.187,-.175),l(.561,-.334),l(.734,-.408),l(.502,-.161),l(.636,-.335),M(265.435,98.655),l(-.469,-.057),l(-.497,-.273),l(-.356,-.562),l(.062,-.635),l(.742,-.738),l(.932,-1.043),l(.816,.432),l(-.375,.435),l(-.112,.462),l(-.233,.333),l(-.262,.116),l(-.58,.319),l(-.244,.448),l(.522,.244),l(.168,-.029),l(.279,-.26),l(.42,-.362),l(.617,-.319),l(.309,.057),l(.495,.461),l(-.177,.347),l(-.246,.159),l(-1.134,.42),l(-.682,.044),M(211.34,59.677),l(-.68,-.046),l(.068,-.872),l(-.375,-.333),l(-.958,.161),l(-2.375,.29),l(.107,-.461),l(.56,-.303),l(1.644,-.561),l(-.302,-.478),l(-.102,-.415),l(.106,-.417),l(.398,-.835),l(.434,-.566),l(.254,-.648),l(.331,-.471),l(1.11,.566),l(-.312,.518),l(.791,.386),l(.527,.047),l(.402,-.469),l(.67,.112),l(.806,.289),l(.917,.514),l(.582,.255),l(2.168,.492),l(.442,.271),l(.176,.255),l(-.09,.925),l(.539,.047),l(.57,-.065),l(.934,.046),l(.701,.142),l(1.019,.427),l(-.419,.096),l(-.269,.127),l(-.46,.271),l(-.949,-.046),l(-.623,-.125),l(-1.328,-.125),l(-.438,-.126),L(217.259,58),l(-.528,-.301),l(-1.017,-.237),l(-.528,.017),l(-.203,.271),l(.174,.588),l(-.126,.096),l(-1.314,.161),l(-.673,.493),l(-.588,.302),l(-1.116,.287),M(200.125,19.1),l(-.862,-.015),l(-1.085,-.195),l(-.308,-.664),l(.819,-.304),l(.77,-.072),l(.666,-.024),l(3.475,-.125),l(1.263,-.12),l(1.374,-.026),l(1.714,.324),l(.397,-.094),l(.397,-.377),l(1.303,-.287),l(1.759,-.099),l(1.975,.209),l(.746,-.001),l(2.562,.137),l(2.621,.324),l(1.424,.09),l(1.461,.161),l(.448,-.165),l(-1.433,-.42),l(-1.67,-.352),l(-.816,-.429),l(.293,-.242),l(1.361,-.148),l(1.101,-.246),l(1.431,-.101),l(2.382,-.201),l(1.666,.119),l(1.944,.191),l(1.009,.265),l(1.19,.456),l(.354,.047),l(.273,-.362),l(-.959,-.508),l(-.828,-.292),l(.499,-.248),l(1.45,.121),l(1.832,.168),l(1.653,.07),l(1.639,.46),l(.378,.023),l(.062,-.195),l(-.301,-.539),l(1.781,-.004),l(1.408,.046),l(.832,.269),l(.831,.34),l(.618,-.001),l(-.044,-.268),l(-.331,-.467),l(1.075,-.077),l(3.691,.386),l(2.726,.288),l(1.937,-.077),l(2.987,.018),l(.967,.047),l(.757,.12),l(.126,0),l(1.419,.094),l(1.089,.191),l(.744,.095),l(1.685,.044),l(1.357,.357),l(-.385,.358),l(-1.237,.121),l(-1.206,.356),l(-1.849,.191),l(-.978,-.045),l(-2.191,-.159),l(-2.284,.005),l(-.776,.142),l(-1.915,.168),l(-.597,.465),l(.75,.366),l(.761,.044),l(1.03,-.048),l(1.705,-.279),l(.79,.021),l(.808,.434),l(-.168,.114),l(-1.246,.139),l(-1.38,.207),l(-1.174,.295),l(-2.098,.518),l(-1.316,.224),l(-1.19,.355),l(-.924,.286),l(-2.252,.005),l(.65,.906),l(-.449,.193),l(-2.297,.455),l(-.768,-.019),l(-1.587,-.037),l(-1.462,-.218),l(-2.386,-.164),l(-.66,.33),l(2.591,.695),l(-.662,.141),l(-.967,-.038),l(-1.297,.022),l(-1.068,.022),l(-2.58,-.214),l(-2.009,.063),l(-.134,.66),l(1.257,-.105),l(1.065,.018),l(2.312,.292),l(.557,.157),l(.12,.67),l(-.33,.197),l(-1.031,.12),l(-.515,.705),l(-1.073,.021),l(-.448,-.058),l(-.402,.176),l(.297,.253),l(.759,.25),l(-.328,.136),l(-1.615,.08),l(-.867,-.037),l(-1.71,-.171),l(-.422,.078),l(.41,.791),l(-.08,.231),l(-.649,.289),l(-.767,.155),l(-1.52,-.112),l(-2.039,-.111),l(-1.43,-.227),l(-1.008,.079),l(-1.219,.5),l(1.031,.112),l(.368,.057),l(2.154,.11),l(1.759,.13),l(1.534,.168),l(2.001,.034),l(.66,.34),l(.045,.359),l(-.907,.398),l(-2.685,.268),l(-.927,.115),l(-1.054,.227),l(-1.115,.077),l(-.467,-.28),l(-.797,-.638),l(-.56,.039),l(-.631,.001),l(-1.453,-.318),l(-.001,.17),l(.331,.508),l(-1.477,-.016),l(-1.5,-.129),l(-.875,-.319),l(-1.033,-.471),l(-.388,.058),l(.527,.717),l(-.24,.17),l(-.821,.133),l(-1.72,-.109),l(-2.276,-.033),l(-.972,-.073),l(-1.382,-.394),l(-.642,-.131),l(-.282,.453),l(-.619,.152),l(-1.843,-.316),l(.161,-.586),l(.219,-.228),l(1.525,-.117),l(.61,-.249),l(.961,-.173),l(1.179,.036),l(.499,-.172),l(-1.073,-.4),l(-1.043,-.651),l(.052,-.154),l(.479,-.117),l(1.316,.036),l(1.743,.093),l(.888,.21),l(1.108,.517),l(1.35,.323),l(1.085,.093),l(1.667,-.022),l(.829,-.136),l(.086,-.268),l(.514,-.304),l(-3.019,.001),l(-1.025,-.171),l(-.156,-.85),l(.211,-.154),l(-1.74,-.153),l(-1.963,-.152),l(-.274,0),l(-.631,.114),l(.204,-.758),l(1.159,-.551),l(1.104,-.16),l(1.837,-.003),l(1.164,.037),l(1.37,.076),l(2.023,.311),l(1.342,.115),l(.486,-.158),l(1.132,-.041),l(-3.399,-.802),l(-1.742,-.313),l(-3.555,-1.27),l(-.406,.242),l(-1.398,-.878),l(.025,-.258),l(.313,-.108),l(1.747,.104),l(1.905,-.004),l(2.019,.06),l(1.6,.382),l(2.535,.784),l(1.448,-.043),l(.833,.095),l(-1.387,-.555),l(-2.015,-.317),l(1.208,-.743),l(1.456,-.329),l(1.731,-.025),l(1.529,-.222),l(2.042,-.07),l(1.157,-.112),l(1.414,-.051),l(-1.778,-.479),l(-1.425,-.153),l(-2.501,.027),l(-1.243,.248),l(-1.305,.158),l(-1.425,.202),l(-1.447,.047),l(-.586,.067),l(-1.532,-.438),l(-.214,.111),l(-.543,.156),l(-2.16,-.018),l(-1.58,.365),l(.311,-.828),l(.98,-.292),l(.007,-.202),l(-.606,-.247),l(-1.375,-.156),l(-1.39,.003),l(-4.189,.505),l(-2.031,.672),l(-.408,-.11),l(-.569,-.251),l(.395,-.133),l(.678,-.023),l(-.117,-.316),l(-.698,-.398),l(-1.216,-.056),l(-.216,-.003),M(200.125,20.844),l(.899,-.096),l(.832,.196),l(.339,.5),l(.511,.495),l(.427,.063),l(1.141,.041),l(-.081,-.236),l(.056,-.411),l(.438,-.109),l(.718,.194),l(.718,.322),l(.374,.3),l(-.066,.171),l(.056,.826),l(.764,.442),l(.953,-.017),l(1.276,-.074),l(1.646,.504),l(-1.123,-.264),l(-1.528,.34),l(-1.599,.221),l(-.83,.377),l(-.287,.197),l(-.265,.315),l(-.448,.021),l(-1.493,-.41),l(-.656,.335),l(.465,.43),l(-.029,.235),l(-.412,.196),l(-.392,.04),l(-1.086,-.31),l(-.944,-.311),l(-.26,.645),l(-.117,.068),l(-.083,.049),l(-.888,.041),l(-1.74,-.094),l(-1.458,-.153),l(-.888,-.154),l(-.494,.021),l(-3.115,-1.31),l(-.191,-.276),l(1.971,-.241),l(3.32,.093),l(.889,.097),l(1.573,.1),l(-2.485,-.693),l(-3.019,-.213),l(-1.103,.122),l(-1.43,-.017),l(-.597,.18),l(-1.008,.022),l(-.606,-.198),l(-1.066,-.517),l(-1.425,-.479),l(-.341,-.355),l(1.971,.124),l(2.278,-.175),l(-1.255,-.249),l(-.756,-.351),l(.38,-.305),l(.729,-.132),l(.769,-.023),l(.921,.042),l(.156,-.219),l(-1.799,-.793),l(1.053,-.114),l(1.213,-.182),l(1.13,.087),l(.584,-.046),l(.145,-.18),l(-.514,-.475),l(1.362,.134),l(.941,.066),l(.83,.202),l(1.589,.869),l(.653,.264),l(.772,.24),l(.674,-.001),l(.36,-.039),M(179.067,27.216),l(-1.156,-.056),l(-.604,-.173),l(-.926,-.638),l(-.621,-.193),l(-3.102,-.091),l(-1.487,.081),l(-.622,.001),l(-1.444,-.056),l(-.767,-.154),l(-1.019,-.37),l(-.161,-.234),l(.335,-.138),l(.802,-.001),l(1.687,.232),l(.867,-.021),l(-.031,-.235),l(-.252,-.275),l(-1.344,-.49),l(-.579,-.098),l(-1.075,-.077),l(-1.392,-.196),l(.065,-.397),l(2.246,-.124),l(2.392,.155),l(.77,.376),l(.999,.453),l(1.979,.193),l(2.189,.114),l(1.178,.233),l(.604,.254),l(1.123,.721),l(.581,.446),l(.168,.426),l(-.481,.194),l(-.919,.137),M(185.907,26.758),l(-1.078,-.037),L(184,26.529),l(-1.029,-.484),l(-1.144,-.76),l(-.03,-.216),l(.239,-.099),l(2.296,-.044),l(1.816,.311),l(3.101,.542),l(-.047,.351),l(-.254,.331),l(-.436,.04),l(-1.563,.177),l(-1.043,.08),M(156.886,26.865),l(-1.573,.646),l(-.558,.27),l(-1.85,.042),l(-1.019,.079),l(-1.898,-.15),l(-.577,-.114),l(-.302,-.423),l(.334,-.291),l(1.365,-.177),l(.899,.056),l(2.351,-.102),l(.496,0),l(2.331,.163),M(132.902,31.305),l(-.53,-.186),l(-.95,-.466),l(-.424,-.112),l(-.33,.057),l(-.56,.207),l(-1.269,.059),l(-.786,-.279),l(-.283,-.319),l(.23,-.264),l(1.13,-.097),l(.503,-.133),l(.771,-.134),l(.977,-.399),l(.848,-.211),l(.726,-.172),l(.548,-.344),l(1.083,-.231),l(1.277,-.079),l(2.532,-.158),l(1.68,.016),l(.888,-.29),l(1.038,-.079),l(1.503,.438),l(-.756,.097),l(-.852,.231),l(-.22,.268),l(.12,.266),l(.469,.474),l(-.777,.001),l(-.912,.115),l(-.918,.662),l(-1,-.017),l(-.867,-.981),l(-.694,-.15),l(-.379,.02),l(-.229,.285),l(-.588,.342),l(-.63,.623),l(-.595,.151),l(-.284,.375),l(-.705,.356),l(-.787,.058),M(191.827,30.313),l(-1.266,-.054),l(-2.278,-.165),l(-.426,.058),l(-.332,-.094),l(-.896,-.489),l(-1.185,-.414),l(.192,-.229),l(2.433,-.042),l(1.542,.263),l(1.472,.054),l(.171,0),l(.89,.358),l(-.179,.246),l(.123,.32),l(-.263,.188),M(144.688,31.739),l(-2.222,-.395),l(-.325,-.674),l(.503,-.057),l(.595,-.17),l(.945,-.096),l(.953,-.133),l(1.279,-.059),l(.522,.187),l(.65,.374),l(.659,.186),l(1.55,-.209),l(.617,.149),l(1.624,.762),l(1.016,.351),l(.897,.036),l(.96,-.058),l(1.418,.09),l(.591,-.02),l(1.116,-.169),l(.092,-.297),l(-.557,-.559),l(-.941,-.391),l(-1.347,-.354),l(.96,-.322),l(.524,-.379),l(.569,-.152),l(1.097,-.116),l(.507,.17),l(.773,.678),l(-.017,.413),l(.518,.654),l(.565,.111),l(.9,.036),l(1.805,.406),l(-.334,-.465),l(.151,-.28),l(.409,-.076),l(1.495,.24),l(.932,.39),l(-.292,.409),l(.039,.5),l(-.358,.461),l(-.573,.277),l(-.755,.111),l(-.782,.001),l(-1.682,.095),l(-1.156,-.071),l(-1.757,-.18),l(-.622,-.017),l(-1.129,.277),l(-1.132,.202),l(-.76,.182),l(-.977,.254),l(-1.625,.292),l(-1.338,.2),L(149.23,34.5),l(-.748,-.07),l(-1.445,-.286),l(-.276,-.378),l(.648,-.128),l(1.219,-.038),l(.738,-.146),l(.852,-.075),l(1.166,-.057),l(.622,.017),l(1.09,-.149),l(.483,-.553),l(-2.768,-.087),l(-.925,-.054),l(-1.564,.28),l(-1.625,.168),l(-1.292,.04),l(-.795,.093),l(-1.681,-.347),l(-.479,.167),l(-.92,.075),l(-.979,-.127),l(-.854,-.33),l(.023,-.111),l(.863,-.427),l(1.098,-.058),l(2.047,-.022),l(.96,-.159),M(178.479,33.234),l(-.984,-.219),l(-.193,-.294),l(.764,-.389),l(.433,-.112),l(.088,-.167),l(-.447,-.333),l(-1.161,-.054),l(-2.13,.227),l(-.939,.076),l(-.331,.019),l(-.854,-.276),l(.039,-.335),l(.739,-.02),l(.542,-.244),l(.587,-.057),l(-.466,-.598),l(.176,-.245),l(.132,-.226),l(.49,.018),l(.859,.224),l(1.942,.746),l(.426,.186),l(.46,-.094),l(-.101,-.243),l(-.959,-.486),l(-.371,-.131),l(-.407,-.357),l(.436,-.095),l(.956,-.059),l(.713,.131),l(1.033,.262),l(.572,.168),l(.27,.018),l(.162,-.452),l(.478,-.133),l(.73,.112),l(.717,.168),l(.327,.168),l(.367,.75),l(-.034,.616),l(-.247,.242),l(-.831,.335),l(-.017,.352),l(.35,.625),l(-.361,.147),l(-1.648,-.089),l(-.862,.112),l(-1.446,.003),M(200.125,30.572),l(-.895,.045),l(-.853,.17),l(-.37,.467),l(1.133,.054),l(.984,-.038),l(.046,-.001),l(.847,.11),l(.463,.129),l(.498,.463),l(.727,.424),l(.621,.091),l(.213,-.074),l(.043,-.314),l(.286,-.056),l(1.075,-.002),l(.883,-.187),l(.766,.11),l(.835,.239),l(.665,.257),l(.976,.053),l(.775,-.463),l(1.393,-.281),l(1.704,-.114),l(1.951,-.246),l(1.533,.053),l(2.59,.014),l(.381,.037),l(.79,.314),l(.911,.239),l(1.418,.146),l(.653,.128),l(.21,.037),l(.361,.166),l(.181,.257),l(-.4,.148),l(-1.833,.407),l(-.135,.255),l(.469,.666),l(-2.486,.076),l(-.592,.02),l(-.651,.091),l(-.768,-.053),l(-.846,-.16),l(-.405,-.125),l(-.306,-.667),l(-.833,-.218),l(-.366,.129),l(.072,.723),l(-.536,.127),l(-.747,-.053),l(-.91,.109),l(-.728,-.017),l(-.495,.001),l(-1.342,-.213),l(-.593,-.197),l(-.495,-.017),l(-.209,.433),l(-1.801,.111),l(-.831,.074),l(-1.453,-.069),l(-.404,-.251),l(-.144,-.686),l(-1.237,.129),l(-.389,.181),l(-.326,.325),l(-.955,.2),l(-1.011,-.034),l(-.112,-.027),l(-.704,-.169),l(-1.186,-.575),l(-.675,.489),l(-1.131,-.07),l(-.666,-.688),l(-.442,-.717),l(.587,-.481),l(.019,-.371),l(-.292,-.316),l(-1.249,-.651),l(-.617,-.299),l(-.047,-.338),l(.636,-.133),l(1.226,-.078),l(2.472,-.023),l(.763,.093),l(1.118,.261),l(.188,.04),l(.872,.184),l(-.613,.189),l(-.259,.013),M(128.19,41.985),l(-.926,-.016),l(-1.059,-.102),l(-.362,-.466),l(-.549,-.467),l(-.432,-.259),l(-1.123,-.363),l(-1.36,-.067),l(-.951,-.138),l(-.469,-.19),l(-.168,-.174),l(.537,-.106),l(.589,-.298),l(.481,-.211),l(.08,-.386),l(-.437,-.809),l(.552,-.001),l(.468,-.177),l(.307,-.372),l(1.104,-.533),l(.526,-.588),l(-.121,-.32),l(-.271,-.16),l(-1.229,-.677),l(-.375,-.448),l(.869,-.001),l(.823,-.056),l(1.455,.051),l(.97,.016),l(1.515,-.092),l(1.284,-.146),l(1.242,-.074),l(.495,.125),l(3.242,.801),l(.918,.088),l(.708,-.055),l(1.316,-.127),l(1.223,.016),l(.771,.07),l(1.35,.373),l(2.389,.815),l(-.242,.143),l(-.432,.036),l(-.26,.072),l(-1.609,.322),l(-1.073,.144),l(-1.829,.428),l(-1.069,.319),l(-1.604,.725),l(-1.025,.563),l(-.549,.089),l(-.974,.124),l(.066,.924),l(-.271,.504),l(-.662,.278),l(-1.215,.124),l(-1.213,-.067),l(-.521,.485),l(-.898,.312),M(190.483,39.666),l(-1.146,-.208),l(-.146,-.524),l(-.941,-.806),l(-.207,-.582),l(.058,-.389),l(.27,-.657),l(.377,-.321),l(1.256,.033),l(-.089,-.16),l(-.416,-.266),l(-.185,-.286),l(.211,-.09),l(.234,-.072),l(2.154,-.058),l(1.215,.087),l(1.464,.248),l(1.282,.051),l(1.316,-.146),l(1.051,.016),l(.694,.105),l(.639,.213),l(-.007,.089),l(-.224,.179),l(-.824,.428),l(-.874,.746),l(-1.513,.92),l(-1.386,.073),l(-2.379,-.154),l(-1.269,.055),l(1.392,.717),l(-.188,.315),l(-.855,.369),l(-.964,.072),M(181.204,41.523),l(-.491,-.085),l(-1.101,-.552),l(-.952,-.641),l(-1.014,-.468),l(-.978,-.225),l(-1.438,-.12),l(-.55,-.174),l(-2.255,-1.066),l(.866,-.654),l(.653,.14),l(1.032,.474),l(1.063,.227),l(.46,.052),l(.615,-.283),l(.908,-.619),l(.415,-.036),l(.018,-.212),l(-1.062,-.565),l(-1.068,-.424),l(-.177,-.231),l(.132,-.107),l(1.683,.086),l(.711,-.215),l(.42,0),l(.996,.39),l(.56,.035),l(.58,-.055),l(.435,-.25),l(1.232,-.127),l(1.354,.069),l(.912,.23),l(-.324,.268),l(-.58,.125),l(-.323,.338),l(-1.55,.375),l(-.392,.16),l(-.069,.194),l(.253,.247),l(.506,.105),l(.692,-.089),l(1.08,.174),l(.868,.245),l(.391,.017),l(.564,.262),l(.186,.438),l(-.681,.352),l(-.156,.35),l(-.271,.68),l(-.457,.366),l(-.508,.14),l(-.658,.019),l(-.582,-.103),l(-.773,-.346),l(-.653,-.103),l(.013,.208),l(1.054,.553),l(-.817,.399),l(-.77,.036),M(243.524,60.394),l(-.234,-.208),l(-1.199,-.235),l(-.673,-.331),l(-.154,-.269),l(.346,-.064),l(.616,-.461),l(-1.378,-.521),l(-1.132,-.125),l(-.76,-.349),l(-.929,-.731),l(-.035,-.511),l(-1.115,-.062),l(-1.311,-.366),l(-.675,-.031),l(.284,.767),l(-.155,.096),l(-.409,-.015),l(-1.704,-.332),l(-.309,.033),l(-.325,.304),l(-.441,.288),l(-1.312,.082),l(-1.349,-.173),l(-1.343,-.189),l(-.813,-.254),l(-.052,-.319),l(.196,-.4),l(.382,-.354),l(1.066,-.163),l(.192,-.178),l(-.128,-.516),l(.206,-.033),l(1.357,.11),l(1.408,.175),l(.517,.144),l(.962,.626),l(.051,-.386),l(-.154,-.193),l(.077,-.194),l(.585,-.033),l(.977,-.099),l(.652,-.163),l(.649,-.114),l(.515,.063),l(.785,.031),l(.166,-.275),l(-1.138,-.825),l(-.773,-.356),l(-.119,-.228),l(.167,-.163),l(.586,-.066),l(.72,-.246),l(1.409,-.591),l(.361,-.541),l(.771,-.46),l(.493,-.379),l(-.109,-.593),l(-.899,-.841),l(-.407,-.496),l(-.541,-.364),l(-.414,.001),l(-1.258,-.33),l(-1.041,-.481),l(-.244,-.467),l(-.527,-.384),l(-.442,.202),l(-.551,.202),l(-.825,-.015),l(-.293,.117),l(-.62,.018),l(-1.255,.169),l(-.214,-.667),l(1.032,-.052),l(1.23,-.103),l(.163,-.269),l(-1.604,-.618),l(-1.552,-.67),l(-.879,-.015),l(-.567,-.185),l(-.169,-.542),l(-.677,-.339),l(-.45,-.05),l(-.918,-.306),l(-.687,-.341),l(-.385,-.119),l(-.611,.155),l(-.81,-.187),l(-1.177,-.238),l(-.489,-.085),l(-.379,.138),l(.529,.307),l(.453,.05),l(2.838,.712),l(.438,.271),l(.069,.306),l(-.505,.221),l(-.669,.069),l(-.541,-.033),l(-.757,-.049),l(-.818,-.252),l(-1.153,-.27),l(-.667,-.066),l(-.323,.17),l(.044,.204),l(.426,.236),l(.259,.438),l(-1.703,-.553),l(-.47,-.05),l(-.396,.119),l(-.63,.153),l(-.767,-.218),l(-.693,-.117),l(-.859,.12),l(-1.474,-.184),l(-1.995,-.167),l(-1.321,.037),l(-1.146,-.032),l(-.862,-.186),l(-.003,-.597),l(-.363,-.153),l(-.904,-.049),l(-.396,.342),l(-.623,.086),l(-1.214,-.049),l(-1.076,-.168),l(-1.303,-.477),l(-.415,-.376),l(.123,-.275),l(.868,-.07),l(1.131,.067),l(1.212,.101),l(.879,-.019),l(.312,-.19),l(-.934,-.463),l(-.8,-.275),l(-.905,-.102),l(-1.106,-.119),l(-.752,.036),l(-.539,-.017),l(-1.249,-.223),l(.114,-.416),l(.292,-.557),l(.34,-.14),l(.646,-.054),l(.081,-.227),l(-1.082,-.4),l(-.044,-.175),l(.449,-.79),l(1.197,-.919),l(.565,-.284),l(.918,-.321),l(.74,-.374),l(.423,-.037),l(.37,-.178),l(.698,-.001),l(.481,-.125),l(.71,-.09),l(1.436,-.109),l(1.348,.033),l(.857,.194),l(-.92,.393),l(-.815,.48),l(-1.394,.639),l(-.43,.529),l(.169,.369),l(1.256,.541),l(-.444,.298),l(-.076,.402),l(.257,.313),l(.862,.554),l(1.559,.621),l(-.096,.121),l(-1.272,.331),l(-.072,.31),l(.959,.033),l(1.504,.101),l(.654,-.639),l(-.103,-.415),l(-.343,-.277),l(-.724,-.103),l(-.422,-.138),l(-.884,-.538),l(.101,-.157),l(.506,-.245),l(.473,-.193),l(1.001,.12),l(.837,-.071),l(-1.204,-.47),l(-.703,-.034),l(-.793,-.279),l(-.056,-.193),l(.053,-.545),l(.886,-.319),l(1.207,.086),l(1.509,-.056),l(-.939,-.281),l(-1.233,-.351),l(.793,-.303),l(1.288,-.198),l(1.044,-.126),l(1.688,-.323),l(1.114,.016),l(.642,.052),l(.833,.141),l(.782,.478),l(1.536,.97),l(.058,.141),l(-.583,.687),l(-.709,.632),l(.038,.733),l(.364,.086),l(.65,.033),l(1.088,-.315),l(.284,-.455),l(.595,-.088),l(.791,.034),l(.454,.174),l(-.006,.262),l(.16,.47),l(.875,.189),l(.196,-.122),l(-.204,-.854),l(.218,-.123),l(.456,-.474),l(1.038,-.265),l(.98,-.054),l(.748,.034),l(.98,.174),l(1.172,.138),l(1.151,-.09),l(.688,.139),l(.327,.262),l(.621,.331),l(.574,.191),L(235.438,40),l(0,.191),l(-.531,.088),l(-.484,.279),l(-.818,.262),l(-.148,.225),l(.45,.259),l(.427,.068),l(.897,-.417),l(.652,-.174),l(.502,.051),l(.476,.242),l(.365,.466),l(.516,.413),l(.342,-.242),l(1.304,-.798),l(1.935,.256),l(.915,.361),l(-.051,.069),l(-.638,.346),l(-.708,.517),l(1.167,-.054),l(.455,-.173),l(1.078,-.105),l(.033,.704),l(.797,.324),l(.523,-.069),l(.831,-.207),l(1.316,-.088),l(.816,.221),l(.566,.273),l(-.162,.154),l(-.461,.223),l(-1.87,.43),l(-.238,.272),l(.523,.253),l(.456,-.068),l(.747,-.171),l(1.235,-.122),l(.406,-.29),l(.361,-.103),l(.479,.067),l(.51,.187),l(.544,.339),l(.636,.522),l(-1.019,.002),l(-1.2,.053),l(-.424,.135),l(.059,.269),l(.372,.134),l(1.333,.065),l(.938,.183),l(.543,.217),l(.233,.301),l(-.37,.034),l(-.748,.001),l(-1.011,-.082),l(-.875,-.216),l(-.824,-.065),l(-.316,.185),l(1.23,.583),l(-.216,.201),l(-1.552,.12),l(.245,.283),l(.437,.166),l(.551,.032),l(1.331,.364),l(1.312,.347),l(.247,.182),l(.039,.282),l(.351,.38),l(.75,-.217),l(.536,.049),l(1.413,.295),l(.298,-.067),l(.649,-.15),l(.61,.032),l(.752,.379),l(.862,.477),l(.376,.346),l(-.685,.1),l(-.801,.117),l(-.027,.444),l(.795,-.001),l(1.405,-.052),l(.51,-.132),l(.895,.048),l(-.386,.559),l(.918,.179),l(.514,-.001),l(.943,-.379),l(.685,.343),l(1.089,.407),l(.194,.098),l(-.275,.229),l(-.254,.099),l(-.103,.326),l(-.819,.05),l(-.718,-.21),l(-.247,-.048),l(-.794,.213),l(.968,.454),l(.279,.162),l(.057,.276),l(-1.057,.197),l(-.356,.228),l(-.312,.292),l(-.372,-.113),l(-.819,-.583),l(-.29,1.103),l(.354,.903),l(-.419,.065),l(-.677,-.257),l(-.751,-.176),l(-.205,-.177),l(-.018,-.243),l(-.315,-.274),l(-.93,.276),l(-.743,-.613),l(.051,-.292),l(.27,-.374),l(-.304,-.129),l(-.224,-.016),l(-.992,-.08),l(-.718,-.292),l(-1.17,-.617),l(-.769,-.292),l(-.762,-.048),l(-.452,.23),l(-.645,.083),L(250,52.592),l(.281,.179),l(1.05,.682),l(-.321,.114),l(-.686,.05),l(-.359,-.259),L(249.277,53),l(-.646,-.21),l(.275,.488),l(.859,.972),l(.604,.015),l(.587,.08),l(.5,.581),l(.612,.805),l(.513,.432),l(.615,-.321),l(.285,.047),l(.592,.399),l(.585,.271),l(1.38,.396),l(-.634,.113),l(-.213,.208),l(.254,.19),l(.568,.286),l(.962,.444),l(.324,.237),l(.242,.682),l(-.112,.428),l(-1.302,-1.155),l(-.554,-.237),l(-.027,.238),l(.118,.27),l(1.055,1.281),l(-.01,.3),l(-.926,-.125),l(.053,.205),l(.432,.409),l(.378,.519),l(-.563,-.172),l(-.615,-.313),l(-.889,-.693),l(-.145,-.031),l(-.719,.064),l(-.91,-.188),l(-1.44,-.662),l(-.319,-.285),l(-1.062,-.665),l(.187,.777),l(-1.22,-.473),l(-.567,-.158),l(-.872,-.03),l(.095,.222),l(.799,.696),l(.853,.426),l(1.842,.645),l(1.296,.644),l(.774,.549),l(.442,.486),l(.429,.689),l(-1.833,-.341),l(-1.524,-.421),l(-1.251,-.28),l(-1.444,-.107),l(-1.092,-.25),l(-.898,-.644),l(-1.146,-.14),l(-.638,-.204),l(-.635,-.141),l(-.058,.145),M(146.194,38.698),l(.818,-.037),l(.78,-.125),l(1.138,-.548),l(.895,-.019),l(1.723,.243),l(.939,.262),l(-.188,.877),l(.515,-.071),l(.66,-.019),l(.792,-.229),l(.599,-.141),l(.758,.016),l(.334,-.071),l(-.989,-.965),l(.156,-.036),l(1.38,.138),l(1.208,.245),l(.675,.245),l(.259,.245),l(.194,.508),l(.965,1.063),l(.638,.346),l(1.045,-.315),l(.14,-.261),l(-1.243,-1.361),l(-.439,-1.321),l(.228,-.354),l(1.91,.262),l(1.775,.156),l(2.031,.719),l(.36,.175),l(.3,.316),l(.16,.701),l(.511,.645),l(.352,.26),l(.856,.606),l(.048,.19),l(-.178,.243),l(-.333,.605),l(.179,.31),l(.224,.12),l(1.4,.649),l(.509,.171),l(1.151,.254),l(1.513,.1),l(2.056,.576),l(1.012,.39),l(.364,.793),l(-.168,.101),l(-1.071,-.082),l(-.811,-.234),l(-.945,-.234),l(-.551,.169),l(-.665,.204),l(-1.021,.036),l(-.256,.118),l(.208,.689),l(1.087,-.069),l(.614,-.152),l(.676,-.119),l(.876,.536),l(-.01,.235),l(-.526,.151),l(-.517,.252),l(-.583,.102),l(-1.417,.12),l(-1.049,-.015),l(-1.194,-.082),l(-1.594,-.248),l(-2.278,-.499),l(-.553,-.217),l(-.436,-.335),l(-.482,-.033),l(-.581,.102),l(-.402,.37),l(-1.114,.505),l(-1.055,.019),l(-1.411,.103),l(-1.253,.42),l(-2.753,.356),l(-1.42,.019),l(-1.205,.086),l(-1.984,-.063),l(-.483,.101),l(-.916,-.015),l(-1,-.282),l(-.061,-.468),l(.198,-.101),l(.002,-.302),l(-.395,-.2),l(-.462,-.1),l(-3.146,-.112),l(-1.258,-.115),l(-.864,-.167),l(-.801,-.2),l(-.753,-.504),l(-1.274,-.554),l(.303,-.069),l(.531,-.222),l(1.572,-.054),l(.603,-.188),l(.558,.016),l(.91,-.019),l(.904,-.087),l(1.716,.031),l(.935,-.002),l(2.14,.047),l(1.09,-.002),l(1.711,-.038),l(.415,-.154),l(-.681,-.221),l(-2.312,-.492),l(-1.942,-.202),l(-4.059,-.061),l(-1.569,-.014),l(-1.694,.055),l(-.955,.053),l(-.604,.001),l(-1.651,-.529),l(.011,-.207),l(.28,-.069),l(.823,-.053),l(1.315,-.209),l(.996,.032),l(1.78,-.141),l(.931,-.105),l(.5,-.277),l(-.392,-.346),l(-2.023,.073),l(-1.578,.159),l(-.393,-.051),l(-.554,-.189),l(-.677,-.346),l(-.65,-.19),l(-.692,.054),l(-.709,-.242),l(-.039,-.279),l(1.304,-.981),l(2.62,-.848),l(.909,-.143),l(.373,-.177),l(1.297,-.267),l(1.324,-.162),l(.701,-.267),l(1.113,-.091),l(1.026,.246),l(-.07,.212),l(-.548,.354),l(-.021,.81),M(251.273,99.526),l(-.188,.153),l(-.16,-.291),l(.192,-.077),l(-.02,-.256),l(.143,-.069),l(-.042,-.154),l(-.224,0),l(-.606,-.231),l(.077,-.229),l(-.31,-2.819),l(-.174,-.274),l(-.488,-.288),l(-.771,-.025),l(-.41,.176),l(-.381,-.085),l(-.505,-.36),l(-.273,-.085),l(-.632,.526),l(-.514,.626),l(-1.139,2.22),l(-1.139,1.45),l(-1.161,-.124),l(-.402,.06),l(-.363,.435),l(-.174,.375),l(-1.093,-.095),l(-1.855,-.004),l(-2.508,-.029),l(-1.76,.009),l(-.968,.523),l(-.534,.305),l(-1.754,.814),l(-.545,.164),l(-.146,.434),l(-.163,.512),l(-.44,.275),l(-1.156,.197),l(-1.305,-.138),l(-1.123,-.01),l(-.93,.091),l(-.47,.203),l(-.162,.375),l(.018,.319),l(.16,.471),l(.047,.362),l(-.875,.427),l(-1.464,.452),l(-.944,.163),l(-.919,.062),l(-.88,.262),l(-.939,.478),l(-.925,.506),l(-.524,.117),l(-.573,-.068),l(-.497,-.169),l(-.371,-.427),l(-.012,-.33),l(.044,-.218),l(.707,-.525),l(.414,-.294),l(.264,-.433),l(.294,-.544),l(.377,-.576),l(.028,-.746),l(-.054,-.545),l(-.876,-3.16),l(-2.529,-1.05),l(-.26,-.33),l(.11,-.318),l(-.307,-.235),l(-.916,-.181),l(-.184,-.294),l(-.178,-.135),l(-.628,.024),l(-.46,-.465),l(-.101,-.429),l(-2.15,-1.061),l(-3.975,-1.576),l(-.977,-.386),l(-.797,-.227),l(-.805,.189),l(-1.469,.592),l(-.707,-.074),l(-.542,.049),l(-.196,-.144),l(-.156,-.115),l(-.474,-.041),l(-.855,.083),l(-.197,-.116),l(-.028,-.282),l(-.373,.075),l(-.412,.191),l(-.219,.06),l(-.573,.141),l(-.506,-.098),l(-.064,-.185),l(-.469,-.086),l(-.241,-.271),l(-.502,-.013),l(-.16,.247),l(-.338,-.48),l(-.271,.012),l(-.02,-.185),l(-1.425,-.208),l(-.518,.076),l(-.833,-.451),l(-.468,-.46),l(-.279,-.371),l(-.896,-.748),l(-.501,.036),l(.131,.347),l(.387,.588),l(-.68,-.003),l(-2.687,.029),l(-2.798,-.029),l(-1.348,.007),l(-2.105,-.003),l(-2.915,.016),l(-2.781,-.029),l(-2.131,.012),l(-2.935,-.014),l(-.601,.003),l(-4.84,-.018),l(-3.617,.004),l(-.875,.005),l(-3.821,-.023),l(-1.089,.035),l(-4.13,-.021),l(-.74,-.011),l(-5.117,.028),l(-1.687,-.006),l(-2.87,.001),l(-3.938,-.008),l(-4.588,.025),l(-1.335,-.022),l(-2.579,-.001),l(-.194,-.013),l(-.187,-.151),l(-.509,-.305),l(-.071,-.437),l(.074,-.346),l(-.708,.25),l(-.373,-.029),l(-.331,-.305),l(-.162,-.496),l(-.125,-.189),l(-.385,.088),l(-.23,.205),l(-.483,.059),l(-.721,-.495),l(-.119,-.425),l(-.201,-.821),l(-1.051,.104),l(-1.01,-.277),l(-.487,-.087),l(-.173,-.087),l(-.143,-.396),l(-.438,-.352),l(-.591,.222),l(-1.236,.046),l(-.461,-.117),l(-.383,-.249),l(-.106,-.25),l(.257,-.648),l(.458,-.222),l(-.227,-.294),l(-1.24,-.086),l(.617,-.518),l(.398,-.281),l(.547,-.149),l(.605,-.508),l(-.874,.006),l(-.621,.149),l(-.362,-.043),L(116,83.422),l(-.039,-.978),l(-.789,.002),l(-1.015,-1.066),l(.132,-.238),l(.034,-.53),l(-.547,.056),l(-.83,.492),l(-1.266,-.934),l(-.384,-.521),l(-.204,-.402),l(-.068,-.432),l(.419,-.404),l(.161,-.254),l(.436,-.3),l(-.358,-.689),l(-.393,-.777),l(.163,-.788),l(-.402,-.255),l(-2.025,-.763),l(-.98,-.314),l(-.189,-.029),l(-.512,-.393),l(-1.67,-1.882),l(-1.769,-1.768),l(-.814,-.58),l(-2.048,-1.175),l(-.35,-.322),l(-.371,-.492),l(-.316,-.199),l(-.832,-.073),l(-.495,.126),l(-.731,.498),l(-1.225,.67),l(-.848,.205),l(-.238,.325),l(-.945,-.673),l(-2.162,-1.318),l(-.348,-.292),l(-.173,-.387),l(-.332,-.388),l(-.739,-.059),l(-2.424,.122),l(-.84,-.074),l(-.196,-.279),l(-.089,-1.046),l(-.026,-2.167),l(.043,-4.334),l(.026,-2.183),l(-.129,-2.796),l(-.052,-2.335),l(-.039,-2.259),l(.003,-2.855),l(-.102,-.483),l(.71,.024),l(.9,-.086),l(.964,.116),l(2.012,.451),l(1.601,.518),l(1.214,.266),l(1.04,.115),l(.731,.032),l(1.619,.164),l(.888,.232),l(.429,.149),l(.254,-.034),l(-.452,-.601),l(-.357,-.2),l(-.345,-.15),l(-.064,-.419),l(1.344,-.423),l(.745,.066),l(.578,-.068),l(.15,-.102),l(1.736,.148),l(.771,-.001),l(1.125,-.373),l(.309,-.186),l(.442,0),l(.656,-.221),l(.759,-.069),l(.866,-.086),l(.734,-.086),l(.469,-.239),l(.392,-.188),l(.771,-.104),l(1.045,-.002),l(.872,.123),l(-.445,.404),l(-.352,.119),l(-1.101,.137),l(-1.092,.373),l(-1.244,.171),l(-1.22,.271),l(-.699,.522),l(-1.767,.255),l(-.681,.487),l(.846,.266),l(1.441,.748),l(-.219,-.55),l(.168,-.351),l(1.196,-.253),l(.39,-.235),l(.726,-.421),l(1.727,-.053),l(.96,-.372),l(1.158,-.389),l(2.066,-.173),l(.643,-.338),l(.921,-.272),l(.821,-.189),l(.476,-.239),l(-.178,-.272),l(-.702,-.392),l(-.655,-.444),l(.899,.101),l(.764,.272),l(.701,.306),l(.412,.324),l(.376,.476),l(.449,.523),l(.393,.235),l(1.246,.486),l(.186,.067),l(1.154,.216),l(.394,-.018),l(.199,-.151),l(-.511,-.639),l(.07,-.27),l(.548,-.035),l(.334,-.136),l(.627,-.103),l(.383,.354),l(.059,.421),l(-.205,.287),l(.833,.133),l(.938,-.069),l(1.136,-.457),l(.536,-.49),l(.479,-.069),l(1.131,.015),l(1.536,.267),l(1.745,.435),l(1.396,.334),l(2.095,.349),l(1.024,.216),l(.619,.066),l(1.572,.282),l(1.121,.065),l(1.144,.148),l(1.096,.032),l(1.4,-.086),l(.899,.099),l(1.008,.282),l(.982,.349),l(.434,.249),l(.191,.333),l(-.524,.134),l(-.935,-.032),l(-.566,.051),l(-.849,.135),l(-.354,.714),l(3.323,.358),l(1.726,.079),l(1.749,.014),l(.868,-.068),l(.738,-.051),l(.94,-.167),l(.895,-.118),l(.938,-.101),l(.886,.032),l(1.432,.477),l(1.452,.179),l(.42,.115),l(1.225,.443),l(-.013,.312),l(-.504,.083),l(-.35,.247),l(.305,.147),l(1.823,.979),l(-.162,-.392),l(-.024,-.312),l(.456,-.05),l(.617,-.132),l(-.062,-.181),l(-.972,-.656),l(-.128,-.198),l(-.145,-.445),l(.121,-.745),l(.35,-.034),l(1.944,-.136),l(.928,-.151),l(.207,-.299),l(.459,-.217),l(.613,-.035),l(1.098,.281),l(1.528,.279),l(.968,.064),l(.969,-.102),l(.612,.414),l(.248,.082),l(.962,.213),l(1.211,.13),l(.678,.081),l(1.146,-.002),l(.879,-.2),l(1.755,-.02),l(1.876,.029),l(1.07,-.052),l(1.18,-.267),l(.959,.478),l(.95,.296),l(.522,-.018),l(.243,-.314),l(-.017,-.513),l(-.666,-.231),l(-.732,-.131),l(-1.377,-.064),l(.089,-.449),l(1.193,-.085),l(.575,.065),l(.804,.214),l(.871,.198),l(.858,.048),l(.498,.198),l(.088,.183),l(-.095,.132),l(-.287,.86),l(.179,.51),l(.304,.164),l(.177,.065),l(.792,.097),l(.951,.311),l(-.071,-.559),l(-.466,-.989),l(.137,-.48),l(.258,-.266),l(.712,.015),l(.811,-.035),l(1.229,-.85),l(.492,-.051),l(.479,-.001),l(.517,-.151),l(.033,-.133),l(-.15,-.367),l(-.375,-.35),l(-.307,.001),l(-.81,.185),l(-.988,-.082),l(.535,-.52),l(.806,-.069),l(.435,-.168),l(.572,-.001),l(.739,.4),l(.464,.167),l(.065,-.268),l(-.081,-.956),l(-.744,.069),l(-.897,-.032),l(-.68,-.116),l(-.859,-.318),l(-.725,.085),l(-1.245,-.183),l(-.861,-.234),l(-.956,-.218),l(-.657,-.338),l(-.092,-.136),l(-.022,-.324),l(.33,-.137),l(.842,-.463),l(-.486,-.221),l(-1.188,-.375),l(.09,-.207),l(.58,-.604),l(.593,-.294),l(.387,-.035),l(1.032,.257),l(.139,-.035),l(.173,-.346),l(-.709,-.362),l(-.201,-.277),l(.23,-.035),l(.551,-.331),l(.367,-.035),l(1.841,-.021),l(.559,.086),l(.728,.189),l(1.26,.449),l(.432,.328),l(.195,.38),l(-.246,.603),l(1.261,.53),l(.809,.495),l(1.134,.493),l(-.377,.341),l(-.985,.036),l(-.474,.273),l(-.416,.557),l(.471,.067),l(1.071,.233),l(.805,.049),l(.387,-.136),l(.597,-.001),l(1.477,.351),l(-.335,.353),l(-.563,.219),l(.092,.151),l(.796,.467),l(.358,.601),l(.025,.833),l(.303,-.063),l(.021,-.004),l(.411,-.067),l(.608,-.367),l(.655,-1.137),l(.668,-.42),l(.523,.016),l(.731,.284),l(1.064,.55),l(.473,.383),l(.209,.45),l(-.159,.433),l(-.336,.034),l(-.796,-.098),l(-.202,.299),l(-.043,.415),l(.35,.396),l(1.146,.659),l(.61,.493),l(.463,.279),l(.595,-.166),l(.896,-.167),l(.369,-.132),l(.208,-.66),l(.764,-.398),l(.599,-.416),l(.249,-.664),l(.363,-.75),l(.237,-.184),l(1.394,.081),l(.329,-.067),l(.134,-.518),l(-.985,-.333),l(-.918,-.35),l(.088,-.891),l(.595,-.271),l(.787,.032),l(.42,-.068),l(.571,.016),l(3.459,.616),l(1.325,.669),l(.506,-.001),l(.553,-.068),l(.454,.201),l(.244,1.036),l(-.474,.268),l(-.431,.101),l(-.243,-.05),l(-.718,-.532),l(-.263,0),l(-.799,.269),l(.123,.316),l(.309,.515),l(.699,.729),l(.855,.528),l(1.108,.576),l(.024,.313),l(-.478,.642),l(-.439,.181),l(-1.407,.772),l(-.674,.083),l(-1.123,.509),l(-.763,-.276),l(-1.654,-.962),l(-.586,-.262),l(-.497,-.048),l(-.684,.281),l(1.364,.521),l(1.483,.896),l(-.708,.067),l(-.691,-.081),l(-1.288,.084),l(-.375,-.129),l(-.596,-.62),l(-1.147,-.014),l(-1.857,.118),l(-.253,.229),l(.614,.244),l(1.311,.421),l(-.159,.195),l(-.611,.327),l(-2.045,1.106),l(-.657,.179),l(-.527,.001),l(-.859,-.241),l(-.816,-.484),l(-.225,-.081),l(-1.189,-.225),l(-.736,-.259),l(-.598,-.112),l(-.947,.014),l(-.289,.004),l(-1.214,.174),l(1.503,.278),l(1.136,.21),l(1.751,.774),l(1.629,.433),l(1.233,.126),l(1.02,.031),l(-.618,1.091),l(-1.237,.705),l(-.856,.432),l(-.728,.161),l(-.829,.049),l(-.928,-.126),l(-1.062,-.38),l(-.048,.351),l(-.025,.287),l(.321,.572),l(-.02,.159),l(-.741,.031),l(-.058,.002),l(-1.365,-.108),l(-1.649,-.41),l(-.884,-.078),l(-2.962,-.322),l(2.146,.864),l(1.576,.156),l(1.367,.267),l(.562,.205),l(.33,.268),l(-.011,.19),l(-.642,.333),l(-1.106,.207),l(-1.429,-.076),l(-.511,-.062),l(-.367,.269),l(1.254,.423),l(-.469,.426),l(-1.06,.316),l(-1.454,.662),l(-.421,.252),l(.218,.704),l(-.313,.235),l(-.909,.205),l(-.31,.282),l(-.529,.64),l(-.276,.296),l(-.241,.669),l(-.274,.543),l(-.323,.666),l(.056,.416),l(-.161,.554),l(.123,.875),l(.136,.536),l(.598,.366),l(.25,.015),l(.257,.091),l(.664,.014),l(1.164,-.094),l(.276,.045),l(.367,.29),l(.413,.763),l(.813,1.157),l(.22,.668),l(-.132,.91),l(.673,.014),l(1.874,-.428),l(1.261,-.033),l(.723,.074),l(.535,.157),l(1.062,.311),l(2.129,.435),l(1.896,.903),l(.993,.933),l(3.5,.67),l(.644,.225),l(.982,.403),l(.986,.253),l(.553,.104),l(.702,-.091),l(.453,.044),l(.828,-.077),l(1.245,.163),l(1.407,.207),l(.401,.194),l(-.297,.702),l(-.142,.85),l(.154,.283),l(.307,.342),l(.07,.416),l(-.115,1.025),l(-.309,.593),l(.022,.208),l(.604,.266),l(.481,.339),l(.264,.354),l(.046,.488),l(-.076,.354),l(.97,.116),l(.963,.47),l(.676,.588),l(.392,.588),l(.078,.162),l(.64,.014),l(.726,.41),l(.907,.601),l(-.349,-.66),l(-.22,-.279),l(.134,-.338),l(.573,-.414),l(.365,.176),l(.381,.456),l(.262,.353),l(.165,-.354),l(.107,-.545),l(-.215,-.456),l(.541,-.532),l(.139,-.546),l(-.183,-.517),l(-.337,-.458),l(-.261,-.754),l(-.004,-.548),l(-.205,-.593),l(-.218,-.43),l(.615,-.016),l(-.097,-.476),l(-.296,-.252),l(-.657,-.163),l(-.375,-.282),l(-.326,-.923),l(1.252,-.271),l(.872,-.241),l(.625,-.271),l(1.758,-.949),l(.629,-.302),l(1.043,-.935),l(.434,-.544),l(.237,-.665),l(.054,-.529),l(-.257,-1.045),l(-.246,-.531),l(-.239,-.319),l(-.938,-.729),l(-.467,-.274),l(-1.105,-.532),l(-.363,-.122),l(-.453,-.274),l(-.151,-.046),l(-.293,-.351),l(.08,-.107),l(.868,-.522),l(.553,-.875),l(.293,-.416),l(.25,-.092),l(.447,-.017),l(.295,-.277),l(-.106,-.523),l(-.18,-.355),l(-.316,-.402),l(-.048,-.202),l(.258,-.357),l(.005,-.264),l(-1.751,-.105),l(1.084,-.92),l(.503,-.704),l(.007,-.125),l(-.316,-.203),l(-.609,-.265),l(-.244,-.266),l(-.043,-.533),l(.305,-.425),l(.554,-.315),l(.57,-.19),l(.827,.062),l(1.781,.374),l(1.097,.234),l(.753,.077),l(1.44,.013),l(1.08,-.144),l(.86,-.222),l(.21,-.047),l(.179,-.063),l(.589,.078),l(.991,.407),l(.254,.125),l(.754,.454),l(.918,.375),l(.796,.437),l(-.294,.391),l(.406,.233),l(1.698,.496),l(1.958,.354),l(.725,-.033),l(.368,-.203),l(.339,.295),l(-.013,.404),l(-.577,.343),l(-.123,.45),l(.438,1.327),l(.136,.722),l(.23,.414),l(-.049,.353),l(-.248,.169),l(-.445,-.014),l(-.347,-.015),l(-.138,.674),l(.375,.274),l(1.137,-.415),l(.366,-.047),l(.781,-.047),l(.286,.015),l(.677,.32),l(.378,.351),l(.004,.259),l(-.081,.123),l(.277,.32),l(.516,-.184),l(.306,-.046),l(1.173,-.079),l(.636,-.184),l(.436,-.383),l(.333,-.551),l(.326,.015),l(.194,.122),l(.693,.717),l(.042,-.062),l(.108,-.764),l(.317,-.583),l(.475,-.262),l(.539,-.385),l(-.651,-.505),l(.008,-.308),l(.272,-.139),l(.98,-.094),l(.193,-.139),l(.512,-.665),l(.667,.37),l(.607,.599),l(.785,.506),l(.596,.797),l(1.045,.764),l(.264,.352),l(-.344,.291),l(.095,.335),l(.573,-.031),l(.365,.777),l(.182,.183),l(.324,.121),l(.743,.136),l(.281,.258),l(.133,.38),l(-.379,.092),l(-.416,.168),l(.411,.318),l(.397,.227),l(.77,.196),l(.279,.227),l(.034,.424),l(-.056,.076),l(-.409,.106),l(-.676,-.029),l(-.745,-.12),l(-.316,.061),l(.091,.166),l(.273,.181),l(.189,.241),l(.333,.513),l(.411,.226),l(.634,.029),l(.462,.18),l(.838,.496),l(.899,.435),l(.246,.33),l(-.035,.195),l(-.447,.781),l(.508,.059),l(.663,-.166),l(.786,-.077),l(.79,.164),l(.574,.194),l(1.162,.49),l(.981,.132),l(1.517,.295),l(-.184,.253),l(-.718,.21),l(-.736,.21),l(-.663,.046),l(-.834,.24),l(-.583,.402),l(-.65,.225),l(-1.032,.061),l(-.286,.075),l(-.324,.268),l(.029,.371),l(-.271,.535),l(1.175,-.343),l(.542,-.09),l(.649,-.105),l(1.201,-.774),l(1.251,-.478),l(1.146,-.106),l(.662,.237),l(.35,.341),l(-.398,.446),l(.036,.119),l(.307,.296),l(.616,-.224),l(.455,-.164),l(.655,.192),l(1.051,.487),l(.226,.251),l(.022,.178),l(-.299,.43),l(-.05,.355),l(-.406,.444),l(1.001,.929),l(-.365,.37),l(-.795,.282),l(-1.078,.621),l(-.662,.281),l(-1.097,.046),l(-.823,.119),l(-1.548,.077),l(-.433,.413),l(-.916,.795),l(-.686,.427),l(-.612,.294),l(-.938,.222),l(-1.494,.172),l(-1.845,.127),l(-1.452,-.07),l(-2.031,-.084),l(-.355,.03),l(-1.073,.075),l(-1.058,-.012),l(-1.873,-.099),l(-.917,-.027),l(-1.758,.106),l(-.547,.206),l(-.523,.294),l(-.537,.585),l(-.205,.554),l(-.287,.335),l(-.591,.19),l(-1.07,.104),l(-.537,.147),l(-1.098,.555),l(-.774,.54),l(-.794,.612),l(-.325,.363),l(-.33,.233),l(-.868,.843),l(-.485,.566),l(-.418,.276),l(-.46,.58),l(-.518,.968),l(.749,-.737),l(.375,-.131),l(.688,-.479),l(1.059,-.944),l(1.097,-.785),l(2.028,-.948),l(1.245,-.395),l(1.797,-.512),l(1.065,-.235),l(1.03,-.235),l(1.473,-.148),l(.922,.056),l(.895,.289),l(.509,.29),l(.136,.189),l(.144,.464),l(-.125,.218),l(-.326,.219),l(-1.059,.292),l(-.753,.452),l(-.581,.044),l(-.845,-.23),l(-.726,.045),l(-.645,.19),l(.279,.08),l(1.13,.229),l(.17,.122),l(.256,.444),l(.074,.095),l(1.299,-.485),l(-.028,.216),l(.479,-.148),l(.372,.162),l(-.36,.229),l(-.231,.256),l(.112,.27),l(-.163,.014),l(-.074,.229),l(-.91,.444),l(1.216,.013),l(.077,.188),l(-.187,.282),l(.091,.43),l(.118,-.081),l(.239,.134),l(-.063,.134),l(.048,.202),l(.351,.457),l(.009,.147),l(.824,.054),l(.154,.094),l(.04,-.067),l(.727,.147),l(-.315,.134),l(-.373,-.013),l(-.047,.134),l(.525,.147),l(.211,.241),l(.569,-.081),l(.135,.134),l(.212,-.014),l(.134,.174),l(.418,-.04),l(-.075,-.107),l(.843,.067),l(.241,.107),l(-.207,.201),l(.242,-.107),l(.26,.027),l(.245,-.013),l(.696,-.362),l(.303,-.081),l(.104,.362),l(.377,.161),l(.538,-.121),l(.488,.416),l(-.405,.254),l(.089,.107),l(.825,.027),l(.164,.174),l(-.521,.121),l(-.161,-.121),l(-.3,.134),l(.118,.094),l(-.515,0),l(-.23,-.04),l(.109,.161),l(-.45,.04),l(.056,.107),l(-.443,.014),l(-.128,.147),l(-.45,.04),l(-.368,.253),l(-.09,-.106),l(-.706,.28),l(-.046,.053),l(-.529,.133),l(-.119,-.267),l(-.274,.106),l(-.163,.267),l(-.188,-.187),l(-.068,.253),l(-.218,.08),l(-.094,.187),l(-.513,0),l(-.081,-.08),l(-.169,-.053),l(.032,-.347),l(-.242,.36),l(-.202,.12),l(-.131,-.253),l(-.354,.027),l(.043,.24),l(-.233,.04),l(.312,.08),l(.033,.213),l(-.103,.12),l(-.174,-.067),l(-.768,.453),l(.127,.16),l(-.235,.12),l(-.194,.053),l(.015,.213),l(-.161,-.12),l(.083,.173),l(-.217,.08),l(-.14,-.107),l(.096,.253),l(-.222,.066),l(-.146,-.08),l(-.148,0),l(-.064,.133),l(-.156,-.106),l(-.243,.227),l(-.086,.292),l(-.201,-.226),l(-.344,.133),l(-.154,-.187),l(-.349,-.479),l(-.138,.24),l(-.419,-.866),l(.456,-.773),l(.284,-.16),l(.035,-.12),l(-.35,.12),l(-.357,.267),l(-.076,-.106),l(.924,-.507),l(.125,.146),l(.195,-.093),l(-.258,-.107),l(1.103,-.52),l(1.109,-.562),l(.658,-.361),l(.336,.094),l(-.067,.428),l(.179,-.054),l(.258,.281),l(-.044,-.201),l(-.017,-.174),l(.632,-.214),l(.73,-.134),l(.192,.067),l(.202,-.081),l(-.152,-.094),l(-.653,-.053),l(-.595,.053),l(-.42,-.053),l(-.804,-.014),l(-.306,.027),l(-.251,.081),l(-.246,.094),l(.033,-.214),l(1.128,-.563),l(.054,-.201),l(.252,-.08),l(-.052,-.174),l(-.523,.281),l(.097,-.134),l(-.502,-.51),l(.309,.443),l(-.36,.482),l(-.328,.013),l(-1.974,.817),l(-.284,.08),l(-.362,-.201),l(-.227,-.067),l(.23,.201),l(-.788,.401),l(-.219,-.174),l(-1.019,-.054),l(-.124,.147),l(-.38,-.241),M(186.193,47.833),l(-.713,-.032),l(-.922,-.181),l(-.882,-.065),l(-1.25,-.314),l(-.973,-.182),l(-.604,-.049),l(-1.083,-.199),l(.43,-.335),l(1.542,-.405),l(.385,-.186),l(.115,-.673),l(.305,-.236),l(.831,-.069),l(.743,.184),l(1.436,.603),l(1.287,.4),l(.074,.285),l(.315,.284),l(1.094,.516),l(-.288,.117),l(-1.263,.486),l(-.578,.051),M(231.09,50.646),l(-1.319,-.03),l(-.449,-.147),l(-.232,-.247),l(-.173,-.478),l(.3,-.43),l(.708,-.664),l(.662,-.267),l(1.359,-.168),l(.911,.197),l(.79,.314),l(-.021,.464),l(-.039,.727),l(-.362,.265),l(-1.025,.348),l(-1.108,.117), +N(444.972,79.145),l(.47,-.218),l(.307,-.093),l(-.294,-.024),l(-.419,.061),l(-.15,-.135),l(-.125,.184),l(-.108,-.012),l(.066,-.491),l(.177,-.218),l(.41,.009),l(1.489,.062),l(.417,.014),l(.339,-.075),l(.121,-.253),l(-.175,-.288),l(.246,-.05),l(-.068,-.122),l(-.068,-.123),l(.353,-.096),l(.12,-.034),l(.051,.154),l(.086,.052),l(.24,0),l(.223,.12),l(.257,.069),l(.514,.068),l(.086,.103),l(.223,-.051),l(.445,0),l(.257,0),l(.223,-.017),l(.086,.137),l(.103,.103),l(.188,.034),l(.171,.069),l(.018,.137),l(.052,.12),l(-.224,.12),l(-.068,.154),l(-.068,.206),l(.018,.171),l(.034,.137),l(.029,.038),l(-2.96,.101),l(-2.246,-.115),l(-.842,-.006),M(717.633,81.109),l(.42,.443),l(.429,.62),l(.183,.457),l(.01,.767),l(-.244,.442),l(-.197,.78),l(-.002,.764),l(.29,.777),l(.592,.849),l(.65,1.446),l(.899,1.614),l(1.115,1.679),l(-1.26,-.677),l(-.832,-.39),l(-.99,-.056),l(-.268,.088),l(-.396,.204),l(-.462,1.045),l(-.266,1.101),l(-.082,.579),l(.277,.982),l(.183,.216),l(.659,.908),l(.54,.201),l(.463,.648),l(-.314,1.246),l(-.664,-1.258),l(-.866,-.301),l(-.224,.029),l(-.415,.303),l(-.311,.534),l(-.643,.907),l(-.422,-.5),l(-.19,-.929),l(.637,-1.146),l(-.395,-.884),l(.175,-.454),l(.502,-.63),l(-.131,-.723),l(-.196,-.376),l(-.27,-.55),l(-.062,-.235),l(.403,-.302),l(.284,-.915),l(.075,-.784),l(.005,-1.326),l(.15,-1.302),l(-.09,-.732),l(-.213,-.469),l(-.83,-.85),l(-.1,-.897),l(.114,-.192),l(.359,-.722),l(.065,-.738),l(-.336,-.457),l(.172,-.237),l(.374,-.03),l(.62,-.031),l(1.023,-.534),M(471.158,84.281),l(-.002,-.142),l(-.165,-.066),l(-.082,-.115),l(-.164,-.082),l(.033,-.099),l(-.033,-.23),l(-.033,-.164),l(.082,-.099),l(-.147,-.131),l(-.099,-.148),l(.132,-.066),l(0,-.165),l(-.296,-.164),l(-.279,-.263),l(-.017,-.164),l(.099,-.131),l(.131,-.165),l(.362,-.017),l(.328,.049),l(.197,.132),l(.51,.016),l(.525,-.099),l(.444,-.247),l(.049,-.065),l(.148,-.083),l(.296,0),l(.065,-.164),l(-.033,-.131),l(-.279,-.066),l(-.296,-.148),l(-.099,-.181),l(.082,-.017),l(.066,-.049),l(.032,-.065),l(-.263,-.066),l(-.361,-.099),l(-.378,-.066),l(-.361,.066),l(-.182,-.066),l(.066,-.181),l(.099,-.197),l(-.066,-.148),l(-.164,-.099),l(-.279,-.082),l(-.23,-.066),l(-.443,-.213),l(-.115,-.23),l(-.164,-.263),l(-.214,-.017),l(-.017,-.099),l(.066,-.131),l(.099,-.115),l(-.132,-.033),l(-.181,.049),l(-.082,-.115),l(-.132,-.181),l(-.345,-.049),l(.049,-.147),l(.033,-.165),l(.099,-.049),l(.115,-.082),l(0,-.083),l(.114,0),l(.066,-.131),l(-.05,-.164),l(-.147,-.099),l(-.197,-.247),l(.131,-.165),l(.033,-.164),l(0,-.083),l(.065,-.115),l(-.049,-.115),l(-.147,.033),l(-.165,-.033),l(-.147,-.099),l(-.099,-.099),l(-.279,-.099),l(-.132,-.131),l(-.542,-.115),l(-.247,.049),l(-.099,-.049),l(-.131,-.049),l(-.23,.083),l(-.147,.099),l(-.165,0),l(-.279,.016),l(-.214,.197),l(-.197,0),l(-.164,-.148),l(-.065,-.148),l(.017,-.099),l(.164,-.099),l(0,-.115),l(-.147,-.017),l(-.296,-.065),l(-.312,-.049),l(-.361,.049),l(-.214,.065),l(-.197,.033),l(-.082,-.148),l(-.132,-.148),l(-.312,-.033),l(-.181,-.016),l(-.197,.131),l(-.229,-.066),l(-.165,-.147),l(.061,-.042),l(.015,-.117),l(.044,-.087),l(-.088,-.233),l(.015,-.189),l(-.131,-.117),l(.059,-.087),l(-.16,-.043),l(-.146,-.102),l(-.029,-.16),l(-.131,-.058),l(-.116,-.102),l(.043,-.073),l(.059,-.087),l(-.073,-.044),l(-.087,-.014),l(-.131,-.073),l(-.146,.015),l(-.204,.059),l(.044,-.102),l(.102,-.073),l(.073,-.087),l(-.029,-.117),l(.072,-.131),l(-.131,-.087),l(.103,-.029),l(.087,-.015),l(.102,-.073),l(.015,-.087),l(.029,-.116),l(.015,-.087),l(-.204,-.058),l(-.087,-.073),l(-.204,-.087),l(-.232,-.073),l(0,-.117),l(.015,-.116),l(-.37,.004),l(-.081,-.106),l(.116,-.058),L(461.402,72),l(.029,-.117),l(.131,0),l(.087,-.116),l(.059,-.102),l(.16,-.058),l(.262,-.043),l(.175,-.073),l(-.059,-.059),l(-.175,-.043),l(-.043,-.146),l(-.015,-.087),l(0,-.073),l(-.088,-.073),l(-.203,-.087),l(-.175,-.233),l(0,-.175),l(.175,-.131),l(-.029,-.16),l(-.073,-.189),l(-.131,-.437),l(-.029,-.16),l(.088,-.16),l(.204,-.131),l(.319,-.131),l(.219,-.204),l(.175,-.277),l(.058,-.131),l(.088,-.043),l(.116,0),l(.189,0),l(.175,-.044),l(.043,-.174),l(-.16,-.131),l(-.145,-.053),l(-.089,-.13),l(-.17,-.038),l(.1,-.253),l(.339,-.038),l(.153,.165),l(.229,.063),l(.188,-.088),l(-.094,-.139),l(.301,-.154),l(.485,.199),l(.296,-.062),l(.312,-.338),l(.311,-.185),l(.75,.106),l(.781,.275),l(.439,0),l(.363,-.154),l(-.386,-.399),l(-.59,-.323),l(-.393,-.03),l(-1.204,.08),l(-.616,-.091),l(-.271,-.108),l(-.299,-.309),l(.258,-.434),l(-.065,-.201),l(-.199,.044),l(.174,-.285),l(1.946,-1.145),l(1.983,-1.195),l(1.385,-.758),l(.591,-.536),l(.43,-.536),l(.105,-.409),l(-.161,-.346),l(-.436,-.392),l(-.703,-.265),l(-1.357,-.499),l(-.439,-.33),l(.327,-.191),l(.542,-.415),l(.057,-.254),l(-.151,-.253),l(-1.286,-1.395),l(-.37,-.509),l(.029,-.37),l(.187,-.403),l(.44,-.535),l(.196,-.356),l(-.772,-1.195),l(-1.402,-1.394),l(.328,-.296),l(1.303,-.777),l(.421,-.364),l(-.543,-.392),l(-.964,-.506),l(-.872,-.194),l(-.563,-.212),l(-.116,-.529),l(.258,-.465),l(.024,-.283),l(.689,-.303),l(1.013,-.672),l(1.023,-.49),l(.77,-.121),l(.824,-.021),l(.514,-.204),l(.404,-.288),l(.617,-.051),l(1.002,-.254),l(.643,-.237),l(.01,.151),l(.255,.386),l(.358,.284),l(.543,.2),l(.919,.082),l(.602,.1),l(.078,.602),l(.695,-.319),l(.421,.049),l(1.083,.048),l(.875,.015),l(.522,.032),l(1.116,-.002),l(1.293,.281),l(2.728,.512),l(.984,.364),l(1.595,.86),l(.583,.214),l(1.48,.246),l(1.296,.212),l(2.018,.623),l(.328,.279),l(-.051,.444),l(.147,.295),l(.426,.294),l(.104,.294),l(-.24,.344),l(-.69,.491),l(-1.092,.54),l(-.816,.262),l(-1.75,.36),l(-.907,.083),l(-1.631,-.013),l(-1.391,-.192),l(-2.038,-.175),l(-1.63,-.192),l(-1.342,-.339),l(-2.256,-.485),l(-1.114,-.112),l(-.476,-.048),l(-.621,-.473),l(-.371,-.163),l(-.771,-.13),l(-.943,.117),l(.307,.163),l(.149,.065),l(.73,.538),l(.482,.146),l(1.109,.601),l(.832,.291),l(.921,.161),l(.634,.242),l(.405,.453),l(-.002,.405),l(-.276,.291),l(-.684,.195),l(.086,.113),l(.208,.531),l(.771,.943),l(.093,.494),l(.155,.207),l(.438,.174),l(1.203,.078),l(.872,.125),l(.499,.619),l(.401,.095),l(1.26,.077),l(.575,.126),l(.364,.079),l(.402,-.128),l(.785,-.097),l(.243,-.302),l(-.001,-.318),l(-.387,-.397),l(-.471,-.079),l(-.455,.096),l(-.447,-.031),l(-.589,-.206),l(-.952,-.795),l(.701,-.674),l(.484,-.001),l(1.116,.479),l(1.441,.333),l(2.09,.427),l(.952,.078),l(.834,-.146),l(.723,.174),l(.261,-.224),l(.05,-.415),l(-.214,-.239),l(-.858,-.656),l(-.348,-.628),l(.285,-.323),l(.19,-.049),l(1.432,-.423),l(1.495,-.359),l(.599,-.244),l(1.133,-.717),l(.172,-.049),l(.462,.064),l(1.829,.29),l(1.41,.533),l(.341,-.001),l(.052,-.065),l(.154,-.503),l(.581,-.767),l(-.048,-.653),l(-.317,-.408),l(-.847,-.163),l(-.3,-.229),l(1.139,-1.005),l(.101,-.247),l(-.205,-.594),l(-.771,-.512),l(.069,-.315),l(.353,-.051),l(1.458,.23),l(2.025,-.12),l(.631,.132),l(.664,.611),l(.616,.445),l(.433,.461),l(-1.045,.051),l(-1.559,.085),l(-.822,.215),l(-.492,.51),l(.191,.18),l(.952,.293),l(.732,.555),l(.804,.194),l(.723,.097),l(1.268,-.133),l(1.33,-.084),l(.301,-.164),l(.257,-.491),l(.291,-.591),l(.284,-.412),l(1.232,-.2),l(1.223,-.414),l(.988,-.216),l(1.924,-.483),l(1.429,-.251),l(1.537,-.318),l(.921,-.3),l(.205,.464),l(.278,.083),l(.571,-.117),l(.487,-.266),l(.148,-.465),l(.386,-.167),l(.718,-.135),l(.859,.065),l(-.18,.399),l(-.058,.597),l(-.858,.084),l(-.178,.149),l(.002,.215),l(.687,.197),l(.507,-.083),l(1.169,-.167),l(.436,-.001),l(.161,.198),l(.23,.049),l(.278,-.133),l(.264,-.216),l(.29,-.431),l(.464,-.183),l(.861,-.118),l(1.049,-.068),l(.768,.032),l(1.075,.23),l(.755,-.018),l(.36,-.083),l(.963,-.467),l(1,-.285),l(.803,-.052),l(.952,.182),l(.326,.166),l(-.631,.45),l(.129,.232),l(.217,.099),l(.632,.131),l(.579,-.018),l(.288,-.232),l(.074,-.398),l(.342,-.084),l(.962,.065),l(.543,-.184),l(.395,-.316),l(.115,-.417),l(-1.37,-1.033),l(.405,-.168),l(.66,-.37),l(.403,-.068),l(.609,.016),l(2.171,.063),l(1.272,.199),l(1.241,.149),l(1.135,.199),l(2.111,.515),l(1.071,.098),l(1.712,.414),l(1.02,.248),l(1.305,.53),l(1.455,.611),l(.864,.379),l(.376,.049),l(.229,-.1),l(1.145,-1.047),l(.236,-.3),l(-.927,.035),l(-.4,-.049),l(-.564,-.232),l(-.365,-.433),l(.027,-.652),l(-.727,-.283),l(-1.987,-.147),l(-.19,-.268),l(.064,-.168),l(.305,-.303),l(.693,-.255),l(.236,-.153),l(.085,-.187),l(-.052,-.833),l(-.251,-.238),l(-1.135,-.066),l(-.232,-.29),l(.328,-.532),l(.359,-.241),l(.391,-.035),l(1.482,-.416),l(1.098,-.485),l(.521,-.416),l(.581,-.608),l(.544,-1.22),l(.637,-.421),l(.374,.069),l(1.562,.155),l(1.613,-.125),l(1.605,-.091),l(.695,.069),l(1.066,-.055),l(.574,.122),l(.309,.279),l(-.018,.332),l(-.423,.836),l(-.348,.348),l(-1.334,.833),l(-.223,.345),l(.752,.342),l(.931,.667),l(.277,.342),l(.21,.818),l(-.174,.222),l(-.575,.375),l(.254,1.179),l(-.058,1.305),l(.263,.583),l(.45,.381),l(1.027,.264),l(.19,.166),l(-.001,.133),l(-.485,.481),l(-.417,.826),l(-.333,.33),l(-.784,.462),l(-1.232,.625),l(-.63,.198),l(-.55,.263),l(.321,.522),l(-.433,.115),L(558,52.195),l(-1.599,-.372),l(-.731,-.08),l(-.97,.034),l(-.601,.115),l(.195,.31),l(.583,.276),l(.738,.21),l(1.569,.208),l(1.133,.079),l(.613,-.05),l(1.188,.144),l(.922,-.034),l(.472,-.358),l(.303,-.358),l(1.352,-.328),l(1.166,-.492),l(.268,-.278),l(.386,-.606),l(.818,-.313),l(.864,-.626),l(.064,-.362),l(-.225,-.561),l(-.609,-.545),l(.244,-.548),l(.237,-.1),l(.677,-.151),l(1.38,-.152),l(1.757,-.003),l(.74,.231),l(.842,.463),l(.151,.778),l(-.34,1.023),l(.302,.279),l(.92,.212),l(1.298,.047),l(.864,-.149),l(.129,-.296),l(-.514,-.18),l(-.797,-.18),l(-.571,.034),l(-.457,-.098),l(.068,-.379),l(1.03,-.382),l(.065,-.249),l(-.218,-.148),l(-.166,-.331),l(-.441,-.763),l(-.511,-.266),l(-.836,-.098),l(-1.093,-.231),l(-.801,-.116),l(-1.288,-.165),l(-.91,.186),l(-.638,.101),l(-1.297,-.181),l(-.896,.019),l(-.015,-.267),l(-.564,-1.071),l(.305,-.657),l(.736,-.697),l(.282,-.46),l(-.134,-.221),l(-1.092,-1.042),l(-.949,-.514),l(-.12,-.189),l(.833,-.554),l(1.213,-.106),l(.998,-.262),l(.744,-.348),l(.172,-.226),l(.169,-.644),l(-.13,-.663),l(.23,.069),l(.64,.051),l(.466,.086),l(.108,.471),l(-.186,.54),l(-.636,.608),l(-.167,.554),l(.14,.448),l(.373,.274),l(.485,.274),l(1.384,.134),l(1.574,.169),l(1.632,.083),l(.819,.409),l(.321,.017),l(.799,-.036),l(-.527,-.89),l(-.521,-.274),l(-1.893,-.1),l(-.931,-.067),l(-.576,-.154),l(-.609,-.448),l(.275,-.329),l(1.374,-.054),l(.444,.172),l(1.145,.084),l(.747,-.157),l(-.09,-.728),l(.408,-.088),l(.84,-.105),l(1.278,-.02),l(1.067,.207),l(1.413,.379),l(1.088,.535),l(1.326,.343),l(.547,.085),l(1.822,.014),l(.727,-.174),l(.138,.345),l(-.781,.38),l(-.696,.259),l(-.248,.771),l(-.129,.972),l(.333,.136),l(.68,-.785),l(.387,-.292),l(.285,.051),l(.604,.528),l(-.088,.749),l(.743,-.205),l(.681,-.273),l(-.044,-.306),l(-.191,-.119),l(-.147,-.358),l(-.748,-.821),l(.188,-.223),l(.686,-.759),l(-.797,-.448),l(-.772,-.258),l(-.93,-.241),l(-.257,-.382),l(-.655,-.051),l(-.979,-.242),l(-1.34,-.207),l(-.307,-.296),l(.062,-.577),l(-.096,-.386),l(-.811,-.667),l(.081,-.247),l(.266,-.16),l(.484,-.125),l(2.31,-.11),l(2.54,-.022),l(2.125,-.128),l(1.421,-.162),l(.475,.317),l(.382,.052),l(.844,-.267),l(1.056,-.286),l(1.413,-.109),l(.589,.194),l(-.957,.338),l(-.451,.407),l(1.737,-.233),l(.521,-.107),l(.955,-.374),l(.27,-.284),l(-.334,-.444),l(-.326,-.177),l(-.925,-.266),l(-.365,-.303),l(-.002,-.232),l(.324,-.539),l(1.176,-.397),l(.966,-.22),l(3.028,-.903),l(.889,-.094),l(.248,-.036),l(.522,-.076),l(1.899,-.096),l(1.663,-.114),l(2.302,-.244),l(2.048,-.263),l(1.595,-.43),l(.855,-.243),l(1.763,.034),l(1.065,-.002),l(.383,.185),l(-.351,.409),l(1.504,.108),l(1.018,-.039),l(1.261,-.188),l(1.345,-.225),l(.95,-.039),l(.982,.166),l(.687,.073),l(.693,-.206),l(.12,-.335),l(-.133,-.167),l(.466,-.337),l(.942,-.077),l(.939,.036),l(1.243,-.377),l(-.618,-.506),l(.122,-.34),l(1.165,-.438),l(1.554,-.383),l(2.23,-.406),l(1.229,-.077),l(.993,.056),l(1.486,-.003),l(.86,.265),l(.045,.266),l(-1.528,.401),l(-.66,.342),l(.488,.15),l(1.83,-.117),l(1.588,.148),l(2.039,-.079),l(.177,.113),l(-.375,.283),l(-1.187,.453),l(-.296,.3),l(1.971,-.004),l(.833,-.02),l(.234,.093),l(1.052,-.545),l(1.366,-.002),l(1.771,-.097),l(.631,.13),l(1.35,-.021),l(1.954,.165),l(1.4,.259),l(1.181,.427),l(.52,.445),l(.726,-.001),l(.854,-.076),l(.422,.5),l(-1.354,.832),l(.241,.128),l(.896,.365),l(-2.329,.859),l(-1.035,.235),l(-1.166,.11),l(-3.404,1.061),l(-3.018,.965),l(-.793,.285),l(-2.388,.375),l(-2.35,.586),l(-2.065,1.126),l(.715,.017),l(1.081,-.247),l(.922,-.458),l(1.663,-.161),l(1.231,-.02),l(2.101,-.268),l(1.879,-.286),l(.879,-.107),l(1.004,-.284),l(-.094,-.389),l(-.492,-.123),l(-.034,-.071),l(.281,-.249),l(.581,-.214),l(.873,.211),l(.603,.389),l(.621,.052),l(.593,.193),l(.737,.052),l(.853,-.055),l(1.155,-.268),l(.499,.07),l(.192,.3),l(.009,.512),l(.522,.404),l(1.422,-.778),l(1.66,-.021),l(1.506,-.145),l(2.354,.014),l(1.919,.155),l(.854,.034),l(1.204,.033),l(-.271,.74),l(.354,.333),l(2.043,.154),l(.848,.121),l(.698,.069),l(1.035,.103),l(2.49,-.145),l(1.209,-.02),l(1.42,.348),l(1.405,-.932),l(-.161,-.352),l(-.038,-.229),l(-.034,-.105),l(1.806,-.48),l(.521,-.019),l(.802,.104),l(1.148,.298),l(.851,.281),l(1.711,.032),l(1.354,-.073),l(1.384,.033),l(1.323,.431),l(.409,.181),l(.058,.386),l(-.52,.088),l(-.268,.036),l(-1.905,.406),l(-2.438,.737),l(-.233,.227),l(.253,.069),l(1.033,.067),l(.957,.016),l(.659,.155),l(.659,.293),l(1.014,.396),l(.583,.172),l(.78,.481),l(1.27,.805),l(1.814,.801),l(1.351,.305),l(.612,-.018),l(.795,-.394),l(.843,-.72),l(1.093,-1.051),l(.601,-.329),l(.29,.017),l(.236,.465),l(.772,.308),l(1.346,.29),l(1.105,.135),l(.848,-.087),l(1.973,-.468),l(.778,-.07),l(.813,.067),l(1.196,.239),l(1.921,.734),l(.315,-.052),l(.186,-.069),l(.491,-.258),l(.221,-.258),l(-.137,-.051),l(.013,-.189),l(.726,-.312),l(.509,-.018),l(.5,.257),l(.575,.188),l(1.302,.032),l(.181,-.5),l(-.194,-.466),l(.15,-.363),l(.093,-.521),l(-1.131,.159),l(-.643,.001),l(-.179,-.104),l(.442,-.296),l(.318,-.087),l(.986,-.089),l(1.021,-.02),l(.832,-.141),l(1.566,-.648),l(.254,0),l(1.76,.241),l(1.561,.137),l(2.036,.188),l(.997,.068),l(.654,.103),l(2.307,.065),l(-1.732,.628),l(.865,.051),l(1.011,-.089),l(.335,.138),l(-.305,.381),l(-.926,.192),l(-.846,.261),l(-.177,.293),l(.664,.033),l(.52,-.122),l(.916,-.14),l(.978,-.33),l(1.62,-.799),l(2.766,.012),l(1.196,.067),l(.903,.172),l(.946,.137),l(.205,.19),l(.221,.104),l(-2.247,.59),l(.559,.137),l(1.674,.289),l(2.174,.202),l(.946,.204),l(.801,.375),l(.367,.427),l(.564,.357),l(.522,.152),l(1.459,-.037),l(1.364,-.105),l(1.138,-.139),l(2.518,-.329),l(2.208,-.107),l(3.008,.131),l(1.515,.134),l(.734,.118),l(1.168,.424),l(.655,.169),l(.525,.338),l(.361,.39),l(-.123,.491),l(-.286,.521),l(.509,.25),l(.764,.065),l(.835,.015),l(.643,.083),l(-.017,.685),l(.419,.416),l(.686,-.168),l(.545,-.435),l(1.211,-.387),l(.348,-.067),l(.35,.049),l(1.696,-.02),l(1.521,-.288),l(.736,.032),l(.588,.434),l(.707,.116),l(1.541,.014),l(2.176,.062),l(.869,-.118),l(1.378,-.504),l(.406,.2),l(.93,.533),l(.396,.216),l(1.095,.265),l(.875,.332),l(.282,.398),l(.612,.148),l(1.556,-.136),l(1.653,-.319),l(.16,-.25),l(-.248,-.333),l(-.805,-.833),l(-.833,-.115),l(.4,-.336),l(.479,-.571),l(1.89,.098),l(1.214,.082),l(1.135,.065),l(1.221,.166),l(.222,.318),l(1.396,-.153),l(2.084,-.054),l(2.304,.013),l(1.292,.148),l(.786,.199),l(1.185,.199),l(1.391,.098),l(.751,.182),l(1.302,.332),l(.747,.065),l(.703,.182),l(1.145,.505),l(0,2.126),l(0,2.222),l(0,2.222),l(0,1.292),l(0,.157),l(0,.576),l(0,.219),l(-1.083,.371),l(-.651,.03),l(-.645,.37),l(-.56,.065),l(-1.044,.065),l(-.355,-.079),l(-.928,-.052),l(-.118,-.343),l(-.271,-.211),l(-.501,.027),l(.241,-.185),l(-.938,.324),l(-.846,.02),l(-.337,-.211),l(-.478,-.079),l(.424,.501),l(-.569,.29),l(.32,.103),l(.942,.205),l(.634,-.36),l(.395,.041),l(.335,.079),l(0,.477),l(.248,.206),l(.76,.269),l(1.059,-.228),l(-.439,.322),l(.741,-.243),l(.065,.336),l(.247,.206),l(.187,.363),l(.068,.189),l(-.722,.522),l(.593,-.064),l(.349,.172),l(.473,.503),l(.501,.157),l(.145,.251),l(-.162,.456),l(.792,-.111),l(-.125,.393),l(.023,.25),l(-.43,.299),l(-.691,.205),l(-.635,-.046),l(-.448,-.14),l(-1.243,-.154),l(-.889,-.077),l(-.347,-.14),l(.123,-.267),l(-.493,-.046),l(-.304,.032),l(-.559,.55),l(-.069,.11),l(-3.06,.913),l(-1.155,.174),l(-.245,0),l(-.43,.203),l(-.219,.188),l(-.719,.22),l(-.991,.033),l(-.308,.11),l(-.48,.405),l(-.462,.203),l(-.946,.033),l(-.854,.622),l(-.24,.279),l(-1.67,.452),l(-.392,.449),l(-1.229,.25),l(-.406,.14),l(-.151,.293),l(.01,.292),l(-.473,.292),l(-.406,.016),l(-.586,-.306),l(-.183,-.262),l(-.169,-.37),l(-.67,-.308),l(-1.074,-.044),l(-1.021,.048),l(-1.159,.172),l(-1.301,.188),l(-.523,.217),l(-1.333,.756),l(-.536,.277),l(-.184,-.138),l(.575,-1.293),l(-.55,.094),l(-.392,-.097),l(-.811,.531),l(-.67,.186),l(-.401,.155),l(-.114,.506),l(-.66,.154),l(-.317,-.168),l(-.253,-.49),l(-.483,-.261),l(-1.024,.636),l(.261,-.204),l(-.557,.062),l(-.283,.092),l(-.628,.522),l(-.141,.261),l(.126,.229),l(.344,.152),l(-.932,.521),l(-.182,.199),l(.342,.167),l(-.647,.352),l(-.88,.55),l(-.626,.503),l(-.298,.35),l(-.01,.531),l(.421,.317),l(.477,.09),l(1.382,-.048),l(.562,.166),l(.11,.167),l(-.436,.394),l(-.752,.455),l(-.181,.302),l(.224,.512),l(.292,.452),l(.786,.089),l(.165,.391),l(-.014,.616),l(-.349,.361),l(-.528,.061),l(-.481,-.209),l(-.017,-.21),l(.388,-.527),l(-.444,-.014),l(-.454,.242),l(-1.014,.843),l(-.56,.675),l(-.237,.599),l(.321,.672),l(.647,.311),l(.154,.237),l(-.294,.387),l(-.688,.313),l(-.956,.031),l(-.664,-.088),l(-.344,.001),l(-.619,.179),l(-.837,.476),l(-.214,.149),l(-.525,.504),l(-.137,.341),l(.111,.281),l(.492,.398),l(.038,.221),l(-.056,.133),l(-.679,.238),l(-.604,.016),L(753.44,82.4),l(-.727,.296),l(-.065,.251),l(.067,.28),l(-.161,.854),l(-.293,.412),l(-.8,.78),l(-1.53,.971),l(-.854,.5),l(-.285,.103),l(-.295,-.614),l(-.198,-.821),l(-.25,-.69),l(-.064,-.794),l(-.351,-.75),l(-.305,-.383),l(-.214,-.915),l(-.514,-1.36),l(-.008,-.578),l(-.154,-.563),l(-.017,-.327),l(-.105,-.193),l(-.262,-.817),l(-.026,-.792),l(.116,-.808),l(.271,-1.396),l(.167,-.226),l(1.185,-.86),l(.716,-.424),l(.57,-.695),l(.14,-.227),l(-.085,-.318),l(-.139,-.166),l(1.632,-.367),l(1.001,-.305),l(.811,-.32),l(1.729,-.884),l(.641,-.412),l(.431,-.428),l(.14,-.335),l(1.784,-.889),l(.872,-.445),l(1.535,-.861),l(.368,-.293),l(.26,-.433),l(1.252,-.435),l(2.106,-.514),l(.257,-.434),l(.773,-.528),l(.086,-.233),l(-.568,-.216),l(.814,-.904),l(-.036,-.483),l(.183,-.391),l(.598,-.204),l(1.729,-.082),l(.513,-.063),l(-.485,-.328),l(-2.065,-.215),l(-.71,.095),l(-1.062,.174),l(-.777,.189),l(.042,.328),l(-.664,.923),l(.125,.202),l(-.04,.14),l(-.662,.11),l(-.479,.11),l(-1.555,.718),l(-1.979,1.042),l(-1.169,.342),l(-.249,-.062),l(.156,-.325),l(.352,-.465),l(-.933,-.076),l(-.16,-.263),l(.252,-.451),l(.442,-.467),l(.207,-.328),l(-.069,-.202),l(-.339,-.031),l(-1.136,.454),l(-.496,.032),l(-.277,-.358),l(-.589,-.17),l(-1.606,.144),l(-1.312,.111),l(-.956,.08),l(-.606,.157),l(-.894,.359),l(-.093,.436),l(.082,.186),l(-1.262,.53),l(-.408,.233),l(.149,.495),l(-1.294,.357),l(-1.019,.434),l(-.84,.479),l(-.496,.461),l(-.332,.46),l(.004,.383),l(.527,.213),l(1.269,.043),l(.278,.275),l(.062,.122),l(-1.152,.139),l(-1.028,.262),l(-1.045,-.059),l(-.698,-.136),l(-.382,.031),l(-.311,.107),l(-.721,.398),l(-.695,-.35),l(-1.112,.383),l(-.747,.139),l(-.487,-.09),l(-.284,-.137),l(.108,-.29),l(.748,-.124),l(.868,-.124),l(.164,-.046),l(-.741,-.64),L(736.444,68),l(-1.06,.017),l(-.854,.155),l(-.353,-.061),l(-.868,-.458),l(-.775,-.029),l(-.745,.047),l(-.704,.246),l(.042,.398),l(-.26,.229),l(-.477,.215),l(-.695,-.243),l(-.408,-.122),l(-1.26,.063),l(-.784,.093),l(-.651,-.075),l(-.887,-.136),l(-.563,.078),l(-.067,.122),l(-.147,.474),l(-.677,.017),l(-.311,-.137),l(-.038,-.382),l(-.203,-.259),l(-1.241,.094),l(-1.014,-.059),l(-1.257,.033),l(-1.158,.063),l(-.836,-.029),l(-.18,.016),l(-1.085,.292),l(-.964,.444),l(-.74,.474),l(-.536,.504),l(-.789,.245),l(-.904,.336),l(-.194,.152),l(-1.047,1.17),l(-1.634,.684),l(-.949,.471),l(-1.157,.711),l(-1.653,1.253),l(-.828,.572),l(-1.573,.873),l(-.893,.376),l(-1.889,.871),l(-.632,.388),l(-.203,.298),l(.018,.357),l(.428,.281),l(.485,.043),l(.918,.013),l(1.046,-.15),l(.656,.043),l(-.329,1.261),l(.016,.415),l(.303,.103),l(.63,-.09),l(.601,-.371),l(.761,.117),l(-.127,.148),L(705.293,81),l(-.112,.222),l(.373,.073),l(1.645,-.018),l(.566,-.238),l(.39,-.519),l(.017,-.638),l(.763,.014),l(.647,-.001),l(.726,.014),l(.951,.265),l(.658,.354),l(.486,.591),l(.847,.575),l(.426,.176),l(.506,.324),l(-.07,.148),l(-.581,.355),l(.453,.221),l(.13,.309),l(-.336,.723),l(.491,.117),l(.215,.235),l(-.291,.515),l(-.348,.397),l(-.532,.559),l(-.724,1.364),l(-.181,.688),l(.057,.219),l(.24,.701),l(-.188,.917),l(-.098,.741),l(-.403,1.408),l(-.146,.493),l(-1.928,1.538),l(-.371,.435),l(-.217,.65),l(-.587,.42),l(-.741,.579),l(-.241,.361),l(-.574,.981),l(-.587,.606),l(-.941,.778),l(-1.784,1.512),l(-.464,.474),l(-.235,.458),l(-.323,.33),l(-.758,.388),l(-.618,.416),l(-.574,.702),l(-.431,.458),l(-.875,.673),l(-.955,.487),l(-1.838,.475),l(-.798,.244),l(-.278,-.427),l(-.519,-.085),l(-.243,.043),l(-.337,-.185),l(-.337,-.513),l(-.663,.272),l(-.464,.101),l(.424,-.586),l(-.624,.173),l(-.506,.486),l(-.649,.543),l(-1.326,1.001),l(-.072,.049),l(-.167,-.393),l(-.298,-.439),l(.111,-.058),l(1.252,-.462),l(.511,-.43),l(.156,-.329),l(-.112,-.299),l(.097,-.128),l(.025,-.385),l(.006,-.613),l(-.062,-.656),l(-.332,-.897),l(.048,-.557),l(1.664,-.982),l(.396,.041),l(.685,.24),l(.679,.225),l(.547,.098),l(.47,-.347),l(.551,-.69),l(.329,-.432),l(.627,-1.08),l(.538,-1.066),l(.278,-.893),l(.291,-.707),l(.66,-.393),l(.566,-.407),l(-.017,-.504),l(-.116,-.389),l(-.064,-.259),l(-.246,-.114),l(-.902,.034),l(-1.181,.208),l(-1.357,.31),l(-.953,.308),l(-.604,.22),l(-1.657,.052),l(-.649,.018),l(-.68,.033),l(-.261,-.446),l(-.44,-1.283),l(-.297,-.866),l(-.205,-.144),l(-2.659,-.839),l(-1.523,-.253),l(-1.247,-.341),l(-.507,-.2),l(-.436,-.389),l(-.927,-1.903),l(-.94,-1.588),l(-1.087,-2.384),l(-.742,-.952),l(-.763,-.467),l(-.539,-.026),l(-1.386,.125),l(-.683,-.188),l(-1.037,-.481),l(-1.148,-.215),l(-.917,.049),l(-1.203,.109),l(-.836,.123),l(-1.854,.143),l(-.602,.136),l(-.478,.165),l(-1.193,.787),l(-.375,.282),l(-.119,.25),l(.822,-.078),l(.558,.026),l(.465,.306),l(.107,.249),l(-.167,.794),l(-1.371,.608),l(-.599,.545),l(-.667,.779),l(-.416,.543),l(-.422,.426),l(-.103,.249),l(.062,.146),l(.35,.348),l(.056,.306),l(-.123,.233),l(-.779,.339),l(-2.44,.752),l(-.438,.089),l(-.343,.016),l(-1.126,-.574),l(-.452,-.172),l(-.046,-.018),l(-.431,-.168),l(-.622,.018),l(-1.228,.297),l(-.86,-.169),l(-.34,-.129),l(-.751,-.506),l(-.74,-.156),l(-.609,.047),l(-.333,.002),l(-1.165,.487),l(-.755,.498),l(-.447,.394),l(-.604,.264),l(-.526,.163),l(-1.147,.136),l(-.867,.106),l(-.532,.075),l(-1.018,.063),l(-1.602,.11),l(-.739,-.039),l(-.984,-.082),l(-.905,-.241),l(-1.318,-.254),l(-.812,-.373),l(-1.132,-.313),l(-.623,-.331),l(-1.333,-.75),l(-.769,-.229),l(-1.423,-.022),l(-1.172,-.037),l(-.796,.077),l(-2.48,.538),l(-.673,-.113),l(-1.643,-.531),l(-.421,-.333),l(-.408,-.451),l(-.182,-.481),l(-.004,-.541),l(-.145,-.204),l(-.767,-.143),l(-.989,-.317),l(-.702,-.231),l(-1.748,-.328),l(-1.036,-.185),l(-1.028,-.098),l(-.84,-.201),l(-1.269,.96),l(-.905,.839),l(-.098,.293),l(.409,.86),l(.396,.304),l(.116,.204),l(-.163,.526),l(-.744,.572),l(-.31,.162),l(-.755,.28),l(-.562,.018),l(-.576,-.186),l(-.312,-.114),l(-.875,-.068),l(-.85,.004),l(-.719,-.083),l(-1.458,.008),l(-.699,-.113),l(-.393,-.406),l(-.694,-.755),l(-.831,-.083),l(-1.842,-.122),l(-.932,-.156),l(-.953,-.097),l(-.84,.18),l(-1.512,.476),l(-1.143,.341),l(-.787,.398),l(-.971,.692),l(-.017,.012),l(-.727,.381),l(-.603,.148),l(-1.387,.08),l(-.599,.207),l(-.799,.425),l(-.154,.044),l(-.244,.074),l(-.569,.003),l(-.228,.014),l(-.064,-.145),l(-.589,0),l(-.294,-.478),l(-.441,-.331),l(.073,-.331),l(-.625,.184),l(-.478,.368),l(-.993,-.074),l(-.882,-.073),l(-.662,-.699),l(-.588,-.552),l(-.956,-.147),l(-.331,-.625),l(-.772,-.588),l(-.698,-.441),l(-.993,.037),l(-.771,.221),l(-.993,.221),l(-.992,0),l(-.589,0),l(-.184,-.184),l(-.258,-.257),l(-.478,0),l(0,-.368),l(-.367,-.331),l(-.92,0),l(-.367,.515),l(-.331,.257),l(-.515,.257),l(-1.104,-1.434),l(-.846,-.882),l(-1.69,-2.133),l(-1.066,-1.029),l(-1.287,-.772),l(-.809,-.294),l(-1.104,-.588),l(.11,-.368),l(.515,-.11),l(0,-.441),l(-.809,.074),l(-.515,.22),l(-.772,.221),l(-.956,.515),l(-1.103,.257),l(-.772,.441),l(-.294,.294),l(-.552,-.184),l(-.441,-.037),l(-.771,.073),l(-.441,.11),l(-.331,-.184),l(.331,-.441),l(.441,-.184),l(.146,-.294),l(-.367,0),l(-.441,.221),l(-.478,-.11),l(-.405,-.294),l(-.478,-.037),l(-.184,.147),l(-.147,.147),l(-.367,-.221),l(-.295,-.368),l(-.294,-.11),l(-.331,.221),l(-.367,-.074),l(-.368,.147),l(-.44,-.11),l(-.295,.147),l(-.478,-.074),l(-.184,-.257),l(.33,-.037),l(-.073,-.331),l(.147,-.257),l(.11,-.331),l(-.515,-.22),l(-.147,-.221),l(.037,-.331),l(-.368,-.404),l(-.882,.037),l(-.625,.11),l(-.772,-.257),l(-.515,-.11),l(-.919,-.147),l(-.735,.037),l(-.11,.221),l(-.589,.184),l(-.515,.037),l(0,.294),l(-.367,.368),l(-.625,.074),l(-1.876,.073),l(-2.021,.405),l(-1.177,.037),l(-.625,.331),l(-.221,.331),l(-.331,-.073),l(-.588,.073),l(-1.545,.11),l(-.735,.11),l(-1.029,.037),l(-1.396,.405),l(-.368,.184),l(-.772,0),l(-.515,0),L(537.304,80),l(-.33,.074),l(-.185,.515),l(.074,.441),l(.294,.221),l(-.294,.074),l(0,.331),l(1.065,.11),l(.956,.294),l(-.11,.257),l(-.515,.073),l(-1.103,-.147),l(-.698,.184),l(-.662,.515),l(.146,.257),l(.441,.478),l(-.331,.294),l(-.588,.147),l(-.735,.368),l(-.467,.067),l(.164,.274),l(.239,0),l(.377,.137),l(-.068,.171),l(.377,.137),l(.651,.069),l(.274,.308),l(1.165,.171),l(.24,.24),l(-.138,.686),l(-.137,.309),l(-1.577,.411),l(-.959,-.034),l(-.343,-.343),l(-.24,0),l(-.171,.309),l(-.651,.343),l(-.411,-.171),l(-.754,-.137),l(-.926,-.309),l(-.274,-.548),l(-.754,-.103),l(-1.062,.103),l(-.137,.412),l(-.617,.068),l(-.651,-.411),l(-.65,-.035),l(-.823,-.068),l(-.514,.377),l(-.377,.343),l(-.274,.274),l(-.686,.171),l(-.411,-.24),l(-.686,-.137),l(-.582,-.548),l(-.72,-.068),l(.034,.24),l(.205,.48),l(-.239,.274),l(-.274,-.137),l(-.068,-.583),l(-.411,-.274),l(-.789,-.343),l(-.582,-.206),l(0,-.343),l(-.96,-.171),l(-.617,.069),l(-.788,-.035),l(-.411,-.514),l(-.411,-.069),l(-.617,.24),l(-.273,.137),l(-.651,.137),l(-.309,-.274),l(-.479,0),l(-.651,-.069),l(-.515,.309),l(-.548,.343),l(-.788,.377),l(-.549,.068),l(-.514,.171),l(-.309,.309),l(-.172,.24),L(509.58,87.5),l(-.479,.206),l(.068,.445),l(.171,.411),l(-.068,.446),l(-.411,.24),l(-.651,0),l(-.514,-.411),l(-.48,-.548),l(-.514,-.24),l(-.411,.069),l(-.103,.308),l(-.343,.549),l(-.823,.137),l(-.205,1.303),l(.343,.171),l(.239,.274),l(-.239,.206),l(-.446,.274),l(-.65,1.165),l(1.37,.343),l(.138,.377),l(-.068,.309),l(.514,.514),l(.103,-.343),l(.583,.206),l(.343,-.034),l(.514,.034),l(.515,.445),l(.479,.206),l(.343,.514),l(.96,1.131),l(-.138,.103),l(-.445,-.103),l(-.309,-.103),l(-.343,.103),l(.068,.308),l(.857,.377),l(.616,.19),l(-.167,.2),l(-.399,.28),l(-.38,.12),l(-.12,0),l(0,.14),l(0,.22),l(-.14,.08),l(-.3,-.2),l(-.34,.2),l(-.399,.26),l(-.64,.12),l(-.319,.08),l(-.26,-.08),l(-.181,-.08),l(-.1,.04),l(-.06,.16),l(.12,.26),l(-.221,.2),l(-.18,.3),l(-.18,.319),l(-.319,.42),l(-.18,.28),l(-.32,.16),l(-.34,.24),l(-.14,.32),l(.08,.2),l(.34,.2),l(.319,.04),l(.18,.3),l(.24,.04),l(.239,.34),l(.28,.419),l(-.06,.38),l(-.101,.2),l(.061,.16),l(.1,-.2),l(.1,-.34),l(.12,-.22),l(.16,-.02),l(-.141,.439),l(-.22,.36),l(.061,.4),l(.12,.1),l(-.16,.2),l(-.04,.4),l(.38,.24),l(.119,.1),l(.12,.52),l(.28,.06),l(.359,.42),l(.2,.28),l(.439,.419),l(.18,.36),l(.359,.06),l(.047,.146),l(-.292,.449),l(-.496,.284),l(-.283,.094),l(-.308,.331),l(-.165,.213),l(-.379,.047),l(-.449,-.142),l(-.591,-.094),l(0,-.308),l(-.283,-.284),l(-.118,0),l(-.095,-.118),l(-.473,-.284),l(-.142,-.189),H(504.5,0),l(-.213,.047),L(504.264,107),l(-.229,.023),l(-.126,-.189),l(-.236,-.071),l(-.236,.023),l(-.284,-.047),l(-.26,-.094),l(-.284,-.166),l(-.354,-.284),l(.118,-.307),l(.118,-.189),l(-.118,-.142),l(-.354,-.024),l(-.378,0),l(-.213,-.166),l(-.189,-.118),l(-.212,0),l(-.143,-.094),l(-.236,-.118),l(-.118,0),l(-.095,.071),l(-.142,.166),l(-.188,-.142),l(-.261,-.071),l(-.354,0),l(-.213,.071),l(-.094,.095),l(-.166,.166),l(-.283,0),l(-.261,.118),l(-.212,-.071),l(-.261,-.118),l(.048,-.118),l(.142,-.118),l(-.308,-.119),l(-.236,-.118),l(-.354,-.071),l(-.52,-.118),l(-.284,-.213),l(-.095,-.142),l(-.354,-.166),l(-.283,.047),l(-.189,0),l(-.401,-.166),l(-.544,0),l(-.426,.095),l(-.307,0),l(-.355,-.047),l(-.307,-.071),l(-.261,-.095),l(-.212,-.166),l(-.213,0),l(-.331,0),l(-.189,-.047),l(-.188,-.094),l(-.284,-.142),l(-.283,-.095),l(-.449,-.023),l(-.402,-.023),l(-.07,-.047),l(-.284,-.047),l(-.26,.166),l(-.112,.309),l(-1.421,-1.012),l(-1.188,-.842),l(-.817,-.385),l(-.62,-.084),l(-.373,-.157),l(-.509,-.5),l(-.236,-.057),l(-.338,.159),l(-.329,-.042),l(-.347,-.515),l(-.795,-.674),l(.595,-.188),l(.519,-.001),l(.445,-.073),l(.1,-.519),l(.359,-.476),L(485,97.85),l(.526,-.03),l(.516,-.131),l(-.432,-.532),l(-.654,-.273),l(-.474,-.36),l(.243,-.116),l(.367,-.03),l(.82,-.117),l(.715,-.348),l(1.244,-.436),l(-.196,-.375),l(-.076,-.058),l(-.799,.088),l(-1.312,.175),l(.012,-.126),l(.021,-.112),l(0,-.224),l(.09,-.514),l(.224,-.089),l(.357,-.022),l(.38,-.134),l(.223,-.179),l(.022,-.179),l(.269,0),l(.736,-.045),l(.805,.157),l(.335,-.134),l(0,-.156),l(.156,-.291),l(.156,-.491),l(-.066,-.067),l(-.09,-.201),l(-.045,-.179),l(-.044,-.134),l(-.179,-.067),l(-.156,-.067),l(.044,-.224),l(.045,-.179),l(.246,0),l(.312,0),l(.134,-.156),l(-.29,-.044),l(-.269,-.089),l(-.223,-.246),l(.312,-.044),l(.357,-.201),l(.156,-.067),l(.201,-.089),l(.045,-.224),l(-.09,-.179),l(-.111,-.089),l(.022,-.179),l(.089,-.111),l(-.156,-.089),l(-.201,.089),l(-.134,.044),l(-.269,0),l(-.357,-.156),l(-.111,-.224),l(-.469,-.022),l(-.291,-.089),l(-.201,-.179),l(-.357,.067),l(-.268,-.112),l(-.469,-.112),l(-.425,-.067),l(-.29,-.268),l(-.224,.067),l(-.045,.157),l(-.29,.134),l(-.224,-.112),l(-.179,-.179),l(-.402,-.044),l(-.022,-.134),l(-.201,-.179),l(0,-.134),l(-.268,-.179),l(-.111,-.156),l(-.357,.067),l(-.536,.134),l(-.269,0),l(-.312,.112),l(-.425,.112),l(-.179,-.156),l(-.179,-.022),l(-.201,.067),l(-.469,-.291),l(-.268,-.067),l(-.47,.067),l(-.268,.179),l(-.291,-.29),l(-.179,-.089),l(-.089,-.224),l(.089,-.179),l(-.089,-.246),l(-.224,-.268),l(0,-.357),l(-.402,0),l(0,-.312),l(-.38,-.022),l(-.514,.067),l(-.156,-.112),l(-.647,0),l(-.269,-.29),l(-.111,-.357),l(-.134,-.291),l(.312,-.134),l(.312,.022),l(0,-.268),l(-.312,-.156),l(-.246,-.156),l(-.134,-.201),l(-.246,-.335),l(-.312,-.134),l(-.201,-.268),l(-.514,.134),l(-.692,-.112),l(-.67,.223),l(-.536,.022),l(-.536,-.246),l(-.134,.268),l(-.179,.291),l(-.313,.156),l(-.469,-.022),l(-.357,-.089),M(527.156,37.071),l(-.59,-.14),l(-.955,-.21),l(-1.128,-.139),l(-.739,.054),l(-.959,.037),l(-.732,.143),l(-.411,-.105),l(-1.025,-.476),l(.737,-.303),l(1.21,-.429),l(.654,-.09),l(1.549,-.002),l(.135,-.357),l(-.728,-.338),l(.351,-.269),l(.419,-.144),l(.676,-.02),l(.852,-.181),l(-.25,-.161),l(-.526,-.233),l(1.539,-.895),l(.513,-.129),l(.226,.073),l(.892,.017),l(.981,-.535),l(.863,-.333),l(1.02,-.261),l(.975,-.15),l(1.305,-.113),l(1.274,.053),l(.738,-.15),l(.786,-.615),l(.273,.018),l(.873,-.132),l(1.722,.276),l(.471,-.038),l(1.93,-.321),l(.958,-.039),l(2.184,-.247),l(1.864,-.116),l(.771,-.564),l(.376,-.152),l(2.511,-.137),l(1.965,-.079),l(.471,.131),l(.442,.225),l(.154,.357),l(-.812,.47),l(-.541,.169),l(-1.346,.319),l(-2.609,.433),l(-4.329,.49),l(-2.187,.281),l(-2.122,.299),l(-1.842,.316),l(-2.102,.242),l(-.941,.203),l(-.288,.274),l(.644,.216),l(-.422,.217),l(-.943,.361),l(-.527,.037),l(-2.047,-.068),l(-.432,.18),l(-.119,.233),l(.621,.249),l(-.331,.233),l(-1.206,.448),l(-.402,-.142),l(-.752,-.087),l(-.592,.304),l(.877,.283),l(.052,.319),l(-1.094,.657),l(-.822,.284),M(517.491,38.443),l(1.041,-.37),l(.512,-.299),l(.428,-.212),l(1.426,-.021),l(1.316,-.249),l(.987,-.02),l(1.412,-.091),l(.551,.069),l(.988,.227),l(-.063,.176),l(-.463,.528),l(-.302,.158),l(-.697,.071),l(-.443,.228),l(-.233,.385),l(.006,.818),l(.445,1.039),l(.957,.826),l(.505,.308),l(.775,.307),l(1.162,.392),l(-.028,.282),l(-2.62,-.089),l(-.844,.053),l(-.917,.326),l(-.596,.086),l(-.676,-.494),l(-.382,-.034),l(-1.091,.088),l(-.673,-.102),l(-.031,-.359),l(1.347,-.362),l(.073,-.24),l(-.102,-.017),l(-.944,-.273),l(-1.442,-.411),l(-1.519,-.17),l(-.33,.156),l(-.624,.122),l(-.681,-.033),l(-.625,-.396),l(-.114,-.415),l(.229,-.312),l(.39,-.209),l(.344,-.036),l(.318,.104),l(.65,.016),l(.518,-.192),l(1.121,-.768),l(.243,-.35),l(-.322,0),l(-.981,-.243),M(.125,56.089),l(0,-.562),l(0,-.576),l(0,-.157),l(0,-1.292),V(0,51.28),l(0,-2.222),l(0,-2.12),l(2.917,.61),l(1.693,.598),l(.933,.181),l(3.819,.99),l(1.059,.395),l(.204,.149),l(.074,.214),l(.445,.429),l(.406,.789),l(-.209,.428),l(1.034,.8),l(.982,.26),l(-.02,-.18),l(.297,-.148),l(-.051,-.196),l(-.638,-.392),l(.016,-.542),l(.077,-.296),l(1.026,-.183),l(.984,.278),l(.573,.098),l(.767,.064),l(1.003,-.117),l(.933,.13),l(.93,.425),l(.694,.359),l(1.676,.684),l(.32,.081),l(.584,.179),l(.43,.211),l(.09,.13),l(-.343,.033),l(-1.026,-.096),l(-.364,.034),l(-.808,.798),l(-1.539,-.468),l(.138,.178),l(.438,.227),l(.465,.324),l(-1.177,-.111),l(-1.008,.05),l(-1.202,-.387),l(-.708,-.096),l(.135,.129),l(.289,.259),l(.084,0),l(.561,.259),l(.205,.307),l(.131,.453),l(-.056,.339),l(-.814,.05),l(-.805,.065),l(-.189,.161),l(.5,.865),l(-.115,.272),l(-1.04,-.078),l(-.397,.081),l(-1.193,-.174),l(-.264,-.352),l(-1.795,-.51),l(-.253,.273),L(9.85,55.79),l(-.276,-.161),l(-.265,-.403),l(.174,-.178),l(-.321,-.42),l(-.87,-.339),l(-.565,-.063),l(-.762,.034),l(-.858,.229),l(-1.343,.084),L(3.57,54.443),l(.059,-.325),l(-.155,-.325),l(-.618,-.487),L(1.958,53.43),l(-.45,.409),l(-.655,1.228),l(-.166,.715),l(-.562,.307), +N(449.401,22.792),l(-1.596,-.014),l(-2.019,-.016),l(-1.739,.063),l(-.764,.061),l(-1.972,-.316),l(.812,-.456),l(.826,-.172),l(.735,-.453),l(1.148,-.588),l(1.354,.691),l(.998,.105),l(1.116,-.088),l(.9,.084),l(.704,.341),l(.865,-.323),l(.53,-.454),l(.868,-.306),l(-.311,.823),l(.086,.32),l(.851,-.001),l(.991,-.495),l(1.061,-.261),l(.803,.128),l(.559,.472),l(.705,.041),l(2.007,-.111),l(1.543,.189),l(.551,.376),l(-.507,.201),l(-2.004,.622),l(-1.623,.38),l(-1.069,.062),l(-.976,.14),l(-1.324,.366),l(-6.271,-.097),l(-.033,-.377),l(1.492,-.26),l(.702,-.677),M(430.027,22.752),l(.068,.697),l(.252,.119),l(1.694,.155),l(.221,-.377),l(.13,-.418),l(.573,-.141),l(.523,-.041),l(.949,.477),l(1.192,.771),l(.798,.235),l(.568,-.218),l(-.222,-.296),l(-.46,-.356),l(-.327,-.477),l(-.04,-.22),l(.91,-.407),l(1.001,.103),l(.485,.18),l(1.278,.018),l(.586,.179),l(-.08,.419),l(-.169,.298),l(.104,.159),l(.549,.118),l(.743,-.338),l(.44,-.1),l(.662,.396),l(.678,.335),l(.785,.156),l(.948,.117),l(1.672,.429),l(.498,.234),l(-1.305,.277),l(-1.981,.218),l(-.696,.293),l(-.731,1.144),l(-.885,.885),l(-1.243,.117),l(-.766,.535),l(-.455,.589),l(-.029,.378),l(-.786,.209),l(-.556,-.018),l(-1.593,-.355),l(-1.883,-.507),l(-1.365,-.568),l(.651,-.364),l(1.565,-.041),l(1.788,-.137),l(.944,-.386),l(-.652,-.249),l(-1.822,.139),l(-1.566,.118),l(-1.694,.042),l(-.502,-.519),l(.959,-.06),l(1.371,-.215),l(2.149,-.314),l(1.547,-.45),l(-2.525,-.405),l(-.881,-.292),l(-.589,.138),l(-1.036,.646),l(-1.069,.293),l(-.562,.059),l(-1.236,-.172),l(-.338,-.174),l(-1.05,-.368),l(-.807,-.233),l(-.698,-.41),l(1.698,-.396),l(-.817,-.571),l(-1.359,.319),l(-.467,-.078),l(-.924,-.751),l(.812,-.36),l(.516,-.021),l(1.075,-.122),l(1.017,.038),l(.577,-.061),l(1.188,-.042),M(425.42,68.82),l(-.148,-.21),l(-.629,.132),l(-.134,-.026),l(-.249,-.237),l(-.239,-.343),l(.188,-.158),l(-.143,-.291),l(-.361,.185),l(-.062,.29),l(.113,.237),l(-.147,.105),l(-.339,.316),l(-.086,.185),l(-.521,.105),l(-.533,-.131),l(-.781,.342),l(.057,.131),l(-.502,.289),l(-.498,.263),l(-1.658,.813),L(418.697,71),l(-.274,.052),l(-.271,0),l(-2.111,.209),l(-.188,-.236),l(-.33,-.131),l(-.183,.209),L(414.976,71),l(.384,-.184),l(-.935,-.236),l(-.794,-.341),l(-.574,-.052),l(-.479,-.578),l(.292,-.368),l(-.126,-.21),l(.34,.026),l(.085,.316),l(.284,-.21),l(.667,.263),l(-.244,-.197),l(.127,-.145),l(.5,-.092),l(-.479,.026),l(-.245,.105),l(-.263,-.184),l(-.111,-.132),l(.579,-.276),l(.455,-.185),l(-.482,.066),l(-.317,-.132),l(.441,-.237),l(.083,-.237),l(-.661,.475),l(-.036,-.264),l(-.265,-.171),l(.005,.211),l(.076,.171),l(-.419,.158),l(-.41,0),l(.014,-.277),l(-.15,.264),l(-.235,-.079),l(-.2,-.448),l(.658,-.449),l(.08,.436),l(.068,-.317),l(.438,.158),l(.211,-.092),l(-.166,-.106),l(.674,-.079),l(.479,-.251),l(-.611,.159),l(-.48,0),l(-.335,-.159),l(.196,-.132),l(.387,-.146),l(.196,-.471),l(-.821,-.014),l(-.546,.094),l(-.406,-.309),l(.368,-.14),l(.643,-.404),l(-.212,-.186),l(-.445,.063),l(-.399,-.062),l(-.211,-.217),l(.284,-.482),l(.619,-.265),l(-.595,-.248),l(-.225,-.374),l(.272,-.188),l(-.089,-.687),l(.106,-.094),l(.594,-.063),l(.392,-.045),l(.455,.044),l(.082,-.11),l(-.255,-.134),l(-.425,-.118),l(-.228,-.17),l(.098,-.188),l(.211,-.125),l(.575,-.064),l(.511,-.346),l(.567,.109),l(.498,-.111),l(.179,-.55),l(.835,.093),l(.668,.125),l(.571,-.252),l(-.989,-.234),l(-.266,-.314),l(.236,-.143),l(1.151,.014),l(.851,-.08),l(.538,.219),l(.06,-.473),l(.477,-.27),l(.297,-.333),l(.78,-.175),l(.438,.189),l(.138,.079),l(.5,-.476),l(.869,-.413),l(.084,-.429),l(.437,-.398),l(1.497,-.735),l(.335,-.192),l(.235,-.048),l(.481,.175),l(.335,-.001),l(.319,-.224),l(-.225,-.223),l(.141,-.128),l(.488,-.224),l(.457,-.305),l(.481,-.483),l(.245,.064),l(.676,-.017),l(-.067,-.612),l(-.471,-.112),l(.434,-.405),l(.511,-.648),l(.841,.063),l(.047,-.341),l(.096,-.228),l(.954,-.116),l(-.396,-.357),l(-.327,-.097),l(-.193,-.146),l(.164,-.245),l(.313,-.246),l(.464,.048),l(.888,-.067),l(-.543,-.522),l(.249,-.082),l(.435,-.034),l(.707,-.263),l(.592,-.067),l(.308,-.208),l(-.358,-.064),l(-.105,-.187),l(.289,-.1),l(.616,-.33),l(.557,.032),l(.351,.098),l(.434,-.264),l(.369,-.031),l(.035,-.176),l(-.421,-.321),l(.627,-.232),l(.146,-.275),l(.336,.01),l(.359,.297),l(.397,.082),l(.526,-.381),l(-.281,-.656),l(.438,.065),l(.698,-.058),l(.207,-.174),l(-.604,-.315),l(.411,-.224),l(.816,-.251),l(.093,-.257),l(.261,-.194),l(.73,-.135),l(.074,.067),l(.274,-.051),l(.102,-.067),l(.492,-.67),l(.521,.25),l(.96,-.153),l(.411,.133),l(.265,.1),l(.646,.065),l(.536,-.419),l(.747,-.84),l(.286,-.085),l(.16,.168),l(-.178,.286),l(-.182,.587),l(.791,-.454),l(.403,-.572),l(.819,-.085),l(.688,-.439),l(.437,.117),l(.665,.353),l(.567,-.643),l(.318,-.272),l(.976,.1),l(1.019,.506),l(.197,-.152),l(.479,-.595),l(.709,-.444),l(.283,-.052),l(.562,.067),l(.338,-.308),l(.469,-.291),l(.619,-.189),l(1.2,-.173),l(.984,.015),l(-1.337,.755),l(-.24,.273),l(-.107,.646),l(.42,.084),l(.691,-.579),l(1.53,-.941),l(.764,-.275),l(.028,.257),l(-.004,.905),l(.704,-.172),l(.438,-.239),l(.855,-.874),l(.959,-.104),l(.586,-.001),l(.216,.154),l(-.383,.257),l(-.335,.257),l(.074,.239),l(-.319,.41),l(.921,.118),l(.221,-.443),l(.902,-.651),l(.421,.017),l(1.682,.561),l(.667,.135),l(.935,.015),l(.649,.237),l(.1,.272),l(-1.216,.393),l(-1.148,.036),l(-2.233,-.047),l(.193,.084),l(.585,.304),l(1.058,.284),l(.383,.302),l(.728,-.052),l(.679,-.102),l(.831,.032),l(.708,.25),l(-.404,.288),l(-.514,.204),l(-.824,.021),l(-.77,.121),l(-1.023,.49),l(-1.013,.672),l(-.689,.303),l(-.001,-.2),l(.096,-.367),l(.874,-.923),l(-.044,-.268),l(-.88,-.348),l(-.672,-.114),l(-1.125,-.431),l(-.556,.003),l(-.555,.07),l(-2.004,.095),l(-.865,.374),l(-.567,.422),l(-.26,.437),l(-.079,.501),l(-.188,.5),l(-1.25,.472),l(-.582,.368),l(-.31,-.148),l(-1.288,-.492),l(-1.657,.225),l(-1.411,-.042),l(-.536,-.13),l(-.861,-.595),l(-.994,-.612),l(-.486,-.082),l(-.355,.103),l(-1.012,.656),l(-.114,-.063),l(-.41,-.031),l(-.865,.038),l(-.281,1.066),l(-.164,.449),l(-.271,.25),l(-.323,-.015),l(-.67,-.129),l(-.972,-.144),l(-1.731,-.389),l(-.168,.183),l(-.021,.663),l(-.083,.199),l(-.318,.299),l(-.695,.004),l(-.871,-.095),l(-.279,-.015),l(-.465,.167),l(-1.484,1.176),l(.05,.213),l(.171,.507),l(-.188,.345),l(-.615,.346),l(-1.325,.919),l(-.687,.442),l(-.981,.021),l(-.121,.244),l(-.06,.971),l(-.32,.598),l(-.383,.469),l(-.574,.499),l(-.495,.545),l(.339,.125),l(.381,.269),l(.252,.587),l(-.17,.176),l(-.44,.177),l(-.733,.036),l(-.932,-.027),l(-.618,.114),l(-.613,.257),l(-.617,.479),l(-.389,.492),l(-.077,.664),l(-.349,1.093),l(.65,.729),l(-.335,1.171),l(.582,.39),l(.715,.186),l(.297,.243),l(-.432,.67),l(-.941,.16),l(.571,.735),l(.26,.427),l(-.249,.346),l(-.029,.532),l(-.769,.384),l(-.414,.013),l(-.117,.423),l(-.506,.224),l(.22,.831),l(-.324,.737),l(-.41,.013),l(-.15,-.342),l(-.293,-.132), +N(464.349,47.431),l(-.024,.283),l(-.258,.465),l(.116,.529),l(.563,.212),l(.872,.194),l(.964,.506),l(.543,.392),l(-.421,.364),l(-1.303,.777),l(-.328,.296),l(1.402,1.394),l(.772,1.195),l(-.196,.356),l(-.44,.535),l(-.187,.403),l(-.029,.37),l(.37,.509),l(1.286,1.395),l(.151,.253),l(-.057,.254),l(-.542,.415),l(-.327,.191),l(.439,.33),l(1.357,.499),l(.703,.265),l(.436,.392),l(.161,.346),l(-.105,.409),l(-.43,.536),l(-.591,.536),l(-1.385,.758),l(-1.983,1.195),l(-1.946,1.145),l(-.174,.285),l(-.935,.206),l(-1.195,.188),l(-.149,.181),l(-.506,-.217),l(-.518,.146),l(-.052,.134),l(-.688,-.07),l(-.193,-.108),l(.057,-.387),l(-.241,.527),l(-.268,.14),l(-.633,.047),l(-.328,.03),l(-.1,.267),l(-.589,-.326),l(-.29,.275),l(-.676,.064),l(-.34,.178),l(-.052,-.127),l(-.504,.108),l(-.504,.108),l(-.211,.266),l(-.311,-.152),l(-.672,.126),l(-.04,-.114),l(-.658,.215),l(-.547,.013),l(-.482,.025),l(-.487,-.253),l(-.223,-.274),l(.273,-.34),l(-.846,.017),l(-.517,.177),l(.065,-.382),l(-.446,.076),l(-.644,-.271),l(-.409,-.061),l(-.415,-.231),l(-.26,-.403),l(-.036,-.714),l(.158,-.374),l(.05,-.436),l(.09,-.234),l(-.347,-.483),l(-.431,-.375),l(.3,-.658),l(-.02,-.392),l(-.305,-.204),l(-.37,-.093),l(.062,-.299),l(.295,-.331),l(.637,-.285),l(.144,-.189),l(-.113,-.331),l(.382,-.143),l(.633,.125),l(.274,.063),l(.483,-.222),l(.303,-.427),l(.104,-.459),l(.207,-.27),l(.301,.316),l(.27,0),l(1.678,-1.114),l(1.142,-.654),l(.835,-.576),l(1.026,-.401),l(.874,.03),l(.06,-.304),l(-.13,-.144),l(-.357,-.16),l(.119,-.371),l(.146,-.387),l(-.329,-.274),l(-1.139,-.095),l(-.836,-.451),l(-.594,-.024),l(-.113,-.234),l(-.327,-.307),l(-.208,-.535),l(.5,-.8),l(-.028,-.392),l(-.405,-.685),l(-.507,-.637),l(.004,-.526),l(.062,-.413),l(-.77,-.558),l(-.508,-.229),l(-1.583,-.207),l(-1.085,-.292),l(-1.286,-.658),l(-.616,-.463),l(-.146,-.033),l(1.012,-.656),l(.355,-.103),l(.486,.082),l(.994,.612),l(.861,.595),l(.536,.13),l(1.411,.042),l(1.657,-.225),l(1.288,.492),l(.31,.148),l(.582,-.368),l(1.25,-.472),l(.188,-.5),l(.079,-.501),l(.26,-.437),l(.567,-.422),l(.865,-.374),l(2.004,-.095),l(.555,-.07),l(.556,-.003),l(1.125,.431),l(.672,.114),l(.88,.348),l(.044,.268),l(-.874,.923),l(-.096,.367),l(.001,.2), +N(453.795,53.873),l(-.23,-.004),l(-.975,.164),l(-.447,.098),l(-.902,-.387),l(-.339,-.178),l(-.347,.114),l(-.641,.374),l(-.542,.599),l(-.309,.146),l(-.658,.018),l(-.545,.355),l(.325,.241),l(.146,.192),l(-.355,.273),l(-.907,.401),l(.317,.271),l(.385,.159),l(.33,.302),l(-.749,.367),l(-.405,.43),l(-.368,.461),l(-1.591,.669),l(-.699,.286),l(-.456,-.205),l(-.326,.08),l(-.538,.539),l(-.646,.144),l(-.663,.348),l(-.217,.284),l(-.191,.142),l(-.746,.033),l(-.221,-.031),l(.151,.535),l(-.484,.425),L(439,61.33),l(.216,.533),l(.243,.25),l(-.244,.955),l(-.498,.063),l(-.217,.204),l(.189,.757),l(-.009,.544),l(.381,.444),l(-.287,.175),l(.926,.082),l(.225,.187),l(.499,-.082),l(.652,.594),l(.428,.314),l(.86,.163),l(.198,.406),l(.32,.139),l(.014,.335),l(-.391,0),l(-.508,.323),l(-.861,.3),l(-.492,.162),l(-.521,-.012),l(-.146,-.115),l(-.805,-.115),l(-.66,-.173),l(-.634,-.069),l(-.137,.104),l(-.446,-.115),l(-.257,.3),l(.819,-.069),l(.497,.265),l(.591,.046),l(.205,.208),l(.481,.069),l(.021,-.127),l(.616,.069),l(.258,-.196),l(.297,.011),l(.481,-.104),l(.226,.081),l(.026,-.15),l(.164,0),l(.214,.15),l(-.029,.081),l(-.722,.023),l(.219,.288),l(-.792,.265),l(-.168,.288),l(-.386,.08),l(-.089,-.092),l(.042,-.161),l(-.014,-.276),l(-.258,.023),l(-.091,.46),l(-.501,.333),l(-.248,.058),l(-.36,-.069),l(-.005,.218),l(-1.418,.035),l(.156,.458),l(.513,.258),l(.066,.609),l(-.109,.33),l(-.281,.051),l(-.308,-.064),l(.038,.429),l(.29,.081),l(-.126,.268),l(.24,.228),l(-.365,.364),l(-.222,.455),l(-.041,.56),l(-.766,1.043),l(-.58,.71),l(-.165,-.062),l(-.442,-.236),l(-.614,.193),l(-1.262,-.089),l(-.106,.311),l(-.252,-.083),l(-.518,.264),l(-.295,.517),l(.356,.336),l(-.376,.374),l(-.48,-.129),l(-.173,-.037),l(-1.158,.269),l(-1.11,-.116),l(-.001,-.142),l(.19,-.078),l(-.062,-.181),l(.281,-.297),l(-.638,-.53),l(-.413,-.479),l(-.22,-.272),l(.529,-.116),l(-.082,-.312),l(.421,.077),l(.147,-.245),l(-.19,-.234),l(-.285,.013),l(-.292,-.377),l(-.527,-.221),l(-.63,-.99),l(-.286,0),l(.011,-.408),l(-.256,-.364),l(-.348,-.298),l(.221,-.484),l(.206,-.341),l(-.418,-.154),l(-.405,.102),l(-.055,-.288),l(-.412,.051),l(-.18,-1.207),l(-.225,-.131),l(.311,-.355),l(.293,.132),l(.15,.342),l(.41,-.013),l(.324,-.737),l(-.22,-.831),l(.506,-.224),l(.117,-.423),l(.414,-.013),l(.769,-.384),l(.029,-.532),l(.249,-.346),l(-.26,-.427),l(-.571,-.735),l(.941,-.16),l(.432,-.67),l(-.297,-.243),l(-.715,-.186),l(-.582,-.39),l(.335,-1.171),l(-.65,-.729),l(.349,-1.093),l(.077,-.664),l(.389,-.492),l(.617,-.479),l(.613,-.257),l(.618,-.114),l(.932,.027),l(.733,-.036),l(.44,-.177),l(.17,-.176),l(-.252,-.587),l(-.381,-.269),l(-.339,-.125),l(.495,-.545),l(.574,-.499),l(.383,-.469),l(.32,-.598),l(.06,-.971),l(.121,-.244),l(.981,-.021),l(.687,-.442),l(1.325,-.919),l(.615,-.346),l(.188,-.345),l(-.171,-.507),l(-.05,-.213),l(1.484,-1.176),l(.465,-.167),l(.279,.015),l(.871,.095),l(.695,-.004),l(.318,-.299),l(.083,-.199),l(.021,-.663),l(.168,-.183),l(1.731,.389),l(.972,.144),l(.67,.129),l(.323,.015),l(.271,-.25),l(.164,-.449),l(.281,-1.066),l(.865,-.038),l(.41,.031),l(.114,.063),l(.146,.033),l(.616,.463),l(1.286,.658),l(1.085,.292),l(1.583,.207),l(.508,.229),l(.77,.558),l(-.062,.413),l(-.004,.526),l(.507,.637),l(.405,.685),l(.028,.392),l(-.5,.8),l(.208,.535),l(.327,.307),l(.113,.234), +N(238.107,361.753),l(.515,-.688),l(.859,0),l(1.202,-.515),l(-.171,-.858),l(-3.091,.344),l(-2.061,.515),l(-1.545,-.344),l(-.515,-.858),l(1.374,-.515),l(1.202,-.172),l(3.091,-.172),l(1.374,-.515),l(-.172,-1.03),l(.859,-.516),l(0,-1.374),l(-1.326,-1.054),l(.982,-.491),l(1.202,-.344),l(1.545,-.172),l(.858,.344),l(.858,.858),l(1.03,1.374),l(1.374,1.202),l(1.03,1.373),l(-.515,2.061),l(-1.545,.516),l(-1.545,.858),l(-3.434,.172),l(-3.435,0),M(172.686,360.379),l(3.091,-.687),l(3.262,0),l(5.495,0),l(2.919,1.202),l(-2.748,.687),l(-3.759,-.337),l(-5.169,-.35),l(-3.091,-.516),M(65.13,371.085),l(1.194,-.265),l(1.393,.133),l(.796,.464),l(-1.99,0),l(-1.393,-.332),M(277.944,379.954),l(.515,-1.202),l(2.404,-1.03),l(2.748,-.172),l(2.061,-.171),l(1.545,-.859),l(.343,-1.545),l(1.374,-.687),l(3.091,-.688),l(4.464,0),l(2.404,0),l(3.434,.688),l(.687,1.889),l(0,1.202),l(-2.061,1.201),l(-11.848,1.03),l(-11.161,.344),M(36.004,376.434),l(1.202,-.858),l(2.061,-.343),l(4.121,.515),l(4.293,1.374),l(-.887,.482),l(-2.719,.204),l(-4.293,-.515),l(-3.777,-.859),M(777.843,385.46),l(3.823,.391),l(.899,.029),l(.322,.234),l(1.202,.294),l(2.329,.088),l(2.126,-.003),l(5.218,.329),l(3.046,.348),l(1.144,-.059),l(.762,.029),l(1.411,.37),l(0,2.175),l(0,2.223),l(0,2.222),l(0,2.223),l(0,2.222),l(0,1.551),l(-.041,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.182,0),l(-.041,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.182,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),H(9.014,0),H(6.792,0),H(4.569,0),H(2.347,0),H(.125,0),l(0,-1.544),l(0,-2.222),l(0,-2.223),l(0,-2.222),l(0,-2.223),l(0,-2.223),l(3.941,.297),l(10.131,0),l(7.898,.516),l(6.868,.172),l(8.586,.858),l(6.353,.515),l(8.757,.172),l(4.808,-.172),l(6.525,-.172),l(2.404,.344),l(3.606,-.858),l(16.312,.344),l(4.638,-.013),l(1.143,-.467),l(-14.366,-.551),l(-9.616,-.688),l(-2.232,0),l(-3.091,-.172),l(-.858,-.171),l(-1.545,-.344),l(-.498,-.455),l(.155,-1.434),l(.687,-.858),l(1.889,-.688),l(-3.263,-.687),l(-2.232,-.344),l(-.953,-.503),l(1.589,-.521),l(-2.891,-.6),l(-3.074,-.208),l(-.104,-.261),l(2.857,-.312),l(2.748,0),l(6.525,.343),l(3.434,0),l(2.576,.344),l(4.636,-1.202),l(2.404,-.687),l(-2.748,-1.03),l(-3.778,-.858),l(-4.391,-.405),l(-2.649,-.625),l(-3.262,-.172),l(-2.919,0),l(-2.919,-.858),l(2.576,-.516),l(1.28,-.342),l(-1.28,-.517),l(-2.919,.516),H(52.66,0),l(-1.717,-.344),L(49.054,373),l(.343,-1.202),l(1.956,-.07),l(1.65,-.273),l(4.98,0),l(4.626,.493),l(3.272,.709),l(1.374,.172),l(4.465,-.858),l(4.089,.243),l(0,-.729),l(.066,-.597),l(-2.255,-.73),l(-2.93,-.075),l(-2.576,-.344),l(2.404,-.687),l(4.121,.171),l(1.717,-.343),l(3.091,-.516),l(3.09,-.343),l(5.667,-.688),l(4.465,-.343),l(3.949,-.516),l(4.464,-.515),l(2.748,.343),l(5.667,0),l(4.464,.258),l(4.121,-.515),l(7.898,.343),l(7.555,-.687),l(3.091,.172),l(1.545,-.688),l(1.545,.516),l(5.323,-.172),l(.121,-.87),l(1.758,-.293),l(1.433,.325),l(.586,.554),l(-.423,.813),l(2.364,.329),l(1.38,-.264),l(-.006,-.938),l(1.438,-.267),l(1.48,.267),l(.212,1.036),l(-1.009,.423),l(.521,.781),l(3.024,-.351),l(1.889,.343),l(3.434,.172),l(2.576,-.687),l(3.778,.086),l(4.868,.33),l(2.344,.013),l(1.449,.109),l(.693,-.53),l(-.611,-.285),l(-2.202,-.122),l(1.305,-.285),l(.041,-.408),l(-.367,-.245),l(-1.386,.123),l(-.693,.04),l(-.856,-.979),l(-2.178,-.337),l(-.676,-.193),l(-.182,-.665),l(4.056,.462),l(3.874,-.245),l(-1.224,-.489),l(-6.035,-.163),l(-.774,-.082),l(-.653,-.489),l(0,-.815),l(2.301,.105),l(.839,.67),l(5.301,-.204),l(7.253,.736),l(2.404,-.172),l(3.262,-.172),l(4.464,.172),l(3.263,.172),l(2.061,-.516),l(.687,-.687),l(1.202,0),l(.344,1.03),l(2.576,.343),l(2.404,-.343),l(.858,.515),l(3.435,.688),l(3.777,.343),l(2.061,.172),l(1.03,-.515),l(.687,-1.202),l(2.747,-.172),l(1.03,.515),l(1.717,.688),l(3.091,-.172),l(3.434,.258),l(4.121,-.344),l(4.979,-.516),l(5.495,-.858),l(3.091,-.515),l(1.202,-.688),l(0,-1.373),l(-1.374,-1.202),l(-.859,-1.545),l(-1.202,-.688),l(-.344,-1.03),l(1.202,-1.03),l(1.717,-.343),l(.858,-1.202),l(-.343,-.858),l(-.172,-1.03),l(-1.202,-.516),l(.344,-1.545),l(1.889,-.172),l(2.404,-1.374),l(1.545,-.515),l(.859,-.859),l(1.03,-.687),l(2.919,-1.202),l(3.606,-.515),l(2.404,-1.202),l(2.404,-.172),l(2.232,-1.03),l(1.545,-.343),l(.343,1.03),l(-1.374,.515),l(-1.03,.344),l(-1.202,.515),l(-.858,0),l(-1.202,0),l(-2.919,1.202),l(-1.03,.687),l(-1.717,1.374),l(-.172,1.202),l(-.687,.687),l(-1.374,-.344),l(-1.03,0),l(-1.202,.516),l(-1.202,.687),l(-1.03,.688),l(-.687,1.201),l(.515,.688),l(.687,.687),l(1.374,.344),l(1.545,0),l(.858,.515),l(.687,1.202),l(1.545,1.546),l(.687,.858),l(1.03,.687),l(.687,1.374),l(.858,1.373),l(.344,1.546),l(-.344,.858),l(-.858,1.717),l(-2.919,1.889),l(-1.202,.172),l(-1.03,.858),l(-1.717,1.03),l(-3.263,.344),l(-4.979,.858),l(-2.404,.344),l(-2.919,.687),l(-7.377,-.141),l(-4.556,-.316),l(-.773,-.401),l(-1.717,-.344),l(-1.717,-.343),l(-1.374,0),l(-.859,.515),l(.515,.858),l(2.061,.688),l(4.121,1.202),l(4.995,.04),l(1.202,.759),l(-3.278,.574),l(-5.667,-.343),l(-4.979,-.516),l(-3.097,-.285),l(-2.151,.253),l(.823,.696),l(1.164,.538),l(3.262,.172),l(2.232,0),l(1.374,.343),l(-.249,.402),l(-.782,.113),l(-2.232,.515),l(-5.151,-.171),l(-1.374,-.172),l(-2.232,-1.202),l(-2.404,0),l(.128,.917),l(2.62,1.144),l(1.03,.172),l(1.202,-.172),l(1.374,.344),l(2.404,0),l(4.98,-.516),l(3.09,.687),l(.385,.431),l(-.041,.6),l(-2.061,.172),l(-3.263,.172),l(-2.608,-.185),l(3.811,.871),l(3.656,-.238),l(1.324,.41),l(2.576,.687),l(6.869,.859),l(8.585,.858),l(10.646,1.373),l(6.525,.516),l(2.061,.858),l(.687,1.03),l(3.091,-.344),l(5.323,-1.545),l(6.525,-.687),l(2.455,-.066),l(6.474,-.105),l(9.788,-.344),l(1.889,.344),l(2.576,-1.202),l(8.414,-1.03),l(11.333,-.172),l(8.929,-.858),l(1.202,-.858),l(-1.202,-.516),l(-.271,-1.07),l(-1.184,-.338),l(-5.071,.035),l(-2.232,.172),l(-4.808,-.344),l(-3.091,0),l(0,-1.202),l(3.263,-1.545),l(3.949,-1.202),l(2.404,-.172),l(4.121,-1.03),l(9.444,-1.202),l(5.323,-.858),l(6.525,0),l(4.979,-.516),l(2.747,-2.061),l(6.039,-1.541),l(-1.23,-.52),l(-2.576,.516),l(-2.061,-.344),l(1.545,-1.03),l(1.545,-.343),l(2.48,-.249),l(.696,-.742),l(3.85,-.742),l(1.577,-.418),l(.603,-.557),l(-1.716,-.881),l(-.093,-.604),l(1.252,-.231),l(.464,.742),l(1.017,-.097),l(2.061,-.858),l(1.03,-.343),l(.858,.171),l(1.203,1.544),l(2.403,-.342),l(.242,-.91),l(.96,-.807),l(1.889,-.516),l(1.374,.516),l(-1.162,.574),l(-.139,.604),l(3.189,-.319),l(4.808,.258),l(3.263,-.172),l(1.03,.858),l(1.545,-.344),l(1.717,-.515),l(5.839,-.858),l(7.212,-1.03),l(4.292,-.858),l(2.061,0),l(2.061,1.373),l(1.718,.344),l(1.889,-.344),l(1.545,-.858),l(7.556,-.344),l(3.434,-.171),l(4.293,.171),l(6.697,.945),l(2.575,0),l(4.293,-.516),l(6.01,-.687),l(5.151,-.688),l(2.404,-.515),l(2.231,-.344),l(.615,-.959),l(1.148,-.835),l(1.671,-.095),l(.938,.965),l(1.294,.409),l(1.732,1.052),l(1.009,.139),l(1.009,-.661),l(1.322,-.174),l(.209,.522),l(-.835,.312),l(.661,.244),l(.8,.278),l(.383,-.383),l(.313,-.383),l(.312,.209),l(-.174,.348),l(0,.521),l(.592,-.174),l(1.913,-.557),l(.418,-1.704),l(5.102,-1.137),l(1.374,-.687),l(3.605,-.172),l(1.363,-.646),l(2.758,-.126),l(.21,-.27),l(-.165,-.297),l(.692,-.23),l(1.221,.165),l(.197,.593),l(.66,.231),l(2.165,-.536),l(1.265,-.223),l(-.726,-.297),l(-.561,-.264),l(.099,-.362),l(1.451,-.1),l(1.562,.215),l(.647,.28),l(.692,-.132),l(-.066,-.33),l(-.527,-.33),l(0,-.561),l(.297,-.23),l(.846,-.242),l(4.292,-.858),l(2.92,-.172),l(3.058,.115),l(2.296,1.076),l(1.316,.023),l(.741,.144),l(.023,.383),l(-.908,.096),l(-.168,.454),l(1.723,.216),l(4.892,.646),l(5.571,.453),l(1.546,.172),l(1.717,-.172),l(7.556,.688),l(5.323,0),l(.687,.687),l(.2,1.075),l(-.73,1.232),l(-.672,.439),l(-.425,1.113),l(-.73,.319),l(-.905,-.402),l(-.83,.402),l(-.73,.959),l(1.507,.457),l(.594,.045),l(.959,-.593),l(.411,.365),l(-.867,1.05),l(-1.215,.062),l(-1.717,1.374),l(0,.858),l(1.889,.688),l(2.919,0),l(1.718,-.859),l(1.889,-1.545),l(1.717,-1.717),l(1.374,-.688),l(4.121,-1.03),l(2.231,-.687),l(3.263,-.344),l(2.061,-1.03),l(1.03,-1.03),l(3.435,-1.03),l(2.403,-.687),l(2.061,-.687),l(2.061,-.172),l(6.182,-.687),l(3.778,.171),l(1.204,-.542),l(.169,-.659),l(.54,-.759),l(.49,-.101),l(.471,.776),l(.305,.775),l(4.892,-.35),l(5.838,0),l(4.979,-.172),l(3.091,.344),l(2.112,-.214),l(1.328,.085),l(1.018,.594),l(1.188,-.764),l(2.714,-1.046),l(1.866,-.226),l(.664,-.028),l(.594,-.028),l(.777,-.057),l(1.512,.311),l(1.166,-.172),l(3.606,.687),l(3.777,.344),l(1.03,0),l(1.064,.573),l(.745,.088),l(2.149,-.088),l(1.271,-.263),l(1.315,-.438),l(-.192,-.216),l(.28,-.53),l(1.447,-.131),l(.921,-.088),l(.786,.062),l(2.195,-.501),l(2.097,.501),l(.688,.687),l(.373,.435),l(1.842,-.131),l(.921,-.044),l(.985,.255),l(1.889,.688),l(2.919,.515),l(2.919,-.343),l(4.121,-.258),l(2.232,-.344),l(2.404,0),l(3.521,.315),l(.702,-.755),l(2.158,-.162),l(.863,1.133),l(4.909,.323),l(.917,-1.133),l(1.889,-.593),l(5.988,.013),l(.756,-.283),l(1.996,.108),l(-.432,-1.403),l(.054,-.809),l(1.232,-.36),l(.872,1.277),l(-.647,1.079),l(.805,.219),l(2.81,.482),l(5.262,.376),l(5.494,.344),l(2.278,.583),l(1.283,.14),l(1.396,-.167),l(2.204,.446),l(1.961,-.167),l(.719,.278),l(-.435,.431),l(-.151,.351),l(.293,.123),l(2.081,.331),l(1.078,.484),l(2.706,-.134),l(.377,.595),l(1.038,.227),l(4.808,.515),l(-.123,.536),l(.567,.236),l(2.695,-.095),l(3.214,.181),l(-.329,-.984),l(.71,-.095),l(.804,.426),l(.331,.709),l(1.135,.284),l(2.672,.519),l(2.576,-.343),l(4.017,.999),l(1.626,.495),l(1.672,.871),l(1.626,.023),l(.504,.187),l(.532,-.021),l(.754,-.047),l(.777,.047),l(.896,.589),l(.541,.118),l(.542,.07),l(.142,-.259),l(.471,0),l(1.484,-.048),l(1.416,.237),l(5.951,.535),l(.729,.516),l(1.733,.323),l(2.979,.944),l(.43,-.335),l(.551,.191),l(.454,.67),l(-.741,.215),l(-1.124,.167),l(-.216,.359),l(.168,.263),l(.55,-.048),l(-.024,.67),l(-.43,-.048),l(-.096,.287),l(-.312,.071),l(-.598,.622),l(-.526,.12),l(-.55,.287),l(-.168,.669),l(-1.603,.096),l(-1.339,-.239),l(-1.794,.359),l(-2.153,.425),l(-2.629,.764),l(1.271,1.103),l(-1.907,.212),l(-1.23,-.255),l(-.763,.212),l(-.043,.637),l(-2.374,.169),l(.136,.514),l(.924,.632),l(-.127,.763),l(-.382,.085),l(-.466,.467),l(.551,.466),l(.085,.764),l(-.764,.424),l(.637,.254),l(.763,0),l(.764,.255),l(.339,.509),l(.17,.721),l(1.284,-.187),l(.836,.907),l(2.035,.297),l(.339,.339),l(2.672,.552),l(-4.113,0),l(-2.799,.138),l(-2.332,.541),l(-1.823,-.085),l(-.806,.212),l(-1.611,.339),l(-1.326,-.32),l(-.546,.426),l(1.116,.529),l(-.503,.447),l(-.669,.195),l(-1.117,.753),l(-2.623,.642),l(.475,.391),l(2.205,-.111),l(.53,0),l(.809,.307),l(.168,.363),l(.499,.18),l(.422,.183),l(.111,.894),l(.209,.502),l(3.195,.279),l(2.874,.948),l(3.662,.801),l(5.151,1.202),l(1.456,.062),l(1.015,.17),l(-.146,.234),l(-1.67,.264),l(-.47,.264),l(1.173,.088),l(2.198,-.293),l(1.988,.166), +E(0,0) +}; + +#undef N +#undef M +#undef L +#undef l +#undef E diff --git a/local/recipes/libs/cairo/source/perf/micro/zrusin-another.h b/local/recipes/libs/cairo/source/perf/micro/zrusin-another.h new file mode 100644 index 0000000000..f6e72aed4c --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/zrusin-another.h @@ -0,0 +1,668 @@ +/* The data in this file was created by Zack Rusin and downloaded from: + + http://ktown.kde.org/~zrusin/examples/cairorender.tar.bz2 + + It is included in the cairo performance test suite by his + permission, (given in email to Carl Worth on 2006-10-23) +*/ +point_t zrusin_another[] = { +{107.893088734820,103.841923410053}, {106.908713734820,104.920048410053}, +{106.605078419636,105.201721390261}, {102.286079757931,107.612435141518}, +{95.848592904540,109.855345077872}, {95.820873452616,109.863161445001}, +{90.517184462013,111.170008329713}, {87.125000000000,111.625000000000}, +{82.393245921775,111.316572641568}, {77.855183975790,110.402282596173}, +{73.577390672683,108.898617908665}, {69.626442523093,106.822066623894}, +{69.373711344187,106.641023992165}, {57.717461344187,97.141023992165}, +{60.861283165549,97.153157587308}, {52.861026127481,102.679312400770}, +{43.297199733607,107.707604120505}, {38.061787185467,109.824994465236}, +{32.824736230810,111.354170438973}, {27.636335844151,112.281599723349}, +{22.546875000000,112.593750000000}, {19.478437557032,111.949288129016}, +{16.158848619890,110.212087077375}, {13.224557514711,107.109984243309}, +{12.401022392395,105.215121771751}, {12.109375000000,103.234375000000}, +{12.857968117079,98.340329228563}, {15.050447208669,93.495802782054}, +{18.606861885297,88.792446786896}, {23.447261757492,84.321912369510}, +{23.462751811761,84.309735859104}, {29.835792474114,80.170241641945}, +{36.826339837257,77.183700966953}, {44.355342734713,75.374150023260}, +{52.343750000000,74.765625000000}, {54.172214431835,74.493658379815}, +{55.005326273741,73.240819884599}, {54.891695624471,73.637732784350}, +{55.835419478567,69.288398667240}, {56.941029555972,65.553969608663}, +{57.993585771605,68.524034756036}, {53.681468264740,66.410473849442}, +{48.062136369578,64.586219029579}, {42.258612309644,63.317877950046}, +{37.437500000000,62.906250000000}, {32.573685233275,63.044800246717}, +{26.989159126193,63.632907811096}, {20.752015377001,64.279295952574}, +{16.562500000000,64.484375000000}, {16.408072340842,64.479600861137}, +{11.611197340842,64.182725861137}, {11.453516511116,64.167941148499}, +{6.725716011250,62.845442977500}, {4.607850691978,60.769517471259}, +{3.781250000000,57.859375000000}, {4.373461857036,55.042556375256}, +{5.951936001924,52.702230099626}, {6.143541831166,52.540844514692}, +{9.884650718045,51.301737345381}, {10.233131146503,51.254965794601}, +{14.936256146503,50.958090794601}, {15.093750000000,50.953125000000}, +{19.896489079886,51.056672881330}, {25.533897731570,51.448761318515}, +{25.296875000000,51.437500000000}, {30.909892241200,52.067729129895}, +{30.484375000000,52.031250000000}, {39.960841830525,52.410121686268}, +{48.752300459876,53.538988916016}, {48.757228534847,53.539874692156}, +{54.123571896675,54.731960341587}, {58.970980406852,56.270657465230}, +{63.248918806945,58.141504425356}, {66.906851838519,60.330039584234}, +{66.896289983187,60.322652661852}, {70.654761046586,63.581911162241}, +{73.423041490057,67.400928399521}, {75.133561184297,71.670457102504}, +{75.718750000000,76.281250000000}, {74.721151272876,79.892293861068}, +{72.068677652167,83.513297493231}, {70.325052633091,85.868624092784}, +{69.828125000000,88.250000000000}, {70.186304443223,90.552747673203}, +{71.326302526678,92.735137555366}, {73.346308881046,94.894011912335}, +{76.344513137007,97.126213009954}, {79.989627194854,99.164217236556}, +{83.789048154438,100.596188457783}, {87.811323321056,101.441306202608}, +{92.125000000000,101.718750000000}, {97.462586180660,101.070932456387}, +{97.557831952069,101.055648080491}, {103.015964519671,99.851433056816}, +{103.984375000000,99.656250000000}, {106.046875000000,99.656250000000}, +{107.893088734820,103.841923410053}, {106.046875000000,104.656250000000}, +{103.984375000000,104.656250000000}, {104.952785480329,104.461066943184}, +{98.254668047931,106.006851919509}, {98.349913819340,105.991567543613}, +{92.125000000000,106.718750000000}, {87.170121991444,106.371193797392}, +{82.386733095562,105.341311542217}, {77.843380617646,103.648282763444}, +{73.608611862993,101.311286990046}, {69.914433306454,98.422394337665}, +{67.154166223322,95.217987444634}, {65.426000244277,91.794908576797}, +{64.828125000000,88.250000000000}, {65.079958470471,86.099459712769}, +{65.803853616909,83.955594657216}, {68.478197347833,80.033577506769}, +{70.243692477124,77.869424888932}, {70.718750000000,76.281250000000}, +{70.335188815703,72.767042897496}, {69.139458509943,69.692821600479}, +{67.063988953414,66.949338837759}, {64.041210016813,64.427347338148}, +{64.030648161481,64.419960415766}, {57.122769593148,60.885592534770}, +{47.867771465153,58.460125307844}, {47.872699540124,58.461011083984}, +{39.531345669475,57.386753313732}, {30.484375000000,57.031250000000}, +{30.058857758800,56.994770870105}, {25.296875000000,56.437500000000}, +{25.059852268430,56.426238681485}, {19.697260920114,56.052702118670}, +{15.093750000000,55.953125000000}, {15.251243853497,55.948159205399}, +{10.548118853497,56.245034205399}, {10.896599281955,56.198262654619}, +{9.168958168834,56.521655485308}, {9.360563998076,56.360269900374}, +{8.781250000000,57.859375000000}, {8.758601803360,58.189255218076}, +{8.735899308021,58.292982528741}, {8.961783988750,58.373307022500}, +{12.077733488884,59.207058851501}, {11.920052659158,59.192274138863}, +{16.716927659158,59.489149138863}, {16.562500000000,59.484375000000}, +{20.310484622999,59.298829047426}, {26.432715873807,58.663967188904}, +{32.129439766725,58.064574753283}, {37.437500000000,57.906250000000}, +{42.956231440356,58.377434549954}, {49.359738630422,59.757530970421}, +{55.603687985260,61.808276150558}, {60.600164228395,64.257215243964}, +{61.652720444028,67.227280391337}, {60.695830521433,70.461601332760}, +{59.795804375529,74.612267215650}, {59.682173726259,75.009180115401}, +{58.534870256371,76.967235761415}, {56.827785568165,78.467279120185}, +{54.713289027441,79.427384197713}, {52.343750000000,79.765625000000}, +{45.078251015287,80.284053101740}, {38.408035162743,81.855361533047}, +{32.254051275886,84.503586483055}, {26.537248188239,88.252764140896}, +{26.552738242508,88.240587630490}, {22.301341239703,92.064975088104}, +{19.363615291331,95.777634717946}, {17.659610007921,99.470217646437}, +{17.109375000000,103.234375000000}, {17.462942485289,104.745484506691}, +{18.934901380110,106.053537922625}, {21.052812442968,107.257743120984}, +{22.546875000000,107.593750000000}, {27.127336030849,107.323869026651}, +{31.729951269190,106.505204561027}, {36.405009689533,105.124224284764}, +{41.202800266393,103.167395879495}, {50.256161372519,98.422250099230}, +{57.732466834451,93.253092412692}, {60.876288655813,93.265226007835}, +{72.532538655813,102.765226007835}, {72.279807476907,102.584183376106}, +{75.647218702317,104.376772716335}, {79.199503524210,105.636779903827}, +{83.003238453225,106.380692983432}, {87.125000000000,106.625000000000}, +{94.491626547384,105.043088554999}, {94.463907095460,105.050904922128}, +{100.135795242069,103.121939858482}, {103.519921580364,101.267028609739}, +{103.216286265180,101.548701589947}, {104.200661265180,100.470576589947}, +{106.046875000000,104.656250000000}, {107.893088734820,103.841923410053}, +{55.872490683787,89.763134548637}, {54.997490683787,85.841259548637}, +{55.036476188094,85.993355189713}, {52.343750000000,85.750000000000}, +{46.702141892082,86.180801752650}, {41.285068752391,87.490050907175}, +{36.021375201732,89.703013308437}, {30.839905860908,92.844954801298}, +{30.840393168266,92.844613599752}, {24.841774707763,97.553563991314}, +{23.093750000000,100.109375000000}, {23.668337709691,101.518994849695}, +{23.371174656526,101.224323797050}, {23.620948599883,101.397798979282}, +{24.023420115060,101.552272092059}, {25.484375000000,101.718750000000}, +{29.298199671143,101.348354407082}, {33.545396502623,100.218839979757}, +{38.283160693967,98.302715245167}, {43.568687444697,95.572488730454}, +{43.462444284634,95.635929361188}, {56.978069284634,87.104679361188}, +{55.872490683787,89.763134548637}, {107.893088734820,103.841923410053}, +{59.646930715366,91.332820638812}, {46.131305715366,99.864070638812}, +{46.025062555303,99.927511269546}, {40.294964306033,102.857441004833}, +{34.923353497377,104.984285020243}, {29.967425328857,106.280551842918}, +{25.484375000000,106.718750000000}, {22.429704884940,106.291477907941}, +{20.160075343474,105.056926202950}, {19.862912290309,104.762255150305}, +{18.581942192719,102.559691058502}, {18.093750000000,100.109375000000}, +{18.781885833597,97.630167914546}, {20.751975292237,94.868311008686}, +{27.972106831734,88.749136400248}, {27.972594139092,88.748795198702}, +{33.744249798268,85.287221066563}, {39.777431247609,82.783386592825}, +{46.000983107918,81.262557622350}, {52.343750000000,80.750000000000}, +{54.881053553302,80.995299290410}, {57.121823397686,81.724997675285}, +{58.847249996203,82.929795925088}, {59.838523811906,84.600394810287}, +{59.877509316213,84.752490451363}, {60.752509316213,88.674365451363}, +{59.646930715366,91.332820638812}, {107.893088734820,103.841923410053}, +{155.484375000000,101.859375000000}, {154.564834615754,105.515207938449}, +{152.115670325806,108.366761454651}, {148.955163295626,109.891294781728}, +{145.437500000000,110.437500000000}, {142.960397099416,109.918703000637}, +{140.390467597390,108.438024620128}, {137.806753458193,106.109033784838}, +{135.288296646094,103.045299421136}, {135.165845369106,102.859481271949}, +{127.322095369106,89.718856271949}, {127.315939322101,89.708486304067}, +{123.037165252408,83.240466071649}, {119.422893480005,79.457711309224}, +{123.333764624626,78.181432151290}, {119.923748586047,88.267600564284}, +{116.288451493331,96.371224650234}, {116.310270123205,96.328970526240}, +{111.013619195867,105.085481651574}, {104.498474377631,112.833853093888}, +{102.718750000000,113.578125000000}, {98.109375000000,113.578125000000}, +{95.790533815800,112.012456612681}, {92.715536961613,101.759617602767}, +{90.624767168816,88.808240839597}, {90.625938562396,88.818553777181}, +{88.018863793847,68.357428789163}, {88.022375537533,68.374401202625}, +{86.904794319936,64.234191072834}, {85.466909526601,60.964474099786}, +{83.670654326939,58.467433589062}, {81.477961890361,56.645252846242}, +{80.463845731714,53.674615230649}, {82.823220731714,47.205865230649}, +{82.883587418943,47.055653464335}, {83.966380643129,44.754922491868}, +{85.291281927099,42.535861182972}, {88.514402164445,41.595109434025}, +{91.785870247761,43.817111177877}, {94.599270325866,47.029404143594}, +{96.906293571887,51.130222797294}, {98.658631158949,56.017801605095}, +{98.664492355983,56.039251079522}, {100.006630671722,63.228131068770}, +{101.762541190731,76.272848032637}, {101.765778670251,76.300425005941}, +{103.467098832178,87.353480411923}, {105.697048617918,94.795754781373}, +{102.319980907406,93.545204629259}, {104.354680083199,92.248641487426}, +{106.296883956259,90.334282557687}, {110.081726403105,84.371439341729}, +{110.069085073875,84.396782220394}, {112.413266990492,78.560599894318}, +{114.080111889746,71.934817013191}, {115.075734612596,64.464258680566}, +{115.406250000000,56.093750000000}, {117.906250000000,53.593750000000}, +{122.515625000000,53.593750000000}, {124.596624760838,54.708311442938}, +{155.065374760838,100.473936442938}, {155.484375000000,101.859375000000}, +{107.893088734820,103.841923410053}, {150.903375239162,103.244813557062}, +{120.434625239162,57.479188557062}, {122.515625000000,58.593750000000}, +{117.906250000000,58.593750000000}, {120.406250000000,56.093750000000}, +{120.037546637404,64.922460069434}, {118.935513110254,72.987057986809}, +{117.106264259508,80.232368855682}, {114.555914926125,86.603217779606}, +{114.543273596895,86.628560658271}, {112.308927321184,90.508291033149}, +{109.859366043741,93.751654942313}, {107.239069916801,96.288467887574}, +{104.492519092594,98.048545370741}, {101.115451382082,96.797995218627}, +{98.626651167822,88.552769588077}, {96.796721329749,76.855824994059}, +{96.799958809269,76.883401967363}, {95.087119328278,64.107806431230}, +{93.835507644017,57.335748920478}, {93.841368841051,57.357198394905}, +{92.427690803113,53.221339702706}, {90.736667174134,50.033095856406}, +{88.719989127239,47.690701322123}, {86.329347835555,46.092390565975}, +{89.552468072901,45.151638817028}, {88.346119356871,47.166952508132}, +{87.460162581057,49.069346535665}, {87.520529268286,48.919134769351}, +{85.161154268286,55.387884769351}, {84.147038109639,52.417247153758}, +{87.106689423061,54.909519535937}, {89.579965473399,58.293338400214}, +{91.528799430064,62.470887052166}, {92.915124462467,67.344348797375}, +{92.918636206153,67.361321210837}, {95.592811437604,88.243946222819}, +{95.593982831184,88.254259160403}, {97.565713038387,100.591944897233}, +{100.428216184200,110.143793387319}, {98.109375000000,108.578125000000}, +{102.718750000000,108.578125000000}, {100.939025622369,109.322396906112}, +{106.962943304133,102.180143348427}, {111.845979876795,94.077279473760}, +{111.867798506669,94.035025349766}, {115.287188913953,86.412086935716}, +{118.541235375374,76.756067848710}, {122.452106519995,75.479788690776}, +{126.837834747592,80.025158928351}, {131.621560677899,87.166513695933}, +{131.615404630894,87.156143728051}, {139.459154630894,100.296768728051}, +{139.336703353906,100.110950578864}, {142.906407402610,104.257287879872}, +{145.437500000000,105.437500000000}, {147.478430454374,105.175111468272}, +{149.243704674194,104.273863545349}, {150.251571634246,103.277760811551}, +{150.484375000000,101.859375000000}, {150.903375239162,103.244813557062}, +{107.893088734820,103.841923410053}, {231.343750000000,91.875000000000}, +{230.760913847107,95.964970754466}, {229.068047862611,99.735912943733}, +{226.348615757792,103.075786207286}, {222.686081243924,105.872550184609}, +{222.648873373705,105.894655312846}, {215.093162016193,109.098726800095}, +{205.138412990776,111.389009633945}, {205.099511514392,111.395066324151}, +{196.531910121565,112.292873746127}, {187.093750000000,112.593750000000}, +{180.736641615184,112.156201510495}, {174.578395035074,110.855968371846}, +{168.685194057574,108.711669078852}, {163.123222480588,105.741922126310}, +{163.102786019362,105.728945017668}, {158.065383006950,101.833715472335}, +{154.350564084671,97.489870440862}, {152.052565874896,92.798170193375}, +{151.265625000000,87.859375000000}, {151.531470468770,85.013668760581}, +{152.287360086651,82.060400295498}, {152.321821893194,81.964698849566}, +{155.704155919825,73.828381186220}, {158.270837388345,69.249451319292}, +{158.258242073026,69.265568807584}, {162.161895999987,65.281962610977}, +{167.278829839386,61.794937132641}, {173.532669176810,58.834467171163}, +{180.847039597849,56.430527525129}, {179.144548452656,58.005986305326}, +{180.222673452656,54.974736305326}, {180.222279555972,54.975844608663}, +{182.650011718926,50.400876966176}, {185.678714551395,49.466466465483}, +{192.833058049629,52.996232862321}, {201.831199616962,58.692914409530}, +{211.602112156950,65.789874557518}, {220.243790039283,73.085988470431}, +{220.250361498213,73.092084369790}, {227.553434625305,81.089470457139}, +{229.783449199558,84.667905408782}, {230.987849850362,87.897461316292}, +{231.037603485703,88.222391630780}, {231.334478485703,91.659891630780}, +{231.343750000000,91.875000000000}, {107.893088734820,103.841923410053}, +{226.353021514297,92.090108369220}, {226.056146514297,88.652608369220}, +{226.105900149638,88.977538683708}, {225.181394550443,86.544985216218}, +{223.368440374695,83.730842042861}, {216.843388501787,76.751665630210}, +{216.849959960717,76.757761529569}, {208.538512843050,69.741375442482}, +{199.012550383038,62.822710590470}, {190.370066950371,57.347517137679}, +{183.790035448605,54.096033534517}, {186.818738281074,53.161623033824}, +{184.933970444028,56.649155391337}, {184.933576547344,56.650263694674}, +{183.855451547344,59.681513694674}, {182.152960402151,61.256972474871}, +{175.418502698190,63.429204703837}, {169.900857660614,65.978500367359}, +{165.523650875013,68.934834264023}, {162.210507926974,72.328181192416}, +{162.197912611655,72.344298680708}, {160.116156580175,76.155993813780}, +{156.990678106806,83.754051150434}, {157.025139913349,83.658349704502}, +{156.265625000000,87.859375000000}, {156.814621625104,91.570970431625}, +{158.524435915329,95.017942059138}, {161.489304493050,98.301050152665}, +{165.803463980638,101.521054982332}, {165.783027519412,101.508077873690}, +{170.773790317426,104.198487171148}, {175.945042464926,106.097156628154}, +{181.362967759816,107.222704739505}, {187.093750000000,107.593750000000}, +{196.179027378435,107.308688753873}, {204.369238485608,106.448683675849}, +{204.330337009224,106.454740366055}, {213.484962983807,104.385648199905}, +{220.132376626295,101.574094687154}, {220.095168756076,101.596199815391}, +{222.954118617208,99.523823167714}, {224.892889637389,97.287524556267}, +{225.994945527893,94.775263620534}, {226.343750000000,91.875000000000}, +{226.353021514297,92.090108369220}, {107.893088734820,103.841923410053}, +{219.781250000000,95.890625000000}, {219.378166433508,93.853798730227}, +{218.111752188172,91.489941446073}, {212.645950385807,85.475693519170}, +{212.685981945341,85.511936058310}, {206.545320157918,80.643069684901}, +{198.180220478697,74.962876659750}, {198.191932106006,74.970352872652}, +{191.582535336704,71.037624006410}, {191.504903114611,70.993386859602}, +{190.358726480976,70.329891393482}, {194.093750000000,68.156250000000}, +{193.486799914207,72.326466575586}, {191.750022838432,75.648693620488}, +{191.727672642897,75.674671879974}, {189.796209835616,77.308949639626}, +{187.307360975056,78.497446987452}, {184.374093537693,79.223076311545}, +{181.109375000000,79.468750000000}, {178.539517280969,79.274893727068}, +{176.586499975916,78.676142180991}, {173.086052480141,74.877460550577}, +{176.026873378540,75.790765650642}, {173.637934677835,76.966105971818}, +{171.454775584042,78.628861257931}, {167.479150931130,83.659399177979}, +{167.492959438562,83.636441477986}, {164.707555748674,89.579684053440}, +{164.890625000000,88.640625000000}, {165.429801946489,91.718738201013}, +{167.140367049889,94.413281660069}, {170.161871706101,96.828214751252}, +{174.633867311024,99.067496848641}, {174.595883286589,99.052025896332}, +{183.311717611230,101.570655775842}, {188.036065935963,102.270678900324}, +{192.781250000000,102.500000000000}, {204.722829878151,102.082467436594}, +{212.458857303872,100.833616072622}, {214.905535432122,99.897801735668}, +{216.940228691241,98.604487224303}, {220.087216056537,94.692203098109}, +{219.781250000000,95.890625000000}, {107.893088734820,103.841923410053}, +{224.475283943463,97.089046901891}, {222.495392805158,99.992428606532}, +{220.012896308759,102.426762775697}, {217.106183317878,104.328760764332}, +{213.853642696128,105.635133927378}, {205.324045121849,107.034720063406}, +{192.781250000000,107.500000000000}, {187.549871564037,107.241039849676}, +{182.344532388770,106.476219224158}, {172.747866713411,103.697974103668}, +{172.709882688976,103.682503151359}, {167.310784543899,100.802644623748}, +{163.281507950111,97.266405839931}, {160.761604303511,93.177746173987}, +{160.111277146626,90.958745814619}, {159.890625000000,88.640625000000}, +{160.073694251326,87.701565946560}, {163.194540561438,81.082308522014}, +{163.208349068870,81.059350822021}, {165.573405849355,77.703241627766}, +{168.240536915958,74.886763742069}, {171.153080947165,72.670612778182}, +{174.254376621460,71.115484349358}, {177.195197519859,72.028789449423}, +{178.991625024084,74.292607819009}, {181.109375000000,74.468750000000}, +{185.450451524944,73.971303012548}, {187.959827357103,72.387828120026}, +{187.937477161568,72.413806379512}, {188.825700085793,70.736033424413}, +{189.093750000000,68.156250000000}, {192.828773519024,65.982608606518}, +{194.057596885389,66.694113140398}, {193.979964663296,66.649875993590}, +{200.870567893994,70.748397127348}, {200.882279521303,70.755873340250}, +{209.532804842082,76.638180315099}, {216.001518054659,81.769313941690}, +{216.041549614192,81.805556480830}, {219.736550554799,85.597619431325}, +{222.481997811828,89.260058553927}, {224.192146066492,92.716513769773}, +{224.781250000000,95.890625000000}, {224.475283943463,97.089046901891}, +{107.893088734820,103.841923410053}, {274.375000000000,74.921875000000}, +{274.375000000000,76.000000000000}, {273.941340954992,77.877573018672}, +{272.878932097861,79.515803527315}, {273.201644884750,79.109789854043}, +{272.240878131027,80.634530144823}, {272.178064435979,80.731878545843}, +{270.366672394243,82.164949472839}, {268.046875000000,82.703125000000}, +{266.183148747233,82.484226579792}, {265.676843902484,82.347511014208}, +{261.919943241226,81.056638412991}, {261.845529920936,81.035610157726}, +{257.771892015055,80.000491652766}, {254.812500000000,79.671875000000}, +{253.064641952966,80.017766952966}, {253.029646790629,80.052082662255}, +{253.183319188544,79.921363850038}, {253.251518993920,79.984611568497}, +{253.185946392942,81.106825858762}, {253.000000000000,86.578125000000}, +{253.496255380785,102.128843883245}, {253.498940253820,102.192840332413}, +{254.068093288267,110.651263719025}, {251.578125000000,113.375000000000}, +{246.875000000000,113.375000000000}, {246.340326851360,113.317155732979}, +{244.239667843345,112.409341061474}, {241.449240399376,110.489665586259}, +{233.966932708158,103.861287459859}, {233.964253154933,103.858697290509}, +{230.739570245917,99.429986748935}, {227.863465886694,92.900734302334}, +{227.865566738278,92.906614054351}, {224.904456445713,83.297192679644}, +{223.890625000000,76.390625000000}, {224.718172891760,73.652424627265}, +{226.991950628026,71.671512863124}, {230.398659300280,70.468125917422}, +{234.625000000000,70.062500000000}, {239.436000436064,69.828681464349}, +{240.453125000000,69.140625000000}, {239.621272369169,63.470278877568}, +{237.983036171748,55.833595299706}, {237.978023315197,55.813489579321}, +{235.265625000000,42.968750000000}, {235.414374888933,43.818233911095}, +{223.164374888933,9.911983911095}, {223.454623060848,7.647483743269}, +{225.610873060848,4.506858743269}, {225.803351703291,4.260965402925}, +{227.719534150475,2.932735689909}, {230.078782966130,2.347671229322}, +{230.218750000000,2.343750000000}, {231.580832848366,2.789728316683}, +{232.871346377781,3.980786060276}, {235.131457239225,7.716876589460}, +{240.051188613236,19.745668022304}, {244.970104457946,33.805503176211}, +{247.762510801176,44.143184476801}, {247.777764624530,44.225329525617}, +{252.184014624530,70.381579525617}, {251.352799675865,68.904817480577}, +{254.575226795957,69.673348314939}, {260.406250000000,70.359375000000}, +{270.523910039912,70.690857394210}, {273.186407177161,72.174765791999}, +{274.049624252688,73.457293811137}, {274.375000000000,74.921875000000}, +{107.893088734820,103.841923410053}, {269.375000000000,74.921875000000}, +{269.694839960088,75.621642605790}, {260.406250000000,75.359375000000}, +{253.596648204043,74.576651685061}, {250.197596782742,73.718304003256}, +{248.084700324135,72.688932519423}, {247.253485375470,71.212170474383}, +{242.847235375470,45.055920474383}, {242.862489198824,45.138065523199}, +{240.182239292054,35.233559323790}, {235.370686386764,21.504331977696}, +{230.614636510775,9.861248410540}, {229.674552059719,7.679370189724}, +{229.774391761009,7.390935745817}, {230.218750000000,7.343750000000}, +{230.358717033870,7.339828770678}, {229.540398296709,7.582784597075}, +{229.732876939152,7.336891256731}, {227.576626939152,10.477516256731}, +{227.866875111067,8.213016088905}, {240.116875111067,42.119266088905}, +{240.265625000000,42.968750000000}, {242.834476684803,54.624010420679}, +{242.829463828252,54.603904700294}, {244.534977630831,62.545346122432}, +{245.453125000000,69.140625000000}, {244.611402180226,71.735213821357}, +{242.306187063936,73.585381035651}, {238.867409665678,74.693638982119}, +{234.625000000000,75.062500000000}, {229.906486871974,75.367549636876}, +{229.092373983240,75.779215997735}, {228.934535185216,76.058687905577}, +{228.890625000000,76.390625000000}, {229.790856054287,82.319994820356}, +{232.571933261722,91.218385945649}, {232.574034113306,91.224265697666}, +{234.986992254083,96.851263251065}, {237.441996845067,100.266302709491}, +{237.439317291842,100.263712540141}, {244.074197100624,106.275959413741}, +{247.409673148640,108.432844267021}, {246.875000000000,108.375000000000}, +{251.578125000000,108.375000000000}, {249.088156711733,111.098736280975}, +{248.501059746180,102.338409667587}, {248.503744619215,102.402406116755}, +{248.000000000000,86.578125000000}, {248.204678607058,80.674424141238}, +{248.635199756080,78.226325931503}, {249.564103209371,76.447917337745}, +{249.529108047034,76.482233047034}, {251.855421271850,75.142541341903}, +{254.812500000000,74.671875000000}, {258.571857984945,75.077633347234}, +{263.279470079064,76.245639842274}, {263.205056758774,76.224611587009}, +{267.479406097516,77.683738985792}, {266.973101252767,77.547023420208}, +{268.046875000000,77.703125000000}, {268.247054721136,77.733964370993}, +{268.227077605757,77.803800527161}, {268.040685564021,77.924371454157}, +{267.977871868973,78.021719855177}, {268.985855115250,76.421460145957}, +{269.308567902139,76.015446472685}, {269.418034045008,75.973989481328}, +{269.375000000000,76.000000000000}, {269.375000000000,74.921875000000}, +{107.893088734820,103.841923410053}, {243.911209450369,105.662056821622}, +{240.832004992147,102.845101845416}, {236.815516984936,97.742848726260}, +{236.813922800164,97.740633958664}, {232.773597278734,91.287437871638}, +{230.710552894044,85.924483215760}, {230.745327869205,86.067653416413}, +{229.840275149638,82.415038683708}, {229.855893749637,82.481339062591}, +{229.093750000000,78.546875000000}, {229.510257350732,77.264688549054}, +{230.557731326090,76.286764971873}, {233.333290689663,75.138571514324}, +{238.843750000000,74.468750000000}, {241.980836948934,74.687319511759}, +{245.189547085049,75.561169162745}, {247.167986856352,77.549353232692}, +{248.217702574415,80.638507879225}, {248.687500000000,88.140625000000}, +{248.194671228610,98.736670034806}, {248.200295344311,98.650162873539}, +{247.698246960594,103.850772804200}, {243.911209450369,105.662056821622}, +{107.893088734820,103.841923410053}, {242.739253039406,103.211727195800}, +{243.205954655689,98.412337126461}, {243.211578771390,98.325829965194}, +{243.687500000000,88.140625000000}, {243.282297425585,81.439617120775}, +{243.185452914951,80.141955837255}, {241.300413051066,79.640805488241}, +{238.843750000000,79.468750000000}, {234.557334310337,79.986428485676}, +{234.323615830224,80.043375869145}, {234.139295619945,80.082650511165}, +{233.899908001681,80.106538837663}, {233.805549923910,79.924172528127}, +{234.093750000000,78.546875000000}, {234.706606250363,81.268660937409}, +{234.722224850362,81.334961316292}, {235.567172130795,84.744846583587}, +{235.601947105956,84.888016784240}, {237.273277721266,89.165687128362}, +{240.873577199836,94.821866041336}, {240.871983015064,94.819651273740}, +{244.355495007853,99.326773154584}, {246.526290549631,101.400443178378}, +{242.739253039406,103.211727195800}, {107.893088734820,103.841923410053}, +{304.579027849556,115.887559254375}, {299.647333003501,118.498603127587}, +{299.601234810263,118.526555579345}, {296.960609810263,120.089055579345}, +{295.687500000000,120.437500000000}, {292.434178516679,119.763451801101}, +{289.591538470777,117.850158805700}, {287.263626957927,114.860898415742}, +{285.554491073762,110.958948033170}, {285.546168760441,110.932189402305}, +{283.409425227272,100.413450166388}, {283.408069329655,100.405281467271}, +{280.968147929764,87.644193704042}, {284.218299056292,87.914012723915}, +{279.519746335556,93.766171451312}, {279.798545332977,93.224824860858}, +{274.937093489612,105.343910553875}, {272.454127837569,109.762553039486}, +{269.772550129691,112.314814767144}, {266.294988321147,110.999865652887}, +{264.699764075525,105.167535274279}, {264.676753039406,105.022647804200}, +{264.221109604112,100.702343060691}, {264.171875000000,98.828125000000}, +{263.607902205199,91.869081828698}, {263.613915250645,91.062865437610}, +{263.781250000000,89.718750000000}, {263.644962649638,88.985351183708}, +{262.873500431741,86.703985451358}, {262.739182179139,86.219942105230}, +{260.786057179139,74.844942105230}, {260.786249814804,74.846062487964}, +{256.958124814804,52.611687487964}, {256.955473276820,52.595988114755}, +{254.892973276820,40.142863114755}, {254.909488793847,40.232428789163}, +{254.331363793847,37.388678789163}, {254.339079247810,37.425229542768}, +{253.651579247810,34.284604542768}, {253.593750000000,33.750000000000}, +{254.239654341050,30.319069019177}, {254.154681406546,30.589185956325}, +{256.319133024351,26.771372253672}, {258.818704827809,25.924919245868}, +{261.217531024880,26.988383072536}, {263.253153025566,28.888095452080}, +{264.856582863559,31.480336604342}, {265.958832572550,34.621386749163}, +{266.013105788729,34.918097636045}, {267.200714432551,44.731495841479}, +{267.198350954149,44.712535224402}, {269.443623734153,61.037071609407}, +{269.421396014347,60.906344576785}, {270.652021489737,67.736566992690}, +{271.992261513603,76.440263813345}, {271.992747064473,76.443809223415}, +{273.038636247453,85.686082548185}, {273.390625000000,92.953125000000}, +{273.238407027301,96.898129287691}, {272.771685367998,99.590064317759}, +{267.989237947004,98.132898258783}, {271.223612947004,86.961023258783}, +{271.391159168632,86.533772766328}, {274.526090303798,81.379570646076}, +{274.584318175231,81.310286998919}, {276.982682022500,78.600716011250}, +{277.142029400154,78.326905342657}, {279.265919333198,75.301911531816}, +{279.298622345235,75.258362091268}, {281.876153531632,73.009942282517}, +{284.906250000000,72.125000000000}, {287.318073492888,72.767987310135}, +{289.339116026344,74.544184270464}, {290.903803647217,77.224443425871}, +{291.946562402359,80.579617321243}, {291.963278527291,80.666832095730}, +{293.477578855570,88.491377103079}, {294.532438780850,92.026218792971}, +{294.690170210143,92.371639700252}, {298.832669585147,102.687317191341}, +{298.821447919079,102.663322107333}, {301.483679194839,107.248880594573}, +{302.541048238599,108.202972500861}, {303.515625000000,108.484375000000}, +{306.015625000000,110.984375000000}, {306.015625000000,113.625000000000}, +{304.579027849556,115.887559254375}, {107.893088734820,103.841923410053}, +{301.015625000000,113.625000000000}, {301.015625000000,110.984375000000}, +{303.515625000000,113.484375000000}, {300.984342386401,112.859527499139}, +{298.555383305161,111.094869405427}, {296.303526841571,108.355227332168}, +{294.303552080921,104.805427892667}, {294.292330414853,104.781432808659}, +{289.997329789857,94.097110299748}, {290.155061219150,94.442531207029}, +{288.709921144430,89.953935396921}, {287.036721472709,81.520667904270}, +{287.053437597641,81.607882678757}, {286.004633973656,77.940190729536}, +{284.906250000000,77.125000000000}, {284.500063101353,77.160595459408}, +{284.155096468369,77.318182717483}, {283.263877654765,78.304137908732}, +{283.296580666802,78.260588468184}, {281.295470599846,81.110594657343}, +{281.454817977500,80.836783988750}, {278.353181824769,84.595963001081}, +{278.411409696202,84.526679353924}, {275.858840831368,88.778727233672}, +{276.026387052996,88.351476741217}, {272.792012052996,99.523351741217}, +{268.009564632002,98.066185682241}, {268.390625000000,92.953125000000}, +{268.055113752547,86.056104951815}, {267.038502935527,77.118690776585}, +{267.038988486397,77.122236186655}, {265.722978510263,68.575933007310}, +{264.516103985653,61.874905423215}, {264.493876265847,61.744178390593}, +{262.239149045851,45.349964775598}, {262.236785567449,45.331004158521}, +{261.049394211271,35.519402363955}, {261.103667427450,35.816113250837}, +{259.699971974434,32.150967047920}, {257.681295172191,30.793830754132}, +{260.180866975649,29.947377746328}, {259.001568593454,31.817064043675}, +{258.916595658950,32.087180980823}, {258.593750000000,33.750000000000}, +{258.535920752190,33.215395457232}, {259.223420752190,36.356020457232}, +{259.231136206153,36.392571210837}, {259.809261206153,39.236321210837}, +{259.825776723180,39.325886885245}, {261.888276723180,51.779011885245}, +{261.885625185196,51.763312512036}, {265.713750185196,73.997687512036}, +{265.713942820861,73.998807894770}, {267.667067820861,85.373807894770}, +{267.532749568259,84.889764548642}, {268.526912350362,87.905273816292}, +{268.781250000000,89.718750000000}, {268.542334749355,91.905884562390}, +{268.548347794801,91.099668171302}, {269.171875000000,98.828125000000}, +{269.216390395888,100.485156939309}, {269.635746960594,104.383602195800}, +{269.612735924475,104.238714725721}, {270.955011678853,109.187634347113}, +{267.477449870309,107.872685232856}, {268.686497162431,106.569478210514}, +{270.375406510388,103.296714446125}, {275.107704667023,91.493925139142}, +{275.386503664444,90.952578548688}, {278.700840527029,86.470174071108}, +{281.281700943708,83.867237276085}, {284.531852070236,84.137056295958}, +{285.408419686884,85.805066273498}, {286.324716189650,88.997159604327}, +{288.341930670345,99.594718532729}, {288.340574772728,99.586549833612}, +{290.328831239559,109.474060597695}, {290.320508926238,109.447301966830}, +{291.419966792073,112.312929709258}, {292.611586529223,114.157653694300}, +{293.999415233321,115.144751323899}, {295.687500000000,115.437500000000}, +{294.414390189737,115.785944420655}, {297.055015189737,114.223444420655}, +{297.008916996499,114.251396872413}, {302.452222150444,111.362440745625}, +{301.015625000000,113.625000000000}, {107.893088734820,103.841923410053}, +{374.437500000000,106.765625000000}, {373.775309600600,109.463093710969}, +{372.064906958700,112.117295697199}, {372.041004786215,112.144602045402}, +{368.522704503395,114.706400007155}, {366.442611342446,115.399541345014}, +{364.281250000000,115.640625000000}, {355.911205219123,114.726652651698}, +{341.052591424867,111.966274658224}, {341.038040421249,111.963294783992}, +{326.905309277070,108.757693347762}, {319.727026481732,106.439595965247}, +{319.807037817648,106.479160754059}, {310.484453831953,101.696158824691}, +{304.482826587959,97.721718623918}, {304.310358047034,97.564641952966}, +{302.095819571999,95.254869206705}, {298.220153609739,90.667578419636}, +{300.367638895226,91.618501549714}, {296.258263895226,91.915376549714}, +{296.078125000000,91.921875000000}, {293.025957236218,91.709450913344}, +{290.151865257421,91.083888117023}, {285.254658796565,88.663603177256}, +{285.219422230119,88.636374171395}, {281.529900243089,84.536170132203}, +{280.513144708967,82.282593311151}, {280.156250000000,80.015625000000}, +{280.896516775664,77.119922391977}, {282.806537684315,74.726645730656}, +{285.448073147177,73.263018105533}, {288.686079158715,72.443690273534}, +{290.750793112766,73.122099563886}, {293.797668112766,76.059599563886}, +{293.736465601749,76.002539206463}, {295.798965601749,77.861914206463}, +{294.222063773555,77.220634985862}, {301.862688773555,77.517509985862}, +{299.265625000000,80.015625000000}, {299.934685624955,74.754308742711}, +{301.898213943218,69.792099871114}, {305.090729619888,65.230982029954}, +{309.446752320064,61.172938863978}, {309.482902906976,61.145713152252}, +{318.065904047846,56.213131631660}, {329.455658353400,51.953267244508}, +{329.496351456999,51.941186017188}, {336.615241964605,50.572965088062}, +{336.666137267666,50.568817238037}, {342.150512267666,50.178192238037}, +{342.328125000000,50.171875000000}, {347.088673798588,50.461178987176}, +{351.635436696472,51.319590054257}, {355.904450990616,52.732856859568}, +{359.831753977986,54.686728061438}, {363.292951645549,57.250115143707}, +{365.880587968213,60.272932122861}, {367.501493801268,63.647371305944}, +{368.062500000000,67.265625000000}, {367.659428864193,69.524372763002}, +{366.507997055207,71.901249483478}, {362.306741008310,76.690232523947}, +{362.309449580203,76.687848273793}, {355.067416613929,81.592460070084}, +{345.579434368324,85.619156329617}, {345.543296906352,85.631025936969}, +{338.856518222681,87.434049611292}, {331.674077585810,88.726763309129}, +{324.032609882622,89.505258086643}, {315.968750000000,89.765625000000}, +{315.697255981477,89.750839477245}, {313.837880981477,89.547714477245}, +{314.109375000000,89.562500000000}, {315.203325765838,88.142787621838}, +{315.234375000000,87.750000000000}, {315.261368553241,87.459370280378}, +{315.416652198286,87.453346686481}, {316.557907675735,88.522399326740}, +{316.429841220906,88.403882310796}, {319.273591220906,90.857007310796}, +{318.935343465338,90.611377991437}, {331.091593465338,97.970752991437}, +{330.612118984109,97.746034726917}, {334.956642245028,98.975789357391}, +{339.851927078584,99.850564497063}, {351.453125000000,100.546875000000}, +{354.203872313810,100.381670729150}, {355.159915151904,99.886038066767}, +{355.055436157189,100.055596900919}, {357.900435727416,97.290434866877}, +{362.379803562479,95.425955323112}, {363.015625000000,95.343750000000}, +{366.828125000000,95.343750000000}, {368.997562855593,96.601357392681}, +{374.106937855593,105.523232392681}, {374.437500000000,106.765625000000}, +{107.893088734820,103.841923410053}, {369.768062144407,108.008017607319}, +{364.658687144407,99.086142607319}, {366.828125000000,100.343750000000}, +{363.015625000000,100.343750000000}, {363.651446437521,100.261544676888}, +{360.724564272584,101.303315133123}, {359.413313842811,102.506903099081}, +{359.308834848096,102.676461933233}, {358.021570604282,103.932262067178}, +{356.186752686190,104.829266770850}, {351.453125000000,105.546875000000}, +{345.006190631125,105.353277680068}, {339.085572921416,104.774435502937}, +{333.730857754972,103.813273142609}, {328.981631015891,102.472715273083}, +{328.502156534662,102.247997008563}, {316.345906534662,94.888622008563}, +{316.007658779094,94.642992689204}, {313.163908779094,92.189867689204}, +{313.035842324265,92.071350673260}, {311.083347801714,89.820090813519}, +{310.234375000000,87.750000000000}, {310.265424234162,87.357212378162}, +{310.780311953087,86.191927459145}, {311.752715552710,85.312201869144}, +{314.109375000000,84.562500000000}, {314.380869018523,84.577285522755}, +{316.240244018523,84.780410522755}, {315.968750000000,84.765625000000}, +{323.705671367377,84.524038788357}, {330.935297414190,83.796674190871}, +{337.694263027319,82.579622263708}, {344.019203093648,80.868974063031}, +{343.983065631676,80.880843670383}, {352.635708386071,77.251289929916}, +{359.003050419797,72.937151726207}, {359.005758991690,72.934767476053}, +{362.163877944793,69.637813016522}, {363.062500000000,67.265625000000}, +{362.747529636232,64.880949006556}, {361.740505781787,62.777849127139}, +{359.948259291951,60.848517668793}, {357.277621022014,58.985146938562}, +{353.920744321884,57.295463452932}, {350.352844553528,56.106191195743}, +{346.509959013911,55.403078825324}, {342.328125000000,55.171875000000}, +{342.505737732334,55.165557761963}, {337.021362732334,55.556182761963}, +{337.072258035395,55.552034911938}, {330.878648543001,56.746313982812}, +{330.919341646600,56.734232755492}, {320.246595952154,60.693118368340}, +{312.454597093024,65.166786847748}, {312.490747679936,65.139561136022}, +{308.794036005112,68.485814845046}, {306.234598556782,72.012587628886}, +{304.746955000045,75.821863132289}, {304.265625000000,80.015625000000}, +{301.668561226445,82.513740014138}, {294.027936226445,82.216865014138}, +{292.451034398251,81.575585793537}, {290.388534398251,79.716210793537}, +{290.327331887234,79.659150436114}, {287.280456887234,76.721650436114}, +{289.345170841285,77.400059726466}, {287.321458102823,77.850263144467}, +{285.927837315685,78.632729269344}, {285.271451974336,79.274608858023}, +{285.175338636761,79.581613557521}, {285.156250000000,80.015625000000}, +{285.837287256911,82.245079867797}, {288.311827769881,84.707375828605}, +{288.276591203435,84.680146822744}, {291.660634742579,86.384861882977}, +{296.078125000000,86.921875000000}, {295.897986104774,86.928373450286}, +{300.007361104774,86.631498450286}, {302.154846390261,87.582421580364}, +{305.732305428001,91.823255793295}, {307.845891952966,94.029108047034}, +{307.673423412041,93.872031376082}, {313.085858668047,97.436653675309}, +{321.942962182352,101.958339245941}, {322.022973518268,101.997904034753}, +{328.415003222930,104.000119152238}, {342.055709578751,107.067955216008}, +{342.041158575133,107.064975341776}, {356.698169780877,109.788972348302}, +{364.281250000000,110.640625000000}, {366.516357996605,110.246724992845}, +{368.302745213785,108.824147954598}, {368.278843041300,108.851454302801}, +{369.437500000000,106.765625000000}, {369.768062144407,108.008017607319}, +{107.893088734820,103.841923410053}, {359.034454681034,69.861443602839}, +{357.173548986071,72.638610976591}, {353.435826646756,75.215386191513}, +{347.992418306797,77.582163291606}, {341.014454609897,79.729336320871}, +{326.426284670840,82.761098429090}, {319.640717587115,83.525315463381}, +{313.234375000000,83.781250000000}, {312.706760041223,83.724940335389}, +{311.331760041223,83.428065335389}, {311.389194323030,83.439762979730}, +{309.920444323030,83.158512979730}, {310.390625000000,83.203125000000}, +{309.032298883605,83.610801187634}, {305.860259182280,80.222501196670}, +{308.487654632717,75.272571710106}, {311.451975717975,70.927537861140}, +{314.718319876723,67.239682598354}, {318.251784547635,64.261288870324}, +{318.235984828743,64.272646821685}, {322.460311501394,61.735717754517}, +{327.134482463160,59.899177687483}, {332.183220900533,58.782772982128}, +{337.531250000000,58.406250000000}, {345.475041381297,58.786142249068}, +{351.020038715603,59.929523334009}, {351.130689531816,59.972424607386}, +{353.699762084814,61.379594420291}, {355.915109055748,63.288105475323}, +{357.703808635445,65.619192847673}, {358.992939014732,68.294091612533}, +{359.034454681034,69.861443602839}, {107.893088734820,103.841923410053}, +{354.288310985268,69.987158387467}, {352.366140944252,66.657207024677}, +{349.213060468184,64.590075392614}, {349.323711284397,64.632976665991}, +{344.735896118703,63.713857750932}, {337.531250000000,63.406250000000}, +{332.857794724467,63.703555142872}, {328.623330036840,64.608634812517}, +{324.752579123606,66.141235370483}, {321.170265171257,68.321103178315}, +{321.154465452365,68.332461129676}, {318.096133248277,70.895083026646}, +{315.305836782025,74.049024638860}, {312.748673492282,77.846568914895}, +{310.389740817720,82.339998803330}, {307.217701116395,78.951698812366}, +{310.390625000000,78.203125000000}, {310.860805676970,78.247737020270}, +{312.329555676970,78.528987020270}, {312.386989958777,78.540684664611}, +{313.761989958777,78.837559664611}, {313.234375000000,78.781250000000}, +{319.326079287885,78.541090786619}, {325.753402829160,77.817026570910}, +{339.735545390103,74.895663679129}, {350.446985853244,71.354926308487}, +{353.125279138929,69.816467148409}, {354.246795318966,68.419806397161}, +{354.288310985268,69.987158387467}, {107.893088734820,103.841923410053}, +{412.906150029990,61.293260146951}, {409.761470127352,62.134684085464}, +{407.280172710472,63.259435125605}, {407.285792255081,63.256184676520}, +{404.793374271599,64.364965077547}, {402.406250000000,64.781250000000}, +{400.799037804796,64.455489160260}, {399.281565012266,63.565560595750}, +{396.896451926356,60.617324020679}, {395.843750000000,59.187500000000}, +{394.132759007664,59.586356110398}, {392.227223295325,60.862510968959}, +{387.514233459670,66.524236094764}, {387.523930329881,66.510005317299}, +{384.972470502350,70.813073903396}, {383.182220364063,75.072391356081}, +{382.127155126215,79.356608210051}, {381.781250000000,83.734375000000}, +{382.036891605602,86.926476407739}, {382.837535469594,90.232985146136}, +{382.953125000000,90.984375000000}, {382.953125000000,110.781250000000}, +{380.453125000000,113.281250000000}, {374.875000000000,113.281250000000}, +{372.797350977108,112.469290573921}, {370.771127450416,110.197059087430}, +{366.940746762890,102.253660683699}, {366.931766441279,102.229357657717}, +{364.988344509233,95.969248633492}, {363.592635453443,89.400212341223}, +{362.750737781251,82.563409292771}, {362.468750000000,75.500000000000}, +{362.469585639102,75.564633561058}, {362.375835639102,71.939633561058}, +{362.376194806642,71.952282634846}, {362.282444806642,68.921032634846}, +{362.281250000000,68.843750000000}, {362.557974048920,65.558176179264}, +{363.371209408870,62.925233614273}, {365.078767647837,60.585701488502}, +{367.830147985199,58.062445160283}, {369.390625000000,57.515625000000}, +{372.609375000000,57.515625000000}, {375.044088155839,59.448023159988}, +{375.637838155839,61.994898159988}, {375.701153736333,62.463240580013}, +{375.794903736333,64.822615580013}, {375.796875000000,64.921875000000}, +{375.796875000000,66.390625000000}, {375.727843254951,66.974057381188}, +{375.364882971473,68.609156073692}, {375.377354243352,68.535253718305}, +{374.986729243352,71.082128718305}, {375.015625000000,70.703125000000}, +{375.946084438562,73.051058522014}, {371.472688855144,73.407169646001}, +{374.338903268299,66.961197216653}, {377.510670879106,61.308691210684}, +{380.962283852915,56.499192859154}, {384.668034355078,52.582243393122}, +{384.668120639869,52.582165462116}, {388.032154904598,50.002880989291}, +{391.626628158728,48.110057708285}, {395.367786243461,46.944465688666}, +{399.171875000000,46.546875000000}, {400.072873198005,46.714879663986}, +{404.885373198005,48.574254663986}, {404.871260445955,48.568850974212}, +{412.883679720929,50.905386234424}, {414.906250000000,53.359375000000}, +{414.906250000000,58.843750000000}, {412.906150029990,61.293260146951}, +{107.893088734820,103.841923410053}, {409.906250000000,58.843750000000}, +{409.906250000000,53.359375000000}, {411.928820279071,55.813363765576}, +{403.097489554045,53.243649025788}, {403.083376801995,53.238245336014}, +{398.270876801995,51.378870336014}, {399.171875000000,51.546875000000}, +{396.227916881538,51.823112436334}, {393.443684341272,52.679004791715}, +{390.735423220402,54.155322135709}, {388.019379360131,56.292834537884}, +{388.019465644922,56.292756606878}, {384.707638022085,59.784010265846}, +{381.637766620894,64.074121289316}, {378.784143606701,69.212630908347}, +{376.121061144856,75.249080353999}, {371.647665561438,75.605191477986}, +{370.464152438185,73.063686657060}, {370.015625000000,70.703125000000}, +{370.044520756648,70.324121281695}, {370.435145756648,67.777246281695}, +{370.447617028527,67.703343926308}, {370.865906745049,65.807192618812}, +{370.796875000000,66.390625000000}, {370.796875000000,64.921875000000}, +{370.798846263667,65.021134419987}, {370.705096263667,62.661759419987}, +{370.768411844161,63.130101840012}, {370.174661844161,60.583226840012}, +{372.609375000000,62.515625000000}, {369.390625000000,62.515625000000}, +{370.951102014801,61.968804839717}, {367.847540591130,65.152891385727}, +{367.281250000000,68.843750000000}, {367.280055193358,68.766467365154}, +{367.373805193358,71.797717365154}, {367.374164360898,71.810366438942}, +{367.467914360898,75.435366438942}, {367.468750000000,75.500000000000}, +{367.725824718749,82.182684457229}, {368.501114546557,88.552912658777}, +{369.800717990767,94.651845116508}, {371.630733558721,100.520642342283}, +{371.621753237110,100.496339316301}, {374.875000000000,108.281250000000}, +{380.453125000000,108.281250000000}, {377.953125000000,110.781250000000}, +{377.953125000000,90.984375000000}, {378.068714530406,91.735764853864}, +{377.111545894398,87.698523592261}, {376.781250000000,83.734375000000}, +{377.206829248785,78.659016789949}, {378.466217135937,73.583858643919}, +{380.533388872650,68.577551096604}, {383.382319670119,63.708744682701}, +{383.392016540330,63.694513905236}, {386.493443824758,59.714265008269}, +{389.655589204675,56.723426531041}, {392.798881617336,54.841378264602}, +{395.843750000000,54.187500000000}, {397.450962195204,54.513260839740}, +{398.968434987734,55.403189404250}, {401.353548073644,58.351425979321}, +{402.406250000000,59.781250000000}, {404.776707744919,58.931315323480}, +{404.782327289528,58.928064874395}, {408.035404872648,57.459065914536}, +{411.906349970010,56.394239853049}, {409.906250000000,58.843750000000}, +{107.893088734820, 103.841923410053} +}; diff --git a/local/recipes/libs/cairo/source/perf/micro/zrusin.c b/local/recipes/libs/cairo/source/perf/micro/zrusin.c new file mode 100644 index 0000000000..3dee74d23e --- /dev/null +++ b/local/recipes/libs/cairo/source/perf/micro/zrusin.c @@ -0,0 +1,97 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * 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: Carl D. Worth + */ + +#include "cairo-perf.h" + +typedef struct { + double x; + double y; +} point_t; + +#include "zrusin-another.h" + +static void +zrusin_another_path (cairo_t *cr) +{ + unsigned int i; + + for (i=0; i < ARRAY_LENGTH (zrusin_another); i++) + cairo_line_to (cr, zrusin_another[i].x, zrusin_another[i].y); +} + +static cairo_time_t +zrusin_another_tessellate (cairo_t *cr, int width, int height, int loops) +{ + zrusin_another_path (cr); + + cairo_perf_timer_start (); + + /* We'd like to measure just tessellation without + * rasterization. For now, we can do that with cairo_in_fill. But + * we'll have to be careful since cairo_in_fill might eventually + * be optimized to have an implementation that doesn't necessarily + * include tessellation. */ + while (loops--) + cairo_in_fill (cr, 50, 50); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +static cairo_time_t +zrusin_another_fill (cairo_t *cr, int width, int height, int loops) +{ + zrusin_another_path (cr); + cairo_set_source_rgb (cr, 0.0, 0.0, 0.8); /* blue */ + + cairo_perf_timer_start (); + + while (loops--) + cairo_fill_preserve (cr); + + cairo_perf_timer_stop (); + + cairo_new_path (cr); + + return cairo_perf_timer_elapsed (); +} + +cairo_bool_t +zrusin_enabled (cairo_perf_t *perf) +{ + return cairo_perf_can_run (perf, "zrusin", NULL); +} + +void +zrusin (cairo_perf_t *perf, cairo_t *cr, int width, int height) +{ + + cairo_perf_run (perf, "zrusin-another-tessellate", zrusin_another_tessellate, NULL); + cairo_perf_run (perf, "zrusin-another-fill", zrusin_another_fill, NULL); +} diff --git a/local/recipes/libs/cairo/source/src/.gitignore b/local/recipes/libs/cairo/source/src/.gitignore new file mode 100644 index 0000000000..32fb7333e8 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/.gitignore @@ -0,0 +1,38 @@ +.deps +.libs +Makefile +Makefile.in +Makefile.am.features +#Makefile.win32.features +*.gcda +*.gcno +*.la +*.lo +*.loT +*.pc +cairo-features.h +cairo-supported-features.h +cairo.def +*.i +*.s +*.o +*.obj +*.pdb +*.dll +*.manifest +*.ilk +*.exp +*.lib +*.trs +*~ +.*.sw? +TAGS +tags +check-has-hidden-symbols.i +check-link +check-skiplist +headers-standalone +!cairo.pc.in +!cairo-uninstalled.pc.in +!cairo-features.pc.in +!cairo-features-uninstalled.pc.in diff --git a/local/recipes/libs/cairo/source/src/README b/local/recipes/libs/cairo/source/src/README new file mode 100644 index 0000000000..03e4455ea5 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/README @@ -0,0 +1,69 @@ +Cairo Library Source Code +========================= + +This directory contains the source code of the cairo library. + + +Source Code Listing +------------------- + +The canonical list of source files is the file Makefile.sources. See that +file for how it works. + + +New Backends +------------ + +The rule of the thumb for adding new backends is to see how other +backends are integrated. Pick one of the simpler, unsupported, backends +and search the entire tree for it, and go from there. + +To add new backends you need to basically: + + * Modify $(top_srcdir)/configure.in to add checks for your backend. + + * Modify Makefile.sources to add source files for your backend, + + * Modify $(top_srcdir)/boilerplate/ to add boilerplate code for + testing your new backend. + + +New API +------- + +After adding new API, run "make check" in this directory and fix any +reported issues. Also add new API to the right location in +$(top_srcdir)/doc/public/cairo-sections.txt and run "make check" +in $(top_builddir)/doc/public to make sure that any newly added +documentation is correctly hooked up. + +Do not forget to add tests for the new API. See next section. + + +Tests +----- + +There are some tests in this directory that check the source code and +the build for various issues. The tests are very quick to run, and +particularly should be run after any documentation or API changes. It +does not hurt to run them after any source modification either. Run +them simply by calling: + + make check + +There are also extensive regression tests in $(top_srcdir)/test. It is +a good idea to run that test suite for any changes made to the source +code. Moreover, for any new feature, API, or bug fix, new tests should +be added to the regression test suite to test the new code. + + +Bibliography +------------ + +A detailed list of academic publications used in cairo code is available +in the file $(top_srcdir)/BIBLIOGRAPHY. Feel free to update as you +implement more papers. + +For more technical publications (eg. Adobe technical reports) just +point them out in a comment in the header of the file implementing them. + diff --git a/local/recipes/libs/cairo/source/src/cairo-analysis-surface-private.h b/local/recipes/libs/cairo/source/src/cairo-analysis-surface-private.h new file mode 100644 index 0000000000..6489cceb86 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-analysis-surface-private.h @@ -0,0 +1,87 @@ +/* + * Copyright © 2005 Keith Packard + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Keith Packard + * + * Contributor(s): + * Keith Packard + */ + +#ifndef CAIRO_ANALYSIS_SURFACE_H +#define CAIRO_ANALYSIS_SURFACE_H + +#include "cairoint.h" + +cairo_private cairo_surface_t * +_cairo_analysis_surface_create (cairo_surface_t *target, + cairo_bool_t create_region_ids); + +cairo_private void +_cairo_analysis_surface_set_ctm (cairo_surface_t *surface, + const cairo_matrix_t *ctm); + +cairo_private void +_cairo_analysis_surface_get_ctm (cairo_surface_t *surface, + cairo_matrix_t *ctm); + +cairo_private cairo_region_t * +_cairo_analysis_surface_get_supported (cairo_surface_t *surface); + +cairo_private cairo_region_t * +_cairo_analysis_surface_get_unsupported (cairo_surface_t *surface); + +cairo_private cairo_bool_t +_cairo_analysis_surface_has_supported (cairo_surface_t *surface); + +cairo_private cairo_bool_t +_cairo_analysis_surface_has_unsupported (cairo_surface_t *surface); + +cairo_private void +_cairo_analysis_surface_get_bounding_box (cairo_surface_t *surface, + cairo_box_t *bbox); + +cairo_private unsigned int +_cairo_analysis_surface_get_source_region_id (cairo_surface_t *surface); + +cairo_private unsigned int +_cairo_analysis_surface_get_mask_region_id (cairo_surface_t *surface); + +cairo_private cairo_int_status_t +_cairo_analysis_surface_merge_status (cairo_int_status_t status_a, + cairo_int_status_t status_b); + +cairo_private cairo_surface_t * +_cairo_null_surface_create (cairo_content_t content); + +static inline cairo_bool_t +_cairo_surface_is_analysis (const cairo_surface_t *surface) +{ + return (cairo_internal_surface_type_t)surface->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS; +} + +#endif /* CAIRO_ANALYSIS_SURFACE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-analysis-surface.c b/local/recipes/libs/cairo/source/src/cairo-analysis-surface.c new file mode 100644 index 0000000000..f6099c41b2 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-analysis-surface.c @@ -0,0 +1,1228 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* + * Copyright © 2006 Keith Packard + * Copyright © 2007 Adrian Johnson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Keith Packard + * + * Contributor(s): + * Keith Packard + * Adrian Johnson + */ + +#include "cairoint.h" + +#include "cairo-analysis-surface-private.h" +#include "cairo-box-inline.h" +#include "cairo-default-context-private.h" +#include "cairo-error-private.h" +#include "cairo-paginated-private.h" +#include "cairo-recording-surface-inline.h" +#include "cairo-surface-snapshot-inline.h" +#include "cairo-surface-subsurface-inline.h" +#include "cairo-region-private.h" + +typedef struct { + cairo_surface_t base; + + cairo_surface_t *target; + + cairo_bool_t first_op; + cairo_bool_t has_supported; + cairo_bool_t has_unsupported; + + cairo_region_t supported_region; + cairo_region_t fallback_region; + cairo_box_t page_bbox; + + cairo_bool_t create_region_ids; + unsigned source_region_id; + unsigned mask_region_id; + + cairo_bool_t has_ctm; + cairo_matrix_t ctm; + +} cairo_analysis_surface_t; + +cairo_int_status_t +_cairo_analysis_surface_merge_status (cairo_int_status_t status_a, + cairo_int_status_t status_b) +{ + /* fatal errors should be checked and propagated at source */ + assert (! _cairo_int_status_is_error (status_a)); + assert (! _cairo_int_status_is_error (status_b)); + + /* return the most important status */ + if (status_a == CAIRO_INT_STATUS_UNSUPPORTED || + status_b == CAIRO_INT_STATUS_UNSUPPORTED) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (status_a == CAIRO_INT_STATUS_IMAGE_FALLBACK || + status_b == CAIRO_INT_STATUS_IMAGE_FALLBACK) + return CAIRO_INT_STATUS_IMAGE_FALLBACK; + + if (status_a == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN || + status_b == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) + return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN; + + if (status_a == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY || + status_b == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY) + return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY; + + /* at this point we have checked all the valid internal codes, so... */ + assert (status_a == CAIRO_INT_STATUS_SUCCESS && + status_b == CAIRO_INT_STATUS_SUCCESS); + + return CAIRO_INT_STATUS_SUCCESS; +} + +struct proxy { + cairo_surface_t base; + cairo_surface_t *target; +}; + +static cairo_status_t +proxy_finish (void *abstract_surface) +{ + return CAIRO_STATUS_SUCCESS; +} + +static const cairo_surface_backend_t proxy_backend = { + CAIRO_INTERNAL_SURFACE_TYPE_NULL, + proxy_finish, +}; + +static cairo_surface_t * +attach_proxy (cairo_surface_t *source, + cairo_surface_t *target) +{ + struct proxy *proxy; + + proxy = _cairo_calloc (sizeof (*proxy)); + if (unlikely (proxy == NULL)) + return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY); + + _cairo_surface_init (&proxy->base, &proxy_backend, NULL, target->content, target->is_vector); + + proxy->target = target; + _cairo_surface_attach_snapshot (source, &proxy->base, NULL); + + return &proxy->base; +} + +static void +detach_proxy (cairo_surface_t *proxy) +{ + cairo_surface_finish (proxy); + cairo_surface_destroy (proxy); +} + +static cairo_int_status_t +_add_operation (cairo_analysis_surface_t *surface, + cairo_rectangle_int_t *rect, + cairo_int_status_t backend_status) +{ + cairo_int_status_t status; + cairo_box_t bbox; + + if (rect->width == 0 || rect->height == 0) { + /* Even though the operation is not visible we must be careful + * to not allow unsupported operations to be replayed to the + * backend during CAIRO_PAGINATED_MODE_RENDER */ + if (backend_status == CAIRO_INT_STATUS_SUCCESS || + backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY || + backend_status == CAIRO_INT_STATUS_NOTHING_TO_DO) + { + return CAIRO_INT_STATUS_SUCCESS; + } + else + { + return CAIRO_INT_STATUS_IMAGE_FALLBACK; + } + } + + _cairo_box_from_rectangle (&bbox, rect); + + if (surface->has_ctm) { + int tx, ty; + + if (_cairo_matrix_is_integer_translation (&surface->ctm, &tx, &ty)) { + rect->x += tx; + rect->y += ty; + + tx = _cairo_fixed_from_int (tx); + bbox.p1.x += tx; + bbox.p2.x += tx; + + ty = _cairo_fixed_from_int (ty); + bbox.p1.y += ty; + bbox.p2.y += ty; + } else { + _cairo_matrix_transform_bounding_box_fixed (&surface->ctm, + &bbox, NULL); + + if (bbox.p1.x == bbox.p2.x || bbox.p1.y == bbox.p2.y) { + /* Even though the operation is not visible we must be + * careful to not allow unsupported operations to be + * replayed to the backend during + * CAIRO_PAGINATED_MODE_RENDER */ + if (backend_status == CAIRO_INT_STATUS_SUCCESS || + backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY || + backend_status == CAIRO_INT_STATUS_NOTHING_TO_DO) + { + return CAIRO_INT_STATUS_SUCCESS; + } + else + { + return CAIRO_INT_STATUS_IMAGE_FALLBACK; + } + } + + _cairo_box_round_to_rectangle (&bbox, rect); + } + } + + if (surface->first_op) { + surface->first_op = FALSE; + surface->page_bbox = bbox; + } else + _cairo_box_add_box(&surface->page_bbox, &bbox); + + /* If the operation is completely enclosed within the fallback + * region there is no benefit in emitting a native operation as + * the fallback image will be painted on top. + */ + if (cairo_region_contains_rectangle (&surface->fallback_region, rect) == CAIRO_REGION_OVERLAP_IN) + return CAIRO_INT_STATUS_IMAGE_FALLBACK; + + if (backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY) { + /* A status of CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY indicates + * that the backend only supports this operation if the + * transparency removed. If the extents of this operation does + * not intersect any other native operation, the operation is + * natively supported and the backend will blend the + * transparency into the white background. + */ + if (cairo_region_contains_rectangle (&surface->supported_region, rect) == CAIRO_REGION_OVERLAP_OUT) + backend_status = CAIRO_INT_STATUS_SUCCESS; + } + + if (backend_status == CAIRO_INT_STATUS_SUCCESS) { + /* Add the operation to the supported region. Operations in + * this region will be emitted as native operations. + */ + surface->has_supported = TRUE; + return cairo_region_union_rectangle (&surface->supported_region, rect); + } + + /* Add the operation to the unsupported region. This region will + * be painted as an image after all native operations have been + * emitted. + */ + surface->has_unsupported = TRUE; + status = cairo_region_union_rectangle (&surface->fallback_region, rect); + + /* The status CAIRO_INT_STATUS_IMAGE_FALLBACK is used to indicate + * unsupported operations to the recording surface as using + * CAIRO_INT_STATUS_UNSUPPORTED would cause cairo-surface to + * invoke the cairo-surface-fallback path then return + * CAIRO_STATUS_SUCCESS. + */ + if (status == CAIRO_INT_STATUS_SUCCESS) + return CAIRO_INT_STATUS_IMAGE_FALLBACK; + else + return status; +} + +static cairo_int_status_t +_analyze_recording_surface_pattern (cairo_analysis_surface_t *surface, + const cairo_pattern_t *pattern, + cairo_rectangle_int_t *extents, + unsigned int *regions_id, + cairo_analysis_source_t source_type) +{ + const cairo_surface_pattern_t *surface_pattern; + cairo_analysis_surface_t *tmp; + cairo_surface_t *source, *proxy; + cairo_matrix_t p2d; + cairo_int_status_t status; + cairo_int_status_t analysis_status = CAIRO_INT_STATUS_SUCCESS; + cairo_bool_t surface_is_unbounded; + cairo_bool_t unused; + cairo_bool_t replay_all; + + assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE); + surface_pattern = (const cairo_surface_pattern_t *) pattern; + assert (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING); + source = surface_pattern->surface; + + proxy = _cairo_surface_has_snapshot (source, &proxy_backend); + if (proxy != NULL) { + /* nothing untoward found so far */ + return CAIRO_STATUS_SUCCESS; + } + + tmp = (cairo_analysis_surface_t *) + _cairo_analysis_surface_create (surface->target, surface->create_region_ids); + if (unlikely (tmp->base.status)) { + status = tmp->base.status; + goto cleanup1; + } + proxy = attach_proxy (source, &tmp->base); + + p2d = pattern->matrix; + status = cairo_matrix_invert (&p2d); + assert (status == CAIRO_INT_STATUS_SUCCESS); + _cairo_analysis_surface_set_ctm (&tmp->base, &p2d); + + source = _cairo_surface_get_source (source, NULL); + surface_is_unbounded = (pattern->extend == CAIRO_EXTEND_REPEAT + || pattern->extend == CAIRO_EXTEND_REFLECT); + + if (surface->create_region_ids) { + status = _cairo_recording_surface_region_array_attach (source, regions_id); + if (unlikely (status)) + goto cleanup2; + } + + replay_all = FALSE; + if (surface->target->backend->analyze_recording_surface) { + status = surface->target->backend->analyze_recording_surface ( + surface->target, + surface_pattern, + surface->create_region_ids ? *regions_id : 0, + source_type, + TRUE); + if (status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) { + /* Ensure all commands are replayed even if previously + * replayed and assigned to a region.*/ + replay_all = TRUE; + status = CAIRO_INT_STATUS_SUCCESS; + } + if (unlikely (status)) + goto cleanup3; + } + + if (surface->create_region_ids) { + status = _cairo_recording_surface_replay_and_create_regions (source, + *regions_id, + &pattern->matrix, + &tmp->base, + surface_is_unbounded, + replay_all); + if (unlikely (status)) + goto cleanup3; + } else { + status = _cairo_recording_surface_replay_with_transform (source, + &pattern->matrix, + &tmp->base, + surface_is_unbounded, + replay_all); + if (unlikely (status)) + goto cleanup3; + } + + if (surface->target->backend->analyze_recording_surface) { + status = surface->target->backend->analyze_recording_surface ( + surface->target, + surface_pattern, + surface->create_region_ids ? *regions_id : 0, + source_type, + FALSE); + if (unlikely (status)) + goto cleanup3; + } + + /* black background or mime data fills entire extents */ + if (!(source->content & CAIRO_CONTENT_ALPHA) || _cairo_surface_has_mime_image (source)) { + cairo_rectangle_int_t rect; + + if (_cairo_surface_get_extents (source, &rect)) { + cairo_box_t bbox; + + _cairo_box_from_rectangle (&bbox, &rect); + _cairo_matrix_transform_bounding_box_fixed (&p2d, &bbox, NULL); + _cairo_box_round_to_rectangle (&bbox, &rect); + status = _add_operation (tmp, &rect, CAIRO_INT_STATUS_SUCCESS); + if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) + status = CAIRO_INT_STATUS_SUCCESS; + if (unlikely (status)) + goto cleanup3; + } + } + + if (tmp->has_supported) { + surface->has_supported = TRUE; + unused = cairo_region_union (&surface->supported_region, &tmp->supported_region); + } + + if (tmp->has_unsupported) { + surface->has_unsupported = TRUE; + unused = cairo_region_union (&surface->fallback_region, &tmp->fallback_region); + } + + analysis_status = tmp->has_unsupported ? CAIRO_INT_STATUS_IMAGE_FALLBACK : CAIRO_INT_STATUS_SUCCESS; + if (pattern->extend != CAIRO_EXTEND_NONE) { + _cairo_unbounded_rectangle_init (extents); + } else { + status = cairo_matrix_invert (&tmp->ctm); + _cairo_matrix_transform_bounding_box_fixed (&tmp->ctm, + &tmp->page_bbox, NULL); + _cairo_box_round_to_rectangle (&tmp->page_bbox, extents); + } + + cleanup3: + if (surface->create_region_ids && unlikely (status)) { + _cairo_recording_surface_region_array_remove (source, *regions_id); + } + cleanup2: + detach_proxy (proxy); + cleanup1: + cairo_surface_destroy (&tmp->base); + + if (unlikely (status)) + return status; + else + return analysis_status; +} + +static cairo_status_t +_cairo_analysis_surface_finish (void *abstract_surface) +{ + cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface; + + _cairo_region_fini (&surface->supported_region); + _cairo_region_fini (&surface->fallback_region); + + cairo_surface_destroy (surface->target); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_bool_t +_cairo_analysis_surface_get_extents (void *abstract_surface, + cairo_rectangle_int_t *rectangle) +{ + cairo_analysis_surface_t *surface = abstract_surface; + + return _cairo_surface_get_extents (surface->target, rectangle); +} + +static void +_rectangle_intersect_clip (cairo_rectangle_int_t *extents, const cairo_clip_t *clip) +{ + if (clip != NULL) + _cairo_rectangle_intersect (extents, _cairo_clip_get_extents (clip)); +} + +static void +_cairo_analysis_surface_operation_extents (cairo_analysis_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip, + cairo_rectangle_int_t *extents) +{ + cairo_bool_t is_empty; + + is_empty = _cairo_surface_get_extents (&surface->base, extents); + + if (_cairo_operator_bounded_by_source (op)) { + cairo_rectangle_int_t source_extents; + + _cairo_pattern_get_extents (source, &source_extents, surface->target->is_vector); + _cairo_rectangle_intersect (extents, &source_extents); + } + + _rectangle_intersect_clip (extents, clip); +} + +static cairo_int_status_t +_cairo_analysis_surface_paint (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip) +{ + cairo_analysis_surface_t *surface = abstract_surface; + cairo_int_status_t backend_status; + cairo_rectangle_int_t extents; + + surface->source_region_id = 0; + surface->mask_region_id = 0; + if (surface->target->backend->paint == NULL) { + backend_status = CAIRO_INT_STATUS_UNSUPPORTED; + } else { + backend_status = + surface->target->backend->paint (surface->target, + op, source, clip); + if (_cairo_int_status_is_error (backend_status)) + return backend_status; + } + + _cairo_analysis_surface_operation_extents (surface, + op, source, clip, + &extents); + if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) { + cairo_rectangle_int_t rec_extents; + backend_status = _analyze_recording_surface_pattern (surface, + source, + &rec_extents, + &surface->source_region_id, + CAIRO_ANALYSIS_SOURCE_PAINT); + _cairo_rectangle_intersect (&extents, &rec_extents); + } + + return _add_operation (surface, &extents, backend_status); +} + +static cairo_int_status_t +_cairo_analysis_surface_mask (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_clip_t *clip) +{ + cairo_analysis_surface_t *surface = abstract_surface; + cairo_int_status_t backend_status; + cairo_rectangle_int_t extents; + + surface->source_region_id = 0; + surface->mask_region_id = 0; + if (surface->target->backend->mask == NULL) { + backend_status = CAIRO_INT_STATUS_UNSUPPORTED; + } else { + backend_status = + surface->target->backend->mask (surface->target, + op, source, mask, clip); + if (_cairo_int_status_is_error (backend_status)) + return backend_status; + } + + _cairo_analysis_surface_operation_extents (surface, + op, source, clip, + &extents); + if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) { + cairo_int_status_t backend_source_status = CAIRO_STATUS_SUCCESS; + cairo_int_status_t backend_mask_status = CAIRO_STATUS_SUCCESS; + cairo_rectangle_int_t rec_extents; + + if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { + cairo_surface_t *src_surface = ((cairo_surface_pattern_t *)source)->surface; + src_surface = _cairo_surface_get_source (src_surface, NULL); + if (_cairo_surface_is_recording (src_surface)) { + backend_source_status = + _analyze_recording_surface_pattern (surface, + source, + &rec_extents, + &surface->source_region_id, + CAIRO_ANALYSIS_SOURCE_MASK); + if (_cairo_int_status_is_error (backend_source_status)) + return backend_source_status; + + _cairo_rectangle_intersect (&extents, &rec_extents); + } + } + + if (mask->type == CAIRO_PATTERN_TYPE_SURFACE) { + cairo_surface_t *mask_surface = ((cairo_surface_pattern_t *)mask)->surface; + mask_surface = _cairo_surface_get_source (mask_surface, NULL); + if (_cairo_surface_is_recording (mask_surface)) { + backend_mask_status = + _analyze_recording_surface_pattern (surface, + mask, + &rec_extents, + &surface->mask_region_id, + CAIRO_ANALYSIS_MASK_MASK); + if (_cairo_int_status_is_error (backend_mask_status)) + return backend_mask_status; + + _cairo_rectangle_intersect (&extents, &rec_extents); + } + } + + backend_status = + _cairo_analysis_surface_merge_status (backend_source_status, + backend_mask_status); + } + + if (_cairo_operator_bounded_by_mask (op)) { + cairo_rectangle_int_t mask_extents; + + _cairo_pattern_get_extents (mask, &mask_extents, surface->target->is_vector); + _cairo_rectangle_intersect (&extents, &mask_extents); + } + + return _add_operation (surface, &extents, backend_status); +} + +static cairo_int_status_t +_cairo_analysis_surface_stroke (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_analysis_surface_t *surface = abstract_surface; + cairo_int_status_t backend_status; + cairo_rectangle_int_t extents; + + surface->source_region_id = 0; + surface->mask_region_id = 0; + if (surface->target->backend->stroke == NULL) { + backend_status = CAIRO_INT_STATUS_UNSUPPORTED; + } else { + backend_status = + surface->target->backend->stroke (surface->target, op, + source, path, style, + ctm, ctm_inverse, + tolerance, antialias, + clip); + if (_cairo_int_status_is_error (backend_status)) + return backend_status; + } + + _cairo_analysis_surface_operation_extents (surface, + op, source, clip, + &extents); + if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) { + cairo_rectangle_int_t rec_extents; + backend_status = _analyze_recording_surface_pattern (surface, + source, + &rec_extents, + &surface->source_region_id, + CAIRO_ANALYSIS_SOURCE_STROKE); + _cairo_rectangle_intersect (&extents, &rec_extents); + } + + if (_cairo_operator_bounded_by_mask (op)) { + cairo_rectangle_int_t mask_extents; + cairo_int_status_t status; + + status = _cairo_path_fixed_stroke_extents (path, style, + ctm, ctm_inverse, + tolerance, + &mask_extents); + if (unlikely (status)) + return status; + + _cairo_rectangle_intersect (&extents, &mask_extents); + } + + return _add_operation (surface, &extents, backend_status); +} + +static cairo_int_status_t +_cairo_analysis_surface_fill (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_analysis_surface_t *surface = abstract_surface; + cairo_int_status_t backend_status; + cairo_rectangle_int_t extents; + + if (surface->target->backend->fill == NULL) { + backend_status = CAIRO_INT_STATUS_UNSUPPORTED; + } else { + backend_status = + surface->target->backend->fill (surface->target, op, + source, path, fill_rule, + tolerance, antialias, + clip); + if (_cairo_int_status_is_error (backend_status)) + return backend_status; + } + + _cairo_analysis_surface_operation_extents (surface, + op, source, clip, + &extents); + if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) { + cairo_rectangle_int_t rec_extents; + backend_status = _analyze_recording_surface_pattern (surface, + source, + &rec_extents, + &surface->source_region_id, + CAIRO_ANALYSIS_SOURCE_FILL); + _cairo_rectangle_intersect (&extents, &rec_extents); + } + + if (_cairo_operator_bounded_by_mask (op)) { + cairo_rectangle_int_t mask_extents; + + _cairo_path_fixed_fill_extents (path, fill_rule, tolerance, + &mask_extents); + + _cairo_rectangle_intersect (&extents, &mask_extents); + } + + return _add_operation (surface, &extents, backend_status); +} + +static cairo_int_status_t +_cairo_analysis_surface_show_glyphs (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip) +{ + cairo_analysis_surface_t *surface = abstract_surface; + cairo_int_status_t status, backend_status; + cairo_rectangle_int_t extents, glyph_extents; + + surface->source_region_id = 0; + surface->mask_region_id = 0; + + /* Adapted from _cairo_surface_show_glyphs */ + if (surface->target->backend->show_glyphs != NULL) { + backend_status = + surface->target->backend->show_glyphs (surface->target, op, + source, + glyphs, num_glyphs, + scaled_font, + clip); + if (_cairo_int_status_is_error (backend_status)) + return backend_status; + } + else if (surface->target->backend->show_text_glyphs != NULL) + { + backend_status = + surface->target->backend->show_text_glyphs (surface->target, op, + source, + NULL, 0, + glyphs, num_glyphs, + NULL, 0, + FALSE, + scaled_font, + clip); + if (_cairo_int_status_is_error (backend_status)) + return backend_status; + } + else + { + backend_status = CAIRO_INT_STATUS_UNSUPPORTED; + } + + _cairo_analysis_surface_operation_extents (surface, + op, source, clip, + &extents); + if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) { + cairo_rectangle_int_t rec_extents; + backend_status = _analyze_recording_surface_pattern (surface, + source, + &rec_extents, + &surface->source_region_id, + CAIRO_ANALYSIS_SOURCE_SHOW_GLYPHS); + _cairo_rectangle_intersect (&extents, &rec_extents); + } + + if (_cairo_operator_bounded_by_mask (op)) { + status = _cairo_scaled_font_glyph_device_extents (scaled_font, + glyphs, + num_glyphs, + &glyph_extents, + NULL); + if (unlikely (status)) + return status; + + _cairo_rectangle_intersect (&extents, &glyph_extents); + } + + return _add_operation (surface, &extents, backend_status); +} + +static cairo_bool_t +_cairo_analysis_surface_has_show_text_glyphs (void *abstract_surface) +{ + cairo_analysis_surface_t *surface = abstract_surface; + + return cairo_surface_has_show_text_glyphs (surface->target); +} + +static cairo_int_status_t +_cairo_analysis_surface_show_text_glyphs (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const char *utf8, + int utf8_len, + cairo_glyph_t *glyphs, + int num_glyphs, + const cairo_text_cluster_t *clusters, + int num_clusters, + cairo_text_cluster_flags_t cluster_flags, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip) +{ + cairo_analysis_surface_t *surface = abstract_surface; + cairo_int_status_t status, backend_status; + cairo_rectangle_int_t extents, glyph_extents; + + surface->source_region_id = 0; + surface->mask_region_id = 0; + + /* Adapted from _cairo_surface_show_glyphs */ + backend_status = CAIRO_INT_STATUS_UNSUPPORTED; + if (surface->target->backend->show_text_glyphs != NULL) { + backend_status = + surface->target->backend->show_text_glyphs (surface->target, op, + source, + utf8, utf8_len, + glyphs, num_glyphs, + clusters, num_clusters, + cluster_flags, + scaled_font, + clip); + if (_cairo_int_status_is_error (backend_status)) + return backend_status; + } + if (backend_status == CAIRO_INT_STATUS_UNSUPPORTED && + surface->target->backend->show_glyphs != NULL) + { + backend_status = + surface->target->backend->show_glyphs (surface->target, op, + source, + glyphs, num_glyphs, + scaled_font, + clip); + if (_cairo_int_status_is_error (backend_status)) + return backend_status; + } + + _cairo_analysis_surface_operation_extents (surface, + op, source, clip, + &extents); + if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) { + cairo_rectangle_int_t rec_extents; + _analyze_recording_surface_pattern (surface, + source, + &rec_extents, + &surface->source_region_id, + CAIRO_ANALYSIS_SOURCE_SHOW_GLYPHS); + _cairo_rectangle_intersect (&extents, &rec_extents); + } + + if (_cairo_operator_bounded_by_mask (op)) { + status = _cairo_scaled_font_glyph_device_extents (scaled_font, + glyphs, + num_glyphs, + &glyph_extents, + NULL); + if (unlikely (status)) + return status; + + _cairo_rectangle_intersect (&extents, &glyph_extents); + } + + return _add_operation (surface, &extents, backend_status); +} + +static cairo_int_status_t +_cairo_analysis_surface_tag (void *abstract_surface, + cairo_bool_t begin, + const char *tag_name, + const char *attributes) +{ + cairo_analysis_surface_t *surface = abstract_surface; + cairo_int_status_t backend_status; + + surface->source_region_id = 0; + surface->mask_region_id = 0; + backend_status = CAIRO_INT_STATUS_SUCCESS; + if (surface->target->backend->tag != NULL) { + backend_status = + surface->target->backend->tag (surface->target, + begin, + tag_name, + attributes); + if (backend_status == CAIRO_INT_STATUS_SUCCESS) + surface->has_supported = TRUE; + } + + return backend_status; +} + +static cairo_bool_t +_cairo_analysis_surface_supports_color_glyph (void *abstract_surface, + cairo_scaled_font_t *scaled_font, + unsigned long glyph_index) +{ + return TRUE; +} + +static cairo_int_status_t +_cairo_analysis_surface_command_id (void *abstract_surface, + unsigned int recording_id, + unsigned int command_id) +{ + cairo_analysis_surface_t *surface = abstract_surface; + cairo_int_status_t backend_status; + + backend_status = CAIRO_INT_STATUS_SUCCESS; + if (surface->target->backend->command_id != NULL) { + backend_status = + surface->target->backend->command_id (surface->target, + recording_id, + command_id); + } + + return backend_status; +} + +static const cairo_surface_backend_t cairo_analysis_surface_backend = { + CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS, + + _cairo_analysis_surface_finish, + NULL, + + NULL, /* create_similar */ + NULL, /* create_similar_image */ + NULL, /* map_to_image */ + NULL, /* unmap */ + + NULL, /* source */ + NULL, /* acquire_source_image */ + NULL, /* release_source_image */ + NULL, /* snapshot */ + + NULL, /* copy_page */ + NULL, /* show_page */ + + _cairo_analysis_surface_get_extents, + NULL, /* get_font_options */ + + NULL, /* flush */ + NULL, /* mark_dirty_rectangle */ + + _cairo_analysis_surface_paint, + _cairo_analysis_surface_mask, + _cairo_analysis_surface_stroke, + _cairo_analysis_surface_fill, + NULL, /* fill_stroke */ + _cairo_analysis_surface_show_glyphs, + _cairo_analysis_surface_has_show_text_glyphs, + _cairo_analysis_surface_show_text_glyphs, + NULL, /* get_supported_mime_types */ + _cairo_analysis_surface_tag, + _cairo_analysis_surface_supports_color_glyph, + NULL, /* analyze_recording_surface */ + _cairo_analysis_surface_command_id, +}; + +cairo_surface_t * +_cairo_analysis_surface_create (cairo_surface_t *target, + cairo_bool_t create_region_ids) +{ + cairo_analysis_surface_t *surface; + cairo_status_t status; + + status = target->status; + if (unlikely (status)) + return _cairo_surface_create_in_error (status); + + surface = _cairo_calloc (sizeof (cairo_analysis_surface_t)); + if (unlikely (surface == NULL)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + /* I believe the content type here is truly arbitrary. I'm quite + * sure nothing will ever use this value. */ + _cairo_surface_init (&surface->base, + &cairo_analysis_surface_backend, + NULL, /* device */ + CAIRO_CONTENT_COLOR_ALPHA, + target->is_vector); + + cairo_matrix_init_identity (&surface->ctm); + surface->has_ctm = FALSE; + + surface->target = cairo_surface_reference (target); + surface->first_op = TRUE; + surface->has_supported = FALSE; + surface->has_unsupported = FALSE; + + surface->create_region_ids = create_region_ids; + surface->source_region_id = 0; + surface->mask_region_id = 0; + + _cairo_region_init (&surface->supported_region); + _cairo_region_init (&surface->fallback_region); + + surface->page_bbox.p1.x = 0; + surface->page_bbox.p1.y = 0; + surface->page_bbox.p2.x = 0; + surface->page_bbox.p2.y = 0; + + return &surface->base; +} + +void +_cairo_analysis_surface_set_ctm (cairo_surface_t *abstract_surface, + const cairo_matrix_t *ctm) +{ + cairo_analysis_surface_t *surface; + + if (abstract_surface->status) + return; + + surface = (cairo_analysis_surface_t *) abstract_surface; + + surface->ctm = *ctm; + surface->has_ctm = ! _cairo_matrix_is_identity (&surface->ctm); +} + +void +_cairo_analysis_surface_get_ctm (cairo_surface_t *abstract_surface, + cairo_matrix_t *ctm) +{ + cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface; + + *ctm = surface->ctm; +} + + +cairo_region_t * +_cairo_analysis_surface_get_supported (cairo_surface_t *abstract_surface) +{ + cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface; + + return &surface->supported_region; +} + +cairo_region_t * +_cairo_analysis_surface_get_unsupported (cairo_surface_t *abstract_surface) +{ + cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface; + + return &surface->fallback_region; +} + +cairo_bool_t +_cairo_analysis_surface_has_supported (cairo_surface_t *abstract_surface) +{ + cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface; + + return surface->has_supported; +} + +cairo_bool_t +_cairo_analysis_surface_has_unsupported (cairo_surface_t *abstract_surface) +{ + cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface; + + return surface->has_unsupported; +} + +void +_cairo_analysis_surface_get_bounding_box (cairo_surface_t *abstract_surface, + cairo_box_t *bbox) +{ + cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface; + + *bbox = surface->page_bbox; +} + +unsigned int +_cairo_analysis_surface_get_source_region_id (cairo_surface_t *abstract_surface) +{ + cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface; + + return surface->source_region_id; +} + +unsigned int +_cairo_analysis_surface_get_mask_region_id (cairo_surface_t *abstract_surface) +{ + cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface; + + return surface->mask_region_id; +} + + +/* null surface type: a surface that does nothing (has no side effects, yay!) */ + +static cairo_int_status_t +_paint_return_success (void *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip) +{ + if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { + cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source; + if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) + return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN; + } + + return CAIRO_INT_STATUS_SUCCESS; +} + +static cairo_int_status_t +_mask_return_success (void *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_clip_t *clip) +{ + if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { + cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source; + if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) + return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN; + } + + if (mask->type == CAIRO_PATTERN_TYPE_SURFACE) { + cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) mask; + if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) + return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN; + } + + return CAIRO_INT_STATUS_SUCCESS; +} + +static cairo_int_status_t +_stroke_return_success (void *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { + cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source; + if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) + return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN; + } + + return CAIRO_INT_STATUS_SUCCESS; +} + +static cairo_int_status_t +_fill_return_success (void *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { + cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source; + if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) + return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN; + } + + return CAIRO_INT_STATUS_SUCCESS; +} + +static cairo_int_status_t +_show_glyphs_return_success (void *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip) +{ + if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { + cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source; + if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) + return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN; + } + + return CAIRO_INT_STATUS_SUCCESS; +} + +static const cairo_surface_backend_t cairo_null_surface_backend = { + CAIRO_INTERNAL_SURFACE_TYPE_NULL, + NULL, /* finish */ + + NULL, /* only accessed through the surface functions */ + + NULL, /* create_similar */ + NULL, /* create similar image */ + NULL, /* map to image */ + NULL, /* unmap image*/ + + NULL, /* source */ + NULL, /* acquire_source_image */ + NULL, /* release_source_image */ + NULL, /* snapshot */ + + NULL, /* copy_page */ + NULL, /* show_page */ + + NULL, /* get_extents */ + NULL, /* get_font_options */ + + NULL, /* flush */ + NULL, /* mark_dirty_rectangle */ + + _paint_return_success, /* paint */ + _mask_return_success, /* mask */ + _stroke_return_success, /* stroke */ + _fill_return_success, /* fill */ + NULL, /* fill_stroke */ + _show_glyphs_return_success, /* show_glyphs */ + NULL, /* has_show_text_glyphs */ + NULL, /* show_text_glyphs */ + NULL, /* get_supported_mime_types */ + NULL, /* tag */ + NULL, /* supports_color_glyph */ + NULL, /* analyze_recording_surface */ + NULL, /* command_id*/ +}; + +cairo_surface_t * +_cairo_null_surface_create (cairo_content_t content) +{ + cairo_surface_t *surface; + + surface = _cairo_calloc (sizeof (cairo_surface_t)); + if (unlikely (surface == NULL)) { + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + } + + _cairo_surface_init (surface, + &cairo_null_surface_backend, + NULL, /* device */ + content, + TRUE); /* is_vector */ + + return surface; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-arc-private.h b/local/recipes/libs/cairo/source/src/cairo-arc-private.h new file mode 100644 index 0000000000..a22c01ac90 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-arc-private.h @@ -0,0 +1,61 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Carl D. Worth + */ + +#ifndef CAIRO_ARC_PRIVATE_H +#define CAIRO_ARC_PRIVATE_H + +#include "cairoint.h" + +CAIRO_BEGIN_DECLS + +cairo_private void +_cairo_arc_path (cairo_t *cr, + double xc, + double yc, + double radius, + double angle1, + double angle2); + +cairo_private void +_cairo_arc_path_negative (cairo_t *cr, + double xc, + double yc, + double radius, + double angle1, + double angle2); + +CAIRO_END_DECLS + +#endif /* CAIRO_ARC_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-arc.c b/local/recipes/libs/cairo/source/src/cairo-arc.c new file mode 100644 index 0000000000..010b9c1a7a --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-arc.c @@ -0,0 +1,317 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + */ + +#include "cairoint.h" + +#include "cairo-arc-private.h" + +#define MAX_FULL_CIRCLES 65536 + +/* Spline deviation from the circle in radius would be given by: + + error = sqrt (x**2 + y**2) - 1 + + A simpler error function to work with is: + + e = x**2 + y**2 - 1 + + From "Good approximation of circles by curvature-continuous Bezier + curves", Tor Dokken and Morten Daehlen, Computer Aided Geometric + Design 8 (1990) 22-41, we learn: + + abs (max(e)) = 4/27 * sin**6(angle/4) / cos**2(angle/4) + + and + abs (error) =~ 1/2 * e + + Of course, this error value applies only for the particular spline + approximation that is used in _cairo_gstate_arc_segment. +*/ +static double +_arc_error_normalized (double angle) +{ + return 2.0/27.0 * pow (sin (angle / 4), 6) / pow (cos (angle / 4), 2); +} + +static double +_arc_max_angle_for_tolerance_normalized (double tolerance) +{ + double angle, error; + int i; + + /* Use table lookup to reduce search time in most cases. */ + struct { + double angle; + double error; + } table[] = { + { M_PI / 1.0, 0.0185185185185185036127 }, + { M_PI / 2.0, 0.000272567143730179811158 }, + { M_PI / 3.0, 2.38647043651461047433e-05 }, + { M_PI / 4.0, 4.2455377443222443279e-06 }, + { M_PI / 5.0, 1.11281001494389081528e-06 }, + { M_PI / 6.0, 3.72662000942734705475e-07 }, + { M_PI / 7.0, 1.47783685574284411325e-07 }, + { M_PI / 8.0, 6.63240432022601149057e-08 }, + { M_PI / 9.0, 3.2715520137536980553e-08 }, + { M_PI / 10.0, 1.73863223499021216974e-08 }, + { M_PI / 11.0, 9.81410988043554039085e-09 }, + }; + int table_size = ARRAY_LENGTH (table); + const int max_segments = 1000; /* this value is chosen arbitrarily. this gives an error of about 1.74909e-20 */ + + for (i = 0; i < table_size; i++) + if (table[i].error < tolerance) + return table[i].angle; + + ++i; + + do { + angle = M_PI / i++; + error = _arc_error_normalized (angle); + } while (error > tolerance && i < max_segments); + + return angle; +} + +static int +_arc_segments_needed (double angle, + double radius, + cairo_matrix_t *ctm, + double tolerance) +{ + double major_axis, max_angle; + + /* the error is amplified by at most the length of the + * major axis of the circle; see cairo-pen.c for a more detailed analysis + * of this. */ + major_axis = _cairo_matrix_transformed_circle_major_axis (ctm, radius); + max_angle = _arc_max_angle_for_tolerance_normalized (tolerance / major_axis); + + return ceil (fabs (angle) / max_angle); +} + +/* We want to draw a single spline approximating a circular arc radius + R from angle A to angle B. Since we want a symmetric spline that + matches the endpoints of the arc in position and slope, we know + that the spline control points must be: + + (R * cos(A), R * sin(A)) + (R * cos(A) - h * sin(A), R * sin(A) + h * cos (A)) + (R * cos(B) + h * sin(B), R * sin(B) - h * cos (B)) + (R * cos(B), R * sin(B)) + + for some value of h. + + "Approximation of circular arcs by cubic polynomials", Michael + Goldapp, Computer Aided Geometric Design 8 (1991) 227-238, provides + various values of h along with error analysis for each. + + From that paper, a very practical value of h is: + + h = 4/3 * R * tan(angle/4) + + This value does not give the spline with minimal error, but it does + provide a very good approximation, (6th-order convergence), and the + error expression is quite simple, (see the comment for + _arc_error_normalized). +*/ +static void +_cairo_arc_segment (cairo_t *cr, + double xc, + double yc, + double radius, + double angle_A, + double angle_B) +{ + double r_sin_A, r_cos_A; + double r_sin_B, r_cos_B; + double h; + + r_sin_A = radius * sin (angle_A); + r_cos_A = radius * cos (angle_A); + r_sin_B = radius * sin (angle_B); + r_cos_B = radius * cos (angle_B); + + h = 4.0/3.0 * tan ((angle_B - angle_A) / 4.0); + + cairo_curve_to (cr, + xc + r_cos_A - h * r_sin_A, + yc + r_sin_A + h * r_cos_A, + xc + r_cos_B + h * r_sin_B, + yc + r_sin_B - h * r_cos_B, + xc + r_cos_B, + yc + r_sin_B); +} + +static void +_cairo_arc_in_direction (cairo_t *cr, + double xc, + double yc, + double radius, + double angle_min, + double angle_max, + cairo_direction_t dir) +{ + if (cairo_status (cr)) + return; + + if (! ISFINITE (angle_max) || ! ISFINITE (angle_min)) + return; + + assert (angle_max >= angle_min); + + if (angle_max - angle_min > 2 * M_PI * MAX_FULL_CIRCLES) { + angle_max = fmod (angle_max - angle_min, 2 * M_PI); + angle_min = fmod (angle_min, 2 * M_PI); + angle_max += angle_min + 2 * M_PI * MAX_FULL_CIRCLES; + } + + /* Recurse if drawing arc larger than pi */ + if (angle_max - angle_min > M_PI) { + double angle_mid = angle_min + (angle_max - angle_min) / 2.0; + if (dir == CAIRO_DIRECTION_FORWARD) { + _cairo_arc_in_direction (cr, xc, yc, radius, + angle_min, angle_mid, + dir); + + _cairo_arc_in_direction (cr, xc, yc, radius, + angle_mid, angle_max, + dir); + } else { + _cairo_arc_in_direction (cr, xc, yc, radius, + angle_mid, angle_max, + dir); + + _cairo_arc_in_direction (cr, xc, yc, radius, + angle_min, angle_mid, + dir); + } + } else if (angle_max != angle_min) { + cairo_matrix_t ctm; + int i, segments; + double step; + + cairo_get_matrix (cr, &ctm); + segments = _arc_segments_needed (angle_max - angle_min, + radius, &ctm, + cairo_get_tolerance (cr)); + step = (angle_max - angle_min) / segments; + segments -= 1; + + if (dir == CAIRO_DIRECTION_REVERSE) { + double t; + + t = angle_min; + angle_min = angle_max; + angle_max = t; + + step = -step; + } + + cairo_line_to (cr, + xc + radius * cos (angle_min), + yc + radius * sin (angle_min)); + + for (i = 0; i < segments; i++, angle_min += step) { + _cairo_arc_segment (cr, xc, yc, radius, + angle_min, angle_min + step); + } + + _cairo_arc_segment (cr, xc, yc, radius, + angle_min, angle_max); + } else { + cairo_line_to (cr, + xc + radius * cos (angle_min), + yc + radius * sin (angle_min)); + } +} + +/** + * _cairo_arc_path: + * @cr: a cairo context + * @xc: X position of the center of the arc + * @yc: Y position of the center of the arc + * @radius: the radius of the arc + * @angle1: the start angle, in radians + * @angle2: the end angle, in radians + * + * Compute a path for the given arc and append it onto the current + * path within @cr. The arc will be accurate within the current + * tolerance and given the current transformation. + **/ +void +_cairo_arc_path (cairo_t *cr, + double xc, + double yc, + double radius, + double angle1, + double angle2) +{ + _cairo_arc_in_direction (cr, xc, yc, + radius, + angle1, angle2, + CAIRO_DIRECTION_FORWARD); +} + +/** + * _cairo_arc_path_negative: + * @xc: X position of the center of the arc + * @yc: Y position of the center of the arc + * @radius: the radius of the arc + * @angle1: the start angle, in radians + * @angle2: the end angle, in radians + * @ctm: the current transformation matrix + * @tolerance: the current tolerance value + * @path: the path onto which the arc will be appended + * + * Compute a path for the given arc (defined in the negative + * direction) and append it onto the current path within @cr. The arc + * will be accurate within the current tolerance and given the current + * transformation. + **/ +void +_cairo_arc_path_negative (cairo_t *cr, + double xc, + double yc, + double radius, + double angle1, + double angle2) +{ + _cairo_arc_in_direction (cr, xc, yc, + radius, + angle2, angle1, + CAIRO_DIRECTION_REVERSE); +} diff --git a/local/recipes/libs/cairo/source/src/cairo-array-private.h b/local/recipes/libs/cairo/source/src/cairo-array-private.h new file mode 100644 index 0000000000..ff5b51f504 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-array-private.h @@ -0,0 +1,100 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + */ + +#ifndef CAIRO_ARRAY_PRIVATE_H +#define CAIRO_ARRAY_PRIVATE_H + +#include "cairo-compiler-private.h" +#include "cairo-types-private.h" + +CAIRO_BEGIN_DECLS + +/* cairo-array.c structures and functions */ + +cairo_private void +_cairo_array_init (cairo_array_t *array, unsigned int element_size); + +cairo_private void +_cairo_array_fini (cairo_array_t *array); + +cairo_private cairo_status_t +_cairo_array_grow_by (cairo_array_t *array, unsigned int additional); + +cairo_private void +_cairo_array_truncate (cairo_array_t *array, unsigned int num_elements); + +cairo_private cairo_status_t +_cairo_array_append (cairo_array_t *array, const void *element); + +cairo_private cairo_status_t +_cairo_array_append_multiple (cairo_array_t *array, + const void *elements, + unsigned int num_elements); + +cairo_private cairo_status_t +_cairo_array_allocate (cairo_array_t *array, + unsigned int num_elements, + void **elements); + +cairo_private void * +_cairo_array_index (cairo_array_t *array, unsigned int index); + +cairo_private const void * +_cairo_array_index_const (const cairo_array_t *array, unsigned int index); + +cairo_private void +_cairo_array_copy_element (const cairo_array_t *array, unsigned int index, void *dst); + +cairo_private unsigned int +_cairo_array_num_elements (const cairo_array_t *array); + +cairo_private unsigned int +_cairo_array_size (const cairo_array_t *array); + +cairo_private void +_cairo_array_sort (const cairo_array_t *array, int (*compar)(const void *, const void *)); + +cairo_private cairo_bool_t +_cairo_array_pop_element (cairo_array_t *array, void *dst); + +cairo_private void * +_cairo_array_last_element (cairo_array_t *array); + +CAIRO_END_DECLS + +#endif /* CAIRO_ARRAY_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-array.c b/local/recipes/libs/cairo/source/src/cairo-array.c new file mode 100644 index 0000000000..a4a4f8c846 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-array.c @@ -0,0 +1,580 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2004 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Kristian Høgsberg + * Carl Worth + */ + +#include "cairoint.h" +#include "cairo-array-private.h" +#include "cairo-error-private.h" + +/*< private > + * _cairo_array_init: + * + * Initialize a new #cairo_array_t object to store objects each of size + * @element_size. + * + * The #cairo_array_t object provides grow-by-doubling storage. It + * never interprets the data passed to it, nor does it provide any + * sort of callback mechanism for freeing resources held onto by + * stored objects. + * + * When finished using the array, _cairo_array_fini() should be + * called to free resources allocated during use of the array. + **/ +void +_cairo_array_init (cairo_array_t *array, unsigned int element_size) +{ + array->size = 0; + array->num_elements = 0; + array->element_size = element_size; + array->elements = NULL; +} + +/*< private > + * _cairo_array_fini: + * @array: A #cairo_array_t + * + * Free all resources associated with @array. After this call, @array + * should not be used again without a subsequent call to + * _cairo_array_init() again first. + **/ +void +_cairo_array_fini (cairo_array_t *array) +{ + free (array->elements); +} + +/*< private > + * _cairo_array_grow_by: + * @array: a #cairo_array_t + * + * Increase the size of @array (if needed) so that there are at least + * @additional free spaces in the array. The actual size of the array + * is always increased by doubling as many times as necessary. + **/ +cairo_status_t +_cairo_array_grow_by (cairo_array_t *array, unsigned int additional) +{ + char *new_elements; + unsigned int old_size = array->size; + unsigned int required_size = array->num_elements + additional; + unsigned int new_size; + + /* check for integer overflow */ + if (required_size > INT_MAX || required_size < array->num_elements) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + if (CAIRO_INJECT_FAULT ()) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + if (required_size <= old_size) + return CAIRO_STATUS_SUCCESS; + + if (old_size == 0) + new_size = 1; + else + new_size = old_size * 2; + + while (new_size < required_size) + new_size = new_size * 2; + + array->size = new_size; + new_elements = _cairo_realloc_ab (array->elements, + array->size, array->element_size); + + if (unlikely (new_elements == NULL)) { + array->size = old_size; + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + array->elements = new_elements; + + return CAIRO_STATUS_SUCCESS; +} + +/*< private > + * _cairo_array_truncate: + * @array: a #cairo_array_t + * + * Truncate size of the array to @num_elements if less than the + * current size. No memory is actually freed. The stored objects + * beyond @num_elements are simply "forgotten". + **/ +void +_cairo_array_truncate (cairo_array_t *array, unsigned int num_elements) +{ + if (num_elements < array->num_elements) + array->num_elements = num_elements; +} + +/*< private > + * _cairo_array_index: + * @array: a #cairo_array_t + * + * If the resulting value is assigned to a pointer to an object of the same + * element_size as initially passed to _cairo_array_init() then that + * pointer may be used for further direct indexing with []. For + * example: + * + * |[ + * cairo_array_t array; + * double *values; + * + * _cairo_array_init (&array, sizeof(double)); + * ... calls to _cairo_array_append() here ... + * + * values = _cairo_array_index (&array, 0); + * for (i = 0; i < _cairo_array_num_elements (&array); i++) + * ... use values[i] here ... + * ]| + * + * Returns: A pointer to the object stored at @index. + **/ +void * +_cairo_array_index (cairo_array_t *array, unsigned int index) +{ + /* We allow an index of 0 for the no-elements case. + * This makes for cleaner calling code which will often look like: + * + * elements = _cairo_array_index (array, 0); + * for (i=0; i < num_elements; i++) { + * ... use elements[i] here ... + * } + * + * which in the num_elements==0 case gets the NULL pointer here, + * but never dereferences it. + */ + if (index == 0 && array->num_elements == 0) + return NULL; + + assert (index < array->num_elements); + + return array->elements + (size_t)index * array->element_size; +} + +/*< private > + * _cairo_array_index_const: + * @array: a #cairo_array_t + * + * If the resulting value is assigned to a pointer to an object of the same + * element_size as initially passed to _cairo_array_init() then that + * pointer may be used for further direct indexing with []. For + * example: + * + * |[), + * or implicitly using the toy text API by way of + * cairo_select_font_face(). The resulting face can be accessed using + * cairo_get_font_face(). + **/ + +/* #cairo_font_face_t */ + +const cairo_font_face_t _cairo_font_face_nil = { + { 0 }, /* hash_entry */ + CAIRO_STATUS_NO_MEMORY, /* status */ + CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ + { 0, 0, 0, NULL }, /* user_data */ + NULL +}; +const cairo_font_face_t _cairo_font_face_nil_file_not_found = { + { 0 }, /* hash_entry */ + CAIRO_STATUS_FILE_NOT_FOUND, /* status */ + CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ + { 0, 0, 0, NULL }, /* user_data */ + NULL +}; + +cairo_status_t +_cairo_font_face_set_error (cairo_font_face_t *font_face, + cairo_status_t status) +{ + if (status == CAIRO_STATUS_SUCCESS) + return status; + + /* Don't overwrite an existing error. This preserves the first + * error, which is the most significant. */ + _cairo_status_set_error (&font_face->status, status); + + return _cairo_error (status); +} + +void +_cairo_font_face_init (cairo_font_face_t *font_face, + const cairo_font_face_backend_t *backend) +{ + CAIRO_MUTEX_INITIALIZE (); + + font_face->status = CAIRO_STATUS_SUCCESS; + CAIRO_REFERENCE_COUNT_INIT (&font_face->ref_count, 1); + font_face->backend = backend; + + _cairo_user_data_array_init (&font_face->user_data); +} + +/** + * cairo_font_face_reference: + * @font_face: a #cairo_font_face_t, (may be %NULL in which case this + * function does nothing). + * + * Increases the reference count on @font_face by one. This prevents + * @font_face from being destroyed until a matching call to + * cairo_font_face_destroy() is made. + * + * Use cairo_font_face_get_reference_count() to get the number of + * references to a #cairo_font_face_t. + * + * Return value: the referenced #cairo_font_face_t. + * + * Since: 1.0 + **/ +cairo_font_face_t * +cairo_font_face_reference (cairo_font_face_t *font_face) +{ + if (font_face == NULL || + CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count)) + return font_face; + + /* We would normally assert that we have a reference here but we + * can't get away with that due to the zombie case as documented + * in _cairo_ft_font_face_destroy. */ + + _cairo_reference_count_inc (&font_face->ref_count); + + return font_face; +} + +static inline cairo_bool_t +__put(cairo_reference_count_t *v) +{ + int c, old; + + c = CAIRO_REFERENCE_COUNT_GET_VALUE(v); + while (c != 1 && (old = _cairo_atomic_int_cmpxchg_return_old(&v->ref_count, c, c - 1)) != c) + c = old; + + return c != 1; +} + +cairo_bool_t +_cairo_font_face_destroy (void *abstract_face) +{ +#if 0 /* Nothing needs to be done, we can just drop the last reference */ + cairo_font_face_t *font_face = abstract_face; + return _cairo_reference_count_dec_and_test (&font_face->ref_count); +#endif + return TRUE; +} + +/** + * cairo_font_face_destroy: + * @font_face: a #cairo_font_face_t + * + * Decreases the reference count on @font_face by one. If the result + * is zero, then @font_face and all associated resources are freed. + * See cairo_font_face_reference(). + * + * Since: 1.0 + **/ +void +cairo_font_face_destroy (cairo_font_face_t *font_face) +{ + if (font_face == NULL || + CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count)) + return; + + assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&font_face->ref_count)); + + /* We allow resurrection to deal with some memory management for the + * FreeType backend where cairo_ft_font_face_t and cairo_ft_unscaled_font_t + * need to effectively mutually reference each other + */ + if (__put (&font_face->ref_count)) + return; + + if (! font_face->backend->destroy (font_face)) + return; + + _cairo_user_data_array_fini (&font_face->user_data); + + free (font_face); +} + +/** + * cairo_font_face_get_type: + * @font_face: a font face + * + * This function returns the type of the backend used to create + * a font face. See #cairo_font_type_t for available types. + * + * Return value: The type of @font_face. + * + * Since: 1.2 + **/ +cairo_font_type_t +cairo_font_face_get_type (cairo_font_face_t *font_face) +{ + if (CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count)) + return CAIRO_FONT_TYPE_TOY; + + return font_face->backend->type; +} + +/** + * cairo_font_face_get_reference_count: + * @font_face: a #cairo_font_face_t + * + * Returns the current reference count of @font_face. + * + * Return value: the current reference count of @font_face. If the + * object is a nil object, 0 will be returned. + * + * Since: 1.4 + **/ +unsigned int +cairo_font_face_get_reference_count (cairo_font_face_t *font_face) +{ + if (font_face == NULL || + CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count)) + return 0; + + return CAIRO_REFERENCE_COUNT_GET_VALUE (&font_face->ref_count); +} + +/** + * cairo_font_face_status: + * @font_face: a #cairo_font_face_t + * + * Checks whether an error has previously occurred for this + * font face + * + * Return value: %CAIRO_STATUS_SUCCESS or another error such as + * %CAIRO_STATUS_NO_MEMORY. + * + * Since: 1.0 + **/ +cairo_status_t +cairo_font_face_status (cairo_font_face_t *font_face) +{ + return font_face->status; +} + +/** + * cairo_font_face_get_user_data: + * @font_face: a #cairo_font_face_t + * @key: the address of the #cairo_user_data_key_t the user data was + * attached to + * + * Return user data previously attached to @font_face using the specified + * key. If no user data has been attached with the given key this + * function returns %NULL. + * + * Return value: the user data previously attached or %NULL. + * + * Since: 1.0 + **/ +void * +cairo_font_face_get_user_data (cairo_font_face_t *font_face, + const cairo_user_data_key_t *key) +{ + return _cairo_user_data_array_get_data (&font_face->user_data, + key); +} + +/** + * cairo_font_face_set_user_data: + * @font_face: a #cairo_font_face_t + * @key: the address of a #cairo_user_data_key_t to attach the user data to + * @user_data: the user data to attach to the font face + * @destroy: a #cairo_destroy_func_t which will be called when the + * font face is destroyed or when new user data is attached using the + * same key. + * + * Attach user data to @font_face. To remove user data from a font face, + * call this function with the key that was used to set it and %NULL + * for @data. + * + * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a + * slot could not be allocated for the user data. + * + * Since: 1.0 + **/ +cairo_status_t +cairo_font_face_set_user_data (cairo_font_face_t *font_face, + const cairo_user_data_key_t *key, + void *user_data, + cairo_destroy_func_t destroy) +{ + if (CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count)) + return font_face->status; + + return _cairo_user_data_array_set_data (&font_face->user_data, + key, user_data, destroy); +} + +void +_cairo_unscaled_font_init (cairo_unscaled_font_t *unscaled_font, + const cairo_unscaled_font_backend_t *backend) +{ + CAIRO_REFERENCE_COUNT_INIT (&unscaled_font->ref_count, 1); + unscaled_font->backend = backend; +} + +cairo_unscaled_font_t * +_cairo_unscaled_font_reference (cairo_unscaled_font_t *unscaled_font) +{ + if (unscaled_font == NULL) + return NULL; + + assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&unscaled_font->ref_count)); + + _cairo_reference_count_inc (&unscaled_font->ref_count); + + return unscaled_font; +} + +void +_cairo_unscaled_font_destroy (cairo_unscaled_font_t *unscaled_font) +{ + if (unscaled_font == NULL) + return; + + assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&unscaled_font->ref_count)); + + if (__put (&unscaled_font->ref_count)) + return; + + if (! unscaled_font->backend->destroy (unscaled_font)) + return; + + free (unscaled_font); +} diff --git a/local/recipes/libs/cairo/source/src/cairo-font-options.c b/local/recipes/libs/cairo/source/src/cairo-font-options.c new file mode 100644 index 0000000000..d5c6663be5 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-font-options.c @@ -0,0 +1,871 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Owen Taylor + */ + +#include "cairoint.h" +#include "cairo-error-private.h" + +/** + * SECTION:cairo-font-options + * @Title: cairo_font_options_t + * @Short_Description: How a font should be rendered + * @See_Also: #cairo_scaled_font_t + * + * The font options specify how fonts should be rendered. Most of the + * time the font options implied by a surface are just right and do not + * need any changes, but for pixel-based targets tweaking font options + * may result in superior output on a particular display. + **/ + +static const cairo_font_options_t _cairo_font_options_nil = { + CAIRO_ANTIALIAS_DEFAULT, + CAIRO_SUBPIXEL_ORDER_DEFAULT, + CAIRO_LCD_FILTER_DEFAULT, + CAIRO_HINT_STYLE_DEFAULT, + CAIRO_HINT_METRICS_DEFAULT, + CAIRO_ROUND_GLYPH_POS_DEFAULT, + NULL, /* variations */ + CAIRO_COLOR_MODE_DEFAULT, + CAIRO_COLOR_PALETTE_DEFAULT, + NULL, 0, /* custom palette */ +}; + +/** + * _cairo_font_options_init_default: + * @options: a #cairo_font_options_t + * + * Initializes all fields of the font options object to default values. + **/ +void +_cairo_font_options_init_default (cairo_font_options_t *options) +{ + options->antialias = CAIRO_ANTIALIAS_DEFAULT; + options->subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT; + options->lcd_filter = CAIRO_LCD_FILTER_DEFAULT; + options->hint_style = CAIRO_HINT_STYLE_DEFAULT; + options->hint_metrics = CAIRO_HINT_METRICS_DEFAULT; + options->round_glyph_positions = CAIRO_ROUND_GLYPH_POS_DEFAULT; + options->variations = NULL; + options->color_mode = CAIRO_COLOR_MODE_DEFAULT; + options->palette_index = CAIRO_COLOR_PALETTE_DEFAULT; + options->custom_palette = NULL; + options->custom_palette_size = 0; +} + +void +_cairo_font_options_init_copy (cairo_font_options_t *options, + const cairo_font_options_t *other) +{ + options->antialias = other->antialias; + options->subpixel_order = other->subpixel_order; + options->lcd_filter = other->lcd_filter; + options->hint_style = other->hint_style; + options->hint_metrics = other->hint_metrics; + options->round_glyph_positions = other->round_glyph_positions; + options->variations = other->variations ? strdup (other->variations) : NULL; + options->color_mode = other->color_mode; + options->palette_index = other->palette_index; + options->custom_palette_size = other->custom_palette_size; + options->custom_palette = NULL; + if (other->custom_palette) { + options->custom_palette = (cairo_palette_color_t *) malloc (sizeof (cairo_palette_color_t) * options->custom_palette_size); + memcpy (options->custom_palette, other->custom_palette, sizeof (cairo_palette_color_t) * options->custom_palette_size); + } +} + +cairo_bool_t +_cairo_font_options_compare (const cairo_font_options_t *a, + const cairo_font_options_t *b) +{ + if (a->antialias != b->antialias || + a->subpixel_order != b->subpixel_order || + a->lcd_filter != b->lcd_filter || + a->hint_style != b->hint_style || + a->hint_metrics != b->hint_metrics || + a->round_glyph_positions != b->round_glyph_positions || + a->color_mode != b->color_mode || + a->palette_index != b->palette_index || + a->custom_palette_size != b->custom_palette_size) + { + return FALSE; + } + + if (a->variations && b->variations && strcmp (a->variations, b->variations) != 0) + return FALSE; + else if (a->variations != b->variations) + return FALSE; + + if (a->custom_palette && b->custom_palette && + memcmp (a->custom_palette, b->custom_palette, sizeof (cairo_palette_color_t) * a->custom_palette_size) != 0) + { + return FALSE; + } + else if (a->custom_palette != b->custom_palette) + { + return FALSE; + } + + return TRUE; +} + +/** + * cairo_font_options_create: + * + * Allocates a new font options object with all options initialized + * to default values. + * + * Return value: a newly allocated #cairo_font_options_t. Free with + * cairo_font_options_destroy(). This function always returns a + * valid pointer; if memory cannot be allocated, then a special + * error object is returned where all operations on the object do nothing. + * You can check for this with cairo_font_options_status(). + * + * Since: 1.0 + **/ +cairo_font_options_t * +cairo_font_options_create (void) +{ + cairo_font_options_t *options; + + options = _cairo_calloc (sizeof (cairo_font_options_t)); + if (!options) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_font_options_t *) &_cairo_font_options_nil; + } + + _cairo_font_options_init_default (options); + + return options; +} + +/** + * cairo_font_options_copy: + * @original: a #cairo_font_options_t + * + * Allocates a new font options object copying the option values from + * @original. + * + * Return value: a newly allocated #cairo_font_options_t. Free with + * cairo_font_options_destroy(). This function always returns a + * valid pointer; if memory cannot be allocated, then a special + * error object is returned where all operations on the object do nothing. + * You can check for this with cairo_font_options_status(). + * + * Since: 1.0 + **/ +cairo_font_options_t * +cairo_font_options_copy (const cairo_font_options_t *original) +{ + cairo_font_options_t *options; + + if (cairo_font_options_status ((cairo_font_options_t *) original)) + return (cairo_font_options_t *) &_cairo_font_options_nil; + + options = _cairo_calloc (sizeof (cairo_font_options_t)); + if (!options) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_font_options_t *) &_cairo_font_options_nil; + } + + _cairo_font_options_init_copy (options, original); + + return options; +} + +void +_cairo_font_options_fini (cairo_font_options_t *options) +{ + free (options->variations); + free (options->custom_palette); +} + +/** + * cairo_font_options_destroy: + * @options: a #cairo_font_options_t + * + * Destroys a #cairo_font_options_t object created with + * cairo_font_options_create() or cairo_font_options_copy(). + * + * Since: 1.0 + **/ +void +cairo_font_options_destroy (cairo_font_options_t *options) +{ + if (cairo_font_options_status (options)) + return; + + _cairo_font_options_fini (options); + free (options); +} + +/** + * cairo_font_options_status: + * @options: a #cairo_font_options_t + * + * Checks whether an error has previously occurred for this + * font options object + * + * Return value: %CAIRO_STATUS_SUCCESS, %CAIRO_STATUS_NO_MEMORY, or + * %CAIRO_STATUS_NULL_POINTER. + * + * Since: 1.0 + **/ +cairo_status_t +cairo_font_options_status (cairo_font_options_t *options) +{ + if (options == NULL) + return CAIRO_STATUS_NULL_POINTER; + else if (options == (cairo_font_options_t *) &_cairo_font_options_nil) + return CAIRO_STATUS_NO_MEMORY; + else + return CAIRO_STATUS_SUCCESS; +} + +/** + * cairo_font_options_merge: + * @options: a #cairo_font_options_t + * @other: another #cairo_font_options_t + * + * Merges non-default options from @other into @options, replacing + * existing values. This operation can be thought of as somewhat + * similar to compositing @other onto @options with the operation + * of %CAIRO_OPERATOR_OVER. + * + * Since: 1.0 + **/ +void +cairo_font_options_merge (cairo_font_options_t *options, + const cairo_font_options_t *other) +{ + if (cairo_font_options_status (options)) + return; + + if (cairo_font_options_status ((cairo_font_options_t *) other)) + return; + + if (other->antialias != CAIRO_ANTIALIAS_DEFAULT) + options->antialias = other->antialias; + if (other->subpixel_order != CAIRO_SUBPIXEL_ORDER_DEFAULT) + options->subpixel_order = other->subpixel_order; + if (other->lcd_filter != CAIRO_LCD_FILTER_DEFAULT) + options->lcd_filter = other->lcd_filter; + if (other->hint_style != CAIRO_HINT_STYLE_DEFAULT) + options->hint_style = other->hint_style; + if (other->hint_metrics != CAIRO_HINT_METRICS_DEFAULT) + options->hint_metrics = other->hint_metrics; + if (other->round_glyph_positions != CAIRO_ROUND_GLYPH_POS_DEFAULT) + options->round_glyph_positions = other->round_glyph_positions; + + if (other->variations) { + if (options->variations) { + char *p; + + /* 'merge' variations by concatenating - later entries win */ + p = malloc (strlen (other->variations) + strlen (options->variations) + 2); + p[0] = 0; + strcat (p, options->variations); + strcat (p, ","); + strcat (p, other->variations); + free (options->variations); + options->variations = p; + } + else { + options->variations = strdup (other->variations); + } + } + + if (other->color_mode != CAIRO_COLOR_MODE_DEFAULT) + options->color_mode = other->color_mode; + if (other->palette_index != CAIRO_COLOR_PALETTE_DEFAULT) + options->palette_index = other->palette_index; + if (other->custom_palette) { + options->custom_palette_size = other->custom_palette_size; + free (options->custom_palette); + options->custom_palette = (cairo_palette_color_t *) malloc (sizeof (cairo_palette_color_t) * options->custom_palette_size); + memcpy (options->custom_palette, other->custom_palette, sizeof (cairo_palette_color_t) * options->custom_palette_size); + } +} + +/** + * cairo_font_options_equal: + * @options: a #cairo_font_options_t + * @other: another #cairo_font_options_t + * + * Compares two font options objects for equality. + * + * Return value: %TRUE if all fields of the two font options objects match. + * Note that this function will return %FALSE if either object is in + * error. + * + * Since: 1.0 + **/ +cairo_bool_t +cairo_font_options_equal (const cairo_font_options_t *options, + const cairo_font_options_t *other) +{ + if (cairo_font_options_status ((cairo_font_options_t *) options)) + return FALSE; + if (cairo_font_options_status ((cairo_font_options_t *) other)) + return FALSE; + + if (options == other) + return TRUE; + + return (options->antialias == other->antialias && + options->subpixel_order == other->subpixel_order && + options->lcd_filter == other->lcd_filter && + options->hint_style == other->hint_style && + options->hint_metrics == other->hint_metrics && + options->round_glyph_positions == other->round_glyph_positions && + ((options->variations == NULL && other->variations == NULL) || + (options->variations != NULL && other->variations != NULL && + strcmp (options->variations, other->variations) == 0)) && + options->color_mode == other->color_mode && + options->palette_index == other->palette_index && + ((options->custom_palette == NULL && other->custom_palette == NULL) || + (options->custom_palette != NULL && other->custom_palette != NULL && + options->custom_palette_size == other->custom_palette_size && + memcmp (options->custom_palette, other->custom_palette, + sizeof (cairo_palette_color_t) * options->custom_palette_size) == 0))); +} + +/** + * cairo_font_options_hash: + * @options: a #cairo_font_options_t + * + * Compute a hash for the font options object; this value will + * be useful when storing an object containing a #cairo_font_options_t + * in a hash table. + * + * Return value: the hash value for the font options object. + * The return value can be cast to a 32-bit type if a + * 32-bit hash value is needed. + * + * Since: 1.0 + **/ +unsigned long +cairo_font_options_hash (const cairo_font_options_t *options) +{ + unsigned long hash = 0; + + if (cairo_font_options_status ((cairo_font_options_t *) options)) + options = &_cairo_font_options_nil; /* force default values */ + + if (options->variations) + hash = _cairo_string_hash (options->variations, strlen (options->variations)); + + hash ^= options->palette_index; + + return ((options->antialias) | + (options->subpixel_order << 4) | + (options->lcd_filter << 8) | + (options->hint_style << 12) | + (options->hint_metrics << 16) | + (options->color_mode << 20)) ^ hash; +} + +/** + * cairo_font_options_set_antialias: + * @options: a #cairo_font_options_t + * @antialias: the new antialiasing mode + * + * Sets the antialiasing mode for the font options object. This + * specifies the type of antialiasing to do when rendering text. + * + * Since: 1.0 + **/ +void +cairo_font_options_set_antialias (cairo_font_options_t *options, + cairo_antialias_t antialias) +{ + if (cairo_font_options_status (options)) + return; + + options->antialias = antialias; +} + +/** + * cairo_font_options_get_antialias: + * @options: a #cairo_font_options_t + * + * Gets the antialiasing mode for the font options object. + * + * Return value: the antialiasing mode + * + * Since: 1.0 + **/ +cairo_antialias_t +cairo_font_options_get_antialias (const cairo_font_options_t *options) +{ + if (cairo_font_options_status ((cairo_font_options_t *) options)) + return CAIRO_ANTIALIAS_DEFAULT; + + return options->antialias; +} + +/** + * cairo_font_options_set_subpixel_order: + * @options: a #cairo_font_options_t + * @subpixel_order: the new subpixel order + * + * Sets the subpixel order for the font options object. The subpixel + * order specifies the order of color elements within each pixel on + * the display device when rendering with an antialiasing mode of + * %CAIRO_ANTIALIAS_SUBPIXEL. See the documentation for + * #cairo_subpixel_order_t for full details. + * + * Since: 1.0 + **/ +void +cairo_font_options_set_subpixel_order (cairo_font_options_t *options, + cairo_subpixel_order_t subpixel_order) +{ + if (cairo_font_options_status (options)) + return; + + options->subpixel_order = subpixel_order; +} + +/** + * cairo_font_options_get_subpixel_order: + * @options: a #cairo_font_options_t + * + * Gets the subpixel order for the font options object. + * See the documentation for #cairo_subpixel_order_t for full details. + * + * Return value: the subpixel order for the font options object + * + * Since: 1.0 + **/ +cairo_subpixel_order_t +cairo_font_options_get_subpixel_order (const cairo_font_options_t *options) +{ + if (cairo_font_options_status ((cairo_font_options_t *) options)) + return CAIRO_SUBPIXEL_ORDER_DEFAULT; + + return options->subpixel_order; +} + +/** + * _cairo_font_options_set_lcd_filter: + * @options: a #cairo_font_options_t + * @lcd_filter: the new LCD filter + * + * Sets the LCD filter for the font options object. The LCD filter + * specifies how pixels are filtered when rendered with an antialiasing + * mode of %CAIRO_ANTIALIAS_SUBPIXEL. See the documentation for + * #cairo_lcd_filter_t for full details. + **/ +void +_cairo_font_options_set_lcd_filter (cairo_font_options_t *options, + cairo_lcd_filter_t lcd_filter) +{ + if (cairo_font_options_status (options)) + return; + + options->lcd_filter = lcd_filter; +} + +/** + * _cairo_font_options_get_lcd_filter: + * @options: a #cairo_font_options_t + * + * Gets the LCD filter for the font options object. + * See the documentation for #cairo_lcd_filter_t for full details. + * + * Return value: the LCD filter for the font options object + **/ +cairo_lcd_filter_t +_cairo_font_options_get_lcd_filter (const cairo_font_options_t *options) +{ + if (cairo_font_options_status ((cairo_font_options_t *) options)) + return CAIRO_LCD_FILTER_DEFAULT; + + return options->lcd_filter; +} + +/** + * _cairo_font_options_set_round_glyph_positions: + * @options: a #cairo_font_options_t + * @round: the new rounding value + * + * Sets the rounding options for the font options object. If rounding is set, a + * glyph's position will be rounded to integer values. + **/ +void +_cairo_font_options_set_round_glyph_positions (cairo_font_options_t *options, + cairo_round_glyph_positions_t round) +{ + if (cairo_font_options_status (options)) + return; + + options->round_glyph_positions = round; +} + +/** + * _cairo_font_options_get_round_glyph_positions: + * @options: a #cairo_font_options_t + * + * Gets the glyph position rounding option for the font options object. + * + * Return value: The round glyph posistions flag for the font options object. + **/ +cairo_round_glyph_positions_t +_cairo_font_options_get_round_glyph_positions (const cairo_font_options_t *options) +{ + if (cairo_font_options_status ((cairo_font_options_t *) options)) + return CAIRO_ROUND_GLYPH_POS_DEFAULT; + + return options->round_glyph_positions; +} + +/** + * cairo_font_options_set_hint_style: + * @options: a #cairo_font_options_t + * @hint_style: the new hint style + * + * Sets the hint style for font outlines for the font options object. + * This controls whether to fit font outlines to the pixel grid, + * and if so, whether to optimize for fidelity or contrast. + * See the documentation for #cairo_hint_style_t for full details. + * + * Since: 1.0 + **/ +void +cairo_font_options_set_hint_style (cairo_font_options_t *options, + cairo_hint_style_t hint_style) +{ + if (cairo_font_options_status (options)) + return; + + options->hint_style = hint_style; +} + +/** + * cairo_font_options_get_hint_style: + * @options: a #cairo_font_options_t + * + * Gets the hint style for font outlines for the font options object. + * See the documentation for #cairo_hint_style_t for full details. + * + * Return value: the hint style for the font options object + * + * Since: 1.0 + **/ +cairo_hint_style_t +cairo_font_options_get_hint_style (const cairo_font_options_t *options) +{ + if (cairo_font_options_status ((cairo_font_options_t *) options)) + return CAIRO_HINT_STYLE_DEFAULT; + + return options->hint_style; +} + +/** + * cairo_font_options_set_hint_metrics: + * @options: a #cairo_font_options_t + * @hint_metrics: the new metrics hinting mode + * + * Sets the metrics hinting mode for the font options object. This + * controls whether metrics are quantized to integer values in + * device units. + * See the documentation for #cairo_hint_metrics_t for full details. + * + * Since: 1.0 + **/ +void +cairo_font_options_set_hint_metrics (cairo_font_options_t *options, + cairo_hint_metrics_t hint_metrics) +{ + if (cairo_font_options_status (options)) + return; + + options->hint_metrics = hint_metrics; +} + +/** + * cairo_font_options_get_hint_metrics: + * @options: a #cairo_font_options_t + * + * Gets the metrics hinting mode for the font options object. + * See the documentation for #cairo_hint_metrics_t for full details. + * + * Return value: the metrics hinting mode for the font options object + * + * Since: 1.0 + **/ +cairo_hint_metrics_t +cairo_font_options_get_hint_metrics (const cairo_font_options_t *options) +{ + if (cairo_font_options_status ((cairo_font_options_t *) options)) + return CAIRO_HINT_METRICS_DEFAULT; + + return options->hint_metrics; +} + +/** + * cairo_font_options_set_variations: + * @options: a #cairo_font_options_t + * @variations: the new font variations, or %NULL + * + * Sets the OpenType font variations for the font options object. + * Font variations are specified as a string with a format that + * is similar to the CSS font-variation-settings. The string contains + * a comma-separated list of axis assignments, which each assignment + * consists of a 4-character axis name and a value, separated by + * whitespace and optional equals sign. + * + * Examples: + * + * wght=200,wdth=140.5 + * + * wght 200 , wdth 140.5 + * + * Since: 1.16 + **/ +void +cairo_font_options_set_variations (cairo_font_options_t *options, + const char *variations) +{ + char *tmp = variations ? strdup (variations) : NULL; + free (options->variations); + options->variations = tmp; +} + +/** + * cairo_font_options_get_variations: + * @options: a #cairo_font_options_t + * + * Gets the OpenType font variations for the font options object. + * See cairo_font_options_set_variations() for details about the + * string format. + * + * Return value: the font variations for the font options object. The + * returned string belongs to the @options and must not be modified. + * It is valid until either the font options object is destroyed or + * the font variations in this object is modified with + * cairo_font_options_set_variations(). + * + * Since: 1.16 + **/ +const char * +cairo_font_options_get_variations (cairo_font_options_t *options) +{ + return options->variations; +} + +/** + * cairo_font_options_set_color_mode: + * @options: a #cairo_font_options_t + * @color_mode: the new color mode + * + * Sets the color mode for the font options object. This controls + * whether color fonts are to be rendered in color or as outlines. + * See the documentation for #cairo_color_mode_t for full details. + * + * Since: 1.18 + **/ +cairo_public void +cairo_font_options_set_color_mode (cairo_font_options_t *options, + cairo_color_mode_t color_mode) +{ + if (cairo_font_options_status (options)) + return; + + options->color_mode = color_mode; +} + +/** + * cairo_font_options_get_color_mode: + * @options: a #cairo_font_options_t + * + * Gets the color mode for the font options object. + * See the documentation for #cairo_color_mode_t for full details. + * + * Return value: the color mode for the font options object + * + * Since: 1.18 + **/ +cairo_public cairo_color_mode_t +cairo_font_options_get_color_mode (const cairo_font_options_t *options) +{ + if (cairo_font_options_status ((cairo_font_options_t *) options)) + return CAIRO_COLOR_MODE_DEFAULT; + + return options->color_mode; +} + +/** + * CAIRO_COLOR_PALETTE_DEFAULT: + * + * The default color palette index. + * + * Since: 1.18 + **/ + +/** + * cairo_font_options_set_color_palette: + * @options: a #cairo_font_options_t + * @palette_index: the palette index in the CPAL table + * + * Sets the OpenType font color palette for the font options + * object. OpenType color fonts with a CPAL table may contain multiple + * palettes. The default color palette index is %CAIRO_COLOR_PALETTE_DEFAULT. + * + * If @palette_index is invalid, the default palette is used. + * + * Individual colors within the palette may be overriden with + * cairo_font_options_set_custom_palette_color(). + * + * Since: 1.18 + **/ +void +cairo_font_options_set_color_palette (cairo_font_options_t *options, + unsigned int palette_index) +{ + if (cairo_font_options_status (options)) + return; + + options->palette_index = palette_index; +} + +/** + * cairo_font_options_get_color_palette: + * @options: a #cairo_font_options_t + * + * Gets the current OpenType color font palette for the font options object. + * + * Return value: the palette index + * + * Since: 1.18 + **/ +unsigned int +cairo_font_options_get_color_palette (const cairo_font_options_t *options) +{ + if (cairo_font_options_status ((cairo_font_options_t *) options)) + return CAIRO_COLOR_PALETTE_DEFAULT; + + return options->palette_index; +} + +/** + * cairo_font_options_set_custom_palette_color: + * @options: a #cairo_font_options_t + * @index: the index of the color to set + * @red: red component of color + * @green: green component of color + * @blue: blue component of color + * @alpha: alpha component of color + * + * Sets a custom palette color for the font options object. This + * overrides the palette color at the specified color index. This override is + * independent of the selected palette index and will remain in place + * even if cairo_font_options_set_color_palette() is called to change + * the palette index. + * + * It is only possible to override color indexes already in the font + * palette. + * + * Since: 1.18 + */ +void +cairo_font_options_set_custom_palette_color (cairo_font_options_t *options, + unsigned int index, + double red, double green, + double blue, double alpha) +{ + unsigned int idx; + + for (idx = 0; idx < options->custom_palette_size; idx++) { + if (options->custom_palette[idx].index == index) { + break; + } + } + + if (idx == options->custom_palette_size) { + options->custom_palette_size++; + options->custom_palette = (cairo_palette_color_t *) + _cairo_realloc_ab (options->custom_palette, + sizeof (cairo_palette_color_t), + options->custom_palette_size); + } + + /* beware of holes */ + memset (&options->custom_palette[idx], 0, sizeof (cairo_palette_color_t)); + + options->custom_palette[idx].index = index; + options->custom_palette[idx].red = red; + options->custom_palette[idx].green = green; + options->custom_palette[idx].blue = blue; + options->custom_palette[idx].alpha = alpha; +} + +/** + * cairo_font_options_get_custom_palette_color: + * @options: a #cairo_font_options_t + * @index: the index of the color to get + * @red: return location for red component of color + * @green: return location for green component of color + * @blue: return location for blue component of color + * @alpha: return location for alpha component of color + * + * Gets the custom palette color for the color index for the font options object. + * + * Returns: `CAIRO_STATUS_SUCCESS` if a custom palette color is + * returned, `CAIRO_STATUS_INVALID_INDEX` if no custom color exists + * for the color index. + * + * Since: 1.18 + */ +cairo_status_t +cairo_font_options_get_custom_palette_color (cairo_font_options_t *options, + unsigned int index, + double *red, double *green, + double *blue, double *alpha) +{ + unsigned int idx; + + for (idx = 0; idx < options->custom_palette_size; idx++) { + if (options->custom_palette[idx].index == index) { + *red = options->custom_palette[idx].red; + *green = options->custom_palette[idx].green; + *blue = options->custom_palette[idx].blue; + *alpha = options->custom_palette[idx].alpha; + return CAIRO_STATUS_SUCCESS; + } + } + + return CAIRO_STATUS_INVALID_INDEX; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-fontconfig-private.h b/local/recipes/libs/cairo/source/src/cairo-fontconfig-private.h new file mode 100644 index 0000000000..15dc032810 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-fontconfig-private.h @@ -0,0 +1,52 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2000 Keith Packard + * Copyright © 2005 Red Hat, Inc + * Copyright © 2010 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Graydon Hoare + * Owen Taylor + * Keith Packard + * Carl Worth + * Chris Wilson + */ + +#ifndef _CAIRO_FONTCONFIG_PRIVATE_H +#define _CAIRO_FONTCONFIG_PRIVATE_H + +#include "cairo.h" + +#if CAIRO_HAS_FC_FONT +#include +#include +#endif + +#endif /* _CAIRO_FONTCONFIG_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-freed-pool-private.h b/local/recipes/libs/cairo/source/src/cairo-freed-pool-private.h new file mode 100644 index 0000000000..ced1adb3d1 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-freed-pool-private.h @@ -0,0 +1,139 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Chris Wilson + */ + +#ifndef CAIRO_FREED_POOL_H +#define CAIRO_FREED_POOL_H + +#include "cairoint.h" +#include "cairo-atomic-private.h" + +CAIRO_BEGIN_DECLS + +#define DISABLE_FREED_POOLS 0 + +#if HAS_ATOMIC_OPS && ! DISABLE_FREED_POOLS +/* Keep a stash of recently freed clip_paths, since we need to + * reallocate them frequently. + */ +#define MAX_FREED_POOL_SIZE 16 +typedef struct { + cairo_atomic_intptr_t pool[MAX_FREED_POOL_SIZE]; + cairo_atomic_int_t top; +} freed_pool_t; + +static cairo_always_inline void * +_atomic_fetch (cairo_atomic_intptr_t *slot) +{ + void *ptr; + + do { + ptr = _cairo_atomic_ptr_get (slot); + } while (! _cairo_atomic_ptr_cmpxchg (slot, ptr, NULL)); + + return ptr; +} + +static cairo_always_inline cairo_bool_t +_atomic_store (cairo_atomic_intptr_t *slot, void *ptr) +{ + return _cairo_atomic_ptr_cmpxchg (slot, NULL, ptr); +} + +cairo_private void * +_freed_pool_get_search (freed_pool_t *pool); + +static inline void * +_freed_pool_get (freed_pool_t *pool) +{ + void *ptr; + int i; + + i = _cairo_atomic_int_get_relaxed (&pool->top) - 1; + if (i < 0) + i = 0; + + ptr = _atomic_fetch (&pool->pool[i]); + if (likely (ptr != NULL)) { + _cairo_atomic_int_set_relaxed (&pool->top, i); + return ptr; + } + + /* either empty or contended */ + return _freed_pool_get_search (pool); +} + +cairo_private void +_freed_pool_put_search (freed_pool_t *pool, void *ptr); + +static inline void +_freed_pool_put (freed_pool_t *pool, void *ptr) +{ + int i; + + i = _cairo_atomic_int_get_relaxed (&pool->top); + if (likely (i < ARRAY_LENGTH (pool->pool) && + _atomic_store (&pool->pool[i], ptr))) + { + _cairo_atomic_int_set_relaxed (&pool->top, i + 1); + return; + } + + /* either full or contended */ + _freed_pool_put_search (pool, ptr); +} + +cairo_private void +_freed_pool_reset (freed_pool_t *pool); + +#define HAS_FREED_POOL 1 + +#else + +/* A warning about an unused freed-pool in a build without atomics + * enabled usually indicates a missing _freed_pool_reset() in the + * static reset function */ + +typedef int freed_pool_t; + +#define _freed_pool_get(pool) NULL +#define _freed_pool_put(pool, ptr) free(ptr) +#define _freed_pool_reset(ptr) + +#endif + +CAIRO_END_DECLS + +#endif /* CAIRO_FREED_POOL_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-freed-pool.c b/local/recipes/libs/cairo/source/src/cairo-freed-pool.c new file mode 100644 index 0000000000..6d46ab1c13 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-freed-pool.c @@ -0,0 +1,92 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Chris Wilson + */ + +#include "cairoint.h" + +#include "cairo-freed-pool-private.h" + +#if HAS_FREED_POOL + +void * +_freed_pool_get_search (freed_pool_t *pool) +{ + void *ptr; + int i; + + for (i = ARRAY_LENGTH (pool->pool); i--;) { + ptr = _atomic_fetch (&pool->pool[i]); + if (ptr != NULL) { + _cairo_atomic_int_set_relaxed (&pool->top, i); + return ptr; + } + } + + /* empty */ + _cairo_atomic_int_set_relaxed (&pool->top, 0); + return NULL; +} + +void +_freed_pool_put_search (freed_pool_t *pool, void *ptr) +{ + int i; + + for (i = 0; i < ARRAY_LENGTH (pool->pool); i++) { + if (_atomic_store (&pool->pool[i], ptr)) { + _cairo_atomic_int_set_relaxed (&pool->top, i + 1); + return; + } + } + + /* full */ + _cairo_atomic_int_set_relaxed (&pool->top, i); + free (ptr); +} + +void +_freed_pool_reset (freed_pool_t *pool) +{ + int i; + + for (i = 0; i < ARRAY_LENGTH (pool->pool); i++) { + free (_atomic_fetch (&pool->pool[i])); + } + + _cairo_atomic_int_set_relaxed (&pool->top, 0); +} + +#endif diff --git a/local/recipes/libs/cairo/source/src/cairo-freelist-private.h b/local/recipes/libs/cairo/source/src/cairo-freelist-private.h new file mode 100644 index 0000000000..f85f689141 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-freelist-private.h @@ -0,0 +1,139 @@ +/* + * Copyright © 2006 Joonas Pihlaja + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ +#ifndef CAIRO_FREELIST_H +#define CAIRO_FREELIST_H + +#include "cairo-types-private.h" +#include "cairo-compiler-private.h" +#include "cairo-freelist-type-private.h" + +/* for stand-alone compilation*/ +#ifndef VG +#define VG(x) +#endif + +#ifndef NULL +#define NULL (void *) 0 +#endif + +/* Initialise a freelist that will be responsible for allocating + * nodes of size nodesize. */ +cairo_private void +_cairo_freelist_init (cairo_freelist_t *freelist, unsigned nodesize); + +/* Deallocate any nodes in the freelist. */ +cairo_private void +_cairo_freelist_fini (cairo_freelist_t *freelist); + +/* Allocate a new node from the freelist. If the freelist contains no + * nodes, a new one will be allocated using malloc(). The caller is + * responsible for calling _cairo_freelist_free() or free() on the + * returned node. Returns %NULL on memory allocation error. */ +cairo_private void * +_cairo_freelist_alloc (cairo_freelist_t *freelist); + +/* Allocate a new node from the freelist. If the freelist contains no + * nodes, a new one will be allocated using calloc(). The caller is + * responsible for calling _cairo_freelist_free() or free() on the + * returned node. Returns %NULL on memory allocation error. */ +cairo_private void * +_cairo_freelist_calloc (cairo_freelist_t *freelist); + +/* Return a node to the freelist. This does not deallocate the memory, + * but makes it available for later reuse by + * _cairo_freelist_alloc(). */ +cairo_private void +_cairo_freelist_free (cairo_freelist_t *freelist, void *node); + + +cairo_private void +_cairo_freepool_init (cairo_freepool_t *freepool, unsigned nodesize); + +cairo_private void +_cairo_freepool_fini (cairo_freepool_t *freepool); + +static inline void +_cairo_freepool_reset (cairo_freepool_t *freepool) +{ + while (freepool->pools != &freepool->embedded_pool) { + cairo_freelist_pool_t *pool = freepool->pools; + freepool->pools = pool->next; + pool->next = freepool->freepools; + freepool->freepools = pool; + } + + freepool->embedded_pool.rem = sizeof (freepool->embedded_data); + freepool->embedded_pool.data = freepool->embedded_data; +} + +cairo_private void * +_cairo_freepool_alloc_from_new_pool (cairo_freepool_t *freepool); + +static inline void * +_cairo_freepool_alloc_from_pool (cairo_freepool_t *freepool) +{ + cairo_freelist_pool_t *pool; + uint8_t *ptr; + + pool = freepool->pools; + if (unlikely (freepool->nodesize > pool->rem)) + return _cairo_freepool_alloc_from_new_pool (freepool); + + ptr = pool->data; + pool->data += freepool->nodesize; + pool->rem -= freepool->nodesize; + VG (VALGRIND_MAKE_MEM_UNDEFINED (ptr, freepool->nodesize)); + return ptr; +} + +static inline void * +_cairo_freepool_alloc (cairo_freepool_t *freepool) +{ + cairo_freelist_node_t *node; + + node = freepool->first_free_node; + if (node == NULL) + return _cairo_freepool_alloc_from_pool (freepool); + + VG (VALGRIND_MAKE_MEM_DEFINED (node, sizeof (node->next))); + freepool->first_free_node = node->next; + VG (VALGRIND_MAKE_MEM_UNDEFINED (node, freepool->nodesize)); + + return node; +} + +cairo_private cairo_status_t +_cairo_freepool_alloc_array (cairo_freepool_t *freepool, + int count, + void **array); + +static inline void +_cairo_freepool_free (cairo_freepool_t *freepool, void *ptr) +{ + cairo_freelist_node_t *node = ptr; + + node->next = freepool->first_free_node; + freepool->first_free_node = node; + VG (VALGRIND_MAKE_MEM_UNDEFINED (node, freepool->nodesize)); +} + +#endif /* CAIRO_FREELIST_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-freelist-type-private.h b/local/recipes/libs/cairo/source/src/cairo-freelist-type-private.h new file mode 100644 index 0000000000..4dd0564610 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-freelist-type-private.h @@ -0,0 +1,54 @@ +/* + * Copyright © 2010 Joonas Pihlaja + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ +#ifndef CAIRO_FREELIST_TYPE_H +#define CAIRO_FREELIST_TYPE_H + +#include "cairo-types-private.h" +#include "cairo-compiler-private.h" + +typedef struct _cairo_freelist_node cairo_freelist_node_t; +struct _cairo_freelist_node { + cairo_freelist_node_t *next; +}; + +typedef struct _cairo_freelist { + cairo_freelist_node_t *first_free_node; + unsigned nodesize; +} cairo_freelist_t; + +typedef struct _cairo_freelist_pool cairo_freelist_pool_t; +struct _cairo_freelist_pool { + cairo_freelist_pool_t *next; + unsigned size, rem; + uint8_t *data; +}; + +typedef struct _cairo_freepool { + cairo_freelist_node_t *first_free_node; + cairo_freelist_pool_t *pools; + cairo_freelist_pool_t *freepools; + unsigned nodesize; + cairo_freelist_pool_t embedded_pool; + uint8_t embedded_data[1000]; +} cairo_freepool_t; + +#endif /* CAIRO_FREELIST_TYPE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-freelist.c b/local/recipes/libs/cairo/source/src/cairo-freelist.c new file mode 100644 index 0000000000..7f2f3b30b8 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-freelist.c @@ -0,0 +1,191 @@ +/* + * Copyright © 2006 Joonas Pihlaja + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "cairoint.h" + +#include "cairo-error-private.h" +#include "cairo-freelist-private.h" + +void +_cairo_freelist_init (cairo_freelist_t *freelist, unsigned nodesize) +{ + memset (freelist, 0, sizeof (cairo_freelist_t)); + freelist->nodesize = nodesize; +} + +void +_cairo_freelist_fini (cairo_freelist_t *freelist) +{ + cairo_freelist_node_t *node = freelist->first_free_node; + while (node) { + cairo_freelist_node_t *next; + + VG (VALGRIND_MAKE_MEM_DEFINED (node, sizeof (node->next))); + next = node->next; + + free (node); + node = next; + } +} + +void * +_cairo_freelist_alloc (cairo_freelist_t *freelist) +{ + if (freelist->first_free_node) { + cairo_freelist_node_t *node; + + node = freelist->first_free_node; + VG (VALGRIND_MAKE_MEM_DEFINED (node, sizeof (node->next))); + freelist->first_free_node = node->next; + VG (VALGRIND_MAKE_MEM_UNDEFINED (node, freelist->nodesize)); + + return node; + } + + return _cairo_malloc (freelist->nodesize); +} + +void * +_cairo_freelist_calloc (cairo_freelist_t *freelist) +{ + void *node = _cairo_freelist_alloc (freelist); + if (node) + memset (node, 0, freelist->nodesize); + return node; +} + +void +_cairo_freelist_free (cairo_freelist_t *freelist, void *voidnode) +{ + cairo_freelist_node_t *node = voidnode; + if (node) { + node->next = freelist->first_free_node; + freelist->first_free_node = node; + VG (VALGRIND_MAKE_MEM_UNDEFINED (node, freelist->nodesize)); + } +} + +void +_cairo_freepool_init (cairo_freepool_t *freepool, unsigned nodesize) +{ + freepool->first_free_node = NULL; + freepool->pools = &freepool->embedded_pool; + freepool->freepools = NULL; + freepool->nodesize = nodesize; + + freepool->embedded_pool.next = NULL; + freepool->embedded_pool.size = sizeof (freepool->embedded_data); + freepool->embedded_pool.rem = sizeof (freepool->embedded_data); + freepool->embedded_pool.data = freepool->embedded_data; + + VG (VALGRIND_MAKE_MEM_UNDEFINED (freepool->embedded_data, sizeof (freepool->embedded_data))); +} + +void +_cairo_freepool_fini (cairo_freepool_t *freepool) +{ + cairo_freelist_pool_t *pool; + + pool = freepool->pools; + while (pool != &freepool->embedded_pool) { + cairo_freelist_pool_t *next = pool->next; + free (pool); + pool = next; + } + + pool = freepool->freepools; + while (pool != NULL) { + cairo_freelist_pool_t *next = pool->next; + free (pool); + pool = next; + } + + VG (VALGRIND_MAKE_MEM_UNDEFINED (freepool, sizeof (freepool))); +} + +void * +_cairo_freepool_alloc_from_new_pool (cairo_freepool_t *freepool) +{ + cairo_freelist_pool_t *pool; + int poolsize; + + if (freepool->freepools != NULL) { + pool = freepool->freepools; + freepool->freepools = pool->next; + + poolsize = pool->size; + } else { + if (freepool->pools != &freepool->embedded_pool) + poolsize = 2 * freepool->pools->size; + else + poolsize = (128 * freepool->nodesize + 8191) & -8192; + + pool = _cairo_malloc (sizeof (cairo_freelist_pool_t) + poolsize); + if (unlikely (pool == NULL)) + return pool; + + pool->size = poolsize; + } + + pool->next = freepool->pools; + freepool->pools = pool; + + pool->rem = poolsize - freepool->nodesize; + pool->data = (uint8_t *) (pool + 1) + freepool->nodesize; + + VG (VALGRIND_MAKE_MEM_UNDEFINED (pool->data, pool->rem)); + + return pool + 1; +} + +cairo_status_t +_cairo_freepool_alloc_array (cairo_freepool_t *freepool, + int count, + void **array) +{ + int i; + + for (i = 0; i < count; i++) { + cairo_freelist_node_t *node; + + node = freepool->first_free_node; + if (likely (node != NULL)) { + VG (VALGRIND_MAKE_MEM_DEFINED (node, sizeof (node->next))); + freepool->first_free_node = node->next; + VG (VALGRIND_MAKE_MEM_UNDEFINED (node, freepool->nodesize)); + } else { + node = _cairo_freepool_alloc_from_pool (freepool); + if (unlikely (node == NULL)) + goto CLEANUP; + } + + array[i] = node; + } + + return CAIRO_STATUS_SUCCESS; + + CLEANUP: + while (i--) + _cairo_freepool_free (freepool, array[i]); + + return _cairo_error (CAIRO_STATUS_NO_MEMORY); +} diff --git a/local/recipes/libs/cairo/source/src/cairo-ft-font.c b/local/recipes/libs/cairo/source/src/cairo-ft-font.c new file mode 100644 index 0000000000..b5d08ee1b3 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-ft-font.c @@ -0,0 +1,4710 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2000 Keith Packard + * Copyright © 2005 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Graydon Hoare + * Owen Taylor + * Keith Packard + * Carl Worth + */ + +#define _DEFAULT_SOURCE /* for strdup() */ +#include "cairoint.h" + +#include "cairo-error-private.h" +#include "cairo-image-surface-private.h" +#include "cairo-ft-private.h" +#include "cairo-list-inline.h" +#include "cairo-path-private.h" +#include "cairo-pattern-private.h" +#include "cairo-pixman-private.h" +#include "cairo-recording-surface-private.h" + +#include + +#include "cairo-fontconfig-private.h" + +#include +#include FT_FREETYPE_H +#include FT_OUTLINE_H +#include FT_IMAGE_H +#include FT_BITMAP_H +#include FT_TRUETYPE_TABLES_H +#include FT_FONT_FORMATS_H +#include FT_MULTIPLE_MASTERS_H +#include FT_SYNTHESIS_H +#include FT_LCD_FILTER_H + +#if HAVE_FT_SVG_DOCUMENT +#include FT_OTSVG_H +#endif + +#if HAVE_UNISTD_H +#include +#elif !defined(access) +#define access(p, m) 0 +#endif + +/* FreeType version older than 2.11 does not have the FT_RENDER_MODE_SDF enum value in FT_Render_Mode */ +#if FREETYPE_MAJOR > 2 || (FREETYPE_MAJOR == 2 && FREETYPE_MINOR >= 11) +#define HAVE_FT_RENDER_MODE_SDF 1 +#endif + +#define DOUBLE_FROM_26_6(t) ((double)(t) / 64.0) +#define DOUBLE_TO_16_16(d) ((FT_Fixed)((d) * 65536.0)) +#define DOUBLE_FROM_16_16(t) ((double)(t) / 65536.0) + +/* SCALE() mimics code from commit 399b00a99b2bbc1c56a05974c936aa69a08021f5 + * concerning a potential division by 0, but instead of doing a * (1/b), it + * does a/b, thus improving the accuracy. With a * (1/b), for a bitmap font + * of size 13, the computed -y_bearing was 0x1.6000000000001p+3 instead of + * 0x1.6p+3 (= 11). This triggered a bug in GNU Emacs (when built against + * cairo), which rounded the value to an integer with ceil(). + * Details: + * https://gitlab.freedesktop.org/cairo/cairo/-/issues/503 + * https://debbugs.gnu.org/cgi/bugreport.cgi?bug=44284 + * + * Note that rounding errors are not necessarily expected by applications + * in simple cases like the GNU Emacs one (an identity transformation, + * which should normally leave the inputs unchanged). However, with the + * current cairo code, due to the scaling, there is no guarantee that + * rounding errors will always be avoided at the end. For instance, + * (a/b)*b may be different from a, but this is still better than doing + * (a*(1/b))*b. + * + * According to the commit mentioned above, avoiding a division by zero + * was an attempt to fix + * https://bugzilla.gnome.org/show_bug.cgi?id=311299 + * but this did not actually solve the problem. So it might be possible + * to change SCALE() to just do (a) / (b). + */ +#define SCALE(a,b) ((b) == 0 ? 0.0 : (a) / (b)) + +/* This is the max number of FT_face objects we keep open at once + */ +#define MAX_OPEN_FACES 10 + +/** + * SECTION:cairo-ft + * @Title: FreeType Fonts + * @Short_Description: Font support for FreeType + * @See_Also: #cairo_font_face_t + * + * The FreeType font backend is primarily used to render text on GNU/Linux + * systems, but can be used on other platforms too. + **/ + +/** + * CAIRO_HAS_FT_FONT: + * + * Defined if the FreeType font backend is available. + * This macro can be used to conditionally compile backend-specific code. + * + * Since: 1.0 + **/ + +/** + * CAIRO_HAS_FC_FONT: + * + * Defined if the Fontconfig-specific functions of the FreeType font backend + * are available. + * This macro can be used to conditionally compile backend-specific code. + * + * Since: 1.10 + **/ + +/* + * The simple 2x2 matrix is converted into separate scale and shape + * factors so that hinting works right + */ + +typedef struct _cairo_ft_font_transform { + double x_scale, y_scale; + double shape[2][2]; +} cairo_ft_font_transform_t; + +/* + * We create an object that corresponds to a single font on the disk; + * (identified by a filename/id pair) these are shared between all + * fonts using that file. For cairo_ft_font_face_create_for_ft_face(), we + * just create a one-off version with a permanent face value. + */ + +typedef struct _cairo_ft_font_face cairo_ft_font_face_t; + +struct _cairo_ft_unscaled_font { + cairo_unscaled_font_t base; + + cairo_bool_t from_face; /* was the FT_Face provided by user? */ + FT_Face face; /* provided or cached face */ + + /* only set if from_face is false */ + char *filename; + int id; + + /* We temporarily scale the unscaled font as needed */ + cairo_bool_t have_scale; + cairo_matrix_t current_scale; + double x_scale; /* Extracted X scale factor */ + double y_scale; /* Extracted Y scale factor */ + cairo_bool_t have_shape; /* true if the current scale has a non-scale component*/ + cairo_matrix_t current_shape; + FT_Matrix Current_Shape; + + unsigned int have_color_set : 1; + unsigned int have_color : 1; /* true if the font contains color glyphs */ + FT_Fixed *variations; /* variation settings that FT_Face came */ + unsigned int num_palettes; + + cairo_mutex_t mutex; + int lock_count; + + cairo_ft_font_face_t *faces; /* Linked list of faces for this font */ +}; + +static int +_cairo_ft_unscaled_font_keys_equal (const void *key_a, + const void *key_b); + +static void +_cairo_ft_unscaled_font_fini (cairo_ft_unscaled_font_t *unscaled); + +typedef struct _cairo_ft_options { + cairo_font_options_t base; + unsigned int load_flags; /* flags for FT_Load_Glyph */ + unsigned int synth_flags; +} cairo_ft_options_t; + +static void +_cairo_ft_options_init_copy (cairo_ft_options_t *options, + const cairo_ft_options_t *other) +{ + _cairo_font_options_init_copy (&options->base, &other->base); + options->load_flags = other->load_flags; + options->synth_flags = other->synth_flags; +} + +static void +_cairo_ft_options_fini (cairo_ft_options_t *options) +{ + _cairo_font_options_fini (&options->base); +} + +struct _cairo_ft_font_face { + cairo_font_face_t base; + + cairo_ft_unscaled_font_t *unscaled; + cairo_ft_options_t ft_options; + cairo_ft_font_face_t *next; + +#if CAIRO_HAS_FC_FONT + FcPattern *pattern; /* if pattern is set, the above fields will be NULL */ + cairo_font_face_t *resolved_font_face; + FcConfig *resolved_config; +#endif +}; + +static const cairo_unscaled_font_backend_t cairo_ft_unscaled_font_backend; + +#if CAIRO_HAS_FC_FONT +static cairo_status_t +_cairo_ft_font_options_substitute (const cairo_font_options_t *options, + FcPattern *pattern); + +static cairo_font_face_t * +_cairo_ft_resolve_pattern (FcPattern *pattern, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options); + +#endif + +cairo_status_t +_cairo_ft_to_cairo_error (FT_Error error) +{ + /* Currently we don't get many (any?) useful statuses here. + * Populate as needed. */ + switch (error) + { + case FT_Err_Ok: + return CAIRO_STATUS_SUCCESS; + case FT_Err_Out_Of_Memory: + return CAIRO_STATUS_NO_MEMORY; + default: + return CAIRO_STATUS_FREETYPE_ERROR; + } +} + +/* + * We maintain a hash table to map file/id => #cairo_ft_unscaled_font_t. + * The hash table itself isn't limited in size. However, we limit the + * number of FT_Face objects we keep around; when we've exceeded that + * limit and need to create a new FT_Face, we dump the FT_Face from a + * random #cairo_ft_unscaled_font_t which has an unlocked FT_Face, (if + * there are any). + */ + +typedef struct _cairo_ft_unscaled_font_map { + cairo_hash_table_t *hash_table; + FT_Library ft_library; + int num_open_faces; +} cairo_ft_unscaled_font_map_t; + +static cairo_ft_unscaled_font_map_t *cairo_ft_unscaled_font_map = NULL; + + +static FT_Face +_cairo_ft_unscaled_font_lock_face (cairo_ft_unscaled_font_t *unscaled); + +static void +_cairo_ft_unscaled_font_unlock_face (cairo_ft_unscaled_font_t *unscaled); + +static cairo_bool_t +_cairo_ft_scaled_font_is_vertical (cairo_scaled_font_t *scaled_font); + + +static void +_font_map_release_face_lock_held (cairo_ft_unscaled_font_map_t *font_map, + cairo_ft_unscaled_font_t *unscaled) +{ + if (unscaled->face) { + FT_Done_Face (unscaled->face); + unscaled->face = NULL; + unscaled->have_scale = FALSE; + + font_map->num_open_faces--; + } +} + +static cairo_status_t +_cairo_ft_unscaled_font_map_create (void) +{ + cairo_ft_unscaled_font_map_t *font_map; + + /* This function is only intended to be called from + * _cairo_ft_unscaled_font_map_lock. So we'll crash if we can + * detect some other call path. */ + assert (cairo_ft_unscaled_font_map == NULL); + + font_map = _cairo_calloc (sizeof (cairo_ft_unscaled_font_map_t)); + if (unlikely (font_map == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + font_map->hash_table = + _cairo_hash_table_create (_cairo_ft_unscaled_font_keys_equal); + + if (unlikely (font_map->hash_table == NULL)) + goto FAIL; + + if (unlikely (FT_Init_FreeType (&font_map->ft_library))) + goto FAIL; + + font_map->num_open_faces = 0; + + cairo_ft_unscaled_font_map = font_map; + return CAIRO_STATUS_SUCCESS; + +FAIL: + if (font_map->hash_table) + _cairo_hash_table_destroy (font_map->hash_table); + free (font_map); + + return _cairo_error (CAIRO_STATUS_NO_MEMORY); +} + + +static void +_cairo_ft_unscaled_font_map_pluck_entry (void *entry, void *closure) +{ + cairo_ft_unscaled_font_t *unscaled = entry; + cairo_ft_unscaled_font_map_t *font_map = closure; + + _cairo_hash_table_remove (font_map->hash_table, + &unscaled->base.hash_entry); + + if (! unscaled->from_face) + _font_map_release_face_lock_held (font_map, unscaled); + + _cairo_ft_unscaled_font_fini (unscaled); + free (unscaled); +} + +static void +_cairo_ft_unscaled_font_map_destroy (void) +{ + cairo_ft_unscaled_font_map_t *font_map; + + CAIRO_MUTEX_LOCK (_cairo_ft_unscaled_font_map_mutex); + font_map = cairo_ft_unscaled_font_map; + cairo_ft_unscaled_font_map = NULL; + CAIRO_MUTEX_UNLOCK (_cairo_ft_unscaled_font_map_mutex); + + if (font_map != NULL) { + _cairo_hash_table_foreach (font_map->hash_table, + _cairo_ft_unscaled_font_map_pluck_entry, + font_map); + assert (font_map->num_open_faces == 0); + + FT_Done_FreeType (font_map->ft_library); + + _cairo_hash_table_destroy (font_map->hash_table); + + free (font_map); + } +} + +static cairo_ft_unscaled_font_map_t * +_cairo_ft_unscaled_font_map_lock (void) +{ + CAIRO_MUTEX_INITIALIZE (); + + CAIRO_MUTEX_LOCK (_cairo_ft_unscaled_font_map_mutex); + + if (unlikely (cairo_ft_unscaled_font_map == NULL)) { + if (unlikely (_cairo_ft_unscaled_font_map_create ())) { + CAIRO_MUTEX_UNLOCK (_cairo_ft_unscaled_font_map_mutex); + return NULL; + } + } + + return cairo_ft_unscaled_font_map; +} + +static void +_cairo_ft_unscaled_font_map_unlock (void) +{ + CAIRO_MUTEX_UNLOCK (_cairo_ft_unscaled_font_map_mutex); +} + +static void +_cairo_ft_unscaled_font_init_key (cairo_ft_unscaled_font_t *key, + cairo_bool_t from_face, + char *filename, + int id, + FT_Face face) +{ + uintptr_t hash; + + key->from_face = from_face; + key->filename = filename; + key->id = id; + key->face = face; + + hash = _cairo_hash_string (filename); + /* the constants are just arbitrary primes */ + hash += ((uintptr_t) id) * 1607; + hash += ((uintptr_t) face) * 2137; + + key->base.hash_entry.hash = hash; +} + +/** + * _cairo_ft_unscaled_font_init: + * + * Initialize a #cairo_ft_unscaled_font_t. + * + * There are two basic flavors of #cairo_ft_unscaled_font_t, one + * created from an FT_Face and the other created from a filename/id + * pair. These two flavors are identified as from_face and !from_face. + * + * To initialize a from_face font, pass filename==%NULL, id=0 and the + * desired face. + * + * To initialize a !from_face font, pass the filename/id as desired + * and face==%NULL. + * + * Note that the code handles these two flavors in very distinct + * ways. For example there is a hash_table mapping + * filename/id->#cairo_unscaled_font_t in the !from_face case, but no + * parallel in the from_face case, (where the calling code would have + * to do its own mapping to ensure similar sharing). + **/ +static cairo_status_t +_cairo_ft_unscaled_font_init (cairo_ft_unscaled_font_t *unscaled, + cairo_bool_t from_face, + const char *filename, + int id, + FT_Face face) +{ + _cairo_unscaled_font_init (&unscaled->base, + &cairo_ft_unscaled_font_backend); + + unscaled->variations = NULL; + + if (from_face) { + FT_MM_Var *ft_mm_var; + unscaled->from_face = TRUE; + _cairo_ft_unscaled_font_init_key (unscaled, TRUE, NULL, id, face); + + + unscaled->have_color = FT_HAS_COLOR (face) != 0; + unscaled->have_color_set = TRUE; + if (FT_Get_MM_Var (face, &ft_mm_var) == 0) { + unscaled->variations = _cairo_calloc_ab (ft_mm_var->num_axis, sizeof (FT_Fixed)); + if (unscaled->variations) + FT_Get_Var_Design_Coordinates (face, ft_mm_var->num_axis, unscaled->variations); + FT_Done_MM_Var (face->glyph->library, ft_mm_var); + } + } else { + char *filename_copy; + + unscaled->from_face = FALSE; + unscaled->face = NULL; + + filename_copy = strdup (filename); + if (unlikely (filename_copy == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + _cairo_ft_unscaled_font_init_key (unscaled, FALSE, filename_copy, id, NULL); + + unscaled->have_color_set = FALSE; + } + + unscaled->have_scale = FALSE; + CAIRO_MUTEX_INIT (unscaled->mutex); + unscaled->lock_count = 0; + + unscaled->faces = NULL; + + return CAIRO_STATUS_SUCCESS; +} + +/** + * _cairo_ft_unscaled_font_fini: + * + * Free all data associated with a #cairo_ft_unscaled_font_t. + * + * CAUTION: The unscaled->face field must be %NULL before calling this + * function. This is because the #cairo_ft_unscaled_font_t_map keeps a + * count of these faces (font_map->num_open_faces) so it maintains the + * unscaled->face field while it has its lock held. See + * _font_map_release_face_lock_held(). + **/ +static void +_cairo_ft_unscaled_font_fini (cairo_ft_unscaled_font_t *unscaled) +{ + assert (unscaled->face == NULL); + + free (unscaled->filename); + unscaled->filename = NULL; + + free (unscaled->variations); + + CAIRO_MUTEX_FINI (unscaled->mutex); +} + +static int +_cairo_ft_unscaled_font_keys_equal (const void *key_a, + const void *key_b) +{ + const cairo_ft_unscaled_font_t *unscaled_a = key_a; + const cairo_ft_unscaled_font_t *unscaled_b = key_b; + + if (unscaled_a->id == unscaled_b->id && + unscaled_a->from_face == unscaled_b->from_face) + { + if (unscaled_a->from_face) + return unscaled_a->face == unscaled_b->face; + + if (unscaled_a->filename == NULL && unscaled_b->filename == NULL) + return TRUE; + else if (unscaled_a->filename == NULL || unscaled_b->filename == NULL) + return FALSE; + else + return (strcmp (unscaled_a->filename, unscaled_b->filename) == 0); + } + + return FALSE; +} + +/* Finds or creates a #cairo_ft_unscaled_font_t for the filename/id from + * pattern. Returns a new reference to the unscaled font. + */ +static cairo_status_t +_cairo_ft_unscaled_font_create_internal (cairo_bool_t from_face, + char *filename, + int id, + FT_Face font_face, + cairo_ft_unscaled_font_t **out) +{ + cairo_ft_unscaled_font_t key, *unscaled; + cairo_ft_unscaled_font_map_t *font_map; + cairo_status_t status; + + font_map = _cairo_ft_unscaled_font_map_lock (); + if (unlikely (font_map == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + _cairo_ft_unscaled_font_init_key (&key, from_face, filename, id, font_face); + + /* Return existing unscaled font if it exists in the hash table. */ + unscaled = _cairo_hash_table_lookup (font_map->hash_table, + &key.base.hash_entry); + if (unscaled != NULL) { + _cairo_unscaled_font_reference (&unscaled->base); + goto DONE; + } + + /* Otherwise create it and insert into hash table. */ + unscaled = _cairo_calloc (sizeof (cairo_ft_unscaled_font_t)); + if (unlikely (unscaled == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto UNWIND_FONT_MAP_LOCK; + } + + status = _cairo_ft_unscaled_font_init (unscaled, from_face, filename, id, font_face); + if (unlikely (status)) + goto UNWIND_UNSCALED_MALLOC; + + assert (unscaled->base.hash_entry.hash == key.base.hash_entry.hash); + status = _cairo_hash_table_insert (font_map->hash_table, + &unscaled->base.hash_entry); + if (unlikely (status)) + goto UNWIND_UNSCALED_FONT_INIT; + +DONE: + _cairo_ft_unscaled_font_map_unlock (); + *out = unscaled; + return CAIRO_STATUS_SUCCESS; + +UNWIND_UNSCALED_FONT_INIT: + _cairo_ft_unscaled_font_fini (unscaled); +UNWIND_UNSCALED_MALLOC: + free (unscaled); +UNWIND_FONT_MAP_LOCK: + _cairo_ft_unscaled_font_map_unlock (); + return status; +} + + +#if CAIRO_HAS_FC_FONT +static cairo_status_t +_cairo_ft_unscaled_font_create_for_pattern (FcPattern *pattern, + cairo_ft_unscaled_font_t **out) +{ + FT_Face font_face = NULL; + char *filename = NULL; + int id = 0; + FcResult ret; + + ret = FcPatternGetFTFace (pattern, FC_FT_FACE, 0, &font_face); + if (ret == FcResultMatch) + goto DONE; + if (ret == FcResultOutOfMemory) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + ret = FcPatternGetString (pattern, FC_FILE, 0, (FcChar8 **) &filename); + if (ret == FcResultOutOfMemory) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + if (ret == FcResultMatch) { + if (access (filename, R_OK) == 0) { + /* If FC_INDEX is not set, we just use 0 */ + ret = FcPatternGetInteger (pattern, FC_INDEX, 0, &id); + if (ret == FcResultOutOfMemory) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + goto DONE; + } else + return _cairo_error (CAIRO_STATUS_FILE_NOT_FOUND); + } + + /* The pattern contains neither a face nor a filename, resolve it later. */ + *out = NULL; + return CAIRO_STATUS_SUCCESS; + +DONE: + return _cairo_ft_unscaled_font_create_internal (font_face != NULL, + filename, id, font_face, + out); +} +#endif + +static cairo_status_t +_cairo_ft_unscaled_font_create_from_face (FT_Face face, + cairo_ft_unscaled_font_t **out) +{ + return _cairo_ft_unscaled_font_create_internal (TRUE, NULL, face->face_index, face, out); +} + +static cairo_bool_t +_cairo_ft_unscaled_font_destroy (void *abstract_font) +{ + cairo_ft_unscaled_font_t *unscaled = abstract_font; + cairo_ft_unscaled_font_map_t *font_map; + + font_map = _cairo_ft_unscaled_font_map_lock (); + /* All created objects must have been mapped in the font map. */ + assert (font_map != NULL); + + if (! _cairo_reference_count_dec_and_test (&unscaled->base.ref_count)) { + /* somebody recreated the font whilst we waited for the lock */ + _cairo_ft_unscaled_font_map_unlock (); + return FALSE; + } + + _cairo_hash_table_remove (font_map->hash_table, + &unscaled->base.hash_entry); + + if (unscaled->from_face) { + /* See comments in _ft_font_face_destroy about the "zombie" state + * for a _ft_font_face. + */ + if (unscaled->faces && unscaled->faces->unscaled == NULL) { + assert (unscaled->faces->next == NULL); + cairo_font_face_destroy (&unscaled->faces->base); + } + } else { + _font_map_release_face_lock_held (font_map, unscaled); + } + unscaled->face = NULL; + + _cairo_ft_unscaled_font_map_unlock (); + + _cairo_ft_unscaled_font_fini (unscaled); + return TRUE; +} + +static cairo_bool_t +_has_unlocked_face (const void *entry) +{ + const cairo_ft_unscaled_font_t *unscaled = entry; + + return (!unscaled->from_face && unscaled->lock_count == 0 && unscaled->face); +} + +/* Ensures that an unscaled font has a face object. If we exceed + * MAX_OPEN_FACES, try to close some. + * + * This differs from _cairo_ft_scaled_font_lock_face in that it doesn't + * set the scale on the face, but just returns it at the last scale. + */ +static cairo_warn FT_Face +_cairo_ft_unscaled_font_lock_face (cairo_ft_unscaled_font_t *unscaled) +{ + cairo_ft_unscaled_font_map_t *font_map; + FT_Face face = NULL; + FT_Error error; + + CAIRO_MUTEX_LOCK (unscaled->mutex); + unscaled->lock_count++; + + if (unscaled->face) + return unscaled->face; + + /* If this unscaled font was created from an FT_Face then we just + * returned it above. */ + assert (!unscaled->from_face); + + font_map = _cairo_ft_unscaled_font_map_lock (); + { + assert (font_map != NULL); + + while (font_map->num_open_faces >= MAX_OPEN_FACES) + { + cairo_ft_unscaled_font_t *entry; + + entry = _cairo_hash_table_random_entry (font_map->hash_table, + _has_unlocked_face); + if (entry == NULL) + break; + + _font_map_release_face_lock_held (font_map, entry); + } + } + _cairo_ft_unscaled_font_map_unlock (); + + error = FT_New_Face (font_map->ft_library, + unscaled->filename, + unscaled->id, + &face); + if (error) + { + unscaled->lock_count--; + CAIRO_MUTEX_UNLOCK (unscaled->mutex); + _cairo_error_throw (_cairo_ft_to_cairo_error (error)); + return NULL; + } + + unscaled->face = face; + + unscaled->have_color = FT_HAS_COLOR (face) != 0; + unscaled->have_color_set = TRUE; + + font_map->num_open_faces++; + + return face; +} + + +/* Unlock unscaled font locked with _cairo_ft_unscaled_font_lock_face + */ +static void +_cairo_ft_unscaled_font_unlock_face (cairo_ft_unscaled_font_t *unscaled) +{ + assert (unscaled->lock_count > 0); + + unscaled->lock_count--; + + CAIRO_MUTEX_UNLOCK (unscaled->mutex); +} + + +static cairo_status_t +_compute_transform (cairo_ft_font_transform_t *sf, + cairo_matrix_t *scale, + cairo_ft_unscaled_font_t *unscaled) +{ + cairo_status_t status; + double x_scale, y_scale; + cairo_matrix_t normalized = *scale; + + /* The font matrix has x and y "scale" components which we extract and + * use as character scale values. These influence the way freetype + * chooses hints, as well as selecting different bitmaps in + * hand-rendered fonts. We also copy the normalized matrix to + * freetype's transformation. + */ + + status = _cairo_matrix_compute_basis_scale_factors (scale, + &x_scale, &y_scale, + 1); + if (unlikely (status)) + return status; + + /* FreeType docs say this about x_scale and y_scale: + * "A character width or height smaller than 1pt is set to 1pt;" + * So, we cap them from below at 1.0 and let the FT transform + * take care of sub-1.0 scaling. */ + if (x_scale < 1.0) + x_scale = 1.0; + if (y_scale < 1.0) + y_scale = 1.0; + + if (unscaled && (unscaled->face->face_flags & FT_FACE_FLAG_SCALABLE) == 0) { + double min_distance = DBL_MAX; + cairo_bool_t magnify = TRUE; + int i; + double best_x_size = 0; + double best_y_size = 0; + + for (i = 0; i < unscaled->face->num_fixed_sizes; i++) { + double x_size = unscaled->face->available_sizes[i].x_ppem / 64.; + double y_size = unscaled->face->available_sizes[i].y_ppem / 64.; + double distance = y_size - y_scale; + + /* + * distance is positive if current strike is larger than desired + * size, and negative if smaller. + * + * We like to prefer down-scaling to upscaling. + */ + + if ((magnify && distance >= 0) || fabs (distance) <= min_distance) { + magnify = distance < 0; + min_distance = fabs (distance); + best_x_size = x_size; + best_y_size = y_size; + } + } + + x_scale = best_x_size; + y_scale = best_y_size; + } + + sf->x_scale = x_scale; + sf->y_scale = y_scale; + + cairo_matrix_scale (&normalized, 1.0 / x_scale, 1.0 / y_scale); + + _cairo_matrix_get_affine (&normalized, + &sf->shape[0][0], &sf->shape[0][1], + &sf->shape[1][0], &sf->shape[1][1], + NULL, NULL); + + return CAIRO_STATUS_SUCCESS; +} + +/* Temporarily scales an unscaled font to the give scale. We catch + * scaling to the same size, since changing a FT_Face is expensive. + */ +static cairo_status_t +_cairo_ft_unscaled_font_set_scale (cairo_ft_unscaled_font_t *unscaled, + cairo_matrix_t *scale) +{ + cairo_status_t status; + cairo_ft_font_transform_t sf; + FT_Matrix mat; + FT_Error error; + + assert (unscaled->face != NULL); + + if (unscaled->have_scale && + scale->xx == unscaled->current_scale.xx && + scale->yx == unscaled->current_scale.yx && + scale->xy == unscaled->current_scale.xy && + scale->yy == unscaled->current_scale.yy) + return CAIRO_STATUS_SUCCESS; + + unscaled->have_scale = TRUE; + unscaled->current_scale = *scale; + + status = _compute_transform (&sf, scale, unscaled); + if (unlikely (status)) + return status; + + unscaled->x_scale = sf.x_scale; + unscaled->y_scale = sf.y_scale; + + mat.xx = DOUBLE_TO_16_16(sf.shape[0][0]); + mat.yx = - DOUBLE_TO_16_16(sf.shape[0][1]); + mat.xy = - DOUBLE_TO_16_16(sf.shape[1][0]); + mat.yy = DOUBLE_TO_16_16(sf.shape[1][1]); + + unscaled->have_shape = (mat.xx != 0x10000 || + mat.yx != 0x00000 || + mat.xy != 0x00000 || + mat.yy != 0x10000); + + unscaled->Current_Shape = mat; + cairo_matrix_init (&unscaled->current_shape, + sf.shape[0][0], sf.shape[0][1], + sf.shape[1][0], sf.shape[1][1], + 0.0, 0.0); + + FT_Set_Transform(unscaled->face, &mat, NULL); + + error = FT_Set_Char_Size (unscaled->face, + sf.x_scale * 64.0 + .5, + sf.y_scale * 64.0 + .5, + 0, 0); + if (error) + return _cairo_error (_cairo_ft_to_cairo_error (error)); + + return CAIRO_STATUS_SUCCESS; +} + +/* we sometimes need to convert the glyph bitmap in a FT_GlyphSlot + * into a different format. For example, we want to convert a + * FT_PIXEL_MODE_LCD or FT_PIXEL_MODE_LCD_V bitmap into a 32-bit + * ARGB or ABGR bitmap. + * + * this function prepares a target descriptor for this operation. + * + * input :: target bitmap descriptor. The function will set its + * 'width', 'rows' and 'pitch' fields, and only these + * + * slot :: the glyph slot containing the source bitmap. this + * function assumes that slot->format == FT_GLYPH_FORMAT_BITMAP + * + * mode :: the requested final rendering mode. supported values are + * MONO, NORMAL (i.e. gray), LCD and LCD_V + * + * the function returns the size in bytes of the corresponding buffer, + * it's up to the caller to allocate the corresponding memory block + * before calling _fill_xrender_bitmap + * + * it also returns -1 in case of error (e.g. incompatible arguments, + * like trying to convert a gray bitmap into a monochrome one) + */ +static int +_compute_xrender_bitmap_size(FT_Bitmap *target, + FT_GlyphSlot slot, + FT_Render_Mode mode) +{ + FT_Bitmap *ftbit; + int width, height, pitch; + + if (slot->format != FT_GLYPH_FORMAT_BITMAP) + return -1; + + /* compute the size of the final bitmap */ + ftbit = &slot->bitmap; + + width = ftbit->width; + height = ftbit->rows; + pitch = (width + 3) & ~3; + + switch (ftbit->pixel_mode) { + case FT_PIXEL_MODE_MONO: + if (mode == FT_RENDER_MODE_MONO) { + pitch = (((width + 31) & ~31) >> 3); + break; + } + /* fall-through */ + + case FT_PIXEL_MODE_GRAY: + if (mode == FT_RENDER_MODE_LCD || + mode == FT_RENDER_MODE_LCD_V) + { + /* each pixel is replicated into a 32-bit ARGB value */ + pitch = width * 4; + } + break; + + case FT_PIXEL_MODE_LCD: + if (mode != FT_RENDER_MODE_LCD) + return -1; + + /* horz pixel triplets are packed into 32-bit ARGB values */ + width /= 3; + pitch = width * 4; + break; + + case FT_PIXEL_MODE_LCD_V: + if (mode != FT_RENDER_MODE_LCD_V) + return -1; + + /* vert pixel triplets are packed into 32-bit ARGB values */ + height /= 3; + pitch = width * 4; + break; + + case FT_PIXEL_MODE_BGRA: + /* each pixel is replicated into a 32-bit ARGB value */ + pitch = width * 4; + break; + + default: /* unsupported source format */ + return -1; + } + + target->width = width; + target->rows = height; + target->pitch = pitch; + target->buffer = NULL; + + return pitch * height; +} + +/* this functions converts the glyph bitmap found in a FT_GlyphSlot + * into a different format (see _compute_xrender_bitmap_size) + * + * you should call this function after _compute_xrender_bitmap_size + * + * target :: target bitmap descriptor. Note that its 'buffer' pointer + * must point to memory allocated by the caller + * + * slot :: the glyph slot containing the source bitmap + * + * mode :: the requested final rendering mode + * + * bgr :: boolean, set if BGR or VBGR pixel ordering is needed + */ +static void +_fill_xrender_bitmap(FT_Bitmap *target, + FT_GlyphSlot slot, + FT_Render_Mode mode, + int bgr) +{ + FT_Bitmap *ftbit = &slot->bitmap; + unsigned char *srcLine = ftbit->buffer; + unsigned char *dstLine = target->buffer; + int src_pitch = ftbit->pitch; + int width = target->width; + int height = target->rows; + int pitch = target->pitch; + int subpixel; + int h; + + subpixel = (mode == FT_RENDER_MODE_LCD || + mode == FT_RENDER_MODE_LCD_V); + + if (src_pitch < 0) + srcLine -= src_pitch * (ftbit->rows - 1); + + target->pixel_mode = ftbit->pixel_mode; + + switch (ftbit->pixel_mode) { + case FT_PIXEL_MODE_MONO: + if (subpixel) { + /* convert mono to ARGB32 values */ + + for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) { + int x; + + for (x = 0; x < width; x++) { + if (srcLine[(x >> 3)] & (0x80 >> (x & 7))) + ((unsigned int *) dstLine)[x] = 0xffffffffU; + } + } + target->pixel_mode = FT_PIXEL_MODE_LCD; + + } else if (mode == FT_RENDER_MODE_NORMAL) { + /* convert mono to 8-bit gray */ + + for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) { + int x; + + for (x = 0; x < width; x++) { + if (srcLine[(x >> 3)] & (0x80 >> (x & 7))) + dstLine[x] = 0xff; + } + } + target->pixel_mode = FT_PIXEL_MODE_GRAY; + + } else { + /* copy mono to mono */ + + int bytes = (width + 7) >> 3; + + for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) + memcpy (dstLine, srcLine, bytes); + } + break; + + case FT_PIXEL_MODE_GRAY: + if (subpixel) { + /* convert gray to ARGB32 values */ + + for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) { + int x; + unsigned int *dst = (unsigned int *) dstLine; + + for (x = 0; x < width; x++) { + unsigned int pix = srcLine[x]; + + pix |= (pix << 8); + pix |= (pix << 16); + + dst[x] = pix; + } + } + target->pixel_mode = FT_PIXEL_MODE_LCD; + } else { + /* copy gray into gray */ + + for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) + memcpy (dstLine, srcLine, width); + } + break; + + case FT_PIXEL_MODE_LCD: + if (!bgr) { + /* convert horizontal RGB into ARGB32 */ + + for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) { + int x; + unsigned char *src = srcLine; + unsigned int *dst = (unsigned int *) dstLine; + + for (x = 0; x < width; x++, src += 3) { + unsigned int pix; + + pix = ((unsigned int)src[0] << 16) | + ((unsigned int)src[1] << 8) | + ((unsigned int)src[2] ) | + ((unsigned int)src[1] << 24) ; + + dst[x] = pix; + } + } + } else { + /* convert horizontal BGR into ARGB32 */ + + for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) { + + int x; + unsigned char *src = srcLine; + unsigned int *dst = (unsigned int *) dstLine; + + for (x = 0; x < width; x++, src += 3) { + unsigned int pix; + + pix = ((unsigned int)src[2] << 16) | + ((unsigned int)src[1] << 8) | + ((unsigned int)src[0] ) | + ((unsigned int)src[1] << 24) ; + + dst[x] = pix; + } + } + } + break; + + case FT_PIXEL_MODE_LCD_V: + /* convert vertical RGB into ARGB32 */ + if (!bgr) { + + for (h = height; h > 0; h--, srcLine += 3 * src_pitch, dstLine += pitch) { + int x; + unsigned char* src = srcLine; + unsigned int* dst = (unsigned int *) dstLine; + + for (x = 0; x < width; x++, src += 1) { + unsigned int pix; + pix = ((unsigned int)src[0] << 16) | + ((unsigned int)src[src_pitch] << 8) | + ((unsigned int)src[src_pitch*2] ) | + ((unsigned int)src[src_pitch] << 24) ; + dst[x] = pix; + } + } + } else { + + for (h = height; h > 0; h--, srcLine += 3*src_pitch, dstLine += pitch) { + int x; + unsigned char *src = srcLine; + unsigned int *dst = (unsigned int *) dstLine; + + for (x = 0; x < width; x++, src += 1) { + unsigned int pix; + + pix = ((unsigned int)src[src_pitch * 2] << 16) | + ((unsigned int)src[src_pitch] << 8) | + ((unsigned int)src[0] ) | + ((unsigned int)src[src_pitch] << 24) ; + + dst[x] = pix; + } + } + } + break; + + case FT_PIXEL_MODE_BGRA: + for (h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch) + memcpy (dstLine, srcLine, (size_t)width * 4); + break; + + default: + assert (0); + } +} + + +/* Fills in val->image with an image surface created from @bitmap + */ +static cairo_status_t +_get_bitmap_surface (FT_Bitmap *bitmap, + FT_Library library, + cairo_bool_t own_buffer, + cairo_font_options_t *font_options, + cairo_image_surface_t **surface) +{ + unsigned int width, height; + unsigned char *data; + int format = CAIRO_FORMAT_A8; + int stride; + cairo_image_surface_t *image; + cairo_bool_t component_alpha = FALSE; + + width = bitmap->width; + height = bitmap->rows; + + if (width == 0 || height == 0) { + *surface = (cairo_image_surface_t *) + cairo_image_surface_create_for_data (NULL, format, 0, 0, 0); + return (*surface)->base.status; + } + + switch (bitmap->pixel_mode) { + case FT_PIXEL_MODE_MONO: + stride = (((width + 31) & ~31) >> 3); + if (own_buffer) { + data = bitmap->buffer; + assert (stride == bitmap->pitch); + } else { + data = _cairo_malloc_ab (height, stride); + if (!data) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + if (stride == bitmap->pitch) { + memcpy (data, bitmap->buffer, (size_t)stride * height); + } else { + int i; + unsigned char *source, *dest; + + source = bitmap->buffer; + dest = data; + for (i = height; i; i--) { + memcpy (dest, source, bitmap->pitch); + memset (dest + bitmap->pitch, '\0', stride - bitmap->pitch); + + source += bitmap->pitch; + dest += stride; + } + } + } + +#ifndef WORDS_BIGENDIAN + { + uint8_t *d = data; + int count = stride * height; + + while (count--) { + *d = CAIRO_BITSWAP8 (*d); + d++; + } + } +#endif + format = CAIRO_FORMAT_A1; + break; + + case FT_PIXEL_MODE_LCD: + case FT_PIXEL_MODE_LCD_V: + case FT_PIXEL_MODE_GRAY: + if (font_options->antialias != CAIRO_ANTIALIAS_SUBPIXEL || + bitmap->pixel_mode == FT_PIXEL_MODE_GRAY) + { + stride = bitmap->pitch; + + /* We don't support stride not multiple of 4. */ + if (stride & 3) + { + assert (!own_buffer); + goto convert; + } + + if (own_buffer) { + data = bitmap->buffer; + } else { + data = _cairo_malloc_ab (height, stride); + if (!data) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + memcpy (data, bitmap->buffer, (size_t)stride * height); + } + + format = CAIRO_FORMAT_A8; + } else { + data = bitmap->buffer; + stride = bitmap->pitch; + format = CAIRO_FORMAT_ARGB32; + component_alpha = TRUE; + } + break; + case FT_PIXEL_MODE_BGRA: + stride = width * 4; + if (own_buffer) { + data = bitmap->buffer; + } else { + data = _cairo_malloc_ab (height, stride); + if (!data) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + memcpy (data, bitmap->buffer, (size_t)stride * height); + } + + if (!_cairo_is_little_endian ()) + { + /* Byteswap. */ + unsigned int i, count = height * width; + uint32_t *p = (uint32_t *) data; + for (i = 0; i < count; i++) + p[i] = bswap_32 (p[i]); + } + format = CAIRO_FORMAT_ARGB32; + break; + case FT_PIXEL_MODE_GRAY2: + case FT_PIXEL_MODE_GRAY4: + convert: + if (!own_buffer && library) + { + /* This is pretty much the only case that we can get in here. */ + /* Convert to 8bit grayscale. */ + + FT_Bitmap tmp; + FT_Int align; + FT_Error error; + + format = CAIRO_FORMAT_A8; + + align = cairo_format_stride_for_width (format, bitmap->width); + + FT_Bitmap_New( &tmp ); + + error = FT_Bitmap_Convert( library, bitmap, &tmp, align ); + if (error) + return _cairo_error (_cairo_ft_to_cairo_error (error)); + + FT_Bitmap_Done( library, bitmap ); + *bitmap = tmp; + + stride = bitmap->pitch; + data = _cairo_malloc_ab (height, stride); + if (!data) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + if (bitmap->num_grays != 256) + { + unsigned int x, y; + unsigned int mul = 255 / (bitmap->num_grays - 1); + FT_Byte *p = bitmap->buffer; + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) + p[x] *= mul; + p += bitmap->pitch; + } + } + + memcpy (data, bitmap->buffer, (size_t)stride * height); + break; + } + /* fall through */ + /* These could be triggered by very rare types of TrueType fonts */ + default: + if (own_buffer) + free (bitmap->buffer); + return _cairo_error (CAIRO_STATUS_INVALID_FORMAT); + } + + /* XXX */ + *surface = image = (cairo_image_surface_t *) + cairo_image_surface_create_for_data (data, + format, + width, height, stride); + if (image->base.status) { + free (data); + return (*surface)->base.status; + } + + if (component_alpha) + pixman_image_set_component_alpha (image->pixman_image, TRUE); + + _cairo_image_surface_assume_ownership_of_data (image); + + _cairo_debug_check_image_surface_is_defined (&image->base); + + return CAIRO_STATUS_SUCCESS; +} + +/* Converts an outline FT_GlyphSlot into an image + * + * This could go through _render_glyph_bitmap as well, letting + * FreeType convert the outline to a bitmap, but doing it ourselves + * has two minor advantages: first, we save a copy of the bitmap + * buffer: we can directly use the buffer that FreeType renders + * into. + * + * Second, it may help when we add support for subpixel + * rendering: the Xft code does it this way. (Keith thinks that + * it may also be possible to get the subpixel rendering with + * FT_Render_Glyph: something worth looking into in more detail + * when we add subpixel support. If so, we may want to eliminate + * this version of the code path entirely. + */ +static cairo_status_t +_render_glyph_outline (FT_Face face, + cairo_font_options_t *font_options, + cairo_image_surface_t **surface) +{ + cairo_subpixel_order_t rgba = CAIRO_SUBPIXEL_ORDER_DEFAULT; + int lcd_filter = FT_LCD_FILTER_DEFAULT; + FT_GlyphSlot glyphslot = face->glyph; + FT_Outline *outline = &glyphslot->outline; + FT_Bitmap bitmap; + FT_BBox cbox; + unsigned int width, height; + cairo_status_t status; + FT_Error error; + FT_Library library = glyphslot->library; + FT_Render_Mode render_mode = FT_RENDER_MODE_NORMAL; + + switch (font_options->antialias) { + case CAIRO_ANTIALIAS_NONE: + render_mode = FT_RENDER_MODE_MONO; + break; + + case CAIRO_ANTIALIAS_SUBPIXEL: + case CAIRO_ANTIALIAS_BEST: + switch (font_options->subpixel_order) { + case CAIRO_SUBPIXEL_ORDER_DEFAULT: + case CAIRO_SUBPIXEL_ORDER_RGB: + case CAIRO_SUBPIXEL_ORDER_BGR: + render_mode = FT_RENDER_MODE_LCD; + break; + + case CAIRO_SUBPIXEL_ORDER_VRGB: + case CAIRO_SUBPIXEL_ORDER_VBGR: + render_mode = FT_RENDER_MODE_LCD_V; + break; + } + + switch (font_options->lcd_filter) { + case CAIRO_LCD_FILTER_NONE: + lcd_filter = FT_LCD_FILTER_NONE; + break; + case CAIRO_LCD_FILTER_INTRA_PIXEL: + lcd_filter = FT_LCD_FILTER_LEGACY; + break; + case CAIRO_LCD_FILTER_FIR3: + lcd_filter = FT_LCD_FILTER_LIGHT; + break; + case CAIRO_LCD_FILTER_DEFAULT: + case CAIRO_LCD_FILTER_FIR5: + lcd_filter = FT_LCD_FILTER_DEFAULT; + break; + } + + break; + + case CAIRO_ANTIALIAS_DEFAULT: + case CAIRO_ANTIALIAS_GRAY: + case CAIRO_ANTIALIAS_GOOD: + case CAIRO_ANTIALIAS_FAST: + render_mode = FT_RENDER_MODE_NORMAL; + } + + FT_Outline_Get_CBox (outline, &cbox); + + cbox.xMin &= -64; + cbox.yMin &= -64; + cbox.xMax = (cbox.xMax + 63) & -64; + cbox.yMax = (cbox.yMax + 63) & -64; + + width = (unsigned int) ((cbox.xMax - cbox.xMin) >> 6); + height = (unsigned int) ((cbox.yMax - cbox.yMin) >> 6); + + if (width * height == 0) { + cairo_format_t format; + /* Looks like fb handles zero-sized images just fine */ + switch (render_mode) { + case FT_RENDER_MODE_MONO: + format = CAIRO_FORMAT_A1; + break; + case FT_RENDER_MODE_LCD: + case FT_RENDER_MODE_LCD_V: + format= CAIRO_FORMAT_ARGB32; + break; + case FT_RENDER_MODE_LIGHT: + case FT_RENDER_MODE_NORMAL: + case FT_RENDER_MODE_MAX: +#if HAVE_FT_RENDER_MODE_SDF + case FT_RENDER_MODE_SDF: +#endif + default: + format = CAIRO_FORMAT_A8; + break; + } + + (*surface) = (cairo_image_surface_t *) + cairo_image_surface_create_for_data (NULL, format, 0, 0, 0); + pixman_image_set_component_alpha ((*surface)->pixman_image, TRUE); + if ((*surface)->base.status) + return (*surface)->base.status; + } else { + + int bitmap_size; + + switch (render_mode) { + case FT_RENDER_MODE_LCD: + if (font_options->subpixel_order == CAIRO_SUBPIXEL_ORDER_BGR) + rgba = CAIRO_SUBPIXEL_ORDER_BGR; + else + rgba = CAIRO_SUBPIXEL_ORDER_RGB; + break; + + case FT_RENDER_MODE_LCD_V: + if (font_options->subpixel_order == CAIRO_SUBPIXEL_ORDER_VBGR) + rgba = CAIRO_SUBPIXEL_ORDER_VBGR; + else + rgba = CAIRO_SUBPIXEL_ORDER_VRGB; + break; + + case FT_RENDER_MODE_MONO: + case FT_RENDER_MODE_LIGHT: + case FT_RENDER_MODE_NORMAL: + case FT_RENDER_MODE_MAX: +#if HAVE_FT_RENDER_MODE_SDF + case FT_RENDER_MODE_SDF: +#endif + default: + break; + } + + FT_Library_SetLcdFilter (library, lcd_filter); + error = FT_Render_Glyph (face->glyph, render_mode); + + FT_Library_SetLcdFilter (library, FT_LCD_FILTER_NONE); + if (error) + return _cairo_error (_cairo_ft_to_cairo_error (error)); + + bitmap_size = _compute_xrender_bitmap_size (&bitmap, + face->glyph, + render_mode); + if (bitmap_size < 0) + return _cairo_error (CAIRO_STATUS_INVALID_FORMAT); + + bitmap.buffer = _cairo_calloc (bitmap_size); + if (bitmap.buffer == NULL) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + _fill_xrender_bitmap (&bitmap, face->glyph, render_mode, + (rgba == CAIRO_SUBPIXEL_ORDER_BGR || rgba == CAIRO_SUBPIXEL_ORDER_VBGR)); + + /* Note: + * _get_bitmap_surface will free bitmap.buffer if there is an error + */ + status = _get_bitmap_surface (&bitmap, NULL, TRUE, font_options, surface); + if (unlikely (status)) + return status; + + /* Note: the font's coordinate system is upside down from ours, so the + * Y coordinate of the control box needs to be negated. Moreover, device + * offsets are position of glyph origin relative to top left while xMin + * and yMax are offsets of top left relative to origin. Another negation. + */ + cairo_surface_set_device_offset (&(*surface)->base, + (double)-glyphslot->bitmap_left, + (double)+glyphslot->bitmap_top); + } + + return CAIRO_STATUS_SUCCESS; +} + +/* Converts a bitmap (or other) FT_GlyphSlot into an image */ +static cairo_status_t +_render_glyph_bitmap (FT_Face face, + cairo_font_options_t *font_options, + cairo_image_surface_t **surface) +{ + FT_GlyphSlot glyphslot = face->glyph; + cairo_status_t status; + FT_Error error; + + /* According to the FreeType docs, glyphslot->format could be + * something other than FT_GLYPH_FORMAT_OUTLINE or + * FT_GLYPH_FORMAT_BITMAP. Calling FT_Render_Glyph gives FreeType + * the opportunity to convert such to + * bitmap. FT_GLYPH_FORMAT_COMPOSITE will not be encountered since + * we avoid the FT_LOAD_NO_RECURSE flag. + */ + error = FT_Render_Glyph (glyphslot, FT_RENDER_MODE_NORMAL); + /* XXX ignoring all other errors for now. They are not fatal, typically + * just a glyph-not-found. */ + if (error == FT_Err_Out_Of_Memory) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + status = _get_bitmap_surface (&glyphslot->bitmap, + glyphslot->library, + FALSE, font_options, + surface); + if (unlikely (status)) + return status; + + /* + * Note: the font's coordinate system is upside down from ours, so the + * Y coordinate of the control box needs to be negated. Moreover, device + * offsets are position of glyph origin relative to top left while + * bitmap_left and bitmap_top are offsets of top left relative to origin. + * Another negation. + */ + cairo_surface_set_device_offset (&(*surface)->base, + -glyphslot->bitmap_left, + +glyphslot->bitmap_top); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_transform_glyph_bitmap (cairo_matrix_t * shape, + cairo_image_surface_t ** surface) +{ + cairo_matrix_t original_to_transformed; + cairo_matrix_t transformed_to_original; + cairo_image_surface_t *old_image; + cairo_surface_t *image; + double x[4], y[4]; + double origin_x, origin_y; + int orig_width, orig_height; + int i; + int x_min, y_min, x_max, y_max; + int width, height; + cairo_status_t status; + cairo_surface_pattern_t pattern; + + /* We want to compute a transform that takes the origin + * (device_x_offset, device_y_offset) to 0,0, then applies + * the "shape" portion of the font transform + */ + original_to_transformed = *shape; + + cairo_surface_get_device_offset (&(*surface)->base, &origin_x, &origin_y); + orig_width = (*surface)->width; + orig_height = (*surface)->height; + + cairo_matrix_translate (&original_to_transformed, + -origin_x, -origin_y); + + /* Find the bounding box of the original bitmap under that + * transform + */ + x[0] = 0; y[0] = 0; + x[1] = orig_width; y[1] = 0; + x[2] = orig_width; y[2] = orig_height; + x[3] = 0; y[3] = orig_height; + + for (i = 0; i < 4; i++) + cairo_matrix_transform_point (&original_to_transformed, + &x[i], &y[i]); + + x_min = floor (x[0]); y_min = floor (y[0]); + x_max = ceil (x[0]); y_max = ceil (y[0]); + + for (i = 1; i < 4; i++) { + if (x[i] < x_min) + x_min = floor (x[i]); + else if (x[i] > x_max) + x_max = ceil (x[i]); + if (y[i] < y_min) + y_min = floor (y[i]); + else if (y[i] > y_max) + y_max = ceil (y[i]); + } + + /* Adjust the transform so that the bounding box starts at 0,0 ... + * this gives our final transform from original bitmap to transformed + * bitmap. + */ + original_to_transformed.x0 -= x_min; + original_to_transformed.y0 -= y_min; + + /* Create the transformed bitmap */ + width = x_max - x_min; + height = y_max - y_min; + + transformed_to_original = original_to_transformed; + status = cairo_matrix_invert (&transformed_to_original); + if (unlikely (status)) + return status; + + if ((*surface)->format == CAIRO_FORMAT_ARGB32 && + !pixman_image_get_component_alpha ((*surface)->pixman_image)) + image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); + else + image = cairo_image_surface_create (CAIRO_FORMAT_A8, width, height); + if (unlikely (image->status)) + return image->status; + + /* Draw the original bitmap transformed into the new bitmap + */ + _cairo_pattern_init_for_surface (&pattern, &(*surface)->base); + cairo_pattern_set_matrix (&pattern.base, &transformed_to_original); + + status = _cairo_surface_paint (image, + CAIRO_OPERATOR_SOURCE, + &pattern.base, + NULL); + + _cairo_pattern_fini (&pattern.base); + + if (unlikely (status)) { + cairo_surface_destroy (image); + return status; + } + + /* Now update the cache entry for the new bitmap, recomputing + * the origin based on the final transform. + */ + cairo_matrix_transform_point (&original_to_transformed, + &origin_x, &origin_y); + + old_image = (*surface); + (*surface) = (cairo_image_surface_t *)image; + + /* Note: we converted subpixel-rendered RGBA images to grayscale, + * so, no need to copy component alpha to new image. */ + + cairo_surface_destroy (&old_image->base); + + cairo_surface_set_device_offset (&(*surface)->base, + _cairo_lround (origin_x), + _cairo_lround (origin_y)); + return CAIRO_STATUS_SUCCESS; +} + +static const cairo_unscaled_font_backend_t cairo_ft_unscaled_font_backend = { + _cairo_ft_unscaled_font_destroy, +#if 0 + _cairo_ft_unscaled_font_create_glyph +#endif +}; + +/* #cairo_ft_scaled_font_t */ + +typedef struct _cairo_ft_scaled_font { + cairo_scaled_font_t base; + cairo_ft_unscaled_font_t *unscaled; + cairo_ft_options_t ft_options; +} cairo_ft_scaled_font_t; + +static const cairo_scaled_font_backend_t _cairo_ft_scaled_font_backend; + +#if CAIRO_HAS_FC_FONT +/* The load flags passed to FT_Load_Glyph control aspects like hinting and + * antialiasing. Here we compute them from the fields of a FcPattern. + */ +static void +_get_pattern_ft_options (FcPattern *pattern, cairo_ft_options_t *ret) +{ + FcBool antialias, vertical_layout, hinting, autohint, bitmap, embolden; + cairo_ft_options_t ft_options; + int rgba; + int hintstyle; + char *variations; + + _cairo_font_options_init_default (&ft_options.base); + ft_options.load_flags = FT_LOAD_DEFAULT; + ft_options.synth_flags = 0; + + /* Check whether to force use of embedded bitmaps */ + if (FcPatternGetBool (pattern, + FC_EMBEDDED_BITMAP, 0, &bitmap) != FcResultMatch) + bitmap = FcFalse; + + /* disable antialiasing if requested */ + if (FcPatternGetBool (pattern, + FC_ANTIALIAS, 0, &antialias) != FcResultMatch) + antialias = FcTrue; + + if (antialias) { + cairo_subpixel_order_t subpixel_order; + int lcd_filter; + + /* disable hinting if requested */ + if (FcPatternGetBool (pattern, + FC_HINTING, 0, &hinting) != FcResultMatch) + hinting = FcTrue; + + if (FcPatternGetInteger (pattern, + FC_RGBA, 0, &rgba) != FcResultMatch) + rgba = FC_RGBA_UNKNOWN; + + switch (rgba) { + case FC_RGBA_RGB: + subpixel_order = CAIRO_SUBPIXEL_ORDER_RGB; + break; + case FC_RGBA_BGR: + subpixel_order = CAIRO_SUBPIXEL_ORDER_BGR; + break; + case FC_RGBA_VRGB: + subpixel_order = CAIRO_SUBPIXEL_ORDER_VRGB; + break; + case FC_RGBA_VBGR: + subpixel_order = CAIRO_SUBPIXEL_ORDER_VBGR; + break; + case FC_RGBA_UNKNOWN: + case FC_RGBA_NONE: + default: + subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT; + break; + } + + if (subpixel_order != CAIRO_SUBPIXEL_ORDER_DEFAULT) { + ft_options.base.subpixel_order = subpixel_order; + ft_options.base.antialias = CAIRO_ANTIALIAS_SUBPIXEL; + } + + if (FcPatternGetInteger (pattern, + FC_LCD_FILTER, 0, &lcd_filter) == FcResultMatch) + { + switch (lcd_filter) { + case FC_LCD_NONE: + ft_options.base.lcd_filter = CAIRO_LCD_FILTER_NONE; + break; + case FC_LCD_DEFAULT: + ft_options.base.lcd_filter = CAIRO_LCD_FILTER_FIR5; + break; + case FC_LCD_LIGHT: + ft_options.base.lcd_filter = CAIRO_LCD_FILTER_FIR3; + break; + case FC_LCD_LEGACY: + ft_options.base.lcd_filter = CAIRO_LCD_FILTER_INTRA_PIXEL; + break; + } + } + + if (FcPatternGetInteger (pattern, + FC_HINT_STYLE, 0, &hintstyle) != FcResultMatch) + hintstyle = FC_HINT_FULL; + + if (!hinting) + hintstyle = FC_HINT_NONE; + + switch (hintstyle) { + case FC_HINT_NONE: + ft_options.base.hint_style = CAIRO_HINT_STYLE_NONE; + break; + case FC_HINT_SLIGHT: + ft_options.base.hint_style = CAIRO_HINT_STYLE_SLIGHT; + break; + case FC_HINT_MEDIUM: + default: + ft_options.base.hint_style = CAIRO_HINT_STYLE_MEDIUM; + break; + case FC_HINT_FULL: + ft_options.base.hint_style = CAIRO_HINT_STYLE_FULL; + break; + } + + /* Force embedded bitmaps off if no hinting requested */ + if (ft_options.base.hint_style == CAIRO_HINT_STYLE_NONE) + bitmap = FcFalse; + + if (!bitmap) + ft_options.load_flags |= FT_LOAD_NO_BITMAP; + + } else { + ft_options.base.antialias = CAIRO_ANTIALIAS_NONE; + } + + /* force autohinting if requested */ + if (FcPatternGetBool (pattern, + FC_AUTOHINT, 0, &autohint) != FcResultMatch) + autohint = FcFalse; + + if (autohint) + ft_options.load_flags |= FT_LOAD_FORCE_AUTOHINT; + + if (FcPatternGetBool (pattern, + FC_VERTICAL_LAYOUT, 0, &vertical_layout) != FcResultMatch) + vertical_layout = FcFalse; + + if (vertical_layout) + ft_options.load_flags |= FT_LOAD_VERTICAL_LAYOUT; + + if (FcPatternGetBool (pattern, + FC_EMBOLDEN, 0, &embolden) != FcResultMatch) + embolden = FcFalse; + + if (embolden) + ft_options.synth_flags |= CAIRO_FT_SYNTHESIZE_BOLD; + + if (FcPatternGetString (pattern, FC_FONT_VARIATIONS, 0, (FcChar8 **) &variations) == FcResultMatch) { + ft_options.base.variations = strdup (variations); + } + + *ret = ft_options; +} +#endif + +static void +_cairo_ft_options_merge (cairo_ft_options_t *options, + cairo_ft_options_t *other) +{ + int load_flags = other->load_flags; + int load_target = FT_LOAD_TARGET_NORMAL; + + /* clear load target mode */ + load_flags &= ~(FT_LOAD_TARGET_(FT_LOAD_TARGET_MODE(other->load_flags))); + + if (load_flags & FT_LOAD_NO_HINTING) + other->base.hint_style = CAIRO_HINT_STYLE_NONE; + + if (other->base.antialias == CAIRO_ANTIALIAS_NONE || + options->base.antialias == CAIRO_ANTIALIAS_NONE) { + options->base.antialias = CAIRO_ANTIALIAS_NONE; + options->base.subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT; + } + + if (other->base.antialias == CAIRO_ANTIALIAS_SUBPIXEL && + options->base.antialias == CAIRO_ANTIALIAS_DEFAULT) { + options->base.antialias = CAIRO_ANTIALIAS_SUBPIXEL; + options->base.subpixel_order = other->base.subpixel_order; + } + + if (options->base.hint_style == CAIRO_HINT_STYLE_DEFAULT) + options->base.hint_style = other->base.hint_style; + + if (other->base.hint_style == CAIRO_HINT_STYLE_NONE) + options->base.hint_style = CAIRO_HINT_STYLE_NONE; + + if (options->base.lcd_filter == CAIRO_LCD_FILTER_DEFAULT) + options->base.lcd_filter = other->base.lcd_filter; + + if (other->base.lcd_filter == CAIRO_LCD_FILTER_NONE) + options->base.lcd_filter = CAIRO_LCD_FILTER_NONE; + + if (options->base.antialias == CAIRO_ANTIALIAS_NONE) { + if (options->base.hint_style == CAIRO_HINT_STYLE_NONE) + load_flags |= FT_LOAD_NO_HINTING; + else + load_target = FT_LOAD_TARGET_MONO; + load_flags |= FT_LOAD_MONOCHROME; + } else { + switch (options->base.hint_style) { + case CAIRO_HINT_STYLE_NONE: + load_flags |= FT_LOAD_NO_HINTING; + break; + case CAIRO_HINT_STYLE_SLIGHT: + load_target = FT_LOAD_TARGET_LIGHT; + break; + case CAIRO_HINT_STYLE_MEDIUM: + break; + case CAIRO_HINT_STYLE_FULL: + case CAIRO_HINT_STYLE_DEFAULT: + if (options->base.antialias == CAIRO_ANTIALIAS_SUBPIXEL) { + switch (options->base.subpixel_order) { + case CAIRO_SUBPIXEL_ORDER_DEFAULT: + case CAIRO_SUBPIXEL_ORDER_RGB: + case CAIRO_SUBPIXEL_ORDER_BGR: + load_target = FT_LOAD_TARGET_LCD; + break; + case CAIRO_SUBPIXEL_ORDER_VRGB: + case CAIRO_SUBPIXEL_ORDER_VBGR: + load_target = FT_LOAD_TARGET_LCD_V; + break; + } + } + break; + } + } + + if (other->base.variations) { + if (options->base.variations) { + char *p; + + /* 'merge' variations by concatenating - later entries win */ + p = malloc (strlen (other->base.variations) + strlen (options->base.variations) + 2); + p[0] = 0; + strcat (p, other->base.variations); + strcat (p, ","); + strcat (p, options->base.variations); + free (options->base.variations); + options->base.variations = p; + } + else { + options->base.variations = strdup (other->base.variations); + } + } + + options->load_flags = load_flags | load_target; + options->synth_flags = other->synth_flags; +} + +static cairo_status_t +_cairo_ft_font_face_scaled_font_create (void *abstract_font_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **font_out) +{ + cairo_ft_font_face_t *font_face = abstract_font_face; + cairo_ft_scaled_font_t *scaled_font; + FT_Face face; + FT_Size_Metrics *metrics; + cairo_font_extents_t fs_metrics; + cairo_status_t status; + cairo_ft_unscaled_font_t *unscaled; + + assert (font_face->unscaled); + + face = _cairo_ft_unscaled_font_lock_face (font_face->unscaled); + if (unlikely (face == NULL)) /* backend error */ + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + scaled_font = _cairo_calloc (sizeof (cairo_ft_scaled_font_t)); + if (unlikely (scaled_font == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto FAIL; + } + + scaled_font->unscaled = unscaled = font_face->unscaled; + _cairo_unscaled_font_reference (&unscaled->base); + + _cairo_font_options_init_copy (&scaled_font->ft_options.base, options); + _cairo_ft_options_merge (&scaled_font->ft_options, &font_face->ft_options); + + status = _cairo_scaled_font_init (&scaled_font->base, + &font_face->base, + font_matrix, ctm, options, + &_cairo_ft_scaled_font_backend); + if (unlikely (status)) + goto CLEANUP_SCALED_FONT; + + status = _cairo_ft_unscaled_font_set_scale (unscaled, + &scaled_font->base.scale); + if (unlikely (status)) { + /* This can only fail if we encounter an error with the underlying + * font, so propagate the error back to the font-face. */ + _cairo_ft_unscaled_font_unlock_face (unscaled); + _cairo_unscaled_font_destroy (&unscaled->base); + free (scaled_font); + return status; + } + + + metrics = &face->size->metrics; + + /* + * Get to unscaled metrics so that the upper level can get back to + * user space + * + * Also use this path for bitmap-only fonts. The other branch uses + * face members that are only relevant for scalable fonts. This is + * detected by simply checking for units_per_EM==0. + */ + if (scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF || + face->units_per_EM == 0) { + fs_metrics.ascent = SCALE (DOUBLE_FROM_26_6 (metrics->ascender), unscaled->y_scale); + fs_metrics.descent = SCALE (DOUBLE_FROM_26_6 (- metrics->descender), unscaled->y_scale); + fs_metrics.height = SCALE (DOUBLE_FROM_26_6 (metrics->height), unscaled->y_scale); + if (!_cairo_ft_scaled_font_is_vertical (&scaled_font->base)) { + fs_metrics.max_x_advance = SCALE (DOUBLE_FROM_26_6 (metrics->max_advance), unscaled->x_scale); + fs_metrics.max_y_advance = 0; + } else { + fs_metrics.max_x_advance = 0; + fs_metrics.max_y_advance = SCALE (DOUBLE_FROM_26_6 (metrics->max_advance), unscaled->y_scale); + } + } else { + double scale = face->units_per_EM; + + fs_metrics.ascent = face->ascender / scale; + fs_metrics.descent = - face->descender / scale; + fs_metrics.height = face->height / scale; + if (!_cairo_ft_scaled_font_is_vertical (&scaled_font->base)) { + fs_metrics.max_x_advance = face->max_advance_width / scale; + fs_metrics.max_y_advance = 0; + } else { + fs_metrics.max_x_advance = 0; + fs_metrics.max_y_advance = face->max_advance_height / scale; + } + } + + status = _cairo_scaled_font_set_metrics (&scaled_font->base, &fs_metrics); + if (unlikely (status)) + goto CLEANUP_SCALED_FONT; + + _cairo_ft_unscaled_font_unlock_face (unscaled); + + *font_out = &scaled_font->base; + return CAIRO_STATUS_SUCCESS; + + CLEANUP_SCALED_FONT: + _cairo_unscaled_font_destroy (&unscaled->base); + free (scaled_font); + FAIL: + _cairo_ft_unscaled_font_unlock_face (font_face->unscaled); + *font_out = _cairo_scaled_font_create_in_error (status); + return CAIRO_STATUS_SUCCESS; /* non-backend error */ +} + +cairo_bool_t +_cairo_scaled_font_is_ft (cairo_scaled_font_t *scaled_font) +{ + return scaled_font->backend == &_cairo_ft_scaled_font_backend; +} + +static void +_cairo_ft_scaled_font_fini (void *abstract_font) +{ + cairo_ft_scaled_font_t *scaled_font = abstract_font; + + if (scaled_font == NULL) + return; + + _cairo_font_options_fini (&scaled_font->ft_options.base); + _cairo_unscaled_font_destroy (&scaled_font->unscaled->base); +} + +static int +_move_to (FT_Vector *to, void *closure) +{ + cairo_path_fixed_t *path = closure; + cairo_fixed_t x, y; + + x = _cairo_fixed_from_26_6 (to->x); + y = _cairo_fixed_from_26_6 (to->y); + + if (_cairo_path_fixed_close_path (path) != CAIRO_STATUS_SUCCESS) + return 1; + if (_cairo_path_fixed_move_to (path, x, y) != CAIRO_STATUS_SUCCESS) + return 1; + + return 0; +} + +static int +_line_to (FT_Vector *to, void *closure) +{ + cairo_path_fixed_t *path = closure; + cairo_fixed_t x, y; + + x = _cairo_fixed_from_26_6 (to->x); + y = _cairo_fixed_from_26_6 (to->y); + + if (_cairo_path_fixed_line_to (path, x, y) != CAIRO_STATUS_SUCCESS) + return 1; + + return 0; +} + +static int +_conic_to (FT_Vector *control, FT_Vector *to, void *closure) +{ + cairo_path_fixed_t *path = closure; + + cairo_fixed_t x0, y0; + cairo_fixed_t x1, y1; + cairo_fixed_t x2, y2; + cairo_fixed_t x3, y3; + cairo_point_t conic; + + if (! _cairo_path_fixed_get_current_point (path, &x0, &y0)) + return 1; + + conic.x = _cairo_fixed_from_26_6 (control->x); + conic.y = _cairo_fixed_from_26_6 (control->y); + + x3 = _cairo_fixed_from_26_6 (to->x); + y3 = _cairo_fixed_from_26_6 (to->y); + + x1 = x0 + 2.0/3.0 * (conic.x - x0); + y1 = y0 + 2.0/3.0 * (conic.y - y0); + + x2 = x3 + 2.0/3.0 * (conic.x - x3); + y2 = y3 + 2.0/3.0 * (conic.y - y3); + + if (_cairo_path_fixed_curve_to (path, + x1, y1, + x2, y2, + x3, y3) != CAIRO_STATUS_SUCCESS) + return 1; + + return 0; +} + +static int +_cubic_to (FT_Vector *control1, FT_Vector *control2, + FT_Vector *to, void *closure) +{ + cairo_path_fixed_t *path = closure; + cairo_fixed_t x0, y0; + cairo_fixed_t x1, y1; + cairo_fixed_t x2, y2; + + x0 = _cairo_fixed_from_26_6 (control1->x); + y0 = _cairo_fixed_from_26_6 (control1->y); + + x1 = _cairo_fixed_from_26_6 (control2->x); + y1 = _cairo_fixed_from_26_6 (control2->y); + + x2 = _cairo_fixed_from_26_6 (to->x); + y2 = _cairo_fixed_from_26_6 (to->y); + + if (_cairo_path_fixed_curve_to (path, + x0, y0, + x1, y1, + x2, y2) != CAIRO_STATUS_SUCCESS) + return 1; + + return 0; +} + +cairo_status_t +_cairo_ft_face_decompose_glyph_outline (FT_Face face, + cairo_path_fixed_t **pathp) +{ + static const FT_Outline_Funcs outline_funcs = { + (FT_Outline_MoveToFunc)_move_to, + (FT_Outline_LineToFunc)_line_to, + (FT_Outline_ConicToFunc)_conic_to, + (FT_Outline_CubicToFunc)_cubic_to, + 0, /* shift */ + 0, /* delta */ + }; + static const FT_Matrix invert_y = { + DOUBLE_TO_16_16 (1.0), 0, + 0, DOUBLE_TO_16_16 (-1.0), + }; + + FT_GlyphSlot glyph; + cairo_path_fixed_t *path; + cairo_status_t status; + + path = _cairo_path_fixed_create (); + if (!path) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + glyph = face->glyph; + + /* Font glyphs have an inverted Y axis compared to cairo. */ + FT_Outline_Transform (&glyph->outline, &invert_y); + if (FT_Outline_Decompose (&glyph->outline, &outline_funcs, path)) { + _cairo_path_fixed_destroy (path); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + status = _cairo_path_fixed_close_path (path); + if (unlikely (status)) { + _cairo_path_fixed_destroy (path); + return status; + } + + *pathp = path; + + return CAIRO_STATUS_SUCCESS; +} + +/* + * Translate glyph to match its metrics. + */ +static void +_cairo_ft_scaled_glyph_vertical_layout_bearing_fix (void *abstract_font, + FT_GlyphSlot glyph) +{ + cairo_ft_scaled_font_t *scaled_font = abstract_font; + FT_Vector vector; + + vector.x = glyph->metrics.vertBearingX - glyph->metrics.horiBearingX; + vector.y = -glyph->metrics.vertBearingY - glyph->metrics.horiBearingY; + + if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) { + FT_Vector_Transform (&vector, &scaled_font->unscaled->Current_Shape); + FT_Outline_Translate(&glyph->outline, vector.x, vector.y); + } else if (glyph->format == FT_GLYPH_FORMAT_BITMAP) { + glyph->bitmap_left += vector.x / 64; + glyph->bitmap_top += vector.y / 64; + } +} + +static void +cairo_ft_apply_variations (FT_Face face, + cairo_ft_scaled_font_t *scaled_font) +{ + FT_MM_Var *ft_mm_var; + FT_Error ret; + unsigned int instance_id = scaled_font->unscaled->id >> 16; + + ret = FT_Get_MM_Var (face, &ft_mm_var); + if (ret == 0) { + FT_Fixed *current_coords; + FT_Fixed *coords; + unsigned int i; + const char *p; + + coords = malloc (sizeof (FT_Fixed) * ft_mm_var->num_axis); + /* FIXME check coords. */ + + if (scaled_font->unscaled->variations) + { + memcpy (coords, scaled_font->unscaled->variations, ft_mm_var->num_axis * sizeof (*coords)); + } + else if (instance_id && instance_id <= ft_mm_var->num_namedstyles) + { + FT_Var_Named_Style *instance = &ft_mm_var->namedstyle[instance_id - 1]; + memcpy (coords, instance->coords, ft_mm_var->num_axis * sizeof (*coords)); + } + else + for (i = 0; i < ft_mm_var->num_axis; i++) + coords[i] = ft_mm_var->axis[i].def; + + p = scaled_font->ft_options.base.variations; + while (p && *p) { + const char *start; + const char *end, *end2; + FT_ULong tag; + double value; + + while (_cairo_isspace (*p)) p++; + + start = p; + end = strchr (p, ','); + if (end && (end - p < 6)) + goto skip; + + tag = FT_MAKE_TAG(p[0], p[1], p[2], p[3]); + + p += 4; + while (_cairo_isspace (*p)) p++; + if (*p == '=') p++; + + if (p - start < 5) + goto skip; + + value = _cairo_strtod (p, (char **) &end2); + + while (end2 && _cairo_isspace (*end2)) end2++; + + if (end2 && (*end2 != ',' && *end2 != '\0')) + goto skip; + + for (i = 0; i < ft_mm_var->num_axis; i++) { + if (ft_mm_var->axis[i].tag == tag) { + coords[i] = (FT_Fixed)(value*65536); + break; + } + } + +skip: + p = end ? end + 1 : NULL; + } + + current_coords = malloc (sizeof (FT_Fixed) * ft_mm_var->num_axis); + ret = FT_Get_Var_Design_Coordinates (face, ft_mm_var->num_axis, current_coords); + if (ret == 0) { + for (i = 0; i < ft_mm_var->num_axis; i++) { + if (coords[i] != current_coords[i]) + break; + } + if (i == ft_mm_var->num_axis) + goto done; + } + + FT_Set_Var_Design_Coordinates (face, ft_mm_var->num_axis, coords); +done: + free (coords); + free (current_coords); + FT_Done_MM_Var (face->glyph->library, ft_mm_var); + } +} + +typedef enum { + CAIRO_FT_GLYPH_TYPE_BITMAP, + CAIRO_FT_GLYPH_TYPE_OUTLINE, + CAIRO_FT_GLYPH_TYPE_SVG, + CAIRO_FT_GLYPH_TYPE_COLR_V0, + CAIRO_FT_GLYPH_TYPE_COLR_V1, +} cairo_ft_glyph_format_t; + +typedef struct { + cairo_scaled_glyph_private_t base; + + cairo_ft_glyph_format_t format; +} cairo_ft_glyph_private_t; + +static const int ft_glyph_private_key; + +static cairo_int_status_t +_cairo_ft_scaled_glyph_load_glyph (cairo_ft_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph, + FT_Face face, + int load_flags, + cairo_bool_t use_em_size, + cairo_bool_t vertical_layout) +{ + FT_Error error; + cairo_status_t status; + cairo_ft_glyph_private_t *glyph_priv; + + glyph_priv = (cairo_ft_glyph_private_t *) _cairo_scaled_glyph_find_private (scaled_glyph, + &ft_glyph_private_key); + assert (glyph_priv != NULL); + + if (use_em_size) { + cairo_matrix_t em_size; + cairo_matrix_init_scale (&em_size, face->units_per_EM, face->units_per_EM); + status = _cairo_ft_unscaled_font_set_scale (scaled_font->unscaled, &em_size); + } else { + status = _cairo_ft_unscaled_font_set_scale (scaled_font->unscaled, + &scaled_font->base.scale); + } + if (unlikely (status)) + return status; + + cairo_ft_apply_variations (face, scaled_font); + +#if defined(HAVE_FT_LOAD_NO_SVG) + if (load_flags & FT_LOAD_COLOR && glyph_priv->format == CAIRO_FT_GLYPH_TYPE_COLR_V1) + load_flags |= FT_LOAD_NO_SVG; +#endif + + error = FT_Load_Glyph (face, + _cairo_scaled_glyph_index(scaled_glyph), + load_flags); + /* XXX ignoring all other errors for now. They are not fatal, typically + * just a glyph-not-found. */ + if (error == FT_Err_Out_Of_Memory) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + /* + * synthesize glyphs if requested + */ + if (scaled_font->ft_options.synth_flags & CAIRO_FT_SYNTHESIZE_BOLD) + FT_GlyphSlot_Embolden (face->glyph); + + if (scaled_font->ft_options.synth_flags & CAIRO_FT_SYNTHESIZE_OBLIQUE) + FT_GlyphSlot_Oblique (face->glyph); + + if (vertical_layout) + _cairo_ft_scaled_glyph_vertical_layout_bearing_fix (scaled_font, face->glyph); + + if (face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) { + FT_Pos xshift, yshift; + + xshift = _cairo_scaled_glyph_xphase (scaled_glyph) << 4; + yshift = _cairo_scaled_glyph_yphase (scaled_glyph) << 4; + + FT_Outline_Translate (&face->glyph->outline, xshift, -yshift); + } + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_ft_glyph_fini (cairo_scaled_glyph_private_t *glyph_private, + cairo_scaled_glyph_t *glyph, + cairo_scaled_font_t *font) +{ + cairo_list_del (&glyph_private->link); + free (glyph_private); +} + + +static void +_cairo_ft_scaled_glyph_set_palette (cairo_ft_scaled_font_t *scaled_font, + FT_Face face, + unsigned int *num_entries_ret, + FT_Color **entries_ret) +{ + unsigned int num_entries = 0; + FT_Color *entries = NULL; + + FT_Palette_Data palette_data; + + if (FT_Palette_Data_Get (face, &palette_data) == 0 && palette_data.num_palettes > 0) { + FT_UShort palette_index = CAIRO_COLOR_PALETTE_DEFAULT; + if (scaled_font->base.options.palette_index < palette_data.num_palettes) + palette_index = scaled_font->base.options.palette_index; + + if (FT_Palette_Select (face, palette_index, &entries) == 0) { + num_entries = palette_data.num_palette_entries; + + /* Overlay custom colors */ + for (unsigned int i = 0; i < scaled_font->base.options.custom_palette_size; i++) { + cairo_palette_color_t *entry = &scaled_font->base.options.custom_palette[i]; + if (entry->index < num_entries) { + entries[entry->index].red = 255 * entry->red; + entries[entry->index].green = 255 * entry->green; + entries[entry->index].blue = 255 * entry->blue; + entries[entry->index].alpha = 255 * entry->alpha; + } + } + } + } + + if (num_entries_ret) + *num_entries_ret = num_entries; + + if (entries_ret) + *entries_ret = entries; +} + +/* returns TRUE if foreground color used */ +static cairo_bool_t +_cairo_ft_scaled_glyph_set_foreground_color (cairo_ft_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph, + FT_Face face, + const cairo_color_t *foreground_color) +{ + cairo_bool_t uses_foreground_color = FALSE; + FT_LayerIterator iterator; + FT_UInt layer_glyph_index; + FT_UInt layer_color_index; + FT_Color color; + + /* Check if there is a layer that uses the foreground color */ + iterator.p = NULL; + while (FT_Get_Color_Glyph_Layer(face, + _cairo_scaled_glyph_index (scaled_glyph), + &layer_glyph_index, + &layer_color_index, + &iterator)) { + if (layer_color_index == 0xFFFF) { + uses_foreground_color = TRUE; + break; + } + } + + if (uses_foreground_color) { + color.red = (FT_Byte)(foreground_color->red * 0xFF); + color.green = (FT_Byte)(foreground_color->green * 0xFF); + color.blue = (FT_Byte)(foreground_color->blue * 0xFF); + color.alpha = (FT_Byte)(foreground_color->alpha * 0xFF); + FT_Palette_Set_Foreground_Color (face, color); + } + + return uses_foreground_color; +} + +static cairo_int_status_t +_cairo_ft_scaled_glyph_init_surface (cairo_ft_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph, + cairo_ft_glyph_private_t *glyph_priv, + cairo_scaled_glyph_info_t info, + FT_Face face, + const cairo_color_t *foreground_color, + cairo_bool_t vertical_layout, + int load_flags) +{ + cairo_ft_unscaled_font_t *unscaled = scaled_font->unscaled; + FT_GlyphSlot glyph; + cairo_status_t status; + cairo_image_surface_t *surface; + cairo_bool_t uses_foreground_color = FALSE; + + /* Only one info type at a time handled in this function */ + assert (info == CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE || info == CAIRO_SCALED_GLYPH_INFO_SURFACE); + + if (info == CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) { + if (!unscaled->have_color) { + scaled_glyph->color_glyph = FALSE; + scaled_glyph->color_glyph_set = TRUE; + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + uses_foreground_color = _cairo_ft_scaled_glyph_set_foreground_color (scaled_font, + scaled_glyph, + face, + foreground_color); + _cairo_ft_scaled_glyph_set_palette (scaled_font, face, NULL, NULL); + + load_flags &= ~FT_LOAD_MONOCHROME; + /* clear load target mode */ + load_flags &= ~(FT_LOAD_TARGET_(FT_LOAD_TARGET_MODE(load_flags))); + load_flags |= FT_LOAD_TARGET_NORMAL; + load_flags |= FT_LOAD_COLOR; + } else { /* info == CAIRO_SCALED_GLYPH_INFO_SURFACE */ + load_flags &= ~FT_LOAD_COLOR; + } + + status = _cairo_ft_scaled_glyph_load_glyph (scaled_font, + scaled_glyph, + face, + load_flags, + FALSE, + vertical_layout); + if (unlikely (status)) + return status; + + glyph = face->glyph; + + if (glyph_priv->format == CAIRO_FT_GLYPH_TYPE_OUTLINE) { + + status = _render_glyph_outline (face, &scaled_font->ft_options.base, + &surface); + } else { + status = _render_glyph_bitmap (face, &scaled_font->ft_options.base, + &surface); + if (likely (status == CAIRO_STATUS_SUCCESS) && unscaled->have_shape) { + status = _transform_glyph_bitmap (&unscaled->current_shape, + &surface); + if (unlikely (status)) + cairo_surface_destroy (&surface->base); + } + } + + if (unlikely (status)) + return status; + + if (info == CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) { + /* We tried loading a color glyph and can now check if we got + * a color glyph and set scaled_glyph->color_glyph + * accordingly */ + if (pixman_image_get_format (surface->pixman_image) == PIXMAN_a8r8g8b8 && + !pixman_image_get_component_alpha (surface->pixman_image)) + { + _cairo_scaled_glyph_set_color_surface (scaled_glyph, + &scaled_font->base, + surface, + uses_foreground_color ? foreground_color : NULL); + + scaled_glyph->color_glyph = TRUE; + } else { + /* We didn't ask for a non-color surface, but store it + * anyway so we don't have to load it again. */ + _cairo_scaled_glyph_set_surface (scaled_glyph, + &scaled_font->base, + surface); + scaled_glyph->color_glyph = FALSE; + status = CAIRO_INT_STATUS_UNSUPPORTED; + } + scaled_glyph->color_glyph_set = TRUE; + } else { /* info == CAIRO_SCALED_GLYPH_INFO_SURFACE */ + _cairo_scaled_glyph_set_surface (scaled_glyph, + &scaled_font->base, + surface); + } + + return status; +} + +static cairo_int_status_t +_cairo_ft_scaled_glyph_init_record_colr_v0_glyph (cairo_ft_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph, + FT_Face face, + cairo_bool_t vertical_layout, + int load_flags) +{ + cairo_surface_t *recording_surface; + cairo_t *cr; + cairo_status_t status; + FT_Color *palette; + unsigned int num_palette_entries; + FT_LayerIterator iterator; + FT_UInt layer_glyph_index; + FT_UInt layer_color_index; + cairo_path_fixed_t *path_fixed; + cairo_path_t *path; + + _cairo_ft_scaled_glyph_set_palette (scaled_font, face, &num_palette_entries, &palette); + + load_flags &= ~FT_LOAD_MONOCHROME; + /* clear load target mode */ + load_flags &= ~(FT_LOAD_TARGET_(FT_LOAD_TARGET_MODE(load_flags))); + load_flags |= FT_LOAD_TARGET_NORMAL; + load_flags |= FT_LOAD_COLOR; + + recording_surface = + cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL); + + cr = cairo_create (recording_surface); + + if (!_cairo_matrix_is_scale_0 (&scaled_font->base.scale)) { + cairo_matrix_t scale; + scale = scaled_font->base.scale; + scale.x0 = scale.y0 = 0.; + cairo_set_matrix (cr, &scale); + } + + iterator.p = NULL; + while (FT_Get_Color_Glyph_Layer(face, + _cairo_scaled_glyph_index (scaled_glyph), + &layer_glyph_index, + &layer_color_index, + &iterator)) + { + cairo_pattern_t *pattern; + if (layer_color_index == 0xFFFF) { + pattern = _cairo_pattern_create_foreground_marker (); + } else { + double r = 0, g = 0, b = 0, a = 1; + if (layer_color_index < num_palette_entries) { + FT_Color *color = &palette[layer_color_index]; + r = color->red / 255.0; + g = color->green/ 255.0; + b = color->blue / 255.0; + a = color->alpha / 255.0; + } + pattern = cairo_pattern_create_rgba (r, g, b, a); + } + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + + if (FT_Load_Glyph (face, layer_glyph_index, load_flags) != 0) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto cleanup; + } + + status = _cairo_ft_face_decompose_glyph_outline (face, &path_fixed); + if (unlikely (status)) + return status; + + path = _cairo_path_create (path_fixed, cr); + _cairo_path_fixed_destroy (path_fixed); + cairo_append_path(cr, path); + cairo_path_destroy (path); + cairo_fill (cr); + } + + cleanup: + cairo_destroy (cr); + + if (status) { + cairo_surface_destroy (recording_surface); + return status; + } + + _cairo_scaled_glyph_set_recording_surface (scaled_glyph, + &scaled_font->base, + recording_surface, + NULL); + return status; +} + +static cairo_int_status_t +_cairo_ft_scaled_glyph_init_record_colr_v1_glyph (cairo_ft_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph, + FT_Face face, + const cairo_color_t *foreground_color, + cairo_text_extents_t *extents) +{ +#if HAVE_FT_COLR_V1 + cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_surface_t *recording_surface; + cairo_t *cr; + FT_Color *palette; + unsigned int num_palette_entries; + cairo_bool_t foreground_source_used = FALSE; + + recording_surface = + cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL); + + cairo_surface_set_device_scale (recording_surface, 1, -1); + + cr = cairo_create (recording_surface); + + cairo_set_font_size (cr, 1.0); + cairo_set_font_options (cr, &scaled_font->base.options); + + extents->x_bearing = DOUBLE_FROM_26_6(face->bbox.xMin); + extents->y_bearing = DOUBLE_FROM_26_6(face->bbox.yMin); + extents->width = DOUBLE_FROM_26_6(face->bbox.xMax) - extents->x_bearing; + extents->height = DOUBLE_FROM_26_6(face->bbox.yMax) - extents->y_bearing; + + _cairo_ft_scaled_glyph_set_palette (scaled_font, face, &num_palette_entries, &palette); + + if (!_cairo_matrix_is_scale_0 (&scaled_font->base.scale)) { + cairo_pattern_t *foreground_pattern = _cairo_pattern_create_solid (foreground_color); + status = _cairo_render_colr_v1_glyph (face, + _cairo_scaled_glyph_index (scaled_glyph), + palette, + num_palette_entries, + cr, + foreground_pattern, + &foreground_source_used); + cairo_pattern_destroy (foreground_pattern); + if (status == CAIRO_STATUS_SUCCESS) + status = cairo_status (cr); + } + + cairo_destroy (cr); + + if (status) { + cairo_surface_destroy (recording_surface); + scaled_glyph->color_glyph = FALSE; + scaled_glyph->color_glyph_set = TRUE; + return status; + } + + _cairo_scaled_glyph_set_recording_surface (scaled_glyph, + &scaled_font->base, + recording_surface, + foreground_source_used ? foreground_color : NULL); + + scaled_glyph->color_glyph = TRUE; + scaled_glyph->color_glyph_set = TRUE; + + /* get metrics */ + + /* Copied from cairo-user-font.c */ + cairo_matrix_t extent_scale; + double extent_x_scale = 1.0; + double extent_y_scale = 1.0; + double snap_x_scale; + double snap_y_scale; + double fixed_scale, x_scale, y_scale; + + extent_scale = scaled_font->base.scale_inverse; + snap_x_scale = 1.0; + snap_y_scale = 1.0; + status = _cairo_matrix_compute_basis_scale_factors (&extent_scale, + &x_scale, &y_scale, + 1); + if (status == CAIRO_STATUS_SUCCESS) { + if (x_scale == 0) + x_scale = 1; + if (y_scale == 0) + y_scale = 1; + + snap_x_scale = x_scale; + snap_y_scale = y_scale; + + /* since glyphs are pretty much 1.0x1.0, we can reduce error by + * scaling to a larger square. say, 1024.x1024. */ + fixed_scale = 1024; + x_scale /= fixed_scale; + y_scale /= fixed_scale; + + cairo_matrix_scale (&extent_scale, 1.0 / x_scale, 1.0 / y_scale); + + extent_x_scale = x_scale; + extent_y_scale = y_scale; + } + + { + /* compute width / height */ + cairo_box_t bbox; + double x1, y1, x2, y2; + double x_scale, y_scale; + + /* Compute extents.x/y/width/height from recording_surface, + * in font space. + */ + status = _cairo_recording_surface_get_bbox ((cairo_recording_surface_t *) recording_surface, + &bbox, + &extent_scale); + if (unlikely (status)) + return status; + + _cairo_box_to_doubles (&bbox, &x1, &y1, &x2, &y2); + + x_scale = extent_x_scale; + y_scale = extent_y_scale; + extents->x_bearing = x1 * x_scale; + extents->y_bearing = y1 * y_scale; + extents->width = (x2 - x1) * x_scale; + extents->height = (y2 - y1) * y_scale; + } + + if (scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF) { + extents->x_advance = _cairo_lround (extents->x_advance / snap_x_scale) * snap_x_scale; + extents->y_advance = _cairo_lround (extents->y_advance / snap_y_scale) * snap_y_scale; + } + + return status; +#else + return CAIRO_INT_STATUS_UNSUPPORTED; +#endif +} + +static cairo_int_status_t +_cairo_ft_scaled_glyph_init_record_svg_glyph (cairo_ft_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph, + FT_Face face, + const cairo_color_t *foreground_color, + cairo_text_extents_t *extents) +{ +#if HAVE_FT_SVG_DOCUMENT + cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_surface_t *recording_surface; + cairo_t *cr; + FT_SVG_Document svg_doc = face->glyph->other; + char *svg_document; + FT_Color *palette; + unsigned int num_palette_entries; + cairo_bool_t foreground_source_used = FALSE; + + /* Create NULL terminated SVG document */ + svg_document = _cairo_strndup ((const char*)svg_doc->svg_document, svg_doc->svg_document_length); + + recording_surface = + cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL); + + cr = cairo_create (recording_surface); + + if (!_cairo_matrix_is_scale_0 (&scaled_font->base.scale)) { + cairo_matrix_t scale; + scale = scaled_font->base.scale; + scale.x0 = scale.y0 = 0.; + cairo_set_matrix (cr, &scale); + } + + cairo_set_font_size (cr, 1.0); + cairo_set_font_options (cr, &scaled_font->base.options); + + extents->x_bearing = DOUBLE_FROM_26_6(face->bbox.xMin); + extents->y_bearing = DOUBLE_FROM_26_6(face->bbox.yMin); + extents->width = DOUBLE_FROM_26_6(face->bbox.xMax) - extents->x_bearing; + extents->height = DOUBLE_FROM_26_6(face->bbox.yMax) - extents->y_bearing; + + _cairo_ft_scaled_glyph_set_palette (scaled_font, face, &num_palette_entries, &palette); + + if (!_cairo_matrix_is_scale_0 (&scaled_font->base.scale)) { + cairo_pattern_t *foreground_pattern = _cairo_pattern_create_solid (foreground_color); + status = _cairo_render_svg_glyph (svg_document, + svg_doc->start_glyph_id, + svg_doc->end_glyph_id, + _cairo_scaled_glyph_index(scaled_glyph), + svg_doc->units_per_EM, + palette, + num_palette_entries, + cr, + foreground_pattern, + &foreground_source_used); + cairo_pattern_destroy (foreground_pattern); + if (status == CAIRO_STATUS_SUCCESS) + status = cairo_status (cr); + } + + cairo_destroy (cr); + free (svg_document); + + if (status) { + cairo_surface_destroy (recording_surface); + scaled_glyph->color_glyph = FALSE; + scaled_glyph->color_glyph_set = TRUE; + return status; + } + + _cairo_scaled_glyph_set_recording_surface (scaled_glyph, + &scaled_font->base, + recording_surface, + foreground_source_used ? foreground_color : NULL); + + scaled_glyph->color_glyph = TRUE; + scaled_glyph->color_glyph_set = TRUE; + + /* get metrics */ + + /* Copied from cairo-user-font.c */ + cairo_matrix_t extent_scale; + double extent_x_scale; + double extent_y_scale; + double snap_x_scale; + double snap_y_scale; + double fixed_scale, x_scale, y_scale; + + extent_scale = scaled_font->base.scale_inverse; + snap_x_scale = 1.0; + snap_y_scale = 1.0; + status = _cairo_matrix_compute_basis_scale_factors (&extent_scale, + &x_scale, &y_scale, + 1); + if (status == CAIRO_STATUS_SUCCESS) { + if (x_scale == 0) + x_scale = 1; + if (y_scale == 0) + y_scale = 1; + + snap_x_scale = x_scale; + snap_y_scale = y_scale; + + /* since glyphs are pretty much 1.0x1.0, we can reduce error by + * scaling to a larger square. say, 1024.x1024. */ + fixed_scale = 1024; + x_scale /= fixed_scale; + y_scale /= fixed_scale; + + cairo_matrix_scale (&extent_scale, 1.0 / x_scale, 1.0 / y_scale); + + extent_x_scale = x_scale; + extent_y_scale = y_scale; + } + + { + /* compute width / height */ + cairo_box_t bbox; + double x1, y1, x2, y2; + double x_scale, y_scale; + + /* Compute extents.x/y/width/height from recording_surface, + * in font space. + */ + status = _cairo_recording_surface_get_bbox ((cairo_recording_surface_t *) recording_surface, + &bbox, + &extent_scale); + if (unlikely (status)) + return status; + + _cairo_box_to_doubles (&bbox, &x1, &y1, &x2, &y2); + + x_scale = extent_x_scale; + y_scale = extent_y_scale; + extents->x_bearing = x1 * x_scale; + extents->y_bearing = y1 * y_scale; + extents->width = (x2 - x1) * x_scale; + extents->height = (y2 - y1) * y_scale; + } + + if (scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF) { + extents->x_advance = _cairo_lround (extents->x_advance / snap_x_scale) * snap_x_scale; + extents->y_advance = _cairo_lround (extents->y_advance / snap_y_scale) * snap_y_scale; + } + + return status; +#else + return CAIRO_INT_STATUS_UNSUPPORTED; +#endif +} + +static cairo_int_status_t +_cairo_ft_scaled_glyph_init_surface_for_recording_surface (cairo_ft_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph, + const cairo_color_t *foreground_color) +{ + cairo_surface_t *surface; + int width, height; + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + cairo_bool_t foreground_used; + + width = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x) - + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x); + height = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y) - + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y); + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); + + cairo_surface_set_device_offset (surface, + - _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x), + - _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y)); + + status = _cairo_recording_surface_replay_with_foreground_color (scaled_glyph->recording_surface, + surface, + foreground_color, + &foreground_used); + if (unlikely (status)) { + cairo_surface_destroy(surface); + return status; + } + + _cairo_scaled_glyph_set_color_surface (scaled_glyph, + &scaled_font->base, + (cairo_image_surface_t *)surface, + foreground_used ? foreground_color : NULL); + surface = NULL; + + if (surface) + cairo_surface_destroy (surface); + + return status; +} + +static void +_cairo_ft_scaled_glyph_get_metrics (cairo_ft_scaled_font_t *scaled_font, + FT_Face face, + cairo_bool_t vertical_layout, + int load_flags, + cairo_text_extents_t *fs_metrics) +{ + FT_Glyph_Metrics *metrics; + cairo_ft_unscaled_font_t *unscaled = scaled_font->unscaled; + cairo_bool_t hint_metrics = scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF; + FT_GlyphSlot glyph = face->glyph; + + /* + * Compute font-space metrics + */ + metrics = &glyph->metrics; + + /* + * Note: Y coordinates of the horizontal bearing need to be negated. + * + * Scale metrics back to glyph space from the scaled glyph space returned + * by FreeType + * + * If we want hinted metrics but aren't asking for hinted glyphs from + * FreeType, then we need to do the metric hinting ourselves. + */ + + if (hint_metrics && (load_flags & FT_LOAD_NO_HINTING)) + { + FT_Pos x1, x2; + FT_Pos y1, y2; + FT_Pos advance; + + if (!vertical_layout) { + x1 = (metrics->horiBearingX) & -64; + x2 = (metrics->horiBearingX + metrics->width + 63) & -64; + y1 = (-metrics->horiBearingY) & -64; + y2 = (-metrics->horiBearingY + metrics->height + 63) & -64; + + advance = ((metrics->horiAdvance + 32) & -64); + + fs_metrics->x_bearing = SCALE (DOUBLE_FROM_26_6 (x1), unscaled->x_scale); + fs_metrics->y_bearing = SCALE (DOUBLE_FROM_26_6 (y1), unscaled->y_scale); + + fs_metrics->width = SCALE (DOUBLE_FROM_26_6 (x2 - x1), unscaled->x_scale); + fs_metrics->height = SCALE (DOUBLE_FROM_26_6 (y2 - y1), unscaled->y_scale); + + fs_metrics->x_advance = SCALE (DOUBLE_FROM_26_6 (advance), unscaled->x_scale); + fs_metrics->y_advance = 0; + } else { + x1 = (metrics->vertBearingX) & -64; + x2 = (metrics->vertBearingX + metrics->width + 63) & -64; + y1 = (metrics->vertBearingY) & -64; + y2 = (metrics->vertBearingY + metrics->height + 63) & -64; + + advance = ((metrics->vertAdvance + 32) & -64); + + fs_metrics->x_bearing = SCALE (DOUBLE_FROM_26_6 (x1), unscaled->x_scale); + fs_metrics->y_bearing = SCALE (DOUBLE_FROM_26_6 (y1), unscaled->y_scale); + + fs_metrics->width = SCALE (DOUBLE_FROM_26_6 (x2 - x1), unscaled->x_scale); + fs_metrics->height = SCALE (DOUBLE_FROM_26_6 (y2 - y1), unscaled->y_scale); + + fs_metrics->x_advance = 0; + fs_metrics->y_advance = SCALE (DOUBLE_FROM_26_6 (advance), unscaled->y_scale); + } + } else { + fs_metrics->width = SCALE (DOUBLE_FROM_26_6 (metrics->width), unscaled->x_scale); + fs_metrics->height = SCALE (DOUBLE_FROM_26_6 (metrics->height), unscaled->y_scale); + + if (!vertical_layout) { + fs_metrics->x_bearing = SCALE (DOUBLE_FROM_26_6 (metrics->horiBearingX), unscaled->x_scale); + fs_metrics->y_bearing = SCALE (DOUBLE_FROM_26_6 (-metrics->horiBearingY), unscaled->y_scale); + + if (hint_metrics || glyph->format != FT_GLYPH_FORMAT_OUTLINE) + fs_metrics->x_advance = SCALE (DOUBLE_FROM_26_6 (metrics->horiAdvance), unscaled->x_scale); + else + fs_metrics->x_advance = SCALE (DOUBLE_FROM_16_16 (glyph->linearHoriAdvance), unscaled->x_scale); + fs_metrics->y_advance = 0; + } else { + fs_metrics->x_bearing = SCALE (DOUBLE_FROM_26_6 (metrics->vertBearingX), unscaled->x_scale); + fs_metrics->y_bearing = SCALE (DOUBLE_FROM_26_6 (metrics->vertBearingY), unscaled->y_scale); + + fs_metrics->x_advance = 0; + if (hint_metrics || glyph->format != FT_GLYPH_FORMAT_OUTLINE) + fs_metrics->y_advance = SCALE (DOUBLE_FROM_26_6 (metrics->vertAdvance), unscaled->y_scale); + else + fs_metrics->y_advance = SCALE (DOUBLE_FROM_16_16 (glyph->linearVertAdvance), unscaled->y_scale); + } + } +} + +static cairo_bool_t +_cairo_ft_scaled_glyph_is_colr_v0 (cairo_ft_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph, + FT_Face face) +{ + FT_LayerIterator iterator; + FT_UInt layer_glyph_index; + FT_UInt layer_color_index; + + iterator.p = NULL; + if (FT_Get_Color_Glyph_Layer(face, + _cairo_scaled_glyph_index (scaled_glyph), + &layer_glyph_index, + &layer_color_index, + &iterator) == 1) + { + return TRUE; + } + + return FALSE; +} + +static cairo_bool_t +_cairo_ft_scaled_glyph_is_colr_v1 (cairo_ft_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph, + FT_Face face) +{ +#if HAVE_FT_COLR_V1 + FT_OpaquePaint paint = { NULL, 0 }; + + if (FT_Get_Color_Glyph_Paint (face, + _cairo_scaled_glyph_index (scaled_glyph), + FT_COLOR_INCLUDE_ROOT_TRANSFORM, + &paint) == 1) + { + return TRUE; + } +#endif + return FALSE; +} + +static cairo_int_status_t +_cairo_ft_scaled_glyph_init_metrics (cairo_ft_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph, + FT_Face face, + cairo_bool_t vertical_layout, + int load_flags, + const cairo_color_t *foreground_color) +{ + cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; + cairo_text_extents_t fs_metrics; + cairo_ft_glyph_private_t *glyph_priv; + + cairo_bool_t hint_metrics = scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF; + + /* _cairo_ft_scaled_glyph_init_metrics() is called once the first + * time a cairo_scaled_glyph_t is created. We first allocate the + * cairo_ft_glyph_private_t struct and determine the glyph type. + */ + + glyph_priv = _cairo_calloc (sizeof (*glyph_priv)); + if (unlikely (glyph_priv == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + _cairo_scaled_glyph_attach_private (scaled_glyph, &glyph_priv->base, + &ft_glyph_private_key, + _cairo_ft_glyph_fini); + + /* We need to load color to determine if this is a color format. */ + int color_flag = 0; + + if (scaled_font->unscaled->have_color && scaled_font->base.options.color_mode != CAIRO_COLOR_MODE_NO_COLOR) + color_flag = FT_LOAD_COLOR; + + /* Ensure use_em_size = FALSE as the format (bitmap or outline) + * may change with the size. */ + status = _cairo_ft_scaled_glyph_load_glyph (scaled_font, + scaled_glyph, + face, + load_flags | color_flag, + FALSE, + vertical_layout); + if (unlikely (status)) + return status; + + cairo_bool_t is_svg_format = FALSE; +#if HAVE_FT_SVG_DOCUMENT + if (face->glyph->format == FT_GLYPH_FORMAT_SVG) + is_svg_format = TRUE; +#endif + + if (is_svg_format) { + glyph_priv->format = CAIRO_FT_GLYPH_TYPE_SVG; + +#if defined(HAVE_FT_COLR_V1) && defined(HAVE_FT_LOAD_NO_SVG) + /* Prefer COLRv1 table over SVG table due to performance reasons for now */ + if (_cairo_ft_scaled_glyph_is_colr_v1 (scaled_font, scaled_glyph, face)) { + glyph_priv->format = CAIRO_FT_GLYPH_TYPE_COLR_V1; + } +#endif + + } else if (face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) { + glyph_priv->format = CAIRO_FT_GLYPH_TYPE_OUTLINE; + if (color_flag) { + if (_cairo_ft_scaled_glyph_is_colr_v1 (scaled_font, scaled_glyph, face)) + glyph_priv->format = CAIRO_FT_GLYPH_TYPE_COLR_V1; + else if (_cairo_ft_scaled_glyph_is_colr_v0 (scaled_font, scaled_glyph, face)) + glyph_priv->format = CAIRO_FT_GLYPH_TYPE_COLR_V0; + } + } else { + /* For anything else we let FreeType render a bitmap. */ + glyph_priv->format = CAIRO_FT_GLYPH_TYPE_BITMAP; + } + + /* If hinting is off, load the glyph with font size set the the em size. */ + if (!hint_metrics) { + status = _cairo_ft_scaled_glyph_load_glyph (scaled_font, + scaled_glyph, + face, + load_flags | color_flag, + TRUE, + vertical_layout); + if (unlikely (status)) + return status; + } + + _cairo_ft_scaled_glyph_get_metrics (scaled_font, + face, + vertical_layout, + load_flags, + &fs_metrics); + + + /* SVG and COLRv1 glyphs require the bounding box to be obtained + * from the ink extents of the rendering. We need to render glyph + * to a recording surface to obtain these extents. But we also + * need the advance from _cairo_ft_scaled_glyph_get_metrics() + * before calling this function. + */ + + if (glyph_priv->format == CAIRO_FT_GLYPH_TYPE_SVG) { + status = (cairo_int_status_t)_cairo_ft_scaled_glyph_init_record_svg_glyph (scaled_font, + scaled_glyph, + face, + foreground_color, + &fs_metrics); + if (unlikely (status)) + return status; + } + + if (glyph_priv->format == CAIRO_FT_GLYPH_TYPE_COLR_V1) { + /* Restore font size if previously loaded at em_size. */ + if (!hint_metrics) { + status = _cairo_ft_scaled_glyph_load_glyph (scaled_font, + scaled_glyph, + face, + load_flags | color_flag, + FALSE, + vertical_layout); + if (unlikely (status)) + return status; + } + + status = (cairo_int_status_t)_cairo_ft_scaled_glyph_init_record_colr_v1_glyph (scaled_font, + scaled_glyph, + face, + foreground_color, + &fs_metrics); + if (unlikely (status)) + return status; + } + + _cairo_scaled_glyph_set_metrics (scaled_glyph, + &scaled_font->base, + &fs_metrics); + + return status; +} + +static cairo_int_status_t +_cairo_ft_scaled_glyph_init (void *abstract_font, + cairo_scaled_glyph_t *scaled_glyph, + cairo_scaled_glyph_info_t info, + const cairo_color_t *foreground_color) +{ + cairo_ft_scaled_font_t *scaled_font = abstract_font; + cairo_ft_unscaled_font_t *unscaled = scaled_font->unscaled; + FT_Face face; + int load_flags = scaled_font->ft_options.load_flags; + cairo_bool_t vertical_layout = FALSE; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_ft_glyph_private_t *glyph_priv; + + face = _cairo_ft_unscaled_font_lock_face (unscaled); + if (!face) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + /* Ignore global advance unconditionally */ + load_flags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; + + if ((info & CAIRO_SCALED_GLYPH_INFO_PATH) != 0 && + (info & (CAIRO_SCALED_GLYPH_INFO_SURFACE | + CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE)) == 0) { + load_flags |= FT_LOAD_NO_BITMAP; + } + + /* + * Don't pass FT_LOAD_VERTICAL_LAYOUT to FT_Load_Glyph here as + * suggested by freetype people. + */ + if (load_flags & FT_LOAD_VERTICAL_LAYOUT) { + load_flags &= ~FT_LOAD_VERTICAL_LAYOUT; + vertical_layout = TRUE; + } + + /* Metrics will always be requested when a scaled glyph is created */ + if (info & CAIRO_SCALED_GLYPH_INFO_METRICS) { + status = _cairo_ft_scaled_glyph_init_metrics (scaled_font, + scaled_glyph, + face, + vertical_layout, + load_flags, + foreground_color); + if (unlikely (status)) + goto FAIL; + } + + glyph_priv = (cairo_ft_glyph_private_t *) _cairo_scaled_glyph_find_private (scaled_glyph, + &ft_glyph_private_key); + assert (glyph_priv != NULL); + + if (info & CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + if (glyph_priv->format == CAIRO_FT_GLYPH_TYPE_SVG || + glyph_priv->format == CAIRO_FT_GLYPH_TYPE_COLR_V0 || + glyph_priv->format == CAIRO_FT_GLYPH_TYPE_COLR_V1) + { + status = _cairo_ft_scaled_glyph_load_glyph (scaled_font, + scaled_glyph, + face, + load_flags | FT_LOAD_COLOR, + FALSE, + vertical_layout); + if (unlikely (status)) + goto FAIL; + + if (glyph_priv->format == CAIRO_FT_GLYPH_TYPE_SVG) { + status = _cairo_ft_scaled_glyph_init_record_svg_glyph (scaled_font, + scaled_glyph, + face, + foreground_color, + &scaled_glyph->fs_metrics); + } else if (glyph_priv->format == CAIRO_FT_GLYPH_TYPE_COLR_V1) { + status = _cairo_ft_scaled_glyph_init_record_colr_v1_glyph (scaled_font, + scaled_glyph, + face, + foreground_color, + &scaled_glyph->fs_metrics); + } else if (glyph_priv->format == CAIRO_FT_GLYPH_TYPE_COLR_V0) { + status = _cairo_ft_scaled_glyph_init_record_colr_v0_glyph (scaled_font, + scaled_glyph, + face, + vertical_layout, + load_flags); + } + } + if (status) + goto FAIL; + } + + if ((info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) && scaled_font->base.options.color_mode != CAIRO_COLOR_MODE_NO_COLOR) { + if (glyph_priv->format == CAIRO_FT_GLYPH_TYPE_SVG || + glyph_priv->format == CAIRO_FT_GLYPH_TYPE_COLR_V1) + { + status = _cairo_ft_scaled_glyph_init_surface_for_recording_surface (scaled_font, + scaled_glyph, + foreground_color); + } else { + status = _cairo_ft_scaled_glyph_init_surface (scaled_font, + scaled_glyph, + glyph_priv, + CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE, + face, + foreground_color, + vertical_layout, + load_flags); + } + if (unlikely (status)) + goto FAIL; + } + + if (info & CAIRO_SCALED_GLYPH_INFO_SURFACE) { + status = _cairo_ft_scaled_glyph_init_surface (scaled_font, + scaled_glyph, + glyph_priv, + CAIRO_SCALED_GLYPH_INFO_SURFACE, + face, + NULL, /* foreground color */ + vertical_layout, + load_flags); + if (unlikely (status)) + goto FAIL; + } + + if (info & CAIRO_SCALED_GLYPH_INFO_PATH) { + cairo_path_fixed_t *path = NULL; /* hide compiler warning */ + + /* Load non-color glyph */ + status = _cairo_ft_scaled_glyph_load_glyph (scaled_font, + scaled_glyph, + face, + load_flags, + FALSE, + vertical_layout); + if (unlikely (status)) + goto FAIL; + + if (face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) + status = _cairo_ft_face_decompose_glyph_outline (face, &path); + else + status = CAIRO_INT_STATUS_UNSUPPORTED; + + if (unlikely (status)) + goto FAIL; + + _cairo_scaled_glyph_set_path (scaled_glyph, + &scaled_font->base, + path); + } + FAIL: + _cairo_ft_unscaled_font_unlock_face (unscaled); + + return status; +} + +static unsigned long +_cairo_ft_ucs4_to_index (void *abstract_font, + uint32_t ucs4) +{ + cairo_ft_scaled_font_t *scaled_font = abstract_font; + cairo_ft_unscaled_font_t *unscaled = scaled_font->unscaled; + FT_Face face; + FT_UInt index; + + face = _cairo_ft_unscaled_font_lock_face (unscaled); + if (!face) + return 0; + +#if CAIRO_HAS_FC_FONT + index = FcFreeTypeCharIndex (face, ucs4); +#else + index = FT_Get_Char_Index (face, ucs4); +#endif + + _cairo_ft_unscaled_font_unlock_face (unscaled); + return index; +} + +static cairo_int_status_t +_cairo_ft_load_truetype_table (void *abstract_font, + unsigned long tag, + long offset, + unsigned char *buffer, + unsigned long *length) +{ + cairo_ft_scaled_font_t *scaled_font = abstract_font; + cairo_ft_unscaled_font_t *unscaled = scaled_font->unscaled; + FT_Face face; + cairo_status_t status = CAIRO_INT_STATUS_UNSUPPORTED; + + /* We don't support the FreeType feature of loading a table + * without specifying the size since this may overflow our + * buffer. */ + assert (length != NULL); + + if (_cairo_ft_scaled_font_is_vertical (&scaled_font->base)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + face = _cairo_ft_unscaled_font_lock_face (unscaled); + if (!face) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + if (FT_IS_SFNT (face)) { + if (buffer == NULL) + *length = 0; + + if (FT_Load_Sfnt_Table (face, tag, offset, buffer, length) == 0) + status = CAIRO_STATUS_SUCCESS; + } + + _cairo_ft_unscaled_font_unlock_face (unscaled); + + return status; +} + +static cairo_int_status_t +_cairo_ft_index_to_ucs4(void *abstract_font, + unsigned long index, + uint32_t *ucs4) +{ + cairo_ft_scaled_font_t *scaled_font = abstract_font; + cairo_ft_unscaled_font_t *unscaled = scaled_font->unscaled; + FT_Face face; + FT_ULong charcode; + FT_UInt gindex; + + face = _cairo_ft_unscaled_font_lock_face (unscaled); + if (!face) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + *ucs4 = (uint32_t) -1; + charcode = FT_Get_First_Char(face, &gindex); + while (gindex != 0) { + if (gindex == index) { + *ucs4 = charcode; + break; + } + charcode = FT_Get_Next_Char (face, charcode, &gindex); + } + + _cairo_ft_unscaled_font_unlock_face (unscaled); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_ft_is_synthetic (void *abstract_font, + cairo_bool_t *is_synthetic) +{ + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + cairo_ft_scaled_font_t *scaled_font = abstract_font; + cairo_ft_unscaled_font_t *unscaled = scaled_font->unscaled; + FT_Face face; + FT_Error error; + + if (scaled_font->ft_options.synth_flags != 0) { + *is_synthetic = TRUE; + return status; + } + + *is_synthetic = FALSE; + face = _cairo_ft_unscaled_font_lock_face (unscaled); + if (!face) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + if (face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) { + FT_MM_Var *mm_var = NULL; + FT_Fixed *coords = NULL; + int num_axis; + int i; + + /* If this is an MM or variable font we can't assume the current outlines + * are the same as the font tables */ + *is_synthetic = TRUE; + + error = FT_Get_MM_Var (face, &mm_var); + if (error) { + status = _cairo_error (_cairo_ft_to_cairo_error (error)); + goto cleanup; + } + + num_axis = mm_var->num_axis; + coords = _cairo_malloc_ab (num_axis, sizeof(FT_Fixed)); + if (!coords) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto cleanup; + } + + /* Check if the current design coordinates are the default + * coordinates. In this case the current outlines match the + * font tables. + */ + FT_Get_Var_Blend_Coordinates (face, num_axis, coords); + *is_synthetic = FALSE; + for (i = 0; i < num_axis; i++) { + if (coords[i]) { + *is_synthetic = TRUE; + break; + } + } + + cleanup: + free (coords); + FT_Done_MM_Var (face->glyph->library, mm_var); + } + + _cairo_ft_unscaled_font_unlock_face (unscaled); + + return status; +} + +static cairo_int_status_t +_cairo_index_to_glyph_name (void *abstract_font, + char **glyph_names, + int num_glyph_names, + unsigned long glyph_index, + unsigned long *glyph_array_index) +{ + cairo_ft_scaled_font_t *scaled_font = abstract_font; + cairo_ft_unscaled_font_t *unscaled = scaled_font->unscaled; + FT_Face face; + char buffer[256]; /* PLRM specifies max name length of 127 */ + FT_Error error; + int i; + + face = _cairo_ft_unscaled_font_lock_face (unscaled); + if (!face) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + error = FT_Get_Glyph_Name (face, glyph_index, buffer, sizeof buffer); + + _cairo_ft_unscaled_font_unlock_face (unscaled); + + if (error != FT_Err_Ok) { + /* propagate fatal errors from FreeType */ + if (error == FT_Err_Out_Of_Memory) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + /* FT first numbers the glyphs in the order they are read from the + * Type 1 font. Then if .notdef is not the first glyph, the first + * glyph is swapped with .notdef to ensure that .notdef is at + * glyph index 0. + * + * As all but two glyphs in glyph_names already have the same + * index as the FT glyph index, we first check if + * glyph_names[glyph_index] is the name we are looking for. If not + * we fall back to searching the entire array. + */ + + if ((long)glyph_index < num_glyph_names && + strcmp (glyph_names[glyph_index], buffer) == 0) + { + *glyph_array_index = glyph_index; + + return CAIRO_STATUS_SUCCESS; + } + + for (i = 0; i < num_glyph_names; i++) { + if (strcmp (glyph_names[i], buffer) == 0) { + *glyph_array_index = i; + + return CAIRO_STATUS_SUCCESS; + } + } + + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_bool_t +_ft_is_type1 (FT_Face face) +{ + const char *font_format = FT_Get_Font_Format (face); + if (font_format && + (strcmp (font_format, "Type 1") == 0 || + strcmp (font_format, "CFF") == 0)) + { + return TRUE; + } + + return FALSE; +} + +static cairo_int_status_t +_cairo_ft_load_type1_data (void *abstract_font, + long offset, + unsigned char *buffer, + unsigned long *length) +{ + cairo_ft_scaled_font_t *scaled_font = abstract_font; + cairo_ft_unscaled_font_t *unscaled = scaled_font->unscaled; + FT_Face face; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + unsigned long available_length; + unsigned long ret; + + assert (length != NULL); + + if (_cairo_ft_scaled_font_is_vertical (&scaled_font->base)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + face = _cairo_ft_unscaled_font_lock_face (unscaled); + if (!face) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + if (FT_IS_SFNT (face)) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto unlock; + } + + if (! _ft_is_type1 (face)) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto unlock; + } + + available_length = MAX (face->stream->size - offset, 0); + if (!buffer) { + *length = available_length; + } else { + if (*length > available_length) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + } else if (face->stream->read != NULL) { + /* Note that read() may be implemented as a macro, thanks POSIX!, so we + * need to wrap the following usage in parentheses in order to + * disambiguate it for the pre-processor - using the verbose function + * pointer dereference for clarity. + */ + ret = (* face->stream->read) (face->stream, + offset, + buffer, + *length); + if (ret != *length) + status = _cairo_error (CAIRO_STATUS_READ_ERROR); + } else { + memcpy (buffer, face->stream->base + offset, *length); + } + } + + unlock: + _cairo_ft_unscaled_font_unlock_face (unscaled); + + return status; +} + +static cairo_bool_t +_cairo_ft_has_color_glyphs (void *scaled) +{ + cairo_ft_unscaled_font_t *unscaled = ((cairo_ft_scaled_font_t *)scaled)->unscaled; + + if (!unscaled->have_color_set) { + FT_Face face; + face = _cairo_ft_unscaled_font_lock_face (unscaled); + if (unlikely (face == NULL)) + return FALSE; + _cairo_ft_unscaled_font_unlock_face (unscaled); + } + + return unscaled->have_color; +} + +static const cairo_scaled_font_backend_t _cairo_ft_scaled_font_backend = { + CAIRO_FONT_TYPE_FT, + _cairo_ft_scaled_font_fini, + _cairo_ft_scaled_glyph_init, + NULL, /* text_to_glyphs */ + _cairo_ft_ucs4_to_index, + _cairo_ft_load_truetype_table, + _cairo_ft_index_to_ucs4, + _cairo_ft_is_synthetic, + _cairo_index_to_glyph_name, + _cairo_ft_load_type1_data, + _cairo_ft_has_color_glyphs +}; + +/* #cairo_ft_font_face_t */ + +#if CAIRO_HAS_FC_FONT +static cairo_font_face_t * +_cairo_ft_font_face_create_for_pattern (FcPattern *pattern); + +static cairo_status_t +_cairo_ft_font_face_create_for_toy (cairo_toy_font_face_t *toy_face, + cairo_font_face_t **font_face_out) +{ + cairo_font_face_t *font_face = (cairo_font_face_t *) &_cairo_font_face_nil; + FcPattern *pattern; + int fcslant; + int fcweight; + + pattern = FcPatternCreate (); + if (!pattern) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return font_face->status; + } + + if (!FcPatternAddString (pattern, + FC_FAMILY, (unsigned char *) toy_face->family)) + { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + goto FREE_PATTERN; + } + + switch (toy_face->slant) + { + case CAIRO_FONT_SLANT_ITALIC: + fcslant = FC_SLANT_ITALIC; + break; + case CAIRO_FONT_SLANT_OBLIQUE: + fcslant = FC_SLANT_OBLIQUE; + break; + case CAIRO_FONT_SLANT_NORMAL: + default: + fcslant = FC_SLANT_ROMAN; + break; + } + + if (!FcPatternAddInteger (pattern, FC_SLANT, fcslant)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + goto FREE_PATTERN; + } + + switch (toy_face->weight) + { + case CAIRO_FONT_WEIGHT_BOLD: + fcweight = FC_WEIGHT_BOLD; + break; + case CAIRO_FONT_WEIGHT_NORMAL: + default: + fcweight = FC_WEIGHT_MEDIUM; + break; + } + + if (!FcPatternAddInteger (pattern, FC_WEIGHT, fcweight)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + goto FREE_PATTERN; + } + + font_face = _cairo_ft_font_face_create_for_pattern (pattern); + + FREE_PATTERN: + FcPatternDestroy (pattern); + + *font_face_out = font_face; + return font_face->status; +} +#endif + +static cairo_bool_t +_cairo_ft_font_face_destroy (void *abstract_face) +{ + cairo_ft_font_face_t *font_face = abstract_face; + + /* When destroying a face created by cairo_ft_font_face_create_for_ft_face, + * we have a special "zombie" state for the face when the unscaled font + * is still alive but there are no other references to a font face with + * the same FT_Face. + * + * We go from: + * + * font_face ------> unscaled + * <-....weak....../ + * + * To: + * + * font_face <------- unscaled + */ + + if (font_face->unscaled && + font_face->unscaled->from_face && + font_face->next == NULL && + font_face->unscaled->faces == font_face && + CAIRO_REFERENCE_COUNT_GET_VALUE (&font_face->unscaled->base.ref_count) > 1) + { + _cairo_unscaled_font_destroy (&font_face->unscaled->base); + font_face->unscaled = NULL; + + return FALSE; + } + + if (font_face->unscaled) { + cairo_ft_font_face_t *tmp_face = NULL; + cairo_ft_font_face_t *last_face = NULL; + + /* Remove face from linked list */ + for (tmp_face = font_face->unscaled->faces; + tmp_face; + tmp_face = tmp_face->next) + { + if (tmp_face == font_face) { + if (last_face) + last_face->next = tmp_face->next; + else + font_face->unscaled->faces = tmp_face->next; + } + + last_face = tmp_face; + } + + _cairo_unscaled_font_destroy (&font_face->unscaled->base); + font_face->unscaled = NULL; + } + + _cairo_ft_options_fini (&font_face->ft_options); + +#if CAIRO_HAS_FC_FONT + if (font_face->pattern) { + FcPatternDestroy (font_face->pattern); + cairo_font_face_destroy (font_face->resolved_font_face); + } +#endif + + return TRUE; +} + +static cairo_font_face_t * +_cairo_ft_font_face_get_implementation (void *abstract_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options) +{ + /* The handling of font options is different depending on how the + * font face was created. When the user creates a font face with + * cairo_ft_font_face_create_for_ft_face(), then the load flags + * passed in augment the load flags for the options. But for + * cairo_ft_font_face_create_for_pattern(), the load flags are + * derived from a pattern where the user has called + * cairo_ft_font_options_substitute(), so *just* use those load + * flags and ignore the options. + */ + +#if CAIRO_HAS_FC_FONT + cairo_ft_font_face_t *font_face = abstract_face; + + /* If we have an unresolved pattern, resolve it and create + * unscaled font. Otherwise, use the ones stored in font_face. + */ + if (font_face->pattern) { + cairo_font_face_t *resolved; + + /* Cache the resolved font whilst the FcConfig remains consistent. */ + resolved = font_face->resolved_font_face; + if (resolved != NULL) { + if (! FcInitBringUptoDate ()) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_font_face_t *) &_cairo_font_face_nil; + } + + if (font_face->resolved_config == FcConfigGetCurrent ()) + return cairo_font_face_reference (resolved); + + cairo_font_face_destroy (resolved); + font_face->resolved_font_face = NULL; + } + + resolved = _cairo_ft_resolve_pattern (font_face->pattern, + font_matrix, + ctm, + options); + if (unlikely (resolved->status)) + return resolved; + + font_face->resolved_font_face = cairo_font_face_reference (resolved); + font_face->resolved_config = FcConfigGetCurrent (); + + return resolved; + } +#endif + + return abstract_face; +} + +const cairo_font_face_backend_t _cairo_ft_font_face_backend = { + CAIRO_FONT_TYPE_FT, +#if CAIRO_HAS_FC_FONT + _cairo_ft_font_face_create_for_toy, +#else + NULL, +#endif + _cairo_ft_font_face_destroy, + _cairo_ft_font_face_scaled_font_create, + _cairo_ft_font_face_get_implementation +}; + +#if CAIRO_HAS_FC_FONT +static cairo_font_face_t * +_cairo_ft_font_face_create_for_pattern (FcPattern *pattern) +{ + cairo_ft_font_face_t *font_face; + + font_face = _cairo_calloc (sizeof (cairo_ft_font_face_t)); + if (unlikely (font_face == NULL)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_font_face_t *) &_cairo_font_face_nil; + } + + font_face->unscaled = NULL; + + _get_pattern_ft_options (pattern, &font_face->ft_options); + + font_face->next = NULL; + + font_face->pattern = FcPatternDuplicate (pattern); + if (unlikely (font_face->pattern == NULL)) { + free (font_face); + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_font_face_t *) &_cairo_font_face_nil; + } + + font_face->resolved_font_face = NULL; + font_face->resolved_config = NULL; + + _cairo_font_face_init (&font_face->base, &_cairo_ft_font_face_backend); + + return &font_face->base; +} +#endif + +static cairo_font_face_t * +_cairo_ft_font_face_create (cairo_ft_unscaled_font_t *unscaled, + cairo_ft_options_t *ft_options) +{ + cairo_ft_font_face_t *font_face, **prev_font_face; + + /* Looked for an existing matching font face */ + for (font_face = unscaled->faces, prev_font_face = &unscaled->faces; + font_face; + prev_font_face = &font_face->next, font_face = font_face->next) + { + if (font_face->ft_options.load_flags == ft_options->load_flags && + font_face->ft_options.synth_flags == ft_options->synth_flags && + cairo_font_options_equal (&font_face->ft_options.base, &ft_options->base)) + { + if (font_face->base.status) { + /* The font_face has been left in an error state, abandon it. */ + *prev_font_face = font_face->next; + break; + } + + if (font_face->unscaled == NULL) { + /* Resurrect this "zombie" font_face (from + * _cairo_ft_font_face_destroy), switching its unscaled_font + * from owner to ownee. */ + font_face->unscaled = unscaled; + _cairo_unscaled_font_reference (&unscaled->base); + return &font_face->base; + } else + return cairo_font_face_reference (&font_face->base); + } + } + + /* No match found, create a new one */ + font_face = _cairo_calloc (sizeof (cairo_ft_font_face_t)); + if (unlikely (!font_face)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_font_face_t *)&_cairo_font_face_nil; + } + + font_face->unscaled = unscaled; + _cairo_unscaled_font_reference (&unscaled->base); + + _cairo_ft_options_init_copy (&font_face->ft_options, ft_options); + + if (unscaled->faces && unscaled->faces->unscaled == NULL) { + /* This "zombie" font_face (from _cairo_ft_font_face_destroy) + * is no longer needed. */ + assert (unscaled->from_face && unscaled->faces->next == NULL); + cairo_font_face_destroy (&unscaled->faces->base); + unscaled->faces = NULL; + } + + font_face->next = unscaled->faces; + unscaled->faces = font_face; + +#if CAIRO_HAS_FC_FONT + font_face->pattern = NULL; +#endif + + _cairo_font_face_init (&font_face->base, &_cairo_ft_font_face_backend); + + return &font_face->base; +} + +/* implement the platform-specific interface */ + +#if CAIRO_HAS_FC_FONT +static cairo_status_t +_cairo_ft_font_options_substitute (const cairo_font_options_t *options, + FcPattern *pattern) +{ + FcValue v; + + if (options->antialias != CAIRO_ANTIALIAS_DEFAULT) + { + if (FcPatternGet (pattern, FC_ANTIALIAS, 0, &v) == FcResultNoMatch) + { + if (! FcPatternAddBool (pattern, + FC_ANTIALIAS, + options->antialias != CAIRO_ANTIALIAS_NONE)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + if (options->antialias != CAIRO_ANTIALIAS_SUBPIXEL) { + FcPatternDel (pattern, FC_RGBA); + if (! FcPatternAddInteger (pattern, FC_RGBA, FC_RGBA_NONE)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + } + } + + if (options->antialias != CAIRO_ANTIALIAS_DEFAULT) + { + if (FcPatternGet (pattern, FC_RGBA, 0, &v) == FcResultNoMatch) + { + int rgba; + + if (options->antialias == CAIRO_ANTIALIAS_SUBPIXEL) { + switch (options->subpixel_order) { + case CAIRO_SUBPIXEL_ORDER_DEFAULT: + case CAIRO_SUBPIXEL_ORDER_RGB: + default: + rgba = FC_RGBA_RGB; + break; + case CAIRO_SUBPIXEL_ORDER_BGR: + rgba = FC_RGBA_BGR; + break; + case CAIRO_SUBPIXEL_ORDER_VRGB: + rgba = FC_RGBA_VRGB; + break; + case CAIRO_SUBPIXEL_ORDER_VBGR: + rgba = FC_RGBA_VBGR; + break; + } + } else { + rgba = FC_RGBA_NONE; + } + + if (! FcPatternAddInteger (pattern, FC_RGBA, rgba)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + } + + if (options->lcd_filter != CAIRO_LCD_FILTER_DEFAULT) + { + if (FcPatternGet (pattern, FC_LCD_FILTER, 0, &v) == FcResultNoMatch) + { + int lcd_filter; + + switch (options->lcd_filter) { + case CAIRO_LCD_FILTER_NONE: + lcd_filter = FT_LCD_FILTER_NONE; + break; + case CAIRO_LCD_FILTER_INTRA_PIXEL: + lcd_filter = FT_LCD_FILTER_LEGACY; + break; + case CAIRO_LCD_FILTER_FIR3: + lcd_filter = FT_LCD_FILTER_LIGHT; + break; + default: + case CAIRO_LCD_FILTER_DEFAULT: + case CAIRO_LCD_FILTER_FIR5: + lcd_filter = FT_LCD_FILTER_DEFAULT; + break; + } + + if (! FcPatternAddInteger (pattern, FC_LCD_FILTER, lcd_filter)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + } + + if (options->hint_style != CAIRO_HINT_STYLE_DEFAULT) + { + if (FcPatternGet (pattern, FC_HINTING, 0, &v) == FcResultNoMatch) + { + if (! FcPatternAddBool (pattern, + FC_HINTING, + options->hint_style != CAIRO_HINT_STYLE_NONE)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + if (FcPatternGet (pattern, FC_HINT_STYLE, 0, &v) == FcResultNoMatch) + { + int hint_style; + + switch (options->hint_style) { + case CAIRO_HINT_STYLE_NONE: + hint_style = FC_HINT_NONE; + break; + case CAIRO_HINT_STYLE_SLIGHT: + hint_style = FC_HINT_SLIGHT; + break; + case CAIRO_HINT_STYLE_MEDIUM: + hint_style = FC_HINT_MEDIUM; + break; + case CAIRO_HINT_STYLE_FULL: + case CAIRO_HINT_STYLE_DEFAULT: + default: + hint_style = FC_HINT_FULL; + break; + } + + if (! FcPatternAddInteger (pattern, FC_HINT_STYLE, hint_style)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + } + + return CAIRO_STATUS_SUCCESS; +} + +/** + * cairo_ft_font_options_substitute: + * @options: a #cairo_font_options_t object + * @pattern: an existing #FcPattern + * + * Add options to a #FcPattern based on a #cairo_font_options_t font + * options object. Options that are already in the pattern, are not overridden, + * so you should call this function after calling FcConfigSubstitute() (the + * user's settings should override options based on the surface type), but + * before calling FcDefaultSubstitute(). + * + * Since: 1.0 + **/ +void +cairo_ft_font_options_substitute (const cairo_font_options_t *options, + FcPattern *pattern) +{ + if (cairo_font_options_status ((cairo_font_options_t *) options)) + return; + + _cairo_ft_font_options_substitute (options, pattern); +} + +static cairo_font_face_t * +_cairo_ft_resolve_pattern (FcPattern *pattern, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *font_options) +{ + cairo_status_t status; + + cairo_matrix_t scale; + FcPattern *resolved; + cairo_ft_font_transform_t sf; + FcResult result; + cairo_ft_unscaled_font_t *unscaled; + cairo_ft_options_t ft_options; + cairo_font_face_t *font_face; + + scale = *ctm; + scale.x0 = scale.y0 = 0; + cairo_matrix_multiply (&scale, + font_matrix, + &scale); + + status = _compute_transform (&sf, &scale, NULL); + if (unlikely (status)) + return (cairo_font_face_t *)&_cairo_font_face_nil; + + pattern = FcPatternDuplicate (pattern); + if (pattern == NULL) + return (cairo_font_face_t *)&_cairo_font_face_nil; + + if (! FcPatternAddDouble (pattern, FC_PIXEL_SIZE, sf.y_scale)) { + font_face = (cairo_font_face_t *)&_cairo_font_face_nil; + goto FREE_PATTERN; + } + + if (! FcConfigSubstitute (NULL, pattern, FcMatchPattern)) { + font_face = (cairo_font_face_t *)&_cairo_font_face_nil; + goto FREE_PATTERN; + } + + status = _cairo_ft_font_options_substitute (font_options, pattern); + if (status) { + font_face = (cairo_font_face_t *)&_cairo_font_face_nil; + goto FREE_PATTERN; + } + + FcDefaultSubstitute (pattern); + + status = _cairo_ft_unscaled_font_create_for_pattern (pattern, &unscaled); + if (unlikely (status)) { + font_face = (cairo_font_face_t *)&_cairo_font_face_nil; + goto FREE_PATTERN; + } + + if (unscaled == NULL) { + resolved = FcFontMatch (NULL, pattern, &result); + if (!resolved) { + /* We failed to find any font. Substitute twin so that the user can + * see something (and hopefully recognise that the font is missing) + * and not just receive a NO_MEMORY error during rendering. + */ + font_face = _cairo_font_face_twin_create_fallback (); + goto FREE_PATTERN; + } + + status = _cairo_ft_unscaled_font_create_for_pattern (resolved, &unscaled); + if (unlikely (status || unscaled == NULL)) { + font_face = (cairo_font_face_t *)&_cairo_font_face_nil; + goto FREE_RESOLVED; + } + } else + resolved = pattern; + + _get_pattern_ft_options (resolved, &ft_options); + font_face = _cairo_ft_font_face_create (unscaled, &ft_options); + _cairo_ft_options_fini (&ft_options); + _cairo_unscaled_font_destroy (&unscaled->base); + +FREE_RESOLVED: + if (resolved != pattern) + FcPatternDestroy (resolved); + +FREE_PATTERN: + FcPatternDestroy (pattern); + + return font_face; +} + +/** + * cairo_ft_font_face_create_for_pattern: + * @pattern: A fontconfig pattern. Cairo makes a copy of the pattern + * if it needs to. You are free to modify or free @pattern after this call. + * + * Creates a new font face for the FreeType font backend based on a + * fontconfig pattern. This font can then be used with + * cairo_set_font_face() or cairo_scaled_font_create(). The + * #cairo_scaled_font_t returned from cairo_scaled_font_create() is + * also for the FreeType backend and can be used with functions such + * as cairo_ft_scaled_font_lock_face(). + * + * Font rendering options are represented both here and when you + * call cairo_scaled_font_create(). Font options that have a representation + * in a #FcPattern must be passed in here; to modify #FcPattern + * appropriately to reflect the options in a #cairo_font_options_t, call + * cairo_ft_font_options_substitute(). + * + * The pattern's FC_FT_FACE element is inspected first and if that is set, + * that will be the FreeType font face associated with the returned cairo + * font face. Otherwise the FC_FILE element is checked. If it's set, + * that and the value of the FC_INDEX element (defaults to zero) of @pattern + * are used to load a font face from file. + * + * If both steps from the previous paragraph fails, @pattern will be passed + * to FcConfigSubstitute, FcDefaultSubstitute, and finally FcFontMatch, + * and the resulting font pattern is used. + * + * If the FC_FT_FACE element of @pattern is set, the user is responsible + * for making sure that the referenced FT_Face remains valid for the life + * time of the returned #cairo_font_face_t. See + * cairo_ft_font_face_create_for_ft_face() for an example of how to couple + * the life time of the FT_Face to that of the cairo font-face. + * + * Return value: a newly created #cairo_font_face_t. Free with + * cairo_font_face_destroy() when you are done using it. + * + * Since: 1.0 + **/ +cairo_font_face_t * +cairo_ft_font_face_create_for_pattern (FcPattern *pattern) +{ + cairo_ft_unscaled_font_t *unscaled; + cairo_font_face_t *font_face; + cairo_ft_options_t ft_options; + cairo_status_t status; + + status = _cairo_ft_unscaled_font_create_for_pattern (pattern, &unscaled); + if (unlikely (status)) { + if (status == CAIRO_STATUS_FILE_NOT_FOUND) + return (cairo_font_face_t *) &_cairo_font_face_nil_file_not_found; + else + return (cairo_font_face_t *) &_cairo_font_face_nil; + } + if (unlikely (unscaled == NULL)) { + /* Store the pattern. We will resolve it and create unscaled + * font when creating scaled fonts */ + return _cairo_ft_font_face_create_for_pattern (pattern); + } + + _get_pattern_ft_options (pattern, &ft_options); + font_face = _cairo_ft_font_face_create (unscaled, &ft_options); + _cairo_ft_options_fini (&ft_options); + _cairo_unscaled_font_destroy (&unscaled->base); + + return font_face; +} +#endif + +/** + * cairo_ft_font_face_create_for_ft_face: + * @face: A FreeType face object, already opened. This must + * be kept around until the face's ref_count drops to + * zero and it is freed. Since the face may be referenced + * internally to Cairo, the best way to determine when it + * is safe to free the face is to pass a + * #cairo_destroy_func_t to cairo_font_face_set_user_data() + * @load_flags: flags to pass to FT_Load_Glyph when loading + * glyphs from the font. These flags are OR'ed together with + * the flags derived from the #cairo_font_options_t passed + * to cairo_scaled_font_create(), so only a few values such + * as %FT_LOAD_VERTICAL_LAYOUT, and %FT_LOAD_FORCE_AUTOHINT + * are useful. You should not pass any of the flags affecting + * the load target, such as %FT_LOAD_TARGET_LIGHT. + * + * Creates a new font face for the FreeType font backend from a + * pre-opened FreeType face. This font can then be used with + * cairo_set_font_face() or cairo_scaled_font_create(). The + * #cairo_scaled_font_t returned from cairo_scaled_font_create() is + * also for the FreeType backend and can be used with functions such + * as cairo_ft_scaled_font_lock_face(). Note that Cairo may keep a reference + * to the FT_Face alive in a font-cache and the exact lifetime of the reference + * depends highly upon the exact usage pattern and is subject to external + * factors. You must not call FT_Done_Face() before the last reference to the + * #cairo_font_face_t has been dropped. + * + * As an example, below is how one might correctly couple the lifetime of + * the FreeType face object to the #cairo_font_face_t. + * + * + * static const cairo_user_data_key_t key; + * + * font_face = cairo_ft_font_face_create_for_ft_face (ft_face, 0); + * status = cairo_font_face_set_user_data (font_face, &key, + * ft_face, (cairo_destroy_func_t) FT_Done_Face); + * if (status) { + * cairo_font_face_destroy (font_face); + * FT_Done_Face (ft_face); + * return ERROR; + * } + * + * + * Return value: a newly created #cairo_font_face_t. Free with + * cairo_font_face_destroy() when you are done using it. + * + * Since: 1.0 + **/ +cairo_font_face_t * +cairo_ft_font_face_create_for_ft_face (FT_Face face, + int load_flags) +{ + cairo_ft_unscaled_font_t *unscaled; + cairo_font_face_t *font_face; + cairo_ft_options_t ft_options; + cairo_status_t status; + + status = _cairo_ft_unscaled_font_create_from_face (face, &unscaled); + if (unlikely (status)) + return (cairo_font_face_t *)&_cairo_font_face_nil; + + ft_options.load_flags = load_flags; + ft_options.synth_flags = 0; + _cairo_font_options_init_default (&ft_options.base); + + font_face = _cairo_ft_font_face_create (unscaled, &ft_options); + _cairo_unscaled_font_destroy (&unscaled->base); + + return font_face; +} + +/** + * cairo_ft_font_face_set_synthesize: + * @font_face: The #cairo_ft_font_face_t object to modify + * @synth_flags: the set of synthesis options to enable + * + * FreeType provides the ability to synthesize different glyphs from a base + * font, which is useful if you lack those glyphs from a true bold or oblique + * font. See also #cairo_ft_synthesize_t. + * + * Since: 1.12 + **/ +void +cairo_ft_font_face_set_synthesize (cairo_font_face_t *font_face, + unsigned int synth_flags) +{ + cairo_ft_font_face_t *ft; + + if (font_face->backend->type != CAIRO_FONT_TYPE_FT) + return; + + ft = (cairo_ft_font_face_t *) font_face; + ft->ft_options.synth_flags |= synth_flags; +} + +/** + * cairo_ft_font_face_unset_synthesize: + * @font_face: The #cairo_ft_font_face_t object to modify + * @synth_flags: the set of synthesis options to disable + * + * See cairo_ft_font_face_set_synthesize(). + * + * Since: 1.12 + **/ +void +cairo_ft_font_face_unset_synthesize (cairo_font_face_t *font_face, + unsigned int synth_flags) +{ + cairo_ft_font_face_t *ft; + + if (font_face->backend->type != CAIRO_FONT_TYPE_FT) + return; + + ft = (cairo_ft_font_face_t *) font_face; + ft->ft_options.synth_flags &= ~synth_flags; +} + +/** + * cairo_ft_font_face_get_synthesize: + * @font_face: The #cairo_ft_font_face_t object to query + * + * See #cairo_ft_synthesize_t. + * + * Returns: the current set of synthesis options. + * + * Since: 1.12 + **/ +unsigned int +cairo_ft_font_face_get_synthesize (cairo_font_face_t *font_face) +{ + cairo_ft_font_face_t *ft; + + if (font_face->backend->type != CAIRO_FONT_TYPE_FT) + return 0; + + ft = (cairo_ft_font_face_t *) font_face; + return ft->ft_options.synth_flags; +} + +/** + * cairo_ft_scaled_font_lock_face: + * @scaled_font: A #cairo_scaled_font_t from the FreeType font backend. Such an + * object can be created by calling cairo_scaled_font_create() on a + * FreeType backend font face (see cairo_ft_font_face_create_for_pattern(), + * cairo_ft_font_face_create_for_ft_face()). + * + * cairo_ft_scaled_font_lock_face() gets the #FT_Face object from a FreeType + * backend font and scales it appropriately for the font and applies OpenType + * font variations if applicable. You must + * release the face with cairo_ft_scaled_font_unlock_face() + * when you are done using it. Since the #FT_Face object can be + * shared between multiple #cairo_scaled_font_t objects, you must not + * lock any other font objects until you unlock this one. A count is + * kept of the number of times cairo_ft_scaled_font_lock_face() is + * called. cairo_ft_scaled_font_unlock_face() must be called the same number + * of times. + * + * You must be careful when using this function in a library or in a + * threaded application, because freetype's design makes it unsafe to + * call freetype functions simultaneously from multiple threads, (even + * if using distinct FT_Face objects). Because of this, application + * code that acquires an FT_Face object with this call must add its + * own locking to protect any use of that object, (and which also must + * protect any other calls into cairo as almost any cairo function + * might result in a call into the freetype library). + * + * Return value: The #FT_Face object for @font, scaled appropriately, + * or %NULL if @scaled_font is in an error state (see + * cairo_scaled_font_status()) or there is insufficient memory. + * + * Since: 1.0 + **/ +FT_Face +cairo_ft_scaled_font_lock_face (cairo_scaled_font_t *abstract_font) +{ + cairo_ft_scaled_font_t *scaled_font = (cairo_ft_scaled_font_t *) abstract_font; + FT_Face face; + cairo_status_t status; + + if (! _cairo_scaled_font_is_ft (abstract_font)) { + _cairo_error_throw (CAIRO_STATUS_FONT_TYPE_MISMATCH); + return NULL; + } + + if (scaled_font->base.status) + return NULL; + + face = _cairo_ft_unscaled_font_lock_face (scaled_font->unscaled); + if (unlikely (face == NULL)) { + status = _cairo_scaled_font_set_error (&scaled_font->base, CAIRO_STATUS_NO_MEMORY); + return NULL; + } + + status = _cairo_ft_unscaled_font_set_scale (scaled_font->unscaled, + &scaled_font->base.scale); + if (unlikely (status)) { + _cairo_ft_unscaled_font_unlock_face (scaled_font->unscaled); + status = _cairo_scaled_font_set_error (&scaled_font->base, status); + return NULL; + } + + cairo_ft_apply_variations (face, scaled_font); + + /* Note: We deliberately release the unscaled font's mutex here, + * so that we are not holding a lock across two separate calls to + * cairo function, (which would give the application some + * opportunity for creating deadlock. This is obviously unsafe, + * but as documented, the user must add manual locking when using + * this function. */ + CAIRO_MUTEX_UNLOCK (scaled_font->unscaled->mutex); + + return face; +} + +/** + * cairo_ft_scaled_font_unlock_face: + * @scaled_font: A #cairo_scaled_font_t from the FreeType font backend. Such an + * object can be created by calling cairo_scaled_font_create() on a + * FreeType backend font face (see cairo_ft_font_face_create_for_pattern(), + * cairo_ft_font_face_create_for_ft_face()). + * + * Releases a face obtained with cairo_ft_scaled_font_lock_face(). + * + * Since: 1.0 + **/ +void +cairo_ft_scaled_font_unlock_face (cairo_scaled_font_t *abstract_font) +{ + cairo_ft_scaled_font_t *scaled_font = (cairo_ft_scaled_font_t *) abstract_font; + + if (! _cairo_scaled_font_is_ft (abstract_font)) { + _cairo_error_throw (CAIRO_STATUS_FONT_TYPE_MISMATCH); + return; + } + + if (scaled_font->base.status) + return; + + /* Note: We released the unscaled font's mutex at the end of + * cairo_ft_scaled_font_lock_face, so we have to acquire it again + * as _cairo_ft_unscaled_font_unlock_face expects it to be held + * when we call into it. */ + CAIRO_MUTEX_LOCK (scaled_font->unscaled->mutex); + + _cairo_ft_unscaled_font_unlock_face (scaled_font->unscaled); +} + +static cairo_bool_t +_cairo_ft_scaled_font_is_vertical (cairo_scaled_font_t *scaled_font) +{ + cairo_ft_scaled_font_t *ft_scaled_font; + + if (!_cairo_scaled_font_is_ft (scaled_font)) + return FALSE; + + ft_scaled_font = (cairo_ft_scaled_font_t *) scaled_font; + if (ft_scaled_font->ft_options.load_flags & FT_LOAD_VERTICAL_LAYOUT) + return TRUE; + return FALSE; +} + +unsigned int +_cairo_ft_scaled_font_get_load_flags (cairo_scaled_font_t *scaled_font) +{ + cairo_ft_scaled_font_t *ft_scaled_font; + + if (! _cairo_scaled_font_is_ft (scaled_font)) + return 0; + + ft_scaled_font = (cairo_ft_scaled_font_t *) scaled_font; + return ft_scaled_font->ft_options.load_flags; +} + +void +_cairo_ft_font_reset_static_data (void) +{ + _cairo_ft_unscaled_font_map_destroy (); +} diff --git a/local/recipes/libs/cairo/source/src/cairo-ft-private.h b/local/recipes/libs/cairo/source/src/cairo-ft-private.h new file mode 100644 index 0000000000..6b0e302233 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-ft-private.h @@ -0,0 +1,99 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Graydon Hoare + * Owen Taylor + */ + +#ifndef CAIRO_FT_PRIVATE_H +#define CAIRO_FT_PRIVATE_H + +#include "cairoint.h" +#include "cairo-ft.h" + +#if CAIRO_HAS_FT_FONT + +#include FT_COLOR_H + +CAIRO_BEGIN_DECLS + +typedef struct _cairo_ft_unscaled_font cairo_ft_unscaled_font_t; + +cairo_private cairo_bool_t +_cairo_scaled_font_is_ft (cairo_scaled_font_t *scaled_font); + +/* These functions are needed by the PDF backend, which needs to keep track of the + * the different fonts-on-disk used by a document, so it can embed them + */ +cairo_private unsigned int +_cairo_ft_scaled_font_get_load_flags (cairo_scaled_font_t *scaled_font); + +cairo_private cairo_status_t +_cairo_ft_to_cairo_error (FT_Error error); + +cairo_private cairo_status_t +_cairo_ft_face_decompose_glyph_outline (FT_Face face, + cairo_path_fixed_t **pathp); + +#if HAVE_FT_SVG_DOCUMENT + +typedef struct FT_Color_ FT_Color; + +cairo_private cairo_status_t +_cairo_render_svg_glyph (const char *svg_document, + unsigned long first_glyph, + unsigned long last_glyph, + unsigned long glyph, + double units_per_em, + FT_Color *palette, + int num_palette_entries, + cairo_t *cr, + cairo_pattern_t *foreground_source, + cairo_bool_t *foreground_source_used); +#endif + +#if HAVE_FT_COLR_V1 +cairo_private cairo_status_t +_cairo_render_colr_v1_glyph (FT_Face face, + unsigned long glyph, + FT_Color *palette, + int num_palette_entries, + cairo_t *cr, + cairo_pattern_t *foreground_source, + cairo_bool_t *foreground_source_used); +#endif + +CAIRO_END_DECLS + +#endif /* CAIRO_HAS_FT_FONT */ +#endif /* CAIRO_FT_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-ft.h b/local/recipes/libs/cairo/source/src/cairo-ft.h new file mode 100644 index 0000000000..a23e0320e5 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-ft.h @@ -0,0 +1,118 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Graydon Hoare + * Owen Taylor + */ + +#ifndef CAIRO_FT_H +#define CAIRO_FT_H + +#include "cairo.h" + +#if CAIRO_HAS_FT_FONT + +/* Fontconfig/FreeType platform-specific font interface */ + +#include +#include FT_FREETYPE_H + +#if CAIRO_HAS_FC_FONT +#include +#endif + +CAIRO_BEGIN_DECLS + +cairo_public cairo_font_face_t * +cairo_ft_font_face_create_for_ft_face (FT_Face face, + int load_flags); + +/** + * cairo_ft_synthesize_t: + * @CAIRO_FT_SYNTHESIZE_BOLD: Embolden the glyphs (redraw with a pixel offset) + * @CAIRO_FT_SYNTHESIZE_OBLIQUE: Slant the glyph outline by 12 degrees to the + * right. + * + * A set of synthesis options to control how FreeType renders the glyphs + * for a particular font face. + * + * Individual synthesis features of a #cairo_ft_font_face_t can be set + * using cairo_ft_font_face_set_synthesize(), or disabled using + * cairo_ft_font_face_unset_synthesize(). The currently enabled set of + * synthesis options can be queried with cairo_ft_font_face_get_synthesize(). + * + * Note: that when synthesizing glyphs, the font metrics returned will only + * be estimates. + * + * Since: 1.12 + **/ +typedef enum { + CAIRO_FT_SYNTHESIZE_BOLD = 1 << 0, + CAIRO_FT_SYNTHESIZE_OBLIQUE = 1 << 1 +} cairo_ft_synthesize_t; + +cairo_public void +cairo_ft_font_face_set_synthesize (cairo_font_face_t *font_face, + unsigned int synth_flags); + +cairo_public void +cairo_ft_font_face_unset_synthesize (cairo_font_face_t *font_face, + unsigned int synth_flags); + +cairo_public unsigned int +cairo_ft_font_face_get_synthesize (cairo_font_face_t *font_face); + + +cairo_public FT_Face +cairo_ft_scaled_font_lock_face (cairo_scaled_font_t *scaled_font); + +cairo_public void +cairo_ft_scaled_font_unlock_face (cairo_scaled_font_t *scaled_font); + +#if CAIRO_HAS_FC_FONT + +cairo_public cairo_font_face_t * +cairo_ft_font_face_create_for_pattern (FcPattern *pattern); + +cairo_public void +cairo_ft_font_options_substitute (const cairo_font_options_t *options, + FcPattern *pattern); + +#endif + +CAIRO_END_DECLS + +#else /* CAIRO_HAS_FT_FONT */ +# error Cairo was not compiled with support for the freetype font backend +#endif /* CAIRO_HAS_FT_FONT */ + +#endif /* CAIRO_FT_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-gstate-private.h b/local/recipes/libs/cairo/source/src/cairo-gstate-private.h new file mode 100644 index 0000000000..fe1556b038 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-gstate-private.h @@ -0,0 +1,402 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Carl D. Worth + */ + +#ifndef CAIRO_GSTATE_PRIVATE_H +#define CAIRO_GSTATE_PRIVATE_H + +#include "cairo-clip-private.h" + +struct _cairo_gstate { + cairo_operator_t op; + + double opacity; + double tolerance; + cairo_antialias_t antialias; + + cairo_stroke_style_t stroke_style; + + cairo_fill_rule_t fill_rule; + + cairo_font_face_t *font_face; + cairo_scaled_font_t *scaled_font; /* Specific to the current CTM */ + cairo_scaled_font_t *previous_scaled_font; /* holdover */ + cairo_matrix_t font_matrix; + cairo_font_options_t font_options; + + cairo_clip_t *clip; + + cairo_surface_t *target; /* The target to which all rendering is directed */ + cairo_surface_t *parent_target; /* The previous target which was receiving rendering */ + cairo_surface_t *original_target; /* The original target the initial gstate was created with */ + + /* the user is allowed to update the device after we have cached the matrices... */ + cairo_observer_t device_transform_observer; + + cairo_matrix_t ctm; + cairo_matrix_t ctm_inverse; + cairo_matrix_t source_ctm_inverse; /* At the time ->source was set */ + cairo_bool_t is_identity; + + cairo_pattern_t *source; + + struct _cairo_gstate *next; +}; + +/* cairo-gstate.c */ +cairo_private cairo_status_t +_cairo_gstate_init (cairo_gstate_t *gstate, + cairo_surface_t *target); + +cairo_private void +_cairo_gstate_fini (cairo_gstate_t *gstate); + +cairo_private cairo_status_t +_cairo_gstate_save (cairo_gstate_t **gstate, cairo_gstate_t **freelist); + +cairo_private cairo_status_t +_cairo_gstate_restore (cairo_gstate_t **gstate, cairo_gstate_t **freelist); + +cairo_private cairo_bool_t +_cairo_gstate_is_group (cairo_gstate_t *gstate); + +cairo_private cairo_status_t +_cairo_gstate_redirect_target (cairo_gstate_t *gstate, cairo_surface_t *child); + +cairo_private cairo_surface_t * +_cairo_gstate_get_target (cairo_gstate_t *gstate); + +cairo_private cairo_surface_t * +_cairo_gstate_get_original_target (cairo_gstate_t *gstate); + +cairo_private cairo_clip_t * +_cairo_gstate_get_clip (cairo_gstate_t *gstate); + +cairo_private cairo_status_t +_cairo_gstate_set_source (cairo_gstate_t *gstate, cairo_pattern_t *source); + +cairo_private cairo_pattern_t * +_cairo_gstate_get_source (cairo_gstate_t *gstate); + +cairo_private cairo_status_t +_cairo_gstate_set_operator (cairo_gstate_t *gstate, cairo_operator_t op); + +cairo_private cairo_operator_t +_cairo_gstate_get_operator (cairo_gstate_t *gstate); + +cairo_private cairo_status_t +_cairo_gstate_set_opacity (cairo_gstate_t *gstate, double opacity); + +cairo_private double +_cairo_gstate_get_opacity (cairo_gstate_t *gstate); + +cairo_private cairo_status_t +_cairo_gstate_set_tolerance (cairo_gstate_t *gstate, double tolerance); + +cairo_private double +_cairo_gstate_get_tolerance (cairo_gstate_t *gstate); + +cairo_private cairo_status_t +_cairo_gstate_set_fill_rule (cairo_gstate_t *gstate, cairo_fill_rule_t fill_rule); + +cairo_private cairo_fill_rule_t +_cairo_gstate_get_fill_rule (cairo_gstate_t *gstate); + +cairo_private cairo_status_t +_cairo_gstate_set_line_width (cairo_gstate_t *gstate, double width); + +cairo_private double +_cairo_gstate_get_line_width (cairo_gstate_t *gstate); + +cairo_private cairo_status_t +_cairo_gstate_set_hairline (cairo_gstate_t *gstate, cairo_bool_t set_hairline); + +cairo_private cairo_bool_t +_cairo_gstate_get_hairline (cairo_gstate_t *gstate); + +cairo_private cairo_status_t +_cairo_gstate_set_line_cap (cairo_gstate_t *gstate, cairo_line_cap_t line_cap); + +cairo_private cairo_line_cap_t +_cairo_gstate_get_line_cap (cairo_gstate_t *gstate); + +cairo_private cairo_status_t +_cairo_gstate_set_line_join (cairo_gstate_t *gstate, cairo_line_join_t line_join); + +cairo_private cairo_line_join_t +_cairo_gstate_get_line_join (cairo_gstate_t *gstate); + +cairo_private cairo_status_t +_cairo_gstate_set_dash (cairo_gstate_t *gstate, const double *dash, int num_dashes, double offset); + +cairo_private void +_cairo_gstate_get_dash (cairo_gstate_t *gstate, double *dash, int *num_dashes, double *offset); + +cairo_private cairo_status_t +_cairo_gstate_set_miter_limit (cairo_gstate_t *gstate, double limit); + +cairo_private double +_cairo_gstate_get_miter_limit (cairo_gstate_t *gstate); + +cairo_private void +_cairo_gstate_get_matrix (cairo_gstate_t *gstate, cairo_matrix_t *matrix); + +cairo_private cairo_status_t +_cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty); + +cairo_private cairo_status_t +_cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy); + +cairo_private cairo_status_t +_cairo_gstate_rotate (cairo_gstate_t *gstate, double angle); + +cairo_private cairo_status_t +_cairo_gstate_transform (cairo_gstate_t *gstate, + const cairo_matrix_t *matrix); + +cairo_private cairo_status_t +_cairo_gstate_set_matrix (cairo_gstate_t *gstate, + const cairo_matrix_t *matrix); + +cairo_private void +_cairo_gstate_identity_matrix (cairo_gstate_t *gstate); + +cairo_private void +_cairo_gstate_user_to_device (cairo_gstate_t *gstate, double *x, double *y); + +cairo_private void +_cairo_gstate_user_to_device_distance (cairo_gstate_t *gstate, double *dx, double *dy); + +cairo_private void +_cairo_gstate_device_to_user (cairo_gstate_t *gstate, double *x, double *y); + +cairo_private void +_cairo_gstate_device_to_user_distance (cairo_gstate_t *gstate, double *dx, double *dy); + +cairo_private void +_do_cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y); + +static inline void +_cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y) +{ + if (! gstate->is_identity) + _do_cairo_gstate_user_to_backend (gstate, x, y); +} + +cairo_private void +_do_cairo_gstate_user_to_backend_distance (cairo_gstate_t *gstate, double *x, double *y); + +static inline void +_cairo_gstate_user_to_backend_distance (cairo_gstate_t *gstate, double *x, double *y) +{ + if (! gstate->is_identity) + _do_cairo_gstate_user_to_backend_distance (gstate, x, y); +} + +cairo_private void +_do_cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y); + +static inline void +_cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y) +{ + if (! gstate->is_identity) + _do_cairo_gstate_backend_to_user (gstate, x, y); +} + +cairo_private void +_do_cairo_gstate_backend_to_user_distance (cairo_gstate_t *gstate, double *x, double *y); + +static inline void +_cairo_gstate_backend_to_user_distance (cairo_gstate_t *gstate, double *x, double *y) +{ + if (! gstate->is_identity) + _do_cairo_gstate_backend_to_user_distance (gstate, x, y); +} + +cairo_private void +_cairo_gstate_backend_to_user_rectangle (cairo_gstate_t *gstate, + double *x1, double *y1, + double *x2, double *y2, + cairo_bool_t *is_tight); + +cairo_private void +_cairo_gstate_path_extents (cairo_gstate_t *gstate, + cairo_path_fixed_t *path, + double *x1, double *y1, + double *x2, double *y2); + +cairo_private cairo_status_t +_cairo_gstate_paint (cairo_gstate_t *gstate); + +cairo_private cairo_status_t +_cairo_gstate_mask (cairo_gstate_t *gstate, + cairo_pattern_t *mask); + +cairo_private cairo_status_t +_cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path); + +cairo_private cairo_status_t +_cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path); + +cairo_private cairo_status_t +_cairo_gstate_copy_page (cairo_gstate_t *gstate); + +cairo_private cairo_status_t +_cairo_gstate_show_page (cairo_gstate_t *gstate); + +cairo_private cairo_status_t +_cairo_gstate_stroke_extents (cairo_gstate_t *gstate, + cairo_path_fixed_t *path, + double *x1, double *y1, + double *x2, double *y2); + +cairo_private cairo_status_t +_cairo_gstate_fill_extents (cairo_gstate_t *gstate, + cairo_path_fixed_t *path, + double *x1, double *y1, + double *x2, double *y2); + +cairo_private cairo_status_t +_cairo_gstate_in_stroke (cairo_gstate_t *gstate, + cairo_path_fixed_t *path, + double x, + double y, + cairo_bool_t *inside_ret); + +cairo_private cairo_bool_t +_cairo_gstate_in_fill (cairo_gstate_t *gstate, + cairo_path_fixed_t *path, + double x, + double y); + +cairo_private cairo_bool_t +_cairo_gstate_in_clip (cairo_gstate_t *gstate, + double x, + double y); + +cairo_private cairo_status_t +_cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path); + +cairo_private cairo_status_t +_cairo_gstate_reset_clip (cairo_gstate_t *gstate); + +cairo_private cairo_bool_t +_cairo_gstate_clip_extents (cairo_gstate_t *gstate, + double *x1, + double *y1, + double *x2, + double *y2); + +cairo_private cairo_rectangle_list_t* +_cairo_gstate_copy_clip_rectangle_list (cairo_gstate_t *gstate); + +cairo_private cairo_status_t +_cairo_gstate_show_surface (cairo_gstate_t *gstate, + cairo_surface_t *surface, + double x, + double y, + double width, + double height); + +cairo_private cairo_status_t +_cairo_gstate_tag_begin (cairo_gstate_t *gstate, + const char *tag_name, + const char *attributes); + +cairo_private cairo_status_t +_cairo_gstate_tag_end (cairo_gstate_t *gstate, + const char *tag_name); + +cairo_private cairo_status_t +_cairo_gstate_set_font_size (cairo_gstate_t *gstate, + double size); + +cairo_private void +_cairo_gstate_get_font_matrix (cairo_gstate_t *gstate, + cairo_matrix_t *matrix); + +cairo_private cairo_status_t +_cairo_gstate_set_font_matrix (cairo_gstate_t *gstate, + const cairo_matrix_t *matrix); + +cairo_private void +_cairo_gstate_get_font_options (cairo_gstate_t *gstate, + cairo_font_options_t *options); + +cairo_private void +_cairo_gstate_set_font_options (cairo_gstate_t *gstate, + const cairo_font_options_t *options); + +cairo_private cairo_status_t +_cairo_gstate_get_font_face (cairo_gstate_t *gstate, + cairo_font_face_t **font_face); + +cairo_private cairo_status_t +_cairo_gstate_get_scaled_font (cairo_gstate_t *gstate, + cairo_scaled_font_t **scaled_font); + +cairo_private cairo_status_t +_cairo_gstate_get_font_extents (cairo_gstate_t *gstate, + cairo_font_extents_t *extents); + +cairo_private cairo_status_t +_cairo_gstate_set_font_face (cairo_gstate_t *gstate, + cairo_font_face_t *font_face); + +cairo_private cairo_status_t +_cairo_gstate_glyph_extents (cairo_gstate_t *gstate, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_text_extents_t *extents); + +cairo_private cairo_status_t +_cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_glyph_text_info_t *info); + +cairo_private cairo_status_t +_cairo_gstate_glyph_path (cairo_gstate_t *gstate, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_path_fixed_t *path); + +cairo_private cairo_status_t +_cairo_gstate_set_antialias (cairo_gstate_t *gstate, + cairo_antialias_t antialias); + +cairo_private cairo_antialias_t +_cairo_gstate_get_antialias (cairo_gstate_t *gstate); + +#endif /* CAIRO_GSTATE_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-gstate.c b/local/recipes/libs/cairo/source/src/cairo-gstate.c new file mode 100644 index 0000000000..274a02a566 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-gstate.c @@ -0,0 +1,2409 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + */ + +#include "cairoint.h" + +#include "cairo-clip-inline.h" +#include "cairo-clip-private.h" +#include "cairo-error-private.h" +#include "cairo-list-inline.h" +#include "cairo-gstate-private.h" +#include "cairo-pattern-private.h" +#include "cairo-traps-private.h" + +static cairo_status_t +_cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other); + +static cairo_status_t +_cairo_gstate_ensure_font_face (cairo_gstate_t *gstate); + +static cairo_status_t +_cairo_gstate_ensure_scaled_font (cairo_gstate_t *gstate); + +static void +_cairo_gstate_unset_scaled_font (cairo_gstate_t *gstate); + +static void +_cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate, + const cairo_glyph_t *glyphs, + int num_glyphs, + const cairo_text_cluster_t *clusters, + int num_clusters, + cairo_text_cluster_flags_t cluster_flags, + cairo_glyph_t *transformed_glyphs, + int *num_transformed_glyphs, + cairo_text_cluster_t *transformed_clusters, + cairo_bool_t perform_early_clip); + +static void +_cairo_gstate_update_device_transform (cairo_observer_t *observer, + void *arg) +{ + cairo_gstate_t *gstate = cairo_container_of (observer, + cairo_gstate_t, + device_transform_observer); + + gstate->is_identity = (_cairo_matrix_is_identity (&gstate->ctm) && + _cairo_matrix_is_identity (&gstate->target->device_transform)); +} + +cairo_status_t +_cairo_gstate_init (cairo_gstate_t *gstate, + cairo_surface_t *target) +{ + VG (VALGRIND_MAKE_MEM_UNDEFINED (gstate, sizeof (cairo_gstate_t))); + + gstate->next = NULL; + + gstate->op = CAIRO_GSTATE_OPERATOR_DEFAULT; + gstate->opacity = 1.; + + gstate->tolerance = CAIRO_GSTATE_TOLERANCE_DEFAULT; + gstate->antialias = CAIRO_ANTIALIAS_DEFAULT; + + _cairo_stroke_style_init (&gstate->stroke_style); + + gstate->fill_rule = CAIRO_GSTATE_FILL_RULE_DEFAULT; + + gstate->font_face = NULL; + gstate->scaled_font = NULL; + gstate->previous_scaled_font = NULL; + + cairo_matrix_init_scale (&gstate->font_matrix, + CAIRO_GSTATE_DEFAULT_FONT_SIZE, + CAIRO_GSTATE_DEFAULT_FONT_SIZE); + + _cairo_font_options_init_default (&gstate->font_options); + + gstate->clip = NULL; + + gstate->target = cairo_surface_reference (target); + gstate->parent_target = NULL; + gstate->original_target = cairo_surface_reference (target); + + gstate->device_transform_observer.callback = _cairo_gstate_update_device_transform; + cairo_list_add (&gstate->device_transform_observer.link, + &gstate->target->device_transform_observers); + + gstate->is_identity = _cairo_matrix_is_identity (&gstate->target->device_transform); + cairo_matrix_init_identity (&gstate->ctm); + gstate->ctm_inverse = gstate->ctm; + gstate->source_ctm_inverse = gstate->ctm; + + gstate->source = (cairo_pattern_t *) &_cairo_pattern_black.base; + + /* Now that the gstate is fully initialized and ready for the eventual + * _cairo_gstate_fini(), we can check for errors (and not worry about + * the resource deallocation). */ + return target->status; +} + +/** + * _cairo_gstate_init_copy: + * + * Initialize @gstate by performing a deep copy of state fields from + * @other. Note that gstate->next is not copied but is set to %NULL by + * this function. + **/ +static cairo_status_t +_cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other) +{ + cairo_status_t status; + + VG (VALGRIND_MAKE_MEM_UNDEFINED (gstate, sizeof (cairo_gstate_t))); + + gstate->op = other->op; + gstate->opacity = other->opacity; + + gstate->tolerance = other->tolerance; + gstate->antialias = other->antialias; + + status = _cairo_stroke_style_init_copy (&gstate->stroke_style, + &other->stroke_style); + if (unlikely (status)) + return status; + + gstate->fill_rule = other->fill_rule; + + gstate->font_face = cairo_font_face_reference (other->font_face); + gstate->scaled_font = cairo_scaled_font_reference (other->scaled_font); + gstate->previous_scaled_font = cairo_scaled_font_reference (other->previous_scaled_font); + + gstate->font_matrix = other->font_matrix; + + _cairo_font_options_init_copy (&gstate->font_options , &other->font_options); + + gstate->clip = _cairo_clip_copy (other->clip); + + gstate->target = cairo_surface_reference (other->target); + /* parent_target is always set to NULL; it's only ever set by redirect_target */ + gstate->parent_target = NULL; + gstate->original_target = cairo_surface_reference (other->original_target); + + gstate->device_transform_observer.callback = _cairo_gstate_update_device_transform; + cairo_list_add (&gstate->device_transform_observer.link, + &gstate->target->device_transform_observers); + + gstate->is_identity = other->is_identity; + gstate->ctm = other->ctm; + gstate->ctm_inverse = other->ctm_inverse; + gstate->source_ctm_inverse = other->source_ctm_inverse; + + gstate->source = cairo_pattern_reference (other->source); + + gstate->next = NULL; + + return CAIRO_STATUS_SUCCESS; +} + +void +_cairo_gstate_fini (cairo_gstate_t *gstate) +{ + _cairo_stroke_style_fini (&gstate->stroke_style); + _cairo_font_options_fini (&gstate->font_options); + + cairo_font_face_destroy (gstate->font_face); + gstate->font_face = NULL; + + cairo_scaled_font_destroy (gstate->previous_scaled_font); + gstate->previous_scaled_font = NULL; + + cairo_scaled_font_destroy (gstate->scaled_font); + gstate->scaled_font = NULL; + + _cairo_clip_destroy (gstate->clip); + + cairo_list_del (&gstate->device_transform_observer.link); + + cairo_surface_destroy (gstate->target); + gstate->target = NULL; + + cairo_surface_destroy (gstate->parent_target); + gstate->parent_target = NULL; + + cairo_surface_destroy (gstate->original_target); + gstate->original_target = NULL; + + cairo_pattern_destroy (gstate->source); + gstate->source = NULL; + + VG (VALGRIND_MAKE_MEM_UNDEFINED (gstate, sizeof (cairo_gstate_t))); +} + +/** + * _cairo_gstate_save: + * @gstate: input/output gstate pointer + * + * Makes a copy of the current state of @gstate and saves it + * to @gstate->next, then put the address of the newly allcated + * copy into @gstate. _cairo_gstate_restore() reverses this. + **/ +cairo_status_t +_cairo_gstate_save (cairo_gstate_t **gstate, cairo_gstate_t **freelist) +{ + cairo_gstate_t *top; + cairo_status_t status; + + if (CAIRO_INJECT_FAULT ()) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + top = *freelist; + if (top == NULL) { + top = _cairo_calloc (sizeof (cairo_gstate_t)); + if (unlikely (top == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } else + *freelist = top->next; + + status = _cairo_gstate_init_copy (top, *gstate); + if (unlikely (status)) { + top->next = *freelist; + *freelist = top; + return status; + } + + top->next = *gstate; + *gstate = top; + + return CAIRO_STATUS_SUCCESS; +} + +/** + * _cairo_gstate_restore: + * @gstate: input/output gstate pointer + * + * Reverses the effects of one _cairo_gstate_save() call. + **/ +cairo_status_t +_cairo_gstate_restore (cairo_gstate_t **gstate, cairo_gstate_t **freelist) +{ + cairo_gstate_t *top; + + top = *gstate; + if (top->next == NULL) + return _cairo_error (CAIRO_STATUS_INVALID_RESTORE); + + *gstate = top->next; + + _cairo_gstate_fini (top); + VG (VALGRIND_MAKE_MEM_UNDEFINED (&top->next, sizeof (cairo_gstate_t *))); + top->next = *freelist; + *freelist = top; + + return CAIRO_STATUS_SUCCESS; +} + +/** + * _cairo_gstate_redirect_target: + * @gstate: a #cairo_gstate_t + * @child: the new child target + * + * Redirect @gstate rendering to a "child" target. The original + * "parent" target with which the gstate was created will not be + * affected. See _cairo_gstate_get_target(). + **/ +cairo_status_t +_cairo_gstate_redirect_target (cairo_gstate_t *gstate, cairo_surface_t *child) +{ + /* If this gstate is already redirected, this is an error; we need a + * new gstate to be able to redirect */ + assert (gstate->parent_target == NULL); + + /* Set up our new parent_target based on our current target; + * gstate->parent_target will take the ref that is held by gstate->target + */ + gstate->parent_target = gstate->target; + + /* Now set up our new target; we overwrite gstate->target directly, + * since its ref is now owned by gstate->parent_target */ + gstate->target = cairo_surface_reference (child); + gstate->is_identity &= _cairo_matrix_is_identity (&child->device_transform); + cairo_list_move (&gstate->device_transform_observer.link, + &gstate->target->device_transform_observers); + + /* The clip is in surface backend coordinates for the previous target; + * translate it into the child's backend coordinates. */ + _cairo_clip_destroy (gstate->clip); + gstate->clip = _cairo_clip_copy_with_translation (gstate->next->clip, + child->device_transform.x0 - gstate->parent_target->device_transform.x0, + child->device_transform.y0 - gstate->parent_target->device_transform.y0); + + return CAIRO_STATUS_SUCCESS; +} + +/** + * _cairo_gstate_is_group: + * @gstate: a #cairo_gstate_t + * + * Check if _cairo_gstate_redirect_target has been called on the head + * of the stack. + * + * Return value: %TRUE if @gstate is redirected to a target different + * than the previous state in the stack, %FALSE otherwise. + **/ +cairo_bool_t +_cairo_gstate_is_group (cairo_gstate_t *gstate) +{ + return gstate->parent_target != NULL; +} + +/** + * _cairo_gstate_get_target: + * @gstate: a #cairo_gstate_t + * + * Return the current drawing target; if drawing is not redirected, + * this will be the same as _cairo_gstate_get_original_target(). + * + * Return value: the current target surface + **/ +cairo_surface_t * +_cairo_gstate_get_target (cairo_gstate_t *gstate) +{ + return gstate->target; +} + +/** + * _cairo_gstate_get_original_target: + * @gstate: a #cairo_gstate_t + * + * Return the original target with which @gstate was created. This + * function always returns the original target independent of any + * child target that may have been set with + * _cairo_gstate_redirect_target. + * + * Return value: the original target surface + **/ +cairo_surface_t * +_cairo_gstate_get_original_target (cairo_gstate_t *gstate) +{ + return gstate->original_target; +} + +/** + * _cairo_gstate_get_clip: + * @gstate: a #cairo_gstate_t + * + * This space left intentionally blank. + * + * Return value: a pointer to the gstate's #cairo_clip_t structure. + **/ +cairo_clip_t * +_cairo_gstate_get_clip (cairo_gstate_t *gstate) +{ + return gstate->clip; +} + +cairo_status_t +_cairo_gstate_set_source (cairo_gstate_t *gstate, + cairo_pattern_t *source) +{ + if (source->status) + return source->status; + + source = cairo_pattern_reference (source); + cairo_pattern_destroy (gstate->source); + gstate->source = source; + gstate->source_ctm_inverse = gstate->ctm_inverse; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_pattern_t * +_cairo_gstate_get_source (cairo_gstate_t *gstate) +{ + if (gstate->source == &_cairo_pattern_black.base) { + /* do not expose the static object to the user */ + gstate->source = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK); + } + + return gstate->source; +} + +cairo_status_t +_cairo_gstate_set_operator (cairo_gstate_t *gstate, cairo_operator_t op) +{ + gstate->op = op; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_operator_t +_cairo_gstate_get_operator (cairo_gstate_t *gstate) +{ + return gstate->op; +} + +cairo_status_t +_cairo_gstate_set_opacity (cairo_gstate_t *gstate, double op) +{ + gstate->opacity = op; + + return CAIRO_STATUS_SUCCESS; +} + +double +_cairo_gstate_get_opacity (cairo_gstate_t *gstate) +{ + return gstate->opacity; +} + +cairo_status_t +_cairo_gstate_set_tolerance (cairo_gstate_t *gstate, double tolerance) +{ + gstate->tolerance = tolerance; + + return CAIRO_STATUS_SUCCESS; +} + +double +_cairo_gstate_get_tolerance (cairo_gstate_t *gstate) +{ + return gstate->tolerance; +} + +cairo_status_t +_cairo_gstate_set_fill_rule (cairo_gstate_t *gstate, cairo_fill_rule_t fill_rule) +{ + gstate->fill_rule = fill_rule; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_fill_rule_t +_cairo_gstate_get_fill_rule (cairo_gstate_t *gstate) +{ + return gstate->fill_rule; +} + +cairo_status_t +_cairo_gstate_set_line_width (cairo_gstate_t *gstate, double width) +{ + if (gstate->stroke_style.is_hairline) + gstate->stroke_style.pre_hairline_line_width = width; + else + gstate->stroke_style.line_width = width; + + return CAIRO_STATUS_SUCCESS; +} + +double +_cairo_gstate_get_line_width (cairo_gstate_t *gstate) +{ + return gstate->stroke_style.line_width; +} + +cairo_status_t +_cairo_gstate_set_hairline (cairo_gstate_t *gstate, cairo_bool_t set_hairline) +{ + if (gstate->stroke_style.is_hairline != set_hairline) { + gstate->stroke_style.is_hairline = set_hairline; + + if (set_hairline) { + gstate->stroke_style.pre_hairline_line_width = gstate->stroke_style.line_width; + gstate->stroke_style.line_width = 0.0; + } else { + gstate->stroke_style.line_width = gstate->stroke_style.pre_hairline_line_width; + } + } + + return CAIRO_STATUS_SUCCESS; +} + +cairo_bool_t +_cairo_gstate_get_hairline (cairo_gstate_t *gstate) +{ + return gstate->stroke_style.is_hairline; +} + +cairo_status_t +_cairo_gstate_set_line_cap (cairo_gstate_t *gstate, cairo_line_cap_t line_cap) +{ + gstate->stroke_style.line_cap = line_cap; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_line_cap_t +_cairo_gstate_get_line_cap (cairo_gstate_t *gstate) +{ + return gstate->stroke_style.line_cap; +} + +cairo_status_t +_cairo_gstate_set_line_join (cairo_gstate_t *gstate, cairo_line_join_t line_join) +{ + gstate->stroke_style.line_join = line_join; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_line_join_t +_cairo_gstate_get_line_join (cairo_gstate_t *gstate) +{ + return gstate->stroke_style.line_join; +} + +cairo_status_t +_cairo_gstate_set_dash (cairo_gstate_t *gstate, const double *dash, int num_dashes, double offset) +{ + double dash_total, on_total, off_total; + int i, j; + + free (gstate->stroke_style.dash); + + gstate->stroke_style.num_dashes = num_dashes; + + if (gstate->stroke_style.num_dashes == 0) { + gstate->stroke_style.dash = NULL; + gstate->stroke_style.dash_offset = 0.0; + return CAIRO_STATUS_SUCCESS; + } + + gstate->stroke_style.dash = _cairo_malloc_ab (gstate->stroke_style.num_dashes, sizeof (double)); + if (unlikely (gstate->stroke_style.dash == NULL)) { + gstate->stroke_style.num_dashes = 0; + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + on_total = off_total = dash_total = 0.0; + for (i = j = 0; i < num_dashes; i++) { + if (dash[i] < 0) + return _cairo_error (CAIRO_STATUS_INVALID_DASH); + + if (dash[i] == 0 && i > 0 && i < num_dashes - 1) { + if (dash[++i] < 0) + return _cairo_error (CAIRO_STATUS_INVALID_DASH); + + gstate->stroke_style.dash[j-1] += dash[i]; + gstate->stroke_style.num_dashes -= 2; + } else + gstate->stroke_style.dash[j++] = dash[i]; + + if (dash[i]) { + dash_total += dash[i]; + if ((i & 1) == 0) + on_total += dash[i]; + else + off_total += dash[i]; + } + } + + if (dash_total == 0.0) + return _cairo_error (CAIRO_STATUS_INVALID_DASH); + + /* An odd dash value indicate symmetric repeating, so the total + * is twice as long. */ + if (gstate->stroke_style.num_dashes & 1) { + dash_total *= 2; + on_total += off_total; + } + + if (dash_total - on_total < CAIRO_FIXED_ERROR_DOUBLE) { + /* Degenerate dash -> solid line */ + free (gstate->stroke_style.dash); + gstate->stroke_style.dash = NULL; + gstate->stroke_style.num_dashes = 0; + gstate->stroke_style.dash_offset = 0.0; + return CAIRO_STATUS_SUCCESS; + } + + /* The dashing code doesn't like a negative offset or a big positive + * offset, so we compute an equivalent offset which is guaranteed to be + * positive and less than twice the pattern length. */ + offset = fmod (offset, dash_total); + if (offset < 0.0) + offset += dash_total; + if (offset <= 0.0) /* Take care of -0 */ + offset = 0.0; + gstate->stroke_style.dash_offset = offset; + + return CAIRO_STATUS_SUCCESS; +} + +void +_cairo_gstate_get_dash (cairo_gstate_t *gstate, + double *dashes, + int *num_dashes, + double *offset) +{ + if (dashes) { + memcpy (dashes, + gstate->stroke_style.dash, + sizeof (double) * gstate->stroke_style.num_dashes); + } + + if (num_dashes) + *num_dashes = gstate->stroke_style.num_dashes; + + if (offset) + *offset = gstate->stroke_style.dash_offset; +} + +cairo_status_t +_cairo_gstate_set_miter_limit (cairo_gstate_t *gstate, double limit) +{ + gstate->stroke_style.miter_limit = limit; + + return CAIRO_STATUS_SUCCESS; +} + +double +_cairo_gstate_get_miter_limit (cairo_gstate_t *gstate) +{ + return gstate->stroke_style.miter_limit; +} + +void +_cairo_gstate_get_matrix (cairo_gstate_t *gstate, cairo_matrix_t *matrix) +{ + *matrix = gstate->ctm; +} + +cairo_status_t +_cairo_gstate_translate (cairo_gstate_t *gstate, double tx, double ty) +{ + cairo_matrix_t tmp; + + if (! ISFINITE (tx) || ! ISFINITE (ty)) + return _cairo_error (CAIRO_STATUS_INVALID_MATRIX); + + _cairo_gstate_unset_scaled_font (gstate); + + cairo_matrix_init_translate (&tmp, tx, ty); + cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm); + gstate->is_identity = FALSE; + + /* paranoid check against gradual numerical instability */ + if (! _cairo_matrix_is_invertible (&gstate->ctm)) + return _cairo_error (CAIRO_STATUS_INVALID_MATRIX); + + cairo_matrix_init_translate (&tmp, -tx, -ty); + cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_scale (cairo_gstate_t *gstate, double sx, double sy) +{ + cairo_matrix_t tmp; + + if (sx * sy == 0.) /* either sx or sy is 0, or det == 0 due to underflow */ + return _cairo_error (CAIRO_STATUS_INVALID_MATRIX); + if (! ISFINITE (sx) || ! ISFINITE (sy)) + return _cairo_error (CAIRO_STATUS_INVALID_MATRIX); + + _cairo_gstate_unset_scaled_font (gstate); + + cairo_matrix_init_scale (&tmp, sx, sy); + cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm); + gstate->is_identity = FALSE; + + /* paranoid check against gradual numerical instability */ + if (! _cairo_matrix_is_invertible (&gstate->ctm)) + return _cairo_error (CAIRO_STATUS_INVALID_MATRIX); + + cairo_matrix_init_scale (&tmp, 1/sx, 1/sy); + cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_rotate (cairo_gstate_t *gstate, double angle) +{ + cairo_matrix_t tmp; + + if (angle == 0.) + return CAIRO_STATUS_SUCCESS; + + if (! ISFINITE (angle)) + return _cairo_error (CAIRO_STATUS_INVALID_MATRIX); + + _cairo_gstate_unset_scaled_font (gstate); + + cairo_matrix_init_rotate (&tmp, angle); + cairo_matrix_multiply (&gstate->ctm, &tmp, &gstate->ctm); + gstate->is_identity = FALSE; + + /* paranoid check against gradual numerical instability */ + if (! _cairo_matrix_is_invertible (&gstate->ctm)) + return _cairo_error (CAIRO_STATUS_INVALID_MATRIX); + + cairo_matrix_init_rotate (&tmp, -angle); + cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_transform (cairo_gstate_t *gstate, + const cairo_matrix_t *matrix) +{ + cairo_matrix_t tmp; + cairo_status_t status; + + if (! _cairo_matrix_is_invertible (matrix)) + return _cairo_error (CAIRO_STATUS_INVALID_MATRIX); + + if (_cairo_matrix_is_identity (matrix)) + return CAIRO_STATUS_SUCCESS; + + tmp = *matrix; + status = cairo_matrix_invert (&tmp); + if (unlikely (status)) + return status; + + _cairo_gstate_unset_scaled_font (gstate); + + cairo_matrix_multiply (&gstate->ctm, matrix, &gstate->ctm); + cairo_matrix_multiply (&gstate->ctm_inverse, &gstate->ctm_inverse, &tmp); + gstate->is_identity = FALSE; + + /* paranoid check against gradual numerical instability */ + if (! _cairo_matrix_is_invertible (&gstate->ctm)) + return _cairo_error (CAIRO_STATUS_INVALID_MATRIX); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_set_matrix (cairo_gstate_t *gstate, + const cairo_matrix_t *matrix) +{ + cairo_status_t status; + + if (memcmp (matrix, &gstate->ctm, sizeof (cairo_matrix_t)) == 0) + return CAIRO_STATUS_SUCCESS; + + if (! _cairo_matrix_is_invertible (matrix)) + return _cairo_error (CAIRO_STATUS_INVALID_MATRIX); + + if (_cairo_matrix_is_identity (matrix)) { + _cairo_gstate_identity_matrix (gstate); + return CAIRO_STATUS_SUCCESS; + } + + _cairo_gstate_unset_scaled_font (gstate); + + gstate->ctm = *matrix; + gstate->ctm_inverse = *matrix; + status = cairo_matrix_invert (&gstate->ctm_inverse); + assert (status == CAIRO_STATUS_SUCCESS); + gstate->is_identity = FALSE; + + return CAIRO_STATUS_SUCCESS; +} + +void +_cairo_gstate_identity_matrix (cairo_gstate_t *gstate) +{ + if (_cairo_matrix_is_identity (&gstate->ctm)) + return; + + _cairo_gstate_unset_scaled_font (gstate); + + cairo_matrix_init_identity (&gstate->ctm); + cairo_matrix_init_identity (&gstate->ctm_inverse); + gstate->is_identity = _cairo_matrix_is_identity (&gstate->target->device_transform); +} + +void +_cairo_gstate_user_to_device (cairo_gstate_t *gstate, double *x, double *y) +{ + cairo_matrix_transform_point (&gstate->ctm, x, y); +} + +void +_cairo_gstate_user_to_device_distance (cairo_gstate_t *gstate, + double *dx, double *dy) +{ + cairo_matrix_transform_distance (&gstate->ctm, dx, dy); +} + +void +_cairo_gstate_device_to_user (cairo_gstate_t *gstate, double *x, double *y) +{ + cairo_matrix_transform_point (&gstate->ctm_inverse, x, y); +} + +void +_cairo_gstate_device_to_user_distance (cairo_gstate_t *gstate, + double *dx, double *dy) +{ + cairo_matrix_transform_distance (&gstate->ctm_inverse, dx, dy); +} + +void +_do_cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y) +{ + cairo_matrix_transform_point (&gstate->ctm, x, y); + cairo_matrix_transform_point (&gstate->target->device_transform, x, y); +} + +void +_do_cairo_gstate_user_to_backend_distance (cairo_gstate_t *gstate, double *x, double *y) +{ + cairo_matrix_transform_distance (&gstate->ctm, x, y); + cairo_matrix_transform_distance (&gstate->target->device_transform, x, y); +} + +void +_do_cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y) +{ + cairo_matrix_transform_point (&gstate->target->device_transform_inverse, x, y); + cairo_matrix_transform_point (&gstate->ctm_inverse, x, y); +} + +void +_do_cairo_gstate_backend_to_user_distance (cairo_gstate_t *gstate, double *x, double *y) +{ + cairo_matrix_transform_distance (&gstate->target->device_transform_inverse, x, y); + cairo_matrix_transform_distance (&gstate->ctm_inverse, x, y); +} + +void +_cairo_gstate_backend_to_user_rectangle (cairo_gstate_t *gstate, + double *x1, double *y1, + double *x2, double *y2, + cairo_bool_t *is_tight) +{ + cairo_matrix_t matrix_inverse; + + if (! _cairo_matrix_is_identity (&gstate->target->device_transform_inverse) || + ! _cairo_matrix_is_identity (&gstate->ctm_inverse)) + { + cairo_matrix_multiply (&matrix_inverse, + &gstate->target->device_transform_inverse, + &gstate->ctm_inverse); + _cairo_matrix_transform_bounding_box (&matrix_inverse, + x1, y1, x2, y2, is_tight); + } + + else + { + if (is_tight) + *is_tight = TRUE; + } +} + +/* XXX: NYI +cairo_status_t +_cairo_gstate_stroke_to_path (cairo_gstate_t *gstate) +{ + cairo_status_t status; + + _cairo_pen_init (&gstate); + return CAIRO_STATUS_SUCCESS; +} +*/ + +void +_cairo_gstate_path_extents (cairo_gstate_t *gstate, + cairo_path_fixed_t *path, + double *x1, double *y1, + double *x2, double *y2) +{ + cairo_box_t box; + double px1, py1, px2, py2; + + if (_cairo_path_fixed_extents (path, &box)) { + px1 = _cairo_fixed_to_double (box.p1.x); + py1 = _cairo_fixed_to_double (box.p1.y); + px2 = _cairo_fixed_to_double (box.p2.x); + py2 = _cairo_fixed_to_double (box.p2.y); + + _cairo_gstate_backend_to_user_rectangle (gstate, + &px1, &py1, &px2, &py2, + NULL); + } else { + px1 = 0.0; + py1 = 0.0; + px2 = 0.0; + py2 = 0.0; + } + + if (x1) + *x1 = px1; + if (y1) + *y1 = py1; + if (x2) + *x2 = px2; + if (y2) + *y2 = py2; +} + +static void +_cairo_gstate_copy_pattern (cairo_pattern_t *pattern, + const cairo_pattern_t *original) +{ + /* First check if the we can replace the original with a much simpler + * pattern. For example, gradients that are uniform or just have a single + * stop can sometimes be replaced with a solid. + */ + + if (_cairo_pattern_is_clear (original)) { + _cairo_pattern_init_solid ((cairo_solid_pattern_t *) pattern, + CAIRO_COLOR_TRANSPARENT); + return; + } + + if (original->type == CAIRO_PATTERN_TYPE_LINEAR || + original->type == CAIRO_PATTERN_TYPE_RADIAL) + { + cairo_color_t color; + if (_cairo_gradient_pattern_is_solid ((cairo_gradient_pattern_t *) original, + NULL, + &color)) + { + _cairo_pattern_init_solid ((cairo_solid_pattern_t *) pattern, + &color); + return; + } + } + + _cairo_pattern_init_static_copy (pattern, original); +} + +static void +_cairo_gstate_copy_transformed_pattern (cairo_gstate_t *gstate, + cairo_pattern_t *pattern, + const cairo_pattern_t *original, + const cairo_matrix_t *ctm_inverse) +{ + /* + * What calculations below do can be described in pseudo-code (so using nonexistent fields) as (using column vectors): + * pattern->matrix = surface->device_transform * + * pattern->matrix * + * ctm_inverse * + * gstate->target->device_transform_inverse + * + * The inverse of which is: + * pattern->matrix_inverse = gstate->target->device_transform * + * ctm * + * pattern->matrix_inverse * + * surface->device_transform_inverse + */ + + _cairo_gstate_copy_pattern (pattern, original); + + if (original->type == CAIRO_PATTERN_TYPE_SURFACE) { + cairo_surface_pattern_t *surface_pattern; + cairo_surface_t *surface; + + surface_pattern = (cairo_surface_pattern_t *) original; + surface = surface_pattern->surface; + + if (_cairo_surface_has_device_transform (surface)) + _cairo_pattern_pretransform (pattern, &surface->device_transform); + } + + if (! _cairo_matrix_is_identity (ctm_inverse)) + _cairo_pattern_transform (pattern, ctm_inverse); + + if (_cairo_surface_has_device_transform (gstate->target)) { + _cairo_pattern_transform (pattern, + &gstate->target->device_transform_inverse); + } +} + +static void +_cairo_gstate_copy_transformed_source (cairo_gstate_t *gstate, + cairo_pattern_t *pattern) +{ + _cairo_gstate_copy_transformed_pattern (gstate, pattern, + gstate->source, + &gstate->source_ctm_inverse); +} + +static void +_cairo_gstate_copy_transformed_mask (cairo_gstate_t *gstate, + cairo_pattern_t *pattern, + cairo_pattern_t *mask) +{ + _cairo_gstate_copy_transformed_pattern (gstate, pattern, + mask, + &gstate->ctm_inverse); +} + +static cairo_operator_t +_reduce_op (cairo_gstate_t *gstate) +{ + cairo_operator_t op; + const cairo_pattern_t *pattern; + + op = gstate->op; + if (op != CAIRO_OPERATOR_SOURCE) + return op; + + pattern = gstate->source; + if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) { + const cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern; + if (solid->color.alpha_short <= 0x00ff) { + op = CAIRO_OPERATOR_CLEAR; + } else if ((gstate->target->content & CAIRO_CONTENT_ALPHA) == 0) { + if ((solid->color.red_short | + solid->color.green_short | + solid->color.blue_short) <= 0x00ff) + { + op = CAIRO_OPERATOR_CLEAR; + } + } + } else if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { + const cairo_surface_pattern_t *surface = (cairo_surface_pattern_t *) pattern; + if (surface->surface->is_clear && + surface->surface->content & CAIRO_CONTENT_ALPHA) + { + op = CAIRO_OPERATOR_CLEAR; + } + } else { + const cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *) pattern; + if (gradient->n_stops == 0) + op = CAIRO_OPERATOR_CLEAR; + } + + return op; +} + +static cairo_status_t +_cairo_gstate_get_pattern_status (const cairo_pattern_t *pattern) +{ + if (unlikely (pattern->type == CAIRO_PATTERN_TYPE_MESH && + ((const cairo_mesh_pattern_t *) pattern)->current_patch)) + { + /* If current patch != NULL, the pattern is under construction + * and cannot be used as a source */ + return CAIRO_STATUS_INVALID_MESH_CONSTRUCTION; + } + + return pattern->status; +} + +cairo_status_t +_cairo_gstate_paint (cairo_gstate_t *gstate) +{ + cairo_pattern_union_t source_pattern; + const cairo_pattern_t *pattern; + cairo_status_t status; + cairo_operator_t op; + + status = _cairo_gstate_get_pattern_status (gstate->source); + if (unlikely (status)) + return status; + + if (gstate->op == CAIRO_OPERATOR_DEST) + return CAIRO_STATUS_SUCCESS; + + if (_cairo_clip_is_all_clipped (gstate->clip)) + return CAIRO_STATUS_SUCCESS; + + op = _reduce_op (gstate); + if (op == CAIRO_OPERATOR_CLEAR) { + pattern = &_cairo_pattern_clear.base; + } else { + _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base); + pattern = &source_pattern.base; + } + + return _cairo_surface_paint (gstate->target, + op, pattern, + gstate->clip); +} + +cairo_status_t +_cairo_gstate_mask (cairo_gstate_t *gstate, + cairo_pattern_t *mask) +{ + cairo_pattern_union_t source_pattern, mask_pattern; + const cairo_pattern_t *source; + cairo_operator_t op; + cairo_status_t status; + + status = _cairo_gstate_get_pattern_status (mask); + if (unlikely (status)) + return status; + + status = _cairo_gstate_get_pattern_status (gstate->source); + if (unlikely (status)) + return status; + + if (gstate->op == CAIRO_OPERATOR_DEST) + return CAIRO_STATUS_SUCCESS; + + if (_cairo_clip_is_all_clipped (gstate->clip)) + return CAIRO_STATUS_SUCCESS; + + assert (gstate->opacity == 1.0); + + if (_cairo_pattern_is_opaque (mask, NULL)) + return _cairo_gstate_paint (gstate); + + if (_cairo_pattern_is_clear (mask) && + _cairo_operator_bounded_by_mask (gstate->op)) + { + return CAIRO_STATUS_SUCCESS; + } + + op = _reduce_op (gstate); + if (op == CAIRO_OPERATOR_CLEAR) { + source = &_cairo_pattern_clear.base; + } else { + _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base); + source = &source_pattern.base; + } + _cairo_gstate_copy_transformed_mask (gstate, &mask_pattern.base, mask); + + if (source->type == CAIRO_PATTERN_TYPE_SOLID && !source->is_foreground_marker && + mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID && + _cairo_operator_bounded_by_source (op)) + { + const cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source; + cairo_color_t combined; + + if (mask_pattern.base.has_component_alpha) { +#define M(R, A, B, c) R.c = A.c * B.c + M(combined, solid->color, mask_pattern.solid.color, red); + M(combined, solid->color, mask_pattern.solid.color, green); + M(combined, solid->color, mask_pattern.solid.color, blue); + M(combined, solid->color, mask_pattern.solid.color, alpha); +#undef M + } else { + combined = solid->color; + _cairo_color_multiply_alpha (&combined, mask_pattern.solid.color.alpha); + } + + _cairo_pattern_init_solid (&source_pattern.solid, &combined); + + status = _cairo_surface_paint (gstate->target, op, + &source_pattern.base, + gstate->clip); + } + else + { + status = _cairo_surface_mask (gstate->target, op, + source, + &mask_pattern.base, + gstate->clip); + } + + return status; +} + +cairo_status_t +_cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path) +{ + cairo_pattern_union_t source_pattern; + cairo_stroke_style_t style; + double dash[2]; + cairo_status_t status; + cairo_matrix_t aggregate_transform; + cairo_matrix_t aggregate_transform_inverse; + + status = _cairo_gstate_get_pattern_status (gstate->source); + if (unlikely (status)) + return status; + + if (gstate->op == CAIRO_OPERATOR_DEST) + return CAIRO_STATUS_SUCCESS; + + if (gstate->stroke_style.line_width <= 0.0 && !gstate->stroke_style.is_hairline) + return CAIRO_STATUS_SUCCESS; + + if (_cairo_clip_is_all_clipped (gstate->clip)) + return CAIRO_STATUS_SUCCESS; + + assert (gstate->opacity == 1.0); + + cairo_matrix_multiply (&aggregate_transform, + &gstate->ctm, + &gstate->target->device_transform); + cairo_matrix_multiply (&aggregate_transform_inverse, + &gstate->target->device_transform_inverse, + &gstate->ctm_inverse); + + memcpy (&style, &gstate->stroke_style, sizeof (gstate->stroke_style)); + if (_cairo_stroke_style_dash_can_approximate (&gstate->stroke_style, &aggregate_transform, gstate->tolerance)) { + style.dash = dash; + _cairo_stroke_style_dash_approximate (&gstate->stroke_style, &gstate->ctm, gstate->tolerance, + &style.dash_offset, + style.dash, + &style.num_dashes); + } + + _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base); + + return _cairo_surface_stroke (gstate->target, + gstate->op, + &source_pattern.base, + path, + &style, + &aggregate_transform, + &aggregate_transform_inverse, + gstate->tolerance, + gstate->antialias, + gstate->clip); +} + +cairo_status_t +_cairo_gstate_in_stroke (cairo_gstate_t *gstate, + cairo_path_fixed_t *path, + double x, + double y, + cairo_bool_t *inside_ret) +{ + cairo_status_t status; + cairo_rectangle_int_t extents; + cairo_box_t limit; + cairo_traps_t traps; + + if (gstate->stroke_style.line_width <= 0.0) { + *inside_ret = FALSE; + return CAIRO_STATUS_SUCCESS; + } + + _cairo_gstate_user_to_backend (gstate, &x, &y); + + /* Before we perform the expensive stroke analysis, + * check whether the point is within the extents of the path. + */ + _cairo_path_fixed_approximate_stroke_extents (path, + &gstate->stroke_style, + &gstate->ctm, + gstate->target->is_vector, + &extents); + if (x < extents.x || x > extents.x + extents.width || + y < extents.y || y > extents.y + extents.height) + { + *inside_ret = FALSE; + return CAIRO_STATUS_SUCCESS; + } + + limit.p1.x = _cairo_fixed_from_double (x) - 1; + limit.p1.y = _cairo_fixed_from_double (y) - 1; + limit.p2.x = limit.p1.x + 2; + limit.p2.y = limit.p1.y + 2; + + _cairo_traps_init (&traps); + _cairo_traps_limit (&traps, &limit, 1); + + status = _cairo_path_fixed_stroke_polygon_to_traps (path, + &gstate->stroke_style, + &gstate->ctm, + &gstate->ctm_inverse, + gstate->tolerance, + &traps); + if (unlikely (status)) + goto BAIL; + + *inside_ret = _cairo_traps_contain (&traps, x, y); + +BAIL: + _cairo_traps_fini (&traps); + + return status; +} + +cairo_status_t +_cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path) +{ + cairo_status_t status; + + status = _cairo_gstate_get_pattern_status (gstate->source); + if (unlikely (status)) + return status; + + if (gstate->op == CAIRO_OPERATOR_DEST) + return CAIRO_STATUS_SUCCESS; + + if (_cairo_clip_is_all_clipped (gstate->clip)) + return CAIRO_STATUS_SUCCESS; + + assert (gstate->opacity == 1.0); + + if (_cairo_path_fixed_fill_is_empty (path)) { + if (_cairo_operator_bounded_by_mask (gstate->op)) + return CAIRO_STATUS_SUCCESS; + + status = _cairo_surface_paint (gstate->target, + CAIRO_OPERATOR_CLEAR, + &_cairo_pattern_clear.base, + gstate->clip); + } else { + cairo_pattern_union_t source_pattern; + const cairo_pattern_t *pattern; + cairo_operator_t op; + cairo_rectangle_int_t extents; + cairo_box_t box; + + op = _reduce_op (gstate); + if (op == CAIRO_OPERATOR_CLEAR) { + pattern = &_cairo_pattern_clear.base; + } else { + _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base); + pattern = &source_pattern.base; + } + + /* Toolkits often paint the entire background with a fill */ + if (_cairo_surface_get_extents (gstate->target, &extents) && + _cairo_path_fixed_is_box (path, &box) && + box.p1.x <= _cairo_fixed_from_int (extents.x) && + box.p1.y <= _cairo_fixed_from_int (extents.y) && + box.p2.x >= _cairo_fixed_from_int (extents.x + extents.width) && + box.p2.y >= _cairo_fixed_from_int (extents.y + extents.height)) + { + status = _cairo_surface_paint (gstate->target, op, pattern, + gstate->clip); + } + else + { + status = _cairo_surface_fill (gstate->target, op, pattern, + path, + gstate->fill_rule, + gstate->tolerance, + gstate->antialias, + gstate->clip); + } + } + + return status; +} + +cairo_bool_t +_cairo_gstate_in_fill (cairo_gstate_t *gstate, + cairo_path_fixed_t *path, + double x, + double y) +{ + _cairo_gstate_user_to_backend (gstate, &x, &y); + + return _cairo_path_fixed_in_fill (path, + gstate->fill_rule, + gstate->tolerance, + x, y); +} + +cairo_bool_t +_cairo_gstate_in_clip (cairo_gstate_t *gstate, + double x, + double y) +{ + cairo_clip_t *clip = gstate->clip; + int i; + + if (_cairo_clip_is_all_clipped (clip)) + return FALSE; + + if (clip == NULL) + return TRUE; + + _cairo_gstate_user_to_backend (gstate, &x, &y); + + if (x < clip->extents.x || + x >= clip->extents.x + clip->extents.width || + y < clip->extents.y || + y >= clip->extents.y + clip->extents.height) + { + return FALSE; + } + + if (clip->num_boxes) { + int fx, fy; + + fx = _cairo_fixed_from_double (x); + fy = _cairo_fixed_from_double (y); + for (i = 0; i < clip->num_boxes; i++) { + if (fx >= clip->boxes[i].p1.x && fx <= clip->boxes[i].p2.x && + fy >= clip->boxes[i].p1.y && fy <= clip->boxes[i].p2.y) + break; + } + if (i == clip->num_boxes) + return FALSE; + } + + if (clip->path) { + cairo_clip_path_t *clip_path = clip->path; + do { + if (! _cairo_path_fixed_in_fill (&clip_path->path, + clip_path->fill_rule, + clip_path->tolerance, + x, y)) + return FALSE; + } while ((clip_path = clip_path->prev) != NULL); + } + + return TRUE; +} + +cairo_status_t +_cairo_gstate_copy_page (cairo_gstate_t *gstate) +{ + cairo_surface_copy_page (gstate->target); + return cairo_surface_status (gstate->target); +} + +cairo_status_t +_cairo_gstate_show_page (cairo_gstate_t *gstate) +{ + cairo_surface_show_page (gstate->target); + return cairo_surface_status (gstate->target); +} + +static void +_cairo_gstate_extents_to_user_rectangle (cairo_gstate_t *gstate, + const cairo_box_t *extents, + double *x1, double *y1, + double *x2, double *y2) +{ + double px1, py1, px2, py2; + + px1 = _cairo_fixed_to_double (extents->p1.x); + py1 = _cairo_fixed_to_double (extents->p1.y); + px2 = _cairo_fixed_to_double (extents->p2.x); + py2 = _cairo_fixed_to_double (extents->p2.y); + + _cairo_gstate_backend_to_user_rectangle (gstate, + &px1, &py1, &px2, &py2, + NULL); + if (x1) + *x1 = px1; + if (y1) + *y1 = py1; + if (x2) + *x2 = px2; + if (y2) + *y2 = py2; +} + +cairo_status_t +_cairo_gstate_stroke_extents (cairo_gstate_t *gstate, + cairo_path_fixed_t *path, + double *x1, double *y1, + double *x2, double *y2) +{ + cairo_int_status_t status; + cairo_box_t extents; + cairo_bool_t empty; + + if (x1) + *x1 = 0.0; + if (y1) + *y1 = 0.0; + if (x2) + *x2 = 0.0; + if (y2) + *y2 = 0.0; + + if (gstate->stroke_style.line_width <= 0.0) + return CAIRO_STATUS_SUCCESS; + + status = CAIRO_INT_STATUS_UNSUPPORTED; + if (_cairo_path_fixed_stroke_is_rectilinear (path)) { + cairo_boxes_t boxes; + + _cairo_boxes_init (&boxes); + status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path, + &gstate->stroke_style, + &gstate->ctm, + gstate->antialias, + &boxes); + empty = boxes.num_boxes == 0; + if (! empty) + _cairo_boxes_extents (&boxes, &extents); + _cairo_boxes_fini (&boxes); + } + + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + cairo_polygon_t polygon; + + _cairo_polygon_init (&polygon, NULL, 0); + status = _cairo_path_fixed_stroke_to_polygon (path, + &gstate->stroke_style, + &gstate->ctm, + &gstate->ctm_inverse, + gstate->tolerance, + &polygon); + empty = polygon.num_edges == 0; + if (! empty) + extents = polygon.extents; + _cairo_polygon_fini (&polygon); + } + if (! empty) { + _cairo_gstate_extents_to_user_rectangle (gstate, &extents, + x1, y1, x2, y2); + } + + return status; +} + +cairo_status_t +_cairo_gstate_fill_extents (cairo_gstate_t *gstate, + cairo_path_fixed_t *path, + double *x1, double *y1, + double *x2, double *y2) +{ + cairo_status_t status; + cairo_box_t extents; + cairo_bool_t empty; + + if (x1) + *x1 = 0.0; + if (y1) + *y1 = 0.0; + if (x2) + *x2 = 0.0; + if (y2) + *y2 = 0.0; + + if (_cairo_path_fixed_fill_is_empty (path)) + return CAIRO_STATUS_SUCCESS; + + if (_cairo_path_fixed_fill_is_rectilinear (path)) { + cairo_boxes_t boxes; + + _cairo_boxes_init (&boxes); + status = _cairo_path_fixed_fill_rectilinear_to_boxes (path, + gstate->fill_rule, + gstate->antialias, + &boxes); + empty = boxes.num_boxes == 0; + if (! empty) + _cairo_boxes_extents (&boxes, &extents); + + _cairo_boxes_fini (&boxes); + } else { + cairo_traps_t traps; + + _cairo_traps_init (&traps); + + status = _cairo_path_fixed_fill_to_traps (path, + gstate->fill_rule, + gstate->tolerance, + &traps); + empty = traps.num_traps == 0; + if (! empty) + _cairo_traps_extents (&traps, &extents); + + _cairo_traps_fini (&traps); + } + + if (! empty) { + _cairo_gstate_extents_to_user_rectangle (gstate, &extents, + x1, y1, x2, y2); + } + + return status; +} + +cairo_status_t +_cairo_gstate_reset_clip (cairo_gstate_t *gstate) +{ + _cairo_clip_destroy (gstate->clip); + gstate->clip = NULL; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path) +{ + gstate->clip = + _cairo_clip_intersect_path (gstate->clip, + path, + gstate->fill_rule, + gstate->tolerance, + gstate->antialias); + /* XXX */ + return CAIRO_STATUS_SUCCESS; +} + +static cairo_bool_t +_cairo_gstate_int_clip_extents (cairo_gstate_t *gstate, + cairo_rectangle_int_t *extents) +{ + cairo_bool_t is_bounded; + + is_bounded = _cairo_surface_get_extents (gstate->target, extents); + + if (gstate->clip) { + _cairo_rectangle_intersect (extents, + _cairo_clip_get_extents (gstate->clip)); + is_bounded = TRUE; + } + + return is_bounded; +} + +cairo_bool_t +_cairo_gstate_clip_extents (cairo_gstate_t *gstate, + double *x1, + double *y1, + double *x2, + double *y2) +{ + cairo_rectangle_int_t extents; + double px1, py1, px2, py2; + + if (! _cairo_gstate_int_clip_extents (gstate, &extents)) + return FALSE; + + px1 = extents.x; + py1 = extents.y; + px2 = extents.x + (int) extents.width; + py2 = extents.y + (int) extents.height; + + _cairo_gstate_backend_to_user_rectangle (gstate, + &px1, &py1, &px2, &py2, + NULL); + + if (x1) + *x1 = px1; + if (y1) + *y1 = py1; + if (x2) + *x2 = px2; + if (y2) + *y2 = py2; + + return TRUE; +} + +cairo_rectangle_list_t* +_cairo_gstate_copy_clip_rectangle_list (cairo_gstate_t *gstate) +{ + cairo_rectangle_int_t extents; + cairo_rectangle_list_t *list; + cairo_clip_t *clip; + + if (_cairo_surface_get_extents (gstate->target, &extents)) + clip = _cairo_clip_copy_intersect_rectangle (gstate->clip, &extents); + else + clip = gstate->clip; + + list = _cairo_clip_copy_rectangle_list (clip, gstate); + + if (clip != gstate->clip) + _cairo_clip_destroy (clip); + + return list; +} + +cairo_status_t +_cairo_gstate_tag_begin (cairo_gstate_t *gstate, + const char *tag_name, const char *attributes) +{ + return _cairo_surface_tag (gstate->target, + TRUE, /* begin */ + tag_name, + attributes ? attributes : ""); +} + +cairo_status_t +_cairo_gstate_tag_end (cairo_gstate_t *gstate, + const char *tag_name) +{ + return _cairo_surface_tag (gstate->target, + FALSE, /* begin */ + tag_name, + NULL); /* attributes */ +} + +static void +_cairo_gstate_unset_scaled_font (cairo_gstate_t *gstate) +{ + if (gstate->scaled_font == NULL) + return; + + if (gstate->previous_scaled_font != NULL) + cairo_scaled_font_destroy (gstate->previous_scaled_font); + + gstate->previous_scaled_font = gstate->scaled_font; + gstate->scaled_font = NULL; +} + +cairo_status_t +_cairo_gstate_set_font_size (cairo_gstate_t *gstate, + double size) +{ + _cairo_gstate_unset_scaled_font (gstate); + + cairo_matrix_init_scale (&gstate->font_matrix, size, size); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_set_font_matrix (cairo_gstate_t *gstate, + const cairo_matrix_t *matrix) +{ + if (memcmp (matrix, &gstate->font_matrix, sizeof (cairo_matrix_t)) == 0) + return CAIRO_STATUS_SUCCESS; + + _cairo_gstate_unset_scaled_font (gstate); + + gstate->font_matrix = *matrix; + + return CAIRO_STATUS_SUCCESS; +} + +void +_cairo_gstate_get_font_matrix (cairo_gstate_t *gstate, + cairo_matrix_t *matrix) +{ + *matrix = gstate->font_matrix; +} + +void +_cairo_gstate_set_font_options (cairo_gstate_t *gstate, + const cairo_font_options_t *options) +{ + if (_cairo_font_options_compare (options, &gstate->font_options)) + return; + + _cairo_gstate_unset_scaled_font (gstate); + + _cairo_font_options_fini (&gstate->font_options); + _cairo_font_options_init_copy (&gstate->font_options, options); +} + +void +_cairo_gstate_get_font_options (cairo_gstate_t *gstate, + cairo_font_options_t *options) +{ + _cairo_font_options_fini (options); + _cairo_font_options_init_copy (options, &gstate->font_options); +} + +cairo_status_t +_cairo_gstate_get_font_face (cairo_gstate_t *gstate, + cairo_font_face_t **font_face) +{ + cairo_status_t status; + + status = _cairo_gstate_ensure_font_face (gstate); + if (unlikely (status)) + return status; + + *font_face = gstate->font_face; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_get_scaled_font (cairo_gstate_t *gstate, + cairo_scaled_font_t **scaled_font) +{ + cairo_status_t status; + + status = _cairo_gstate_ensure_scaled_font (gstate); + if (unlikely (status)) + return status; + + *scaled_font = gstate->scaled_font; + + return CAIRO_STATUS_SUCCESS; +} + +/* + * Like everything else in this file, fonts involve Too Many Coordinate Spaces; + * it is easy to get confused about what's going on. + * + * The user's view + * --------------- + * + * Users ask for things in user space. When cairo starts, a user space unit + * is about 1/96 inch, which is similar to (but importantly different from) + * the normal "point" units most users think in terms of. When a user + * selects a font, its scale is set to "one user unit". The user can then + * independently scale the user coordinate system *or* the font matrix, in + * order to adjust the rendered size of the font. + * + * Metrics are returned in user space, whether they are obtained from + * the currently selected font in a #cairo_t or from a #cairo_scaled_font_t + * which is a font specialized to a particular scale matrix, CTM, and target + * surface. + * + * The font's view + * --------------- + * + * Fonts are designed and stored (in say .ttf files) in "font space", which + * describes an "EM Square" (a design tile) and has some abstract number + * such as 1000, 1024, or 2048 units per "EM". This is basically an + * uninteresting space for us, but we need to remember that it exists. + * + * Font resources (from libraries or operating systems) render themselves + * to a particular device. Since they do not want to make most programmers + * worry about the font design space, the scaling API is simplified to + * involve just telling the font the required pixel size of the EM square + * (that is, in device space). + * + * + * Cairo's gstate view + * ------------------- + * + * In addition to the CTM and CTM inverse, we keep a matrix in the gstate + * called the "font matrix" which describes the user's most recent + * font-scaling or font-transforming request. This is kept in terms of an + * abstract scale factor, composed with the CTM and used to set the font's + * pixel size. So if the user asks to "scale the font by 12", the matrix + * is: + * + * [ 12.0, 0.0, 0.0, 12.0, 0.0, 0.0 ] + * + * It is an affine matrix, like all cairo matrices, where its tx and ty + * components are used to "nudging" fonts around and are handled in gstate + * and then ignored by the "scaled-font" layer. + * + * In order to perform any action on a font, we must build an object + * called a #cairo_font_scale_t; this contains the central 2x2 matrix + * resulting from "font matrix * CTM" (sans the font matrix translation + * components as stated in the previous paragraph). + * + * We pass this to the font when making requests of it, which causes it to + * reply for a particular [user request, device] combination, under the CTM + * (to accommodate the "zoom in" == "bigger fonts" issue above). + * + * The other terms in our communication with the font are therefore in + * device space. When we ask it to perform text->glyph conversion, it will + * produce a glyph string in device space. Glyph vectors we pass to it for + * measuring or rendering should be in device space. The metrics which we + * get back from the font will be in device space. The contents of the + * global glyph image cache will be in device space. + * + * + * Cairo's public view + * ------------------- + * + * Since the values entering and leaving via public API calls are in user + * space, the gstate functions typically need to multiply arguments by the + * CTM (for user-input glyph vectors), and return values by the CTM inverse + * (for font responses such as metrics or glyph vectors). + * + */ + +static cairo_status_t +_cairo_gstate_ensure_font_face (cairo_gstate_t *gstate) +{ + cairo_font_face_t *font_face; + + if (gstate->font_face != NULL) + return gstate->font_face->status; + + + font_face = cairo_toy_font_face_create (CAIRO_FONT_FAMILY_DEFAULT, + CAIRO_FONT_SLANT_DEFAULT, + CAIRO_FONT_WEIGHT_DEFAULT); + if (font_face->status) + return font_face->status; + + gstate->font_face = font_face; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_gstate_ensure_scaled_font (cairo_gstate_t *gstate) +{ + cairo_status_t status; + cairo_font_options_t options; + cairo_scaled_font_t *scaled_font; + cairo_matrix_t font_ctm; + + if (gstate->scaled_font != NULL) + return gstate->scaled_font->status; + + status = _cairo_gstate_ensure_font_face (gstate); + if (unlikely (status)) + return status; + + cairo_surface_get_font_options (gstate->target, &options); + cairo_font_options_merge (&options, &gstate->font_options); + + cairo_matrix_multiply (&font_ctm, + &gstate->ctm, + &gstate->target->device_transform); + + scaled_font = cairo_scaled_font_create (gstate->font_face, + &gstate->font_matrix, + &font_ctm, + &options); + + _cairo_font_options_fini (&options); + + status = cairo_scaled_font_status (scaled_font); + if (unlikely (status)) + return status; + + gstate->scaled_font = scaled_font; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_get_font_extents (cairo_gstate_t *gstate, + cairo_font_extents_t *extents) +{ + cairo_status_t status = _cairo_gstate_ensure_scaled_font (gstate); + if (unlikely (status)) + return status; + + cairo_scaled_font_extents (gstate->scaled_font, extents); + + return cairo_scaled_font_status (gstate->scaled_font); +} + +cairo_status_t +_cairo_gstate_set_font_face (cairo_gstate_t *gstate, + cairo_font_face_t *font_face) +{ + if (font_face && font_face->status) + return _cairo_error (font_face->status); + + if (font_face == gstate->font_face) + return CAIRO_STATUS_SUCCESS; + + cairo_font_face_destroy (gstate->font_face); + gstate->font_face = cairo_font_face_reference (font_face); + + _cairo_gstate_unset_scaled_font (gstate); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_gstate_glyph_extents (cairo_gstate_t *gstate, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_text_extents_t *extents) +{ + cairo_status_t status; + + status = _cairo_gstate_ensure_scaled_font (gstate); + if (unlikely (status)) + return status; + + cairo_scaled_font_glyph_extents (gstate->scaled_font, + glyphs, num_glyphs, + extents); + + return cairo_scaled_font_status (gstate->scaled_font); +} + +cairo_status_t +_cairo_gstate_show_text_glyphs (cairo_gstate_t *gstate, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_glyph_text_info_t *info) +{ + cairo_glyph_t stack_transformed_glyphs[CAIRO_STACK_ARRAY_LENGTH (cairo_glyph_t)]; + cairo_text_cluster_t stack_transformed_clusters[CAIRO_STACK_ARRAY_LENGTH (cairo_text_cluster_t)]; + cairo_pattern_union_t source_pattern; + cairo_glyph_t *transformed_glyphs; + const cairo_pattern_t *pattern; + cairo_text_cluster_t *transformed_clusters; + cairo_operator_t op; + cairo_status_t status; + + status = _cairo_gstate_get_pattern_status (gstate->source); + if (unlikely (status)) + return status; + + if (gstate->op == CAIRO_OPERATOR_DEST) + return CAIRO_STATUS_SUCCESS; + + if (_cairo_clip_is_all_clipped (gstate->clip)) + return CAIRO_STATUS_SUCCESS; + + status = _cairo_gstate_ensure_scaled_font (gstate); + if (unlikely (status)) + return status; + + transformed_glyphs = stack_transformed_glyphs; + transformed_clusters = stack_transformed_clusters; + + if (num_glyphs > ARRAY_LENGTH (stack_transformed_glyphs)) { + transformed_glyphs = cairo_glyph_allocate (num_glyphs); + if (unlikely (transformed_glyphs == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + if (info != NULL) { + if (info->num_clusters > ARRAY_LENGTH (stack_transformed_clusters)) { + transformed_clusters = cairo_text_cluster_allocate (info->num_clusters); + if (unlikely (transformed_clusters == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CLEANUP_GLYPHS; + } + } + + _cairo_gstate_transform_glyphs_to_backend (gstate, + glyphs, num_glyphs, + info->clusters, + info->num_clusters, + info->cluster_flags, + transformed_glyphs, + &num_glyphs, + transformed_clusters, + TRUE); + } else { + _cairo_gstate_transform_glyphs_to_backend (gstate, + glyphs, num_glyphs, + NULL, 0, 0, + transformed_glyphs, + &num_glyphs, + NULL, + TRUE); + } + + if (num_glyphs == 0) + goto CLEANUP_GLYPHS; + + op = _reduce_op (gstate); + if (op == CAIRO_OPERATOR_CLEAR) { + pattern = &_cairo_pattern_clear.base; + } else { + _cairo_gstate_copy_transformed_source (gstate, &source_pattern.base); + pattern = &source_pattern.base; + } + + /* For really huge font sizes, we can just do path;fill instead of + * show_glyphs, as show_glyphs would put excess pressure on the cache, + * and moreover, not all components below us correctly handle huge font + * sizes. I wanted to set the limit at 256. But alas, seems like cairo's + * rasterizer is something like ten times slower than freetype's for huge + * sizes. So, no win just yet. For now, do it for insanely-huge sizes, + * just to make sure we don't make anyone unhappy. When we get a really + * fast rasterizer in cairo, we may want to readjust this. + * + * Needless to say, do this only if show_text_glyphs is not available. */ + if (cairo_surface_has_show_text_glyphs (gstate->target) || + _cairo_scaled_font_get_max_scale (gstate->scaled_font) <= 10240) + { + + if (info != NULL) { + status = _cairo_surface_show_text_glyphs (gstate->target, op, pattern, + info->utf8, info->utf8_len, + transformed_glyphs, num_glyphs, + transformed_clusters, info->num_clusters, + info->cluster_flags, + gstate->scaled_font, + gstate->clip); + } else { + status = _cairo_surface_show_text_glyphs (gstate->target, op, pattern, + NULL, 0, + transformed_glyphs, num_glyphs, + NULL, 0, 0, + gstate->scaled_font, + gstate->clip); + } + } + else + { + cairo_path_fixed_t path; + + _cairo_path_fixed_init (&path); + + status = _cairo_scaled_font_glyph_path (gstate->scaled_font, + transformed_glyphs, num_glyphs, + &path); + + if (status == CAIRO_STATUS_SUCCESS) { + status = _cairo_surface_fill (gstate->target, op, pattern, + &path, + CAIRO_FILL_RULE_WINDING, + gstate->tolerance, + gstate->scaled_font->options.antialias, + gstate->clip); + } + + _cairo_path_fixed_fini (&path); + } + +CLEANUP_GLYPHS: + if (transformed_glyphs != stack_transformed_glyphs) + cairo_glyph_free (transformed_glyphs); + if (transformed_clusters != stack_transformed_clusters) + cairo_text_cluster_free (transformed_clusters); + + return status; +} + +cairo_status_t +_cairo_gstate_glyph_path (cairo_gstate_t *gstate, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_path_fixed_t *path) +{ + cairo_glyph_t stack_transformed_glyphs[CAIRO_STACK_ARRAY_LENGTH (cairo_glyph_t)]; + cairo_glyph_t *transformed_glyphs; + cairo_status_t status; + + status = _cairo_gstate_ensure_scaled_font (gstate); + if (unlikely (status)) + return status; + + if (num_glyphs < ARRAY_LENGTH (stack_transformed_glyphs)) { + transformed_glyphs = stack_transformed_glyphs; + } else { + transformed_glyphs = cairo_glyph_allocate (num_glyphs); + if (unlikely (transformed_glyphs == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + _cairo_gstate_transform_glyphs_to_backend (gstate, + glyphs, num_glyphs, + NULL, 0, 0, + transformed_glyphs, + &num_glyphs, NULL, FALSE); + + status = _cairo_scaled_font_glyph_path (gstate->scaled_font, + transformed_glyphs, num_glyphs, + path); + + if (transformed_glyphs != stack_transformed_glyphs) + cairo_glyph_free (transformed_glyphs); + + return status; +} + +cairo_status_t +_cairo_gstate_set_antialias (cairo_gstate_t *gstate, + cairo_antialias_t antialias) +{ + gstate->antialias = antialias; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_antialias_t +_cairo_gstate_get_antialias (cairo_gstate_t *gstate) +{ + return gstate->antialias; +} + +/** + * _cairo_gstate_transform_glyphs_to_backend: + * @gstate: a #cairo_gstate_t + * @glyphs: the array of #cairo_glyph_t objects to be transformed + * @num_glyphs: the number of elements in @glyphs + * @transformed_glyphs: a pre-allocated array of at least @num_glyphs + * #cairo_glyph_t objects + * @num_transformed_glyphs: the number of elements in @transformed_glyphs + * after dropping out of bounds glyphs, or %NULL if glyphs shouldn't be + * dropped + * + * Transform an array of glyphs to backend space by first adding the offset + * of the font matrix, then transforming from user space to backend space. + * The result of the transformation is placed in @transformed_glyphs. + * + * This also uses information from the scaled font and the surface to + * cull/drop glyphs that will not be visible. + **/ +static void +_cairo_gstate_transform_glyphs_to_backend (cairo_gstate_t *gstate, + const cairo_glyph_t *glyphs, + int num_glyphs, + const cairo_text_cluster_t *clusters, + int num_clusters, + cairo_text_cluster_flags_t cluster_flags, + cairo_glyph_t *transformed_glyphs, + int *num_transformed_glyphs, + cairo_text_cluster_t *transformed_clusters, + cairo_bool_t perform_early_clip) +{ + cairo_rectangle_int_t surface_extents; + cairo_matrix_t *ctm = &gstate->ctm; + cairo_matrix_t *font_matrix = &gstate->font_matrix; + cairo_matrix_t *device_transform = &gstate->target->device_transform; + cairo_bool_t drop = FALSE; + double x1 = 0, x2 = 0, y1 = 0, y2 = 0; + int i, j, k; + + drop = TRUE; + if (!perform_early_clip || !_cairo_gstate_int_clip_extents (gstate, &surface_extents)) { + drop = FALSE; /* unbounded surface */ + } else { + double scale10 = 10 * _cairo_scaled_font_get_max_scale (gstate->scaled_font); + if (surface_extents.width == 0 || surface_extents.height == 0) { + /* No visible area. Don't draw anything */ + *num_transformed_glyphs = 0; + return; + } + /* XXX We currently drop any glyphs that have their position outside + * of the surface boundaries by a safety margin depending on the + * font scale. This however can fail in extreme cases where the + * font has really long swashes for example... We can correctly + * handle that by looking the glyph up and using its device bbox + * to device if it's going to be visible, but I'm not inclined to + * do that now. + */ + x1 = surface_extents.x - scale10; + y1 = surface_extents.y - scale10; + x2 = surface_extents.x + (int) surface_extents.width + scale10; + y2 = surface_extents.y + (int) surface_extents.height + scale10; + } + + if (!drop) + *num_transformed_glyphs = num_glyphs; + +#define KEEP_GLYPH(glyph) (x1 <= glyph.x && glyph.x <= x2 && y1 <= glyph.y && glyph.y <= y2) + + j = 0; + if (_cairo_matrix_is_identity (ctm) && + _cairo_matrix_is_identity (device_transform) && + font_matrix->x0 == 0 && font_matrix->y0 == 0) + { + if (! drop) { + memcpy (transformed_glyphs, glyphs, + num_glyphs * sizeof (cairo_glyph_t)); + memcpy (transformed_clusters, clusters, + num_clusters * sizeof (cairo_text_cluster_t)); + j = num_glyphs; + } else if (num_clusters == 0) { + for (i = 0; i < num_glyphs; i++) { + transformed_glyphs[j].index = glyphs[i].index; + transformed_glyphs[j].x = glyphs[i].x; + transformed_glyphs[j].y = glyphs[i].y; + if (KEEP_GLYPH (transformed_glyphs[j])) + j++; + } + } else { + const cairo_glyph_t *cur_glyph; + + if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD) + cur_glyph = glyphs + num_glyphs - 1; + else + cur_glyph = glyphs; + + for (i = 0; i < num_clusters; i++) { + cairo_bool_t cluster_visible = FALSE; + + for (k = 0; k < clusters[i].num_glyphs; k++) { + transformed_glyphs[j+k].index = cur_glyph->index; + transformed_glyphs[j+k].x = cur_glyph->x; + transformed_glyphs[j+k].y = cur_glyph->y; + if (KEEP_GLYPH (transformed_glyphs[j+k])) + cluster_visible = TRUE; + + if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD) + cur_glyph--; + else + cur_glyph++; + } + + transformed_clusters[i] = clusters[i]; + if (cluster_visible) + j += k; + else + transformed_clusters[i].num_glyphs = 0; + } + } + } + else if (_cairo_matrix_is_translation (ctm) && + _cairo_matrix_is_translation (device_transform)) + { + double tx = font_matrix->x0 + ctm->x0 + device_transform->x0; + double ty = font_matrix->y0 + ctm->y0 + device_transform->y0; + + if (! drop || num_clusters == 0) { + for (i = 0; i < num_glyphs; i++) { + transformed_glyphs[j].index = glyphs[i].index; + transformed_glyphs[j].x = glyphs[i].x + tx; + transformed_glyphs[j].y = glyphs[i].y + ty; + if (!drop || KEEP_GLYPH (transformed_glyphs[j])) + j++; + } + memcpy (transformed_clusters, clusters, + num_clusters * sizeof (cairo_text_cluster_t)); + } else { + const cairo_glyph_t *cur_glyph; + + if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD) + cur_glyph = glyphs + num_glyphs - 1; + else + cur_glyph = glyphs; + + for (i = 0; i < num_clusters; i++) { + cairo_bool_t cluster_visible = FALSE; + + for (k = 0; k < clusters[i].num_glyphs; k++) { + transformed_glyphs[j+k].index = cur_glyph->index; + transformed_glyphs[j+k].x = cur_glyph->x + tx; + transformed_glyphs[j+k].y = cur_glyph->y + ty; + if (KEEP_GLYPH (transformed_glyphs[j+k])) + cluster_visible = TRUE; + + if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD) + cur_glyph--; + else + cur_glyph++; + } + + transformed_clusters[i] = clusters[i]; + if (cluster_visible) + j += k; + else + transformed_clusters[i].num_glyphs = 0; + } + } + } + else + { + cairo_matrix_t aggregate_transform; + + cairo_matrix_init_translate (&aggregate_transform, + gstate->font_matrix.x0, + gstate->font_matrix.y0); + cairo_matrix_multiply (&aggregate_transform, + &aggregate_transform, ctm); + cairo_matrix_multiply (&aggregate_transform, + &aggregate_transform, device_transform); + + if (! drop || num_clusters == 0) { + for (i = 0; i < num_glyphs; i++) { + transformed_glyphs[j] = glyphs[i]; + cairo_matrix_transform_point (&aggregate_transform, + &transformed_glyphs[j].x, + &transformed_glyphs[j].y); + if (! drop || KEEP_GLYPH (transformed_glyphs[j])) + j++; + } + memcpy (transformed_clusters, clusters, + num_clusters * sizeof (cairo_text_cluster_t)); + } else { + const cairo_glyph_t *cur_glyph; + + if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD) + cur_glyph = glyphs + num_glyphs - 1; + else + cur_glyph = glyphs; + + for (i = 0; i < num_clusters; i++) { + cairo_bool_t cluster_visible = FALSE; + for (k = 0; k < clusters[i].num_glyphs; k++) { + transformed_glyphs[j+k] = *cur_glyph; + cairo_matrix_transform_point (&aggregate_transform, + &transformed_glyphs[j+k].x, + &transformed_glyphs[j+k].y); + if (KEEP_GLYPH (transformed_glyphs[j+k])) + cluster_visible = TRUE; + + if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD) + cur_glyph--; + else + cur_glyph++; + } + + transformed_clusters[i] = clusters[i]; + if (cluster_visible) + j += k; + else + transformed_clusters[i].num_glyphs = 0; + } + } + } + *num_transformed_glyphs = j; + + if (num_clusters != 0 && cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD) { + for (i = 0; i < --j; i++) { + cairo_glyph_t tmp; + + tmp = transformed_glyphs[i]; + transformed_glyphs[i] = transformed_glyphs[j]; + transformed_glyphs[j] = tmp; + } + } +} diff --git a/local/recipes/libs/cairo/source/src/cairo-hash-private.h b/local/recipes/libs/cairo/source/src/cairo-hash-private.h new file mode 100644 index 0000000000..30e51ffe66 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-hash-private.h @@ -0,0 +1,87 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2004 Red Hat, Inc. + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Keith Packard + * Graydon Hoare + * Carl Worth + */ + +#ifndef CAIRO_HASH_PRIVATE_H +#define CAIRO_HASH_PRIVATE_H + +#include "cairo-compiler-private.h" +#include "cairo-types-private.h" + +/* XXX: I'd like this file to be self-contained in terms of + * includeability, but that's not really possible with the current + * monolithic cairoint.h. So, for now, just include cairoint.h instead + * if you want to include this file. */ + +typedef cairo_bool_t +(*cairo_hash_keys_equal_func_t) (const void *key_a, const void *key_b); + +typedef cairo_bool_t +(*cairo_hash_predicate_func_t) (const void *entry); + +typedef void +(*cairo_hash_callback_func_t) (void *entry, + void *closure); + +cairo_private cairo_hash_table_t * +_cairo_hash_table_create (cairo_hash_keys_equal_func_t keys_equal); + +cairo_private void +_cairo_hash_table_destroy (cairo_hash_table_t *hash_table); + +cairo_private void * +_cairo_hash_table_lookup (cairo_hash_table_t *hash_table, + cairo_hash_entry_t *key); + +cairo_private void * +_cairo_hash_table_random_entry (cairo_hash_table_t *hash_table, + cairo_hash_predicate_func_t predicate); + +cairo_private cairo_status_t +_cairo_hash_table_insert (cairo_hash_table_t *hash_table, + cairo_hash_entry_t *entry); + +cairo_private void +_cairo_hash_table_remove (cairo_hash_table_t *hash_table, + cairo_hash_entry_t *key); + +cairo_private void +_cairo_hash_table_foreach (cairo_hash_table_t *hash_table, + cairo_hash_callback_func_t hash_callback, + void *closure); + +#endif diff --git a/local/recipes/libs/cairo/source/src/cairo-hash.c b/local/recipes/libs/cairo/source/src/cairo-hash.c new file mode 100644 index 0000000000..6aba636cfc --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-hash.c @@ -0,0 +1,578 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2004 Red Hat, Inc. + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Keith Packard + * Graydon Hoare + * Carl Worth + */ + +#include "cairoint.h" +#include "cairo-error-private.h" + +/* + * An entry can be in one of three states: + * + * FREE: Entry has never been used, terminates all searches. + * Appears in the table as a %NULL pointer. + * + * DEAD: Entry had been live in the past. A dead entry can be reused + * but does not terminate a search for an exact entry. + * Appears in the table as a pointer to DEAD_ENTRY. + * + * LIVE: Entry is currently being used. + * Appears in the table as any non-%NULL, non-DEAD_ENTRY pointer. + */ + +#define DEAD_ENTRY ((cairo_hash_entry_t *) 0x1) + +#define ENTRY_IS_FREE(entry) ((entry) == NULL) +#define ENTRY_IS_DEAD(entry) ((entry) == DEAD_ENTRY) +#define ENTRY_IS_LIVE(entry) ((entry) > DEAD_ENTRY) + +/* + * This table is open-addressed with double hashing. Each table size + * is a prime and it makes for the "first" hash modulus; a second + * prime (2 less than the first prime) serves as the "second" hash + * modulus, which is smaller and thus guarantees a complete + * permutation of table indices. + * + * Hash tables are rehashed in order to keep between 12.5% and 50% + * entries in the hash table alive and at least 25% free. When table + * size is changed, the new table has about 25% live elements. + * + * The free entries guarantee an expected constant-time lookup. + * Doubling/halving the table in the described fashion guarantees + * amortized O(1) insertion/removal. + * + * This structure, and accompanying table, is borrowed/modified from the + * file xserver/render/glyph.c in the freedesktop.org x server, with + * permission (and suggested modification of doubling sizes) by Keith + * Packard. + */ + +static const unsigned long hash_table_sizes[] = { + 43, + 73, + 151, + 283, + 571, + 1153, + 2269, + 4519, + 9013, + 18043, + 36109, + 72091, + 144409, + 288361, + 576883, + 1153459, + 2307163, + 4613893, + 9227641, + 18455029, + 36911011, + 73819861, + 147639589, + 295279081, + 590559793 +}; + +struct _cairo_hash_table { + cairo_hash_keys_equal_func_t keys_equal; + + cairo_hash_entry_t *cache[32]; + + const unsigned long *table_size; + cairo_hash_entry_t **entries; + + unsigned long live_entries; + unsigned long free_entries; + unsigned long iterating; /* Iterating, no insert, no resize */ +}; + +/** + * _cairo_hash_table_uid_keys_equal: + * @key_a: the first key to be compared + * @key_b: the second key to be compared + * + * Provides a #cairo_hash_keys_equal_func_t which always returns + * %TRUE. This is useful to create hash tables using keys whose hash + * completely describes the key, because in this special case + * comparing the hashes is sufficient to guarantee that the keys are + * equal. + * + * Return value: %TRUE. + **/ +static cairo_bool_t +_cairo_hash_table_uid_keys_equal (const void *key_a, const void *key_b) +{ + return TRUE; +} + +/** + * _cairo_hash_table_create: + * @keys_equal: a function to return %TRUE if two keys are equal + * + * Creates a new hash table which will use the keys_equal() function + * to compare hash keys. Data is provided to the hash table in the + * form of user-derived versions of #cairo_hash_entry_t. A hash entry + * must be able to hold both a key (including a hash code) and a + * value. Sometimes only the key will be necessary, (as in + * _cairo_hash_table_remove), and other times both a key and a value + * will be necessary, (as in _cairo_hash_table_insert). + * + * If @keys_equal is %NULL, two keys will be considered equal if and + * only if their hashes are equal. + * + * See #cairo_hash_entry_t for more details. + * + * Return value: the new hash table or %NULL if out of memory. + **/ +cairo_hash_table_t * +_cairo_hash_table_create (cairo_hash_keys_equal_func_t keys_equal) +{ + cairo_hash_table_t *hash_table; + + hash_table = _cairo_calloc (sizeof (cairo_hash_table_t)); + if (unlikely (hash_table == NULL)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return NULL; + } + + if (keys_equal == NULL) + hash_table->keys_equal = _cairo_hash_table_uid_keys_equal; + else + hash_table->keys_equal = keys_equal; + + memset (&hash_table->cache, 0, sizeof (hash_table->cache)); + hash_table->table_size = &hash_table_sizes[0]; + + hash_table->entries = _cairo_calloc_ab (*hash_table->table_size, + sizeof (cairo_hash_entry_t *)); + if (unlikely (hash_table->entries == NULL)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + free (hash_table); + return NULL; + } + + hash_table->live_entries = 0; + hash_table->free_entries = *hash_table->table_size; + hash_table->iterating = 0; + + return hash_table; +} + +/** + * _cairo_hash_table_destroy: + * @hash_table: an empty hash table to destroy + * + * Immediately destroys the given hash table, freeing all resources + * associated with it. + * + * WARNING: The hash_table must have no live entries in it before + * _cairo_hash_table_destroy is called. It is a fatal error otherwise, + * and this function will halt. The rationale for this behavior is to + * avoid memory leaks and to avoid needless complication of the API + * with destroy notify callbacks. + * + * WARNING: The hash_table must have no running iterators in it when + * _cairo_hash_table_destroy is called. It is a fatal error otherwise, + * and this function will halt. + **/ +void +_cairo_hash_table_destroy (cairo_hash_table_t *hash_table) +{ + /* The hash table must be empty. Otherwise, halt. */ + assert (hash_table->live_entries == 0); + /* No iterators can be running. Otherwise, halt. */ + assert (hash_table->iterating == 0); + + free (hash_table->entries); + free (hash_table); +} + +static cairo_hash_entry_t ** +_cairo_hash_table_lookup_unique_key (cairo_hash_table_t *hash_table, + cairo_hash_entry_t *key) +{ + unsigned long table_size, i, idx, step; + cairo_hash_entry_t **entry; + + table_size = *hash_table->table_size; + idx = key->hash % table_size; + + entry = &hash_table->entries[idx]; + if (! ENTRY_IS_LIVE (*entry)) + return entry; + + i = 1; + step = 1 + key->hash % (table_size - 2); + do { + idx += step; + if (idx >= table_size) + idx -= table_size; + + entry = &hash_table->entries[idx]; + if (! ENTRY_IS_LIVE (*entry)) + return entry; + } while (++i < table_size); + + ASSERT_NOT_REACHED; + return NULL; +} + +/** + * _cairo_hash_table_manage: + * @hash_table: a hash table + * + * Resize the hash table if the number of entries has gotten much + * bigger or smaller than the ideal number of entries for the current + * size and guarantee some free entries to be used as lookup + * termination points. + * + * Return value: %CAIRO_STATUS_SUCCESS if successful or + * %CAIRO_STATUS_NO_MEMORY if out of memory. + **/ +static cairo_status_t +_cairo_hash_table_manage (cairo_hash_table_t *hash_table) +{ + cairo_hash_table_t tmp; + unsigned long new_size, i; + + /* Keep between 12.5% and 50% entries in the hash table alive and + * at least 25% free. */ + unsigned long live_high = *hash_table->table_size >> 1; + unsigned long live_low = live_high >> 2; + unsigned long free_low = live_high >> 1; + + tmp = *hash_table; + + if (hash_table->live_entries > live_high) + { + tmp.table_size = hash_table->table_size + 1; + /* This code is being abused if we can't make a table big enough. */ + assert (tmp.table_size - hash_table_sizes < + ARRAY_LENGTH (hash_table_sizes)); + } + else if (hash_table->live_entries < live_low) + { + /* Can't shrink if we're at the smallest size */ + if (hash_table->table_size == &hash_table_sizes[0]) + tmp.table_size = hash_table->table_size; + else + tmp.table_size = hash_table->table_size - 1; + } + + if (tmp.table_size == hash_table->table_size && + hash_table->free_entries > free_low) + { + /* The number of live entries is within the desired bounds + * (we're not going to resize the table) and we have enough + * free entries. Do nothing. */ + return CAIRO_STATUS_SUCCESS; + } + + new_size = *tmp.table_size; + tmp.entries = _cairo_calloc_ab (new_size, sizeof (cairo_hash_entry_t*)); + if (unlikely (tmp.entries == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + for (i = 0; i < *hash_table->table_size; ++i) { + if (ENTRY_IS_LIVE (hash_table->entries[i])) { + *_cairo_hash_table_lookup_unique_key (&tmp, hash_table->entries[i]) + = hash_table->entries[i]; + } + } + + free (hash_table->entries); + hash_table->entries = tmp.entries; + hash_table->table_size = tmp.table_size; + hash_table->free_entries = new_size - hash_table->live_entries; + + return CAIRO_STATUS_SUCCESS; +} + +/** + * _cairo_hash_table_lookup: + * @hash_table: a hash table + * @key: the key of interest + * + * Performs a lookup in @hash_table looking for an entry which has a + * key that matches @key, (as determined by the keys_equal() function + * passed to _cairo_hash_table_create). + * + * Return value: the matching entry, of %NULL if no match was found. + **/ +void * +_cairo_hash_table_lookup (cairo_hash_table_t *hash_table, + cairo_hash_entry_t *key) +{ + cairo_hash_entry_t *entry; + unsigned long table_size, i, idx, step; + uintptr_t hash = key->hash; + + entry = hash_table->cache[hash & 31]; + if (entry && entry->hash == hash && hash_table->keys_equal (key, entry)) + return entry; + + table_size = *hash_table->table_size; + idx = hash % table_size; + + entry = hash_table->entries[idx]; + if (ENTRY_IS_LIVE (entry)) { + if (entry->hash == hash && hash_table->keys_equal (key, entry)) + goto insert_cache; + } else if (ENTRY_IS_FREE (entry)) + return NULL; + + i = 1; + step = 1 + hash % (table_size - 2); + do { + idx += step; + if (idx >= table_size) + idx -= table_size; + + entry = hash_table->entries[idx]; + if (ENTRY_IS_LIVE (entry)) { + if (entry->hash == hash && hash_table->keys_equal (key, entry)) + goto insert_cache; + } else if (ENTRY_IS_FREE (entry)) + return NULL; + } while (++i < table_size); + + ASSERT_NOT_REACHED; + return NULL; + +insert_cache: + hash_table->cache[hash & 31] = entry; + return entry; +} + +/** + * _cairo_hash_table_random_entry: + * @hash_table: a hash table + * @predicate: a predicate function. + * + * Find a random entry in the hash table satisfying the given + * @predicate. + * + * We use the same algorithm as the lookup algorithm to walk over the + * entries in the hash table in a pseudo-random order. Walking + * linearly would favor entries following gaps in the hash table. We + * could also call rand() repeatedly, which works well for almost-full + * tables, but degrades when the table is almost empty, or predicate + * returns %TRUE for most entries. + * + * Return value: a random live entry or %NULL if there are no entries + * that match the given predicate. In particular, if predicate is + * %NULL, a %NULL return value indicates that the table is empty. + **/ +void * +_cairo_hash_table_random_entry (cairo_hash_table_t *hash_table, + cairo_hash_predicate_func_t predicate) +{ + cairo_hash_entry_t *entry; + unsigned long hash; + unsigned long table_size, i, idx, step; + + assert (predicate != NULL); + + table_size = *hash_table->table_size; + hash = rand (); + idx = hash % table_size; + + entry = hash_table->entries[idx]; + if (ENTRY_IS_LIVE (entry) && predicate (entry)) + return entry; + + i = 1; + step = 1 + hash % (table_size - 2); + do { + idx += step; + if (idx >= table_size) + idx -= table_size; + + entry = hash_table->entries[idx]; + if (ENTRY_IS_LIVE (entry) && predicate (entry)) + return entry; + } while (++i < table_size); + + return NULL; +} + +/** + * _cairo_hash_table_insert: + * @hash_table: a hash table + * @key_and_value: an entry to be inserted + * + * Insert the entry #key_and_value into the hash table. + * + * WARNING: There must not be an existing entry in the hash table + * with a matching key. + * + * WARNING: It is a fatal error to insert an element while + * an iterator is running + * + * Instead of using insert to replace an entry, consider just editing + * the entry obtained with _cairo_hash_table_lookup. Or if absolutely + * necessary, use _cairo_hash_table_remove first. + * + * Return value: %CAIRO_STATUS_SUCCESS if successful or + * %CAIRO_STATUS_NO_MEMORY if insufficient memory is available. + **/ +cairo_status_t +_cairo_hash_table_insert (cairo_hash_table_t *hash_table, + cairo_hash_entry_t *key_and_value) +{ + cairo_hash_entry_t **entry; + cairo_status_t status; + + /* Insert is illegal while an iterator is running. */ + assert (hash_table->iterating == 0); + + status = _cairo_hash_table_manage (hash_table); + if (unlikely (status)) + return status; + + entry = _cairo_hash_table_lookup_unique_key (hash_table, key_and_value); + + if (ENTRY_IS_FREE (*entry)) + hash_table->free_entries--; + + *entry = key_and_value; + hash_table->cache[key_and_value->hash & 31] = key_and_value; + hash_table->live_entries++; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_hash_entry_t ** +_cairo_hash_table_lookup_exact_key (cairo_hash_table_t *hash_table, + cairo_hash_entry_t *key) +{ + unsigned long table_size, i, idx, step; + cairo_hash_entry_t **entry; + + table_size = *hash_table->table_size; + idx = key->hash % table_size; + + entry = &hash_table->entries[idx]; + if (*entry == key) + return entry; + + i = 1; + step = 1 + key->hash % (table_size - 2); + do { + idx += step; + if (idx >= table_size) + idx -= table_size; + + entry = &hash_table->entries[idx]; + if (*entry == key) + return entry; + } while (++i < table_size); + + ASSERT_NOT_REACHED; + return NULL; +} +/** + * _cairo_hash_table_remove: + * @hash_table: a hash table + * @key: key of entry to be removed + * + * Remove an entry from the hash table which points to @key. + * + * Return value: %CAIRO_STATUS_SUCCESS if successful or + * %CAIRO_STATUS_NO_MEMORY if out of memory. + **/ +void +_cairo_hash_table_remove (cairo_hash_table_t *hash_table, + cairo_hash_entry_t *key) +{ + *_cairo_hash_table_lookup_exact_key (hash_table, key) = DEAD_ENTRY; + hash_table->live_entries--; + hash_table->cache[key->hash & 31] = NULL; + + /* Check for table resize. Don't do this when iterating as this will + * reorder elements of the table and cause the iteration to potentially + * skip some elements. */ + if (hash_table->iterating == 0) { + /* This call _can_ fail, but only in failing to allocate new + * memory to shrink the hash table. It does leave the table in a + * consistent state, and we've already succeeded in removing the + * entry, so we don't examine the failure status of this call. */ + _cairo_hash_table_manage (hash_table); + } +} + +/** + * _cairo_hash_table_foreach: + * @hash_table: a hash table + * @hash_callback: function to be called for each live entry + * @closure: additional argument to be passed to @hash_callback + * + * Call @hash_callback for each live entry in the hash table, in a + * non-specified order. + * + * Entries in @hash_table may be removed by code executed from @hash_callback. + * + * Entries may not be inserted to @hash_table, nor may @hash_table + * be destroyed by code executed from @hash_callback. The relevant + * functions will halt in these cases. + **/ +void +_cairo_hash_table_foreach (cairo_hash_table_t *hash_table, + cairo_hash_callback_func_t hash_callback, + void *closure) +{ + unsigned long i; + cairo_hash_entry_t *entry; + + /* Mark the table for iteration */ + ++hash_table->iterating; + for (i = 0; i < *hash_table->table_size; i++) { + entry = hash_table->entries[i]; + if (ENTRY_IS_LIVE(entry)) + hash_callback (entry, closure); + } + /* If some elements were deleted during the iteration, + * the table may need resizing. Just do this every time + * as the check is inexpensive. + */ + if (--hash_table->iterating == 0) { + /* Should we fail to shrink the hash table, it is left unaltered, + * and we don't need to propagate the error status. */ + _cairo_hash_table_manage (hash_table); + } +} diff --git a/local/recipes/libs/cairo/source/src/cairo-hull.c b/local/recipes/libs/cairo/source/src/cairo-hull.c new file mode 100644 index 0000000000..c65593327f --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-hull.c @@ -0,0 +1,235 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2003 University of Southern California + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + */ + +#include "cairoint.h" + +#include "cairo-error-private.h" +#include "cairo-slope-private.h" + +typedef struct cairo_hull { + cairo_point_t point; + cairo_slope_t slope; + int discard; + int id; +} cairo_hull_t; + +static void +_cairo_hull_init (cairo_hull_t *hull, + cairo_pen_vertex_t *vertices, + int num_vertices) +{ + cairo_point_t *p, *extremum, tmp; + int i; + + extremum = &vertices[0].point; + for (i = 1; i < num_vertices; i++) { + p = &vertices[i].point; + if (p->y < extremum->y || (p->y == extremum->y && p->x < extremum->x)) + extremum = p; + } + /* Put the extremal point at the beginning of the array */ + tmp = *extremum; + *extremum = vertices[0].point; + vertices[0].point = tmp; + + for (i = 0; i < num_vertices; i++) { + hull[i].point = vertices[i].point; + _cairo_slope_init (&hull[i].slope, &hull[0].point, &hull[i].point); + + /* give each point a unique id for later comparison */ + hull[i].id = i; + + /* Don't discard by default */ + hull[i].discard = 0; + + /* Discard all points coincident with the extremal point */ + if (i != 0 && hull[i].slope.dx == 0 && hull[i].slope.dy == 0) + hull[i].discard = 1; + } +} + +static inline cairo_int64_t +_slope_length (cairo_slope_t *slope) +{ + return _cairo_int64_add (_cairo_int32x32_64_mul (slope->dx, slope->dx), + _cairo_int32x32_64_mul (slope->dy, slope->dy)); +} + +static int +_cairo_hull_vertex_compare (const void *av, const void *bv) +{ + cairo_hull_t *a = (cairo_hull_t *) av; + cairo_hull_t *b = (cairo_hull_t *) bv; + int ret; + + /* Some libraries are reported to actually compare identical + * pointers and require the result to be 0. This is the crazy world we + * have to live in. + */ + if (a == b) + return 0; + + ret = _cairo_slope_compare (&a->slope, &b->slope); + + /* + * In the case of two vertices with identical slope from the + * extremal point discard the nearer point. + */ + if (ret == 0) { + int cmp; + + cmp = _cairo_int64_cmp (_slope_length (&a->slope), + _slope_length (&b->slope)); + + /* + * Use the points' ids to ensure a well-defined ordering, + * and avoid setting discard on both points. + */ + if (cmp < 0 || (cmp == 0 && a->id < b->id)) { + a->discard = 1; + ret = -1; + } else { + b->discard = 1; + ret = 1; + } + } + + return ret; +} + +static int +_cairo_hull_prev_valid (cairo_hull_t *hull, int num_hull, int index) +{ + /* hull[0] is always valid, and we never need to wraparound, (if + * we are passed an index of 0 here, then the calling loop is just + * about to terminate). */ + if (index == 0) + return 0; + + do { + index--; + } while (hull[index].discard); + + return index; +} + +static int +_cairo_hull_next_valid (cairo_hull_t *hull, int num_hull, int index) +{ + do { + index = (index + 1) % num_hull; + } while (hull[index].discard); + + return index; +} + +static void +_cairo_hull_eliminate_concave (cairo_hull_t *hull, int num_hull) +{ + int i, j, k; + cairo_slope_t slope_ij, slope_jk; + + i = 0; + j = _cairo_hull_next_valid (hull, num_hull, i); + k = _cairo_hull_next_valid (hull, num_hull, j); + + do { + _cairo_slope_init (&slope_ij, &hull[i].point, &hull[j].point); + _cairo_slope_init (&slope_jk, &hull[j].point, &hull[k].point); + + /* Is the angle formed by ij and jk concave? */ + if (_cairo_slope_compare (&slope_ij, &slope_jk) >= 0) { + if (i == k) + return; + hull[j].discard = 1; + j = i; + i = _cairo_hull_prev_valid (hull, num_hull, j); + } else { + i = j; + j = k; + k = _cairo_hull_next_valid (hull, num_hull, j); + } + } while (j != 0); +} + +static void +_cairo_hull_to_pen (cairo_hull_t *hull, cairo_pen_vertex_t *vertices, int *num_vertices) +{ + int i, j = 0; + + for (i = 0; i < *num_vertices; i++) { + if (hull[i].discard) + continue; + vertices[j++].point = hull[i].point; + } + + *num_vertices = j; +} + +/* Given a set of vertices, compute the convex hull using the Graham + scan algorithm. */ +cairo_status_t +_cairo_hull_compute (cairo_pen_vertex_t *vertices, int *num_vertices) +{ + cairo_hull_t hull_stack[CAIRO_STACK_ARRAY_LENGTH (cairo_hull_t)]; + cairo_hull_t *hull; + int num_hull = *num_vertices; + + if (CAIRO_INJECT_FAULT ()) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + if (num_hull > ARRAY_LENGTH (hull_stack)) { + hull = _cairo_malloc_ab (num_hull, sizeof (cairo_hull_t)); + if (unlikely (hull == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } else { + hull = hull_stack; + } + + _cairo_hull_init (hull, vertices, num_hull); + + qsort (hull + 1, num_hull - 1, + sizeof (cairo_hull_t), _cairo_hull_vertex_compare); + + _cairo_hull_eliminate_concave (hull, num_hull); + + _cairo_hull_to_pen (hull, vertices, num_vertices); + + if (hull != hull_stack) + free (hull); + + return CAIRO_STATUS_SUCCESS; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-image-compositor.c b/local/recipes/libs/cairo/source/src/cairo-image-compositor.c new file mode 100644 index 0000000000..8a3b2629f9 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-image-compositor.c @@ -0,0 +1,3177 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2003 University of Southern California + * Copyright © 2009,2010,2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Chris Wilson + */ + +/* The primarily reason for keeping a traps-compositor around is + * for validating cairo-xlib (which currently also uses traps). + */ + +#include "cairoint.h" + +#include "cairo-image-surface-private.h" + +#include "cairo-compositor-private.h" +#include "cairo-spans-compositor-private.h" + +#include "cairo-region-private.h" +#include "cairo-traps-private.h" +#include "cairo-tristrip-private.h" + +#include "cairo-pixman-private.h" + +static pixman_image_t * +to_pixman_image (cairo_surface_t *s) +{ + return ((cairo_image_surface_t *)s)->pixman_image; +} + +static cairo_int_status_t +acquire (void *abstract_dst) +{ + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +release (void *abstract_dst) +{ + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +set_clip_region (void *_surface, + cairo_region_t *region) +{ + cairo_image_surface_t *surface = _surface; + pixman_region32_t *rgn = region ? ®ion->rgn : NULL; + + if (! pixman_image_set_clip_region32 (surface->pixman_image, rgn)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +draw_image_boxes (void *_dst, + cairo_image_surface_t *image, + cairo_boxes_t *boxes, + int dx, int dy) +{ + cairo_image_surface_t *dst = _dst; + struct _cairo_boxes_chunk *chunk; + int i; + + TRACE ((stderr, "%s x %d\n", __FUNCTION__, boxes->num_boxes)); + + for (chunk = &boxes->chunks; chunk; chunk = chunk->next) { + for (i = 0; i < chunk->count; i++) { + cairo_box_t *b = &chunk->base[i]; + int x = _cairo_fixed_integer_part (b->p1.x); + int y = _cairo_fixed_integer_part (b->p1.y); + int w = _cairo_fixed_integer_part (b->p2.x) - x; + int h = _cairo_fixed_integer_part (b->p2.y) - y; + if (dst->pixman_format != image->pixman_format || + ! pixman_blt ((uint32_t *)image->data, (uint32_t *)dst->data, + image->stride / sizeof (uint32_t), + dst->stride / sizeof (uint32_t), + PIXMAN_FORMAT_BPP (image->pixman_format), + PIXMAN_FORMAT_BPP (dst->pixman_format), + x + dx, y + dy, + x, y, + w, h)) + { + pixman_image_composite32 (PIXMAN_OP_SRC, + image->pixman_image, NULL, dst->pixman_image, + x + dx, y + dy, + 0, 0, + x, y, + w, h); + } + } + } + return CAIRO_STATUS_SUCCESS; +} + +static inline uint32_t +color_to_uint32 (const cairo_color_t *color) +{ + return + ((uint32_t)color->alpha_short >> 8 << 24) | + (color->red_short >> 8 << 16) | + (color->green_short & 0xff00) | + (color->blue_short >> 8); +} + +static inline cairo_bool_t +color_to_pixel (const cairo_color_t *color, + pixman_format_code_t format, + uint32_t *pixel) +{ + uint32_t c; + + if (!(format == PIXMAN_a8r8g8b8 || + format == PIXMAN_x8r8g8b8 || + format == PIXMAN_a8b8g8r8 || + format == PIXMAN_x8b8g8r8 || + format == PIXMAN_b8g8r8a8 || + format == PIXMAN_b8g8r8x8 || + format == PIXMAN_r5g6b5 || + format == PIXMAN_b5g6r5 || + format == PIXMAN_a8)) + { + return FALSE; + } + + c = color_to_uint32 (color); + + if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_ABGR) { + c = ((c & 0xff000000) >> 0) | + ((c & 0x00ff0000) >> 16) | + ((c & 0x0000ff00) >> 0) | + ((c & 0x000000ff) << 16); + } + + if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_BGRA) { + c = ((c & 0xff000000) >> 24) | + ((c & 0x00ff0000) >> 8) | + ((c & 0x0000ff00) << 8) | + ((c & 0x000000ff) << 24); + } + + if (format == PIXMAN_a8) { + c = c >> 24; + } else if (format == PIXMAN_r5g6b5 || format == PIXMAN_b5g6r5) { + c = ((((c) >> 3) & 0x001f) | + (((c) >> 5) & 0x07e0) | + (((c) >> 8) & 0xf800)); + } + + *pixel = c; + return TRUE; +} + +static pixman_op_t +_pixman_operator (cairo_operator_t op) +{ + switch ((int) op) { + case CAIRO_OPERATOR_CLEAR: + return PIXMAN_OP_CLEAR; + + case CAIRO_OPERATOR_SOURCE: + return PIXMAN_OP_SRC; + case CAIRO_OPERATOR_OVER: + return PIXMAN_OP_OVER; + case CAIRO_OPERATOR_IN: + return PIXMAN_OP_IN; + case CAIRO_OPERATOR_OUT: + return PIXMAN_OP_OUT; + case CAIRO_OPERATOR_ATOP: + return PIXMAN_OP_ATOP; + + case CAIRO_OPERATOR_DEST: + return PIXMAN_OP_DST; + case CAIRO_OPERATOR_DEST_OVER: + return PIXMAN_OP_OVER_REVERSE; + case CAIRO_OPERATOR_DEST_IN: + return PIXMAN_OP_IN_REVERSE; + case CAIRO_OPERATOR_DEST_OUT: + return PIXMAN_OP_OUT_REVERSE; + case CAIRO_OPERATOR_DEST_ATOP: + return PIXMAN_OP_ATOP_REVERSE; + + case CAIRO_OPERATOR_XOR: + return PIXMAN_OP_XOR; + case CAIRO_OPERATOR_ADD: + return PIXMAN_OP_ADD; + case CAIRO_OPERATOR_SATURATE: + return PIXMAN_OP_SATURATE; + + case CAIRO_OPERATOR_MULTIPLY: + return PIXMAN_OP_MULTIPLY; + case CAIRO_OPERATOR_SCREEN: + return PIXMAN_OP_SCREEN; + case CAIRO_OPERATOR_OVERLAY: + return PIXMAN_OP_OVERLAY; + case CAIRO_OPERATOR_DARKEN: + return PIXMAN_OP_DARKEN; + case CAIRO_OPERATOR_LIGHTEN: + return PIXMAN_OP_LIGHTEN; + case CAIRO_OPERATOR_COLOR_DODGE: + return PIXMAN_OP_COLOR_DODGE; + case CAIRO_OPERATOR_COLOR_BURN: + return PIXMAN_OP_COLOR_BURN; + case CAIRO_OPERATOR_HARD_LIGHT: + return PIXMAN_OP_HARD_LIGHT; + case CAIRO_OPERATOR_SOFT_LIGHT: + return PIXMAN_OP_SOFT_LIGHT; + case CAIRO_OPERATOR_DIFFERENCE: + return PIXMAN_OP_DIFFERENCE; + case CAIRO_OPERATOR_EXCLUSION: + return PIXMAN_OP_EXCLUSION; + case CAIRO_OPERATOR_HSL_HUE: + return PIXMAN_OP_HSL_HUE; + case CAIRO_OPERATOR_HSL_SATURATION: + return PIXMAN_OP_HSL_SATURATION; + case CAIRO_OPERATOR_HSL_COLOR: + return PIXMAN_OP_HSL_COLOR; + case CAIRO_OPERATOR_HSL_LUMINOSITY: + return PIXMAN_OP_HSL_LUMINOSITY; + + default: + ASSERT_NOT_REACHED; + return PIXMAN_OP_OVER; + } +} + +static cairo_bool_t +__fill_reduces_to_source (cairo_operator_t op, + const cairo_color_t *color, + const cairo_image_surface_t *dst) +{ + if (op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_CLEAR) + return TRUE; + if (op == CAIRO_OPERATOR_OVER && CAIRO_COLOR_IS_OPAQUE (color)) + return TRUE; + if (dst->base.is_clear) + return op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD; + + return FALSE; +} + +static cairo_bool_t +fill_reduces_to_source (cairo_operator_t op, + const cairo_color_t *color, + const cairo_image_surface_t *dst, + uint32_t *pixel) +{ + if (__fill_reduces_to_source (op, color, dst)) { + return color_to_pixel (color, dst->pixman_format, pixel); + } + + return FALSE; +} + +static cairo_int_status_t +fill_rectangles (void *_dst, + cairo_operator_t op, + const cairo_color_t *color, + cairo_rectangle_int_t *rects, + int num_rects) +{ + cairo_image_surface_t *dst = _dst; + uint32_t pixel; + int i; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + if (fill_reduces_to_source (op, color, dst, &pixel)) { + for (i = 0; i < num_rects; i++) { + pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t), + PIXMAN_FORMAT_BPP (dst->pixman_format), + rects[i].x, rects[i].y, + rects[i].width, rects[i].height, + pixel); + } + } else { + pixman_image_t *src = _pixman_image_for_color (color); + if (unlikely (src == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + op = _pixman_operator (op); + for (i = 0; i < num_rects; i++) { + pixman_image_composite32 (op, + src, NULL, dst->pixman_image, + 0, 0, + 0, 0, + rects[i].x, rects[i].y, + rects[i].width, rects[i].height); + } + + pixman_image_unref (src); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +fill_boxes (void *_dst, + cairo_operator_t op, + const cairo_color_t *color, + cairo_boxes_t *boxes) +{ + cairo_image_surface_t *dst = _dst; + struct _cairo_boxes_chunk *chunk; + uint32_t pixel; + int i; + + TRACE ((stderr, "%s x %d\n", __FUNCTION__, boxes->num_boxes)); + + if (fill_reduces_to_source (op, color, dst, &pixel)) { + for (chunk = &boxes->chunks; chunk; chunk = chunk->next) { + for (i = 0; i < chunk->count; i++) { + int x = _cairo_fixed_integer_part (chunk->base[i].p1.x); + int y = _cairo_fixed_integer_part (chunk->base[i].p1.y); + int w = _cairo_fixed_integer_part (chunk->base[i].p2.x) - x; + int h = _cairo_fixed_integer_part (chunk->base[i].p2.y) - y; + pixman_fill ((uint32_t *) dst->data, + dst->stride / sizeof (uint32_t), + PIXMAN_FORMAT_BPP (dst->pixman_format), + x, y, w, h, pixel); + } + } + } + else + { + pixman_image_t *src = _pixman_image_for_color (color); + if (unlikely (src == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + op = _pixman_operator (op); + for (chunk = &boxes->chunks; chunk; chunk = chunk->next) { + for (i = 0; i < chunk->count; i++) { + int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x); + int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y); + int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x); + int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y); + pixman_image_composite32 (op, + src, NULL, dst->pixman_image, + 0, 0, + 0, 0, + x1, y1, + x2-x1, y2-y1); + } + } + + pixman_image_unref (src); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +composite (void *_dst, + cairo_operator_t op, + cairo_surface_t *abstract_src, + cairo_surface_t *abstract_mask, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height) +{ + cairo_image_source_t *src = (cairo_image_source_t *)abstract_src; + cairo_image_source_t *mask = (cairo_image_source_t *)abstract_mask; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + if (mask) { + pixman_image_composite32 (_pixman_operator (op), + src->pixman_image, mask->pixman_image, to_pixman_image (_dst), + src_x, src_y, + mask_x, mask_y, + dst_x, dst_y, + width, height); + } else { + pixman_image_composite32 (_pixman_operator (op), + src->pixman_image, NULL, to_pixman_image (_dst), + src_x, src_y, + 0, 0, + dst_x, dst_y, + width, height); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +lerp (void *_dst, + cairo_surface_t *abstract_src, + cairo_surface_t *abstract_mask, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height) +{ + cairo_image_surface_t *dst = _dst; + cairo_image_source_t *src = (cairo_image_source_t *)abstract_src; + cairo_image_source_t *mask = (cairo_image_source_t *)abstract_mask; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + +#if PIXMAN_HAS_OP_LERP + pixman_image_composite32 (PIXMAN_OP_LERP_SRC, + src->pixman_image, mask->pixman_image, dst->pixman_image, + src_x, src_y, + mask_x, mask_y, + dst_x, dst_y, + width, height); +#else + /* Punch the clip out of the destination */ + TRACE ((stderr, "%s - OUT_REVERSE (mask=%d/%p, dst=%d/%p)\n", + __FUNCTION__, + mask->base.unique_id, mask->pixman_image, + dst->base.unique_id, dst->pixman_image)); + pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE, + mask->pixman_image, NULL, dst->pixman_image, + mask_x, mask_y, + 0, 0, + dst_x, dst_y, + width, height); + + /* Now add the two results together */ + TRACE ((stderr, "%s - ADD (src=%d/%p, mask=%d/%p, dst=%d/%p)\n", + __FUNCTION__, + src->base.unique_id, src->pixman_image, + mask->base.unique_id, mask->pixman_image, + dst->base.unique_id, dst->pixman_image)); + pixman_image_composite32 (PIXMAN_OP_ADD, + src->pixman_image, mask->pixman_image, dst->pixman_image, + src_x, src_y, + mask_x, mask_y, + dst_x, dst_y, + width, height); +#endif + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +composite_boxes (void *_dst, + cairo_operator_t op, + cairo_surface_t *abstract_src, + cairo_surface_t *abstract_mask, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + cairo_boxes_t *boxes, + const cairo_rectangle_int_t *extents) +{ + pixman_image_t *dst = to_pixman_image (_dst); + pixman_image_t *src = ((cairo_image_source_t *)abstract_src)->pixman_image; + pixman_image_t *mask = abstract_mask ? ((cairo_image_source_t *)abstract_mask)->pixman_image : NULL; + pixman_image_t *free_src = NULL; + struct _cairo_boxes_chunk *chunk; + int i; + + /* XXX consider using a region? saves multiple prepare-composite */ + TRACE ((stderr, "%s x %d\n", __FUNCTION__, boxes->num_boxes)); + + if (((cairo_surface_t *)_dst)->is_clear && + (op == CAIRO_OPERATOR_SOURCE || + op == CAIRO_OPERATOR_OVER || + op == CAIRO_OPERATOR_ADD)) { + op = PIXMAN_OP_SRC; + } else if (mask) { + if (op == CAIRO_OPERATOR_CLEAR) { +#if PIXMAN_HAS_OP_LERP + op = PIXMAN_OP_LERP_CLEAR; +#else + free_src = src = _pixman_image_for_color (CAIRO_COLOR_WHITE); + if (unlikely (src == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + op = PIXMAN_OP_OUT_REVERSE; +#endif + } else if (op == CAIRO_OPERATOR_SOURCE) { +#if PIXMAN_HAS_OP_LERP + op = PIXMAN_OP_LERP_SRC; +#else + return CAIRO_INT_STATUS_UNSUPPORTED; +#endif + } else { + op = _pixman_operator (op); + } + } else { + op = _pixman_operator (op); + } + + for (chunk = &boxes->chunks; chunk; chunk = chunk->next) { + for (i = 0; i < chunk->count; i++) { + int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x); + int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y); + int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x); + int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y); + + pixman_image_composite32 (op, src, mask, dst, + x1 + src_x, y1 + src_y, + x1 + mask_x, y1 + mask_y, + x1 + dst_x, y1 + dst_y, + x2 - x1, y2 - y1); + } + } + + if (free_src) + pixman_image_unref (free_src); + + return CAIRO_STATUS_SUCCESS; +} + +#define CAIRO_FIXED_16_16_MIN _cairo_fixed_from_int (-32768) +#define CAIRO_FIXED_16_16_MAX _cairo_fixed_from_int (32767) + +static cairo_bool_t +line_exceeds_16_16 (const cairo_line_t *line) +{ + return + line->p1.x <= CAIRO_FIXED_16_16_MIN || + line->p1.x >= CAIRO_FIXED_16_16_MAX || + + line->p2.x <= CAIRO_FIXED_16_16_MIN || + line->p2.x >= CAIRO_FIXED_16_16_MAX || + + line->p1.y <= CAIRO_FIXED_16_16_MIN || + line->p1.y >= CAIRO_FIXED_16_16_MAX || + + line->p2.y <= CAIRO_FIXED_16_16_MIN || + line->p2.y >= CAIRO_FIXED_16_16_MAX; +} + +static void +project_line_x_onto_16_16 (const cairo_line_t *line, + cairo_fixed_t top, + cairo_fixed_t bottom, + pixman_line_fixed_t *out) +{ + /* XXX use fixed-point arithmetic? */ + cairo_point_double_t p1, p2; + double m; + + p1.x = _cairo_fixed_to_double (line->p1.x); + p1.y = _cairo_fixed_to_double (line->p1.y); + + p2.x = _cairo_fixed_to_double (line->p2.x); + p2.y = _cairo_fixed_to_double (line->p2.y); + + m = (p2.x - p1.x) / (p2.y - p1.y); + out->p1.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (top - line->p1.y)); + out->p2.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (bottom - line->p1.y)); +} + +void +_pixman_image_add_traps (pixman_image_t *image, + int dst_x, int dst_y, + cairo_traps_t *traps) +{ + cairo_trapezoid_t *t = traps->traps; + int num_traps = traps->num_traps; + while (num_traps--) { + pixman_trapezoid_t trap; + + /* top/bottom will be clamped to surface bounds */ + trap.top = _cairo_fixed_to_16_16 (t->top); + trap.bottom = _cairo_fixed_to_16_16 (t->bottom); + + /* However, all the other coordinates will have been left untouched so + * as not to introduce numerical error. Recompute them if they + * exceed the 16.16 limits. + */ + if (unlikely (line_exceeds_16_16 (&t->left))) { + project_line_x_onto_16_16 (&t->left, t->top, t->bottom, &trap.left); + trap.left.p1.y = trap.top; + trap.left.p2.y = trap.bottom; + } else { + trap.left.p1.x = _cairo_fixed_to_16_16 (t->left.p1.x); + trap.left.p1.y = _cairo_fixed_to_16_16 (t->left.p1.y); + trap.left.p2.x = _cairo_fixed_to_16_16 (t->left.p2.x); + trap.left.p2.y = _cairo_fixed_to_16_16 (t->left.p2.y); + } + + if (unlikely (line_exceeds_16_16 (&t->right))) { + project_line_x_onto_16_16 (&t->right, t->top, t->bottom, &trap.right); + trap.right.p1.y = trap.top; + trap.right.p2.y = trap.bottom; + } else { + trap.right.p1.x = _cairo_fixed_to_16_16 (t->right.p1.x); + trap.right.p1.y = _cairo_fixed_to_16_16 (t->right.p1.y); + trap.right.p2.x = _cairo_fixed_to_16_16 (t->right.p2.x); + trap.right.p2.y = _cairo_fixed_to_16_16 (t->right.p2.y); + } + + pixman_rasterize_trapezoid (image, &trap, -dst_x, -dst_y); + t++; + } +} + +static cairo_int_status_t +composite_traps (void *_dst, + cairo_operator_t op, + cairo_surface_t *abstract_src, + int src_x, + int src_y, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents, + cairo_antialias_t antialias, + cairo_traps_t *traps) +{ + cairo_image_surface_t *dst = (cairo_image_surface_t *) _dst; + cairo_image_source_t *src = (cairo_image_source_t *) abstract_src; + cairo_int_status_t status; + pixman_image_t *mask; + pixman_format_code_t format; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + /* pixman doesn't eliminate self-intersecting trapezoids/edges */ + status = _cairo_bentley_ottmann_tessellate_traps (traps, + CAIRO_FILL_RULE_WINDING); + if (status != CAIRO_INT_STATUS_SUCCESS) + return status; + + /* Special case adding trapezoids onto a mask surface; we want to avoid + * creating an intermediate temporary mask unnecessarily. + * + * We make the assumption here that the portion of the trapezoids + * contained within the surface is bounded by [dst_x,dst_y,width,height]; + * the Cairo core code passes bounds based on the trapezoid extents. + */ + format = antialias == CAIRO_ANTIALIAS_NONE ? PIXMAN_a1 : PIXMAN_a8; + if (dst->pixman_format == format && + (abstract_src == NULL || + (op == CAIRO_OPERATOR_ADD && src->is_opaque_solid))) + { + _pixman_image_add_traps (dst->pixman_image, dst_x, dst_y, traps); + return CAIRO_STATUS_SUCCESS; + } + + mask = pixman_image_create_bits (format, + extents->width, extents->height, + NULL, 0); + if (unlikely (mask == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + _pixman_image_add_traps (mask, extents->x, extents->y, traps); + pixman_image_composite32 (_pixman_operator (op), + src->pixman_image, mask, dst->pixman_image, + extents->x + src_x, extents->y + src_y, + 0, 0, + extents->x - dst_x, extents->y - dst_y, + extents->width, extents->height); + + pixman_image_unref (mask); + + return CAIRO_STATUS_SUCCESS; +} + +static void +set_point (pixman_point_fixed_t *p, cairo_point_t *c) +{ + p->x = _cairo_fixed_to_16_16 (c->x); + p->y = _cairo_fixed_to_16_16 (c->y); +} + +void +_pixman_image_add_tristrip (pixman_image_t *image, + int dst_x, int dst_y, + cairo_tristrip_t *strip) +{ + pixman_triangle_t tri; + pixman_point_fixed_t *p[3] = {&tri.p1, &tri.p2, &tri.p3 }; + int n; + + set_point (p[0], &strip->points[0]); + set_point (p[1], &strip->points[1]); + set_point (p[2], &strip->points[2]); + pixman_add_triangles (image, -dst_x, -dst_y, 1, &tri); + for (n = 3; n < strip->num_points; n++) { + set_point (p[n%3], &strip->points[n]); + pixman_add_triangles (image, -dst_x, -dst_y, 1, &tri); + } +} + +static cairo_int_status_t +composite_tristrip (void *_dst, + cairo_operator_t op, + cairo_surface_t *abstract_src, + int src_x, + int src_y, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents, + cairo_antialias_t antialias, + cairo_tristrip_t *strip) +{ + cairo_image_surface_t *dst = (cairo_image_surface_t *) _dst; + cairo_image_source_t *src = (cairo_image_source_t *) abstract_src; + pixman_image_t *mask; + pixman_format_code_t format; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + if (strip->num_points < 3) + return CAIRO_STATUS_SUCCESS; + + if (1) { /* pixman doesn't eliminate self-intersecting triangles/edges */ + cairo_int_status_t status; + cairo_traps_t traps; + int n; + + _cairo_traps_init (&traps); + for (n = 0; n < strip->num_points; n++) { + cairo_point_t p[4]; + + p[0] = strip->points[0]; + p[1] = strip->points[1]; + p[2] = strip->points[2]; + p[3] = strip->points[0]; + + _cairo_traps_tessellate_convex_quad (&traps, p); + } + status = composite_traps (_dst, op, abstract_src, + src_x, src_y, + dst_x, dst_y, + extents, antialias, &traps); + _cairo_traps_fini (&traps); + + return status; + } + + format = antialias == CAIRO_ANTIALIAS_NONE ? PIXMAN_a1 : PIXMAN_a8; + if (dst->pixman_format == format && + (abstract_src == NULL || + (op == CAIRO_OPERATOR_ADD && src->is_opaque_solid))) + { + _pixman_image_add_tristrip (dst->pixman_image, dst_x, dst_y, strip); + return CAIRO_STATUS_SUCCESS; + } + + mask = pixman_image_create_bits (format, + extents->width, extents->height, + NULL, 0); + if (unlikely (mask == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + _pixman_image_add_tristrip (mask, extents->x, extents->y, strip); + pixman_image_composite32 (_pixman_operator (op), + src->pixman_image, mask, dst->pixman_image, + extents->x + src_x, extents->y + src_y, + 0, 0, + extents->x - dst_x, extents->y - dst_y, + extents->width, extents->height); + + pixman_image_unref (mask); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +check_composite_glyphs (const cairo_composite_rectangles_t *extents, + cairo_scaled_font_t *scaled_font, + cairo_glyph_t *glyphs, + int *num_glyphs) +{ + return CAIRO_STATUS_SUCCESS; +} + +#if HAS_PIXMAN_GLYPHS +static pixman_glyph_cache_t *global_glyph_cache; + +static inline pixman_glyph_cache_t * +get_glyph_cache (void) +{ + if (!global_glyph_cache) + global_glyph_cache = pixman_glyph_cache_create (); + + return global_glyph_cache; +} + +void +_cairo_image_compositor_reset_static_data (void) +{ + CAIRO_MUTEX_LOCK (_cairo_glyph_cache_mutex); + + if (global_glyph_cache) + pixman_glyph_cache_destroy (global_glyph_cache); + global_glyph_cache = NULL; + + CAIRO_MUTEX_UNLOCK (_cairo_glyph_cache_mutex); +} + +void +_cairo_image_scaled_glyph_fini (cairo_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph) +{ + CAIRO_MUTEX_LOCK (_cairo_glyph_cache_mutex); + + if (global_glyph_cache) { + pixman_glyph_cache_remove ( + global_glyph_cache, scaled_font, + (void *)scaled_glyph->hash_entry.hash); + } + + CAIRO_MUTEX_UNLOCK (_cairo_glyph_cache_mutex); +} + +#define PHASE(x) ((int)(floor (4 * (x + 0.125)) - 4 * floor (x + 0.125))) +#define POSITION(x) ((int) floor (x + 0.125)) + +static cairo_int_status_t +composite_glyphs (void *_dst, + cairo_operator_t op, + cairo_surface_t *_src, + int src_x, + int src_y, + int dst_x, + int dst_y, + cairo_composite_glyphs_info_t *info) +{ + cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; + pixman_glyph_cache_t *glyph_cache; + pixman_glyph_t pglyphs_stack[CAIRO_STACK_ARRAY_LENGTH (pixman_glyph_t)]; + pixman_glyph_t *pglyphs = pglyphs_stack; + pixman_glyph_t *pg; + int i; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + CAIRO_MUTEX_LOCK (_cairo_glyph_cache_mutex); + + glyph_cache = get_glyph_cache(); + if (unlikely (glyph_cache == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto out_unlock; + } + + pixman_glyph_cache_freeze (glyph_cache); + + if (info->num_glyphs > ARRAY_LENGTH (pglyphs_stack)) { + pglyphs = _cairo_malloc_ab (info->num_glyphs, sizeof (pixman_glyph_t)); + if (unlikely (pglyphs == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto out_thaw; + } + } + + pg = pglyphs; + for (i = 0; i < info->num_glyphs; i++) { + unsigned long index = info->glyphs[i].index; + const void *glyph; + unsigned long xphase, yphase; + + xphase = PHASE(info->glyphs[i].x); + yphase = PHASE(info->glyphs[i].y); + + index = index | (xphase << 24) | (yphase << 26); + + glyph = pixman_glyph_cache_lookup (glyph_cache, info->font, (void *)(uintptr_t)index); + if (!glyph) { + cairo_scaled_glyph_t *scaled_glyph; + cairo_image_surface_t *glyph_surface; + + /* This call can actually end up recursing, so we have to + * drop the mutex around it. + */ + CAIRO_MUTEX_UNLOCK (_cairo_glyph_cache_mutex); + status = _cairo_scaled_glyph_lookup (info->font, index, + CAIRO_SCALED_GLYPH_INFO_SURFACE, + NULL, /* foreground color */ + &scaled_glyph); + CAIRO_MUTEX_LOCK (_cairo_glyph_cache_mutex); + + if (unlikely (status)) + goto out_thaw; + + glyph_surface = scaled_glyph->surface; + glyph = pixman_glyph_cache_insert (glyph_cache, info->font, (void *)(uintptr_t)index, + glyph_surface->base.device_transform.x0, + glyph_surface->base.device_transform.y0, + glyph_surface->pixman_image); + if (unlikely (!glyph)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto out_thaw; + } + } + + pg->x = POSITION (info->glyphs[i].x); + pg->y = POSITION (info->glyphs[i].y); + pg->glyph = glyph; + pg++; + } + + if (info->use_mask) { + pixman_format_code_t mask_format; + + mask_format = pixman_glyph_get_mask_format (glyph_cache, pg - pglyphs, pglyphs); + + pixman_composite_glyphs (_pixman_operator (op), + ((cairo_image_source_t *)_src)->pixman_image, + to_pixman_image (_dst), + mask_format, + info->extents.x + src_x, info->extents.y + src_y, + info->extents.x, info->extents.y, + info->extents.x - dst_x, info->extents.y - dst_y, + info->extents.width, info->extents.height, + glyph_cache, pg - pglyphs, pglyphs); + } else { + pixman_composite_glyphs_no_mask (_pixman_operator (op), + ((cairo_image_source_t *)_src)->pixman_image, + to_pixman_image (_dst), + src_x, src_y, + - dst_x, - dst_y, + glyph_cache, pg - pglyphs, pglyphs); + } + +out_thaw: + pixman_glyph_cache_thaw (glyph_cache); + + if (pglyphs != pglyphs_stack) + free(pglyphs); + +out_unlock: + CAIRO_MUTEX_UNLOCK (_cairo_glyph_cache_mutex); + return status; +} +#else +void +_cairo_image_compositor_reset_static_data (void) +{ +} + +void +_cairo_image_scaled_glyph_fini (cairo_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph) +{ +} + +static cairo_int_status_t +composite_one_glyph (void *_dst, + cairo_operator_t op, + cairo_surface_t *_src, + int src_x, + int src_y, + int dst_x, + int dst_y, + cairo_composite_glyphs_info_t *info) +{ + cairo_image_surface_t *glyph_surface; + cairo_scaled_glyph_t *scaled_glyph; + cairo_status_t status; + int x, y; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + status = _cairo_scaled_glyph_lookup (info->font, + info->glyphs[0].index, + CAIRO_SCALED_GLYPH_INFO_SURFACE, + NULL, /* foreground color */ + &scaled_glyph); + + if (unlikely (status)) + return status; + + glyph_surface = scaled_glyph->surface; + if (glyph_surface->width == 0 || glyph_surface->height == 0) + return CAIRO_INT_STATUS_NOTHING_TO_DO; + + /* round glyph locations to the nearest pixel */ + /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */ + x = _cairo_lround (info->glyphs[0].x - + glyph_surface->base.device_transform.x0); + y = _cairo_lround (info->glyphs[0].y - + glyph_surface->base.device_transform.y0); + + pixman_image_composite32 (_pixman_operator (op), + ((cairo_image_source_t *)_src)->pixman_image, + glyph_surface->pixman_image, + to_pixman_image (_dst), + x + src_x, y + src_y, + 0, 0, + x - dst_x, y - dst_y, + glyph_surface->width, + glyph_surface->height); + + return CAIRO_INT_STATUS_SUCCESS; +} + +static cairo_int_status_t +composite_glyphs_via_mask (void *_dst, + cairo_operator_t op, + cairo_surface_t *_src, + int src_x, + int src_y, + int dst_x, + int dst_y, + cairo_composite_glyphs_info_t *info) +{ + cairo_scaled_glyph_t *glyph_cache[64]; + pixman_image_t *white = _pixman_image_for_color (CAIRO_COLOR_WHITE); + cairo_scaled_glyph_t *scaled_glyph; + uint8_t buf[2048]; + pixman_image_t *mask; + pixman_format_code_t format; + cairo_status_t status; + int i; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + if (unlikely (white == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + /* XXX convert the glyphs to common formats a8/a8r8g8b8 to hit + * optimised paths through pixman. Should we increase the bit + * depth of the target surface, we should reconsider the appropriate + * mask formats. + */ + + status = _cairo_scaled_glyph_lookup (info->font, + info->glyphs[0].index, + CAIRO_SCALED_GLYPH_INFO_SURFACE, + NULL, /* foreground color */ + &scaled_glyph); + if (unlikely (status)) { + pixman_image_unref (white); + return status; + } + + memset (glyph_cache, 0, sizeof (glyph_cache)); + glyph_cache[info->glyphs[0].index % ARRAY_LENGTH (glyph_cache)] = scaled_glyph; + + format = PIXMAN_a8; + i = (info->extents.width + 3) & ~3; + if (scaled_glyph->surface->base.content & CAIRO_CONTENT_COLOR) { + format = PIXMAN_a8r8g8b8; + i = info->extents.width * 4; + } + + if (i * info->extents.height > (int) sizeof (buf)) { + mask = pixman_image_create_bits (format, + info->extents.width, + info->extents.height, + NULL, 0); + } else { + memset (buf, 0, i * info->extents.height); + mask = pixman_image_create_bits (format, + info->extents.width, + info->extents.height, + (uint32_t *)buf, i); + } + if (unlikely (mask == NULL)) { + pixman_image_unref (white); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + status = CAIRO_STATUS_SUCCESS; + for (i = 0; i < info->num_glyphs; i++) { + unsigned long glyph_index = info->glyphs[i].index; + int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache); + cairo_image_surface_t *glyph_surface; + int x, y; + + scaled_glyph = glyph_cache[cache_index]; + if (scaled_glyph == NULL || + _cairo_scaled_glyph_index (scaled_glyph) != glyph_index) + { + status = _cairo_scaled_glyph_lookup (info->font, glyph_index, + CAIRO_SCALED_GLYPH_INFO_SURFACE, + NULL, /* foreground color */ + &scaled_glyph); + + if (unlikely (status)) { + pixman_image_unref (mask); + pixman_image_unref (white); + return status; + } + + glyph_cache[cache_index] = scaled_glyph; + } + + glyph_surface = scaled_glyph->surface; + if (glyph_surface->width && glyph_surface->height) { + if (glyph_surface->base.content & CAIRO_CONTENT_COLOR && + format == PIXMAN_a8) { + pixman_image_t *ca_mask; + + format = PIXMAN_a8r8g8b8; + ca_mask = pixman_image_create_bits (format, + info->extents.width, + info->extents.height, + NULL, 0); + if (unlikely (ca_mask == NULL)) { + pixman_image_unref (mask); + pixman_image_unref (white); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + pixman_image_composite32 (PIXMAN_OP_SRC, + white, mask, ca_mask, + 0, 0, + 0, 0, + 0, 0, + info->extents.width, + info->extents.height); + pixman_image_unref (mask); + mask = ca_mask; + } + + /* round glyph locations to the nearest pixel */ + /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */ + x = _cairo_lround (info->glyphs[i].x - + glyph_surface->base.device_transform.x0); + y = _cairo_lround (info->glyphs[i].y - + glyph_surface->base.device_transform.y0); + + if (glyph_surface->pixman_format == format) { + pixman_image_composite32 (PIXMAN_OP_ADD, + glyph_surface->pixman_image, NULL, mask, + 0, 0, + 0, 0, + x - info->extents.x, y - info->extents.y, + glyph_surface->width, + glyph_surface->height); + } else { + pixman_image_composite32 (PIXMAN_OP_ADD, + white, glyph_surface->pixman_image, mask, + 0, 0, + 0, 0, + x - info->extents.x, y - info->extents.y, + glyph_surface->width, + glyph_surface->height); + } + } + } + + if (format == PIXMAN_a8r8g8b8) + pixman_image_set_component_alpha (mask, TRUE); + + pixman_image_composite32 (_pixman_operator (op), + ((cairo_image_source_t *)_src)->pixman_image, + mask, + to_pixman_image (_dst), + info->extents.x + src_x, info->extents.y + src_y, + 0, 0, + info->extents.x - dst_x, info->extents.y - dst_y, + info->extents.width, info->extents.height); + pixman_image_unref (mask); + pixman_image_unref (white); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +composite_glyphs (void *_dst, + cairo_operator_t op, + cairo_surface_t *_src, + int src_x, + int src_y, + int dst_x, + int dst_y, + cairo_composite_glyphs_info_t *info) +{ + cairo_scaled_glyph_t *glyph_cache[64]; + pixman_image_t *dst, *src; + cairo_status_t status; + int i; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + if (info->num_glyphs == 1) + return composite_one_glyph(_dst, op, _src, src_x, src_y, dst_x, dst_y, info); + + if (info->use_mask) + return composite_glyphs_via_mask(_dst, op, _src, src_x, src_y, dst_x, dst_y, info); + + op = _pixman_operator (op); + dst = to_pixman_image (_dst); + src = ((cairo_image_source_t *)_src)->pixman_image; + + memset (glyph_cache, 0, sizeof (glyph_cache)); + status = CAIRO_STATUS_SUCCESS; + + for (i = 0; i < info->num_glyphs; i++) { + int x, y; + cairo_image_surface_t *glyph_surface; + cairo_scaled_glyph_t *scaled_glyph; + unsigned long glyph_index = info->glyphs[i].index; + int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache); + + scaled_glyph = glyph_cache[cache_index]; + if (scaled_glyph == NULL || + _cairo_scaled_glyph_index (scaled_glyph) != glyph_index) + { + status = _cairo_scaled_glyph_lookup (info->font, glyph_index, + CAIRO_SCALED_GLYPH_INFO_SURFACE, + NULL, /* foreground color */ + &scaled_glyph); + + if (unlikely (status)) + break; + + glyph_cache[cache_index] = scaled_glyph; + } + + glyph_surface = scaled_glyph->surface; + if (glyph_surface->width && glyph_surface->height) { + /* round glyph locations to the nearest pixel */ + /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */ + x = _cairo_lround (info->glyphs[i].x - + glyph_surface->base.device_transform.x0); + y = _cairo_lround (info->glyphs[i].y - + glyph_surface->base.device_transform.y0); + + pixman_image_composite32 (op, src, glyph_surface->pixman_image, dst, + x + src_x, y + src_y, + 0, 0, + x - dst_x, y - dst_y, + glyph_surface->width, + glyph_surface->height); + } + } + + return status; +} +#endif + +static cairo_int_status_t +check_composite (const cairo_composite_rectangles_t *extents) +{ + return CAIRO_STATUS_SUCCESS; +} + +const cairo_compositor_t * +_cairo_image_traps_compositor_get (void) +{ + static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT; + static cairo_traps_compositor_t compositor; + + if (_cairo_atomic_init_once_enter(&once)) { + _cairo_traps_compositor_init(&compositor, + &__cairo_no_compositor); + compositor.acquire = acquire; + compositor.release = release; + compositor.set_clip_region = set_clip_region; + compositor.pattern_to_surface = _cairo_image_source_create_for_pattern; + compositor.draw_image_boxes = draw_image_boxes; + //compositor.copy_boxes = copy_boxes; + compositor.fill_boxes = fill_boxes; + compositor.check_composite = check_composite; + compositor.composite = composite; + compositor.lerp = lerp; + //compositor.check_composite_boxes = check_composite_boxes; + compositor.composite_boxes = composite_boxes; + //compositor.check_composite_traps = check_composite_traps; + compositor.composite_traps = composite_traps; + //compositor.check_composite_tristrip = check_composite_traps; + compositor.composite_tristrip = composite_tristrip; + compositor.check_composite_glyphs = check_composite_glyphs; + compositor.composite_glyphs = composite_glyphs; + + _cairo_atomic_init_once_leave(&once); + } + + return &compositor.base; +} + +const cairo_compositor_t * +_cairo_image_mask_compositor_get (void) +{ + static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT; + static cairo_mask_compositor_t compositor; + + if (_cairo_atomic_init_once_enter(&once)) { + _cairo_mask_compositor_init (&compositor, + _cairo_image_traps_compositor_get ()); + compositor.acquire = acquire; + compositor.release = release; + compositor.set_clip_region = set_clip_region; + compositor.pattern_to_surface = _cairo_image_source_create_for_pattern; + compositor.draw_image_boxes = draw_image_boxes; + compositor.fill_rectangles = fill_rectangles; + compositor.fill_boxes = fill_boxes; + compositor.check_composite = check_composite; + compositor.composite = composite; + //compositor.lerp = lerp; + //compositor.check_composite_boxes = check_composite_boxes; + compositor.composite_boxes = composite_boxes; + compositor.check_composite_glyphs = check_composite_glyphs; + compositor.composite_glyphs = composite_glyphs; + + _cairo_atomic_init_once_leave(&once); + } + + return &compositor.base; +} + +#if PIXMAN_HAS_COMPOSITOR +typedef struct _cairo_image_span_renderer { + cairo_span_renderer_t base; + + pixman_image_compositor_t *compositor; + pixman_image_t *src, *mask; + float opacity; + cairo_rectangle_int_t extents; +} cairo_image_span_renderer_t; +COMPILE_TIME_ASSERT (sizeof (cairo_image_span_renderer_t) <= sizeof (cairo_abstract_span_renderer_t)); + +static cairo_status_t +_cairo_image_bounded_opaque_spans (void *abstract_renderer, + int y, int height, + const cairo_half_open_span_t *spans, + unsigned num_spans) +{ + cairo_image_span_renderer_t *r = abstract_renderer; + + if (num_spans == 0) + return CAIRO_STATUS_SUCCESS; + + do { + if (spans[0].coverage) + pixman_image_compositor_blt (r->compositor, + spans[0].x, y, + spans[1].x - spans[0].x, height, + spans[0].coverage); + spans++; + } while (--num_spans > 1); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_image_bounded_spans (void *abstract_renderer, + int y, int height, + const cairo_half_open_span_t *spans, + unsigned num_spans) +{ + cairo_image_span_renderer_t *r = abstract_renderer; + + if (num_spans == 0) + return CAIRO_STATUS_SUCCESS; + + do { + if (spans[0].coverage) { + pixman_image_compositor_blt (r->compositor, + spans[0].x, y, + spans[1].x - spans[0].x, height, + r->opacity * spans[0].coverage); + } + spans++; + } while (--num_spans > 1); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_image_unbounded_spans (void *abstract_renderer, + int y, int height, + const cairo_half_open_span_t *spans, + unsigned num_spans) +{ + cairo_image_span_renderer_t *r = abstract_renderer; + + assert (y + height <= r->extents.height); + if (y > r->extents.y) { + pixman_image_compositor_blt (r->compositor, + r->extents.x, r->extents.y, + r->extents.width, y - r->extents.y, + 0); + } + + if (num_spans == 0) { + pixman_image_compositor_blt (r->compositor, + r->extents.x, y, + r->extents.width, height, + 0); + } else { + if (spans[0].x != r->extents.x) { + pixman_image_compositor_blt (r->compositor, + r->extents.x, y, + spans[0].x - r->extents.x, + height, + 0); + } + + do { + assert (spans[0].x < r->extents.x + r->extents.width); + pixman_image_compositor_blt (r->compositor, + spans[0].x, y, + spans[1].x - spans[0].x, height, + r->opacity * spans[0].coverage); + spans++; + } while (--num_spans > 1); + + if (spans[0].x != r->extents.x + r->extents.width) { + assert (spans[0].x < r->extents.x + r->extents.width); + pixman_image_compositor_blt (r->compositor, + spans[0].x, y, + r->extents.x + r->extents.width - spans[0].x, height, + 0); + } + } + + r->extents.y = y + height; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_image_clipped_spans (void *abstract_renderer, + int y, int height, + const cairo_half_open_span_t *spans, + unsigned num_spans) +{ + cairo_image_span_renderer_t *r = abstract_renderer; + + assert (num_spans); + + do { + if (! spans[0].inverse) + pixman_image_compositor_blt (r->compositor, + spans[0].x, y, + spans[1].x - spans[0].x, height, + r->opacity * spans[0].coverage); + spans++; + } while (--num_spans > 1); + + r->extents.y = y + height; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_image_finish_unbounded_spans (void *abstract_renderer) +{ + cairo_image_span_renderer_t *r = abstract_renderer; + + if (r->extents.y < r->extents.height) { + pixman_image_compositor_blt (r->compositor, + r->extents.x, r->extents.y, + r->extents.width, + r->extents.height - r->extents.y, + 0); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +span_renderer_init (cairo_abstract_span_renderer_t *_r, + const cairo_composite_rectangles_t *composite, + cairo_bool_t needs_clip) +{ + cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *)_r; + cairo_image_surface_t *dst = (cairo_image_surface_t *)composite->surface; + const cairo_pattern_t *source = &composite->source_pattern.base; + cairo_operator_t op = composite->op; + int src_x, src_y; + int mask_x, mask_y; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + if (op == CAIRO_OPERATOR_CLEAR) { + op = PIXMAN_OP_LERP_CLEAR; + } else if (dst->base.is_clear && + (op == CAIRO_OPERATOR_SOURCE || + op == CAIRO_OPERATOR_OVER || + op == CAIRO_OPERATOR_ADD)) { + op = PIXMAN_OP_SRC; + } else if (op == CAIRO_OPERATOR_SOURCE) { + op = PIXMAN_OP_LERP_SRC; + } else { + op = _pixman_operator (op); + } + + r->compositor = NULL; + r->mask = NULL; + r->src = _pixman_image_for_pattern (dst, source, FALSE, + &composite->unbounded, + &composite->source_sample_area, + &src_x, &src_y); + if (unlikely (r->src == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + r->opacity = 1.0; + if (composite->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID) { + r->opacity = composite->mask_pattern.solid.color.alpha; + } else { + r->mask = _pixman_image_for_pattern (dst, + &composite->mask_pattern.base, + TRUE, + &composite->unbounded, + &composite->mask_sample_area, + &mask_x, &mask_y); + if (unlikely (r->mask == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + /* XXX Component-alpha? */ + if ((dst->base.content & CAIRO_CONTENT_COLOR) == 0 && + _cairo_pattern_is_opaque (source, &composite->source_sample_area)) + { + pixman_image_unref (r->src); + r->src = r->mask; + src_x = mask_x; + src_y = mask_y; + r->mask = NULL; + } + } + + if (composite->is_bounded) { + if (r->opacity == 1.) + r->base.render_rows = _cairo_image_bounded_opaque_spans; + else + r->base.render_rows = _cairo_image_bounded_spans; + r->base.finish = NULL; + } else { + if (needs_clip) + r->base.render_rows = _cairo_image_clipped_spans; + else + r->base.render_rows = _cairo_image_unbounded_spans; + r->base.finish = _cairo_image_finish_unbounded_spans; + r->extents = composite->unbounded; + r->extents.height += r->extents.y; + } + + r->compositor = + pixman_image_create_compositor (op, r->src, r->mask, dst->pixman_image, + composite->unbounded.x + src_x, + composite->unbounded.y + src_y, + composite->unbounded.x + mask_x, + composite->unbounded.y + mask_y, + composite->unbounded.x, + composite->unbounded.y, + composite->unbounded.width, + composite->unbounded.height); + if (unlikely (r->compositor == NULL)) + return CAIRO_INT_STATUS_NOTHING_TO_DO; + + return CAIRO_STATUS_SUCCESS; +} + +static void +span_renderer_fini (cairo_abstract_span_renderer_t *_r, + cairo_int_status_t status) +{ + cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *) _r; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + if (status == CAIRO_INT_STATUS_SUCCESS && r->base.finish) + r->base.finish (r); + + if (r->compositor) + pixman_image_compositor_destroy (r->compositor); + + if (r->src) + pixman_image_unref (r->src); + if (r->mask) + pixman_image_unref (r->mask); +} +#else +typedef struct _cairo_image_span_renderer { + cairo_span_renderer_t base; + + const cairo_composite_rectangles_t *composite; + + float opacity; + uint8_t op; + int bpp; + + pixman_image_t *src, *mask; + union { + struct fill { + ptrdiff_t stride; + uint8_t *data; + uint32_t pixel; + } fill; + struct blit { + int stride; + uint8_t *data; + int src_stride; + uint8_t *src_data; + } blit; + struct composite { + pixman_image_t *dst; + int src_x, src_y; + int mask_x, mask_y; + int run_length; + } composite; + struct finish { + cairo_rectangle_int_t extents; + int src_x, src_y; + ptrdiff_t stride; + uint8_t *data; + } mask; + } u; + uint8_t _buf[0]; +#define SZ_BUF (int)(sizeof (cairo_abstract_span_renderer_t) - sizeof (cairo_image_span_renderer_t)) +} cairo_image_span_renderer_t; +COMPILE_TIME_ASSERT (sizeof (cairo_image_span_renderer_t) <= sizeof (cairo_abstract_span_renderer_t)); + +static cairo_status_t +_cairo_image_spans (void *abstract_renderer, + int y, int height, + const cairo_half_open_span_t *spans, + unsigned num_spans) +{ + cairo_image_span_renderer_t *r = abstract_renderer; + uint8_t *mask, *row; + int len; + + if (num_spans == 0) + return CAIRO_STATUS_SUCCESS; + + mask = r->u.mask.data + (y - r->u.mask.extents.y) * r->u.mask.stride; + mask += spans[0].x - r->u.mask.extents.x; + row = mask; + + do { + len = spans[1].x - spans[0].x; + if (spans[0].coverage) { + *row++ = r->opacity * spans[0].coverage; + if (--len) + memset (row, row[-1], len); + } + row += len; + spans++; + } while (--num_spans > 1); + + len = row - mask; + row = mask; + while (--height) { + mask += r->u.mask.stride; + memcpy (mask, row, len); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_image_spans_and_zero (void *abstract_renderer, + int y, int height, + const cairo_half_open_span_t *spans, + unsigned num_spans) +{ + cairo_image_span_renderer_t *r = abstract_renderer; + uint8_t *mask; + int len; + + mask = r->u.mask.data; + if (y > r->u.mask.extents.y) { + len = (y - r->u.mask.extents.y) * r->u.mask.stride; + memset (mask, 0, len); + mask += len; + } + + r->u.mask.extents.y = y + height; + r->u.mask.data = mask + height * r->u.mask.stride; + if (num_spans == 0) { + memset (mask, 0, height * r->u.mask.stride); + } else { + uint8_t *row = mask; + + if (spans[0].x != r->u.mask.extents.x) { + len = spans[0].x - r->u.mask.extents.x; + memset (row, 0, len); + row += len; + } + + do { + len = spans[1].x - spans[0].x; + *row++ = r->opacity * spans[0].coverage; + if (len > 1) { + memset (row, row[-1], --len); + row += len; + } + spans++; + } while (--num_spans > 1); + + if (spans[0].x != r->u.mask.extents.x + r->u.mask.extents.width) { + len = r->u.mask.extents.x + r->u.mask.extents.width - spans[0].x; + memset (row, 0, len); + } + + row = mask; + while (--height) { + mask += r->u.mask.stride; + memcpy (mask, row, r->u.mask.extents.width); + } + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_image_finish_spans_and_zero (void *abstract_renderer) +{ + cairo_image_span_renderer_t *r = abstract_renderer; + + if (r->u.mask.extents.y < r->u.mask.extents.height) + memset (r->u.mask.data, 0, (r->u.mask.extents.height - r->u.mask.extents.y) * r->u.mask.stride); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_fill8_spans (void *abstract_renderer, int y, int h, + const cairo_half_open_span_t *spans, unsigned num_spans) +{ + cairo_image_span_renderer_t *r = abstract_renderer; + + if (num_spans == 0) + return CAIRO_STATUS_SUCCESS; + + if (likely(h == 1)) { + do { + if (spans[0].coverage) { + int len = spans[1].x - spans[0].x; + uint8_t *d = r->u.fill.data + r->u.fill.stride*y + spans[0].x; + if (len == 1) + *d = r->u.fill.pixel; + else + memset(d, r->u.fill.pixel, len); + } + spans++; + } while (--num_spans > 1); + } else { + do { + if (spans[0].coverage) { + int yy = y, hh = h; + do { + int len = spans[1].x - spans[0].x; + uint8_t *d = r->u.fill.data + r->u.fill.stride*yy + spans[0].x; + if (len == 1) + *d = r->u.fill.pixel; + else + memset(d, r->u.fill.pixel, len); + yy++; + } while (--hh); + } + spans++; + } while (--num_spans > 1); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_fill16_spans (void *abstract_renderer, int y, int h, + const cairo_half_open_span_t *spans, unsigned num_spans) +{ + cairo_image_span_renderer_t *r = abstract_renderer; + + if (num_spans == 0) + return CAIRO_STATUS_SUCCESS; + + if (likely(h == 1)) { + do { + if (spans[0].coverage) { + int len = spans[1].x - spans[0].x; + uint16_t *d = (uint16_t*)(r->u.fill.data + r->u.fill.stride*y + spans[0].x*2); + while (len-- > 0) + *d++ = r->u.fill.pixel; + } + spans++; + } while (--num_spans > 1); + } else { + do { + if (spans[0].coverage) { + int yy = y, hh = h; + do { + int len = spans[1].x - spans[0].x; + uint16_t *d = (uint16_t*)(r->u.fill.data + r->u.fill.stride*yy + spans[0].x*2); + while (len-- > 0) + *d++ = r->u.fill.pixel; + yy++; + } while (--hh); + } + spans++; + } while (--num_spans > 1); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_fill32_spans (void *abstract_renderer, int y, int h, + const cairo_half_open_span_t *spans, unsigned num_spans) +{ + cairo_image_span_renderer_t *r = abstract_renderer; + + if (num_spans == 0) + return CAIRO_STATUS_SUCCESS; + + if (likely(h == 1)) { + do { + if (spans[0].coverage) { + int len = spans[1].x - spans[0].x; + if (len > 32) { + pixman_fill ((uint32_t *)r->u.fill.data, r->u.fill.stride / sizeof(uint32_t), r->bpp, + spans[0].x, y, len, 1, r->u.fill.pixel); + } else { + uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*y + spans[0].x*4); + while (len-- > 0) + *d++ = r->u.fill.pixel; + } + } + spans++; + } while (--num_spans > 1); + } else { + do { + if (spans[0].coverage) { + if (spans[1].x - spans[0].x > 16) { + pixman_fill ((uint32_t *)r->u.fill.data, r->u.fill.stride / sizeof(uint32_t), r->bpp, + spans[0].x, y, spans[1].x - spans[0].x, h, + r->u.fill.pixel); + } else { + int yy = y, hh = h; + do { + int len = spans[1].x - spans[0].x; + uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*yy + spans[0].x*4); + while (len-- > 0) + *d++ = r->u.fill.pixel; + yy++; + } while (--hh); + } + } + spans++; + } while (--num_spans > 1); + } + + return CAIRO_STATUS_SUCCESS; +} + +#if 0 +static cairo_status_t +_fill_spans (void *abstract_renderer, int y, int h, + const cairo_half_open_span_t *spans, unsigned num_spans) +{ + cairo_image_span_renderer_t *r = abstract_renderer; + + if (num_spans == 0) + return CAIRO_STATUS_SUCCESS; + + do { + if (spans[0].coverage) { + pixman_fill ((uint32_t *) r->data, r->stride, r->bpp, + spans[0].x, y, + spans[1].x - spans[0].x, h, + r->pixel); + } + spans++; + } while (--num_spans > 1); + + return CAIRO_STATUS_SUCCESS; +} +#endif + +static cairo_status_t +_blit_spans (void *abstract_renderer, int y, int h, + const cairo_half_open_span_t *spans, unsigned num_spans) +{ + cairo_image_span_renderer_t *r = abstract_renderer; + int cpp; + + if (num_spans == 0) + return CAIRO_STATUS_SUCCESS; + + cpp = r->bpp/8; + if (likely (h == 1)) { + uint8_t *src = r->u.blit.src_data + y*r->u.blit.src_stride; + uint8_t *dst = r->u.blit.data + y*r->u.blit.stride; + do { + if (spans[0].coverage) { + void *s = src + spans[0].x*cpp; + void *d = dst + spans[0].x*cpp; + int len = (spans[1].x - spans[0].x) * cpp; + switch (len) { + case 1: + *(uint8_t *)d = *(uint8_t *)s; + break; + case 2: + *(uint16_t *)d = *(uint16_t *)s; + break; + case 4: + *(uint32_t *)d = *(uint32_t *)s; + break; +#if HAVE_UINT64_T + case 8: + *(uint64_t *)d = *(uint64_t *)s; + break; +#endif + default: + memcpy(d, s, len); + break; + } + } + spans++; + } while (--num_spans > 1); + } else { + do { + if (spans[0].coverage) { + int yy = y, hh = h; + do { + void *src = r->u.blit.src_data + yy*r->u.blit.src_stride + spans[0].x*cpp; + void *dst = r->u.blit.data + yy*r->u.blit.stride + spans[0].x*cpp; + int len = (spans[1].x - spans[0].x) * cpp; + switch (len) { + case 1: + *(uint8_t *)dst = *(uint8_t *)src; + break; + case 2: + *(uint16_t *)dst = *(uint16_t *)src; + break; + case 4: + *(uint32_t *)dst = *(uint32_t *)src; + break; +#if HAVE_UINT64_T + case 8: + *(uint64_t *)dst = *(uint64_t *)src; + break; +#endif + default: + memcpy(dst, src, len); + break; + } + yy++; + } while (--hh); + } + spans++; + } while (--num_spans > 1); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_mono_spans (void *abstract_renderer, int y, int h, + const cairo_half_open_span_t *spans, unsigned num_spans) +{ + cairo_image_span_renderer_t *r = abstract_renderer; + + if (num_spans == 0) + return CAIRO_STATUS_SUCCESS; + + do { + if (spans[0].coverage) { + pixman_image_composite32 (r->op, + r->src, NULL, r->u.composite.dst, + spans[0].x + r->u.composite.src_x, y + r->u.composite.src_y, + 0, 0, + spans[0].x, y, + spans[1].x - spans[0].x, h); + } + spans++; + } while (--num_spans > 1); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_mono_unbounded_spans (void *abstract_renderer, int y, int h, + const cairo_half_open_span_t *spans, unsigned num_spans) +{ + cairo_image_span_renderer_t *r = abstract_renderer; + + if (num_spans == 0) { + pixman_image_composite32 (PIXMAN_OP_CLEAR, + r->src, NULL, r->u.composite.dst, + spans[0].x + r->u.composite.src_x, y + r->u.composite.src_y, + 0, 0, + r->composite->unbounded.x, y, + r->composite->unbounded.width, h); + r->u.composite.mask_y = y + h; + return CAIRO_STATUS_SUCCESS; + } + + if (y != r->u.composite.mask_y) { + pixman_image_composite32 (PIXMAN_OP_CLEAR, + r->src, NULL, r->u.composite.dst, + spans[0].x + r->u.composite.src_x, y + r->u.composite.src_y, + 0, 0, + r->composite->unbounded.x, r->u.composite.mask_y, + r->composite->unbounded.width, y - r->u.composite.mask_y); + } + + if (spans[0].x != r->composite->unbounded.x) { + pixman_image_composite32 (PIXMAN_OP_CLEAR, + r->src, NULL, r->u.composite.dst, + spans[0].x + r->u.composite.src_x, y + r->u.composite.src_y, + 0, 0, + r->composite->unbounded.x, y, + spans[0].x - r->composite->unbounded.x, h); + } + + do { + int op = spans[0].coverage ? r->op : PIXMAN_OP_CLEAR; + pixman_image_composite32 (op, + r->src, NULL, r->u.composite.dst, + spans[0].x + r->u.composite.src_x, y + r->u.composite.src_y, + 0, 0, + spans[0].x, y, + spans[1].x - spans[0].x, h); + spans++; + } while (--num_spans > 1); + + if (spans[0].x != r->composite->unbounded.x + r->composite->unbounded.width) { + pixman_image_composite32 (PIXMAN_OP_CLEAR, + r->src, NULL, r->u.composite.dst, + spans[0].x + r->u.composite.src_x, y + r->u.composite.src_y, + 0, 0, + spans[0].x, y, + r->composite->unbounded.x + r->composite->unbounded.width - spans[0].x, h); + } + + r->u.composite.mask_y = y + h; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_mono_finish_unbounded_spans (void *abstract_renderer) +{ + cairo_image_span_renderer_t *r = abstract_renderer; + + if (r->u.composite.mask_y < r->composite->unbounded.y + r->composite->unbounded.height) { + pixman_image_composite32 (PIXMAN_OP_CLEAR, + r->src, NULL, r->u.composite.dst, + r->composite->unbounded.x + r->u.composite.src_x, r->u.composite.mask_y + r->u.composite.src_y, + 0, 0, + r->composite->unbounded.x, r->u.composite.mask_y, + r->composite->unbounded.width, + r->composite->unbounded.y + r->composite->unbounded.height - r->u.composite.mask_y); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +mono_renderer_init (cairo_image_span_renderer_t *r, + const cairo_composite_rectangles_t *composite, + cairo_antialias_t antialias, + cairo_bool_t needs_clip) +{ + cairo_image_surface_t *dst = (cairo_image_surface_t *)composite->surface; + + if (antialias != CAIRO_ANTIALIAS_NONE) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (!_cairo_pattern_is_opaque_solid (&composite->mask_pattern.base)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + r->base.render_rows = NULL; + if (composite->source_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID) { + const cairo_color_t *color; + + color = &composite->source_pattern.solid.color; + if (composite->op == CAIRO_OPERATOR_CLEAR) + color = CAIRO_COLOR_TRANSPARENT; + + if (fill_reduces_to_source (composite->op, color, dst, &r->u.fill.pixel)) { + /* Use plain C for the fill operations as the span length is + * typically small, too small to payback the startup overheads of + * using SSE2 etc. + */ + switch (PIXMAN_FORMAT_BPP(dst->pixman_format)) { + case 8: r->base.render_rows = _fill8_spans; break; + case 16: r->base.render_rows = _fill16_spans; break; + case 32: r->base.render_rows = _fill32_spans; break; + default: break; + } + r->u.fill.data = dst->data; + r->u.fill.stride = dst->stride; + } + } else if ((composite->op == CAIRO_OPERATOR_SOURCE || + (composite->op == CAIRO_OPERATOR_OVER && + (dst->base.is_clear || (dst->base.content & CAIRO_CONTENT_ALPHA) == 0))) && + composite->source_pattern.base.type == CAIRO_PATTERN_TYPE_SURFACE && + composite->source_pattern.surface.surface->backend->type == CAIRO_SURFACE_TYPE_IMAGE && + to_image_surface(composite->source_pattern.surface.surface)->format == dst->format) + { + cairo_image_surface_t *src = + to_image_surface(composite->source_pattern.surface.surface); + int tx, ty; + + if (_cairo_matrix_is_integer_translation(&composite->source_pattern.base.matrix, + &tx, &ty) && + composite->bounded.x + tx >= 0 && + composite->bounded.y + ty >= 0 && + composite->bounded.x + composite->bounded.width + tx <= src->width && + composite->bounded.y + composite->bounded.height + ty <= src->height) { + + r->u.blit.stride = dst->stride; + r->u.blit.data = dst->data; + r->u.blit.src_stride = src->stride; + r->u.blit.src_data = src->data + src->stride * ty + tx * 4; + r->base.render_rows = _blit_spans; + } + } + + if (r->base.render_rows == NULL) { + r->src = _pixman_image_for_pattern (dst, &composite->source_pattern.base, FALSE, + &composite->unbounded, + &composite->source_sample_area, + &r->u.composite.src_x, &r->u.composite.src_y); + if (unlikely (r->src == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + r->u.composite.dst = to_pixman_image (composite->surface); + r->op = _pixman_operator (composite->op); + if (composite->is_bounded == 0) { + r->base.render_rows = _mono_unbounded_spans; + r->base.finish = _mono_finish_unbounded_spans; + r->u.composite.mask_y = composite->unbounded.y; + } else + r->base.render_rows = _mono_spans; + } + r->bpp = PIXMAN_FORMAT_BPP(dst->pixman_format); + + return CAIRO_INT_STATUS_SUCCESS; +} + +#define ONE_HALF 0x7f +#define RB_MASK 0x00ff00ff +#define RB_ONE_HALF 0x007f007f +#define RB_MASK_PLUS_ONE 0x01000100 +#define G_SHIFT 8 +static inline uint32_t +mul8x2_8 (uint32_t a, uint8_t b) +{ + uint32_t t = (a & RB_MASK) * b + RB_ONE_HALF; + return ((t + ((t >> G_SHIFT) & RB_MASK)) >> G_SHIFT) & RB_MASK; +} + +static inline uint32_t +add8x2_8x2 (uint32_t a, uint32_t b) +{ + uint32_t t = a + b; + t |= RB_MASK_PLUS_ONE - ((t >> G_SHIFT) & RB_MASK); + return t & RB_MASK; +} + +static inline uint8_t +mul8_8 (uint8_t a, uint8_t b) +{ + uint16_t t = a * (uint16_t)b + ONE_HALF; + return ((t >> G_SHIFT) + t) >> G_SHIFT; +} + +static inline uint32_t +lerp8x4 (uint32_t src, uint8_t a, uint32_t dst) +{ + return (add8x2_8x2 (mul8x2_8 (src, a), + mul8x2_8 (dst, ~a)) | + add8x2_8x2 (mul8x2_8 (src >> G_SHIFT, a), + mul8x2_8 (dst >> G_SHIFT, ~a)) << G_SHIFT); +} + +static cairo_status_t +_fill_a8_lerp_opaque_spans (void *abstract_renderer, int y, int h, + const cairo_half_open_span_t *spans, unsigned num_spans) +{ + cairo_image_span_renderer_t *r = abstract_renderer; + + if (num_spans == 0) + return CAIRO_STATUS_SUCCESS; + + if (likely(h == 1)) { + uint8_t *d = r->u.fill.data + r->u.fill.stride*y; + do { + uint8_t a = spans[0].coverage; + if (a) { + int len = spans[1].x - spans[0].x; + if (a == 0xff) { + memset(d + spans[0].x, r->u.fill.pixel, len); + } else { + uint8_t s = mul8_8(a, r->u.fill.pixel); + uint8_t *dst = d + spans[0].x; + a = ~a; + while (len-- > 0) { + uint8_t t = mul8_8(*dst, a); + *dst++ = t + s; + } + } + } + spans++; + } while (--num_spans > 1); + } else { + do { + uint8_t a = spans[0].coverage; + if (a) { + int yy = y, hh = h; + if (a == 0xff) { + do { + int len = spans[1].x - spans[0].x; + uint8_t *d = r->u.fill.data + r->u.fill.stride*yy + spans[0].x; + memset(d, r->u.fill.pixel, len); + yy++; + } while (--hh); + } else { + uint8_t s = mul8_8(a, r->u.fill.pixel); + a = ~a; + do { + int len = spans[1].x - spans[0].x; + uint8_t *d = r->u.fill.data + r->u.fill.stride*yy + spans[0].x; + while (len-- > 0) { + uint8_t t = mul8_8(*d, a); + *d++ = t + s; + } + yy++; + } while (--hh); + } + } + spans++; + } while (--num_spans > 1); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_fill_xrgb32_lerp_opaque_spans (void *abstract_renderer, int y, int h, + const cairo_half_open_span_t *spans, unsigned num_spans) +{ + cairo_image_span_renderer_t *r = abstract_renderer; + + if (num_spans == 0) + return CAIRO_STATUS_SUCCESS; + + if (likely(h == 1)) { + do { + uint8_t a = spans[0].coverage; + if (a) { + int len = spans[1].x - spans[0].x; + uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*y + spans[0].x*4); + if (a == 0xff) { + if (len > 31) { + pixman_fill ((uint32_t *)r->u.fill.data, r->u.fill.stride / sizeof(uint32_t), 32, + spans[0].x, y, len, 1, r->u.fill.pixel); + } else { + uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*y + spans[0].x*4); + while (len-- > 0) + *d++ = r->u.fill.pixel; + } + } else while (len-- > 0) { + *d = lerp8x4 (r->u.fill.pixel, a, *d); + d++; + } + } + spans++; + } while (--num_spans > 1); + } else { + do { + uint8_t a = spans[0].coverage; + if (a) { + if (a == 0xff) { + if (spans[1].x - spans[0].x > 16) { + pixman_fill ((uint32_t *)r->u.fill.data, r->u.fill.stride / sizeof(uint32_t), 32, + spans[0].x, y, spans[1].x - spans[0].x, h, + r->u.fill.pixel); + } else { + int yy = y, hh = h; + do { + int len = spans[1].x - spans[0].x; + uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*yy + spans[0].x*4); + while (len-- > 0) + *d++ = r->u.fill.pixel; + yy++; + } while (--hh); + } + } else { + int yy = y, hh = h; + do { + int len = spans[1].x - spans[0].x; + uint32_t *d = (uint32_t *)(r->u.fill.data + r->u.fill.stride*yy + spans[0].x*4); + while (len-- > 0) { + *d = lerp8x4 (r->u.fill.pixel, a, *d); + d++; + } + yy++; + } while (--hh); + } + } + spans++; + } while (--num_spans > 1); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_fill_a8_lerp_spans (void *abstract_renderer, int y, int h, + const cairo_half_open_span_t *spans, unsigned num_spans) +{ + cairo_image_span_renderer_t *r = abstract_renderer; + + if (num_spans == 0) + return CAIRO_STATUS_SUCCESS; + + if (likely(h == 1)) { + do { + uint8_t a = mul8_8 (spans[0].coverage, r->bpp); + if (a) { + int len = spans[1].x - spans[0].x; + uint8_t *d = r->u.fill.data + r->u.fill.stride*y + spans[0].x; + uint16_t p = (uint16_t)a * r->u.fill.pixel + 0x7f; + uint16_t ia = ~a; + while (len-- > 0) { + uint16_t t = *d*ia + p; + *d++ = (t + (t>>8)) >> 8; + } + } + spans++; + } while (--num_spans > 1); + } else { + do { + uint8_t a = mul8_8 (spans[0].coverage, r->bpp); + if (a) { + int yy = y, hh = h; + uint16_t p = (uint16_t)a * r->u.fill.pixel + 0x7f; + uint16_t ia = ~a; + do { + int len = spans[1].x - spans[0].x; + uint8_t *d = r->u.fill.data + r->u.fill.stride*yy + spans[0].x; + while (len-- > 0) { + uint16_t t = *d*ia + p; + *d++ = (t + (t>>8)) >> 8; + } + yy++; + } while (--hh); + } + spans++; + } while (--num_spans > 1); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_fill_xrgb32_lerp_spans (void *abstract_renderer, int y, int h, + const cairo_half_open_span_t *spans, unsigned num_spans) +{ + cairo_image_span_renderer_t *r = abstract_renderer; + + if (num_spans == 0) + return CAIRO_STATUS_SUCCESS; + + if (likely(h == 1)) { + do { + uint8_t a = mul8_8 (spans[0].coverage, r->bpp); + if (a) { + int len = spans[1].x - spans[0].x; + uint32_t *d = (uint32_t*)(r->u.fill.data + r->u.fill.stride*y + spans[0].x*4); + while (len-- > 0) { + *d = lerp8x4 (r->u.fill.pixel, a, *d); + d++; + } + } + spans++; + } while (--num_spans > 1); + } else { + do { + uint8_t a = mul8_8 (spans[0].coverage, r->bpp); + if (a) { + int yy = y, hh = h; + do { + int len = spans[1].x - spans[0].x; + uint32_t *d = (uint32_t *)(r->u.fill.data + r->u.fill.stride*yy + spans[0].x*4); + while (len-- > 0) { + *d = lerp8x4 (r->u.fill.pixel, a, *d); + d++; + } + yy++; + } while (--hh); + } + spans++; + } while (--num_spans > 1); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_blit_xrgb32_lerp_spans (void *abstract_renderer, int y, int h, + const cairo_half_open_span_t *spans, unsigned num_spans) +{ + cairo_image_span_renderer_t *r = abstract_renderer; + + if (num_spans == 0) + return CAIRO_STATUS_SUCCESS; + + if (likely(h == 1)) { + uint8_t *src = r->u.blit.src_data + y*r->u.blit.src_stride; + uint8_t *dst = r->u.blit.data + y*r->u.blit.stride; + do { + uint8_t a = mul8_8 (spans[0].coverage, r->bpp); + if (a) { + uint32_t *s = (uint32_t*)src + spans[0].x; + uint32_t *d = (uint32_t*)dst + spans[0].x; + int len = spans[1].x - spans[0].x; + if (a == 0xff) { + if (len == 1) + *d = *s; + else + memcpy(d, s, len*4); + } else { + while (len-- > 0) { + *d = lerp8x4 (*s, a, *d); + s++, d++; + } + } + } + spans++; + } while (--num_spans > 1); + } else { + do { + uint8_t a = mul8_8 (spans[0].coverage, r->bpp); + if (a) { + int yy = y, hh = h; + do { + uint32_t *s = (uint32_t *)(r->u.blit.src_data + yy*r->u.blit.src_stride + spans[0].x * 4); + uint32_t *d = (uint32_t *)(r->u.blit.data + yy*r->u.blit.stride + spans[0].x * 4); + int len = spans[1].x - spans[0].x; + if (a == 0xff) { + if (len == 1) + *d = *s; + else + memcpy(d, s, len * 4); + } else { + while (len-- > 0) { + *d = lerp8x4 (*s, a, *d); + s++, d++; + } + } + yy++; + } while (--hh); + } + spans++; + } while (--num_spans > 1); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_inplace_spans (void *abstract_renderer, + int y, int h, + const cairo_half_open_span_t *spans, + unsigned num_spans) +{ + cairo_image_span_renderer_t *r = abstract_renderer; + uint8_t *mask; + int x0, x1; + + if (num_spans == 0) + return CAIRO_STATUS_SUCCESS; + + if (num_spans == 2 && spans[0].coverage == 0xff) { + pixman_image_composite32 (r->op, r->src, NULL, r->u.composite.dst, + spans[0].x + r->u.composite.src_x, + y + r->u.composite.src_y, + 0, 0, + spans[0].x, y, + spans[1].x - spans[0].x, h); + return CAIRO_STATUS_SUCCESS; + } + + mask = (uint8_t *)pixman_image_get_data (r->mask); + x1 = x0 = spans[0].x; + do { + int len = spans[1].x - spans[0].x; + *mask++ = spans[0].coverage; + if (len > 1) { + if (len >= r->u.composite.run_length && spans[0].coverage == 0xff) { + if (x1 != x0) { + pixman_image_composite32 (r->op, r->src, r->mask, r->u.composite.dst, + x0 + r->u.composite.src_x, + y + r->u.composite.src_y, + 0, 0, + x0, y, + x1 - x0, h); + } + pixman_image_composite32 (r->op, r->src, NULL, r->u.composite.dst, + spans[0].x + r->u.composite.src_x, + y + r->u.composite.src_y, + 0, 0, + spans[0].x, y, + len, h); + mask = (uint8_t *)pixman_image_get_data (r->mask); + x0 = spans[1].x; + } else if (spans[0].coverage == 0x0 && + x1 - x0 > r->u.composite.run_length) { + pixman_image_composite32 (r->op, r->src, r->mask, r->u.composite.dst, + x0 + r->u.composite.src_x, + y + r->u.composite.src_y, + 0, 0, + x0, y, + x1 - x0, h); + mask = (uint8_t *)pixman_image_get_data (r->mask); + x0 = spans[1].x; + }else { + memset (mask, spans[0].coverage, --len); + mask += len; + } + } + x1 = spans[1].x; + spans++; + } while (--num_spans > 1); + + if (x1 != x0) { + pixman_image_composite32 (r->op, r->src, r->mask, r->u.composite.dst, + x0 + r->u.composite.src_x, + y + r->u.composite.src_y, + 0, 0, + x0, y, + x1 - x0, h); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_inplace_opacity_spans (void *abstract_renderer, int y, int h, + const cairo_half_open_span_t *spans, + unsigned num_spans) +{ + cairo_image_span_renderer_t *r = abstract_renderer; + uint8_t *mask; + int x0, x1; + + if (num_spans == 0) + return CAIRO_STATUS_SUCCESS; + + mask = (uint8_t *)pixman_image_get_data (r->mask); + x1 = x0 = spans[0].x; + do { + int len = spans[1].x - spans[0].x; + uint8_t m = mul8_8(spans[0].coverage, r->bpp); + *mask++ = m; + if (len > 1) { + if (m == 0 && + x1 - x0 > r->u.composite.run_length) { + pixman_image_composite32 (r->op, r->src, r->mask, r->u.composite.dst, + x0 + r->u.composite.src_x, + y + r->u.composite.src_y, + 0, 0, + x0, y, + x1 - x0, h); + mask = (uint8_t *)pixman_image_get_data (r->mask); + x0 = spans[1].x; + }else { + memset (mask, m, --len); + mask += len; + } + } + x1 = spans[1].x; + spans++; + } while (--num_spans > 1); + + if (x1 != x0) { + pixman_image_composite32 (r->op, r->src, r->mask, r->u.composite.dst, + x0 + r->u.composite.src_x, + y + r->u.composite.src_y, + 0, 0, + x0, y, + x1 - x0, h); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_inplace_src_spans (void *abstract_renderer, int y, int h, + const cairo_half_open_span_t *spans, + unsigned num_spans) +{ + cairo_image_span_renderer_t *r = abstract_renderer; + uint8_t *m, *base = (uint8_t*)pixman_image_get_data(r->mask); + int x0; + + if (num_spans == 0) + return CAIRO_STATUS_SUCCESS; + + x0 = spans[0].x; + m = base; + do { + int len = spans[1].x - spans[0].x; + if (len >= r->u.composite.run_length && spans[0].coverage == 0xff) { + if (spans[0].x != x0) { +#if PIXMAN_HAS_OP_LERP + pixman_image_composite32 (PIXMAN_OP_LERP_SRC, + r->src, r->mask, r->u.composite.dst, + x0 + r->u.composite.src_x, + y + r->u.composite.src_y, + 0, 0, + x0, y, + spans[0].x - x0, h); +#else + pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE, + r->mask, NULL, r->u.composite.dst, + 0, 0, + 0, 0, + x0, y, + spans[0].x - x0, h); + pixman_image_composite32 (PIXMAN_OP_ADD, + r->src, r->mask, r->u.composite.dst, + x0 + r->u.composite.src_x, + y + r->u.composite.src_y, + 0, 0, + x0, y, + spans[0].x - x0, h); +#endif + } + + pixman_image_composite32 (PIXMAN_OP_SRC, + r->src, NULL, r->u.composite.dst, + spans[0].x + r->u.composite.src_x, + y + r->u.composite.src_y, + 0, 0, + spans[0].x, y, + spans[1].x - spans[0].x, h); + + m = base; + x0 = spans[1].x; + } else if (spans[0].coverage == 0x0) { + if (spans[0].x != x0) { +#if PIXMAN_HAS_OP_LERP + pixman_image_composite32 (PIXMAN_OP_LERP_SRC, + r->src, r->mask, r->u.composite.dst, + x0 + r->u.composite.src_x, + y + r->u.composite.src_y, + 0, 0, + x0, y, + spans[0].x - x0, h); +#else + pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE, + r->mask, NULL, r->u.composite.dst, + 0, 0, + 0, 0, + x0, y, + spans[0].x - x0, h); + pixman_image_composite32 (PIXMAN_OP_ADD, + r->src, r->mask, r->u.composite.dst, + x0 + r->u.composite.src_x, + y + r->u.composite.src_y, + 0, 0, + x0, y, + spans[0].x - x0, h); +#endif + } + + m = base; + x0 = spans[1].x; + } else { + *m++ = spans[0].coverage; + if (len > 1) { + memset (m, spans[0].coverage, --len); + m += len; + } + } + spans++; + } while (--num_spans > 1); + + if (spans[0].x != x0) { +#if PIXMAN_HAS_OP_LERP + pixman_image_composite32 (PIXMAN_OP_LERP_SRC, + r->src, r->mask, r->u.composite.dst, + x0 + r->u.composite.src_x, + y + r->u.composite.src_y, + 0, 0, + x0, y, + spans[0].x - x0, h); +#else + pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE, + r->mask, NULL, r->u.composite.dst, + 0, 0, + 0, 0, + x0, y, + spans[0].x - x0, h); + pixman_image_composite32 (PIXMAN_OP_ADD, + r->src, r->mask, r->u.composite.dst, + x0 + r->u.composite.src_x, + y + r->u.composite.src_y, + 0, 0, + x0, y, + spans[0].x - x0, h); +#endif + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_inplace_src_opacity_spans (void *abstract_renderer, int y, int h, + const cairo_half_open_span_t *spans, + unsigned num_spans) +{ + cairo_image_span_renderer_t *r = abstract_renderer; + uint8_t *mask; + int x0; + + if (num_spans == 0) + return CAIRO_STATUS_SUCCESS; + + x0 = spans[0].x; + mask = (uint8_t *)pixman_image_get_data (r->mask); + do { + int len = spans[1].x - spans[0].x; + uint8_t m = mul8_8(spans[0].coverage, r->bpp); + if (m == 0) { + if (spans[0].x != x0) { +#if PIXMAN_HAS_OP_LERP + pixman_image_composite32 (PIXMAN_OP_LERP_SRC, + r->src, r->mask, r->u.composite.dst, + x0 + r->u.composite.src_x, + y + r->u.composite.src_y, + 0, 0, + x0, y, + spans[0].x - x0, h); +#else + pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE, + r->mask, NULL, r->u.composite.dst, + 0, 0, + 0, 0, + x0, y, + spans[0].x - x0, h); + pixman_image_composite32 (PIXMAN_OP_ADD, + r->src, r->mask, r->u.composite.dst, + x0 + r->u.composite.src_x, + y + r->u.composite.src_y, + 0, 0, + x0, y, + spans[0].x - x0, h); +#endif + } + + mask = (uint8_t *)pixman_image_get_data (r->mask); + x0 = spans[1].x; + } else { + *mask++ = m; + if (len > 1) { + memset (mask, m, --len); + mask += len; + } + } + spans++; + } while (--num_spans > 1); + + if (spans[0].x != x0) { +#if PIXMAN_HAS_OP_LERP + pixman_image_composite32 (PIXMAN_OP_LERP_SRC, + r->src, r->mask, r->u.composite.dst, + x0 + r->u.composite.src_x, + y + r->u.composite.src_y, + 0, 0, + x0, y, + spans[0].x - x0, h); +#else + pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE, + r->mask, NULL, r->u.composite.dst, + 0, 0, + 0, 0, + x0, y, + spans[0].x - x0, h); + pixman_image_composite32 (PIXMAN_OP_ADD, + r->src, r->mask, r->u.composite.dst, + x0 + r->u.composite.src_x, + y + r->u.composite.src_y, + 0, 0, + x0, y, + spans[0].x - x0, h); +#endif + } + + return CAIRO_STATUS_SUCCESS; +} + +static void free_pixels (pixman_image_t *image, void *data) +{ + free (data); +} + +static cairo_int_status_t +inplace_renderer_init (cairo_image_span_renderer_t *r, + const cairo_composite_rectangles_t *composite, + cairo_antialias_t antialias, + cairo_bool_t needs_clip) +{ + cairo_image_surface_t *dst = (cairo_image_surface_t *)composite->surface; + uint8_t *buf; + + if (composite->mask_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID) + return CAIRO_INT_STATUS_UNSUPPORTED; + + r->base.render_rows = NULL; + r->bpp = composite->mask_pattern.solid.color.alpha_short >> 8; + + if (composite->source_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID) { + const cairo_color_t *color; + + color = &composite->source_pattern.solid.color; + if (composite->op == CAIRO_OPERATOR_CLEAR) + color = CAIRO_COLOR_TRANSPARENT; + + if (fill_reduces_to_source (composite->op, color, dst, &r->u.fill.pixel)) { + /* Use plain C for the fill operations as the span length is + * typically small, too small to payback the startup overheads of + * using SSE2 etc. + */ + if (r->bpp == 0xff) { + switch (dst->format) { + case CAIRO_FORMAT_A8: + r->base.render_rows = _fill_a8_lerp_opaque_spans; + break; + case CAIRO_FORMAT_RGB24: + case CAIRO_FORMAT_ARGB32: + r->base.render_rows = _fill_xrgb32_lerp_opaque_spans; + break; + case CAIRO_FORMAT_A1: + case CAIRO_FORMAT_RGB16_565: + case CAIRO_FORMAT_RGB30: + case CAIRO_FORMAT_RGB96F: + case CAIRO_FORMAT_RGBA128F: + case CAIRO_FORMAT_INVALID: + default: break; + } + } else { + switch (dst->format) { + case CAIRO_FORMAT_A8: + r->base.render_rows = _fill_a8_lerp_spans; + break; + case CAIRO_FORMAT_RGB24: + case CAIRO_FORMAT_ARGB32: + r->base.render_rows = _fill_xrgb32_lerp_spans; + break; + case CAIRO_FORMAT_A1: + case CAIRO_FORMAT_RGB16_565: + case CAIRO_FORMAT_RGB30: + case CAIRO_FORMAT_RGB96F: + case CAIRO_FORMAT_RGBA128F: + case CAIRO_FORMAT_INVALID: + default: break; + } + } + r->u.fill.data = dst->data; + r->u.fill.stride = dst->stride; + } + } else if ((dst->format == CAIRO_FORMAT_ARGB32 || dst->format == CAIRO_FORMAT_RGB24) && + (composite->op == CAIRO_OPERATOR_SOURCE || + (composite->op == CAIRO_OPERATOR_OVER && + (dst->base.is_clear || (dst->base.content & CAIRO_CONTENT_ALPHA) == 0))) && + composite->source_pattern.base.type == CAIRO_PATTERN_TYPE_SURFACE && + composite->source_pattern.surface.surface->backend->type == CAIRO_SURFACE_TYPE_IMAGE && + to_image_surface(composite->source_pattern.surface.surface)->format == dst->format) + { + cairo_image_surface_t *src = + to_image_surface(composite->source_pattern.surface.surface); + int tx, ty; + + if (_cairo_matrix_is_integer_translation(&composite->source_pattern.base.matrix, + &tx, &ty) && + composite->bounded.x + tx >= 0 && + composite->bounded.y + ty >= 0 && + composite->bounded.x + composite->bounded.width + tx <= src->width && + composite->bounded.y + composite->bounded.height + ty <= src->height) { + + assert(PIXMAN_FORMAT_BPP(dst->pixman_format) == 32); + r->u.blit.stride = dst->stride; + r->u.blit.data = dst->data; + r->u.blit.src_stride = src->stride; + r->u.blit.src_data = src->data + src->stride * ty + tx * 4; + r->base.render_rows = _blit_xrgb32_lerp_spans; + } + } + if (r->base.render_rows == NULL) { + const cairo_pattern_t *src = &composite->source_pattern.base; + unsigned int width; + + if (composite->is_bounded == 0) + return CAIRO_INT_STATUS_UNSUPPORTED; + + r->base.render_rows = r->bpp == 0xff ? _inplace_spans : _inplace_opacity_spans; + width = (composite->bounded.width + 3) & ~3; + + r->u.composite.run_length = 8; + if (src->type == CAIRO_PATTERN_TYPE_LINEAR || + src->type == CAIRO_PATTERN_TYPE_RADIAL) + r->u.composite.run_length = 256; + if (dst->base.is_clear && + (composite->op == CAIRO_OPERATOR_SOURCE || + composite->op == CAIRO_OPERATOR_OVER || + composite->op == CAIRO_OPERATOR_ADD)) { + r->op = PIXMAN_OP_SRC; + } else if (composite->op == CAIRO_OPERATOR_SOURCE) { + r->base.render_rows = r->bpp == 0xff ? _inplace_src_spans : _inplace_src_opacity_spans; + r->u.composite.mask_y = r->composite->unbounded.y; + width = (composite->unbounded.width + 3) & ~3; + } else if (composite->op == CAIRO_OPERATOR_CLEAR) { + r->op = PIXMAN_OP_OUT_REVERSE; + src = NULL; + } else { + r->op = _pixman_operator (composite->op); + } + + r->src = _pixman_image_for_pattern (dst, src, FALSE, + &composite->bounded, + &composite->source_sample_area, + &r->u.composite.src_x, &r->u.composite.src_y); + if (unlikely (r->src == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + /* Create an effectively unbounded mask by repeating the single line */ + buf = r->_buf; + if (width > SZ_BUF) { + buf = _cairo_malloc (width); + if (unlikely (buf == NULL)) { + pixman_image_unref (r->src); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + } + r->mask = pixman_image_create_bits (PIXMAN_a8, + width, composite->unbounded.height, + (uint32_t *)buf, 0); + if (unlikely (r->mask == NULL)) { + pixman_image_unref (r->src); + if (buf != r->_buf) + free (buf); + return _cairo_error(CAIRO_STATUS_NO_MEMORY); + } + + if (buf != r->_buf) + pixman_image_set_destroy_function (r->mask, free_pixels, buf); + + r->u.composite.dst = dst->pixman_image; + } + + return CAIRO_INT_STATUS_SUCCESS; +} + +static cairo_int_status_t +span_renderer_init (cairo_abstract_span_renderer_t *_r, + const cairo_composite_rectangles_t *composite, + cairo_antialias_t antialias, + cairo_bool_t needs_clip) +{ + cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *)_r; + cairo_image_surface_t *dst = (cairo_image_surface_t *)composite->surface; + const cairo_pattern_t *source = &composite->source_pattern.base; + cairo_operator_t op = composite->op; + cairo_int_status_t status; + + TRACE ((stderr, "%s: antialias=%d, needs_clip=%d\n", __FUNCTION__, + antialias, needs_clip)); + + if (needs_clip) + return CAIRO_INT_STATUS_UNSUPPORTED; + + r->composite = composite; + r->mask = NULL; + r->src = NULL; + r->base.finish = NULL; + + status = mono_renderer_init (r, composite, antialias, needs_clip); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + status = inplace_renderer_init (r, composite, antialias, needs_clip); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + r->bpp = 0; + + if (op == CAIRO_OPERATOR_CLEAR) { +#if PIXMAN_HAS_OP_LERP + op = PIXMAN_OP_LERP_CLEAR; +#else + source = &_cairo_pattern_white.base; + op = PIXMAN_OP_OUT_REVERSE; +#endif + } else if (dst->base.is_clear && + (op == CAIRO_OPERATOR_SOURCE || + op == CAIRO_OPERATOR_OVER || + op == CAIRO_OPERATOR_ADD)) { + op = PIXMAN_OP_SRC; + } else if (op == CAIRO_OPERATOR_SOURCE) { + if (_cairo_pattern_is_opaque (&composite->source_pattern.base, + &composite->source_sample_area)) + { + op = PIXMAN_OP_OVER; + } + else + { +#if PIXMAN_HAS_OP_LERP + op = PIXMAN_OP_LERP_SRC; +#else + return CAIRO_INT_STATUS_UNSUPPORTED; +#endif + } + } else { + op = _pixman_operator (op); + } + r->op = op; + + r->src = _pixman_image_for_pattern (dst, source, FALSE, + &composite->unbounded, + &composite->source_sample_area, + &r->u.mask.src_x, &r->u.mask.src_y); + if (unlikely (r->src == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + r->opacity = 1.0; + if (composite->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID) { + r->opacity = composite->mask_pattern.solid.color.alpha; + } else { + pixman_image_t *mask; + int mask_x, mask_y; + + mask = _pixman_image_for_pattern (dst, + &composite->mask_pattern.base, + TRUE, + &composite->unbounded, + &composite->mask_sample_area, + &mask_x, &mask_y); + if (unlikely (mask == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + /* XXX Component-alpha? */ + if ((dst->base.content & CAIRO_CONTENT_COLOR) == 0 && + _cairo_pattern_is_opaque (source, &composite->source_sample_area)) + { + pixman_image_unref (r->src); + r->src = mask; + r->u.mask.src_x = mask_x; + r->u.mask.src_y = mask_y; + mask = NULL; + } + + if (mask) { + pixman_image_unref (mask); + return CAIRO_INT_STATUS_UNSUPPORTED; + } + } + + r->u.mask.extents = composite->unbounded; + r->u.mask.stride = (r->u.mask.extents.width + 3) & ~3; + if (r->u.mask.extents.height * r->u.mask.stride > SZ_BUF) { + r->mask = pixman_image_create_bits (PIXMAN_a8, + r->u.mask.extents.width, + r->u.mask.extents.height, + NULL, 0); + + r->base.render_rows = _cairo_image_spans; + r->base.finish = NULL; + } else { + r->mask = pixman_image_create_bits (PIXMAN_a8, + r->u.mask.extents.width, + r->u.mask.extents.height, + (uint32_t *)r->_buf, r->u.mask.stride); + + r->base.render_rows = _cairo_image_spans_and_zero; + r->base.finish = _cairo_image_finish_spans_and_zero; + } + if (unlikely (r->mask == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + r->u.mask.data = (uint8_t *) pixman_image_get_data (r->mask); + r->u.mask.stride = pixman_image_get_stride (r->mask); + + r->u.mask.extents.height += r->u.mask.extents.y; + return CAIRO_STATUS_SUCCESS; +} + +static void +span_renderer_fini (cairo_abstract_span_renderer_t *_r, + cairo_int_status_t status) +{ + cairo_image_span_renderer_t *r = (cairo_image_span_renderer_t *) _r; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { + if (r->base.finish) + r->base.finish (r); + } + if (likely (status == CAIRO_INT_STATUS_SUCCESS && r->bpp == 0)) { + const cairo_composite_rectangles_t *composite = r->composite; + + pixman_image_composite32 (r->op, r->src, r->mask, + to_pixman_image (composite->surface), + composite->unbounded.x + r->u.mask.src_x, + composite->unbounded.y + r->u.mask.src_y, + 0, 0, + composite->unbounded.x, + composite->unbounded.y, + composite->unbounded.width, + composite->unbounded.height); + } + + if (r->src) + pixman_image_unref (r->src); + if (r->mask) + pixman_image_unref (r->mask); +} +#endif + +const cairo_compositor_t * +_cairo_image_spans_compositor_get (void) +{ + static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT; + static cairo_spans_compositor_t spans; + static cairo_compositor_t shape; + + if (_cairo_atomic_init_once_enter(&once)) { + _cairo_shape_mask_compositor_init (&shape, + _cairo_image_traps_compositor_get()); + shape.glyphs = NULL; + + _cairo_spans_compositor_init (&spans, &shape); + + spans.flags = 0; +#if PIXMAN_HAS_OP_LERP + spans.flags |= CAIRO_SPANS_COMPOSITOR_HAS_LERP; +#endif + + //spans.acquire = acquire; + //spans.release = release; + spans.fill_boxes = fill_boxes; + spans.draw_image_boxes = draw_image_boxes; + //spans.copy_boxes = copy_boxes; + spans.pattern_to_surface = _cairo_image_source_create_for_pattern; + //spans.check_composite_boxes = check_composite_boxes; + spans.composite_boxes = composite_boxes; + //spans.check_span_renderer = check_span_renderer; + spans.renderer_init = span_renderer_init; + spans.renderer_fini = span_renderer_fini; + + _cairo_atomic_init_once_leave(&once); + } + + return &spans.base; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-image-info-private.h b/local/recipes/libs/cairo/source/src/cairo-image-info-private.h new file mode 100644 index 0000000000..3808d07b3d --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-image-info-private.h @@ -0,0 +1,68 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2008 Adrian Johnson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Adrian Johnson. + * + * Contributor(s): + * Adrian Johnson + */ + +#ifndef CAIRO_IMAGE_INFO_PRIVATE_H +#define CAIRO_IMAGE_INFO_PRIVATE_H + +#include "cairoint.h" + +typedef struct _cairo_image_info { + int width; + int height; + int num_components; + int bits_per_component; +} cairo_image_info_t; + +cairo_private cairo_int_status_t +_cairo_image_info_get_jpeg_info (cairo_image_info_t *info, + const unsigned char *data, + unsigned long length); + +cairo_private cairo_int_status_t +_cairo_image_info_get_jpx_info (cairo_image_info_t *info, + const unsigned char *data, + unsigned long length); + +cairo_private cairo_int_status_t +_cairo_image_info_get_png_info (cairo_image_info_t *info, + const unsigned char *data, + unsigned long length); + +cairo_private cairo_int_status_t +_cairo_image_info_get_jbig2_info (cairo_image_info_t *info, + const unsigned char *data, + unsigned long length); + +#endif /* CAIRO_IMAGE_INFO_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-image-info.c b/local/recipes/libs/cairo/source/src/cairo-image-info.c new file mode 100644 index 0000000000..9693e487f6 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-image-info.c @@ -0,0 +1,433 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2008 Adrian Johnson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Adrian Johnson. + * + * Contributor(s): + * Adrian Johnson + */ + +#include "cairoint.h" + +#include "cairo-error-private.h" +#include "cairo-image-info-private.h" + +/* JPEG (image/jpeg) + * + * http://www.w3.org/Graphics/JPEG/itu-t81.pdf + */ + +/* Markers with no parameters. All other markers are followed by a two + * byte length of the parameters. */ +#define TEM 0x01 +#define RST_begin 0xd0 +#define RST_end 0xd7 +#define SOI 0xd8 +#define EOI 0xd9 + +/* Start of frame markers. */ +#define SOF0 0xc0 +#define SOF1 0xc1 +#define SOF2 0xc2 +#define SOF3 0xc3 +#define SOF5 0xc5 +#define SOF6 0xc6 +#define SOF7 0xc7 +#define SOF9 0xc9 +#define SOF10 0xca +#define SOF11 0xcb +#define SOF13 0xcd +#define SOF14 0xce +#define SOF15 0xcf + +static const unsigned char * +_jpeg_skip_segment (const unsigned char *p) +{ + int len; + + p++; + len = (p[0] << 8) | p[1]; + + return p + len; +} + +static void +_jpeg_extract_info (cairo_image_info_t *info, const unsigned char *p) +{ + info->width = (p[6] << 8) + p[7]; + info->height = (p[4] << 8) + p[5]; + info->num_components = p[8]; + info->bits_per_component = p[3]; +} + +cairo_int_status_t +_cairo_image_info_get_jpeg_info (cairo_image_info_t *info, + const unsigned char *data, + unsigned long length) +{ + const unsigned char *p = data; + + while (p + 1 < data + length) { + if (*p != 0xff) + return CAIRO_INT_STATUS_UNSUPPORTED; + p++; + + switch (*p) { + /* skip fill bytes */ + case 0xff: + p++; + break; + + case TEM: + case SOI: + case EOI: + p++; + break; + + case SOF0: + case SOF1: + case SOF2: + case SOF3: + case SOF5: + case SOF6: + case SOF7: + case SOF9: + case SOF10: + case SOF11: + case SOF13: + case SOF14: + case SOF15: + /* Start of frame found. Extract the image parameters. */ + if (p + 8 > data + length) + return CAIRO_INT_STATUS_UNSUPPORTED; + + _jpeg_extract_info (info, p); + return CAIRO_STATUS_SUCCESS; + + default: + if (*p >= RST_begin && *p <= RST_end) { + p++; + break; + } + + if (p + 3 > data + length) + return CAIRO_INT_STATUS_UNSUPPORTED; + + p = _jpeg_skip_segment (p); + break; + } + } + + return CAIRO_STATUS_SUCCESS; +} + +/* JPEG 2000 (image/jp2) + * + * http://www.jpeg.org/public/15444-1annexi.pdf + */ + +#define JPX_FILETYPE 0x66747970 +#define JPX_JP2_HEADER 0x6A703268 +#define JPX_IMAGE_HEADER 0x69686472 + +static const unsigned char _jpx_signature[] = { + 0x00, 0x00, 0x00, 0x0c, 0x6a, 0x50, 0x20, 0x20, 0x0d, 0x0a, 0x87, 0x0a +}; + +static const unsigned char * +_jpx_next_box (const unsigned char *p, const unsigned char *end) +{ + if (p + 4 < end) { + uint32_t length = get_unaligned_be32 (p); + if (p + length < end) + return p + length; + } + + return end; +} + +static const unsigned char * +_jpx_get_box_contents (const unsigned char *p) +{ + return p + 8; +} + +static cairo_bool_t +_jpx_match_box (const unsigned char *p, const unsigned char *end, uint32_t type) +{ + uint32_t length; + + if (p + 8 < end) { + length = get_unaligned_be32 (p); + if (get_unaligned_be32 (p + 4) == type && p + length < end) + return TRUE; + } + + return FALSE; +} + +static const unsigned char * +_jpx_find_box (const unsigned char *p, const unsigned char *end, uint32_t type) +{ + while (p < end) { + if (_jpx_match_box (p, end, type)) + return p; + p = _jpx_next_box (p, end); + } + + return NULL; +} + +static cairo_int_status_t +_jpx_extract_info (const unsigned char *p, cairo_image_info_t *info, const unsigned char *end) +{ + if (p + 11 >= end) { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + info->height = get_unaligned_be32 (p); + info->width = get_unaligned_be32 (p + 4); + info->num_components = (p[8] << 8) + p[9]; + info->bits_per_component = p[10]; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_int_status_t +_cairo_image_info_get_jpx_info (cairo_image_info_t *info, + const unsigned char *data, + unsigned long length) +{ + const unsigned char *p = data; + const unsigned char *end = data + length; + + /* First 12 bytes must be the JPEG 2000 signature box. */ + if (length < ARRAY_LENGTH(_jpx_signature) || + memcmp(p, _jpx_signature, ARRAY_LENGTH(_jpx_signature)) != 0) + return CAIRO_INT_STATUS_UNSUPPORTED; + + p += ARRAY_LENGTH(_jpx_signature); + + /* Next box must be a File Type Box */ + if (! _jpx_match_box (p, end, JPX_FILETYPE)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + p = _jpx_next_box (p, end); + + /* Locate the JP2 header box. */ + p = _jpx_find_box (p, end, JPX_JP2_HEADER); + if (!p) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* Step into the JP2 header box. First box must be the Image + * Header */ + p = _jpx_get_box_contents (p); + if (! _jpx_match_box (p, end, JPX_IMAGE_HEADER)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* Get the image info */ + p = _jpx_get_box_contents (p); + return _jpx_extract_info (p, info, end); +} + +/* PNG (image/png) + * + * http://www.w3.org/TR/2003/REC-PNG-20031110/ + */ + +#define PNG_IHDR 0x49484452 + +static const unsigned char _png_magic[8] = { 137, 80, 78, 71, 13, 10, 26, 10 }; + +cairo_int_status_t +_cairo_image_info_get_png_info (cairo_image_info_t *info, + const unsigned char *data, + unsigned long length) +{ + const unsigned char *p = data; + const unsigned char *end = data + length; + + if (length < 8 || memcmp (data, _png_magic, 8) != 0) + return CAIRO_INT_STATUS_UNSUPPORTED; + + p += 8; + + /* The first chunk must be IDHR. IDHR has 13 bytes of data plus + * the 12 bytes of overhead for the chunk. */ + if (p + 13 + 12 > end) + return CAIRO_INT_STATUS_UNSUPPORTED; + + p += 4; + if (get_unaligned_be32 (p) != PNG_IHDR) + return CAIRO_INT_STATUS_UNSUPPORTED; + + p += 4; + info->width = get_unaligned_be32 (p); + p += 4; + info->height = get_unaligned_be32 (p); + + return CAIRO_STATUS_SUCCESS; +} + +static const unsigned char * +_jbig2_find_data_end (const unsigned char *p, + const unsigned char *end, + int type) +{ + unsigned char end_seq[2]; + int mmr; + + /* Segments of type "Immediate generic region" may have an + * unspecified data length. The JBIG2 specification specifies the + * method to find the end of the data for these segments. */ + if (type == 36 || type == 38 || type == 39) { + if (p + 18 < end) { + mmr = p[17] & 0x01; + if (mmr) { + /* MMR encoding ends with 0x00, 0x00 */ + end_seq[0] = 0x00; + end_seq[1] = 0x00; + } else { + /* Template encoding ends with 0xff, 0xac */ + end_seq[0] = 0xff; + end_seq[1] = 0xac; + } + p += 18; + while (p < end) { + if (p[0] == end_seq[0] && p[1] == end_seq[1]) { + /* Skip the 2 terminating bytes and the 4 byte row count that follows. */ + p += 6; + if (p < end) + return p; + } + p++; + } + } + } + + return NULL; +} + +static const unsigned char * +_jbig2_get_next_segment (const unsigned char *p, + const unsigned char *end, + int *type, + const unsigned char **data, + unsigned long *data_len) +{ + unsigned long seg_num; + cairo_bool_t big_page_size; + int num_segs; + int ref_seg_bytes; + int referred_size; + + if (p + 6 >= end) + return NULL; + + seg_num = get_unaligned_be32 (p); + *type = p[4] & 0x3f; + big_page_size = (p[4] & 0x40) != 0; + p += 5; + + num_segs = p[0] >> 5; + if (num_segs == 7) { + if (p + 4 >= end) + return NULL; + num_segs = get_unaligned_be32 (p) & 0x1fffffff; + ref_seg_bytes = 4 + ((num_segs + 1)/8); + } else { + ref_seg_bytes = 1; + } + p += ref_seg_bytes; + + if (seg_num <= 256) + referred_size = 1; + else if (seg_num <= 65536) + referred_size = 2; + else + referred_size = 4; + + p += num_segs * referred_size; + p += big_page_size ? 4 : 1; + if (p + 4 >= end) + return NULL; + + *data_len = get_unaligned_be32 (p); + p += 4; + *data = p; + + if (*data_len == 0xffffffff) { + /* if data length is -1 we have to scan through the data to find the end */ + p = _jbig2_find_data_end (*data, end, *type); + if (!p || p >= end) + return NULL; + + *data_len = p - *data; + } else { + p += *data_len; + } + + if (p < end) + return p; + else + return NULL; +} + +static void +_jbig2_extract_info (cairo_image_info_t *info, const unsigned char *p) +{ + info->width = get_unaligned_be32 (p); + info->height = get_unaligned_be32 (p + 4); + info->num_components = 1; + info->bits_per_component = 1; +} + +cairo_int_status_t +_cairo_image_info_get_jbig2_info (cairo_image_info_t *info, + const unsigned char *data, + unsigned long length) +{ + const unsigned char *p = data; + const unsigned char *end = data + length; + int seg_type; + const unsigned char *seg_data; + unsigned long seg_data_len; + + while (p && p < end) { + p = _jbig2_get_next_segment (p, end, &seg_type, &seg_data, &seg_data_len); + if (p && seg_type == 48 && seg_data_len > 8) { + /* page information segment */ + _jbig2_extract_info (info, seg_data); + return CAIRO_STATUS_SUCCESS; + } + } + + return CAIRO_INT_STATUS_UNSUPPORTED; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-image-mask-compositor.c b/local/recipes/libs/cairo/source/src/cairo-image-mask-compositor.c new file mode 100644 index 0000000000..4934216f87 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-image-mask-compositor.c @@ -0,0 +1,414 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2003 University of Southern California + * Copyright © 2009,2010,2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Chris Wilson + */ + +/* This compositor is slightly pointless. Just exists for testing + * and as skeleton code. + */ + +#include "cairoint.h" + +#include "cairo-image-surface-private.h" + +#include "cairo-compositor-private.h" +#include "cairo-region-private.h" + +#error This file isn't included in any Makefile + +static cairo_int_status_t +acquire (void *abstract_dst) +{ + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +release (void *abstract_dst) +{ + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +set_clip_region (void *_surface, + cairo_region_t *region) +{ + cairo_image_surface_t *surface = _surface; + pixman_region32_t *rgn = region ? ®ion->rgn : NULL; + + if (! pixman_image_set_clip_region32 (surface->pixman_image, rgn)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_bool_t +has_snapshot (void *_dst, + const cairo_pattern_t *pattern) +{ + return FALSE; +} + +static cairo_int_status_t +draw_image (void *_dst, + cairo_image_surface_t *image, + int src_x, int src_y, + int width, int height, + int dst_x, int dst_y) +{ + cairo_image_surface_t *dst = (cairo_image_surface_t *)_dst; + + pixman_image_composite32 (PIXMAN_OP_SRC, + image->pixman_image, NULL, dst->pixman_image, + src_x, src_y, + 0, 0, + dst_x, dst_y, + width, height); + return CAIRO_STATUS_SUCCESS; +} + +static inline uint32_t +color_to_uint32 (const cairo_color_t *color) +{ + return + ((uint32_t)color->alpha_short >> 8 << 24) | + (color->red_short >> 8 << 16) | + (color->green_short & 0xff00) | + (color->blue_short >> 8); +} + +static inline cairo_bool_t +color_to_pixel (const cairo_color_t *color, + double opacity, + pixman_format_code_t format, + uint32_t *pixel) +{ + cairo_color_t opacity_color; + uint32_t c; + + if (!(format == PIXMAN_a8r8g8b8 || + format == PIXMAN_x8r8g8b8 || + format == PIXMAN_a8b8g8r8 || + format == PIXMAN_x8b8g8r8 || + format == PIXMAN_b8g8r8a8 || + format == PIXMAN_b8g8r8x8 || + format == PIXMAN_r5g6b5 || + format == PIXMAN_b5g6r5 || + format == PIXMAN_a8)) + { + return FALSE; + } + + if (opacity != 1.0) { + _cairo_color_init_rgba (&opacity_color, + color->red, + color->green, + color->blue, + color->alpha * opacity); + color = &opacity_color; + } + c = color_to_uint32 (color); + + if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_ABGR) { + c = ((c & 0xff000000) >> 0) | + ((c & 0x00ff0000) >> 16) | + ((c & 0x0000ff00) >> 0) | + ((c & 0x000000ff) << 16); + } + + if (PIXMAN_FORMAT_TYPE (format) == PIXMAN_TYPE_BGRA) { + c = ((c & 0xff000000) >> 24) | + ((c & 0x00ff0000) >> 8) | + ((c & 0x0000ff00) << 8) | + ((c & 0x000000ff) << 24); + } + + if (format == PIXMAN_a8) { + c = c >> 24; + } else if (format == PIXMAN_r5g6b5 || format == PIXMAN_b5g6r5) { + c = ((((c) >> 3) & 0x001f) | + (((c) >> 5) & 0x07e0) | + (((c) >> 8) & 0xf800)); + } + + *pixel = c; + return TRUE; +} + +static cairo_int_status_t +fill_rectangles (void *_dst, + cairo_operator_t op, + const cairo_color_t *color, + cairo_rectangle_int_t *rects, + int num_rects) +{ + cairo_image_surface_t *dst = _dst; + uint32_t pixel; + int i; + + if (! color_to_pixel (color, 1.0, dst->pixman_format, &pixel)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + for (i = 0; i < num_rects; i++) { + pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t), + PIXMAN_FORMAT_BPP (dst->pixman_format), + rects[i].x, rects[i].y, + rects[i].width, rects[i].height, + pixel); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +fill_boxes (void *_dst, + cairo_operator_t op, + const cairo_color_t *color, + cairo_boxes_t *boxes) +{ + cairo_image_surface_t *dst = _dst; + struct _cairo_boxes_chunk *chunk; + uint32_t pixel; + int i; + + assert (boxes->is_pixel_aligned); + + if (! color_to_pixel (color, 1.0, dst->pixman_format, &pixel)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + for (chunk = &boxes->chunks; chunk; chunk = chunk->next) { + for (i = 0; i < chunk->count; i++) { + int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x); + int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y); + int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x); + int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y); + pixman_fill ((uint32_t *) dst->data, dst->stride / sizeof (uint32_t), + PIXMAN_FORMAT_BPP (dst->pixman_format), + x1, y1, x2 - x1, y2 - y1, + pixel); + } + } + + return CAIRO_STATUS_SUCCESS; +} + +static pixman_op_t +_pixman_operator (cairo_operator_t op) +{ + switch ((int) op) { + case CAIRO_OPERATOR_CLEAR: + return PIXMAN_OP_CLEAR; + + case CAIRO_OPERATOR_SOURCE: + return PIXMAN_OP_SRC; + case CAIRO_OPERATOR_OVER: + return PIXMAN_OP_OVER; + case CAIRO_OPERATOR_IN: + return PIXMAN_OP_IN; + case CAIRO_OPERATOR_OUT: + return PIXMAN_OP_OUT; + case CAIRO_OPERATOR_ATOP: + return PIXMAN_OP_ATOP; + + case CAIRO_OPERATOR_DEST: + return PIXMAN_OP_DST; + case CAIRO_OPERATOR_DEST_OVER: + return PIXMAN_OP_OVER_REVERSE; + case CAIRO_OPERATOR_DEST_IN: + return PIXMAN_OP_IN_REVERSE; + case CAIRO_OPERATOR_DEST_OUT: + return PIXMAN_OP_OUT_REVERSE; + case CAIRO_OPERATOR_DEST_ATOP: + return PIXMAN_OP_ATOP_REVERSE; + + case CAIRO_OPERATOR_XOR: + return PIXMAN_OP_XOR; + case CAIRO_OPERATOR_ADD: + return PIXMAN_OP_ADD; + case CAIRO_OPERATOR_SATURATE: + return PIXMAN_OP_SATURATE; + + case CAIRO_OPERATOR_MULTIPLY: + return PIXMAN_OP_MULTIPLY; + case CAIRO_OPERATOR_SCREEN: + return PIXMAN_OP_SCREEN; + case CAIRO_OPERATOR_OVERLAY: + return PIXMAN_OP_OVERLAY; + case CAIRO_OPERATOR_DARKEN: + return PIXMAN_OP_DARKEN; + case CAIRO_OPERATOR_LIGHTEN: + return PIXMAN_OP_LIGHTEN; + case CAIRO_OPERATOR_COLOR_DODGE: + return PIXMAN_OP_COLOR_DODGE; + case CAIRO_OPERATOR_COLOR_BURN: + return PIXMAN_OP_COLOR_BURN; + case CAIRO_OPERATOR_HARD_LIGHT: + return PIXMAN_OP_HARD_LIGHT; + case CAIRO_OPERATOR_SOFT_LIGHT: + return PIXMAN_OP_SOFT_LIGHT; + case CAIRO_OPERATOR_DIFFERENCE: + return PIXMAN_OP_DIFFERENCE; + case CAIRO_OPERATOR_EXCLUSION: + return PIXMAN_OP_EXCLUSION; + case CAIRO_OPERATOR_HSL_HUE: + return PIXMAN_OP_HSL_HUE; + case CAIRO_OPERATOR_HSL_SATURATION: + return PIXMAN_OP_HSL_SATURATION; + case CAIRO_OPERATOR_HSL_COLOR: + return PIXMAN_OP_HSL_COLOR; + case CAIRO_OPERATOR_HSL_LUMINOSITY: + return PIXMAN_OP_HSL_LUMINOSITY; + + default: + ASSERT_NOT_REACHED; + return PIXMAN_OP_OVER; + } +} + +static cairo_int_status_t +composite (void *_dst, + cairo_operator_t op, + cairo_surface_t *abstract_src, + cairo_surface_t *abstract_mask, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height) +{ + cairo_image_surface_t *dst = _dst; + cairo_pixman_source_t *src = (cairo_pixman_source_t *)abstract_src; + cairo_pixman_source_t *mask = (cairo_pixman_source_t *)abstract_mask; + if (mask) { + pixman_image_composite32 (_pixman_operator (op), + src->pixman_image, mask->pixman_image, dst->pixman_image, + src_x, src_y, + mask_x, mask_y, + dst_x, dst_y, + width, height); + } else { + pixman_image_composite32 (_pixman_operator (op), + src->pixman_image, NULL, dst->pixman_image, + src_x, src_y, + 0, 0, + dst_x, dst_y, + width, height); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +composite_boxes (void *_dst, + cairo_operator_t op, + cairo_surface_t *abstract_src, + cairo_surface_t *abstract_mask, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + cairo_boxes_t *boxes) +{ + cairo_image_surface_t *dst = _dst; + cairo_pixman_source_t *src = (cairo_pixman_source_t *)abstract_src; + cairo_pixman_source_t *mask = (cairo_pixman_source_t *)abstract_mask; + struct _cairo_boxes_chunk *chunk; + int i; + + assert (boxes->is_pixel_aligned); + + op = _pixman_operator (op); + for (chunk = &boxes->chunks; chunk; chunk = chunk->next) { + for (i = 0; i < chunk->count; i++) { + int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x); + int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y); + int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x); + int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y); + + if (mask) { + pixman_image_composite32 (op, + src->pixman_image, mask->pixman_image, dst->pixman_image, + x1 + src_x, y1 + src_y, + x1 + mask_x, y1 + mask_y, + x1 + dst_x, y1 + dst_y, + x2 - x1, y2 - y1); + } else { + pixman_image_composite32 (op, + src->pixman_image, NULL, dst->pixman_image, + x1 + src_x, y1 + src_y, + 0, 0, + x1 + dst_x, y1 + dst_y, + x2 - x1, y2 - y1); + } + } + } + + return CAIRO_STATUS_SUCCESS; +} + +const cairo_compositor_t * +_cairo_image_mask_compositor_get (void) +{ + static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT; + static cairo_mask_compositor_t compositor; + + if (_cairo_atomic_init_once_enter(&once)) { + _cairo_mask_compositor_init (&compositor, + _cairo_image_traps_compositor_get ()); + compositor.acquire = acquire; + compositor.release = release; + compositor.set_clip_region = set_clip_region; + compositor.pattern_to_surface = _cairo_pixman_source_create_for_pattern; + compositor.has_snapshot = has_snapshot; + compositor.draw_image = draw_image; + compositor.fill_rectangles = fill_rectangles; + compositor.fill_boxes = fill_boxes; +#error check_composite must never be NULL, because it gets called without a NULL pointer check + //compositor.check_composite = check_composite; + compositor.composite = composite; + //compositor.check_composite_boxes = check_composite_boxes; + compositor.composite_boxes = composite_boxes; + + _cairo_atomic_init_once_leave(&once); + } + + return &compositor.base; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-image-source.c b/local/recipes/libs/cairo/source/src/cairo-image-source.c new file mode 100644 index 0000000000..eaf72e2cc9 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-image-source.c @@ -0,0 +1,1652 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2003 University of Southern California + * Copyright © 2009,2010,2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Chris Wilson + */ + +/* The purpose of this file/surface is to simply translate a pattern + * to a pixman_image_t and thence to feed it back to the general + * compositor interface. + */ + +#include "cairoint.h" + +#include "cairo-image-surface-private.h" + +#include "cairo-compositor-private.h" +#include "cairo-error-private.h" +#include "cairo-pattern-inline.h" +#include "cairo-paginated-private.h" +#include "cairo-recording-surface-private.h" +#include "cairo-surface-observer-private.h" +#include "cairo-surface-snapshot-inline.h" +#include "cairo-surface-subsurface-private.h" + +#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */ + +#if CAIRO_NO_MUTEX +#define PIXMAN_HAS_ATOMIC_OPS 1 +#endif + +#if PIXMAN_HAS_ATOMIC_OPS +static pixman_image_t *__pixman_transparent_image; +static pixman_image_t *__pixman_black_image; +static pixman_image_t *__pixman_white_image; + +static pixman_image_t * +_pixman_transparent_image (void) +{ + pixman_image_t *image; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + image = __pixman_transparent_image; + if (unlikely (image == NULL)) { + pixman_color_t color; + + color.red = 0x00; + color.green = 0x00; + color.blue = 0x00; + color.alpha = 0x00; + + image = pixman_image_create_solid_fill (&color); + if (unlikely (image == NULL)) + return NULL; + + if (_cairo_atomic_ptr_cmpxchg (&__pixman_transparent_image, + NULL, image)) + { + pixman_image_ref (image); + } + } else { + pixman_image_ref (image); + } + + return image; +} + +static pixman_image_t * +_pixman_black_image (void) +{ + pixman_image_t *image; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + image = __pixman_black_image; + if (unlikely (image == NULL)) { + pixman_color_t color; + + color.red = 0x00; + color.green = 0x00; + color.blue = 0x00; + color.alpha = 0xffff; + + image = pixman_image_create_solid_fill (&color); + if (unlikely (image == NULL)) + return NULL; + + if (_cairo_atomic_ptr_cmpxchg (&__pixman_black_image, + NULL, image)) + { + pixman_image_ref (image); + } + } else { + pixman_image_ref (image); + } + + return image; +} + +static pixman_image_t * +_pixman_white_image (void) +{ + pixman_image_t *image; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + image = __pixman_white_image; + if (unlikely (image == NULL)) { + pixman_color_t color; + + color.red = 0xffff; + color.green = 0xffff; + color.blue = 0xffff; + color.alpha = 0xffff; + + image = pixman_image_create_solid_fill (&color); + if (unlikely (image == NULL)) + return NULL; + + if (_cairo_atomic_ptr_cmpxchg (&__pixman_white_image, + NULL, image)) + { + pixman_image_ref (image); + } + } else { + pixman_image_ref (image); + } + + return image; +} + +static uint32_t +hars_petruska_f54_1_random (void) +{ +#define rol(x,k) ((x << k) | (x >> (32-k))) + static uint32_t x; + return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849; +#undef rol +} + +static struct { + cairo_color_t color; + pixman_image_t *image; +} cache[16]; +static int n_cached; + +#else /* !PIXMAN_HAS_ATOMIC_OPS */ +static pixman_image_t * +_pixman_transparent_image (void) +{ + TRACE ((stderr, "%s\n", __FUNCTION__)); + return _pixman_image_for_color (CAIRO_COLOR_TRANSPARENT); +} + +static pixman_image_t * +_pixman_black_image (void) +{ + TRACE ((stderr, "%s\n", __FUNCTION__)); + return _pixman_image_for_color (CAIRO_COLOR_BLACK); +} + +static pixman_image_t * +_pixman_white_image (void) +{ + TRACE ((stderr, "%s\n", __FUNCTION__)); + return _pixman_image_for_color (CAIRO_COLOR_WHITE); +} +#endif /* !PIXMAN_HAS_ATOMIC_OPS */ + + +pixman_image_t * +_pixman_image_for_color (const cairo_color_t *cairo_color) +{ + pixman_color_t color; + pixman_image_t *image; + +#if PIXMAN_HAS_ATOMIC_OPS + int i; + + if (CAIRO_COLOR_IS_CLEAR (cairo_color)) + return _pixman_transparent_image (); + + if (CAIRO_COLOR_IS_OPAQUE (cairo_color)) { + if (cairo_color->red_short <= 0x00ff && + cairo_color->green_short <= 0x00ff && + cairo_color->blue_short <= 0x00ff) + { + return _pixman_black_image (); + } + + if (cairo_color->red_short >= 0xff00 && + cairo_color->green_short >= 0xff00 && + cairo_color->blue_short >= 0xff00) + { + return _pixman_white_image (); + } + } + + CAIRO_MUTEX_LOCK (_cairo_image_solid_cache_mutex); + for (i = 0; i < n_cached; i++) { + if (_cairo_color_equal (&cache[i].color, cairo_color)) { + image = pixman_image_ref (cache[i].image); + goto UNLOCK; + } + } +#endif + + color.red = cairo_color->red_short; + color.green = cairo_color->green_short; + color.blue = cairo_color->blue_short; + color.alpha = cairo_color->alpha_short; + + image = pixman_image_create_solid_fill (&color); +#if PIXMAN_HAS_ATOMIC_OPS + if (image == NULL) + goto UNLOCK; + + if (n_cached < ARRAY_LENGTH (cache)) { + i = n_cached++; + } else { + i = hars_petruska_f54_1_random () % ARRAY_LENGTH (cache); + pixman_image_unref (cache[i].image); + } + cache[i].image = pixman_image_ref (image); + cache[i].color = *cairo_color; + +UNLOCK: + CAIRO_MUTEX_UNLOCK (_cairo_image_solid_cache_mutex); +#endif + return image; +} + + +void +_cairo_image_reset_static_data (void) +{ +#if PIXMAN_HAS_ATOMIC_OPS + while (n_cached) + pixman_image_unref (cache[--n_cached].image); + + if (__pixman_transparent_image) { + pixman_image_unref (__pixman_transparent_image); + __pixman_transparent_image = NULL; + } + + if (__pixman_black_image) { + pixman_image_unref (__pixman_black_image); + __pixman_black_image = NULL; + } + + if (__pixman_white_image) { + pixman_image_unref (__pixman_white_image); + __pixman_white_image = NULL; + } +#endif +} + +static pixman_image_t * +_pixman_image_for_gradient (const cairo_gradient_pattern_t *pattern, + const cairo_rectangle_int_t *extents, + int *ix, int *iy) +{ + pixman_image_t *pixman_image; + pixman_gradient_stop_t pixman_stops_static[2]; + pixman_gradient_stop_t *pixman_stops = pixman_stops_static; + pixman_transform_t pixman_transform; + cairo_matrix_t matrix; + cairo_circle_double_t extremes[2]; + pixman_point_fixed_t p1, p2; + unsigned int i; + cairo_int_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + if (pattern->n_stops > ARRAY_LENGTH(pixman_stops_static)) { + pixman_stops = _cairo_malloc_ab (pattern->n_stops, + sizeof(pixman_gradient_stop_t)); + if (unlikely (pixman_stops == NULL)) + return NULL; + } + + for (i = 0; i < pattern->n_stops; i++) { + pixman_stops[i].x = _cairo_fixed_16_16_from_double (pattern->stops[i].offset); + pixman_stops[i].color.red = pattern->stops[i].color.red_short; + pixman_stops[i].color.green = pattern->stops[i].color.green_short; + pixman_stops[i].color.blue = pattern->stops[i].color.blue_short; + pixman_stops[i].color.alpha = pattern->stops[i].color.alpha_short; + } + + _cairo_gradient_pattern_fit_to_range (pattern, PIXMAN_MAX_INT >> 1, &matrix, extremes); + + p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x); + p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y); + p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x); + p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y); + + if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) { + pixman_image = pixman_image_create_linear_gradient (&p1, &p2, + pixman_stops, + pattern->n_stops); + } else { + pixman_fixed_t r1, r2; + + r1 = _cairo_fixed_16_16_from_double (extremes[0].radius); + r2 = _cairo_fixed_16_16_from_double (extremes[1].radius); + + pixman_image = pixman_image_create_radial_gradient (&p1, &p2, r1, r2, + pixman_stops, + pattern->n_stops); + } + + if (pixman_stops != pixman_stops_static) + free (pixman_stops); + + if (unlikely (pixman_image == NULL)) + return NULL; + + *ix = *iy = 0; + status = _cairo_matrix_to_pixman_matrix_offset (&matrix, pattern->base.filter, + extents->x + extents->width/2., + extents->y + extents->height/2., + &pixman_transform, ix, iy); + if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) { + if (unlikely (status != CAIRO_INT_STATUS_SUCCESS) || + ! pixman_image_set_transform (pixman_image, &pixman_transform)) + { + pixman_image_unref (pixman_image); + return NULL; + } + } + + { + pixman_repeat_t pixman_repeat; + + switch (pattern->base.extend) { + default: + case CAIRO_EXTEND_NONE: + pixman_repeat = PIXMAN_REPEAT_NONE; + break; + case CAIRO_EXTEND_REPEAT: + pixman_repeat = PIXMAN_REPEAT_NORMAL; + break; + case CAIRO_EXTEND_REFLECT: + pixman_repeat = PIXMAN_REPEAT_REFLECT; + break; + case CAIRO_EXTEND_PAD: + pixman_repeat = PIXMAN_REPEAT_PAD; + break; + } + + pixman_image_set_repeat (pixman_image, pixman_repeat); + } + + return pixman_image; +} + +static pixman_image_t * +_pixman_image_for_mesh (const cairo_mesh_pattern_t *pattern, + const cairo_rectangle_int_t *extents, + int *tx, int *ty) +{ + pixman_image_t *image; + int width, height; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + *tx = -extents->x; + *ty = -extents->y; + width = extents->width; + height = extents->height; + + image = pixman_image_create_bits (PIXMAN_a8r8g8b8, width, height, NULL, 0); + if (unlikely (image == NULL)) + return NULL; + + _cairo_mesh_pattern_rasterize (pattern, + pixman_image_get_data (image), + width, height, + pixman_image_get_stride (image), + *tx, *ty); + return image; +} + +struct acquire_source_cleanup { + cairo_surface_t *surface; + cairo_image_surface_t *image; + void *image_extra; +}; + +static void +_acquire_source_cleanup (pixman_image_t *pixman_image, + void *closure) +{ + struct acquire_source_cleanup *data = closure; + + _cairo_surface_release_source_image (data->surface, + data->image, + data->image_extra); + free (data); +} + +static void +_defer_free_cleanup (pixman_image_t *pixman_image, + void *closure) +{ + cairo_surface_destroy (closure); +} + +static uint16_t +expand_channel (uint16_t v, uint32_t bits) +{ + int offset = 16 - bits; + while (offset > 0) { + v |= v >> bits; + offset -= bits; + bits += bits; + } + return v; +} + +static pixman_image_t * +_pixel_to_solid (cairo_image_surface_t *image, int x, int y) +{ + uint32_t pixel; + float *rgba; + pixman_color_t color; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + switch (image->format) { + default: + case CAIRO_FORMAT_INVALID: + ASSERT_NOT_REACHED; + return NULL; + + case CAIRO_FORMAT_A1: + pixel = *(uint8_t *) (image->data + y * image->stride + x/8); + return pixel & (1 << (x&7)) ? _pixman_black_image () : _pixman_transparent_image (); + + case CAIRO_FORMAT_A8: + color.alpha = *(uint8_t *) (image->data + y * image->stride + x); + color.alpha |= color.alpha << 8; + if (color.alpha == 0) + return _pixman_transparent_image (); + if (color.alpha == 0xffff) + return _pixman_black_image (); + + color.red = color.green = color.blue = 0; + return pixman_image_create_solid_fill (&color); + + case CAIRO_FORMAT_RGB16_565: + pixel = *(uint16_t *) (image->data + y * image->stride + 2 * x); + if (pixel == 0) + return _pixman_black_image (); + if (pixel == 0xffff) + return _pixman_white_image (); + + color.alpha = 0xffff; + color.red = expand_channel ((pixel >> 11 & 0x1f) << 11, 5); + color.green = expand_channel ((pixel >> 5 & 0x3f) << 10, 6); + color.blue = expand_channel ((pixel & 0x1f) << 11, 5); + return pixman_image_create_solid_fill (&color); + + case CAIRO_FORMAT_RGB30: + pixel = *(uint32_t *) (image->data + y * image->stride + 4 * x); + pixel &= 0x3fffffff; /* ignore alpha bits */ + if (pixel == 0) + return _pixman_black_image (); + if (pixel == 0x3fffffff) + return _pixman_white_image (); + + /* convert 10bpc to 16bpc */ + color.alpha = 0xffff; + color.red = expand_channel((pixel >> 20) & 0x3fff, 10); + color.green = expand_channel((pixel >> 10) & 0x3fff, 10); + color.blue = expand_channel(pixel & 0x3fff, 10); + return pixman_image_create_solid_fill (&color); + + case CAIRO_FORMAT_ARGB32: + case CAIRO_FORMAT_RGB24: + pixel = *(uint32_t *) (image->data + y * image->stride + 4 * x); + color.alpha = image->format == CAIRO_FORMAT_ARGB32 ? (pixel >> 24) | (pixel >> 16 & 0xff00) : 0xffff; + if (color.alpha == 0) + return _pixman_transparent_image (); + if (pixel == 0xffffffff) + return _pixman_white_image (); + if (color.alpha == 0xffff && (pixel & 0xffffff) == 0) + return _pixman_black_image (); + + color.red = (pixel >> 16 & 0xff) | (pixel >> 8 & 0xff00); + color.green = (pixel >> 8 & 0xff) | (pixel & 0xff00); + color.blue = (pixel & 0xff) | (pixel << 8 & 0xff00); + return pixman_image_create_solid_fill (&color); + + case CAIRO_FORMAT_RGB96F: + case CAIRO_FORMAT_RGBA128F: + if (image->format == CAIRO_FORMAT_RGBA128F) + { + rgba = (float *)&image->data[y * image->stride + 16 * x]; + color.alpha = 65535.f * rgba[3]; + + if (color.alpha == 0) + return _pixman_transparent_image (); + } + else + { + rgba = (float *)&image->data[y * image->stride + 12 * x]; + color.alpha = 0xffff; + } + + if (color.alpha == 0xffff && rgba[0] == 0.f && rgba[1] == 0.f && rgba[2] == 0.f) + return _pixman_black_image (); + if (color.alpha == 0xffff && rgba[0] == 1.f && rgba[1] == 1.f && rgba[2] == 1.f) + return _pixman_white_image (); + + color.red = rgba[0] * 65535.f; + color.green = rgba[1] * 65535.f; + color.blue = rgba[2] * 65535.f; + return pixman_image_create_solid_fill (&color); + } +} + +/* ========================================================================== */ + +/* Index into filter table */ +typedef enum +{ + KERNEL_IMPULSE, + KERNEL_BOX, + KERNEL_LINEAR, + KERNEL_MITCHELL, + KERNEL_NOTCH, + KERNEL_CATMULL_ROM, + KERNEL_LANCZOS3, + KERNEL_LANCZOS3_STRETCHED, + KERNEL_TENT +} kernel_t; + +/* Produce contribution of a filter of size r for pixel centered on x. + For a typical low-pass function this evaluates the function at x/r. + If the frequency is higher than 1/2, such as when r is less than 1, + this may need to integrate several samples, see cubic for examples. +*/ +typedef double (* kernel_func_t) (double x, double r); + +/* Return maximum number of pixels that will be non-zero. Except for + impluse this is the maximum of 2 and the width of the non-zero part + of the filter rounded up to the next integer. +*/ +typedef int (* kernel_width_func_t) (double r); + +/* Table of filters */ +typedef struct +{ + kernel_t kernel; + kernel_func_t func; + kernel_width_func_t width; +} filter_info_t; + +/* PIXMAN_KERNEL_IMPULSE: Returns pixel nearest the center. This + matches PIXMAN_FILTER_NEAREST. This is useful if you wish to + combine the result of nearest in one direction with another filter + in the other. +*/ + +static double +impulse_kernel (double x, double r) +{ + return 1; +} + +static int +impulse_width (double r) +{ + return 1; +} + +/* PIXMAN_KERNEL_BOX: Intersection of a box of width r with square + pixels. This is the smallest possible filter such that the output + image contains an equal contribution from all the input + pixels. Lots of software uses this. The function is a trapazoid of + width r+1, not a box. + + When r == 1.0, PIXMAN_KERNEL_BOX, PIXMAN_KERNEL_LINEAR, and + PIXMAN_KERNEL_TENT all produce the same filter, allowing + them to be exchanged at this point. +*/ + +static double +box_kernel (double x, double r) +{ + return MAX (0.0, MIN (MIN (r, 1.0), + MIN ((r + 1) / 2 - x, (r + 1) / 2 + x))); +} + +static int +box_width (double r) +{ + return r < 1.0 ? 2 : ceil(r + 1); +} + +/* PIXMAN_KERNEL_LINEAR: Weighted sum of the two pixels nearest the + center, or a triangle of width 2. This matches + PIXMAN_FILTER_BILINEAR. This is useful if you wish to combine the + result of bilinear in one direction with another filter in the + other. This is not a good filter if r > 1. You may actually want + PIXMAN_FILTER_TENT. + + When r == 1.0, PIXMAN_KERNEL_BOX, PIXMAN_KERNEL_LINEAR, and + PIXMAN_KERNEL_TENT all produce the same filter, allowing + them to be exchanged at this point. +*/ + +static double +linear_kernel (double x, double r) +{ + return MAX (1.0 - fabs(x), 0.0); +} + +static int +linear_width (double r) +{ + return 2; +} + +/* Cubic functions described in the Mitchell-Netravali paper. + http://mentallandscape.com/Papers_siggraph88.pdf. This describes + all possible cubic functions that can be used for sampling. +*/ + +static double +general_cubic (double x, double r, double B, double C) +{ + double ax; + if (r < 1.0) + return + general_cubic(x * 2 - .5, r * 2, B, C) + + general_cubic(x * 2 + .5, r * 2, B, C); + + ax = fabs (x / r); + + if (ax < 1) + { + return (((12 - 9 * B - 6 * C) * ax + + (-18 + 12 * B + 6 * C)) * ax * ax + + (6 - 2 * B)) / 6; + } + else if (ax < 2) + { + return ((((-B - 6 * C) * ax + + (6 * B + 30 * C)) * ax + + (-12 * B - 48 * C)) * ax + + (8 * B + 24 * C)) / 6; + } + else + { + return 0.0; + } +} + +static int +cubic_width (double r) +{ + return MAX (2, ceil (r * 4)); +} + +/* PIXMAN_KERNEL_CATMULL_ROM: Catmull-Rom interpolation. Often called + "cubic interpolation", "b-spline", or just "cubic" by other + software. This filter has negative values so it can produce ringing + and output pixels outside the range of input pixels. This is very + close to lanczos2 so there is no reason to supply that as well. +*/ + +static double +cubic_kernel (double x, double r) +{ + return general_cubic (x, r, 0.0, 0.5); +} + +/* PIXMAN_KERNEL_MITCHELL: Cubic recommended by the Mitchell-Netravali + paper. This has negative values and because the values at +/-1 are + not zero it does not interpolate the pixels, meaning it will change + an image even if there is no translation. +*/ + +static double +mitchell_kernel (double x, double r) +{ + return general_cubic (x, r, 1/3.0, 1/3.0); +} + +/* PIXMAN_KERNEL_NOTCH: Cubic recommended by the Mitchell-Netravali + paper to remove postaliasing artifacts. This does not remove + aliasing already present in the source image, though it may appear + to due to it's excessive blurriness. In any case this is more + useful than gaussian for image reconstruction. +*/ + +static double +notch_kernel (double x, double r) +{ + return general_cubic (x, r, 1.5, -0.25); +} + +/* PIXMAN_KERNEL_LANCZOS3: lanczos windowed sinc function from -3 to + +3. Very popular with high-end software though I think any + advantage over cubics is hidden by quantization and programming + mistakes. You will see LANCZOS5 or even 7 sometimes. +*/ + +static double +sinc (double x) +{ + return x ? sin (M_PI * x) / (M_PI * x) : 1.0; +} + +static double +lanczos (double x, double n) +{ + return fabs (x) < n ? sinc (x) * sinc (x * (1.0 / n)) : 0.0; +} + +static double +lanczos3_kernel (double x, double r) +{ + if (r < 1.0) + return + lanczos3_kernel (x * 2 - .5, r * 2) + + lanczos3_kernel (x * 2 + .5, r * 2); + else + return lanczos (x / r, 3.0); +} + +static int +lanczos3_width (double r) +{ + return MAX (2, ceil (r * 6)); +} + +/* PIXMAN_KERNEL_LANCZOS3_STRETCHED - The LANCZOS3 kernel widened by + 4/3. Recommended by Jim Blinn + http://graphics.cs.cmu.edu/nsp/course/15-462/Fall07/462/papers/jaggy.pdf +*/ + +static double +nice_kernel (double x, double r) +{ + return lanczos3_kernel (x, r * (4.0/3)); +} + +static int +nice_width (double r) +{ + return MAX (2.0, ceil (r * 8)); +} + +/* PIXMAN_KERNEL_TENT: Triangle of width 2r. Lots of software uses + this as a "better" filter, twice the size of a box but smaller than + a cubic. + + When r == 1.0, PIXMAN_KERNEL_BOX, PIXMAN_KERNEL_LINEAR, and + PIXMAN_KERNEL_TENT all produce the same filter, allowing + them to be exchanged at this point. +*/ + +static double +tent_kernel (double x, double r) +{ + if (r < 1.0) + return box_kernel(x, r); + else + return MAX (1.0 - fabs(x / r), 0.0); +} + +static int +tent_width (double r) +{ + return r < 1.0 ? 2 : ceil(2 * r); +} + + +static const filter_info_t filters[] = +{ + { KERNEL_IMPULSE, impulse_kernel, impulse_width }, + { KERNEL_BOX, box_kernel, box_width }, + { KERNEL_LINEAR, linear_kernel, linear_width }, + { KERNEL_MITCHELL, mitchell_kernel, cubic_width }, + { KERNEL_NOTCH, notch_kernel, cubic_width }, + { KERNEL_CATMULL_ROM, cubic_kernel, cubic_width }, + { KERNEL_LANCZOS3, lanczos3_kernel, lanczos3_width }, + { KERNEL_LANCZOS3_STRETCHED,nice_kernel, nice_width }, + { KERNEL_TENT, tent_kernel, tent_width } +}; + +/* Fills in one dimension of the filter array */ +static void get_filter(kernel_t filter, double r, + int width, int subsample, + pixman_fixed_t* out) +{ + int i; + pixman_fixed_t *p = out; + int n_phases = 1 << subsample; + double step = 1.0 / n_phases; + kernel_func_t func = filters[filter].func; + + /* special-case the impulse filter: */ + if (width <= 1) + { + for (i = 0; i < n_phases; ++i) + *p++ = pixman_fixed_1; + return; + } + + for (i = 0; i < n_phases; ++i) + { + double frac = (i + .5) * step; + /* Center of left-most pixel: */ + double x1 = ceil (frac - width / 2.0 - 0.5) - frac + 0.5; + double total = 0; + pixman_fixed_t new_total = 0; + int j; + + for (j = 0; j < width; ++j) + { + double v = func(x1 + j, r); + total += v; + p[j] = pixman_double_to_fixed (v); + } + + /* Normalize */ + total = 1 / total; + for (j = 0; j < width; ++j) + new_total += (p[j] *= total); + + /* Put any error on center pixel */ + p[width / 2] += (pixman_fixed_1 - new_total); + + p += width; + } +} + + +/* Create the parameter list for a SEPARABLE_CONVOLUTION filter + * with the given kernels and scale parameters. + */ +static pixman_fixed_t * +create_separable_convolution (int *n_values, + kernel_t xfilter, + double sx, + kernel_t yfilter, + double sy) +{ + int xwidth, xsubsample, ywidth, ysubsample, size_x, size_y; + pixman_fixed_t *params; + + xwidth = filters[xfilter].width(sx); + xsubsample = 0; + if (xwidth > 1) + while (sx * (1 << xsubsample) <= 128.0) xsubsample++; + size_x = (1 << xsubsample) * xwidth; + + ywidth = filters[yfilter].width(sy); + ysubsample = 0; + if (ywidth > 1) + while (sy * (1 << ysubsample) <= 128.0) ysubsample++; + size_y = (1 << ysubsample) * ywidth; + + *n_values = 4 + size_x + size_y; + params = _cairo_malloc (*n_values * sizeof (pixman_fixed_t)); + if (!params) return 0; + + params[0] = pixman_int_to_fixed (xwidth); + params[1] = pixman_int_to_fixed (ywidth); + params[2] = pixman_int_to_fixed (xsubsample); + params[3] = pixman_int_to_fixed (ysubsample); + + get_filter(xfilter, sx, xwidth, xsubsample, params + 4); + get_filter(yfilter, sy, ywidth, ysubsample, params + 4 + size_x); + + return params; +} + +/* ========================================================================== */ + +static cairo_bool_t +_pixman_image_set_properties (pixman_image_t *pixman_image, + const cairo_pattern_t *pattern, + const cairo_rectangle_int_t *extents, + int *ix,int *iy) +{ + pixman_transform_t pixman_transform; + cairo_int_status_t status; + + status = _cairo_matrix_to_pixman_matrix_offset (&pattern->matrix, + pattern->filter, + extents->x + extents->width/2., + extents->y + extents->height/2., + &pixman_transform, ix, iy); + if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) + { + /* If the transform is an identity, we don't need to set it + * and we can use any filtering, so choose the fastest one. */ + pixman_image_set_filter (pixman_image, PIXMAN_FILTER_NEAREST, NULL, 0); + } + else if (unlikely (status != CAIRO_INT_STATUS_SUCCESS || + ! pixman_image_set_transform (pixman_image, + &pixman_transform))) + { + return FALSE; + } + else + { + pixman_filter_t pixman_filter; + kernel_t kernel; + double dx, dy; + + /* Compute scale factors from the pattern matrix. These scale + * factors are from user to pattern space, and as such they + * are greater than 1.0 for downscaling and less than 1.0 for + * upscaling. The factors are the size of an axis-aligned + * rectangle with the same area as the parallelgram a 1x1 + * square transforms to. + */ + dx = hypot (pattern->matrix.xx, pattern->matrix.xy); + dy = hypot (pattern->matrix.yx, pattern->matrix.yy); + + /* Clip at maximum pixman_fixed number. Besides making it + * passable to pixman, this avoids errors from inf and nan. + */ + if (! (dx < 0x7FFF)) dx = 0x7FFF; + if (! (dy < 0x7FFF)) dy = 0x7FFF; + + switch (pattern->filter) { + case CAIRO_FILTER_FAST: + pixman_filter = PIXMAN_FILTER_FAST; + break; + case CAIRO_FILTER_GOOD: + pixman_filter = PIXMAN_FILTER_SEPARABLE_CONVOLUTION; + kernel = KERNEL_BOX; + /* Clip the filter size to prevent extreme slowness. This + value could be raised if 2-pass filtering is done */ + if (dx > 16.0) dx = 16.0; + if (dy > 16.0) dy = 16.0; + /* Match the bilinear filter for scales > .75: */ + if (dx < 1.0/0.75) dx = 1.0; + if (dy < 1.0/0.75) dy = 1.0; + break; + case CAIRO_FILTER_BEST: + pixman_filter = PIXMAN_FILTER_SEPARABLE_CONVOLUTION; + kernel = KERNEL_CATMULL_ROM; /* LANCZOS3 is better but not much */ + /* Clip the filter size to prevent extreme slowness. This + value could be raised if 2-pass filtering is done */ + if (dx > 16.0) { dx = 16.0; kernel = KERNEL_BOX; } + /* blur up to 2x scale, then blend to square pixels for larger: */ + else if (dx < 1.0) { + if (dx < 1.0/128) dx = 1.0/127; + else if (dx < 0.5) dx = 1.0 / (1.0 / dx - 1.0); + else dx = 1.0; + } + if (dy > 16.0) { dy = 16.0; kernel = KERNEL_BOX; } + else if (dy < 1.0) { + if (dy < 1.0/128) dy = 1.0/127; + else if (dy < 0.5) dy = 1.0 / (1.0 / dy - 1.0); + else dy = 1.0; + } + break; + case CAIRO_FILTER_NEAREST: + pixman_filter = PIXMAN_FILTER_NEAREST; + break; + case CAIRO_FILTER_BILINEAR: + pixman_filter = PIXMAN_FILTER_BILINEAR; + break; + case CAIRO_FILTER_GAUSSIAN: + /* XXX: The GAUSSIAN value has no implementation in cairo + * whatsoever, so it was really a mistake to have it in the + * API. We could fix this by officially deprecating it, or + * else inventing semantics and providing an actual + * implementation for it. */ + default: + pixman_filter = PIXMAN_FILTER_BEST; + } + + if (pixman_filter == PIXMAN_FILTER_SEPARABLE_CONVOLUTION) { + int n_params; + pixman_fixed_t *params; + params = create_separable_convolution + (&n_params, kernel, dx, kernel, dy); + pixman_image_set_filter (pixman_image, pixman_filter, + params, n_params); + free (params); + } else { + pixman_image_set_filter (pixman_image, pixman_filter, NULL, 0); + } + } + + { + pixman_repeat_t pixman_repeat; + + switch (pattern->extend) { + default: + case CAIRO_EXTEND_NONE: + pixman_repeat = PIXMAN_REPEAT_NONE; + break; + case CAIRO_EXTEND_REPEAT: + pixman_repeat = PIXMAN_REPEAT_NORMAL; + break; + case CAIRO_EXTEND_REFLECT: + pixman_repeat = PIXMAN_REPEAT_REFLECT; + break; + case CAIRO_EXTEND_PAD: + pixman_repeat = PIXMAN_REPEAT_PAD; + break; + } + + pixman_image_set_repeat (pixman_image, pixman_repeat); + } + + if (pattern->has_component_alpha) + pixman_image_set_component_alpha (pixman_image, TRUE); + + return TRUE; +} + +struct proxy { + cairo_surface_t base; + cairo_surface_t *image; +}; + +static cairo_status_t +proxy_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) +{ + struct proxy *proxy = abstract_surface; + return _cairo_surface_acquire_source_image (proxy->image, image_out, image_extra); +} + +static void +proxy_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) +{ + struct proxy *proxy = abstract_surface; + _cairo_surface_release_source_image (proxy->image, image, image_extra); +} + +static cairo_status_t +proxy_finish (void *abstract_surface) +{ + return CAIRO_STATUS_SUCCESS; +} + +static const cairo_surface_backend_t proxy_backend = { + CAIRO_INTERNAL_SURFACE_TYPE_NULL, + proxy_finish, + NULL, + + NULL, /* create similar */ + NULL, /* create similar image */ + NULL, /* map to image */ + NULL, /* unmap image */ + + _cairo_surface_default_source, + proxy_acquire_source_image, + proxy_release_source_image, +}; + +static cairo_surface_t * +attach_proxy (cairo_surface_t *source, + cairo_surface_t *image) +{ + struct proxy *proxy; + + proxy = _cairo_calloc (sizeof (*proxy)); + if (unlikely (proxy == NULL)) + return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY); + + _cairo_surface_init (&proxy->base, &proxy_backend, NULL, image->content, FALSE); + + proxy->image = image; + _cairo_surface_attach_snapshot (source, &proxy->base, NULL); + + return &proxy->base; +} + +static void +detach_proxy (cairo_surface_t *source, + cairo_surface_t *proxy) +{ + cairo_surface_finish (proxy); + cairo_surface_destroy (proxy); +} + +static cairo_surface_t * +get_proxy (cairo_surface_t *proxy) +{ + return ((struct proxy *)proxy)->image; +} + +static pixman_image_t * +_pixman_image_for_recording (cairo_image_surface_t *dst, + const cairo_surface_pattern_t *pattern, + cairo_bool_t is_mask, + const cairo_rectangle_int_t *extents, + const cairo_rectangle_int_t *sample, + int *ix, int *iy) +{ + cairo_surface_t *source, *clone, *proxy; + cairo_rectangle_int_t limit; + cairo_rectangle_int_t src_limit; + pixman_image_t *pixman_image; + cairo_status_t status; + cairo_extend_t extend; + cairo_matrix_t *m, matrix; + double sx = 1.0, sy = 1.0; + int tx = 0, ty = 0; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + *ix = *iy = 0; + + source = _cairo_pattern_get_source (pattern, &limit); + src_limit = limit; + + extend = pattern->base.extend; + if (_cairo_rectangle_contains_rectangle (&limit, sample)) + extend = CAIRO_EXTEND_NONE; + + if (extend == CAIRO_EXTEND_NONE) { + if (! _cairo_rectangle_intersect (&limit, sample)) + return _pixman_transparent_image (); + } + + if (! _cairo_matrix_is_identity (&pattern->base.matrix)) { + double x1, y1, x2, y2; + + matrix = pattern->base.matrix; + status = cairo_matrix_invert (&matrix); + assert (status == CAIRO_STATUS_SUCCESS); + + x1 = limit.x; + y1 = limit.y; + x2 = limit.x + limit.width; + y2 = limit.y + limit.height; + + _cairo_matrix_transform_bounding_box (&matrix, + &x1, &y1, &x2, &y2, NULL); + + limit.x = floor (x1); + limit.y = floor (y1); + limit.width = ceil (x2) - limit.x; + limit.height = ceil (y2) - limit.y; + sx = (double)src_limit.width / limit.width; + sy = (double)src_limit.height / limit.height; + } + tx = limit.x; + ty = limit.y; + + /* XXX transformations! */ + proxy = _cairo_surface_has_snapshot (source, &proxy_backend); + if (proxy != NULL) { + clone = cairo_surface_reference (get_proxy (proxy)); + goto done; + } + + if (is_mask) { + clone = cairo_image_surface_create (CAIRO_FORMAT_A8, + limit.width, limit.height); + } else { + if (dst->base.content == source->content) + clone = cairo_image_surface_create (dst->format, + limit.width, limit.height); + else + clone = _cairo_image_surface_create_with_content (source->content, + limit.width, + limit.height); + if (dst->base.foreground_source) + clone->foreground_source = cairo_pattern_reference (dst->base.foreground_source); + } + + m = NULL; + if (extend == CAIRO_EXTEND_NONE) { + matrix = pattern->base.matrix; + if (tx | ty) + cairo_matrix_translate (&matrix, tx, ty); + m = &matrix; + } else { + cairo_matrix_init_scale (&matrix, sx, sy); + cairo_matrix_translate (&matrix, src_limit.x/sx, src_limit.y/sy); + m = &matrix; + } + + /* Handle recursion by returning future reads from the current image */ + proxy = attach_proxy (source, clone); + status = _cairo_recording_surface_replay_with_clip (source, m, clone, NULL); + if (clone->foreground_used) + dst->base.foreground_used = clone->foreground_used; + detach_proxy (source, proxy); + if (unlikely (status)) { + cairo_surface_destroy (clone); + return NULL; + } + +done: + pixman_image = pixman_image_ref (((cairo_image_surface_t *)clone)->pixman_image); + cairo_surface_destroy (clone); + + if (extend == CAIRO_EXTEND_NONE) { + *ix = -limit.x; + *iy = -limit.y; + } else { + cairo_pattern_union_t tmp_pattern; + _cairo_pattern_init_static_copy (&tmp_pattern.base, &pattern->base); + matrix = pattern->base.matrix; + status = cairo_matrix_invert(&matrix); + assert (status == CAIRO_STATUS_SUCCESS); + cairo_matrix_translate (&matrix, src_limit.x, src_limit.y); + cairo_matrix_scale (&matrix, sx, sy); + status = cairo_matrix_invert(&matrix); + assert (status == CAIRO_STATUS_SUCCESS); + cairo_pattern_set_matrix (&tmp_pattern.base, &matrix); + if (! _pixman_image_set_properties (pixman_image, + &tmp_pattern.base, extents, + ix, iy)) { + pixman_image_unref (pixman_image); + pixman_image= NULL; + } + } + + return pixman_image; +} + +static pixman_image_t * +_pixman_image_for_surface (cairo_image_surface_t *dst, + const cairo_surface_pattern_t *pattern, + cairo_bool_t is_mask, + const cairo_rectangle_int_t *extents, + const cairo_rectangle_int_t *sample, + int *ix, int *iy) +{ + cairo_extend_t extend = pattern->base.extend; + pixman_image_t *pixman_image; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + *ix = *iy = 0; + pixman_image = NULL; + if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) + return _pixman_image_for_recording(dst, pattern, + is_mask, extents, sample, + ix, iy); + + if (pattern->surface->type == CAIRO_SURFACE_TYPE_IMAGE && + (! is_mask || ! pattern->base.has_component_alpha || + (pattern->surface->content & CAIRO_CONTENT_COLOR) == 0)) + { + cairo_surface_t *defer_free = NULL; + cairo_image_surface_t *source = (cairo_image_surface_t *) pattern->surface; + cairo_surface_type_t type; + + if (_cairo_surface_is_snapshot (&source->base)) { + defer_free = _cairo_surface_snapshot_get_target (&source->base); + source = (cairo_image_surface_t *) defer_free; + } + + type = source->base.backend->type; + if (type == CAIRO_SURFACE_TYPE_IMAGE) { + if (extend != CAIRO_EXTEND_NONE && + sample->x >= 0 && + sample->y >= 0 && + sample->x + sample->width <= source->width && + sample->y + sample->height <= source->height) + { + extend = CAIRO_EXTEND_NONE; + } + + if (sample->width == 1 && sample->height == 1) { + if (sample->x < 0 || + sample->y < 0 || + sample->x >= source->width || + sample->y >= source->height) + { + if (extend == CAIRO_EXTEND_NONE) { + cairo_surface_destroy (defer_free); + return _pixman_transparent_image (); + } + } + else + { + pixman_image = _pixel_to_solid (source, + sample->x, sample->y); + if (pixman_image) { + cairo_surface_destroy (defer_free); + return pixman_image; + } + } + } + +#if PIXMAN_HAS_ATOMIC_OPS + /* avoid allocating a 'pattern' image if we can reuse the original */ + if (extend == CAIRO_EXTEND_NONE && + _cairo_matrix_is_pixman_translation (&pattern->base.matrix, + pattern->base.filter, + ix, iy)) + { + cairo_surface_destroy (defer_free); + return pixman_image_ref (source->pixman_image); + } +#endif + + pixman_image = pixman_image_create_bits (source->pixman_format, + source->width, + source->height, + (uint32_t *) source->data, + source->stride); + if (unlikely (pixman_image == NULL)) { + cairo_surface_destroy (defer_free); + return NULL; + } + + if (defer_free) { + pixman_image_set_destroy_function (pixman_image, + _defer_free_cleanup, + defer_free); + } + } else if (type == CAIRO_SURFACE_TYPE_SUBSURFACE) { + cairo_surface_subsurface_t *sub; + cairo_bool_t is_contained = FALSE; + + sub = (cairo_surface_subsurface_t *) source; + source = (cairo_image_surface_t *) sub->target; + + if (sample->x >= 0 && + sample->y >= 0 && + sample->x + sample->width <= sub->extents.width && + sample->y + sample->height <= sub->extents.height) + { + is_contained = TRUE; + } + + if (sample->width == 1 && sample->height == 1) { + if (is_contained) { + pixman_image = _pixel_to_solid (source, + sub->extents.x + sample->x, + sub->extents.y + sample->y); + if (pixman_image) + return pixman_image; + } else { + if (extend == CAIRO_EXTEND_NONE) + return _pixman_transparent_image (); + } + } + +#if PIXMAN_HAS_ATOMIC_OPS + *ix = sub->extents.x; + *iy = sub->extents.y; + if (is_contained && + _cairo_matrix_is_pixman_translation (&pattern->base.matrix, + pattern->base.filter, + ix, iy)) + { + return pixman_image_ref (source->pixman_image); + } +#endif + + /* Avoid sub-byte offsets, force a copy in that case. */ + if (PIXMAN_FORMAT_BPP (source->pixman_format) >= 8) { + if (is_contained) { + void *data = source->data + + sub->extents.x * PIXMAN_FORMAT_BPP(source->pixman_format)/8 + + sub->extents.y * source->stride; + pixman_image = pixman_image_create_bits (source->pixman_format, + sub->extents.width, + sub->extents.height, + data, + source->stride); + if (unlikely (pixman_image == NULL)) + return NULL; + } else { + /* XXX for a simple translation and EXTEND_NONE we can + * fix up the pattern matrix instead. + */ + } + } + } + } + + if (pixman_image == NULL) { + struct acquire_source_cleanup *cleanup; + cairo_image_surface_t *image; + void *extra; + cairo_status_t status; + + status = _cairo_surface_acquire_source_image (pattern->surface, &image, &extra); + if (unlikely (status)) + return NULL; + + pixman_image = pixman_image_create_bits (image->pixman_format, + image->width, + image->height, + (uint32_t *) image->data, + image->stride); + if (unlikely (pixman_image == NULL)) { + _cairo_surface_release_source_image (pattern->surface, image, extra); + return NULL; + } + + cleanup = _cairo_malloc (sizeof (*cleanup)); + if (unlikely (cleanup == NULL)) { + _cairo_surface_release_source_image (pattern->surface, image, extra); + pixman_image_unref (pixman_image); + return NULL; + } + + cleanup->surface = pattern->surface; + cleanup->image = image; + cleanup->image_extra = extra; + pixman_image_set_destroy_function (pixman_image, + _acquire_source_cleanup, cleanup); + } + + if (! _pixman_image_set_properties (pixman_image, + &pattern->base, extents, + ix, iy)) { + pixman_image_unref (pixman_image); + pixman_image= NULL; + } + + return pixman_image; +} + +struct raster_source_cleanup { + const cairo_pattern_t *pattern; + cairo_surface_t *surface; + cairo_image_surface_t *image; + void *image_extra; +}; + +static void +_raster_source_cleanup (pixman_image_t *pixman_image, + void *closure) +{ + struct raster_source_cleanup *data = closure; + + _cairo_surface_release_source_image (data->surface, + data->image, + data->image_extra); + + _cairo_raster_source_pattern_release (data->pattern, + data->surface); + + free (data); +} + +static pixman_image_t * +_pixman_image_for_raster (cairo_image_surface_t *dst, + const cairo_raster_source_pattern_t *pattern, + cairo_bool_t is_mask, + const cairo_rectangle_int_t *extents, + const cairo_rectangle_int_t *sample, + int *ix, int *iy) +{ + pixman_image_t *pixman_image; + struct raster_source_cleanup *cleanup; + cairo_image_surface_t *image; + void *extra; + cairo_status_t status; + cairo_surface_t *surface; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + *ix = *iy = 0; + + surface = _cairo_raster_source_pattern_acquire (&pattern->base, + &dst->base, NULL); + if (unlikely (surface == NULL || surface->status)) + return NULL; + + status = _cairo_surface_acquire_source_image (surface, &image, &extra); + if (unlikely (status)) { + _cairo_raster_source_pattern_release (&pattern->base, surface); + return NULL; + } + + assert (image->width == pattern->extents.width); + assert (image->height == pattern->extents.height); + + pixman_image = pixman_image_create_bits (image->pixman_format, + image->width, + image->height, + (uint32_t *) image->data, + image->stride); + if (unlikely (pixman_image == NULL)) { + _cairo_surface_release_source_image (surface, image, extra); + _cairo_raster_source_pattern_release (&pattern->base, surface); + return NULL; + } + + cleanup = _cairo_calloc (sizeof (*cleanup)); + if (unlikely (cleanup == NULL)) { + pixman_image_unref (pixman_image); + _cairo_surface_release_source_image (surface, image, extra); + _cairo_raster_source_pattern_release (&pattern->base, surface); + return NULL; + } + + cleanup->pattern = &pattern->base; + cleanup->surface = surface; + cleanup->image = image; + cleanup->image_extra = extra; + pixman_image_set_destroy_function (pixman_image, + _raster_source_cleanup, cleanup); + + if (! _pixman_image_set_properties (pixman_image, + &pattern->base, extents, + ix, iy)) { + pixman_image_unref (pixman_image); + pixman_image= NULL; + } + + return pixman_image; +} + +pixman_image_t * +_pixman_image_for_pattern (cairo_image_surface_t *dst, + const cairo_pattern_t *pattern, + cairo_bool_t is_mask, + const cairo_rectangle_int_t *extents, + const cairo_rectangle_int_t *sample, + int *tx, int *ty) +{ + *tx = *ty = 0; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + if (pattern == NULL) + return _pixman_white_image (); + + switch (pattern->type) { + default: + ASSERT_NOT_REACHED; + case CAIRO_PATTERN_TYPE_SOLID: + return _pixman_image_for_color (&((const cairo_solid_pattern_t *) pattern)->color); + + case CAIRO_PATTERN_TYPE_RADIAL: + case CAIRO_PATTERN_TYPE_LINEAR: + return _pixman_image_for_gradient ((const cairo_gradient_pattern_t *) pattern, + extents, tx, ty); + + case CAIRO_PATTERN_TYPE_MESH: + return _pixman_image_for_mesh ((const cairo_mesh_pattern_t *) pattern, + extents, tx, ty); + + case CAIRO_PATTERN_TYPE_SURFACE: + return _pixman_image_for_surface (dst, + (const cairo_surface_pattern_t *) pattern, + is_mask, extents, sample, + tx, ty); + + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + return _pixman_image_for_raster (dst, + (const cairo_raster_source_pattern_t *) pattern, + is_mask, extents, sample, + tx, ty); + } +} + +static cairo_status_t +_cairo_image_source_finish (void *abstract_surface) +{ + cairo_image_source_t *source = abstract_surface; + + pixman_image_unref (source->pixman_image); + return CAIRO_STATUS_SUCCESS; +} + +const cairo_surface_backend_t _cairo_image_source_backend = { + CAIRO_SURFACE_TYPE_IMAGE, + _cairo_image_source_finish, + NULL, /* read-only wrapper */ +}; + +cairo_surface_t * +_cairo_image_source_create_for_pattern (cairo_surface_t *dst, + const cairo_pattern_t *pattern, + cairo_bool_t is_mask, + const cairo_rectangle_int_t *extents, + const cairo_rectangle_int_t *sample, + int *src_x, int *src_y) +{ + cairo_image_source_t *source; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + source = _cairo_calloc (sizeof (cairo_image_source_t)); + if (unlikely (source == NULL)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + source->pixman_image = + _pixman_image_for_pattern ((cairo_image_surface_t *)dst, + pattern, is_mask, + extents, sample, + src_x, src_y); + if (unlikely (source->pixman_image == NULL)) { + free (source); + return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY); + } + + _cairo_surface_init (&source->base, + &_cairo_image_source_backend, + NULL, /* device */ + CAIRO_CONTENT_COLOR_ALPHA, + FALSE); /* is_vector */ + + source->is_opaque_solid = + pattern == NULL || _cairo_pattern_is_opaque_solid (pattern); + + return &source->base; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-image-surface-inline.h b/local/recipes/libs/cairo/source/src/cairo-image-surface-inline.h new file mode 100644 index 0000000000..743d5fd3e7 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-image-surface-inline.h @@ -0,0 +1,96 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + */ + +#ifndef CAIRO_IMAGE_SURFACE_INLINE_H +#define CAIRO_IMAGE_SURFACE_INLINE_H + +#include "cairo-surface-private.h" +#include "cairo-image-surface-private.h" + +CAIRO_BEGIN_DECLS + +static inline cairo_image_surface_t * +_cairo_image_surface_create_in_error (cairo_status_t status) +{ + return (cairo_image_surface_t *) _cairo_surface_create_in_error (status); +} + +static inline void +_cairo_image_surface_set_parent (cairo_image_surface_t *image, + cairo_surface_t *parent) +{ + image->parent = parent; +} + +static inline cairo_bool_t +_cairo_image_surface_is_clone (cairo_image_surface_t *image) +{ + return image->parent != NULL; +} + +/** + * _cairo_surface_is_image: + * @surface: a #cairo_surface_t + * + * Checks if a surface is an #cairo_image_surface_t + * + * Return value: %TRUE if the surface is an image surface + **/ +static inline cairo_bool_t +_cairo_surface_is_image (const cairo_surface_t *surface) +{ + /* _cairo_surface_nil sets a NULL backend so be safe */ + return surface->backend && surface->backend->type == CAIRO_SURFACE_TYPE_IMAGE; +} + +/** + * _cairo_surface_is_image_source: + * @surface: a #cairo_surface_t + * + * Checks if a surface is an #cairo_image_source_t + * + * Return value: %TRUE if the surface is an image source + **/ +static inline cairo_bool_t +_cairo_surface_is_image_source (const cairo_surface_t *surface) +{ + return surface->backend == &_cairo_image_source_backend; +} + +CAIRO_END_DECLS + +#endif /* CAIRO_IMAGE_SURFACE_INLINE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-image-surface-private.h b/local/recipes/libs/cairo/source/src/cairo-image-surface-private.h new file mode 100644 index 0000000000..2b7921133f --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-image-surface-private.h @@ -0,0 +1,239 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + */ + +#ifndef CAIRO_IMAGE_SURFACE_PRIVATE_H +#define CAIRO_IMAGE_SURFACE_PRIVATE_H + +#include "cairo-surface-private.h" + +#include +#include + +CAIRO_BEGIN_DECLS + +/* The canonical image backend */ +struct _cairo_image_surface { + cairo_surface_t base; + + pixman_image_t *pixman_image; + const cairo_compositor_t *compositor; + + /* Parenting is tricky wrt lifetime tracking... + * + * One use for tracking the parent of an image surface is for + * create_similar_image() where we wish to create a device specific + * surface but return an image surface to the user. In such a case, + * the image may be owned by the device specific surface, its parent, + * but the user lifetime tracking is then performed on the image. So + * when the image is then finalized we call cairo_surface_destroy() + * on the parent. However, for normal usage where the lifetime tracking + * is done on the parent surface, we need to be careful to unhook + * the image->parent pointer before finalizing the image. + */ + cairo_surface_t *parent; + + pixman_format_code_t pixman_format; + cairo_format_t format; + unsigned char *data; + + int width; + int height; + ptrdiff_t stride; + int depth; + + unsigned owns_data : 1; + unsigned transparency : 2; + unsigned color : 2; +}; +#define to_image_surface(S) ((cairo_image_surface_t *)(S)) + +/* A wrapper for holding pixman images returned by create_for_pattern */ +typedef struct _cairo_image_source { + cairo_surface_t base; + + pixman_image_t *pixman_image; + unsigned is_opaque_solid : 1; +} cairo_image_source_t; + +cairo_private extern const cairo_surface_backend_t _cairo_image_surface_backend; +cairo_private extern const cairo_surface_backend_t _cairo_image_source_backend; + +cairo_private const cairo_compositor_t * +_cairo_image_mask_compositor_get (void); + +cairo_private const cairo_compositor_t * +_cairo_image_traps_compositor_get (void); + +cairo_private const cairo_compositor_t * +_cairo_image_spans_compositor_get (void); + +#define _cairo_image_default_compositor_get _cairo_image_spans_compositor_get + +cairo_private cairo_int_status_t +_cairo_image_surface_paint (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip); + +cairo_private cairo_int_status_t +_cairo_image_surface_mask (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_clip_t *clip); + +cairo_private cairo_int_status_t +_cairo_image_surface_stroke (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip); + +cairo_private cairo_int_status_t +_cairo_image_surface_fill (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip); + +cairo_private cairo_int_status_t +_cairo_image_surface_glyphs (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip); + +cairo_private void +_cairo_image_surface_init (cairo_image_surface_t *surface, + pixman_image_t *pixman_image, + pixman_format_code_t pixman_format); + +cairo_private cairo_surface_t * +_cairo_image_surface_create_similar (void *abstract_other, + cairo_content_t content, + int width, + int height); + +cairo_private cairo_image_surface_t * +_cairo_image_surface_map_to_image (void *abstract_other, + const cairo_rectangle_int_t *extents); + +cairo_private cairo_int_status_t +_cairo_image_surface_unmap_image (void *abstract_surface, + cairo_image_surface_t *image); + +cairo_private cairo_surface_t * +_cairo_image_surface_source (void *abstract_surface, + cairo_rectangle_int_t *extents); + +cairo_private cairo_status_t +_cairo_image_surface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra); + +cairo_private void +_cairo_image_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra); + +cairo_private cairo_surface_t * +_cairo_image_surface_snapshot (void *abstract_surface); + +cairo_private_no_warn cairo_bool_t +_cairo_image_surface_get_extents (void *abstract_surface, + cairo_rectangle_int_t *rectangle); + +cairo_private void +_cairo_image_surface_get_font_options (void *abstract_surface, + cairo_font_options_t *options); + +cairo_private cairo_surface_t * +_cairo_image_source_create_for_pattern (cairo_surface_t *dst, + const cairo_pattern_t *pattern, + cairo_bool_t is_mask, + const cairo_rectangle_int_t *extents, + const cairo_rectangle_int_t *sample, + int *src_x, int *src_y); + +cairo_private cairo_status_t +_cairo_image_surface_finish (void *abstract_surface); + +cairo_private pixman_image_t * +_pixman_image_for_color (const cairo_color_t *cairo_color); + +cairo_private pixman_image_t * +_pixman_image_for_pattern (cairo_image_surface_t *dst, + const cairo_pattern_t *pattern, + cairo_bool_t is_mask, + const cairo_rectangle_int_t *extents, + const cairo_rectangle_int_t *sample, + int *tx, int *ty); + +cairo_private void +_pixman_image_add_traps (pixman_image_t *image, + int dst_x, int dst_y, + cairo_traps_t *traps); + +cairo_private void +_pixman_image_add_tristrip (pixman_image_t *image, + int dst_x, int dst_y, + cairo_tristrip_t *strip); + +cairo_private cairo_image_surface_t * +_cairo_image_surface_clone_subimage (cairo_surface_t *surface, + const cairo_rectangle_int_t *extents); + +/* Similar to clone; but allow format conversion */ +cairo_private cairo_image_surface_t * +_cairo_image_surface_create_from_image (cairo_image_surface_t *other, + pixman_format_code_t format, + int x, int y, int width, int height, + int stride); + +CAIRO_END_DECLS + +#endif /* CAIRO_IMAGE_SURFACE_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-image-surface.c b/local/recipes/libs/cairo/source/src/cairo-image-surface.c new file mode 100644 index 0000000000..f18366b635 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-image-surface.c @@ -0,0 +1,1372 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2003 University of Southern California + * Copyright © 2009,2010,2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Chris Wilson + */ + +#include "cairoint.h" + +#include "cairo-boxes-private.h" +#include "cairo-clip-private.h" +#include "cairo-composite-rectangles-private.h" +#include "cairo-compositor-private.h" +#include "cairo-default-context-private.h" +#include "cairo-error-private.h" +#include "cairo-image-surface-inline.h" +#include "cairo-paginated-private.h" +#include "cairo-pattern-private.h" +#include "cairo-pixman-private.h" +#include "cairo-recording-surface-private.h" +#include "cairo-region-private.h" +#include "cairo-scaled-font-private.h" +#include "cairo-surface-snapshot-inline.h" +#include "cairo-surface-snapshot-private.h" +#include "cairo-surface-subsurface-private.h" + +/* Limit on the width / height of an image surface in pixels. This is + * mainly determined by coordinates of things sent to pixman at the + * moment being in 16.16 format. */ +#define MAX_IMAGE_SIZE 32767 + +/** + * SECTION:cairo-image + * @Title: Image Surfaces + * @Short_Description: Rendering to memory buffers + * @See_Also: #cairo_surface_t + * + * Image surfaces provide the ability to render to memory buffers + * either allocated by cairo or by the calling code. The supported + * image formats are those defined in #cairo_format_t. + **/ + +/** + * CAIRO_HAS_IMAGE_SURFACE: + * + * Defined if the image surface backend is available. + * The image surface backend is always built in. + * This macro was added for completeness in cairo 1.8. + * + * Since: 1.8 + **/ + +static cairo_bool_t +_cairo_image_surface_is_size_valid (int width, int height) +{ + return 0 <= width && width <= MAX_IMAGE_SIZE && + 0 <= height && height <= MAX_IMAGE_SIZE; +} + +cairo_format_t +_cairo_format_from_pixman_format (pixman_format_code_t pixman_format) +{ + switch (pixman_format) { + case PIXMAN_rgba_float: + return CAIRO_FORMAT_RGBA128F; + case PIXMAN_rgb_float: + return CAIRO_FORMAT_RGB96F; + case PIXMAN_a8r8g8b8: + return CAIRO_FORMAT_ARGB32; + case PIXMAN_x2r10g10b10: + return CAIRO_FORMAT_RGB30; + case PIXMAN_x8r8g8b8: + return CAIRO_FORMAT_RGB24; + case PIXMAN_a8: + return CAIRO_FORMAT_A8; + case PIXMAN_a1: + return CAIRO_FORMAT_A1; + case PIXMAN_r5g6b5: + return CAIRO_FORMAT_RGB16_565; + case PIXMAN_r8g8b8a8: case PIXMAN_r8g8b8x8: + case PIXMAN_a8r8g8b8_sRGB: +#if HAS_PIXMAN_r8g8b8_sRGB + case PIXMAN_r8g8b8_sRGB: +#endif + case PIXMAN_a8b8g8r8: case PIXMAN_x8b8g8r8: case PIXMAN_r8g8b8: + case PIXMAN_b8g8r8: case PIXMAN_b5g6r5: + case PIXMAN_a1r5g5b5: case PIXMAN_x1r5g5b5: case PIXMAN_a1b5g5r5: + case PIXMAN_x1b5g5r5: case PIXMAN_a4r4g4b4: case PIXMAN_x4r4g4b4: + case PIXMAN_a4b4g4r4: case PIXMAN_x4b4g4r4: case PIXMAN_r3g3b2: + case PIXMAN_b2g3r3: case PIXMAN_a2r2g2b2: case PIXMAN_a2b2g2r2: + case PIXMAN_c8: case PIXMAN_g8: case PIXMAN_x4a4: + case PIXMAN_a4: case PIXMAN_r1g2b1: case PIXMAN_b1g2r1: + case PIXMAN_a1r1g1b1: case PIXMAN_a1b1g1r1: case PIXMAN_c4: + case PIXMAN_g4: case PIXMAN_g1: + case PIXMAN_yuy2: case PIXMAN_yv12: + case PIXMAN_b8g8r8x8: + case PIXMAN_b8g8r8a8: + case PIXMAN_a2b10g10r10: + case PIXMAN_x2b10g10r10: + case PIXMAN_a2r10g10b10: + case PIXMAN_x14r6g6b6: + default: + return CAIRO_FORMAT_INVALID; + } + + return CAIRO_FORMAT_INVALID; +} + +cairo_content_t +_cairo_content_from_pixman_format (pixman_format_code_t pixman_format) +{ + cairo_content_t content; + + content = 0; + if (PIXMAN_FORMAT_RGB (pixman_format)) + content |= CAIRO_CONTENT_COLOR; + if (PIXMAN_FORMAT_A (pixman_format)) + content |= CAIRO_CONTENT_ALPHA; + + return content; +} + +void +_cairo_image_surface_init (cairo_image_surface_t *surface, + pixman_image_t *pixman_image, + pixman_format_code_t pixman_format) +{ + surface->parent = NULL; + surface->pixman_image = pixman_image; + + surface->pixman_format = pixman_format; + surface->format = _cairo_format_from_pixman_format (pixman_format); + surface->data = (uint8_t *) pixman_image_get_data (pixman_image); + surface->owns_data = FALSE; + surface->transparency = CAIRO_IMAGE_UNKNOWN; + surface->color = CAIRO_IMAGE_UNKNOWN_COLOR; + + surface->width = pixman_image_get_width (pixman_image); + surface->height = pixman_image_get_height (pixman_image); + surface->stride = pixman_image_get_stride (pixman_image); + surface->depth = pixman_image_get_depth (pixman_image); + + surface->base.is_clear = surface->width == 0 || surface->height == 0; + + surface->compositor = _cairo_image_spans_compositor_get (); +} + +cairo_surface_t * +_cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image, + pixman_format_code_t pixman_format) +{ + cairo_image_surface_t *surface; + + surface = _cairo_calloc (sizeof (cairo_image_surface_t)); + if (unlikely (surface == NULL)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + _cairo_surface_init (&surface->base, + &_cairo_image_surface_backend, + NULL, /* device */ + _cairo_content_from_pixman_format (pixman_format), + FALSE); /* is_vector */ + + _cairo_image_surface_init (surface, pixman_image, pixman_format); + + return &surface->base; +} + +cairo_bool_t +_pixman_format_from_masks (cairo_format_masks_t *masks, + pixman_format_code_t *format_ret) +{ + pixman_format_code_t format; + int format_type; + int a, r, g, b; + cairo_format_masks_t format_masks; + + a = _cairo_popcount (masks->alpha_mask); + r = _cairo_popcount (masks->red_mask); + g = _cairo_popcount (masks->green_mask); + b = _cairo_popcount (masks->blue_mask); + + if (masks->red_mask) { + if (masks->red_mask > masks->blue_mask) + format_type = PIXMAN_TYPE_ARGB; + else + format_type = PIXMAN_TYPE_ABGR; + } else if (masks->alpha_mask) { + format_type = PIXMAN_TYPE_A; + } else { + return FALSE; + } + + format = PIXMAN_FORMAT (masks->bpp, format_type, a, r, g, b); + + if (! pixman_format_supported_destination (format)) + return FALSE; + + /* Sanity check that we got out of PIXMAN_FORMAT exactly what we + * expected. This avoid any problems from something bizarre like + * alpha in the least-significant bits, or insane channel order, + * or whatever. */ + if (!_pixman_format_to_masks (format, &format_masks) || + masks->bpp != format_masks.bpp || + masks->red_mask != format_masks.red_mask || + masks->green_mask != format_masks.green_mask || + masks->blue_mask != format_masks.blue_mask) + { + return FALSE; + } + + *format_ret = format; + return TRUE; +} + +/* Convenience function to convert #cairo_dither_t into #pixman_dither_t */ +static pixman_dither_t +_cairo_dither_to_pixman_dither (cairo_dither_t dither) +{ + switch (dither) { + case CAIRO_DITHER_FAST: + return PIXMAN_DITHER_FAST; + case CAIRO_DITHER_GOOD: + return PIXMAN_DITHER_GOOD; + case CAIRO_DITHER_BEST: + return PIXMAN_DITHER_BEST; + case CAIRO_DITHER_NONE: + case CAIRO_DITHER_DEFAULT: + default: + return PIXMAN_DITHER_NONE; + } +} + +/* A mask consisting of N bits set to 1. */ +#define MASK(N) ((1UL << (N))-1) + +cairo_bool_t +_pixman_format_to_masks (pixman_format_code_t format, + cairo_format_masks_t *masks) +{ + int a, r, g, b; + + masks->bpp = PIXMAN_FORMAT_BPP (format); + + /* Number of bits in each channel */ + a = PIXMAN_FORMAT_A (format); + r = PIXMAN_FORMAT_R (format); + g = PIXMAN_FORMAT_G (format); + b = PIXMAN_FORMAT_B (format); + + switch (PIXMAN_FORMAT_TYPE (format)) { + case PIXMAN_TYPE_ARGB: + masks->alpha_mask = MASK (a) << (r + g + b); + masks->red_mask = MASK (r) << (g + b); + masks->green_mask = MASK (g) << (b); + masks->blue_mask = MASK (b); + return TRUE; + case PIXMAN_TYPE_ABGR: + masks->alpha_mask = MASK (a) << (b + g + r); + masks->blue_mask = MASK (b) << (g + r); + masks->green_mask = MASK (g) << (r); + masks->red_mask = MASK (r); + return TRUE; +#ifdef PIXMAN_TYPE_BGRA + case PIXMAN_TYPE_BGRA: + masks->blue_mask = MASK (b) << (masks->bpp - b); + masks->green_mask = MASK (g) << (masks->bpp - b - g); + masks->red_mask = MASK (r) << (masks->bpp - b - g - r); + masks->alpha_mask = MASK (a); + return TRUE; +#endif + case PIXMAN_TYPE_A: + masks->alpha_mask = MASK (a); + masks->red_mask = 0; + masks->green_mask = 0; + masks->blue_mask = 0; + return TRUE; + case PIXMAN_TYPE_OTHER: + case PIXMAN_TYPE_COLOR: + case PIXMAN_TYPE_GRAY: + case PIXMAN_TYPE_YUY2: + case PIXMAN_TYPE_YV12: + default: + masks->alpha_mask = 0; + masks->red_mask = 0; + masks->green_mask = 0; + masks->blue_mask = 0; + return FALSE; + } +} + +pixman_format_code_t +_cairo_format_to_pixman_format_code (cairo_format_t format) +{ + pixman_format_code_t ret; + switch (format) { + case CAIRO_FORMAT_A1: + ret = PIXMAN_a1; + break; + case CAIRO_FORMAT_A8: + ret = PIXMAN_a8; + break; + case CAIRO_FORMAT_RGB24: + ret = PIXMAN_x8r8g8b8; + break; + case CAIRO_FORMAT_RGB30: + ret = PIXMAN_x2r10g10b10; + break; + case CAIRO_FORMAT_RGB16_565: + ret = PIXMAN_r5g6b5; + break; + case CAIRO_FORMAT_RGB96F: + ret = PIXMAN_rgb_float; + break; + case CAIRO_FORMAT_RGBA128F: + ret = PIXMAN_rgba_float; + break; + case CAIRO_FORMAT_ARGB32: + case CAIRO_FORMAT_INVALID: + default: + ret = PIXMAN_a8r8g8b8; + break; + } + return ret; +} + +cairo_surface_t * +_cairo_image_surface_create_with_pixman_format (unsigned char *data, + pixman_format_code_t pixman_format, + int width, + int height, + int stride) +{ + cairo_surface_t *surface; + pixman_image_t *pixman_image; + + if (! _cairo_image_surface_is_size_valid (width, height)) + { + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); + } + + pixman_image = pixman_image_create_bits (pixman_format, width, height, + (uint32_t *) data, stride); + + if (unlikely (pixman_image == NULL)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + surface = _cairo_image_surface_create_for_pixman_image (pixman_image, + pixman_format); + if (unlikely (surface->status)) { + pixman_image_unref (pixman_image); + return surface; + } + + /* we can not make any assumptions about the initial state of user data */ + surface->is_clear = data == NULL; + return surface; +} + +/** + * cairo_image_surface_create: + * @format: format of pixels in the surface to create + * @width: width of the surface, in pixels + * @height: height of the surface, in pixels + * + * Creates an image surface of the specified format and + * dimensions. Initially the surface contents are set to 0. + * (Specifically, within each pixel, each color or alpha channel + * belonging to format will be 0. The contents of bits within a pixel, + * but not belonging to the given format are undefined). + * + * Return value: a pointer to the newly created surface. The caller + * owns the surface and should call cairo_surface_destroy() when done + * with it. + * + * This function always returns a valid pointer, but it will return a + * pointer to a "nil" surface if an error such as out of memory + * occurs. You can use cairo_surface_status() to check for this. + * + * Since: 1.0 + **/ +cairo_surface_t * +cairo_image_surface_create (cairo_format_t format, + int width, + int height) +{ + pixman_format_code_t pixman_format; + + if (! CAIRO_FORMAT_VALID (format)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); + + pixman_format = _cairo_format_to_pixman_format_code (format); + + return _cairo_image_surface_create_with_pixman_format (NULL, pixman_format, + width, height, -1); +} + +cairo_surface_t * +_cairo_image_surface_create_with_content (cairo_content_t content, + int width, + int height) +{ + return cairo_image_surface_create (_cairo_format_from_content (content), + width, height); +} + +/** + * cairo_format_stride_for_width: + * @format: A #cairo_format_t value + * @width: The desired width of an image surface to be created. + * + * This function provides a stride value that will respect all + * alignment requirements of the accelerated image-rendering code + * within cairo. Typical usage will be of the form: + * + * + * int stride; + * unsigned char *data; + * cairo_surface_t *surface; + * + * stride = cairo_format_stride_for_width (format, width); + * data = malloc (stride * height); + * surface = cairo_image_surface_create_for_data (data, format, + * width, height, + * stride); + * + * + * Return value: the appropriate stride to use given the desired + * format and width, or -1 if either the format is invalid or the width + * too large. + * + * Since: 1.6 + **/ +int +cairo_format_stride_for_width (cairo_format_t format, + int width) +{ + int bpp; + + if (! CAIRO_FORMAT_VALID (format)) { + _cairo_error_throw (CAIRO_STATUS_INVALID_FORMAT); + return -1; + } + + bpp = _cairo_format_bits_per_pixel (format); + if ((unsigned) (width) >= (INT32_MAX - 7) / (unsigned) (bpp)) + return -1; + + return CAIRO_STRIDE_FOR_WIDTH_BPP (width, bpp); +} + +/** + * cairo_image_surface_create_for_data: + * @data: a pointer to a buffer supplied by the application in which + * to write contents. This pointer must be suitably aligned for any + * kind of variable, (for example, a pointer returned by malloc). + * @format: the format of pixels in the buffer + * @width: the width of the image to be stored in the buffer + * @height: the height of the image to be stored in the buffer + * @stride: the number of bytes between the start of rows in the + * buffer as allocated. This value should always be computed by + * cairo_format_stride_for_width() before allocating the data + * buffer. + * + * Creates an image surface for the provided pixel data. The output + * buffer must be kept around until the #cairo_surface_t is destroyed + * or cairo_surface_finish() is called on the surface. The initial + * contents of @data will be used as the initial image contents; you + * must explicitly clear the buffer, using, for example, + * cairo_rectangle() and cairo_fill() if you want it cleared. + * + * Note that the stride may be larger than + * width*bytes_per_pixel to provide proper alignment for each pixel + * and row. This alignment is required to allow high-performance rendering + * within cairo. The correct way to obtain a legal stride value is to + * call cairo_format_stride_for_width() with the desired format and + * maximum image width value, and then use the resulting stride value + * to allocate the data and to create the image surface. See + * cairo_format_stride_for_width() for example code. + * + * Return value: a pointer to the newly created surface. The caller + * owns the surface and should call cairo_surface_destroy() when done + * with it. + * + * This function always returns a valid pointer, but it will return a + * pointer to a "nil" surface in the case of an error such as out of + * memory or an invalid stride value. In case of invalid stride value + * the error status of the returned surface will be + * %CAIRO_STATUS_INVALID_STRIDE. You can use + * cairo_surface_status() to check for this. + * + * See cairo_surface_set_user_data() for a means of attaching a + * destroy-notification fallback to the surface if necessary. + * + * Since: 1.0 + **/ +cairo_surface_t * +cairo_image_surface_create_for_data (unsigned char *data, + cairo_format_t format, + int width, + int height, + int stride) +{ + pixman_format_code_t pixman_format; + int minstride; + + if (! CAIRO_FORMAT_VALID (format)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); + + if ((stride & (CAIRO_STRIDE_ALIGNMENT-1)) != 0) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE)); + + if (! _cairo_image_surface_is_size_valid (width, height)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); + + minstride = cairo_format_stride_for_width (format, width); + if (stride < 0) { + if (stride > -minstride) { + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE)); + } + } else { + if (stride < minstride) { + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE)); + } + } + + pixman_format = _cairo_format_to_pixman_format_code (format); + return _cairo_image_surface_create_with_pixman_format (data, + pixman_format, + width, height, + stride); +} + +/** + * cairo_image_surface_get_data: + * @surface: a #cairo_image_surface_t + * + * Get a pointer to the data of the image surface, for direct + * inspection or modification. + * + * A call to cairo_surface_flush() is required before accessing the + * pixel data to ensure that all pending drawing operations are + * finished. A call to cairo_surface_mark_dirty() is required after + * the data is modified. + * + * Return value: a pointer to the image data of this surface or %NULL + * if @surface is not an image surface, or if cairo_surface_finish() + * has been called. + * + * Since: 1.2 + **/ +unsigned char * +cairo_image_surface_get_data (cairo_surface_t *surface) +{ + cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface; + + if (! _cairo_surface_is_image (surface)) { + _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + return NULL; + } + + return image_surface->data; +} + +/** + * cairo_image_surface_get_format: + * @surface: a #cairo_image_surface_t + * + * Get the format of the surface. + * + * Return value: the format of the surface + * + * Since: 1.2 + **/ +cairo_format_t +cairo_image_surface_get_format (cairo_surface_t *surface) +{ + cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface; + + if (! _cairo_surface_is_image (surface)) { + _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + return CAIRO_FORMAT_INVALID; + } + + return image_surface->format; +} + +/** + * cairo_image_surface_get_width: + * @surface: a #cairo_image_surface_t + * + * Get the width of the image surface in pixels. + * + * Return value: the width of the surface in pixels. + * + * Since: 1.0 + **/ +int +cairo_image_surface_get_width (cairo_surface_t *surface) +{ + cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface; + + if (! _cairo_surface_is_image (surface)) { + _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + return 0; + } + + return image_surface->width; +} + +/** + * cairo_image_surface_get_height: + * @surface: a #cairo_image_surface_t + * + * Get the height of the image surface in pixels. + * + * Return value: the height of the surface in pixels. + * + * Since: 1.0 + **/ +int +cairo_image_surface_get_height (cairo_surface_t *surface) +{ + cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface; + + if (! _cairo_surface_is_image (surface)) { + _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + return 0; + } + + return image_surface->height; +} + +/** + * cairo_image_surface_get_stride: + * @surface: a #cairo_image_surface_t + * + * Get the stride of the image surface in bytes + * + * Return value: the stride of the image surface in bytes (or 0 if + * @surface is not an image surface). The stride is the distance in + * bytes from the beginning of one row of the image data to the + * beginning of the next row. + * + * Since: 1.2 + **/ +int +cairo_image_surface_get_stride (cairo_surface_t *surface) +{ + + cairo_image_surface_t *image_surface = (cairo_image_surface_t *) surface; + + if (! _cairo_surface_is_image (surface)) { + _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + return 0; + } + + return image_surface->stride; +} + +cairo_format_t +_cairo_format_from_content (cairo_content_t content) +{ + switch (content) { + case CAIRO_CONTENT_COLOR: + return CAIRO_FORMAT_RGB24; + case CAIRO_CONTENT_ALPHA: + return CAIRO_FORMAT_A8; + case CAIRO_CONTENT_COLOR_ALPHA: + return CAIRO_FORMAT_ARGB32; + } + + ASSERT_NOT_REACHED; + return CAIRO_FORMAT_INVALID; +} + +cairo_content_t +_cairo_content_from_format (cairo_format_t format) +{ + switch (format) { + case CAIRO_FORMAT_RGBA128F: + case CAIRO_FORMAT_ARGB32: + return CAIRO_CONTENT_COLOR_ALPHA; + case CAIRO_FORMAT_RGB96F: + case CAIRO_FORMAT_RGB30: + return CAIRO_CONTENT_COLOR; + case CAIRO_FORMAT_RGB24: + return CAIRO_CONTENT_COLOR; + case CAIRO_FORMAT_RGB16_565: + return CAIRO_CONTENT_COLOR; + case CAIRO_FORMAT_A8: + case CAIRO_FORMAT_A1: + return CAIRO_CONTENT_ALPHA; + case CAIRO_FORMAT_INVALID: + break; + } + + ASSERT_NOT_REACHED; + return CAIRO_CONTENT_COLOR_ALPHA; +} + +int +_cairo_format_bits_per_pixel (cairo_format_t format) +{ + switch (format) { + case CAIRO_FORMAT_RGBA128F: + return 128; + case CAIRO_FORMAT_RGB96F: + return 96; + case CAIRO_FORMAT_ARGB32: + case CAIRO_FORMAT_RGB30: + case CAIRO_FORMAT_RGB24: + return 32; + case CAIRO_FORMAT_RGB16_565: + return 16; + case CAIRO_FORMAT_A8: + return 8; + case CAIRO_FORMAT_A1: + return 1; + case CAIRO_FORMAT_INVALID: + default: + ASSERT_NOT_REACHED; + return 0; + } +} + +cairo_surface_t * +_cairo_image_surface_create_similar (void *abstract_other, + cairo_content_t content, + int width, + int height) +{ + cairo_image_surface_t *other = abstract_other; + + TRACE ((stderr, "%s (other=%u)\n", __FUNCTION__, other->base.unique_id)); + + if (! _cairo_image_surface_is_size_valid (width, height)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); + + if (content == other->base.content) { + return _cairo_image_surface_create_with_pixman_format (NULL, + other->pixman_format, + width, height, + 0); + } + + return _cairo_image_surface_create_with_content (content, + width, height); +} + +cairo_surface_t * +_cairo_image_surface_snapshot (void *abstract_surface) +{ + cairo_image_surface_t *image = abstract_surface; + cairo_image_surface_t *clone; + + /* If we own the image, we can simply steal the memory for the snapshot */ + if (image->owns_data && image->base._finishing) { + clone = (cairo_image_surface_t *) + _cairo_image_surface_create_for_pixman_image (image->pixman_image, + image->pixman_format); + if (unlikely (clone->base.status)) + return &clone->base; + + image->pixman_image = NULL; + image->owns_data = FALSE; + + clone->transparency = image->transparency; + clone->color = image->color; + + clone->owns_data = TRUE; + return &clone->base; + } + + clone = (cairo_image_surface_t *) + _cairo_image_surface_create_with_pixman_format (NULL, + image->pixman_format, + image->width, + image->height, + 0); + if (unlikely (clone->base.status)) + return &clone->base; + + if (clone->stride == image->stride) { + memcpy (clone->data, image->data, clone->stride * clone->height); + } else { + pixman_image_composite32 (PIXMAN_OP_SRC, + image->pixman_image, NULL, clone->pixman_image, + 0, 0, + 0, 0, + 0, 0, + image->width, image->height); + } + clone->base.is_clear = FALSE; + return &clone->base; +} + +cairo_image_surface_t * +_cairo_image_surface_map_to_image (void *abstract_other, + const cairo_rectangle_int_t *extents) +{ + cairo_image_surface_t *other = abstract_other; + cairo_surface_t *surface; + uint8_t *data; + + data = other->data; + data += extents->y * other->stride; + data += extents->x * PIXMAN_FORMAT_BPP (other->pixman_format)/ 8; + + surface = + _cairo_image_surface_create_with_pixman_format (data, + other->pixman_format, + extents->width, + extents->height, + other->stride); + + cairo_surface_set_device_offset (surface, -extents->x, -extents->y); + return (cairo_image_surface_t *) surface; +} + +cairo_int_status_t +_cairo_image_surface_unmap_image (void *abstract_surface, + cairo_image_surface_t *image) +{ + cairo_surface_finish (&image->base); + cairo_surface_destroy (&image->base); + + return CAIRO_INT_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_image_surface_finish (void *abstract_surface) +{ + cairo_image_surface_t *surface = abstract_surface; + + if (surface->pixman_image) { + pixman_image_unref (surface->pixman_image); + surface->pixman_image = NULL; + } + + if (surface->owns_data) { + free (surface->data); + surface->data = NULL; + } + + if (surface->parent) { + cairo_surface_t *parent = surface->parent; + surface->parent = NULL; + cairo_surface_destroy (parent); + } + + return CAIRO_STATUS_SUCCESS; +} + +void +_cairo_image_surface_assume_ownership_of_data (cairo_image_surface_t *surface) +{ + surface->owns_data = TRUE; +} + +cairo_surface_t * +_cairo_image_surface_source (void *abstract_surface, + cairo_rectangle_int_t *extents) +{ + cairo_image_surface_t *surface = abstract_surface; + + if (extents) { + extents->x = extents->y = 0; + extents->width = surface->width; + extents->height = surface->height; + } + + return &surface->base; +} + +cairo_status_t +_cairo_image_surface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) +{ + *image_out = abstract_surface; + *image_extra = NULL; + + return CAIRO_STATUS_SUCCESS; +} + +void +_cairo_image_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) +{ +} + +/* high level image interface */ +cairo_bool_t +_cairo_image_surface_get_extents (void *abstract_surface, + cairo_rectangle_int_t *rectangle) +{ + cairo_image_surface_t *surface = abstract_surface; + + rectangle->x = 0; + rectangle->y = 0; + rectangle->width = surface->width; + rectangle->height = surface->height; + + return TRUE; +} + +cairo_int_status_t +_cairo_image_surface_paint (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip) +{ + cairo_image_surface_t *surface = abstract_surface; + pixman_dither_t pixman_dither = _cairo_dither_to_pixman_dither (source->dither); + pixman_image_set_dither (surface->pixman_image, pixman_dither); + + TRACE ((stderr, "%s (surface=%d)\n", + __FUNCTION__, surface->base.unique_id)); + + return _cairo_compositor_paint (surface->compositor, + &surface->base, op, source, clip); +} + +cairo_int_status_t +_cairo_image_surface_mask (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_clip_t *clip) +{ + cairo_image_surface_t *surface = abstract_surface; + + TRACE ((stderr, "%s (surface=%d)\n", + __FUNCTION__, surface->base.unique_id)); + + return _cairo_compositor_mask (surface->compositor, + &surface->base, op, source, mask, clip); +} + +cairo_int_status_t +_cairo_image_surface_stroke (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_image_surface_t *surface = abstract_surface; + + TRACE ((stderr, "%s (surface=%d)\n", + __FUNCTION__, surface->base.unique_id)); + + return _cairo_compositor_stroke (surface->compositor, &surface->base, + op, source, path, + style, ctm, ctm_inverse, + tolerance, antialias, clip); +} + +cairo_int_status_t +_cairo_image_surface_fill (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_image_surface_t *surface = abstract_surface; + + TRACE ((stderr, "%s (surface=%d)\n", + __FUNCTION__, surface->base.unique_id)); + + return _cairo_compositor_fill (surface->compositor, &surface->base, + op, source, path, + fill_rule, tolerance, antialias, + clip); +} + +cairo_int_status_t +_cairo_image_surface_glyphs (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip) +{ + cairo_image_surface_t *surface = abstract_surface; + + TRACE ((stderr, "%s (surface=%d)\n", + __FUNCTION__, surface->base.unique_id)); + + return _cairo_compositor_glyphs (surface->compositor, &surface->base, + op, source, + glyphs, num_glyphs, scaled_font, + clip); +} + +void +_cairo_image_surface_get_font_options (void *abstract_surface, + cairo_font_options_t *options) +{ + _cairo_font_options_init_default (options); + + cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_ON); + _cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_ON); +} + +const cairo_surface_backend_t _cairo_image_surface_backend = { + CAIRO_SURFACE_TYPE_IMAGE, + _cairo_image_surface_finish, + + _cairo_default_context_create, + + _cairo_image_surface_create_similar, + NULL, /* create similar image */ + _cairo_image_surface_map_to_image, + _cairo_image_surface_unmap_image, + + _cairo_image_surface_source, + _cairo_image_surface_acquire_source_image, + _cairo_image_surface_release_source_image, + _cairo_image_surface_snapshot, + + NULL, /* copy_page */ + NULL, /* show_page */ + + _cairo_image_surface_get_extents, + _cairo_image_surface_get_font_options, + + NULL, /* flush */ + NULL, + + _cairo_image_surface_paint, + _cairo_image_surface_mask, + _cairo_image_surface_stroke, + _cairo_image_surface_fill, + NULL, /* fill-stroke */ + _cairo_image_surface_glyphs, +}; + +/* A convenience function for when one needs to coerce an image + * surface to an alternate format. */ +cairo_image_surface_t * +_cairo_image_surface_coerce (cairo_image_surface_t *surface) +{ + return _cairo_image_surface_coerce_to_format (surface, + _cairo_format_from_content (surface->base.content)); +} + +/* A convenience function for when one needs to coerce an image + * surface to an alternate format. */ +cairo_image_surface_t * +_cairo_image_surface_coerce_to_format (cairo_image_surface_t *surface, + cairo_format_t format) +{ + cairo_image_surface_t *clone; + cairo_status_t status; + + status = surface->base.status; + if (unlikely (status)) + return (cairo_image_surface_t *)_cairo_surface_create_in_error (status); + + if (surface->format == format) + return (cairo_image_surface_t *)cairo_surface_reference(&surface->base); + + clone = (cairo_image_surface_t *) + cairo_image_surface_create (format, surface->width, surface->height); + if (unlikely (clone->base.status)) + return clone; + + pixman_image_composite32 (PIXMAN_OP_SRC, + surface->pixman_image, NULL, clone->pixman_image, + 0, 0, + 0, 0, + 0, 0, + surface->width, surface->height); + clone->base.is_clear = FALSE; + + clone->base.device_transform = + surface->base.device_transform; + clone->base.device_transform_inverse = + surface->base.device_transform_inverse; + + return clone; +} + +cairo_image_surface_t * +_cairo_image_surface_create_from_image (cairo_image_surface_t *other, + pixman_format_code_t format, + int x, int y, + int width, int height, int stride) +{ + cairo_image_surface_t *surface; + cairo_status_t status; + pixman_image_t *image; + void *mem = NULL; + + status = other->base.status; + if (unlikely (status)) + goto cleanup; + + if (stride) { + mem = _cairo_malloc_ab (height, stride); + if (unlikely (mem == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto cleanup; + } + } + + image = pixman_image_create_bits (format, width, height, mem, stride); + if (unlikely (image == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto cleanup_mem; + } + + surface = (cairo_image_surface_t *) + _cairo_image_surface_create_for_pixman_image (image, format); + if (unlikely (surface->base.status)) { + status = surface->base.status; + goto cleanup_image; + } + + pixman_image_composite32 (PIXMAN_OP_SRC, + other->pixman_image, NULL, image, + x, y, + 0, 0, + 0, 0, + width, height); + surface->base.is_clear = FALSE; + surface->owns_data = mem != NULL; + + return surface; + +cleanup_image: + pixman_image_unref (image); +cleanup_mem: + free (mem); +cleanup: + return (cairo_image_surface_t *) _cairo_surface_create_in_error (status); +} + +static cairo_image_transparency_t +_cairo_image_compute_transparency (cairo_image_surface_t *image) +{ + int x, y; + cairo_image_transparency_t transparency; + + if ((image->base.content & CAIRO_CONTENT_ALPHA) == 0) + return CAIRO_IMAGE_IS_OPAQUE; + + if (image->base.is_clear) + return CAIRO_IMAGE_HAS_BILEVEL_ALPHA; + + if ((image->base.content & CAIRO_CONTENT_COLOR) == 0) { + if (image->format == CAIRO_FORMAT_A1) { + return CAIRO_IMAGE_HAS_BILEVEL_ALPHA; + } else if (image->format == CAIRO_FORMAT_A8) { + for (y = 0; y < image->height; y++) { + uint8_t *alpha = (uint8_t *) (image->data + y * image->stride); + + for (x = 0; x < image->width; x++, alpha++) { + if (*alpha > 0 && *alpha < 255) + return CAIRO_IMAGE_HAS_ALPHA; + } + } + return CAIRO_IMAGE_HAS_BILEVEL_ALPHA; + } else { + return CAIRO_IMAGE_HAS_ALPHA; + } + } + + if (image->format == CAIRO_FORMAT_RGB16_565) { + return CAIRO_IMAGE_IS_OPAQUE; + } + + if (image->format != CAIRO_FORMAT_ARGB32) + return CAIRO_IMAGE_HAS_ALPHA; + + transparency = CAIRO_IMAGE_IS_OPAQUE; + for (y = 0; y < image->height; y++) { + uint32_t *pixel = (uint32_t *) (image->data + y * image->stride); + + for (x = 0; x < image->width; x++, pixel++) { + int a = (*pixel & 0xff000000) >> 24; + if (a > 0 && a < 255) { + return CAIRO_IMAGE_HAS_ALPHA; + } else if (a == 0) { + transparency = CAIRO_IMAGE_HAS_BILEVEL_ALPHA; + } + } + } + + return transparency; +} + +cairo_image_transparency_t +_cairo_image_analyze_transparency (cairo_image_surface_t *image) +{ + if (_cairo_surface_is_snapshot (&image->base)) { + if (image->transparency == CAIRO_IMAGE_UNKNOWN) + image->transparency = _cairo_image_compute_transparency (image); + + return image->transparency; + } + + return _cairo_image_compute_transparency (image); +} + +static cairo_image_color_t +_cairo_image_compute_color (cairo_image_surface_t *image) +{ + int x, y; + cairo_image_color_t color; + + if (image->width == 0 || image->height == 0) + return CAIRO_IMAGE_IS_MONOCHROME; + + if (image->format == CAIRO_FORMAT_A1) + return CAIRO_IMAGE_IS_MONOCHROME; + + if (image->format == CAIRO_FORMAT_A8) + return CAIRO_IMAGE_IS_GRAYSCALE; + + if (image->format == CAIRO_FORMAT_ARGB32) { + color = CAIRO_IMAGE_IS_MONOCHROME; + for (y = 0; y < image->height; y++) { + uint32_t *pixel = (uint32_t *) (image->data + y * image->stride); + + for (x = 0; x < image->width; x++, pixel++) { + int a = (*pixel & 0xff000000) >> 24; + int r = (*pixel & 0x00ff0000) >> 16; + int g = (*pixel & 0x0000ff00) >> 8; + int b = (*pixel & 0x000000ff); + if (a == 0) { + r = g = b = 0; + } else { + r = (r * 255 + a / 2) / a; + g = (g * 255 + a / 2) / a; + b = (b * 255 + a / 2) / a; + } + if (!(r == g && g == b)) + return CAIRO_IMAGE_IS_COLOR; + else if (r > 0 && r < 255) + color = CAIRO_IMAGE_IS_GRAYSCALE; + } + } + return color; + } + + if (image->format == CAIRO_FORMAT_RGB24) { + color = CAIRO_IMAGE_IS_MONOCHROME; + for (y = 0; y < image->height; y++) { + uint32_t *pixel = (uint32_t *) (image->data + y * image->stride); + + for (x = 0; x < image->width; x++, pixel++) { + int r = (*pixel & 0x00ff0000) >> 16; + int g = (*pixel & 0x0000ff00) >> 8; + int b = (*pixel & 0x000000ff); + if (!(r == g && g == b)) + return CAIRO_IMAGE_IS_COLOR; + else if (r > 0 && r < 255) + color = CAIRO_IMAGE_IS_GRAYSCALE; + } + } + return color; + } + + return CAIRO_IMAGE_IS_COLOR; +} + +cairo_image_color_t +_cairo_image_analyze_color (cairo_image_surface_t *image) +{ + if (_cairo_surface_is_snapshot (&image->base)) { + if (image->color == CAIRO_IMAGE_UNKNOWN_COLOR) + image->color = _cairo_image_compute_color (image); + + return image->color; + } + + return _cairo_image_compute_color (image); +} + +cairo_image_surface_t * +_cairo_image_surface_clone_subimage (cairo_surface_t *surface, + const cairo_rectangle_int_t *extents) +{ + cairo_surface_t *image; + cairo_surface_pattern_t pattern; + cairo_status_t status; + + image = cairo_surface_create_similar_image (surface, + _cairo_format_from_content (surface->content), + extents->width, + extents->height); + if (image->status) + return to_image_surface (image); + + /* TODO: check me with non-identity device_transform. Should we + * clone the scaling, too? */ + cairo_surface_set_device_offset (image, + -extents->x, + -extents->y); + + _cairo_pattern_init_for_surface (&pattern, surface); + pattern.base.filter = CAIRO_FILTER_NEAREST; + + status = _cairo_surface_paint (image, + CAIRO_OPERATOR_SOURCE, + &pattern.base, + NULL); + + _cairo_pattern_fini (&pattern.base); + + if (unlikely (status)) + goto error; + + /* We use the parent as a flag during map-to-image/umap-image that the + * resultant image came from a fallback rather than as direct call + * to the backend's map_to_image(). Whilst we use it as a simple flag, + * we need to make sure the parent surface obeys the reference counting + * semantics and is consistent for all callers. + */ + _cairo_image_surface_set_parent (to_image_surface (image), + cairo_surface_reference (surface)); + + return to_image_surface (image); + +error: + cairo_surface_destroy (image); + return to_image_surface (_cairo_surface_create_in_error (status)); +} diff --git a/local/recipes/libs/cairo/source/src/cairo-line-inline.h b/local/recipes/libs/cairo/source/src/cairo-line-inline.h new file mode 100644 index 0000000000..71cc5e7ebf --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-line-inline.h @@ -0,0 +1,48 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2014 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + */ + +#ifndef CAIRO_LINE_INLINE_H +#define CAIRO_LINE_INLINE_H + +#include "cairo-types-private.h" +#include "cairo-compiler-private.h" +#include "cairo-fixed-private.h" +#include "cairo-line-private.h" + +static inline int +cairo_lines_equal (const cairo_line_t *a, const cairo_line_t *b) +{ + return (a->p1.x == b->p1.x && a->p1.y == b->p1.y && + a->p2.x == b->p2.x && a->p2.y == b->p2.y); +} + +#endif /* CAIRO_LINE_INLINE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-line-private.h b/local/recipes/libs/cairo/source/src/cairo-line-private.h new file mode 100644 index 0000000000..6ddcae18d6 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-line-private.h @@ -0,0 +1,51 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2014 Intel Corporation, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + */ + +#ifndef CAIRO_LINE_PRIVATE_H +#define CAIRO_LINE_PRIVATE_H + +#include "cairo-types-private.h" +#include "cairo-error-private.h" +#include "cairo-compiler-private.h" + +CAIRO_BEGIN_DECLS + +cairo_private int +_cairo_lines_compare_at_y (const cairo_line_t *a, + const cairo_line_t *b, + int y); + +CAIRO_END_DECLS + +#endif /* CAIRO_LINE_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-line.c b/local/recipes/libs/cairo/source/src/cairo-line.c new file mode 100644 index 0000000000..2c1768eeb1 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-line.c @@ -0,0 +1,307 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* + * Copyright © 2004 Carl Worth + * Copyright © 2006 Red Hat, Inc. + * Copyright © 2008 Chris Wilson + * Copyright © 2014 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Keith Packard + * + * Contributor(s): + * Carl D. Worth + * Chris Wilson + * + */ + +#include "cairoint.h" + +#include "cairo-line-inline.h" +#include "cairo-slope-private.h" + +static int +line_compare_for_y_against_x (const cairo_line_t *a, + int32_t y, + int32_t x) +{ + int32_t adx, ady; + int32_t dx, dy; + cairo_int64_t L, R; + + if (x < a->p1.x && x < a->p2.x) + return 1; + if (x > a->p1.x && x > a->p2.x) + return -1; + + adx = a->p2.x - a->p1.x; + dx = x - a->p1.x; + + if (adx == 0) + return -dx; + if (dx == 0 || (adx ^ dx) < 0) + return adx; + + dy = y - a->p1.y; + ady = a->p2.y - a->p1.y; + + L = _cairo_int32x32_64_mul (dy, adx); + R = _cairo_int32x32_64_mul (dx, ady); + + return _cairo_int64_cmp (L, R); +} + +/* + * We need to compare the x-coordinates of a pair of lines for a particular y, + * without loss of precision. + * + * The x-coordinate along an edge for a given y is: + * X = A_x + (Y - A_y) * A_dx / A_dy + * + * So the inequality we wish to test is: + * A_x + (Y - A_y) * A_dx / A_dy ∘ B_x + (Y - B_y) * B_dx / B_dy, + * where ∘ is our inequality operator. + * + * By construction, we know that A_dy and B_dy (and (Y - A_y), (Y - B_y)) are + * all positive, so we can rearrange it thus without causing a sign change: + * A_dy * B_dy * (A_x - B_x) ∘ (Y - B_y) * B_dx * A_dy + * - (Y - A_y) * A_dx * B_dy + * + * Given the assumption that all the deltas fit within 32 bits, we can compute + * this comparison directly using 128 bit arithmetic. For certain, but common, + * input we can reduce this down to a single 32 bit compare by inspecting the + * deltas. + * + * (And put the burden of the work on developing fast 128 bit ops, which are + * required throughout the tessellator.) + * + * See the similar discussion for _slope_compare(). + */ +static int +lines_compare_x_for_y_general (const cairo_line_t *a, + const cairo_line_t *b, + int32_t y) +{ + /* XXX: We're assuming here that dx and dy will still fit in 32 + * bits. That's not true in general as there could be overflow. We + * should prevent that before the tessellation algorithm + * begins. + */ + int32_t dx = 0; + int32_t adx = 0, ady = 0; + int32_t bdx = 0, bdy = 0; + enum { + HAVE_NONE = 0x0, + HAVE_DX = 0x1, + HAVE_ADX = 0x2, + HAVE_DX_ADX = HAVE_DX | HAVE_ADX, + HAVE_BDX = 0x4, + HAVE_DX_BDX = HAVE_DX | HAVE_BDX, + HAVE_ADX_BDX = HAVE_ADX | HAVE_BDX, + HAVE_ALL = HAVE_DX | HAVE_ADX | HAVE_BDX + } have_dx_adx_bdx = HAVE_ALL; + + ady = a->p2.y - a->p1.y; + adx = a->p2.x - a->p1.x; + if (adx == 0) + have_dx_adx_bdx &= ~HAVE_ADX; + + bdy = b->p2.y - b->p1.y; + bdx = b->p2.x - b->p1.x; + if (bdx == 0) + have_dx_adx_bdx &= ~HAVE_BDX; + + dx = a->p1.x - b->p1.x; + if (dx == 0) + have_dx_adx_bdx &= ~HAVE_DX; + +#define L _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (ady, bdy), dx) +#define A _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (adx, bdy), y - a->p1.y) +#define B _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (bdx, ady), y - b->p1.y) + switch (have_dx_adx_bdx) { + default: + case HAVE_NONE: + return 0; + case HAVE_DX: + /* A_dy * B_dy * (A_x - B_x) ∘ 0 */ + return dx; /* ady * bdy is positive definite */ + case HAVE_ADX: + /* 0 ∘ - (Y - A_y) * A_dx * B_dy */ + return adx; /* bdy * (y - a->top.y) is positive definite */ + case HAVE_BDX: + /* 0 ∘ (Y - B_y) * B_dx * A_dy */ + return -bdx; /* ady * (y - b->top.y) is positive definite */ + case HAVE_ADX_BDX: + /* 0 ∘ (Y - B_y) * B_dx * A_dy - (Y - A_y) * A_dx * B_dy */ + if ((adx ^ bdx) < 0) { + return adx; + } else if (a->p1.y == b->p1.y) { /* common origin */ + cairo_int64_t adx_bdy, bdx_ady; + + /* ∴ A_dx * B_dy ∘ B_dx * A_dy */ + + adx_bdy = _cairo_int32x32_64_mul (adx, bdy); + bdx_ady = _cairo_int32x32_64_mul (bdx, ady); + + return _cairo_int64_cmp (adx_bdy, bdx_ady); + } else + return _cairo_int128_cmp (A, B); + case HAVE_DX_ADX: + /* A_dy * (A_x - B_x) ∘ - (Y - A_y) * A_dx */ + if ((-adx ^ dx) < 0) { + return dx; + } else { + cairo_int64_t ady_dx, dy_adx; + + ady_dx = _cairo_int32x32_64_mul (ady, dx); + dy_adx = _cairo_int32x32_64_mul (a->p1.y - y, adx); + + return _cairo_int64_cmp (ady_dx, dy_adx); + } + case HAVE_DX_BDX: + /* B_dy * (A_x - B_x) ∘ (Y - B_y) * B_dx */ + if ((bdx ^ dx) < 0) { + return dx; + } else { + cairo_int64_t bdy_dx, dy_bdx; + + bdy_dx = _cairo_int32x32_64_mul (bdy, dx); + dy_bdx = _cairo_int32x32_64_mul (y - b->p1.y, bdx); + + return _cairo_int64_cmp (bdy_dx, dy_bdx); + } + case HAVE_ALL: + /* XXX try comparing (a->p2.x - b->p2.x) et al */ + return _cairo_int128_cmp (L, _cairo_int128_sub (B, A)); + } +#undef B +#undef A +#undef L +} + +static int +lines_compare_x_for_y (const cairo_line_t *a, + const cairo_line_t *b, + int32_t y) +{ + /* If the sweep-line is currently on an end-point of a line, + * then we know its precise x value (and considering that we often need to + * compare events at end-points, this happens frequently enough to warrant + * special casing). + */ + enum { + HAVE_NEITHER = 0x0, + HAVE_AX = 0x1, + HAVE_BX = 0x2, + HAVE_BOTH = HAVE_AX | HAVE_BX + } have_ax_bx = HAVE_BOTH; + int32_t ax = 0, bx = 0; + + if (y == a->p1.y) + ax = a->p1.x; + else if (y == a->p2.y) + ax = a->p2.x; + else + have_ax_bx &= ~HAVE_AX; + + if (y == b->p1.y) + bx = b->p1.x; + else if (y == b->p2.y) + bx = b->p2.x; + else + have_ax_bx &= ~HAVE_BX; + + switch (have_ax_bx) { + default: + case HAVE_NEITHER: + return lines_compare_x_for_y_general (a, b, y); + case HAVE_AX: + return -line_compare_for_y_against_x (b, y, ax); + case HAVE_BX: + return line_compare_for_y_against_x (a, y, bx); + case HAVE_BOTH: + return ax - bx; + } +} + +static int bbox_compare (const cairo_line_t *a, + const cairo_line_t *b) +{ + int32_t amin, amax; + int32_t bmin, bmax; + + if (a->p1.x < a->p2.x) { + amin = a->p1.x; + amax = a->p2.x; + } else { + amin = a->p2.x; + amax = a->p1.x; + } + + if (b->p1.x < b->p2.x) { + bmin = b->p1.x; + bmax = b->p2.x; + } else { + bmin = b->p2.x; + bmax = b->p1.x; + } + + if (amax < bmin) + return -1; + + if (amin > bmax) + return +1; + + return 0; +} + +int +_cairo_lines_compare_at_y (const cairo_line_t *a, + const cairo_line_t *b, + int y) +{ + cairo_slope_t sa, sb; + int ret; + + if (cairo_lines_equal (a, b)) + return 0; + + /* Don't bother solving for abscissa if the edges' bounding boxes + * can be used to order them. + */ + ret = bbox_compare (a, b); + if (ret) + return ret; + + ret = lines_compare_x_for_y (a, b, y); + if (ret) + return ret; + + _cairo_slope_init (&sa, &a->p1, &a->p2); + _cairo_slope_init (&sb, &b->p1, &b->p2); + + return _cairo_slope_compare (&sb, &sa); +} diff --git a/local/recipes/libs/cairo/source/src/cairo-list-inline.h b/local/recipes/libs/cairo/source/src/cairo-list-inline.h new file mode 100644 index 0000000000..959c038061 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-list-inline.h @@ -0,0 +1,363 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Chris Wilson. + * + * Contributor(s): + * Chris Wilson + * + */ + +#ifndef CAIRO_LIST_INLINE_H +#define CAIRO_LIST_INLINE_H + +#include "cairo-list-private.h" + +/*< private > + * cairo_list_entry: + * @ptr: the pointer to the #cairo_list_t member. + * @type: the type of the struct. + * @member: the name of the list_head within the struct. + * + * Return value: the pointer the struct containing the @member that @ptr points to. + **/ +#define cairo_list_entry(ptr, type, member) \ + cairo_container_of(ptr, type, member) + +#define cairo_list_first_entry(ptr, type, member) \ + cairo_list_entry((ptr)->next, type, member) + +#define cairo_list_last_entry(ptr, type, member) \ + cairo_list_entry((ptr)->prev, type, member) + +/*< private > + * cairo_list_foreach: + * @pos: a #cairo_list_t* to use as a loop variable. + * @head: the list. + * + * Iterate the list. @pos points to the #cairo_list_t member of the entry struct. + **/ +#define cairo_list_foreach(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +/*< private > + * cairo_list_foreach_entry: + * @pos: a variable of type T * to use as a loop variable. + * @type: the type of the entry struct + * @head: the list + * @member: the name of the #cairo_list_t member of the entry + * + * Iterate the list of type T. + **/ +#define cairo_list_foreach_entry(pos, type, head, member) \ + for (pos = cairo_list_entry((head)->next, type, member);\ + &pos->member != (head); \ + pos = cairo_list_entry(pos->member.next, type, member)) + +/*< private > + * cairo_list_foreach_entry_safe: + * @pos: a variable of type T * to use as a loop variable. + * @n: a variable of type T * that point to the next item after @pos. + * @type: the type of the entry struct + * @head: the list + * @member: the name of the #cairo_list_t member of the entry + * + * Iterate the list of type T. It is safe to remove items while + * iterating. @n is a temporary variable required to support safe + * iterating. + * + * |[ + * struct foo { + * int a; + * cairo_list_t list; + * } + * + * struct foo linked_list; + * cairo_list_init (&linked_list); + * ... calls to cairo_list_add (entry, &linked_list); + * + * struct foo *pos, *next; + * cairo_list_foreach_entry_safe(pos, next, struct foo, &linked_list, list) { + * printf("%d\n", pos->a); + * cairo_list_del (pos); + * } + * ]| + **/ +#define cairo_list_foreach_entry_safe(pos, n, type, head, member) \ + for (pos = cairo_list_entry ((head)->next, type, member),\ + n = cairo_list_entry (pos->member.next, type, member);\ + &pos->member != (head); \ + pos = n, n = cairo_list_entry (n->member.next, type, member)) + +/*< private > + * cairo_list_foreach_entry: + * @pos: a variable of type T * to use as a loop variable. + * @type: the type of the entry struct + * @head: the list + * @member: the name of the #cairo_list_t member of the entry + * + * Iterate the list of type T in reverse direction. + **/ +#define cairo_list_foreach_entry_reverse(pos, type, head, member) \ + for (pos = cairo_list_entry((head)->prev, type, member);\ + &pos->member != (head); \ + pos = cairo_list_entry(pos->member.prev, type, member)) + +/*< private > + * cairo_list_foreach_entry_safe: + * @pos: a variable of type T * to use as a loop variable. + * @n: a variable of type T * that point to the next item after @pos. + * @type: the type of the entry struct + * @head: the list + * @member: the name of the #cairo_list_t member of the entry + * + * Iterate the list of type T in reverse direction. It is safe to + * remove items while iterating. @n is a temporary variable required + * to support safe iterating. + **/ +#define cairo_list_foreach_entry_reverse_safe(pos, n, type, head, member) \ + for (pos = cairo_list_entry((head)->prev, type, member),\ + n = cairo_list_entry (pos->member.prev, type, member);\ + &pos->member != (head); \ + pos = n, n = cairo_list_entry (n->member.prev, type, member)) + +#ifdef CAIRO_LIST_DEBUG +static inline void +_cairo_list_validate (const cairo_list_t *link) +{ + assert (link->next->prev == link); + assert (link->prev->next == link); +} +static inline void +cairo_list_validate (const cairo_list_t *head) +{ + cairo_list_t *link; + + cairo_list_foreach (link, head) + _cairo_list_validate (link); +} +static inline cairo_bool_t +cairo_list_is_empty (const cairo_list_t *head); +static inline void +cairo_list_validate_is_empty (const cairo_list_t *head) +{ + assert (head->next == NULL || (cairo_list_is_empty (head) && head->next == head->prev)); +} +#else +#define _cairo_list_validate(link) +#define cairo_list_validate(head) +#define cairo_list_validate_is_empty(head) +#endif + +/*< private > + * cairo_list_init: + * @entry: list entry to initialize + * + * Initializes the list entry to point to itself. The result is an + * empty list. + **/ +static inline void +cairo_list_init (cairo_list_t *entry) +{ + entry->next = entry; + entry->prev = entry; +} + +static inline void +__cairo_list_add (cairo_list_t *entry, + cairo_list_t *prev, + cairo_list_t *next) +{ + next->prev = entry; + entry->next = next; + entry->prev = prev; + prev->next = entry; +} + +/*< private > + * cairo_list_add: + * @entry: new entry + * @head: linked list head + * + * Insert a @entry at the start of the list. + **/ +static inline void +cairo_list_add (cairo_list_t *entry, cairo_list_t *head) +{ + cairo_list_validate (head); + cairo_list_validate_is_empty (entry); + __cairo_list_add (entry, head, head->next); + cairo_list_validate (head); +} + +/*< private > + * cairo_list_add_tail: + * @entry: new entry + * @head: linked list head + * + * Append a @entry to the end of the list. + **/ +static inline void +cairo_list_add_tail (cairo_list_t *entry, cairo_list_t *head) +{ + cairo_list_validate (head); + cairo_list_validate_is_empty (entry); + __cairo_list_add (entry, head->prev, head); + cairo_list_validate (head); +} + +static inline void +__cairo_list_del (cairo_list_t *prev, cairo_list_t *next) +{ + next->prev = prev; + prev->next = next; +} + +static inline void +_cairo_list_del (cairo_list_t *entry) +{ + __cairo_list_del (entry->prev, entry->next); +} + +/*< private > + * cairo_list_del: + * @entry: entry to remove + * + * Remove @entry from the list it is in. + **/ +static inline void +cairo_list_del (cairo_list_t *entry) +{ + _cairo_list_del (entry); + cairo_list_init (entry); +} + +/*< private > + * cairo_list_move: + * @entry: entry to move + * @head: linked list to move @entry to + * + * Remove @entry from the list it is in and insert it at the start of @head list. + **/ +static inline void +cairo_list_move (cairo_list_t *entry, cairo_list_t *head) +{ + cairo_list_validate (head); + __cairo_list_del (entry->prev, entry->next); + __cairo_list_add (entry, head, head->next); + cairo_list_validate (head); +} + +/*< private > + * cairo_list_move_tail: + * @entry: entry tp move + * @head: linked list to move @entry to + * + * Remove @entry from the list it is in and append it to the end of @head list. + **/ +static inline void +cairo_list_move_tail (cairo_list_t *entry, cairo_list_t *head) +{ + cairo_list_validate (head); + __cairo_list_del (entry->prev, entry->next); + __cairo_list_add (entry, head->prev, head); + cairo_list_validate (head); +} + +/*< private > + * cairo_list_move_list: + * @old: List to move + * @new: List to move to. Should be empty, + * + * Move @old list to @new list, fixing up the references. + **/ +static inline void +cairo_list_move_list (cairo_list_t *old, cairo_list_t *new) +{ + __cairo_list_add (new, old->prev, old->next); + cairo_list_init (old); +} + +/*< private > + * cairo_list_is_first: + * @entry: entry to check + * @head: linked list + * + * Return %TRUE if @entry is the first item in @head. + **/ +static inline cairo_bool_t +cairo_list_is_first (const cairo_list_t *entry, + const cairo_list_t *head) +{ + cairo_list_validate (head); + return entry->prev == head; +} + +/*< private > + * cairo_list_is_last: + * @entry: entry to check + * @head: linked list + * + * Return %TRUE if @entry is the last item in @head. + **/ +static inline cairo_bool_t +cairo_list_is_last (const cairo_list_t *entry, + const cairo_list_t *head) +{ + cairo_list_validate (head); + return entry->next == head; +} + +/*< private > + * cairo_list_is_empty: + * @head: linked list + * + * Return %TRUE if @head is empty. + **/ +static inline cairo_bool_t +cairo_list_is_empty (const cairo_list_t *head) +{ + cairo_list_validate (head); + return head->next == head; +} + +/*< private > + * cairo_list_is_singular: + * @head: linked list + * + * Return %TRUE if @head has only one entry. + **/ +static inline cairo_bool_t +cairo_list_is_singular (const cairo_list_t *head) +{ + cairo_list_validate (head); + return head->next != head && head->next == head->prev; +} + +#endif /* CAIRO_LIST_INLINE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-list-private.h b/local/recipes/libs/cairo/source/src/cairo-list-private.h new file mode 100644 index 0000000000..9f39b668f8 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-list-private.h @@ -0,0 +1,48 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Chris Wilson. + * + * Contributor(s): + * Chris Wilson + * + */ + +#ifndef CAIRO_LIST_PRIVATE_H +#define CAIRO_LIST_PRIVATE_H + +#include "cairo-compiler-private.h" + +/* Basic circular, doubly linked list implementation */ + +typedef struct _cairo_list { + struct _cairo_list *next, *prev; +} cairo_list_t; + +#endif /* CAIRO_LIST_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-lzw.c b/local/recipes/libs/cairo/source/src/cairo-lzw.c new file mode 100644 index 0000000000..e17cdfc1c7 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-lzw.c @@ -0,0 +1,407 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2006 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + */ + +#include "cairoint.h" +#include "cairo-error-private.h" + +typedef struct _lzw_buf { + cairo_status_t status; + + unsigned char *data; + int data_size; + int num_data; + uint32_t pending; + unsigned int pending_bits; +} lzw_buf_t; + +/* An lzw_buf_t is a simple, growable chunk of memory for holding + * variable-size objects of up to 16 bits each. + * + * Initialize an lzw_buf_t to the given size in bytes. + * + * To store objects into the lzw_buf_t, call _lzw_buf_store_bits and + * when finished, call _lzw_buf_store_pending, (which flushes out the + * last few bits that hadn't yet made a complete byte yet). + * + * Instead of returning failure from any functions, lzw_buf_t provides + * a status value that the caller can query, (and should query at + * least once when done with the object). The status value will be + * either %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY; + */ +static void +_lzw_buf_init (lzw_buf_t *buf, int size) +{ + if (size == 0) + size = 16; + + buf->status = CAIRO_STATUS_SUCCESS; + buf->data_size = size; + buf->num_data = 0; + buf->pending = 0; + buf->pending_bits = 0; + + buf->data = _cairo_malloc (size); + if (unlikely (buf->data == NULL)) { + buf->data_size = 0; + buf->status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + return; + } +} + +/* Increase the buffer size by doubling. + * + * Returns %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY + */ +static cairo_status_t +_lzw_buf_grow (lzw_buf_t *buf) +{ + int new_size = buf->data_size * 2; + unsigned char *new_data; + + if (buf->status) + return buf->status; + + new_data = NULL; + /* check for integer overflow */ + if (new_size / 2 == buf->data_size) + new_data = realloc (buf->data, new_size); + + if (unlikely (new_data == NULL)) { + free (buf->data); + buf->data_size = 0; + buf->status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + return buf->status; + } + + buf->data = new_data; + buf->data_size = new_size; + + return CAIRO_STATUS_SUCCESS; +} + +/* Store the lowest num_bits bits of values into buf. + * + * Note: The bits of value above size_in_bits must be 0, (so don't lie + * about the size). + * + * See also _lzw_buf_store_pending which must be called after the last + * call to _lzw_buf_store_bits. + * + * Sets buf->status to either %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY. + */ +static void +_lzw_buf_store_bits (lzw_buf_t *buf, uint16_t value, int num_bits) +{ + cairo_status_t status; + + assert (value <= (1 << num_bits) - 1); + + if (buf->status) + return; + + buf->pending = (buf->pending << num_bits) | value; + buf->pending_bits += num_bits; + + while (buf->pending_bits >= 8) { + if (buf->num_data >= buf->data_size) { + status = _lzw_buf_grow (buf); + if (unlikely (status)) + return; + } + buf->data[buf->num_data++] = buf->pending >> (buf->pending_bits - 8); + buf->pending_bits -= 8; + } +} + +/* Store the last remaining pending bits into the buffer. + * + * Note: This function must be called after the last call to + * _lzw_buf_store_bits. + * + * Sets buf->status to either %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY. + */ +static void +_lzw_buf_store_pending (lzw_buf_t *buf) +{ + cairo_status_t status; + + if (buf->status) + return; + + if (buf->pending_bits == 0) + return; + + assert (buf->pending_bits < 8); + + if (buf->num_data >= buf->data_size) { + status = _lzw_buf_grow (buf); + if (unlikely (status)) + return; + } + + buf->data[buf->num_data++] = buf->pending << (8 - buf->pending_bits); + buf->pending_bits = 0; +} + +/* LZW defines a few magic code values */ +#define LZW_CODE_CLEAR_TABLE 256 +#define LZW_CODE_EOD 257 +#define LZW_CODE_FIRST 258 + +/* We pack three separate values into a symbol as follows: + * + * 12 bits (31 down to 20): CODE: code value used to represent this symbol + * 12 bits (19 down to 8): PREV: previous code value in chain + * 8 bits ( 7 down to 0): NEXT: next byte value in chain + */ +typedef uint32_t lzw_symbol_t; + +#define LZW_SYMBOL_SET(sym, prev, next) ((sym) = ((prev) << 8)|(next)) +#define LZW_SYMBOL_SET_CODE(sym, code, prev, next) ((sym) = ((code << 20)|(prev) << 8)|(next)) +#define LZW_SYMBOL_GET_CODE(sym) (((sym) >> 20)) +#define LZW_SYMBOL_GET_PREV(sym) (((sym) >> 8) & 0x7ff) +#define LZW_SYMBOL_GET_BYTE(sym) (((sym) >> 0) & 0x0ff) + +/* The PREV+NEXT fields can be seen as the key used to fetch values + * from the hash table, while the code is the value fetched. + */ +#define LZW_SYMBOL_KEY_MASK 0x000fffff + +/* Since code values are only stored starting with 258 we can safely + * use a zero value to represent free slots in the hash table. */ +#define LZW_SYMBOL_FREE 0x00000000 + +/* These really aren't very free for modifying. First, the PostScript + * specification sets the 9-12 bit range. Second, the encoding of + * lzw_symbol_t above also relies on 2 of LZW_BITS_MAX plus one byte + * fitting within 32 bits. + * + * But other than that, the LZW compression scheme could function with + * more bits per code. + */ +#define LZW_BITS_MIN 9 +#define LZW_BITS_MAX 12 +#define LZW_BITS_BOUNDARY(bits) ((1<<(bits))-1) +#define LZW_MAX_SYMBOLS (1<table, 0, LZW_SYMBOL_TABLE_SIZE * sizeof (lzw_symbol_t)); +} + +/* Lookup a symbol in the symbol table. The PREV and NEXT fields of + * symbol form the key for the lookup. + * + * If successful, then this function returns %TRUE and slot_ret will be + * left pointing at the result that will have the CODE field of + * interest. + * + * If the lookup fails, then this function returns %FALSE and slot_ret + * will be pointing at the location in the table to which a new CODE + * value should be stored along with PREV and NEXT. + */ +static cairo_bool_t +_lzw_symbol_table_lookup (lzw_symbol_table_t *table, + lzw_symbol_t symbol, + lzw_symbol_t **slot_ret) +{ + /* The algorithm here is identical to that in cairo-hash.c. We + * copy it here to allow for a rather more efficient + * implementation due to several circumstances that do not apply + * to the more general case: + * + * 1) We have a known bound on the total number of symbols, so we + * have a fixed-size table without any copying when growing + * + * 2) We never delete any entries, so we don't need to + * support/check for DEAD entries during lookup. + * + * 3) The object fits in 32 bits so we store each object in its + * entirety within the table rather than storing objects + * externally and putting pointers in the table, (which here + * would just double the storage requirements and have negative + * impacts on memory locality). + */ + int i, idx, step, hash = symbol & LZW_SYMBOL_KEY_MASK; + lzw_symbol_t candidate; + + idx = hash % LZW_SYMBOL_MOD1; + step = 0; + + *slot_ret = NULL; + for (i = 0; i < LZW_SYMBOL_TABLE_SIZE; i++) + { + candidate = table->table[idx]; + if (candidate == LZW_SYMBOL_FREE) + { + *slot_ret = &table->table[idx]; + return FALSE; + } + else /* candidate is LIVE */ + { + if ((candidate & LZW_SYMBOL_KEY_MASK) == + (symbol & LZW_SYMBOL_KEY_MASK)) + { + *slot_ret = &table->table[idx]; + return TRUE; + } + } + + if (step == 0) { + step = hash % LZW_SYMBOL_MOD2; + if (step == 0) + step = 1; + } + + idx += step; + if (idx >= LZW_SYMBOL_TABLE_SIZE) + idx -= LZW_SYMBOL_TABLE_SIZE; + } + + return FALSE; +} + +/* Compress a bytestream using the LZW algorithm. + * + * This is an original implementation based on reading the + * specification of the LZWDecode filter in the PostScript Language + * Reference. The free parameters in the LZW algorithm are set to the + * values mandated by PostScript, (symbols encoded with widths from 9 + * to 12 bits). + * + * This function returns a pointer to a newly allocated buffer holding + * the compressed data, or %NULL if an out-of-memory situation + * occurs. + * + * Notice that any one of the _lzw_buf functions called here could + * trigger an out-of-memory condition. But lzw_buf_t uses cairo's + * shutdown-on-error idiom, so it's safe to continue to call into + * lzw_buf without having to check for errors, (until a final check at + * the end). + */ +unsigned char * +_cairo_lzw_compress (unsigned char *data, unsigned long *size_in_out) +{ + int bytes_remaining = *size_in_out; + lzw_buf_t buf; + lzw_symbol_table_t table; + lzw_symbol_t symbol, *slot = NULL; /* just to squelch a warning */ + int code_next = LZW_CODE_FIRST; + int code_bits = LZW_BITS_MIN; + int prev, next = 0; /* just to squelch a warning */ + + if (*size_in_out == 0) + return NULL; + + _lzw_buf_init (&buf, *size_in_out); + + _lzw_symbol_table_init (&table); + + /* The LZW header is a clear table code. */ + _lzw_buf_store_bits (&buf, LZW_CODE_CLEAR_TABLE, code_bits); + + while (1) { + + /* Find the longest existing code in the symbol table that + * matches the current input, if any. */ + prev = *data++; + bytes_remaining--; + if (bytes_remaining) { + do + { + next = *data++; + bytes_remaining--; + LZW_SYMBOL_SET (symbol, prev, next); + if (_lzw_symbol_table_lookup (&table, symbol, &slot)) + prev = LZW_SYMBOL_GET_CODE (*slot); + } while (bytes_remaining && *slot != LZW_SYMBOL_FREE); + if (*slot == LZW_SYMBOL_FREE) { + data--; + bytes_remaining++; + } + } + + /* Write the code into the output. This is either a byte read + * directly from the input, or a code from the last successful + * lookup. */ + _lzw_buf_store_bits (&buf, prev, code_bits); + + if (likely (slot != NULL)) + LZW_SYMBOL_SET_CODE (*slot, code_next, prev, next); + + code_next++; + + if (code_next > LZW_BITS_BOUNDARY(code_bits)) + { + code_bits++; + if (code_bits > LZW_BITS_MAX) { + _lzw_symbol_table_init (&table); + _lzw_buf_store_bits (&buf, LZW_CODE_CLEAR_TABLE, code_bits - 1); + code_bits = LZW_BITS_MIN; + code_next = LZW_CODE_FIRST; + } + } + + if (bytes_remaining == 0) + break; + } + + /* The LZW footer is an end-of-data code. */ + _lzw_buf_store_bits (&buf, LZW_CODE_EOD, code_bits); + + _lzw_buf_store_pending (&buf); + + /* See if we ever ran out of memory while writing to buf. */ + if (buf.status == CAIRO_STATUS_NO_MEMORY) { + *size_in_out = 0; + return NULL; + } + + assert (buf.status == CAIRO_STATUS_SUCCESS); + + *size_in_out = buf.num_data; + return buf.data; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-malloc-private.h b/local/recipes/libs/cairo/source/src/cairo-malloc-private.h new file mode 100644 index 0000000000..b850c475cd --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-malloc-private.h @@ -0,0 +1,218 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2007 Mozilla Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Mozilla Foundation + * + * Contributor(s): + * Vladimir Vukicevic + */ + +#ifndef CAIRO_MALLOC_PRIVATE_H +#define CAIRO_MALLOC_PRIVATE_H + +#include "cairo-wideint-private.h" +#include + +#if HAVE_MEMFAULT +#include +#define CAIRO_INJECT_FAULT() MEMFAULT_INJECT_FAULT() +#else +#define CAIRO_INJECT_FAULT() 0 +#endif + +/** + * _cairo_malloc: + * @size: size in bytes + * + * Allocate @size memory using malloc(). + * The memory should be freed using free(). + * malloc is skipped, if 0 bytes are requested, and %NULL will be returned. + * + * Return value: A pointer to the newly allocated memory, or %NULL in + * case of malloc() failure or size is 0. + **/ + +#define _cairo_malloc(size) \ + ((size) != 0 ? malloc(size) : NULL) + +/** + * _cairo_calloc: + * @size: size of each element + * + * Allocates @size memory using calloc(). Behaves much like + * calloc(), except that only one parameter is required. + * The memory should be freed using free(). + * calloc is skipped, if 0 bytes are requested, and %NULL will be returned. + * + * Return value: A pointer to the newly allocated memory, or %NULL in + * case of calloc() failure or overflow. + **/ + +#define _cairo_calloc(size) \ + ((size) != 0 ? calloc(1,size) : NULL) + +/** + * _cairo_malloc_ab: + * @a: number of elements to allocate + * @size: size of each element + * + * Allocates @a*@size memory using _cairo_malloc(), taking care to not + * overflow when doing the multiplication. Behaves much like + * calloc(), except that the returned memory is not set to zero. + * The memory should be freed using free(). + * + * @size should be a constant so that the compiler can optimize + * out a constant division. + * + * Return value: A pointer to the newly allocated memory, or %NULL in + * case of malloc() failure or overflow. + **/ + +static cairo_always_inline void * +_cairo_malloc_ab(size_t a, size_t size) +{ + size_t c; + if (_cairo_mul_size_t_overflow (a, size, &c)) + return NULL; + + return _cairo_malloc(c); +} + +/** + * _cairo_calloc_ab: + * @a: number of elements to allocate + * @size: size of each element + * + * Allocates @a*@size memory using _cairo_calloc(), taking care to not + * overflow when doing the multiplication. + * + * @size should be a constant so that the compiler can optimize + * out a constant division. + * + * Return value: A pointer to the newly allocated memory, or %NULL in + * case of calloc() failure or overflow. + **/ + +static cairo_always_inline void * +_cairo_calloc_ab(size_t a, size_t size) +{ + size_t c; + if (_cairo_mul_size_t_overflow (a, size, &c)) + return NULL; + + return _cairo_calloc(c); +} + +/** + * _cairo_realloc_ab: + * @ptr: original pointer to block of memory to be resized + * @a: number of elements to allocate + * @size: size of each element + * + * Reallocates @ptr a block of @a*@size memory using realloc(), taking + * care to not overflow when doing the multiplication. The memory + * should be freed using free(). + * + * @size should be a constant so that the compiler can optimize + * out a constant division. + * + * Return value: A pointer to the newly allocated memory, or %NULL in + * case of realloc() failure or overflow (whereupon the original block + * of memory * is left untouched). + **/ + +static cairo_always_inline void * +_cairo_realloc_ab(void *ptr, size_t a, size_t size) +{ + size_t c; + if (_cairo_mul_size_t_overflow (a, size, &c)) + return NULL; + + return realloc(ptr, c); +} + +/** + * _cairo_malloc_abc: + * @a: first factor of number of elements to allocate + * @b: second factor of number of elements to allocate + * @size: size of each element + * + * Allocates @a*@b*@size memory using _cairo_malloc(), taking care to not + * overflow when doing the multiplication. Behaves like + * _cairo_malloc_ab(). The memory should be freed using free(). + * + * @size should be a constant so that the compiler can optimize + * out a constant division. + * + * Return value: A pointer to the newly allocated memory, or %NULL in + * case of malloc() failure or overflow. + **/ + +static cairo_always_inline void * +_cairo_malloc_abc(size_t a, size_t b, size_t size) +{ + size_t c, d; + if (_cairo_mul_size_t_overflow (a, b, &c)) + return NULL; + + if (_cairo_mul_size_t_overflow (c, size, &d)) + return NULL; + + return _cairo_malloc(d); +} + +/** + * _cairo_malloc_ab_plus_c: + * @a: number of elements to allocate + * @size: size of each element + * @c: additional size to allocate + * + * Allocates @a*@size+@c memory using _cairo_malloc(), taking care to not + * overflow when doing the arithmetic. Behaves similar to + * _cairo_malloc_ab(). The memory should be freed using free(). + * + * Return value: A pointer to the newly allocated memory, or %NULL in + * case of malloc() failure or overflow. + **/ + +static cairo_always_inline void * +_cairo_malloc_ab_plus_c(size_t a, size_t size, size_t c) +{ + size_t d, e; + if (_cairo_mul_size_t_overflow (a, size, &d)) + return NULL; + + if (_cairo_add_size_t_overflow (d, c, &e)) + return NULL; + + return _cairo_malloc(e); +} + +#endif /* CAIRO_MALLOC_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-mask-compositor.c b/local/recipes/libs/cairo/source/src/cairo-mask-compositor.c new file mode 100644 index 0000000000..4d6b118dda --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-mask-compositor.c @@ -0,0 +1,1481 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Joonas Pihlaja + * Chris Wilson + */ + +/* This compositor renders the shape to a mask using an image surface + * then calls composite. + */ + +#include "cairoint.h" + +#include "cairo-clip-inline.h" +#include "cairo-compositor-private.h" +#include "cairo-image-surface-private.h" +#include "cairo-pattern-inline.h" +#include "cairo-region-private.h" +#include "cairo-surface-observer-private.h" +#include "cairo-surface-offset-private.h" +#include "cairo-surface-snapshot-private.h" +#include "cairo-surface-subsurface-private.h" + +typedef cairo_int_status_t +(*draw_func_t) (const cairo_mask_compositor_t *compositor, + cairo_surface_t *dst, + void *closure, + cairo_operator_t op, + const cairo_pattern_t *src, + const cairo_rectangle_int_t *src_sample, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents, + cairo_clip_t *clip); + +static void do_unaligned_row(void (*blt)(void *closure, + int16_t x, int16_t y, + int16_t w, int16_t h, + uint16_t coverage), + void *closure, + const cairo_box_t *b, + int tx, int y, int h, + uint16_t coverage) +{ + int x1 = _cairo_fixed_integer_part (b->p1.x) - tx; + int x2 = _cairo_fixed_integer_part (b->p2.x) - tx; + if (x2 > x1) { + if (! _cairo_fixed_is_integer (b->p1.x)) { + blt(closure, x1, y, 1, h, + coverage * (256 - _cairo_fixed_fractional_part (b->p1.x))); + x1++; + } + + if (x2 > x1) + blt(closure, x1, y, x2-x1, h, (coverage << 8) - (coverage >> 8)); + + if (! _cairo_fixed_is_integer (b->p2.x)) + blt(closure, x2, y, 1, h, + coverage * _cairo_fixed_fractional_part (b->p2.x)); + } else + blt(closure, x1, y, 1, h, + coverage * (b->p2.x - b->p1.x)); +} + +static void do_unaligned_box(void (*blt)(void *closure, + int16_t x, int16_t y, + int16_t w, int16_t h, + uint16_t coverage), + void *closure, + const cairo_box_t *b, int tx, int ty) +{ + int y1 = _cairo_fixed_integer_part (b->p1.y) - ty; + int y2 = _cairo_fixed_integer_part (b->p2.y) - ty; + if (y2 > y1) { + if (! _cairo_fixed_is_integer (b->p1.y)) { + do_unaligned_row(blt, closure, b, tx, y1, 1, + 256 - _cairo_fixed_fractional_part (b->p1.y)); + y1++; + } + + if (y2 > y1) + do_unaligned_row(blt, closure, b, tx, y1, y2-y1, 256); + + if (! _cairo_fixed_is_integer (b->p2.y)) + do_unaligned_row(blt, closure, b, tx, y2, 1, + _cairo_fixed_fractional_part (b->p2.y)); + } else + do_unaligned_row(blt, closure, b, tx, y1, 1, + b->p2.y - b->p1.y); +} + +struct blt_in { + const cairo_mask_compositor_t *compositor; + cairo_surface_t *dst; +}; + +static void blt_in(void *closure, + int16_t x, int16_t y, + int16_t w, int16_t h, + uint16_t coverage) +{ + struct blt_in *info = closure; + cairo_color_t color; + cairo_rectangle_int_t rect; + + if (coverage == 0xffff) + return; + + rect.x = x; + rect.y = y; + rect.width = w; + rect.height = h; + + _cairo_color_init_rgba (&color, 0, 0, 0, coverage / (double) 0xffff); + info->compositor->fill_rectangles (info->dst, CAIRO_OPERATOR_IN, + &color, &rect, 1); +} + +static cairo_surface_t * +create_composite_mask (const cairo_mask_compositor_t *compositor, + cairo_surface_t *dst, + void *draw_closure, + draw_func_t draw_func, + draw_func_t mask_func, + const cairo_composite_rectangles_t *extents) +{ + cairo_surface_t *surface; + cairo_int_status_t status; + struct blt_in info; + int i; + + surface = _cairo_surface_create_scratch (dst, CAIRO_CONTENT_ALPHA, + extents->bounded.width, + extents->bounded.height, + NULL); + if (unlikely (surface->status)) + return surface; + + status = compositor->acquire (surface); + if (unlikely (status)) { + cairo_surface_destroy (surface); + return _cairo_int_surface_create_in_error (status); + } + + if (!surface->is_clear) { + cairo_rectangle_int_t rect; + + rect.x = rect.y = 0; + rect.width = extents->bounded.width; + rect.height = extents->bounded.height; + + status = compositor->fill_rectangles (surface, CAIRO_OPERATOR_CLEAR, + CAIRO_COLOR_TRANSPARENT, + &rect, 1); + if (unlikely (status)) + goto error; + } + + if (mask_func) { + status = mask_func (compositor, surface, draw_closure, + CAIRO_OPERATOR_SOURCE, NULL, NULL, + extents->bounded.x, extents->bounded.y, + &extents->bounded, extents->clip); + if (likely (status != CAIRO_INT_STATUS_UNSUPPORTED)) + goto out; + } + + /* Is it worth setting the clip region here? */ + status = draw_func (compositor, surface, draw_closure, + CAIRO_OPERATOR_ADD, NULL, NULL, + extents->bounded.x, extents->bounded.y, + &extents->bounded, NULL); + if (unlikely (status)) + goto error; + + info.compositor = compositor; + info.dst = surface; + for (i = 0; i < extents->clip->num_boxes; i++) { + cairo_box_t *b = &extents->clip->boxes[i]; + + if (! _cairo_fixed_is_integer (b->p1.x) || + ! _cairo_fixed_is_integer (b->p1.y) || + ! _cairo_fixed_is_integer (b->p2.x) || + ! _cairo_fixed_is_integer (b->p2.y)) + { + do_unaligned_box(blt_in, &info, b, + extents->bounded.x, + extents->bounded.y); + } + } + + if (extents->clip->path != NULL) { + status = _cairo_clip_combine_with_surface (extents->clip, surface, + extents->bounded.x, + extents->bounded.y); + if (unlikely (status)) + goto error; + } + +out: + compositor->release (surface); + surface->is_clear = FALSE; + return surface; + +error: + compositor->release (surface); + if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) { + cairo_surface_destroy (surface); + surface = _cairo_int_surface_create_in_error (status); + } + return surface; +} + +/* Handles compositing with a clip surface when the operator allows + * us to combine the clip with the mask + */ +static cairo_status_t +clip_and_composite_with_mask (const cairo_mask_compositor_t *compositor, + void *draw_closure, + draw_func_t draw_func, + draw_func_t mask_func, + cairo_operator_t op, + cairo_pattern_t *pattern, + const cairo_composite_rectangles_t*extents) +{ + cairo_surface_t *dst = extents->surface; + cairo_surface_t *mask, *src; + int src_x, src_y; + + mask = create_composite_mask (compositor, dst, draw_closure, + draw_func, mask_func, + extents); + if (unlikely (mask->status)) + return mask->status; + + if (pattern != NULL || dst->content != CAIRO_CONTENT_ALPHA) { + src = compositor->pattern_to_surface (dst, + &extents->source_pattern.base, + FALSE, + &extents->bounded, + &extents->source_sample_area, + &src_x, &src_y); + if (unlikely (src->status)) { + cairo_surface_destroy (mask); + return src->status; + } + + compositor->composite (dst, op, src, mask, + extents->bounded.x + src_x, + extents->bounded.y + src_y, + 0, 0, + extents->bounded.x, extents->bounded.y, + extents->bounded.width, extents->bounded.height); + + cairo_surface_destroy (src); + } else { + compositor->composite (dst, op, mask, NULL, + 0, 0, + 0, 0, + extents->bounded.x, extents->bounded.y, + extents->bounded.width, extents->bounded.height); + } + cairo_surface_destroy (mask); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_surface_t * +get_clip_source (const cairo_mask_compositor_t *compositor, + cairo_clip_t *clip, + cairo_surface_t *dst, + const cairo_rectangle_int_t *bounds, + int *out_x, int *out_y) +{ + cairo_surface_pattern_t pattern; + cairo_rectangle_int_t r; + cairo_surface_t *surface; + + surface = _cairo_clip_get_image (clip, dst, bounds); + if (unlikely (surface->status)) + return surface; + + _cairo_pattern_init_for_surface (&pattern, surface); + pattern.base.filter = CAIRO_FILTER_NEAREST; + cairo_surface_destroy (surface); + + r.x = r.y = 0; + r.width = bounds->width; + r.height = bounds->height; + + surface = compositor->pattern_to_surface (dst, &pattern.base, TRUE, + &r, &r, out_x, out_y); + _cairo_pattern_fini (&pattern.base); + + *out_x += -bounds->x; + *out_y += -bounds->y; + return surface; +} + +/* Handles compositing with a clip surface when we have to do the operation + * in two pieces and combine them together. + */ +static cairo_status_t +clip_and_composite_combine (const cairo_mask_compositor_t *compositor, + void *draw_closure, + draw_func_t draw_func, + cairo_operator_t op, + const cairo_pattern_t *pattern, + const cairo_composite_rectangles_t*extents) +{ + cairo_surface_t *dst = extents->surface; + cairo_surface_t *tmp, *clip; + cairo_status_t status; + int clip_x, clip_y; + + tmp = _cairo_surface_create_scratch (dst, dst->content, + extents->bounded.width, + extents->bounded.height, + NULL); + if (unlikely (tmp->status)) + return tmp->status; + + compositor->composite (tmp, CAIRO_OPERATOR_SOURCE, dst, NULL, + extents->bounded.x, extents->bounded.y, + 0, 0, + 0, 0, + extents->bounded.width, extents->bounded.height); + + status = draw_func (compositor, tmp, draw_closure, op, + pattern, &extents->source_sample_area, + extents->bounded.x, extents->bounded.y, + &extents->bounded, NULL); + if (unlikely (status)) + goto cleanup; + + clip = get_clip_source (compositor, + extents->clip, dst, &extents->bounded, + &clip_x, &clip_y); + if (unlikely ((status = clip->status))) + goto cleanup; + + if (dst->is_clear) { + compositor->composite (dst, CAIRO_OPERATOR_SOURCE, tmp, clip, + 0, 0, + clip_x, clip_y, + extents->bounded.x, extents->bounded.y, + extents->bounded.width, extents->bounded.height); + } else { + /* Punch the clip out of the destination */ + compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, clip, NULL, + clip_x, clip_y, + 0, 0, + extents->bounded.x, extents->bounded.y, + extents->bounded.width, extents->bounded.height); + + /* Now add the two results together */ + compositor->composite (dst, CAIRO_OPERATOR_ADD, tmp, clip, + 0, 0, + clip_x, clip_y, + extents->bounded.x, extents->bounded.y, + extents->bounded.width, extents->bounded.height); + } + cairo_surface_destroy (clip); + +cleanup: + cairo_surface_destroy (tmp); + return status; +} + +/* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's + * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip)) + */ +static cairo_status_t +clip_and_composite_source (const cairo_mask_compositor_t *compositor, + void *draw_closure, + draw_func_t draw_func, + draw_func_t mask_func, + cairo_pattern_t *pattern, + const cairo_composite_rectangles_t *extents) +{ + cairo_surface_t *dst = extents->surface; + cairo_surface_t *mask, *src; + int src_x, src_y; + + /* Create a surface that is mask IN clip */ + mask = create_composite_mask (compositor, dst, draw_closure, + draw_func, mask_func, + extents); + if (unlikely (mask->status)) + return mask->status; + + src = compositor->pattern_to_surface (dst, + pattern, + FALSE, + &extents->bounded, + &extents->source_sample_area, + &src_x, &src_y); + if (unlikely (src->status)) { + cairo_surface_destroy (mask); + return src->status; + } + + if (dst->is_clear) { + compositor->composite (dst, CAIRO_OPERATOR_SOURCE, src, mask, + extents->bounded.x + src_x, extents->bounded.y + src_y, + 0, 0, + extents->bounded.x, extents->bounded.y, + extents->bounded.width, extents->bounded.height); + } else { + /* Compute dest' = dest OUT (mask IN clip) */ + compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL, + 0, 0, 0, 0, + extents->bounded.x, extents->bounded.y, + extents->bounded.width, extents->bounded.height); + + /* Now compute (src IN (mask IN clip)) ADD dest' */ + compositor->composite (dst, CAIRO_OPERATOR_ADD, src, mask, + extents->bounded.x + src_x, extents->bounded.y + src_y, + 0, 0, + extents->bounded.x, extents->bounded.y, + extents->bounded.width, extents->bounded.height); + } + + cairo_surface_destroy (src); + cairo_surface_destroy (mask); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_bool_t +can_reduce_alpha_op (cairo_operator_t op) +{ + int iop = op; + switch (iop) { + case CAIRO_OPERATOR_OVER: + case CAIRO_OPERATOR_SOURCE: + case CAIRO_OPERATOR_ADD: + return TRUE; + default: + return FALSE; + } +} + +static cairo_bool_t +reduce_alpha_op (cairo_surface_t *dst, + cairo_operator_t op, + const cairo_pattern_t *pattern) +{ + return dst->is_clear && + dst->content == CAIRO_CONTENT_ALPHA && + _cairo_pattern_is_opaque_solid (pattern) && + can_reduce_alpha_op (op); +} + +static cairo_status_t +fixup_unbounded (const cairo_mask_compositor_t *compositor, + cairo_surface_t *dst, + const cairo_composite_rectangles_t *extents) +{ + cairo_rectangle_int_t rects[4]; + int n; + + if (extents->bounded.width == extents->unbounded.width && + extents->bounded.height == extents->unbounded.height) + { + return CAIRO_STATUS_SUCCESS; + } + + n = 0; + if (extents->bounded.width == 0 || extents->bounded.height == 0) { + rects[n].x = extents->unbounded.x; + rects[n].width = extents->unbounded.width; + rects[n].y = extents->unbounded.y; + rects[n].height = extents->unbounded.height; + n++; + } else { + /* top */ + if (extents->bounded.y != extents->unbounded.y) { + rects[n].x = extents->unbounded.x; + rects[n].width = extents->unbounded.width; + rects[n].y = extents->unbounded.y; + rects[n].height = extents->bounded.y - extents->unbounded.y; + n++; + } + /* left */ + if (extents->bounded.x != extents->unbounded.x) { + rects[n].x = extents->unbounded.x; + rects[n].width = extents->bounded.x - extents->unbounded.x; + rects[n].y = extents->bounded.y; + rects[n].height = extents->bounded.height; + n++; + } + /* right */ + if (extents->bounded.x + extents->bounded.width != extents->unbounded.x + extents->unbounded.width) { + rects[n].x = extents->bounded.x + extents->bounded.width; + rects[n].width = extents->unbounded.x + extents->unbounded.width - rects[n].x; + rects[n].y = extents->bounded.y; + rects[n].height = extents->bounded.height; + n++; + } + /* bottom */ + if (extents->bounded.y + extents->bounded.height != extents->unbounded.y + extents->unbounded.height) { + rects[n].x = extents->unbounded.x; + rects[n].width = extents->unbounded.width; + rects[n].y = extents->bounded.y + extents->bounded.height; + rects[n].height = extents->unbounded.y + extents->unbounded.height - rects[n].y; + n++; + } + } + + return compositor->fill_rectangles (dst, CAIRO_OPERATOR_CLEAR, + CAIRO_COLOR_TRANSPARENT, + rects, n); +} + +static cairo_status_t +fixup_unbounded_with_mask (const cairo_mask_compositor_t *compositor, + cairo_surface_t *dst, + const cairo_composite_rectangles_t *extents) +{ + cairo_surface_t *mask; + int mask_x, mask_y; + + mask = get_clip_source (compositor, + extents->clip, dst, &extents->unbounded, + &mask_x, &mask_y); + if (unlikely (mask->status)) + return mask->status; + + /* top */ + if (extents->bounded.y != extents->unbounded.y) { + int x = extents->unbounded.x; + int y = extents->unbounded.y; + int width = extents->unbounded.width; + int height = extents->bounded.y - y; + + compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL, + x + mask_x, y + mask_y, + 0, 0, + x, y, + width, height); + } + + /* left */ + if (extents->bounded.x != extents->unbounded.x) { + int x = extents->unbounded.x; + int y = extents->bounded.y; + int width = extents->bounded.x - x; + int height = extents->bounded.height; + + compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL, + x + mask_x, y + mask_y, + 0, 0, + x, y, + width, height); + } + + /* right */ + if (extents->bounded.x + extents->bounded.width != extents->unbounded.x + extents->unbounded.width) { + int x = extents->bounded.x + extents->bounded.width; + int y = extents->bounded.y; + int width = extents->unbounded.x + extents->unbounded.width - x; + int height = extents->bounded.height; + + compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL, + x + mask_x, y + mask_y, + 0, 0, + x, y, + width, height); + } + + /* bottom */ + if (extents->bounded.y + extents->bounded.height != extents->unbounded.y + extents->unbounded.height) { + int x = extents->unbounded.x; + int y = extents->bounded.y + extents->bounded.height; + int width = extents->unbounded.width; + int height = extents->unbounded.y + extents->unbounded.height - y; + + compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL, + x + mask_x, y + mask_y, + 0, 0, + x, y, + width, height); + } + + cairo_surface_destroy (mask); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +fixup_unbounded_boxes (const cairo_mask_compositor_t *compositor, + const cairo_composite_rectangles_t *extents, + cairo_boxes_t *boxes) +{ + cairo_surface_t *dst = extents->surface; + cairo_boxes_t clear; + cairo_region_t *clip_region; + cairo_box_t box; + cairo_status_t status; + struct _cairo_boxes_chunk *chunk; + int i; + + assert (boxes->is_pixel_aligned); + + clip_region = NULL; + if (_cairo_clip_is_region (extents->clip) && + (clip_region = _cairo_clip_get_region (extents->clip)) && + cairo_region_contains_rectangle (clip_region, + &extents->bounded) == CAIRO_REGION_OVERLAP_IN) + clip_region = NULL; + + + if (boxes->num_boxes <= 1 && clip_region == NULL) + return fixup_unbounded (compositor, dst, extents); + + _cairo_boxes_init (&clear); + + box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width); + box.p1.y = _cairo_fixed_from_int (extents->unbounded.y); + box.p2.x = _cairo_fixed_from_int (extents->unbounded.x); + box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height); + + if (clip_region == NULL) { + cairo_boxes_t tmp; + + _cairo_boxes_init (&tmp); + + status = _cairo_boxes_add (&tmp, CAIRO_ANTIALIAS_DEFAULT, &box); + assert (status == CAIRO_STATUS_SUCCESS); + + tmp.chunks.next = &boxes->chunks; + tmp.num_boxes += boxes->num_boxes; + + status = _cairo_bentley_ottmann_tessellate_boxes (&tmp, + CAIRO_FILL_RULE_WINDING, + &clear); + + tmp.chunks.next = NULL; + } else { + pixman_box32_t *pbox; + + pbox = pixman_region32_rectangles (&clip_region->rgn, &i); + _cairo_boxes_limit (&clear, (cairo_box_t *) pbox, i); + + status = _cairo_boxes_add (&clear, CAIRO_ANTIALIAS_DEFAULT, &box); + assert (status == CAIRO_STATUS_SUCCESS); + + for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { + for (i = 0; i < chunk->count; i++) { + status = _cairo_boxes_add (&clear, + CAIRO_ANTIALIAS_DEFAULT, + &chunk->base[i]); + if (unlikely (status)) { + _cairo_boxes_fini (&clear); + return status; + } + } + } + + status = _cairo_bentley_ottmann_tessellate_boxes (&clear, + CAIRO_FILL_RULE_WINDING, + &clear); + } + + if (likely (status == CAIRO_STATUS_SUCCESS)) { + status = compositor->fill_boxes (dst, + CAIRO_OPERATOR_CLEAR, + CAIRO_COLOR_TRANSPARENT, + &clear); + } + + _cairo_boxes_fini (&clear); + + return status; +} + +enum { + NEED_CLIP_REGION = 0x1, + NEED_CLIP_SURFACE = 0x2, + FORCE_CLIP_REGION = 0x4, +}; + +static cairo_bool_t +need_bounded_clip (cairo_composite_rectangles_t *extents) +{ + unsigned int flags = NEED_CLIP_REGION; + if (! _cairo_clip_is_region (extents->clip)) + flags |= NEED_CLIP_SURFACE; + return flags; +} + +static cairo_bool_t +need_unbounded_clip (cairo_composite_rectangles_t *extents) +{ + unsigned int flags = 0; + if (! extents->is_bounded) { + flags |= NEED_CLIP_REGION; + if (! _cairo_clip_is_region (extents->clip)) + flags |= NEED_CLIP_SURFACE; + } + if (extents->clip->path != NULL) + flags |= NEED_CLIP_SURFACE; + return flags; +} + +static cairo_status_t +clip_and_composite (const cairo_mask_compositor_t *compositor, + draw_func_t draw_func, + draw_func_t mask_func, + void *draw_closure, + cairo_composite_rectangles_t*extents, + unsigned int need_clip) +{ + cairo_surface_t *dst = extents->surface; + cairo_operator_t op = extents->op; + cairo_pattern_t *src = &extents->source_pattern.base; + cairo_region_t *clip_region = NULL; + cairo_status_t status; + + compositor->acquire (dst); + + if (need_clip & NEED_CLIP_REGION) { + clip_region = _cairo_clip_get_region (extents->clip); + if ((need_clip & FORCE_CLIP_REGION) == 0 && + _cairo_composite_rectangles_can_reduce_clip (extents, + extents->clip)) + clip_region = NULL; + if (clip_region != NULL) { + status = compositor->set_clip_region (dst, clip_region); + if (unlikely (status)) { + compositor->release (dst); + return status; + } + } + } + + if (reduce_alpha_op (dst, op, &extents->source_pattern.base)) { + op = CAIRO_OPERATOR_ADD; + src = NULL; + } + + if (op == CAIRO_OPERATOR_SOURCE) { + status = clip_and_composite_source (compositor, + draw_closure, draw_func, mask_func, + src, extents); + } else { + if (op == CAIRO_OPERATOR_CLEAR) { + op = CAIRO_OPERATOR_DEST_OUT; + src = NULL; + } + + if (need_clip & NEED_CLIP_SURFACE) { + if (extents->is_bounded) { + status = clip_and_composite_with_mask (compositor, + draw_closure, + draw_func, + mask_func, + op, src, extents); + } else { + status = clip_and_composite_combine (compositor, + draw_closure, + draw_func, + op, src, extents); + } + } else { + status = draw_func (compositor, + dst, draw_closure, + op, src, &extents->source_sample_area, + 0, 0, + &extents->bounded, + extents->clip); + } + } + + if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) { + if (need_clip & NEED_CLIP_SURFACE) + status = fixup_unbounded_with_mask (compositor, dst, extents); + else + status = fixup_unbounded (compositor, dst, extents); + } + + if (clip_region) + compositor->set_clip_region (dst, NULL); + + compositor->release (dst); + + return status; +} + +static cairo_int_status_t +trim_extents_to_boxes (cairo_composite_rectangles_t *extents, + cairo_boxes_t *boxes) +{ + cairo_box_t box; + + _cairo_boxes_extents (boxes, &box); + return _cairo_composite_rectangles_intersect_mask_extents (extents, &box); +} + +static cairo_status_t +upload_boxes (const cairo_mask_compositor_t *compositor, + cairo_composite_rectangles_t *extents, + cairo_boxes_t *boxes) +{ + cairo_surface_t *dst = extents->surface; + const cairo_pattern_t *source = &extents->source_pattern.base; + cairo_surface_t *src; + cairo_rectangle_int_t limit; + cairo_int_status_t status; + int tx, ty; + + src = _cairo_pattern_get_source ((cairo_surface_pattern_t *)source, &limit); + if (!(src->type == CAIRO_SURFACE_TYPE_IMAGE || src->type == dst->type)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (! _cairo_matrix_is_integer_translation (&source->matrix, &tx, &ty)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* Check that the data is entirely within the image */ + if (extents->bounded.x + tx < limit.x || extents->bounded.y + ty < limit.y) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (extents->bounded.x + extents->bounded.width + tx > limit.x + limit.width || + extents->bounded.y + extents->bounded.height + ty > limit.y + limit.height) + return CAIRO_INT_STATUS_UNSUPPORTED; + + tx += limit.x; + ty += limit.y; + + if (src->type == CAIRO_SURFACE_TYPE_IMAGE) + status = compositor->draw_image_boxes (dst, + (cairo_image_surface_t *)src, + boxes, tx, ty); + else + status = compositor->copy_boxes (dst, src, boxes, &extents->bounded, + tx, ty); + + return status; +} + +static cairo_status_t +composite_boxes (const cairo_mask_compositor_t *compositor, + const cairo_composite_rectangles_t *extents, + cairo_boxes_t *boxes) +{ + cairo_surface_t *dst = extents->surface; + cairo_operator_t op = extents->op; + const cairo_pattern_t *source = &extents->source_pattern.base; + cairo_bool_t need_clip_mask = extents->clip->path != NULL; + cairo_status_t status; + + if (need_clip_mask && + (! extents->is_bounded || op == CAIRO_OPERATOR_SOURCE)) + { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + status = compositor->acquire (dst); + if (unlikely (status)) + return status; + + if (! need_clip_mask && source->type == CAIRO_PATTERN_TYPE_SOLID) { + const cairo_color_t *color; + + color = &((cairo_solid_pattern_t *) source)->color; + status = compositor->fill_boxes (dst, op, color, boxes); + } else { + cairo_surface_t *src, *mask = NULL; + int src_x, src_y; + int mask_x = 0, mask_y = 0; + + if (need_clip_mask) { + mask = get_clip_source (compositor, + extents->clip, dst, &extents->bounded, + &mask_x, &mask_y); + if (unlikely (mask->status)) + return mask->status; + + if (op == CAIRO_OPERATOR_CLEAR) { + source = NULL; + op = CAIRO_OPERATOR_DEST_OUT; + } + } + + if (source || mask == NULL) { + src = compositor->pattern_to_surface (dst, source, FALSE, + &extents->bounded, + &extents->source_sample_area, + &src_x, &src_y); + } else { + src = mask; + src_x = mask_x; + src_y = mask_y; + mask = NULL; + } + + status = compositor->composite_boxes (dst, op, src, mask, + src_x, src_y, + mask_x, mask_y, + 0, 0, + boxes, &extents->bounded); + + cairo_surface_destroy (src); + cairo_surface_destroy (mask); + } + + if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) + status = fixup_unbounded_boxes (compositor, extents, boxes); + + compositor->release (dst); + + return status; +} + +static cairo_status_t +clip_and_composite_boxes (const cairo_mask_compositor_t *compositor, + cairo_composite_rectangles_t *extents, + cairo_boxes_t *boxes) +{ + cairo_surface_t *dst = extents->surface; + cairo_int_status_t status; + + if (boxes->num_boxes == 0) { + if (extents->is_bounded) + return CAIRO_STATUS_SUCCESS; + + return fixup_unbounded_boxes (compositor, extents, boxes); + } + + if (! boxes->is_pixel_aligned) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = trim_extents_to_boxes (extents, boxes); + if (unlikely (status)) + return status; + + if (extents->source_pattern.base.type == CAIRO_PATTERN_TYPE_SURFACE && + extents->clip->path == NULL && + (extents->op == CAIRO_OPERATOR_SOURCE || + (dst->is_clear && (extents->op == CAIRO_OPERATOR_OVER || + extents->op == CAIRO_OPERATOR_ADD)))) + { + status = upload_boxes (compositor, extents, boxes); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + } + + return composite_boxes (compositor, extents, boxes); +} + +/* high-level compositor interface */ + +static cairo_int_status_t +_cairo_mask_compositor_paint (const cairo_compositor_t *_compositor, + cairo_composite_rectangles_t *extents) +{ + cairo_mask_compositor_t *compositor = (cairo_mask_compositor_t*)_compositor; + cairo_boxes_t boxes; + cairo_int_status_t status; + + status = compositor->check_composite (extents); + if (unlikely (status)) + return status; + + _cairo_clip_steal_boxes (extents->clip, &boxes); + status = clip_and_composite_boxes (compositor, extents, &boxes); + _cairo_clip_unsteal_boxes (extents->clip, &boxes); + + return status; +} + +struct composite_opacity_info { + const cairo_mask_compositor_t *compositor; + uint8_t op; + cairo_surface_t *dst; + cairo_surface_t *src; + int src_x, src_y; + double opacity; +}; + +static void composite_opacity(void *closure, + int16_t x, int16_t y, + int16_t w, int16_t h, + uint16_t coverage) +{ + struct composite_opacity_info *info = closure; + const cairo_mask_compositor_t *compositor = info->compositor; + cairo_surface_t *mask; + int mask_x, mask_y; + cairo_color_t color; + cairo_solid_pattern_t solid; + + _cairo_color_init_rgba (&color, 0, 0, 0, info->opacity * coverage); + _cairo_pattern_init_solid (&solid, &color); + mask = compositor->pattern_to_surface (info->dst, &solid.base, TRUE, + &_cairo_unbounded_rectangle, + &_cairo_unbounded_rectangle, + &mask_x, &mask_y); + if (likely (mask->status == CAIRO_STATUS_SUCCESS)) { + if (info->src) { + compositor->composite (info->dst, info->op, info->src, mask, + x + info->src_x, y + info->src_y, + mask_x, mask_y, + x, y, + w, h); + } else { + compositor->composite (info->dst, info->op, mask, NULL, + mask_x, mask_y, + 0, 0, + x, y, + w, h); + } + } + + cairo_surface_destroy (mask); +} + +static cairo_int_status_t +composite_opacity_boxes (const cairo_mask_compositor_t *compositor, + cairo_surface_t *dst, + void *closure, + cairo_operator_t op, + const cairo_pattern_t *src_pattern, + const cairo_rectangle_int_t *src_sample, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents, + cairo_clip_t *clip) +{ + const cairo_solid_pattern_t *mask_pattern = closure; + struct composite_opacity_info info; + int i; + + assert (clip); + + info.compositor = compositor; + info.op = op; + info.dst = dst; + + if (src_pattern != NULL) { + info.src = compositor->pattern_to_surface (dst, src_pattern, FALSE, + extents, src_sample, + &info.src_x, &info.src_y); + if (unlikely (info.src->status)) + return info.src->status; + } else + info.src = NULL; + + info.opacity = mask_pattern->color.alpha / (double) 0xffff; + + /* XXX for lots of boxes create a clip region for the fully opaque areas */ + for (i = 0; i < clip->num_boxes; i++) + do_unaligned_box(composite_opacity, &info, + &clip->boxes[i], dst_x, dst_y); + cairo_surface_destroy (info.src); + + return CAIRO_STATUS_SUCCESS; +} + +struct composite_box_info { + const cairo_mask_compositor_t *compositor; + cairo_surface_t *dst; + cairo_surface_t *src; + int src_x, src_y; + uint8_t op; +}; + +static void composite_box(void *closure, + int16_t x, int16_t y, + int16_t w, int16_t h, + uint16_t coverage) +{ + struct composite_box_info *info = closure; + const cairo_mask_compositor_t *compositor = info->compositor; + + if (! CAIRO_ALPHA_SHORT_IS_OPAQUE (coverage)) { + cairo_surface_t *mask; + cairo_color_t color; + cairo_solid_pattern_t solid; + int mask_x, mask_y; + + _cairo_color_init_rgba (&color, 0, 0, 0, coverage / (double)0xffff); + _cairo_pattern_init_solid (&solid, &color); + + mask = compositor->pattern_to_surface (info->dst, &solid.base, FALSE, + &_cairo_unbounded_rectangle, + &_cairo_unbounded_rectangle, + &mask_x, &mask_y); + + if (likely (mask->status == CAIRO_STATUS_SUCCESS)) { + compositor->composite (info->dst, info->op, info->src, mask, + x + info->src_x, y + info->src_y, + mask_x, mask_y, + x, y, + w, h); + } + + cairo_surface_destroy (mask); + } else { + compositor->composite (info->dst, info->op, info->src, NULL, + x + info->src_x, y + info->src_y, + 0, 0, + x, y, + w, h); + } +} + +static cairo_int_status_t +composite_mask_clip_boxes (const cairo_mask_compositor_t *compositor, + cairo_surface_t *dst, + void *closure, + cairo_operator_t op, + const cairo_pattern_t *src_pattern, + const cairo_rectangle_int_t *src_sample, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents, + cairo_clip_t *clip) +{ + cairo_composite_rectangles_t *composite = closure; + struct composite_box_info info; + int i; + + assert (src_pattern == NULL); + assert (op == CAIRO_OPERATOR_SOURCE); + + info.compositor = compositor; + info.op = CAIRO_OPERATOR_SOURCE; + info.dst = dst; + info.src = compositor->pattern_to_surface (dst, + &composite->mask_pattern.base, + FALSE, extents, + &composite->mask_sample_area, + &info.src_x, &info.src_y); + if (unlikely (info.src->status)) + return info.src->status; + + info.src_x += dst_x; + info.src_y += dst_y; + + for (i = 0; i < clip->num_boxes; i++) + do_unaligned_box(composite_box, &info, &clip->boxes[i], dst_x, dst_y); + + cairo_surface_destroy (info.src); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +composite_mask (const cairo_mask_compositor_t *compositor, + cairo_surface_t *dst, + void *closure, + cairo_operator_t op, + const cairo_pattern_t *src_pattern, + const cairo_rectangle_int_t *src_sample, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents, + cairo_clip_t *clip) +{ + cairo_composite_rectangles_t *composite = closure; + cairo_surface_t *src, *mask; + int src_x, src_y; + int mask_x, mask_y; + + if (src_pattern != NULL) { + src = compositor->pattern_to_surface (dst, src_pattern, FALSE, + extents, src_sample, + &src_x, &src_y); + if (unlikely (src->status)) + return src->status; + + mask = compositor->pattern_to_surface (dst, &composite->mask_pattern.base, TRUE, + extents, &composite->mask_sample_area, + &mask_x, &mask_y); + if (unlikely (mask->status)) { + cairo_surface_destroy (src); + return mask->status; + } + + compositor->composite (dst, op, src, mask, + extents->x + src_x, extents->y + src_y, + extents->x + mask_x, extents->y + mask_y, + extents->x - dst_x, extents->y - dst_y, + extents->width, extents->height); + + cairo_surface_destroy (mask); + cairo_surface_destroy (src); + } else { + src = compositor->pattern_to_surface (dst, &composite->mask_pattern.base, FALSE, + extents, &composite->mask_sample_area, + &src_x, &src_y); + if (unlikely (src->status)) + return src->status; + + compositor->composite (dst, op, src, NULL, + extents->x + src_x, extents->y + src_y, + 0, 0, + extents->x - dst_x, extents->y - dst_y, + extents->width, extents->height); + + cairo_surface_destroy (src); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_mask_compositor_mask (const cairo_compositor_t *_compositor, + cairo_composite_rectangles_t *extents) +{ + const cairo_mask_compositor_t *compositor = (cairo_mask_compositor_t*)_compositor; + cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED; + + status = compositor->check_composite (extents); + if (unlikely (status)) + return status; + + if (extents->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID && + extents->clip->path == NULL && + _cairo_clip_is_region (extents->clip)) { + status = clip_and_composite (compositor, + composite_opacity_boxes, + composite_opacity_boxes, + &extents->mask_pattern.solid, + extents, need_unbounded_clip (extents)); + } else { + status = clip_and_composite (compositor, + composite_mask, + extents->clip->path == NULL ? composite_mask_clip_boxes : NULL, + extents, + extents, need_bounded_clip (extents)); + } + + return status; +} + +static cairo_int_status_t +_cairo_mask_compositor_stroke (const cairo_compositor_t *_compositor, + cairo_composite_rectangles_t *extents, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias) +{ + const cairo_mask_compositor_t *compositor = (cairo_mask_compositor_t*)_compositor; + cairo_surface_t *mask; + cairo_surface_pattern_t pattern; + cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED; + + status = compositor->check_composite (extents); + if (unlikely (status)) + return status; + + if (_cairo_path_fixed_stroke_is_rectilinear (path)) { + cairo_boxes_t boxes; + + _cairo_boxes_init_with_clip (&boxes, extents->clip); + status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path, + style, + ctm, + antialias, + &boxes); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) + status = clip_and_composite_boxes (compositor, extents, &boxes); + _cairo_boxes_fini (&boxes); + } + + + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + mask = cairo_surface_create_similar_image (extents->surface, + CAIRO_FORMAT_A8, + extents->bounded.width, + extents->bounded.height); + if (unlikely (mask->status)) + return mask->status; + + status = _cairo_surface_offset_stroke (mask, + extents->bounded.x, + extents->bounded.y, + CAIRO_OPERATOR_ADD, + &_cairo_pattern_white.base, + path, style, ctm, ctm_inverse, + tolerance, antialias, + extents->clip); + if (unlikely (status)) { + cairo_surface_destroy (mask); + return status; + } + + _cairo_pattern_init_for_surface (&pattern, mask); + cairo_surface_destroy (mask); + + cairo_matrix_init_translate (&pattern.base.matrix, + -extents->bounded.x, + -extents->bounded.y); + pattern.base.filter = CAIRO_FILTER_NEAREST; + pattern.base.extend = CAIRO_EXTEND_NONE; + status = _cairo_surface_mask (extents->surface, + extents->op, + &extents->source_pattern.base, + &pattern.base, + extents->clip); + _cairo_pattern_fini (&pattern.base); + } + + return status; +} + +static cairo_int_status_t +_cairo_mask_compositor_fill (const cairo_compositor_t *_compositor, + cairo_composite_rectangles_t *extents, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + const cairo_mask_compositor_t *compositor = (cairo_mask_compositor_t*)_compositor; + cairo_surface_t *mask; + cairo_surface_pattern_t pattern; + cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED; + + status = compositor->check_composite (extents); + if (unlikely (status)) + return status; + + if (_cairo_path_fixed_fill_is_rectilinear (path)) { + cairo_boxes_t boxes; + + _cairo_boxes_init_with_clip (&boxes, extents->clip); + status = _cairo_path_fixed_fill_rectilinear_to_boxes (path, + fill_rule, + antialias, + &boxes); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) + status = clip_and_composite_boxes (compositor, extents, &boxes); + _cairo_boxes_fini (&boxes); + } + + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + mask = cairo_surface_create_similar_image (extents->surface, + CAIRO_FORMAT_A8, + extents->bounded.width, + extents->bounded.height); + if (unlikely (mask->status)) + return mask->status; + + status = _cairo_surface_offset_fill (mask, + extents->bounded.x, + extents->bounded.y, + CAIRO_OPERATOR_ADD, + &_cairo_pattern_white.base, + path, fill_rule, tolerance, antialias, + extents->clip); + if (unlikely (status)) { + cairo_surface_destroy (mask); + return status; + } + + _cairo_pattern_init_for_surface (&pattern, mask); + cairo_surface_destroy (mask); + + cairo_matrix_init_translate (&pattern.base.matrix, + -extents->bounded.x, + -extents->bounded.y); + pattern.base.filter = CAIRO_FILTER_NEAREST; + pattern.base.extend = CAIRO_EXTEND_NONE; + status = _cairo_surface_mask (extents->surface, + extents->op, + &extents->source_pattern.base, + &pattern.base, + extents->clip); + _cairo_pattern_fini (&pattern.base); + } + + return status; +} + +static cairo_int_status_t +_cairo_mask_compositor_glyphs (const cairo_compositor_t *_compositor, + cairo_composite_rectangles_t *extents, + cairo_scaled_font_t *scaled_font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_bool_t overlap) +{ + const cairo_mask_compositor_t *compositor = (cairo_mask_compositor_t*)_compositor; + cairo_surface_t *mask; + cairo_surface_pattern_t pattern; + cairo_int_status_t status; + + status = compositor->check_composite (extents); + if (unlikely (status)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + mask = cairo_surface_create_similar_image (extents->surface, + CAIRO_FORMAT_A8, + extents->bounded.width, + extents->bounded.height); + if (unlikely (mask->status)) + return mask->status; + + status = _cairo_surface_offset_glyphs (mask, + extents->bounded.x, + extents->bounded.y, + CAIRO_OPERATOR_ADD, + &_cairo_pattern_white.base, + scaled_font, glyphs, num_glyphs, + extents->clip); + if (unlikely (status)) { + cairo_surface_destroy (mask); + return status; + } + + _cairo_pattern_init_for_surface (&pattern, mask); + cairo_surface_destroy (mask); + + cairo_matrix_init_translate (&pattern.base.matrix, + -extents->bounded.x, + -extents->bounded.y); + pattern.base.filter = CAIRO_FILTER_NEAREST; + pattern.base.extend = CAIRO_EXTEND_NONE; + status = _cairo_surface_mask (extents->surface, + extents->op, + &extents->source_pattern.base, + &pattern.base, + extents->clip); + _cairo_pattern_fini (&pattern.base); + + return status; +} + +void +_cairo_mask_compositor_init (cairo_mask_compositor_t *compositor, + const cairo_compositor_t *delegate) +{ + compositor->base.delegate = delegate; + + compositor->base.paint = _cairo_mask_compositor_paint; + compositor->base.mask = _cairo_mask_compositor_mask; + compositor->base.fill = _cairo_mask_compositor_fill; + compositor->base.stroke = _cairo_mask_compositor_stroke; + compositor->base.glyphs = _cairo_mask_compositor_glyphs; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-matrix.c b/local/recipes/libs/cairo/source/src/cairo-matrix.c new file mode 100644 index 0000000000..f2be48b74d --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-matrix.c @@ -0,0 +1,1190 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + */ + +#include "cairoint.h" +#include "cairo-error-private.h" +#include + +#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */ + +/** + * SECTION:cairo-matrix + * @Title: cairo_matrix_t + * @Short_Description: Generic matrix operations + * @See_Also: #cairo_t + * + * #cairo_matrix_t is used throughout cairo to convert between different + * coordinate spaces. A #cairo_matrix_t holds an affine transformation, + * such as a scale, rotation, shear, or a combination of these. + * The transformation of a point (x,y) + * is given by: + * + * + * x_new = xx * x + xy * y + x0; + * y_new = yx * x + yy * y + y0; + * + * + * The current transformation matrix of a #cairo_t, represented as a + * #cairo_matrix_t, defines the transformation from user-space + * coordinates to device-space coordinates. See cairo_get_matrix() and + * cairo_set_matrix(). + **/ + +static void +_cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar); + +static void +_cairo_matrix_compute_adjoint (cairo_matrix_t *matrix); + +/** + * cairo_matrix_init_identity: + * @matrix: a #cairo_matrix_t + * + * Modifies @matrix to be an identity transformation. + * + * Since: 1.0 + **/ +void +cairo_matrix_init_identity (cairo_matrix_t *matrix) +{ + cairo_matrix_init (matrix, + 1, 0, + 0, 1, + 0, 0); +} + +/** + * cairo_matrix_init: + * @matrix: a #cairo_matrix_t + * @xx: xx component of the affine transformation + * @yx: yx component of the affine transformation + * @xy: xy component of the affine transformation + * @yy: yy component of the affine transformation + * @x0: X translation component of the affine transformation + * @y0: Y translation component of the affine transformation + * + * Sets @matrix to be the affine transformation given by + * @xx, @yx, @xy, @yy, @x0, @y0. The transformation is given + * by: + * + * x_new = xx * x + xy * y + x0; + * y_new = yx * x + yy * y + y0; + * + * + * Since: 1.0 + **/ +void +cairo_matrix_init (cairo_matrix_t *matrix, + double xx, double yx, + + double xy, double yy, + double x0, double y0) +{ + matrix->xx = xx; matrix->yx = yx; + matrix->xy = xy; matrix->yy = yy; + matrix->x0 = x0; matrix->y0 = y0; +} + +/** + * _cairo_matrix_get_affine: + * @matrix: a #cairo_matrix_t + * @xx: location to store xx component of matrix + * @yx: location to store yx component of matrix + * @xy: location to store xy component of matrix + * @yy: location to store yy component of matrix + * @x0: location to store x0 (X-translation component) of matrix, or %NULL + * @y0: location to store y0 (Y-translation component) of matrix, or %NULL + * + * Gets the matrix values for the affine transformation that @matrix represents. + * See cairo_matrix_init(). + * + * + * This function is a leftover from the old public API, but is still + * mildly useful as an internal means for getting at the matrix + * members in a positional way. For example, when reassigning to some + * external matrix type, or when renaming members to more meaningful + * names (such as a,b,c,d,e,f) for particular manipulations. + **/ +void +_cairo_matrix_get_affine (const cairo_matrix_t *matrix, + double *xx, double *yx, + double *xy, double *yy, + double *x0, double *y0) +{ + *xx = matrix->xx; + *yx = matrix->yx; + + *xy = matrix->xy; + *yy = matrix->yy; + + if (x0) + *x0 = matrix->x0; + if (y0) + *y0 = matrix->y0; +} + +/** + * cairo_matrix_init_translate: + * @matrix: a #cairo_matrix_t + * @tx: amount to translate in the X direction + * @ty: amount to translate in the Y direction + * + * Initializes @matrix to a transformation that translates by @tx and + * @ty in the X and Y dimensions, respectively. + * + * Since: 1.0 + **/ +void +cairo_matrix_init_translate (cairo_matrix_t *matrix, + double tx, double ty) +{ + cairo_matrix_init (matrix, + 1, 0, + 0, 1, + tx, ty); +} + +/** + * cairo_matrix_translate: + * @matrix: a #cairo_matrix_t + * @tx: amount to translate in the X direction + * @ty: amount to translate in the Y direction + * + * Applies a translation by @tx, @ty to the transformation in + * @matrix. The effect of the new transformation is to first translate + * the coordinates by @tx and @ty, then apply the original transformation + * to the coordinates. + * + * Since: 1.0 + **/ +void +cairo_matrix_translate (cairo_matrix_t *matrix, double tx, double ty) +{ + cairo_matrix_t tmp; + + cairo_matrix_init_translate (&tmp, tx, ty); + + cairo_matrix_multiply (matrix, &tmp, matrix); +} + +/** + * cairo_matrix_init_scale: + * @matrix: a #cairo_matrix_t + * @sx: scale factor in the X direction + * @sy: scale factor in the Y direction + * + * Initializes @matrix to a transformation that scales by @sx and @sy + * in the X and Y dimensions, respectively. + * + * Since: 1.0 + **/ +void +cairo_matrix_init_scale (cairo_matrix_t *matrix, + double sx, double sy) +{ + cairo_matrix_init (matrix, + sx, 0, + 0, sy, + 0, 0); +} + +/** + * cairo_matrix_scale: + * @matrix: a #cairo_matrix_t + * @sx: scale factor in the X direction + * @sy: scale factor in the Y direction + * + * Applies scaling by @sx, @sy to the transformation in @matrix. The + * effect of the new transformation is to first scale the coordinates + * by @sx and @sy, then apply the original transformation to the coordinates. + * + * Since: 1.0 + **/ +void +cairo_matrix_scale (cairo_matrix_t *matrix, double sx, double sy) +{ + cairo_matrix_t tmp; + + cairo_matrix_init_scale (&tmp, sx, sy); + + cairo_matrix_multiply (matrix, &tmp, matrix); +} + +/** + * cairo_matrix_init_rotate: + * @matrix: a #cairo_matrix_t + * @radians: angle of rotation, in radians. The direction of rotation + * is defined such that positive angles rotate in the direction from + * the positive X axis toward the positive Y axis. With the default + * axis orientation of cairo, positive angles rotate in a clockwise + * direction. + * + * Initialized @matrix to a transformation that rotates by @radians. + * + * Since: 1.0 + **/ +void +cairo_matrix_init_rotate (cairo_matrix_t *matrix, + double radians) +{ + double s; + double c; + + s = sin (radians); + c = cos (radians); + + cairo_matrix_init (matrix, + c, s, + -s, c, + 0, 0); +} + +/** + * cairo_matrix_rotate: + * @matrix: a #cairo_matrix_t + * @radians: angle of rotation, in radians. The direction of rotation + * is defined such that positive angles rotate in the direction from + * the positive X axis toward the positive Y axis. With the default + * axis orientation of cairo, positive angles rotate in a clockwise + * direction. + * + * Applies rotation by @radians to the transformation in + * @matrix. The effect of the new transformation is to first rotate the + * coordinates by @radians, then apply the original transformation + * to the coordinates. + * + * Since: 1.0 + **/ +void +cairo_matrix_rotate (cairo_matrix_t *matrix, double radians) +{ + cairo_matrix_t tmp; + + cairo_matrix_init_rotate (&tmp, radians); + + cairo_matrix_multiply (matrix, &tmp, matrix); +} + +/** + * cairo_matrix_multiply: + * @result: a #cairo_matrix_t in which to store the result + * @a: a #cairo_matrix_t + * @b: a #cairo_matrix_t + * + * Multiplies the affine transformations in @a and @b together + * and stores the result in @result. The effect of the resulting + * transformation is to first apply the transformation in @a to the + * coordinates and then apply the transformation in @b to the + * coordinates. + * + * It is allowable for @result to be identical to either @a or @b. + * + * Since: 1.0 + **/ +/* + * XXX: The ordering of the arguments to this function corresponds + * to [row_vector]*A*B. If we want to use column vectors instead, + * then we need to switch the two arguments and fix up all + * uses. + */ +void +cairo_matrix_multiply (cairo_matrix_t *result, const cairo_matrix_t *a, const cairo_matrix_t *b) +{ + cairo_matrix_t r; + + r.xx = a->xx * b->xx + a->yx * b->xy; + r.yx = a->xx * b->yx + a->yx * b->yy; + + r.xy = a->xy * b->xx + a->yy * b->xy; + r.yy = a->xy * b->yx + a->yy * b->yy; + + r.x0 = a->x0 * b->xx + a->y0 * b->xy + b->x0; + r.y0 = a->x0 * b->yx + a->y0 * b->yy + b->y0; + + *result = r; +} + +void +_cairo_matrix_multiply (cairo_matrix_t *r, + const cairo_matrix_t *a, + const cairo_matrix_t *b) +{ + r->xx = a->xx * b->xx + a->yx * b->xy; + r->yx = a->xx * b->yx + a->yx * b->yy; + + r->xy = a->xy * b->xx + a->yy * b->xy; + r->yy = a->xy * b->yx + a->yy * b->yy; + + r->x0 = a->x0 * b->xx + a->y0 * b->xy + b->x0; + r->y0 = a->x0 * b->yx + a->y0 * b->yy + b->y0; +} + +/** + * cairo_matrix_transform_distance: + * @matrix: a #cairo_matrix_t + * @dx: X component of a distance vector. An in/out parameter + * @dy: Y component of a distance vector. An in/out parameter + * + * Transforms the distance vector (@dx,@dy) by @matrix. This is + * similar to cairo_matrix_transform_point() except that the translation + * components of the transformation are ignored. The calculation of + * the returned vector is as follows: + * + * + * dx_new = xx * dx + xy * dy; + * dy_new = yx * dx + yy * dy; + * + * + * Since: 1.0 + **/ +void +cairo_matrix_transform_distance (const cairo_matrix_t *matrix, double *dx, double *dy) +{ + double new_x, new_y; + + new_x = (matrix->xx * *dx + matrix->xy * *dy); + new_y = (matrix->yx * *dx + matrix->yy * *dy); + + *dx = new_x; + *dy = new_y; +} + +/** + * cairo_matrix_transform_point: + * @matrix: a #cairo_matrix_t + * @x: X position. An in/out parameter + * @y: Y position. An in/out parameter + * + * Transforms the point (@x, @y) by @matrix. + * + * Since: 1.0 + **/ +void +cairo_matrix_transform_point (const cairo_matrix_t *matrix, double *x, double *y) +{ + cairo_matrix_transform_distance (matrix, x, y); + + *x += matrix->x0; + *y += matrix->y0; +} + +void +_cairo_matrix_transform_bounding_box (const cairo_matrix_t *matrix, + double *x1, double *y1, + double *x2, double *y2, + cairo_bool_t *is_tight) +{ + int i; + double quad_x[4], quad_y[4]; + double min_x, max_x; + double min_y, max_y; + + if (matrix->xy == 0. && matrix->yx == 0.) { + /* non-rotation/skew matrix, just map the two extreme points */ + + if (matrix->xx != 1.) { + quad_x[0] = *x1 * matrix->xx; + quad_x[1] = *x2 * matrix->xx; + if (quad_x[0] < quad_x[1]) { + *x1 = quad_x[0]; + *x2 = quad_x[1]; + } else { + *x1 = quad_x[1]; + *x2 = quad_x[0]; + } + } + if (matrix->x0 != 0.) { + *x1 += matrix->x0; + *x2 += matrix->x0; + } + + if (matrix->yy != 1.) { + quad_y[0] = *y1 * matrix->yy; + quad_y[1] = *y2 * matrix->yy; + if (quad_y[0] < quad_y[1]) { + *y1 = quad_y[0]; + *y2 = quad_y[1]; + } else { + *y1 = quad_y[1]; + *y2 = quad_y[0]; + } + } + if (matrix->y0 != 0.) { + *y1 += matrix->y0; + *y2 += matrix->y0; + } + + if (is_tight) + *is_tight = TRUE; + + return; + } + + /* general matrix */ + quad_x[0] = *x1; + quad_y[0] = *y1; + cairo_matrix_transform_point (matrix, &quad_x[0], &quad_y[0]); + + quad_x[1] = *x2; + quad_y[1] = *y1; + cairo_matrix_transform_point (matrix, &quad_x[1], &quad_y[1]); + + quad_x[2] = *x1; + quad_y[2] = *y2; + cairo_matrix_transform_point (matrix, &quad_x[2], &quad_y[2]); + + quad_x[3] = *x2; + quad_y[3] = *y2; + cairo_matrix_transform_point (matrix, &quad_x[3], &quad_y[3]); + + min_x = max_x = quad_x[0]; + min_y = max_y = quad_y[0]; + + for (i=1; i < 4; i++) { + if (quad_x[i] < min_x) + min_x = quad_x[i]; + if (quad_x[i] > max_x) + max_x = quad_x[i]; + + if (quad_y[i] < min_y) + min_y = quad_y[i]; + if (quad_y[i] > max_y) + max_y = quad_y[i]; + } + + *x1 = min_x; + *y1 = min_y; + *x2 = max_x; + *y2 = max_y; + + if (is_tight) { + /* it's tight if and only if the four corner points form an axis-aligned + rectangle. + And that's true if and only if we can derive corners 0 and 3 from + corners 1 and 2 in one of two straightforward ways... + We could use a tolerance here but for now we'll fall back to FALSE in the case + of floating point error. + */ + *is_tight = + (quad_x[1] == quad_x[0] && quad_y[1] == quad_y[3] && + quad_x[2] == quad_x[3] && quad_y[2] == quad_y[0]) || + (quad_x[1] == quad_x[3] && quad_y[1] == quad_y[0] && + quad_x[2] == quad_x[0] && quad_y[2] == quad_y[3]); + } +} + +cairo_private void +_cairo_matrix_transform_bounding_box_fixed (const cairo_matrix_t *matrix, + cairo_box_t *bbox, + cairo_bool_t *is_tight) +{ + double x1, y1, x2, y2; + + _cairo_box_to_doubles (bbox, &x1, &y1, &x2, &y2); + _cairo_matrix_transform_bounding_box (matrix, &x1, &y1, &x2, &y2, is_tight); + _cairo_box_from_doubles (bbox, &x1, &y1, &x2, &y2); +} + +static void +_cairo_matrix_scalar_multiply (cairo_matrix_t *matrix, double scalar) +{ + matrix->xx *= scalar; + matrix->yx *= scalar; + + matrix->xy *= scalar; + matrix->yy *= scalar; + + matrix->x0 *= scalar; + matrix->y0 *= scalar; +} + +/* This function isn't a correct adjoint in that the implicit 1 in the + homogeneous result should actually be ad-bc instead. But, since this + adjoint is only used in the computation of the inverse, which + divides by det (A)=ad-bc anyway, everything works out in the end. */ +static void +_cairo_matrix_compute_adjoint (cairo_matrix_t *matrix) +{ + /* adj (A) = transpose (C:cofactor (A,i,j)) */ + double a, b, c, d, tx, ty; + + _cairo_matrix_get_affine (matrix, + &a, &b, + &c, &d, + &tx, &ty); + + cairo_matrix_init (matrix, + d, -b, + -c, a, + c*ty - d*tx, b*tx - a*ty); +} + +/** + * cairo_matrix_invert: + * @matrix: a #cairo_matrix_t + * + * Changes @matrix to be the inverse of its original value. Not + * all transformation matrices have inverses; if the matrix + * collapses points together (it is degenerate), + * then it has no inverse and this function will fail. + * + * Returns: If @matrix has an inverse, modifies @matrix to + * be the inverse matrix and returns %CAIRO_STATUS_SUCCESS. Otherwise, + * returns %CAIRO_STATUS_INVALID_MATRIX. + * + * Since: 1.0 + **/ +cairo_status_t +cairo_matrix_invert (cairo_matrix_t *matrix) +{ + double det; + + /* Simple scaling|translation matrices are quite common... */ + if (matrix->xy == 0. && matrix->yx == 0.) { + matrix->x0 = -matrix->x0; + matrix->y0 = -matrix->y0; + + if (matrix->xx != 1.) { + if (matrix->xx == 0.) + return _cairo_error (CAIRO_STATUS_INVALID_MATRIX); + + matrix->xx = 1. / matrix->xx; + matrix->x0 *= matrix->xx; + } + + if (matrix->yy != 1.) { + if (matrix->yy == 0.) + return _cairo_error (CAIRO_STATUS_INVALID_MATRIX); + + matrix->yy = 1. / matrix->yy; + matrix->y0 *= matrix->yy; + } + + return CAIRO_STATUS_SUCCESS; + } + + /* inv (A) = 1/det (A) * adj (A) */ + det = _cairo_matrix_compute_determinant (matrix); + + if (! ISFINITE (det)) + return _cairo_error (CAIRO_STATUS_INVALID_MATRIX); + + if (det == 0) + return _cairo_error (CAIRO_STATUS_INVALID_MATRIX); + + _cairo_matrix_compute_adjoint (matrix); + _cairo_matrix_scalar_multiply (matrix, 1 / det); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_bool_t +_cairo_matrix_is_invertible (const cairo_matrix_t *matrix) +{ + double det; + + det = _cairo_matrix_compute_determinant (matrix); + + return ISFINITE (det) && det != 0.; +} + +cairo_bool_t +_cairo_matrix_is_scale_0 (const cairo_matrix_t *matrix) +{ + return matrix->xx == 0. && + matrix->xy == 0. && + matrix->yx == 0. && + matrix->yy == 0.; +} + +double +_cairo_matrix_compute_determinant (const cairo_matrix_t *matrix) +{ + double a, b, c, d; + + a = matrix->xx; b = matrix->yx; + c = matrix->xy; d = matrix->yy; + + return a*d - b*c; +} + +/** + * _cairo_matrix_compute_basis_scale_factors: + * @matrix: a matrix + * @basis_scale: the scale factor in the direction of basis + * @normal_scale: the scale factor in the direction normal to the basis + * @x_basis: basis to use. X basis if true, Y basis otherwise. + * + * Computes |Mv| and det(M)/|Mv| for v=[1,0] if x_basis is true, and v=[0,1] + * otherwise, and M is @matrix. + * + * Return value: the scale factor of @matrix on the height of the font, + * or 1.0 if @matrix is %NULL. + **/ +cairo_status_t +_cairo_matrix_compute_basis_scale_factors (const cairo_matrix_t *matrix, + double *basis_scale, double *normal_scale, + cairo_bool_t x_basis) +{ + double det; + + det = _cairo_matrix_compute_determinant (matrix); + + if (! ISFINITE (det)) + return _cairo_error (CAIRO_STATUS_INVALID_MATRIX); + + if (det == 0) + { + *basis_scale = *normal_scale = 0; + } + else + { + double x = x_basis != 0; + double y = x == 0; + double major, minor; + + cairo_matrix_transform_distance (matrix, &x, &y); + major = hypot (x, y); + /* + * ignore mirroring + */ + if (det < 0) + det = -det; + if (major) + minor = det / major; + else + minor = 0.0; + if (x_basis) + { + *basis_scale = major; + *normal_scale = minor; + } + else + { + *basis_scale = minor; + *normal_scale = major; + } + } + + return CAIRO_STATUS_SUCCESS; +} + +cairo_bool_t +_cairo_matrix_is_integer_translation (const cairo_matrix_t *matrix, + int *itx, int *ity) +{ + if (_cairo_matrix_is_translation (matrix)) + { + cairo_fixed_t x0_fixed = _cairo_fixed_from_double (matrix->x0); + cairo_fixed_t y0_fixed = _cairo_fixed_from_double (matrix->y0); + + if (_cairo_fixed_is_integer (x0_fixed) && + _cairo_fixed_is_integer (y0_fixed)) + { + if (itx) + *itx = _cairo_fixed_integer_part (x0_fixed); + if (ity) + *ity = _cairo_fixed_integer_part (y0_fixed); + + return TRUE; + } + } + + return FALSE; +} + +#define SCALING_EPSILON _cairo_fixed_to_double(1) + +/* This only returns true if the matrix is 90 degree rotations or + * flips. It appears calling code is relying on this. It will return + * false for other rotations even if the scale is one. Approximations + * are allowed to handle matricies filled in using trig functions + * such as sin(M_PI_2). + */ +cairo_bool_t +_cairo_matrix_has_unity_scale (const cairo_matrix_t *matrix) +{ + /* check that the determinant is near +/-1 */ + double det = _cairo_matrix_compute_determinant (matrix); + if (fabs (det * det - 1.0) < SCALING_EPSILON) { + /* check that one axis is close to zero */ + if (fabs (matrix->xy) < SCALING_EPSILON && + fabs (matrix->yx) < SCALING_EPSILON) + return TRUE; + if (fabs (matrix->xx) < SCALING_EPSILON && + fabs (matrix->yy) < SCALING_EPSILON) + return TRUE; + /* If rotations are allowed then it must instead test for + * orthogonality. This is xx*xy+yx*yy ~= 0. + */ + } + return FALSE; +} + +/* By pixel exact here, we mean a matrix that is composed only of + * 90 degree rotations, flips, and integer translations and produces a 1:1 + * mapping between source and destination pixels. If we transform an image + * with a pixel-exact matrix, filtering is not useful. + */ +cairo_bool_t +_cairo_matrix_is_pixel_exact (const cairo_matrix_t *matrix) +{ + cairo_fixed_t x0_fixed, y0_fixed; + + if (! _cairo_matrix_has_unity_scale (matrix)) + return FALSE; + + x0_fixed = _cairo_fixed_from_double (matrix->x0); + y0_fixed = _cairo_fixed_from_double (matrix->y0); + + return _cairo_fixed_is_integer (x0_fixed) && _cairo_fixed_is_integer (y0_fixed); +} + +/* + A circle in user space is transformed into an ellipse in device space. + + The following is a derivation of a formula to calculate the length of the + major axis for this ellipse; this is useful for error bounds calculations. + + Thanks to Walter Brisken for this derivation: + + 1. First some notation: + + All capital letters represent vectors in two dimensions. A prime ' + represents a transformed coordinate. Matrices are written in underlined + form, ie _R_. Lowercase letters represent scalar real values. + + 2. The question has been posed: What is the maximum expansion factor + achieved by the linear transformation + + X' = X _R_ + + where _R_ is a real-valued 2x2 matrix with entries: + + _R_ = [a b] + [c d] . + + In other words, what is the maximum radius, MAX[ |X'| ], reached for any + X on the unit circle ( |X| = 1 ) ? + + 3. Some useful formulae + + (A) through (C) below are standard double-angle formulae. (D) is a lesser + known result and is derived below: + + (A) sin²(θ) = (1 - cos(2*θ))/2 + (B) cos²(θ) = (1 + cos(2*θ))/2 + (C) sin(θ)*cos(θ) = sin(2*θ)/2 + (D) MAX[a*cos(θ) + b*sin(θ)] = sqrt(a² + b²) + + Proof of (D): + + find the maximum of the function by setting the derivative to zero: + + -a*sin(θ)+b*cos(θ) = 0 + + From this it follows that + + tan(θ) = b/a + + and hence + + sin(θ) = b/sqrt(a² + b²) + + and + + cos(θ) = a/sqrt(a² + b²) + + Thus the maximum value is + + MAX[a*cos(θ) + b*sin(θ)] = (a² + b²)/sqrt(a² + b²) + = sqrt(a² + b²) + + 4. Derivation of maximum expansion + + To find MAX[ |X'| ] we search brute force method using calculus. The unit + circle on which X is constrained is to be parameterized by t: + + X(θ) = (cos(θ), sin(θ)) + + Thus + + X'(θ) = X(θ) * _R_ = (cos(θ), sin(θ)) * [a b] + [c d] + = (a*cos(θ) + c*sin(θ), b*cos(θ) + d*sin(θ)). + + Define + + r(θ) = |X'(θ)| + + Thus + + r²(θ) = (a*cos(θ) + c*sin(θ))² + (b*cos(θ) + d*sin(θ))² + = (a² + b²)*cos²(θ) + (c² + d²)*sin²(θ) + + 2*(a*c + b*d)*cos(θ)*sin(θ) + + Now apply the double angle formulae (A) to (C) from above: + + r²(θ) = (a² + b² + c² + d²)/2 + + (a² + b² - c² - d²)*cos(2*θ)/2 + + (a*c + b*d)*sin(2*θ) + = f + g*cos(φ) + h*sin(φ) + + Where + + f = (a² + b² + c² + d²)/2 + g = (a² + b² - c² - d²)/2 + h = (a*c + d*d) + φ = 2*θ + + It is clear that MAX[ |X'| ] = sqrt(MAX[ r² ]). Here we determine MAX[ r² ] + using (D) from above: + + MAX[ r² ] = f + sqrt(g² + h²) + + And finally + + MAX[ |X'| ] = sqrt( f + sqrt(g² + h²) ) + + Which is the solution to this problem. + + Walter Brisken + 2004/10/08 + + (Note that the minor axis length is at the minimum of the above solution, + which is just sqrt ( f - sqrt(g² + h²) ) given the symmetry of (D)). + + + For another derivation of the same result, using Singular Value Decomposition, + see doc/tutorial/src/singular.c. +*/ + +/* determine the length of the major axis of a circle of the given radius + after applying the transformation matrix. */ +double +_cairo_matrix_transformed_circle_major_axis (const cairo_matrix_t *matrix, + double radius) +{ + double a, b, c, d, f, g, h, i, j; + + if (_cairo_matrix_has_unity_scale (matrix)) + return radius; + + _cairo_matrix_get_affine (matrix, + &a, &b, + &c, &d, + NULL, NULL); + + i = a*a + b*b; + j = c*c + d*d; + + f = 0.5 * (i + j); + g = 0.5 * (i - j); + h = a*c + b*d; + + return radius * sqrt (f + hypot (g, h)); + + /* + * we don't need the minor axis length, which is + * double min = radius * sqrt (f - sqrt (g*g+h*h)); + */ +} + +static const pixman_transform_t pixman_identity_transform = {{ + {1 << 16, 0, 0}, + { 0, 1 << 16, 0}, + { 0, 0, 1 << 16} + }}; + +static cairo_status_t +_cairo_matrix_to_pixman_matrix (const cairo_matrix_t *matrix, + pixman_transform_t *pixman_transform, + double xc, + double yc) +{ + cairo_matrix_t inv; + unsigned max_iterations; + + pixman_transform->matrix[0][0] = _cairo_fixed_16_16_from_double (matrix->xx); + pixman_transform->matrix[0][1] = _cairo_fixed_16_16_from_double (matrix->xy); + pixman_transform->matrix[0][2] = _cairo_fixed_16_16_from_double (matrix->x0); + + pixman_transform->matrix[1][0] = _cairo_fixed_16_16_from_double (matrix->yx); + pixman_transform->matrix[1][1] = _cairo_fixed_16_16_from_double (matrix->yy); + pixman_transform->matrix[1][2] = _cairo_fixed_16_16_from_double (matrix->y0); + + pixman_transform->matrix[2][0] = 0; + pixman_transform->matrix[2][1] = 0; + pixman_transform->matrix[2][2] = 1 << 16; + + /* The conversion above breaks cairo's translation invariance: + * a translation of (a, b) in device space translates to + * a translation of (xx * a + xy * b, yx * a + yy * b) + * for cairo, while pixman uses rounded versions of xx ... yy. + * This error increases as a and b get larger. + * + * To compensate for this, we fix the point (xc, yc) in pattern + * space and adjust pixman's transform to agree with cairo's at + * that point. + */ + + if (_cairo_matrix_has_unity_scale (matrix)) + return CAIRO_STATUS_SUCCESS; + + if (unlikely (fabs (matrix->xx) > PIXMAN_MAX_INT || + fabs (matrix->xy) > PIXMAN_MAX_INT || + fabs (matrix->x0) > PIXMAN_MAX_INT || + fabs (matrix->yx) > PIXMAN_MAX_INT || + fabs (matrix->yy) > PIXMAN_MAX_INT || + fabs (matrix->y0) > PIXMAN_MAX_INT)) + { + return _cairo_error (CAIRO_STATUS_INVALID_MATRIX); + } + + /* Note: If we can't invert the transformation, skip the adjustment. */ + inv = *matrix; + if (cairo_matrix_invert (&inv) != CAIRO_STATUS_SUCCESS) + return CAIRO_STATUS_SUCCESS; + + /* find the pattern space coordinate that maps to (xc, yc) */ + max_iterations = 5; + do { + double x,y; + pixman_vector_t vector; + cairo_fixed_16_16_t dx, dy; + + vector.vector[0] = _cairo_fixed_16_16_from_double (xc); + vector.vector[1] = _cairo_fixed_16_16_from_double (yc); + vector.vector[2] = 1 << 16; + + /* If we can't transform the reference point, skip the adjustment. */ + if (! pixman_transform_point_3d (pixman_transform, &vector)) + return CAIRO_STATUS_SUCCESS; + + x = pixman_fixed_to_double (vector.vector[0]); + y = pixman_fixed_to_double (vector.vector[1]); + cairo_matrix_transform_point (&inv, &x, &y); + + /* Ideally, the vector should now be (xc, yc). + * We can now compensate for the resulting error. + */ + x -= xc; + y -= yc; + cairo_matrix_transform_distance (matrix, &x, &y); + dx = _cairo_fixed_16_16_from_double (x); + dy = _cairo_fixed_16_16_from_double (y); + pixman_transform->matrix[0][2] -= dx; + pixman_transform->matrix[1][2] -= dy; + + if (dx == 0 && dy == 0) + return CAIRO_STATUS_SUCCESS; + } while (--max_iterations); + + /* We didn't find an exact match between cairo and pixman, but + * the matrix should be mostly correct */ + return CAIRO_STATUS_SUCCESS; +} + +static inline double +_pixman_nearest_sample (double d) +{ + return ceil (d - .5); +} + +/** + * _cairo_matrix_is_pixman_translation: + * @matrix: a matrix + * @filter: the filter to be used on the pattern transformed by @matrix + * @x_offset: the translation in the X direction + * @y_offset: the translation in the Y direction + * + * Checks if @matrix translated by (x_offset, y_offset) can be + * represented using just an offset (within the range pixman can + * accept) and an identity matrix. + * + * Passing a non-zero value in x_offset/y_offset has the same effect + * as applying cairo_matrix_translate(matrix, x_offset, y_offset) and + * setting x_offset and y_offset to 0. + * + * Upon return x_offset and y_offset contain the translation vector if + * the return value is %TRUE. If the return value is %FALSE, they will + * not be modified. + * + * Return value: %TRUE if @matrix can be represented as a pixman + * translation, %FALSE otherwise. + **/ +cairo_bool_t +_cairo_matrix_is_pixman_translation (const cairo_matrix_t *matrix, + cairo_filter_t filter, + int *x_offset, + int *y_offset) +{ + double tx, ty; + + if (!_cairo_matrix_is_translation (matrix)) + return FALSE; + + if (matrix->x0 == 0. && matrix->y0 == 0.) + return TRUE; + + tx = matrix->x0 + *x_offset; + ty = matrix->y0 + *y_offset; + + if (filter == CAIRO_FILTER_FAST || filter == CAIRO_FILTER_NEAREST) { + tx = _pixman_nearest_sample (tx); + ty = _pixman_nearest_sample (ty); + } else if (tx != floor (tx) || ty != floor (ty)) { + return FALSE; + } + + if (fabs (tx) > PIXMAN_MAX_INT || fabs (ty) > PIXMAN_MAX_INT) + return FALSE; + + *x_offset = _cairo_lround (tx); + *y_offset = _cairo_lround (ty); + return TRUE; +} + +/** + * _cairo_matrix_to_pixman_matrix_offset: + * @matrix: a matrix + * @filter: the filter to be used on the pattern transformed by @matrix + * @xc: the X coordinate of the point to fix in pattern space + * @yc: the Y coordinate of the point to fix in pattern space + * @out_transform: the transformation which best approximates @matrix + * @x_offset: the translation in the X direction + * @y_offset: the translation in the Y direction + * + * This function tries to represent @matrix translated by (x_offset, + * y_offset) as a %pixman_transform_t and an translation. + * + * Passing a non-zero value in x_offset/y_offset has the same effect + * as applying cairo_matrix_translate(matrix, x_offset, y_offset) and + * setting x_offset and y_offset to 0. + * + * If it is possible to represent the matrix with an identity + * %pixman_transform_t and a translation within the valid range for + * pixman, this function will set @out_transform to be the identity, + * @x_offset and @y_offset to be the translation vector and will + * return %CAIRO_INT_STATUS_NOTHING_TO_DO. Otherwise it will try to + * evenly divide the translational component of @matrix between + * @out_transform and (@x_offset, @y_offset). + * + * Upon return x_offset and y_offset contain the translation vector. + * + * Return value: %CAIRO_INT_STATUS_NOTHING_TO_DO if the out_transform + * is the identity, %CAIRO_STATUS_INVALID_MATRIX if it was not + * possible to represent @matrix as a pixman_transform_t without + * overflows, %CAIRO_STATUS_SUCCESS otherwise. + **/ +cairo_status_t +_cairo_matrix_to_pixman_matrix_offset (const cairo_matrix_t *matrix, + cairo_filter_t filter, + double xc, + double yc, + pixman_transform_t *out_transform, + int *x_offset, + int *y_offset) +{ + cairo_bool_t is_pixman_translation; + + is_pixman_translation = _cairo_matrix_is_pixman_translation (matrix, + filter, + x_offset, + y_offset); + + if (is_pixman_translation) { + *out_transform = pixman_identity_transform; + return CAIRO_INT_STATUS_NOTHING_TO_DO; + } else { + cairo_matrix_t m; + + m = *matrix; + cairo_matrix_translate (&m, *x_offset, *y_offset); + if (m.x0 != 0.0 || m.y0 != 0.0) { + double tx, ty, norm; + int i, j; + + /* pixman also limits the [xy]_offset to 16 bits so evenly + * spread the bits between the two. + * + * To do this, find the solutions of: + * |x| = |x*m.xx + y*m.xy + m.x0| + * |y| = |x*m.yx + y*m.yy + m.y0| + * + * and select the one whose maximum norm is smallest. + */ + tx = m.x0; + ty = m.y0; + norm = MAX (fabs (tx), fabs (ty)); + + for (i = -1; i < 2; i+=2) { + for (j = -1; j < 2; j+=2) { + double x, y, den, new_norm; + + den = (m.xx + i) * (m.yy + j) - m.xy * m.yx; + if (fabs (den) < DBL_EPSILON) + continue; + + x = m.y0 * m.xy - m.x0 * (m.yy + j); + y = m.x0 * m.yx - m.y0 * (m.xx + i); + + den = 1 / den; + x *= den; + y *= den; + + new_norm = MAX (fabs (x), fabs (y)); + if (norm > new_norm) { + norm = new_norm; + tx = x; + ty = y; + } + } + } + + tx = floor (tx); + ty = floor (ty); + *x_offset = -tx; + *y_offset = -ty; + cairo_matrix_translate (&m, tx, ty); + } else { + *x_offset = 0; + *y_offset = 0; + } + + return _cairo_matrix_to_pixman_matrix (&m, out_transform, xc, yc); + } +} diff --git a/local/recipes/libs/cairo/source/src/cairo-mempool-private.h b/local/recipes/libs/cairo/source/src/cairo-mempool-private.h new file mode 100644 index 0000000000..a09f6ce51f --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-mempool-private.h @@ -0,0 +1,85 @@ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2007 Chris Wilson + * Copyright © 2009 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributors(s): + * Chris Wilson + */ + +#ifndef CAIRO_MEMPOOL_PRIVATE_H +#define CAIRO_MEMPOOL_PRIVATE_H + +#include "cairo-compiler-private.h" +#include "cairo-error-private.h" + +#include /* for size_t */ + +CAIRO_BEGIN_DECLS + +typedef struct _cairo_mempool cairo_mempool_t; + +struct _cairo_mempool { + char *base; + struct _cairo_memblock { + int bits; + cairo_list_t link; + } *blocks; + cairo_list_t free[32]; + unsigned char *map; + + unsigned int num_blocks; + int min_bits; /* Minimum block size is 1 << min_bits */ + int num_sizes; + int max_free_bits; + + size_t free_bytes; + size_t max_bytes; +}; + +cairo_private cairo_status_t +_cairo_mempool_init (cairo_mempool_t *pool, + void *base, + size_t bytes, + int min_bits, + int num_sizes); + +cairo_private void * +_cairo_mempool_alloc (cairo_mempool_t *pi, size_t bytes); + +cairo_private void +_cairo_mempool_free (cairo_mempool_t *pi, void *storage); + +cairo_private void +_cairo_mempool_fini (cairo_mempool_t *pool); + +CAIRO_END_DECLS + +#endif /* CAIRO_MEMPOOL_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-mempool.c b/local/recipes/libs/cairo/source/src/cairo-mempool.c new file mode 100644 index 0000000000..6cebaf123a --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-mempool.c @@ -0,0 +1,369 @@ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2007 Chris Wilson + * Copyright © 2009 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipoolent may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributors(s): + * Chris Wilson + */ + +#include "cairoint.h" + +#include "cairo-mempool-private.h" +#include "cairo-list-inline.h" + +/* a simple buddy allocator for memory pools + * XXX fragmentation? use Doug Lea's malloc? + */ + +#define BITTEST(p, n) ((p)->map[(n) >> 3] & (128 >> ((n) & 7))) +#define BITSET(p, n) ((p)->map[(n) >> 3] |= (128 >> ((n) & 7))) +#define BITCLEAR(p, n) ((p)->map[(n) >> 3] &= ~(128 >> ((n) & 7))) + +static void +clear_bits (cairo_mempool_t *pool, size_t first, size_t last) +{ + size_t i, n = last; + size_t first_full = (first + 7) & ~7; + size_t past_full = last & ~7; + size_t bytes; + + if (n > first_full) + n = first_full; + for (i = first; i < n; i++) + BITCLEAR (pool, i); + + if (past_full > first_full) { + bytes = past_full - first_full; + bytes = bytes >> 3; + memset (pool->map + (first_full >> 3), 0, bytes); + } + + if (past_full < n) + past_full = n; + for (i = past_full; i < last; i++) + BITCLEAR (pool, i); +} + +static void +free_bits (cairo_mempool_t *pool, size_t start, int bits, cairo_bool_t clear) +{ + struct _cairo_memblock *block; + + if (clear) + clear_bits (pool, start, start + (((size_t) 1) << bits)); + + block = pool->blocks + start; + block->bits = bits; + + cairo_list_add (&block->link, &pool->free[bits]); + + pool->free_bytes += ((size_t) 1) << (bits + pool->min_bits); + if (bits > pool->max_free_bits) + pool->max_free_bits = bits; +} + +/* Add a chunk to the free list */ +static void +free_blocks (cairo_mempool_t *pool, + size_t first, + size_t last, + cairo_bool_t clear) +{ + size_t i, len; + int bits = 0; + + for (i = first, len = 1; i < last; i += len) { + /* To avoid cost quadratic in the number of different + * blocks produced from this chunk of store, we have to + * use the size of the previous block produced from this + * chunk as the starting point to work out the size of the + * next block we can produce. If you look at the binary + * representation of the starting points of the blocks + * produced, you can see that you first of all increase the + * size of the blocks produced up to some maximum as the + * address dealt with gets offsets added on which zap out + * low order bits, then decrease as the low order bits of the + * final block produced get added in. E.g. as you go from + * 001 to 0111 you generate blocks + * of size 001 at 001 taking you to 010 + * of size 010 at 010 taking you to 100 + * of size 010 at 100 taking you to 110 + * of size 001 at 110 taking you to 111 + * So the maximum total cost of the loops below this comment + * is one trip from the lowest blocksize to the highest and + * back again. + */ + while (bits < pool->num_sizes - 1) { + size_t next_bits = bits + 1; + size_t next_len = len << 1; + + if (i + next_bits > last) { + /* off end of chunk to be freed */ + break; + } + + if (i & (next_len - 1)) /* block would not be on boundary */ + break; + + bits = next_bits; + len = next_len; + } + + do { + if (i + len <= last && /* off end of chunk to be freed */ + (i & (len - 1)) == 0) /* block would not be on boundary */ + break; + + bits--; len >>=1; + } while (len); + + if (len == 0) + break; + + free_bits (pool, i, bits, clear); + } +} + +static struct _cairo_memblock * +get_buddy (cairo_mempool_t *pool, size_t offset, int bits) +{ + struct _cairo_memblock *block; + + if (offset + (((size_t) 1) << bits) >= pool->num_blocks) + return NULL; /* invalid */ + + if (BITTEST (pool, offset + (((size_t) 1) << bits) - 1)) + return NULL; /* buddy is allocated */ + + block = pool->blocks + offset; + if (block->bits != bits) + return NULL; /* buddy is partially allocated */ + + return block; +} + +static void +merge_buddies (cairo_mempool_t *pool, + struct _cairo_memblock *block, + int max_bits) +{ + size_t block_offset = block - pool->blocks; + int bits = block->bits; + + while (bits < max_bits - 1) { + /* while you can, merge two blocks and get a legal block size */ + size_t buddy_offset = block_offset ^ (((size_t) 1) << bits); + + block = get_buddy (pool, buddy_offset, bits); + if (block == NULL) + break; + + cairo_list_del (&block->link); + + /* Merged block starts at buddy */ + if (buddy_offset < block_offset) + block_offset = buddy_offset; + + bits++; + } + + block = pool->blocks + block_offset; + block->bits = bits; + cairo_list_add (&block->link, &pool->free[bits]); + + if (bits > pool->max_free_bits) + pool->max_free_bits = bits; +} + +/* attempt to merge all available buddies up to a particular size */ +static int +merge_bits (cairo_mempool_t *pool, int max_bits) +{ + struct _cairo_memblock *block, *buddy, *next; + int bits; + + for (bits = 0; bits < max_bits - 1; bits++) { + cairo_list_foreach_entry_safe (block, next, + struct _cairo_memblock, + &pool->free[bits], + link) + { + size_t buddy_offset = (block - pool->blocks) ^ (((size_t) 1) << bits); + + buddy = get_buddy (pool, buddy_offset, bits); + if (buddy == NULL) + continue; + + if (buddy == next) { + next = cairo_container_of (buddy->link.next, + struct _cairo_memblock, + link); + } + + cairo_list_del (&block->link); + merge_buddies (pool, block, max_bits); + } + } + + return pool->max_free_bits; +} + +/* find store for 1 << bits blocks */ +static void * +buddy_malloc (cairo_mempool_t *pool, int bits) +{ + size_t past, offset; + struct _cairo_memblock *block; + int b; + + if (bits > pool->max_free_bits && bits > merge_bits (pool, bits)) + return NULL; + + /* Find a list with blocks big enough on it */ + block = NULL; + for (b = bits; b <= pool->max_free_bits; b++) { + if (! cairo_list_is_empty (&pool->free[b])) { + block = cairo_list_first_entry (&pool->free[b], + struct _cairo_memblock, + link); + break; + } + } + assert (block != NULL); + + cairo_list_del (&block->link); + + while (cairo_list_is_empty (&pool->free[pool->max_free_bits])) { + if (--pool->max_free_bits == -1) + break; + } + + /* Mark end of allocated area */ + offset = block - pool->blocks; + past = offset + (((size_t) 1) << bits); + BITSET (pool, past - 1); + block->bits = bits; + + /* If we used a larger free block than we needed, free the rest */ + pool->free_bytes -= ((size_t) 1) << (b + pool->min_bits); + free_blocks (pool, past, offset + (((size_t) 1) << b), 0); + + return pool->base + ((block - pool->blocks) << pool->min_bits); +} + +cairo_status_t +_cairo_mempool_init (cairo_mempool_t *pool, + void *base, size_t bytes, + int min_bits, int num_sizes) +{ + uintptr_t tmp; + int num_blocks; + int i; + + /* Align the start to an integral chunk */ + tmp = ((uintptr_t) base) & ((((size_t) 1) << min_bits) - 1); + if (tmp) { + tmp = (((size_t) 1) << min_bits) - tmp; + base = (char *)base + tmp; + bytes -= tmp; + } + + assert ((((uintptr_t) base) & ((((size_t) 1) << min_bits) - 1)) == 0); + assert (num_sizes < ARRAY_LENGTH (pool->free)); + + pool->base = base; + pool->free_bytes = 0; + pool->max_bytes = bytes; + pool->max_free_bits = -1; + + num_blocks = bytes >> min_bits; + pool->blocks = _cairo_calloc_ab (num_blocks, sizeof (struct _cairo_memblock)); + if (pool->blocks == NULL) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + pool->num_blocks = num_blocks; + pool->min_bits = min_bits; + pool->num_sizes = num_sizes; + + for (i = 0; i < ARRAY_LENGTH (pool->free); i++) + cairo_list_init (&pool->free[i]); + + pool->map = _cairo_malloc ((num_blocks + 7) >> 3); + if (pool->map == NULL) { + free (pool->blocks); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + memset (pool->map, -1, (num_blocks + 7) >> 3); + clear_bits (pool, 0, num_blocks); + + /* Now add all blocks to the free list */ + free_blocks (pool, 0, num_blocks, 1); + + return CAIRO_STATUS_SUCCESS; +} + +void * +_cairo_mempool_alloc (cairo_mempool_t *pool, size_t bytes) +{ + size_t size; + int bits; + + size = ((size_t) 1) << pool->min_bits; + for (bits = 0; size < bytes; bits++) + size <<= 1; + if (bits >= pool->num_sizes) + return NULL; + + return buddy_malloc (pool, bits); +} + +void +_cairo_mempool_free (cairo_mempool_t *pool, void *storage) +{ + size_t block_offset; + struct _cairo_memblock *block; + + block_offset = ((char *)storage - pool->base) >> pool->min_bits; + block = pool->blocks + block_offset; + + BITCLEAR (pool, block_offset + ((((size_t) 1) << block->bits) - 1)); + pool->free_bytes += ((size_t) 1) << (block->bits + pool->min_bits); + + merge_buddies (pool, block, pool->num_sizes); +} + +void +_cairo_mempool_fini (cairo_mempool_t *pool) +{ + free (pool->map); + free (pool->blocks); +} diff --git a/local/recipes/libs/cairo/source/src/cairo-mesh-pattern-rasterizer.c b/local/recipes/libs/cairo/source/src/cairo-mesh-pattern-rasterizer.c new file mode 100644 index 0000000000..f47800c8ae --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-mesh-pattern-rasterizer.c @@ -0,0 +1,941 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright 2009 Andrea Canciani + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Andrea Canciani. + * + * Contributor(s): + * Andrea Canciani + */ + +#include "cairoint.h" + +#include "cairo-array-private.h" +#include "cairo-pattern-private.h" + +/* + * Rasterizer for mesh patterns. + * + * This implementation is based on techniques derived from several + * papers (available from ACM): + * + * - Lien, Shantz and Pratt "Adaptive Forward Differencing for + * Rendering Curves and Surfaces" (discussion of the AFD technique, + * bound of 1/sqrt(2) on step length without proof) + * + * - Popescu and Rosen, "Forward rasterization" (description of + * forward rasterization, proof of the previous bound) + * + * - Klassen, "Integer Forward Differencing of Cubic Polynomials: + * Analysis and Algorithms" + * + * - Klassen, "Exact Integer Hybrid Subdivision and Forward + * Differencing of Cubics" (improving the bound on the minimum + * number of steps) + * + * - Chang, Shantz and Rocchetti, "Rendering Cubic Curves and Surfaces + * with Integer Adaptive Forward Differencing" (analysis of forward + * differencing applied to Bezier patches) + * + * Notes: + * - Poor performance expected in degenerate cases + * + * - Patches mostly outside the drawing area are drawn completely (and + * clipped), wasting time + * + * - Both previous problems are greatly reduced by splitting until a + * reasonably small size and clipping the new tiles: execution time + * is quadratic in the convex-hull diameter instead than linear to + * the painted area. Splitting the tiles doesn't change the painted + * area but (usually) reduces the bounding box area (bbox area can + * remain the same after splitting, but cannot grow) + * + * - The initial implementation used adaptive forward differencing, + * but simple forward differencing scored better in benchmarks + * + * Idea: + * + * We do a sampling over the cubic patch with step du and dv (in the + * two parameters) that guarantees that any point of our sampling will + * be at most at 1/sqrt(2) from its adjacent points. In formulae + * (assuming B is the patch): + * + * |B(u,v) - B(u+du,v)| < 1/sqrt(2) + * |B(u,v) - B(u,v+dv)| < 1/sqrt(2) + * + * This means that every pixel covered by the patch will contain at + * least one of the samples, thus forward rasterization can be + * performed. Sketch of proof (from Popescu and Rosen): + * + * Let's take the P pixel we're interested into. If we assume it to be + * square, its boundaries define 9 regions on the plane: + * + * 1|2|3 + * -+-+- + * 8|P|4 + * -+-+- + * 7|6|5 + * + * Let's check that the pixel P will contain at least one point + * assuming that it is covered by the patch. + * + * Since the pixel is covered by the patch, its center will belong to + * (at least) one of the quads: + * + * {(B(u,v), B(u+du,v), B(u,v+dv), B(u+du,v+dv)) for u,v in [0,1]} + * + * If P doesn't contain any of the corners of the quad: + * + * - if one of the corners is in 1,3,5 or 7, other two of them have to + * be in 2,4,6 or 8, thus if the last corner is not in P, the length + * of one of the edges will be > 1/sqrt(2) + * + * - if none of the corners is in 1,3,5 or 7, all of them are in 2,4,6 + * and/or 8. If they are all in different regions, they can't + * satisfy the distance constraint. If two of them are in the same + * region (let's say 2), no point is in 6 and again it is impossible + * to have the center of P in the quad respecting the distance + * constraint (both these assertions can be checked by continuity + * considering the length of the edges of a quad with the vertices + * on the edges of P) + * + * Each of the cases led to a contradiction, so P contains at least + * one of the corners of the quad. + */ + +/* + * Make sure that errors are less than 1 in fixed point math if you + * change these values. + * + * The error is amplified by about steps^3/4 times. + * The rasterizer always uses a number of steps that is a power of 2. + * + * 256 is the maximum allowed number of steps (to have error < 1) + * using 8.24 for the differences. + */ +#define STEPS_MAX_V 256.0 +#define STEPS_MAX_U 256.0 + +/* + * If the patch/curve is only partially visible, split it to a finer + * resolution to get higher chances to clip (part of) it. + * + * These values have not been computed, but simply obtained + * empirically (by benchmarking some patches). They should never be + * greater than STEPS_MAX_V (or STEPS_MAX_U), but they can be as small + * as 1 (depending on how much you want to spend time in splitting the + * patch/curve when trying to save some rasterization time). + */ +#define STEPS_CLIP_V 64.0 +#define STEPS_CLIP_U 64.0 + + +/* Utils */ +static inline double +sqlen (cairo_point_double_t p0, cairo_point_double_t p1) +{ + cairo_point_double_t delta; + + delta.x = p0.x - p1.x; + delta.y = p0.y - p1.y; + + return delta.x * delta.x + delta.y * delta.y; +} + +static inline int16_t +_color_delta_to_shifted_short (int32_t from, int32_t to, int shift) +{ + int32_t delta = to - from; + + /* We need to round toward zero, because otherwise adding the + * delta 2^shift times can overflow */ + if (delta >= 0) + return delta >> shift; + else + return -((-delta) >> shift); +} + +/* + * Convert a number of steps to the equivalent shift. + * + * Input: the square of the minimum number of steps + * + * Output: the smallest integer x such that 2^x > steps + */ +static inline int +sqsteps2shift (double steps_sq) +{ + int r; + frexp (MAX (1.0, steps_sq), &r); + return (r + 1) >> 1; +} + +/* + * FD functions + * + * A Bezier curve is defined (with respect to a parameter t in + * [0,1]) from its nodes (x,y,z,w) like this: + * + * B(t) = x(1-t)^3 + 3yt(1-t)^2 + 3zt^2(1-t) + wt^3 + * + * To efficiently evaluate a Bezier curve, the rasterizer uses forward + * differences. Given x, y, z, w (the 4 nodes of the Bezier curve), it + * is possible to convert them to forward differences form and walk + * over the curve using fd_init (), fd_down () and fd_fwd (). + * + * f[0] is always the value of the Bezier curve for "current" t. + */ + +/* + * Initialize the coefficient for forward differences. + * + * Input: x,y,z,w are the 4 nodes of the Bezier curve + * + * Output: f[i] is the i-th difference of the curve + * + * f[0] is the value of the curve for t==0, i.e. f[0]==x. + * + * The initial step is 1; this means that each step increases t by 1 + * (so fd_init () immediately followed by fd_fwd (f) n times makes + * f[0] be the value of the curve for t==n). + */ +static inline void +fd_init (double x, double y, double z, double w, double f[4]) +{ + f[0] = x; + f[1] = w - x; + f[2] = 6. * (w - 2. * z + y); + f[3] = 6. * (w - 3. * z + 3. * y - x); +} + +/* + * Halve the step of the coefficients for forward differences. + * + * Input: f[i] is the i-th difference of the curve + * + * Output: f[i] is the i-th difference of the curve with half the + * original step + * + * f[0] is not affected, so the current t is not changed. + * + * The other coefficients are changed so that the step is half the + * original step. This means that doing fd_fwd (f) n times with the + * input f results in the same f[0] as doing fd_fwd (f) 2n times with + * the output f. + */ +static inline void +fd_down (double f[4]) +{ + f[3] *= 0.125; + f[2] = f[2] * 0.25 - f[3]; + f[1] = (f[1] - f[2]) * 0.5; +} + +/* + * Perform one step of forward differences along the curve. + * + * Input: f[i] is the i-th difference of the curve + * + * Output: f[i] is the i-th difference of the curve after one step + */ +static inline void +fd_fwd (double f[4]) +{ + f[0] += f[1]; + f[1] += f[2]; + f[2] += f[3]; +} + +/* + * Transform to integer forward differences. + * + * Input: d[n] is the n-th difference (in double precision) + * + * Output: i[n] is the n-th difference (in fixed point precision) + * + * i[0] is 9.23 fixed point, other differences are 4.28 fixed point. + */ +static inline void +fd_fixed (double d[4], int32_t i[4]) +{ + i[0] = _cairo_fixed_16_16_from_double (256 * 2 * d[0]); + i[1] = _cairo_fixed_16_16_from_double (256 * 16 * d[1]); + i[2] = _cairo_fixed_16_16_from_double (256 * 16 * d[2]); + i[3] = _cairo_fixed_16_16_from_double (256 * 16 * d[3]); +} + +/* + * Perform one step of integer forward differences along the curve. + * + * Input: f[n] is the n-th difference + * + * Output: f[n] is the n-th difference + * + * f[0] is 9.23 fixed point, other differences are 4.28 fixed point. + */ +static inline void +fd_fixed_fwd (int32_t f[4]) +{ + f[0] += (f[1] >> 5) + ((f[1] >> 4) & 1); + f[1] += f[2]; + f[2] += f[3]; +} + +/* + * Compute the minimum number of steps that guarantee that walking + * over a curve will leave no holes. + * + * Input: p[0..3] the nodes of the Bezier curve + * + * Returns: the square of the number of steps + * + * Idea: + * + * We want to make sure that at every step we move by less than + * 1/sqrt(2). + * + * The derivative of the cubic Bezier with nodes (p0, p1, p2, p3) is + * the quadratic Bezier with nodes (p1-p0, p2-p1, p3-p2) scaled by 3, + * so (since a Bezier curve is always bounded by its convex hull), we + * can say that: + * + * max(|B'(t)|) <= 3 max (|p1-p0|, |p2-p1|, |p3-p2|) + * + * We can improve this by noticing that a quadratic Bezier (a,b,c) is + * bounded by the quad (a,lerp(a,b,t),lerp(b,c,t),c) for any t, so + * (substituting the previous values, using t=0.5 and simplifying): + * + * max(|B'(t)|) <= 3 max (|p1-p0|, |p2-p0|/2, |p3-p1|/2, |p3-p2|) + * + * So, to guarantee a maximum step length of 1/sqrt(2) we must do: + * + * 3 max (|p1-p0|, |p2-p0|/2, |p3-p1|/2, |p3-p2|) sqrt(2) steps + */ +static inline double +bezier_steps_sq (cairo_point_double_t p[4]) +{ + double tmp = sqlen (p[0], p[1]); + tmp = MAX (tmp, sqlen (p[2], p[3])); + tmp = MAX (tmp, sqlen (p[0], p[2]) * .25); + tmp = MAX (tmp, sqlen (p[1], p[3]) * .25); + return 18.0 * tmp; +} + +/* + * Split a 1D Bezier cubic using de Casteljau's algorithm. + * + * Input: x,y,z,w the nodes of the Bezier curve + * + * Output: x0,y0,z0,w0 and x1,y1,z1,w1 are respectively the nodes of + * the first half and of the second half of the curve + * + * The output control nodes have to be distinct. + */ +static inline void +split_bezier_1D (double x, double y, double z, double w, + double *x0, double *y0, double *z0, double *w0, + double *x1, double *y1, double *z1, double *w1) +{ + double tmp; + + *x0 = x; + *w1 = w; + + tmp = 0.5 * (y + z); + *y0 = 0.5 * (x + y); + *z1 = 0.5 * (z + w); + + *z0 = 0.5 * (*y0 + tmp); + *y1 = 0.5 * (tmp + *z1); + + *w0 = *x1 = 0.5 * (*z0 + *y1); +} + +/* + * Split a Bezier curve using de Casteljau's algorithm. + * + * Input: p[0..3] the nodes of the Bezier curve + * + * Output: fst_half[0..3] and snd_half[0..3] are respectively the + * nodes of the first and of the second half of the curve + * + * fst_half and snd_half must be different, but they can be the same as + * nodes. + */ +static void +split_bezier (cairo_point_double_t p[4], + cairo_point_double_t fst_half[4], + cairo_point_double_t snd_half[4]) +{ + split_bezier_1D (p[0].x, p[1].x, p[2].x, p[3].x, + &fst_half[0].x, &fst_half[1].x, &fst_half[2].x, &fst_half[3].x, + &snd_half[0].x, &snd_half[1].x, &snd_half[2].x, &snd_half[3].x); + + split_bezier_1D (p[0].y, p[1].y, p[2].y, p[3].y, + &fst_half[0].y, &fst_half[1].y, &fst_half[2].y, &fst_half[3].y, + &snd_half[0].y, &snd_half[1].y, &snd_half[2].y, &snd_half[3].y); +} + + +typedef enum _intersection { + INSIDE = -1, /* the interval is entirely contained in the reference interval */ + OUTSIDE = 0, /* the interval has no intersection with the reference interval */ + PARTIAL = 1 /* the interval intersects the reference interval (but is not fully inside it) */ +} intersection_t; + +/* + * Check if an interval if inside another. + * + * Input: a,b are the extrema of the first interval + * c,d are the extrema of the second interval + * + * Returns: INSIDE iff [a,b) intersection [c,d) = [a,b) + * OUTSIDE iff [a,b) intersection [c,d) = {} + * PARTIAL otherwise + * + * The function assumes a < b and c < d + * + * Note: Bitwise-anding the results along each component gives the + * expected result for [a,b) x [A,B) intersection [c,d) x [C,D). + */ +static inline int +intersect_interval (double a, double b, double c, double d) +{ + if (c <= a && b <= d) + return INSIDE; + else if (a >= d || b <= c) + return OUTSIDE; + else + return PARTIAL; +} + +/* + * Set the color of a pixel. + * + * Input: data is the base pointer of the image + * width, height are the dimensions of the image + * stride is the stride in bytes between adjacent rows + * x, y are the coordinates of the pixel to be colored + * r,g,b,a are the color components of the color to be set + * + * Output: the (x,y) pixel in data has the (r,g,b,a) color + * + * The input color components are not premultiplied, but the data + * stored in the image is assumed to be in CAIRO_FORMAT_ARGB32 (8 bpc, + * premultiplied). + * + * If the pixel to be set is outside the image, this function does + * nothing. + */ +static inline void +draw_pixel (unsigned char *data, int width, int height, int stride, + int x, int y, uint16_t r, uint16_t g, uint16_t b, uint16_t a) +{ + if (likely (0 <= x && 0 <= y && x < width && y < height)) { + uint32_t tr, tg, tb, ta; + + /* Premultiply and round */ + ta = a; + tr = r * ta + 0x8000; + tg = g * ta + 0x8000; + tb = b * ta + 0x8000; + + tr += tr >> 16; + tg += tg >> 16; + tb += tb >> 16; + + *((uint32_t*) (data + y*(ptrdiff_t)stride + 4*x)) = ((ta << 16) & 0xff000000) | + ((tr >> 8) & 0xff0000) | ((tg >> 16) & 0xff00) | (tb >> 24); + } +} + +/* + * Forward-rasterize a cubic curve using forward differences. + * + * Input: data is the base pointer of the image + * width, height are the dimensions of the image + * stride is the stride in bytes between adjacent rows + * ushift is log2(n) if n is the number of desired steps + * dxu[i], dyu[i] are the x,y forward differences of the curve + * r0,g0,b0,a0 are the color components of the start point + * r3,g3,b3,a3 are the color components of the end point + * + * Output: data will be changed to have the requested curve drawn in + * the specified colors + * + * The input color components are not premultiplied, but the data + * stored in the image is assumed to be in CAIRO_FORMAT_ARGB32 (8 bpc, + * premultiplied). + * + * The function draws n+1 pixels, that is from the point at step 0 to + * the point at step n, both included. This is the discrete equivalent + * to drawing the curve for values of the interpolation parameter in + * [0,1] (including both extremes). + */ +static inline void +rasterize_bezier_curve (unsigned char *data, int width, int height, int stride, + int ushift, double dxu[4], double dyu[4], + uint16_t r0, uint16_t g0, uint16_t b0, uint16_t a0, + uint16_t r3, uint16_t g3, uint16_t b3, uint16_t a3) +{ + int32_t xu[4], yu[4]; + int x0, y0, u, usteps = 1 << ushift; + + uint16_t r = r0, g = g0, b = b0, a = a0; + int16_t dr = _color_delta_to_shifted_short (r0, r3, ushift); + int16_t dg = _color_delta_to_shifted_short (g0, g3, ushift); + int16_t db = _color_delta_to_shifted_short (b0, b3, ushift); + int16_t da = _color_delta_to_shifted_short (a0, a3, ushift); + + fd_fixed (dxu, xu); + fd_fixed (dyu, yu); + + /* + * Use (dxu[0],dyu[0]) as origin for the forward differences. + * + * This makes it possible to handle much larger coordinates (the + * ones that can be represented as cairo_fixed_t) + */ + x0 = _cairo_fixed_from_double (dxu[0]); + y0 = _cairo_fixed_from_double (dyu[0]); + xu[0] = 0; + yu[0] = 0; + + for (u = 0; u <= usteps; ++u) { + /* + * This rasterizer assumes that pixels are integer aligned + * squares, so a generic (x,y) point belongs to the pixel with + * top-left coordinates (floor(x), floor(y)) + */ + + int x = _cairo_fixed_integer_floor (x0 + (xu[0] >> 15) + ((xu[0] >> 14) & 1)); + int y = _cairo_fixed_integer_floor (y0 + (yu[0] >> 15) + ((yu[0] >> 14) & 1)); + + draw_pixel (data, width, height, stride, x, y, r, g, b, a); + + fd_fixed_fwd (xu); + fd_fixed_fwd (yu); + r += dr; + g += dg; + b += db; + a += da; + } +} + +/* + * Clip, split and rasterize a Bezier curve. + * + * Input: data is the base pointer of the image + * width, height are the dimensions of the image + * stride is the stride in bytes between adjacent rows + * p[i] is the i-th node of the Bezier curve + * c0[i] is the i-th color component at the start point + * c3[i] is the i-th color component at the end point + * + * Output: data will be changed to have the requested curve drawn in + * the specified colors + * + * The input color components are not premultiplied, but the data + * stored in the image is assumed to be in CAIRO_FORMAT_ARGB32 (8 bpc, + * premultiplied). + * + * The color components are red, green, blue and alpha, in this order. + * + * The function guarantees that it will draw the curve with a step + * small enough to never have a distance above 1/sqrt(2) between two + * consecutive points (which is needed to ensure that no hole can + * appear when using this function to rasterize a patch). + */ +static void +draw_bezier_curve (unsigned char *data, int width, int height, int stride, + cairo_point_double_t p[4], double c0[4], double c3[4]) +{ + double top, bottom, left, right, steps_sq; + int i, v; + + top = bottom = p[0].y; + for (i = 1; i < 4; ++i) { + top = MIN (top, p[i].y); + bottom = MAX (bottom, p[i].y); + } + + /* Check visibility */ + v = intersect_interval (top, bottom, 0, height); + if (v == OUTSIDE) + return; + + left = right = p[0].x; + for (i = 1; i < 4; ++i) { + left = MIN (left, p[i].x); + right = MAX (right, p[i].x); + } + + v &= intersect_interval (left, right, 0, width); + if (v == OUTSIDE) + return; + + steps_sq = bezier_steps_sq (p); + if (steps_sq >= (v == INSIDE ? STEPS_MAX_U * STEPS_MAX_U : STEPS_CLIP_U * STEPS_CLIP_U)) { + /* + * The number of steps is greater than the threshold. This + * means that either the error would become too big if we + * directly rasterized it or that we can probably save some + * time by splitting the curve and clipping part of it + */ + cairo_point_double_t first[4], second[4]; + double midc[4]; + split_bezier (p, first, second); + midc[0] = (c0[0] + c3[0]) * 0.5; + midc[1] = (c0[1] + c3[1]) * 0.5; + midc[2] = (c0[2] + c3[2]) * 0.5; + midc[3] = (c0[3] + c3[3]) * 0.5; + draw_bezier_curve (data, width, height, stride, first, c0, midc); + draw_bezier_curve (data, width, height, stride, second, midc, c3); + } else { + double xu[4], yu[4]; + int ushift = sqsteps2shift (steps_sq), k; + + fd_init (p[0].x, p[1].x, p[2].x, p[3].x, xu); + fd_init (p[0].y, p[1].y, p[2].y, p[3].y, yu); + + for (k = 0; k < ushift; ++k) { + fd_down (xu); + fd_down (yu); + } + + rasterize_bezier_curve (data, width, height, stride, ushift, + xu, yu, + _cairo_color_double_to_short (c0[0]), + _cairo_color_double_to_short (c0[1]), + _cairo_color_double_to_short (c0[2]), + _cairo_color_double_to_short (c0[3]), + _cairo_color_double_to_short (c3[0]), + _cairo_color_double_to_short (c3[1]), + _cairo_color_double_to_short (c3[2]), + _cairo_color_double_to_short (c3[3])); + + /* Draw the end point, to make sure that we didn't leave it + * out because of rounding */ + draw_pixel (data, width, height, stride, + _cairo_fixed_integer_floor (_cairo_fixed_from_double (p[3].x)), + _cairo_fixed_integer_floor (_cairo_fixed_from_double (p[3].y)), + _cairo_color_double_to_short (c3[0]), + _cairo_color_double_to_short (c3[1]), + _cairo_color_double_to_short (c3[2]), + _cairo_color_double_to_short (c3[3])); + } +} + +/* + * Forward-rasterize a cubic Bezier patch using forward differences. + * + * Input: data is the base pointer of the image + * width, height are the dimensions of the image + * stride is the stride in bytes between adjacent rows + * vshift is log2(n) if n is the number of desired steps + * p[i][j], p[i][j] are the nodes of the Bezier patch + * col[i][j] is the j-th color component of the i-th corner + * + * Output: data will be changed to have the requested patch drawn in + * the specified colors + * + * The nodes of the patch are as follows: + * + * u\v 0 - > 1 + * 0 p00 p01 p02 p03 + * | p10 p11 p12 p13 + * v p20 p21 p22 p23 + * 1 p30 p31 p32 p33 + * + * i.e. u varies along the first component (rows), v varies along the + * second one (columns). + * + * The color components are red, green, blue and alpha, in this order. + * c[0..3] are the colors in p00, p30, p03, p33 respectively + * + * The input color components are not premultiplied, but the data + * stored in the image is assumed to be in CAIRO_FORMAT_ARGB32 (8 bpc, + * premultiplied). + * + * If the patch folds over itself, the part with the highest v + * parameter is considered above. If both have the same v, the one + * with the highest u parameter is above. + * + * The function draws n+1 curves, that is from the curve at step 0 to + * the curve at step n, both included. This is the discrete equivalent + * to drawing the patch for values of the interpolation parameter in + * [0,1] (including both extremes). + */ +static inline void +rasterize_bezier_patch (unsigned char *data, int width, int height, int stride, int vshift, + cairo_point_double_t p[4][4], double col[4][4]) +{ + double pv[4][2][4], cstart[4], cend[4], dcstart[4], dcend[4]; + int v, i, k; + + v = 1 << vshift; + + /* + * pv[i][0] is the function (represented using forward + * differences) mapping v to the x coordinate of the i-th node of + * the Bezier curve with parameter u. + * (Likewise p[i][0] gives the y coordinate). + * + * This means that (pv[0][0][0],pv[0][1][0]), + * (pv[1][0][0],pv[1][1][0]), (pv[2][0][0],pv[2][1][0]) and + * (pv[3][0][0],pv[3][1][0]) are the nodes of the Bezier curve for + * the "current" v value (see the FD comments for more details). + */ + for (i = 0; i < 4; ++i) { + fd_init (p[i][0].x, p[i][1].x, p[i][2].x, p[i][3].x, pv[i][0]); + fd_init (p[i][0].y, p[i][1].y, p[i][2].y, p[i][3].y, pv[i][1]); + for (k = 0; k < vshift; ++k) { + fd_down (pv[i][0]); + fd_down (pv[i][1]); + } + } + + for (i = 0; i < 4; ++i) { + cstart[i] = col[0][i]; + cend[i] = col[1][i]; + dcstart[i] = (col[2][i] - col[0][i]) / v; + dcend[i] = (col[3][i] - col[1][i]) / v; + } + + v++; + while (v--) { + cairo_point_double_t nodes[4]; + for (i = 0; i < 4; ++i) { + nodes[i].x = pv[i][0][0]; + nodes[i].y = pv[i][1][0]; + } + + draw_bezier_curve (data, width, height, stride, nodes, cstart, cend); + + for (i = 0; i < 4; ++i) { + fd_fwd (pv[i][0]); + fd_fwd (pv[i][1]); + cstart[i] += dcstart[i]; + cend[i] += dcend[i]; + } + } +} + +/* + * Clip, split and rasterize a Bezier cubic patch. + * + * Input: data is the base pointer of the image + * width, height are the dimensions of the image + * stride is the stride in bytes between adjacent rows + * p[i][j], p[i][j] are the nodes of the patch + * col[i][j] is the j-th color component of the i-th corner + * + * Output: data will be changed to have the requested patch drawn in + * the specified colors + * + * The nodes of the patch are as follows: + * + * u\v 0 - > 1 + * 0 p00 p01 p02 p03 + * | p10 p11 p12 p13 + * v p20 p21 p22 p23 + * 1 p30 p31 p32 p33 + * + * i.e. u varies along the first component (rows), v varies along the + * second one (columns). + * + * The color components are red, green, blue and alpha, in this order. + * c[0..3] are the colors in p00, p30, p03, p33 respectively + * + * The input color components are not premultiplied, but the data + * stored in the image is assumed to be in CAIRO_FORMAT_ARGB32 (8 bpc, + * premultiplied). + * + * If the patch folds over itself, the part with the highest v + * parameter is considered above. If both have the same v, the one + * with the highest u parameter is above. + * + * The function guarantees that it will draw the patch with a step + * small enough to never have a distance above 1/sqrt(2) between two + * adjacent points (which guarantees that no hole can appear). + * + * This function can be used to rasterize a tile of PDF type 7 + * shadings (see http://www.adobe.com/devnet/pdf/pdf_reference.html). + */ +static void +draw_bezier_patch (unsigned char *data, int width, int height, int stride, + cairo_point_double_t p[4][4], double c[4][4]) +{ + double top, bottom, left, right, steps_sq; + int i, j, v; + + top = bottom = p[0][0].y; + for (i = 0; i < 4; ++i) { + for (j= 0; j < 4; ++j) { + top = MIN (top, p[i][j].y); + bottom = MAX (bottom, p[i][j].y); + } + } + + v = intersect_interval (top, bottom, 0, height); + if (v == OUTSIDE) + return; + + left = right = p[0][0].x; + for (i = 0; i < 4; ++i) { + for (j= 0; j < 4; ++j) { + left = MIN (left, p[i][j].x); + right = MAX (right, p[i][j].x); + } + } + + v &= intersect_interval (left, right, 0, width); + if (v == OUTSIDE) + return; + + steps_sq = 0; + for (i = 0; i < 4; ++i) + steps_sq = MAX (steps_sq, bezier_steps_sq (p[i])); + + if (steps_sq >= (v == INSIDE ? STEPS_MAX_V * STEPS_MAX_V : STEPS_CLIP_V * STEPS_CLIP_V)) { + /* The number of steps is greater than the threshold. This + * means that either the error would become too big if we + * directly rasterized it or that we can probably save some + * time by splitting the curve and clipping part of it. The + * patch is only split in the v direction to guarantee that + * rasterizing each part will overwrite parts with low v with + * overlapping parts with higher v. */ + + cairo_point_double_t first[4][4], second[4][4]; + double subc[4][4]; + + for (i = 0; i < 4; ++i) + split_bezier (p[i], first[i], second[i]); + + for (i = 0; i < 4; ++i) { + subc[0][i] = c[0][i]; + subc[1][i] = c[1][i]; + subc[2][i] = 0.5 * (c[0][i] + c[2][i]); + subc[3][i] = 0.5 * (c[1][i] + c[3][i]); + } + + draw_bezier_patch (data, width, height, stride, first, subc); + + for (i = 0; i < 4; ++i) { + subc[0][i] = subc[2][i]; + subc[1][i] = subc[3][i]; + subc[2][i] = c[2][i]; + subc[3][i] = c[3][i]; + } + draw_bezier_patch (data, width, height, stride, second, subc); + } else { + rasterize_bezier_patch (data, width, height, stride, sqsteps2shift (steps_sq), p, c); + } +} + +/* + * Draw a tensor product shading pattern. + * + * Input: mesh is the mesh pattern + * data is the base pointer of the image + * width, height are the dimensions of the image + * stride is the stride in bytes between adjacent rows + * + * Output: data will be changed to have the pattern drawn on it + * + * data is assumed to be clear and its content is assumed to be in + * CAIRO_FORMAT_ARGB32 (8 bpc, premultiplied). + * + * This function can be used to rasterize a PDF type 7 shading (see + * http://www.adobe.com/devnet/pdf/pdf_reference.html). + */ +void +_cairo_mesh_pattern_rasterize (const cairo_mesh_pattern_t *mesh, + void *data, + int width, + int height, + int stride, + double x_offset, + double y_offset) +{ + cairo_point_double_t nodes[4][4]; + double colors[4][4]; + cairo_matrix_t p2u; + unsigned int i, j, k, n; + cairo_status_t status; + const cairo_mesh_patch_t *patch; + const cairo_color_t *c; + + assert (mesh->base.status == CAIRO_STATUS_SUCCESS); + assert (mesh->current_patch == NULL); + + p2u = mesh->base.matrix; + status = cairo_matrix_invert (&p2u); + assert (status == CAIRO_STATUS_SUCCESS); + + n = _cairo_array_num_elements (&mesh->patches); + patch = _cairo_array_index_const (&mesh->patches, 0); + for (i = 0; i < n; i++) { + for (j = 0; j < 4; j++) { + for (k = 0; k < 4; k++) { + nodes[j][k] = patch->points[j][k]; + cairo_matrix_transform_point (&p2u, &nodes[j][k].x, &nodes[j][k].y); + nodes[j][k].x += x_offset; + nodes[j][k].y += y_offset; + } + } + + c = &patch->colors[0]; + colors[0][0] = c->red; + colors[0][1] = c->green; + colors[0][2] = c->blue; + colors[0][3] = c->alpha; + + c = &patch->colors[3]; + colors[1][0] = c->red; + colors[1][1] = c->green; + colors[1][2] = c->blue; + colors[1][3] = c->alpha; + + c = &patch->colors[1]; + colors[2][0] = c->red; + colors[2][1] = c->green; + colors[2][2] = c->blue; + colors[2][3] = c->alpha; + + c = &patch->colors[2]; + colors[3][0] = c->red; + colors[3][1] = c->green; + colors[3][2] = c->blue; + colors[3][3] = c->alpha; + + draw_bezier_patch (data, width, height, stride, nodes, colors); + patch++; + } +} diff --git a/local/recipes/libs/cairo/source/src/cairo-misc.c b/local/recipes/libs/cairo/source/src/cairo-misc.c new file mode 100644 index 0000000000..59cf76fc92 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-misc.c @@ -0,0 +1,1214 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2007 Adrian Johnson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Adrian Johnson + */ + +#include "cairoint.h" +#include "cairo-error-private.h" + +#include +#include +#include +#include +#ifdef HAVE_XLOCALE_H +#include +#endif +#if HAVE_FCNTL_H +#include +#endif + +COMPILE_TIME_ASSERT ((int)CAIRO_STATUS_LAST_STATUS < (int)CAIRO_INT_STATUS_UNSUPPORTED); +COMPILE_TIME_ASSERT (CAIRO_INT_STATUS_LAST_STATUS <= 127); + +/** + * SECTION:cairo-status + * @Title: Error handling + * @Short_Description: Decoding cairo's status + * @See_Also: cairo_status(), cairo_surface_status(), cairo_pattern_status(), + * cairo_font_face_status(), cairo_scaled_font_status(), + * cairo_region_status() + * + * Cairo uses a single status type to represent all kinds of errors. A status + * value of %CAIRO_STATUS_SUCCESS represents no error and has an integer value + * of zero. All other status values represent an error. + * + * Cairo's error handling is designed to be easy to use and safe. All major + * cairo objects retain an error status internally which + * can be queried anytime by the users using cairo*_status() calls. In + * the mean time, it is safe to call all cairo functions normally even if the + * underlying object is in an error status. This means that no error handling + * code is required before or after each individual cairo function call. + **/ + +/* Public stuff */ + +/** + * cairo_status_to_string: + * @status: a cairo status + * + * Provides a human-readable description of a #cairo_status_t. + * + * Returns: a string representation of the status + * + * Since: 1.0 + **/ +const char * +cairo_status_to_string (cairo_status_t status) +{ + switch (status) { + case CAIRO_STATUS_SUCCESS: + return "no error has occurred"; + case CAIRO_STATUS_NO_MEMORY: + return "out of memory"; + case CAIRO_STATUS_INVALID_RESTORE: + return "cairo_restore() without matching cairo_save()"; + case CAIRO_STATUS_INVALID_POP_GROUP: + return "no saved group to pop, i.e. cairo_pop_group() without matching cairo_push_group()"; + case CAIRO_STATUS_NO_CURRENT_POINT: + return "no current point defined"; + case CAIRO_STATUS_INVALID_MATRIX: + return "invalid matrix (not invertible)"; + case CAIRO_STATUS_INVALID_STATUS: + return "invalid value for an input cairo_status_t"; + case CAIRO_STATUS_NULL_POINTER: + return "NULL pointer"; + case CAIRO_STATUS_INVALID_STRING: + return "input string not valid UTF-8"; + case CAIRO_STATUS_INVALID_PATH_DATA: + return "input path data not valid"; + case CAIRO_STATUS_READ_ERROR: + return "error while reading from input stream"; + case CAIRO_STATUS_WRITE_ERROR: + return "error while writing to output stream"; + case CAIRO_STATUS_SURFACE_FINISHED: + return "the target surface has been finished"; + case CAIRO_STATUS_SURFACE_TYPE_MISMATCH: + return "the surface type is not appropriate for the operation"; + case CAIRO_STATUS_PATTERN_TYPE_MISMATCH: + return "the pattern type is not appropriate for the operation"; + case CAIRO_STATUS_INVALID_CONTENT: + return "invalid value for an input cairo_content_t"; + case CAIRO_STATUS_INVALID_FORMAT: + return "invalid value for an input cairo_format_t"; + case CAIRO_STATUS_INVALID_VISUAL: + return "invalid value for an input Visual*"; + case CAIRO_STATUS_FILE_NOT_FOUND: + return "file not found"; + case CAIRO_STATUS_INVALID_DASH: + return "invalid value for a dash setting"; + case CAIRO_STATUS_INVALID_DSC_COMMENT: + return "invalid value for a DSC comment"; + case CAIRO_STATUS_INVALID_INDEX: + return "invalid index passed to getter"; + case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE: + return "clip region not representable in desired format"; + case CAIRO_STATUS_TEMP_FILE_ERROR: + return "error creating or writing to a temporary file"; + case CAIRO_STATUS_INVALID_STRIDE: + return "invalid value for stride"; + case CAIRO_STATUS_FONT_TYPE_MISMATCH: + return "the font type is not appropriate for the operation"; + case CAIRO_STATUS_USER_FONT_IMMUTABLE: + return "the user-font is immutable"; + case CAIRO_STATUS_USER_FONT_ERROR: + return "error occurred in a user-font callback function"; + case CAIRO_STATUS_NEGATIVE_COUNT: + return "negative number used where it is not allowed"; + case CAIRO_STATUS_INVALID_CLUSTERS: + return "input clusters do not represent the accompanying text and glyph arrays"; + case CAIRO_STATUS_INVALID_SLANT: + return "invalid value for an input cairo_font_slant_t"; + case CAIRO_STATUS_INVALID_WEIGHT: + return "invalid value for an input cairo_font_weight_t"; + case CAIRO_STATUS_INVALID_SIZE: + return "invalid value (typically too big) for the size of the input (surface, pattern, etc.)"; + case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED: + return "user-font method not implemented"; + case CAIRO_STATUS_DEVICE_TYPE_MISMATCH: + return "the device type is not appropriate for the operation"; + case CAIRO_STATUS_DEVICE_ERROR: + return "an operation to the device caused an unspecified error"; + case CAIRO_STATUS_INVALID_MESH_CONSTRUCTION: + return "invalid operation during mesh pattern construction"; + case CAIRO_STATUS_DEVICE_FINISHED: + return "the target device has been finished"; + case CAIRO_STATUS_JBIG2_GLOBAL_MISSING: + return "CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID used but no CAIRO_MIME_TYPE_JBIG2_GLOBAL data provided"; + case CAIRO_STATUS_PNG_ERROR: + return "error occurred in libpng while reading from or writing to a PNG file"; + case CAIRO_STATUS_FREETYPE_ERROR: + return "error occurred in libfreetype"; + case CAIRO_STATUS_WIN32_GDI_ERROR: + return "error occurred in the Windows Graphics Device Interface"; + case CAIRO_STATUS_TAG_ERROR: + return "invalid tag name, attributes, or nesting"; + case CAIRO_STATUS_DWRITE_ERROR: + return "Window Direct Write error"; + case CAIRO_STATUS_SVG_FONT_ERROR: + return "error occured while rendering an OpenType-SVG font"; + default: + case CAIRO_STATUS_LAST_STATUS: + return ""; + } +} + +/** + * cairo_glyph_allocate: + * @num_glyphs: number of glyphs to allocate + * + * Allocates an array of #cairo_glyph_t's. + * This function is only useful in implementations of + * #cairo_user_scaled_font_text_to_glyphs_func_t where the user + * needs to allocate an array of glyphs that cairo will free. + * For all other uses, user can use their own allocation method + * for glyphs. + * + * This function returns %NULL if @num_glyphs is not positive, + * or if out of memory. That means, the %NULL return value + * signals out-of-memory only if @num_glyphs was positive. + * + * Returns: the newly allocated array of glyphs that should be + * freed using cairo_glyph_free() + * + * Since: 1.8 + **/ +cairo_glyph_t * +cairo_glyph_allocate (int num_glyphs) +{ + if (num_glyphs <= 0) + return NULL; + + return _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); +} + +/** + * cairo_glyph_free: + * @glyphs: array of glyphs to free, or %NULL + * + * Frees an array of #cairo_glyph_t's allocated using cairo_glyph_allocate(). + * This function is only useful to free glyph array returned + * by cairo_scaled_font_text_to_glyphs() where cairo returns + * an array of glyphs that the user will free. + * For all other uses, user can use their own allocation method + * for glyphs. + * + * Since: 1.8 + **/ +void +cairo_glyph_free (cairo_glyph_t *glyphs) +{ + free (glyphs); +} + +/** + * cairo_text_cluster_allocate: + * @num_clusters: number of text_clusters to allocate + * + * Allocates an array of #cairo_text_cluster_t's. + * This function is only useful in implementations of + * #cairo_user_scaled_font_text_to_glyphs_func_t where the user + * needs to allocate an array of text clusters that cairo will free. + * For all other uses, user can use their own allocation method + * for text clusters. + * + * This function returns %NULL if @num_clusters is not positive, + * or if out of memory. That means, the %NULL return value + * signals out-of-memory only if @num_clusters was positive. + * + * Returns: the newly allocated array of text clusters that should be + * freed using cairo_text_cluster_free() + * + * Since: 1.8 + **/ +cairo_text_cluster_t * +cairo_text_cluster_allocate (int num_clusters) +{ + if (num_clusters <= 0) + return NULL; + + return _cairo_malloc_ab (num_clusters, sizeof (cairo_text_cluster_t)); +} + +/** + * cairo_text_cluster_free: + * @clusters: array of text clusters to free, or %NULL + * + * Frees an array of #cairo_text_cluster's allocated using cairo_text_cluster_allocate(). + * This function is only useful to free text cluster array returned + * by cairo_scaled_font_text_to_glyphs() where cairo returns + * an array of text clusters that the user will free. + * For all other uses, user can use their own allocation method + * for text clusters. + * + * Since: 1.8 + **/ +void +cairo_text_cluster_free (cairo_text_cluster_t *clusters) +{ + free (clusters); +} + +/* Private stuff */ + +/** + * _cairo_validate_text_clusters: + * @utf8: UTF-8 text + * @utf8_len: length of @utf8 in bytes + * @glyphs: array of glyphs + * @num_glyphs: number of glyphs + * @clusters: array of cluster mapping information + * @num_clusters: number of clusters in the mapping + * @cluster_flags: cluster flags + * + * Check that clusters cover the entire glyphs and utf8 arrays, + * and that cluster boundaries are UTF-8 boundaries. + * + * Return value: %CAIRO_STATUS_SUCCESS upon success, or + * %CAIRO_STATUS_INVALID_CLUSTERS on error. + * The error is either invalid UTF-8 input, + * or bad cluster mapping. + **/ +cairo_status_t +_cairo_validate_text_clusters (const char *utf8, + int utf8_len, + const cairo_glyph_t *glyphs, + int num_glyphs, + const cairo_text_cluster_t *clusters, + int num_clusters, + cairo_text_cluster_flags_t cluster_flags) +{ + cairo_status_t status; + unsigned int n_bytes = 0; + unsigned int n_glyphs = 0; + int i; + + for (i = 0; i < num_clusters; i++) { + int cluster_bytes = clusters[i].num_bytes; + int cluster_glyphs = clusters[i].num_glyphs; + + if (cluster_bytes < 0 || cluster_glyphs < 0) + goto BAD; + + /* A cluster should cover at least one character or glyph. + * I can't see any use for a 0,0 cluster. + * I can't see an immediate use for a zero-text cluster + * right now either, but they don't harm. + * Zero-glyph clusters on the other hand are useful for + * things like U+200C ZERO WIDTH NON-JOINER */ + if (cluster_bytes == 0 && cluster_glyphs == 0) + goto BAD; + + /* Since n_bytes and n_glyphs are unsigned, but the rest of + * values involved are signed, we can detect overflow easily */ + if (n_bytes+cluster_bytes > (unsigned int)utf8_len || n_glyphs+cluster_glyphs > (unsigned int)num_glyphs) + goto BAD; + + /* Make sure we've got valid UTF-8 for the cluster */ + status = _cairo_utf8_to_ucs4 (utf8+n_bytes, cluster_bytes, NULL, NULL); + if (unlikely (status)) + return _cairo_error (CAIRO_STATUS_INVALID_CLUSTERS); + + n_bytes += cluster_bytes ; + n_glyphs += cluster_glyphs; + } + + if (n_bytes != (unsigned int) utf8_len || n_glyphs != (unsigned int) num_glyphs) { + BAD: + return _cairo_error (CAIRO_STATUS_INVALID_CLUSTERS); + } + + return CAIRO_STATUS_SUCCESS; +} + +/** + * _cairo_operator_bounded_by_mask: + * @op: a #cairo_operator_t + * + * A bounded operator is one where mask pixel + * of zero results in no effect on the destination image. + * + * Unbounded operators often require special handling; if you, for + * example, draw trapezoids with an unbounded operator, the effect + * extends past the bounding box of the trapezoids. + * + * Return value: %TRUE if the operator is bounded by the mask operand + **/ +cairo_bool_t +_cairo_operator_bounded_by_mask (cairo_operator_t op) +{ + switch (op) { + case CAIRO_OPERATOR_CLEAR: + case CAIRO_OPERATOR_SOURCE: + case CAIRO_OPERATOR_OVER: + case CAIRO_OPERATOR_ATOP: + case CAIRO_OPERATOR_DEST: + case CAIRO_OPERATOR_DEST_OVER: + case CAIRO_OPERATOR_DEST_OUT: + case CAIRO_OPERATOR_XOR: + case CAIRO_OPERATOR_ADD: + case CAIRO_OPERATOR_SATURATE: + case CAIRO_OPERATOR_MULTIPLY: + case CAIRO_OPERATOR_SCREEN: + case CAIRO_OPERATOR_OVERLAY: + case CAIRO_OPERATOR_DARKEN: + case CAIRO_OPERATOR_LIGHTEN: + case CAIRO_OPERATOR_COLOR_DODGE: + case CAIRO_OPERATOR_COLOR_BURN: + case CAIRO_OPERATOR_HARD_LIGHT: + case CAIRO_OPERATOR_SOFT_LIGHT: + case CAIRO_OPERATOR_DIFFERENCE: + case CAIRO_OPERATOR_EXCLUSION: + case CAIRO_OPERATOR_HSL_HUE: + case CAIRO_OPERATOR_HSL_SATURATION: + case CAIRO_OPERATOR_HSL_COLOR: + case CAIRO_OPERATOR_HSL_LUMINOSITY: + return TRUE; + case CAIRO_OPERATOR_OUT: + case CAIRO_OPERATOR_IN: + case CAIRO_OPERATOR_DEST_IN: + case CAIRO_OPERATOR_DEST_ATOP: + return FALSE; + default: + ASSERT_NOT_REACHED; + return FALSE; /* squelch warning */ + } +} + +/** + * _cairo_operator_bounded_by_source: + * @op: a #cairo_operator_t + * + * A bounded operator is one where source pixels of zero + * (in all four components, r, g, b and a) effect no change + * in the resulting destination image. + * + * Unbounded operators often require special handling; if you, for + * example, copy a surface with the SOURCE operator, the effect + * extends past the bounding box of the source surface. + * + * Return value: %TRUE if the operator is bounded by the source operand + **/ +cairo_bool_t +_cairo_operator_bounded_by_source (cairo_operator_t op) +{ + switch (op) { + case CAIRO_OPERATOR_OVER: + case CAIRO_OPERATOR_ATOP: + case CAIRO_OPERATOR_DEST: + case CAIRO_OPERATOR_DEST_OVER: + case CAIRO_OPERATOR_DEST_OUT: + case CAIRO_OPERATOR_XOR: + case CAIRO_OPERATOR_ADD: + case CAIRO_OPERATOR_SATURATE: + case CAIRO_OPERATOR_MULTIPLY: + case CAIRO_OPERATOR_SCREEN: + case CAIRO_OPERATOR_OVERLAY: + case CAIRO_OPERATOR_DARKEN: + case CAIRO_OPERATOR_LIGHTEN: + case CAIRO_OPERATOR_COLOR_DODGE: + case CAIRO_OPERATOR_COLOR_BURN: + case CAIRO_OPERATOR_HARD_LIGHT: + case CAIRO_OPERATOR_SOFT_LIGHT: + case CAIRO_OPERATOR_DIFFERENCE: + case CAIRO_OPERATOR_EXCLUSION: + case CAIRO_OPERATOR_HSL_HUE: + case CAIRO_OPERATOR_HSL_SATURATION: + case CAIRO_OPERATOR_HSL_COLOR: + case CAIRO_OPERATOR_HSL_LUMINOSITY: + return TRUE; + case CAIRO_OPERATOR_CLEAR: + case CAIRO_OPERATOR_SOURCE: + case CAIRO_OPERATOR_OUT: + case CAIRO_OPERATOR_IN: + case CAIRO_OPERATOR_DEST_IN: + case CAIRO_OPERATOR_DEST_ATOP: + return FALSE; + default: + ASSERT_NOT_REACHED; + return FALSE; /* squelch warning */ + } +} + +uint32_t +_cairo_operator_bounded_by_either (cairo_operator_t op) +{ + switch (op) { + case CAIRO_OPERATOR_OVER: + case CAIRO_OPERATOR_ATOP: + case CAIRO_OPERATOR_DEST: + case CAIRO_OPERATOR_DEST_OVER: + case CAIRO_OPERATOR_DEST_OUT: + case CAIRO_OPERATOR_XOR: + case CAIRO_OPERATOR_ADD: + case CAIRO_OPERATOR_SATURATE: + case CAIRO_OPERATOR_MULTIPLY: + case CAIRO_OPERATOR_SCREEN: + case CAIRO_OPERATOR_OVERLAY: + case CAIRO_OPERATOR_DARKEN: + case CAIRO_OPERATOR_LIGHTEN: + case CAIRO_OPERATOR_COLOR_DODGE: + case CAIRO_OPERATOR_COLOR_BURN: + case CAIRO_OPERATOR_HARD_LIGHT: + case CAIRO_OPERATOR_SOFT_LIGHT: + case CAIRO_OPERATOR_DIFFERENCE: + case CAIRO_OPERATOR_EXCLUSION: + case CAIRO_OPERATOR_HSL_HUE: + case CAIRO_OPERATOR_HSL_SATURATION: + case CAIRO_OPERATOR_HSL_COLOR: + case CAIRO_OPERATOR_HSL_LUMINOSITY: + return CAIRO_OPERATOR_BOUND_BY_MASK | CAIRO_OPERATOR_BOUND_BY_SOURCE; + case CAIRO_OPERATOR_CLEAR: + case CAIRO_OPERATOR_SOURCE: + return CAIRO_OPERATOR_BOUND_BY_MASK; + case CAIRO_OPERATOR_OUT: + case CAIRO_OPERATOR_IN: + case CAIRO_OPERATOR_DEST_IN: + case CAIRO_OPERATOR_DEST_ATOP: + return 0; + default: + ASSERT_NOT_REACHED; + return FALSE; /* squelch warning */ + } + +} + +#if DISABLE_SOME_FLOATING_POINT +/* This function is identical to the C99 function lround(), except that it + * performs arithmetic rounding (floor(d + .5) instead of away-from-zero rounding) and + * has a valid input range of (INT_MIN, INT_MAX] instead of + * [INT_MIN, INT_MAX]. It is much faster on both x86 and FPU-less systems + * than other commonly used methods for rounding (lround, round, rint, lrint + * or float (d + 0.5)). + * + * The reason why this function is much faster on x86 than other + * methods is due to the fact that it avoids the fldcw instruction. + * This instruction incurs a large performance penalty on modern Intel + * processors due to how it prevents efficient instruction pipelining. + * + * The reason why this function is much faster on FPU-less systems is for + * an entirely different reason. All common rounding methods involve multiple + * floating-point operations. Each one of these operations has to be + * emulated in software, which adds up to be a large performance penalty. + * This function doesn't perform any floating-point calculations, and thus + * avoids this penalty. + */ +int +_cairo_lround (double d) +{ + uint32_t top, shift_amount, output; + union { + double d; + uint64_t ui64; + uint32_t ui32[2]; + } u; + + u.d = d; + + /* If the integer word order doesn't match the float word order, we swap + * the words of the input double. This is needed because we will be + * treating the whole double as a 64-bit unsigned integer. Notice that we + * use WORDS_BIGENDIAN to detect the integer word order, which isn't + * exactly correct because WORDS_BIGENDIAN refers to byte order, not word + * order. Thus, we are making the assumption that the byte order is the + * same as the integer word order which, on the modern machines that we + * care about, is OK. + */ +#if ( defined(FLOAT_WORDS_BIGENDIAN) && !defined(WORDS_BIGENDIAN)) || \ + (!defined(FLOAT_WORDS_BIGENDIAN) && defined(WORDS_BIGENDIAN)) + { + uint32_t temp = u.ui32[0]; + u.ui32[0] = u.ui32[1]; + u.ui32[1] = temp; + } +#endif + +#ifdef WORDS_BIGENDIAN + #define MSW (0) /* Most Significant Word */ + #define LSW (1) /* Least Significant Word */ +#else + #define MSW (1) + #define LSW (0) +#endif + + /* By shifting the most significant word of the input double to the + * right 20 places, we get the very "top" of the double where the exponent + * and sign bit lie. + */ + top = u.ui32[MSW] >> 20; + + /* Here, we calculate how much we have to shift the mantissa to normalize + * it to an integer value. We extract the exponent "top" by masking out the + * sign bit, then we calculate the shift amount by subtracting the exponent + * from the bias. Notice that the correct bias for 64-bit doubles is + * actually 1075, but we use 1053 instead for two reasons: + * + * 1) To perform rounding later on, we will first need the target + * value in a 31.1 fixed-point format. Thus, the bias needs to be one + * less: (1075 - 1: 1074). + * + * 2) To avoid shifting the mantissa as a full 64-bit integer (which is + * costly on certain architectures), we break the shift into two parts. + * First, the upper and lower parts of the mantissa are shifted + * individually by a constant amount that all valid inputs will require + * at the very least. This amount is chosen to be 21, because this will + * allow the two parts of the mantissa to later be combined into a + * single 32-bit representation, on which the remainder of the shift + * will be performed. Thus, we decrease the bias by an additional 21: + * (1074 - 21: 1053). + */ + shift_amount = 1053 - (top & 0x7FF); + + /* We are done with the exponent portion in "top", so here we shift it off + * the end. + */ + top >>= 11; + + /* Before we perform any operations on the mantissa, we need to OR in + * the implicit 1 at the top (see the IEEE-754 spec). We needn't mask + * off the sign bit nor the exponent bits because these higher bits won't + * make a bit of difference in the rest of our calculations. + */ + u.ui32[MSW] |= 0x100000; + + /* If the input double is negative, we have to decrease the mantissa + * by a hair. This is an important part of performing arithmetic rounding, + * as negative numbers must round towards positive infinity in the + * halfwase case of -x.5. Since "top" contains only the sign bit at this + * point, we can just decrease the mantissa by the value of "top". + */ + u.ui64 -= top; + + /* By decrementing "top", we create a bitmask with a value of either + * 0x0 (if the input was negative) or 0xFFFFFFFF (if the input was positive + * and thus the unsigned subtraction underflowed) that we'll use later. + */ + top--; + + /* Here, we shift the mantissa by the constant value as described above. + * We can emulate a 64-bit shift right by 21 through shifting the top 32 + * bits left 11 places and ORing in the bottom 32 bits shifted 21 places + * to the right. Both parts of the mantissa are now packed into a single + * 32-bit integer. Although we severely truncate the lower part in the + * process, we still have enough significant bits to perform the conversion + * without error (for all valid inputs). + */ + output = (u.ui32[MSW] << 11) | (u.ui32[LSW] >> 21); + + /* Next, we perform the shift that converts the X.Y fixed-point number + * currently found in "output" to the desired 31.1 fixed-point format + * needed for the following rounding step. It is important to consider + * all possible values for "shift_amount" at this point: + * + * - {shift_amount < 0} Since shift_amount is an unsigned integer, it + * really can't have a value less than zero. But, if the shift_amount + * calculation above caused underflow (which would happen with + * input > INT_MAX or input <= INT_MIN) then shift_amount will now be + * a very large number, and so this shift will result in complete + * garbage. But that's OK, as the input was out of our range, so our + * output is undefined. + * + * - {shift_amount > 31} If the magnitude of the input was very small + * (i.e. |input| << 1.0), shift_amount will have a value greater than + * 31. Thus, this shift will also result in garbage. After performing + * the shift, we will zero-out "output" if this is the case. + * + * - {0 <= shift_amount < 32} In this case, the shift will properly convert + * the mantissa into a 31.1 fixed-point number. + */ + output >>= shift_amount; + + /* This is where we perform rounding with the 31.1 fixed-point number. + * Since what we're after is arithmetic rounding, we simply add the single + * fractional bit into the integer part of "output", and just keep the + * integer part. + */ + output = (output >> 1) + (output & 1); + + /* Here, we zero-out the result if the magnitude if the input was very small + * (as explained in the section above). Notice that all input out of the + * valid range is also caught by this condition, which means we produce 0 + * for all invalid input, which is a nice side effect. + * + * The most straightforward way to do this would be: + * + * if (shift_amount > 31) + * output = 0; + * + * But we can use a little trick to avoid the potential branch. The + * expression (shift_amount > 31) will be either 1 or 0, which when + * decremented will be either 0x0 or 0xFFFFFFFF (unsigned underflow), + * which can be used to conditionally mask away all the bits in "output" + * (in the 0x0 case), effectively zeroing it out. Certain, compilers would + * have done this for us automatically. + */ + output &= ((shift_amount > 31) - 1); + + /* If the input double was a negative number, then we have to negate our + * output. The most straightforward way to do this would be: + * + * if (!top) + * output = -output; + * + * as "top" at this point is either 0x0 (if the input was negative) or + * 0xFFFFFFFF (if the input was positive). But, we can use a trick to + * avoid the branch. Observe that the following snippet of code has the + * same effect as the reference snippet above: + * + * if (!top) + * output = 0 - output; + * else + * output = output - 0; + * + * Armed with the bitmask found in "top", we can condense the two statements + * into the following: + * + * output = (output & top) - (output & ~top); + * + * where, in the case that the input double was negative, "top" will be 0, + * and the statement will be equivalent to: + * + * output = (0) - (output); + * + * and if the input double was positive, "top" will be 0xFFFFFFFF, and the + * statement will be equivalent to: + * + * output = (output) - (0); + * + * Which, as pointed out earlier, is equivalent to the original reference + * snippet. + */ + output = (output & top) - (output & ~top); + + return output; +#undef MSW +#undef LSW +} +#endif + +/* Convert a 32-bit IEEE single precision floating point number to a + * 'half' representation (s10.5) + */ +uint16_t +_cairo_half_from_float (float f) +{ + union { + uint32_t ui; + float f; + } u; + int s, e, m; + + u.f = f; + s = (u.ui >> 16) & 0x00008000; + e = ((u.ui >> 23) & 0x000000ff) - (127 - 15); + m = u.ui & 0x007fffff; + if (e <= 0) { + if (e < -10) { + /* underflow */ + return 0; + } + + m = (m | 0x00800000) >> (1 - e); + + /* round to nearest, round 0.5 up. */ + if (m & 0x00001000) + m += 0x00002000; + return s | (m >> 13); + } else if (e == 0xff - (127 - 15)) { + if (m == 0) { + /* infinity */ + return s | 0x7c00; + } else { + /* nan */ + m >>= 13; + return s | 0x7c00 | m | (m == 0); + } + } else { + /* round to nearest, round 0.5 up. */ + if (m & 0x00001000) { + m += 0x00002000; + + if (m & 0x00800000) { + m = 0; + e += 1; + } + } + + if (e > 30) { + /* overflow -> infinity */ + return s | 0x7c00; + } + + return s | (e << 10) | (m >> 13); + } +} + +#ifndef __BIONIC__ +# include + +const char * +_cairo_get_locale_decimal_point (void) +{ + struct lconv *locale_data = localeconv (); + return locale_data->decimal_point; +} + +#else +/* Android's Bionic libc doesn't provide decimal_point */ +const char * +_cairo_get_locale_decimal_point (void) +{ + return "."; +} +#endif + +#if defined (HAVE_NEWLOCALE) && defined (HAVE_STRTOD_L) + +static locale_t C_locale; + +static locale_t +get_C_locale (void) +{ + locale_t C; + +retry: + C = (locale_t) _cairo_atomic_ptr_get ((cairo_atomic_intptr_t *) &C_locale); + + if (unlikely (!C)) { + C = newlocale (LC_ALL_MASK, "C", NULL); + + if (!_cairo_atomic_ptr_cmpxchg ((cairo_atomic_intptr_t *) &C_locale, NULL, C)) { + freelocale (C_locale); + goto retry; + } + } + + return C; +} + +double +_cairo_strtod (const char *nptr, char **endptr) +{ + return strtod_l (nptr, endptr, get_C_locale ()); +} + +#else + +/* strtod replacement that ignores locale and only accepts decimal points */ +double +_cairo_strtod (const char *nptr, char **endptr) +{ + const char *decimal_point; + int decimal_point_len; + const char *p; + char buf[100]; + char *bufptr; + char *bufend = buf + sizeof(buf) - 1; + double value; + char *end; + int delta; + cairo_bool_t have_dp; + + decimal_point = _cairo_get_locale_decimal_point (); + decimal_point_len = strlen (decimal_point); + assert (decimal_point_len != 0); + + p = nptr; + bufptr = buf; + delta = 0; + have_dp = FALSE; + while (*p && _cairo_isspace (*p)) { + p++; + delta++; + } + + while (*p && (bufptr + decimal_point_len < bufend)) { + if (_cairo_isdigit (*p)) { + *bufptr++ = *p; + } else if (*p == '.') { + if (have_dp) + break; + strncpy (bufptr, decimal_point, decimal_point_len); + bufptr += decimal_point_len; + delta -= decimal_point_len - 1; + have_dp = TRUE; + } else if (bufptr == buf && (*p == '-' || *p == '+')) { + *bufptr++ = *p; + } else { + break; + } + p++; + } + *bufptr = 0; + + value = strtod (buf, &end); + if (endptr) { + if (end == buf) + *endptr = (char*)(nptr); + else + *endptr = (char*)(nptr + (end - buf) + delta); + } + + return value; +} +#endif + +#ifndef HAVE_STRNDUP +char * +_cairo_strndup (const char *s, size_t n) +{ + const char *end; + size_t len; + char *sdup; + + if (s == NULL) + return NULL; + + end = memchr (s, 0, n); + if (end) + len = end - s; + else + len = n; + + sdup = (char *) _cairo_malloc (len + 1); + if (sdup != NULL) { + memcpy (sdup, s, len); + sdup[len] = '\0'; + } + + return sdup; +} +#endif + +/** + * _cairo_fopen: + * @filename: filename to open + * @mode: mode string with which to open the file + * @file_out: reference to file handle + * + * Exactly like the C library function, but possibly doing encoding + * conversion on the filename. On all platforms, the filename is + * passed directly to the system, but on Windows, the filename is + * interpreted as UTF-8, rather than in a codepage that would depend + * on system settings. + * + * Return value: CAIRO_STATUS_SUCCESS when the filename was converted + * successfully to the native encoding, or the error reported by + * _cairo_utf8_to_utf16 otherwise. To check if the file handle could + * be obtained, dereference file_out and compare its value against + * NULL + **/ +cairo_status_t +_cairo_fopen (const char *filename, const char *mode, FILE **file_out) +{ + FILE *result; +#ifdef _WIN32 /* also defined on x86_64 */ + uint16_t *filename_w; + uint16_t *mode_w; + cairo_status_t status; + + *file_out = NULL; + + if (filename == NULL || mode == NULL) { + errno = EINVAL; + return CAIRO_STATUS_SUCCESS; + } + + if ((status = _cairo_utf8_to_utf16 (filename, -1, &filename_w, NULL)) != CAIRO_STATUS_SUCCESS) { + errno = EINVAL; + return status; + } + + if ((status = _cairo_utf8_to_utf16 (mode, -1, &mode_w, NULL)) != CAIRO_STATUS_SUCCESS) { + free (filename_w); + errno = EINVAL; + return status; + } + + result = _wfopen (filename_w, mode_w); + + free (filename_w); + free (mode_w); + +#else /* Use fopen directly */ + +#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 7) + /* Glibc 2.7 supports the "e" mode flag that opens the file with O_CLOEXEC. + * this avoid the race condition in the fcntl fallback below. */ + + char new_mode[20]; + snprintf (new_mode, sizeof (new_mode), "%s%s", mode, "e"); + result = fopen (filename, new_mode); + +#else /* fopen "e" not available */ + + result = fopen (filename, mode); + +#if defined(HAVE_FCNTL_H) && defined(FD_CLOEXEC) + /* Manually set CLOEXEC */ + if (result != NULL) { + int fd = fileno (result); + if (fd != -1) { + int flags = fcntl (fd, F_GETFD); + if (flags >= 0) + flags = fcntl (fd, F_SETFD, flags | FD_CLOEXEC); + } + } +#endif /* defined(HAVE_FCNTL_H) && defined(FD_CLOEXEC) */ + +#endif /* fopen "e" not available */ + +#endif /* !_WIN32 */ + + *file_out = result; + + return CAIRO_STATUS_SUCCESS; +} + +#ifdef _WIN32 +#include +#include + +/* tmpfile() replacement for Windows. + * + * On Windows tmpfile() creates the file in the root directory. This + * may fail due to insufficient privileges. + */ +static FILE * +_cairo_win32_tmpfile (void) +{ + DWORD path_len; + WCHAR path_name[MAX_PATH + 1]; + WCHAR file_name[MAX_PATH + 1]; + HANDLE handle; + int fd; + FILE *fp; + + path_len = GetTempPathW (MAX_PATH, path_name); + if (path_len <= 0 || path_len >= MAX_PATH) + return NULL; + + if (GetTempFileNameW (path_name, L"cairo_", 0, file_name) == 0) + return NULL; + + handle = CreateFileW (file_name, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, + NULL); + if (handle == INVALID_HANDLE_VALUE) { + DeleteFileW (file_name); + return NULL; + } + + fd = _open_osfhandle((intptr_t) handle, 0); + if (fd < 0) { + CloseHandle (handle); + return NULL; + } + + fp = fdopen(fd, "w+b"); + if (fp == NULL) { + _close(fd); + return NULL; + } + + return fp; +} +#endif /* _WIN32 */ + +/** + * _cairo_tmpfile: + * + * Exactly like the C library function. On platforms that support + * O_CLOEXEC, the file will be opened with this flag. On Windows, the + * file is opened in the temp directory instead of the root directory. + * + * Return value: a file handle or NULL on error. + **/ +FILE * +_cairo_tmpfile (void) +{ +#ifdef _WIN32 + return _cairo_win32_tmpfile (); +#else /* !_WIN32 */ + int fd; + FILE *file; + int flags; + +#ifdef O_TMPFILE + fd = open(P_tmpdir, + O_TMPFILE | O_EXCL | O_RDWR | O_NOATIME | O_CLOEXEC, + 0600); + if (fd == -1 && errno == ENOENT) { + fd = open("/tmp", + O_TMPFILE | O_EXCL | O_RDWR | O_NOATIME | O_CLOEXEC, + 0600); + } + if (fd != -1) + return fdopen (fd, "wb+"); + + /* Fallback */ +#endif /* O_TMPFILE */ + + file = tmpfile(); + +#if defined(HAVE_FCNTL_H) && defined(FD_CLOEXEC) + /* Manually set CLOEXEC */ + if (file != NULL) { + fd = fileno(file); + if (fd != -1) { + flags = fcntl(fd, F_GETFD); + if (flags >= 0 && !(flags & FD_CLOEXEC)) + fcntl(fd, F_SETFD, flags | FD_CLOEXEC); + } + } +#endif /* defined(HAVE_FCNTL_H) && defined(FD_CLOEXEC) */ + + return file; +#endif /* !_WIN32 */ +} + +typedef struct _cairo_intern_string { + cairo_hash_entry_t hash_entry; + int len; + char *string; +} cairo_intern_string_t; + +static cairo_hash_table_t *_cairo_intern_string_ht; + +unsigned long +_cairo_string_hash (const char *str, int len) +{ + const signed char *p = (const signed char *) str; + unsigned int h = *p; + + for (p += 1; len > 0; len--, p++) + h = (h << 5) - h + *p; + + return h; +} + +static cairo_bool_t +_intern_string_equal (const void *_a, const void *_b) +{ + const cairo_intern_string_t *a = _a; + const cairo_intern_string_t *b = _b; + + if (a->len != b->len) + return FALSE; + + return memcmp (a->string, b->string, a->len) == 0; +} + +cairo_status_t +_cairo_intern_string (const char **str_inout, int len) +{ + char *str = (char *) *str_inout; + cairo_intern_string_t tmpl, *istring; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + if (CAIRO_INJECT_FAULT ()) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + if (len < 0) + len = strlen (str); + tmpl.hash_entry.hash = _cairo_string_hash (str, len); + tmpl.len = len; + tmpl.string = (char *) str; + + CAIRO_MUTEX_LOCK (_cairo_intern_string_mutex); + if (_cairo_intern_string_ht == NULL) { + _cairo_intern_string_ht = _cairo_hash_table_create (_intern_string_equal); + if (unlikely (_cairo_intern_string_ht == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto BAIL; + } + } + + istring = _cairo_hash_table_lookup (_cairo_intern_string_ht, + &tmpl.hash_entry); + if (istring == NULL) { + istring = _cairo_malloc (sizeof (cairo_intern_string_t) + len + 1); + if (likely (istring != NULL)) { + istring->hash_entry.hash = tmpl.hash_entry.hash; + istring->len = tmpl.len; + istring->string = (char *) (istring + 1); + memcpy (istring->string, str, len); + istring->string[len] = '\0'; + + status = _cairo_hash_table_insert (_cairo_intern_string_ht, + &istring->hash_entry); + if (unlikely (status)) { + free (istring); + goto BAIL; + } + } else { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto BAIL; + } + } + + *str_inout = istring->string; + + BAIL: + CAIRO_MUTEX_UNLOCK (_cairo_intern_string_mutex); + return status; +} + +static void +_intern_string_pluck (void *entry, void *closure) +{ + _cairo_hash_table_remove (closure, entry); + free (entry); +} + +void +_cairo_intern_string_reset_static_data (void) +{ + CAIRO_MUTEX_LOCK (_cairo_intern_string_mutex); + if (_cairo_intern_string_ht != NULL) { + _cairo_hash_table_foreach (_cairo_intern_string_ht, + _intern_string_pluck, + _cairo_intern_string_ht); + _cairo_hash_table_destroy(_cairo_intern_string_ht); + _cairo_intern_string_ht = NULL; + } + CAIRO_MUTEX_UNLOCK (_cairo_intern_string_mutex); +} diff --git a/local/recipes/libs/cairo/source/src/cairo-mono-scan-converter.c b/local/recipes/libs/cairo/source/src/cairo-mono-scan-converter.c new file mode 100644 index 0000000000..e7c8ddb1ef --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-mono-scan-converter.c @@ -0,0 +1,587 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* + * Copyright (c) 2011 Intel Corporation + * + * 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. + */ +#include "cairoint.h" +#include "cairo-spans-private.h" +#include "cairo-error-private.h" + +#include +#include +#include + +struct quorem { + int32_t quo; + int32_t rem; +}; + +struct edge { + struct edge *next, *prev; + + int32_t height_left; + int32_t dir; + int32_t vertical; + + int32_t dy; + struct quorem x; + struct quorem dxdy; +}; + +/* A collection of sorted and vertically clipped edges of the polygon. + * Edges are moved from the polygon to an active list while scan + * converting. */ +struct polygon { + /* The vertical clip extents. */ + int32_t ymin, ymax; + + int num_edges; + struct edge *edges; + + /* Array of edges all starting in the same bucket. An edge is put + * into bucket EDGE_BUCKET_INDEX(edge->ytop, polygon->ymin) when + * it is added to the polygon. */ + struct edge **y_buckets; + + struct edge *y_buckets_embedded[64]; + struct edge edges_embedded[32]; +}; + +struct mono_scan_converter { + struct polygon polygon[1]; + + /* Leftmost edge on the current scan line. */ + struct edge head, tail; + int is_vertical; + + cairo_half_open_span_t *spans; + cairo_half_open_span_t spans_embedded[64]; + int num_spans; + + /* Clip box. */ + int32_t xmin, xmax; + int32_t ymin, ymax; +}; + +#define I(x) _cairo_fixed_integer_round_down(x) + +/* Compute the floored division (x*a)/b. Assumes / and % perform symmetric + * division. */ +static struct quorem +floored_muldivrem(int x, int a, int b) +{ + struct quorem qr; + long long xa = (long long)x*a; + qr.quo = xa/b; + qr.rem = xa%b; + if ((xa>=0) != (b>=0) && qr.rem) { + qr.quo -= 1; + qr.rem += b; + } + return qr; +} + +static cairo_status_t +polygon_init (struct polygon *polygon, int ymin, int ymax) +{ + unsigned h = ymax - ymin + 1; + + polygon->y_buckets = polygon->y_buckets_embedded; + if (h > ARRAY_LENGTH (polygon->y_buckets_embedded)) { + polygon->y_buckets = _cairo_malloc_ab (h, sizeof (struct edge *)); + if (unlikely (NULL == polygon->y_buckets)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + memset (polygon->y_buckets, 0, h * sizeof (struct edge *)); + polygon->y_buckets[h-1] = (void *)-1; + + polygon->ymin = ymin; + polygon->ymax = ymax; + return CAIRO_STATUS_SUCCESS; +} + +static void +polygon_fini (struct polygon *polygon) +{ + if (polygon->y_buckets != polygon->y_buckets_embedded) + free (polygon->y_buckets); + + if (polygon->edges != polygon->edges_embedded) + free (polygon->edges); +} + +static void +_polygon_insert_edge_into_its_y_bucket(struct polygon *polygon, + struct edge *e, + int y) +{ + struct edge **ptail = &polygon->y_buckets[y - polygon->ymin]; + if (*ptail) + (*ptail)->prev = e; + e->next = *ptail; + e->prev = NULL; + *ptail = e; +} + +inline static void +polygon_add_edge (struct polygon *polygon, + const cairo_edge_t *edge) +{ + struct edge *e; + cairo_fixed_t dx; + cairo_fixed_t dy; + int y, ytop, ybot; + int ymin = polygon->ymin; + int ymax = polygon->ymax; + + y = I(edge->top); + ytop = MAX(y, ymin); + + y = I(edge->bottom); + ybot = MIN(y, ymax); + + if (ybot <= ytop) + return; + + e = polygon->edges + polygon->num_edges++; + e->height_left = ybot - ytop; + e->dir = edge->dir; + + dx = edge->line.p2.x - edge->line.p1.x; + dy = edge->line.p2.y - edge->line.p1.y; + + if (dx == 0) { + e->vertical = TRUE; + e->x.quo = edge->line.p1.x; + e->x.rem = 0; + e->dxdy.quo = 0; + e->dxdy.rem = 0; + e->dy = 0; + } else { + e->vertical = FALSE; + e->dxdy = floored_muldivrem (dx, CAIRO_FIXED_ONE, dy); + e->dy = dy; + + e->x = floored_muldivrem (ytop * CAIRO_FIXED_ONE + CAIRO_FIXED_FRAC_MASK/2 - edge->line.p1.y, + dx, dy); + e->x.quo += edge->line.p1.x; + } + e->x.rem -= dy; + + _polygon_insert_edge_into_its_y_bucket (polygon, e, ytop); +} + +static struct edge * +merge_sorted_edges (struct edge *head_a, struct edge *head_b) +{ + struct edge *head, **next, *prev; + int32_t x; + + prev = head_a->prev; + next = &head; + if (head_a->x.quo <= head_b->x.quo) { + head = head_a; + } else { + head = head_b; + head_b->prev = prev; + goto start_with_b; + } + + do { + x = head_b->x.quo; + while (head_a != NULL && head_a->x.quo <= x) { + prev = head_a; + next = &head_a->next; + head_a = head_a->next; + } + + head_b->prev = prev; + *next = head_b; + if (head_a == NULL) + return head; + +start_with_b: + x = head_a->x.quo; + while (head_b != NULL && head_b->x.quo <= x) { + prev = head_b; + next = &head_b->next; + head_b = head_b->next; + } + + head_a->prev = prev; + *next = head_a; + if (head_b == NULL) + return head; + } while (1); +} + +static struct edge * +sort_edges (struct edge *list, + unsigned int level, + struct edge **head_out) +{ + struct edge *head_other, *remaining; + unsigned int i; + + head_other = list->next; + + if (head_other == NULL) { + *head_out = list; + return NULL; + } + + remaining = head_other->next; + if (list->x.quo <= head_other->x.quo) { + *head_out = list; + head_other->next = NULL; + } else { + *head_out = head_other; + head_other->prev = list->prev; + head_other->next = list; + list->prev = head_other; + list->next = NULL; + } + + for (i = 0; i < level && remaining; i++) { + remaining = sort_edges (remaining, i, &head_other); + *head_out = merge_sorted_edges (*head_out, head_other); + } + + return remaining; +} + +static struct edge * +merge_unsorted_edges (struct edge *head, struct edge *unsorted) +{ + sort_edges (unsorted, UINT_MAX, &unsorted); + return merge_sorted_edges (head, unsorted); +} + +inline static void +active_list_merge_edges (struct mono_scan_converter *c, struct edge *edges) +{ + struct edge *e; + + for (e = edges; c->is_vertical && e; e = e->next) + c->is_vertical = e->vertical; + + c->head.next = merge_unsorted_edges (c->head.next, edges); +} + +inline static void +add_span (struct mono_scan_converter *c, int x1, int x2) +{ + int n; + + if (x1 < c->xmin) + x1 = c->xmin; + if (x2 > c->xmax) + x2 = c->xmax; + if (x2 <= x1) + return; + + n = c->num_spans++; + c->spans[n].x = x1; + c->spans[n].coverage = 255; + + n = c->num_spans++; + c->spans[n].x = x2; + c->spans[n].coverage = 0; +} + +inline static void +row (struct mono_scan_converter *c, unsigned int mask) +{ + struct edge *edge = c->head.next; + int xstart = INT_MIN, prev_x = INT_MIN; + int winding = 0; + + c->num_spans = 0; + while (&c->tail != edge) { + struct edge *next = edge->next; + int xend = I(edge->x.quo); + + if (--edge->height_left) { + if (!edge->vertical) { + edge->x.quo += edge->dxdy.quo; + edge->x.rem += edge->dxdy.rem; + if (edge->x.rem >= 0) { + ++edge->x.quo; + edge->x.rem -= edge->dy; + } + } + + if (edge->x.quo < prev_x) { + struct edge *pos = edge->prev; + pos->next = next; + next->prev = pos; + do { + pos = pos->prev; + } while (edge->x.quo < pos->x.quo); + pos->next->prev = edge; + edge->next = pos->next; + edge->prev = pos; + pos->next = edge; + } else + prev_x = edge->x.quo; + } else { + edge->prev->next = next; + next->prev = edge->prev; + } + + winding += edge->dir; + if ((winding & mask) == 0) { + if (I(next->x.quo) > xend + 1) { + add_span (c, xstart, xend); + xstart = INT_MIN; + } + } else if (xstart == INT_MIN) + xstart = xend; + + edge = next; + } +} + +static cairo_status_t +_mono_scan_converter_init(struct mono_scan_converter *c, + int xmin, int ymin, + int xmax, int ymax) +{ + cairo_status_t status; + int max_num_spans; + + status = polygon_init (c->polygon, ymin, ymax); + if (unlikely (status)) + return status; + + max_num_spans = xmax - xmin + 1; + if (max_num_spans > ARRAY_LENGTH(c->spans_embedded)) { + c->spans = _cairo_malloc_ab (max_num_spans, + sizeof (cairo_half_open_span_t)); + if (unlikely (c->spans == NULL)) { + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + } else + c->spans = c->spans_embedded; + + c->xmin = xmin; + c->xmax = xmax; + c->ymin = ymin; + c->ymax = ymax; + + c->head.vertical = 1; + c->head.height_left = INT_MAX; + c->head.x.quo = _cairo_fixed_from_int (_cairo_fixed_integer_part (INT_MIN)); + c->head.prev = NULL; + c->head.next = &c->tail; + c->tail.prev = &c->head; + c->tail.next = NULL; + c->tail.x.quo = _cairo_fixed_from_int (_cairo_fixed_integer_part (INT_MAX)); + c->tail.height_left = INT_MAX; + c->tail.vertical = 1; + + c->is_vertical = 1; + return CAIRO_STATUS_SUCCESS; +} + +static void +_mono_scan_converter_fini(struct mono_scan_converter *self) +{ + if (self->spans != self->spans_embedded) + free (self->spans); + + polygon_fini(self->polygon); +} + +static cairo_status_t +mono_scan_converter_allocate_edges(struct mono_scan_converter *c, + int num_edges) + +{ + c->polygon->num_edges = 0; + c->polygon->edges = c->polygon->edges_embedded; + if (num_edges > ARRAY_LENGTH (c->polygon->edges_embedded)) { + c->polygon->edges = _cairo_malloc_ab (num_edges, sizeof (struct edge)); + if (unlikely (c->polygon->edges == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + return CAIRO_STATUS_SUCCESS; +} + +static void +mono_scan_converter_add_edge (struct mono_scan_converter *c, + const cairo_edge_t *edge) +{ + polygon_add_edge (c->polygon, edge); +} + +static void +step_edges (struct mono_scan_converter *c, int count) +{ + struct edge *edge; + + for (edge = c->head.next; edge != &c->tail; edge = edge->next) { + edge->height_left -= count; + if (! edge->height_left) { + edge->prev->next = edge->next; + edge->next->prev = edge->prev; + } + } +} + +static cairo_status_t +mono_scan_converter_render(struct mono_scan_converter *c, + unsigned int winding_mask, + cairo_span_renderer_t *renderer) +{ + struct polygon *polygon = c->polygon; + int i, j, h = c->ymax - c->ymin; + cairo_status_t status; + + for (i = 0; i < h; i = j) { + j = i + 1; + + if (polygon->y_buckets[i]) + active_list_merge_edges (c, polygon->y_buckets[i]); + + if (c->is_vertical) { + int min_height; + struct edge *e; + + e = c->head.next; + min_height = e->height_left; + while (e != &c->tail) { + if (e->height_left < min_height) + min_height = e->height_left; + e = e->next; + } + + while (--min_height >= 1 && polygon->y_buckets[j] == NULL) + j++; + if (j != i + 1) + step_edges (c, j - (i + 1)); + } + + row (c, winding_mask); + if (c->num_spans) { + status = renderer->render_rows (renderer, c->ymin+i, j-i, + c->spans, c->num_spans); + if (unlikely (status)) + return status; + } + + /* XXX recompute after dropping edges? */ + if (c->head.next == &c->tail) + c->is_vertical = 1; + } + + return CAIRO_STATUS_SUCCESS; +} + +struct _cairo_mono_scan_converter { + cairo_scan_converter_t base; + + struct mono_scan_converter converter[1]; + cairo_fill_rule_t fill_rule; +}; + +typedef struct _cairo_mono_scan_converter cairo_mono_scan_converter_t; + +static void +_cairo_mono_scan_converter_destroy (void *converter) +{ + cairo_mono_scan_converter_t *self = converter; + _mono_scan_converter_fini (self->converter); + free(self); +} + +cairo_status_t +_cairo_mono_scan_converter_add_polygon (void *converter, + const cairo_polygon_t *polygon) +{ + cairo_mono_scan_converter_t *self = converter; + cairo_status_t status; + int i; + +#if 0 + FILE *file = fopen ("polygon.txt", "w"); + _cairo_debug_print_polygon (file, polygon); + fclose (file); +#endif + + status = mono_scan_converter_allocate_edges (self->converter, + polygon->num_edges); + if (unlikely (status)) + return status; + + for (i = 0; i < polygon->num_edges; i++) + mono_scan_converter_add_edge (self->converter, &polygon->edges[i]); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_mono_scan_converter_generate (void *converter, + cairo_span_renderer_t *renderer) +{ + cairo_mono_scan_converter_t *self = converter; + + return mono_scan_converter_render (self->converter, + self->fill_rule == CAIRO_FILL_RULE_WINDING ? ~0 : 1, + renderer); +} + +cairo_scan_converter_t * +_cairo_mono_scan_converter_create (int xmin, + int ymin, + int xmax, + int ymax, + cairo_fill_rule_t fill_rule) +{ + cairo_mono_scan_converter_t *self; + cairo_status_t status; + + self = _cairo_calloc (sizeof(struct _cairo_mono_scan_converter)); + if (unlikely (self == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto bail_nomem; + } + + self->base.destroy = _cairo_mono_scan_converter_destroy; + self->base.generate = _cairo_mono_scan_converter_generate; + + status = _mono_scan_converter_init (self->converter, + xmin, ymin, xmax, ymax); + if (unlikely (status)) + goto bail; + + self->fill_rule = fill_rule; + + return &self->base; + + bail: + self->base.destroy(&self->base); + bail_nomem: + return _cairo_scan_converter_create_in_error (status); +} diff --git a/local/recipes/libs/cairo/source/src/cairo-mutex-impl-private.h b/local/recipes/libs/cairo/source/src/cairo-mutex-impl-private.h new file mode 100644 index 0000000000..b9430beef2 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-mutex-impl-private.h @@ -0,0 +1,247 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005,2007 Red Hat, Inc. + * Copyright © 2007 Mathias Hasselmann + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Mathias Hasselmann + * Behdad Esfahbod + */ + +#ifndef CAIRO_MUTEX_IMPL_PRIVATE_H +#define CAIRO_MUTEX_IMPL_PRIVATE_H + +#include "cairo.h" + +#include "config.h" + +#if HAVE_LOCKDEP +#include +#endif + +/* A fully qualified no-operation statement */ +#define CAIRO_MUTEX_IMPL_NOOP do {/*no-op*/} while (0) +/* And one that evaluates its argument once */ +#define CAIRO_MUTEX_IMPL_NOOP1(expr) do { (void)(expr); } while (0) +/* Note: 'if (expr) {}' is an alternative to '(void)(expr);' that will 'use' the + * result of __attribute__((warn_used_result)) functions. */ + +/* Cairo mutex implementation: + * + * Any new mutex implementation needs to do the following: + * + * - Condition on the right header or feature. Headers are + * preferred as eg. you still can use win32 mutex implementation + * on a win32 system even if you do not compile the win32 + * surface/backend. + * + * - typedef #cairo_mutex_impl_t to the proper mutex type on your target + * system. Note that you may or may not need to use a pointer, + * depending on what kinds of initialization your mutex + * implementation supports. No trailing semicolon needed. + * You should be able to compile the following snippet (don't try + * running it): + * + * + * cairo_mutex_impl_t _cairo_some_mutex; + * + * + * - #define %CAIRO_MUTEX_IMPL_ 1 with suitable name for your platform. You + * can later use this symbol in cairo-system.c. + * + * - #define CAIRO_MUTEX_IMPL_LOCK(mutex) and CAIRO_MUTEX_IMPL_UNLOCK(mutex) to + * proper statement to lock/unlock the mutex object passed in. + * You can (and should) assume that the mutex is already + * initialized, and is-not-already-locked/is-locked, + * respectively. Use the "do { ... } while (0)" idiom if necessary. + * No trailing semicolons are needed (in any macro you define here). + * You should be able to compile the following snippet: + * + * - #define CAIRO_MUTEX_IMPL_TRY_LOCK(mutex) to try locking the mutex object, + * returning TRUE if the lock is acquired, FALSE if the mutex could not be locked. + * + * + * cairo_mutex_impl_t _cairo_some_mutex; + * + * if (1) + * CAIRO_MUTEX_IMPL_LOCK (_cairo_some_mutex); + * else + * CAIRO_MUTEX_IMPL_UNLOCK (_cairo_some_mutex); + * + * + * - #define %CAIRO_MUTEX_IMPL_NIL_INITIALIZER to something that can + * initialize the #cairo_mutex_impl_t type you defined. Most of the + * time one of 0, %NULL, or {} works. At this point + * you should be able to compile the following snippet: + * + * + * cairo_mutex_impl_t _cairo_some_mutex = CAIRO_MUTEX_IMPL_NIL_INITIALIZER; + * + * if (1) + * CAIRO_MUTEX_IMPL_LOCK (_cairo_some_mutex); + * else + * CAIRO_MUTEX_IMPL_UNLOCK (_cairo_some_mutex); + * + * + * - If the above code is not enough to initialize a mutex on + * your platform, #define CAIRO_MUTEX_IMPL_INIT(mutex) to statement + * to initialize the mutex (allocate resources, etc). Such that + * you should be able to compile AND RUN the following snippet: + * + * + * cairo_mutex_impl_t _cairo_some_mutex = CAIRO_MUTEX_IMPL_NIL_INITIALIZER; + * + * CAIRO_MUTEX_IMPL_INIT (_cairo_some_mutex); + * + * if (1) + * CAIRO_MUTEX_IMPL_LOCK (_cairo_some_mutex); + * else + * CAIRO_MUTEX_IMPL_UNLOCK (_cairo_some_mutex); + * + * + * - If you define CAIRO_MUTEX_IMPL_INIT(mutex), cairo will use it to + * initialize all static mutex'es. If for any reason that should + * not happen (eg. %CAIRO_MUTEX_IMPL_INIT is just a faster way than + * what cairo does using %CAIRO_MUTEX_IMPL_NIL_INITIALIZER), then + * + * #define CAIRO_MUTEX_IMPL_INITIALIZE() CAIRO_MUTEX_IMPL_NOOP + * + * + * - If your system supports freeing a mutex object (deallocating + * resources, etc), then #define CAIRO_MUTEX_IMPL_FINI(mutex) to do + * that. + * + * - If you define CAIRO_MUTEX_IMPL_FINI(mutex), cairo will use it to + * define a finalizer function to finalize all static mutex'es. + * However, it's up to you to call CAIRO_MUTEX_IMPL_FINALIZE() at + * proper places, eg. when the system is unloading the cairo library. + * So, if for any reason finalizing static mutex'es is not needed + * (eg. you never call CAIRO_MUTEX_IMPL_FINALIZE()), then + * + * #define CAIRO_MUTEX_IMPL_FINALIZE() CAIRO_MUTEX_IMPL_NOOP + * + * + * - That is all. If for any reason you think the above API is + * not enough to implement #cairo_mutex_impl_t on your system, please + * stop and write to the cairo mailing list about it. DO NOT + * poke around cairo-mutex-private.h for possible solutions. + */ + +#if CAIRO_NO_MUTEX + +/* No mutexes */ + + typedef int cairo_mutex_impl_t; + +# define CAIRO_MUTEX_IMPL_NO 1 +# define CAIRO_MUTEX_IMPL_INITIALIZE() CAIRO_MUTEX_IMPL_NOOP +# define CAIRO_MUTEX_IMPL_LOCK(mutex) CAIRO_MUTEX_IMPL_NOOP1(mutex) +# define CAIRO_MUTEX_IMPL_TRY_LOCK(mutex) ((mutex), TRUE) +# define CAIRO_MUTEX_IMPL_UNLOCK(mutex) CAIRO_MUTEX_IMPL_NOOP1(mutex) +# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER 0 + +# define CAIRO_MUTEX_HAS_RECURSIVE_IMPL 1 + + typedef int cairo_recursive_mutex_impl_t; + +# define CAIRO_RECURSIVE_MUTEX_IMPL_INIT(mutex) +# define CAIRO_RECURSIVE_MUTEX_IMPL_NIL_INITIALIZER 0 + +#elif defined(_WIN32) /******************************************************/ + +# include + + typedef CRITICAL_SECTION cairo_mutex_impl_t; + +# define CAIRO_MUTEX_IMPL_WIN32 1 +# define CAIRO_MUTEX_IMPL_LOCK(mutex) EnterCriticalSection (&(mutex)) +# define CAIRO_MUTEX_IMPL_TRY_LOCK(mutex) TryEnterCriticalSection (&(mutex)) +# define CAIRO_MUTEX_IMPL_UNLOCK(mutex) LeaveCriticalSection (&(mutex)) +# define CAIRO_MUTEX_IMPL_INIT(mutex) InitializeCriticalSection (&(mutex)) +# define CAIRO_MUTEX_IMPL_FINI(mutex) DeleteCriticalSection (&(mutex)) +# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER { NULL, 0, 0, NULL, NULL, 0 } + +#elif CAIRO_HAS_PTHREAD /* and finally if there are no native mutexes ********/ + +# include + + typedef pthread_mutex_t cairo_mutex_impl_t; + typedef pthread_mutex_t cairo_recursive_mutex_impl_t; + +# define CAIRO_MUTEX_IMPL_PTHREAD 1 +#if HAVE_LOCKDEP +/* expose all mutexes to the validator */ +# define CAIRO_MUTEX_IMPL_INIT(mutex) pthread_mutex_init (&(mutex), NULL) +#endif +# define CAIRO_MUTEX_IMPL_LOCK(mutex) pthread_mutex_lock (&(mutex)) +# define CAIRO_MUTEX_IMPL_TRY_LOCK(mutex) (pthread_mutex_trylock (&(mutex)) == 0) +# define CAIRO_MUTEX_IMPL_UNLOCK(mutex) pthread_mutex_unlock (&(mutex)) +#if HAVE_LOCKDEP +# define CAIRO_MUTEX_IS_LOCKED(mutex) LOCKDEP_IS_LOCKED (&(mutex)) +# define CAIRO_MUTEX_IS_UNLOCKED(mutex) LOCKDEP_IS_UNLOCKED (&(mutex)) +#endif +# define CAIRO_MUTEX_IMPL_FINI(mutex) pthread_mutex_destroy (&(mutex)) +#if ! HAVE_LOCKDEP +# define CAIRO_MUTEX_IMPL_FINALIZE() CAIRO_MUTEX_IMPL_NOOP +#endif +# define CAIRO_MUTEX_IMPL_NIL_INITIALIZER PTHREAD_MUTEX_INITIALIZER + +# define CAIRO_MUTEX_HAS_RECURSIVE_IMPL 1 +# define CAIRO_RECURSIVE_MUTEX_IMPL_INIT(mutex) do { \ + pthread_mutexattr_t attr; \ + pthread_mutexattr_init (&attr); \ + pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE); \ + pthread_mutex_init (&(mutex), &attr); \ + pthread_mutexattr_destroy (&attr); \ +} while (0) +# define CAIRO_RECURSIVE_MUTEX_IMPL_NIL_INITIALIZER PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP + +#else /**********************************************************************/ + +# error "XXX: No mutex implementation found. Cairo will not work with multiple threads. Define CAIRO_NO_MUTEX to 1 to acknowledge and accept this limitation and compile cairo without thread-safety support." + +#endif + +/* By default mutex implementations are assumed to be recursive */ +#if ! CAIRO_MUTEX_HAS_RECURSIVE_IMPL + +# define CAIRO_MUTEX_HAS_RECURSIVE_IMPL 1 + + typedef cairo_mutex_impl_t cairo_recursive_mutex_impl_t; + +# define CAIRO_RECURSIVE_MUTEX_IMPL_INIT(mutex) CAIRO_MUTEX_IMPL_INIT(mutex) +# define CAIRO_RECURSIVE_MUTEX_IMPL_NIL_INITIALIZER CAIRO_MUTEX_IMPL_NIL_INITIALIZER + +#endif + +#endif diff --git a/local/recipes/libs/cairo/source/src/cairo-mutex-list-private.h b/local/recipes/libs/cairo/source/src/cairo-mutex-list-private.h new file mode 100644 index 0000000000..af5cc0517a --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-mutex-list-private.h @@ -0,0 +1,72 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2007 Mathias Hasselmann + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * Contributor(s): + * Mathias Hasselmann + */ + +#ifndef CAIRO_FEATURES_H +/* This block is to just make this header file standalone */ +#define CAIRO_MUTEX_DECLARE(mutex) +#endif + +CAIRO_MUTEX_DECLARE (_cairo_pattern_solid_surface_cache_lock) + +CAIRO_MUTEX_DECLARE (_cairo_image_solid_cache_mutex) + +CAIRO_MUTEX_DECLARE (_cairo_toy_font_face_mutex) +CAIRO_MUTEX_DECLARE (_cairo_intern_string_mutex) +CAIRO_MUTEX_DECLARE (_cairo_scaled_font_map_mutex) +CAIRO_MUTEX_DECLARE (_cairo_scaled_glyph_page_cache_mutex) +CAIRO_MUTEX_DECLARE (_cairo_scaled_font_error_mutex) +CAIRO_MUTEX_DECLARE (_cairo_glyph_cache_mutex) + +#if CAIRO_HAS_FT_FONT +CAIRO_MUTEX_DECLARE (_cairo_ft_unscaled_font_map_mutex) +#endif + +#if CAIRO_HAS_WIN32_FONT +CAIRO_MUTEX_DECLARE (_cairo_win32_font_face_mutex) +CAIRO_MUTEX_DECLARE (_cairo_win32_font_dc_mutex) +#endif + +#if CAIRO_HAS_XLIB_SURFACE +CAIRO_MUTEX_DECLARE (_cairo_xlib_display_mutex) +#endif + +#if CAIRO_HAS_XCB_SURFACE +CAIRO_MUTEX_DECLARE (_cairo_xcb_connections_mutex) +#endif + +#if !defined (HAS_ATOMIC_OPS) || defined (ATOMIC_OP_NEEDS_MEMORY_BARRIER) +CAIRO_MUTEX_DECLARE (_cairo_atomic_mutex) +#endif + +/* Undefine, to err on unintended inclusion */ +#undef CAIRO_MUTEX_DECLARE diff --git a/local/recipes/libs/cairo/source/src/cairo-mutex-private.h b/local/recipes/libs/cairo/source/src/cairo-mutex-private.h new file mode 100644 index 0000000000..6b3eb03654 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-mutex-private.h @@ -0,0 +1,73 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005,2007 Red Hat, Inc. + * Copyright © 2007 Mathias Hasselmann + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Mathias Hasselmann + * Behdad Esfahbod + */ + +#ifndef CAIRO_MUTEX_PRIVATE_H +#define CAIRO_MUTEX_PRIVATE_H + +#include "cairo-mutex-type-private.h" + +CAIRO_BEGIN_DECLS + +#if _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER +cairo_private void _cairo_mutex_initialize (void); +#endif +#if _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER +cairo_private void _cairo_mutex_finalize (void); +#endif +/* only if using static initializer and/or finalizer define the boolean */ +#if _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER || _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER + +#if HAS_ATOMIC_OPS + cairo_private extern cairo_atomic_int_t _cairo_mutex_initialized; +#else + cairo_private extern int _cairo_mutex_initialized; +#endif + +#endif + +/* Finally, extern the static mutexes and undef */ + +#define CAIRO_MUTEX_DECLARE(mutex) cairo_private extern cairo_mutex_t mutex; +#include "cairo-mutex-list-private.h" +#undef CAIRO_MUTEX_DECLARE + +CAIRO_END_DECLS + +#endif diff --git a/local/recipes/libs/cairo/source/src/cairo-mutex-type-private.h b/local/recipes/libs/cairo/source/src/cairo-mutex-type-private.h new file mode 100644 index 0000000000..ef8fc5e463 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-mutex-type-private.h @@ -0,0 +1,201 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005,2007 Red Hat, Inc. + * Copyright © 2007 Mathias Hasselmann + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Mathias Hasselmann + * Behdad Esfahbod + */ + +#ifndef CAIRO_MUTEX_TYPE_PRIVATE_H +#define CAIRO_MUTEX_TYPE_PRIVATE_H + +#include "cairo-compiler-private.h" +#include "cairo-mutex-impl-private.h" + +/* Only the following four are mandatory at this point */ +#ifndef CAIRO_MUTEX_IMPL_LOCK +# error "CAIRO_MUTEX_IMPL_LOCK not defined. Check cairo-mutex-impl-private.h." +#endif +#ifndef CAIRO_MUTEX_IMPL_TRY_LOCK +# error "CAIRO_MUTEX_IMPL_TRY_LOCK not defined. Check cairo-mutex-impl-private.h." +#endif +#ifndef CAIRO_MUTEX_IMPL_UNLOCK +# error "CAIRO_MUTEX_IMPL_UNLOCK not defined. Check cairo-mutex-impl-private.h." +#endif +#ifndef CAIRO_MUTEX_IMPL_NIL_INITIALIZER +# error "CAIRO_MUTEX_IMPL_NIL_INITIALIZER not defined. Check cairo-mutex-impl-private.h." +#endif +#ifndef CAIRO_RECURSIVE_MUTEX_IMPL_INIT +# error "CAIRO_RECURSIVE_MUTEX_IMPL_INIT not defined. Check cairo-mutex-impl-private.h." +#endif + + +/* make sure implementations don't fool us: we decide these ourself */ +#undef _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER +#undef _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER + + +#ifdef CAIRO_MUTEX_IMPL_INIT + +/* If %CAIRO_MUTEX_IMPL_INIT is defined, we may need to initialize all + * static mutex'es. */ +# ifndef CAIRO_MUTEX_IMPL_INITIALIZE +# define CAIRO_MUTEX_IMPL_INITIALIZE() do { \ + if (!_cairo_mutex_initialized) \ + _cairo_mutex_initialize (); \ + } while(0) + +/* and make sure we implement the above */ +# define _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER 1 +# endif /* CAIRO_MUTEX_IMPL_INITIALIZE */ + +#else /* no CAIRO_MUTEX_IMPL_INIT */ + +/* Otherwise we probably don't need to initialize static mutex'es, */ +# ifndef CAIRO_MUTEX_IMPL_INITIALIZE +# define CAIRO_MUTEX_IMPL_INITIALIZE() CAIRO_MUTEX_IMPL_NOOP +# endif /* CAIRO_MUTEX_IMPL_INITIALIZE */ + +/* and dynamic ones can be initialized using the static initializer. */ +# define CAIRO_MUTEX_IMPL_INIT(mutex) do { \ + cairo_mutex_t _tmp_mutex = CAIRO_MUTEX_IMPL_NIL_INITIALIZER; \ + memcpy (&(mutex), &_tmp_mutex, sizeof (_tmp_mutex)); \ + } while (0) + +#endif /* CAIRO_MUTEX_IMPL_INIT */ + +#ifdef CAIRO_MUTEX_IMPL_FINI + +/* If %CAIRO_MUTEX_IMPL_FINI is defined, we may need to finalize all + * static mutex'es. */ +# ifndef CAIRO_MUTEX_IMPL_FINALIZE +# define CAIRO_MUTEX_IMPL_FINALIZE() do { \ + if (_cairo_mutex_initialized) \ + _cairo_mutex_finalize (); \ + } while(0) + +/* and make sure we implement the above */ +# define _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER 1 +# endif /* CAIRO_MUTEX_IMPL_FINALIZE */ + +#else /* no CAIRO_MUTEX_IMPL_FINI */ + +/* Otherwise we probably don't need to finalize static mutex'es, */ +# ifndef CAIRO_MUTEX_IMPL_FINALIZE +# define CAIRO_MUTEX_IMPL_FINALIZE() CAIRO_MUTEX_IMPL_NOOP +# endif /* CAIRO_MUTEX_IMPL_FINALIZE */ + +/* neither do the dynamic ones. */ +# define CAIRO_MUTEX_IMPL_FINI(mutex) CAIRO_MUTEX_IMPL_NOOP1(mutex) + +#endif /* CAIRO_MUTEX_IMPL_FINI */ + + +#ifndef _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER +#define _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER 0 +#endif +#ifndef _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER +#define _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER 0 +#endif + + +/* Make sure everything we want is defined */ +#ifndef CAIRO_MUTEX_IMPL_INITIALIZE +# error "CAIRO_MUTEX_IMPL_INITIALIZE not defined" +#endif +#ifndef CAIRO_MUTEX_IMPL_FINALIZE +# error "CAIRO_MUTEX_IMPL_FINALIZE not defined" +#endif +#ifndef CAIRO_MUTEX_IMPL_LOCK +# error "CAIRO_MUTEX_IMPL_LOCK not defined" +#endif +#ifndef CAIRO_MUTEX_IMPL_TRY_LOCK +# error "CAIRO_MUTEX_IMPL_TRY_LOCK not defined" +#endif +#ifndef CAIRO_MUTEX_IMPL_UNLOCK +# error "CAIRO_MUTEX_IMPL_UNLOCK not defined" +#endif +#ifndef CAIRO_MUTEX_IMPL_INIT +# error "CAIRO_MUTEX_IMPL_INIT not defined" +#endif +#ifndef CAIRO_MUTEX_IMPL_FINI +# error "CAIRO_MUTEX_IMPL_FINI not defined" +#endif +#ifndef CAIRO_MUTEX_IMPL_NIL_INITIALIZER +# error "CAIRO_MUTEX_IMPL_NIL_INITIALIZER not defined" +#endif + + +/* Public interface. */ + +/* By default it simply uses the implementation provided. + * But we can provide for debugging features by overriding them */ + +#ifndef CAIRO_MUTEX_DEBUG +typedef cairo_mutex_impl_t cairo_mutex_t; +typedef cairo_recursive_mutex_impl_t cairo_recursive_mutex_t; +#else +# define cairo_mutex_t cairo_mutex_impl_t +#endif + +#define CAIRO_MUTEX_INITIALIZE CAIRO_MUTEX_IMPL_INITIALIZE +#define CAIRO_MUTEX_FINALIZE CAIRO_MUTEX_IMPL_FINALIZE +#define CAIRO_MUTEX_LOCK CAIRO_MUTEX_IMPL_LOCK +#define CAIRO_MUTEX_TRY_LOCK CAIRO_MUTEX_IMPL_TRY_LOCK +#define CAIRO_MUTEX_UNLOCK CAIRO_MUTEX_IMPL_UNLOCK +#define CAIRO_MUTEX_INIT CAIRO_MUTEX_IMPL_INIT +#define CAIRO_MUTEX_FINI CAIRO_MUTEX_IMPL_FINI +#define CAIRO_MUTEX_NIL_INITIALIZER CAIRO_MUTEX_IMPL_NIL_INITIALIZER + +#define CAIRO_RECURSIVE_MUTEX_INIT CAIRO_RECURSIVE_MUTEX_IMPL_INIT +#define CAIRO_RECURSIVE_MUTEX_NIL_INITIALIZER CAIRO_RECURSIVE_MUTEX_IMPL_NIL_INITIALIZER + +#ifndef CAIRO_MUTEX_IS_LOCKED +# define CAIRO_MUTEX_IS_LOCKED(name) 1 +#endif +#ifndef CAIRO_MUTEX_IS_UNLOCKED +# define CAIRO_MUTEX_IS_UNLOCKED(name) 1 +#endif + + +/* Debugging support */ + +#ifdef CAIRO_MUTEX_DEBUG + +/* TODO add mutex debugging facilities here (eg deadlock detection) */ + +#endif /* CAIRO_MUTEX_DEBUG */ + +#endif diff --git a/local/recipes/libs/cairo/source/src/cairo-mutex.c b/local/recipes/libs/cairo/source/src/cairo-mutex.c new file mode 100644 index 0000000000..89acad5253 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-mutex.c @@ -0,0 +1,113 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2007 Mathias Hasselmann + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * Contributor(s): + * Mathias Hasselmann + */ + +#include "cairoint.h" + +#include "cairo-mutex-private.h" + +#define CAIRO_MUTEX_DECLARE(mutex) cairo_mutex_t mutex = CAIRO_MUTEX_NIL_INITIALIZER; +#include "cairo-mutex-list-private.h" +#undef CAIRO_MUTEX_DECLARE + +#if _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER || _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER + +#define _CAIRO_MUTEX_UNINITIALIZED 0 +#define _CAIRO_MUTEX_INITIALIZING 1 +#define _CAIRO_MUTEX_INITIALIZED 2 + +# if _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER +# define _CAIRO_MUTEX_IMPL_INITIALIZED_DEFAULT_VALUE _CAIRO_MUTEX_UNINITIALIZED +# else +# define _CAIRO_MUTEX_IMPL_INITIALIZED_DEFAULT_VALUE _CAIRO_MUTEX_INITIALIZED +# endif + +#if HAS_ATOMIC_OPS +cairo_atomic_int_t _cairo_mutex_initialized = _CAIRO_MUTEX_IMPL_INITIALIZED_DEFAULT_VALUE; +#else +int _cairo_mutex_initialized = _CAIRO_MUTEX_IMPL_INITIALIZED_DEFAULT_VALUE; +#endif + +# undef _CAIRO_MUTEX_IMPL_INITIALIZED_DEFAULT_VALUE + +#endif + +#if _CAIRO_MUTEX_IMPL_USE_STATIC_INITIALIZER +void _cairo_mutex_initialize (void) +{ +#if HAS_ATOMIC_OPS + int old_value; + do { + old_value = _cairo_atomic_int_cmpxchg_return_old (&_cairo_mutex_initialized, + _CAIRO_MUTEX_UNINITIALIZED, + _CAIRO_MUTEX_INITIALIZING); + if (old_value == _CAIRO_MUTEX_INITIALIZED) + return; + + } while (old_value == _CAIRO_MUTEX_INITIALIZING); +#else + if (_cairo_mutex_initialized == _CAIRO_MUTEX_INITIALIZED) + return; + + _cairo_mutex_initialized = _CAIRO_MUTEX_INITIALIZED; +#endif + +#define CAIRO_MUTEX_DECLARE(mutex) CAIRO_MUTEX_INIT (mutex); +#include "cairo-mutex-list-private.h" +#undef CAIRO_MUTEX_DECLARE + +#if HAS_ATOMIC_OPS + _cairo_atomic_int_set_relaxed (&_cairo_mutex_initialized, _CAIRO_MUTEX_INITIALIZED); +#endif +} +#endif + +#if _CAIRO_MUTEX_IMPL_USE_STATIC_FINALIZER +void _cairo_mutex_finalize (void) +{ +#if HAS_ATOMIC_OPS + if (!_cairo_atomic_int_cmpxchg (&_cairo_mutex_initialized, + _CAIRO_MUTEX_INITIALIZED, + _CAIRO_MUTEX_UNINITIALIZED)) + return; +#else + if (_cairo_mutex_initialized != _CAIRO_MUTEX_INITIALIZED) + return; + + _cairo_mutex_initialized = _CAIRO_MUTEX_UNINITIALIZED; +#endif + +#define CAIRO_MUTEX_DECLARE(mutex) CAIRO_MUTEX_FINI (mutex); +#include "cairo-mutex-list-private.h" +#undef CAIRO_MUTEX_DECLARE +} +#endif diff --git a/local/recipes/libs/cairo/source/src/cairo-no-compositor.c b/local/recipes/libs/cairo/source/src/cairo-no-compositor.c new file mode 100644 index 0000000000..1602a12f63 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-no-compositor.c @@ -0,0 +1,107 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Joonas Pihlaja + * Chris Wilson + */ + +#include "cairoint.h" + +#include "cairo-compositor-private.h" + +static cairo_int_status_t +_cairo_no_compositor_paint (const cairo_compositor_t *_compositor, + cairo_composite_rectangles_t *extents) +{ + ASSERT_NOT_REACHED; + return CAIRO_INT_STATUS_NOTHING_TO_DO; +} + +static cairo_int_status_t +_cairo_no_compositor_mask (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *extents) +{ + ASSERT_NOT_REACHED; + return CAIRO_INT_STATUS_NOTHING_TO_DO; +} + +static cairo_int_status_t +_cairo_no_compositor_stroke (const cairo_compositor_t *_compositor, + cairo_composite_rectangles_t *extents, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias) +{ + ASSERT_NOT_REACHED; + return CAIRO_INT_STATUS_NOTHING_TO_DO; +} + +static cairo_int_status_t +_cairo_no_compositor_fill (const cairo_compositor_t *_compositor, + cairo_composite_rectangles_t *extents, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + ASSERT_NOT_REACHED; + return CAIRO_INT_STATUS_NOTHING_TO_DO; +} + +static cairo_int_status_t +_cairo_no_compositor_glyphs (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *extents, + cairo_scaled_font_t *scaled_font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_bool_t overlap) +{ + ASSERT_NOT_REACHED; + return CAIRO_INT_STATUS_NOTHING_TO_DO; +} + +const cairo_compositor_t __cairo_no_compositor = { + NULL, + _cairo_no_compositor_paint, + _cairo_no_compositor_mask, + _cairo_no_compositor_stroke, + _cairo_no_compositor_fill, + _cairo_no_compositor_glyphs, +}; diff --git a/local/recipes/libs/cairo/source/src/cairo-observer.c b/local/recipes/libs/cairo/source/src/cairo-observer.c new file mode 100644 index 0000000000..36d6b93bd6 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-observer.c @@ -0,0 +1,52 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2010 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Intel Corporation + * + * Contributor(s): + * Chris Wilson + */ + +#include "cairoint.h" + +#include "cairo-list-inline.h" + +void +_cairo_observers_notify (cairo_list_t *observers, void *arg) +{ + cairo_observer_t *obs, *next; + + cairo_list_foreach_entry_safe (obs, next, + cairo_observer_t, + observers, link) + { + obs->callback (obs, arg); + } +} diff --git a/local/recipes/libs/cairo/source/src/cairo-output-stream-private.h b/local/recipes/libs/cairo/source/src/cairo-output-stream-private.h new file mode 100644 index 0000000000..fe091d0c07 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-output-stream-private.h @@ -0,0 +1,201 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2006 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Author(s): + * Kristian Høgsberg + */ + +#ifndef CAIRO_OUTPUT_STREAM_PRIVATE_H +#define CAIRO_OUTPUT_STREAM_PRIVATE_H + +#include "cairo-compiler-private.h" +#include "cairo-types-private.h" + +#include +#include +#include + +typedef cairo_status_t +(*cairo_output_stream_write_func_t) (cairo_output_stream_t *output_stream, + const unsigned char *data, + unsigned int length); + +typedef cairo_status_t +(*cairo_output_stream_flush_func_t) (cairo_output_stream_t *output_stream); + +typedef cairo_status_t +(*cairo_output_stream_close_func_t) (cairo_output_stream_t *output_stream); + +struct _cairo_output_stream { + cairo_output_stream_write_func_t write_func; + cairo_output_stream_flush_func_t flush_func; + cairo_output_stream_close_func_t close_func; + long long position; + cairo_status_t status; + cairo_bool_t closed; +}; + +extern const cairo_private cairo_output_stream_t _cairo_output_stream_nil; + +cairo_private void +_cairo_output_stream_init (cairo_output_stream_t *stream, + cairo_output_stream_write_func_t write_func, + cairo_output_stream_flush_func_t flush_func, + cairo_output_stream_close_func_t close_func); + +cairo_private cairo_status_t +_cairo_output_stream_fini (cairo_output_stream_t *stream); + + +/* We already have the following declared in cairo.h: + +typedef cairo_status_t (*cairo_write_func_t) (void *closure, + const unsigned char *data, + unsigned int length); +*/ +typedef cairo_status_t (*cairo_close_func_t) (void *closure); + + +/* This function never returns %NULL. If an error occurs (NO_MEMORY) + * while trying to create the output stream this function returns a + * valid pointer to a nil output stream. + * + * Note that even with a nil surface, the close_func callback will be + * called by a call to _cairo_output_stream_close or + * _cairo_output_stream_destroy. + */ +cairo_private cairo_output_stream_t * +_cairo_output_stream_create (cairo_write_func_t write_func, + cairo_close_func_t close_func, + void *closure); + +cairo_private cairo_output_stream_t * +_cairo_output_stream_create_in_error (cairo_status_t status); + +/* Tries to flush any buffer maintained by the stream or its delegates. */ +cairo_private cairo_status_t +_cairo_output_stream_flush (cairo_output_stream_t *stream); + +/* Returns the final status value associated with this object, just + * before its last gasp. This final status value will capture any + * status failure returned by the stream's close_func as well. */ +cairo_private cairo_status_t +_cairo_output_stream_close (cairo_output_stream_t *stream); + +/* Returns the final status value associated with this object, just + * before its last gasp. This final status value will capture any + * status failure returned by the stream's close_func as well. */ +cairo_private cairo_status_t +_cairo_output_stream_destroy (cairo_output_stream_t *stream); + +cairo_private void +_cairo_output_stream_write (cairo_output_stream_t *stream, + const void *data, size_t length); + +cairo_private void +_cairo_output_stream_write_hex_string (cairo_output_stream_t *stream, + const unsigned char *data, + size_t length); + +cairo_private void +_cairo_output_stream_vprintf (cairo_output_stream_t *stream, + const char *fmt, + va_list ap) CAIRO_PRINTF_FORMAT ( 2, 0); + +cairo_private void +_cairo_output_stream_printf (cairo_output_stream_t *stream, + const char *fmt, + ...) CAIRO_PRINTF_FORMAT (2, 3); + +/* Print matrix element values with rounding of insignificant digits. */ +cairo_private void +_cairo_output_stream_print_matrix (cairo_output_stream_t *stream, + const cairo_matrix_t *matrix); + +cairo_private long long +_cairo_output_stream_get_position (cairo_output_stream_t *stream); + +cairo_private cairo_status_t +_cairo_output_stream_get_status (cairo_output_stream_t *stream); + +/* This function never returns %NULL. If an error occurs (NO_MEMORY or + * WRITE_ERROR) while trying to create the output stream this function + * returns a valid pointer to a nil output stream. + * + * Note: Even if a nil surface is returned, the caller should still + * call _cairo_output_stream_destroy (or _cairo_output_stream_close at + * least) in order to ensure that everything is properly cleaned up. + */ +cairo_private cairo_output_stream_t * +_cairo_output_stream_create_for_filename (const char *filename); + +/* This function never returns %NULL. If an error occurs (NO_MEMORY or + * WRITE_ERROR) while trying to create the output stream this function + * returns a valid pointer to a nil output stream. + * + * The caller still "owns" file and is responsible for calling fclose + * on it when finished. The stream will not do this itself. + */ +cairo_private cairo_output_stream_t * +_cairo_output_stream_create_for_file (FILE *file); + +cairo_private cairo_output_stream_t * +_cairo_memory_stream_create (void); + +cairo_private void +_cairo_memory_stream_copy (cairo_output_stream_t *base, + cairo_output_stream_t *dest); + +cairo_private int +_cairo_memory_stream_length (cairo_output_stream_t *stream); + +cairo_private cairo_status_t +_cairo_memory_stream_destroy (cairo_output_stream_t *abstract_stream, + unsigned char **data_out, + unsigned long *length_out); + +cairo_private cairo_output_stream_t * +_cairo_null_stream_create (void); + +/* cairo-base85-stream.c */ +cairo_private cairo_output_stream_t * +_cairo_base85_stream_create (cairo_output_stream_t *output); + +/* cairo-base64-stream.c */ +cairo_private cairo_output_stream_t * +_cairo_base64_stream_create (cairo_output_stream_t *output); + +/* cairo-deflate-stream.c */ +cairo_private cairo_output_stream_t * +_cairo_deflate_stream_create (cairo_output_stream_t *output); + + +#endif /* CAIRO_OUTPUT_STREAM_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-output-stream.c b/local/recipes/libs/cairo/source/src/cairo-output-stream.c new file mode 100644 index 0000000000..799a73e04f --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-output-stream.c @@ -0,0 +1,824 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo-output-stream.c: Output stream abstraction + * + * Copyright © 2005 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Author(s): + * Kristian Høgsberg + */ + +#define _DEFAULT_SOURCE /* for snprintf() */ +#include "cairoint.h" + +#include "cairo-output-stream-private.h" + +#include "cairo-array-private.h" +#include "cairo-error-private.h" +#include "cairo-compiler-private.h" + +#include +#include + +/* Numbers printed with %f are printed with this number of significant + * digits after the decimal. + */ +#define SIGNIFICANT_DIGITS_AFTER_DECIMAL 6 + +/* Numbers printed with %g are assumed to only have %CAIRO_FIXED_FRAC_BITS + * bits of precision available after the decimal point. + * + * FIXED_POINT_DECIMAL_DIGITS specifies the minimum number of decimal + * digits after the decimal point required to preserve the available + * precision. + * + * The conversion is: + * + * + * FIXED_POINT_DECIMAL_DIGITS = ceil( CAIRO_FIXED_FRAC_BITS * ln(2)/ln(10) ) + * + * + * We can replace ceil(x) with (int)(x+1) since x will never be an + * integer for any likely value of %CAIRO_FIXED_FRAC_BITS. + */ +#define FIXED_POINT_DECIMAL_DIGITS ((int)(CAIRO_FIXED_FRAC_BITS*0.301029996 + 1)) + +void +_cairo_output_stream_init (cairo_output_stream_t *stream, + cairo_output_stream_write_func_t write_func, + cairo_output_stream_flush_func_t flush_func, + cairo_output_stream_close_func_t close_func) +{ + stream->write_func = write_func; + stream->flush_func = flush_func; + stream->close_func = close_func; + stream->position = 0; + stream->status = CAIRO_STATUS_SUCCESS; + stream->closed = FALSE; +} + +cairo_status_t +_cairo_output_stream_fini (cairo_output_stream_t *stream) +{ + return _cairo_output_stream_close (stream); +} + +const cairo_output_stream_t _cairo_output_stream_nil = { + NULL, /* write_func */ + NULL, /* flush_func */ + NULL, /* close_func */ + 0, /* position */ + CAIRO_STATUS_NO_MEMORY, + FALSE /* closed */ +}; + +static const cairo_output_stream_t _cairo_output_stream_nil_write_error = { + NULL, /* write_func */ + NULL, /* flush_func */ + NULL, /* close_func */ + 0, /* position */ + CAIRO_STATUS_WRITE_ERROR, + FALSE /* closed */ +}; + +typedef struct _cairo_output_stream_with_closure { + cairo_output_stream_t base; + cairo_write_func_t write_func; + cairo_close_func_t close_func; + void *closure; +} cairo_output_stream_with_closure_t; + + +static cairo_status_t +closure_write (cairo_output_stream_t *stream, + const unsigned char *data, unsigned int length) +{ + cairo_output_stream_with_closure_t *stream_with_closure = + (cairo_output_stream_with_closure_t *) stream; + + if (stream_with_closure->write_func == NULL) + return CAIRO_STATUS_SUCCESS; + + return stream_with_closure->write_func (stream_with_closure->closure, + data, length); +} + +static cairo_status_t +closure_close (cairo_output_stream_t *stream) +{ + cairo_output_stream_with_closure_t *stream_with_closure = + (cairo_output_stream_with_closure_t *) stream; + + if (stream_with_closure->close_func != NULL) + return stream_with_closure->close_func (stream_with_closure->closure); + else + return CAIRO_STATUS_SUCCESS; +} + +cairo_output_stream_t * +_cairo_output_stream_create (cairo_write_func_t write_func, + cairo_close_func_t close_func, + void *closure) +{ + cairo_output_stream_with_closure_t *stream; + + stream = _cairo_calloc (sizeof (cairo_output_stream_with_closure_t)); + if (unlikely (stream == NULL)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_output_stream_t *) &_cairo_output_stream_nil; + } + + _cairo_output_stream_init (&stream->base, + closure_write, NULL, closure_close); + stream->write_func = write_func; + stream->close_func = close_func; + stream->closure = closure; + + return &stream->base; +} + +cairo_output_stream_t * +_cairo_output_stream_create_in_error (cairo_status_t status) +{ + cairo_output_stream_t *stream; + + /* check for the common ones */ + if (status == CAIRO_STATUS_NO_MEMORY) + return (cairo_output_stream_t *) &_cairo_output_stream_nil; + if (status == CAIRO_STATUS_WRITE_ERROR) + return (cairo_output_stream_t *) &_cairo_output_stream_nil_write_error; + + stream = _cairo_calloc (sizeof (cairo_output_stream_t)); + if (unlikely (stream == NULL)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_output_stream_t *) &_cairo_output_stream_nil; + } + + _cairo_output_stream_init (stream, NULL, NULL, NULL); + stream->status = status; + + return stream; +} + +cairo_status_t +_cairo_output_stream_flush (cairo_output_stream_t *stream) +{ + cairo_status_t status; + + if (stream->closed) + return stream->status; + + if (stream == &_cairo_output_stream_nil || + stream == &_cairo_output_stream_nil_write_error) + { + return stream->status; + } + + if (stream->flush_func) { + status = stream->flush_func (stream); + /* Don't overwrite a pre-existing status failure. */ + if (stream->status == CAIRO_STATUS_SUCCESS) + stream->status = status; + } + + return stream->status; +} + +cairo_status_t +_cairo_output_stream_close (cairo_output_stream_t *stream) +{ + cairo_status_t status; + + if (stream->closed) + return stream->status; + + if (stream == &_cairo_output_stream_nil || + stream == &_cairo_output_stream_nil_write_error) + { + return stream->status; + } + + if (stream->close_func) { + status = stream->close_func (stream); + /* Don't overwrite a pre-existing status failure. */ + if (stream->status == CAIRO_STATUS_SUCCESS) + stream->status = status; + } + + stream->closed = TRUE; + + return stream->status; +} + +cairo_status_t +_cairo_output_stream_destroy (cairo_output_stream_t *stream) +{ + cairo_status_t status; + + assert (stream != NULL); + + if (stream == &_cairo_output_stream_nil || + stream == &_cairo_output_stream_nil_write_error) + { + return stream->status; + } + + status = _cairo_output_stream_fini (stream); + free (stream); + + return status; +} + +void +_cairo_output_stream_write (cairo_output_stream_t *stream, + const void *data, size_t length) +{ + if (length == 0 || stream->status) + return; + + if (stream->closed) { + stream->status = CAIRO_STATUS_WRITE_ERROR; + return; + } + + stream->status = stream->write_func (stream, data, length); + stream->position += length; +} + +void +_cairo_output_stream_write_hex_string (cairo_output_stream_t *stream, + const unsigned char *data, + size_t length) +{ + const char hex_chars[] = "0123456789abcdef"; + char buffer[2]; + unsigned int i, column; + + for (i = 0, column = 0; i < length; i++, column++) { + if (column == 38) { + _cairo_output_stream_write (stream, "\n", 1); + column = 0; + } + buffer[0] = hex_chars[(data[i] >> 4) & 0x0f]; + buffer[1] = hex_chars[data[i] & 0x0f]; + _cairo_output_stream_write (stream, buffer, 2); + } +} + +/* Format a double in a locale independent way and trim trailing + * zeros. Based on code from Alex Larson . + * https://mail.gnome.org/archives/gtk-devel-list/2001-October/msg00087.html + * + * The code in the patch is copyright Red Hat, Inc under the LGPL, but + * has been relicensed under the LGPL/MPL dual license for inclusion + * into cairo (see COPYING). -- Kristian Høgsberg + */ +static void +_cairo_dtostr (char *buffer, size_t size, double d, cairo_bool_t limited_precision) +{ + const char *decimal_point; + int decimal_point_len; + char *p; + int decimal_len; + int num_zeros, decimal_digits; + + /* Omit the minus sign from negative zero. */ + if (d == 0.0) + d = 0.0; + + decimal_point = _cairo_get_locale_decimal_point (); + decimal_point_len = strlen (decimal_point); + + assert (decimal_point_len != 0); + + if (limited_precision) { + snprintf (buffer, size, "%.*f", FIXED_POINT_DECIMAL_DIGITS, d); + } else { + /* Using "%f" to print numbers less than 0.1 will result in + * reduced precision due to the default 6 digits after the + * decimal point. + * + * For numbers is < 0.1, we print with maximum precision and count + * the number of zeros between the decimal point and the first + * significant digit. We then print the number again with the + * number of decimal places that gives us the required number of + * significant digits. This ensures the number is correctly + * rounded. + */ + if (fabs (d) >= 0.1) { + snprintf (buffer, size, "%f", d); + } else { + snprintf (buffer, size, "%.18f", d); + p = buffer; + + if (*p == '+' || *p == '-') + p++; + + while (_cairo_isdigit (*p)) + p++; + + if (strncmp (p, decimal_point, decimal_point_len) == 0) + p += decimal_point_len; + + num_zeros = 0; + while (*p++ == '0') + num_zeros++; + + decimal_digits = num_zeros + SIGNIFICANT_DIGITS_AFTER_DECIMAL; + + if (decimal_digits < 18) + snprintf (buffer, size, "%.*f", decimal_digits, d); + } + } + p = buffer; + + if (*p == '+' || *p == '-') + p++; + + while (_cairo_isdigit (*p)) + p++; + + if (strncmp (p, decimal_point, decimal_point_len) == 0) { + *p = '.'; + decimal_len = strlen (p + decimal_point_len); + memmove (p + 1, p + decimal_point_len, decimal_len); + p[1 + decimal_len] = 0; + + /* Remove trailing zeros and decimal point if possible. */ + for (p = p + decimal_len; *p == '0'; p--) + *p = 0; + + if (*p == '.') { + *p = 0; + p--; + } + } +} + +enum { + LENGTH_MODIFIER_LONG = 0x100, + LENGTH_MODIFIER_LONG_LONG = 0x200 +}; + +/* Here's a limited reimplementation of printf. The reason for doing + * this is primarily to special case handling of doubles. We want + * locale independent formatting of doubles and we want to trim + * trailing zeros. This is handled by dtostr() above, and the code + * below handles everything else by calling snprintf() to do the + * formatting. This functionality is only for internal use and we + * only implement the formats we actually use. + */ +void +_cairo_output_stream_vprintf (cairo_output_stream_t *stream, + const char *fmt, va_list ap) +{ +#define SINGLE_FMT_BUFFER_SIZE 32 + char buffer[512], single_fmt[SINGLE_FMT_BUFFER_SIZE]; + int single_fmt_length; + char *p; + const char *f, *start; + int length_modifier, width; + cairo_bool_t var_width; + + f = fmt; + p = buffer; + while (*f != '\0') { + if (p == buffer + sizeof (buffer)) { + _cairo_output_stream_write (stream, buffer, sizeof (buffer)); + p = buffer; + } + + if (*f != '%') { + *p++ = *f++; + continue; + } + + start = f; + f++; + + if (*f == '0') + f++; + + var_width = FALSE; + if (*f == '*') { + var_width = TRUE; + f++; + } + + while (_cairo_isdigit (*f)) + f++; + + length_modifier = 0; + if (*f == 'l') { + length_modifier = LENGTH_MODIFIER_LONG; + f++; + if (*f == 'l') { + length_modifier = LENGTH_MODIFIER_LONG_LONG; + f++; + } + } + + /* The only format strings exist in the cairo implementation + * itself. So there's an internal consistency problem if any + * of them is larger than our format buffer size. */ + single_fmt_length = f - start + 1; + assert (single_fmt_length + 1 <= SINGLE_FMT_BUFFER_SIZE); + + /* Reuse the format string for this conversion. */ + memcpy (single_fmt, start, single_fmt_length); + single_fmt[single_fmt_length] = '\0'; + + /* Flush contents of buffer before snprintf()'ing into it. */ + _cairo_output_stream_write (stream, buffer, p - buffer); + + /* We group signed and unsigned together in this switch, the + * only thing that matters here is the size of the arguments, + * since we're just passing the data through to sprintf(). */ + switch (*f | length_modifier) { + case '%': + buffer[0] = *f; + buffer[1] = 0; + break; + case 'd': + case 'u': + case 'o': + case 'x': + case 'X': + if (var_width) { + width = va_arg (ap, int); + snprintf (buffer, sizeof buffer, + single_fmt, width, va_arg (ap, int)); + } else { + snprintf (buffer, sizeof buffer, single_fmt, va_arg (ap, int)); + } + break; + case 'd' | LENGTH_MODIFIER_LONG: + case 'u' | LENGTH_MODIFIER_LONG: + case 'o' | LENGTH_MODIFIER_LONG: + case 'x' | LENGTH_MODIFIER_LONG: + case 'X' | LENGTH_MODIFIER_LONG: + if (var_width) { + width = va_arg (ap, int); + snprintf (buffer, sizeof buffer, + single_fmt, width, va_arg (ap, long int)); + } else { + snprintf (buffer, sizeof buffer, + single_fmt, va_arg (ap, long int)); + } + break; + case 'd' | LENGTH_MODIFIER_LONG_LONG: + case 'u' | LENGTH_MODIFIER_LONG_LONG: + case 'o' | LENGTH_MODIFIER_LONG_LONG: + case 'x' | LENGTH_MODIFIER_LONG_LONG: + case 'X' | LENGTH_MODIFIER_LONG_LONG: + if (var_width) { + width = va_arg (ap, int); + snprintf (buffer, sizeof buffer, + single_fmt, width, va_arg (ap, long long int)); + } else { + snprintf (buffer, sizeof buffer, + single_fmt, va_arg (ap, long long int)); + } + break; + case 's': { + /* Write out strings as they may be larger than the buffer. */ + const char *s = va_arg (ap, const char *); + int len = strlen(s); + _cairo_output_stream_write (stream, s, len); + buffer[0] = 0; + } + break; + case 'f': + _cairo_dtostr (buffer, sizeof buffer, va_arg (ap, double), FALSE); + break; + case 'g': + _cairo_dtostr (buffer, sizeof buffer, va_arg (ap, double), TRUE); + break; + case 'c': + buffer[0] = va_arg (ap, int); + buffer[1] = 0; + break; + default: + ASSERT_NOT_REACHED; + } + p = buffer + strlen (buffer); + f++; + } + + _cairo_output_stream_write (stream, buffer, p - buffer); +} + +void +_cairo_output_stream_printf (cairo_output_stream_t *stream, + const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + + _cairo_output_stream_vprintf (stream, fmt, ap); + + va_end (ap); +} + +/* Matrix elements that are smaller than the value of the largest element * MATRIX_ROUNDING_TOLERANCE + * are rounded down to zero. */ +#define MATRIX_ROUNDING_TOLERANCE 1e-12 + +void +_cairo_output_stream_print_matrix (cairo_output_stream_t *stream, + const cairo_matrix_t *matrix) +{ + cairo_matrix_t m; + double s, e; + + m = *matrix; + s = fabs (m.xx); + if (fabs (m.xy) > s) + s = fabs (m.xy); + if (fabs (m.yx) > s) + s = fabs (m.yx); + if (fabs (m.yy) > s) + s = fabs (m.yy); + + e = s * MATRIX_ROUNDING_TOLERANCE; + if (fabs(m.xx) < e) + m.xx = 0; + if (fabs(m.xy) < e) + m.xy = 0; + if (fabs(m.yx) < e) + m.yx = 0; + if (fabs(m.yy) < e) + m.yy = 0; + if (fabs(m.x0) < e) + m.x0 = 0; + if (fabs(m.y0) < e) + m.y0 = 0; + + _cairo_output_stream_printf (stream, + "%f %f %f %f %f %f", + m.xx, m.yx, m.xy, m.yy, m.x0, m.y0); +} + +long long +_cairo_output_stream_get_position (cairo_output_stream_t *stream) +{ + return stream->position; +} + +cairo_status_t +_cairo_output_stream_get_status (cairo_output_stream_t *stream) +{ + return stream->status; +} + +/* Maybe this should be a configure time option, so embedded targets + * don't have to pull in stdio. */ + + +typedef struct _stdio_stream { + cairo_output_stream_t base; + FILE *file; +} stdio_stream_t; + +static cairo_status_t +stdio_write (cairo_output_stream_t *base, + const unsigned char *data, unsigned int length) +{ + stdio_stream_t *stream = (stdio_stream_t *) base; + + if (fwrite (data, 1, length, stream->file) != length) + return _cairo_error (CAIRO_STATUS_WRITE_ERROR); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +stdio_flush (cairo_output_stream_t *base) +{ + stdio_stream_t *stream = (stdio_stream_t *) base; + + fflush (stream->file); + + if (ferror (stream->file)) + return _cairo_error (CAIRO_STATUS_WRITE_ERROR); + else + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +stdio_close (cairo_output_stream_t *base) +{ + cairo_status_t status; + stdio_stream_t *stream = (stdio_stream_t *) base; + + status = stdio_flush (base); + + fclose (stream->file); + + return status; +} + +cairo_output_stream_t * +_cairo_output_stream_create_for_file (FILE *file) +{ + stdio_stream_t *stream; + + if (file == NULL) { + _cairo_error_throw (CAIRO_STATUS_WRITE_ERROR); + return (cairo_output_stream_t *) &_cairo_output_stream_nil_write_error; + } + + stream = _cairo_calloc (sizeof *stream); + if (unlikely (stream == NULL)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_output_stream_t *) &_cairo_output_stream_nil; + } + + _cairo_output_stream_init (&stream->base, + stdio_write, stdio_flush, stdio_flush); + stream->file = file; + + return &stream->base; +} + +cairo_output_stream_t * +_cairo_output_stream_create_for_filename (const char *filename) +{ + stdio_stream_t *stream; + FILE *file; + cairo_status_t status; + + if (filename == NULL) + return _cairo_null_stream_create (); + + status = _cairo_fopen (filename, "wb", &file); + + if (status != CAIRO_STATUS_SUCCESS) + return _cairo_output_stream_create_in_error (status); + + if (file == NULL) { + switch (errno) { + case ENOMEM: + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_output_stream_t *) &_cairo_output_stream_nil; + default: + _cairo_error_throw (CAIRO_STATUS_WRITE_ERROR); + return (cairo_output_stream_t *) &_cairo_output_stream_nil_write_error; + } + } + + stream = _cairo_calloc (sizeof *stream); + if (unlikely (stream == NULL)) { + fclose (file); + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_output_stream_t *) &_cairo_output_stream_nil; + } + + _cairo_output_stream_init (&stream->base, + stdio_write, stdio_flush, stdio_close); + stream->file = file; + + return &stream->base; +} + + +typedef struct _memory_stream { + cairo_output_stream_t base; + cairo_array_t array; +} memory_stream_t; + +static cairo_status_t +memory_write (cairo_output_stream_t *base, + const unsigned char *data, unsigned int length) +{ + memory_stream_t *stream = (memory_stream_t *) base; + + return _cairo_array_append_multiple (&stream->array, data, length); +} + +static cairo_status_t +memory_close (cairo_output_stream_t *base) +{ + memory_stream_t *stream = (memory_stream_t *) base; + + _cairo_array_fini (&stream->array); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_output_stream_t * +_cairo_memory_stream_create (void) +{ + memory_stream_t *stream; + + stream = _cairo_calloc (sizeof *stream); + if (unlikely (stream == NULL)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_output_stream_t *) &_cairo_output_stream_nil; + } + + _cairo_output_stream_init (&stream->base, memory_write, NULL, memory_close); + _cairo_array_init (&stream->array, 1); + + return &stream->base; +} + +cairo_status_t +_cairo_memory_stream_destroy (cairo_output_stream_t *abstract_stream, + unsigned char **data_out, + unsigned long *length_out) +{ + memory_stream_t *stream; + cairo_status_t status; + + status = abstract_stream->status; + if (unlikely (status)) + return _cairo_output_stream_destroy (abstract_stream); + + stream = (memory_stream_t *) abstract_stream; + + *length_out = _cairo_array_num_elements (&stream->array); + *data_out = _cairo_calloc (*length_out); + if (unlikely (*data_out == NULL)) { + status = _cairo_output_stream_destroy (abstract_stream); + assert (status == CAIRO_STATUS_SUCCESS); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + memcpy (*data_out, _cairo_array_index (&stream->array, 0), *length_out); + + return _cairo_output_stream_destroy (abstract_stream); +} + +void +_cairo_memory_stream_copy (cairo_output_stream_t *base, + cairo_output_stream_t *dest) +{ + memory_stream_t *stream = (memory_stream_t *) base; + + if (base->status) { + dest->status = base->status; + return; + } + + _cairo_output_stream_write (dest, + _cairo_array_index (&stream->array, 0), + _cairo_array_num_elements (&stream->array)); +} + +int +_cairo_memory_stream_length (cairo_output_stream_t *base) +{ + memory_stream_t *stream = (memory_stream_t *) base; + + return _cairo_array_num_elements (&stream->array); +} + +static cairo_status_t +null_write (cairo_output_stream_t *base, + const unsigned char *data, unsigned int length) +{ + return CAIRO_STATUS_SUCCESS; +} + +cairo_output_stream_t * +_cairo_null_stream_create (void) +{ + cairo_output_stream_t *stream; + + stream = _cairo_calloc (sizeof *stream); + if (unlikely (stream == NULL)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_output_stream_t *) &_cairo_output_stream_nil; + } + + _cairo_output_stream_init (stream, null_write, NULL, NULL); + + return stream; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-paginated-private.h b/local/recipes/libs/cairo/source/src/cairo-paginated-private.h new file mode 100644 index 0000000000..cc8fd1c7b4 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-paginated-private.h @@ -0,0 +1,184 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Carl Worth + */ + +#ifndef CAIRO_PAGINATED_H +#define CAIRO_PAGINATED_H + +#include "cairoint.h" + +struct _cairo_paginated_surface_backend { + /* Optional. Will be called once for each page. + * + * Note: With respect to the order of drawing operations as seen + * by the target, this call will occur before any drawing + * operations for the relevant page. However, with respect to the + * function calls as made by the user, this call will be *after* + * any drawing operations for the page, (that is, it will occur + * during the user's call to cairo_show_page or cairo_copy_page). + */ + cairo_warn cairo_int_status_t + (*start_page) (void *surface); + + /* Required. Will be called twice for each page, once with an + * argument of CAIRO_PAGINATED_MODE_ANALYZE and once with + * CAIRO_PAGINATED_MODE_RENDER. See more details in the + * documentation for _cairo_paginated_surface_create below. + */ + cairo_warn cairo_int_status_t + (*set_paginated_mode) (void *surface, + cairo_paginated_mode_t mode); + + /* Optional. Specifies the smallest box that encloses all objects + * on the page. Will be called at the end of the ANALYZE phase but + * before the mode is changed to RENDER. + */ + cairo_warn cairo_int_status_t + (*set_bounding_box) (void *surface, + cairo_box_t *bbox); + + /* Optional. Indicates whether the page requires fallback images. + * Will be called at the end of the ANALYZE phase but before the + * mode is changed to RENDER. + */ + cairo_warn cairo_int_status_t + (*set_fallback_images_required) (void *surface, + cairo_bool_t fallbacks_required); + + cairo_bool_t + (*supports_fine_grained_fallbacks) (void *surface); + + /* Optional. Indicates whether the page requires a thumbnail image to be + * supplied. If a thumbnail is required, set width, height to size required + * and return TRUE. + */ + cairo_bool_t + (*requires_thumbnail_image) (void *surface, + int *width, + int *height); + + /* If thumbbail image requested, this function will be called before + * _show_page(). + */ + cairo_warn cairo_int_status_t + (*set_thumbnail_image) (void *surface, + cairo_image_surface_t *image); +}; + +/* A #cairo_paginated_surface_t provides a very convenient wrapper that + * is well-suited for doing the analysis common to most surfaces that + * have paginated output, (that is, things directed at printers, or + * for saving content in files such as PostScript or PDF files). + * + * To use the paginated surface, you'll first need to create your + * 'real' surface using _cairo_surface_init() and the standard + * #cairo_surface_backend_t. Then you also call + * _cairo_paginated_surface_create which takes its own, much simpler, + * #cairo_paginated_surface_backend_t. You are free to return the result + * of _cairo_paginated_surface_create() from your public + * cairo__surface_create(). The paginated backend will be careful + * to not let the user see that they really got a "wrapped" + * surface. See test-paginated-surface.c for a fairly minimal example + * of a paginated-using surface. That should be a reasonable example + * to follow. + * + * What the paginated surface does is first save all drawing + * operations for a page into a recording-surface. Then when the user calls + * cairo_show_page(), the paginated surface performs the following + * sequence of operations (using the backend functions passed to + * cairo_paginated_surface_create()): + * + * 1. Calls start_page() (if not %NULL). At this point, it is appropriate + * for the target to emit any page-specific header information into + * its output. + * + * 2. Calls set_paginated_mode() with an argument of %CAIRO_PAGINATED_MODE_ANALYZE + * + * 3. Replays the recording-surface to the target surface, (with an + * analysis surface inserted between which watches the return value + * from each operation). This analysis stage is used to decide which + * operations will require fallbacks. + * + * 4. Calls set_bounding_box() to provide the target surface with the + * tight bounding box of the page. + * + * 5. Calls set_paginated_mode() with an argument of %CAIRO_PAGINATED_MODE_RENDER + * + * 6. Replays a subset of the recording-surface operations to the target surface + * + * 7. Calls set_paginated_mode() with an argument of %CAIRO_PAGINATED_MODE_FALLBACK + * + * 8. Replays the remaining operations to an image surface, sets an + * appropriate clip on the target, then paints the resulting image + * surface to the target. + * + * So, the target will see drawing operations during three separate + * stages, (ANALYZE, RENDER and FALLBACK). During the ANALYZE phase + * the target should not actually perform any rendering, (for example, + * if performing output to a file, no output should be generated + * during this stage). Instead the drawing functions simply need to + * return %CAIRO_STATUS_SUCCESS or %CAIRO_INT_STATUS_UNSUPPORTED to + * indicate whether rendering would be supported. And it should do + * this as quickly as possible. The FALLBACK phase allows the surface + * to distinguish fallback images from native rendering in case they + * need to be handled as a special case. + * + * Note: The paginated surface layer assumes that the target surface + * is "blank" by default at the beginning of each page, without any + * need for an explicit erase operation, (as opposed to an image + * surface, for example, which might have uninitialized content + * originally). As such, it optimizes away CLEAR operations that + * happen at the beginning of each page---the target surface will not + * even see these operations. + */ +cairo_private cairo_surface_t * +_cairo_paginated_surface_create (cairo_surface_t *target, + cairo_content_t content, + const cairo_paginated_surface_backend_t *backend); + +cairo_private cairo_surface_t * +_cairo_paginated_surface_get_target (cairo_surface_t *surface); + +cairo_private cairo_surface_t * +_cairo_paginated_surface_get_recording (cairo_surface_t *surface); + +cairo_private cairo_bool_t +_cairo_surface_is_paginated (cairo_surface_t *surface); + +cairo_private cairo_status_t +_cairo_paginated_surface_set_size (cairo_surface_t *surface, + double width, + double height); + +#endif /* CAIRO_PAGINATED_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-paginated-surface-private.h b/local/recipes/libs/cairo/source/src/cairo-paginated-surface-private.h new file mode 100644 index 0000000000..ebf4b34249 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-paginated-surface-private.h @@ -0,0 +1,62 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Carl Worth + */ + +#ifndef CAIRO_PAGINATED_SURFACE_H +#define CAIRO_PAGINATED_SURFACE_H + +#include "cairo.h" + +#include "cairo-surface-private.h" + +typedef struct _cairo_paginated_surface { + cairo_surface_t base; + + /* The target surface to hold the final result. */ + cairo_surface_t *target; + + cairo_content_t content; + + /* Paginated-surface specific functions for the target */ + const cairo_paginated_surface_backend_t *backend; + + /* A cairo_recording_surface to record all operations. To be replayed + * against target, and also against image surface as necessary for + * fallbacks. */ + cairo_surface_t *recording_surface; + + int page_num; +} cairo_paginated_surface_t; + +#endif /* CAIRO_PAGINATED_SURFACE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-paginated-surface.c b/local/recipes/libs/cairo/source/src/cairo-paginated-surface.c new file mode 100644 index 0000000000..ff05ecd519 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-paginated-surface.c @@ -0,0 +1,831 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * Copyright © 2007 Adrian Johnson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Carl Worth + * Keith Packard + * Adrian Johnson + */ + +/* The paginated surface layer exists to provide as much code sharing + * as possible for the various paginated surface backends in cairo + * (PostScript, PDF, etc.). See cairo-paginated-private.h for + * more details on how it works and how to use it. + */ + +#include "cairoint.h" + +#include "cairo-paginated-private.h" +#include "cairo-paginated-surface-private.h" +#include "cairo-recording-surface-private.h" +#include "cairo-analysis-surface-private.h" +#include "cairo-error-private.h" +#include "cairo-image-surface-private.h" +#include "cairo-surface-subsurface-inline.h" + +static const cairo_surface_backend_t cairo_paginated_surface_backend; + +static cairo_int_status_t +_cairo_paginated_surface_show_page (void *abstract_surface); + +static cairo_surface_t * +_cairo_paginated_surface_create_similar (void *abstract_surface, + cairo_content_t content, + int width, + int height) +{ + cairo_rectangle_t rect; + rect.x = rect.y = 0.; + rect.width = width; + rect.height = height; + return cairo_recording_surface_create (content, &rect); +} + +static cairo_surface_t * +_create_recording_surface_for_target (cairo_surface_t *target, + cairo_content_t content) +{ + cairo_rectangle_int_t rect; + + if (_cairo_surface_get_extents (target, &rect)) { + cairo_rectangle_t recording_extents; + + recording_extents.x = rect.x; + recording_extents.y = rect.y; + recording_extents.width = rect.width; + recording_extents.height = rect.height; + + return cairo_recording_surface_create (content, &recording_extents); + } else { + return cairo_recording_surface_create (content, NULL); + } +} + +cairo_surface_t * +_cairo_paginated_surface_create (cairo_surface_t *target, + cairo_content_t content, + const cairo_paginated_surface_backend_t *backend) +{ + cairo_paginated_surface_t *surface; + cairo_status_t status; + + surface = _cairo_calloc (sizeof (cairo_paginated_surface_t)); + if (unlikely (surface == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto FAIL; + } + + _cairo_surface_init (&surface->base, + &cairo_paginated_surface_backend, + NULL, /* device */ + content, + target->is_vector); + + /* Override surface->base.type with target's type so we don't leak + * evidence of the paginated wrapper out to the user. */ + surface->base.type = target->type; + + surface->target = cairo_surface_reference (target); + + surface->content = content; + surface->backend = backend; + + surface->recording_surface = _create_recording_surface_for_target (target, content); + status = surface->recording_surface->status; + if (unlikely (status)) + goto FAIL_CLEANUP_SURFACE; + + surface->page_num = 1; + surface->base.is_clear = TRUE; + + return &surface->base; + + FAIL_CLEANUP_SURFACE: + cairo_surface_destroy (target); + free (surface); + FAIL: + return _cairo_surface_create_in_error (status); +} + +cairo_bool_t +_cairo_surface_is_paginated (cairo_surface_t *surface) +{ + return surface->backend == &cairo_paginated_surface_backend; +} + +cairo_surface_t * +_cairo_paginated_surface_get_target (cairo_surface_t *surface) +{ + cairo_paginated_surface_t *paginated_surface; + + assert (_cairo_surface_is_paginated (surface)); + + paginated_surface = (cairo_paginated_surface_t *) surface; + return paginated_surface->target; +} + +cairo_surface_t * +_cairo_paginated_surface_get_recording (cairo_surface_t *surface) +{ + cairo_paginated_surface_t *paginated_surface; + + assert (_cairo_surface_is_paginated (surface)); + + paginated_surface = (cairo_paginated_surface_t *) surface; + return paginated_surface->recording_surface; +} + +cairo_status_t +_cairo_paginated_surface_set_size (cairo_surface_t *surface, + double width, + double height) +{ + cairo_paginated_surface_t *paginated_surface; + cairo_status_t status; + cairo_rectangle_t recording_extents; + + assert (_cairo_surface_is_paginated (surface)); + + paginated_surface = (cairo_paginated_surface_t *) surface; + + recording_extents.x = 0; + recording_extents.y = 0; + recording_extents.width = width; + recording_extents.height = height; + + cairo_surface_destroy (paginated_surface->recording_surface); + paginated_surface->recording_surface = cairo_recording_surface_create (paginated_surface->content, + &recording_extents); + status = paginated_surface->recording_surface->status; + if (unlikely (status)) + return _cairo_surface_set_error (surface, status); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_paginated_surface_finish (void *abstract_surface) +{ + cairo_paginated_surface_t *surface = abstract_surface; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + if (! surface->base.is_clear || surface->page_num == 1) { + /* Bypass some of the sanity checking in cairo-surface.c, as we + * know that the surface is finished... + */ + status = _cairo_paginated_surface_show_page (surface); + } + + /* XXX We want to propagate any errors from destroy(), but those are not + * returned via the api. So we need to explicitly finish the target, + * and check the status afterwards. However, we can only call finish() + * on the target, if we own it. + */ + if (CAIRO_REFERENCE_COUNT_GET_VALUE (&surface->target->ref_count) == 1) + cairo_surface_finish (surface->target); + if (status == CAIRO_STATUS_SUCCESS) + status = cairo_surface_status (surface->target); + cairo_surface_destroy (surface->target); + + cairo_surface_finish (surface->recording_surface); + if (status == CAIRO_STATUS_SUCCESS) + status = cairo_surface_status (surface->recording_surface); + cairo_surface_destroy (surface->recording_surface); + + return status; +} + +static cairo_surface_t * +_cairo_paginated_surface_create_image_surface (void *abstract_surface, + int width, + int height) +{ + cairo_paginated_surface_t *surface = abstract_surface; + cairo_surface_t *image; + cairo_font_options_t options; + + image = _cairo_image_surface_create_with_content (surface->content, + width, + height); + + cairo_surface_get_font_options (&surface->base, &options); + _cairo_surface_set_font_options (image, &options); + + return image; +} + +static cairo_surface_t * +_cairo_paginated_surface_source (void *abstract_surface, + cairo_rectangle_int_t *extents) +{ + cairo_paginated_surface_t *surface = abstract_surface; + return _cairo_surface_get_source (surface->target, extents); +} + +static cairo_status_t +_cairo_paginated_surface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) +{ + cairo_paginated_surface_t *surface = abstract_surface; + cairo_bool_t is_bounded; + cairo_surface_t *image; + cairo_status_t status; + cairo_rectangle_int_t extents; + + is_bounded = _cairo_surface_get_extents (surface->target, &extents); + if (! is_bounded) + return CAIRO_INT_STATUS_UNSUPPORTED; + + image = _cairo_paginated_surface_create_image_surface (surface, + extents.width, + extents.height); + + status = _cairo_recording_surface_replay (surface->recording_surface, image); + if (unlikely (status)) { + cairo_surface_destroy (image); + return status; + } + + *image_out = (cairo_image_surface_t*) image; + *image_extra = NULL; + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_paginated_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) +{ + cairo_surface_destroy (&image->base); +} + +static cairo_int_status_t +_paint_thumbnail_image (cairo_paginated_surface_t *surface, + int width, + int height) +{ + cairo_surface_pattern_t pattern; + cairo_rectangle_int_t extents; + double x_scale; + double y_scale; + cairo_surface_t *image = NULL; + cairo_surface_t *opaque = NULL; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + _cairo_surface_get_extents (surface->target, &extents); + x_scale = (double)width / extents.width; + y_scale = (double)height / extents.height; + + image = _cairo_paginated_surface_create_image_surface (surface, width, height); + cairo_surface_set_device_scale (image, x_scale, y_scale); + cairo_surface_set_device_offset (image, -extents.x*x_scale, -extents.y*y_scale); + status = _cairo_recording_surface_replay (surface->recording_surface, image); + if (unlikely (status)) + goto cleanup; + + /* flatten transparency */ + + opaque = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height); + if (unlikely (opaque->status)) { + status = opaque->status; + goto cleanup; + } + + status = _cairo_surface_paint (opaque, + CAIRO_OPERATOR_SOURCE, + &_cairo_pattern_white.base, + NULL); + if (unlikely (status)) + goto cleanup; + + _cairo_pattern_init_for_surface (&pattern, image); + pattern.base.filter = CAIRO_FILTER_NEAREST; + status = _cairo_surface_paint (opaque, CAIRO_OPERATOR_OVER, &pattern.base, NULL); + _cairo_pattern_fini (&pattern.base); + if (unlikely (status)) + goto cleanup; + + status = surface->backend->set_thumbnail_image (surface->target, (cairo_image_surface_t *)opaque); + + cleanup: + if (image) + cairo_surface_destroy (image); + if (opaque) + cairo_surface_destroy (opaque); + + return status; +} + +static cairo_int_status_t +_paint_fallback_image (cairo_paginated_surface_t *surface, + cairo_rectangle_int_t *rect) +{ + double x_scale = surface->base.x_fallback_resolution / surface->target->x_resolution; + double y_scale = surface->base.y_fallback_resolution / surface->target->y_resolution; + int x, y, width, height; + cairo_status_t status; + cairo_surface_t *image; + cairo_surface_pattern_t pattern; + cairo_clip_t *clip; + + x = rect->x; + y = rect->y; + width = rect->width; + height = rect->height; + image = _cairo_paginated_surface_create_image_surface (surface, + ceil (width * x_scale), + ceil (height * y_scale)); + cairo_surface_set_device_scale (image, x_scale, y_scale); + /* set_device_offset just sets the x0/y0 components of the matrix; + * so we have to do the scaling manually. */ + cairo_surface_set_device_offset (image, -x*x_scale, -y*y_scale); + + status = _cairo_recording_surface_replay (surface->recording_surface, image); + if (unlikely (status)) + goto CLEANUP_IMAGE; + + _cairo_pattern_init_for_surface (&pattern, image); + cairo_matrix_init (&pattern.base.matrix, + x_scale, 0, 0, y_scale, -x*x_scale, -y*y_scale); + /* the fallback should be rendered at native resolution, so disable + * filtering (if possible) to avoid introducing potential artifacts. */ + pattern.base.filter = CAIRO_FILTER_NEAREST; + + clip = _cairo_clip_intersect_rectangle (NULL, rect); + status = _cairo_surface_paint (surface->target, + CAIRO_OPERATOR_SOURCE, + &pattern.base, clip); + _cairo_clip_destroy (clip); + _cairo_pattern_fini (&pattern.base); + +CLEANUP_IMAGE: + cairo_surface_destroy (image); + + return status; +} + +static cairo_int_status_t +_paint_page (cairo_paginated_surface_t *surface) +{ + cairo_surface_t *analysis; + cairo_int_status_t status; + cairo_bool_t has_supported, has_page_fallback, has_finegrained_fallback; + unsigned int regions_id = 0; + cairo_bool_t replay_all; + + if (unlikely (surface->target->status)) + return surface->target->status; + + analysis = _cairo_analysis_surface_create (surface->target, TRUE); + if (unlikely (analysis->status)) + return _cairo_surface_set_error (surface->target, analysis->status); + + status = surface->backend->set_paginated_mode (surface->target, + CAIRO_PAGINATED_MODE_ANALYZE); + if (unlikely (status)) + goto FAIL; + + replay_all = FALSE; + if (surface->target->backend->analyze_recording_surface && + _cairo_recording_surface_has_tags (surface->recording_surface)) + { + replay_all = TRUE; + } + + status = _cairo_recording_surface_region_array_attach (surface->recording_surface, ®ions_id); + if (status) + goto FAIL; + + status = _cairo_recording_surface_replay_and_create_regions (surface->recording_surface, + regions_id, + NULL, analysis, FALSE, replay_all); + if (status) + goto FAIL; + + assert (analysis->status == CAIRO_STATUS_SUCCESS); + + if (surface->backend->set_bounding_box) { + cairo_box_t bbox; + + _cairo_analysis_surface_get_bounding_box (analysis, &bbox); + status = surface->backend->set_bounding_box (surface->target, &bbox); + if (unlikely (status)) + goto FAIL; + } + + if (surface->backend->set_fallback_images_required) { + cairo_bool_t has_fallbacks = _cairo_analysis_surface_has_unsupported (analysis); + + status = surface->backend->set_fallback_images_required (surface->target, + has_fallbacks); + if (unlikely (status)) + goto FAIL; + } + + /* Finer grained fallbacks are currently only supported for some + * surface types */ + if (surface->backend->supports_fine_grained_fallbacks != NULL && + surface->backend->supports_fine_grained_fallbacks (surface->target)) + { + has_supported = _cairo_analysis_surface_has_supported (analysis); + has_page_fallback = FALSE; + has_finegrained_fallback = _cairo_analysis_surface_has_unsupported (analysis); + } + else + { + if (_cairo_analysis_surface_has_unsupported (analysis)) { + has_supported = FALSE; + has_page_fallback = TRUE; + } else { + has_supported = TRUE; + has_page_fallback = FALSE; + } + has_finegrained_fallback = FALSE; + } + + status = surface->backend->set_paginated_mode (surface->target, + CAIRO_PAGINATED_MODE_RENDER); + if (unlikely (status)) + goto FAIL; + + if (has_supported) { + status = _cairo_recording_surface_replay_region (surface->recording_surface, + regions_id, + NULL, + surface->target, + CAIRO_RECORDING_REGION_NATIVE); + assert (status != CAIRO_INT_STATUS_UNSUPPORTED); + if (unlikely (status)) + goto FAIL; + } + + if (has_page_fallback) { + cairo_rectangle_int_t extents; + cairo_bool_t is_bounded; + + status = surface->backend->set_paginated_mode (surface->target, + CAIRO_PAGINATED_MODE_FALLBACK); + if (unlikely (status)) + goto FAIL; + + is_bounded = _cairo_surface_get_extents (surface->target, &extents); + if (! is_bounded) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto FAIL; + } + + status = _paint_fallback_image (surface, &extents); + if (unlikely (status)) + goto FAIL; + } + + if (has_finegrained_fallback) { + cairo_region_t *region; + int num_rects, i; + + status = surface->backend->set_paginated_mode (surface->target, + CAIRO_PAGINATED_MODE_FALLBACK); + if (unlikely (status)) + goto FAIL; + + region = _cairo_analysis_surface_get_unsupported (analysis); + + num_rects = cairo_region_num_rectangles (region); + for (i = 0; i < num_rects; i++) { + cairo_rectangle_int_t rect; + + cairo_region_get_rectangle (region, i, &rect); + status = _paint_fallback_image (surface, &rect); + if (unlikely (status)) + goto FAIL; + } + } + + if (surface->backend->requires_thumbnail_image) { + int width, height; + + if (surface->backend->requires_thumbnail_image (surface->target, &width, &height)) + _paint_thumbnail_image (surface, width, height); + } + + FAIL: + if (regions_id) + _cairo_recording_surface_region_array_remove (surface->recording_surface, regions_id); + + cairo_surface_destroy (analysis); + + return _cairo_surface_set_error (surface->target, status); +} + +static cairo_status_t +_start_page (cairo_paginated_surface_t *surface) +{ + if (surface->target->status) + return surface->target->status; + + if (! surface->backend->start_page) + return CAIRO_STATUS_SUCCESS; + + return _cairo_surface_set_error (surface->target, + surface->backend->start_page (surface->target)); +} + +static cairo_int_status_t +_cairo_paginated_surface_copy_page (void *abstract_surface) +{ + cairo_status_t status; + cairo_paginated_surface_t *surface = abstract_surface; + + status = _start_page (surface); + if (unlikely (status)) + return status; + + status = _paint_page (surface); + if (unlikely (status)) + return status; + + surface->page_num++; + + /* XXX: It might make sense to add some support here for calling + * cairo_surface_copy_page on the target surface. It would be an + * optimization for the output, but the interaction with image + * fallbacks gets tricky. For now, we just let the target see a + * show_page and we implement the copying by simply not destroying + * the recording-surface. */ + + cairo_surface_show_page (surface->target); + return cairo_surface_status (surface->target); +} + +static cairo_int_status_t +_cairo_paginated_surface_show_page (void *abstract_surface) +{ + cairo_status_t status; + cairo_paginated_surface_t *surface = abstract_surface; + + status = _start_page (surface); + if (unlikely (status)) + return status; + + status = _paint_page (surface); + if (unlikely (status)) + return status; + + cairo_surface_show_page (surface->target); + status = surface->target->status; + if (unlikely (status)) + return status; + + status = surface->recording_surface->status; + if (unlikely (status)) + return status; + + if (! surface->base.finished) { + cairo_surface_destroy (surface->recording_surface); + + surface->recording_surface = _create_recording_surface_for_target (surface->target, + surface->content); + status = surface->recording_surface->status; + if (unlikely (status)) + return status; + + surface->page_num++; + surface->base.is_clear = TRUE; + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_bool_t +_cairo_paginated_surface_get_extents (void *abstract_surface, + cairo_rectangle_int_t *rectangle) +{ + cairo_paginated_surface_t *surface = abstract_surface; + + return _cairo_surface_get_extents (surface->target, rectangle); +} + +static void +_cairo_paginated_surface_get_font_options (void *abstract_surface, + cairo_font_options_t *options) +{ + cairo_paginated_surface_t *surface = abstract_surface; + + cairo_surface_get_font_options (surface->target, options); +} + +static cairo_int_status_t +_cairo_paginated_surface_paint (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip) +{ + cairo_paginated_surface_t *surface = abstract_surface; + + return _cairo_surface_paint (surface->recording_surface, op, source, clip); +} + +static cairo_int_status_t +_cairo_paginated_surface_mask (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_clip_t *clip) +{ + cairo_paginated_surface_t *surface = abstract_surface; + + return _cairo_surface_mask (surface->recording_surface, op, source, mask, clip); +} + +static cairo_int_status_t +_cairo_paginated_surface_stroke (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_paginated_surface_t *surface = abstract_surface; + + return _cairo_surface_stroke (surface->recording_surface, op, source, + path, style, + ctm, ctm_inverse, + tolerance, antialias, + clip); +} + +static cairo_int_status_t +_cairo_paginated_surface_fill (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_paginated_surface_t *surface = abstract_surface; + + return _cairo_surface_fill (surface->recording_surface, op, source, + path, fill_rule, + tolerance, antialias, + clip); +} + +static cairo_bool_t +_cairo_paginated_surface_has_show_text_glyphs (void *abstract_surface) +{ + cairo_paginated_surface_t *surface = abstract_surface; + + return cairo_surface_has_show_text_glyphs (surface->target); +} + +static cairo_int_status_t +_cairo_paginated_surface_show_text_glyphs (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const char *utf8, + int utf8_len, + cairo_glyph_t *glyphs, + int num_glyphs, + const cairo_text_cluster_t *clusters, + int num_clusters, + cairo_text_cluster_flags_t cluster_flags, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip) +{ + cairo_paginated_surface_t *surface = abstract_surface; + + return _cairo_surface_show_text_glyphs (surface->recording_surface, op, source, + utf8, utf8_len, + glyphs, num_glyphs, + clusters, num_clusters, + cluster_flags, + scaled_font, + clip); +} + +static const char ** +_cairo_paginated_surface_get_supported_mime_types (void *abstract_surface) +{ + cairo_paginated_surface_t *surface = abstract_surface; + + if (surface->target->backend->get_supported_mime_types) + return surface->target->backend->get_supported_mime_types (surface->target); + + return NULL; +} + +static cairo_int_status_t +_cairo_paginated_surface_tag (void *abstract_surface, + cairo_bool_t begin, + const char *tag_name, + const char *attributes) +{ + cairo_paginated_surface_t *surface = abstract_surface; + + return _cairo_surface_tag (surface->recording_surface, + begin, tag_name, attributes); +} + +static cairo_bool_t +_cairo_paginated_surface_supports_color_glyph (void *abstract_surface, + cairo_scaled_font_t *scaled_font, + unsigned long glyph_index) +{ + return TRUE; +} + +static cairo_surface_t * +_cairo_paginated_surface_snapshot (void *abstract_other) +{ + cairo_paginated_surface_t *other = abstract_other; + + return other->recording_surface->backend->snapshot (other->recording_surface); +} + +static cairo_t * +_cairo_paginated_context_create (void *target) +{ + cairo_paginated_surface_t *surface = target; + + if (_cairo_surface_is_subsurface (&surface->base)) + surface = (cairo_paginated_surface_t *) + _cairo_surface_subsurface_get_target (&surface->base); + + return surface->recording_surface->backend->create_context (target); +} + +static const cairo_surface_backend_t cairo_paginated_surface_backend = { + CAIRO_INTERNAL_SURFACE_TYPE_PAGINATED, + _cairo_paginated_surface_finish, + + _cairo_paginated_context_create, + + _cairo_paginated_surface_create_similar, + NULL, /* create similar image */ + NULL, /* map to image */ + NULL, /* unmap image */ + + _cairo_paginated_surface_source, + _cairo_paginated_surface_acquire_source_image, + _cairo_paginated_surface_release_source_image, + _cairo_paginated_surface_snapshot, + + _cairo_paginated_surface_copy_page, + _cairo_paginated_surface_show_page, + + _cairo_paginated_surface_get_extents, + _cairo_paginated_surface_get_font_options, + + NULL, /* flush */ + NULL, /* mark_dirty_rectangle */ + + _cairo_paginated_surface_paint, + _cairo_paginated_surface_mask, + _cairo_paginated_surface_stroke, + _cairo_paginated_surface_fill, + NULL, /* fill_stroke */ + NULL, /* show_glyphs */ + _cairo_paginated_surface_has_show_text_glyphs, + _cairo_paginated_surface_show_text_glyphs, + _cairo_paginated_surface_get_supported_mime_types, + _cairo_paginated_surface_tag, + _cairo_paginated_surface_supports_color_glyph, +}; diff --git a/local/recipes/libs/cairo/source/src/cairo-path-bounds.c b/local/recipes/libs/cairo/source/src/cairo-path-bounds.c new file mode 100644 index 0000000000..ac85f27bee --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-path-bounds.c @@ -0,0 +1,230 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2003 University of Southern California + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + */ + +#include "cairoint.h" +#include "cairo-box-inline.h" +#include "cairo-error-private.h" +#include "cairo-path-fixed-private.h" + +typedef struct _cairo_path_bounder { + cairo_point_t current_point; + cairo_bool_t has_extents; + cairo_box_t extents; +} cairo_path_bounder_t; + +static cairo_status_t +_cairo_path_bounder_move_to (void *closure, + const cairo_point_t *point) +{ + cairo_path_bounder_t *bounder = closure; + + bounder->current_point = *point; + + if (likely (bounder->has_extents)) { + _cairo_box_add_point (&bounder->extents, point); + } else { + bounder->has_extents = TRUE; + _cairo_box_set (&bounder->extents, point, point); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_path_bounder_line_to (void *closure, + const cairo_point_t *point) +{ + cairo_path_bounder_t *bounder = closure; + + bounder->current_point = *point; + _cairo_box_add_point (&bounder->extents, point); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_path_bounder_curve_to (void *closure, + const cairo_point_t *b, + const cairo_point_t *c, + const cairo_point_t *d) +{ + cairo_path_bounder_t *bounder = closure; + + _cairo_box_add_curve_to (&bounder->extents, + &bounder->current_point, + b, c, d); + bounder->current_point = *d; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_path_bounder_close_path (void *closure) +{ + return CAIRO_STATUS_SUCCESS; +} + +cairo_bool_t +_cairo_path_bounder_extents (const cairo_path_fixed_t *path, + cairo_box_t *extents) +{ + cairo_path_bounder_t bounder; + cairo_status_t status; + + bounder.has_extents = FALSE; + status = _cairo_path_fixed_interpret (path, + _cairo_path_bounder_move_to, + _cairo_path_bounder_line_to, + _cairo_path_bounder_curve_to, + _cairo_path_bounder_close_path, + &bounder); + assert (!status); + + if (bounder.has_extents) + *extents = bounder.extents; + + return bounder.has_extents; +} + +void +_cairo_path_fixed_approximate_clip_extents (const cairo_path_fixed_t *path, + cairo_rectangle_int_t *extents) +{ + _cairo_path_fixed_approximate_fill_extents (path, extents); +} + +void +_cairo_path_fixed_approximate_fill_extents (const cairo_path_fixed_t *path, + cairo_rectangle_int_t *extents) +{ + _cairo_path_fixed_fill_extents (path, CAIRO_FILL_RULE_WINDING, 0, extents); +} + +void +_cairo_path_fixed_fill_extents (const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_rectangle_int_t *extents) +{ + if (path->extents.p1.x < path->extents.p2.x && + path->extents.p1.y < path->extents.p2.y) { + _cairo_box_round_to_rectangle (&path->extents, extents); + } else { + extents->x = extents->y = 0; + extents->width = extents->height = 0; + } +} + +/* Adjusts the fill extents (above) by the device-space pen. */ +void +_cairo_path_fixed_approximate_stroke_extents (const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + cairo_bool_t is_vector, + cairo_rectangle_int_t *extents) +{ + if (path->has_extents) { + cairo_box_t box_extents; + double dx, dy; + + _cairo_stroke_style_max_distance_from_path (style, path, ctm, &dx, &dy); + if (is_vector) + { + /* When calculating extents for vector surfaces, ensure lines thinner + * than the fixed point resolution are not optimized away. */ + double min = _cairo_fixed_to_double (CAIRO_FIXED_EPSILON*2); + if (dx < min) + dx = min; + + if (dy < min) + dy = min; + } + + box_extents = path->extents; + box_extents.p1.x -= _cairo_fixed_from_double (dx); + box_extents.p1.y -= _cairo_fixed_from_double (dy); + box_extents.p2.x += _cairo_fixed_from_double (dx); + box_extents.p2.y += _cairo_fixed_from_double (dy); + + _cairo_box_round_to_rectangle (&box_extents, extents); + } else { + extents->x = extents->y = 0; + extents->width = extents->height = 0; + } +} + +cairo_status_t +_cairo_path_fixed_stroke_extents (const cairo_path_fixed_t *path, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_rectangle_int_t *extents) +{ + cairo_polygon_t polygon; + cairo_status_t status; + cairo_stroke_style_t style; + + /* When calculating extents for vector surfaces, ensure lines thinner + * than one point are not optimized away. */ + double min_line_width = _cairo_matrix_transformed_circle_major_axis (ctm_inverse, 1.0); + if (stroke_style->line_width < min_line_width) + { + style = *stroke_style; + style.line_width = min_line_width; + stroke_style = &style; + } + + _cairo_polygon_init (&polygon, NULL, 0); + status = _cairo_path_fixed_stroke_to_polygon (path, + stroke_style, + ctm, ctm_inverse, + tolerance, + &polygon); + _cairo_box_round_to_rectangle (&polygon.extents, extents); + _cairo_polygon_fini (&polygon); + + return status; +} + +cairo_bool_t +_cairo_path_fixed_extents (const cairo_path_fixed_t *path, + cairo_box_t *box) +{ + *box = path->extents; + return path->has_extents; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-path-fill.c b/local/recipes/libs/cairo/source/src/cairo-path-fill.c new file mode 100644 index 0000000000..d0c8551dc7 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-path-fill.c @@ -0,0 +1,349 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + */ + +#include "cairoint.h" +#include "cairo-boxes-private.h" +#include "cairo-error-private.h" +#include "cairo-path-fixed-private.h" +#include "cairo-region-private.h" +#include "cairo-traps-private.h" + +typedef struct cairo_filler { + cairo_polygon_t *polygon; + double tolerance; + + cairo_box_t limit; + cairo_bool_t has_limits; + + cairo_point_t current_point; + cairo_point_t last_move_to; +} cairo_filler_t; + +static cairo_status_t +_cairo_filler_line_to (void *closure, + const cairo_point_t *point) +{ + cairo_filler_t *filler = closure; + cairo_status_t status; + + status = _cairo_polygon_add_external_edge (filler->polygon, + &filler->current_point, + point); + + filler->current_point = *point; + + return status; +} + +static cairo_status_t +_cairo_filler_add_point (void *closure, + const cairo_point_t *point, + const cairo_slope_t *tangent) +{ + return _cairo_filler_line_to (closure, point); +}; + +static cairo_status_t +_cairo_filler_close (void *closure) +{ + cairo_filler_t *filler = closure; + + /* close the subpath */ + return _cairo_filler_line_to (closure, &filler->last_move_to); +} + +static cairo_status_t +_cairo_filler_move_to (void *closure, + const cairo_point_t *point) +{ + cairo_filler_t *filler = closure; + cairo_status_t status; + + /* close current subpath */ + status = _cairo_filler_close (closure); + if (unlikely (status)) + return status; + + /* make sure that the closure represents a degenerate path */ + filler->current_point = *point; + filler->last_move_to = *point; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_filler_curve_to (void *closure, + const cairo_point_t *p1, + const cairo_point_t *p2, + const cairo_point_t *p3) +{ + cairo_filler_t *filler = closure; + cairo_spline_t spline; + + if (filler->has_limits) { + if (! _cairo_spline_intersects (&filler->current_point, p1, p2, p3, + &filler->limit)) + return _cairo_filler_line_to (filler, p3); + } + + if (! _cairo_spline_init (&spline, + _cairo_filler_add_point, filler, + &filler->current_point, p1, p2, p3)) + { + return _cairo_filler_line_to (closure, p3); + } + + return _cairo_spline_decompose (&spline, filler->tolerance); +} + +cairo_status_t +_cairo_path_fixed_fill_to_polygon (const cairo_path_fixed_t *path, + double tolerance, + cairo_polygon_t *polygon) +{ + cairo_filler_t filler; + cairo_status_t status; + + filler.polygon = polygon; + filler.tolerance = tolerance; + + filler.has_limits = FALSE; + if (polygon->num_limits) { + filler.has_limits = TRUE; + filler.limit = polygon->limit; + } + + /* make sure that the closure represents a degenerate path */ + filler.current_point.x = 0; + filler.current_point.y = 0; + filler.last_move_to = filler.current_point; + + status = _cairo_path_fixed_interpret (path, + _cairo_filler_move_to, + _cairo_filler_line_to, + _cairo_filler_curve_to, + _cairo_filler_close, + &filler); + if (unlikely (status)) + return status; + + return _cairo_filler_close (&filler); +} + +typedef struct cairo_filler_rectilinear_aligned { + cairo_polygon_t *polygon; + + cairo_point_t current_point; + cairo_point_t last_move_to; +} cairo_filler_ra_t; + +static cairo_status_t +_cairo_filler_ra_line_to (void *closure, + const cairo_point_t *point) +{ + cairo_filler_ra_t *filler = closure; + cairo_status_t status; + cairo_point_t p; + + p.x = _cairo_fixed_round_down (point->x); + p.y = _cairo_fixed_round_down (point->y); + + status = _cairo_polygon_add_external_edge (filler->polygon, + &filler->current_point, + &p); + + filler->current_point = p; + + return status; +} + +static cairo_status_t +_cairo_filler_ra_close (void *closure) +{ + cairo_filler_ra_t *filler = closure; + return _cairo_filler_ra_line_to (closure, &filler->last_move_to); +} + +static cairo_status_t +_cairo_filler_ra_move_to (void *closure, + const cairo_point_t *point) +{ + cairo_filler_ra_t *filler = closure; + cairo_status_t status; + cairo_point_t p; + + /* close current subpath */ + status = _cairo_filler_ra_close (closure); + if (unlikely (status)) + return status; + + p.x = _cairo_fixed_round_down (point->x); + p.y = _cairo_fixed_round_down (point->y); + + /* make sure that the closure represents a degenerate path */ + filler->current_point = p; + filler->last_move_to = p; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_path_fixed_fill_rectilinear_to_polygon (const cairo_path_fixed_t *path, + cairo_antialias_t antialias, + cairo_polygon_t *polygon) +{ + cairo_filler_ra_t filler; + cairo_status_t status; + + if (antialias != CAIRO_ANTIALIAS_NONE) + return _cairo_path_fixed_fill_to_polygon (path, 0., polygon); + + filler.polygon = polygon; + + /* make sure that the closure represents a degenerate path */ + filler.current_point.x = 0; + filler.current_point.y = 0; + filler.last_move_to = filler.current_point; + + status = _cairo_path_fixed_interpret_flat (path, + _cairo_filler_ra_move_to, + _cairo_filler_ra_line_to, + _cairo_filler_ra_close, + &filler, + 0.); + if (unlikely (status)) + return status; + + return _cairo_filler_ra_close (&filler); +} + +cairo_status_t +_cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_traps_t *traps) +{ + cairo_polygon_t polygon; + cairo_status_t status; + + if (_cairo_path_fixed_fill_is_empty (path)) + return CAIRO_STATUS_SUCCESS; + + _cairo_polygon_init (&polygon, traps->limits, traps->num_limits); + status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon); + if (unlikely (status || polygon.num_edges == 0)) + goto CLEANUP; + + status = _cairo_bentley_ottmann_tessellate_polygon (traps, + &polygon, fill_rule); + + CLEANUP: + _cairo_polygon_fini (&polygon); + return status; +} + +static cairo_status_t +_cairo_path_fixed_fill_rectilinear_tessellate_to_boxes (const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + cairo_antialias_t antialias, + cairo_boxes_t *boxes) +{ + cairo_polygon_t polygon; + cairo_status_t status; + + _cairo_polygon_init (&polygon, boxes->limits, boxes->num_limits); + boxes->num_limits = 0; + + /* tolerance will be ignored as the path is rectilinear */ + status = _cairo_path_fixed_fill_rectilinear_to_polygon (path, antialias, &polygon); + if (likely (status == CAIRO_STATUS_SUCCESS)) { + status = + _cairo_bentley_ottmann_tessellate_rectilinear_polygon_to_boxes (&polygon, + fill_rule, + boxes); + } + + _cairo_polygon_fini (&polygon); + + return status; +} + +cairo_status_t +_cairo_path_fixed_fill_rectilinear_to_boxes (const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + cairo_antialias_t antialias, + cairo_boxes_t *boxes) +{ + cairo_path_fixed_iter_t iter; + cairo_status_t status; + cairo_box_t box; + + if (_cairo_path_fixed_is_box (path, &box)) + return _cairo_boxes_add (boxes, antialias, &box); + + _cairo_path_fixed_iter_init (&iter, path); + while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) { + if (box.p1.y == box.p2.y || box.p1.x == box.p2.x) + continue; + + if (box.p1.y > box.p2.y) { + cairo_fixed_t t; + + t = box.p1.y; + box.p1.y = box.p2.y; + box.p2.y = t; + + t = box.p1.x; + box.p1.x = box.p2.x; + box.p2.x = t; + } + + status = _cairo_boxes_add (boxes, antialias, &box); + if (unlikely (status)) + return status; + } + + if (_cairo_path_fixed_iter_at_end (&iter)) + return _cairo_bentley_ottmann_tessellate_boxes (boxes, fill_rule, boxes); + + /* path is not rectangular, try extracting clipped rectilinear edges */ + _cairo_boxes_clear (boxes); + return _cairo_path_fixed_fill_rectilinear_tessellate_to_boxes (path, + fill_rule, + antialias, + boxes); +} diff --git a/local/recipes/libs/cairo/source/src/cairo-path-fixed-private.h b/local/recipes/libs/cairo/source/src/cairo-path-fixed-private.h new file mode 100644 index 0000000000..e499063444 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-path-fixed-private.h @@ -0,0 +1,206 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Carl D. Worth + */ + +#ifndef CAIRO_PATH_FIXED_PRIVATE_H +#define CAIRO_PATH_FIXED_PRIVATE_H + +#include "cairo-types-private.h" +#include "cairo-compiler-private.h" +#include "cairo-list-private.h" + +#define WATCH_PATH 0 +#if WATCH_PATH +#include +#endif + +enum cairo_path_op { + CAIRO_PATH_OP_MOVE_TO = 0, + CAIRO_PATH_OP_LINE_TO = 1, + CAIRO_PATH_OP_CURVE_TO = 2, + CAIRO_PATH_OP_CLOSE_PATH = 3 +}; + +/* we want to make sure a single byte is used for the enum */ +typedef char cairo_path_op_t; + +/* make _cairo_path_fixed fit into ~512 bytes -- about 50 items */ +#define CAIRO_PATH_BUF_SIZE ((512 - sizeof (cairo_path_buf_t)) \ + / (2 * sizeof (cairo_point_t) + sizeof (cairo_path_op_t))) + +#define cairo_path_head(path__) (&(path__)->buf.base) +#define cairo_path_tail(path__) cairo_path_buf_prev (cairo_path_head (path__)) + +#define cairo_path_buf_next(pos__) \ + cairo_list_entry ((pos__)->link.next, cairo_path_buf_t, link) +#define cairo_path_buf_prev(pos__) \ + cairo_list_entry ((pos__)->link.prev, cairo_path_buf_t, link) + +#define cairo_path_foreach_buf_start(pos__, path__) \ + pos__ = cairo_path_head (path__); do +#define cairo_path_foreach_buf_end(pos__, path__) \ + while ((pos__ = cairo_path_buf_next (pos__)) != cairo_path_head (path__)) + + +typedef struct _cairo_path_buf { + cairo_list_t link; + unsigned int num_ops; + unsigned int size_ops; + unsigned int num_points; + unsigned int size_points; + + cairo_path_op_t *op; + cairo_point_t *points; +} cairo_path_buf_t; + +typedef struct _cairo_path_buf_fixed { + cairo_path_buf_t base; + + cairo_path_op_t op[CAIRO_PATH_BUF_SIZE]; + cairo_point_t points[2 * CAIRO_PATH_BUF_SIZE]; +} cairo_path_buf_fixed_t; + +/* + NOTES: + has_curve_to => !stroke_is_rectilinear + fill_is_rectilinear => stroke_is_rectilinear + fill_is_empty => fill_is_rectilinear + fill_maybe_region => fill_is_rectilinear +*/ +struct _cairo_path_fixed { + cairo_point_t last_move_point; + cairo_point_t current_point; + unsigned int has_current_point : 1; + unsigned int needs_move_to : 1; + unsigned int has_extents : 1; + unsigned int has_curve_to : 1; + unsigned int stroke_is_rectilinear : 1; + unsigned int fill_is_rectilinear : 1; + unsigned int fill_maybe_region : 1; + unsigned int fill_is_empty : 1; + + cairo_box_t extents; + + cairo_path_buf_fixed_t buf; +}; + +cairo_private void +_cairo_path_fixed_translate (cairo_path_fixed_t *path, + cairo_fixed_t offx, + cairo_fixed_t offy); + +cairo_private cairo_status_t +_cairo_path_fixed_append (cairo_path_fixed_t *path, + const cairo_path_fixed_t *other, + cairo_fixed_t tx, + cairo_fixed_t ty); + +cairo_private uintptr_t +_cairo_path_fixed_hash (const cairo_path_fixed_t *path); + +cairo_private unsigned long +_cairo_path_fixed_size (const cairo_path_fixed_t *path); + +cairo_private cairo_bool_t +_cairo_path_fixed_equal (const cairo_path_fixed_t *a, + const cairo_path_fixed_t *b); + +typedef struct _cairo_path_fixed_iter { + const cairo_path_buf_t *first; + const cairo_path_buf_t *buf; + unsigned int n_op; + unsigned int n_point; +} cairo_path_fixed_iter_t; + +cairo_private void +_cairo_path_fixed_iter_init (cairo_path_fixed_iter_t *iter, + const cairo_path_fixed_t *path); + +cairo_private cairo_bool_t +_cairo_path_fixed_iter_is_fill_box (cairo_path_fixed_iter_t *_iter, + cairo_box_t *box); + +cairo_private cairo_bool_t +_cairo_path_fixed_iter_at_end (const cairo_path_fixed_iter_t *iter); + +static inline cairo_bool_t +_cairo_path_fixed_fill_is_empty (const cairo_path_fixed_t *path) +{ + return path->fill_is_empty; +} + +static inline cairo_bool_t +_cairo_path_fixed_fill_is_rectilinear (const cairo_path_fixed_t *path) +{ + if (! path->fill_is_rectilinear) + return 0; + + if (! path->has_current_point || path->needs_move_to) + return 1; + + /* check whether the implicit close preserves the rectilinear property */ + return path->current_point.x == path->last_move_point.x || + path->current_point.y == path->last_move_point.y; +} + +static inline cairo_bool_t +_cairo_path_fixed_stroke_is_rectilinear (const cairo_path_fixed_t *path) +{ + return path->stroke_is_rectilinear; +} + +static inline cairo_bool_t +_cairo_path_fixed_fill_maybe_region (const cairo_path_fixed_t *path) +{ + if (! path->fill_maybe_region) + return 0; + + if (! path->has_current_point || path->needs_move_to) + return 1; + + /* check whether the implicit close preserves the rectilinear property + * (the integer point property is automatically preserved) + */ + return path->current_point.x == path->last_move_point.x || + path->current_point.y == path->last_move_point.y; +} + +cairo_private cairo_bool_t +_cairo_path_fixed_is_stroke_box (const cairo_path_fixed_t *path, + cairo_box_t *box); + +cairo_private cairo_bool_t +_cairo_path_fixed_is_simple_quad (const cairo_path_fixed_t *path); + +#endif /* CAIRO_PATH_FIXED_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-path-fixed.c b/local/recipes/libs/cairo/source/src/cairo-path-fixed.c new file mode 100644 index 0000000000..ca759447ec --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-path-fixed.c @@ -0,0 +1,1597 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + */ + +#include "cairoint.h" + +#include "cairo-box-inline.h" +#include "cairo-error-private.h" +#include "cairo-list-inline.h" +#include "cairo-path-fixed-private.h" +#include "cairo-slope-private.h" + +static cairo_status_t +_cairo_path_fixed_add (cairo_path_fixed_t *path, + cairo_path_op_t op, + const cairo_point_t *points, + int num_points); + +static void +_cairo_path_fixed_add_buf (cairo_path_fixed_t *path, + cairo_path_buf_t *buf); + +static cairo_path_buf_t * +_cairo_path_buf_create (int size_ops, int size_points); + +static void +_cairo_path_buf_destroy (cairo_path_buf_t *buf); + +static void +_cairo_path_buf_add_op (cairo_path_buf_t *buf, + cairo_path_op_t op); + +static void +_cairo_path_buf_add_points (cairo_path_buf_t *buf, + const cairo_point_t *points, + int num_points); + +void +_cairo_path_fixed_init (cairo_path_fixed_t *path) +{ + VG (VALGRIND_MAKE_MEM_UNDEFINED (path, sizeof (cairo_path_fixed_t))); + + cairo_list_init (&path->buf.base.link); + + path->buf.base.num_ops = 0; + path->buf.base.num_points = 0; + path->buf.base.size_ops = ARRAY_LENGTH (path->buf.op); + path->buf.base.size_points = ARRAY_LENGTH (path->buf.points); + path->buf.base.op = path->buf.op; + path->buf.base.points = path->buf.points; + + path->current_point.x = 0; + path->current_point.y = 0; + path->last_move_point = path->current_point; + + path->has_current_point = FALSE; + path->needs_move_to = TRUE; + path->has_extents = FALSE; + path->has_curve_to = FALSE; + path->stroke_is_rectilinear = TRUE; + path->fill_is_rectilinear = TRUE; + path->fill_maybe_region = TRUE; + path->fill_is_empty = TRUE; + + path->extents.p1.x = path->extents.p1.y = 0; + path->extents.p2.x = path->extents.p2.y = 0; +} + +cairo_status_t +_cairo_path_fixed_init_copy (cairo_path_fixed_t *path, + const cairo_path_fixed_t *other) +{ + cairo_path_buf_t *buf, *other_buf; + unsigned int num_points, num_ops; + + VG (VALGRIND_MAKE_MEM_UNDEFINED (path, sizeof (cairo_path_fixed_t))); + + cairo_list_init (&path->buf.base.link); + + path->buf.base.op = path->buf.op; + path->buf.base.points = path->buf.points; + path->buf.base.size_ops = ARRAY_LENGTH (path->buf.op); + path->buf.base.size_points = ARRAY_LENGTH (path->buf.points); + + path->current_point = other->current_point; + path->last_move_point = other->last_move_point; + + path->has_current_point = other->has_current_point; + path->needs_move_to = other->needs_move_to; + path->has_extents = other->has_extents; + path->has_curve_to = other->has_curve_to; + path->stroke_is_rectilinear = other->stroke_is_rectilinear; + path->fill_is_rectilinear = other->fill_is_rectilinear; + path->fill_maybe_region = other->fill_maybe_region; + path->fill_is_empty = other->fill_is_empty; + + path->extents = other->extents; + + path->buf.base.num_ops = other->buf.base.num_ops; + path->buf.base.num_points = other->buf.base.num_points; + memcpy (path->buf.op, other->buf.base.op, + other->buf.base.num_ops * sizeof (other->buf.op[0])); + memcpy (path->buf.points, other->buf.points, + other->buf.base.num_points * sizeof (other->buf.points[0])); + + num_points = num_ops = 0; + for (other_buf = cairo_path_buf_next (cairo_path_head (other)); + other_buf != cairo_path_head (other); + other_buf = cairo_path_buf_next (other_buf)) + { + num_ops += other_buf->num_ops; + num_points += other_buf->num_points; + } + + if (num_ops) { + buf = _cairo_path_buf_create (num_ops, num_points); + if (unlikely (buf == NULL)) { + _cairo_path_fixed_fini (path); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + for (other_buf = cairo_path_buf_next (cairo_path_head (other)); + other_buf != cairo_path_head (other); + other_buf = cairo_path_buf_next (other_buf)) + { + memcpy (buf->op + buf->num_ops, other_buf->op, + other_buf->num_ops * sizeof (buf->op[0])); + buf->num_ops += other_buf->num_ops; + + memcpy (buf->points + buf->num_points, other_buf->points, + other_buf->num_points * sizeof (buf->points[0])); + buf->num_points += other_buf->num_points; + } + + _cairo_path_fixed_add_buf (path, buf); + } + + return CAIRO_STATUS_SUCCESS; +} + +uintptr_t +_cairo_path_fixed_hash (const cairo_path_fixed_t *path) +{ + uintptr_t hash = _CAIRO_HASH_INIT_VALUE; + const cairo_path_buf_t *buf; + unsigned int count; + + count = 0; + cairo_path_foreach_buf_start (buf, path) { + hash = _cairo_hash_bytes (hash, buf->op, + buf->num_ops * sizeof (buf->op[0])); + count += buf->num_ops; + } cairo_path_foreach_buf_end (buf, path); + hash = _cairo_hash_bytes (hash, &count, sizeof (count)); + + count = 0; + cairo_path_foreach_buf_start (buf, path) { + hash = _cairo_hash_bytes (hash, buf->points, + buf->num_points * sizeof (buf->points[0])); + count += buf->num_points; + } cairo_path_foreach_buf_end (buf, path); + hash = _cairo_hash_bytes (hash, &count, sizeof (count)); + + return hash; +} + +unsigned long +_cairo_path_fixed_size (const cairo_path_fixed_t *path) +{ + const cairo_path_buf_t *buf; + int num_points, num_ops; + + num_ops = num_points = 0; + cairo_path_foreach_buf_start (buf, path) { + num_ops += buf->num_ops; + num_points += buf->num_points; + } cairo_path_foreach_buf_end (buf, path); + + return num_ops * sizeof (buf->op[0]) + + num_points * sizeof (buf->points[0]); +} + +cairo_bool_t +_cairo_path_fixed_equal (const cairo_path_fixed_t *a, + const cairo_path_fixed_t *b) +{ + const cairo_path_buf_t *buf_a, *buf_b; + const cairo_path_op_t *ops_a, *ops_b; + const cairo_point_t *points_a, *points_b; + int num_points_a, num_ops_a; + int num_points_b, num_ops_b; + + if (a == b) + return TRUE; + + /* use the flags to quickly differentiate based on contents */ + if (a->has_curve_to != b->has_curve_to) + { + return FALSE; + } + + if (a->extents.p1.x != b->extents.p1.x || + a->extents.p1.y != b->extents.p1.y || + a->extents.p2.x != b->extents.p2.x || + a->extents.p2.y != b->extents.p2.y) + { + return FALSE; + } + + num_ops_a = num_points_a = 0; + cairo_path_foreach_buf_start (buf_a, a) { + num_ops_a += buf_a->num_ops; + num_points_a += buf_a->num_points; + } cairo_path_foreach_buf_end (buf_a, a); + + num_ops_b = num_points_b = 0; + cairo_path_foreach_buf_start (buf_b, b) { + num_ops_b += buf_b->num_ops; + num_points_b += buf_b->num_points; + } cairo_path_foreach_buf_end (buf_b, b); + + if (num_ops_a == 0 && num_ops_b == 0) + return TRUE; + + if (num_ops_a != num_ops_b || num_points_a != num_points_b) + return FALSE; + + buf_a = cairo_path_head (a); + num_points_a = buf_a->num_points; + num_ops_a = buf_a->num_ops; + ops_a = buf_a->op; + points_a = buf_a->points; + + buf_b = cairo_path_head (b); + num_points_b = buf_b->num_points; + num_ops_b = buf_b->num_ops; + ops_b = buf_b->op; + points_b = buf_b->points; + + while (TRUE) { + int num_ops = MIN (num_ops_a, num_ops_b); + int num_points = MIN (num_points_a, num_points_b); + + if (memcmp (ops_a, ops_b, num_ops * sizeof (cairo_path_op_t))) + return FALSE; + if (memcmp (points_a, points_b, num_points * sizeof (cairo_point_t))) + return FALSE; + + num_ops_a -= num_ops; + ops_a += num_ops; + num_points_a -= num_points; + points_a += num_points; + if (num_ops_a == 0 || num_points_a == 0) { + if (num_ops_a || num_points_a) + return FALSE; + + buf_a = cairo_path_buf_next (buf_a); + if (buf_a == cairo_path_head (a)) + break; + + num_points_a = buf_a->num_points; + num_ops_a = buf_a->num_ops; + ops_a = buf_a->op; + points_a = buf_a->points; + } + + num_ops_b -= num_ops; + ops_b += num_ops; + num_points_b -= num_points; + points_b += num_points; + if (num_ops_b == 0 || num_points_b == 0) { + if (num_ops_b || num_points_b) + return FALSE; + + buf_b = cairo_path_buf_next (buf_b); + if (buf_b == cairo_path_head (b)) + break; + + num_points_b = buf_b->num_points; + num_ops_b = buf_b->num_ops; + ops_b = buf_b->op; + points_b = buf_b->points; + } + } + + return TRUE; +} + +cairo_path_fixed_t * +_cairo_path_fixed_create (void) +{ + cairo_path_fixed_t *path; + + path = _cairo_calloc (sizeof (cairo_path_fixed_t)); + if (!path) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return NULL; + } + + _cairo_path_fixed_init (path); + return path; +} + +void +_cairo_path_fixed_fini (cairo_path_fixed_t *path) +{ + cairo_path_buf_t *buf; + + buf = cairo_path_buf_next (cairo_path_head (path)); + while (buf != cairo_path_head (path)) { + cairo_path_buf_t *this = buf; + buf = cairo_path_buf_next (buf); + _cairo_path_buf_destroy (this); + } + + VG (VALGRIND_MAKE_MEM_UNDEFINED (path, sizeof (cairo_path_fixed_t))); +} + +void +_cairo_path_fixed_destroy (cairo_path_fixed_t *path) +{ + _cairo_path_fixed_fini (path); + free (path); +} + +static cairo_path_op_t +_cairo_path_fixed_last_op (cairo_path_fixed_t *path) +{ + cairo_path_buf_t *buf; + + buf = cairo_path_tail (path); + assert (buf->num_ops != 0); + + return buf->op[buf->num_ops - 1]; +} + +static inline const cairo_point_t * +_cairo_path_fixed_penultimate_point (cairo_path_fixed_t *path) +{ + cairo_path_buf_t *buf; + + buf = cairo_path_tail (path); + if (likely (buf->num_points >= 2)) { + return &buf->points[buf->num_points - 2]; + } else { + cairo_path_buf_t *prev_buf = cairo_path_buf_prev (buf); + + assert (prev_buf->num_points >= 2 - buf->num_points); + return &prev_buf->points[prev_buf->num_points - (2 - buf->num_points)]; + } +} + +static void +_cairo_path_fixed_drop_line_to (cairo_path_fixed_t *path) +{ + cairo_path_buf_t *buf; + + assert (_cairo_path_fixed_last_op (path) == CAIRO_PATH_OP_LINE_TO); + + buf = cairo_path_tail (path); + buf->num_points--; + buf->num_ops--; +} + +cairo_status_t +_cairo_path_fixed_move_to (cairo_path_fixed_t *path, + cairo_fixed_t x, + cairo_fixed_t y) +{ + _cairo_path_fixed_new_sub_path (path); + + path->has_current_point = TRUE; + path->current_point.x = x; + path->current_point.y = y; + path->last_move_point = path->current_point; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_path_fixed_move_to_apply (cairo_path_fixed_t *path) +{ + if (likely (! path->needs_move_to)) + return CAIRO_STATUS_SUCCESS; + + path->needs_move_to = FALSE; + + if (path->has_extents) { + _cairo_box_add_point (&path->extents, &path->current_point); + } else { + _cairo_box_set (&path->extents, &path->current_point, &path->current_point); + path->has_extents = TRUE; + } + + if (path->fill_maybe_region) { + path->fill_maybe_region = _cairo_fixed_is_integer (path->current_point.x) && + _cairo_fixed_is_integer (path->current_point.y); + } + + path->last_move_point = path->current_point; + + return _cairo_path_fixed_add (path, CAIRO_PATH_OP_MOVE_TO, &path->current_point, 1); +} + +void +_cairo_path_fixed_new_sub_path (cairo_path_fixed_t *path) +{ + if (! path->needs_move_to) { + /* If the current subpath doesn't need_move_to, it contains at least one command */ + if (path->fill_is_rectilinear) { + /* Implicitly close for fill */ + path->fill_is_rectilinear = path->current_point.x == path->last_move_point.x || + path->current_point.y == path->last_move_point.y; + path->fill_maybe_region &= path->fill_is_rectilinear; + } + path->needs_move_to = TRUE; + } + + path->has_current_point = FALSE; +} + +cairo_status_t +_cairo_path_fixed_rel_move_to (cairo_path_fixed_t *path, + cairo_fixed_t dx, + cairo_fixed_t dy) +{ + if (unlikely (! path->has_current_point)) + return _cairo_error (CAIRO_STATUS_NO_CURRENT_POINT); + + return _cairo_path_fixed_move_to (path, + path->current_point.x + dx, + path->current_point.y + dy); + +} + +cairo_status_t +_cairo_path_fixed_line_to (cairo_path_fixed_t *path, + cairo_fixed_t x, + cairo_fixed_t y) +{ + cairo_status_t status; + cairo_point_t point; + + point.x = x; + point.y = y; + + /* When there is not yet a current point, the line_to operation + * becomes a move_to instead. Note: We have to do this by + * explicitly calling into _cairo_path_fixed_move_to to ensure + * that the last_move_point state is updated properly. + */ + if (! path->has_current_point) + return _cairo_path_fixed_move_to (path, point.x, point.y); + + status = _cairo_path_fixed_move_to_apply (path); + if (unlikely (status)) + return status; + + /* If the previous op was but the initial MOVE_TO and this segment + * is degenerate, then we can simply skip this point. Note that + * a move-to followed by a degenerate line-to is a valid path for + * stroking, but at all other times is simply a degenerate segment. + */ + if (_cairo_path_fixed_last_op (path) != CAIRO_PATH_OP_MOVE_TO) { + if (x == path->current_point.x && y == path->current_point.y) + return CAIRO_STATUS_SUCCESS; + } + + /* If the previous op was also a LINE_TO with the same gradient, + * then just change its end-point rather than adding a new op. + */ + if (_cairo_path_fixed_last_op (path) == CAIRO_PATH_OP_LINE_TO) { + const cairo_point_t *p; + + p = _cairo_path_fixed_penultimate_point (path); + if (p->x == path->current_point.x && p->y == path->current_point.y) { + /* previous line element was degenerate, replace */ + _cairo_path_fixed_drop_line_to (path); + } else { + cairo_slope_t prev, self; + + _cairo_slope_init (&prev, p, &path->current_point); + _cairo_slope_init (&self, &path->current_point, &point); + if (_cairo_slope_equal (&prev, &self) && + /* cannot trim anti-parallel segments whilst stroking */ + ! _cairo_slope_backwards (&prev, &self)) + { + _cairo_path_fixed_drop_line_to (path); + /* In this case the flags might be more restrictive than + * what we actually need. + * When changing the flags definition we should check if + * changing the line_to point can affect them. + */ + } + } + } + + if (path->stroke_is_rectilinear) { + path->stroke_is_rectilinear = path->current_point.x == x || + path->current_point.y == y; + path->fill_is_rectilinear &= path->stroke_is_rectilinear; + path->fill_maybe_region &= path->fill_is_rectilinear; + if (path->fill_maybe_region) { + path->fill_maybe_region = _cairo_fixed_is_integer (x) && + _cairo_fixed_is_integer (y); + } + if (path->fill_is_empty) { + path->fill_is_empty = path->current_point.x == x && + path->current_point.y == y; + } + } + + path->current_point = point; + + _cairo_box_add_point (&path->extents, &point); + + return _cairo_path_fixed_add (path, CAIRO_PATH_OP_LINE_TO, &point, 1); +} + +cairo_status_t +_cairo_path_fixed_rel_line_to (cairo_path_fixed_t *path, + cairo_fixed_t dx, + cairo_fixed_t dy) +{ + if (unlikely (! path->has_current_point)) + return _cairo_error (CAIRO_STATUS_NO_CURRENT_POINT); + + return _cairo_path_fixed_line_to (path, + path->current_point.x + dx, + path->current_point.y + dy); +} + +cairo_status_t +_cairo_path_fixed_curve_to (cairo_path_fixed_t *path, + cairo_fixed_t x0, cairo_fixed_t y0, + cairo_fixed_t x1, cairo_fixed_t y1, + cairo_fixed_t x2, cairo_fixed_t y2) +{ + cairo_status_t status; + cairo_point_t point[3]; + + /* If this curves does not move, replace it with a line-to. + * This frequently happens with rounded-rectangles and r==0. + */ + if (path->current_point.x == x2 && path->current_point.y == y2) { + if (x1 == x2 && x0 == x2 && y1 == y2 && y0 == y2) + return _cairo_path_fixed_line_to (path, x2, y2); + + /* We may want to check for the absence of a cusp, in which case + * we can also replace the curve-to with a line-to. + */ + } + + /* make sure subpaths are started properly */ + if (! path->has_current_point) { + status = _cairo_path_fixed_move_to (path, x0, y0); + assert (status == CAIRO_STATUS_SUCCESS); + } + + status = _cairo_path_fixed_move_to_apply (path); + if (unlikely (status)) + return status; + + /* If the previous op was a degenerate LINE_TO, drop it. */ + if (_cairo_path_fixed_last_op (path) == CAIRO_PATH_OP_LINE_TO) { + const cairo_point_t *p; + + p = _cairo_path_fixed_penultimate_point (path); + if (p->x == path->current_point.x && p->y == path->current_point.y) { + /* previous line element was degenerate, replace */ + _cairo_path_fixed_drop_line_to (path); + } + } + + point[0].x = x0; point[0].y = y0; + point[1].x = x1; point[1].y = y1; + point[2].x = x2; point[2].y = y2; + + _cairo_box_add_curve_to (&path->extents, &path->current_point, + &point[0], &point[1], &point[2]); + + path->current_point = point[2]; + path->has_curve_to = TRUE; + path->stroke_is_rectilinear = FALSE; + path->fill_is_rectilinear = FALSE; + path->fill_maybe_region = FALSE; + path->fill_is_empty = FALSE; + + return _cairo_path_fixed_add (path, CAIRO_PATH_OP_CURVE_TO, point, 3); +} + +cairo_status_t +_cairo_path_fixed_rel_curve_to (cairo_path_fixed_t *path, + cairo_fixed_t dx0, cairo_fixed_t dy0, + cairo_fixed_t dx1, cairo_fixed_t dy1, + cairo_fixed_t dx2, cairo_fixed_t dy2) +{ + if (unlikely (! path->has_current_point)) + return _cairo_error (CAIRO_STATUS_NO_CURRENT_POINT); + + return _cairo_path_fixed_curve_to (path, + path->current_point.x + dx0, + path->current_point.y + dy0, + + path->current_point.x + dx1, + path->current_point.y + dy1, + + path->current_point.x + dx2, + path->current_point.y + dy2); +} + +cairo_status_t +_cairo_path_fixed_close_path (cairo_path_fixed_t *path) +{ + cairo_status_t status; + + if (! path->has_current_point) + return CAIRO_STATUS_SUCCESS; + + /* + * Add a line_to, to compute flags and solve any degeneracy. + * It will be removed later (if it was actually added). + */ + status = _cairo_path_fixed_line_to (path, + path->last_move_point.x, + path->last_move_point.y); + if (unlikely (status)) + return status; + + /* + * If the command used to close the path is a line_to, drop it. + * We must check that last command is actually a line_to, + * because the path could have been closed with a curve_to (and + * the previous line_to not added as it would be degenerate). + */ + if (_cairo_path_fixed_last_op (path) == CAIRO_PATH_OP_LINE_TO) + _cairo_path_fixed_drop_line_to (path); + + path->needs_move_to = TRUE; /* After close_path, add an implicit move_to */ + + return _cairo_path_fixed_add (path, CAIRO_PATH_OP_CLOSE_PATH, NULL, 0); +} + +cairo_bool_t +_cairo_path_fixed_get_current_point (cairo_path_fixed_t *path, + cairo_fixed_t *x, + cairo_fixed_t *y) +{ + if (! path->has_current_point) + return FALSE; + + *x = path->current_point.x; + *y = path->current_point.y; + + return TRUE; +} + +static cairo_status_t +_cairo_path_fixed_add (cairo_path_fixed_t *path, + cairo_path_op_t op, + const cairo_point_t *points, + int num_points) +{ + cairo_path_buf_t *buf = cairo_path_tail (path); + + if (buf->num_ops + 1 > buf->size_ops || + buf->num_points + num_points > buf->size_points) + { + buf = _cairo_path_buf_create (buf->num_ops * 2, buf->num_points * 2); + if (unlikely (buf == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + _cairo_path_fixed_add_buf (path, buf); + } + + if (WATCH_PATH) { + const char *op_str[] = { + "move-to", + "line-to", + "curve-to", + "close-path", + }; + char buf[1024]; + int len = 0; + int i; + + len += snprintf (buf + len, sizeof (buf), "["); + for (i = 0; i < num_points; i++) { + if (i != 0) + len += snprintf (buf + len, sizeof (buf), " "); + len += snprintf (buf + len, sizeof (buf), "(%f, %f)", + _cairo_fixed_to_double (points[i].x), + _cairo_fixed_to_double (points[i].y)); + } + len += snprintf (buf + len, sizeof (buf), "]"); + +#define STRINGIFYFLAG(x) (path->x ? #x " " : "") + fprintf (stderr, + "_cairo_path_fixed_add (%s, %s) [%s%s%s%s%s%s%s%s]\n", + op_str[(int) op], buf, + STRINGIFYFLAG(has_current_point), + STRINGIFYFLAG(needs_move_to), + STRINGIFYFLAG(has_extents), + STRINGIFYFLAG(has_curve_to), + STRINGIFYFLAG(stroke_is_rectilinear), + STRINGIFYFLAG(fill_is_rectilinear), + STRINGIFYFLAG(fill_is_empty), + STRINGIFYFLAG(fill_maybe_region) + ); +#undef STRINGIFYFLAG + } + + _cairo_path_buf_add_op (buf, op); + _cairo_path_buf_add_points (buf, points, num_points); + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_path_fixed_add_buf (cairo_path_fixed_t *path, + cairo_path_buf_t *buf) +{ + cairo_list_add_tail (&buf->link, &cairo_path_head (path)->link); +} + +COMPILE_TIME_ASSERT (sizeof (cairo_path_op_t) == 1); +static cairo_path_buf_t * +_cairo_path_buf_create (int size_ops, int size_points) +{ + cairo_path_buf_t *buf; + + /* adjust size_ops to ensure that buf->points is naturally aligned */ + size_ops += sizeof (double) - ((sizeof (cairo_path_buf_t) + size_ops) % sizeof (double)); + buf = _cairo_malloc_ab_plus_c (size_points, sizeof (cairo_point_t), size_ops + sizeof (cairo_path_buf_t)); + if (buf) { + buf->num_ops = 0; + buf->num_points = 0; + buf->size_ops = size_ops; + buf->size_points = size_points; + + buf->op = (cairo_path_op_t *) (buf + 1); + buf->points = (cairo_point_t *) (buf->op + size_ops); + } + + return buf; +} + +static void +_cairo_path_buf_destroy (cairo_path_buf_t *buf) +{ + free (buf); +} + +static void +_cairo_path_buf_add_op (cairo_path_buf_t *buf, + cairo_path_op_t op) +{ + buf->op[buf->num_ops++] = op; +} + +static void +_cairo_path_buf_add_points (cairo_path_buf_t *buf, + const cairo_point_t *points, + int num_points) +{ + if (num_points == 0) + return; + + memcpy (buf->points + buf->num_points, + points, + sizeof (points[0]) * num_points); + buf->num_points += num_points; +} + +cairo_status_t +_cairo_path_fixed_interpret (const cairo_path_fixed_t *path, + cairo_path_fixed_move_to_func_t *move_to, + cairo_path_fixed_line_to_func_t *line_to, + cairo_path_fixed_curve_to_func_t *curve_to, + cairo_path_fixed_close_path_func_t *close_path, + void *closure) +{ + const cairo_path_buf_t *buf; + cairo_status_t status; + + cairo_path_foreach_buf_start (buf, path) { + const cairo_point_t *points = buf->points; + unsigned int i; + + for (i = 0; i < buf->num_ops; i++) { + switch (buf->op[i]) { + case CAIRO_PATH_OP_MOVE_TO: + status = (*move_to) (closure, &points[0]); + points += 1; + break; + case CAIRO_PATH_OP_LINE_TO: + status = (*line_to) (closure, &points[0]); + points += 1; + break; + case CAIRO_PATH_OP_CURVE_TO: + status = (*curve_to) (closure, &points[0], &points[1], &points[2]); + points += 3; + break; + default: + ASSERT_NOT_REACHED; + case CAIRO_PATH_OP_CLOSE_PATH: + status = (*close_path) (closure); + break; + } + + if (unlikely (status)) + return status; + } + } cairo_path_foreach_buf_end (buf, path); + + if (path->needs_move_to && path->has_current_point) + return (*move_to) (closure, &path->current_point); + + return CAIRO_STATUS_SUCCESS; +} + +typedef struct _cairo_path_fixed_append_closure { + cairo_point_t offset; + cairo_path_fixed_t *path; +} cairo_path_fixed_append_closure_t; + +static cairo_status_t +_append_move_to (void *abstract_closure, + const cairo_point_t *point) +{ + cairo_path_fixed_append_closure_t *closure = abstract_closure; + + return _cairo_path_fixed_move_to (closure->path, + point->x + closure->offset.x, + point->y + closure->offset.y); +} + +static cairo_status_t +_append_line_to (void *abstract_closure, + const cairo_point_t *point) +{ + cairo_path_fixed_append_closure_t *closure = abstract_closure; + + return _cairo_path_fixed_line_to (closure->path, + point->x + closure->offset.x, + point->y + closure->offset.y); +} + +static cairo_status_t +_append_curve_to (void *abstract_closure, + const cairo_point_t *p0, + const cairo_point_t *p1, + const cairo_point_t *p2) +{ + cairo_path_fixed_append_closure_t *closure = abstract_closure; + + return _cairo_path_fixed_curve_to (closure->path, + p0->x + closure->offset.x, + p0->y + closure->offset.y, + p1->x + closure->offset.x, + p1->y + closure->offset.y, + p2->x + closure->offset.x, + p2->y + closure->offset.y); +} + +static cairo_status_t +_append_close_path (void *abstract_closure) +{ + cairo_path_fixed_append_closure_t *closure = abstract_closure; + + return _cairo_path_fixed_close_path (closure->path); +} + +cairo_status_t +_cairo_path_fixed_append (cairo_path_fixed_t *path, + const cairo_path_fixed_t *other, + cairo_fixed_t tx, + cairo_fixed_t ty) +{ + cairo_path_fixed_append_closure_t closure; + + closure.path = path; + closure.offset.x = tx; + closure.offset.y = ty; + + return _cairo_path_fixed_interpret (other, + _append_move_to, + _append_line_to, + _append_curve_to, + _append_close_path, + &closure); +} + +static void +_cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path, + cairo_fixed_t offx, + cairo_fixed_t offy, + cairo_fixed_t scalex, + cairo_fixed_t scaley) +{ + cairo_path_buf_t *buf; + unsigned int i; + + if (scalex == CAIRO_FIXED_ONE && scaley == CAIRO_FIXED_ONE) { + _cairo_path_fixed_translate (path, offx, offy); + return; + } + + path->last_move_point.x = _cairo_fixed_mul (scalex, path->last_move_point.x) + offx; + path->last_move_point.y = _cairo_fixed_mul (scaley, path->last_move_point.y) + offy; + path->current_point.x = _cairo_fixed_mul (scalex, path->current_point.x) + offx; + path->current_point.y = _cairo_fixed_mul (scaley, path->current_point.y) + offy; + + path->fill_maybe_region = TRUE; + + cairo_path_foreach_buf_start (buf, path) { + for (i = 0; i < buf->num_points; i++) { + if (scalex != CAIRO_FIXED_ONE) + buf->points[i].x = _cairo_fixed_mul (buf->points[i].x, scalex); + buf->points[i].x += offx; + + if (scaley != CAIRO_FIXED_ONE) + buf->points[i].y = _cairo_fixed_mul (buf->points[i].y, scaley); + buf->points[i].y += offy; + + if (path->fill_maybe_region) { + path->fill_maybe_region = _cairo_fixed_is_integer (buf->points[i].x) && + _cairo_fixed_is_integer (buf->points[i].y); + } + } + } cairo_path_foreach_buf_end (buf, path); + + path->fill_maybe_region &= path->fill_is_rectilinear; + + path->extents.p1.x = _cairo_fixed_mul (scalex, path->extents.p1.x) + offx; + path->extents.p2.x = _cairo_fixed_mul (scalex, path->extents.p2.x) + offx; + if (scalex < 0) { + cairo_fixed_t t = path->extents.p1.x; + path->extents.p1.x = path->extents.p2.x; + path->extents.p2.x = t; + } + + path->extents.p1.y = _cairo_fixed_mul (scaley, path->extents.p1.y) + offy; + path->extents.p2.y = _cairo_fixed_mul (scaley, path->extents.p2.y) + offy; + if (scaley < 0) { + cairo_fixed_t t = path->extents.p1.y; + path->extents.p1.y = path->extents.p2.y; + path->extents.p2.y = t; + } +} + +void +_cairo_path_fixed_translate (cairo_path_fixed_t *path, + cairo_fixed_t offx, + cairo_fixed_t offy) +{ + cairo_path_buf_t *buf; + unsigned int i; + + if (offx == 0 && offy == 0) + return; + + path->last_move_point.x += offx; + path->last_move_point.y += offy; + path->current_point.x += offx; + path->current_point.y += offy; + + path->fill_maybe_region = TRUE; + + cairo_path_foreach_buf_start (buf, path) { + for (i = 0; i < buf->num_points; i++) { + buf->points[i].x += offx; + buf->points[i].y += offy; + + if (path->fill_maybe_region) { + path->fill_maybe_region = _cairo_fixed_is_integer (buf->points[i].x) && + _cairo_fixed_is_integer (buf->points[i].y); + } + } + } cairo_path_foreach_buf_end (buf, path); + + path->fill_maybe_region &= path->fill_is_rectilinear; + + path->extents.p1.x += offx; + path->extents.p1.y += offy; + path->extents.p2.x += offx; + path->extents.p2.y += offy; +} + + +static inline void +_cairo_path_fixed_transform_point (cairo_point_t *p, + const cairo_matrix_t *matrix) +{ + double dx, dy; + + dx = _cairo_fixed_to_double (p->x); + dy = _cairo_fixed_to_double (p->y); + cairo_matrix_transform_point (matrix, &dx, &dy); + p->x = _cairo_fixed_from_double (dx); + p->y = _cairo_fixed_from_double (dy); +} + +/** + * _cairo_path_fixed_transform: + * @path: a #cairo_path_fixed_t to be transformed + * @matrix: a #cairo_matrix_t + * + * Transform the fixed-point path according to the given matrix. + * There is a fast path for the case where @matrix has no rotation + * or shear. + **/ +void +_cairo_path_fixed_transform (cairo_path_fixed_t *path, + const cairo_matrix_t *matrix) +{ + cairo_box_t extents; + cairo_point_t point; + cairo_path_buf_t *buf; + unsigned int i; + + if (matrix->yx == 0.0 && matrix->xy == 0.0) { + /* Fast path for the common case of scale+transform */ + _cairo_path_fixed_offset_and_scale (path, + _cairo_fixed_from_double (matrix->x0), + _cairo_fixed_from_double (matrix->y0), + _cairo_fixed_from_double (matrix->xx), + _cairo_fixed_from_double (matrix->yy)); + return; + } + + _cairo_path_fixed_transform_point (&path->last_move_point, matrix); + _cairo_path_fixed_transform_point (&path->current_point, matrix); + + buf = cairo_path_head (path); + if (buf->num_points == 0) + return; + + extents = path->extents; + point = buf->points[0]; + _cairo_path_fixed_transform_point (&point, matrix); + _cairo_box_set (&path->extents, &point, &point); + + cairo_path_foreach_buf_start (buf, path) { + for (i = 0; i < buf->num_points; i++) { + _cairo_path_fixed_transform_point (&buf->points[i], matrix); + _cairo_box_add_point (&path->extents, &buf->points[i]); + } + } cairo_path_foreach_buf_end (buf, path); + + if (path->has_curve_to) { + cairo_bool_t is_tight; + + _cairo_matrix_transform_bounding_box_fixed (matrix, &extents, &is_tight); + if (!is_tight) { + cairo_bool_t has_extents; + + has_extents = _cairo_path_bounder_extents (path, &extents); + assert (has_extents); + } + path->extents = extents; + } + + /* flags might become more strict than needed */ + path->stroke_is_rectilinear = FALSE; + path->fill_is_rectilinear = FALSE; + path->fill_is_empty = FALSE; + path->fill_maybe_region = FALSE; +} + +/* Closure for path flattening */ +typedef struct cairo_path_flattener { + double tolerance; + cairo_point_t current_point; + cairo_path_fixed_move_to_func_t *move_to; + cairo_path_fixed_line_to_func_t *line_to; + cairo_path_fixed_close_path_func_t *close_path; + void *closure; +} cpf_t; + +static cairo_status_t +_cpf_move_to (void *closure, + const cairo_point_t *point) +{ + cpf_t *cpf = closure; + + cpf->current_point = *point; + + return cpf->move_to (cpf->closure, point); +} + +static cairo_status_t +_cpf_line_to (void *closure, + const cairo_point_t *point) +{ + cpf_t *cpf = closure; + + cpf->current_point = *point; + + return cpf->line_to (cpf->closure, point); +} + +static cairo_status_t +_cpf_add_point (void *closure, + const cairo_point_t *point, + const cairo_slope_t *tangent) +{ + return _cpf_line_to (closure, point); +}; + +static cairo_status_t +_cpf_curve_to (void *closure, + const cairo_point_t *p1, + const cairo_point_t *p2, + const cairo_point_t *p3) +{ + cpf_t *cpf = closure; + cairo_spline_t spline; + + cairo_point_t *p0 = &cpf->current_point; + + if (! _cairo_spline_init (&spline, + _cpf_add_point, + cpf, + p0, p1, p2, p3)) + { + return _cpf_line_to (closure, p3); + } + + cpf->current_point = *p3; + + return _cairo_spline_decompose (&spline, cpf->tolerance); +} + +static cairo_status_t +_cpf_close_path (void *closure) +{ + cpf_t *cpf = closure; + + return cpf->close_path (cpf->closure); +} + +cairo_status_t +_cairo_path_fixed_interpret_flat (const cairo_path_fixed_t *path, + cairo_path_fixed_move_to_func_t *move_to, + cairo_path_fixed_line_to_func_t *line_to, + cairo_path_fixed_close_path_func_t *close_path, + void *closure, + double tolerance) +{ + cpf_t flattener; + + if (! path->has_curve_to) { + return _cairo_path_fixed_interpret (path, + move_to, + line_to, + NULL, + close_path, + closure); + } + + flattener.tolerance = tolerance; + flattener.move_to = move_to; + flattener.line_to = line_to; + flattener.close_path = close_path; + flattener.closure = closure; + return _cairo_path_fixed_interpret (path, + _cpf_move_to, + _cpf_line_to, + _cpf_curve_to, + _cpf_close_path, + &flattener); +} + +static inline void +_canonical_box (cairo_box_t *box, + const cairo_point_t *p1, + const cairo_point_t *p2) +{ + if (p1->x <= p2->x) { + box->p1.x = p1->x; + box->p2.x = p2->x; + } else { + box->p1.x = p2->x; + box->p2.x = p1->x; + } + + if (p1->y <= p2->y) { + box->p1.y = p1->y; + box->p2.y = p2->y; + } else { + box->p1.y = p2->y; + box->p2.y = p1->y; + } +} + +static inline cairo_bool_t +_path_is_quad (const cairo_path_fixed_t *path) +{ + const cairo_path_buf_t *buf = cairo_path_head (path); + + /* Do we have the right number of ops? */ + if (buf->num_ops < 4 || buf->num_ops > 6) + return FALSE; + + /* Check whether the ops are those that would be used for a rectangle */ + if (buf->op[0] != CAIRO_PATH_OP_MOVE_TO || + buf->op[1] != CAIRO_PATH_OP_LINE_TO || + buf->op[2] != CAIRO_PATH_OP_LINE_TO || + buf->op[3] != CAIRO_PATH_OP_LINE_TO) + { + return FALSE; + } + + /* we accept an implicit close for filled paths */ + if (buf->num_ops > 4) { + /* Now, there are choices. The rectangle might end with a LINE_TO + * (to the original point), but this isn't required. If it + * doesn't, then it must end with a CLOSE_PATH. */ + if (buf->op[4] == CAIRO_PATH_OP_LINE_TO) { + if (buf->points[4].x != buf->points[0].x || + buf->points[4].y != buf->points[0].y) + return FALSE; + } else if (buf->op[4] != CAIRO_PATH_OP_CLOSE_PATH) { + return FALSE; + } + + if (buf->num_ops == 6) { + /* A trailing CLOSE_PATH or MOVE_TO is ok */ + if (buf->op[5] != CAIRO_PATH_OP_MOVE_TO && + buf->op[5] != CAIRO_PATH_OP_CLOSE_PATH) + return FALSE; + } + } + + return TRUE; +} + +static inline cairo_bool_t +_points_form_rect (const cairo_point_t *points) +{ + if (points[0].y == points[1].y && + points[1].x == points[2].x && + points[2].y == points[3].y && + points[3].x == points[0].x) + return TRUE; + if (points[0].x == points[1].x && + points[1].y == points[2].y && + points[2].x == points[3].x && + points[3].y == points[0].y) + return TRUE; + return FALSE; +} + +/* + * Check whether the given path contains a single rectangle. + */ +cairo_bool_t +_cairo_path_fixed_is_box (const cairo_path_fixed_t *path, + cairo_box_t *box) +{ + const cairo_path_buf_t *buf; + + if (! path->fill_is_rectilinear) + return FALSE; + + if (! _path_is_quad (path)) + return FALSE; + + buf = cairo_path_head (path); + if (_points_form_rect (buf->points)) { + _canonical_box (box, &buf->points[0], &buf->points[2]); + return TRUE; + } + + return FALSE; +} + +/* Determine whether two lines A->B and C->D intersect based on the + * algorithm described here: http://paulbourke.net/geometry/pointlineplane/ */ +static inline cairo_bool_t +_lines_intersect_or_are_coincident (cairo_point_t a, + cairo_point_t b, + cairo_point_t c, + cairo_point_t d) +{ + cairo_int64_t numerator_a, numerator_b, denominator; + cairo_bool_t denominator_negative; + + denominator = _cairo_int64_sub (_cairo_int32x32_64_mul (d.y - c.y, b.x - a.x), + _cairo_int32x32_64_mul (d.x - c.x, b.y - a.y)); + numerator_a = _cairo_int64_sub (_cairo_int32x32_64_mul (d.x - c.x, a.y - c.y), + _cairo_int32x32_64_mul (d.y - c.y, a.x - c.x)); + numerator_b = _cairo_int64_sub (_cairo_int32x32_64_mul (b.x - a.x, a.y - c.y), + _cairo_int32x32_64_mul (b.y - a.y, a.x - c.x)); + + if (_cairo_int64_is_zero (denominator)) { + /* If the denominator and numerators are both zero, + * the lines are coincident. */ + if (_cairo_int64_is_zero (numerator_a) && _cairo_int64_is_zero (numerator_b)) + return TRUE; + + /* Otherwise, a zero denominator indicates the lines are + * parallel and never intersect. */ + return FALSE; + } + + /* The lines intersect if both quotients are between 0 and 1 (exclusive). */ + + /* We first test whether either quotient is a negative number. */ + denominator_negative = _cairo_int64_negative (denominator); + if (_cairo_int64_negative (numerator_a) ^ denominator_negative) + return FALSE; + if (_cairo_int64_negative (numerator_b) ^ denominator_negative) + return FALSE; + + /* A zero quotient indicates an "intersection" at an endpoint, which + * we aren't considering a true intersection. */ + if (_cairo_int64_is_zero (numerator_a) || _cairo_int64_is_zero (numerator_b)) + return FALSE; + + /* If the absolute value of the numerator is larger than or equal to the + * denominator the result of the division would be greater than or equal + * to one. */ + if (! denominator_negative) { + if (! _cairo_int64_lt (numerator_a, denominator) || + ! _cairo_int64_lt (numerator_b, denominator)) + return FALSE; + } else { + if (! _cairo_int64_lt (denominator, numerator_a) || + ! _cairo_int64_lt (denominator, numerator_b)) + return FALSE; + } + + return TRUE; +} + +cairo_bool_t +_cairo_path_fixed_is_simple_quad (const cairo_path_fixed_t *path) +{ + const cairo_point_t *points; + + if (! _path_is_quad (path)) + return FALSE; + + points = cairo_path_head (path)->points; + if (_points_form_rect (points)) + return TRUE; + + if (_lines_intersect_or_are_coincident (points[0], points[1], + points[3], points[2])) + return FALSE; + + if (_lines_intersect_or_are_coincident (points[0], points[3], + points[1], points[2])) + return FALSE; + + return TRUE; +} + +cairo_bool_t +_cairo_path_fixed_is_stroke_box (const cairo_path_fixed_t *path, + cairo_box_t *box) +{ + const cairo_path_buf_t *buf = cairo_path_head (path); + + if (! path->fill_is_rectilinear) + return FALSE; + + /* Do we have the right number of ops? */ + if (buf->num_ops != 5) + return FALSE; + + /* Check whether the ops are those that would be used for a rectangle */ + if (buf->op[0] != CAIRO_PATH_OP_MOVE_TO || + buf->op[1] != CAIRO_PATH_OP_LINE_TO || + buf->op[2] != CAIRO_PATH_OP_LINE_TO || + buf->op[3] != CAIRO_PATH_OP_LINE_TO || + buf->op[4] != CAIRO_PATH_OP_CLOSE_PATH) + { + return FALSE; + } + + /* Ok, we may have a box, if the points line up */ + if (buf->points[0].y == buf->points[1].y && + buf->points[1].x == buf->points[2].x && + buf->points[2].y == buf->points[3].y && + buf->points[3].x == buf->points[0].x) + { + _canonical_box (box, &buf->points[0], &buf->points[2]); + return TRUE; + } + + if (buf->points[0].x == buf->points[1].x && + buf->points[1].y == buf->points[2].y && + buf->points[2].x == buf->points[3].x && + buf->points[3].y == buf->points[0].y) + { + _canonical_box (box, &buf->points[0], &buf->points[2]); + return TRUE; + } + + return FALSE; +} + +/* + * Check whether the given path contains a single rectangle + * that is logically equivalent to: + * + * cairo_move_to (cr, x, y); + * cairo_rel_line_to (cr, width, 0); + * cairo_rel_line_to (cr, 0, height); + * cairo_rel_line_to (cr, -width, 0); + * cairo_close_path (cr); + * + */ +cairo_bool_t +_cairo_path_fixed_is_rectangle (const cairo_path_fixed_t *path, + cairo_box_t *box) +{ + const cairo_path_buf_t *buf; + + if (! _cairo_path_fixed_is_box (path, box)) + return FALSE; + + /* This check is valid because the current implementation of + * _cairo_path_fixed_is_box () only accepts rectangles like: + * move,line,line,line[,line|close[,close|move]]. */ + buf = cairo_path_head (path); + if (buf->num_ops > 4) + return TRUE; + + return FALSE; +} + +void +_cairo_path_fixed_iter_init (cairo_path_fixed_iter_t *iter, + const cairo_path_fixed_t *path) +{ + iter->first = iter->buf = cairo_path_head (path); + iter->n_op = 0; + iter->n_point = 0; +} + +static cairo_bool_t +_cairo_path_fixed_iter_next_op (cairo_path_fixed_iter_t *iter) +{ + if (++iter->n_op >= iter->buf->num_ops) { + iter->buf = cairo_path_buf_next (iter->buf); + if (iter->buf == iter->first) { + iter->buf = NULL; + return FALSE; + } + + iter->n_op = 0; + iter->n_point = 0; + } + + return TRUE; +} + +cairo_bool_t +_cairo_path_fixed_iter_is_fill_box (cairo_path_fixed_iter_t *_iter, + cairo_box_t *box) +{ + cairo_point_t points[5]; + cairo_path_fixed_iter_t iter; + + if (_iter->buf == NULL) + return FALSE; + + iter = *_iter; + + if (iter.n_op == iter.buf->num_ops && ! _cairo_path_fixed_iter_next_op (&iter)) + return FALSE; + + /* Check whether the ops are those that would be used for a rectangle */ + if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_MOVE_TO) + return FALSE; + points[0] = iter.buf->points[iter.n_point++]; + if (! _cairo_path_fixed_iter_next_op (&iter)) + return FALSE; + + if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_LINE_TO) + return FALSE; + points[1] = iter.buf->points[iter.n_point++]; + if (! _cairo_path_fixed_iter_next_op (&iter)) + return FALSE; + + /* a horizontal/vertical closed line is also a degenerate rectangle */ + switch (iter.buf->op[iter.n_op]) { + case CAIRO_PATH_OP_CLOSE_PATH: + _cairo_path_fixed_iter_next_op (&iter); /* fall through */ + case CAIRO_PATH_OP_MOVE_TO: /* implicit close */ + box->p1 = box->p2 = points[0]; + *_iter = iter; + return TRUE; + default: + return FALSE; + case CAIRO_PATH_OP_LINE_TO: + break; + } + + points[2] = iter.buf->points[iter.n_point++]; + if (! _cairo_path_fixed_iter_next_op (&iter)) + return FALSE; + + if (iter.buf->op[iter.n_op] != CAIRO_PATH_OP_LINE_TO) + return FALSE; + points[3] = iter.buf->points[iter.n_point++]; + + /* Now, there are choices. The rectangle might end with a LINE_TO + * (to the original point), but this isn't required. If it + * doesn't, then it must end with a CLOSE_PATH (which may be implicit). */ + if (! _cairo_path_fixed_iter_next_op (&iter)) { + /* implicit close due to fill */ + } else if (iter.buf->op[iter.n_op] == CAIRO_PATH_OP_LINE_TO) { + points[4] = iter.buf->points[iter.n_point++]; + if (points[4].x != points[0].x || points[4].y != points[0].y) + return FALSE; + _cairo_path_fixed_iter_next_op (&iter); + } else if (iter.buf->op[iter.n_op] == CAIRO_PATH_OP_CLOSE_PATH) { + _cairo_path_fixed_iter_next_op (&iter); + } else if (iter.buf->op[iter.n_op] == CAIRO_PATH_OP_MOVE_TO) { + /* implicit close-path due to new-sub-path */ + } else { + return FALSE; + } + + /* Ok, we may have a box, if the points line up */ + if (points[0].y == points[1].y && + points[1].x == points[2].x && + points[2].y == points[3].y && + points[3].x == points[0].x) + { + box->p1 = points[0]; + box->p2 = points[2]; + *_iter = iter; + return TRUE; + } + + if (points[0].x == points[1].x && + points[1].y == points[2].y && + points[2].x == points[3].x && + points[3].y == points[0].y) + { + box->p1 = points[1]; + box->p2 = points[3]; + *_iter = iter; + return TRUE; + } + + return FALSE; +} + +cairo_bool_t +_cairo_path_fixed_iter_at_end (const cairo_path_fixed_iter_t *iter) +{ + if (iter->buf == NULL) + return TRUE; + + return iter->n_op == iter->buf->num_ops; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-path-in-fill.c b/local/recipes/libs/cairo/source/src/cairo-path-in-fill.c new file mode 100644 index 0000000000..342d5a28e8 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-path-in-fill.c @@ -0,0 +1,298 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2008 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Chris Wilson. + * + * Contributor(s): + * Chris Wilson + */ + +#include "cairoint.h" +#include "cairo-path-fixed-private.h" + +typedef struct cairo_in_fill { + double tolerance; + cairo_bool_t on_edge; + int winding; + + cairo_fixed_t x, y; + + cairo_bool_t has_current_point; + cairo_point_t current_point; + cairo_point_t first_point; +} cairo_in_fill_t; + +static void +_cairo_in_fill_init (cairo_in_fill_t *in_fill, + double tolerance, + double x, + double y) +{ + in_fill->on_edge = FALSE; + in_fill->winding = 0; + in_fill->tolerance = tolerance; + + in_fill->x = _cairo_fixed_from_double (x); + in_fill->y = _cairo_fixed_from_double (y); + + in_fill->has_current_point = FALSE; + in_fill->current_point.x = 0; + in_fill->current_point.y = 0; +} + +static void +_cairo_in_fill_fini (cairo_in_fill_t *in_fill) +{ +} + +static int +edge_compare_for_y_against_x (const cairo_point_t *p1, + const cairo_point_t *p2, + cairo_fixed_t y, + cairo_fixed_t x) +{ + cairo_fixed_t adx, ady; + cairo_fixed_t dx, dy; + cairo_int64_t L, R; + + adx = p2->x - p1->x; + dx = x - p1->x; + + if (adx == 0) + return -dx; + if ((adx ^ dx) < 0) + return adx; + + dy = y - p1->y; + ady = p2->y - p1->y; + + L = _cairo_int32x32_64_mul (dy, adx); + R = _cairo_int32x32_64_mul (dx, ady); + + return _cairo_int64_cmp (L, R); +} + +static void +_cairo_in_fill_add_edge (cairo_in_fill_t *in_fill, + const cairo_point_t *p1, + const cairo_point_t *p2) +{ + int dir; + + if (in_fill->on_edge) + return; + + /* count the number of edge crossing to -∞ */ + + dir = 1; + if (p2->y < p1->y) { + const cairo_point_t *tmp; + + tmp = p1; + p1 = p2; + p2 = tmp; + + dir = -1; + } + + /* First check whether the query is on an edge */ + if ((p1->x == in_fill->x && p1->y == in_fill->y) || + (p2->x == in_fill->x && p2->y == in_fill->y) || + (! (p2->y < in_fill->y || p1->y > in_fill->y || + (p1->x > in_fill->x && p2->x > in_fill->x) || + (p1->x < in_fill->x && p2->x < in_fill->x)) && + edge_compare_for_y_against_x (p1, p2, in_fill->y, in_fill->x) == 0)) + { + in_fill->on_edge = TRUE; + return; + } + + /* edge is entirely above or below, note the shortening rule */ + if (p2->y <= in_fill->y || p1->y > in_fill->y) + return; + + /* edge lies wholly to the right */ + if (p1->x >= in_fill->x && p2->x >= in_fill->x) + return; + + if ((p1->x <= in_fill->x && p2->x <= in_fill->x) || + edge_compare_for_y_against_x (p1, p2, in_fill->y, in_fill->x) < 0) + { + in_fill->winding += dir; + } +} + +static cairo_status_t +_cairo_in_fill_move_to (void *closure, + const cairo_point_t *point) +{ + cairo_in_fill_t *in_fill = closure; + + /* implicit close path */ + if (in_fill->has_current_point) { + _cairo_in_fill_add_edge (in_fill, + &in_fill->current_point, + &in_fill->first_point); + } + + in_fill->first_point = *point; + in_fill->current_point = *point; + in_fill->has_current_point = TRUE; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_in_fill_line_to (void *closure, + const cairo_point_t *point) +{ + cairo_in_fill_t *in_fill = closure; + + if (in_fill->has_current_point) + _cairo_in_fill_add_edge (in_fill, &in_fill->current_point, point); + + in_fill->current_point = *point; + in_fill->has_current_point = TRUE; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_in_fill_add_point (void *closure, + const cairo_point_t *point, + const cairo_slope_t *tangent) +{ + return _cairo_in_fill_line_to (closure, point); +}; + +static cairo_status_t +_cairo_in_fill_curve_to (void *closure, + const cairo_point_t *b, + const cairo_point_t *c, + const cairo_point_t *d) +{ + cairo_in_fill_t *in_fill = closure; + cairo_spline_t spline; + cairo_fixed_t top, bot, left; + + /* first reject based on bbox */ + bot = top = in_fill->current_point.y; + if (b->y < top) top = b->y; + if (b->y > bot) bot = b->y; + if (c->y < top) top = c->y; + if (c->y > bot) bot = c->y; + if (d->y < top) top = d->y; + if (d->y > bot) bot = d->y; + if (bot < in_fill->y || top > in_fill->y) { + in_fill->current_point = *d; + return CAIRO_STATUS_SUCCESS; + } + + left = in_fill->current_point.x; + if (b->x < left) left = b->x; + if (c->x < left) left = c->x; + if (d->x < left) left = d->x; + if (left > in_fill->x) { + in_fill->current_point = *d; + return CAIRO_STATUS_SUCCESS; + } + + /* XXX Investigate direct inspection of the inflections? */ + if (! _cairo_spline_init (&spline, + _cairo_in_fill_add_point, + in_fill, + &in_fill->current_point, b, c, d)) + { + return CAIRO_STATUS_SUCCESS; + } + + return _cairo_spline_decompose (&spline, in_fill->tolerance); +} + +static cairo_status_t +_cairo_in_fill_close_path (void *closure) +{ + cairo_in_fill_t *in_fill = closure; + + if (in_fill->has_current_point) { + _cairo_in_fill_add_edge (in_fill, + &in_fill->current_point, + &in_fill->first_point); + + in_fill->has_current_point = FALSE; + } + + return CAIRO_STATUS_SUCCESS; +} + +cairo_bool_t +_cairo_path_fixed_in_fill (const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + double x, + double y) +{ + cairo_in_fill_t in_fill; + cairo_status_t status; + cairo_bool_t is_inside; + + if (_cairo_path_fixed_fill_is_empty (path)) + return FALSE; + + _cairo_in_fill_init (&in_fill, tolerance, x, y); + + status = _cairo_path_fixed_interpret (path, + _cairo_in_fill_move_to, + _cairo_in_fill_line_to, + _cairo_in_fill_curve_to, + _cairo_in_fill_close_path, + &in_fill); + assert (status == CAIRO_STATUS_SUCCESS); + + _cairo_in_fill_close_path (&in_fill); + + if (in_fill.on_edge) { + is_inside = TRUE; + } else switch (fill_rule) { + case CAIRO_FILL_RULE_EVEN_ODD: + is_inside = in_fill.winding & 1; + break; + case CAIRO_FILL_RULE_WINDING: + is_inside = in_fill.winding != 0; + break; + default: + ASSERT_NOT_REACHED; + is_inside = FALSE; + break; + } + + _cairo_in_fill_fini (&in_fill); + + return is_inside; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-path-private.h b/local/recipes/libs/cairo/source/src/cairo-path-private.h new file mode 100644 index 0000000000..7b54317e20 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-path-private.h @@ -0,0 +1,57 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2006 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Carl D. Worth + */ + +#ifndef CAIRO_PATH_PRIVATE_H +#define CAIRO_PATH_PRIVATE_H + +#include "cairoint.h" + +cairo_private cairo_path_t * +_cairo_path_create (cairo_path_fixed_t *path, + cairo_t *cr); + +cairo_private cairo_path_t * +_cairo_path_create_flat (cairo_path_fixed_t *path, + cairo_t *cr); + +cairo_private cairo_path_t * +_cairo_path_create_in_error (cairo_status_t status); + +cairo_private cairo_status_t +_cairo_path_append_to_context (const cairo_path_t *path, + cairo_t *cr); + +#endif /* CAIRO_PATH_DATA_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-path-stroke-boxes.c b/local/recipes/libs/cairo/source/src/cairo-path-stroke-boxes.c new file mode 100644 index 0000000000..fba170c638 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-path-stroke-boxes.c @@ -0,0 +1,711 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Chris Wilson + */ + +#define _DEFAULT_SOURCE /* for hypot() */ +#include "cairoint.h" + +#include "cairo-box-inline.h" +#include "cairo-boxes-private.h" +#include "cairo-error-private.h" +#include "cairo-path-fixed-private.h" +#include "cairo-slope-private.h" +#include "cairo-stroke-dash-private.h" + +typedef struct _segment_t { + cairo_point_t p1, p2; + unsigned flags; +#define HORIZONTAL 0x1 +#define FORWARDS 0x2 +#define JOIN 0x4 +} segment_t; + +typedef struct _cairo_rectilinear_stroker { + const cairo_stroke_style_t *stroke_style; + const cairo_matrix_t *ctm; + cairo_antialias_t antialias; + + cairo_fixed_t half_line_x, half_line_y; + cairo_boxes_t *boxes; + cairo_point_t current_point; + cairo_point_t first_point; + cairo_bool_t open_sub_path; + + cairo_stroker_dash_t dash; + + cairo_bool_t has_bounds; + cairo_box_t bounds; + + int num_segments; + int segments_size; + segment_t *segments; + segment_t segments_embedded[8]; /* common case is a single rectangle */ +} cairo_rectilinear_stroker_t; + +static void +_cairo_rectilinear_stroker_limit (cairo_rectilinear_stroker_t *stroker, + const cairo_box_t *boxes, + int num_boxes) +{ + stroker->has_bounds = TRUE; + _cairo_boxes_get_extents (boxes, num_boxes, &stroker->bounds); + + stroker->bounds.p1.x -= stroker->half_line_x; + stroker->bounds.p2.x += stroker->half_line_x; + + stroker->bounds.p1.y -= stroker->half_line_y; + stroker->bounds.p2.y += stroker->half_line_y; +} + +static cairo_bool_t +_cairo_rectilinear_stroker_init (cairo_rectilinear_stroker_t *stroker, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + cairo_antialias_t antialias, + cairo_boxes_t *boxes) +{ + /* This special-case rectilinear stroker only supports + * miter-joined lines (not curves) and a translation-only matrix + * (though it could probably be extended to support a matrix with + * uniform, integer scaling). + * + * It also only supports horizontal and vertical line_to + * elements. But we don't catch that here, but instead return + * UNSUPPORTED from _cairo_rectilinear_stroker_line_to if any + * non-rectilinear line_to is encountered. + */ + if (stroke_style->line_join != CAIRO_LINE_JOIN_MITER) + return FALSE; + + /* If the miter limit turns right angles into bevels, then we + * can't use this optimization. Remember, the ratio is + * 1/sin(ɸ/2). So the cutoff is 1/sin(Ï€/4.0) or ⎷2, + * which we round for safety. */ + if (stroke_style->miter_limit < M_SQRT2) + return FALSE; + + if (! (stroke_style->line_cap == CAIRO_LINE_CAP_BUTT || + stroke_style->line_cap == CAIRO_LINE_CAP_SQUARE)) + { + return FALSE; + } + + if (! _cairo_matrix_is_scale (ctm)) + return FALSE; + + stroker->stroke_style = stroke_style; + stroker->ctm = ctm; + stroker->antialias = antialias; + + stroker->half_line_x = + _cairo_fixed_from_double (fabs(ctm->xx) * stroke_style->line_width / 2.0); + stroker->half_line_y = + _cairo_fixed_from_double (fabs(ctm->yy) * stroke_style->line_width / 2.0); + + stroker->open_sub_path = FALSE; + stroker->segments = stroker->segments_embedded; + stroker->segments_size = ARRAY_LENGTH (stroker->segments_embedded); + stroker->num_segments = 0; + + _cairo_stroker_dash_init (&stroker->dash, stroke_style); + + stroker->has_bounds = FALSE; + + stroker->boxes = boxes; + + return TRUE; +} + +static void +_cairo_rectilinear_stroker_fini (cairo_rectilinear_stroker_t *stroker) +{ + if (stroker->segments != stroker->segments_embedded) + free (stroker->segments); +} + +static cairo_status_t +_cairo_rectilinear_stroker_add_segment (cairo_rectilinear_stroker_t *stroker, + const cairo_point_t *p1, + const cairo_point_t *p2, + unsigned flags) +{ + if (CAIRO_INJECT_FAULT ()) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + if (stroker->num_segments == stroker->segments_size) { + int new_size = stroker->segments_size * 2; + segment_t *new_segments; + + if (stroker->segments == stroker->segments_embedded) { + new_segments = _cairo_malloc_ab (new_size, sizeof (segment_t)); + if (unlikely (new_segments == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + memcpy (new_segments, stroker->segments, + stroker->num_segments * sizeof (segment_t)); + } else { + new_segments = _cairo_realloc_ab (stroker->segments, + new_size, sizeof (segment_t)); + if (unlikely (new_segments == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + stroker->segments_size = new_size; + stroker->segments = new_segments; + } + + stroker->segments[stroker->num_segments].p1 = *p1; + stroker->segments[stroker->num_segments].p2 = *p2; + stroker->segments[stroker->num_segments].flags = flags; + stroker->num_segments++; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_rectilinear_stroker_emit_segments (cairo_rectilinear_stroker_t *stroker) +{ + cairo_line_cap_t line_cap = stroker->stroke_style->line_cap; + cairo_fixed_t half_line_x = stroker->half_line_x; + cairo_fixed_t half_line_y = stroker->half_line_y; + cairo_status_t status; + int i, j; + + /* For each segment we generate a single rectangle. + * This rectangle is based on a perpendicular extension (by half the + * line width) of the segment endpoints * after some adjustments of the + * endpoints to account for caps and joins. + */ + for (i = 0; i < stroker->num_segments; i++) { + cairo_bool_t lengthen_initial, lengthen_final; + cairo_point_t *a, *b; + cairo_box_t box; + + a = &stroker->segments[i].p1; + b = &stroker->segments[i].p2; + + /* We adjust the initial point of the segment to extend the + * rectangle to include the previous cap or join, (this + * adjustment applies to all segments except for the first + * segment of open, butt-capped paths). However, we must be + * careful not to emit a miter join across a degenerate segment + * which has been elided. + * + * Overlapping segments will be eliminated by the tessellation. + * Ideally, we would not emit these self-intersections at all, + * but that is tricky with segments shorter than half_line_width. + */ + j = i == 0 ? stroker->num_segments - 1 : i-1; + lengthen_initial = (stroker->segments[i].flags ^ stroker->segments[j].flags) & HORIZONTAL; + j = i == stroker->num_segments - 1 ? 0 : i+1; + lengthen_final = (stroker->segments[i].flags ^ stroker->segments[j].flags) & HORIZONTAL; + if (stroker->open_sub_path) { + if (i == 0) + lengthen_initial = line_cap != CAIRO_LINE_CAP_BUTT; + + if (i == stroker->num_segments - 1) + lengthen_final = line_cap != CAIRO_LINE_CAP_BUTT; + } + + /* Perform the adjustments of the endpoints. */ + if (lengthen_initial | lengthen_final) { + if (a->y == b->y) { + if (a->x < b->x) { + if (lengthen_initial) + a->x -= half_line_x; + if (lengthen_final) + b->x += half_line_x; + } else { + if (lengthen_initial) + a->x += half_line_x; + if (lengthen_final) + b->x -= half_line_x; + } + } else { + if (a->y < b->y) { + if (lengthen_initial) + a->y -= half_line_y; + if (lengthen_final) + b->y += half_line_y; + } else { + if (lengthen_initial) + a->y += half_line_y; + if (lengthen_final) + b->y -= half_line_y; + } + } + } + + /* Form the rectangle by expanding by half the line width in + * either perpendicular direction. */ + if (a->y == b->y) { + a->y -= half_line_y; + b->y += half_line_y; + } else { + a->x -= half_line_x; + b->x += half_line_x; + } + + if (a->x < b->x) { + box.p1.x = a->x; + box.p2.x = b->x; + } else { + box.p1.x = b->x; + box.p2.x = a->x; + } + if (a->y < b->y) { + box.p1.y = a->y; + box.p2.y = b->y; + } else { + box.p1.y = b->y; + box.p2.y = a->y; + } + + status = _cairo_boxes_add (stroker->boxes, stroker->antialias, &box); + if (unlikely (status)) + return status; + } + + stroker->num_segments = 0; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_rectilinear_stroker_emit_segments_dashed (cairo_rectilinear_stroker_t *stroker) +{ + cairo_status_t status; + cairo_line_cap_t line_cap = stroker->stroke_style->line_cap; + cairo_fixed_t half_line_x = stroker->half_line_x; + cairo_fixed_t half_line_y = stroker->half_line_y; + int i; + + for (i = 0; i < stroker->num_segments; i++) { + cairo_point_t *a, *b; + cairo_bool_t is_horizontal; + cairo_box_t box; + + a = &stroker->segments[i].p1; + b = &stroker->segments[i].p2; + + is_horizontal = stroker->segments[i].flags & HORIZONTAL; + + /* Handle the joins for a potentially degenerate segment. */ + if (line_cap == CAIRO_LINE_CAP_BUTT && + stroker->segments[i].flags & JOIN && + (i != stroker->num_segments - 1 || + (! stroker->open_sub_path && stroker->dash.dash_starts_on))) + { + cairo_slope_t out_slope; + int j = (i + 1) % stroker->num_segments; + cairo_bool_t forwards = !!(stroker->segments[i].flags & FORWARDS); + + _cairo_slope_init (&out_slope, + &stroker->segments[j].p1, + &stroker->segments[j].p2); + box.p2 = box.p1 = stroker->segments[i].p2; + + if (is_horizontal) { + if (forwards) + box.p2.x += half_line_x; + else + box.p1.x -= half_line_x; + + if (out_slope.dy > 0) + box.p1.y -= half_line_y; + else + box.p2.y += half_line_y; + } else { + if (forwards) + box.p2.y += half_line_y; + else + box.p1.y -= half_line_y; + + if (out_slope.dx > 0) + box.p1.x -= half_line_x; + else + box.p2.x += half_line_x; + } + + status = _cairo_boxes_add (stroker->boxes, stroker->antialias, &box); + if (unlikely (status)) + return status; + } + + /* Perform the adjustments of the endpoints. */ + if (is_horizontal) { + if (line_cap == CAIRO_LINE_CAP_SQUARE) { + if (a->x <= b->x) { + a->x -= half_line_x; + b->x += half_line_x; + } else { + a->x += half_line_x; + b->x -= half_line_x; + } + } + + a->y += half_line_y; + b->y -= half_line_y; + } else { + if (line_cap == CAIRO_LINE_CAP_SQUARE) { + if (a->y <= b->y) { + a->y -= half_line_y; + b->y += half_line_y; + } else { + a->y += half_line_y; + b->y -= half_line_y; + } + } + + a->x += half_line_x; + b->x -= half_line_x; + } + + if (a->x == b->x && a->y == b->y) + continue; + + if (a->x < b->x) { + box.p1.x = a->x; + box.p2.x = b->x; + } else { + box.p1.x = b->x; + box.p2.x = a->x; + } + if (a->y < b->y) { + box.p1.y = a->y; + box.p2.y = b->y; + } else { + box.p1.y = b->y; + box.p2.y = a->y; + } + + status = _cairo_boxes_add (stroker->boxes, stroker->antialias, &box); + if (unlikely (status)) + return status; + } + + stroker->num_segments = 0; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_rectilinear_stroker_move_to (void *closure, + const cairo_point_t *point) +{ + cairo_rectilinear_stroker_t *stroker = closure; + cairo_status_t status; + + if (stroker->dash.dashed) + status = _cairo_rectilinear_stroker_emit_segments_dashed (stroker); + else + status = _cairo_rectilinear_stroker_emit_segments (stroker); + if (unlikely (status)) + return status; + + /* reset the dash pattern for new sub paths */ + _cairo_stroker_dash_start (&stroker->dash); + + stroker->current_point = *point; + stroker->first_point = *point; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_rectilinear_stroker_line_to (void *closure, + const cairo_point_t *b) +{ + cairo_rectilinear_stroker_t *stroker = closure; + cairo_point_t *a = &stroker->current_point; + cairo_status_t status; + + /* We only support horizontal or vertical elements. */ + assert (a->x == b->x || a->y == b->y); + + /* We don't draw anything for degenerate paths. */ + if (a->x == b->x && a->y == b->y) + return CAIRO_STATUS_SUCCESS; + + status = _cairo_rectilinear_stroker_add_segment (stroker, a, b, + (a->y == b->y) | JOIN); + + stroker->current_point = *b; + stroker->open_sub_path = TRUE; + + return status; +} + +static cairo_status_t +_cairo_rectilinear_stroker_line_to_dashed (void *closure, + const cairo_point_t *point) +{ + cairo_rectilinear_stroker_t *stroker = closure; + const cairo_point_t *a = &stroker->current_point; + const cairo_point_t *b = point; + cairo_bool_t fully_in_bounds; + double sf, sign, remain; + cairo_fixed_t mag; + cairo_status_t status; + cairo_line_t segment; + cairo_bool_t dash_on = FALSE; + unsigned is_horizontal; + + /* We don't draw anything for degenerate paths. */ + if (a->x == b->x && a->y == b->y) + return CAIRO_STATUS_SUCCESS; + + /* We only support horizontal or vertical elements. */ + assert (a->x == b->x || a->y == b->y); + + fully_in_bounds = TRUE; + if (stroker->has_bounds && + (! _cairo_box_contains_point (&stroker->bounds, a) || + ! _cairo_box_contains_point (&stroker->bounds, b))) + { + fully_in_bounds = FALSE; + } + + is_horizontal = a->y == b->y; + if (is_horizontal) { + mag = b->x - a->x; + sf = fabs (stroker->ctm->xx); + } else { + mag = b->y - a->y; + sf = fabs (stroker->ctm->yy); + } + if (mag < 0) { + remain = _cairo_fixed_to_double (-mag); + sign = 1.; + } else { + remain = _cairo_fixed_to_double (mag); + is_horizontal |= FORWARDS; + sign = -1.; + } + + segment.p2 = segment.p1 = *a; + while (remain > 0.) { + double step_length; + + step_length = MIN (sf * stroker->dash.dash_remain, remain); + remain -= step_length; + + mag = _cairo_fixed_from_double (sign*remain); + if (is_horizontal & 0x1) + segment.p2.x = b->x + mag; + else + segment.p2.y = b->y + mag; + + if (stroker->dash.dash_on && + (fully_in_bounds || + _cairo_box_intersects_line_segment (&stroker->bounds, &segment))) + { + status = _cairo_rectilinear_stroker_add_segment (stroker, + &segment.p1, + &segment.p2, + is_horizontal | (remain <= 0.) << 2); + if (unlikely (status)) + return status; + + dash_on = TRUE; + } + else + { + dash_on = FALSE; + } + + _cairo_stroker_dash_step (&stroker->dash, step_length / sf); + segment.p1 = segment.p2; + } + + if (stroker->dash.dash_on && ! dash_on && + (fully_in_bounds || + _cairo_box_intersects_line_segment (&stroker->bounds, &segment))) + { + + /* This segment ends on a transition to dash_on, compute a new face + * and add cap for the beginning of the next dash_on step. + */ + + status = _cairo_rectilinear_stroker_add_segment (stroker, + &segment.p1, + &segment.p1, + is_horizontal | JOIN); + if (unlikely (status)) + return status; + } + + stroker->current_point = *point; + stroker->open_sub_path = TRUE; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_rectilinear_stroker_close_path (void *closure) +{ + cairo_rectilinear_stroker_t *stroker = closure; + cairo_status_t status; + + /* We don't draw anything for degenerate paths. */ + if (! stroker->open_sub_path) + return CAIRO_STATUS_SUCCESS; + + if (stroker->dash.dashed) { + status = _cairo_rectilinear_stroker_line_to_dashed (stroker, + &stroker->first_point); + } else { + status = _cairo_rectilinear_stroker_line_to (stroker, + &stroker->first_point); + } + if (unlikely (status)) + return status; + + stroker->open_sub_path = FALSE; + + if (stroker->dash.dashed) + status = _cairo_rectilinear_stroker_emit_segments_dashed (stroker); + else + status = _cairo_rectilinear_stroker_emit_segments (stroker); + if (unlikely (status)) + return status; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_int_status_t +_cairo_path_fixed_stroke_rectilinear_to_boxes (const cairo_path_fixed_t *path, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + cairo_antialias_t antialias, + cairo_boxes_t *boxes) +{ + cairo_rectilinear_stroker_t rectilinear_stroker; + cairo_int_status_t status; + cairo_box_t box; + + assert (_cairo_path_fixed_stroke_is_rectilinear (path)); + + if (! _cairo_rectilinear_stroker_init (&rectilinear_stroker, + stroke_style, ctm, antialias, + boxes)) + { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + if (! rectilinear_stroker.dash.dashed && + _cairo_path_fixed_is_stroke_box (path, &box) && + /* if the segments overlap we need to feed them into the tessellator */ + box.p2.x - box.p1.x > 2* rectilinear_stroker.half_line_x && + box.p2.y - box.p1.y > 2* rectilinear_stroker.half_line_y) + { + cairo_box_t b; + + /* top */ + b.p1.x = box.p1.x - rectilinear_stroker.half_line_x; + b.p2.x = box.p2.x + rectilinear_stroker.half_line_x; + b.p1.y = box.p1.y - rectilinear_stroker.half_line_y; + b.p2.y = box.p1.y + rectilinear_stroker.half_line_y; + status = _cairo_boxes_add (boxes, antialias, &b); + assert (status == CAIRO_INT_STATUS_SUCCESS); + + /* left (excluding top/bottom) */ + b.p1.x = box.p1.x - rectilinear_stroker.half_line_x; + b.p2.x = box.p1.x + rectilinear_stroker.half_line_x; + b.p1.y = box.p1.y + rectilinear_stroker.half_line_y; + b.p2.y = box.p2.y - rectilinear_stroker.half_line_y; + status = _cairo_boxes_add (boxes, antialias, &b); + assert (status == CAIRO_INT_STATUS_SUCCESS); + + /* right (excluding top/bottom) */ + b.p1.x = box.p2.x - rectilinear_stroker.half_line_x; + b.p2.x = box.p2.x + rectilinear_stroker.half_line_x; + b.p1.y = box.p1.y + rectilinear_stroker.half_line_y; + b.p2.y = box.p2.y - rectilinear_stroker.half_line_y; + status = _cairo_boxes_add (boxes, antialias, &b); + assert (status == CAIRO_INT_STATUS_SUCCESS); + + /* bottom */ + b.p1.x = box.p1.x - rectilinear_stroker.half_line_x; + b.p2.x = box.p2.x + rectilinear_stroker.half_line_x; + b.p1.y = box.p2.y - rectilinear_stroker.half_line_y; + b.p2.y = box.p2.y + rectilinear_stroker.half_line_y; + status = _cairo_boxes_add (boxes, antialias, &b); + assert (status == CAIRO_INT_STATUS_SUCCESS); + + goto done; + } + + if (boxes->num_limits) { + _cairo_rectilinear_stroker_limit (&rectilinear_stroker, + boxes->limits, + boxes->num_limits); + } + + status = _cairo_path_fixed_interpret (path, + _cairo_rectilinear_stroker_move_to, + rectilinear_stroker.dash.dashed ? + _cairo_rectilinear_stroker_line_to_dashed : + _cairo_rectilinear_stroker_line_to, + NULL, + _cairo_rectilinear_stroker_close_path, + &rectilinear_stroker); + if (unlikely (status)) + goto BAIL; + + if (rectilinear_stroker.dash.dashed) + status = _cairo_rectilinear_stroker_emit_segments_dashed (&rectilinear_stroker); + else + status = _cairo_rectilinear_stroker_emit_segments (&rectilinear_stroker); + if (unlikely (status)) + goto BAIL; + + /* As we incrementally tessellate, we do not eliminate self-intersections */ + status = _cairo_bentley_ottmann_tessellate_boxes (boxes, + CAIRO_FILL_RULE_WINDING, + boxes); + if (unlikely (status)) + goto BAIL; + +done: + _cairo_rectilinear_stroker_fini (&rectilinear_stroker); + return CAIRO_STATUS_SUCCESS; + +BAIL: + _cairo_rectilinear_stroker_fini (&rectilinear_stroker); + _cairo_boxes_clear (boxes); + return status; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-path-stroke-polygon.c b/local/recipes/libs/cairo/source/src/cairo-path-stroke-polygon.c new file mode 100644 index 0000000000..510ad3a6ae --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-path-stroke-polygon.c @@ -0,0 +1,1412 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Chris Wilson + */ + +#define _DEFAULT_SOURCE /* for hypot() */ +#include "cairoint.h" + +#include "cairo-box-inline.h" +#include "cairo-boxes-private.h" +#include "cairo-contour-inline.h" +#include "cairo-contour-private.h" +#include "cairo-error-private.h" +#include "cairo-path-fixed-private.h" +#include "cairo-slope-private.h" + +#define DEBUG 0 + +struct stroker { + cairo_stroke_style_t style; + +#if DEBUG + cairo_contour_t path; +#endif + + struct stroke_contour { + /* Note that these are not strictly contours as they may intersect */ + cairo_contour_t contour; + } cw, ccw; + cairo_uint64_t contour_tolerance; + cairo_polygon_t *polygon; + + const cairo_matrix_t *ctm; + const cairo_matrix_t *ctm_inverse; + double tolerance; + double spline_cusp_tolerance; + double half_line_width; + cairo_bool_t ctm_det_positive; + + cairo_pen_t pen; + + cairo_point_t first_point; + + cairo_bool_t has_initial_sub_path; + + cairo_bool_t has_current_face; + cairo_stroke_face_t current_face; + + cairo_bool_t has_first_face; + cairo_stroke_face_t first_face; + + cairo_bool_t has_bounds; + cairo_box_t bounds; +}; + +static inline double +normalize_slope (double *dx, double *dy); + +static void +compute_face (const cairo_point_t *point, + const cairo_slope_t *dev_slope, + struct stroker *stroker, + cairo_stroke_face_t *face); + +static cairo_uint64_t +point_distance_sq (const cairo_point_t *p1, + const cairo_point_t *p2) +{ + int32_t dx = p1->x - p2->x; + int32_t dy = p1->y - p2->y; + return _cairo_int32x32_64_mul (dx, dx) + _cairo_int32x32_64_mul (dy, dy); +} + +static cairo_bool_t +within_tolerance (const cairo_point_t *p1, + const cairo_point_t *p2, + cairo_uint64_t tolerance) +{ + return FALSE; + return _cairo_int64_lt (point_distance_sq (p1, p2), tolerance); +} + +static void +contour_add_point (struct stroker *stroker, + struct stroke_contour *c, + const cairo_point_t *point) +{ + if (! within_tolerance (point, _cairo_contour_last_point (&c->contour), + stroker->contour_tolerance)) + _cairo_contour_add_point (&c->contour, point); + //*_cairo_contour_last_point (&c->contour) = *point; +} + +static void +translate_point (cairo_point_t *point, const cairo_point_t *offset) +{ + point->x += offset->x; + point->y += offset->y; +} + +static int +slope_compare_sgn (double dx1, double dy1, double dx2, double dy2) +{ + double c = (dx1 * dy2 - dx2 * dy1); + + if (c > 0) return 1; + if (c < 0) return -1; + return 0; +} + +/* + * Construct a fan around the midpoint using the vertices from pen between + * inpt and outpt. + */ +static void +add_fan (struct stroker *stroker, + const cairo_slope_t *in_vector, + const cairo_slope_t *out_vector, + const cairo_point_t *midpt, + cairo_bool_t clockwise, + struct stroke_contour *c) +{ + cairo_pen_t *pen = &stroker->pen; + int start, stop; + + if (stroker->has_bounds && + ! _cairo_box_contains_point (&stroker->bounds, midpt)) + return; + + assert (stroker->pen.num_vertices); + + if (clockwise) { + _cairo_pen_find_active_cw_vertices (pen, + in_vector, out_vector, + &start, &stop); + while (start != stop) { + cairo_point_t p = *midpt; + translate_point (&p, &pen->vertices[start].point); + contour_add_point (stroker, c, &p); + + if (++start == pen->num_vertices) + start = 0; + } + } else { + _cairo_pen_find_active_ccw_vertices (pen, + in_vector, out_vector, + &start, &stop); + while (start != stop) { + cairo_point_t p = *midpt; + translate_point (&p, &pen->vertices[start].point); + contour_add_point (stroker, c, &p); + + if (start-- == 0) + start += pen->num_vertices; + } + } +} + +static int +join_is_clockwise (const cairo_stroke_face_t *in, + const cairo_stroke_face_t *out) +{ + return _cairo_slope_compare (&in->dev_vector, &out->dev_vector) < 0; +} + +static void +inner_join (struct stroker *stroker, + const cairo_stroke_face_t *in, + const cairo_stroke_face_t *out, + int clockwise) +{ +#if 0 + cairo_point_t last; + const cairo_point_t *p, *outpt; + struct stroke_contour *inner; + cairo_int64_t d_p, d_last; + cairo_int64_t half_line_width; + cairo_bool_t negate; + + /* XXX line segments shorter than line-width */ + + if (clockwise) { + inner = &stroker->ccw; + outpt = &out->ccw; + negate = 1; + } else { + inner = &stroker->cw; + outpt = &out->cw; + negate = 0; + } + + half_line_width = CAIRO_FIXED_ONE*CAIRO_FIXED_ONE/2 * stroker->style.line_width * out->length + .5; + + /* On the inside, the previous end-point is always + * closer to the new face by definition. + */ + last = *_cairo_contour_last_point (&inner->contour); + d_last = distance_from_face (out, &last, negate); + _cairo_contour_remove_last_point (&inner->contour); + +prev: + if (inner->contour.chain.num_points == 0) { + contour_add_point (stroker, inner, outpt); + return; + } + p = _cairo_contour_last_point (&inner->contour); + d_p = distance_from_face (out, p, negate); + if (_cairo_int64_lt (d_p, half_line_width) && + !_cairo_int64_negative (distance_along_face (out, p))) + { + last = *p; + d_last = d_p; + _cairo_contour_remove_last_point (&inner->contour); + goto prev; + } + + compute_inner_joint (&last, d_last, p, d_p, half_line_width); + contour_add_point (stroker, inner, &last); +#else + const cairo_point_t *outpt; + struct stroke_contour *inner; + + if (clockwise) { + inner = &stroker->ccw; + outpt = &out->ccw; + } else { + inner = &stroker->cw; + outpt = &out->cw; + } + contour_add_point (stroker, inner, &in->point); + contour_add_point (stroker, inner, outpt); +#endif +} + +static void +inner_close (struct stroker *stroker, + const cairo_stroke_face_t *in, + cairo_stroke_face_t *out) +{ +#if 0 + cairo_point_t last; + const cairo_point_t *p, *outpt, *inpt; + struct stroke_contour *inner; + struct _cairo_contour_chain *chain; + + /* XXX line segments shorter than line-width */ + + if (join_is_clockwise (in, out)) { + inner = &stroker->ccw; + outpt = &in->ccw; + inpt = &out->ccw; + } else { + inner = &stroker->cw; + outpt = &in->cw; + inpt = &out->cw; + } + + if (inner->contour.chain.num_points == 0) { + contour_add_point (stroker, inner, &in->point); + contour_add_point (stroker, inner, inpt); + *_cairo_contour_first_point (&inner->contour) = + *_cairo_contour_last_point (&inner->contour); + return; + } + + line_width = stroker->style.line_width/2; + line_width *= CAIRO_FIXED_ONE; + + d_last = sign * distance_from_face (out, outpt); + last = *outpt; + + for (chain = &inner->contour.chain; chain; chain = chain->next) { + for (i = 0; i < chain->num_points; i++) { + p = &chain->points[i]; + if ((d_p = sign * distance_from_face (in, p)) >= line_width && + distance_from_edge (stroker, inpt, &last, p) < line_width) + { + goto out; + } + + if (p->x != last.x || p->y != last.y) { + last = *p; + d_last = d_p; + } + } + } +out: + + if (d_p != d_last) { + double dot = (line_width - d_last) / (d_p - d_last); + last.x += dot * (p->x - last.x); + last.y += dot * (p->y - last.y); + } + *_cairo_contour_last_point (&inner->contour) = last; + + for (chain = &inner->contour.chain; chain; chain = chain->next) { + for (i = 0; i < chain->num_points; i++) { + cairo_point_t *pp = &chain->points[i]; + if (pp == p) + return; + *pp = last; + } + } +#else + const cairo_point_t *inpt; + struct stroke_contour *inner; + + if (join_is_clockwise (in, out)) { + inner = &stroker->ccw; + inpt = &out->ccw; + } else { + inner = &stroker->cw; + inpt = &out->cw; + } + + contour_add_point (stroker, inner, &in->point); + contour_add_point (stroker, inner, inpt); + *_cairo_contour_first_point (&inner->contour) = + *_cairo_contour_last_point (&inner->contour); +#endif +} + +static void +outer_close (struct stroker *stroker, + const cairo_stroke_face_t *in, + const cairo_stroke_face_t *out) +{ + const cairo_point_t *inpt, *outpt; + struct stroke_contour *outer; + int clockwise; + + if (in->cw.x == out->cw.x && in->cw.y == out->cw.y && + in->ccw.x == out->ccw.x && in->ccw.y == out->ccw.y) + { + return; + } + + clockwise = join_is_clockwise (in, out); + if (clockwise) { + inpt = &in->cw; + outpt = &out->cw; + outer = &stroker->cw; + } else { + inpt = &in->ccw; + outpt = &out->ccw; + outer = &stroker->ccw; + } + + if (within_tolerance (inpt, outpt, stroker->contour_tolerance)) { + *_cairo_contour_first_point (&outer->contour) = + *_cairo_contour_last_point (&outer->contour); + return; + } + + switch (stroker->style.line_join) { + case CAIRO_LINE_JOIN_ROUND: + if ((in->dev_slope.x * out->dev_slope.x + + in->dev_slope.y * out->dev_slope.y) < stroker->spline_cusp_tolerance) + { + /* construct a fan around the common midpoint */ + add_fan (stroker, + &in->dev_vector, &out->dev_vector, &in->point, + clockwise, outer); + } /* else: bevel join */ + break; + + case CAIRO_LINE_JOIN_MITER: + default: { + /* dot product of incoming slope vector with outgoing slope vector */ + double in_dot_out = in->dev_slope.x * out->dev_slope.x + + in->dev_slope.y * out->dev_slope.y; + double ml = stroker->style.miter_limit; + + /* Check the miter limit -- lines meeting at an acute angle + * can generate long miters, the limit converts them to bevel + * + * Consider the miter join formed when two line segments + * meet at an angle psi: + * + * /.\ + * /. .\ + * /./ \.\ + * /./psi\.\ + * + * We can zoom in on the right half of that to see: + * + * |\ + * | \ psi/2 + * | \ + * | \ + * | \ + * | \ + * miter \ + * length \ + * | \ + * | .\ + * | . \ + * |. line \ + * \ width \ + * \ \ + * + * + * The right triangle in that figure, (the line-width side is + * shown faintly with three '.' characters), gives us the + * following expression relating miter length, angle and line + * width: + * + * 1 /sin (psi/2) = miter_length / line_width + * + * The right-hand side of this relationship is the same ratio + * in which the miter limit (ml) is expressed. We want to know + * when the miter length is within the miter limit. That is + * when the following condition holds: + * + * 1/sin(psi/2) <= ml + * 1 <= ml sin(psi/2) + * 1 <= ml² sin²(psi/2) + * 2 <= ml² 2 sin²(psi/2) + * 2·sin²(psi/2) = 1-cos(psi) + * 2 <= ml² (1-cos(psi)) + * + * in · out = |in| |out| cos (psi) + * + * in and out are both unit vectors, so: + * + * in · out = cos (psi) + * + * 2 <= ml² (1 - in · out) + * + */ + if (2 <= ml * ml * (1 + in_dot_out)) { + double x1, y1, x2, y2; + double mx, my; + double dx1, dx2, dy1, dy2; + double ix, iy; + double fdx1, fdy1, fdx2, fdy2; + double mdx, mdy; + + /* + * we've got the points already transformed to device + * space, but need to do some computation with them and + * also need to transform the slope from user space to + * device space + */ + /* outer point of incoming line face */ + x1 = _cairo_fixed_to_double (inpt->x); + y1 = _cairo_fixed_to_double (inpt->y); + dx1 = in->dev_slope.x; + dy1 = in->dev_slope.y; + + /* outer point of outgoing line face */ + x2 = _cairo_fixed_to_double (outpt->x); + y2 = _cairo_fixed_to_double (outpt->y); + dx2 = out->dev_slope.x; + dy2 = out->dev_slope.y; + + /* + * Compute the location of the outer corner of the miter. + * That's pretty easy -- just the intersection of the two + * outer edges. We've got slopes and points on each + * of those edges. Compute my directly, then compute + * mx by using the edge with the larger dy; that avoids + * dividing by values close to zero. + */ + my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) / + (dx1 * dy2 - dx2 * dy1)); + if (fabs (dy1) >= fabs (dy2)) + mx = (my - y1) * dx1 / dy1 + x1; + else + mx = (my - y2) * dx2 / dy2 + x2; + + /* + * When the two outer edges are nearly parallel, slight + * perturbations in the position of the outer points of the lines + * caused by representing them in fixed point form can cause the + * intersection point of the miter to move a large amount. If + * that moves the miter intersection from between the two faces, + * then draw a bevel instead. + */ + + ix = _cairo_fixed_to_double (in->point.x); + iy = _cairo_fixed_to_double (in->point.y); + + /* slope of one face */ + fdx1 = x1 - ix; fdy1 = y1 - iy; + + /* slope of the other face */ + fdx2 = x2 - ix; fdy2 = y2 - iy; + + /* slope from the intersection to the miter point */ + mdx = mx - ix; mdy = my - iy; + + /* + * Make sure the miter point line lies between the two + * faces by comparing the slopes + */ + if (slope_compare_sgn (fdx1, fdy1, mdx, mdy) != + slope_compare_sgn (fdx2, fdy2, mdx, mdy)) + { + cairo_point_t p; + + p.x = _cairo_fixed_from_double (mx); + p.y = _cairo_fixed_from_double (my); + + *_cairo_contour_last_point (&outer->contour) = p; + *_cairo_contour_first_point (&outer->contour) = p; + return; + } + } + break; + } + + case CAIRO_LINE_JOIN_BEVEL: + break; + } + contour_add_point (stroker, outer, outpt); +} + +static void +outer_join (struct stroker *stroker, + const cairo_stroke_face_t *in, + const cairo_stroke_face_t *out, + int clockwise) +{ + const cairo_point_t *inpt, *outpt; + struct stroke_contour *outer; + + if (in->cw.x == out->cw.x && in->cw.y == out->cw.y && + in->ccw.x == out->ccw.x && in->ccw.y == out->ccw.y) + { + return; + } + if (clockwise) { + inpt = &in->cw; + outpt = &out->cw; + outer = &stroker->cw; + } else { + inpt = &in->ccw; + outpt = &out->ccw; + outer = &stroker->ccw; + } + + switch (stroker->style.line_join) { + case CAIRO_LINE_JOIN_ROUND: + if ((in->dev_slope.x * out->dev_slope.x + + in->dev_slope.y * out->dev_slope.y) < stroker->spline_cusp_tolerance) + { + /* construct a fan around the common midpoint */ + add_fan (stroker, + &in->dev_vector, &out->dev_vector, &in->point, + clockwise, outer); + } /* else: bevel join */ + break; + + case CAIRO_LINE_JOIN_MITER: + default: { + /* dot product of incoming slope vector with outgoing slope vector */ + double in_dot_out = in->dev_slope.x * out->dev_slope.x + + in->dev_slope.y * out->dev_slope.y; + double ml = stroker->style.miter_limit; + + /* Check the miter limit -- lines meeting at an acute angle + * can generate long miters, the limit converts them to bevel + * + * Consider the miter join formed when two line segments + * meet at an angle psi: + * + * /.\ + * /. .\ + * /./ \.\ + * /./psi\.\ + * + * We can zoom in on the right half of that to see: + * + * |\ + * | \ psi/2 + * | \ + * | \ + * | \ + * | \ + * miter \ + * length \ + * | \ + * | .\ + * | . \ + * |. line \ + * \ width \ + * \ \ + * + * + * The right triangle in that figure, (the line-width side is + * shown faintly with three '.' characters), gives us the + * following expression relating miter length, angle and line + * width: + * + * 1 /sin (psi/2) = miter_length / line_width + * + * The right-hand side of this relationship is the same ratio + * in which the miter limit (ml) is expressed. We want to know + * when the miter length is within the miter limit. That is + * when the following condition holds: + * + * 1/sin(psi/2) <= ml + * 1 <= ml sin(psi/2) + * 1 <= ml² sin²(psi/2) + * 2 <= ml² 2 sin²(psi/2) + * 2·sin²(psi/2) = 1-cos(psi) + * 2 <= ml² (1-cos(psi)) + * + * in · out = |in| |out| cos (psi) + * + * in and out are both unit vectors, so: + * + * in · out = cos (psi) + * + * 2 <= ml² (1 - in · out) + * + */ + if (2 <= ml * ml * (1 + in_dot_out)) { + double x1, y1, x2, y2; + double mx, my; + double dx1, dx2, dy1, dy2; + double ix, iy; + double fdx1, fdy1, fdx2, fdy2; + double mdx, mdy; + + /* + * we've got the points already transformed to device + * space, but need to do some computation with them and + * also need to transform the slope from user space to + * device space + */ + /* outer point of incoming line face */ + x1 = _cairo_fixed_to_double (inpt->x); + y1 = _cairo_fixed_to_double (inpt->y); + dx1 = in->dev_slope.x; + dy1 = in->dev_slope.y; + + /* outer point of outgoing line face */ + x2 = _cairo_fixed_to_double (outpt->x); + y2 = _cairo_fixed_to_double (outpt->y); + dx2 = out->dev_slope.x; + dy2 = out->dev_slope.y; + + /* + * Compute the location of the outer corner of the miter. + * That's pretty easy -- just the intersection of the two + * outer edges. We've got slopes and points on each + * of those edges. Compute my directly, then compute + * mx by using the edge with the larger dy; that avoids + * dividing by values close to zero. + */ + my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) / + (dx1 * dy2 - dx2 * dy1)); + if (fabs (dy1) >= fabs (dy2)) + mx = (my - y1) * dx1 / dy1 + x1; + else + mx = (my - y2) * dx2 / dy2 + x2; + + /* + * When the two outer edges are nearly parallel, slight + * perturbations in the position of the outer points of the lines + * caused by representing them in fixed point form can cause the + * intersection point of the miter to move a large amount. If + * that moves the miter intersection from between the two faces, + * then draw a bevel instead. + */ + + ix = _cairo_fixed_to_double (in->point.x); + iy = _cairo_fixed_to_double (in->point.y); + + /* slope of one face */ + fdx1 = x1 - ix; fdy1 = y1 - iy; + + /* slope of the other face */ + fdx2 = x2 - ix; fdy2 = y2 - iy; + + /* slope from the intersection to the miter point */ + mdx = mx - ix; mdy = my - iy; + + /* + * Make sure the miter point line lies between the two + * faces by comparing the slopes + */ + if (slope_compare_sgn (fdx1, fdy1, mdx, mdy) != + slope_compare_sgn (fdx2, fdy2, mdx, mdy)) + { + cairo_point_t p; + + p.x = _cairo_fixed_from_double (mx); + p.y = _cairo_fixed_from_double (my); + + *_cairo_contour_last_point (&outer->contour) = p; + return; + } + } + break; + } + + case CAIRO_LINE_JOIN_BEVEL: + break; + } + contour_add_point (stroker,outer, outpt); +} + +static void +add_cap (struct stroker *stroker, + const cairo_stroke_face_t *f, + struct stroke_contour *c) +{ + switch (stroker->style.line_cap) { + case CAIRO_LINE_CAP_ROUND: { + cairo_slope_t slope; + + slope.dx = -f->dev_vector.dx; + slope.dy = -f->dev_vector.dy; + + add_fan (stroker, &f->dev_vector, &slope, &f->point, FALSE, c); + break; + } + + case CAIRO_LINE_CAP_SQUARE: { + cairo_slope_t fvector; + cairo_point_t p; + double dx, dy; + + dx = f->usr_vector.x; + dy = f->usr_vector.y; + dx *= stroker->half_line_width; + dy *= stroker->half_line_width; + cairo_matrix_transform_distance (stroker->ctm, &dx, &dy); + fvector.dx = _cairo_fixed_from_double (dx); + fvector.dy = _cairo_fixed_from_double (dy); + + p.x = f->ccw.x + fvector.dx; + p.y = f->ccw.y + fvector.dy; + contour_add_point (stroker, c, &p); + + p.x = f->cw.x + fvector.dx; + p.y = f->cw.y + fvector.dy; + contour_add_point (stroker, c, &p); + } + + case CAIRO_LINE_CAP_BUTT: + default: + break; + } + contour_add_point (stroker, c, &f->cw); +} + +static void +add_leading_cap (struct stroker *stroker, + const cairo_stroke_face_t *face, + struct stroke_contour *c) +{ + cairo_stroke_face_t reversed; + cairo_point_t t; + + reversed = *face; + + /* The initial cap needs an outward facing vector. Reverse everything */ + reversed.usr_vector.x = -reversed.usr_vector.x; + reversed.usr_vector.y = -reversed.usr_vector.y; + reversed.dev_vector.dx = -reversed.dev_vector.dx; + reversed.dev_vector.dy = -reversed.dev_vector.dy; + + t = reversed.cw; + reversed.cw = reversed.ccw; + reversed.ccw = t; + + add_cap (stroker, &reversed, c); +} + +static void +add_trailing_cap (struct stroker *stroker, + const cairo_stroke_face_t *face, + struct stroke_contour *c) +{ + add_cap (stroker, face, c); +} + +static inline double +normalize_slope (double *dx, double *dy) +{ + double dx0 = *dx, dy0 = *dy; + double mag; + + assert (dx0 != 0.0 || dy0 != 0.0); + + if (dx0 == 0.0) { + *dx = 0.0; + if (dy0 > 0.0) { + mag = dy0; + *dy = 1.0; + } else { + mag = -dy0; + *dy = -1.0; + } + } else if (dy0 == 0.0) { + *dy = 0.0; + if (dx0 > 0.0) { + mag = dx0; + *dx = 1.0; + } else { + mag = -dx0; + *dx = -1.0; + } + } else { + mag = hypot (dx0, dy0); + *dx = dx0 / mag; + *dy = dy0 / mag; + } + + return mag; +} + +static void +compute_face (const cairo_point_t *point, + const cairo_slope_t *dev_slope, + struct stroker *stroker, + cairo_stroke_face_t *face) +{ + double face_dx, face_dy; + cairo_point_t offset_ccw, offset_cw; + double slope_dx, slope_dy; + + slope_dx = _cairo_fixed_to_double (dev_slope->dx); + slope_dy = _cairo_fixed_to_double (dev_slope->dy); + face->length = normalize_slope (&slope_dx, &slope_dy); + face->dev_slope.x = slope_dx; + face->dev_slope.y = slope_dy; + + /* + * rotate to get a line_width/2 vector along the face, note that + * the vector must be rotated the right direction in device space, + * but by 90° in user space. So, the rotation depends on + * whether the ctm reflects or not, and that can be determined + * by looking at the determinant of the matrix. + */ + if (! _cairo_matrix_is_identity (stroker->ctm_inverse)) { + /* Normalize the matrix! */ + cairo_matrix_transform_distance (stroker->ctm_inverse, + &slope_dx, &slope_dy); + normalize_slope (&slope_dx, &slope_dy); + + if (stroker->ctm_det_positive) { + face_dx = - slope_dy * stroker->half_line_width; + face_dy = slope_dx * stroker->half_line_width; + } else { + face_dx = slope_dy * stroker->half_line_width; + face_dy = - slope_dx * stroker->half_line_width; + } + + /* back to device space */ + cairo_matrix_transform_distance (stroker->ctm, &face_dx, &face_dy); + } else { + face_dx = - slope_dy * stroker->half_line_width; + face_dy = slope_dx * stroker->half_line_width; + } + + offset_ccw.x = _cairo_fixed_from_double (face_dx); + offset_ccw.y = _cairo_fixed_from_double (face_dy); + offset_cw.x = -offset_ccw.x; + offset_cw.y = -offset_ccw.y; + + face->ccw = *point; + translate_point (&face->ccw, &offset_ccw); + + face->point = *point; + + face->cw = *point; + translate_point (&face->cw, &offset_cw); + + face->usr_vector.x = slope_dx; + face->usr_vector.y = slope_dy; + + face->dev_vector = *dev_slope; +} + +static void +add_caps (struct stroker *stroker) +{ + /* check for a degenerative sub_path */ + if (stroker->has_initial_sub_path && + ! stroker->has_first_face && + ! stroker->has_current_face && + stroker->style.line_cap == CAIRO_LINE_CAP_ROUND) + { + /* pick an arbitrary slope to use */ + cairo_slope_t slope = { CAIRO_FIXED_ONE, 0 }; + cairo_stroke_face_t face; + + /* arbitrarily choose first_point */ + compute_face (&stroker->first_point, &slope, stroker, &face); + + add_leading_cap (stroker, &face, &stroker->ccw); + add_trailing_cap (stroker, &face, &stroker->ccw); + + /* ensure the circle is complete */ + _cairo_contour_add_point (&stroker->ccw.contour, + _cairo_contour_first_point (&stroker->ccw.contour)); + + _cairo_polygon_add_contour (stroker->polygon, &stroker->ccw.contour); + _cairo_contour_reset (&stroker->ccw.contour); + } else { + if (stroker->has_current_face) + add_trailing_cap (stroker, &stroker->current_face, &stroker->ccw); + +#if DEBUG + { + FILE *file = fopen ("contours.txt", "a"); + _cairo_debug_print_contour (file, &stroker->path); + _cairo_debug_print_contour (file, &stroker->cw.contour); + _cairo_debug_print_contour (file, &stroker->ccw.contour); + fclose (file); + _cairo_contour_reset (&stroker->path); + } +#endif + + _cairo_polygon_add_contour (stroker->polygon, &stroker->ccw.contour); + _cairo_contour_reset (&stroker->ccw.contour); + + if (stroker->has_first_face) { + _cairo_contour_add_point (&stroker->ccw.contour, + &stroker->first_face.cw); + add_leading_cap (stroker, &stroker->first_face, &stroker->ccw); +#if DEBUG + { + FILE *file = fopen ("contours.txt", "a"); + _cairo_debug_print_contour (file, &stroker->ccw.contour); + fclose (file); + } +#endif + + _cairo_polygon_add_contour (stroker->polygon, + &stroker->ccw.contour); + _cairo_contour_reset (&stroker->ccw.contour); + } + + _cairo_polygon_add_contour (stroker->polygon, &stroker->cw.contour); + _cairo_contour_reset (&stroker->cw.contour); + } +} + +static cairo_status_t +close_path (void *closure); + +static cairo_status_t +move_to (void *closure, + const cairo_point_t *point) +{ + struct stroker *stroker = closure; + + /* Cap the start and end of the previous sub path as needed */ + add_caps (stroker); + + stroker->has_first_face = FALSE; + stroker->has_current_face = FALSE; + stroker->has_initial_sub_path = FALSE; + + stroker->first_point = *point; + +#if DEBUG + _cairo_contour_add_point (&stroker->path, point); +#endif + + stroker->current_face.point = *point; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +line_to (void *closure, + const cairo_point_t *point) +{ + struct stroker *stroker = closure; + cairo_stroke_face_t start; + cairo_point_t *p1 = &stroker->current_face.point; + cairo_slope_t dev_slope; + + stroker->has_initial_sub_path = TRUE; + + if (p1->x == point->x && p1->y == point->y) + return CAIRO_STATUS_SUCCESS; + +#if DEBUG + _cairo_contour_add_point (&stroker->path, point); +#endif + + _cairo_slope_init (&dev_slope, p1, point); + compute_face (p1, &dev_slope, stroker, &start); + + if (stroker->has_current_face) { + int clockwise = _cairo_slope_compare (&stroker->current_face.dev_vector, + &start.dev_vector); + if (clockwise) { + clockwise = clockwise < 0; + /* Join with final face from previous segment */ + if (! within_tolerance (&stroker->current_face.ccw, &start.ccw, + stroker->contour_tolerance) || + ! within_tolerance (&stroker->current_face.cw, &start.cw, + stroker->contour_tolerance)) + { + outer_join (stroker, &stroker->current_face, &start, clockwise); + inner_join (stroker, &stroker->current_face, &start, clockwise); + } + } + } else { + if (! stroker->has_first_face) { + /* Save sub path's first face in case needed for closing join */ + stroker->first_face = start; + stroker->has_first_face = TRUE; + } + stroker->has_current_face = TRUE; + + contour_add_point (stroker, &stroker->cw, &start.cw); + contour_add_point (stroker, &stroker->ccw, &start.ccw); + } + + stroker->current_face = start; + stroker->current_face.point = *point; + stroker->current_face.ccw.x += dev_slope.dx; + stroker->current_face.ccw.y += dev_slope.dy; + stroker->current_face.cw.x += dev_slope.dx; + stroker->current_face.cw.y += dev_slope.dy; + + contour_add_point (stroker, &stroker->cw, &stroker->current_face.cw); + contour_add_point (stroker, &stroker->ccw, &stroker->current_face.ccw); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +spline_to (void *closure, + const cairo_point_t *point, + const cairo_slope_t *tangent) +{ + struct stroker *stroker = closure; + cairo_stroke_face_t face; + +#if DEBUG + _cairo_contour_add_point (&stroker->path, point); +#endif + if ((tangent->dx | tangent->dy) == 0) { + struct stroke_contour *outer; + cairo_point_t t; + int clockwise; + + face = stroker->current_face; + + face.usr_vector.x = -face.usr_vector.x; + face.usr_vector.y = -face.usr_vector.y; + face.dev_vector.dx = -face.dev_vector.dx; + face.dev_vector.dy = -face.dev_vector.dy; + + t = face.cw; + face.cw = face.ccw; + face.ccw = t; + + clockwise = join_is_clockwise (&stroker->current_face, &face); + if (clockwise) { + outer = &stroker->cw; + } else { + outer = &stroker->ccw; + } + + add_fan (stroker, + &stroker->current_face.dev_vector, + &face.dev_vector, + &stroker->current_face.point, + clockwise, outer); + } else { + compute_face (point, tangent, stroker, &face); + + if ((face.dev_slope.x * stroker->current_face.dev_slope.x + + face.dev_slope.y * stroker->current_face.dev_slope.y) < stroker->spline_cusp_tolerance) + { + struct stroke_contour *outer; + int clockwise = join_is_clockwise (&stroker->current_face, &face); + + stroker->current_face.cw.x += face.point.x - stroker->current_face.point.x; + stroker->current_face.cw.y += face.point.y - stroker->current_face.point.y; + contour_add_point (stroker, &stroker->cw, &stroker->current_face.cw); + + stroker->current_face.ccw.x += face.point.x - stroker->current_face.point.x; + stroker->current_face.ccw.y += face.point.y - stroker->current_face.point.y; + contour_add_point (stroker, &stroker->ccw, &stroker->current_face.ccw); + + if (clockwise) { + outer = &stroker->cw; + } else { + outer = &stroker->ccw; + } + add_fan (stroker, + &stroker->current_face.dev_vector, + &face.dev_vector, + &stroker->current_face.point, + clockwise, outer); + } + + contour_add_point (stroker, &stroker->cw, &face.cw); + contour_add_point (stroker, &stroker->ccw, &face.ccw); + } + + stroker->current_face = face; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +curve_to (void *closure, + const cairo_point_t *b, + const cairo_point_t *c, + const cairo_point_t *d) +{ + struct stroker *stroker = closure; + cairo_spline_t spline; + cairo_stroke_face_t face; + + if (stroker->has_bounds && + ! _cairo_spline_intersects (&stroker->current_face.point, b, c, d, + &stroker->bounds)) + return line_to (closure, d); + + if (! _cairo_spline_init (&spline, spline_to, stroker, + &stroker->current_face.point, b, c, d)) + return line_to (closure, d); + + compute_face (&stroker->current_face.point, &spline.initial_slope, + stroker, &face); + + if (stroker->has_current_face) { + int clockwise = join_is_clockwise (&stroker->current_face, &face); + /* Join with final face from previous segment */ + outer_join (stroker, &stroker->current_face, &face, clockwise); + inner_join (stroker, &stroker->current_face, &face, clockwise); + } else { + if (! stroker->has_first_face) { + /* Save sub path's first face in case needed for closing join */ + stroker->first_face = face; + stroker->has_first_face = TRUE; + } + stroker->has_current_face = TRUE; + + contour_add_point (stroker, &stroker->cw, &face.cw); + contour_add_point (stroker, &stroker->ccw, &face.ccw); + } + stroker->current_face = face; + + return _cairo_spline_decompose (&spline, stroker->tolerance); +} + +static cairo_status_t +close_path (void *closure) +{ + struct stroker *stroker = closure; + cairo_status_t status; + + status = line_to (stroker, &stroker->first_point); + if (unlikely (status)) + return status; + + if (stroker->has_first_face && stroker->has_current_face) { + /* Join first and final faces of sub path */ + outer_close (stroker, &stroker->current_face, &stroker->first_face); + inner_close (stroker, &stroker->current_face, &stroker->first_face); +#if 0 + *_cairo_contour_first_point (&stroker->ccw.contour) = + *_cairo_contour_last_point (&stroker->ccw.contour); + + *_cairo_contour_first_point (&stroker->cw.contour) = + *_cairo_contour_last_point (&stroker->cw.contour); +#endif + + _cairo_polygon_add_contour (stroker->polygon, &stroker->cw.contour); + _cairo_polygon_add_contour (stroker->polygon, &stroker->ccw.contour); + +#if DEBUG + { + FILE *file = fopen ("contours.txt", "a"); + _cairo_debug_print_contour (file, &stroker->path); + _cairo_debug_print_contour (file, &stroker->cw.contour); + _cairo_debug_print_contour (file, &stroker->ccw.contour); + fclose (file); + + _cairo_contour_reset (&stroker->path); + } +#endif + _cairo_contour_reset (&stroker->cw.contour); + _cairo_contour_reset (&stroker->ccw.contour); + } else { + /* Cap the start and end of the sub path as needed */ + add_caps (stroker); + } + + stroker->has_initial_sub_path = FALSE; + stroker->has_first_face = FALSE; + stroker->has_current_face = FALSE; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_path_fixed_stroke_to_polygon (const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_polygon_t *polygon) +{ + struct stroker stroker; + cairo_status_t status; + + if (style->num_dashes) { + return _cairo_path_fixed_stroke_dashed_to_polygon (path, + style, + ctm, + ctm_inverse, + tolerance, + polygon); + } + + stroker.has_bounds = polygon->num_limits; + if (stroker.has_bounds) { + /* Extend the bounds in each direction to account for the maximum area + * we might generate trapezoids, to capture line segments that are + * outside of the bounds but which might generate rendering that's + * within bounds. + */ + double dx, dy; + cairo_fixed_t fdx, fdy; + int i; + + stroker.bounds = polygon->limits[0]; + for (i = 1; i < polygon->num_limits; i++) + _cairo_box_add_box (&stroker.bounds, &polygon->limits[i]); + + _cairo_stroke_style_max_distance_from_path (style, path, ctm, &dx, &dy); + fdx = _cairo_fixed_from_double (dx); + fdy = _cairo_fixed_from_double (dy); + + stroker.bounds.p1.x -= fdx; + stroker.bounds.p2.x += fdx; + stroker.bounds.p1.y -= fdy; + stroker.bounds.p2.y += fdy; + } + + stroker.style = *style; + stroker.ctm = ctm; + stroker.ctm_inverse = ctm_inverse; + stroker.tolerance = tolerance; + stroker.half_line_width = style->line_width / 2.; + + /* If `CAIRO_LINE_JOIN_ROUND` is selected and a joint's `arc height` + * is greater than `tolerance` then two segments are joined with + * round-join, otherwise bevel-join is used. + * + * (See https://gitlab.freedesktop.org/cairo/cairo/-/merge_requests/372#note_1698225 + * for an illustration.) + * + * `Arc height` is the distance from the center of arc's chord to + * the center of the arc. It is also the difference of arc's radius + * and the "distance from a point where segments are joined to the + * chord" (distance to the chord). Arc's radius is the half of a line + * width and the "distance to the chord" is equal to "half of a line width" + * times `cos(half the angle between segment vectors)`. So + * + * arc_height = w/2 - w/2 * cos(phi/2), + * + * where `w/2` is the "half of a line width". + * + * Using the double angle cosine formula we can express the `cos(phi/2)` + * with just `cos(phi)` which is also the dot product of segments' + * unit vectors. + * + * cos(phi/2) = sqrt ( (1 + cos(phi)) / 2 ); + * cos(phi/2) is in [0; 1] range, cannot be negative; + * + * cos(phi) = a . b = (ax * bx + ay * by), + * + * where `a` and `b` are unit vectors of the segments to be joined. + * + * Since `arc height` should be greater than the `tolerance` to produce + * a round-join we can write + * + * w/2 * (1 - cos(phi/2)) > tolerance; + * 1 - tolerance / (w/2) > cos(phi/2); [!] + * + * which can be rewritten with the above double angle formula to + * + * cos(phi) < 2 * ( 1 - tolerance / (w/2) )^2 - 1, + * + * [!] Note that `w/2` is in [tolerance; +inf] range, since `cos(phi/2)` + * cannot be negative. The left part of the above inequality is the + * dot product and the right part is the `spline_cusp_tolerance`: + * + * (ax * bx + ay * by) < spline_cusp_tolerance. + * + * In the code below only the `spline_cusp_tolerance` is calculated. + * The dot product is calculated later, in the condition expression + * itself. "Half of a line width" must be scaled with CTM for tolerance + * condition to be properly met. Also, since `arch height` cannot exceed + * the "half of a line width" and since `cos(phi/2)` cannot be negative, + * when `tolerance` is greater than the "half of a line width" the + * bevel-join should be produced. + */ + double scaled_hlw = hypot(stroker.half_line_width * ctm->xx, + stroker.half_line_width * ctm->yx); + + if (scaled_hlw <= tolerance) { + stroker.spline_cusp_tolerance = -1.0; + } else { + stroker.spline_cusp_tolerance = 1 - tolerance / scaled_hlw; + stroker.spline_cusp_tolerance *= stroker.spline_cusp_tolerance; + stroker.spline_cusp_tolerance *= 2; + stroker.spline_cusp_tolerance -= 1; + } + + stroker.ctm_det_positive = + _cairo_matrix_compute_determinant (ctm) >= 0.0; + + stroker.pen.num_vertices = 0; + if (path->has_curve_to || + style->line_join == CAIRO_LINE_JOIN_ROUND || + style->line_cap == CAIRO_LINE_CAP_ROUND) { + status = _cairo_pen_init (&stroker.pen, + stroker.half_line_width, + tolerance, ctm); + if (unlikely (status)) + return status; + + /* If the line width is so small that the pen is reduced to a + single point, then we have nothing to do. */ + if (stroker.pen.num_vertices <= 1) + return CAIRO_STATUS_SUCCESS; + } + + stroker.has_current_face = FALSE; + stroker.has_first_face = FALSE; + stroker.has_initial_sub_path = FALSE; + +#if DEBUG + remove ("contours.txt"); + remove ("polygons.txt"); + _cairo_contour_init (&stroker.path, 0); +#endif + _cairo_contour_init (&stroker.cw.contour, 1); + _cairo_contour_init (&stroker.ccw.contour, -1); + tolerance *= CAIRO_FIXED_ONE; + tolerance *= tolerance; + stroker.contour_tolerance = tolerance; + stroker.polygon = polygon; + + status = _cairo_path_fixed_interpret (path, + move_to, + line_to, + curve_to, + close_path, + &stroker); + /* Cap the start and end of the final sub path as needed */ + if (likely (status == CAIRO_STATUS_SUCCESS)) + add_caps (&stroker); + + _cairo_contour_fini (&stroker.cw.contour); + _cairo_contour_fini (&stroker.ccw.contour); + if (stroker.pen.num_vertices) + _cairo_pen_fini (&stroker.pen); + +#if DEBUG + { + FILE *file = fopen ("polygons.txt", "a"); + _cairo_debug_print_polygon (file, polygon); + fclose (file); + } +#endif + + return status; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-path-stroke-traps.c b/local/recipes/libs/cairo/source/src/cairo-path-stroke-traps.c new file mode 100644 index 0000000000..4eabf6583e --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-path-stroke-traps.c @@ -0,0 +1,1168 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2013 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Chris Wilson + */ + +#include "cairoint.h" + +#include "cairo-box-inline.h" +#include "cairo-path-fixed-private.h" +#include "cairo-slope-private.h" +#include "cairo-stroke-dash-private.h" +#include "cairo-traps-private.h" + +#include + +struct stroker { + const cairo_stroke_style_t *style; + + const cairo_matrix_t *ctm; + const cairo_matrix_t *ctm_inverse; + double spline_cusp_tolerance; + double half_line_width; + double tolerance; + double ctm_determinant; + cairo_bool_t ctm_det_positive; + cairo_line_join_t line_join; + + cairo_traps_t *traps; + + cairo_pen_t pen; + + cairo_point_t first_point; + + cairo_bool_t has_initial_sub_path; + + cairo_bool_t has_current_face; + cairo_stroke_face_t current_face; + + cairo_bool_t has_first_face; + cairo_stroke_face_t first_face; + + cairo_stroker_dash_t dash; + + cairo_bool_t has_bounds; + cairo_box_t tight_bounds; + cairo_box_t line_bounds; + cairo_box_t join_bounds; +}; + +static cairo_status_t +stroker_init (struct stroker *stroker, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_traps_t *traps) +{ + cairo_status_t status; + + stroker->style = style; + stroker->ctm = ctm; + stroker->ctm_inverse = NULL; + if (! _cairo_matrix_is_identity (ctm_inverse)) + stroker->ctm_inverse = ctm_inverse; + stroker->line_join = style->line_join; + stroker->half_line_width = style->line_width / 2.0; + stroker->tolerance = tolerance; + stroker->traps = traps; + + /* If `CAIRO_LINE_JOIN_ROUND` is selected and a joint's `arc height` + * is greater than `tolerance` then two segments are joined with + * round-join, otherwise bevel-join is used. + * + * `Arc height` is the difference of the "half of a line width" and + * the "half of a line width" times `cos(half the angle between segment vectors)`. + * + * See detailed description in the `_cairo_path_fixed_stroke_to_polygon()` + * function in the `cairo-path-stroke-polygon.c` file or follow the + * https://gitlab.freedesktop.org/cairo/cairo/-/merge_requests/372#note_1698225 + * link to see the detailed description with an illustration. + */ + double scaled_hlw = hypot(stroker->half_line_width * ctm->xx, + stroker->half_line_width * ctm->yx); + + if (scaled_hlw <= tolerance) { + stroker->spline_cusp_tolerance = -1.0; + } else { + stroker->spline_cusp_tolerance = 1 - tolerance / scaled_hlw; + stroker->spline_cusp_tolerance *= stroker->spline_cusp_tolerance; + stroker->spline_cusp_tolerance *= 2; + stroker->spline_cusp_tolerance -= 1; + } + + stroker->ctm_determinant = _cairo_matrix_compute_determinant (stroker->ctm); + stroker->ctm_det_positive = stroker->ctm_determinant >= 0.0; + + status = _cairo_pen_init (&stroker->pen, + stroker->half_line_width, + tolerance, ctm); + if (unlikely (status)) + return status; + + stroker->has_current_face = FALSE; + stroker->has_first_face = FALSE; + stroker->has_initial_sub_path = FALSE; + + _cairo_stroker_dash_init (&stroker->dash, style); + + stroker->has_bounds = traps->num_limits; + if (stroker->has_bounds) { + /* Extend the bounds in each direction to account for the maximum area + * we might generate trapezoids, to capture line segments that are outside + * of the bounds but which might generate rendering that's within bounds. + */ + double dx, dy; + cairo_fixed_t fdx, fdy; + + stroker->tight_bounds = traps->bounds; + + _cairo_stroke_style_max_distance_from_path (stroker->style, path, + stroker->ctm, &dx, &dy); + + _cairo_stroke_style_max_line_distance_from_path (stroker->style, path, + stroker->ctm, &dx, &dy); + + fdx = _cairo_fixed_from_double (dx); + fdy = _cairo_fixed_from_double (dy); + + stroker->line_bounds = stroker->tight_bounds; + stroker->line_bounds.p1.x -= fdx; + stroker->line_bounds.p2.x += fdx; + stroker->line_bounds.p1.y -= fdy; + stroker->line_bounds.p2.y += fdy; + + _cairo_stroke_style_max_join_distance_from_path (stroker->style, path, + stroker->ctm, &dx, &dy); + + fdx = _cairo_fixed_from_double (dx); + fdy = _cairo_fixed_from_double (dy); + + stroker->join_bounds = stroker->tight_bounds; + stroker->join_bounds.p1.x -= fdx; + stroker->join_bounds.p2.x += fdx; + stroker->join_bounds.p1.y -= fdy; + stroker->join_bounds.p2.y += fdy; + } + + return CAIRO_STATUS_SUCCESS; +} + +static void +stroker_fini (struct stroker *stroker) +{ + _cairo_pen_fini (&stroker->pen); +} + +static void +translate_point (cairo_point_t *point, cairo_point_t *offset) +{ + point->x += offset->x; + point->y += offset->y; +} + +static int +join_is_clockwise (const cairo_stroke_face_t *in, + const cairo_stroke_face_t *out) +{ + return _cairo_slope_compare (&in->dev_vector, &out->dev_vector) < 0; +} + +static int +slope_compare_sgn (double dx1, double dy1, double dx2, double dy2) +{ + double c = dx1 * dy2 - dx2 * dy1; + if (c > 0) return 1; + if (c < 0) return -1; + return 0; +} + +static cairo_bool_t +stroker_intersects_join (const struct stroker *stroker, + const cairo_point_t *in, + const cairo_point_t *out) +{ + cairo_line_t segment; + + if (! stroker->has_bounds) + return TRUE; + + segment.p1 = *in; + segment.p2 = *out; + return _cairo_box_intersects_line_segment (&stroker->join_bounds, &segment); +} + +static void +join (struct stroker *stroker, + cairo_stroke_face_t *in, + cairo_stroke_face_t *out) +{ + int clockwise = join_is_clockwise (out, in); + cairo_point_t *inpt, *outpt; + + if (in->cw.x == out->cw.x && + in->cw.y == out->cw.y && + in->ccw.x == out->ccw.x && + in->ccw.y == out->ccw.y) + { + return; + } + + if (clockwise) { + inpt = &in->ccw; + outpt = &out->ccw; + } else { + inpt = &in->cw; + outpt = &out->cw; + } + + if (! stroker_intersects_join (stroker, inpt, outpt)) + return; + + switch (stroker->line_join) { + case CAIRO_LINE_JOIN_ROUND: + /* construct a fan around the common midpoint */ + if ((in->dev_slope.x * out->dev_slope.x + + in->dev_slope.y * out->dev_slope.y) < stroker->spline_cusp_tolerance) + { + int start, stop; + cairo_point_t tri[3], edges[4]; + cairo_pen_t *pen = &stroker->pen; + + edges[0] = in->cw; + edges[1] = in->ccw; + tri[0] = in->point; + tri[1] = *inpt; + if (clockwise) { + _cairo_pen_find_active_ccw_vertices (pen, + &in->dev_vector, &out->dev_vector, + &start, &stop); + while (start != stop) { + tri[2] = in->point; + translate_point (&tri[2], &pen->vertices[start].point); + edges[2] = in->point; + edges[3] = tri[2]; + _cairo_traps_tessellate_triangle_with_edges (stroker->traps, + tri, edges); + tri[1] = tri[2]; + edges[0] = edges[2]; + edges[1] = edges[3]; + + if (start-- == 0) + start += pen->num_vertices; + } + } else { + _cairo_pen_find_active_cw_vertices (pen, + &in->dev_vector, &out->dev_vector, + &start, &stop); + while (start != stop) { + tri[2] = in->point; + translate_point (&tri[2], &pen->vertices[start].point); + edges[2] = in->point; + edges[3] = tri[2]; + _cairo_traps_tessellate_triangle_with_edges (stroker->traps, + tri, edges); + tri[1] = tri[2]; + edges[0] = edges[2]; + edges[1] = edges[3]; + + if (++start == pen->num_vertices) + start = 0; + } + } + tri[2] = *outpt; + edges[2] = out->cw; + edges[3] = out->ccw; + _cairo_traps_tessellate_triangle_with_edges (stroker->traps, + tri, edges); + } else { + cairo_point_t t[] = { { in->point.x, in->point.y}, { inpt->x, inpt->y }, { outpt->x, outpt->y } }; + cairo_point_t e[] = { { in->cw.x, in->cw.y}, { in->ccw.x, in->ccw.y }, + { out->cw.x, out->cw.y}, { out->ccw.x, out->ccw.y } }; + _cairo_traps_tessellate_triangle_with_edges (stroker->traps, t, e); + } + break; + + case CAIRO_LINE_JOIN_MITER: + default: { + /* dot product of incoming slope vector with outgoing slope vector */ + double in_dot_out = (-in->usr_vector.x * out->usr_vector.x + + -in->usr_vector.y * out->usr_vector.y); + double ml = stroker->style->miter_limit; + + /* Check the miter limit -- lines meeting at an acute angle + * can generate long miters, the limit converts them to bevel + * + * Consider the miter join formed when two line segments + * meet at an angle psi: + * + * /.\ + * /. .\ + * /./ \.\ + * /./psi\.\ + * + * We can zoom in on the right half of that to see: + * + * |\ + * | \ psi/2 + * | \ + * | \ + * | \ + * | \ + * miter \ + * length \ + * | \ + * | .\ + * | . \ + * |. line \ + * \ width \ + * \ \ + * + * + * The right triangle in that figure, (the line-width side is + * shown faintly with three '.' characters), gives us the + * following expression relating miter length, angle and line + * width: + * + * 1 /sin (psi/2) = miter_length / line_width + * + * The right-hand side of this relationship is the same ratio + * in which the miter limit (ml) is expressed. We want to know + * when the miter length is within the miter limit. That is + * when the following condition holds: + * + * 1/sin(psi/2) <= ml + * 1 <= ml sin(psi/2) + * 1 <= ml² sin²(psi/2) + * 2 <= ml² 2 sin²(psi/2) + * 2·sin²(psi/2) = 1-cos(psi) + * 2 <= ml² (1-cos(psi)) + * + * in · out = |in| |out| cos (psi) + * + * in and out are both unit vectors, so: + * + * in · out = cos (psi) + * + * 2 <= ml² (1 - in · out) + * + */ + if (2 <= ml * ml * (1 - in_dot_out)) { + double x1, y1, x2, y2; + double mx, my; + double dx1, dx2, dy1, dy2; + cairo_point_t outer; + cairo_point_t quad[4]; + double ix, iy; + double fdx1, fdy1, fdx2, fdy2; + double mdx, mdy; + + /* + * we've got the points already transformed to device + * space, but need to do some computation with them and + * also need to transform the slope from user space to + * device space + */ + /* outer point of incoming line face */ + x1 = _cairo_fixed_to_double (inpt->x); + y1 = _cairo_fixed_to_double (inpt->y); + dx1 = in->usr_vector.x; + dy1 = in->usr_vector.y; + cairo_matrix_transform_distance (stroker->ctm, &dx1, &dy1); + + /* outer point of outgoing line face */ + x2 = _cairo_fixed_to_double (outpt->x); + y2 = _cairo_fixed_to_double (outpt->y); + dx2 = out->usr_vector.x; + dy2 = out->usr_vector.y; + cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2); + + /* + * Compute the location of the outer corner of the miter. + * That's pretty easy -- just the intersection of the two + * outer edges. We've got slopes and points on each + * of those edges. Compute my directly, then compute + * mx by using the edge with the larger dy; that avoids + * dividing by values close to zero. + */ + my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) / + (dx1 * dy2 - dx2 * dy1)); + if (fabs (dy1) >= fabs (dy2)) + mx = (my - y1) * dx1 / dy1 + x1; + else + mx = (my - y2) * dx2 / dy2 + x2; + + /* + * When the two outer edges are nearly parallel, slight + * perturbations in the position of the outer points of the lines + * caused by representing them in fixed point form can cause the + * intersection point of the miter to move a large amount. If + * that moves the miter intersection from between the two faces, + * then draw a bevel instead. + */ + + ix = _cairo_fixed_to_double (in->point.x); + iy = _cairo_fixed_to_double (in->point.y); + + /* slope of one face */ + fdx1 = x1 - ix; fdy1 = y1 - iy; + + /* slope of the other face */ + fdx2 = x2 - ix; fdy2 = y2 - iy; + + /* slope from the intersection to the miter point */ + mdx = mx - ix; mdy = my - iy; + + /* + * Make sure the miter point line lies between the two + * faces by comparing the slopes + */ + if (slope_compare_sgn (fdx1, fdy1, mdx, mdy) != + slope_compare_sgn (fdx2, fdy2, mdx, mdy)) + { + /* + * Draw the quadrilateral + */ + outer.x = _cairo_fixed_from_double (mx); + outer.y = _cairo_fixed_from_double (my); + + quad[0] = in->point; + quad[1] = *inpt; + quad[2] = outer; + quad[3] = *outpt; + + _cairo_traps_tessellate_convex_quad (stroker->traps, quad); + break; + } + } + } + /* fall through ... */ + case CAIRO_LINE_JOIN_BEVEL: { + cairo_point_t t[] = { { in->point.x, in->point.y }, { inpt->x, inpt->y }, { outpt->x, outpt->y } }; + cairo_point_t e[] = { { in->cw.x, in->cw.y }, { in->ccw.x, in->ccw.y }, + { out->cw.x, out->cw.y }, { out->ccw.x, out->ccw.y } }; + _cairo_traps_tessellate_triangle_with_edges (stroker->traps, t, e); + break; + } + } +} + +static void +add_cap (struct stroker *stroker, cairo_stroke_face_t *f) +{ + switch (stroker->style->line_cap) { + case CAIRO_LINE_CAP_ROUND: { + int start, stop; + cairo_slope_t in_slope, out_slope; + cairo_point_t tri[3], edges[4]; + cairo_pen_t *pen = &stroker->pen; + + in_slope = f->dev_vector; + out_slope.dx = -in_slope.dx; + out_slope.dy = -in_slope.dy; + _cairo_pen_find_active_cw_vertices (pen, &in_slope, &out_slope, + &start, &stop); + edges[0] = f->cw; + edges[1] = f->ccw; + tri[0] = f->point; + tri[1] = f->cw; + while (start != stop) { + tri[2] = f->point; + translate_point (&tri[2], &pen->vertices[start].point); + edges[2] = f->point; + edges[3] = tri[2]; + _cairo_traps_tessellate_triangle_with_edges (stroker->traps, + tri, edges); + + tri[1] = tri[2]; + edges[0] = edges[2]; + edges[1] = edges[3]; + if (++start == pen->num_vertices) + start = 0; + } + tri[2] = f->ccw; + edges[2] = f->cw; + edges[3] = f->ccw; + _cairo_traps_tessellate_triangle_with_edges (stroker->traps, + tri, edges); + break; + } + + case CAIRO_LINE_CAP_SQUARE: { + double dx, dy; + cairo_slope_t fvector; + cairo_point_t quad[4]; + + dx = f->usr_vector.x; + dy = f->usr_vector.y; + dx *= stroker->half_line_width; + dy *= stroker->half_line_width; + cairo_matrix_transform_distance (stroker->ctm, &dx, &dy); + fvector.dx = _cairo_fixed_from_double (dx); + fvector.dy = _cairo_fixed_from_double (dy); + + quad[0] = f->cw; + quad[1].x = f->cw.x + fvector.dx; + quad[1].y = f->cw.y + fvector.dy; + quad[2].x = f->ccw.x + fvector.dx; + quad[2].y = f->ccw.y + fvector.dy; + quad[3] = f->ccw; + + _cairo_traps_tessellate_convex_quad (stroker->traps, quad); + break; + } + + case CAIRO_LINE_CAP_BUTT: + default: + break; + } +} + +static void +add_leading_cap (struct stroker *stroker, + cairo_stroke_face_t *face) +{ + cairo_stroke_face_t reversed; + cairo_point_t t; + + reversed = *face; + + /* The initial cap needs an outward facing vector. Reverse everything */ + reversed.usr_vector.x = -reversed.usr_vector.x; + reversed.usr_vector.y = -reversed.usr_vector.y; + reversed.dev_vector.dx = -reversed.dev_vector.dx; + reversed.dev_vector.dy = -reversed.dev_vector.dy; + t = reversed.cw; + reversed.cw = reversed.ccw; + reversed.ccw = t; + + add_cap (stroker, &reversed); +} + +static void +add_trailing_cap (struct stroker *stroker, cairo_stroke_face_t *face) +{ + add_cap (stroker, face); +} + +static inline double +normalize_slope (double *dx, double *dy) +{ + double dx0 = *dx, dy0 = *dy; + + if (dx0 == 0.0 && dy0 == 0.0) + return 0; + + if (dx0 == 0.0) { + *dx = 0.0; + if (dy0 > 0.0) { + *dy = 1.0; + return dy0; + } else { + *dy = -1.0; + return -dy0; + } + } else if (dy0 == 0.0) { + *dy = 0.0; + if (dx0 > 0.0) { + *dx = 1.0; + return dx0; + } else { + *dx = -1.0; + return -dx0; + } + } else { + double mag = hypot (dx0, dy0); + *dx = dx0 / mag; + *dy = dy0 / mag; + return mag; + } +} + +static void +compute_face (const cairo_point_t *point, + const cairo_slope_t *dev_slope, + struct stroker *stroker, + cairo_stroke_face_t *face) +{ + double face_dx, face_dy; + cairo_point_t offset_ccw, offset_cw; + double slope_dx, slope_dy; + + slope_dx = _cairo_fixed_to_double (dev_slope->dx); + slope_dy = _cairo_fixed_to_double (dev_slope->dy); + face->length = normalize_slope (&slope_dx, &slope_dy); + face->dev_slope.x = slope_dx; + face->dev_slope.y = slope_dy; + + /* + * rotate to get a line_width/2 vector along the face, note that + * the vector must be rotated the right direction in device space, + * but by 90° in user space. So, the rotation depends on + * whether the ctm reflects or not, and that can be determined + * by looking at the determinant of the matrix. + */ + if (stroker->ctm_inverse) { + cairo_matrix_transform_distance (stroker->ctm_inverse, &slope_dx, &slope_dy); + normalize_slope (&slope_dx, &slope_dy); + + if (stroker->ctm_det_positive) { + face_dx = - slope_dy * stroker->half_line_width; + face_dy = slope_dx * stroker->half_line_width; + } else { + face_dx = slope_dy * stroker->half_line_width; + face_dy = - slope_dx * stroker->half_line_width; + } + + /* back to device space */ + cairo_matrix_transform_distance (stroker->ctm, &face_dx, &face_dy); + } else { + face_dx = - slope_dy * stroker->half_line_width; + face_dy = slope_dx * stroker->half_line_width; + } + + offset_ccw.x = _cairo_fixed_from_double (face_dx); + offset_ccw.y = _cairo_fixed_from_double (face_dy); + offset_cw.x = -offset_ccw.x; + offset_cw.y = -offset_ccw.y; + + face->ccw = *point; + translate_point (&face->ccw, &offset_ccw); + + face->point = *point; + + face->cw = *point; + translate_point (&face->cw, &offset_cw); + + face->usr_vector.x = slope_dx; + face->usr_vector.y = slope_dy; + + face->dev_vector = *dev_slope; +} + +static void +add_caps (struct stroker *stroker) +{ + /* check for a degenerative sub_path */ + if (stroker->has_initial_sub_path && + !stroker->has_first_face && + !stroker->has_current_face && + stroker->style->line_cap == CAIRO_LINE_CAP_ROUND) + { + /* pick an arbitrary slope to use */ + cairo_slope_t slope = { CAIRO_FIXED_ONE, 0 }; + cairo_stroke_face_t face; + + /* arbitrarily choose first_point + * first_point and current_point should be the same */ + compute_face (&stroker->first_point, &slope, stroker, &face); + + add_leading_cap (stroker, &face); + add_trailing_cap (stroker, &face); + } + + if (stroker->has_first_face) + add_leading_cap (stroker, &stroker->first_face); + + if (stroker->has_current_face) + add_trailing_cap (stroker, &stroker->current_face); +} + +static cairo_bool_t +stroker_intersects_edge (const struct stroker *stroker, + const cairo_stroke_face_t *start, + const cairo_stroke_face_t *end) +{ + cairo_box_t box; + + if (! stroker->has_bounds) + return TRUE; + + if (_cairo_box_contains_point (&stroker->tight_bounds, &start->cw)) + return TRUE; + box.p2 = box.p1 = start->cw; + + if (_cairo_box_contains_point (&stroker->tight_bounds, &start->ccw)) + return TRUE; + _cairo_box_add_point (&box, &start->ccw); + + if (_cairo_box_contains_point (&stroker->tight_bounds, &end->cw)) + return TRUE; + _cairo_box_add_point (&box, &end->cw); + + if (_cairo_box_contains_point (&stroker->tight_bounds, &end->ccw)) + return TRUE; + _cairo_box_add_point (&box, &end->ccw); + + return (box.p2.x > stroker->tight_bounds.p1.x && + box.p1.x < stroker->tight_bounds.p2.x && + box.p2.y > stroker->tight_bounds.p1.y && + box.p1.y < stroker->tight_bounds.p2.y); +} + +static void +add_sub_edge (struct stroker *stroker, + const cairo_point_t *p1, const cairo_point_t *p2, + const cairo_slope_t *dev_slope, + cairo_stroke_face_t *start, cairo_stroke_face_t *end) +{ + cairo_point_t rectangle[4]; + + compute_face (p1, dev_slope, stroker, start); + + *end = *start; + end->point = *p2; + rectangle[0].x = p2->x - p1->x; + rectangle[0].y = p2->y - p1->y; + translate_point (&end->ccw, &rectangle[0]); + translate_point (&end->cw, &rectangle[0]); + + if (p1->x == p2->x && p1->y == p2->y) + return; + + if (! stroker_intersects_edge (stroker, start, end)) + return; + + rectangle[0] = start->cw; + rectangle[1] = start->ccw; + rectangle[2] = end->ccw; + rectangle[3] = end->cw; + + _cairo_traps_tessellate_convex_quad (stroker->traps, rectangle); +} + +static cairo_status_t +move_to (void *closure, const cairo_point_t *point) +{ + struct stroker *stroker = closure; + + /* Cap the start and end of the previous sub path as needed */ + add_caps (stroker); + + stroker->first_point = *point; + stroker->current_face.point = *point; + + stroker->has_first_face = FALSE; + stroker->has_current_face = FALSE; + stroker->has_initial_sub_path = FALSE; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +move_to_dashed (void *closure, const cairo_point_t *point) +{ + /* reset the dash pattern for new sub paths */ + struct stroker *stroker = closure; + + _cairo_stroker_dash_start (&stroker->dash); + return move_to (closure, point); +} + +static cairo_status_t +line_to (void *closure, const cairo_point_t *point) +{ + struct stroker *stroker = closure; + cairo_stroke_face_t start, end; + const cairo_point_t *p1 = &stroker->current_face.point; + const cairo_point_t *p2 = point; + cairo_slope_t dev_slope; + + stroker->has_initial_sub_path = TRUE; + + if (p1->x == p2->x && p1->y == p2->y) + return CAIRO_STATUS_SUCCESS; + + _cairo_slope_init (&dev_slope, p1, p2); + add_sub_edge (stroker, p1, p2, &dev_slope, &start, &end); + + if (stroker->has_current_face) { + /* Join with final face from previous segment */ + join (stroker, &stroker->current_face, &start); + } else if (!stroker->has_first_face) { + /* Save sub path's first face in case needed for closing join */ + stroker->first_face = start; + stroker->has_first_face = TRUE; + } + stroker->current_face = end; + stroker->has_current_face = TRUE; + + return CAIRO_STATUS_SUCCESS; +} + +/* + * Dashed lines. Cap each dash end, join around turns when on + */ +static cairo_status_t +line_to_dashed (void *closure, const cairo_point_t *point) +{ + struct stroker *stroker = closure; + double mag, remain, step_length = 0; + double slope_dx, slope_dy; + double dx2, dy2; + cairo_stroke_face_t sub_start, sub_end; + const cairo_point_t *p1 = &stroker->current_face.point; + const cairo_point_t *p2 = point; + cairo_slope_t dev_slope; + cairo_line_t segment; + cairo_bool_t fully_in_bounds; + + stroker->has_initial_sub_path = stroker->dash.dash_starts_on; + + if (p1->x == p2->x && p1->y == p2->y) + return CAIRO_STATUS_SUCCESS; + + fully_in_bounds = TRUE; + if (stroker->has_bounds && + (! _cairo_box_contains_point (&stroker->join_bounds, p1) || + ! _cairo_box_contains_point (&stroker->join_bounds, p2))) + { + fully_in_bounds = FALSE; + } + + _cairo_slope_init (&dev_slope, p1, p2); + + slope_dx = _cairo_fixed_to_double (p2->x - p1->x); + slope_dy = _cairo_fixed_to_double (p2->y - p1->y); + + if (stroker->ctm_inverse) + cairo_matrix_transform_distance (stroker->ctm_inverse, &slope_dx, &slope_dy); + mag = normalize_slope (&slope_dx, &slope_dy); + if (mag <= DBL_EPSILON) + return CAIRO_STATUS_SUCCESS; + + remain = mag; + segment.p1 = *p1; + while (remain) { + step_length = MIN (stroker->dash.dash_remain, remain); + remain -= step_length; + dx2 = slope_dx * (mag - remain); + dy2 = slope_dy * (mag - remain); + cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2); + segment.p2.x = _cairo_fixed_from_double (dx2) + p1->x; + segment.p2.y = _cairo_fixed_from_double (dy2) + p1->y; + + if (stroker->dash.dash_on && + (fully_in_bounds || + (! stroker->has_first_face && stroker->dash.dash_starts_on) || + _cairo_box_intersects_line_segment (&stroker->join_bounds, &segment))) + { + add_sub_edge (stroker, + &segment.p1, &segment.p2, + &dev_slope, + &sub_start, &sub_end); + + if (stroker->has_current_face) { + /* Join with final face from previous segment */ + join (stroker, &stroker->current_face, &sub_start); + + stroker->has_current_face = FALSE; + } else if (! stroker->has_first_face && stroker->dash.dash_starts_on) { + /* Save sub path's first face in case needed for closing join */ + stroker->first_face = sub_start; + stroker->has_first_face = TRUE; + } else { + /* Cap dash start if not connecting to a previous segment */ + add_leading_cap (stroker, &sub_start); + } + + if (remain) { + /* Cap dash end if not at end of segment */ + add_trailing_cap (stroker, &sub_end); + } else { + stroker->current_face = sub_end; + stroker->has_current_face = TRUE; + } + } else { + if (stroker->has_current_face) { + /* Cap final face from previous segment */ + add_trailing_cap (stroker, &stroker->current_face); + + stroker->has_current_face = FALSE; + } + } + + _cairo_stroker_dash_step (&stroker->dash, step_length); + segment.p1 = segment.p2; + } + + if (stroker->dash.dash_on && ! stroker->has_current_face) { + /* This segment ends on a transition to dash_on, compute a new face + * and add cap for the beginning of the next dash_on step. + * + * Note: this will create a degenerate cap if this is not the last line + * in the path. Whether this behaviour is desirable or not is debatable. + * On one side these degenerate caps can not be reproduced with regular + * path stroking. + * On the other hand, Acroread 7 also produces the degenerate caps. + */ + compute_face (point, &dev_slope, stroker, &stroker->current_face); + + add_leading_cap (stroker, &stroker->current_face); + + stroker->has_current_face = TRUE; + } else + stroker->current_face.point = *point; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +add_point (void *closure, + const cairo_point_t *point, + const cairo_slope_t *tangent) +{ + return line_to_dashed (closure, point); +}; + +static cairo_status_t +spline_to (void *closure, + const cairo_point_t *point, + const cairo_slope_t *tangent) +{ + struct stroker *stroker = closure; + cairo_stroke_face_t face; + + if ((tangent->dx | tangent->dy) == 0) { + cairo_point_t t; + + face = stroker->current_face; + + face.usr_vector.x = -face.usr_vector.x; + face.usr_vector.y = -face.usr_vector.y; + face.dev_slope.x = -face.dev_slope.x; + face.dev_slope.y = -face.dev_slope.y; + face.dev_vector.dx = -face.dev_vector.dx; + face.dev_vector.dy = -face.dev_vector.dy; + + t = face.cw; + face.cw = face.ccw; + face.ccw = t; + + join (stroker, &stroker->current_face, &face); + } else { + cairo_point_t rectangle[4]; + + compute_face (&stroker->current_face.point, tangent, stroker, &face); + join (stroker, &stroker->current_face, &face); + + rectangle[0] = face.cw; + rectangle[1] = face.ccw; + + rectangle[2].x = point->x - face.point.x; + rectangle[2].y = point->y - face.point.y; + face.point = *point; + translate_point (&face.ccw, &rectangle[2]); + translate_point (&face.cw, &rectangle[2]); + + rectangle[2] = face.ccw; + rectangle[3] = face.cw; + + _cairo_traps_tessellate_convex_quad (stroker->traps, rectangle); + } + + stroker->current_face = face; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +curve_to (void *closure, + const cairo_point_t *b, + const cairo_point_t *c, + const cairo_point_t *d) +{ + struct stroker *stroker = closure; + cairo_line_join_t line_join_save; + cairo_spline_t spline; + cairo_stroke_face_t face; + cairo_status_t status; + + if (stroker->has_bounds && + ! _cairo_spline_intersects (&stroker->current_face.point, b, c, d, + &stroker->line_bounds)) + return line_to (closure, d); + + if (! _cairo_spline_init (&spline, spline_to, stroker, + &stroker->current_face.point, b, c, d)) + return line_to (closure, d); + + compute_face (&stroker->current_face.point, &spline.initial_slope, + stroker, &face); + + if (stroker->has_current_face) { + /* Join with final face from previous segment */ + join (stroker, &stroker->current_face, &face); + } else { + if (! stroker->has_first_face) { + /* Save sub path's first face in case needed for closing join */ + stroker->first_face = face; + stroker->has_first_face = TRUE; + } + stroker->has_current_face = TRUE; + } + stroker->current_face = face; + + /* Temporarily modify the stroker to use round joins to guarantee + * smooth stroked curves. */ + line_join_save = stroker->line_join; + stroker->line_join = CAIRO_LINE_JOIN_ROUND; + + status = _cairo_spline_decompose (&spline, stroker->tolerance); + + stroker->line_join = line_join_save; + + return status; +} + +static cairo_status_t +curve_to_dashed (void *closure, + const cairo_point_t *b, + const cairo_point_t *c, + const cairo_point_t *d) +{ + struct stroker *stroker = closure; + cairo_spline_t spline; + cairo_line_join_t line_join_save; + cairo_spline_add_point_func_t func; + cairo_status_t status; + + func = add_point; + + if (stroker->has_bounds && + ! _cairo_spline_intersects (&stroker->current_face.point, b, c, d, + &stroker->line_bounds)) + return func (closure, d, NULL); + + if (! _cairo_spline_init (&spline, func, stroker, + &stroker->current_face.point, b, c, d)) + return func (closure, d, NULL); + + /* Temporarily modify the stroker to use round joins to guarantee + * smooth stroked curves. */ + line_join_save = stroker->line_join; + stroker->line_join = CAIRO_LINE_JOIN_ROUND; + + status = _cairo_spline_decompose (&spline, stroker->tolerance); + + stroker->line_join = line_join_save; + + return status; +} + +static cairo_status_t +_close_path (struct stroker *stroker) +{ + if (stroker->has_first_face && stroker->has_current_face) { + /* Join first and final faces of sub path */ + join (stroker, &stroker->current_face, &stroker->first_face); + } else { + /* Cap the start and end of the sub path as needed */ + add_caps (stroker); + } + + stroker->has_initial_sub_path = FALSE; + stroker->has_first_face = FALSE; + stroker->has_current_face = FALSE; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +close_path (void *closure) +{ + struct stroker *stroker = closure; + cairo_status_t status; + + status = line_to (stroker, &stroker->first_point); + if (unlikely (status)) + return status; + + return _close_path (stroker); +} + +static cairo_status_t +close_path_dashed (void *closure) +{ + struct stroker *stroker = closure; + cairo_status_t status; + + status = line_to_dashed (stroker, &stroker->first_point); + if (unlikely (status)) + return status; + + return _close_path (stroker); +} + +cairo_int_status_t +_cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_traps_t *traps) +{ + struct stroker stroker; + cairo_status_t status; + + status = stroker_init (&stroker, path, style, + ctm, ctm_inverse, tolerance, + traps); + if (unlikely (status)) + return status; + + if (stroker.dash.dashed) + status = _cairo_path_fixed_interpret (path, + move_to_dashed, + line_to_dashed, + curve_to_dashed, + close_path_dashed, + &stroker); + else + status = _cairo_path_fixed_interpret (path, + move_to, + line_to, + curve_to, + close_path, + &stroker); + assert(status == CAIRO_STATUS_SUCCESS); + add_caps (&stroker); + + stroker_fini (&stroker); + + return traps->status; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-path-stroke-tristrip.c b/local/recipes/libs/cairo/source/src/cairo-path-stroke-tristrip.c new file mode 100644 index 0000000000..3178765608 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-path-stroke-tristrip.c @@ -0,0 +1,1088 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Chris Wilson + */ + +#define _DEFAULT_SOURCE /* for hypot() */ +#include "cairoint.h" + +#include "cairo-box-inline.h" +#include "cairo-boxes-private.h" +#include "cairo-error-private.h" +#include "cairo-path-fixed-private.h" +#include "cairo-slope-private.h" +#include "cairo-tristrip-private.h" + +struct stroker { + cairo_stroke_style_t style; + + cairo_tristrip_t *strip; + + const cairo_matrix_t *ctm; + const cairo_matrix_t *ctm_inverse; + double tolerance; + cairo_bool_t ctm_det_positive; + + cairo_pen_t pen; + + cairo_bool_t has_sub_path; + + cairo_point_t first_point; + + cairo_bool_t has_current_face; + cairo_stroke_face_t current_face; + + cairo_bool_t has_first_face; + cairo_stroke_face_t first_face; + + cairo_box_t limit; + cairo_bool_t has_limits; +}; + +static inline double +normalize_slope (double *dx, double *dy); + +static void +compute_face (const cairo_point_t *point, + const cairo_slope_t *dev_slope, + struct stroker *stroker, + cairo_stroke_face_t *face); + +static void +translate_point (cairo_point_t *point, const cairo_point_t *offset) +{ + point->x += offset->x; + point->y += offset->y; +} + +static int +slope_compare_sgn (double dx1, double dy1, double dx2, double dy2) +{ + double c = (dx1 * dy2 - dx2 * dy1); + + if (c > 0) return 1; + if (c < 0) return -1; + return 0; +} + +static inline int +range_step (int i, int step, int max) +{ + i += step; + if (i < 0) + i = max - 1; + if (i >= max) + i = 0; + return i; +} + +/* + * Construct a fan around the midpoint using the vertices from pen between + * inpt and outpt. + */ +static void +add_fan (struct stroker *stroker, + const cairo_slope_t *in_vector, + const cairo_slope_t *out_vector, + const cairo_point_t *midpt, + const cairo_point_t *inpt, + const cairo_point_t *outpt, + cairo_bool_t clockwise) +{ + int start, stop, step, i, npoints; + + if (clockwise) { + step = 1; + + start = _cairo_pen_find_active_cw_vertex_index (&stroker->pen, + in_vector); + if (_cairo_slope_compare (&stroker->pen.vertices[start].slope_cw, + in_vector) < 0) + start = range_step (start, 1, stroker->pen.num_vertices); + + stop = _cairo_pen_find_active_cw_vertex_index (&stroker->pen, + out_vector); + if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_ccw, + out_vector) > 0) + { + stop = range_step (stop, -1, stroker->pen.num_vertices); + if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_cw, + in_vector) < 0) + return; + } + + npoints = stop - start; + } else { + step = -1; + + start = _cairo_pen_find_active_ccw_vertex_index (&stroker->pen, + in_vector); + if (_cairo_slope_compare (&stroker->pen.vertices[start].slope_ccw, + in_vector) < 0) + start = range_step (start, -1, stroker->pen.num_vertices); + + stop = _cairo_pen_find_active_ccw_vertex_index (&stroker->pen, + out_vector); + if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_cw, + out_vector) > 0) + { + stop = range_step (stop, 1, stroker->pen.num_vertices); + if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_ccw, + in_vector) < 0) + return; + } + + npoints = start - stop; + } + stop = range_step (stop, step, stroker->pen.num_vertices); + if (npoints < 0) + npoints += stroker->pen.num_vertices; + if (npoints <= 1) + return; + + for (i = start; + i != stop; + i = range_step (i, step, stroker->pen.num_vertices)) + { + cairo_point_t p = *midpt; + translate_point (&p, &stroker->pen.vertices[i].point); + //contour_add_point (stroker, c, &p); + } +} + +static int +join_is_clockwise (const cairo_stroke_face_t *in, + const cairo_stroke_face_t *out) +{ + return _cairo_slope_compare (&in->dev_vector, &out->dev_vector) < 0; +} + +static void +inner_join (struct stroker *stroker, + const cairo_stroke_face_t *in, + const cairo_stroke_face_t *out, + int clockwise) +{ + const cairo_point_t *outpt; + + if (clockwise) { + outpt = &out->ccw; + } else { + outpt = &out->cw; + } + //contour_add_point (stroker, inner, &in->point); + //contour_add_point (stroker, inner, outpt); +} + +static void +inner_close (struct stroker *stroker, + const cairo_stroke_face_t *in, + cairo_stroke_face_t *out) +{ + const cairo_point_t *inpt; + + if (join_is_clockwise (in, out)) { + inpt = &out->ccw; + } else { + inpt = &out->cw; + } + + //contour_add_point (stroker, inner, &in->point); + //contour_add_point (stroker, inner, inpt); + //*_cairo_contour_first_point (&inner->contour) = + //*_cairo_contour_last_point (&inner->contour); +} + +static void +outer_close (struct stroker *stroker, + const cairo_stroke_face_t *in, + const cairo_stroke_face_t *out) +{ + const cairo_point_t *inpt, *outpt; + int clockwise; + + if (in->cw.x == out->cw.x && in->cw.y == out->cw.y && + in->ccw.x == out->ccw.x && in->ccw.y == out->ccw.y) + { + return; + } + clockwise = join_is_clockwise (in, out); + if (clockwise) { + inpt = &in->cw; + outpt = &out->cw; + } else { + inpt = &in->ccw; + outpt = &out->ccw; + } + + switch (stroker->style.line_join) { + case CAIRO_LINE_JOIN_ROUND: + /* construct a fan around the common midpoint */ + add_fan (stroker, + &in->dev_vector, + &out->dev_vector, + &in->point, inpt, outpt, + clockwise); + break; + + case CAIRO_LINE_JOIN_MITER: + default: { + /* dot product of incoming slope vector with outgoing slope vector */ + double in_dot_out = -in->usr_vector.x * out->usr_vector.x + + -in->usr_vector.y * out->usr_vector.y; + double ml = stroker->style.miter_limit; + + /* Check the miter limit -- lines meeting at an acute angle + * can generate long miters, the limit converts them to bevel + * + * Consider the miter join formed when two line segments + * meet at an angle psi: + * + * /.\ + * /. .\ + * /./ \.\ + * /./psi\.\ + * + * We can zoom in on the right half of that to see: + * + * |\ + * | \ psi/2 + * | \ + * | \ + * | \ + * | \ + * miter \ + * length \ + * | \ + * | .\ + * | . \ + * |. line \ + * \ width \ + * \ \ + * + * + * The right triangle in that figure, (the line-width side is + * shown faintly with three '.' characters), gives us the + * following expression relating miter length, angle and line + * width: + * + * 1 /sin (psi/2) = miter_length / line_width + * + * The right-hand side of this relationship is the same ratio + * in which the miter limit (ml) is expressed. We want to know + * when the miter length is within the miter limit. That is + * when the following condition holds: + * + * 1/sin(psi/2) <= ml + * 1 <= ml sin(psi/2) + * 1 <= ml² sin²(psi/2) + * 2 <= ml² 2 sin²(psi/2) + * 2·sin²(psi/2) = 1-cos(psi) + * 2 <= ml² (1-cos(psi)) + * + * in · out = |in| |out| cos (psi) + * + * in and out are both unit vectors, so: + * + * in · out = cos (psi) + * + * 2 <= ml² (1 - in · out) + * + */ + if (2 <= ml * ml * (1 - in_dot_out)) { + double x1, y1, x2, y2; + double mx, my; + double dx1, dx2, dy1, dy2; + double ix, iy; + double fdx1, fdy1, fdx2, fdy2; + double mdx, mdy; + + /* + * we've got the points already transformed to device + * space, but need to do some computation with them and + * also need to transform the slope from user space to + * device space + */ + /* outer point of incoming line face */ + x1 = _cairo_fixed_to_double (inpt->x); + y1 = _cairo_fixed_to_double (inpt->y); + dx1 = in->usr_vector.x; + dy1 = in->usr_vector.y; + cairo_matrix_transform_distance (stroker->ctm, &dx1, &dy1); + + /* outer point of outgoing line face */ + x2 = _cairo_fixed_to_double (outpt->x); + y2 = _cairo_fixed_to_double (outpt->y); + dx2 = out->usr_vector.x; + dy2 = out->usr_vector.y; + cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2); + + /* + * Compute the location of the outer corner of the miter. + * That's pretty easy -- just the intersection of the two + * outer edges. We've got slopes and points on each + * of those edges. Compute my directly, then compute + * mx by using the edge with the larger dy; that avoids + * dividing by values close to zero. + */ + my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) / + (dx1 * dy2 - dx2 * dy1)); + if (fabs (dy1) >= fabs (dy2)) + mx = (my - y1) * dx1 / dy1 + x1; + else + mx = (my - y2) * dx2 / dy2 + x2; + + /* + * When the two outer edges are nearly parallel, slight + * perturbations in the position of the outer points of the lines + * caused by representing them in fixed point form can cause the + * intersection point of the miter to move a large amount. If + * that moves the miter intersection from between the two faces, + * then draw a bevel instead. + */ + + ix = _cairo_fixed_to_double (in->point.x); + iy = _cairo_fixed_to_double (in->point.y); + + /* slope of one face */ + fdx1 = x1 - ix; fdy1 = y1 - iy; + + /* slope of the other face */ + fdx2 = x2 - ix; fdy2 = y2 - iy; + + /* slope from the intersection to the miter point */ + mdx = mx - ix; mdy = my - iy; + + /* + * Make sure the miter point line lies between the two + * faces by comparing the slopes + */ + if (slope_compare_sgn (fdx1, fdy1, mdx, mdy) != + slope_compare_sgn (fdx2, fdy2, mdx, mdy)) + { + cairo_point_t p; + + p.x = _cairo_fixed_from_double (mx); + p.y = _cairo_fixed_from_double (my); + + //*_cairo_contour_last_point (&outer->contour) = p; + //*_cairo_contour_first_point (&outer->contour) = p; + return; + } + } + break; + } + + case CAIRO_LINE_JOIN_BEVEL: + break; + } + //contour_add_point (stroker, outer, outpt); +} + +static void +outer_join (struct stroker *stroker, + const cairo_stroke_face_t *in, + const cairo_stroke_face_t *out, + int clockwise) +{ + const cairo_point_t *inpt, *outpt; + + if (in->cw.x == out->cw.x && in->cw.y == out->cw.y && + in->ccw.x == out->ccw.x && in->ccw.y == out->ccw.y) + { + return; + } + if (clockwise) { + inpt = &in->cw; + outpt = &out->cw; + } else { + inpt = &in->ccw; + outpt = &out->ccw; + } + + switch (stroker->style.line_join) { + case CAIRO_LINE_JOIN_ROUND: + /* construct a fan around the common midpoint */ + add_fan (stroker, + &in->dev_vector, + &out->dev_vector, + &in->point, inpt, outpt, + clockwise); + break; + + case CAIRO_LINE_JOIN_MITER: + default: { + /* dot product of incoming slope vector with outgoing slope vector */ + double in_dot_out = -in->usr_vector.x * out->usr_vector.x + + -in->usr_vector.y * out->usr_vector.y; + double ml = stroker->style.miter_limit; + + /* Check the miter limit -- lines meeting at an acute angle + * can generate long miters, the limit converts them to bevel + * + * Consider the miter join formed when two line segments + * meet at an angle psi: + * + * /.\ + * /. .\ + * /./ \.\ + * /./psi\.\ + * + * We can zoom in on the right half of that to see: + * + * |\ + * | \ psi/2 + * | \ + * | \ + * | \ + * | \ + * miter \ + * length \ + * | \ + * | .\ + * | . \ + * |. line \ + * \ width \ + * \ \ + * + * + * The right triangle in that figure, (the line-width side is + * shown faintly with three '.' characters), gives us the + * following expression relating miter length, angle and line + * width: + * + * 1 /sin (psi/2) = miter_length / line_width + * + * The right-hand side of this relationship is the same ratio + * in which the miter limit (ml) is expressed. We want to know + * when the miter length is within the miter limit. That is + * when the following condition holds: + * + * 1/sin(psi/2) <= ml + * 1 <= ml sin(psi/2) + * 1 <= ml² sin²(psi/2) + * 2 <= ml² 2 sin²(psi/2) + * 2·sin²(psi/2) = 1-cos(psi) + * 2 <= ml² (1-cos(psi)) + * + * in · out = |in| |out| cos (psi) + * + * in and out are both unit vectors, so: + * + * in · out = cos (psi) + * + * 2 <= ml² (1 - in · out) + * + */ + if (2 <= ml * ml * (1 - in_dot_out)) { + double x1, y1, x2, y2; + double mx, my; + double dx1, dx2, dy1, dy2; + double ix, iy; + double fdx1, fdy1, fdx2, fdy2; + double mdx, mdy; + + /* + * we've got the points already transformed to device + * space, but need to do some computation with them and + * also need to transform the slope from user space to + * device space + */ + /* outer point of incoming line face */ + x1 = _cairo_fixed_to_double (inpt->x); + y1 = _cairo_fixed_to_double (inpt->y); + dx1 = in->usr_vector.x; + dy1 = in->usr_vector.y; + cairo_matrix_transform_distance (stroker->ctm, &dx1, &dy1); + + /* outer point of outgoing line face */ + x2 = _cairo_fixed_to_double (outpt->x); + y2 = _cairo_fixed_to_double (outpt->y); + dx2 = out->usr_vector.x; + dy2 = out->usr_vector.y; + cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2); + + /* + * Compute the location of the outer corner of the miter. + * That's pretty easy -- just the intersection of the two + * outer edges. We've got slopes and points on each + * of those edges. Compute my directly, then compute + * mx by using the edge with the larger dy; that avoids + * dividing by values close to zero. + */ + my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) / + (dx1 * dy2 - dx2 * dy1)); + if (fabs (dy1) >= fabs (dy2)) + mx = (my - y1) * dx1 / dy1 + x1; + else + mx = (my - y2) * dx2 / dy2 + x2; + + /* + * When the two outer edges are nearly parallel, slight + * perturbations in the position of the outer points of the lines + * caused by representing them in fixed point form can cause the + * intersection point of the miter to move a large amount. If + * that moves the miter intersection from between the two faces, + * then draw a bevel instead. + */ + + ix = _cairo_fixed_to_double (in->point.x); + iy = _cairo_fixed_to_double (in->point.y); + + /* slope of one face */ + fdx1 = x1 - ix; fdy1 = y1 - iy; + + /* slope of the other face */ + fdx2 = x2 - ix; fdy2 = y2 - iy; + + /* slope from the intersection to the miter point */ + mdx = mx - ix; mdy = my - iy; + + /* + * Make sure the miter point line lies between the two + * faces by comparing the slopes + */ + if (slope_compare_sgn (fdx1, fdy1, mdx, mdy) != + slope_compare_sgn (fdx2, fdy2, mdx, mdy)) + { + cairo_point_t p; + + p.x = _cairo_fixed_from_double (mx); + p.y = _cairo_fixed_from_double (my); + + //*_cairo_contour_last_point (&outer->contour) = p; + return; + } + } + break; + } + + case CAIRO_LINE_JOIN_BEVEL: + break; + } + //contour_add_point (stroker,outer, outpt); +} + +static void +add_cap (struct stroker *stroker, + const cairo_stroke_face_t *f) +{ + switch (stroker->style.line_cap) { + case CAIRO_LINE_CAP_ROUND: { + cairo_slope_t slope; + + slope.dx = -f->dev_vector.dx; + slope.dy = -f->dev_vector.dy; + + add_fan (stroker, &f->dev_vector, &slope, + &f->point, &f->ccw, &f->cw, + FALSE); + break; + } + + case CAIRO_LINE_CAP_SQUARE: { + double dx, dy; + cairo_slope_t fvector; + cairo_point_t quad[4]; + + dx = f->usr_vector.x; + dy = f->usr_vector.y; + dx *= stroker->style.line_width / 2.0; + dy *= stroker->style.line_width / 2.0; + cairo_matrix_transform_distance (stroker->ctm, &dx, &dy); + fvector.dx = _cairo_fixed_from_double (dx); + fvector.dy = _cairo_fixed_from_double (dy); + + quad[0] = f->ccw; + quad[1].x = f->ccw.x + fvector.dx; + quad[1].y = f->ccw.y + fvector.dy; + quad[2].x = f->cw.x + fvector.dx; + quad[2].y = f->cw.y + fvector.dy; + quad[3] = f->cw; + + //contour_add_point (stroker, c, &quad[1]); + //contour_add_point (stroker, c, &quad[2]); + } + + case CAIRO_LINE_CAP_BUTT: + default: + break; + } + //contour_add_point (stroker, c, &f->cw); +} + +static void +add_leading_cap (struct stroker *stroker, + const cairo_stroke_face_t *face) +{ + cairo_stroke_face_t reversed; + cairo_point_t t; + + reversed = *face; + + /* The initial cap needs an outward facing vector. Reverse everything */ + reversed.usr_vector.x = -reversed.usr_vector.x; + reversed.usr_vector.y = -reversed.usr_vector.y; + reversed.dev_vector.dx = -reversed.dev_vector.dx; + reversed.dev_vector.dy = -reversed.dev_vector.dy; + + t = reversed.cw; + reversed.cw = reversed.ccw; + reversed.ccw = t; + + add_cap (stroker, &reversed); +} + +static void +add_trailing_cap (struct stroker *stroker, + const cairo_stroke_face_t *face) +{ + add_cap (stroker, face); +} + +static inline double +normalize_slope (double *dx, double *dy) +{ + double dx0 = *dx, dy0 = *dy; + double mag; + + assert (dx0 != 0.0 || dy0 != 0.0); + + if (dx0 == 0.0) { + *dx = 0.0; + if (dy0 > 0.0) { + mag = dy0; + *dy = 1.0; + } else { + mag = -dy0; + *dy = -1.0; + } + } else if (dy0 == 0.0) { + *dy = 0.0; + if (dx0 > 0.0) { + mag = dx0; + *dx = 1.0; + } else { + mag = -dx0; + *dx = -1.0; + } + } else { + mag = hypot (dx0, dy0); + *dx = dx0 / mag; + *dy = dy0 / mag; + } + + return mag; +} + +static void +compute_face (const cairo_point_t *point, + const cairo_slope_t *dev_slope, + struct stroker *stroker, + cairo_stroke_face_t *face) +{ + double face_dx, face_dy; + cairo_point_t offset_ccw, offset_cw; + double slope_dx, slope_dy; + + slope_dx = _cairo_fixed_to_double (dev_slope->dx); + slope_dy = _cairo_fixed_to_double (dev_slope->dy); + face->length = normalize_slope (&slope_dx, &slope_dy); + face->dev_slope.x = slope_dx; + face->dev_slope.y = slope_dy; + + /* + * rotate to get a line_width/2 vector along the face, note that + * the vector must be rotated the right direction in device space, + * but by 90° in user space. So, the rotation depends on + * whether the ctm reflects or not, and that can be determined + * by looking at the determinant of the matrix. + */ + if (! _cairo_matrix_is_identity (stroker->ctm_inverse)) { + /* Normalize the matrix! */ + cairo_matrix_transform_distance (stroker->ctm_inverse, + &slope_dx, &slope_dy); + normalize_slope (&slope_dx, &slope_dy); + + if (stroker->ctm_det_positive) { + face_dx = - slope_dy * (stroker->style.line_width / 2.0); + face_dy = slope_dx * (stroker->style.line_width / 2.0); + } else { + face_dx = slope_dy * (stroker->style.line_width / 2.0); + face_dy = - slope_dx * (stroker->style.line_width / 2.0); + } + + /* back to device space */ + cairo_matrix_transform_distance (stroker->ctm, &face_dx, &face_dy); + } else { + face_dx = - slope_dy * (stroker->style.line_width / 2.0); + face_dy = slope_dx * (stroker->style.line_width / 2.0); + } + + offset_ccw.x = _cairo_fixed_from_double (face_dx); + offset_ccw.y = _cairo_fixed_from_double (face_dy); + offset_cw.x = -offset_ccw.x; + offset_cw.y = -offset_ccw.y; + + face->ccw = *point; + translate_point (&face->ccw, &offset_ccw); + + face->point = *point; + + face->cw = *point; + translate_point (&face->cw, &offset_cw); + + face->usr_vector.x = slope_dx; + face->usr_vector.y = slope_dy; + + face->dev_vector = *dev_slope; +} + +static void +add_caps (struct stroker *stroker) +{ + /* check for a degenerative sub_path */ + if (stroker->has_sub_path && + ! stroker->has_first_face && + ! stroker->has_current_face && + stroker->style.line_cap == CAIRO_LINE_CAP_ROUND) + { + /* pick an arbitrary slope to use */ + cairo_slope_t slope = { CAIRO_FIXED_ONE, 0 }; + cairo_stroke_face_t face; + + /* arbitrarily choose first_point */ + compute_face (&stroker->first_point, &slope, stroker, &face); + + add_leading_cap (stroker, &face); + add_trailing_cap (stroker, &face); + + /* ensure the circle is complete */ + //_cairo_contour_add_point (&stroker->ccw.contour, + //_cairo_contour_first_point (&stroker->ccw.contour)); + } else { + if (stroker->has_current_face) + add_trailing_cap (stroker, &stroker->current_face); + + //_cairo_polygon_add_contour (stroker->polygon, &stroker->ccw.contour); + //_cairo_contour_reset (&stroker->ccw.contour); + + if (stroker->has_first_face) { + //_cairo_contour_add_point (&stroker->ccw.contour, + //&stroker->first_face.cw); + add_leading_cap (stroker, &stroker->first_face); + //_cairo_polygon_add_contour (stroker->polygon, + //&stroker->ccw.contour); + //_cairo_contour_reset (&stroker->ccw.contour); + } + } +} + +static cairo_status_t +move_to (void *closure, + const cairo_point_t *point) +{ + struct stroker *stroker = closure; + + /* Cap the start and end of the previous sub path as needed */ + add_caps (stroker); + + stroker->has_first_face = FALSE; + stroker->has_current_face = FALSE; + stroker->has_sub_path = FALSE; + + stroker->first_point = *point; + + stroker->current_face.point = *point; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +line_to (void *closure, + const cairo_point_t *point) +{ + struct stroker *stroker = closure; + cairo_stroke_face_t start; + cairo_point_t *p1 = &stroker->current_face.point; + cairo_slope_t dev_slope; + + stroker->has_sub_path = TRUE; + + if (p1->x == point->x && p1->y == point->y) + return CAIRO_STATUS_SUCCESS; + + _cairo_slope_init (&dev_slope, p1, point); + compute_face (p1, &dev_slope, stroker, &start); + + if (stroker->has_current_face) { + int clockwise = join_is_clockwise (&stroker->current_face, &start); + /* Join with final face from previous segment */ + outer_join (stroker, &stroker->current_face, &start, clockwise); + inner_join (stroker, &stroker->current_face, &start, clockwise); + } else { + if (! stroker->has_first_face) { + /* Save sub path's first face in case needed for closing join */ + stroker->first_face = start; + _cairo_tristrip_move_to (stroker->strip, &start.cw); + stroker->has_first_face = TRUE; + } + stroker->has_current_face = TRUE; + + _cairo_tristrip_add_point (stroker->strip, &start.cw); + _cairo_tristrip_add_point (stroker->strip, &start.ccw); + } + + stroker->current_face = start; + stroker->current_face.point = *point; + stroker->current_face.ccw.x += dev_slope.dx; + stroker->current_face.ccw.y += dev_slope.dy; + stroker->current_face.cw.x += dev_slope.dx; + stroker->current_face.cw.y += dev_slope.dy; + + _cairo_tristrip_add_point (stroker->strip, &stroker->current_face.cw); + _cairo_tristrip_add_point (stroker->strip, &stroker->current_face.ccw); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +spline_to (void *closure, + const cairo_point_t *point, + const cairo_slope_t *tangent) +{ + struct stroker *stroker = closure; + cairo_stroke_face_t face; + + if (tangent->dx == 0 && tangent->dy == 0) { + const cairo_point_t *inpt, *outpt; + cairo_point_t t; + int clockwise; + + face = stroker->current_face; + + face.usr_vector.x = -face.usr_vector.x; + face.usr_vector.y = -face.usr_vector.y; + face.dev_vector.dx = -face.dev_vector.dx; + face.dev_vector.dy = -face.dev_vector.dy; + + t = face.cw; + face.cw = face.ccw; + face.ccw = t; + + clockwise = join_is_clockwise (&stroker->current_face, &face); + if (clockwise) { + inpt = &stroker->current_face.cw; + outpt = &face.cw; + } else { + inpt = &stroker->current_face.ccw; + outpt = &face.ccw; + } + + add_fan (stroker, + &stroker->current_face.dev_vector, + &face.dev_vector, + &stroker->current_face.point, inpt, outpt, + clockwise); + } else { + compute_face (point, tangent, stroker, &face); + + if (face.dev_slope.x * stroker->current_face.dev_slope.x + + face.dev_slope.y * stroker->current_face.dev_slope.y < 0) + { + const cairo_point_t *inpt, *outpt; + int clockwise = join_is_clockwise (&stroker->current_face, &face); + + stroker->current_face.cw.x += face.point.x - stroker->current_face.point.x; + stroker->current_face.cw.y += face.point.y - stroker->current_face.point.y; + //contour_add_point (stroker, &stroker->cw, &stroker->current_face.cw); + + stroker->current_face.ccw.x += face.point.x - stroker->current_face.point.x; + stroker->current_face.ccw.y += face.point.y - stroker->current_face.point.y; + //contour_add_point (stroker, &stroker->ccw, &stroker->current_face.ccw); + + if (clockwise) { + inpt = &stroker->current_face.cw; + outpt = &face.cw; + } else { + inpt = &stroker->current_face.ccw; + outpt = &face.ccw; + } + add_fan (stroker, + &stroker->current_face.dev_vector, + &face.dev_vector, + &stroker->current_face.point, inpt, outpt, + clockwise); + } + + _cairo_tristrip_add_point (stroker->strip, &face.cw); + _cairo_tristrip_add_point (stroker->strip, &face.ccw); + } + + stroker->current_face = face; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +curve_to (void *closure, + const cairo_point_t *b, + const cairo_point_t *c, + const cairo_point_t *d) +{ + struct stroker *stroker = closure; + cairo_spline_t spline; + cairo_stroke_face_t face; + + if (stroker->has_limits) { + if (! _cairo_spline_intersects (&stroker->current_face.point, b, c, d, + &stroker->limit)) + return line_to (closure, d); + } + + if (! _cairo_spline_init (&spline, spline_to, stroker, + &stroker->current_face.point, b, c, d)) + return line_to (closure, d); + + compute_face (&stroker->current_face.point, &spline.initial_slope, + stroker, &face); + + if (stroker->has_current_face) { + int clockwise = join_is_clockwise (&stroker->current_face, &face); + /* Join with final face from previous segment */ + outer_join (stroker, &stroker->current_face, &face, clockwise); + inner_join (stroker, &stroker->current_face, &face, clockwise); + } else { + if (! stroker->has_first_face) { + /* Save sub path's first face in case needed for closing join */ + stroker->first_face = face; + _cairo_tristrip_move_to (stroker->strip, &face.cw); + stroker->has_first_face = TRUE; + } + stroker->has_current_face = TRUE; + + _cairo_tristrip_add_point (stroker->strip, &face.cw); + _cairo_tristrip_add_point (stroker->strip, &face.ccw); + } + stroker->current_face = face; + + return _cairo_spline_decompose (&spline, stroker->tolerance); +} + +static cairo_status_t +close_path (void *closure) +{ + struct stroker *stroker = closure; + cairo_status_t status; + + status = line_to (stroker, &stroker->first_point); + if (unlikely (status)) + return status; + + if (stroker->has_first_face && stroker->has_current_face) { + /* Join first and final faces of sub path */ + outer_close (stroker, &stroker->current_face, &stroker->first_face); + inner_close (stroker, &stroker->current_face, &stroker->first_face); + } else { + /* Cap the start and end of the sub path as needed */ + add_caps (stroker); + } + + stroker->has_sub_path = FALSE; + stroker->has_first_face = FALSE; + stroker->has_current_face = FALSE; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_int_status_t +_cairo_path_fixed_stroke_to_tristrip (const cairo_path_fixed_t *path, + const cairo_stroke_style_t*style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_tristrip_t *strip) +{ + struct stroker stroker; + cairo_int_status_t status; + int i; + + if (style->num_dashes) + return CAIRO_INT_STATUS_UNSUPPORTED; + + stroker.style = *style; + stroker.ctm = ctm; + stroker.ctm_inverse = ctm_inverse; + stroker.tolerance = tolerance; + + stroker.ctm_det_positive = + _cairo_matrix_compute_determinant (ctm) >= 0.0; + + status = _cairo_pen_init (&stroker.pen, + style->line_width / 2.0, + tolerance, ctm); + if (unlikely (status)) + return status; + + if (stroker.pen.num_vertices <= 1) + return CAIRO_INT_STATUS_NOTHING_TO_DO; + + stroker.has_current_face = FALSE; + stroker.has_first_face = FALSE; + stroker.has_sub_path = FALSE; + + stroker.has_limits = strip->num_limits > 0; + stroker.limit = strip->limits[0]; + for (i = 1; i < strip->num_limits; i++) + _cairo_box_add_box (&stroker.limit, &strip->limits[i]); + + stroker.strip = strip; + + status = _cairo_path_fixed_interpret (path, + move_to, + line_to, + curve_to, + close_path, + &stroker); + /* Cap the start and end of the final sub path as needed */ + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) + add_caps (&stroker); + + _cairo_pen_fini (&stroker.pen); + + return status; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-path-stroke.c b/local/recipes/libs/cairo/source/src/cairo-path-stroke.c new file mode 100644 index 0000000000..60f647eb7b --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-path-stroke.c @@ -0,0 +1,1494 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Chris Wilson + */ + +#define _DEFAULT_SOURCE /* for hypot() */ +#include "cairoint.h" + +#include "cairo-box-inline.h" +#include "cairo-boxes-private.h" +#include "cairo-error-private.h" +#include "cairo-path-fixed-private.h" +#include "cairo-slope-private.h" +#include "cairo-stroke-dash-private.h" +#include "cairo-traps-private.h" + +typedef struct cairo_stroker { + cairo_stroke_style_t style; + + const cairo_matrix_t *ctm; + const cairo_matrix_t *ctm_inverse; + double half_line_width; + double tolerance; + double spline_cusp_tolerance; + double ctm_determinant; + cairo_bool_t ctm_det_positive; + + void *closure; + cairo_status_t (*add_external_edge) (void *closure, + const cairo_point_t *p1, + const cairo_point_t *p2); + cairo_status_t (*add_triangle) (void *closure, + const cairo_point_t triangle[3]); + cairo_status_t (*add_triangle_fan) (void *closure, + const cairo_point_t *midpt, + const cairo_point_t *points, + int npoints); + cairo_status_t (*add_convex_quad) (void *closure, + const cairo_point_t quad[4]); + + cairo_pen_t pen; + + cairo_point_t current_point; + cairo_point_t first_point; + + cairo_bool_t has_initial_sub_path; + + cairo_bool_t has_current_face; + cairo_stroke_face_t current_face; + + cairo_bool_t has_first_face; + cairo_stroke_face_t first_face; + + cairo_stroker_dash_t dash; + + cairo_bool_t has_bounds; + cairo_box_t bounds; +} cairo_stroker_t; + +static void +_cairo_stroker_limit (cairo_stroker_t *stroker, + const cairo_path_fixed_t *path, + const cairo_box_t *boxes, + int num_boxes) +{ + double dx, dy; + cairo_fixed_t fdx, fdy; + + stroker->has_bounds = TRUE; + _cairo_boxes_get_extents (boxes, num_boxes, &stroker->bounds); + + /* Extend the bounds in each direction to account for the maximum area + * we might generate trapezoids, to capture line segments that are outside + * of the bounds but which might generate rendering that's within bounds. + */ + + _cairo_stroke_style_max_distance_from_path (&stroker->style, path, + stroker->ctm, &dx, &dy); + + fdx = _cairo_fixed_from_double (dx); + fdy = _cairo_fixed_from_double (dy); + + stroker->bounds.p1.x -= fdx; + stroker->bounds.p2.x += fdx; + + stroker->bounds.p1.y -= fdy; + stroker->bounds.p2.y += fdy; +} + +static cairo_status_t +_cairo_stroker_init (cairo_stroker_t *stroker, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + const cairo_box_t *limits, + int num_limits) +{ + cairo_status_t status; + + stroker->style = *stroke_style; + stroker->ctm = ctm; + stroker->ctm_inverse = ctm_inverse; + stroker->tolerance = tolerance; + stroker->half_line_width = stroke_style->line_width / 2.0; + + /* To test whether we need to join two segments of a spline using + * a round-join or a bevel-join, we can inspect the angle between the + * two segments. If the difference between the chord distance + * (half-line-width times the cosine of the bisection angle) and the + * half-line-width itself is greater than tolerance then we need to + * inject a point. + */ + stroker->spline_cusp_tolerance = 1 - tolerance / stroker->half_line_width; + stroker->spline_cusp_tolerance *= stroker->spline_cusp_tolerance; + stroker->spline_cusp_tolerance *= 2; + stroker->spline_cusp_tolerance -= 1; + + stroker->ctm_determinant = _cairo_matrix_compute_determinant (stroker->ctm); + stroker->ctm_det_positive = stroker->ctm_determinant >= 0.0; + + status = _cairo_pen_init (&stroker->pen, + stroker->half_line_width, tolerance, ctm); + if (unlikely (status)) + return status; + + stroker->has_current_face = FALSE; + stroker->has_first_face = FALSE; + stroker->has_initial_sub_path = FALSE; + + /* Coverity complains these may be unitialized. */ + memset (&stroker->current_face, 0, sizeof (cairo_stroke_face_t)); + memset (&stroker->first_face, 0, sizeof (cairo_stroke_face_t)); + + _cairo_stroker_dash_init (&stroker->dash, stroke_style); + + stroker->add_external_edge = NULL; + + stroker->has_bounds = FALSE; + if (num_limits) + _cairo_stroker_limit (stroker, path, limits, num_limits); + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_stroker_fini (cairo_stroker_t *stroker) +{ + _cairo_pen_fini (&stroker->pen); +} + +static void +_translate_point (cairo_point_t *point, const cairo_point_t *offset) +{ + point->x += offset->x; + point->y += offset->y; +} + +static int +_cairo_stroker_join_is_clockwise (const cairo_stroke_face_t *in, + const cairo_stroke_face_t *out) +{ + cairo_slope_t in_slope, out_slope; + + _cairo_slope_init (&in_slope, &in->point, &in->cw); + _cairo_slope_init (&out_slope, &out->point, &out->cw); + + return _cairo_slope_compare (&in_slope, &out_slope) < 0; +} + +/** + * _cairo_slope_compare_sgn: + * + * Return -1, 0 or 1 depending on the relative slopes of + * two lines. + **/ +static int +_cairo_slope_compare_sgn (double dx1, double dy1, double dx2, double dy2) +{ + double c = (dx1 * dy2 - dx2 * dy1); + + if (c > 0) return 1; + if (c < 0) return -1; + return 0; +} + +/* + * Construct a fan around the midpoint using the vertices from pen between + * inpt and outpt. + */ +static cairo_status_t +_tessellate_fan (cairo_stroker_t *stroker, + const cairo_slope_t *in_vector, + const cairo_slope_t *out_vector, + const cairo_point_t *midpt, + const cairo_point_t *inpt, + const cairo_point_t *outpt, + cairo_bool_t clockwise) +{ + cairo_point_t stack_points[64], *points = stack_points; + cairo_pen_t *pen = &stroker->pen; + int start, stop, num_points = 0; + cairo_status_t status; + + if (stroker->has_bounds && + ! _cairo_box_contains_point (&stroker->bounds, midpt)) + goto BEVEL; + + assert (stroker->pen.num_vertices); + + if (clockwise) { + _cairo_pen_find_active_ccw_vertices (pen, + in_vector, out_vector, + &start, &stop); + if (stroker->add_external_edge) { + cairo_point_t last; + last = *inpt; + while (start != stop) { + cairo_point_t p = *midpt; + _translate_point (&p, &pen->vertices[start].point); + + status = stroker->add_external_edge (stroker->closure, + &last, &p); + if (unlikely (status)) + return status; + last = p; + + if (start-- == 0) + start += pen->num_vertices; + } + status = stroker->add_external_edge (stroker->closure, + &last, outpt); + } else { + if (start == stop) + goto BEVEL; + + num_points = stop - start; + if (num_points < 0) + num_points += pen->num_vertices; + num_points += 2; + if (num_points > ARRAY_LENGTH(stack_points)) { + points = _cairo_malloc_ab (num_points, sizeof (cairo_point_t)); + if (unlikely (points == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + points[0] = *inpt; + num_points = 1; + while (start != stop) { + points[num_points] = *midpt; + _translate_point (&points[num_points], &pen->vertices[start].point); + num_points++; + + if (start-- == 0) + start += pen->num_vertices; + } + points[num_points++] = *outpt; + } + } else { + _cairo_pen_find_active_cw_vertices (pen, + in_vector, out_vector, + &start, &stop); + if (stroker->add_external_edge) { + cairo_point_t last; + last = *inpt; + while (start != stop) { + cairo_point_t p = *midpt; + _translate_point (&p, &pen->vertices[start].point); + + status = stroker->add_external_edge (stroker->closure, + &p, &last); + if (unlikely (status)) + return status; + last = p; + + if (++start == pen->num_vertices) + start = 0; + } + status = stroker->add_external_edge (stroker->closure, + outpt, &last); + } else { + if (start == stop) + goto BEVEL; + + num_points = stop - start; + if (num_points < 0) + num_points += pen->num_vertices; + num_points += 2; + if (num_points > ARRAY_LENGTH(stack_points)) { + points = _cairo_malloc_ab (num_points, sizeof (cairo_point_t)); + if (unlikely (points == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + points[0] = *inpt; + num_points = 1; + while (start != stop) { + points[num_points] = *midpt; + _translate_point (&points[num_points], &pen->vertices[start].point); + num_points++; + + if (++start == pen->num_vertices) + start = 0; + } + points[num_points++] = *outpt; + } + } + + if (num_points) { + status = stroker->add_triangle_fan (stroker->closure, + midpt, points, num_points); + } + + if (points != stack_points) + free (points); + + return status; + +BEVEL: + /* Ensure a leak free connection... */ + if (stroker->add_external_edge != NULL) { + if (clockwise) + return stroker->add_external_edge (stroker->closure, inpt, outpt); + else + return stroker->add_external_edge (stroker->closure, outpt, inpt); + } else { + stack_points[0] = *midpt; + stack_points[1] = *inpt; + stack_points[2] = *outpt; + return stroker->add_triangle (stroker->closure, stack_points); + } +} + +static cairo_status_t +_cairo_stroker_join (cairo_stroker_t *stroker, + const cairo_stroke_face_t *in, + const cairo_stroke_face_t *out) +{ + int clockwise = _cairo_stroker_join_is_clockwise (out, in); + const cairo_point_t *inpt, *outpt; + cairo_point_t points[4]; + cairo_status_t status; + + if (in->cw.x == out->cw.x && in->cw.y == out->cw.y && + in->ccw.x == out->ccw.x && in->ccw.y == out->ccw.y) + { + return CAIRO_STATUS_SUCCESS; + } + + if (clockwise) { + if (stroker->add_external_edge != NULL) { + status = stroker->add_external_edge (stroker->closure, + &out->cw, &in->point); + if (unlikely (status)) + return status; + + status = stroker->add_external_edge (stroker->closure, + &in->point, &in->cw); + if (unlikely (status)) + return status; + } + + inpt = &in->ccw; + outpt = &out->ccw; + } else { + if (stroker->add_external_edge != NULL) { + status = stroker->add_external_edge (stroker->closure, + &in->ccw, &in->point); + if (unlikely (status)) + return status; + + status = stroker->add_external_edge (stroker->closure, + &in->point, &out->ccw); + if (unlikely (status)) + return status; + } + + inpt = &in->cw; + outpt = &out->cw; + } + + switch (stroker->style.line_join) { + case CAIRO_LINE_JOIN_ROUND: + /* construct a fan around the common midpoint */ + return _tessellate_fan (stroker, + &in->dev_vector, + &out->dev_vector, + &in->point, inpt, outpt, + clockwise); + + case CAIRO_LINE_JOIN_MITER: + default: { + /* dot product of incoming slope vector with outgoing slope vector */ + double in_dot_out = -in->usr_vector.x * out->usr_vector.x + + -in->usr_vector.y * out->usr_vector.y; + double ml = stroker->style.miter_limit; + + /* Check the miter limit -- lines meeting at an acute angle + * can generate long miters, the limit converts them to bevel + * + * Consider the miter join formed when two line segments + * meet at an angle psi: + * + * /.\ + * /. .\ + * /./ \.\ + * /./psi\.\ + * + * We can zoom in on the right half of that to see: + * + * |\ + * | \ psi/2 + * | \ + * | \ + * | \ + * | \ + * miter \ + * length \ + * | \ + * | .\ + * | . \ + * |. line \ + * \ width \ + * \ \ + * + * + * The right triangle in that figure, (the line-width side is + * shown faintly with three '.' characters), gives us the + * following expression relating miter length, angle and line + * width: + * + * 1 /sin (psi/2) = miter_length / line_width + * + * The right-hand side of this relationship is the same ratio + * in which the miter limit (ml) is expressed. We want to know + * when the miter length is within the miter limit. That is + * when the following condition holds: + * + * 1/sin(psi/2) <= ml + * 1 <= ml sin(psi/2) + * 1 <= ml² sin²(psi/2) + * 2 <= ml² 2 sin²(psi/2) + * 2·sin²(psi/2) = 1-cos(psi) + * 2 <= ml² (1-cos(psi)) + * + * in · out = |in| |out| cos (psi) + * + * in and out are both unit vectors, so: + * + * in · out = cos (psi) + * + * 2 <= ml² (1 - in · out) + * + */ + if (2 <= ml * ml * (1 - in_dot_out)) { + double x1, y1, x2, y2; + double mx, my; + double dx1, dx2, dy1, dy2; + double ix, iy; + double fdx1, fdy1, fdx2, fdy2; + double mdx, mdy; + + /* + * we've got the points already transformed to device + * space, but need to do some computation with them and + * also need to transform the slope from user space to + * device space + */ + /* outer point of incoming line face */ + x1 = _cairo_fixed_to_double (inpt->x); + y1 = _cairo_fixed_to_double (inpt->y); + dx1 = in->usr_vector.x; + dy1 = in->usr_vector.y; + cairo_matrix_transform_distance (stroker->ctm, &dx1, &dy1); + + /* outer point of outgoing line face */ + x2 = _cairo_fixed_to_double (outpt->x); + y2 = _cairo_fixed_to_double (outpt->y); + dx2 = out->usr_vector.x; + dy2 = out->usr_vector.y; + cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2); + + /* + * Compute the location of the outer corner of the miter. + * That's pretty easy -- just the intersection of the two + * outer edges. We've got slopes and points on each + * of those edges. Compute my directly, then compute + * mx by using the edge with the larger dy; that avoids + * dividing by values close to zero. + */ + my = (((x2 - x1) * dy1 * dy2 - y2 * dx2 * dy1 + y1 * dx1 * dy2) / + (dx1 * dy2 - dx2 * dy1)); + if (fabs (dy1) >= fabs (dy2)) + mx = (my - y1) * dx1 / dy1 + x1; + else + mx = (my - y2) * dx2 / dy2 + x2; + + /* + * When the two outer edges are nearly parallel, slight + * perturbations in the position of the outer points of the lines + * caused by representing them in fixed point form can cause the + * intersection point of the miter to move a large amount. If + * that moves the miter intersection from between the two faces, + * then draw a bevel instead. + */ + + ix = _cairo_fixed_to_double (in->point.x); + iy = _cairo_fixed_to_double (in->point.y); + + /* slope of one face */ + fdx1 = x1 - ix; fdy1 = y1 - iy; + + /* slope of the other face */ + fdx2 = x2 - ix; fdy2 = y2 - iy; + + /* slope from the intersection to the miter point */ + mdx = mx - ix; mdy = my - iy; + + /* + * Make sure the miter point line lies between the two + * faces by comparing the slopes + */ + if (_cairo_slope_compare_sgn (fdx1, fdy1, mdx, mdy) != + _cairo_slope_compare_sgn (fdx2, fdy2, mdx, mdy)) + { + if (stroker->add_external_edge != NULL) { + points[0].x = _cairo_fixed_from_double (mx); + points[0].y = _cairo_fixed_from_double (my); + + if (clockwise) { + status = stroker->add_external_edge (stroker->closure, + inpt, &points[0]); + if (unlikely (status)) + return status; + + status = stroker->add_external_edge (stroker->closure, + &points[0], outpt); + if (unlikely (status)) + return status; + } else { + status = stroker->add_external_edge (stroker->closure, + outpt, &points[0]); + if (unlikely (status)) + return status; + + status = stroker->add_external_edge (stroker->closure, + &points[0], inpt); + if (unlikely (status)) + return status; + } + + return CAIRO_STATUS_SUCCESS; + } else { + points[0] = in->point; + points[1] = *inpt; + points[2].x = _cairo_fixed_from_double (mx); + points[2].y = _cairo_fixed_from_double (my); + points[3] = *outpt; + + return stroker->add_convex_quad (stroker->closure, points); + } + } + } + } + + /* fall through ... */ + + case CAIRO_LINE_JOIN_BEVEL: + if (stroker->add_external_edge != NULL) { + if (clockwise) { + return stroker->add_external_edge (stroker->closure, + inpt, outpt); + } else { + return stroker->add_external_edge (stroker->closure, + outpt, inpt); + } + } else { + points[0] = in->point; + points[1] = *inpt; + points[2] = *outpt; + + return stroker->add_triangle (stroker->closure, points); + } + } +} + +static cairo_status_t +_cairo_stroker_add_cap (cairo_stroker_t *stroker, + const cairo_stroke_face_t *f) +{ + switch (stroker->style.line_cap) { + case CAIRO_LINE_CAP_ROUND: { + cairo_slope_t slope; + + slope.dx = -f->dev_vector.dx; + slope.dy = -f->dev_vector.dy; + + return _tessellate_fan (stroker, + &f->dev_vector, + &slope, + &f->point, &f->cw, &f->ccw, + FALSE); + + } + + case CAIRO_LINE_CAP_SQUARE: { + double dx, dy; + cairo_slope_t fvector; + cairo_point_t quad[4]; + + dx = f->usr_vector.x; + dy = f->usr_vector.y; + dx *= stroker->half_line_width; + dy *= stroker->half_line_width; + cairo_matrix_transform_distance (stroker->ctm, &dx, &dy); + fvector.dx = _cairo_fixed_from_double (dx); + fvector.dy = _cairo_fixed_from_double (dy); + + quad[0] = f->ccw; + quad[1].x = f->ccw.x + fvector.dx; + quad[1].y = f->ccw.y + fvector.dy; + quad[2].x = f->cw.x + fvector.dx; + quad[2].y = f->cw.y + fvector.dy; + quad[3] = f->cw; + + if (stroker->add_external_edge != NULL) { + cairo_status_t status; + + status = stroker->add_external_edge (stroker->closure, + &quad[0], &quad[1]); + if (unlikely (status)) + return status; + + status = stroker->add_external_edge (stroker->closure, + &quad[1], &quad[2]); + if (unlikely (status)) + return status; + + status = stroker->add_external_edge (stroker->closure, + &quad[2], &quad[3]); + if (unlikely (status)) + return status; + + return CAIRO_STATUS_SUCCESS; + } else { + return stroker->add_convex_quad (stroker->closure, quad); + } + } + + case CAIRO_LINE_CAP_BUTT: + default: + if (stroker->add_external_edge != NULL) { + return stroker->add_external_edge (stroker->closure, + &f->ccw, &f->cw); + } else { + return CAIRO_STATUS_SUCCESS; + } + } +} + +static cairo_status_t +_cairo_stroker_add_leading_cap (cairo_stroker_t *stroker, + const cairo_stroke_face_t *face) +{ + cairo_stroke_face_t reversed; + cairo_point_t t; + + reversed = *face; + + /* The initial cap needs an outward facing vector. Reverse everything */ + reversed.usr_vector.x = -reversed.usr_vector.x; + reversed.usr_vector.y = -reversed.usr_vector.y; + reversed.dev_vector.dx = -reversed.dev_vector.dx; + reversed.dev_vector.dy = -reversed.dev_vector.dy; + t = reversed.cw; + reversed.cw = reversed.ccw; + reversed.ccw = t; + + return _cairo_stroker_add_cap (stroker, &reversed); +} + +static cairo_status_t +_cairo_stroker_add_trailing_cap (cairo_stroker_t *stroker, + const cairo_stroke_face_t *face) +{ + return _cairo_stroker_add_cap (stroker, face); +} + +static inline cairo_bool_t +_compute_normalized_device_slope (double *dx, double *dy, + const cairo_matrix_t *ctm_inverse, + double *mag_out) +{ + double dx0 = *dx, dy0 = *dy; + double mag; + + cairo_matrix_transform_distance (ctm_inverse, &dx0, &dy0); + + if (dx0 == 0.0 && dy0 == 0.0) { + if (mag_out) + *mag_out = 0.0; + return FALSE; + } + + if (dx0 == 0.0) { + *dx = 0.0; + if (dy0 > 0.0) { + mag = dy0; + *dy = 1.0; + } else { + mag = -dy0; + *dy = -1.0; + } + } else if (dy0 == 0.0) { + *dy = 0.0; + if (dx0 > 0.0) { + mag = dx0; + *dx = 1.0; + } else { + mag = -dx0; + *dx = -1.0; + } + } else { + mag = hypot (dx0, dy0); + *dx = dx0 / mag; + *dy = dy0 / mag; + } + + if (mag_out) + *mag_out = mag; + + return TRUE; +} + +static void +_compute_face (const cairo_point_t *point, + const cairo_slope_t *dev_slope, + double slope_dx, + double slope_dy, + cairo_stroker_t *stroker, + cairo_stroke_face_t *face) +{ + double face_dx, face_dy; + cairo_point_t offset_ccw, offset_cw; + + /* + * rotate to get a line_width/2 vector along the face, note that + * the vector must be rotated the right direction in device space, + * but by 90° in user space. So, the rotation depends on + * whether the ctm reflects or not, and that can be determined + * by looking at the determinant of the matrix. + */ + if (stroker->ctm_det_positive) + { + face_dx = - slope_dy * stroker->half_line_width; + face_dy = slope_dx * stroker->half_line_width; + } + else + { + face_dx = slope_dy * stroker->half_line_width; + face_dy = - slope_dx * stroker->half_line_width; + } + + /* back to device space */ + cairo_matrix_transform_distance (stroker->ctm, &face_dx, &face_dy); + + offset_ccw.x = _cairo_fixed_from_double (face_dx); + offset_ccw.y = _cairo_fixed_from_double (face_dy); + offset_cw.x = -offset_ccw.x; + offset_cw.y = -offset_ccw.y; + + face->ccw = *point; + _translate_point (&face->ccw, &offset_ccw); + + face->point = *point; + + face->cw = *point; + _translate_point (&face->cw, &offset_cw); + + face->usr_vector.x = slope_dx; + face->usr_vector.y = slope_dy; + + face->dev_vector = *dev_slope; +} + +static cairo_status_t +_cairo_stroker_add_caps (cairo_stroker_t *stroker) +{ + cairo_status_t status; + + /* check for a degenerative sub_path */ + if (stroker->has_initial_sub_path + && ! stroker->has_first_face + && ! stroker->has_current_face + && stroker->style.line_cap == CAIRO_LINE_CAP_ROUND) + { + /* pick an arbitrary slope to use */ + double dx = 1.0, dy = 0.0; + cairo_slope_t slope = { CAIRO_FIXED_ONE, 0 }; + cairo_stroke_face_t face; + + _compute_normalized_device_slope (&dx, &dy, + stroker->ctm_inverse, NULL); + + /* arbitrarily choose first_point + * first_point and current_point should be the same */ + _compute_face (&stroker->first_point, &slope, dx, dy, stroker, &face); + + status = _cairo_stroker_add_leading_cap (stroker, &face); + if (unlikely (status)) + return status; + + status = _cairo_stroker_add_trailing_cap (stroker, &face); + if (unlikely (status)) + return status; + } + + if (stroker->has_first_face) { + status = _cairo_stroker_add_leading_cap (stroker, + &stroker->first_face); + if (unlikely (status)) + return status; + } + + if (stroker->has_current_face) { + status = _cairo_stroker_add_trailing_cap (stroker, + &stroker->current_face); + if (unlikely (status)) + return status; + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_stroker_add_sub_edge (cairo_stroker_t *stroker, + const cairo_point_t *p1, + const cairo_point_t *p2, + cairo_slope_t *dev_slope, + double slope_dx, double slope_dy, + cairo_stroke_face_t *start, + cairo_stroke_face_t *end) +{ + _compute_face (p1, dev_slope, slope_dx, slope_dy, stroker, start); + *end = *start; + + if (p1->x == p2->x && p1->y == p2->y) + return CAIRO_STATUS_SUCCESS; + + end->point = *p2; + end->ccw.x += p2->x - p1->x; + end->ccw.y += p2->y - p1->y; + end->cw.x += p2->x - p1->x; + end->cw.y += p2->y - p1->y; + + if (stroker->add_external_edge != NULL) { + cairo_status_t status; + + status = stroker->add_external_edge (stroker->closure, + &end->cw, &start->cw); + if (unlikely (status)) + return status; + + status = stroker->add_external_edge (stroker->closure, + &start->ccw, &end->ccw); + if (unlikely (status)) + return status; + + return CAIRO_STATUS_SUCCESS; + } else { + cairo_point_t quad[4]; + + quad[0] = start->cw; + quad[1] = end->cw; + quad[2] = end->ccw; + quad[3] = start->ccw; + + return stroker->add_convex_quad (stroker->closure, quad); + } +} + +static cairo_status_t +_cairo_stroker_move_to (void *closure, + const cairo_point_t *point) +{ + cairo_stroker_t *stroker = closure; + cairo_status_t status; + + /* reset the dash pattern for new sub paths */ + _cairo_stroker_dash_start (&stroker->dash); + + /* Cap the start and end of the previous sub path as needed */ + status = _cairo_stroker_add_caps (stroker); + if (unlikely (status)) + return status; + + stroker->first_point = *point; + stroker->current_point = *point; + + stroker->has_first_face = FALSE; + stroker->has_current_face = FALSE; + stroker->has_initial_sub_path = FALSE; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_stroker_line_to (void *closure, + const cairo_point_t *point) +{ + cairo_stroker_t *stroker = closure; + cairo_stroke_face_t start, end; + cairo_point_t *p1 = &stroker->current_point; + cairo_slope_t dev_slope; + double slope_dx, slope_dy; + cairo_status_t status; + + stroker->has_initial_sub_path = TRUE; + + if (p1->x == point->x && p1->y == point->y) + return CAIRO_STATUS_SUCCESS; + + _cairo_slope_init (&dev_slope, p1, point); + slope_dx = _cairo_fixed_to_double (point->x - p1->x); + slope_dy = _cairo_fixed_to_double (point->y - p1->y); + _compute_normalized_device_slope (&slope_dx, &slope_dy, + stroker->ctm_inverse, NULL); + + status = _cairo_stroker_add_sub_edge (stroker, + p1, point, + &dev_slope, + slope_dx, slope_dy, + &start, &end); + if (unlikely (status)) + return status; + + if (stroker->has_current_face) { + /* Join with final face from previous segment */ + status = _cairo_stroker_join (stroker, + &stroker->current_face, + &start); + if (unlikely (status)) + return status; + } else if (! stroker->has_first_face) { + /* Save sub path's first face in case needed for closing join */ + stroker->first_face = start; + stroker->has_first_face = TRUE; + } + stroker->current_face = end; + stroker->has_current_face = TRUE; + + stroker->current_point = *point; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_stroker_add_point_line_to (void *closure, + const cairo_point_t *point, + const cairo_slope_t *tangent) +{ + return _cairo_stroker_line_to (closure, point); +}; + +static cairo_status_t +_cairo_stroker_spline_to (void *closure, + const cairo_point_t *point, + const cairo_slope_t *tangent) +{ + cairo_stroker_t *stroker = closure; + cairo_stroke_face_t new_face; + double slope_dx, slope_dy; + cairo_point_t points[3]; + cairo_point_t intersect_point; + + stroker->has_initial_sub_path = TRUE; + + if (stroker->current_point.x == point->x && + stroker->current_point.y == point->y) + return CAIRO_STATUS_SUCCESS; + + slope_dx = _cairo_fixed_to_double (tangent->dx); + slope_dy = _cairo_fixed_to_double (tangent->dy); + + if (! _compute_normalized_device_slope (&slope_dx, &slope_dy, + stroker->ctm_inverse, NULL)) + return CAIRO_STATUS_SUCCESS; + + _compute_face (point, tangent, + slope_dx, slope_dy, + stroker, &new_face); + + assert (stroker->has_current_face); + + if ((new_face.dev_slope.x * stroker->current_face.dev_slope.x + + new_face.dev_slope.y * stroker->current_face.dev_slope.y) < stroker->spline_cusp_tolerance) { + + const cairo_point_t *inpt, *outpt; + int clockwise = _cairo_stroker_join_is_clockwise (&new_face, + &stroker->current_face); + + if (clockwise) { + inpt = &stroker->current_face.cw; + outpt = &new_face.cw; + } else { + inpt = &stroker->current_face.ccw; + outpt = &new_face.ccw; + } + + _tessellate_fan (stroker, + &stroker->current_face.dev_vector, + &new_face.dev_vector, + &stroker->current_face.point, + inpt, outpt, + clockwise); + } + + if (_slow_segment_intersection (&stroker->current_face.cw, + &stroker->current_face.ccw, + &new_face.cw, + &new_face.ccw, + &intersect_point)) { + points[0] = stroker->current_face.ccw; + points[1] = new_face.ccw; + points[2] = intersect_point; + stroker->add_triangle (stroker->closure, points); + + points[0] = stroker->current_face.cw; + points[1] = new_face.cw; + stroker->add_triangle (stroker->closure, points); + } else { + points[0] = stroker->current_face.ccw; + points[1] = stroker->current_face.cw; + points[2] = new_face.cw; + stroker->add_triangle (stroker->closure, points); + + points[0] = stroker->current_face.ccw; + points[1] = new_face.cw; + points[2] = new_face.ccw; + stroker->add_triangle (stroker->closure, points); + } + + stroker->current_face = new_face; + stroker->has_current_face = TRUE; + stroker->current_point = *point; + + return CAIRO_STATUS_SUCCESS; +} + +/* + * Dashed lines. Cap each dash end, join around turns when on + */ +static cairo_status_t +_cairo_stroker_line_to_dashed (void *closure, + const cairo_point_t *p2) +{ + cairo_stroker_t *stroker = closure; + double mag, remain, step_length = 0; + double slope_dx, slope_dy; + double dx2, dy2; + cairo_stroke_face_t sub_start, sub_end; + cairo_point_t *p1 = &stroker->current_point; + cairo_slope_t dev_slope; + cairo_line_t segment; + cairo_bool_t fully_in_bounds; + cairo_status_t status; + + stroker->has_initial_sub_path = stroker->dash.dash_starts_on; + + if (p1->x == p2->x && p1->y == p2->y) + return CAIRO_STATUS_SUCCESS; + + fully_in_bounds = TRUE; + if (stroker->has_bounds && + (! _cairo_box_contains_point (&stroker->bounds, p1) || + ! _cairo_box_contains_point (&stroker->bounds, p2))) + { + fully_in_bounds = FALSE; + } + + _cairo_slope_init (&dev_slope, p1, p2); + + slope_dx = _cairo_fixed_to_double (p2->x - p1->x); + slope_dy = _cairo_fixed_to_double (p2->y - p1->y); + + if (! _compute_normalized_device_slope (&slope_dx, &slope_dy, + stroker->ctm_inverse, &mag)) + { + return CAIRO_STATUS_SUCCESS; + } + + remain = mag; + segment.p1 = *p1; + while (remain) { + step_length = MIN (stroker->dash.dash_remain, remain); + remain -= step_length; + dx2 = slope_dx * (mag - remain); + dy2 = slope_dy * (mag - remain); + cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2); + segment.p2.x = _cairo_fixed_from_double (dx2) + p1->x; + segment.p2.y = _cairo_fixed_from_double (dy2) + p1->y; + + if (stroker->dash.dash_on && + (fully_in_bounds || + (! stroker->has_first_face && stroker->dash.dash_starts_on) || + _cairo_box_intersects_line_segment (&stroker->bounds, &segment))) + { + status = _cairo_stroker_add_sub_edge (stroker, + &segment.p1, &segment.p2, + &dev_slope, + slope_dx, slope_dy, + &sub_start, &sub_end); + if (unlikely (status)) + return status; + + if (stroker->has_current_face) + { + /* Join with final face from previous segment */ + status = _cairo_stroker_join (stroker, + &stroker->current_face, + &sub_start); + if (unlikely (status)) + return status; + + stroker->has_current_face = FALSE; + } + else if (! stroker->has_first_face && + stroker->dash.dash_starts_on) + { + /* Save sub path's first face in case needed for closing join */ + stroker->first_face = sub_start; + stroker->has_first_face = TRUE; + } + else + { + /* Cap dash start if not connecting to a previous segment */ + status = _cairo_stroker_add_leading_cap (stroker, &sub_start); + if (unlikely (status)) + return status; + } + + if (remain) { + /* Cap dash end if not at end of segment */ + status = _cairo_stroker_add_trailing_cap (stroker, &sub_end); + if (unlikely (status)) + return status; + } else { + stroker->current_face = sub_end; + stroker->has_current_face = TRUE; + } + } else { + if (stroker->has_current_face) { + /* Cap final face from previous segment */ + status = _cairo_stroker_add_trailing_cap (stroker, + &stroker->current_face); + if (unlikely (status)) + return status; + + stroker->has_current_face = FALSE; + } + } + + _cairo_stroker_dash_step (&stroker->dash, step_length); + segment.p1 = segment.p2; + } + + if (stroker->dash.dash_on && ! stroker->has_current_face) { + /* This segment ends on a transition to dash_on, compute a new face + * and add cap for the beginning of the next dash_on step. + * + * Note: this will create a degenerate cap if this is not the last line + * in the path. Whether this behaviour is desirable or not is debatable. + * On one side these degenerate caps can not be reproduced with regular + * path stroking. + * On the other hand, Acroread 7 also produces the degenerate caps. + */ + _compute_face (p2, &dev_slope, + slope_dx, slope_dy, + stroker, + &stroker->current_face); + + status = _cairo_stroker_add_leading_cap (stroker, + &stroker->current_face); + if (unlikely (status)) + return status; + + stroker->has_current_face = TRUE; + } + + stroker->current_point = *p2; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_stroker_add_point_line_to_dashed (void *closure, + const cairo_point_t *point, + const cairo_slope_t *tangent) +{ + return _cairo_stroker_line_to_dashed (closure, point); +}; + +static cairo_status_t +_cairo_stroker_curve_to (void *closure, + const cairo_point_t *b, + const cairo_point_t *c, + const cairo_point_t *d) +{ + cairo_stroker_t *stroker = closure; + cairo_spline_t spline; + cairo_line_join_t line_join_save; + cairo_stroke_face_t face; + double slope_dx, slope_dy; + cairo_spline_add_point_func_t line_to; + cairo_spline_add_point_func_t spline_to; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + line_to = stroker->dash.dashed ? + _cairo_stroker_add_point_line_to_dashed : + _cairo_stroker_add_point_line_to; + + /* spline_to is only capable of rendering non-degenerate splines. */ + spline_to = stroker->dash.dashed ? + _cairo_stroker_add_point_line_to_dashed : + _cairo_stroker_spline_to; + + if (! _cairo_spline_init (&spline, + spline_to, + stroker, + &stroker->current_point, b, c, d)) + { + cairo_slope_t fallback_slope; + _cairo_slope_init (&fallback_slope, &stroker->current_point, d); + return line_to (closure, d, &fallback_slope); + } + + /* If the line width is so small that the pen is reduced to a + single point, then we have nothing to do. */ + if (stroker->pen.num_vertices <= 1) + return CAIRO_STATUS_SUCCESS; + + /* Compute the initial face */ + if (! stroker->dash.dashed || stroker->dash.dash_on) { + slope_dx = _cairo_fixed_to_double (spline.initial_slope.dx); + slope_dy = _cairo_fixed_to_double (spline.initial_slope.dy); + if (_compute_normalized_device_slope (&slope_dx, &slope_dy, + stroker->ctm_inverse, NULL)) + { + _compute_face (&stroker->current_point, + &spline.initial_slope, + slope_dx, slope_dy, + stroker, &face); + } + if (stroker->has_current_face) { + status = _cairo_stroker_join (stroker, + &stroker->current_face, &face); + if (unlikely (status)) + return status; + } else if (! stroker->has_first_face) { + stroker->first_face = face; + stroker->has_first_face = TRUE; + } + + stroker->current_face = face; + stroker->has_current_face = TRUE; + } + + /* Temporarily modify the stroker to use round joins to guarantee + * smooth stroked curves. */ + line_join_save = stroker->style.line_join; + stroker->style.line_join = CAIRO_LINE_JOIN_ROUND; + + status = _cairo_spline_decompose (&spline, stroker->tolerance); + if (unlikely (status)) + return status; + + /* And join the final face */ + if (! stroker->dash.dashed || stroker->dash.dash_on) { + slope_dx = _cairo_fixed_to_double (spline.final_slope.dx); + slope_dy = _cairo_fixed_to_double (spline.final_slope.dy); + if (_compute_normalized_device_slope (&slope_dx, &slope_dy, + stroker->ctm_inverse, NULL)) + { + _compute_face (&stroker->current_point, + &spline.final_slope, + slope_dx, slope_dy, + stroker, &face); + } + + status = _cairo_stroker_join (stroker, &stroker->current_face, &face); + if (unlikely (status)) + return status; + + stroker->current_face = face; + } + + stroker->style.line_join = line_join_save; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_stroker_close_path (void *closure) +{ + cairo_stroker_t *stroker = closure; + cairo_status_t status; + + if (stroker->dash.dashed) + status = _cairo_stroker_line_to_dashed (stroker, &stroker->first_point); + else + status = _cairo_stroker_line_to (stroker, &stroker->first_point); + if (unlikely (status)) + return status; + + if (stroker->has_first_face && stroker->has_current_face) { + /* Join first and final faces of sub path */ + status = _cairo_stroker_join (stroker, + &stroker->current_face, + &stroker->first_face); + if (unlikely (status)) + return status; + } else { + /* Cap the start and end of the sub path as needed */ + status = _cairo_stroker_add_caps (stroker); + if (unlikely (status)) + return status; + } + + stroker->has_initial_sub_path = FALSE; + stroker->has_first_face = FALSE; + stroker->has_current_face = FALSE; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_path_fixed_stroke_to_shaper (cairo_path_fixed_t *path, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_status_t (*add_triangle) (void *closure, + const cairo_point_t triangle[3]), + cairo_status_t (*add_triangle_fan) (void *closure, + const cairo_point_t *midpt, + const cairo_point_t *points, + int npoints), + cairo_status_t (*add_convex_quad) (void *closure, + const cairo_point_t quad[4]), + void *closure) +{ + cairo_stroker_t stroker; + cairo_status_t status; + + status = _cairo_stroker_init (&stroker, path, stroke_style, + ctm, ctm_inverse, tolerance, + NULL, 0); + if (unlikely (status)) + return status; + + stroker.add_triangle = add_triangle; + stroker.add_triangle_fan = add_triangle_fan; + stroker.add_convex_quad = add_convex_quad; + stroker.closure = closure; + + status = _cairo_path_fixed_interpret (path, + _cairo_stroker_move_to, + stroker.dash.dashed ? + _cairo_stroker_line_to_dashed : + _cairo_stroker_line_to, + _cairo_stroker_curve_to, + _cairo_stroker_close_path, + &stroker); + + if (unlikely (status)) + goto BAIL; + + /* Cap the start and end of the final sub path as needed */ + status = _cairo_stroker_add_caps (&stroker); + +BAIL: + _cairo_stroker_fini (&stroker); + + return status; +} + +cairo_status_t +_cairo_path_fixed_stroke_dashed_to_polygon (const cairo_path_fixed_t *path, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_polygon_t *polygon) +{ + cairo_stroker_t stroker; + cairo_status_t status; + + status = _cairo_stroker_init (&stroker, path, stroke_style, + ctm, ctm_inverse, tolerance, + polygon->limits, polygon->num_limits); + if (unlikely (status)) + return status; + + stroker.add_external_edge = _cairo_polygon_add_external_edge, + stroker.closure = polygon; + + status = _cairo_path_fixed_interpret (path, + _cairo_stroker_move_to, + stroker.dash.dashed ? + _cairo_stroker_line_to_dashed : + _cairo_stroker_line_to, + _cairo_stroker_curve_to, + _cairo_stroker_close_path, + &stroker); + + if (unlikely (status)) + goto BAIL; + + /* Cap the start and end of the final sub path as needed */ + status = _cairo_stroker_add_caps (&stroker); + +BAIL: + _cairo_stroker_fini (&stroker); + + return status; +} + +cairo_int_status_t +_cairo_path_fixed_stroke_polygon_to_traps (const cairo_path_fixed_t *path, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_traps_t *traps) +{ + cairo_int_status_t status; + cairo_polygon_t polygon; + + _cairo_polygon_init (&polygon, traps->limits, traps->num_limits); + status = _cairo_path_fixed_stroke_to_polygon (path, + stroke_style, + ctm, + ctm_inverse, + tolerance, + &polygon); + if (unlikely (status)) + goto BAIL; + + status = _cairo_polygon_status (&polygon); + if (unlikely (status)) + goto BAIL; + + status = _cairo_bentley_ottmann_tessellate_polygon (traps, &polygon, + CAIRO_FILL_RULE_WINDING); + +BAIL: + _cairo_polygon_fini (&polygon); + + return status; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-path.c b/local/recipes/libs/cairo/source/src/cairo-path.c new file mode 100644 index 0000000000..6f7a9cef0e --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-path.c @@ -0,0 +1,478 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2006 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Carl D. Worth + */ + +#include "cairoint.h" + +#include "cairo-private.h" +#include "cairo-backend-private.h" +#include "cairo-error-private.h" +#include "cairo-path-private.h" +#include "cairo-path-fixed-private.h" + +/** + * SECTION:cairo-paths + * @Title: Paths + * @Short_Description: Creating paths and manipulating path data + * + * Paths are the most basic drawing tools and are primarily used to implicitly + * generate simple masks. + **/ + +static const cairo_path_t _cairo_path_nil = { CAIRO_STATUS_NO_MEMORY, NULL, 0 }; + +/* Closure for path interpretation. */ +typedef struct cairo_path_count { + int count; +} cpc_t; + +static cairo_status_t +_cpc_move_to (void *closure, + const cairo_point_t *point) +{ + cpc_t *cpc = closure; + + cpc->count += 2; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cpc_line_to (void *closure, + const cairo_point_t *point) +{ + cpc_t *cpc = closure; + + cpc->count += 2; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cpc_curve_to (void *closure, + const cairo_point_t *p1, + const cairo_point_t *p2, + const cairo_point_t *p3) +{ + cpc_t *cpc = closure; + + cpc->count += 4; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cpc_close_path (void *closure) +{ + cpc_t *cpc = closure; + + cpc->count += 1; + + return CAIRO_STATUS_SUCCESS; +} + +static int +_cairo_path_count (cairo_path_t *path, + cairo_path_fixed_t *path_fixed, + double tolerance, + cairo_bool_t flatten) +{ + cairo_status_t status; + cpc_t cpc; + + cpc.count = 0; + + if (flatten) { + status = _cairo_path_fixed_interpret_flat (path_fixed, + _cpc_move_to, + _cpc_line_to, + _cpc_close_path, + &cpc, + tolerance); + } else { + status = _cairo_path_fixed_interpret (path_fixed, + _cpc_move_to, + _cpc_line_to, + _cpc_curve_to, + _cpc_close_path, + &cpc); + } + + if (unlikely (status)) + return -1; + + return cpc.count; +} + +/* Closure for path interpretation. */ +typedef struct cairo_path_populate { + cairo_path_data_t *data; + cairo_t *cr; +} cpp_t; + +static cairo_status_t +_cpp_move_to (void *closure, + const cairo_point_t *point) +{ + cpp_t *cpp = closure; + cairo_path_data_t *data = cpp->data; + double x, y; + + x = _cairo_fixed_to_double (point->x); + y = _cairo_fixed_to_double (point->y); + + _cairo_backend_to_user (cpp->cr, &x, &y); + + data->header.type = CAIRO_PATH_MOVE_TO; + data->header.length = 2; + + /* We index from 1 to leave room for data->header */ + data[1].point.x = x; + data[1].point.y = y; + + cpp->data += data->header.length; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cpp_line_to (void *closure, + const cairo_point_t *point) +{ + cpp_t *cpp = closure; + cairo_path_data_t *data = cpp->data; + double x, y; + + x = _cairo_fixed_to_double (point->x); + y = _cairo_fixed_to_double (point->y); + + _cairo_backend_to_user (cpp->cr, &x, &y); + + data->header.type = CAIRO_PATH_LINE_TO; + data->header.length = 2; + + /* We index from 1 to leave room for data->header */ + data[1].point.x = x; + data[1].point.y = y; + + cpp->data += data->header.length; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cpp_curve_to (void *closure, + const cairo_point_t *p1, + const cairo_point_t *p2, + const cairo_point_t *p3) +{ + cpp_t *cpp = closure; + cairo_path_data_t *data = cpp->data; + double x1, y1; + double x2, y2; + double x3, y3; + + x1 = _cairo_fixed_to_double (p1->x); + y1 = _cairo_fixed_to_double (p1->y); + _cairo_backend_to_user (cpp->cr, &x1, &y1); + + x2 = _cairo_fixed_to_double (p2->x); + y2 = _cairo_fixed_to_double (p2->y); + _cairo_backend_to_user (cpp->cr, &x2, &y2); + + x3 = _cairo_fixed_to_double (p3->x); + y3 = _cairo_fixed_to_double (p3->y); + _cairo_backend_to_user (cpp->cr, &x3, &y3); + + data->header.type = CAIRO_PATH_CURVE_TO; + data->header.length = 4; + + /* We index from 1 to leave room for data->header */ + data[1].point.x = x1; + data[1].point.y = y1; + + data[2].point.x = x2; + data[2].point.y = y2; + + data[3].point.x = x3; + data[3].point.y = y3; + + cpp->data += data->header.length; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cpp_close_path (void *closure) +{ + cpp_t *cpp = closure; + cairo_path_data_t *data = cpp->data; + + data->header.type = CAIRO_PATH_CLOSE_PATH; + data->header.length = 1; + + cpp->data += data->header.length; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_path_populate (cairo_path_t *path, + cairo_path_fixed_t *path_fixed, + cairo_t *cr, + cairo_bool_t flatten) +{ + cairo_status_t status; + cpp_t cpp; + + cpp.data = path->data; + cpp.cr = cr; + + if (flatten) { + status = _cairo_path_fixed_interpret_flat (path_fixed, + _cpp_move_to, + _cpp_line_to, + _cpp_close_path, + &cpp, + cairo_get_tolerance (cr)); + } else { + status = _cairo_path_fixed_interpret (path_fixed, + _cpp_move_to, + _cpp_line_to, + _cpp_curve_to, + _cpp_close_path, + &cpp); + } + + if (unlikely (status)) + return status; + + /* Sanity check the count */ + assert (cpp.data - path->data == path->num_data); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_path_t * +_cairo_path_create_in_error (cairo_status_t status) +{ + cairo_path_t *path; + + /* special case NO_MEMORY so as to avoid allocations */ + if (status == CAIRO_STATUS_NO_MEMORY) + return (cairo_path_t*) &_cairo_path_nil; + + path = _cairo_calloc (sizeof (cairo_path_t)); + if (unlikely (path == NULL)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_path_t*) &_cairo_path_nil; + } + + path->num_data = 0; + path->data = NULL; + path->status = status; + + return path; +} + +static cairo_path_t * +_cairo_path_create_internal (cairo_path_fixed_t *path_fixed, + cairo_t *cr, + cairo_bool_t flatten) +{ + cairo_path_t *path; + + path = _cairo_calloc (sizeof (cairo_path_t)); + if (unlikely (path == NULL)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_path_t*) &_cairo_path_nil; + } + + path->num_data = _cairo_path_count (path, path_fixed, + cairo_get_tolerance (cr), + flatten); + if (path->num_data < 0) { + free (path); + return (cairo_path_t*) &_cairo_path_nil; + } + + if (path->num_data) { + path->data = _cairo_malloc_ab (path->num_data, + sizeof (cairo_path_data_t)); + if (unlikely (path->data == NULL)) { + free (path); + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_path_t*) &_cairo_path_nil; + } + + path->status = _cairo_path_populate (path, path_fixed, cr, flatten); + } else { + path->data = NULL; + path->status = CAIRO_STATUS_SUCCESS; + } + + return path; +} + +/** + * cairo_path_destroy: + * @path: a path previously returned by either cairo_copy_path() or + * cairo_copy_path_flat(). + * + * Immediately releases all memory associated with @path. After a call + * to cairo_path_destroy() the @path pointer is no longer valid and + * should not be used further. + * + * Note: cairo_path_destroy() should only be called with a + * pointer to a #cairo_path_t returned by a cairo function. Any path + * that is created manually (ie. outside of cairo) should be destroyed + * manually as well. + * + * Since: 1.0 + **/ +void +cairo_path_destroy (cairo_path_t *path) +{ + if (path == NULL || path == &_cairo_path_nil) + return; + + free (path->data); + + free (path); +} + +/** + * _cairo_path_create: + * @path: a fixed-point, device-space path to be converted and copied + * @cr: the current graphics context + * + * Creates a user-space #cairo_path_t copy of the given device-space + * @path. The @cr parameter provides the inverse CTM for the + * conversion. + * + * Return value: the new copy of the path. If there is insufficient + * memory a pointer to a special static nil #cairo_path_t will be + * returned instead with status==%CAIRO_STATUS_NO_MEMORY and + * data==%NULL. + **/ +cairo_path_t * +_cairo_path_create (cairo_path_fixed_t *path, + cairo_t *cr) +{ + return _cairo_path_create_internal (path, cr, FALSE); +} + +/** + * _cairo_path_create_flat: + * @path: a fixed-point, device-space path to be flattened, converted and copied + * @cr: the current graphics context + * + * Creates a flattened, user-space #cairo_path_t copy of the given + * device-space @path. The @cr parameter provide the inverse CTM + * for the conversion, as well as the tolerance value to control the + * accuracy of the flattening. + * + * Return value: the flattened copy of the path. If there is insufficient + * memory a pointer to a special static nil #cairo_path_t will be + * returned instead with status==%CAIRO_STATUS_NO_MEMORY and + * data==%NULL. + **/ +cairo_path_t * +_cairo_path_create_flat (cairo_path_fixed_t *path, + cairo_t *cr) +{ + return _cairo_path_create_internal (path, cr, TRUE); +} + +/** + * _cairo_path_append_to_context: + * @path: the path data to be appended + * @cr: a cairo context + * + * Append @path to the current path within @cr. + * + * Return value: %CAIRO_STATUS_INVALID_PATH_DATA if the data in @path + * is invalid, and %CAIRO_STATUS_SUCCESS otherwise. + **/ +cairo_status_t +_cairo_path_append_to_context (const cairo_path_t *path, + cairo_t *cr) +{ + const cairo_path_data_t *p, *end; + + end = &path->data[path->num_data]; + for (p = &path->data[0]; p < end; p += p->header.length) { + switch (p->header.type) { + case CAIRO_PATH_MOVE_TO: + if (unlikely (p->header.length < 2)) + return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA); + + cairo_move_to (cr, p[1].point.x, p[1].point.y); + break; + + case CAIRO_PATH_LINE_TO: + if (unlikely (p->header.length < 2)) + return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA); + + cairo_line_to (cr, p[1].point.x, p[1].point.y); + break; + + case CAIRO_PATH_CURVE_TO: + if (unlikely (p->header.length < 4)) + return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA); + + cairo_curve_to (cr, + p[1].point.x, p[1].point.y, + p[2].point.x, p[2].point.y, + p[3].point.x, p[3].point.y); + break; + + case CAIRO_PATH_CLOSE_PATH: + if (unlikely (p->header.length < 1)) + return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA); + + cairo_close_path (cr); + break; + + default: + return _cairo_error (CAIRO_STATUS_INVALID_PATH_DATA); + } + + if (unlikely (cr->status)) + return cr->status; + } + + return CAIRO_STATUS_SUCCESS; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-pattern-inline.h b/local/recipes/libs/cairo/source/src/cairo-pattern-inline.h new file mode 100644 index 0000000000..97e8ea034e --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-pattern-inline.h @@ -0,0 +1,65 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Carl D. Worth + */ + +#ifndef CAIRO_PATTERN_INLINE_H +#define CAIRO_PATTERN_INLINE_H + +#include "cairo-pattern-private.h" + +#include "cairo-list-inline.h" + +CAIRO_BEGIN_DECLS + +static inline void +_cairo_pattern_add_observer (cairo_pattern_t *pattern, + cairo_pattern_observer_t *observer, + void (*func) (cairo_pattern_observer_t *, + cairo_pattern_t *, + unsigned int)) +{ + observer->notify = func; + cairo_list_add (&observer->link, &pattern->observers); +} + +static inline cairo_surface_t * +_cairo_pattern_get_source (const cairo_surface_pattern_t *pattern, + cairo_rectangle_int_t *extents) +{ + return _cairo_surface_get_source (pattern->surface, extents); +} + +CAIRO_END_DECLS + +#endif /* CAIRO_PATTERN_INLINE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-pattern-private.h b/local/recipes/libs/cairo/source/src/cairo-pattern-private.h new file mode 100644 index 0000000000..0e69d01776 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-pattern-private.h @@ -0,0 +1,387 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Carl D. Worth + */ + +#ifndef CAIRO_PATTERN_PRIVATE_H +#define CAIRO_PATTERN_PRIVATE_H + +#include "cairo-error-private.h" +#include "cairo-types-private.h" +#include "cairo-list-private.h" +#include "cairo-surface-private.h" + +#include /* FILE* */ + +CAIRO_BEGIN_DECLS + +typedef struct _cairo_pattern_observer cairo_pattern_observer_t; + +enum { + CAIRO_PATTERN_NOTIFY_MATRIX = 0x1, + CAIRO_PATTERN_NOTIFY_FILTER = 0x2, + CAIRO_PATTERN_NOTIFY_EXTEND = 0x4, + CAIRO_PATTERN_NOTIFY_OPACITY = 0x9, + CAIRO_PATTERN_NOTIFY_DITHER = 0x12, +}; + +struct _cairo_pattern_observer { + void (*notify) (cairo_pattern_observer_t *, + cairo_pattern_t *pattern, + unsigned int flags); + cairo_list_t link; +}; + +struct _cairo_pattern { + cairo_reference_count_t ref_count; + cairo_status_t status; + cairo_user_data_array_t user_data; + cairo_list_t observers; + + cairo_pattern_type_t type; + + cairo_filter_t filter; + cairo_extend_t extend; + cairo_bool_t has_component_alpha; + cairo_bool_t is_foreground_marker; + cairo_dither_t dither; + + cairo_matrix_t matrix; + double opacity; +}; + +struct _cairo_solid_pattern { + cairo_pattern_t base; + cairo_color_t color; +}; + +typedef struct _cairo_surface_pattern { + cairo_pattern_t base; + + cairo_surface_t *surface; + + /* This field is only used by the wrapper surface for retreiving + * the region id from the target during create regions and passing + * the region id to the target surface during playback. + */ + unsigned int region_array_id; +} cairo_surface_pattern_t; + +typedef struct _cairo_gradient_stop { + double offset; + cairo_color_stop_t color; +} cairo_gradient_stop_t; + +typedef struct _cairo_gradient_pattern { + cairo_pattern_t base; + + unsigned int n_stops; + unsigned int stops_size; + cairo_gradient_stop_t *stops; + cairo_gradient_stop_t stops_embedded[2]; +} cairo_gradient_pattern_t; + +typedef struct _cairo_linear_pattern { + cairo_gradient_pattern_t base; + + cairo_point_double_t pd1; + cairo_point_double_t pd2; +} cairo_linear_pattern_t; + +typedef struct _cairo_radial_pattern { + cairo_gradient_pattern_t base; + + cairo_circle_double_t cd1; + cairo_circle_double_t cd2; +} cairo_radial_pattern_t; + +typedef union { + cairo_gradient_pattern_t base; + + cairo_linear_pattern_t linear; + cairo_radial_pattern_t radial; +} cairo_gradient_pattern_union_t; + +/* + * A mesh patch is a tensor-product patch (bicubic Bezier surface + * patch). It has 16 control points. Each set of 4 points along the + * sides of the 4x4 grid of control points is a Bezier curve that + * defines one side of the patch. A color is assigned to each + * corner. The inner 4 points provide additional control over the + * shape and the color mapping. + * + * Cairo uses the same convention as the PDF Reference for numbering + * the points and side of the patch. + * + * + * Side 1 + * + * p[0][3] p[1][3] p[2][3] p[3][3] + * Side 0 p[0][2] p[1][2] p[2][2] p[3][2] Side 2 + * p[0][1] p[1][1] p[2][1] p[3][1] + * p[0][0] p[1][0] p[2][0] p[3][0] + * + * Side 3 + * + * + * Point Color + * ------------------------- + * points[0][0] colors[0] + * points[0][3] colors[1] + * points[3][3] colors[2] + * points[3][0] colors[3] + */ + +typedef struct _cairo_mesh_patch { + cairo_point_double_t points[4][4]; + cairo_color_t colors[4]; +} cairo_mesh_patch_t; + +typedef struct _cairo_mesh_pattern { + cairo_pattern_t base; + + cairo_array_t patches; + cairo_mesh_patch_t *current_patch; + int current_side; + cairo_bool_t has_control_point[4]; + cairo_bool_t has_color[4]; +} cairo_mesh_pattern_t; + +typedef struct _cairo_raster_source_pattern { + cairo_pattern_t base; + + cairo_content_t content; + cairo_rectangle_int_t extents; + + cairo_raster_source_acquire_func_t acquire; + cairo_raster_source_release_func_t release; + cairo_raster_source_snapshot_func_t snapshot; + cairo_raster_source_copy_func_t copy; + cairo_raster_source_finish_func_t finish; + + /* an explicit pre-allocated member in preference to the general user-data */ + void *user_data; +} cairo_raster_source_pattern_t; + +typedef union { + cairo_pattern_t base; + + cairo_solid_pattern_t solid; + cairo_surface_pattern_t surface; + cairo_gradient_pattern_union_t gradient; + cairo_mesh_pattern_t mesh; + cairo_raster_source_pattern_t raster_source; +} cairo_pattern_union_t; + +/* cairo-pattern.c */ + +cairo_private cairo_pattern_t * +_cairo_pattern_create_in_error (cairo_status_t status); + +cairo_private cairo_status_t +_cairo_pattern_create_copy (cairo_pattern_t **pattern, + const cairo_pattern_t *other); + +cairo_private void +_cairo_pattern_init (cairo_pattern_t *pattern, + cairo_pattern_type_t type); + +cairo_private cairo_status_t +_cairo_pattern_init_copy (cairo_pattern_t *pattern, + const cairo_pattern_t *other); + +cairo_private void +_cairo_pattern_init_static_copy (cairo_pattern_t *pattern, + const cairo_pattern_t *other); + +cairo_private cairo_status_t +_cairo_pattern_init_snapshot (cairo_pattern_t *pattern, + const cairo_pattern_t *other); + +cairo_private void +_cairo_pattern_init_solid (cairo_solid_pattern_t *pattern, + const cairo_color_t *color); + +cairo_private void +_cairo_pattern_init_for_surface (cairo_surface_pattern_t *pattern, + cairo_surface_t *surface); + +cairo_private void +_cairo_pattern_fini (cairo_pattern_t *pattern); + +cairo_private cairo_pattern_t * +_cairo_pattern_create_solid (const cairo_color_t *color); + +cairo_private cairo_pattern_t * +_cairo_pattern_create_foreground_marker (void); + +cairo_private void +_cairo_pattern_transform (cairo_pattern_t *pattern, + const cairo_matrix_t *ctm_inverse); + +cairo_private void +_cairo_pattern_pretransform (cairo_pattern_t *pattern, + const cairo_matrix_t *ctm); + +cairo_private cairo_bool_t +_cairo_pattern_is_opaque_solid (const cairo_pattern_t *pattern); + +cairo_private cairo_bool_t +_cairo_pattern_is_opaque (const cairo_pattern_t *pattern, + const cairo_rectangle_int_t *extents); + +cairo_private cairo_bool_t +_cairo_pattern_is_clear (const cairo_pattern_t *pattern); + +cairo_private cairo_bool_t +_cairo_gradient_pattern_is_solid (const cairo_gradient_pattern_t *gradient, + const cairo_rectangle_int_t *extents, + cairo_color_t *color); + +cairo_private cairo_bool_t +_cairo_pattern_is_constant_alpha (const cairo_pattern_t *abstract_pattern, + const cairo_rectangle_int_t *extents, + double *alpha); + +cairo_private void +_cairo_gradient_pattern_fit_to_range (const cairo_gradient_pattern_t *gradient, + double max_value, + cairo_matrix_t *out_matrix, + cairo_circle_double_t out_circle[2]); + +cairo_private cairo_bool_t +_cairo_radial_pattern_focus_is_inside (const cairo_radial_pattern_t *radial); + +cairo_private void +_cairo_gradient_pattern_box_to_parameter (const cairo_gradient_pattern_t *gradient, + double x0, double y0, + double x1, double y1, + double tolerance, + double out_range[2]); + +cairo_private void +_cairo_gradient_pattern_interpolate (const cairo_gradient_pattern_t *gradient, + double t, + cairo_circle_double_t *out_circle); + +cairo_private void +_cairo_pattern_alpha_range (const cairo_pattern_t *pattern, + double *out_min, + double *out_max); + +cairo_private cairo_bool_t +_cairo_mesh_pattern_coord_box (const cairo_mesh_pattern_t *mesh, + double *out_xmin, + double *out_ymin, + double *out_xmax, + double *out_ymax); + +cairo_private void +_cairo_pattern_sampled_area (const cairo_pattern_t *pattern, + const cairo_rectangle_int_t *extents, + cairo_rectangle_int_t *sample); + +cairo_private void +_cairo_pattern_get_extents (const cairo_pattern_t *pattern, + cairo_rectangle_int_t *extents, + cairo_bool_t is_vector); + +cairo_private cairo_int_status_t +_cairo_pattern_get_ink_extents (const cairo_pattern_t *pattern, + cairo_rectangle_int_t *extents); + +cairo_private uintptr_t +_cairo_pattern_hash (const cairo_pattern_t *pattern); + +cairo_private uintptr_t +_cairo_linear_pattern_hash (uintptr_t hash, + const cairo_linear_pattern_t *linear); + +cairo_private uintptr_t +_cairo_radial_pattern_hash (uintptr_t hash, + const cairo_radial_pattern_t *radial); + +cairo_private cairo_bool_t +_cairo_linear_pattern_equal (const cairo_linear_pattern_t *a, + const cairo_linear_pattern_t *b); + +cairo_private unsigned long +_cairo_pattern_size (const cairo_pattern_t *pattern); + +cairo_private cairo_bool_t +_cairo_radial_pattern_equal (const cairo_radial_pattern_t *a, + const cairo_radial_pattern_t *b); + +cairo_private cairo_bool_t +_cairo_pattern_equal (const cairo_pattern_t *a, + const cairo_pattern_t *b); + +cairo_private cairo_filter_t +_cairo_pattern_analyze_filter (const cairo_pattern_t *pattern); + +/* cairo-mesh-pattern-rasterizer.c */ + +cairo_private void +_cairo_mesh_pattern_rasterize (const cairo_mesh_pattern_t *mesh, + void *data, + int width, + int height, + int stride, + double x_offset, + double y_offset); + +cairo_private cairo_surface_t * +_cairo_raster_source_pattern_acquire (const cairo_pattern_t *abstract_pattern, + cairo_surface_t *target, + const cairo_rectangle_int_t *extents); + +cairo_private void +_cairo_raster_source_pattern_release (const cairo_pattern_t *abstract_pattern, + cairo_surface_t *surface); + +cairo_private cairo_status_t +_cairo_raster_source_pattern_snapshot (cairo_pattern_t *abstract_pattern); + +cairo_private cairo_status_t +_cairo_raster_source_pattern_init_copy (cairo_pattern_t *pattern, + const cairo_pattern_t *other); + +cairo_private void +_cairo_raster_source_pattern_finish (cairo_pattern_t *abstract_pattern); + +cairo_private void +_cairo_debug_print_pattern (FILE *file, const cairo_pattern_t *pattern); + +CAIRO_END_DECLS + +#endif /* CAIRO_PATTERN_PRIVATE */ diff --git a/local/recipes/libs/cairo/source/src/cairo-pattern.c b/local/recipes/libs/cairo/source/src/cairo-pattern.c new file mode 100644 index 0000000000..4d713e6c65 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-pattern.c @@ -0,0 +1,4857 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2004 David Reveman + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of David + * Reveman not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. David Reveman makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL DAVID REVEMAN BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: David Reveman + * Keith Packard + * Carl Worth + */ + +#include "cairoint.h" + +#include "cairo-array-private.h" +#include "cairo-error-private.h" +#include "cairo-freed-pool-private.h" +#include "cairo-image-surface-private.h" +#include "cairo-list-inline.h" +#include "cairo-path-private.h" +#include "cairo-pattern-private.h" +#include "cairo-recording-surface-inline.h" +#include "cairo-surface-snapshot-inline.h" + +#include + +#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */ + +/** + * SECTION:cairo-pattern + * @Title: cairo_pattern_t + * @Short_Description: Sources for drawing + * @See_Also: #cairo_t, #cairo_surface_t + * + * #cairo_pattern_t is the paint with which cairo draws. + * The primary use of patterns is as the source for all cairo drawing + * operations, although they can also be used as masks, that is, as the + * brush too. + * + * A cairo pattern is created by using one of the many constructors, + * of the form + * cairo_pattern_create_type() + * or implicitly through + * cairo_set_source_type() + * functions. + **/ + +/** + * CAIRO_HAS_MIME_SURFACE: + * + * Unused symbol, always defined. + * + * Since: 1.12 + **/ + +static freed_pool_t freed_pattern_pool[5]; + +static const cairo_solid_pattern_t _cairo_pattern_nil = { + { + CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ + CAIRO_STATUS_NO_MEMORY, /* status */ + { 0, 0, 0, NULL }, /* user_data */ + { NULL, NULL }, /* observers */ + + CAIRO_PATTERN_TYPE_SOLID, /* type */ + CAIRO_FILTER_DEFAULT, /* filter */ + CAIRO_EXTEND_GRADIENT_DEFAULT, /* extend */ + FALSE, /* has component alpha */ + FALSE, /* is_foreground_marker */ + CAIRO_DITHER_DEFAULT, /* dither */ + { 1., 0., 0., 1., 0., 0., }, /* matrix */ + 1.0 /* opacity */ + } +}; + +static const cairo_solid_pattern_t _cairo_pattern_nil_null_pointer = { + { + CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ + CAIRO_STATUS_NULL_POINTER, /* status */ + { 0, 0, 0, NULL }, /* user_data */ + { NULL, NULL }, /* observers */ + + CAIRO_PATTERN_TYPE_SOLID, /* type */ + CAIRO_FILTER_DEFAULT, /* filter */ + CAIRO_EXTEND_GRADIENT_DEFAULT, /* extend */ + FALSE, /* has component alpha */ + FALSE, /* is_foreground_marker */ + CAIRO_DITHER_DEFAULT, /* dither */ + { 1., 0., 0., 1., 0., 0., }, /* matrix */ + 1.0 /* opacity */ + } +}; + +const cairo_solid_pattern_t _cairo_pattern_black = { + { + CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ + CAIRO_STATUS_SUCCESS, /* status */ + { 0, 0, 0, NULL }, /* user_data */ + { NULL, NULL }, /* observers */ + + CAIRO_PATTERN_TYPE_SOLID, /* type */ + CAIRO_FILTER_NEAREST, /* filter */ + CAIRO_EXTEND_REPEAT, /* extend */ + FALSE, /* has component alpha */ + FALSE, /* is_foreground_marker */ + CAIRO_DITHER_DEFAULT, /* dither */ + { 1., 0., 0., 1., 0., 0., }, /* matrix */ + 1.0 /* opacity */ + }, + { 0., 0., 0., 1., 0, 0, 0, 0xffff },/* color (double rgba, short rgba) */ +}; + +const cairo_solid_pattern_t _cairo_pattern_clear = { + { + CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ + CAIRO_STATUS_SUCCESS, /* status */ + { 0, 0, 0, NULL }, /* user_data */ + { NULL, NULL }, /* observers */ + + CAIRO_PATTERN_TYPE_SOLID, /* type */ + CAIRO_FILTER_NEAREST, /* filter */ + CAIRO_EXTEND_REPEAT, /* extend */ + FALSE, /* has component alpha */ + FALSE, /* is_foreground_marker */ + CAIRO_DITHER_DEFAULT, /* dither */ + { 1., 0., 0., 1., 0., 0., }, /* matrix */ + 1.0 /* opacity */ + }, + { 0., 0., 0., 0., 0, 0, 0, 0 },/* color (double rgba, short rgba) */ +}; + +const cairo_solid_pattern_t _cairo_pattern_white = { + { + CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ + CAIRO_STATUS_SUCCESS, /* status */ + { 0, 0, 0, NULL }, /* user_data */ + { NULL, NULL }, /* observers */ + + CAIRO_PATTERN_TYPE_SOLID, /* type */ + CAIRO_FILTER_NEAREST, /* filter */ + CAIRO_EXTEND_REPEAT, /* extend */ + FALSE, /* has component alpha */ + FALSE, /* is_foreground_marker */ + CAIRO_DITHER_DEFAULT, /* dither */ + { 1., 0., 0., 1., 0., 0., }, /* matrix */ + 1.0 /* opacity */ + }, + { 1., 1., 1., 1., 0xffff, 0xffff, 0xffff, 0xffff },/* color (double rgba, short rgba) */ +}; + +static void +_cairo_pattern_notify_observers (cairo_pattern_t *pattern, + unsigned int flags) +{ + cairo_pattern_observer_t *pos; + + cairo_list_foreach_entry (pos, cairo_pattern_observer_t, &pattern->observers, link) + pos->notify (pos, pattern, flags); +} + +/** + * _cairo_pattern_set_error: + * @pattern: a pattern + * @status: a status value indicating an error + * + * Atomically sets pattern->status to @status and calls _cairo_error; + * Does nothing if status is %CAIRO_STATUS_SUCCESS. + * + * All assignments of an error status to pattern->status should happen + * through _cairo_pattern_set_error(). Note that due to the nature of + * the atomic operation, it is not safe to call this function on the nil + * objects. + * + * The purpose of this function is to allow the user to set a + * breakpoint in _cairo_error() to generate a stack trace for when the + * user causes cairo to detect an error. + **/ +static cairo_status_t +_cairo_pattern_set_error (cairo_pattern_t *pattern, + cairo_status_t status) +{ + if (status == CAIRO_STATUS_SUCCESS) + return status; + + /* Don't overwrite an existing error. This preserves the first + * error, which is the most significant. */ + _cairo_status_set_error (&pattern->status, status); + + return _cairo_error (status); +} + +void +_cairo_pattern_init (cairo_pattern_t *pattern, cairo_pattern_type_t type) +{ +#if HAVE_VALGRIND + switch (type) { + case CAIRO_PATTERN_TYPE_SOLID: + VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_solid_pattern_t)); + break; + case CAIRO_PATTERN_TYPE_SURFACE: + VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_surface_pattern_t)); + break; + case CAIRO_PATTERN_TYPE_LINEAR: + VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_linear_pattern_t)); + break; + case CAIRO_PATTERN_TYPE_RADIAL: + VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_radial_pattern_t)); + break; + case CAIRO_PATTERN_TYPE_MESH: + VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_mesh_pattern_t)); + break; + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + break; + } +#endif + + pattern->type = type; + pattern->status = CAIRO_STATUS_SUCCESS; + + /* Set the reference count to zero for on-stack patterns. + * Callers needs to explicitly increment the count for heap allocations. */ + CAIRO_REFERENCE_COUNT_INIT (&pattern->ref_count, 0); + + _cairo_user_data_array_init (&pattern->user_data); + + if (type == CAIRO_PATTERN_TYPE_SURFACE || + type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) + pattern->extend = CAIRO_EXTEND_SURFACE_DEFAULT; + else + pattern->extend = CAIRO_EXTEND_GRADIENT_DEFAULT; + + pattern->filter = CAIRO_FILTER_DEFAULT; + pattern->opacity = 1.0; + + pattern->has_component_alpha = FALSE; + pattern->is_foreground_marker = FALSE; + + pattern->dither = CAIRO_DITHER_DEFAULT; + + cairo_matrix_init_identity (&pattern->matrix); + + cairo_list_init (&pattern->observers); +} + +static cairo_status_t +_cairo_gradient_pattern_init_copy (cairo_gradient_pattern_t *pattern, + const cairo_gradient_pattern_t *other) +{ + if (CAIRO_INJECT_FAULT ()) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + if (other->base.type == CAIRO_PATTERN_TYPE_LINEAR) + { + cairo_linear_pattern_t *dst = (cairo_linear_pattern_t *) pattern; + cairo_linear_pattern_t *src = (cairo_linear_pattern_t *) other; + + *dst = *src; + } + else + { + cairo_radial_pattern_t *dst = (cairo_radial_pattern_t *) pattern; + cairo_radial_pattern_t *src = (cairo_radial_pattern_t *) other; + + *dst = *src; + } + + if (other->stops == other->stops_embedded) + pattern->stops = pattern->stops_embedded; + else if (other->stops) + { + pattern->stops = _cairo_malloc_ab (other->stops_size, + sizeof (cairo_gradient_stop_t)); + if (unlikely (pattern->stops == NULL)) { + pattern->stops_size = 0; + pattern->n_stops = 0; + return _cairo_pattern_set_error (&pattern->base, CAIRO_STATUS_NO_MEMORY); + } + + memcpy (pattern->stops, other->stops, + other->n_stops * sizeof (cairo_gradient_stop_t)); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_mesh_pattern_init_copy (cairo_mesh_pattern_t *pattern, + const cairo_mesh_pattern_t *other) +{ + *pattern = *other; + + _cairo_array_init (&pattern->patches, sizeof (cairo_mesh_patch_t)); + return _cairo_array_append_multiple (&pattern->patches, + _cairo_array_index_const (&other->patches, 0), + _cairo_array_num_elements (&other->patches)); +} + +cairo_status_t +_cairo_pattern_init_copy (cairo_pattern_t *pattern, + const cairo_pattern_t *other) +{ + cairo_status_t status; + + if (other->status) + return _cairo_pattern_set_error (pattern, other->status); + + switch (other->type) { + case CAIRO_PATTERN_TYPE_SOLID: { + cairo_solid_pattern_t *dst = (cairo_solid_pattern_t *) pattern; + cairo_solid_pattern_t *src = (cairo_solid_pattern_t *) other; + + VG (VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_solid_pattern_t))); + + *dst = *src; + } break; + case CAIRO_PATTERN_TYPE_SURFACE: { + cairo_surface_pattern_t *dst = (cairo_surface_pattern_t *) pattern; + cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) other; + + VG (VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_surface_pattern_t))); + + *dst = *src; + cairo_surface_reference (dst->surface); + } break; + case CAIRO_PATTERN_TYPE_LINEAR: + case CAIRO_PATTERN_TYPE_RADIAL: { + cairo_gradient_pattern_t *dst = (cairo_gradient_pattern_t *) pattern; + cairo_gradient_pattern_t *src = (cairo_gradient_pattern_t *) other; + + if (other->type == CAIRO_PATTERN_TYPE_LINEAR) { + VG (VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_linear_pattern_t))); + } else { + VG (VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_radial_pattern_t))); + } + + status = _cairo_gradient_pattern_init_copy (dst, src); + if (unlikely (status)) + return status; + + } break; + case CAIRO_PATTERN_TYPE_MESH: { + cairo_mesh_pattern_t *dst = (cairo_mesh_pattern_t *) pattern; + cairo_mesh_pattern_t *src = (cairo_mesh_pattern_t *) other; + + VG (VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_mesh_pattern_t))); + + status = _cairo_mesh_pattern_init_copy (dst, src); + if (unlikely (status)) + return status; + + } break; + + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: { + status = _cairo_raster_source_pattern_init_copy (pattern, other); + if (unlikely (status)) + return status; + } break; + } + + /* The reference count and user_data array are unique to the copy. */ + CAIRO_REFERENCE_COUNT_INIT (&pattern->ref_count, 0); + _cairo_user_data_array_init (&pattern->user_data); + cairo_list_init (&pattern->observers); + + return CAIRO_STATUS_SUCCESS; +} + +void +_cairo_pattern_init_static_copy (cairo_pattern_t *pattern, + const cairo_pattern_t *other) +{ + int size; + + assert (other->status == CAIRO_STATUS_SUCCESS); + + switch (other->type) { + default: + ASSERT_NOT_REACHED; + case CAIRO_PATTERN_TYPE_SOLID: + size = sizeof (cairo_solid_pattern_t); + break; + case CAIRO_PATTERN_TYPE_SURFACE: + size = sizeof (cairo_surface_pattern_t); + break; + case CAIRO_PATTERN_TYPE_LINEAR: + size = sizeof (cairo_linear_pattern_t); + break; + case CAIRO_PATTERN_TYPE_RADIAL: + size = sizeof (cairo_radial_pattern_t); + break; + case CAIRO_PATTERN_TYPE_MESH: + size = sizeof (cairo_mesh_pattern_t); + break; + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + size = sizeof (cairo_raster_source_pattern_t); + break; + } + + memcpy (pattern, other, size); + + CAIRO_REFERENCE_COUNT_INIT (&pattern->ref_count, 0); + _cairo_user_data_array_init (&pattern->user_data); + cairo_list_init (&pattern->observers); +} + +cairo_status_t +_cairo_pattern_init_snapshot (cairo_pattern_t *pattern, + const cairo_pattern_t *other) +{ + cairo_status_t status; + + /* We don't bother doing any fancy copy-on-write implementation + * for the pattern's data. It's generally quite tiny. */ + status = _cairo_pattern_init_copy (pattern, other); + if (unlikely (status)) + return status; + + /* But we do let the surface snapshot stuff be as fancy as it + * would like to be. */ + if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { + cairo_surface_pattern_t *surface_pattern = + (cairo_surface_pattern_t *) pattern; + cairo_surface_t *surface = surface_pattern->surface; + + surface_pattern->surface = _cairo_surface_snapshot (surface); + + cairo_surface_destroy (surface); + + status = surface_pattern->surface->status; + } else if (pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) + status = _cairo_raster_source_pattern_snapshot (pattern); + + return status; +} + +void +_cairo_pattern_fini (cairo_pattern_t *pattern) +{ + _cairo_user_data_array_fini (&pattern->user_data); + + switch (pattern->type) { + case CAIRO_PATTERN_TYPE_SOLID: + break; + case CAIRO_PATTERN_TYPE_SURFACE: { + cairo_surface_pattern_t *surface_pattern = + (cairo_surface_pattern_t *) pattern; + + cairo_surface_destroy (surface_pattern->surface); + } break; + case CAIRO_PATTERN_TYPE_LINEAR: + case CAIRO_PATTERN_TYPE_RADIAL: { + cairo_gradient_pattern_t *gradient = + (cairo_gradient_pattern_t *) pattern; + + if (gradient->stops && gradient->stops != gradient->stops_embedded) + free (gradient->stops); + } break; + case CAIRO_PATTERN_TYPE_MESH: { + cairo_mesh_pattern_t *mesh = + (cairo_mesh_pattern_t *) pattern; + + _cairo_array_fini (&mesh->patches); + } break; + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + _cairo_raster_source_pattern_finish (pattern); + break; + } + +#if HAVE_VALGRIND + switch (pattern->type) { + case CAIRO_PATTERN_TYPE_SOLID: + VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_solid_pattern_t)); + break; + case CAIRO_PATTERN_TYPE_SURFACE: + VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_surface_pattern_t)); + break; + case CAIRO_PATTERN_TYPE_LINEAR: + VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_linear_pattern_t)); + break; + case CAIRO_PATTERN_TYPE_RADIAL: + VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_radial_pattern_t)); + break; + case CAIRO_PATTERN_TYPE_MESH: + VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_mesh_pattern_t)); + break; + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + break; + } +#endif +} + +cairo_status_t +_cairo_pattern_create_copy (cairo_pattern_t **pattern_out, + const cairo_pattern_t *other) +{ + cairo_pattern_t *pattern; + cairo_status_t status; + + if (other->status) + return other->status; + + switch (other->type) { + case CAIRO_PATTERN_TYPE_SOLID: + pattern = _cairo_malloc (sizeof (cairo_solid_pattern_t)); + break; + case CAIRO_PATTERN_TYPE_SURFACE: + pattern = _cairo_malloc (sizeof (cairo_surface_pattern_t)); + break; + case CAIRO_PATTERN_TYPE_LINEAR: + pattern = _cairo_malloc (sizeof (cairo_linear_pattern_t)); + break; + case CAIRO_PATTERN_TYPE_RADIAL: + pattern = _cairo_malloc (sizeof (cairo_radial_pattern_t)); + break; + case CAIRO_PATTERN_TYPE_MESH: + pattern = _cairo_malloc (sizeof (cairo_mesh_pattern_t)); + break; + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + pattern = _cairo_malloc (sizeof (cairo_raster_source_pattern_t)); + break; + default: + ASSERT_NOT_REACHED; + return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH); + } + if (unlikely (pattern == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + status = _cairo_pattern_init_copy (pattern, other); + if (unlikely (status)) { + free (pattern); + return status; + } + + CAIRO_REFERENCE_COUNT_INIT (&pattern->ref_count, 1); + *pattern_out = pattern; + return CAIRO_STATUS_SUCCESS; +} + +void +_cairo_pattern_init_solid (cairo_solid_pattern_t *pattern, + const cairo_color_t *color) +{ + _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_TYPE_SOLID); + pattern->color = *color; +} + +void +_cairo_pattern_init_for_surface (cairo_surface_pattern_t *pattern, + cairo_surface_t *surface) +{ + if (surface->status) { + /* Force to solid to simplify the pattern_fini process. */ + _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_TYPE_SOLID); + _cairo_pattern_set_error (&pattern->base, surface->status); + return; + } + + _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_TYPE_SURFACE); + + pattern->surface = cairo_surface_reference (surface); + pattern->region_array_id = 0; +} + +static void +_cairo_pattern_init_gradient (cairo_gradient_pattern_t *pattern, + cairo_pattern_type_t type) +{ + _cairo_pattern_init (&pattern->base, type); + + pattern->n_stops = 0; + pattern->stops_size = 0; + pattern->stops = NULL; +} + +static void +_cairo_pattern_init_linear (cairo_linear_pattern_t *pattern, + double x0, double y0, double x1, double y1) +{ + _cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_TYPE_LINEAR); + + pattern->pd1.x = x0; + pattern->pd1.y = y0; + pattern->pd2.x = x1; + pattern->pd2.y = y1; +} + +static void +_cairo_pattern_init_radial (cairo_radial_pattern_t *pattern, + double cx0, double cy0, double radius0, + double cx1, double cy1, double radius1) +{ + _cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_TYPE_RADIAL); + + pattern->cd1.center.x = cx0; + pattern->cd1.center.y = cy0; + pattern->cd1.radius = fabs (radius0); + pattern->cd2.center.x = cx1; + pattern->cd2.center.y = cy1; + pattern->cd2.radius = fabs (radius1); +} + +cairo_pattern_t * +_cairo_pattern_create_solid (const cairo_color_t *color) +{ + cairo_solid_pattern_t *pattern; + + pattern = + _freed_pool_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_SOLID]); + if (unlikely (pattern == NULL)) { + /* None cached, need to create a new pattern. */ + pattern = _cairo_calloc (sizeof (cairo_solid_pattern_t)); + if (unlikely (pattern == NULL)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_pattern_t *) &_cairo_pattern_nil; + } + } + + _cairo_pattern_init_solid (pattern, color); + CAIRO_REFERENCE_COUNT_INIT (&pattern->base.ref_count, 1); + + return &pattern->base; +} + +cairo_pattern_t * +_cairo_pattern_create_foreground_marker (void) +{ + cairo_pattern_t *pattern = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK); + pattern->is_foreground_marker = TRUE; + return pattern; +} + +cairo_pattern_t * +_cairo_pattern_create_in_error (cairo_status_t status) +{ + cairo_pattern_t *pattern; + + if (status == CAIRO_STATUS_NO_MEMORY) + return (cairo_pattern_t *)&_cairo_pattern_nil.base; + + CAIRO_MUTEX_INITIALIZE (); + + pattern = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK); + if (pattern->status == CAIRO_STATUS_SUCCESS) + status = _cairo_pattern_set_error (pattern, status); + + return pattern; +} + +/** + * cairo_pattern_create_rgb: + * @red: red component of the color + * @green: green component of the color + * @blue: blue component of the color + * + * Creates a new #cairo_pattern_t corresponding to an opaque color. The + * color components are floating point numbers in the range 0 to 1. + * If the values passed in are outside that range, they will be + * clamped. + * + * Return value: the newly created #cairo_pattern_t if successful, or + * an error pattern in case of no memory. The caller owns the + * returned object and should call cairo_pattern_destroy() when + * finished with it. + * + * This function will always return a valid pointer, but if an error + * occurred the pattern status will be set to an error. To inspect + * the status of a pattern use cairo_pattern_status(). + * + * Since: 1.0 + **/ +cairo_pattern_t * +cairo_pattern_create_rgb (double red, double green, double blue) +{ + return cairo_pattern_create_rgba (red, green, blue, 1.0); +} + +/** + * cairo_pattern_create_rgba: + * @red: red component of the color + * @green: green component of the color + * @blue: blue component of the color + * @alpha: alpha component of the color + * + * Creates a new #cairo_pattern_t corresponding to a translucent color. + * The color components are floating point numbers in the range 0 to + * 1. If the values passed in are outside that range, they will be + * clamped. + * + * The color is specified in the same way as in cairo_set_source_rgb(). + * + * Return value: the newly created #cairo_pattern_t if successful, or + * an error pattern in case of no memory. The caller owns the + * returned object and should call cairo_pattern_destroy() when + * finished with it. + * + * This function will always return a valid pointer, but if an error + * occurred the pattern status will be set to an error. To inspect + * the status of a pattern use cairo_pattern_status(). + * + * Since: 1.0 + **/ +cairo_pattern_t * +cairo_pattern_create_rgba (double red, double green, double blue, + double alpha) +{ + cairo_color_t color; + + red = _cairo_restrict_value (red, 0.0, 1.0); + green = _cairo_restrict_value (green, 0.0, 1.0); + blue = _cairo_restrict_value (blue, 0.0, 1.0); + alpha = _cairo_restrict_value (alpha, 0.0, 1.0); + + _cairo_color_init_rgba (&color, red, green, blue, alpha); + + CAIRO_MUTEX_INITIALIZE (); + + return _cairo_pattern_create_solid (&color); +} + +/** + * cairo_pattern_create_for_surface: + * @surface: the surface + * + * Create a new #cairo_pattern_t for the given surface. + * + * Return value: the newly created #cairo_pattern_t if successful, or + * an error pattern in case of no memory. The caller owns the + * returned object and should call cairo_pattern_destroy() when + * finished with it. + * + * This function will always return a valid pointer, but if an error + * occurred the pattern status will be set to an error. To inspect + * the status of a pattern use cairo_pattern_status(). + * + * Since: 1.0 + **/ +cairo_pattern_t * +cairo_pattern_create_for_surface (cairo_surface_t *surface) +{ + cairo_surface_pattern_t *pattern; + + if (surface == NULL) { + _cairo_error_throw (CAIRO_STATUS_NULL_POINTER); + return (cairo_pattern_t*) &_cairo_pattern_nil_null_pointer; + } + + if (surface->status) + return _cairo_pattern_create_in_error (surface->status); + + pattern = + _freed_pool_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_SURFACE]); + if (unlikely (pattern == NULL)) { + pattern = _cairo_calloc (sizeof (cairo_surface_pattern_t)); + if (unlikely (pattern == NULL)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_pattern_t *)&_cairo_pattern_nil.base; + } + } + + CAIRO_MUTEX_INITIALIZE (); + + _cairo_pattern_init_for_surface (pattern, surface); + CAIRO_REFERENCE_COUNT_INIT (&pattern->base.ref_count, 1); + + return &pattern->base; +} + +/** + * cairo_pattern_create_linear: + * @x0: x coordinate of the start point + * @y0: y coordinate of the start point + * @x1: x coordinate of the end point + * @y1: y coordinate of the end point + * + * Create a new linear gradient #cairo_pattern_t along the line defined + * by (x0, y0) and (x1, y1). Before using the gradient pattern, a + * number of color stops should be defined using + * cairo_pattern_add_color_stop_rgb() or + * cairo_pattern_add_color_stop_rgba(). + * + * Note: The coordinates here are in pattern space. For a new pattern, + * pattern space is identical to user space, but the relationship + * between the spaces can be changed with cairo_pattern_set_matrix(). + * + * Return value: the newly created #cairo_pattern_t if successful, or + * an error pattern in case of no memory. The caller owns the + * returned object and should call cairo_pattern_destroy() when + * finished with it. + * + * This function will always return a valid pointer, but if an error + * occurred the pattern status will be set to an error. To inspect + * the status of a pattern use cairo_pattern_status(). + * + * Since: 1.0 + **/ +cairo_pattern_t * +cairo_pattern_create_linear (double x0, double y0, double x1, double y1) +{ + cairo_linear_pattern_t *pattern; + + pattern = + _freed_pool_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_LINEAR]); + if (unlikely (pattern == NULL)) { + pattern = _cairo_calloc (sizeof (cairo_linear_pattern_t)); + if (unlikely (pattern == NULL)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_pattern_t *) &_cairo_pattern_nil.base; + } + } + + CAIRO_MUTEX_INITIALIZE (); + + _cairo_pattern_init_linear (pattern, x0, y0, x1, y1); + CAIRO_REFERENCE_COUNT_INIT (&pattern->base.base.ref_count, 1); + + return &pattern->base.base; +} + +/** + * cairo_pattern_create_radial: + * @cx0: x coordinate for the center of the start circle + * @cy0: y coordinate for the center of the start circle + * @radius0: radius of the start circle + * @cx1: x coordinate for the center of the end circle + * @cy1: y coordinate for the center of the end circle + * @radius1: radius of the end circle + * + * Creates a new radial gradient #cairo_pattern_t between the two + * circles defined by (cx0, cy0, radius0) and (cx1, cy1, radius1). Before using the + * gradient pattern, a number of color stops should be defined using + * cairo_pattern_add_color_stop_rgb() or + * cairo_pattern_add_color_stop_rgba(). + * + * Note: The coordinates here are in pattern space. For a new pattern, + * pattern space is identical to user space, but the relationship + * between the spaces can be changed with cairo_pattern_set_matrix(). + * + * Return value: the newly created #cairo_pattern_t if successful, or + * an error pattern in case of no memory. The caller owns the + * returned object and should call cairo_pattern_destroy() when + * finished with it. + * + * This function will always return a valid pointer, but if an error + * occurred the pattern status will be set to an error. To inspect + * the status of a pattern use cairo_pattern_status(). + * + * Since: 1.0 + **/ +cairo_pattern_t * +cairo_pattern_create_radial (double cx0, double cy0, double radius0, + double cx1, double cy1, double radius1) +{ + cairo_radial_pattern_t *pattern; + + pattern = + _freed_pool_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_RADIAL]); + if (unlikely (pattern == NULL)) { + pattern = _cairo_calloc (sizeof (cairo_radial_pattern_t)); + if (unlikely (pattern == NULL)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_pattern_t *) &_cairo_pattern_nil.base; + } + } + + CAIRO_MUTEX_INITIALIZE (); + + _cairo_pattern_init_radial (pattern, cx0, cy0, radius0, cx1, cy1, radius1); + CAIRO_REFERENCE_COUNT_INIT (&pattern->base.base.ref_count, 1); + + return &pattern->base.base; +} + +/* This order is specified in the diagram in the documentation for + * cairo_pattern_create_mesh() */ +static const int mesh_path_point_i[12] = { 0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 2, 1 }; +static const int mesh_path_point_j[12] = { 0, 1, 2, 3, 3, 3, 3, 2, 1, 0, 0, 0 }; +static const int mesh_control_point_i[4] = { 1, 1, 2, 2 }; +static const int mesh_control_point_j[4] = { 1, 2, 2, 1 }; + +/** + * cairo_pattern_create_mesh: + * + * Create a new mesh pattern. + * + * Mesh patterns are tensor-product patch meshes (type 7 shadings in + * PDF). Mesh patterns may also be used to create other types of + * shadings that are special cases of tensor-product patch meshes such + * as Coons patch meshes (type 6 shading in PDF) and Gouraud-shaded + * triangle meshes (type 4 and 5 shadings in PDF). + * + * Mesh patterns consist of one or more tensor-product patches, which + * should be defined before using the mesh pattern. Using a mesh + * pattern with a partially defined patch as source or mask will put + * the context in an error status with a status of + * %CAIRO_STATUS_INVALID_MESH_CONSTRUCTION. + * + * A tensor-product patch is defined by 4 Bézier curves (side 0, 1, 2, + * 3) and by 4 additional control points (P0, P1, P2, P3) that provide + * further control over the patch and complete the definition of the + * tensor-product patch. The corner C0 is the first point of the + * patch. + * + * Degenerate sides are permitted so straight lines may be used. A + * zero length line on one side may be used to create 3 sided patches. + * + * + * C1 Side 1 C2 + * +---------------+ + * | | + * | P1 P2 | + * | | + * Side 0 | | Side 2 + * | | + * | | + * | P0 P3 | + * | | + * +---------------+ + * C0 Side 3 C3 + * + * + * Each patch is constructed by first calling + * cairo_mesh_pattern_begin_patch(), then cairo_mesh_pattern_move_to() + * to specify the first point in the patch (C0). Then the sides are + * specified with calls to cairo_mesh_pattern_curve_to() and + * cairo_mesh_pattern_line_to(). + * + * The four additional control points (P0, P1, P2, P3) in a patch can + * be specified with cairo_mesh_pattern_set_control_point(). + * + * At each corner of the patch (C0, C1, C2, C3) a color may be + * specified with cairo_mesh_pattern_set_corner_color_rgb() or + * cairo_mesh_pattern_set_corner_color_rgba(). Any corner whose color + * is not explicitly specified defaults to transparent black. + * + * A Coons patch is a special case of the tensor-product patch where + * the control points are implicitly defined by the sides of the + * patch. The default value for any control point not specified is the + * implicit value for a Coons patch, i.e. if no control points are + * specified the patch is a Coons patch. + * + * A triangle is a special case of the tensor-product patch where the + * control points are implicitly defined by the sides of the patch, + * all the sides are lines and one of them has length 0, i.e. if the + * patch is specified using just 3 lines, it is a triangle. If the + * corners connected by the 0-length side have the same color, the + * patch is a Gouraud-shaded triangle. + * + * Patches may be oriented differently to the above diagram. For + * example the first point could be at the top left. The diagram only + * shows the relationship between the sides, corners and control + * points. Regardless of where the first point is located, when + * specifying colors, corner 0 will always be the first point, corner + * 1 the point between side 0 and side 1 etc. + * + * Calling cairo_mesh_pattern_end_patch() completes the current + * patch. If less than 4 sides have been defined, the first missing + * side is defined as a line from the current point to the first point + * of the patch (C0) and the other sides are degenerate lines from C0 + * to C0. The corners between the added sides will all be coincident + * with C0 of the patch and their color will be set to be the same as + * the color of C0. + * + * Additional patches may be added with additional calls to + * cairo_mesh_pattern_begin_patch()/cairo_mesh_pattern_end_patch(). + * + * + * cairo_pattern_t *pattern = cairo_pattern_create_mesh (); + * + * /* Add a Coons patch */ + * cairo_mesh_pattern_begin_patch (pattern); + * cairo_mesh_pattern_move_to (pattern, 0, 0); + * cairo_mesh_pattern_curve_to (pattern, 30, -30, 60, 30, 100, 0); + * cairo_mesh_pattern_curve_to (pattern, 60, 30, 130, 60, 100, 100); + * cairo_mesh_pattern_curve_to (pattern, 60, 70, 30, 130, 0, 100); + * cairo_mesh_pattern_curve_to (pattern, 30, 70, -30, 30, 0, 0); + * cairo_mesh_pattern_set_corner_color_rgb (pattern, 0, 1, 0, 0); + * cairo_mesh_pattern_set_corner_color_rgb (pattern, 1, 0, 1, 0); + * cairo_mesh_pattern_set_corner_color_rgb (pattern, 2, 0, 0, 1); + * cairo_mesh_pattern_set_corner_color_rgb (pattern, 3, 1, 1, 0); + * cairo_mesh_pattern_end_patch (pattern); + * + * /* Add a Gouraud-shaded triangle */ + * cairo_mesh_pattern_begin_patch (pattern) + * cairo_mesh_pattern_move_to (pattern, 100, 100); + * cairo_mesh_pattern_line_to (pattern, 130, 130); + * cairo_mesh_pattern_line_to (pattern, 130, 70); + * cairo_mesh_pattern_set_corner_color_rgb (pattern, 0, 1, 0, 0); + * cairo_mesh_pattern_set_corner_color_rgb (pattern, 1, 0, 1, 0); + * cairo_mesh_pattern_set_corner_color_rgb (pattern, 2, 0, 0, 1); + * cairo_mesh_pattern_end_patch (pattern) + * + * + * When two patches overlap, the last one that has been added is drawn + * over the first one. + * + * When a patch folds over itself, points are sorted depending on + * their parameter coordinates inside the patch. The v coordinate + * ranges from 0 to 1 when moving from side 3 to side 1; the u + * coordinate ranges from 0 to 1 when going from side 0 to side + * 2. Points with higher v coordinate hide points with lower v + * coordinate. When two points have the same v coordinate, the one + * with higher u coordinate is above. This means that points nearer to + * side 1 are above points nearer to side 3; when this is not + * sufficient to decide which point is above (for example when both + * points belong to side 1 or side 3) points nearer to side 2 are + * above points nearer to side 0. + * + * For a complete definition of tensor-product patches, see the PDF + * specification (ISO32000), which describes the parametrization in + * detail. + * + * Note: The coordinates are always in pattern space. For a new + * pattern, pattern space is identical to user space, but the + * relationship between the spaces can be changed with + * cairo_pattern_set_matrix(). + * + * Return value: the newly created #cairo_pattern_t if successful, or + * an error pattern in case of no memory. The caller owns the returned + * object and should call cairo_pattern_destroy() when finished with + * it. + * + * This function will always return a valid pointer, but if an error + * occurred the pattern status will be set to an error. To inspect the + * status of a pattern use cairo_pattern_status(). + * + * Since: 1.12 + **/ +cairo_pattern_t * +cairo_pattern_create_mesh (void) +{ + cairo_mesh_pattern_t *pattern; + + pattern = + _freed_pool_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_MESH]); + if (unlikely (pattern == NULL)) { + pattern = _cairo_calloc (sizeof (cairo_mesh_pattern_t)); + if (unlikely (pattern == NULL)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_pattern_t *) &_cairo_pattern_nil.base; + } + } + + CAIRO_MUTEX_INITIALIZE (); + + _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_TYPE_MESH); + _cairo_array_init (&pattern->patches, sizeof (cairo_mesh_patch_t)); + pattern->current_patch = NULL; + CAIRO_REFERENCE_COUNT_INIT (&pattern->base.ref_count, 1); + + return &pattern->base; +} + +/** + * cairo_pattern_reference: + * @pattern: a #cairo_pattern_t + * + * Increases the reference count on @pattern by one. This prevents + * @pattern from being destroyed until a matching call to + * cairo_pattern_destroy() is made. + * + * Use cairo_pattern_get_reference_count() to get the number of + * references to a #cairo_pattern_t. + * + * Return value: the referenced #cairo_pattern_t. + * + * Since: 1.0 + **/ +cairo_pattern_t * +cairo_pattern_reference (cairo_pattern_t *pattern) +{ + if (pattern == NULL || + CAIRO_REFERENCE_COUNT_IS_INVALID (&pattern->ref_count)) + return pattern; + + assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&pattern->ref_count)); + + _cairo_reference_count_inc (&pattern->ref_count); + + return pattern; +} + +/** + * cairo_pattern_get_type: + * @pattern: a #cairo_pattern_t + * + * Get the pattern's type. See #cairo_pattern_type_t for available + * types. + * + * Return value: The type of @pattern. + * + * Since: 1.2 + **/ +cairo_pattern_type_t +cairo_pattern_get_type (cairo_pattern_t *pattern) +{ + return pattern->type; +} + +/** + * cairo_pattern_status: + * @pattern: a #cairo_pattern_t + * + * Checks whether an error has previously occurred for this + * pattern. + * + * Return value: %CAIRO_STATUS_SUCCESS, %CAIRO_STATUS_NO_MEMORY, + * %CAIRO_STATUS_INVALID_MATRIX, %CAIRO_STATUS_PATTERN_TYPE_MISMATCH, + * or %CAIRO_STATUS_INVALID_MESH_CONSTRUCTION. + * + * Since: 1.0 + **/ +cairo_status_t +cairo_pattern_status (cairo_pattern_t *pattern) +{ + return pattern->status; +} + +/** + * cairo_pattern_destroy: + * @pattern: a #cairo_pattern_t + * + * Decreases the reference count on @pattern by one. If the result is + * zero, then @pattern and all associated resources are freed. See + * cairo_pattern_reference(). + * + * Since: 1.0 + **/ +void +cairo_pattern_destroy (cairo_pattern_t *pattern) +{ + cairo_pattern_type_t type; + + if (pattern == NULL || + CAIRO_REFERENCE_COUNT_IS_INVALID (&pattern->ref_count)) + return; + + assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&pattern->ref_count)); + + if (! _cairo_reference_count_dec_and_test (&pattern->ref_count)) + return; + + type = pattern->type; + _cairo_pattern_fini (pattern); + + /* maintain a small cache of freed patterns */ + if (type < ARRAY_LENGTH (freed_pattern_pool)) + _freed_pool_put (&freed_pattern_pool[type], pattern); + else + free (pattern); +} + +/** + * cairo_pattern_get_reference_count: + * @pattern: a #cairo_pattern_t + * + * Returns the current reference count of @pattern. + * + * Return value: the current reference count of @pattern. If the + * object is a nil object, 0 will be returned. + * + * Since: 1.4 + **/ +unsigned int +cairo_pattern_get_reference_count (cairo_pattern_t *pattern) +{ + if (pattern == NULL || + CAIRO_REFERENCE_COUNT_IS_INVALID (&pattern->ref_count)) + return 0; + + return CAIRO_REFERENCE_COUNT_GET_VALUE (&pattern->ref_count); +} + +/** + * cairo_pattern_get_user_data: + * @pattern: a #cairo_pattern_t + * @key: the address of the #cairo_user_data_key_t the user data was + * attached to + * + * Return user data previously attached to @pattern using the + * specified key. If no user data has been attached with the given + * key this function returns %NULL. + * + * Return value: the user data previously attached or %NULL. + * + * Since: 1.4 + **/ +void * +cairo_pattern_get_user_data (cairo_pattern_t *pattern, + const cairo_user_data_key_t *key) +{ + return _cairo_user_data_array_get_data (&pattern->user_data, + key); +} + +/** + * cairo_pattern_set_user_data: + * @pattern: a #cairo_pattern_t + * @key: the address of a #cairo_user_data_key_t to attach the user data to + * @user_data: the user data to attach to the #cairo_pattern_t + * @destroy: a #cairo_destroy_func_t which will be called when the + * #cairo_t is destroyed or when new user data is attached using the + * same key. + * + * Attach user data to @pattern. To remove user data from a surface, + * call this function with the key that was used to set it and %NULL + * for @data. + * + * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a + * slot could not be allocated for the user data. + * + * Since: 1.4 + **/ +cairo_status_t +cairo_pattern_set_user_data (cairo_pattern_t *pattern, + const cairo_user_data_key_t *key, + void *user_data, + cairo_destroy_func_t destroy) +{ + if (CAIRO_REFERENCE_COUNT_IS_INVALID (&pattern->ref_count)) + return pattern->status; + + return _cairo_user_data_array_set_data (&pattern->user_data, + key, user_data, destroy); +} + +/** + * cairo_mesh_pattern_begin_patch: + * @pattern: a #cairo_pattern_t + * + * Begin a patch in a mesh pattern. + * + * After calling this function, the patch shape should be defined with + * cairo_mesh_pattern_move_to(), cairo_mesh_pattern_line_to() and + * cairo_mesh_pattern_curve_to(). + * + * After defining the patch, cairo_mesh_pattern_end_patch() must be + * called before using @pattern as a source or mask. + * + * Note: If @pattern is not a mesh pattern then @pattern will be put + * into an error status with a status of + * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH. If @pattern already has a + * current patch, it will be put into an error status with a status of + * %CAIRO_STATUS_INVALID_MESH_CONSTRUCTION. + * + * Since: 1.12 + **/ +void +cairo_mesh_pattern_begin_patch (cairo_pattern_t *pattern) +{ + cairo_mesh_pattern_t *mesh; + cairo_status_t status; + cairo_mesh_patch_t *current_patch; + int i; + + if (unlikely (pattern->status)) + return; + + if (unlikely (pattern->type != CAIRO_PATTERN_TYPE_MESH)) { + _cairo_pattern_set_error (pattern, CAIRO_STATUS_PATTERN_TYPE_MISMATCH); + return; + } + + mesh = (cairo_mesh_pattern_t *) pattern; + if (unlikely (mesh->current_patch)) { + _cairo_pattern_set_error (pattern, CAIRO_STATUS_INVALID_MESH_CONSTRUCTION); + return; + } + + status = _cairo_array_allocate (&mesh->patches, 1, (void **) ¤t_patch); + if (unlikely (status)) { + _cairo_pattern_set_error (pattern, status); + return; + } + + mesh->current_patch = current_patch; + mesh->current_side = -2; /* no current point */ + + for (i = 0; i < 4; i++) + mesh->has_control_point[i] = FALSE; + + for (i = 0; i < 4; i++) + mesh->has_color[i] = FALSE; +} + +static void +_calc_control_point (cairo_mesh_patch_t *patch, int control_point) +{ + /* The Coons patch is a special case of the Tensor Product patch + * where the four control points are: + * + * P11 = S(1/3, 1/3) + * P12 = S(1/3, 2/3) + * P21 = S(2/3, 1/3) + * P22 = S(2/3, 2/3) + * + * where S is the gradient surface. + * + * When one or more control points has not been specified + * calculated the Coons patch control points are substituted. If + * no control points are specified the gradient will be a Coons + * patch. + * + * The equations below are defined in the ISO32000 standard. + */ + cairo_point_double_t *p[3][3]; + int cp_i, cp_j, i, j; + + cp_i = mesh_control_point_i[control_point]; + cp_j = mesh_control_point_j[control_point]; + + for (i = 0; i < 3; i++) + for (j = 0; j < 3; j++) + p[i][j] = &patch->points[cp_i ^ i][cp_j ^ j]; + + p[0][0]->x = (- 4 * p[1][1]->x + + 6 * (p[1][0]->x + p[0][1]->x) + - 2 * (p[1][2]->x + p[2][1]->x) + + 3 * (p[2][0]->x + p[0][2]->x) + - 1 * p[2][2]->x) * (1. / 9); + + p[0][0]->y = (- 4 * p[1][1]->y + + 6 * (p[1][0]->y + p[0][1]->y) + - 2 * (p[1][2]->y + p[2][1]->y) + + 3 * (p[2][0]->y + p[0][2]->y) + - 1 * p[2][2]->y) * (1. / 9); +} + +/** + * cairo_mesh_pattern_end_patch: + * @pattern: a #cairo_pattern_t + * + * Indicates the end of the current patch in a mesh pattern. + * + * If the current patch has less than 4 sides, it is closed with a + * straight line from the current point to the first point of the + * patch as if cairo_mesh_pattern_line_to() was used. + * + * Note: If @pattern is not a mesh pattern then @pattern will be put + * into an error status with a status of + * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH. If @pattern has no current + * patch or the current patch has no current point, @pattern will be + * put into an error status with a status of + * %CAIRO_STATUS_INVALID_MESH_CONSTRUCTION. + * + * Since: 1.12 + **/ +void +cairo_mesh_pattern_end_patch (cairo_pattern_t *pattern) +{ + cairo_mesh_pattern_t *mesh; + cairo_mesh_patch_t *current_patch; + int i; + + if (unlikely (pattern->status)) + return; + + if (unlikely (pattern->type != CAIRO_PATTERN_TYPE_MESH)) { + _cairo_pattern_set_error (pattern, CAIRO_STATUS_PATTERN_TYPE_MISMATCH); + return; + } + + mesh = (cairo_mesh_pattern_t *) pattern; + current_patch = mesh->current_patch; + if (unlikely (!current_patch)) { + _cairo_pattern_set_error (pattern, CAIRO_STATUS_INVALID_MESH_CONSTRUCTION); + return; + } + + if (unlikely (mesh->current_side == -2)) { + _cairo_pattern_set_error (pattern, CAIRO_STATUS_INVALID_MESH_CONSTRUCTION); + return; + } + + while (mesh->current_side < 3) { + int corner_num; + + cairo_mesh_pattern_line_to (pattern, + current_patch->points[0][0].x, + current_patch->points[0][0].y); + + corner_num = mesh->current_side + 1; + if (corner_num < 4 && ! mesh->has_color[corner_num]) { + current_patch->colors[corner_num] = current_patch->colors[0]; + mesh->has_color[corner_num] = TRUE; + } + } + + for (i = 0; i < 4; i++) { + if (! mesh->has_control_point[i]) + _calc_control_point (current_patch, i); + } + + for (i = 0; i < 4; i++) { + if (! mesh->has_color[i]) + current_patch->colors[i] = *CAIRO_COLOR_TRANSPARENT; + } + + mesh->current_patch = NULL; +} + +/** + * cairo_mesh_pattern_curve_to: + * @pattern: a #cairo_pattern_t + * @x1: the X coordinate of the first control point + * @y1: the Y coordinate of the first control point + * @x2: the X coordinate of the second control point + * @y2: the Y coordinate of the second control point + * @x3: the X coordinate of the end of the curve + * @y3: the Y coordinate of the end of the curve + * + * Adds a cubic Bézier spline to the current patch from the current + * point to position (@x3, @y3) in pattern-space coordinates, using + * (@x1, @y1) and (@x2, @y2) as the control points. + * + * If the current patch has no current point before the call to + * cairo_mesh_pattern_curve_to(), this function will behave as if + * preceded by a call to cairo_mesh_pattern_move_to(@pattern, @x1, + * @y1). + * + * After this call the current point will be (@x3, @y3). + * + * Note: If @pattern is not a mesh pattern then @pattern will be put + * into an error status with a status of + * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH. If @pattern has no current + * patch or the current patch already has 4 sides, @pattern will be + * put into an error status with a status of + * %CAIRO_STATUS_INVALID_MESH_CONSTRUCTION. + * + * Since: 1.12 + **/ +void +cairo_mesh_pattern_curve_to (cairo_pattern_t *pattern, + double x1, double y1, + double x2, double y2, + double x3, double y3) +{ + cairo_mesh_pattern_t *mesh; + int current_point, i, j; + + if (unlikely (pattern->status)) + return; + + if (unlikely (pattern->type != CAIRO_PATTERN_TYPE_MESH)) { + _cairo_pattern_set_error (pattern, CAIRO_STATUS_PATTERN_TYPE_MISMATCH); + return; + } + + mesh = (cairo_mesh_pattern_t *) pattern; + if (unlikely (!mesh->current_patch)) { + _cairo_pattern_set_error (pattern, CAIRO_STATUS_INVALID_MESH_CONSTRUCTION); + return; + } + + if (unlikely (mesh->current_side == 3)) { + _cairo_pattern_set_error (pattern, CAIRO_STATUS_INVALID_MESH_CONSTRUCTION); + return; + } + + if (mesh->current_side == -2) + cairo_mesh_pattern_move_to (pattern, x1, y1); + + assert (mesh->current_side >= -1); + assert (pattern->status == CAIRO_STATUS_SUCCESS); + + mesh->current_side++; + + current_point = 3 * mesh->current_side; + + current_point++; + i = mesh_path_point_i[current_point]; + j = mesh_path_point_j[current_point]; + mesh->current_patch->points[i][j].x = x1; + mesh->current_patch->points[i][j].y = y1; + + current_point++; + i = mesh_path_point_i[current_point]; + j = mesh_path_point_j[current_point]; + mesh->current_patch->points[i][j].x = x2; + mesh->current_patch->points[i][j].y = y2; + + current_point++; + if (current_point < 12) { + i = mesh_path_point_i[current_point]; + j = mesh_path_point_j[current_point]; + mesh->current_patch->points[i][j].x = x3; + mesh->current_patch->points[i][j].y = y3; + } +} + +/** + * cairo_mesh_pattern_line_to: + * @pattern: a #cairo_pattern_t + * @x: the X coordinate of the end of the new line + * @y: the Y coordinate of the end of the new line + * + * Adds a line to the current patch from the current point to position + * (@x, @y) in pattern-space coordinates. + * + * If there is no current point before the call to + * cairo_mesh_pattern_line_to() this function will behave as + * cairo_mesh_pattern_move_to(@pattern, @x, @y). + * + * After this call the current point will be (@x, @y). + * + * Note: If @pattern is not a mesh pattern then @pattern will be put + * into an error status with a status of + * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH. If @pattern has no current + * patch or the current patch already has 4 sides, @pattern will be + * put into an error status with a status of + * %CAIRO_STATUS_INVALID_MESH_CONSTRUCTION. + * + * Since: 1.12 + **/ +void +cairo_mesh_pattern_line_to (cairo_pattern_t *pattern, + double x, double y) +{ + cairo_mesh_pattern_t *mesh; + cairo_point_double_t last_point; + int last_point_idx, i, j; + + if (unlikely (pattern->status)) + return; + + if (unlikely (pattern->type != CAIRO_PATTERN_TYPE_MESH)) { + _cairo_pattern_set_error (pattern, CAIRO_STATUS_PATTERN_TYPE_MISMATCH); + return; + } + + mesh = (cairo_mesh_pattern_t *) pattern; + if (unlikely (!mesh->current_patch)) { + _cairo_pattern_set_error (pattern, CAIRO_STATUS_INVALID_MESH_CONSTRUCTION); + return; + } + + if (unlikely (mesh->current_side == 3)) { + _cairo_pattern_set_error (pattern, CAIRO_STATUS_INVALID_MESH_CONSTRUCTION); + return; + } + + if (mesh->current_side == -2) { + cairo_mesh_pattern_move_to (pattern, x, y); + return; + } + + last_point_idx = 3 * (mesh->current_side + 1); + i = mesh_path_point_i[last_point_idx]; + j = mesh_path_point_j[last_point_idx]; + + last_point = mesh->current_patch->points[i][j]; + + cairo_mesh_pattern_curve_to (pattern, + (2 * last_point.x + x) * (1. / 3), + (2 * last_point.y + y) * (1. / 3), + (last_point.x + 2 * x) * (1. / 3), + (last_point.y + 2 * y) * (1. / 3), + x, y); +} + +/** + * cairo_mesh_pattern_move_to: + * @pattern: a #cairo_pattern_t + * @x: the X coordinate of the new position + * @y: the Y coordinate of the new position + * + * Define the first point of the current patch in a mesh pattern. + * + * After this call the current point will be (@x, @y). + * + * Note: If @pattern is not a mesh pattern then @pattern will be put + * into an error status with a status of + * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH. If @pattern has no current + * patch or the current patch already has at least one side, @pattern + * will be put into an error status with a status of + * %CAIRO_STATUS_INVALID_MESH_CONSTRUCTION. + * + * Since: 1.12 + **/ +void +cairo_mesh_pattern_move_to (cairo_pattern_t *pattern, + double x, double y) +{ + cairo_mesh_pattern_t *mesh; + + if (unlikely (pattern->status)) + return; + + if (unlikely (pattern->type != CAIRO_PATTERN_TYPE_MESH)) { + _cairo_pattern_set_error (pattern, CAIRO_STATUS_PATTERN_TYPE_MISMATCH); + return; + } + + mesh = (cairo_mesh_pattern_t *) pattern; + if (unlikely (!mesh->current_patch)) { + _cairo_pattern_set_error (pattern, CAIRO_STATUS_INVALID_MESH_CONSTRUCTION); + return; + } + + if (unlikely (mesh->current_side >= 0)) { + _cairo_pattern_set_error (pattern, CAIRO_STATUS_INVALID_MESH_CONSTRUCTION); + return; + } + + mesh->current_side = -1; + mesh->current_patch->points[0][0].x = x; + mesh->current_patch->points[0][0].y = y; +} + +/** + * cairo_mesh_pattern_set_control_point: + * @pattern: a #cairo_pattern_t + * @point_num: the control point to set the position for + * @x: the X coordinate of the control point + * @y: the Y coordinate of the control point + * + * Set an internal control point of the current patch. + * + * Valid values for @point_num are from 0 to 3 and identify the + * control points as explained in cairo_pattern_create_mesh(). + * + * Note: If @pattern is not a mesh pattern then @pattern will be put + * into an error status with a status of + * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH. If @point_num is not valid, + * @pattern will be put into an error status with a status of + * %CAIRO_STATUS_INVALID_INDEX. If @pattern has no current patch, + * @pattern will be put into an error status with a status of + * %CAIRO_STATUS_INVALID_MESH_CONSTRUCTION. + * + * Since: 1.12 + **/ +void +cairo_mesh_pattern_set_control_point (cairo_pattern_t *pattern, + unsigned int point_num, + double x, + double y) +{ + cairo_mesh_pattern_t *mesh; + int i, j; + + if (unlikely (pattern->status)) + return; + + if (unlikely (pattern->type != CAIRO_PATTERN_TYPE_MESH)) { + _cairo_pattern_set_error (pattern, CAIRO_STATUS_PATTERN_TYPE_MISMATCH); + return; + } + + if (unlikely (point_num > 3)) { + _cairo_pattern_set_error (pattern, CAIRO_STATUS_INVALID_INDEX); + return; + } + + mesh = (cairo_mesh_pattern_t *) pattern; + if (unlikely (!mesh->current_patch)) { + _cairo_pattern_set_error (pattern, CAIRO_STATUS_INVALID_MESH_CONSTRUCTION); + return; + } + + i = mesh_control_point_i[point_num]; + j = mesh_control_point_j[point_num]; + + mesh->current_patch->points[i][j].x = x; + mesh->current_patch->points[i][j].y = y; + mesh->has_control_point[point_num] = TRUE; +} + +/* make room for at least one more color stop */ +static cairo_status_t +_cairo_pattern_gradient_grow (cairo_gradient_pattern_t *pattern) +{ + cairo_gradient_stop_t *new_stops; + int old_size = pattern->stops_size; + int embedded_size = ARRAY_LENGTH (pattern->stops_embedded); + int new_size = 2 * MAX (old_size, 4); + + /* we have a local buffer at pattern->stops_embedded. try to fulfill the request + * from there. */ + if (old_size < embedded_size) { + pattern->stops = pattern->stops_embedded; + pattern->stops_size = embedded_size; + return CAIRO_STATUS_SUCCESS; + } + + if (CAIRO_INJECT_FAULT ()) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + assert (pattern->n_stops <= pattern->stops_size); + + if (pattern->stops == pattern->stops_embedded) { + new_stops = _cairo_malloc_ab (new_size, sizeof (cairo_gradient_stop_t)); + if (new_stops) + memcpy (new_stops, pattern->stops, old_size * sizeof (cairo_gradient_stop_t)); + } else { + new_stops = _cairo_realloc_ab (pattern->stops, + new_size, + sizeof (cairo_gradient_stop_t)); + } + + if (unlikely (new_stops == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + pattern->stops = new_stops; + pattern->stops_size = new_size; + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_mesh_pattern_set_corner_color (cairo_mesh_pattern_t *mesh, + unsigned int corner_num, + double red, double green, double blue, + double alpha) +{ + cairo_color_t *color; + + assert (mesh->current_patch); + assert (corner_num <= 3); + + color = &mesh->current_patch->colors[corner_num]; + color->red = red; + color->green = green; + color->blue = blue; + color->alpha = alpha; + + color->red_short = _cairo_color_double_to_short (red); + color->green_short = _cairo_color_double_to_short (green); + color->blue_short = _cairo_color_double_to_short (blue); + color->alpha_short = _cairo_color_double_to_short (alpha); + + mesh->has_color[corner_num] = TRUE; +} + +/** + * cairo_mesh_pattern_set_corner_color_rgb: + * @pattern: a #cairo_pattern_t + * @corner_num: the corner to set the color for + * @red: red component of color + * @green: green component of color + * @blue: blue component of color + * + * Sets the color of a corner of the current patch in a mesh pattern. + * + * The color is specified in the same way as in cairo_set_source_rgb(). + * + * Valid values for @corner_num are from 0 to 3 and identify the + * corners as explained in cairo_pattern_create_mesh(). + * + * Note: If @pattern is not a mesh pattern then @pattern will be put + * into an error status with a status of + * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH. If @corner_num is not valid, + * @pattern will be put into an error status with a status of + * %CAIRO_STATUS_INVALID_INDEX. If @pattern has no current patch, + * @pattern will be put into an error status with a status of + * %CAIRO_STATUS_INVALID_MESH_CONSTRUCTION. + * + * Since: 1.12 + **/ +void +cairo_mesh_pattern_set_corner_color_rgb (cairo_pattern_t *pattern, + unsigned int corner_num, + double red, double green, double blue) +{ + cairo_mesh_pattern_set_corner_color_rgba (pattern, corner_num, red, green, blue, 1.0); +} + +/** + * cairo_mesh_pattern_set_corner_color_rgba: + * @pattern: a #cairo_pattern_t + * @corner_num: the corner to set the color for + * @red: red component of color + * @green: green component of color + * @blue: blue component of color + * @alpha: alpha component of color + * + * Sets the color of a corner of the current patch in a mesh pattern. + * + * The color is specified in the same way as in cairo_set_source_rgba(). + * + * Valid values for @corner_num are from 0 to 3 and identify the + * corners as explained in cairo_pattern_create_mesh(). + * + * Note: If @pattern is not a mesh pattern then @pattern will be put + * into an error status with a status of + * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH. If @corner_num is not valid, + * @pattern will be put into an error status with a status of + * %CAIRO_STATUS_INVALID_INDEX. If @pattern has no current patch, + * @pattern will be put into an error status with a status of + * %CAIRO_STATUS_INVALID_MESH_CONSTRUCTION. + * + * Since: 1.12 + **/ +void +cairo_mesh_pattern_set_corner_color_rgba (cairo_pattern_t *pattern, + unsigned int corner_num, + double red, double green, double blue, + double alpha) +{ + cairo_mesh_pattern_t *mesh; + + if (unlikely (pattern->status)) + return; + + if (unlikely (pattern->type != CAIRO_PATTERN_TYPE_MESH)) { + _cairo_pattern_set_error (pattern, CAIRO_STATUS_PATTERN_TYPE_MISMATCH); + return; + } + + if (unlikely (corner_num > 3)) { + _cairo_pattern_set_error (pattern, CAIRO_STATUS_INVALID_INDEX); + return; + } + + mesh = (cairo_mesh_pattern_t *) pattern; + if (unlikely (!mesh->current_patch)) { + _cairo_pattern_set_error (pattern, CAIRO_STATUS_INVALID_MESH_CONSTRUCTION); + return; + } + + red = _cairo_restrict_value (red, 0.0, 1.0); + green = _cairo_restrict_value (green, 0.0, 1.0); + blue = _cairo_restrict_value (blue, 0.0, 1.0); + alpha = _cairo_restrict_value (alpha, 0.0, 1.0); + + _cairo_mesh_pattern_set_corner_color (mesh, corner_num, red, green, blue, alpha); +} + +static void +_cairo_pattern_add_color_stop (cairo_gradient_pattern_t *pattern, + double offset, + double red, + double green, + double blue, + double alpha) +{ + cairo_gradient_stop_t *stops; + unsigned int i; + + if (pattern->n_stops >= pattern->stops_size) { + cairo_status_t status = _cairo_pattern_gradient_grow (pattern); + if (unlikely (status)) { + status = _cairo_pattern_set_error (&pattern->base, status); + return; + } + } + + stops = pattern->stops; + + for (i = 0; i < pattern->n_stops; i++) + { + if (offset < stops[i].offset) + { + memmove (&stops[i + 1], &stops[i], + sizeof (cairo_gradient_stop_t) * (pattern->n_stops - i)); + + break; + } + } + + stops[i].offset = offset; + + stops[i].color.red = red; + stops[i].color.green = green; + stops[i].color.blue = blue; + stops[i].color.alpha = alpha; + + stops[i].color.red_short = _cairo_color_double_to_short (red); + stops[i].color.green_short = _cairo_color_double_to_short (green); + stops[i].color.blue_short = _cairo_color_double_to_short (blue); + stops[i].color.alpha_short = _cairo_color_double_to_short (alpha); + + pattern->n_stops++; +} + +/** + * cairo_pattern_add_color_stop_rgb: + * @pattern: a #cairo_pattern_t + * @offset: an offset in the range [0.0 .. 1.0] + * @red: red component of color + * @green: green component of color + * @blue: blue component of color + * + * Adds an opaque color stop to a gradient pattern. The offset + * specifies the location along the gradient's control vector. For + * example, a linear gradient's control vector is from (x0,y0) to + * (x1,y1) while a radial gradient's control vector is from any point + * on the start circle to the corresponding point on the end circle. + * + * The color is specified in the same way as in cairo_set_source_rgb(). + * + * If two (or more) stops are specified with identical offset values, + * they will be sorted according to the order in which the stops are + * added, (stops added earlier will compare less than stops added + * later). This can be useful for reliably making sharp color + * transitions instead of the typical blend. + * + * + * Note: If the pattern is not a gradient pattern, (eg. a linear or + * radial pattern), then the pattern will be put into an error status + * with a status of %CAIRO_STATUS_PATTERN_TYPE_MISMATCH. + * + * Since: 1.0 + **/ +void +cairo_pattern_add_color_stop_rgb (cairo_pattern_t *pattern, + double offset, + double red, + double green, + double blue) +{ + cairo_pattern_add_color_stop_rgba (pattern, offset, red, green, blue, 1.0); +} + +/** + * cairo_pattern_add_color_stop_rgba: + * @pattern: a #cairo_pattern_t + * @offset: an offset in the range [0.0 .. 1.0] + * @red: red component of color + * @green: green component of color + * @blue: blue component of color + * @alpha: alpha component of color + * + * Adds a translucent color stop to a gradient pattern. The offset + * specifies the location along the gradient's control vector. For + * example, a linear gradient's control vector is from (x0,y0) to + * (x1,y1) while a radial gradient's control vector is from any point + * on the start circle to the corresponding point on the end circle. + * + * The color is specified in the same way as in cairo_set_source_rgba(). + * + * If two (or more) stops are specified with identical offset values, + * they will be sorted according to the order in which the stops are + * added, (stops added earlier will compare less than stops added + * later). This can be useful for reliably making sharp color + * transitions instead of the typical blend. + * + * Note: If the pattern is not a gradient pattern, (eg. a linear or + * radial pattern), then the pattern will be put into an error status + * with a status of %CAIRO_STATUS_PATTERN_TYPE_MISMATCH. + * + * Since: 1.0 + **/ +void +cairo_pattern_add_color_stop_rgba (cairo_pattern_t *pattern, + double offset, + double red, + double green, + double blue, + double alpha) +{ + if (pattern->status) + return; + + if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR && + pattern->type != CAIRO_PATTERN_TYPE_RADIAL) + { + _cairo_pattern_set_error (pattern, CAIRO_STATUS_PATTERN_TYPE_MISMATCH); + return; + } + + offset = _cairo_restrict_value (offset, 0.0, 1.0); + red = _cairo_restrict_value (red, 0.0, 1.0); + green = _cairo_restrict_value (green, 0.0, 1.0); + blue = _cairo_restrict_value (blue, 0.0, 1.0); + alpha = _cairo_restrict_value (alpha, 0.0, 1.0); + + _cairo_pattern_add_color_stop ((cairo_gradient_pattern_t *) pattern, + offset, red, green, blue, alpha); +} + +/** + * cairo_pattern_set_matrix: + * @pattern: a #cairo_pattern_t + * @matrix: a #cairo_matrix_t + * + * Sets the pattern's transformation matrix to @matrix. This matrix is + * a transformation from user space to pattern space. + * + * When a pattern is first created it always has the identity matrix + * for its transformation matrix, which means that pattern space is + * initially identical to user space. + * + * Important: Please note that the direction of this transformation + * matrix is from user space to pattern space. This means that if you + * imagine the flow from a pattern to user space (and on to device + * space), then coordinates in that flow will be transformed by the + * inverse of the pattern matrix. + * + * For example, if you want to make a pattern appear twice as large as + * it does by default the correct code to use is: + * + * + * cairo_matrix_init_scale (&matrix, 0.5, 0.5); + * cairo_pattern_set_matrix (pattern, &matrix); + * + * + * Meanwhile, using values of 2.0 rather than 0.5 in the code above + * would cause the pattern to appear at half of its default size. + * + * Also, please note the discussion of the user-space locking + * semantics of cairo_set_source(). + * + * Since: 1.0 + **/ +void +cairo_pattern_set_matrix (cairo_pattern_t *pattern, + const cairo_matrix_t *matrix) +{ + cairo_matrix_t inverse; + cairo_status_t status; + + if (pattern->status) + return; + + if (memcmp (&pattern->matrix, matrix, sizeof (cairo_matrix_t)) == 0) + return; + + pattern->matrix = *matrix; + _cairo_pattern_notify_observers (pattern, CAIRO_PATTERN_NOTIFY_MATRIX); + + inverse = *matrix; + status = cairo_matrix_invert (&inverse); + if (unlikely (status)) + status = _cairo_pattern_set_error (pattern, status); +} + +/** + * cairo_pattern_get_matrix: + * @pattern: a #cairo_pattern_t + * @matrix: return value for the matrix + * + * Stores the pattern's transformation matrix into @matrix. + * + * Since: 1.0 + **/ +void +cairo_pattern_get_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix) +{ + *matrix = pattern->matrix; +} + +/** + * cairo_pattern_set_filter: + * @pattern: a #cairo_pattern_t + * @filter: a #cairo_filter_t describing the filter to use for resizing + * the pattern + * + * Sets the filter to be used for resizing when using this pattern. + * See #cairo_filter_t for details on each filter. + * + * * Note that you might want to control filtering even when you do not + * have an explicit #cairo_pattern_t object, (for example when using + * cairo_set_source_surface()). In these cases, it is convenient to + * use cairo_get_source() to get access to the pattern that cairo + * creates implicitly. For example: + * + * + * cairo_set_source_surface (cr, image, x, y); + * cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); + * + * + * Since: 1.0 + **/ +void +cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter) +{ + if (pattern->status) + return; + + pattern->filter = filter; + _cairo_pattern_notify_observers (pattern, CAIRO_PATTERN_NOTIFY_FILTER); +} + +/** + * cairo_pattern_get_filter: + * @pattern: a #cairo_pattern_t + * + * Gets the current filter for a pattern. See #cairo_filter_t + * for details on each filter. + * + * Return value: the current filter used for resizing the pattern. + * + * Since: 1.0 + **/ +cairo_filter_t +cairo_pattern_get_filter (cairo_pattern_t *pattern) +{ + return pattern->filter; +} + +/** + * cairo_pattern_get_dither: + * @pattern: a #cairo_pattern_t + * + * Gets the current dithering mode, as set by + * cairo_pattern_set_dither(). + * + * Return value: the current dithering mode. + * + * Since: 1.18 + **/ +cairo_dither_t +cairo_pattern_get_dither (cairo_pattern_t *pattern) +{ + return pattern->dither; +} + +/** + * cairo_pattern_set_dither: + * @pattern: a #cairo_pattern_t + * @dither: a #cairo_dither_t describing the new dithering mode + * + * Set the dithering mode of the rasterizer used for drawing shapes. + * This value is a hint, and a particular backend may or may not support + * a particular value. At the current time, only pixman is supported. + * + * Since: 1.18 + **/ +void +cairo_pattern_set_dither (cairo_pattern_t *pattern, cairo_dither_t dither) +{ + if (pattern->status) + return; + + pattern->dither = dither; + _cairo_pattern_notify_observers (pattern, CAIRO_PATTERN_NOTIFY_DITHER); + +} + +/** + * cairo_pattern_set_extend: + * @pattern: a #cairo_pattern_t + * @extend: a #cairo_extend_t describing how the area outside of the + * pattern will be drawn + * + * Sets the mode to be used for drawing outside the area of a pattern. + * See #cairo_extend_t for details on the semantics of each extend + * strategy. + * + * The default extend mode is %CAIRO_EXTEND_NONE for surface patterns + * and %CAIRO_EXTEND_PAD for gradient patterns. + * + * Since: 1.0 + **/ +void +cairo_pattern_set_extend (cairo_pattern_t *pattern, cairo_extend_t extend) +{ + if (pattern->status) + return; + + pattern->extend = extend; + _cairo_pattern_notify_observers (pattern, CAIRO_PATTERN_NOTIFY_EXTEND); +} + +/** + * cairo_pattern_get_extend: + * @pattern: a #cairo_pattern_t + * + * Gets the current extend mode for a pattern. See #cairo_extend_t + * for details on the semantics of each extend strategy. + * + * Return value: the current extend strategy used for drawing the + * pattern. + * + * Since: 1.0 + **/ +cairo_extend_t +cairo_pattern_get_extend (cairo_pattern_t *pattern) +{ + return pattern->extend; +} + +void +_cairo_pattern_pretransform (cairo_pattern_t *pattern, + const cairo_matrix_t *ctm) +{ + if (pattern->status) + return; + + cairo_matrix_multiply (&pattern->matrix, &pattern->matrix, ctm); +} + +void +_cairo_pattern_transform (cairo_pattern_t *pattern, + const cairo_matrix_t *ctm_inverse) +{ + if (pattern->status) + return; + + cairo_matrix_multiply (&pattern->matrix, ctm_inverse, &pattern->matrix); +} + +static cairo_bool_t +_linear_pattern_is_degenerate (const cairo_linear_pattern_t *linear) +{ + return fabs (linear->pd1.x - linear->pd2.x) < DBL_EPSILON && + fabs (linear->pd1.y - linear->pd2.y) < DBL_EPSILON; +} + +static cairo_bool_t +_radial_pattern_is_degenerate (const cairo_radial_pattern_t *radial) +{ + /* A radial pattern is considered degenerate if it can be + * represented as a solid or clear pattern. This corresponds to + * one of the two cases: + * + * 1) The radii are both very small: + * |dr| < DBL_EPSILON && min (r0, r1) < DBL_EPSILON + * + * 2) The two circles have about the same radius and are very + * close to each other (approximately a cylinder gradient that + * doesn't move with the parameter): + * |dr| < DBL_EPSILON && max (|dx|, |dy|) < 2 * DBL_EPSILON + * + * These checks are consistent with the assumptions used in + * _cairo_radial_pattern_box_to_parameter (). + */ + + return fabs (radial->cd1.radius - radial->cd2.radius) < DBL_EPSILON && + (MIN (radial->cd1.radius, radial->cd2.radius) < DBL_EPSILON || + MAX (fabs (radial->cd1.center.x - radial->cd2.center.x), + fabs (radial->cd1.center.y - radial->cd2.center.y)) < 2 * DBL_EPSILON); +} + +static void +_cairo_linear_pattern_box_to_parameter (const cairo_linear_pattern_t *linear, + double x0, double y0, + double x1, double y1, + double range[2]) +{ + double t0, tdx, tdy; + double p1x, p1y, pdx, pdy, invsqnorm; + + assert (! _linear_pattern_is_degenerate (linear)); + + /* + * Linear gradients are othrogonal to the line passing through + * their extremes. Because of convexity, the parameter range can + * be computed as the convex hull (one the real line) of the + * parameter values of the 4 corners of the box. + * + * The parameter value t for a point (x,y) can be computed as: + * + * t = (p2 - p1) . (x,y) / |p2 - p1|^2 + * + * t0 is the t value for the top left corner + * tdx is the difference between left and right corners + * tdy is the difference between top and bottom corners + */ + + p1x = linear->pd1.x; + p1y = linear->pd1.y; + pdx = linear->pd2.x - p1x; + pdy = linear->pd2.y - p1y; + invsqnorm = 1.0 / (pdx * pdx + pdy * pdy); + pdx *= invsqnorm; + pdy *= invsqnorm; + + t0 = (x0 - p1x) * pdx + (y0 - p1y) * pdy; + tdx = (x1 - x0) * pdx; + tdy = (y1 - y0) * pdy; + + /* + * Because of the linearity of the t value, tdx can simply be + * added the t0 to move along the top edge. After this, range[0] + * and range[1] represent the parameter range for the top edge, so + * extending it to include the whole box simply requires adding + * tdy to the correct extreme. + */ + + range[0] = range[1] = t0; + if (tdx < 0) + range[0] += tdx; + else + range[1] += tdx; + + if (tdy < 0) + range[0] += tdy; + else + range[1] += tdy; +} + +static cairo_bool_t +_extend_range (double range[2], double value, cairo_bool_t valid) +{ + if (!valid) + range[0] = range[1] = value; + else if (value < range[0]) + range[0] = value; + else if (value > range[1]) + range[1] = value; + + return TRUE; +} + +/* + * _cairo_radial_pattern_focus_is_inside: + * + * Returns %TRUE if and only if the focus point exists and is + * contained in one of the two extreme circles. This condition is + * equivalent to one of the two extreme circles being completely + * contained in the other one. + * + * Note: if the focus is on the border of one of the two circles (in + * which case the circles are tangent in the focus point), it is not + * considered as contained in the circle, hence this function returns + * %FALSE. + * + */ +cairo_bool_t +_cairo_radial_pattern_focus_is_inside (const cairo_radial_pattern_t *radial) +{ + double cx, cy, cr, dx, dy, dr; + + cx = radial->cd1.center.x; + cy = radial->cd1.center.y; + cr = radial->cd1.radius; + dx = radial->cd2.center.x - cx; + dy = radial->cd2.center.y - cy; + dr = radial->cd2.radius - cr; + + return dx*dx + dy*dy < dr*dr; +} + +static void +_cairo_radial_pattern_box_to_parameter (const cairo_radial_pattern_t *radial, + double x0, double y0, + double x1, double y1, + double tolerance, + double range[2]) +{ + double cx, cy, cr, dx, dy, dr; + double a, x_focus, y_focus; + double mindr, minx, miny, maxx, maxy; + cairo_bool_t valid; + + assert (! _radial_pattern_is_degenerate (radial)); + assert (x0 < x1); + assert (y0 < y1); + + tolerance = MAX (tolerance, DBL_EPSILON); + + range[0] = range[1] = 0; + valid = FALSE; + + x_focus = y_focus = 0; /* silence gcc */ + + cx = radial->cd1.center.x; + cy = radial->cd1.center.y; + cr = radial->cd1.radius; + dx = radial->cd2.center.x - cx; + dy = radial->cd2.center.y - cy; + dr = radial->cd2.radius - cr; + + /* translate by -(cx, cy) to simplify computations */ + x0 -= cx; + y0 -= cy; + x1 -= cx; + y1 -= cy; + + /* enlarge boundaries slightly to avoid rounding problems in the + * parameter range computation */ + x0 -= DBL_EPSILON; + y0 -= DBL_EPSILON; + x1 += DBL_EPSILON; + y1 += DBL_EPSILON; + + /* enlarge boundaries even more to avoid rounding problems when + * testing if a point belongs to the box */ + minx = x0 - DBL_EPSILON; + miny = y0 - DBL_EPSILON; + maxx = x1 + DBL_EPSILON; + maxy = y1 + DBL_EPSILON; + + /* we don't allow negative radiuses, so we will be checking that + * t*dr >= mindr to consider t valid */ + mindr = -(cr + DBL_EPSILON); + + /* + * After the previous transformations, the start circle is + * centered in the origin and has radius cr. A 1-unit change in + * the t parameter corresponds to dx,dy,dr changes in the x,y,r of + * the circle (center coordinates, radius). + * + * To compute the minimum range needed to correctly draw the + * pattern, we start with an empty range and extend it to include + * the circles touching the bounding box or within it. + */ + + /* + * Focus, the point where the circle has radius == 0. + * + * r = cr + t * dr = 0 + * t = -cr / dr + * + * If the radius is constant (dr == 0) there is no focus (the + * gradient represents a cylinder instead of a cone). + */ + if (fabs (dr) >= DBL_EPSILON) { + double t_focus; + + t_focus = -cr / dr; + x_focus = t_focus * dx; + y_focus = t_focus * dy; + if (minx <= x_focus && x_focus <= maxx && + miny <= y_focus && y_focus <= maxy) + { + valid = _extend_range (range, t_focus, valid); + } + } + + /* + * Circles externally tangent to box edges. + * + * All circles have center in (dx, dy) * t + * + * If the circle is tangent to the line defined by the edge of the + * box, then at least one of the following holds true: + * + * (dx*t) + (cr + dr*t) == x0 (left edge) + * (dx*t) - (cr + dr*t) == x1 (right edge) + * (dy*t) + (cr + dr*t) == y0 (top edge) + * (dy*t) - (cr + dr*t) == y1 (bottom edge) + * + * The solution is only valid if the tangent point is actually on + * the edge, i.e. if its y coordinate is in [y0,y1] for left/right + * edges and if its x coordinate is in [x0,x1] for top/bottom + * edges. + * + * For the first equation: + * + * (dx + dr) * t = x0 - cr + * t = (x0 - cr) / (dx + dr) + * y = dy * t + * + * in the code this becomes: + * + * t_edge = (num) / (den) + * v = (delta) * t_edge + * + * If the denominator in t is 0, the pattern is tangent to a line + * parallel to the edge under examination. The corner-case where + * the boundary line is the same as the edge is handled by the + * focus point case and/or by the a==0 case. + */ +#define T_EDGE(num,den,delta,lower,upper) \ + if (fabs (den) >= DBL_EPSILON) { \ + double t_edge, v; \ + \ + t_edge = (num) / (den); \ + v = t_edge * (delta); \ + if (t_edge * dr >= mindr && (lower) <= v && v <= (upper)) \ + valid = _extend_range (range, t_edge, valid); \ + } + + /* circles tangent (externally) to left/right/top/bottom edge */ + T_EDGE (x0 - cr, dx + dr, dy, miny, maxy); + T_EDGE (x1 + cr, dx - dr, dy, miny, maxy); + T_EDGE (y0 - cr, dy + dr, dx, minx, maxx); + T_EDGE (y1 + cr, dy - dr, dx, minx, maxx); + +#undef T_EDGE + + /* + * Circles passing through a corner. + * + * A circle passing through the point (x,y) satisfies: + * + * (x-t*dx)^2 + (y-t*dy)^2 == (cr + t*dr)^2 + * + * If we set: + * a = dx^2 + dy^2 - dr^2 + * b = x*dx + y*dy + cr*dr + * c = x^2 + y^2 - cr^2 + * we have: + * a*t^2 - 2*b*t + c == 0 + */ + a = dx * dx + dy * dy - dr * dr; + if (fabs (a) < DBL_EPSILON * DBL_EPSILON) { + double b, maxd2; + + /* Ensure that gradients with both a and dr small are + * considered degenerate. + * The floating point version of the degeneracy test implemented + * in _radial_pattern_is_degenerate() is: + * + * 1) The circles are practically the same size: + * |dr| < DBL_EPSILON + * AND + * 2a) The circles are both very small: + * min (r0, r1) < DBL_EPSILON + * OR + * 2b) The circles are very close to each other: + * max (|dx|, |dy|) < 2 * DBL_EPSILON + * + * Assuming that the gradient is not degenerate, we want to + * show that |a| < DBL_EPSILON^2 implies |dr| >= DBL_EPSILON. + * + * If the gradient is not degenerate yet it has |dr| < + * DBL_EPSILON, (2b) is false, thus: + * + * max (|dx|, |dy|) >= 2*DBL_EPSILON + * which implies: + * 4*DBL_EPSILON^2 <= max (|dx|, |dy|)^2 <= dx^2 + dy^2 + * + * From the definition of a, we get: + * a = dx^2 + dy^2 - dr^2 < DBL_EPSILON^2 + * dx^2 + dy^2 - DBL_EPSILON^2 < dr^2 + * 3*DBL_EPSILON^2 < dr^2 + * + * which is inconsistent with the hypotheses, thus |dr| < + * DBL_EPSILON is false or the gradient is degenerate. + */ + assert (fabs (dr) >= DBL_EPSILON); + + /* + * If a == 0, all the circles are tangent to a line in the + * focus point. If this line is within the box extents, we + * should add the circle with infinite radius, but this would + * make the range unbounded, so we add the smallest circle whose + * distance to the desired (degenerate) circle within the + * bounding box does not exceed tolerance. + * + * The equation of the line is b==0, i.e.: + * x*dx + y*dy + cr*dr == 0 + * + * We compute the intersection of the line with the box and + * keep the intersection with maximum square distance (maxd2) + * from the focus point. + * + * In the code the intersection is represented in another + * coordinate system, whose origin is the focus point and + * which has a u,v axes, which are respectively orthogonal and + * parallel to the edge being intersected. + * + * The intersection is valid only if it belongs to the box, + * otherwise it is ignored. + * + * For example: + * + * y = y0 + * x*dx + y0*dy + cr*dr == 0 + * x = -(y0*dy + cr*dr) / dx + * + * which in (u,v) is: + * u = y0 - y_focus + * v = -(y0*dy + cr*dr) / dx - x_focus + * + * In the code: + * u = (edge) - (u_origin) + * v = -((edge) * (delta) + cr*dr) / (den) - v_focus + */ +#define T_EDGE(edge,delta,den,lower,upper,u_origin,v_origin) \ + if (fabs (den) >= DBL_EPSILON) { \ + double v; \ + \ + v = -((edge) * (delta) + cr * dr) / (den); \ + if ((lower) <= v && v <= (upper)) { \ + double u, d2; \ + \ + u = (edge) - (u_origin); \ + v -= (v_origin); \ + d2 = u*u + v*v; \ + if (maxd2 < d2) \ + maxd2 = d2; \ + } \ + } + + maxd2 = 0; + + /* degenerate circles (lines) passing through each edge */ + T_EDGE (y0, dy, dx, minx, maxx, y_focus, x_focus); + T_EDGE (y1, dy, dx, minx, maxx, y_focus, x_focus); + T_EDGE (x0, dx, dy, miny, maxy, x_focus, y_focus); + T_EDGE (x1, dx, dy, miny, maxy, x_focus, y_focus); + +#undef T_EDGE + + /* + * The limit circle can be transformed rigidly to the y=0 line + * and the circles tangent to it in (0,0) are: + * + * x^2 + (y-r)^2 = r^2 <=> x^2 + y^2 - 2*y*r = 0 + * + * y is the distance from the line, in our case tolerance; + * x is the distance along the line, i.e. sqrt(maxd2), + * so: + * + * r = cr + dr * t = (maxd2 + tolerance^2) / (2*tolerance) + * t = (r - cr) / dr = + * (maxd2 + tolerance^2 - 2*tolerance*cr) / (2*tolerance*dr) + */ + if (maxd2 > 0) { + double t_limit = maxd2 + tolerance*tolerance - 2*tolerance*cr; + t_limit /= 2 * tolerance * dr; + valid = _extend_range (range, t_limit, valid); + } + + /* + * Nondegenerate, nonlimit circles passing through the corners. + * + * a == 0 && a*t^2 - 2*b*t + c == 0 + * + * t = c / (2*b) + * + * The b == 0 case has just been handled, so we only have to + * compute this if b != 0. + */ +#define T_CORNER(x,y) \ + b = (x) * dx + (y) * dy + cr * dr; \ + if (fabs (b) >= DBL_EPSILON) { \ + double t_corner; \ + double x2 = (x) * (x); \ + double y2 = (y) * (y); \ + double cr2 = (cr) * (cr); \ + double c = x2 + y2 - cr2; \ + \ + t_corner = 0.5 * c / b; \ + if (t_corner * dr >= mindr) \ + valid = _extend_range (range, t_corner, valid); \ + } + + /* circles touching each corner */ + T_CORNER (x0, y0); + T_CORNER (x0, y1); + T_CORNER (x1, y0); + T_CORNER (x1, y1); + +#undef T_CORNER + } else { + double inva, b, c, d; + + inva = 1 / a; + + /* + * Nondegenerate, nonlimit circles passing through the corners. + * + * a != 0 && a*t^2 - 2*b*t + c == 0 + * + * t = (b +- sqrt (b*b - a*c)) / a + * + * If the argument of sqrt() is negative, then no circle + * passes through the corner. + */ +#define T_CORNER(x,y) \ + b = (x) * dx + (y) * dy + cr * dr; \ + c = (x) * (x) + (y) * (y) - cr * cr; \ + d = b * b - a * c; \ + if (d >= 0) { \ + double t_corner; \ + \ + d = sqrt (d); \ + t_corner = (b + d) * inva; \ + if (t_corner * dr >= mindr) \ + valid = _extend_range (range, t_corner, valid); \ + t_corner = (b - d) * inva; \ + if (t_corner * dr >= mindr) \ + valid = _extend_range (range, t_corner, valid); \ + } + + /* circles touching each corner */ + T_CORNER (x0, y0); + T_CORNER (x0, y1); + T_CORNER (x1, y0); + T_CORNER (x1, y1); + +#undef T_CORNER + } +} + +/** + * _cairo_gradient_pattern_box_to_parameter: + * + * Compute a interpolation range sufficient to draw (within the given + * tolerance) the gradient in the given box getting the same result as + * using the (-inf, +inf) range. + * + * Assumes that the pattern is not degenerate. This can be guaranteed + * by simplifying it to a solid clear if _cairo_pattern_is_clear or to + * a solid color if _cairo_gradient_pattern_is_solid. + * + * The range isn't guaranteed to be minimal, but it tries to. + **/ +void +_cairo_gradient_pattern_box_to_parameter (const cairo_gradient_pattern_t *gradient, + double x0, double y0, + double x1, double y1, + double tolerance, + double out_range[2]) +{ + assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR || + gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL); + + if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) { + _cairo_linear_pattern_box_to_parameter ((cairo_linear_pattern_t *) gradient, + x0, y0, x1, y1, out_range); + } else { + _cairo_radial_pattern_box_to_parameter ((cairo_radial_pattern_t *) gradient, + x0, y0, x1, y1, tolerance, out_range); + } +} + +/** + * _cairo_gradient_pattern_interpolate: + * + * Interpolate between the start and end objects of linear or radial + * gradients. The interpolated object is stored in out_circle, with + * the radius being zero in the linear gradient case. + **/ +void +_cairo_gradient_pattern_interpolate (const cairo_gradient_pattern_t *gradient, + double t, + cairo_circle_double_t *out_circle) +{ + assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR || + gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL); + +#define lerp(a,b) (a)*(1-t) + (b)*t + + if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) { + cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient; + out_circle->center.x = lerp (linear->pd1.x, linear->pd2.x); + out_circle->center.y = lerp (linear->pd1.y, linear->pd2.y); + out_circle->radius = 0; + } else { + cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) gradient; + out_circle->center.x = lerp (radial->cd1.center.x, radial->cd2.center.x); + out_circle->center.y = lerp (radial->cd1.center.y, radial->cd2.center.y); + out_circle->radius = lerp (radial->cd1.radius , radial->cd2.radius); + } + +#undef lerp +} + +/** + * _cairo_gradient_pattern_fit_to_range: + * + * Scale the extremes of a gradient to guarantee that the coordinates + * and their deltas are within the range (-max_value, max_value). The + * new extremes are stored in out_circle. + * + * The pattern matrix is scaled to guarantee that the aspect of the + * gradient is the same and the result is stored in out_matrix. + * + **/ +void +_cairo_gradient_pattern_fit_to_range (const cairo_gradient_pattern_t *gradient, + double max_value, + cairo_matrix_t *out_matrix, + cairo_circle_double_t out_circle[2]) +{ + double dim; + + assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR || + gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL); + + if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) { + cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient; + + out_circle[0].center = linear->pd1; + out_circle[0].radius = 0; + out_circle[1].center = linear->pd2; + out_circle[1].radius = 0; + + dim = fabs (linear->pd1.x); + dim = MAX (dim, fabs (linear->pd1.y)); + dim = MAX (dim, fabs (linear->pd2.x)); + dim = MAX (dim, fabs (linear->pd2.y)); + dim = MAX (dim, fabs (linear->pd1.x - linear->pd2.x)); + dim = MAX (dim, fabs (linear->pd1.y - linear->pd2.y)); + } else { + cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) gradient; + + out_circle[0] = radial->cd1; + out_circle[1] = radial->cd2; + + dim = fabs (radial->cd1.center.x); + dim = MAX (dim, fabs (radial->cd1.center.y)); + dim = MAX (dim, fabs (radial->cd1.radius)); + dim = MAX (dim, fabs (radial->cd2.center.x)); + dim = MAX (dim, fabs (radial->cd2.center.y)); + dim = MAX (dim, fabs (radial->cd2.radius)); + dim = MAX (dim, fabs (radial->cd1.center.x - radial->cd2.center.x)); + dim = MAX (dim, fabs (radial->cd1.center.y - radial->cd2.center.y)); + dim = MAX (dim, fabs (radial->cd1.radius - radial->cd2.radius)); + } + dim = MAX (dim, fabs (gradient->base.matrix.xx)); + dim = MAX (dim, fabs (gradient->base.matrix.xy)); + dim = MAX (dim, fabs (gradient->base.matrix.x0)); + dim = MAX (dim, fabs (gradient->base.matrix.yx)); + dim = MAX (dim, fabs (gradient->base.matrix.yy)); + dim = MAX (dim, fabs (gradient->base.matrix.y0)); + + if (unlikely (dim > max_value)) { + cairo_matrix_t scale; + + dim = max_value / dim; + + out_circle[0].center.x *= dim; + out_circle[0].center.y *= dim; + out_circle[0].radius *= dim; + out_circle[1].center.x *= dim; + out_circle[1].center.y *= dim; + out_circle[1].radius *= dim; + + cairo_matrix_init_scale (&scale, dim, dim); + cairo_matrix_multiply (out_matrix, &gradient->base.matrix, &scale); + } else { + *out_matrix = gradient->base.matrix; + } +} + +static cairo_bool_t +_gradient_is_clear (const cairo_gradient_pattern_t *gradient, + const cairo_rectangle_int_t *extents) +{ + unsigned int i; + + assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR || + gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL); + + if (gradient->n_stops == 0 || + (gradient->base.extend == CAIRO_EXTEND_NONE && + gradient->stops[0].offset == gradient->stops[gradient->n_stops - 1].offset)) + return TRUE; + + if (gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL) { + /* degenerate radial gradients are clear */ + if (_radial_pattern_is_degenerate ((cairo_radial_pattern_t *) gradient)) + return TRUE; + } else if (gradient->base.extend == CAIRO_EXTEND_NONE) { + /* EXTEND_NONE degenerate linear gradients are clear */ + if (_linear_pattern_is_degenerate ((cairo_linear_pattern_t *) gradient)) + return TRUE; + } + + /* Check if the extents intersect the drawn part of the pattern. */ + if (extents != NULL && + (gradient->base.extend == CAIRO_EXTEND_NONE || + gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL)) + { + double t[2]; + + _cairo_gradient_pattern_box_to_parameter (gradient, + extents->x, + extents->y, + extents->x + extents->width, + extents->y + extents->height, + DBL_EPSILON, + t); + + if (gradient->base.extend == CAIRO_EXTEND_NONE && + (t[0] >= gradient->stops[gradient->n_stops - 1].offset || + t[1] <= gradient->stops[0].offset)) + { + return TRUE; + } + + if (t[0] == t[1]) + return TRUE; + } + + for (i = 0; i < gradient->n_stops; i++) + if (! CAIRO_COLOR_IS_CLEAR (&gradient->stops[i].color)) + return FALSE; + + return TRUE; +} + +static void +_gradient_color_average (const cairo_gradient_pattern_t *gradient, + cairo_color_t *color) +{ + double delta0, delta1; + double r, g, b, a; + unsigned int i, start = 1, end; + + assert (gradient->n_stops > 0); + assert (gradient->base.extend != CAIRO_EXTEND_NONE); + + if (gradient->n_stops == 1) { + _cairo_color_init_rgba (color, + gradient->stops[0].color.red, + gradient->stops[0].color.green, + gradient->stops[0].color.blue, + gradient->stops[0].color.alpha); + return; + } + + end = gradient->n_stops - 1; + + switch (gradient->base.extend) { + case CAIRO_EXTEND_REPEAT: + /* + * Sa, Sb and Sy, Sz are the first two and last two stops respectively. + * The weight of the first and last stop can be computed as the area of + * the following triangles (taken with height 1, since the whole [0-1] + * will have total weight 1 this way): b*h/2 + * + * + + + * / |\ / | \ + * / | \ / | \ + * / | \ / | \ + * ~~~~~+---+---+---+~~~~~~~+-------+---+---+~~~~~ + * -1+Sz 0 Sa Sb Sy Sz 1 1+Sa + * + * For the first stop: (Sb-(-1+Sz)/2 = (1+Sb-Sz)/2 + * For the last stop: ((1+Sa)-Sy)/2 = (1+Sa-Sy)/2 + * Halving the result is done after summing up all the areas. + */ + delta0 = 1.0 + gradient->stops[1].offset - gradient->stops[end].offset; + delta1 = 1.0 + gradient->stops[0].offset - gradient->stops[end-1].offset; + break; + + case CAIRO_EXTEND_REFLECT: + /* + * Sa, Sb and Sy, Sz are the first two and last two stops respectively. + * The weight of the first and last stop can be computed as the area of + * the following trapezoids (taken with height 1, since the whole [0-1] + * will have total weight 1 this way): (b+B)*h/2 + * + * +-------+ +---+ + * | |\ / | | + * | | \ / | | + * | | \ / | | + * +-------+---+~~~~~~~+-------+---+ + * 0 Sa Sb Sy Sz 1 + * + * For the first stop: (Sa+Sb)/2 + * For the last stop: ((1-Sz) + (1-Sy))/2 = (2-Sy-Sz)/2 + * Halving the result is done after summing up all the areas. + */ + delta0 = gradient->stops[0].offset + gradient->stops[1].offset; + delta1 = 2.0 - gradient->stops[end-1].offset - gradient->stops[end].offset; + break; + + case CAIRO_EXTEND_PAD: + /* PAD is computed as the average of the first and last stop: + * - take both of them with weight 1 (they will be halved + * after the whole sum has been computed). + * - avoid summing any of the inner stops. + */ + delta0 = delta1 = 1.0; + start = end; + break; + + case CAIRO_EXTEND_NONE: + default: + ASSERT_NOT_REACHED; + _cairo_color_init_rgba (color, 0, 0, 0, 0); + return; + } + + r = delta0 * gradient->stops[0].color.red; + g = delta0 * gradient->stops[0].color.green; + b = delta0 * gradient->stops[0].color.blue; + a = delta0 * gradient->stops[0].color.alpha; + + for (i = start; i < end; ++i) { + /* Inner stops weight is the same as the area of the triangle they influence + * (which goes from the stop before to the stop after), again with height 1 + * since the whole must sum up to 1: b*h/2 + * Halving is done after the whole sum has been computed. + */ + double delta = gradient->stops[i+1].offset - gradient->stops[i-1].offset; + r += delta * gradient->stops[i].color.red; + g += delta * gradient->stops[i].color.green; + b += delta * gradient->stops[i].color.blue; + a += delta * gradient->stops[i].color.alpha; + } + + r += delta1 * gradient->stops[end].color.red; + g += delta1 * gradient->stops[end].color.green; + b += delta1 * gradient->stops[end].color.blue; + a += delta1 * gradient->stops[end].color.alpha; + + _cairo_color_init_rgba (color, r * .5, g * .5, b * .5, a * .5); +} + +/** + * _cairo_pattern_alpha_range: + * + * Convenience function to determine the minimum and maximum alpha in + * the drawn part of a pattern (i.e. ignoring clear parts caused by + * extend modes and/or pattern shape). + * + * If not NULL, out_min and out_max will be set respectively to the + * minimum and maximum alpha value of the pattern. + **/ +void +_cairo_pattern_alpha_range (const cairo_pattern_t *pattern, + double *out_min, + double *out_max) +{ + double alpha_min, alpha_max; + + switch (pattern->type) { + case CAIRO_PATTERN_TYPE_SOLID: { + const cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern; + alpha_min = alpha_max = solid->color.alpha; + break; + } + + case CAIRO_PATTERN_TYPE_LINEAR: + case CAIRO_PATTERN_TYPE_RADIAL: { + const cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *) pattern; + unsigned int i; + + assert (gradient->n_stops >= 1); + + alpha_min = alpha_max = gradient->stops[0].color.alpha; + for (i = 1; i < gradient->n_stops; i++) { + if (alpha_min > gradient->stops[i].color.alpha) + alpha_min = gradient->stops[i].color.alpha; + else if (alpha_max < gradient->stops[i].color.alpha) + alpha_max = gradient->stops[i].color.alpha; + } + + break; + } + + case CAIRO_PATTERN_TYPE_MESH: { + const cairo_mesh_pattern_t *mesh = (const cairo_mesh_pattern_t *) pattern; + const cairo_mesh_patch_t *patch = _cairo_array_index_const (&mesh->patches, 0); + unsigned int i, j, n = _cairo_array_num_elements (&mesh->patches); + + assert (n >= 1); + + alpha_min = alpha_max = patch[0].colors[0].alpha; + for (i = 0; i < n; i++) { + for (j = 0; j < 4; j++) { + if (patch[i].colors[j].alpha < alpha_min) + alpha_min = patch[i].colors[j].alpha; + else if (patch[i].colors[j].alpha > alpha_max) + alpha_max = patch[i].colors[j].alpha; + } + } + + break; + } + + default: + ASSERT_NOT_REACHED; + /* fall through */ + + case CAIRO_PATTERN_TYPE_SURFACE: + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + alpha_min = 0; + alpha_max = 1; + break; + } + + if (out_min) + *out_min = alpha_min; + if (out_max) + *out_max = alpha_max; +} + +/** + * _cairo_mesh_pattern_coord_box: + * + * Convenience function to determine the range of the coordinates of + * the points used to define the patches of the mesh. + * + * This is guaranteed to contain the pattern extents, but might not be + * tight, just like a Bezier curve is always inside the convex hull of + * the control points. + * + * This function cannot be used while the mesh is being constructed. + * + * The function returns TRUE and sets the output parameters to define + * the coordinate range if the mesh pattern contains at least one + * patch, otherwise it returns FALSE. + **/ +cairo_bool_t +_cairo_mesh_pattern_coord_box (const cairo_mesh_pattern_t *mesh, + double *out_xmin, + double *out_ymin, + double *out_xmax, + double *out_ymax) +{ + const cairo_mesh_patch_t *patch; + unsigned int num_patches, i, j, k; + double x0, y0, x1, y1; + + assert (mesh->current_patch == NULL); + + num_patches = _cairo_array_num_elements (&mesh->patches); + + if (num_patches == 0) + return FALSE; + + patch = _cairo_array_index_const (&mesh->patches, 0); + x0 = x1 = patch->points[0][0].x; + y0 = y1 = patch->points[0][0].y; + + for (i = 0; i < num_patches; i++) { + for (j = 0; j < 4; j++) { + for (k = 0; k < 4; k++) { + x0 = MIN (x0, patch[i].points[j][k].x); + y0 = MIN (y0, patch[i].points[j][k].y); + x1 = MAX (x1, patch[i].points[j][k].x); + y1 = MAX (y1, patch[i].points[j][k].y); + } + } + } + + *out_xmin = x0; + *out_ymin = y0; + *out_xmax = x1; + *out_ymax = y1; + + return TRUE; +} + +/** + * _cairo_gradient_pattern_is_solid: + * + * Convenience function to determine whether a gradient pattern is + * a solid color within the given extents. In this case the color + * argument is initialized to the color the pattern represents. + * This functions doesn't handle completely transparent gradients, + * thus it should be called only after _cairo_pattern_is_clear has + * returned FALSE. + * + * Return value: %TRUE if the pattern is a solid color. + **/ +cairo_bool_t +_cairo_gradient_pattern_is_solid (const cairo_gradient_pattern_t *gradient, + const cairo_rectangle_int_t *extents, + cairo_color_t *color) +{ + unsigned int i; + + assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR || + gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL); + + /* TODO: radial */ + if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) { + cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient; + if (_linear_pattern_is_degenerate (linear)) { + _gradient_color_average (gradient, color); + return TRUE; + } + + if (gradient->base.extend == CAIRO_EXTEND_NONE) { + double t[2]; + + /* We already know that the pattern is not clear, thus if some + * part of it is clear, the whole is not solid. + */ + + if (extents == NULL) + return FALSE; + + _cairo_linear_pattern_box_to_parameter (linear, + extents->x, + extents->y, + extents->x + extents->width, + extents->y + extents->height, + t); + + if (t[0] < 0.0 || t[1] > 1.0) + return FALSE; + } + } else + return FALSE; + + for (i = 1; i < gradient->n_stops; i++) + if (! _cairo_color_stop_equal (&gradient->stops[0].color, + &gradient->stops[i].color)) + return FALSE; + + _cairo_color_init_rgba (color, + gradient->stops[0].color.red, + gradient->stops[0].color.green, + gradient->stops[0].color.blue, + gradient->stops[0].color.alpha); + + return TRUE; +} + +/** + * _cairo_pattern_is_constant_alpha: + * + * Convenience function to determine whether a pattern has constant + * alpha within the given extents. In this case the alpha argument is + * initialized to the alpha within the extents. + * + * Return value: %TRUE if the pattern has constant alpha. + **/ +cairo_bool_t +_cairo_pattern_is_constant_alpha (const cairo_pattern_t *abstract_pattern, + const cairo_rectangle_int_t *extents, + double *alpha) +{ + const cairo_pattern_union_t *pattern; + cairo_color_t color; + + if (_cairo_pattern_is_clear (abstract_pattern)) { + *alpha = 0.0; + return TRUE; + } + + if (_cairo_pattern_is_opaque (abstract_pattern, extents)) { + *alpha = 1.0; + return TRUE; + } + + pattern = (cairo_pattern_union_t *) abstract_pattern; + switch (pattern->base.type) { + case CAIRO_PATTERN_TYPE_SOLID: + *alpha = pattern->solid.color.alpha; + return TRUE; + + case CAIRO_PATTERN_TYPE_LINEAR: + case CAIRO_PATTERN_TYPE_RADIAL: + if (_cairo_gradient_pattern_is_solid (&pattern->gradient.base, extents, &color)) { + *alpha = color.alpha; + return TRUE; + } else { + return FALSE; + } + + /* TODO: need to test these as well */ + case CAIRO_PATTERN_TYPE_SURFACE: + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + case CAIRO_PATTERN_TYPE_MESH: + return FALSE; + } + + ASSERT_NOT_REACHED; + return FALSE; +} + +static cairo_bool_t +_mesh_is_clear (const cairo_mesh_pattern_t *mesh) +{ + double x1, y1, x2, y2; + cairo_bool_t is_valid; + + is_valid = _cairo_mesh_pattern_coord_box (mesh, &x1, &y1, &x2, &y2); + if (!is_valid) + return TRUE; + + if (x2 - x1 < DBL_EPSILON || y2 - y1 < DBL_EPSILON) + return TRUE; + + return FALSE; +} + +/** + * _cairo_pattern_is_opaque_solid: + * + * Convenience function to determine whether a pattern is an opaque + * (alpha==1.0) solid color pattern. This is done by testing whether + * the pattern's alpha value when converted to a byte is 255, so if a + * backend actually supported deep alpha channels this function might + * not do the right thing. + * + * Return value: %TRUE if the pattern is an opaque, solid color. + **/ +cairo_bool_t +_cairo_pattern_is_opaque_solid (const cairo_pattern_t *pattern) +{ + cairo_solid_pattern_t *solid; + + if (pattern->type != CAIRO_PATTERN_TYPE_SOLID) + return FALSE; + + solid = (cairo_solid_pattern_t *) pattern; + + return CAIRO_COLOR_IS_OPAQUE (&solid->color); +} + +static cairo_bool_t +_surface_is_opaque (const cairo_surface_pattern_t *pattern, + const cairo_rectangle_int_t *sample) +{ + cairo_rectangle_int_t extents; + + if (pattern->surface->content & CAIRO_CONTENT_ALPHA) + return FALSE; + + if (pattern->base.extend != CAIRO_EXTEND_NONE) + return TRUE; + + if (! _cairo_surface_get_extents (pattern->surface, &extents)) + return TRUE; + + if (sample == NULL) + return FALSE; + + return _cairo_rectangle_contains_rectangle (&extents, sample); +} + +static cairo_bool_t +_raster_source_is_opaque (const cairo_raster_source_pattern_t *pattern, + const cairo_rectangle_int_t *sample) +{ + if (pattern->content & CAIRO_CONTENT_ALPHA) + return FALSE; + + if (pattern->base.extend != CAIRO_EXTEND_NONE) + return TRUE; + + if (sample == NULL) + return FALSE; + + return _cairo_rectangle_contains_rectangle (&pattern->extents, sample); +} + +static cairo_bool_t +_surface_is_clear (const cairo_surface_pattern_t *pattern) +{ + cairo_rectangle_int_t extents; + + if (_cairo_surface_get_extents (pattern->surface, &extents) && + (extents.width == 0 || extents.height == 0)) + return TRUE; + + return pattern->surface->is_clear && + pattern->surface->content & CAIRO_CONTENT_ALPHA; +} + +static cairo_bool_t +_raster_source_is_clear (const cairo_raster_source_pattern_t *pattern) +{ + return pattern->extents.width == 0 || pattern->extents.height == 0; +} + +static cairo_bool_t +_gradient_is_opaque (const cairo_gradient_pattern_t *gradient, + const cairo_rectangle_int_t *sample) +{ + unsigned int i; + + assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR || + gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL); + + if (gradient->n_stops == 0 || + (gradient->base.extend == CAIRO_EXTEND_NONE && + gradient->stops[0].offset == gradient->stops[gradient->n_stops - 1].offset)) + return FALSE; + + if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) { + if (gradient->base.extend == CAIRO_EXTEND_NONE) { + double t[2]; + cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient; + + /* EXTEND_NONE degenerate radial gradients are clear */ + if (_linear_pattern_is_degenerate (linear)) + return FALSE; + + if (sample == NULL) + return FALSE; + + _cairo_linear_pattern_box_to_parameter (linear, + sample->x, + sample->y, + sample->x + sample->width, + sample->y + sample->height, + t); + + if (t[0] < 0.0 || t[1] > 1.0) + return FALSE; + } + } else + return FALSE; /* TODO: check actual intersection */ + + for (i = 0; i < gradient->n_stops; i++) + if (! CAIRO_COLOR_IS_OPAQUE (&gradient->stops[i].color)) + return FALSE; + + return TRUE; +} + +/** + * _cairo_pattern_is_opaque: + * + * Convenience function to determine whether a pattern is an opaque + * pattern (of any type). The same caveats that apply to + * _cairo_pattern_is_opaque_solid apply here as well. + * + * Return value: %TRUE if the pattern is a opaque. + **/ +cairo_bool_t +_cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern, + const cairo_rectangle_int_t *sample) +{ + const cairo_pattern_union_t *pattern; + + if (abstract_pattern->has_component_alpha) + return FALSE; + + pattern = (cairo_pattern_union_t *) abstract_pattern; + switch (pattern->base.type) { + case CAIRO_PATTERN_TYPE_SOLID: + return _cairo_pattern_is_opaque_solid (abstract_pattern); + case CAIRO_PATTERN_TYPE_SURFACE: + return _surface_is_opaque (&pattern->surface, sample); + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + return _raster_source_is_opaque (&pattern->raster_source, sample); + case CAIRO_PATTERN_TYPE_LINEAR: + case CAIRO_PATTERN_TYPE_RADIAL: + return _gradient_is_opaque (&pattern->gradient.base, sample); + case CAIRO_PATTERN_TYPE_MESH: + return FALSE; + } + + ASSERT_NOT_REACHED; + return FALSE; +} + +cairo_bool_t +_cairo_pattern_is_clear (const cairo_pattern_t *abstract_pattern) +{ + const cairo_pattern_union_t *pattern; + + if (abstract_pattern->has_component_alpha) + return FALSE; + + pattern = (cairo_pattern_union_t *) abstract_pattern; + switch (abstract_pattern->type) { + case CAIRO_PATTERN_TYPE_SOLID: + return CAIRO_COLOR_IS_CLEAR (&pattern->solid.color); + case CAIRO_PATTERN_TYPE_SURFACE: + return _surface_is_clear (&pattern->surface); + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + return _raster_source_is_clear (&pattern->raster_source); + case CAIRO_PATTERN_TYPE_LINEAR: + case CAIRO_PATTERN_TYPE_RADIAL: + return _gradient_is_clear (&pattern->gradient.base, NULL); + case CAIRO_PATTERN_TYPE_MESH: + return _mesh_is_clear (&pattern->mesh); + } + + ASSERT_NOT_REACHED; + return FALSE; +} + +/* + * Will given row of back-translation matrix work with bilinear scale? + * This is true for scales larger than 1. Also it was judged acceptable + * for scales larger than .75. And if there is integer translation + * then a scale of exactly .5 works. + */ +static int +use_bilinear(double x, double y, double t) +{ + /* This is the inverse matrix! */ + double h = x*x + y*y; + if (h < 1.0 / (0.75 * 0.75)) + return TRUE; /* scale > .75 */ + if ((h > 3.99 && h < 4.01) /* scale is 1/2 */ + && !_cairo_fixed_from_double(x*y) /* parallel to an axis */ + && _cairo_fixed_is_integer (_cairo_fixed_from_double (t))) + return TRUE; + return FALSE; +} + +/** + * _cairo_pattern_analyze_filter: + * @pattern: surface pattern + * + * Possibly optimize the filter to a simpler value depending on transformation + * + * Returns: the optimized #cairo_filter_t to use with @pattern. + **/ +cairo_filter_t +_cairo_pattern_analyze_filter (const cairo_pattern_t *pattern) +{ + switch (pattern->filter) { + case CAIRO_FILTER_GOOD: + case CAIRO_FILTER_BEST: + case CAIRO_FILTER_BILINEAR: + case CAIRO_FILTER_FAST: + /* If source pixels map 1:1 onto destination pixels, we do + * not need to filter (and do not want to filter, since it + * will cause blurriness) + */ + if (_cairo_matrix_is_pixel_exact (&pattern->matrix)) { + return CAIRO_FILTER_NEAREST; + } else { + /* Use BILINEAR for any scale greater than .75 instead + * of GOOD. For scales of 1 and larger this is identical, + * for the smaller sizes it was judged that the artifacts + * were not worse than the artifacts from a box filer. + * BILINEAR can also be used if the scale is exactly .5 + * and the translation in that direction is an integer. + */ + if (pattern->filter == CAIRO_FILTER_GOOD && + use_bilinear (pattern->matrix.xx, pattern->matrix.xy, + pattern->matrix.x0) && + use_bilinear (pattern->matrix.yx, pattern->matrix.yy, + pattern->matrix.y0)) + return CAIRO_FILTER_BILINEAR; + } + break; + + case CAIRO_FILTER_NEAREST: + case CAIRO_FILTER_GAUSSIAN: + default: + break; + } + + return pattern->filter; +} + +/** + * _cairo_hypot: + * Returns: value similar to hypot(@x,@y) + * + * May want to replace this with Manhattan distance (abs(x)+abs(y)) if + * hypot is too slow, as there is no need for accuracy here. + **/ +static inline double +_cairo_hypot(double x, double y) +{ + return hypot(x, y); +} + +/** + * _cairo_pattern_sampled_area: + * + * Return region of @pattern that will be sampled to fill @extents, + * based on the transformation and filter. + * + * This does not include pixels that are mulitiplied by values very + * close to zero by the ends of filters. This is so that transforms + * that should be the identity or 90 degree rotations do not expand + * the source unexpectedly. + * + * XXX: We don't actually have any way of querying the backend for + * the filter radius, so we just guess base on what we know that + * backends do currently (see bug #10508) + **/ +void +_cairo_pattern_sampled_area (const cairo_pattern_t *pattern, + const cairo_rectangle_int_t *extents, + cairo_rectangle_int_t *sample) +{ + double x1, x2, y1, y2; + double padx, pady; + + /* Assume filters are interpolating, which means identity + cannot change the image */ + if (_cairo_matrix_is_identity (&pattern->matrix)) { + *sample = *extents; + return; + } + + /* Transform the centers of the corner pixels */ + x1 = extents->x + 0.5; + y1 = extents->y + 0.5; + x2 = x1 + (extents->width - 1); + y2 = y1 + (extents->height - 1); + _cairo_matrix_transform_bounding_box (&pattern->matrix, + &x1, &y1, &x2, &y2, + NULL); + + /* How far away from center will it actually sample? + * This is the distance from a transformed pixel center to the + * furthest sample of reasonable size. + */ + switch (pattern->filter) { + case CAIRO_FILTER_NEAREST: + case CAIRO_FILTER_FAST: + /* Correct value is zero, but when the sample is on an integer + * it is unknown if the backend will sample the pixel to the + * left or right. This value makes it include both possible pixels. + */ + padx = pady = 0.004; + break; + case CAIRO_FILTER_BILINEAR: + case CAIRO_FILTER_GAUSSIAN: + default: + /* Correct value is .5 */ + padx = pady = 0.495; + break; + case CAIRO_FILTER_GOOD: + /* Correct value is max(width,1)*.5 */ + padx = _cairo_hypot (pattern->matrix.xx, pattern->matrix.xy); + if (padx <= 1.0) padx = 0.495; + else if (padx >= 16.0) padx = 7.92; + else padx *= 0.495; + pady = _cairo_hypot (pattern->matrix.yx, pattern->matrix.yy); + if (pady <= 1.0) pady = 0.495; + else if (pady >= 16.0) pady = 7.92; + else pady *= 0.495; + break; + case CAIRO_FILTER_BEST: + /* Correct value is width*2 */ + padx = _cairo_hypot (pattern->matrix.xx, pattern->matrix.xy) * 1.98; + if (padx > 7.92) padx = 7.92; + pady = _cairo_hypot (pattern->matrix.yx, pattern->matrix.yy) * 1.98; + if (pady > 7.92) pady = 7.92; + break; + } + + /* round furthest samples to edge of pixels */ + x1 = floor (x1 - padx); + if (x1 < CAIRO_RECT_INT_MIN) x1 = CAIRO_RECT_INT_MIN; + sample->x = x1; + + y1 = floor (y1 - pady); + if (y1 < CAIRO_RECT_INT_MIN) y1 = CAIRO_RECT_INT_MIN; + sample->y = y1; + + x2 = floor (x2 + padx) + 1.0; + if (x2 > CAIRO_RECT_INT_MAX) x2 = CAIRO_RECT_INT_MAX; + sample->width = x2 - x1; + + y2 = floor (y2 + pady) + 1.0; + if (y2 > CAIRO_RECT_INT_MAX) y2 = CAIRO_RECT_INT_MAX; + sample->height = y2 - y1; +} + +/** + * _cairo_pattern_get_extents: + * + * Return the "target-space" extents of @pattern in @extents. + * + * For unbounded patterns, the @extents will be initialized with + * "infinite" extents, (minimum and maximum fixed-point values). + * + * When is_vector is TRUE, avoid rounding to zero widths or heights that + * are less than 1 unit. + * + * XXX: Currently, bounded gradient patterns will also return + * "infinite" extents, though it would be possible to optimize these + * with a little more work. + **/ +void +_cairo_pattern_get_extents (const cairo_pattern_t *pattern, + cairo_rectangle_int_t *extents, + cairo_bool_t is_vector) +{ + double x1, y1, x2, y2; + int ix1, ix2, iy1, iy2; + cairo_bool_t round_x = FALSE; + cairo_bool_t round_y = FALSE; + + switch (pattern->type) { + case CAIRO_PATTERN_TYPE_SOLID: + goto UNBOUNDED; + + case CAIRO_PATTERN_TYPE_SURFACE: + { + cairo_rectangle_int_t surface_extents; + const cairo_surface_pattern_t *surface_pattern = + (const cairo_surface_pattern_t *) pattern; + cairo_surface_t *surface = surface_pattern->surface; + + if (! _cairo_surface_get_extents (surface, &surface_extents)) + goto UNBOUNDED; + + if (surface_extents.width == 0 || surface_extents.height == 0) + goto EMPTY; + + if (pattern->extend != CAIRO_EXTEND_NONE) + goto UNBOUNDED; + + x1 = surface_extents.x; + y1 = surface_extents.y; + x2 = surface_extents.x + (int) surface_extents.width; + y2 = surface_extents.y + (int) surface_extents.height; + + goto HANDLE_FILTER; + } + break; + + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + { + const cairo_raster_source_pattern_t *raster = + (const cairo_raster_source_pattern_t *) pattern; + + if (raster->extents.width == 0 || raster->extents.height == 0) + goto EMPTY; + + if (pattern->extend != CAIRO_EXTEND_NONE) + goto UNBOUNDED; + + x1 = raster->extents.x; + y1 = raster->extents.y; + x2 = raster->extents.x + (int) raster->extents.width; + y2 = raster->extents.y + (int) raster->extents.height; + } + HANDLE_FILTER: + switch (pattern->filter) { + case CAIRO_FILTER_NEAREST: + case CAIRO_FILTER_FAST: + round_x = round_y = TRUE; + /* We don't know which way .5 will go, so fudge it slightly. */ + x1 -= 0.004; + y1 -= 0.004; + x2 += 0.004; + y2 += 0.004; + break; + case CAIRO_FILTER_BEST: + /* Assume best filter will produce nice antialiased edges */ + break; + case CAIRO_FILTER_BILINEAR: + case CAIRO_FILTER_GAUSSIAN: + case CAIRO_FILTER_GOOD: + default: + /* These filters can blur the edge out 1/2 pixel when scaling up */ + if (_cairo_hypot (pattern->matrix.xx, pattern->matrix.yx) < 1.0) { + x1 -= 0.5; + x2 += 0.5; + round_x = TRUE; + } + if (_cairo_hypot (pattern->matrix.xy, pattern->matrix.yy) < 1.0) { + y1 -= 0.5; + y2 += 0.5; + round_y = TRUE; + } + break; + } + break; + + case CAIRO_PATTERN_TYPE_RADIAL: + { + const cairo_radial_pattern_t *radial = + (const cairo_radial_pattern_t *) pattern; + double cx1, cy1; + double cx2, cy2; + double r1, r2; + + if (_radial_pattern_is_degenerate (radial)) { + /* cairo-gstate should have optimised degenerate + * patterns to solid clear patterns, so we can ignore + * them here. */ + goto EMPTY; + } + + /* TODO: in some cases (focus outside/on the circle) it is + * half-bounded. */ + if (pattern->extend != CAIRO_EXTEND_NONE) + goto UNBOUNDED; + + cx1 = radial->cd1.center.x; + cy1 = radial->cd1.center.y; + r1 = radial->cd1.radius; + + cx2 = radial->cd2.center.x; + cy2 = radial->cd2.center.y; + r2 = radial->cd2.radius; + + x1 = MIN (cx1 - r1, cx2 - r2); + y1 = MIN (cy1 - r1, cy2 - r2); + x2 = MAX (cx1 + r1, cx2 + r2); + y2 = MAX (cy1 + r1, cy2 + r2); + } + break; + + case CAIRO_PATTERN_TYPE_LINEAR: + { + const cairo_linear_pattern_t *linear = + (const cairo_linear_pattern_t *) pattern; + + if (pattern->extend != CAIRO_EXTEND_NONE) + goto UNBOUNDED; + + if (_linear_pattern_is_degenerate (linear)) { + /* cairo-gstate should have optimised degenerate + * patterns to solid ones, so we can again ignore + * them here. */ + goto EMPTY; + } + + /* TODO: to get tight extents, use the matrix to transform + * the pattern instead of transforming the extents later. */ + if (pattern->matrix.xy != 0. || pattern->matrix.yx != 0.) + goto UNBOUNDED; + + if (linear->pd1.x == linear->pd2.x) { + x1 = -HUGE_VAL; + x2 = HUGE_VAL; + y1 = MIN (linear->pd1.y, linear->pd2.y); + y2 = MAX (linear->pd1.y, linear->pd2.y); + } else if (linear->pd1.y == linear->pd2.y) { + x1 = MIN (linear->pd1.x, linear->pd2.x); + x2 = MAX (linear->pd1.x, linear->pd2.x); + y1 = -HUGE_VAL; + y2 = HUGE_VAL; + } else { + goto UNBOUNDED; + } + + /* The current linear renderer just point-samples in the middle + of the pixels, similar to the NEAREST filter: */ + round_x = round_y = TRUE; + } + break; + + case CAIRO_PATTERN_TYPE_MESH: + { + const cairo_mesh_pattern_t *mesh = + (const cairo_mesh_pattern_t *) pattern; + if (! _cairo_mesh_pattern_coord_box (mesh, &x1, &y1, &x2, &y2)) + goto EMPTY; + } + break; + + default: + ASSERT_NOT_REACHED; + } + + if (_cairo_matrix_is_translation (&pattern->matrix)) { + x1 -= pattern->matrix.x0; x2 -= pattern->matrix.x0; + y1 -= pattern->matrix.y0; y2 -= pattern->matrix.y0; + } else { + cairo_matrix_t imatrix; + cairo_status_t status; + + imatrix = pattern->matrix; + status = cairo_matrix_invert (&imatrix); + /* cairo_pattern_set_matrix ensures the matrix is invertible */ + assert (status == CAIRO_STATUS_SUCCESS); + + _cairo_matrix_transform_bounding_box (&imatrix, + &x1, &y1, &x2, &y2, + NULL); + } + + if (!round_x) { + x1 -= 0.5; + x2 += 0.5; + } + if (x1 < CAIRO_RECT_INT_MIN) + ix1 = CAIRO_RECT_INT_MIN; + else + ix1 = _cairo_lround (x1); + if (x2 > CAIRO_RECT_INT_MAX) + ix2 = CAIRO_RECT_INT_MAX; + else + ix2 = _cairo_lround (x2); + extents->x = ix1; extents->width = ix2 - ix1; + if (is_vector && extents->width == 0 && x1 != x2) + extents->width += 1; + + if (!round_y) { + y1 -= 0.5; + y2 += 0.5; + } + if (y1 < CAIRO_RECT_INT_MIN) + iy1 = CAIRO_RECT_INT_MIN; + else + iy1 = _cairo_lround (y1); + if (y2 > CAIRO_RECT_INT_MAX) + iy2 = CAIRO_RECT_INT_MAX; + else + iy2 = _cairo_lround (y2); + extents->y = iy1; extents->height = iy2 - iy1; + if (is_vector && extents->height == 0 && y1 != y2) + extents->height += 1; + + return; + + UNBOUNDED: + /* unbounded patterns -> 'infinite' extents */ + _cairo_unbounded_rectangle_init (extents); + return; + + EMPTY: + extents->x = extents->y = 0; + extents->width = extents->height = 0; + return; +} + +/** + * _cairo_pattern_get_ink_extents: + * + * Return the "target-space" inked extents of @pattern in @extents. + **/ +cairo_int_status_t +_cairo_pattern_get_ink_extents (const cairo_pattern_t *pattern, + cairo_rectangle_int_t *extents) +{ + if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE && + pattern->extend == CAIRO_EXTEND_NONE) + { + const cairo_surface_pattern_t *surface_pattern = + (const cairo_surface_pattern_t *) pattern; + cairo_surface_t *surface = surface_pattern->surface; + + surface = _cairo_surface_get_source (surface, NULL); + if (_cairo_surface_is_recording (surface)) { + cairo_matrix_t imatrix; + cairo_box_t box; + cairo_status_t status; + + imatrix = pattern->matrix; + status = cairo_matrix_invert (&imatrix); + /* cairo_pattern_set_matrix ensures the matrix is invertible */ + assert (status == CAIRO_STATUS_SUCCESS); + + status = _cairo_recording_surface_get_ink_bbox ((cairo_recording_surface_t *)surface, + &box, &imatrix); + if (unlikely (status)) + return status; + + _cairo_box_round_to_rectangle (&box, extents); + return CAIRO_STATUS_SUCCESS; + } + } + + _cairo_pattern_get_extents (pattern, extents, TRUE); + return CAIRO_STATUS_SUCCESS; +} + +static uintptr_t +_cairo_solid_pattern_hash (uintptr_t hash, + const cairo_solid_pattern_t *solid) +{ + hash = _cairo_hash_bytes (hash, &solid->color, sizeof (solid->color)); + + return hash; +} + +static uintptr_t +_cairo_gradient_color_stops_hash (uintptr_t hash, + const cairo_gradient_pattern_t *gradient) +{ + unsigned int n; + + hash = _cairo_hash_bytes (hash, + &gradient->n_stops, + sizeof (gradient->n_stops)); + + for (n = 0; n < gradient->n_stops; n++) { + hash = _cairo_hash_bytes (hash, + &gradient->stops[n].offset, + sizeof (double)); + hash = _cairo_hash_bytes (hash, + &gradient->stops[n].color, + sizeof (cairo_color_stop_t)); + } + + return hash; +} + +uintptr_t +_cairo_linear_pattern_hash (uintptr_t hash, + const cairo_linear_pattern_t *linear) +{ + hash = _cairo_hash_bytes (hash, &linear->pd1, sizeof (linear->pd1)); + hash = _cairo_hash_bytes (hash, &linear->pd2, sizeof (linear->pd2)); + + return _cairo_gradient_color_stops_hash (hash, &linear->base); +} + +uintptr_t +_cairo_radial_pattern_hash (uintptr_t hash, + const cairo_radial_pattern_t *radial) +{ + hash = _cairo_hash_bytes (hash, &radial->cd1.center, sizeof (radial->cd1.center)); + hash = _cairo_hash_bytes (hash, &radial->cd1.radius, sizeof (radial->cd1.radius)); + hash = _cairo_hash_bytes (hash, &radial->cd2.center, sizeof (radial->cd2.center)); + hash = _cairo_hash_bytes (hash, &radial->cd2.radius, sizeof (radial->cd2.radius)); + + return _cairo_gradient_color_stops_hash (hash, &radial->base); +} + +static uintptr_t +_cairo_mesh_pattern_hash (uintptr_t hash, const cairo_mesh_pattern_t *mesh) +{ + const cairo_mesh_patch_t *patch = _cairo_array_index_const (&mesh->patches, 0); + unsigned int i, n = _cairo_array_num_elements (&mesh->patches); + + for (i = 0; i < n; i++) + hash = _cairo_hash_bytes (hash, patch + i, sizeof (cairo_mesh_patch_t)); + + return hash; +} + +static uintptr_t +_cairo_surface_pattern_hash (uintptr_t hash, + const cairo_surface_pattern_t *surface) +{ + hash ^= surface->surface->unique_id; + + return hash; +} + +static uintptr_t +_cairo_raster_source_pattern_hash (uintptr_t hash, + const cairo_raster_source_pattern_t *raster) +{ + hash ^= (uintptr_t)raster->user_data; + + return hash; +} + +uintptr_t +_cairo_pattern_hash (const cairo_pattern_t *pattern) +{ + uintptr_t hash = _CAIRO_HASH_INIT_VALUE; + + if (pattern->status) + return 0; + + hash = _cairo_hash_bytes (hash, &pattern->type, sizeof (pattern->type)); + if (pattern->type != CAIRO_PATTERN_TYPE_SOLID) { + hash = _cairo_hash_bytes (hash, + &pattern->matrix, sizeof (pattern->matrix)); + hash = _cairo_hash_bytes (hash, + &pattern->filter, sizeof (pattern->filter)); + hash = _cairo_hash_bytes (hash, + &pattern->extend, sizeof (pattern->extend)); + hash = _cairo_hash_bytes (hash, + &pattern->has_component_alpha, + sizeof (pattern->has_component_alpha)); + } + + switch (pattern->type) { + case CAIRO_PATTERN_TYPE_SOLID: + return _cairo_solid_pattern_hash (hash, (cairo_solid_pattern_t *) pattern); + case CAIRO_PATTERN_TYPE_LINEAR: + return _cairo_linear_pattern_hash (hash, (cairo_linear_pattern_t *) pattern); + case CAIRO_PATTERN_TYPE_RADIAL: + return _cairo_radial_pattern_hash (hash, (cairo_radial_pattern_t *) pattern); + case CAIRO_PATTERN_TYPE_MESH: + return _cairo_mesh_pattern_hash (hash, (cairo_mesh_pattern_t *) pattern); + case CAIRO_PATTERN_TYPE_SURFACE: + return _cairo_surface_pattern_hash (hash, (cairo_surface_pattern_t *) pattern); + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + return _cairo_raster_source_pattern_hash (hash, (cairo_raster_source_pattern_t *) pattern); + default: + ASSERT_NOT_REACHED; + return FALSE; + } +} + +static cairo_bool_t +_cairo_solid_pattern_equal (const cairo_solid_pattern_t *a, + const cairo_solid_pattern_t *b) +{ + return _cairo_color_equal (&a->color, &b->color); +} + +static cairo_bool_t +_cairo_gradient_color_stops_equal (const cairo_gradient_pattern_t *a, + const cairo_gradient_pattern_t *b) +{ + unsigned int n; + + if (a->n_stops != b->n_stops) + return FALSE; + + for (n = 0; n < a->n_stops; n++) { + if (a->stops[n].offset != b->stops[n].offset) + return FALSE; + if (! _cairo_color_stop_equal (&a->stops[n].color, &b->stops[n].color)) + return FALSE; + } + + return TRUE; +} + +cairo_bool_t +_cairo_linear_pattern_equal (const cairo_linear_pattern_t *a, + const cairo_linear_pattern_t *b) +{ + if (a->pd1.x != b->pd1.x) + return FALSE; + + if (a->pd1.y != b->pd1.y) + return FALSE; + + if (a->pd2.x != b->pd2.x) + return FALSE; + + if (a->pd2.y != b->pd2.y) + return FALSE; + + return _cairo_gradient_color_stops_equal (&a->base, &b->base); +} + +cairo_bool_t +_cairo_radial_pattern_equal (const cairo_radial_pattern_t *a, + const cairo_radial_pattern_t *b) +{ + if (a->cd1.center.x != b->cd1.center.x) + return FALSE; + + if (a->cd1.center.y != b->cd1.center.y) + return FALSE; + + if (a->cd1.radius != b->cd1.radius) + return FALSE; + + if (a->cd2.center.x != b->cd2.center.x) + return FALSE; + + if (a->cd2.center.y != b->cd2.center.y) + return FALSE; + + if (a->cd2.radius != b->cd2.radius) + return FALSE; + + return _cairo_gradient_color_stops_equal (&a->base, &b->base); +} + +static cairo_bool_t +_cairo_mesh_pattern_equal (const cairo_mesh_pattern_t *a, + const cairo_mesh_pattern_t *b) +{ + const cairo_mesh_patch_t *patch_a, *patch_b; + unsigned int i, num_patches_a, num_patches_b; + + num_patches_a = _cairo_array_num_elements (&a->patches); + num_patches_b = _cairo_array_num_elements (&b->patches); + + if (num_patches_a != num_patches_b) + return FALSE; + + for (i = 0; i < num_patches_a; i++) { + patch_a = _cairo_array_index_const (&a->patches, i); + patch_b = _cairo_array_index_const (&b->patches, i); + if (memcmp (patch_a, patch_b, sizeof(cairo_mesh_patch_t)) != 0) + return FALSE; + } + + return TRUE; +} + +static cairo_bool_t +_cairo_surface_pattern_equal (const cairo_surface_pattern_t *a, + const cairo_surface_pattern_t *b) +{ + return a->surface->unique_id == b->surface->unique_id; +} + +static cairo_bool_t +_cairo_raster_source_pattern_equal (const cairo_raster_source_pattern_t *a, + const cairo_raster_source_pattern_t *b) +{ + return a->user_data == b->user_data; +} + +cairo_bool_t +_cairo_pattern_equal (const cairo_pattern_t *a, const cairo_pattern_t *b) +{ + if (a->status || b->status) + return FALSE; + + if (a == b) + return TRUE; + + if (a->type != b->type) + return FALSE; + + if (a->has_component_alpha != b->has_component_alpha) + return FALSE; + + if (a->type != CAIRO_PATTERN_TYPE_SOLID) { + if (memcmp (&a->matrix, &b->matrix, sizeof (cairo_matrix_t))) + return FALSE; + + if (a->filter != b->filter) + return FALSE; + + if (a->extend != b->extend) + return FALSE; + } + + switch (a->type) { + case CAIRO_PATTERN_TYPE_SOLID: + return _cairo_solid_pattern_equal ((cairo_solid_pattern_t *) a, + (cairo_solid_pattern_t *) b); + case CAIRO_PATTERN_TYPE_LINEAR: + return _cairo_linear_pattern_equal ((cairo_linear_pattern_t *) a, + (cairo_linear_pattern_t *) b); + case CAIRO_PATTERN_TYPE_RADIAL: + return _cairo_radial_pattern_equal ((cairo_radial_pattern_t *) a, + (cairo_radial_pattern_t *) b); + case CAIRO_PATTERN_TYPE_MESH: + return _cairo_mesh_pattern_equal ((cairo_mesh_pattern_t *) a, + (cairo_mesh_pattern_t *) b); + case CAIRO_PATTERN_TYPE_SURFACE: + return _cairo_surface_pattern_equal ((cairo_surface_pattern_t *) a, + (cairo_surface_pattern_t *) b); + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + return _cairo_raster_source_pattern_equal ((cairo_raster_source_pattern_t *) a, + (cairo_raster_source_pattern_t *) b); + default: + ASSERT_NOT_REACHED; + return FALSE; + } +} + +/** + * cairo_pattern_get_rgba: + * @pattern: a #cairo_pattern_t + * @red: return value for red component of color, or %NULL + * @green: return value for green component of color, or %NULL + * @blue: return value for blue component of color, or %NULL + * @alpha: return value for alpha component of color, or %NULL + * + * Gets the solid color for a solid color pattern. + * + * Note that the color and alpha values are not premultiplied. + * + * Return value: %CAIRO_STATUS_SUCCESS, or + * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if the pattern is not a solid + * color pattern. + * + * Since: 1.4 + **/ +cairo_status_t +cairo_pattern_get_rgba (cairo_pattern_t *pattern, + double *red, double *green, + double *blue, double *alpha) +{ + cairo_solid_pattern_t *solid = (cairo_solid_pattern_t*) pattern; + double r0, g0, b0, a0; + + if (pattern->status) + return pattern->status; + + if (pattern->type != CAIRO_PATTERN_TYPE_SOLID) + return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH); + + _cairo_color_get_rgba (&solid->color, &r0, &g0, &b0, &a0); + + if (red) + *red = r0; + if (green) + *green = g0; + if (blue) + *blue = b0; + if (alpha) + *alpha = a0; + + return CAIRO_STATUS_SUCCESS; +} + +/** + * cairo_pattern_get_surface: + * @pattern: a #cairo_pattern_t + * @surface: return value for surface of pattern, or %NULL + * + * Gets the surface of a surface pattern. The reference returned in + * @surface is owned by the pattern; the caller should call + * cairo_surface_reference() if the surface is to be retained. + * + * Return value: %CAIRO_STATUS_SUCCESS, or + * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if the pattern is not a surface + * pattern. + * + * Since: 1.4 + **/ +cairo_status_t +cairo_pattern_get_surface (cairo_pattern_t *pattern, + cairo_surface_t **surface) +{ + cairo_surface_pattern_t *spat = (cairo_surface_pattern_t*) pattern; + + if (pattern->status) + return pattern->status; + + if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE) + return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH); + + if (surface) + *surface = spat->surface; + + return CAIRO_STATUS_SUCCESS; +} + +/** + * cairo_pattern_get_color_stop_rgba: + * @pattern: a #cairo_pattern_t + * @index: index of the stop to return data for + * @offset: return value for the offset of the stop, or %NULL + * @red: return value for red component of color, or %NULL + * @green: return value for green component of color, or %NULL + * @blue: return value for blue component of color, or %NULL + * @alpha: return value for alpha component of color, or %NULL + * + * Gets the color and offset information at the given @index for a + * gradient pattern. Values of @index range from 0 to n-1 + * where n is the number returned + * by cairo_pattern_get_color_stop_count(). + * + * Note that the color and alpha values are not premultiplied. + * + * Return value: %CAIRO_STATUS_SUCCESS, or %CAIRO_STATUS_INVALID_INDEX + * if @index is not valid for the given pattern. If the pattern is + * not a gradient pattern, %CAIRO_STATUS_PATTERN_TYPE_MISMATCH is + * returned. + * + * Since: 1.4 + **/ +cairo_status_t +cairo_pattern_get_color_stop_rgba (cairo_pattern_t *pattern, + int index, double *offset, + double *red, double *green, + double *blue, double *alpha) +{ + cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t*) pattern; + + if (pattern->status) + return pattern->status; + + if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR && + pattern->type != CAIRO_PATTERN_TYPE_RADIAL) + return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH); + + if (index < 0 || (unsigned int) index >= gradient->n_stops) + return _cairo_error (CAIRO_STATUS_INVALID_INDEX); + + if (offset) + *offset = gradient->stops[index].offset; + if (red) + *red = gradient->stops[index].color.red; + if (green) + *green = gradient->stops[index].color.green; + if (blue) + *blue = gradient->stops[index].color.blue; + if (alpha) + *alpha = gradient->stops[index].color.alpha; + + return CAIRO_STATUS_SUCCESS; +} + +/** + * cairo_pattern_get_color_stop_count: + * @pattern: a #cairo_pattern_t + * @count: return value for the number of color stops, or %NULL + * + * Gets the number of color stops specified in the given gradient + * pattern. + * + * Return value: %CAIRO_STATUS_SUCCESS, or + * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if @pattern is not a gradient + * pattern. + * + * Since: 1.4 + **/ +cairo_status_t +cairo_pattern_get_color_stop_count (cairo_pattern_t *pattern, + int *count) +{ + cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t*) pattern; + + if (pattern->status) + return pattern->status; + + if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR && + pattern->type != CAIRO_PATTERN_TYPE_RADIAL) + return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH); + + if (count) + *count = gradient->n_stops; + + return CAIRO_STATUS_SUCCESS; +} + +/** + * cairo_pattern_get_linear_points: + * @pattern: a #cairo_pattern_t + * @x0: return value for the x coordinate of the first point, or %NULL + * @y0: return value for the y coordinate of the first point, or %NULL + * @x1: return value for the x coordinate of the second point, or %NULL + * @y1: return value for the y coordinate of the second point, or %NULL + * + * Gets the gradient endpoints for a linear gradient. + * + * Return value: %CAIRO_STATUS_SUCCESS, or + * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if @pattern is not a linear + * gradient pattern. + * + * Since: 1.4 + **/ +cairo_status_t +cairo_pattern_get_linear_points (cairo_pattern_t *pattern, + double *x0, double *y0, + double *x1, double *y1) +{ + cairo_linear_pattern_t *linear = (cairo_linear_pattern_t*) pattern; + + if (pattern->status) + return pattern->status; + + if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR) + return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH); + + if (x0) + *x0 = linear->pd1.x; + if (y0) + *y0 = linear->pd1.y; + if (x1) + *x1 = linear->pd2.x; + if (y1) + *y1 = linear->pd2.y; + + return CAIRO_STATUS_SUCCESS; +} + +/** + * cairo_pattern_get_radial_circles: + * @pattern: a #cairo_pattern_t + * @x0: return value for the x coordinate of the center of the first circle, or %NULL + * @y0: return value for the y coordinate of the center of the first circle, or %NULL + * @r0: return value for the radius of the first circle, or %NULL + * @x1: return value for the x coordinate of the center of the second circle, or %NULL + * @y1: return value for the y coordinate of the center of the second circle, or %NULL + * @r1: return value for the radius of the second circle, or %NULL + * + * Gets the gradient endpoint circles for a radial gradient, each + * specified as a center coordinate and a radius. + * + * Return value: %CAIRO_STATUS_SUCCESS, or + * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if @pattern is not a radial + * gradient pattern. + * + * Since: 1.4 + **/ +cairo_status_t +cairo_pattern_get_radial_circles (cairo_pattern_t *pattern, + double *x0, double *y0, double *r0, + double *x1, double *y1, double *r1) +{ + cairo_radial_pattern_t *radial = (cairo_radial_pattern_t*) pattern; + + if (pattern->status) + return pattern->status; + + if (pattern->type != CAIRO_PATTERN_TYPE_RADIAL) + return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH); + + if (x0) + *x0 = radial->cd1.center.x; + if (y0) + *y0 = radial->cd1.center.y; + if (r0) + *r0 = radial->cd1.radius; + if (x1) + *x1 = radial->cd2.center.x; + if (y1) + *y1 = radial->cd2.center.y; + if (r1) + *r1 = radial->cd2.radius; + + return CAIRO_STATUS_SUCCESS; +} + +/** + * cairo_mesh_pattern_get_patch_count: + * @pattern: a #cairo_pattern_t + * @count: return value for the number patches, or %NULL + * + * Gets the number of patches specified in the given mesh pattern. + * + * The number only includes patches which have been finished by + * calling cairo_mesh_pattern_end_patch(). For example it will be 0 + * during the definition of the first patch. + * + * Return value: %CAIRO_STATUS_SUCCESS, or + * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if @pattern is not a mesh + * pattern. + * + * Since: 1.12 + **/ +cairo_status_t +cairo_mesh_pattern_get_patch_count (cairo_pattern_t *pattern, + unsigned int *count) +{ + cairo_mesh_pattern_t *mesh = (cairo_mesh_pattern_t *) pattern; + + if (unlikely (pattern->status)) + return pattern->status; + + if (unlikely (pattern->type != CAIRO_PATTERN_TYPE_MESH)) + return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH); + + if (count) { + *count = _cairo_array_num_elements (&mesh->patches); + if (mesh->current_patch) + *count -= 1; + } + + return CAIRO_STATUS_SUCCESS; +} + +/** + * cairo_mesh_pattern_get_path: + * @pattern: a #cairo_pattern_t + * @patch_num: the patch number to return data for + * + * Gets path defining the patch @patch_num for a mesh + * pattern. + * + * @patch_num can range from 0 to n-1 where n is the number returned by + * cairo_mesh_pattern_get_patch_count(). + * + * Return value: the path defining the patch, or a path with status + * %CAIRO_STATUS_INVALID_INDEX if @patch_num or @point_num is not + * valid for @pattern. If @pattern is not a mesh pattern, a path with + * status %CAIRO_STATUS_PATTERN_TYPE_MISMATCH is returned. + * + * Since: 1.12 + **/ +cairo_path_t * +cairo_mesh_pattern_get_path (cairo_pattern_t *pattern, + unsigned int patch_num) +{ + cairo_mesh_pattern_t *mesh = (cairo_mesh_pattern_t *) pattern; + const cairo_mesh_patch_t *patch; + cairo_path_t *path; + cairo_path_data_t *data; + unsigned int patch_count; + int l, current_point; + + if (unlikely (pattern->status)) + return _cairo_path_create_in_error (pattern->status); + + if (unlikely (pattern->type != CAIRO_PATTERN_TYPE_MESH)) + return _cairo_path_create_in_error (_cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH)); + + patch_count = _cairo_array_num_elements (&mesh->patches); + if (mesh->current_patch) + patch_count--; + + if (unlikely (patch_num >= patch_count)) + return _cairo_path_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_INDEX)); + + patch = _cairo_array_index_const (&mesh->patches, patch_num); + + path = _cairo_calloc (sizeof (cairo_path_t)); + if (path == NULL) + return _cairo_path_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + path->num_data = 18; + path->data = _cairo_calloc_ab (path->num_data, + sizeof (cairo_path_data_t)); + if (path->data == NULL) { + free (path); + return _cairo_path_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + } + + data = path->data; + data[0].header.type = CAIRO_PATH_MOVE_TO; + data[0].header.length = 2; + data[1].point.x = patch->points[0][0].x; + data[1].point.y = patch->points[0][0].y; + data += data[0].header.length; + + current_point = 0; + + for (l = 0; l < 4; l++) { + int i, j, k; + + data[0].header.type = CAIRO_PATH_CURVE_TO; + data[0].header.length = 4; + + for (k = 1; k < 4; k++) { + current_point = (current_point + 1) % 12; + i = mesh_path_point_i[current_point]; + j = mesh_path_point_j[current_point]; + data[k].point.x = patch->points[i][j].x; + data[k].point.y = patch->points[i][j].y; + } + + data += data[0].header.length; + } + + path->status = CAIRO_STATUS_SUCCESS; + + return path; +} + +/** + * cairo_mesh_pattern_get_corner_color_rgba: + * @pattern: a #cairo_pattern_t + * @patch_num: the patch number to return data for + * @corner_num: the corner number to return data for + * @red: return value for red component of color, or %NULL + * @green: return value for green component of color, or %NULL + * @blue: return value for blue component of color, or %NULL + * @alpha: return value for alpha component of color, or %NULL + * + * Gets the color information in corner @corner_num of patch + * @patch_num for a mesh pattern. + * + * @patch_num can range from 0 to n-1 where n is the number returned by + * cairo_mesh_pattern_get_patch_count(). + * + * Valid values for @corner_num are from 0 to 3 and identify the + * corners as explained in cairo_pattern_create_mesh(). + * + * Note that the color and alpha values are not premultiplied. + * + * Return value: %CAIRO_STATUS_SUCCESS, or %CAIRO_STATUS_INVALID_INDEX + * if @patch_num or @corner_num is not valid for @pattern. If + * @pattern is not a mesh pattern, %CAIRO_STATUS_PATTERN_TYPE_MISMATCH + * is returned. + * + * Since: 1.12 + **/ +cairo_status_t +cairo_mesh_pattern_get_corner_color_rgba (cairo_pattern_t *pattern, + unsigned int patch_num, + unsigned int corner_num, + double *red, double *green, + double *blue, double *alpha) +{ + cairo_mesh_pattern_t *mesh = (cairo_mesh_pattern_t *) pattern; + unsigned int patch_count; + const cairo_mesh_patch_t *patch; + + if (unlikely (pattern->status)) + return pattern->status; + + if (unlikely (pattern->type != CAIRO_PATTERN_TYPE_MESH)) + return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH); + + if (unlikely (corner_num > 3)) + return _cairo_error (CAIRO_STATUS_INVALID_INDEX); + + patch_count = _cairo_array_num_elements (&mesh->patches); + if (mesh->current_patch) + patch_count--; + + if (unlikely (patch_num >= patch_count)) + return _cairo_error (CAIRO_STATUS_INVALID_INDEX); + + patch = _cairo_array_index_const (&mesh->patches, patch_num); + + if (red) + *red = patch->colors[corner_num].red; + if (green) + *green = patch->colors[corner_num].green; + if (blue) + *blue = patch->colors[corner_num].blue; + if (alpha) + *alpha = patch->colors[corner_num].alpha; + + return CAIRO_STATUS_SUCCESS; +} + +/** + * cairo_mesh_pattern_get_control_point: + * @pattern: a #cairo_pattern_t + * @patch_num: the patch number to return data for + * @point_num: the control point number to return data for + * @x: return value for the x coordinate of the control point, or %NULL + * @y: return value for the y coordinate of the control point, or %NULL + * + * Gets the control point @point_num of patch @patch_num for a mesh + * pattern. + * + * @patch_num can range from 0 to n-1 where n is the number returned by + * cairo_mesh_pattern_get_patch_count(). + * + * Valid values for @point_num are from 0 to 3 and identify the + * control points as explained in cairo_pattern_create_mesh(). + * + * Return value: %CAIRO_STATUS_SUCCESS, or %CAIRO_STATUS_INVALID_INDEX + * if @patch_num or @point_num is not valid for @pattern. If @pattern + * is not a mesh pattern, %CAIRO_STATUS_PATTERN_TYPE_MISMATCH is + * returned. + * + * Since: 1.12 + **/ +cairo_status_t +cairo_mesh_pattern_get_control_point (cairo_pattern_t *pattern, + unsigned int patch_num, + unsigned int point_num, + double *x, double *y) +{ + cairo_mesh_pattern_t *mesh = (cairo_mesh_pattern_t *) pattern; + const cairo_mesh_patch_t *patch; + unsigned int patch_count; + int i, j; + + if (pattern->status) + return pattern->status; + + if (pattern->type != CAIRO_PATTERN_TYPE_MESH) + return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH); + + if (point_num > 3) + return _cairo_error (CAIRO_STATUS_INVALID_INDEX); + + patch_count = _cairo_array_num_elements (&mesh->patches); + if (mesh->current_patch) + patch_count--; + + if (unlikely (patch_num >= patch_count)) + return _cairo_error (CAIRO_STATUS_INVALID_INDEX); + + patch = _cairo_array_index_const (&mesh->patches, patch_num); + + i = mesh_control_point_i[point_num]; + j = mesh_control_point_j[point_num]; + + if (x) + *x = patch->points[i][j].x; + if (y) + *y = patch->points[i][j].y; + + return CAIRO_STATUS_SUCCESS; +} + +void +_cairo_pattern_reset_static_data (void) +{ + int i; + + for (i = 0; i < ARRAY_LENGTH (freed_pattern_pool); i++) + _freed_pool_reset (&freed_pattern_pool[i]); +} + +static void +_cairo_debug_print_surface_pattern (FILE *file, + const cairo_surface_pattern_t *pattern) +{ + const char *s; + switch (pattern->surface->type) { + case CAIRO_SURFACE_TYPE_IMAGE: s = "image"; break; + case CAIRO_SURFACE_TYPE_PDF: s = "pdf"; break; + case CAIRO_SURFACE_TYPE_PS: s = "ps"; break; + case CAIRO_SURFACE_TYPE_XLIB: s = "xlib"; break; + case CAIRO_SURFACE_TYPE_XCB: s = "xcb"; break; + case CAIRO_SURFACE_TYPE_GLITZ: s = "glitz"; break; + case CAIRO_SURFACE_TYPE_QUARTZ: s = "quartz"; break; + case CAIRO_SURFACE_TYPE_WIN32: s = "win32"; break; + case CAIRO_SURFACE_TYPE_BEOS: s = "beos"; break; + case CAIRO_SURFACE_TYPE_DIRECTFB: s = "directfb"; break; + case CAIRO_SURFACE_TYPE_SVG: s = "svg"; break; + case CAIRO_SURFACE_TYPE_OS2: s = "os2"; break; + case CAIRO_SURFACE_TYPE_WIN32_PRINTING: s = "win32_printing"; break; + case CAIRO_SURFACE_TYPE_QUARTZ_IMAGE: s = "quartz_image"; break; + case CAIRO_SURFACE_TYPE_SCRIPT: s = "script"; break; + case CAIRO_SURFACE_TYPE_QT: s = "qt"; break; + case CAIRO_SURFACE_TYPE_RECORDING: s = "recording"; break; + case CAIRO_SURFACE_TYPE_VG: s = "vg"; break; + case CAIRO_SURFACE_TYPE_GL: s = "gl"; break; + case CAIRO_SURFACE_TYPE_DRM: s = "drm"; break; + case CAIRO_SURFACE_TYPE_TEE: s = "tee"; break; + case CAIRO_SURFACE_TYPE_XML: s = "xml"; break; + case CAIRO_SURFACE_TYPE_SKIA: s = "skia"; break; /* Deprecated */ + case CAIRO_SURFACE_TYPE_SUBSURFACE: s = "subsurface"; break; + case CAIRO_SURFACE_TYPE_COGL: s = "cogl"; break; + default: s = "invalid"; ASSERT_NOT_REACHED; break; + } + fprintf (file, " surface type: %s\n", s); +} + +static void +_cairo_debug_print_raster_source_pattern (FILE *file, + const cairo_raster_source_pattern_t *raster) +{ + fprintf (file, " content: %x, size %dx%d\n", raster->content, raster->extents.width, raster->extents.height); +} + +static void +_cairo_debug_print_linear_pattern (FILE *file, + const cairo_linear_pattern_t *pattern) +{ +} + +static void +_cairo_debug_print_radial_pattern (FILE *file, + const cairo_radial_pattern_t *pattern) +{ +} + +static void +_cairo_debug_print_mesh_pattern (FILE *file, + const cairo_mesh_pattern_t *pattern) +{ +} + +void +_cairo_debug_print_pattern (FILE *file, const cairo_pattern_t *pattern) +{ + const char *s; + switch (pattern->type) { + case CAIRO_PATTERN_TYPE_SOLID: s = "solid"; break; + case CAIRO_PATTERN_TYPE_SURFACE: s = "surface"; break; + case CAIRO_PATTERN_TYPE_LINEAR: s = "linear"; break; + case CAIRO_PATTERN_TYPE_RADIAL: s = "radial"; break; + case CAIRO_PATTERN_TYPE_MESH: s = "mesh"; break; + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: s = "raster"; break; + default: s = "invalid"; ASSERT_NOT_REACHED; break; + } + + fprintf (file, "pattern: %s\n", s); + if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) + return; + + switch (pattern->extend) { + case CAIRO_EXTEND_NONE: s = "none"; break; + case CAIRO_EXTEND_REPEAT: s = "repeat"; break; + case CAIRO_EXTEND_REFLECT: s = "reflect"; break; + case CAIRO_EXTEND_PAD: s = "pad"; break; + default: s = "invalid"; ASSERT_NOT_REACHED; break; + } + fprintf (file, " extend: %s\n", s); + + switch (pattern->filter) { + case CAIRO_FILTER_FAST: s = "fast"; break; + case CAIRO_FILTER_GOOD: s = "good"; break; + case CAIRO_FILTER_BEST: s = "best"; break; + case CAIRO_FILTER_NEAREST: s = "nearest"; break; + case CAIRO_FILTER_BILINEAR: s = "bilinear"; break; + case CAIRO_FILTER_GAUSSIAN: s = "gaussian"; break; + default: s = "invalid"; ASSERT_NOT_REACHED; break; + } + fprintf (file, " filter: %s\n", s); + fprintf (file, " matrix: [%g %g %g %g %g %g]\n", + pattern->matrix.xx, pattern->matrix.yx, + pattern->matrix.xy, pattern->matrix.yy, + pattern->matrix.x0, pattern->matrix.y0); + switch (pattern->type) { + default: + case CAIRO_PATTERN_TYPE_SOLID: + break; + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + _cairo_debug_print_raster_source_pattern (file, (cairo_raster_source_pattern_t *)pattern); + break; + case CAIRO_PATTERN_TYPE_SURFACE: + _cairo_debug_print_surface_pattern (file, (cairo_surface_pattern_t *)pattern); + break; + case CAIRO_PATTERN_TYPE_LINEAR: + _cairo_debug_print_linear_pattern (file, (cairo_linear_pattern_t *)pattern); + break; + case CAIRO_PATTERN_TYPE_RADIAL: + _cairo_debug_print_radial_pattern (file, (cairo_radial_pattern_t *)pattern); + break; + case CAIRO_PATTERN_TYPE_MESH: + _cairo_debug_print_mesh_pattern (file, (cairo_mesh_pattern_t *)pattern); + break; + } +} diff --git a/local/recipes/libs/cairo/source/src/cairo-pdf-interchange.c b/local/recipes/libs/cairo/source/src/cairo-pdf-interchange.c new file mode 100644 index 0000000000..720ce0d532 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-pdf-interchange.c @@ -0,0 +1,2965 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2016 Adrian Johnson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Adrian Johnson. + * + * Contributor(s): + * Adrian Johnson + */ + + +/* PDF Document Interchange features: + * - metadata + * - document outline + * - tagged pdf + * - hyperlinks + * - page labels + */ + +#define _DEFAULT_SOURCE /* for localtime_r(), gmtime_r(), snprintf(), strdup() */ +#include "cairoint.h" + +#include "cairo-pdf.h" +#include "cairo-pdf-surface-private.h" + +#include "cairo-array-private.h" +#include "cairo-error-private.h" +#include "cairo-output-stream-private.h" +#include "cairo-recording-surface-inline.h" +#include "cairo-recording-surface-private.h" +#include "cairo-surface-snapshot-inline.h" + +#include + +#ifndef HAVE_LOCALTIME_R +#define localtime_r(T, BUF) (*(BUF) = *localtime (T)) +#endif +#ifndef HAVE_GMTIME_R +#define gmtime_r(T, BUF) (*(BUF) = *gmtime (T)) +#endif + +/* #define DEBUG_PDF_INTERCHANGE 1 */ + +#if DEBUG_PDF_INTERCHANGE +static void +print_tree (cairo_pdf_surface_t *surface, cairo_pdf_struct_tree_node_t *node); + +static void +print_command (cairo_pdf_command_t *command, int indent); + +static void +print_command_list(cairo_pdf_command_list_t *command_list); +#endif + +static void +_cairo_pdf_command_init_key (cairo_pdf_command_entry_t *key) +{ + key->base.hash = _cairo_hash_uintptr (_CAIRO_HASH_INIT_VALUE, (uintptr_t)key->recording_id); + key->base.hash = _cairo_hash_uintptr (key->base.hash, (uintptr_t)key->command_id); +} + +static cairo_bool_t +_cairo_pdf_command_equal (const void *key_a, const void *key_b) +{ + const cairo_pdf_command_entry_t *a = key_a; + const cairo_pdf_command_entry_t *b = key_b; + + return a->recording_id == b->recording_id && a->command_id == b->command_id; +} + +static void +_cairo_pdf_command_pluck (void *entry, void *closure) +{ + cairo_pdf_command_entry_t *dest = entry; + cairo_hash_table_t *table = closure; + + _cairo_hash_table_remove (table, &dest->base); + free (dest); +} + +static cairo_pdf_struct_tree_node_t * +lookup_node_for_command (cairo_pdf_surface_t *surface, + unsigned int recording_id, + unsigned int command_id) +{ + cairo_pdf_command_entry_t entry_key; + cairo_pdf_command_entry_t *entry; + cairo_pdf_interchange_t *ic = &surface->interchange; + + entry_key.recording_id = recording_id; + entry_key.command_id = command_id; + _cairo_pdf_command_init_key (&entry_key); + entry = _cairo_hash_table_lookup (ic->command_to_node_map, &entry_key.base); + assert (entry != NULL); + return entry->node; +} + +static cairo_int_status_t +command_list_add (cairo_pdf_surface_t *surface, + unsigned int command_id, + cairo_pdf_operation_t flags) +{ + cairo_pdf_interchange_t *ic = &surface->interchange; + cairo_pdf_command_t command; + cairo_int_status_t status; + + unsigned num_elements = _cairo_array_num_elements (&ic->current_commands->commands); + if (command_id > num_elements) { + void *elements; + unsigned additional_elements = command_id - num_elements; + status = _cairo_array_allocate (&ic->current_commands->commands, additional_elements, &elements); + if (unlikely (status)) + return status; + memset (elements, 0, additional_elements * sizeof(cairo_pdf_command_t)); + } + + command.group = NULL; + command.node = NULL; + command.command_id = command_id; + command.mcid_index = 0; + command.flags = flags; + return _cairo_array_append (&ic->current_commands->commands, &command); +} + +static cairo_int_status_t +command_list_push_group (cairo_pdf_surface_t *surface, + unsigned int command_id, + cairo_surface_t *recording_surface, + unsigned int region_id) +{ + cairo_pdf_interchange_t *ic = &surface->interchange; + cairo_pdf_command_t *command; + cairo_pdf_command_list_t *group; + cairo_pdf_recording_surface_commands_t recording_commands; + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + + group = _cairo_calloc (sizeof(cairo_pdf_command_list_t)); + _cairo_array_init (&group->commands, sizeof(cairo_pdf_command_t)); + group->parent = ic->current_commands; + + command_list_add (surface, command_id, PDF_GROUP); + command = _cairo_array_index (&ic->current_commands->commands, command_id); + command->group = group; + ic->current_commands = group; + + recording_commands.recording_surface = recording_surface; + recording_commands.command_list = group; + recording_commands.region_id = region_id; + status = _cairo_array_append (&ic->recording_surface_commands, &recording_commands); + + return status; +} + +static void +command_list_pop_group (cairo_pdf_surface_t *surface) +{ + cairo_pdf_interchange_t *ic = &surface->interchange; + + ic->current_commands = ic->current_commands->parent; +} + +static cairo_bool_t +command_list_is_group (cairo_pdf_surface_t *surface, + unsigned int command_id) +{ + cairo_pdf_interchange_t *ic = &surface->interchange; + cairo_pdf_command_t *command; + unsigned num_elements = _cairo_array_num_elements (&ic->current_commands->commands); + + if (command_id >= num_elements) + return FALSE; + + command = _cairo_array_index (&ic->current_commands->commands, command_id); + return command->flags == PDF_GROUP; +} + + +/* Is there any content between current command and next + * begin/end/group? */ +static cairo_bool_t +command_list_has_content (cairo_pdf_surface_t *surface, + unsigned int command_id, + unsigned int *content_command_id) +{ + cairo_pdf_interchange_t *ic = &surface->interchange; + cairo_pdf_command_t *command; + unsigned i; + unsigned num_elements = _cairo_array_num_elements (&ic->current_commands->commands); + + for (i = command_id + 1; i < num_elements; i++) { + command = _cairo_array_index (&ic->current_commands->commands, i); + switch (command->flags) { + case PDF_CONTENT: + if (content_command_id) + *content_command_id = i; + return TRUE; + break; + case PDF_BEGIN: + case PDF_END: + case PDF_GROUP: + return FALSE; + case PDF_NONE: + break; + } + } + return FALSE; +} + +static void +command_list_set_mcid (cairo_pdf_surface_t *surface, + unsigned int command_id, + cairo_pdf_struct_tree_node_t *node, + int mcid_index) +{ + cairo_pdf_interchange_t *ic = &surface->interchange; + cairo_pdf_command_t *command; + + command = _cairo_array_index (&ic->current_commands->commands, command_id); + command->node = node; + command->mcid_index = mcid_index; +} + +static void +command_list_set_current_recording_commands (cairo_pdf_surface_t *surface, + cairo_surface_t *recording_surface, + unsigned int region_id) +{ + cairo_pdf_interchange_t *ic = &surface->interchange; + unsigned i; + cairo_pdf_recording_surface_commands_t *commands; + unsigned num_elements = _cairo_array_num_elements (&ic->recording_surface_commands); + + for (i = 0; i < num_elements; i++) { + commands = _cairo_array_index (&ic->recording_surface_commands, i); + if (commands->region_id == region_id) { + ic->current_commands = commands->command_list; + return; + } + } + ASSERT_NOT_REACHED; /* recording_surface not found */ +} + +static void +update_mcid_order (cairo_pdf_surface_t *surface, + cairo_pdf_command_list_t *command_list) +{ + cairo_pdf_interchange_t *ic = &surface->interchange; + cairo_pdf_command_t *command; + cairo_pdf_page_mcid_t *mcid_elem; + unsigned i; + unsigned num_elements = _cairo_array_num_elements (&command_list->commands); + + for (i = 0; i < num_elements; i++) { + command = _cairo_array_index (&command_list->commands, i); + if (command->node) { + mcid_elem = _cairo_array_index (&command->node->mcid, command->mcid_index); + mcid_elem->order = ic->mcid_order++; + } + + if (command->group) + update_mcid_order (surface, command->group); + } +} + +static void +_cairo_pdf_content_tag_init_key (cairo_pdf_content_tag_t *key) +{ + key->base.hash = _cairo_hash_string (key->node->attributes.content.id); +} + +static cairo_bool_t +_cairo_pdf_content_tag_equal (const void *key_a, const void *key_b) +{ + const cairo_pdf_content_tag_t *a = key_a; + const cairo_pdf_content_tag_t *b = key_b; + + return strcmp (a->node->attributes.content.id, b->node->attributes.content.id) == 0; +} + +static void +_cairo_pdf_content_tag_pluck (void *entry, void *closure) +{ + cairo_pdf_content_tag_t *content_tag = entry; + cairo_hash_table_t *table = closure; + + _cairo_hash_table_remove (table, &content_tag->base); + free (content_tag); +} + +static cairo_status_t +lookup_content_node_for_ref_node (cairo_pdf_surface_t *surface, + cairo_pdf_struct_tree_node_t *ref_node, + cairo_pdf_struct_tree_node_t **node) +{ + cairo_pdf_content_tag_t entry_key; + cairo_pdf_content_tag_t *entry; + cairo_pdf_interchange_t *ic = &surface->interchange; + + entry_key.node = ref_node; + _cairo_pdf_content_tag_init_key (&entry_key); + entry = _cairo_hash_table_lookup (ic->content_tag_map, &entry_key.base); + if (!entry) { + return _cairo_tag_error ("CONTENT_REF ref='%s' not found", + ref_node->attributes.content_ref.ref); + } + + *node = entry->node; + return CAIRO_STATUS_SUCCESS; +} + +static void +write_rect_to_pdf_quad_points (cairo_output_stream_t *stream, + const cairo_rectangle_t *rect, + double surface_height) +{ + _cairo_output_stream_printf (stream, + "%f %f %f %f %f %f %f %f", + rect->x, + surface_height - rect->y, + rect->x + rect->width, + surface_height - rect->y, + rect->x + rect->width, + surface_height - (rect->y + rect->height), + rect->x, + surface_height - (rect->y + rect->height)); +} + +static void +write_rect_int_to_pdf_bbox (cairo_output_stream_t *stream, + const cairo_rectangle_int_t *rect, + double surface_height) +{ + _cairo_output_stream_printf (stream, + "%d %f %d %f", + rect->x, + surface_height - (rect->y + rect->height), + rect->x + rect->width, + surface_height - rect->y); +} + +static cairo_int_status_t +add_tree_node (cairo_pdf_surface_t *surface, + cairo_pdf_struct_tree_node_t *parent, + const char *name, + const char *attributes, + cairo_pdf_struct_tree_node_t **new_node) +{ + cairo_pdf_struct_tree_node_t *node; + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + + node = _cairo_calloc (sizeof(cairo_pdf_struct_tree_node_t)); + if (unlikely (node == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + node->name = strdup (name); + node->res = _cairo_pdf_surface_new_object (surface); + if (node->res.id == 0) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + node->parent = parent; + cairo_list_init (&node->children); + _cairo_array_init (&node->mcid, sizeof (cairo_pdf_page_mcid_t)); + node->annot = NULL; + node->extents.valid = FALSE; + + cairo_list_add_tail (&node->link, &parent->children); + + if (strcmp (node->name, CAIRO_TAG_CONTENT) == 0) { + node->type = PDF_NODE_CONTENT; + status = _cairo_tag_parse_content_attributes (attributes, &node->attributes.content); + } else if (strcmp (node->name, CAIRO_TAG_CONTENT_REF) == 0) { + node->type = PDF_NODE_CONTENT_REF; + status = _cairo_tag_parse_content_ref_attributes (attributes, &node->attributes.content_ref); + } else if (strcmp (node->name, "Artifact") == 0) { + node->type = PDF_NODE_ARTIFACT; + } else { + node->type = PDF_NODE_STRUCT; + } + + *new_node = node; + return status; +} + +static void +free_node (cairo_pdf_struct_tree_node_t *node) +{ + cairo_pdf_struct_tree_node_t *child, *next; + + if (!node) + return; + + cairo_list_foreach_entry_safe (child, next, cairo_pdf_struct_tree_node_t, + &node->children, + link) + { + cairo_list_del (&child->link); + free_node (child); + } + free (node->name); + _cairo_array_fini (&node->mcid); + if (node->type == PDF_NODE_CONTENT) + _cairo_tag_free_content_attributes (&node->attributes.content); + + if (node->type == PDF_NODE_CONTENT_REF) + _cairo_tag_free_content_ref_attributes (&node->attributes.content_ref); + + free (node); +} + +static cairo_status_t +add_mcid_to_node (cairo_pdf_surface_t *surface, + cairo_pdf_struct_tree_node_t *node, + unsigned int command_id, + int *mcid) +{ + cairo_pdf_page_mcid_t mcid_elem; + cairo_int_status_t status; + cairo_pdf_interchange_t *ic = &surface->interchange; + + status = _cairo_array_append (&ic->mcid_to_tree, &node); + if (unlikely (status)) + return status; + + mcid_elem.order = -1; + mcid_elem.page = _cairo_array_num_elements (&surface->pages); + mcid_elem.xobject_res = ic->current_recording_surface_res; + mcid_elem.mcid = _cairo_array_num_elements (&ic->mcid_to_tree) - 1; + mcid_elem.child_node = NULL; + command_list_set_mcid (surface, command_id, node, _cairo_array_num_elements (&node->mcid)); + *mcid = mcid_elem.mcid; + return _cairo_array_append (&node->mcid, &mcid_elem); +} + +static cairo_status_t +add_child_to_mcid_array (cairo_pdf_surface_t *surface, + cairo_pdf_struct_tree_node_t *node, + unsigned int command_id, + cairo_pdf_struct_tree_node_t *child) +{ + cairo_pdf_page_mcid_t mcid_elem; + + mcid_elem.order = -1; + mcid_elem.page = 0; + mcid_elem.xobject_res.id = 0; + mcid_elem.mcid = 0; + mcid_elem.child_node = child; + command_list_set_mcid (surface, command_id, node, _cairo_array_num_elements (&node->mcid)); + return _cairo_array_append (&node->mcid, &mcid_elem); +} + +static cairo_int_status_t +add_annotation (cairo_pdf_surface_t *surface, + cairo_pdf_struct_tree_node_t *node, + const char *name, + const char *attributes) +{ + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + cairo_pdf_interchange_t *ic = &surface->interchange; + cairo_pdf_annotation_t *annot; + + annot = _cairo_calloc (sizeof (cairo_pdf_annotation_t)); + if (unlikely (annot == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + status = _cairo_tag_parse_link_attributes (attributes, &annot->link_attrs); + if (unlikely (status)) { + free (annot); + return status; + } + + if (annot->link_attrs.link_page == 0) + annot->link_attrs.link_page = _cairo_array_num_elements (&surface->pages); + + annot->node = node; + + annot->res = _cairo_pdf_surface_new_object (surface); + if (annot->res.id == 0) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + node->annot = annot; + status = _cairo_array_append (&ic->annots, &annot); + + return status; +} + +static void +free_annotation (cairo_pdf_annotation_t *annot) +{ + _cairo_tag_free_link_attributes (&annot->link_attrs); + free (annot); +} + +static void +cairo_pdf_interchange_clear_annotations (cairo_pdf_surface_t *surface) +{ + cairo_pdf_interchange_t *ic = &surface->interchange; + int num_elems, i; + + num_elems = _cairo_array_num_elements (&ic->annots); + for (i = 0; i < num_elems; i++) { + cairo_pdf_annotation_t * annot; + + _cairo_array_copy_element (&ic->annots, i, &annot); + free_annotation (annot); + } + _cairo_array_truncate (&ic->annots, 0); +} + +static void +cairo_pdf_interchange_write_node_mcid (cairo_pdf_surface_t *surface, + cairo_pdf_page_mcid_t *mcid_elem, + int page) +{ + cairo_pdf_page_info_t *page_info; + + page_info = _cairo_array_index (&surface->pages, mcid_elem->page - 1); + if (mcid_elem->page == page && mcid_elem->xobject_res.id == 0) { + _cairo_output_stream_printf (surface->object_stream.stream, "%d ", mcid_elem->mcid); + } else { + _cairo_output_stream_printf (surface->object_stream.stream, + "\n << /Type /MCR "); + if (mcid_elem->page != page) { + _cairo_output_stream_printf (surface->object_stream.stream, + "/Pg %d 0 R ", + page_info->page_res.id); + } + if (mcid_elem->xobject_res.id != 0) { + _cairo_output_stream_printf (surface->object_stream.stream, + "/Stm %d 0 R ", + mcid_elem->xobject_res.id); + } + _cairo_output_stream_printf (surface->object_stream.stream, + "/MCID %d >> ", + mcid_elem->mcid); + } +} + +static int +_mcid_order_compare (const void *a, + const void *b) +{ + const cairo_pdf_page_mcid_t *mcid_a = a; + const cairo_pdf_page_mcid_t *mcid_b = b; + + if (mcid_a->order < mcid_b->order) + return -1; + else if (mcid_a->order > mcid_b->order) + return 1; + else + return 0; +} + +static cairo_int_status_t +cairo_pdf_interchange_write_node_object (cairo_pdf_surface_t *surface, + cairo_pdf_struct_tree_node_t *node, + int depth) +{ + cairo_pdf_page_mcid_t *mcid_elem, *child_mcid_elem; + unsigned i, j, num_mcid; + int first_page = 0; + cairo_pdf_page_info_t *page_info; + cairo_int_status_t status; + cairo_bool_t has_children = FALSE; + + /* The Root node is written in cairo_pdf_interchange_write_struct_tree(). */ + if (!node->parent) + return CAIRO_STATUS_SUCCESS; + + if (node->type == PDF_NODE_CONTENT || + node->type == PDF_NODE_CONTENT_REF || + node->type == PDF_NODE_ARTIFACT) + { + return CAIRO_STATUS_SUCCESS; + } + + status = _cairo_pdf_surface_object_begin (surface, node->res); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->object_stream.stream, + "<< /Type /StructElem\n" + " /S /%s\n" + " /P %d 0 R\n", + node->name, + node->parent->res.id); + + /* Write /K entry (children of this StructElem) */ + num_mcid = _cairo_array_num_elements (&node->mcid); + if (num_mcid > 0 ) { + _cairo_array_sort (&node->mcid, _mcid_order_compare); + /* Find the first MCID element and use the page number to set /Pg */ + for (i = 0; i < num_mcid; i++) { + mcid_elem = _cairo_array_index (&node->mcid, i); + assert (mcid_elem->order != -1); + if (mcid_elem->child_node) { + if (mcid_elem->child_node->type == PDF_NODE_CONTENT_REF) { + cairo_pdf_struct_tree_node_t *content_node; + status = lookup_content_node_for_ref_node (surface, mcid_elem->child_node, &content_node); + if (status) + return status; + + /* CONTENT_REF will not have child nodes */ + if (_cairo_array_num_elements (&content_node->mcid) > 0) { + child_mcid_elem = _cairo_array_index (&content_node->mcid, 0); + first_page = child_mcid_elem->page; + page_info = _cairo_array_index (&surface->pages, first_page - 1); + _cairo_output_stream_printf (surface->object_stream.stream, + " /Pg %d 0 R\n", + page_info->page_res.id); + has_children = TRUE; + break; + } + } else { + has_children = TRUE; + } + } else { + first_page = mcid_elem->page; + page_info = _cairo_array_index (&surface->pages, first_page - 1); + _cairo_output_stream_printf (surface->object_stream.stream, + " /Pg %d 0 R\n", + page_info->page_res.id); + has_children = TRUE; + break; + } + } + + if (has_children || node->annot) { + _cairo_output_stream_printf (surface->object_stream.stream, " /K "); + + if (num_mcid > 1 || node->annot) + _cairo_output_stream_printf (surface->object_stream.stream, "[ "); + + for (i = 0; i < num_mcid; i++) { + if (node->annot) { + if (node->annot->link_attrs.link_page != first_page) { + page_info = _cairo_array_index (&surface->pages, node->annot->link_attrs.link_page - 1); + _cairo_output_stream_printf (surface->object_stream.stream, + "<< /Type /OBJR /Pg %d 0 R /Obj %d 0 R >> ", + page_info->page_res.id, + node->annot->res.id); + } else { + _cairo_output_stream_printf (surface->object_stream.stream, + "<< /Type /OBJR /Obj %d 0 R >> ", + node->annot->res.id); + } + } + mcid_elem = _cairo_array_index (&node->mcid, i); + if (mcid_elem->child_node) { + if (mcid_elem->child_node->type == PDF_NODE_CONTENT_REF) { + cairo_pdf_struct_tree_node_t *content_node; + status = lookup_content_node_for_ref_node (surface, mcid_elem->child_node, &content_node); + if (status) + return status; + + assert (content_node->type == PDF_NODE_CONTENT); + + /* CONTENT_REF will not have child nodes */ + for (j = 0; j < _cairo_array_num_elements (&content_node->mcid); j++) { + child_mcid_elem = _cairo_array_index (&content_node->mcid, j); + cairo_pdf_interchange_write_node_mcid (surface, child_mcid_elem, first_page); + } + } else if (mcid_elem->child_node->type != PDF_NODE_CONTENT) { + _cairo_output_stream_printf (surface->object_stream.stream, + " %d 0 R ", + mcid_elem->child_node->res.id); + } + } else { + cairo_pdf_interchange_write_node_mcid (surface, mcid_elem, first_page); + } + } + + if (num_mcid > 1 || node->annot) + _cairo_output_stream_printf (surface->object_stream.stream, "]"); + } + + _cairo_output_stream_printf (surface->object_stream.stream, "\n"); + } + + _cairo_output_stream_printf (surface->object_stream.stream, + ">>\n"); + + _cairo_pdf_surface_object_end (surface); + + return _cairo_output_stream_get_status (surface->object_stream.stream); +} + +static void +init_named_dest_key (cairo_pdf_named_dest_t *dest) +{ + dest->base.hash = _cairo_hash_bytes (_CAIRO_HASH_INIT_VALUE, + dest->attrs.name, + strlen (dest->attrs.name)); +} + +static cairo_bool_t +_named_dest_equal (const void *key_a, const void *key_b) +{ + const cairo_pdf_named_dest_t *a = key_a; + const cairo_pdf_named_dest_t *b = key_b; + + return strcmp (a->attrs.name, b->attrs.name) == 0; +} + +static void +_named_dest_pluck (void *entry, void *closure) +{ + cairo_pdf_named_dest_t *dest = entry; + cairo_hash_table_t *table = closure; + + _cairo_hash_table_remove (table, &dest->base); + _cairo_tag_free_dest_attributes (&dest->attrs); + free (dest); +} + +static cairo_int_status_t +cairo_pdf_interchange_write_explicit_dest (cairo_pdf_surface_t *surface, + int page, + cairo_bool_t has_pos, + double x, + double y) +{ + cairo_pdf_page_info_t *page_info; + + page_info = _cairo_array_index (&surface->pages, page - 1); + + if (has_pos) { + _cairo_output_stream_printf (surface->object_stream.stream, + "[%d 0 R /XYZ %f %f 0]\n", + page_info->page_res.id, + x, + page_info->height - y); + } else { + _cairo_output_stream_printf (surface->object_stream.stream, + "[%d 0 R /XYZ null null 0]\n", + page_info->page_res.id); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +cairo_pdf_interchange_write_dest (cairo_pdf_surface_t *surface, + cairo_link_attrs_t *link_attrs) +{ + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + cairo_pdf_interchange_t *ic = &surface->interchange; + + /* If the dest is known, emit an explicit dest */ + if (link_attrs->link_type == TAG_LINK_DEST_AND_URI || link_attrs->link_type == TAG_LINK_DEST) { + cairo_pdf_named_dest_t key; + cairo_pdf_named_dest_t *named_dest; + + /* check if we already have this dest */ + key.attrs.name = link_attrs->dest; + init_named_dest_key (&key); + named_dest = _cairo_hash_table_lookup (ic->named_dests, &key.base); + if (named_dest) { + double x = 0; + double y = 0; + + if (named_dest->extents.valid) { + x = named_dest->extents.extents.x; + y = named_dest->extents.extents.y; + } + + if (named_dest->attrs.x_valid) + x = named_dest->attrs.x; + + if (named_dest->attrs.y_valid) + y = named_dest->attrs.y; + + if (named_dest->attrs.internal) { + _cairo_output_stream_printf (surface->object_stream.stream, " /Dest "); + status = cairo_pdf_interchange_write_explicit_dest (surface, + named_dest->page, + TRUE, + x, y); + } else { + char *name = NULL; + + status = _cairo_utf8_to_pdf_string (named_dest->attrs.name, &name); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->object_stream.stream, " /Dest %s\n", + name); + free (name); + } + return status; + } + /* name does not exist */ + if (link_attrs->link_type == TAG_LINK_DEST_AND_URI) { + /* Don't emit anything. The caller will fallback to emitting a URI destination. */ + return CAIRO_INT_STATUS_NOTHING_TO_DO; + } + + /* Mising destination. Emit a "do nothing" dest that points to the same page and position. */ + _cairo_tag_warning ("Link to dest=\"%s\" not found", link_attrs->dest); + _cairo_output_stream_printf (surface->object_stream.stream, " /Dest "); + status = cairo_pdf_interchange_write_explicit_dest (surface, + link_attrs->link_page, + FALSE, + 0, 0); + return status; + } + + /* link_attrs->link_type == TAG_LINK_PAGE */ + + if (link_attrs->page < 1) + return _cairo_tag_error ("Link attribute: \"page=%d\" page must be >= 1", link_attrs->page); + + if (link_attrs->page > (int)_cairo_array_num_elements (&surface->pages)) + return _cairo_tag_error ("Link attribute: \"page=%d\" page exceeds page count (%d)", + link_attrs->page, _cairo_array_num_elements (&surface->pages)); + + _cairo_output_stream_printf (surface->object_stream.stream, " /Dest "); + return cairo_pdf_interchange_write_explicit_dest (surface, + link_attrs->page, + link_attrs->has_pos, + link_attrs->pos.x, + link_attrs->pos.y); +} + +static cairo_int_status_t +_cairo_utf8_to_pdf_utf8_hexstring (const char *utf8, char **str_out) +{ + int i; + int len; + unsigned char *p; + cairo_bool_t ascii; + char *str; + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + + ascii = TRUE; + p = (unsigned char *)utf8; + len = 0; + while (*p) { + if (*p < 32 || *p > 126) { + ascii = FALSE; + } + if (*p == '(' || *p == ')' || *p == '\\') + len += 2; + else + len++; + p++; + } + + if (ascii) { + str = _cairo_malloc (len + 3); + if (str == NULL) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + str[0] = '('; + p = (unsigned char *)utf8; + i = 1; + while (*p) { + if (*p == '(' || *p == ')' || *p == '\\') + str[i++] = '\\'; + str[i++] = *p; + p++; + } + str[i++] = ')'; + str[i++] = 0; + } else { + str = _cairo_malloc (len*2 + 3); + if (str == NULL) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + str[0] = '<'; + p = (unsigned char *)utf8; + i = 1; + while (*p) { + if (*p == '\\') { + snprintf(str + i, 3, "%02x", '\\'); + i += 2; + } + snprintf(str + i, 3, "%02x", *p); + i += 2; + p++; + } + str[i++] = '>'; + str[i++] = 0; + } + *str_out = str; + + return status; +} + +static cairo_int_status_t +cairo_pdf_interchange_write_link_action (cairo_pdf_surface_t *surface, + cairo_link_attrs_t *link_attrs) +{ + cairo_int_status_t status; + char *dest = NULL; + + if (link_attrs->link_type == TAG_LINK_DEST_AND_URI || + link_attrs->link_type == TAG_LINK_DEST || + link_attrs->link_type == TAG_LINK_PAGE) + { + status = cairo_pdf_interchange_write_dest (surface, link_attrs); + if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) + return status; + + /* CAIRO_INT_STATUS_NOTHING_TO_DO means that the link type is TAG_LINK_DEST_AND_URI + * and the DEST is missing. Fall through to writing a URI link below. + */ + } + + if (link_attrs->link_type == TAG_LINK_URI || link_attrs->link_type == TAG_LINK_DEST_AND_URI) { + status = _cairo_utf8_to_pdf_string (link_attrs->uri, &dest); + if (unlikely (status)) + return status; + + if (dest[0] != '(') { + free (dest); + return _cairo_tag_error ("Link attribute: \"url=%s\" URI may only contain ASCII characters", + link_attrs->uri); + } + + _cairo_output_stream_printf (surface->object_stream.stream, + " /A <<\n" + " /Type /Action\n" + " /S /URI\n" + " /URI %s\n" + " >>\n", + dest); + free (dest); + } else if (link_attrs->link_type == TAG_LINK_FILE) { + /* According to "Developing with PDF", Leonard Rosenthol, 2013, + * The F key is encoded in the "standard encoding for the + * platform on which the document is being viewed. For most + * modern operating systems, that's UTF-8" + * + * As we don't know the target platform, we assume UTF-8. The + * F key may contain multi-byte encodings using the hex + * encoding. + * + * For PDF 1.7 we also include the UF key which uses the + * standard PDF UTF-16BE strings. + */ + status = _cairo_utf8_to_pdf_utf8_hexstring (link_attrs->file, &dest); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->object_stream.stream, + " /A <<\n" + " /Type /Action\n" + " /S /GoToR\n" + " /F %s\n", + dest); + free (dest); + + if (surface->pdf_version >= CAIRO_PDF_VERSION_1_7) + { + status = _cairo_utf8_to_pdf_string (link_attrs->file, &dest); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->object_stream.stream, + " /UF %s\n", + dest); + free (dest); + } + + if (link_attrs->dest) { + status = _cairo_utf8_to_pdf_string (link_attrs->dest, &dest); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->object_stream.stream, + " /D %s\n", + dest); + free (dest); + } else { + if (link_attrs->has_pos) { + _cairo_output_stream_printf (surface->object_stream.stream, + " /D [%d /XYZ %f %f 0]\n", + link_attrs->page, + link_attrs->pos.x, + link_attrs->pos.y); + } else { + _cairo_output_stream_printf (surface->object_stream.stream, + " /D [%d /XYZ null null 0]\n", + link_attrs->page); + } + } + _cairo_output_stream_printf (surface->object_stream.stream, + " >>\n"); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +cairo_pdf_interchange_write_annot (cairo_pdf_surface_t *surface, + cairo_pdf_annotation_t *annot, + cairo_bool_t struct_parents) +{ + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + cairo_pdf_interchange_t *ic = &surface->interchange; + cairo_pdf_struct_tree_node_t *node = annot->node; + int sp; + int i, num_rects; + double height; + + num_rects = _cairo_array_num_elements (&annot->link_attrs.rects); + if (strcmp (node->name, CAIRO_TAG_LINK) == 0 && + annot->link_attrs.link_type != TAG_LINK_EMPTY && + (node->extents.valid || num_rects > 0)) + { + status = _cairo_array_append (&ic->parent_tree, &node->res); + if (unlikely (status)) + return status; + + sp = _cairo_array_num_elements (&ic->parent_tree) - 1; + + status = _cairo_pdf_surface_object_begin (surface, annot->res); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->object_stream.stream, + "<< /Type /Annot\n" + " /Subtype /Link\n"); + + if (struct_parents) { + _cairo_output_stream_printf (surface->object_stream.stream, + " /StructParent %d\n", + sp); + } + + height = surface->height; + if (num_rects > 0) { + cairo_rectangle_int_t bbox_rect; + + _cairo_output_stream_printf (surface->object_stream.stream, + " /QuadPoints [ "); + for (i = 0; i < num_rects; i++) { + cairo_rectangle_t rectf; + cairo_rectangle_int_t recti; + + _cairo_array_copy_element (&annot->link_attrs.rects, i, &rectf); + _cairo_rectangle_int_from_double (&recti, &rectf); + if (i == 0) + bbox_rect = recti; + else + _cairo_rectangle_union (&bbox_rect, &recti); + + write_rect_to_pdf_quad_points (surface->object_stream.stream, &rectf, height); + _cairo_output_stream_printf (surface->object_stream.stream, " "); + } + _cairo_output_stream_printf (surface->object_stream.stream, + "]\n" + " /Rect [ "); + write_rect_int_to_pdf_bbox (surface->object_stream.stream, &bbox_rect, height); + _cairo_output_stream_printf (surface->object_stream.stream, " ]\n"); + } else { + _cairo_output_stream_printf (surface->object_stream.stream, + " /Rect [ "); + write_rect_int_to_pdf_bbox (surface->object_stream.stream, &node->extents.extents, height); + _cairo_output_stream_printf (surface->object_stream.stream, " ]\n"); + } + + status = cairo_pdf_interchange_write_link_action (surface, &annot->link_attrs); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->object_stream.stream, + " /BS << /W 0 >>\n" + ">>\n"); + + _cairo_pdf_surface_object_end (surface); + status = _cairo_output_stream_get_status (surface->object_stream.stream); + } + + return status; +} + +static cairo_int_status_t +cairo_pdf_interchange_walk_struct_tree (cairo_pdf_surface_t *surface, + cairo_pdf_struct_tree_node_t *node, + int depth, + cairo_int_status_t (*func) (cairo_pdf_surface_t *surface, + cairo_pdf_struct_tree_node_t *node, + int depth)) +{ + cairo_int_status_t status; + cairo_pdf_struct_tree_node_t *child; + + status = func (surface, node, depth); + if (unlikely (status)) + return status; + + depth++; + cairo_list_foreach_entry (child, cairo_pdf_struct_tree_node_t, + &node->children, link) + { + status = cairo_pdf_interchange_walk_struct_tree (surface, child, depth, func); + if (unlikely (status)) + return status; + } + depth--; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +cairo_pdf_interchange_write_struct_tree (cairo_pdf_surface_t *surface) +{ + cairo_pdf_interchange_t *ic = &surface->interchange; + cairo_pdf_struct_tree_node_t *child; + cairo_int_status_t status; + + if (cairo_list_is_empty (&ic->struct_root->children)) + return CAIRO_STATUS_SUCCESS; + + status = cairo_pdf_interchange_walk_struct_tree (surface, + ic->struct_root, + 0, + cairo_pdf_interchange_write_node_object); + if (unlikely (status)) + return status; + + status = _cairo_pdf_surface_object_begin (surface, surface->struct_tree_root); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->object_stream.stream, + "<< /Type /StructTreeRoot\n" + " /ParentTree %d 0 R\n", + ic->parent_tree_res.id); + + if (cairo_list_is_singular (&ic->struct_root->children)) { + child = cairo_list_first_entry (&ic->struct_root->children, cairo_pdf_struct_tree_node_t, link); + _cairo_output_stream_printf (surface->object_stream.stream, " /K [ %d 0 R ]\n", child->res.id); + } else { + _cairo_output_stream_printf (surface->object_stream.stream, " /K [ "); + + cairo_list_foreach_entry (child, cairo_pdf_struct_tree_node_t, + &ic->struct_root->children, link) + { + if (child->type == PDF_NODE_CONTENT || child->type == PDF_NODE_ARTIFACT) + continue; + + _cairo_output_stream_printf (surface->object_stream.stream, "%d 0 R ", child->res.id); + } + _cairo_output_stream_printf (surface->object_stream.stream, "]\n"); + } + + _cairo_output_stream_printf (surface->object_stream.stream, + ">>\n"); + _cairo_pdf_surface_object_end (surface); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +cairo_pdf_interchange_write_annots (cairo_pdf_surface_t *surface, + cairo_bool_t struct_parents) +{ + cairo_pdf_interchange_t *ic = &surface->interchange; + int num_elems, i, page_num; + cairo_pdf_page_info_t *page_info; + cairo_pdf_annotation_t *annot; + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + + num_elems = _cairo_array_num_elements (&ic->annots); + for (i = 0; i < num_elems; i++) { + _cairo_array_copy_element (&ic->annots, i, &annot); + page_num = annot->link_attrs.link_page; + if (page_num > (int)_cairo_array_num_elements (&surface->pages)) { + return _cairo_tag_error ("Link attribute: \"link_page=%d\" page exceeds page count (%d)", + page_num, + _cairo_array_num_elements (&surface->pages)); + } + + page_info = _cairo_array_index (&surface->pages, page_num - 1); + status = _cairo_array_append (&page_info->annots, &annot->res); + if (status) + return status; + + status = cairo_pdf_interchange_write_annot (surface, annot, struct_parents); + if (unlikely (status)) + return status; + } + + return status; +} + +static cairo_int_status_t +cairo_pdf_interchange_write_content_parent_elems (cairo_pdf_surface_t *surface) +{ + int num_elems, i; + cairo_pdf_struct_tree_node_t *node; + cairo_pdf_interchange_t *ic = &surface->interchange; + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + + num_elems = _cairo_array_num_elements (&ic->mcid_to_tree); + status = _cairo_pdf_surface_object_begin (surface, ic->content_parent_res); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->object_stream.stream, + "[\n"); + for (i = 0; i < num_elems; i++) { + _cairo_array_copy_element (&ic->mcid_to_tree, i, &node); + _cairo_output_stream_printf (surface->object_stream.stream, " %d 0 R\n", node->res.id); + } + _cairo_output_stream_printf (surface->object_stream.stream, + "]\n"); + _cairo_pdf_surface_object_end (surface); + + return status; +} + +static cairo_int_status_t +cairo_pdf_interchange_apply_extents_from_content_ref (cairo_pdf_surface_t *surface, + cairo_pdf_struct_tree_node_t *node, + int depth) +{ + cairo_int_status_t status; + + if (node->type != PDF_NODE_CONTENT_REF) + return CAIRO_STATUS_SUCCESS; + + cairo_pdf_struct_tree_node_t *content_node; + status = lookup_content_node_for_ref_node (surface, node, &content_node); + if (status) + return status; + + /* Merge extents with all parent nodes */ + node = node->parent; + while (node) { + if (node->extents.valid) { + _cairo_rectangle_union (&node->extents.extents, &content_node->extents.extents); + } else { + node->extents = content_node->extents; + } + node = node->parent; + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +cairo_pdf_interchange_update_extents (cairo_pdf_surface_t *surface) +{ + cairo_pdf_interchange_t *ic = &surface->interchange; + + return cairo_pdf_interchange_walk_struct_tree (surface, + ic->struct_root, + 0, + cairo_pdf_interchange_apply_extents_from_content_ref); +} + +static cairo_int_status_t +cairo_pdf_interchange_write_parent_tree (cairo_pdf_surface_t *surface) +{ + int num_elems, i; + cairo_pdf_resource_t *res; + cairo_pdf_interchange_t *ic = &surface->interchange; + cairo_int_status_t status; + + num_elems = _cairo_array_num_elements (&ic->parent_tree); + if (num_elems > 0) { + ic->parent_tree_res = _cairo_pdf_surface_new_object (surface); + if (ic->parent_tree_res.id == 0) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + status = _cairo_pdf_surface_object_begin (surface, ic->parent_tree_res); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->object_stream.stream, + "<< /Nums [\n"); + for (i = 0; i < num_elems; i++) { + res = _cairo_array_index (&ic->parent_tree, i); + if (res->id) { + _cairo_output_stream_printf (surface->object_stream.stream, + " %d %d 0 R\n", + i, + res->id); + } + } + _cairo_output_stream_printf (surface->object_stream.stream, + " ]\n" + ">>\n"); + _cairo_pdf_surface_object_end (surface); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +cairo_pdf_interchange_write_outline (cairo_pdf_surface_t *surface) +{ + int num_elems, i; + cairo_pdf_outline_entry_t *outline; + cairo_pdf_interchange_t *ic = &surface->interchange; + cairo_int_status_t status; + char *name = NULL; + + num_elems = _cairo_array_num_elements (&ic->outline); + if (num_elems < 2) + return CAIRO_INT_STATUS_SUCCESS; + + _cairo_array_copy_element (&ic->outline, 0, &outline); + outline->res = _cairo_pdf_surface_new_object (surface); + if (outline->res.id == 0) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + surface->outlines_dict_res = outline->res; + status = _cairo_pdf_surface_object_begin (surface, outline->res); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->object_stream.stream, + "<< /Type /Outlines\n" + " /First %d 0 R\n" + " /Last %d 0 R\n" + " /Count %d\n" + ">>\n", + outline->first_child->res.id, + outline->last_child->res.id, + outline->count); + _cairo_pdf_surface_object_end (surface); + + for (i = 1; i < num_elems; i++) { + _cairo_array_copy_element (&ic->outline, i, &outline); + _cairo_pdf_surface_update_object (surface, outline->res); + + status = _cairo_utf8_to_pdf_string (outline->name, &name); + if (unlikely (status)) + return status; + + status = _cairo_pdf_surface_object_begin (surface, outline->res); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->object_stream.stream, + "<< /Title %s\n" + " /Parent %d 0 R\n", + name, + outline->parent->res.id); + free (name); + + if (outline->prev) { + _cairo_output_stream_printf (surface->object_stream.stream, + " /Prev %d 0 R\n", + outline->prev->res.id); + } + + if (outline->next) { + _cairo_output_stream_printf (surface->object_stream.stream, + " /Next %d 0 R\n", + outline->next->res.id); + } + + if (outline->first_child) { + _cairo_output_stream_printf (surface->object_stream.stream, + " /First %d 0 R\n" + " /Last %d 0 R\n" + " /Count %d\n", + outline->first_child->res.id, + outline->last_child->res.id, + outline->count); + } + + if (outline->flags) { + int flags = 0; + if (outline->flags & CAIRO_PDF_OUTLINE_FLAG_ITALIC) + flags |= 1; + if (outline->flags & CAIRO_PDF_OUTLINE_FLAG_BOLD) + flags |= 2; + _cairo_output_stream_printf (surface->object_stream.stream, + " /F %d\n", + flags); + } + + status = cairo_pdf_interchange_write_link_action (surface, &outline->link_attrs); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->object_stream.stream, + ">>\n"); + _cairo_pdf_surface_object_end (surface); + } + + return status; +} + +/* + * Split a page label into a text prefix and numeric suffix. Leading '0's are + * included in the prefix. eg + * "3" => NULL, 3 + * "cover" => "cover", 0 + * "A-2" => "A-", 2 + * "A-002" => "A-00", 2 + */ +static char * +split_label (const char* label, int *num) +{ + int len, i; + + *num = 0; + len = strlen (label); + if (len == 0) + return NULL; + + i = len; + while (i > 0 && _cairo_isdigit (label[i-1])) + i--; + + while (i < len && label[i] == '0') + i++; + + if (i < len) + sscanf (label + i, "%d", num); + + if (i > 0) { + char *s; + s = _cairo_malloc (i + 1); + if (!s) + return NULL; + + memcpy (s, label, i); + s[i] = 0; + return s; + } + + return NULL; +} + +/* strcmp that handles NULL arguments */ +static cairo_bool_t +strcmp_null (const char *s1, const char *s2) +{ + if (s1 && s2) + return strcmp (s1, s2) == 0; + + if (!s1 && !s2) + return TRUE; + + return FALSE; +} + +static cairo_int_status_t +cairo_pdf_interchange_write_page_labels (cairo_pdf_surface_t *surface) +{ + int num_elems, i; + char *label; + char *prefix; + char *prev_prefix; + int num, prev_num; + cairo_int_status_t status; + cairo_bool_t has_labels; + + /* Check if any labels defined */ + num_elems = _cairo_array_num_elements (&surface->page_labels); + has_labels = FALSE; + for (i = 0; i < num_elems; i++) { + _cairo_array_copy_element (&surface->page_labels, i, &label); + if (label) { + has_labels = TRUE; + break; + } + } + + if (!has_labels) + return CAIRO_STATUS_SUCCESS; + + surface->page_labels_res = _cairo_pdf_surface_new_object (surface); + if (surface->page_labels_res.id == 0) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + status = _cairo_pdf_surface_object_begin (surface, surface->page_labels_res); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->object_stream.stream, + "<< /Nums [\n"); + prefix = NULL; + prev_prefix = NULL; + num = 0; + prev_num = 0; + for (i = 0; i < num_elems; i++) { + _cairo_array_copy_element (&surface->page_labels, i, &label); + if (label) { + prefix = split_label (label, &num); + } else { + prefix = NULL; + num = i + 1; + } + + if (!strcmp_null (prefix, prev_prefix) || num != prev_num + 1) { + _cairo_output_stream_printf (surface->object_stream.stream, " %d << ", i); + + if (num) + _cairo_output_stream_printf (surface->object_stream.stream, "/S /D /St %d ", num); + + if (prefix) { + char *s; + status = _cairo_utf8_to_pdf_string (prefix, &s); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->object_stream.stream, "/P %s ", s); + free (s); + } + + _cairo_output_stream_printf (surface->object_stream.stream, ">>\n"); + } + free (prev_prefix); + prev_prefix = prefix; + prefix = NULL; + prev_num = num; + } + free (prefix); + free (prev_prefix); + _cairo_output_stream_printf (surface->object_stream.stream, + " ]\n" + ">>\n"); + _cairo_pdf_surface_object_end (surface); + + return CAIRO_STATUS_SUCCESS; +} + +static void +_collect_external_dest (void *entry, void *closure) +{ + cairo_pdf_named_dest_t *dest = entry; + cairo_pdf_surface_t *surface = closure; + cairo_pdf_interchange_t *ic = &surface->interchange; + + if (!dest->attrs.internal) + ic->sorted_dests[ic->num_dests++] = dest; +} + +static int +_dest_compare (const void *a, const void *b) +{ + const cairo_pdf_named_dest_t * const *dest_a = a; + const cairo_pdf_named_dest_t * const *dest_b = b; + + return strcmp ((*dest_a)->attrs.name, (*dest_b)->attrs.name); +} + +static cairo_int_status_t +_cairo_pdf_interchange_write_document_dests (cairo_pdf_surface_t *surface) +{ + int i; + cairo_pdf_interchange_t *ic = &surface->interchange; + cairo_int_status_t status; + cairo_pdf_page_info_t *page_info; + + if (ic->num_dests == 0) { + ic->dests_res.id = 0; + return CAIRO_STATUS_SUCCESS; + } + + ic->sorted_dests = _cairo_calloc_ab (ic->num_dests, sizeof (cairo_pdf_named_dest_t *)); + if (unlikely (ic->sorted_dests == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + ic->num_dests = 0; + _cairo_hash_table_foreach (ic->named_dests, _collect_external_dest, surface); + + qsort (ic->sorted_dests, ic->num_dests, sizeof (cairo_pdf_named_dest_t *), _dest_compare); + + ic->dests_res = _cairo_pdf_surface_new_object (surface); + if (ic->dests_res.id == 0) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + status = _cairo_pdf_surface_object_begin (surface, ic->dests_res); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->object_stream.stream, + "<< /Names [\n"); + for (i = 0; i < ic->num_dests; i++) { + cairo_pdf_named_dest_t *dest = ic->sorted_dests[i]; + double x = 0; + double y = 0; + char *name = NULL; + + if (dest->attrs.internal) + continue; + + if (dest->extents.valid) { + x = dest->extents.extents.x; + y = dest->extents.extents.y; + } + + if (dest->attrs.x_valid) + x = dest->attrs.x; + + if (dest->attrs.y_valid) + y = dest->attrs.y; + + status = _cairo_utf8_to_pdf_string (dest->attrs.name, &name); + if (unlikely (status)) + return status; + + page_info = _cairo_array_index (&surface->pages, dest->page - 1); + _cairo_output_stream_printf (surface->object_stream.stream, + " %s [%d 0 R /XYZ %f %f 0]\n", + name, + page_info->page_res.id, + x, + page_info->height - y); + free (name); + + } + _cairo_output_stream_printf (surface->object_stream.stream, + " ]\n" + ">>\n"); + _cairo_pdf_surface_object_end (surface); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +cairo_pdf_interchange_write_names_dict (cairo_pdf_surface_t *surface) +{ + cairo_pdf_interchange_t *ic = &surface->interchange; + cairo_int_status_t status; + + status = _cairo_pdf_interchange_write_document_dests (surface); + if (unlikely (status)) + return status; + + surface->names_dict_res.id = 0; + if (ic->dests_res.id != 0) { + surface->names_dict_res = _cairo_pdf_surface_new_object (surface); + if (surface->names_dict_res.id == 0) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + status = _cairo_pdf_surface_object_begin (surface, surface->names_dict_res); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->object_stream.stream, + "<< /Dests %d 0 R >>\n", + ic->dests_res.id); + _cairo_pdf_surface_object_end (surface); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +cairo_pdf_interchange_write_docinfo (cairo_pdf_surface_t *surface) +{ + cairo_pdf_interchange_t *ic = &surface->interchange; + cairo_int_status_t status; + unsigned int i, num_elems; + struct metadata *data; + unsigned char *p; + + surface->docinfo_res = _cairo_pdf_surface_new_object (surface); + if (surface->docinfo_res.id == 0) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + status = _cairo_pdf_surface_object_begin (surface, surface->docinfo_res); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->object_stream.stream, + "<< /Producer (cairo %s (https://cairographics.org))\n", + cairo_version_string ()); + + if (ic->docinfo.title) + _cairo_output_stream_printf (surface->object_stream.stream, " /Title %s\n", ic->docinfo.title); + + if (ic->docinfo.author) + _cairo_output_stream_printf (surface->object_stream.stream, " /Author %s\n", ic->docinfo.author); + + if (ic->docinfo.subject) + _cairo_output_stream_printf (surface->object_stream.stream, " /Subject %s\n", ic->docinfo.subject); + + if (ic->docinfo.keywords) + _cairo_output_stream_printf (surface->object_stream.stream, " /Keywords %s\n", ic->docinfo.keywords); + + if (ic->docinfo.creator) + _cairo_output_stream_printf (surface->object_stream.stream, " /Creator %s\n", ic->docinfo.creator); + + if (ic->docinfo.create_date) + _cairo_output_stream_printf (surface->object_stream.stream, " /CreationDate %s\n", ic->docinfo.create_date); + + if (ic->docinfo.mod_date) + _cairo_output_stream_printf (surface->object_stream.stream, " /ModDate %s\n", ic->docinfo.mod_date); + + num_elems = _cairo_array_num_elements (&ic->custom_metadata); + for (i = 0; i < num_elems; i++) { + data = _cairo_array_index (&ic->custom_metadata, i); + if (data->value) { + _cairo_output_stream_printf (surface->object_stream.stream, " /"); + /* The name can be any utf8 string. Use hex codes as + * specified in section 7.3.5 of PDF reference + */ + p = (unsigned char *)data->name; + while (*p) { + if (*p < 0x21 || *p > 0x7e || *p == '#' || *p == '/') + _cairo_output_stream_printf (surface->object_stream.stream, "#%02x", *p); + else + _cairo_output_stream_printf (surface->object_stream.stream, "%c", *p); + p++; + } + _cairo_output_stream_printf (surface->object_stream.stream, " %s\n", data->value); + } + } + + _cairo_output_stream_printf (surface->object_stream.stream, + ">>\n"); + _cairo_pdf_surface_object_end (surface); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_pdf_interchange_begin_structure_tag (cairo_pdf_surface_t *surface, + cairo_tag_type_t tag_type, + const char *name, + const char *attributes) +{ + int mcid; + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + cairo_pdf_interchange_t *ic = &surface->interchange; + cairo_pdf_command_entry_t *command_entry; + cairo_pdf_struct_tree_node_t *parent_node; + unsigned int content_command_id; + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) { + ic->content_emitted = FALSE; + status = add_tree_node (surface, ic->current_analyze_node, name, attributes, &ic->current_analyze_node); + if (unlikely (status)) + return status; + + status = command_list_add (surface, ic->command_id, PDF_BEGIN); + if (unlikely (status)) + return status; + + /* Add to command_id to node map. */ + command_entry = _cairo_calloc (sizeof(cairo_pdf_command_entry_t)); + command_entry->recording_id = ic->recording_id; + command_entry->command_id = ic->command_id; + command_entry->node = ic->current_analyze_node; + _cairo_pdf_command_init_key (command_entry); + status = _cairo_hash_table_insert (ic->command_to_node_map, &command_entry->base); + if (unlikely(status)) + return status; + + if (tag_type & TAG_TYPE_LINK) { + status = add_annotation (surface, ic->current_analyze_node, name, attributes); + if (unlikely (status)) + return status; + } + + if (ic->current_analyze_node->type == PDF_NODE_CONTENT) { + cairo_pdf_content_tag_t *content = _cairo_calloc (sizeof(cairo_pdf_content_tag_t)); + content->node = ic->current_analyze_node; + _cairo_pdf_content_tag_init_key (content); + status = _cairo_hash_table_insert (ic->content_tag_map, &content->base); + if (unlikely (status)) + return status; + } + + ic->content_emitted = FALSE; + + } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_RENDER) { + if (ic->marked_content_open) { + status = _cairo_pdf_operators_tag_end (&surface->pdf_operators); + ic->marked_content_open = FALSE; + if (unlikely (status)) + return status; + } + + ic->current_render_node = lookup_node_for_command (surface, ic->recording_id, ic->command_id); + if (ic->current_render_node->type == PDF_NODE_ARTIFACT) { + if (command_list_has_content (surface, ic->command_id, NULL)) { + status = _cairo_pdf_operators_tag_begin (&surface->pdf_operators, name, -1); + ic->marked_content_open = TRUE; + } + } else if (ic->current_render_node->type == PDF_NODE_CONTENT_REF) { + parent_node = ic->current_render_node->parent; + add_child_to_mcid_array (surface, parent_node, ic->command_id, ic->current_render_node); + } else { + parent_node = ic->current_render_node->parent; + add_child_to_mcid_array (surface, parent_node, ic->command_id, ic->current_render_node); + if (command_list_has_content (surface, ic->command_id, &content_command_id)) { + add_mcid_to_node (surface, ic->current_render_node, content_command_id, &mcid); + const char *tag_name = name; + if (ic->current_render_node->type == PDF_NODE_CONTENT) + tag_name = ic->current_render_node->attributes.content.tag_name; + + status = _cairo_pdf_operators_tag_begin (&surface->pdf_operators, tag_name, mcid); + ic->marked_content_open = TRUE; + } + } + } + + return status; +} + +static cairo_int_status_t +_cairo_pdf_interchange_begin_dest_tag (cairo_pdf_surface_t *surface, + cairo_tag_type_t tag_type, + const char *name, + const char *attributes) +{ + cairo_pdf_named_dest_t *dest; + cairo_pdf_interchange_t *ic = &surface->interchange; + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) { + dest = _cairo_calloc (sizeof (cairo_pdf_named_dest_t)); + if (unlikely (dest == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + status = _cairo_tag_parse_dest_attributes (attributes, &dest->attrs); + if (unlikely (status)) + { + free (dest); + return status; + } + + dest->page = _cairo_array_num_elements (&surface->pages); + init_named_dest_key (dest); + status = _cairo_hash_table_insert (ic->named_dests, &dest->base); + if (unlikely (status)) { + free (dest->attrs.name); + free (dest); + return status; + } + + _cairo_tag_stack_set_top_data (&ic->analysis_tag_stack, dest); + ic->num_dests++; + } + + return status; +} + +cairo_int_status_t +_cairo_pdf_interchange_tag_begin (cairo_pdf_surface_t *surface, + const char *name, + const char *attributes) +{ + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + cairo_tag_type_t tag_type; + cairo_pdf_interchange_t *ic = &surface->interchange; + + if (ic->ignore_current_surface) + return CAIRO_STATUS_SUCCESS; + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) { + status = _cairo_tag_stack_push (&ic->analysis_tag_stack, name, attributes); + + } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_RENDER) { + status = _cairo_tag_stack_push (&ic->render_tag_stack, name, attributes); + } + if (unlikely (status)) + return status; + + tag_type = _cairo_tag_get_type (name); + if (tag_type & (TAG_TYPE_STRUCTURE|TAG_TYPE_CONTENT|TAG_TYPE_CONTENT_REF|TAG_TYPE_ARTIFACT)) { + status = _cairo_pdf_interchange_begin_structure_tag (surface, tag_type, name, attributes); + if (unlikely (status)) + return status; + } + + if (tag_type & TAG_TYPE_DEST) { + status = _cairo_pdf_interchange_begin_dest_tag (surface, tag_type, name, attributes); + if (unlikely (status)) + return status; + } + + return status; +} + +static cairo_int_status_t +_cairo_pdf_interchange_end_structure_tag (cairo_pdf_surface_t *surface, + cairo_tag_type_t tag_type, + cairo_tag_stack_elem_t *elem) +{ + cairo_pdf_interchange_t *ic = &surface->interchange; + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + int mcid; + unsigned int content_command_id; + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) { + assert (ic->current_analyze_node->parent != NULL); + status = command_list_add (surface, ic->command_id, PDF_END); + if (unlikely (status)) + return status; + + ic->content_emitted = FALSE; + ic->current_analyze_node = ic->current_analyze_node->parent; + + } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_RENDER) { + if (ic->marked_content_open) { + status = _cairo_pdf_operators_tag_end (&surface->pdf_operators); + ic->marked_content_open = FALSE; + if (unlikely (status)) + return status; + } + ic->current_render_node = ic->current_render_node->parent; + if (ic->current_render_node->parent && + command_list_has_content (surface, ic->command_id, &content_command_id)) + { + add_mcid_to_node (surface, ic->current_render_node, content_command_id, &mcid); + status = _cairo_pdf_operators_tag_begin (&surface->pdf_operators, + ic->current_render_node->name, mcid); + ic->marked_content_open = TRUE; + } + } + + return status; +} + +cairo_int_status_t +_cairo_pdf_interchange_tag_end (cairo_pdf_surface_t *surface, + const char *name) +{ + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + cairo_pdf_interchange_t *ic = &surface->interchange; + cairo_tag_type_t tag_type; + cairo_tag_stack_elem_t *elem; + + if (ic->ignore_current_surface) + return CAIRO_STATUS_SUCCESS; + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) { + status = _cairo_tag_stack_pop (&ic->analysis_tag_stack, name, &elem); + + } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_RENDER) { + status = _cairo_tag_stack_pop (&ic->render_tag_stack, name, &elem); + } else { + ASSERT_NOT_REACHED; + } + if (unlikely (status)) + return status; + + tag_type = _cairo_tag_get_type (name); + if (tag_type & (TAG_TYPE_STRUCTURE|TAG_TYPE_CONTENT|TAG_TYPE_CONTENT_REF|TAG_TYPE_ARTIFACT)) { + status = _cairo_pdf_interchange_end_structure_tag (surface, tag_type, elem); + if (unlikely (status)) + goto cleanup; + } + + cleanup: + _cairo_tag_stack_free_elem (elem); + + return status; +} + +cairo_int_status_t +_cairo_pdf_interchange_command_id (cairo_pdf_surface_t *surface, + unsigned int recording_id, + unsigned int command_id) +{ + cairo_pdf_interchange_t *ic = &surface->interchange; + int mcid; + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + + ic->recording_id = recording_id; + ic->command_id = command_id; + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_RENDER && ic->current_render_node) { + /* TODO If the group does not have tags we don't need to close the current tag. */ + if (command_list_is_group (surface, command_id)) { + /* A "Do /xnnn" can not be inside a tag (since the + * XObject may also contain tags). Close the tag. + */ + if (ic->marked_content_open) { + status = _cairo_pdf_operators_tag_end (&surface->pdf_operators); + ic->marked_content_open = FALSE; + } + /* If there is any more content after this and we are + * inside a tag (current node is not the root node), + * ensure that the next command will open the tag. + */ + if (command_list_has_content (surface, command_id, NULL) && ic->current_render_node->parent) { + ic->render_next_command_has_content = TRUE; + } + } else if (ic->render_next_command_has_content) { + /* After a "Do /xnnn" operation, if there is more content, open the tag. */ + add_mcid_to_node (surface, ic->current_render_node, ic->command_id, &mcid); + status = _cairo_pdf_operators_tag_begin (&surface->pdf_operators, + ic->current_render_node->name, mcid); + ic->marked_content_open = TRUE; + ic->render_next_command_has_content = FALSE; + } + } + + return status; +} + +/* Check if this use of recording surface is or will need to be part of the the struct tree */ +cairo_bool_t +_cairo_pdf_interchange_struct_tree_requires_recording_surface ( + cairo_pdf_surface_t *surface, + const cairo_surface_pattern_t *recording_surface_pattern, + cairo_analysis_source_t source_type) +{ + cairo_surface_t *recording_surface = recording_surface_pattern->surface; + cairo_surface_t *free_me = NULL; + cairo_bool_t requires_recording = FALSE; + + if (recording_surface_pattern->base.extend != CAIRO_EXTEND_NONE) + return FALSE; + + if (_cairo_surface_is_snapshot (recording_surface)) + free_me = recording_surface = _cairo_surface_snapshot_get_target (recording_surface); + + if (_cairo_surface_is_recording (recording_surface) && + _cairo_recording_surface_has_tags (recording_surface)) + { + /* Check if tags are to be ignored in this source */ + switch (source_type) { + case CAIRO_ANALYSIS_SOURCE_PAINT: + case CAIRO_ANALYSIS_SOURCE_FILL: + requires_recording = TRUE; + break; + case CAIRO_ANALYSIS_SOURCE_MASK: /* TODO: allow SOURCE_MASK with solid MASK_MASK */ + case CAIRO_ANALYSIS_MASK_MASK: + case CAIRO_ANALYSIS_SOURCE_STROKE: + case CAIRO_ANALYSIS_SOURCE_SHOW_GLYPHS: + case CAIRO_ANALYSIS_SOURCE_NONE: + break; + } + } + + cairo_surface_destroy (free_me); + return requires_recording; +} + +/* Called at the start of a recording group during analyze. This will + * be called during the analysis of the drawing operation. */ +cairo_int_status_t +_cairo_pdf_interchange_recording_source_surface_begin ( + cairo_pdf_surface_t *surface, + const cairo_surface_pattern_t *recording_surface_pattern, + unsigned int region_id, + cairo_analysis_source_t source_type) +{ + cairo_pdf_interchange_t *ic = &surface->interchange; + cairo_recording_surface_stack_entry_t element; + cairo_int_status_t status; + + /* A new recording surface is being replayed */ + ic->ignore_current_surface = TRUE; + if (_cairo_pdf_interchange_struct_tree_requires_recording_surface (surface, + recording_surface_pattern, + source_type)) + { + ic->ignore_current_surface = FALSE; + } + + element.ignore_surface = ic->ignore_current_surface; + element.current_node = ic->current_analyze_node; + ic->content_emitted = FALSE; + + /* Push to stack so that the current source identifiers can be + * restored after this recording surface has ended. */ + status = _cairo_array_append (&ic->recording_surface_stack, &element); + if (status) + return status; + + if (ic->ignore_current_surface) + return CAIRO_STATUS_SUCCESS; + + status = command_list_push_group (surface, ic->command_id, recording_surface_pattern->surface, region_id); + if (unlikely (status)) + return status; + + return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN; +} + +/* Called at the end of a recording group during analyze. */ +cairo_int_status_t +_cairo_pdf_interchange_recording_source_surface_end ( + cairo_pdf_surface_t *surface, + const cairo_surface_pattern_t *recording_surface_pattern, + unsigned int region_id, + cairo_analysis_source_t source_type) +{ + cairo_pdf_interchange_t *ic = &surface->interchange; + cairo_recording_surface_stack_entry_t element; + cairo_recording_surface_stack_entry_t *element_ptr; + + if (!ic->ignore_current_surface) + command_list_pop_group (surface); + + if (_cairo_array_pop_element (&ic->recording_surface_stack, &element)) { + element_ptr = _cairo_array_last_element (&ic->recording_surface_stack); + if (element_ptr) { + ic->ignore_current_surface = element_ptr->ignore_surface; + assert (ic->current_analyze_node == element_ptr->current_node); + } else { + /* Back at the page content. */ + ic->ignore_current_surface = FALSE; + } + ic->content_emitted = FALSE; + return CAIRO_STATUS_SUCCESS; + } + ASSERT_NOT_REACHED; /* _recording_source_surface_begin/end mismatch */ + + return CAIRO_STATUS_SUCCESS; +} + +/* Called at the start of a recording group during render. This will + * be called after the end of page content. */ +cairo_int_status_t +_cairo_pdf_interchange_emit_recording_surface_begin (cairo_pdf_surface_t *surface, + cairo_surface_t *recording_surface, + int region_id, + cairo_pdf_resource_t surface_resource, + int *struct_parents) +{ + cairo_pdf_interchange_t *ic = &surface->interchange; + cairo_int_status_t status; + + /* When + * _cairo_pdf_interchange_struct_tree_requires_recording_surface() + * is false, the region_id of the recording surface is set to 0. + */ + if (region_id == 0) { + ic->ignore_current_surface = TRUE; + return CAIRO_STATUS_SUCCESS; + } + + command_list_set_current_recording_commands (surface, recording_surface, region_id); + + ic->ignore_current_surface = FALSE; + _cairo_array_truncate (&ic->mcid_to_tree, 0); + ic->current_recording_surface_res = surface_resource; + + ic->content_parent_res = _cairo_pdf_surface_new_object (surface); + if (ic->content_parent_res.id == 0) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + status = _cairo_array_append (&ic->parent_tree, &ic->content_parent_res); + if (unlikely (status)) + return status; + + *struct_parents = _cairo_array_num_elements (&ic->parent_tree) - 1; + + ic->render_next_command_has_content = FALSE; + + return CAIRO_STATUS_SUCCESS; +} + +/* Called at the end of a recording group during render. */ +cairo_int_status_t +_cairo_pdf_interchange_emit_recording_surface_end (cairo_pdf_surface_t *surface, + cairo_surface_t *recording_surface) +{ + cairo_pdf_interchange_t *ic = &surface->interchange; + + if (ic->ignore_current_surface) + return CAIRO_STATUS_SUCCESS; + + ic->current_recording_surface_res.id = 0; + return cairo_pdf_interchange_write_content_parent_elems (surface); +} + +static void _add_operation_extents_to_dest_tag (cairo_tag_stack_elem_t *elem, + void *closure) +{ + const cairo_rectangle_int_t *extents = (const cairo_rectangle_int_t *) closure; + cairo_pdf_named_dest_t *dest; + + if (_cairo_tag_get_type (elem->name) & TAG_TYPE_DEST) { + if (elem->data) { + dest = (cairo_pdf_named_dest_t *) elem->data; + if (dest->extents.valid) { + _cairo_rectangle_union (&dest->extents.extents, extents); + } else { + dest->extents.extents = *extents; + dest->extents.valid = TRUE; + } + } + } +} + +cairo_int_status_t +_cairo_pdf_interchange_add_operation_extents (cairo_pdf_surface_t *surface, + const cairo_rectangle_int_t *extents) +{ + cairo_pdf_interchange_t *ic = &surface->interchange; + + /* Add extents to current node and all DEST tags on the stack */ + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) { + if (ic->current_analyze_node) { + if (ic->current_analyze_node->extents.valid) { + _cairo_rectangle_union (&ic->current_analyze_node->extents.extents, extents); + } else { + ic->current_analyze_node->extents.extents = *extents; + ic->current_analyze_node->extents.valid = TRUE; + } + } + + _cairo_tag_stack_foreach (&ic->analysis_tag_stack, + _add_operation_extents_to_dest_tag, + (void*)extents); + } + + return CAIRO_STATUS_SUCCESS; +} + +cairo_int_status_t +_cairo_pdf_interchange_add_content (cairo_pdf_surface_t *surface) +{ + cairo_pdf_interchange_t *ic = &surface->interchange; + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + + if (ic->ignore_current_surface) + return CAIRO_STATUS_SUCCESS; + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) { + status = command_list_add (surface, ic->command_id, PDF_CONTENT); + if (unlikely (status)) + return status; + } + + return status; +} + +/* Called at the start of 1emiting the page content during analyze or render */ +cairo_int_status_t +_cairo_pdf_interchange_begin_page_content (cairo_pdf_surface_t *surface) +{ + cairo_pdf_interchange_t *ic = &surface->interchange; + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + int mcid; + unsigned int content_command_id; + cairo_pdf_command_list_t *page_commands; + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) { + status = _cairo_array_allocate (&ic->page_commands, 1, (void**)&page_commands); + if (unlikely (status)) + return status; + + _cairo_array_init (&page_commands->commands, sizeof(cairo_pdf_command_t)); + page_commands->parent = NULL; + ic->current_commands = page_commands; + ic->ignore_current_surface = FALSE; + } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_RENDER) { + ic->current_commands = _cairo_array_last_element (&ic->page_commands); + /* Each page has its own parent tree to map MCID to nodes. */ + _cairo_array_truncate (&ic->mcid_to_tree, 0); + ic->ignore_current_surface = FALSE; + ic->content_parent_res = _cairo_pdf_surface_new_object (surface); + if (ic->content_parent_res.id == 0) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + status = _cairo_array_append (&ic->parent_tree, &ic->content_parent_res); + if (unlikely (status)) + return status; + + surface->page_parent_tree = _cairo_array_num_elements (&ic->parent_tree) - 1; + + if (ic->next_page_render_node && ic->next_page_render_node->parent && + command_list_has_content (surface, -1, &content_command_id)) + { + add_mcid_to_node (surface, ic->next_page_render_node, content_command_id, &mcid); + const char *tag_name = ic->next_page_render_node->name; + if (ic->next_page_render_node->type == PDF_NODE_CONTENT) + tag_name = ic->next_page_render_node->attributes.content.tag_name; + + status = _cairo_pdf_operators_tag_begin (&surface->pdf_operators, tag_name, mcid); + ic->marked_content_open = TRUE; + } + ic->render_next_command_has_content = FALSE; + } + + return status; +} + +/* Called at the end of emiting the page content during analyze or render */ +cairo_int_status_t +_cairo_pdf_interchange_end_page_content (cairo_pdf_surface_t *surface) +{ + cairo_pdf_interchange_t *ic = &surface->interchange; + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_RENDER) { + /* If a content tag is open across pages, the old page needs an EMC emitted. */ + if (ic->marked_content_open) { + status = _cairo_pdf_operators_tag_end (&surface->pdf_operators); + ic->marked_content_open = FALSE; + } + ic->next_page_render_node = ic->current_render_node; + } + + return status; +} + +cairo_int_status_t +_cairo_pdf_interchange_write_page_objects (cairo_pdf_surface_t *surface) +{ + return cairo_pdf_interchange_write_content_parent_elems (surface); +} + +cairo_int_status_t +_cairo_pdf_interchange_write_document_objects (cairo_pdf_surface_t *surface) +{ + cairo_pdf_interchange_t *ic = &surface->interchange; + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + cairo_tag_stack_structure_type_t tag_type; + cairo_bool_t write_struct_tree = FALSE; + + status = cairo_pdf_interchange_update_extents (surface); + if (unlikely (status)) + return status; + + tag_type = _cairo_tag_stack_get_structure_type (&ic->analysis_tag_stack); + if (tag_type == TAG_TREE_TYPE_TAGGED || tag_type == TAG_TREE_TYPE_STRUCTURE || + tag_type == TAG_TREE_TYPE_LINK_ONLY) + { + write_struct_tree = TRUE; + } + + status = cairo_pdf_interchange_write_annots (surface, write_struct_tree); + if (unlikely (status)) + return status; + + if (write_struct_tree) { + surface->struct_tree_root = _cairo_pdf_surface_new_object (surface); + if (surface->struct_tree_root.id == 0) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + ic->struct_root->res = surface->struct_tree_root; + + status = cairo_pdf_interchange_write_parent_tree (surface); + if (unlikely (status)) + return status; + + unsigned num_pages = _cairo_array_num_elements (&ic->page_commands); + for (unsigned i = 0; i < num_pages; i++) { + cairo_pdf_command_list_t *command_list; + command_list = _cairo_array_index (&ic->page_commands, i); + update_mcid_order (surface, command_list); + } + + status = cairo_pdf_interchange_write_struct_tree (surface); + if (unlikely (status)) + return status; + + if (tag_type == TAG_TREE_TYPE_TAGGED) + surface->tagged = TRUE; + } + + status = cairo_pdf_interchange_write_outline (surface); + if (unlikely (status)) + return status; + + status = cairo_pdf_interchange_write_page_labels (surface); + if (unlikely (status)) + return status; + + status = cairo_pdf_interchange_write_names_dict (surface); + if (unlikely (status)) + return status; + + status = cairo_pdf_interchange_write_docinfo (surface); + + return status; +} + +static void +_cairo_pdf_interchange_set_create_date (cairo_pdf_surface_t *surface) +{ + time_t utc, local, offset; + struct tm tm_local, tm_utc; + char buf[50]; + int buf_size; + char *p; + cairo_pdf_interchange_t *ic = &surface->interchange; + + utc = time (NULL); + localtime_r (&utc, &tm_local); + strftime (buf, sizeof(buf), "(D:%Y%m%d%H%M%S", &tm_local); + + /* strftime "%z" is non standard and does not work on windows (it prints zone name, not offset). + * Calculate time zone offset by comparing local and utc time_t values for the same time. + */ + gmtime_r (&utc, &tm_utc); + tm_utc.tm_isdst = tm_local.tm_isdst; + local = mktime (&tm_utc); + offset = difftime (utc, local); + + if (offset == 0) { + strcat (buf, "Z"); + } else { + if (offset > 0) { + strcat (buf, "+"); + } else { + strcat (buf, "-"); + offset = -offset; + } + p = buf + strlen (buf); + buf_size = sizeof (buf) - strlen (buf); + snprintf (p, buf_size, "%02d'%02d", (int)(offset/3600), (int)(offset%3600)/60); + } + strcat (buf, ")"); + ic->docinfo.create_date = strdup (buf); +} + +cairo_int_status_t +_cairo_pdf_interchange_init (cairo_pdf_surface_t *surface) +{ + cairo_pdf_interchange_t *ic = &surface->interchange; + cairo_pdf_outline_entry_t *outline_root; + cairo_int_status_t status; + + _cairo_tag_stack_init (&ic->analysis_tag_stack); + _cairo_tag_stack_init (&ic->render_tag_stack); + ic->struct_root = _cairo_calloc (sizeof(cairo_pdf_struct_tree_node_t)); + if (unlikely (ic->struct_root == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + ic->struct_root->res.id = 0; + cairo_list_init (&ic->struct_root->children); + _cairo_array_init (&ic->struct_root->mcid, sizeof(cairo_pdf_page_mcid_t)); + + ic->current_analyze_node = ic->struct_root; + ic->current_render_node = NULL; + ic->next_page_render_node = ic->struct_root; + _cairo_array_init (&ic->recording_surface_stack, sizeof(cairo_recording_surface_stack_entry_t)); + ic->current_recording_surface_res.id = 0; + ic->command_to_node_map = _cairo_hash_table_create (_cairo_pdf_command_equal); + if (unlikely (ic->command_to_node_map == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + ic->content_tag_map = _cairo_hash_table_create (_cairo_pdf_content_tag_equal); + if (unlikely (ic->content_tag_map == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + _cairo_array_init (&ic->parent_tree, sizeof(cairo_pdf_resource_t)); + _cairo_array_init (&ic->mcid_to_tree, sizeof(cairo_pdf_struct_tree_node_t *)); + _cairo_array_init (&ic->annots, sizeof(cairo_pdf_annotation_t *)); + ic->parent_tree_res.id = 0; + cairo_list_init (&ic->extents_list); + ic->named_dests = _cairo_hash_table_create (_named_dest_equal); + if (unlikely (ic->named_dests == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + _cairo_array_init (&ic->page_commands, sizeof(cairo_pdf_command_list_t)); + ic->current_commands = NULL; + _cairo_array_init (&ic->recording_surface_commands, sizeof(cairo_pdf_recording_surface_commands_t)); + + ic->num_dests = 0; + ic->sorted_dests = NULL; + ic->dests_res.id = 0; + ic->ignore_current_surface = FALSE; + ic->content_emitted = FALSE; + ic->marked_content_open = FALSE; + ic->render_next_command_has_content = FALSE; + ic->mcid_order = 0; + + _cairo_array_init (&ic->outline, sizeof(cairo_pdf_outline_entry_t *)); + outline_root = _cairo_calloc (sizeof(cairo_pdf_outline_entry_t)); + if (unlikely (outline_root == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + memset (&ic->docinfo, 0, sizeof (ic->docinfo)); + _cairo_array_init (&ic->custom_metadata, sizeof(struct metadata)); + _cairo_pdf_interchange_set_create_date (surface); + status = _cairo_array_append (&ic->outline, &outline_root); + + return status; +} + +static void +_cairo_pdf_interchange_free_outlines (cairo_pdf_surface_t *surface) +{ + cairo_pdf_interchange_t *ic = &surface->interchange; + int num_elems, i; + + num_elems = _cairo_array_num_elements (&ic->outline); + for (i = 0; i < num_elems; i++) { + cairo_pdf_outline_entry_t *outline; + + _cairo_array_copy_element (&ic->outline, i, &outline); + free (outline->name); + _cairo_tag_free_link_attributes (&outline->link_attrs); + free (outline); + } + _cairo_array_fini (&ic->outline); +} + +void +_cairo_pdf_interchange_fini (cairo_pdf_surface_t *surface) +{ + cairo_pdf_interchange_t *ic = &surface->interchange; + unsigned int i, num_elems; + struct metadata *data; + + _cairo_tag_stack_fini (&ic->analysis_tag_stack); + _cairo_tag_stack_fini (&ic->render_tag_stack); + _cairo_array_fini (&ic->mcid_to_tree); + cairo_pdf_interchange_clear_annotations (surface); + _cairo_array_fini (&ic->annots); + + _cairo_array_fini (&ic->recording_surface_stack); + _cairo_array_fini (&ic->parent_tree); + + _cairo_hash_table_foreach (ic->command_to_node_map, + _cairo_pdf_command_pluck, + ic->command_to_node_map); + _cairo_hash_table_destroy (ic->command_to_node_map); + + _cairo_hash_table_foreach (ic->named_dests, _named_dest_pluck, ic->named_dests); + _cairo_hash_table_destroy (ic->named_dests); + + _cairo_hash_table_foreach (ic->content_tag_map, _cairo_pdf_content_tag_pluck, ic->content_tag_map); + _cairo_hash_table_destroy(ic->content_tag_map); + + free_node (ic->struct_root); + + num_elems = _cairo_array_num_elements (&ic->recording_surface_commands); + for (i = 0; i < num_elems; i++) { + cairo_pdf_recording_surface_commands_t *recording_command; + cairo_pdf_command_list_t *command_list; + + recording_command = _cairo_array_index (&ic->recording_surface_commands, i); + command_list = recording_command->command_list; + _cairo_array_fini (&command_list->commands); + free (command_list); + } + _cairo_array_fini (&ic->recording_surface_commands); + + num_elems = _cairo_array_num_elements (&ic->page_commands); + for (i = 0; i < num_elems; i++) { + cairo_pdf_command_list_t *command_list; + command_list = _cairo_array_index (&ic->page_commands, i); + _cairo_array_fini (&command_list->commands); + } + _cairo_array_fini (&ic->page_commands); + + free (ic->sorted_dests); + _cairo_pdf_interchange_free_outlines (surface); + free (ic->docinfo.title); + free (ic->docinfo.author); + free (ic->docinfo.subject); + free (ic->docinfo.keywords); + free (ic->docinfo.creator); + free (ic->docinfo.create_date); + free (ic->docinfo.mod_date); + + num_elems = _cairo_array_num_elements (&ic->custom_metadata); + for (i = 0; i < num_elems; i++) { + data = _cairo_array_index (&ic->custom_metadata, i); + free (data->name); + free (data->value); + } + _cairo_array_fini (&ic->custom_metadata); +} + +cairo_int_status_t +_cairo_pdf_interchange_add_outline (cairo_pdf_surface_t *surface, + int parent_id, + const char *name, + const char *link_attribs, + cairo_pdf_outline_flags_t flags, + int *id) +{ + cairo_pdf_interchange_t *ic = &surface->interchange; + cairo_pdf_outline_entry_t *outline; + cairo_pdf_outline_entry_t *parent; + cairo_int_status_t status; + + if (parent_id < 0 || parent_id >= (int)_cairo_array_num_elements (&ic->outline)) + return CAIRO_STATUS_SUCCESS; + + outline = _cairo_calloc (sizeof(cairo_pdf_outline_entry_t)); + if (unlikely (outline == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + status = _cairo_tag_parse_link_attributes (link_attribs, &outline->link_attrs); + if (unlikely (status)) { + free (outline); + return status; + } + + outline->res = _cairo_pdf_surface_new_object (surface); + if (outline->res.id == 0) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + outline->name = strdup (name); + outline->flags = flags; + outline->count = 0; + + _cairo_array_copy_element (&ic->outline, parent_id, &parent); + + outline->parent = parent; + outline->first_child = NULL; + outline->last_child = NULL; + outline->next = NULL; + if (parent->last_child) { + parent->last_child->next = outline; + outline->prev = parent->last_child; + parent->last_child = outline; + } else { + parent->first_child = outline; + parent->last_child = outline; + outline->prev = NULL; + } + + *id = _cairo_array_num_elements (&ic->outline); + status = _cairo_array_append (&ic->outline, &outline); + if (unlikely (status)) + return status; + + /* Update Count */ + outline = outline->parent; + while (outline) { + if (outline->flags & CAIRO_PDF_OUTLINE_FLAG_OPEN) { + outline->count++; + } else { + outline->count--; + break; + } + outline = outline->parent; + } + + return CAIRO_STATUS_SUCCESS; +} + +/* + * Date must be in the following format: + * + * YYYY-MM-DDThh:mm:ss[Z+-]hh:mm + * + * Only the year is required. If a field is included all preceding + * fields must be included. + */ +static char * +iso8601_to_pdf_date_string (const char *iso) +{ + char buf[40]; + const char *p; + int i; + + /* Check that utf8 contains only the characters "0123456789-T:Z+" */ + p = iso; + while (*p) { + if (!_cairo_isdigit (*p) && *p != '-' && *p != 'T' && + *p != ':' && *p != 'Z' && *p != '+') + return NULL; + p++; + } + + p = iso; + strcpy (buf, "("); + + /* YYYY (required) */ + if (strlen (p) < 4) + return NULL; + + strncat (buf, p, 4); + p += 4; + + /* -MM, -DD, Thh, :mm, :ss */ + for (i = 0; i < 5; i++) { + if (strlen (p) < 3) + goto finish; + + strncat (buf, p + 1, 2); + p += 3; + } + + /* Z, +, - */ + if (strlen (p) < 1) + goto finish; + strncat (buf, p, 1); + p += 1; + + /* hh */ + if (strlen (p) < 2) + goto finish; + + strncat (buf, p, 2); + strcat (buf, "'"); + p += 2; + + /* :mm */ + if (strlen (p) < 3) + goto finish; + + strncat (buf, p + 1, 2); + strcat (buf, "'"); + + finish: + strcat (buf, ")"); + return strdup (buf); +} + +cairo_int_status_t +_cairo_pdf_interchange_set_metadata (cairo_pdf_surface_t *surface, + cairo_pdf_metadata_t metadata, + const char *utf8) +{ + cairo_pdf_interchange_t *ic = &surface->interchange; + cairo_status_t status; + char *s = NULL; + + if (utf8) { + if (metadata == CAIRO_PDF_METADATA_CREATE_DATE || + metadata == CAIRO_PDF_METADATA_MOD_DATE) { + s = iso8601_to_pdf_date_string (utf8); + } else { + status = _cairo_utf8_to_pdf_string (utf8, &s); + if (unlikely (status)) + return status; + } + } + + switch (metadata) { + case CAIRO_PDF_METADATA_TITLE: + free (ic->docinfo.title); + ic->docinfo.title = s; + break; + case CAIRO_PDF_METADATA_AUTHOR: + free (ic->docinfo.author); + ic->docinfo.author = s; + break; + case CAIRO_PDF_METADATA_SUBJECT: + free (ic->docinfo.subject); + ic->docinfo.subject = s; + break; + case CAIRO_PDF_METADATA_KEYWORDS: + free (ic->docinfo.keywords); + ic->docinfo.keywords = s; + break; + case CAIRO_PDF_METADATA_CREATOR: + free (ic->docinfo.creator); + ic->docinfo.creator = s; + break; + case CAIRO_PDF_METADATA_CREATE_DATE: + free (ic->docinfo.create_date); + ic->docinfo.create_date = s; + break; + case CAIRO_PDF_METADATA_MOD_DATE: + free (ic->docinfo.mod_date); + ic->docinfo.mod_date = s; + break; + } + + return CAIRO_STATUS_SUCCESS; +} + +static const char *reserved_metadata_names[] = { + "", + "Title", + "Author", + "Subject", + "Keywords", + "Creator", + "Producer", + "CreationDate", + "ModDate", + "Trapped", +}; + +cairo_int_status_t +_cairo_pdf_interchange_set_custom_metadata (cairo_pdf_surface_t *surface, + const char *name, + const char *value) +{ + cairo_pdf_interchange_t *ic = &surface->interchange; + struct metadata *data; + struct metadata new_data; + int i, num_elems; + cairo_int_status_t status; + char *s = NULL; + + if (name == NULL) + return CAIRO_STATUS_NULL_POINTER; + + for (i = 0; i < ARRAY_LENGTH (reserved_metadata_names); i++) { + if (strcmp(name, reserved_metadata_names[i]) == 0) + return CAIRO_STATUS_INVALID_STRING; + } + + /* First check if we already have an entry for this name. If so, + * update the value. A NULL value means the entry has been removed + * and will not be emitted. */ + num_elems = _cairo_array_num_elements (&ic->custom_metadata); + for (i = 0; i < num_elems; i++) { + data = _cairo_array_index (&ic->custom_metadata, i); + if (strcmp(name, data->name) == 0) { + free (data->value); + data->value = NULL; + if (value && strlen(value)) { + status = _cairo_utf8_to_pdf_string (value, &s); + if (unlikely (status)) + return status; + data->value = s; + } + return CAIRO_STATUS_SUCCESS; + } + } + + /* Add new entry */ + status = CAIRO_STATUS_SUCCESS; + if (value && strlen(value)) { + new_data.name = strdup (name); + status = _cairo_utf8_to_pdf_string (value, &s); + if (unlikely (status)) { + free (new_data.name); + return status; + } + new_data.value = s; + status = _cairo_array_append (&ic->custom_metadata, &new_data); + } + + return status; +} + +#if DEBUG_PDF_INTERCHANGE +static cairo_int_status_t +print_node (cairo_pdf_surface_t *surface, + cairo_pdf_struct_tree_node_t *node, + int depth) +{ + if (node == NULL) { + printf("%*sNode: ptr: NULL\n", depth*2, ""); + } else if (node == surface->interchange.struct_root) { + printf("%*sNode: ptr: %p root\n", depth*2, "", node); + } else { + printf("%*sNode: ptr: %p name: '%s'\n", depth*2, "", node, node->name); + } + depth++; + printf("%*sType: ", depth*2, ""); + switch (node->type) { + case PDF_NODE_STRUCT: + printf("STRUCT\n"); + break; + case PDF_NODE_CONTENT: + printf("CONTENT\n"); + printf("%*sContent.id: %s\n", depth*2, "", node->attributes.content.id); + printf("%*sContent.tag_name: %s\n", depth*2, "", node->attributes.content.tag_name); + break; + case PDF_NODE_CONTENT_REF: + printf("CONTENT_REF\n"); + printf("%*sContent_Ref.ref: %s\n", depth*2, "", node->attributes.content_ref.ref); + break; + case PDF_NODE_ARTIFACT: + printf("ARTIFACT\n"); + break; + } + printf("%*sres: %d\n", depth*2, "", node->res.id); + printf("%*sparent: %p\n", depth*2, "", node->parent); + printf("%*sannot:", depth*2, ""); + if (node->annot) + printf(" node: %p res: %d", node->annot->node, node->annot->res.id); + printf("\n"); + printf("%*sextents: ", depth*2, ""); + if (node->extents.valid) { + printf("x: %d y: %d w: %d h: %d\n", + node->extents.extents.x, + node->extents.extents.y, + node->extents.extents.width, + node->extents.extents.height); + } else { + printf("not valid\n"); + } + + printf("%*smcid: ", depth*2, ""); + int num_mcid = _cairo_array_num_elements (&node->mcid); + for (int i = 0; i < num_mcid; i++) { + cairo_pdf_page_mcid_t *mcid_elem = _cairo_array_index (&node->mcid, i); + if (mcid_elem->child_node) { + printf("(order: %d, %p) ", mcid_elem->order, mcid_elem->child_node); + } else { + printf("(order: %d, pg: %d, xobject_res: %d, mcid: %d) ", + mcid_elem->order, mcid_elem->page, mcid_elem->xobject_res.id, mcid_elem->mcid); + } + } + printf("\n"); + return CAIRO_STATUS_SUCCESS; +} + +static void +print_tree (cairo_pdf_surface_t *surface, + cairo_pdf_struct_tree_node_t *node) +{ + printf("Structure Tree:\n"); + cairo_pdf_interchange_walk_struct_tree (surface, node, 0, print_node); +} + +static void +print_command (cairo_pdf_command_t *command, int indent) +{ + printf("%*s%d ", indent*2, "", command->command_id); + switch (command->flags) { + case PDF_CONTENT: + printf("CONTENT"); + break; + case PDF_BEGIN: + printf("BEGIN"); + break; + case PDF_END: + printf("END"); + break; + case PDF_GROUP: + printf("GROUP: %p", command->group); + break; + case PDF_NONE: + printf("NONE"); + break; + } + printf(" node: %p index: %d\n", command->node, command->mcid_index); +} + +static void +print_commands (cairo_pdf_command_list_t *command_list, int indent) +{ + cairo_pdf_command_t *command; + unsigned i; + unsigned num_elements = _cairo_array_num_elements (&command_list->commands); + + for (i = 0; i < num_elements; i++) { + command = _cairo_array_index (&command_list->commands, i); + print_command (command, indent); + if (command->flags == PDF_GROUP) + print_commands (command->group, indent + 1); + } +} + +static void +print_command_list(cairo_pdf_command_list_t *command_list) +{ + printf("Command List: %p\n", command_list); + print_commands (command_list, 0); + printf("end\n"); +} +#endif diff --git a/local/recipes/libs/cairo/source/src/cairo-pdf-operators-private.h b/local/recipes/libs/cairo/source/src/cairo-pdf-operators-private.h new file mode 100644 index 0000000000..ed8be7f96e --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-pdf-operators-private.h @@ -0,0 +1,184 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2004 Red Hat, Inc + * Copyright © 2006 Red Hat, Inc + * Copyright © 2007 Adrian Johnson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Kristian Høgsberg + * Carl Worth + * Adrian Johnson + */ + +#ifndef CAIRO_PDF_OPERATORS_H +#define CAIRO_PDF_OPERATORS_H + +#include "cairo-compiler-private.h" +#include "cairo-error-private.h" +#include "cairo-types-private.h" + +/* The glyph buffer size is based on the expected maximum glyphs in a + * line so that an entire line can be emitted in as one string. If the + * glyphs in a line exceeds this size the only downside is the slight + * overhead of emitting two strings. + */ +#define PDF_GLYPH_BUFFER_SIZE 200 + +typedef cairo_int_status_t +(*cairo_pdf_operators_use_font_subset_t) (unsigned int font_id, + unsigned int subset_id, + void *closure); + +typedef struct _cairo_pdf_glyph { + unsigned int glyph_index; + double x_position; + double x_advance; +} cairo_pdf_glyph_t; + +typedef struct _cairo_pdf_operators { + cairo_output_stream_t *stream; + cairo_matrix_t cairo_to_pdf; + cairo_scaled_font_subsets_t *font_subsets; + cairo_pdf_operators_use_font_subset_t use_font_subset; + void *use_font_subset_closure; + cairo_bool_t ps_output; /* output is for PostScript */ + cairo_bool_t use_actual_text; + cairo_bool_t in_text_object; /* inside BT/ET pair */ + + /* PDF text state */ + cairo_bool_t is_new_text_object; /* text object started but matrix and font not yet selected */ + unsigned int font_id; + unsigned int subset_id; + cairo_matrix_t text_matrix; /* PDF text matrix (Tlm in the PDF reference) */ + cairo_matrix_t cairo_to_pdftext; /* translate cairo coords to PDF text space */ + cairo_matrix_t font_matrix_inverse; + double cur_x; /* Current position in PDF text space (Tm in the PDF reference) */ + double cur_y; + int hex_width; + cairo_bool_t is_latin; + int num_glyphs; + double glyph_buf_x_pos; + cairo_pdf_glyph_t glyphs[PDF_GLYPH_BUFFER_SIZE]; + + /* PDF line style */ + cairo_bool_t has_line_style; + double line_width; + cairo_line_cap_t line_cap; + cairo_line_join_t line_join; + double miter_limit; + cairo_bool_t has_dashes; +} cairo_pdf_operators_t; + +cairo_private void +_cairo_pdf_operators_init (cairo_pdf_operators_t *pdf_operators, + cairo_output_stream_t *stream, + cairo_matrix_t *cairo_to_pdf, + cairo_scaled_font_subsets_t *font_subsets, + cairo_bool_t ps); + +cairo_private cairo_status_t +_cairo_pdf_operators_fini (cairo_pdf_operators_t *pdf_operators); + +cairo_private void +_cairo_pdf_operators_set_font_subsets_callback (cairo_pdf_operators_t *pdf_operators, + cairo_pdf_operators_use_font_subset_t use_font_subset, + void *closure); + +cairo_private void +_cairo_pdf_operators_set_stream (cairo_pdf_operators_t *pdf_operators, + cairo_output_stream_t *stream); + + +cairo_private void +_cairo_pdf_operators_set_cairo_to_pdf_matrix (cairo_pdf_operators_t *pdf_operators, + cairo_matrix_t *cairo_to_pdf); + +cairo_private void +_cairo_pdf_operators_enable_actual_text (cairo_pdf_operators_t *pdf_operators, + cairo_bool_t enable); + +cairo_private cairo_status_t +_cairo_pdf_operators_flush (cairo_pdf_operators_t *pdf_operators); + +cairo_private void +_cairo_pdf_operators_reset (cairo_pdf_operators_t *pdf_operators); + +cairo_private cairo_int_status_t +_cairo_pdf_operators_clip (cairo_pdf_operators_t *pdf_operators, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule); + +cairo_private cairo_int_status_t +_cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators, + const cairo_stroke_style_t *style, + double scale); + +cairo_private cairo_int_status_t +_cairo_pdf_operators_stroke (cairo_pdf_operators_t *pdf_operators, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse); + +cairo_private cairo_int_status_t +_cairo_pdf_operators_fill (cairo_pdf_operators_t *pdf_operators, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule); + +cairo_private cairo_int_status_t +_cairo_pdf_operators_fill_stroke (cairo_pdf_operators_t *pdf_operators, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse); + +cairo_private cairo_int_status_t +_cairo_pdf_operators_show_text_glyphs (cairo_pdf_operators_t *pdf_operators, + const char *utf8, + int utf8_len, + cairo_glyph_t *glyphs, + int num_glyphs, + const cairo_text_cluster_t *clusters, + int num_clusters, + cairo_text_cluster_flags_t cluster_flags, + cairo_scaled_font_t *scaled_font); + +cairo_private cairo_int_status_t +_cairo_pdf_operators_tag_begin (cairo_pdf_operators_t *pdf_operators, + const char *tag_name, + int mcid); + +cairo_private cairo_int_status_t +_cairo_pdf_operators_tag_end (cairo_pdf_operators_t *pdf_operators); + +#endif /* CAIRO_PDF_OPERATORS_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-pdf-operators.c b/local/recipes/libs/cairo/source/src/cairo-pdf-operators.c new file mode 100644 index 0000000000..7bed413104 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-pdf-operators.c @@ -0,0 +1,1601 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2004 Red Hat, Inc + * Copyright © 2006 Red Hat, Inc + * Copyright © 2007, 2008 Adrian Johnson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Kristian Høgsberg + * Carl Worth + * Adrian Johnson + */ + +#include "cairoint.h" + +#if CAIRO_HAS_PDF_OPERATORS + +#include "cairo-error-private.h" +#include "cairo-pdf-operators-private.h" +#include "cairo-path-fixed-private.h" +#include "cairo-output-stream-private.h" +#include "cairo-scaled-font-subsets-private.h" + +static cairo_status_t +_cairo_pdf_operators_end_text (cairo_pdf_operators_t *pdf_operators); + + +void +_cairo_pdf_operators_init (cairo_pdf_operators_t *pdf_operators, + cairo_output_stream_t *stream, + cairo_matrix_t *cairo_to_pdf, + cairo_scaled_font_subsets_t *font_subsets, + cairo_bool_t ps) +{ + pdf_operators->stream = stream; + pdf_operators->cairo_to_pdf = *cairo_to_pdf; + pdf_operators->font_subsets = font_subsets; + pdf_operators->ps_output = ps; + pdf_operators->use_font_subset = NULL; + pdf_operators->use_font_subset_closure = NULL; + pdf_operators->in_text_object = FALSE; + pdf_operators->num_glyphs = 0; + pdf_operators->has_line_style = FALSE; + pdf_operators->use_actual_text = FALSE; +} + +cairo_status_t +_cairo_pdf_operators_fini (cairo_pdf_operators_t *pdf_operators) +{ + return _cairo_pdf_operators_flush (pdf_operators); +} + +void +_cairo_pdf_operators_set_font_subsets_callback (cairo_pdf_operators_t *pdf_operators, + cairo_pdf_operators_use_font_subset_t use_font_subset, + void *closure) +{ + pdf_operators->use_font_subset = use_font_subset; + pdf_operators->use_font_subset_closure = closure; +} + +/* Change the output stream to a different stream. + * _cairo_pdf_operators_flush() should always be called before calling + * this function. + */ +void +_cairo_pdf_operators_set_stream (cairo_pdf_operators_t *pdf_operators, + cairo_output_stream_t *stream) +{ + pdf_operators->stream = stream; + pdf_operators->has_line_style = FALSE; +} + +void +_cairo_pdf_operators_set_cairo_to_pdf_matrix (cairo_pdf_operators_t *pdf_operators, + cairo_matrix_t *cairo_to_pdf) +{ + pdf_operators->cairo_to_pdf = *cairo_to_pdf; + pdf_operators->has_line_style = FALSE; +} + +cairo_private void +_cairo_pdf_operators_enable_actual_text (cairo_pdf_operators_t *pdf_operators, + cairo_bool_t enable) +{ + pdf_operators->use_actual_text = enable; +} + +/* Finish writing out any pending commands to the stream. This + * function must be called by the surface before emitting anything + * into the PDF stream. + * + * pdf_operators may leave the emitted PDF for some operations + * unfinished in case subsequent operations can be merged. This + * function will finish off any incomplete operation so the stream + * will be in a state where the surface may emit its own PDF + * operations (eg changing patterns). + * + */ +cairo_status_t +_cairo_pdf_operators_flush (cairo_pdf_operators_t *pdf_operators) +{ + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + if (pdf_operators->in_text_object) + status = _cairo_pdf_operators_end_text (pdf_operators); + + return status; +} + +/* Reset the known graphics state of the PDF consumer. ie no + * assumptions will be made about the state. The next time a + * particular graphics state is required (eg line width) the state + * operator is always emitted and then remembered for subsequent + * operations. + * + * This should be called when starting a new stream or after emitting + * the 'Q' operator (where pdf-operators functions were called inside + * the q/Q pair). + */ +void +_cairo_pdf_operators_reset (cairo_pdf_operators_t *pdf_operators) +{ + pdf_operators->has_line_style = FALSE; +} + +/* A word wrap stream can be used as a filter to do word wrapping on + * top of an existing output stream. The word wrapping is quite + * simple, using isspace to determine characters that separate + * words. Any word that will cause the column count exceed the given + * max_column will have a '\n' character emitted before it. + * + * The stream is careful to maintain integrity for words that cross + * the boundary from one call to write to the next. + * + * Note: This stream does not guarantee that the output will never + * exceed max_column. In particular, if a single word is larger than + * max_column it will not be broken up. + */ + +typedef enum _cairo_word_wrap_state { + WRAP_STATE_DELIMITER, + WRAP_STATE_WORD, + WRAP_STATE_STRING, + WRAP_STATE_HEXSTRING +} cairo_word_wrap_state_t; + + +typedef struct _word_wrap_stream { + cairo_output_stream_t base; + cairo_output_stream_t *output; + int max_column; + cairo_bool_t ps_output; + int column; + cairo_word_wrap_state_t state; + cairo_bool_t in_escape; + int escape_digits; +} word_wrap_stream_t; + + + +/* Emit word bytes up to the next delimiter character */ +static int +_word_wrap_stream_count_word_up_to (word_wrap_stream_t *stream, + const unsigned char *data, int length) +{ + const unsigned char *s = data; + int count = 0; + + while (length--) { + if (_cairo_isspace (*s) || *s == '<' || *s == '(') { + stream->state = WRAP_STATE_DELIMITER; + break; + } + + count++; + stream->column++; + s++; + } + + if (count) + _cairo_output_stream_write (stream->output, data, count); + + return count; +} + + +/* Emit hexstring bytes up to either the end of the ASCII hexstring or the number + * of columns remaining. + */ +static int +_word_wrap_stream_count_hexstring_up_to (word_wrap_stream_t *stream, + const unsigned char *data, int length) +{ + const unsigned char *s = data; + int count = 0; + cairo_bool_t newline = FALSE; + + while (length--) { + count++; + stream->column++; + if (*s == '>') { + stream->state = WRAP_STATE_DELIMITER; + break; + } + + if (stream->column > stream->max_column) { + newline = TRUE; + break; + } + s++; + } + + if (count) + _cairo_output_stream_write (stream->output, data, count); + + if (newline) { + _cairo_output_stream_printf (stream->output, "\n"); + stream->column = 0; + } + + return count; +} + +/* Count up to either the end of the string or the number of columns + * remaining. + */ +static int +_word_wrap_stream_count_string_up_to (word_wrap_stream_t *stream, + const unsigned char *data, int length) +{ + const unsigned char *s = data; + int count = 0; + cairo_bool_t newline = FALSE; + + while (length--) { + count++; + stream->column++; + if (!stream->in_escape) { + if (*s == ')') { + stream->state = WRAP_STATE_DELIMITER; + break; + } + if (*s == '\\') { + stream->in_escape = TRUE; + stream->escape_digits = 0; + } else if (stream->ps_output && stream->column > stream->max_column) { + newline = TRUE; + break; + } + } else { + if (!_cairo_isdigit(*s) || ++stream->escape_digits == 3) + stream->in_escape = FALSE; + } + s++; + } + + if (count) + _cairo_output_stream_write (stream->output, data, count); + + if (newline) { + _cairo_output_stream_printf (stream->output, "\\\n"); + stream->column = 0; + } + + return count; +} + +static cairo_status_t +_word_wrap_stream_write (cairo_output_stream_t *base, + const unsigned char *data, + unsigned int length) +{ + word_wrap_stream_t *stream = (word_wrap_stream_t *) base; + int count; + + while (length) { + switch (stream->state) { + case WRAP_STATE_WORD: + count = _word_wrap_stream_count_word_up_to (stream, data, length); + break; + case WRAP_STATE_HEXSTRING: + count = _word_wrap_stream_count_hexstring_up_to (stream, data, length); + break; + case WRAP_STATE_STRING: + count = _word_wrap_stream_count_string_up_to (stream, data, length); + break; + case WRAP_STATE_DELIMITER: + count = 1; + stream->column++; + if (*data == '\n' || stream->column >= stream->max_column) { + _cairo_output_stream_printf (stream->output, "\n"); + stream->column = 0; + } + if (*data == '<') { + stream->state = WRAP_STATE_HEXSTRING; + } else if (*data == '(') { + stream->state = WRAP_STATE_STRING; + } else if (!_cairo_isspace (*data)) { + stream->state = WRAP_STATE_WORD; + } + if (*data != '\n') + _cairo_output_stream_write (stream->output, data, 1); + break; + + default: + ASSERT_NOT_REACHED; + count = length; + break; + } + data += count; + length -= count; + } + + return _cairo_output_stream_get_status (stream->output); +} + +static cairo_status_t +_word_wrap_stream_close (cairo_output_stream_t *base) +{ + word_wrap_stream_t *stream = (word_wrap_stream_t *) base; + + return _cairo_output_stream_get_status (stream->output); +} + +static cairo_output_stream_t * +_word_wrap_stream_create (cairo_output_stream_t *output, cairo_bool_t ps, int max_column) +{ + word_wrap_stream_t *stream; + + if (output->status) + return _cairo_output_stream_create_in_error (output->status); + + stream = _cairo_calloc (sizeof (word_wrap_stream_t)); + if (unlikely (stream == NULL)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_output_stream_t *) &_cairo_output_stream_nil; + } + + _cairo_output_stream_init (&stream->base, + _word_wrap_stream_write, + NULL, + _word_wrap_stream_close); + stream->output = output; + stream->max_column = max_column; + stream->ps_output = ps; + stream->column = 0; + stream->state = WRAP_STATE_DELIMITER; + stream->in_escape = FALSE; + stream->escape_digits = 0; + + return &stream->base; +} + +typedef struct _pdf_path_info { + cairo_output_stream_t *output; + cairo_matrix_t *path_transform; + cairo_line_cap_t line_cap; + cairo_point_t last_move_to_point; + cairo_bool_t has_sub_path; +} pdf_path_info_t; + +static cairo_status_t +_cairo_pdf_path_move_to (void *closure, + const cairo_point_t *point) +{ + pdf_path_info_t *info = closure; + double x = _cairo_fixed_to_double (point->x); + double y = _cairo_fixed_to_double (point->y); + + info->last_move_to_point = *point; + info->has_sub_path = FALSE; + cairo_matrix_transform_point (info->path_transform, &x, &y); + _cairo_output_stream_printf (info->output, + "%g %g m ", x, y); + + return _cairo_output_stream_get_status (info->output); +} + +static cairo_status_t +_cairo_pdf_path_line_to (void *closure, + const cairo_point_t *point) +{ + pdf_path_info_t *info = closure; + double x = _cairo_fixed_to_double (point->x); + double y = _cairo_fixed_to_double (point->y); + + if (info->line_cap != CAIRO_LINE_CAP_ROUND && + ! info->has_sub_path && + point->x == info->last_move_to_point.x && + point->y == info->last_move_to_point.y) + { + return CAIRO_STATUS_SUCCESS; + } + + info->has_sub_path = TRUE; + cairo_matrix_transform_point (info->path_transform, &x, &y); + _cairo_output_stream_printf (info->output, + "%g %g l ", x, y); + + return _cairo_output_stream_get_status (info->output); +} + +static cairo_status_t +_cairo_pdf_path_curve_to (void *closure, + const cairo_point_t *b, + const cairo_point_t *c, + const cairo_point_t *d) +{ + pdf_path_info_t *info = closure; + double bx = _cairo_fixed_to_double (b->x); + double by = _cairo_fixed_to_double (b->y); + double cx = _cairo_fixed_to_double (c->x); + double cy = _cairo_fixed_to_double (c->y); + double dx = _cairo_fixed_to_double (d->x); + double dy = _cairo_fixed_to_double (d->y); + + info->has_sub_path = TRUE; + cairo_matrix_transform_point (info->path_transform, &bx, &by); + cairo_matrix_transform_point (info->path_transform, &cx, &cy); + cairo_matrix_transform_point (info->path_transform, &dx, &dy); + _cairo_output_stream_printf (info->output, + "%g %g %g %g %g %g c ", + bx, by, cx, cy, dx, dy); + return _cairo_output_stream_get_status (info->output); +} + +static cairo_status_t +_cairo_pdf_path_close_path (void *closure) +{ + pdf_path_info_t *info = closure; + + if (info->line_cap != CAIRO_LINE_CAP_ROUND && + ! info->has_sub_path) + { + return CAIRO_STATUS_SUCCESS; + } + + _cairo_output_stream_printf (info->output, + "h\n"); + + return _cairo_output_stream_get_status (info->output); +} + +static cairo_status_t +_cairo_pdf_path_rectangle (pdf_path_info_t *info, cairo_box_t *box) +{ + double x1 = _cairo_fixed_to_double (box->p1.x); + double y1 = _cairo_fixed_to_double (box->p1.y); + double x2 = _cairo_fixed_to_double (box->p2.x); + double y2 = _cairo_fixed_to_double (box->p2.y); + + cairo_matrix_transform_point (info->path_transform, &x1, &y1); + cairo_matrix_transform_point (info->path_transform, &x2, &y2); + _cairo_output_stream_printf (info->output, + "%g %g %g %g re ", + x1, y1, x2 - x1, y2 - y1); + + return _cairo_output_stream_get_status (info->output); +} + +/* The line cap value is needed to workaround the fact that PostScript + * and PDF semantics for stroking degenerate sub-paths do not match + * cairo semantics. (PostScript draws something for any line cap + * value, while cairo draws something only for round caps). + * + * When using this function to emit a path to be filled, rather than + * stroked, simply pass %CAIRO_LINE_CAP_ROUND which will guarantee that + * the stroke workaround will not modify the path being emitted. + */ +static cairo_status_t +_cairo_pdf_operators_emit_path (cairo_pdf_operators_t *pdf_operators, + const cairo_path_fixed_t*path, + cairo_matrix_t *path_transform, + cairo_line_cap_t line_cap) +{ + cairo_output_stream_t *word_wrap; + cairo_status_t status, status2; + pdf_path_info_t info; + cairo_box_t box; + + word_wrap = _word_wrap_stream_create (pdf_operators->stream, pdf_operators->ps_output, 72); + status = _cairo_output_stream_get_status (word_wrap); + if (unlikely (status)) + return _cairo_output_stream_destroy (word_wrap); + + info.output = word_wrap; + info.path_transform = path_transform; + info.line_cap = line_cap; + if (_cairo_path_fixed_is_rectangle (path, &box) && + ((path_transform->xx == 0 && path_transform->yy == 0) || + (path_transform->xy == 0 && path_transform->yx == 0))) { + status = _cairo_pdf_path_rectangle (&info, &box); + } else { + status = _cairo_path_fixed_interpret (path, + _cairo_pdf_path_move_to, + _cairo_pdf_path_line_to, + _cairo_pdf_path_curve_to, + _cairo_pdf_path_close_path, + &info); + } + + status2 = _cairo_output_stream_destroy (word_wrap); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; + + return status; +} + +cairo_int_status_t +_cairo_pdf_operators_clip (cairo_pdf_operators_t *pdf_operators, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule) +{ + const char *pdf_operator; + cairo_status_t status; + + if (pdf_operators->in_text_object) { + status = _cairo_pdf_operators_end_text (pdf_operators); + if (unlikely (status)) + return status; + } + + if (! path->has_current_point) { + /* construct an empty path */ + _cairo_output_stream_printf (pdf_operators->stream, "0 0 m "); + } else { + status = _cairo_pdf_operators_emit_path (pdf_operators, + path, + &pdf_operators->cairo_to_pdf, + CAIRO_LINE_CAP_ROUND); + if (unlikely (status)) + return status; + } + + switch (fill_rule) { + default: + ASSERT_NOT_REACHED; + case CAIRO_FILL_RULE_WINDING: + pdf_operator = "W"; + break; + case CAIRO_FILL_RULE_EVEN_ODD: + pdf_operator = "W*"; + break; + } + + _cairo_output_stream_printf (pdf_operators->stream, + "%s n\n", + pdf_operator); + + return _cairo_output_stream_get_status (pdf_operators->stream); +} + +static int +_cairo_pdf_line_cap (cairo_line_cap_t cap) +{ + switch (cap) { + case CAIRO_LINE_CAP_BUTT: + return 0; + case CAIRO_LINE_CAP_ROUND: + return 1; + case CAIRO_LINE_CAP_SQUARE: + return 2; + default: + ASSERT_NOT_REACHED; + return 0; + } +} + +static int +_cairo_pdf_line_join (cairo_line_join_t join) +{ + switch (join) { + case CAIRO_LINE_JOIN_MITER: + return 0; + case CAIRO_LINE_JOIN_ROUND: + return 1; + case CAIRO_LINE_JOIN_BEVEL: + return 2; + default: + ASSERT_NOT_REACHED; + return 0; + } +} + +cairo_int_status_t +_cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t *pdf_operators, + const cairo_stroke_style_t *style, + double scale) +{ + double *dash = style->dash; + int num_dashes = style->num_dashes; + double dash_offset = style->dash_offset; + double line_width = style->line_width * scale; + + /* PostScript has "special needs" when it comes to zero-length + * dash segments with butt caps. It apparently (at least + * according to ghostscript) draws hairlines for this + * case. That's not what the cairo semantics want, so we first + * touch up the array to eliminate any 0.0 values that will + * result in "on" segments. + */ + if (num_dashes && style->line_cap == CAIRO_LINE_CAP_BUTT) { + int i; + + /* If there's an odd number of dash values they will each get + * interpreted as both on and off. So we first explicitly + * expand the array to remove the duplicate usage so that we + * can modify some of the values. + */ + if (num_dashes % 2) { + dash = _cairo_malloc_abc (num_dashes, 2, sizeof (double)); + if (unlikely (dash == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + memcpy (dash, style->dash, num_dashes * sizeof (double)); + memcpy (dash + num_dashes, style->dash, num_dashes * sizeof (double)); + + num_dashes *= 2; + } + + for (i = 0; i < num_dashes; i += 2) { + if (dash[i] == 0.0) { + /* Do not modify the dashes in-place, as we may need to also + * replay this stroke to an image fallback. + */ + if (dash == style->dash) { + dash = _cairo_malloc_ab (num_dashes, sizeof (double)); + if (unlikely (dash == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + memcpy (dash, style->dash, num_dashes * sizeof (double)); + } + + /* If we're at the front of the list, we first rotate + * two elements from the end of the list to the front + * of the list before folding away the 0.0. Or, if + * there are only two dash elements, then there is + * nothing at all to draw. + */ + if (i == 0) { + double last_two[2]; + + if (num_dashes == 2) { + free (dash); + return CAIRO_INT_STATUS_NOTHING_TO_DO; + } + + /* The cases of num_dashes == 0, 1, or 3 elements + * cannot exist, so the rotation of 2 elements + * will always be safe */ + memcpy (last_two, dash + num_dashes - 2, sizeof (last_two)); + memmove (dash + 2, dash, (num_dashes - 2) * sizeof (double)); + memcpy (dash, last_two, sizeof (last_two)); + dash_offset += dash[0] + dash[1]; + i = 2; + } + dash[i-1] += dash[i+1]; + num_dashes -= 2; + memmove (dash + i, dash + i + 2, (num_dashes - i) * sizeof (double)); + /* If we might have just rotated, it's possible that + * we rotated a 0.0 value to the front of the list. + * Set i to -2 so it will get incremented to 0. */ + if (i == 2) + i = -2; + } + } + } + + if (!pdf_operators->has_line_style || pdf_operators->line_width != line_width) { + _cairo_output_stream_printf (pdf_operators->stream, + "%f w\n", + line_width); + pdf_operators->line_width = line_width; + } + + if (!pdf_operators->has_line_style || pdf_operators->line_cap != style->line_cap) { + _cairo_output_stream_printf (pdf_operators->stream, + "%d J\n", + _cairo_pdf_line_cap (style->line_cap)); + pdf_operators->line_cap = style->line_cap; + } + + if (!pdf_operators->has_line_style || pdf_operators->line_join != style->line_join) { + _cairo_output_stream_printf (pdf_operators->stream, + "%d j\n", + _cairo_pdf_line_join (style->line_join)); + pdf_operators->line_join = style->line_join; + } + + if (num_dashes) { + int d; + + _cairo_output_stream_printf (pdf_operators->stream, "["); + for (d = 0; d < num_dashes; d++) + _cairo_output_stream_printf (pdf_operators->stream, " %f", dash[d] * scale); + _cairo_output_stream_printf (pdf_operators->stream, "] %f d\n", + dash_offset * scale); + pdf_operators->has_dashes = TRUE; + } else if (!pdf_operators->has_line_style || pdf_operators->has_dashes) { + _cairo_output_stream_printf (pdf_operators->stream, "[] 0.0 d\n"); + pdf_operators->has_dashes = FALSE; + } + if (dash != style->dash) + free (dash); + + if (!pdf_operators->has_line_style || pdf_operators->miter_limit != style->miter_limit) { + _cairo_output_stream_printf (pdf_operators->stream, + "%f M ", + style->miter_limit < 1.0 ? 1.0 : style->miter_limit); + pdf_operators->miter_limit = style->miter_limit; + } + pdf_operators->has_line_style = TRUE; + + return _cairo_output_stream_get_status (pdf_operators->stream); +} + +/* Scale the matrix so the largest absolute value of the non + * translation components is 1.0. Return the scale required to restore + * the matrix to the original values. + * + * eg the matrix [ 100 0 0 50 20 10 ] + * + * is rescaled to [ 1 0 0 0.5 0.2 0.1 ] + * and the scale returned is 100 + */ +static void +_cairo_matrix_factor_out_scale (cairo_matrix_t *m, double *scale) +{ + double s; + + s = fabs (m->xx); + if (fabs (m->xy) > s) + s = fabs (m->xy); + if (fabs (m->yx) > s) + s = fabs (m->yx); + if (fabs (m->yy) > s) + s = fabs (m->yy); + *scale = s; + s = 1.0/s; + cairo_matrix_scale (m, s, s); +} + +static cairo_int_status_t +_cairo_pdf_operators_emit_stroke (cairo_pdf_operators_t *pdf_operators, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + const char *pdf_operator) +{ + cairo_int_status_t status; + cairo_matrix_t m, path_transform; + cairo_bool_t has_ctm = TRUE; + double scale = 1.0; + + if (pdf_operators->in_text_object) { + status = _cairo_pdf_operators_end_text (pdf_operators); + if (unlikely (status)) + return status; + } + + /* Optimize away the stroke ctm when it does not affect the + * stroke. There are other ctm cases that could be optimized + * however this is the most common. + */ + if (fabs(ctm->xx) == 1.0 && fabs(ctm->yy) == 1.0 && + fabs(ctm->xy) == 0.0 && fabs(ctm->yx) == 0.0) + { + has_ctm = FALSE; + } + + /* The PDF CTM is transformed to the user space CTM when stroking + * so the correct pen shape will be used. This also requires that + * the path be transformed to user space when emitted. The + * conversion of path coordinates to user space may cause rounding + * errors. For example the device space point (1.234, 3.142) when + * transformed to a user space CTM of [100 0 0 100 0 0] will be + * emitted as (0.012, 0.031). + * + * To avoid the rounding problem we scale the user space CTM + * matrix so that all the non translation components of the matrix + * are <= 1. The line width and and dashes are scaled by the + * inverse of the scale applied to the CTM. This maintains the + * shape of the stroke pen while keeping the user space CTM within + * the range that maximizes the precision of the emitted path. + */ + if (has_ctm) { + m = *ctm; + /* Zero out the translation since it does not affect the pen + * shape however it may cause unnecessary digits to be emitted. + */ + m.x0 = 0.0; + m.y0 = 0.0; + _cairo_matrix_factor_out_scale (&m, &scale); + path_transform = m; + status = cairo_matrix_invert (&path_transform); + if (unlikely (status)) + return status; + + cairo_matrix_multiply (&m, &m, &pdf_operators->cairo_to_pdf); + } + + status = _cairo_pdf_operators_emit_stroke_style (pdf_operators, style, scale); + if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) + return CAIRO_STATUS_SUCCESS; + if (unlikely (status)) + return status; + + if (has_ctm) { + _cairo_output_stream_printf (pdf_operators->stream, "q "); + _cairo_output_stream_print_matrix (pdf_operators->stream, &m); + _cairo_output_stream_printf (pdf_operators->stream, " cm\n"); + } else { + path_transform = pdf_operators->cairo_to_pdf; + } + + status = _cairo_pdf_operators_emit_path (pdf_operators, + path, + &path_transform, + style->line_cap); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (pdf_operators->stream, "%s", pdf_operator); + if (has_ctm) + _cairo_output_stream_printf (pdf_operators->stream, " Q"); + + _cairo_output_stream_printf (pdf_operators->stream, "\n"); + + return _cairo_output_stream_get_status (pdf_operators->stream); +} + +cairo_int_status_t +_cairo_pdf_operators_stroke (cairo_pdf_operators_t *pdf_operators, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse) +{ + return _cairo_pdf_operators_emit_stroke (pdf_operators, + path, + style, + ctm, + ctm_inverse, + "S"); +} + +cairo_int_status_t +_cairo_pdf_operators_fill (cairo_pdf_operators_t *pdf_operators, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule) +{ + const char *pdf_operator; + cairo_status_t status; + + if (pdf_operators->in_text_object) { + status = _cairo_pdf_operators_end_text (pdf_operators); + if (unlikely (status)) + return status; + } + + status = _cairo_pdf_operators_emit_path (pdf_operators, + path, + &pdf_operators->cairo_to_pdf, + CAIRO_LINE_CAP_ROUND); + if (unlikely (status)) + return status; + + switch (fill_rule) { + default: + ASSERT_NOT_REACHED; + case CAIRO_FILL_RULE_WINDING: + pdf_operator = "f"; + break; + case CAIRO_FILL_RULE_EVEN_ODD: + pdf_operator = "f*"; + break; + } + + _cairo_output_stream_printf (pdf_operators->stream, + "%s\n", + pdf_operator); + + return _cairo_output_stream_get_status (pdf_operators->stream); +} + +cairo_int_status_t +_cairo_pdf_operators_fill_stroke (cairo_pdf_operators_t *pdf_operators, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse) +{ + const char *operator; + + switch (fill_rule) { + default: + ASSERT_NOT_REACHED; + case CAIRO_FILL_RULE_WINDING: + operator = "B"; + break; + case CAIRO_FILL_RULE_EVEN_ODD: + operator = "B*"; + break; + } + + return _cairo_pdf_operators_emit_stroke (pdf_operators, + path, + style, + ctm, + ctm_inverse, + operator); +} + +static void +_cairo_pdf_operators_emit_glyph_index (cairo_pdf_operators_t *pdf_operators, + cairo_output_stream_t *stream, + unsigned int glyph) +{ + if (pdf_operators->is_latin) { + if (glyph == '(' || glyph == ')' || glyph == '\\') + _cairo_output_stream_printf (stream, "\\%c", glyph); + else if (glyph >= 0x20 && glyph <= 0x7e) + _cairo_output_stream_printf (stream, "%c", glyph); + else + _cairo_output_stream_printf (stream, "\\%03o", glyph); + } else { + _cairo_output_stream_printf (stream, + "%0*x", + pdf_operators->hex_width, + glyph); + } +} + +#define GLYPH_POSITION_TOLERANCE 0.001 + +/* Emit the string of glyphs using the 'Tj' operator. This requires + * that the glyphs are positioned at their natural glyph advances. */ +static cairo_status_t +_cairo_pdf_operators_emit_glyph_string (cairo_pdf_operators_t *pdf_operators, + cairo_output_stream_t *stream) +{ + int i; + + _cairo_output_stream_printf (stream, "%s", pdf_operators->is_latin ? "(" : "<"); + for (i = 0; i < pdf_operators->num_glyphs; i++) { + _cairo_pdf_operators_emit_glyph_index (pdf_operators, + stream, + pdf_operators->glyphs[i].glyph_index); + pdf_operators->cur_x += pdf_operators->glyphs[i].x_advance; + } + _cairo_output_stream_printf (stream, "%sTj\n", pdf_operators->is_latin ? ")" : ">"); + + return _cairo_output_stream_get_status (stream); +} + +/* Emit the string of glyphs using the 'TJ' operator. + * + * The TJ operator takes an array of strings of glyphs. Each string of + * glyphs is displayed using the glyph advances of each glyph to + * position the glyphs. A relative adjustment to the glyph advance may + * be specified by including the adjustment between two strings. The + * adjustment is in units of text space * -1000. + */ +static cairo_status_t +_cairo_pdf_operators_emit_glyph_string_with_positioning ( + cairo_pdf_operators_t *pdf_operators, + cairo_output_stream_t *stream) +{ + int i; + + _cairo_output_stream_printf (stream, "[%s", pdf_operators->is_latin ? "(" : "<"); + for (i = 0; i < pdf_operators->num_glyphs; i++) { + if (pdf_operators->glyphs[i].x_position != pdf_operators->cur_x) + { + double delta = pdf_operators->glyphs[i].x_position - pdf_operators->cur_x; + int rounded_delta; + + delta = -1000.0*delta; + /* As the delta is in 1/1000 of a unit of text space, + * rounding to an integer should still provide sufficient + * precision. We round the delta before adding to Tm_x so + * that we keep track of the accumulated rounding error in + * the PDF interpreter and compensate for it when + * calculating subsequent deltas. + */ + rounded_delta = _cairo_lround (delta); + if (abs(rounded_delta) < 3) + rounded_delta = 0; + if (rounded_delta != 0) { + if (pdf_operators->is_latin) { + _cairo_output_stream_printf (stream, + ")%d(", + rounded_delta); + } else { + _cairo_output_stream_printf (stream, + ">%d<", + rounded_delta); + } + } + + /* Convert the rounded delta back to text + * space before adding to the current text + * position. */ + delta = rounded_delta/-1000.0; + pdf_operators->cur_x += delta; + } + + _cairo_pdf_operators_emit_glyph_index (pdf_operators, + stream, + pdf_operators->glyphs[i].glyph_index); + pdf_operators->cur_x += pdf_operators->glyphs[i].x_advance; + } + _cairo_output_stream_printf (stream, "%s]TJ\n", pdf_operators->is_latin ? ")" : ">"); + + return _cairo_output_stream_get_status (stream); +} + +static cairo_status_t +_cairo_pdf_operators_flush_glyphs (cairo_pdf_operators_t *pdf_operators) +{ + cairo_output_stream_t *word_wrap_stream; + cairo_status_t status, status2; + int i; + double x; + + if (pdf_operators->num_glyphs == 0) + return CAIRO_STATUS_SUCCESS; + + word_wrap_stream = _word_wrap_stream_create (pdf_operators->stream, pdf_operators->ps_output, 72); + status = _cairo_output_stream_get_status (word_wrap_stream); + if (unlikely (status)) + return _cairo_output_stream_destroy (word_wrap_stream); + + /* Check if glyph advance used to position every glyph */ + x = pdf_operators->cur_x; + for (i = 0; i < pdf_operators->num_glyphs; i++) { + if (fabs(pdf_operators->glyphs[i].x_position - x) > GLYPH_POSITION_TOLERANCE) + break; + x += pdf_operators->glyphs[i].x_advance; + } + if (i == pdf_operators->num_glyphs) { + status = _cairo_pdf_operators_emit_glyph_string (pdf_operators, + word_wrap_stream); + } else { + status = _cairo_pdf_operators_emit_glyph_string_with_positioning ( + pdf_operators, word_wrap_stream); + } + + pdf_operators->num_glyphs = 0; + pdf_operators->glyph_buf_x_pos = pdf_operators->cur_x; + status2 = _cairo_output_stream_destroy (word_wrap_stream); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; + + return status; +} + +static cairo_status_t +_cairo_pdf_operators_add_glyph (cairo_pdf_operators_t *pdf_operators, + cairo_scaled_font_subsets_glyph_t *glyph, + double x_position) +{ + double x, y; + + x = glyph->x_advance; + y = glyph->y_advance; + if (glyph->is_scaled) + cairo_matrix_transform_distance (&pdf_operators->font_matrix_inverse, &x, &y); + + pdf_operators->glyphs[pdf_operators->num_glyphs].x_position = x_position; + pdf_operators->glyphs[pdf_operators->num_glyphs].glyph_index = glyph->subset_glyph_index; + pdf_operators->glyphs[pdf_operators->num_glyphs].x_advance = x; + pdf_operators->glyph_buf_x_pos += x; + pdf_operators->num_glyphs++; + if (pdf_operators->num_glyphs == PDF_GLYPH_BUFFER_SIZE) + return _cairo_pdf_operators_flush_glyphs (pdf_operators); + + return CAIRO_STATUS_SUCCESS; +} + +/* Use 'Tm' operator to set the PDF text matrix. */ +static cairo_status_t +_cairo_pdf_operators_set_text_matrix (cairo_pdf_operators_t *pdf_operators, + cairo_matrix_t *matrix) +{ + cairo_matrix_t inverse; + cairo_status_t status; + + /* We require the matrix to be invertable. */ + inverse = *matrix; + status = cairo_matrix_invert (&inverse); + if (unlikely (status)) + return status; + + pdf_operators->text_matrix = *matrix; + pdf_operators->cur_x = 0; + pdf_operators->cur_y = 0; + pdf_operators->glyph_buf_x_pos = 0; + _cairo_output_stream_print_matrix (pdf_operators->stream, &pdf_operators->text_matrix); + _cairo_output_stream_printf (pdf_operators->stream, " Tm\n"); + + pdf_operators->cairo_to_pdftext = *matrix; + status = cairo_matrix_invert (&pdf_operators->cairo_to_pdftext); + assert (status == CAIRO_STATUS_SUCCESS); + cairo_matrix_multiply (&pdf_operators->cairo_to_pdftext, + &pdf_operators->cairo_to_pdf, + &pdf_operators->cairo_to_pdftext); + + return _cairo_output_stream_get_status (pdf_operators->stream); +} + +#define TEXT_MATRIX_TOLERANCE 1e-6 + +/* Set the translation components of the PDF text matrix to x, y. The + * 'Td' operator is used to transform the text matrix. + */ +static cairo_status_t +_cairo_pdf_operators_set_text_position (cairo_pdf_operators_t *pdf_operators, + double x, + double y) +{ + cairo_matrix_t translate, inverse; + cairo_status_t status; + + /* The Td operator transforms the text_matrix with: + * + * text_matrix' = T x text_matrix + * + * where T is a translation matrix with the translation components + * set to the Td operands tx and ty. + */ + inverse = pdf_operators->text_matrix; + status = cairo_matrix_invert (&inverse); + assert (status == CAIRO_STATUS_SUCCESS); + pdf_operators->text_matrix.x0 = x; + pdf_operators->text_matrix.y0 = y; + cairo_matrix_multiply (&translate, &pdf_operators->text_matrix, &inverse); + if (fabs(translate.x0) < TEXT_MATRIX_TOLERANCE) + translate.x0 = 0.0; + if (fabs(translate.y0) < TEXT_MATRIX_TOLERANCE) + translate.y0 = 0.0; + _cairo_output_stream_printf (pdf_operators->stream, + "%f %f Td\n", + translate.x0, + translate.y0); + pdf_operators->cur_x = 0; + pdf_operators->cur_y = 0; + pdf_operators->glyph_buf_x_pos = 0; + + pdf_operators->cairo_to_pdftext = pdf_operators->text_matrix; + status = cairo_matrix_invert (&pdf_operators->cairo_to_pdftext); + assert (status == CAIRO_STATUS_SUCCESS); + cairo_matrix_multiply (&pdf_operators->cairo_to_pdftext, + &pdf_operators->cairo_to_pdf, + &pdf_operators->cairo_to_pdftext); + + return _cairo_output_stream_get_status (pdf_operators->stream); +} + +/* Select the font using the 'Tf' operator. The font size is set to 1 + * as we use the 'Tm' operator to set the font scale. + */ +static cairo_status_t +_cairo_pdf_operators_set_font_subset (cairo_pdf_operators_t *pdf_operators, + cairo_scaled_font_subsets_glyph_t *subset_glyph) +{ + cairo_status_t status; + + _cairo_output_stream_printf (pdf_operators->stream, + "/f-%d-%d 1 Tf\n", + subset_glyph->font_id, + subset_glyph->subset_id); + if (pdf_operators->use_font_subset) { + status = pdf_operators->use_font_subset (subset_glyph->font_id, + subset_glyph->subset_id, + pdf_operators->use_font_subset_closure); + if (unlikely (status)) + return status; + } + pdf_operators->font_id = subset_glyph->font_id; + pdf_operators->subset_id = subset_glyph->subset_id; + pdf_operators->is_latin = subset_glyph->is_latin; + + if (subset_glyph->is_composite) + pdf_operators->hex_width = 4; + else + pdf_operators->hex_width = 2; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_pdf_operators_begin_text (cairo_pdf_operators_t *pdf_operators) +{ + _cairo_output_stream_printf (pdf_operators->stream, "BT\n"); + + pdf_operators->in_text_object = TRUE; + pdf_operators->num_glyphs = 0; + pdf_operators->glyph_buf_x_pos = 0; + + return _cairo_output_stream_get_status (pdf_operators->stream); +} + +static cairo_status_t +_cairo_pdf_operators_end_text (cairo_pdf_operators_t *pdf_operators) +{ + cairo_status_t status; + + status = _cairo_pdf_operators_flush_glyphs (pdf_operators); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (pdf_operators->stream, "ET\n"); + + pdf_operators->in_text_object = FALSE; + + return _cairo_output_stream_get_status (pdf_operators->stream); +} + +/* Compare the scale components of two matrices. The translation + * components are ignored. */ +static cairo_bool_t +_cairo_matrix_scale_equal (cairo_matrix_t *a, cairo_matrix_t *b) +{ + return (a->xx == b->xx && + a->xy == b->xy && + a->yx == b->yx && + a->yy == b->yy); +} + +static cairo_status_t +_cairo_pdf_operators_begin_actualtext (cairo_pdf_operators_t *pdf_operators, + const char *utf8, + int utf8_len) +{ + uint16_t *utf16; + int utf16_len; + cairo_status_t status; + int i; + + _cairo_output_stream_printf (pdf_operators->stream, "/Span << /ActualText stream, + "%04x", (int) (utf16[i])); + } + free (utf16); + } + _cairo_output_stream_printf (pdf_operators->stream, "> >> BDC\n"); + + return _cairo_output_stream_get_status (pdf_operators->stream); +} + +static cairo_status_t +_cairo_pdf_operators_end_actualtext (cairo_pdf_operators_t *pdf_operators) +{ + _cairo_output_stream_printf (pdf_operators->stream, "EMC\n"); + + return _cairo_output_stream_get_status (pdf_operators->stream); +} + +static cairo_status_t +_cairo_pdf_operators_emit_glyph (cairo_pdf_operators_t *pdf_operators, + cairo_glyph_t *glyph, + cairo_scaled_font_subsets_glyph_t *subset_glyph) +{ + double x, y; + cairo_status_t status; + + if (pdf_operators->is_new_text_object || + pdf_operators->font_id != subset_glyph->font_id || + pdf_operators->subset_id != subset_glyph->subset_id) + { + status = _cairo_pdf_operators_flush_glyphs (pdf_operators); + if (unlikely (status)) + return status; + + status = _cairo_pdf_operators_set_font_subset (pdf_operators, subset_glyph); + if (unlikely (status)) + return status; + + pdf_operators->is_new_text_object = FALSE; + } + + x = glyph->x; + y = glyph->y; + cairo_matrix_transform_point (&pdf_operators->cairo_to_pdftext, &x, &y); + + /* The TJ operator for displaying text strings can only set + * the horizontal position of the glyphs. If the y position + * (in text space) changes, use the Td operator to change the + * current position to the next glyph. We also use the Td + * operator to move the current position if the horizontal + * position changes by more than 10 (in text space + * units). This is because the horizontal glyph positioning + * in the TJ operator is intended for kerning and there may be + * PDF consumers that do not handle very large position + * adjustments in TJ. + */ + if (fabs(x - pdf_operators->glyph_buf_x_pos) > 10 || + fabs(y - pdf_operators->cur_y) > GLYPH_POSITION_TOLERANCE) + { + status = _cairo_pdf_operators_flush_glyphs (pdf_operators); + if (unlikely (status)) + return status; + + x = glyph->x; + y = glyph->y; + cairo_matrix_transform_point (&pdf_operators->cairo_to_pdf, &x, &y); + status = _cairo_pdf_operators_set_text_position (pdf_operators, x, y); + if (unlikely (status)) + return status; + + x = 0.0; + y = 0.0; + } + + status = _cairo_pdf_operators_add_glyph (pdf_operators, + subset_glyph, + x); + return status; +} + +/* A utf8_len of -1 indicates no unicode text. A utf8_len = 0 is an + * empty string. + */ +static cairo_int_status_t +_cairo_pdf_operators_emit_cluster (cairo_pdf_operators_t *pdf_operators, + const char *utf8, + int utf8_len, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_text_cluster_flags_t cluster_flags, + cairo_scaled_font_t *scaled_font) +{ + cairo_scaled_font_subsets_glyph_t subset_glyph; + cairo_glyph_t *cur_glyph; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + int i; + + /* If the cluster maps 1 glyph to 1 or more unicode characters, we + * first try _map_glyph() with the unicode string to see if it can + * use toUnicode to map our glyph to the unicode. This will fail + * if the glyph is already mapped to a different unicode string. + * + * We also go through this path if no unicode mapping was + * supplied (utf8_len < 0). + * + * Mapping a glyph to a zero length unicode string requires the + * use of ActualText. + */ + if (num_glyphs == 1 && utf8_len != 0) { + status = _cairo_scaled_font_subsets_map_glyph (pdf_operators->font_subsets, + scaled_font, + glyphs->index, + utf8, + utf8_len, + &subset_glyph); + if (unlikely (status)) + return status; + + if (subset_glyph.utf8_is_mapped || utf8_len < 0) { + status = _cairo_pdf_operators_emit_glyph (pdf_operators, + glyphs, + &subset_glyph); + if (unlikely (status)) + return status; + + return CAIRO_STATUS_SUCCESS; + } + } + + if (pdf_operators->use_actual_text) { + /* Fallback to using ActualText to map zero or more glyphs to a + * unicode string. */ + status = _cairo_pdf_operators_flush_glyphs (pdf_operators); + if (unlikely (status)) + return status; + + status = _cairo_pdf_operators_begin_actualtext (pdf_operators, utf8, utf8_len); + if (unlikely (status)) + return status; + } + + if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD) + cur_glyph = glyphs + num_glyphs - 1; + else + cur_glyph = glyphs; + + /* XXX + * If no glyphs, we should put *something* here for the text to be selectable. */ + for (i = 0; i < num_glyphs; i++) { + status = _cairo_scaled_font_subsets_map_glyph (pdf_operators->font_subsets, + scaled_font, + cur_glyph->index, + NULL, -1, + &subset_glyph); + if (unlikely (status)) + return status; + + status = _cairo_pdf_operators_emit_glyph (pdf_operators, + cur_glyph, + &subset_glyph); + if (unlikely (status)) + return status; + + if ((cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)) + cur_glyph--; + else + cur_glyph++; + } + + if (pdf_operators->use_actual_text) { + status = _cairo_pdf_operators_flush_glyphs (pdf_operators); + if (unlikely (status)) + return status; + + status = _cairo_pdf_operators_end_actualtext (pdf_operators); + } + + return status; +} + +cairo_int_status_t +_cairo_pdf_operators_show_text_glyphs (cairo_pdf_operators_t *pdf_operators, + const char *utf8, + int utf8_len, + cairo_glyph_t *glyphs, + int num_glyphs, + const cairo_text_cluster_t *clusters, + int num_clusters, + cairo_text_cluster_flags_t cluster_flags, + cairo_scaled_font_t *scaled_font) +{ + cairo_status_t status; + int i; + cairo_matrix_t text_matrix, invert_y_axis; + double x, y; + const char *cur_text; + cairo_glyph_t *cur_glyph; + + pdf_operators->font_matrix_inverse = scaled_font->font_matrix; + status = cairo_matrix_invert (&pdf_operators->font_matrix_inverse); + if (status == CAIRO_STATUS_INVALID_MATRIX) + return CAIRO_STATUS_SUCCESS; + assert (status == CAIRO_STATUS_SUCCESS); + + pdf_operators->is_new_text_object = FALSE; + if (pdf_operators->in_text_object == FALSE) { + status = _cairo_pdf_operators_begin_text (pdf_operators); + if (unlikely (status)) + return status; + + /* Force Tm and Tf to be emitted when starting a new text + * object.*/ + pdf_operators->is_new_text_object = TRUE; + } + + cairo_matrix_init_scale (&invert_y_axis, 1, -1); + text_matrix = scaled_font->scale; + + /* Invert y axis in device space */ + cairo_matrix_multiply (&text_matrix, &invert_y_axis, &text_matrix); + + if (pdf_operators->is_new_text_object || + ! _cairo_matrix_scale_equal (&pdf_operators->text_matrix, &text_matrix)) + { + status = _cairo_pdf_operators_flush_glyphs (pdf_operators); + if (unlikely (status)) + return status; + + x = glyphs[0].x; + y = glyphs[0].y; + cairo_matrix_transform_point (&pdf_operators->cairo_to_pdf, &x, &y); + text_matrix.x0 = x; + text_matrix.y0 = y; + status = _cairo_pdf_operators_set_text_matrix (pdf_operators, &text_matrix); + if (status == CAIRO_STATUS_INVALID_MATRIX) + return CAIRO_STATUS_SUCCESS; + if (unlikely (status)) + return status; + } + + if (num_clusters > 0) { + cur_text = utf8; + if ((cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)) + cur_glyph = glyphs + num_glyphs; + else + cur_glyph = glyphs; + for (i = 0; i < num_clusters; i++) { + if ((cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)) + cur_glyph -= clusters[i].num_glyphs; + status = _cairo_pdf_operators_emit_cluster (pdf_operators, + cur_text, + clusters[i].num_bytes, + cur_glyph, + clusters[i].num_glyphs, + cluster_flags, + scaled_font); + if (unlikely (status)) + return status; + + cur_text += clusters[i].num_bytes; + if (!(cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD)) + cur_glyph += clusters[i].num_glyphs; + } + } else { + for (i = 0; i < num_glyphs; i++) { + status = _cairo_pdf_operators_emit_cluster (pdf_operators, + NULL, + -1, /* no unicode string available */ + &glyphs[i], + 1, + FALSE, + scaled_font); + if (unlikely (status)) + return status; + } + } + + return _cairo_output_stream_get_status (pdf_operators->stream); +} + +cairo_int_status_t +_cairo_pdf_operators_tag_begin (cairo_pdf_operators_t *pdf_operators, + const char *tag_name, + int mcid) +{ + cairo_status_t status; + + if (pdf_operators->in_text_object) { + status = _cairo_pdf_operators_end_text (pdf_operators); + if (unlikely (status)) + return status; + } + + if (mcid >= 0) { + _cairo_output_stream_printf (pdf_operators->stream, + "/%s << /MCID %d >> BDC\n", + tag_name, + mcid); + } else { + _cairo_output_stream_printf (pdf_operators->stream, + "/%s BMC\n", + tag_name); + } + + return _cairo_output_stream_get_status (pdf_operators->stream); +} + +cairo_int_status_t +_cairo_pdf_operators_tag_end (cairo_pdf_operators_t *pdf_operators) +{ + cairo_status_t status; + + if (pdf_operators->in_text_object) { + status = _cairo_pdf_operators_end_text (pdf_operators); + if (unlikely (status)) + return status; + } + + _cairo_output_stream_printf (pdf_operators->stream, "EMC\n"); + + return _cairo_output_stream_get_status (pdf_operators->stream); +} + +#endif /* CAIRO_HAS_PDF_OPERATORS */ diff --git a/local/recipes/libs/cairo/source/src/cairo-pdf-shading-private.h b/local/recipes/libs/cairo/source/src/cairo-pdf-shading-private.h new file mode 100644 index 0000000000..0ca8cb7d51 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-pdf-shading-private.h @@ -0,0 +1,100 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Adrian Johnson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Adrian Johnson. + * + * Contributor(s): + * Adrian Johnson + */ + +#ifndef CAIRO_PDF_SHADING_H +#define CAIRO_PDF_SHADING_H + +#include "cairo-compiler-private.h" +#include "cairo-types-private.h" +#include "cairo-pattern-private.h" + + +typedef struct _cairo_pdf_shading { + int shading_type; + int bits_per_coordinate; + int bits_per_component; + int bits_per_flag; + double *decode_array; + int decode_array_length; + unsigned char *data; + unsigned long data_length; +} cairo_pdf_shading_t; + + +/** + * _cairo_pdf_shading_init_color: + * @shading: a #cairo_pdf_shading_t to initialize + * @pattern: the #cairo_mesh_pattern_t to initialize from + * + * Generate the PDF shading dictionary data for the a PDF type 7 + * shading from RGB part of the specified mesh pattern. + * + * Return value: %CAIRO_STATUS_SUCCESS if successful, possible errors + * include %CAIRO_STATUS_NO_MEMORY. + **/ +cairo_private cairo_status_t +_cairo_pdf_shading_init_color (cairo_pdf_shading_t *shading, + const cairo_mesh_pattern_t *pattern); + + +/** + * _cairo_pdf_shading_init_alpha: + * @shading: a #cairo_pdf_shading_t to initialize + * @pattern: the #cairo_mesh_pattern_t to initialize from + * + * Generate the PDF shading dictionary data for a PDF type 7 + * shading from alpha part of the specified mesh pattern. + * + * Return value: %CAIRO_STATUS_SUCCESS if successful, possible errors + * include %CAIRO_STATUS_NO_MEMORY. + **/ +cairo_private cairo_status_t +_cairo_pdf_shading_init_alpha (cairo_pdf_shading_t *shading, + const cairo_mesh_pattern_t *pattern); + +/** + * _cairo_pdf_shading_fini: + * @shading: a #cairo_pdf_shading_t + * + * Free all resources associated with @shading. After this call, + * @shading should not be used again without a subsequent call to + * _cairo_pdf_shading_init() again first. + **/ +cairo_private void +_cairo_pdf_shading_fini (cairo_pdf_shading_t *shading); + + +#endif /* CAIRO_PDF_SHADING_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-pdf-shading.c b/local/recipes/libs/cairo/source/src/cairo-pdf-shading.c new file mode 100644 index 0000000000..b114b3104b --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-pdf-shading.c @@ -0,0 +1,279 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Adrian Johnson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Adrian Johnson. + * + * Contributor(s): + * Adrian Johnson + */ + +#include "cairoint.h" + +#if CAIRO_HAS_PDF_OPERATORS + +#include "cairo-pdf-shading-private.h" + +#include "cairo-array-private.h" +#include "cairo-error-private.h" +#include + +static unsigned char * +encode_coordinate (unsigned char *p, double c) +{ + uint32_t f; + + f = c; + *p++ = f >> 24; + *p++ = (f >> 16) & 0xff; + *p++ = (f >> 8) & 0xff; + *p++ = f & 0xff; + + return p; +} + +static unsigned char * +encode_point (unsigned char *p, const cairo_point_double_t *point) +{ + p = encode_coordinate (p, point->x); + p = encode_coordinate (p, point->y); + + return p; +} + +static unsigned char * +encode_color_component (unsigned char *p, double color) +{ + uint16_t c; + + c = _cairo_color_double_to_short (color); + *p++ = c >> 8; + *p++ = c & 0xff; + + return p; +} + +static unsigned char * +encode_color (unsigned char *p, const cairo_color_t *color) +{ + p = encode_color_component (p, color->red); + p = encode_color_component (p, color->green); + p = encode_color_component (p, color->blue); + + return p; +} + +static unsigned char * +encode_alpha (unsigned char *p, const cairo_color_t *color) +{ + p = encode_color_component (p, color->alpha); + + return p; +} + +static cairo_status_t +_cairo_pdf_shading_generate_decode_array (cairo_pdf_shading_t *shading, + const cairo_mesh_pattern_t *mesh, + cairo_bool_t is_alpha) +{ + unsigned int num_color_components, i; + cairo_bool_t is_valid; + + if (is_alpha) + num_color_components = 1; + else + num_color_components = 3; + + shading->decode_array_length = 4 + num_color_components * 2; + shading->decode_array = _cairo_malloc_ab (shading->decode_array_length, + sizeof (double)); + if (unlikely (shading->decode_array == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + is_valid = _cairo_mesh_pattern_coord_box (mesh, + &shading->decode_array[0], + &shading->decode_array[2], + &shading->decode_array[1], + &shading->decode_array[3]); + + assert (is_valid); + assert (shading->decode_array[1] - shading->decode_array[0] >= DBL_EPSILON); + assert (shading->decode_array[3] - shading->decode_array[2] >= DBL_EPSILON); + + for (i = 0; i < num_color_components; i++) { + shading->decode_array[4 + 2*i] = 0; + shading->decode_array[5 + 2*i] = 1; + } + + return CAIRO_STATUS_SUCCESS; +} + +/* The ISO32000 specification mandates this order for the points which + * define the patch. */ +static const int pdf_points_order_i[16] = { + 0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 2, 1, 1, 1, 2, 2 }; +static const int pdf_points_order_j[16] = { + 0, 1, 2, 3, 3, 3, 3, 2, 1, 0, 0, 0, 1, 2, 2, 1 }; + +static cairo_status_t +_cairo_pdf_shading_generate_data (cairo_pdf_shading_t *shading, + const cairo_mesh_pattern_t *mesh, + cairo_bool_t is_alpha) +{ + const cairo_mesh_patch_t *patch; + double x_off, y_off, x_scale, y_scale; + unsigned int num_patches; + unsigned int num_color_components; + unsigned char *p; + unsigned int i, j; + + if (is_alpha) + num_color_components = 1; + else + num_color_components = 3; + + num_patches = _cairo_array_num_elements (&mesh->patches); + patch = _cairo_array_index_const (&mesh->patches, 0); + + /* Each patch requires: + * + * 1 flag - 1 byte + * 16 points. Each point is 2 coordinates. Each coordinate is + * stored in 4 bytes. + * + * 4 colors. Each color is stored in 2 bytes * num_color_components. + */ + shading->data_length = num_patches * (1 + 16 * 2 * 4 + 4 * 2 * num_color_components); + shading->data = _cairo_malloc (shading->data_length); + if (unlikely (shading->data == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + x_off = shading->decode_array[0]; + y_off = shading->decode_array[2]; + x_scale = UINT32_MAX / (shading->decode_array[1] - x_off); + y_scale = UINT32_MAX / (shading->decode_array[3] - y_off); + + p = shading->data; + for (i = 0; i < num_patches; i++) { + /* edge flag */ + *p++ = 0; + + /* 16 points */ + for (j = 0; j < 16; j++) { + cairo_point_double_t point; + int pi, pj; + + pi = pdf_points_order_i[j]; + pj = pdf_points_order_j[j]; + point = patch[i].points[pi][pj]; + + /* Transform the point as specified in the decode array */ + point.x -= x_off; + point.y -= y_off; + point.x *= x_scale; + point.y *= y_scale; + + /* Make sure that rounding errors don't cause + * wraparounds */ + point.x = _cairo_restrict_value (point.x, 0, UINT32_MAX); + point.y = _cairo_restrict_value (point.y, 0, UINT32_MAX); + + p = encode_point (p, &point); + } + + /* 4 colors */ + for (j = 0; j < 4; j++) { + if (is_alpha) + p = encode_alpha (p, &patch[i].colors[j]); + else + p = encode_color (p, &patch[i].colors[j]); + } + } + + assert (p == shading->data + shading->data_length); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_pdf_shading_init (cairo_pdf_shading_t *shading, + const cairo_mesh_pattern_t *mesh, + cairo_bool_t is_alpha) +{ + cairo_status_t status; + + assert (mesh->base.status == CAIRO_STATUS_SUCCESS); + assert (mesh->current_patch == NULL); + + shading->shading_type = 7; + + /* + * Coordinates from the minimum to the maximum value of the mesh + * map to the [0..UINT32_MAX] range and are represented as + * uint32_t values. + * + * Color components are represented as uint16_t (in a 0.16 fixed + * point format, as in the rest of cairo). + */ + shading->bits_per_coordinate = 32; + shading->bits_per_component = 16; + shading->bits_per_flag = 8; + + shading->decode_array = NULL; + shading->data = NULL; + + status = _cairo_pdf_shading_generate_decode_array (shading, mesh, is_alpha); + if (unlikely (status)) + return status; + + return _cairo_pdf_shading_generate_data (shading, mesh, is_alpha); +} + +cairo_status_t +_cairo_pdf_shading_init_color (cairo_pdf_shading_t *shading, + const cairo_mesh_pattern_t *pattern) +{ + return _cairo_pdf_shading_init (shading, pattern, FALSE); +} + +cairo_status_t +_cairo_pdf_shading_init_alpha (cairo_pdf_shading_t *shading, + const cairo_mesh_pattern_t *pattern) +{ + return _cairo_pdf_shading_init (shading, pattern, TRUE); +} + +void +_cairo_pdf_shading_fini (cairo_pdf_shading_t *shading) +{ + free (shading->data); + free (shading->decode_array); +} + +#endif /* CAIRO_HAS_PDF_OPERATORS */ diff --git a/local/recipes/libs/cairo/source/src/cairo-pdf-surface-private.h b/local/recipes/libs/cairo/source/src/cairo-pdf-surface-private.h new file mode 100644 index 0000000000..bf1d39456c --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-pdf-surface-private.h @@ -0,0 +1,587 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2004 Red Hat, Inc + * Copyright © 2006 Red Hat, Inc + * Copyright © 2007, 2008 Adrian Johnson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Kristian Høgsberg + * Carl Worth + * Adrian Johnson + */ + +#ifndef CAIRO_PDF_SURFACE_PRIVATE_H +#define CAIRO_PDF_SURFACE_PRIVATE_H + +#include "cairo-pdf.h" + +#include "cairo-surface-private.h" +#include "cairo-surface-clipper-private.h" +#include "cairo-pdf-operators-private.h" +#include "cairo-path-fixed-private.h" +#include "cairo-tag-attributes-private.h" +#include "cairo-tag-stack-private.h" + +typedef struct _cairo_pdf_resource { + unsigned int id; +} cairo_pdf_resource_t; + + +#define CAIRO_NUM_OPERATORS (CAIRO_OPERATOR_HSL_LUMINOSITY + 1) + +typedef struct _cairo_pdf_group_resources { + cairo_bool_t operators[CAIRO_NUM_OPERATORS]; + cairo_array_t alphas; + cairo_array_t smasks; + cairo_array_t patterns; + cairo_array_t shadings; + cairo_array_t xobjects; + cairo_array_t fonts; +} cairo_pdf_group_resources_t; + +typedef struct _cairo_pdf_source_surface_entry { + cairo_hash_entry_t base; + unsigned int id; + unsigned char *unique_id; + unsigned long unique_id_length; + cairo_operator_t operator; + + /* If not 0, this is the recording surface region id of the source surface. */ + int region_id; + + cairo_bool_t interpolate; + cairo_bool_t stencil_mask; + cairo_bool_t smask; + cairo_bool_t need_transp_group; + cairo_pdf_resource_t surface_res; + cairo_pdf_resource_t smask_res; + + /* True if surface will be emitted as an Image XObject. */ + cairo_bool_t emit_image; + + /* Extents of the source surface. */ + cairo_bool_t bounded; + cairo_rectangle_int_t extents; + + /* Union of source extents required for all operations using this source */ + cairo_rectangle_int_t required_extents; +} cairo_pdf_source_surface_entry_t; + +typedef struct _cairo_pdf_source_surface { + cairo_pattern_type_t type; + cairo_surface_t *surface; + unsigned int region_id; + cairo_pattern_t *raster_pattern; + cairo_pdf_source_surface_entry_t *hash_entry; +} cairo_pdf_source_surface_t; + +typedef struct _cairo_pdf_pattern { + double width; + double height; + cairo_rectangle_int_t extents; + cairo_pattern_t *pattern; + cairo_pdf_resource_t pattern_res; + cairo_pdf_resource_t gstate_res; + cairo_operator_t operator; + cairo_bool_t is_shading; + + /* Index into nodes array in cairo_pdf_surface_node_entry_t or -1 if not used */ + int region_id; + + /* PDF pattern space is the pattern matrix concatenated with the + * initial space of the parent object. If the parent object is the + * page, the initial space does not include the Y-axis flipping + * matrix emitted at the start of the page content stream. If the + * parent object is not the page content stream, the initial space + * will have a flipped Y-axis. The inverted_y_axis flag is true + * when the initial space of the parent object that is drawing + * this pattern has a flipped Y-axis. + */ + cairo_bool_t inverted_y_axis; +} cairo_pdf_pattern_t; + +typedef enum _cairo_pdf_operation { + PDF_PAINT, + PDF_MASK, + PDF_FILL, + PDF_STROKE, + PDF_SHOW_GLYPHS +} cairo_pdf_operation_t; + +typedef struct _cairo_pdf_smask_group { + double width; + double height; + cairo_rectangle_int_t extents; + cairo_pdf_resource_t group_res; + cairo_pdf_operation_t operation; + cairo_pattern_t *source; + cairo_pdf_resource_t source_res; + cairo_pattern_t *mask; + cairo_path_fixed_t path; + cairo_fill_rule_t fill_rule; + cairo_stroke_style_t style; + cairo_matrix_t ctm; + cairo_matrix_t ctm_inverse; + char *utf8; + int utf8_len; + cairo_glyph_t *glyphs; + int num_glyphs; + cairo_text_cluster_t *clusters; + int num_clusters; + cairo_bool_t cluster_flags; + cairo_scaled_font_t *scaled_font; +} cairo_pdf_smask_group_t; + +typedef struct _cairo_pdf_jbig2_global { + unsigned char *id; + unsigned long id_length; + cairo_pdf_resource_t res; + cairo_bool_t emitted; +} cairo_pdf_jbig2_global_t; + +typedef struct _cairo_pdf_page_info { + double width; + double height; + cairo_pdf_resource_t page_res; + cairo_pdf_resource_t content; + cairo_pdf_resource_t resources; + cairo_pdf_resource_t thumbnail; + cairo_array_t annots; /* */ + int struct_parents; +} cairo_pdf_page_info_t; + + +/* cairo-pdf-interchange.c types */ + +typedef struct _pdf_tag_extents { + cairo_rectangle_int_t extents; + cairo_bool_t valid; +} cairo_pdf_tag_extents_t; + +typedef struct _pdf_page_mcid { + int order; + int page; + cairo_pdf_resource_t xobject_res; /* 0 if not in an XObject */ + int mcid; + struct _cairo_pdf_struct_tree_node *child_node; +} cairo_pdf_page_mcid_t; + +/* The non PDF_NODE_STRUCT types are excluded from the struct tree embedded in + * the PDF. */ +typedef enum _cairo_pdf_tree_node_type { + PDF_NODE_STRUCT, + PDF_NODE_CONTENT, + PDF_NODE_CONTENT_REF, + PDF_NODE_ARTIFACT, +} cairo_pdf_tree_node_type_t; + +typedef struct _cairo_pdf_struct_tree_node { + cairo_hash_entry_t hash; + cairo_pdf_tree_node_type_t type; + char *name; + cairo_pdf_resource_t res; + struct _cairo_pdf_struct_tree_node *parent; + cairo_list_t children; + cairo_array_t mcid; /* array of cairo_pdf_page_mcid_t */ + struct _cairo_pdf_annotation *annot; + cairo_pdf_tag_extents_t extents; + + union { + cairo_content_attrs_t content; /* type == PDF_NODE_CONTENT */ + cairo_content_ref_attrs_t content_ref; /* type == PDF_NODE_CONTENT_REF */ + } attributes; + + cairo_list_t link; /* linked list of parent's children */ +} cairo_pdf_struct_tree_node_t; + +typedef struct _cairo_pdf_command_entry { + cairo_hash_entry_t base; + unsigned int recording_id; + unsigned int command_id; + cairo_pdf_struct_tree_node_t *node; +} cairo_pdf_command_entry_t; + +typedef struct _cairo_recording_surface_stack_entry { + cairo_bool_t ignore_surface; + cairo_pdf_struct_tree_node_t *current_node; +} cairo_recording_surface_stack_entry_t; + +typedef struct _cairo_pdf_content_tag { + cairo_hash_entry_t base; + cairo_pdf_struct_tree_node_t *node; +} cairo_pdf_content_tag_t; + +typedef struct _cairo_pdf_annotation { + cairo_pdf_struct_tree_node_t *node; /* node containing the annotation */ + cairo_link_attrs_t link_attrs; + cairo_pdf_resource_t res; +} cairo_pdf_annotation_t; + +typedef struct _cairo_pdf_named_dest { + cairo_hash_entry_t base; + cairo_pdf_tag_extents_t extents; + cairo_dest_attrs_t attrs; + int page; +} cairo_pdf_named_dest_t; + +typedef struct _cairo_pdf_outline_entry { + char *name; + cairo_link_attrs_t link_attrs; + cairo_pdf_outline_flags_t flags; + cairo_pdf_resource_t res; + struct _cairo_pdf_outline_entry *parent; + struct _cairo_pdf_outline_entry *first_child; + struct _cairo_pdf_outline_entry *last_child; + struct _cairo_pdf_outline_entry *next; + struct _cairo_pdf_outline_entry *prev; + int count; +} cairo_pdf_outline_entry_t; + +struct docinfo { + char *title; + char *author; + char *subject; + char *keywords; + char *creator; + char *create_date; + char *mod_date; +}; + +struct metadata { + char *name; + char *value; +}; + +typedef enum _cairo_pdf_operation_flags_t { + PDF_NONE = 0, + PDF_CONTENT, + PDF_BEGIN, + PDF_END, + PDF_GROUP, +} cairo_pdf_operation_flags_t; + +typedef struct _pdf_command_list { + cairo_array_t commands; + struct _pdf_command_list *parent; +} cairo_pdf_command_list_t; + +typedef struct _pdf_operation { + cairo_pdf_command_list_t *group; + cairo_pdf_struct_tree_node_t *node; + unsigned int command_id; + int mcid_index; + cairo_pdf_operation_flags_t flags; +} cairo_pdf_command_t; + +typedef struct _pdf_recording_surface_commands { + cairo_surface_t *recording_surface; + cairo_pdf_command_list_t *command_list; + unsigned int region_id; +} cairo_pdf_recording_surface_commands_t; + +typedef struct _cairo_pdf_interchange { + cairo_tag_stack_t analysis_tag_stack; + cairo_tag_stack_t render_tag_stack; + cairo_pdf_struct_tree_node_t *struct_root; + + /* Current position in the tree during the analysis stage and across + * pages as each page adds to the tree */ + cairo_pdf_struct_tree_node_t *current_analyze_node; + + /* Currently open tag content containing content. NULL if no content tag open. + * A content containg tag may be open across pages */ + cairo_pdf_struct_tree_node_t *current_render_node; + cairo_pdf_struct_tree_node_t *next_page_render_node; + + cairo_array_t recording_surface_stack; /* cairo_recording_surface_stack_entry_t */ + cairo_pdf_resource_t current_recording_surface_res; + cairo_hash_table_t *command_to_node_map; /* */ + cairo_bool_t ignore_current_surface; + cairo_hash_table_t *content_tag_map; /* */ + + cairo_array_t parent_tree; /* */ + cairo_array_t annots; /* array of pointers to cairo_pdf_annotation_t */ + cairo_pdf_resource_t content_parent_res; + cairo_pdf_resource_t parent_tree_res; + + /* mcid to tree node for current page or group */ + cairo_array_t mcid_to_tree; /* */ + + cairo_array_t page_commands; /* */ + cairo_pdf_command_list_t *current_commands; /* */ + cairo_array_t recording_surface_commands; /* */ + + cairo_list_t extents_list; + cairo_hash_table_t *named_dests; + int num_dests; + cairo_pdf_named_dest_t **sorted_dests; + cairo_pdf_resource_t dests_res; + int annot_page; + cairo_array_t outline; /* array of pointers to cairo_pdf_outline_entry_t; */ + struct docinfo docinfo; + cairo_array_t custom_metadata; /* array of struct metadata */ + cairo_bool_t content_emitted; + cairo_bool_t marked_content_open; + unsigned int recording_id; + unsigned int command_id; + cairo_bool_t render_next_command_has_content; + int mcid_order; + +} cairo_pdf_interchange_t; + +typedef struct _cairo_pdf_color_glyph { + cairo_hash_entry_t base; + cairo_scaled_font_t *scaled_font; + unsigned long glyph_index; + cairo_bool_t supported; +} cairo_pdf_color_glyph_t; + +/* pdf surface data */ + +typedef struct _cairo_pdf_surface cairo_pdf_surface_t; + +struct _cairo_pdf_surface { + cairo_surface_t base; + + /* Prefer the name "output" here to avoid confusion over the + * structure within a PDF document known as a "stream". */ + cairo_output_stream_t *output; + + double width; + double height; + cairo_rectangle_int_t surface_extents; + cairo_bool_t surface_bounded; + cairo_matrix_t cairo_to_pdf; + cairo_bool_t in_xobject; + + cairo_array_t objects; /* cairo_pdf_resource_t - list of every resource in the PDF */ + cairo_array_t pages; /* */ + cairo_array_t rgb_linear_functions; + cairo_array_t alpha_linear_functions; + cairo_array_t page_patterns; /* cairo_pdf_pattern_t */ + cairo_array_t page_surfaces; /* cairo_pdf_source_surface_t */ + cairo_array_t doc_surfaces; /* cairo_pdf_source_surface_t */ + cairo_hash_table_t *all_surfaces; /* cairo_pdf_source_surface_entry_t* */ + int duplicate_surface_number; + cairo_array_t smask_groups; + cairo_array_t knockout_group; + cairo_array_t jbig2_global; + cairo_hash_table_t *color_glyphs; + + cairo_scaled_font_subsets_t *font_subsets; + cairo_array_t fonts; + + cairo_pdf_resource_t next_available_resource; + cairo_pdf_resource_t pages_resource; + cairo_pdf_resource_t struct_tree_root; + + cairo_pdf_version_t pdf_version; + cairo_bool_t compress_streams; + + cairo_pdf_resource_t content; + cairo_pdf_resource_t content_resources; + cairo_pdf_group_resources_t resources; + cairo_bool_t has_fallback_images; + cairo_bool_t header_emitted; + + struct { + cairo_bool_t active; + cairo_pdf_resource_t self; + cairo_pdf_resource_t length; + long long start_offset; + cairo_bool_t compressed; + cairo_output_stream_t *old_output; + } pdf_stream; + + struct { + cairo_bool_t active; + cairo_output_stream_t *stream; + cairo_output_stream_t *mem_stream; + cairo_output_stream_t *old_output; + cairo_pdf_resource_t resource; + cairo_box_double_t bbox; + cairo_bool_t is_knockout; + } group_stream; + + struct { + cairo_bool_t active; + cairo_output_stream_t *stream; + cairo_pdf_resource_t resource; + cairo_array_t objects; + } object_stream; + + cairo_surface_clipper_t clipper; + + cairo_pdf_operators_t pdf_operators; + cairo_paginated_mode_t paginated_mode; + cairo_bool_t type3_replay; + cairo_bool_t select_pattern_gstate_saved; + + cairo_bool_t force_fallbacks; + + cairo_operator_t current_operator; + cairo_bool_t reset_gs_required; + cairo_bool_t current_pattern_is_solid_color; + cairo_bool_t current_color_is_stroke; + double current_color_red; + double current_color_green; + double current_color_blue; + double current_color_alpha; + + cairo_pdf_interchange_t interchange; + int page_parent_tree; /* -1 if not used */ + cairo_array_t page_annots; + cairo_bool_t tagged; + char *current_page_label; + cairo_array_t page_labels; + cairo_pdf_resource_t outlines_dict_res; + cairo_pdf_resource_t names_dict_res; + cairo_pdf_resource_t docinfo_res; + cairo_pdf_resource_t page_labels_res; + + int thumbnail_width; + int thumbnail_height; + cairo_image_surface_t *thumbnail_image; + + cairo_surface_t *paginated_surface; + + cairo_bool_t debug; +}; + +cairo_private cairo_pdf_resource_t +_cairo_pdf_surface_new_object (cairo_pdf_surface_t *surface); + +cairo_private void +_cairo_pdf_surface_update_object (cairo_pdf_surface_t *surface, + cairo_pdf_resource_t resource); + +cairo_private cairo_int_status_t +_cairo_utf8_to_pdf_string (const char *utf8, char **str_out); + +cairo_private cairo_int_status_t +_cairo_pdf_interchange_init (cairo_pdf_surface_t *surface); + +cairo_private void +_cairo_pdf_interchange_fini (cairo_pdf_surface_t *surface); + +cairo_private cairo_int_status_t +_cairo_pdf_interchange_begin_page_content (cairo_pdf_surface_t *surface); + +cairo_private cairo_int_status_t +_cairo_pdf_interchange_end_page_content (cairo_pdf_surface_t *surface); + +cairo_private cairo_int_status_t +_cairo_pdf_interchange_tag_begin (cairo_pdf_surface_t *surface, + const char *name, + const char *attributes); + +cairo_private cairo_int_status_t +_cairo_pdf_surface_object_begin (cairo_pdf_surface_t *surface, + cairo_pdf_resource_t resource); + +cairo_private void +_cairo_pdf_surface_object_end (cairo_pdf_surface_t *surface); + +cairo_private cairo_bool_t +_cairo_pdf_interchange_struct_tree_requires_recording_surface ( + cairo_pdf_surface_t *surface, + const cairo_surface_pattern_t *recording_surface, + cairo_analysis_source_t source_type); + +cairo_private cairo_int_status_t +_cairo_pdf_interchange_recording_source_surface_begin ( + cairo_pdf_surface_t *surface, + const cairo_surface_pattern_t *recording_surface_pattern, + unsigned int region_id, + cairo_analysis_source_t source_type); + +cairo_private cairo_int_status_t +_cairo_pdf_interchange_recording_source_surface_end ( + cairo_pdf_surface_t *surface, + const cairo_surface_pattern_t *recording_surface_pattern, + unsigned int region_id, + cairo_analysis_source_t source_type); + +cairo_private cairo_int_status_t +_cairo_pdf_interchange_emit_recording_surface_begin ( + cairo_pdf_surface_t *surface, + cairo_surface_t *recording_surface, + int region_id, + cairo_pdf_resource_t surface_resource, + int *struct_parents); + +cairo_private cairo_int_status_t +_cairo_pdf_interchange_emit_recording_surface_end ( + cairo_pdf_surface_t *surface, + cairo_surface_t *recording_surface); + +cairo_private cairo_int_status_t +_cairo_pdf_interchange_tag_end (cairo_pdf_surface_t *surface, + const char *name); + +cairo_private cairo_int_status_t +_cairo_pdf_interchange_command_id (cairo_pdf_surface_t *surface, + unsigned int recording_id, + unsigned int command_id); + +cairo_private cairo_int_status_t +_cairo_pdf_interchange_add_operation_extents (cairo_pdf_surface_t *surface, + const cairo_rectangle_int_t *extents); + +cairo_private cairo_int_status_t +_cairo_pdf_interchange_add_content (cairo_pdf_surface_t *surface); + +cairo_private cairo_int_status_t +_cairo_pdf_interchange_write_page_objects (cairo_pdf_surface_t *surface); + +cairo_private cairo_int_status_t +_cairo_pdf_interchange_write_document_objects (cairo_pdf_surface_t *surface); + +cairo_private cairo_int_status_t +_cairo_pdf_interchange_add_outline (cairo_pdf_surface_t *surface, + int parent_id, + const char *name, + const char *dest, + cairo_pdf_outline_flags_t flags, + int *id); + +cairo_private cairo_int_status_t +_cairo_pdf_interchange_set_metadata (cairo_pdf_surface_t *surface, + cairo_pdf_metadata_t metadata, + const char *utf8); + +cairo_private cairo_int_status_t +_cairo_pdf_interchange_set_custom_metadata (cairo_pdf_surface_t *surface, + const char *name, + const char *value); + +#endif /* CAIRO_PDF_SURFACE_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-pdf-surface.c b/local/recipes/libs/cairo/source/src/cairo-pdf-surface.c new file mode 100644 index 0000000000..3e734c7595 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-pdf-surface.c @@ -0,0 +1,9538 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2004 Red Hat, Inc + * Copyright © 2006 Red Hat, Inc + * Copyright © 2007, 2008 Adrian Johnson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Kristian Høgsberg + * Carl Worth + * Adrian Johnson + */ + +#define _DEFAULT_SOURCE /* for snprintf() */ +#include "cairoint.h" + +#include "cairo-pdf.h" +#include "cairo-pdf-surface-private.h" +#include "cairo-pdf-operators-private.h" +#include "cairo-pdf-shading-private.h" + +#include "cairo-array-private.h" +#include "cairo-analysis-surface-private.h" +#include "cairo-composite-rectangles-private.h" +#include "cairo-default-context-private.h" +#include "cairo-error-private.h" +#include "cairo-user-font-private.h" +#include "cairo-image-surface-inline.h" +#include "cairo-image-info-private.h" +#include "cairo-recording-surface-inline.h" +#include "cairo-recording-surface-private.h" +#include "cairo-output-stream-private.h" +#include "cairo-paginated-private.h" +#include "cairo-scaled-font-subsets-private.h" +#include "cairo-surface-clipper-private.h" +#include "cairo-surface-snapshot-inline.h" +#include "cairo-surface-subsurface-private.h" +#include "cairo-type3-glyph-surface-private.h" + +#include + +/* + * Page Structure of the Generated PDF: + * + * Each page requiring fallbacks images contains a knockout group at + * the top level. The first operation of the knockout group paints a + * group containing all the supported drawing operations. Fallback + * images (if any) are painted in the knockout group. This ensures + * that fallback images do not composite with any content under the + * fallback images. + * + * Streams: + * + * This PDF surface has three types of streams: + * - PDF Stream + * - Content Stream + * - Group Stream + * - Object stream + * + * Calling _cairo_output_stream_printf (surface->output, ...) will + * write to the currently open stream. + * + * PDF Stream: + * A PDF Stream may be opened and closed with the following functions: + * _cairo_pdf_surface_open stream () + * _cairo_pdf_surface_close_stream () + * + * PDF Streams are written directly to the PDF file. They are used for + * fonts, images and patterns. + * + * Content Stream: + * The Content Stream is opened and closed with the following functions: + * _cairo_pdf_surface_open_content_stream () + * _cairo_pdf_surface_close_content_stream () + * + * The Content Stream contains the text and graphics operators. + * + * Group Stream: + * A Group Stream may be opened and closed with the following functions: + * _cairo_pdf_surface_open_group () + * _cairo_pdf_surface_close_group () + * + * A Group Stream is a Form XObject. It is used for short sequences + * of operators. As the content is very short the group is stored in + * memory until it is closed. This allows some optimization such as + * including the Resource dictionary and stream length inside the + * XObject instead of using an indirect object. + * + * Object Stream (PDF 1.5) + * An Object Stream may be opened and closed with the following functions: + * _cairo_pdf_surface_open_object_stream () + * _cairo_pdf_surface_close_object_stream () + * + * An Object Stream contains one or more objects compressed into a stream. + * Only non stream objects are permitted. When emitting objects intended for + * the Object Stream, enclose the emit object operation with + * _cairo_pdf_surface_object_begin()/_cairo_pdf_surface_object_end(). + */ + +/** + * SECTION:cairo-pdf + * @Title: PDF Surfaces + * @Short_Description: Rendering PDF documents + * @See_Also: #cairo_surface_t + * + * The PDF surface is used to render cairo graphics to Adobe + * PDF files and is a multi-page vector surface backend. + * + * The following mime types are supported on source patterns: + * %CAIRO_MIME_TYPE_JPEG, %CAIRO_MIME_TYPE_JP2, + * %CAIRO_MIME_TYPE_UNIQUE_ID, %CAIRO_MIME_TYPE_JBIG2, + * %CAIRO_MIME_TYPE_JBIG2_GLOBAL, %CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID, + * %CAIRO_MIME_TYPE_CCITT_FAX, %CAIRO_MIME_TYPE_CCITT_FAX_PARAMS. + * + * # JBIG2 Images # + * JBIG2 data in PDF must be in the embedded format as described in + * ISO/IEC 11544. Image specific JBIG2 data must be in + * %CAIRO_MIME_TYPE_JBIG2. Any global segments in the JBIG2 data + * (segments with page association field set to 0) must be in + * %CAIRO_MIME_TYPE_JBIG2_GLOBAL. The global data may be shared by + * multiple images. All images sharing the same global data must set + * %CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID to a unique identifier. At least + * one of the images must provide the global data using + * %CAIRO_MIME_TYPE_JBIG2_GLOBAL. The global data will only be + * embedded once and shared by all JBIG2 images with the same + * %CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID. + * + * # CCITT Fax Images # {#ccitt} + * The %CAIRO_MIME_TYPE_CCITT_FAX mime data requires a number of decoding + * parameters These parameters are specified using %CAIRO_MIME_TYPE_CCITT_FAX_PARAMS. + * + * %CAIRO_MIME_TYPE_CCITT_FAX_PARAMS mime data must contain a string of the form + * "param1=value1 param2=value2 ...". + * + * @Columns: [required] An integer specifying the width of the image in pixels. + * + * @Rows: [required] An integer specifying the height of the image in scan lines. + * + * @K: [optional] An integer identifying the encoding scheme used. < 0 + * is 2 dimensional Group 4, = 0 is Group3 1 dimensional, > 0 is mixed 1 + * and 2 dimensional encoding. Default is 0. + * + * @EndOfLine: [optional] If true end-of-line bit patterns are present. Default is false. + * + * @EncodedByteAlign: [optional] If true the end of line is padded + * with 0 bits so the next line begins on a byte boundary. Default is false. + * + * @EndOfBlock: [optional] If true the data contains an end-of-block pattern. Default is true. + * + * @BlackIs1: [optional] If true 1 bits are black pixels. Default is false. + * + * @DamagedRowsBeforeError: [optional] An integer specifying the + * number of damages rows tolerated before an error occurs. Default is 0. + * + * Boolean values may be "true" or "false", or 1 or 0. + * + * These parameters are the same as the CCITTFaxDecode parameters in the + * [PostScript Language Reference](https://www.adobe.com/products/postscript/pdfs/PLRM.pdf) + * and [Portable Document Format (PDF)](https://www.adobe.com/content/dam/Adobe/en/devnet/pdf/pdfs/PDF32000_2008.pdf). + * Refer to these documents for further details. + * + * An example %CAIRO_MIME_TYPE_CCITT_FAX_PARAMS string is: + * + * + * "Columns=10230 Rows=40000 K=1 EndOfLine=true EncodedByteAlign=1 BlackIs1=false" + * + * + **/ + +static cairo_bool_t +_cairo_pdf_surface_get_extents (void *abstract_surface, + cairo_rectangle_int_t *rectangle); + +/** + * CAIRO_HAS_PDF_SURFACE: + * + * Defined if the PDF surface backend is available. + * This macro can be used to conditionally compile backend-specific code. + * + * Since: 1.2 + **/ + +static const cairo_pdf_version_t _cairo_pdf_versions[] = +{ + CAIRO_PDF_VERSION_1_4, + CAIRO_PDF_VERSION_1_5, + CAIRO_PDF_VERSION_1_6, + CAIRO_PDF_VERSION_1_7 +}; + +#define CAIRO_PDF_VERSION_LAST ARRAY_LENGTH (_cairo_pdf_versions) + +static const char * _cairo_pdf_version_strings[CAIRO_PDF_VERSION_LAST] = +{ + "PDF 1.4", + "PDF 1.5", + "PDF 1.6", + "PDF 1.7" +}; + +static const char *_cairo_pdf_supported_mime_types[] = +{ + CAIRO_MIME_TYPE_JPEG, + CAIRO_MIME_TYPE_JP2, + CAIRO_MIME_TYPE_UNIQUE_ID, + CAIRO_MIME_TYPE_JBIG2, + CAIRO_MIME_TYPE_JBIG2_GLOBAL, + CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID, + CAIRO_MIME_TYPE_CCITT_FAX, + CAIRO_MIME_TYPE_CCITT_FAX_PARAMS, + NULL +}; + +/* PDF cross-reference stream types */ +typedef enum { + PDF_OBJECT_FREE = 0, + PDF_OBJECT_UNCOMPRESSED = 1, + PDF_OBJECT_COMPRESSED = 2, +} cairo_pdf_object_type_t; + +typedef struct _cairo_pdf_object { + cairo_pdf_object_type_t type; + union { + long long offset; /* type == PDF_OBJECT_UNCOMPRESSED */ + struct compressed_obj { /* type == PDF_OBJECT_COMPRESSED */ + cairo_pdf_resource_t xref_stream; + int index; + } compressed_obj; + } u; +} cairo_pdf_object_t; + +typedef struct _cairo_xref_stream_object { + cairo_pdf_resource_t resource; + long long offset; +} cairo_xref_stream_object_t; + +typedef struct _cairo_pdf_font { + unsigned int font_id; + unsigned int subset_id; + cairo_pdf_resource_t subset_resource; +} cairo_pdf_font_t; + +typedef struct _cairo_pdf_rgb_linear_function { + cairo_pdf_resource_t resource; + double color1[3]; + double color2[3]; +} cairo_pdf_rgb_linear_function_t; + +typedef struct _cairo_pdf_alpha_linear_function { + cairo_pdf_resource_t resource; + double alpha1; + double alpha2; +} cairo_pdf_alpha_linear_function_t; + +static void +_cairo_pdf_surface_clear (cairo_pdf_surface_t *surface, + cairo_bool_t clear_doc_surfaces); + +static void +_cairo_pdf_smask_group_destroy (cairo_pdf_smask_group_t *group); + +static cairo_int_status_t +_cairo_pdf_surface_add_font (unsigned int font_id, + unsigned int subset_id, + void *closure); + +static void +_cairo_pdf_group_resources_init (cairo_pdf_group_resources_t *res); + +static cairo_int_status_t +_cairo_pdf_surface_open_stream (cairo_pdf_surface_t *surface, + cairo_pdf_resource_t *resource, + cairo_bool_t compressed, + const char *fmt, + ...) CAIRO_PRINTF_FORMAT(4, 5); +static cairo_int_status_t +_cairo_pdf_surface_close_stream (cairo_pdf_surface_t *surface); + +static cairo_int_status_t +_cairo_pdf_surface_emit_surface (cairo_pdf_surface_t *surface, + cairo_pdf_source_surface_t *source, + cairo_bool_t test, + cairo_bool_t *is_image); + +static cairo_int_status_t +_cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface); + +static cairo_int_status_t +_cairo_pdf_surface_write_pages (cairo_pdf_surface_t *surface); + +static cairo_int_status_t +_cairo_pdf_surface_write_catalog (cairo_pdf_surface_t *surface, + cairo_pdf_resource_t catalog); + +static long long +_cairo_pdf_surface_write_xref (cairo_pdf_surface_t *surface); + +static cairo_int_status_t +_cairo_pdf_surface_write_xref_stream (cairo_pdf_surface_t *surface, + cairo_pdf_resource_t xref_res, + cairo_pdf_resource_t root_res, + cairo_pdf_resource_t info_res, + long long *xref_offset); + +static cairo_int_status_t +_cairo_pdf_surface_write_patterns_and_smask_groups (cairo_pdf_surface_t *surface, + cairo_bool_t finish); + +static cairo_int_status_t +_cairo_pdf_surface_emit_font_subsets (cairo_pdf_surface_t *surface); + +static cairo_bool_t +_cairo_pdf_source_surface_equal (const void *key_a, const void *key_b); + +static cairo_bool_t +_cairo_pdf_color_glyph_equal (const void *key_a, const void *key_b); + +static const cairo_surface_backend_t cairo_pdf_surface_backend; +static const cairo_paginated_surface_backend_t cairo_pdf_surface_paginated_backend; + +cairo_pdf_resource_t +_cairo_pdf_surface_new_object (cairo_pdf_surface_t *surface) +{ + cairo_pdf_resource_t resource; + cairo_int_status_t status; + cairo_pdf_object_t object; + + /* Default to Uncompressed. If this object is used with + * _cairo_pdf_surface_object_begin() and Object Streams are + * enabled it will be changed to Compressed. */ + object.type = PDF_OBJECT_UNCOMPRESSED; + object.u.offset = _cairo_output_stream_get_position (surface->output); + + status = _cairo_array_append (&surface->objects, &object); + if (unlikely (status)) { + resource.id = 0; + return resource; + } + + resource = surface->next_available_resource; + surface->next_available_resource.id++; + + return resource; +} + +void +_cairo_pdf_surface_update_object (cairo_pdf_surface_t *surface, + cairo_pdf_resource_t resource) +{ + cairo_pdf_object_t *object; + + object = _cairo_array_index (&surface->objects, resource.id - 1); + object->u.offset = _cairo_output_stream_get_position (surface->output); +} + +static void +_cairo_pdf_surface_set_size_internal (cairo_pdf_surface_t *surface, + double width, + double height) +{ + surface->width = width; + surface->height = height; + surface->surface_extents.x = 0; + surface->surface_extents.y = 0; + surface->surface_extents.width = ceil (surface->width); + surface->surface_extents.height = ceil (surface->height); +} + +static cairo_bool_t +_path_covers_bbox (cairo_pdf_surface_t *surface, + cairo_path_fixed_t *path) +{ + cairo_box_t box; + + return _cairo_path_fixed_is_box (path, &box) && + box.p1.x <= 0 && + box.p1.y <= 0 && + box.p2.x >= _cairo_fixed_from_double (surface->width) && + box.p2.y >= _cairo_fixed_from_double (surface->height); +} + +static cairo_status_t +_cairo_pdf_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_pdf_surface_t *surface = cairo_container_of (clipper, + cairo_pdf_surface_t, + clipper); + cairo_int_status_t status; + + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (unlikely (status)) + return status; + + if (path == NULL) { + _cairo_output_stream_printf (surface->output, "Q q\n"); + + surface->current_pattern_is_solid_color = FALSE; + surface->current_operator = CAIRO_OPERATOR_OVER; + _cairo_pdf_operators_reset (&surface->pdf_operators); + + return CAIRO_STATUS_SUCCESS; + } + + if (_path_covers_bbox (surface, path)) + return CAIRO_STATUS_SUCCESS; + + return _cairo_pdf_operators_clip (&surface->pdf_operators, path, fill_rule); +} + +static cairo_surface_t * +_cairo_pdf_surface_create_for_stream_internal (cairo_output_stream_t *output, + double width, + double height) +{ + cairo_pdf_surface_t *surface; + cairo_status_t status, status_ignored; + + surface = _cairo_calloc (sizeof (cairo_pdf_surface_t)); + if (unlikely (surface == NULL)) { + /* destroy stream on behalf of caller */ + status = _cairo_output_stream_destroy (output); + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + } + + _cairo_surface_init (&surface->base, + &cairo_pdf_surface_backend, + NULL, /* device */ + CAIRO_CONTENT_COLOR_ALPHA, + TRUE); /* is_vector */ + + surface->output = output; + surface->width = width; + surface->height = height; + cairo_matrix_init (&surface->cairo_to_pdf, 1, 0, 0, 1, 0, 0); + surface->in_xobject = FALSE; + surface->surface_extents.x = 0; + surface->surface_extents.y = 0; + surface->surface_extents.width = ceil (surface->width); + surface->surface_extents.height = ceil (surface->height); + surface->surface_bounded = TRUE; + + _cairo_array_init (&surface->objects, sizeof (cairo_pdf_object_t)); + _cairo_array_init (&surface->pages, sizeof (cairo_pdf_page_info_t)); + _cairo_array_init (&surface->rgb_linear_functions, sizeof (cairo_pdf_rgb_linear_function_t)); + _cairo_array_init (&surface->alpha_linear_functions, sizeof (cairo_pdf_alpha_linear_function_t)); + _cairo_array_init (&surface->fonts, sizeof (cairo_pdf_font_t)); + _cairo_array_init (&surface->smask_groups, sizeof (cairo_pdf_smask_group_t *)); + _cairo_array_init (&surface->knockout_group, sizeof (cairo_pdf_resource_t)); + + _cairo_array_init (&surface->page_patterns, sizeof (cairo_pdf_pattern_t)); + _cairo_array_init (&surface->page_surfaces, sizeof (cairo_pdf_source_surface_t)); + _cairo_array_init (&surface->doc_surfaces, sizeof (cairo_pdf_source_surface_t)); + _cairo_array_init (&surface->jbig2_global, sizeof (cairo_pdf_jbig2_global_t)); + surface->all_surfaces = _cairo_hash_table_create (_cairo_pdf_source_surface_equal); + if (unlikely (surface->all_surfaces == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto BAIL0; + } + + surface->color_glyphs = _cairo_hash_table_create (_cairo_pdf_color_glyph_equal); + if (unlikely (surface->color_glyphs == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto BAIL1; + } + + surface->duplicate_surface_number = 0; + + _cairo_pdf_group_resources_init (&surface->resources); + + surface->font_subsets = _cairo_scaled_font_subsets_create_composite (); + if (! surface->font_subsets) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto BAIL2; + } + + _cairo_scaled_font_subsets_enable_latin_subset (surface->font_subsets, TRUE); + + surface->next_available_resource.id = 1; + surface->pages_resource = _cairo_pdf_surface_new_object (surface); + if (surface->pages_resource.id == 0) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto BAIL3; + } + + surface->struct_tree_root.id = 0; + surface->pdf_version = CAIRO_PDF_VERSION_1_7; + surface->compress_streams = TRUE; + surface->pdf_stream.active = FALSE; + surface->pdf_stream.old_output = NULL; + surface->group_stream.active = FALSE; + surface->group_stream.stream = NULL; + surface->group_stream.mem_stream = NULL; + surface->object_stream.active = FALSE; + surface->object_stream.stream = NULL; + _cairo_array_init (&surface->object_stream.objects, sizeof (cairo_xref_stream_object_t)); + + surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE; + surface->type3_replay = FALSE; + + surface->force_fallbacks = FALSE; + surface->select_pattern_gstate_saved = FALSE; + surface->current_pattern_is_solid_color = FALSE; + surface->current_operator = CAIRO_OPERATOR_OVER; + surface->reset_gs_required = FALSE; + surface->header_emitted = FALSE; + + _cairo_surface_clipper_init (&surface->clipper, + _cairo_pdf_surface_clipper_intersect_clip_path); + + _cairo_pdf_operators_init (&surface->pdf_operators, + surface->output, + &surface->cairo_to_pdf, + surface->font_subsets, + FALSE); + _cairo_pdf_operators_set_font_subsets_callback (&surface->pdf_operators, + _cairo_pdf_surface_add_font, + surface); + _cairo_pdf_operators_enable_actual_text(&surface->pdf_operators, TRUE); + + status = _cairo_pdf_interchange_init (surface); + if (unlikely (status)) + goto BAIL3; + + surface->page_parent_tree = -1; + _cairo_array_init (&surface->page_annots, sizeof (cairo_pdf_resource_t)); + surface->tagged = FALSE; + surface->current_page_label = NULL; + _cairo_array_init (&surface->page_labels, sizeof (char *)); + surface->outlines_dict_res.id = 0; + surface->names_dict_res.id = 0; + surface->docinfo_res.id = 0; + surface->page_labels_res.id = 0; + surface->thumbnail_width = 0; + surface->thumbnail_height = 0; + surface->thumbnail_image = NULL; + + surface->debug = FALSE; + if (getenv ("CAIRO_DEBUG_PDF") != NULL) { + surface->debug = TRUE; + surface->compress_streams = FALSE; + } + + surface->paginated_surface = _cairo_paginated_surface_create ( + &surface->base, + CAIRO_CONTENT_COLOR_ALPHA, + &cairo_pdf_surface_paginated_backend); + + status = surface->paginated_surface->status; + if (status == CAIRO_STATUS_SUCCESS) { + /* paginated keeps the only reference to surface now, drop ours */ + cairo_surface_destroy (&surface->base); + return surface->paginated_surface; + } + +BAIL3: + _cairo_scaled_font_subsets_destroy (surface->font_subsets); +BAIL2: + _cairo_hash_table_destroy (surface->color_glyphs); +BAIL1: + _cairo_hash_table_destroy (surface->all_surfaces); +BAIL0: + _cairo_array_fini (&surface->objects); + free (surface); + + /* destroy stream on behalf of caller */ + status_ignored = _cairo_output_stream_destroy (output); + + return _cairo_surface_create_in_error (status); +} + +/** + * cairo_pdf_surface_create_for_stream: + * @write_func: a #cairo_write_func_t to accept the output data, may be %NULL + * to indicate a no-op @write_func. With a no-op @write_func, + * the surface may be queried or used as a source without + * generating any temporary files. + * @closure: the closure argument for @write_func + * @width_in_points: width of the surface, in points (1 point == 1/72.0 inch) + * @height_in_points: height of the surface, in points (1 point == 1/72.0 inch) + * + * Creates a PDF surface of the specified size in points to be written + * incrementally to the stream represented by @write_func and @closure. + * + * Return value: a pointer to the newly created surface. The caller + * owns the surface and should call cairo_surface_destroy() when done + * with it. + * + * This function always returns a valid pointer, but it will return a + * pointer to a "nil" surface if an error such as out of memory + * occurs. You can use cairo_surface_status() to check for this. + * + * Since: 1.2 + **/ +cairo_surface_t * +cairo_pdf_surface_create_for_stream (cairo_write_func_t write_func, + void *closure, + double width_in_points, + double height_in_points) +{ + cairo_output_stream_t *output; + + output = _cairo_output_stream_create (write_func, NULL, closure); + if (_cairo_output_stream_get_status (output)) + return _cairo_surface_create_in_error (_cairo_output_stream_destroy (output)); + + return _cairo_pdf_surface_create_for_stream_internal (output, + width_in_points, + height_in_points); +} + +/** + * cairo_pdf_surface_create: + * @filename: a filename for the PDF output (must be writable), %NULL may be + * used to specify no output. This will generate a PDF surface that + * may be queried and used as a source, without generating a + * temporary file. + * @width_in_points: width of the surface, in points (1 point == 1/72.0 inch) + * @height_in_points: height of the surface, in points (1 point == 1/72.0 inch) + * + * Creates a PDF surface of the specified size in points to be written + * to @filename. + * + * Return value: a pointer to the newly created surface. The caller + * owns the surface and should call cairo_surface_destroy() when done + * with it. + * + * This function always returns a valid pointer, but it will return a + * pointer to a "nil" surface if an error such as out of memory + * occurs. You can use cairo_surface_status() to check for this. + * + * Since: 1.2 + **/ +cairo_surface_t * +cairo_pdf_surface_create (const char *filename, + double width_in_points, + double height_in_points) +{ + cairo_output_stream_t *output; + + output = _cairo_output_stream_create_for_filename (filename); + if (_cairo_output_stream_get_status (output)) + return _cairo_surface_create_in_error (_cairo_output_stream_destroy (output)); + + return _cairo_pdf_surface_create_for_stream_internal (output, + width_in_points, + height_in_points); +} + +static cairo_bool_t +_cairo_surface_is_pdf (cairo_surface_t *surface) +{ + return surface->backend == &cairo_pdf_surface_backend; +} + +/* If the abstract_surface is a paginated surface, and that paginated + * surface's target is a pdf_surface, then set pdf_surface to that + * target. Otherwise return FALSE. + */ +static cairo_bool_t +_extract_pdf_surface (cairo_surface_t *surface, + cairo_pdf_surface_t **pdf_surface) +{ + cairo_surface_t *target; + cairo_status_t status_ignored; + + if (surface->status) + return FALSE; + if (surface->finished) { + status_ignored = _cairo_surface_set_error (surface, + _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + return FALSE; + } + + if (! _cairo_surface_is_paginated (surface)) { + status_ignored = _cairo_surface_set_error (surface, + _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); + return FALSE; + } + + target = _cairo_paginated_surface_get_target (surface); + if (target->status) { + status_ignored = _cairo_surface_set_error (surface, + target->status); + return FALSE; + } + if (target->finished) { + status_ignored = _cairo_surface_set_error (surface, + _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + return FALSE; + } + + if (! _cairo_surface_is_pdf (target)) { + status_ignored = _cairo_surface_set_error (surface, + _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); + return FALSE; + } + + *pdf_surface = (cairo_pdf_surface_t *) target; + return TRUE; +} + +/** + * cairo_pdf_surface_restrict_to_version: + * @surface: a PDF #cairo_surface_t + * @version: PDF version + * + * Restricts the generated PDF file to @version. See cairo_pdf_get_versions() + * for a list of available version values that can be used here. + * + * This function should only be called before any drawing operations + * have been performed on the given surface. The simplest way to do + * this is to call this function immediately after creating the + * surface. + * + * Since: 1.10 + **/ +void +cairo_pdf_surface_restrict_to_version (cairo_surface_t *abstract_surface, + cairo_pdf_version_t version) +{ + cairo_pdf_surface_t *surface = NULL; /* hide compiler warning */ + + if (! _extract_pdf_surface (abstract_surface, &surface)) + return; + + if (version < CAIRO_PDF_VERSION_LAST) + surface->pdf_version = version; + + _cairo_pdf_operators_enable_actual_text(&surface->pdf_operators, + version >= CAIRO_PDF_VERSION_1_5); +} + +/** + * cairo_pdf_get_versions: + * @versions: supported version list + * @num_versions: list length + * + * Used to retrieve the list of supported versions. See + * cairo_pdf_surface_restrict_to_version(). + * + * Since: 1.10 + **/ +void +cairo_pdf_get_versions (cairo_pdf_version_t const **versions, + int *num_versions) +{ + if (versions != NULL) + *versions = _cairo_pdf_versions; + + if (num_versions != NULL) + *num_versions = CAIRO_PDF_VERSION_LAST; +} + +/** + * cairo_pdf_version_to_string: + * @version: a version id + * + * Get the string representation of the given @version id. This function + * will return %NULL if @version isn't valid. See cairo_pdf_get_versions() + * for a way to get the list of valid version ids. + * + * Return value: the string associated to given version. + * + * Since: 1.10 + **/ +const char * +cairo_pdf_version_to_string (cairo_pdf_version_t version) +{ + if (version < 0 || version >= CAIRO_PDF_VERSION_LAST) + return NULL; + + return _cairo_pdf_version_strings[version]; +} + +/** + * cairo_pdf_surface_set_size: + * @surface: a PDF #cairo_surface_t + * @width_in_points: new surface width, in points (1 point == 1/72.0 inch) + * @height_in_points: new surface height, in points (1 point == 1/72.0 inch) + * + * Changes the size of a PDF surface for the current (and + * subsequent) pages. + * + * This function should only be called before any drawing operations + * have been performed on the current page. The simplest way to do + * this is to call this function immediately after creating the + * surface or immediately after completing a page with either + * cairo_show_page() or cairo_copy_page(). + * + * Since: 1.2 + **/ +void +cairo_pdf_surface_set_size (cairo_surface_t *surface, + double width_in_points, + double height_in_points) +{ + cairo_pdf_surface_t *pdf_surface = NULL; /* hide compiler warning */ + cairo_status_t status; + + if (! _extract_pdf_surface (surface, &pdf_surface)) + return; + + _cairo_pdf_surface_set_size_internal (pdf_surface, + width_in_points, + height_in_points); + status = _cairo_paginated_surface_set_size (pdf_surface->paginated_surface, + width_in_points, + height_in_points); + if (status) + status = _cairo_surface_set_error (surface, status); +} + +/** + * CAIRO_PDF_OUTLINE_ROOT: + * + * The root outline item in cairo_pdf_surface_add_outline(). + * + * Since: 1.16 + **/ + +/** + * cairo_pdf_surface_add_outline: + * @surface: a PDF #cairo_surface_t + * @parent_id: the id of the parent item or %CAIRO_PDF_OUTLINE_ROOT if this is a top level item. + * @utf8: the name of the outline + * @link_attribs: the link attributes specifying where this outline links to + * @flags: outline item flags + * + * Add an item to the document outline hierarchy with the name @utf8 + * that links to the location specified by @link_attribs. Link + * attributes have the same keys and values as the [Link Tag][link], + * excluding the "rect" attribute. The item will be a child of the + * item with id @parent_id. Use %CAIRO_PDF_OUTLINE_ROOT as the parent + * id of top level items. + * + * Return value: the id for the added item. + * + * Since: 1.16 + **/ +int +cairo_pdf_surface_add_outline (cairo_surface_t *surface, + int parent_id, + const char *utf8, + const char *link_attribs, + cairo_pdf_outline_flags_t flags) +{ + cairo_pdf_surface_t *pdf_surface = NULL; /* hide compiler warning */ + cairo_status_t status; + int id = 0; + + if (! _extract_pdf_surface (surface, &pdf_surface)) + return 0; + + status = _cairo_pdf_interchange_add_outline (pdf_surface, + parent_id, + utf8, + link_attribs, + flags, + &id); + if (status) + status = _cairo_surface_set_error (surface, status); + + return id; +} + +/** + * cairo_pdf_surface_set_metadata: + * @surface: a PDF #cairo_surface_t + * @metadata: The metadata item to set. + * @utf8: metadata value + * + * Set document metadata. The %CAIRO_PDF_METADATA_CREATE_DATE and + * %CAIRO_PDF_METADATA_MOD_DATE values must be in ISO-8601 format: + * YYYY-MM-DDThh:mm:ss. An optional timezone of the form "[+/-]hh:mm" + * or "Z" for UTC time can be appended. All other metadata values can be any UTF-8 + * string. + * + * For example: + * + * cairo_pdf_surface_set_metadata (surface, CAIRO_PDF_METADATA_TITLE, "My Document"); + * cairo_pdf_surface_set_metadata (surface, CAIRO_PDF_METADATA_CREATE_DATE, "2015-12-31T23:59+02:00"); + * + * + * Since: 1.16 + **/ +void +cairo_pdf_surface_set_metadata (cairo_surface_t *surface, + cairo_pdf_metadata_t metadata, + const char *utf8) +{ + cairo_pdf_surface_t *pdf_surface = NULL; /* hide compiler warning */ + cairo_status_t status; + + if (! _extract_pdf_surface (surface, &pdf_surface)) + return; + + status = _cairo_pdf_interchange_set_metadata (pdf_surface, metadata, utf8); + if (status) + status = _cairo_surface_set_error (surface, status); +} + +/** + * cairo_pdf_surface_set_custom_metadata: + * @surface: a PDF #cairo_surface_t + * @name: The name of the custom metadata item to set (utf8). + * @value: The value of the metadata (utf8). + * + * Set custom document metadata. @name may be any string except for + * the following names reserved by PDF: "Title", "Author", "Subject", + * "Keywords", "Creator", "Producer", "CreationDate", "ModDate", + * "Trapped". + * + * If @value is NULL or an empty string, the @name metadata will not be set. + * + * For example: + * + * cairo_pdf_surface_set_custom_metadata (surface, "ISBN", "978-0123456789"); + * + * + * Since: 1.18 + **/ +void +cairo_pdf_surface_set_custom_metadata (cairo_surface_t *surface, + const char *name, + const char *value) +{ + cairo_pdf_surface_t *pdf_surface = NULL; /* hide compiler warning */ + cairo_status_t status; + + if (! _extract_pdf_surface (surface, &pdf_surface)) + return; + + status = _cairo_pdf_interchange_set_custom_metadata (pdf_surface, name, value); + if (status) + status = _cairo_surface_set_error (surface, status); +} + +/** + * cairo_pdf_surface_set_page_label: + * @surface: a PDF #cairo_surface_t + * @utf8: The page label. + * + * Set page label for the current page. + * + * Since: 1.16 + **/ +void +cairo_pdf_surface_set_page_label (cairo_surface_t *surface, + const char *utf8) +{ + cairo_pdf_surface_t *pdf_surface = NULL; /* hide compiler warning */ + + if (! _extract_pdf_surface (surface, &pdf_surface)) + return; + + free (pdf_surface->current_page_label); + pdf_surface->current_page_label = utf8 ? strdup (utf8) : NULL; +} + +/** + * cairo_pdf_surface_set_thumbnail_size: + * @surface: a PDF #cairo_surface_t + * @width: Thumbnail width. + * @height: Thumbnail height + * + * Set the thumbnail image size for the current and all subsequent + * pages. Setting a width or height of 0 disables thumbnails for the + * current and subsequent pages. + * + * Since: 1.16 + **/ +void +cairo_pdf_surface_set_thumbnail_size (cairo_surface_t *surface, + int width, + int height) +{ + cairo_pdf_surface_t *pdf_surface = NULL; /* hide compiler warning */ + + if (! _extract_pdf_surface (surface, &pdf_surface)) + return; + + pdf_surface->thumbnail_width = width; + pdf_surface->thumbnail_height = height; +} + +static void +_cairo_pdf_surface_clear (cairo_pdf_surface_t *surface, + cairo_bool_t clear_doc_surfaces) +{ + int i, size; + cairo_pdf_pattern_t *pattern; + cairo_pdf_source_surface_t *src_surface; + cairo_pdf_smask_group_t *group; + cairo_pdf_source_surface_t doc_surface; + + size = _cairo_array_num_elements (&surface->page_patterns); + for (i = 0; i < size; i++) { + pattern = (cairo_pdf_pattern_t *) _cairo_array_index (&surface->page_patterns, i); + cairo_pattern_destroy (pattern->pattern); + } + _cairo_array_truncate (&surface->page_patterns, 0); + + size = _cairo_array_num_elements (&surface->page_surfaces); + for (i = 0; i < size; i++) { + src_surface = (cairo_pdf_source_surface_t *) _cairo_array_index (&surface->page_surfaces, i); + if (src_surface->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) { + cairo_pattern_destroy (src_surface->raster_pattern); + } else { + if (_cairo_surface_is_recording (src_surface->surface) && src_surface->region_id != 0) + _cairo_recording_surface_region_array_remove (src_surface->surface, src_surface->region_id); + cairo_surface_destroy (src_surface->surface); + } + } + _cairo_array_truncate (&surface->page_surfaces, 0); + + size = _cairo_array_num_elements (&surface->smask_groups); + for (i = 0; i < size; i++) { + _cairo_array_copy_element (&surface->smask_groups, i, &group); + _cairo_pdf_smask_group_destroy (group); + } + _cairo_array_truncate (&surface->smask_groups, 0); + _cairo_array_truncate (&surface->knockout_group, 0); + _cairo_array_truncate (&surface->page_annots, 0); + + if (surface->thumbnail_image) + cairo_surface_destroy (&surface->thumbnail_image->base); + surface->thumbnail_image = NULL; + + if (clear_doc_surfaces) { + size = _cairo_array_num_elements (&surface->doc_surfaces); + for (i = 0; i < size; i++) { + _cairo_array_copy_element (&surface->doc_surfaces, i, &doc_surface); + if (doc_surface.type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) { + cairo_pattern_destroy (doc_surface.raster_pattern); + } else { + if (_cairo_surface_is_recording (doc_surface.surface) && doc_surface.region_id != 0) + _cairo_recording_surface_region_array_remove (doc_surface.surface, doc_surface.region_id); + cairo_surface_destroy (doc_surface.surface); + } + } + _cairo_array_truncate (&surface->doc_surfaces, 0); + } +} + +static void +_cairo_pdf_group_resources_init (cairo_pdf_group_resources_t *res) +{ + int i; + + for (i = 0; i < CAIRO_NUM_OPERATORS; i++) + res->operators[i] = FALSE; + + _cairo_array_init (&res->alphas, sizeof (double)); + _cairo_array_init (&res->smasks, sizeof (cairo_pdf_resource_t)); + _cairo_array_init (&res->patterns, sizeof (cairo_pdf_resource_t)); + _cairo_array_init (&res->shadings, sizeof (cairo_pdf_resource_t)); + _cairo_array_init (&res->xobjects, sizeof (cairo_pdf_resource_t)); + _cairo_array_init (&res->fonts, sizeof (cairo_pdf_font_t)); +} + +static void +_cairo_pdf_group_resources_fini (cairo_pdf_group_resources_t *res) +{ + _cairo_array_fini (&res->alphas); + _cairo_array_fini (&res->smasks); + _cairo_array_fini (&res->patterns); + _cairo_array_fini (&res->shadings); + _cairo_array_fini (&res->xobjects); + _cairo_array_fini (&res->fonts); +} + +static void +_cairo_pdf_group_resources_clear (cairo_pdf_group_resources_t *res) +{ + int i; + + for (i = 0; i < CAIRO_NUM_OPERATORS; i++) + res->operators[i] = FALSE; + + _cairo_array_truncate (&res->alphas, 0); + _cairo_array_truncate (&res->smasks, 0); + _cairo_array_truncate (&res->patterns, 0); + _cairo_array_truncate (&res->shadings, 0); + _cairo_array_truncate (&res->xobjects, 0); + _cairo_array_truncate (&res->fonts, 0); +} + +static void +_cairo_pdf_surface_add_operator (cairo_pdf_surface_t *surface, + cairo_operator_t op) +{ + cairo_pdf_group_resources_t *res = &surface->resources; + + res->operators[op] = TRUE; +} + +static cairo_int_status_t +_cairo_pdf_surface_add_alpha (cairo_pdf_surface_t *surface, + double alpha, + int *index) +{ + int num_alphas, i; + double other; + cairo_int_status_t status; + cairo_pdf_group_resources_t *res = &surface->resources; + + num_alphas = _cairo_array_num_elements (&res->alphas); + for (i = 0; i < num_alphas; i++) { + _cairo_array_copy_element (&res->alphas, i, &other); + if (alpha == other) { + *index = i; + return CAIRO_STATUS_SUCCESS; + } + } + + status = _cairo_array_append (&res->alphas, &alpha); + if (unlikely (status)) + return status; + + *index = _cairo_array_num_elements (&res->alphas) - 1; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_pdf_surface_add_smask (cairo_pdf_surface_t *surface, + cairo_pdf_resource_t smask) +{ + return _cairo_array_append (&(surface->resources.smasks), &smask); +} + +static cairo_int_status_t +_cairo_pdf_surface_add_pattern (cairo_pdf_surface_t *surface, + cairo_pdf_resource_t pattern) +{ + return _cairo_array_append (&(surface->resources.patterns), &pattern); +} + +static cairo_int_status_t +_cairo_pdf_surface_add_shading (cairo_pdf_surface_t *surface, + cairo_pdf_resource_t shading) +{ + return _cairo_array_append (&(surface->resources.shadings), &shading); +} + + +static cairo_int_status_t +_cairo_pdf_surface_add_xobject (cairo_pdf_surface_t *surface, + cairo_pdf_resource_t xobject) +{ + return _cairo_array_append (&(surface->resources.xobjects), &xobject); +} + +static cairo_int_status_t +_cairo_pdf_surface_add_font (unsigned int font_id, + unsigned int subset_id, + void *closure) +{ + cairo_pdf_surface_t *surface = closure; + cairo_pdf_font_t font; + int num_fonts, i; + cairo_int_status_t status; + cairo_pdf_group_resources_t *res = &surface->resources; + + num_fonts = _cairo_array_num_elements (&res->fonts); + for (i = 0; i < num_fonts; i++) { + _cairo_array_copy_element (&res->fonts, i, &font); + if (font.font_id == font_id && + font.subset_id == subset_id) + return CAIRO_STATUS_SUCCESS; + } + + num_fonts = _cairo_array_num_elements (&surface->fonts); + for (i = 0; i < num_fonts; i++) { + _cairo_array_copy_element (&surface->fonts, i, &font); + if (font.font_id == font_id && + font.subset_id == subset_id) + return _cairo_array_append (&res->fonts, &font); + } + + font.font_id = font_id; + font.subset_id = subset_id; + font.subset_resource = _cairo_pdf_surface_new_object (surface); + if (font.subset_resource.id == 0) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + status = _cairo_array_append (&surface->fonts, &font); + if (unlikely (status)) + return status; + + return _cairo_array_append (&res->fonts, &font); +} + +static cairo_pdf_resource_t +_cairo_pdf_surface_get_font_resource (cairo_pdf_surface_t *surface, + unsigned int font_id, + unsigned int subset_id) +{ + cairo_pdf_font_t font; + int num_fonts, i; + + num_fonts = _cairo_array_num_elements (&surface->fonts); + for (i = 0; i < num_fonts; i++) { + _cairo_array_copy_element (&surface->fonts, i, &font); + if (font.font_id == font_id && font.subset_id == subset_id) + return font.subset_resource; + } + + font.subset_resource.id = 0; + return font.subset_resource; +} + +static const char * +_cairo_operator_to_pdf_blend_mode (cairo_operator_t op) +{ + switch (op) { + /* The extend blend mode operators */ + case CAIRO_OPERATOR_MULTIPLY: return "Multiply"; + case CAIRO_OPERATOR_SCREEN: return "Screen"; + case CAIRO_OPERATOR_OVERLAY: return "Overlay"; + case CAIRO_OPERATOR_DARKEN: return "Darken"; + case CAIRO_OPERATOR_LIGHTEN: return "Lighten"; + case CAIRO_OPERATOR_COLOR_DODGE: return "ColorDodge"; + case CAIRO_OPERATOR_COLOR_BURN: return "ColorBurn"; + case CAIRO_OPERATOR_HARD_LIGHT: return "HardLight"; + case CAIRO_OPERATOR_SOFT_LIGHT: return "SoftLight"; + case CAIRO_OPERATOR_DIFFERENCE: return "Difference"; + case CAIRO_OPERATOR_EXCLUSION: return "Exclusion"; + case CAIRO_OPERATOR_HSL_HUE: return "Hue"; + case CAIRO_OPERATOR_HSL_SATURATION: return "Saturation"; + case CAIRO_OPERATOR_HSL_COLOR: return "Color"; + case CAIRO_OPERATOR_HSL_LUMINOSITY: return "Luminosity"; + + default: + /* The original Porter-Duff set */ + case CAIRO_OPERATOR_CLEAR: + case CAIRO_OPERATOR_SOURCE: + case CAIRO_OPERATOR_OVER: + case CAIRO_OPERATOR_IN: + case CAIRO_OPERATOR_OUT: + case CAIRO_OPERATOR_ATOP: + case CAIRO_OPERATOR_DEST: + case CAIRO_OPERATOR_DEST_OVER: + case CAIRO_OPERATOR_DEST_IN: + case CAIRO_OPERATOR_DEST_OUT: + case CAIRO_OPERATOR_DEST_ATOP: + case CAIRO_OPERATOR_XOR: + case CAIRO_OPERATOR_ADD: + case CAIRO_OPERATOR_SATURATE: + return "Normal"; + } +} + +static void +_cairo_pdf_surface_emit_group_resources (cairo_pdf_surface_t *surface, + cairo_pdf_group_resources_t *res, + cairo_bool_t gs0) +{ + int num_alphas, num_smasks, num_resources, i; + double alpha; + cairo_pdf_resource_t *smask, *pattern, *shading, *xobject; + cairo_pdf_font_t *font; + + _cairo_output_stream_printf (surface->output, "<<\n"); + + num_alphas = _cairo_array_num_elements (&res->alphas); + num_smasks = _cairo_array_num_elements (&res->smasks); + if (num_alphas > 0 || num_smasks > 0) { + _cairo_output_stream_printf (surface->output, + " /ExtGState <<\n"); + + if (gs0) { + _cairo_output_stream_printf (surface->output, + " /gs0 << /BM /Normal /SMask /None /CA 1.0 /ca 1.0 >>\n"); + } + + for (i = 0; i < CAIRO_NUM_OPERATORS; i++) { + if (res->operators[i]) { + _cairo_output_stream_printf (surface->output, + " /b%d << /BM /%s >>\n", + i, _cairo_operator_to_pdf_blend_mode(i)); + } + } + + for (i = 0; i < num_alphas; i++) { + _cairo_array_copy_element (&res->alphas, i, &alpha); + _cairo_output_stream_printf (surface->output, + " /a%d << /CA %f /ca %f >>\n", + i, alpha, alpha); + } + + for (i = 0; i < num_smasks; i++) { + smask = _cairo_array_index (&res->smasks, i); + _cairo_output_stream_printf (surface->output, + " /s%d %d 0 R\n", + smask->id, smask->id); + } + + _cairo_output_stream_printf (surface->output, + " >>\n"); + } + + num_resources = _cairo_array_num_elements (&res->patterns); + if (num_resources > 0) { + _cairo_output_stream_printf (surface->output, + " /Pattern <<"); + for (i = 0; i < num_resources; i++) { + pattern = _cairo_array_index (&res->patterns, i); + _cairo_output_stream_printf (surface->output, + " /p%d %d 0 R", + pattern->id, pattern->id); + } + + _cairo_output_stream_printf (surface->output, + " >>\n"); + } + + num_resources = _cairo_array_num_elements (&res->shadings); + if (num_resources > 0) { + _cairo_output_stream_printf (surface->output, + " /Shading <<"); + for (i = 0; i < num_resources; i++) { + shading = _cairo_array_index (&res->shadings, i); + _cairo_output_stream_printf (surface->output, + " /sh%d %d 0 R", + shading->id, shading->id); + } + + _cairo_output_stream_printf (surface->output, + " >>\n"); + } + + num_resources = _cairo_array_num_elements (&res->xobjects); + if (num_resources > 0) { + _cairo_output_stream_printf (surface->output, + " /XObject <<"); + + for (i = 0; i < num_resources; i++) { + xobject = _cairo_array_index (&res->xobjects, i); + _cairo_output_stream_printf (surface->output, + " /x%d %d 0 R", + xobject->id, xobject->id); + } + + _cairo_output_stream_printf (surface->output, + " >>\n"); + } + + num_resources = _cairo_array_num_elements (&res->fonts); + if (num_resources > 0) { + _cairo_output_stream_printf (surface->output," /Font <<\n"); + for (i = 0; i < num_resources; i++) { + font = _cairo_array_index (&res->fonts, i); + _cairo_output_stream_printf (surface->output, + " /f-%d-%d %d 0 R\n", + font->font_id, + font->subset_id, + font->subset_resource.id); + } + _cairo_output_stream_printf (surface->output, " >>\n"); + } + + _cairo_output_stream_printf (surface->output, + ">>\n"); +} + +static cairo_pdf_smask_group_t * +_cairo_pdf_surface_create_smask_group (cairo_pdf_surface_t *surface, + const cairo_rectangle_int_t *extents) +{ + cairo_pdf_smask_group_t *group; + + group = _cairo_calloc (sizeof (cairo_pdf_smask_group_t)); + if (unlikely (group == NULL)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return NULL; + } + + group->group_res = _cairo_pdf_surface_new_object (surface); + if (group->group_res.id == 0) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + free (group); + return NULL; + } + group->width = surface->width; + group->height = surface->height; + if (extents != NULL) { + group->extents = *extents; + } else { + group->extents.x = 0; + group->extents.y = 0; + group->extents.width = surface->width; + group->extents.height = surface->height; + } + + return group; +} + +static void +_cairo_pdf_smask_group_destroy (cairo_pdf_smask_group_t *group) +{ + if (group->operation == PDF_FILL || group->operation == PDF_STROKE) + _cairo_path_fixed_fini (&group->path); + if (group->source) + cairo_pattern_destroy (group->source); + if (group->mask) + cairo_pattern_destroy (group->mask); + free (group->utf8); + free (group->glyphs); + free (group->clusters); + if (group->scaled_font) + cairo_scaled_font_destroy (group->scaled_font); + free (group); +} + +static cairo_int_status_t +_cairo_pdf_surface_add_smask_group (cairo_pdf_surface_t *surface, + cairo_pdf_smask_group_t *group) +{ + return _cairo_array_append (&surface->smask_groups, &group); +} + +static cairo_bool_t +_cairo_pdf_source_surface_equal (const void *key_a, const void *key_b) +{ + const cairo_pdf_source_surface_entry_t *a = key_a; + const cairo_pdf_source_surface_entry_t *b = key_b; + + if (a->interpolate != b->interpolate) + return FALSE; + + if (a->region_id != b->region_id) + return FALSE; + + if (a->unique_id && b->unique_id && a->unique_id_length == b->unique_id_length) + return (memcmp (a->unique_id, b->unique_id, a->unique_id_length) == 0); + + return (a->id == b->id); +} + +static void +_cairo_pdf_source_surface_init_key (cairo_pdf_source_surface_entry_t *key) +{ + if (key->unique_id && key->unique_id_length > 0) { + key->base.hash = _cairo_hash_bytes (_CAIRO_HASH_INIT_VALUE, + key->unique_id, key->unique_id_length); + } else { + key->base.hash = key->id; + } + key->base.hash = _cairo_hash_bytes (key->base.hash, + &key->region_id, + sizeof(key->region_id)); +} + +static cairo_bool_t +_cairo_pdf_color_glyph_equal (const void *key_a, const void *key_b) +{ + const cairo_pdf_color_glyph_t *a = key_a; + const cairo_pdf_color_glyph_t *b = key_b; + + if (a->scaled_font != b->scaled_font) + return FALSE; + + return (a->glyph_index == b->glyph_index); +} + +static void +_cairo_pdf_color_glyph_init_key (cairo_pdf_color_glyph_t *key) +{ + key->base.hash = _cairo_hash_uintptr (_CAIRO_HASH_INIT_VALUE, (uintptr_t)key->scaled_font); + key->base.hash = _cairo_hash_uintptr (key->base.hash, key->glyph_index); +} + +static cairo_int_status_t +_cairo_pdf_surface_acquire_source_image_from_pattern (cairo_pdf_surface_t *surface, + const cairo_pattern_t *pattern, + cairo_image_surface_t **image, + void **image_extra) +{ + switch (pattern->type) { + case CAIRO_PATTERN_TYPE_SURFACE: { + cairo_surface_pattern_t *surf_pat = (cairo_surface_pattern_t *) pattern; + return _cairo_surface_acquire_source_image (surf_pat->surface, image, image_extra); + } break; + + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: { + cairo_surface_t *surf; + surf = _cairo_raster_source_pattern_acquire (pattern, &surface->base, NULL); + if (!surf) + return CAIRO_INT_STATUS_UNSUPPORTED; + assert (_cairo_surface_is_image (surf)); + *image = (cairo_image_surface_t *) surf; + } break; + + case CAIRO_PATTERN_TYPE_SOLID: + case CAIRO_PATTERN_TYPE_LINEAR: + case CAIRO_PATTERN_TYPE_RADIAL: + case CAIRO_PATTERN_TYPE_MESH: + default: + ASSERT_NOT_REACHED; + break; + } + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_pdf_surface_release_source_image_from_pattern (cairo_pdf_surface_t *surface, + const cairo_pattern_t *pattern, + cairo_image_surface_t *image, + void *image_extra) +{ + switch (pattern->type) { + case CAIRO_PATTERN_TYPE_SURFACE: { + cairo_surface_pattern_t *surf_pat = (cairo_surface_pattern_t *) pattern; + _cairo_surface_release_source_image (surf_pat->surface, image, image_extra); + } break; + + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + _cairo_raster_source_pattern_release (pattern, &image->base); + break; + + case CAIRO_PATTERN_TYPE_SOLID: + case CAIRO_PATTERN_TYPE_LINEAR: + case CAIRO_PATTERN_TYPE_RADIAL: + case CAIRO_PATTERN_TYPE_MESH: + default: + + ASSERT_NOT_REACHED; + break; + } +} + +static cairo_int_status_t +_get_source_surface_extents (cairo_surface_t *source, + cairo_rectangle_int_t *extents, + cairo_bool_t *bounded, + cairo_bool_t *subsurface) +{ + cairo_int_status_t status; + + *bounded = TRUE; + *subsurface = FALSE; + if (source->type == CAIRO_SURFACE_TYPE_RECORDING) { + cairo_surface_t *free_me = NULL; + + if (_cairo_surface_is_snapshot (source)) + free_me = source = _cairo_surface_snapshot_get_target (source); + + if (source->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) { + cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source; + + *extents = sub->extents; + *subsurface = TRUE; + } else { + cairo_box_t box; + + *bounded = _cairo_surface_get_extents (source, extents); + if (! *bounded) { + status = _cairo_recording_surface_get_ink_bbox ((cairo_recording_surface_t *)source, + &box, NULL); + if (unlikely (status)) { + cairo_surface_destroy (free_me); + return status; + } + _cairo_box_round_to_rectangle (&box, extents); + } + } + cairo_surface_destroy (free_me); + } else { + *bounded = _cairo_surface_get_extents (source, extents); + } + + return CAIRO_STATUS_SUCCESS; +} + +/** + * _cairo_pdf_surface_add_source_surface: + * @surface: [in] the pdf surface + * @source_surface: [in] A #cairo_surface_t to use as the source surface + * @source_pattern: [in] A #cairo_pattern_t of type SURFACE or RASTER_SOURCE to use as the source + * @region_id: [in] Surfaces containing tags set this to the recording + * surface region id. When tags are used in a XObject, PDF requires a + * separate object for each use (section 14.7.4.2) @region_id is used + * as a key to ensure a separate object is emitted for each use. Set + * to 0 for surfaces without tags. + * @op: [in] the operator used to composite this source + * @filter: [in] filter type of the source pattern + * @stencil_mask: [in] if true, the surface will be written to the PDF as an /ImageMask + * @smask: [in] if true, only the alpha channel will be written (images only) + * @need_transp_group: [in] if true and an XObject is used, make it a Transparency group + * @extents: [in] extents of the operation that is using this source + * @smask_res: [in] if not NULL, the image written will specify this resource as the smask for + * the image (images only) + * @pdf_source: [out] return pdf_source_surface entry in hash table + * @x_offset: [out] if not NULL return x offset of surface + * @y_offset: [out] if not NULL return y offset of surface + * @source_extents: [out] if not NULL return operation extents in source space + * + * Add surface or raster_source pattern to list of surfaces to be + * written to the PDF file when the current page is finished. Returns + * a PDF resource to reference the surface. A hash table of all + * surfaces in the PDF file (keyed by CAIRO_MIME_TYPE_UNIQUE_ID or + * surface unique_id) is used to ensure surfaces with the same id are + * only written once to the PDF file. + * + * Only one of @source_pattern or @source_surface is to be + * specified. Set the other to NULL. + **/ +static cairo_int_status_t +_cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface, + cairo_surface_t *source_surface, + const cairo_pattern_t *source_pattern, + int region_id, + cairo_operator_t op, + cairo_filter_t filter, + cairo_bool_t stencil_mask, + cairo_bool_t smask, + cairo_bool_t need_transp_group, + const cairo_rectangle_int_t *extents, + cairo_pdf_resource_t *smask_res, + cairo_pdf_source_surface_entry_t **pdf_source, + double *x_offset, + double *y_offset, + cairo_rectangle_int_t *source_extents) +{ + cairo_pdf_source_surface_t src_surface; + cairo_pdf_source_surface_entry_t surface_key; + cairo_pdf_source_surface_entry_t *surface_entry; + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + cairo_bool_t interpolate; + unsigned char *unique_id = NULL; + unsigned long unique_id_length = 0; + cairo_image_surface_t *image; + void *image_extra; + cairo_box_t box; + cairo_rectangle_int_t op_extents; + double x, y; + cairo_bool_t subsurface; + cairo_bool_t emit_image; + + switch (filter) { + default: + case CAIRO_FILTER_GOOD: + case CAIRO_FILTER_BEST: + case CAIRO_FILTER_BILINEAR: + interpolate = TRUE; + break; + case CAIRO_FILTER_FAST: + case CAIRO_FILTER_NEAREST: + case CAIRO_FILTER_GAUSSIAN: + interpolate = FALSE; + break; + } + + x = 0; + y = 0; + if (source_pattern) { + if (source_pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) { + status = _cairo_pdf_surface_acquire_source_image_from_pattern (surface, source_pattern, + &image, &image_extra); + if (unlikely (status)) + return status; + source_surface = &image->base; + cairo_surface_get_device_offset (source_surface, &x, &y); + } else { + cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source_pattern; + source_surface = surface_pattern->surface; + } + } + if (x_offset) + *x_offset = x; + if (y_offset) + *y_offset = y; + + /* transform operation extents to pattern space */ + op_extents = *extents; + if (source_pattern) + { + _cairo_box_from_rectangle (&box, extents); + _cairo_matrix_transform_bounding_box_fixed (&source_pattern->matrix, &box, NULL); + _cairo_box_round_to_rectangle (&box, &op_extents); + } + if (source_extents) + *source_extents = op_extents; + + surface_key.id = source_surface->unique_id; + + /* Recording surfaces do not use interpolate. Ensure it is always + * false for recording surfaces. This is because pdf-interchange + * needs to lookup recording surfaces in the hash table using + * interpolate = FALSE in the key since it does not know the + * interpolate value passed to this function. + */ + emit_image = source_surface->type != CAIRO_SURFACE_TYPE_RECORDING; + surface_key.interpolate = emit_image ? interpolate : FALSE; + + cairo_surface_get_mime_data (source_surface, CAIRO_MIME_TYPE_UNIQUE_ID, + (const unsigned char **) &surface_key.unique_id, + &surface_key.unique_id_length); + + surface_key.region_id = region_id; + _cairo_pdf_source_surface_init_key (&surface_key); + surface_entry = _cairo_hash_table_lookup (surface->all_surfaces, &surface_key.base); + if (surface_entry) { + if (pdf_source) + *pdf_source = surface_entry; + + if (source_pattern && source_pattern->extend != CAIRO_EXTEND_NONE) + _cairo_unbounded_rectangle_init (&op_extents); + + _cairo_rectangle_intersect (&op_extents, &surface_entry->extents); + _cairo_rectangle_union (&surface_entry->required_extents, &op_extents); + status = CAIRO_STATUS_SUCCESS; + } + + if (status || surface_entry) { + if (source_pattern && source_pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) + _cairo_pdf_surface_release_source_image_from_pattern (surface, source_pattern, image, image_extra); + return status; + } + + if (surface_key.unique_id && surface_key.unique_id_length > 0) { + unique_id = _cairo_malloc (surface_key.unique_id_length); + if (unique_id == NULL) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto fail1; + } + + unique_id_length = surface_key.unique_id_length; + memcpy (unique_id, surface_key.unique_id, unique_id_length); + } else { + unique_id = NULL; + unique_id_length = 0; + } + + surface_entry = _cairo_calloc (sizeof (cairo_pdf_source_surface_entry_t)); + if (surface_entry == NULL) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto fail1; + } + + if (pdf_source) + *pdf_source = surface_entry; + + surface_entry->id = surface_key.id; + surface_entry->region_id = region_id; + surface_entry->operator = op; + surface_entry->interpolate = emit_image ? interpolate : FALSE; + surface_entry->emit_image = emit_image; + surface_entry->stencil_mask = stencil_mask; + surface_entry->smask = smask; + surface_entry->need_transp_group = need_transp_group; + surface_entry->unique_id_length = unique_id_length; + surface_entry->unique_id = unique_id; + if (smask_res) + surface_entry->smask_res = *smask_res; + else + surface_entry->smask_res.id = 0; + + status = _get_source_surface_extents (source_surface, + &surface_entry->extents, + &surface_entry->bounded, + &subsurface); + if (unlikely (status)) + goto fail2; + + if (subsurface) { + *x_offset = -surface_entry->extents.x; + *y_offset = -surface_entry->extents.y; + } + + if (source_pattern && source_pattern->extend != CAIRO_EXTEND_NONE) + _cairo_unbounded_rectangle_init (&op_extents); + + _cairo_rectangle_intersect (&op_extents, &surface_entry->extents); + surface_entry->required_extents = op_extents; + + _cairo_pdf_source_surface_init_key (surface_entry); + + src_surface.hash_entry = surface_entry; + src_surface.region_id = 0; + if (source_pattern && source_pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) { + src_surface.type = CAIRO_PATTERN_TYPE_RASTER_SOURCE; + src_surface.surface = NULL; + status = _cairo_pattern_create_copy (&src_surface.raster_pattern, source_pattern); + if (unlikely (status)) + goto fail2; + + } else { + src_surface.type = CAIRO_PATTERN_TYPE_SURFACE; + src_surface.surface = cairo_surface_reference (source_surface); + src_surface.raster_pattern = NULL; + if (source_pattern) { + cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source_pattern; + src_surface.region_id = surface_pattern->region_array_id; + if (_cairo_surface_is_recording (surface_pattern->surface) && + surface_pattern->region_array_id != 0) + { + _cairo_recording_surface_region_array_reference (surface_pattern->surface, + surface_pattern->region_array_id); + } + } + } + + surface_entry->surface_res = _cairo_pdf_surface_new_object (surface); + if (surface_entry->surface_res.id == 0) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto fail3; + } + + if (surface_entry->bounded) { + status = _cairo_array_append (&surface->page_surfaces, &src_surface); + if (unlikely (status)) + goto fail3; + } else { + status = _cairo_array_append (&surface->doc_surfaces, &src_surface); + if (unlikely (status)) + goto fail3; + } + + status = _cairo_hash_table_insert (surface->all_surfaces, + &surface_entry->base); + if (unlikely(status)) + goto fail3; + + if (source_pattern && source_pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) + _cairo_pdf_surface_release_source_image_from_pattern (surface, source_pattern, image, image_extra); + + return CAIRO_STATUS_SUCCESS; + +fail3: + if (source_pattern && source_pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) + cairo_pattern_destroy (src_surface.raster_pattern); + else + cairo_surface_destroy (src_surface.surface); + +fail2: + free (surface_entry); + +fail1: + if (unique_id) + free (unique_id); + + if (source_pattern && source_pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) + _cairo_pdf_surface_release_source_image_from_pattern (surface, source_pattern, image, image_extra); + + return status; +} + +static cairo_int_status_t +_cairo_pdf_surface_add_pdf_pattern_or_shading (cairo_pdf_surface_t *surface, + const cairo_pattern_t *pattern, + cairo_operator_t op, + cairo_analysis_source_t source_type, + const cairo_rectangle_int_t *extents, + cairo_bool_t is_shading, + cairo_pdf_resource_t *pattern_res, + cairo_pdf_resource_t *gstate_res) +{ + cairo_pdf_pattern_t pdf_pattern; + cairo_int_status_t status; + int region_id = 0; + + pdf_pattern.is_shading = is_shading; + pdf_pattern.operator = op; + + /* Solid colors are emitted into the content stream */ + if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) { + pattern_res->id = 0; + gstate_res->id = 0; + return CAIRO_INT_STATUS_SUCCESS; + } + + status = _cairo_pattern_create_copy (&pdf_pattern.pattern, pattern); + if (unlikely (status)) + return status; + + pdf_pattern.pattern_res = _cairo_pdf_surface_new_object (surface); + if (pdf_pattern.pattern_res.id == 0) { + cairo_pattern_destroy (pdf_pattern.pattern); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + pdf_pattern.gstate_res.id = 0; + + /* gradient patterns require an smask object to implement transparency */ + if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR || + pattern->type == CAIRO_PATTERN_TYPE_RADIAL || + pattern->type == CAIRO_PATTERN_TYPE_MESH) + { + double min_alpha; + + _cairo_pattern_alpha_range (pattern, &min_alpha, NULL); + if (! CAIRO_ALPHA_IS_OPAQUE (min_alpha)) { + pdf_pattern.gstate_res = _cairo_pdf_surface_new_object (surface); + if (pdf_pattern.gstate_res.id == 0) { + cairo_pattern_destroy (pdf_pattern.pattern); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + } + } + + pdf_pattern.width = surface->width; + pdf_pattern.height = surface->height; + if (extents != NULL) { + pdf_pattern.extents = *extents; + } else { + pdf_pattern.extents.x = 0; + pdf_pattern.extents.y = 0; + pdf_pattern.extents.width = surface->width; + pdf_pattern.extents.height = surface->height; + } + + *pattern_res = pdf_pattern.pattern_res; + *gstate_res = pdf_pattern.gstate_res; + /* If the pattern requires a gstate it will be drawn from within + * an XObject. The initial space of each XObject has an inverted + * Y-axis. */ + pdf_pattern.inverted_y_axis = pdf_pattern.gstate_res.id ? TRUE : surface->in_xobject; + + if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { + cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern; + if (_cairo_pdf_interchange_struct_tree_requires_recording_surface (surface, + surface_pattern, + source_type)) + { + region_id = surface_pattern->region_array_id; + } + } + pdf_pattern.region_id = region_id; + + status = _cairo_array_append (&surface->page_patterns, &pdf_pattern); + if (unlikely (status)) { + cairo_pattern_destroy (pdf_pattern.pattern); + return status; + } + + return CAIRO_INT_STATUS_SUCCESS; +} + +/* Get BBox from extents */ +static void +_get_bbox_from_extents (const cairo_rectangle_int_t *extents, + cairo_box_double_t *bbox) +{ + bbox->p1.x = extents->x; + bbox->p1.y = extents->y; + bbox->p2.x = extents->x + extents->width; + bbox->p2.y = extents->y + extents->height; +} + +static cairo_int_status_t +_cairo_pdf_surface_add_pdf_shading (cairo_pdf_surface_t *surface, + const cairo_pattern_t *pattern, + cairo_operator_t op, + const cairo_rectangle_int_t *extents, + cairo_pdf_resource_t *shading_res, + cairo_pdf_resource_t *gstate_res) +{ + return _cairo_pdf_surface_add_pdf_pattern_or_shading (surface, + pattern, + op, + CAIRO_ANALYSIS_SOURCE_NONE, + extents, + TRUE, + shading_res, + gstate_res); +} + +static cairo_int_status_t +_cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface, + const cairo_pattern_t *pattern, + cairo_operator_t op, + cairo_analysis_source_t source_type, + const cairo_rectangle_int_t *extents, + cairo_pdf_resource_t *pattern_res, + cairo_pdf_resource_t *gstate_res) +{ + return _cairo_pdf_surface_add_pdf_pattern_or_shading (surface, + pattern, + op, + source_type, + extents, + FALSE, + pattern_res, + gstate_res); +} + +static cairo_int_status_t +_cairo_pdf_surface_open_stream (cairo_pdf_surface_t *surface, + cairo_pdf_resource_t *resource, + cairo_bool_t compressed, + const char *fmt, + ...) +{ + va_list ap; + cairo_pdf_resource_t self, length; + cairo_output_stream_t *output = NULL; + + if (resource) { + self = *resource; + _cairo_pdf_surface_update_object (surface, self); + } else { + self = _cairo_pdf_surface_new_object (surface); + if (self.id == 0) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + length = _cairo_pdf_surface_new_object (surface); + if (length.id == 0) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + if (compressed) { + output = _cairo_deflate_stream_create (surface->output); + if (_cairo_output_stream_get_status (output)) + return _cairo_output_stream_destroy (output); + } + + surface->pdf_stream.active = TRUE; + surface->pdf_stream.self = self; + surface->pdf_stream.length = length; + surface->pdf_stream.compressed = compressed; + surface->current_pattern_is_solid_color = FALSE; + surface->current_operator = CAIRO_OPERATOR_OVER; + _cairo_pdf_operators_reset (&surface->pdf_operators); + + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n" + "<< /Length %d 0 R\n", + surface->pdf_stream.self.id, + surface->pdf_stream.length.id); + if (compressed) + _cairo_output_stream_printf (surface->output, + " /Filter /FlateDecode\n"); + + if (fmt != NULL) { + va_start (ap, fmt); + _cairo_output_stream_vprintf (surface->output, fmt, ap); + va_end (ap); + } + + _cairo_output_stream_printf (surface->output, + ">>\n" + "stream\n"); + + surface->pdf_stream.start_offset = _cairo_output_stream_get_position (surface->output); + + if (compressed) { + assert (surface->pdf_stream.old_output == NULL); + surface->pdf_stream.old_output = surface->output; + surface->output = output; + _cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output); + } + _cairo_pdf_operators_reset (&surface->pdf_operators); + + return _cairo_output_stream_get_status (surface->output); +} + +static cairo_int_status_t +_cairo_pdf_surface_close_stream (cairo_pdf_surface_t *surface) +{ + cairo_int_status_t status; + long long length; + + if (! surface->pdf_stream.active) + return CAIRO_INT_STATUS_SUCCESS; + + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + + if (surface->pdf_stream.compressed) { + cairo_int_status_t status2; + + status2 = _cairo_output_stream_destroy (surface->output); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) + status = status2; + + surface->output = surface->pdf_stream.old_output; + _cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output); + surface->pdf_stream.old_output = NULL; + } + + length = _cairo_output_stream_get_position (surface->output) - + surface->pdf_stream.start_offset; + _cairo_output_stream_printf (surface->output, + "\n" + "endstream\n" + "endobj\n"); + + _cairo_pdf_surface_update_object (surface, + surface->pdf_stream.length); + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n" + " %lld\n" + "endobj\n", + surface->pdf_stream.length.id, + length); + + surface->pdf_stream.active = FALSE; + + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) + status = _cairo_output_stream_get_status (surface->output); + + return status; +} + +static void +_cairo_pdf_surface_write_memory_stream (cairo_pdf_surface_t *surface, + cairo_output_stream_t *mem_stream, + cairo_pdf_resource_t resource, + cairo_pdf_group_resources_t *resources, + cairo_bool_t is_knockout_group, + const cairo_box_double_t *bbox) +{ + _cairo_pdf_surface_update_object (surface, resource); + + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n" + "<< /Type /XObject\n" + " /Length %d\n", + resource.id, + _cairo_memory_stream_length (mem_stream)); + + if (surface->compress_streams) { + _cairo_output_stream_printf (surface->output, + " /Filter /FlateDecode\n"); + } + + _cairo_output_stream_printf (surface->output, + " /Subtype /Form\n" + " /BBox [ %f %f %f %f ]\n" + " /Group <<\n" + " /Type /Group\n" + " /S /Transparency\n" + " /I true\n" + " /CS /DeviceRGB\n", + bbox->p1.x, bbox->p1.y, bbox->p2.x, bbox->p2.y); + + if (is_knockout_group) + _cairo_output_stream_printf (surface->output, + " /K true\n"); + + _cairo_output_stream_printf (surface->output, + " >>\n" + " /Resources\n"); + _cairo_pdf_surface_emit_group_resources (surface, resources, TRUE); + _cairo_output_stream_printf (surface->output, + ">>\n" + "stream\n"); + _cairo_memory_stream_copy (mem_stream, surface->output); + _cairo_output_stream_printf (surface->output, + "endstream\n" + "endobj\n"); +} + +static cairo_int_status_t +_cairo_pdf_surface_open_group (cairo_pdf_surface_t *surface, + const cairo_box_double_t *bbox, + cairo_pdf_resource_t *resource) +{ + cairo_int_status_t status; + + assert (surface->pdf_stream.active == FALSE); + assert (surface->group_stream.active == FALSE); + + surface->group_stream.active = TRUE; + + surface->group_stream.mem_stream = _cairo_memory_stream_create (); + + if (surface->compress_streams) { + surface->group_stream.stream = + _cairo_deflate_stream_create (surface->group_stream.mem_stream); + } else { + surface->group_stream.stream = surface->group_stream.mem_stream; + } + status = _cairo_output_stream_get_status (surface->group_stream.stream); + + surface->group_stream.old_output = surface->output; + surface->output = surface->group_stream.stream; + _cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output); + _cairo_pdf_group_resources_clear (&surface->resources); + + if (resource) { + surface->group_stream.resource = *resource; + } else { + surface->group_stream.resource = _cairo_pdf_surface_new_object (surface); + if (surface->group_stream.resource.id == 0) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + surface->group_stream.is_knockout = FALSE; + surface->group_stream.bbox = *bbox; + + /* Reset gstate */ + surface->reset_gs_required = TRUE; + surface->current_pattern_is_solid_color = FALSE; + surface->current_operator = CAIRO_OPERATOR_OVER; + _cairo_pdf_operators_reset (&surface->pdf_operators); + + return status; +} + +static cairo_int_status_t +_cairo_pdf_surface_open_knockout_group (cairo_pdf_surface_t *surface, + const cairo_box_double_t *bbox) +{ + cairo_int_status_t status; + + status = _cairo_pdf_surface_open_group (surface, bbox, NULL); + if (unlikely (status)) + return status; + + surface->group_stream.is_knockout = TRUE; + + return CAIRO_INT_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_pdf_surface_close_group (cairo_pdf_surface_t *surface, + cairo_pdf_resource_t *group) +{ + cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS, status2; + + assert (surface->pdf_stream.active == FALSE); + assert (surface->group_stream.active == TRUE); + + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (unlikely (status)) + return status; + + if (surface->compress_streams) { + status = _cairo_output_stream_destroy (surface->group_stream.stream); + surface->group_stream.stream = NULL; + + _cairo_output_stream_printf (surface->group_stream.mem_stream, + "\n"); + } + surface->output = surface->group_stream.old_output; + _cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->output); + surface->group_stream.active = FALSE; + _cairo_pdf_surface_write_memory_stream (surface, + surface->group_stream.mem_stream, + surface->group_stream.resource, + &surface->resources, + surface->group_stream.is_knockout, + &surface->group_stream.bbox); + if (group) + *group = surface->group_stream.resource; + + status2 = _cairo_output_stream_destroy (surface->group_stream.mem_stream); + if (status == CAIRO_INT_STATUS_SUCCESS) + status = status2; + + surface->group_stream.mem_stream = NULL; + surface->group_stream.stream = NULL; + surface->reset_gs_required = FALSE; + + return status; +} + +static cairo_int_status_t +_cairo_pdf_surface_open_object_stream (cairo_pdf_surface_t *surface) +{ + if (surface->debug || surface->pdf_version < CAIRO_PDF_VERSION_1_5) { + /* Object streams not supported. All objects will be written + * directly to the file. */ + assert (surface->pdf_stream.active == FALSE); + assert (surface->group_stream.active == FALSE); + surface->object_stream.stream = surface->output; + } else { + surface->object_stream.resource = _cairo_pdf_surface_new_object (surface); + if (surface->object_stream.resource.id == 0) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + _cairo_array_truncate (&surface->object_stream.objects, 0); + surface->object_stream.stream = _cairo_memory_stream_create (); + surface->object_stream.active = TRUE; + } + return _cairo_output_stream_get_status (surface->object_stream.stream); +} + +cairo_int_status_t +_cairo_pdf_surface_object_begin (cairo_pdf_surface_t *surface, + cairo_pdf_resource_t resource) +{ + cairo_xref_stream_object_t xref_obj; + cairo_pdf_object_t *object; + cairo_int_status_t status; + + if (surface->object_stream.active) { + xref_obj.resource = resource; + xref_obj.offset = _cairo_output_stream_get_position (surface->object_stream.stream); + status = _cairo_array_append (&surface->object_stream.objects, &xref_obj); + if (unlikely (status)) + return status; + + object = _cairo_array_index (&surface->objects, resource.id - 1); + object->type = PDF_OBJECT_COMPRESSED; + object->u.compressed_obj.xref_stream = surface->object_stream.resource; + object->u.compressed_obj.index = _cairo_array_num_elements (&surface->object_stream.objects) - 1; + + } else { + _cairo_pdf_surface_update_object (surface, resource); + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n", + resource.id); + } + return CAIRO_INT_STATUS_SUCCESS; +} + +void +_cairo_pdf_surface_object_end (cairo_pdf_surface_t *surface) +{ + if (!surface->object_stream.active) { + _cairo_output_stream_printf (surface->output, + "endobj\n"); + } +} + +static int +_cairo_xref_stream_object_compare (const void *a, + const void *b) +{ + const cairo_xref_stream_object_t *a_obj = a; + const cairo_xref_stream_object_t *b_obj = b; + + if (a_obj->offset < b_obj->offset) + return -1; + else if (a_obj->offset > b_obj->offset) + return 1; + else + return 0; +} + +static cairo_int_status_t +_cairo_pdf_surface_close_object_stream (cairo_pdf_surface_t *surface) +{ + int i, num_objects; + cairo_xref_stream_object_t *xref_obj; + long long start_pos, length; + cairo_output_stream_t *index_stream; + cairo_output_stream_t *deflate_stream; + cairo_pdf_resource_t length_res; + cairo_int_status_t status; + cairo_pdf_object_t *object; + + if (!surface->object_stream.active) { + surface->object_stream.stream = NULL; + return CAIRO_INT_STATUS_SUCCESS; + } + + num_objects = _cairo_array_num_elements (&surface->object_stream.objects); + if (num_objects == 0) { + object = _cairo_array_index (&surface->objects, surface->object_stream.resource.id - 1); + object->type = PDF_OBJECT_FREE; + return CAIRO_INT_STATUS_SUCCESS; + } + + index_stream = _cairo_memory_stream_create (); + /* PDF requires the object id/offset pairs to be sorted by offset. */ + _cairo_array_sort (&surface->object_stream.objects, _cairo_xref_stream_object_compare); + for (i = 0; i < num_objects; i++) { + xref_obj = _cairo_array_index (&surface->object_stream.objects, i); + _cairo_output_stream_printf (index_stream, + "%d %lld\n", + xref_obj->resource.id, + xref_obj->offset); + } + + length_res = _cairo_pdf_surface_new_object (surface); + if (length_res.id == 0) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + _cairo_pdf_surface_update_object (surface, surface->object_stream.resource); + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n" + "<< /Type /ObjStm\n" + " /Length %d 0 R\n" + " /N %d\n" + " /First %d\n", + surface->object_stream.resource.id, + length_res.id, + num_objects, + _cairo_memory_stream_length (index_stream)); + + if (surface->compress_streams) { + _cairo_output_stream_printf (surface->output, + " /Filter /FlateDecode\n"); + } + + _cairo_output_stream_printf (surface->output, + ">>\n" + "stream\n"); + + start_pos = _cairo_output_stream_get_position (surface->output); + if (surface->compress_streams) { + deflate_stream = _cairo_deflate_stream_create (surface->output); + _cairo_memory_stream_copy (index_stream, deflate_stream); + _cairo_memory_stream_copy (surface->object_stream.stream, deflate_stream); + status = _cairo_output_stream_destroy (deflate_stream); + if (unlikely (status)) + return status; + + length = _cairo_output_stream_get_position (surface->output) - start_pos; + } else { + _cairo_memory_stream_copy (index_stream, surface->output); + _cairo_memory_stream_copy (surface->object_stream.stream, surface->output); + length = _cairo_output_stream_get_position (surface->output) - start_pos; + } + + _cairo_output_stream_printf (surface->output, + "\n" + "endstream\n" + "endobj\n"); + + _cairo_pdf_surface_update_object (surface, + length_res); + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n" + " %lld\n" + "endobj\n", + length_res.id, + length); + + status = _cairo_output_stream_destroy (index_stream); + if (unlikely (status)) + return status; + + status = _cairo_output_stream_destroy (surface->object_stream.stream); + if (unlikely (status)) + return status; + + surface->object_stream.stream = NULL; + surface->object_stream.active = FALSE; + + return _cairo_output_stream_get_status (surface->output); +} + +static cairo_int_status_t +_cairo_pdf_surface_open_content_stream (cairo_pdf_surface_t *surface, + const cairo_box_double_t *bbox, + cairo_pdf_resource_t *resource, + cairo_bool_t is_form, + cairo_bool_t is_group, + int struct_parents) +{ + cairo_int_status_t status; + + assert (surface->pdf_stream.active == FALSE); + assert (surface->group_stream.active == FALSE); + + surface->content_resources = _cairo_pdf_surface_new_object (surface); + if (surface->content_resources.id == 0) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + if (is_form) { + assert (bbox != NULL); + + cairo_output_stream_t *mem_stream = _cairo_memory_stream_create (); + if (is_group) { + _cairo_output_stream_printf (mem_stream, + " /Type /XObject\n" + " /Subtype /Form\n" + " /BBox [ %f %f %f %f ]\n" + " /Group <<\n" + " /Type /Group\n" + " /S /Transparency\n" + " /I true\n" + " /CS /DeviceRGB\n" + " >>\n" + " /Resources %d 0 R\n", + bbox->p1.x, + bbox->p1.y, + bbox->p2.x, + bbox->p2.y, + surface->content_resources.id); + } else { + _cairo_output_stream_printf (mem_stream, + " /Type /XObject\n" + " /Subtype /Form\n" + " /BBox [ %f %f %f %f ]\n" + " /Resources %d 0 R\n", + bbox->p1.x, + bbox->p1.y, + bbox->p2.x, + bbox->p2.y, + surface->content_resources.id); + } + if (struct_parents >= 0) { + _cairo_output_stream_printf (mem_stream, + " /StructParents %d\n", struct_parents); + } + + unsigned char *data; + unsigned long length; + status = _cairo_memory_stream_destroy (mem_stream, &data, &length); + if (unlikely (status)) + return status; + + char *str = _cairo_strndup ((const char*)data, length); /* Add NULL terminator */ + + status = + _cairo_pdf_surface_open_stream (surface, + resource, + surface->compress_streams, + "%s", + str); + free (str); + free (data); + } else { + status = + _cairo_pdf_surface_open_stream (surface, + resource, + surface->compress_streams, + NULL); + _cairo_output_stream_printf (surface->output, + "1 0 0 -1 0 %f cm\n", + surface->height); + } + if (unlikely (status)) + return status; + + surface->content = surface->pdf_stream.self; + + _cairo_output_stream_printf (surface->output, "q\n"); + _cairo_pdf_operators_reset (&surface->pdf_operators); + + return _cairo_output_stream_get_status (surface->output); +} + +static cairo_int_status_t +_cairo_pdf_surface_close_content_stream (cairo_pdf_surface_t *surface, + cairo_bool_t is_form) +{ + cairo_int_status_t status; + + assert (surface->pdf_stream.active == TRUE); + assert (surface->group_stream.active == FALSE); + + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->output, "Q\n"); + status = _cairo_pdf_surface_close_stream (surface); + if (unlikely (status)) + return status; + + _cairo_pdf_surface_update_object (surface, surface->content_resources); + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n", + surface->content_resources.id); + _cairo_pdf_surface_emit_group_resources (surface, &surface->resources, is_form); + _cairo_output_stream_printf (surface->output, + "endobj\n"); + + return _cairo_output_stream_get_status (surface->output); +} + +static void +_cairo_pdf_source_surface_entry_pluck (void *entry, void *closure) +{ + cairo_pdf_source_surface_entry_t *surface_entry = entry; + cairo_hash_table_t *patterns = closure; + + _cairo_hash_table_remove (patterns, &surface_entry->base); + free (surface_entry->unique_id); + + free (surface_entry); +} + +static void +_cairo_pdf_color_glyph_pluck (void *entry, void *closure) +{ + cairo_pdf_color_glyph_t *glyph_entry = entry; + cairo_hash_table_t *patterns = closure; + + _cairo_hash_table_remove (patterns, &glyph_entry->base); + cairo_scaled_font_destroy (glyph_entry->scaled_font); + + free (glyph_entry); +} + +static cairo_int_status_t +_cairo_pdf_surface_write_page_dicts (cairo_pdf_surface_t *surface) +{ + cairo_int_status_t status; + cairo_pdf_page_info_t *page_info; + int num_annots; + cairo_pdf_resource_t res; + + for (unsigned i = 0; i < _cairo_array_num_elements (&surface->pages); i++) { + page_info = _cairo_array_index (&surface->pages, i); + + status = _cairo_pdf_surface_object_begin (surface, page_info->page_res); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->object_stream.stream, + "<< /Type /Page %% %d\n" + " /Parent %d 0 R\n" + " /MediaBox [ 0 0 %f %f ]\n" + " /Contents %d 0 R\n" + " /Group <<\n" + " /Type /Group\n" + " /S /Transparency\n" + " /I true\n" + " /CS /DeviceRGB\n" + " >>\n" + " /Resources %d 0 R\n", + i + 1, + surface->pages_resource.id, + page_info->width, + page_info->height, + page_info->content.id, + page_info->resources.id); + + if (page_info->struct_parents >= 0) { + _cairo_output_stream_printf (surface->object_stream.stream, + " /StructParents %d\n", + page_info->struct_parents); + } + + num_annots = _cairo_array_num_elements (&page_info->annots); + if (num_annots > 0) { + _cairo_output_stream_printf (surface->object_stream.stream, + " /Annots [ "); + for (int j = 0; j < num_annots; j++) { + _cairo_array_copy_element (&page_info->annots, j, &res); + _cairo_output_stream_printf (surface->object_stream.stream, + "%d 0 R ", + res.id); + } + _cairo_output_stream_printf (surface->object_stream.stream, "]\n"); + } + + if (page_info->thumbnail.id) { + _cairo_output_stream_printf (surface->object_stream.stream, + " /Thumb %d 0 R\n", + page_info->thumbnail.id); + } + + _cairo_output_stream_printf (surface->object_stream.stream, + ">>\n"); + _cairo_pdf_surface_object_end (surface); + } + + return status; +} + +static cairo_status_t +_cairo_pdf_surface_finish (void *abstract_surface) +{ + cairo_pdf_surface_t *surface = abstract_surface; + long long offset; + cairo_pdf_resource_t catalog; + cairo_status_t status = CAIRO_STATUS_SUCCESS, status2; + int size, i; + cairo_pdf_jbig2_global_t *global; + char *label; + cairo_pdf_resource_t xref_res; + + /* Some of the data may be in an inconistent state if there is an error status. */ + if (surface->base.status != CAIRO_STATUS_SUCCESS) + goto CLEANUP; + + _cairo_pdf_surface_clear (surface, FALSE); + + status = _cairo_pdf_surface_open_object_stream (surface); + if (unlikely (status)) + goto CLEANUP; + + /* Emit unbounded surfaces */ + status = _cairo_pdf_surface_write_patterns_and_smask_groups (surface, TRUE); + if (unlikely (status)) + goto CLEANUP; + + _cairo_pdf_surface_clear (surface, TRUE); + + status = _cairo_pdf_surface_emit_font_subsets (surface); + if (unlikely (status)) + goto CLEANUP; + + /* Emit any new patterns or surfaces created by the Type 3 font subset. */ + _cairo_pdf_surface_write_patterns_and_smask_groups (surface, TRUE); + + _cairo_pdf_surface_clear (surface, TRUE); + + status = _cairo_pdf_surface_write_pages (surface); + if (unlikely (status)) + goto CLEANUP; + + status = _cairo_pdf_interchange_write_document_objects (surface); + if (unlikely (status)) + goto CLEANUP; + + status = _cairo_pdf_surface_write_page_dicts (surface); + if (unlikely (status)) + goto CLEANUP; + + catalog = _cairo_pdf_surface_new_object (surface); + if (catalog.id == 0) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CLEANUP; + } + + status = _cairo_pdf_surface_write_catalog (surface, catalog); + if (unlikely (status)) + goto CLEANUP; + + status = _cairo_pdf_surface_close_object_stream (surface); + if (unlikely (status)) + goto CLEANUP; + + if (!surface->debug && surface->pdf_version >= CAIRO_PDF_VERSION_1_5) + { + xref_res = _cairo_pdf_surface_new_object (surface); + status = _cairo_pdf_surface_write_xref_stream (surface, + xref_res, + catalog, + surface->docinfo_res, + &offset); + } else { + offset = _cairo_pdf_surface_write_xref (surface); + _cairo_output_stream_printf (surface->output, + "trailer\n" + "<< /Size %d\n" + " /Root %d 0 R\n" + " /Info %d 0 R\n" + ">>\n", + surface->next_available_resource.id, + catalog.id, + surface->docinfo_res.id); + } + _cairo_output_stream_printf (surface->output, + "startxref\n" + "%lld\n" + "%%%%EOF\n", + offset); + + CLEANUP: + + /* pdf_operators has already been flushed when the last stream was + * closed so we should never be writing anything here - however, + * the stream may itself be in an error state. */ + status2 = _cairo_pdf_operators_fini (&surface->pdf_operators); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; + + /* close any active streams still open due to fatal errors */ + status2 = _cairo_pdf_surface_close_stream (surface); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; + + if (surface->group_stream.stream != NULL) { + status2 = _cairo_output_stream_destroy (surface->group_stream.stream); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; + } + if (surface->group_stream.mem_stream != NULL) { + status2 = _cairo_output_stream_destroy (surface->group_stream.mem_stream); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; + } + if (surface->pdf_stream.active) + surface->output = surface->pdf_stream.old_output; + if (surface->group_stream.active) + surface->output = surface->group_stream.old_output; + + /* and finish the pdf surface */ + status2 = _cairo_output_stream_destroy (surface->output); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; + + _cairo_pdf_group_resources_fini (&surface->resources); + + _cairo_array_fini (&surface->objects); + size = _cairo_array_num_elements (&surface->pages); + for (i = 0; i < size; i++) { + cairo_pdf_page_info_t *page_info = _cairo_array_index (&surface->pages, i); + _cairo_array_fini (&page_info->annots); + } + _cairo_array_fini (&surface->pages); + _cairo_array_fini (&surface->rgb_linear_functions); + _cairo_array_fini (&surface->alpha_linear_functions); + _cairo_array_fini (&surface->page_patterns); + _cairo_array_fini (&surface->page_surfaces); + _cairo_array_fini (&surface->object_stream.objects); + + _cairo_array_fini (&surface->doc_surfaces); + _cairo_hash_table_foreach (surface->all_surfaces, + _cairo_pdf_source_surface_entry_pluck, + surface->all_surfaces); + _cairo_hash_table_destroy (surface->all_surfaces); + _cairo_array_fini (&surface->smask_groups); + _cairo_array_fini (&surface->fonts); + _cairo_array_fini (&surface->knockout_group); + _cairo_array_fini (&surface->page_annots); + + _cairo_hash_table_foreach (surface->color_glyphs, + _cairo_pdf_color_glyph_pluck, + surface->color_glyphs); + _cairo_hash_table_destroy (surface->color_glyphs); + + if (surface->font_subsets) { + _cairo_scaled_font_subsets_destroy (surface->font_subsets); + surface->font_subsets = NULL; + } + + size = _cairo_array_num_elements (&surface->jbig2_global); + for (i = 0; i < size; i++) { + global = (cairo_pdf_jbig2_global_t *) _cairo_array_index (&surface->jbig2_global, i); + free(global->id); + if (!global->emitted) + return _cairo_error (CAIRO_STATUS_JBIG2_GLOBAL_MISSING); + } + _cairo_array_fini (&surface->jbig2_global); + + size = _cairo_array_num_elements (&surface->page_labels); + for (i = 0; i < size; i++) { + _cairo_array_copy_element (&surface->page_labels, i, &label); + free (label); + } + _cairo_array_fini (&surface->page_labels); + + _cairo_surface_clipper_reset (&surface->clipper); + + _cairo_pdf_interchange_fini (surface); + + return status; +} + +static cairo_int_status_t +_cairo_pdf_surface_start_page (void *abstract_surface) +{ + cairo_pdf_surface_t *surface = abstract_surface; + cairo_pdf_page_info_t page_info; + cairo_int_status_t status; + + /* Document header */ + if (! surface->header_emitted) { + const char *version; + + switch (surface->pdf_version) { + case CAIRO_PDF_VERSION_1_4: + version = "1.4"; + break; + case CAIRO_PDF_VERSION_1_5: + version = "1.5"; + break; + case CAIRO_PDF_VERSION_1_6: + version = "1.6"; + break; + default: + case CAIRO_PDF_VERSION_1_7: + version = "1.7"; + break; + } + + _cairo_output_stream_printf (surface->output, + "%%PDF-%s\n", version); + _cairo_output_stream_printf (surface->output, + "%%%c%c%c%c\n", 181, 237, 174, 251); + surface->header_emitted = TRUE; + } + + _cairo_pdf_group_resources_clear (&surface->resources); + surface->in_xobject = FALSE; + + page_info.page_res = _cairo_pdf_surface_new_object (surface); + if (page_info.page_res.id == 0) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + page_info.width = surface->width; + page_info.height = surface->height; + page_info.content.id = 0; + page_info.resources.id = 0; + page_info.thumbnail.id = 0; + page_info.struct_parents = -1; + _cairo_array_init (&page_info.annots, sizeof (cairo_pdf_resource_t)); + + status = _cairo_array_append (&surface->pages, &page_info); + if (unlikely (status)) + return status; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_pdf_surface_has_fallback_images (void *abstract_surface, + cairo_bool_t has_fallbacks) +{ + cairo_int_status_t status; + cairo_pdf_surface_t *surface = abstract_surface; + cairo_box_double_t bbox; + + status = _cairo_pdf_interchange_end_page_content (surface); + if (unlikely (status)) + return status; + + surface->has_fallback_images = has_fallbacks; + surface->in_xobject = has_fallbacks; + bbox.p1.x = 0; + bbox.p1.y = 0; + bbox.p2.x = surface->width; + bbox.p2.y = surface->height; + status = _cairo_pdf_surface_open_content_stream (surface, &bbox, NULL, has_fallbacks, has_fallbacks, -1); + if (unlikely (status)) + return status; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_bool_t +_cairo_pdf_surface_supports_fine_grained_fallbacks (void *abstract_surface) +{ + return TRUE; +} + +static cairo_bool_t +_cairo_pdf_surface_requires_thumbnail_image (void *abstract_surface, + int *width, + int *height) +{ + cairo_pdf_surface_t *surface = abstract_surface; + + if (surface->thumbnail_width > 0 && surface->thumbnail_height > 0) { + *width = surface->thumbnail_width; + *height = surface->thumbnail_height; + return TRUE; + } + + return FALSE; +} + +static cairo_int_status_t +_cairo_pdf_surface_set_thumbnail_image (void *abstract_surface, + cairo_image_surface_t *image) +{ + cairo_pdf_surface_t *surface = abstract_surface; + + surface->thumbnail_image = (cairo_image_surface_t *)cairo_surface_reference(&image->base); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_pdf_surface_add_padded_image_surface (cairo_pdf_surface_t *surface, + const cairo_pattern_t *source, + const cairo_rectangle_int_t *extents, + cairo_pdf_source_surface_entry_t **pdf_source, + double *x_offset, + double *y_offset, + cairo_rectangle_int_t *source_extents) +{ + cairo_image_surface_t *image; + cairo_surface_t *pad_image; + void *image_extra; + cairo_int_status_t status; + int w, h; + cairo_box_t box; + cairo_rectangle_int_t rect; + cairo_surface_pattern_t pad_pattern; + + status = _cairo_pdf_surface_acquire_source_image_from_pattern (surface, source, + &image, &image_extra); + if (unlikely (status)) + return status; + + pad_image = &image->base; + + /* get the operation extents in pattern space */ + _cairo_box_from_rectangle (&box, extents); + _cairo_matrix_transform_bounding_box_fixed (&source->matrix, &box, NULL); + _cairo_box_round_to_rectangle (&box, &rect); + + /* Check if image needs padding to fill extents */ + w = image->width; + h = image->height; + if (_cairo_fixed_integer_ceil(box.p1.x) < 0 || + _cairo_fixed_integer_ceil(box.p1.y) < 0 || + _cairo_fixed_integer_floor(box.p2.x) > w || + _cairo_fixed_integer_floor(box.p2.y) > h) + { + pad_image = _cairo_image_surface_create_with_content (image->base.content, + rect.width, + rect.height); + if (pad_image->status) { + status = pad_image->status; + goto BAIL; + } + + _cairo_pattern_init_for_surface (&pad_pattern, &image->base); + cairo_matrix_init_translate (&pad_pattern.base.matrix, rect.x, rect.y); + pad_pattern.base.extend = CAIRO_EXTEND_PAD; + status = _cairo_surface_paint (pad_image, + CAIRO_OPERATOR_SOURCE, &pad_pattern.base, + NULL); + _cairo_pattern_fini (&pad_pattern.base); + if (unlikely (status)) + goto BAIL; + } + + status = _cairo_pdf_surface_add_source_surface (surface, + pad_image, + NULL, + -1 , /* node_surface_index */ + CAIRO_OPERATOR_OVER, /* not used for images */ + source->filter, + FALSE, /* stencil mask */ + FALSE, /* smask */ + FALSE, /* need_transp_group */ + extents, + NULL, /* smask_res */ + pdf_source, + x_offset, + y_offset, + source_extents); + if (unlikely (status)) + goto BAIL; + + if (pad_image != &image->base) { + /* If using a padded image, replace _add_source_surface + * x/y_offset with padded image offset. Note: + * _add_source_surface only sets a non zero x/y_offset for + * RASTER_SOURCE patterns. _add_source_surface will always set + * x/y_offset to 0 for surfaces so we can ignore the returned + * offset and replace it with the offset required for the + * padded image */ + *x_offset = rect.x; + *y_offset = rect.y; + } + +BAIL: + if (pad_image != &image->base) + cairo_surface_destroy (pad_image); + + _cairo_pdf_surface_release_source_image_from_pattern (surface, source, image, image_extra); + + return status; +} + +/* Emit alpha channel from the image into stream_res. + */ +static cairo_int_status_t +_cairo_pdf_surface_emit_smask (cairo_pdf_surface_t *surface, + cairo_image_surface_t *image, + cairo_bool_t stencil_mask, + cairo_bool_t interpolate, + cairo_pdf_resource_t *stream_res) +{ + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + char *alpha; + unsigned long alpha_size; + uint32_t *pixel32; + uint8_t *pixel8; + int i, x, y, bit, a; + cairo_image_transparency_t transparency; + + /* This is the only image format we support, which simplifies things. */ + assert (image->format == CAIRO_FORMAT_ARGB32 || + image->format == CAIRO_FORMAT_RGB24 || + image->format == CAIRO_FORMAT_A8 || + image->format == CAIRO_FORMAT_A1 ); + + transparency = _cairo_image_analyze_transparency (image); + if (stencil_mask) { + assert (transparency == CAIRO_IMAGE_IS_OPAQUE || + transparency == CAIRO_IMAGE_HAS_BILEVEL_ALPHA); + } else { + assert (transparency != CAIRO_IMAGE_IS_OPAQUE); + } + + if (transparency == CAIRO_IMAGE_HAS_BILEVEL_ALPHA || transparency == CAIRO_IMAGE_IS_OPAQUE) { + alpha_size = (image->width + 7) / 8 * image->height; + alpha = _cairo_malloc_ab ((image->width+7) / 8, image->height); + } else { + alpha_size = image->height * image->width; + alpha = _cairo_malloc_ab (image->height, image->width); + } + + if (unlikely (alpha == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CLEANUP; + } + + i = 0; + for (y = 0; y < image->height; y++) { + if (transparency == CAIRO_IMAGE_IS_OPAQUE) { + for (x = 0; x < (image->width + 7) / 8; x++) + alpha[i++] = 0xff; + } else if (image->format == CAIRO_FORMAT_A1) { + pixel8 = (uint8_t *) (image->data + y * image->stride); + + for (x = 0; x < (image->width + 7) / 8; x++, pixel8++) { + a = *pixel8; + a = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (a); + alpha[i++] = a; + } + } else { + pixel8 = (uint8_t *) (image->data + y * image->stride); + pixel32 = (uint32_t *) (image->data + y * image->stride); + bit = 7; + for (x = 0; x < image->width; x++) { + if (image->format == CAIRO_FORMAT_ARGB32) { + a = (*pixel32 & 0xff000000) >> 24; + pixel32++; + } else { + a = *pixel8; + pixel8++; + } + + if (transparency == CAIRO_IMAGE_HAS_ALPHA) { + alpha[i++] = a; + } else { /* transparency == CAIRO_IMAGE_HAS_BILEVEL_ALPHA or CAIRO_IMAGE_IS_OPAQUE */ + if (bit == 7) + alpha[i] = 0; + if (a != 0) + alpha[i] |= (1 << bit); + bit--; + if (bit < 0) { + bit = 7; + i++; + } + } + } + if (bit != 7) + i++; + } + } + + if (stencil_mask) { + status = _cairo_pdf_surface_open_stream (surface, + stream_res, + TRUE, + " /Type /XObject\n" + " /Subtype /Image\n" + " /ImageMask true\n" + " /Width %d\n" + " /Height %d\n" + " /Interpolate %s\n" + " /BitsPerComponent 1\n" + " /Decode [1 0]\n", + image->width, image->height, + interpolate ? "true" : "false"); + } else { + status = _cairo_pdf_surface_open_stream (surface, + stream_res, + TRUE, + " /Type /XObject\n" + " /Subtype /Image\n" + " /Width %d\n" + " /Height %d\n" + " /ColorSpace /DeviceGray\n" + " /Interpolate %s\n" + " /BitsPerComponent %d\n", + image->width, image->height, + interpolate ? "true" : "false", + transparency == CAIRO_IMAGE_HAS_ALPHA ? 8 : 1); + } + if (unlikely (status)) + goto CLEANUP_ALPHA; + + _cairo_output_stream_write (surface->output, alpha, alpha_size); + status = _cairo_pdf_surface_close_stream (surface); + + CLEANUP_ALPHA: + free (alpha); + CLEANUP: + return status; +} + +/** + * _cairo_pdf_surface_emit_image: + * @surface: the pdf surface + * @image_surf: The image to write + * @surface_entry: Contains image resource, smask resource, interpolate and stencil mask parameters. + * + * Emit an image stream using the @image_res resource and write out + * the image data from @image_surf. If @smask_res is not null, @smask_res will + * be specified as the smask for the image. Otherwise emit the an smask if + * the image is requires one. + **/ +static cairo_int_status_t +_cairo_pdf_surface_emit_image (cairo_pdf_surface_t *surface, + cairo_image_surface_t *image_surf, + cairo_pdf_source_surface_entry_t *surface_entry) +{ + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + char *data; + unsigned long data_size; + uint32_t *pixel; + int i, x, y, bit; + cairo_pdf_resource_t smask = {0}; /* squelch bogus compiler warning */ + cairo_bool_t need_smask; + cairo_image_color_t color; + cairo_image_surface_t *image; + cairo_image_transparency_t transparency; + char smask_buf[30]; + + image = image_surf; + if (image->format != CAIRO_FORMAT_RGB24 && + image->format != CAIRO_FORMAT_ARGB32 && + image->format != CAIRO_FORMAT_A8 && + image->format != CAIRO_FORMAT_A1) + { + cairo_surface_t *surf; + cairo_surface_pattern_t pattern; + + surf = _cairo_image_surface_create_with_content (image_surf->base.content, + image_surf->width, + image_surf->height); + image = (cairo_image_surface_t *) surf; + if (surf->status) { + status = surf->status; + goto CLEANUP; + } + + _cairo_pattern_init_for_surface (&pattern, &image_surf->base); + status = _cairo_surface_paint (surf, + CAIRO_OPERATOR_SOURCE, &pattern.base, + NULL); + _cairo_pattern_fini (&pattern.base); + if (unlikely (status)) + goto CLEANUP; + } + + if (surface_entry->smask || surface_entry->stencil_mask) { + return _cairo_pdf_surface_emit_smask (surface, image, + surface_entry->stencil_mask, + surface_entry->interpolate, + &surface_entry->surface_res); + } + + color = _cairo_image_analyze_color (image); + switch (color) { + default: + case CAIRO_IMAGE_UNKNOWN_COLOR: + ASSERT_NOT_REACHED; + case CAIRO_IMAGE_IS_COLOR: + data_size = image->height * image->width * 3; + data = _cairo_malloc_abc (image->width, image->height, 3); + break; + + case CAIRO_IMAGE_IS_GRAYSCALE: + data_size = image->height * image->width; + data = _cairo_malloc_ab (image->width, image->height); + break; + case CAIRO_IMAGE_IS_MONOCHROME: + data_size = (image->width + 7) / 8 * image->height; + data = _cairo_malloc_ab ((image->width+7) / 8, image->height); + break; + } + if (unlikely (data == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CLEANUP; + } + + i = 0; + for (y = 0; y < image->height; y++) { + pixel = (uint32_t *) (image->data + y * image->stride); + + bit = 7; + for (x = 0; x < image->width; x++, pixel++) { + int r, g, b; + + /* XXX: We're un-premultiplying alpha here. My reading of the PDF + * specification suggests that we should be able to avoid having + * to do this by filling in the SMask's Matte dictionary + * appropriately, but my attempts to do that so far have + * failed. */ + if (image->format == CAIRO_FORMAT_ARGB32) { + uint8_t a; + a = (*pixel & 0xff000000) >> 24; + if (a == 0) { + r = g = b = 0; + } else { + r = (((*pixel & 0xff0000) >> 16) * 255 + a / 2) / a; + g = (((*pixel & 0x00ff00) >> 8) * 255 + a / 2) / a; + b = (((*pixel & 0x0000ff) >> 0) * 255 + a / 2) / a; + } + } else if (image->format == CAIRO_FORMAT_RGB24) { + r = (*pixel & 0x00ff0000) >> 16; + g = (*pixel & 0x0000ff00) >> 8; + b = (*pixel & 0x000000ff) >> 0; + } else { + r = g = b = 0; + } + + switch (color) { + case CAIRO_IMAGE_IS_COLOR: + case CAIRO_IMAGE_UNKNOWN_COLOR: + data[i++] = r; + data[i++] = g; + data[i++] = b; + break; + + case CAIRO_IMAGE_IS_GRAYSCALE: + data[i++] = r; + break; + + case CAIRO_IMAGE_IS_MONOCHROME: + if (bit == 7) + data[i] = 0; + if (r != 0) + data[i] |= (1 << bit); + bit--; + if (bit < 0) { + bit = 7; + i++; + } + break; + } + } + if (bit != 7) + i++; + } + + if (surface_entry->smask_res.id != 0) { + need_smask = TRUE; + smask = surface_entry->smask_res; + } else { + need_smask = FALSE; + if (image->format == CAIRO_FORMAT_ARGB32 || + image->format == CAIRO_FORMAT_A8 || + image->format == CAIRO_FORMAT_A1) + { + transparency = _cairo_image_analyze_transparency (image); + if (transparency != CAIRO_IMAGE_IS_OPAQUE) { + need_smask = TRUE; + smask = _cairo_pdf_surface_new_object (surface); + if (smask.id == 0) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CLEANUP_RGB; + } + + status = _cairo_pdf_surface_emit_smask (surface, image, FALSE, surface_entry->interpolate, &smask); + if (unlikely (status)) + goto CLEANUP_RGB; + } + } + } + + if (need_smask) + snprintf(smask_buf, sizeof(smask_buf), " /SMask %d 0 R\n", smask.id); + else + smask_buf[0] = 0; + + status = _cairo_pdf_surface_open_stream (surface, + &surface_entry->surface_res, + TRUE, + " /Type /XObject\n" + " /Subtype /Image\n" + " /Width %d\n" + " /Height %d\n" + " /ColorSpace %s\n" + " /Interpolate %s\n" + " /BitsPerComponent %d\n" + "%s", + image->width, + image->height, + color == CAIRO_IMAGE_IS_COLOR ? "/DeviceRGB" : "/DeviceGray", + surface_entry->interpolate ? "true" : "false", + color == CAIRO_IMAGE_IS_MONOCHROME? 1 : 8, + smask_buf); + if (unlikely (status)) + goto CLEANUP_RGB; + +#undef IMAGE_DICTIONARY + + _cairo_output_stream_write (surface->output, data, data_size); + status = _cairo_pdf_surface_close_stream (surface); + +CLEANUP_RGB: + free (data); +CLEANUP: + if (image != image_surf) + cairo_surface_destroy (&image->base); + + return status; +} + +static cairo_int_status_t +_cairo_pdf_surface_lookup_jbig2_global (cairo_pdf_surface_t *surface, + const unsigned char *global_id, + unsigned long global_id_length, + cairo_pdf_jbig2_global_t **entry) +{ + cairo_pdf_jbig2_global_t global; + int size, i; + cairo_int_status_t status; + + size = _cairo_array_num_elements (&surface->jbig2_global); + for (i = 0; i < size; i++) { + *entry = (cairo_pdf_jbig2_global_t *) _cairo_array_index (&surface->jbig2_global, i); + if ((*entry)->id && global_id && (*entry)->id_length == global_id_length + && memcmp((*entry)->id, global_id, global_id_length) == 0) { + return CAIRO_STATUS_SUCCESS; + } + } + + global.id = _cairo_malloc (global_id_length); + if (unlikely (global.id == NULL)) { + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + memcpy (global.id, global_id, global_id_length); + global.id_length = global_id_length; + global.res = _cairo_pdf_surface_new_object (surface); + if (global.res.id == 0) { + free(global.id); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + global.emitted = FALSE; + status = _cairo_array_append (&surface->jbig2_global, &global); + if (unlikely(status)) + return status; + + size = _cairo_array_num_elements (&surface->jbig2_global); + *entry = (cairo_pdf_jbig2_global_t *) _cairo_array_index (&surface->jbig2_global, size - 1); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_pdf_surface_emit_jbig2_image (cairo_pdf_surface_t *surface, + cairo_surface_t *source, + cairo_pdf_source_surface_entry_t *surface_entry, + cairo_bool_t test) +{ + cairo_int_status_t status; + const unsigned char *mime_data; + unsigned long mime_data_length; + cairo_image_info_t info; + const unsigned char *global_id; + unsigned long global_id_length; + const unsigned char *global_data; + unsigned long global_data_length; + cairo_pdf_jbig2_global_t *global_entry = NULL; /* hide compiler warning */ + char smask_buf[30]; + char decode_parms_buf[100]; + + cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JBIG2, + &mime_data, &mime_data_length); + if (mime_data == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_image_info_get_jbig2_info (&info, mime_data, mime_data_length); + if (status) + return status; + + /* At this point we know emitting jbig2 will succeed. */ + if (test) + return CAIRO_STATUS_SUCCESS; + + cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID, + &global_id, &global_id_length); + if (global_id && global_id_length > 0) { + status = _cairo_pdf_surface_lookup_jbig2_global (surface, global_id, global_id_length, &global_entry); + if (unlikely(status)) + return status; + + if (!global_entry->emitted) { + cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JBIG2_GLOBAL, + &global_data, &global_data_length); + if (global_data) { + status = _cairo_pdf_surface_open_stream (surface, &global_entry->res, FALSE, NULL); + if (unlikely(status)) + return status; + + _cairo_output_stream_write (surface->output, global_data, global_data_length); + status = _cairo_pdf_surface_close_stream (surface); + if (unlikely(status)) + return status; + + global_entry->emitted = TRUE; + } + } + + snprintf(decode_parms_buf, sizeof(decode_parms_buf), + " /DecodeParms << /JBIG2Globals %d 0 R >>\n", global_entry->res.id); + } else { + decode_parms_buf[0] = 0; + } + + if (surface_entry->smask_res.id) + snprintf(smask_buf, sizeof(smask_buf), " /SMask %d 0 R\n", surface_entry->smask_res.id); + else + smask_buf[0] = 0; + + if (surface_entry->stencil_mask) { + status = _cairo_pdf_surface_open_stream (surface, + &surface_entry->surface_res, + FALSE, + " /Type /XObject\n" + " /Subtype /Image\n" + " /ImageMask true\n" + " /Width %d\n" + " /Height %d\n" + " /Interpolate %s\n" + " /BitsPerComponent 1\n" + " /Decode [1 0]\n" + " /Filter /JPXDecode\n" + "%s", + info.width, + info.height, + surface_entry->interpolate ? "true" : "false", + decode_parms_buf); + } else { + status = _cairo_pdf_surface_open_stream (surface, + &surface_entry->surface_res, + FALSE, + " /Type /XObject\n" + " /Subtype /Image\n" + " /Width %d\n" + " /Height %d\n" + " /ColorSpace /DeviceGray\n" + " /BitsPerComponent 1\n" + " /Interpolate %s\n" + "%s" + " /Filter /JBIG2Decode\n" + "%s", + info.width, + info.height, + surface_entry->interpolate ? "true" : "false", + smask_buf, + decode_parms_buf); + } + if (unlikely(status)) + return status; + + _cairo_output_stream_write (surface->output, mime_data, mime_data_length); + status = _cairo_pdf_surface_close_stream (surface); + + return status; +} + +static cairo_int_status_t +_cairo_pdf_surface_emit_jpx_image (cairo_pdf_surface_t *surface, + cairo_surface_t *source, + cairo_pdf_source_surface_entry_t *surface_entry, + cairo_bool_t test) +{ + cairo_int_status_t status; + const unsigned char *mime_data; + unsigned long mime_data_length; + cairo_image_info_t info; + char smask_buf[30]; + + if (surface->pdf_version < CAIRO_PDF_VERSION_1_5) + return CAIRO_INT_STATUS_UNSUPPORTED; + + cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JP2, + &mime_data, &mime_data_length); + if (mime_data == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_image_info_get_jpx_info (&info, mime_data, mime_data_length); + if (status) + return status; + + if ((surface_entry->smask || surface_entry->stencil_mask) && info.num_components != 1) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if ((surface_entry->stencil_mask) && info.bits_per_component != 1) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (surface_entry->smask_res.id) + snprintf(smask_buf, sizeof(smask_buf), " /SMask %d 0 R\n", surface_entry->smask_res.id); + else + smask_buf[0] = 0; + + /* At this point we know emitting jpx will succeed. */ + if (test) + return CAIRO_STATUS_SUCCESS; + + if (surface_entry->stencil_mask) { + status = _cairo_pdf_surface_open_stream (surface, + &surface_entry->surface_res, + FALSE, + " /Type /XObject\n" + " /Subtype /Image\n" + " /ImageMask true\n" + " /Width %d\n" + " /Height %d\n" + " /Interpolate %s\n" + " /BitsPerComponent 1\n" + " /Decode [1 0]\n" + " /Filter /JPXDecode\n", + info.width, + info.height, + surface_entry->interpolate ? "true" : "false"); + } else { + status = _cairo_pdf_surface_open_stream (surface, + &surface_entry->surface_res, + FALSE, + " /Type /XObject\n" + " /Subtype /Image\n" + " /Width %d\n" + " /Height %d\n" + " /Interpolate %s\n" + "%s" + " /Filter /JPXDecode\n", + info.width, + info.height, + surface_entry->interpolate ? "true" : "false", + smask_buf); + } + if (status) + return status; + + _cairo_output_stream_write (surface->output, mime_data, mime_data_length); + status = _cairo_pdf_surface_close_stream (surface); + + return status; +} + +static cairo_int_status_t +_cairo_pdf_surface_emit_jpeg_image (cairo_pdf_surface_t *surface, + cairo_surface_t *source, + cairo_pdf_source_surface_entry_t *surface_entry, + cairo_bool_t test) +{ + cairo_int_status_t status; + const unsigned char *mime_data; + unsigned long mime_data_length; + cairo_image_info_t info; + const char *colorspace; + char smask_buf[30]; + + cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG, + &mime_data, &mime_data_length); + if (unlikely (source->status)) + return source->status; + if (mime_data == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_image_info_get_jpeg_info (&info, mime_data, mime_data_length); + if (unlikely (status)) + return status; + + if ((surface_entry->smask || surface_entry->stencil_mask) && info.num_components != 1) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if ((surface_entry->stencil_mask) && info.bits_per_component != 1) + return CAIRO_INT_STATUS_UNSUPPORTED; + + switch (info.num_components) { + case 1: + colorspace = "/DeviceGray"; + break; + case 3: + colorspace = "/DeviceRGB"; + break; + case 4: + colorspace = "/DeviceCMYK"; + break; + default: + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + /* At this point we know emitting jpeg will succeed. */ + if (test) + return CAIRO_STATUS_SUCCESS; + + if (surface_entry->smask_res.id) + snprintf(smask_buf, sizeof(smask_buf), " /SMask %d 0 R\n", surface_entry->smask_res.id); + else + smask_buf[0] = 0; + + if (surface_entry->stencil_mask) { + status = _cairo_pdf_surface_open_stream (surface, + &surface_entry->surface_res, + FALSE, + " /Type /XObject\n" + " /Subtype /Image\n" + " /ImageMask true\n" + " /Width %d\n" + " /Height %d\n" + " /Interpolate %s\n" + " /BitsPerComponent 1\n" + " /Decode [1 0]\n" + " /Filter /DCTDecode\n", + info.width, + info.height, + surface_entry->interpolate ? "true" : "false"); + } else { + status = _cairo_pdf_surface_open_stream (surface, + &surface_entry->surface_res, + FALSE, + " /Type /XObject\n" + " /Subtype /Image\n" + " /Width %d\n" + " /Height %d\n" + " /ColorSpace %s\n" + " /Interpolate %s\n" + " /BitsPerComponent %d\n" + "%s" + " /Filter /DCTDecode\n", + info.width, + info.height, + colorspace, + surface_entry->interpolate ? "true" : "false", + info.bits_per_component, + smask_buf); + } + if (unlikely (status)) + return status; + + _cairo_output_stream_write (surface->output, mime_data, mime_data_length); + status = _cairo_pdf_surface_close_stream (surface); + + return status; +} + +static cairo_int_status_t +_cairo_pdf_surface_emit_ccitt_image (cairo_pdf_surface_t *surface, + cairo_surface_t *source, + cairo_pdf_source_surface_entry_t *surface_entry, + cairo_bool_t test) +{ + cairo_status_t status; + const unsigned char *ccitt_data; + unsigned long ccitt_data_len; + const unsigned char *ccitt_params_string; + unsigned long ccitt_params_string_len; + char *params, *p, *end; + cairo_ccitt_params_t ccitt_params; + char buf[300]; + + cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_CCITT_FAX, + &ccitt_data, &ccitt_data_len); + if (unlikely (source->status)) + return source->status; + if (ccitt_data == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_CCITT_FAX_PARAMS, + &ccitt_params_string, &ccitt_params_string_len); + if (unlikely (source->status)) + return source->status; + if (ccitt_params_string == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* ensure params_string is null terminated */ + params = _cairo_strndup ((const char *)ccitt_params_string, ccitt_params_string_len); + if (unlikely (params == NULL)) + return _cairo_surface_set_error (&surface->base, CAIRO_STATUS_NO_MEMORY); + + status = _cairo_tag_parse_ccitt_params (params, &ccitt_params); + if (unlikely(status)) + return source->status; + + free (params); + + /* At this point we know emitting jbig2 will succeed. */ + if (test) + return CAIRO_STATUS_SUCCESS; + + p = buf; + *p = 0; + end = buf + sizeof(buf) - 1; + p += snprintf (p, end - p, "/Columns %d /Rows %d /K %d", + ccitt_params.columns, + ccitt_params.rows, + ccitt_params.k); + if (ccitt_params.end_of_line) + p += snprintf (p, end - p, " /EndOfLine true"); + + if (ccitt_params.encoded_byte_align) + p += snprintf (p, end - p, " /EncodedByteAlign true"); + + if (!ccitt_params.end_of_block) + p += snprintf (p, end - p, " /EndOfBlock false"); + + if (ccitt_params.black_is_1) + p += snprintf (p, end - p, " /BlackIs1 true"); + + if (ccitt_params.damaged_rows_before_error > 0) { + p += snprintf (p, end - p, " /DamagedRowsBeforeError %d", + ccitt_params.damaged_rows_before_error); + } + + if (surface_entry->stencil_mask) { + status = _cairo_pdf_surface_open_stream (surface, + &surface_entry->surface_res, + FALSE, + " /Type /XObject\n" + " /Subtype /Image\n" + " /ImageMask true\n" + " /Width %d\n" + " /Height %d\n" + " /Interpolate %s\n" + " /BitsPerComponent 1\n" + " /Decode [1 0]\n" + " /Filter /CCITTFaxDecode\n" + " /DecodeParms << %s >> ", + ccitt_params.columns, + ccitt_params.rows, + surface_entry->interpolate ? "true" : "false", + buf); + } else { + status = _cairo_pdf_surface_open_stream (surface, + &surface_entry->surface_res, + FALSE, + " /Type /XObject\n" + " /Subtype /Image\n" + " /Width %d\n" + " /Height %d\n" + " /ColorSpace /DeviceGray\n" + " /BitsPerComponent 1\n" + " /Interpolate %s\n" + " /Filter /CCITTFaxDecode\n" + " /DecodeParms << %s >> ", + ccitt_params.columns, + ccitt_params.rows, + surface_entry->interpolate ? "true" : "false", + buf); + } + if (unlikely (status)) + return status; + + _cairo_output_stream_write (surface->output, ccitt_data, ccitt_data_len); + status = _cairo_pdf_surface_close_stream (surface); + + return status; +} + +static cairo_int_status_t +_cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t *surface, + cairo_pdf_source_surface_t *pdf_source) +{ + cairo_rectangle_int_t old_surface_extents; + cairo_bool_t old_surface_bounded; + cairo_paginated_mode_t old_paginated_mode; + cairo_surface_clipper_t old_clipper; + cairo_bool_t old_in_xobject; + cairo_box_double_t bbox; + cairo_int_status_t status; + int alpha = 0; + cairo_surface_t *free_me = NULL; + cairo_surface_t *source; + const cairo_rectangle_int_t *extents; + cairo_bool_t is_subsurface; + cairo_bool_t transparency_group; + cairo_recording_surface_t *recording; + int struct_parents = -1; + + assert (pdf_source->type == CAIRO_PATTERN_TYPE_SURFACE); + + if (pdf_source->hash_entry->bounded) { + extents = &pdf_source->hash_entry->extents; + } else { + extents = &pdf_source->hash_entry->required_extents; + } + + is_subsurface = FALSE; + source = pdf_source->surface; + if (_cairo_surface_is_snapshot (source)) + free_me = source = _cairo_surface_snapshot_get_target (source); + + if (source->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) { + cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source; + + source = sub->target; + extents = &sub->extents; + is_subsurface = TRUE; + } + + assert (source->type == CAIRO_SURFACE_TYPE_RECORDING); + recording = (cairo_recording_surface_t *) source; + + old_in_xobject = surface->in_xobject; + old_surface_extents = surface->surface_extents; + old_surface_bounded = surface->surface_bounded; + old_paginated_mode = surface->paginated_mode; + old_clipper = surface->clipper; + surface->surface_extents = *extents; + _cairo_surface_clipper_init (&surface->clipper, + _cairo_pdf_surface_clipper_intersect_clip_path); + + _cairo_pdf_operators_reset (&surface->pdf_operators); + surface->in_xobject = TRUE; + surface->surface_extents = *extents; + surface->surface_bounded = TRUE; + + /* Patterns are emitted after fallback images. The paginated mode + * needs to be set to _RENDER while the recording surface is replayed + * back to this surface. + */ + surface->paginated_mode = CAIRO_PAGINATED_MODE_RENDER; + _cairo_pdf_group_resources_clear (&surface->resources); + _get_bbox_from_extents (extents, &bbox); + + /* We can optimize away the transparency group allowing the viewer + * to replay the group in place when: + * - ca/CA when painting this groups is 1.0 (need_transp_group is FALSE), + * - all operators are OVER, and + * - the recording contains only opaque and/or clear alpha. + */ + transparency_group = pdf_source->hash_entry->need_transp_group || + !(pdf_source->hash_entry->operator == CAIRO_OPERATOR_OVER && + _cairo_recording_surface_has_only_bilevel_alpha (recording) && + _cairo_recording_surface_has_only_op_over (recording)); + + status = _cairo_pdf_interchange_emit_recording_surface_begin (surface, + pdf_source->surface, + pdf_source->hash_entry->region_id, + pdf_source->hash_entry->surface_res, + &struct_parents); + if (unlikely (status)) + goto err; + + status = _cairo_pdf_surface_open_content_stream (surface, + &bbox, + &pdf_source->hash_entry->surface_res, + TRUE, + transparency_group, + struct_parents); + if (unlikely (status)) + goto err; + + /* Reset gstate */ + surface->reset_gs_required = TRUE; + + if (source->content == CAIRO_CONTENT_COLOR) { + status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha); + if (unlikely (status)) + goto err; + + _cairo_output_stream_printf (surface->output, + "q /a%d gs 0 0 0 rg %d %d %d %d re f Q\n", + alpha, + extents->x, + extents->y, + extents->width, + extents->height); + } + + status = _cairo_recording_surface_replay_region (source, + pdf_source->region_id, + is_subsurface ? extents : NULL, + &surface->base, + CAIRO_RECORDING_REGION_NATIVE); + assert (status != CAIRO_INT_STATUS_UNSUPPORTED); + if (unlikely (status)) + goto err; + + status = _cairo_pdf_surface_close_content_stream (surface, TRUE); + + _cairo_surface_clipper_reset (&surface->clipper); + surface->clipper = old_clipper; + _cairo_pdf_operators_reset (&surface->pdf_operators); + surface->in_xobject = old_in_xobject; + surface->paginated_mode = old_paginated_mode; + surface->surface_extents = old_surface_extents; + surface->surface_bounded = old_surface_bounded; + surface->reset_gs_required = FALSE; + + if (pdf_source->hash_entry->region_id > 0) + status = _cairo_pdf_interchange_emit_recording_surface_end (surface, pdf_source->surface); + +err: + cairo_surface_destroy (free_me); + return status; +} + +/** + * _cairo_pdf_surface_emit_surface: + * @surface: [in] the pdf surface + * @source: [in] #cairo_pdf_source_surface_t containing the surface to write + * @test: [in] if true, test what type of surface will be emitted. + * @is_image: [out] if @test is true, returns TRUE if the surface will be emitted + * as an Image XObject. + * + * If @test is FALSE, emit @src_surface as an XObject. + * If @test is TRUE, don't emit anything. Set @is_image based on the output that would be emitted. + **/ +static cairo_int_status_t +_cairo_pdf_surface_emit_surface (cairo_pdf_surface_t *surface, + cairo_pdf_source_surface_t *source, + cairo_bool_t test, + cairo_bool_t *is_image) +{ + cairo_image_surface_t *image; + void *image_extra; + cairo_int_status_t status; + + /* Try all the supported mime types and recording type, falling through + * each option if unsupported */ + if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { + status = _cairo_pdf_surface_emit_jbig2_image (surface, + source->surface, + source->hash_entry, + test); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) { + *is_image = TRUE; + return status; + } + + status = _cairo_pdf_surface_emit_jpx_image (surface, + source->surface, + source->hash_entry, + test); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) { + *is_image = TRUE; + return status; + } + + status = _cairo_pdf_surface_emit_jpeg_image (surface, + source->surface, + source->hash_entry, + test); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) { + *is_image = TRUE; + return status; + } + + status = _cairo_pdf_surface_emit_ccitt_image (surface, + source->surface, + source->hash_entry, + test); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) { + *is_image = TRUE; + return status; + } + + if (source->surface->type == CAIRO_SURFACE_TYPE_RECORDING) { + if (test) { + *is_image = FALSE; + return CAIRO_INT_STATUS_SUCCESS; + } else { + return _cairo_pdf_surface_emit_recording_surface (surface, source); + } + } + } + + /* The only option left is to emit as an image surface */ + + if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { + status = _cairo_surface_acquire_source_image (source->surface, &image, &image_extra); + } else { + status = _cairo_pdf_surface_acquire_source_image_from_pattern (surface, + source->raster_pattern, + &image, + &image_extra); + } + if (unlikely (status)) + return status; + + if (test) { + *is_image = TRUE; + } else { + status = _cairo_pdf_surface_emit_image (surface, + image, + source->hash_entry); + } + + if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { + _cairo_surface_release_source_image (source->surface, image, image_extra); + } else { + _cairo_pdf_surface_release_source_image_from_pattern (surface, + source->raster_pattern, + image, + image_extra); + } + + return status; +} + +static cairo_int_status_t +_cairo_pdf_surface_emit_surface_pattern (cairo_pdf_surface_t *surface, + cairo_pdf_pattern_t *pdf_pattern) +{ + cairo_pattern_t *pattern = pdf_pattern->pattern; + cairo_int_status_t status; + cairo_matrix_t cairo_p2d, pdf_p2d; + cairo_extend_t extend = cairo_pattern_get_extend (pattern); + double xstep, ystep; + cairo_rectangle_int_t pattern_extents; + double x_offset; + double y_offset; + char draw_surface[50]; + char draw_surface2[200]; + cairo_box_double_t bbox; + cairo_matrix_t mat; + cairo_pdf_source_surface_entry_t *pdf_source; + cairo_rectangle_int_t op_extents; + + assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE); + if (pattern->extend == CAIRO_EXTEND_PAD) { + status = _cairo_pdf_surface_add_padded_image_surface (surface, + pattern, + &pdf_pattern->extents, + &pdf_source, + &x_offset, + &y_offset, + &op_extents); + } else { + status = _cairo_pdf_surface_add_source_surface (surface, + NULL, + pattern, + pdf_pattern->region_id, + pdf_pattern->operator, + pattern->filter, + FALSE, /* stencil mask */ + FALSE, /* smask */ + FALSE, /* need_transp_group */ + &pdf_pattern->extents, + NULL, /* smask_res */ + &pdf_source, + &x_offset, + &y_offset, + &op_extents); + } + if (unlikely (status)) + return status; + + pattern_extents = pdf_source->extents; + if (!pdf_source->bounded) + { + extend = CAIRO_EXTEND_NONE; + _cairo_rectangle_intersect (&pattern_extents, &op_extents); + } + + switch (extend) { + case CAIRO_EXTEND_PAD: + case CAIRO_EXTEND_NONE: + { + /* In PS/PDF, (as far as I can tell), all patterns are + * repeating. So we support cairo's EXTEND_NONE semantics + * by setting the repeat step size to a size large enough + * to guarantee that no more than a single occurrence will + * be visible. + * + * First, map the surface extents into pattern space (since + * xstep and ystep are in pattern space). Then use an upper + * bound on the length of the diagonal of the pattern image + * and the surface as repeat size. This guarantees to never + * repeat visibly. + */ + double x1 = 0.0, y1 = 0.0; + double x2 = surface->surface_extents.width; + double y2 = surface->surface_extents.height; + _cairo_matrix_transform_bounding_box (&pattern->matrix, + &x1, &y1, &x2, &y2, + NULL); + + /* Rather than computing precise bounds of the union, just + * add the surface extents unconditionally. We only + * required an answer that's large enough, we don't really + * care if it's not as tight as possible.*/ + xstep = ystep = ceil ((x2 - x1) + (y2 - y1) + + pattern_extents.width + pattern_extents.height); + } + break; + case CAIRO_EXTEND_REPEAT: + xstep = pattern_extents.width; + ystep = pattern_extents.height; + break; + + case CAIRO_EXTEND_REFLECT: + pattern_extents.width *= 2; + pattern_extents.height *= 2; + xstep = pattern_extents.width; + ystep = pattern_extents.height; + break; + + /* All the rest (if any) should have been analyzed away, so this + * case should be unreachable. */ + default: + ASSERT_NOT_REACHED; + xstep = 0; + ystep = 0; + } + + /* At this point, (that is, within the surface backend interface), + * the pattern's matrix maps from cairo's device space to cairo's + * pattern space, (both with their origin at the upper-left, and + * cairo's pattern space of size width,height). + * + * Then, we must emit a PDF pattern object that maps from its own + * pattern space, (which has a size that we establish in the BBox + * dictionary entry), to the PDF page's *initial* space, (which + * does not benefit from the Y-axis flipping matrix that we emit + * on each page). So the PDF patterns matrix maps from a + * (width,height) pattern space to a device space with the origin + * in the lower-left corner. + * + * So to handle all of that, we start with an identity matrix for + * the PDF pattern to device matrix. We translate it up by the + * image height then flip it in the Y direction, (moving us from + * the PDF origin to cairo's origin). We then multiply in the + * inverse of the cairo pattern matrix, (since it maps from device + * to pattern, while we're setting up pattern to device). Finally, + * we translate back down by the image height and flip again to + * end up at the lower-left origin that PDF expects. + * + * Additionally, within the stream that paints the pattern itself, + * we are using a PDF image object that has a size of (1,1) so we + * have to scale it up by the image width and height to fill our + * pattern cell. + */ + cairo_p2d = pattern->matrix; + status = cairo_matrix_invert (&cairo_p2d); + /* cairo_pattern_set_matrix ensures the matrix is invertible */ + assert (status == CAIRO_INT_STATUS_SUCCESS); + + if (pdf_pattern->inverted_y_axis) + cairo_matrix_init (&mat, 1, 0, 0, 1, 0, 0); + else + cairo_matrix_init (&mat, 1, 0, 0, -1, 0, surface->height); + + cairo_matrix_multiply (&pdf_p2d, &cairo_p2d, &mat); + cairo_matrix_translate (&pdf_p2d, x_offset, y_offset); + if (pdf_source->emit_image) { + cairo_matrix_translate (&pdf_p2d, 0.0, pdf_source->extents.height); + cairo_matrix_scale (&pdf_p2d, 1.0, -1.0); + } + + _get_bbox_from_extents (&pattern_extents, &bbox); + _cairo_pdf_surface_update_object (surface, pdf_pattern->pattern_res); + status = _cairo_pdf_surface_open_stream (surface, + &pdf_pattern->pattern_res, + FALSE, + " /PatternType 1\n" + " /BBox [ %f %f %f %f ]\n" + " /XStep %f\n" + " /YStep %f\n" + " /TilingType 1\n" + " /PaintType 1\n" + " /Matrix [ %f %f %f %f %f %f ]\n" + " /Resources << /XObject << /x%d %d 0 R >> >>\n", + bbox.p1.x, bbox.p1.y, bbox.p2.x, bbox.p2.y, + xstep, ystep, + pdf_p2d.xx, pdf_p2d.yx, + pdf_p2d.xy, pdf_p2d.yy, + pdf_p2d.x0, pdf_p2d.y0, + pdf_source->surface_res.id, + pdf_source->surface_res.id); + if (unlikely (status)) + return status; + + if (pdf_source->emit_image) { + snprintf(draw_surface, + sizeof (draw_surface), + "q %d 0 0 %d 0 0 cm /x%d Do Q", + pdf_source->extents.width, + pdf_source->extents.height, + pdf_source->surface_res.id); + } else { + snprintf(draw_surface, + sizeof (draw_surface), + "/x%d Do", + pdf_source->surface_res.id); + } + + if (extend == CAIRO_EXTEND_REFLECT) { + cairo_rectangle_int_t p_extents = pdf_source->extents; + snprintf(draw_surface2, + sizeof (draw_surface2), + "%d %d %d %d re W n %s", + p_extents.x, p_extents.y, + p_extents.width, p_extents.height, + draw_surface); + + _cairo_output_stream_printf (surface->output, "q %s Q\n", draw_surface2); + + cairo_matrix_init_translate (&mat, p_extents.x, p_extents.y); + cairo_matrix_scale (&mat, -1, 1); + cairo_matrix_translate (&mat, -2*p_extents.width, 0); + cairo_matrix_translate (&mat, -p_extents.x, -p_extents.y); + _cairo_output_stream_printf (surface->output, "q "); + _cairo_output_stream_print_matrix (surface->output, &mat); + _cairo_output_stream_printf (surface->output, " cm %s Q\n", draw_surface2); + + cairo_matrix_init_translate (&mat, p_extents.x, p_extents.y); + cairo_matrix_scale (&mat, 1, -1); + cairo_matrix_translate (&mat, 0, -2*p_extents.height); + cairo_matrix_translate (&mat, -p_extents.x, -p_extents.y); + _cairo_output_stream_printf (surface->output, "q "); + _cairo_output_stream_print_matrix (surface->output, &mat); + _cairo_output_stream_printf (surface->output, " cm %s Q\n", draw_surface2); + + cairo_matrix_init_translate (&mat, p_extents.x, p_extents.y); + cairo_matrix_scale (&mat, -1, -1); + cairo_matrix_translate (&mat, -2*p_extents.width, -2*p_extents.height); + cairo_matrix_translate (&mat, -p_extents.x, -p_extents.y); + _cairo_output_stream_printf (surface->output, "q "); + _cairo_output_stream_print_matrix (surface->output, &mat); + _cairo_output_stream_printf (surface->output, " cm %s Q\n", draw_surface2); + } else { + _cairo_output_stream_printf (surface->output, + " %s \n", + draw_surface); + } + + status = _cairo_pdf_surface_close_stream (surface); + if (unlikely (status)) + return status; + + return _cairo_output_stream_get_status (surface->output); +} + +typedef struct _cairo_pdf_color_stop { + double offset; + double color[4]; + cairo_pdf_resource_t resource; +} cairo_pdf_color_stop_t; + +static cairo_int_status_t +cairo_pdf_surface_emit_rgb_linear_function (cairo_pdf_surface_t *surface, + cairo_pdf_color_stop_t *stop1, + cairo_pdf_color_stop_t *stop2, + cairo_pdf_resource_t *function) +{ + int num_elems, i; + cairo_pdf_rgb_linear_function_t elem; + cairo_pdf_resource_t res; + cairo_int_status_t status; + + num_elems = _cairo_array_num_elements (&surface->rgb_linear_functions); + for (i = 0; i < num_elems; i++) { + _cairo_array_copy_element (&surface->rgb_linear_functions, i, &elem); + if (memcmp (&elem.color1[0], &stop1->color[0], sizeof (double)*3) != 0) + continue; + if (memcmp (&elem.color2[0], &stop2->color[0], sizeof (double)*3) != 0) + continue; + *function = elem.resource; + return CAIRO_STATUS_SUCCESS; + } + + res = _cairo_pdf_surface_new_object (surface); + if (res.id == 0) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n" + "<< /FunctionType 2\n" + " /Domain [ 0 1 ]\n" + " /C0 [ %f %f %f ]\n" + " /C1 [ %f %f %f ]\n" + " /N 1\n" + ">>\n" + "endobj\n", + res.id, + stop1->color[0], + stop1->color[1], + stop1->color[2], + stop2->color[0], + stop2->color[1], + stop2->color[2]); + + elem.resource = res; + memcpy (&elem.color1[0], &stop1->color[0], sizeof (double)*3); + memcpy (&elem.color2[0], &stop2->color[0], sizeof (double)*3); + + status = _cairo_array_append (&surface->rgb_linear_functions, &elem); + *function = res; + + return status; +} + +static cairo_int_status_t +cairo_pdf_surface_emit_alpha_linear_function (cairo_pdf_surface_t *surface, + cairo_pdf_color_stop_t *stop1, + cairo_pdf_color_stop_t *stop2, + cairo_pdf_resource_t *function) +{ + int num_elems, i; + cairo_pdf_alpha_linear_function_t elem; + cairo_pdf_resource_t res; + cairo_int_status_t status; + + num_elems = _cairo_array_num_elements (&surface->alpha_linear_functions); + for (i = 0; i < num_elems; i++) { + _cairo_array_copy_element (&surface->alpha_linear_functions, i, &elem); + if (elem.alpha1 != stop1->color[3]) + continue; + if (elem.alpha2 != stop2->color[3]) + continue; + *function = elem.resource; + return CAIRO_STATUS_SUCCESS; + } + + res = _cairo_pdf_surface_new_object (surface); + if (res.id == 0) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n" + "<< /FunctionType 2\n" + " /Domain [ 0 1 ]\n" + " /C0 [ %f ]\n" + " /C1 [ %f ]\n" + " /N 1\n" + ">>\n" + "endobj\n", + res.id, + stop1->color[3], + stop2->color[3]); + + elem.resource = res; + elem.alpha1 = stop1->color[3]; + elem.alpha2 = stop2->color[3]; + + status = _cairo_array_append (&surface->alpha_linear_functions, &elem); + *function = res; + + return status; +} + +static cairo_int_status_t +_cairo_pdf_surface_emit_stitched_colorgradient (cairo_pdf_surface_t *surface, + unsigned int n_stops, + cairo_pdf_color_stop_t *stops, + cairo_bool_t is_alpha, + cairo_pdf_resource_t *function) +{ + cairo_pdf_resource_t res; + unsigned int i; + cairo_int_status_t status; + + /* emit linear gradients between pairs of subsequent stops... */ + for (i = 0; i < n_stops-1; i++) { + if (is_alpha) { + status = cairo_pdf_surface_emit_alpha_linear_function (surface, + &stops[i], + &stops[i+1], + &stops[i].resource); + if (unlikely (status)) + return status; + } else { + status = cairo_pdf_surface_emit_rgb_linear_function (surface, + &stops[i], + &stops[i+1], + &stops[i].resource); + if (unlikely (status)) + return status; + } + } + + /* ... and stitch them together */ + res = _cairo_pdf_surface_new_object (surface); + if (res.id == 0) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n" + "<< /FunctionType 3\n" + " /Domain [ %f %f ]\n", + res.id, + stops[0].offset, + stops[n_stops - 1].offset); + + _cairo_output_stream_printf (surface->output, + " /Functions [ "); + for (i = 0; i < n_stops-1; i++) + _cairo_output_stream_printf (surface->output, + "%d 0 R ", stops[i].resource.id); + _cairo_output_stream_printf (surface->output, + "]\n"); + + _cairo_output_stream_printf (surface->output, + " /Bounds [ "); + for (i = 1; i < n_stops-1; i++) + _cairo_output_stream_printf (surface->output, + "%f ", stops[i].offset); + _cairo_output_stream_printf (surface->output, + "]\n"); + + _cairo_output_stream_printf (surface->output, + " /Encode [ "); + for (i = 1; i < n_stops; i++) + _cairo_output_stream_printf (surface->output, + "0 1 "); + _cairo_output_stream_printf (surface->output, + "]\n"); + + _cairo_output_stream_printf (surface->output, + ">>\n" + "endobj\n"); + + *function = res; + + return _cairo_output_stream_get_status (surface->output); +} + + +static void +calc_gradient_color (cairo_pdf_color_stop_t *new_stop, + cairo_pdf_color_stop_t *stop1, + cairo_pdf_color_stop_t *stop2) +{ + int i; + double offset = stop1->offset / (stop1->offset + 1.0 - stop2->offset); + + for (i = 0; i < 4; i++) + new_stop->color[i] = stop1->color[i] + offset*(stop2->color[i] - stop1->color[i]); +} + +#define COLOR_STOP_EPSILON 1e-6 + +static cairo_int_status_t +_cairo_pdf_surface_emit_pattern_stops (cairo_pdf_surface_t *surface, + cairo_gradient_pattern_t *pattern, + cairo_pdf_resource_t *color_function, + cairo_pdf_resource_t *alpha_function) +{ + cairo_pdf_color_stop_t *allstops, *stops; + unsigned int n_stops; + unsigned int i; + cairo_bool_t emit_alpha = FALSE; + cairo_int_status_t status; + + color_function->id = 0; + alpha_function->id = 0; + + allstops = _cairo_malloc_ab ((pattern->n_stops + 2), sizeof (cairo_pdf_color_stop_t)); + if (unlikely (allstops == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + stops = &allstops[1]; + n_stops = pattern->n_stops; + + for (i = 0; i < n_stops; i++) { + stops[i].color[0] = pattern->stops[i].color.red; + stops[i].color[1] = pattern->stops[i].color.green; + stops[i].color[2] = pattern->stops[i].color.blue; + stops[i].color[3] = pattern->stops[i].color.alpha; + if (!CAIRO_ALPHA_IS_OPAQUE (stops[i].color[3])) + emit_alpha = TRUE; + stops[i].offset = pattern->stops[i].offset; + } + + if (pattern->base.extend == CAIRO_EXTEND_REPEAT || + pattern->base.extend == CAIRO_EXTEND_REFLECT) { + if (stops[0].offset > COLOR_STOP_EPSILON) { + if (pattern->base.extend == CAIRO_EXTEND_REFLECT) + memcpy (allstops, stops, sizeof (cairo_pdf_color_stop_t)); + else + calc_gradient_color (&allstops[0], &stops[0], &stops[n_stops-1]); + stops = allstops; + n_stops++; + } + stops[0].offset = 0.0; + + if (stops[n_stops-1].offset < 1.0 - COLOR_STOP_EPSILON) { + if (pattern->base.extend == CAIRO_EXTEND_REFLECT) { + memcpy (&stops[n_stops], + &stops[n_stops - 1], + sizeof (cairo_pdf_color_stop_t)); + } else { + calc_gradient_color (&stops[n_stops], &stops[0], &stops[n_stops-1]); + } + n_stops++; + } + stops[n_stops-1].offset = 1.0; + } + + if (stops[0].offset == stops[n_stops - 1].offset) { + /* + * The first and the last stops have the same offset, but we + * don't want a function with an empty domain, because that + * would provoke underdefined behaviour from rasterisers. + * This can only happen with EXTEND_PAD, because EXTEND_NONE + * is optimised into a clear pattern in cairo-gstate, and + * REFLECT/REPEAT are always transformed to have the first + * stop at t=0 and the last stop at t=1. Thus we want a step + * function going from the first color to the last one. + * + * This can be accomplished by stitching three functions: + * - a constant first color function, + * - a step from the first color to the last color (with empty domain) + * - a constant last color function + */ + cairo_pdf_color_stop_t pad_stops[4]; + + assert (pattern->base.extend == CAIRO_EXTEND_PAD); + + pad_stops[0] = pad_stops[1] = stops[0]; + pad_stops[2] = pad_stops[3] = stops[n_stops - 1]; + + pad_stops[0].offset = 0; + pad_stops[3].offset = 1; + + status = _cairo_pdf_surface_emit_stitched_colorgradient (surface, + 4, + pad_stops, + FALSE, + color_function); + if (unlikely (status)) + goto BAIL; + + if (emit_alpha) { + status = _cairo_pdf_surface_emit_stitched_colorgradient (surface, + 4, + pad_stops, + TRUE, + alpha_function); + if (unlikely (status)) + goto BAIL; + } + } else if (n_stops == 2) { + /* no need for stitched function */ + status = cairo_pdf_surface_emit_rgb_linear_function (surface, + &stops[0], + &stops[n_stops - 1], + color_function); + if (unlikely (status)) + goto BAIL; + + if (emit_alpha) { + status = cairo_pdf_surface_emit_alpha_linear_function (surface, + &stops[0], + &stops[n_stops - 1], + alpha_function); + if (unlikely (status)) + goto BAIL; + } + } else { + /* multiple stops: stitch. XXX possible optimization: regularly spaced + * stops do not require stitching. XXX */ + status = _cairo_pdf_surface_emit_stitched_colorgradient (surface, + n_stops, + stops, + FALSE, + color_function); + if (unlikely (status)) + goto BAIL; + + if (emit_alpha) { + status = _cairo_pdf_surface_emit_stitched_colorgradient (surface, + n_stops, + stops, + TRUE, + alpha_function); + if (unlikely (status)) + goto BAIL; + } + } + +BAIL: + free (allstops); + return status; +} + +static cairo_int_status_t +_cairo_pdf_surface_emit_repeating_function (cairo_pdf_surface_t *surface, + cairo_gradient_pattern_t *pattern, + cairo_pdf_resource_t *function, + int begin, + int end) +{ + cairo_pdf_resource_t res; + int i; + + res = _cairo_pdf_surface_new_object (surface); + if (res.id == 0) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n" + "<< /FunctionType 3\n" + " /Domain [ %d %d ]\n", + res.id, + begin, + end); + + _cairo_output_stream_printf (surface->output, + " /Functions [ "); + for (i = begin; i < end; i++) + _cairo_output_stream_printf (surface->output, + "%d 0 R ", function->id); + _cairo_output_stream_printf (surface->output, + "]\n"); + + _cairo_output_stream_printf (surface->output, + " /Bounds [ "); + for (i = begin + 1; i < end; i++) + _cairo_output_stream_printf (surface->output, + "%d ", i); + _cairo_output_stream_printf (surface->output, + "]\n"); + + _cairo_output_stream_printf (surface->output, + " /Encode [ "); + for (i = begin; i < end; i++) { + if ((i % 2) && pattern->base.extend == CAIRO_EXTEND_REFLECT) { + _cairo_output_stream_printf (surface->output, + "1 0 "); + } else { + _cairo_output_stream_printf (surface->output, + "0 1 "); + } + } + _cairo_output_stream_printf (surface->output, + "]\n"); + + _cairo_output_stream_printf (surface->output, + ">>\n" + "endobj\n"); + + *function = res; + + return _cairo_output_stream_get_status (surface->output); +} + +static cairo_int_status_t +cairo_pdf_surface_emit_transparency_group (cairo_pdf_surface_t *surface, + cairo_pdf_pattern_t *pdf_pattern, + cairo_pdf_resource_t gstate_resource, + cairo_pdf_resource_t gradient_mask) +{ + cairo_pdf_resource_t smask_resource; + cairo_int_status_t status; + char buf[100]; + double x1, y1, x2, y2; + + if (pdf_pattern->is_shading) { + snprintf(buf, sizeof(buf), + " /Shading\n" + " << /sh%d %d 0 R >>\n", + gradient_mask.id, + gradient_mask.id); + } else { + snprintf(buf, sizeof(buf), + " /Pattern\n" + " << /p%d %d 0 R >>\n", + gradient_mask.id, + gradient_mask.id); + } + + if (pdf_pattern->is_shading) { + cairo_box_t box; + + /* When emitting a shading operator we are in cairo pattern + * coordinates. _cairo_pdf_surface_paint_gradient has set the + * ctm to the pattern matrix (including the conversion from + * pdf to cairo coordinates) */ + _cairo_box_from_rectangle (&box, &pdf_pattern->extents); + _cairo_box_to_doubles (&box, &x1, &y1, &x2, &y2); + _cairo_matrix_transform_bounding_box (&pdf_pattern->pattern->matrix, &x1, &y1, &x2, &y2, NULL); + } else { + cairo_box_double_t box; + + /* When emitting a shading pattern we are in pdf page + * coordinates. The color and alpha shading patterns painted + * in the XObject below contain the cairo pattern to pdf page + * matrix in the /Matrix entry of the pattern. */ + _get_bbox_from_extents (&pdf_pattern->extents, &box); + x1 = box.p1.x; + y1 = box.p1.y; + x2 = box.p2.x; + y2 = box.p2.y; + } + status = _cairo_pdf_surface_open_stream (surface, + NULL, + surface->compress_streams, + " /Type /XObject\n" + " /Subtype /Form\n" + " /FormType 1\n" + " /BBox [ %f %f %f %f ]\n" + " /Resources\n" + " << /ExtGState\n" + " << /a0 << /ca 1 /CA 1 >>" + " >>\n" + "%s" + " >>\n" + " /Group\n" + " << /Type /Group\n" + " /S /Transparency\n" + " /I true\n" + " /CS /DeviceGray\n" + " >>\n", + x1,y1,x2,y2, + buf); + if (unlikely (status)) + return status; + + if (pdf_pattern->is_shading) { + _cairo_output_stream_printf (surface->output, + "/a0 gs /sh%d sh\n", + gradient_mask.id); + } else { + _cairo_output_stream_printf (surface->output, + "q\n" + "/a0 gs\n" + "/Pattern cs /p%d scn\n" + "0 0 %f %f re\n" + "f\n" + "Q\n", + gradient_mask.id, + surface->width, + surface->height); + } + + status = _cairo_pdf_surface_close_stream (surface); + if (unlikely (status)) + return status; + + smask_resource = _cairo_pdf_surface_new_object (surface); + if (smask_resource.id == 0) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n" + "<< /Type /Mask\n" + " /S /Luminosity\n" + " /G %d 0 R\n" + ">>\n" + "endobj\n", + smask_resource.id, + surface->pdf_stream.self.id); + + /* Create GState which uses the transparency group as an SMask. */ + _cairo_pdf_surface_update_object (surface, gstate_resource); + + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n" + "<< /Type /ExtGState\n" + " /SMask %d 0 R\n" + " /ca 1\n" + " /CA 1\n" + " /AIS false\n" + ">>\n" + "endobj\n", + gstate_resource.id, + smask_resource.id); + + return _cairo_output_stream_get_status (surface->output); +} + +static void +_cairo_pdf_surface_output_gradient (cairo_pdf_surface_t *surface, + const cairo_pdf_pattern_t *pdf_pattern, + cairo_pdf_resource_t pattern_resource, + const cairo_matrix_t *pat_to_pdf, + const cairo_circle_double_t*start, + const cairo_circle_double_t*end, + const double *domain, + const char *colorspace, + cairo_pdf_resource_t color_function) +{ + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n", + pattern_resource.id); + + if (!pdf_pattern->is_shading) { + _cairo_output_stream_printf (surface->output, + "<< /Type /Pattern\n" + " /PatternType 2\n" + " /Matrix [ "); + _cairo_output_stream_print_matrix (surface->output, pat_to_pdf); + _cairo_output_stream_printf (surface->output, + " ]\n" + " /Shading\n"); + } + + if (pdf_pattern->pattern->type == CAIRO_PATTERN_TYPE_LINEAR) { + _cairo_output_stream_printf (surface->output, + " << /ShadingType 2\n" + " /ColorSpace %s\n" + " /Coords [ %f %f %f %f ]\n", + colorspace, + start->center.x, start->center.y, + end->center.x, end->center.y); + } else { + _cairo_output_stream_printf (surface->output, + " << /ShadingType 3\n" + " /ColorSpace %s\n" + " /Coords [ %f %f %f %f %f %f ]\n", + colorspace, + start->center.x, start->center.y, + MAX (start->radius, 0), + end->center.x, end->center.y, + MAX (end->radius, 0)); + } + + _cairo_output_stream_printf (surface->output, + " /Domain [ %f %f ]\n", + domain[0], domain[1]); + + if (pdf_pattern->pattern->extend != CAIRO_EXTEND_NONE) { + _cairo_output_stream_printf (surface->output, + " /Extend [ true true ]\n"); + } else { + _cairo_output_stream_printf (surface->output, + " /Extend [ false false ]\n"); + } + + _cairo_output_stream_printf (surface->output, + " /Function %d 0 R\n" + " >>\n", + color_function.id); + + if (!pdf_pattern->is_shading) { + _cairo_output_stream_printf (surface->output, + ">>\n"); + } + + _cairo_output_stream_printf (surface->output, + "endobj\n"); +} + +static cairo_int_status_t +_cairo_pdf_surface_emit_gradient (cairo_pdf_surface_t *surface, + cairo_pdf_pattern_t *pdf_pattern) +{ + cairo_gradient_pattern_t *pattern = (cairo_gradient_pattern_t *) pdf_pattern->pattern; + cairo_pdf_resource_t color_function, alpha_function; + cairo_matrix_t pat_to_pdf; + cairo_circle_double_t start, end; + double domain[2]; + cairo_int_status_t status; + cairo_matrix_t mat; + + assert (pattern->n_stops != 0); + + status = _cairo_pdf_surface_emit_pattern_stops (surface, + pattern, + &color_function, + &alpha_function); + if (unlikely (status)) + return status; + + pat_to_pdf = pattern->base.matrix; + status = cairo_matrix_invert (&pat_to_pdf); + /* cairo_pattern_set_matrix ensures the matrix is invertible */ + assert (status == CAIRO_INT_STATUS_SUCCESS); + + if (pdf_pattern->inverted_y_axis) + cairo_matrix_init (&mat, 1, 0, 0, 1, 0, 0); + else + cairo_matrix_init (&mat, 1, 0, 0, -1, 0, surface->height); + + cairo_matrix_multiply (&pat_to_pdf, &pat_to_pdf, &mat); + + if (pattern->base.extend == CAIRO_EXTEND_REPEAT || + pattern->base.extend == CAIRO_EXTEND_REFLECT) + { + double bounds_x1, bounds_x2, bounds_y1, bounds_y2; + double x_scale, y_scale, tolerance; + + /* TODO: use tighter extents */ + bounds_x1 = 0; + bounds_y1 = 0; + bounds_x2 = surface->width; + bounds_y2 = surface->height; + _cairo_matrix_transform_bounding_box (&pattern->base.matrix, + &bounds_x1, &bounds_y1, + &bounds_x2, &bounds_y2, + NULL); + + x_scale = surface->base.x_resolution / surface->base.x_fallback_resolution; + y_scale = surface->base.y_resolution / surface->base.y_fallback_resolution; + + tolerance = fabs (_cairo_matrix_compute_determinant (&pattern->base.matrix)); + tolerance /= _cairo_matrix_transformed_circle_major_axis (&pattern->base.matrix, 1); + tolerance *= MIN (x_scale, y_scale); + + _cairo_gradient_pattern_box_to_parameter (pattern, + bounds_x1, bounds_y1, + bounds_x2, bounds_y2, + tolerance, domain); + } else if (pattern->stops[0].offset == pattern->stops[pattern->n_stops - 1].offset) { + /* + * If the first and the last stop offset are the same, then + * the color function is a step function. + * _cairo_ps_surface_emit_pattern_stops emits it as a stitched + * function no matter how many stops the pattern has. The + * domain of the stitched function will be [0 1] in this case. + * + * This is done to avoid emitting degenerate gradients for + * EXTEND_PAD patterns having a step color function. + */ + domain[0] = 0.0; + domain[1] = 1.0; + + assert (pattern->base.extend == CAIRO_EXTEND_PAD); + } else { + domain[0] = pattern->stops[0].offset; + domain[1] = pattern->stops[pattern->n_stops - 1].offset; + } + + /* PDF requires the first and last stop to be the same as the + * extreme coordinates. For repeating patterns this moves the + * extreme coordinates out to the begin/end of the repeating + * function. For non repeating patterns this may move the extreme + * coordinates in if there are not stops at offset 0 and 1. */ + _cairo_gradient_pattern_interpolate (pattern, domain[0], &start); + _cairo_gradient_pattern_interpolate (pattern, domain[1], &end); + + if (pattern->base.extend == CAIRO_EXTEND_REPEAT || + pattern->base.extend == CAIRO_EXTEND_REFLECT) + { + int repeat_begin, repeat_end; + + repeat_begin = floor (domain[0]); + repeat_end = ceil (domain[1]); + + status = _cairo_pdf_surface_emit_repeating_function (surface, + pattern, + &color_function, + repeat_begin, + repeat_end); + if (unlikely (status)) + return status; + + if (alpha_function.id != 0) { + status = _cairo_pdf_surface_emit_repeating_function (surface, + pattern, + &alpha_function, + repeat_begin, + repeat_end); + if (unlikely (status)) + return status; + } + } else if (pattern->n_stops <= 2) { + /* For EXTEND_NONE and EXTEND_PAD if there are only two stops a + * Type 2 function is used by itself without a stitching + * function. Type 2 functions always have the domain [0 1] */ + domain[0] = 0.0; + domain[1] = 1.0; + } + + _cairo_pdf_surface_update_object (surface, pdf_pattern->pattern_res); + _cairo_pdf_surface_output_gradient (surface, pdf_pattern, + pdf_pattern->pattern_res, + &pat_to_pdf, &start, &end, domain, + "/DeviceRGB", color_function); + + if (alpha_function.id != 0) { + cairo_pdf_resource_t mask_resource; + + assert (pdf_pattern->gstate_res.id != 0); + + /* Create pattern for SMask. */ + mask_resource = _cairo_pdf_surface_new_object (surface); + if (mask_resource.id == 0) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + _cairo_pdf_surface_output_gradient (surface, pdf_pattern, + mask_resource, + &pat_to_pdf, &start, &end, domain, + "/DeviceGray", alpha_function); + + status = cairo_pdf_surface_emit_transparency_group (surface, + pdf_pattern, + pdf_pattern->gstate_res, + mask_resource); + if (unlikely (status)) + return status; + } + + return _cairo_output_stream_get_status (surface->output); +} + +static cairo_int_status_t +_cairo_pdf_surface_emit_mesh_pattern (cairo_pdf_surface_t *surface, + cairo_pdf_pattern_t *pdf_pattern) +{ + cairo_matrix_t pat_to_pdf; + cairo_int_status_t status; + cairo_pattern_t *pattern = pdf_pattern->pattern; + cairo_pdf_shading_t shading; + int i; + cairo_pdf_resource_t res; + cairo_matrix_t mat; + + pat_to_pdf = pattern->matrix; + status = cairo_matrix_invert (&pat_to_pdf); + /* cairo_pattern_set_matrix ensures the matrix is invertible */ + assert (status == CAIRO_INT_STATUS_SUCCESS); + + if (pdf_pattern->inverted_y_axis) + cairo_matrix_init (&mat, 1, 0, 0, 1, 0, 0); + else + cairo_matrix_init (&mat, 1, 0, 0, -1, 0, surface->height); + + cairo_matrix_multiply (&pat_to_pdf, &pat_to_pdf, &mat); + + status = _cairo_pdf_shading_init_color (&shading, (cairo_mesh_pattern_t *) pattern); + if (unlikely (status)) + return status; + + res = _cairo_pdf_surface_new_object (surface); + if (unlikely (res.id == 0)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n" + "<< /ShadingType %d\n" + " /ColorSpace /DeviceRGB\n" + " /BitsPerCoordinate %d\n" + " /BitsPerComponent %d\n" + " /BitsPerFlag %d\n" + " /Decode [", + res.id, + shading.shading_type, + shading.bits_per_coordinate, + shading.bits_per_component, + shading.bits_per_flag); + + for (i = 0; i < shading.decode_array_length; i++) + _cairo_output_stream_printf (surface->output, "%f ", shading.decode_array[i]); + + _cairo_output_stream_printf (surface->output, + "]\n" + " /Length %ld\n" + ">>\n" + "stream\n", + shading.data_length); + + _cairo_output_stream_write (surface->output, shading.data, shading.data_length); + + _cairo_output_stream_printf (surface->output, + "\nendstream\n" + "endobj\n"); + + _cairo_pdf_shading_fini (&shading); + + _cairo_pdf_surface_update_object (surface, pdf_pattern->pattern_res); + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n" + "<< /Type /Pattern\n" + " /PatternType 2\n" + " /Matrix [ ", + pdf_pattern->pattern_res.id); + _cairo_output_stream_print_matrix (surface->output, &pat_to_pdf); + _cairo_output_stream_printf (surface->output, + " ]\n" + " /Shading %d 0 R\n" + ">>\n" + "endobj\n", + res.id); + + if (pdf_pattern->gstate_res.id != 0) { + cairo_pdf_resource_t mask_resource; + + /* Create pattern for SMask. */ + res = _cairo_pdf_surface_new_object (surface); + if (unlikely (res.id == 0)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + status = _cairo_pdf_shading_init_alpha (&shading, (cairo_mesh_pattern_t *) pattern); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n" + "<< /ShadingType %d\n" + " /ColorSpace /DeviceGray\n" + " /BitsPerCoordinate %d\n" + " /BitsPerComponent %d\n" + " /BitsPerFlag %d\n" + " /Decode [", + res.id, + shading.shading_type, + shading.bits_per_coordinate, + shading.bits_per_component, + shading.bits_per_flag); + + for (i = 0; i < shading.decode_array_length; i++) + _cairo_output_stream_printf (surface->output, "%f ", shading.decode_array[i]); + + _cairo_output_stream_printf (surface->output, + "]\n" + " /Length %ld\n" + ">>\n" + "stream\n", + shading.data_length); + + _cairo_output_stream_write (surface->output, shading.data, shading.data_length); + + _cairo_output_stream_printf (surface->output, + "\nendstream\n" + "endobj\n"); + _cairo_pdf_shading_fini (&shading); + + mask_resource = _cairo_pdf_surface_new_object (surface); + if (unlikely (mask_resource.id == 0)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n" + "<< /Type /Pattern\n" + " /PatternType 2\n" + " /Matrix [ ", + mask_resource.id); + _cairo_output_stream_print_matrix (surface->output, &pat_to_pdf); + _cairo_output_stream_printf (surface->output, + " ]\n" + " /Shading %d 0 R\n" + ">>\n" + "endobj\n", + res.id); + + status = cairo_pdf_surface_emit_transparency_group (surface, + pdf_pattern, + pdf_pattern->gstate_res, + mask_resource); + if (unlikely (status)) + return status; + } + + return _cairo_output_stream_get_status (surface->output); +} + +static cairo_int_status_t +_cairo_pdf_surface_emit_pattern (cairo_pdf_surface_t *surface, cairo_pdf_pattern_t *pdf_pattern) +{ + cairo_int_status_t status; + + switch (pdf_pattern->pattern->type) { + case CAIRO_PATTERN_TYPE_SOLID: + ASSERT_NOT_REACHED; + status = _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH); + break; + + case CAIRO_PATTERN_TYPE_SURFACE: + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + status = _cairo_pdf_surface_emit_surface_pattern (surface, pdf_pattern); + break; + + case CAIRO_PATTERN_TYPE_LINEAR: + case CAIRO_PATTERN_TYPE_RADIAL: + status = _cairo_pdf_surface_emit_gradient (surface, pdf_pattern); + break; + + case CAIRO_PATTERN_TYPE_MESH: + status = _cairo_pdf_surface_emit_mesh_pattern (surface, pdf_pattern); + break; + + default: + ASSERT_NOT_REACHED; + status = _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH); + break; + } + + return status; +} + +static cairo_int_status_t +_cairo_pdf_surface_paint_surface_pattern (cairo_pdf_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_analysis_source_t source_type, + const cairo_rectangle_int_t *extents, + double alpha, + cairo_pdf_resource_t *smask_res, + cairo_bool_t stencil_mask) +{ + cairo_matrix_t cairo_p2d, pdf_p2d; + cairo_int_status_t status; + int alpha_id; + double x_offset; + double y_offset; + cairo_pdf_source_surface_entry_t *pdf_source; + int region_id = 0; + + if (source->extend == CAIRO_EXTEND_PAD && + !(source->type == CAIRO_PATTERN_TYPE_SURFACE && + ((cairo_surface_pattern_t *)source)->surface->type == CAIRO_SURFACE_TYPE_RECORDING)) + { + status = _cairo_pdf_surface_add_padded_image_surface (surface, + source, + extents, + &pdf_source, + &x_offset, + &y_offset, + NULL); + } else { + if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { + cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) source; + if (_cairo_pdf_interchange_struct_tree_requires_recording_surface (surface, + surface_pattern, + source_type)) + { + region_id = surface_pattern->region_array_id; + } + } + status = _cairo_pdf_surface_add_source_surface (surface, + NULL, + source, + region_id, + op, + source->filter, + stencil_mask, + FALSE, /* smask */ + alpha != 1.0, /* need_transp_group */ + extents, + smask_res, + + &pdf_source, + &x_offset, + &y_offset, + NULL); + } + if (unlikely (status)) + return status; + + cairo_p2d = source->matrix; + status = cairo_matrix_invert (&cairo_p2d); + /* cairo_pattern_set_matrix ensures the matrix is invertible */ + assert (status == CAIRO_INT_STATUS_SUCCESS); + + pdf_p2d = surface->cairo_to_pdf; + cairo_matrix_multiply (&pdf_p2d, &cairo_p2d, &pdf_p2d); + cairo_matrix_translate (&pdf_p2d, x_offset, y_offset); + if (pdf_source->emit_image) { + int width, height; + + if (pdf_source->bounded) { + width = pdf_source->extents.width; + height = pdf_source->extents.height; + } else { + /* We can't scale an image to an unbounded surface size so just set the size to 1 */ + width = 1; + height = 1; + } + + cairo_matrix_translate (&pdf_p2d, 0.0, height); + cairo_matrix_scale (&pdf_p2d, 1.0, -1.0); + cairo_matrix_scale (&pdf_p2d, width, height); + } + + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (unlikely (status)) + return status; + + if (! _cairo_matrix_is_identity (&pdf_p2d)) { + _cairo_output_stream_print_matrix (surface->output, &pdf_p2d); + _cairo_output_stream_printf (surface->output, " cm\n"); + } + + status = _cairo_pdf_surface_add_alpha (surface, alpha, &alpha_id); + if (unlikely (status)) + return status; + + if (stencil_mask) { + _cairo_output_stream_printf (surface->output, + "/x%d Do\n", + pdf_source->surface_res.id); + } else { + _cairo_output_stream_printf (surface->output, + "/a%d gs /x%d Do\n", + alpha_id, + pdf_source->surface_res.id); + } + + return _cairo_pdf_surface_add_xobject (surface, pdf_source->surface_res); +} + +static cairo_int_status_t +_cairo_pdf_surface_paint_gradient (cairo_pdf_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_rectangle_int_t *extents, + double alpha) +{ + cairo_pdf_resource_t shading_res, gstate_res; + cairo_matrix_t pat_to_pdf; + cairo_int_status_t status; + int alpha_id; + + status = _cairo_pdf_surface_add_pdf_shading (surface, source, + op, extents, + &shading_res, &gstate_res); + if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO)) + return CAIRO_INT_STATUS_SUCCESS; + if (unlikely (status)) + return status; + + pat_to_pdf = source->matrix; + status = cairo_matrix_invert (&pat_to_pdf); + /* cairo_pattern_set_matrix ensures the matrix is invertible */ + assert (status == CAIRO_INT_STATUS_SUCCESS); + cairo_matrix_multiply (&pat_to_pdf, &pat_to_pdf, &surface->cairo_to_pdf); + + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (unlikely (status)) + return status; + + if (! _cairo_matrix_is_identity (&pat_to_pdf)) { + _cairo_output_stream_print_matrix (surface->output, &pat_to_pdf); + _cairo_output_stream_printf (surface->output, " cm\n"); + } + + status = _cairo_pdf_surface_add_shading (surface, shading_res); + if (unlikely (status)) + return status; + + if (gstate_res.id != 0) { + status = _cairo_pdf_surface_add_smask (surface, gstate_res); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->output, + "/s%d gs /sh%d sh\n", + gstate_res.id, + shading_res.id); + } else { + status = _cairo_pdf_surface_add_alpha (surface, alpha, &alpha_id); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->output, + "/a%d gs /sh%d sh\n", + alpha_id, + shading_res.id); + } + + return status; +} + +static cairo_int_status_t +_cairo_pdf_surface_paint_pattern (cairo_pdf_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_analysis_source_t source_type, + const cairo_rectangle_int_t *extents, + double alpha, + cairo_bool_t mask) +{ + switch (source->type) { + case CAIRO_PATTERN_TYPE_SURFACE: + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + return _cairo_pdf_surface_paint_surface_pattern (surface, + op, + source, + source_type, + extents, + alpha, + NULL, + mask); + case CAIRO_PATTERN_TYPE_LINEAR: + case CAIRO_PATTERN_TYPE_RADIAL: + case CAIRO_PATTERN_TYPE_MESH: + return _cairo_pdf_surface_paint_gradient (surface, + op, + source, + extents, + alpha); + + case CAIRO_PATTERN_TYPE_SOLID: + default: + ASSERT_NOT_REACHED; + return CAIRO_STATUS_SUCCESS; + } +} + +static cairo_bool_t +_can_paint_pattern (const cairo_pattern_t *pattern) +{ + switch (pattern->type) { + case CAIRO_PATTERN_TYPE_SOLID: + return FALSE; + + case CAIRO_PATTERN_TYPE_SURFACE: + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + return (pattern->extend == CAIRO_EXTEND_NONE || + pattern->extend == CAIRO_EXTEND_PAD); + + case CAIRO_PATTERN_TYPE_LINEAR: + case CAIRO_PATTERN_TYPE_RADIAL: + return TRUE; + + case CAIRO_PATTERN_TYPE_MESH: + return FALSE; + + default: + ASSERT_NOT_REACHED; + return FALSE; + } +} + +static cairo_int_status_t +_cairo_pdf_surface_select_operator (cairo_pdf_surface_t *surface, + cairo_operator_t op) +{ + cairo_int_status_t status; + + if (surface->reset_gs_required) { + _cairo_output_stream_printf (surface->output, "/gs0 gs\n"); + surface->reset_gs_required = FALSE; + } + + if (op == surface->current_operator) + return CAIRO_STATUS_SUCCESS; + + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->output, + "/b%d gs\n", op); + surface->current_operator = op; + _cairo_pdf_surface_add_operator (surface, op); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_pdf_surface_select_pattern (cairo_pdf_surface_t *surface, + const cairo_pattern_t *pattern, + cairo_pdf_resource_t pattern_res, + cairo_bool_t is_stroke) +{ + cairo_int_status_t status; + int alpha; + const cairo_color_t *solid_color = NULL; + + if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) { + const cairo_solid_pattern_t *solid = (const cairo_solid_pattern_t *) pattern; + + solid_color = &solid->color; + } + + if (solid_color != NULL) { + if (surface->current_pattern_is_solid_color == FALSE || + surface->current_color_red != solid_color->red || + surface->current_color_green != solid_color->green || + surface->current_color_blue != solid_color->blue || + surface->current_color_is_stroke != is_stroke) + { + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->output, + "%f %f %f ", + solid_color->red, + solid_color->green, + solid_color->blue); + + if (is_stroke) + _cairo_output_stream_printf (surface->output, "RG "); + else + _cairo_output_stream_printf (surface->output, "rg "); + + surface->current_color_red = solid_color->red; + surface->current_color_green = solid_color->green; + surface->current_color_blue = solid_color->blue; + surface->current_color_is_stroke = is_stroke; + } + + if (surface->current_pattern_is_solid_color == FALSE || + surface->current_color_alpha != solid_color->alpha) + { + status = _cairo_pdf_surface_add_alpha (surface, solid_color->alpha, &alpha); + if (unlikely (status)) + return status; + + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->output, + "/a%d gs\n", + alpha); + surface->current_color_alpha = solid_color->alpha; + } + + surface->current_pattern_is_solid_color = TRUE; + } else { + status = _cairo_pdf_surface_add_alpha (surface, 1.0, &alpha); + if (unlikely (status)) + return status; + + status = _cairo_pdf_surface_add_pattern (surface, pattern_res); + if (unlikely (status)) + return status; + + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (unlikely (status)) + return status; + + /* fill-stroke calls select_pattern twice. Don't save if the + * gstate is already saved. */ + if (!surface->select_pattern_gstate_saved) + _cairo_output_stream_printf (surface->output, "q "); + + if (is_stroke) { + _cairo_output_stream_printf (surface->output, + "/Pattern CS /p%d SCN ", + pattern_res.id); + } else { + _cairo_output_stream_printf (surface->output, + "/Pattern cs /p%d scn ", + pattern_res.id); + } + _cairo_output_stream_printf (surface->output, + "/a%d gs\n", + alpha); + surface->select_pattern_gstate_saved = TRUE; + surface->current_pattern_is_solid_color = FALSE; + } + + return _cairo_output_stream_get_status (surface->output); +} + +static cairo_int_status_t +_cairo_pdf_surface_unselect_pattern (cairo_pdf_surface_t *surface) +{ + cairo_int_status_t status; + + if (surface->select_pattern_gstate_saved) { + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->output, "Q\n"); + _cairo_pdf_operators_reset (&surface->pdf_operators); + surface->current_pattern_is_solid_color = FALSE; + } + surface->select_pattern_gstate_saved = FALSE; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_pdf_surface_show_page (void *abstract_surface) +{ + cairo_pdf_surface_t *surface = abstract_surface; + cairo_int_status_t status; + + status = _cairo_array_append (&surface->page_labels, &surface->current_page_label); + if (unlikely (status)) + return status; + + surface->current_page_label = NULL; + + status = _cairo_pdf_interchange_end_page_content (surface); + if (unlikely (status)) + return status; + + status = _cairo_pdf_surface_close_content_stream (surface, FALSE); + if (unlikely (status)) + return status; + + _cairo_surface_clipper_reset (&surface->clipper); + + status = _cairo_pdf_surface_write_page (surface); + if (unlikely (status)) + return status; + + _cairo_pdf_surface_clear (surface, FALSE); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_bool_t +_cairo_pdf_surface_get_extents (void *abstract_surface, + cairo_rectangle_int_t *rectangle) +{ + cairo_pdf_surface_t *surface = abstract_surface; + + if (surface->surface_bounded) + *rectangle = surface->surface_extents; + + return surface->surface_bounded; +} + +static void +_cairo_pdf_surface_get_font_options (void *abstract_surface, + cairo_font_options_t *options) +{ + _cairo_font_options_init_default (options); + + cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE); + cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF); + cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_GRAY); + _cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_OFF); +} + +static cairo_int_status_t +_cairo_pdf_surface_write_pages (cairo_pdf_surface_t *surface) +{ + cairo_pdf_page_info_t *page_info; + int num_pages, i; + cairo_int_status_t status; + + status = _cairo_pdf_surface_object_begin (surface, surface->pages_resource); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->object_stream.stream, + "<< /Type /Pages\n" + " /Kids [ "); + + num_pages = _cairo_array_num_elements (&surface->pages); + for (i = 0; i < num_pages; i++) { + page_info = _cairo_array_index (&surface->pages, i); + _cairo_output_stream_printf (surface->object_stream.stream, "%d 0 R ", page_info->page_res.id); + } + + _cairo_output_stream_printf (surface->object_stream.stream, "]\n"); + _cairo_output_stream_printf (surface->object_stream.stream, " /Count %d\n", num_pages); + + + /* TODO: Figure out which other defaults to be inherited by /Page + * objects. */ + _cairo_output_stream_printf (surface->object_stream.stream, + ">>\n"); + _cairo_pdf_surface_object_end (surface); + + return CAIRO_INT_STATUS_SUCCESS; +} + +cairo_int_status_t +_cairo_utf8_to_pdf_string (const char *utf8, char **str_out) +{ + int i; + int len; + unsigned char *p; + cairo_bool_t ascii; + char *str; + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + + ascii = TRUE; + p = (unsigned char *)utf8; + len = 0; + while (*p) { + if (*p < 32 || *p > 126) { + ascii = FALSE; + break; + } + if (*p == '(' || *p == ')' || *p == '\\') + len += 2; + else + len++; + p++; + } + + if (ascii) { + str = _cairo_malloc (len + 3); + if (str == NULL) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + str[0] = '('; + p = (unsigned char *)utf8; + i = 1; + while (*p) { + if (*p == '(' || *p == ')' || *p == '\\') + str[i++] = '\\'; + str[i++] = *p; + p++; + } + str[i++] = ')'; + str[i++] = 0; + } else { + uint16_t *utf16 = NULL; + int utf16_len = 0; + + status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &utf16_len); + if (unlikely (status)) + return status; + + str = _cairo_malloc (utf16_len*4 + 7); + if (str == NULL) { + free (utf16); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + strcpy (str, ""); + free (utf16); + } + *str_out = str; + + return status; +} + +static cairo_int_status_t +_cairo_pdf_surface_emit_unicode_for_glyph (cairo_pdf_surface_t *surface, + const char *utf8) +{ + uint16_t *utf16 = NULL; + int utf16_len = 0; + cairo_int_status_t status; + int i; + + if (utf8 && *utf8) { + status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &utf16_len); + if (unlikely (status == CAIRO_INT_STATUS_INVALID_STRING)) { + utf16 = NULL; + utf16_len = 0; + } else if (unlikely (status)) { + return status; + } + } + + _cairo_output_stream_printf (surface->output, "<"); + if (utf16 == NULL || utf16_len == 0) { + /* According to the "ToUnicode Mapping File Tutorial" + * http://www.adobe.com/devnet/acrobat/pdfs/5411.ToUnicode.pdf + * + * Glyphs that do not map to a Unicode code point must be + * mapped to 0xfffd "REPLACEMENT CHARACTER". + */ + _cairo_output_stream_printf (surface->output, + "fffd"); + } else { + for (i = 0; i < utf16_len; i++) + _cairo_output_stream_printf (surface->output, + "%04x", (int) (utf16[i])); + } + _cairo_output_stream_printf (surface->output, ">"); + + free (utf16); + + return CAIRO_STATUS_SUCCESS; +} + +/* Bob Jenkins hash + * + * Public domain code from: + * http://burtleburtle.net/bob/hash/doobs.html + */ + +#define HASH_MIX(a,b,c) \ +{ \ + a -= b; a -= c; a ^= (c>>13); \ + b -= c; b -= a; b ^= (a<<8); \ + c -= a; c -= b; c ^= (b>>13); \ + a -= b; a -= c; a ^= (c>>12); \ + b -= c; b -= a; b ^= (a<<16); \ + c -= a; c -= b; c ^= (b>>5); \ + a -= b; a -= c; a ^= (c>>3); \ + b -= c; b -= a; b ^= (a<<10); \ + c -= a; c -= b; c ^= (b>>15); \ +} + +static uint32_t +_hash_data (const unsigned char *data, int length, uint32_t initval) +{ + uint32_t a, b, c, len; + + len = length; + a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */ + c = initval; /* the previous hash value */ + + while (len >= 12) { + a += (data[0] + ((uint32_t)data[1]<<8) + ((uint32_t)data[2]<<16) + ((uint32_t)data[3]<<24)); + b += (data[4] + ((uint32_t)data[5]<<8) + ((uint32_t)data[6]<<16) + ((uint32_t)data[7]<<24)); + c += (data[8] + ((uint32_t)data[9]<<8) + ((uint32_t)data[10]<<16)+ ((uint32_t)data[11]<<24)); + HASH_MIX (a,b,c); + data += 12; + len -= 12; + } + + c += length; + switch(len) { + case 11: c+= ((uint32_t) data[10] << 24); /* fall through */ + case 10: c+= ((uint32_t) data[9] << 16); /* fall through */ + case 9 : c+= ((uint32_t) data[8] << 8); /* fall through */ + case 8 : b+= ((uint32_t) data[7] << 24); /* fall through */ + case 7 : b+= ((uint32_t) data[6] << 16); /* fall through */ + case 6 : b+= ((uint32_t) data[5] << 8); /* fall through */ + case 5 : b+= data[4]; /* fall through */ + case 4 : a+= ((uint32_t) data[3] << 24); /* fall through */ + case 3 : a+= ((uint32_t) data[2] << 16); /* fall through */ + case 2 : a+= ((uint32_t) data[1] << 8); /* fall through */ + case 1 : a+= data[0]; + } + HASH_MIX (a,b,c); + + return c; +} + +static void +_create_font_subset_tag (cairo_scaled_font_subset_t *font_subset, + const char *font_name, + char *tag) +{ + uint32_t hash; + int i; + + hash = _hash_data ((unsigned char *) font_name, strlen(font_name), 0); + hash = _hash_data ((unsigned char *) (font_subset->glyphs), + font_subset->num_glyphs * sizeof(unsigned long), hash); + + for (i = 0; i < 6; i++) { + tag[i] = 'A' + (hash % 26); + hash /= 26; + } + tag[i] = 0; +} + +static cairo_int_status_t +_cairo_pdf_surface_emit_to_unicode_stream (cairo_pdf_surface_t *surface, + cairo_scaled_font_subset_t *font_subset, + cairo_pdf_resource_t *stream) +{ + unsigned int i, num_bfchar; + cairo_int_status_t status; + + stream->id = 0; + + status = _cairo_pdf_surface_open_stream (surface, + NULL, + surface->compress_streams, + NULL); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->output, + "/CIDInit /ProcSet findresource begin\n" + "12 dict begin\n" + "begincmap\n" + "/CIDSystemInfo\n" + "<< /Registry (Adobe)\n" + " /Ordering (UCS)\n" + " /Supplement 0\n" + ">> def\n" + "/CMapName /Adobe-Identity-UCS def\n" + "/CMapType 2 def\n" + "1 begincodespacerange\n"); + + if (font_subset->is_composite && !font_subset->is_latin) { + _cairo_output_stream_printf (surface->output, + "<0000> \n"); + } else { + _cairo_output_stream_printf (surface->output, + "<00> \n"); + } + + _cairo_output_stream_printf (surface->output, + "endcodespacerange\n"); + + if (font_subset->is_scaled) { + /* Type 3 fonts include glyph 0 in the subset */ + num_bfchar = font_subset->num_glyphs; + + /* The CMap specification has a limit of 100 characters per beginbfchar operator */ + _cairo_output_stream_printf (surface->output, + "%d beginbfchar\n", + num_bfchar > 100 ? 100 : num_bfchar); + + for (i = 0; i < num_bfchar; i++) { + if (i != 0 && i % 100 == 0) { + _cairo_output_stream_printf (surface->output, + "endbfchar\n" + "%d beginbfchar\n", + num_bfchar - i > 100 ? 100 : num_bfchar - i); + } + _cairo_output_stream_printf (surface->output, "<%02x> ", i); + status = _cairo_pdf_surface_emit_unicode_for_glyph (surface, + font_subset->utf8[i]); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->output, + "\n"); + } + } else { + /* Other fonts reserve glyph 0 for .notdef. Omit glyph 0 from the /ToUnicode map */ + num_bfchar = font_subset->num_glyphs - 1; + + /* The CMap specification has a limit of 100 characters per beginbfchar operator */ + _cairo_output_stream_printf (surface->output, + "%d beginbfchar\n", + num_bfchar > 100 ? 100 : num_bfchar); + + for (i = 0; i < num_bfchar; i++) { + if (i != 0 && i % 100 == 0) { + _cairo_output_stream_printf (surface->output, + "endbfchar\n" + "%d beginbfchar\n", + num_bfchar - i > 100 ? 100 : num_bfchar - i); + } + if (font_subset->is_latin) + _cairo_output_stream_printf (surface->output, "<%02x> ", font_subset->to_latin_char[i + 1]); + else if (font_subset->is_composite) + _cairo_output_stream_printf (surface->output, "<%04x> ", i + 1); + else + _cairo_output_stream_printf (surface->output, "<%02x> ", i + 1); + + status = _cairo_pdf_surface_emit_unicode_for_glyph (surface, + font_subset->utf8[i + 1]); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->output, + "\n"); + } + } + + _cairo_output_stream_printf (surface->output, + "endbfchar\n"); + + _cairo_output_stream_printf (surface->output, + "endcmap\n" + "CMapName currentdict /CMap defineresource pop\n" + "end\n" + "end\n"); + + *stream = surface->pdf_stream.self; + return _cairo_pdf_surface_close_stream (surface); +} + +#define PDF_UNITS_PER_EM 1000 + +static cairo_int_status_t +_cairo_pdf_surface_emit_cff_font (cairo_pdf_surface_t *surface, + cairo_scaled_font_subset_t *font_subset, + cairo_cff_subset_t *subset) +{ + cairo_pdf_resource_t stream, descriptor, cidfont_dict; + cairo_pdf_resource_t subset_resource, to_unicode_stream; + cairo_pdf_font_t font; + unsigned int i, last_glyph; + cairo_int_status_t status; + char tag[10]; + + _create_font_subset_tag (font_subset, subset->ps_name, tag); + + subset_resource = _cairo_pdf_surface_get_font_resource (surface, + font_subset->font_id, + font_subset->subset_id); + if (subset_resource.id == 0) + return CAIRO_STATUS_SUCCESS; + + status = _cairo_pdf_surface_open_stream (surface, + NULL, + TRUE, + font_subset->is_latin ? + " /Subtype /Type1C\n" : + " /Subtype /CIDFontType0C\n"); + if (unlikely (status)) + return status; + + stream = surface->pdf_stream.self; + _cairo_output_stream_write (surface->output, + subset->data, subset->data_length); + status = _cairo_pdf_surface_close_stream (surface); + if (unlikely (status)) + return status; + + status = _cairo_pdf_surface_emit_to_unicode_stream (surface, + font_subset, + &to_unicode_stream); + if (_cairo_int_status_is_error (status)) + return status; + + descriptor = _cairo_pdf_surface_new_object (surface); + if (descriptor.id == 0) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n" + "<< /Type /FontDescriptor\n" + " /FontName /%s+%s\n", + descriptor.id, + tag, + subset->ps_name); + + if (subset->family_name_utf8) { + char *pdf_str; + + status = _cairo_utf8_to_pdf_string (subset->family_name_utf8, &pdf_str); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { + _cairo_output_stream_printf (surface->output, + " /FontFamily %s\n", + pdf_str); + free (pdf_str); + } else if (status != CAIRO_INT_STATUS_INVALID_STRING) { + return status; + } + } + + _cairo_output_stream_printf (surface->output, + " /Flags 4\n" + " /FontBBox [ %ld %ld %ld %ld ]\n" + " /ItalicAngle 0\n" + " /Ascent %ld\n" + " /Descent %ld\n" + " /CapHeight %ld\n" + " /StemV 80\n" + " /StemH 80\n" + " /FontFile3 %u 0 R\n" + ">>\n" + "endobj\n", + (long)(subset->x_min*PDF_UNITS_PER_EM), + (long)(subset->y_min*PDF_UNITS_PER_EM), + (long)(subset->x_max*PDF_UNITS_PER_EM), + (long)(subset->y_max*PDF_UNITS_PER_EM), + (long)(subset->ascent*PDF_UNITS_PER_EM), + (long)(subset->descent*PDF_UNITS_PER_EM), + (long)(subset->y_max*PDF_UNITS_PER_EM), + stream.id); + + if (font_subset->is_latin) { + /* find last glyph used */ + for (i = 255; i >= 32; i--) + if (font_subset->latin_to_subset_glyph_index[i] > 0) + break; + + last_glyph = i; + _cairo_pdf_surface_update_object (surface, subset_resource); + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n" + "<< /Type /Font\n" + " /Subtype /Type1\n" + " /BaseFont /%s+%s\n" + " /FirstChar 32\n" + " /LastChar %d\n" + " /FontDescriptor %d 0 R\n" + " /Encoding /WinAnsiEncoding\n" + " /Widths [", + subset_resource.id, + tag, + subset->ps_name, + last_glyph, + descriptor.id); + + for (i = 32; i < last_glyph + 1; i++) { + int glyph = font_subset->latin_to_subset_glyph_index[i]; + if (glyph > 0) { + _cairo_output_stream_printf (surface->output, + " %f", + (subset->widths[glyph]*PDF_UNITS_PER_EM)); + } else { + _cairo_output_stream_printf (surface->output, " 0"); + } + } + + _cairo_output_stream_printf (surface->output, + " ]\n"); + + if (to_unicode_stream.id != 0) + _cairo_output_stream_printf (surface->output, + " /ToUnicode %d 0 R\n", + to_unicode_stream.id); + + _cairo_output_stream_printf (surface->output, + ">>\n" + "endobj\n"); + } else { + cidfont_dict = _cairo_pdf_surface_new_object (surface); + if (cidfont_dict.id == 0) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n" + "<< /Type /Font\n" + " /Subtype /CIDFontType0\n" + " /BaseFont /%s+%s\n" + " /CIDSystemInfo\n" + " << /Registry (Adobe)\n" + " /Ordering (Identity)\n" + " /Supplement 0\n" + " >>\n" + " /FontDescriptor %d 0 R\n" + " /W [0 [", + cidfont_dict.id, + tag, + subset->ps_name, + descriptor.id); + + for (i = 0; i < font_subset->num_glyphs; i++) + _cairo_output_stream_printf (surface->output, + " %f", + (subset->widths[i]*PDF_UNITS_PER_EM)); + + _cairo_output_stream_printf (surface->output, + " ]]\n" + ">>\n" + "endobj\n"); + + _cairo_pdf_surface_update_object (surface, subset_resource); + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n" + "<< /Type /Font\n" + " /Subtype /Type0\n" + " /BaseFont /%s+%s\n" + " /Encoding /Identity-H\n" + " /DescendantFonts [ %d 0 R]\n", + subset_resource.id, + tag, + subset->ps_name, + cidfont_dict.id); + + if (to_unicode_stream.id != 0) + _cairo_output_stream_printf (surface->output, + " /ToUnicode %d 0 R\n", + to_unicode_stream.id); + + _cairo_output_stream_printf (surface->output, + ">>\n" + "endobj\n"); + } + + font.font_id = font_subset->font_id; + font.subset_id = font_subset->subset_id; + font.subset_resource = subset_resource; + status = _cairo_array_append (&surface->fonts, &font); + + return status; +} + +static cairo_int_status_t +_cairo_pdf_surface_emit_cff_font_subset (cairo_pdf_surface_t *surface, + cairo_scaled_font_subset_t *font_subset) +{ + cairo_int_status_t status; + cairo_cff_subset_t subset; + char name[64]; + + snprintf (name, sizeof name, "CairoFont-%d-%d", + font_subset->font_id, font_subset->subset_id); + status = _cairo_cff_subset_init (&subset, name, font_subset); + if (unlikely (status)) + return status; + + status = _cairo_pdf_surface_emit_cff_font (surface, font_subset, &subset); + + _cairo_cff_subset_fini (&subset); + + return status; +} + +static cairo_int_status_t +_cairo_pdf_surface_emit_cff_fallback_font (cairo_pdf_surface_t *surface, + cairo_scaled_font_subset_t *font_subset) +{ + cairo_int_status_t status; + cairo_cff_subset_t subset; + char name[64]; + + /* CFF fallback subsetting does not work with 8-bit glyphs unless + * they are a latin subset */ + if (!font_subset->is_composite && !font_subset->is_latin) + return CAIRO_INT_STATUS_UNSUPPORTED; + + snprintf (name, sizeof name, "CairoFont-%d-%d", + font_subset->font_id, font_subset->subset_id); + status = _cairo_cff_fallback_init (&subset, name, font_subset); + if (unlikely (status)) + return status; + + status = _cairo_pdf_surface_emit_cff_font (surface, font_subset, &subset); + + _cairo_cff_fallback_fini (&subset); + + return status; +} + +static cairo_int_status_t +_cairo_pdf_surface_emit_type1_font (cairo_pdf_surface_t *surface, + cairo_scaled_font_subset_t *font_subset, + cairo_type1_subset_t *subset) +{ + cairo_pdf_resource_t stream, descriptor, subset_resource, to_unicode_stream; + cairo_pdf_font_t font; + cairo_int_status_t status; + unsigned long length; + unsigned int i, last_glyph; + char tag[10]; + + _create_font_subset_tag (font_subset, subset->base_font, tag); + + subset_resource = _cairo_pdf_surface_get_font_resource (surface, + font_subset->font_id, + font_subset->subset_id); + if (subset_resource.id == 0) + return CAIRO_STATUS_SUCCESS; + + length = subset->header_length + subset->data_length + subset->trailer_length; + status = _cairo_pdf_surface_open_stream (surface, + NULL, + TRUE, + " /Length1 %lu\n" + " /Length2 %lu\n" + " /Length3 %lu\n", + subset->header_length, + subset->data_length, + subset->trailer_length); + if (unlikely (status)) + return status; + + stream = surface->pdf_stream.self; + _cairo_output_stream_write (surface->output, subset->data, length); + status = _cairo_pdf_surface_close_stream (surface); + if (unlikely (status)) + return status; + + status = _cairo_pdf_surface_emit_to_unicode_stream (surface, + font_subset, + &to_unicode_stream); + if (_cairo_int_status_is_error (status)) + return status; + + last_glyph = font_subset->num_glyphs - 1; + if (font_subset->is_latin) { + /* find last glyph used */ + for (i = 255; i >= 32; i--) + if (font_subset->latin_to_subset_glyph_index[i] > 0) + break; + + last_glyph = i; + } + + descriptor = _cairo_pdf_surface_new_object (surface); + if (descriptor.id == 0) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n" + "<< /Type /FontDescriptor\n" + " /FontName /%s+%s\n" + " /Flags 4\n" + " /FontBBox [ %ld %ld %ld %ld ]\n" + " /ItalicAngle 0\n" + " /Ascent %ld\n" + " /Descent %ld\n" + " /CapHeight %ld\n" + " /StemV 80\n" + " /StemH 80\n" + " /FontFile %u 0 R\n" + ">>\n" + "endobj\n", + descriptor.id, + tag, + subset->base_font, + (long)(subset->x_min*PDF_UNITS_PER_EM), + (long)(subset->y_min*PDF_UNITS_PER_EM), + (long)(subset->x_max*PDF_UNITS_PER_EM), + (long)(subset->y_max*PDF_UNITS_PER_EM), + (long)(subset->ascent*PDF_UNITS_PER_EM), + (long)(subset->descent*PDF_UNITS_PER_EM), + (long)(subset->y_max*PDF_UNITS_PER_EM), + stream.id); + + _cairo_pdf_surface_update_object (surface, subset_resource); + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n" + "<< /Type /Font\n" + " /Subtype /Type1\n" + " /BaseFont /%s+%s\n" + " /FirstChar %d\n" + " /LastChar %d\n" + " /FontDescriptor %d 0 R\n", + subset_resource.id, + tag, + subset->base_font, + font_subset->is_latin ? 32 : 0, + last_glyph, + descriptor.id); + + if (font_subset->is_latin) + _cairo_output_stream_printf (surface->output, " /Encoding /WinAnsiEncoding\n"); + + _cairo_output_stream_printf (surface->output, " /Widths ["); + if (font_subset->is_latin) { + for (i = 32; i < last_glyph + 1; i++) { + int glyph = font_subset->latin_to_subset_glyph_index[i]; + if (glyph > 0) { + _cairo_output_stream_printf (surface->output, + " %f", + (subset->widths[glyph]*PDF_UNITS_PER_EM)); + } else { + _cairo_output_stream_printf (surface->output, " 0"); + } + } + } else { + for (i = 0; i < font_subset->num_glyphs; i++) + _cairo_output_stream_printf (surface->output, + " %f", + (subset->widths[i]*PDF_UNITS_PER_EM)); + } + + _cairo_output_stream_printf (surface->output, + " ]\n"); + + if (to_unicode_stream.id != 0) + _cairo_output_stream_printf (surface->output, + " /ToUnicode %d 0 R\n", + to_unicode_stream.id); + + _cairo_output_stream_printf (surface->output, + ">>\n" + "endobj\n"); + + font.font_id = font_subset->font_id; + font.subset_id = font_subset->subset_id; + font.subset_resource = subset_resource; + return _cairo_array_append (&surface->fonts, &font); +} + +static cairo_int_status_t +_cairo_pdf_surface_emit_type1_font_subset (cairo_pdf_surface_t *surface, + cairo_scaled_font_subset_t *font_subset) +{ + cairo_int_status_t status; + cairo_type1_subset_t subset; + char name[64]; + + /* 16-bit glyphs not compatible with Type 1 fonts */ + if (font_subset->is_composite && !font_subset->is_latin) + return CAIRO_INT_STATUS_UNSUPPORTED; + + snprintf (name, sizeof name, "CairoFont-%d-%d", + font_subset->font_id, font_subset->subset_id); + status = _cairo_type1_subset_init (&subset, name, font_subset, FALSE); + if (unlikely (status)) + return status; + + status = _cairo_pdf_surface_emit_type1_font (surface, font_subset, &subset); + + _cairo_type1_subset_fini (&subset); + return status; +} + +static cairo_int_status_t +_cairo_pdf_surface_emit_type1_fallback_font (cairo_pdf_surface_t *surface, + cairo_scaled_font_subset_t *font_subset) +{ + cairo_int_status_t status; + cairo_type1_subset_t subset; + char name[64]; + + /* 16-bit glyphs not compatible with Type 1 fonts */ + if (font_subset->is_composite && !font_subset->is_latin) + return CAIRO_INT_STATUS_UNSUPPORTED; + + snprintf (name, sizeof name, "CairoFont-%d-%d", + font_subset->font_id, font_subset->subset_id); + status = _cairo_type1_fallback_init_binary (&subset, name, font_subset); + if (unlikely (status)) + return status; + + status = _cairo_pdf_surface_emit_type1_font (surface, font_subset, &subset); + + _cairo_type1_fallback_fini (&subset); + return status; +} + +static cairo_int_status_t +_cairo_pdf_surface_emit_truetype_font_subset (cairo_pdf_surface_t *surface, + cairo_scaled_font_subset_t *font_subset) +{ + cairo_pdf_resource_t stream, descriptor, cidfont_dict; + cairo_pdf_resource_t subset_resource, to_unicode_stream; + cairo_int_status_t status; + cairo_pdf_font_t font; + cairo_truetype_subset_t subset; + unsigned int i, last_glyph; + char tag[10]; + + subset_resource = _cairo_pdf_surface_get_font_resource (surface, + font_subset->font_id, + font_subset->subset_id); + if (subset_resource.id == 0) + return CAIRO_STATUS_SUCCESS; + + status = _cairo_truetype_subset_init_pdf (&subset, font_subset); + if (unlikely (status)) + return status; + + _create_font_subset_tag (font_subset, subset.ps_name, tag); + + status = _cairo_pdf_surface_open_stream (surface, + NULL, + TRUE, + " /Length1 %lu\n", + subset.data_length); + if (unlikely (status)) { + _cairo_truetype_subset_fini (&subset); + return status; + } + + stream = surface->pdf_stream.self; + _cairo_output_stream_write (surface->output, + subset.data, subset.data_length); + status = _cairo_pdf_surface_close_stream (surface); + if (unlikely (status)) { + _cairo_truetype_subset_fini (&subset); + return status; + } + + status = _cairo_pdf_surface_emit_to_unicode_stream (surface, + font_subset, + &to_unicode_stream); + if (_cairo_int_status_is_error (status)) { + _cairo_truetype_subset_fini (&subset); + return status; + } + + descriptor = _cairo_pdf_surface_new_object (surface); + if (descriptor.id == 0) { + _cairo_truetype_subset_fini (&subset); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n" + "<< /Type /FontDescriptor\n" + " /FontName /%s+%s\n", + descriptor.id, + tag, + subset.ps_name); + + if (subset.family_name_utf8) { + char *pdf_str; + + status = _cairo_utf8_to_pdf_string (subset.family_name_utf8, &pdf_str); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { + _cairo_output_stream_printf (surface->output, + " /FontFamily %s\n", + pdf_str); + free (pdf_str); + } else if (status != CAIRO_INT_STATUS_INVALID_STRING) { + return status; + } + } + + _cairo_output_stream_printf (surface->output, + " /Flags %d\n" + " /FontBBox [ %ld %ld %ld %ld ]\n" + " /ItalicAngle 0\n" + " /Ascent %ld\n" + " /Descent %ld\n" + " /CapHeight %ld\n" + " /StemV 80\n" + " /StemH 80\n" + " /FontFile2 %u 0 R\n" + ">>\n" + "endobj\n", + font_subset->is_latin ? 32 : 4, + (long)(subset.x_min*PDF_UNITS_PER_EM), + (long)(subset.y_min*PDF_UNITS_PER_EM), + (long)(subset.x_max*PDF_UNITS_PER_EM), + (long)(subset.y_max*PDF_UNITS_PER_EM), + (long)(subset.ascent*PDF_UNITS_PER_EM), + (long)(subset.descent*PDF_UNITS_PER_EM), + (long)(subset.y_max*PDF_UNITS_PER_EM), + stream.id); + + if (font_subset->is_latin) { + /* find last glyph used */ + for (i = 255; i >= 32; i--) + if (font_subset->latin_to_subset_glyph_index[i] > 0) + break; + + last_glyph = i; + _cairo_pdf_surface_update_object (surface, subset_resource); + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n" + "<< /Type /Font\n" + " /Subtype /TrueType\n" + " /BaseFont /%s+%s\n" + " /FirstChar 32\n" + " /LastChar %d\n" + " /FontDescriptor %d 0 R\n" + " /Encoding /WinAnsiEncoding\n" + " /Widths [", + subset_resource.id, + tag, + subset.ps_name, + last_glyph, + descriptor.id); + + for (i = 32; i < last_glyph + 1; i++) { + int glyph = font_subset->latin_to_subset_glyph_index[i]; + if (glyph > 0) { + _cairo_output_stream_printf (surface->output, + " %f", + (subset.widths[glyph]*PDF_UNITS_PER_EM)); + } else { + _cairo_output_stream_printf (surface->output, " 0"); + } + } + + _cairo_output_stream_printf (surface->output, + " ]\n"); + + if (to_unicode_stream.id != 0) + _cairo_output_stream_printf (surface->output, + " /ToUnicode %d 0 R\n", + to_unicode_stream.id); + + _cairo_output_stream_printf (surface->output, + ">>\n" + "endobj\n"); + } else { + cidfont_dict = _cairo_pdf_surface_new_object (surface); + if (cidfont_dict.id == 0) { + _cairo_truetype_subset_fini (&subset); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n" + "<< /Type /Font\n" + " /Subtype /CIDFontType2\n" + " /BaseFont /%s+%s\n" + " /CIDSystemInfo\n" + " << /Registry (Adobe)\n" + " /Ordering (Identity)\n" + " /Supplement 0\n" + " >>\n" + " /FontDescriptor %d 0 R\n" + " /W [0 [", + cidfont_dict.id, + tag, + subset.ps_name, + descriptor.id); + + for (i = 0; i < font_subset->num_glyphs; i++) + _cairo_output_stream_printf (surface->output, + " %f", + (subset.widths[i]*PDF_UNITS_PER_EM)); + + _cairo_output_stream_printf (surface->output, + " ]]\n" + ">>\n" + "endobj\n"); + + _cairo_pdf_surface_update_object (surface, subset_resource); + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n" + "<< /Type /Font\n" + " /Subtype /Type0\n" + " /BaseFont /%s+%s\n" + " /Encoding /Identity-H\n" + " /DescendantFonts [ %d 0 R]\n", + subset_resource.id, + tag, + subset.ps_name, + cidfont_dict.id); + + if (to_unicode_stream.id != 0) + _cairo_output_stream_printf (surface->output, + " /ToUnicode %d 0 R\n", + to_unicode_stream.id); + + _cairo_output_stream_printf (surface->output, + ">>\n" + "endobj\n"); + } + + font.font_id = font_subset->font_id; + font.subset_id = font_subset->subset_id; + font.subset_resource = subset_resource; + status = _cairo_array_append (&surface->fonts, &font); + + _cairo_truetype_subset_fini (&subset); + + return status; +} + +static cairo_int_status_t +_cairo_pdf_emit_imagemask (cairo_image_surface_t *image, + cairo_output_stream_t *stream) +{ + uint8_t *byte, output_byte; + int row, col, num_cols; + + /* The only image type supported by Type 3 fonts are 1-bit image + * masks */ + assert (image->format == CAIRO_FORMAT_A1); + + _cairo_output_stream_printf (stream, + "BI\n" + "/IM true\n" + "/W %d\n" + "/H %d\n" + "/BPC 1\n" + "/D [1 0]\n", + image->width, + image->height); + + _cairo_output_stream_printf (stream, + "ID "); + + num_cols = (image->width + 7) / 8; + for (row = 0; row < image->height; row++) { + byte = image->data + row * image->stride; + for (col = 0; col < num_cols; col++) { + output_byte = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (*byte); + _cairo_output_stream_write (stream, &output_byte, 1); + byte++; + } + } + + _cairo_output_stream_printf (stream, + "\nEI\n"); + + return _cairo_output_stream_get_status (stream); +} + +static cairo_int_status_t +cairo_pdf_surface_emit_color_glyph (cairo_pdf_surface_t *surface, + cairo_scaled_font_t *scaled_font, + unsigned long glyph_index, + cairo_box_t *bbox, + double *width) +{ + cairo_rectangle_int_t extents; + cairo_scaled_glyph_t *scaled_glyph; + cairo_matrix_t mat; + cairo_int_status_t status; + double x_advance, y_advance; + cairo_matrix_t font_matrix_inverse; + cairo_surface_t *analysis; + cairo_rectangle_int_t old_surface_extents; + cairo_bool_t old_surface_bounded; + cairo_paginated_mode_t old_paginated_mode; + cairo_surface_t *glyph_surface = NULL; + unsigned int regions_id = 0; + cairo_surface_pattern_t surface_pattern; + + _cairo_scaled_font_freeze_cache (scaled_font); + status = _cairo_scaled_glyph_lookup (scaled_font, + glyph_index, + CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE, + NULL, /* foreground color */ + &scaled_glyph); + if (status == CAIRO_INT_STATUS_SUCCESS) + glyph_surface = cairo_surface_reference (scaled_glyph->recording_surface); + + _cairo_scaled_font_thaw_cache (scaled_font); + if (unlikely (status)) + return status; + + analysis = _cairo_analysis_surface_create (&surface->base, TRUE); + if (unlikely (analysis->status)) { + status = _cairo_surface_set_error (&surface->base, analysis->status); + goto cleanup; + } + + extents.x = _cairo_fixed_to_double (scaled_glyph->bbox.p1.x); + extents.y = _cairo_fixed_to_double (scaled_glyph->bbox.p1.y); + extents.width = _cairo_fixed_to_double (scaled_glyph->bbox.p2.x) - extents.x; + extents.height = _cairo_fixed_to_double (scaled_glyph->bbox.p2.y) - extents.y; + + old_surface_extents = surface->surface_extents; + old_surface_bounded = surface->surface_bounded; + old_paginated_mode = surface->paginated_mode; + surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE; + surface->type3_replay = TRUE; + surface->surface_extents = extents; + surface->surface_bounded = TRUE; + + status = _cairo_recording_surface_region_array_attach (glyph_surface, ®ions_id); + if (status) + goto cleanup; + + status = _cairo_recording_surface_replay_and_create_regions (glyph_surface, regions_id, + NULL, analysis, TRUE, FALSE); + if (status) + goto cleanup; + + surface->surface_extents = old_surface_extents; + surface->surface_bounded = old_surface_bounded; + surface->paginated_mode = old_paginated_mode; + surface->type3_replay = FALSE; + + if (status == CAIRO_INT_STATUS_SUCCESS && + _cairo_analysis_surface_has_unsupported (analysis)) + { + status = CAIRO_INT_STATUS_UNSUPPORTED; + } + + cairo_surface_destroy (analysis); + if (status) + goto cleanup; + + _cairo_pattern_init_for_surface (&surface_pattern, glyph_surface); + surface_pattern.region_array_id = regions_id; + + cairo_matrix_init_identity (&mat); + cairo_matrix_multiply (&mat, &mat, &scaled_font->scale_inverse); + + /* transform glyph extents to operation space */ + cairo_box_t box; + _cairo_box_from_rectangle (&box, &extents); + _cairo_matrix_transform_bounding_box_fixed (&mat, &box, NULL); + _cairo_box_round_to_rectangle (&box, &extents); + + status = cairo_matrix_invert (&mat); + if (status) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto cleanup; + } + + cairo_pattern_set_matrix (&surface_pattern.base, &mat); + + x_advance = scaled_glyph->metrics.x_advance; + y_advance = scaled_glyph->metrics.y_advance; + font_matrix_inverse = scaled_font->font_matrix; + status = cairo_matrix_invert (&font_matrix_inverse); + if (status) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto cleanup; + } + + cairo_matrix_transform_distance (&font_matrix_inverse, &x_advance, &y_advance); + *width = x_advance; + + *bbox = scaled_glyph->bbox; + _cairo_matrix_transform_bounding_box_fixed (&scaled_font->scale_inverse, + bbox, NULL); + + _cairo_output_stream_printf (surface->output, + "%f 0 d0\n", + x_advance); + + _cairo_pdf_surface_paint_surface_pattern (surface, + CAIRO_OPERATOR_OVER, + &surface_pattern.base, + CAIRO_ANALYSIS_SOURCE_NONE, + &extents, + 1.0, /* alpha */ + NULL, /* smask_res */ + FALSE); /* mask */ + + cleanup: + cairo_surface_destroy (glyph_surface); + + return status; +} + +static cairo_int_status_t +cairo_pdf_surface_emit_color_glyph_image (cairo_pdf_surface_t *surface, + cairo_scaled_font_t *scaled_font, + unsigned long glyph_index, + cairo_box_t *bbox, + double *width) +{ + cairo_rectangle_int_t extents; + cairo_pattern_t *image_pattern; + cairo_scaled_glyph_t *scaled_glyph; + cairo_matrix_t mat; + cairo_int_status_t status, status2; + double x_advance, y_advance; + cairo_matrix_t font_matrix_inverse; + + _cairo_scaled_font_freeze_cache (scaled_font); + status = _cairo_scaled_glyph_lookup (scaled_font, + glyph_index, + CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE, + NULL, /* foreground color */ + &scaled_glyph); + if (unlikely (status)) + goto FAIL; + + extents.x = _cairo_fixed_to_double (scaled_glyph->bbox.p1.x); + extents.y = _cairo_fixed_to_double (scaled_glyph->bbox.p1.y); + extents.width = _cairo_fixed_to_double (scaled_glyph->bbox.p2.x) - extents.x; + extents.height = _cairo_fixed_to_double (scaled_glyph->bbox.p2.y) - extents.y; + + image_pattern = cairo_pattern_create_for_surface (&scaled_glyph->color_surface->base); + + cairo_matrix_init_translate (&mat, extents.x, extents.y); + cairo_matrix_multiply (&mat, &mat, &scaled_font->scale_inverse); + status2 = cairo_matrix_invert (&mat); + cairo_pattern_set_matrix (image_pattern, &mat); + + x_advance = scaled_glyph->metrics.x_advance; + y_advance = scaled_glyph->metrics.y_advance; + font_matrix_inverse = scaled_font->font_matrix; + status2 = cairo_matrix_invert (&font_matrix_inverse); + + /* The invertability of font_matrix is tested in + * pdf_operators_show_glyphs before any glyphs are mapped to the + * subset. */ + assert (status2 == CAIRO_INT_STATUS_SUCCESS); + + cairo_matrix_transform_distance (&font_matrix_inverse, &x_advance, &y_advance); + *width = x_advance; + + *bbox = scaled_glyph->bbox; + _cairo_matrix_transform_bounding_box_fixed (&scaled_font->scale_inverse, + bbox, NULL); + + _cairo_output_stream_printf (surface->output, + "%f 0 d0\n", + x_advance); + + _cairo_pdf_surface_paint_surface_pattern (surface, + CAIRO_OPERATOR_OVER, + image_pattern, + CAIRO_ANALYSIS_SOURCE_NONE, + &extents, + 1.0, /* alpha */ + NULL, /* smask_res */ + FALSE); /* mask */ + cairo_pattern_destroy (image_pattern); + FAIL: + _cairo_scaled_font_thaw_cache (scaled_font); + + return status; +} + +static cairo_int_status_t +_cairo_pdf_surface_emit_type3_font_subset (cairo_pdf_surface_t *surface, + cairo_scaled_font_subset_t *font_subset) +{ + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + cairo_pdf_resource_t *glyphs, encoding, char_procs, subset_resource, to_unicode_stream; + cairo_pdf_font_t font; + double *widths; + unsigned int i; + cairo_box_t font_bbox = {{0,0},{0,0}}; + cairo_box_t bbox = {{0,0},{0,0}}; + cairo_surface_t *type3_surface; + + if (font_subset->num_glyphs == 0) + return CAIRO_STATUS_SUCCESS; + + subset_resource = _cairo_pdf_surface_get_font_resource (surface, + font_subset->font_id, + font_subset->subset_id); + if (subset_resource.id == 0) + return CAIRO_STATUS_SUCCESS; + + glyphs = _cairo_malloc_ab (font_subset->num_glyphs, sizeof (cairo_pdf_resource_t)); + if (unlikely (glyphs == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + widths = _cairo_malloc_ab (font_subset->num_glyphs, sizeof (double)); + if (unlikely (widths == NULL)) { + free (glyphs); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + _cairo_pdf_group_resources_clear (&surface->resources); + type3_surface = _cairo_type3_glyph_surface_create (font_subset->scaled_font, + NULL, + _cairo_pdf_emit_imagemask, + surface->font_subsets, + FALSE); + if (unlikely (type3_surface->status)) { + free (glyphs); + free (widths); + return type3_surface->status; + } + + _cairo_type3_glyph_surface_set_font_subsets_callback (type3_surface, + _cairo_pdf_surface_add_font, + surface); + + for (i = 0; i < font_subset->num_glyphs; i++) { + status = _cairo_pdf_surface_open_stream (surface, + NULL, + surface->compress_streams, + NULL); + if (unlikely (status)) + break; + + glyphs[i] = surface->pdf_stream.self; + status = _cairo_type3_glyph_surface_emit_glyph (type3_surface, + surface->output, + font_subset->glyphs[i], + &bbox, + &widths[i]); + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + status = cairo_pdf_surface_emit_color_glyph (surface, + font_subset->scaled_font, + font_subset->glyphs[i], + &bbox, + &widths[i]); + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + status = cairo_pdf_surface_emit_color_glyph_image (surface, + font_subset->scaled_font, + font_subset->glyphs[i], + &bbox, + &widths[i]); + } + } + if (unlikely (status)) + break; + + status = _cairo_pdf_surface_close_stream (surface); + if (unlikely (status)) + break; + + if (i == 0) { + font_bbox.p1.x = bbox.p1.x; + font_bbox.p1.y = bbox.p1.y; + font_bbox.p2.x = bbox.p2.x; + font_bbox.p2.y = bbox.p2.y; + } else { + if (bbox.p1.x < font_bbox.p1.x) + font_bbox.p1.x = bbox.p1.x; + if (bbox.p1.y < font_bbox.p1.y) + font_bbox.p1.y = bbox.p1.y; + if (bbox.p2.x > font_bbox.p2.x) + font_bbox.p2.x = bbox.p2.x; + if (bbox.p2.y > font_bbox.p2.y) + font_bbox.p2.y = bbox.p2.y; + } + } + cairo_surface_destroy (type3_surface); + if (unlikely (status)) { + free (glyphs); + free (widths); + return status; + } + + encoding = _cairo_pdf_surface_new_object (surface); + if (encoding.id == 0) { + free (glyphs); + free (widths); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n" + "<< /Type /Encoding\n" + " /Differences [0", encoding.id); + for (i = 0; i < font_subset->num_glyphs; i++) + _cairo_output_stream_printf (surface->output, + " /%d", i); + _cairo_output_stream_printf (surface->output, + "]\n" + ">>\n" + "endobj\n"); + + char_procs = _cairo_pdf_surface_new_object (surface); + if (char_procs.id == 0) { + free (glyphs); + free (widths); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n" + "<<\n", char_procs.id); + for (i = 0; i < font_subset->num_glyphs; i++) + _cairo_output_stream_printf (surface->output, + " /%d %d 0 R\n", + i, glyphs[i].id); + _cairo_output_stream_printf (surface->output, + ">>\n" + "endobj\n"); + + free (glyphs); + + status = _cairo_pdf_surface_emit_to_unicode_stream (surface, + font_subset, + &to_unicode_stream); + if (_cairo_int_status_is_error (status)) { + free (widths); + return status; + } + + _cairo_pdf_surface_update_object (surface, subset_resource); + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n" + "<< /Type /Font\n" + " /Subtype /Type3\n" + " /FontBBox [%f %f %f %f]\n" + " /FontMatrix [ 1 0 0 -1 0 0 ]\n" + " /Encoding %d 0 R\n" + " /CharProcs %d 0 R\n" + " /FirstChar 0\n" + " /LastChar %d\n", + subset_resource.id, + _cairo_fixed_to_double (font_bbox.p1.x), + _cairo_fixed_to_double (font_bbox.p1.y), + _cairo_fixed_to_double (font_bbox.p2.x), + _cairo_fixed_to_double (font_bbox.p2.y), + encoding.id, + char_procs.id, + font_subset->num_glyphs - 1); + + _cairo_output_stream_printf (surface->output, + " /Widths ["); + for (i = 0; i < font_subset->num_glyphs; i++) + _cairo_output_stream_printf (surface->output, " %f", widths[i]); + _cairo_output_stream_printf (surface->output, + "]\n"); + free (widths); + + _cairo_output_stream_printf (surface->output, + " /Resources\n"); + _cairo_pdf_surface_emit_group_resources (surface, &surface->resources, FALSE); + + if (to_unicode_stream.id != 0) + _cairo_output_stream_printf (surface->output, + " /ToUnicode %d 0 R\n", + to_unicode_stream.id); + + _cairo_output_stream_printf (surface->output, + ">>\n" + "endobj\n"); + + font.font_id = font_subset->font_id; + font.subset_id = font_subset->subset_id; + font.subset_resource = subset_resource; + return _cairo_array_append (&surface->fonts, &font); +} + +static cairo_int_status_t +_cairo_pdf_surface_emit_unscaled_font_subset (cairo_scaled_font_subset_t *font_subset, + void *closure) +{ + cairo_pdf_surface_t *surface = closure; + cairo_int_status_t status; + + status = _cairo_pdf_surface_emit_cff_font_subset (surface, font_subset); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + status = _cairo_pdf_surface_emit_truetype_font_subset (surface, font_subset); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + status = _cairo_pdf_surface_emit_type1_font_subset (surface, font_subset); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + status = _cairo_pdf_surface_emit_cff_fallback_font (surface, font_subset); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + status = _cairo_pdf_surface_emit_type1_fallback_font (surface, font_subset); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + ASSERT_NOT_REACHED; + return CAIRO_INT_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_pdf_surface_emit_scaled_font_subset (cairo_scaled_font_subset_t *font_subset, + void *closure) +{ + cairo_pdf_surface_t *surface = closure; + cairo_int_status_t status; + + status = _cairo_pdf_surface_emit_type3_font_subset (surface, font_subset); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + ASSERT_NOT_REACHED; + return CAIRO_INT_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_pdf_surface_emit_font_subsets (cairo_pdf_surface_t *surface) +{ + cairo_int_status_t status; + + status = _cairo_scaled_font_subsets_foreach_unscaled (surface->font_subsets, + _cairo_pdf_surface_emit_unscaled_font_subset, + surface); + if (unlikely (status)) + goto BAIL; + + status = _cairo_scaled_font_subsets_foreach_scaled (surface->font_subsets, + _cairo_pdf_surface_emit_scaled_font_subset, + surface); + +BAIL: + _cairo_scaled_font_subsets_destroy (surface->font_subsets); + surface->font_subsets = NULL; + + return status; +} + +static cairo_int_status_t +_cairo_pdf_surface_write_catalog (cairo_pdf_surface_t *surface, + cairo_pdf_resource_t catalog) +{ + cairo_status_t status; + + status = _cairo_pdf_surface_object_begin (surface, catalog); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->object_stream.stream, + "<< /Type /Catalog\n" + " /Pages %d 0 R\n", + surface->pages_resource.id); + + if (surface->struct_tree_root.id != 0) { + _cairo_output_stream_printf (surface->object_stream.stream, + " /StructTreeRoot %d 0 R\n", + surface->struct_tree_root.id); + if (surface->tagged) { + _cairo_output_stream_printf (surface->object_stream.stream, + " /MarkInfo << /Marked true >>\n"); + } + } + + if (surface->outlines_dict_res.id != 0) { + _cairo_output_stream_printf (surface->object_stream.stream, + " /Outlines %d 0 R\n", + surface->outlines_dict_res.id); + } + + if (surface->page_labels_res.id != 0) { + _cairo_output_stream_printf (surface->object_stream.stream, + " /PageLabels %d 0 R\n", + surface->page_labels_res.id); + } + + if (surface->names_dict_res.id != 0) { + _cairo_output_stream_printf (surface->object_stream.stream, + " /Names %d 0 R\n", + surface->names_dict_res.id); + } + + _cairo_output_stream_printf (surface->object_stream.stream, + ">>\n"); + _cairo_pdf_surface_object_end (surface); + + return status; +} + +static long long +_cairo_pdf_surface_write_xref (cairo_pdf_surface_t *surface) +{ + cairo_pdf_object_t *object; + int num_objects, i; + long long offset; + + num_objects = _cairo_array_num_elements (&surface->objects); + + offset = _cairo_output_stream_get_position (surface->output); + _cairo_output_stream_printf (surface->output, + "xref\n" + "%d %d\n", + 0, num_objects + 1); + + _cairo_output_stream_printf (surface->output, + "0000000000 65535 f \n"); + for (i = 0; i < num_objects; i++) { + object = _cairo_array_index (&surface->objects, i); + _cairo_output_stream_printf (surface->output, + "%010lld 00000 n \n", object->u.offset); + } + + return offset; +} + +static void +_cairo_write_xref_stream_entry (cairo_output_stream_t *stream, + int id, + int type, + int field2_size, + long long field2, + int field3, + cairo_bool_t write_as_comments) +{ + char buf[20]; + int i; + + if (write_as_comments) { + _cairo_output_stream_printf (stream, "%% %5d %2d %10lld %d\n", id, type, field2, field3); + } else { + /* Each field is big endian */ + buf[0] = type; /* field 1 */ + for (i = field2_size - 1; i >= 0; i--) { + buf[i + 1] = field2 & 0xff; + field2 >>= 8; + } + buf[field2_size + 1] = field3 >> 8; + buf[field2_size + 2] = field3 & 0xff; + _cairo_output_stream_write (stream, buf, field2_size + 3); + } +} + +static void +_cairo_write_xref_stream_entries (cairo_pdf_surface_t *surface, + cairo_output_stream_t *stream, + int field2_size, + cairo_bool_t write_as_comments) +{ + cairo_pdf_object_t *object; + int num_objects, i; + + /* PDF requires this to be first entry */ + _cairo_write_xref_stream_entry (stream, + 0, + PDF_OBJECT_FREE, + field2_size, + 0, /* next free object number */ + 0xffff, /* next generation number */ + write_as_comments); + + num_objects = _cairo_array_num_elements (&surface->objects); + for (i = 0; i < num_objects; i++) { + object = _cairo_array_index (&surface->objects, i); + if (object->type == PDF_OBJECT_UNCOMPRESSED) { + _cairo_write_xref_stream_entry (stream, + i + 1, + object->type, + field2_size, + object->u.offset, + 0, /* generation number */ + write_as_comments); + } else if (object->type == PDF_OBJECT_COMPRESSED) { + _cairo_write_xref_stream_entry (stream, + i + 1, + object->type, + field2_size, + object->u.compressed_obj.xref_stream.id, + object->u.compressed_obj.index, + write_as_comments); + } else { + _cairo_write_xref_stream_entry (stream, + i + 1, + PDF_OBJECT_FREE, + field2_size, + 0, + 0xffff, + write_as_comments); + } + } +} + +static cairo_int_status_t +_cairo_pdf_surface_write_xref_stream (cairo_pdf_surface_t *surface, + cairo_pdf_resource_t xref_res, + cairo_pdf_resource_t root_res, + cairo_pdf_resource_t info_res, + long long *xref_offset) +{ + cairo_output_stream_t *mem_stream; + cairo_output_stream_t *xref_stream; + long long offset; + int offset_bytes; + cairo_status_t status; + + *xref_offset = _cairo_output_stream_get_position (surface->output); + + /* Find the minimum number of bytes required to represent offsets in the generated file (up to this point). */ + offset_bytes = 0; + offset = *xref_offset; + while (offset > 0) { + offset >>= 8; + offset_bytes++; + } + + mem_stream = _cairo_memory_stream_create (); + xref_stream = _cairo_deflate_stream_create (mem_stream); + _cairo_write_xref_stream_entries (surface, xref_stream, offset_bytes, FALSE); + + status = _cairo_output_stream_destroy (xref_stream); + if (unlikely (status)) + return status; + + _cairo_pdf_surface_update_object (surface, xref_res); + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n" + "<< /Type /XRef\n" + " /Length %d\n" + " /Filter /FlateDecode\n" + " /Size %d\n" + " /W [1 %d 2]\n" + " /Root %d 0 R\n" + " /Info %d 0 R\n" + ">>\n", + xref_res.id, + _cairo_memory_stream_length (mem_stream), + surface->next_available_resource.id, + offset_bytes, + root_res.id, + info_res.id); + + if (!surface->compress_streams) { + /* Adobe Reader requires xref streams to be flate encoded (PDF + * Reference 1.7, implementation note 20). This means + * compression must always be enabled on this stream. To + * facilitate debugging when compress_stream is disabled, emit + * a human readable format of the xref stream as PDF comments. + */ + _cairo_output_stream_printf (surface->output, + "%% id type offset/obj gen/index\n"); + _cairo_write_xref_stream_entries (surface, surface->output, offset_bytes, TRUE); + } + + _cairo_output_stream_printf (surface->output, + "stream\n"); + _cairo_memory_stream_copy (mem_stream, surface->output); + status = _cairo_output_stream_destroy (mem_stream); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->output, + "\n" + "endstream\n" + "endobj\n"); + + return _cairo_output_stream_get_status (surface->output); +} + +static cairo_int_status_t +_cairo_pdf_surface_write_mask_group (cairo_pdf_surface_t *surface, + cairo_pdf_smask_group_t *group) +{ + cairo_pdf_resource_t mask_group; + cairo_pdf_resource_t smask; + cairo_pdf_smask_group_t *smask_group; + cairo_pdf_resource_t pattern_res, gstate_res; + cairo_int_status_t status; + cairo_box_double_t bbox; + + /* Create mask group */ + _get_bbox_from_extents (&group->extents, &bbox); + status = _cairo_pdf_surface_open_group (surface, &bbox, NULL); + if (unlikely (status)) + return status; + + if (_can_paint_pattern (group->mask)) { + _cairo_output_stream_printf (surface->output, "q\n"); + status = _cairo_pdf_surface_paint_pattern (surface, + CAIRO_OPERATOR_OVER, + group->mask, + CAIRO_ANALYSIS_MASK_MASK, + &group->extents, + 1.0, /* alpha */ + FALSE); /* mask */ + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->output, "Q\n"); + } else { + pattern_res.id = 0; + gstate_res.id = 0; + status = _cairo_pdf_surface_add_pdf_pattern (surface, group->mask, + CAIRO_OPERATOR_OVER, + CAIRO_ANALYSIS_MASK_MASK, + NULL, + &pattern_res, &gstate_res); + if (unlikely (status)) + return status; + + if (gstate_res.id != 0) { + smask_group = _cairo_pdf_surface_create_smask_group (surface, &group->extents); + if (unlikely (smask_group == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + smask_group->width = group->width; + smask_group->height = group->height; + smask_group->operation = PDF_PAINT; + smask_group->source = cairo_pattern_reference (group->mask); + smask_group->source_res = pattern_res; + status = _cairo_pdf_surface_add_smask_group (surface, smask_group); + if (unlikely (status)) { + _cairo_pdf_smask_group_destroy (smask_group); + return status; + } + + status = _cairo_pdf_surface_add_smask (surface, gstate_res); + if (unlikely (status)) + return status; + + status = _cairo_pdf_surface_add_xobject (surface, smask_group->group_res); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->output, + "q /s%d gs /x%d Do Q\n", + gstate_res.id, + smask_group->group_res.id); + } else { + status = _cairo_pdf_surface_select_pattern (surface, group->mask, pattern_res, FALSE); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->output, + "%f %f %f %f re f\n", + bbox.p1.x, + bbox.p1.y, + bbox.p2.x - bbox.p1.x, + bbox.p2.y - bbox.p1.y); + + status = _cairo_pdf_surface_unselect_pattern (surface); + if (unlikely (status)) + return status; + } + } + + status = _cairo_pdf_surface_close_group (surface, &mask_group); + if (unlikely (status)) + return status; + + /* Create source group */ + status = _cairo_pdf_surface_open_group (surface, &bbox, &group->source_res); + if (unlikely (status)) + return status; + + if (_can_paint_pattern (group->source)) { + _cairo_output_stream_printf (surface->output, "q\n"); + status = _cairo_pdf_surface_paint_pattern (surface, + CAIRO_OPERATOR_OVER, + group->source, + CAIRO_ANALYSIS_MASK_MASK, + &group->extents, + 1.0, /* alpha */ + FALSE); /* mask */ + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->output, "Q\n"); + } else { + pattern_res.id = 0; + gstate_res.id = 0; + status = _cairo_pdf_surface_add_pdf_pattern (surface, group->source, + CAIRO_OPERATOR_OVER, + CAIRO_ANALYSIS_MASK_MASK, + NULL, + &pattern_res, &gstate_res); + if (unlikely (status)) + return status; + + if (gstate_res.id != 0) { + smask_group = _cairo_pdf_surface_create_smask_group (surface, &group->extents); + if (unlikely (smask_group == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + smask_group->operation = PDF_PAINT; + smask_group->source = cairo_pattern_reference (group->source); + smask_group->source_res = pattern_res; + status = _cairo_pdf_surface_add_smask_group (surface, smask_group); + if (unlikely (status)) { + _cairo_pdf_smask_group_destroy (smask_group); + return status; + } + + status = _cairo_pdf_surface_add_smask (surface, gstate_res); + if (unlikely (status)) + return status; + + status = _cairo_pdf_surface_add_xobject (surface, smask_group->group_res); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->output, + "q /s%d gs /x%d Do Q\n", + gstate_res.id, + smask_group->group_res.id); + } else { + status = _cairo_pdf_surface_select_pattern (surface, group->source, pattern_res, FALSE); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->output, + "%f %f %f %f re f\n", + bbox.p1.x, + bbox.p1.y, + bbox.p2.x - bbox.p1.x, + bbox.p2.y - bbox.p1.y); + + status = _cairo_pdf_surface_unselect_pattern (surface); + if (unlikely (status)) + return status; + } + } + + status = _cairo_pdf_surface_close_group (surface, NULL); + if (unlikely (status)) + return status; + + /* Create an smask based on the alpha component of mask_group */ + smask = _cairo_pdf_surface_new_object (surface); + if (smask.id == 0) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n" + "<< /Type /Mask\n" + " /S /Alpha\n" + " /G %d 0 R\n" + ">>\n" + "endobj\n", + smask.id, + mask_group.id); + + /* Create a GState that uses the smask */ + _cairo_pdf_surface_update_object (surface, group->group_res); + _cairo_output_stream_printf (surface->output, + "%d 0 obj\n" + "<< /Type /ExtGState\n" + " /SMask %d 0 R\n" + " /ca 1\n" + " /CA 1\n" + " /AIS false\n" + ">>\n" + "endobj\n", + group->group_res.id, + smask.id); + + return _cairo_output_stream_get_status (surface->output); +} + +static cairo_int_status_t +_cairo_pdf_surface_write_smask_group (cairo_pdf_surface_t *surface, + cairo_pdf_smask_group_t *group) +{ + double old_width, old_height; + cairo_bool_t old_in_xobject; + cairo_int_status_t status; + cairo_box_double_t bbox; + cairo_rectangle_int_t old_surface_extents; + + old_width = surface->width; + old_height = surface->height; + old_surface_extents = surface->surface_extents; + old_in_xobject = surface->in_xobject; + surface->in_xobject = TRUE; + _cairo_pdf_surface_set_size_internal (surface, + group->width, + group->height); + _cairo_pdf_operators_reset (&surface->pdf_operators); + /* _mask is a special case that requires two groups - source + * and mask as well as a smask and gstate dictionary */ + if (group->operation == PDF_MASK) { + status = _cairo_pdf_surface_write_mask_group (surface, group); + goto RESTORE_SIZE; + } + + _get_bbox_from_extents (&group->extents, &bbox); + status = _cairo_pdf_surface_open_group (surface, &bbox, &group->group_res); + if (unlikely (status)) + return status; + + status = _cairo_pdf_surface_select_pattern (surface, + group->source, + group->source_res, + group->operation == PDF_STROKE); + if (unlikely (status)) + return status; + + switch (group->operation) { + case PDF_PAINT: + _cairo_output_stream_printf (surface->output, + "0 0 %f %f re f\n", + surface->width, surface->height); + break; + case PDF_MASK: + ASSERT_NOT_REACHED; + break; + case PDF_FILL: + status = _cairo_pdf_operators_fill (&surface->pdf_operators, + &group->path, + group->fill_rule); + break; + case PDF_STROKE: + status = _cairo_pdf_operators_stroke (&surface->pdf_operators, + &group->path, + &group->style, + &group->ctm, + &group->ctm_inverse); + break; + case PDF_SHOW_GLYPHS: + status = _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators, + group->utf8, group->utf8_len, + group->glyphs, group->num_glyphs, + group->clusters, group->num_clusters, + group->cluster_flags, + group->scaled_font); + break; + } + if (unlikely (status)) + return status; + + status = _cairo_pdf_surface_unselect_pattern (surface); + if (unlikely (status)) + return status; + + status = _cairo_pdf_surface_close_group (surface, NULL); + +RESTORE_SIZE: + surface->in_xobject = old_in_xobject; + _cairo_pdf_surface_set_size_internal (surface, + old_width, + old_height); + surface->surface_extents = old_surface_extents; + _cairo_pdf_operators_reset (&surface->pdf_operators); + + return status; +} + +static cairo_int_status_t +_cairo_pdf_surface_write_patterns_and_smask_groups (cairo_pdf_surface_t *surface, + cairo_bool_t finish) +{ + cairo_pdf_pattern_t pattern; + cairo_pdf_smask_group_t *group; + cairo_pdf_source_surface_t src_surface; + unsigned int pattern_index, group_index, surface_index, doc_surface_index; + cairo_int_status_t status; + cairo_bool_t is_image; + + /* Writing out PDF_MASK groups will cause additional smask groups + * to be appended to surface->smask_groups. Additional patterns + * may also be appended to surface->patterns. + * + * Writing recording surface patterns will cause additional patterns + * and groups to be appended. + */ + pattern_index = 0; + group_index = 0; + surface_index = 0; + doc_surface_index = 0; + while ((pattern_index < _cairo_array_num_elements (&surface->page_patterns)) || + (group_index < _cairo_array_num_elements (&surface->smask_groups)) || + (surface_index < _cairo_array_num_elements (&surface->page_surfaces)) || + (finish && (doc_surface_index < _cairo_array_num_elements (&surface->doc_surfaces)))) + { + for (; group_index < _cairo_array_num_elements (&surface->smask_groups); group_index++) { + _cairo_array_copy_element (&surface->smask_groups, group_index, &group); + status = _cairo_pdf_surface_write_smask_group (surface, group); + if (unlikely (status)) + return status; + } + + for (; pattern_index < _cairo_array_num_elements (&surface->page_patterns); pattern_index++) { + _cairo_array_copy_element (&surface->page_patterns, pattern_index, &pattern); + status = _cairo_pdf_surface_emit_pattern (surface, &pattern); + if (unlikely (status)) + return status; + } + + for (; surface_index < _cairo_array_num_elements (&surface->page_surfaces); surface_index++) { + _cairo_array_copy_element (&surface->page_surfaces, surface_index, &src_surface); + status = _cairo_pdf_surface_emit_surface (surface, &src_surface, FALSE, &is_image); + if (unlikely (status)) + return status; + } + + if (finish) { + for (; doc_surface_index < _cairo_array_num_elements (&surface->doc_surfaces); doc_surface_index++) { + _cairo_array_copy_element (&surface->doc_surfaces, doc_surface_index, &src_surface); + status = _cairo_pdf_surface_emit_surface (surface, &src_surface, FALSE, &is_image); + if (unlikely (status)) + return status; + } + } + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_pdf_surface_write_page (cairo_pdf_surface_t *surface) +{ + cairo_pdf_resource_t knockout, res; + cairo_int_status_t status; + unsigned int i, len; + cairo_pdf_page_info_t *page_info; + + page_info = _cairo_array_last_element (&surface->pages); + + status = _cairo_pdf_surface_open_object_stream (surface); + if (unlikely (status)) + return status; + + status = _cairo_pdf_interchange_write_page_objects (surface); + if (unlikely (status)) + return status; + + _cairo_pdf_group_resources_clear (&surface->resources); + if (surface->has_fallback_images) { + cairo_rectangle_int_t extents; + cairo_box_double_t bbox; + + extents.x = 0; + extents.y = 0; + extents.width = ceil (surface->width); + extents.height = ceil (surface->height); + _get_bbox_from_extents (&extents, &bbox); + status = _cairo_pdf_surface_open_knockout_group (surface, &bbox); + if (unlikely (status)) + return status; + + len = _cairo_array_num_elements (&surface->knockout_group); + for (i = 0; i < len; i++) { + _cairo_array_copy_element (&surface->knockout_group, i, &res); + _cairo_output_stream_printf (surface->output, + "/x%d Do\n", + res.id); + status = _cairo_pdf_surface_add_xobject (surface, res); + if (unlikely (status)) + return status; + } + _cairo_output_stream_printf (surface->output, + "/x%d Do\n", + surface->content.id); + status = _cairo_pdf_surface_add_xobject (surface, surface->content); + if (unlikely (status)) + return status; + + status = _cairo_pdf_surface_close_group (surface, &knockout); + if (unlikely (status)) + return status; + + _cairo_pdf_group_resources_clear (&surface->resources); + status = _cairo_pdf_surface_open_content_stream (surface, NULL, NULL, FALSE, FALSE, -1); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->output, + "/x%d Do\n", + knockout.id); + status = _cairo_pdf_surface_add_xobject (surface, knockout); + if (unlikely (status)) + return status; + + status = _cairo_pdf_surface_close_content_stream (surface, FALSE); + if (unlikely (status)) + return status; + } + + if (surface->thumbnail_image) { + cairo_pdf_source_surface_entry_t entry; + + memset (&entry, 0, sizeof (entry)); + page_info->thumbnail = _cairo_pdf_surface_new_object (surface); + entry.surface_res = page_info->thumbnail; + _cairo_pdf_surface_emit_image (surface, surface->thumbnail_image, &entry); + } + + page_info->content = surface->content; + page_info->resources = surface->content_resources; + page_info->struct_parents = surface->page_parent_tree; + + status = _cairo_pdf_surface_write_patterns_and_smask_groups (surface, FALSE); + if (unlikely (status)) + return status; + + return _cairo_pdf_surface_close_object_stream (surface); +} + +static cairo_int_status_t +_cairo_pdf_surface_analyze_surface_pattern_transparency (cairo_pdf_surface_t *surface, + cairo_surface_pattern_t *pattern) +{ + cairo_image_surface_t *image; + void *image_extra; + cairo_int_status_t status; + cairo_image_transparency_t transparency; + + status = _cairo_surface_acquire_source_image (pattern->surface, + &image, + &image_extra); + if (unlikely (status)) + return status; + + if (image->base.status) + return image->base.status; + + transparency = _cairo_image_analyze_transparency (image); + if (transparency == CAIRO_IMAGE_IS_OPAQUE) + status = CAIRO_STATUS_SUCCESS; + else + status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY; + + _cairo_surface_release_source_image (pattern->surface, image, image_extra); + + return status; +} + +static cairo_bool_t +_surface_pattern_supported (cairo_surface_pattern_t *pattern) +{ + cairo_extend_t extend; + + if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) + return TRUE; + + if (pattern->surface->backend->acquire_source_image == NULL) + return FALSE; + + /* Does an ALPHA-only source surface even make sense? Maybe, but I + * don't think it's worth the extra code to support it. */ + +/* XXX: Need to write this function here... + if (pattern->surface->content == CAIRO_CONTENT_ALPHA) + return FALSE; +*/ + + extend = cairo_pattern_get_extend (&pattern->base); + switch (extend) { + case CAIRO_EXTEND_NONE: + case CAIRO_EXTEND_REPEAT: + case CAIRO_EXTEND_REFLECT: + /* There's no point returning FALSE for EXTEND_PAD, as the image + * surface does not currently implement it either */ + case CAIRO_EXTEND_PAD: + return TRUE; + } + + ASSERT_NOT_REACHED; + return FALSE; +} + +static cairo_bool_t +_pattern_supported (const cairo_pattern_t *pattern) +{ + switch (pattern->type) { + case CAIRO_PATTERN_TYPE_SOLID: + case CAIRO_PATTERN_TYPE_LINEAR: + case CAIRO_PATTERN_TYPE_RADIAL: + case CAIRO_PATTERN_TYPE_MESH: + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + return TRUE; + + case CAIRO_PATTERN_TYPE_SURFACE: + return _surface_pattern_supported ((cairo_surface_pattern_t *) pattern); + + default: + ASSERT_NOT_REACHED; + return FALSE; + } +} + +static cairo_bool_t +_pdf_operator_supported (cairo_operator_t op) +{ + switch (op) { + case CAIRO_OPERATOR_OVER: + case CAIRO_OPERATOR_MULTIPLY: + case CAIRO_OPERATOR_SCREEN: + case CAIRO_OPERATOR_OVERLAY: + case CAIRO_OPERATOR_DARKEN: + case CAIRO_OPERATOR_LIGHTEN: + case CAIRO_OPERATOR_COLOR_DODGE: + case CAIRO_OPERATOR_COLOR_BURN: + case CAIRO_OPERATOR_HARD_LIGHT: + case CAIRO_OPERATOR_SOFT_LIGHT: + case CAIRO_OPERATOR_DIFFERENCE: + case CAIRO_OPERATOR_EXCLUSION: + case CAIRO_OPERATOR_HSL_HUE: + case CAIRO_OPERATOR_HSL_SATURATION: + case CAIRO_OPERATOR_HSL_COLOR: + case CAIRO_OPERATOR_HSL_LUMINOSITY: + return TRUE; + + default: + case CAIRO_OPERATOR_CLEAR: + case CAIRO_OPERATOR_SOURCE: + case CAIRO_OPERATOR_IN: + case CAIRO_OPERATOR_OUT: + case CAIRO_OPERATOR_ATOP: + case CAIRO_OPERATOR_DEST: + case CAIRO_OPERATOR_DEST_OVER: + case CAIRO_OPERATOR_DEST_IN: + case CAIRO_OPERATOR_DEST_OUT: + case CAIRO_OPERATOR_DEST_ATOP: + case CAIRO_OPERATOR_XOR: + case CAIRO_OPERATOR_ADD: + case CAIRO_OPERATOR_SATURATE: + return FALSE; + } +} + +static cairo_int_status_t +_cairo_pdf_surface_analyze_operation (cairo_pdf_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *pattern, + const cairo_rectangle_int_t *extents) +{ + if (surface->force_fallbacks && + surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) + { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + if (! _pattern_supported (pattern)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (_pdf_operator_supported (op)) { + if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { + cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern; + + if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) { + if (pattern->extend == CAIRO_EXTEND_PAD) { + cairo_box_t box; + cairo_rectangle_int_t rect; + cairo_rectangle_int_t rec_extents; + + /* get the operation extents in pattern space */ + _cairo_box_from_rectangle (&box, extents); + _cairo_matrix_transform_bounding_box_fixed (&pattern->matrix, &box, NULL); + _cairo_box_round_to_rectangle (&box, &rect); + + /* Check if surface needs padding to fill extents */ + if (_cairo_surface_get_extents (surface_pattern->surface, &rec_extents)) { + if (_cairo_fixed_integer_ceil(box.p1.x) < rec_extents.x || + _cairo_fixed_integer_ceil(box.p1.y) < rec_extents.y || + _cairo_fixed_integer_floor(box.p2.x) > rec_extents.x + rec_extents.width || + _cairo_fixed_integer_floor(box.p2.y) > rec_extents.y + rec_extents.height) + { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + } + } + return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN; + } + } + + return CAIRO_STATUS_SUCCESS; + } + + + /* The SOURCE operator is supported if the pattern is opaque or if + * there is nothing painted underneath. */ + if (op == CAIRO_OPERATOR_SOURCE) { + if (surface->type3_replay) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { + cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern; + + if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) { + if (_cairo_pattern_is_opaque (pattern, extents)) { + return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN; + } else { + /* FIXME: The analysis surface does not yet have + * the capability to analyze a non opaque recording + * surface and mark it supported if there is + * nothing underneath. For now recording surfaces of + * type CONTENT_COLOR_ALPHA painted with + * OPERATOR_SOURCE will result in a fallback + * image. */ + + return CAIRO_INT_STATUS_UNSUPPORTED; + } + } else { + return _cairo_pdf_surface_analyze_surface_pattern_transparency (surface, + surface_pattern); + } + } + + if (_cairo_pattern_is_opaque (pattern, extents)) + return CAIRO_STATUS_SUCCESS; + else + return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY; + } + + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_bool_t +_cairo_pdf_surface_operation_supported (cairo_pdf_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *pattern, + const cairo_rectangle_int_t *extents) +{ + return _cairo_pdf_surface_analyze_operation (surface, op, pattern, extents) != CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_pdf_surface_start_fallback (cairo_pdf_surface_t *surface) +{ + cairo_box_double_t bbox; + cairo_int_status_t status; + + status = _cairo_pdf_surface_close_content_stream (surface, FALSE); + if (unlikely (status)) + return status; + + status = _cairo_array_append (&surface->knockout_group, &surface->content); + if (unlikely (status)) + return status; + + _cairo_pdf_group_resources_clear (&surface->resources); + bbox.p1.x = 0; + bbox.p1.y = 0; + bbox.p2.x = surface->width; + bbox.p2.y = surface->height; + status = _cairo_pdf_surface_open_content_stream (surface, &bbox, NULL, TRUE, TRUE, -1); + if (unlikely (status)) + return status; + + return _cairo_pdf_interchange_begin_page_content (surface); +} + +/* If source is an opaque image and mask is an image and both images + * have the same bounding box we can emit them as a image/smask pair. + */ +static cairo_int_status_t +_cairo_pdf_surface_emit_combined_smask (cairo_pdf_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_rectangle_int_t *extents) +{ + cairo_int_status_t status; + cairo_image_surface_t *image; + void *image_extra; + cairo_image_transparency_t transparency; + int src_width, src_height; + int mask_width, mask_height; + double src_x_offset, src_y_offset; + double mask_x_offset, mask_y_offset; + double src_x1, src_y1, src_x2, src_y2; + double mask_x1, mask_y1, mask_x2, mask_y2; + cairo_matrix_t p2u; + double src_radius, mask_radius, e; + cairo_bool_t need_smask; + cairo_pdf_source_surface_entry_t *pdf_source; + + /* Check that source and mask are images */ + + if (!((source->type == CAIRO_PATTERN_TYPE_SURFACE || source->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) && + (mask->type == CAIRO_PATTERN_TYPE_SURFACE || mask->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE))) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (source->type == CAIRO_PATTERN_TYPE_SURFACE && + ((cairo_surface_pattern_t *) source)->surface->type == CAIRO_SURFACE_TYPE_RECORDING) + { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + if (mask->type == CAIRO_PATTERN_TYPE_SURFACE && + ((cairo_surface_pattern_t *) mask)->surface->type == CAIRO_SURFACE_TYPE_RECORDING) + { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + if (source->extend != CAIRO_EXTEND_NONE || mask->extend != CAIRO_EXTEND_NONE) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* Check that source is opaque and get image sizes */ + + status = _cairo_pdf_surface_acquire_source_image_from_pattern (surface, source, + &image, &image_extra); + if (unlikely (status)) + return status; + + if (image->base.status) + return image->base.status; + + src_width = image->width; + src_height = image->height; + if (source->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) { + cairo_surface_get_device_offset (&image->base, &src_x_offset, &src_y_offset); + } else { + src_x_offset = 0; + src_y_offset = 0; + } + + transparency = _cairo_image_analyze_transparency (image); + _cairo_pdf_surface_release_source_image_from_pattern (surface, source, image, image_extra); + + if (transparency != CAIRO_IMAGE_IS_OPAQUE) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_pdf_surface_acquire_source_image_from_pattern (surface, mask, + &image, &image_extra); + if (unlikely (status)) + return status; + + if (image->base.status) + return image->base.status; + + mask_width = image->width; + mask_height = image->height; + if (mask->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) { + cairo_surface_get_device_offset (&image->base, &mask_x_offset, &mask_y_offset); + } else { + mask_x_offset = 0; + mask_y_offset = 0; + } + + transparency = _cairo_image_analyze_transparency (image); + need_smask = transparency != CAIRO_IMAGE_IS_OPAQUE; + + _cairo_pdf_surface_release_source_image_from_pattern (surface, mask, image, image_extra); + + /* Check that both images have the same extents with a tolerance + * of half the smallest source pixel. */ + + p2u = source->matrix; + status = cairo_matrix_invert (&p2u); + /* cairo_pattern_set_matrix ensures the matrix is invertible */ + assert (status == CAIRO_INT_STATUS_SUCCESS); + src_x1 = 0; + src_y1 = 0; + src_x2 = src_width; + src_y2 = src_height; + cairo_matrix_transform_point (&p2u, &src_x1, &src_y1); + cairo_matrix_transform_point (&p2u, &src_x2, &src_y2); + src_radius = _cairo_matrix_transformed_circle_major_axis (&p2u, 0.5); + + p2u = mask->matrix; + status = cairo_matrix_invert (&p2u); + /* cairo_pattern_set_matrix ensures the matrix is invertible */ + assert (status == CAIRO_INT_STATUS_SUCCESS); + mask_x1 = 0; + mask_y1 = 0; + mask_x2 = mask_width; + mask_y2 = mask_height; + cairo_matrix_transform_point (&p2u, &mask_x1, &mask_y1); + cairo_matrix_transform_point (&p2u, &mask_x2, &mask_y2); + mask_radius = _cairo_matrix_transformed_circle_major_axis (&p2u, 0.5); + + if (src_radius < mask_radius) + e = src_radius; + else + e = mask_radius; + + if (fabs(src_x1 - mask_x1) > e || + fabs(src_x2 - mask_x2) > e || + fabs(src_y1 - mask_y1) > e || + fabs(src_y2 - mask_y2) > e) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* Check both images have same device offset */ + if (fabs(src_x_offset - mask_x_offset) > e || + fabs(src_y_offset - mask_y_offset) > e) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (need_smask) { + status = _cairo_pdf_surface_add_source_surface (surface, + NULL, + mask, + -1, /* node_surface_index */ + op, + source->filter, + FALSE, /* stencil mask */ + TRUE, /* smask */ + FALSE, /* need_transp_group */ + extents, + NULL, /* smask_res */ + &pdf_source, + NULL, + NULL, + NULL); + if (unlikely (status)) + return status; + } + + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->output, "q\n"); + status = _cairo_pdf_surface_paint_surface_pattern (surface, op, source, + CAIRO_ANALYSIS_SOURCE_NONE, + extents, + 1.0, /* alpha */ + need_smask ? &pdf_source->surface_res : NULL, + FALSE); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->output, "Q\n"); + + status = _cairo_output_stream_get_status (surface->output); + + + return status; +} + +/* A PDF stencil mask is an A1 mask used with the current color */ +static cairo_int_status_t +_cairo_pdf_surface_emit_stencil_mask (cairo_pdf_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_rectangle_int_t *extents) +{ + cairo_int_status_t status; + cairo_image_surface_t *image; + void *image_extra; + cairo_image_transparency_t transparency; + cairo_pdf_resource_t pattern_res = {0}; + + if (! (source->type == CAIRO_PATTERN_TYPE_SOLID && + (mask->type == CAIRO_PATTERN_TYPE_SURFACE || mask->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE))) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (mask->type == CAIRO_PATTERN_TYPE_SURFACE && + ((cairo_surface_pattern_t *) mask)->surface->type == CAIRO_SURFACE_TYPE_RECORDING) + { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + status = _cairo_pdf_surface_acquire_source_image_from_pattern (surface, mask, + &image, &image_extra); + if (unlikely (status)) + return status; + + if (image->base.status) + return image->base.status; + + transparency = _cairo_image_analyze_transparency (image); + if (transparency != CAIRO_IMAGE_IS_OPAQUE && + transparency != CAIRO_IMAGE_HAS_BILEVEL_ALPHA) + { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto cleanup; + } + + status = _cairo_pdf_surface_select_pattern (surface, source, + pattern_res, FALSE); + if (unlikely (status)) + return status; + + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->output, "q\n"); + status = _cairo_pdf_surface_paint_surface_pattern (surface, op, mask, + CAIRO_ANALYSIS_SOURCE_NONE, + extents, 1.0, NULL, TRUE); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->output, "Q\n"); + + status = _cairo_output_stream_get_status (surface->output); + +cleanup: + _cairo_pdf_surface_release_source_image_from_pattern (surface, mask, image, image_extra); + + return status; +} + +static cairo_int_status_t +_cairo_pdf_surface_set_clip (cairo_pdf_surface_t *surface, + cairo_composite_rectangles_t *composite) +{ + cairo_clip_t *clip = composite->clip; + + if (_cairo_composite_rectangles_can_reduce_clip (composite, clip)) + clip = NULL; + + if (clip == NULL) { + if (_cairo_composite_rectangles_can_reduce_clip (composite, + surface->clipper.clip)) + return CAIRO_STATUS_SUCCESS; + } + + return _cairo_surface_clipper_set_clip (&surface->clipper, clip); +} + +static cairo_int_status_t +_cairo_pdf_surface_paint (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip) +{ + cairo_pdf_surface_t *surface = abstract_surface; + cairo_pdf_smask_group_t *group; + cairo_pdf_resource_t pattern_res, gstate_res; + cairo_composite_rectangles_t extents; + cairo_int_status_t status; + + status = _cairo_composite_rectangles_init_for_paint (&extents, + &surface->base, + op, source, clip); + if (unlikely (status)) + return status; + + status = _cairo_pdf_interchange_add_operation_extents (surface, &extents.bounded); + if (unlikely (status)) + return status; + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) { + status = _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded); + goto cleanup; + } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) { + status = _cairo_pdf_surface_start_fallback (surface); + if (unlikely (status)) + goto cleanup; + } + + assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded)); + + status = _cairo_pdf_surface_set_clip (surface, &extents); + if (unlikely (status)) + goto cleanup; + + status = _cairo_pdf_surface_select_operator (surface, op); + if (unlikely (status)) + goto cleanup; + + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (unlikely (status)) + goto cleanup; + + if (_can_paint_pattern (source)) { + _cairo_output_stream_printf (surface->output, "q\n"); + status = _cairo_pdf_surface_paint_pattern (surface, + op, + source, + CAIRO_ANALYSIS_SOURCE_PAINT, + &extents.bounded, + 1.0, /* alpha */ + FALSE); /* mask */ + if (unlikely (status)) + goto cleanup; + + _cairo_output_stream_printf (surface->output, "Q\n"); + _cairo_composite_rectangles_fini (&extents); + return _cairo_output_stream_get_status (surface->output); + } + + pattern_res.id = 0; + gstate_res.id = 0; + status = _cairo_pdf_surface_add_pdf_pattern (surface, source, op, + CAIRO_ANALYSIS_SOURCE_PAINT, + &extents.bounded, + &pattern_res, &gstate_res); + if (unlikely (status)) + goto cleanup; + + if (gstate_res.id != 0) { + group = _cairo_pdf_surface_create_smask_group (surface, &extents.bounded); + if (unlikely (group == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto cleanup; + } + + group->operation = PDF_PAINT; + status = _cairo_pattern_create_copy (&group->source, source); + if (unlikely (status)) { + _cairo_pdf_smask_group_destroy (group); + goto cleanup; + } + group->source_res = pattern_res; + status = _cairo_pdf_surface_add_smask_group (surface, group); + if (unlikely (status)) { + _cairo_pdf_smask_group_destroy (group); + goto cleanup; + } + + status = _cairo_pdf_surface_add_smask (surface, gstate_res); + if (unlikely (status)) + goto cleanup; + + status = _cairo_pdf_surface_add_xobject (surface, group->group_res); + if (unlikely (status)) + goto cleanup; + + _cairo_output_stream_printf (surface->output, + "q /s%d gs /x%d Do Q\n", + gstate_res.id, + group->group_res.id); + } else { + status = _cairo_pdf_surface_select_pattern (surface, source, + pattern_res, FALSE); + if (unlikely (status)) + goto cleanup; + + _cairo_output_stream_printf (surface->output, + "%d %d %d %d re f\n", + surface->surface_extents.x, + surface->surface_extents.y, + surface->surface_extents.width, + surface->surface_extents.height); + + status = _cairo_pdf_surface_unselect_pattern (surface); + if (unlikely (status)) + goto cleanup; + } + + _cairo_composite_rectangles_fini (&extents); + return _cairo_output_stream_get_status (surface->output); + +cleanup: + _cairo_composite_rectangles_fini (&extents); + return status; +} + +static cairo_int_status_t +_cairo_pdf_surface_mask (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_clip_t *clip) +{ + cairo_pdf_surface_t *surface = abstract_surface; + cairo_pdf_smask_group_t *group; + cairo_composite_rectangles_t extents; + cairo_int_status_t status; + cairo_rectangle_int_t r; + cairo_box_t box; + double alpha; + + status = _cairo_composite_rectangles_init_for_mask (&extents, + &surface->base, + op, source, mask, clip); + if (unlikely (status)) + return status; + + status = _cairo_pdf_interchange_add_operation_extents (surface, &extents.bounded); + if (unlikely (status)) + return status; + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) { + cairo_int_status_t source_status, mask_status; + + status = _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded); + if (_cairo_int_status_is_error (status)) + goto cleanup; + source_status = status; + + if (mask->has_component_alpha) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + } else { + status = _cairo_pdf_surface_analyze_operation (surface, op, mask, &extents.bounded); + if (_cairo_int_status_is_error (status)) + goto cleanup; + } + mask_status = status; + + _cairo_composite_rectangles_fini (&extents); + return _cairo_analysis_surface_merge_status (source_status, + mask_status); + } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) { + status = _cairo_pdf_surface_start_fallback (surface); + if (unlikely (status)) + goto cleanup; + } + + assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded)); + assert (_cairo_pdf_surface_operation_supported (surface, op, mask, &extents.bounded)); + + /* get the accurate extents */ + status = _cairo_pattern_get_ink_extents (source, &r); + if (unlikely (status)) + goto cleanup; + + /* XXX slight impedance mismatch */ + _cairo_box_from_rectangle (&box, &r); + status = _cairo_composite_rectangles_intersect_source_extents (&extents, + &box); + if (unlikely (status)) + goto cleanup; + + status = _cairo_pattern_get_ink_extents (mask, &r); + if (unlikely (status)) + goto cleanup; + + _cairo_box_from_rectangle (&box, &r); + status = _cairo_composite_rectangles_intersect_mask_extents (&extents, + &box); + if (unlikely (status)) + goto cleanup; + + status = _cairo_pdf_surface_set_clip (surface, &extents); + if (unlikely (status)) + goto cleanup; + + status = _cairo_pdf_surface_select_operator (surface, op); + if (unlikely (status)) + goto cleanup; + + /* Check if we can combine source and mask into a smask image */ + status = _cairo_pdf_surface_emit_combined_smask (surface, op, source, mask, &extents.bounded); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + goto cleanup; + + /* Check if we can use a stencil mask */ + status = _cairo_pdf_surface_emit_stencil_mask (surface, op, source, mask, &extents.bounded); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + goto cleanup; + + /* Check if we can set ca/CA instead of an smask. We could handle + * other source patterns as well but for now this is the easiest, + * and most common, case to handle. */ + if (_cairo_pattern_is_constant_alpha (mask, &extents.bounded, &alpha) && + _can_paint_pattern (source)) { + + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (unlikely (status)) + goto cleanup; + + _cairo_output_stream_printf (surface->output, "q\n"); + status = _cairo_pdf_surface_paint_pattern (surface, + op, + source, + CAIRO_ANALYSIS_SOURCE_MASK, + &extents.bounded, + alpha, + FALSE); /* mask */ + if (unlikely (status)) + goto cleanup; + + _cairo_output_stream_printf (surface->output, "Q\n"); + _cairo_composite_rectangles_fini (&extents); + return _cairo_output_stream_get_status (surface->output); + } + + group = _cairo_pdf_surface_create_smask_group (surface, &extents.bounded); + if (unlikely (group == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto cleanup; + } + + group->operation = PDF_MASK; + status = _cairo_pattern_create_copy (&group->source, source); + if (unlikely (status)) { + _cairo_pdf_smask_group_destroy (group); + goto cleanup; + } + status = _cairo_pattern_create_copy (&group->mask, mask); + if (unlikely (status)) { + _cairo_pdf_smask_group_destroy (group); + goto cleanup; + } + group->source_res = _cairo_pdf_surface_new_object (surface); + if (group->source_res.id == 0) { + _cairo_pdf_smask_group_destroy (group); + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto cleanup; + } + + status = _cairo_pdf_surface_add_smask_group (surface, group); + if (unlikely (status)) { + _cairo_pdf_smask_group_destroy (group); + goto cleanup; + } + + status = _cairo_pdf_surface_add_smask (surface, group->group_res); + if (unlikely (status)) + goto cleanup; + + status = _cairo_pdf_surface_add_xobject (surface, group->source_res); + if (unlikely (status)) + goto cleanup; + + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (unlikely (status)) + goto cleanup; + + _cairo_output_stream_printf (surface->output, + "q /s%d gs /x%d Do Q\n", + group->group_res.id, + group->source_res.id); + + _cairo_composite_rectangles_fini (&extents); + return _cairo_output_stream_get_status (surface->output); + +cleanup: + _cairo_composite_rectangles_fini (&extents); + return status; +} + +static cairo_int_status_t +_cairo_pdf_surface_stroke (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_pdf_surface_t *surface = abstract_surface; + cairo_pdf_smask_group_t *group; + cairo_pdf_resource_t pattern_res, gstate_res; + cairo_composite_rectangles_t extents; + cairo_int_status_t status; + + status = _cairo_composite_rectangles_init_for_stroke (&extents, + &surface->base, + op, source, + path, style, ctm, + clip); + if (unlikely (status)) + return status; + + /* use the more accurate extents */ + if (extents.is_bounded) { + cairo_rectangle_int_t mask; + cairo_box_t box; + + status = _cairo_path_fixed_stroke_extents (path, style, + ctm, ctm_inverse, + tolerance, + &mask); + if (unlikely (status)) + goto cleanup; + + _cairo_box_from_rectangle (&box, &mask); + status = _cairo_composite_rectangles_intersect_mask_extents (&extents, + &box); + if (unlikely (status)) + goto cleanup; + } + + status = _cairo_pdf_interchange_add_operation_extents (surface, &extents.bounded); + if (unlikely (status)) + goto cleanup; + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) { + status = _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded); + goto cleanup; + } + + assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded)); + + status = _cairo_pdf_surface_set_clip (surface, &extents); + if (unlikely (status)) + goto cleanup; + + pattern_res.id = 0; + gstate_res.id = 0; + status = _cairo_pdf_surface_add_pdf_pattern (surface, source, op, + CAIRO_ANALYSIS_SOURCE_STROKE, + &extents.bounded, + &pattern_res, &gstate_res); + if (unlikely (status)) + goto cleanup; + + status = _cairo_pdf_surface_select_operator (surface, op); + if (unlikely (status)) + goto cleanup; + + if (gstate_res.id != 0) { + group = _cairo_pdf_surface_create_smask_group (surface, &extents.bounded); + if (unlikely (group == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto cleanup; + } + + group->operation = PDF_STROKE; + status = _cairo_pattern_create_copy (&group->source, source); + if (unlikely (status)) { + _cairo_pdf_smask_group_destroy (group); + goto cleanup; + } + group->source_res = pattern_res; + status = _cairo_path_fixed_init_copy (&group->path, path); + if (unlikely (status)) { + _cairo_pdf_smask_group_destroy (group); + goto cleanup; + } + + group->style = *style; + group->ctm = *ctm; + group->ctm_inverse = *ctm_inverse; + status = _cairo_pdf_surface_add_smask_group (surface, group); + if (unlikely (status)) { + _cairo_pdf_smask_group_destroy (group); + goto cleanup; + } + + status = _cairo_pdf_surface_add_smask (surface, gstate_res); + if (unlikely (status)) + goto cleanup; + + status = _cairo_pdf_surface_add_xobject (surface, group->group_res); + if (unlikely (status)) + goto cleanup; + + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (unlikely (status)) + goto cleanup; + + _cairo_output_stream_printf (surface->output, + "q /s%d gs /x%d Do Q\n", + gstate_res.id, + group->group_res.id); + } else { + status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, TRUE); + if (unlikely (status)) + goto cleanup; + + status = _cairo_pdf_operators_stroke (&surface->pdf_operators, + path, + style, + ctm, + ctm_inverse); + if (unlikely (status)) + goto cleanup; + + status = _cairo_pdf_surface_unselect_pattern (surface); + if (unlikely (status)) + goto cleanup; + } + + _cairo_composite_rectangles_fini (&extents); + return _cairo_output_stream_get_status (surface->output); + +cleanup: + _cairo_composite_rectangles_fini (&extents); + return status; +} + +static cairo_int_status_t +_cairo_pdf_surface_fill (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t*path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_pdf_surface_t *surface = abstract_surface; + cairo_int_status_t status; + cairo_pdf_smask_group_t *group; + cairo_pdf_resource_t pattern_res, gstate_res; + cairo_composite_rectangles_t extents; + + status = _cairo_composite_rectangles_init_for_fill (&extents, + &surface->base, + op, source, path, + clip); + if (unlikely (status)) + return status; + + /* use the more accurate extents */ + if (extents.is_bounded) { + cairo_rectangle_int_t mask; + cairo_box_t box; + + _cairo_path_fixed_fill_extents (path, + fill_rule, + tolerance, + &mask); + + _cairo_box_from_rectangle (&box, &mask); + status = _cairo_composite_rectangles_intersect_mask_extents (&extents, + &box); + if (unlikely (status)) + goto cleanup; + } + + status = _cairo_pdf_interchange_add_operation_extents (surface, &extents.bounded); + if (unlikely (status)) + goto cleanup; + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) { + status = _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded); + goto cleanup; + } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) { + status = _cairo_pdf_surface_start_fallback (surface); + if (unlikely (status)) + goto cleanup; + } + + assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded)); + + status = _cairo_pdf_surface_set_clip (surface, &extents); + if (unlikely (status)) + goto cleanup; + + status = _cairo_pdf_surface_select_operator (surface, op); + if (unlikely (status)) + goto cleanup; + + if (_can_paint_pattern (source)) { + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (unlikely (status)) + goto cleanup; + + _cairo_output_stream_printf (surface->output, "q\n"); + status = _cairo_pdf_operators_clip (&surface->pdf_operators, + path, + fill_rule); + if (unlikely (status)) + goto cleanup; + + status = _cairo_pdf_surface_paint_pattern (surface, + op, + source, + CAIRO_ANALYSIS_SOURCE_FILL, + &extents.bounded, + 1.0, /* alpha */ + FALSE); /* mask */ + if (unlikely (status)) + goto cleanup; + + _cairo_output_stream_printf (surface->output, "Q\n"); + status = _cairo_output_stream_get_status (surface->output); + goto cleanup; + } + + pattern_res.id = 0; + gstate_res.id = 0; + status = _cairo_pdf_surface_add_pdf_pattern (surface, source, op, + CAIRO_ANALYSIS_SOURCE_FILL, + &extents.bounded, + &pattern_res, &gstate_res); + if (unlikely (status)) + goto cleanup; + + if (gstate_res.id != 0) { + group = _cairo_pdf_surface_create_smask_group (surface, &extents.bounded); + if (unlikely (group == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto cleanup; + } + + group->operation = PDF_FILL; + status = _cairo_pattern_create_copy (&group->source, source); + if (unlikely (status)) { + _cairo_pdf_smask_group_destroy (group); + goto cleanup; + } + group->source_res = pattern_res; + status = _cairo_path_fixed_init_copy (&group->path, path); + if (unlikely (status)) { + _cairo_pdf_smask_group_destroy (group); + goto cleanup; + } + + group->fill_rule = fill_rule; + status = _cairo_pdf_surface_add_smask_group (surface, group); + if (unlikely (status)) { + _cairo_pdf_smask_group_destroy (group); + goto cleanup; + } + + status = _cairo_pdf_surface_add_smask (surface, gstate_res); + if (unlikely (status)) + goto cleanup; + + status = _cairo_pdf_surface_add_xobject (surface, group->group_res); + if (unlikely (status)) + goto cleanup; + + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (unlikely (status)) + goto cleanup; + + _cairo_output_stream_printf (surface->output, + "q /s%d gs /x%d Do Q\n", + gstate_res.id, + group->group_res.id); + } else { + status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, FALSE); + if (unlikely (status)) + goto cleanup; + + status = _cairo_pdf_operators_fill (&surface->pdf_operators, + path, + fill_rule); + if (unlikely (status)) + goto cleanup; + + status = _cairo_pdf_surface_unselect_pattern (surface); + if (unlikely (status)) + goto cleanup; + } + + _cairo_composite_rectangles_fini (&extents); + return _cairo_output_stream_get_status (surface->output); + +cleanup: + _cairo_composite_rectangles_fini (&extents); + return status; +} + +static cairo_int_status_t +_cairo_pdf_surface_fill_stroke (void *abstract_surface, + cairo_operator_t fill_op, + const cairo_pattern_t *fill_source, + cairo_fill_rule_t fill_rule, + double fill_tolerance, + cairo_antialias_t fill_antialias, + const cairo_path_fixed_t*path, + cairo_operator_t stroke_op, + const cairo_pattern_t *stroke_source, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *stroke_ctm, + const cairo_matrix_t *stroke_ctm_inverse, + double stroke_tolerance, + cairo_antialias_t stroke_antialias, + const cairo_clip_t *clip) +{ + cairo_pdf_surface_t *surface = abstract_surface; + cairo_int_status_t status; + cairo_pdf_resource_t fill_pattern_res, stroke_pattern_res, gstate_res; + cairo_composite_rectangles_t extents; + + /* During analysis we return unsupported and let the _fill and + * _stroke functions that are on the fallback path do the analysis + * for us. During render we may still encounter unsupported + * combinations of fill/stroke patterns. However we can return + * unsupported anytime to let the _fill and _stroke functions take + * over. + */ + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* PDF rendering of fill-stroke is not the same as cairo when + * either the fill or stroke is not opaque. + */ + if ( !_cairo_pattern_is_opaque (fill_source, NULL) || + !_cairo_pattern_is_opaque (stroke_source, NULL)) + { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + if (fill_op != stroke_op) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* Compute the operation extents using the stroke which will naturally + * be larger than the fill extents. + */ + status = _cairo_composite_rectangles_init_for_stroke (&extents, + &surface->base, + stroke_op, stroke_source, + path, stroke_style, stroke_ctm, + clip); + if (unlikely (status)) + return status; + + /* use the more accurate extents */ + if (extents.is_bounded) { + cairo_rectangle_int_t mask; + cairo_box_t box; + + status = _cairo_path_fixed_stroke_extents (path, stroke_style, + stroke_ctm, stroke_ctm_inverse, + stroke_tolerance, + &mask); + if (unlikely (status)) + goto cleanup; + + _cairo_box_from_rectangle (&box, &mask); + status = _cairo_composite_rectangles_intersect_mask_extents (&extents, + &box); + if (unlikely (status)) + goto cleanup; + } + + status = _cairo_pdf_surface_set_clip (surface, &extents); + if (unlikely (status)) + goto cleanup; + + status = _cairo_pdf_surface_select_operator (surface, fill_op); + if (unlikely (status)) + goto cleanup; + + /* use the more accurate extents */ + if (extents.is_bounded) { + cairo_rectangle_int_t mask; + cairo_box_t box; + + _cairo_path_fixed_fill_extents (path, + fill_rule, + fill_tolerance, + &mask); + + _cairo_box_from_rectangle (&box, &mask); + status = _cairo_composite_rectangles_intersect_mask_extents (&extents, + &box); + if (unlikely (status)) + goto cleanup; + } + + status = _cairo_pdf_interchange_add_operation_extents (surface, &extents.bounded); + if (unlikely (status)) + goto cleanup; + + fill_pattern_res.id = 0; + gstate_res.id = 0; + status = _cairo_pdf_surface_add_pdf_pattern (surface, fill_source, + fill_op, + CAIRO_ANALYSIS_SOURCE_FILL, + &extents.bounded, + &fill_pattern_res, + &gstate_res); + if (unlikely (status)) + goto cleanup; + + assert (gstate_res.id == 0); + + stroke_pattern_res.id = 0; + gstate_res.id = 0; + status = _cairo_pdf_surface_add_pdf_pattern (surface, + stroke_source, + stroke_op, + CAIRO_ANALYSIS_SOURCE_STROKE, + &extents.bounded, + &stroke_pattern_res, + &gstate_res); + if (unlikely (status)) + goto cleanup; + + assert (gstate_res.id == 0); + + /* As PDF has separate graphics state for fill and stroke we can + * select both at the same time */ + status = _cairo_pdf_surface_select_pattern (surface, fill_source, + fill_pattern_res, FALSE); + if (unlikely (status)) + goto cleanup; + + status = _cairo_pdf_surface_select_pattern (surface, stroke_source, + stroke_pattern_res, TRUE); + if (unlikely (status)) + goto cleanup; + + status = _cairo_pdf_operators_fill_stroke (&surface->pdf_operators, + path, + fill_rule, + stroke_style, + stroke_ctm, + stroke_ctm_inverse); + if (unlikely (status)) + goto cleanup; + + status = _cairo_pdf_surface_unselect_pattern (surface); + if (unlikely (status)) + goto cleanup; + + _cairo_composite_rectangles_fini (&extents); + return _cairo_output_stream_get_status (surface->output); + +cleanup: + _cairo_composite_rectangles_fini (&extents); + return status; +} + +static cairo_bool_t +_cairo_pdf_surface_has_show_text_glyphs (void *abstract_surface) +{ + return TRUE; +} + +static cairo_int_status_t +_cairo_pdf_surface_show_text_glyphs (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const char *utf8, + int utf8_len, + cairo_glyph_t *glyphs, + int num_glyphs, + const cairo_text_cluster_t *clusters, + int num_clusters, + cairo_text_cluster_flags_t cluster_flags, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip) +{ + cairo_pdf_surface_t *surface = abstract_surface; + cairo_pdf_smask_group_t *group; + cairo_pdf_resource_t pattern_res, gstate_res; + cairo_composite_rectangles_t extents; + cairo_bool_t overlap; + cairo_int_status_t status; + + status = _cairo_composite_rectangles_init_for_glyphs (&extents, + &surface->base, + op, source, + scaled_font, + glyphs, num_glyphs, + clip, + &overlap); + if (unlikely (status)) + return status; + + status = _cairo_pdf_interchange_add_content (surface); + if (unlikely (status)) + return status; + + status = _cairo_pdf_interchange_add_operation_extents (surface, &extents.bounded); + if (unlikely (status)) + return status; + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) { + /* Enabling text in Type 3 fonts currently crashes cairo. Most + * PDF viewers don't seem to suport text in Type 3 so we let + * this go to image fallback. + */ + if (surface->type3_replay) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_pdf_surface_analyze_operation (surface, op, source, &extents.bounded); + goto cleanup; + } + + assert (_cairo_pdf_surface_operation_supported (surface, op, source, &extents.bounded)); + + status = _cairo_pdf_surface_set_clip (surface, &extents); + if (unlikely (status)) + goto cleanup; + + pattern_res.id = 0; + gstate_res.id = 0; + status = _cairo_pdf_surface_add_pdf_pattern (surface, source, op, + CAIRO_ANALYSIS_SOURCE_SHOW_GLYPHS, + &extents.bounded, + &pattern_res, &gstate_res); + if (unlikely (status)) + goto cleanup; + + status = _cairo_pdf_surface_select_operator (surface, op); + if (unlikely (status)) + goto cleanup; + + if (gstate_res.id != 0) { + group = _cairo_pdf_surface_create_smask_group (surface, &extents.bounded); + if (unlikely (group == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto cleanup; + } + + group->operation = PDF_SHOW_GLYPHS; + status = _cairo_pattern_create_copy (&group->source, source); + if (unlikely (status)) { + _cairo_pdf_smask_group_destroy (group); + goto cleanup; + } + group->source_res = pattern_res; + + if (utf8_len) { + group->utf8 = _cairo_malloc (utf8_len); + if (unlikely (group->utf8 == NULL)) { + _cairo_pdf_smask_group_destroy (group); + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto cleanup; + } + memcpy (group->utf8, utf8, utf8_len); + } + group->utf8_len = utf8_len; + + if (num_glyphs) { + group->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); + if (unlikely (group->glyphs == NULL)) { + _cairo_pdf_smask_group_destroy (group); + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto cleanup; + } + memcpy (group->glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs); + } + group->num_glyphs = num_glyphs; + + if (num_clusters) { + group->clusters = _cairo_malloc_ab (num_clusters, sizeof (cairo_text_cluster_t)); + if (unlikely (group->clusters == NULL)) { + _cairo_pdf_smask_group_destroy (group); + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto cleanup; + } + memcpy (group->clusters, clusters, sizeof (cairo_text_cluster_t) * num_clusters); + } + group->num_clusters = num_clusters; + + group->scaled_font = cairo_scaled_font_reference (scaled_font); + status = _cairo_pdf_surface_add_smask_group (surface, group); + if (unlikely (status)) { + _cairo_pdf_smask_group_destroy (group); + goto cleanup; + } + + status = _cairo_pdf_surface_add_smask (surface, gstate_res); + if (unlikely (status)) + goto cleanup; + + status = _cairo_pdf_surface_add_xobject (surface, group->group_res); + if (unlikely (status)) + goto cleanup; + + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (unlikely (status)) + goto cleanup; + + _cairo_output_stream_printf (surface->output, + "q /s%d gs /x%d Do Q\n", + gstate_res.id, + group->group_res.id); + } else { + status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, FALSE); + if (unlikely (status)) + goto cleanup; + + /* User-fonts can use strokes; reset the stroke pattern as well. */ + if (_cairo_font_face_is_user(scaled_font->font_face)) { + status = _cairo_pdf_surface_select_pattern (surface, source, pattern_res, TRUE); + if (unlikely (status)) + goto cleanup; + } + + /* Each call to show_glyphs() with a transclucent pattern must + * be in a separate text object otherwise overlapping text + * from separate calls to show_glyphs will not composite with + * each other. */ + if (! _cairo_pattern_is_opaque (source, &extents.bounded)) { + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (unlikely (status)) + goto cleanup; + } + + status = _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators, + utf8, utf8_len, + glyphs, num_glyphs, + clusters, num_clusters, + cluster_flags, + scaled_font); + if (unlikely (status)) + goto cleanup; + + status = _cairo_pdf_surface_unselect_pattern (surface); + if (unlikely (status)) + goto cleanup; + } + + _cairo_composite_rectangles_fini (&extents); + return _cairo_output_stream_get_status (surface->output); + +cleanup: + _cairo_composite_rectangles_fini (&extents); + return status; +} + +static const char ** +_cairo_pdf_surface_get_supported_mime_types (void *abstract_surface) +{ + return _cairo_pdf_supported_mime_types; +} + +static cairo_int_status_t +_cairo_pdf_surface_tag (void *abstract_surface, + cairo_bool_t begin, + const char *tag_name, + const char *attributes) + +{ + cairo_pdf_surface_t *surface = abstract_surface; + cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; + + if (begin) + status = _cairo_pdf_interchange_tag_begin (surface, tag_name, attributes); + else + status = _cairo_pdf_interchange_tag_end (surface, tag_name); + + return status; +} + +static cairo_int_status_t +_cairo_pdf_surface_command_id (void *abstract_surface, + unsigned int recording_id, + unsigned int command_id) +{ + cairo_pdf_surface_t *surface = abstract_surface; + + return _cairo_pdf_interchange_command_id (surface, recording_id, command_id); +} + +/* The Type 3 font subset support will the embed the + * CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE image if vector operations + * are not supported. The only case we don't currently handle is if a + * foreground color is used. + */ +static cairo_bool_t +_cairo_pdf_surface_supports_color_glyph (void *abstract_surface, + cairo_scaled_font_t *scaled_font, + unsigned long glyph_index) +{ + cairo_pdf_surface_t *surface = abstract_surface; + cairo_pdf_color_glyph_t glyph_key; + cairo_pdf_color_glyph_t *glyph_entry; + cairo_scaled_glyph_t *scaled_glyph; + cairo_status_t status; + + glyph_key.scaled_font = scaled_font; + glyph_key.glyph_index = glyph_index; + + _cairo_pdf_color_glyph_init_key (&glyph_key); + glyph_entry = _cairo_hash_table_lookup (surface->color_glyphs, &glyph_key.base); + if (glyph_entry) + return glyph_entry->supported; + + glyph_entry = _cairo_calloc (sizeof (cairo_pdf_color_glyph_t)); + if (glyph_entry == NULL) { + status = _cairo_surface_set_error (&surface->base, + _cairo_error (CAIRO_STATUS_NO_MEMORY)); + return FALSE; + } + + glyph_entry->scaled_font = cairo_scaled_font_reference (scaled_font); + glyph_entry->glyph_index = glyph_index; + _cairo_pdf_color_glyph_init_key (glyph_entry); + + glyph_entry->supported = FALSE; + _cairo_scaled_font_freeze_cache (scaled_font); + status = _cairo_scaled_glyph_lookup (scaled_font, + glyph_index, + CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE, + NULL, /* foreground color */ + &scaled_glyph); + if (unlikely (status)) + goto done; + + glyph_entry->supported = !(scaled_glyph->recording_uses_foreground_color || + scaled_glyph->recording_uses_foreground_marker); + + done: + _cairo_scaled_font_thaw_cache (scaled_font); + + status = _cairo_hash_table_insert (surface->color_glyphs, + &glyph_entry->base); + if (unlikely(status)) { + status = _cairo_surface_set_error (&surface->base, + _cairo_error (CAIRO_STATUS_NO_MEMORY)); + return FALSE; + } + + return glyph_entry->supported; +} + +static cairo_int_status_t +_cairo_pdf_surface_analyze_recording_surface(void *abstract_surface, + const cairo_surface_pattern_t *recording_surface_pattern, + unsigned int region_id, + cairo_analysis_source_t source_type, + cairo_bool_t begin) +{ + cairo_pdf_surface_t *surface = abstract_surface; + cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; + + if (begin) { + status = _cairo_pdf_interchange_recording_source_surface_begin ( + surface, + recording_surface_pattern, + region_id, + source_type); + } else { + status = _cairo_pdf_interchange_recording_source_surface_end ( + surface, + recording_surface_pattern, + region_id, + source_type); + } + + return status; +} + +static cairo_int_status_t +_cairo_pdf_surface_set_paginated_mode (void *abstract_surface, + cairo_paginated_mode_t paginated_mode) +{ + cairo_pdf_surface_t *surface = abstract_surface; + cairo_int_status_t status; + + surface->paginated_mode = paginated_mode; + + status = _cairo_pdf_interchange_begin_page_content (surface); + if (unlikely (status)) + return status; + + if (paginated_mode == CAIRO_PAGINATED_MODE_RENDER) { + surface->surface_extents.x = 0; + surface->surface_extents.y = 0; + surface->surface_extents.width = ceil (surface->width); + surface->surface_extents.height = ceil (surface->height); + } + + return CAIRO_INT_STATUS_SUCCESS; +} + +static const cairo_surface_backend_t cairo_pdf_surface_backend = { + CAIRO_SURFACE_TYPE_PDF, + _cairo_pdf_surface_finish, + + _cairo_default_context_create, + + NULL, /* create similar: handled by wrapper */ + NULL, /* create similar image */ + NULL, /* map to image */ + NULL, /* unmap image */ + + _cairo_surface_default_source, + NULL, /* acquire_source_image */ + NULL, /* release_source_image */ + NULL, /* snapshot */ + + NULL, /* _cairo_pdf_surface_copy_page */ + _cairo_pdf_surface_show_page, + + _cairo_pdf_surface_get_extents, + _cairo_pdf_surface_get_font_options, + + NULL, /* flush */ + NULL, /* mark_dirty_rectangle */ + + /* Here are the drawing functions */ + _cairo_pdf_surface_paint, + _cairo_pdf_surface_mask, + _cairo_pdf_surface_stroke, + _cairo_pdf_surface_fill, + _cairo_pdf_surface_fill_stroke, + NULL, /* show_glyphs */ + _cairo_pdf_surface_has_show_text_glyphs, + _cairo_pdf_surface_show_text_glyphs, + _cairo_pdf_surface_get_supported_mime_types, + _cairo_pdf_surface_tag, + _cairo_pdf_surface_supports_color_glyph, + _cairo_pdf_surface_analyze_recording_surface, + _cairo_pdf_surface_command_id, +}; + +static const cairo_paginated_surface_backend_t +cairo_pdf_surface_paginated_backend = { + _cairo_pdf_surface_start_page, + _cairo_pdf_surface_set_paginated_mode, + NULL, /* set_bounding_box */ + _cairo_pdf_surface_has_fallback_images, + _cairo_pdf_surface_supports_fine_grained_fallbacks, + _cairo_pdf_surface_requires_thumbnail_image, + _cairo_pdf_surface_set_thumbnail_image, +}; diff --git a/local/recipes/libs/cairo/source/src/cairo-pdf.h b/local/recipes/libs/cairo/source/src/cairo-pdf.h new file mode 100644 index 0000000000..7e8025be30 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-pdf.h @@ -0,0 +1,170 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + */ + +#ifndef CAIRO_PDF_H +#define CAIRO_PDF_H + +#include "cairo.h" + +#if CAIRO_HAS_PDF_SURFACE + +CAIRO_BEGIN_DECLS + +/** + * cairo_pdf_version_t: + * @CAIRO_PDF_VERSION_1_4: The version 1.4 of the PDF specification. (Since 1.10) + * @CAIRO_PDF_VERSION_1_5: The version 1.5 of the PDF specification. (Since 1.10) + * @CAIRO_PDF_VERSION_1_6: The version 1.6 of the PDF specification. (Since 1.18) + * @CAIRO_PDF_VERSION_1_7: The version 1.7 of the PDF specification. (Since 1.18) + * + * #cairo_pdf_version_t is used to describe the version number of the PDF + * specification that a generated PDF file will conform to. + * + * Since: 1.10 + **/ +typedef enum _cairo_pdf_version { + CAIRO_PDF_VERSION_1_4, + CAIRO_PDF_VERSION_1_5, + CAIRO_PDF_VERSION_1_6, + CAIRO_PDF_VERSION_1_7 +} cairo_pdf_version_t; + +cairo_public cairo_surface_t * +cairo_pdf_surface_create (const char *filename, + double width_in_points, + double height_in_points); + +cairo_public cairo_surface_t * +cairo_pdf_surface_create_for_stream (cairo_write_func_t write_func, + void *closure, + double width_in_points, + double height_in_points); + +cairo_public void +cairo_pdf_surface_restrict_to_version (cairo_surface_t *surface, + cairo_pdf_version_t version); + +cairo_public void +cairo_pdf_get_versions (cairo_pdf_version_t const **versions, + int *num_versions); + +cairo_public const char * +cairo_pdf_version_to_string (cairo_pdf_version_t version); + +cairo_public void +cairo_pdf_surface_set_size (cairo_surface_t *surface, + double width_in_points, + double height_in_points); + +/** + * cairo_pdf_outline_flags_t: + * @CAIRO_PDF_OUTLINE_FLAG_OPEN: The outline item defaults to open in the PDF viewer (Since 1.16) + * @CAIRO_PDF_OUTLINE_FLAG_BOLD: The outline item is displayed by the viewer in bold text (Since 1.16) + * @CAIRO_PDF_OUTLINE_FLAG_ITALIC: The outline item is displayed by the viewer in italic text (Since 1.16) + * + * #cairo_pdf_outline_flags_t is used by the + * cairo_pdf_surface_add_outline() function specify the attributes of + * an outline item. These flags may be bitwise-or'd to produce any + * combination of flags. + * + * Since: 1.16 + **/ +typedef enum _cairo_pdf_outline_flags { + CAIRO_PDF_OUTLINE_FLAG_OPEN = 0x1, + CAIRO_PDF_OUTLINE_FLAG_BOLD = 0x2, + CAIRO_PDF_OUTLINE_FLAG_ITALIC = 0x4, +} cairo_pdf_outline_flags_t; + +#define CAIRO_PDF_OUTLINE_ROOT 0 + +cairo_public int +cairo_pdf_surface_add_outline (cairo_surface_t *surface, + int parent_id, + const char *utf8, + const char *link_attribs, + cairo_pdf_outline_flags_t flags); + +/** + * cairo_pdf_metadata_t: + * @CAIRO_PDF_METADATA_TITLE: The document title (Since 1.16) + * @CAIRO_PDF_METADATA_AUTHOR: The document author (Since 1.16) + * @CAIRO_PDF_METADATA_SUBJECT: The document subject (Since 1.16) + * @CAIRO_PDF_METADATA_KEYWORDS: The document keywords (Since 1.16) + * @CAIRO_PDF_METADATA_CREATOR: The document creator (Since 1.16) + * @CAIRO_PDF_METADATA_CREATE_DATE: The document creation date (Since 1.16) + * @CAIRO_PDF_METADATA_MOD_DATE: The document modification date (Since 1.16) + * + * #cairo_pdf_metadata_t is used by the + * cairo_pdf_surface_set_metadata() function specify the metadata to set. + * + * Since: 1.16 + **/ +typedef enum _cairo_pdf_metadata { + CAIRO_PDF_METADATA_TITLE, + CAIRO_PDF_METADATA_AUTHOR, + CAIRO_PDF_METADATA_SUBJECT, + CAIRO_PDF_METADATA_KEYWORDS, + CAIRO_PDF_METADATA_CREATOR, + CAIRO_PDF_METADATA_CREATE_DATE, + CAIRO_PDF_METADATA_MOD_DATE, +} cairo_pdf_metadata_t; + +cairo_public void +cairo_pdf_surface_set_metadata (cairo_surface_t *surface, + cairo_pdf_metadata_t metadata, + const char *utf8); + +cairo_public void +cairo_pdf_surface_set_custom_metadata (cairo_surface_t *surface, + const char *name, + const char *value); + +cairo_public void +cairo_pdf_surface_set_page_label (cairo_surface_t *surface, + const char *utf8); + +cairo_public void +cairo_pdf_surface_set_thumbnail_size (cairo_surface_t *surface, + int width, + int height); + +CAIRO_END_DECLS + +#else /* CAIRO_HAS_PDF_SURFACE */ +# error Cairo was not compiled with support for the pdf backend +#endif /* CAIRO_HAS_PDF_SURFACE */ + +#endif /* CAIRO_PDF_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-pen.c b/local/recipes/libs/cairo/source/src/cairo-pen.c new file mode 100644 index 0000000000..a4b84aae58 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-pen.c @@ -0,0 +1,480 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2008 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Chris Wilson + */ + +#include "cairoint.h" + +#include "cairo-error-private.h" +#include "cairo-slope-private.h" + +static void +_cairo_pen_compute_slopes (cairo_pen_t *pen); + +cairo_status_t +_cairo_pen_init (cairo_pen_t *pen, + double radius, + double tolerance, + const cairo_matrix_t *ctm) +{ + int i; + int reflect; + + if (CAIRO_INJECT_FAULT ()) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + VG (VALGRIND_MAKE_MEM_UNDEFINED (pen, sizeof (cairo_pen_t))); + + pen->radius = radius; + pen->tolerance = tolerance; + + reflect = _cairo_matrix_compute_determinant (ctm) < 0.; + + pen->num_vertices = _cairo_pen_vertices_needed (tolerance, + radius, + ctm); + + if (pen->num_vertices > ARRAY_LENGTH (pen->vertices_embedded)) { + pen->vertices = _cairo_malloc_ab (pen->num_vertices, + sizeof (cairo_pen_vertex_t)); + if (unlikely (pen->vertices == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } else { + pen->vertices = pen->vertices_embedded; + } + + /* + * Compute pen coordinates. To generate the right ellipse, compute points around + * a circle in user space and transform them to device space. To get a consistent + * orientation in device space, flip the pen if the transformation matrix + * is reflecting + */ + for (i=0; i < pen->num_vertices; i++) { + cairo_pen_vertex_t *v = &pen->vertices[i]; + double theta = 2 * M_PI * i / (double) pen->num_vertices, dx, dy; + if (reflect) + theta = -theta; + dx = radius * cos (theta); + dy = radius * sin (theta); + cairo_matrix_transform_distance (ctm, &dx, &dy); + v->point.x = _cairo_fixed_from_double (dx); + v->point.y = _cairo_fixed_from_double (dy); + } + + _cairo_pen_compute_slopes (pen); + + return CAIRO_STATUS_SUCCESS; +} + +void +_cairo_pen_fini (cairo_pen_t *pen) +{ + if (pen->vertices != pen->vertices_embedded) + free (pen->vertices); + + + VG (VALGRIND_MAKE_MEM_UNDEFINED (pen, sizeof (cairo_pen_t))); +} + +cairo_status_t +_cairo_pen_init_copy (cairo_pen_t *pen, const cairo_pen_t *other) +{ + VG (VALGRIND_MAKE_MEM_UNDEFINED (pen, sizeof (cairo_pen_t))); + + *pen = *other; + + if (CAIRO_INJECT_FAULT ()) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + pen->vertices = pen->vertices_embedded; + if (pen->num_vertices) { + if (pen->num_vertices > ARRAY_LENGTH (pen->vertices_embedded)) { + pen->vertices = _cairo_malloc_ab (pen->num_vertices, + sizeof (cairo_pen_vertex_t)); + if (unlikely (pen->vertices == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + memcpy (pen->vertices, other->vertices, + pen->num_vertices * sizeof (cairo_pen_vertex_t)); + } + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_pen_add_points (cairo_pen_t *pen, cairo_point_t *point, int num_points) +{ + cairo_status_t status; + int num_vertices; + int i; + + if (CAIRO_INJECT_FAULT ()) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + num_vertices = pen->num_vertices + num_points; + if (num_vertices > ARRAY_LENGTH (pen->vertices_embedded) || + pen->vertices != pen->vertices_embedded) + { + cairo_pen_vertex_t *vertices; + + if (pen->vertices == pen->vertices_embedded) { + vertices = _cairo_malloc_ab (num_vertices, + sizeof (cairo_pen_vertex_t)); + if (unlikely (vertices == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + memcpy (vertices, pen->vertices, + pen->num_vertices * sizeof (cairo_pen_vertex_t)); + } else { + vertices = _cairo_realloc_ab (pen->vertices, + num_vertices, + sizeof (cairo_pen_vertex_t)); + if (unlikely (vertices == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + pen->vertices = vertices; + } + + pen->num_vertices = num_vertices; + + /* initialize new vertices */ + for (i=0; i < num_points; i++) + pen->vertices[pen->num_vertices-num_points+i].point = point[i]; + + status = _cairo_hull_compute (pen->vertices, &pen->num_vertices); + if (unlikely (status)) + return status; + + _cairo_pen_compute_slopes (pen); + + return CAIRO_STATUS_SUCCESS; +} + +/* +The circular pen in user space is transformed into an ellipse in +device space. + +We construct the pen by computing points along the circumference +using equally spaced angles. + +We show that this approximation to the ellipse has maximum error at the +major axis of the ellipse. + +Set + + M = major axis length + m = minor axis length + +Align 'M' along the X axis and 'm' along the Y axis and draw +an ellipse parameterized by angle 't': + + x = M cos t y = m sin t + +Perturb t by ± d and compute two new points (x+,y+), (x-,y-). +The distance from the average of these two points to (x,y) represents +the maximum error in approximating the ellipse with a polygon formed +from vertices 2∆ radians apart. + + x+ = M cos (t+∆) y+ = m sin (t+∆) + x- = M cos (t-∆) y- = m sin (t-∆) + +Now compute the approximation error, E: + + Ex = (x - (x+ + x-) / 2) + Ex = (M cos(t) - (Mcos(t+∆) + Mcos(t-∆))/2) + = M (cos(t) - (cos(t)cos(∆) + sin(t)sin(∆) + + cos(t)cos(∆) - sin(t)sin(∆))/2) + = M(cos(t) - cos(t)cos(∆)) + = M cos(t) (1 - cos(∆)) + + Ey = y - (y+ - y-) / 2 + = m sin (t) - (m sin(t+∆) + m sin(t-∆)) / 2 + = m (sin(t) - (sin(t)cos(∆) + cos(t)sin(∆) + + sin(t)cos(∆) - cos(t)sin(∆))/2) + = m (sin(t) - sin(t)cos(∆)) + = m sin(t) (1 - cos(∆)) + + E² = Ex² + Ey² + = (M cos(t) (1 - cos (∆)))² + (m sin(t) (1-cos(∆)))² + = (1 - cos(∆))² (M² cos²(t) + m² sin²(t)) + = (1 - cos(∆))² ((m² + M² - m²) cos² (t) + m² sin²(t)) + = (1 - cos(∆))² (M² - m²) cos² (t) + (1 - cos(∆))² m² + +Find the extremum by differentiation wrt t and setting that to zero + +∂(E²)/∂(t) = (1-cos(∆))² (M² - m²) (-2 cos(t) sin(t)) + + 0 = 2 cos (t) sin (t) + 0 = sin (2t) + t = nÏ€ + +Which is to say that the maximum and minimum errors occur on the +axes of the ellipse at 0 and Ï€ radians: + + E²(0) = (1-cos(∆))² (M² - m²) + (1-cos(∆))² m² + = (1-cos(∆))² M² + E²(Ï€) = (1-cos(∆))² m² + +maximum error = M (1-cos(∆)) +minimum error = m (1-cos(∆)) + +We must make maximum error ≤ tolerance, so compute the ∆ needed: + + tolerance = M (1-cos(∆)) + tolerance / M = 1 - cos (∆) + cos(∆) = 1 - tolerance/M + ∆ = acos (1 - tolerance / M); + +Remembering that ∆ is half of our angle between vertices, +the number of vertices is then + + vertices = ceil(2Ï€/2∆). + = ceil(Ï€/∆). + +Note that this also equation works for M == m (a circle) as it +doesn't matter where on the circle the error is computed. +*/ + +int +_cairo_pen_vertices_needed (double tolerance, + double radius, + const cairo_matrix_t *matrix) +{ + /* + * the pen is a circle that gets transformed to an ellipse by matrix. + * compute major axis length for a pen with the specified radius. + * we don't need the minor axis length. + */ + double major_axis = _cairo_matrix_transformed_circle_major_axis (matrix, + radius); + int num_vertices; + + if (tolerance >= 4*major_axis) { /* XXX relaxed from 2*major for inkscape */ + num_vertices = 1; + } else if (tolerance >= major_axis) { + num_vertices = 4; + } else { + double divisor = acos (1 - tolerance / major_axis); + + if (divisor == 0.0) + return 4; + + num_vertices = ceil (2*M_PI / divisor); + + /* number of vertices must be even */ + if (num_vertices % 2) + num_vertices++; + + /* And we must always have at least 4 vertices. */ + if (num_vertices < 4) + num_vertices = 4; + } + + return num_vertices; +} + +static void +_cairo_pen_compute_slopes (cairo_pen_t *pen) +{ + int i, i_prev; + cairo_pen_vertex_t *prev, *v, *next; + + for (i=0, i_prev = pen->num_vertices - 1; + i < pen->num_vertices; + i_prev = i++) { + prev = &pen->vertices[i_prev]; + v = &pen->vertices[i]; + next = &pen->vertices[(i + 1) % pen->num_vertices]; + + _cairo_slope_init (&v->slope_cw, &prev->point, &v->point); + _cairo_slope_init (&v->slope_ccw, &v->point, &next->point); + } +} +/* + * Find active pen vertex for clockwise edge of stroke at the given slope. + * + * The strictness of the inequalities here is delicate. The issue is + * that the slope_ccw member of one pen vertex will be equivalent to + * the slope_cw member of the next pen vertex in a counterclockwise + * order. However, for this function, we care strongly about which + * vertex is returned. + * + * [I think the "care strongly" above has to do with ensuring that the + * pen's "extra points" from the spline's initial and final slopes are + * properly found when beginning the spline stroking.] + */ +int +_cairo_pen_find_active_cw_vertex_index (const cairo_pen_t *pen, + const cairo_slope_t *slope) +{ + int i; + + for (i=0; i < pen->num_vertices; i++) { + if ((_cairo_slope_compare (slope, &pen->vertices[i].slope_ccw) < 0) && + (_cairo_slope_compare (slope, &pen->vertices[i].slope_cw) >= 0)) + break; + } + + /* If the desired slope cannot be found between any of the pen + * vertices, then we must have a degenerate pen, (such as a pen + * that's been transformed to a line). In that case, we consider + * the first pen vertex as the appropriate clockwise vertex. + */ + if (i == pen->num_vertices) + i = 0; + + return i; +} + +/* Find active pen vertex for counterclockwise edge of stroke at the given slope. + * + * Note: See the comments for _cairo_pen_find_active_cw_vertex_index + * for some details about the strictness of the inequalities here. + */ +int +_cairo_pen_find_active_ccw_vertex_index (const cairo_pen_t *pen, + const cairo_slope_t *slope) +{ + cairo_slope_t slope_reverse; + int i; + + slope_reverse = *slope; + slope_reverse.dx = -slope_reverse.dx; + slope_reverse.dy = -slope_reverse.dy; + + for (i=pen->num_vertices-1; i >= 0; i--) { + if ((_cairo_slope_compare (&pen->vertices[i].slope_ccw, &slope_reverse) >= 0) && + (_cairo_slope_compare (&pen->vertices[i].slope_cw, &slope_reverse) < 0)) + break; + } + + /* If the desired slope cannot be found between any of the pen + * vertices, then we must have a degenerate pen, (such as a pen + * that's been transformed to a line). In that case, we consider + * the last pen vertex as the appropriate counterclockwise vertex. + */ + if (i < 0) + i = pen->num_vertices - 1; + + return i; +} + +void +_cairo_pen_find_active_cw_vertices (const cairo_pen_t *pen, + const cairo_slope_t *in, + const cairo_slope_t *out, + int *start, int *stop) +{ + + int lo = 0, hi = pen->num_vertices; + int i; + + i = (lo + hi) >> 1; + do { + if (_cairo_slope_compare (&pen->vertices[i].slope_cw, in) < 0) + lo = i; + else + hi = i; + i = (lo + hi) >> 1; + } while (hi - lo > 1); + if (_cairo_slope_compare (&pen->vertices[i].slope_cw, in) < 0) + if (++i == pen->num_vertices) + i = 0; + *start = i; + + if (_cairo_slope_compare (out, &pen->vertices[i].slope_ccw) >= 0) { + lo = i; + hi = i + pen->num_vertices; + i = (lo + hi) >> 1; + do { + int j = i; + if (j >= pen->num_vertices) + j -= pen->num_vertices; + if (_cairo_slope_compare (&pen->vertices[j].slope_cw, out) > 0) + hi = i; + else + lo = i; + i = (lo + hi) >> 1; + } while (hi - lo > 1); + if (i >= pen->num_vertices) + i -= pen->num_vertices; + } + *stop = i; +} + +void +_cairo_pen_find_active_ccw_vertices (const cairo_pen_t *pen, + const cairo_slope_t *in, + const cairo_slope_t *out, + int *start, int *stop) +{ + int lo = 0, hi = pen->num_vertices; + int i; + + i = (lo + hi) >> 1; + do { + if (_cairo_slope_compare (in, &pen->vertices[i].slope_ccw) < 0) + lo = i; + else + hi = i; + i = (lo + hi) >> 1; + } while (hi - lo > 1); + if (_cairo_slope_compare (in, &pen->vertices[i].slope_ccw) < 0) + if (++i == pen->num_vertices) + i = 0; + *start = i; + + if (_cairo_slope_compare (&pen->vertices[i].slope_cw, out) <= 0) { + lo = i; + hi = i + pen->num_vertices; + i = (lo + hi) >> 1; + do { + int j = i; + if (j >= pen->num_vertices) + j -= pen->num_vertices; + if (_cairo_slope_compare (out, &pen->vertices[j].slope_ccw) > 0) + hi = i; + else + lo = i; + i = (lo + hi) >> 1; + } while (hi - lo > 1); + if (i >= pen->num_vertices) + i -= pen->num_vertices; + } + *stop = i; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-pixman-private.h b/local/recipes/libs/cairo/source/src/cairo-pixman-private.h new file mode 100644 index 0000000000..d187b79f66 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-pixman-private.h @@ -0,0 +1,45 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright ©2013 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Chris Wilson + */ + +#ifndef CAIRO_PIXMAN_PRIVATE_H +#define CAIRO_PIXMAN_PRIVATE_H + +#include "cairo-pixman-private.h" /* keep make check happy */ + +#include + +#endif diff --git a/local/recipes/libs/cairo/source/src/cairo-png.c b/local/recipes/libs/cairo/source/src/cairo-png.c new file mode 100644 index 0000000000..287f705459 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-png.c @@ -0,0 +1,983 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2003 University of Southern California + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Kristian Høgsberg + * Chris Wilson + */ + +#include "cairoint.h" + +#include "cairo-error-private.h" +#include "cairo-image-surface-private.h" +#include "cairo-output-stream-private.h" + +#include +#include +#include + +/** + * SECTION:cairo-png + * @Title: PNG Support + * @Short_Description: Reading and writing PNG images + * @See_Also: #cairo_surface_t + * + * The PNG functions allow reading PNG images into image surfaces, and writing + * any surface to a PNG file. + * + * It is a toy API. It only offers very simple support for reading and + * writing PNG files, which is sufficient for testing and + * demonstration purposes. Applications which need more control over + * the generated PNG file should access the pixel data directly, using + * cairo_image_surface_get_data() or a backend-specific access + * function, and process it with another library, e.g. gdk-pixbuf or + * libpng. + **/ + +/** + * CAIRO_HAS_PNG_FUNCTIONS: + * + * Defined if the PNG functions are available. + * This macro can be used to conditionally compile code using the cairo + * PNG functions. + * + * Since: 1.0 + **/ + +struct png_read_closure_t { + cairo_read_func_t read_func; + void *closure; + cairo_output_stream_t *png_data; +}; + + +/* Unpremultiplies data and converts native endian ARGB => RGBA bytes */ +static void +unpremultiply_data (png_structp png, png_row_infop row_info, png_bytep data) +{ + unsigned int i; + + for (i = 0; i < row_info->rowbytes; i += 4) { + uint8_t *b = &data[i]; + uint32_t pixel; + uint8_t alpha; + + memcpy (&pixel, b, sizeof (uint32_t)); + alpha = (pixel & 0xff000000) >> 24; + if (alpha == 0) { + b[0] = b[1] = b[2] = b[3] = 0; + } else { + b[0] = (((pixel & 0xff0000) >> 16) * 255 + alpha / 2) / alpha; + b[1] = (((pixel & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha; + b[2] = (((pixel & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha; + b[3] = alpha; + } + } +} + +static uint16_t f_to_u16(float val) +{ + if (val < 0) + return 0; + else if (val > 1) + return 65535; + else + return (uint16_t)(val * 65535.f); +} + +static void +unpremultiply_float (float *f, uint16_t *d16, unsigned width) +{ + unsigned int i; + + for (i = 0; i < width; i++) { + float r, g, b, a; + + r = *f++; + g = *f++; + b = *f++; + a = *f++; + + if (a > 0) { + *d16++ = f_to_u16(r / a); + *d16++ = f_to_u16(g / a); + *d16++ = f_to_u16(b / a); + *d16++ = f_to_u16(a); + } else { + *d16++ = 0; + *d16++ = 0; + *d16++ = 0; + *d16++ = 0; + } + } +} + +static void +premultiply_float (float *f, const uint16_t *d16, unsigned int width) +{ + unsigned int i = width; + + /* Convert d16 in place back to float */ + while (i--) { + float a = d16[i * 4 + 3] / 65535.f; + + f[i * 4 + 3] = a; + f[i * 4 + 2] = (float)d16[i * 4 + 2] / 65535.f * a; + f[i * 4 + 1] = (float)d16[i * 4 + 1] / 65535.f * a; + f[i * 4] = (float)d16[i * 4] / 65535.f * a; + } +} + +static void convert_u16_to_float (float *f, const uint16_t *d16, unsigned int width) +{ + /* Convert d16 in place back to float */ + unsigned int i = width; + + while (i--) { + f[i * 3 + 2] = (float)d16[i * 4 + 2] / 65535.f; + f[i * 3 + 1] = (float)d16[i * 4 + 1] / 65535.f; + f[i * 3] = (float)d16[i * 4] / 65535.f; + } +} + +static void +convert_float_to_u16 (float *f, uint16_t *d16, unsigned int width) +{ + unsigned int i; + + for (i = 0; i < width; i++) { + *d16++ = f_to_u16(*f++); + *d16++ = f_to_u16(*f++); + *d16++ = f_to_u16(*f++); + *d16++ = 0; + } +} + +/* Converts native endian xRGB => RGBx bytes */ +static void +convert_data_to_bytes (png_structp png, png_row_infop row_info, png_bytep data) +{ + unsigned int i; + + for (i = 0; i < row_info->rowbytes; i += 4) { + uint8_t *b = &data[i]; + uint32_t pixel; + + memcpy (&pixel, b, sizeof (uint32_t)); + + b[0] = (pixel & 0xff0000) >> 16; + b[1] = (pixel & 0x00ff00) >> 8; + b[2] = (pixel & 0x0000ff) >> 0; + b[3] = 0; + } +} + +/* Use a couple of simple error callbacks that do not print anything to + * stderr and rely on the user to check for errors via the #cairo_status_t + * return. + */ +static void +png_simple_error_callback (png_structp png, + png_const_charp error_msg) +{ + cairo_status_t *error = png_get_error_ptr (png); + + /* default to the most likely error */ + if (*error == CAIRO_STATUS_SUCCESS) + *error = _cairo_error (CAIRO_STATUS_PNG_ERROR); + +#ifdef PNG_SETJMP_SUPPORTED + longjmp (png_jmpbuf (png), 1); +#endif + + /* if we get here, then we have to choice but to abort ... */ +} + +static void +png_simple_warning_callback (png_structp png, + png_const_charp error_msg) +{ + /* png does not expect to abort and will try to tidy up and continue + * loading the image after a warning. So we also want to return the + * (incorrect?) surface. + * + * We use our own warning callback to squelch any attempts by libpng + * to write to stderr as we may not be in control of that output. + */ +} + + +/* Starting with libpng-1.2.30, we must explicitly specify an output_flush_fn. + * Otherwise, we will segfault if we are writing to a stream. */ +static void +png_simple_output_flush_fn (png_structp png_ptr) +{ +} + +static cairo_status_t +write_png (cairo_surface_t *surface, + png_rw_ptr write_func, + void *closure) +{ + int i; + cairo_int_status_t status; + cairo_image_surface_t *image; + cairo_image_surface_t * volatile clone; + void *image_extra; + png_struct *png; + png_info *info; + png_byte **volatile rows = NULL; + png_color_16 white; + int png_color_type; + int bpc; + unsigned char *volatile u16_copy = NULL; + + status = _cairo_surface_acquire_source_image (surface, + &image, + &image_extra); + + if (status == CAIRO_INT_STATUS_UNSUPPORTED) + return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + else if (unlikely (status)) + return status; + + /* PNG complains about "Image width or height is zero in IHDR" */ + if (image->width == 0 || image->height == 0) { + status = _cairo_error (CAIRO_STATUS_WRITE_ERROR); + goto BAIL1; + } + + /* Don't coerce to a lower resolution format */ + if (image->format == CAIRO_FORMAT_RGB96F || + image->format == CAIRO_FORMAT_RGBA128F) { + u16_copy = _cairo_malloc_ab (image->width * 8, image->height); + if (!u16_copy) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto BAIL1; + } + clone = (cairo_image_surface_t *)cairo_surface_reference (&image->base); + } else { + /* Handle the various fallback formats (e.g. low bit-depth XServers) + * by coercing them to a simpler format using pixman. + */ + clone = _cairo_image_surface_coerce (image); + status = clone->base.status; + } + if (unlikely (status)) + goto BAIL1; + + rows = _cairo_malloc_ab (clone->height, sizeof (png_byte*)); + if (unlikely (rows == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto BAIL2; + } + + if (!u16_copy) { + for (i = 0; i < clone->height; i++) + rows[i] = (png_byte *)clone->data + i * clone->stride; + } else { + for (i = 0; i < clone->height; i++) { + float *float_line = (float *)&clone->data[i * clone->stride]; + uint16_t *u16_line = (uint16_t *)&u16_copy[i * clone->width * 8]; + + if (image->format == CAIRO_FORMAT_RGBA128F) + unpremultiply_float (float_line, u16_line, clone->width); + else + convert_float_to_u16 (float_line, u16_line, clone->width); + + rows[i] = (png_byte *)u16_line; + } + } + + png = png_create_write_struct (PNG_LIBPNG_VER_STRING, &status, + png_simple_error_callback, + png_simple_warning_callback); + if (unlikely (png == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto BAIL3; + } + + info = png_create_info_struct (png); + if (unlikely (info == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto BAIL4; + } + +#ifdef PNG_SETJMP_SUPPORTED + if (setjmp (png_jmpbuf (png))) + goto BAIL4; +#endif + + png_set_write_fn (png, closure, write_func, png_simple_output_flush_fn); + + switch (clone->format) { + case CAIRO_FORMAT_ARGB32: + bpc = 8; + if (_cairo_image_analyze_transparency (clone) == CAIRO_IMAGE_IS_OPAQUE) + png_color_type = PNG_COLOR_TYPE_RGB; + else + png_color_type = PNG_COLOR_TYPE_RGB_ALPHA; + break; + case CAIRO_FORMAT_RGB30: + bpc = 10; + png_color_type = PNG_COLOR_TYPE_RGB; + break; + case CAIRO_FORMAT_RGB24: + bpc = 8; + png_color_type = PNG_COLOR_TYPE_RGB; + break; + case CAIRO_FORMAT_A8: + bpc = 8; + png_color_type = PNG_COLOR_TYPE_GRAY; + break; + case CAIRO_FORMAT_A1: + bpc = 1; + png_color_type = PNG_COLOR_TYPE_GRAY; +#ifndef WORDS_BIGENDIAN + png_set_packswap (png); +#endif + break; + case CAIRO_FORMAT_RGB96F: + bpc = 16; + png_color_type = PNG_COLOR_TYPE_RGB; + break; + case CAIRO_FORMAT_RGBA128F: + bpc = 16; + png_color_type = PNG_COLOR_TYPE_RGB_ALPHA; + break; + case CAIRO_FORMAT_INVALID: + case CAIRO_FORMAT_RGB16_565: + default: + status = _cairo_error (CAIRO_STATUS_INVALID_FORMAT); + goto BAIL4; + } + + png_set_IHDR (png, info, + clone->width, + clone->height, bpc, + png_color_type, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + + white.gray = (1 << bpc) - 1; + white.red = white.blue = white.green = white.gray; + png_set_bKGD (png, info, &white); + + if (0) { /* XXX extract meta-data from surface (i.e. creation date) */ + png_time pt; + + png_convert_from_time_t (&pt, time (NULL)); + png_set_tIME (png, info, &pt); + } + + /* We have to call png_write_info() before setting up the write + * transformation, since it stores data internally in 'png' + * that is needed for the write transformation functions to work. + */ + png_write_info (png, info); + +#ifndef WORDS_BIGENDIAN + /* libpng treats 16-bit data as big-endian by default. Swapping the + * byte-order on little endian ensures the native-endian data can be + * provided to png_write_image. This does not affect 8-bit data. + */ + png_set_swap (png); +#endif + + if (png_color_type == PNG_COLOR_TYPE_RGB_ALPHA) { + if (clone->format != CAIRO_FORMAT_RGBA128F) + png_set_write_user_transform_fn (png, unpremultiply_data); + } else if (png_color_type == PNG_COLOR_TYPE_RGB) { + if (clone->format != CAIRO_FORMAT_RGB96F) + png_set_write_user_transform_fn (png, convert_data_to_bytes); + png_set_filler (png, 0, PNG_FILLER_AFTER); + } + + png_write_image (png, rows); + png_write_end (png, info); + +BAIL4: + png_destroy_write_struct (&png, &info); +BAIL3: + free (rows); +BAIL2: + cairo_surface_destroy (&clone->base); + free (u16_copy); +BAIL1: + _cairo_surface_release_source_image (surface, image, image_extra); + + return status; +} + +static void +stdio_write_func (png_structp png, png_bytep data, png_size_t size) +{ + FILE *fp; + + fp = png_get_io_ptr (png); + while (size) { + size_t ret = fwrite (data, 1, size, fp); + size -= ret; + data += ret; + if (size && ferror (fp)) { + cairo_status_t *error = png_get_error_ptr (png); + if (*error == CAIRO_STATUS_SUCCESS) + *error = _cairo_error (CAIRO_STATUS_WRITE_ERROR); + png_error (png, NULL); + } + } +} + +/** + * cairo_surface_write_to_png: + * @surface: a #cairo_surface_t with pixel contents + * @filename: the name of a file to write to; on Windows this filename + * is encoded in UTF-8. + * + * Writes the contents of @surface to a new file @filename as a PNG + * image. + * + * Return value: %CAIRO_STATUS_SUCCESS if the PNG file was written + * successfully. Otherwise, %CAIRO_STATUS_NO_MEMORY if memory could not + * be allocated for the operation or + * %CAIRO_STATUS_SURFACE_TYPE_MISMATCH if the surface does not have + * pixel contents, or %CAIRO_STATUS_WRITE_ERROR if an I/O error occurs + * while attempting to write the file, or %CAIRO_STATUS_PNG_ERROR if libpng + * returned an error. + * + * Since: 1.0 + **/ +cairo_status_t +cairo_surface_write_to_png (cairo_surface_t *surface, + const char *filename) +{ + FILE *fp; + cairo_status_t status; + + if (surface->status) + return surface->status; + + if (surface->finished) + return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED); + + status = _cairo_fopen (filename, "wb", &fp); + + if (status != CAIRO_STATUS_SUCCESS) + return _cairo_error (status); + + if (fp == NULL) { + switch (errno) { + case ENOMEM: + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + default: + return _cairo_error (CAIRO_STATUS_WRITE_ERROR); + } + } + + status = write_png (surface, stdio_write_func, fp); + + if (fclose (fp) && status == CAIRO_STATUS_SUCCESS) + status = _cairo_error (CAIRO_STATUS_WRITE_ERROR); + + return status; +} + +struct png_write_closure_t { + cairo_write_func_t write_func; + void *closure; +}; + +static void +stream_write_func (png_structp png, png_bytep data, png_size_t size) +{ + cairo_status_t status; + struct png_write_closure_t *png_closure; + + png_closure = png_get_io_ptr (png); + status = png_closure->write_func (png_closure->closure, data, size); + if (unlikely (status)) { + cairo_status_t *error = png_get_error_ptr (png); + if (*error == CAIRO_STATUS_SUCCESS) + *error = status; + png_error (png, NULL); + } +} + +/** + * cairo_surface_write_to_png_stream: + * @surface: a #cairo_surface_t with pixel contents + * @write_func: a #cairo_write_func_t + * @closure: closure data for the write function + * + * Writes the image surface to the write function. + * + * Return value: %CAIRO_STATUS_SUCCESS if the PNG file was written + * successfully. Otherwise, %CAIRO_STATUS_NO_MEMORY is returned if + * memory could not be allocated for the operation, + * %CAIRO_STATUS_SURFACE_TYPE_MISMATCH if the surface does not have + * pixel contents, or %CAIRO_STATUS_PNG_ERROR if libpng + * returned an error. + * + * Since: 1.0 + **/ +cairo_status_t +cairo_surface_write_to_png_stream (cairo_surface_t *surface, + cairo_write_func_t write_func, + void *closure) +{ + struct png_write_closure_t png_closure; + + if (surface->status) + return surface->status; + + if (surface->finished) + return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED); + + png_closure.write_func = write_func; + png_closure.closure = closure; + + return write_png (surface, stream_write_func, &png_closure); +} + +static inline int +multiply_alpha (int alpha, int color) +{ + int temp = (alpha * color) + 0x80; + return ((temp + (temp >> 8)) >> 8); +} + +/* Premultiplies data and converts RGBA bytes => native endian */ +static void +premultiply_data (png_structp png, + png_row_infop row_info, + png_bytep data) +{ + unsigned int i; + + for (i = 0; i < row_info->rowbytes; i += 4) { + uint8_t *base = &data[i]; + uint8_t alpha = base[3]; + uint32_t p; + + if (alpha == 0) { + p = 0; + } else { + uint8_t red = base[0]; + uint8_t green = base[1]; + uint8_t blue = base[2]; + + if (alpha != 0xff) { + red = multiply_alpha (alpha, red); + green = multiply_alpha (alpha, green); + blue = multiply_alpha (alpha, blue); + } + p = ((uint32_t)alpha << 24) | (red << 16) | (green << 8) | (blue << 0); + } + memcpy (base, &p, sizeof (uint32_t)); + } +} + +/* Converts RGBx bytes to native endian xRGB */ +static void +convert_bytes_to_data (png_structp png, png_row_infop row_info, png_bytep data) +{ + unsigned int i; + + for (i = 0; i < row_info->rowbytes; i += 4) { + uint8_t *base = &data[i]; + uint8_t red = base[0]; + uint8_t green = base[1]; + uint8_t blue = base[2]; + uint32_t pixel; + + pixel = (0xffu << 24) | (red << 16) | (green << 8) | (blue << 0); + memcpy (base, &pixel, sizeof (uint32_t)); + } +} + +static cairo_status_t +stdio_read_func (void *closure, unsigned char *data, unsigned int size) +{ + FILE *file = closure; + + while (size) { + size_t ret; + + ret = fread (data, 1, size, file); + size -= ret; + data += ret; + + if (size && (feof (file) || ferror (file))) + return _cairo_error (CAIRO_STATUS_READ_ERROR); + } + + return CAIRO_STATUS_SUCCESS; +} + +static void +stream_read_func (png_structp png, png_bytep data, png_size_t size) +{ + cairo_status_t status; + struct png_read_closure_t *png_closure; + + png_closure = png_get_io_ptr (png); + status = png_closure->read_func (png_closure->closure, data, size); + if (unlikely (status)) { + cairo_status_t *error = png_get_error_ptr (png); + if (*error == CAIRO_STATUS_SUCCESS) + *error = status; + png_error (png, NULL); + } + + _cairo_output_stream_write (png_closure->png_data, data, size); +} + +static cairo_surface_t * +read_png (struct png_read_closure_t *png_closure) +{ + cairo_surface_t * volatile surface; + png_struct *png = NULL; + png_info *info; + png_byte * volatile data = NULL; + png_byte ** volatile row_pointers = NULL; + png_uint_32 png_width, png_height; + int depth, color_type, interlace, stride; + unsigned int i; + cairo_format_t format; + cairo_status_t status; + unsigned char *mime_data; + unsigned long mime_data_length; + + png_closure->png_data = _cairo_memory_stream_create (); + + /* XXX: Perhaps we'll want some other error handlers? */ + png = png_create_read_struct (PNG_LIBPNG_VER_STRING, + &status, + png_simple_error_callback, + png_simple_warning_callback); + if (unlikely (png == NULL)) { + surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + goto BAIL; + } + + info = png_create_info_struct (png); + if (unlikely (info == NULL)) { + surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + goto BAIL; + } + + png_set_read_fn (png, png_closure, stream_read_func); + + status = CAIRO_STATUS_SUCCESS; +#ifdef PNG_SETJMP_SUPPORTED + if (setjmp (png_jmpbuf (png))) { + surface = _cairo_surface_create_in_error (status); + goto BAIL; + } +#endif + + png_read_info (png, info); + +#ifndef WORDS_BIGENDIAN + /* libpng treats 16-bit data as big-endian by default. Swapping the + * byte-order on little endian ensures the native-endian data can be + * provided to png_read_image. This does not affect 8-bit data. + */ + png_set_swap (png); +#endif + + png_get_IHDR (png, info, + &png_width, &png_height, &depth, + &color_type, &interlace, NULL, NULL); + if (unlikely (status)) { /* catch any early warnings */ + surface = _cairo_surface_create_in_error (status); + goto BAIL; + } + + /* convert palette/gray image to rgb */ + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_palette_to_rgb (png); + + /* expand gray bit depth if needed */ + if (color_type == PNG_COLOR_TYPE_GRAY) + png_set_expand_gray_1_2_4_to_8 (png); + + /* transform transparency to alpha */ + if (png_get_valid (png, info, PNG_INFO_tRNS)) + png_set_tRNS_to_alpha (png); + + if (depth < 8) + png_set_packing (png); + + /* convert grayscale to RGB */ + if (color_type == PNG_COLOR_TYPE_GRAY || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + png_set_gray_to_rgb (png); + } + + if (interlace != PNG_INTERLACE_NONE) + png_set_interlace_handling (png); + + png_set_filler (png, 0xff, PNG_FILLER_AFTER); + + /* recheck header after setting EXPAND options */ + png_read_update_info (png, info); + png_get_IHDR (png, info, + &png_width, &png_height, &depth, + &color_type, &interlace, NULL, NULL); + if ((depth != 8 && depth != 16) || + ! (color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA)) + { + surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_READ_ERROR)); + goto BAIL; + } + + switch (color_type) { + default: + ASSERT_NOT_REACHED; + /* fall-through just in case ;-) */ + + case PNG_COLOR_TYPE_RGB_ALPHA: + if (depth == 8) { + format = CAIRO_FORMAT_ARGB32; + png_set_read_user_transform_fn (png, premultiply_data); + } else { + format = CAIRO_FORMAT_RGBA128F; + } + break; + + case PNG_COLOR_TYPE_RGB: + if (depth == 8) { + format = CAIRO_FORMAT_RGB24; + png_set_read_user_transform_fn (png, convert_bytes_to_data); + } else { + format = CAIRO_FORMAT_RGB96F; + } + break; + } + + stride = cairo_format_stride_for_width (format, png_width); + if (stride < 0) { + surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_STRIDE)); + goto BAIL; + } + + data = _cairo_malloc_ab (png_height, stride); + if (unlikely (data == NULL)) { + surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + goto BAIL; + } + + row_pointers = _cairo_malloc_ab (png_height, sizeof (char *)); + if (unlikely (row_pointers == NULL)) { + surface = _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + goto BAIL; + } + + for (i = 0; i < png_height; i++) + row_pointers[i] = &data[i * (ptrdiff_t)stride]; + + png_read_image (png, row_pointers); + png_read_end (png, info); + + if (unlikely (status)) { /* catch any late warnings - probably hit an error already */ + surface = _cairo_surface_create_in_error (status); + goto BAIL; + } + + if (format == CAIRO_FORMAT_RGBA128F) { + i = png_height; + + while (i--) { + float *float_line = (float *)row_pointers[i]; + uint16_t *u16_line = (uint16_t *)row_pointers[i]; + + premultiply_float (float_line, u16_line, png_width); + } + } else if (format == CAIRO_FORMAT_RGB96F) { + i = png_height; + + while (i--) { + float *float_line = (float *)row_pointers[i]; + uint16_t *u16_line = (uint16_t *)row_pointers[i]; + + convert_u16_to_float (float_line, u16_line, png_width); + } + } + + surface = cairo_image_surface_create_for_data (data, format, + png_width, png_height, + stride); + if (surface->status) + goto BAIL; + + _cairo_image_surface_assume_ownership_of_data ((cairo_image_surface_t*)surface); + data = NULL; + + _cairo_debug_check_image_surface_is_defined (surface); + + status = _cairo_memory_stream_destroy (png_closure->png_data, + &mime_data, + &mime_data_length); + png_closure->png_data = NULL; + if (unlikely (status)) { + cairo_surface_destroy (surface); + surface = _cairo_surface_create_in_error (status); + goto BAIL; + } + + status = cairo_surface_set_mime_data (surface, + CAIRO_MIME_TYPE_PNG, + mime_data, + mime_data_length, + free, + mime_data); + if (unlikely (status)) { + free (mime_data); + cairo_surface_destroy (surface); + surface = _cairo_surface_create_in_error (status); + goto BAIL; + } + + BAIL: + free (row_pointers); + free (data); + if (png != NULL) + png_destroy_read_struct (&png, &info, NULL); + if (png_closure->png_data != NULL) { + cairo_status_t status_ignored; + + status_ignored = _cairo_output_stream_destroy (png_closure->png_data); + } + + return surface; +} + +/** + * cairo_image_surface_create_from_png: + * @filename: name of PNG file to load. On Windows this filename + * is encoded in UTF-8. + * + * Creates a new image surface and initializes the contents to the + * given PNG file. + * + * Return value: a new #cairo_surface_t initialized with the contents + * of the PNG file, or a "nil" surface if any error occurred. A nil + * surface can be checked for with cairo_surface_status(surface) which + * may return one of the following values: + * + * %CAIRO_STATUS_NO_MEMORY + * %CAIRO_STATUS_FILE_NOT_FOUND + * %CAIRO_STATUS_READ_ERROR + * %CAIRO_STATUS_PNG_ERROR + * + * Alternatively, you can allow errors to propagate through the drawing + * operations and check the status on the context upon completion + * using cairo_status(). + * + * Since: 1.0 + **/ +cairo_surface_t * +cairo_image_surface_create_from_png (const char *filename) +{ + struct png_read_closure_t png_closure; + cairo_surface_t *surface; + cairo_status_t status; + + status = _cairo_fopen (filename, "rb", (FILE **) &png_closure.closure); + + if (status != CAIRO_STATUS_SUCCESS) + return _cairo_surface_create_in_error (status); + + if (png_closure.closure == NULL) { + switch (errno) { + case ENOMEM: + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + break; + case ENOENT: + status = _cairo_error (CAIRO_STATUS_FILE_NOT_FOUND); + break; + default: + status = _cairo_error (CAIRO_STATUS_READ_ERROR); + break; + } + return _cairo_surface_create_in_error (status); + } + + png_closure.read_func = stdio_read_func; + + surface = read_png (&png_closure); + + fclose (png_closure.closure); + + return surface; +} + +/** + * cairo_image_surface_create_from_png_stream: + * @read_func: function called to read the data of the file + * @closure: data to pass to @read_func. + * + * Creates a new image surface from PNG data read incrementally + * via the @read_func function. + * + * Return value: a new #cairo_surface_t initialized with the contents + * of the PNG file or a "nil" surface if the data read is not a valid PNG image + * or memory could not be allocated for the operation. A nil + * surface can be checked for with cairo_surface_status(surface) which + * may return one of the following values: + * + * %CAIRO_STATUS_NO_MEMORY + * %CAIRO_STATUS_READ_ERROR + * %CAIRO_STATUS_PNG_ERROR + * + * Alternatively, you can allow errors to propagate through the drawing + * operations and check the status on the context upon completion + * using cairo_status(). + * + * Since: 1.0 + **/ +cairo_surface_t * +cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func, + void *closure) +{ + struct png_read_closure_t png_closure; + + png_closure.read_func = read_func; + png_closure.closure = closure; + + return read_png (&png_closure); +} diff --git a/local/recipes/libs/cairo/source/src/cairo-polygon-intersect.c b/local/recipes/libs/cairo/source/src/cairo-polygon-intersect.c new file mode 100644 index 0000000000..001e55ee06 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-polygon-intersect.c @@ -0,0 +1,1472 @@ +/* + * Copyright © 2004 Carl Worth + * Copyright © 2006 Red Hat, Inc. + * Copyright © 2008 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Carl Worth + * + * Contributor(s): + * Carl D. Worth + * Chris Wilson + */ + +/* Provide definitions for standalone compilation */ +#include "cairoint.h" + +#include "cairo-error-private.h" +#include "cairo-freelist-private.h" +#include "cairo-combsort-inline.h" + + +typedef struct _cairo_bo_intersect_ordinate { + int32_t ordinate; + enum { EXCESS = -1, EXACT = 0, DEFAULT = 1 } approx; +} cairo_bo_intersect_ordinate_t; + +typedef struct _cairo_bo_intersect_point { + cairo_bo_intersect_ordinate_t x; + cairo_bo_intersect_ordinate_t y; +} cairo_bo_intersect_point_t; + +typedef struct _cairo_bo_edge cairo_bo_edge_t; + +typedef struct _cairo_bo_deferred { + cairo_bo_edge_t *other; + int32_t top; +} cairo_bo_deferred_t; + +struct _cairo_bo_edge { + int a_or_b; + cairo_edge_t edge; + cairo_bo_edge_t *prev; + cairo_bo_edge_t *next; + cairo_bo_deferred_t deferred; +}; + +/* the parent is always given by index/2 */ +#define PQ_PARENT_INDEX(i) ((i) >> 1) +#define PQ_FIRST_ENTRY 1 + +/* left and right children are index * 2 and (index * 2) +1 respectively */ +#define PQ_LEFT_CHILD_INDEX(i) ((i) << 1) + +typedef enum { + CAIRO_BO_EVENT_TYPE_STOP = -1, + CAIRO_BO_EVENT_TYPE_INTERSECTION, + CAIRO_BO_EVENT_TYPE_START +} cairo_bo_event_type_t; + +typedef struct _cairo_bo_event { + cairo_bo_event_type_t type; + cairo_bo_intersect_point_t point; +} cairo_bo_event_t; + +typedef struct _cairo_bo_start_event { + cairo_bo_event_type_t type; + cairo_bo_intersect_point_t point; + cairo_bo_edge_t edge; +} cairo_bo_start_event_t; + +typedef struct _cairo_bo_queue_event { + cairo_bo_event_type_t type; + cairo_bo_intersect_point_t point; + cairo_bo_edge_t *e1; + cairo_bo_edge_t *e2; +} cairo_bo_queue_event_t; + +typedef struct _pqueue { + int size, max_size; + + cairo_bo_event_t **elements; + cairo_bo_event_t *elements_embedded[1024]; +} pqueue_t; + +typedef struct _cairo_bo_event_queue { + cairo_freepool_t pool; + pqueue_t pqueue; + cairo_bo_event_t **start_events; +} cairo_bo_event_queue_t; + +typedef struct _cairo_bo_sweep_line { + cairo_bo_edge_t *head; + int32_t current_y; + cairo_bo_edge_t *current_edge; +} cairo_bo_sweep_line_t; + +static cairo_fixed_t +_line_compute_intersection_x_for_y (const cairo_line_t *line, + cairo_fixed_t y) +{ + cairo_fixed_t x, dy; + + if (y == line->p1.y) + return line->p1.x; + if (y == line->p2.y) + return line->p2.x; + + x = line->p1.x; + dy = line->p2.y - line->p1.y; + if (dy != 0) { + x += _cairo_fixed_mul_div_floor (y - line->p1.y, + line->p2.x - line->p1.x, + dy); + } + + return x; +} + +static inline int +_cairo_bo_point32_compare (cairo_bo_intersect_point_t const *a, + cairo_bo_intersect_point_t const *b) +{ + int cmp; + + cmp = a->y.ordinate - b->y.ordinate; + if (cmp) + return cmp; + + cmp = a->y.approx - b->y.approx; + if (cmp) + return cmp; + + return a->x.ordinate - b->x.ordinate; +} + +/* Compare the slope of a to the slope of b, returning 1, 0, -1 if the + * slope a is respectively greater than, equal to, or less than the + * slope of b. + * + * For each edge, consider the direction vector formed from: + * + * top -> bottom + * + * which is: + * + * (dx, dy) = (line.p2.x - line.p1.x, line.p2.y - line.p1.y) + * + * We then define the slope of each edge as dx/dy, (which is the + * inverse of the slope typically used in math instruction). We never + * compute a slope directly as the value approaches infinity, but we + * can derive a slope comparison without division as follows, (where + * the ? represents our compare operator). + * + * 1. slope(a) ? slope(b) + * 2. adx/ady ? bdx/bdy + * 3. (adx * bdy) ? (bdx * ady) + * + * Note that from step 2 to step 3 there is no change needed in the + * sign of the result since both ady and bdy are guaranteed to be + * greater than or equal to 0. + * + * When using this slope comparison to sort edges, some care is needed + * when interpreting the results. Since the slope compare operates on + * distance vectors from top to bottom it gives a correct left to + * right sort for edges that have a common top point, (such as two + * edges with start events at the same location). On the other hand, + * the sense of the result will be exactly reversed for two edges that + * have a common stop point. + */ +static inline int +_slope_compare (const cairo_bo_edge_t *a, + const cairo_bo_edge_t *b) +{ + /* XXX: We're assuming here that dx and dy will still fit in 32 + * bits. That's not true in general as there could be overflow. We + * should prevent that before the tessellation algorithm + * begins. + */ + int32_t adx = a->edge.line.p2.x - a->edge.line.p1.x; + int32_t bdx = b->edge.line.p2.x - b->edge.line.p1.x; + + /* Since the dy's are all positive by construction we can fast + * path several common cases. + */ + + /* First check for vertical lines. */ + if (adx == 0) + return -bdx; + if (bdx == 0) + return adx; + + /* Then where the two edges point in different directions wrt x. */ + if ((adx ^ bdx) < 0) + return adx; + + /* Finally we actually need to do the general comparison. */ + { + int32_t ady = a->edge.line.p2.y - a->edge.line.p1.y; + int32_t bdy = b->edge.line.p2.y - b->edge.line.p1.y; + cairo_int64_t adx_bdy = _cairo_int32x32_64_mul (adx, bdy); + cairo_int64_t bdx_ady = _cairo_int32x32_64_mul (bdx, ady); + + return _cairo_int64_cmp (adx_bdy, bdx_ady); + } +} + +/* + * We need to compare the x-coordinates of a pair of lines for a particular y, + * without loss of precision. + * + * The x-coordinate along an edge for a given y is: + * X = A_x + (Y - A_y) * A_dx / A_dy + * + * So the inequality we wish to test is: + * A_x + (Y - A_y) * A_dx / A_dy ∘ B_x + (Y - B_y) * B_dx / B_dy, + * where ∘ is our inequality operator. + * + * By construction, we know that A_dy and B_dy (and (Y - A_y), (Y - B_y)) are + * all positive, so we can rearrange it thus without causing a sign change: + * A_dy * B_dy * (A_x - B_x) ∘ (Y - B_y) * B_dx * A_dy + * - (Y - A_y) * A_dx * B_dy + * + * Given the assumption that all the deltas fit within 32 bits, we can compute + * this comparison directly using 128 bit arithmetic. For certain, but common, + * input we can reduce this down to a single 32 bit compare by inspecting the + * deltas. + * + * (And put the burden of the work on developing fast 128 bit ops, which are + * required throughout the tessellator.) + * + * See the similar discussion for _slope_compare(). + */ +static int +edges_compare_x_for_y_general (const cairo_bo_edge_t *a, + const cairo_bo_edge_t *b, + int32_t y) +{ + /* XXX: We're assuming here that dx and dy will still fit in 32 + * bits. That's not true in general as there could be overflow. We + * should prevent that before the tessellation algorithm + * begins. + */ + int32_t dx; + int32_t adx, ady; + int32_t bdx, bdy; + enum { + HAVE_NONE = 0x0, + HAVE_DX = 0x1, + HAVE_ADX = 0x2, + HAVE_DX_ADX = HAVE_DX | HAVE_ADX, + HAVE_BDX = 0x4, + HAVE_DX_BDX = HAVE_DX | HAVE_BDX, + HAVE_ADX_BDX = HAVE_ADX | HAVE_BDX, + HAVE_ALL = HAVE_DX | HAVE_ADX | HAVE_BDX + } have_dx_adx_bdx = HAVE_ALL; + + /* don't bother solving for abscissa if the edges' bounding boxes + * can be used to order them. */ + { + int32_t amin, amax; + int32_t bmin, bmax; + if (a->edge.line.p1.x < a->edge.line.p2.x) { + amin = a->edge.line.p1.x; + amax = a->edge.line.p2.x; + } else { + amin = a->edge.line.p2.x; + amax = a->edge.line.p1.x; + } + if (b->edge.line.p1.x < b->edge.line.p2.x) { + bmin = b->edge.line.p1.x; + bmax = b->edge.line.p2.x; + } else { + bmin = b->edge.line.p2.x; + bmax = b->edge.line.p1.x; + } + if (amax < bmin) return -1; + if (amin > bmax) return +1; + } + + ady = a->edge.line.p2.y - a->edge.line.p1.y; + adx = a->edge.line.p2.x - a->edge.line.p1.x; + if (adx == 0) + have_dx_adx_bdx &= ~HAVE_ADX; + + bdy = b->edge.line.p2.y - b->edge.line.p1.y; + bdx = b->edge.line.p2.x - b->edge.line.p1.x; + if (bdx == 0) + have_dx_adx_bdx &= ~HAVE_BDX; + + dx = a->edge.line.p1.x - b->edge.line.p1.x; + if (dx == 0) + have_dx_adx_bdx &= ~HAVE_DX; + +#define L _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (ady, bdy), dx) +#define A _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (adx, bdy), y - a->edge.line.p1.y) +#define B _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (bdx, ady), y - b->edge.line.p1.y) + switch (have_dx_adx_bdx) { + default: + case HAVE_NONE: + return 0; + case HAVE_DX: + /* A_dy * B_dy * (A_x - B_x) ∘ 0 */ + return dx; /* ady * bdy is positive definite */ + case HAVE_ADX: + /* 0 ∘ - (Y - A_y) * A_dx * B_dy */ + return adx; /* bdy * (y - a->top.y) is positive definite */ + case HAVE_BDX: + /* 0 ∘ (Y - B_y) * B_dx * A_dy */ + return -bdx; /* ady * (y - b->top.y) is positive definite */ + case HAVE_ADX_BDX: + /* 0 ∘ (Y - B_y) * B_dx * A_dy - (Y - A_y) * A_dx * B_dy */ + if ((adx ^ bdx) < 0) { + return adx; + } else if (a->edge.line.p1.y == b->edge.line.p1.y) { /* common origin */ + cairo_int64_t adx_bdy, bdx_ady; + + /* ∴ A_dx * B_dy ∘ B_dx * A_dy */ + + adx_bdy = _cairo_int32x32_64_mul (adx, bdy); + bdx_ady = _cairo_int32x32_64_mul (bdx, ady); + + return _cairo_int64_cmp (adx_bdy, bdx_ady); + } else + return _cairo_int128_cmp (A, B); + case HAVE_DX_ADX: + /* A_dy * (A_x - B_x) ∘ - (Y - A_y) * A_dx */ + if ((-adx ^ dx) < 0) { + return dx; + } else { + cairo_int64_t ady_dx, dy_adx; + + ady_dx = _cairo_int32x32_64_mul (ady, dx); + dy_adx = _cairo_int32x32_64_mul (a->edge.line.p1.y - y, adx); + + return _cairo_int64_cmp (ady_dx, dy_adx); + } + case HAVE_DX_BDX: + /* B_dy * (A_x - B_x) ∘ (Y - B_y) * B_dx */ + if ((bdx ^ dx) < 0) { + return dx; + } else { + cairo_int64_t bdy_dx, dy_bdx; + + bdy_dx = _cairo_int32x32_64_mul (bdy, dx); + dy_bdx = _cairo_int32x32_64_mul (y - b->edge.line.p1.y, bdx); + + return _cairo_int64_cmp (bdy_dx, dy_bdx); + } + case HAVE_ALL: + /* XXX try comparing (a->edge.line.p2.x - b->edge.line.p2.x) et al */ + return _cairo_int128_cmp (L, _cairo_int128_sub (B, A)); + } +#undef B +#undef A +#undef L +} + +/* + * We need to compare the x-coordinate of a line for a particular y wrt to a + * given x, without loss of precision. + * + * The x-coordinate along an edge for a given y is: + * X = A_x + (Y - A_y) * A_dx / A_dy + * + * So the inequality we wish to test is: + * A_x + (Y - A_y) * A_dx / A_dy ∘ X + * where ∘ is our inequality operator. + * + * By construction, we know that A_dy (and (Y - A_y)) are + * all positive, so we can rearrange it thus without causing a sign change: + * (Y - A_y) * A_dx ∘ (X - A_x) * A_dy + * + * Given the assumption that all the deltas fit within 32 bits, we can compute + * this comparison directly using 64 bit arithmetic. + * + * See the similar discussion for _slope_compare() and + * edges_compare_x_for_y_general(). + */ +static int +edge_compare_for_y_against_x (const cairo_bo_edge_t *a, + int32_t y, + int32_t x) +{ + int32_t adx, ady; + int32_t dx, dy; + cairo_int64_t L, R; + + if (x < a->edge.line.p1.x && x < a->edge.line.p2.x) + return 1; + if (x > a->edge.line.p1.x && x > a->edge.line.p2.x) + return -1; + + adx = a->edge.line.p2.x - a->edge.line.p1.x; + dx = x - a->edge.line.p1.x; + + if (adx == 0) + return -dx; + if (dx == 0 || (adx ^ dx) < 0) + return adx; + + dy = y - a->edge.line.p1.y; + ady = a->edge.line.p2.y - a->edge.line.p1.y; + + L = _cairo_int32x32_64_mul (dy, adx); + R = _cairo_int32x32_64_mul (dx, ady); + + return _cairo_int64_cmp (L, R); +} + +static int +edges_compare_x_for_y (const cairo_bo_edge_t *a, + const cairo_bo_edge_t *b, + int32_t y) +{ + /* If the sweep-line is currently on an end-point of a line, + * then we know its precise x value (and considering that we often need to + * compare events at end-points, this happens frequently enough to warrant + * special casing). + */ + enum { + HAVE_NEITHER = 0x0, + HAVE_AX = 0x1, + HAVE_BX = 0x2, + HAVE_BOTH = HAVE_AX | HAVE_BX + } have_ax_bx = HAVE_BOTH; + int32_t ax = 0, bx = 0; + + if (y == a->edge.line.p1.y) + ax = a->edge.line.p1.x; + else if (y == a->edge.line.p2.y) + ax = a->edge.line.p2.x; + else + have_ax_bx &= ~HAVE_AX; + + if (y == b->edge.line.p1.y) + bx = b->edge.line.p1.x; + else if (y == b->edge.line.p2.y) + bx = b->edge.line.p2.x; + else + have_ax_bx &= ~HAVE_BX; + + switch (have_ax_bx) { + default: + case HAVE_NEITHER: + return edges_compare_x_for_y_general (a, b, y); + case HAVE_AX: + return -edge_compare_for_y_against_x (b, y, ax); + case HAVE_BX: + return edge_compare_for_y_against_x (a, y, bx); + case HAVE_BOTH: + return ax - bx; + } +} + +static inline int +_line_equal (const cairo_line_t *a, const cairo_line_t *b) +{ + return a->p1.x == b->p1.x && a->p1.y == b->p1.y && + a->p2.x == b->p2.x && a->p2.y == b->p2.y; +} + +static int +_cairo_bo_sweep_line_compare_edges (cairo_bo_sweep_line_t *sweep_line, + const cairo_bo_edge_t *a, + const cairo_bo_edge_t *b) +{ + int cmp; + + /* compare the edges if not identical */ + if (! _line_equal (&a->edge.line, &b->edge.line)) { + cmp = edges_compare_x_for_y (a, b, sweep_line->current_y); + if (cmp) + return cmp; + + /* The two edges intersect exactly at y, so fall back on slope + * comparison. We know that this compare_edges function will be + * called only when starting a new edge, (not when stopping an + * edge), so we don't have to worry about conditionally inverting + * the sense of _slope_compare. */ + cmp = _slope_compare (a, b); + if (cmp) + return cmp; + } + + /* We've got two collinear edges now. */ + return b->edge.bottom - a->edge.bottom; +} + +static inline cairo_int64_t +det32_64 (int32_t a, int32_t b, + int32_t c, int32_t d) +{ + /* det = a * d - b * c */ + return _cairo_int64_sub (_cairo_int32x32_64_mul (a, d), + _cairo_int32x32_64_mul (b, c)); +} + +static inline cairo_int128_t +det64x32_128 (cairo_int64_t a, int32_t b, + cairo_int64_t c, int32_t d) +{ + /* det = a * d - b * c */ + return _cairo_int128_sub (_cairo_int64x32_128_mul (a, d), + _cairo_int64x32_128_mul (c, b)); +} + +static inline cairo_bo_intersect_ordinate_t +round_to_nearest (cairo_quorem64_t d, + cairo_int64_t den) +{ + cairo_bo_intersect_ordinate_t ordinate; + int32_t quo = d.quo; + cairo_int64_t drem_2 = _cairo_int64_mul (d.rem, _cairo_int32_to_int64 (2)); + + /* assert (! _cairo_int64_negative (den));*/ + + if (_cairo_int64_lt (drem_2, _cairo_int64_negate (den))) { + quo -= 1; + drem_2 = _cairo_int64_negate (drem_2); + } else if (_cairo_int64_le (den, drem_2)) { + quo += 1; + drem_2 = _cairo_int64_negate (drem_2); + } + + ordinate.ordinate = quo; + ordinate.approx = _cairo_int64_is_zero (drem_2) ? EXACT : _cairo_int64_negative (drem_2) ? EXCESS : DEFAULT; + + return ordinate; +} + +/* Compute the intersection of two lines as defined by two edges. The + * result is provided as a coordinate pair of 128-bit integers. + * + * Returns %CAIRO_BO_STATUS_INTERSECTION if there is an intersection or + * %CAIRO_BO_STATUS_PARALLEL if the two lines are exactly parallel. + */ +static cairo_bool_t +intersect_lines (cairo_bo_edge_t *a, + cairo_bo_edge_t *b, + cairo_bo_intersect_point_t *intersection) +{ + cairo_int64_t a_det, b_det; + + /* XXX: We're assuming here that dx and dy will still fit in 32 + * bits. That's not true in general as there could be overflow. We + * should prevent that before the tessellation algorithm begins. + * What we're doing to mitigate this is to perform clamping in + * cairo_bo_tessellate_polygon(). + */ + int32_t dx1 = a->edge.line.p1.x - a->edge.line.p2.x; + int32_t dy1 = a->edge.line.p1.y - a->edge.line.p2.y; + + int32_t dx2 = b->edge.line.p1.x - b->edge.line.p2.x; + int32_t dy2 = b->edge.line.p1.y - b->edge.line.p2.y; + + cairo_int64_t den_det; + cairo_int64_t R; + cairo_quorem64_t qr; + + den_det = det32_64 (dx1, dy1, dx2, dy2); + + /* Q: Can we determine that the lines do not intersect (within range) + * much more cheaply than computing the intersection point i.e. by + * avoiding the division? + * + * X = ax + t * adx = bx + s * bdx; + * Y = ay + t * ady = by + s * bdy; + * ∴ t * (ady*bdx - bdy*adx) = bdx * (by - ay) + bdy * (ax - bx) + * => t * L = R + * + * Therefore we can reject any intersection (under the criteria for + * valid intersection events) if: + * L^R < 0 => t < 0, or + * L t > 1 + * + * (where top/bottom must at least extend to the line endpoints). + * + * A similar substitution can be performed for s, yielding: + * s * (ady*bdx - bdy*adx) = ady * (ax - bx) - adx * (ay - by) + */ + R = det32_64 (dx2, dy2, + b->edge.line.p1.x - a->edge.line.p1.x, + b->edge.line.p1.y - a->edge.line.p1.y); + if (_cairo_int64_le (den_det, R)) + return FALSE; + + R = det32_64 (dy1, dx1, + a->edge.line.p1.y - b->edge.line.p1.y, + a->edge.line.p1.x - b->edge.line.p1.x); + if (_cairo_int64_le (den_det, R)) + return FALSE; + + /* We now know that the two lines should intersect within range. */ + + a_det = det32_64 (a->edge.line.p1.x, a->edge.line.p1.y, + a->edge.line.p2.x, a->edge.line.p2.y); + b_det = det32_64 (b->edge.line.p1.x, b->edge.line.p1.y, + b->edge.line.p2.x, b->edge.line.p2.y); + + /* x = det (a_det, dx1, b_det, dx2) / den_det */ + qr = _cairo_int_96by64_32x64_divrem (det64x32_128 (a_det, dx1, + b_det, dx2), + den_det); + if (_cairo_int64_eq (qr.rem, den_det)) + return FALSE; + + intersection->x = round_to_nearest (qr, den_det); + + /* y = det (a_det, dy1, b_det, dy2) / den_det */ + qr = _cairo_int_96by64_32x64_divrem (det64x32_128 (a_det, dy1, + b_det, dy2), + den_det); + if (_cairo_int64_eq (qr.rem, den_det)) + return FALSE; + + intersection->y = round_to_nearest (qr, den_det); + + return TRUE; +} + +static int +_cairo_bo_intersect_ordinate_32_compare (cairo_bo_intersect_ordinate_t a, + int32_t b) +{ + /* First compare the quotient */ + if (a.ordinate > b) + return +1; + if (a.ordinate < b) + return -1; + + return a.approx; /* == EXCESS ? -1 : a.approx == EXACT ? 0 : 1;*/ +} + +/* Does the given edge contain the given point. The point must already + * be known to be contained within the line determined by the edge, + * (most likely the point results from an intersection of this edge + * with another). + * + * If we had exact arithmetic, then this function would simply be a + * matter of examining whether the y value of the point lies within + * the range of y values of the edge. But since intersection points + * are not exact due to being rounded to the nearest integer within + * the available precision, we must also examine the x value of the + * point. + * + * The definition of "contains" here is that the given intersection + * point will be seen by the sweep line after the start event for the + * given edge and before the stop event for the edge. See the comments + * in the implementation for more details. + */ +static cairo_bool_t +_cairo_bo_edge_contains_intersect_point (cairo_bo_edge_t *edge, + cairo_bo_intersect_point_t *point) +{ + return _cairo_bo_intersect_ordinate_32_compare (point->y, + edge->edge.bottom) < 0; +} + +/* Compute the intersection of two edges. The result is provided as a + * coordinate pair of 128-bit integers. + * + * Returns %CAIRO_BO_STATUS_INTERSECTION if there is an intersection + * that is within both edges, %CAIRO_BO_STATUS_NO_INTERSECTION if the + * intersection of the lines defined by the edges occurs outside of + * one or both edges, and %CAIRO_BO_STATUS_PARALLEL if the two edges + * are exactly parallel. + * + * Note that when determining if a candidate intersection is "inside" + * an edge, we consider both the infinitesimal shortening and the + * infinitesimal tilt rules described by John Hobby. Specifically, if + * the intersection is exactly the same as an edge point, it is + * effectively outside (no intersection is returned). Also, if the + * intersection point has the same + */ +static cairo_bool_t +_cairo_bo_edge_intersect (cairo_bo_edge_t *a, + cairo_bo_edge_t *b, + cairo_bo_intersect_point_t *intersection) +{ + if (! intersect_lines (a, b, intersection)) + return FALSE; + + if (! _cairo_bo_edge_contains_intersect_point (a, intersection)) + return FALSE; + + if (! _cairo_bo_edge_contains_intersect_point (b, intersection)) + return FALSE; + + return TRUE; +} + +static inline int +cairo_bo_event_compare (const cairo_bo_event_t *a, + const cairo_bo_event_t *b) +{ + int cmp; + + cmp = _cairo_bo_point32_compare (&a->point, &b->point); + if (cmp) + return cmp; + + cmp = a->type - b->type; + if (cmp) + return cmp; + + return a < b ? -1 : a == b ? 0 : 1; +} + +static inline void +_pqueue_init (pqueue_t *pq) +{ + pq->max_size = ARRAY_LENGTH (pq->elements_embedded); + pq->size = 0; + + pq->elements = pq->elements_embedded; +} + +static inline void +_pqueue_fini (pqueue_t *pq) +{ + if (pq->elements != pq->elements_embedded) + free (pq->elements); +} + +static cairo_status_t +_pqueue_grow (pqueue_t *pq) +{ + cairo_bo_event_t **new_elements; + pq->max_size *= 2; + + if (pq->elements == pq->elements_embedded) { + new_elements = _cairo_malloc_ab (pq->max_size, + sizeof (cairo_bo_event_t *)); + if (unlikely (new_elements == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + memcpy (new_elements, pq->elements_embedded, + sizeof (pq->elements_embedded)); + } else { + new_elements = _cairo_realloc_ab (pq->elements, + pq->max_size, + sizeof (cairo_bo_event_t *)); + if (unlikely (new_elements == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + pq->elements = new_elements; + return CAIRO_STATUS_SUCCESS; +} + +static inline cairo_status_t +_pqueue_push (pqueue_t *pq, cairo_bo_event_t *event) +{ + cairo_bo_event_t **elements; + int i, parent; + + if (unlikely (pq->size + 1 == pq->max_size)) { + cairo_status_t status; + + status = _pqueue_grow (pq); + if (unlikely (status)) + return status; + } + + elements = pq->elements; + + for (i = ++pq->size; + i != PQ_FIRST_ENTRY && + cairo_bo_event_compare (event, + elements[parent = PQ_PARENT_INDEX (i)]) < 0; + i = parent) + { + elements[i] = elements[parent]; + } + + elements[i] = event; + + return CAIRO_STATUS_SUCCESS; +} + +static inline void +_pqueue_pop (pqueue_t *pq) +{ + cairo_bo_event_t **elements = pq->elements; + cairo_bo_event_t *tail; + int child, i; + + tail = elements[pq->size--]; + if (pq->size == 0) { + elements[PQ_FIRST_ENTRY] = NULL; + return; + } + + for (i = PQ_FIRST_ENTRY; + (child = PQ_LEFT_CHILD_INDEX (i)) <= pq->size; + i = child) + { + if (child != pq->size && + cairo_bo_event_compare (elements[child+1], + elements[child]) < 0) + { + child++; + } + + if (cairo_bo_event_compare (elements[child], tail) >= 0) + break; + + elements[i] = elements[child]; + } + elements[i] = tail; +} + +static inline cairo_status_t +_cairo_bo_event_queue_insert (cairo_bo_event_queue_t *queue, + cairo_bo_event_type_t type, + cairo_bo_edge_t *e1, + cairo_bo_edge_t *e2, + const cairo_bo_intersect_point_t *point) +{ + cairo_bo_queue_event_t *event; + + event = _cairo_freepool_alloc (&queue->pool); + if (unlikely (event == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + event->type = type; + event->e1 = e1; + event->e2 = e2; + event->point = *point; + + return _pqueue_push (&queue->pqueue, (cairo_bo_event_t *) event); +} + +static void +_cairo_bo_event_queue_delete (cairo_bo_event_queue_t *queue, + cairo_bo_event_t *event) +{ + _cairo_freepool_free (&queue->pool, event); +} + +static cairo_bo_event_t * +_cairo_bo_event_dequeue (cairo_bo_event_queue_t *event_queue) +{ + cairo_bo_event_t *event, *cmp; + + event = event_queue->pqueue.elements[PQ_FIRST_ENTRY]; + cmp = *event_queue->start_events; + if (event == NULL || + (cmp != NULL && cairo_bo_event_compare (cmp, event) < 0)) + { + event = cmp; + event_queue->start_events++; + } + else + { + _pqueue_pop (&event_queue->pqueue); + } + + return event; +} + +CAIRO_COMBSORT_DECLARE (_cairo_bo_event_queue_sort, + cairo_bo_event_t *, + cairo_bo_event_compare) + +static void +_cairo_bo_event_queue_init (cairo_bo_event_queue_t *event_queue, + cairo_bo_event_t **start_events, + int num_events) +{ + _cairo_bo_event_queue_sort (start_events, num_events); + start_events[num_events] = NULL; + + event_queue->start_events = start_events; + + _cairo_freepool_init (&event_queue->pool, + sizeof (cairo_bo_queue_event_t)); + _pqueue_init (&event_queue->pqueue); + event_queue->pqueue.elements[PQ_FIRST_ENTRY] = NULL; +} + +static cairo_status_t +event_queue_insert_stop (cairo_bo_event_queue_t *event_queue, + cairo_bo_edge_t *edge) +{ + cairo_bo_intersect_point_t point; + + point.y.ordinate = edge->edge.bottom; + point.y.approx = EXACT; + point.x.ordinate = _line_compute_intersection_x_for_y (&edge->edge.line, + point.y.ordinate); + point.x.approx = EXACT; + + return _cairo_bo_event_queue_insert (event_queue, + CAIRO_BO_EVENT_TYPE_STOP, + edge, NULL, + &point); +} + +static void +_cairo_bo_event_queue_fini (cairo_bo_event_queue_t *event_queue) +{ + _pqueue_fini (&event_queue->pqueue); + _cairo_freepool_fini (&event_queue->pool); +} + +static inline cairo_status_t +event_queue_insert_if_intersect_below_current_y (cairo_bo_event_queue_t *event_queue, + cairo_bo_edge_t *left, + cairo_bo_edge_t *right) +{ + cairo_bo_intersect_point_t intersection; + + if (_line_equal (&left->edge.line, &right->edge.line)) + return CAIRO_STATUS_SUCCESS; + + /* The names "left" and "right" here are correct descriptions of + * the order of the two edges within the active edge list. So if a + * slope comparison also puts left less than right, then we know + * that the intersection of these two segments has already + * occurred before the current sweep line position. */ + if (_slope_compare (left, right) <= 0) + return CAIRO_STATUS_SUCCESS; + + if (! _cairo_bo_edge_intersect (left, right, &intersection)) + return CAIRO_STATUS_SUCCESS; + + return _cairo_bo_event_queue_insert (event_queue, + CAIRO_BO_EVENT_TYPE_INTERSECTION, + left, right, + &intersection); +} + +static void +_cairo_bo_sweep_line_init (cairo_bo_sweep_line_t *sweep_line) +{ + sweep_line->head = NULL; + sweep_line->current_y = INT32_MIN; + sweep_line->current_edge = NULL; +} + +static cairo_status_t +sweep_line_insert (cairo_bo_sweep_line_t *sweep_line, + cairo_bo_edge_t *edge) +{ + if (sweep_line->current_edge != NULL) { + cairo_bo_edge_t *prev, *next; + int cmp; + + cmp = _cairo_bo_sweep_line_compare_edges (sweep_line, + sweep_line->current_edge, + edge); + if (cmp < 0) { + prev = sweep_line->current_edge; + next = prev->next; + while (next != NULL && + _cairo_bo_sweep_line_compare_edges (sweep_line, + next, edge) < 0) + { + prev = next, next = prev->next; + } + + prev->next = edge; + edge->prev = prev; + edge->next = next; + if (next != NULL) + next->prev = edge; + } else if (cmp > 0) { + next = sweep_line->current_edge; + prev = next->prev; + while (prev != NULL && + _cairo_bo_sweep_line_compare_edges (sweep_line, + prev, edge) > 0) + { + next = prev, prev = next->prev; + } + + next->prev = edge; + edge->next = next; + edge->prev = prev; + if (prev != NULL) + prev->next = edge; + else + sweep_line->head = edge; + } else { + prev = sweep_line->current_edge; + edge->prev = prev; + edge->next = prev->next; + if (prev->next != NULL) + prev->next->prev = edge; + prev->next = edge; + } + } else { + sweep_line->head = edge; + } + + sweep_line->current_edge = edge; + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_bo_sweep_line_delete (cairo_bo_sweep_line_t *sweep_line, + cairo_bo_edge_t *edge) +{ + if (edge->prev != NULL) + edge->prev->next = edge->next; + else + sweep_line->head = edge->next; + + if (edge->next != NULL) + edge->next->prev = edge->prev; + + if (sweep_line->current_edge == edge) + sweep_line->current_edge = edge->prev ? edge->prev : edge->next; +} + +static void +_cairo_bo_sweep_line_swap (cairo_bo_sweep_line_t *sweep_line, + cairo_bo_edge_t *left, + cairo_bo_edge_t *right) +{ + if (left->prev != NULL) + left->prev->next = right; + else + sweep_line->head = right; + + if (right->next != NULL) + right->next->prev = left; + + left->next = right->next; + right->next = left; + + right->prev = left->prev; + left->prev = right; +} + +static inline cairo_bool_t +edges_colinear (const cairo_bo_edge_t *a, const cairo_bo_edge_t *b) +{ + if (_line_equal (&a->edge.line, &b->edge.line)) + return TRUE; + + if (_slope_compare (a, b)) + return FALSE; + + /* The choice of y is not truly arbitrary since we must guarantee that it + * is greater than the start of either line. + */ + if (a->edge.line.p1.y == b->edge.line.p1.y) { + return a->edge.line.p1.x == b->edge.line.p1.x; + } else if (a->edge.line.p1.y < b->edge.line.p1.y) { + return edge_compare_for_y_against_x (b, + a->edge.line.p1.y, + a->edge.line.p1.x) == 0; + } else { + return edge_compare_for_y_against_x (a, + b->edge.line.p1.y, + b->edge.line.p1.x) == 0; + } +} + +static void +edges_end (cairo_bo_edge_t *left, + int32_t bot, + cairo_polygon_t *polygon) +{ + cairo_bo_deferred_t *l = &left->deferred; + cairo_bo_edge_t *right = l->other; + + assert(right->deferred.other == NULL); + if (likely (l->top < bot)) { + _cairo_polygon_add_line (polygon, &left->edge.line, l->top, bot, 1); + _cairo_polygon_add_line (polygon, &right->edge.line, l->top, bot, -1); + } + + l->other = NULL; +} + +static inline void +edges_start_or_continue (cairo_bo_edge_t *left, + cairo_bo_edge_t *right, + int top, + cairo_polygon_t *polygon) +{ + assert (right != NULL); + assert (right->deferred.other == NULL); + + if (left->deferred.other == right) + return; + + if (left->deferred.other != NULL) { + if (edges_colinear (left->deferred.other, right)) { + cairo_bo_edge_t *old = left->deferred.other; + + /* continuation on right, extend right to cover both */ + assert (old->deferred.other == NULL); + assert (old->edge.line.p2.y > old->edge.line.p1.y); + + if (old->edge.line.p1.y < right->edge.line.p1.y) + right->edge.line.p1 = old->edge.line.p1; + if (old->edge.line.p2.y > right->edge.line.p2.y) + right->edge.line.p2 = old->edge.line.p2; + left->deferred.other = right; + return; + } + + edges_end (left, top, polygon); + } + + if (! edges_colinear (left, right)) { + left->deferred.top = top; + left->deferred.other = right; + } +} + +#define is_zero(w) ((w)[0] == 0 || (w)[1] == 0) + +static inline void +active_edges (cairo_bo_edge_t *left, + int32_t top, + cairo_polygon_t *polygon) +{ + cairo_bo_edge_t *right; + int winding[2] = {0, 0}; + + /* Yes, this is naive. Consider this a placeholder. */ + + while (left != NULL) { + assert (is_zero (winding)); + + do { + winding[left->a_or_b] += left->edge.dir; + if (! is_zero (winding)) + break; + + if unlikely ((left->deferred.other)) + edges_end (left, top, polygon); + + left = left->next; + if (! left) + return; + } while (1); + + right = left->next; + do { + if unlikely ((right->deferred.other)) + edges_end (right, top, polygon); + + winding[right->a_or_b] += right->edge.dir; + if (is_zero (winding)) { + if (right->next == NULL || + ! edges_colinear (right, right->next)) + break; + } + + right = right->next; + } while (1); + + edges_start_or_continue (left, right, top, polygon); + + left = right->next; + } +} + +static cairo_status_t +intersection_sweep (cairo_bo_event_t **start_events, + int num_events, + cairo_polygon_t *polygon) +{ + cairo_status_t status = CAIRO_STATUS_SUCCESS; /* silence compiler */ + cairo_bo_event_queue_t event_queue; + cairo_bo_sweep_line_t sweep_line; + cairo_bo_event_t *event; + cairo_bo_edge_t *left, *right; + cairo_bo_edge_t *e1, *e2; + + _cairo_bo_event_queue_init (&event_queue, start_events, num_events); + _cairo_bo_sweep_line_init (&sweep_line); + + while ((event = _cairo_bo_event_dequeue (&event_queue))) { + if (event->point.y.ordinate != sweep_line.current_y) { + active_edges (sweep_line.head, + sweep_line.current_y, + polygon); + sweep_line.current_y = event->point.y.ordinate; + } + + switch (event->type) { + case CAIRO_BO_EVENT_TYPE_START: + e1 = &((cairo_bo_start_event_t *) event)->edge; + + status = sweep_line_insert (&sweep_line, e1); + if (unlikely (status)) + goto unwind; + + status = event_queue_insert_stop (&event_queue, e1); + if (unlikely (status)) + goto unwind; + + left = e1->prev; + right = e1->next; + + if (left != NULL) { + status = event_queue_insert_if_intersect_below_current_y (&event_queue, left, e1); + if (unlikely (status)) + goto unwind; + } + + if (right != NULL) { + status = event_queue_insert_if_intersect_below_current_y (&event_queue, e1, right); + if (unlikely (status)) + goto unwind; + } + + break; + + case CAIRO_BO_EVENT_TYPE_STOP: + e1 = ((cairo_bo_queue_event_t *) event)->e1; + _cairo_bo_event_queue_delete (&event_queue, event); + + if (e1->deferred.other) + edges_end (e1, sweep_line.current_y, polygon); + + left = e1->prev; + right = e1->next; + + _cairo_bo_sweep_line_delete (&sweep_line, e1); + + if (left != NULL && right != NULL) { + status = event_queue_insert_if_intersect_below_current_y (&event_queue, left, right); + if (unlikely (status)) + goto unwind; + } + + break; + + case CAIRO_BO_EVENT_TYPE_INTERSECTION: + e1 = ((cairo_bo_queue_event_t *) event)->e1; + e2 = ((cairo_bo_queue_event_t *) event)->e2; + _cairo_bo_event_queue_delete (&event_queue, event); + + /* skip this intersection if its edges are not adjacent */ + if (e2 != e1->next) + break; + + if (e1->deferred.other) + edges_end (e1, sweep_line.current_y, polygon); + if (e2->deferred.other) + edges_end (e2, sweep_line.current_y, polygon); + + left = e1->prev; + right = e2->next; + + _cairo_bo_sweep_line_swap (&sweep_line, e1, e2); + + /* after the swap e2 is left of e1 */ + + if (left != NULL) { + status = event_queue_insert_if_intersect_below_current_y (&event_queue, left, e2); + if (unlikely (status)) + goto unwind; + } + + if (right != NULL) { + status = event_queue_insert_if_intersect_below_current_y (&event_queue, e1, right); + if (unlikely (status)) + goto unwind; + } + + break; + } + } + + unwind: + _cairo_bo_event_queue_fini (&event_queue); + + return status; +} + +cairo_status_t +_cairo_polygon_intersect (cairo_polygon_t *a, int winding_a, + cairo_polygon_t *b, int winding_b) +{ + cairo_status_t status; + cairo_bo_start_event_t stack_events[CAIRO_STACK_ARRAY_LENGTH (cairo_bo_start_event_t)]; + cairo_bo_start_event_t *events; + cairo_bo_event_t *stack_event_ptrs[ARRAY_LENGTH (stack_events) + 1]; + cairo_bo_event_t **event_ptrs; + int num_events; + int i, j; + + /* XXX lazy */ + if (winding_a != CAIRO_FILL_RULE_WINDING) { + status = _cairo_polygon_reduce (a, winding_a); + if (unlikely (status)) + return status; + } + + if (winding_b != CAIRO_FILL_RULE_WINDING) { + status = _cairo_polygon_reduce (b, winding_b); + if (unlikely (status)) + return status; + } + + if (unlikely (0 == a->num_edges)) + return CAIRO_STATUS_SUCCESS; + + if (unlikely (0 == b->num_edges)) { + a->num_edges = 0; + return CAIRO_STATUS_SUCCESS; + } + + events = stack_events; + event_ptrs = stack_event_ptrs; + num_events = a->num_edges + b->num_edges; + if (num_events > ARRAY_LENGTH (stack_events)) { + events = _cairo_malloc_ab_plus_c (num_events, + sizeof (cairo_bo_start_event_t) + + sizeof (cairo_bo_event_t *), + sizeof (cairo_bo_event_t *)); + if (unlikely (events == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + event_ptrs = (cairo_bo_event_t **) (events + num_events); + } + + j = 0; + for (i = 0; i < a->num_edges; i++) { + event_ptrs[j] = (cairo_bo_event_t *) &events[j]; + + events[j].type = CAIRO_BO_EVENT_TYPE_START; + events[j].point.y.ordinate = a->edges[i].top; + events[j].point.y.approx = EXACT; + events[j].point.x.ordinate = + _line_compute_intersection_x_for_y (&a->edges[i].line, + events[j].point.y.ordinate); + events[j].point.x.approx = EXACT; + + events[j].edge.a_or_b = 0; + events[j].edge.edge = a->edges[i]; + events[j].edge.deferred.other = NULL; + events[j].edge.prev = NULL; + events[j].edge.next = NULL; + j++; + } + + for (i = 0; i < b->num_edges; i++) { + event_ptrs[j] = (cairo_bo_event_t *) &events[j]; + + events[j].type = CAIRO_BO_EVENT_TYPE_START; + events[j].point.y.ordinate = b->edges[i].top; + events[j].point.y.approx = EXACT; + events[j].point.x.ordinate = + _line_compute_intersection_x_for_y (&b->edges[i].line, + events[j].point.y.ordinate); + events[j].point.x.approx = EXACT; + + events[j].edge.a_or_b = 1; + events[j].edge.edge = b->edges[i]; + events[j].edge.deferred.other = NULL; + events[j].edge.prev = NULL; + events[j].edge.next = NULL; + j++; + } + assert (j == num_events); + +#if 0 + { + FILE *file = fopen ("clip_a.txt", "w"); + _cairo_debug_print_polygon (file, a); + fclose (file); + } + { + FILE *file = fopen ("clip_b.txt", "w"); + _cairo_debug_print_polygon (file, b); + fclose (file); + } +#endif + + a->num_edges = 0; + status = intersection_sweep (event_ptrs, num_events, a); + if (events != stack_events) + free (events); + +#if 0 + { + FILE *file = fopen ("clip_result.txt", "w"); + _cairo_debug_print_polygon (file, a); + fclose (file); + } +#endif + + return status; +} + +cairo_status_t +_cairo_polygon_intersect_with_boxes (cairo_polygon_t *polygon, + cairo_fill_rule_t *winding, + cairo_box_t *boxes, + int num_boxes) +{ + cairo_polygon_t b; + cairo_status_t status; + int n; + + if (num_boxes == 0) { + polygon->num_edges = 0; + return CAIRO_STATUS_SUCCESS; + } + + for (n = 0; n < num_boxes; n++) { + if (polygon->extents.p1.x >= boxes[n].p1.x && + polygon->extents.p2.x <= boxes[n].p2.x && + polygon->extents.p1.y >= boxes[n].p1.y && + polygon->extents.p2.y <= boxes[n].p2.y) + { + return CAIRO_STATUS_SUCCESS; + } + } + + _cairo_polygon_init (&b, NULL, 0); + for (n = 0; n < num_boxes; n++) { + if (boxes[n].p2.x > polygon->extents.p1.x && + boxes[n].p1.x < polygon->extents.p2.x && + boxes[n].p2.y > polygon->extents.p1.y && + boxes[n].p1.y < polygon->extents.p2.y) + { + cairo_point_t p1, p2; + + p1.y = boxes[n].p1.y; + p2.y = boxes[n].p2.y; + + p2.x = p1.x = boxes[n].p1.x; + _cairo_polygon_add_external_edge (&b, &p1, &p2); + + p2.x = p1.x = boxes[n].p2.x; + _cairo_polygon_add_external_edge (&b, &p2, &p1); + } + } + + status = _cairo_polygon_intersect (polygon, *winding, + &b, CAIRO_FILL_RULE_WINDING); + _cairo_polygon_fini (&b); + + *winding = CAIRO_FILL_RULE_WINDING; + return status; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-polygon-reduce.c b/local/recipes/libs/cairo/source/src/cairo-polygon-reduce.c new file mode 100644 index 0000000000..da6c9ab7c7 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-polygon-reduce.c @@ -0,0 +1,1438 @@ +/* + * Copyright © 2004 Carl Worth + * Copyright © 2006 Red Hat, Inc. + * Copyright © 2008 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Carl Worth + * + * Contributor(s): + * Carl D. Worth + * Chris Wilson + */ + +/* Provide definitions for standalone compilation */ +#include "cairoint.h" + +#include "cairo-error-private.h" +#include "cairo-freelist-private.h" +#include "cairo-combsort-inline.h" + +#define DEBUG_POLYGON 0 + +typedef cairo_point_t cairo_bo_point32_t; + +typedef struct _cairo_bo_intersect_ordinate { + int32_t ordinate; + enum { EXACT, INEXACT } exactness; +} cairo_bo_intersect_ordinate_t; + +typedef struct _cairo_bo_intersect_point { + cairo_bo_intersect_ordinate_t x; + cairo_bo_intersect_ordinate_t y; +} cairo_bo_intersect_point_t; + +typedef struct _cairo_bo_edge cairo_bo_edge_t; + +typedef struct _cairo_bo_deferred { + cairo_bo_edge_t *right; + int32_t top; +} cairo_bo_deferred_t; + +struct _cairo_bo_edge { + cairo_edge_t edge; + cairo_bo_edge_t *prev; + cairo_bo_edge_t *next; + cairo_bo_deferred_t deferred; +}; + +/* the parent is always given by index/2 */ +#define PQ_PARENT_INDEX(i) ((i) >> 1) +#define PQ_FIRST_ENTRY 1 + +/* left and right children are index * 2 and (index * 2) +1 respectively */ +#define PQ_LEFT_CHILD_INDEX(i) ((i) << 1) + +typedef enum { + CAIRO_BO_EVENT_TYPE_STOP, + CAIRO_BO_EVENT_TYPE_INTERSECTION, + CAIRO_BO_EVENT_TYPE_START +} cairo_bo_event_type_t; + +typedef struct _cairo_bo_event { + cairo_bo_event_type_t type; + cairo_point_t point; +} cairo_bo_event_t; + +typedef struct _cairo_bo_start_event { + cairo_bo_event_type_t type; + cairo_point_t point; + cairo_bo_edge_t edge; +} cairo_bo_start_event_t; + +typedef struct _cairo_bo_queue_event { + cairo_bo_event_type_t type; + cairo_point_t point; + cairo_bo_edge_t *e1; + cairo_bo_edge_t *e2; +} cairo_bo_queue_event_t; + +typedef struct _pqueue { + int size, max_size; + + cairo_bo_event_t **elements; + cairo_bo_event_t *elements_embedded[1024]; +} pqueue_t; + +typedef struct _cairo_bo_event_queue { + cairo_freepool_t pool; + pqueue_t pqueue; + cairo_bo_event_t **start_events; +} cairo_bo_event_queue_t; + +typedef struct _cairo_bo_sweep_line { + cairo_bo_edge_t *head; + int32_t current_y; + cairo_bo_edge_t *current_edge; +} cairo_bo_sweep_line_t; + +static cairo_fixed_t +_line_compute_intersection_x_for_y (const cairo_line_t *line, + cairo_fixed_t y) +{ + cairo_fixed_t x, dy; + + if (y == line->p1.y) + return line->p1.x; + if (y == line->p2.y) + return line->p2.x; + + x = line->p1.x; + dy = line->p2.y - line->p1.y; + if (dy != 0) { + x += _cairo_fixed_mul_div_floor (y - line->p1.y, + line->p2.x - line->p1.x, + dy); + } + + return x; +} + +static inline int +_cairo_bo_point32_compare (cairo_bo_point32_t const *a, + cairo_bo_point32_t const *b) +{ + int cmp; + + cmp = a->y - b->y; + if (cmp) + return cmp; + + return a->x - b->x; +} + +/* Compare the slope of a to the slope of b, returning 1, 0, -1 if the + * slope a is respectively greater than, equal to, or less than the + * slope of b. + * + * For each edge, consider the direction vector formed from: + * + * top -> bottom + * + * which is: + * + * (dx, dy) = (line.p2.x - line.p1.x, line.p2.y - line.p1.y) + * + * We then define the slope of each edge as dx/dy, (which is the + * inverse of the slope typically used in math instruction). We never + * compute a slope directly as the value approaches infinity, but we + * can derive a slope comparison without division as follows, (where + * the ? represents our compare operator). + * + * 1. slope(a) ? slope(b) + * 2. adx/ady ? bdx/bdy + * 3. (adx * bdy) ? (bdx * ady) + * + * Note that from step 2 to step 3 there is no change needed in the + * sign of the result since both ady and bdy are guaranteed to be + * greater than or equal to 0. + * + * When using this slope comparison to sort edges, some care is needed + * when interpreting the results. Since the slope compare operates on + * distance vectors from top to bottom it gives a correct left to + * right sort for edges that have a common top point, (such as two + * edges with start events at the same location). On the other hand, + * the sense of the result will be exactly reversed for two edges that + * have a common stop point. + */ +static inline int +_slope_compare (const cairo_bo_edge_t *a, + const cairo_bo_edge_t *b) +{ + /* XXX: We're assuming here that dx and dy will still fit in 32 + * bits. That's not true in general as there could be overflow. We + * should prevent that before the tessellation algorithm + * begins. + */ + int32_t adx = a->edge.line.p2.x - a->edge.line.p1.x; + int32_t bdx = b->edge.line.p2.x - b->edge.line.p1.x; + + /* Since the dy's are all positive by construction we can fast + * path several common cases. + */ + + /* First check for vertical lines. */ + if (adx == 0) + return -bdx; + if (bdx == 0) + return adx; + + /* Then where the two edges point in different directions wrt x. */ + if ((adx ^ bdx) < 0) + return adx; + + /* Finally we actually need to do the general comparison. */ + { + int32_t ady = a->edge.line.p2.y - a->edge.line.p1.y; + int32_t bdy = b->edge.line.p2.y - b->edge.line.p1.y; + cairo_int64_t adx_bdy = _cairo_int32x32_64_mul (adx, bdy); + cairo_int64_t bdx_ady = _cairo_int32x32_64_mul (bdx, ady); + + return _cairo_int64_cmp (adx_bdy, bdx_ady); + } +} + +/* + * We need to compare the x-coordinates of a pair of lines for a particular y, + * without loss of precision. + * + * The x-coordinate along an edge for a given y is: + * X = A_x + (Y - A_y) * A_dx / A_dy + * + * So the inequality we wish to test is: + * A_x + (Y - A_y) * A_dx / A_dy ∘ B_x + (Y - B_y) * B_dx / B_dy, + * where ∘ is our inequality operator. + * + * By construction, we know that A_dy and B_dy (and (Y - A_y), (Y - B_y)) are + * all positive, so we can rearrange it thus without causing a sign change: + * A_dy * B_dy * (A_x - B_x) ∘ (Y - B_y) * B_dx * A_dy + * - (Y - A_y) * A_dx * B_dy + * + * Given the assumption that all the deltas fit within 32 bits, we can compute + * this comparison directly using 128 bit arithmetic. For certain, but common, + * input we can reduce this down to a single 32 bit compare by inspecting the + * deltas. + * + * (And put the burden of the work on developing fast 128 bit ops, which are + * required throughout the tessellator.) + * + * See the similar discussion for _slope_compare(). + */ +static int +edges_compare_x_for_y_general (const cairo_bo_edge_t *a, + const cairo_bo_edge_t *b, + int32_t y) +{ + /* XXX: We're assuming here that dx and dy will still fit in 32 + * bits. That's not true in general as there could be overflow. We + * should prevent that before the tessellation algorithm + * begins. + */ + int32_t dx; + int32_t adx, ady; + int32_t bdx, bdy; + enum { + HAVE_NONE = 0x0, + HAVE_DX = 0x1, + HAVE_ADX = 0x2, + HAVE_DX_ADX = HAVE_DX | HAVE_ADX, + HAVE_BDX = 0x4, + HAVE_DX_BDX = HAVE_DX | HAVE_BDX, + HAVE_ADX_BDX = HAVE_ADX | HAVE_BDX, + HAVE_ALL = HAVE_DX | HAVE_ADX | HAVE_BDX + } have_dx_adx_bdx = HAVE_ALL; + + /* don't bother solving for abscissa if the edges' bounding boxes + * can be used to order them. */ + { + int32_t amin, amax; + int32_t bmin, bmax; + if (a->edge.line.p1.x < a->edge.line.p2.x) { + amin = a->edge.line.p1.x; + amax = a->edge.line.p2.x; + } else { + amin = a->edge.line.p2.x; + amax = a->edge.line.p1.x; + } + if (b->edge.line.p1.x < b->edge.line.p2.x) { + bmin = b->edge.line.p1.x; + bmax = b->edge.line.p2.x; + } else { + bmin = b->edge.line.p2.x; + bmax = b->edge.line.p1.x; + } + if (amax < bmin) return -1; + if (amin > bmax) return +1; + } + + ady = a->edge.line.p2.y - a->edge.line.p1.y; + adx = a->edge.line.p2.x - a->edge.line.p1.x; + if (adx == 0) + have_dx_adx_bdx &= ~HAVE_ADX; + + bdy = b->edge.line.p2.y - b->edge.line.p1.y; + bdx = b->edge.line.p2.x - b->edge.line.p1.x; + if (bdx == 0) + have_dx_adx_bdx &= ~HAVE_BDX; + + dx = a->edge.line.p1.x - b->edge.line.p1.x; + if (dx == 0) + have_dx_adx_bdx &= ~HAVE_DX; + +#define L _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (ady, bdy), dx) +#define A _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (adx, bdy), y - a->edge.line.p1.y) +#define B _cairo_int64x32_128_mul (_cairo_int32x32_64_mul (bdx, ady), y - b->edge.line.p1.y) + switch (have_dx_adx_bdx) { + default: + case HAVE_NONE: + return 0; + case HAVE_DX: + /* A_dy * B_dy * (A_x - B_x) ∘ 0 */ + return dx; /* ady * bdy is positive definite */ + case HAVE_ADX: + /* 0 ∘ - (Y - A_y) * A_dx * B_dy */ + return adx; /* bdy * (y - a->top.y) is positive definite */ + case HAVE_BDX: + /* 0 ∘ (Y - B_y) * B_dx * A_dy */ + return -bdx; /* ady * (y - b->top.y) is positive definite */ + case HAVE_ADX_BDX: + /* 0 ∘ (Y - B_y) * B_dx * A_dy - (Y - A_y) * A_dx * B_dy */ + if ((adx ^ bdx) < 0) { + return adx; + } else if (a->edge.line.p1.y == b->edge.line.p1.y) { /* common origin */ + cairo_int64_t adx_bdy, bdx_ady; + + /* ∴ A_dx * B_dy ∘ B_dx * A_dy */ + + adx_bdy = _cairo_int32x32_64_mul (adx, bdy); + bdx_ady = _cairo_int32x32_64_mul (bdx, ady); + + return _cairo_int64_cmp (adx_bdy, bdx_ady); + } else + return _cairo_int128_cmp (A, B); + case HAVE_DX_ADX: + /* A_dy * (A_x - B_x) ∘ - (Y - A_y) * A_dx */ + if ((-adx ^ dx) < 0) { + return dx; + } else { + cairo_int64_t ady_dx, dy_adx; + + ady_dx = _cairo_int32x32_64_mul (ady, dx); + dy_adx = _cairo_int32x32_64_mul (a->edge.line.p1.y - y, adx); + + return _cairo_int64_cmp (ady_dx, dy_adx); + } + case HAVE_DX_BDX: + /* B_dy * (A_x - B_x) ∘ (Y - B_y) * B_dx */ + if ((bdx ^ dx) < 0) { + return dx; + } else { + cairo_int64_t bdy_dx, dy_bdx; + + bdy_dx = _cairo_int32x32_64_mul (bdy, dx); + dy_bdx = _cairo_int32x32_64_mul (y - b->edge.line.p1.y, bdx); + + return _cairo_int64_cmp (bdy_dx, dy_bdx); + } + case HAVE_ALL: + /* XXX try comparing (a->edge.line.p2.x - b->edge.line.p2.x) et al */ + return _cairo_int128_cmp (L, _cairo_int128_sub (B, A)); + } +#undef B +#undef A +#undef L +} + +/* + * We need to compare the x-coordinate of a line for a particular y wrt to a + * given x, without loss of precision. + * + * The x-coordinate along an edge for a given y is: + * X = A_x + (Y - A_y) * A_dx / A_dy + * + * So the inequality we wish to test is: + * A_x + (Y - A_y) * A_dx / A_dy ∘ X + * where ∘ is our inequality operator. + * + * By construction, we know that A_dy (and (Y - A_y)) are + * all positive, so we can rearrange it thus without causing a sign change: + * (Y - A_y) * A_dx ∘ (X - A_x) * A_dy + * + * Given the assumption that all the deltas fit within 32 bits, we can compute + * this comparison directly using 64 bit arithmetic. + * + * See the similar discussion for _slope_compare() and + * edges_compare_x_for_y_general(). + */ +static int +edge_compare_for_y_against_x (const cairo_bo_edge_t *a, + int32_t y, + int32_t x) +{ + int32_t adx, ady; + int32_t dx, dy; + cairo_int64_t L, R; + + if (x < a->edge.line.p1.x && x < a->edge.line.p2.x) + return 1; + if (x > a->edge.line.p1.x && x > a->edge.line.p2.x) + return -1; + + adx = a->edge.line.p2.x - a->edge.line.p1.x; + dx = x - a->edge.line.p1.x; + + if (adx == 0) + return -dx; + if (dx == 0 || (adx ^ dx) < 0) + return adx; + + dy = y - a->edge.line.p1.y; + ady = a->edge.line.p2.y - a->edge.line.p1.y; + + L = _cairo_int32x32_64_mul (dy, adx); + R = _cairo_int32x32_64_mul (dx, ady); + + return _cairo_int64_cmp (L, R); +} + +static int +edges_compare_x_for_y (const cairo_bo_edge_t *a, + const cairo_bo_edge_t *b, + int32_t y) +{ + /* If the sweep-line is currently on an end-point of a line, + * then we know its precise x value (and considering that we often need to + * compare events at end-points, this happens frequently enough to warrant + * special casing). + */ + enum { + HAVE_NEITHER = 0x0, + HAVE_AX = 0x1, + HAVE_BX = 0x2, + HAVE_BOTH = HAVE_AX | HAVE_BX + } have_ax_bx = HAVE_BOTH; + int32_t ax = 0, bx = 0; + + if (y == a->edge.line.p1.y) + ax = a->edge.line.p1.x; + else if (y == a->edge.line.p2.y) + ax = a->edge.line.p2.x; + else + have_ax_bx &= ~HAVE_AX; + + if (y == b->edge.line.p1.y) + bx = b->edge.line.p1.x; + else if (y == b->edge.line.p2.y) + bx = b->edge.line.p2.x; + else + have_ax_bx &= ~HAVE_BX; + + switch (have_ax_bx) { + default: + case HAVE_NEITHER: + return edges_compare_x_for_y_general (a, b, y); + case HAVE_AX: + return -edge_compare_for_y_against_x (b, y, ax); + case HAVE_BX: + return edge_compare_for_y_against_x (a, y, bx); + case HAVE_BOTH: + return ax - bx; + } +} + +static inline int +_line_equal (const cairo_line_t *a, const cairo_line_t *b) +{ + return (a->p1.x == b->p1.x && a->p1.y == b->p1.y && + a->p2.x == b->p2.x && a->p2.y == b->p2.y); +} + +static int +_cairo_bo_sweep_line_compare_edges (cairo_bo_sweep_line_t *sweep_line, + const cairo_bo_edge_t *a, + const cairo_bo_edge_t *b) +{ + int cmp; + + /* compare the edges if not identical */ + if (! _line_equal (&a->edge.line, &b->edge.line)) { + cmp = edges_compare_x_for_y (a, b, sweep_line->current_y); + if (cmp) + return cmp; + + /* The two edges intersect exactly at y, so fall back on slope + * comparison. We know that this compare_edges function will be + * called only when starting a new edge, (not when stopping an + * edge), so we don't have to worry about conditionally inverting + * the sense of _slope_compare. */ + cmp = _slope_compare (a, b); + if (cmp) + return cmp; + } + + /* We've got two collinear edges now. */ + return b->edge.bottom - a->edge.bottom; +} + +static inline cairo_int64_t +det32_64 (int32_t a, int32_t b, + int32_t c, int32_t d) +{ + /* det = a * d - b * c */ + return _cairo_int64_sub (_cairo_int32x32_64_mul (a, d), + _cairo_int32x32_64_mul (b, c)); +} + +static inline cairo_int128_t +det64x32_128 (cairo_int64_t a, int32_t b, + cairo_int64_t c, int32_t d) +{ + /* det = a * d - b * c */ + return _cairo_int128_sub (_cairo_int64x32_128_mul (a, d), + _cairo_int64x32_128_mul (c, b)); +} + +/* Compute the intersection of two lines as defined by two edges. The + * result is provided as a coordinate pair of 128-bit integers. + * + * Returns %CAIRO_BO_STATUS_INTERSECTION if there is an intersection or + * %CAIRO_BO_STATUS_PARALLEL if the two lines are exactly parallel. + */ +static cairo_bool_t +intersect_lines (cairo_bo_edge_t *a, + cairo_bo_edge_t *b, + cairo_bo_intersect_point_t *intersection) +{ + cairo_int64_t a_det, b_det; + + /* XXX: We're assuming here that dx and dy will still fit in 32 + * bits. That's not true in general as there could be overflow. We + * should prevent that before the tessellation algorithm begins. + * What we're doing to mitigate this is to perform clamping in + * cairo_bo_tessellate_polygon(). + */ + int32_t dx1 = a->edge.line.p1.x - a->edge.line.p2.x; + int32_t dy1 = a->edge.line.p1.y - a->edge.line.p2.y; + + int32_t dx2 = b->edge.line.p1.x - b->edge.line.p2.x; + int32_t dy2 = b->edge.line.p1.y - b->edge.line.p2.y; + + cairo_int64_t den_det; + cairo_int64_t R; + cairo_quorem64_t qr; + + den_det = det32_64 (dx1, dy1, dx2, dy2); + + /* Q: Can we determine that the lines do not intersect (within range) + * much more cheaply than computing the intersection point i.e. by + * avoiding the division? + * + * X = ax + t * adx = bx + s * bdx; + * Y = ay + t * ady = by + s * bdy; + * ∴ t * (ady*bdx - bdy*adx) = bdx * (by - ay) + bdy * (ax - bx) + * => t * L = R + * + * Therefore we can reject any intersection (under the criteria for + * valid intersection events) if: + * L^R < 0 => t < 0, or + * L t > 1 + * + * (where top/bottom must at least extend to the line endpoints). + * + * A similar substitution can be performed for s, yielding: + * s * (ady*bdx - bdy*adx) = ady * (ax - bx) - adx * (ay - by) + */ + R = det32_64 (dx2, dy2, + b->edge.line.p1.x - a->edge.line.p1.x, + b->edge.line.p1.y - a->edge.line.p1.y); + if (_cairo_int64_negative (den_det)) { + if (_cairo_int64_ge (den_det, R)) + return FALSE; + } else { + if (_cairo_int64_le (den_det, R)) + return FALSE; + } + + R = det32_64 (dy1, dx1, + a->edge.line.p1.y - b->edge.line.p1.y, + a->edge.line.p1.x - b->edge.line.p1.x); + if (_cairo_int64_negative (den_det)) { + if (_cairo_int64_ge (den_det, R)) + return FALSE; + } else { + if (_cairo_int64_le (den_det, R)) + return FALSE; + } + + /* We now know that the two lines should intersect within range. */ + + a_det = det32_64 (a->edge.line.p1.x, a->edge.line.p1.y, + a->edge.line.p2.x, a->edge.line.p2.y); + b_det = det32_64 (b->edge.line.p1.x, b->edge.line.p1.y, + b->edge.line.p2.x, b->edge.line.p2.y); + + /* x = det (a_det, dx1, b_det, dx2) / den_det */ + qr = _cairo_int_96by64_32x64_divrem (det64x32_128 (a_det, dx1, + b_det, dx2), + den_det); + if (_cairo_int64_eq (qr.rem, den_det)) + return FALSE; +#if 0 + intersection->x.exactness = _cairo_int64_is_zero (qr.rem) ? EXACT : INEXACT; +#else + intersection->x.exactness = EXACT; + if (! _cairo_int64_is_zero (qr.rem)) { + if (_cairo_int64_negative (den_det) ^ _cairo_int64_negative (qr.rem)) + qr.rem = _cairo_int64_negate (qr.rem); + qr.rem = _cairo_int64_mul (qr.rem, _cairo_int32_to_int64 (2)); + if (_cairo_int64_ge (qr.rem, den_det)) { + qr.quo = _cairo_int64_add (qr.quo, + _cairo_int32_to_int64 (_cairo_int64_negative (qr.quo) ? -1 : 1)); + } else + intersection->x.exactness = INEXACT; + } +#endif + intersection->x.ordinate = _cairo_int64_to_int32 (qr.quo); + + /* y = det (a_det, dy1, b_det, dy2) / den_det */ + qr = _cairo_int_96by64_32x64_divrem (det64x32_128 (a_det, dy1, + b_det, dy2), + den_det); + if (_cairo_int64_eq (qr.rem, den_det)) + return FALSE; +#if 0 + intersection->y.exactness = _cairo_int64_is_zero (qr.rem) ? EXACT : INEXACT; +#else + intersection->y.exactness = EXACT; + if (! _cairo_int64_is_zero (qr.rem)) { + if (_cairo_int64_negative (den_det) ^ _cairo_int64_negative (qr.rem)) + qr.rem = _cairo_int64_negate (qr.rem); + qr.rem = _cairo_int64_mul (qr.rem, _cairo_int32_to_int64 (2)); + if (_cairo_int64_ge (qr.rem, den_det)) { + qr.quo = _cairo_int64_add (qr.quo, + _cairo_int32_to_int64 (_cairo_int64_negative (qr.quo) ? -1 : 1)); + } else + intersection->y.exactness = INEXACT; + } +#endif + intersection->y.ordinate = _cairo_int64_to_int32 (qr.quo); + + return TRUE; +} + +static int +_cairo_bo_intersect_ordinate_32_compare (cairo_bo_intersect_ordinate_t a, + int32_t b) +{ + /* First compare the quotient */ + if (a.ordinate > b) + return +1; + if (a.ordinate < b) + return -1; + /* With quotient identical, if remainder is 0 then compare equal */ + /* Otherwise, the non-zero remainder makes a > b */ + return INEXACT == a.exactness; +} + +/* Does the given edge contain the given point. The point must already + * be known to be contained within the line determined by the edge, + * (most likely the point results from an intersection of this edge + * with another). + * + * If we had exact arithmetic, then this function would simply be a + * matter of examining whether the y value of the point lies within + * the range of y values of the edge. But since intersection points + * are not exact due to being rounded to the nearest integer within + * the available precision, we must also examine the x value of the + * point. + * + * The definition of "contains" here is that the given intersection + * point will be seen by the sweep line after the start event for the + * given edge and before the stop event for the edge. See the comments + * in the implementation for more details. + */ +static cairo_bool_t +_cairo_bo_edge_contains_intersect_point (cairo_bo_edge_t *edge, + cairo_bo_intersect_point_t *point) +{ + int cmp_top, cmp_bottom; + + /* XXX: When running the actual algorithm, we don't actually need to + * compare against edge->top at all here, since any intersection above + * top is eliminated early via a slope comparison. We're leaving these + * here for now only for the sake of the quadratic-time intersection + * finder which needs them. + */ + + cmp_top = _cairo_bo_intersect_ordinate_32_compare (point->y, + edge->edge.top); + cmp_bottom = _cairo_bo_intersect_ordinate_32_compare (point->y, + edge->edge.bottom); + + if (cmp_top < 0 || cmp_bottom > 0) + { + return FALSE; + } + + if (cmp_top > 0 && cmp_bottom < 0) + { + return TRUE; + } + + /* At this stage, the point lies on the same y value as either + * edge->top or edge->bottom, so we have to examine the x value in + * order to properly determine containment. */ + + /* If the y value of the point is the same as the y value of the + * top of the edge, then the x value of the point must be greater + * to be considered as inside the edge. Similarly, if the y value + * of the point is the same as the y value of the bottom of the + * edge, then the x value of the point must be less to be + * considered as inside. */ + + if (cmp_top == 0) { + cairo_fixed_t top_x; + + top_x = _line_compute_intersection_x_for_y (&edge->edge.line, + edge->edge.top); + return _cairo_bo_intersect_ordinate_32_compare (point->x, top_x) > 0; + } else { /* cmp_bottom == 0 */ + cairo_fixed_t bot_x; + + bot_x = _line_compute_intersection_x_for_y (&edge->edge.line, + edge->edge.bottom); + return _cairo_bo_intersect_ordinate_32_compare (point->x, bot_x) < 0; + } +} + +/* Compute the intersection of two edges. The result is provided as a + * coordinate pair of 128-bit integers. + * + * Returns %CAIRO_BO_STATUS_INTERSECTION if there is an intersection + * that is within both edges, %CAIRO_BO_STATUS_NO_INTERSECTION if the + * intersection of the lines defined by the edges occurs outside of + * one or both edges, and %CAIRO_BO_STATUS_PARALLEL if the two edges + * are exactly parallel. + * + * Note that when determining if a candidate intersection is "inside" + * an edge, we consider both the infinitesimal shortening and the + * infinitesimal tilt rules described by John Hobby. Specifically, if + * the intersection is exactly the same as an edge point, it is + * effectively outside (no intersection is returned). Also, if the + * intersection point has the same + */ +static cairo_bool_t +_cairo_bo_edge_intersect (cairo_bo_edge_t *a, + cairo_bo_edge_t *b, + cairo_bo_point32_t *intersection) +{ + cairo_bo_intersect_point_t quorem; + + if (! intersect_lines (a, b, &quorem)) + return FALSE; + + if (! _cairo_bo_edge_contains_intersect_point (a, &quorem)) + return FALSE; + + if (! _cairo_bo_edge_contains_intersect_point (b, &quorem)) + return FALSE; + + /* Now that we've correctly compared the intersection point and + * determined that it lies within the edge, then we know that we + * no longer need any more bits of storage for the intersection + * than we do for our edge coordinates. We also no longer need the + * remainder from the division. */ + intersection->x = quorem.x.ordinate; + intersection->y = quorem.y.ordinate; + + return TRUE; +} + +static inline int +cairo_bo_event_compare (const cairo_bo_event_t *a, + const cairo_bo_event_t *b) +{ + int cmp; + + cmp = _cairo_bo_point32_compare (&a->point, &b->point); + if (cmp) + return cmp; + + cmp = a->type - b->type; + if (cmp) + return cmp; + + return a - b; +} + +static inline void +_pqueue_init (pqueue_t *pq) +{ + pq->max_size = ARRAY_LENGTH (pq->elements_embedded); + pq->size = 0; + + pq->elements = pq->elements_embedded; +} + +static inline void +_pqueue_fini (pqueue_t *pq) +{ + if (pq->elements != pq->elements_embedded) + free (pq->elements); +} + +static cairo_status_t +_pqueue_grow (pqueue_t *pq) +{ + cairo_bo_event_t **new_elements; + pq->max_size *= 2; + + if (pq->elements == pq->elements_embedded) { + new_elements = _cairo_malloc_ab (pq->max_size, + sizeof (cairo_bo_event_t *)); + if (unlikely (new_elements == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + memcpy (new_elements, pq->elements_embedded, + sizeof (pq->elements_embedded)); + } else { + new_elements = _cairo_realloc_ab (pq->elements, + pq->max_size, + sizeof (cairo_bo_event_t *)); + if (unlikely (new_elements == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + pq->elements = new_elements; + return CAIRO_STATUS_SUCCESS; +} + +static inline cairo_status_t +_pqueue_push (pqueue_t *pq, cairo_bo_event_t *event) +{ + cairo_bo_event_t **elements; + int i, parent; + + if (unlikely (pq->size + 1 == pq->max_size)) { + cairo_status_t status; + + status = _pqueue_grow (pq); + if (unlikely (status)) + return status; + } + + elements = pq->elements; + + for (i = ++pq->size; + i != PQ_FIRST_ENTRY && + cairo_bo_event_compare (event, + elements[parent = PQ_PARENT_INDEX (i)]) < 0; + i = parent) + { + elements[i] = elements[parent]; + } + + elements[i] = event; + + return CAIRO_STATUS_SUCCESS; +} + +static inline void +_pqueue_pop (pqueue_t *pq) +{ + cairo_bo_event_t **elements = pq->elements; + cairo_bo_event_t *tail; + int child, i; + + tail = elements[pq->size--]; + if (pq->size == 0) { + elements[PQ_FIRST_ENTRY] = NULL; + return; + } + + for (i = PQ_FIRST_ENTRY; + (child = PQ_LEFT_CHILD_INDEX (i)) <= pq->size; + i = child) + { + if (child != pq->size && + cairo_bo_event_compare (elements[child+1], + elements[child]) < 0) + { + child++; + } + + if (cairo_bo_event_compare (elements[child], tail) >= 0) + break; + + elements[i] = elements[child]; + } + elements[i] = tail; +} + +static inline cairo_status_t +_cairo_bo_event_queue_insert (cairo_bo_event_queue_t *queue, + cairo_bo_event_type_t type, + cairo_bo_edge_t *e1, + cairo_bo_edge_t *e2, + const cairo_point_t *point) +{ + cairo_bo_queue_event_t *event; + + event = _cairo_freepool_alloc (&queue->pool); + if (unlikely (event == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + event->type = type; + event->e1 = e1; + event->e2 = e2; + event->point = *point; + + return _pqueue_push (&queue->pqueue, (cairo_bo_event_t *) event); +} + +static void +_cairo_bo_event_queue_delete (cairo_bo_event_queue_t *queue, + cairo_bo_event_t *event) +{ + _cairo_freepool_free (&queue->pool, event); +} + +static cairo_bo_event_t * +_cairo_bo_event_dequeue (cairo_bo_event_queue_t *event_queue) +{ + cairo_bo_event_t *event, *cmp; + + event = event_queue->pqueue.elements[PQ_FIRST_ENTRY]; + cmp = *event_queue->start_events; + if (event == NULL || + (cmp != NULL && cairo_bo_event_compare (cmp, event) < 0)) + { + event = cmp; + event_queue->start_events++; + } + else + { + _pqueue_pop (&event_queue->pqueue); + } + + return event; +} + +CAIRO_COMBSORT_DECLARE (_cairo_bo_event_queue_sort, + cairo_bo_event_t *, + cairo_bo_event_compare) + +static void +_cairo_bo_event_queue_init (cairo_bo_event_queue_t *event_queue, + cairo_bo_event_t **start_events, + int num_events) +{ + _cairo_bo_event_queue_sort (start_events, num_events); + start_events[num_events] = NULL; + + event_queue->start_events = start_events; + + _cairo_freepool_init (&event_queue->pool, + sizeof (cairo_bo_queue_event_t)); + _pqueue_init (&event_queue->pqueue); + event_queue->pqueue.elements[PQ_FIRST_ENTRY] = NULL; +} + +static cairo_status_t +_cairo_bo_event_queue_insert_stop (cairo_bo_event_queue_t *event_queue, + cairo_bo_edge_t *edge) +{ + cairo_bo_point32_t point; + + point.y = edge->edge.bottom; + point.x = _line_compute_intersection_x_for_y (&edge->edge.line, + point.y); + return _cairo_bo_event_queue_insert (event_queue, + CAIRO_BO_EVENT_TYPE_STOP, + edge, NULL, + &point); +} + +static void +_cairo_bo_event_queue_fini (cairo_bo_event_queue_t *event_queue) +{ + _pqueue_fini (&event_queue->pqueue); + _cairo_freepool_fini (&event_queue->pool); +} + +static inline cairo_status_t +_cairo_bo_event_queue_insert_if_intersect_below_current_y (cairo_bo_event_queue_t *event_queue, + cairo_bo_edge_t *left, + cairo_bo_edge_t *right) +{ + cairo_bo_point32_t intersection; + + if (_line_equal (&left->edge.line, &right->edge.line)) + return CAIRO_STATUS_SUCCESS; + + /* The names "left" and "right" here are correct descriptions of + * the order of the two edges within the active edge list. So if a + * slope comparison also puts left less than right, then we know + * that the intersection of these two segments has already + * occurred before the current sweep line position. */ + if (_slope_compare (left, right) <= 0) + return CAIRO_STATUS_SUCCESS; + + if (! _cairo_bo_edge_intersect (left, right, &intersection)) + return CAIRO_STATUS_SUCCESS; + + return _cairo_bo_event_queue_insert (event_queue, + CAIRO_BO_EVENT_TYPE_INTERSECTION, + left, right, + &intersection); +} + +static void +_cairo_bo_sweep_line_init (cairo_bo_sweep_line_t *sweep_line) +{ + sweep_line->head = NULL; + sweep_line->current_y = INT32_MIN; + sweep_line->current_edge = NULL; +} + +static cairo_status_t +_cairo_bo_sweep_line_insert (cairo_bo_sweep_line_t *sweep_line, + cairo_bo_edge_t *edge) +{ + if (sweep_line->current_edge != NULL) { + cairo_bo_edge_t *prev, *next; + int cmp; + + cmp = _cairo_bo_sweep_line_compare_edges (sweep_line, + sweep_line->current_edge, + edge); + if (cmp < 0) { + prev = sweep_line->current_edge; + next = prev->next; + while (next != NULL && + _cairo_bo_sweep_line_compare_edges (sweep_line, + next, edge) < 0) + { + prev = next, next = prev->next; + } + + prev->next = edge; + edge->prev = prev; + edge->next = next; + if (next != NULL) + next->prev = edge; + } else if (cmp > 0) { + next = sweep_line->current_edge; + prev = next->prev; + while (prev != NULL && + _cairo_bo_sweep_line_compare_edges (sweep_line, + prev, edge) > 0) + { + next = prev, prev = next->prev; + } + + next->prev = edge; + edge->next = next; + edge->prev = prev; + if (prev != NULL) + prev->next = edge; + else + sweep_line->head = edge; + } else { + prev = sweep_line->current_edge; + edge->prev = prev; + edge->next = prev->next; + if (prev->next != NULL) + prev->next->prev = edge; + prev->next = edge; + } + } else { + sweep_line->head = edge; + } + + sweep_line->current_edge = edge; + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_bo_sweep_line_delete (cairo_bo_sweep_line_t *sweep_line, + cairo_bo_edge_t *edge) +{ + if (edge->prev != NULL) + edge->prev->next = edge->next; + else + sweep_line->head = edge->next; + + if (edge->next != NULL) + edge->next->prev = edge->prev; + + if (sweep_line->current_edge == edge) + sweep_line->current_edge = edge->prev ? edge->prev : edge->next; +} + +static void +_cairo_bo_sweep_line_swap (cairo_bo_sweep_line_t *sweep_line, + cairo_bo_edge_t *left, + cairo_bo_edge_t *right) +{ + if (left->prev != NULL) + left->prev->next = right; + else + sweep_line->head = right; + + if (right->next != NULL) + right->next->prev = left; + + left->next = right->next; + right->next = left; + + right->prev = left->prev; + left->prev = right; +} + +static inline cairo_bool_t +edges_colinear (const cairo_bo_edge_t *a, const cairo_bo_edge_t *b) +{ + if (_line_equal (&a->edge.line, &b->edge.line)) + return TRUE; + + if (_slope_compare (a, b)) + return FALSE; + + /* The choice of y is not truly arbitrary since we must guarantee that it + * is greater than the start of either line. + */ + if (a->edge.line.p1.y == b->edge.line.p1.y) { + return a->edge.line.p1.x == b->edge.line.p1.x; + } else if (a->edge.line.p2.y == b->edge.line.p2.y) { + return a->edge.line.p2.x == b->edge.line.p2.x; + } else if (a->edge.line.p1.y < b->edge.line.p1.y) { + return edge_compare_for_y_against_x (b, + a->edge.line.p1.y, + a->edge.line.p1.x) == 0; + } else { + return edge_compare_for_y_against_x (a, + b->edge.line.p1.y, + b->edge.line.p1.x) == 0; + } +} + +static void +_cairo_bo_edge_end (cairo_bo_edge_t *left, + int32_t bot, + cairo_polygon_t *polygon) +{ + cairo_bo_deferred_t *d = &left->deferred; + + if (likely (d->top < bot)) { + _cairo_polygon_add_line (polygon, + &left->edge.line, + d->top, bot, + 1); + _cairo_polygon_add_line (polygon, + &d->right->edge.line, + d->top, bot, + -1); + } + + d->right = NULL; +} + + +static inline void +_cairo_bo_edge_start_or_continue (cairo_bo_edge_t *left, + cairo_bo_edge_t *right, + int top, + cairo_polygon_t *polygon) +{ + if (left->deferred.right == right) + return; + + if (left->deferred.right != NULL) { + if (right != NULL && edges_colinear (left->deferred.right, right)) + { + /* continuation on right, so just swap edges */ + left->deferred.right = right; + return; + } + + _cairo_bo_edge_end (left, top, polygon); + } + + if (right != NULL && ! edges_colinear (left, right)) { + left->deferred.top = top; + left->deferred.right = right; + } +} + +static inline void +_active_edges_to_polygon (cairo_bo_edge_t *left, + int32_t top, + cairo_fill_rule_t fill_rule, + cairo_polygon_t *polygon) +{ + cairo_bo_edge_t *right; + unsigned int mask; + + if (fill_rule == CAIRO_FILL_RULE_WINDING) + mask = ~0; + else + mask = 1; + + while (left != NULL) { + int in_out = left->edge.dir; + + right = left->next; + if (left->deferred.right == NULL) { + while (right != NULL && right->deferred.right == NULL) + right = right->next; + + if (right != NULL && edges_colinear (left, right)) { + /* continuation on left */ + left->deferred = right->deferred; + right->deferred.right = NULL; + } + } + + right = left->next; + while (right != NULL) { + if (right->deferred.right != NULL) + _cairo_bo_edge_end (right, top, polygon); + + in_out += right->edge.dir; + if ((in_out & mask) == 0) { + /* skip co-linear edges */ + if (right->next == NULL || !edges_colinear (right, right->next)) + break; + } + + right = right->next; + } + + _cairo_bo_edge_start_or_continue (left, right, top, polygon); + + left = right; + if (left != NULL) + left = left->next; + } +} + + +static cairo_status_t +_cairo_bentley_ottmann_tessellate_bo_edges (cairo_bo_event_t **start_events, + int num_events, + cairo_fill_rule_t fill_rule, + cairo_polygon_t *polygon) +{ + cairo_status_t status = CAIRO_STATUS_SUCCESS; /* silence compiler */ + cairo_bo_event_queue_t event_queue; + cairo_bo_sweep_line_t sweep_line; + cairo_bo_event_t *event; + cairo_bo_edge_t *left, *right; + cairo_bo_edge_t *e1, *e2; + + _cairo_bo_event_queue_init (&event_queue, start_events, num_events); + _cairo_bo_sweep_line_init (&sweep_line); + + while ((event = _cairo_bo_event_dequeue (&event_queue))) { + if (event->point.y != sweep_line.current_y) { + _active_edges_to_polygon (sweep_line.head, + sweep_line.current_y, + fill_rule, polygon); + + sweep_line.current_y = event->point.y; + } + + switch (event->type) { + case CAIRO_BO_EVENT_TYPE_START: + e1 = &((cairo_bo_start_event_t *) event)->edge; + + status = _cairo_bo_sweep_line_insert (&sweep_line, e1); + if (unlikely (status)) + goto unwind; + + status = _cairo_bo_event_queue_insert_stop (&event_queue, e1); + if (unlikely (status)) + goto unwind; + + left = e1->prev; + right = e1->next; + + if (left != NULL) { + status = _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, left, e1); + if (unlikely (status)) + goto unwind; + } + + if (right != NULL) { + status = _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, e1, right); + if (unlikely (status)) + goto unwind; + } + + break; + + case CAIRO_BO_EVENT_TYPE_STOP: + e1 = ((cairo_bo_queue_event_t *) event)->e1; + _cairo_bo_event_queue_delete (&event_queue, event); + + left = e1->prev; + right = e1->next; + + _cairo_bo_sweep_line_delete (&sweep_line, e1); + + if (e1->deferred.right != NULL) + _cairo_bo_edge_end (e1, e1->edge.bottom, polygon); + + if (left != NULL && right != NULL) { + status = _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, left, right); + if (unlikely (status)) + goto unwind; + } + + break; + + case CAIRO_BO_EVENT_TYPE_INTERSECTION: + e1 = ((cairo_bo_queue_event_t *) event)->e1; + e2 = ((cairo_bo_queue_event_t *) event)->e2; + _cairo_bo_event_queue_delete (&event_queue, event); + + /* skip this intersection if its edges are not adjacent */ + if (e2 != e1->next) + break; + + left = e1->prev; + right = e2->next; + + _cairo_bo_sweep_line_swap (&sweep_line, e1, e2); + + /* after the swap e2 is left of e1 */ + + if (left != NULL) { + status = _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, left, e2); + if (unlikely (status)) + goto unwind; + } + + if (right != NULL) { + status = _cairo_bo_event_queue_insert_if_intersect_below_current_y (&event_queue, e1, right); + if (unlikely (status)) + goto unwind; + } + + break; + } + } + + unwind: + _cairo_bo_event_queue_fini (&event_queue); + + return status; +} + +cairo_status_t +_cairo_polygon_reduce (cairo_polygon_t *polygon, + cairo_fill_rule_t fill_rule) +{ + cairo_status_t status; + cairo_bo_start_event_t stack_events[CAIRO_STACK_ARRAY_LENGTH (cairo_bo_start_event_t)]; + cairo_bo_start_event_t *events; + cairo_bo_event_t *stack_event_ptrs[ARRAY_LENGTH (stack_events) + 1]; + cairo_bo_event_t **event_ptrs; + int num_limits; + int num_events; + int i; + + num_events = polygon->num_edges; + if (unlikely (0 == num_events)) + return CAIRO_STATUS_SUCCESS; + + if (DEBUG_POLYGON) { + FILE *file = fopen ("reduce_in.txt", "w"); + _cairo_debug_print_polygon (file, polygon); + fclose (file); + } + + events = stack_events; + event_ptrs = stack_event_ptrs; + if (num_events > ARRAY_LENGTH (stack_events)) { + events = _cairo_malloc_ab_plus_c (num_events, + sizeof (cairo_bo_start_event_t) + + sizeof (cairo_bo_event_t *), + sizeof (cairo_bo_event_t *)); + if (unlikely (events == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + event_ptrs = (cairo_bo_event_t **) (events + num_events); + } + + for (i = 0; i < num_events; i++) { + event_ptrs[i] = (cairo_bo_event_t *) &events[i]; + + events[i].type = CAIRO_BO_EVENT_TYPE_START; + events[i].point.y = polygon->edges[i].top; + events[i].point.x = + _line_compute_intersection_x_for_y (&polygon->edges[i].line, + events[i].point.y); + + events[i].edge.edge = polygon->edges[i]; + events[i].edge.deferred.right = NULL; + events[i].edge.prev = NULL; + events[i].edge.next = NULL; + } + + num_limits = polygon->num_limits; polygon->num_limits = 0; + polygon->num_edges = 0; + + status = _cairo_bentley_ottmann_tessellate_bo_edges (event_ptrs, + num_events, + fill_rule, + polygon); + polygon->num_limits = num_limits; + + if (events != stack_events) + free (events); + + if (DEBUG_POLYGON) { + FILE *file = fopen ("reduce_out.txt", "w"); + _cairo_debug_print_polygon (file, polygon); + fclose (file); + } + + return status; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-polygon.c b/local/recipes/libs/cairo/source/src/cairo-polygon.c new file mode 100644 index 0000000000..0e0b813285 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-polygon.c @@ -0,0 +1,608 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + */ + +#include "cairoint.h" + +#include "cairo-boxes-private.h" +#include "cairo-contour-private.h" +#include "cairo-error-private.h" + +#define DEBUG_POLYGON 0 + +#if DEBUG_POLYGON && !NDEBUG +static void +assert_last_edge_is_valid(cairo_polygon_t *polygon, + const cairo_box_t *limit) +{ + cairo_edge_t *edge; + cairo_fixed_t x; + + edge = &polygon->edges[polygon->num_edges-1]; + + assert (edge->bottom > edge->top); + assert (edge->top >= limit->p1.y); + assert (edge->bottom <= limit->p2.y); + + x = _cairo_edge_compute_intersection_x_for_y (&edge->line.p1, + &edge->line.p2, + edge->top); + assert (x >= limit->p1.x); + assert (x <= limit->p2.x); + + x = _cairo_edge_compute_intersection_x_for_y (&edge->line.p1, + &edge->line.p2, + edge->bottom); + assert (x >= limit->p1.x); + assert (x <= limit->p2.x); +} +#else +#define assert_last_edge_is_valid(p, l) +#endif + +static void +_cairo_polygon_add_edge (cairo_polygon_t *polygon, + const cairo_point_t *p1, + const cairo_point_t *p2, + int dir); + +void +_cairo_polygon_limit (cairo_polygon_t *polygon, + const cairo_box_t *limits, + int num_limits) +{ + int n; + + polygon->limits = limits; + polygon->num_limits = num_limits; + + if (polygon->num_limits) { + polygon->limit = limits[0]; + for (n = 1; n < num_limits; n++) { + if (limits[n].p1.x < polygon->limit.p1.x) + polygon->limit.p1.x = limits[n].p1.x; + + if (limits[n].p1.y < polygon->limit.p1.y) + polygon->limit.p1.y = limits[n].p1.y; + + if (limits[n].p2.x > polygon->limit.p2.x) + polygon->limit.p2.x = limits[n].p2.x; + + if (limits[n].p2.y > polygon->limit.p2.y) + polygon->limit.p2.y = limits[n].p2.y; + } + } +} + +void +_cairo_polygon_limit_to_clip (cairo_polygon_t *polygon, + const cairo_clip_t *clip) +{ + if (clip) + _cairo_polygon_limit (polygon, clip->boxes, clip->num_boxes); + else + _cairo_polygon_limit (polygon, 0, 0); +} + +void +_cairo_polygon_init (cairo_polygon_t *polygon, + const cairo_box_t *limits, + int num_limits) +{ + VG (VALGRIND_MAKE_MEM_UNDEFINED (polygon, sizeof (cairo_polygon_t))); + + polygon->status = CAIRO_STATUS_SUCCESS; + + polygon->num_edges = 0; + + polygon->edges = polygon->edges_embedded; + polygon->edges_size = ARRAY_LENGTH (polygon->edges_embedded); + + polygon->extents.p1.x = polygon->extents.p1.y = INT32_MAX; + polygon->extents.p2.x = polygon->extents.p2.y = INT32_MIN; + + _cairo_polygon_limit (polygon, limits, num_limits); +} + +void +_cairo_polygon_init_with_clip (cairo_polygon_t *polygon, + const cairo_clip_t *clip) +{ + if (clip) + _cairo_polygon_init (polygon, clip->boxes, clip->num_boxes); + else + _cairo_polygon_init (polygon, 0, 0); +} + +cairo_status_t +_cairo_polygon_init_boxes (cairo_polygon_t *polygon, + const cairo_boxes_t *boxes) +{ + const struct _cairo_boxes_chunk *chunk; + int i; + + VG (VALGRIND_MAKE_MEM_UNDEFINED (polygon, sizeof (cairo_polygon_t))); + + polygon->status = CAIRO_STATUS_SUCCESS; + + polygon->num_edges = 0; + + polygon->edges = polygon->edges_embedded; + polygon->edges_size = ARRAY_LENGTH (polygon->edges_embedded); + if (boxes->num_boxes > ARRAY_LENGTH (polygon->edges_embedded)/2) { + polygon->edges_size = 2 * boxes->num_boxes; + polygon->edges = _cairo_malloc_ab (polygon->edges_size, + 2*sizeof(cairo_edge_t)); + if (unlikely (polygon->edges == NULL)) + return polygon->status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + polygon->extents.p1.x = polygon->extents.p1.y = INT32_MAX; + polygon->extents.p2.x = polygon->extents.p2.y = INT32_MIN; + + polygon->limits = NULL; + polygon->num_limits = 0; + + for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { + for (i = 0; i < chunk->count; i++) { + cairo_point_t p1, p2; + + p1 = chunk->base[i].p1; + p2.x = p1.x; + p2.y = chunk->base[i].p2.y; + _cairo_polygon_add_edge (polygon, &p1, &p2, 1); + + p1 = chunk->base[i].p2; + p2.x = p1.x; + p2.y = chunk->base[i].p1.y; + _cairo_polygon_add_edge (polygon, &p1, &p2, 1); + } + } + + return polygon->status; +} + +cairo_status_t +_cairo_polygon_init_box_array (cairo_polygon_t *polygon, + cairo_box_t *boxes, + int num_boxes) +{ + int i; + + VG (VALGRIND_MAKE_MEM_UNDEFINED (polygon, sizeof (cairo_polygon_t))); + + polygon->status = CAIRO_STATUS_SUCCESS; + + polygon->num_edges = 0; + + polygon->edges = polygon->edges_embedded; + polygon->edges_size = ARRAY_LENGTH (polygon->edges_embedded); + if (num_boxes > ARRAY_LENGTH (polygon->edges_embedded)/2) { + polygon->edges_size = 2 * num_boxes; + polygon->edges = _cairo_malloc_ab (polygon->edges_size, + 2*sizeof(cairo_edge_t)); + if (unlikely (polygon->edges == NULL)) + return polygon->status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + polygon->extents.p1.x = polygon->extents.p1.y = INT32_MAX; + polygon->extents.p2.x = polygon->extents.p2.y = INT32_MIN; + + polygon->limits = NULL; + polygon->num_limits = 0; + + for (i = 0; i < num_boxes; i++) { + cairo_point_t p1, p2; + + p1 = boxes[i].p1; + p2.x = p1.x; + p2.y = boxes[i].p2.y; + _cairo_polygon_add_edge (polygon, &p1, &p2, 1); + + p1 = boxes[i].p2; + p2.x = p1.x; + p2.y = boxes[i].p1.y; + _cairo_polygon_add_edge (polygon, &p1, &p2, 1); + } + + return polygon->status; +} + + +void +_cairo_polygon_fini (cairo_polygon_t *polygon) +{ + if (polygon->edges != polygon->edges_embedded) + free (polygon->edges); + + VG (VALGRIND_MAKE_MEM_UNDEFINED (polygon, sizeof (cairo_polygon_t))); +} + +/* make room for at least one more edge */ +static cairo_bool_t +_cairo_polygon_grow (cairo_polygon_t *polygon) +{ + cairo_edge_t *new_edges; + int old_size = polygon->edges_size; + int new_size = 4 * old_size; + + if (CAIRO_INJECT_FAULT ()) { + polygon->status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + return FALSE; + } + + if (polygon->edges == polygon->edges_embedded) { + new_edges = _cairo_malloc_ab (new_size, sizeof (cairo_edge_t)); + if (new_edges != NULL) + memcpy (new_edges, polygon->edges, old_size * sizeof (cairo_edge_t)); + } else { + new_edges = _cairo_realloc_ab (polygon->edges, + new_size, sizeof (cairo_edge_t)); + } + + if (unlikely (new_edges == NULL)) { + polygon->status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + return FALSE; + } + + polygon->edges = new_edges; + polygon->edges_size = new_size; + + return TRUE; +} + +static void +_add_edge (cairo_polygon_t *polygon, + const cairo_point_t *p1, + const cairo_point_t *p2, + int top, int bottom, + int dir) +{ + cairo_edge_t *edge; + + assert (top < bottom); + + if (unlikely (polygon->num_edges == polygon->edges_size)) { + if (! _cairo_polygon_grow (polygon)) + return; + } + + edge = &polygon->edges[polygon->num_edges++]; + edge->line.p1 = *p1; + edge->line.p2 = *p2; + edge->top = top; + edge->bottom = bottom; + edge->dir = dir; + + if (top < polygon->extents.p1.y) + polygon->extents.p1.y = top; + if (bottom > polygon->extents.p2.y) + polygon->extents.p2.y = bottom; + + if (p1->x < polygon->extents.p1.x || p1->x > polygon->extents.p2.x) { + cairo_fixed_t x = p1->x; + if (top != p1->y) + x = _cairo_edge_compute_intersection_x_for_y (p1, p2, top); + if (x < polygon->extents.p1.x) + polygon->extents.p1.x = x; + if (x > polygon->extents.p2.x) + polygon->extents.p2.x = x; + } + + if (p2->x < polygon->extents.p1.x || p2->x > polygon->extents.p2.x) { + cairo_fixed_t x = p2->x; + if (bottom != p2->y) + x = _cairo_edge_compute_intersection_x_for_y (p1, p2, bottom); + if (x < polygon->extents.p1.x) + polygon->extents.p1.x = x; + if (x > polygon->extents.p2.x) + polygon->extents.p2.x = x; + } +} + +static void +_add_clipped_edge (cairo_polygon_t *polygon, + const cairo_point_t *p1, + const cairo_point_t *p2, + const int top, const int bottom, + const int dir) +{ + cairo_point_t bot_left, top_right; + cairo_fixed_t top_y, bot_y; + int n; + + for (n = 0; n < polygon->num_limits; n++) { + const cairo_box_t *limits = &polygon->limits[n]; + cairo_fixed_t pleft, pright; + + if (top >= limits->p2.y) + continue; + if (bottom <= limits->p1.y) + continue; + + bot_left.x = limits->p1.x; + bot_left.y = limits->p2.y; + + top_right.x = limits->p2.x; + top_right.y = limits->p1.y; + + /* The useful region */ + top_y = MAX (top, limits->p1.y); + bot_y = MIN (bottom, limits->p2.y); + + /* The projection of the edge on the horizontal axis */ + pleft = MIN (p1->x, p2->x); + pright = MAX (p1->x, p2->x); + + if (limits->p1.x <= pleft && pright <= limits->p2.x) { + /* Projection of the edge completely contained in the box: + * clip vertically by restricting top and bottom */ + + _add_edge (polygon, p1, p2, top_y, bot_y, dir); + assert_last_edge_is_valid (polygon, limits); + } else if (pright <= limits->p1.x) { + /* Projection of the edge to the left of the box: + * replace with the left side of the box (clipped top/bottom) */ + + _add_edge (polygon, &limits->p1, &bot_left, top_y, bot_y, dir); + assert_last_edge_is_valid (polygon, limits); + } else if (limits->p2.x <= pleft) { + /* Projection of the edge to the right of the box: + * replace with the right side of the box (clipped top/bottom) */ + + _add_edge (polygon, &top_right, &limits->p2, top_y, bot_y, dir); + assert_last_edge_is_valid (polygon, limits); + } else { + /* The edge and the box intersect in a generic way */ + cairo_fixed_t left_y, right_y; + cairo_bool_t top_left_to_bottom_right; + + /* + * The edge intersects the lines corresponding to the left + * and right sides of the limit box at left_y and right_y, + * but we need to add edges for the range from top_y to + * bot_y. + * + * For both intersections, there are three cases: + * + * 1) It is outside the vertical range of the limit + * box. In this case we can simply further clip the + * edge we will be emitting (i.e. restrict its + * top/bottom limits to those of the limit box). + * + * 2) It is inside the vertical range of the limit + * box. In this case, we need to add the vertical edge + * connecting the correct vertex to the intersection, + * in order to preserve the winding count. + * + * 3) It is exactly on the box. In this case, do nothing. + * + * These operations restrict the active range (stored in + * top_y/bot_y) so that the p1-p2 edge is completely + * inside the box if it is clipped to this vertical range. + */ + + top_left_to_bottom_right = (p1->x <= p2->x) == (p1->y <= p2->y); + if (top_left_to_bottom_right) { + if (pleft >= limits->p1.x) { + left_y = top_y; + } else { + left_y = _cairo_edge_compute_intersection_y_for_x (p1, p2, + limits->p1.x); + if (_cairo_edge_compute_intersection_x_for_y (p1, p2, left_y) < limits->p1.x) + left_y++; + } + + left_y = MIN (left_y, bot_y); + if (top_y < left_y) { + _add_edge (polygon, &limits->p1, &bot_left, + top_y, left_y, dir); + assert_last_edge_is_valid (polygon, limits); + top_y = left_y; + } + + if (pright <= limits->p2.x) { + right_y = bot_y; + } else { + right_y = _cairo_edge_compute_intersection_y_for_x (p1, p2, + limits->p2.x); + if (_cairo_edge_compute_intersection_x_for_y (p1, p2, right_y) > limits->p2.x) + right_y--; + } + + right_y = MAX (right_y, top_y); + if (bot_y > right_y) { + _add_edge (polygon, &top_right, &limits->p2, + right_y, bot_y, dir); + assert_last_edge_is_valid (polygon, limits); + bot_y = right_y; + } + } else { + if (pright <= limits->p2.x) { + right_y = top_y; + } else { + right_y = _cairo_edge_compute_intersection_y_for_x (p1, p2, + limits->p2.x); + if (_cairo_edge_compute_intersection_x_for_y (p1, p2, right_y) > limits->p2.x) + right_y++; + } + + right_y = MIN (right_y, bot_y); + if (top_y < right_y) { + _add_edge (polygon, &top_right, &limits->p2, + top_y, right_y, dir); + assert_last_edge_is_valid (polygon, limits); + top_y = right_y; + } + + if (pleft >= limits->p1.x) { + left_y = bot_y; + } else { + left_y = _cairo_edge_compute_intersection_y_for_x (p1, p2, + limits->p1.x); + if (_cairo_edge_compute_intersection_x_for_y (p1, p2, left_y) < limits->p1.x) + left_y--; + } + + left_y = MAX (left_y, top_y); + if (bot_y > left_y) { + _add_edge (polygon, &limits->p1, &bot_left, + left_y, bot_y, dir); + assert_last_edge_is_valid (polygon, limits); + bot_y = left_y; + } + } + + if (top_y != bot_y) { + _add_edge (polygon, p1, p2, top_y, bot_y, dir); + assert_last_edge_is_valid (polygon, limits); + } + } + } +} + +static void +_cairo_polygon_add_edge (cairo_polygon_t *polygon, + const cairo_point_t *p1, + const cairo_point_t *p2, + int dir) +{ + /* drop horizontal edges */ + if (p1->y == p2->y) + return; + + if (p1->y > p2->y) { + const cairo_point_t *t; + t = p1, p1 = p2, p2 = t; + dir = -dir; + } + + if (polygon->num_limits) { + if (p2->y <= polygon->limit.p1.y) + return; + + if (p1->y >= polygon->limit.p2.y) + return; + + _add_clipped_edge (polygon, p1, p2, p1->y, p2->y, dir); + } else + _add_edge (polygon, p1, p2, p1->y, p2->y, dir); +} + +cairo_status_t +_cairo_polygon_add_external_edge (void *polygon, + const cairo_point_t *p1, + const cairo_point_t *p2) +{ + _cairo_polygon_add_edge (polygon, p1, p2, 1); + return _cairo_polygon_status (polygon); +} + +cairo_status_t +_cairo_polygon_add_line (cairo_polygon_t *polygon, + const cairo_line_t *line, + int top, int bottom, + int dir) +{ + /* drop horizontal edges */ + if (line->p1.y == line->p2.y) + return CAIRO_STATUS_SUCCESS; + + if (bottom <= top) + return CAIRO_STATUS_SUCCESS; + + if (polygon->num_limits) { + if (line->p2.y <= polygon->limit.p1.y) + return CAIRO_STATUS_SUCCESS; + + if (line->p1.y >= polygon->limit.p2.y) + return CAIRO_STATUS_SUCCESS; + + _add_clipped_edge (polygon, &line->p1, &line->p2, top, bottom, dir); + } else + _add_edge (polygon, &line->p1, &line->p2, top, bottom, dir); + + return polygon->status; +} + +cairo_status_t +_cairo_polygon_add_contour (cairo_polygon_t *polygon, + const cairo_contour_t *contour) +{ + const struct _cairo_contour_chain *chain; + const cairo_point_t *prev = NULL; + int i; + + if (contour->chain.num_points <= 1) + return CAIRO_INT_STATUS_SUCCESS; + + prev = &contour->chain.points[0]; + for (chain = &contour->chain; chain; chain = chain->next) { + for (i = 0; i < chain->num_points; i++) { + _cairo_polygon_add_edge (polygon, prev, &chain->points[i], + contour->direction); + prev = &chain->points[i]; + } + } + + return polygon->status; +} + +void +_cairo_polygon_translate (cairo_polygon_t *polygon, int dx, int dy) +{ + int n; + + dx = _cairo_fixed_from_int (dx); + dy = _cairo_fixed_from_int (dy); + + polygon->extents.p1.x += dx; + polygon->extents.p2.x += dx; + polygon->extents.p1.y += dy; + polygon->extents.p2.y += dy; + + for (n = 0; n < polygon->num_edges; n++) { + cairo_edge_t *e = &polygon->edges[n]; + + e->top += dy; + e->bottom += dy; + + e->line.p1.x += dx; + e->line.p2.x += dx; + e->line.p1.y += dy; + e->line.p2.y += dy; + } +} diff --git a/local/recipes/libs/cairo/source/src/cairo-private.h b/local/recipes/libs/cairo/source/src/cairo-private.h new file mode 100644 index 0000000000..9f4f55b7ce --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-private.h @@ -0,0 +1,64 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Carl D. Worth + */ + +#ifndef CAIRO_PRIVATE_H +#define CAIRO_PRIVATE_H + +#include "cairo-types-private.h" +#include "cairo-reference-count-private.h" + +CAIRO_BEGIN_DECLS + +struct _cairo { + cairo_reference_count_t ref_count; + cairo_status_t status; + cairo_user_data_array_t user_data; + + const cairo_backend_t *backend; +}; + +cairo_private cairo_t * +_cairo_create_in_error (cairo_status_t status); + +cairo_private void +_cairo_init (cairo_t *cr, + const cairo_backend_t *backend); + +cairo_private void +_cairo_fini (cairo_t *cr); + +CAIRO_END_DECLS + +#endif /* CAIRO_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-ps-surface-private.h b/local/recipes/libs/cairo/source/src/cairo-ps-surface-private.h new file mode 100644 index 0000000000..e825b57fdd --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-ps-surface-private.h @@ -0,0 +1,126 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2003 University of Southern California + * Copyright © 2005 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Kristian Høgsberg + * Keith Packard + */ + +#ifndef CAIRO_PS_SURFACE_PRIVATE_H +#define CAIRO_PS_SURFACE_PRIVATE_H + +#include "cairo-ps.h" + +#include "cairo-surface-private.h" +#include "cairo-surface-clipper-private.h" +#include "cairo-pdf-operators-private.h" + +#include + +typedef struct _cairo_ps_form { + cairo_hash_entry_t base; + unsigned char *unique_id; + unsigned long unique_id_length; + cairo_bool_t is_image; + int id; + cairo_surface_t *src_surface; + unsigned int regions_id; + cairo_rectangle_int_t src_surface_extents; + cairo_bool_t src_surface_bounded; + cairo_filter_t filter; + + /* Union of source extents required for all operations using this form */ + cairo_rectangle_int_t required_extents; +} cairo_ps_form_t; + +typedef struct cairo_ps_surface { + cairo_surface_t base; + + /* Here final_stream corresponds to the stream/file passed to + * cairo_ps_surface_create surface is built. Meanwhile stream is a + * temporary stream in which the file output is built, (so that + * the header can be built and inserted into the target stream + * before the contents of the temporary stream are copied). */ + cairo_output_stream_t *final_stream; + + FILE *tmpfile; + cairo_output_stream_t *stream; + + cairo_bool_t eps; + cairo_bool_t contains_eps; + cairo_content_t content; + double width; + double height; + cairo_point_int_t document_bbox_p1, document_bbox_p2; /* in PS coordinates */ + cairo_rectangle_int_t surface_extents; + cairo_bool_t surface_bounded; + cairo_matrix_t cairo_to_ps; + cairo_bool_t paint_proc; /* TRUE if surface will be used in a PaintProc */ + + cairo_bool_t current_pattern_is_solid_color; + cairo_color_t current_color; + + int num_pages; + + cairo_paginated_mode_t paginated_mode; + + cairo_bool_t force_fallbacks; + cairo_bool_t has_creation_date; + time_t creation_date; + + cairo_scaled_font_subsets_t *font_subsets; + + cairo_list_t document_media; + cairo_array_t dsc_header_comments; + cairo_array_t dsc_setup_comments; + cairo_array_t dsc_page_setup_comments; + + cairo_array_t recording_surf_stack; + + cairo_array_t *dsc_comment_target; + + cairo_ps_level_t ps_level; + cairo_ps_level_t ps_level_used; + + cairo_surface_clipper_t clipper; + + cairo_pdf_operators_t pdf_operators; + cairo_surface_t *paginated_surface; + cairo_hash_table_t *forms; + int num_forms; + long total_form_size; +} cairo_ps_surface_t; + +#endif /* CAIRO_PS_SURFACE_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-ps-surface.c b/local/recipes/libs/cairo/source/src/cairo-ps-surface.c new file mode 100644 index 0000000000..4cae9e0599 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-ps-surface.c @@ -0,0 +1,5437 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2003 University of Southern California + * Copyright © 2005 Red Hat, Inc + * Copyright © 2007,2008 Adrian Johnson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Kristian Høgsberg + * Keith Packard + * Adrian Johnson + */ + + +/* + * Design of the PS output: + * + * The PS output is harmonised with the PDF operations using PS procedures + * to emulate the PDF operators. + * + * This has a number of advantages: + * 1. A large chunk of code is shared between the PDF and PS backends. + * See cairo-pdf-operators. + * 2. Using gs to do PS -> PDF and PDF -> PS will always work well. + */ + +#define _DEFAULT_SOURCE /* for ctime_r(), snprintf(), strdup() */ +#include "cairoint.h" + +#include "cairo-ps.h" +#include "cairo-ps-surface-private.h" + +#include "cairo-pdf-operators-private.h" +#include "cairo-pdf-shading-private.h" + +#include "cairo-array-private.h" +#include "cairo-composite-rectangles-private.h" +#include "cairo-default-context-private.h" +#include "cairo-error-private.h" +#include "cairo-image-info-private.h" +#include "cairo-image-surface-inline.h" +#include "cairo-list-inline.h" +#include "cairo-output-stream-private.h" +#include "cairo-paginated-private.h" +#include "cairo-recording-surface-inline.h" +#include "cairo-recording-surface-private.h" +#include "cairo-scaled-font-subsets-private.h" +#include "cairo-surface-clipper-private.h" +#include "cairo-surface-snapshot-inline.h" +#include "cairo-surface-subsurface-private.h" +#include "cairo-tag-attributes-private.h" +#include "cairo-type3-glyph-surface-private.h" + +#include +#include +#include +#include +#include + +/* Forms are emitted at the start and stored in memory so we limit the + * total size of all forms to prevent running out of memory. If this + * limit is exceeded, surfaces that would be stored in forms are + * emitted each time the surface is used. */ +#define MAX_L2_FORM_DATA (256*1024) +#define MAX_L3_FORM_DATA (2*1024*1024) /* Assume Level 3 printers have more memory */ + +/* #define DEBUG_PS 1 */ + +#if DEBUG_PS +#define DEBUG_FALLBACK(s) \ + fprintf (stderr, "%s::%d -- %s\n", __FUNCTION__, __LINE__, (s)) +#else +#define DEBUG_FALLBACK(s) +#endif + +#if !defined(HAVE_CTIME_R) && !defined(__redox__) +static char *ctime_r(const time_t *timep, char *buf) +{ + (void)buf; + return ctime(timep); +} +#endif + +/** + * SECTION:cairo-ps + * @Title: PostScript Surfaces + * @Short_Description: Rendering PostScript documents + * @See_Also: #cairo_surface_t + * + * The PostScript surface is used to render cairo graphics to Adobe + * PostScript files and is a multi-page vector surface backend. + * + * The following mime types are supported on source patterns: + * %CAIRO_MIME_TYPE_JPEG, %CAIRO_MIME_TYPE_UNIQUE_ID, + * %CAIRO_MIME_TYPE_CCITT_FAX, %CAIRO_MIME_TYPE_CCITT_FAX_PARAMS, + * %CAIRO_MIME_TYPE_EPS, %CAIRO_MIME_TYPE_EPS_PARAMS. + * + * Source surfaces used by the PostScript surface that have a + * %CAIRO_MIME_TYPE_UNIQUE_ID mime type will be stored in PostScript + * printer memory for the duration of the print + * job. %CAIRO_MIME_TYPE_UNIQUE_ID should only be used for small + * frequently used sources. + * + * The %CAIRO_MIME_TYPE_CCITT_FAX and %CAIRO_MIME_TYPE_CCITT_FAX_PARAMS mime types + * are documented in [CCITT Fax Images][ccitt]. + * + * # Embedding EPS files # {#eps} + * + * Encapsulated PostScript files can be embedded in the PS output by + * setting the CAIRO_MIME_TYPE_EPS mime data on a surface to the EPS + * data and painting the surface. The EPS will be scaled and + * translated to the extents of the surface the EPS data is attached + * to. + * + * The %CAIRO_MIME_TYPE_EPS mime type requires the + * %CAIRO_MIME_TYPE_EPS_PARAMS mime data to also be provided in order + * to specify the embeddding parameters. %CAIRO_MIME_TYPE_EPS_PARAMS + * mime data must contain a string of the form "bbox=[llx lly urx + * ury]" that specifies the bounding box (in PS coordinates) of the + * EPS graphics. The parameters are: lower left x, lower left y, upper + * right x, upper right y. Normally the bbox data is identical to the + * \%\%\%BoundingBox data in the EPS file. + * + **/ + +/** + * CAIRO_HAS_PS_SURFACE: + * + * Defined if the PostScript surface backend is available. + * This macro can be used to conditionally compile backend-specific code. + * + * Since: 1.2 + **/ + +typedef enum { + CAIRO_PS_COMPRESS_NONE, + CAIRO_PS_COMPRESS_LZW, + CAIRO_PS_COMPRESS_DEFLATE +} cairo_ps_compress_t; + +typedef enum { + CAIRO_EMIT_SURFACE_ANALYZE, + CAIRO_EMIT_SURFACE_EMIT, + CAIRO_EMIT_SURFACE_EMIT_FORM +} cairo_emit_surface_mode_t; + +typedef struct { + /* input params */ + cairo_surface_t *src_surface; + unsigned int regions_id; + cairo_operator_t op; + const cairo_rectangle_int_t *src_surface_extents; + cairo_bool_t src_surface_bounded; + const cairo_rectangle_int_t *src_op_extents; /* operation extents in src space */ + cairo_filter_t filter; + cairo_bool_t stencil_mask; /* TRUE if source is to be used as a mask */ + + /* output params */ + cairo_bool_t is_image; /* returns TRUE if PS image will be emitted */ + /* FALSE if recording will be emitted */ + long approx_size; + int eod_count; +} cairo_emit_surface_params_t; + +static const cairo_surface_backend_t cairo_ps_surface_backend; +static const cairo_paginated_surface_backend_t cairo_ps_surface_paginated_backend; + +static cairo_bool_t +_cairo_ps_surface_get_extents (void *abstract_surface, + cairo_rectangle_int_t *rectangle); + +static void +_cairo_ps_form_emit (void *entry, void *closure); + +static const cairo_ps_level_t _cairo_ps_levels[] = +{ + CAIRO_PS_LEVEL_2, + CAIRO_PS_LEVEL_3 +}; + +#define CAIRO_PS_LEVEL_LAST ARRAY_LENGTH (_cairo_ps_levels) + +static const char * _cairo_ps_level_strings[CAIRO_PS_LEVEL_LAST] = +{ + "PS Level 2", + "PS Level 3" +}; + +static const char *_cairo_ps_supported_mime_types[] = +{ + CAIRO_MIME_TYPE_JPEG, + CAIRO_MIME_TYPE_UNIQUE_ID, + CAIRO_MIME_TYPE_CCITT_FAX, + CAIRO_MIME_TYPE_CCITT_FAX_PARAMS, + CAIRO_MIME_TYPE_EPS, + CAIRO_MIME_TYPE_EPS_PARAMS, + NULL +}; + +typedef struct _cairo_page_standard_media { + const char *name; + int width; + int height; +} cairo_page_standard_media_t; + +static const cairo_page_standard_media_t _cairo_page_standard_media[] = +{ + { "A0", 2384, 3371 }, + { "A1", 1685, 2384 }, + { "A2", 1190, 1684 }, + { "A3", 842, 1190 }, + { "A4", 595, 842 }, + { "A5", 420, 595 }, + { "B4", 729, 1032 }, + { "B5", 516, 729 }, + { "Letter", 612, 792 }, + { "Tabloid", 792, 1224 }, + { "Ledger", 1224, 792 }, + { "Legal", 612, 1008 }, + { "Statement", 396, 612 }, + { "Executive", 540, 720 }, + { "Folio", 612, 936 }, + { "Quarto", 610, 780 }, + { "10x14", 720, 1008 }, +}; + +typedef struct _cairo_page_media { + char *name; + int width; + int height; + cairo_list_t link; +} cairo_page_media_t; + +static void +_cairo_ps_form_init_key (cairo_ps_form_t *key) +{ + key->base.hash = _cairo_hash_bytes (_CAIRO_HASH_INIT_VALUE, + key->unique_id, key->unique_id_length); +} + +static cairo_bool_t +_cairo_ps_form_equal (const void *key_a, const void *key_b) +{ + const cairo_ps_form_t *a = key_a; + const cairo_ps_form_t *b = key_b; + + if (a->filter != b->filter) + return FALSE; + + if (a->unique_id_length != b->unique_id_length) + return FALSE; + + return memcmp (a->unique_id, b->unique_id, a->unique_id_length) == 0; +} + +static void +_cairo_ps_form_pluck (void *entry, void *closure) +{ + cairo_ps_form_t *surface_entry = entry; + cairo_hash_table_t *patterns = closure; + + _cairo_hash_table_remove (patterns, &surface_entry->base); + free (surface_entry->unique_id); + if (_cairo_surface_is_recording (surface_entry->src_surface) && surface_entry->regions_id != 0) + _cairo_recording_surface_region_array_remove (surface_entry->src_surface, surface_entry->regions_id); + cairo_surface_destroy (surface_entry->src_surface); + free (surface_entry); +} + +static void +_cairo_ps_surface_emit_header (cairo_ps_surface_t *surface) +{ + char ctime_buf[26]; + time_t now; + char **comments; + int i, num_comments; + int level; + const char *eps_header = ""; + cairo_bool_t has_bbox; + + if (surface->has_creation_date) + now = surface->creation_date; + else + now = time (NULL); + + if (surface->ps_level_used == CAIRO_PS_LEVEL_2) + level = 2; + else + level = 3; + + if (surface->eps) + eps_header = " EPSF-3.0"; + + _cairo_output_stream_printf (surface->final_stream, + "%%!PS-Adobe-3.0%s\n" + "%%%%Creator: cairo %s (https://cairographics.org)\n", + eps_header, + cairo_version_string ()); + + if (!getenv ("CAIRO_DEBUG_PS_NO_DATE")) { + _cairo_output_stream_printf (surface->final_stream, + "%%%%CreationDate: %s", + ctime_r (&now, ctime_buf)); + } + + _cairo_output_stream_printf (surface->final_stream, + "%%%%Pages: %d\n" + "%%%%DocumentData: Clean7Bit\n" + "%%%%LanguageLevel: %d\n", + surface->num_pages, + level); + + if (!cairo_list_is_empty (&surface->document_media)) { + cairo_page_media_t *page; + cairo_bool_t first = TRUE; + + cairo_list_foreach_entry (page, cairo_page_media_t, &surface->document_media, link) { + if (first) { + _cairo_output_stream_printf (surface->final_stream, + "%%%%DocumentMedia: "); + first = FALSE; + } else { + _cairo_output_stream_printf (surface->final_stream, + "%%%%+ "); + } + _cairo_output_stream_printf (surface->final_stream, + "%s %d %d 0 () ()\n", + page->name, + page->width, + page->height); + } + } + + has_bbox = FALSE; + num_comments = _cairo_array_num_elements (&surface->dsc_header_comments); + comments = _cairo_array_index (&surface->dsc_header_comments, 0); + for (i = 0; i < num_comments; i++) { + _cairo_output_stream_printf (surface->final_stream, + "%s\n", comments[i]); + if (strncmp (comments[i], "%%BoundingBox:", 14) == 0) + has_bbox = TRUE; + + free (comments[i]); + comments[i] = NULL; + } + + if (!has_bbox) { + _cairo_output_stream_printf (surface->final_stream, + "%%%%BoundingBox: %d %d %d %d\n", + surface->document_bbox_p1.x, + surface->document_bbox_p1.y, + surface->document_bbox_p2.x, + surface->document_bbox_p2.y); + } + + _cairo_output_stream_printf (surface->final_stream, + "%%%%EndComments\n"); + + _cairo_output_stream_printf (surface->final_stream, + "%%%%BeginProlog\n"); + + if (surface->eps) { + _cairo_output_stream_printf (surface->final_stream, + "50 dict begin\n"); + } else { + _cairo_output_stream_printf (surface->final_stream, + "/languagelevel where\n" + "{ pop languagelevel } { 1 } ifelse\n" + "%d lt { /Helvetica findfont 12 scalefont setfont 50 500 moveto\n" + " (This print job requires a PostScript Language Level %d printer.) show\n" + " showpage quit } if\n", + level, + level); + } + + _cairo_output_stream_printf (surface->final_stream, + "/q { gsave } bind def\n" + "/Q { grestore } bind def\n" + "/cm { 6 array astore concat } bind def\n" + "/w { setlinewidth } bind def\n" + "/J { setlinecap } bind def\n" + "/j { setlinejoin } bind def\n" + "/M { setmiterlimit } bind def\n" + "/d { setdash } bind def\n" + "/m { moveto } bind def\n" + "/l { lineto } bind def\n" + "/c { curveto } bind def\n" + "/h { closepath } bind def\n" + "/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto\n" + " 0 exch rlineto 0 rlineto closepath } bind def\n" + "/S { stroke } bind def\n" + "/f { fill } bind def\n" + "/f* { eofill } bind def\n" + "/n { newpath } bind def\n" + "/W { clip } bind def\n" + "/W* { eoclip } bind def\n" + "/BT { } bind def\n" + "/ET { } bind def\n" + "/BDC { mark 3 1 roll /BDC pdfmark } bind def\n" + "/EMC { mark /EMC pdfmark } bind def\n" + "/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def\n" + "/Tj { show currentpoint cairo_store_point } bind def\n" + "/TJ {\n" + " {\n" + " dup\n" + " type /stringtype eq\n" + " { show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse\n" + " } forall\n" + " currentpoint cairo_store_point\n" + "} bind def\n" + "/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore\n" + " cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def\n" + "/Tf { pop /cairo_font exch def /cairo_font_matrix where\n" + " { pop cairo_selectfont } if } bind def\n" + "/Td { matrix translate cairo_font_matrix matrix concatmatrix dup\n" + " /cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point\n" + " /cairo_font where { pop cairo_selectfont } if } bind def\n" + "/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def\n" + " cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def\n" + "/g { setgray } bind def\n" + "/rg { setrgbcolor } bind def\n" + "/d1 { setcachedevice } bind def\n" + "/cairo_data_source {\n" + " CairoDataIndex CairoData length lt\n" + " { CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def }\n" + " { () } ifelse\n" + "} def\n" + "/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def\n" + "/cairo_image { image cairo_flush_ascii85_file } def\n" + "/cairo_imagemask { imagemask cairo_flush_ascii85_file } def\n"); + + if (!surface->eps) { + _cairo_output_stream_printf (surface->final_stream, + "/cairo_set_page_size {\n" + " %% Change paper size, but only if different from previous paper size otherwise\n" + " %% duplex fails. PLRM specifies a tolerance of 5 pts when matching paper size\n" + " %% so we use the same when checking if the size changes.\n" + " /setpagedevice where {\n" + " pop currentpagedevice\n" + " /PageSize known {\n" + " 2 copy\n" + " currentpagedevice /PageSize get aload pop\n" + " exch 4 1 roll\n" + " sub abs 5 gt\n" + " 3 1 roll\n" + " sub abs 5 gt\n" + " or\n" + " } {\n" + " true\n" + " } ifelse\n" + " {\n" + " 2 array astore\n" + " 2 dict begin\n" + " /PageSize exch def\n" + " /ImagingBBox null def\n" + " currentdict end\n" + " setpagedevice\n" + " } {\n" + " pop pop\n" + " } ifelse\n" + " } {\n" + " pop\n" + " } ifelse\n" + "} def\n"); + } + if (surface->contains_eps) { + _cairo_output_stream_printf (surface->final_stream, + "/cairo_eps_begin {\n" + " /cairo_save_state save def\n" + " /dict_count countdictstack def\n" + " /op_count count 1 sub def\n" + " userdict begin\n" + " /showpage { } def\n" + " 0 g 0 J 1 w 0 j 10 M [ ] 0 d n\n" + "} bind def\n" + "/cairo_eps_end {\n" + " count op_count sub { pop } repeat\n" + " countdictstack dict_count sub { end } repeat\n" + " cairo_save_state restore\n" + "} bind def\n"); + } + + _cairo_output_stream_printf (surface->final_stream, + "%%%%EndProlog\n"); +} + +static cairo_status_t +_cairo_ps_surface_emit_type1_font_subset (cairo_ps_surface_t *surface, + cairo_scaled_font_subset_t *font_subset) + + +{ + cairo_type1_subset_t subset; + cairo_status_t status; + int length; + char name[64]; + + snprintf (name, sizeof name, "f-%d-%d", + font_subset->font_id, font_subset->subset_id); + status = _cairo_type1_subset_init (&subset, name, font_subset, TRUE); + if (unlikely (status)) + return status; + + /* FIXME: Figure out document structure convention for fonts */ + +#if DEBUG_PS + _cairo_output_stream_printf (surface->final_stream, + "%% _cairo_ps_surface_emit_type1_font_subset\n"); +#endif + + _cairo_output_stream_printf (surface->final_stream, + "%%%%BeginResource: font %s\n", + subset.base_font); + length = subset.header_length + subset.data_length + subset.trailer_length; + _cairo_output_stream_write (surface->final_stream, subset.data, length); + _cairo_output_stream_printf (surface->final_stream, + "%%%%EndResource\n"); + + _cairo_type1_subset_fini (&subset); + + return CAIRO_STATUS_SUCCESS; +} + + +static cairo_status_t +_cairo_ps_surface_emit_type1_font_fallback (cairo_ps_surface_t *surface, + cairo_scaled_font_subset_t *font_subset) +{ + cairo_type1_subset_t subset; + cairo_status_t status; + int length; + char name[64]; + + snprintf (name, sizeof name, "f-%d-%d", + font_subset->font_id, font_subset->subset_id); + status = _cairo_type1_fallback_init_hex (&subset, name, font_subset); + if (unlikely (status)) + return status; + +#if DEBUG_PS + _cairo_output_stream_printf (surface->final_stream, + "%% _cairo_ps_surface_emit_type1_font_fallback\n"); +#endif + + _cairo_output_stream_printf (surface->final_stream, + "%%%%BeginResource: font %s\n", + subset.base_font); + length = subset.header_length + subset.data_length + subset.trailer_length; + _cairo_output_stream_write (surface->final_stream, subset.data, length); + _cairo_output_stream_printf (surface->final_stream, + "%%%%EndResource\n"); + + _cairo_type1_fallback_fini (&subset); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_ps_surface_emit_truetype_font_subset (cairo_ps_surface_t *surface, + cairo_scaled_font_subset_t *font_subset) + + +{ + cairo_truetype_subset_t subset; + cairo_status_t status; + unsigned int i, begin, end; + + status = _cairo_truetype_subset_init_ps (&subset, font_subset); + if (unlikely (status)) + return status; + + /* FIXME: Figure out document structure convention for fonts */ + +#if DEBUG_PS + _cairo_output_stream_printf (surface->final_stream, + "%% _cairo_ps_surface_emit_truetype_font_subset\n"); +#endif + + _cairo_output_stream_printf (surface->final_stream, + "%%%%BeginResource: font %s\n", + subset.ps_name); + _cairo_output_stream_printf (surface->final_stream, + "11 dict begin\n" + "/FontType 42 def\n" + "/FontName /%s def\n" + "/PaintType 0 def\n" + "/FontMatrix [ 1 0 0 1 0 0 ] def\n" + "/FontBBox [ 0 0 0 0 ] def\n" + "/Encoding 256 array def\n" + "0 1 255 { Encoding exch /.notdef put } for\n", + subset.ps_name); + + /* FIXME: Figure out how subset->x_max etc maps to the /FontBBox */ + + if (font_subset->is_latin) { + for (i = 1; i < 256; i++) { + if (font_subset->latin_to_subset_glyph_index[i] > 0) { + if (font_subset->glyph_names != NULL) { + _cairo_output_stream_printf (surface->final_stream, + "Encoding %d /%s put\n", + i, font_subset->glyph_names[font_subset->latin_to_subset_glyph_index[i]]); + } else { + _cairo_output_stream_printf (surface->final_stream, + "Encoding %d /g%ld put\n", i, font_subset->latin_to_subset_glyph_index[i]); + } + } + } + } else { + for (i = 1; i < font_subset->num_glyphs; i++) { + if (font_subset->glyph_names != NULL) { + _cairo_output_stream_printf (surface->final_stream, + "Encoding %d /%s put\n", + i, font_subset->glyph_names[i]); + } else { + _cairo_output_stream_printf (surface->final_stream, + "Encoding %d /g%d put\n", i, i); + } + } + } + + _cairo_output_stream_printf (surface->final_stream, + "/CharStrings %d dict dup begin\n" + "/.notdef 0 def\n", + font_subset->num_glyphs); + + for (i = 1; i < font_subset->num_glyphs; i++) { + if (font_subset->glyph_names != NULL) { + _cairo_output_stream_printf (surface->final_stream, + "/%s %d def\n", + font_subset->glyph_names[i], i); + } else { + _cairo_output_stream_printf (surface->final_stream, + "/g%d %d def\n", i, i); + } + } + + _cairo_output_stream_printf (surface->final_stream, + "end readonly def\n"); + + _cairo_output_stream_printf (surface->final_stream, + "/sfnts [\n"); + begin = 0; + end = 0; + for (i = 0; i < subset.num_string_offsets; i++) { + end = subset.string_offsets[i]; + _cairo_output_stream_printf (surface->final_stream,"<"); + _cairo_output_stream_write_hex_string (surface->final_stream, + subset.data + begin, end - begin); + _cairo_output_stream_printf (surface->final_stream,"00>\n"); + begin = end; + } + if (subset.data_length > end) { + _cairo_output_stream_printf (surface->final_stream,"<"); + _cairo_output_stream_write_hex_string (surface->final_stream, + subset.data + end, subset.data_length - end); + _cairo_output_stream_printf (surface->final_stream,"00>\n"); + } + + _cairo_output_stream_printf (surface->final_stream, + "] def\n" + "/f-%d-%d currentdict end definefont pop\n", + font_subset->font_id, + font_subset->subset_id); + _cairo_output_stream_printf (surface->final_stream, + "%%%%EndResource\n"); + _cairo_truetype_subset_fini (&subset); + + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_ps_emit_imagemask (cairo_image_surface_t *image, + cairo_output_stream_t *stream) +{ + uint8_t *row, *byte; + int rows, cols; + + /* The only image type supported by Type 3 fonts are 1-bit image + * masks */ + assert (image->format == CAIRO_FORMAT_A1); + + _cairo_output_stream_printf (stream, + "<<\n" + " /ImageType 1\n" + " /Width %d\n" + " /Height %d\n" + " /ImageMatrix [%d 0 0 %d 0 %d]\n" + " /Decode [1 0]\n" + " /BitsPerComponent 1\n", + image->width, + image->height, + image->width, + -image->height, + image->height); + + _cairo_output_stream_printf (stream, + " /DataSource {<\n "); + for (row = image->data, rows = image->height; rows; row += image->stride, rows--) { + for (byte = row, cols = (image->width + 7) / 8; cols; byte++, cols--) { + uint8_t output_byte = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (*byte); + _cairo_output_stream_printf (stream, "%02x ", output_byte); + } + _cairo_output_stream_printf (stream, "\n "); + } + _cairo_output_stream_printf (stream, ">}\n>>\n"); + + _cairo_output_stream_printf (stream, + "imagemask\n"); + + return _cairo_output_stream_get_status (stream); +} + +static cairo_status_t +_cairo_ps_surface_emit_type3_font_subset (cairo_ps_surface_t *surface, + cairo_scaled_font_subset_t *font_subset) + + +{ + cairo_status_t status; + unsigned int i; + cairo_box_t font_bbox = {{0,0},{0,0}}; + cairo_box_t bbox = {{0,0},{0,0}}; + cairo_surface_t *type3_surface; + double width; + + if (font_subset->num_glyphs == 0) + return CAIRO_STATUS_SUCCESS; + +#if DEBUG_PS + _cairo_output_stream_printf (surface->final_stream, + "%% _cairo_ps_surface_emit_type3_font_subset\n"); +#endif + + _cairo_output_stream_printf (surface->final_stream, + "%%%%BeginResource: font\n"); + _cairo_output_stream_printf (surface->final_stream, + "8 dict begin\n" + "/FontType 3 def\n" + "/FontMatrix [1 0 0 -1 0 0] def\n" + "/Encoding 256 array def\n" + "0 1 255 { Encoding exch /.notdef put } for\n"); + + type3_surface = _cairo_type3_glyph_surface_create (font_subset->scaled_font, + NULL, + _cairo_ps_emit_imagemask, + surface->font_subsets, + TRUE); + status = type3_surface->status; + if (unlikely (status)) + return status; + + for (i = 0; i < font_subset->num_glyphs; i++) { + if (font_subset->glyph_names != NULL) { + _cairo_output_stream_printf (surface->final_stream, + "Encoding %d /%s put\n", + i, font_subset->glyph_names[i]); + } else { + _cairo_output_stream_printf (surface->final_stream, + "Encoding %d /g%d put\n", i, i); + } + } + + _cairo_output_stream_printf (surface->final_stream, + "/Glyphs [\n"); + + for (i = 0; i < font_subset->num_glyphs; i++) { + _cairo_output_stream_printf (surface->final_stream, + " { %% %d\n", i); + status = _cairo_type3_glyph_surface_emit_glyph (type3_surface, + surface->final_stream, + font_subset->glyphs[i], + &bbox, + &width); + if (unlikely (status)) + break; + + _cairo_output_stream_printf (surface->final_stream, + " }\n"); + if (i == 0) { + font_bbox.p1.x = bbox.p1.x; + font_bbox.p1.y = bbox.p1.y; + font_bbox.p2.x = bbox.p2.x; + font_bbox.p2.y = bbox.p2.y; + } else { + if (bbox.p1.x < font_bbox.p1.x) + font_bbox.p1.x = bbox.p1.x; + if (bbox.p1.y < font_bbox.p1.y) + font_bbox.p1.y = bbox.p1.y; + if (bbox.p2.x > font_bbox.p2.x) + font_bbox.p2.x = bbox.p2.x; + if (bbox.p2.y > font_bbox.p2.y) + font_bbox.p2.y = bbox.p2.y; + } + } + cairo_surface_finish (type3_surface); + cairo_surface_destroy (type3_surface); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->final_stream, + "] def\n" + "/FontBBox [%f %f %f %f] def\n" + "/BuildChar {\n" + " exch /Glyphs get\n" + " exch get\n" + " 10 dict begin exec end\n" + "} bind def\n" + "currentdict\n" + "end\n" + "/f-%d-%d exch definefont pop\n", + _cairo_fixed_to_double (font_bbox.p1.x), + - _cairo_fixed_to_double (font_bbox.p2.y), + _cairo_fixed_to_double (font_bbox.p2.x), + - _cairo_fixed_to_double (font_bbox.p1.y), + font_subset->font_id, + font_subset->subset_id); + _cairo_output_stream_printf (surface->final_stream, + "%%%%EndResource\n"); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_ps_surface_emit_unscaled_font_subset (cairo_scaled_font_subset_t *font_subset, + void *closure) +{ + cairo_ps_surface_t *surface = closure; + cairo_int_status_t status; + + status = _cairo_scaled_font_subset_create_glyph_names (font_subset); + if (_cairo_int_status_is_error (status)) + return status; + + status = _cairo_ps_surface_emit_type1_font_subset (surface, font_subset); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + status = _cairo_ps_surface_emit_truetype_font_subset (surface, font_subset); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + status = _cairo_ps_surface_emit_type1_font_fallback (surface, font_subset); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + ASSERT_NOT_REACHED; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_ps_surface_emit_scaled_font_subset (cairo_scaled_font_subset_t *font_subset, + void *closure) +{ + cairo_ps_surface_t *surface = closure; + cairo_int_status_t status; + + status = _cairo_scaled_font_subset_create_glyph_names (font_subset); + if (_cairo_int_status_is_error (status)) + return status; + + status = _cairo_ps_surface_emit_type3_font_subset (surface, font_subset); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + ASSERT_NOT_REACHED; + return CAIRO_INT_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_ps_surface_emit_font_subsets (cairo_ps_surface_t *surface) +{ + cairo_status_t status; + +#if DEBUG_PS + _cairo_output_stream_printf (surface->final_stream, + "%% _cairo_ps_surface_emit_font_subsets\n"); +#endif + + status = _cairo_scaled_font_subsets_foreach_unscaled (surface->font_subsets, + _cairo_ps_surface_emit_unscaled_font_subset, + surface); + if (unlikely (status)) + return status; + + return _cairo_scaled_font_subsets_foreach_scaled (surface->font_subsets, + _cairo_ps_surface_emit_scaled_font_subset, + surface); +} + +static cairo_int_status_t +_cairo_ps_surface_emit_forms (cairo_ps_surface_t *surface) +{ + _cairo_hash_table_foreach (surface->forms, + _cairo_ps_form_emit, + surface); + return surface->base.status; +} + +static cairo_status_t +_cairo_ps_surface_emit_body (cairo_ps_surface_t *surface) +{ + char buf[4096]; + int n; + + if (ferror (surface->tmpfile) != 0) + return _cairo_error (CAIRO_STATUS_TEMP_FILE_ERROR); + + rewind (surface->tmpfile); + while ((n = fread (buf, 1, sizeof (buf), surface->tmpfile)) > 0) + _cairo_output_stream_write (surface->final_stream, buf, n); + + if (ferror (surface->tmpfile) != 0) + return _cairo_error (CAIRO_STATUS_TEMP_FILE_ERROR); + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_ps_surface_emit_footer (cairo_ps_surface_t *surface) +{ + _cairo_output_stream_printf (surface->final_stream, + "%%%%Trailer\n"); + + if (surface->eps) { + _cairo_output_stream_printf (surface->final_stream, + "end\n"); + } + + _cairo_output_stream_printf (surface->final_stream, + "%%%%EOF\n"); +} + +static cairo_bool_t +_path_covers_bbox (cairo_ps_surface_t *surface, + cairo_path_fixed_t *path) +{ + cairo_box_t box; + + if (_cairo_path_fixed_is_box (path, &box)) { + cairo_rectangle_int_t rect; + + _cairo_box_round_to_rectangle (&box, &rect); + + /* skip trivial whole-page clips */ + if (_cairo_rectangle_intersect (&rect, &surface->surface_extents)) { + if (rect.x == surface->surface_extents.x && + rect.width == surface->surface_extents.width && + rect.y == surface->surface_extents.y && + rect.height == surface->surface_extents.height) + { + return TRUE; + } + } + } + + return FALSE; +} + +static cairo_status_t +_cairo_ps_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_ps_surface_t *surface = cairo_container_of (clipper, + cairo_ps_surface_t, + clipper); + cairo_output_stream_t *stream = surface->stream; + cairo_status_t status; + + assert (surface->paginated_mode != CAIRO_PAGINATED_MODE_ANALYZE); + +#if DEBUG_PS + _cairo_output_stream_printf (stream, + "%% _cairo_ps_surface_intersect_clip_path\n"); +#endif + + if (path == NULL) { + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (stream, "Q q\n"); + + surface->current_pattern_is_solid_color = FALSE; + _cairo_pdf_operators_reset (&surface->pdf_operators); + + return CAIRO_STATUS_SUCCESS; + } + + if (_path_covers_bbox (surface, path)) + return CAIRO_STATUS_SUCCESS; + + return _cairo_pdf_operators_clip (&surface->pdf_operators, + path, + fill_rule); +} + +/* PLRM specifies a tolerance of 5 points when matching page sizes */ +static cairo_bool_t +_ps_page_dimension_equal (int a, int b) +{ + return (abs (a - b) < 5); +} + +static const char * +_cairo_ps_surface_get_page_media (cairo_ps_surface_t *surface) +{ + int width, height, i; + char buf[50]; + cairo_page_media_t *page; + const char *page_name; + + width = _cairo_lround (surface->width); + height = _cairo_lround (surface->height); + + /* search previously used page sizes */ + cairo_list_foreach_entry (page, cairo_page_media_t, &surface->document_media, link) { + if (_ps_page_dimension_equal (width, page->width) && + _ps_page_dimension_equal (height, page->height)) + return page->name; + } + + /* search list of standard page sizes */ + page_name = NULL; + for (i = 0; i < ARRAY_LENGTH (_cairo_page_standard_media); i++) { + if (_ps_page_dimension_equal (width, _cairo_page_standard_media[i].width) && + _ps_page_dimension_equal (height, _cairo_page_standard_media[i].height)) + { + page_name = _cairo_page_standard_media[i].name; + width = _cairo_page_standard_media[i].width; + height = _cairo_page_standard_media[i].height; + break; + } + } + + page = _cairo_calloc (sizeof (cairo_page_media_t)); + if (unlikely (page == NULL)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return NULL; + } + + if (page_name) { + page->name = strdup (page_name); + } else { + snprintf (buf, sizeof (buf), "%dx%dmm", + (int) _cairo_lround (surface->width * 25.4/72), + (int) _cairo_lround (surface->height * 25.4/72)); + page->name = strdup (buf); + } + + if (unlikely (page->name == NULL)) { + free (page); + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return NULL; + } + + page->width = width; + page->height = height; + cairo_list_add_tail (&page->link, &surface->document_media); + + return page->name; +} + +static cairo_surface_t * +_cairo_ps_surface_create_for_stream_internal (cairo_output_stream_t *stream, + double width, + double height) +{ + cairo_status_t status, status_ignored; + cairo_ps_surface_t *surface; + + surface = _cairo_calloc (sizeof (cairo_ps_surface_t)); + if (unlikely (surface == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CLEANUP; + } + + _cairo_surface_init (&surface->base, + &cairo_ps_surface_backend, + NULL, /* device */ + CAIRO_CONTENT_COLOR_ALPHA, + TRUE); /* is_vector */ + + surface->final_stream = stream; + + surface->tmpfile = _cairo_tmpfile (); + if (surface->tmpfile == NULL) { + switch (errno) { + case ENOMEM: + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + break; + default: + status = _cairo_error (CAIRO_STATUS_TEMP_FILE_ERROR); + break; + } + goto CLEANUP_SURFACE; + } + + surface->stream = _cairo_output_stream_create_for_file (surface->tmpfile); + status = _cairo_output_stream_get_status (surface->stream); + if (unlikely (status)) + goto CLEANUP_OUTPUT_STREAM; + + surface->font_subsets = _cairo_scaled_font_subsets_create_simple (); + if (unlikely (surface->font_subsets == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CLEANUP_OUTPUT_STREAM; + } + + _cairo_scaled_font_subsets_enable_latin_subset (surface->font_subsets, TRUE); + surface->has_creation_date = FALSE; + surface->eps = FALSE; + surface->ps_level = CAIRO_PS_LEVEL_3; + surface->ps_level_used = CAIRO_PS_LEVEL_2; + surface->width = width; + surface->height = height; + cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, 1, 0, 0); + surface->surface_extents.x = 0; + surface->surface_extents.y = 0; + surface->surface_extents.width = ceil (surface->width); + surface->surface_extents.height = ceil (surface->height); + surface->surface_bounded = TRUE; + surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE; + surface->force_fallbacks = FALSE; + surface->content = CAIRO_CONTENT_COLOR_ALPHA; + surface->current_pattern_is_solid_color = FALSE; + surface->document_bbox_p1.x = 0; + surface->document_bbox_p1.y = 0; + surface->document_bbox_p2.x = 0; + surface->document_bbox_p2.y = 0; + surface->total_form_size = 0; + surface->contains_eps = FALSE; + surface->paint_proc = FALSE; + + _cairo_surface_clipper_init (&surface->clipper, + _cairo_ps_surface_clipper_intersect_clip_path); + + _cairo_pdf_operators_init (&surface->pdf_operators, + surface->stream, + &surface->cairo_to_ps, + surface->font_subsets, + TRUE); + surface->num_pages = 0; + + cairo_list_init (&surface->document_media); + _cairo_array_init (&surface->dsc_header_comments, sizeof (char *)); + _cairo_array_init (&surface->dsc_setup_comments, sizeof (char *)); + _cairo_array_init (&surface->dsc_page_setup_comments, sizeof (char *)); + _cairo_array_init (&surface->recording_surf_stack, sizeof (unsigned int)); + + surface->num_forms = 0; + surface->forms = _cairo_hash_table_create (_cairo_ps_form_equal); + if (unlikely (surface->forms == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CLEANUP_FONT_SUBSETS; + } + + surface->dsc_comment_target = &surface->dsc_header_comments; + + surface->paginated_surface = _cairo_paginated_surface_create ( + &surface->base, + CAIRO_CONTENT_COLOR_ALPHA, + &cairo_ps_surface_paginated_backend); + status = surface->paginated_surface->status; + if (status == CAIRO_STATUS_SUCCESS) { + /* paginated keeps the only reference to surface now, drop ours */ + cairo_surface_destroy (&surface->base); + return surface->paginated_surface; + } + + CLEANUP_FONT_SUBSETS: + _cairo_scaled_font_subsets_destroy (surface->font_subsets); + CLEANUP_OUTPUT_STREAM: + status_ignored = _cairo_output_stream_destroy (surface->stream); + fclose (surface->tmpfile); + CLEANUP_SURFACE: + free (surface); + CLEANUP: + /* destroy stream on behalf of caller */ + status_ignored = _cairo_output_stream_destroy (stream); + + return _cairo_surface_create_in_error (status); +} + +/** + * cairo_ps_surface_create: + * @filename: a filename for the PS output (must be writable), %NULL may be + * used to specify no output. This will generate a PS surface that + * may be queried and used as a source, without generating a + * temporary file. + * @width_in_points: width of the surface, in points (1 point == 1/72.0 inch) + * @height_in_points: height of the surface, in points (1 point == 1/72.0 inch) + * + * Creates a PostScript surface of the specified size in points to be + * written to @filename. See cairo_ps_surface_create_for_stream() for + * a more flexible mechanism for handling the PostScript output than + * simply writing it to a named file. + * + * Note that the size of individual pages of the PostScript output can + * vary. See cairo_ps_surface_set_size(). + * + * Return value: a pointer to the newly created surface. The caller + * owns the surface and should call cairo_surface_destroy() when done + * with it. + * + * This function always returns a valid pointer, but it will return a + * pointer to a "nil" surface if an error such as out of memory + * occurs. You can use cairo_surface_status() to check for this. + * + * Since: 1.2 + **/ +cairo_surface_t * +cairo_ps_surface_create (const char *filename, + double width_in_points, + double height_in_points) +{ + cairo_output_stream_t *stream; + + stream = _cairo_output_stream_create_for_filename (filename); + if (_cairo_output_stream_get_status (stream)) + return _cairo_surface_create_in_error (_cairo_output_stream_destroy (stream)); + + return _cairo_ps_surface_create_for_stream_internal (stream, + width_in_points, + height_in_points); +} + +/** + * cairo_ps_surface_create_for_stream: + * @write_func: a #cairo_write_func_t to accept the output data, may be %NULL + * to indicate a no-op @write_func. With a no-op @write_func, + * the surface may be queried or used as a source without + * generating any temporary files. + * @closure: the closure argument for @write_func + * @width_in_points: width of the surface, in points (1 point == 1/72.0 inch) + * @height_in_points: height of the surface, in points (1 point == 1/72.0 inch) + * + * Creates a PostScript surface of the specified size in points to be + * written incrementally to the stream represented by @write_func and + * @closure. See cairo_ps_surface_create() for a more convenient way + * to simply direct the PostScript output to a named file. + * + * Note that the size of individual pages of the PostScript + * output can vary. See cairo_ps_surface_set_size(). + * + * Return value: a pointer to the newly created surface. The caller + * owns the surface and should call cairo_surface_destroy() when done + * with it. + * + * This function always returns a valid pointer, but it will return a + * pointer to a "nil" surface if an error such as out of memory + * occurs. You can use cairo_surface_status() to check for this. + * + * Since: 1.2 + **/ +cairo_surface_t * +cairo_ps_surface_create_for_stream (cairo_write_func_t write_func, + void *closure, + double width_in_points, + double height_in_points) +{ + cairo_output_stream_t *stream; + + stream = _cairo_output_stream_create (write_func, NULL, closure); + if (_cairo_output_stream_get_status (stream)) + return _cairo_surface_create_in_error (_cairo_output_stream_destroy (stream)); + + return _cairo_ps_surface_create_for_stream_internal (stream, + width_in_points, + height_in_points); +} + +static cairo_bool_t +_cairo_surface_is_ps (cairo_surface_t *surface) +{ + return surface->backend == &cairo_ps_surface_backend; +} + +/* If the abstract_surface is a paginated surface, and that paginated + * surface's target is a ps_surface, then set ps_surface to that + * target. Otherwise return FALSE. + */ +static cairo_bool_t +_extract_ps_surface (cairo_surface_t *surface, + cairo_bool_t set_error_on_failure, + cairo_ps_surface_t **ps_surface) +{ + cairo_surface_t *target; + + if (surface->status) + return FALSE; + if (surface->finished) { + if (set_error_on_failure) + _cairo_surface_set_error (surface, + _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + return FALSE; + } + + if (! _cairo_surface_is_paginated (surface)) { + if (set_error_on_failure) + _cairo_surface_set_error (surface, + _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); + return FALSE; + } + + target = _cairo_paginated_surface_get_target (surface); + if (target->status) { + if (set_error_on_failure) + _cairo_surface_set_error (surface, target->status); + return FALSE; + } + if (target->finished) { + if (set_error_on_failure) + _cairo_surface_set_error (surface, + _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + return FALSE; + } + + if (! _cairo_surface_is_ps (target)) { + if (set_error_on_failure) + _cairo_surface_set_error (surface, + _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); + return FALSE; + } + + *ps_surface = (cairo_ps_surface_t *) target; + return TRUE; +} + +/** + * cairo_ps_surface_restrict_to_level: + * @surface: a PostScript #cairo_surface_t + * @level: PostScript level + * + * Restricts the generated PostSript file to @level. See + * cairo_ps_get_levels() for a list of available level values that + * can be used here. + * + * This function should only be called before any drawing operations + * have been performed on the given surface. The simplest way to do + * this is to call this function immediately after creating the + * surface. + * + * Since: 1.6 + **/ +void +cairo_ps_surface_restrict_to_level (cairo_surface_t *surface, + cairo_ps_level_t level) +{ + cairo_ps_surface_t *ps_surface = NULL; + + if (! _extract_ps_surface (surface, TRUE, &ps_surface)) + return; + + if (level < CAIRO_PS_LEVEL_LAST) + ps_surface->ps_level = level; +} + +/** + * cairo_ps_get_levels: + * @levels: supported level list + * @num_levels: list length + * + * Used to retrieve the list of supported levels. See + * cairo_ps_surface_restrict_to_level(). + * + * Since: 1.6 + **/ +void +cairo_ps_get_levels (cairo_ps_level_t const **levels, + int *num_levels) +{ + if (levels != NULL) + *levels = _cairo_ps_levels; + + if (num_levels != NULL) + *num_levels = CAIRO_PS_LEVEL_LAST; +} + +/** + * cairo_ps_level_to_string: + * @level: a level id + * + * Get the string representation of the given @level id. This function + * will return %NULL if @level id isn't valid. See cairo_ps_get_levels() + * for a way to get the list of valid level ids. + * + * Return value: the string associated to given level. + * + * Since: 1.6 + **/ +const char * +cairo_ps_level_to_string (cairo_ps_level_t level) +{ + if (level >= CAIRO_PS_LEVEL_LAST) + return NULL; + + return _cairo_ps_level_strings[level]; +} + +/** + * cairo_ps_surface_set_eps: + * @surface: a PostScript #cairo_surface_t + * @eps: %TRUE to output EPS format PostScript + * + * If @eps is %TRUE, the PostScript surface will output Encapsulated + * PostScript. + * + * This function should only be called before any drawing operations + * have been performed on the current page. The simplest way to do + * this is to call this function immediately after creating the + * surface. An Encapsulated PostScript file should never contain more + * than one page. + * + * Since: 1.6 + **/ +void +cairo_ps_surface_set_eps (cairo_surface_t *surface, + cairo_bool_t eps) +{ + cairo_ps_surface_t *ps_surface = NULL; + + if (! _extract_ps_surface (surface, TRUE, &ps_surface)) + return; + + ps_surface->eps = eps; +} + +/** + * cairo_ps_surface_get_eps: + * @surface: a PostScript #cairo_surface_t + * + * Check whether the PostScript surface will output Encapsulated PostScript. + * + * Return value: %TRUE if the surface will output Encapsulated PostScript. + * + * Since: 1.6 + **/ +cairo_public cairo_bool_t +cairo_ps_surface_get_eps (cairo_surface_t *surface) +{ + cairo_ps_surface_t *ps_surface = NULL; + + if (! _extract_ps_surface (surface, FALSE, &ps_surface)) + return FALSE; + + return ps_surface->eps; +} + +/** + * cairo_ps_surface_set_size: + * @surface: a PostScript #cairo_surface_t + * @width_in_points: new surface width, in points (1 point == 1/72.0 inch) + * @height_in_points: new surface height, in points (1 point == 1/72.0 inch) + * + * Changes the size of a PostScript surface for the current (and + * subsequent) pages. + * + * This function should only be called before any drawing operations + * have been performed on the current page. The simplest way to do + * this is to call this function immediately after creating the + * surface or immediately after completing a page with either + * cairo_show_page() or cairo_copy_page(). + * + * Since: 1.2 + **/ +void +cairo_ps_surface_set_size (cairo_surface_t *surface, + double width_in_points, + double height_in_points) +{ + cairo_ps_surface_t *ps_surface = NULL; + cairo_status_t status; + + if (! _extract_ps_surface (surface, TRUE, &ps_surface)) + return; + + ps_surface->width = width_in_points; + ps_surface->height = height_in_points; + cairo_matrix_init (&ps_surface->cairo_to_ps, 1, 0, 0, 1, 0, 0); + ps_surface->surface_extents.x = 0; + ps_surface->surface_extents.y = 0; + ps_surface->surface_extents.width = ceil (ps_surface->width); + ps_surface->surface_extents.height = ceil (ps_surface->height); + _cairo_pdf_operators_set_cairo_to_pdf_matrix (&ps_surface->pdf_operators, + &ps_surface->cairo_to_ps); + status = _cairo_paginated_surface_set_size (ps_surface->paginated_surface, + width_in_points, + height_in_points); + if (status) + status = _cairo_surface_set_error (surface, status); +} + +/** + * cairo_ps_surface_dsc_comment: + * @surface: a PostScript #cairo_surface_t + * @comment: a comment string to be emitted into the PostScript output + * + * Emit a comment into the PostScript output for the given surface. + * + * The comment is expected to conform to the PostScript Language + * Document Structuring Conventions (DSC). Please see that manual for + * details on the available comments and their meanings. In + * particular, the \%\%IncludeFeature comment allows a + * device-independent means of controlling printer device features. So + * the PostScript Printer Description Files Specification will also be + * a useful reference. + * + * The comment string must begin with a percent character (\%) and the + * total length of the string (including any initial percent + * characters) must not exceed 255 characters. Violating either of + * these conditions will place @surface into an error state. But + * beyond these two conditions, this function will not enforce + * conformance of the comment with any particular specification. + * + * The comment string must not contain any newline characters. + * + * The DSC specifies different sections in which particular comments + * can appear. This function provides for comments to be emitted + * within three sections: the header, the Setup section, and the + * PageSetup section. Comments appearing in the first two sections + * apply to the entire document while comments in the BeginPageSetup + * section apply only to a single page. + * + * For comments to appear in the header section, this function should + * be called after the surface is created, but before a call to + * cairo_ps_surface_dsc_begin_setup(). + * + * For comments to appear in the Setup section, this function should + * be called after a call to cairo_ps_surface_dsc_begin_setup() but + * before a call to cairo_ps_surface_dsc_begin_page_setup(). + * + * For comments to appear in the PageSetup section, this function + * should be called after a call to + * cairo_ps_surface_dsc_begin_page_setup(). + * + * Note that it is only necessary to call + * cairo_ps_surface_dsc_begin_page_setup() for the first page of any + * surface. After a call to cairo_show_page() or cairo_copy_page() + * comments are unambiguously directed to the PageSetup section of the + * current page. But it doesn't hurt to call this function at the + * beginning of every page as that consistency may make the calling + * code simpler. + * + * As a final note, cairo automatically generates several comments on + * its own. As such, applications must not manually generate any of + * the following comments: + * + * Header section: \%!PS-Adobe-3.0, \%\%Creator, \%\%CreationDate, \%\%Pages, + * \%\%BoundingBox, \%\%DocumentData, \%\%LanguageLevel, \%\%EndComments. + * + * Setup section: \%\%BeginSetup, \%\%EndSetup + * + * PageSetup section: \%\%BeginPageSetup, \%\%PageBoundingBox, \%\%EndPageSetup. + * + * Other sections: \%\%BeginProlog, \%\%EndProlog, \%\%Page, \%\%Trailer, \%\%EOF + * + * Here is an example sequence showing how this function might be used: + * + * + * cairo_surface_t *surface = cairo_ps_surface_create (filename, width, height); + * ... + * cairo_ps_surface_dsc_comment (surface, "%%Title: My excellent document"); + * cairo_ps_surface_dsc_comment (surface, "%%Copyright: Copyright (C) 2006 Cairo Lover") + * ... + * cairo_ps_surface_dsc_begin_setup (surface); + * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *MediaColor White"); + * ... + * cairo_ps_surface_dsc_begin_page_setup (surface); + * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *PageSize A3"); + * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *InputSlot LargeCapacity"); + * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *MediaType Glossy"); + * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *MediaColor Blue"); + * ... draw to first page here .. + * cairo_show_page (cr); + * ... + * cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *PageSize A5"); + * ... + * + * + * Since: 1.2 + **/ +void +cairo_ps_surface_dsc_comment (cairo_surface_t *surface, + const char *comment) +{ + cairo_ps_surface_t *ps_surface = NULL; + cairo_status_t status; + char *comment_copy; + + if (! _extract_ps_surface (surface, TRUE, &ps_surface)) + return; + + /* A couple of sanity checks on the comment value. */ + if (comment == NULL) { + status = _cairo_surface_set_error (surface, CAIRO_STATUS_NULL_POINTER); + return; + } + + if (comment[0] != '%' || strlen (comment) > 255) { + status = _cairo_surface_set_error (surface, CAIRO_STATUS_INVALID_DSC_COMMENT); + return; + } + + /* Then, copy the comment and store it in the appropriate array. */ + comment_copy = strdup (comment); + if (unlikely (comment_copy == NULL)) { + status = _cairo_surface_set_error (surface, CAIRO_STATUS_NO_MEMORY); + return; + } + + status = _cairo_array_append (ps_surface->dsc_comment_target, &comment_copy); + if (unlikely (status)) { + free (comment_copy); + status = _cairo_surface_set_error (surface, status); + return; + } +} + +/** + * cairo_ps_surface_dsc_begin_setup: + * @surface: a PostScript #cairo_surface_t + * + * This function indicates that subsequent calls to + * cairo_ps_surface_dsc_comment() should direct comments to the Setup + * section of the PostScript output. + * + * This function should be called at most once per surface, and must + * be called before any call to cairo_ps_surface_dsc_begin_page_setup() + * and before any drawing is performed to the surface. + * + * See cairo_ps_surface_dsc_comment() for more details. + * + * Since: 1.2 + **/ +void +cairo_ps_surface_dsc_begin_setup (cairo_surface_t *surface) +{ + cairo_ps_surface_t *ps_surface = NULL; + + if (! _extract_ps_surface (surface, TRUE, &ps_surface)) + return; + + if (ps_surface->dsc_comment_target == &ps_surface->dsc_header_comments) + ps_surface->dsc_comment_target = &ps_surface->dsc_setup_comments; +} + +/** + * cairo_ps_surface_dsc_begin_page_setup: + * @surface: a PostScript #cairo_surface_t + * + * This function indicates that subsequent calls to + * cairo_ps_surface_dsc_comment() should direct comments to the + * PageSetup section of the PostScript output. + * + * This function call is only needed for the first page of a + * surface. It should be called after any call to + * cairo_ps_surface_dsc_begin_setup() and before any drawing is + * performed to the surface. + * + * See cairo_ps_surface_dsc_comment() for more details. + * + * Since: 1.2 + **/ +void +cairo_ps_surface_dsc_begin_page_setup (cairo_surface_t *surface) +{ + cairo_ps_surface_t *ps_surface = NULL; + + if (! _extract_ps_surface (surface, TRUE, &ps_surface)) + return; + + if (ps_surface->dsc_comment_target == &ps_surface->dsc_header_comments || + ps_surface->dsc_comment_target == &ps_surface->dsc_setup_comments) + { + ps_surface->dsc_comment_target = &ps_surface->dsc_page_setup_comments; + } +} + +static cairo_status_t +_cairo_ps_surface_finish (void *abstract_surface) +{ + cairo_status_t status, status2; + cairo_ps_surface_t *surface = abstract_surface; + int i, num_comments; + char **comments; + + status = surface->base.status; + if (unlikely (status)) + goto CLEANUP; + + _cairo_ps_surface_emit_header (surface); + + _cairo_output_stream_printf (surface->final_stream, + "%%%%BeginSetup\n"); + + num_comments = _cairo_array_num_elements (&surface->dsc_setup_comments); + if (num_comments) { + comments = _cairo_array_index (&surface->dsc_setup_comments, 0); + for (i = 0; i < num_comments; i++) { + _cairo_output_stream_printf (surface->final_stream, + "%s\n", comments[i]); + free (comments[i]); + comments[i] = NULL; + } + } + + status = _cairo_ps_surface_emit_font_subsets (surface); + if (unlikely (status)) + goto CLEANUP; + + status = _cairo_ps_surface_emit_forms (surface); + if (unlikely (status)) + goto CLEANUP; + + _cairo_output_stream_printf (surface->final_stream, + "%%%%EndSetup\n"); + + status = _cairo_ps_surface_emit_body (surface); + if (unlikely (status)) + goto CLEANUP; + + _cairo_ps_surface_emit_footer (surface); + +CLEANUP: + _cairo_hash_table_foreach (surface->forms, + _cairo_ps_form_pluck, + surface->forms); + _cairo_hash_table_destroy (surface->forms); + _cairo_scaled_font_subsets_destroy (surface->font_subsets); + + status2 = _cairo_output_stream_destroy (surface->stream); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; + + fclose (surface->tmpfile); + + status2 = _cairo_output_stream_destroy (surface->final_stream); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; + + while (! cairo_list_is_empty (&surface->document_media)) { + cairo_page_media_t *page; + + page = cairo_list_first_entry (&surface->document_media, + cairo_page_media_t, + link); + cairo_list_del (&page->link); + free (page->name); + free (page); + } + + num_comments = _cairo_array_num_elements (&surface->dsc_header_comments); + comments = _cairo_array_index (&surface->dsc_header_comments, 0); + for (i = 0; i < num_comments; i++) + free (comments[i]); + _cairo_array_fini (&surface->dsc_header_comments); + + num_comments = _cairo_array_num_elements (&surface->dsc_setup_comments); + comments = _cairo_array_index (&surface->dsc_setup_comments, 0); + for (i = 0; i < num_comments; i++) + free (comments[i]); + _cairo_array_fini (&surface->dsc_setup_comments); + + num_comments = _cairo_array_num_elements (&surface->dsc_page_setup_comments); + comments = _cairo_array_index (&surface->dsc_page_setup_comments, 0); + for (i = 0; i < num_comments; i++) + free (comments[i]); + _cairo_array_fini (&surface->dsc_page_setup_comments); + + _cairo_array_fini (&surface->recording_surf_stack); + + _cairo_surface_clipper_reset (&surface->clipper); + + return status; +} + +static cairo_int_status_t +_cairo_ps_surface_start_page (void *abstract_surface) +{ + cairo_ps_surface_t *surface = abstract_surface; + + /* Increment before print so page numbers start at 1. */ + surface->num_pages++; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_ps_surface_show_page (void *abstract_surface) +{ + cairo_ps_surface_t *surface = abstract_surface; + cairo_int_status_t status; + + if (surface->clipper.clip != NULL) + _cairo_surface_clipper_reset (&surface->clipper); + + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->stream, + "Q Q\n" + "showpage\n"); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_bool_t +color_is_gray (double red, double green, double blue) +{ + const double epsilon = 0.00001; + + return (fabs (red - green) < epsilon && + fabs (red - blue) < epsilon); +} + +/** + * _cairo_ps_surface_acquire_source_surface_from_pattern: + * @surface: [in] the ps surface + * @pattern: [in] A #cairo_pattern_t of type SURFACE or RASTER_SOURCE to use + * as the source + * @extents: [in] extents of the operation that is using this source + * @src_surface_extents: [out] return source surface extents + * @src_surface_bounded: [out] return TRUE if source surface is bounded + * @src_op_extents: [out] return operation extents in source space + * @source_surface: [out] returns surface of type image surface or recording surface + * @x_offset: [out] return x offset of surface + * @y_offset: [out] return y offset of surface + * + * Acquire source surface or raster source pattern. + **/ +static cairo_status_t +_cairo_ps_surface_acquire_source_surface_from_pattern ( + cairo_ps_surface_t *surface, + const cairo_pattern_t *pattern, + const cairo_rectangle_int_t *extents, + cairo_rectangle_int_t *src_surface_extents, + cairo_bool_t *src_surface_bounded, + cairo_rectangle_int_t *src_op_extents, + cairo_surface_t **source_surface, + double *x_offset, + double *y_offset) +{ + cairo_status_t status; + cairo_box_t bbox; + + *x_offset = 0; + *y_offset = 0; + + /* get the operation extents in pattern space */ + _cairo_box_from_rectangle (&bbox, extents); + _cairo_matrix_transform_bounding_box_fixed (&pattern->matrix, &bbox, NULL); + _cairo_box_round_to_rectangle (&bbox, src_op_extents); + + if (pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) { + cairo_surface_t *surf; + + surf = _cairo_raster_source_pattern_acquire (pattern, &surface->base, src_op_extents); + if (!surf) + return CAIRO_INT_STATUS_UNSUPPORTED; + + *src_surface_bounded = _cairo_surface_get_extents (surf, src_surface_extents); + cairo_surface_get_device_offset (surf, x_offset, y_offset); + *source_surface = surf; + } else if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { + cairo_surface_t *surf = NULL; + + *source_surface = ((cairo_surface_pattern_t *) pattern)->surface; + surf = *source_surface; + *src_surface_bounded = _cairo_surface_get_extents (surf, src_surface_extents); + if (surf->type == CAIRO_SURFACE_TYPE_RECORDING) { + if (_cairo_surface_is_snapshot (surf)) + surf = _cairo_surface_snapshot_get_target (surf); + + if (surf->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) { + cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) surf; + + *src_surface_extents = sub->extents; + *src_surface_bounded = TRUE; + *x_offset = -sub->extents.x; + *y_offset = -sub->extents.y; + } + + cairo_surface_destroy (surf); + } else if (surf->type != CAIRO_SURFACE_TYPE_IMAGE) { + cairo_image_surface_t *image; + void *image_extra; + + status = _cairo_surface_acquire_source_image (surf, &image, &image_extra); + if (unlikely (status)) + return status; + + *src_surface_bounded = _cairo_surface_get_extents (&image->base, src_surface_extents); + _cairo_surface_release_source_image (surf, image, image_extra); + } + } else { + ASSERT_NOT_REACHED; + } + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_ps_surface_release_source_surface_from_pattern (cairo_ps_surface_t *surface, + const cairo_pattern_t *pattern, + cairo_surface_t *source_surface) +{ + if (pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) + _cairo_raster_source_pattern_release (pattern, source_surface); +} + +/** + * _cairo_ps_surface_create_padded_image_from_image: + * @surface: the ps surface + * @source: The source image + * @extents: extents of the operation that is using this source + * @image: returns the padded image or NULL if padding not required to fill @extents + * @image_extents: returns extents of padded image. These extents in are in source image space. + * + * Creates a padded image if the source image does not fill the extents. + **/ +static cairo_status_t +_cairo_ps_surface_create_padded_image_from_image (cairo_ps_surface_t *surface, + cairo_image_surface_t *source, + const cairo_matrix_t *source_matrix, + const cairo_rectangle_int_t *extents, + cairo_image_surface_t **image, + cairo_rectangle_int_t *image_extents) +{ + cairo_box_t box; + cairo_rectangle_int_t rect; + cairo_surface_t *pad_image; + cairo_surface_pattern_t pad_pattern; + int w, h; + cairo_int_status_t status; + + /* get the operation extents in pattern space */ + _cairo_box_from_rectangle (&box, extents); + _cairo_matrix_transform_bounding_box_fixed (source_matrix, &box, NULL); + _cairo_box_round_to_rectangle (&box, &rect); + + /* Check if image needs padding to fill extents. */ + w = source->width; + h = source->height; + if (_cairo_fixed_integer_ceil(box.p1.x) < 0 || + _cairo_fixed_integer_ceil(box.p1.y) < 0 || + _cairo_fixed_integer_floor(box.p2.y) > w || + _cairo_fixed_integer_floor(box.p2.y) > h) + { + pad_image = _cairo_image_surface_create_with_content (source->base.content, + rect.width, + rect.height); + if (pad_image->status) + return pad_image->status; + + _cairo_pattern_init_for_surface (&pad_pattern, &source->base); + cairo_matrix_init_translate (&pad_pattern.base.matrix, rect.x, rect.y); + pad_pattern.base.extend = CAIRO_EXTEND_PAD; + status = _cairo_surface_paint (pad_image, + CAIRO_OPERATOR_SOURCE, + &pad_pattern.base, + NULL); + _cairo_pattern_fini (&pad_pattern.base); + *image = (cairo_image_surface_t *) pad_image; + image_extents->x = rect.x; + image_extents->y = rect.y; + image_extents->width = rect.width; + image_extents->height = rect.height; + } else { + *image = NULL; + status = CAIRO_STATUS_SUCCESS; + } + + return status; +} + +static cairo_int_status_t +_cairo_ps_surface_analyze_surface_pattern_transparency (cairo_ps_surface_t *surface, + const cairo_pattern_t *pattern, + const cairo_rectangle_int_t *extents) +{ + cairo_rectangle_int_t src_surface_extents; + cairo_bool_t src_surface_bounded; + cairo_rectangle_int_t src_op_extents; + cairo_surface_t *source_surface; + double x_offset, y_offset; + cairo_image_surface_t *image; + void *image_extra; + cairo_int_status_t status; + cairo_image_transparency_t transparency; + + status = _cairo_ps_surface_acquire_source_surface_from_pattern (surface, + pattern, + extents, + &src_surface_extents, + &src_surface_bounded, + &src_op_extents, + &source_surface, + &x_offset, + &y_offset); + if (unlikely (status)) + return status; + + status = _cairo_surface_acquire_source_image (source_surface, &image, &image_extra); + if (unlikely (status)) + return status; + + if (image->base.status) + return image->base.status; + + transparency = _cairo_image_analyze_transparency (image); + switch (transparency) { + case CAIRO_IMAGE_IS_OPAQUE: + status = CAIRO_STATUS_SUCCESS; + break; + + case CAIRO_IMAGE_HAS_BILEVEL_ALPHA: + if (surface->ps_level == CAIRO_PS_LEVEL_2) { + status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY; + } else { + surface->ps_level_used = CAIRO_PS_LEVEL_3; + status = CAIRO_STATUS_SUCCESS; + } + break; + + case CAIRO_IMAGE_HAS_ALPHA: + status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY; + break; + + case CAIRO_IMAGE_UNKNOWN: + ASSERT_NOT_REACHED; + } + + _cairo_surface_release_source_image (source_surface, image, image_extra); + _cairo_ps_surface_release_source_surface_from_pattern (surface, pattern, source_surface); + + return status; +} + +static cairo_bool_t +surface_pattern_supported (const cairo_surface_pattern_t *pattern) +{ + if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) + return TRUE; + + if (pattern->surface->backend->acquire_source_image == NULL) + return FALSE; + + /* Does an ALPHA-only source surface even make sense? Maybe, but I + * don't think it's worth the extra code to support it. */ + +/* XXX: Need to write this function here... + content = pattern->surface->content; + if (content == CAIRO_CONTENT_ALPHA) + return FALSE; +*/ + + return TRUE; +} + +static cairo_bool_t +_gradient_pattern_supported (cairo_ps_surface_t *surface, + const cairo_pattern_t *pattern) +{ + double min_alpha, max_alpha; + + if (surface->ps_level == CAIRO_PS_LEVEL_2) + return FALSE; + + /* Alpha gradients are only supported (by flattening the alpha) + * if there is no variation in the alpha across the gradient. */ + _cairo_pattern_alpha_range (pattern, &min_alpha, &max_alpha); + if (min_alpha != max_alpha) + return FALSE; + + surface->ps_level_used = CAIRO_PS_LEVEL_3; + + return TRUE; +} + +static cairo_bool_t +pattern_supported (cairo_ps_surface_t *surface, const cairo_pattern_t *pattern) +{ + switch (pattern->type) { + case CAIRO_PATTERN_TYPE_SOLID: + return TRUE; + + case CAIRO_PATTERN_TYPE_LINEAR: + case CAIRO_PATTERN_TYPE_RADIAL: + case CAIRO_PATTERN_TYPE_MESH: + return _gradient_pattern_supported (surface, pattern); + + case CAIRO_PATTERN_TYPE_SURFACE: + return surface_pattern_supported ((cairo_surface_pattern_t *) pattern); + + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + return TRUE; + + default: + ASSERT_NOT_REACHED; + return FALSE; + } +} + +static cairo_bool_t +mask_supported (cairo_ps_surface_t *surface, + const cairo_pattern_t *mask, + const cairo_rectangle_int_t *extents) +{ + if (surface->ps_level == CAIRO_PS_LEVEL_2) + return FALSE; + + if (mask->type == CAIRO_PATTERN_TYPE_SURFACE) { + cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) mask; + if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_IMAGE) { + /* check if mask if opaque or bilevel alpha */ + if (_cairo_ps_surface_analyze_surface_pattern_transparency (surface, mask, extents) == CAIRO_INT_STATUS_SUCCESS) { + surface->ps_level_used = CAIRO_PS_LEVEL_3; + return TRUE; + } + } + } + + return FALSE; +} + +static cairo_int_status_t +_cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *pattern, + const cairo_pattern_t *mask, + const cairo_rectangle_int_t *extents) +{ + double min_alpha; + + if (surface->force_fallbacks && + surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) + { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + if (! pattern_supported (surface, pattern)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (! (op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_OVER)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* Mask is only supported when the mask is an image with opaque or bilevel alpha. */ + if (mask && !mask_supported (surface, mask, extents)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { + cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern; + + if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) { + if (pattern->extend == CAIRO_EXTEND_PAD) { + cairo_box_t box; + cairo_rectangle_int_t rect; + cairo_rectangle_int_t rec_extents; + + /* get the operation extents in pattern space */ + _cairo_box_from_rectangle (&box, extents); + _cairo_matrix_transform_bounding_box_fixed (&pattern->matrix, &box, NULL); + _cairo_box_round_to_rectangle (&box, &rect); + + /* Check if surface needs padding to fill extents */ + if (_cairo_surface_get_extents (surface_pattern->surface, &rec_extents)) { + if (_cairo_fixed_integer_ceil(box.p1.x) < rec_extents.x || + _cairo_fixed_integer_ceil(box.p1.y) < rec_extents.y || + _cairo_fixed_integer_floor(box.p2.y) > rec_extents.x + rec_extents.width || + _cairo_fixed_integer_floor(box.p2.y) > rec_extents.y + rec_extents.height) + { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + } + } + return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN; + } + } + + if (op == CAIRO_OPERATOR_SOURCE) { + if (mask) + return CAIRO_INT_STATUS_UNSUPPORTED; + else + return CAIRO_STATUS_SUCCESS; + } + + /* CAIRO_OPERATOR_OVER is only supported for opaque patterns. If + * the pattern contains transparency, we return + * CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY to the analysis + * surface. If the analysis surface determines that there is + * anything drawn under this operation, a fallback image will be + * used. Otherwise the operation will be replayed during the + * render stage and we blend the transparency into the white + * background to convert the pattern to opaque. + */ + if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE || pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) + return _cairo_ps_surface_analyze_surface_pattern_transparency (surface, pattern, extents); + + /* Patterns whose drawn part is opaque are directly supported; + those whose drawn part is partially transparent can be + supported by flattening the alpha. */ + _cairo_pattern_alpha_range (pattern, &min_alpha, NULL); + if (CAIRO_ALPHA_IS_OPAQUE (min_alpha)) + return CAIRO_STATUS_SUCCESS; + + return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY; +} + +static cairo_bool_t +_cairo_ps_surface_operation_supported (cairo_ps_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *pattern, + const cairo_pattern_t *mask, + const cairo_rectangle_int_t *extents) +{ + return _cairo_ps_surface_analyze_operation (surface, op, pattern, mask, extents) != CAIRO_INT_STATUS_UNSUPPORTED; +} + +/* The "standard" implementation limit for PostScript string sizes is + * 65535 characters (see PostScript Language Reference, Appendix + * B). + */ +#define STRING_ARRAY_MAX_STRING_SIZE 65535 +#define STRING_ARRAY_MAX_COLUMN 72 + +typedef struct _string_array_stream { + cairo_output_stream_t base; + cairo_output_stream_t *output; + int column; + int string_size; + int tuple_count; + cairo_bool_t use_strings; +} string_array_stream_t; + +static cairo_status_t +_base85_string_wrap_stream_write (cairo_output_stream_t *base, + const unsigned char *data, + unsigned int length) +{ + string_array_stream_t *stream = (string_array_stream_t *) base; + unsigned char c; + + if (length == 0) + return CAIRO_STATUS_SUCCESS; + + while (length--) { + if (stream->column == 0) { + if (stream->use_strings) { + _cairo_output_stream_printf (stream->output, "<~"); + stream->column = 2; + } else { + _cairo_output_stream_printf (stream->output, " "); + stream->column = 1; + } + } + + c = *data++; + _cairo_output_stream_write (stream->output, &c, 1); + stream->column++; + + /* Base85 encodes each 4 byte tuple with a 5 ASCII character + * tuple, except for 'z' with represents 4 zero bytes. We need + * to keep track of the string length after decoding. + */ + if (c == 'z') { + stream->string_size += 4; + stream->tuple_count = 0; + } else { + if (++stream->tuple_count == 5) { + stream->string_size += 4; + stream->tuple_count = 0; + } + } + + /* Split string at tuple boundary when there is not enough + * space for another tuple */ + if (stream->use_strings && + stream->tuple_count == 0 && + stream->string_size > STRING_ARRAY_MAX_STRING_SIZE - 4) + { + _cairo_output_stream_printf (stream->output, "~>\n"); + stream->string_size = 0; + stream->column = 0; + } + if (stream->column >= STRING_ARRAY_MAX_COLUMN) { + _cairo_output_stream_printf (stream->output, "\n "); + stream->column = 1; + } + } + + return _cairo_output_stream_get_status (stream->output); +} + +static cairo_status_t +_base85_string_wrap_stream_close (cairo_output_stream_t *base) +{ + string_array_stream_t *stream = (string_array_stream_t *) base; + + if (!stream->use_strings || stream->string_size != 0) + _cairo_output_stream_printf (stream->output, "~>"); + + return _cairo_output_stream_get_status (stream->output); +} + +/* A _base85_strings_stream wraps an existing output stream. It takes + * base85 encoded data and splits it into strings each limited to + * STRING_ARRAY_MAX_STRING_SIZE bytes when decoded. Each string is + * enclosed in "<~" and "~>". + + * The string array stream is also careful to wrap the output within + * STRING_ARRAY_MAX_COLUMN columns. Wrapped lines start with a space + * in case an encoded line starts with %% which could be interpreted + * as a DSC comment. + */ +static cairo_output_stream_t * +_base85_strings_stream_create (cairo_output_stream_t *output) +{ + string_array_stream_t *stream; + + stream = _cairo_calloc (sizeof (string_array_stream_t)); + if (unlikely (stream == NULL)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_output_stream_t *) &_cairo_output_stream_nil; + } + + _cairo_output_stream_init (&stream->base, + _base85_string_wrap_stream_write, + NULL, + _base85_string_wrap_stream_close); + stream->output = output; + stream->column = 0; + stream->string_size = 0; + stream->tuple_count = 0; + stream->use_strings = TRUE; + + return &stream->base; +} + +/* A base85_wrap_stream wraps an existing output stream. It wraps the + * output within STRING_ARRAY_MAX_COLUMN columns. A base85 EOD "~>" is + * appended to the end. Wrapped lines start with a space in case an + * encoded line starts with %% which could be interpreted as a DSC + * comment. + */ +static cairo_output_stream_t * +_base85_wrap_stream_create (cairo_output_stream_t *output) +{ + string_array_stream_t *stream; + + stream = _cairo_calloc (sizeof (string_array_stream_t)); + if (unlikely (stream == NULL)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_output_stream_t *) &_cairo_output_stream_nil; + } + + _cairo_output_stream_init (&stream->base, + _base85_string_wrap_stream_write, + NULL, + _base85_string_wrap_stream_close); + stream->output = output; + stream->column = 0; + stream->string_size = 0; + stream->tuple_count = 0; + stream->use_strings = FALSE; + + return &stream->base; +} + + +/* PS Output - this section handles output of the parts of the recording + * surface we can render natively in PS. */ + +static cairo_status_t +_cairo_ps_surface_flatten_image_transparency (cairo_ps_surface_t *surface, + cairo_image_surface_t *image, + cairo_image_surface_t **opaque_image) +{ + cairo_surface_t *opaque; + cairo_surface_pattern_t pattern; + cairo_status_t status; + + opaque = cairo_image_surface_create (CAIRO_FORMAT_RGB24, + image->width, + image->height); + if (unlikely (opaque->status)) + return opaque->status; + + if (surface->content == CAIRO_CONTENT_COLOR_ALPHA) { + status = _cairo_surface_paint (opaque, + CAIRO_OPERATOR_SOURCE, + &_cairo_pattern_white.base, + NULL); + if (unlikely (status)) { + cairo_surface_destroy (opaque); + return status; + } + } + + _cairo_pattern_init_for_surface (&pattern, &image->base); + pattern.base.filter = CAIRO_FILTER_NEAREST; + status = _cairo_surface_paint (opaque, CAIRO_OPERATOR_OVER, &pattern.base, NULL); + _cairo_pattern_fini (&pattern.base); + if (unlikely (status)) { + cairo_surface_destroy (opaque); + return status; + } + + *opaque_image = (cairo_image_surface_t *) opaque; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_ps_surface_emit_base85_string (cairo_ps_surface_t *surface, + const unsigned char *data, + unsigned long length, + cairo_ps_compress_t compress, + cairo_bool_t use_strings) +{ + cairo_output_stream_t *base85_stream, *string_array_stream, *deflate_stream; + unsigned char *data_compressed; + unsigned long data_compressed_size; + cairo_status_t status, status2; + cairo_status_t this_cannot_be_handled; + + if (use_strings) + string_array_stream = _base85_strings_stream_create (surface->stream); + else + string_array_stream = _base85_wrap_stream_create (surface->stream); + + status = _cairo_output_stream_get_status (string_array_stream); + if (unlikely (status)) + return _cairo_output_stream_destroy (string_array_stream); + + base85_stream = _cairo_base85_stream_create (string_array_stream); + status = _cairo_output_stream_get_status (base85_stream); + if (unlikely (status)) { + status2 = _cairo_output_stream_destroy (string_array_stream); + return _cairo_output_stream_destroy (base85_stream); + } + + status = 0; + switch (compress) { + case CAIRO_PS_COMPRESS_NONE: + _cairo_output_stream_write (base85_stream, data, length); + break; + + case CAIRO_PS_COMPRESS_LZW: + /* XXX: Should fix cairo-lzw to provide a stream-based interface + * instead. */ + data_compressed_size = length; + data_compressed = _cairo_lzw_compress ((unsigned char*)data, &data_compressed_size); + if (unlikely (data_compressed == NULL)) { + this_cannot_be_handled = _cairo_output_stream_destroy (string_array_stream); + this_cannot_be_handled = _cairo_output_stream_destroy (base85_stream); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + _cairo_output_stream_write (base85_stream, data_compressed, data_compressed_size); + free (data_compressed); + break; + + case CAIRO_PS_COMPRESS_DEFLATE: + deflate_stream = _cairo_deflate_stream_create (base85_stream); + if (_cairo_output_stream_get_status (deflate_stream)) { + return _cairo_output_stream_destroy (deflate_stream); + } + _cairo_output_stream_write (deflate_stream, data, length); + status = _cairo_output_stream_destroy (deflate_stream); + if (unlikely (status)) { + this_cannot_be_handled = _cairo_output_stream_destroy (string_array_stream); + this_cannot_be_handled = _cairo_output_stream_destroy (base85_stream); + return status; + } + break; + } + status = _cairo_output_stream_destroy (base85_stream); + status2 = _cairo_output_stream_destroy (string_array_stream); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; + + return status; +} + +static const char * +get_interpolate (cairo_filter_t filter) +{ + const char *interpolate; + + switch (filter) { + default: + case CAIRO_FILTER_GOOD: + case CAIRO_FILTER_BEST: + case CAIRO_FILTER_BILINEAR: + interpolate = "true"; + break; + case CAIRO_FILTER_FAST: + case CAIRO_FILTER_NEAREST: + case CAIRO_FILTER_GAUSSIAN: + interpolate = "false"; + break; + } + + return interpolate; +} + +static cairo_status_t +_cairo_ps_surface_emit_image (cairo_ps_surface_t *surface, + cairo_emit_surface_mode_t mode, + cairo_emit_surface_params_t *params) +{ + cairo_status_t status; + unsigned char *data; + unsigned long data_size; + cairo_image_surface_t *ps_image; + int x, y, i, a; + cairo_image_transparency_t transparency; + cairo_bool_t use_mask; + uint32_t *pixel32; + uint8_t *pixel8; + int bit; + cairo_image_color_t color; + const char *interpolate; + cairo_ps_compress_t compress; + const char *compress_filter; + cairo_image_surface_t *image_surf; + cairo_image_surface_t *image; + void *image_extra; + + if (params->src_surface->status) + return params->src_surface->status; + + status = _cairo_surface_acquire_source_image (params->src_surface, &image_surf, &image_extra); + if (unlikely (status)) + return status; + + image = image_surf; + if (image->format != CAIRO_FORMAT_RGB24 && + image->format != CAIRO_FORMAT_ARGB32 && + image->format != CAIRO_FORMAT_A8 && + image->format != CAIRO_FORMAT_A1) + { + cairo_surface_t *surf; + cairo_surface_pattern_t pattern; + + surf = _cairo_image_surface_create_with_content (image->base.content, + image->width, + image->height); + if (surf->status) { + status = surf->status; + goto bail0; + } + + _cairo_pattern_init_for_surface (&pattern, &image->base); + status = _cairo_surface_paint (surf, + CAIRO_OPERATOR_SOURCE, &pattern.base, + NULL); + _cairo_pattern_fini (&pattern.base); + image = (cairo_image_surface_t *) surf; + if (unlikely (status)) + goto bail0; + } + ps_image = image; + interpolate = get_interpolate (params->filter); + + if (params->stencil_mask) { + use_mask = FALSE; + color = CAIRO_IMAGE_IS_MONOCHROME; + transparency = CAIRO_IMAGE_HAS_BILEVEL_ALPHA; + } else { + transparency = _cairo_image_analyze_transparency (image); + + /* PostScript can not represent the alpha channel, so we blend the + current image over a white (or black for CONTENT_COLOR + surfaces) RGB surface to eliminate it. */ + + if (params->op == CAIRO_OPERATOR_SOURCE || + transparency == CAIRO_IMAGE_HAS_ALPHA || + (transparency == CAIRO_IMAGE_HAS_BILEVEL_ALPHA && + surface->ps_level == CAIRO_PS_LEVEL_2)) + { + status = _cairo_ps_surface_flatten_image_transparency (surface, + image, + &ps_image); + if (unlikely (status)) + return status; + + use_mask = FALSE; + } else if (transparency == CAIRO_IMAGE_IS_OPAQUE) { + use_mask = FALSE; + } else { /* transparency == CAIRO_IMAGE_HAS_BILEVEL_ALPHA */ + use_mask = TRUE; + } + + color = _cairo_image_analyze_color (ps_image); + } + + /* Type 2 (mask and image interleaved) has the mask and image + * samples interleaved by row. The mask row is first, one bit per + * pixel with (bit 7 first). The row is padded to byte + * boundaries. The image data is 3 bytes per pixel RGB format. */ + switch (color) { + default: + case CAIRO_IMAGE_UNKNOWN_COLOR: + ASSERT_NOT_REACHED; + case CAIRO_IMAGE_IS_COLOR: + data_size = ps_image->width * 3; + break; + case CAIRO_IMAGE_IS_GRAYSCALE: + data_size = ps_image->width; + break; + case CAIRO_IMAGE_IS_MONOCHROME: + data_size = (ps_image->width + 7)/8; + break; + } + if (use_mask) + data_size += (ps_image->width + 7)/8; + data_size *= ps_image->height; + data = _cairo_malloc (data_size); + if (unlikely (data == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto bail1; + } + + i = 0; + for (y = 0; y < ps_image->height; y++) { + if (params->stencil_mask || use_mask) { + /* mask row */ + if (ps_image->format == CAIRO_FORMAT_A1) { + pixel8 = (uint8_t *) (ps_image->data + y * ps_image->stride); + + for (x = 0; x < (ps_image->width + 7) / 8; x++, pixel8++) { + a = *pixel8; + a = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (a); + data[i++] = a; + } + } else { + pixel8 = (uint8_t *) (ps_image->data + y * ps_image->stride); + pixel32 = (uint32_t *) (ps_image->data + y * ps_image->stride); + bit = 7; + for (x = 0; x < ps_image->width; x++) { + if (ps_image->format == CAIRO_FORMAT_ARGB32) { + a = (*pixel32 & 0xff000000) >> 24; + pixel32++; + } else { + a = *pixel8; + pixel8++; + } + + if (transparency == CAIRO_IMAGE_HAS_ALPHA) { + data[i++] = a; + } else { /* transparency == CAIRO_IMAGE_HAS_BILEVEL_ALPHA or CAIRO_IMAGE_IS_OPAQUE */ + if (bit == 7) + data[i] = 0; + if (a != 0) + data[i] |= (1 << bit); + bit--; + if (bit < 0) { + bit = 7; + i++; + } + } + } + if (bit != 7) + i++; + } + } + if (params->stencil_mask) + continue; + + /* image row*/ + pixel32 = (uint32_t *) (ps_image->data + y * ps_image->stride); + bit = 7; + for (x = 0; x < ps_image->width; x++, pixel32++) { + int r, g, b; + + if (ps_image->format == CAIRO_FORMAT_ARGB32) { + /* At this point ARGB32 images are either opaque or + * bilevel alpha so we don't need to unpremultiply. */ + if (((*pixel32 & 0xff000000) >> 24) == 0) { + r = g = b = 0; + } else { + r = (*pixel32 & 0x00ff0000) >> 16; + g = (*pixel32 & 0x0000ff00) >> 8; + b = (*pixel32 & 0x000000ff) >> 0; + } + } else if (ps_image->format == CAIRO_FORMAT_RGB24) { + r = (*pixel32 & 0x00ff0000) >> 16; + g = (*pixel32 & 0x0000ff00) >> 8; + b = (*pixel32 & 0x000000ff) >> 0; + } else { + r = g = b = 0; + } + + switch (color) { + case CAIRO_IMAGE_IS_COLOR: + case CAIRO_IMAGE_UNKNOWN_COLOR: + data[i++] = r; + data[i++] = g; + data[i++] = b; + break; + + case CAIRO_IMAGE_IS_GRAYSCALE: + data[i++] = r; + break; + + case CAIRO_IMAGE_IS_MONOCHROME: + if (bit == 7) + data[i] = 0; + if (r != 0) + data[i] |= (1 << bit); + bit--; + if (bit < 0) { + bit = 7; + i++; + } + break; + } + } + if (bit != 7) + i++; + } + + if (surface->ps_level == CAIRO_PS_LEVEL_2) { + compress = CAIRO_PS_COMPRESS_LZW; + compress_filter = "LZWDecode"; + } else { + compress = CAIRO_PS_COMPRESS_DEFLATE; + compress_filter = "FlateDecode"; + surface->ps_level_used = CAIRO_PS_LEVEL_3; + } + + if (surface->paint_proc) { + /* Emit the image data as a base85-encoded string which will + * be used as the data source for the image operator later. */ + _cairo_output_stream_printf (surface->stream, + "/CairoData [\n"); + + status = _cairo_ps_surface_emit_base85_string (surface, + data, + data_size, + compress, + TRUE); + if (unlikely (status)) + goto bail2; + + _cairo_output_stream_printf (surface->stream, + "] def\n"); + _cairo_output_stream_printf (surface->stream, + "/CairoDataIndex 0 def\n"); + } else { + _cairo_output_stream_printf (surface->stream, + "/cairo_ascii85_file currentfile /ASCII85Decode filter def\n"); + } + + if (use_mask) { + _cairo_output_stream_printf (surface->stream, + "%s setcolorspace\n" + "<<\n" + " /ImageType 3\n" + " /InterleaveType 2\n" + " /DataDict <<\n" + " /ImageType 1\n" + " /Width %d\n" + " /Height %d\n" + " /Interpolate %s\n" + " /BitsPerComponent %d\n" + " /Decode [ %s ]\n", + color == CAIRO_IMAGE_IS_COLOR ? "/DeviceRGB" : "/DeviceGray", + ps_image->width, + ps_image->height, + interpolate, + color == CAIRO_IMAGE_IS_MONOCHROME ? 1 : 8, + color == CAIRO_IMAGE_IS_COLOR ? "0 1 0 1 0 1" : "0 1"); + + if (surface->paint_proc) { + _cairo_output_stream_printf (surface->stream, + " /DataSource { cairo_data_source } /%s filter\n", + compress_filter); + } else { + _cairo_output_stream_printf (surface->stream, + " /DataSource cairo_ascii85_file /%s filter\n", + compress_filter); + } + + _cairo_output_stream_printf (surface->stream, + " /ImageMatrix [ %d 0 0 %d 0 %d ]\n" + " >>\n" + " /MaskDict <<\n" + " /ImageType 1\n" + " /Width %d\n" + " /Height %d\n" + " /Interpolate %s\n" + " /BitsPerComponent 1\n" + " /Decode [ 1 0 ]\n" + " /ImageMatrix [ %d 0 0 %d 0 %d ]\n" + " >>\n" + ">>\n" + "image\n", + ps_image->width, + -ps_image->height, + ps_image->height, + ps_image->width, + ps_image->height, + interpolate, + ps_image->width, + -ps_image->height, + ps_image->height); + } else { + const char *decode; + + if (!params->stencil_mask) { + _cairo_output_stream_printf (surface->stream, + "%s setcolorspace\n", + color == CAIRO_IMAGE_IS_COLOR ? "/DeviceRGB" : "/DeviceGray"); + } + if (params->stencil_mask) + decode = "1 0"; + else if (color == CAIRO_IMAGE_IS_COLOR) + decode = "0 1 0 1 0 1"; + else + decode ="0 1"; + + _cairo_output_stream_printf (surface->stream, + "<<\n" + " /ImageType 1\n" + " /Width %d\n" + " /Height %d\n" + " /Interpolate %s\n" + " /BitsPerComponent %d\n" + " /Decode [ %s ]\n", + ps_image->width, + ps_image->height, + interpolate, + color == CAIRO_IMAGE_IS_MONOCHROME ? 1 : 8, + decode); + if (surface->paint_proc) { + _cairo_output_stream_printf (surface->stream, + " /DataSource { cairo_data_source } /%s filter\n", + compress_filter); + } else { + _cairo_output_stream_printf (surface->stream, + " /DataSource cairo_ascii85_file /%s filter\n", + compress_filter); + } + + _cairo_output_stream_printf (surface->stream, + " /ImageMatrix [ %d 0 0 %d 0 %d ]\n" + ">>\n" + "%s%s\n", + ps_image->width, + -ps_image->height, + ps_image->height, + surface->paint_proc ? "" : "cairo_", + params->stencil_mask ? "imagemask" : "image"); + } + + if (!surface->paint_proc) { + /* Emit the image data as a base85-encoded string which will + * be used as the data source for the image operator. */ + status = _cairo_ps_surface_emit_base85_string (surface, + data, + data_size, + compress, + FALSE); + _cairo_output_stream_printf (surface->stream, "\n"); + } else { + status = CAIRO_STATUS_SUCCESS; + } + +bail2: + free (data); + +bail1: + if (!use_mask && ps_image != image) + cairo_surface_destroy (&ps_image->base); + +bail0: + if (image != image_surf) + cairo_surface_destroy (&image->base); + + _cairo_surface_release_source_image (params->src_surface, image_surf, image_extra); + + return status; +} + +static cairo_int_status_t +_cairo_ps_surface_emit_jpeg_image (cairo_ps_surface_t *surface, + cairo_emit_surface_mode_t mode, + cairo_emit_surface_params_t *params) +{ + cairo_status_t status; + const unsigned char *mime_data; + unsigned long mime_data_length; + cairo_image_info_t info; + const char *colorspace; + const char *decode; + + if (unlikely (params->src_surface->status)) + return params->src_surface->status; + + cairo_surface_get_mime_data (params->src_surface, CAIRO_MIME_TYPE_JPEG, + &mime_data, &mime_data_length); + if (mime_data == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_image_info_get_jpeg_info (&info, mime_data, mime_data_length); + if (unlikely (status)) + return status; + + switch (info.num_components) { + case 1: + colorspace = "/DeviceGray"; + decode = "0 1"; + break; + case 3: + colorspace = "/DeviceRGB"; + decode = "0 1 0 1 0 1"; + break; + case 4: + colorspace = "/DeviceCMYK"; + decode = "0 1 0 1 0 1 0 1"; + break; + default: + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + /* At this point we know emitting jpeg will succeed. */ + if (mode == CAIRO_EMIT_SURFACE_ANALYZE) { + params->is_image = TRUE; + params->approx_size = mime_data_length; + return CAIRO_STATUS_SUCCESS; + } + + if (surface->paint_proc) { + /* Emit the image data as a base85-encoded string which will + * be used as the data source for the image operator later. */ + _cairo_output_stream_printf (surface->stream, + "/CairoData [\n"); + + status = _cairo_ps_surface_emit_base85_string (surface, + mime_data, + mime_data_length, + CAIRO_PS_COMPRESS_NONE, + TRUE); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->stream, + "] def\n"); + _cairo_output_stream_printf (surface->stream, + "/CairoDataIndex 0 def\n"); + } else { + _cairo_output_stream_printf (surface->stream, + "/cairo_ascii85_file currentfile /ASCII85Decode filter def\n"); + } + + _cairo_output_stream_printf (surface->stream, + "%s setcolorspace\n" + "<<\n" + " /ImageType 1\n" + " /Width %d\n" + " /Height %d\n" + " /BitsPerComponent %d\n" + " /Interpolate %s\n" + " /Decode [ %s ]\n", + colorspace, + info.width, + info.height, + info.bits_per_component, + get_interpolate (params->filter), + decode); + + if (surface->paint_proc) { + _cairo_output_stream_printf (surface->stream, + " /DataSource { cairo_data_source } /DCTDecode filter\n"); + } else { + _cairo_output_stream_printf (surface->stream, + " /DataSource cairo_ascii85_file /DCTDecode filter\n"); + } + + _cairo_output_stream_printf (surface->stream, + " /ImageMatrix [ %d 0 0 %d 0 %d ]\n" + ">>\n" + "%simage\n", + info.width, + -info.height, + info.height, + surface->paint_proc ? "" : "cairo_"); + + if (!surface->paint_proc) { + /* Emit the image data as a base85-encoded string which will + * be used as the data source for the image operator. */ + status = _cairo_ps_surface_emit_base85_string (surface, + mime_data, + mime_data_length, + CAIRO_PS_COMPRESS_NONE, + FALSE); + } + + return status; +} + +static cairo_int_status_t +_cairo_ps_surface_emit_ccitt_image (cairo_ps_surface_t *surface, + cairo_emit_surface_mode_t mode, + cairo_emit_surface_params_t *params) +{ + cairo_status_t status; + const unsigned char *ccitt_data; + unsigned long ccitt_data_len; + const unsigned char *ccitt_params_data; + unsigned long ccitt_params_data_len; + char *ccitt_params_string; + cairo_ccitt_params_t ccitt_params; + + if (unlikely (params->src_surface->status)) + return params->src_surface->status; + + cairo_surface_get_mime_data (params->src_surface, CAIRO_MIME_TYPE_CCITT_FAX, + &ccitt_data, &ccitt_data_len); + if (ccitt_data == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + cairo_surface_get_mime_data (params->src_surface, CAIRO_MIME_TYPE_CCITT_FAX_PARAMS, + &ccitt_params_data, &ccitt_params_data_len); + if (ccitt_params_data == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* ensure params_string is null terminated */ + ccitt_params_string = _cairo_strndup ((const char *)ccitt_params_data, ccitt_params_data_len); + if (unlikely (ccitt_params_string == NULL)) + return _cairo_surface_set_error (&surface->base, CAIRO_STATUS_NO_MEMORY); + + status = _cairo_tag_parse_ccitt_params (ccitt_params_string, &ccitt_params); + if (unlikely(status)) + return status; + + free (ccitt_params_string); + + if (ccitt_params.columns <= 0 || ccitt_params.rows <= 0) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* At this point we know emitting ccitt will succeed. */ + if (mode == CAIRO_EMIT_SURFACE_ANALYZE) { + params->is_image = TRUE; + params->approx_size = ccitt_data_len; + return CAIRO_STATUS_SUCCESS; + } + + if (surface->paint_proc) { + /* Emit the image data as a base85-encoded string which will + * be used as the data source for the image operator later. */ + _cairo_output_stream_printf (surface->stream, + "/CairoData [\n"); + + status = _cairo_ps_surface_emit_base85_string (surface, + ccitt_data, + ccitt_data_len, + CAIRO_PS_COMPRESS_NONE, + TRUE); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->stream, + "] def\n"); + _cairo_output_stream_printf (surface->stream, + "/CairoDataIndex 0 def\n"); + } else { + _cairo_output_stream_printf (surface->stream, + "/cairo_ascii85_file currentfile /ASCII85Decode filter def\n"); + } + + if (!params->stencil_mask) { + _cairo_output_stream_printf (surface->stream, + "/DeviceGray setcolorspace\n"); + } + + _cairo_output_stream_printf (surface->stream, + "<<\n" + " /ImageType 1\n" + " /Width %d\n" + " /Height %d\n" + " /BitsPerComponent 1\n" + " /Interpolate %s\n" + " /Decode [ 0 1 ]\n", + ccitt_params.columns, + ccitt_params.rows, + get_interpolate (params->filter)); + + if (surface->paint_proc) { + _cairo_output_stream_printf (surface->stream, + " /DataSource { cairo_data_source }\n"); + } else { + _cairo_output_stream_printf (surface->stream, + " /DataSource cairo_ascii85_file\n"); + } + + _cairo_output_stream_printf (surface->stream, + " << /Columns %d /Rows %d /K %d\n", + ccitt_params.columns, + ccitt_params.rows, + ccitt_params.k); + + if (ccitt_params.end_of_line) + _cairo_output_stream_printf (surface->stream, " /EndOfLine true\n"); + + if (ccitt_params.encoded_byte_align) + _cairo_output_stream_printf (surface->stream, " /EncodedByteAlign true\n"); + + if (!ccitt_params.end_of_block) + _cairo_output_stream_printf (surface->stream, " /EndOfBlock false\n"); + + if (ccitt_params.black_is_1) + _cairo_output_stream_printf (surface->stream, " /BlackIs1 true\n"); + + if (ccitt_params.damaged_rows_before_error > 0) { + _cairo_output_stream_printf (surface->stream, + " /DamagedRowsBeforeError %d\n", + ccitt_params.damaged_rows_before_error); + } + + _cairo_output_stream_printf (surface->stream, + " >> /CCITTFaxDecode filter\n"); + + _cairo_output_stream_printf (surface->stream, + " /ImageMatrix [ %d 0 0 %d 0 %d ]\n" + ">>\n" + "%s%s\n", + ccitt_params.columns, + -ccitt_params.rows, + ccitt_params.rows, + surface->paint_proc ? "" : "cairo_", + params->stencil_mask ? "imagemask" : "image"); + + if (!surface->paint_proc) { + /* Emit the image data as a base85-encoded string which will + * be used as the data source for the image operator. */ + status = _cairo_ps_surface_emit_base85_string (surface, + ccitt_data, + ccitt_data_len, + CAIRO_PS_COMPRESS_NONE, + FALSE); + } + + return status; +} + +/* The '|' character is not used in PS (including ASCII85). We can + * speed up the search by first searching for the first char before + * comparing strings. + */ +#define SUBFILE_FILTER_EOD "|EOD|" + +/* Count number of non overlapping occurrences of SUBFILE_FILTER_EOD in data. */ +static int +count_eod_strings (const unsigned char *data, unsigned long data_len) +{ + const unsigned char *p = data; + const unsigned char *end; + int first_char, len, count; + const char *eod_str = SUBFILE_FILTER_EOD; + + first_char = eod_str[0]; + len = strlen (eod_str); + p = data; + end = data + data_len - len + 1; + count = 0; + while (p < end) { + p = memchr (p, first_char, end - p); + if (!p) + break; + + if (memcmp (p, eod_str, len) == 0) { + count++; + p += len; + } + } + + return count; +} + +static cairo_status_t +_cairo_ps_surface_emit_eps (cairo_ps_surface_t *surface, + cairo_emit_surface_mode_t mode, + cairo_emit_surface_params_t *params) +{ + cairo_status_t status; + const unsigned char *eps_data = NULL; + unsigned long eps_data_len; + const unsigned char *eps_params_string = NULL; + unsigned long eps_params_string_len; + char *params_string = NULL; + cairo_eps_params_t eps_params; + cairo_matrix_t mat; + double eps_width, eps_height; + + if (unlikely (params->src_surface->status)) + return params->src_surface->status; + + /* We only embed EPS with level 3 as we may use ReusableStreamDecode and we + * don't know what level the EPS file requires. */ + if (surface->ps_level == CAIRO_PS_LEVEL_2) + return CAIRO_INT_STATUS_UNSUPPORTED; + + cairo_surface_get_mime_data (params->src_surface, CAIRO_MIME_TYPE_EPS, + &eps_data, &eps_data_len); + if (eps_data == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + cairo_surface_get_mime_data (params->src_surface, CAIRO_MIME_TYPE_EPS_PARAMS, + &eps_params_string, &eps_params_string_len); + if (eps_params_string == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* ensure params_string is null terminated */ + params_string = _cairo_strndup ((const char *)eps_params_string, eps_params_string_len); + if (unlikely (params_string == NULL)) + return _cairo_surface_set_error (&surface->base, CAIRO_STATUS_NO_MEMORY); + + status = _cairo_tag_parse_eps_params (params_string, &eps_params); + if (unlikely(status)) + return status; + + /* At this point we know emitting EPS will succeed. */ + if (mode == CAIRO_EMIT_SURFACE_ANALYZE) { + params->is_image = FALSE; + params->approx_size = eps_data_len; + surface->contains_eps = TRUE; + + /* Find number of occurrences of SUBFILE_FILTER_EOD in the EPS data. + * We will need it before emitting the data if a ReusableStream is used. + */ + params->eod_count = count_eod_strings (eps_data, eps_data_len); + return CAIRO_STATUS_SUCCESS; + } + + surface->ps_level_used = CAIRO_PS_LEVEL_3; + _cairo_output_stream_printf (surface->stream, "cairo_eps_begin\n"); + + eps_width = eps_params.bbox.p2.x - eps_params.bbox.p1.x; + eps_height = eps_params.bbox.p2.y - eps_params.bbox.p1.y; + cairo_matrix_init_translate (&mat, + params->src_surface_extents->x, + params->src_surface_extents->y); + cairo_matrix_scale (&mat, + params->src_surface_extents->width/eps_width, + params->src_surface_extents->height/eps_height); + cairo_matrix_scale (&mat, 1, -1); + cairo_matrix_translate (&mat, -eps_params.bbox.p1.x, -eps_params.bbox.p2.y); + + if (! _cairo_matrix_is_identity (&mat)) { + _cairo_output_stream_printf (surface->stream, "[ "); + _cairo_output_stream_print_matrix (surface->stream, &mat); + _cairo_output_stream_printf (surface->stream, " ] concat\n"); + } + + _cairo_output_stream_printf (surface->stream, + "%f %f %f %f rectclip\n", + eps_params.bbox.p1.x, + eps_params.bbox.p1.y, + eps_width, + eps_height); + + _cairo_output_stream_printf (surface->stream, + "%%%%BeginDocument: Document%d\n", + params->src_surface->unique_id); + _cairo_output_stream_write (surface->stream, eps_data, eps_data_len); + _cairo_output_stream_printf (surface->stream, "%%%%EndDocument"); + _cairo_output_stream_printf (surface->stream, "\ncairo_eps_end\n"); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_ps_surface_emit_recording_surface (cairo_ps_surface_t *surface, + cairo_surface_t *recording_surface, + unsigned int regions_id, + const cairo_rectangle_int_t *recording_extents, + cairo_bool_t subsurface) +{ + double old_width, old_height; + cairo_rectangle_int_t old_surface_extents; + cairo_bool_t old_surface_bounded; + cairo_matrix_t old_cairo_to_ps; + cairo_content_t old_content; + cairo_surface_clipper_t old_clipper; + cairo_int_status_t status; + cairo_surface_t *free_me = NULL; + unsigned int id; + int i, recording_surf_stack_size; + + /* Prevent infinite recursion if the recording_surface references a recording + * currently being emitted */ + recording_surf_stack_size = _cairo_array_num_elements (&surface->recording_surf_stack); + for (i = 0; i < recording_surf_stack_size; i++) { + _cairo_array_copy_element (&surface->recording_surf_stack, i, &id); + if (id == recording_surface->unique_id) + return CAIRO_STATUS_SUCCESS; + } + id = recording_surface->unique_id; + status = _cairo_array_append (&surface->recording_surf_stack, &id); + if (unlikely (status)) + return status; + + if (_cairo_surface_is_snapshot (recording_surface)) + free_me = recording_surface = _cairo_surface_snapshot_get_target (recording_surface); + + old_content = surface->content; + old_width = surface->width; + old_height = surface->height; + old_surface_extents = surface->surface_extents; + old_surface_bounded = surface->surface_bounded; + old_cairo_to_ps = surface->cairo_to_ps; + old_clipper = surface->clipper; + _cairo_surface_clipper_init (&surface->clipper, + _cairo_ps_surface_clipper_intersect_clip_path); + +#if DEBUG_PS + _cairo_output_stream_printf (surface->stream, + "%% _cairo_ps_surface_emit_recording_surface" + " x: %d, y: %d, w: %d, h: %d subsurface: %d\n", + recording_extents->x, recording_extents->y, + recording_extents->width, recording_extents->height, + subsurface); +#endif + + surface->width = recording_extents->width; + surface->height = recording_extents->height; + surface->surface_extents = *recording_extents; + surface->current_pattern_is_solid_color = FALSE; + _cairo_pdf_operators_reset (&surface->pdf_operators); + cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, 1, 0, 0); + _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators, + &surface->cairo_to_ps); + _cairo_output_stream_printf (surface->stream, " q\n"); + + if (recording_surface->content == CAIRO_CONTENT_COLOR) { + surface->content = CAIRO_CONTENT_COLOR; + _cairo_output_stream_printf (surface->stream, + " 0 g %d %d %d %d rectfill\n", + recording_extents->x, + recording_extents->y, + recording_extents->width, + recording_extents->height); + } + + status = _cairo_recording_surface_replay_region (recording_surface, + regions_id, + subsurface ? recording_extents : NULL, + &surface->base, + CAIRO_RECORDING_REGION_NATIVE); + assert (status != CAIRO_INT_STATUS_UNSUPPORTED); + if (unlikely (status)) + return status; + + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->stream, " Q\n"); + + _cairo_surface_clipper_reset (&surface->clipper); + surface->clipper = old_clipper; + surface->content = old_content; + surface->width = old_width; + surface->height = old_height; + surface->surface_extents = old_surface_extents; + surface->surface_bounded = old_surface_bounded; + surface->current_pattern_is_solid_color = FALSE; + _cairo_pdf_operators_reset (&surface->pdf_operators); + surface->cairo_to_ps = old_cairo_to_ps; + + _cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators, + &surface->cairo_to_ps); + cairo_surface_destroy (free_me); + + _cairo_array_truncate (&surface->recording_surf_stack, recording_surf_stack_size); + + return status; +} + +static void +_cairo_ps_surface_flatten_transparency (cairo_ps_surface_t *surface, + const cairo_color_t *color, + double *red, + double *green, + double *blue) +{ + *red = color->red; + *green = color->green; + *blue = color->blue; + + if (! CAIRO_COLOR_IS_OPAQUE (color)) { + *red *= color->alpha; + *green *= color->alpha; + *blue *= color->alpha; + if (surface->content == CAIRO_CONTENT_COLOR_ALPHA) { + double one_minus_alpha = 1. - color->alpha; + *red += one_minus_alpha; + *green += one_minus_alpha; + *blue += one_minus_alpha; + } + } +} + +static void +_cairo_ps_surface_emit_solid_pattern (cairo_ps_surface_t *surface, + cairo_solid_pattern_t *pattern) +{ + double red, green, blue; + + _cairo_ps_surface_flatten_transparency (surface, &pattern->color, &red, &green, &blue); + + if (color_is_gray (red, green, blue)) + _cairo_output_stream_printf (surface->stream, + "%f g\n", + red); + else + _cairo_output_stream_printf (surface->stream, + "%f %f %f rg\n", + red, green, blue); +} + +/* + * PS Forms are used for sources that have CAIRO_MIME_TYPE_UNIQUE_ID. They will be + * emitted once in the PS header and can be rendered with the 'execform' operator. + * + * This function tries adding the source the form hash table. If the source does not + * have CAIRO_MIME_TYPE_UNIQUE_ID, CAIRO_INT_STATUS_UNSUPPORTED is returned. + + * @source: [in] the source for the form + * @params: [in] source parameters + * @test: [in] if TRUE, test if form will be used (excludes size check) + * @ps_form [out] the new or existing entry int the hash table. + * image or recording. + */ +static cairo_int_status_t +_cairo_ps_surface_use_form (cairo_ps_surface_t *surface, + cairo_emit_surface_params_t *params, + cairo_bool_t test, + cairo_ps_form_t **ps_form) +{ + cairo_ps_form_t source_key; + cairo_ps_form_t *source_entry; + unsigned char *unique_id = NULL; + unsigned long unique_id_length = 0; + cairo_status_t status; + long max_size; + + if (params->op != CAIRO_OPERATOR_OVER || params->stencil_mask) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (params->src_surface->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) + return CAIRO_INT_STATUS_UNSUPPORTED; + + cairo_surface_get_mime_data (params->src_surface, CAIRO_MIME_TYPE_UNIQUE_ID, + (const unsigned char **) &source_key.unique_id, + &source_key.unique_id_length); + if (source_key.unique_id == NULL || source_key.unique_id_length == 0) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (test) + return CAIRO_STATUS_SUCCESS; + + source_key.filter = params->filter; + _cairo_ps_form_init_key (&source_key); + source_entry = _cairo_hash_table_lookup (surface->forms, &source_key.base); + if (source_entry) { + _cairo_rectangle_union (&source_entry->required_extents, params->src_op_extents); + *ps_form = source_entry; + return CAIRO_STATUS_SUCCESS; + } + + if (surface->ps_level == CAIRO_PS_LEVEL_3) + max_size = MAX_L3_FORM_DATA; + else + max_size = MAX_L2_FORM_DATA; + + /* Don't add any more Forms if we exceed the form memory limit */ + if (surface->total_form_size + params->approx_size > max_size) + return CAIRO_INT_STATUS_UNSUPPORTED; + + surface->total_form_size += params->approx_size; + unique_id = _cairo_malloc (source_key.unique_id_length); + if (unique_id == NULL) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + unique_id_length = source_key.unique_id_length; + memcpy (unique_id, source_key.unique_id, unique_id_length); + + source_entry = _cairo_calloc (sizeof (cairo_ps_form_t)); + if (source_entry == NULL) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto fail; + } + + source_entry->unique_id_length = unique_id_length; + source_entry->unique_id = unique_id; + source_entry->id = surface->num_forms++; + source_entry->src_surface = cairo_surface_reference (params->src_surface); + source_entry->regions_id = params->regions_id; + if (_cairo_surface_is_recording (source_entry->src_surface) && source_entry->regions_id != 0) + _cairo_recording_surface_region_array_reference (source_entry->src_surface, source_entry->regions_id); + source_entry->src_surface_extents = *params->src_surface_extents; + source_entry->src_surface_bounded = params->src_surface_bounded; + source_entry->required_extents = *params->src_op_extents; + source_entry->filter = params->filter; + source_entry->is_image = params->is_image; + _cairo_ps_form_init_key (source_entry); + status = _cairo_hash_table_insert (surface->forms, &source_entry->base); + if (unlikely(status)) + goto fail; + + *ps_form = source_entry; + return CAIRO_STATUS_SUCCESS; + + fail: + free (unique_id); + free (source_entry); + return status; +} + +static cairo_int_status_t +_cairo_ps_surface_emit_form (cairo_ps_surface_t *surface, + cairo_emit_surface_params_t *params, + cairo_bool_t test) +{ + cairo_ps_form_t *ps_form = NULL; + cairo_status_t status; + + status = _cairo_ps_surface_use_form (surface, + params, + test, + &ps_form); + if (test || status) + return status; + + /* _cairo_ps_form_emit will use Level 3 if permitted by ps_level */ + if (surface->ps_level == CAIRO_PS_LEVEL_3) + surface->ps_level_used = CAIRO_PS_LEVEL_3; + + _cairo_output_stream_printf (surface->stream, + "/cairoform-%d /Form findresource execform\n", + ps_form->id); + + return CAIRO_STATUS_SUCCESS; +} + +/* Emit a surface. This function has three modes. + * + * CAIRO_EMIT_SURFACE_ANALYZE: This will determine the surface type to + * be emitted and approximate size. is_image is set to TRUE if the + * emitted surface is an image surface (including mime images). This + * is used by the caller to setup the correct CTM. approx_size is set + * to the approximate size of the emitted surface and is used as an + * input by the emit mode. + * + * CAIRO_EMIT_SURFACE_EMIT: Emits the surface will be emitted. The + * approx_size and the surface unique id values are used to determine + * if a Form should be used. If a form is used, the exec form + * operation is emitted and the surface is added to the forms hash + * table. + * + * CAIRO_EMIT_SURFACE_EMIT_FORM: Emits the form definition for the surface. + * + * Usage is: + * 1) Setup input params and call with ANALYZE. + * 2) Setup CTM for surface and call with EMIT using same params struct. + * The EMIT_FORM mode is used when emitting the form definitions. + */ +static cairo_int_status_t +_cairo_ps_surface_emit_surface (cairo_ps_surface_t *surface, + cairo_emit_surface_mode_t mode, + cairo_emit_surface_params_t *params) +{ + cairo_int_status_t status; + cairo_output_stream_t *old_stream = NULL; + cairo_bool_t use_form; + + /* Try emitting as a form. Returns unsupported if the surface is + * deemed unsuitable for a form. */ + use_form = FALSE; + if (mode == CAIRO_EMIT_SURFACE_ANALYZE || mode == CAIRO_EMIT_SURFACE_EMIT) { + status = _cairo_ps_surface_emit_form (surface, + params, + mode == CAIRO_EMIT_SURFACE_ANALYZE); + use_form = (status == CAIRO_INT_STATUS_SUCCESS); + if (status != CAIRO_INT_STATUS_SUCCESS && status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + if (mode == CAIRO_EMIT_SURFACE_EMIT && status == CAIRO_INT_STATUS_SUCCESS) + return status; + } + + status = _cairo_ps_surface_emit_eps (surface, mode, params); + if (status == CAIRO_INT_STATUS_SUCCESS) { + params->is_image = FALSE; + goto surface_emitted; + } + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + status = _cairo_ps_surface_emit_jpeg_image (surface, mode, params); + if (status == CAIRO_INT_STATUS_SUCCESS) { + params->is_image = TRUE; + goto surface_emitted; + } + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + status = _cairo_ps_surface_emit_ccitt_image (surface, mode, params); + if (status == CAIRO_INT_STATUS_SUCCESS) { + params->is_image = TRUE; + goto surface_emitted; + } + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + if (mode == CAIRO_EMIT_SURFACE_ANALYZE) { + /* Find size of image or recording surface by emitting to a memory stream */ + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (unlikely (status)) + return status; + + old_stream = surface->stream; + surface->stream = _cairo_memory_stream_create (); + _cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->stream); + } + + if (params->src_surface->type == CAIRO_SURFACE_TYPE_RECORDING) { + params->is_image = FALSE; + if (params->src_surface->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) { + cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) params->src_surface; + status = _cairo_ps_surface_emit_recording_surface (surface, + sub->target, + params->regions_id, + &sub->extents, + TRUE); + } else { + status = _cairo_ps_surface_emit_recording_surface (surface, + params->src_surface, + params->regions_id, + params->src_op_extents, + FALSE); + } + } else { + params->is_image = TRUE; + status = _cairo_ps_surface_emit_image (surface, mode, params); + } + + if (mode == CAIRO_EMIT_SURFACE_ANALYZE) { + unsigned char *data; + unsigned long length; + + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (unlikely (status)) + return status; + + status = _cairo_memory_stream_destroy (surface->stream, &data, &length); + free (data); + surface->stream = old_stream; + if (unlikely (status)) + return status; + + params->approx_size = length; + _cairo_pdf_operators_set_stream (&surface->pdf_operators, + surface->stream); + } + + surface_emitted: + + return status; +} + +static void +_cairo_ps_form_emit (void *entry, void *closure) +{ + cairo_ps_form_t *form = entry; + cairo_ps_surface_t *surface = closure; + cairo_emit_surface_params_t params; + cairo_int_status_t status; + cairo_output_stream_t *old_stream; + + params.src_surface = form->src_surface; + params.regions_id = form->regions_id; + params.op = CAIRO_OPERATOR_OVER; + params.src_surface_extents = &form->src_surface_extents; + params.src_surface_bounded = form->src_surface_bounded; + params.src_op_extents = &form->required_extents; + params.filter = form->filter; + params.stencil_mask = FALSE; + params.is_image = form->is_image; + params.approx_size = 0; + params.eod_count = 0; + + _cairo_output_stream_printf (surface->final_stream, + "%%%%BeginResource: form cairoform-%d\n", + form->id); + + _cairo_output_stream_printf (surface->final_stream, + "/cairo_paint_form-%d", + form->id); + if (surface->ps_level == CAIRO_PS_LEVEL_3) { + surface->paint_proc = FALSE; + _cairo_output_stream_printf (surface->final_stream, + "\n" + "currentfile\n" + "<< /Filter /SubFileDecode\n" + " /DecodeParms << /EODString (%s) /EODCount 0 >>\n" + ">> /ReusableStreamDecode filter\n", + SUBFILE_FILTER_EOD); + } else { + surface->paint_proc = TRUE; + _cairo_output_stream_printf (surface->final_stream, + " {\n"); + } + _cairo_output_stream_printf (surface->final_stream, + "5 dict begin\n"); + + old_stream = surface->stream; + surface->stream = surface->final_stream; + _cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->stream); + status = _cairo_ps_surface_emit_surface (surface, + CAIRO_EMIT_SURFACE_EMIT_FORM, + ¶ms); + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + surface->stream = old_stream; + _cairo_pdf_operators_set_stream (&surface->pdf_operators, surface->stream); + + _cairo_output_stream_printf (surface->final_stream, + "end\n"); + if (surface->ps_level == CAIRO_PS_LEVEL_3) { + _cairo_output_stream_printf (surface->final_stream, + "%s\n" + "def\n", + SUBFILE_FILTER_EOD); + } else { + _cairo_output_stream_printf (surface->final_stream, + "} bind def\n"); + } + + _cairo_output_stream_printf (surface->final_stream, + "\n" + "/cairoform-%d\n" + "<<\n" + " /FormType 1\n", + form->id); + + if (form->is_image) { + _cairo_output_stream_printf (surface->final_stream, + " /BBox [ 0 0 1 1 ]\n"); + } else { + _cairo_output_stream_printf (surface->final_stream, + " /BBox [ %d %d %d %d ]\n", + form->required_extents.x, + form->required_extents.y, + form->required_extents.x + form->required_extents.width, + form->required_extents.y + form->required_extents.height); + } + + _cairo_output_stream_printf (surface->final_stream, + " /Matrix [ 1 0 0 1 0 0 ]\n" + " /PaintProc { pop cairo_paint_form-%d", + form->id); + + if (surface->ps_level == CAIRO_PS_LEVEL_3) { + _cairo_output_stream_printf (surface->final_stream, + " dup 0 setfileposition cvx exec"); + } + _cairo_output_stream_printf (surface->final_stream, + " } bind\n" + ">>\n" + "/Form defineresource pop\n"); + + _cairo_output_stream_printf (surface->final_stream, + "%%%%EndResource\n"); + if (status) + surface->base.status = status; +} + +static void +_path_fixed_init_rectangle (cairo_path_fixed_t *path, + cairo_rectangle_int_t *rect) +{ + cairo_status_t status; + + _cairo_path_fixed_init (path); + + status = _cairo_path_fixed_move_to (path, + _cairo_fixed_from_int (rect->x), + _cairo_fixed_from_int (rect->y)); + assert (status == CAIRO_STATUS_SUCCESS); + status = _cairo_path_fixed_rel_line_to (path, + _cairo_fixed_from_int (rect->width), + _cairo_fixed_from_int (0)); + assert (status == CAIRO_STATUS_SUCCESS); + status = _cairo_path_fixed_rel_line_to (path, + _cairo_fixed_from_int (0), + _cairo_fixed_from_int (rect->height)); + assert (status == CAIRO_STATUS_SUCCESS); + status = _cairo_path_fixed_rel_line_to (path, + _cairo_fixed_from_int (-rect->width), + _cairo_fixed_from_int (0)); + assert (status == CAIRO_STATUS_SUCCESS); + + status = _cairo_path_fixed_close_path (path); + assert (status == CAIRO_STATUS_SUCCESS); +} + +static cairo_status_t +_cairo_ps_surface_paint_surface (cairo_ps_surface_t *surface, + const cairo_pattern_t *pattern, + cairo_rectangle_int_t *extents, + cairo_operator_t op, + cairo_bool_t stencil_mask) +{ + cairo_rectangle_int_t src_surface_extents; + cairo_bool_t src_surface_bounded; + cairo_rectangle_int_t src_op_extents; + cairo_surface_t *source_surface; + double x_offset, y_offset; + cairo_status_t status; + cairo_matrix_t cairo_p2d, ps_p2d; + cairo_path_fixed_t path; + cairo_emit_surface_params_t params; + cairo_image_surface_t *image = NULL; + unsigned int region_id = 0; + + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (unlikely (status)) + return status; + + if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { + cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern; + region_id = surface_pattern->region_array_id; + } + + status = _cairo_ps_surface_acquire_source_surface_from_pattern (surface, + pattern, + extents, + &src_surface_extents, + &src_surface_bounded, + &src_op_extents, + &source_surface, + &x_offset, + &y_offset); + if (unlikely (status)) + return status; + + if (pattern->extend == CAIRO_EXTEND_PAD && + pattern->type == CAIRO_PATTERN_TYPE_SURFACE && + ((cairo_surface_pattern_t *)pattern)->surface->type == CAIRO_SURFACE_TYPE_IMAGE) { + cairo_image_surface_t *img; + + img = (cairo_image_surface_t *) source_surface; + status = _cairo_ps_surface_create_padded_image_from_image (surface, + img, + &pattern->matrix, + extents, + &image, + &src_surface_extents); + if (unlikely (status)) + goto release_source; + + x_offset = src_surface_extents.x; + y_offset = src_surface_extents.y; + } + + _path_fixed_init_rectangle (&path, extents); + status = _cairo_pdf_operators_clip (&surface->pdf_operators, + &path, + CAIRO_FILL_RULE_WINDING); + _cairo_path_fixed_fini (&path); + if (unlikely (status)) + goto release_source; + + cairo_p2d = pattern->matrix; + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_FALLBACK) { + double x_scale = cairo_p2d.xx; + double y_scale = cairo_p2d.yy; + + _cairo_output_stream_printf (surface->stream, + "%% Fallback Image: x=%f y=%f w=%d h=%d ", + -cairo_p2d.x0/x_scale, + -cairo_p2d.y0/y_scale, + (int)(src_surface_extents.width/x_scale), + (int)(src_surface_extents.height/y_scale)); + if (x_scale == y_scale) { + _cairo_output_stream_printf (surface->stream, + "res=%fppi ", + x_scale*72); + } else { + _cairo_output_stream_printf (surface->stream, + "res=%fx%fppi ", + x_scale*72, + y_scale*72); + } + _cairo_output_stream_printf (surface->stream, + "size=%ld\n", + (long)src_surface_extents.width * src_surface_extents.height * 3); + } else { + if (op == CAIRO_OPERATOR_SOURCE) { + _cairo_output_stream_printf (surface->stream, + "%d g %d %d %d %d rectfill\n", + surface->content == CAIRO_CONTENT_COLOR ? 0 : 1, + surface->surface_extents.x, + surface->surface_extents.y, + surface->surface_extents.width, + surface->surface_extents.height); + } + } + + status = cairo_matrix_invert (&cairo_p2d); + /* cairo_pattern_set_matrix ensures the matrix is invertible */ + assert (status == CAIRO_STATUS_SUCCESS); + + ps_p2d = surface->cairo_to_ps; + cairo_matrix_multiply (&ps_p2d, &cairo_p2d, &ps_p2d); + cairo_matrix_translate (&ps_p2d, x_offset, y_offset); + + params.src_surface = image ? &image->base : source_surface; + params.regions_id = image ? 0 : region_id; + params.op = op; + params.src_surface_extents = &src_surface_extents; + params.src_surface_bounded = src_surface_bounded; + params.src_op_extents = &src_op_extents; + params.filter = pattern->filter; + params.stencil_mask = stencil_mask; + params.is_image = FALSE; + params.approx_size = 0; + + status = _cairo_ps_surface_emit_surface (surface, CAIRO_EMIT_SURFACE_ANALYZE, ¶ms); + if (unlikely (status)) + goto release_source; + + if (params.is_image) { + cairo_matrix_translate (&ps_p2d, 0.0, src_surface_extents.height); + cairo_matrix_scale (&ps_p2d, 1.0, -1.0); + cairo_matrix_scale (&ps_p2d, src_surface_extents.width, src_surface_extents.height); + } + + if (! _cairo_matrix_is_identity (&ps_p2d)) { + _cairo_output_stream_printf (surface->stream, "[ "); + _cairo_output_stream_print_matrix (surface->stream, &ps_p2d); + _cairo_output_stream_printf (surface->stream, " ] concat\n"); + } + + status = _cairo_ps_surface_emit_surface (surface, CAIRO_EMIT_SURFACE_EMIT, ¶ms); + + release_source: + if (image) + cairo_surface_destroy (&image->base); + + _cairo_ps_surface_release_source_surface_from_pattern (surface, pattern, source_surface); + + return status; +} + +static cairo_status_t +_cairo_ps_surface_emit_surface_pattern (cairo_ps_surface_t *surface, + cairo_pattern_t *pattern, + cairo_rectangle_int_t *extents, + cairo_operator_t op) +{ + cairo_status_t status; + double xstep, ystep; + cairo_rectangle_int_t pattern_extents; + cairo_bool_t bounded; + cairo_matrix_t cairo_p2d, ps_p2d; + cairo_bool_t old_paint_proc; + double x_offset, y_offset; + cairo_surface_t *source_surface; + cairo_image_surface_t *image = NULL; + cairo_rectangle_int_t src_op_extents; + cairo_emit_surface_params_t params; + cairo_extend_t extend = cairo_pattern_get_extend (pattern); + unsigned int region_id = 0; + + cairo_p2d = pattern->matrix; + status = cairo_matrix_invert (&cairo_p2d); + /* cairo_pattern_set_matrix ensures the matrix is invertible */ + assert (status == CAIRO_STATUS_SUCCESS); + + if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { + cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern; + region_id = surface_pattern->region_array_id; + } + + status = _cairo_ps_surface_acquire_source_surface_from_pattern (surface, + pattern, + extents, + &pattern_extents, + &bounded, + &src_op_extents, + &source_surface, + &x_offset, &y_offset); + if (unlikely (status)) + return status; + + if (extend == CAIRO_EXTEND_PAD) { + cairo_image_surface_t *img; + + assert (source_surface->type == CAIRO_SURFACE_TYPE_IMAGE); + img = (cairo_image_surface_t *) source_surface; + status = _cairo_ps_surface_create_padded_image_from_image (surface, + img, + &pattern->matrix, + extents, + &image, + &pattern_extents); + if (unlikely (status)) + goto release_source; + } + if (unlikely (status)) + goto release_source; + + if (!bounded) + { + extend = CAIRO_EXTEND_NONE; + _cairo_rectangle_intersect (&pattern_extents, &src_op_extents); + } + + switch (extend) { + case CAIRO_EXTEND_PAD: + case CAIRO_EXTEND_NONE: + { + /* In PS/PDF, (as far as I can tell), all patterns are + * repeating. So we support cairo's EXTEND_NONE semantics + * by setting the repeat step size to a size large enough + * to guarantee that no more than a single occurrence will + * be visible. + * + * First, map the surface extents into pattern space (since + * xstep and ystep are in pattern space). Then use an upper + * bound on the length of the diagonal of the pattern image + * and the surface as repeat size. This guarantees to never + * repeat visibly. + */ + double x1 = 0.0, y1 = 0.0; + double x2 = surface->surface_extents.width; + double y2 = surface->surface_extents.height; + _cairo_matrix_transform_bounding_box (&pattern->matrix, + &x1, &y1, &x2, &y2, + NULL); + + /* Rather than computing precise bounds of the union, just + * add the surface extents unconditionally. We only + * required an answer that's large enough, we don't really + * care if it's not as tight as possible.*/ + xstep = ystep = ceil ((x2 - x1) + (y2 - y1) + + pattern_extents.width + pattern_extents.height); + break; + } + case CAIRO_EXTEND_REPEAT: + xstep = pattern_extents.width; + ystep = pattern_extents.height; + break; + case CAIRO_EXTEND_REFLECT: + xstep = pattern_extents.width*2; + ystep = pattern_extents.height*2; + break; + /* All the rest (if any) should have been analyzed away, so these + * cases should be unreachable. */ + default: + ASSERT_NOT_REACHED; + xstep = 0; + ystep = 0; + } + + _cairo_output_stream_printf (surface->stream, + "/CairoPattern {\n" + "q %d %d %d %d rectclip\n", + pattern_extents.x, pattern_extents.y, + pattern_extents.width, pattern_extents.height); + + if (extend == CAIRO_EXTEND_REPEAT || extend == CAIRO_EXTEND_REFLECT) + src_op_extents = pattern_extents; + + old_paint_proc = surface->paint_proc; + surface->paint_proc = TRUE; + params.src_surface = image ? &image->base : source_surface; + params.regions_id = image ? 0 : region_id; + params.op = op; + params.src_surface_extents = &pattern_extents; + params.src_surface_bounded = bounded; + params.src_op_extents = &src_op_extents; + params.filter = pattern->filter; + params.stencil_mask = FALSE; + params.is_image = FALSE; + params.approx_size = 0; + status = _cairo_ps_surface_emit_surface (surface, CAIRO_EMIT_SURFACE_ANALYZE, ¶ms); + if (unlikely (status)) + goto release_source; + + if (params.is_image) { + _cairo_output_stream_printf (surface->stream, + "[ %d 0 0 %d 0 0 ] concat\n", + pattern_extents.width, pattern_extents.height); + } + + if (op == CAIRO_OPERATOR_SOURCE) { + _cairo_output_stream_printf (surface->stream, + "%d g %d %d %f %f rectfill\n", + surface->content == CAIRO_CONTENT_COLOR ? 0 : 1, + pattern_extents.x, pattern_extents.y, + xstep, ystep); + } + + status = _cairo_ps_surface_emit_surface (surface, CAIRO_EMIT_SURFACE_EMIT, ¶ms); + if (unlikely (status)) + goto release_source; + + _cairo_output_stream_printf (surface->stream, + " Q } bind def\n"); + + _cairo_output_stream_printf (surface->stream, + "<< /PatternType 1\n" + " /PaintType 1\n" + " /TilingType 1\n"); + _cairo_output_stream_printf (surface->stream, + " /XStep %f /YStep %f\n", + xstep, ystep); + + if (extend == CAIRO_EXTEND_REFLECT) { + cairo_matrix_t mat; + + _cairo_output_stream_printf (surface->stream, + " /BBox [%d %d %d %d]\n" + " /PaintProc {\n" + " pop CairoPattern\n", + pattern_extents.x, + pattern_extents.y, + pattern_extents.x + pattern_extents.width*2, + pattern_extents.y + pattern_extents.height*2); + + cairo_matrix_init_translate (&mat, pattern_extents.x, pattern_extents.y); + cairo_matrix_scale (&mat, -1, 1); + cairo_matrix_translate (&mat, -2*pattern_extents.width, 0); + cairo_matrix_translate (&mat, -pattern_extents.x, -pattern_extents.y); + _cairo_output_stream_printf (surface->stream, " q ["); + _cairo_output_stream_print_matrix (surface->stream, &mat); + _cairo_output_stream_printf (surface->stream, "] concat CairoPattern Q\n"); + + cairo_matrix_init_translate (&mat, pattern_extents.x, pattern_extents.y); + cairo_matrix_scale (&mat, 1, -1); + cairo_matrix_translate (&mat, 0, -2*pattern_extents.height); + cairo_matrix_translate (&mat, -pattern_extents.x, -pattern_extents.y); + _cairo_output_stream_printf (surface->stream, " q ["); + _cairo_output_stream_print_matrix (surface->stream, &mat); + _cairo_output_stream_printf (surface->stream, "] concat CairoPattern Q\n"); + + cairo_matrix_init_translate (&mat, pattern_extents.x, pattern_extents.y); + cairo_matrix_scale (&mat, -1, -1); + cairo_matrix_translate (&mat, -2*pattern_extents.width, -2*pattern_extents.height); + cairo_matrix_translate (&mat, -pattern_extents.x, -pattern_extents.y); + _cairo_output_stream_printf (surface->stream, " q ["); + _cairo_output_stream_print_matrix (surface->stream, &mat); + _cairo_output_stream_printf (surface->stream, "] concat CairoPattern Q\n"); + + _cairo_output_stream_printf (surface->stream, " } bind\n"); + } else { + if (op == CAIRO_OPERATOR_SOURCE) { + _cairo_output_stream_printf (surface->stream, + " /BBox [0 0 %f %f]\n", + xstep, ystep); + } else { + _cairo_output_stream_printf (surface->stream, + " /BBox [%d %d %d %d]\n", + pattern_extents.x, + pattern_extents.y, + pattern_extents.x + pattern_extents.width, + pattern_extents.y + pattern_extents.height); + } + _cairo_output_stream_printf (surface->stream, + " /PaintProc { pop CairoPattern }\n"); + } + + _cairo_output_stream_printf (surface->stream, + ">>\n"); + + cairo_p2d = pattern->matrix; + status = cairo_matrix_invert (&cairo_p2d); + /* cairo_pattern_set_matrix ensures the matrix is invertible */ + assert (status == CAIRO_STATUS_SUCCESS); + + cairo_matrix_init_identity (&ps_p2d); + cairo_matrix_multiply (&ps_p2d, &cairo_p2d, &ps_p2d); + cairo_matrix_translate (&ps_p2d, x_offset, y_offset); + if (((cairo_surface_pattern_t *)pattern)->surface->type != CAIRO_SURFACE_TYPE_RECORDING) + { + cairo_matrix_translate (&ps_p2d, 0.0, pattern_extents.height); + cairo_matrix_scale (&ps_p2d, 1.0, -1.0); + } + + _cairo_output_stream_printf (surface->stream, "[ "); + _cairo_output_stream_print_matrix (surface->stream, &ps_p2d); + _cairo_output_stream_printf (surface->stream, + " ]\n" + "makepattern setpattern\n"); + + surface->paint_proc = old_paint_proc; + + release_source: + if (image) + cairo_surface_destroy (&image->base); + + _cairo_ps_surface_release_source_surface_from_pattern (surface, pattern, source_surface); + + return status; +} + +typedef struct _cairo_ps_color_stop { + double offset; + double color[4]; +} cairo_ps_color_stop_t; + +static void +_cairo_ps_surface_emit_linear_colorgradient (cairo_ps_surface_t *surface, + cairo_ps_color_stop_t *stop1, + cairo_ps_color_stop_t *stop2) +{ + _cairo_output_stream_printf (surface->stream, + " << /FunctionType 2\n" + " /Domain [ 0 1 ]\n" + " /C0 [ %f %f %f ]\n" + " /C1 [ %f %f %f ]\n" + " /N 1\n" + " >>\n", + stop1->color[0], + stop1->color[1], + stop1->color[2], + stop2->color[0], + stop2->color[1], + stop2->color[2]); +} + +static void +_cairo_ps_surface_emit_stitched_colorgradient (cairo_ps_surface_t *surface, + unsigned int n_stops, + cairo_ps_color_stop_t stops[]) +{ + unsigned int i; + + _cairo_output_stream_printf (surface->stream, + "<< /FunctionType 3\n" + " /Domain [ 0 1 ]\n" + " /Functions [\n"); + for (i = 0; i < n_stops - 1; i++) + _cairo_ps_surface_emit_linear_colorgradient (surface, &stops[i], &stops[i+1]); + + _cairo_output_stream_printf (surface->stream, " ]\n"); + + _cairo_output_stream_printf (surface->stream, " /Bounds [ "); + for (i = 1; i < n_stops-1; i++) + _cairo_output_stream_printf (surface->stream, "%f ", stops[i].offset); + _cairo_output_stream_printf (surface->stream, "]\n"); + + _cairo_output_stream_printf (surface->stream, " /Encode [ 1 1 %d { pop 0 1 } for ]\n", + n_stops - 1); + + _cairo_output_stream_printf (surface->stream, ">>\n"); +} + +static void +calc_gradient_color (cairo_ps_color_stop_t *new_stop, + cairo_ps_color_stop_t *stop1, + cairo_ps_color_stop_t *stop2) +{ + int i; + double offset = stop1->offset / (stop1->offset + 1.0 - stop2->offset); + + for (i = 0; i < 4; i++) + new_stop->color[i] = stop1->color[i] + offset*(stop2->color[i] - stop1->color[i]); +} + +#define COLOR_STOP_EPSILON 1e-6 + +static cairo_status_t +_cairo_ps_surface_emit_pattern_stops (cairo_ps_surface_t *surface, + cairo_gradient_pattern_t *pattern) +{ + cairo_ps_color_stop_t *allstops, *stops; + unsigned int i, n_stops; + + allstops = _cairo_malloc_ab ((pattern->n_stops + 2), sizeof (cairo_ps_color_stop_t)); + if (unlikely (allstops == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + stops = &allstops[1]; + n_stops = pattern->n_stops; + + for (i = 0; i < n_stops; i++) { + cairo_gradient_stop_t *stop = &pattern->stops[i]; + + stops[i].color[0] = stop->color.red; + stops[i].color[1] = stop->color.green; + stops[i].color[2] = stop->color.blue; + stops[i].color[3] = stop->color.alpha; + stops[i].offset = pattern->stops[i].offset; + } + + if (pattern->base.extend == CAIRO_EXTEND_REPEAT || + pattern->base.extend == CAIRO_EXTEND_REFLECT) + { + if (stops[0].offset > COLOR_STOP_EPSILON) { + if (pattern->base.extend == CAIRO_EXTEND_REFLECT) + memcpy (allstops, stops, sizeof (cairo_ps_color_stop_t)); + else + calc_gradient_color (&allstops[0], &stops[0], &stops[n_stops-1]); + stops = allstops; + n_stops++; + } + stops[0].offset = 0.0; + + if (stops[n_stops-1].offset < 1.0 - COLOR_STOP_EPSILON) { + if (pattern->base.extend == CAIRO_EXTEND_REFLECT) { + memcpy (&stops[n_stops], + &stops[n_stops - 1], + sizeof (cairo_ps_color_stop_t)); + } else { + calc_gradient_color (&stops[n_stops], &stops[0], &stops[n_stops-1]); + } + n_stops++; + } + stops[n_stops-1].offset = 1.0; + } + + for (i = 0; i < n_stops; i++) { + double red, green, blue; + cairo_color_t color; + + _cairo_color_init_rgba (&color, + stops[i].color[0], + stops[i].color[1], + stops[i].color[2], + stops[i].color[3]); + _cairo_ps_surface_flatten_transparency (surface, &color, + &red, &green, &blue); + stops[i].color[0] = red; + stops[i].color[1] = green; + stops[i].color[2] = blue; + } + + _cairo_output_stream_printf (surface->stream, + "/CairoFunction\n"); + if (stops[0].offset == stops[n_stops - 1].offset) { + /* + * The first and the last stops have the same offset, but we + * don't want a function with an empty domain, because that + * would provoke underdefined behaviour from rasterisers. + * This can only happen with EXTEND_PAD, because EXTEND_NONE + * is optimised into a clear pattern in cairo-gstate, and + * REFLECT/REPEAT are always transformed to have the first + * stop at t=0 and the last stop at t=1. Thus we want a step + * function going from the first color to the last one. + * + * This can be accomplished by stitching three functions: + * - a constant first color function, + * - a step from the first color to the last color (with empty domain) + * - a constant last color function + */ + cairo_ps_color_stop_t pad_stops[4]; + + assert (pattern->base.extend == CAIRO_EXTEND_PAD); + + pad_stops[0] = pad_stops[1] = stops[0]; + pad_stops[2] = pad_stops[3] = stops[n_stops - 1]; + + pad_stops[0].offset = 0; + pad_stops[3].offset = 1; + + _cairo_ps_surface_emit_stitched_colorgradient (surface, 4, pad_stops); + } else if (n_stops == 2) { + /* no need for stitched function */ + _cairo_ps_surface_emit_linear_colorgradient (surface, &stops[0], &stops[1]); + } else { + /* multiple stops: stitch. XXX possible optimization: regularly spaced + * stops do not require stitching. XXX */ + _cairo_ps_surface_emit_stitched_colorgradient (surface, n_stops, stops); + } + _cairo_output_stream_printf (surface->stream, + "def\n"); + + free (allstops); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_ps_surface_emit_repeating_function (cairo_ps_surface_t *surface, + cairo_gradient_pattern_t *pattern, + int begin, + int end) +{ + _cairo_output_stream_printf (surface->stream, + "/CairoFunction\n" + "<< /FunctionType 3\n" + " /Domain [ %d %d ]\n" + " /Functions [ %d {CairoFunction} repeat ]\n" + " /Bounds [ %d 1 %d {} for ]\n", + begin, + end, + end - begin, + begin + 1, + end - 1); + + if (pattern->base.extend == CAIRO_EXTEND_REFLECT) { + _cairo_output_stream_printf (surface->stream, " /Encode [ %d 1 %d { 2 mod 0 eq {0 1} {1 0} ifelse } for ]\n", + begin, + end - 1); + } else { + _cairo_output_stream_printf (surface->stream, " /Encode [ %d 1 %d { pop 0 1 } for ]\n", + begin, + end - 1); + } + + _cairo_output_stream_printf (surface->stream, ">> def\n"); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_ps_surface_emit_gradient (cairo_ps_surface_t *surface, + cairo_gradient_pattern_t *pattern, + cairo_bool_t is_ps_pattern) +{ + cairo_matrix_t pat_to_ps; + cairo_circle_double_t start, end; + double domain[2]; + cairo_status_t status; + + assert (pattern->n_stops != 0); + + status = _cairo_ps_surface_emit_pattern_stops (surface, pattern); + if (unlikely (status)) + return status; + + pat_to_ps = pattern->base.matrix; + status = cairo_matrix_invert (&pat_to_ps); + /* cairo_pattern_set_matrix ensures the matrix is invertible */ + assert (status == CAIRO_STATUS_SUCCESS); + cairo_matrix_multiply (&pat_to_ps, &pat_to_ps, &surface->cairo_to_ps); + + if (pattern->base.extend == CAIRO_EXTEND_REPEAT || + pattern->base.extend == CAIRO_EXTEND_REFLECT) + { + double bounds_x1, bounds_x2, bounds_y1, bounds_y2; + double x_scale, y_scale, tolerance; + + /* TODO: use tighter extents */ + bounds_x1 = 0; + bounds_y1 = 0; + bounds_x2 = surface->width; + bounds_y2 = surface->height; + _cairo_matrix_transform_bounding_box (&pattern->base.matrix, + &bounds_x1, &bounds_y1, + &bounds_x2, &bounds_y2, + NULL); + + x_scale = surface->base.x_resolution / surface->base.x_fallback_resolution; + y_scale = surface->base.y_resolution / surface->base.y_fallback_resolution; + + tolerance = fabs (_cairo_matrix_compute_determinant (&pattern->base.matrix)); + tolerance /= _cairo_matrix_transformed_circle_major_axis (&pattern->base.matrix, 1); + tolerance *= MIN (x_scale, y_scale); + + _cairo_gradient_pattern_box_to_parameter (pattern, + bounds_x1, bounds_y1, + bounds_x2, bounds_y2, + tolerance, domain); + } else if (pattern->stops[0].offset == pattern->stops[pattern->n_stops - 1].offset) { + /* + * If the first and the last stop offset are the same, then + * the color function is a step function. + * _cairo_ps_surface_emit_pattern_stops emits it as a stitched + * function no matter how many stops the pattern has. The + * domain of the stitched function will be [0 1] in this case. + * + * This is done to avoid emitting degenerate gradients for + * EXTEND_PAD patterns having a step color function. + */ + domain[0] = 0.0; + domain[1] = 1.0; + + assert (pattern->base.extend == CAIRO_EXTEND_PAD); + } else { + domain[0] = pattern->stops[0].offset; + domain[1] = pattern->stops[pattern->n_stops - 1].offset; + } + + /* PS requires the first and last stop to be the same as the + * extreme coordinates. For repeating patterns this moves the + * extreme coordinates out to the begin/end of the repeating + * function. For non repeating patterns this may move the extreme + * coordinates in if there are not stops at offset 0 and 1. */ + _cairo_gradient_pattern_interpolate (pattern, domain[0], &start); + _cairo_gradient_pattern_interpolate (pattern, domain[1], &end); + + if (pattern->base.extend == CAIRO_EXTEND_REPEAT || + pattern->base.extend == CAIRO_EXTEND_REFLECT) + { + int repeat_begin, repeat_end; + + repeat_begin = floor (domain[0]); + repeat_end = ceil (domain[1]); + + status = _cairo_ps_surface_emit_repeating_function (surface, + pattern, + repeat_begin, + repeat_end); + if (unlikely (status)) + return status; + } else if (pattern->n_stops <= 2) { + /* For EXTEND_NONE and EXTEND_PAD if there are only two stops a + * Type 2 function is used by itself without a stitching + * function. Type 2 functions always have the domain [0 1] */ + domain[0] = 0.0; + domain[1] = 1.0; + } + + if (is_ps_pattern) { + _cairo_output_stream_printf (surface->stream, + "<< /PatternType 2\n" + " /Shading\n"); + } + + if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) { + _cairo_output_stream_printf (surface->stream, + " << /ShadingType 2\n" + " /ColorSpace /DeviceRGB\n" + " /Coords [ %f %f %f %f ]\n", + start.center.x, start.center.y, + end.center.x, end.center.y); + } else { + _cairo_output_stream_printf (surface->stream, + " << /ShadingType 3\n" + " /ColorSpace /DeviceRGB\n" + " /Coords [ %f %f %f %f %f %f ]\n", + start.center.x, start.center.y, + MAX (start.radius, 0), + end.center.x, end.center.y, + MAX (end.radius, 0)); + } + + if (pattern->base.extend != CAIRO_EXTEND_NONE) { + _cairo_output_stream_printf (surface->stream, + " /Extend [ true true ]\n"); + } else { + _cairo_output_stream_printf (surface->stream, + " /Extend [ false false ]\n"); + } + + if (domain[0] == 0.0 && domain[1] == 1.0) { + _cairo_output_stream_printf (surface->stream, + " /Function CairoFunction\n"); + } else { + _cairo_output_stream_printf (surface->stream, + " /Function <<\n" + " /FunctionType 3\n" + " /Domain [ 0 1 ]\n" + " /Bounds [ ]\n" + " /Encode [ %f %f ]\n" + " /Functions [ CairoFunction ]\n" + " >>\n", + domain[0], domain[1]); + } + + _cairo_output_stream_printf (surface->stream, + " >>\n"); + + if (is_ps_pattern) { + _cairo_output_stream_printf (surface->stream, + ">>\n" + "[ "); + _cairo_output_stream_print_matrix (surface->stream, &pat_to_ps); + _cairo_output_stream_printf (surface->stream, " ]\n" + "makepattern setpattern\n"); + } else { + _cairo_output_stream_printf (surface->stream, + "shfill\n"); + } + + return status; +} + +static cairo_status_t +_cairo_ps_surface_emit_mesh_pattern (cairo_ps_surface_t *surface, + cairo_mesh_pattern_t *pattern, + cairo_bool_t is_ps_pattern) +{ + cairo_matrix_t pat_to_ps; + cairo_status_t status; + cairo_pdf_shading_t shading; + int i; + + if (_cairo_array_num_elements (&pattern->patches) == 0) + return CAIRO_INT_STATUS_NOTHING_TO_DO; + + pat_to_ps = pattern->base.matrix; + status = cairo_matrix_invert (&pat_to_ps); + /* cairo_pattern_set_matrix ensures the matrix is invertible */ + assert (status == CAIRO_STATUS_SUCCESS); + + cairo_matrix_multiply (&pat_to_ps, &pat_to_ps, &surface->cairo_to_ps); + + status = _cairo_pdf_shading_init_color (&shading, pattern); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->stream, + "currentfile\n" + "/ASCII85Decode filter /FlateDecode filter /ReusableStreamDecode filter\n"); + + status = _cairo_ps_surface_emit_base85_string (surface, + shading.data, + shading.data_length, + CAIRO_PS_COMPRESS_DEFLATE, + FALSE); + if (status) + return status; + + _cairo_output_stream_printf (surface->stream, + "\n" + "/CairoData exch def\n"); + + if (is_ps_pattern) { + _cairo_output_stream_printf (surface->stream, + "<< /PatternType 2\n" + " /Shading\n"); + } + + _cairo_output_stream_printf (surface->stream, + " << /ShadingType %d\n" + " /ColorSpace /DeviceRGB\n" + " /DataSource CairoData\n" + " /BitsPerCoordinate %d\n" + " /BitsPerComponent %d\n" + " /BitsPerFlag %d\n" + " /Decode [", + shading.shading_type, + shading.bits_per_coordinate, + shading.bits_per_component, + shading.bits_per_flag); + + for (i = 0; i < shading.decode_array_length; i++) + _cairo_output_stream_printf (surface->stream, "%f ", shading.decode_array[i]); + + _cairo_output_stream_printf (surface->stream, + "]\n" + " >>\n"); + + if (is_ps_pattern) { + _cairo_output_stream_printf (surface->stream, + ">>\n" + "[ \n"); + _cairo_output_stream_print_matrix (surface->stream, &pat_to_ps); + _cairo_output_stream_printf (surface->stream, + " ]\n" + "makepattern\n" + "setpattern\n"); + } else { + _cairo_output_stream_printf (surface->stream, "shfill\n"); + } + + _cairo_output_stream_printf (surface->stream, + "currentdict /CairoData undef\n"); + + _cairo_pdf_shading_fini (&shading); + + return status; +} + +static cairo_status_t +_cairo_ps_surface_emit_pattern (cairo_ps_surface_t *surface, + const cairo_pattern_t *pattern, + cairo_rectangle_int_t *extents, + cairo_operator_t op) +{ + cairo_status_t status; + + if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) { + cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern; + + if (surface->current_pattern_is_solid_color == FALSE || + ! _cairo_color_equal (&surface->current_color, &solid->color)) + { + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (unlikely (status)) + return status; + + _cairo_ps_surface_emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern); + + surface->current_pattern_is_solid_color = TRUE; + surface->current_color = solid->color; + } + + return CAIRO_STATUS_SUCCESS; + } + + surface->current_pattern_is_solid_color = FALSE; + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (unlikely (status)) + return status; + + switch (pattern->type) { + case CAIRO_PATTERN_TYPE_SOLID: + + _cairo_ps_surface_emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern); + break; + + case CAIRO_PATTERN_TYPE_SURFACE: + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + status = _cairo_ps_surface_emit_surface_pattern (surface, + (cairo_pattern_t *)pattern, + extents, + op); + if (unlikely (status)) + return status; + break; + + case CAIRO_PATTERN_TYPE_LINEAR: + case CAIRO_PATTERN_TYPE_RADIAL: + status = _cairo_ps_surface_emit_gradient (surface, + (cairo_gradient_pattern_t *) pattern, + TRUE); + if (unlikely (status)) + return status; + break; + + case CAIRO_PATTERN_TYPE_MESH: + status = _cairo_ps_surface_emit_mesh_pattern (surface, + (cairo_mesh_pattern_t *) pattern, + TRUE); + if (unlikely (status)) + return status; + break; + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_ps_surface_paint_gradient (cairo_ps_surface_t *surface, + const cairo_pattern_t *source, + const cairo_rectangle_int_t *extents) +{ + cairo_matrix_t pat_to_ps; + cairo_status_t status; + + pat_to_ps = source->matrix; + status = cairo_matrix_invert (&pat_to_ps); + /* cairo_pattern_set_matrix ensures the matrix is invertible */ + assert (status == CAIRO_STATUS_SUCCESS); + cairo_matrix_multiply (&pat_to_ps, &pat_to_ps, &surface->cairo_to_ps); + + if (! _cairo_matrix_is_identity (&pat_to_ps)) { + _cairo_output_stream_printf (surface->stream, "["); + _cairo_output_stream_print_matrix (surface->stream, &pat_to_ps); + _cairo_output_stream_printf (surface->stream, "] concat\n"); + } + + if (source->type == CAIRO_PATTERN_TYPE_MESH) { + status = _cairo_ps_surface_emit_mesh_pattern (surface, + (cairo_mesh_pattern_t *)source, + FALSE); + if (unlikely (status)) + return status; + } else { + status = _cairo_ps_surface_emit_gradient (surface, + (cairo_gradient_pattern_t *)source, + FALSE); + if (unlikely (status)) + return status; + } + + return status; +} + +static cairo_status_t +_cairo_ps_surface_paint_pattern (cairo_ps_surface_t *surface, + const cairo_pattern_t *source, + cairo_rectangle_int_t *extents, + cairo_operator_t op, + cairo_bool_t stencil_mask) +{ + switch (source->type) { + case CAIRO_PATTERN_TYPE_SURFACE: + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + return _cairo_ps_surface_paint_surface (surface, + source, + extents, + op, + stencil_mask); + + case CAIRO_PATTERN_TYPE_LINEAR: + case CAIRO_PATTERN_TYPE_RADIAL: + case CAIRO_PATTERN_TYPE_MESH: + return _cairo_ps_surface_paint_gradient (surface, + source, + extents); + + case CAIRO_PATTERN_TYPE_SOLID: + default: + ASSERT_NOT_REACHED; + return CAIRO_STATUS_SUCCESS; + } +} + +static cairo_bool_t +_can_paint_pattern (const cairo_pattern_t *pattern) +{ + switch (pattern->type) { + case CAIRO_PATTERN_TYPE_SOLID: + return FALSE; + + case CAIRO_PATTERN_TYPE_SURFACE: + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + return (pattern->extend == CAIRO_EXTEND_NONE || + pattern->extend == CAIRO_EXTEND_PAD); + + case CAIRO_PATTERN_TYPE_LINEAR: + case CAIRO_PATTERN_TYPE_RADIAL: + case CAIRO_PATTERN_TYPE_MESH: + return TRUE; + + default: + ASSERT_NOT_REACHED; + return FALSE; + } +} + +static cairo_bool_t +_cairo_ps_surface_get_extents (void *abstract_surface, + cairo_rectangle_int_t *rectangle) +{ + cairo_ps_surface_t *surface = abstract_surface; + + if (surface->surface_bounded) + *rectangle = surface->surface_extents; + + return surface->surface_bounded; +} + +static void +_cairo_ps_surface_get_font_options (void *abstract_surface, + cairo_font_options_t *options) +{ + _cairo_font_options_init_default (options); + + cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE); + cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF); + cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_GRAY); + _cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_OFF); +} + +static cairo_int_status_t +_cairo_ps_surface_set_clip (cairo_ps_surface_t *surface, + cairo_composite_rectangles_t *composite) +{ + cairo_clip_t *clip = composite->clip; + + if (_cairo_composite_rectangles_can_reduce_clip (composite, clip)) + clip = NULL; + + if (clip == NULL) { + if (_cairo_composite_rectangles_can_reduce_clip (composite, + surface->clipper.clip)) + return CAIRO_STATUS_SUCCESS; + } + + return _cairo_surface_clipper_set_clip (&surface->clipper, clip); +} + +static cairo_int_status_t +_cairo_ps_surface_paint (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip) +{ + cairo_ps_surface_t *surface = abstract_surface; + cairo_output_stream_t *stream = surface->stream; + cairo_composite_rectangles_t extents; + cairo_status_t status; + + status = _cairo_composite_rectangles_init_for_paint (&extents, + &surface->base, + op, source, clip); + if (unlikely (status)) + return status; + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) { + status = _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded); + goto cleanup_composite; + } + + assert (_cairo_ps_surface_operation_supported (surface, op, source, NULL, &extents.bounded)); + +#if DEBUG_PS + _cairo_output_stream_printf (stream, + "%% _cairo_ps_surface_paint\n"); +#endif + + status = _cairo_ps_surface_set_clip (surface, &extents); + if (unlikely (status)) + goto cleanup_composite; + + if (_can_paint_pattern (source)) { + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (unlikely (status)) + goto cleanup_composite; + + _cairo_output_stream_printf (stream, "q\n"); + status = _cairo_ps_surface_paint_pattern (surface, + source, + &extents.bounded, op, FALSE); + if (unlikely (status)) + goto cleanup_composite; + + _cairo_output_stream_printf (stream, "Q\n"); + } else { + status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op); + if (unlikely (status)) + goto cleanup_composite; + + _cairo_output_stream_printf (stream, "%d %d %d %d rectfill\n", + surface->surface_extents.x, + surface->surface_extents.y, + surface->surface_extents.width, + surface->surface_extents.height); + } + +cleanup_composite: + _cairo_composite_rectangles_fini (&extents); + return status; +} + +static cairo_int_status_t +_cairo_ps_surface_mask (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_clip_t *clip) +{ + cairo_ps_surface_t *surface = abstract_surface; + cairo_output_stream_t *stream = surface->stream; + cairo_composite_rectangles_t extents; + cairo_status_t status; + + status = _cairo_composite_rectangles_init_for_mask (&extents, + &surface->base, + op, source, mask, clip); + if (unlikely (status)) + return status; + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) { + status = _cairo_ps_surface_analyze_operation (surface, op, source, mask, &extents.bounded); + goto cleanup_composite; + } + + assert (_cairo_ps_surface_operation_supported (surface, op, source, mask, &extents.bounded)); + +#if DEBUG_PS + _cairo_output_stream_printf (stream, + "%% _cairo_ps_surface_mask\n"); +#endif + + status = _cairo_ps_surface_set_clip (surface, &extents); + if (unlikely (status)) + goto cleanup_composite; + + status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op); + if (unlikely (status)) + goto cleanup_composite; + + _cairo_output_stream_printf (stream, "q\n"); + status = _cairo_ps_surface_paint_pattern (surface, + mask, + &extents.bounded, op, TRUE); + if (unlikely (status)) + goto cleanup_composite; + + _cairo_output_stream_printf (stream, "Q\n"); + +cleanup_composite: + _cairo_composite_rectangles_fini (&extents); + return status; +} + +static cairo_int_status_t +_cairo_ps_surface_stroke (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_ps_surface_t *surface = abstract_surface; + cairo_composite_rectangles_t extents; + cairo_int_status_t status; + + status = _cairo_composite_rectangles_init_for_stroke (&extents, + &surface->base, + op, source, + path, style, ctm, + clip); + if (unlikely (status)) + return status; + + /* use the more accurate extents */ + { + cairo_rectangle_int_t r; + cairo_box_t b; + + status = _cairo_path_fixed_stroke_extents (path, style, + ctm, ctm_inverse, + tolerance, + &r); + if (unlikely (status)) + goto cleanup_composite; + + _cairo_box_from_rectangle (&b, &r); + status = _cairo_composite_rectangles_intersect_mask_extents (&extents, &b); + if (unlikely (status)) + goto cleanup_composite; + } + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) { + status = _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded); + goto cleanup_composite; + } + + assert (_cairo_ps_surface_operation_supported (surface, op, source, NULL, &extents.bounded)); + +#if DEBUG_PS + _cairo_output_stream_printf (surface->stream, + "%% _cairo_ps_surface_stroke\n"); +#endif + + status = _cairo_ps_surface_set_clip (surface, &extents); + if (unlikely (status)) + goto cleanup_composite; + + status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op); + if (unlikely (status)) + goto cleanup_composite; + + status = _cairo_pdf_operators_stroke (&surface->pdf_operators, + path, + style, + ctm, + ctm_inverse); + +cleanup_composite: + _cairo_composite_rectangles_fini (&extents); + return status; +} + +static cairo_int_status_t +_cairo_ps_surface_fill (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t*path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_ps_surface_t *surface = abstract_surface; + cairo_composite_rectangles_t extents; + cairo_int_status_t status; + + status = _cairo_composite_rectangles_init_for_fill (&extents, + &surface->base, + op, source, path, + clip); + if (unlikely (status)) + return status; + + /* use the more accurate extents */ + { + cairo_rectangle_int_t r; + cairo_box_t b; + + _cairo_path_fixed_fill_extents (path, + fill_rule, + tolerance, + &r); + + _cairo_box_from_rectangle (&b, &r); + status = _cairo_composite_rectangles_intersect_mask_extents (&extents, &b); + if (unlikely (status)) + goto cleanup_composite; + } + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) { + status = _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded); + goto cleanup_composite; + } + + assert (_cairo_ps_surface_operation_supported (surface, op, source, NULL, &extents.bounded)); + +#if DEBUG_PS + _cairo_output_stream_printf (surface->stream, + "%% _cairo_ps_surface_fill\n"); +#endif + + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (unlikely (status)) + goto cleanup_composite; + + status = _cairo_ps_surface_set_clip (surface, &extents); + if (unlikely (status)) + goto cleanup_composite; + + if (_can_paint_pattern (source)) { + _cairo_output_stream_printf (surface->stream, "q\n"); + + status = _cairo_pdf_operators_clip (&surface->pdf_operators, + path, + fill_rule); + if (unlikely (status)) + goto cleanup_composite; + + status = _cairo_ps_surface_paint_pattern (surface, + source, + &extents.bounded, op, FALSE); + if (unlikely (status)) + goto cleanup_composite; + + _cairo_output_stream_printf (surface->stream, "Q\n"); + _cairo_pdf_operators_reset (&surface->pdf_operators); + } else { + status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op); + if (unlikely (status)) + goto cleanup_composite; + + status = _cairo_pdf_operators_fill (&surface->pdf_operators, + path, + fill_rule); + } + +cleanup_composite: + _cairo_composite_rectangles_fini (&extents); + return status; +} + +static cairo_bool_t +_cairo_ps_surface_has_show_text_glyphs (void *abstract_surface) +{ + return TRUE; +} + +static cairo_int_status_t +_cairo_ps_surface_show_text_glyphs (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const char *utf8, + int utf8_len, + cairo_glyph_t *glyphs, + int num_glyphs, + const cairo_text_cluster_t *clusters, + int num_clusters, + cairo_text_cluster_flags_t cluster_flags, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip) +{ + cairo_ps_surface_t *surface = abstract_surface; + cairo_composite_rectangles_t extents; + cairo_bool_t overlap; + cairo_status_t status; + + status = _cairo_composite_rectangles_init_for_glyphs (&extents, + &surface->base, + op, source, + scaled_font, + glyphs, num_glyphs, + clip, + &overlap); + if (unlikely (status)) + return status; + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) { + status = _cairo_ps_surface_analyze_operation (surface, op, source, NULL, &extents.bounded); + goto cleanup_composite; + } + + assert (_cairo_ps_surface_operation_supported (surface, op, source, NULL, &extents.bounded)); + +#if DEBUG_PS + _cairo_output_stream_printf (surface->stream, + "%% _cairo_ps_surface_show_glyphs\n"); +#endif + + status = _cairo_ps_surface_set_clip (surface, &extents); + if (unlikely (status)) + goto cleanup_composite; + + status = _cairo_ps_surface_emit_pattern (surface, source, &extents.bounded, op); + if (unlikely (status)) + goto cleanup_composite; + + status = _cairo_pdf_operators_show_text_glyphs (&surface->pdf_operators, + utf8, utf8_len, + glyphs, num_glyphs, + clusters, num_clusters, + cluster_flags, + scaled_font); + +cleanup_composite: + _cairo_composite_rectangles_fini (&extents); + return status; +} + +static const char ** +_cairo_ps_surface_get_supported_mime_types (void *abstract_surface) +{ + return _cairo_ps_supported_mime_types; +} + +static cairo_int_status_t +_cairo_ps_surface_set_paginated_mode (void *abstract_surface, + cairo_paginated_mode_t paginated_mode) +{ + cairo_ps_surface_t *surface = abstract_surface; + cairo_status_t status; + + surface->paginated_mode = paginated_mode; + + if (paginated_mode == CAIRO_PAGINATED_MODE_RENDER) { + surface->surface_extents.x = 0; + surface->surface_extents.y = 0; + surface->surface_extents.width = ceil (surface->width); + surface->surface_extents.height = ceil (surface->height); + + if (surface->clipper.clip != NULL) + { + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + + _cairo_output_stream_printf (surface->stream, "Q q\n"); + _cairo_surface_clipper_reset (&surface->clipper); + } + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_ps_surface_set_bounding_box (void *abstract_surface, + cairo_box_t *analysis_bbox) +{ + cairo_ps_surface_t *surface = abstract_surface; + int i, num_comments; + char **comments; + cairo_bool_t has_page_media, has_page_bbox; + const char *page_media; + cairo_rectangle_int_t page_bbox; + cairo_point_int_t bbox_p1, bbox_p2; /* in PS coordinates */ + + _cairo_box_round_to_rectangle (analysis_bbox, &page_bbox); + + /* convert to PS coordinates */ + bbox_p1.x = page_bbox.x; + bbox_p1.y = ceil(surface->height) - (page_bbox.y + page_bbox.height); + bbox_p2.x = page_bbox.x + page_bbox.width; + bbox_p2.y = ceil(surface->height) - page_bbox.y; + + if (surface->num_pages == 1) { + surface->document_bbox_p1 = bbox_p1; + surface->document_bbox_p2 = bbox_p2; + } else { + if (bbox_p1.x < surface->document_bbox_p1.x) + surface->document_bbox_p1.x = bbox_p1.x; + if (bbox_p1.y < surface->document_bbox_p1.y) + surface->document_bbox_p1.y = bbox_p1.y; + if (bbox_p2.x < surface->document_bbox_p2.x) + surface->document_bbox_p2.x = bbox_p2.x; + if (bbox_p2.y < surface->document_bbox_p2.y) + surface->document_bbox_p2.y = bbox_p2.y; + } + + _cairo_output_stream_printf (surface->stream, + "%%%%Page: %d %d\n", + surface->num_pages, + surface->num_pages); + + _cairo_output_stream_printf (surface->stream, + "%%%%BeginPageSetup\n"); + + has_page_media = FALSE; + has_page_bbox = FALSE; + num_comments = _cairo_array_num_elements (&surface->dsc_page_setup_comments); + comments = _cairo_array_index (&surface->dsc_page_setup_comments, 0); + for (i = 0; i < num_comments; i++) { + _cairo_output_stream_printf (surface->stream, + "%s\n", comments[i]); + if (strncmp (comments[i], "%%PageMedia:", 11) == 0) + has_page_media = TRUE; + + if (strncmp (comments[i], "%%PageBoundingBox:", 18) == 0) + has_page_bbox = TRUE; + + free (comments[i]); + comments[i] = NULL; + } + _cairo_array_truncate (&surface->dsc_page_setup_comments, 0); + + if (!has_page_media && !surface->eps) { + page_media = _cairo_ps_surface_get_page_media (surface); + if (unlikely (page_media == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + _cairo_output_stream_printf (surface->stream, + "%%%%PageMedia: %s\n", + page_media); + } + + if (!has_page_bbox) { + _cairo_output_stream_printf (surface->stream, + "%%%%PageBoundingBox: %d %d %d %d\n", + bbox_p1.x, + bbox_p1.y, + bbox_p2.x, + bbox_p2.y); + } + + if (!surface->eps) { + _cairo_output_stream_printf (surface->stream, + "%f %f cairo_set_page_size\n", + ceil(surface->width), + ceil(surface->height)); + } + + _cairo_output_stream_printf (surface->stream, + "%%%%EndPageSetup\n" + "q %d %d %d %d rectclip\n" + "1 0 0 -1 0 %f cm q\n", + bbox_p1.x, + bbox_p1.y, + bbox_p2.x - bbox_p1.x, + bbox_p2.y - bbox_p1.y, + ceil(surface->height)); + + surface->current_pattern_is_solid_color = FALSE; + _cairo_pdf_operators_reset (&surface->pdf_operators); + + return _cairo_output_stream_get_status (surface->stream); +} + +static cairo_bool_t +_cairo_ps_surface_supports_fine_grained_fallbacks (void *abstract_surface) +{ + return TRUE; +} + +static const cairo_surface_backend_t cairo_ps_surface_backend = { + CAIRO_SURFACE_TYPE_PS, + _cairo_ps_surface_finish, + + _cairo_default_context_create, + + NULL, /* create similar: handled by wrapper */ + NULL, /* create similar image */ + NULL, /* map to image */ + NULL, /* unmap image */ + + _cairo_surface_default_source, + NULL, /* acquire_source_image */ + NULL, /* release_source_image */ + NULL, /* snapshot */ + + NULL, /* cairo_ps_surface_copy_page */ + _cairo_ps_surface_show_page, + + _cairo_ps_surface_get_extents, + _cairo_ps_surface_get_font_options, + + NULL, /* flush */ + NULL, /* mark_dirty_rectangle */ + + /* Here are the drawing functions */ + + _cairo_ps_surface_paint, /* paint */ + _cairo_ps_surface_mask, + _cairo_ps_surface_stroke, + _cairo_ps_surface_fill, + NULL, /* fill-stroke */ + NULL, /* show_glyphs */ + _cairo_ps_surface_has_show_text_glyphs, + _cairo_ps_surface_show_text_glyphs, + _cairo_ps_surface_get_supported_mime_types, +}; + +static const cairo_paginated_surface_backend_t cairo_ps_surface_paginated_backend = { + _cairo_ps_surface_start_page, + _cairo_ps_surface_set_paginated_mode, + _cairo_ps_surface_set_bounding_box, + NULL, /* _cairo_ps_surface_has_fallback_images, */ + _cairo_ps_surface_supports_fine_grained_fallbacks, +}; diff --git a/local/recipes/libs/cairo/source/src/cairo-ps.h b/local/recipes/libs/cairo/source/src/cairo-ps.h new file mode 100644 index 0000000000..33d0e0d941 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-ps.h @@ -0,0 +1,116 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + */ + +#ifndef CAIRO_PS_H +#define CAIRO_PS_H + +#include "cairo.h" + +#if CAIRO_HAS_PS_SURFACE + +#include + +CAIRO_BEGIN_DECLS + +/* PS-surface functions */ + +/** + * cairo_ps_level_t: + * @CAIRO_PS_LEVEL_2: The language level 2 of the PostScript specification. (Since 1.6) + * @CAIRO_PS_LEVEL_3: The language level 3 of the PostScript specification. (Since 1.6) + * + * #cairo_ps_level_t is used to describe the language level of the + * PostScript Language Reference that a generated PostScript file will + * conform to. + * + * Since: 1.6 + **/ +typedef enum _cairo_ps_level { + CAIRO_PS_LEVEL_2, + CAIRO_PS_LEVEL_3 +} cairo_ps_level_t; + +cairo_public cairo_surface_t * +cairo_ps_surface_create (const char *filename, + double width_in_points, + double height_in_points); + +cairo_public cairo_surface_t * +cairo_ps_surface_create_for_stream (cairo_write_func_t write_func, + void *closure, + double width_in_points, + double height_in_points); + +cairo_public void +cairo_ps_surface_restrict_to_level (cairo_surface_t *surface, + cairo_ps_level_t level); + +cairo_public void +cairo_ps_get_levels (cairo_ps_level_t const **levels, + int *num_levels); + +cairo_public const char * +cairo_ps_level_to_string (cairo_ps_level_t level); + +cairo_public void +cairo_ps_surface_set_eps (cairo_surface_t *surface, + cairo_bool_t eps); + +cairo_public cairo_bool_t +cairo_ps_surface_get_eps (cairo_surface_t *surface); + +cairo_public void +cairo_ps_surface_set_size (cairo_surface_t *surface, + double width_in_points, + double height_in_points); + +cairo_public void +cairo_ps_surface_dsc_comment (cairo_surface_t *surface, + const char *comment); + +cairo_public void +cairo_ps_surface_dsc_begin_setup (cairo_surface_t *surface); + +cairo_public void +cairo_ps_surface_dsc_begin_page_setup (cairo_surface_t *surface); + +CAIRO_END_DECLS + +#else /* CAIRO_HAS_PS_SURFACE */ +# error Cairo was not compiled with support for the ps backend +#endif /* CAIRO_HAS_PS_SURFACE */ + +#endif /* CAIRO_PS_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-quartz-font.c b/local/recipes/libs/cairo/source/src/cairo-quartz-font.c new file mode 100644 index 0000000000..b1a6fd7f58 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-quartz-font.c @@ -0,0 +1,851 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright � 2008 Mozilla Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * + * Contributor(s): + * Vladimir Vukicevic + */ + +#include "cairoint.h" + +#include + +#include "cairo-image-surface-private.h" +#include "cairo-quartz.h" +#include "cairo-quartz-private.h" + +#include "cairo-error-private.h" + +//#define DEBUG /* Uncomment this to get debug messages on the console. */ +/** + * SECTION:cairo-quartz-fonts + * @Title: Quartz (CGFont) Fonts + * @Short_Description: Font support via Core Text on Apple operating systems. + * @See_Also: #cairo_font_face_t + * + * Provide support for font faces via Core Text. + **/ + +/** + * CAIRO_HAS_QUARTZ_FONT: + * + * Defined if the Quartz font backend is available. + * This macro can be used to conditionally compile backend-specific code. + * + * Since: 1.6 + **/ + +/* These are private functions */ +static bool (*CGContextGetAllowsFontSmoothingPtr) (CGContextRef) = NULL; +static ATSFontRef (*FMGetATSFontRefFromFontPtr) (FMFont iFont) = NULL; + +static cairo_bool_t _cairo_quartz_font_symbol_lookup_done = FALSE; +/* Cairo's transformations assume a unit-scaled font. */ +static const CGFloat font_scale = 1.0; + +/* Defined in 10.11 */ +#define CGGLYPH_MAX ((CGGlyph) 0xFFFE) /* kCGFontIndexMax */ +#define CGGLYPH_INVALID ((CGGlyph) 0xFFFF) /* kCGFontIndexInvalid */ + +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1080 +#define FONT_ORIENTATION_HORIZONTAL kCTFontHorizontalOrientation +#define FONT_COLOR_GLYPHS kCTFontColorGlyphsTrait +#else +#define FONT_ORIENTATION_HORIZONTAL kCTFontOrientationHorizontal +#define FONT_COLOR_GLYPHS kCTFontTraitColorGlyphs +#endif + +static void +quartz_font_ensure_symbols(void) +{ + if (_cairo_quartz_font_symbol_lookup_done) + return; + + CGContextGetAllowsFontSmoothingPtr = + dlsym (RTLD_DEFAULT, "CGContextGetAllowsFontSmoothing"); + + FMGetATSFontRefFromFontPtr = dlsym(RTLD_DEFAULT, "FMGetATSFontRefFromFont"); + + _cairo_quartz_font_symbol_lookup_done = TRUE; +} + +typedef struct _cairo_quartz_font_face cairo_quartz_font_face_t; +typedef struct _cairo_quartz_scaled_font cairo_quartz_scaled_font_t; + +struct _cairo_quartz_scaled_font { + cairo_scaled_font_t base; + CTFontRef ctFont; +}; + +struct _cairo_quartz_font_face { + cairo_font_face_t base; + + CGFontRef cgFont; +}; + +/* + * font face backend + */ + +static cairo_status_t +_cairo_quartz_font_face_create_for_toy (cairo_toy_font_face_t *toy_face, + cairo_font_face_t **font_face) +{ + const char *family; + char *full_name; + CFStringRef FontName = NULL; + CGFontRef cgFont = NULL; + int loop; + + family = toy_face->family; + full_name = _cairo_malloc (strlen (family) + 64); // give us a bit of room to tack on Bold, Oblique, etc. + /* handle CSS-ish faces */ + if (!strcmp(family, "serif") || !strcmp(family, "Times Roman")) + family = "Times"; + else if (!strcmp(family, "sans-serif") || !strcmp(family, "sans")) + family = "Helvetica"; + else if (!strcmp(family, "cursive")) + family = "Apple Chancery"; + else if (!strcmp(family, "fantasy")) + family = "Papyrus"; + else if (!strcmp(family, "monospace") || !strcmp(family, "mono")) + family = "Courier"; + + /* Try to build up the full name, e.g. "Helvetica Bold Oblique" first, + * then drop the bold, then drop the slant, then drop both.. finally + * just use "Helvetica". And if Helvetica doesn't exist, give up. + */ + for (loop = 0; loop < 5; loop++) { + if (loop == 4) + family = "Helvetica"; + + strcpy (full_name, family); + + if (loop < 3 && (loop & 1) == 0) { + if (toy_face->weight == CAIRO_FONT_WEIGHT_BOLD) + strcat (full_name, "-Bold"); + } + + if (loop < 3 && (loop & 2) == 0) { + if (toy_face->slant == CAIRO_FONT_SLANT_ITALIC) + strcat (full_name, "-Italic"); + else if (toy_face->slant == CAIRO_FONT_SLANT_OBLIQUE) + strcat (full_name, "-Oblique"); + } + + FontName = CFStringCreateWithCString (NULL, full_name, kCFStringEncodingASCII); + cgFont = CGFontCreateWithFontName (FontName); + CFRelease (FontName); + + if (!cgFont) { + /* Attempt to create font by replacing hyphens for spaces in font name. */ + for (size_t i = 0; i < strlen (full_name); i++) { + if (full_name[i] == '-') + full_name[i] = ' '; + } + FontName = CFStringCreateWithCString (NULL, full_name, kCFStringEncodingASCII); + cgFont = CGFontCreateWithFontName (FontName); + CFRelease (FontName); + } + + if (cgFont) + break; + } + + if (!cgFont) { + /* Give up */ + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + *font_face = cairo_quartz_font_face_create_for_cgfont (cgFont); + CFRelease (cgFont); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_bool_t +_cairo_quartz_font_face_destroy (void *abstract_face) +{ + cairo_quartz_font_face_t *font_face = (cairo_quartz_font_face_t*) abstract_face; + + CGFontRelease (font_face->cgFont); + return TRUE; +} + +static const cairo_scaled_font_backend_t _cairo_quartz_scaled_font_backend; + +#ifdef DEBUG +static void +_cairo_quartz_debug_font_characteristics (cairo_quartz_scaled_font_t *font) +{ + CGRect ct_bbox = CTFontGetBoundingBox (font->ctFont); + CGFloat ct_ascent = CTFontGetAscent (font->ctFont); + CGFloat ct_descent = CTFontGetDescent (font->ctFont); + CGFloat ct_leading = CTFontGetLeading (font->ctFont); + CGFloat ct_capheight = CTFontGetCapHeight (font->ctFont); + CGFloat ct_xheight = CTFontGetXHeight (font->ctFont); + char chars[] = "ymMW"; + CGGlyph glyphs[4]; + UniChar *utf16 = NULL; + CGSize ct_advances[4]; + CGRect ct_gbbox[4], ct_gobox[4], ct_rbbox, ct_robox; + double ct_radvance; + int converted; + cairo_status_t rv; + + rv = _cairo_utf8_to_utf16 (chars, 4, &utf16, &converted); + if (rv) return; + CTFontGetGlyphsForCharacters (font->ctFont, utf16, glyphs, 4); + free (utf16); + ct_rbbox = CTFontGetBoundingRectsForGlyphs (font->ctFont, FONT_ORIENTATION_HORIZONTAL, glyphs, ct_gbbox, 4); + ct_robox = CTFontGetOpticalBoundsForGlyphs (font->ctFont, glyphs, ct_gobox, 4, 0); + ct_radvance = CTFontGetAdvancesForGlyphs (font->ctFont, FONT_ORIENTATION_HORIZONTAL, glyphs, ct_advances, 4); + + fprintf (stderr, "\nCTFont Bounding Box: %f %f %f %f\nAscent %f Descent %f Leading %f Cap Height %f X-Height %f\n", + ct_bbox.origin.x, ct_bbox.origin.y, ct_bbox.size.width, ct_bbox.size.height, ct_ascent, ct_descent, + ct_leading, ct_capheight, ct_xheight); + fprintf (stderr, "CTFont string\n\t bounding box %f %f %f %f advance %f\n\toptical box %f %f %f %f\n\n", + ct_rbbox.origin.x, ct_rbbox.origin.y, ct_rbbox.size.width, ct_rbbox.size.height, ct_radvance, + ct_robox.origin.x, ct_robox.origin.y, ct_robox.size.width, ct_robox.size.height); + for (int i = 0; i < 4; ++i) + { + fprintf (stderr, "Character %c\n", chars[i]); + fprintf (stderr, "\tbox %f %f %f %f\n\toptical %f %f %f %f advance %f %f\n", + ct_gbbox[i].origin.x, ct_gbbox[i].origin.y, ct_gbbox[i].size.width, ct_gbbox[i].size.height, + ct_advances[i].width, ct_advances[i].height, + ct_gobox[i].origin.x, ct_gobox[i].origin.y, ct_gobox[i].size.width, ct_gobox[i].size.height); + } + fprintf (stderr, "\n"); +} +#endif + +static cairo_status_t +_cairo_quartz_font_face_scaled_font_create (void *abstract_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **font_out) +{ + cairo_quartz_font_face_t *font_face = abstract_face; + cairo_quartz_scaled_font_t *font = NULL; + cairo_status_t status; + cairo_font_extents_t fs_metrics; + CTFontRef ctFont; + CGRect bbox; + + font = _cairo_calloc (sizeof(cairo_quartz_scaled_font_t)); + if (font == NULL) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + memset (font, 0, sizeof(cairo_quartz_scaled_font_t)); + + status = _cairo_scaled_font_init (&font->base, + &font_face->base, font_matrix, ctm, options, + &_cairo_quartz_scaled_font_backend); + if (status) + goto FINISH; + + ctFont = CTFontCreateWithGraphicsFont (font_face->cgFont, font_scale, NULL, NULL); + /* initialize metrics */ + fs_metrics.ascent = CTFontGetAscent (ctFont); + fs_metrics.descent = CTFontGetDescent (ctFont); + fs_metrics.height = fs_metrics.ascent + fs_metrics.descent + + CTFontGetLeading (ctFont); + + bbox = CTFontGetBoundingBox (ctFont); + fs_metrics.max_x_advance = CGRectGetMaxX(bbox); + fs_metrics.max_y_advance = 0.0; + font->ctFont = CFRetain (ctFont); + status = _cairo_scaled_font_set_metrics (&font->base, &fs_metrics); +#ifdef DEBUG + { + CFStringRef fontFullName = CTFontCopyFullName (ctFont); + const char* font_full_name = CFStringGetCStringPtr(fontFullName, kCFStringEncodingUTF8); + + fprintf (stderr, "Create scaled font %s with scale %f ascent %f, descent %f, height %f, x-advance %f\n", + font_full_name, fs_metrics.ascent, fs_metrics.descent, fs_metrics.height, + fs_metrics.max_x_advance); + _cairo_quartz_debug_font_characteristics (font); + } +#endif + +FINISH: + if (status != CAIRO_STATUS_SUCCESS) { + free (font); + } else { + *font_out = (cairo_scaled_font_t*) font; + } + + return status; +} + +const cairo_font_face_backend_t _cairo_quartz_font_face_backend = { + CAIRO_FONT_TYPE_QUARTZ, + _cairo_quartz_font_face_create_for_toy, + _cairo_quartz_font_face_destroy, + _cairo_quartz_font_face_scaled_font_create +}; + +static inline cairo_quartz_font_face_t* +_cairo_quartz_font_face_create () +{ + cairo_quartz_font_face_t *font_face = + _cairo_calloc (sizeof (cairo_quartz_font_face_t)); + + if (!font_face) { + cairo_status_t ignore_status; + ignore_status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + return (cairo_quartz_font_face_t *)&_cairo_font_face_nil; + } + + _cairo_font_face_init (&font_face->base, &_cairo_quartz_font_face_backend); + + return font_face; +} + +/** + * cairo_quartz_font_face_create_for_cgfont: + * @font: a #CGFontRef obtained through a method external to cairo. + * + * Creates a new font for the Quartz font backend based on a + * #CGFontRef. This font can then be used with + * cairo_set_font_face() or cairo_scaled_font_create(). + * + * Return value: a newly created #cairo_font_face_t. Free with + * cairo_font_face_destroy() when you are done using it. + * + * Since: 1.6 + **/ +cairo_font_face_t * +cairo_quartz_font_face_create_for_cgfont (CGFontRef font) +{ + cairo_quartz_font_face_t* font_face = _cairo_quartz_font_face_create (); + + if (cairo_font_face_status (&font_face->base)) + return &font_face->base; + + font_face->cgFont = CGFontRetain (font); + + return &font_face->base; +} + +/* + * scaled font backend + */ + +static cairo_quartz_font_face_t * +_cairo_quartz_scaled_to_face (void *abstract_font) +{ + cairo_quartz_scaled_font_t *sfont = (cairo_quartz_scaled_font_t*) abstract_font; + cairo_font_face_t *font_face = sfont->base.font_face; + assert (font_face->backend->type == CAIRO_FONT_TYPE_QUARTZ); + return (cairo_quartz_font_face_t*) font_face; +} + +static void +_cairo_quartz_scaled_font_fini(void *abstract_font) +{ + cairo_quartz_scaled_font_t* font = (cairo_quartz_scaled_font_t*)abstract_font; + CFRelease (font->ctFont); +} + +static inline CGGlyph +_cairo_quartz_scaled_glyph_index (cairo_scaled_glyph_t *scaled_glyph) { + unsigned long index = _cairo_scaled_glyph_index (scaled_glyph); + return index <= CGGLYPH_MAX ? index : CGGLYPH_INVALID; +} + +static cairo_int_status_t +_cairo_quartz_init_glyph_metrics (cairo_quartz_scaled_font_t *font, + cairo_scaled_glyph_t *scaled_glyph) +{ + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + + cairo_text_extents_t extents = {0, 0, 0, 0, 0, 0}; + CGGlyph glyph = _cairo_quartz_scaled_glyph_index (scaled_glyph); + CGSize advance; + CGRect bbox; + double xmin, ymin, xmax, ymax; + + if (unlikely (glyph == CGGLYPH_INVALID)) + goto FAIL; + + CTFontGetAdvancesForGlyphs (font->ctFont, FONT_ORIENTATION_HORIZONTAL, &glyph, &advance, 1); + CTFontGetBoundingRectsForGlyphs (font->ctFont, FONT_ORIENTATION_HORIZONTAL, &glyph, &bbox, 1); + /* broken fonts like Al Bayan return incorrect bounds for some null characters, + see https://bugzilla.mozilla.org/show_bug.cgi?id=534260 */ + if (unlikely (bbox.origin.x == -32767 && + bbox.origin.y == -32767 && + bbox.size.width == 65534 && + bbox.size.height == 65534)) { + bbox.origin.x = bbox.origin.y = 0; + bbox.size.width = bbox.size.height = 0; + } + +#ifdef DEBUG + fprintf (stderr, "[0x%04x] bbox: x %f y %f width %f height %f\n", glyph, + bbox.origin.x, bbox.origin.y, bbox.size.width, bbox.size.height); +#endif + + xmin = CGRectGetMinX(bbox); + ymin = CGRectGetMinY(bbox); + xmax = CGRectGetMaxX(bbox); + ymax = CGRectGetMaxY(bbox); + + extents.x_bearing = xmin; + extents.y_bearing = - ymax; + extents.width = xmax - xmin; + extents.height = ymax - ymin; +/* At the necessary 1.0pt ctFont size some glyphs get a reduced + * advance that causes overlaps when scaled up. We can avoid that by + * using the width instead if it's wider. Since cairo doesn't support + * vertical font layout we don't do the same for y_advance. + */ + extents.x_advance = MAX(extents.width, advance.width); + extents.y_advance = advance.height; + +#ifdef DEBUG + fprintf (stderr, "[0x%04x] extents: bearings: %f %f dim: %f %f adv: %f %f\n\n", glyph, + extents.x_bearing, extents.y_bearing, extents.width, extents.height, extents.x_advance, extents.y_advance); +#endif + + FAIL: + _cairo_scaled_glyph_set_metrics (scaled_glyph, + &font->base, + &extents); + + return status; +} + +static void +_cairo_quartz_path_apply_func (void *info, const CGPathElement *el) +{ + cairo_path_fixed_t *path = (cairo_path_fixed_t *) info; + cairo_status_t status; + + switch (el->type) { + case kCGPathElementMoveToPoint: + status = _cairo_path_fixed_move_to (path, + _cairo_fixed_from_double(el->points[0].x), + _cairo_fixed_from_double(el->points[0].y)); + assert(!status); + break; + case kCGPathElementAddLineToPoint: + status = _cairo_path_fixed_line_to (path, + _cairo_fixed_from_double(el->points[0].x), + _cairo_fixed_from_double(el->points[0].y)); + assert(!status); + break; + case kCGPathElementAddQuadCurveToPoint: { + cairo_fixed_t fx, fy; + double x, y; + if (!_cairo_path_fixed_get_current_point (path, &fx, &fy)) + fx = fy = 0; + x = _cairo_fixed_to_double (fx); + y = _cairo_fixed_to_double (fy); + + status = _cairo_path_fixed_curve_to (path, + _cairo_fixed_from_double((x + el->points[0].x * 2.0) / 3.0), + _cairo_fixed_from_double((y + el->points[0].y * 2.0) / 3.0), + _cairo_fixed_from_double((el->points[0].x * 2.0 + el->points[1].x) / 3.0), + _cairo_fixed_from_double((el->points[0].y * 2.0 + el->points[1].y) / 3.0), + _cairo_fixed_from_double(el->points[1].x), + _cairo_fixed_from_double(el->points[1].y)); + } + assert(!status); + break; + case kCGPathElementAddCurveToPoint: + status = _cairo_path_fixed_curve_to (path, + _cairo_fixed_from_double(el->points[0].x), + _cairo_fixed_from_double(el->points[0].y), + _cairo_fixed_from_double(el->points[1].x), + _cairo_fixed_from_double(el->points[1].y), + _cairo_fixed_from_double(el->points[2].x), + _cairo_fixed_from_double(el->points[2].y)); + assert(!status); + break; + case kCGPathElementCloseSubpath: + status = _cairo_path_fixed_close_path (path); + assert(!status); + break; + } +} + +static cairo_int_status_t +_cairo_quartz_init_glyph_path (cairo_quartz_scaled_font_t *font, + cairo_scaled_glyph_t *scaled_glyph) +{ + CGGlyph glyph = _cairo_quartz_scaled_glyph_index (scaled_glyph); + CGAffineTransform textMatrix; + CGPathRef glyphPath; + cairo_path_fixed_t *path; + + if (unlikely (glyph == CGGLYPH_INVALID)) { + _cairo_scaled_glyph_set_path (scaled_glyph, &font->base, _cairo_path_fixed_create()); + return CAIRO_STATUS_SUCCESS; + } + + /* scale(1,-1) * font->base.scale */ + textMatrix = CGAffineTransformMake (font->base.scale.xx, + font->base.scale.yx, + -font->base.scale.xy, + -font->base.scale.yy, + 0, 0); + + glyphPath = CTFontCreatePathForGlyph (font->ctFont, glyph, &textMatrix); + + if (!glyphPath) + return CAIRO_INT_STATUS_UNSUPPORTED; + + path = _cairo_path_fixed_create (); + if (!path) { + CGPathRelease (glyphPath); + return _cairo_error(CAIRO_STATUS_NO_MEMORY); + } + + CGPathApply (glyphPath, path, _cairo_quartz_path_apply_func); + + CGPathRelease (glyphPath); + + _cairo_scaled_glyph_set_path (scaled_glyph, &font->base, path); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_bool_t +_cairo_quartz_font_has_color_glyphs (void *abstract_font) +{ + cairo_quartz_scaled_font_t *face = (cairo_quartz_scaled_font_t*)abstract_font; + CTFontSymbolicTraits traits = CTFontGetSymbolicTraits (face->ctFont); + return traits & FONT_COLOR_GLYPHS; +} + +static cairo_int_status_t +_cairo_quartz_init_glyph_surface (cairo_quartz_scaled_font_t *font, + cairo_scaled_glyph_t *scaled_glyph, + cairo_scaled_glyph_info_t info, + const cairo_color_t *fg_color) +{ + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + cairo_image_surface_t *surface = NULL; + + CGGlyph glyph = _cairo_quartz_scaled_glyph_index (scaled_glyph); + cairo_text_extents_t metrics = scaled_glyph->fs_metrics; + CGRect bbox = CGRectMake (metrics.x_bearing, -(metrics.y_bearing + metrics.height), + metrics.width, metrics.height); + double width, height; + + CGAffineTransform textMatrix; + CGRect glyphRect, glyphRectInt; + CGPoint glyphOrigin; + cairo_bool_t is_color = info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE; + cairo_format_t format = is_color ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_A8; + +#ifdef DEBUG + fprintf (stderr, "[0x%04x] bearing: %f %f width %f height %f advances %f %f\n", + glyph, metrics.x_bearing, metrics.y_bearing, metrics.width, metrics.height, + metrics.x_advance, metrics.y_advance); + fprintf (stderr, "[0x%04x] bounds: origin %f %f, size %f %f\n", glyph, bbox.origin.x, + bbox.origin.y, bbox.size.width, bbox.size.height); +#endif + /* Create blank 2x2 image if we don't have this character. + * Maybe we should draw a better missing-glyph slug or something, + * but this is ok for now. + */ + if (unlikely (glyph == CGGLYPH_INVALID)) { + surface = (cairo_image_surface_t*) cairo_image_surface_create (CAIRO_FORMAT_A8, 2, 2); + status = cairo_surface_status ((cairo_surface_t *) surface); + if (status) + return status; + + _cairo_scaled_glyph_set_surface (scaled_glyph, + &font->base, + surface); + return CAIRO_STATUS_SUCCESS; + } + +/* Note: Certain opentype color fonts have the ability to provide a + * mixture of color and not-color glyphs. The Core Text API doesn't + * expose a way to query individual glyphs and at the level that that + * API is written it's not supposed to matter. The following code will + * cheerfully render any glyph requested onto the image surface. If + * the font is capable of color and + * COLOR_SCALED_GLYPH_INFO_COLOR_SURFACE is set then you get back a + * CAIRO_FORMAT_ARGB32 surface. If a foreground color is provided then + * the glyph will be drawn in that color, otherwise it will be black. + */ + if (unlikely (is_color && ! _cairo_quartz_font_has_color_glyphs (font))) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* scale(1,-1) * font->base.scale * scale(1,-1) */ + textMatrix = CGAffineTransformMake (font->base.scale.xx, + -font->base.scale.yx, + -font->base.scale.xy, + font->base.scale.yy, + 0, 0); + glyphRect = CGRectApplyAffineTransform (bbox, textMatrix); + + /* Round the rectangle outwards, so that we don't have to deal + * with non-integer-pixel origins or dimensions. + */ + glyphRectInt = CGRectIntegral (glyphRect); + +#ifdef DEBUG + fprintf (stderr, "glyphRect[o]: %f %f %f %f\n", + glyphRect.origin.x, glyphRect.origin.y, glyphRect.size.width, glyphRect.size.height); + fprintf (stderr, "glyphRectInt: %f %f %f %f\n", + glyphRectInt.origin.x, glyphRectInt.origin.y, glyphRectInt.size.width, glyphRectInt.size.height); +#endif + + glyphOrigin = glyphRectInt.origin; + + width = glyphRectInt.size.width; + height = glyphRectInt.size.height; + + surface = (cairo_image_surface_t*) cairo_image_surface_create (format, width, height); + if (surface->base.status) + return surface->base.status; + + if (surface->width != 0 && surface->height != 0) { + CGColorSpaceRef colorspace = is_color ? CGColorSpaceCreateDeviceRGB () : NULL; + CGBitmapInfo bitinfo = is_color ? kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst : kCGImageAlphaOnly; + + CGContextRef cgContext = CGBitmapContextCreate (surface->data, + surface->width, + surface->height, + 8, + surface->stride, + colorspace, + bitinfo); + + if (cgContext == NULL) { + cairo_surface_destroy (&surface->base); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + if (fg_color) + CGContextSetRGBFillColor (cgContext, fg_color->red, fg_color->green, fg_color->blue, fg_color->alpha); + _cairo_quartz_set_antialiasing (cgContext, font->base.options.antialias); + CGContextSetAlpha (cgContext, 1.0); + CGContextTranslateCTM (cgContext, -glyphOrigin.x, -glyphOrigin.y); + CGContextConcatCTM (cgContext, textMatrix); + CTFontDrawGlyphs (font->ctFont, &glyph, &CGPointZero, 1, cgContext); + CGContextRelease (cgContext); + CGColorSpaceRelease (colorspace); + } + + cairo_surface_set_device_offset (&surface->base, + - glyphOrigin.x, + height + glyphOrigin.y); + cairo_surface_mark_dirty (&surface->base); + + if (is_color) + _cairo_scaled_glyph_set_color_surface (scaled_glyph, &font->base, surface, fg_color); + else + _cairo_scaled_glyph_set_surface (scaled_glyph, &font->base, surface); + + return status; +} + +static cairo_int_status_t +_cairo_quartz_scaled_glyph_init (void *abstract_font, + cairo_scaled_glyph_t *scaled_glyph, + cairo_scaled_glyph_info_t info, + const cairo_color_t *foreground_color) +{ + cairo_quartz_scaled_font_t *font = (cairo_quartz_scaled_font_t *) abstract_font; + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + + if (!status && (info & CAIRO_SCALED_GLYPH_INFO_METRICS)) + status = _cairo_quartz_init_glyph_metrics (font, scaled_glyph); + + if (!status && (info & CAIRO_SCALED_GLYPH_INFO_PATH)) + status = _cairo_quartz_init_glyph_path (font, scaled_glyph); + + if (!status && (info & (CAIRO_SCALED_GLYPH_INFO_SURFACE | + CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE ))) + status = _cairo_quartz_init_glyph_surface (font, scaled_glyph, + info, foreground_color); + + return status; +} + +static unsigned long +_cairo_quartz_ucs4_to_index (void *abstract_font, + uint32_t ucs4) +{ + cairo_quartz_scaled_font_t *font = (cairo_quartz_scaled_font_t*) abstract_font; + CGGlyph glyph[2]; + UniChar utf16[2]; + + int len = _cairo_ucs4_to_utf16 (ucs4, utf16); + CTFontGetGlyphsForCharacters (font->ctFont, utf16, glyph, len); + return glyph[0]; +} + +static cairo_int_status_t +_cairo_quartz_load_truetype_table (void *abstract_font, + unsigned long tag, + long offset, + unsigned char *buffer, + unsigned long *length) +{ + cairo_quartz_scaled_font_t *font = (cairo_quartz_scaled_font_t*) abstract_font; + CFDataRef data = CTFontCopyTable (font->ctFont, tag, kCTFontTableOptionNoOptions); + + if (!data) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (buffer == NULL) { + *length = CFDataGetLength (data); + CFRelease (data); + return CAIRO_STATUS_SUCCESS; + } + + if (CFDataGetLength (data) < offset + (long) *length) { + CFRelease (data); + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + CFDataGetBytes (data, CFRangeMake (offset, *length), buffer); + CFRelease (data); + + return CAIRO_STATUS_SUCCESS; +} + +static const cairo_scaled_font_backend_t _cairo_quartz_scaled_font_backend = { + CAIRO_FONT_TYPE_QUARTZ, + _cairo_quartz_scaled_font_fini, + _cairo_quartz_scaled_glyph_init, + NULL, /* text_to_glyphs */ + _cairo_quartz_ucs4_to_index, + _cairo_quartz_load_truetype_table, + NULL, /*index_to_ucs4*/ + NULL, /* is_synthetic */ + NULL, /* index_to_glyph_name */ + NULL, /* load_type1_data */ + _cairo_quartz_font_has_color_glyphs +}; +/* + * private methods that the quartz surface uses + */ + +CGFontRef +_cairo_quartz_scaled_font_get_cg_font_ref (cairo_scaled_font_t *abstract_font) +{ + cairo_quartz_font_face_t *ffont = _cairo_quartz_scaled_to_face(abstract_font); + + return ffont->cgFont; +} + +CTFontRef +_cairo_quartz_scaled_font_get_ct_font (cairo_scaled_font_t *abstract_font) +{ + cairo_quartz_scaled_font_t *font = (cairo_quartz_scaled_font_t*) abstract_font; + + return font->ctFont; +} + + void + _cairo_quartz_set_antialiasing (CGContextRef cgContext, cairo_antialias_t antialias) +{ + switch (antialias) { + case CAIRO_ANTIALIAS_SUBPIXEL: + case CAIRO_ANTIALIAS_BEST: + CGContextSetShouldAntialias (cgContext, TRUE); + CGContextSetShouldSmoothFonts (cgContext, TRUE); + quartz_font_ensure_symbols (); + if (CGContextGetAllowsFontSmoothingPtr && + !CGContextGetAllowsFontSmoothingPtr (cgContext)) + CGContextSetAllowsFontSmoothing (cgContext, TRUE); + break; + case CAIRO_ANTIALIAS_NONE: + CGContextSetShouldAntialias (cgContext, FALSE); + break; + case CAIRO_ANTIALIAS_GRAY: + case CAIRO_ANTIALIAS_GOOD: + case CAIRO_ANTIALIAS_FAST: + CGContextSetShouldAntialias (cgContext, TRUE); + CGContextSetShouldSmoothFonts (cgContext, FALSE); + break; + case CAIRO_ANTIALIAS_DEFAULT: + default: + /* Don't do anything */ + break; + } + +} +/* + * compat with old ATSUI backend + */ + +/** + * cairo_quartz_font_face_create_for_atsu_font_id: + * @font_id: an ATSUFontID for the font. + * + * Creates a new font for the Quartz font backend based on an + * #ATSUFontID. This font can then be used with + * cairo_set_font_face() or cairo_scaled_font_create(). + * + * Return value: a newly created #cairo_font_face_t. Free with + * cairo_font_face_destroy() when you are done using it. + * + * Since: 1.6 + **/ +cairo_font_face_t * +cairo_quartz_font_face_create_for_atsu_font_id (ATSUFontID font_id) +{ + quartz_font_ensure_symbols(); + + if (FMGetATSFontRefFromFontPtr != NULL) { + ATSFontRef atsFont = FMGetATSFontRefFromFontPtr (font_id); + CGFontRef cgFont = CGFontCreateWithPlatformFont (&atsFont); + cairo_font_face_t *ff; + + ff = cairo_quartz_font_face_create_for_cgfont (cgFont); + + CGFontRelease (cgFont); + + return ff; + } else { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_font_face_t *)&_cairo_font_face_nil; + } +} + +/* This is the old name for the above function, exported for compat purposes */ +cairo_font_face_t *cairo_atsui_font_face_create_for_atsu_font_id (ATSUFontID font_id); + +cairo_font_face_t * +cairo_atsui_font_face_create_for_atsu_font_id (ATSUFontID font_id) +{ + return cairo_quartz_font_face_create_for_atsu_font_id (font_id); +} diff --git a/local/recipes/libs/cairo/source/src/cairo-quartz-image-surface.c b/local/recipes/libs/cairo/source/src/cairo-quartz-image-surface.c new file mode 100644 index 0000000000..4f9bc21184 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-quartz-image-surface.c @@ -0,0 +1,395 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright � 2008 Mozilla Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * + * Contributor(s): + * Vladimir Vukicevic + */ + +#include "cairoint.h" + +#include "cairo-image-surface-inline.h" +#include "cairo-quartz-image.h" +#include "cairo-quartz-private.h" +#include "cairo-surface-backend-private.h" + +#include "cairo-error-private.h" +#include "cairo-default-context-private.h" + +#define SURFACE_ERROR_NO_MEMORY (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_NO_MEMORY))) +#define SURFACE_ERROR_TYPE_MISMATCH (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_SURFACE_TYPE_MISMATCH))) +#define SURFACE_ERROR_INVALID_SIZE (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_INVALID_SIZE))) +#define SURFACE_ERROR_INVALID_FORMAT (_cairo_surface_create_in_error(_cairo_error(CAIRO_STATUS_INVALID_FORMAT))) + +/** + * CAIRO_HAS_QUARTZ_IMAGE_SURFACE: + * + * Defined if the Quartz image surface backend is available. + * This macro can be used to conditionally compile backend-specific code. + * + * Since: 1.10 + **/ + +static cairo_surface_t * +_cairo_quartz_image_surface_create_similar (void *asurface, + cairo_content_t content, + int width, + int height) +{ + cairo_surface_t *isurf = + _cairo_image_surface_create_with_content (content, width, height); + cairo_surface_t *result = cairo_quartz_image_surface_create (isurf); + cairo_surface_destroy (isurf); + + return result; +} + +static cairo_surface_t * +_cairo_quartz_image_surface_create_similar_image (void *asurface, + cairo_format_t format, + int width, + int height) +{ + cairo_surface_t *isurf = cairo_image_surface_create (format, width, height); + cairo_surface_t *result = cairo_quartz_image_surface_create (isurf); + cairo_surface_destroy (isurf); + + return result; +} + +static cairo_status_t +_cairo_quartz_image_surface_finish (void *asurface) +{ + cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface; + + CGContextRelease (surface->cgContext); + if (surface->imageSurface) + cairo_surface_destroy ( (cairo_surface_t*) surface->imageSurface); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_quartz_image_surface_acquire_source_image (void *asurface, + cairo_image_surface_t **image_out, + void **image_extra) +{ + cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface; + + *image_out = surface->imageSurface; + *image_extra = NULL; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_image_surface_t * +_cairo_quartz_image_surface_map_to_image (void *asurface, + const cairo_rectangle_int_t *extents) +{ + cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface; + return _cairo_surface_map_to_image (&surface->imageSurface->base, extents); +} + +static cairo_int_status_t +_cairo_quartz_image_surface_unmap_image (void *asurface, + cairo_image_surface_t *image) +{ + cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface; + return _cairo_surface_unmap_image (&surface->imageSurface->base, image); +} + +static cairo_bool_t +_cairo_quartz_image_surface_get_extents (void *asurface, + cairo_rectangle_int_t *extents) +{ + cairo_quartz_image_surface_t *surface = (cairo_quartz_image_surface_t *) asurface; + + extents->x = 0; + extents->y = 0; + extents->width = surface->width; + extents->height = surface->height; + return TRUE; +} + +static cairo_int_status_t +_cairo_quartz_image_surface_paint (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip) +{ + cairo_quartz_image_surface_t *surface = abstract_surface; + return _cairo_surface_paint (&surface->imageSurface->base, + op, source, clip); +} + +static cairo_int_status_t +_cairo_quartz_image_surface_mask (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_clip_t *clip) +{ + cairo_quartz_image_surface_t *surface = abstract_surface; + return _cairo_surface_mask (&surface->imageSurface->base, + op, source, mask, clip); +} + +static cairo_int_status_t +_cairo_quartz_image_surface_stroke (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_quartz_image_surface_t *surface = abstract_surface; + return _cairo_surface_stroke (&surface->imageSurface->base, + op, source, path, + style, ctm, ctm_inverse, + tolerance, antialias, clip); +} + +static cairo_int_status_t +_cairo_quartz_image_surface_fill (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_quartz_image_surface_t *surface = abstract_surface; + return _cairo_surface_fill (&surface->imageSurface->base, + op, source, path, + fill_rule, tolerance, antialias, + clip); +} + +static cairo_int_status_t +_cairo_quartz_image_surface_glyphs (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip) +{ + cairo_quartz_image_surface_t *surface = abstract_surface; + return _cairo_surface_show_text_glyphs (&surface->imageSurface->base, + op, source, + NULL, 0, + glyphs, num_glyphs, + NULL, 0, 0, + scaled_font, clip); +} + + +static const cairo_surface_backend_t cairo_quartz_image_surface_backend = { + CAIRO_SURFACE_TYPE_QUARTZ_IMAGE, + _cairo_quartz_image_surface_finish, + + _cairo_default_context_create, + + _cairo_quartz_image_surface_create_similar, + _cairo_quartz_image_surface_create_similar_image, + _cairo_quartz_image_surface_map_to_image, + _cairo_quartz_image_surface_unmap_image, + + _cairo_surface_default_source, + _cairo_quartz_image_surface_acquire_source_image, + NULL, /* release_source_image */ + NULL, /* snapshot */ + + NULL, /* copy_page */ + NULL, /* show_page */ + + _cairo_quartz_image_surface_get_extents, + NULL, /* get_font_options */ + + NULL, /*surface_flush */ + NULL, /* mark_dirty_rectangle */ + + _cairo_quartz_image_surface_paint, + _cairo_quartz_image_surface_mask, + _cairo_quartz_image_surface_stroke, + _cairo_quartz_image_surface_fill, + NULL, /* fill-stroke */ + _cairo_quartz_image_surface_glyphs, +}; + +/** + * cairo_quartz_image_surface_create: + * @image_surface: a cairo image surface to wrap with a quartz image surface + * + * Creates a Quartz surface backed by a CGBitmapContext that references the + * given image surface. The resulting surface can be rendered quickly + * when used as a source when rendering to a #cairo_quartz_surface. + * + * Return value: the newly created surface. + * + * Since: 1.6 + **/ +cairo_surface_t * +cairo_quartz_image_surface_create (cairo_surface_t *surface) +{ + cairo_quartz_image_surface_t *qisurf; + cairo_image_surface_t *image_surface; + int width, height, stride; + cairo_format_t format; + CGBitmapInfo bitinfo = kCGBitmapByteOrder32Host; + CGColorSpaceRef colorspace; + + if (surface->status) + return surface; + + if (! _cairo_surface_is_image (surface)) + return SURFACE_ERROR_TYPE_MISMATCH; + + image_surface = (cairo_image_surface_t*) surface; + width = image_surface->width; + height = image_surface->height; + stride = image_surface->stride; + format = image_surface->format; + + if (!_cairo_quartz_verify_surface_size(width, height)) + return SURFACE_ERROR_INVALID_SIZE; + + if (width == 0 || height == 0) + return SURFACE_ERROR_INVALID_SIZE; + + if (format != CAIRO_FORMAT_ARGB32 && format != CAIRO_FORMAT_RGB24) + return SURFACE_ERROR_INVALID_FORMAT; + + qisurf = _cairo_calloc (sizeof(cairo_quartz_image_surface_t)); + if (qisurf == NULL) + return SURFACE_ERROR_NO_MEMORY; + + _cairo_surface_init (&qisurf->base, + &cairo_quartz_image_surface_backend, + NULL, /* device */ + _cairo_content_from_format (format), + FALSE); /* is_vector */ + + if (_cairo_surface_is_quartz (surface) || _cairo_surface_is_quartz_image (surface)) { + CGContextRef context = cairo_quartz_surface_get_cg_context(surface); + colorspace = _cairo_quartz_create_color_space (context); + } + else { + colorspace = CGDisplayCopyColorSpace (CGMainDisplayID ()); + } + + bitinfo |= format == CAIRO_FORMAT_ARGB32 ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst; + + qisurf->width = width; + qisurf->height = height; + + qisurf->cgContext = CGBitmapContextCreate (image_surface->data, width, height, 8, image_surface->stride, + colorspace, bitinfo); + qisurf->imageSurface = (cairo_image_surface_t*) cairo_surface_reference(surface); + + CGColorSpaceRelease (colorspace); + return &qisurf->base; +} + + +/** + * cairo_quartz_image_surface_get_image: + * @surface: a #cairo_surface_t + * + * Returns a #cairo_surface_t image surface that refers to the same bits + * as the image of the quartz surface. + * + * Return value: a #cairo_surface_t (owned by the quartz #cairo_surface_t), + * or %NULL if the quartz surface is not an image surface. + * + * Since: 1.6 + **/ +cairo_surface_t * +cairo_quartz_image_surface_get_image (cairo_surface_t *surface) +{ + cairo_quartz_image_surface_t *qsurface = (cairo_quartz_image_surface_t*) surface; + + /* Throw an error for a non-quartz surface */ + if (! _cairo_surface_is_quartz (surface)) { + return SURFACE_ERROR_TYPE_MISMATCH; + } + + return (cairo_surface_t*) qsurface->imageSurface; +} + +/* + * _cairo_quartz_image_surface_get_cg_context: + * @surface: the Cairo Quartz surface + * + * Returns the CGContextRef that the given Quartz surface is backed + * by. + * + * A call to cairo_surface_flush() is required before using the + * CGContextRef to ensure that all pending drawing operations are + * finished and to restore any temporary modification cairo has made + * to its state. A call to cairo_surface_mark_dirty() is required + * after the state or the content of the CGContextRef has been + * modified. + * + * Return value: the CGContextRef for the given surface. + * + **/ +CGContextRef +_cairo_quartz_image_surface_get_cg_context (cairo_surface_t *surface) +{ + if (surface && _cairo_surface_is_quartz_image (surface)) { + cairo_quartz_surface_t *quartz = (cairo_quartz_surface_t *) surface; + return quartz->cgContext; + } else + return NULL; +} + +/* + * _cairo_surface_is_quartz_image: + * @surface: a #cairo_surface_t + * + * Checks if a surface is a #cairo_quartz_surface_t + * + * Return value: True if the surface is an quartz surface + **/ +cairo_bool_t +_cairo_surface_is_quartz_image (const cairo_surface_t *surface) { + return surface->backend == &cairo_quartz_image_surface_backend; +} + +cairo_bool_t +_cairo_quartz_image_surface_is_zero (const cairo_quartz_image_surface_t *surface) { + return surface->width == 0 || surface->height == 0; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-quartz-image.h b/local/recipes/libs/cairo/source/src/cairo-quartz-image.h new file mode 100644 index 0000000000..0dd5abb4fd --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-quartz-image.h @@ -0,0 +1,59 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2008 Mozilla Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * + * Contributor(s): + * Vladimir Vukicevic + */ + +#ifndef CAIRO_QUARTZ_IMAGE_H +#define CAIRO_QUARTZ_IMAGE_H + +#include "cairo.h" + +#if CAIRO_HAS_QUARTZ_IMAGE_SURFACE + +#include + +CAIRO_BEGIN_DECLS + +cairo_public cairo_surface_t * +cairo_quartz_image_surface_create (cairo_surface_t *image_surface); + +cairo_public cairo_surface_t * +cairo_quartz_image_surface_get_image (cairo_surface_t *surface); + +CAIRO_END_DECLS + +#else /* CAIRO_HAS_QUARTZ_IMAGE_SURFACE */ +# error Cairo was not compiled with support for the quartz-image backend +#endif /* CAIRO_HAS_QUARTZ_IMAGE_SURFACE */ + +#endif /* CAIRO_QUARTZ_IMAGE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-quartz-private.h b/local/recipes/libs/cairo/source/src/cairo-quartz-private.h new file mode 100644 index 0000000000..bdfdf8c2bb --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-quartz-private.h @@ -0,0 +1,122 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2004 Calum Robinson + * Copyright (C) 2006,2007 Mozilla Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Calum Robinson + * + * Contributor(s): + * Calum Robinson + * Vladimir Vukicevic + */ + +#ifndef CAIRO_QUARTZ_PRIVATE_H +#define CAIRO_QUARTZ_PRIVATE_H + +#include "cairoint.h" + +#if CAIRO_HAS_QUARTZ_SURFACE +#include "cairo-quartz.h" +#include "cairo-surface-clipper-private.h" + +#ifndef CGFLOAT_DEFINED +/* On 10.4, Quartz APIs used float instead of CGFloat */ +typedef float CGFloat; +#endif + +typedef CGFloat cairo_quartz_float_t; + +typedef enum { + DO_DIRECT, + DO_SHADING, + DO_IMAGE, + DO_LAYER +} cairo_quartz_action_t; + +/* define CTFontRef for pre-10.5 SDKs */ +typedef const struct __CTFont *CTFontRef; + +typedef struct cairo_quartz_surface { + cairo_surface_t base; + + CGContextRef cgContext; + CGAffineTransform cgContextBaseCTM; + +#if MAC_OS_X_VERSION_MIN_REQUIRED < 10600 + void *imageData; +#endif + + cairo_surface_clipper_t clipper; + cairo_rectangle_int_t extents; + cairo_rectangle_int_t virtual_extents; + CGLayerRef cgLayer; +} cairo_quartz_surface_t; + +typedef struct cairo_quartz_image_surface { + cairo_surface_t base; + + int width, height; + CGContextRef cgContext; + cairo_image_surface_t *imageSurface; +} cairo_quartz_image_surface_t; + +cairo_private cairo_bool_t +_cairo_quartz_verify_surface_size(int width, int height); + +cairo_private cairo_bool_t +_cairo_surface_is_quartz (const cairo_surface_t *surface); + +cairo_private cairo_bool_t +_cairo_surface_is_quartz_image (const cairo_surface_t *surface); +cairo_private cairo_bool_t +_cairo_quartz_image_surface_is_zero (const cairo_quartz_image_surface_t *surface); + +cairo_private CGColorSpaceRef +_cairo_quartz_create_color_space (CGContextRef context); +cairo_private CGContextRef +_cairo_quartz_image_surface_get_cg_context (cairo_surface_t *surface); + +cairo_private CGFontRef +_cairo_quartz_scaled_font_get_cg_font_ref (cairo_scaled_font_t *sfont); +cairo_private CTFontRef +_cairo_quartz_scaled_font_get_ct_font (cairo_scaled_font_t *sfont); +cairo_private cairo_font_face_t* +_cairo_quartz_font_face_create_for_ctfont (CTFontRef ctFont); +cairo_private void +_cairo_quartz_set_antialiasing (CGContextRef context, cairo_antialias_t antialias); + +cairo_status_t _cairo_quartz_surface_to_png (cairo_surface_t *abstract_surface, const char *dest); +cairo_private void _cairo_quartz_image_to_png (CGImageRef, const char *dest); + +#else + +# error Cairo was not compiled with support for the quartz backend + +#endif /* CAIRO_HAS_QUARTZ_SURFACE */ + +#endif /* CAIRO_QUARTZ_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-quartz-surface.c b/local/recipes/libs/cairo/source/src/cairo-quartz-surface.c new file mode 100644 index 0000000000..0a5c72f0d5 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-quartz-surface.c @@ -0,0 +1,2470 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright � 2006, 2007 Mozilla Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * + * Contributor(s): + * Vladimir Vukicevic + */ + +#include "cairoint.h" + +#include "cairo-quartz-private.h" +#include "cairo-quartz-image.h" + +#include "cairo-composite-rectangles-private.h" +#include "cairo-compositor-private.h" +#include "cairo-default-context-private.h" +#include "cairo-error-private.h" +#include "cairo-image-surface-inline.h" +#include "cairo-pattern-private.h" +#include "cairo-surface-backend-private.h" +#include "cairo-surface-clipper-private.h" +#include "cairo-recording-surface-private.h" + +#include + +#ifndef RTLD_DEFAULT +#define RTLD_DEFAULT ((void *) 0) +#endif + +#include +#include + +#undef QUARTZ_DEBUG + +#ifdef QUARTZ_DEBUG +#define ND(_x) fprintf _x +#else +#define ND(_x) do {} while(0) +#endif + +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1080 +#define FONT_ORIENTATION_HORIZONTAL kCTFontHorizontalOrientation +#else +#define FONT_ORIENTATION_HORIZONTAL kCTFontOrientationHorizontal +#endif + +static inline cairo_bool_t +_is_quartz_surface (cairo_surface_t *surface) { + return _cairo_surface_is_quartz (surface) || _cairo_surface_is_quartz_image (surface); +} + +static inline cairo_bool_t +_cairo_quartz_surface_is_zero (cairo_quartz_surface_t* surface) { + return surface->extents.width == 0 || surface->extents.height == 0; +} + +static inline cairo_bool_t +_cairo_quartz_is_zero_surface (cairo_surface_t* surface) { + assert (_is_quartz_surface (surface)); + if (_cairo_surface_is_quartz (surface)) + return (_cairo_quartz_surface_is_zero ((cairo_quartz_surface_t*) surface)); + else + return (_cairo_quartz_image_surface_is_zero ((cairo_quartz_image_surface_t*) surface)); +} + +/** + * SECTION:cairo-quartz + * @Title: Quartz Surfaces + * @Short_Description: Rendering to Quartz surfaces + * @See_Also: #cairo_surface_t + * + * The Quartz surface is used to render cairo graphics targeting the + * Apple OS X Quartz rendering system. + **/ + +/** + * CAIRO_HAS_QUARTZ_SURFACE: + * + * Defined if the Quartz surface backend is available. + * This macro can be used to conditionally compile backend-specific code. + * + * Since: 1.6 + **/ + +/* + * macOS Private functions + */ +typedef enum { + kCGContextTypeUnknown, + kCGContextTypePDF, + kCGContextTypePostScript, + kCGContextTypeWindow, + kCGContextTypeBitmap, + kCGContextTypeGL, + kCGContextTypeDisplayList, + kCGContextTypeKSeparation, + kCGContextTypeIOSurface, + kCGContextTypeCount +} CGContextType; + + +static bool (*CGContextGetAllowsFontSmoothingPtr) (CGContextRef) = NULL; +static unsigned int (*CGContextGetTypePtr) (CGContextRef) = NULL; +static void +quartz_ensure_symbols() +{ + static cairo_bool_t symbol_lookup_done = FALSE; + if (!symbol_lookup_done) { + CGContextGetTypePtr = dlsym (RTLD_DEFAULT, "CGContextGetType"); + CGContextGetAllowsFontSmoothingPtr = + dlsym (RTLD_DEFAULT, "CGContextGetAllowsFontSmoothing"); + symbol_lookup_done = TRUE; + } +} + +typedef struct +{ + cairo_surface_t base; + CGImageRef image; +} cairo_quartz_snapshot_t; + +static cairo_surface_t* _cairo_quartz_snapshot_create (cairo_surface_t *surface); +static cairo_status_t _cairo_quartz_snapshot_finish (void *surface); +static CGImageRef _cairo_quartz_surface_snapshot_get_image (cairo_surface_t *surface); + +static const cairo_surface_backend_t cairo_quartz_snapshot_backend = { + CAIRO_INTERNAL_SURFACE_TYPE_QUARTZ_SNAPSHOT, + _cairo_quartz_snapshot_finish, +}; + +static cairo_quartz_surface_t * +_cairo_quartz_surface_create_internal (CGContextRef cgContext, + cairo_content_t content, + unsigned int width, + unsigned int height); + +CGColorSpaceRef +_cairo_quartz_create_color_space (CGContextRef context) +{ + CGColorSpaceRef color_space = NULL; + CGContextType cgtype = kCGContextTypeUnknown; + + if (context) + { + if (CGBitmapContextGetBitsPerPixel (context) < 24) + return 0; + + quartz_ensure_symbols(); + cgtype = CGContextGetTypePtr (context); + switch (cgtype) + { + case kCGContextTypeUnknown: + break; + case kCGContextTypePDF: + color_space = CGColorSpaceCreateDeviceRGB (); + break; + case kCGContextTypePostScript: + case kCGContextTypeWindow: + break; + case kCGContextTypeBitmap: + color_space = CGBitmapContextGetColorSpace (context); + color_space = CGColorSpaceRetain (color_space); + break; + case kCGContextTypeGL: + case kCGContextTypeDisplayList: + case kCGContextTypeKSeparation: + case kCGContextTypeIOSurface: + case kCGContextTypeCount: + default: + break; + } + if (color_space) + return color_space; + } + if (!color_space) + color_space = CGDisplayCopyColorSpace (CGMainDisplayID ()); + + if (!color_space) + color_space = CGColorSpaceCreateDeviceRGB (); + + return color_space; +} + +static CGColorRef +_cairo_quartz_create_cgcolor (CGColorSpaceRef cs, CGFloat red, CGFloat green, + CGFloat blue, CGFloat alpha) +{ + CGFloat colors[4] = { red, green, blue, alpha }; + CGColorRef cgc; + if (!CGColorSpaceRetain(cs)) + { + cs = _cairo_quartz_create_color_space (NULL); + } + cgc = CGColorCreate (cs, colors); + CGColorSpaceRelease (cs); + return cgc; +} + +static CGColorRef +_cairo_quartz_black (CGColorSpaceRef cs) +{ + return _cairo_quartz_create_cgcolor (cs, 0.0, 0.0, 0.0, 1.0); +} + +static inline cairo_bool_t +_cairo_quartz_is_cgcontext_bitmap_context (CGContextRef cgc) +{ + if (unlikely (cgc == NULL)) + return FALSE; + + quartz_ensure_symbols (); + if (likely (CGContextGetTypePtr)) { + /* 4 is the type value of a bitmap context */ + return CGContextGetTypePtr (cgc) == kCGContextTypeBitmap; + } + + /* This will cause a (harmless) warning to be printed if called on a non-bitmap context */ + return CGBitmapContextGetBitsPerPixel (cgc) != 0; +} + +/* CoreGraphics limitation with flipped CTM surfaces: height must be less than signed 16-bit max */ + +#define CG_MAX_HEIGHT SHRT_MAX +#define CG_MAX_WIDTH USHRT_MAX + +/* is the desired size of the surface within bounds? */ +cairo_bool_t +_cairo_quartz_verify_surface_size (int width, int height) +{ + /* hmmm, allow width, height == 0 ? */ + if (width < 0 || height < 0) + return FALSE; + + if (width > CG_MAX_WIDTH || height > CG_MAX_HEIGHT) + return FALSE; + + return TRUE; +} + +/* + * Cairo path -> Quartz path conversion helpers + */ + +/* cairo path -> execute in context */ +static cairo_status_t +_cairo_path_to_quartz_context_move_to (void *closure, + const cairo_point_t *point) +{ + //ND ((stderr, "moveto: %f %f\n", _cairo_fixed_to_double (point->x), _cairo_fixed_to_double (point->y))); + double x = _cairo_fixed_to_double (point->x); + double y = _cairo_fixed_to_double (point->y); + + CGContextMoveToPoint (closure, x, y); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_path_to_quartz_context_line_to (void *closure, + const cairo_point_t *point) +{ + //ND ((stderr, "lineto: %f %f\n", _cairo_fixed_to_double (point->x), _cairo_fixed_to_double (point->y))); + double x = _cairo_fixed_to_double (point->x); + double y = _cairo_fixed_to_double (point->y); + + CGContextAddLineToPoint (closure, x, y); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_path_to_quartz_context_curve_to (void *closure, + const cairo_point_t *p0, + const cairo_point_t *p1, + const cairo_point_t *p2) +{ + //ND ((stderr, "curveto: %f,%f %f,%f %f,%f\n", + // _cairo_fixed_to_double (p0->x), _cairo_fixed_to_double (p0->y), + // _cairo_fixed_to_double (p1->x), _cairo_fixed_to_double (p1->y), + // _cairo_fixed_to_double (p2->x), _cairo_fixed_to_double (p2->y))); + double x0 = _cairo_fixed_to_double (p0->x); + double y0 = _cairo_fixed_to_double (p0->y); + double x1 = _cairo_fixed_to_double (p1->x); + double y1 = _cairo_fixed_to_double (p1->y); + double x2 = _cairo_fixed_to_double (p2->x); + double y2 = _cairo_fixed_to_double (p2->y); + + CGContextAddCurveToPoint (closure, x0, y0, x1, y1, x2, y2); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_path_to_quartz_context_close_path (void *closure) +{ + //ND ((stderr, "closepath\n")); + CGContextClosePath (closure); + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_quartz_cairo_path_to_quartz_context (const cairo_path_fixed_t *path, + CGContextRef closure) +{ + cairo_status_t status; + + CGContextBeginPath (closure); + status = _cairo_path_fixed_interpret (path, + _cairo_path_to_quartz_context_move_to, + _cairo_path_to_quartz_context_line_to, + _cairo_path_to_quartz_context_curve_to, + _cairo_path_to_quartz_context_close_path, + closure); + + assert (status == CAIRO_STATUS_SUCCESS); +} + +/* + * Misc helpers/callbacks + */ + + +static CGBlendMode +_cairo_quartz_cairo_operator_to_quartz_blend (cairo_operator_t op) +{ + switch (op) { + case CAIRO_OPERATOR_MULTIPLY: + return kCGBlendModeMultiply; + case CAIRO_OPERATOR_SCREEN: + return kCGBlendModeScreen; + case CAIRO_OPERATOR_OVERLAY: + return kCGBlendModeOverlay; + case CAIRO_OPERATOR_DARKEN: + return kCGBlendModeDarken; + case CAIRO_OPERATOR_LIGHTEN: + return kCGBlendModeLighten; + case CAIRO_OPERATOR_COLOR_DODGE: + return kCGBlendModeColorDodge; + case CAIRO_OPERATOR_COLOR_BURN: + return kCGBlendModeColorBurn; + case CAIRO_OPERATOR_HARD_LIGHT: + return kCGBlendModeHardLight; + case CAIRO_OPERATOR_SOFT_LIGHT: + return kCGBlendModeSoftLight; + case CAIRO_OPERATOR_DIFFERENCE: + return kCGBlendModeDifference; + case CAIRO_OPERATOR_EXCLUSION: + return kCGBlendModeExclusion; + case CAIRO_OPERATOR_HSL_HUE: + return kCGBlendModeHue; + case CAIRO_OPERATOR_HSL_SATURATION: + return kCGBlendModeSaturation; + case CAIRO_OPERATOR_HSL_COLOR: + return kCGBlendModeColor; + case CAIRO_OPERATOR_HSL_LUMINOSITY: + return kCGBlendModeLuminosity; + + case CAIRO_OPERATOR_CLEAR: + return kCGBlendModeClear; + case CAIRO_OPERATOR_SOURCE: + return kCGBlendModeCopy; + case CAIRO_OPERATOR_OVER: + return kCGBlendModeNormal; + case CAIRO_OPERATOR_IN: + return kCGBlendModeSourceIn; + case CAIRO_OPERATOR_OUT: + return kCGBlendModeSourceOut; + case CAIRO_OPERATOR_ATOP: + return kCGBlendModeSourceAtop; + case CAIRO_OPERATOR_DEST_OVER: + return kCGBlendModeDestinationOver; + case CAIRO_OPERATOR_DEST_IN: + return kCGBlendModeDestinationIn; + case CAIRO_OPERATOR_DEST_OUT: + return kCGBlendModeDestinationOut; + case CAIRO_OPERATOR_DEST_ATOP: + return kCGBlendModeDestinationAtop; + case CAIRO_OPERATOR_XOR: + return kCGBlendModeXOR; + case CAIRO_OPERATOR_ADD: + return kCGBlendModePlusLighter; + case CAIRO_OPERATOR_DEST: + case CAIRO_OPERATOR_SATURATE: + default: + ASSERT_NOT_REACHED; + } +} + +static cairo_int_status_t +_cairo_cgcontext_set_cairo_operator (CGContextRef context, cairo_operator_t op) +{ + CGBlendMode blendmode; + + assert (op != CAIRO_OPERATOR_DEST); + + /* Quartz doesn't support SATURATE at all. COLOR_DODGE and + * COLOR_BURN in Quartz follow the ISO32000 definition, but cairo + * uses the definition from the Adobe Supplement. Also fallback + * on SOFT_LIGHT and HSL_HUE, because their results are + * significantly different from those provided by pixman. + */ + if (op == CAIRO_OPERATOR_SATURATE || + op == CAIRO_OPERATOR_SOFT_LIGHT || + op == CAIRO_OPERATOR_HSL_HUE || + op == CAIRO_OPERATOR_COLOR_DODGE || + op == CAIRO_OPERATOR_COLOR_BURN) + { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + blendmode = _cairo_quartz_cairo_operator_to_quartz_blend (op); + CGContextSetBlendMode (context, blendmode); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_quartz_surface_set_cairo_operator (cairo_quartz_surface_t *surface, cairo_operator_t op) +{ + ND((stderr, "%p _cairo_quartz_surface_set_cairo_operator %d\n", surface, op)); + + /* When the destination has no color components, we can avoid some + * fallbacks, but we have to workaround operators which behave + * differently in Quartz. */ + if (surface->base.content == CAIRO_CONTENT_ALPHA) { + assert (op != CAIRO_OPERATOR_ATOP); /* filtered by surface layer */ + + if (op == CAIRO_OPERATOR_SOURCE || + op == CAIRO_OPERATOR_IN || + op == CAIRO_OPERATOR_OUT || + op == CAIRO_OPERATOR_DEST_IN || + op == CAIRO_OPERATOR_DEST_ATOP || + op == CAIRO_OPERATOR_XOR) + { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + if (op == CAIRO_OPERATOR_DEST_OVER) + op = CAIRO_OPERATOR_OVER; + else if (op == CAIRO_OPERATOR_SATURATE) + op = CAIRO_OPERATOR_ADD; + else if (op == CAIRO_OPERATOR_COLOR_DODGE) + op = CAIRO_OPERATOR_OVER; + else if (op == CAIRO_OPERATOR_COLOR_BURN) + op = CAIRO_OPERATOR_OVER; + } + + return _cairo_cgcontext_set_cairo_operator (surface->cgContext, op); +} + +static inline CGLineCap +_cairo_quartz_cairo_line_cap_to_quartz (cairo_line_cap_t ccap) +{ + switch (ccap) { + default: + ASSERT_NOT_REACHED; + + case CAIRO_LINE_CAP_BUTT: + return kCGLineCapButt; + + case CAIRO_LINE_CAP_ROUND: + return kCGLineCapRound; + + case CAIRO_LINE_CAP_SQUARE: + return kCGLineCapSquare; + } +} + +static inline CGLineJoin +_cairo_quartz_cairo_line_join_to_quartz (cairo_line_join_t cjoin) +{ + switch (cjoin) { + default: + ASSERT_NOT_REACHED; + + case CAIRO_LINE_JOIN_MITER: + return kCGLineJoinMiter; + + case CAIRO_LINE_JOIN_ROUND: + return kCGLineJoinRound; + + case CAIRO_LINE_JOIN_BEVEL: + return kCGLineJoinBevel; + } +} + +static inline CGInterpolationQuality +_cairo_quartz_filter_to_quartz (cairo_filter_t filter) +{ + /* The CGInterpolationQuality enumeration values seem to have the + * following meaning: + * - kCGInterpolationNone: nearest neighbor + * - kCGInterpolationLow: bilinear + * - kCGInterpolationHigh: bicubic? Lanczos? + */ + + switch (filter) { + case CAIRO_FILTER_NEAREST: + case CAIRO_FILTER_FAST: + return kCGInterpolationNone; + + case CAIRO_FILTER_BEST: + return kCGInterpolationHigh; + + case CAIRO_FILTER_GOOD: + case CAIRO_FILTER_BILINEAR: + return kCGInterpolationLow; + + case CAIRO_FILTER_GAUSSIAN: + return kCGInterpolationDefault; + + default: + ASSERT_NOT_REACHED; + return kCGInterpolationDefault; + } +} + +static inline void +_cairo_quartz_cairo_matrix_to_quartz (const cairo_matrix_t *src, + CGAffineTransform *dst) +{ + dst->a = src->xx; + dst->b = src->yx; + dst->c = src->xy; + dst->d = src->yy; + dst->tx = src->x0; + dst->ty = src->y0; +} + + +/* + * Source -> Quartz setup and finish functions + */ + +static void +ComputeGradientValue (void *info, + const cairo_quartz_float_t *in, + cairo_quartz_float_t *out) +{ + double fdist = *in; + const cairo_gradient_pattern_t *grad = (cairo_gradient_pattern_t*) info; + unsigned int i; + + /* Put fdist back in the 0.0..1.0 range if we're doing + * REPEAT/REFLECT + */ + if (grad->base.extend == CAIRO_EXTEND_REPEAT) { + fdist = fdist - floor (fdist); + } else if (grad->base.extend == CAIRO_EXTEND_REFLECT) { + fdist = fmod (fabs (fdist), 2.0); + if (fdist > 1.0) + fdist = 2.0 - fdist; + } + + for (i = 0; i < grad->n_stops; i++) + if (grad->stops[i].offset > fdist) + break; + + if (i == 0 || i == grad->n_stops) { + if (i == grad->n_stops) + --i; + out[0] = grad->stops[i].color.red; + out[1] = grad->stops[i].color.green; + out[2] = grad->stops[i].color.blue; + out[3] = grad->stops[i].color.alpha; + } else { + cairo_quartz_float_t ax = grad->stops[i-1].offset; + cairo_quartz_float_t bx = grad->stops[i].offset - ax; + cairo_quartz_float_t bp = (fdist - ax)/bx; + cairo_quartz_float_t ap = 1.0 - bp; + + out[0] = + grad->stops[i-1].color.red * ap + + grad->stops[i].color.red * bp; + out[1] = + grad->stops[i-1].color.green * ap + + grad->stops[i].color.green * bp; + out[2] = + grad->stops[i-1].color.blue * ap + + grad->stops[i].color.blue * bp; + out[3] = + grad->stops[i-1].color.alpha * ap + + grad->stops[i].color.alpha * bp; + } +} + +static const cairo_quartz_float_t gradient_output_value_ranges[8] = { + 0.f, 1.f, 0.f, 1.f, 0.f, 1.f, 0.f, 1.f +}; +static const CGFunctionCallbacks gradient_callbacks = { + 0, ComputeGradientValue, (CGFunctionReleaseInfoCallback) cairo_pattern_destroy +}; + +/* Quartz computes a small number of samples of the gradient color + * function. On MacOS X 10.5 it apparently computes only 1024 + * samples. */ +#define MAX_GRADIENT_RANGE 1024 + +static CGFunctionRef +CairoQuartzCreateGradientFunction (const cairo_gradient_pattern_t *gradient, + const cairo_rectangle_int_t *extents, + cairo_circle_double_t *start, + cairo_circle_double_t *end) +{ + cairo_pattern_t *pat; + cairo_quartz_float_t input_value_range[2]; + + if (gradient->base.extend != CAIRO_EXTEND_NONE) { + double bounds_x1, bounds_x2, bounds_y1, bounds_y2; + double t[2], tolerance; + + tolerance = fabs (_cairo_matrix_compute_determinant (&gradient->base.matrix)); + tolerance /= _cairo_matrix_transformed_circle_major_axis (&gradient->base.matrix, 1); + + bounds_x1 = extents->x; + bounds_y1 = extents->y; + bounds_x2 = extents->x + extents->width; + bounds_y2 = extents->y + extents->height; + _cairo_matrix_transform_bounding_box (&gradient->base.matrix, + &bounds_x1, &bounds_y1, + &bounds_x2, &bounds_y2, + NULL); + + _cairo_gradient_pattern_box_to_parameter (gradient, + bounds_x1, bounds_y1, + bounds_x2, bounds_y2, + tolerance, + t); + + if (gradient->base.extend == CAIRO_EXTEND_PAD) { + t[0] = MAX (t[0], -0.5); + t[1] = MIN (t[1], 1.5); + } else if (t[1] - t[0] > MAX_GRADIENT_RANGE) + return NULL; + + /* set the input range for the function -- the function knows how + to map values outside of 0.0 .. 1.0 to the correct color */ + input_value_range[0] = t[0]; + input_value_range[1] = t[1]; + } else { + input_value_range[0] = 0; + input_value_range[1] = 1; + } + + _cairo_gradient_pattern_interpolate (gradient, input_value_range[0], start); + _cairo_gradient_pattern_interpolate (gradient, input_value_range[1], end); + + if (_cairo_pattern_create_copy (&pat, &gradient->base)) + return NULL; + + return CGFunctionCreate (pat, + 1, + input_value_range, + 4, + gradient_output_value_ranges, + &gradient_callbacks); +} + +static cairo_status_t +_cairo_surface_to_cgimage (cairo_surface_t *source, + cairo_rectangle_int_t *extents, + cairo_format_t format, + cairo_matrix_t *matrix, + const cairo_clip_t *clip, + CGImageRef *image_out) +{ + cairo_status_t status; + cairo_quartz_image_surface_t *image_surface; + void *image_extra; + cairo_bool_t acquired = FALSE; + + if (_is_quartz_surface (source)) { + CGContextRef cgContext = cairo_quartz_surface_get_cg_context(source); + if (_cairo_quartz_is_zero_surface (source)) { + *image_out = NULL; + return CAIRO_INT_STATUS_NOTHING_TO_DO; + } + + if (_cairo_quartz_is_cgcontext_bitmap_context (cgContext)) { + *image_out = _cairo_quartz_surface_snapshot_get_image (source); + return CAIRO_STATUS_SUCCESS; + } + + *image_out = NULL; + return CAIRO_STATUS_SURFACE_TYPE_MISMATCH; + } + + if (source->type == CAIRO_SURFACE_TYPE_RECORDING) { + cairo_image_surface_t *surface = + (cairo_image_surface_t*)cairo_image_surface_create (format, extents->width, + extents->height); + if (unlikely (surface->base.status)) { + status = surface->base.status; + cairo_surface_destroy (&surface->base); + return status; + } + + status = _cairo_recording_surface_replay_with_clip (source, + matrix, + &surface->base, + NULL); + if (unlikely (status)) { + cairo_surface_destroy (&surface->base); + return status; + } + + image_surface = + (cairo_quartz_image_surface_t*)cairo_quartz_image_surface_create (&surface->base); + cairo_matrix_init_identity (matrix); + } + else { + cairo_image_surface_t *surface; + status = _cairo_surface_acquire_source_image (source, &surface, + &image_extra); + if (unlikely (status)) + return status; + image_surface = + (cairo_quartz_image_surface_t*)cairo_quartz_image_surface_create (&surface->base); + status = image_surface->base.status; + if (status) + _cairo_surface_release_source_image (source, surface, image_extra); + else + acquired = TRUE; + } + + *image_out = NULL; + if (image_surface->width > 0 && image_surface->height > 0) { + *image_out = _cairo_quartz_surface_snapshot_get_image (&image_surface->base); + status = CAIRO_STATUS_SUCCESS; + } + + if (acquired) { + _cairo_surface_release_source_image (source, image_surface->imageSurface, image_extra); + image_surface->imageSurface = NULL; + } + cairo_surface_destroy (&image_surface->base); + + /* TODO: differentiate memory error and unsupported surface type */ + if (unlikely (*image_out == NULL)) + status = CAIRO_INT_STATUS_UNSUPPORTED; + + return status; +} + +/* Generic #cairo_pattern_t -> CGPattern function */ + +typedef struct { + CGImageRef image; + CGRect imageBounds; + cairo_bool_t do_reflect; +} SurfacePatternDrawInfo; + +static void +SurfacePatternDrawFunc (void *ainfo, CGContextRef context) +{ + SurfacePatternDrawInfo *info = (SurfacePatternDrawInfo*) ainfo; + + CGContextTranslateCTM (context, 0, info->imageBounds.size.height); + CGContextScaleCTM (context, 1, -1); + + CGContextDrawImage (context, info->imageBounds, info->image); + if (info->do_reflect) { + /* draw 3 more copies of the image, flipped. + * DrawImage draws the image according to the current Y-direction into the rectangle given + * (imageBounds); at the time of the first DrawImage above, the origin is at the bottom left + * of the base image position, and the Y axis is extending upwards. + */ + + /* Make the y axis extend downwards, and draw a flipped image below */ + CGContextScaleCTM (context, 1, -1); + CGContextDrawImage (context, info->imageBounds, info->image); + + /* Shift over to the right, and flip vertically (translation is 2x, + * since we'll be flipping and thus rendering the rectangle "backwards" + */ + CGContextTranslateCTM (context, 2 * info->imageBounds.size.width, 0); + CGContextScaleCTM (context, -1, 1); + CGContextDrawImage (context, info->imageBounds, info->image); + + /* Then unflip the Y-axis again, and draw the image above the point. */ + CGContextScaleCTM (context, 1, -1); + CGContextDrawImage (context, info->imageBounds, info->image); + } +} + +static void +SurfacePatternReleaseInfoFunc (void *ainfo) +{ + SurfacePatternDrawInfo *info = (SurfacePatternDrawInfo*) ainfo; + + CGImageRelease (info->image); + free (info); +} + +static cairo_int_status_t +_cairo_quartz_cairo_repeating_surface_pattern_to_quartz (cairo_quartz_surface_t *surface, + const cairo_pattern_t *source, + const cairo_clip_t *clip, + CGPatternRef *cgpat) +{ + cairo_surface_pattern_t *spattern = (cairo_surface_pattern_t *) source; + cairo_surface_t *pat_surf = spattern->surface; + cairo_rectangle_int_t extents; + cairo_format_t format = _cairo_format_from_content (surface->base.content); + + CGImageRef image; + CGRect pbounds; + CGAffineTransform ptransform, stransform; + CGPatternCallbacks cb = { 0, + SurfacePatternDrawFunc, + SurfacePatternReleaseInfoFunc }; + SurfacePatternDrawInfo *info; + cairo_quartz_float_t rw, rh; + cairo_status_t status; + cairo_bool_t is_bounded = _cairo_surface_get_extents (pat_surf, &extents); + cairo_matrix_t m = spattern->base.matrix; + + /* SURFACE is the only type we'll handle here */ + assert (source->type == CAIRO_PATTERN_TYPE_SURFACE); + + if (pat_surf->type != CAIRO_SURFACE_TYPE_RECORDING) + assert (is_bounded); + + status = _cairo_surface_to_cgimage (pat_surf, &extents, format, + &m, clip, &image); + + if (unlikely (status)) + return status; + + info = _cairo_calloc (sizeof (SurfacePatternDrawInfo)); + if (unlikely (!info)) + { + CGImageRelease (image); + return CAIRO_STATUS_NO_MEMORY; + } + + info->image = image; + info->imageBounds = CGRectMake (0, 0, extents.width, extents.height); + info->do_reflect = FALSE; + + pbounds.origin.x = 0; + pbounds.origin.y = 0; + + switch (spattern->base.extend) { + case CAIRO_EXTEND_NONE: + case CAIRO_EXTEND_PAD: + case CAIRO_EXTEND_REPEAT: + pbounds.size.width = extents.width; + pbounds.size.height = extents.height; + break; + case CAIRO_EXTEND_REFLECT: + pbounds.size.width = 2.0 * extents.width; + pbounds.size.height = 2.0 * extents.height; + info->do_reflect = TRUE; + break; + } + rw = pbounds.size.width; + rh = pbounds.size.height; + + cairo_matrix_invert (&m); + _cairo_quartz_cairo_matrix_to_quartz (&m, &stransform); + + /* The pattern matrix is relative to the bottom left, again; the + * incoming cairo pattern matrix is relative to the upper left. + * So we take the pattern matrix and the original context matrix, + * which gives us the correct base translation/y flip. + */ + ptransform = CGAffineTransformConcat (stransform, surface->cgContextBaseCTM); + +#ifdef QUARTZ_DEBUG + ND ((stderr, " pbounds: %f %f %f %f\n", pbounds.origin.x, pbounds.origin.y, pbounds.size.width, pbounds.size.height)); + ND ((stderr, " pattern xform: t: %f %f xx: %f xy: %f yx: %f yy: %f\n", ptransform.tx, ptransform.ty, ptransform.a, ptransform.b, ptransform.c, ptransform.d)); + CGAffineTransform xform = CGContextGetCTM (surface->cgContext); + ND ((stderr, " context xform: t: %f %f xx: %f xy: %f yx: %f yy: %f\n", xform.tx, xform.ty, xform.a, xform.b, xform.c, xform.d)); +#endif + + *cgpat = CGPatternCreate (info, + pbounds, + ptransform, + rw, rh, + kCGPatternTilingConstantSpacing, /* kCGPatternTilingNoDistortion, */ + TRUE, + &cb); + + return CAIRO_STATUS_SUCCESS; +} + +/* State used during a drawing operation. */ +typedef struct { + /* The destination of the mask */ + CGContextRef cgMaskContext; + + /* The destination of the drawing of the source */ + CGContextRef cgDrawContext; + + /* The filter to be used when drawing the source */ + CGInterpolationQuality filter; + + /* Action type */ + cairo_quartz_action_t action; + + /* Destination rect */ + CGRect rect; + + /* Used with DO_SHADING, DO_IMAGE */ + CGAffineTransform transform; + + /* Used with DO_IMAGE */ + CGImageRef image; + + /* Used with DO_SHADING */ + CGShadingRef shading; + + /* Temporary destination for unbounded operations */ + CGLayerRef layer; + CGRect clipRect; +} cairo_quartz_drawing_state_t; + +static cairo_int_status_t +_cairo_quartz_setup_pattern_source (cairo_quartz_drawing_state_t *state, + const cairo_pattern_t *source, + cairo_quartz_surface_t *surface, + const cairo_clip_t *clip, + cairo_operator_t op) +{ + const cairo_surface_pattern_t *spat = (const cairo_surface_pattern_t *) source; + cairo_surface_t *pat_surf = spat->surface; + cairo_matrix_t m = spat->base.matrix; + cairo_format_t format = _cairo_format_from_content (surface->base.content); + cairo_rectangle_int_t extents, pattern_extents; + CGImageRef img; + + cairo_quartz_float_t patternAlpha = 1.0f; + CGColorSpaceRef patternSpace; + CGPatternRef cgpat = NULL; + cairo_int_status_t status; + CGColorRef black = _cairo_quartz_black (_cairo_quartz_create_color_space (state->cgDrawContext)); + + _cairo_surface_get_extents (&surface->base, &extents); + + if (pat_surf->backend->type == CAIRO_SURFACE_TYPE_QUARTZ) { + cairo_quartz_surface_t *quartz_surf = (cairo_quartz_surface_t *) pat_surf; + + if (quartz_surf->cgLayer && source->extend == CAIRO_EXTEND_NONE) { + cairo_matrix_invert (&m); + _cairo_quartz_cairo_matrix_to_quartz (&m, &state->transform); + state->rect = CGRectMake (0, 0, quartz_surf->extents.width, quartz_surf->extents.height); + state->layer = quartz_surf->cgLayer; + state->action = DO_LAYER; + return CAIRO_STATUS_SUCCESS; + } + } + + status = _cairo_surface_to_cgimage (pat_surf, &extents, format, + &m, clip, &img); // Note that only pat_surf will get used! + if (unlikely (status)) + return status; + + state->image = img; + + if (state->filter == kCGInterpolationNone && _cairo_matrix_is_translation (&m)) { + m.x0 = -ceil (m.x0 - 0.5); + m.y0 = -ceil (m.y0 - 0.5); + } else { + cairo_matrix_invert (&m); + } + + _cairo_quartz_cairo_matrix_to_quartz (&m, &state->transform); + + if (pat_surf->type != CAIRO_SURFACE_TYPE_RECORDING) { + cairo_bool_t is_bounded = _cairo_surface_get_extents (pat_surf, &pattern_extents); + assert (is_bounded); + } else { + _cairo_surface_get_extents (&surface->base, &pattern_extents); + } + + if (source->extend == CAIRO_EXTEND_NONE) { + int x, y; + + if (op == CAIRO_OPERATOR_SOURCE && + (pat_surf->content == CAIRO_CONTENT_ALPHA || + ! _cairo_matrix_is_integer_translation (&m, &x, &y))) + { + state->layer = CGLayerCreateWithContext (surface->cgContext, + state->clipRect.size, + NULL); + state->cgDrawContext = CGLayerGetContext (state->layer); + CGContextTranslateCTM (state->cgDrawContext, + -state->clipRect.origin.x, + -state->clipRect.origin.y); + } + + CGContextSetFillColorWithColor (state->cgDrawContext, black); + + state->rect = CGRectMake (0, 0, pattern_extents.width, pattern_extents.height); + state->action = DO_IMAGE; + return CAIRO_STATUS_SUCCESS; + } + + if (source->extend == CAIRO_EXTEND_REPEAT) + { + CGAffineTransform xform = CGAffineTransformConcat (CGContextGetCTM (state->cgDrawContext), + state->transform); + CGRect srcRect = CGRectMake (0, 0, extents.width, extents.height); + srcRect = CGRectApplyAffineTransform (srcRect, xform); + xform = CGAffineTransformInvert (xform); + srcRect = CGRectApplyAffineTransform (srcRect, xform); + state->rect = srcRect; + } + + status = _cairo_quartz_cairo_repeating_surface_pattern_to_quartz (surface, source, clip, &cgpat); + if (unlikely (status)) + return status; + + patternSpace = CGColorSpaceCreatePattern (NULL); + /* To pass pthread-same-source. */ + if (source->extend == CAIRO_EXTEND_REPEAT) + CGContextSetInterpolationQuality(state->cgDrawContext, state->filter); + CGContextSetFillColorSpace (state->cgDrawContext, patternSpace); + CGContextSetFillPattern (state->cgDrawContext, cgpat, &patternAlpha); + CGContextSetStrokeColorSpace (state->cgDrawContext, patternSpace); + CGContextSetStrokePattern (state->cgDrawContext, cgpat, &patternAlpha); + CGColorSpaceRelease (patternSpace); + + /* Quartz likes to munge the pattern phase (as yet unexplained + * why); force it to 0,0 as we've already baked in the correct + * pattern translation into the pattern matrix + */ + CGContextSetPatternPhase (state->cgDrawContext, CGSizeMake (0, 0)); + + CGPatternRelease (cgpat); + CGColorRelease (black); + + state->action = DO_DIRECT; + return CAIRO_STATUS_SUCCESS; +} + + +/* +Quartz does not support repeating gradients. We handle repeating gradients +by manually extending the gradient and repeating color stops. We need to +minimize the number of repetitions since Quartz seems to sample our color +function across the entire range, even if part of that range is not needed +for the visible area of the gradient, and it samples with some fixed resolution, +so if the gradient range is too large it samples with very low resolution and +the gradient is very coarse. _cairo_quartz_create_gradient_function computes +the number of repetitions needed based on the extents. +*/ +static cairo_int_status_t +_cairo_quartz_setup_gradient_source (cairo_quartz_drawing_state_t *state, + const cairo_gradient_pattern_t *gradient, + const cairo_rectangle_int_t *extents) +{ + cairo_matrix_t mat; + cairo_circle_double_t start, end; + CGFunctionRef gradFunc; + CGColorSpaceRef rgb; + bool extend = gradient->base.extend != CAIRO_EXTEND_NONE; + + assert (gradient->n_stops > 0); + + mat = gradient->base.matrix; + cairo_matrix_invert (&mat); + _cairo_quartz_cairo_matrix_to_quartz (&mat, &state->transform); + + gradFunc = CairoQuartzCreateGradientFunction (gradient, extents, + &start, &end); + + if (unlikely (gradFunc == NULL)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + rgb = _cairo_quartz_create_color_space (NULL); + + if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) { + state->shading = CGShadingCreateAxial (rgb, + CGPointMake (start.center.x, + start.center.y), + CGPointMake (end.center.x, + end.center.y), + gradFunc, + extend, extend); + } else { + state->shading = CGShadingCreateRadial (rgb, + CGPointMake (start.center.x, + start.center.y), + MAX (start.radius, 0), + CGPointMake (end.center.x, + end.center.y), + MAX (end.radius, 0), + gradFunc, + extend, extend); + } + + CGColorSpaceRelease (rgb); + CGFunctionRelease (gradFunc); + + state->action = DO_SHADING; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_quartz_setup_state (cairo_quartz_drawing_state_t *state, + cairo_composite_rectangles_t *composite) +{ + cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) composite->surface; + cairo_operator_t op = composite->op; + const cairo_pattern_t *source = &composite->source_pattern.base; + const cairo_clip_t *clip = composite->clip; + cairo_bool_t needs_temp; + cairo_status_t status; + + state->layer = NULL; + state->image = NULL; + state->shading = NULL; + state->cgDrawContext = NULL; + state->cgMaskContext = NULL; + state->layer = NULL; + + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) + return status; + + status = _cairo_quartz_surface_set_cairo_operator (surface, op); + if (unlikely (status)) + return status; + + /* Save before we change the pattern, colorspace, etc. so that + * we can restore and make sure that quartz releases our + * pattern (which may be stack allocated) + */ + + CGContextSaveGState (surface->cgContext); + state->clipRect = CGContextGetClipBoundingBox (surface->cgContext); + state->clipRect = CGRectIntegral (state->clipRect); + state->rect = state->clipRect; + + state->cgMaskContext = surface->cgContext; + state->cgDrawContext = state->cgMaskContext; + + state->filter = _cairo_quartz_filter_to_quartz (source->filter); + + if (op == CAIRO_OPERATOR_CLEAR) { + CGColorRef black = _cairo_quartz_black (_cairo_quartz_create_color_space (surface->cgContext)); + CGContextSetFillColorWithColor (state->cgDrawContext, black); + + state->action = DO_DIRECT; + CGColorRelease (black); + return CAIRO_STATUS_SUCCESS; + } + + /* + * To implement mask unbounded operations Quartz needs a temporary + * surface which will be composited entirely (ignoring the mask). + * To implement source unbounded operations Quartz needs a + * temporary surface which allows extending the source to a size + * covering the whole mask, but there are some optimization + * opportunities: + * + * - CLEAR completely ignores the source, thus we can just use a + * solid color fill. + * + * - SOURCE can be implemented by drawing the source and clearing + * outside of the source as long as the two regions have no + * intersection. This happens when the source is a pixel-aligned + * rectangle. If the source is at least as big as the + * intersection between the clip rectangle and the mask + * rectangle, no clear operation is needed. + */ + needs_temp = ! _cairo_operator_bounded_by_mask (op); + + if (needs_temp) { + state->layer = CGLayerCreateWithContext (surface->cgContext, + state->clipRect.size, + NULL); + state->cgDrawContext = CGLayerGetContext (state->layer); + state->cgMaskContext = state->cgDrawContext; + CGContextTranslateCTM (state->cgDrawContext, + -state->clipRect.origin.x, + -state->clipRect.origin.y); + } + + if (source->type == CAIRO_PATTERN_TYPE_SOLID) { + cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source; + CGColorRef color = _cairo_quartz_create_cgcolor (_cairo_quartz_create_color_space (state->cgDrawContext), + solid->color.red, + solid->color.green, + solid->color.blue, + solid->color.alpha); + + + CGContextSetStrokeColorWithColor (state->cgDrawContext, color); + CGContextSetFillColorWithColor (state->cgDrawContext, color); + + CGColorRelease (color); + state->action = DO_DIRECT; + return CAIRO_STATUS_SUCCESS; + } + + if (source->type == CAIRO_PATTERN_TYPE_LINEAR || + source->type == CAIRO_PATTERN_TYPE_RADIAL) + { + const cairo_gradient_pattern_t *gpat = (const cairo_gradient_pattern_t *)source; + cairo_rectangle_int_t extents; + + extents = surface->virtual_extents; + extents.x -= surface->base.device_transform.x0; + extents.y -= surface->base.device_transform.y0; + _cairo_rectangle_union (&extents, &surface->extents); + + return _cairo_quartz_setup_gradient_source (state, gpat, &extents); + } + + + if (source->type == CAIRO_PATTERN_TYPE_SURFACE) + return _cairo_quartz_setup_pattern_source (state, source, surface, clip, op); + + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static void +_cairo_quartz_teardown_state (cairo_quartz_drawing_state_t *state, + cairo_composite_rectangles_t *extents) +{ + cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) extents->surface; + + if (state->layer) { + if (state->action != DO_LAYER) + CGContextDrawLayerInRect (surface->cgContext, + state->clipRect, + state->layer); + CGLayerRelease (state->layer); + } + + if (state->cgMaskContext) + CGContextRestoreGState (surface->cgContext); + + if (state->image) + CGImageRelease (state->image); + + if (state->shading) + CGShadingRelease (state->shading); +} + +static inline void +_cairo_quartz_draw_cgcontext (cairo_quartz_drawing_state_t *state, + cairo_operator_t op) +{ + CGColorSpaceRef cs = _cairo_quartz_create_color_space (state->cgDrawContext); + CGColorRef transparent = _cairo_quartz_create_cgcolor (cs, 0.0, 0.0, 0.0, 0.0); //releases cs + + if (! (op == CAIRO_OPERATOR_SOURCE && + state->cgDrawContext == state->cgMaskContext)) + return; + + CGContextBeginPath (state->cgDrawContext); + CGContextAddRect (state->cgDrawContext, state->rect); + + CGContextTranslateCTM (state->cgDrawContext, 0, state->rect.size.height); + CGContextScaleCTM (state->cgDrawContext, 1, -1); + CGContextConcatCTM (state->cgDrawContext, + CGAffineTransformInvert (state->transform)); + + CGContextAddRect (state->cgDrawContext, state->clipRect); + + CGContextSetFillColorWithColor (state->cgDrawContext, transparent); + CGContextEOFillPath (state->cgDrawContext); + CGColorRelease (transparent); +} + + +static void +_cairo_quartz_draw_source (cairo_quartz_drawing_state_t *state, + cairo_operator_t op) +{ + CGContextSetShouldAntialias (state->cgDrawContext, state->filter != kCGInterpolationNone); + CGContextSetInterpolationQuality(state->cgDrawContext, state->filter); + + if (state->action == DO_DIRECT) { + CGContextFillRect (state->cgDrawContext, state->rect); + return; + } + + CGContextConcatCTM (state->cgDrawContext, state->transform); + + if (state->action == DO_SHADING) { + CGContextDrawShading (state->cgDrawContext, state->shading); + return; + } + + CGContextTranslateCTM (state->cgDrawContext, 0, state->rect.size.height); + CGContextScaleCTM (state->cgDrawContext, 1, -1); + + if (state->action == DO_IMAGE) { + CGContextDrawImage (state->cgDrawContext, state->rect, state->image); + _cairo_quartz_draw_cgcontext (state, op); + return; + } + + if (state->action == DO_LAYER) { + CGContextDrawLayerInRect (state->cgDrawContext, state->rect, state->layer); + _cairo_quartz_draw_cgcontext (state, op); + return; + } + assert (FALSE); // Unreachable +} + +static cairo_image_surface_t * +_cairo_quartz_surface_map_to_image (void *abstract_surface, + const cairo_rectangle_int_t *extents) +{ + cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; + cairo_surface_t *return_surface = NULL; + unsigned int stride, bitinfo, bpp, color_comps; + CGColorSpaceRef colorspace; + unsigned char *imageData; + cairo_format_t format; + + if (_cairo_quartz_is_zero_surface (&surface->base)) + return (cairo_image_surface_t *) cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0); + + if (! _cairo_quartz_is_cgcontext_bitmap_context (surface->cgContext)) + return _cairo_image_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); + + bitinfo = CGBitmapContextGetBitmapInfo (surface->cgContext); + bpp = CGBitmapContextGetBitsPerPixel (surface->cgContext); + + // let's hope they don't add YUV under us + colorspace = _cairo_quartz_create_color_space (surface->cgContext); + color_comps = CGColorSpaceGetNumberOfComponents (colorspace); + CGColorSpaceRelease (colorspace); + + /* XXX TODO: We can handle many more data formats by + * converting to pixman_format_t */ + + if (bpp == 32 && color_comps == 3 && + (bitinfo & kCGBitmapAlphaInfoMask) == kCGImageAlphaPremultipliedFirst && + (bitinfo & kCGBitmapByteOrderMask) == kCGBitmapByteOrder32Host) + { + format = CAIRO_FORMAT_ARGB32; + } + else if (bpp == 32 && color_comps == 3 && + (bitinfo & kCGBitmapAlphaInfoMask) == kCGImageAlphaNoneSkipFirst && + (bitinfo & kCGBitmapByteOrderMask) == kCGBitmapByteOrder32Host) + { + format = CAIRO_FORMAT_RGB24; + } + else if (bpp == 8 && color_comps == 0) + { + format = CAIRO_FORMAT_A8; + } + else + { + return _cairo_image_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); + } + + imageData = CGBitmapContextGetData (surface->cgContext); + stride = CGBitmapContextGetBytesPerRow (surface->cgContext); + + imageData += extents->y * stride + extents->x * bpp / 8; + return_surface = cairo_image_surface_create_for_data (imageData, + format, + extents->width, + extents->height, + stride); + + return (cairo_image_surface_t *) return_surface; +} + +static cairo_int_status_t +_cairo_quartz_surface_unmap_image (void *abstract_surface, + cairo_image_surface_t *image) +{ + cairo_surface_finish (&image->base); + cairo_surface_destroy (&image->base); + + return CAIRO_STATUS_SUCCESS; +} + + +/* + * Cairo surface backend implementations + */ + +static cairo_status_t +_cairo_quartz_surface_finish (void *abstract_surface) +{ + cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; + + ND ((stderr, "_cairo_quartz_surface_finish[%p] cgc: %p\n", surface, surface->cgContext)); + + if (_cairo_quartz_is_zero_surface (&surface->base)) + return CAIRO_STATUS_SUCCESS; + + /* Restore our saved gstate that we use to reset clipping */ + CGContextRestoreGState (surface->cgContext); + _cairo_surface_clipper_reset (&surface->clipper); + + CGContextRelease (surface->cgContext); + + surface->cgContext = NULL; + + if (surface->cgLayer) + { + CGLayerRelease (surface->cgLayer); + surface->cgLayer = NULL; + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_quartz_surface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) +{ + cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; + + //ND ((stderr, "%p _cairo_quartz_surface_acquire_source_image\n", surface)); + + *image_extra = NULL; + + *image_out = _cairo_quartz_surface_map_to_image (surface, &surface->extents); + if (unlikely (cairo_surface_status(&(*image_out)->base))) { + cairo_surface_destroy (&(*image_out)->base); + *image_out = NULL; + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_quartz_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) +{ + _cairo_quartz_surface_unmap_image (abstract_surface, image); +} + +static cairo_surface_t* +_cairo_quartz_surface_create_with_cglayer (cairo_quartz_surface_t *surface, + cairo_content_t content, + int width, int height) +{ + CGAffineTransform xform; + CGContextRef context; + CGLayerRef layer; + cairo_quartz_surface_t* new_surface; + + if (surface->cgContext == NULL || surface->cgLayer != NULL) + return NULL; + + if (width <= 0 || height <= 0) + return NULL; + + xform = CGContextGetUserSpaceToDeviceSpaceTransform (surface->cgContext); + layer = CGLayerCreateWithContext (surface->cgContext, + CGSizeMake (width * xform.a, + height * xform.d), + NULL); + + context = CGLayerGetContext (layer); + CGContextTranslateCTM (context, 0.0, height); + CGContextScaleCTM (context, xform.a, -xform.d); + new_surface = _cairo_quartz_surface_create_internal (context, content, + width, height); + if (unlikely (new_surface->base.status)) + { + CGContextRelease (context); + CGLayerRelease (layer); + return &new_surface->base; + } + new_surface->cgLayer = CGLayerRetain(layer); + CGContextRetain(context); + new_surface->virtual_extents = surface->virtual_extents; + + return &new_surface->base; +} + +static cairo_surface_t * +_cairo_quartz_surface_create_similar (void *abstract_surface, + cairo_content_t content, + int width, + int height) +{ + cairo_quartz_surface_t *surface, *similar_quartz; + cairo_surface_t *similar; + cairo_format_t format; + + // verify width and height of surface + if (!_cairo_quartz_verify_surface_size (width, height)) { + return _cairo_surface_create_in_error (_cairo_error + (CAIRO_STATUS_INVALID_SIZE)); + } + + surface = (cairo_quartz_surface_t *) abstract_surface; + if (surface->cgContext && !surface->cgLayer && !(width && height)) + _cairo_quartz_surface_create_with_cglayer (surface, content, + width, height); + + if (content == CAIRO_CONTENT_COLOR_ALPHA) + format = CAIRO_FORMAT_ARGB32; + else if (content == CAIRO_CONTENT_COLOR) + format = CAIRO_FORMAT_RGB24; + else if (content == CAIRO_CONTENT_ALPHA) + format = CAIRO_FORMAT_A8; + else + return NULL; + + similar = cairo_quartz_surface_create (format, width, height); + if (unlikely (similar->status)) + return similar; + + similar_quartz = (cairo_quartz_surface_t *) similar; + similar_quartz->virtual_extents = surface->virtual_extents; + + return similar; +} + +static cairo_bool_t +_cairo_quartz_surface_get_extents (void *abstract_surface, + cairo_rectangle_int_t *extents) +{ + cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *) abstract_surface; + + *extents = surface->extents; + return TRUE; +} + +static cairo_int_status_t +_cairo_quartz_cg_paint (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *extents) +{ + cairo_quartz_drawing_state_t state; + cairo_int_status_t rv; + + ND ((stderr, "%p _cairo_quartz_surface_paint op %d source->type %d\n", + extents->surface, extents->op, extents->source_pattern.base.type)); + + rv = _cairo_quartz_setup_state (&state, extents); + if (unlikely (rv)) + goto BAIL; + + _cairo_quartz_draw_source (&state, extents->op); + +BAIL: + _cairo_quartz_teardown_state (&state, extents); + + ND ((stderr, "-- paint\n")); + return rv; +} + +static cairo_int_status_t +_cairo_quartz_cg_mask_with_surface (cairo_composite_rectangles_t *extents, + cairo_surface_t *mask_surf, + const cairo_matrix_t *mask_mat, + CGInterpolationQuality filter) +{ + CGRect rect; + CGImageRef img; + cairo_status_t status; + CGAffineTransform mask_matrix; + cairo_quartz_drawing_state_t state; + cairo_format_t format = _cairo_format_from_content (extents->surface->content); + cairo_rectangle_int_t dest_extents; + cairo_matrix_t m = *mask_mat; + + _cairo_surface_get_extents (extents->surface, &dest_extents); + status = _cairo_surface_to_cgimage (mask_surf, &dest_extents, format, + &m, extents->clip, &img); + if (unlikely (status)) + return status; + + status = _cairo_quartz_setup_state (&state, extents); + if (unlikely (status)) + goto BAIL; + + rect = CGRectMake (0.0, 0.0, CGImageGetWidth (img), CGImageGetHeight (img)); + _cairo_quartz_cairo_matrix_to_quartz (&m, &mask_matrix); + + /* ClipToMask is essentially drawing an image, so we need to flip the CTM + * to get the image to appear oriented the right way */ + CGContextConcatCTM (state.cgMaskContext, CGAffineTransformInvert (mask_matrix)); + CGContextTranslateCTM (state.cgMaskContext, 0.0, rect.size.height); + CGContextScaleCTM (state.cgMaskContext, 1.0, -1.0); + + state.filter = filter; + + CGContextSetInterpolationQuality (state.cgMaskContext, filter); + CGContextSetShouldAntialias (state.cgMaskContext, filter != kCGInterpolationNone); + + CGContextClipToMask (state.cgMaskContext, rect, img); + + CGContextScaleCTM (state.cgMaskContext, 1.0, -1.0); + CGContextTranslateCTM (state.cgMaskContext, 0.0, -rect.size.height); + CGContextConcatCTM (state.cgMaskContext, mask_matrix); + + _cairo_quartz_draw_source (&state, extents->op); + +BAIL: + _cairo_quartz_teardown_state (&state, extents); + + CGImageRelease (img); + + return status; +} + +static cairo_int_status_t +_cairo_quartz_cg_mask_with_solid (cairo_quartz_surface_t *surface, + cairo_composite_rectangles_t *extents) +{ + cairo_quartz_drawing_state_t state; + double alpha = extents->mask_pattern.solid.color.alpha; + cairo_status_t status; + + status = _cairo_quartz_setup_state (&state, extents); + if (unlikely (status)) + return status; + + CGContextSetAlpha (surface->cgContext, alpha); + _cairo_quartz_draw_source (&state, extents->op); + + _cairo_quartz_teardown_state (&state, extents); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_quartz_cg_mask (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *extents) +{ + cairo_quartz_surface_t *surface = (cairo_quartz_surface_t *)extents->surface; + const cairo_pattern_t *source = &extents->source_pattern.base; + const cairo_pattern_t *mask = &extents->mask_pattern.base; + cairo_surface_t *mask_surf; + cairo_matrix_t matrix; + cairo_status_t status; + cairo_bool_t need_temp; + CGInterpolationQuality filter; + + ND ((stderr, "%p _cairo_quartz_surface_mask op %d source->type %d mask->type %d\n", + extents->surface, extents->op, extents->source_pattern.base.type, + extents->mask_pattern.base.type)); + + if (mask->type == CAIRO_PATTERN_TYPE_SOLID) + return _cairo_quartz_cg_mask_with_solid (surface, extents); + + need_temp = (mask->type != CAIRO_PATTERN_TYPE_SURFACE || + mask->extend != CAIRO_EXTEND_NONE); + + filter = _cairo_quartz_filter_to_quartz (source->filter); + + if (! need_temp) { + mask_surf = extents->mask_pattern.surface.surface; + + /* When an opaque surface used as a mask in Quartz, its + * luminosity is used as the alpha value, so we can only use + * surfaces with alpha without creating a temporary mask. */ + need_temp = ! (mask_surf->content & CAIRO_CONTENT_ALPHA); + } + + if (! need_temp) { + CGInterpolationQuality mask_filter; + cairo_bool_t simple_transform; + + matrix = mask->matrix; + + mask_filter = _cairo_quartz_filter_to_quartz (mask->filter); + if (mask_filter == kCGInterpolationNone) { + simple_transform = _cairo_matrix_is_translation (&matrix); + if (simple_transform) { + matrix.x0 = ceil (matrix.x0 - 0.5); + matrix.y0 = ceil (matrix.y0 - 0.5); + } + } else { + simple_transform = _cairo_matrix_is_integer_translation (&matrix, + NULL, + NULL); + } + + /* Quartz only allows one interpolation to be set for mask and + * source, so we can skip the temp surface only if the source + * filtering makes the mask look correct. */ + if (source->type == CAIRO_PATTERN_TYPE_SURFACE) + need_temp = ! (simple_transform || filter == mask_filter); + else + filter = mask_filter; + } + + if (need_temp) { + /* Render the mask to a surface */ + mask_surf = _cairo_quartz_surface_create_similar (surface, + CAIRO_CONTENT_ALPHA, + surface->extents.width, + surface->extents.height); + status = mask_surf->status; + if (unlikely (status)) + goto BAIL; + + /* mask_surf is clear, so use OVER instead of SOURCE to avoid a + * temporary layer or fallback to cairo-image. */ + status = _cairo_surface_paint (mask_surf, CAIRO_OPERATOR_OVER, mask, NULL); + if (unlikely (status)) + goto BAIL; + + cairo_matrix_init_identity (&matrix); + } + + status = _cairo_quartz_cg_mask_with_surface (extents, + mask_surf, &matrix, filter); + +BAIL: + + if (need_temp) + cairo_surface_destroy (mask_surf); + + return status; +} + +static cairo_int_status_t +_cairo_quartz_cg_fill (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *extents, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_quartz_drawing_state_t state; + cairo_int_status_t rv = CAIRO_STATUS_SUCCESS; + + ND ((stderr, "%p _cairo_quartz_surface_fill op %d source->type %d\n", + extents->surface, extents->op, extents->source_pattern.base.type)); + + rv = _cairo_quartz_setup_state (&state, extents); + if (unlikely (rv)) + goto BAIL; + + CGContextSetShouldAntialias (state.cgMaskContext, (antialias != CAIRO_ANTIALIAS_NONE)); + + _cairo_quartz_cairo_path_to_quartz_context (path, state.cgMaskContext); + + if (state.action == DO_DIRECT) { + assert (state.cgDrawContext == state.cgMaskContext); + if (fill_rule == CAIRO_FILL_RULE_WINDING) + CGContextFillPath (state.cgMaskContext); + else + CGContextEOFillPath (state.cgMaskContext); + } else { + if (fill_rule == CAIRO_FILL_RULE_WINDING) + CGContextClip (state.cgMaskContext); + else + CGContextEOClip (state.cgMaskContext); + + _cairo_quartz_draw_source (&state, extents->op); + } + +BAIL: + _cairo_quartz_teardown_state (&state, extents); + + ND ((stderr, "-- fill\n")); + return rv; +} + +static cairo_int_status_t +_cairo_quartz_cg_stroke (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *extents, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_quartz_drawing_state_t state; + cairo_int_status_t rv = CAIRO_STATUS_SUCCESS; + CGAffineTransform strokeTransform, invStrokeTransform; + + ND ((stderr, "%p _cairo_quartz_surface_stroke op %d source->type %d\n", + extents->surface, extents->op, extents->source_pattern.base.type)); + + rv = _cairo_quartz_setup_state (&state, extents); + if (unlikely (rv)) + goto BAIL; + + // Turning antialiasing off used to cause misrendering with + // single-pixel lines (e.g. 20,10.5 -> 21,10.5 end up being rendered as 2 pixels). + // That's been since fixed in at least 10.5, and in the latest 10.4 dot releases. + CGContextSetShouldAntialias (state.cgMaskContext, (antialias != CAIRO_ANTIALIAS_NONE)); + CGContextSetLineWidth (state.cgMaskContext, style->line_width); + CGContextSetLineCap (state.cgMaskContext, _cairo_quartz_cairo_line_cap_to_quartz (style->line_cap)); + CGContextSetLineJoin (state.cgMaskContext, _cairo_quartz_cairo_line_join_to_quartz (style->line_join)); + CGContextSetMiterLimit (state.cgMaskContext, style->miter_limit); + + if (style->dash && style->num_dashes) { + cairo_quartz_float_t sdash[CAIRO_STACK_ARRAY_LENGTH (cairo_quartz_float_t)]; + cairo_quartz_float_t *fdash = sdash; + unsigned int max_dashes = style->num_dashes; + unsigned int k; + + if (style->num_dashes%2) + max_dashes *= 2; + if (max_dashes > ARRAY_LENGTH (sdash)) + fdash = _cairo_malloc_ab (max_dashes, sizeof (cairo_quartz_float_t)); + if (unlikely (fdash == NULL)) { + rv = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto BAIL; + } + + for (k = 0; k < max_dashes; k++) + fdash[k] = (cairo_quartz_float_t) style->dash[k % style->num_dashes]; + + CGContextSetLineDash (state.cgMaskContext, style->dash_offset, fdash, max_dashes); + if (fdash != sdash) + free (fdash); + } else + CGContextSetLineDash (state.cgMaskContext, 0, NULL, 0); + + _cairo_quartz_cairo_path_to_quartz_context (path, state.cgMaskContext); + + _cairo_quartz_cairo_matrix_to_quartz (ctm, &strokeTransform); + CGContextConcatCTM (state.cgMaskContext, strokeTransform); + + if (state.action == DO_DIRECT) { + assert (state.cgDrawContext == state.cgMaskContext); + CGContextStrokePath (state.cgMaskContext); + } else { + CGContextReplacePathWithStrokedPath (state.cgMaskContext); + CGContextClip (state.cgMaskContext); + + _cairo_quartz_cairo_matrix_to_quartz (ctm_inverse, &invStrokeTransform); + CGContextConcatCTM (state.cgMaskContext, invStrokeTransform); + + _cairo_quartz_draw_source (&state, extents->op); + } + +BAIL: + _cairo_quartz_teardown_state (&state, extents); + + ND ((stderr, "-- stroke\n")); + return rv; +} + +#if CAIRO_HAS_QUARTZ_FONT +static cairo_int_status_t +_cairo_quartz_cg_glyphs (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *extents, + cairo_scaled_font_t *scaled_font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_bool_t overlap) +{ + CGAffineTransform textTransform, invTextTransform; + CGGlyph glyphs_static[CAIRO_STACK_ARRAY_LENGTH (CGPoint)]; + CGPoint cg_positions_static[CAIRO_STACK_ARRAY_LENGTH (CGPoint)]; + CGGlyph *cg_glyphs = &glyphs_static[0]; + CGPoint *cg_positions = &cg_positions_static[0]; + + cairo_quartz_drawing_state_t state; + cairo_int_status_t rv = CAIRO_INT_STATUS_UNSUPPORTED; + CGPoint origin; + CTFontRef ctFont = NULL; + + cairo_bool_t didForceFontSmoothing = FALSE; + + if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_QUARTZ) + return CAIRO_INT_STATUS_UNSUPPORTED; + + rv = _cairo_quartz_setup_state (&state, extents); + if (unlikely (rv)) + goto BAIL; + + if (state.action == DO_DIRECT) { + assert (state.cgDrawContext == state.cgMaskContext); + CGContextSetTextDrawingMode (state.cgMaskContext, kCGTextFill); + } else { + CGContextSetTextDrawingMode (state.cgMaskContext, kCGTextClip); + } + + /* this doesn't addref */ + ctFont = _cairo_quartz_scaled_font_get_ct_font (scaled_font); + _cairo_quartz_set_antialiasing (state.cgMaskContext, scaled_font->options.antialias); + + if (num_glyphs > ARRAY_LENGTH (glyphs_static)) { + cg_glyphs = (CGGlyph*) _cairo_malloc_ab (num_glyphs, sizeof (CGGlyph) + sizeof (CGPoint)); + if (unlikely (cg_glyphs == NULL)) { + rv = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto BAIL; + } + + cg_positions = (CGPoint*) (cg_glyphs + num_glyphs); + } + + /* scale(1,-1) * scaled_font->scale */ + textTransform = CGAffineTransformMake (scaled_font->scale.xx, + scaled_font->scale.yx, + -scaled_font->scale.xy, + -scaled_font->scale.yy, + 0.0, 0.0); + + /* scaled_font->scale_inverse * scale(1,-1) */ + invTextTransform = CGAffineTransformMake (scaled_font->scale_inverse.xx, + -scaled_font->scale_inverse.yx, + scaled_font->scale_inverse.xy, + -scaled_font->scale_inverse.yy, + 0.0, 0.0); + + + origin = CGPointMake (glyphs[0].x, glyphs[0].y); + for (int i = 0; i < num_glyphs; ++i) + { + cg_glyphs[i] = glyphs[i].index; + cg_positions[i] = CGPointMake (glyphs[i].x - origin.x, glyphs[i].y - origin.y); + cg_positions[i] = CGPointApplyAffineTransform (cg_positions[i], invTextTransform); + } + + /* Translate to the first glyph's position before drawing */ + CGContextTranslateCTM (state.cgMaskContext, origin.x, origin.y); + CGContextConcatCTM (state.cgMaskContext, textTransform); + + CTFontDrawGlyphs (ctFont, cg_glyphs, cg_positions, num_glyphs, state.cgMaskContext); + + CGContextConcatCTM (state.cgMaskContext, invTextTransform); + CGContextTranslateCTM (state.cgMaskContext, -origin.x, -origin.y); + + if (state.action != DO_DIRECT) + _cairo_quartz_draw_source (&state, extents->op); + +BAIL: + if (didForceFontSmoothing) + CGContextSetAllowsFontSmoothing (state.cgMaskContext, FALSE); + + _cairo_quartz_teardown_state (&state, extents); + + if (cg_glyphs != glyphs_static) + free (cg_glyphs); + + return rv; +} +#endif /* CAIRO_HAS_QUARTZ_FONT */ + +static const cairo_compositor_t _cairo_quartz_cg_compositor = { + &_cairo_fallback_compositor, + + _cairo_quartz_cg_paint, + _cairo_quartz_cg_mask, + _cairo_quartz_cg_stroke, + _cairo_quartz_cg_fill, +#if CAIRO_HAS_QUARTZ_FONT + _cairo_quartz_cg_glyphs, +#else + NULL, +#endif +}; + +static cairo_int_status_t +_cairo_quartz_surface_paint (void *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip) +{ + return _cairo_compositor_paint (&_cairo_quartz_cg_compositor, + surface, op, source, clip); +} + +static cairo_int_status_t +_cairo_quartz_surface_mask (void *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_clip_t *clip) +{ + return _cairo_compositor_mask (&_cairo_quartz_cg_compositor, + surface, op, source, mask, + clip); +} + +static cairo_int_status_t +_cairo_quartz_surface_fill (void *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + return _cairo_compositor_fill (&_cairo_quartz_cg_compositor, + surface, op, source, path, + fill_rule, tolerance, antialias, + clip); +} + +static cairo_int_status_t +_cairo_quartz_surface_stroke (void *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + return _cairo_compositor_stroke (&_cairo_quartz_cg_compositor, + surface, op, source, path, + style, ctm,ctm_inverse, + tolerance, antialias, clip); +} + +static cairo_int_status_t +_cairo_quartz_surface_glyphs (void *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip) +{ + return _cairo_compositor_glyphs (&_cairo_quartz_cg_compositor, + surface, op, source, + glyphs, num_glyphs, scaled_font, + clip); +} + +static cairo_status_t +_cairo_quartz_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_quartz_surface_t *surface = + cairo_container_of (clipper, cairo_quartz_surface_t, clipper); + + ND ((stderr, "%p _cairo_quartz_surface_intersect_clip_path path: %p\n", surface, path)); + + if (_cairo_quartz_is_zero_surface (&surface->base)) + return CAIRO_STATUS_SUCCESS; + + if (path == NULL) { + /* If we're being asked to reset the clip, we can only do it + * by restoring the gstate to our previous saved one, and + * saving it again. + * + * Note that this assumes that ALL quartz surface creation + * functions will do a SaveGState first; we do this in create_internal. + */ + CGContextRestoreGState (surface->cgContext); + CGContextSaveGState (surface->cgContext); + } else { + CGContextSetShouldAntialias (surface->cgContext, (antialias != CAIRO_ANTIALIAS_NONE)); + + _cairo_quartz_cairo_path_to_quartz_context (path, surface->cgContext); + + if (fill_rule == CAIRO_FILL_RULE_WINDING) + CGContextClip (surface->cgContext); + else + CGContextEOClip (surface->cgContext); + } + + ND ((stderr, "-- intersect_clip_path\n")); + + return CAIRO_STATUS_SUCCESS; +} + +// XXXtodo implement show_page; need to figure out how to handle begin/end + +static const cairo_surface_backend_t cairo_quartz_surface_backend = { + CAIRO_SURFACE_TYPE_QUARTZ, + _cairo_quartz_surface_finish, + + _cairo_default_context_create, + + _cairo_quartz_surface_create_similar, + NULL, /* similar image */ + _cairo_quartz_surface_map_to_image, + _cairo_quartz_surface_unmap_image, + + _cairo_surface_default_source, + _cairo_quartz_surface_acquire_source_image, + _cairo_quartz_surface_release_source_image, + NULL, /* snapshot */ + + NULL, /* copy_page */ + NULL, /* show_page */ + + _cairo_quartz_surface_get_extents, + NULL, /* get_font_options */ + + NULL, /* flush */ + NULL, /* mark_dirty_rectangle */ + + _cairo_quartz_surface_paint, + _cairo_quartz_surface_mask, + _cairo_quartz_surface_stroke, + _cairo_quartz_surface_fill, + NULL, /* fill-stroke */ + _cairo_quartz_surface_glyphs, + NULL, /* has_show_text_glyphs */ + NULL, /* show_text_glyphs */ + NULL, /* get_supported_mime_types */ + NULL, /* tag */ +}; + +cairo_quartz_surface_t * +_cairo_quartz_surface_create_internal (CGContextRef cgContext, + cairo_content_t content, + unsigned int width, + unsigned int height) +{ + cairo_quartz_surface_t *surface; + + /* Init the base surface */ + surface = _cairo_calloc (sizeof (cairo_quartz_surface_t)); + if (unlikely (surface == NULL)) + return (cairo_quartz_surface_t*) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + memset (surface, 0, sizeof (cairo_quartz_surface_t)); + + _cairo_surface_init (&surface->base, + &cairo_quartz_surface_backend, + NULL, /* device */ + content, + FALSE); /* is_vector */ + + _cairo_surface_clipper_init (&surface->clipper, + _cairo_quartz_surface_clipper_intersect_clip_path); + + /* Save our extents */ + surface->extents.x = surface->extents.y = 0; + surface->extents.width = width; + surface->extents.height = height; + surface->virtual_extents = surface->extents; + + if (_cairo_quartz_is_zero_surface (&surface->base)) { + surface->cgContext = NULL; + surface->cgContextBaseCTM = CGAffineTransformIdentity; + surface->base.is_clear = TRUE; + return surface; + } + + /* Save so we can always get back to a known-good CGContext -- this is + * required for proper behaviour of intersect_clip_path(NULL) + */ + CGContextSaveGState (cgContext); + + surface->cgContext = cgContext; + surface->cgContextBaseCTM = CGContextGetCTM (cgContext); + + return surface; +} + +/** + * cairo_quartz_surface_create_for_cg_context: + * @cgContext: the existing CGContext for which to create the surface + * @width: width of the surface, in pixels + * @height: height of the surface, in pixels + * + * Creates a Quartz surface that wraps the given CGContext. The + * CGContext is assumed to be in the standard Cairo coordinate space + * (that is, with the origin at the upper left and the Y axis + * increasing downward). If the CGContext is in the Quartz coordinate + * space (with the origin at the bottom left), then it should be + * flipped before this function is called. The flip can be accomplished + * using a translate and a scale; for example: + * + * + * CGContextTranslateCTM (cgContext, 0.0, height); + * CGContextScaleCTM (cgContext, 1.0, -1.0); + * + * + * All Cairo operations are implemented in terms of Quartz operations, + * as long as Quartz-compatible elements are used (such as Quartz fonts). + * + * Return value: the newly created Cairo surface. + * + * Since: 1.6 + **/ + +cairo_surface_t * +cairo_quartz_surface_create_for_cg_context (CGContextRef cgContext, + unsigned int width, + unsigned int height) +{ + cairo_quartz_surface_t *surf = + _cairo_quartz_surface_create_internal (cgContext, CAIRO_CONTENT_COLOR_ALPHA, + width, height); + if (likely (!surf->base.status)) + CGContextRetain (cgContext); + + return &surf->base; +} + +/** + * cairo_quartz_surface_create: + * @format: format of pixels in the surface to create + * @width: width of the surface, in pixels + * @height: height of the surface, in pixels + * + * Creates a Quartz surface backed by a CGBitmapContext using the main + * display's colorspace to avoid an expensive colorspace transform + * done serially on the CPU. This may produce slightly different + * colors from what's intended. Programs for which color management is + * important should create their own CGBitmapContext with a + * device-independent color space; most will expect Cairo to draw in + * sRGB and would use CGColorSpaceCreateWithName(kCGColorSpaceSRGB). + * + * All Cairo operations, including those that require software + * rendering, will succeed on this surface. + * + * Return value: the newly created surface. + * + * Since: 1.6 + **/ +cairo_surface_t * +cairo_quartz_surface_create (cairo_format_t format, + unsigned int width, + unsigned int height) +{ + cairo_quartz_surface_t *surf; + CGContextRef cgc; + CGColorSpaceRef cgColorspace; + CGBitmapInfo bitinfo; + void *imageData = NULL; + int stride; + int bitsPerComponent; + + if (!_cairo_quartz_verify_surface_size (width, height)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); + + if (width == 0 || height == 0) { + return &_cairo_quartz_surface_create_internal (NULL, _cairo_content_from_format (format), + width, height)->base; + } + + if (format == CAIRO_FORMAT_ARGB32 || + format == CAIRO_FORMAT_RGB24) + { + cgColorspace = _cairo_quartz_create_color_space (NULL); + bitinfo = kCGBitmapByteOrder32Host; + if (format == CAIRO_FORMAT_ARGB32) + bitinfo |= kCGImageAlphaPremultipliedFirst; + else + bitinfo |= kCGImageAlphaNoneSkipFirst; + bitsPerComponent = 8; + stride = width * 4; + } else if (format == CAIRO_FORMAT_A8) { + cgColorspace = NULL; + stride = width; + bitinfo = kCGImageAlphaOnly; + bitsPerComponent = 8; + } else if (format == CAIRO_FORMAT_A1) { + /* I don't think we can usefully support this, as defined by + * cairo_format_t -- these are 1-bit pixels stored in 32-bit + * quantities. + */ + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); + } else { + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); + } + + /* The Apple docs say that for best performance, the stride and the data + * pointer should be 16-byte aligned. malloc already aligns to 16-bytes, + * so we don't have to anything special on allocation. + */ + stride = (stride + 15) & ~15; + cgc = CGBitmapContextCreate (imageData, + width, + height, + bitsPerComponent, + stride, + cgColorspace, + bitinfo); + CGColorSpaceRelease (cgColorspace); + + if (!cgc) { + if (imageData) + free (imageData); + + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + } + + /* flip the Y axis */ + CGContextTranslateCTM (cgc, 0.0, height); + CGContextScaleCTM (cgc, 1.0, -1.0); + + surf = _cairo_quartz_surface_create_internal (cgc, _cairo_content_from_format (format), + width, height); + if (surf->base.status) { + CGContextRelease (cgc); + + if (imageData) + free (imageData); + + // create_internal will have set an error + return &surf->base; + } + + surf->base.is_clear = TRUE; + + return &surf->base; +} + +/** + * cairo_quartz_surface_get_cg_context: + * @surface: the Cairo Quartz surface + * + * Returns the CGContextRef that the given Quartz surface is backed + * by. + * + * A call to cairo_surface_flush() is required before using the + * CGContextRef to ensure that all pending drawing operations are + * finished and to restore any temporary modification cairo has made + * to its state. A call to cairo_surface_mark_dirty() is required + * after the state or the content of the CGContextRef has been + * modified. + * + * Return value: the CGContextRef for the given surface. + * + * Since: 1.6 + **/ +CGContextRef +cairo_quartz_surface_get_cg_context (cairo_surface_t *surface) +{ + if (surface && _cairo_surface_is_quartz (surface)) { + cairo_quartz_surface_t *quartz = (cairo_quartz_surface_t *) surface; + return quartz->cgContext; + } + + if (surface && _cairo_surface_is_quartz_image (surface)) { + cairo_quartz_image_surface_t *quartz = (cairo_quartz_image_surface_t *) surface; + return quartz->cgContext; + } + + return NULL; +} + +/** + * _cairo_surface_is_quartz: + * @surface: a #cairo_surface_t + * + * Checks if a surface is a #cairo_quartz_surface_t + * + * Return value: True if the surface is an quartz surface + **/ +cairo_bool_t +_cairo_surface_is_quartz (const cairo_surface_t *surface) +{ + return surface->backend == &cairo_quartz_surface_backend; +} + +cairo_surface_t* +_cairo_quartz_snapshot_create (cairo_surface_t *surface) +{ + cairo_quartz_snapshot_t *snapshot = NULL; + CGContextRef cgContext; + if (!surface || ! _is_quartz_surface (surface) || _cairo_quartz_is_zero_surface (surface)) + return NULL; + + if (_cairo_surface_is_quartz (surface) && + ! _cairo_quartz_is_cgcontext_bitmap_context (((cairo_quartz_surface_t*)surface)->cgContext)) + return NULL; + + snapshot = _cairo_calloc (sizeof (cairo_quartz_snapshot_t)); + + if (unlikely (surface == NULL)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + memset (snapshot, 0, sizeof (cairo_quartz_snapshot_t)); + cgContext = cairo_quartz_surface_get_cg_context (surface); + _cairo_surface_init (&snapshot->base, + &cairo_quartz_snapshot_backend, + NULL, CAIRO_CONTENT_COLOR_ALPHA, FALSE); + snapshot->image = CGBitmapContextCreateImage (cgContext); + _cairo_surface_attach_snapshot (surface, &snapshot->base, NULL); + cairo_surface_destroy (&snapshot->base); // The surface has reffed the snapshot so we must unref it here. + + return &snapshot->base; +} + +cairo_status_t +_cairo_quartz_snapshot_finish (void *surface) +{ + cairo_quartz_snapshot_t *snapshot = (cairo_quartz_snapshot_t *)surface; + if (snapshot->image) + CGImageRelease (snapshot->image); + return CAIRO_STATUS_SUCCESS; +} + +CGImageRef +_cairo_quartz_surface_snapshot_get_image (cairo_surface_t *surface) +{ + cairo_surface_t *snapshot; + assert (_is_quartz_surface (surface)); + snapshot = + _cairo_surface_has_snapshot (surface, &cairo_quartz_snapshot_backend); + + if (unlikely (!snapshot)) + { + snapshot = _cairo_quartz_snapshot_create (surface); + if (unlikely (!snapshot || cairo_surface_status (snapshot))) + return NULL; + } + + return CGImageRetain (((cairo_quartz_snapshot_t*)snapshot)->image); +} + +void +_cairo_quartz_image_to_png (CGImageRef image, const char *dest) +{ + CFStringRef png_utti = CFSTR("public.png"); + CFStringRef path; + CFURLRef url; + CGImageDestinationRef image_dest; + + if (!dest) + return; + path = CFStringCreateWithCString (NULL, dest, kCFStringEncodingUTF8); + url = CFURLCreateWithFileSystemPath (NULL, path, kCFURLPOSIXPathStyle, FALSE); + image_dest = CGImageDestinationCreateWithURL (url, png_utti, 1, NULL); + + CGImageDestinationAddImage (image_dest, image, NULL); + CGImageDestinationFinalize (image_dest); + + CFRelease (url); + CFRelease (path); + } + +cairo_status_t +_cairo_quartz_surface_to_png (cairo_surface_t *abstract_surface, const char *dest) +{ + CGImageRef image; + cairo_quartz_surface_t *surface; + if (!(_cairo_surface_is_quartz (abstract_surface) && + _cairo_quartz_is_cgcontext_bitmap_context (((cairo_quartz_surface_t*)abstract_surface)->cgContext))) { + return CAIRO_STATUS_SURFACE_TYPE_MISMATCH; + } + + surface = (cairo_quartz_surface_t*)abstract_surface; + image = CGBitmapContextCreateImage (surface->cgContext); + _cairo_quartz_image_to_png (image, dest); + + CGImageRelease (image); + return CAIRO_STATUS_SUCCESS; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-quartz.h b/local/recipes/libs/cairo/source/src/cairo-quartz.h new file mode 100644 index 0000000000..9e11e876fe --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-quartz.h @@ -0,0 +1,82 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2006, 2007 Mozilla Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * + * Contributor(s): + * Vladimir Vukicevic + */ + +#ifndef CAIRO_QUARTZ_H +#define CAIRO_QUARTZ_H + +#include "cairo.h" + +#if CAIRO_HAS_QUARTZ_SURFACE + +#include + +CAIRO_BEGIN_DECLS + +cairo_public cairo_surface_t * +cairo_quartz_surface_create (cairo_format_t format, + unsigned int width, + unsigned int height); + +cairo_public cairo_surface_t * +cairo_quartz_surface_create_for_cg_context (CGContextRef cgContext, + unsigned int width, + unsigned int height); + +cairo_public CGContextRef +cairo_quartz_surface_get_cg_context (cairo_surface_t *surface); + +#if CAIRO_HAS_QUARTZ_FONT + +/* + * Quartz font support + */ + +cairo_public cairo_font_face_t * +cairo_quartz_font_face_create_for_cgfont (CGFontRef font); + +cairo_public cairo_font_face_t * +cairo_quartz_font_face_create_for_atsu_font_id (ATSUFontID font_id); + +#endif /* CAIRO_HAS_QUARTZ_FONT */ + +CAIRO_END_DECLS + +#else + +# error Cairo was not compiled with support for the quartz backend + +#endif /* CAIRO_HAS_QUARTZ_SURFACE */ + +#endif /* CAIRO_QUARTZ_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-raster-source-pattern.c b/local/recipes/libs/cairo/source/src/cairo-raster-source-pattern.c new file mode 100644 index 0000000000..0ae3b946a0 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-raster-source-pattern.c @@ -0,0 +1,430 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Chris Wilson + */ + +#include "cairoint.h" +#include "cairo-error-private.h" +#include "cairo-pattern-private.h" + +/** + * SECTION:cairo-raster-source + * @Title: Raster Sources + * @Short_Description: Supplying arbitrary image data + * @See_Also: #cairo_pattern_t + * + * The raster source provides the ability to supply arbitrary pixel data + * whilst rendering. The pixels are queried at the time of rasterisation + * by means of user callback functions, allowing for the ultimate + * flexibility. For example, in handling compressed image sources, you + * may keep a MRU cache of decompressed images and decompress sources on the + * fly and discard old ones to conserve memory. + * + * For the raster source to be effective, you must at least specify + * the acquire and release callbacks which are used to retrieve the pixel + * data for the region of interest and demark when it can be freed afterwards. + * Other callbacks are provided for when the pattern is copied temporarily + * during rasterisation, or more permanently as a snapshot in order to keep + * the pixel data available for printing. + **/ + +cairo_surface_t * +_cairo_raster_source_pattern_acquire (const cairo_pattern_t *abstract_pattern, + cairo_surface_t *target, + const cairo_rectangle_int_t *extents) +{ + cairo_raster_source_pattern_t *pattern = + (cairo_raster_source_pattern_t *) abstract_pattern; + + if (pattern->acquire == NULL) + return NULL; + + if (extents == NULL) + extents = &pattern->extents; + + return pattern->acquire (&pattern->base, pattern->user_data, + target, extents); +} + +void +_cairo_raster_source_pattern_release (const cairo_pattern_t *abstract_pattern, + cairo_surface_t *surface) +{ + cairo_raster_source_pattern_t *pattern = + (cairo_raster_source_pattern_t *) abstract_pattern; + + if (pattern->release == NULL) + return; + + pattern->release (&pattern->base, pattern->user_data, surface); +} + +cairo_status_t +_cairo_raster_source_pattern_init_copy (cairo_pattern_t *abstract_pattern, + const cairo_pattern_t *other) +{ + cairo_raster_source_pattern_t *pattern = + (cairo_raster_source_pattern_t *) abstract_pattern; + cairo_status_t status; + + VG (VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_raster_source_pattern_t))); + memcpy(pattern, other, sizeof (cairo_raster_source_pattern_t)); + + status = CAIRO_STATUS_SUCCESS; + if (pattern->copy) + status = pattern->copy (&pattern->base, pattern->user_data, other); + + return status; +} + +cairo_status_t +_cairo_raster_source_pattern_snapshot (cairo_pattern_t *abstract_pattern) +{ + cairo_raster_source_pattern_t *pattern = + (cairo_raster_source_pattern_t *) abstract_pattern; + + if (pattern->snapshot == NULL) + return CAIRO_STATUS_SUCCESS; + + return pattern->snapshot (&pattern->base, pattern->user_data); +} + +void +_cairo_raster_source_pattern_finish (cairo_pattern_t *abstract_pattern) +{ + cairo_raster_source_pattern_t *pattern = + (cairo_raster_source_pattern_t *) abstract_pattern; + + if (pattern->finish == NULL) + return; + + pattern->finish (&pattern->base, pattern->user_data); +} + +/* Public interface */ + +/** + * cairo_pattern_create_raster_source: + * @user_data: the user data to be passed to all callbacks + * @content: content type for the pixel data that will be returned. Knowing + * the content type ahead of time is used for analysing the operation and + * picking the appropriate rendering path. + * @width: maximum size of the sample area + * @height: maximum size of the sample area + * + * Creates a new user pattern for providing pixel data. + * + * Use the setter functions to associate callbacks with the returned + * pattern. The only mandatory callback is acquire. + * + * Return value: a newly created #cairo_pattern_t. Free with + * cairo_pattern_destroy() when you are done using it. + * + * Since: 1.12 + **/ +cairo_pattern_t * +cairo_pattern_create_raster_source (void *user_data, + cairo_content_t content, + int width, int height) +{ + cairo_raster_source_pattern_t *pattern; + + CAIRO_MUTEX_INITIALIZE (); + + if (width < 0 || height < 0) + return _cairo_pattern_create_in_error (CAIRO_STATUS_INVALID_SIZE); + + if (! CAIRO_CONTENT_VALID (content)) + return _cairo_pattern_create_in_error (CAIRO_STATUS_INVALID_CONTENT); + + pattern = _cairo_calloc (sizeof (*pattern)); + if (unlikely (pattern == NULL)) + return _cairo_pattern_create_in_error (CAIRO_STATUS_NO_MEMORY); + + _cairo_pattern_init (&pattern->base, + CAIRO_PATTERN_TYPE_RASTER_SOURCE); + CAIRO_REFERENCE_COUNT_INIT (&pattern->base.ref_count, 1); + + pattern->content = content; + + pattern->extents.x = 0; + pattern->extents.y = 0; + pattern->extents.width = width; + pattern->extents.height = height; + + pattern->user_data = user_data; + + return &pattern->base; +} + +/** + * cairo_raster_source_pattern_set_callback_data: + * @pattern: the pattern to update + * @data: the user data to be passed to all callbacks + * + * Updates the user data that is provided to all callbacks. + * + * Since: 1.12 + **/ +void +cairo_raster_source_pattern_set_callback_data (cairo_pattern_t *abstract_pattern, + void *data) +{ + cairo_raster_source_pattern_t *pattern; + + if (abstract_pattern->type != CAIRO_PATTERN_TYPE_RASTER_SOURCE) + return; + + pattern = (cairo_raster_source_pattern_t *) abstract_pattern; + pattern->user_data = data; +} + +/** + * cairo_raster_source_pattern_get_callback_data: + * @pattern: the pattern to update + * + * Queries the current user data. + * + * Return value: the current user-data passed to each callback + * + * Since: 1.12 + **/ +void * +cairo_raster_source_pattern_get_callback_data (cairo_pattern_t *abstract_pattern) +{ + cairo_raster_source_pattern_t *pattern; + + if (abstract_pattern->type != CAIRO_PATTERN_TYPE_RASTER_SOURCE) + return NULL; + + pattern = (cairo_raster_source_pattern_t *) abstract_pattern; + return pattern->user_data; +} + +/** + * cairo_raster_source_pattern_set_acquire: + * @pattern: the pattern to update + * @acquire: acquire callback + * @release: release callback + * + * Specifies the callbacks used to generate the image surface for a rendering + * operation (acquire) and the function used to cleanup that surface afterwards. + * + * The @acquire callback should create a surface (preferably an image + * surface created to match the target using + * cairo_surface_create_similar_image()) that defines at least the region + * of interest specified by extents. The surface is allowed to be the entire + * sample area, but if it does contain a subsection of the sample area, + * the surface extents should be provided by setting the device offset (along + * with its width and height) using cairo_surface_set_device_offset(). + * + * Since: 1.12 + **/ +void +cairo_raster_source_pattern_set_acquire (cairo_pattern_t *abstract_pattern, + cairo_raster_source_acquire_func_t acquire, + cairo_raster_source_release_func_t release) +{ + cairo_raster_source_pattern_t *pattern; + + if (abstract_pattern->type != CAIRO_PATTERN_TYPE_RASTER_SOURCE) + return; + + pattern = (cairo_raster_source_pattern_t *) abstract_pattern; + pattern->acquire = acquire; + pattern->release = release; +} + +/** + * cairo_raster_source_pattern_get_acquire: + * @pattern: the pattern to query + * @acquire: return value for the current acquire callback + * @release: return value for the current release callback + * + * Queries the current acquire and release callbacks. + * + * Since: 1.12 + **/ +void +cairo_raster_source_pattern_get_acquire (cairo_pattern_t *abstract_pattern, + cairo_raster_source_acquire_func_t *acquire, + cairo_raster_source_release_func_t *release) +{ + cairo_raster_source_pattern_t *pattern; + + if (abstract_pattern->type != CAIRO_PATTERN_TYPE_RASTER_SOURCE) + return; + + pattern = (cairo_raster_source_pattern_t *) abstract_pattern; + if (acquire) + *acquire = pattern->acquire; + if (release) + *release = pattern->release; +} + +/** + * cairo_raster_source_pattern_set_snapshot: + * @pattern: the pattern to update + * @snapshot: snapshot callback + * + * Sets the callback that will be used whenever a snapshot is taken of the + * pattern, that is whenever the current contents of the pattern should be + * preserved for later use. This is typically invoked whilst printing. + * + * Since: 1.12 + **/ +void +cairo_raster_source_pattern_set_snapshot (cairo_pattern_t *abstract_pattern, + cairo_raster_source_snapshot_func_t snapshot) +{ + cairo_raster_source_pattern_t *pattern; + + if (abstract_pattern->type != CAIRO_PATTERN_TYPE_RASTER_SOURCE) + return; + + pattern = (cairo_raster_source_pattern_t *) abstract_pattern; + pattern->snapshot = snapshot; +} + +/** + * cairo_raster_source_pattern_get_snapshot: + * @pattern: the pattern to query + * + * Queries the current snapshot callback. + * + * Return value: the current snapshot callback + * + * Since: 1.12 + **/ +cairo_raster_source_snapshot_func_t +cairo_raster_source_pattern_get_snapshot (cairo_pattern_t *abstract_pattern) +{ + cairo_raster_source_pattern_t *pattern; + + if (abstract_pattern->type != CAIRO_PATTERN_TYPE_RASTER_SOURCE) + return NULL; + + pattern = (cairo_raster_source_pattern_t *) abstract_pattern; + return pattern->snapshot; +} + +/** + * cairo_raster_source_pattern_set_copy: + * @pattern: the pattern to update + * @copy: the copy callback + * + * Updates the copy callback which is used whenever a temporary copy of the + * pattern is taken. + * + * Since: 1.12 + **/ +void +cairo_raster_source_pattern_set_copy (cairo_pattern_t *abstract_pattern, + cairo_raster_source_copy_func_t copy) +{ + cairo_raster_source_pattern_t *pattern; + + if (abstract_pattern->type != CAIRO_PATTERN_TYPE_RASTER_SOURCE) + return; + + pattern = (cairo_raster_source_pattern_t *) abstract_pattern; + pattern->copy = copy; +} + +/** + * cairo_raster_source_pattern_get_copy: + * @pattern: the pattern to query + * + * Queries the current copy callback. + * + * Return value: the current copy callback + * + * Since: 1.12 + **/ +cairo_raster_source_copy_func_t +cairo_raster_source_pattern_get_copy (cairo_pattern_t *abstract_pattern) +{ + cairo_raster_source_pattern_t *pattern; + + if (abstract_pattern->type != CAIRO_PATTERN_TYPE_RASTER_SOURCE) + return NULL; + + pattern = (cairo_raster_source_pattern_t *) abstract_pattern; + return pattern->copy; +} + +/** + * cairo_raster_source_pattern_set_finish: + * @pattern: the pattern to update + * @finish: the finish callback + * + * Updates the finish callback which is used whenever a pattern (or a copy + * thereof) will no longer be used. + * + * Since: 1.12 + **/ +void +cairo_raster_source_pattern_set_finish (cairo_pattern_t *abstract_pattern, + cairo_raster_source_finish_func_t finish) +{ + cairo_raster_source_pattern_t *pattern; + + if (abstract_pattern->type != CAIRO_PATTERN_TYPE_RASTER_SOURCE) + return; + + pattern = (cairo_raster_source_pattern_t *) abstract_pattern; + pattern->finish = finish; +} + +/** + * cairo_raster_source_pattern_get_finish: + * @pattern: the pattern to query + * + * Queries the current finish callback. + * + * Return value: the current finish callback + * + * Since: 1.12 + **/ +cairo_raster_source_finish_func_t +cairo_raster_source_pattern_get_finish (cairo_pattern_t *abstract_pattern) +{ + cairo_raster_source_pattern_t *pattern; + + if (abstract_pattern->type != CAIRO_PATTERN_TYPE_RASTER_SOURCE) + return NULL; + + pattern = (cairo_raster_source_pattern_t *) abstract_pattern; + return pattern->finish; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-recording-surface-inline.h b/local/recipes/libs/cairo/source/src/cairo-recording-surface-inline.h new file mode 100644 index 0000000000..9002ccd693 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-recording-surface-inline.h @@ -0,0 +1,68 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Kristian Høgsberg + * Adrian Johnson + */ + +#ifndef CAIRO_RECORDING_SURFACE_INLINE_H +#define CAIRO_RECORDING_SURFACE_INLINE_H + +#include "cairo-recording-surface-private.h" + +static inline cairo_bool_t +_cairo_recording_surface_get_bounds (cairo_surface_t *surface, + cairo_rectangle_t *extents) +{ + cairo_recording_surface_t *recording = (cairo_recording_surface_t *)surface; + if (recording->unbounded) + return FALSE; + + *extents = recording->extents_pixels; + return TRUE; +} + +/** + * _cairo_surface_is_recording: + * @surface: a #cairo_surface_t + * + * Checks if a surface is a #cairo_recording_surface_t + * + * Return value: %TRUE if the surface is a recording surface + **/ +static inline cairo_bool_t +_cairo_surface_is_recording (const cairo_surface_t *surface) +{ + return surface->backend->type == CAIRO_SURFACE_TYPE_RECORDING; +} + +#endif /* CAIRO_RECORDING_SURFACE_INLINE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-recording-surface-private.h b/local/recipes/libs/cairo/source/src/cairo-recording-surface-private.h new file mode 100644 index 0000000000..2ee414e7d1 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-recording-surface-private.h @@ -0,0 +1,271 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Kristian Høgsberg + * Adrian Johnson + */ + +#ifndef CAIRO_RECORDING_SURFACE_H +#define CAIRO_RECORDING_SURFACE_H + +#include "cairoint.h" +#include "cairo-path-fixed-private.h" +#include "cairo-pattern-private.h" +#include "cairo-surface-backend-private.h" + +typedef enum { + /* The 5 basic drawing operations. */ + CAIRO_COMMAND_PAINT, + CAIRO_COMMAND_MASK, + CAIRO_COMMAND_STROKE, + CAIRO_COMMAND_FILL, + CAIRO_COMMAND_SHOW_TEXT_GLYPHS, + + /* cairo_tag_begin()/cairo_tag_end() */ + CAIRO_COMMAND_TAG, +} cairo_command_type_t; + +typedef enum { + CAIRO_RECORDING_REGION_ALL = 0, + CAIRO_RECORDING_REGION_NATIVE, + CAIRO_RECORDING_REGION_IMAGE_FALLBACK +} cairo_recording_region_type_t; + +typedef enum { + CAIRO_RECORDING_REPLAY, + CAIRO_RECORDING_CREATE_REGIONS, + CAIRO_RECORDING_REPLAY_REGION +} cairo_recording_replay_type_t; + +typedef struct _cairo_command_header { + cairo_command_type_t type; + cairo_operator_t op; + cairo_rectangle_int_t extents; + cairo_clip_t *clip; + + int index; + struct _cairo_command_header *chain; +} cairo_command_header_t; + +typedef struct _cairo_command_paint { + cairo_command_header_t header; + cairo_pattern_union_t source; +} cairo_command_paint_t; + +typedef struct _cairo_command_mask { + cairo_command_header_t header; + cairo_pattern_union_t source; + cairo_pattern_union_t mask; +} cairo_command_mask_t; + +typedef struct _cairo_command_stroke { + cairo_command_header_t header; + cairo_pattern_union_t source; + cairo_path_fixed_t path; + cairo_stroke_style_t style; + cairo_matrix_t ctm; + cairo_matrix_t ctm_inverse; + double tolerance; + cairo_antialias_t antialias; +} cairo_command_stroke_t; + +typedef struct _cairo_command_fill { + cairo_command_header_t header; + cairo_pattern_union_t source; + cairo_path_fixed_t path; + cairo_fill_rule_t fill_rule; + double tolerance; + cairo_antialias_t antialias; +} cairo_command_fill_t; + +typedef struct _cairo_command_show_text_glyphs { + cairo_command_header_t header; + cairo_pattern_union_t source; + char *utf8; + int utf8_len; + cairo_glyph_t *glyphs; + unsigned int num_glyphs; + cairo_text_cluster_t *clusters; + int num_clusters; + cairo_text_cluster_flags_t cluster_flags; + cairo_scaled_font_t *scaled_font; +} cairo_command_show_text_glyphs_t; + +typedef struct _cairo_command_tag { + cairo_command_header_t header; + cairo_bool_t begin; + char *tag_name; + char *attributes; +} cairo_command_tag_t; + +typedef union _cairo_command { + cairo_command_header_t header; + + cairo_command_paint_t paint; + cairo_command_mask_t mask; + cairo_command_stroke_t stroke; + cairo_command_fill_t fill; + cairo_command_show_text_glyphs_t show_text_glyphs; + cairo_command_tag_t tag; +} cairo_command_t; + +typedef struct _cairo_recording_surface { + cairo_surface_t base; + + /* A recording-surface is logically unbounded, but when used as a + * source we need to render it to an image, so we need a size at + * which to create that image. */ + cairo_rectangle_t extents_pixels; + cairo_rectangle_int_t extents; + cairo_bool_t unbounded; + + cairo_array_t commands; + unsigned int *indices; + unsigned int num_indices; + cairo_bool_t optimize_clears; + cairo_bool_t has_bilevel_alpha; + cairo_bool_t has_only_op_over; + cairo_bool_t has_tags; + + struct bbtree { + cairo_box_t extents; + struct bbtree *left, *right; + cairo_command_header_t *chain; + } bbtree; + + /* The mutex protects modification to all subsequent fields. */ + cairo_mutex_t mutex; + + cairo_list_t region_array_list; + +} cairo_recording_surface_t; + +typedef struct _cairo_recording_region_element { + cairo_recording_region_type_t region; + unsigned int source_id; + unsigned int mask_id; +} cairo_recording_region_element_t; + +typedef struct _cairo_recording_region_array { + unsigned int id; + cairo_reference_count_t ref_count; + cairo_array_t regions; /* cairo_recording_region_element_t */ + cairo_list_t link; +} cairo_recording_regions_array_t; + +cairo_private cairo_int_status_t +_cairo_recording_surface_get_path (cairo_surface_t *surface, + cairo_path_fixed_t *path); + +cairo_private cairo_status_t +_cairo_recording_surface_replay_one (cairo_recording_surface_t *surface, + long unsigned index, + cairo_surface_t *target); + +cairo_private cairo_status_t +_cairo_recording_surface_replay (cairo_surface_t *surface, + cairo_surface_t *target); + +cairo_private cairo_status_t +_cairo_recording_surface_replay_with_foreground_color (cairo_surface_t *surface, + cairo_surface_t *target, + const cairo_color_t *foreground_color, + cairo_bool_t *foreground_used); + +cairo_private cairo_status_t +_cairo_recording_surface_replay_with_transform (cairo_surface_t *surface, + const cairo_matrix_t *surface_transform, + cairo_surface_t *target, + cairo_bool_t surface_is_unbounded, + cairo_bool_t replay_all); + +cairo_private cairo_status_t +_cairo_recording_surface_replay_with_clip (cairo_surface_t *surface, + const cairo_matrix_t *surface_transform, + cairo_surface_t *target, + const cairo_clip_t *target_clip); + +cairo_private cairo_status_t +_cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface, + unsigned int regions_id, + const cairo_matrix_t *surface_transform, + cairo_surface_t *target, + cairo_bool_t surface_is_unbounded, + cairo_bool_t replay_all); + +cairo_private cairo_status_t +_cairo_recording_surface_replay_region (cairo_surface_t *surface, + unsigned int regions_id, + const cairo_rectangle_int_t *surface_extents, + cairo_surface_t *target, + cairo_recording_region_type_t region); + +cairo_private cairo_status_t +_cairo_recording_surface_get_bbox (cairo_recording_surface_t *recording, + cairo_box_t *bbox, + const cairo_matrix_t *transform); + +cairo_private cairo_status_t +_cairo_recording_surface_get_ink_bbox (cairo_recording_surface_t *surface, + cairo_box_t *bbox, + const cairo_matrix_t *transform); + +cairo_private cairo_bool_t +_cairo_recording_surface_has_only_bilevel_alpha (cairo_recording_surface_t *surface); + +cairo_private cairo_bool_t +_cairo_recording_surface_has_only_op_over (cairo_recording_surface_t *surface); + +cairo_private cairo_bool_t +_cairo_recording_surface_has_tags (cairo_surface_t *surface); + +cairo_private cairo_status_t +_cairo_recording_surface_region_array_attach (cairo_surface_t *surface, + unsigned int *id); + +cairo_private void +_cairo_recording_surface_region_array_reference (cairo_surface_t *surface, + unsigned int id); + +cairo_private void +_cairo_recording_surface_region_array_remove (cairo_surface_t *surface, + unsigned int id); + +cairo_private void +_cairo_debug_print_recording_surface (FILE *file, + cairo_surface_t *surface, + unsigned int regions_id, + int indent, + cairo_bool_t recurse); + +#endif /* CAIRO_RECORDING_SURFACE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-recording-surface.c b/local/recipes/libs/cairo/source/src/cairo-recording-surface.c new file mode 100644 index 0000000000..6add3a218e --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-recording-surface.c @@ -0,0 +1,2946 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * Copyright © 2007 Adrian Johnson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Kristian Høgsberg + * Carl Worth + * Adrian Johnson + */ + +/** + * SECTION:cairo-recording + * @Title: Recording Surfaces + * @Short_Description: Records all drawing operations + * @See_Also: #cairo_surface_t + * + * A recording surface is a surface that records all drawing operations at + * the highest level of the surface backend interface, (that is, the + * level of paint, mask, stroke, fill, and show_text_glyphs). The recording + * surface can then be "replayed" against any target surface by using it + * as a source surface. + * + * If you want to replay a surface so that the results in target will be + * identical to the results that would have been obtained if the original + * operations applied to the recording surface had instead been applied to the + * target surface, you can use code like this: + * + * cairo_t *cr; + * + * cr = cairo_create (target); + * cairo_set_source_surface (cr, recording_surface, 0.0, 0.0); + * cairo_paint (cr); + * cairo_destroy (cr); + * + * + * A recording surface is logically unbounded, i.e. it has no implicit constraint + * on the size of the drawing surface. However, in practice this is rarely + * useful as you wish to replay against a particular target surface with + * known bounds. For this case, it is more efficient to specify the target + * extents to the recording surface upon creation. + * + * The recording phase of the recording surface is careful to snapshot all + * necessary objects (paths, patterns, etc.), in order to achieve + * accurate replay. The efficiency of the recording surface could be + * improved by improving the implementation of snapshot for the + * various objects. For example, it would be nice to have a + * copy-on-write implementation for _cairo_surface_snapshot. + **/ + +#include "cairoint.h" + +#include "cairo-array-private.h" +#include "cairo-analysis-surface-private.h" +#include "cairo-clip-private.h" +#include "cairo-combsort-inline.h" +#include "cairo-composite-rectangles-private.h" +#include "cairo-default-context-private.h" +#include "cairo-error-private.h" +#include "cairo-image-surface-private.h" +#include "cairo-list-inline.h" +#include "cairo-recording-surface-inline.h" +#include "cairo-surface-snapshot-inline.h" +#include "cairo-surface-wrapper-private.h" +#include "cairo-traps-private.h" + +typedef struct _cairo_recording_surface_replay_params { + const cairo_rectangle_int_t *surface_extents; + const cairo_matrix_t *surface_transform; + cairo_surface_t *target; + const cairo_clip_t *target_clip; + cairo_bool_t surface_is_unbounded; + cairo_recording_replay_type_t type; + cairo_recording_region_type_t region; + unsigned int regions_id; + const cairo_color_t *foreground_color; + cairo_bool_t foreground_used; + cairo_bool_t replay_all; +} cairo_recording_surface_replay_params_t; + +static const cairo_surface_backend_t cairo_recording_surface_backend; + +/** + * CAIRO_HAS_RECORDING_SURFACE: + * + * Defined if the recording surface backend is available. + * The recording surface backend is always built in. + * This macro was added for completeness in cairo 1.10. + * + * Since: 1.10 + **/ + +/* Currently all recording surfaces do have a size which should be passed + * in as the maximum size of any target surface against which the + * recording-surface will ever be replayed. + * + * XXX: The naming of "pixels" in the size here is a misnomer. It's + * actually a size in whatever device-space units are desired (again, + * according to the intended replay target). + */ + +static int bbtree_left_or_right (struct bbtree *bbt, + const cairo_box_t *box) +{ + int left, right; + + if (bbt->left) { + cairo_box_t *e = &bbt->left->extents; + cairo_box_t b; + + b.p1.x = MIN (e->p1.x, box->p1.x); + b.p1.y = MIN (e->p1.y, box->p1.y); + b.p2.x = MAX (e->p2.x, box->p2.x); + b.p2.y = MAX (e->p2.y, box->p2.y); + + left = _cairo_fixed_integer_part (b.p2.x - b.p1.x) * _cairo_fixed_integer_part (b.p2.y - b.p1.y); + left -= _cairo_fixed_integer_part (e->p2.x - e->p1.x) * _cairo_fixed_integer_part (e->p2.y - e->p1.y); + } else + left = 0; + + if (bbt->right) { + cairo_box_t *e = &bbt->right->extents; + cairo_box_t b; + + b.p1.x = MIN (e->p1.x, box->p1.x); + b.p1.y = MIN (e->p1.y, box->p1.y); + b.p2.x = MAX (e->p2.x, box->p2.x); + b.p2.y = MAX (e->p2.y, box->p2.y); + + right = _cairo_fixed_integer_part (b.p2.x - b.p1.x) * _cairo_fixed_integer_part (b.p2.y - b.p1.y); + right -= _cairo_fixed_integer_part (e->p2.x - e->p1.x) * _cairo_fixed_integer_part (e->p2.y - e->p1.y); + } else + right = 0; + + return left <= right; +} + +#define INVALID_CHAIN ((cairo_command_header_t *)-1) + +static struct bbtree * +bbtree_new (const cairo_box_t *box, cairo_command_header_t *chain) +{ + struct bbtree *bbt = _cairo_calloc (sizeof (*bbt)); + if (bbt == NULL) + return NULL; + bbt->extents = *box; + bbt->left = bbt->right = NULL; + bbt->chain = chain; + return bbt; +} + +static void +bbtree_init (struct bbtree *bbt, cairo_command_header_t *header) +{ + _cairo_box_from_rectangle (&bbt->extents, &header->extents); + bbt->chain = header; +} + +static cairo_status_t +bbtree_add (struct bbtree *bbt, + cairo_command_header_t *header, + const cairo_box_t *box) +{ + if (box->p1.x < bbt->extents.p1.x || box->p1.y < bbt->extents.p1.y || + box->p2.x > bbt->extents.p2.x || box->p2.y > bbt->extents.p2.y) + { + if (bbt->chain) { + if (bbtree_left_or_right (bbt, &bbt->extents)) { + if (bbt->left == NULL) { + bbt->left = bbtree_new (&bbt->extents, bbt->chain); + if (unlikely (bbt->left == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } else + bbtree_add (bbt->left, bbt->chain, &bbt->extents); + } else { + if (bbt->right == NULL) { + bbt->right = bbtree_new (&bbt->extents, bbt->chain); + if (unlikely (bbt->right == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } else + bbtree_add (bbt->right, bbt->chain, &bbt->extents); + } + + bbt->chain = NULL; + } + + bbt->extents.p1.x = MIN (bbt->extents.p1.x, box->p1.x); + bbt->extents.p1.y = MIN (bbt->extents.p1.y, box->p1.y); + bbt->extents.p2.x = MAX (bbt->extents.p2.x, box->p2.x); + bbt->extents.p2.y = MAX (bbt->extents.p2.y, box->p2.y); + } + + if (box->p1.x == bbt->extents.p1.x && box->p1.y == bbt->extents.p1.y && + box->p2.x == bbt->extents.p2.x && box->p2.y == bbt->extents.p2.y) + { + cairo_command_header_t *last = header; + while (last->chain) /* expected to be infrequent */ + last = last->chain; + last->chain = bbt->chain; + bbt->chain = header; + return CAIRO_STATUS_SUCCESS; + } + + if (bbtree_left_or_right (bbt, box)) { + if (bbt->left == NULL) { + bbt->left = bbtree_new (box, header); + if (unlikely (bbt->left == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } else + return bbtree_add (bbt->left, header, box); + } else { + if (bbt->right == NULL) { + bbt->right = bbtree_new (box, header); + if (unlikely (bbt->right == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } else + return bbtree_add (bbt->right, header, box); + } + + return CAIRO_STATUS_SUCCESS; +} + +static void bbtree_del (struct bbtree *bbt) +{ + if (bbt->left) + bbtree_del (bbt->left); + if (bbt->right) + bbtree_del (bbt->right); + + free (bbt); +} + +static cairo_bool_t box_outside (const cairo_box_t *a, const cairo_box_t *b) +{ + return + a->p1.x >= b->p2.x || a->p1.y >= b->p2.y || + a->p2.x <= b->p1.x || a->p2.y <= b->p1.y; +} + +static void +bbtree_foreach_mark_visible (struct bbtree *bbt, + const cairo_box_t *box, + unsigned int **indices) +{ + cairo_command_header_t *chain; + + for (chain = bbt->chain; chain; chain = chain->chain) + *(*indices)++ = chain->index; + + if (bbt->left && ! box_outside (box, &bbt->left->extents)) + bbtree_foreach_mark_visible (bbt->left, box, indices); + if (bbt->right && ! box_outside (box, &bbt->right->extents)) + bbtree_foreach_mark_visible (bbt->right, box, indices); +} + +static inline int intcmp (const unsigned int a, const unsigned int b) +{ + return a - b; +} +CAIRO_COMBSORT_DECLARE (sort_indices, unsigned int, intcmp) + +static inline int sizecmp (unsigned int a, unsigned int b, cairo_command_header_t **elements) +{ + const cairo_rectangle_int_t *r; + + r = &elements[a]->extents; + a = r->width * r->height; + + r = &elements[b]->extents; + b = r->width * r->height; + + return b - a; +} +CAIRO_COMBSORT_DECLARE_WITH_DATA (sort_commands, unsigned int, sizecmp) + +static void +_cairo_recording_surface_destroy_bbtree (cairo_recording_surface_t *surface) +{ + cairo_command_t **elements; + int i, num_elements; + + if (surface->bbtree.chain == INVALID_CHAIN) + return; + + if (surface->bbtree.left) { + bbtree_del (surface->bbtree.left); + surface->bbtree.left = NULL; + } + if (surface->bbtree.right) { + bbtree_del (surface->bbtree.right); + surface->bbtree.right = NULL; + } + + elements = _cairo_array_index (&surface->commands, 0); + num_elements = surface->commands.num_elements; + for (i = 0; i < num_elements; i++) + elements[i]->header.chain = NULL; + + surface->bbtree.chain = INVALID_CHAIN; +} + +static cairo_status_t +_cairo_recording_surface_create_bbtree (cairo_recording_surface_t *surface) +{ + cairo_command_t **elements = _cairo_array_index (&surface->commands, 0); + unsigned int *indices; + cairo_status_t status; + unsigned int i, count; + + count = surface->commands.num_elements; + if (count > surface->num_indices) { + free (surface->indices); + surface->indices = _cairo_malloc_ab (count, sizeof (int)); + if (unlikely (surface->indices == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + surface->num_indices = count; + } + + indices = surface->indices; + for (i = 0; i < count; i++) + indices[i] = i; + + sort_commands (indices, count, elements); + + bbtree_init (&surface->bbtree, &elements[indices[0]]->header); + for (i = 1; i < count; i++) { + cairo_command_header_t *header = &elements[indices[i]]->header; + cairo_box_t box; + + _cairo_box_from_rectangle (&box, &header->extents); + status = bbtree_add (&surface->bbtree, header, &box); + if (unlikely (status)) + goto cleanup; + } + + return CAIRO_STATUS_SUCCESS; + +cleanup: + if (surface->bbtree.left) + bbtree_del (surface->bbtree.left); + if (surface->bbtree.right) + bbtree_del (surface->bbtree.right); + return status; +} + +/** + * cairo_recording_surface_create: + * @content: the content of the recording surface + * @extents: the extents to record in pixels, can be %NULL to record + * unbounded operations. + * + * Creates a recording-surface which can be used to record all drawing operations + * at the highest level (that is, the level of paint, mask, stroke, fill + * and show_text_glyphs). The recording surface can then be "replayed" against + * any target surface by using it as a source to drawing operations. + * + * The recording phase of the recording surface is careful to snapshot all + * necessary objects (paths, patterns, etc.), in order to achieve + * accurate replay. + * + * Return value: a pointer to the newly created surface. The caller + * owns the surface and should call cairo_surface_destroy() when done + * with it. + * + * Since: 1.10 + **/ +cairo_surface_t * +cairo_recording_surface_create (cairo_content_t content, + const cairo_rectangle_t *extents) +{ + cairo_recording_surface_t *surface; + + surface = _cairo_calloc (sizeof (cairo_recording_surface_t)); + if (unlikely (surface == NULL)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + _cairo_surface_init (&surface->base, + &cairo_recording_surface_backend, + NULL, /* device */ + content, + TRUE); /* is_vector */ + + + surface->unbounded = TRUE; + + /* unbounded -> 'infinite' extents */ + if (extents != NULL) { + surface->extents_pixels = *extents; + + /* XXX check for overflow */ + surface->extents.x = floor (extents->x); + surface->extents.y = floor (extents->y); + surface->extents.width = ceil (extents->x + extents->width) - surface->extents.x; + surface->extents.height = ceil (extents->y + extents->height) - surface->extents.y; + + surface->unbounded = FALSE; + } + + _cairo_array_init (&surface->commands, sizeof (cairo_command_t *)); + + surface->base.is_clear = TRUE; + + surface->bbtree.left = surface->bbtree.right = NULL; + surface->bbtree.chain = INVALID_CHAIN; + + surface->indices = NULL; + surface->num_indices = 0; + surface->optimize_clears = TRUE; + surface->has_bilevel_alpha = FALSE; + surface->has_only_op_over = FALSE; + surface->has_tags = FALSE; + + CAIRO_MUTEX_INIT (surface->mutex); + + cairo_list_init (&surface->region_array_list); + + return &surface->base; +} + +static cairo_surface_t * +_cairo_recording_surface_create_similar (void *abstract_surface, + cairo_content_t content, + int width, + int height) +{ + cairo_rectangle_t extents; + extents.x = extents.y = 0; + extents.width = width; + extents.height = height; + return cairo_recording_surface_create (content, &extents); +} + +static void +destroy_pattern_region_array (const cairo_pattern_t *pattern, + unsigned int region_id) +{ + if (region_id != 0) { + if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { + cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern; + if (_cairo_surface_is_recording (surface_pattern->surface)) + _cairo_recording_surface_region_array_remove (surface_pattern->surface, region_id); + } + } +} + +static void +_cairo_recording_surface_region_array_destroy (cairo_recording_surface_t *surface, + cairo_recording_regions_array_t *region_array) +{ + cairo_command_t **elements; + cairo_recording_region_element_t *region_elements; + int i, num_elements; + + num_elements = MIN(surface->commands.num_elements, _cairo_array_num_elements(®ion_array->regions)); + elements = _cairo_array_index (&surface->commands, 0); + region_elements = _cairo_array_index (®ion_array->regions, 0); + for (i = 0; i < num_elements; i++) { + cairo_command_t *command = elements[i]; + cairo_recording_region_element_t *region_element = ®ion_elements[i]; + + switch (command->header.type) { + case CAIRO_COMMAND_PAINT: + destroy_pattern_region_array (&command->paint.source.base, region_element->source_id); + break; + + case CAIRO_COMMAND_MASK: + destroy_pattern_region_array (&command->mask.source.base, region_element->source_id); + destroy_pattern_region_array (&command->mask.mask.base, region_element->mask_id); + break; + + case CAIRO_COMMAND_STROKE: + destroy_pattern_region_array (&command->stroke.source.base, region_element->source_id); + break; + + case CAIRO_COMMAND_FILL: + destroy_pattern_region_array (&command->fill.source.base, region_element->source_id); + break; + + case CAIRO_COMMAND_SHOW_TEXT_GLYPHS: + destroy_pattern_region_array (&command->show_text_glyphs.source.base, region_element->source_id); + break; + + case CAIRO_COMMAND_TAG: + break; + + default: + ASSERT_NOT_REACHED; + } + } + + _cairo_array_fini (®ion_array->regions); + free (region_array); +} + +static cairo_status_t +_cairo_recording_surface_finish (void *abstract_surface) +{ + cairo_recording_surface_t *surface = abstract_surface; + cairo_command_t **elements; + int i, num_elements; + cairo_recording_regions_array_t *region_array, *region_next; + + /* Normally backend surfaces hold a reference to the surface as + * well as the region and free the region before the surface. So + * the regions should already be freed at this point but just in + * case we ensure the regions are freed before destroying the + * surface. */ + cairo_list_foreach_entry_safe (region_array, region_next, + cairo_recording_regions_array_t, + &surface->region_array_list, link) + { + cairo_list_del (®ion_array->link); + _cairo_recording_surface_region_array_destroy (surface, region_array); + } + + num_elements = surface->commands.num_elements; + elements = _cairo_array_index (&surface->commands, 0); + for (i = 0; i < num_elements; i++) { + cairo_command_t *command = elements[i]; + + switch (command->header.type) { + case CAIRO_COMMAND_PAINT: + _cairo_pattern_fini (&command->paint.source.base); + break; + + case CAIRO_COMMAND_MASK: + _cairo_pattern_fini (&command->mask.source.base); + _cairo_pattern_fini (&command->mask.mask.base); + break; + + case CAIRO_COMMAND_STROKE: + _cairo_pattern_fini (&command->stroke.source.base); + _cairo_path_fixed_fini (&command->stroke.path); + _cairo_stroke_style_fini (&command->stroke.style); + break; + + case CAIRO_COMMAND_FILL: + _cairo_pattern_fini (&command->fill.source.base); + _cairo_path_fixed_fini (&command->fill.path); + break; + + case CAIRO_COMMAND_SHOW_TEXT_GLYPHS: + _cairo_pattern_fini (&command->show_text_glyphs.source.base); + free (command->show_text_glyphs.utf8); + free (command->show_text_glyphs.glyphs); + free (command->show_text_glyphs.clusters); + cairo_scaled_font_destroy (command->show_text_glyphs.scaled_font); + break; + + case CAIRO_COMMAND_TAG: + free (command->tag.tag_name); + if (command->tag.begin) { + free (command->tag.attributes); + } + break; + + default: + ASSERT_NOT_REACHED; + } + + _cairo_clip_destroy (command->header.clip); + free (command); + } + + _cairo_array_fini (&surface->commands); + + if (surface->bbtree.left) + bbtree_del (surface->bbtree.left); + if (surface->bbtree.right) + bbtree_del (surface->bbtree.right); + + free (surface->indices); + + return CAIRO_STATUS_SUCCESS; +} + +struct proxy { + cairo_surface_t base; + cairo_surface_t *image; +}; + +static cairo_status_t +proxy_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) +{ + struct proxy *proxy = abstract_surface; + return _cairo_surface_acquire_source_image (proxy->image, image_out, image_extra); +} + +static void +proxy_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) +{ + struct proxy *proxy = abstract_surface; + _cairo_surface_release_source_image (proxy->image, image, image_extra); +} + +static cairo_status_t +proxy_finish (void *abstract_surface) +{ + return CAIRO_STATUS_SUCCESS; +} + +static const cairo_surface_backend_t proxy_backend = { + CAIRO_INTERNAL_SURFACE_TYPE_NULL, + proxy_finish, + NULL, + + NULL, /* create similar */ + NULL, /* create similar image */ + NULL, /* map to image */ + NULL, /* unmap image */ + + _cairo_surface_default_source, + proxy_acquire_source_image, + proxy_release_source_image, +}; + +static cairo_surface_t * +attach_proxy (cairo_surface_t *source, + cairo_surface_t *image) +{ + struct proxy *proxy; + + proxy = _cairo_calloc (sizeof (*proxy)); + if (unlikely (proxy == NULL)) + return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY); + + _cairo_surface_init (&proxy->base, &proxy_backend, NULL, image->content, FALSE); + + proxy->image = image; + _cairo_surface_attach_snapshot (source, &proxy->base, NULL); + + return &proxy->base; +} + +static void +detach_proxy (cairo_surface_t *source, + cairo_surface_t *proxy) +{ + cairo_surface_finish (proxy); + cairo_surface_destroy (proxy); +} + +static cairo_surface_t * +get_proxy (cairo_surface_t *proxy) +{ + return ((struct proxy *)proxy)->image; +} + +static cairo_status_t +_cairo_recording_surface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) +{ + cairo_recording_surface_t *surface = abstract_surface; + cairo_surface_t *image, *proxy; + cairo_status_t status; + + proxy = _cairo_surface_has_snapshot (abstract_surface, &proxy_backend); + if (proxy != NULL) { + *image_out = (cairo_image_surface_t *) + cairo_surface_reference (get_proxy (proxy)); + *image_extra = NULL; + return CAIRO_STATUS_SUCCESS; + } + + if (surface->unbounded) + return CAIRO_INT_STATUS_UNSUPPORTED; + image = _cairo_image_surface_create_with_content (surface->base.content, + surface->extents.width, + surface->extents.height); + cairo_surface_set_device_offset (image, -surface->extents.x, -surface->extents.y); + if (unlikely (image->status)) + return image->status; + + cairo_surface_set_device_offset(image, -surface->extents.x, -surface->extents.y); + + /* Handle recursion by returning future reads from the current image */ + proxy = attach_proxy (abstract_surface, image); + status = _cairo_recording_surface_replay (&surface->base, image); + detach_proxy (abstract_surface, proxy); + + if (unlikely (status)) { + cairo_surface_destroy (image); + return status; + } + + *image_out = (cairo_image_surface_t *) image; + *image_extra = NULL; + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_recording_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) +{ + cairo_surface_destroy (&image->base); +} + +static cairo_status_t +_command_init (cairo_recording_surface_t *surface, + cairo_command_header_t *command, + cairo_command_type_t type, + cairo_operator_t op, + cairo_composite_rectangles_t *composite) +{ + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + command->type = type; + command->op = op; + + command->extents = composite ? composite->unbounded : _cairo_empty_rectangle; + command->chain = NULL; + command->index = surface->commands.num_elements; + + /* steal the clip */ + command->clip = NULL; + if (composite && ! _cairo_composite_rectangles_can_reduce_clip (composite, + composite->clip)) + { + command->clip = composite->clip; + composite->clip = NULL; + } + + return status; +} + +static void +_cairo_recording_surface_break_self_copy_loop (cairo_recording_surface_t *surface) +{ + cairo_surface_flush (&surface->base); +} + +static cairo_status_t +_cairo_recording_surface_commit (cairo_recording_surface_t *surface, + cairo_command_header_t *command) +{ + _cairo_recording_surface_break_self_copy_loop (surface); + return _cairo_array_append (&surface->commands, &command); +} + +static void +_cairo_recording_surface_reset (cairo_recording_surface_t *surface) +{ + /* Reset the commands and temporaries */ + _cairo_recording_surface_finish (surface); + + surface->bbtree.left = surface->bbtree.right = NULL; + surface->bbtree.chain = INVALID_CHAIN; + + surface->indices = NULL; + surface->num_indices = 0; + + _cairo_array_init (&surface->commands, sizeof (cairo_command_t *)); +} + +static cairo_int_status_t +_cairo_recording_surface_paint (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip) +{ + cairo_status_t status; + cairo_recording_surface_t *surface = abstract_surface; + cairo_command_paint_t *command; + cairo_composite_rectangles_t composite; + + TRACE ((stderr, "%s: surface=%d\n", __FUNCTION__, surface->base.unique_id)); + + if (op == CAIRO_OPERATOR_CLEAR && clip == NULL) { + if (surface->optimize_clears) { + _cairo_recording_surface_reset (surface); + return CAIRO_STATUS_SUCCESS; + } + } + + if (clip == NULL && surface->optimize_clears && + (op == CAIRO_OPERATOR_SOURCE || + (op == CAIRO_OPERATOR_OVER && + (surface->base.is_clear || _cairo_pattern_is_opaque_solid (source))))) + { + _cairo_recording_surface_reset (surface); + } + + status = _cairo_composite_rectangles_init_for_paint (&composite, + &surface->base, + op, source, + clip); + if (unlikely (status)) + return status; + + command = _cairo_calloc (sizeof (cairo_command_paint_t)); + if (unlikely (command == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CLEANUP_COMPOSITE; + } + + status = _command_init (surface, + &command->header, CAIRO_COMMAND_PAINT, op, + &composite); + if (unlikely (status)) + goto CLEANUP_COMMAND; + + status = _cairo_pattern_init_snapshot (&command->source.base, source); + if (unlikely (status)) + goto CLEANUP_COMMAND; + + status = _cairo_recording_surface_commit (surface, &command->header); + if (unlikely (status)) + goto CLEANUP_SOURCE; + + _cairo_recording_surface_destroy_bbtree (surface); + + _cairo_composite_rectangles_fini (&composite); + return CAIRO_STATUS_SUCCESS; + + CLEANUP_SOURCE: + _cairo_pattern_fini (&command->source.base); + CLEANUP_COMMAND: + _cairo_clip_destroy (command->header.clip); + free (command); +CLEANUP_COMPOSITE: + _cairo_composite_rectangles_fini (&composite); + return status; +} + +static cairo_int_status_t +_cairo_recording_surface_mask (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_clip_t *clip) +{ + cairo_status_t status; + cairo_recording_surface_t *surface = abstract_surface; + cairo_command_mask_t *command; + cairo_composite_rectangles_t composite; + + TRACE ((stderr, "%s: surface=%d\n", __FUNCTION__, surface->base.unique_id)); + + status = _cairo_composite_rectangles_init_for_mask (&composite, + &surface->base, + op, source, mask, + clip); + if (unlikely (status)) + return status; + + command = _cairo_calloc (sizeof (cairo_command_mask_t)); + if (unlikely (command == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CLEANUP_COMPOSITE; + } + + status = _command_init (surface, + &command->header, CAIRO_COMMAND_MASK, op, + &composite); + if (unlikely (status)) + goto CLEANUP_COMMAND; + + status = _cairo_pattern_init_snapshot (&command->source.base, source); + if (unlikely (status)) + goto CLEANUP_COMMAND; + + status = _cairo_pattern_init_snapshot (&command->mask.base, mask); + if (unlikely (status)) + goto CLEANUP_SOURCE; + + status = _cairo_recording_surface_commit (surface, &command->header); + if (unlikely (status)) + goto CLEANUP_MASK; + + _cairo_recording_surface_destroy_bbtree (surface); + + _cairo_composite_rectangles_fini (&composite); + return CAIRO_STATUS_SUCCESS; + + CLEANUP_MASK: + _cairo_pattern_fini (&command->mask.base); + CLEANUP_SOURCE: + _cairo_pattern_fini (&command->source.base); + CLEANUP_COMMAND: + _cairo_clip_destroy (command->header.clip); + free (command); +CLEANUP_COMPOSITE: + _cairo_composite_rectangles_fini (&composite); + return status; +} + +static cairo_int_status_t +_cairo_recording_surface_stroke (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_status_t status; + cairo_recording_surface_t *surface = abstract_surface; + cairo_command_stroke_t *command; + cairo_composite_rectangles_t composite; + + TRACE ((stderr, "%s: surface=%d\n", __FUNCTION__, surface->base.unique_id)); + + status = _cairo_composite_rectangles_init_for_stroke (&composite, + &surface->base, + op, source, + path, style, ctm, + clip); + if (unlikely (status)) + return status; + + command = _cairo_calloc (sizeof (cairo_command_stroke_t)); + if (unlikely (command == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CLEANUP_COMPOSITE; + } + + status = _command_init (surface, + &command->header, CAIRO_COMMAND_STROKE, op, + &composite); + if (unlikely (status)) + goto CLEANUP_COMMAND; + + status = _cairo_pattern_init_snapshot (&command->source.base, source); + if (unlikely (status)) + goto CLEANUP_COMMAND; + + status = _cairo_path_fixed_init_copy (&command->path, path); + if (unlikely (status)) + goto CLEANUP_SOURCE; + + status = _cairo_stroke_style_init_copy (&command->style, style); + if (unlikely (status)) + goto CLEANUP_PATH; + + command->ctm = *ctm; + command->ctm_inverse = *ctm_inverse; + command->tolerance = tolerance; + command->antialias = antialias; + + status = _cairo_recording_surface_commit (surface, &command->header); + if (unlikely (status)) + goto CLEANUP_STYLE; + + _cairo_recording_surface_destroy_bbtree (surface); + + _cairo_composite_rectangles_fini (&composite); + return CAIRO_STATUS_SUCCESS; + + CLEANUP_STYLE: + _cairo_stroke_style_fini (&command->style); + CLEANUP_PATH: + _cairo_path_fixed_fini (&command->path); + CLEANUP_SOURCE: + _cairo_pattern_fini (&command->source.base); + CLEANUP_COMMAND: + _cairo_clip_destroy (command->header.clip); + free (command); +CLEANUP_COMPOSITE: + _cairo_composite_rectangles_fini (&composite); + return status; +} + +static cairo_int_status_t +_cairo_recording_surface_fill (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_status_t status; + cairo_recording_surface_t *surface = abstract_surface; + cairo_command_fill_t *command; + cairo_composite_rectangles_t composite; + + TRACE ((stderr, "%s: surface=%d\n", __FUNCTION__, surface->base.unique_id)); + + status = _cairo_composite_rectangles_init_for_fill (&composite, + &surface->base, + op, source, path, + clip); + if (unlikely (status)) + return status; + + command = _cairo_calloc (sizeof (cairo_command_fill_t)); + if (unlikely (command == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CLEANUP_COMPOSITE; + } + + status =_command_init (surface, + &command->header, CAIRO_COMMAND_FILL, op, + &composite); + if (unlikely (status)) + goto CLEANUP_COMMAND; + + status = _cairo_pattern_init_snapshot (&command->source.base, source); + if (unlikely (status)) + goto CLEANUP_COMMAND; + + status = _cairo_path_fixed_init_copy (&command->path, path); + if (unlikely (status)) + goto CLEANUP_SOURCE; + + command->fill_rule = fill_rule; + command->tolerance = tolerance; + command->antialias = antialias; + + status = _cairo_recording_surface_commit (surface, &command->header); + if (unlikely (status)) + goto CLEANUP_PATH; + + _cairo_recording_surface_destroy_bbtree (surface); + + _cairo_composite_rectangles_fini (&composite); + return CAIRO_STATUS_SUCCESS; + + CLEANUP_PATH: + _cairo_path_fixed_fini (&command->path); + CLEANUP_SOURCE: + _cairo_pattern_fini (&command->source.base); + CLEANUP_COMMAND: + _cairo_clip_destroy (command->header.clip); + free (command); +CLEANUP_COMPOSITE: + _cairo_composite_rectangles_fini (&composite); + return status; +} + +static cairo_bool_t +_cairo_recording_surface_has_show_text_glyphs (void *abstract_surface) +{ + return TRUE; +} + +static cairo_int_status_t +_cairo_recording_surface_show_text_glyphs (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const char *utf8, + int utf8_len, + cairo_glyph_t *glyphs, + int num_glyphs, + const cairo_text_cluster_t *clusters, + int num_clusters, + cairo_text_cluster_flags_t cluster_flags, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip) +{ + cairo_status_t status; + cairo_recording_surface_t *surface = abstract_surface; + cairo_command_show_text_glyphs_t *command; + cairo_composite_rectangles_t composite; + + TRACE ((stderr, "%s: surface=%d\n", __FUNCTION__, surface->base.unique_id)); + + status = _cairo_composite_rectangles_init_for_glyphs (&composite, + &surface->base, + op, source, + scaled_font, + glyphs, num_glyphs, + clip, + NULL); + if (unlikely (status)) + return status; + + command = _cairo_calloc (sizeof (cairo_command_show_text_glyphs_t)); + if (unlikely (command == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CLEANUP_COMPOSITE; + } + + status = _command_init (surface, + &command->header, CAIRO_COMMAND_SHOW_TEXT_GLYPHS, + op, &composite); + if (unlikely (status)) + goto CLEANUP_COMMAND; + + status = _cairo_pattern_init_snapshot (&command->source.base, source); + if (unlikely (status)) + goto CLEANUP_COMMAND; + + command->utf8 = NULL; + command->utf8_len = utf8_len; + command->glyphs = NULL; + command->num_glyphs = num_glyphs; + command->clusters = NULL; + command->num_clusters = num_clusters; + + if (utf8_len) { + command->utf8 = _cairo_malloc (utf8_len); + if (unlikely (command->utf8 == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CLEANUP_ARRAYS; + } + memcpy (command->utf8, utf8, utf8_len); + } + if (num_glyphs) { + command->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (glyphs[0])); + if (unlikely (command->glyphs == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CLEANUP_ARRAYS; + } + memcpy (command->glyphs, glyphs, sizeof (glyphs[0]) * num_glyphs); + } + if (num_clusters) { + command->clusters = _cairo_malloc_ab (num_clusters, sizeof (clusters[0])); + if (unlikely (command->clusters == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CLEANUP_ARRAYS; + } + memcpy (command->clusters, clusters, sizeof (clusters[0]) * num_clusters); + } + + command->cluster_flags = cluster_flags; + + status = scaled_font->status; + if (unlikely (status)) + goto CLEANUP_ARRAYS; + + command->scaled_font = cairo_scaled_font_reference (scaled_font); + + status = _cairo_recording_surface_commit (surface, &command->header); + if (unlikely (status)) + goto CLEANUP_SCALED_FONT; + + _cairo_composite_rectangles_fini (&composite); + return CAIRO_STATUS_SUCCESS; + + CLEANUP_SCALED_FONT: + cairo_scaled_font_destroy (command->scaled_font); + CLEANUP_ARRAYS: + free (command->utf8); + free (command->glyphs); + free (command->clusters); + + _cairo_pattern_fini (&command->source.base); + CLEANUP_COMMAND: + _cairo_clip_destroy (command->header.clip); + free (command); +CLEANUP_COMPOSITE: + _cairo_composite_rectangles_fini (&composite); + return status; +} + +static cairo_int_status_t +_cairo_recording_surface_tag (void *abstract_surface, + cairo_bool_t begin, + const char *tag_name, + const char *attributes) +{ + cairo_status_t status; + cairo_recording_surface_t *surface = abstract_surface; + cairo_command_tag_t *command; + + TRACE ((stderr, "%s: surface=%d\n", __FUNCTION__, surface->base.unique_id)); + + surface->has_tags = TRUE; + + command = _cairo_calloc (sizeof (cairo_command_tag_t)); + if (unlikely (command == NULL)) { + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + status = _command_init (surface, + &command->header, CAIRO_COMMAND_TAG, CAIRO_OPERATOR_SOURCE, + NULL); + if (unlikely (status)) + goto CLEANUP_COMMAND; + + command->begin = begin; + command->tag_name = strdup (tag_name); + if (unlikely (command->tag_name == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CLEANUP_COMMAND; + } + if (begin) { + if (attributes) { + command->attributes = strdup (attributes); + if (unlikely (command->attributes == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CLEANUP_STRINGS; + } + } + } + + status = _cairo_recording_surface_commit (surface, &command->header); + if (unlikely (status)) + goto CLEANUP_STRINGS; + + _cairo_recording_surface_destroy_bbtree (surface); + + return CAIRO_STATUS_SUCCESS; + + CLEANUP_STRINGS: + free (command->tag_name); + free (command->attributes); + CLEANUP_COMMAND: + _cairo_clip_destroy (command->header.clip); + free (command); + return status; +} + +static cairo_bool_t +_cairo_recording_surface_supports_color_glyph (void *abstract_surface, + cairo_scaled_font_t *scaled_font, + unsigned long glyph_index) +{ + return TRUE; +} + +static void +_command_init_copy (cairo_recording_surface_t *surface, + cairo_command_header_t *dst, + const cairo_command_header_t *src) +{ + dst->type = src->type; + dst->op = src->op; + + dst->extents = src->extents; + dst->chain = NULL; + dst->index = surface->commands.num_elements; + + dst->clip = _cairo_clip_copy (src->clip); +} + +static cairo_status_t +_cairo_recording_surface_copy__paint (cairo_recording_surface_t *surface, + const cairo_command_t *src) +{ + cairo_command_paint_t *command; + cairo_status_t status; + + command = _cairo_calloc (sizeof (*command)); + if (unlikely (command == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto err; + } + + _command_init_copy (surface, &command->header, &src->header); + + status = _cairo_pattern_init_copy (&command->source.base, + &src->paint.source.base); + if (unlikely (status)) + goto err_command; + + status = _cairo_recording_surface_commit (surface, &command->header); + if (unlikely (status)) + goto err_source; + + return CAIRO_STATUS_SUCCESS; + +err_source: + _cairo_pattern_fini (&command->source.base); +err_command: + free(command); +err: + return status; +} + +static cairo_status_t +_cairo_recording_surface_copy__mask (cairo_recording_surface_t *surface, + const cairo_command_t *src) +{ + cairo_command_mask_t *command; + cairo_status_t status; + + command = _cairo_calloc (sizeof (*command)); + if (unlikely (command == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto err; + } + + _command_init_copy (surface, &command->header, &src->header); + + status = _cairo_pattern_init_copy (&command->source.base, + &src->mask.source.base); + if (unlikely (status)) + goto err_command; + + status = _cairo_pattern_init_copy (&command->mask.base, + &src->mask.mask.base); + if (unlikely (status)) + goto err_source; + + status = _cairo_recording_surface_commit (surface, &command->header); + if (unlikely (status)) + goto err_mask; + + return CAIRO_STATUS_SUCCESS; + +err_mask: + _cairo_pattern_fini (&command->mask.base); +err_source: + _cairo_pattern_fini (&command->source.base); +err_command: + free(command); +err: + return status; +} + +static cairo_status_t +_cairo_recording_surface_copy__stroke (cairo_recording_surface_t *surface, + const cairo_command_t *src) +{ + cairo_command_stroke_t *command; + cairo_status_t status; + + command = _cairo_calloc (sizeof (*command)); + if (unlikely (command == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto err; + } + + _command_init_copy (surface, &command->header, &src->header); + + status = _cairo_pattern_init_copy (&command->source.base, + &src->stroke.source.base); + if (unlikely (status)) + goto err_command; + + status = _cairo_path_fixed_init_copy (&command->path, &src->stroke.path); + if (unlikely (status)) + goto err_source; + + status = _cairo_stroke_style_init_copy (&command->style, + &src->stroke.style); + if (unlikely (status)) + goto err_path; + + command->ctm = src->stroke.ctm; + command->ctm_inverse = src->stroke.ctm_inverse; + command->tolerance = src->stroke.tolerance; + command->antialias = src->stroke.antialias; + + status = _cairo_recording_surface_commit (surface, &command->header); + if (unlikely (status)) + goto err_style; + + return CAIRO_STATUS_SUCCESS; + +err_style: + _cairo_stroke_style_fini (&command->style); +err_path: + _cairo_path_fixed_fini (&command->path); +err_source: + _cairo_pattern_fini (&command->source.base); +err_command: + free(command); +err: + return status; +} + +static cairo_status_t +_cairo_recording_surface_copy__fill (cairo_recording_surface_t *surface, + const cairo_command_t *src) +{ + cairo_command_fill_t *command; + cairo_status_t status; + + command = _cairo_calloc (sizeof (*command)); + if (unlikely (command == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto err; + } + + _command_init_copy (surface, &command->header, &src->header); + + status = _cairo_pattern_init_copy (&command->source.base, + &src->fill.source.base); + if (unlikely (status)) + goto err_command; + + status = _cairo_path_fixed_init_copy (&command->path, &src->fill.path); + if (unlikely (status)) + goto err_source; + + command->fill_rule = src->fill.fill_rule; + command->tolerance = src->fill.tolerance; + command->antialias = src->fill.antialias; + + status = _cairo_recording_surface_commit (surface, &command->header); + if (unlikely (status)) + goto err_path; + + return CAIRO_STATUS_SUCCESS; + +err_path: + _cairo_path_fixed_fini (&command->path); +err_source: + _cairo_pattern_fini (&command->source.base); +err_command: + free(command); +err: + return status; +} + +static cairo_status_t +_cairo_recording_surface_copy__glyphs (cairo_recording_surface_t *surface, + const cairo_command_t *src) +{ + cairo_command_show_text_glyphs_t *command; + cairo_status_t status; + + command = _cairo_calloc (sizeof (*command)); + if (unlikely (command == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto err; + } + + _command_init_copy (surface, &command->header, &src->header); + + status = _cairo_pattern_init_copy (&command->source.base, + &src->show_text_glyphs.source.base); + if (unlikely (status)) + goto err_command; + + command->utf8 = NULL; + command->utf8_len = src->show_text_glyphs.utf8_len; + command->glyphs = NULL; + command->num_glyphs = src->show_text_glyphs.num_glyphs; + command->clusters = NULL; + command->num_clusters = src->show_text_glyphs.num_clusters; + + if (command->utf8_len) { + command->utf8 = _cairo_malloc (command->utf8_len); + if (unlikely (command->utf8 == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto err_arrays; + } + memcpy (command->utf8, src->show_text_glyphs.utf8, command->utf8_len); + } + if (command->num_glyphs) { + command->glyphs = _cairo_malloc_ab (command->num_glyphs, + sizeof (command->glyphs[0])); + if (unlikely (command->glyphs == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto err_arrays; + } + memcpy (command->glyphs, src->show_text_glyphs.glyphs, + sizeof (command->glyphs[0]) * command->num_glyphs); + } + if (command->num_clusters) { + command->clusters = _cairo_malloc_ab (command->num_clusters, + sizeof (command->clusters[0])); + if (unlikely (command->clusters == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto err_arrays; + } + memcpy (command->clusters, src->show_text_glyphs.clusters, + sizeof (command->clusters[0]) * command->num_clusters); + } + + command->cluster_flags = src->show_text_glyphs.cluster_flags; + + command->scaled_font = + cairo_scaled_font_reference (src->show_text_glyphs.scaled_font); + + status = _cairo_recording_surface_commit (surface, &command->header); + if (unlikely (status)) + goto err_arrays; + + return CAIRO_STATUS_SUCCESS; + +err_arrays: + free (command->utf8); + free (command->glyphs); + free (command->clusters); + _cairo_pattern_fini (&command->source.base); +err_command: + free(command); +err: + return status; +} + +static cairo_status_t +_cairo_recording_surface_copy__tag (cairo_recording_surface_t *surface, + const cairo_command_t *src) +{ + cairo_command_tag_t *command; + cairo_status_t status; + + command = _cairo_calloc (sizeof (*command)); + if (unlikely (command == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto err; + } + + _command_init_copy (surface, &command->header, &src->header); + + command->begin = src->tag.begin; + command->tag_name = strdup (src->tag.tag_name); + if (unlikely (command->tag_name == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto err_command; + } + if (src->tag.begin) { + if (src->tag.attributes) { + command->attributes = strdup (src->tag.attributes); + if (unlikely (command->attributes == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto err_command; + } + } + } + + status = _cairo_recording_surface_commit (surface, &command->header); + if (unlikely (status)) + goto err_command; + + return CAIRO_STATUS_SUCCESS; + +err_command: + free(command->tag_name); + free(command->attributes); + free(command); +err: + return status; +} + +static cairo_status_t +_cairo_recording_surface_copy (cairo_recording_surface_t *dst, + cairo_recording_surface_t *src) +{ + cairo_command_t **elements; + int i, num_elements; + cairo_status_t status; + + elements = _cairo_array_index (&src->commands, 0); + num_elements = src->commands.num_elements; + for (i = 0; i < num_elements; i++) { + const cairo_command_t *command = elements[i]; + + switch (command->header.type) { + case CAIRO_COMMAND_PAINT: + status = _cairo_recording_surface_copy__paint (dst, command); + break; + + case CAIRO_COMMAND_MASK: + status = _cairo_recording_surface_copy__mask (dst, command); + break; + + case CAIRO_COMMAND_STROKE: + status = _cairo_recording_surface_copy__stroke (dst, command); + break; + + case CAIRO_COMMAND_FILL: + status = _cairo_recording_surface_copy__fill (dst, command); + break; + + case CAIRO_COMMAND_SHOW_TEXT_GLYPHS: + status = _cairo_recording_surface_copy__glyphs (dst, command); + break; + + case CAIRO_COMMAND_TAG: + status = _cairo_recording_surface_copy__tag (dst, command); + break; + + default: + ASSERT_NOT_REACHED; + } + + if (unlikely (status)) + return status; + } + + return CAIRO_STATUS_SUCCESS; +} + +/** + * _cairo_recording_surface_snapshot: + * @surface: a #cairo_surface_t which must be a recording surface + * + * Make an immutable copy of @surface. It is an error to call a + * surface-modifying function on the result of this function. + * + * The caller owns the return value and should call + * cairo_surface_destroy() when finished with it. This function will not + * return %NULL, but will return a nil surface instead. + * + * Return value: The snapshot surface. + **/ +static cairo_surface_t * +_cairo_recording_surface_snapshot (void *abstract_other) +{ + cairo_recording_surface_t *other = abstract_other; + cairo_recording_surface_t *surface; + cairo_status_t status; + + surface = _cairo_calloc (sizeof (cairo_recording_surface_t)); + if (unlikely (surface == NULL)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + _cairo_surface_init (&surface->base, + &cairo_recording_surface_backend, + NULL, /* device */ + other->base.content, + other->base.is_vector); + + surface->extents_pixels = other->extents_pixels; + surface->extents = other->extents; + surface->unbounded = other->unbounded; + surface->has_bilevel_alpha = other->has_bilevel_alpha; + surface->has_only_op_over = other->has_only_op_over; + surface->has_tags = other->has_tags; + + surface->base.is_clear = other->base.is_clear; + + surface->bbtree.left = surface->bbtree.right = NULL; + surface->bbtree.chain = INVALID_CHAIN; + + surface->indices = NULL; + surface->num_indices = 0; + surface->optimize_clears = TRUE; + + CAIRO_MUTEX_INIT (surface->mutex); + + cairo_list_init (&surface->region_array_list); + + _cairo_array_init (&surface->commands, sizeof (cairo_command_t *)); + status = _cairo_recording_surface_copy (surface, other); + if (unlikely (status)) { + cairo_surface_destroy (&surface->base); + return _cairo_surface_create_in_error (status); + } + + return &surface->base; +} + +static cairo_bool_t +_cairo_recording_surface_get_extents (void *abstract_surface, + cairo_rectangle_int_t *rectangle) +{ + cairo_recording_surface_t *surface = abstract_surface; + + if (surface->unbounded) + return FALSE; + + *rectangle = surface->extents; + return TRUE; +} + +static const cairo_surface_backend_t cairo_recording_surface_backend = { + CAIRO_SURFACE_TYPE_RECORDING, + _cairo_recording_surface_finish, + + _cairo_default_context_create, + + _cairo_recording_surface_create_similar, + NULL, /* create similar image */ + NULL, /* map to image */ + NULL, /* unmap image */ + + _cairo_surface_default_source, + _cairo_recording_surface_acquire_source_image, + _cairo_recording_surface_release_source_image, + _cairo_recording_surface_snapshot, + + NULL, /* copy_page */ + NULL, /* show_page */ + + _cairo_recording_surface_get_extents, + NULL, /* get_font_options */ + + NULL, /* flush */ + NULL, /* mark_dirty_rectangle */ + + /* Here are the 5 basic drawing operations, (which are in some + * sense the only things that cairo_recording_surface should need to + * implement). However, we implement the more generic show_text_glyphs + * instead of show_glyphs. One or the other is eough. */ + + _cairo_recording_surface_paint, + _cairo_recording_surface_mask, + _cairo_recording_surface_stroke, + _cairo_recording_surface_fill, + NULL, /* fill-stroke */ + NULL, + _cairo_recording_surface_has_show_text_glyphs, + _cairo_recording_surface_show_text_glyphs, + NULL, /* get_supported_mime_types */ + _cairo_recording_surface_tag, + _cairo_recording_surface_supports_color_glyph, + NULL, /* analyze_recording_surface */ + NULL, /* command_id */ +}; + +static unsigned int +_cairo_recording_surface_regions_allocate_unique_id (void) +{ + static cairo_atomic_int_t unique_id; + +#if CAIRO_NO_MUTEX + if (++unique_id == 0) + unique_id = 1; + return unique_id; +#else + int old, id; + + do { + old = _cairo_atomic_uint_get (&unique_id); + id = old + 1; + if (id == 0) + id = 1; + } while (! _cairo_atomic_uint_cmpxchg (&unique_id, old, id)); + + return id; +#endif +} + +static cairo_recording_regions_array_t * +_cairo_recording_surface_region_array_find (cairo_recording_surface_t *surface, + unsigned int id) +{ + cairo_recording_regions_array_t *regions; + + cairo_list_foreach_entry (regions, cairo_recording_regions_array_t, + &surface->region_array_list, link) + { + if (regions->id == id) + return regions; + } + + return NULL; +} + +/* Create and initialize a new #cairo_recording_regions_array_t. Attach + * it to the recording surface and return its id + */ +cairo_status_t +_cairo_recording_surface_region_array_attach (cairo_surface_t *abstract_surface, + unsigned int *id) +{ + cairo_recording_regions_array_t *region_array; + cairo_recording_surface_t *surface = (cairo_recording_surface_t *) abstract_surface; + + assert (_cairo_surface_is_recording (abstract_surface)); + + region_array = _cairo_calloc (sizeof (cairo_recording_regions_array_t)); + if (region_array == NULL) { + *id = 0; + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + region_array->id = _cairo_recording_surface_regions_allocate_unique_id (); + + CAIRO_REFERENCE_COUNT_INIT (®ion_array->ref_count, 1); + + _cairo_array_init (®ion_array->regions, sizeof (cairo_recording_region_element_t)); + + CAIRO_MUTEX_LOCK (surface->mutex); + cairo_list_add (®ion_array->link, &surface->region_array_list); + CAIRO_MUTEX_UNLOCK (surface->mutex); + + *id = region_array->id; + + return CAIRO_STATUS_SUCCESS; +} + +void +_cairo_recording_surface_region_array_remove (cairo_surface_t *abstract_surface, + unsigned int id) +{ + cairo_recording_regions_array_t *region_array; + cairo_recording_surface_t *surface = (cairo_recording_surface_t *) abstract_surface; + + if (id == 0) + return; + + assert (_cairo_surface_is_recording (abstract_surface)); + + CAIRO_MUTEX_LOCK (surface->mutex); + region_array = _cairo_recording_surface_region_array_find (surface, id); + if (region_array) { + if (_cairo_reference_count_dec_and_test (®ion_array->ref_count)) + cairo_list_del (®ion_array->link); + else + region_array = NULL; + } + + CAIRO_MUTEX_UNLOCK (surface->mutex); + + if (region_array) + _cairo_recording_surface_region_array_destroy (surface, region_array); +} + +void +_cairo_recording_surface_region_array_reference (cairo_surface_t *abstract_surface, + unsigned int id) +{ + cairo_recording_regions_array_t *region_array; + cairo_recording_surface_t *surface = (cairo_recording_surface_t *) abstract_surface; + + assert (_cairo_surface_is_recording (abstract_surface)); + + CAIRO_MUTEX_LOCK (surface->mutex); + region_array = _cairo_recording_surface_region_array_find (surface, id); + if (region_array) { + _cairo_reference_count_inc (®ion_array->ref_count); + } + + CAIRO_MUTEX_UNLOCK (surface->mutex); +} + +cairo_int_status_t +_cairo_recording_surface_get_path (cairo_surface_t *abstract_surface, + cairo_path_fixed_t *path) +{ + cairo_recording_surface_t *surface; + cairo_command_t **elements; + int i, num_elements; + cairo_int_status_t status; + + if (unlikely (abstract_surface->status)) + return abstract_surface->status; + + surface = (cairo_recording_surface_t *) abstract_surface; + status = CAIRO_STATUS_SUCCESS; + + num_elements = surface->commands.num_elements; + elements = _cairo_array_index (&surface->commands, 0); + for (i = 0; i < num_elements; i++) { + cairo_command_t *command = elements[i]; + + switch (command->header.type) { + case CAIRO_COMMAND_PAINT: + case CAIRO_COMMAND_MASK: + status = CAIRO_INT_STATUS_UNSUPPORTED; + break; + + case CAIRO_COMMAND_STROKE: + { + cairo_traps_t traps; + + _cairo_traps_init (&traps); + + /* XXX call cairo_stroke_to_path() when that is implemented */ + status = _cairo_path_fixed_stroke_polygon_to_traps (&command->stroke.path, + &command->stroke.style, + &command->stroke.ctm, + &command->stroke.ctm_inverse, + command->stroke.tolerance, + &traps); + + if (status == CAIRO_INT_STATUS_SUCCESS) + status = _cairo_traps_path (&traps, path); + + _cairo_traps_fini (&traps); + break; + } + case CAIRO_COMMAND_FILL: + { + status = _cairo_path_fixed_append (path, + &command->fill.path, + 0, 0); + break; + } + case CAIRO_COMMAND_SHOW_TEXT_GLYPHS: + { + status = _cairo_scaled_font_glyph_path (command->show_text_glyphs.scaled_font, + command->show_text_glyphs.glyphs, + command->show_text_glyphs.num_glyphs, + path); + break; + } + + case CAIRO_COMMAND_TAG: + break; + + default: + ASSERT_NOT_REACHED; + } + + if (unlikely (status)) + break; + } + + return status; +} + +static int +_cairo_recording_surface_get_visible_commands (cairo_recording_surface_t *surface, + const cairo_rectangle_int_t *extents) +{ + unsigned int num_visible, *indices; + cairo_box_t box; + + if (surface->commands.num_elements == 0) + return 0; + + _cairo_box_from_rectangle (&box, extents); + + if (surface->bbtree.chain == INVALID_CHAIN) + _cairo_recording_surface_create_bbtree (surface); + + indices = surface->indices; + bbtree_foreach_mark_visible (&surface->bbtree, &box, &indices); + num_visible = indices - surface->indices; + if (num_visible > 1) + sort_indices (surface->indices, num_visible); + + return num_visible; +} + +static void +_cairo_recording_surface_merge_source_attributes (cairo_recording_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source) +{ + if (op != CAIRO_OPERATOR_OVER) + surface->has_only_op_over = FALSE; + + if (source->type == CAIRO_PATTERN_TYPE_SURFACE) { + cairo_surface_pattern_t *surf_pat = (cairo_surface_pattern_t *) source; + cairo_surface_t *surf = surf_pat->surface; + cairo_surface_t *free_me = NULL; + + if (_cairo_surface_is_snapshot (surf)) + free_me = surf = _cairo_surface_snapshot_get_target (surf); + + if (unlikely (surf->status)) + // There was some kind of error and the surface could be a nil error + // surface with various "problems" (e.g. ->backend == NULL). + return; + + if (surf->type == CAIRO_SURFACE_TYPE_RECORDING) { + cairo_recording_surface_t *rec_surf = (cairo_recording_surface_t *) surf; + + if (! _cairo_recording_surface_has_only_bilevel_alpha (rec_surf)) + surface->has_bilevel_alpha = FALSE; + + if (! _cairo_recording_surface_has_only_op_over (rec_surf)) + surface->has_only_op_over = FALSE; + + } else if (surf->type == CAIRO_SURFACE_TYPE_IMAGE) { + cairo_image_surface_t *img_surf = (cairo_image_surface_t *) surf; + + if (_cairo_image_analyze_transparency (img_surf) == CAIRO_IMAGE_HAS_ALPHA) + surface->has_bilevel_alpha = FALSE; + + } else { + if (!_cairo_pattern_is_clear (source) && !_cairo_pattern_is_opaque (source, NULL)) + surface->has_bilevel_alpha = FALSE; + } + + cairo_surface_destroy (free_me); + return; + + } else if (source->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) { + cairo_surface_t *image; + cairo_surface_t *raster; + + image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1); + raster = _cairo_raster_source_pattern_acquire (source, image, NULL); + cairo_surface_destroy (image); + if (raster) { + if (raster->type == CAIRO_SURFACE_TYPE_IMAGE) { + if (_cairo_image_analyze_transparency ((cairo_image_surface_t *)raster) == CAIRO_IMAGE_HAS_ALPHA) + surface->has_bilevel_alpha = FALSE; + } + + _cairo_raster_source_pattern_release (source, raster); + if (raster->type == CAIRO_SURFACE_TYPE_IMAGE) + return; + } + } + + if (!_cairo_pattern_is_clear (source) && !_cairo_pattern_is_opaque (source, NULL)) + surface->has_bilevel_alpha = FALSE; +} + +static cairo_status_t +_cairo_recording_surface_replay_internal (cairo_recording_surface_t *surface, + cairo_recording_surface_replay_params_t *params) +{ + cairo_surface_wrapper_t wrapper; + cairo_command_t **elements; + cairo_recording_regions_array_t *regions_array = NULL; + cairo_recording_region_element_t *region_elements = NULL; + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + cairo_rectangle_int_t extents; + cairo_bool_t use_indices = FALSE; + const cairo_rectangle_int_t *r; + unsigned int i, num_elements; + + if (unlikely (surface->base.status)) + return surface->base.status; + + if (unlikely (params->target->status)) + return params->target->status; + + if (unlikely (surface->base.finished)) + return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED); + + if (surface->base.is_clear) + return CAIRO_STATUS_SUCCESS; + + assert (_cairo_surface_is_recording (&surface->base)); + + if (params->regions_id != 0) { + regions_array = _cairo_recording_surface_region_array_find (surface, params->regions_id); + assert (regions_array != NULL); + } + + _cairo_surface_wrapper_init (&wrapper, params->target); + if (params->surface_extents) + _cairo_surface_wrapper_intersect_extents (&wrapper, params->surface_extents); + r = &_cairo_unbounded_rectangle; + if (! surface->unbounded && !params->surface_is_unbounded) { + _cairo_surface_wrapper_intersect_extents (&wrapper, &surface->extents); + r = &surface->extents; + } + _cairo_surface_wrapper_set_inverse_transform (&wrapper, params->surface_transform); + _cairo_surface_wrapper_set_clip (&wrapper, params->target_clip); + + if (params->foreground_color) { + params->target->foreground_source = _cairo_pattern_create_solid (params->foreground_color); + params->target->foreground_used = FALSE; + } + + /* Compute the extents of the target clip in recorded device space */ + if (! _cairo_surface_wrapper_get_target_extents (&wrapper, params->surface_is_unbounded, &extents)) + goto done; + + surface->has_bilevel_alpha = TRUE; + surface->has_only_op_over = TRUE; + + num_elements = surface->commands.num_elements; + if (regions_array) { + if (params->type == CAIRO_RECORDING_CREATE_REGIONS) { + /* Re-running create regions with the same region id is not supported. */ + assert (_cairo_array_num_elements (®ions_array->regions) == 0); + void *array_elems; + status = _cairo_array_allocate (®ions_array->regions, num_elements, &array_elems); + if (unlikely (status)) + return status; + + /* Set regions to CAIRO_RECORDING_REGION_ALL and ids to 0 */ + memset (array_elems, 0, num_elements * sizeof (cairo_recording_region_element_t)); + } else { + assert (_cairo_array_num_elements (®ions_array->regions) == num_elements); + } + } + + elements = _cairo_array_index (&surface->commands, 0); + if (regions_array) + region_elements = _cairo_array_index (®ions_array->regions, 0); + + if (!params->replay_all && (extents.width < r->width || extents.height < r->height)) { + num_elements = + _cairo_recording_surface_get_visible_commands (surface, &extents); + use_indices = num_elements != surface->commands.num_elements; + } + + cairo_bool_t target_is_analysis = _cairo_surface_is_analysis (params->target); + + for (i = 0; i < num_elements; i++) { + cairo_command_t *command = elements[use_indices ? surface->indices[i] : i]; + cairo_recording_region_element_t *region_element = NULL; + unsigned int source_region_id = 0; + unsigned int mask_region_id = 0; + + if (region_elements) + region_element = ®ion_elements[use_indices ? surface->indices[i] : i]; + + if (region_element && params->type == CAIRO_RECORDING_REPLAY_REGION && + region_element->region != params->region) + { + continue; + } + + if (! _cairo_rectangle_intersects (&extents, &command->header.extents)) { + if (command->header.type != CAIRO_COMMAND_TAG) + continue; + } + + + if (params->target->backend->command_id) { + status = params->target->backend->command_id (params->target, params->regions_id, i); + if (unlikely (status)) + return status; + } + + switch (command->header.type) { + case CAIRO_COMMAND_PAINT: + if (region_element) + source_region_id = region_element->source_id; + + status = _cairo_surface_wrapper_paint (&wrapper, + command->header.op, + &command->paint.source.base, + source_region_id, + command->header.clip); + if (params->type == CAIRO_RECORDING_CREATE_REGIONS) { + _cairo_recording_surface_merge_source_attributes (surface, + command->header.op, + &command->paint.source.base); + if (region_element && target_is_analysis) + region_element->source_id = _cairo_analysis_surface_get_source_region_id (params->target); + } + break; + + case CAIRO_COMMAND_MASK: + if (region_element) { + source_region_id = region_element->source_id; + mask_region_id = region_element->mask_id; + } + + status = _cairo_surface_wrapper_mask (&wrapper, + command->header.op, + &command->mask.source.base, + source_region_id, + &command->mask.mask.base, + mask_region_id, + command->header.clip); + if (params->type == CAIRO_RECORDING_CREATE_REGIONS) { + _cairo_recording_surface_merge_source_attributes (surface, + command->header.op, + &command->mask.source.base); + _cairo_recording_surface_merge_source_attributes (surface, + command->header.op, + &command->mask.mask.base); + if (region_element && target_is_analysis) { + region_element->source_id = _cairo_analysis_surface_get_source_region_id (params->target); + region_element->mask_id = _cairo_analysis_surface_get_mask_region_id (params->target); + } + } + break; + + case CAIRO_COMMAND_STROKE: + if (region_element) + source_region_id = region_element->source_id; + + status = _cairo_surface_wrapper_stroke (&wrapper, + command->header.op, + &command->stroke.source.base, + source_region_id, + &command->stroke.path, + &command->stroke.style, + &command->stroke.ctm, + &command->stroke.ctm_inverse, + command->stroke.tolerance, + command->stroke.antialias, + command->header.clip); + if (params->type == CAIRO_RECORDING_CREATE_REGIONS) { + _cairo_recording_surface_merge_source_attributes (surface, + command->header.op, + &command->stroke.source.base); + if (region_element && target_is_analysis) + region_element->source_id = _cairo_analysis_surface_get_source_region_id (params->target); + } + break; + + case CAIRO_COMMAND_FILL: + status = CAIRO_INT_STATUS_UNSUPPORTED; + if (region_element) + source_region_id = region_element->source_id; + + if (_cairo_surface_wrapper_has_fill_stroke (&wrapper)) { + cairo_command_t *stroke_command = NULL; + cairo_recording_region_element_t *stroke_region_element = NULL; + unsigned stroke_region_id = 0; + + /* The analysis surface does not implement + * fill_stroke. When creating regions the fill and + * stroke commands are tested separately. + */ + if (params->type != CAIRO_RECORDING_CREATE_REGIONS && i < num_elements - 1) { + stroke_command = elements[i + 1]; + if (region_elements) + stroke_region_element = ®ion_elements[i + 1]; + } + + if (stroke_region_element) + stroke_region_id = stroke_region_element->source_id; + + if (stroke_command && stroke_region_element && + params->type == CAIRO_RECORDING_REPLAY_REGION && + params->region != CAIRO_RECORDING_REGION_ALL) + { + if (stroke_region_element->region != params->region) + stroke_command = NULL; + } + + if (stroke_command != NULL && + stroke_command->header.type == CAIRO_COMMAND_STROKE && + _cairo_path_fixed_equal (&command->fill.path, + &stroke_command->stroke.path) && + _cairo_clip_equal (command->header.clip, + stroke_command->header.clip)) + { + status = _cairo_surface_wrapper_fill_stroke (&wrapper, + command->header.op, + &command->fill.source.base, + source_region_id, + command->fill.fill_rule, + command->fill.tolerance, + command->fill.antialias, + &command->fill.path, + stroke_command->header.op, + &stroke_command->stroke.source.base, + stroke_region_id, + &stroke_command->stroke.style, + &stroke_command->stroke.ctm, + &stroke_command->stroke.ctm_inverse, + stroke_command->stroke.tolerance, + stroke_command->stroke.antialias, + command->header.clip); + if (params->type == CAIRO_RECORDING_CREATE_REGIONS) { + _cairo_recording_surface_merge_source_attributes (surface, + command->header.op, + &command->fill.source.base); + _cairo_recording_surface_merge_source_attributes (surface, + command->header.op, + &command->stroke.source.base); + } + i++; + } + } + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + status = _cairo_surface_wrapper_fill (&wrapper, + command->header.op, + &command->fill.source.base, + source_region_id, + &command->fill.path, + command->fill.fill_rule, + command->fill.tolerance, + command->fill.antialias, + command->header.clip); + if (params->type == CAIRO_RECORDING_CREATE_REGIONS) { + _cairo_recording_surface_merge_source_attributes (surface, + command->header.op, + &command->fill.source.base); + if (region_element && target_is_analysis) + region_element->source_id = _cairo_analysis_surface_get_source_region_id (params->target); + } + } + break; + + case CAIRO_COMMAND_SHOW_TEXT_GLYPHS: + if (region_element) + source_region_id = region_element->source_id; + + status = _cairo_surface_wrapper_show_text_glyphs (&wrapper, + command->header.op, + &command->show_text_glyphs.source.base, + source_region_id, + command->show_text_glyphs.utf8, command->show_text_glyphs.utf8_len, + command->show_text_glyphs.glyphs, command->show_text_glyphs.num_glyphs, + command->show_text_glyphs.clusters, command->show_text_glyphs.num_clusters, + command->show_text_glyphs.cluster_flags, + command->show_text_glyphs.scaled_font, + command->header.clip); + if (params->type == CAIRO_RECORDING_CREATE_REGIONS) { + _cairo_recording_surface_merge_source_attributes (surface, + command->header.op, + &command->show_text_glyphs.source.base); + if (region_element && target_is_analysis) + region_element->source_id = _cairo_analysis_surface_get_source_region_id (params->target); + + } + break; + + case CAIRO_COMMAND_TAG: + status = _cairo_surface_wrapper_tag (&wrapper, + command->tag.begin, + command->tag.tag_name, + command->tag.attributes); + break; + + default: + ASSERT_NOT_REACHED; + } + + /* It's possible that a degenerate clip caused the command to end up doing nothing when replayed. */ + if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO)) + status = CAIRO_INT_STATUS_SUCCESS; + + if (params->type == CAIRO_RECORDING_CREATE_REGIONS && region_element) { + if (status == CAIRO_INT_STATUS_SUCCESS) { + region_element->region = CAIRO_RECORDING_REGION_NATIVE; + } else if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) { + region_element->region = CAIRO_RECORDING_REGION_IMAGE_FALLBACK; + status = CAIRO_INT_STATUS_SUCCESS; + } else { + assert (_cairo_int_status_is_error (status)); + } + } + + if (unlikely (status)) + break; + } + +done: + if (params->foreground_color) { + cairo_pattern_destroy (params->target->foreground_source); + params->target->foreground_source = NULL; + params->foreground_used = params->target->foreground_used; + } + + _cairo_surface_wrapper_fini (&wrapper); + return _cairo_surface_set_error (&surface->base, status); +} + +cairo_status_t +_cairo_recording_surface_replay_one (cairo_recording_surface_t *surface, + long unsigned index, + cairo_surface_t *target) +{ + cairo_surface_wrapper_t wrapper; + cairo_command_t **elements, *command; + cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; + + if (unlikely (surface->base.status)) + return surface->base.status; + + if (unlikely (target->status)) + return target->status; + + if (unlikely (surface->base.finished)) + return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED); + + assert (_cairo_surface_is_recording (&surface->base)); + + /* XXX + * Use a surface wrapper because we may want to do transformed + * replay in the future. + */ + _cairo_surface_wrapper_init (&wrapper, target); + + if (index > surface->commands.num_elements) + return _cairo_error (CAIRO_STATUS_READ_ERROR); + + elements = _cairo_array_index (&surface->commands, 0); + command = elements[index]; + switch (command->header.type) { + case CAIRO_COMMAND_PAINT: + status = _cairo_surface_wrapper_paint (&wrapper, + command->header.op, + &command->paint.source.base, + 0, + command->header.clip); + break; + + case CAIRO_COMMAND_MASK: + status = _cairo_surface_wrapper_mask (&wrapper, + command->header.op, + &command->mask.source.base, + 0, + &command->mask.mask.base, + 0, + command->header.clip); + break; + + case CAIRO_COMMAND_STROKE: + status = _cairo_surface_wrapper_stroke (&wrapper, + command->header.op, + &command->stroke.source.base, + 0, + &command->stroke.path, + &command->stroke.style, + &command->stroke.ctm, + &command->stroke.ctm_inverse, + command->stroke.tolerance, + command->stroke.antialias, + command->header.clip); + break; + + case CAIRO_COMMAND_FILL: + status = _cairo_surface_wrapper_fill (&wrapper, + command->header.op, + &command->fill.source.base, + 0, + &command->fill.path, + command->fill.fill_rule, + command->fill.tolerance, + command->fill.antialias, + command->header.clip); + break; + + case CAIRO_COMMAND_SHOW_TEXT_GLYPHS: + status = _cairo_surface_wrapper_show_text_glyphs (&wrapper, + command->header.op, + &command->show_text_glyphs.source.base, + 0, + command->show_text_glyphs.utf8, command->show_text_glyphs.utf8_len, + command->show_text_glyphs.glyphs, command->show_text_glyphs.num_glyphs, + command->show_text_glyphs.clusters, command->show_text_glyphs.num_clusters, + command->show_text_glyphs.cluster_flags, + command->show_text_glyphs.scaled_font, + command->header.clip); + break; + + case CAIRO_COMMAND_TAG: + status = _cairo_surface_wrapper_tag (&wrapper, + command->tag.begin, + command->tag.tag_name, + command->tag.attributes); + break; + + default: + ASSERT_NOT_REACHED; + } + + _cairo_surface_wrapper_fini (&wrapper); + return _cairo_surface_set_error (&surface->base, status); +} +/** + * _cairo_recording_surface_replay: + * @surface: the #cairo_recording_surface_t + * @target: a target #cairo_surface_t onto which to replay the operations + * @width_pixels: width of the surface, in pixels + * @height_pixels: height of the surface, in pixels + * + * A recording surface can be "replayed" against any target surface, + * after which the results in target will be identical to the results + * that would have been obtained if the original operations applied to + * the recording surface had instead been applied to the target surface. + **/ +cairo_status_t +_cairo_recording_surface_replay (cairo_surface_t *surface, + cairo_surface_t *target) +{ + cairo_recording_surface_replay_params_t params; + + params.surface_extents = NULL; + params.surface_transform = NULL; + params.target = target; + params.target_clip = NULL; + params.surface_is_unbounded = FALSE; + params.type = CAIRO_RECORDING_REPLAY; + params.region = CAIRO_RECORDING_REGION_ALL; + params.regions_id = 0; + params.foreground_color = NULL; + params.replay_all = FALSE; + + return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, ¶ms); +} + +cairo_status_t +_cairo_recording_surface_replay_with_foreground_color (cairo_surface_t *surface, + cairo_surface_t *target, + const cairo_color_t *foreground_color, + cairo_bool_t *foreground_used) +{ + cairo_recording_surface_replay_params_t params; + cairo_status_t status; + + params.surface_extents = NULL; + params.surface_transform = NULL; + params.target = target; + params.target_clip = NULL; + params.surface_is_unbounded = FALSE; + params.type = CAIRO_RECORDING_REPLAY; + params.region = CAIRO_RECORDING_REGION_ALL; + params.regions_id = 0; + params.foreground_color = foreground_color; + params.foreground_used = FALSE; + params.replay_all = FALSE; + + status = _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, ¶ms); + *foreground_used = params.foreground_used; + + return status; +} + +cairo_status_t +_cairo_recording_surface_replay_with_transform (cairo_surface_t *surface, + const cairo_matrix_t *surface_transform, + cairo_surface_t *target, + cairo_bool_t surface_is_unbounded, + cairo_bool_t replay_all) +{ + cairo_recording_surface_replay_params_t params; + + params.surface_extents = NULL; + params.surface_transform = surface_transform; + params.target = target; + params.target_clip = NULL; + params.surface_is_unbounded = surface_is_unbounded; + params.type = CAIRO_RECORDING_REPLAY; + params.region = CAIRO_RECORDING_REGION_ALL; + params.regions_id = 0; + params.foreground_color = NULL; + params.replay_all = replay_all; + + return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, ¶ms); +} + +cairo_status_t +_cairo_recording_surface_replay_with_clip (cairo_surface_t *surface, + const cairo_matrix_t *surface_transform, + cairo_surface_t *target, + const cairo_clip_t *target_clip) +{ + cairo_recording_surface_replay_params_t params; + + params.surface_extents = NULL; + params.surface_transform = surface_transform; + params.target = target; + params.target_clip = target_clip; + params.surface_is_unbounded = FALSE; + params.type = CAIRO_RECORDING_REPLAY; + params.region = CAIRO_RECORDING_REGION_ALL; + params.regions_id = 0; + params.foreground_color = NULL; + params.replay_all = FALSE; + + return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, ¶ms); +} + +/* Replay recording to surface. When the return status of each operation is + * one of %CAIRO_STATUS_SUCCESS, %CAIRO_INT_STATUS_UNSUPPORTED, or + * %CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY the status of each operation + * will be stored in the recording surface. Any other status will abort the + * replay and return the status. + */ +cairo_status_t +_cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface, + unsigned int regions_id, + const cairo_matrix_t *surface_transform, + cairo_surface_t *target, + cairo_bool_t surface_is_unbounded, + cairo_bool_t replay_all) +{ + cairo_recording_surface_replay_params_t params; + + params.surface_extents = NULL; + params.surface_transform = surface_transform; + params.target = target; + params.target_clip = NULL; + params.surface_is_unbounded = surface_is_unbounded; + params.type = CAIRO_RECORDING_CREATE_REGIONS; + params.region = CAIRO_RECORDING_REGION_ALL; + params.regions_id = regions_id; + params.foreground_color = NULL; + params.replay_all = replay_all; + + return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, ¶ms); +} + +cairo_status_t +_cairo_recording_surface_replay_region (cairo_surface_t *surface, + unsigned int regions_id, + const cairo_rectangle_int_t *surface_extents, + cairo_surface_t *target, + cairo_recording_region_type_t region) +{ + cairo_recording_surface_replay_params_t params; + + params.surface_extents = surface_extents; + params.surface_transform = NULL; + params.target = target; + params.target_clip = NULL; + params.surface_is_unbounded = FALSE; + params.type = CAIRO_RECORDING_REPLAY_REGION; + params.region = region; + params.regions_id = regions_id; + params.foreground_color = NULL; + params.replay_all = FALSE; + + return _cairo_recording_surface_replay_internal ((cairo_recording_surface_t *) surface, ¶ms); +} + +static cairo_status_t +_recording_surface_get_ink_bbox (cairo_recording_surface_t *surface, + cairo_box_t *bbox, + const cairo_matrix_t *transform) +{ + cairo_surface_t *null_surface; + cairo_surface_t *analysis_surface; + cairo_status_t status; + + null_surface = _cairo_null_surface_create (surface->base.content); + analysis_surface = _cairo_analysis_surface_create (null_surface, FALSE); + cairo_surface_destroy (null_surface); + + status = analysis_surface->status; + if (unlikely (status)) + return status; + + if (transform != NULL) + _cairo_analysis_surface_set_ctm (analysis_surface, transform); + + status = _cairo_recording_surface_replay (&surface->base, analysis_surface); + _cairo_analysis_surface_get_bounding_box (analysis_surface, bbox); + cairo_surface_destroy (analysis_surface); + + return status; +} + +/** + * cairo_recording_surface_ink_extents: + * @surface: a #cairo_recording_surface_t + * @x0: the x-coordinate of the top-left of the ink bounding box + * @y0: the y-coordinate of the top-left of the ink bounding box + * @width: the width of the ink bounding box + * @height: the height of the ink bounding box + * + * Measures the extents of the operations stored within the recording-surface. + * This is useful to compute the required size of an image surface (or + * equivalent) into which to replay the full sequence of drawing operations. + * + * Since: 1.10 + **/ +void +cairo_recording_surface_ink_extents (cairo_surface_t *surface, + double *x0, + double *y0, + double *width, + double *height) +{ + cairo_status_t status; + cairo_box_t bbox; + + memset (&bbox, 0, sizeof (bbox)); + + if (surface->status || ! _cairo_surface_is_recording (surface)) { + _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + goto DONE; + } + + status = _recording_surface_get_ink_bbox ((cairo_recording_surface_t *) surface, + &bbox, + NULL); + if (unlikely (status)) + status = _cairo_surface_set_error (surface, status); + +DONE: + if (x0) + *x0 = _cairo_fixed_to_double (bbox.p1.x); + if (y0) + *y0 = _cairo_fixed_to_double (bbox.p1.y); + if (width) + *width = _cairo_fixed_to_double (bbox.p2.x - bbox.p1.x); + if (height) + *height = _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y); +} + +cairo_status_t +_cairo_recording_surface_get_bbox (cairo_recording_surface_t *surface, + cairo_box_t *bbox, + const cairo_matrix_t *transform) +{ + if (! surface->unbounded) { + _cairo_box_from_rectangle (bbox, &surface->extents); + if (transform != NULL) + _cairo_matrix_transform_bounding_box_fixed (transform, bbox, NULL); + + return CAIRO_STATUS_SUCCESS; + } + + return _recording_surface_get_ink_bbox (surface, bbox, transform); +} + +cairo_status_t +_cairo_recording_surface_get_ink_bbox (cairo_recording_surface_t *surface, + cairo_box_t *bbox, + const cairo_matrix_t *transform) +{ + return _recording_surface_get_ink_bbox (surface, bbox, transform); +} + +/** + * cairo_recording_surface_get_extents: + * @surface: a #cairo_recording_surface_t + * @extents: the #cairo_rectangle_t to be assigned the extents + * + * Get the extents of the recording-surface. + * + * Return value: %TRUE if the surface is bounded, of recording type, and + * not in an error state, otherwise %FALSE + * + * Since: 1.12 + **/ +cairo_bool_t +cairo_recording_surface_get_extents (cairo_surface_t *surface, + cairo_rectangle_t *extents) +{ + cairo_recording_surface_t *record; + + if (surface->status || ! _cairo_surface_is_recording (surface)) { + _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + return FALSE; + } + + record = (cairo_recording_surface_t *)surface; + if (record->unbounded) + return FALSE; + + *extents = record->extents_pixels; + return TRUE; +} + +cairo_bool_t +_cairo_recording_surface_has_only_bilevel_alpha (cairo_recording_surface_t *surface) +{ + return surface->has_bilevel_alpha; +} + +cairo_bool_t +_cairo_recording_surface_has_only_op_over (cairo_recording_surface_t *surface) +{ + return surface->has_only_op_over; +} + +cairo_bool_t +_cairo_recording_surface_has_tags (cairo_surface_t *surface) +{ + cairo_recording_surface_t *record; + + if (surface->status || ! _cairo_surface_is_recording (surface)) { + _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + return FALSE; + } + + record = (cairo_recording_surface_t *)surface; + + return record->has_tags; +} + +static void +print_indent (FILE *file, int indent) +{ + fprintf (file, "%*s", indent * 2, ""); +} + +static void +print_pattern (FILE *file, + const cairo_pattern_t *pattern, + unsigned int region_id, + int indent, + cairo_bool_t recurse) +{ + switch (pattern->type) { + case CAIRO_PATTERN_TYPE_SOLID: { + cairo_solid_pattern_t *p = (cairo_solid_pattern_t *) pattern; + if (pattern->is_foreground_marker) { + fprintf (file, "solid foreground\n"); + } else { + fprintf (file, "solid rgba: %f %f %f %f\n", + p->color.red, + p->color.green, + p->color.blue, + p->color.alpha); + } + } break; + case CAIRO_PATTERN_TYPE_SURFACE: { + cairo_surface_pattern_t *p = (cairo_surface_pattern_t *) pattern; + fprintf (file, "surface "); + if (p->surface->type == CAIRO_SURFACE_TYPE_RECORDING) { + fprintf (file, "recording id: %d\n", p->surface->unique_id); + if (recurse) { + _cairo_debug_print_recording_surface (file, p->surface, + region_id, + indent + 1, recurse); + } + } else if (p->surface->type == CAIRO_SURFACE_TYPE_IMAGE) { + cairo_image_surface_t *image = (cairo_image_surface_t *)p->surface; + fprintf (file, "image format: "); + switch (image->format) { + case CAIRO_FORMAT_INVALID: fputs ("INVALID", file); break; + case CAIRO_FORMAT_ARGB32: fputs ("ARGB32", file); break; + case CAIRO_FORMAT_RGB24: fputs ("RGB24", file); break; + case CAIRO_FORMAT_A8: fputs ("A8", file); break; + case CAIRO_FORMAT_A1: fputs ("A1", file); break; + case CAIRO_FORMAT_RGB16_565: fputs ("RGB16_565", file); break; + case CAIRO_FORMAT_RGB30: fputs ("RGB30", file); break; + case CAIRO_FORMAT_RGB96F: fputs ("RGB96F", file); break; + case CAIRO_FORMAT_RGBA128F: fputs ("RGBA128F", file); break; + } + fprintf (file, " width: %d height: %d\n", image->width, image->height); + } else { + fprintf (file, "type %d\n", p->surface->type); + } + } break; + case CAIRO_PATTERN_TYPE_LINEAR: + fprintf (file, "linear\n"); + break; + case CAIRO_PATTERN_TYPE_RADIAL: + fprintf (file, "radial\n"); + break; + case CAIRO_PATTERN_TYPE_MESH: + fprintf (file, "mesh\n"); + break; + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + fprintf (file, "raster\n"); + break; + } +} + +void +_cairo_debug_print_recording_surface (FILE *file, + cairo_surface_t *surface, + unsigned int regions_id, + int indent, + cairo_bool_t recurse) +{ + cairo_command_t **elements; + cairo_recording_region_element_t *region_elements = NULL; + unsigned int i, num_elements; + cairo_recording_surface_t *recording_surface; + cairo_surface_t *free_me = NULL; + char common[100]; + + if (_cairo_surface_is_snapshot (surface)) + free_me = surface = _cairo_surface_snapshot_get_target (surface); + + assert (_cairo_surface_is_recording (surface)); + recording_surface = (cairo_recording_surface_t *)surface; + + print_indent (file, indent); + indent++; + fprintf(file, "recording surface id: %d regions id: %d\n", recording_surface->base.unique_id, regions_id); + num_elements = recording_surface->commands.num_elements; + elements = _cairo_array_index (&recording_surface->commands, 0); + + if (regions_id != 0) { + cairo_recording_regions_array_t *regions_array; + regions_array = _cairo_recording_surface_region_array_find (recording_surface, regions_id); + assert (regions_array != NULL); + assert (_cairo_array_num_elements (®ions_array->regions) == num_elements); + region_elements = _cairo_array_index (®ions_array->regions, 0); + } + + for (i = 0; i < num_elements; i++) { + cairo_command_t *command = elements[i]; + unsigned int source_region_id = 0; + unsigned int mask_region_id = 0; + + common[0] = 0; + if (region_elements) { + cairo_recording_region_element_t *region_element = ®ion_elements[i]; + strcpy (common, "region: "); + switch (region_element->region) { + case CAIRO_RECORDING_REGION_ALL: strcat (common, "all"); break; + case CAIRO_RECORDING_REGION_NATIVE: strcat (common, "native"); break; + case CAIRO_RECORDING_REGION_IMAGE_FALLBACK: strcat (common, "fallback"); break; + } + source_region_id = region_element->source_id; + mask_region_id = region_element->mask_id; + } + sprintf (common + strlen(common), " op: %s", _cairo_debug_operator_to_string (command->header.op)); + + switch (command->header.type) { + case CAIRO_COMMAND_PAINT: + print_indent (file, indent); + fprintf(file, "%d PAINT %s source: ", i, common); + print_pattern (file, &command->paint.source.base, source_region_id, indent + 1, recurse); + break; + + case CAIRO_COMMAND_MASK: + print_indent (file, indent); + fprintf(file, "%d MASK %s\n", i, common); + print_indent (file, indent + 1); + fprintf(file, "source: "); + print_pattern (file, &command->mask.source.base, source_region_id, indent + 1, recurse); + print_indent (file, indent + 1); + fprintf(file, "mask: "); + print_pattern (file, &command->mask.mask.base, mask_region_id, indent + 1, recurse); + break; + + case CAIRO_COMMAND_STROKE: + print_indent (file, indent); + fprintf(file, "%d STROKE %s source:", i, common); + print_pattern (file, &command->stroke.source.base, source_region_id, indent + 1, recurse); + break; + + case CAIRO_COMMAND_FILL: + print_indent (file, indent); + fprintf(file, "%d FILL %s source: ", i, common); + print_pattern (file, &command->fill.source.base, source_region_id, indent + 1, recurse); + break; + + case CAIRO_COMMAND_SHOW_TEXT_GLYPHS: + print_indent (file, indent); + fprintf(file, "%d SHOW_TEXT_GLYPHS %s font_type: ", i, common); + switch (command->show_text_glyphs.scaled_font->backend->type) { + case CAIRO_FONT_TYPE_TOY: fputs ("toy", file); break; + case CAIRO_FONT_TYPE_FT: fputs ("ft", file); break; + case CAIRO_FONT_TYPE_WIN32: fputs ("win32", file); break; + case CAIRO_FONT_TYPE_QUARTZ: fputs ("quartz", file); break; + case CAIRO_FONT_TYPE_USER: fputs ("user", file); break; + case CAIRO_FONT_TYPE_DWRITE: fputs ("dwrite", file); break; + } + fprintf (file, " glyphs:"); + for (unsigned j = 0; j < command->show_text_glyphs.num_glyphs; j++) + fprintf (file, " %ld", command->show_text_glyphs.glyphs[j].index); + fprintf (file, " source:"); + print_pattern (file, &command->show_text_glyphs.source.base, source_region_id, indent + 1, recurse); + break; + + case CAIRO_COMMAND_TAG: + print_indent (file, indent); + fprintf(file, "%d %s %s '%s'\n", + i, + command->tag.begin ? "BEGIN TAG" : "END TAG", + command->tag.tag_name, command->tag.attributes); + break; + + default: + ASSERT_NOT_REACHED; + } + } + cairo_surface_destroy (free_me); +} diff --git a/local/recipes/libs/cairo/source/src/cairo-rectangle.c b/local/recipes/libs/cairo/source/src/cairo-rectangle.c new file mode 100644 index 0000000000..2d51d7b10a --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-rectangle.c @@ -0,0 +1,299 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2006 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + */ + +#include "cairoint.h" + +#include "cairo-box-inline.h" + +const cairo_rectangle_int_t _cairo_empty_rectangle = { 0, 0, 0, 0 }; +const cairo_rectangle_int_t _cairo_unbounded_rectangle = { + CAIRO_RECT_INT_MIN, CAIRO_RECT_INT_MIN, + CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN, + CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN, +}; + +cairo_private void +_cairo_box_from_doubles (cairo_box_t *box, + double *x1, double *y1, + double *x2, double *y2) +{ + box->p1.x = _cairo_fixed_from_double (*x1); + box->p1.y = _cairo_fixed_from_double (*y1); + box->p2.x = _cairo_fixed_from_double (*x2); + box->p2.y = _cairo_fixed_from_double (*y2); +} + +cairo_private void +_cairo_box_to_doubles (const cairo_box_t *box, + double *x1, double *y1, + double *x2, double *y2) +{ + *x1 = _cairo_fixed_to_double (box->p1.x); + *y1 = _cairo_fixed_to_double (box->p1.y); + *x2 = _cairo_fixed_to_double (box->p2.x); + *y2 = _cairo_fixed_to_double (box->p2.y); +} + +void +_cairo_box_from_rectangle (cairo_box_t *box, + const cairo_rectangle_int_t *rect) +{ + box->p1.x = _cairo_fixed_from_int (rect->x); + box->p1.y = _cairo_fixed_from_int (rect->y); + box->p2.x = _cairo_fixed_from_int (rect->x + rect->width); + box->p2.y = _cairo_fixed_from_int (rect->y + rect->height); +} + +void +_cairo_boxes_get_extents (const cairo_box_t *boxes, + int num_boxes, + cairo_box_t *extents) +{ + assert (num_boxes > 0); + *extents = *boxes; + while (--num_boxes) + _cairo_box_add_box (extents, ++boxes); +} + +/* XXX We currently have a confusing mix of boxes and rectangles as + * exemplified by this function. A #cairo_box_t is a rectangular area + * represented by the coordinates of the upper left and lower right + * corners, expressed in fixed point numbers. A #cairo_rectangle_int_t is + * also a rectangular area, but represented by the upper left corner + * and the width and the height, as integer numbers. + * + * This function converts a #cairo_box_t to a #cairo_rectangle_int_t by + * increasing the area to the nearest integer coordinates. We should + * standardize on #cairo_rectangle_fixed_t and #cairo_rectangle_int_t, and + * this function could be renamed to the more reasonable + * _cairo_rectangle_fixed_round. + */ + +void +_cairo_box_round_to_rectangle (const cairo_box_t *box, + cairo_rectangle_int_t *rectangle) +{ + rectangle->x = _cairo_fixed_integer_floor (box->p1.x); + rectangle->y = _cairo_fixed_integer_floor (box->p1.y); + rectangle->width = _cairo_fixed_integer_ceil (box->p2.x) - rectangle->x; + rectangle->height = _cairo_fixed_integer_ceil (box->p2.y) - rectangle->y; +} + +cairo_bool_t +_cairo_rectangle_intersect (cairo_rectangle_int_t *dst, + const cairo_rectangle_int_t *src) +{ + int x1, y1, x2, y2; + + x1 = MAX (dst->x, src->x); + y1 = MAX (dst->y, src->y); + /* Beware the unsigned promotion, fortunately we have bits to spare + * as (CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN) < UINT_MAX + */ + x2 = MIN (dst->x + (int) dst->width, src->x + (int) src->width); + y2 = MIN (dst->y + (int) dst->height, src->y + (int) src->height); + + if (x1 >= x2 || y1 >= y2) { + dst->x = 0; + dst->y = 0; + dst->width = 0; + dst->height = 0; + + return FALSE; + } else { + dst->x = x1; + dst->y = y1; + dst->width = x2 - x1; + dst->height = y2 - y1; + + return TRUE; + } +} + +/* Extends the dst rectangle to also contain src. + * If one of the rectangles is empty, the result is undefined + */ +void +_cairo_rectangle_union (cairo_rectangle_int_t *dst, + const cairo_rectangle_int_t *src) +{ + int x1, y1, x2, y2; + + x1 = MIN (dst->x, src->x); + y1 = MIN (dst->y, src->y); + /* Beware the unsigned promotion, fortunately we have bits to spare + * as (CAIRO_RECT_INT_MAX - CAIRO_RECT_INT_MIN) < UINT_MAX + */ + x2 = MAX (dst->x + (int) dst->width, src->x + (int) src->width); + y2 = MAX (dst->y + (int) dst->height, src->y + (int) src->height); + + dst->x = x1; + dst->y = y1; + dst->width = x2 - x1; + dst->height = y2 - y1; +} + +#define P1x (line->p1.x) +#define P1y (line->p1.y) +#define P2x (line->p2.x) +#define P2y (line->p2.y) +#define B1x (box->p1.x) +#define B1y (box->p1.y) +#define B2x (box->p2.x) +#define B2y (box->p2.y) + +/* + * Check whether any part of line intersects box. This function essentially + * computes whether the ray starting at line->p1 in the direction of line->p2 + * intersects the box before it reaches p2. Normally, this is done + * by dividing by the lengths of the line projected onto each axis. Because + * we're in fixed point, this function does a bit more work to avoid having to + * do the division -- we don't care about the actual intersection point, so + * it's of no interest to us. + */ + +cairo_bool_t +_cairo_box_intersects_line_segment (const cairo_box_t *box, cairo_line_t *line) +{ + cairo_fixed_t t1=0, t2=0, t3=0, t4=0; + cairo_int64_t t1y, t2y, t3x, t4x; + + cairo_fixed_t xlen, ylen; + + if (_cairo_box_contains_point (box, &line->p1) || + _cairo_box_contains_point (box, &line->p2)) + return TRUE; + + xlen = P2x - P1x; + ylen = P2y - P1y; + + if (xlen) { + if (xlen > 0) { + t1 = B1x - P1x; + t2 = B2x - P1x; + } else { + t1 = P1x - B2x; + t2 = P1x - B1x; + xlen = - xlen; + } + + if ((t1 < 0 || t1 > xlen) && + (t2 < 0 || t2 > xlen)) + return FALSE; + } else { + /* Fully vertical line -- check that X is in bounds */ + if (P1x < B1x || P1x > B2x) + return FALSE; + } + + if (ylen) { + if (ylen > 0) { + t3 = B1y - P1y; + t4 = B2y - P1y; + } else { + t3 = P1y - B2y; + t4 = P1y - B1y; + ylen = - ylen; + } + + if ((t3 < 0 || t3 > ylen) && + (t4 < 0 || t4 > ylen)) + return FALSE; + } else { + /* Fully horizontal line -- check Y */ + if (P1y < B1y || P1y > B2y) + return FALSE; + } + + /* If we had a horizontal or vertical line, then it's already been checked */ + if (P1x == P2x || P1y == P2y) + return TRUE; + + /* Check overlap. Note that t1 < t2 and t3 < t4 here. */ + t1y = _cairo_int32x32_64_mul (t1, ylen); + t2y = _cairo_int32x32_64_mul (t2, ylen); + t3x = _cairo_int32x32_64_mul (t3, xlen); + t4x = _cairo_int32x32_64_mul (t4, xlen); + + if (_cairo_int64_lt(t1y, t4x) && + _cairo_int64_lt(t3x, t2y)) + return TRUE; + + return FALSE; +} + +static cairo_status_t +_cairo_box_add_spline_point (void *closure, + const cairo_point_t *point, + const cairo_slope_t *tangent) +{ + _cairo_box_add_point (closure, point); + + return CAIRO_STATUS_SUCCESS; +} + +/* assumes a has been previously added */ +void +_cairo_box_add_curve_to (cairo_box_t *extents, + const cairo_point_t *a, + const cairo_point_t *b, + const cairo_point_t *c, + const cairo_point_t *d) +{ + _cairo_box_add_point (extents, d); + if (!_cairo_box_contains_point (extents, b) || + !_cairo_box_contains_point (extents, c)) + { + cairo_status_t status; + + status = _cairo_spline_bound (_cairo_box_add_spline_point, + extents, a, b, c, d); + assert (status == CAIRO_STATUS_SUCCESS); + } +} + +void +_cairo_rectangle_int_from_double (cairo_rectangle_int_t *recti, + const cairo_rectangle_t *rectf) +{ + recti->x = floor (rectf->x); + recti->y = floor (rectf->y); + recti->width = ceil (rectf->x + rectf->width) - floor (rectf->x); + recti->height = ceil (rectf->y + rectf->height) - floor (rectf->y); +} diff --git a/local/recipes/libs/cairo/source/src/cairo-rectangular-scan-converter.c b/local/recipes/libs/cairo/source/src/cairo-rectangular-scan-converter.c new file mode 100644 index 0000000000..e353b34e85 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-rectangular-scan-converter.c @@ -0,0 +1,791 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * Contributor(s): + * Chris Wilson + */ + +#include "cairoint.h" + +#include "cairo-combsort-inline.h" +#include "cairo-error-private.h" +#include "cairo-freelist-private.h" +#include "cairo-list-private.h" +#include "cairo-spans-private.h" + +#include + +typedef struct _rectangle { + struct _rectangle *next, *prev; + cairo_fixed_t left, right; + cairo_fixed_t top, bottom; + int32_t top_y, bottom_y; + int dir; +} rectangle_t; + +#define UNROLL3(x) x x x + +/* the parent is always given by index/2 */ +#define PQ_PARENT_INDEX(i) ((i) >> 1) +#define PQ_FIRST_ENTRY 1 + +/* left and right children are index * 2 and (index * 2) +1 respectively */ +#define PQ_LEFT_CHILD_INDEX(i) ((i) << 1) + +typedef struct _pqueue { + int size, max_size; + + rectangle_t **elements; + rectangle_t *elements_embedded[1024]; +} pqueue_t; + +typedef struct { + rectangle_t **start; + pqueue_t stop; + rectangle_t head, tail; + rectangle_t *insert_cursor; + int32_t current_y; + int32_t xmin, xmax; + + struct coverage { + struct cell { + struct cell *prev, *next; + int x, covered, uncovered; + } head, tail, *cursor; + unsigned int count; + cairo_freepool_t pool; + } coverage; + + cairo_half_open_span_t spans_stack[CAIRO_STACK_ARRAY_LENGTH (cairo_half_open_span_t)]; + cairo_half_open_span_t *spans; + unsigned int num_spans; + unsigned int size_spans; + + jmp_buf jmpbuf; +} sweep_line_t; + +static inline int +rectangle_compare_start (const rectangle_t *a, + const rectangle_t *b) +{ + int cmp; + + cmp = a->top_y - b->top_y; + if (cmp) + return cmp; + + return a->left - b->left; +} + +static inline int +rectangle_compare_stop (const rectangle_t *a, + const rectangle_t *b) +{ + return a->bottom_y - b->bottom_y; +} + +static inline void +pqueue_init (pqueue_t *pq) +{ + pq->max_size = ARRAY_LENGTH (pq->elements_embedded); + pq->size = 0; + + pq->elements = pq->elements_embedded; + pq->elements[PQ_FIRST_ENTRY] = NULL; +} + +static inline void +pqueue_fini (pqueue_t *pq) +{ + if (pq->elements != pq->elements_embedded) + free (pq->elements); +} + +static cairo_bool_t +pqueue_grow (pqueue_t *pq) +{ + rectangle_t **new_elements; + pq->max_size *= 2; + + if (pq->elements == pq->elements_embedded) { + new_elements = _cairo_malloc_ab (pq->max_size, + sizeof (rectangle_t *)); + if (unlikely (new_elements == NULL)) + return FALSE; + + memcpy (new_elements, pq->elements_embedded, + sizeof (pq->elements_embedded)); + } else { + new_elements = _cairo_realloc_ab (pq->elements, + pq->max_size, + sizeof (rectangle_t *)); + if (unlikely (new_elements == NULL)) + return FALSE; + } + + pq->elements = new_elements; + return TRUE; +} + +static inline void +pqueue_push (sweep_line_t *sweep, rectangle_t *rectangle) +{ + rectangle_t **elements; + int i, parent; + + if (unlikely (sweep->stop.size + 1 == sweep->stop.max_size)) { + if (unlikely (! pqueue_grow (&sweep->stop))) + longjmp (sweep->jmpbuf, + _cairo_error (CAIRO_STATUS_NO_MEMORY)); + } + + elements = sweep->stop.elements; + for (i = ++sweep->stop.size; + i != PQ_FIRST_ENTRY && + rectangle_compare_stop (rectangle, + elements[parent = PQ_PARENT_INDEX (i)]) < 0; + i = parent) + { + elements[i] = elements[parent]; + } + + elements[i] = rectangle; +} + +static inline void +pqueue_pop (pqueue_t *pq) +{ + rectangle_t **elements = pq->elements; + rectangle_t *tail; + int child, i; + + tail = elements[pq->size--]; + if (pq->size == 0) { + elements[PQ_FIRST_ENTRY] = NULL; + return; + } + + for (i = PQ_FIRST_ENTRY; + (child = PQ_LEFT_CHILD_INDEX (i)) <= pq->size; + i = child) + { + if (child != pq->size && + rectangle_compare_stop (elements[child+1], + elements[child]) < 0) + { + child++; + } + + if (rectangle_compare_stop (elements[child], tail) >= 0) + break; + + elements[i] = elements[child]; + } + elements[i] = tail; +} + +static inline rectangle_t * +peek_stop (sweep_line_t *sweep) +{ + return sweep->stop.elements[PQ_FIRST_ENTRY]; +} + +CAIRO_COMBSORT_DECLARE (rectangle_sort, rectangle_t *, rectangle_compare_start) + +static void +sweep_line_init (sweep_line_t *sweep) +{ + sweep->head.left = INT_MIN; + sweep->head.next = &sweep->tail; + sweep->tail.left = INT_MAX; + sweep->tail.prev = &sweep->head; + sweep->insert_cursor = &sweep->tail; + + _cairo_freepool_init (&sweep->coverage.pool, sizeof (struct cell)); + + sweep->spans = sweep->spans_stack; + sweep->size_spans = ARRAY_LENGTH (sweep->spans_stack); + + sweep->coverage.head.prev = NULL; + sweep->coverage.head.x = INT_MIN; + sweep->coverage.tail.next = NULL; + sweep->coverage.tail.x = INT_MAX; + + pqueue_init (&sweep->stop); +} + +static void +sweep_line_fini (sweep_line_t *sweep) +{ + _cairo_freepool_fini (&sweep->coverage.pool); + pqueue_fini (&sweep->stop); + + if (sweep->spans != sweep->spans_stack) + free (sweep->spans); +} + +static inline void +add_cell (sweep_line_t *sweep, int x, int covered, int uncovered) +{ + struct cell *cell; + + cell = sweep->coverage.cursor; + if (cell->x > x) { + do { + UNROLL3({ + if (cell->prev->x < x) + break; + cell = cell->prev; + }) + } while (TRUE); + } else { + if (cell->x == x) + goto found; + + do { + UNROLL3({ + cell = cell->next; + if (cell->x >= x) + break; + }) + } while (TRUE); + } + + if (x != cell->x) { + struct cell *c; + + sweep->coverage.count++; + + c = _cairo_freepool_alloc (&sweep->coverage.pool); + if (unlikely (c == NULL)) { + longjmp (sweep->jmpbuf, + _cairo_error (CAIRO_STATUS_NO_MEMORY)); + } + + cell->prev->next = c; + c->prev = cell->prev; + c->next = cell; + cell->prev = c; + + c->x = x; + c->covered = 0; + c->uncovered = 0; + + cell = c; + } + +found: + cell->covered += covered; + cell->uncovered += uncovered; + sweep->coverage.cursor = cell; +} + +static inline void +_active_edges_to_spans (sweep_line_t *sweep) +{ + int32_t y = sweep->current_y; + rectangle_t *rectangle; + int coverage, prev_coverage; + int prev_x; + struct cell *cell; + + sweep->num_spans = 0; + if (sweep->head.next == &sweep->tail) + return; + + sweep->coverage.head.next = &sweep->coverage.tail; + sweep->coverage.tail.prev = &sweep->coverage.head; + sweep->coverage.cursor = &sweep->coverage.tail; + sweep->coverage.count = 0; + + /* XXX cell coverage only changes when a rectangle appears or + * disappears. Try only modifying coverage at such times. + */ + for (rectangle = sweep->head.next; + rectangle != &sweep->tail; + rectangle = rectangle->next) + { + int height; + int frac, i; + + if (y == rectangle->bottom_y) { + height = rectangle->bottom & CAIRO_FIXED_FRAC_MASK; + if (height == 0) + continue; + } else + height = CAIRO_FIXED_ONE; + if (y == rectangle->top_y) + height -= rectangle->top & CAIRO_FIXED_FRAC_MASK; + height *= rectangle->dir; + + i = _cairo_fixed_integer_part (rectangle->left), + frac = _cairo_fixed_fractional_part (rectangle->left); + add_cell (sweep, i, + (CAIRO_FIXED_ONE-frac) * height, + frac * height); + + i = _cairo_fixed_integer_part (rectangle->right), + frac = _cairo_fixed_fractional_part (rectangle->right); + add_cell (sweep, i, + -(CAIRO_FIXED_ONE-frac) * height, + -frac * height); + } + + if (2*sweep->coverage.count >= sweep->size_spans) { + unsigned size; + + size = sweep->size_spans; + while (size <= 2*sweep->coverage.count) + size <<= 1; + + if (sweep->spans != sweep->spans_stack) + free (sweep->spans); + + sweep->spans = _cairo_malloc_ab (size, sizeof (cairo_half_open_span_t)); + if (unlikely (sweep->spans == NULL)) + longjmp (sweep->jmpbuf, _cairo_error (CAIRO_STATUS_NO_MEMORY)); + + sweep->size_spans = size; + } + + prev_coverage = coverage = 0; + prev_x = INT_MIN; + for (cell = sweep->coverage.head.next; cell != &sweep->coverage.tail; cell = cell->next) { + if (cell->x != prev_x && coverage != prev_coverage) { + int n = sweep->num_spans++; + int c = coverage >> (CAIRO_FIXED_FRAC_BITS * 2 - 8); + sweep->spans[n].x = prev_x; + sweep->spans[n].inverse = 0; + sweep->spans[n].coverage = c - (c >> 8); + prev_coverage = coverage; + } + + coverage += cell->covered; + if (coverage != prev_coverage) { + int n = sweep->num_spans++; + int c = coverage >> (CAIRO_FIXED_FRAC_BITS * 2 - 8); + sweep->spans[n].x = cell->x; + sweep->spans[n].inverse = 0; + sweep->spans[n].coverage = c - (c >> 8); + prev_coverage = coverage; + } + coverage += cell->uncovered; + prev_x = cell->x + 1; + } + _cairo_freepool_reset (&sweep->coverage.pool); + + if (sweep->num_spans) { + if (prev_x <= sweep->xmax) { + int n = sweep->num_spans++; + int c = coverage >> (CAIRO_FIXED_FRAC_BITS * 2 - 8); + sweep->spans[n].x = prev_x; + sweep->spans[n].inverse = 0; + sweep->spans[n].coverage = c - (c >> 8); + } + + if (coverage && prev_x < sweep->xmax) { + int n = sweep->num_spans++; + sweep->spans[n].x = sweep->xmax; + sweep->spans[n].inverse = 1; + sweep->spans[n].coverage = 0; + } + } +} + +static inline void +sweep_line_delete (sweep_line_t *sweep, + rectangle_t *rectangle) +{ + if (sweep->insert_cursor == rectangle) + sweep->insert_cursor = rectangle->next; + + rectangle->prev->next = rectangle->next; + rectangle->next->prev = rectangle->prev; + + pqueue_pop (&sweep->stop); +} + +static inline void +sweep_line_insert (sweep_line_t *sweep, + rectangle_t *rectangle) +{ + rectangle_t *pos; + + pos = sweep->insert_cursor; + if (pos->left != rectangle->left) { + if (pos->left > rectangle->left) { + do { + UNROLL3({ + if (pos->prev->left < rectangle->left) + break; + pos = pos->prev; + }) + } while (TRUE); + } else { + do { + UNROLL3({ + pos = pos->next; + if (pos->left >= rectangle->left) + break; + }); + } while (TRUE); + } + } + + pos->prev->next = rectangle; + rectangle->prev = pos->prev; + rectangle->next = pos; + pos->prev = rectangle; + sweep->insert_cursor = rectangle; + + pqueue_push (sweep, rectangle); +} + +static void +render_rows (sweep_line_t *sweep_line, + cairo_span_renderer_t *renderer, + int height) +{ + cairo_status_t status; + + _active_edges_to_spans (sweep_line); + + status = renderer->render_rows (renderer, + sweep_line->current_y, height, + sweep_line->spans, + sweep_line->num_spans); + if (unlikely (status)) + longjmp (sweep_line->jmpbuf, status); +} + +static cairo_status_t +generate (cairo_rectangular_scan_converter_t *self, + cairo_span_renderer_t *renderer, + rectangle_t **rectangles) +{ + sweep_line_t sweep_line; + rectangle_t *start, *stop; + cairo_status_t status; + + sweep_line_init (&sweep_line); + sweep_line.xmin = _cairo_fixed_integer_part (self->extents.p1.x); + sweep_line.xmax = _cairo_fixed_integer_part (self->extents.p2.x); + sweep_line.start = rectangles; + if ((status = setjmp (sweep_line.jmpbuf))) + goto out; + + sweep_line.current_y = _cairo_fixed_integer_part (self->extents.p1.y); + start = *sweep_line.start++; + do { + if (start->top_y != sweep_line.current_y) { + render_rows (&sweep_line, renderer, + start->top_y - sweep_line.current_y); + sweep_line.current_y = start->top_y; + } + + do { + sweep_line_insert (&sweep_line, start); + start = *sweep_line.start++; + if (start == NULL) + goto end; + if (start->top_y != sweep_line.current_y) + break; + } while (TRUE); + + render_rows (&sweep_line, renderer, 1); + + stop = peek_stop (&sweep_line); + while (stop->bottom_y == sweep_line.current_y) { + sweep_line_delete (&sweep_line, stop); + stop = peek_stop (&sweep_line); + if (stop == NULL) + break; + } + + sweep_line.current_y++; + + while (stop != NULL && stop->bottom_y < start->top_y) { + if (stop->bottom_y != sweep_line.current_y) { + render_rows (&sweep_line, renderer, + stop->bottom_y - sweep_line.current_y); + sweep_line.current_y = stop->bottom_y; + } + + render_rows (&sweep_line, renderer, 1); + + do { + sweep_line_delete (&sweep_line, stop); + stop = peek_stop (&sweep_line); + } while (stop != NULL && stop->bottom_y == sweep_line.current_y); + + sweep_line.current_y++; + } + } while (TRUE); + + end: + render_rows (&sweep_line, renderer, 1); + + stop = peek_stop (&sweep_line); + while (stop->bottom_y == sweep_line.current_y) { + sweep_line_delete (&sweep_line, stop); + stop = peek_stop (&sweep_line); + if (stop == NULL) + goto out; + } + + while (++sweep_line.current_y < _cairo_fixed_integer_part (self->extents.p2.y)) { + if (stop->bottom_y != sweep_line.current_y) { + render_rows (&sweep_line, renderer, + stop->bottom_y - sweep_line.current_y); + sweep_line.current_y = stop->bottom_y; + } + + render_rows (&sweep_line, renderer, 1); + + do { + sweep_line_delete (&sweep_line, stop); + stop = peek_stop (&sweep_line); + if (stop == NULL) + goto out; + } while (stop->bottom_y == sweep_line.current_y); + + } + + out: + sweep_line_fini (&sweep_line); + + return status; +} +static void generate_row(cairo_span_renderer_t *renderer, + const rectangle_t *r, + int y, int h, + uint16_t coverage) +{ + cairo_half_open_span_t spans[4]; + unsigned int num_spans = 0; + int x1 = _cairo_fixed_integer_part (r->left); + int x2 = _cairo_fixed_integer_part (r->right); + if (x2 > x1) { + if (! _cairo_fixed_is_integer (r->left)) { + spans[num_spans].x = x1; + spans[num_spans].coverage = + coverage * (256 - _cairo_fixed_fractional_part (r->left)) >> 8; + num_spans++; + x1++; + } + + if (x2 > x1) { + spans[num_spans].x = x1; + spans[num_spans].coverage = coverage - (coverage >> 8); + num_spans++; + } + + if (! _cairo_fixed_is_integer (r->right)) { + spans[num_spans].x = x2++; + spans[num_spans].coverage = + coverage * _cairo_fixed_fractional_part (r->right) >> 8; + num_spans++; + } + } else { + spans[num_spans].x = x2++; + spans[num_spans].coverage = coverage * (r->right - r->left) >> 8; + num_spans++; + } + + spans[num_spans].x = x2; + spans[num_spans].coverage = 0; + num_spans++; + + renderer->render_rows (renderer, y, h, spans, num_spans); +} + +static cairo_status_t +generate_box (cairo_rectangular_scan_converter_t *self, + cairo_span_renderer_t *renderer) +{ + const rectangle_t *r = self->chunks.base; + int y1 = _cairo_fixed_integer_part (r->top); + int y2 = _cairo_fixed_integer_part (r->bottom); + if (y2 > y1) { + if (! _cairo_fixed_is_integer (r->top)) { + generate_row(renderer, r, y1, 1, + 256 - _cairo_fixed_fractional_part (r->top)); + y1++; + } + + if (y2 > y1) + generate_row(renderer, r, y1, y2-y1, 256); + + if (! _cairo_fixed_is_integer (r->bottom)) + generate_row(renderer, r, y2, 1, + _cairo_fixed_fractional_part (r->bottom)); + } else + generate_row(renderer, r, y1, 1, r->bottom - r->top); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_rectangular_scan_converter_generate (void *converter, + cairo_span_renderer_t *renderer) +{ + cairo_rectangular_scan_converter_t *self = converter; + rectangle_t *rectangles_stack[CAIRO_STACK_ARRAY_LENGTH (rectangle_t *)]; + rectangle_t **rectangles; + struct _cairo_rectangular_scan_converter_chunk *chunk; + cairo_status_t status; + int i, j; + + if (unlikely (self->num_rectangles == 0)) { + return renderer->render_rows (renderer, + _cairo_fixed_integer_part (self->extents.p1.y), + _cairo_fixed_integer_part (self->extents.p2.y - self->extents.p1.y), + NULL, 0); + } + + if (self->num_rectangles == 1) + return generate_box (self, renderer); + + rectangles = rectangles_stack; + if (unlikely (self->num_rectangles >= ARRAY_LENGTH (rectangles_stack))) { + rectangles = _cairo_malloc_ab (self->num_rectangles + 1, + sizeof (rectangle_t *)); + if (unlikely (rectangles == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + j = 0; + for (chunk = &self->chunks; chunk != NULL; chunk = chunk->next) { + rectangle_t *rectangle; + + rectangle = chunk->base; + for (i = 0; i < chunk->count; i++) + rectangles[j++] = &rectangle[i]; + } + rectangle_sort (rectangles, j); + rectangles[j] = NULL; + + status = generate (self, renderer, rectangles); + + if (rectangles != rectangles_stack) + free (rectangles); + + return status; +} + +static rectangle_t * +_allocate_rectangle (cairo_rectangular_scan_converter_t *self) +{ + rectangle_t *rectangle; + struct _cairo_rectangular_scan_converter_chunk *chunk; + + chunk = self->tail; + if (chunk->count == chunk->size) { + int size; + + size = chunk->size * 2; + chunk->next = _cairo_malloc_ab_plus_c (size, + sizeof (rectangle_t), + sizeof (struct _cairo_rectangular_scan_converter_chunk)); + + if (unlikely (chunk->next == NULL)) + return NULL; + + chunk = chunk->next; + chunk->next = NULL; + chunk->count = 0; + chunk->size = size; + chunk->base = chunk + 1; + self->tail = chunk; + } + + rectangle = chunk->base; + return rectangle + chunk->count++; +} + +cairo_status_t +_cairo_rectangular_scan_converter_add_box (cairo_rectangular_scan_converter_t *self, + const cairo_box_t *box, + int dir) +{ + rectangle_t *rectangle; + + rectangle = _allocate_rectangle (self); + if (unlikely (rectangle == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + rectangle->dir = dir; + rectangle->left = MAX (box->p1.x, self->extents.p1.x); + rectangle->right = MIN (box->p2.x, self->extents.p2.x); + if (unlikely (rectangle->right <= rectangle->left)) { + self->tail->count--; + return CAIRO_STATUS_SUCCESS; + } + + rectangle->top = MAX (box->p1.y, self->extents.p1.y); + rectangle->top_y = _cairo_fixed_integer_floor (rectangle->top); + rectangle->bottom = MIN (box->p2.y, self->extents.p2.y); + rectangle->bottom_y = _cairo_fixed_integer_floor (rectangle->bottom); + if (likely (rectangle->bottom > rectangle->top)) + self->num_rectangles++; + else + self->tail->count--; + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_rectangular_scan_converter_destroy (void *converter) +{ + cairo_rectangular_scan_converter_t *self = converter; + struct _cairo_rectangular_scan_converter_chunk *chunk, *next; + + for (chunk = self->chunks.next; chunk != NULL; chunk = next) { + next = chunk->next; + free (chunk); + } +} + +void +_cairo_rectangular_scan_converter_init (cairo_rectangular_scan_converter_t *self, + const cairo_rectangle_int_t *extents) +{ + self->base.destroy = _cairo_rectangular_scan_converter_destroy; + self->base.generate = _cairo_rectangular_scan_converter_generate; + + _cairo_box_from_rectangle (&self->extents, extents); + + self->chunks.base = self->buf; + self->chunks.next = NULL; + self->chunks.count = 0; + self->chunks.size = sizeof (self->buf) / sizeof (rectangle_t); + self->tail = &self->chunks; + + self->num_rectangles = 0; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-reference-count-private.h b/local/recipes/libs/cairo/source/src/cairo-reference-count-private.h new file mode 100644 index 0000000000..f19125c618 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-reference-count-private.h @@ -0,0 +1,62 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2007 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Chris Wilson + */ + +#ifndef CAIRO_REFRENCE_COUNT_PRIVATE_H +#define CAIRO_REFRENCE_COUNT_PRIVATE_H + +#include "cairo-atomic-private.h" + +/* Encapsulate operations on the object's reference count */ +typedef struct { + cairo_atomic_int_t ref_count; +} cairo_reference_count_t; + +#define _cairo_reference_count_inc(RC) _cairo_atomic_int_inc (&(RC)->ref_count) +#define _cairo_reference_count_dec(RC) _cairo_atomic_int_dec (&(RC)->ref_count) +#define _cairo_reference_count_dec_and_test(RC) _cairo_atomic_int_dec_and_test (&(RC)->ref_count) + +#define CAIRO_REFERENCE_COUNT_INIT(RC, VALUE) ((RC)->ref_count = (VALUE)) + +#define CAIRO_REFERENCE_COUNT_GET_VALUE(RC) _cairo_atomic_int_get (&(RC)->ref_count) + +#define CAIRO_REFERENCE_COUNT_INVALID_VALUE ((int) -1) +#define CAIRO_REFERENCE_COUNT_INVALID {CAIRO_REFERENCE_COUNT_INVALID_VALUE} + +#define CAIRO_REFERENCE_COUNT_IS_INVALID(RC) (CAIRO_REFERENCE_COUNT_GET_VALUE (RC) == CAIRO_REFERENCE_COUNT_INVALID_VALUE) + +#define CAIRO_REFERENCE_COUNT_HAS_REFERENCE(RC) (CAIRO_REFERENCE_COUNT_GET_VALUE (RC) > 0) + +#endif diff --git a/local/recipes/libs/cairo/source/src/cairo-region-private.h b/local/recipes/libs/cairo/source/src/cairo-region-private.h new file mode 100644 index 0000000000..549e508789 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-region-private.h @@ -0,0 +1,77 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Owen Taylor + * Vladimir Vukicevic + * Søren Sandmann + */ + +#ifndef CAIRO_REGION_PRIVATE_H +#define CAIRO_REGION_PRIVATE_H + +#include "cairo-types-private.h" +#include "cairo-reference-count-private.h" + +#include + +CAIRO_BEGIN_DECLS + +struct _cairo_region { + cairo_reference_count_t ref_count; + cairo_status_t status; + + pixman_region32_t rgn; +}; + +cairo_private cairo_region_t * +_cairo_region_create_in_error (cairo_status_t status); + +cairo_private void +_cairo_region_init (cairo_region_t *region); + +cairo_private void +_cairo_region_init_rectangle (cairo_region_t *region, + const cairo_rectangle_int_t *rectangle); + +cairo_private void +_cairo_region_fini (cairo_region_t *region); + +cairo_private cairo_region_t * +_cairo_region_create_from_boxes (const cairo_box_t *boxes, int count); + +cairo_private cairo_box_t * +_cairo_region_get_boxes (const cairo_region_t *region, int *nbox); + +CAIRO_END_DECLS + +#endif /* CAIRO_REGION_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-region.c b/local/recipes/libs/cairo/source/src/cairo-region.c new file mode 100644 index 0000000000..6107472948 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-region.c @@ -0,0 +1,922 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Owen Taylor + * Vladimir Vukicevic + * Søren Sandmann + */ + +#include "cairoint.h" + +#include "cairo-error-private.h" +#include "cairo-region-private.h" + +/* XXX need to update pixman headers to be const as appropriate */ +#define CONST_CAST (pixman_region32_t *) + +/** + * SECTION:cairo-region + * @Title: Regions + * @Short_Description: Representing a pixel-aligned area + * + * Regions are a simple graphical data type representing an area of + * integer-aligned rectangles. They are often used on raster surfaces + * to track areas of interest, such as change or clip areas. + **/ + +static const cairo_region_t _cairo_region_nil = { + CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ + CAIRO_STATUS_NO_MEMORY, /* status */ +}; + +cairo_region_t * +_cairo_region_create_in_error (cairo_status_t status) +{ + switch (status) { + case CAIRO_STATUS_NO_MEMORY: + return (cairo_region_t *) &_cairo_region_nil; + + case CAIRO_STATUS_SUCCESS: + case CAIRO_STATUS_LAST_STATUS: + ASSERT_NOT_REACHED; + /* fall-through */ + case CAIRO_STATUS_SURFACE_TYPE_MISMATCH: + case CAIRO_STATUS_INVALID_STATUS: + case CAIRO_STATUS_INVALID_CONTENT: + case CAIRO_STATUS_INVALID_FORMAT: + case CAIRO_STATUS_INVALID_VISUAL: + case CAIRO_STATUS_READ_ERROR: + case CAIRO_STATUS_WRITE_ERROR: + case CAIRO_STATUS_FILE_NOT_FOUND: + case CAIRO_STATUS_TEMP_FILE_ERROR: + case CAIRO_STATUS_INVALID_STRIDE: + case CAIRO_STATUS_INVALID_SIZE: + case CAIRO_STATUS_DEVICE_TYPE_MISMATCH: + case CAIRO_STATUS_DEVICE_ERROR: + case CAIRO_STATUS_INVALID_RESTORE: + case CAIRO_STATUS_INVALID_POP_GROUP: + case CAIRO_STATUS_NO_CURRENT_POINT: + case CAIRO_STATUS_INVALID_MATRIX: + case CAIRO_STATUS_NULL_POINTER: + case CAIRO_STATUS_INVALID_STRING: + case CAIRO_STATUS_INVALID_PATH_DATA: + case CAIRO_STATUS_SURFACE_FINISHED: + case CAIRO_STATUS_PATTERN_TYPE_MISMATCH: + case CAIRO_STATUS_INVALID_DASH: + case CAIRO_STATUS_INVALID_DSC_COMMENT: + case CAIRO_STATUS_INVALID_INDEX: + case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE: + case CAIRO_STATUS_FONT_TYPE_MISMATCH: + case CAIRO_STATUS_USER_FONT_IMMUTABLE: + case CAIRO_STATUS_USER_FONT_ERROR: + case CAIRO_STATUS_NEGATIVE_COUNT: + case CAIRO_STATUS_INVALID_CLUSTERS: + case CAIRO_STATUS_INVALID_SLANT: + case CAIRO_STATUS_INVALID_WEIGHT: + case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED: + case CAIRO_STATUS_INVALID_MESH_CONSTRUCTION: + case CAIRO_STATUS_DEVICE_FINISHED: + case CAIRO_STATUS_JBIG2_GLOBAL_MISSING: + case CAIRO_STATUS_PNG_ERROR: + case CAIRO_STATUS_FREETYPE_ERROR: + case CAIRO_STATUS_WIN32_GDI_ERROR: + case CAIRO_STATUS_TAG_ERROR: + case CAIRO_STATUS_DWRITE_ERROR: + case CAIRO_STATUS_SVG_FONT_ERROR: + default: + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_region_t *) &_cairo_region_nil; + } +} + +/** + * _cairo_region_set_error: + * @region: a region + * @status: a status value indicating an error + * + * Atomically sets region->status to @status and calls _cairo_error; + * Does nothing if status is %CAIRO_STATUS_SUCCESS or any of the internal + * status values. + * + * All assignments of an error status to region->status should happen + * through _cairo_region_set_error(). Note that due to the nature of + * the atomic operation, it is not safe to call this function on the + * nil objects. + * + * The purpose of this function is to allow the user to set a + * breakpoint in _cairo_error() to generate a stack trace for when the + * user causes cairo to detect an error. + * + * Return value: the error status. + **/ +static cairo_status_t +_cairo_region_set_error (cairo_region_t *region, + cairo_status_t status) +{ + if (status == CAIRO_STATUS_SUCCESS) + return CAIRO_STATUS_SUCCESS; + + /* Don't overwrite an existing error. This preserves the first + * error, which is the most significant. */ + _cairo_status_set_error (®ion->status, status); + + return _cairo_error (status); +} + +void +_cairo_region_init (cairo_region_t *region) +{ + VG (VALGRIND_MAKE_MEM_UNDEFINED (region, sizeof (cairo_region_t))); + + region->status = CAIRO_STATUS_SUCCESS; + CAIRO_REFERENCE_COUNT_INIT (®ion->ref_count, 0); + pixman_region32_init (®ion->rgn); +} + +void +_cairo_region_init_rectangle (cairo_region_t *region, + const cairo_rectangle_int_t *rectangle) +{ + VG (VALGRIND_MAKE_MEM_UNDEFINED (region, sizeof (cairo_region_t))); + + region->status = CAIRO_STATUS_SUCCESS; + CAIRO_REFERENCE_COUNT_INIT (®ion->ref_count, 0); + pixman_region32_init_rect (®ion->rgn, + rectangle->x, rectangle->y, + rectangle->width, rectangle->height); +} + +void +_cairo_region_fini (cairo_region_t *region) +{ + assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (®ion->ref_count)); + pixman_region32_fini (®ion->rgn); + VG (VALGRIND_MAKE_MEM_UNDEFINED (region, sizeof (cairo_region_t))); +} + +/** + * cairo_region_create: + * + * Allocates a new empty region object. + * + * Return value: A newly allocated #cairo_region_t. Free with + * cairo_region_destroy(). This function always returns a + * valid pointer; if memory cannot be allocated, then a special + * error object is returned where all operations on the object do nothing. + * You can check for this with cairo_region_status(). + * + * Since: 1.10 + **/ +cairo_region_t * +cairo_region_create (void) +{ + cairo_region_t *region; + + region = _cairo_calloc (sizeof (cairo_region_t)); + if (region == NULL) + return (cairo_region_t *) &_cairo_region_nil; + + region->status = CAIRO_STATUS_SUCCESS; + CAIRO_REFERENCE_COUNT_INIT (®ion->ref_count, 1); + + pixman_region32_init (®ion->rgn); + + return region; +} + +/** + * cairo_region_create_rectangles: + * @rects: an array of @count rectangles + * @count: number of rectangles + * + * Allocates a new region object containing the union of all given @rects. + * + * Return value: A newly allocated #cairo_region_t. Free with + * cairo_region_destroy(). This function always returns a + * valid pointer; if memory cannot be allocated, then a special + * error object is returned where all operations on the object do nothing. + * You can check for this with cairo_region_status(). + * + * Since: 1.10 + **/ +cairo_region_t * +cairo_region_create_rectangles (const cairo_rectangle_int_t *rects, + int count) +{ + pixman_box32_t stack_pboxes[CAIRO_STACK_ARRAY_LENGTH (pixman_box32_t)]; + pixman_box32_t *pboxes = stack_pboxes; + cairo_region_t *region; + int i; + + region = _cairo_calloc (sizeof (cairo_region_t)); + if (unlikely (region == NULL)) + return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + CAIRO_REFERENCE_COUNT_INIT (®ion->ref_count, 1); + region->status = CAIRO_STATUS_SUCCESS; + + if (count == 1) { + pixman_region32_init_rect (®ion->rgn, + rects->x, rects->y, + rects->width, rects->height); + + return region; + } + + if (count > ARRAY_LENGTH (stack_pboxes)) { + pboxes = _cairo_malloc_ab (count, sizeof (pixman_box32_t)); + if (unlikely (pboxes == NULL)) { + free (region); + return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + } + } + + for (i = 0; i < count; i++) { + pboxes[i].x1 = rects[i].x; + pboxes[i].y1 = rects[i].y; + pboxes[i].x2 = rects[i].x + rects[i].width; + pboxes[i].y2 = rects[i].y + rects[i].height; + } + + i = pixman_region32_init_rects (®ion->rgn, pboxes, count); + + if (pboxes != stack_pboxes) + free (pboxes); + + if (unlikely (i == 0)) { + free (region); + return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + } + + return region; +} + +cairo_region_t * +_cairo_region_create_from_boxes (const cairo_box_t *boxes, int count) +{ + cairo_region_t *region; + + region = _cairo_calloc (sizeof (cairo_region_t)); + if (unlikely (region == NULL)) + return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + CAIRO_REFERENCE_COUNT_INIT (®ion->ref_count, 1); + region->status = CAIRO_STATUS_SUCCESS; + + if (! pixman_region32_init_rects (®ion->rgn, + (pixman_box32_t *)boxes, count)) { + free (region); + return _cairo_region_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + } + + return region; +} + +cairo_box_t * +_cairo_region_get_boxes (const cairo_region_t *region, int *nbox) +{ + if (region->status) { + nbox = 0; + return NULL; + } + + return (cairo_box_t *) pixman_region32_rectangles (CONST_CAST ®ion->rgn, nbox); +} + +/** + * cairo_region_create_rectangle: + * @rectangle: a #cairo_rectangle_int_t + * + * Allocates a new region object containing @rectangle. + * + * Return value: A newly allocated #cairo_region_t. Free with + * cairo_region_destroy(). This function always returns a + * valid pointer; if memory cannot be allocated, then a special + * error object is returned where all operations on the object do nothing. + * You can check for this with cairo_region_status(). + * + * Since: 1.10 + **/ +cairo_region_t * +cairo_region_create_rectangle (const cairo_rectangle_int_t *rectangle) +{ + cairo_region_t *region; + + region = _cairo_calloc (sizeof (cairo_region_t)); + if (unlikely (region == NULL)) + return (cairo_region_t *) &_cairo_region_nil; + + region->status = CAIRO_STATUS_SUCCESS; + CAIRO_REFERENCE_COUNT_INIT (®ion->ref_count, 1); + + pixman_region32_init_rect (®ion->rgn, + rectangle->x, rectangle->y, + rectangle->width, rectangle->height); + + return region; +} + +/** + * cairo_region_copy: + * @original: a #cairo_region_t + * + * Allocates a new region object copying the area from @original. + * + * Return value: A newly allocated #cairo_region_t. Free with + * cairo_region_destroy(). This function always returns a + * valid pointer; if memory cannot be allocated, then a special + * error object is returned where all operations on the object do nothing. + * You can check for this with cairo_region_status(). + * + * Since: 1.10 + **/ +cairo_region_t * +cairo_region_copy (const cairo_region_t *original) +{ + cairo_region_t *copy; + + if (original != NULL && original->status) + return (cairo_region_t *) &_cairo_region_nil; + + copy = cairo_region_create (); + if (unlikely (copy->status)) + return copy; + + if (original != NULL && + ! pixman_region32_copy (©->rgn, CONST_CAST &original->rgn)) + { + cairo_region_destroy (copy); + return (cairo_region_t *) &_cairo_region_nil; + } + + return copy; +} + +/** + * cairo_region_reference: + * @region: a #cairo_region_t + * + * Increases the reference count on @region by one. This prevents + * @region from being destroyed until a matching call to + * cairo_region_destroy() is made. + * + * Return value: the referenced #cairo_region_t. + * + * Since: 1.10 + **/ +cairo_region_t * +cairo_region_reference (cairo_region_t *region) +{ + if (region == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (®ion->ref_count)) + return NULL; + + assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (®ion->ref_count)); + + _cairo_reference_count_inc (®ion->ref_count); + return region; +} + +/** + * cairo_region_destroy: + * @region: a #cairo_region_t + * + * Destroys a #cairo_region_t object created with + * cairo_region_create(), cairo_region_copy(), or + * or cairo_region_create_rectangle(). + * + * Since: 1.10 + **/ +void +cairo_region_destroy (cairo_region_t *region) +{ + if (region == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (®ion->ref_count)) + return; + + assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (®ion->ref_count)); + + if (! _cairo_reference_count_dec_and_test (®ion->ref_count)) + return; + + _cairo_region_fini (region); + free (region); +} + +/** + * cairo_region_num_rectangles: + * @region: a #cairo_region_t + * + * Returns the number of rectangles contained in @region. + * + * Return value: The number of rectangles contained in @region. + * + * Since: 1.10 + **/ +int +cairo_region_num_rectangles (const cairo_region_t *region) +{ + if (region->status) + return 0; + + return pixman_region32_n_rects (CONST_CAST ®ion->rgn); +} + +/** + * cairo_region_get_rectangle: + * @region: a #cairo_region_t + * @nth: a number indicating which rectangle should be returned + * @rectangle: return location for a #cairo_rectangle_int_t + * + * Stores the @nth rectangle from the region in @rectangle. + * + * Since: 1.10 + **/ +void +cairo_region_get_rectangle (const cairo_region_t *region, + int nth, + cairo_rectangle_int_t *rectangle) +{ + pixman_box32_t *pbox; + + if (region->status) { + rectangle->x = rectangle->y = 0; + rectangle->width = rectangle->height = 0; + return; + } + + pbox = pixman_region32_rectangles (CONST_CAST ®ion->rgn, NULL) + nth; + + rectangle->x = pbox->x1; + rectangle->y = pbox->y1; + rectangle->width = pbox->x2 - pbox->x1; + rectangle->height = pbox->y2 - pbox->y1; +} + +/** + * cairo_region_get_extents: + * @region: a #cairo_region_t + * @extents: rectangle into which to store the extents + * + * Gets the bounding rectangle of @region as a #cairo_rectangle_int_t + * + * Since: 1.10 + **/ +void +cairo_region_get_extents (const cairo_region_t *region, + cairo_rectangle_int_t *extents) +{ + pixman_box32_t *pextents; + + if (region->status) { + extents->x = extents->y = 0; + extents->width = extents->height = 0; + return; + } + + pextents = pixman_region32_extents (CONST_CAST ®ion->rgn); + + extents->x = pextents->x1; + extents->y = pextents->y1; + extents->width = pextents->x2 - pextents->x1; + extents->height = pextents->y2 - pextents->y1; +} + +/** + * cairo_region_status: + * @region: a #cairo_region_t + * + * Checks whether an error has previous occurred for this + * region object. + * + * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY + * + * Since: 1.10 + **/ +cairo_status_t +cairo_region_status (const cairo_region_t *region) +{ + return region->status; +} + +/** + * cairo_region_subtract: + * @dst: a #cairo_region_t + * @other: another #cairo_region_t + * + * Subtracts @other from @dst and places the result in @dst + * + * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY + * + * Since: 1.10 + **/ +cairo_status_t +cairo_region_subtract (cairo_region_t *dst, const cairo_region_t *other) +{ + if (dst->status) + return dst->status; + + if (other->status) + return _cairo_region_set_error (dst, other->status); + + if (! pixman_region32_subtract (&dst->rgn, + &dst->rgn, + CONST_CAST &other->rgn)) + { + return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY); + } + + return CAIRO_STATUS_SUCCESS; +} + +/** + * cairo_region_subtract_rectangle: + * @dst: a #cairo_region_t + * @rectangle: a #cairo_rectangle_int_t + * + * Subtracts @rectangle from @dst and places the result in @dst + * + * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY + * + * Since: 1.10 + **/ +cairo_status_t +cairo_region_subtract_rectangle (cairo_region_t *dst, + const cairo_rectangle_int_t *rectangle) +{ + cairo_status_t status = CAIRO_STATUS_SUCCESS; + pixman_region32_t region; + + if (dst->status) + return dst->status; + + pixman_region32_init_rect (®ion, + rectangle->x, rectangle->y, + rectangle->width, rectangle->height); + + if (! pixman_region32_subtract (&dst->rgn, &dst->rgn, ®ion)) + status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY); + + pixman_region32_fini (®ion); + + return status; +} + +/** + * cairo_region_intersect: + * @dst: a #cairo_region_t + * @other: another #cairo_region_t + * + * Computes the intersection of @dst with @other and places the result in @dst + * + * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY + * + * Since: 1.10 + **/ +cairo_status_t +cairo_region_intersect (cairo_region_t *dst, const cairo_region_t *other) +{ + if (dst->status) + return dst->status; + + if (other->status) + return _cairo_region_set_error (dst, other->status); + + if (! pixman_region32_intersect (&dst->rgn, &dst->rgn, CONST_CAST &other->rgn)) + return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY); + + return CAIRO_STATUS_SUCCESS; +} + +/** + * cairo_region_intersect_rectangle: + * @dst: a #cairo_region_t + * @rectangle: a #cairo_rectangle_int_t + * + * Computes the intersection of @dst with @rectangle and places the + * result in @dst + * + * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY + * + * Since: 1.10 + **/ +cairo_status_t +cairo_region_intersect_rectangle (cairo_region_t *dst, + const cairo_rectangle_int_t *rectangle) +{ + cairo_status_t status = CAIRO_STATUS_SUCCESS; + pixman_region32_t region; + + if (dst->status) + return dst->status; + + pixman_region32_init_rect (®ion, + rectangle->x, rectangle->y, + rectangle->width, rectangle->height); + + if (! pixman_region32_intersect (&dst->rgn, &dst->rgn, ®ion)) + status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY); + + pixman_region32_fini (®ion); + + return status; +} + +/** + * cairo_region_union: + * @dst: a #cairo_region_t + * @other: another #cairo_region_t + * + * Computes the union of @dst with @other and places the result in @dst + * + * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY + * + * Since: 1.10 + **/ +cairo_status_t +cairo_region_union (cairo_region_t *dst, + const cairo_region_t *other) +{ + if (dst->status) + return dst->status; + + if (other->status) + return _cairo_region_set_error (dst, other->status); + + if (! pixman_region32_union (&dst->rgn, &dst->rgn, CONST_CAST &other->rgn)) + return _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY); + + return CAIRO_STATUS_SUCCESS; +} + +/** + * cairo_region_union_rectangle: + * @dst: a #cairo_region_t + * @rectangle: a #cairo_rectangle_int_t + * + * Computes the union of @dst with @rectangle and places the result in @dst. + * + * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY + * + * Since: 1.10 + **/ +cairo_status_t +cairo_region_union_rectangle (cairo_region_t *dst, + const cairo_rectangle_int_t *rectangle) +{ + cairo_status_t status = CAIRO_STATUS_SUCCESS; + pixman_region32_t region; + + if (dst->status) + return dst->status; + + pixman_region32_init_rect (®ion, + rectangle->x, rectangle->y, + rectangle->width, rectangle->height); + + if (! pixman_region32_union (&dst->rgn, &dst->rgn, ®ion)) + status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY); + + pixman_region32_fini (®ion); + + return status; +} + +/** + * cairo_region_xor: + * @dst: a #cairo_region_t + * @other: another #cairo_region_t + * + * Computes the exclusive difference of @dst with @other and places the + * result in @dst. That is, @dst will be set to contain all areas that + * are either in @dst or in @other, but not in both. + * + * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY + * + * Since: 1.10 + **/ +cairo_status_t +cairo_region_xor (cairo_region_t *dst, const cairo_region_t *other) +{ + cairo_status_t status = CAIRO_STATUS_SUCCESS; + pixman_region32_t tmp; + + if (dst->status) + return dst->status; + + if (other->status) + return _cairo_region_set_error (dst, other->status); + + pixman_region32_init (&tmp); + + /* XXX: get an xor function into pixman */ + if (! pixman_region32_subtract (&tmp, CONST_CAST &other->rgn, &dst->rgn) || + ! pixman_region32_subtract (&dst->rgn, &dst->rgn, CONST_CAST &other->rgn) || + ! pixman_region32_union (&dst->rgn, &dst->rgn, &tmp)) + status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY); + + pixman_region32_fini (&tmp); + + return status; +} + +/** + * cairo_region_xor_rectangle: + * @dst: a #cairo_region_t + * @rectangle: a #cairo_rectangle_int_t + * + * Computes the exclusive difference of @dst with @rectangle and places the + * result in @dst. That is, @dst will be set to contain all areas that are + * either in @dst or in @rectangle, but not in both. + * + * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY + * + * Since: 1.10 + **/ +cairo_status_t +cairo_region_xor_rectangle (cairo_region_t *dst, + const cairo_rectangle_int_t *rectangle) +{ + cairo_status_t status = CAIRO_STATUS_SUCCESS; + pixman_region32_t region, tmp; + + if (dst->status) + return dst->status; + + pixman_region32_init_rect (®ion, + rectangle->x, rectangle->y, + rectangle->width, rectangle->height); + pixman_region32_init (&tmp); + + /* XXX: get an xor function into pixman */ + if (! pixman_region32_subtract (&tmp, ®ion, &dst->rgn) || + ! pixman_region32_subtract (&dst->rgn, &dst->rgn, ®ion) || + ! pixman_region32_union (&dst->rgn, &dst->rgn, &tmp)) + status = _cairo_region_set_error (dst, CAIRO_STATUS_NO_MEMORY); + + pixman_region32_fini (&tmp); + pixman_region32_fini (®ion); + + return status; +} + +/** + * cairo_region_is_empty: + * @region: a #cairo_region_t + * + * Checks whether @region is empty. + * + * Return value: %TRUE if @region is empty, %FALSE if it isn't. + * + * Since: 1.10 + **/ +cairo_bool_t +cairo_region_is_empty (const cairo_region_t *region) +{ + if (region->status) + return TRUE; + + return ! pixman_region32_not_empty (CONST_CAST ®ion->rgn); +} + +/** + * cairo_region_translate: + * @region: a #cairo_region_t + * @dx: Amount to translate in the x direction + * @dy: Amount to translate in the y direction + * + * Translates @region by (@dx, @dy). + * + * Since: 1.10 + **/ +void +cairo_region_translate (cairo_region_t *region, + int dx, int dy) +{ + if (region->status) + return; + + pixman_region32_translate (®ion->rgn, dx, dy); +} + +/** + * cairo_region_contains_rectangle: + * @region: a #cairo_region_t + * @rectangle: a #cairo_rectangle_int_t + * + * Checks whether @rectangle is inside, outside or partially contained + * in @region + * + * Return value: + * %CAIRO_REGION_OVERLAP_IN if @rectangle is entirely inside @region, + * %CAIRO_REGION_OVERLAP_OUT if @rectangle is entirely outside @region, or + * %CAIRO_REGION_OVERLAP_PART if @rectangle is partially inside and partially outside @region. + * + * Since: 1.10 + **/ +cairo_region_overlap_t +cairo_region_contains_rectangle (const cairo_region_t *region, + const cairo_rectangle_int_t *rectangle) +{ + pixman_box32_t pbox; + pixman_region_overlap_t poverlap; + + if (region->status) + return CAIRO_REGION_OVERLAP_OUT; + + pbox.x1 = rectangle->x; + pbox.y1 = rectangle->y; + pbox.x2 = rectangle->x + rectangle->width; + pbox.y2 = rectangle->y + rectangle->height; + + poverlap = pixman_region32_contains_rectangle (CONST_CAST ®ion->rgn, + &pbox); + switch (poverlap) { + default: + case PIXMAN_REGION_OUT: return CAIRO_REGION_OVERLAP_OUT; + case PIXMAN_REGION_IN: return CAIRO_REGION_OVERLAP_IN; + case PIXMAN_REGION_PART: return CAIRO_REGION_OVERLAP_PART; + } +} + +/** + * cairo_region_contains_point: + * @region: a #cairo_region_t + * @x: the x coordinate of a point + * @y: the y coordinate of a point + * + * Checks whether (@x, @y) is contained in @region. + * + * Return value: %TRUE if (@x, @y) is contained in @region, %FALSE if it is not. + * + * Since: 1.10 + **/ +cairo_bool_t +cairo_region_contains_point (const cairo_region_t *region, + int x, int y) +{ + pixman_box32_t box; + + if (region->status) + return FALSE; + + return pixman_region32_contains_point (CONST_CAST ®ion->rgn, x, y, &box); +} + +/** + * cairo_region_equal: + * @a: a #cairo_region_t or %NULL + * @b: a #cairo_region_t or %NULL + * + * Compares whether region_a is equivalent to region_b. %NULL as an argument + * is equal to itself, but not to any non-%NULL region. + * + * Return value: %TRUE if both regions contained the same coverage, + * %FALSE if it is not or any region is in an error status. + * + * Since: 1.10 + **/ +cairo_bool_t +cairo_region_equal (const cairo_region_t *a, + const cairo_region_t *b) +{ + /* error objects are never equal */ + if ((a != NULL && a->status) || (b != NULL && b->status)) + return FALSE; + + if (a == b) + return TRUE; + + if (a == NULL || b == NULL) + return FALSE; + + return pixman_region32_equal (CONST_CAST &a->rgn, CONST_CAST &b->rgn); +} diff --git a/local/recipes/libs/cairo/source/src/cairo-rtree-private.h b/local/recipes/libs/cairo/source/src/cairo-rtree-private.h new file mode 100644 index 0000000000..27806cab60 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-rtree-private.h @@ -0,0 +1,142 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Chris Wilson. + * + * Contributor(s): + * Chris Wilson + * + */ + +#ifndef CAIRO_RTREE_PRIVATE_H +#define CAIRO_RTREE_PRIVATE_H + +#include "cairo-compiler-private.h" +#include "cairo-error-private.h" +#include "cairo-types-private.h" + +#include "cairo-freelist-private.h" +#include "cairo-list-inline.h" + +enum { + CAIRO_RTREE_NODE_AVAILABLE, + CAIRO_RTREE_NODE_DIVIDED, + CAIRO_RTREE_NODE_OCCUPIED, +}; + +typedef struct _cairo_rtree_node { + struct _cairo_rtree_node *children[4], *parent; + cairo_list_t link; + uint16_t pinned; + uint16_t state; + uint16_t x, y; + uint16_t width, height; +} cairo_rtree_node_t; + +typedef struct _cairo_rtree { + cairo_rtree_node_t root; + int min_size; + cairo_list_t pinned; + cairo_list_t available; + cairo_list_t evictable; + void (*destroy) (cairo_rtree_node_t *); + cairo_freepool_t node_freepool; +} cairo_rtree_t; + +cairo_private cairo_rtree_node_t * +_cairo_rtree_node_create (cairo_rtree_t *rtree, + cairo_rtree_node_t *parent, + int x, + int y, + int width, + int height); + +cairo_private cairo_status_t +_cairo_rtree_node_insert (cairo_rtree_t *rtree, + cairo_rtree_node_t *node, + int width, + int height, + cairo_rtree_node_t **out); + +cairo_private void +_cairo_rtree_node_collapse (cairo_rtree_t *rtree, cairo_rtree_node_t *node); + +cairo_private void +_cairo_rtree_node_remove (cairo_rtree_t *rtree, cairo_rtree_node_t *node); + +cairo_private void +_cairo_rtree_node_destroy (cairo_rtree_t *rtree, cairo_rtree_node_t *node); + +cairo_private void +_cairo_rtree_init (cairo_rtree_t *rtree, + int width, + int height, + int min_size, + int node_size, + void (*destroy)(cairo_rtree_node_t *)); + +cairo_private cairo_int_status_t +_cairo_rtree_insert (cairo_rtree_t *rtree, + int width, + int height, + cairo_rtree_node_t **out); + +cairo_private cairo_int_status_t +_cairo_rtree_evict_random (cairo_rtree_t *rtree, + int width, + int height, + cairo_rtree_node_t **out); + +cairo_private void +_cairo_rtree_foreach (cairo_rtree_t *rtree, + void (*func)(cairo_rtree_node_t *, void *data), + void *data); + +static inline void * +_cairo_rtree_pin (cairo_rtree_t *rtree, cairo_rtree_node_t *node) +{ + assert (node->state == CAIRO_RTREE_NODE_OCCUPIED); + if (! node->pinned) { + cairo_list_move (&node->link, &rtree->pinned); + node->pinned = 1; + } + + return node; +} + +cairo_private void +_cairo_rtree_unpin (cairo_rtree_t *rtree); + +cairo_private void +_cairo_rtree_reset (cairo_rtree_t *rtree); + +cairo_private void +_cairo_rtree_fini (cairo_rtree_t *rtree); + +#endif /* CAIRO_RTREE_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-rtree.c b/local/recipes/libs/cairo/source/src/cairo-rtree.c new file mode 100644 index 0000000000..dbc040929a --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-rtree.c @@ -0,0 +1,388 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Chris Wilson. + * + * Contributor(s): + * Chris Wilson + * + */ + +#include "cairoint.h" + +#include "cairo-error-private.h" +#include "cairo-rtree-private.h" + +cairo_rtree_node_t * +_cairo_rtree_node_create (cairo_rtree_t *rtree, + cairo_rtree_node_t *parent, + int x, + int y, + int width, + int height) +{ + cairo_rtree_node_t *node; + + node = _cairo_freepool_alloc (&rtree->node_freepool); + if (node == NULL) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return NULL; + } + + node->children[0] = NULL; + node->parent = parent; + node->state = CAIRO_RTREE_NODE_AVAILABLE; + node->pinned = FALSE; + node->x = x; + node->y = y; + node->width = width; + node->height = height; + + cairo_list_add (&node->link, &rtree->available); + + return node; +} + +void +_cairo_rtree_node_destroy (cairo_rtree_t *rtree, cairo_rtree_node_t *node) +{ + int i; + + cairo_list_del (&node->link); + + if (node->state == CAIRO_RTREE_NODE_OCCUPIED) { + rtree->destroy (node); + } else { + for (i = 0; i < 4 && node->children[i] != NULL; i++) + _cairo_rtree_node_destroy (rtree, node->children[i]); + } + + _cairo_freepool_free (&rtree->node_freepool, node); +} + +void +_cairo_rtree_node_collapse (cairo_rtree_t *rtree, cairo_rtree_node_t *node) +{ + int i; + + do { + assert (node->state == CAIRO_RTREE_NODE_DIVIDED); + + for (i = 0; i < 4 && node->children[i] != NULL; i++) + if (node->children[i]->state != CAIRO_RTREE_NODE_AVAILABLE) + return; + + for (i = 0; i < 4 && node->children[i] != NULL; i++) + _cairo_rtree_node_destroy (rtree, node->children[i]); + + node->children[0] = NULL; + node->state = CAIRO_RTREE_NODE_AVAILABLE; + cairo_list_move (&node->link, &rtree->available); + } while ((node = node->parent) != NULL); +} + +cairo_status_t +_cairo_rtree_node_insert (cairo_rtree_t *rtree, + cairo_rtree_node_t *node, + int width, + int height, + cairo_rtree_node_t **out) +{ + int w, h, i; + + assert (node->state == CAIRO_RTREE_NODE_AVAILABLE); + assert (node->pinned == FALSE); + + if (node->width - width > rtree->min_size || + node->height - height > rtree->min_size) + { + w = node->width - width; + h = node->height - height; + + i = 0; + node->children[i] = _cairo_rtree_node_create (rtree, node, + node->x, node->y, + width, height); + if (unlikely (node->children[i] == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + i++; + + if (w > rtree->min_size) { + node->children[i] = _cairo_rtree_node_create (rtree, node, + node->x + width, + node->y, + w, height); + if (unlikely (node->children[i] == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + i++; + } + + if (h > rtree->min_size) { + node->children[i] = _cairo_rtree_node_create (rtree, node, + node->x, + node->y + height, + width, h); + if (unlikely (node->children[i] == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + i++; + + if (w > rtree->min_size) { + node->children[i] = _cairo_rtree_node_create (rtree, node, + node->x + width, + node->y + height, + w, h); + if (unlikely (node->children[i] == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + i++; + } + } + + if (i < 4) + node->children[i] = NULL; + + node->state = CAIRO_RTREE_NODE_DIVIDED; + cairo_list_move (&node->link, &rtree->evictable); + node = node->children[0]; + } + + node->state = CAIRO_RTREE_NODE_OCCUPIED; + cairo_list_move (&node->link, &rtree->evictable); + *out = node; + + return CAIRO_STATUS_SUCCESS; +} + +void +_cairo_rtree_node_remove (cairo_rtree_t *rtree, cairo_rtree_node_t *node) +{ + assert (node->state == CAIRO_RTREE_NODE_OCCUPIED); + assert (node->pinned == FALSE); + + rtree->destroy (node); + + node->state = CAIRO_RTREE_NODE_AVAILABLE; + cairo_list_move (&node->link, &rtree->available); + + _cairo_rtree_node_collapse (rtree, node->parent); +} + +cairo_int_status_t +_cairo_rtree_insert (cairo_rtree_t *rtree, + int width, + int height, + cairo_rtree_node_t **out) +{ + cairo_rtree_node_t *node; + + cairo_list_foreach_entry (node, cairo_rtree_node_t, + &rtree->available, link) + { + if (node->width >= width && node->height >= height) + return _cairo_rtree_node_insert (rtree, node, width, height, out); + } + + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static uint32_t +hars_petruska_f54_1_random (void) +{ +#define rol(x,k) ((x << k) | (x >> (32-k))) + static uint32_t x; + return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849; +#undef rol +} + +cairo_int_status_t +_cairo_rtree_evict_random (cairo_rtree_t *rtree, + int width, + int height, + cairo_rtree_node_t **out) +{ + cairo_int_status_t ret = CAIRO_INT_STATUS_UNSUPPORTED; + cairo_rtree_node_t *node, *next; + cairo_list_t tmp_pinned; + int i, cnt; + + cairo_list_init (&tmp_pinned); + + /* propagate pinned from children to root */ + cairo_list_foreach_entry_safe (node, next, + cairo_rtree_node_t, &rtree->pinned, link) { + node = node->parent; + while (node && ! node->pinned) { + node->pinned = 1; + cairo_list_move (&node->link, &tmp_pinned); + node = node->parent; + } + } + + cnt = 0; + cairo_list_foreach_entry (node, cairo_rtree_node_t, + &rtree->evictable, link) + { + if (node->width >= width && node->height >= height) + cnt++; + } + + if (cnt == 0) + goto out; + + cnt = hars_petruska_f54_1_random () % cnt; + cairo_list_foreach_entry (node, cairo_rtree_node_t, + &rtree->evictable, link) + { + if (node->width >= width && node->height >= height && cnt-- == 0) { + if (node->state == CAIRO_RTREE_NODE_OCCUPIED) { + rtree->destroy (node); + } else { + for (i = 0; i < 4 && node->children[i] != NULL; i++) + _cairo_rtree_node_destroy (rtree, node->children[i]); + node->children[0] = NULL; + } + + node->state = CAIRO_RTREE_NODE_AVAILABLE; + cairo_list_move (&node->link, &rtree->available); + + *out = node; + ret = CAIRO_STATUS_SUCCESS; + break; + } + } + +out: + while (! cairo_list_is_empty (&tmp_pinned)) { + node = cairo_list_first_entry (&tmp_pinned, cairo_rtree_node_t, link); + node->pinned = 0; + cairo_list_move (&node->link, &rtree->evictable); + } + return ret; +} + +void +_cairo_rtree_unpin (cairo_rtree_t *rtree) +{ + while (! cairo_list_is_empty (&rtree->pinned)) { + cairo_rtree_node_t *node = cairo_list_first_entry (&rtree->pinned, + cairo_rtree_node_t, + link); + node->pinned = 0; + cairo_list_move (&node->link, &rtree->evictable); + } +} + +void +_cairo_rtree_init (cairo_rtree_t *rtree, + int width, + int height, + int min_size, + int node_size, + void (*destroy) (cairo_rtree_node_t *)) +{ + assert (node_size >= (int) sizeof (cairo_rtree_node_t)); + _cairo_freepool_init (&rtree->node_freepool, node_size); + + cairo_list_init (&rtree->available); + cairo_list_init (&rtree->pinned); + cairo_list_init (&rtree->evictable); + + rtree->min_size = min_size; + rtree->destroy = destroy; + + memset (&rtree->root, 0, sizeof (rtree->root)); + rtree->root.width = width; + rtree->root.height = height; + rtree->root.state = CAIRO_RTREE_NODE_AVAILABLE; + cairo_list_add (&rtree->root.link, &rtree->available); +} + +void +_cairo_rtree_reset (cairo_rtree_t *rtree) +{ + int i; + + if (rtree->root.state == CAIRO_RTREE_NODE_OCCUPIED) { + rtree->destroy (&rtree->root); + } else { + for (i = 0; i < 4 && rtree->root.children[i] != NULL; i++) + _cairo_rtree_node_destroy (rtree, rtree->root.children[i]); + rtree->root.children[0] = NULL; + } + + cairo_list_init (&rtree->available); + cairo_list_init (&rtree->evictable); + cairo_list_init (&rtree->pinned); + + rtree->root.state = CAIRO_RTREE_NODE_AVAILABLE; + rtree->root.pinned = FALSE; + cairo_list_add (&rtree->root.link, &rtree->available); +} + +static void +_cairo_rtree_node_foreach (cairo_rtree_node_t *node, + void (*func)(cairo_rtree_node_t *, void *data), + void *data) +{ + int i; + + for (i = 0; i < 4 && node->children[i] != NULL; i++) + _cairo_rtree_node_foreach(node->children[i], func, data); + + func(node, data); +} + +void +_cairo_rtree_foreach (cairo_rtree_t *rtree, + void (*func)(cairo_rtree_node_t *, void *data), + void *data) +{ + int i; + + if (rtree->root.state == CAIRO_RTREE_NODE_OCCUPIED) { + func(&rtree->root, data); + } else { + for (i = 0; i < 4 && rtree->root.children[i] != NULL; i++) + _cairo_rtree_node_foreach (rtree->root.children[i], func, data); + } +} + +void +_cairo_rtree_fini (cairo_rtree_t *rtree) +{ + int i; + + if (rtree->root.state == CAIRO_RTREE_NODE_OCCUPIED) { + rtree->destroy (&rtree->root); + } else { + for (i = 0; i < 4 && rtree->root.children[i] != NULL; i++) + _cairo_rtree_node_destroy (rtree, rtree->root.children[i]); + } + + _cairo_freepool_fini (&rtree->node_freepool); +} diff --git a/local/recipes/libs/cairo/source/src/cairo-scaled-font-private.h b/local/recipes/libs/cairo/source/src/cairo-scaled-font-private.h new file mode 100644 index 0000000000..64abbe0f51 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-scaled-font-private.h @@ -0,0 +1,200 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + */ + +#ifndef CAIRO_SCALED_FONT_PRIVATE_H +#define CAIRO_SCALED_FONT_PRIVATE_H + +#include "cairo.h" + +#include "cairo-types-private.h" +#include "cairo-list-private.h" +#include "cairo-mutex-type-private.h" +#include "cairo-reference-count-private.h" + +CAIRO_BEGIN_DECLS + +typedef struct _cairo_scaled_glyph_page cairo_scaled_glyph_page_t; + +struct _cairo_scaled_font { + /* For most cairo objects, the rule for multiple threads is that + * the user is responsible for any locking if the same object is + * manipulated from multiple threads simultaneously. + * + * However, with the caching that cairo does for scaled fonts, a + * user can easily end up with the same cairo_scaled_font object + * being manipulated from multiple threads without the user ever + * being aware of this, (and in fact, unable to control it). + * + * So, as a special exception, the cairo implementation takes care + * of all locking needed for cairo_scaled_font_t. Most of what is + * in the scaled font is immutable, (which is what allows for the + * sharing in the first place). The things that are modified and + * the locks protecting them are as follows: + * + * 1. The reference count (scaled_font->ref_count) + * + * Modifications to the reference count are protected by the + * _cairo_scaled_font_map_mutex. This is because the reference + * count of a scaled font is intimately related with the font + * map itself, (and the magic holdovers array). + * + * 2. The cache of glyphs (scaled_font->glyphs) + * 3. The backend private data (scaled_font->surface_backend, + * scaled_font->surface_private) + * + * Modifications to these fields are protected with locks on + * scaled_font->mutex in the generic scaled_font code. + */ + + cairo_hash_entry_t hash_entry; + + /* useful bits for _cairo_scaled_font_nil */ + cairo_status_t status; + cairo_reference_count_t ref_count; + cairo_user_data_array_t user_data; + + cairo_font_face_t *original_font_face; /* may be NULL */ + + /* hash key members */ + cairo_font_face_t *font_face; /* may be NULL */ + cairo_matrix_t font_matrix; /* font space => user space */ + cairo_matrix_t ctm; /* user space => device space */ + cairo_font_options_t options; + + unsigned int placeholder : 1; /* protected by fontmap mutex */ + unsigned int holdover : 1; + unsigned int finished : 1; + + /* "live" scaled_font members */ + cairo_matrix_t scale; /* font space => device space */ + cairo_matrix_t scale_inverse; /* device space => font space */ + double max_scale; /* maximum x/y expansion of scale */ + cairo_font_extents_t extents; /* user space */ + cairo_font_extents_t fs_extents; /* font space */ + + /* The mutex protects modification to all subsequent fields. */ + cairo_recursive_mutex_t mutex; + + cairo_hash_table_t *glyphs; + cairo_list_t glyph_pages; + cairo_bool_t cache_frozen; + cairo_bool_t global_cache_frozen; + cairo_array_t recording_surfaces_to_free; /* array of cairo_surface_t* */ + + cairo_list_t dev_privates; + + /* font backend managing this scaled font */ + const cairo_scaled_font_backend_t *backend; + cairo_list_t link; +}; + +struct _cairo_scaled_font_private { + cairo_list_t link; + const void *key; + void (*destroy) (cairo_scaled_font_private_t *, + cairo_scaled_font_t *); +}; + +struct _cairo_scaled_glyph { + cairo_hash_entry_t hash_entry; + + cairo_text_extents_t metrics; /* user-space metrics */ + cairo_text_extents_t fs_metrics; /* font-space metrics */ + cairo_box_t bbox; /* device-space bounds */ + int16_t x_advance; /* device-space rounded X advance */ + int16_t y_advance; /* device-space rounded Y advance */ + + unsigned int has_info; + cairo_image_surface_t *surface; /* device-space image */ + cairo_path_fixed_t *path; /* device-space outline */ + cairo_surface_t *recording_surface; /* device-space recording-surface */ + cairo_image_surface_t *color_surface; /* device-space color image */ + + const void *dev_private_key; + void *dev_private; + cairo_list_t dev_privates; + + cairo_color_t foreground_color; /* only used for color glyphs */ + + /* TRUE if the recording_surface used the foreground_source to render. */ + unsigned recording_uses_foreground_color : 1; + + /* TRUE if the recording surface uses the foreground marker. */ + unsigned recording_uses_foreground_marker : 1; + + /* TRUE if color_glyph specifies if glyph is color or non color, FALSE if glyph color type unknown. */ + unsigned color_glyph_set : 1; + + unsigned color_glyph : 1; +}; + +struct _cairo_scaled_glyph_private { + cairo_list_t link; + const void *key; + void (*destroy) (cairo_scaled_glyph_private_t *, + cairo_scaled_glyph_t *, + cairo_scaled_font_t *); +}; + +cairo_private cairo_scaled_font_private_t * +_cairo_scaled_font_find_private (cairo_scaled_font_t *scaled_font, + const void *key); + +cairo_private void +_cairo_scaled_font_attach_private (cairo_scaled_font_t *scaled_font, + cairo_scaled_font_private_t *priv, + const void *key, + void (*destroy) (cairo_scaled_font_private_t *, + cairo_scaled_font_t *)); + +cairo_private cairo_scaled_glyph_private_t * +_cairo_scaled_glyph_find_private (cairo_scaled_glyph_t *scaled_glyph, + const void *key); + +cairo_private void +_cairo_scaled_glyph_attach_private (cairo_scaled_glyph_t *scaled_glyph, + cairo_scaled_glyph_private_t *priv, + const void *key, + void (*destroy) (cairo_scaled_glyph_private_t *, + cairo_scaled_glyph_t *, + cairo_scaled_font_t *)); +cairo_private cairo_bool_t +_cairo_scaled_font_has_color_glyphs (cairo_scaled_font_t *scaled_font); + +CAIRO_END_DECLS + +#endif /* CAIRO_SCALED_FONT_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-scaled-font-subsets-private.h b/local/recipes/libs/cairo/source/src/cairo-scaled-font-subsets-private.h new file mode 100644 index 0000000000..2599bb6c35 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-scaled-font-subsets-private.h @@ -0,0 +1,710 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2006 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + */ + +#ifndef CAIRO_SCALED_FONT_SUBSETS_PRIVATE_H +#define CAIRO_SCALED_FONT_SUBSETS_PRIVATE_H + +#include "cairoint.h" + +#if CAIRO_HAS_FONT_SUBSET + +CAIRO_BEGIN_DECLS + +typedef struct _cairo_scaled_font_subsets_glyph { + unsigned int font_id; + unsigned int subset_id; + unsigned int subset_glyph_index; + cairo_bool_t is_scaled; + cairo_bool_t is_composite; + cairo_bool_t is_latin; + double x_advance; + double y_advance; + cairo_bool_t utf8_is_mapped; + uint32_t unicode; +} cairo_scaled_font_subsets_glyph_t; + +/** + * _cairo_scaled_font_subsets_create_scaled: + * + * Create a new #cairo_scaled_font_subsets_t object which can be used + * to create subsets of any number of #cairo_scaled_font_t + * objects. This allows the (arbitrarily large and sparse) glyph + * indices of a #cairo_scaled_font_t to be mapped to one or more font + * subsets with glyph indices packed into the range + * [0 .. max_glyphs_per_subset). + * + * Return value: a pointer to the newly creates font subsets. The + * caller owns this object and should call + * _cairo_scaled_font_subsets_destroy() when done with it. + **/ +cairo_private cairo_scaled_font_subsets_t * +_cairo_scaled_font_subsets_create_scaled (void); + +/** + * _cairo_scaled_font_subsets_create_simple: + * + * Create a new #cairo_scaled_font_subsets_t object which can be used + * to create font subsets suitable for embedding as Postscript or PDF + * simple fonts. + * + * Glyphs with an outline path available will be mapped to one font + * subset for each font face. Glyphs from bitmap fonts will mapped to + * separate font subsets for each #cairo_scaled_font_t object. + * + * The maximum number of glyphs per subset is 256. Each subset + * reserves the first glyph for the .notdef glyph. + * + * Return value: a pointer to the newly creates font subsets. The + * caller owns this object and should call + * _cairo_scaled_font_subsets_destroy() when done with it. + **/ +cairo_private cairo_scaled_font_subsets_t * +_cairo_scaled_font_subsets_create_simple (void); + +/** + * _cairo_scaled_font_subsets_create_composite: + * + * Create a new #cairo_scaled_font_subsets_t object which can be used + * to create font subsets suitable for embedding as Postscript or PDF + * composite fonts. + * + * Glyphs with an outline path available will be mapped to one font + * subset for each font face. Each unscaled subset has a maximum of + * 65536 glyphs except for Type1 fonts which have a maximum of 256 glyphs. + * + * Glyphs from bitmap fonts will mapped to separate font subsets for + * each #cairo_scaled_font_t object. Each unscaled subset has a maximum + * of 256 glyphs. + * + * Each subset reserves the first glyph for the .notdef glyph. + * + * Return value: a pointer to the newly creates font subsets. The + * caller owns this object and should call + * _cairo_scaled_font_subsets_destroy() when done with it. + **/ +cairo_private cairo_scaled_font_subsets_t * +_cairo_scaled_font_subsets_create_composite (void); + +/** + * _cairo_scaled_font_subsets_destroy: + * @font_subsets: a #cairo_scaled_font_subsets_t object to be destroyed + * + * Destroys @font_subsets and all resources associated with it. + **/ +cairo_private void +_cairo_scaled_font_subsets_destroy (cairo_scaled_font_subsets_t *font_subsets); + +/** + * _cairo_scaled_font_subsets_enable_latin_subset: + * @font_subsets: a #cairo_scaled_font_subsets_t object to be destroyed + * @use_latin: a #cairo_bool_t indicating if a latin subset is to be used + * + * If enabled, all CP1252 characters will be placed in a separate + * 8-bit latin subset. + **/ +cairo_private void +_cairo_scaled_font_subsets_enable_latin_subset (cairo_scaled_font_subsets_t *font_subsets, + cairo_bool_t use_latin); + +/** + * _cairo_scaled_font_subsets_map_glyph: + * @font_subsets: a #cairo_scaled_font_subsets_t + * @scaled_font: the font of the glyph to be mapped + * @scaled_font_glyph_index: the index of the glyph to be mapped + * @utf8: a string of text encoded in UTF-8 + * @utf8_len: length of @utf8 in bytes + * @subset_glyph_ret: return structure containing subset font and glyph id + * + * Map a glyph from a #cairo_scaled_font to a new index within a + * subset of that font. The mapping performed is from the tuple: + * + * (scaled_font, scaled_font_glyph_index) + * + * to the tuple: + * + * (font_id, subset_id, subset_glyph_index) + * + * This mapping is 1:1. If the input tuple has previously mapped, the + * the output tuple previously returned will be returned again. + * + * Otherwise, the return tuple will be constructed as follows: + * + * 1) There is a 1:1 correspondence between the input scaled_font + * value and the output font_id value. If no mapping has been + * previously performed with the scaled_font value then the + * smallest unused font_id value will be returned. + * + * 2) Within the set of output tuples of the same font_id value the + * smallest value of subset_id will be returned such that + * subset_glyph_index does not exceed max_glyphs_per_subset (as + * passed to _cairo_scaled_font_subsets_create()) and that the + * resulting tuple is unique. + * + * 3) The smallest value of subset_glyph_index is returned such that + * the resulting tuple is unique. + * + * The net result is that any #cairo_scaled_font_t will be represented + * by one or more font subsets. Each subset is effectively a tuple of + * (scaled_font, font_id, subset_id) and within each subset there + * exists a mapping of scaled_glyph_font_index to subset_glyph_index. + * + * This final description of a font subset is the same representation + * used by #cairo_scaled_font_subset_t as provided by + * _cairo_scaled_font_subsets_foreach. + * + * @utf8 and @utf8_len specify a string of unicode characters that the + * glyph @scaled_font_glyph_index maps to. If @utf8_is_mapped in + * @subset_glyph_ret is %TRUE, the font subsetting will (where index to + * unicode mapping is supported) ensure that @scaled_font_glyph_index + * maps to @utf8. If @utf8_is_mapped is %FALSE, + * @scaled_font_glyph_index has already been mapped to a different + * unicode string. + * + * The returned values in the #cairo_scaled_font_subsets_glyph_t struct are: + * + * @font_id: The font ID of the mapped glyph + * @subset_id : The subset ID of the mapped glyph within the @font_id + * @subset_glyph_index: The index of the mapped glyph within the @subset_id subset + * @is_scaled: If true, the mapped glyph is from a bitmap font, and separate font + * subset is created for each font scale used. If false, the outline of the mapped glyph + * is available. One font subset for each font face is created. + * @x_advance, @y_advance: When @is_scaled is true, @x_advance and @y_advance contain + * the x and y advance for the mapped glyph in device space. + * When @is_scaled is false, @x_advance and @y_advance contain the x and y advance for + * the mapped glyph from an unhinted 1 point font. + * @utf8_is_mapped: If true the utf8 string provided to _cairo_scaled_font_subsets_map_glyph() + * is (or already was) the utf8 string mapped to this glyph. If false the glyph is already + * mapped to a different utf8 string. + * @unicode: the unicode character mapped to this glyph by the font backend. + * + * Return value: %CAIRO_STATUS_SUCCESS if successful, or a non-zero + * value indicating an error. Possible errors include + * %CAIRO_STATUS_NO_MEMORY. + **/ +cairo_private cairo_status_t +_cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *font_subsets, + cairo_scaled_font_t *scaled_font, + unsigned long scaled_font_glyph_index, + const char * utf8, + int utf8_len, + cairo_scaled_font_subsets_glyph_t *subset_glyph_ret); + +typedef cairo_int_status_t +(*cairo_scaled_font_subset_callback_func_t) (cairo_scaled_font_subset_t *font_subset, + void *closure); + +/** + * _cairo_scaled_font_subsets_foreach_scaled: + * @font_subsets: a #cairo_scaled_font_subsets_t + * @font_subset_callback: a function to be called for each font subset + * @closure: closure data for the callback function + * + * Iterate over each unique scaled font subset as created by calls to + * _cairo_scaled_font_subsets_map_glyph(). A subset is determined by + * unique pairs of (font_id, subset_id) as returned by + * _cairo_scaled_font_subsets_map_glyph(). + * + * For each subset, @font_subset_callback will be called and will be + * provided with both a #cairo_scaled_font_subset_t object containing + * all the glyphs in the subset as well as the value of @closure. + * + * The #cairo_scaled_font_subset_t object contains the scaled_font, + * the font_id, and the subset_id corresponding to all glyphs + * belonging to the subset. In addition, it contains an array providing + * a mapping between subset glyph indices and the original scaled font + * glyph indices. + * + * The index of the array corresponds to subset_glyph_index values + * returned by _cairo_scaled_font_subsets_map_glyph() while the + * values of the array correspond to the scaled_font_glyph_index + * values passed as input to the same function. + * + * Return value: %CAIRO_STATUS_SUCCESS if successful, or a non-zero + * value indicating an error. Possible errors include + * %CAIRO_STATUS_NO_MEMORY. + **/ +cairo_private cairo_status_t +_cairo_scaled_font_subsets_foreach_scaled (cairo_scaled_font_subsets_t *font_subsets, + cairo_scaled_font_subset_callback_func_t font_subset_callback, + void *closure); + +/** + * _cairo_scaled_font_subsets_foreach_unscaled: + * @font_subsets: a #cairo_scaled_font_subsets_t + * @font_subset_callback: a function to be called for each font subset + * @closure: closure data for the callback function + * + * Iterate over each unique unscaled font subset as created by calls to + * _cairo_scaled_font_subsets_map_glyph(). A subset is determined by + * unique pairs of (font_id, subset_id) as returned by + * _cairo_scaled_font_subsets_map_glyph(). + * + * For each subset, @font_subset_callback will be called and will be + * provided with both a #cairo_scaled_font_subset_t object containing + * all the glyphs in the subset as well as the value of @closure. + * + * The #cairo_scaled_font_subset_t object contains the scaled_font, + * the font_id, and the subset_id corresponding to all glyphs + * belonging to the subset. In addition, it contains an array providing + * a mapping between subset glyph indices and the original scaled font + * glyph indices. + * + * The index of the array corresponds to subset_glyph_index values + * returned by _cairo_scaled_font_subsets_map_glyph() while the + * values of the array correspond to the scaled_font_glyph_index + * values passed as input to the same function. + * + * Return value: %CAIRO_STATUS_SUCCESS if successful, or a non-zero + * value indicating an error. Possible errors include + * %CAIRO_STATUS_NO_MEMORY. + **/ +cairo_private cairo_status_t +_cairo_scaled_font_subsets_foreach_unscaled (cairo_scaled_font_subsets_t *font_subsets, + cairo_scaled_font_subset_callback_func_t font_subset_callback, + void *closure); + +/** + * _cairo_scaled_font_subset_create_glyph_names: + * @font_subsets: a #cairo_scaled_font_subsets_t + * + * Create an array of strings containing the glyph name for each glyph + * in @font_subsets. The array as store in font_subsets->glyph_names. + * + * Return value: %CAIRO_STATUS_SUCCESS if successful, + * %CAIRO_INT_STATUS_UNSUPPORTED if the font backend does not support + * mapping the glyph indices to unicode characters. Possible errors + * include %CAIRO_STATUS_NO_MEMORY. + **/ +cairo_private cairo_int_status_t +_cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset); + +typedef struct _cairo_cff_subset { + char *family_name_utf8; + char *ps_name; + double *widths; + double x_min, y_min, x_max, y_max; + double ascent, descent; + char *data; + unsigned long data_length; +} cairo_cff_subset_t; + +/** + * _cairo_cff_subset_init: + * @cff_subset: a #cairo_cff_subset_t to initialize + * @font_subset: the #cairo_scaled_font_subset_t to initialize from + * + * If possible (depending on the format of the underlying + * #cairo_scaled_font_t and the font backend in use) generate a + * cff file corresponding to @font_subset and initialize + * @cff_subset with information about the subset and the cff + * data. + * + * Return value: %CAIRO_STATUS_SUCCESS if successful, + * %CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a + * cff file, or an non-zero value indicating an error. Possible + * errors include %CAIRO_STATUS_NO_MEMORY. + **/ +cairo_private cairo_status_t +_cairo_cff_subset_init (cairo_cff_subset_t *cff_subset, + const char *name, + cairo_scaled_font_subset_t *font_subset); + +/** + * _cairo_cff_subset_fini: + * @cff_subset: a #cairo_cff_subset_t + * + * Free all resources associated with @cff_subset. After this + * call, @cff_subset should not be used again without a + * subsequent call to _cairo_cff_subset_init() again first. + **/ +cairo_private void +_cairo_cff_subset_fini (cairo_cff_subset_t *cff_subset); + +/** + * _cairo_cff_scaled_font_is_cid_cff: + * @scaled_font: a #cairo_scaled_font_t + * + * Return %TRUE if @scaled_font is a CID CFF font, otherwise return %FALSE. + **/ +cairo_private cairo_bool_t +_cairo_cff_scaled_font_is_cid_cff (cairo_scaled_font_t *scaled_font); + +/** + * _cairo_cff_fallback_init: + * @cff_subset: a #cairo_cff_subset_t to initialize + * @font_subset: the #cairo_scaled_font_subset_t to initialize from + * + * If possible (depending on the format of the underlying + * #cairo_scaled_font_t and the font backend in use) generate a cff + * file corresponding to @font_subset and initialize @cff_subset + * with information about the subset and the cff data. + * + * Return value: %CAIRO_STATUS_SUCCESS if successful, + * %CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a + * cff file, or an non-zero value indicating an error. Possible + * errors include %CAIRO_STATUS_NO_MEMORY. + **/ +cairo_private cairo_status_t +_cairo_cff_fallback_init (cairo_cff_subset_t *cff_subset, + const char *name, + cairo_scaled_font_subset_t *font_subset); + +/** + * _cairo_cff_fallback_fini: + * @cff_subset: a #cairo_cff_subset_t + * + * Free all resources associated with @cff_subset. After this + * call, @cff_subset should not be used again without a + * subsequent call to _cairo_cff_subset_init() again first. + **/ +cairo_private void +_cairo_cff_fallback_fini (cairo_cff_subset_t *cff_subset); + +typedef struct _cairo_truetype_subset { + char *family_name_utf8; + char *ps_name; + double *widths; + double x_min, y_min, x_max, y_max; + double ascent, descent; + unsigned char *data; + unsigned long data_length; + unsigned long *string_offsets; + unsigned long num_string_offsets; +} cairo_truetype_subset_t; + +/** + * _cairo_truetype_subset_init_ps: + * @truetype_subset: a #cairo_truetype_subset_t to initialize + * @font_subset: the #cairo_scaled_font_subset_t to initialize from + * + * If possible (depending on the format of the underlying + * #cairo_scaled_font_t and the font backend in use) generate a + * truetype file corresponding to @font_subset and initialize + * @truetype_subset with information about the subset and the truetype + * data. The generated font will be suitable for embedding in + * PostScript. + * + * Return value: %CAIRO_STATUS_SUCCESS if successful, + * %CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a + * truetype file, or an non-zero value indicating an error. Possible + * errors include %CAIRO_STATUS_NO_MEMORY. + **/ +cairo_private cairo_status_t +_cairo_truetype_subset_init_ps (cairo_truetype_subset_t *truetype_subset, + cairo_scaled_font_subset_t *font_subset); + +/** + * _cairo_truetype_subset_init_pdf: + * @truetype_subset: a #cairo_truetype_subset_t to initialize + * @font_subset: the #cairo_scaled_font_subset_t to initialize from + * + * If possible (depending on the format of the underlying + * #cairo_scaled_font_t and the font backend in use) generate a + * truetype file corresponding to @font_subset and initialize + * @truetype_subset with information about the subset and the truetype + * data. The generated font will be suitable for embedding in + * PDF. + * + * Return value: %CAIRO_STATUS_SUCCESS if successful, + * %CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a + * truetype file, or an non-zero value indicating an error. Possible + * errors include %CAIRO_STATUS_NO_MEMORY. + **/ +cairo_private cairo_status_t +_cairo_truetype_subset_init_pdf (cairo_truetype_subset_t *truetype_subset, + cairo_scaled_font_subset_t *font_subset); + +/** + * _cairo_truetype_subset_fini: + * @truetype_subset: a #cairo_truetype_subset_t + * + * Free all resources associated with @truetype_subset. After this + * call, @truetype_subset should not be used again without a + * subsequent call to _cairo_truetype_subset_init() again first. + **/ +cairo_private void +_cairo_truetype_subset_fini (cairo_truetype_subset_t *truetype_subset); + +cairo_private const char * +_cairo_ps_standard_encoding_to_glyphname (int glyph); + +cairo_private int +_cairo_unicode_to_winansi (unsigned long unicode); + +cairo_private const char * +_cairo_winansi_to_glyphname (int glyph); + +typedef struct _cairo_type1_subset { + char *base_font; + double *widths; + double x_min, y_min, x_max, y_max; + double ascent, descent; + char *data; + unsigned long header_length; + unsigned long data_length; + unsigned long trailer_length; +} cairo_type1_subset_t; + + +/** + * _cairo_type1_subset_init: + * @type1_subset: a #cairo_type1_subset_t to initialize + * @font_subset: the #cairo_scaled_font_subset_t to initialize from + * @hex_encode: if true the encrypted portion of the font is hex encoded + * + * If possible (depending on the format of the underlying + * #cairo_scaled_font_t and the font backend in use) generate a type1 + * file corresponding to @font_subset and initialize @type1_subset + * with information about the subset and the type1 data. + * + * Return value: %CAIRO_STATUS_SUCCESS if successful, + * %CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a type1 + * file, or an non-zero value indicating an error. Possible errors + * include %CAIRO_STATUS_NO_MEMORY. + **/ +cairo_private cairo_status_t +_cairo_type1_subset_init (cairo_type1_subset_t *type_subset, + const char *name, + cairo_scaled_font_subset_t *font_subset, + cairo_bool_t hex_encode); + +/** + * _cairo_type1_subset_fini: + * @type1_subset: a #cairo_type1_subset_t + * + * Free all resources associated with @type1_subset. After this call, + * @type1_subset should not be used again without a subsequent call to + * _cairo_truetype_type1_init() again first. + **/ +cairo_private void +_cairo_type1_subset_fini (cairo_type1_subset_t *subset); + +/** + * _cairo_type1_scaled_font_is_type1: + * @scaled_font: a #cairo_scaled_font_t + * + * Return %TRUE if @scaled_font is a Type 1 font, otherwise return %FALSE. + **/ +cairo_private cairo_bool_t +_cairo_type1_scaled_font_is_type1 (cairo_scaled_font_t *scaled_font); + +/** + * _cairo_type1_fallback_init_binary: + * @type1_subset: a #cairo_type1_subset_t to initialize + * @font_subset: the #cairo_scaled_font_subset_t to initialize from + * + * If possible (depending on the format of the underlying + * #cairo_scaled_font_t and the font backend in use) generate a type1 + * file corresponding to @font_subset and initialize @type1_subset + * with information about the subset and the type1 data. The encrypted + * part of the font is binary encoded. + * + * Return value: %CAIRO_STATUS_SUCCESS if successful, + * %CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a type1 + * file, or an non-zero value indicating an error. Possible errors + * include %CAIRO_STATUS_NO_MEMORY. + **/ +cairo_private cairo_status_t +_cairo_type1_fallback_init_binary (cairo_type1_subset_t *type_subset, + const char *name, + cairo_scaled_font_subset_t *font_subset); + +/** + * _cairo_type1_fallback_init_hex: + * @type1_subset: a #cairo_type1_subset_t to initialize + * @font_subset: the #cairo_scaled_font_subset_t to initialize from + * + * If possible (depending on the format of the underlying + * #cairo_scaled_font_t and the font backend in use) generate a type1 + * file corresponding to @font_subset and initialize @type1_subset + * with information about the subset and the type1 data. The encrypted + * part of the font is hex encoded. + * + * Return value: %CAIRO_STATUS_SUCCESS if successful, + * %CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a type1 + * file, or an non-zero value indicating an error. Possible errors + * include %CAIRO_STATUS_NO_MEMORY. + **/ +cairo_private cairo_status_t +_cairo_type1_fallback_init_hex (cairo_type1_subset_t *type_subset, + const char *name, + cairo_scaled_font_subset_t *font_subset); + +/** + * _cairo_type1_fallback_fini: + * @type1_subset: a #cairo_type1_subset_t + * + * Free all resources associated with @type1_subset. After this call, + * @type1_subset should not be used again without a subsequent call to + * _cairo_truetype_type1_init() again first. + **/ +cairo_private void +_cairo_type1_fallback_fini (cairo_type1_subset_t *subset); + +typedef struct _cairo_type2_charstrings { + int *widths; + long x_min, y_min, x_max, y_max; + long ascent, descent; + cairo_array_t charstrings; +} cairo_type2_charstrings_t; + +/** + * _cairo_type2_charstrings_init: + * @type2_subset: a #cairo_type2_subset_t to initialize + * @font_subset: the #cairo_scaled_font_subset_t to initialize from + * + * If possible (depending on the format of the underlying + * #cairo_scaled_font_t and the font backend in use) generate type2 + * charstrings to @font_subset and initialize @type2_subset + * with information about the subset. + * + * Return value: %CAIRO_STATUS_SUCCESS if successful, + * %CAIRO_INT_STATUS_UNSUPPORTED if the font can't be subset as a type2 + * charstrings, or an non-zero value indicating an error. Possible errors + * include %CAIRO_STATUS_NO_MEMORY. + **/ +cairo_private cairo_status_t +_cairo_type2_charstrings_init (cairo_type2_charstrings_t *charstrings, + cairo_scaled_font_subset_t *font_subset); + +/** + * _cairo_type2_charstrings_fini: + * @subset: a #cairo_type2_charstrings_t + * + * Free all resources associated with @type2_charstring. After this call, + * @type2_charstring should not be used again without a subsequent call to + * _cairo_type2_charstring_init() again first. + **/ +cairo_private void +_cairo_type2_charstrings_fini (cairo_type2_charstrings_t *charstrings); + +/** + * _cairo_truetype_index_to_ucs4: + * @scaled_font: the #cairo_scaled_font_t + * @index: the glyph index + * @ucs4: return value for the unicode value of the glyph + * + * If possible (depending on the format of the underlying + * #cairo_scaled_font_t and the font backend in use) assign + * the unicode character of the glyph to @ucs4. + * + * If mapping glyph indices to unicode is supported but the unicode + * value of the specified glyph is not available, @ucs4 is set to -1. + * + * Return value: %CAIRO_STATUS_SUCCESS if successful, + * %CAIRO_INT_STATUS_UNSUPPORTED if mapping glyph indices to unicode + * is not supported. Possible errors include %CAIRO_STATUS_NO_MEMORY. + **/ +cairo_private cairo_int_status_t +_cairo_truetype_index_to_ucs4 (cairo_scaled_font_t *scaled_font, + unsigned long index, + uint32_t *ucs4); + +/** + * _cairo_truetype_read_font_name: + * @scaled_font: the #cairo_scaled_font_t + * @ps_name: returns the PostScript name of the font + * or %NULL if the name could not be found. + * @font_name: returns the font name or %NULL if the name could not be found. + * + * If possible (depending on the format of the underlying + * #cairo_scaled_font_t and the font backend in use) read the + * PostScript and Font names from a TrueType/OpenType font. + * + * The font name is the full name of the font eg "DejaVu Sans Bold". + * The PostScript name is a shortened name with spaces removed + * suitable for use as the font name in a PS or PDF file eg + * "DejaVuSans-Bold". + * + * Return value: %CAIRO_STATUS_SUCCESS if successful, + * %CAIRO_INT_STATUS_UNSUPPORTED if the font is not TrueType/OpenType + * or the name table is not present. Possible errors include + * %CAIRO_STATUS_NO_MEMORY. + **/ +cairo_private cairo_int_status_t +_cairo_truetype_read_font_name (cairo_scaled_font_t *scaled_font, + char **ps_name, + char **font_name); + +/** + * _cairo_truetype_get_style: + * @scaled_font: the #cairo_scaled_font_t + * @weight: returns the font weight from the OS/2 table + * @bold: returns true if font is bold + * @italic: returns true if font is italic + * + * If the font is a truetype/opentype font with an OS/2 table, get the + * weight, bold, and italic data from the OS/2 table. The weight + * values have the same meaning as the lfWeight field of the Windows + * LOGFONT structure. Refer to the TrueType Specification for + * definition of the weight values. + * + * Return value: %CAIRO_STATUS_SUCCESS if successful, + * %CAIRO_INT_STATUS_UNSUPPORTED if the font is not TrueType/OpenType + * or the OS/2 table is not present. + **/ +cairo_private cairo_int_status_t +_cairo_truetype_get_style (cairo_scaled_font_t *scaled_font, + int *weight, + cairo_bool_t *bold, + cairo_bool_t *italic); + +/** + * _cairo_escape_ps_name: + * @ps_name: returns the PostScript name with all invalid characters escaped + * + * Ensure that PostSript name is a valid PDF/PostSript name object. + * In PDF names are treated as UTF8 and non ASCII bytes, ' ', + * and '#' are encoded as '#' followed by 2 hex digits that + * encode the byte. + * + * Return value: %CAIRO_STATUS_SUCCESS if successful. Possible errors include + * %CAIRO_STATUS_NO_MEMORY. + **/ +cairo_private cairo_int_status_t +_cairo_escape_ps_name (char **ps_name); + +#if DEBUG_SUBSETS +cairo_private void +dump_scaled_font_subsets (cairo_scaled_font_subsets_t *font_subsets); +#endif + +CAIRO_END_DECLS + + +#endif /* CAIRO_HAS_FONT_SUBSET */ + +#endif /* CAIRO_SCALED_FONT_SUBSETS_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-scaled-font-subsets.c b/local/recipes/libs/cairo/source/src/cairo-scaled-font-subsets.c new file mode 100644 index 0000000000..f15f819a02 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-scaled-font-subsets.c @@ -0,0 +1,1375 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2003 University of Southern California + * Copyright © 2005 Red Hat, Inc + * Copyright © 2006 Keith Packard + * Copyright © 2006 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Kristian Høgsberg + * Keith Packard + * Adrian Johnson + */ + +#define _DEFAULT_SOURCE /* for snprintf(), strdup() */ +#include "cairoint.h" +#include "cairo-error-private.h" + +#if CAIRO_HAS_FONT_SUBSET + +#include "cairo-scaled-font-subsets-private.h" +#include "cairo-user-font-private.h" + +#define MAX_GLYPHS_PER_SIMPLE_FONT 256 +#define MAX_GLYPHS_PER_COMPOSITE_FONT 65536 + +typedef enum { + CAIRO_SUBSETS_SCALED, + CAIRO_SUBSETS_SIMPLE, + CAIRO_SUBSETS_COMPOSITE +} cairo_subsets_type_t; + +typedef enum { + CAIRO_SUBSETS_FOREACH_UNSCALED, + CAIRO_SUBSETS_FOREACH_SCALED, +} cairo_subsets_foreach_type_t; + +typedef struct _cairo_sub_font { + cairo_hash_entry_t base; + + cairo_bool_t is_scaled; + cairo_bool_t is_composite; + cairo_bool_t use_latin_subset; + cairo_bool_t reserve_notdef; + cairo_scaled_font_subsets_t *parent; + cairo_scaled_font_t *scaled_font; + unsigned int font_id; + + int current_subset; + int num_glyphs_in_current_subset; + int num_glyphs_in_latin_subset; + int max_glyphs_per_subset; + char latin_char_map[256]; + + cairo_hash_table_t *sub_font_glyphs; + struct _cairo_sub_font *next; +} cairo_sub_font_t; + +struct _cairo_scaled_font_subsets { + cairo_subsets_type_t type; + cairo_bool_t use_latin_subset; + + int max_glyphs_per_unscaled_subset_used; + cairo_hash_table_t *unscaled_sub_fonts; + cairo_sub_font_t *unscaled_sub_fonts_list; + cairo_sub_font_t *unscaled_sub_fonts_list_end; + + int max_glyphs_per_scaled_subset_used; + cairo_hash_table_t *scaled_sub_fonts; + cairo_sub_font_t *scaled_sub_fonts_list; + cairo_sub_font_t *scaled_sub_fonts_list_end; + + int num_sub_fonts; +}; + +typedef struct _cairo_sub_font_glyph { + cairo_hash_entry_t base; + + unsigned int subset_id; + unsigned int subset_glyph_index; + double x_advance; + double y_advance; + + cairo_bool_t is_latin; + int latin_character; + cairo_bool_t is_mapped; + uint32_t unicode; + char *utf8; + int utf8_len; +} cairo_sub_font_glyph_t; + +typedef struct _cairo_sub_font_collection { + unsigned long *glyphs; /* scaled_font_glyph_index */ + char **utf8; + unsigned int glyphs_size; + int *to_latin_char; + unsigned long *latin_to_subset_glyph_index; + unsigned int max_glyph; + unsigned int num_glyphs; + + unsigned int subset_id; + + cairo_status_t status; + cairo_scaled_font_subset_callback_func_t font_subset_callback; + void *font_subset_callback_closure; +} cairo_sub_font_collection_t; + +typedef struct _cairo_string_entry { + cairo_hash_entry_t base; + char *string; +} cairo_string_entry_t; + +static cairo_status_t +_cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font, + unsigned long scaled_font_glyph_index, + const char * utf8, + int utf8_len, + cairo_scaled_font_subsets_glyph_t *subset_glyph); + +static void +_cairo_sub_font_glyph_init_key (cairo_sub_font_glyph_t *sub_font_glyph, + unsigned long scaled_font_glyph_index) +{ + sub_font_glyph->base.hash = scaled_font_glyph_index; +} + +static cairo_sub_font_glyph_t * +_cairo_sub_font_glyph_create (unsigned long scaled_font_glyph_index, + unsigned int subset_id, + unsigned int subset_glyph_index, + double x_advance, + double y_advance, + int latin_character, + uint32_t unicode, + char *utf8, + int utf8_len) +{ + cairo_sub_font_glyph_t *sub_font_glyph; + + sub_font_glyph = _cairo_calloc (sizeof (cairo_sub_font_glyph_t)); + if (unlikely (sub_font_glyph == NULL)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return NULL; + } + + _cairo_sub_font_glyph_init_key (sub_font_glyph, scaled_font_glyph_index); + sub_font_glyph->subset_id = subset_id; + sub_font_glyph->subset_glyph_index = subset_glyph_index; + sub_font_glyph->x_advance = x_advance; + sub_font_glyph->y_advance = y_advance; + sub_font_glyph->is_latin = (latin_character >= 0); + sub_font_glyph->latin_character = latin_character; + sub_font_glyph->is_mapped = FALSE; + sub_font_glyph->unicode = unicode; + sub_font_glyph->utf8 = utf8; + sub_font_glyph->utf8_len = utf8_len; + + return sub_font_glyph; +} + +static void +_cairo_sub_font_glyph_destroy (cairo_sub_font_glyph_t *sub_font_glyph) +{ + free (sub_font_glyph->utf8); + + free (sub_font_glyph); +} + +static void +_cairo_sub_font_glyph_pluck (void *entry, void *closure) +{ + cairo_sub_font_glyph_t *sub_font_glyph = entry; + cairo_hash_table_t *sub_font_glyphs = closure; + + _cairo_hash_table_remove (sub_font_glyphs, &sub_font_glyph->base); + _cairo_sub_font_glyph_destroy (sub_font_glyph); +} + +static void +_cairo_sub_font_glyph_collect (void *entry, void *closure) +{ + cairo_sub_font_glyph_t *sub_font_glyph = entry; + cairo_sub_font_collection_t *collection = closure; + unsigned long scaled_font_glyph_index; + unsigned int subset_glyph_index; + + if (sub_font_glyph->subset_id != collection->subset_id) + return; + + scaled_font_glyph_index = sub_font_glyph->base.hash; + subset_glyph_index = sub_font_glyph->subset_glyph_index; + + /* Ensure we don't exceed the allocated bounds. */ + assert (subset_glyph_index < collection->glyphs_size); + + collection->glyphs[subset_glyph_index] = scaled_font_glyph_index; + collection->utf8[subset_glyph_index] = sub_font_glyph->utf8; + collection->to_latin_char[subset_glyph_index] = sub_font_glyph->latin_character; + if (sub_font_glyph->is_latin) + collection->latin_to_subset_glyph_index[sub_font_glyph->latin_character] = subset_glyph_index; + + if (subset_glyph_index > collection->max_glyph) + collection->max_glyph = subset_glyph_index; + + collection->num_glyphs++; +} + +static cairo_bool_t +_cairo_sub_fonts_equal (const void *key_a, const void *key_b) +{ + const cairo_sub_font_t *sub_font_a = key_a; + const cairo_sub_font_t *sub_font_b = key_b; + cairo_scaled_font_t *a = sub_font_a->scaled_font; + cairo_scaled_font_t *b = sub_font_b->scaled_font; + + if (sub_font_a->is_scaled) + return a == b; + else + return a->font_face == b->font_face || a->original_font_face == b->original_font_face; +} + +static void +_cairo_sub_font_init_key (cairo_sub_font_t *sub_font, + cairo_scaled_font_t *scaled_font) +{ + if (sub_font->is_scaled) + { + sub_font->base.hash = (uintptr_t) scaled_font; + sub_font->scaled_font = scaled_font; + } + else + { + sub_font->base.hash = (uintptr_t) scaled_font->font_face; + sub_font->scaled_font = scaled_font; + } +} + +static cairo_status_t +_cairo_sub_font_create (cairo_scaled_font_subsets_t *parent, + cairo_scaled_font_t *scaled_font, + unsigned int font_id, + int max_glyphs_per_subset, + cairo_bool_t is_scaled, + cairo_bool_t is_composite, + cairo_sub_font_t **sub_font_out) +{ + cairo_sub_font_t *sub_font; + int i; + + sub_font = _cairo_calloc (sizeof (cairo_sub_font_t)); + if (unlikely (sub_font == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + sub_font->is_scaled = is_scaled; + sub_font->is_composite = is_composite; + sub_font->reserve_notdef = !sub_font->is_scaled; + _cairo_sub_font_init_key (sub_font, scaled_font); + + sub_font->parent = parent; + sub_font->scaled_font = scaled_font; + sub_font->font_id = font_id; + + sub_font->use_latin_subset = parent->use_latin_subset; + + /* latin subsets of Type 3 and CID CFF fonts are not supported */ + if (sub_font->is_scaled || + _cairo_cff_scaled_font_is_cid_cff (scaled_font) ) + { + sub_font->use_latin_subset = FALSE; + } + + if (sub_font->use_latin_subset) + sub_font->current_subset = 1; /* reserve subset 0 for latin glyphs */ + else + sub_font->current_subset = 0; + + sub_font->num_glyphs_in_current_subset = 0; + sub_font->num_glyphs_in_latin_subset = 0; + sub_font->max_glyphs_per_subset = max_glyphs_per_subset; + for (i = 0; i < 256; i++) + sub_font->latin_char_map[i] = FALSE; + + sub_font->sub_font_glyphs = _cairo_hash_table_create (NULL); + if (unlikely (sub_font->sub_font_glyphs == NULL)) { + free (sub_font); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + sub_font->next = NULL; + *sub_font_out = sub_font; + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_sub_font_destroy (cairo_sub_font_t *sub_font) +{ + _cairo_hash_table_foreach (sub_font->sub_font_glyphs, + _cairo_sub_font_glyph_pluck, + sub_font->sub_font_glyphs); + _cairo_hash_table_destroy (sub_font->sub_font_glyphs); + cairo_scaled_font_destroy (sub_font->scaled_font); + free (sub_font); +} + +static void +_cairo_sub_font_pluck (void *entry, void *closure) +{ + cairo_sub_font_t *sub_font = entry; + cairo_hash_table_t *sub_fonts = closure; + + _cairo_hash_table_remove (sub_fonts, &sub_font->base); + _cairo_sub_font_destroy (sub_font); +} + +/* Characters 0x80 to 0x9f in the winansi encoding. + * All other characters in the range 0x00 to 0xff map 1:1 to unicode */ +static unsigned int _winansi_0x80_to_0x9f[] = { + 0x20ac, 0x0000, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021, + 0x02c6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x017d, 0x0000, + 0x0000, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014, + 0x02dc, 0x2122, 0x0161, 0x203a, 0x0153, 0x0000, 0x017e, 0x0178 +}; + +int +_cairo_unicode_to_winansi (unsigned long uni) +{ + int i; + + /* exclude the extra "hyphen" at 0xad to avoid duplicate glyphnames */ + if ((uni >= 0x20 && uni <= 0x7e) || + (uni >= 0xa1 && uni <= 0xff && uni != 0xad) || + uni == 0) + return uni; + + for (i = 0; i < 32; i++) + if (_winansi_0x80_to_0x9f[i] == uni) + return i + 0x80; + + return -1; +} + +static cairo_status_t +_cairo_sub_font_glyph_lookup_unicode (cairo_scaled_font_t *scaled_font, + unsigned long scaled_font_glyph_index, + uint32_t *unicode_out, + char **utf8_out, + int *utf8_len_out) +{ + uint32_t unicode; + char buf[8]; + int len; + cairo_status_t status; + + /* Do a reverse lookup on the glyph index. unicode is -1 if the + * index could not be mapped to a unicode character. */ + unicode = -1; + status = _cairo_truetype_index_to_ucs4 (scaled_font, + scaled_font_glyph_index, + &unicode); + if (_cairo_status_is_error (status)) + return status; + + if (unicode == (uint32_t)-1 && scaled_font->backend->index_to_ucs4) { + status = scaled_font->backend->index_to_ucs4 (scaled_font, + scaled_font_glyph_index, + &unicode); + if (unlikely (status)) + return status; + } + + *unicode_out = unicode; + *utf8_out = NULL; + *utf8_len_out = 0; + if (unicode != (uint32_t) -1) { + len = _cairo_ucs4_to_utf8 (unicode, buf); + if (len > 0) { + *utf8_out = _cairo_strndup (buf, len); + if (unlikely (*utf8_out == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + *utf8_len_out = len; + } + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_sub_font_glyph_map_to_unicode (cairo_sub_font_glyph_t *sub_font_glyph, + const char *utf8, + int utf8_len, + cairo_bool_t *is_mapped) +{ + *is_mapped = FALSE; + + if (utf8_len < 0) + return CAIRO_STATUS_SUCCESS; + + if (utf8 != NULL && utf8_len != 0 && utf8[utf8_len - 1] == '\0') + utf8_len--; + + if (utf8 != NULL && utf8_len != 0) { + if (sub_font_glyph->utf8 != NULL) { + if (utf8_len == sub_font_glyph->utf8_len && + strncmp (utf8, sub_font_glyph->utf8, utf8_len) == 0) + { + /* Requested utf8 mapping matches the existing mapping */ + *is_mapped = TRUE; + } + } else { + /* No existing mapping. Use the requested mapping */ + sub_font_glyph->utf8 = _cairo_strndup (utf8, utf8_len); + if (unlikely (sub_font_glyph->utf8 == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + sub_font_glyph->utf8_len = utf8_len; + *is_mapped = TRUE; + } + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_sub_font_lookup_glyph (cairo_sub_font_t *sub_font, + unsigned long scaled_font_glyph_index, + const char *utf8, + int utf8_len, + cairo_scaled_font_subsets_glyph_t *subset_glyph) +{ + cairo_sub_font_glyph_t key, *sub_font_glyph; + cairo_int_status_t status; + + _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index); + sub_font_glyph = _cairo_hash_table_lookup (sub_font->sub_font_glyphs, + &key.base); + if (sub_font_glyph != NULL) { + subset_glyph->font_id = sub_font->font_id; + subset_glyph->subset_id = sub_font_glyph->subset_id; + if (sub_font_glyph->is_latin) + subset_glyph->subset_glyph_index = sub_font_glyph->latin_character; + else + subset_glyph->subset_glyph_index = sub_font_glyph->subset_glyph_index; + + subset_glyph->is_scaled = sub_font->is_scaled; + subset_glyph->is_composite = sub_font->is_composite; + subset_glyph->is_latin = sub_font_glyph->is_latin; + subset_glyph->x_advance = sub_font_glyph->x_advance; + subset_glyph->y_advance = sub_font_glyph->y_advance; + status = _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph, + utf8, utf8_len, + &subset_glyph->utf8_is_mapped); + subset_glyph->unicode = sub_font_glyph->unicode; + + return status; + } + + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_status_t +_cairo_sub_font_add_glyph (cairo_sub_font_t *sub_font, + unsigned long scaled_font_glyph_index, + cairo_bool_t is_latin, + int latin_character, + uint32_t unicode, + char *utf8, + int utf8_len, + cairo_sub_font_glyph_t **sub_font_glyph_out) +{ + cairo_scaled_glyph_t *scaled_glyph; + cairo_sub_font_glyph_t *sub_font_glyph; + int *num_glyphs_in_subset_ptr; + double x_advance; + double y_advance; + cairo_int_status_t status; + + _cairo_scaled_font_freeze_cache (sub_font->scaled_font); + status = _cairo_scaled_glyph_lookup (sub_font->scaled_font, + scaled_font_glyph_index, + CAIRO_SCALED_GLYPH_INFO_METRICS, + NULL, /* foreground color */ + &scaled_glyph); + assert (status != CAIRO_INT_STATUS_UNSUPPORTED); + if (unlikely (status)) { + _cairo_scaled_font_thaw_cache (sub_font->scaled_font); + return status; + } + + x_advance = scaled_glyph->metrics.x_advance; + y_advance = scaled_glyph->metrics.y_advance; + _cairo_scaled_font_thaw_cache (sub_font->scaled_font); + + if (!is_latin && sub_font->num_glyphs_in_current_subset == sub_font->max_glyphs_per_subset) + { + sub_font->current_subset++; + sub_font->num_glyphs_in_current_subset = 0; + } + + if (is_latin) + num_glyphs_in_subset_ptr = &sub_font->num_glyphs_in_latin_subset; + else + num_glyphs_in_subset_ptr = &sub_font->num_glyphs_in_current_subset; + + if ((*num_glyphs_in_subset_ptr == 0) && sub_font->reserve_notdef) + (*num_glyphs_in_subset_ptr)++; + + sub_font_glyph = _cairo_sub_font_glyph_create (scaled_font_glyph_index, + is_latin ? 0 : sub_font->current_subset, + *num_glyphs_in_subset_ptr, + x_advance, + y_advance, + is_latin ? latin_character : -1, + unicode, + utf8, + utf8_len); + + if (unlikely (sub_font_glyph == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + status = _cairo_hash_table_insert (sub_font->sub_font_glyphs, &sub_font_glyph->base); + if (unlikely (status)) { + _cairo_sub_font_glyph_destroy (sub_font_glyph); + return status; + } + + (*num_glyphs_in_subset_ptr)++; + if (sub_font->is_scaled) { + if (*num_glyphs_in_subset_ptr > sub_font->parent->max_glyphs_per_scaled_subset_used) + sub_font->parent->max_glyphs_per_scaled_subset_used = *num_glyphs_in_subset_ptr; + } else { + if (*num_glyphs_in_subset_ptr > sub_font->parent->max_glyphs_per_unscaled_subset_used) + sub_font->parent->max_glyphs_per_unscaled_subset_used = *num_glyphs_in_subset_ptr; + } + + *sub_font_glyph_out = sub_font_glyph; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_sub_font_map_glyph (cairo_sub_font_t *sub_font, + unsigned long scaled_font_glyph_index, + const char *text_utf8, + int text_utf8_len, + cairo_scaled_font_subsets_glyph_t *subset_glyph) +{ + cairo_sub_font_glyph_t key, *sub_font_glyph; + cairo_status_t status; + + _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index); + sub_font_glyph = _cairo_hash_table_lookup (sub_font->sub_font_glyphs, + &key.base); + if (sub_font_glyph == NULL) { + uint32_t font_unicode; + char *font_utf8; + int font_utf8_len; + cairo_bool_t is_latin; + int latin_character; + + status = _cairo_sub_font_glyph_lookup_unicode (sub_font->scaled_font, + scaled_font_glyph_index, + &font_unicode, + &font_utf8, + &font_utf8_len); + if (unlikely(status)) + return status; + + /* If the supplied utf8 is a valid single character, use it + * instead of the font lookup */ + if (text_utf8 != NULL && text_utf8_len > 0) { + uint32_t *ucs4; + int ucs4_len; + + status = _cairo_utf8_to_ucs4 (text_utf8, text_utf8_len, + &ucs4, &ucs4_len); + if (status == CAIRO_STATUS_SUCCESS) { + if (ucs4_len == 1) { + font_unicode = ucs4[0]; + free (font_utf8); + font_utf8 = _cairo_strndup (text_utf8, text_utf8_len); + if (font_utf8 == NULL) { + free (ucs4); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + font_utf8_len = text_utf8_len; + } + free (ucs4); + } + } + + /* If glyph is in the winansi encoding and font is not a scaled + * font, put glyph in the latin subset. */ + is_latin = FALSE; + latin_character = -1; + if (sub_font->use_latin_subset && !sub_font->is_scaled) + { + latin_character = _cairo_unicode_to_winansi (font_unicode); + if (latin_character > 0) + { + if (!sub_font->latin_char_map[latin_character]) { + sub_font->latin_char_map[latin_character] = TRUE; + is_latin = TRUE; + } + } + } + + status = _cairo_sub_font_add_glyph (sub_font, + scaled_font_glyph_index, + is_latin, + latin_character, + font_unicode, + font_utf8, + font_utf8_len, + &sub_font_glyph); + if (unlikely(status)) + return status; + } + + subset_glyph->font_id = sub_font->font_id; + subset_glyph->subset_id = sub_font_glyph->subset_id; + if (sub_font_glyph->is_latin) + subset_glyph->subset_glyph_index = sub_font_glyph->latin_character; + else + subset_glyph->subset_glyph_index = sub_font_glyph->subset_glyph_index; + + subset_glyph->is_scaled = sub_font->is_scaled; + subset_glyph->is_composite = sub_font->is_composite; + subset_glyph->is_latin = sub_font_glyph->is_latin; + subset_glyph->x_advance = sub_font_glyph->x_advance; + subset_glyph->y_advance = sub_font_glyph->y_advance; + status = _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph, + text_utf8, text_utf8_len, + &subset_glyph->utf8_is_mapped); + subset_glyph->unicode = sub_font_glyph->unicode; + + return status; +} + +static void +_cairo_sub_font_collect (void *entry, void *closure) +{ + cairo_sub_font_t *sub_font = entry; + cairo_sub_font_collection_t *collection = closure; + cairo_scaled_font_subset_t subset; + int i; + unsigned int j; + + if (collection->status) + return; + + collection->status = sub_font->scaled_font->status; + if (collection->status) + return; + + for (i = 0; i <= sub_font->current_subset; i++) { + collection->subset_id = i; + collection->num_glyphs = 0; + collection->max_glyph = 0; + memset (collection->latin_to_subset_glyph_index, 0, 256*sizeof(unsigned long)); + + if (sub_font->reserve_notdef) { + // add .notdef + collection->glyphs[0] = 0; + collection->utf8[0] = 0; + collection->to_latin_char[0] = 0; + collection->latin_to_subset_glyph_index[0] = 0; + collection->num_glyphs++; + } + + _cairo_hash_table_foreach (sub_font->sub_font_glyphs, + _cairo_sub_font_glyph_collect, collection); + if (collection->status) + break; + + if (collection->num_glyphs == 0) + continue; + + if (sub_font->reserve_notdef && collection->num_glyphs == 1) + continue; + + /* Ensure the resulting array has no uninitialized holes */ + assert (collection->num_glyphs == collection->max_glyph + 1); + + subset.scaled_font = sub_font->scaled_font; + subset.is_composite = sub_font->is_composite; + subset.is_scaled = sub_font->is_scaled; + subset.font_id = sub_font->font_id; + subset.subset_id = i; + subset.glyphs = collection->glyphs; + subset.utf8 = collection->utf8; + subset.num_glyphs = collection->num_glyphs; + subset.glyph_names = NULL; + + subset.is_latin = FALSE; + if (sub_font->use_latin_subset && i == 0) { + subset.is_latin = TRUE; + subset.to_latin_char = collection->to_latin_char; + subset.latin_to_subset_glyph_index = collection->latin_to_subset_glyph_index; + } else { + subset.to_latin_char = NULL; + subset.latin_to_subset_glyph_index = NULL; + } + + collection->status = (collection->font_subset_callback) (&subset, + collection->font_subset_callback_closure); + + if (subset.glyph_names != NULL) { + for (j = 0; j < collection->num_glyphs; j++) + free (subset.glyph_names[j]); + free (subset.glyph_names); + } + + if (collection->status) + break; + } +} + +static cairo_scaled_font_subsets_t * +_cairo_scaled_font_subsets_create_internal (cairo_subsets_type_t type) +{ + cairo_scaled_font_subsets_t *subsets; + + subsets = _cairo_calloc (sizeof (cairo_scaled_font_subsets_t)); + if (unlikely (subsets == NULL)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return NULL; + } + + subsets->type = type; + subsets->use_latin_subset = FALSE; + subsets->max_glyphs_per_unscaled_subset_used = 0; + subsets->max_glyphs_per_scaled_subset_used = 0; + subsets->num_sub_fonts = 0; + + subsets->unscaled_sub_fonts = _cairo_hash_table_create (_cairo_sub_fonts_equal); + if (! subsets->unscaled_sub_fonts) { + free (subsets); + return NULL; + } + subsets->unscaled_sub_fonts_list = NULL; + subsets->unscaled_sub_fonts_list_end = NULL; + + subsets->scaled_sub_fonts = _cairo_hash_table_create (_cairo_sub_fonts_equal); + if (! subsets->scaled_sub_fonts) { + _cairo_hash_table_destroy (subsets->unscaled_sub_fonts); + free (subsets); + return NULL; + } + subsets->scaled_sub_fonts_list = NULL; + subsets->scaled_sub_fonts_list_end = NULL; + + return subsets; +} + +cairo_scaled_font_subsets_t * +_cairo_scaled_font_subsets_create_scaled (void) +{ + return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_SCALED); +} + +cairo_scaled_font_subsets_t * +_cairo_scaled_font_subsets_create_simple (void) +{ + return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_SIMPLE); +} + +cairo_scaled_font_subsets_t * +_cairo_scaled_font_subsets_create_composite (void) +{ + return _cairo_scaled_font_subsets_create_internal (CAIRO_SUBSETS_COMPOSITE); +} + +void +_cairo_scaled_font_subsets_destroy (cairo_scaled_font_subsets_t *subsets) +{ + _cairo_hash_table_foreach (subsets->scaled_sub_fonts, _cairo_sub_font_pluck, subsets->scaled_sub_fonts); + _cairo_hash_table_destroy (subsets->scaled_sub_fonts); + + _cairo_hash_table_foreach (subsets->unscaled_sub_fonts, _cairo_sub_font_pluck, subsets->unscaled_sub_fonts); + _cairo_hash_table_destroy (subsets->unscaled_sub_fonts); + + free (subsets); +} + +void +_cairo_scaled_font_subsets_enable_latin_subset (cairo_scaled_font_subsets_t *font_subsets, + cairo_bool_t use_latin) +{ + font_subsets->use_latin_subset = use_latin; +} + +cairo_status_t +_cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t *subsets, + cairo_scaled_font_t *scaled_font, + unsigned long scaled_font_glyph_index, + const char * utf8, + int utf8_len, + cairo_scaled_font_subsets_glyph_t *subset_glyph) +{ + cairo_sub_font_t key, *sub_font; + cairo_scaled_glyph_t *scaled_glyph; + cairo_font_face_t *font_face; + cairo_matrix_t identity; + cairo_font_options_t font_options; + cairo_scaled_font_t *unscaled_font; + cairo_int_status_t status; + int max_glyphs; + cairo_bool_t type1_font; + cairo_bool_t has_path; + cairo_bool_t has_color; + cairo_bool_t is_user; + + /* Lookup glyph in unscaled subsets */ + if (subsets->type != CAIRO_SUBSETS_SCALED) { + key.is_scaled = FALSE; + _cairo_sub_font_init_key (&key, scaled_font); + sub_font = _cairo_hash_table_lookup (subsets->unscaled_sub_fonts, + &key.base); + if (sub_font != NULL) { + status = _cairo_sub_font_lookup_glyph (sub_font, + scaled_font_glyph_index, + utf8, utf8_len, + subset_glyph); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + } + } + + /* Lookup glyph in scaled subsets */ + key.is_scaled = TRUE; + _cairo_sub_font_init_key (&key, scaled_font); + sub_font = _cairo_hash_table_lookup (subsets->scaled_sub_fonts, + &key.base); + if (sub_font != NULL) { + status = _cairo_sub_font_lookup_glyph (sub_font, + scaled_font_glyph_index, + utf8, utf8_len, + subset_glyph); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + } + + /* Glyph not found. Determine whether the glyph is outline or + * bitmap and add to the appropriate subset. + */ + is_user = _cairo_font_face_is_user (scaled_font->font_face); + _cairo_scaled_font_freeze_cache (scaled_font); + /* Check if glyph is color */ + status = _cairo_scaled_glyph_lookup (scaled_font, + scaled_font_glyph_index, + CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE, + NULL, /* foreground color */ + &scaled_glyph); + has_color = (status == CAIRO_INT_STATUS_SUCCESS); + + /* Check if glyph has a path */ + status = _cairo_scaled_glyph_lookup (scaled_font, + scaled_font_glyph_index, + CAIRO_SCALED_GLYPH_INFO_PATH, + NULL, /* foreground color */ + &scaled_glyph); + has_path = (status == CAIRO_INT_STATUS_SUCCESS); + + /* glyph_index 0 (the .notdef glyph) is a special case. Some fonts + * will return CAIRO_INT_STATUS_UNSUPPORTED when doing a + * _scaled_glyph_lookup(_GLYPH_INFO_PATH). Type1-fallback creates + * empty glyphs in this case so we can put the glyph in a unscaled + * subset. + */ + if (scaled_font_glyph_index == 0 && !is_user) + has_path = TRUE; + + /* If this fails there is nothing we can do with this glyph. */ + status = _cairo_scaled_glyph_lookup (scaled_font, + scaled_font_glyph_index, + CAIRO_SCALED_GLYPH_INFO_SURFACE, + NULL, /* foreground color */ + &scaled_glyph); + _cairo_scaled_font_thaw_cache (scaled_font); + if (_cairo_int_status_is_error (status)) + return status; + + /* Type 3 glyphs (is_user and has_color) must be added to scaled subset */ + if (subsets->type != CAIRO_SUBSETS_SCALED && + has_path && !has_color && !is_user) + { + /* Path available. Add to unscaled subset. */ + key.is_scaled = FALSE; + _cairo_sub_font_init_key (&key, scaled_font); + sub_font = _cairo_hash_table_lookup (subsets->unscaled_sub_fonts, + &key.base); + if (sub_font == NULL) { + font_face = cairo_scaled_font_get_font_face (scaled_font); + cairo_matrix_init_identity (&identity); + _cairo_font_options_init_default (&font_options); + cairo_scaled_font_get_font_options (scaled_font, &font_options); + cairo_font_options_set_hint_style (&font_options, CAIRO_HINT_STYLE_NONE); + cairo_font_options_set_hint_metrics (&font_options, CAIRO_HINT_METRICS_OFF); + unscaled_font = cairo_scaled_font_create (font_face, + &identity, + &identity, + &font_options); + if (unlikely (unscaled_font->status)) + return unscaled_font->status; + + subset_glyph->is_scaled = FALSE; + type1_font = _cairo_type1_scaled_font_is_type1 (unscaled_font); + if (subsets->type == CAIRO_SUBSETS_COMPOSITE && !type1_font) { + max_glyphs = MAX_GLYPHS_PER_COMPOSITE_FONT; + subset_glyph->is_composite = TRUE; + } else { + max_glyphs = MAX_GLYPHS_PER_SIMPLE_FONT; + subset_glyph->is_composite = FALSE; + } + + status = _cairo_sub_font_create (subsets, + unscaled_font, + subsets->num_sub_fonts, + max_glyphs, + subset_glyph->is_scaled, + subset_glyph->is_composite, + &sub_font); + + if (unlikely (status)) { + cairo_scaled_font_destroy (unscaled_font); + return status; + } + + status = _cairo_hash_table_insert (subsets->unscaled_sub_fonts, + &sub_font->base); + + if (unlikely (status)) { + _cairo_sub_font_destroy (sub_font); + return status; + } + if (!subsets->unscaled_sub_fonts_list) + subsets->unscaled_sub_fonts_list = sub_font; + else + subsets->unscaled_sub_fonts_list_end->next = sub_font; + subsets->unscaled_sub_fonts_list_end = sub_font; + subsets->num_sub_fonts++; + } + } else { + /* No path available. Add to scaled subset. */ + key.is_scaled = TRUE; + _cairo_sub_font_init_key (&key, scaled_font); + sub_font = _cairo_hash_table_lookup (subsets->scaled_sub_fonts, + &key.base); + if (sub_font == NULL) { + subset_glyph->is_scaled = TRUE; + subset_glyph->is_composite = FALSE; + if (subsets->type == CAIRO_SUBSETS_SCALED) + max_glyphs = INT_MAX; + else + max_glyphs = MAX_GLYPHS_PER_SIMPLE_FONT; + + status = _cairo_sub_font_create (subsets, + cairo_scaled_font_reference (scaled_font), + subsets->num_sub_fonts, + max_glyphs, + subset_glyph->is_scaled, + subset_glyph->is_composite, + &sub_font); + if (unlikely (status)) { + cairo_scaled_font_destroy (scaled_font); + return status; + } + + status = _cairo_hash_table_insert (subsets->scaled_sub_fonts, + &sub_font->base); + if (unlikely (status)) { + _cairo_sub_font_destroy (sub_font); + return status; + } + if (!subsets->scaled_sub_fonts_list) + subsets->scaled_sub_fonts_list = sub_font; + else + subsets->scaled_sub_fonts_list_end->next = sub_font; + subsets->scaled_sub_fonts_list_end = sub_font; + subsets->num_sub_fonts++; + } + } + + return _cairo_sub_font_map_glyph (sub_font, + scaled_font_glyph_index, + utf8, utf8_len, + subset_glyph); +} + +static cairo_status_t +_cairo_scaled_font_subsets_foreach_internal (cairo_scaled_font_subsets_t *font_subsets, + cairo_scaled_font_subset_callback_func_t font_subset_callback, + void *closure, + cairo_subsets_foreach_type_t type) +{ + cairo_sub_font_collection_t collection; + cairo_sub_font_t *sub_font; + cairo_bool_t is_scaled; + + is_scaled = FALSE; + + if (type == CAIRO_SUBSETS_FOREACH_SCALED) + is_scaled = TRUE; + + if (is_scaled) + collection.glyphs_size = font_subsets->max_glyphs_per_scaled_subset_used; + else + collection.glyphs_size = font_subsets->max_glyphs_per_unscaled_subset_used; + + if (! collection.glyphs_size) + return CAIRO_STATUS_SUCCESS; + + collection.glyphs = _cairo_malloc_ab (collection.glyphs_size, sizeof(unsigned long)); + collection.utf8 = _cairo_malloc_ab (collection.glyphs_size, sizeof(char *)); + collection.to_latin_char = _cairo_malloc_ab (collection.glyphs_size, sizeof(int)); + collection.latin_to_subset_glyph_index = _cairo_malloc_ab (256, sizeof(unsigned long)); + if (unlikely (collection.glyphs == NULL || + collection.utf8 == NULL || + collection.to_latin_char == NULL || + collection.latin_to_subset_glyph_index == NULL)) { + free (collection.glyphs); + free (collection.utf8); + free (collection.to_latin_char); + free (collection.latin_to_subset_glyph_index); + + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + collection.font_subset_callback = font_subset_callback; + collection.font_subset_callback_closure = closure; + collection.status = CAIRO_STATUS_SUCCESS; + + if (is_scaled) + sub_font = font_subsets->scaled_sub_fonts_list; + else + sub_font = font_subsets->unscaled_sub_fonts_list; + + while (sub_font) { + _cairo_sub_font_collect (sub_font, &collection); + sub_font = sub_font->next; + } + free (collection.utf8); + free (collection.glyphs); + free (collection.to_latin_char); + free (collection.latin_to_subset_glyph_index); + + return collection.status; +} + +cairo_status_t +_cairo_scaled_font_subsets_foreach_scaled (cairo_scaled_font_subsets_t *font_subsets, + cairo_scaled_font_subset_callback_func_t font_subset_callback, + void *closure) +{ + return _cairo_scaled_font_subsets_foreach_internal (font_subsets, + font_subset_callback, + closure, + CAIRO_SUBSETS_FOREACH_SCALED); +} + +cairo_status_t +_cairo_scaled_font_subsets_foreach_unscaled (cairo_scaled_font_subsets_t *font_subsets, + cairo_scaled_font_subset_callback_func_t font_subset_callback, + void *closure) +{ + return _cairo_scaled_font_subsets_foreach_internal (font_subsets, + font_subset_callback, + closure, + CAIRO_SUBSETS_FOREACH_UNSCALED); +} + +static cairo_bool_t +_cairo_string_equal (const void *key_a, const void *key_b) +{ + const cairo_string_entry_t *a = key_a; + const cairo_string_entry_t *b = key_b; + + if (strcmp (a->string, b->string) == 0) + return TRUE; + else + return FALSE; +} + +#if DEBUG_SUBSETS + +static void +dump_glyph (void *entry, void *closure) +{ + cairo_sub_font_glyph_t *glyph = entry; + char buf[10]; + int i; + + printf(" font_glyph_index: %ld\n", glyph->base.hash); + printf(" subset_id: %d\n", glyph->subset_id); + printf(" subset_glyph_index: %d\n", glyph->subset_glyph_index); + printf(" x_advance: %f\n", glyph->x_advance); + printf(" y_advance: %f\n", glyph->y_advance); + printf(" is_latin: %d\n", glyph->is_latin); + printf(" latin_character: '%c' (0x%02x)\n", glyph->latin_character, glyph->latin_character); + printf(" is_latin: %d\n", glyph->is_latin); + printf(" is_mapped: %d\n", glyph->is_mapped); + printf(" unicode: U+%04x\n", glyph->unicode); + memset(buf, 0, sizeof(buf)); + memcpy(buf, glyph->utf8, glyph->utf8_len); + printf(" utf8: '%s'\n", buf); + printf(" utf8 (hex):"); + for (i = 0; i < glyph->utf8_len; i++) + printf(" 0x%02x", glyph->utf8[i]); + printf("\n\n"); +} + +static void +dump_subfont (cairo_sub_font_t *sub_font) +{ + while (sub_font) { + printf(" font_id: %d\n", sub_font->font_id); + printf(" current_subset: %d\n", sub_font->current_subset); + printf(" is_scaled: %d\n", sub_font->is_scaled); + printf(" is_composite: %d\n", sub_font->is_composite); + printf(" is_user: %d\n", sub_font->is_user); + printf(" use_latin_subset: %d\n", sub_font->use_latin_subset); + printf(" reserve_notdef: %d\n", sub_font->reserve_notdef); + printf(" num_glyphs_in_current_subset: %d\n", sub_font->num_glyphs_in_current_subset); + printf(" num_glyphs_in_latin_subset: %d\n", sub_font->num_glyphs_in_latin_subset); + printf(" max_glyphs_per_subset: %d\n\n", sub_font->max_glyphs_per_subset); + + _cairo_hash_table_foreach (sub_font->sub_font_glyphs, dump_glyph, NULL); + + printf("\n"); + sub_font = sub_font->next; + } +} + +void +dump_scaled_font_subsets (cairo_scaled_font_subsets_t *font_subsets) +{ + printf("font subsets\n"); + switch (font_subsets->type) + { + case CAIRO_SUBSETS_SCALED: + printf(" type: CAIRO_SUBSETS_SCALED\n"); + break; + case CAIRO_SUBSETS_SIMPLE: + printf(" type: CAIRO_SUBSETS_SIMPLE\n"); + break; + case CAIRO_SUBSETS_COMPOSITE: + printf(" type: CAIRO_SUBSETS_COMPOSITE\n"); + break; + } + printf(" use_latin_subset: %d\n", font_subsets->use_latin_subset); + printf(" max_glyphs_per_unscaled_subset_used: %d\n", font_subsets->max_glyphs_per_unscaled_subset_used); + printf(" max_glyphs_per_scaled_subset_used: %d\n", font_subsets->max_glyphs_per_scaled_subset_used); + printf(" num_sub_fonts: %d\n\n", font_subsets->num_sub_fonts); + + printf(" scaled subsets:\n"); + dump_subfont (font_subsets->scaled_sub_fonts_list); + + printf("\n unscaled subsets:\n"); + dump_subfont (font_subsets->unscaled_sub_fonts_list); +} + +#endif + + +static void +_cairo_string_init_key (cairo_string_entry_t *key, char *s) +{ + unsigned long sum = 0; + unsigned int i; + + for (i = 0; i < strlen(s); i++) + sum += s[i]; + key->base.hash = sum; + key->string = s; +} + +static cairo_status_t +create_string_entry (char *s, cairo_string_entry_t **entry) +{ + *entry = _cairo_calloc (sizeof (cairo_string_entry_t)); + if (unlikely (*entry == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + _cairo_string_init_key (*entry, s); + + return CAIRO_STATUS_SUCCESS; +} + +static void +_pluck_entry (void *entry, void *closure) +{ + _cairo_hash_table_remove (closure, entry); + free (entry); +} + +cairo_int_status_t +_cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset) +{ + unsigned int i; + cairo_hash_table_t *names; + cairo_string_entry_t key, *entry; + char buf[30]; + char *utf8; + uint16_t *utf16; + int utf16_len; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + names = _cairo_hash_table_create (_cairo_string_equal); + if (unlikely (names == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + subset->glyph_names = _cairo_calloc_ab (subset->num_glyphs, sizeof (char *)); + if (unlikely (subset->glyph_names == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CLEANUP_HASH; + } + + i = 0; + if (! subset->is_scaled) { + subset->glyph_names[0] = strdup (".notdef"); + if (unlikely (subset->glyph_names[0] == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CLEANUP_HASH; + } + + status = create_string_entry (subset->glyph_names[0], &entry); + if (unlikely (status)) + goto CLEANUP_HASH; + + status = _cairo_hash_table_insert (names, &entry->base); + if (unlikely (status)) { + free (entry); + goto CLEANUP_HASH; + } + i++; + } + + for (; i < subset->num_glyphs; i++) { + utf8 = subset->utf8[i]; + utf16 = NULL; + utf16_len = 0; + if (utf8 && *utf8) { + status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &utf16_len); + if (status == CAIRO_STATUS_INVALID_STRING) { + utf16 = NULL; + utf16_len = 0; + } else if (unlikely (status)) { + goto CLEANUP_HASH; + } + } + + if (utf16_len == 1) { + int ch = _cairo_unicode_to_winansi (utf16[0]); + if (ch > 0 && _cairo_winansi_to_glyphname (ch)) { + strncpy (buf, _cairo_winansi_to_glyphname (ch), sizeof (buf)); + buf[sizeof (buf)-1] = '\0'; + } else { + snprintf (buf, sizeof (buf), "uni%04X", (int) utf16[0]); + } + + _cairo_string_init_key (&key, buf); + entry = _cairo_hash_table_lookup (names, &key.base); + if (entry != NULL) + snprintf (buf, sizeof (buf), "g%d", i); + } else { + snprintf (buf, sizeof (buf), "g%d", i); + } + free (utf16); + + subset->glyph_names[i] = strdup (buf); + if (unlikely (subset->glyph_names[i] == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CLEANUP_HASH; + } + + status = create_string_entry (subset->glyph_names[i], &entry); + if (unlikely (status)) + goto CLEANUP_HASH; + + status = _cairo_hash_table_insert (names, &entry->base); + if (unlikely (status)) { + free (entry); + goto CLEANUP_HASH; + } + } + +CLEANUP_HASH: + _cairo_hash_table_foreach (names, _pluck_entry, names); + _cairo_hash_table_destroy (names); + + if (likely (status == CAIRO_STATUS_SUCCESS)) + return CAIRO_STATUS_SUCCESS; + + if (subset->glyph_names != NULL) { + for (i = 0; i < subset->num_glyphs; i++) { + free (subset->glyph_names[i]); + } + + free (subset->glyph_names); + subset->glyph_names = NULL; + } + + return status; +} + +cairo_int_status_t +_cairo_escape_ps_name (char **ps_name) +{ + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + /* Ensure PS name is a valid PDF/PS name object. In PDF names are + * treated as UTF8 and non ASCII bytes, ' ', and '#' are encoded + * as '#' followed by 2 hex digits that encode the byte. By also + * encoding the characters in the reserved string we ensure the + * name is also PS compatible. */ + if (*ps_name) { + static const char *reserved = "()<>[]{}/%#\\"; + char buf[128]; /* max name length is 127 bytes */ + char *src = *ps_name; + char *dst = buf; + + while (*src && dst < buf + 127) { + unsigned char c = *src; + if (c < 0x21 || c > 0x7e || strchr (reserved, c)) { + if (dst + 4 > buf + 127) + break; + + snprintf (dst, 4, "#%02X", c); + src++; + dst += 3; + } else { + *dst++ = *src++; + } + } + *dst = 0; + free (*ps_name); + *ps_name = strdup (buf); + if (*ps_name == NULL) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + } + + return status; +} + +#endif /* CAIRO_HAS_FONT_SUBSET */ diff --git a/local/recipes/libs/cairo/source/src/cairo-scaled-font.c b/local/recipes/libs/cairo/source/src/cairo-scaled-font.c new file mode 100755 index 0000000000..82a4447f54 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-scaled-font.c @@ -0,0 +1,3122 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright © 2005 Keith Packard + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Keith Packard + * + * Contributor(s): + * Keith Packard + * Carl D. Worth + * Graydon Hoare + * Owen Taylor + * Behdad Esfahbod + * Chris Wilson + */ + +#include "cairoint.h" +#include "cairo-array-private.h" +#include "cairo-error-private.h" +#include "cairo-image-surface-private.h" +#include "cairo-list-inline.h" +#include "cairo-pattern-private.h" +#include "cairo-scaled-font-private.h" +#include "cairo-surface-backend-private.h" + +/** + * SECTION:cairo-scaled-font + * @Title: cairo_scaled_font_t + * @Short_Description: Font face at particular size and options + * @See_Also: #cairo_font_face_t, #cairo_matrix_t, #cairo_font_options_t + * + * #cairo_scaled_font_t represents a realization of a font face at a particular + * size and transformation and a certain set of font options. + **/ + +static uintptr_t +_cairo_scaled_font_compute_hash (cairo_scaled_font_t *scaled_font); + +/* Global Glyph Cache + * + * We maintain a global pool of glyphs split between all active fonts. This + * allows a heavily used individual font to cache more glyphs than we could + * manage if we used per-font glyph caches, but at the same time maintains + * fairness across all fonts and provides a cap on the maximum number of + * global glyphs. + * + * The glyphs are allocated in pages, which are capped in the global pool. + * Using pages means we can reduce the frequency at which we have to probe the + * global pool and ameliorates the memory allocation pressure. + */ + +/* XXX: This number is arbitrary---we've never done any measurement of this. */ +#define MAX_GLYPH_PAGES_CACHED 512 +static cairo_cache_t cairo_scaled_glyph_page_cache; + +#define CAIRO_SCALED_GLYPH_PAGE_SIZE 32 +struct _cairo_scaled_glyph_page { + cairo_cache_entry_t cache_entry; + cairo_scaled_font_t *scaled_font; + cairo_list_t link; + + unsigned int num_glyphs; + cairo_scaled_glyph_t glyphs[CAIRO_SCALED_GLYPH_PAGE_SIZE]; +}; + +/* + * Notes: + * + * To store rasterizations of glyphs, we use an image surface and the + * device offset to represent the glyph origin. + * + * A device_transform converts from device space (a conceptual space) to + * surface space. For simple cases of translation only, it's called a + * device_offset and is public API (cairo_surface_[gs]et_device_offset()). + * A possibly better name for those functions could have been + * cairo_surface_[gs]et_origin(). So, that's what they do: they set where + * the device-space origin (0,0) is in the surface. If the origin is inside + * the surface, device_offset values are positive. It may look like this: + * + * Device space: + * (-x,-y) <-- negative numbers + * +----------------+ + * | . | + * | . | + * |......(0,0) <---|-- device-space origin + * | | + * | | + * +----------------+ + * (width-x,height-y) + * + * Surface space: + * (0,0) <-- surface-space origin + * +---------------+ + * | . | + * | . | + * |......(x,y) <--|-- device_offset + * | | + * | | + * +---------------+ + * (width,height) + * + * In other words: device_offset is the coordinates of the device-space + * origin relative to the top-left of the surface. + * + * We use device offsets in a couple of places: + * + * - Public API: To let toolkits like Gtk+ give user a surface that + * only represents part of the final destination (say, the expose + * area), but has the same device space as the destination. In these + * cases device_offset is typically negative. Example: + * + * application window + * +---------------+ + * | . | + * | (x,y). | + * |......+---+ | + * | | | <--|-- expose area + * | +---+ | + * +---------------+ + * + * In this case, the user of cairo API can set the device_space on + * the expose area to (-x,-y) to move the device space origin to that + * of the application window, such that drawing in the expose area + * surface and painting it in the application window has the same + * effect as drawing in the application window directly. Gtk+ has + * been using this feature. + * + * - Glyph surfaces: In most font rendering systems, glyph surfaces + * have an origin at (0,0) and a bounding box that is typically + * represented as (x_bearing,y_bearing,width,height). Depending on + * which way y progresses in the system, y_bearing may typically be + * negative (for systems similar to cairo, with origin at top left), + * or be positive (in systems like PDF with origin at bottom left). + * No matter which is the case, it is important to note that + * (x_bearing,y_bearing) is the coordinates of top-left of the glyph + * relative to the glyph origin. That is, for example: + * + * Scaled-glyph space: + * + * (x_bearing,y_bearing) <-- negative numbers + * +----------------+ + * | . | + * | . | + * |......(0,0) <---|-- glyph origin + * | | + * | | + * +----------------+ + * (width+x_bearing,height+y_bearing) + * + * Note the similarity of the origin to the device space. That is + * exactly how we use the device_offset to represent scaled glyphs: + * to use the device-space origin as the glyph origin. + * + * Now compare the scaled-glyph space to device-space and surface-space + * and convince yourself that: + * + * (x_bearing,y_bearing) = (-x,-y) = - device_offset + * + * That's right. If you are not convinced yet, contrast the definition + * of the two: + * + * "(x_bearing,y_bearing) is the coordinates of top-left of the + * glyph relative to the glyph origin." + * + * "In other words: device_offset is the coordinates of the + * device-space origin relative to the top-left of the surface." + * + * and note that glyph origin = device-space origin. + */ + +static void +_cairo_scaled_font_fini_internal (cairo_scaled_font_t *scaled_font); + +static void +_cairo_scaled_glyph_fini (cairo_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph) +{ + while (! cairo_list_is_empty (&scaled_glyph->dev_privates)) { + cairo_scaled_glyph_private_t *private = + cairo_list_first_entry (&scaled_glyph->dev_privates, + cairo_scaled_glyph_private_t, + link); + private->destroy (private, scaled_glyph, scaled_font); + } + + _cairo_image_scaled_glyph_fini (scaled_font, scaled_glyph); + + if (scaled_glyph->surface != NULL) + cairo_surface_destroy (&scaled_glyph->surface->base); + + if (scaled_glyph->path != NULL) + _cairo_path_fixed_destroy (scaled_glyph->path); + + if (scaled_glyph->recording_surface != NULL) { + cairo_status_t status; + + /* If the recording surface contains other fonts, destroying + * it while holding _cairo_scaled_glyph_page_cache_mutex will + * result in deadlock when the recording surface font is + * destroyed. Instead, move the recording surface to a list of + * surfaces to free and free it in + * _cairo_scaled_font_thaw_cache() after + * _cairo_scaled_glyph_page_cache_mutex is unlocked. */ + status = _cairo_array_append (&scaled_font->recording_surfaces_to_free, &scaled_glyph->recording_surface); + assert (status == CAIRO_STATUS_SUCCESS); + } + + if (scaled_glyph->color_surface != NULL) + cairo_surface_destroy (&scaled_glyph->color_surface->base); +} + +#define ZOMBIE 0 +static const cairo_scaled_font_t _cairo_scaled_font_nil = { + { ZOMBIE }, /* hash_entry */ + CAIRO_STATUS_NO_MEMORY, /* status */ + CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ + { 0, 0, 0, NULL }, /* user_data */ + NULL, /* original_font_face */ + NULL, /* font_face */ + { 1., 0., 0., 1., 0, 0}, /* font_matrix */ + { 1., 0., 0., 1., 0, 0}, /* ctm */ + { CAIRO_ANTIALIAS_DEFAULT, /* options */ + CAIRO_SUBPIXEL_ORDER_DEFAULT, + CAIRO_HINT_STYLE_DEFAULT, + CAIRO_HINT_METRICS_DEFAULT} , + FALSE, /* placeholder */ + FALSE, /* holdover */ + TRUE, /* finished */ + { 1., 0., 0., 1., 0, 0}, /* scale */ + { 1., 0., 0., 1., 0, 0}, /* scale_inverse */ + 1., /* max_scale */ + { 0., 0., 0., 0., 0. }, /* extents */ + { 0., 0., 0., 0., 0. }, /* fs_extents */ + CAIRO_MUTEX_NIL_INITIALIZER,/* mutex */ + NULL, /* glyphs */ + { NULL, NULL }, /* pages */ + FALSE, /* cache_frozen */ + FALSE, /* global_cache_frozen */ + { 0, 0, sizeof(cairo_surface_t*), NULL }, /* recording_surfaces_to_free */ + { NULL, NULL }, /* privates */ + NULL /* backend */ +}; + +/** + * _cairo_scaled_font_set_error: + * @scaled_font: a scaled_font + * @status: a status value indicating an error + * + * Atomically sets scaled_font->status to @status and calls _cairo_error; + * Does nothing if status is %CAIRO_STATUS_SUCCESS. + * + * All assignments of an error status to scaled_font->status should happen + * through _cairo_scaled_font_set_error(). Note that due to the nature of + * the atomic operation, it is not safe to call this function on the nil + * objects. + * + * The purpose of this function is to allow the user to set a + * breakpoint in _cairo_error() to generate a stack trace for when the + * user causes cairo to detect an error. + * + * Return value: the error status. + **/ +cairo_status_t +_cairo_scaled_font_set_error (cairo_scaled_font_t *scaled_font, + cairo_status_t status) +{ + if (status == CAIRO_STATUS_SUCCESS) + return status; + + /* Don't overwrite an existing error. This preserves the first + * error, which is the most significant. */ + _cairo_status_set_error (&scaled_font->status, status); + + return _cairo_error (status); +} + +/** + * cairo_scaled_font_get_type: + * @scaled_font: a #cairo_scaled_font_t + * + * This function returns the type of the backend used to create + * a scaled font. See #cairo_font_type_t for available types. + * However, this function never returns %CAIRO_FONT_TYPE_TOY. + * + * Return value: The type of @scaled_font. + * + * Since: 1.2 + **/ +cairo_font_type_t +cairo_scaled_font_get_type (cairo_scaled_font_t *scaled_font) +{ + if (CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count)) + return CAIRO_FONT_TYPE_TOY; + + return scaled_font->backend->type; +} + +/** + * cairo_scaled_font_status: + * @scaled_font: a #cairo_scaled_font_t + * + * Checks whether an error has previously occurred for this + * scaled_font. + * + * Return value: %CAIRO_STATUS_SUCCESS or another error such as + * %CAIRO_STATUS_NO_MEMORY. + * + * Since: 1.0 + **/ +cairo_status_t +cairo_scaled_font_status (cairo_scaled_font_t *scaled_font) +{ + return scaled_font->status; +} + +/* Here we keep a unique mapping from + * font_face/matrix/ctm/font_options => #cairo_scaled_font_t. + * + * Here are the things that we want to map: + * + * a) All otherwise referenced #cairo_scaled_font_t's + * b) Some number of not otherwise referenced #cairo_scaled_font_t's + * + * The implementation uses a hash table which covers (a) + * completely. Then, for (b) we have an array of otherwise + * unreferenced fonts (holdovers) which are expired in + * least-recently-used order. + * + * The cairo_scaled_font_create() code gets to treat this like a regular + * hash table. All of the magic for the little holdover cache is in + * cairo_scaled_font_reference() and cairo_scaled_font_destroy(). + */ + +/* This defines the size of the holdover array ... that is, the number + * of scaled fonts we keep around even when not otherwise referenced + */ +#define CAIRO_SCALED_FONT_MAX_HOLDOVERS 256 + +typedef struct _cairo_scaled_font_map { + cairo_scaled_font_t *mru_scaled_font; + cairo_hash_table_t *hash_table; + cairo_scaled_font_t *holdovers[CAIRO_SCALED_FONT_MAX_HOLDOVERS]; + int num_holdovers; +} cairo_scaled_font_map_t; + +static cairo_scaled_font_map_t *cairo_scaled_font_map; + +static int +_cairo_scaled_font_keys_equal (const void *abstract_key_a, const void *abstract_key_b); + +static cairo_scaled_font_map_t * +_cairo_scaled_font_map_lock (void) +{ + CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex); + + if (cairo_scaled_font_map == NULL) { + cairo_scaled_font_map = _cairo_calloc (sizeof (cairo_scaled_font_map_t)); + if (unlikely (cairo_scaled_font_map == NULL)) + goto CLEANUP_MUTEX_LOCK; + + cairo_scaled_font_map->mru_scaled_font = NULL; + cairo_scaled_font_map->hash_table = + _cairo_hash_table_create (_cairo_scaled_font_keys_equal); + + if (unlikely (cairo_scaled_font_map->hash_table == NULL)) + goto CLEANUP_SCALED_FONT_MAP; + + cairo_scaled_font_map->num_holdovers = 0; + } + + return cairo_scaled_font_map; + + CLEANUP_SCALED_FONT_MAP: + free (cairo_scaled_font_map); + cairo_scaled_font_map = NULL; + CLEANUP_MUTEX_LOCK: + CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex); + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return NULL; +} + +static void +_cairo_scaled_font_map_unlock (void) +{ + CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex); +} + +void +_cairo_scaled_font_map_destroy (void) +{ + cairo_scaled_font_map_t *font_map; + cairo_scaled_font_t *scaled_font; + + CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex); + + font_map = cairo_scaled_font_map; + if (unlikely (font_map == NULL)) { + goto CLEANUP_MUTEX_LOCK; + } + + scaled_font = font_map->mru_scaled_font; + if (scaled_font != NULL) { + CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex); + cairo_scaled_font_destroy (scaled_font); + CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex); + } + + /* remove scaled_fonts starting from the end so that font_map->holdovers + * is always in a consistent state when we release the mutex. */ + while (font_map->num_holdovers) { + scaled_font = font_map->holdovers[font_map->num_holdovers-1]; + assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count)); + _cairo_hash_table_remove (font_map->hash_table, + &scaled_font->hash_entry); + + font_map->num_holdovers--; + + /* This releases the font_map lock to avoid the possibility of a + * recursive deadlock when the scaled font destroy closure gets + * called + */ + _cairo_scaled_font_fini (scaled_font); + + free (scaled_font); + } + + _cairo_hash_table_destroy (font_map->hash_table); + + free (cairo_scaled_font_map); + cairo_scaled_font_map = NULL; + + CLEANUP_MUTEX_LOCK: + CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex); +} + +static void +_cairo_scaled_glyph_page_destroy (cairo_scaled_font_t *scaled_font, + cairo_scaled_glyph_page_t *page) +{ + unsigned int n; + + assert (!scaled_font->cache_frozen); + assert (!scaled_font->global_cache_frozen); + + for (n = 0; n < page->num_glyphs; n++) { + _cairo_hash_table_remove (scaled_font->glyphs, + &page->glyphs[n].hash_entry); + _cairo_scaled_glyph_fini (scaled_font, &page->glyphs[n]); + } + + cairo_list_del (&page->link); + free (page); +} + +static void +_cairo_scaled_glyph_page_pluck (void *closure) +{ + cairo_scaled_glyph_page_t *page = closure; + cairo_scaled_font_t *scaled_font; + + assert (! cairo_list_is_empty (&page->link)); + + scaled_font = page->scaled_font; + + /* The font is locked in _cairo_scaled_glyph_page_can_remove () */ + _cairo_scaled_glyph_page_destroy (scaled_font, page); + CAIRO_MUTEX_UNLOCK (scaled_font->mutex); +} + +/* If a scaled font wants to unlock the font map while still being + * created (needed for user-fonts), we need to take extra care not + * ending up with multiple identical scaled fonts being created. + * + * What we do is, we create a fake identical scaled font, and mark + * it as placeholder, lock its mutex, and insert that in the fontmap + * hash table. This makes other code trying to create an identical + * scaled font to just wait and retry. + * + * The reason we have to create a fake scaled font instead of just using + * scaled_font is for lifecycle management: we need to (or rather, + * other code needs to) reference the scaled_font in the hash table. + * We can't do that on the input scaled_font as it may be freed by + * font backend upon error. + */ + +cairo_status_t +_cairo_scaled_font_register_placeholder_and_unlock_font_map (cairo_scaled_font_t *scaled_font) +{ + cairo_status_t status; + cairo_scaled_font_t *placeholder_scaled_font; + + assert (CAIRO_MUTEX_IS_LOCKED (_cairo_scaled_font_map_mutex)); + + status = scaled_font->status; + if (unlikely (status)) + return status; + + placeholder_scaled_font = _cairo_calloc (sizeof (cairo_scaled_font_t)); + if (unlikely (placeholder_scaled_font == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + /* full initialization is wasteful, but who cares... */ + status = _cairo_scaled_font_init (placeholder_scaled_font, + scaled_font->font_face, + &scaled_font->font_matrix, + &scaled_font->ctm, + &scaled_font->options, + NULL); + if (unlikely (status)) + goto FREE_PLACEHOLDER; + + placeholder_scaled_font->placeholder = TRUE; + + placeholder_scaled_font->hash_entry.hash + = _cairo_scaled_font_compute_hash (placeholder_scaled_font); + status = _cairo_hash_table_insert (cairo_scaled_font_map->hash_table, + &placeholder_scaled_font->hash_entry); + if (unlikely (status)) + goto FINI_PLACEHOLDER; + + CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex); + CAIRO_MUTEX_LOCK (placeholder_scaled_font->mutex); + + return CAIRO_STATUS_SUCCESS; + + FINI_PLACEHOLDER: + _cairo_scaled_font_fini_internal (placeholder_scaled_font); + FREE_PLACEHOLDER: + free (placeholder_scaled_font); + + return _cairo_scaled_font_set_error (scaled_font, status); +} + +void +_cairo_scaled_font_unregister_placeholder_and_lock_font_map (cairo_scaled_font_t *scaled_font) +{ + cairo_scaled_font_t *placeholder_scaled_font; + + CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex); + + /* temporary hash value to match the placeholder */ + scaled_font->hash_entry.hash + = _cairo_scaled_font_compute_hash (scaled_font); + placeholder_scaled_font = + _cairo_hash_table_lookup (cairo_scaled_font_map->hash_table, + &scaled_font->hash_entry); + assert (placeholder_scaled_font != NULL); + assert (placeholder_scaled_font->placeholder); + assert (CAIRO_MUTEX_IS_LOCKED (placeholder_scaled_font->mutex)); + + _cairo_hash_table_remove (cairo_scaled_font_map->hash_table, + &placeholder_scaled_font->hash_entry); + + CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex); + + CAIRO_MUTEX_UNLOCK (placeholder_scaled_font->mutex); + cairo_scaled_font_destroy (placeholder_scaled_font); + + CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex); +} + +static void +_cairo_scaled_font_placeholder_wait_for_creation_to_finish (cairo_scaled_font_t *placeholder_scaled_font) +{ + /* reference the place holder so it doesn't go away */ + cairo_scaled_font_reference (placeholder_scaled_font); + + /* now unlock the fontmap mutex so creation has a chance to finish */ + CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex); + + /* wait on placeholder mutex until we are awaken */ + CAIRO_MUTEX_LOCK (placeholder_scaled_font->mutex); + + /* ok, creation done. just clean up and back out */ + CAIRO_MUTEX_UNLOCK (placeholder_scaled_font->mutex); + cairo_scaled_font_destroy (placeholder_scaled_font); + + CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex); +} + +/* Fowler / Noll / Vo (FNV) Hash (http://www.isthe.com/chongo/tech/comp/fnv/) + * + * Not necessarily better than a lot of other hashes, but should be OK, and + * well tested with binary data. + */ + +#define FNV_64_PRIME ((uint64_t)0x00000100000001B3) +#define FNV1_64_INIT ((uint64_t)0xcbf29ce484222325) + +static uint64_t +_hash_matrix_fnv (const cairo_matrix_t *matrix, + uint64_t hval) +{ + const uint8_t *buffer = (const uint8_t *) matrix; + int len = sizeof (cairo_matrix_t); + do { + hval *= FNV_64_PRIME; + hval ^= *buffer++; + } while (--len); + + return hval; +} + +static uint64_t +_hash_mix_bits (uint64_t hash) +{ + hash += hash << 12; + hash ^= hash >> 7; + hash += hash << 3; + hash ^= hash >> 17; + hash += hash << 5; + return hash; +} + +static uintptr_t +_cairo_scaled_font_compute_hash (cairo_scaled_font_t *scaled_font) +{ + uint64_t hash = FNV1_64_INIT; + + /* We do a bytewise hash on the font matrices */ + hash = _hash_matrix_fnv (&scaled_font->font_matrix, hash); + hash = _hash_matrix_fnv (&scaled_font->ctm, hash); + hash = _hash_mix_bits (hash); + + hash ^= (uintptr_t) scaled_font->original_font_face; + hash ^= cairo_font_options_hash (&scaled_font->options); + + /* final mixing of bits */ + hash = _hash_mix_bits (hash); + assert (hash != ZOMBIE); + + return hash; +} + +static void +_cairo_scaled_font_init_key (cairo_scaled_font_t *scaled_font, + cairo_font_face_t *font_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options) +{ + scaled_font->status = CAIRO_STATUS_SUCCESS; + scaled_font->placeholder = FALSE; + scaled_font->font_face = font_face; + scaled_font->original_font_face = font_face; + scaled_font->font_matrix = *font_matrix; + scaled_font->ctm = *ctm; + /* ignore translation values in the ctm */ + scaled_font->ctm.x0 = 0.; + scaled_font->ctm.y0 = 0.; + _cairo_font_options_init_copy (&scaled_font->options, options); + + scaled_font->hash_entry.hash = + _cairo_scaled_font_compute_hash (scaled_font); +} + +static void +_cairo_scaled_font_fini_key (cairo_scaled_font_t *scaled_font) +{ + _cairo_font_options_fini (&scaled_font->options); +} + +static cairo_bool_t +_cairo_scaled_font_keys_equal (const void *abstract_key_a, + const void *abstract_key_b) +{ + const cairo_scaled_font_t *key_a = abstract_key_a; + const cairo_scaled_font_t *key_b = abstract_key_b; + + return key_a->original_font_face == key_b->original_font_face && + memcmp ((unsigned char *)(&key_a->font_matrix.xx), + (unsigned char *)(&key_b->font_matrix.xx), + sizeof(cairo_matrix_t)) == 0 && + memcmp ((unsigned char *)(&key_a->ctm.xx), + (unsigned char *)(&key_b->ctm.xx), + sizeof(cairo_matrix_t)) == 0 && + cairo_font_options_equal (&key_a->options, &key_b->options); +} + +static cairo_bool_t +_cairo_scaled_font_matches (const cairo_scaled_font_t *scaled_font, + const cairo_font_face_t *font_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options) +{ + return scaled_font->original_font_face == font_face && + memcmp ((unsigned char *)(&scaled_font->font_matrix.xx), + (unsigned char *)(&font_matrix->xx), + sizeof(cairo_matrix_t)) == 0 && + memcmp ((unsigned char *)(&scaled_font->ctm.xx), + (unsigned char *)(&ctm->xx), + sizeof(cairo_matrix_t)) == 0 && + cairo_font_options_equal (&scaled_font->options, options); +} + +/* + * Basic #cairo_scaled_font_t object management + */ + +cairo_status_t +_cairo_scaled_font_init (cairo_scaled_font_t *scaled_font, + cairo_font_face_t *font_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + const cairo_scaled_font_backend_t *backend) +{ + cairo_status_t status; + + status = cairo_font_options_status ((cairo_font_options_t *) options); + if (unlikely (status)) + return status; + + scaled_font->status = CAIRO_STATUS_SUCCESS; + scaled_font->placeholder = FALSE; + scaled_font->font_face = font_face; + scaled_font->original_font_face = font_face; + scaled_font->font_matrix = *font_matrix; + scaled_font->ctm = *ctm; + /* ignore translation values in the ctm */ + scaled_font->ctm.x0 = 0.; + scaled_font->ctm.y0 = 0.; + _cairo_font_options_init_copy (&scaled_font->options, options); + + cairo_matrix_multiply (&scaled_font->scale, + &scaled_font->font_matrix, + &scaled_font->ctm); + + scaled_font->max_scale = MAX (fabs (scaled_font->scale.xx) + fabs (scaled_font->scale.xy), + fabs (scaled_font->scale.yx) + fabs (scaled_font->scale.yy)); + scaled_font->scale_inverse = scaled_font->scale; + status = cairo_matrix_invert (&scaled_font->scale_inverse); + if (unlikely (status)) { + /* If the font scale matrix is rank 0, just using an all-zero inverse matrix + * makes everything work correctly. This make font size 0 work without + * producing an error. + * + * FIXME: If the scale is rank 1, we still go into error mode. But then + * again, that's what we do everywhere in cairo. + * + * Also, the check for == 0. below may be too harsh... + */ + if (_cairo_matrix_is_scale_0 (&scaled_font->scale)) { + cairo_matrix_init (&scaled_font->scale_inverse, + 0, 0, 0, 0, + -scaled_font->scale.x0, + -scaled_font->scale.y0); + } else + return status; + } + + scaled_font->glyphs = _cairo_hash_table_create (NULL); + if (unlikely (scaled_font->glyphs == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + cairo_list_init (&scaled_font->glyph_pages); + scaled_font->cache_frozen = FALSE; + scaled_font->global_cache_frozen = FALSE; + _cairo_array_init (&scaled_font->recording_surfaces_to_free, sizeof (cairo_surface_t *)); + + scaled_font->holdover = FALSE; + scaled_font->finished = FALSE; + + CAIRO_REFERENCE_COUNT_INIT (&scaled_font->ref_count, 1); + + _cairo_user_data_array_init (&scaled_font->user_data); + + cairo_font_face_reference (font_face); + scaled_font->original_font_face = NULL; + + CAIRO_RECURSIVE_MUTEX_INIT (scaled_font->mutex); + + cairo_list_init (&scaled_font->dev_privates); + + scaled_font->backend = backend; + cairo_list_init (&scaled_font->link); + + return CAIRO_STATUS_SUCCESS; +} + +static void _cairo_scaled_font_free_recording_surfaces (cairo_scaled_font_t *scaled_font) +{ + int num_recording_surfaces; + cairo_surface_t *surface; + + num_recording_surfaces = _cairo_array_num_elements (&scaled_font->recording_surfaces_to_free); + if (num_recording_surfaces > 0) { + for (int i = 0; i < num_recording_surfaces; i++) { + _cairo_array_copy_element (&scaled_font->recording_surfaces_to_free, i, &surface); + cairo_surface_finish (surface); + cairo_surface_destroy (surface); + } + _cairo_array_truncate (&scaled_font->recording_surfaces_to_free, 0); + } +} + +void +_cairo_scaled_font_freeze_cache (cairo_scaled_font_t *scaled_font) +{ + /* ensure we do not modify an error object */ + assert (scaled_font->status == CAIRO_STATUS_SUCCESS); + + CAIRO_MUTEX_LOCK (scaled_font->mutex); + scaled_font->cache_frozen = TRUE; +} + +void +_cairo_scaled_font_thaw_cache (cairo_scaled_font_t *scaled_font) +{ + assert (scaled_font->cache_frozen); + + if (scaled_font->global_cache_frozen) { + CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex); + _cairo_cache_thaw (&cairo_scaled_glyph_page_cache); + CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex); + scaled_font->global_cache_frozen = FALSE; + } + + _cairo_scaled_font_free_recording_surfaces (scaled_font); + + scaled_font->cache_frozen = FALSE; + CAIRO_MUTEX_UNLOCK (scaled_font->mutex); +} + +void +_cairo_scaled_font_reset_cache (cairo_scaled_font_t *scaled_font) +{ + cairo_scaled_glyph_page_t *page; + + CAIRO_MUTEX_LOCK (scaled_font->mutex); + assert (! scaled_font->cache_frozen); + assert (! scaled_font->global_cache_frozen); + CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex); + + cairo_list_foreach_entry (page, + cairo_scaled_glyph_page_t, + &scaled_font->glyph_pages, + link) { + cairo_scaled_glyph_page_cache.size -= page->cache_entry.size; + _cairo_hash_table_remove (cairo_scaled_glyph_page_cache.hash_table, + (cairo_hash_entry_t *) &page->cache_entry); + } + + CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex); + + /* Destroy scaled_font's pages while holding its lock only, and not the + * global page cache lock. The destructor can cause us to recurse and + * end up back here for a different scaled_font. */ + + while (! cairo_list_is_empty (&scaled_font->glyph_pages)) { + page = cairo_list_first_entry (&scaled_font->glyph_pages, + cairo_scaled_glyph_page_t, + link); + _cairo_scaled_glyph_page_destroy (scaled_font, page); + } + + CAIRO_MUTEX_UNLOCK (scaled_font->mutex); +} + +cairo_status_t +_cairo_scaled_font_set_metrics (cairo_scaled_font_t *scaled_font, + cairo_font_extents_t *fs_metrics) +{ + cairo_status_t status; + double font_scale_x, font_scale_y; + + scaled_font->fs_extents = *fs_metrics; + + status = _cairo_matrix_compute_basis_scale_factors (&scaled_font->font_matrix, + &font_scale_x, &font_scale_y, + 1); + if (unlikely (status)) + return status; + + /* + * The font responded in unscaled units, scale by the font + * matrix scale factors to get to user space + */ + + scaled_font->extents.ascent = fs_metrics->ascent * font_scale_y; + scaled_font->extents.descent = fs_metrics->descent * font_scale_y; + scaled_font->extents.height = fs_metrics->height * font_scale_y; + scaled_font->extents.max_x_advance = fs_metrics->max_x_advance * font_scale_x; + scaled_font->extents.max_y_advance = fs_metrics->max_y_advance * font_scale_y; + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_scaled_font_fini_internal (cairo_scaled_font_t *scaled_font) +{ + assert (! scaled_font->cache_frozen); + assert (! scaled_font->global_cache_frozen); + scaled_font->finished = TRUE; + + _cairo_scaled_font_reset_cache (scaled_font); + _cairo_hash_table_destroy (scaled_font->glyphs); + _cairo_font_options_fini (&scaled_font->options); + + cairo_font_face_destroy (scaled_font->font_face); + cairo_font_face_destroy (scaled_font->original_font_face); + + _cairo_scaled_font_free_recording_surfaces (scaled_font); + _cairo_array_fini (&scaled_font->recording_surfaces_to_free); + + CAIRO_MUTEX_FINI (scaled_font->mutex); + + while (! cairo_list_is_empty (&scaled_font->dev_privates)) { + cairo_scaled_font_private_t *private = + cairo_list_first_entry (&scaled_font->dev_privates, + cairo_scaled_font_private_t, + link); + private->destroy (private, scaled_font); + } + + if (scaled_font->backend != NULL && scaled_font->backend->fini != NULL) + scaled_font->backend->fini (scaled_font); + + _cairo_user_data_array_fini (&scaled_font->user_data); +} + +void +_cairo_scaled_font_fini (cairo_scaled_font_t *scaled_font) +{ + /* Release the lock to avoid the possibility of a recursive + * deadlock when the scaled font destroy closure gets called. */ + CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_map_mutex); + _cairo_scaled_font_fini_internal (scaled_font); + CAIRO_MUTEX_LOCK (_cairo_scaled_font_map_mutex); +} + +void +_cairo_scaled_font_attach_private (cairo_scaled_font_t *scaled_font, + cairo_scaled_font_private_t *private, + const void *key, + void (*destroy) (cairo_scaled_font_private_t *, + cairo_scaled_font_t *)) +{ + private->key = key; + private->destroy = destroy; + cairo_list_add (&private->link, &scaled_font->dev_privates); +} + +cairo_scaled_font_private_t * +_cairo_scaled_font_find_private (cairo_scaled_font_t *scaled_font, + const void *key) +{ + cairo_scaled_font_private_t *priv; + + cairo_list_foreach_entry (priv, cairo_scaled_font_private_t, + &scaled_font->dev_privates, link) + { + if (priv->key == key) { + if (priv->link.prev != &scaled_font->dev_privates) + cairo_list_move (&priv->link, &scaled_font->dev_privates); + return priv; + } + } + + return NULL; +} + +void +_cairo_scaled_glyph_attach_private (cairo_scaled_glyph_t *scaled_glyph, + cairo_scaled_glyph_private_t *private, + const void *key, + void (*destroy) (cairo_scaled_glyph_private_t *, + cairo_scaled_glyph_t *, + cairo_scaled_font_t *)) +{ + private->key = key; + private->destroy = destroy; + cairo_list_add (&private->link, &scaled_glyph->dev_privates); +} + +cairo_scaled_glyph_private_t * +_cairo_scaled_glyph_find_private (cairo_scaled_glyph_t *scaled_glyph, + const void *key) +{ + cairo_scaled_glyph_private_t *priv; + + cairo_list_foreach_entry (priv, cairo_scaled_glyph_private_t, + &scaled_glyph->dev_privates, link) + { + if (priv->key == key) { + if (priv->link.prev != &scaled_glyph->dev_privates) + cairo_list_move (&priv->link, &scaled_glyph->dev_privates); + return priv; + } + } + + return NULL; +} + +/** + * cairo_scaled_font_create: + * @font_face: a #cairo_font_face_t + * @font_matrix: font space to user space transformation matrix for the + * font. In the simplest case of a N point font, this matrix is + * just a scale by N, but it can also be used to shear the font + * or stretch it unequally along the two axes. See + * cairo_set_font_matrix(). + * @ctm: user to device transformation matrix with which the font will + * be used. + * @options: options to use when getting metrics for the font and + * rendering with it. + * + * Creates a #cairo_scaled_font_t object from a font face and matrices that + * describe the size of the font and the environment in which it will + * be used. + * + * Return value: a newly created #cairo_scaled_font_t. Destroy with + * cairo_scaled_font_destroy() + * + * Since: 1.0 + **/ +cairo_scaled_font_t * +cairo_scaled_font_create (cairo_font_face_t *font_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options) +{ + cairo_status_t status; + cairo_scaled_font_map_t *font_map; + cairo_font_face_t *original_font_face = font_face; + cairo_scaled_font_t key, *old = NULL, *scaled_font = NULL, *dead = NULL; + double det; + + status = font_face->status; + if (unlikely (status)) + return _cairo_scaled_font_create_in_error (status); + + det = _cairo_matrix_compute_determinant (font_matrix); + if (! ISFINITE (det)) + return _cairo_scaled_font_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_MATRIX)); + + det = _cairo_matrix_compute_determinant (ctm); + if (! ISFINITE (det)) + return _cairo_scaled_font_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_MATRIX)); + + status = cairo_font_options_status ((cairo_font_options_t *) options); + if (unlikely (status)) + return _cairo_scaled_font_create_in_error (status); + + /* Note that degenerate ctm or font_matrix *are* allowed. + * We want to support a font size of 0. */ + + font_map = _cairo_scaled_font_map_lock (); + if (unlikely (font_map == NULL)) + return _cairo_scaled_font_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + scaled_font = font_map->mru_scaled_font; + if (scaled_font != NULL && + _cairo_scaled_font_matches (scaled_font, + font_face, font_matrix, ctm, options)) + { + assert (scaled_font->hash_entry.hash != ZOMBIE); + assert (! scaled_font->placeholder); + + if (likely (scaled_font->status == CAIRO_STATUS_SUCCESS)) { + /* We increment the reference count manually here, (rather + * than calling into cairo_scaled_font_reference), since we + * must modify the reference count while our lock is still + * held. */ + _cairo_reference_count_inc (&scaled_font->ref_count); + _cairo_scaled_font_map_unlock (); + return scaled_font; + } + + /* the font has been put into an error status - abandon the cache */ + _cairo_hash_table_remove (font_map->hash_table, + &scaled_font->hash_entry); + scaled_font->hash_entry.hash = ZOMBIE; + dead = scaled_font; + font_map->mru_scaled_font = NULL; + } + + _cairo_scaled_font_init_key (&key, font_face, font_matrix, ctm, options); + + while ((scaled_font = _cairo_hash_table_lookup (font_map->hash_table, + &key.hash_entry))) + { + if (! scaled_font->placeholder) + break; + + /* If the scaled font is being created (happens for user-font), + * just wait until it's done, then retry */ + _cairo_scaled_font_placeholder_wait_for_creation_to_finish (scaled_font); + } + _cairo_scaled_font_fini_key (&key); + + if (scaled_font != NULL) { + /* If the original reference count is 0, then this font must have + * been found in font_map->holdovers, (which means this caching is + * actually working). So now we remove it from the holdovers + * array, unless we caught the font in the middle of destruction. + */ + if (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count)) { + if (scaled_font->holdover) { + int i; + + for (i = 0; i < font_map->num_holdovers; i++) { + if (font_map->holdovers[i] == scaled_font) { + font_map->num_holdovers--; + memmove (&font_map->holdovers[i], + &font_map->holdovers[i+1], + (font_map->num_holdovers - i) * sizeof (cairo_scaled_font_t*)); + break; + } + } + + scaled_font->holdover = FALSE; + } + + /* reset any error status */ + scaled_font->status = CAIRO_STATUS_SUCCESS; + } + + if (likely (scaled_font->status == CAIRO_STATUS_SUCCESS)) { + /* We increment the reference count manually here, (rather + * than calling into cairo_scaled_font_reference), since we + * must modify the reference count while our lock is still + * held. */ + + old = font_map->mru_scaled_font; + font_map->mru_scaled_font = scaled_font; + /* increment reference count for the mru cache */ + _cairo_reference_count_inc (&scaled_font->ref_count); + /* and increment for the returned reference */ + _cairo_reference_count_inc (&scaled_font->ref_count); + _cairo_scaled_font_map_unlock (); + + cairo_scaled_font_destroy (old); + if (font_face != original_font_face) + cairo_font_face_destroy (font_face); + + return scaled_font; + } + + /* the font has been put into an error status - abandon the cache */ + _cairo_hash_table_remove (font_map->hash_table, + &scaled_font->hash_entry); + scaled_font->hash_entry.hash = ZOMBIE; + } + + + /* Otherwise create it and insert it into the hash table. */ + if (font_face->backend->get_implementation != NULL) { + font_face = font_face->backend->get_implementation (font_face, + font_matrix, + ctm, + options); + if (unlikely (font_face->status)) { + _cairo_scaled_font_map_unlock (); + return _cairo_scaled_font_create_in_error (font_face->status); + } + } + + status = font_face->backend->scaled_font_create (font_face, font_matrix, + ctm, options, &scaled_font); + if (unlikely (status)) { + _cairo_scaled_font_map_unlock (); + if (font_face != original_font_face) + cairo_font_face_destroy (font_face); + + if (dead != NULL) + cairo_scaled_font_destroy (dead); + + return _cairo_scaled_font_create_in_error (status); + } + /* Or did we encounter an error whilst constructing the scaled font? */ + if (unlikely (scaled_font->status)) { + _cairo_scaled_font_map_unlock (); + if (font_face != original_font_face) + cairo_font_face_destroy (font_face); + + if (dead != NULL) + cairo_scaled_font_destroy (dead); + + return scaled_font; + } + + /* Our caching above is defeated if the backend switches fonts on us - + * e.g. old incarnations of toy-font-face and lazily resolved + * ft-font-faces + */ + assert (scaled_font->font_face == font_face); + assert (! scaled_font->cache_frozen); + assert (! scaled_font->global_cache_frozen); + + scaled_font->original_font_face = + cairo_font_face_reference (original_font_face); + + scaled_font->hash_entry.hash = _cairo_scaled_font_compute_hash(scaled_font); + + status = _cairo_hash_table_insert (font_map->hash_table, + &scaled_font->hash_entry); + if (likely (status == CAIRO_STATUS_SUCCESS)) { + old = font_map->mru_scaled_font; + font_map->mru_scaled_font = scaled_font; + _cairo_reference_count_inc (&scaled_font->ref_count); + } + + _cairo_scaled_font_map_unlock (); + + cairo_scaled_font_destroy (old); + if (font_face != original_font_face) + cairo_font_face_destroy (font_face); + + if (dead != NULL) + cairo_scaled_font_destroy (dead); + + if (unlikely (status)) { + /* We can't call _cairo_scaled_font_destroy here since it expects + * that the font has already been successfully inserted into the + * hash table. */ + _cairo_scaled_font_fini_internal (scaled_font); + free (scaled_font); + return _cairo_scaled_font_create_in_error (status); + } + + return scaled_font; +} + +static cairo_scaled_font_t *_cairo_scaled_font_nil_objects[CAIRO_STATUS_LAST_STATUS + 1]; + +/* XXX This should disappear in favour of a common pool of error objects. */ +cairo_scaled_font_t * +_cairo_scaled_font_create_in_error (cairo_status_t status) +{ + cairo_scaled_font_t *scaled_font; + + assert (status != CAIRO_STATUS_SUCCESS); + + if (status == CAIRO_STATUS_NO_MEMORY) + return (cairo_scaled_font_t *) &_cairo_scaled_font_nil; + + CAIRO_MUTEX_LOCK (_cairo_scaled_font_error_mutex); + scaled_font = _cairo_scaled_font_nil_objects[status]; + if (unlikely (scaled_font == NULL)) { + scaled_font = _cairo_calloc (sizeof (cairo_scaled_font_t)); + if (unlikely (scaled_font == NULL)) { + CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_error_mutex); + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_scaled_font_t *) &_cairo_scaled_font_nil; + } + + *scaled_font = _cairo_scaled_font_nil; + scaled_font->status = status; + _cairo_scaled_font_nil_objects[status] = scaled_font; + } + CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_error_mutex); + + return scaled_font; +} + +void +_cairo_scaled_font_reset_static_data (void) +{ + int status; + + CAIRO_MUTEX_LOCK (_cairo_scaled_font_error_mutex); + for (status = CAIRO_STATUS_SUCCESS; + status <= CAIRO_STATUS_LAST_STATUS; + status++) + { + free (_cairo_scaled_font_nil_objects[status]); + _cairo_scaled_font_nil_objects[status] = NULL; + } + CAIRO_MUTEX_UNLOCK (_cairo_scaled_font_error_mutex); + + CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex); + if (cairo_scaled_glyph_page_cache.hash_table != NULL) { + _cairo_cache_fini (&cairo_scaled_glyph_page_cache); + cairo_scaled_glyph_page_cache.hash_table = NULL; + } + CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex); +} + +/** + * cairo_scaled_font_reference: + * @scaled_font: a #cairo_scaled_font_t, (may be %NULL in which case + * this function does nothing) + * + * Increases the reference count on @scaled_font by one. This prevents + * @scaled_font from being destroyed until a matching call to + * cairo_scaled_font_destroy() is made. + * + * Use cairo_scaled_font_get_reference_count() to get the number of + * references to a #cairo_scaled_font_t. + * + * Returns: the referenced #cairo_scaled_font_t + * + * Since: 1.0 + **/ +cairo_scaled_font_t * +cairo_scaled_font_reference (cairo_scaled_font_t *scaled_font) +{ + if (scaled_font == NULL || + CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count)) + return scaled_font; + + assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count)); + + _cairo_reference_count_inc (&scaled_font->ref_count); + + return scaled_font; +} + +/** + * cairo_scaled_font_destroy: + * @scaled_font: a #cairo_scaled_font_t + * + * Decreases the reference count on @font by one. If the result + * is zero, then @font and all associated resources are freed. + * See cairo_scaled_font_reference(). + * + * Since: 1.0 + **/ +void +cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font) +{ + cairo_scaled_font_t *lru = NULL; + cairo_scaled_font_map_t *font_map; + + assert (CAIRO_MUTEX_IS_UNLOCKED (_cairo_scaled_font_map_mutex)); + + if (scaled_font == NULL || + CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count)) + return; + + assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count)); + + font_map = _cairo_scaled_font_map_lock (); + assert (font_map != NULL); + + if (! _cairo_reference_count_dec_and_test (&scaled_font->ref_count)) + goto unlock; + + assert (! scaled_font->cache_frozen); + assert (! scaled_font->global_cache_frozen); + + /* Another thread may have resurrected the font whilst we waited */ + if (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count)) { + if (! scaled_font->placeholder && + scaled_font->hash_entry.hash != ZOMBIE) + { + /* Another thread may have already inserted us into the holdovers */ + if (scaled_font->holdover) + goto unlock; + + /* Rather than immediately destroying this object, we put it into + * the font_map->holdovers array in case it will get used again + * soon (and is why we must hold the lock over the atomic op on + * the reference count). To make room for it, we do actually + * destroy the least-recently-used holdover. + */ + + if (font_map->num_holdovers == CAIRO_SCALED_FONT_MAX_HOLDOVERS) { + lru = font_map->holdovers[0]; + assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&lru->ref_count)); + + _cairo_hash_table_remove (font_map->hash_table, + &lru->hash_entry); + + font_map->num_holdovers--; + memmove (&font_map->holdovers[0], + &font_map->holdovers[1], + font_map->num_holdovers * sizeof (cairo_scaled_font_t*)); + } + + font_map->holdovers[font_map->num_holdovers++] = scaled_font; + scaled_font->holdover = TRUE; + } else + lru = scaled_font; + } + + unlock: + _cairo_scaled_font_map_unlock (); + + /* If we pulled an item from the holdovers array, (while the font + * map lock was held, of course), then there is no way that anyone + * else could have acquired a reference to it. So we can now + * safely call fini on it without any lock held. This is desirable + * as we never want to call into any backend function with a lock + * held. */ + if (lru != NULL) { + _cairo_scaled_font_fini_internal (lru); + free (lru); + } +} + +/** + * cairo_scaled_font_get_reference_count: + * @scaled_font: a #cairo_scaled_font_t + * + * Returns the current reference count of @scaled_font. + * + * Return value: the current reference count of @scaled_font. If the + * object is a nil object, 0 will be returned. + * + * Since: 1.4 + **/ +unsigned int +cairo_scaled_font_get_reference_count (cairo_scaled_font_t *scaled_font) +{ + if (scaled_font == NULL || + CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count)) + return 0; + + return CAIRO_REFERENCE_COUNT_GET_VALUE (&scaled_font->ref_count); +} + +/** + * cairo_scaled_font_get_user_data: + * @scaled_font: a #cairo_scaled_font_t + * @key: the address of the #cairo_user_data_key_t the user data was + * attached to + * + * Return user data previously attached to @scaled_font using the + * specified key. If no user data has been attached with the given + * key this function returns %NULL. + * + * Return value: the user data previously attached or %NULL. + * + * Since: 1.4 + **/ +void * +cairo_scaled_font_get_user_data (cairo_scaled_font_t *scaled_font, + const cairo_user_data_key_t *key) +{ + return _cairo_user_data_array_get_data (&scaled_font->user_data, + key); +} + +/** + * cairo_scaled_font_set_user_data: + * @scaled_font: a #cairo_scaled_font_t + * @key: the address of a #cairo_user_data_key_t to attach the user data to + * @user_data: the user data to attach to the #cairo_scaled_font_t + * @destroy: a #cairo_destroy_func_t which will be called when the + * #cairo_t is destroyed or when new user data is attached using the + * same key. + * + * Attach user data to @scaled_font. To remove user data from a surface, + * call this function with the key that was used to set it and %NULL + * for @data. + * + * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a + * slot could not be allocated for the user data. + * + * Since: 1.4 + **/ +cairo_status_t +cairo_scaled_font_set_user_data (cairo_scaled_font_t *scaled_font, + const cairo_user_data_key_t *key, + void *user_data, + cairo_destroy_func_t destroy) +{ + if (CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count)) + return scaled_font->status; + + return _cairo_user_data_array_set_data (&scaled_font->user_data, + key, user_data, destroy); +} + +/* Public font API follows. */ + +/** + * cairo_scaled_font_extents: + * @scaled_font: a #cairo_scaled_font_t + * @extents: a #cairo_font_extents_t which to store the retrieved extents. + * + * Gets the metrics for a #cairo_scaled_font_t. + * + * Since: 1.0 + **/ +void +cairo_scaled_font_extents (cairo_scaled_font_t *scaled_font, + cairo_font_extents_t *extents) +{ + if (scaled_font->status) { + extents->ascent = 0.0; + extents->descent = 0.0; + extents->height = 0.0; + extents->max_x_advance = 0.0; + extents->max_y_advance = 0.0; + return; + } + + *extents = scaled_font->extents; +} + +/** + * cairo_scaled_font_text_extents: + * @scaled_font: a #cairo_scaled_font_t + * @utf8: a NUL-terminated string of text, encoded in UTF-8 + * @extents: a #cairo_text_extents_t which to store the retrieved extents. + * + * Gets the extents for a string of text. The extents describe a + * user-space rectangle that encloses the "inked" portion of the text + * drawn at the origin (0,0) (as it would be drawn by cairo_show_text() + * if the cairo graphics state were set to the same font_face, + * font_matrix, ctm, and font_options as @scaled_font). Additionally, + * the x_advance and y_advance values indicate the amount by which the + * current point would be advanced by cairo_show_text(). + * + * Note that whitespace characters do not directly contribute to the + * size of the rectangle (extents.width and extents.height). They do + * contribute indirectly by changing the position of non-whitespace + * characters. In particular, trailing whitespace characters are + * likely to not affect the size of the rectangle, though they will + * affect the x_advance and y_advance values. + * + * Since: 1.2 + **/ +void +cairo_scaled_font_text_extents (cairo_scaled_font_t *scaled_font, + const char *utf8, + cairo_text_extents_t *extents) +{ + cairo_status_t status; + cairo_glyph_t *glyphs = NULL; + int num_glyphs; + + if (scaled_font->status) + goto ZERO_EXTENTS; + + if (utf8 == NULL) + goto ZERO_EXTENTS; + + status = cairo_scaled_font_text_to_glyphs (scaled_font, 0., 0., + utf8, -1, + &glyphs, &num_glyphs, + NULL, NULL, + NULL); + if (unlikely (status)) { + status = _cairo_scaled_font_set_error (scaled_font, status); + goto ZERO_EXTENTS; + } + + cairo_scaled_font_glyph_extents (scaled_font, glyphs, num_glyphs, extents); + free (glyphs); + + return; + +ZERO_EXTENTS: + extents->x_bearing = 0.0; + extents->y_bearing = 0.0; + extents->width = 0.0; + extents->height = 0.0; + extents->x_advance = 0.0; + extents->y_advance = 0.0; +} + +/** + * cairo_scaled_font_glyph_extents: + * @scaled_font: a #cairo_scaled_font_t + * @glyphs: an array of glyph IDs with X and Y offsets. + * @num_glyphs: the number of glyphs in the @glyphs array + * @extents: a #cairo_text_extents_t which to store the retrieved extents. + * + * Gets the extents for an array of glyphs. The extents describe a + * user-space rectangle that encloses the "inked" portion of the + * glyphs, (as they would be drawn by cairo_show_glyphs() if the cairo + * graphics state were set to the same font_face, font_matrix, ctm, + * and font_options as @scaled_font). Additionally, the x_advance and + * y_advance values indicate the amount by which the current point + * would be advanced by cairo_show_glyphs(). + * + * Note that whitespace glyphs do not contribute to the size of the + * rectangle (extents.width and extents.height). + * + * Since: 1.0 + **/ +void +cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_text_extents_t *extents) +{ + cairo_status_t status; + int i; + double min_x = 0.0, min_y = 0.0, max_x = 0.0, max_y = 0.0; + cairo_bool_t visible = FALSE; + cairo_scaled_glyph_t *scaled_glyph = NULL; + + extents->x_bearing = 0.0; + extents->y_bearing = 0.0; + extents->width = 0.0; + extents->height = 0.0; + extents->x_advance = 0.0; + extents->y_advance = 0.0; + + if (unlikely (scaled_font->status)) + goto ZERO_EXTENTS; + + if (num_glyphs == 0) + goto ZERO_EXTENTS; + + if (unlikely (num_glyphs < 0)) { + _cairo_error_throw (CAIRO_STATUS_NEGATIVE_COUNT); + /* XXX Can't propagate error */ + goto ZERO_EXTENTS; + } + + if (unlikely (glyphs == NULL)) { + _cairo_error_throw (CAIRO_STATUS_NULL_POINTER); + /* XXX Can't propagate error */ + goto ZERO_EXTENTS; + } + + _cairo_scaled_font_freeze_cache (scaled_font); + + for (i = 0; i < num_glyphs; i++) { + double left, top, right, bottom; + + status = _cairo_scaled_glyph_lookup (scaled_font, + glyphs[i].index, + CAIRO_SCALED_GLYPH_INFO_METRICS, + NULL, /* foreground color */ + &scaled_glyph); + if (unlikely (status)) { + status = _cairo_scaled_font_set_error (scaled_font, status); + goto UNLOCK; + } + + /* "Ink" extents should skip "invisible" glyphs */ + if (scaled_glyph->metrics.width == 0 || scaled_glyph->metrics.height == 0) + continue; + + left = scaled_glyph->metrics.x_bearing + glyphs[i].x; + right = left + scaled_glyph->metrics.width; + top = scaled_glyph->metrics.y_bearing + glyphs[i].y; + bottom = top + scaled_glyph->metrics.height; + + if (!visible) { + visible = TRUE; + min_x = left; + max_x = right; + min_y = top; + max_y = bottom; + } else { + if (left < min_x) min_x = left; + if (right > max_x) max_x = right; + if (top < min_y) min_y = top; + if (bottom > max_y) max_y = bottom; + } + } + + if (visible) { + extents->x_bearing = min_x - glyphs[0].x; + extents->y_bearing = min_y - glyphs[0].y; + extents->width = max_x - min_x; + extents->height = max_y - min_y; + } else { + extents->x_bearing = 0.0; + extents->y_bearing = 0.0; + extents->width = 0.0; + extents->height = 0.0; + } + + if (num_glyphs) { + double x0, y0, x1, y1; + + x0 = glyphs[0].x; + y0 = glyphs[0].y; + + /* scaled_glyph contains the glyph for num_glyphs - 1 already. */ + x1 = glyphs[num_glyphs - 1].x + scaled_glyph->metrics.x_advance; + y1 = glyphs[num_glyphs - 1].y + scaled_glyph->metrics.y_advance; + + extents->x_advance = x1 - x0; + extents->y_advance = y1 - y0; + } else { + extents->x_advance = 0.0; + extents->y_advance = 0.0; + } + + UNLOCK: + _cairo_scaled_font_thaw_cache (scaled_font); + return; + +ZERO_EXTENTS: + extents->x_bearing = 0.0; + extents->y_bearing = 0.0; + extents->width = 0.0; + extents->height = 0.0; + extents->x_advance = 0.0; + extents->y_advance = 0.0; +} + +#define GLYPH_LUT_SIZE 64 +static cairo_status_t +cairo_scaled_font_text_to_glyphs_internal_cached (cairo_scaled_font_t *scaled_font, + double x, + double y, + const char *utf8, + cairo_glyph_t *glyphs, + cairo_text_cluster_t **clusters, + int num_chars) +{ + struct glyph_lut_elt { + unsigned long index; + double x_advance; + double y_advance; + } glyph_lut[GLYPH_LUT_SIZE]; + uint32_t glyph_lut_unicode[GLYPH_LUT_SIZE]; + cairo_status_t status; + const char *p; + int i; + + for (i = 0; i < GLYPH_LUT_SIZE; i++) + glyph_lut_unicode[i] = ~0U; + + p = utf8; + for (i = 0; i < num_chars; i++) { + int idx, num_bytes; + uint32_t unicode; + cairo_scaled_glyph_t *scaled_glyph; + struct glyph_lut_elt *glyph_slot; + + num_bytes = _cairo_utf8_get_char_validated (p, &unicode); + p += num_bytes; + + glyphs[i].x = x; + glyphs[i].y = y; + + idx = unicode % ARRAY_LENGTH (glyph_lut); + glyph_slot = &glyph_lut[idx]; + if (glyph_lut_unicode[idx] == unicode) { + glyphs[i].index = glyph_slot->index; + x += glyph_slot->x_advance; + y += glyph_slot->y_advance; + } else { + unsigned long g; + + g = scaled_font->backend->ucs4_to_index (scaled_font, unicode); + status = _cairo_scaled_glyph_lookup (scaled_font, + g, + CAIRO_SCALED_GLYPH_INFO_METRICS, + NULL, /* foreground color */ + &scaled_glyph); + if (unlikely (status)) + return status; + + x += scaled_glyph->metrics.x_advance; + y += scaled_glyph->metrics.y_advance; + + glyph_lut_unicode[idx] = unicode; + glyph_slot->index = g; + glyph_slot->x_advance = scaled_glyph->metrics.x_advance; + glyph_slot->y_advance = scaled_glyph->metrics.y_advance; + + glyphs[i].index = g; + } + + if (clusters) { + (*clusters)[i].num_bytes = num_bytes; + (*clusters)[i].num_glyphs = 1; + } + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +cairo_scaled_font_text_to_glyphs_internal_uncached (cairo_scaled_font_t *scaled_font, + double x, + double y, + const char *utf8, + cairo_glyph_t *glyphs, + cairo_text_cluster_t **clusters, + int num_chars) +{ + const char *p; + int i; + + p = utf8; + for (i = 0; i < num_chars; i++) { + unsigned long g; + int num_bytes; + uint32_t unicode; + cairo_scaled_glyph_t *scaled_glyph; + cairo_status_t status; + + num_bytes = _cairo_utf8_get_char_validated (p, &unicode); + p += num_bytes; + + glyphs[i].x = x; + glyphs[i].y = y; + + g = scaled_font->backend->ucs4_to_index (scaled_font, unicode); + + /* + * No advance needed for a single character string. So, let's speed up + * one-character strings by skipping glyph lookup. + */ + if (num_chars > 1) { + status = _cairo_scaled_glyph_lookup (scaled_font, + g, + CAIRO_SCALED_GLYPH_INFO_METRICS, + NULL, /* foreground color */ + &scaled_glyph); + if (unlikely (status)) + return status; + + x += scaled_glyph->metrics.x_advance; + y += scaled_glyph->metrics.y_advance; + } + + glyphs[i].index = g; + + if (clusters) { + (*clusters)[i].num_bytes = num_bytes; + (*clusters)[i].num_glyphs = 1; + } + } + + return CAIRO_STATUS_SUCCESS; +} + +/** + * cairo_scaled_font_text_to_glyphs: + * @scaled_font: a #cairo_scaled_font_t + * @x: X position to place first glyph + * @y: Y position to place first glyph + * @utf8: a string of text encoded in UTF-8 + * @utf8_len: length of @utf8 in bytes, or -1 if it is NUL-terminated + * @glyphs: pointer to array of glyphs to fill + * @num_glyphs: pointer to number of glyphs + * @clusters: pointer to array of cluster mapping information to fill, or %NULL + * @num_clusters: pointer to number of clusters, or %NULL + * @cluster_flags: pointer to location to store cluster flags corresponding to the + * output @clusters, or %NULL + * + * Converts UTF-8 text to an array of glyphs, optionally with cluster + * mapping, that can be used to render later using @scaled_font. + * + * If @glyphs initially points to a non-%NULL value, that array is used + * as a glyph buffer, and @num_glyphs should point to the number of glyph + * entries available there. If the provided glyph array is too short for + * the conversion, a new glyph array is allocated using cairo_glyph_allocate() + * and placed in @glyphs. Upon return, @num_glyphs always contains the + * number of generated glyphs. If the value @glyphs points to has changed + * after the call, the user is responsible for freeing the allocated glyph + * array using cairo_glyph_free(). This may happen even if the provided + * array was large enough. + * + * If @clusters is not %NULL, @num_clusters and @cluster_flags should not be %NULL, + * and cluster mapping will be computed. + * The semantics of how cluster array allocation works is similar to the glyph + * array. That is, + * if @clusters initially points to a non-%NULL value, that array is used + * as a cluster buffer, and @num_clusters should point to the number of cluster + * entries available there. If the provided cluster array is too short for + * the conversion, a new cluster array is allocated using cairo_text_cluster_allocate() + * and placed in @clusters. Upon return, @num_clusters always contains the + * number of generated clusters. If the value @clusters points at has changed + * after the call, the user is responsible for freeing the allocated cluster + * array using cairo_text_cluster_free(). This may happen even if the provided + * array was large enough. + * + * In the simplest case, @glyphs and @clusters can point to %NULL initially + * and a suitable array will be allocated. In code: + * + * cairo_status_t status; + * + * cairo_glyph_t *glyphs = NULL; + * int num_glyphs; + * cairo_text_cluster_t *clusters = NULL; + * int num_clusters; + * cairo_text_cluster_flags_t cluster_flags; + * + * status = cairo_scaled_font_text_to_glyphs (scaled_font, + * x, y, + * utf8, utf8_len, + * &glyphs, &num_glyphs, + * &clusters, &num_clusters, &cluster_flags); + * + * if (status == CAIRO_STATUS_SUCCESS) { + * cairo_show_text_glyphs (cr, + * utf8, utf8_len, + * glyphs, num_glyphs, + * clusters, num_clusters, cluster_flags); + * + * cairo_glyph_free (glyphs); + * cairo_text_cluster_free (clusters); + * } + * + * + * If no cluster mapping is needed: + * + * cairo_status_t status; + * + * cairo_glyph_t *glyphs = NULL; + * int num_glyphs; + * + * status = cairo_scaled_font_text_to_glyphs (scaled_font, + * x, y, + * utf8, utf8_len, + * &glyphs, &num_glyphs, + * NULL, NULL, + * NULL); + * + * if (status == CAIRO_STATUS_SUCCESS) { + * cairo_show_glyphs (cr, glyphs, num_glyphs); + * cairo_glyph_free (glyphs); + * } + * + * + * If stack-based glyph and cluster arrays are to be used for small + * arrays: + * + * cairo_status_t status; + * + * cairo_glyph_t stack_glyphs[40]; + * cairo_glyph_t *glyphs = stack_glyphs; + * int num_glyphs = sizeof (stack_glyphs) / sizeof (stack_glyphs[0]); + * cairo_text_cluster_t stack_clusters[40]; + * cairo_text_cluster_t *clusters = stack_clusters; + * int num_clusters = sizeof (stack_clusters) / sizeof (stack_clusters[0]); + * cairo_text_cluster_flags_t cluster_flags; + * + * status = cairo_scaled_font_text_to_glyphs (scaled_font, + * x, y, + * utf8, utf8_len, + * &glyphs, &num_glyphs, + * &clusters, &num_clusters, &cluster_flags); + * + * if (status == CAIRO_STATUS_SUCCESS) { + * cairo_show_text_glyphs (cr, + * utf8, utf8_len, + * glyphs, num_glyphs, + * clusters, num_clusters, cluster_flags); + * + * if (glyphs != stack_glyphs) + * cairo_glyph_free (glyphs); + * if (clusters != stack_clusters) + * cairo_text_cluster_free (clusters); + * } + * + * + * For details of how @clusters, @num_clusters, and @cluster_flags map input + * UTF-8 text to the output glyphs see cairo_show_text_glyphs(). + * + * The output values can be readily passed to cairo_show_text_glyphs() + * cairo_show_glyphs(), or related functions, assuming that the exact + * same @scaled_font is used for the operation. + * + * Return value: %CAIRO_STATUS_SUCCESS upon success, or an error status + * if the input values are wrong or if conversion failed. If the input + * values are correct but the conversion failed, the error status is also + * set on @scaled_font. + * + * Since: 1.8 + **/ +#define CACHING_THRESHOLD 16 +cairo_status_t +cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font, + double x, + double y, + const char *utf8, + int utf8_len, + cairo_glyph_t **glyphs, + int *num_glyphs, + cairo_text_cluster_t **clusters, + int *num_clusters, + cairo_text_cluster_flags_t *cluster_flags) +{ + int num_chars = 0; + cairo_int_status_t status; + cairo_glyph_t *orig_glyphs; + cairo_text_cluster_t *orig_clusters; + + status = scaled_font->status; + if (unlikely (status)) + return status; + + /* A slew of sanity checks */ + + /* glyphs and num_glyphs can't be NULL */ + if (glyphs == NULL || + num_glyphs == NULL) { + status = _cairo_error (CAIRO_STATUS_NULL_POINTER); + goto BAIL; + } + + /* Special case for NULL and -1 */ + if (utf8 == NULL && utf8_len == -1) + utf8_len = 0; + + /* No NULLs for non-NULLs! */ + if ((utf8_len && utf8 == NULL) || + (clusters && num_clusters == NULL) || + (clusters && cluster_flags == NULL)) { + status = _cairo_error (CAIRO_STATUS_NULL_POINTER); + goto BAIL; + } + + /* A -1 for utf8_len means NUL-terminated */ + if (utf8_len == -1) + utf8_len = strlen (utf8); + + /* A NULL *glyphs means no prealloced glyphs array */ + if (glyphs && *glyphs == NULL) + *num_glyphs = 0; + + /* A NULL *clusters means no prealloced clusters array */ + if (clusters && *clusters == NULL) + *num_clusters = 0; + + if (!clusters && num_clusters) { + num_clusters = NULL; + } + + if (cluster_flags) { + *cluster_flags = FALSE; + } + + if (!clusters && cluster_flags) { + cluster_flags = NULL; + } + + /* Apart from that, no negatives */ + if (utf8_len < 0 || + *num_glyphs < 0 || + (num_clusters && *num_clusters < 0)) { + status = _cairo_error (CAIRO_STATUS_NEGATIVE_COUNT); + goto BAIL; + } + + if (utf8_len == 0) { + status = CAIRO_STATUS_SUCCESS; + goto BAIL; + } + + /* validate input so backend does not have to */ + status = _cairo_utf8_to_ucs4 (utf8, utf8_len, NULL, &num_chars); + if (unlikely (status)) + goto BAIL; + + _cairo_scaled_font_freeze_cache (scaled_font); + + orig_glyphs = *glyphs; + orig_clusters = clusters ? *clusters : NULL; + + if (scaled_font->backend->text_to_glyphs) { + status = scaled_font->backend->text_to_glyphs (scaled_font, x, y, + utf8, utf8_len, + glyphs, num_glyphs, + clusters, num_clusters, + cluster_flags); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) { + if (status == CAIRO_INT_STATUS_SUCCESS) { + /* The checks here are crude; we only should do them in + * user-font backend, but they don't hurt here. This stuff + * can be hard to get right. */ + + if (*num_glyphs < 0) { + status = _cairo_error (CAIRO_STATUS_NEGATIVE_COUNT); + goto DONE; + } + if (*num_glyphs != 0 && *glyphs == NULL) { + status = _cairo_error (CAIRO_STATUS_NULL_POINTER); + goto DONE; + } + + if (clusters) { + if (*num_clusters < 0) { + status = _cairo_error (CAIRO_STATUS_NEGATIVE_COUNT); + goto DONE; + } + if (*num_clusters != 0 && *clusters == NULL) { + status = _cairo_error (CAIRO_STATUS_NULL_POINTER); + goto DONE; + } + + /* Don't trust the backend, validate clusters! */ + status = + _cairo_validate_text_clusters (utf8, utf8_len, + *glyphs, *num_glyphs, + *clusters, *num_clusters, + *cluster_flags); + } + } + + goto DONE; + } + } + + if (*num_glyphs < num_chars) { + *glyphs = cairo_glyph_allocate (num_chars); + if (unlikely (*glyphs == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto DONE; + } + } + *num_glyphs = num_chars; + + if (clusters) { + if (*num_clusters < num_chars) { + *clusters = cairo_text_cluster_allocate (num_chars); + if (unlikely (*clusters == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto DONE; + } + } + *num_clusters = num_chars; + } + + if (num_chars > CACHING_THRESHOLD) + status = cairo_scaled_font_text_to_glyphs_internal_cached (scaled_font, + x, y, + utf8, + *glyphs, + clusters, + num_chars); + else + status = cairo_scaled_font_text_to_glyphs_internal_uncached (scaled_font, + x, y, + utf8, + *glyphs, + clusters, + num_chars); + + DONE: /* error that should be logged on scaled_font happened */ + _cairo_scaled_font_thaw_cache (scaled_font); + + if (unlikely (status)) { + *num_glyphs = 0; + if (*glyphs != orig_glyphs) { + cairo_glyph_free (*glyphs); + *glyphs = orig_glyphs; + } + + if (clusters) { + *num_clusters = 0; + if (*clusters != orig_clusters) { + cairo_text_cluster_free (*clusters); + *clusters = orig_clusters; + } + } + } + + return _cairo_scaled_font_set_error (scaled_font, status); + + BAIL: /* error with input arguments */ + + if (num_glyphs) + *num_glyphs = 0; + + if (num_clusters) + *num_clusters = 0; + + return status; +} + +static inline cairo_bool_t +_range_contains_glyph (const cairo_box_t *extents, + cairo_fixed_t left, + cairo_fixed_t top, + cairo_fixed_t right, + cairo_fixed_t bottom) +{ + if (left == right || top == bottom) + return FALSE; + + return right > extents->p1.x && + left < extents->p2.x && + bottom > extents->p1.y && + top < extents->p2.y; +} + +static cairo_status_t +_cairo_scaled_font_single_glyph_device_extents (cairo_scaled_font_t *scaled_font, + const cairo_glyph_t *glyph, + cairo_rectangle_int_t *extents) +{ + cairo_scaled_glyph_t *scaled_glyph; + cairo_status_t status; + + _cairo_scaled_font_freeze_cache (scaled_font); + status = _cairo_scaled_glyph_lookup (scaled_font, + glyph->index, + CAIRO_SCALED_GLYPH_INFO_METRICS, + NULL, /* foreground color */ + &scaled_glyph); + if (likely (status == CAIRO_STATUS_SUCCESS)) { + cairo_bool_t round_xy = _cairo_font_options_get_round_glyph_positions (&scaled_font->options) == CAIRO_ROUND_GLYPH_POS_ON; + cairo_box_t box; + cairo_fixed_t v; + + if (round_xy) + v = _cairo_fixed_from_int (_cairo_lround (glyph->x)); + else + v = _cairo_fixed_from_double (glyph->x); + box.p1.x = v + scaled_glyph->bbox.p1.x; + box.p2.x = v + scaled_glyph->bbox.p2.x; + + if (round_xy) + v = _cairo_fixed_from_int (_cairo_lround (glyph->y)); + else + v = _cairo_fixed_from_double (glyph->y); + box.p1.y = v + scaled_glyph->bbox.p1.y; + box.p2.y = v + scaled_glyph->bbox.p2.y; + + _cairo_box_round_to_rectangle (&box, extents); + } + _cairo_scaled_font_thaw_cache (scaled_font); + return status; +} + +/* + * Compute a device-space bounding box for the glyphs. + */ +cairo_status_t +_cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t *scaled_font, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_rectangle_int_t *extents, + cairo_bool_t *overlap_out) +{ + cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_box_t box = { { INT_MAX, INT_MAX }, { INT_MIN, INT_MIN }}; + cairo_scaled_glyph_t *glyph_cache[64]; + cairo_bool_t overlap = overlap_out ? FALSE : TRUE; + cairo_round_glyph_positions_t round_glyph_positions = _cairo_font_options_get_round_glyph_positions (&scaled_font->options); + int i; + + if (unlikely (scaled_font->status)) + return scaled_font->status; + + if (num_glyphs == 1) { + if (overlap_out) + *overlap_out = FALSE; + return _cairo_scaled_font_single_glyph_device_extents (scaled_font, + glyphs, + extents); + } + + _cairo_scaled_font_freeze_cache (scaled_font); + + memset (glyph_cache, 0, sizeof (glyph_cache)); + + for (i = 0; i < num_glyphs; i++) { + cairo_scaled_glyph_t *scaled_glyph; + cairo_fixed_t x, y, x1, y1, x2, y2; + int cache_index = glyphs[i].index % ARRAY_LENGTH (glyph_cache); + + scaled_glyph = glyph_cache[cache_index]; + if (scaled_glyph == NULL || + _cairo_scaled_glyph_index (scaled_glyph) != glyphs[i].index) + { + status = _cairo_scaled_glyph_lookup (scaled_font, + glyphs[i].index, + CAIRO_SCALED_GLYPH_INFO_METRICS, + NULL, /* foreground color */ + &scaled_glyph); + if (unlikely (status)) + break; + + glyph_cache[cache_index] = scaled_glyph; + } + + if (round_glyph_positions == CAIRO_ROUND_GLYPH_POS_ON) + x = _cairo_fixed_from_int (_cairo_lround (glyphs[i].x)); + else + x = _cairo_fixed_from_double (glyphs[i].x); + x1 = x + scaled_glyph->bbox.p1.x; + x2 = x + scaled_glyph->bbox.p2.x; + + if (round_glyph_positions == CAIRO_ROUND_GLYPH_POS_ON) + y = _cairo_fixed_from_int (_cairo_lround (glyphs[i].y)); + else + y = _cairo_fixed_from_double (glyphs[i].y); + y1 = y + scaled_glyph->bbox.p1.y; + y2 = y + scaled_glyph->bbox.p2.y; + + if (overlap == FALSE) + overlap = _range_contains_glyph (&box, x1, y1, x2, y2); + + if (x1 < box.p1.x) box.p1.x = x1; + if (x2 > box.p2.x) box.p2.x = x2; + if (y1 < box.p1.y) box.p1.y = y1; + if (y2 > box.p2.y) box.p2.y = y2; + } + + _cairo_scaled_font_thaw_cache (scaled_font); + if (unlikely (status)) + return _cairo_scaled_font_set_error (scaled_font, status); + + if (box.p1.x < box.p2.x) { + _cairo_box_round_to_rectangle (&box, extents); + } else { + extents->x = extents->y = 0; + extents->width = extents->height = 0; + } + + if (overlap_out != NULL) + *overlap_out = overlap; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_bool_t +_cairo_scaled_font_glyph_approximate_extents (cairo_scaled_font_t *scaled_font, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_rectangle_int_t *extents) +{ + double x0, x1, y0, y1, pad; + int i; + + /* If any of the factors are suspect (i.e. the font is broken), bail */ + if (scaled_font->fs_extents.max_x_advance == 0 || + scaled_font->fs_extents.height == 0 || + scaled_font->max_scale == 0) + { + return FALSE; + } + + assert (num_glyphs); + + x0 = x1 = glyphs[0].x; + y0 = y1 = glyphs[0].y; + for (i = 1; i < num_glyphs; i++) { + double g; + + g = glyphs[i].x; + if (g < x0) x0 = g; + if (g > x1) x1 = g; + + g = glyphs[i].y; + if (g < y0) y0 = g; + if (g > y1) y1 = g; + } + + pad = MAX(scaled_font->fs_extents.max_x_advance, + scaled_font->fs_extents.height); + pad *= scaled_font->max_scale; + + extents->x = floor (x0 - pad); + extents->width = ceil (x1 + pad) - extents->x; + extents->y = floor (y0 - pad); + extents->height = ceil (y1 + pad) - extents->y; + return TRUE; +} + +/* Add a single-device-unit rectangle to a path. */ +static cairo_status_t +_add_unit_rectangle_to_path (cairo_path_fixed_t *path, + cairo_fixed_t x, + cairo_fixed_t y) +{ + cairo_status_t status; + + status = _cairo_path_fixed_move_to (path, x, y); + if (unlikely (status)) + return status; + + status = _cairo_path_fixed_rel_line_to (path, + _cairo_fixed_from_int (1), + _cairo_fixed_from_int (0)); + if (unlikely (status)) + return status; + + status = _cairo_path_fixed_rel_line_to (path, + _cairo_fixed_from_int (0), + _cairo_fixed_from_int (1)); + if (unlikely (status)) + return status; + + status = _cairo_path_fixed_rel_line_to (path, + _cairo_fixed_from_int (-1), + _cairo_fixed_from_int (0)); + if (unlikely (status)) + return status; + + return _cairo_path_fixed_close_path (path); +} + +/** + * _trace_mask_to_path: + * @bitmap: An alpha mask (either %CAIRO_FORMAT_A1 or %CAIRO_FORMAT_A8) + * @path: An initialized path to hold the result + * + * Given a mask surface, (an alpha image), fill out the provided path + * so that when filled it would result in something that approximates + * the mask. + * + * Note: The current tracing code here is extremely primitive. It + * operates only on an A1 surface, (converting an A8 surface to A1 if + * necessary), and performs the tracing by drawing a little square + * around each pixel that is on in the mask. We do not pretend that + * this is a high-quality result. But we are leaving it up to someone + * who cares enough about getting a better result to implement + * something more sophisticated. + **/ +static cairo_status_t +_trace_mask_to_path (cairo_image_surface_t *mask, + cairo_path_fixed_t *path, + double tx, double ty) +{ + const uint8_t *row; + int rows, cols, bytes_per_row; + int x, y, bit; + double xoff, yoff; + cairo_fixed_t x0, y0; + cairo_fixed_t px, py; + cairo_status_t status; + + mask = _cairo_image_surface_coerce_to_format (mask, CAIRO_FORMAT_A1); + status = mask->base.status; + if (unlikely (status)) + return status; + + cairo_surface_get_device_offset (&mask->base, &xoff, &yoff); + x0 = _cairo_fixed_from_double (tx - xoff); + y0 = _cairo_fixed_from_double (ty - yoff); + + bytes_per_row = (mask->width + 7) / 8; + row = mask->data; + for (y = 0, rows = mask->height; rows--; row += mask->stride, y++) { + const uint8_t *byte_ptr = row; + x = 0; + py = _cairo_fixed_from_int (y); + for (cols = bytes_per_row; cols--; ) { + uint8_t byte = *byte_ptr++; + if (byte == 0) { + x += 8; + continue; + } + + byte = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (byte); + for (bit = 1 << 7; bit && x < mask->width; bit >>= 1, x++) { + if (byte & bit) { + px = _cairo_fixed_from_int (x); + status = _add_unit_rectangle_to_path (path, + px + x0, + py + y0); + if (unlikely (status)) + goto BAIL; + } + } + } + } + +BAIL: + cairo_surface_destroy (&mask->base); + + return status; +} + +cairo_status_t +_cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_path_fixed_t *path) +{ + cairo_int_status_t status; + int i; + + status = scaled_font->status; + if (unlikely (status)) + return status; + + _cairo_scaled_font_freeze_cache (scaled_font); + for (i = 0; i < num_glyphs; i++) { + cairo_scaled_glyph_t *scaled_glyph; + + status = _cairo_scaled_glyph_lookup (scaled_font, + glyphs[i].index, + CAIRO_SCALED_GLYPH_INFO_PATH, + NULL, /* foreground color */ + &scaled_glyph); + if (status == CAIRO_INT_STATUS_SUCCESS) { + status = _cairo_path_fixed_append (path, + scaled_glyph->path, + _cairo_fixed_from_double (glyphs[i].x), + _cairo_fixed_from_double (glyphs[i].y)); + + } else if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + /* If the font is incapable of providing a path, then we'll + * have to trace our own from a surface. + */ + status = _cairo_scaled_glyph_lookup (scaled_font, + glyphs[i].index, + CAIRO_SCALED_GLYPH_INFO_SURFACE, + NULL, /* foreground color */ + &scaled_glyph); + if (unlikely (status)) + goto BAIL; + + status = _trace_mask_to_path (scaled_glyph->surface, path, + glyphs[i].x, glyphs[i].y); + } + + if (unlikely (status)) + goto BAIL; + } + BAIL: + _cairo_scaled_font_thaw_cache (scaled_font); + + return _cairo_scaled_font_set_error (scaled_font, status); +} + +/** + * _cairo_scaled_glyph_set_metrics: + * @scaled_glyph: a #cairo_scaled_glyph_t + * @scaled_font: a #cairo_scaled_font_t + * @fs_metrics: a #cairo_text_extents_t in font space + * + * _cairo_scaled_glyph_set_metrics() stores user space metrics + * for the specified glyph given font space metrics. It is + * called by the font backend when initializing a glyph with + * %CAIRO_SCALED_GLYPH_INFO_METRICS. + **/ +void +_cairo_scaled_glyph_set_metrics (cairo_scaled_glyph_t *scaled_glyph, + cairo_scaled_font_t *scaled_font, + cairo_text_extents_t *fs_metrics) +{ + cairo_bool_t first = TRUE; + double hm, wm; + double min_user_x = 0.0, max_user_x = 0.0, min_user_y = 0.0, max_user_y = 0.0; + double min_device_x = 0.0, max_device_x = 0.0, min_device_y = 0.0, max_device_y = 0.0; + double device_x_advance, device_y_advance; + + scaled_glyph->fs_metrics = *fs_metrics; + + for (hm = 0.0; hm <= 1.0; hm += 1.0) + for (wm = 0.0; wm <= 1.0; wm += 1.0) { + double x, y; + + /* Transform this corner to user space */ + x = fs_metrics->x_bearing + fs_metrics->width * wm; + y = fs_metrics->y_bearing + fs_metrics->height * hm; + cairo_matrix_transform_point (&scaled_font->font_matrix, + &x, &y); + if (first) { + min_user_x = max_user_x = x; + min_user_y = max_user_y = y; + } else { + if (x < min_user_x) min_user_x = x; + if (x > max_user_x) max_user_x = x; + if (y < min_user_y) min_user_y = y; + if (y > max_user_y) max_user_y = y; + } + + /* Transform this corner to device space from glyph origin */ + x = fs_metrics->x_bearing + fs_metrics->width * wm; + y = fs_metrics->y_bearing + fs_metrics->height * hm; + cairo_matrix_transform_distance (&scaled_font->scale, + &x, &y); + + if (first) { + min_device_x = max_device_x = x; + min_device_y = max_device_y = y; + } else { + if (x < min_device_x) min_device_x = x; + if (x > max_device_x) max_device_x = x; + if (y < min_device_y) min_device_y = y; + if (y > max_device_y) max_device_y = y; + } + first = FALSE; + } + scaled_glyph->metrics.x_bearing = min_user_x; + scaled_glyph->metrics.y_bearing = min_user_y; + scaled_glyph->metrics.width = max_user_x - min_user_x; + scaled_glyph->metrics.height = max_user_y - min_user_y; + + scaled_glyph->metrics.x_advance = fs_metrics->x_advance; + scaled_glyph->metrics.y_advance = fs_metrics->y_advance; + cairo_matrix_transform_distance (&scaled_font->font_matrix, + &scaled_glyph->metrics.x_advance, + &scaled_glyph->metrics.y_advance); + + device_x_advance = fs_metrics->x_advance; + device_y_advance = fs_metrics->y_advance; + cairo_matrix_transform_distance (&scaled_font->scale, + &device_x_advance, + &device_y_advance); + + scaled_glyph->bbox.p1.x = _cairo_fixed_from_double (min_device_x); + scaled_glyph->bbox.p1.y = _cairo_fixed_from_double (min_device_y); + scaled_glyph->bbox.p2.x = _cairo_fixed_from_double (max_device_x); + scaled_glyph->bbox.p2.y = _cairo_fixed_from_double (max_device_y); + + scaled_glyph->x_advance = _cairo_lround (device_x_advance); + scaled_glyph->y_advance = _cairo_lround (device_y_advance); + + scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_METRICS; +} + +void +_cairo_scaled_glyph_set_surface (cairo_scaled_glyph_t *scaled_glyph, + cairo_scaled_font_t *scaled_font, + cairo_image_surface_t *surface) +{ + if (scaled_glyph->surface != NULL) + cairo_surface_destroy (&scaled_glyph->surface->base); + + /* sanity check the backend glyph contents */ + _cairo_debug_check_image_surface_is_defined (&surface->base); + scaled_glyph->surface = surface; + + if (surface != NULL) + scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_SURFACE; + else + scaled_glyph->has_info &= ~CAIRO_SCALED_GLYPH_INFO_SURFACE; +} + +void +_cairo_scaled_glyph_set_path (cairo_scaled_glyph_t *scaled_glyph, + cairo_scaled_font_t *scaled_font, + cairo_path_fixed_t *path) +{ + if (scaled_glyph->path != NULL) + _cairo_path_fixed_destroy (scaled_glyph->path); + + scaled_glyph->path = path; + + if (path != NULL) + scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_PATH; + else + scaled_glyph->has_info &= ~CAIRO_SCALED_GLYPH_INFO_PATH; +} + +/** + * _cairo_scaled_glyph_set_recording_surface: + * @scaled_glyph: a #cairo_scaled_glyph_t + * @scaled_font: a #cairo_scaled_font_t + * @recording_surface: The recording surface + * @foreground_color: The foreground color that was used to record the + * glyph, or NULL if foreground color not required. + * + * Sets the surface that was used to record the glyph. + **/ +void +_cairo_scaled_glyph_set_recording_surface (cairo_scaled_glyph_t *scaled_glyph, + cairo_scaled_font_t *scaled_font, + cairo_surface_t *recording_surface, + const cairo_color_t * foreground_color) +{ + if (scaled_glyph->recording_surface != NULL) { + cairo_surface_finish (scaled_glyph->recording_surface); + cairo_surface_destroy (scaled_glyph->recording_surface); + } + + scaled_glyph->recording_surface = recording_surface; + scaled_glyph->recording_uses_foreground_color = foreground_color != NULL; + if (foreground_color) + scaled_glyph->foreground_color = *foreground_color; + + if (recording_surface != NULL) + scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE; + else + scaled_glyph->has_info &= ~CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE; +} + +/** + * _cairo_scaled_glyph_set_color_surface: + * @scaled_glyph: a #cairo_scaled_glyph_t + * @scaled_font: a #cairo_scaled_font_t + * @surface: The image surface + * @foreground_marker_color: The foreground color that was used to + * substitute the foreground_marker, or NULL if foreground_marker not + * used when rendering the surface color. + * + * Sets the color surface of the glyph. + **/ +void +_cairo_scaled_glyph_set_color_surface (cairo_scaled_glyph_t *scaled_glyph, + cairo_scaled_font_t *scaled_font, + cairo_image_surface_t *surface, + const cairo_color_t *foreground_marker_color) +{ + if (scaled_glyph->color_surface != NULL) + cairo_surface_destroy (&scaled_glyph->color_surface->base); + + /* sanity check the backend glyph contents */ + _cairo_debug_check_image_surface_is_defined (&surface->base); + scaled_glyph->color_surface = surface; + scaled_glyph->recording_uses_foreground_marker = foreground_marker_color != NULL; + if (foreground_marker_color) + scaled_glyph->foreground_color = *foreground_marker_color; + + if (surface != NULL) + scaled_glyph->has_info |= CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE; + else + scaled_glyph->has_info &= ~CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE; +} + +/* _cairo_hash_table_random_entry () predicate. To avoid race conditions, + * the font is locked when tested. The font is unlocked in + * _cairo_scaled_glyph_page_pluck. */ +static cairo_bool_t +_cairo_scaled_glyph_page_can_remove (const void *closure) +{ + const cairo_scaled_glyph_page_t *page = closure; + cairo_scaled_font_t *scaled_font; + + scaled_font = page->scaled_font; + + if (!CAIRO_MUTEX_TRY_LOCK (scaled_font->mutex)) + return FALSE; + + if (scaled_font->cache_frozen != 0) { + CAIRO_MUTEX_UNLOCK (scaled_font->mutex); + return FALSE; + } + + return TRUE; +} + +static cairo_status_t +_cairo_scaled_font_allocate_glyph (cairo_scaled_font_t *scaled_font, + cairo_scaled_glyph_t **scaled_glyph) +{ + cairo_scaled_glyph_page_t *page; + cairo_status_t status; + + assert (scaled_font->cache_frozen); + + /* only the first page in the list may contain available slots */ + if (! cairo_list_is_empty (&scaled_font->glyph_pages)) { + page = cairo_list_last_entry (&scaled_font->glyph_pages, + cairo_scaled_glyph_page_t, + link); + if (page->num_glyphs < CAIRO_SCALED_GLYPH_PAGE_SIZE) { + *scaled_glyph = &page->glyphs[page->num_glyphs++]; + return CAIRO_STATUS_SUCCESS; + } + } + + page = _cairo_calloc (sizeof (cairo_scaled_glyph_page_t)); + if (unlikely (page == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + page->cache_entry.hash = (uintptr_t) scaled_font; + page->scaled_font = scaled_font; + page->cache_entry.size = 1; /* XXX occupancy weighting? */ + page->num_glyphs = 0; + + CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex); + if (scaled_font->global_cache_frozen == FALSE) { + if (unlikely (cairo_scaled_glyph_page_cache.hash_table == NULL)) { + status = _cairo_cache_init (&cairo_scaled_glyph_page_cache, + NULL, + _cairo_scaled_glyph_page_can_remove, + _cairo_scaled_glyph_page_pluck, + MAX_GLYPH_PAGES_CACHED); + if (unlikely (status)) { + CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex); + free (page); + return status; + } + } + + _cairo_cache_freeze (&cairo_scaled_glyph_page_cache); + scaled_font->global_cache_frozen = TRUE; + } + + status = _cairo_cache_insert (&cairo_scaled_glyph_page_cache, + &page->cache_entry); + CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex); + if (unlikely (status)) { + free (page); + return status; + } + + cairo_list_add_tail (&page->link, &scaled_font->glyph_pages); + + *scaled_glyph = &page->glyphs[page->num_glyphs++]; + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_scaled_font_free_last_glyph (cairo_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph) +{ + cairo_scaled_glyph_page_t *page; + + assert (scaled_font->cache_frozen); + assert (! cairo_list_is_empty (&scaled_font->glyph_pages)); + page = cairo_list_last_entry (&scaled_font->glyph_pages, + cairo_scaled_glyph_page_t, + link); + assert (scaled_glyph == &page->glyphs[page->num_glyphs-1]); + + _cairo_scaled_glyph_fini (scaled_font, scaled_glyph); + + if (--page->num_glyphs == 0) { + _cairo_scaled_font_thaw_cache (scaled_font); + CAIRO_MUTEX_LOCK (scaled_font->mutex); + + CAIRO_MUTEX_LOCK (_cairo_scaled_glyph_page_cache_mutex); + /* Temporarily disconnect callback to avoid recursive locking */ + cairo_scaled_glyph_page_cache.entry_destroy = NULL; + _cairo_cache_remove (&cairo_scaled_glyph_page_cache, + &page->cache_entry); + _cairo_scaled_glyph_page_destroy (scaled_font, page); + cairo_scaled_glyph_page_cache.entry_destroy = _cairo_scaled_glyph_page_pluck; + CAIRO_MUTEX_UNLOCK (_cairo_scaled_glyph_page_cache_mutex); + + CAIRO_MUTEX_UNLOCK (scaled_font->mutex); + _cairo_scaled_font_freeze_cache (scaled_font); + } +} + +/** + * _cairo_scaled_glyph_lookup: + * @scaled_font: a #cairo_scaled_font_t + * @index: the glyph to create + * @info: a #cairo_scaled_glyph_info_t marking which portions of + * the glyph should be filled in. + * @foreground_color - foreground color to use when rendering color + * fonts. Use NULL if not requesting + * CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE or + * CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE, or foreground color is + * unknown. + * @scaled_glyph_ret: a #cairo_scaled_glyph_t where the glyph + * is returned. + * + * If the desired info is not available, (for example, when trying to + * get INFO_PATH with a bitmapped font), this function will return + * %CAIRO_INT_STATUS_UNSUPPORTED. + * + * Note: This function must be called with the scaled font frozen, and it must + * remain frozen for as long as the @scaled_glyph_ret is alive. (If the scaled + * font was not frozen, then there is no guarantee that the glyph would not be + * evicted before you tried to access it.) See + * _cairo_scaled_font_freeze_cache() and _cairo_scaled_font_thaw_cache(). + * + * Returns: a glyph with the requested portions filled in. Glyph + * lookup is cached and glyph will be automatically freed along + * with the scaled_font so no explicit free is required. + * @info can be one or more of: + * %CAIRO_SCALED_GLYPH_INFO_METRICS - glyph metrics and bounding box + * %CAIRO_SCALED_GLYPH_INFO_SURFACE - surface holding glyph image + * %CAIRO_SCALED_GLYPH_INFO_PATH - path holding glyph outline in device space + * %CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE - surface holding recording of glyph + * %CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE - surface holding color glyph image + **/ +cairo_int_status_t +_cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font, + unsigned long index, + cairo_scaled_glyph_info_t info, + const cairo_color_t *foreground_color, + cairo_scaled_glyph_t **scaled_glyph_ret) +{ + cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; + cairo_scaled_glyph_t *scaled_glyph; + cairo_scaled_glyph_info_t need_info; + cairo_hash_entry_t key; + + *scaled_glyph_ret = NULL; + + if (unlikely (scaled_font->status)) + return scaled_font->status; + + assert (CAIRO_MUTEX_IS_LOCKED(scaled_font->mutex)); + assert (scaled_font->cache_frozen); + + if (CAIRO_INJECT_FAULT ()) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + if (foreground_color == NULL) + foreground_color = CAIRO_COLOR_BLACK; + + /* + * Check cache for glyph + */ + key.hash = index; + scaled_glyph = _cairo_hash_table_lookup (scaled_font->glyphs, &key); + if (scaled_glyph == NULL) { + status = _cairo_scaled_font_allocate_glyph (scaled_font, &scaled_glyph); + if (unlikely (status)) + goto err; + + memset (scaled_glyph, 0, sizeof (cairo_scaled_glyph_t)); + _cairo_scaled_glyph_set_index (scaled_glyph, index); + cairo_list_init (&scaled_glyph->dev_privates); + + /* ask backend to initialize metrics and shape fields */ + status = + scaled_font->backend->scaled_glyph_init (scaled_font, + scaled_glyph, + info | CAIRO_SCALED_GLYPH_INFO_METRICS, + foreground_color); + if (unlikely (status)) { + _cairo_scaled_font_free_last_glyph (scaled_font, scaled_glyph); + goto err; + } + + status = _cairo_hash_table_insert (scaled_font->glyphs, + &scaled_glyph->hash_entry); + if (unlikely (status)) { + _cairo_scaled_font_free_last_glyph (scaled_font, scaled_glyph); + goto err; + } + } + + /* + * Check and see if the glyph, as provided, + * already has the requested data and amend it if not + */ + need_info = info & ~scaled_glyph->has_info; + + /* If this is not a color glyph, don't try loading the color surface again. */ + if ((need_info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) && + scaled_glyph->color_glyph_set && !scaled_glyph->color_glyph) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* If requesting a color surface or recording for a glyph that has + * used the foreground color to render the recording, and the + * foreground color has changed, request a new recording. */ + if ((info & (CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE | CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE)) && + scaled_glyph->recording_uses_foreground_color && + !_cairo_color_equal (foreground_color, &scaled_glyph->foreground_color)) + { + need_info |= CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE; + } + + /* If requesting a color surface for a glyph that has + * used the foreground color to render the color_surface, and the + * foreground color has changed, request a new image. */ + if (info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE && + (scaled_glyph->recording_uses_foreground_marker || scaled_glyph->recording_uses_foreground_color) && + !_cairo_color_equal (foreground_color, &scaled_glyph->foreground_color)) + { + need_info |= CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE; + } + + if (need_info) { + status = scaled_font->backend->scaled_glyph_init (scaled_font, + scaled_glyph, + need_info, + foreground_color); + if (unlikely (status)) + goto err; + + /* Don't trust the scaled_glyph_init() return value, the font + * backend may not even know about some of the info. For example, + * no backend other than the user-fonts knows about recording-surface + * glyph info. */ + if (info & ~scaled_glyph->has_info) + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + *scaled_glyph_ret = scaled_glyph; + return CAIRO_STATUS_SUCCESS; + +err: + /* It's not an error for the backend to not support the info we want. */ + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + status = _cairo_scaled_font_set_error (scaled_font, status); + return status; +} + +double +_cairo_scaled_font_get_max_scale (cairo_scaled_font_t *scaled_font) +{ + return scaled_font->max_scale; +} + +/** + * cairo_scaled_font_get_font_face: + * @scaled_font: a #cairo_scaled_font_t + * + * Gets the font face that this scaled font uses. This might be the + * font face passed to cairo_scaled_font_create(), but this does not + * hold true for all possible cases. + * + * Return value: The #cairo_font_face_t with which @scaled_font was + * created. This object is owned by cairo. To keep a reference to it, + * you must call cairo_scaled_font_reference(). + * + * Since: 1.2 + **/ +cairo_font_face_t * +cairo_scaled_font_get_font_face (cairo_scaled_font_t *scaled_font) +{ + if (scaled_font->status) + return (cairo_font_face_t*) &_cairo_font_face_nil; + + if (scaled_font->original_font_face != NULL) + return scaled_font->original_font_face; + + return scaled_font->font_face; +} + +/** + * cairo_scaled_font_get_font_matrix: + * @scaled_font: a #cairo_scaled_font_t + * @font_matrix: return value for the matrix + * + * Stores the font matrix with which @scaled_font was created into + * @matrix. + * + * Since: 1.2 + **/ +void +cairo_scaled_font_get_font_matrix (cairo_scaled_font_t *scaled_font, + cairo_matrix_t *font_matrix) +{ + if (scaled_font->status) { + cairo_matrix_init_identity (font_matrix); + return; + } + + *font_matrix = scaled_font->font_matrix; +} + +/** + * cairo_scaled_font_get_ctm: + * @scaled_font: a #cairo_scaled_font_t + * @ctm: return value for the CTM + * + * Stores the CTM with which @scaled_font was created into @ctm. + * Note that the translation offsets (x0, y0) of the CTM are ignored + * by cairo_scaled_font_create(). So, the matrix this + * function returns always has 0,0 as x0,y0. + * + * Since: 1.2 + **/ +void +cairo_scaled_font_get_ctm (cairo_scaled_font_t *scaled_font, + cairo_matrix_t *ctm) +{ + if (scaled_font->status) { + cairo_matrix_init_identity (ctm); + return; + } + + *ctm = scaled_font->ctm; +} + +/** + * cairo_scaled_font_get_scale_matrix: + * @scaled_font: a #cairo_scaled_font_t + * @scale_matrix: return value for the matrix + * + * Stores the scale matrix of @scaled_font into @matrix. + * The scale matrix is product of the font matrix and the ctm + * associated with the scaled font, and hence is the matrix mapping from + * font space to device space. + * + * Since: 1.8 + **/ +void +cairo_scaled_font_get_scale_matrix (cairo_scaled_font_t *scaled_font, + cairo_matrix_t *scale_matrix) +{ + if (scaled_font->status) { + cairo_matrix_init_identity (scale_matrix); + return; + } + + *scale_matrix = scaled_font->scale; +} + +/** + * cairo_scaled_font_get_font_options: + * @scaled_font: a #cairo_scaled_font_t + * @options: return value for the font options + * + * Stores the font options with which @scaled_font was created into + * @options. + * + * Since: 1.2 + **/ +void +cairo_scaled_font_get_font_options (cairo_scaled_font_t *scaled_font, + cairo_font_options_t *options) +{ + if (cairo_font_options_status (options)) + return; + + if (scaled_font->status) { + _cairo_font_options_init_default (options); + return; + } + + _cairo_font_options_fini (options); + _cairo_font_options_init_copy (options, &scaled_font->options); +} + +cairo_bool_t +_cairo_scaled_font_has_color_glyphs (cairo_scaled_font_t *scaled_font) +{ + if (scaled_font->backend != NULL && scaled_font->backend->has_color_glyphs != NULL) + return scaled_font->backend->has_color_glyphs (scaled_font); + else + return FALSE; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-script-private.h b/local/recipes/libs/cairo/source/src/cairo-script-private.h new file mode 100644 index 0000000000..989401244e --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-script-private.h @@ -0,0 +1,57 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2008 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Chris Wilson + * + * Contributor(s): + * Chris Wilson + */ + +#ifndef CAIRO_SCRIPT_PRIVATE_H +#define CAIRO_SCRIPT_PRIVATE_H + +#include "cairo.h" +#include "cairo-script.h" + +#include "cairo-compiler-private.h" +#include "cairo-output-stream-private.h" +#include "cairo-types-private.h" + +CAIRO_BEGIN_DECLS + +cairo_private cairo_device_t * +_cairo_script_context_create_internal (cairo_output_stream_t *stream); + +cairo_private void +_cairo_script_context_attach_snapshots (cairo_device_t *device, + cairo_bool_t enable); + +CAIRO_END_DECLS + +#endif /* CAIRO_SCRIPT_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-script-surface.c b/local/recipes/libs/cairo/source/src/cairo-script-surface.c new file mode 100644 index 0000000000..6d25acd385 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-script-surface.c @@ -0,0 +1,4086 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2008 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Chris Wilson. + * + * Contributor(s): + * Chris Wilson + */ + +/* The script surface is one that records all operations performed on + * it in the form of a procedural script, similar in fashion to + * PostScript but using Cairo's imaging model. In essence, this is + * equivalent to the recording-surface, but as there is no impedance mismatch + * between Cairo and CairoScript, we can generate output immediately + * without having to copy and hold the data in memory. + */ + +/** + * SECTION:cairo-script + * @Title: Script Surfaces + * @Short_Description: Rendering to replayable scripts + * @See_Also: #cairo_surface_t + * + * The script surface provides the ability to render to a native + * script that matches the cairo drawing model. The scripts can + * be replayed using tools under the util/cairo-script directory, + * or with cairo-perf-trace. + **/ + +/** + * CAIRO_HAS_SCRIPT_SURFACE: + * + * Defined if the script surface backend is available. + * The script surface backend is always built in since 1.12. + * + * Since: 1.12 + **/ + + +#include "cairoint.h" + +#include "cairo-script.h" +#include "cairo-script-private.h" + +#include "cairo-analysis-surface-private.h" +#include "cairo-default-context-private.h" +#include "cairo-device-private.h" +#include "cairo-error-private.h" +#include "cairo-list-inline.h" +#include "cairo-image-surface-private.h" +#include "cairo-output-stream-private.h" +#include "cairo-pattern-private.h" +#include "cairo-recording-surface-inline.h" +#include "cairo-scaled-font-private.h" +#include "cairo-surface-clipper-private.h" +#include "cairo-surface-snapshot-inline.h" +#include "cairo-surface-subsurface-private.h" +#include "cairo-surface-wrapper-private.h" + +#if CAIRO_HAS_FT_FONT +#include "cairo-ft-private.h" +#endif + +#include + +#ifdef WORDS_BIGENDIAN +#define to_be32(x) x +#else +#define to_be32(x) bswap_32(x) +#endif + +#define _cairo_output_stream_puts(S, STR) \ + _cairo_output_stream_write ((S), (STR), strlen (STR)) + +#define static cairo_warn static + +typedef struct _cairo_script_context cairo_script_context_t; +typedef struct _cairo_script_surface cairo_script_surface_t; +typedef struct _cairo_script_implicit_context cairo_script_implicit_context_t; +typedef struct _cairo_script_font cairo_script_font_t; + +typedef struct _operand { + enum { + SURFACE, + DEFERRED, + } type; + cairo_list_t link; +} operand_t; + + +struct deferred_finish { + cairo_list_t link; + operand_t operand; +}; + +struct _cairo_script_context { + cairo_device_t base; + + int active; + int attach_snapshots; + + cairo_bool_t owns_stream; + cairo_output_stream_t *stream; + cairo_script_mode_t mode; + + struct _bitmap { + unsigned long min; + unsigned long count; + unsigned int map[64]; + struct _bitmap *next; + } surface_id, font_id; + + cairo_list_t operands; + cairo_list_t deferred; + + cairo_list_t fonts; + cairo_list_t defines; +}; + +struct _cairo_script_font { + cairo_scaled_font_private_t base; + + cairo_bool_t has_sfnt; + unsigned long id; + unsigned long subset_glyph_index; + cairo_list_t link; + cairo_scaled_font_t *parent; +}; + +struct _cairo_script_implicit_context { + cairo_operator_t current_operator; + cairo_fill_rule_t current_fill_rule; + double current_tolerance; + cairo_antialias_t current_antialias; + cairo_stroke_style_t current_style; + cairo_pattern_union_t current_source; + cairo_matrix_t current_ctm; + cairo_matrix_t current_stroke_matrix; + cairo_matrix_t current_font_matrix; + cairo_font_options_t current_font_options; + cairo_scaled_font_t *current_scaled_font; + cairo_path_fixed_t current_path; + cairo_bool_t has_clip; +}; + +struct _cairo_script_surface { + cairo_surface_t base; + + cairo_surface_wrapper_t wrapper; + + cairo_surface_clipper_t clipper; + + operand_t operand; + cairo_bool_t emitted; + cairo_bool_t defined; + cairo_bool_t active; + + double width, height; + + /* implicit flattened context */ + cairo_script_implicit_context_t cr; +}; + +static const cairo_surface_backend_t _cairo_script_surface_backend; + +static cairo_script_surface_t * +_cairo_script_surface_create_internal (cairo_script_context_t *ctx, + cairo_content_t content, + cairo_rectangle_t *extents, + cairo_surface_t *passthrough); + +static void +_cairo_script_scaled_font_fini (cairo_scaled_font_private_t *abstract_private, + cairo_scaled_font_t *scaled_font); + +static void +_cairo_script_implicit_context_init (cairo_script_implicit_context_t *cr); + +static void +_cairo_script_implicit_context_reset (cairo_script_implicit_context_t *cr); + +static void +_bitmap_release_id (struct _bitmap *b, unsigned long token) +{ + struct _bitmap **prev = NULL; + + do { + if (token < b->min + sizeof (b->map) * CHAR_BIT) { + unsigned int bit, elem; + + token -= b->min; + elem = token / (sizeof (b->map[0]) * CHAR_BIT); + bit = token % (sizeof (b->map[0]) * CHAR_BIT); + b->map[elem] &= ~(1 << bit); + if (! --b->count && prev) { + *prev = b->next; + free (b); + } + return; + } + prev = &b->next; + b = b->next; + } while (b != NULL); +} + +static cairo_status_t +_bitmap_next_id (struct _bitmap *b, + unsigned long *id) +{ + struct _bitmap *bb, **prev = NULL; + unsigned long min = 0; + + do { + if (b->min != min) + break; + + if (b->count < sizeof (b->map) * CHAR_BIT) { + unsigned int n, m, bit; + for (n = 0; n < ARRAY_LENGTH (b->map); n++) { + if (b->map[n] == (unsigned int) -1) + continue; + + for (m=0, bit=1; mmap[0])*CHAR_BIT; m++, bit<<=1) { + if ((b->map[n] & bit) == 0) { + b->map[n] |= bit; + b->count++; + *id = n * sizeof (b->map[0])*CHAR_BIT + m + b->min; + return CAIRO_STATUS_SUCCESS; + } + } + } + } + min += sizeof (b->map) * CHAR_BIT; + + prev = &b->next; + b = b->next; + } while (b != NULL); + assert (prev != NULL); + + bb = _cairo_calloc (sizeof (struct _bitmap)); + if (unlikely (bb == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + *prev = bb; + bb->next = b; + bb->min = min; + bb->count = 1; + bb->map[0] = 0x1; + memset (bb->map + 1, 0, sizeof (bb->map) - sizeof (bb->map[0])); + *id = min; + + return CAIRO_STATUS_SUCCESS; +} + +static void +_bitmap_fini (struct _bitmap *b) +{ + while (b != NULL) { + struct _bitmap *next = b->next; + free (b); + b = next; + } +} + +static const char * +_direction_to_string (cairo_bool_t backward) +{ + static const char *names[] = { + "FORWARD", + "BACKWARD" + }; + assert (backward < ARRAY_LENGTH (names)); + return names[backward]; +} + +static const char * +_operator_to_string (cairo_operator_t op) +{ + static const char *names[] = { + "CLEAR", /* CAIRO_OPERATOR_CLEAR */ + + "SOURCE", /* CAIRO_OPERATOR_SOURCE */ + "OVER", /* CAIRO_OPERATOR_OVER */ + "IN", /* CAIRO_OPERATOR_IN */ + "OUT", /* CAIRO_OPERATOR_OUT */ + "ATOP", /* CAIRO_OPERATOR_ATOP */ + + "DEST", /* CAIRO_OPERATOR_DEST */ + "DEST_OVER", /* CAIRO_OPERATOR_DEST_OVER */ + "DEST_IN", /* CAIRO_OPERATOR_DEST_IN */ + "DEST_OUT", /* CAIRO_OPERATOR_DEST_OUT */ + "DEST_ATOP", /* CAIRO_OPERATOR_DEST_ATOP */ + + "XOR", /* CAIRO_OPERATOR_XOR */ + "ADD", /* CAIRO_OPERATOR_ADD */ + "SATURATE", /* CAIRO_OPERATOR_SATURATE */ + + "MULTIPLY", /* CAIRO_OPERATOR_MULTIPLY */ + "SCREEN", /* CAIRO_OPERATOR_SCREEN */ + "OVERLAY", /* CAIRO_OPERATOR_OVERLAY */ + "DARKEN", /* CAIRO_OPERATOR_DARKEN */ + "LIGHTEN", /* CAIRO_OPERATOR_LIGHTEN */ + "DODGE", /* CAIRO_OPERATOR_COLOR_DODGE */ + "BURN", /* CAIRO_OPERATOR_COLOR_BURN */ + "HARD_LIGHT", /* CAIRO_OPERATOR_HARD_LIGHT */ + "SOFT_LIGHT", /* CAIRO_OPERATOR_SOFT_LIGHT */ + "DIFFERENCE", /* CAIRO_OPERATOR_DIFFERENCE */ + "EXCLUSION", /* CAIRO_OPERATOR_EXCLUSION */ + "HSL_HUE", /* CAIRO_OPERATOR_HSL_HUE */ + "HSL_SATURATION", /* CAIRO_OPERATOR_HSL_SATURATION */ + "HSL_COLOR", /* CAIRO_OPERATOR_HSL_COLOR */ + "HSL_LUMINOSITY" /* CAIRO_OPERATOR_HSL_LUMINOSITY */ + }; + assert (op < ARRAY_LENGTH (names)); + return names[op]; +} + +static const char * +_extend_to_string (cairo_extend_t extend) +{ + static const char *names[] = { + "EXTEND_NONE", /* CAIRO_EXTEND_NONE */ + "EXTEND_REPEAT", /* CAIRO_EXTEND_REPEAT */ + "EXTEND_REFLECT", /* CAIRO_EXTEND_REFLECT */ + "EXTEND_PAD" /* CAIRO_EXTEND_PAD */ + }; + assert (extend < ARRAY_LENGTH (names)); + return names[extend]; +} + +static const char * +_filter_to_string (cairo_filter_t filter) +{ + static const char *names[] = { + "FILTER_FAST", /* CAIRO_FILTER_FAST */ + "FILTER_GOOD", /* CAIRO_FILTER_GOOD */ + "FILTER_BEST", /* CAIRO_FILTER_BEST */ + "FILTER_NEAREST", /* CAIRO_FILTER_NEAREST */ + "FILTER_BILINEAR", /* CAIRO_FILTER_BILINEAR */ + "FILTER_GAUSSIAN", /* CAIRO_FILTER_GAUSSIAN */ + }; + assert (filter < ARRAY_LENGTH (names)); + return names[filter]; +} + +static const char * +_dither_to_string (cairo_dither_t dither) +{ + static const char *names[] = { + "DITHER_DEFAULT", /* CAIRO_FILTER_FAST */ + "DITHER_NONE", /* CAIRO_FILTER_GOOD */ + "DITHER_FAST", /* CAIRO_FILTER_BEST */ + "DITHER_GOOD", /* CAIRO_FILTER_NEAREST */ + "DITHER_BEST", /* CAIRO_FILTER_BILINEAR */ + }; + assert (dither < ARRAY_LENGTH (names)); + return names[dither]; +} + + +static const char * +_fill_rule_to_string (cairo_fill_rule_t rule) +{ + static const char *names[] = { + "WINDING", /* CAIRO_FILL_RULE_WINDING */ + "EVEN_ODD" /* CAIRO_FILL_RILE_EVEN_ODD */ + }; + assert (rule < ARRAY_LENGTH (names)); + return names[rule]; +} + +static const char * +_antialias_to_string (cairo_antialias_t antialias) +{ + static const char *names[] = { + "ANTIALIAS_DEFAULT", /* CAIRO_ANTIALIAS_DEFAULT */ + "ANTIALIAS_NONE", /* CAIRO_ANTIALIAS_NONE */ + "ANTIALIAS_GRAY", /* CAIRO_ANTIALIAS_GRAY */ + "ANTIALIAS_SUBPIXEL", /* CAIRO_ANTIALIAS_SUBPIXEL */ + "ANTIALIAS_FAST", /* CAIRO_ANTIALIAS_FAST */ + "ANTIALIAS_GOOD", /* CAIRO_ANTIALIAS_GOOD */ + "ANTIALIAS_BEST" /* CAIRO_ANTIALIAS_BEST */ + }; + assert (antialias < ARRAY_LENGTH (names)); + return names[antialias]; +} + +static const char * +_line_cap_to_string (cairo_line_cap_t line_cap) +{ + static const char *names[] = { + "LINE_CAP_BUTT", /* CAIRO_LINE_CAP_BUTT */ + "LINE_CAP_ROUND", /* CAIRO_LINE_CAP_ROUND */ + "LINE_CAP_SQUARE" /* CAIRO_LINE_CAP_SQUARE */ + }; + assert (line_cap < ARRAY_LENGTH (names)); + return names[line_cap]; +} + +static const char * +_line_join_to_string (cairo_line_join_t line_join) +{ + static const char *names[] = { + "LINE_JOIN_MITER", /* CAIRO_LINE_JOIN_MITER */ + "LINE_JOIN_ROUND", /* CAIRO_LINE_JOIN_ROUND */ + "LINE_JOIN_BEVEL", /* CAIRO_LINE_JOIN_BEVEL */ + }; + assert (line_join < ARRAY_LENGTH (names)); + return names[line_join]; +} + +static inline cairo_script_context_t * +to_context (cairo_script_surface_t *surface) +{ + return (cairo_script_context_t *) surface->base.device; +} + +static cairo_bool_t +target_is_active (cairo_script_surface_t *surface) +{ + return cairo_list_is_first (&surface->operand.link, + &to_context (surface)->operands); +} + +static void +target_push (cairo_script_surface_t *surface) +{ + cairo_list_move (&surface->operand.link, &to_context (surface)->operands); +} + +static int +target_depth (cairo_script_surface_t *surface) +{ + cairo_list_t *link; + int depth = 0; + + cairo_list_foreach (link, &to_context (surface)->operands) { + if (link == &surface->operand.link) + break; + depth++; + } + + return depth; +} + +static void +_get_target (cairo_script_surface_t *surface) +{ + cairo_script_context_t *ctx = to_context (surface); + + if (target_is_active (surface)) { + _cairo_output_stream_puts (ctx->stream, "dup "); + return; + } + + if (surface->defined) { + _cairo_output_stream_printf (ctx->stream, "s%u ", + surface->base.unique_id); + } else { + int depth = target_depth (surface); + + assert (! cairo_list_is_empty (&surface->operand.link)); + assert (! target_is_active (surface)); + + if (ctx->active) { + _cairo_output_stream_printf (ctx->stream, "%d index ", depth); + _cairo_output_stream_puts (ctx->stream, "/target get exch pop "); + } else { + if (depth == 1) { + _cairo_output_stream_puts (ctx->stream, "exch "); + } else { + _cairo_output_stream_printf (ctx->stream, + "%d -1 roll ", depth); + } + target_push (surface); + _cairo_output_stream_puts (ctx->stream, "dup "); + } + } +} + +static const char * +_content_to_string (cairo_content_t content) +{ + switch (content) { + case CAIRO_CONTENT_ALPHA: return "ALPHA"; + case CAIRO_CONTENT_COLOR: return "COLOR"; + default: + case CAIRO_CONTENT_COLOR_ALPHA: return "COLOR_ALPHA"; + } +} + +static cairo_status_t +_emit_surface (cairo_script_surface_t *surface) +{ + cairo_script_context_t *ctx = to_context (surface); + + _cairo_output_stream_printf (ctx->stream, + "<< /content //%s", + _content_to_string (surface->base.content)); + if (surface->width != -1 && surface->height != -1) { + _cairo_output_stream_printf (ctx->stream, + " /width %f /height %f", + surface->width, + surface->height); + } + + if (surface->base.x_fallback_resolution != + CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT || + surface->base.y_fallback_resolution != + CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT) + { + _cairo_output_stream_printf (ctx->stream, + " /fallback-resolution [%f %f]", + surface->base.x_fallback_resolution, + surface->base.y_fallback_resolution); + } + + if (surface->base.device_transform.x0 != 0. || + surface->base.device_transform.y0 != 0.) + { + /* XXX device offset is encoded into the pattern matrices etc. */ + if (0) { + _cairo_output_stream_printf (ctx->stream, + " /device-offset [%f %f]", + surface->base.device_transform.x0, + surface->base.device_transform.y0); + } + } + + _cairo_output_stream_puts (ctx->stream, " >> surface context\n"); + surface->emitted = TRUE; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_context (cairo_script_surface_t *surface) +{ + cairo_script_context_t *ctx = to_context (surface); + + if (target_is_active (surface)) + return CAIRO_STATUS_SUCCESS; + + while (! cairo_list_is_empty (&ctx->operands)) { + operand_t *op; + cairo_script_surface_t *old; + + op = cairo_list_first_entry (&ctx->operands, + operand_t, + link); + if (op->type == DEFERRED) + break; + + old = cairo_container_of (op, cairo_script_surface_t, operand); + if (old == surface) + break; + if (old->active) + break; + + if (! old->defined) { + assert (old->emitted); + _cairo_output_stream_printf (ctx->stream, + "/target get /s%u exch def pop\n", + old->base.unique_id); + old->defined = TRUE; + } else { + _cairo_output_stream_puts (ctx->stream, "pop\n"); + } + + cairo_list_del (&old->operand.link); + } + + if (target_is_active (surface)) + return CAIRO_STATUS_SUCCESS; + + if (! surface->emitted) { + cairo_status_t status; + + status = _emit_surface (surface); + if (unlikely (status)) + return status; + } else if (cairo_list_is_empty (&surface->operand.link)) { + assert (surface->defined); + _cairo_output_stream_printf (ctx->stream, + "s%u context\n", + surface->base.unique_id); + _cairo_script_implicit_context_reset (&surface->cr); + _cairo_surface_clipper_reset (&surface->clipper); + } else { + int depth = target_depth (surface); + if (depth == 1) { + _cairo_output_stream_puts (ctx->stream, "exch\n"); + } else { + _cairo_output_stream_printf (ctx->stream, + "%d -1 roll\n", + depth); + } + } + target_push (surface); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_operator (cairo_script_surface_t *surface, + cairo_operator_t op) +{ + assert (target_is_active (surface)); + + if (surface->cr.current_operator == op) + return CAIRO_STATUS_SUCCESS; + + surface->cr.current_operator = op; + + _cairo_output_stream_printf (to_context (surface)->stream, + "//%s set-operator\n", + _operator_to_string (op)); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_fill_rule (cairo_script_surface_t *surface, + cairo_fill_rule_t fill_rule) +{ + assert (target_is_active (surface)); + + if (surface->cr.current_fill_rule == fill_rule) + return CAIRO_STATUS_SUCCESS; + + surface->cr.current_fill_rule = fill_rule; + + _cairo_output_stream_printf (to_context (surface)->stream, + "//%s set-fill-rule\n", + _fill_rule_to_string (fill_rule)); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_tolerance (cairo_script_surface_t *surface, + double tolerance, + cairo_bool_t force) +{ + assert (target_is_active (surface)); + + if ((! force || + fabs (tolerance - CAIRO_GSTATE_TOLERANCE_DEFAULT) < 1e-5) && + surface->cr.current_tolerance == tolerance) + { + return CAIRO_STATUS_SUCCESS; + } + + surface->cr.current_tolerance = tolerance; + + _cairo_output_stream_printf (to_context (surface)->stream, + "%f set-tolerance\n", + tolerance); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_antialias (cairo_script_surface_t *surface, + cairo_antialias_t antialias) +{ + assert (target_is_active (surface)); + + if (surface->cr.current_antialias == antialias) + return CAIRO_STATUS_SUCCESS; + + surface->cr.current_antialias = antialias; + + _cairo_output_stream_printf (to_context (surface)->stream, + "//%s set-antialias\n", + _antialias_to_string (antialias)); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_line_width (cairo_script_surface_t *surface, + double line_width, + cairo_bool_t force) +{ + assert (target_is_active (surface)); + + if ((! force || + fabs (line_width - CAIRO_GSTATE_LINE_WIDTH_DEFAULT) < 1e-5) && + surface->cr.current_style.line_width == line_width) + { + return CAIRO_STATUS_SUCCESS; + } + + surface->cr.current_style.line_width = line_width; + + _cairo_output_stream_printf (to_context (surface)->stream, + "%f set-line-width\n", + line_width); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_hairline (cairo_script_surface_t *surface, cairo_bool_t set_hairline) +{ + assert (target_is_active (surface)); + + if (surface->cr.current_style.is_hairline == set_hairline) + { + return CAIRO_STATUS_SUCCESS; + } + + surface->cr.current_style.is_hairline = set_hairline; + + _cairo_output_stream_printf (to_context (surface)->stream, + "%d set-hairline\n", + set_hairline); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_line_cap (cairo_script_surface_t *surface, + cairo_line_cap_t line_cap) +{ + assert (target_is_active (surface)); + + if (surface->cr.current_style.line_cap == line_cap) + return CAIRO_STATUS_SUCCESS; + + surface->cr.current_style.line_cap = line_cap; + + _cairo_output_stream_printf (to_context (surface)->stream, + "//%s set-line-cap\n", + _line_cap_to_string (line_cap)); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_line_join (cairo_script_surface_t *surface, + cairo_line_join_t line_join) +{ + assert (target_is_active (surface)); + + if (surface->cr.current_style.line_join == line_join) + return CAIRO_STATUS_SUCCESS; + + surface->cr.current_style.line_join = line_join; + + _cairo_output_stream_printf (to_context (surface)->stream, + "//%s set-line-join\n", + _line_join_to_string (line_join)); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_miter_limit (cairo_script_surface_t *surface, + double miter_limit, + cairo_bool_t force) +{ + assert (target_is_active (surface)); + + if ((! force || + fabs (miter_limit - CAIRO_GSTATE_MITER_LIMIT_DEFAULT) < 1e-5) && + surface->cr.current_style.miter_limit == miter_limit) + { + return CAIRO_STATUS_SUCCESS; + } + + surface->cr.current_style.miter_limit = miter_limit; + + _cairo_output_stream_printf (to_context (surface)->stream, + "%f set-miter-limit\n", + miter_limit); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_bool_t +_dashes_equal (const double *a, const double *b, int num_dashes) +{ + while (num_dashes--) { + if (fabs (*a - *b) > 1e-5) + return FALSE; + a++, b++; + } + + return TRUE; +} + +static cairo_status_t +_emit_dash (cairo_script_surface_t *surface, + const double *dash, + unsigned int num_dashes, + double offset, + cairo_bool_t force) +{ + unsigned int n; + + assert (target_is_active (surface)); + + if (force && + num_dashes == 0 && + surface->cr.current_style.num_dashes == 0) + { + return CAIRO_STATUS_SUCCESS; + } + + if (! force && + (surface->cr.current_style.num_dashes == num_dashes && + (num_dashes == 0 || + (fabs (surface->cr.current_style.dash_offset - offset) < 1e-5 && + _dashes_equal (surface->cr.current_style.dash, dash, num_dashes))))) + { + return CAIRO_STATUS_SUCCESS; + } + + + if (num_dashes) { + surface->cr.current_style.dash = _cairo_realloc_ab + (surface->cr.current_style.dash, num_dashes, sizeof (double)); + if (unlikely (surface->cr.current_style.dash == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + memcpy (surface->cr.current_style.dash, dash, + sizeof (double) * num_dashes); + } else { + free (surface->cr.current_style.dash); + surface->cr.current_style.dash = NULL; + } + + surface->cr.current_style.num_dashes = num_dashes; + surface->cr.current_style.dash_offset = offset; + + _cairo_output_stream_puts (to_context (surface)->stream, "["); + for (n = 0; n < num_dashes; n++) { + _cairo_output_stream_printf (to_context (surface)->stream, "%f", dash[n]); + if (n < num_dashes-1) + _cairo_output_stream_puts (to_context (surface)->stream, " "); + } + _cairo_output_stream_printf (to_context (surface)->stream, + "] %f set-dash\n", + offset); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_stroke_style (cairo_script_surface_t *surface, + const cairo_stroke_style_t *style, + cairo_bool_t force) +{ + cairo_status_t status; + + assert (target_is_active (surface)); + + status = _emit_line_width (surface, style->line_width, force); + if (unlikely (status)) + return status; + + status = _emit_line_cap (surface, style->line_cap); + if (unlikely (status)) + return status; + + status = _emit_line_join (surface, style->line_join); + if (unlikely (status)) + return status; + + status = _emit_miter_limit (surface, style->miter_limit, force); + if (unlikely (status)) + return status; + + status = _emit_hairline (surface, style->is_hairline); + if (unlikely (status)) + return status; + + status = _emit_dash (surface, + style->dash, style->num_dashes, style->dash_offset, + force); + if (unlikely (status)) + return status; + + return CAIRO_STATUS_SUCCESS; +} + +static const char * +_format_to_string (cairo_format_t format) +{ + switch (format) { + case CAIRO_FORMAT_RGBA128F: return "RGBA128F"; + case CAIRO_FORMAT_RGB96F: return "RGB96F"; + case CAIRO_FORMAT_ARGB32: return "ARGB32"; + case CAIRO_FORMAT_RGB30: return "RGB30"; + case CAIRO_FORMAT_RGB24: return "RGB24"; + case CAIRO_FORMAT_RGB16_565: return "RGB16_565"; + case CAIRO_FORMAT_A8: return "A8"; + case CAIRO_FORMAT_A1: return "A1"; + case CAIRO_FORMAT_INVALID: return "INVALID"; + } + ASSERT_NOT_REACHED; + return "INVALID"; +} + +static cairo_status_t +_emit_solid_pattern (cairo_script_surface_t *surface, + const cairo_pattern_t *pattern) +{ + cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern; + cairo_script_context_t *ctx = to_context (surface); + + if (! CAIRO_COLOR_IS_OPAQUE (&solid->color)) + { + if (! (surface->base.content & CAIRO_CONTENT_COLOR) || + ((solid->color.red_short == 0 || solid->color.red_short == 0xffff) && + (solid->color.green_short == 0 || solid->color.green_short == 0xffff) && + (solid->color.blue_short == 0 || solid->color.blue_short == 0xffff) )) + { + _cairo_output_stream_printf (ctx->stream, + "%f a", + solid->color.alpha); + } + else + { + _cairo_output_stream_printf (ctx->stream, + "%f %f %f %f rgba", + solid->color.red, + solid->color.green, + solid->color.blue, + solid->color.alpha); + } + } + else + { + if (solid->color.red_short == solid->color.green_short && + solid->color.red_short == solid->color.blue_short) + { + _cairo_output_stream_printf (ctx->stream, + "%f g", + solid->color.red); + } + else + { + _cairo_output_stream_printf (ctx->stream, + "%f %f %f rgb", + solid->color.red, + solid->color.green, + solid->color.blue); + } + } + + return CAIRO_STATUS_SUCCESS; +} + + +static cairo_status_t +_emit_gradient_color_stops (cairo_gradient_pattern_t *gradient, + cairo_output_stream_t *output) +{ + unsigned int n; + + for (n = 0; n < gradient->n_stops; n++) { + _cairo_output_stream_printf (output, + "\n %f %f %f %f %f add-color-stop", + gradient->stops[n].offset, + gradient->stops[n].color.red, + gradient->stops[n].color.green, + gradient->stops[n].color.blue, + gradient->stops[n].color.alpha); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_linear_pattern (cairo_script_surface_t *surface, + const cairo_pattern_t *pattern) +{ + cairo_script_context_t *ctx = to_context (surface); + cairo_linear_pattern_t *linear; + + linear = (cairo_linear_pattern_t *) pattern; + + _cairo_output_stream_printf (ctx->stream, + "%f %f %f %f linear", + linear->pd1.x, linear->pd1.y, + linear->pd2.x, linear->pd2.y); + return _emit_gradient_color_stops (&linear->base, ctx->stream); +} + +static cairo_status_t +_emit_radial_pattern (cairo_script_surface_t *surface, + const cairo_pattern_t *pattern) +{ + cairo_script_context_t *ctx = to_context (surface); + cairo_radial_pattern_t *radial; + + radial = (cairo_radial_pattern_t *) pattern; + + _cairo_output_stream_printf (ctx->stream, + "%f %f %f %f %f %f radial", + radial->cd1.center.x, + radial->cd1.center.y, + radial->cd1.radius, + radial->cd2.center.x, + radial->cd2.center.y, + radial->cd2.radius); + return _emit_gradient_color_stops (&radial->base, ctx->stream); +} + +static cairo_status_t +_emit_mesh_pattern (cairo_script_surface_t *surface, + const cairo_pattern_t *pattern) +{ + cairo_script_context_t *ctx = to_context (surface); + cairo_pattern_t *mesh; + cairo_status_t status; + unsigned int i, n; + + mesh = (cairo_pattern_t *) pattern; + status = cairo_mesh_pattern_get_patch_count (mesh, &n); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (ctx->stream, "mesh"); + for (i = 0; i < n; i++) { + cairo_path_t *path; + cairo_path_data_t *data; + int j; + + _cairo_output_stream_printf (ctx->stream, "\n begin-patch"); + + path = cairo_mesh_pattern_get_path (mesh, i); + if (unlikely (path->status)) + return path->status; + + for (j = 0; j < path->num_data; j+=data[0].header.length) { + data = &path->data[j]; + switch (data->header.type) { + case CAIRO_PATH_MOVE_TO: + _cairo_output_stream_printf (ctx->stream, + "\n %f %f m", + data[1].point.x, data[1].point.y); + break; + case CAIRO_PATH_LINE_TO: + _cairo_output_stream_printf (ctx->stream, + "\n %f %f l", + data[1].point.x, data[1].point.y); + break; + case CAIRO_PATH_CURVE_TO: + _cairo_output_stream_printf (ctx->stream, + "\n %f %f %f %f %f %f c", + data[1].point.x, data[1].point.y, + data[2].point.x, data[2].point.y, + data[3].point.x, data[3].point.y); + break; + case CAIRO_PATH_CLOSE_PATH: + break; + } + } + cairo_path_destroy (path); + + for (j = 0; j < 4; j++) { + double x, y; + + status = cairo_mesh_pattern_get_control_point (mesh, i, j, &x, &y); + if (unlikely (status)) + return status; + _cairo_output_stream_printf (ctx->stream, + "\n %d %f %f set-control-point", + j, x, y); + } + + for (j = 0; j < 4; j++) { + double r, g, b, a; + + status = cairo_mesh_pattern_get_corner_color_rgba (mesh, i, j, &r, &g, &b, &a); + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (ctx->stream, + "\n %d %f %f %f %f set-corner-color", + j, r, g, b, a); + } + + _cairo_output_stream_printf (ctx->stream, "\n end-patch"); + } + + return CAIRO_STATUS_SUCCESS; +} + +struct script_snapshot { + cairo_surface_t base; +}; + +static cairo_status_t +script_snapshot_finish (void *abstract_surface) +{ + return CAIRO_STATUS_SUCCESS; +} + +static const cairo_surface_backend_t script_snapshot_backend = { + CAIRO_SURFACE_TYPE_SCRIPT, + script_snapshot_finish, +}; + +static void +detach_snapshot (cairo_surface_t *abstract_surface) +{ + cairo_script_surface_t *surface = (cairo_script_surface_t *)abstract_surface; + cairo_script_context_t *ctx = to_context (surface); + + _cairo_output_stream_printf (ctx->stream, + "/s%d undef\n", + surface->base.unique_id); +} + +static void +attach_snapshot (cairo_script_context_t *ctx, + cairo_surface_t *source) +{ + struct script_snapshot *surface; + + if (! ctx->attach_snapshots) + return; + + surface = _cairo_calloc (sizeof (*surface)); + if (unlikely (surface == NULL)) + return; + + _cairo_surface_init (&surface->base, + &script_snapshot_backend, + &ctx->base, + source->content, + source->is_vector); + + _cairo_output_stream_printf (ctx->stream, + "dup /s%d exch def ", + surface->base.unique_id); + + _cairo_surface_attach_snapshot (source, &surface->base, detach_snapshot); + cairo_surface_destroy (&surface->base); +} + +static cairo_status_t +_emit_recording_surface_pattern (cairo_script_surface_t *surface, + cairo_recording_surface_t *source) +{ + cairo_script_implicit_context_t old_cr; + cairo_script_context_t *ctx = to_context (surface); + cairo_script_surface_t *similar; + cairo_surface_t *snapshot; + cairo_rectangle_t r, *extents; + cairo_status_t status; + + snapshot = _cairo_surface_has_snapshot (&source->base, &script_snapshot_backend); + if (snapshot) { + _cairo_output_stream_printf (ctx->stream, "s%d", snapshot->unique_id); + return CAIRO_INT_STATUS_SUCCESS; + } + + extents = NULL; + if (_cairo_recording_surface_get_bounds (&source->base, &r)) + extents = &r; + + similar = _cairo_script_surface_create_internal (ctx, + source->base.content, + extents, + NULL); + if (unlikely (similar->base.status)) + return similar->base.status; + + similar->base.is_clear = TRUE; + + _cairo_output_stream_printf (ctx->stream, "//%s ", + _content_to_string (source->base.content)); + if (extents) { + _cairo_output_stream_printf (ctx->stream, "[%f %f %f %f]", + extents->x, extents->y, + extents->width, extents->height); + } else + _cairo_output_stream_puts (ctx->stream, "[]"); + _cairo_output_stream_puts (ctx->stream, " record\n"); + + attach_snapshot (ctx, &source->base); + + _cairo_output_stream_puts (ctx->stream, "dup context\n"); + + target_push (similar); + similar->emitted = TRUE; + + + old_cr = surface->cr; + _cairo_script_implicit_context_init (&surface->cr); + status = _cairo_recording_surface_replay (&source->base, &similar->base); + surface->cr = old_cr; + + if (unlikely (status)) { + cairo_surface_destroy (&similar->base); + return status; + } + + cairo_list_del (&similar->operand.link); + assert (target_is_active (surface)); + + _cairo_output_stream_puts (ctx->stream, "pop "); + cairo_surface_destroy (&similar->base); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_script_surface_pattern (cairo_script_surface_t *surface, + cairo_script_surface_t *source) +{ + _get_target (source); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_write_image_surface (cairo_output_stream_t *output, + const cairo_image_surface_t *image) +{ + int row, width; + ptrdiff_t stride; + uint8_t row_stack[CAIRO_STACK_BUFFER_SIZE]; + uint8_t *rowdata; + uint8_t *data; + + stride = image->stride; + width = image->width; + data = image->data; +#if WORDS_BIGENDIAN + switch (image->format) { + case CAIRO_FORMAT_A1: + for (row = image->height; row--; ) { + _cairo_output_stream_write (output, data, (width+7)/8); + data += stride; + } + break; + case CAIRO_FORMAT_A8: + for (row = image->height; row--; ) { + _cairo_output_stream_write (output, data, width); + data += stride; + } + break; + case CAIRO_FORMAT_RGB16_565: + for (row = image->height; row--; ) { + _cairo_output_stream_write (output, data, 2*width); + data += stride; + } + break; + case CAIRO_FORMAT_RGB24: + for (row = image->height; row--; ) { + int col; + rowdata = data; + for (col = width; col--; ) { + _cairo_output_stream_write (output, rowdata, 3); + rowdata+=4; + } + data += stride; + } + break; + case CAIRO_FORMAT_ARGB32: + for (row = image->height; row--; ) { + _cairo_output_stream_write (output, data, 4*width); + data += stride; + } + break; + case CAIRO_FORMAT_INVALID: + default: + ASSERT_NOT_REACHED; + break; + } +#else + if (stride > ARRAY_LENGTH (row_stack)) { + rowdata = _cairo_malloc (stride); + if (unlikely (rowdata == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } else + rowdata = row_stack; + + switch (image->format) { + case CAIRO_FORMAT_A1: + for (row = image->height; row--; ) { + int col; + for (col = 0; col < (width + 7)/8; col++) + rowdata[col] = CAIRO_BITSWAP8 (data[col]); + _cairo_output_stream_write (output, rowdata, (width+7)/8); + data += stride; + } + break; + case CAIRO_FORMAT_A8: + for (row = image->height; row--; ) { + _cairo_output_stream_write (output, data, width); + data += stride; + } + break; + case CAIRO_FORMAT_RGB16_565: + for (row = image->height; row--; ) { + uint16_t *src = (uint16_t *) data; + uint16_t *dst = (uint16_t *) rowdata; + int col; + for (col = 0; col < width; col++) + dst[col] = bswap_16 (src[col]); + _cairo_output_stream_write (output, rowdata, 2*width); + data += stride; + } + break; + case CAIRO_FORMAT_RGB24: + for (row = image->height; row--; ) { + uint8_t *src = data; + int col; + for (col = 0; col < width; col++) { + rowdata[3*col+2] = *src++; + rowdata[3*col+1] = *src++; + rowdata[3*col+0] = *src++; + src++; + } + _cairo_output_stream_write (output, rowdata, 3*width); + data += stride; + } + break; + case CAIRO_FORMAT_RGB30: + case CAIRO_FORMAT_ARGB32: + for (row = image->height; row--; ) { + uint32_t *src = (uint32_t *) data; + uint32_t *dst = (uint32_t *) rowdata; + int col; + for (col = 0; col < width; col++) + dst[col] = bswap_32 (src[col]); + _cairo_output_stream_write (output, rowdata, 4*width); + data += stride; + } + break; + case CAIRO_FORMAT_RGB96F: + for (row = image->height; row--; ) { + _cairo_output_stream_write (output, data, 12*width); + data += stride; + } + break; + case CAIRO_FORMAT_RGBA128F: + for (row = image->height; row--; ) { + _cairo_output_stream_write (output, data, 16*width); + data += stride; + } + break; + case CAIRO_FORMAT_INVALID: + default: + ASSERT_NOT_REACHED; + break; + } + if (rowdata != row_stack) + free (rowdata); +#endif + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_emit_png_surface (cairo_script_surface_t *surface, + cairo_image_surface_t *image) +{ + cairo_script_context_t *ctx = to_context (surface); + cairo_output_stream_t *base85_stream; + cairo_status_t status; + const uint8_t *mime_data; + unsigned long mime_data_length; + + cairo_surface_get_mime_data (&image->base, CAIRO_MIME_TYPE_PNG, + &mime_data, &mime_data_length); + if (mime_data == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + _cairo_output_stream_printf (ctx->stream, + "<< " + "/width %d " + "/height %d " + "/format //%s " + "/mime-type (image/png) " + "/source <~", + image->width, image->height, + _format_to_string (image->format)); + + base85_stream = _cairo_base85_stream_create (ctx->stream); + _cairo_output_stream_write (base85_stream, mime_data, mime_data_length); + status = _cairo_output_stream_destroy (base85_stream); + if (unlikely (status)) + return status; + + _cairo_output_stream_puts (ctx->stream, "~> >> image "); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_emit_image_surface (cairo_script_surface_t *surface, + cairo_image_surface_t *image) +{ + cairo_script_context_t *ctx = to_context (surface); + cairo_output_stream_t *base85_stream; + cairo_output_stream_t *zlib_stream; + cairo_int_status_t status, status2; + cairo_surface_t *snapshot; + const uint8_t *mime_data; + unsigned long mime_data_length; + + snapshot = _cairo_surface_has_snapshot (&image->base, + &script_snapshot_backend); + if (snapshot) { + _cairo_output_stream_printf (ctx->stream, "s%u ", snapshot->unique_id); + return CAIRO_INT_STATUS_SUCCESS; + } + + status = _emit_png_surface (surface, image); + if (_cairo_int_status_is_error (status)) { + return status; + } else if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + cairo_image_surface_t *clone; + uint32_t len; + + if (image->format == CAIRO_FORMAT_INVALID) { + clone = _cairo_image_surface_coerce (image); + } else { + clone = (cairo_image_surface_t *) + cairo_surface_reference (&image->base); + } + + _cairo_output_stream_printf (ctx->stream, + "<< " + "/width %d " + "/height %d " + "/format //%s " + "/source ", + clone->width, clone->height, + _format_to_string (clone->format)); + + switch (clone->format) { + case CAIRO_FORMAT_A1: + len = (clone->width + 7)/8; + break; + case CAIRO_FORMAT_A8: + len = clone->width; + break; + case CAIRO_FORMAT_RGB16_565: + len = clone->width * 2; + break; + case CAIRO_FORMAT_RGB24: + len = clone->width * 3; + break; + case CAIRO_FORMAT_RGB30: + case CAIRO_FORMAT_ARGB32: + len = clone->width * 4; + break; + case CAIRO_FORMAT_RGB96F: + len = clone->width * 12; + break; + case CAIRO_FORMAT_RGBA128F: + len = clone->width * 16; + break; + case CAIRO_FORMAT_INVALID: + default: + ASSERT_NOT_REACHED; + len = 0; + break; + } + len *= clone->height; + + if (len > 24) { + _cairo_output_stream_puts (ctx->stream, "<|"); + + base85_stream = _cairo_base85_stream_create (ctx->stream); + + len = to_be32 (len); + _cairo_output_stream_write (base85_stream, &len, sizeof (len)); + + zlib_stream = _cairo_deflate_stream_create (base85_stream); + status = _write_image_surface (zlib_stream, clone); + + status2 = _cairo_output_stream_destroy (zlib_stream); + if (status == CAIRO_INT_STATUS_SUCCESS) + status = status2; + status2 = _cairo_output_stream_destroy (base85_stream); + if (status == CAIRO_INT_STATUS_SUCCESS) + status = status2; + if (unlikely (status)) + return status; + } else { + _cairo_output_stream_puts (ctx->stream, "<~"); + + base85_stream = _cairo_base85_stream_create (ctx->stream); + status = _write_image_surface (base85_stream, clone); + status2 = _cairo_output_stream_destroy (base85_stream); + if (status == CAIRO_INT_STATUS_SUCCESS) + status = status2; + if (unlikely (status)) + return status; + } + _cairo_output_stream_puts (ctx->stream, "~> >> image "); + + cairo_surface_destroy (&clone->base); + } + + cairo_surface_get_mime_data (&image->base, CAIRO_MIME_TYPE_JPEG, + &mime_data, &mime_data_length); + if (mime_data != NULL) { + _cairo_output_stream_printf (ctx->stream, + "\n (%s) <~", + CAIRO_MIME_TYPE_JPEG); + + base85_stream = _cairo_base85_stream_create (ctx->stream); + _cairo_output_stream_write (base85_stream, mime_data, mime_data_length); + status = _cairo_output_stream_destroy (base85_stream); + if (unlikely (status)) + return status; + + _cairo_output_stream_puts (ctx->stream, "~> set-mime-data\n"); + } + + cairo_surface_get_mime_data (&image->base, CAIRO_MIME_TYPE_JP2, + &mime_data, &mime_data_length); + if (mime_data != NULL) { + _cairo_output_stream_printf (ctx->stream, + "\n (%s) <~", + CAIRO_MIME_TYPE_JP2); + + base85_stream = _cairo_base85_stream_create (ctx->stream); + _cairo_output_stream_write (base85_stream, mime_data, mime_data_length); + status = _cairo_output_stream_destroy (base85_stream); + if (unlikely (status)) + return status; + + _cairo_output_stream_puts (ctx->stream, "~> set-mime-data\n"); + } + + return CAIRO_INT_STATUS_SUCCESS; +} + +static cairo_int_status_t +_emit_image_surface_pattern (cairo_script_surface_t *surface, + cairo_surface_t *source) +{ + cairo_image_surface_t *image; + cairo_status_t status; + void *extra; + + status = _cairo_surface_acquire_source_image (source, &image, &extra); + if (likely (status == CAIRO_STATUS_SUCCESS)) { + status = _emit_image_surface (surface, image); + _cairo_surface_release_source_image (source, image, extra); + } + + return status; +} + +static cairo_int_status_t +_emit_subsurface_pattern (cairo_script_surface_t *surface, + cairo_surface_subsurface_t *sub) +{ + cairo_surface_t *source = sub->target; + cairo_int_status_t status; + + switch ((int) source->backend->type) { + case CAIRO_SURFACE_TYPE_RECORDING: + status = _emit_recording_surface_pattern (surface, (cairo_recording_surface_t *) source); + break; + case CAIRO_SURFACE_TYPE_SCRIPT: + status = _emit_script_surface_pattern (surface, (cairo_script_surface_t *) source); + break; + default: + status = _emit_image_surface_pattern (surface, source); + break; + } + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (to_context (surface)->stream, + "%d %d %d %d subsurface ", + sub->extents.x, + sub->extents.y, + sub->extents.width, + sub->extents.height); + return CAIRO_INT_STATUS_SUCCESS; +} + +static cairo_int_status_t +_emit_surface_pattern (cairo_script_surface_t *surface, + const cairo_pattern_t *pattern) +{ + cairo_script_context_t *ctx = to_context (surface); + cairo_surface_pattern_t *surface_pattern; + cairo_surface_t *source, *snapshot, *free_me = NULL; + cairo_surface_t *take_snapshot = NULL; + cairo_int_status_t status; + + surface_pattern = (cairo_surface_pattern_t *) pattern; + source = surface_pattern->surface; + + if (_cairo_surface_is_snapshot (source)) { + snapshot = _cairo_surface_has_snapshot (source, &script_snapshot_backend); + if (snapshot) { + _cairo_output_stream_printf (ctx->stream, + "s%d pattern ", + snapshot->unique_id); + return CAIRO_INT_STATUS_SUCCESS; + } + + if (_cairo_surface_snapshot_is_reused (source)) + take_snapshot = source; + + free_me = source = _cairo_surface_snapshot_get_target (source); + } + + switch ((int) source->backend->type) { + case CAIRO_SURFACE_TYPE_RECORDING: + status = _emit_recording_surface_pattern (surface, (cairo_recording_surface_t *) source); + break; + case CAIRO_SURFACE_TYPE_SCRIPT: + status = _emit_script_surface_pattern (surface, (cairo_script_surface_t *) source); + break; + case CAIRO_SURFACE_TYPE_SUBSURFACE: + status = _emit_subsurface_pattern (surface, (cairo_surface_subsurface_t *) source); + break; + default: + status = _emit_image_surface_pattern (surface, source); + break; + } + cairo_surface_destroy (free_me); + if (unlikely (status)) + return status; + + if (take_snapshot) + attach_snapshot (ctx, take_snapshot); + + _cairo_output_stream_puts (ctx->stream, "pattern"); + return CAIRO_INT_STATUS_SUCCESS; +} + +static cairo_int_status_t +_emit_raster_pattern (cairo_script_surface_t *surface, + const cairo_pattern_t *pattern) +{ + cairo_surface_t *source; + cairo_int_status_t status; + + source = _cairo_raster_source_pattern_acquire (pattern, &surface->base, NULL); + if (unlikely (source == NULL)) { + ASSERT_NOT_REACHED; + return CAIRO_INT_STATUS_UNSUPPORTED; + } + if (unlikely (source->status)) + return source->status; + + status = _emit_image_surface_pattern (surface, source); + _cairo_raster_source_pattern_release (pattern, source); + if (unlikely (status)) + return status; + + _cairo_output_stream_puts (to_context(surface)->stream, "pattern"); + return CAIRO_INT_STATUS_SUCCESS; +} + +static cairo_int_status_t +_emit_pattern (cairo_script_surface_t *surface, + const cairo_pattern_t *pattern) +{ + cairo_script_context_t *ctx = to_context (surface); + cairo_int_status_t status; + cairo_bool_t is_default_extend; + cairo_bool_t need_newline = TRUE; + + switch (pattern->type) { + case CAIRO_PATTERN_TYPE_SOLID: + /* solid colors do not need filter/extend/matrix */ + return _emit_solid_pattern (surface, pattern); + + case CAIRO_PATTERN_TYPE_LINEAR: + status = _emit_linear_pattern (surface, pattern); + is_default_extend = pattern->extend == CAIRO_EXTEND_GRADIENT_DEFAULT; + break; + case CAIRO_PATTERN_TYPE_RADIAL: + status = _emit_radial_pattern (surface, pattern); + is_default_extend = pattern->extend == CAIRO_EXTEND_GRADIENT_DEFAULT; + break; + case CAIRO_PATTERN_TYPE_MESH: + status = _emit_mesh_pattern (surface, pattern); + is_default_extend = TRUE; + break; + case CAIRO_PATTERN_TYPE_SURFACE: + status = _emit_surface_pattern (surface, pattern); + is_default_extend = pattern->extend == CAIRO_EXTEND_SURFACE_DEFAULT; + break; + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + status = _emit_raster_pattern (surface, pattern); + is_default_extend = pattern->extend == CAIRO_EXTEND_SURFACE_DEFAULT; + break; + + default: + ASSERT_NOT_REACHED; + status = CAIRO_INT_STATUS_UNSUPPORTED; + } + if (unlikely (status)) + return status; + + if (! _cairo_matrix_is_identity (&pattern->matrix)) { + if (need_newline) { + _cairo_output_stream_puts (ctx->stream, "\n "); + need_newline = FALSE; + } + + _cairo_output_stream_printf (ctx->stream, + " [%f %f %f %f %f %f] set-matrix\n ", + pattern->matrix.xx, pattern->matrix.yx, + pattern->matrix.xy, pattern->matrix.yy, + pattern->matrix.x0, pattern->matrix.y0); + } + + /* XXX need to discriminate the user explicitly setting the default */ + if (pattern->filter != CAIRO_FILTER_DEFAULT) { + if (need_newline) { + _cairo_output_stream_puts (ctx->stream, "\n "); + need_newline = FALSE; + } + + _cairo_output_stream_printf (ctx->stream, + " //%s set-filter\n ", + _filter_to_string (pattern->filter)); + } + /* XXX need to discriminate the user explicitly setting the default */ + if (pattern->dither != CAIRO_DITHER_DEFAULT) { + if (need_newline) { + _cairo_output_stream_puts (ctx->stream, "\n "); + need_newline = FALSE; + } + + _cairo_output_stream_printf (ctx->stream, + " //%s set-dither\n ", + _dither_to_string (pattern->dither)); + } + if (! is_default_extend ){ + if (need_newline) { + _cairo_output_stream_puts (ctx->stream, "\n "); + need_newline = FALSE; + } + + _cairo_output_stream_printf (ctx->stream, + " //%s set-extend\n ", + _extend_to_string (pattern->extend)); + } + + if (need_newline) + _cairo_output_stream_puts (ctx->stream, "\n "); + + return CAIRO_INT_STATUS_SUCCESS; +} + +static cairo_int_status_t +_emit_identity (cairo_script_surface_t *surface, + cairo_bool_t *matrix_updated) +{ + assert (target_is_active (surface)); + + if (_cairo_matrix_is_identity (&surface->cr.current_ctm)) + return CAIRO_INT_STATUS_SUCCESS; + + _cairo_output_stream_puts (to_context (surface)->stream, + "identity set-matrix\n"); + + *matrix_updated = TRUE; + cairo_matrix_init_identity (&surface->cr.current_ctm); + + return CAIRO_INT_STATUS_SUCCESS; +} + +static cairo_int_status_t +_emit_source (cairo_script_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source) +{ + cairo_bool_t matrix_updated = FALSE; + cairo_int_status_t status; + + assert (target_is_active (surface)); + + if (op == CAIRO_OPERATOR_CLEAR) { + /* the source is ignored, so don't change it */ + return CAIRO_INT_STATUS_SUCCESS; + } + + if (_cairo_pattern_equal (&surface->cr.current_source.base, source)) + return CAIRO_INT_STATUS_SUCCESS; + + _cairo_pattern_fini (&surface->cr.current_source.base); + status = _cairo_pattern_init_copy (&surface->cr.current_source.base, + source); + if (unlikely (status)) + return status; + + status = _emit_identity (surface, &matrix_updated); + if (unlikely (status)) + return status; + + status = _emit_pattern (surface, source); + if (unlikely (status)) + return status; + + assert (target_is_active (surface)); + _cairo_output_stream_puts (to_context (surface)->stream, + " set-source\n"); + return CAIRO_INT_STATUS_SUCCESS; +} + +static cairo_status_t +_path_move_to (void *closure, + const cairo_point_t *point) +{ + _cairo_output_stream_printf (closure, + " %f %f m", + _cairo_fixed_to_double (point->x), + _cairo_fixed_to_double (point->y)); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_path_line_to (void *closure, + const cairo_point_t *point) +{ + _cairo_output_stream_printf (closure, + " %f %f l", + _cairo_fixed_to_double (point->x), + _cairo_fixed_to_double (point->y)); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_path_curve_to (void *closure, + const cairo_point_t *p1, + const cairo_point_t *p2, + const cairo_point_t *p3) +{ + _cairo_output_stream_printf (closure, + " %f %f %f %f %f %f c", + _cairo_fixed_to_double (p1->x), + _cairo_fixed_to_double (p1->y), + _cairo_fixed_to_double (p2->x), + _cairo_fixed_to_double (p2->y), + _cairo_fixed_to_double (p3->x), + _cairo_fixed_to_double (p3->y)); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_path_close (void *closure) +{ + _cairo_output_stream_printf (closure, + " h"); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_path_boxes (cairo_script_surface_t *surface, + const cairo_path_fixed_t *path) +{ + cairo_script_context_t *ctx = to_context (surface); + cairo_path_fixed_iter_t iter; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + struct _cairo_boxes_chunk *chunk; + cairo_boxes_t boxes; + cairo_box_t box; + int i; + + _cairo_boxes_init (&boxes); + _cairo_path_fixed_iter_init (&iter, path); + while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) { + if (box.p1.y == box.p2.y || box.p1.x == box.p2.x) + continue; + + status = _cairo_boxes_add (&boxes, CAIRO_ANTIALIAS_DEFAULT, &box); + if (unlikely (status)) { + _cairo_boxes_fini (&boxes); + return status; + } + } + + if (! _cairo_path_fixed_iter_at_end (&iter)) { + _cairo_boxes_fini (&boxes); + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + for (chunk = &boxes.chunks; chunk; chunk = chunk->next) { + for (i = 0; i < chunk->count; i++) { + const cairo_box_t *b = &chunk->base[i]; + double x1 = _cairo_fixed_to_double (b->p1.x); + double y1 = _cairo_fixed_to_double (b->p1.y); + double x2 = _cairo_fixed_to_double (b->p2.x); + double y2 = _cairo_fixed_to_double (b->p2.y); + + _cairo_output_stream_printf (ctx->stream, + "\n %f %f %f %f rectangle", + x1, y1, x2 - x1, y2 - y1); + } + } + + _cairo_boxes_fini (&boxes); + return status; +} + +static cairo_status_t +_emit_path (cairo_script_surface_t *surface, + const cairo_path_fixed_t *path, + cairo_bool_t is_fill) +{ + cairo_script_context_t *ctx = to_context (surface); + cairo_box_t box; + cairo_int_status_t status; + + assert (target_is_active (surface)); + assert (_cairo_matrix_is_identity (&surface->cr.current_ctm)); + + if (_cairo_path_fixed_equal (&surface->cr.current_path, path)) + return CAIRO_STATUS_SUCCESS; + + _cairo_path_fixed_fini (&surface->cr.current_path); + + _cairo_output_stream_puts (ctx->stream, "n"); + + if (path == NULL) { + _cairo_path_fixed_init (&surface->cr.current_path); + _cairo_output_stream_puts (ctx->stream, "\n"); + return CAIRO_STATUS_SUCCESS; + } + + status = _cairo_path_fixed_init_copy (&surface->cr.current_path, path); + if (unlikely (status)) + return status; + + status = CAIRO_INT_STATUS_UNSUPPORTED; + if (_cairo_path_fixed_is_rectangle (path, &box)) { + double x1 = _cairo_fixed_to_double (box.p1.x); + double y1 = _cairo_fixed_to_double (box.p1.y); + double x2 = _cairo_fixed_to_double (box.p2.x); + double y2 = _cairo_fixed_to_double (box.p2.y); + + assert (x1 > -9999); + + _cairo_output_stream_printf (ctx->stream, + " %f %f %f %f rectangle", + x1, y1, x2 - x1, y2 - y1); + status = CAIRO_INT_STATUS_SUCCESS; + } else if (is_fill && _cairo_path_fixed_fill_is_rectilinear (path)) { + status = _emit_path_boxes (surface, path); + } + + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + status = _cairo_path_fixed_interpret (path, + _path_move_to, + _path_line_to, + _path_curve_to, + _path_close, + ctx->stream); + } + + _cairo_output_stream_puts (ctx->stream, "\n"); + + return status; +} +static cairo_bool_t +_scaling_matrix_equal (const cairo_matrix_t *a, + const cairo_matrix_t *b) +{ + return fabs (a->xx - b->xx) < 1e-5 && + fabs (a->xy - b->xy) < 1e-5 && + fabs (a->yx - b->yx) < 1e-5 && + fabs (a->yy - b->yy) < 1e-5; +} + +static cairo_status_t +_emit_scaling_matrix (cairo_script_surface_t *surface, + const cairo_matrix_t *ctm, + cairo_bool_t *matrix_updated) +{ + cairo_script_context_t *ctx = to_context (surface); + cairo_bool_t was_identity; + assert (target_is_active (surface)); + + if (_scaling_matrix_equal (&surface->cr.current_ctm, ctm)) + return CAIRO_STATUS_SUCCESS; + + was_identity = _cairo_matrix_is_identity (&surface->cr.current_ctm); + + *matrix_updated = TRUE; + surface->cr.current_ctm = *ctm; + surface->cr.current_ctm.x0 = 0.; + surface->cr.current_ctm.y0 = 0.; + + if (_cairo_matrix_is_identity (&surface->cr.current_ctm)) { + _cairo_output_stream_puts (ctx->stream, + "identity set-matrix\n"); + } else if (was_identity && fabs (ctm->yx) < 1e-5 && fabs (ctm->xy) < 1e-5) { + _cairo_output_stream_printf (ctx->stream, + "%f %f scale\n", + ctm->xx, ctm->yy); + } else { + _cairo_output_stream_printf (ctx->stream, + "[%f %f %f %f 0 0] set-matrix\n", + ctm->xx, ctm->yx, + ctm->xy, ctm->yy); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_font_matrix (cairo_script_surface_t *surface, + const cairo_matrix_t *font_matrix) +{ + cairo_script_context_t *ctx = to_context (surface); + assert (target_is_active (surface)); + + if (memcmp (&surface->cr.current_font_matrix, + font_matrix, + sizeof (cairo_matrix_t)) == 0) + { + return CAIRO_STATUS_SUCCESS; + } + + surface->cr.current_font_matrix = *font_matrix; + + if (_cairo_matrix_is_identity (font_matrix)) { + _cairo_output_stream_puts (ctx->stream, + "identity set-font-matrix\n"); + } else { + _cairo_output_stream_printf (ctx->stream, + "[%f %f %f %f %f %f] set-font-matrix\n", + font_matrix->xx, font_matrix->yx, + font_matrix->xy, font_matrix->yy, + font_matrix->x0, font_matrix->y0); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_surface_t * +_cairo_script_surface_create_similar (void *abstract_surface, + cairo_content_t content, + int width, + int height) +{ + cairo_script_surface_t *surface, *other = abstract_surface; + cairo_surface_t *passthrough = NULL; + cairo_script_context_t *ctx; + cairo_rectangle_t extents; + cairo_status_t status; + + ctx = to_context (other); + + status = cairo_device_acquire (&ctx->base); + if (unlikely (status)) + return _cairo_surface_create_in_error (status); + + if (! other->emitted) { + status = _emit_surface (other); + if (unlikely (status)) { + cairo_device_release (&ctx->base); + return _cairo_surface_create_in_error (status); + } + + target_push (other); + } + + if (_cairo_surface_wrapper_is_active (&other->wrapper)) { + passthrough = + _cairo_surface_wrapper_create_similar (&other->wrapper, + content, width, height); + if (unlikely (passthrough->status)) { + cairo_device_release (&ctx->base); + return passthrough; + } + } + + extents.x = extents.y = 0; + extents.width = width; + extents.height = height; + surface = _cairo_script_surface_create_internal (ctx, content, + &extents, passthrough); + cairo_surface_destroy (passthrough); + + if (unlikely (surface->base.status)) { + cairo_device_release (&ctx->base); + return &surface->base; + } + + _get_target (other); + _cairo_output_stream_printf (ctx->stream, + "%u %u //%s similar dup /s%u exch def context\n", + width, height, + _content_to_string (content), + surface->base.unique_id); + + surface->emitted = TRUE; + surface->defined = TRUE; + surface->base.is_clear = TRUE; + target_push (surface); + + cairo_device_release (&ctx->base); + return &surface->base; +} + +static cairo_status_t +_device_flush (void *abstract_device) +{ + cairo_script_context_t *ctx = abstract_device; + + return _cairo_output_stream_flush (ctx->stream); +} + +static void +_device_finish (void *abstract_device) +{ + cairo_script_context_t *ctx = abstract_device; + + cairo_status_t status = _cairo_output_stream_close (ctx->stream); + status = _cairo_device_set_error (&ctx->base, status); + (void) status; +} + +static void +_device_destroy (void *abstract_device) +{ + cairo_script_context_t *ctx = abstract_device; + cairo_status_t status; + + while (! cairo_list_is_empty (&ctx->fonts)) { + cairo_script_font_t *font; + + font = cairo_list_first_entry (&ctx->fonts, cairo_script_font_t, link); + cairo_list_del (&font->base.link); + cairo_list_del (&font->link); + free (font); + } + + _bitmap_fini (ctx->surface_id.next); + _bitmap_fini (ctx->font_id.next); + + if (ctx->owns_stream) + status = _cairo_output_stream_destroy (ctx->stream); + + free (ctx); +} + +static cairo_surface_t * +_cairo_script_surface_source (void *abstract_surface, + cairo_rectangle_int_t *extents) +{ + cairo_script_surface_t *surface = abstract_surface; + + if (extents) { + extents->x = extents->y = 0; + extents->width = surface->width; + extents->height = surface->height; + } + + return &surface->base; +} + +static cairo_status_t +_cairo_script_surface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) +{ + cairo_script_surface_t *surface = abstract_surface; + + if (_cairo_surface_wrapper_is_active (&surface->wrapper)) { + return _cairo_surface_wrapper_acquire_source_image (&surface->wrapper, + image_out, + image_extra); + } + + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static void +_cairo_script_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) +{ + cairo_script_surface_t *surface = abstract_surface; + + assert (_cairo_surface_wrapper_is_active (&surface->wrapper)); + _cairo_surface_wrapper_release_source_image (&surface->wrapper, + image, + image_extra); +} + +static cairo_status_t +_cairo_script_surface_finish (void *abstract_surface) +{ + cairo_script_surface_t *surface = abstract_surface; + cairo_script_context_t *ctx = to_context (surface); + cairo_status_t status = CAIRO_STATUS_SUCCESS, status2; + + _cairo_surface_wrapper_fini (&surface->wrapper); + + free (surface->cr.current_style.dash); + surface->cr.current_style.dash = NULL; + + _cairo_pattern_fini (&surface->cr.current_source.base); + _cairo_path_fixed_fini (&surface->cr.current_path); + _cairo_font_options_fini (&surface->cr.current_font_options); + _cairo_surface_clipper_reset (&surface->clipper); + + status = cairo_device_acquire (&ctx->base); + if (unlikely (status)) + return status; + + if (surface->emitted) { + assert (! surface->active); + + if (! cairo_list_is_empty (&surface->operand.link)) { + if (! ctx->active) { + if (target_is_active (surface)) { + _cairo_output_stream_printf (ctx->stream, + "pop\n"); + } else { + int depth = target_depth (surface); + if (depth == 1) { + _cairo_output_stream_printf (ctx->stream, + "exch pop\n"); + } else { + _cairo_output_stream_printf (ctx->stream, + "%d -1 roll pop\n", + depth); + } + } + cairo_list_del (&surface->operand.link); + } else { + struct deferred_finish *link = _cairo_calloc (sizeof (*link)); + if (link == NULL) { + status2 = _cairo_error (CAIRO_STATUS_NO_MEMORY); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; + cairo_list_del (&surface->operand.link); + } else { + link->operand.type = DEFERRED; + cairo_list_move_list (&surface->operand.link, &link->operand.link); + cairo_list_add (&link->link, &ctx->deferred); + } + } + } + + if (surface->defined) { + _cairo_output_stream_printf (ctx->stream, + "/s%u undef\n", + surface->base.unique_id); + } + } + + if (status == CAIRO_STATUS_SUCCESS) + status = _cairo_output_stream_flush (to_context (surface)->stream); + + cairo_device_release (&ctx->base); + + return status; +} + +static cairo_int_status_t +_cairo_script_surface_copy_page (void *abstract_surface) +{ + cairo_script_surface_t *surface = abstract_surface; + cairo_status_t status; + + status = cairo_device_acquire (surface->base.device); + if (unlikely (status)) + return status; + + status = _emit_context (surface); + if (unlikely (status)) + goto BAIL; + + _cairo_output_stream_puts (to_context (surface)->stream, "copy-page\n"); + +BAIL: + cairo_device_release (surface->base.device); + return status; +} + +static cairo_int_status_t +_cairo_script_surface_show_page (void *abstract_surface) +{ + cairo_script_surface_t *surface = abstract_surface; + cairo_status_t status; + + status = cairo_device_acquire (surface->base.device); + if (unlikely (status)) + return status; + + status = _emit_context (surface); + if (unlikely (status)) + goto BAIL; + + _cairo_output_stream_puts (to_context (surface)->stream, "show-page\n"); + +BAIL: + cairo_device_release (surface->base.device); + return status; +} + +static cairo_status_t +_cairo_script_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_script_surface_t *surface = cairo_container_of (clipper, + cairo_script_surface_t, + clipper); + cairo_script_context_t *ctx = to_context (surface); + cairo_bool_t matrix_updated = FALSE; + cairo_status_t status; + cairo_box_t box; + + status = _emit_context (surface); + if (unlikely (status)) + return status; + + if (path == NULL) { + if (surface->cr.has_clip) { + _cairo_output_stream_puts (ctx->stream, "reset-clip\n"); + surface->cr.has_clip = FALSE; + } + return CAIRO_STATUS_SUCCESS; + } + + /* skip the trivial clip covering the surface extents */ + if (surface->width >= 0 && surface->height >= 0 && + _cairo_path_fixed_is_box (path, &box)) + { + if (box.p1.x <= 0 && box.p1.y <= 0 && + box.p2.x >= _cairo_fixed_from_double (surface->width) && + box.p2.y >= _cairo_fixed_from_double (surface->height)) + { + return CAIRO_STATUS_SUCCESS; + } + } + + status = _emit_identity (surface, &matrix_updated); + if (unlikely (status)) + return status; + + status = _emit_fill_rule (surface, fill_rule); + if (unlikely (status)) + return status; + + if (path->has_curve_to) { + status = _emit_tolerance (surface, tolerance, matrix_updated); + if (unlikely (status)) + return status; + } + + if (! _cairo_path_fixed_fill_maybe_region (path)) { + status = _emit_antialias (surface, antialias); + if (unlikely (status)) + return status; + } + + status = _emit_path (surface, path, TRUE); + if (unlikely (status)) + return status; + + _cairo_output_stream_puts (ctx->stream, "clip+\n"); + surface->cr.has_clip = TRUE; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +active (cairo_script_surface_t *surface) +{ + cairo_status_t status; + + status = cairo_device_acquire (surface->base.device); + if (unlikely (status)) + return status; + + if (surface->active++ == 0) + to_context (surface)->active++; + + return CAIRO_STATUS_SUCCESS; +} + +static void +inactive (cairo_script_surface_t *surface) +{ + cairo_script_context_t *ctx = to_context (surface); + cairo_list_t sorted; + + assert (surface->active > 0); + if (--surface->active) + goto DONE; + + assert (ctx->active > 0); + if (--ctx->active) + goto DONE; + + cairo_list_init (&sorted); + while (! cairo_list_is_empty (&ctx->deferred)) { + struct deferred_finish *df; + cairo_list_t *operand; + int depth; + + df = cairo_list_first_entry (&ctx->deferred, + struct deferred_finish, + link); + + depth = 0; + cairo_list_foreach (operand, &ctx->operands) { + if (operand == &df->operand.link) + break; + depth++; + } + + df->operand.type = depth; + + if (cairo_list_is_empty (&sorted)) { + cairo_list_move (&df->link, &sorted); + } else { + struct deferred_finish *pos; + + cairo_list_foreach_entry (pos, struct deferred_finish, + &sorted, + link) + { + if (df->operand.type < pos->operand.type) + break; + } + cairo_list_move_tail (&df->link, &pos->link); + } + } + + while (! cairo_list_is_empty (&sorted)) { + struct deferred_finish *df; + cairo_list_t *operand; + int depth; + + df = cairo_list_first_entry (&sorted, + struct deferred_finish, + link); + + depth = 0; + cairo_list_foreach (operand, &ctx->operands) { + if (operand == &df->operand.link) + break; + depth++; + } + + if (depth == 0) { + _cairo_output_stream_printf (ctx->stream, + "pop\n"); + } else if (depth == 1) { + _cairo_output_stream_printf (ctx->stream, + "exch pop\n"); + } else { + _cairo_output_stream_printf (ctx->stream, + "%d -1 roll pop\n", + depth); + } + + cairo_list_del (&df->operand.link); + cairo_list_del (&df->link); + free (df); + } + +DONE: + cairo_device_release (surface->base.device); +} + +static cairo_int_status_t +_cairo_script_surface_paint (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip) +{ + cairo_script_surface_t *surface = abstract_surface; + cairo_status_t status; + + status = active (surface); + if (unlikely (status)) + return status; + + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) + goto BAIL; + + status = _emit_context (surface); + if (unlikely (status)) + goto BAIL; + + status = _emit_source (surface, op, source); + if (unlikely (status)) + goto BAIL; + + status = _emit_operator (surface, op); + if (unlikely (status)) + goto BAIL; + + _cairo_output_stream_puts (to_context (surface)->stream, + "paint\n"); + + inactive (surface); + + if (_cairo_surface_wrapper_is_active (&surface->wrapper)) { + return _cairo_surface_wrapper_paint (&surface->wrapper, + op, source, 0, clip); + } + + return CAIRO_STATUS_SUCCESS; + +BAIL: + inactive (surface); + return status; +} + +static cairo_int_status_t +_cairo_script_surface_mask (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_clip_t *clip) +{ + cairo_script_surface_t *surface = abstract_surface; + cairo_status_t status; + + status = active (surface); + if (unlikely (status)) + return status; + + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) + goto BAIL; + + status = _emit_context (surface); + if (unlikely (status)) + goto BAIL; + + status = _emit_source (surface, op, source); + if (unlikely (status)) + goto BAIL; + + status = _emit_operator (surface, op); + if (unlikely (status)) + goto BAIL; + + if (_cairo_pattern_equal (source, mask)) { + _cairo_output_stream_puts (to_context (surface)->stream, "/source get"); + } else { + status = _emit_pattern (surface, mask); + if (unlikely (status)) + goto BAIL; + } + + assert (surface->cr.current_operator == op); + + _cairo_output_stream_puts (to_context (surface)->stream, + " mask\n"); + + inactive (surface); + + if (_cairo_surface_wrapper_is_active (&surface->wrapper)) { + return _cairo_surface_wrapper_mask (&surface->wrapper, + op, source, 0, mask, 0, clip); + } + + return CAIRO_STATUS_SUCCESS; + +BAIL: + inactive (surface); + return status; +} + +static cairo_int_status_t +_cairo_script_surface_stroke (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_script_surface_t *surface = abstract_surface; + cairo_bool_t matrix_updated = FALSE; + cairo_status_t status; + + status = active (surface); + if (unlikely (status)) + return status; + + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) + goto BAIL; + + status = _emit_context (surface); + if (unlikely (status)) + goto BAIL; + + status = _emit_identity (surface, &matrix_updated); + if (unlikely (status)) + goto BAIL; + + status = _emit_path (surface, path, FALSE); + if (unlikely (status)) + goto BAIL; + + status = _emit_source (surface, op, source); + if (unlikely (status)) + goto BAIL; + + status = _emit_scaling_matrix (surface, ctm, &matrix_updated); + if (unlikely (status)) + goto BAIL; + + status = _emit_operator (surface, op); + if (unlikely (status)) + goto BAIL; + + if (_scaling_matrix_equal (&surface->cr.current_ctm, + &surface->cr.current_stroke_matrix)) + { + matrix_updated = FALSE; + } + else + { + matrix_updated = TRUE; + surface->cr.current_stroke_matrix = surface->cr.current_ctm; + } + + status = _emit_stroke_style (surface, style, matrix_updated); + if (unlikely (status)) + goto BAIL; + + status = _emit_tolerance (surface, tolerance, matrix_updated); + if (unlikely (status)) + goto BAIL; + + status = _emit_antialias (surface, antialias); + if (unlikely (status)) + goto BAIL; + + _cairo_output_stream_puts (to_context (surface)->stream, "stroke+\n"); + + inactive (surface); + + if (_cairo_surface_wrapper_is_active (&surface->wrapper)) { + return _cairo_surface_wrapper_stroke (&surface->wrapper, + op, source, 0, path, + style, + ctm, ctm_inverse, + tolerance, antialias, + clip); + } + + return CAIRO_STATUS_SUCCESS; + +BAIL: + inactive (surface); + return status; +} + +static cairo_int_status_t +_cairo_script_surface_fill (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_script_surface_t *surface = abstract_surface; + cairo_bool_t matrix_updated = FALSE; + cairo_status_t status; + cairo_box_t box; + + status = active (surface); + if (unlikely (status)) + return status; + + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) + goto BAIL; + + status = _emit_context (surface); + if (unlikely (status)) + goto BAIL; + + status = _emit_identity (surface, &matrix_updated); + if (unlikely (status)) + goto BAIL; + + status = _emit_source (surface, op, source); + if (unlikely (status)) + goto BAIL; + + if (! _cairo_path_fixed_is_box (path, &box)) { + status = _emit_fill_rule (surface, fill_rule); + if (unlikely (status)) + goto BAIL; + } + + if (path->has_curve_to) { + status = _emit_tolerance (surface, tolerance, matrix_updated); + if (unlikely (status)) + goto BAIL; + } + + if (! _cairo_path_fixed_fill_maybe_region (path)) { + status = _emit_antialias (surface, antialias); + if (unlikely (status)) + goto BAIL; + } + + status = _emit_path (surface, path, TRUE); + if (unlikely (status)) + goto BAIL; + + status = _emit_operator (surface, op); + if (unlikely (status)) + goto BAIL; + + _cairo_output_stream_puts (to_context (surface)->stream, "fill+\n"); + + inactive (surface); + + if (_cairo_surface_wrapper_is_active (&surface->wrapper)) { + return _cairo_surface_wrapper_fill (&surface->wrapper, + op, source, 0, path, + fill_rule, + tolerance, + antialias, + clip); + } + + return CAIRO_STATUS_SUCCESS; + +BAIL: + inactive (surface); + return status; +} + +static cairo_surface_t * +_cairo_script_surface_snapshot (void *abstract_surface) +{ + cairo_script_surface_t *surface = abstract_surface; + + if (_cairo_surface_wrapper_is_active (&surface->wrapper)) + return _cairo_surface_wrapper_snapshot (&surface->wrapper); + + return NULL; +} + +static cairo_bool_t +_cairo_script_surface_has_show_text_glyphs (void *abstract_surface) +{ + return TRUE; +} + +static const char * +_subpixel_order_to_string (cairo_subpixel_order_t subpixel_order) +{ + static const char *names[] = { + "SUBPIXEL_ORDER_DEFAULT", /* CAIRO_SUBPIXEL_ORDER_DEFAULT */ + "SUBPIXEL_ORDER_RGB", /* CAIRO_SUBPIXEL_ORDER_RGB */ + "SUBPIXEL_ORDER_BGR", /* CAIRO_SUBPIXEL_ORDER_BGR */ + "SUBPIXEL_ORDER_VRGB", /* CAIRO_SUBPIXEL_ORDER_VRGB */ + "SUBPIXEL_ORDER_VBGR" /* CAIRO_SUBPIXEL_ORDER_VBGR */ + }; + return names[subpixel_order]; +} +static const char * +_hint_style_to_string (cairo_hint_style_t hint_style) +{ + static const char *names[] = { + "HINT_STYLE_DEFAULT", /* CAIRO_HINT_STYLE_DEFAULT */ + "HINT_STYLE_NONE", /* CAIRO_HINT_STYLE_NONE */ + "HINT_STYLE_SLIGHT", /* CAIRO_HINT_STYLE_SLIGHT */ + "HINT_STYLE_MEDIUM", /* CAIRO_HINT_STYLE_MEDIUM */ + "HINT_STYLE_FULL" /* CAIRO_HINT_STYLE_FULL */ + }; + return names[hint_style]; +} +static const char * +_hint_metrics_to_string (cairo_hint_metrics_t hint_metrics) +{ + static const char *names[] = { + "HINT_METRICS_DEFAULT", /* CAIRO_HINT_METRICS_DEFAULT */ + "HINT_METRICS_OFF", /* CAIRO_HINT_METRICS_OFF */ + "HINT_METRICS_ON" /* CAIRO_HINT_METRICS_ON */ + }; + return names[hint_metrics]; +} + +static cairo_status_t +_emit_font_options (cairo_script_surface_t *surface, + cairo_font_options_t *font_options) +{ + cairo_script_context_t *ctx = to_context (surface); + + if (cairo_font_options_equal (&surface->cr.current_font_options, + font_options)) + { + return CAIRO_STATUS_SUCCESS; + } + + _cairo_output_stream_printf (ctx->stream, "<<"); + + if (font_options->antialias != surface->cr.current_font_options.antialias) { + _cairo_output_stream_printf (ctx->stream, + " /antialias //%s", + _antialias_to_string (font_options->antialias)); + } + + if (font_options->subpixel_order != + surface->cr.current_font_options.subpixel_order) + { + _cairo_output_stream_printf (ctx->stream, + " /subpixel-order //%s", + _subpixel_order_to_string (font_options->subpixel_order)); + } + + if (font_options->hint_style != + surface->cr.current_font_options.hint_style) + { + _cairo_output_stream_printf (ctx->stream, + " /hint-style //%s", + _hint_style_to_string (font_options->hint_style)); + } + + if (font_options->hint_metrics != + surface->cr.current_font_options.hint_metrics) + { + _cairo_output_stream_printf (ctx->stream, + " /hint-metrics //%s", + _hint_metrics_to_string (font_options->hint_metrics)); + } + + _cairo_output_stream_printf (ctx->stream, + " >> set-font-options\n"); + + surface->cr.current_font_options = *font_options; + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_script_scaled_font_fini (cairo_scaled_font_private_t *abstract_private, + cairo_scaled_font_t *scaled_font) +{ + cairo_script_font_t *priv = (cairo_script_font_t *)abstract_private; + cairo_script_context_t *ctx = (cairo_script_context_t *)abstract_private->key; + cairo_status_t status; + + status = cairo_device_acquire (&ctx->base); + if (likely (status == CAIRO_STATUS_SUCCESS)) { + _cairo_output_stream_printf (ctx->stream, + "/f%lu undef /sf%lu undef\n", + priv->id, + priv->id); + + _bitmap_release_id (&ctx->font_id, priv->id); + cairo_device_release (&ctx->base); + } + + cairo_list_del (&priv->link); + cairo_list_del (&priv->base.link); + free (priv); +} + +static cairo_script_font_t * +_cairo_script_font_get (cairo_script_context_t *ctx, cairo_scaled_font_t *font) +{ + return (cairo_script_font_t *) _cairo_scaled_font_find_private (font, ctx); +} + +static long unsigned +_cairo_script_font_id (cairo_script_context_t *ctx, cairo_scaled_font_t *font) +{ + return _cairo_script_font_get (ctx, font)->id; +} + +static cairo_status_t +_emit_type42_font (cairo_script_surface_t *surface, + cairo_scaled_font_t *scaled_font) +{ + cairo_script_context_t *ctx = to_context (surface); + const cairo_scaled_font_backend_t *backend; + cairo_output_stream_t *base85_stream; + cairo_output_stream_t *zlib_stream; + cairo_status_t status, status2; + unsigned long size; + unsigned int load_flags; + uint32_t len; + uint8_t *buf; + + backend = scaled_font->backend; + if (backend->load_truetype_table == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + size = 0; + status = backend->load_truetype_table (scaled_font, 0, 0, NULL, &size); + if (unlikely (status)) + return status; + + buf = _cairo_malloc (size); + if (unlikely (buf == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + status = backend->load_truetype_table (scaled_font, 0, 0, buf, &size); + if (unlikely (status)) { + free (buf); + return status; + } + +#if CAIRO_HAS_FT_FONT + load_flags = _cairo_ft_scaled_font_get_load_flags (scaled_font); +#else + load_flags = 0; +#endif + _cairo_output_stream_printf (ctx->stream, + "<< " + "/type 42 " + "/index 0 " + "/flags %d " + "/source <|", + load_flags); + + base85_stream = _cairo_base85_stream_create (ctx->stream); + len = to_be32 (size); + _cairo_output_stream_write (base85_stream, &len, sizeof (len)); + + zlib_stream = _cairo_deflate_stream_create (base85_stream); + + _cairo_output_stream_write (zlib_stream, buf, size); + free (buf); + + status2 = _cairo_output_stream_destroy (zlib_stream); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; + + status2 = _cairo_output_stream_destroy (base85_stream); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; + + _cairo_output_stream_printf (ctx->stream, + "~> >> font dup /f%lu exch def set-font-face", + _cairo_script_font_id (ctx, scaled_font)); + + return status; +} + +static cairo_status_t +_emit_scaled_font_init (cairo_script_surface_t *surface, + cairo_scaled_font_t *scaled_font, + cairo_script_font_t **font_out) +{ + cairo_script_context_t *ctx = to_context (surface); + cairo_script_font_t *font_private; + cairo_int_status_t status; + + font_private = _cairo_calloc (sizeof (cairo_script_font_t)); + if (unlikely (font_private == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + _cairo_scaled_font_attach_private (scaled_font, &font_private->base, ctx, + _cairo_script_scaled_font_fini); + + font_private->parent = scaled_font; + font_private->subset_glyph_index = 0; + font_private->has_sfnt = TRUE; + + cairo_list_add (&font_private->link, &ctx->fonts); + + status = _bitmap_next_id (&ctx->font_id, + &font_private->id); + if (unlikely (status)) { + free (font_private); + return status; + } + + status = _emit_context (surface); + if (unlikely (status)) { + free (font_private); + return status; + } + + status = _emit_type42_font (surface, scaled_font); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) { + *font_out = font_private; + return status; + } + + font_private->has_sfnt = FALSE; + _cairo_output_stream_printf (ctx->stream, + "dict\n" + " /type 3 set\n" + " /metrics [%f %f %f %f %f] set\n" + " /glyphs array set\n" + " font dup /f%lu exch def set-font-face", + scaled_font->fs_extents.ascent, + scaled_font->fs_extents.descent, + scaled_font->fs_extents.height, + scaled_font->fs_extents.max_x_advance, + scaled_font->fs_extents.max_y_advance, + font_private->id); + + *font_out = font_private; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_scaled_font (cairo_script_surface_t *surface, + cairo_scaled_font_t *scaled_font) +{ + cairo_script_context_t *ctx = to_context (surface); + cairo_matrix_t matrix; + cairo_font_options_t options; + cairo_bool_t matrix_updated = FALSE; + cairo_status_t status; + cairo_script_font_t *font_private; + + cairo_scaled_font_get_ctm (scaled_font, &matrix); + status = _emit_scaling_matrix (surface, &matrix, &matrix_updated); + if (unlikely (status)) + return status; + + if (! matrix_updated && surface->cr.current_scaled_font == scaled_font) + return CAIRO_STATUS_SUCCESS; + + surface->cr.current_scaled_font = scaled_font; + + font_private = _cairo_script_font_get (ctx, scaled_font); + if (font_private == NULL) { + cairo_scaled_font_get_font_matrix (scaled_font, &matrix); + status = _emit_font_matrix (surface, &matrix); + if (unlikely (status)) + return status; + + _cairo_font_options_init_default (&options); + cairo_scaled_font_get_font_options (scaled_font, &options); + status = _emit_font_options (surface, &options); + if (unlikely (status)) + return status; + + status = _emit_scaled_font_init (surface, scaled_font, &font_private); + if (unlikely (status)) + return status; + + assert (target_is_active (surface)); + _cairo_output_stream_printf (ctx->stream, + " /scaled-font get /sf%lu exch def\n", + font_private->id); + } else { + _cairo_output_stream_printf (ctx->stream, + "sf%lu set-scaled-font\n", + font_private->id); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_scaled_glyph_vector (cairo_script_surface_t *surface, + cairo_scaled_font_t *scaled_font, + cairo_script_font_t *font_private, + cairo_scaled_glyph_t *scaled_glyph) +{ + cairo_script_context_t *ctx = to_context (surface); + cairo_script_implicit_context_t old_cr; + cairo_status_t status; + unsigned long index; + + index = ++font_private->subset_glyph_index; + scaled_glyph->dev_private_key = ctx; + scaled_glyph->dev_private = (void *)(uintptr_t)index; + + _cairo_output_stream_printf (ctx->stream, + "%lu <<\n" + " /metrics [%f %f %f %f %f %f]\n" + " /render {\n", + index, + scaled_glyph->fs_metrics.x_bearing, + scaled_glyph->fs_metrics.y_bearing, + scaled_glyph->fs_metrics.width, + scaled_glyph->fs_metrics.height, + scaled_glyph->fs_metrics.x_advance, + scaled_glyph->fs_metrics.y_advance); + + if (! _cairo_matrix_is_identity (&scaled_font->scale_inverse)) { + _cairo_output_stream_printf (ctx->stream, + "[%f %f %f %f %f %f] transform\n", + scaled_font->scale_inverse.xx, + scaled_font->scale_inverse.yx, + scaled_font->scale_inverse.xy, + scaled_font->scale_inverse.yy, + scaled_font->scale_inverse.x0, + scaled_font->scale_inverse.y0); + } + + old_cr = surface->cr; + _cairo_script_implicit_context_init (&surface->cr); + status = _cairo_recording_surface_replay (scaled_glyph->recording_surface, + &surface->base); + surface->cr = old_cr; + + _cairo_output_stream_puts (ctx->stream, "} >> set\n"); + + return status; +} + +static cairo_status_t +_emit_scaled_glyph_bitmap (cairo_script_surface_t *surface, + cairo_scaled_font_t *scaled_font, + cairo_script_font_t *font_private, + cairo_scaled_glyph_t *scaled_glyph) +{ + cairo_script_context_t *ctx = to_context (surface); + cairo_status_t status; + unsigned long index; + + index = ++font_private->subset_glyph_index; + scaled_glyph->dev_private_key = ctx; + scaled_glyph->dev_private = (void *)(uintptr_t)index; + + _cairo_output_stream_printf (ctx->stream, + "%lu <<\n" + " /metrics [%f %f %f %f %f %f]\n" + " /render {\n" + "%f %f translate\n", + index, + scaled_glyph->fs_metrics.x_bearing, + scaled_glyph->fs_metrics.y_bearing, + scaled_glyph->fs_metrics.width, + scaled_glyph->fs_metrics.height, + scaled_glyph->fs_metrics.x_advance, + scaled_glyph->fs_metrics.y_advance, + scaled_glyph->fs_metrics.x_bearing, + scaled_glyph->fs_metrics.y_bearing); + + status = _emit_image_surface (surface, scaled_glyph->surface); + if (unlikely (status)) + return status; + + _cairo_output_stream_puts (ctx->stream, "pattern "); + + if (! _cairo_matrix_is_identity (&scaled_font->font_matrix)) { + _cairo_output_stream_printf (ctx->stream, + "\n [%f %f %f %f %f %f] set-matrix\n", + scaled_font->font_matrix.xx, + scaled_font->font_matrix.yx, + scaled_font->font_matrix.xy, + scaled_font->font_matrix.yy, + scaled_font->font_matrix.x0, + scaled_font->font_matrix.y0); + } + _cairo_output_stream_puts (ctx->stream, + "mask\n} >> set\n"); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_scaled_glyph_prologue (cairo_script_surface_t *surface, + cairo_scaled_font_t *scaled_font) +{ + cairo_script_context_t *ctx = to_context (surface); + + _cairo_output_stream_printf (ctx->stream, "f%lu /glyphs get\n", + _cairo_script_font_id (ctx, scaled_font)); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_emit_scaled_glyphs (cairo_script_surface_t *surface, + cairo_scaled_font_t *scaled_font, + cairo_glyph_t *glyphs, + unsigned int num_glyphs) +{ + cairo_script_context_t *ctx = to_context (surface); + cairo_script_font_t *font_private; + cairo_status_t status; + unsigned int n; + cairo_bool_t have_glyph_prologue = FALSE; + + if (num_glyphs == 0) + return CAIRO_STATUS_SUCCESS; + + font_private = _cairo_script_font_get (ctx, scaled_font); + if (font_private->has_sfnt) + return CAIRO_STATUS_SUCCESS; + + _cairo_scaled_font_freeze_cache (scaled_font); + for (n = 0; n < num_glyphs; n++) { + cairo_scaled_glyph_t *scaled_glyph; + + status = _cairo_scaled_glyph_lookup (scaled_font, + glyphs[n].index, + CAIRO_SCALED_GLYPH_INFO_METRICS, + NULL, /* foreground color */ + &scaled_glyph); + if (unlikely (status)) + break; + + if (scaled_glyph->dev_private_key == ctx) + continue; + + status = _cairo_scaled_glyph_lookup (scaled_font, + glyphs[n].index, + CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE, + NULL, /* foreground color */ + &scaled_glyph); + if (_cairo_status_is_error (status)) + break; + + if (status == CAIRO_STATUS_SUCCESS) { + if (! have_glyph_prologue) { + status = _emit_scaled_glyph_prologue (surface, scaled_font); + if (unlikely (status)) + break; + + have_glyph_prologue = TRUE; + } + + status = _emit_scaled_glyph_vector (surface, + scaled_font, font_private, + scaled_glyph); + if (unlikely (status)) + break; + + continue; + } + + status = _cairo_scaled_glyph_lookup (scaled_font, + glyphs[n].index, + CAIRO_SCALED_GLYPH_INFO_SURFACE, + NULL, /* foreground color */ + &scaled_glyph); + if (_cairo_status_is_error (status)) + break; + + if (status == CAIRO_STATUS_SUCCESS) { + if (! have_glyph_prologue) { + status = _emit_scaled_glyph_prologue (surface, scaled_font); + if (unlikely (status)) + break; + + have_glyph_prologue = TRUE; + } + + status = _emit_scaled_glyph_bitmap (surface, + scaled_font, + font_private, + scaled_glyph); + if (unlikely (status)) + break; + + continue; + } + } + _cairo_scaled_font_thaw_cache (scaled_font); + + if (have_glyph_prologue) { + _cairo_output_stream_puts (to_context (surface)->stream, "pop pop\n"); + } + + return status; +} + +static void +to_octal (int value, char *buf, size_t size) +{ + do { + buf[--size] = '0' + (value & 7); + value >>= 3; + } while (size); +} + +static void +_emit_string_literal (cairo_script_surface_t *surface, + const char *utf8, int len) +{ + cairo_script_context_t *ctx = to_context (surface); + char c; + const char *end; + + _cairo_output_stream_puts (ctx->stream, "("); + + if (utf8 == NULL) { + end = utf8; + } else { + if (len < 0) + len = strlen (utf8); + end = utf8 + len; + } + + while (utf8 < end) { + switch ((c = *utf8++)) { + case '\n': + c = 'n'; + goto ESCAPED_CHAR; + case '\r': + c = 'r'; + goto ESCAPED_CHAR; + case '\t': + c = 't'; + goto ESCAPED_CHAR; + case '\b': + c = 'b'; + goto ESCAPED_CHAR; + case '\f': + c = 'f'; + goto ESCAPED_CHAR; + case '\\': + case '(': + case ')': +ESCAPED_CHAR: + _cairo_output_stream_printf (ctx->stream, "\\%c", c); + break; + default: + if (_cairo_isprint(c)) { + _cairo_output_stream_printf (ctx->stream, "%c", c); + } else { + char buf[4] = { '\\' }; + + to_octal (c, buf+1, 3); + _cairo_output_stream_write (ctx->stream, buf, 4); + } + break; + } + } + _cairo_output_stream_puts (ctx->stream, ")"); +} + +static cairo_int_status_t +_cairo_script_surface_show_text_glyphs (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const char *utf8, + int utf8_len, + cairo_glyph_t *glyphs, + int num_glyphs, + const cairo_text_cluster_t *clusters, + int num_clusters, + cairo_text_cluster_flags_t backward, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip) +{ + cairo_script_surface_t *surface = abstract_surface; + cairo_script_context_t *ctx = to_context (surface); + cairo_script_font_t *font_private; + cairo_scaled_glyph_t *scaled_glyph; + cairo_matrix_t matrix; + cairo_status_t status; + double x, y, ix, iy; + int n; + cairo_output_stream_t *base85_stream = NULL; + + status = active (surface); + if (unlikely (status)) + return status; + + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) + goto BAIL; + + status = _emit_context (surface); + if (unlikely (status)) + goto BAIL; + + status = _emit_source (surface, op, source); + if (unlikely (status)) + goto BAIL; + + status = _emit_scaled_font (surface, scaled_font); + if (unlikely (status)) + goto BAIL; + + status = _emit_operator (surface, op); + if (unlikely (status)) + goto BAIL; + + status = _emit_scaled_glyphs (surface, scaled_font, glyphs, num_glyphs); + if (unlikely (status)) + goto BAIL; + + /* (utf8) [cx cy [glyphs]] [clusters] backward show_text_glyphs */ + /* [cx cy [glyphs]] show_glyphs */ + + if (utf8 != NULL && clusters != NULL) { + _emit_string_literal (surface, utf8, utf8_len); + _cairo_output_stream_puts (ctx->stream, " "); + } + + matrix = surface->cr.current_ctm; + status = cairo_matrix_invert (&matrix); + assert (status == CAIRO_STATUS_SUCCESS); + + ix = x = glyphs[0].x; + iy = y = glyphs[0].y; + cairo_matrix_transform_point (&matrix, &ix, &iy); + ix -= scaled_font->font_matrix.x0; + iy -= scaled_font->font_matrix.y0; + + _cairo_scaled_font_freeze_cache (scaled_font); + font_private = _cairo_script_font_get (ctx, scaled_font); + + _cairo_output_stream_printf (ctx->stream, + "[%f %f ", + ix, iy); + + for (n = 0; n < num_glyphs; n++) { + if (font_private->has_sfnt) { + if (glyphs[n].index > 256) + break; + } else { + status = _cairo_scaled_glyph_lookup (scaled_font, + glyphs[n].index, + CAIRO_SCALED_GLYPH_INFO_METRICS, + NULL, /* foreground color */ + &scaled_glyph); + if (unlikely (status)) { + _cairo_scaled_font_thaw_cache (scaled_font); + goto BAIL; + } + + if ((uintptr_t)scaled_glyph->dev_private > 256) + break; + } + } + + if (n == num_glyphs) { + _cairo_output_stream_puts (ctx->stream, "<~"); + base85_stream = _cairo_base85_stream_create (ctx->stream); + } else + _cairo_output_stream_puts (ctx->stream, "["); + + for (n = 0; n < num_glyphs; n++) { + double dx, dy; + + status = _cairo_scaled_glyph_lookup (scaled_font, + glyphs[n].index, + CAIRO_SCALED_GLYPH_INFO_METRICS, + NULL, /* foreground color */ + &scaled_glyph); + if (unlikely (status)) { + _cairo_scaled_font_thaw_cache (scaled_font); + goto BAIL; + } + + if (fabs (glyphs[n].x - x) > 1e-5 || fabs (glyphs[n].y - y) > 1e-5) { + if (fabs (glyphs[n].y - y) < 1e-5) { + if (base85_stream != NULL) { + status = _cairo_output_stream_destroy (base85_stream); + if (unlikely (status)) { + base85_stream = NULL; + break; + } + + _cairo_output_stream_printf (ctx->stream, + "~> %f <~", glyphs[n].x - x); + base85_stream = _cairo_base85_stream_create (ctx->stream); + } else { + _cairo_output_stream_printf (ctx->stream, + " ] %f [ ", glyphs[n].x - x); + } + + x = glyphs[n].x; + } else { + ix = x = glyphs[n].x; + iy = y = glyphs[n].y; + cairo_matrix_transform_point (&matrix, &ix, &iy); + ix -= scaled_font->font_matrix.x0; + iy -= scaled_font->font_matrix.y0; + if (base85_stream != NULL) { + status = _cairo_output_stream_destroy (base85_stream); + if (unlikely (status)) { + base85_stream = NULL; + break; + } + + _cairo_output_stream_printf (ctx->stream, + "~> %f %f <~", + ix, iy); + base85_stream = _cairo_base85_stream_create (ctx->stream); + } else { + _cairo_output_stream_printf (ctx->stream, + " ] %f %f [ ", + ix, iy); + } + } + } + if (base85_stream != NULL) { + uint8_t c; + + if (font_private->has_sfnt) + c = glyphs[n].index; + else + c = (uint8_t) (uintptr_t) scaled_glyph->dev_private; + + _cairo_output_stream_write (base85_stream, &c, 1); + } else { + if (font_private->has_sfnt) + _cairo_output_stream_printf (ctx->stream, " %lu", + glyphs[n].index); + else + _cairo_output_stream_printf (ctx->stream, " %lu", + (long unsigned) (uintptr_t)scaled_glyph->dev_private); + } + + dx = scaled_glyph->metrics.x_advance; + dy = scaled_glyph->metrics.y_advance; + cairo_matrix_transform_distance (&scaled_font->ctm, &dx, &dy); + x += dx; + y += dy; + } + _cairo_scaled_font_thaw_cache (scaled_font); + + if (base85_stream != NULL) { + cairo_status_t status2; + + status2 = _cairo_output_stream_destroy (base85_stream); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; + + _cairo_output_stream_printf (ctx->stream, "~>"); + } else { + _cairo_output_stream_puts (ctx->stream, " ]"); + } + if (unlikely (status)) + return status; + + if (utf8 != NULL && clusters != NULL) { + for (n = 0; n < num_clusters; n++) { + if (clusters[n].num_bytes > UCHAR_MAX || + clusters[n].num_glyphs > UCHAR_MAX) + { + break; + } + } + + if (n < num_clusters) { + _cairo_output_stream_puts (ctx->stream, "] [ "); + for (n = 0; n < num_clusters; n++) { + _cairo_output_stream_printf (ctx->stream, + "%d %d ", + clusters[n].num_bytes, + clusters[n].num_glyphs); + } + _cairo_output_stream_puts (ctx->stream, "]"); + } + else + { + _cairo_output_stream_puts (ctx->stream, "] <~"); + base85_stream = _cairo_base85_stream_create (ctx->stream); + for (n = 0; n < num_clusters; n++) { + uint8_t c[2]; + c[0] = clusters[n].num_bytes; + c[1] = clusters[n].num_glyphs; + _cairo_output_stream_write (base85_stream, c, 2); + } + status = _cairo_output_stream_destroy (base85_stream); + if (unlikely (status)) + goto BAIL; + + _cairo_output_stream_puts (ctx->stream, "~>"); + } + + _cairo_output_stream_printf (ctx->stream, + " //%s show-text-glyphs\n", + _direction_to_string (backward)); + } else { + _cairo_output_stream_puts (ctx->stream, + "] show-glyphs\n"); + } + + inactive (surface); + + if (_cairo_surface_wrapper_is_active (&surface->wrapper)){ + return _cairo_surface_wrapper_show_text_glyphs (&surface->wrapper, + op, source, 0, + utf8, utf8_len, + glyphs, num_glyphs, + clusters, num_clusters, + backward, + scaled_font, + clip); + } + + return CAIRO_STATUS_SUCCESS; + +BAIL: + inactive (surface); + return status; +} + +static cairo_bool_t +_cairo_script_surface_get_extents (void *abstract_surface, + cairo_rectangle_int_t *rectangle) +{ + cairo_script_surface_t *surface = abstract_surface; + + if (_cairo_surface_wrapper_is_active (&surface->wrapper)) { + return _cairo_surface_wrapper_get_extents (&surface->wrapper, + rectangle); + } + + if (surface->width < 0 || surface->height < 0) + return FALSE; + + rectangle->x = 0; + rectangle->y = 0; + rectangle->width = surface->width; + rectangle->height = surface->height; + + return TRUE; +} + +static const cairo_surface_backend_t +_cairo_script_surface_backend = { + CAIRO_SURFACE_TYPE_SCRIPT, + _cairo_script_surface_finish, + + _cairo_default_context_create, + + _cairo_script_surface_create_similar, + NULL, /* create similar image */ + NULL, /* map to image */ + NULL, /* unmap image */ + + _cairo_script_surface_source, + _cairo_script_surface_acquire_source_image, + _cairo_script_surface_release_source_image, + _cairo_script_surface_snapshot, + + _cairo_script_surface_copy_page, + _cairo_script_surface_show_page, + + _cairo_script_surface_get_extents, + NULL, /* get_font_options */ + + NULL, /* flush */ + NULL, /* mark_dirty_rectangle */ + + _cairo_script_surface_paint, + _cairo_script_surface_mask, + _cairo_script_surface_stroke, + _cairo_script_surface_fill, + NULL, /* fill/stroke */ + NULL, /* glyphs */ + _cairo_script_surface_has_show_text_glyphs, + _cairo_script_surface_show_text_glyphs +}; + +static void +_cairo_script_implicit_context_init (cairo_script_implicit_context_t *cr) +{ + cr->current_operator = CAIRO_GSTATE_OPERATOR_DEFAULT; + cr->current_fill_rule = CAIRO_GSTATE_FILL_RULE_DEFAULT; + cr->current_tolerance = CAIRO_GSTATE_TOLERANCE_DEFAULT; + cr->current_antialias = CAIRO_ANTIALIAS_DEFAULT; + _cairo_stroke_style_init (&cr->current_style); + _cairo_pattern_init_solid (&cr->current_source.solid, + CAIRO_COLOR_BLACK); + _cairo_path_fixed_init (&cr->current_path); + cairo_matrix_init_identity (&cr->current_ctm); + cairo_matrix_init_identity (&cr->current_stroke_matrix); + cairo_matrix_init_identity (&cr->current_font_matrix); + _cairo_font_options_init_default (&cr->current_font_options); + cr->current_scaled_font = NULL; + cr->has_clip = FALSE; +} + +static void +_cairo_script_implicit_context_reset (cairo_script_implicit_context_t *cr) +{ + free (cr->current_style.dash); + cr->current_style.dash = NULL; + + _cairo_pattern_fini (&cr->current_source.base); + _cairo_path_fixed_fini (&cr->current_path); + + _cairo_script_implicit_context_init (cr); +} + +static cairo_script_surface_t * +_cairo_script_surface_create_internal (cairo_script_context_t *ctx, + cairo_content_t content, + cairo_rectangle_t *extents, + cairo_surface_t *passthrough) +{ + cairo_script_surface_t *surface; + + if (unlikely (ctx == NULL)) + return (cairo_script_surface_t *) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NULL_POINTER)); + + surface = _cairo_calloc (sizeof (cairo_script_surface_t)); + if (unlikely (surface == NULL)) + return (cairo_script_surface_t *) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + _cairo_surface_init (&surface->base, + &_cairo_script_surface_backend, + &ctx->base, + content, + TRUE); /* is_vector */ + + _cairo_surface_wrapper_init (&surface->wrapper, passthrough); + + _cairo_surface_clipper_init (&surface->clipper, + _cairo_script_surface_clipper_intersect_clip_path); + + surface->width = surface->height = -1; + if (extents) { + surface->width = extents->width; + surface->height = extents->height; + cairo_surface_set_device_offset (&surface->base, + -extents->x, -extents->y); + } + + surface->emitted = FALSE; + surface->defined = FALSE; + surface->active = FALSE; + surface->operand.type = SURFACE; + cairo_list_init (&surface->operand.link); + + _cairo_script_implicit_context_init (&surface->cr); + + return surface; +} + +static const cairo_device_backend_t _cairo_script_device_backend = { + CAIRO_DEVICE_TYPE_SCRIPT, + + NULL, NULL, /* lock, unlock */ + + _device_flush, /* flush */ + _device_finish, /* finish */ + _device_destroy +}; + +cairo_device_t * +_cairo_script_context_create_internal (cairo_output_stream_t *stream) +{ + cairo_script_context_t *ctx; + + ctx = _cairo_calloc (sizeof (cairo_script_context_t)); + if (unlikely (ctx == NULL)) + return _cairo_device_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + memset (ctx, 0, sizeof (cairo_script_context_t)); + + _cairo_device_init (&ctx->base, &_cairo_script_device_backend); + + cairo_list_init (&ctx->operands); + cairo_list_init (&ctx->deferred); + ctx->stream = stream; + ctx->mode = CAIRO_SCRIPT_MODE_ASCII; + + cairo_list_init (&ctx->fonts); + cairo_list_init (&ctx->defines); + + ctx->attach_snapshots = TRUE; + + return &ctx->base; +} + +void +_cairo_script_context_attach_snapshots (cairo_device_t *device, + cairo_bool_t enable) +{ + cairo_script_context_t *ctx; + + ctx = (cairo_script_context_t *) device; + ctx->attach_snapshots = enable; +} + +static cairo_device_t * +_cairo_script_context_create (cairo_output_stream_t *stream) +{ + cairo_script_context_t *ctx; + + ctx = (cairo_script_context_t *) + _cairo_script_context_create_internal (stream); + if (unlikely (ctx->base.status)) + return &ctx->base; + + ctx->owns_stream = TRUE; + _cairo_output_stream_puts (ctx->stream, "%!CairoScript\n"); + return &ctx->base; +} + +/** + * cairo_script_create: + * @filename: the name (path) of the file to write the script to + * + * Creates a output device for emitting the script, used when + * creating the individual surfaces. + * + * Return value: a pointer to the newly created device. The caller + * owns the surface and should call cairo_device_destroy() when done + * with it. + * + * This function always returns a valid pointer, but it will return a + * pointer to a "nil" device if an error such as out of memory + * occurs. You can use cairo_device_status() to check for this. + * + * Since: 1.12 + **/ +cairo_device_t * +cairo_script_create (const char *filename) +{ + cairo_output_stream_t *stream; + cairo_status_t status; + + stream = _cairo_output_stream_create_for_filename (filename); + if ((status = _cairo_output_stream_get_status (stream))) + return _cairo_device_create_in_error (status); + + return _cairo_script_context_create (stream); +} + +/** + * cairo_script_create_for_stream: + * @write_func: callback function passed the bytes written to the script + * @closure: user data to be passed to the callback + * + * Creates a output device for emitting the script, used when + * creating the individual surfaces. + * + * Return value: a pointer to the newly created device. The caller + * owns the surface and should call cairo_device_destroy() when done + * with it. + * + * This function always returns a valid pointer, but it will return a + * pointer to a "nil" device if an error such as out of memory + * occurs. You can use cairo_device_status() to check for this. + * + * Since: 1.12 + **/ +cairo_device_t * +cairo_script_create_for_stream (cairo_write_func_t write_func, + void *closure) +{ + cairo_output_stream_t *stream; + cairo_status_t status; + + stream = _cairo_output_stream_create (write_func, NULL, closure); + if ((status = _cairo_output_stream_get_status (stream))) + return _cairo_device_create_in_error (status); + + return _cairo_script_context_create (stream); +} + +/** + * cairo_script_write_comment: + * @script: the script (output device) + * @comment: the string to emit + * @len:the length of the string to write, or -1 to use strlen() + * + * Emit a string verbatim into the script. + * + * Since: 1.12 + **/ +void +cairo_script_write_comment (cairo_device_t *script, + const char *comment, + int len) +{ + cairo_script_context_t *context = (cairo_script_context_t *) script; + + if (len < 0) + len = strlen (comment); + + _cairo_output_stream_puts (context->stream, "% "); + _cairo_output_stream_write (context->stream, comment, len); + _cairo_output_stream_puts (context->stream, "\n"); +} + +/** + * cairo_script_set_mode: + * @script: The script (output device) + * @mode: the new mode + * + * Change the output mode of the script + * + * Since: 1.12 + **/ +void +cairo_script_set_mode (cairo_device_t *script, + cairo_script_mode_t mode) +{ + cairo_script_context_t *context = (cairo_script_context_t *) script; + + context->mode = mode; +} + +/** + * cairo_script_get_mode: + * @script: The script (output device) to query + * + * Queries the script for its current output mode. + * + * Return value: the current output mode of the script + * + * Since: 1.12 + **/ +cairo_script_mode_t +cairo_script_get_mode (cairo_device_t *script) +{ + cairo_script_context_t *context = (cairo_script_context_t *) script; + + return context->mode; +} + +/** + * cairo_script_surface_create: + * @script: the script (output device) + * @content: the content of the surface + * @width: width in pixels + * @height: height in pixels + * + * Create a new surface that will emit its rendering through @script + * + * Return value: a pointer to the newly created surface. The caller + * owns the surface and should call cairo_surface_destroy() when done + * with it. + * + * This function always returns a valid pointer, but it will return a + * pointer to a "nil" surface if an error such as out of memory + * occurs. You can use cairo_surface_status() to check for this. + * + * Since: 1.12 + **/ +cairo_surface_t * +cairo_script_surface_create (cairo_device_t *script, + cairo_content_t content, + double width, + double height) +{ + cairo_rectangle_t *extents, r; + + if (unlikely (script->backend->type != CAIRO_DEVICE_TYPE_SCRIPT)) + return _cairo_surface_create_in_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH); + + if (unlikely (script->status)) + return _cairo_surface_create_in_error (script->status); + + extents = NULL; + if (width > 0 && height > 0) { + r.x = r.y = 0; + r.width = width; + r.height = height; + extents = &r; + } + return &_cairo_script_surface_create_internal ((cairo_script_context_t *) script, + content, extents, + NULL)->base; +} + +/** + * cairo_script_surface_create_for_target: + * @script: the script (output device) + * @target: a target surface to wrap + * + * Create a pxoy surface that will render to @target and record + * the operations to @device. + * + * Return value: a pointer to the newly created surface. The caller + * owns the surface and should call cairo_surface_destroy() when done + * with it. + * + * This function always returns a valid pointer, but it will return a + * pointer to a "nil" surface if an error such as out of memory + * occurs. You can use cairo_surface_status() to check for this. + * + * Since: 1.12 + **/ +cairo_surface_t * +cairo_script_surface_create_for_target (cairo_device_t *script, + cairo_surface_t *target) +{ + cairo_rectangle_int_t extents; + cairo_rectangle_t rect, *r; + + if (unlikely (script->backend->type != CAIRO_DEVICE_TYPE_SCRIPT)) + return _cairo_surface_create_in_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH); + + if (unlikely (script->status)) + return _cairo_surface_create_in_error (script->status); + + if (unlikely (target->status)) + return _cairo_surface_create_in_error (target->status); + + r = NULL; + if (_cairo_surface_get_extents (target, &extents)) { + rect.x = rect.y = 0; + rect.width = extents.width; + rect.height = extents.height; + r= ▭ + } + return &_cairo_script_surface_create_internal ((cairo_script_context_t *) script, + target->content, r, + target)->base; +} + +/** + * cairo_script_from_recording_surface: + * @script: the script (output device) + * @recording_surface: the recording surface to replay + * + * Converts the record operations in @recording_surface into a script. + * + * Return value: #CAIRO_STATUS_SUCCESS on successful completion or an error code. + * + * Since: 1.12 + **/ +cairo_status_t +cairo_script_from_recording_surface (cairo_device_t *script, + cairo_surface_t *recording_surface) +{ + cairo_rectangle_t r, *extents; + cairo_surface_t *surface; + cairo_status_t status; + + if (unlikely (script->backend->type != CAIRO_DEVICE_TYPE_SCRIPT)) + return _cairo_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH); + + if (unlikely (script->status)) + return _cairo_error (script->status); + + if (unlikely (recording_surface->status)) + return recording_surface->status; + + if (unlikely (! _cairo_surface_is_recording (recording_surface))) + return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + + extents = NULL; + if (_cairo_recording_surface_get_bounds (recording_surface, &r)) + extents = &r; + + surface = &_cairo_script_surface_create_internal ((cairo_script_context_t *) script, + recording_surface->content, + extents, + NULL)->base; + if (unlikely (surface->status)) + return surface->status; + + status = _cairo_recording_surface_replay (recording_surface, surface); + cairo_surface_destroy (surface); + + return status; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-script.h b/local/recipes/libs/cairo/source/src/cairo-script.h new file mode 100644 index 0000000000..b5a8cf32d0 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-script.h @@ -0,0 +1,98 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2008 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Chris Wilson + * + * Contributor(s): + * Chris Wilson + */ + +#ifndef CAIRO_SCRIPT_H +#define CAIRO_SCRIPT_H + +#include "cairo.h" + +#if CAIRO_HAS_SCRIPT_SURFACE + +CAIRO_BEGIN_DECLS + +/** + * cairo_script_mode_t: + * @CAIRO_SCRIPT_MODE_ASCII: the output will be in readable text (default). (Since 1.12) + * @CAIRO_SCRIPT_MODE_BINARY: the output will use byte codes. (Since 1.12) + * + * A set of script output variants. + * + * Since: 1.12 + **/ +typedef enum { + CAIRO_SCRIPT_MODE_ASCII, + CAIRO_SCRIPT_MODE_BINARY +} cairo_script_mode_t; + +cairo_public cairo_device_t * +cairo_script_create (const char *filename); + +cairo_public cairo_device_t * +cairo_script_create_for_stream (cairo_write_func_t write_func, + void *closure); + +cairo_public void +cairo_script_write_comment (cairo_device_t *script, + const char *comment, + int len); + +cairo_public void +cairo_script_set_mode (cairo_device_t *script, + cairo_script_mode_t mode); + +cairo_public cairo_script_mode_t +cairo_script_get_mode (cairo_device_t *script); + +cairo_public cairo_surface_t * +cairo_script_surface_create (cairo_device_t *script, + cairo_content_t content, + double width, + double height); + +cairo_public cairo_surface_t * +cairo_script_surface_create_for_target (cairo_device_t *script, + cairo_surface_t *target); + +cairo_public cairo_status_t +cairo_script_from_recording_surface (cairo_device_t *script, + cairo_surface_t *recording_surface); + +CAIRO_END_DECLS + +#else /*CAIRO_HAS_SCRIPT_SURFACE*/ +# error Cairo was not compiled with support for the CairoScript backend +#endif /*CAIRO_HAS_SCRIPT_SURFACE*/ + +#endif /*CAIRO_SCRIPT_H*/ diff --git a/local/recipes/libs/cairo/source/src/cairo-shape-mask-compositor.c b/local/recipes/libs/cairo/source/src/cairo-shape-mask-compositor.c new file mode 100644 index 0000000000..0f4918603d --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-shape-mask-compositor.c @@ -0,0 +1,340 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Chris Wilson + */ + +#include "cairoint.h" + +#include "cairo-compositor-private.h" +#include "cairo-clip-private.h" +#include "cairo-pattern-private.h" +#include "cairo-surface-private.h" +#include "cairo-surface-offset-private.h" + +static cairo_int_status_t +_cairo_shape_mask_compositor_stroke (const cairo_compositor_t *_compositor, + cairo_composite_rectangles_t *extents, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_surface_t *mask; + cairo_surface_pattern_t pattern; + cairo_int_status_t status; + cairo_clip_t *clip; + + if (! extents->is_bounded) + return CAIRO_INT_STATUS_UNSUPPORTED; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + mask = _cairo_surface_create_scratch (extents->surface, + CAIRO_CONTENT_ALPHA, + extents->bounded.width, + extents->bounded.height, + NULL); + if (unlikely (mask->status)) + return mask->status; + + clip = extents->clip; + if (! _cairo_clip_is_region (clip)) + clip = _cairo_clip_copy_region (clip); + + if (! mask->is_clear) { + status = _cairo_surface_offset_paint (mask, + extents->bounded.x, + extents->bounded.y, + CAIRO_OPERATOR_CLEAR, + &_cairo_pattern_clear.base, + clip); + if (unlikely (status)) + goto error; + } + + status = _cairo_surface_offset_stroke (mask, + extents->bounded.x, + extents->bounded.y, + CAIRO_OPERATOR_ADD, + &_cairo_pattern_white.base, + path, style, ctm, ctm_inverse, + tolerance, antialias, + clip); + if (unlikely (status)) + goto error; + + if (clip != extents->clip) { + status = _cairo_clip_combine_with_surface (extents->clip, mask, + extents->bounded.x, + extents->bounded.y); + if (unlikely (status)) + goto error; + } + + _cairo_pattern_init_for_surface (&pattern, mask); + cairo_matrix_init_translate (&pattern.base.matrix, + -extents->bounded.x, + -extents->bounded.y); + pattern.base.filter = CAIRO_FILTER_NEAREST; + pattern.base.extend = CAIRO_EXTEND_NONE; + if (extents->op == CAIRO_OPERATOR_SOURCE) { + status = _cairo_surface_mask (extents->surface, + CAIRO_OPERATOR_DEST_OUT, + &_cairo_pattern_white.base, + &pattern.base, + clip); + if (status == CAIRO_INT_STATUS_SUCCESS) { + status = _cairo_surface_mask (extents->surface, + CAIRO_OPERATOR_ADD, + &extents->source_pattern.base, + &pattern.base, + clip); + } + } else { + status = _cairo_surface_mask (extents->surface, + extents->op, + &extents->source_pattern.base, + &pattern.base, + clip); + } + _cairo_pattern_fini (&pattern.base); + +error: + cairo_surface_destroy (mask); + if (clip != extents->clip) + _cairo_clip_destroy (clip); + return status; +} + +static cairo_int_status_t +_cairo_shape_mask_compositor_fill (const cairo_compositor_t *_compositor, + cairo_composite_rectangles_t *extents, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_surface_t *mask; + cairo_surface_pattern_t pattern; + cairo_int_status_t status; + cairo_clip_t *clip; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + if (! extents->is_bounded) + return CAIRO_INT_STATUS_UNSUPPORTED; + + mask = _cairo_surface_create_scratch (extents->surface, + CAIRO_CONTENT_ALPHA, + extents->bounded.width, + extents->bounded.height, + NULL); + if (unlikely (mask->status)) + return mask->status; + + clip = extents->clip; + if (! _cairo_clip_is_region (clip)) + clip = _cairo_clip_copy_region (clip); + + if (! mask->is_clear) { + status = _cairo_surface_offset_paint (mask, + extents->bounded.x, + extents->bounded.y, + CAIRO_OPERATOR_CLEAR, + &_cairo_pattern_clear.base, + clip); + if (unlikely (status)) + goto error; + } + + status = _cairo_surface_offset_fill (mask, + extents->bounded.x, + extents->bounded.y, + CAIRO_OPERATOR_ADD, + &_cairo_pattern_white.base, + path, fill_rule, tolerance, antialias, + clip); + if (unlikely (status)) + goto error; + + if (clip != extents->clip) { + status = _cairo_clip_combine_with_surface (extents->clip, mask, + extents->bounded.x, + extents->bounded.y); + if (unlikely (status)) + goto error; + } + + _cairo_pattern_init_for_surface (&pattern, mask); + cairo_matrix_init_translate (&pattern.base.matrix, + -extents->bounded.x, + -extents->bounded.y); + pattern.base.filter = CAIRO_FILTER_NEAREST; + pattern.base.extend = CAIRO_EXTEND_NONE; + if (extents->op == CAIRO_OPERATOR_SOURCE) { + status = _cairo_surface_mask (extents->surface, + CAIRO_OPERATOR_DEST_OUT, + &_cairo_pattern_white.base, + &pattern.base, + clip); + if (status == CAIRO_INT_STATUS_SUCCESS) { + status = _cairo_surface_mask (extents->surface, + CAIRO_OPERATOR_ADD, + &extents->source_pattern.base, + &pattern.base, + clip); + } + } else { + status = _cairo_surface_mask (extents->surface, + extents->op, + &extents->source_pattern.base, + &pattern.base, + clip); + } + _cairo_pattern_fini (&pattern.base); + +error: + if (clip != extents->clip) + _cairo_clip_destroy (clip); + cairo_surface_destroy (mask); + return status; +} + +static cairo_int_status_t +_cairo_shape_mask_compositor_glyphs (const cairo_compositor_t *_compositor, + cairo_composite_rectangles_t *extents, + cairo_scaled_font_t *scaled_font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_bool_t overlap) +{ + cairo_surface_t *mask; + cairo_surface_pattern_t pattern; + cairo_int_status_t status; + cairo_clip_t *clip; + + if (! extents->is_bounded) + return CAIRO_INT_STATUS_UNSUPPORTED; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + mask = _cairo_surface_create_scratch (extents->surface, + CAIRO_CONTENT_ALPHA, + extents->bounded.width, + extents->bounded.height, + NULL); + if (unlikely (mask->status)) + return mask->status; + + clip = extents->clip; + if (! _cairo_clip_is_region (clip)) + clip = _cairo_clip_copy_region (clip); + + if (! mask->is_clear) { + status = _cairo_surface_offset_paint (mask, + extents->bounded.x, + extents->bounded.y, + CAIRO_OPERATOR_CLEAR, + &_cairo_pattern_clear.base, + clip); + if (unlikely (status)) + goto error; + } + + status = _cairo_surface_offset_glyphs (mask, + extents->bounded.x, + extents->bounded.y, + CAIRO_OPERATOR_ADD, + &_cairo_pattern_white.base, + scaled_font, glyphs, num_glyphs, + clip); + if (unlikely (status)) + goto error; + + if (clip != extents->clip) { + status = _cairo_clip_combine_with_surface (extents->clip, mask, + extents->bounded.x, + extents->bounded.y); + if (unlikely (status)) + goto error; + } + + _cairo_pattern_init_for_surface (&pattern, mask); + cairo_matrix_init_translate (&pattern.base.matrix, + -extents->bounded.x, + -extents->bounded.y); + pattern.base.filter = CAIRO_FILTER_NEAREST; + pattern.base.extend = CAIRO_EXTEND_NONE; + if (extents->op == CAIRO_OPERATOR_SOURCE) { + status = _cairo_surface_mask (extents->surface, + CAIRO_OPERATOR_DEST_OUT, + &_cairo_pattern_white.base, + &pattern.base, + clip); + if (status == CAIRO_INT_STATUS_SUCCESS) { + status = _cairo_surface_mask (extents->surface, + CAIRO_OPERATOR_ADD, + &extents->source_pattern.base, + &pattern.base, + clip); + } + } else { + status = _cairo_surface_mask (extents->surface, + extents->op, + &extents->source_pattern.base, + &pattern.base, + clip); + } + _cairo_pattern_fini (&pattern.base); + +error: + if (clip != extents->clip) + _cairo_clip_destroy (clip); + cairo_surface_destroy (mask); + return status; +} + +void +_cairo_shape_mask_compositor_init (cairo_compositor_t *compositor, + const cairo_compositor_t *delegate) +{ + compositor->delegate = delegate; + + compositor->paint = NULL; + compositor->mask = NULL; + compositor->fill = _cairo_shape_mask_compositor_fill; + compositor->stroke = _cairo_shape_mask_compositor_stroke; + compositor->glyphs = _cairo_shape_mask_compositor_glyphs; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-slope-private.h b/local/recipes/libs/cairo/source/src/cairo-slope-private.h new file mode 100644 index 0000000000..6a58c9f456 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-slope-private.h @@ -0,0 +1,72 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + */ + +#ifndef _CAIRO_SLOPE_PRIVATE_H +#define _CAIRO_SLOPE_PRIVATE_H + +#include "cairo-types-private.h" +#include "cairo-fixed-private.h" + +static inline void +_cairo_slope_init (cairo_slope_t *slope, + const cairo_point_t *a, + const cairo_point_t *b) +{ + slope->dx = b->x - a->x; + slope->dy = b->y - a->y; +} + +static inline cairo_bool_t +_cairo_slope_equal (const cairo_slope_t *a, const cairo_slope_t *b) +{ + return _cairo_int64_eq (_cairo_int32x32_64_mul (a->dy, b->dx), + _cairo_int32x32_64_mul (b->dy, a->dx)); +} + +static inline cairo_bool_t +_cairo_slope_backwards (const cairo_slope_t *a, const cairo_slope_t *b) +{ + return _cairo_int64_negative (_cairo_int64_add (_cairo_int32x32_64_mul (a->dx, b->dx), + _cairo_int32x32_64_mul (a->dy, b->dy))); +} + +cairo_private int +_cairo_slope_compare (const cairo_slope_t *a, + const cairo_slope_t *b) cairo_pure; + + +#endif /* _CAIRO_SLOPE_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-slope.c b/local/recipes/libs/cairo/source/src/cairo-slope.c new file mode 100644 index 0000000000..cc5f30cb0b --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-slope.c @@ -0,0 +1,99 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + */ + +#include "cairoint.h" + +#include "cairo-slope-private.h" + +/* Compare two slopes. Slope angles begin at 0 in the direction of the + positive X axis and increase in the direction of the positive Y + axis. + + This function always compares the slope vectors based on the + smaller angular difference between them, (that is based on an + angular difference that is strictly less than pi). To break ties + when comparing slope vectors with an angular difference of exactly + pi, the vector with a positive dx (or positive dy if dx's are zero) + is considered to be more positive than the other. + + Also, all slope vectors with both dx==0 and dy==0 are considered + equal and more positive than any non-zero vector. + + < 0 => a less positive than b + == 0 => a equal to b + > 0 => a more positive than b +*/ +int +_cairo_slope_compare (const cairo_slope_t *a, const cairo_slope_t *b) +{ + cairo_int64_t ady_bdx = _cairo_int32x32_64_mul (a->dy, b->dx); + cairo_int64_t bdy_adx = _cairo_int32x32_64_mul (b->dy, a->dx); + int cmp; + + cmp = _cairo_int64_cmp (ady_bdx, bdy_adx); + if (cmp) + return cmp; + + /* special-case zero vectors. the intended logic here is: + * zero vectors all compare equal, and more positive than any + * non-zero vector. + */ + if (a->dx == 0 && a->dy == 0 && b->dx == 0 && b->dy ==0) + return 0; + if (a->dx == 0 && a->dy == 0) + return 1; + if (b->dx == 0 && b->dy ==0) + return -1; + + /* Finally, we're looking at two vectors that are either equal or + * that differ by exactly pi. We can identify the "differ by pi" + * case by looking for a change in sign in either dx or dy between + * a and b. + * + * And in these cases, we eliminate the ambiguity by reducing the angle + * of b by an infinitesimally small amount, (that is, 'a' will + * always be considered less than 'b'). + */ + if ((a->dx ^ b->dx) < 0 || (a->dy ^ b->dy) < 0) { + if (a->dx > 0 || (a->dx == 0 && a->dy > 0)) + return -1; + else + return +1; + } + + /* Finally, for identical slopes, we obviously return 0. */ + return 0; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-spans-compositor-private.h b/local/recipes/libs/cairo/source/src/cairo-spans-compositor-private.h new file mode 100644 index 0000000000..0babebd26b --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-spans-compositor-private.h @@ -0,0 +1,111 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Chris Wilson + */ + +#ifndef CAIRO_SPANS_COMPOSITOR_PRIVATE_H +#define CAIRO_SPANS_COMPOSITOR_PRIVATE_H + +#include "cairo-compositor-private.h" +#include "cairo-types-private.h" +#include "cairo-spans-private.h" + +CAIRO_BEGIN_DECLS + +typedef struct _cairo_abstract_span_renderer { + cairo_span_renderer_t base; + char data[4096]; +} cairo_abstract_span_renderer_t; + +struct cairo_spans_compositor { + cairo_compositor_t base; + + unsigned int flags; +#define CAIRO_SPANS_COMPOSITOR_HAS_LERP 0x1 + + /* pixel-aligned fast paths */ + cairo_int_status_t (*fill_boxes) (void *surface, + cairo_operator_t op, + const cairo_color_t *color, + cairo_boxes_t *boxes); + + cairo_int_status_t (*draw_image_boxes) (void *surface, + cairo_image_surface_t *image, + cairo_boxes_t *boxes, + int dx, int dy); + + cairo_int_status_t (*copy_boxes) (void *surface, + cairo_surface_t *src, + cairo_boxes_t *boxes, + const cairo_rectangle_int_t *extents, + int dx, int dy); + + cairo_surface_t * (*pattern_to_surface) (cairo_surface_t *dst, + const cairo_pattern_t *pattern, + cairo_bool_t is_mask, + const cairo_rectangle_int_t *extents, + const cairo_rectangle_int_t *sample, + int *src_x, int *src_y); + + cairo_int_status_t (*composite_boxes) (void *surface, + cairo_operator_t op, + cairo_surface_t *source, + cairo_surface_t *mask, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + cairo_boxes_t *boxes, + const cairo_rectangle_int_t *extents); + + /* general shape masks using a span renderer */ + cairo_int_status_t (*renderer_init) (cairo_abstract_span_renderer_t *renderer, + const cairo_composite_rectangles_t *extents, + cairo_antialias_t antialias, + cairo_bool_t needs_clip); + + void (*renderer_fini) (cairo_abstract_span_renderer_t *renderer, + cairo_int_status_t status); +}; + +cairo_private void +_cairo_spans_compositor_init (cairo_spans_compositor_t *compositor, + const cairo_compositor_t *delegate); + +CAIRO_END_DECLS + +#endif /* CAIRO_SPANS_COMPOSITOR_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-spans-compositor.c b/local/recipes/libs/cairo/source/src/cairo-spans-compositor.c new file mode 100644 index 0000000000..50c92b25c5 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-spans-compositor.c @@ -0,0 +1,1201 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Joonas Pihlaja + * Chris Wilson + */ + +#include "cairoint.h" + +#include "cairo-compositor-private.h" +#include "cairo-clip-inline.h" +#include "cairo-clip-private.h" +#include "cairo-image-surface-private.h" +#include "cairo-paginated-private.h" +#include "cairo-pattern-inline.h" +#include "cairo-region-private.h" +#include "cairo-recording-surface-inline.h" +#include "cairo-spans-compositor-private.h" +#include "cairo-surface-subsurface-private.h" +#include "cairo-surface-snapshot-private.h" +#include "cairo-surface-observer-private.h" + +typedef struct { + cairo_polygon_t *polygon; + cairo_fill_rule_t fill_rule; + cairo_antialias_t antialias; +} composite_spans_info_t; + +static cairo_int_status_t +composite_polygon (const cairo_spans_compositor_t *compositor, + cairo_composite_rectangles_t *extents, + cairo_polygon_t *polygon, + cairo_fill_rule_t fill_rule, + cairo_antialias_t antialias); + +static cairo_int_status_t +composite_boxes (const cairo_spans_compositor_t *compositor, + cairo_composite_rectangles_t *extents, + cairo_boxes_t *boxes); + +static cairo_int_status_t +clip_and_composite_polygon (const cairo_spans_compositor_t *compositor, + cairo_composite_rectangles_t *extents, + cairo_polygon_t *polygon, + cairo_fill_rule_t fill_rule, + cairo_antialias_t antialias); +static cairo_surface_t * +get_clip_surface (const cairo_spans_compositor_t *compositor, + cairo_surface_t *dst, + const cairo_clip_t *clip, + const cairo_rectangle_int_t *extents) +{ + cairo_composite_rectangles_t composite; + cairo_surface_t *surface; + cairo_box_t box; + cairo_polygon_t polygon; + const cairo_clip_path_t *clip_path; + cairo_antialias_t antialias; + cairo_fill_rule_t fill_rule; + cairo_int_status_t status; + + assert (clip->path); + + surface = _cairo_surface_create_scratch (dst, + CAIRO_CONTENT_ALPHA, + extents->width, + extents->height, + CAIRO_COLOR_TRANSPARENT); + + _cairo_box_from_rectangle (&box, extents); + _cairo_polygon_init (&polygon, &box, 1); + + clip_path = clip->path; + status = _cairo_path_fixed_fill_to_polygon (&clip_path->path, + clip_path->tolerance, + &polygon); + if (unlikely (status)) + goto cleanup_polygon; + + polygon.num_limits = 0; + + antialias = clip_path->antialias; + fill_rule = clip_path->fill_rule; + + if (clip->boxes) { + cairo_polygon_t intersect; + cairo_boxes_t tmp; + + _cairo_boxes_init_for_array (&tmp, clip->boxes, clip->num_boxes); + status= _cairo_polygon_init_boxes (&intersect, &tmp); + if (unlikely (status)) + goto cleanup_polygon; + + status = _cairo_polygon_intersect (&polygon, fill_rule, + &intersect, CAIRO_FILL_RULE_WINDING); + _cairo_polygon_fini (&intersect); + + if (unlikely (status)) + goto cleanup_polygon; + + fill_rule = CAIRO_FILL_RULE_WINDING; + } + + polygon.limits = NULL; + polygon.num_limits = 0; + + clip_path = clip_path->prev; + while (clip_path) { + if (clip_path->antialias == antialias) { + cairo_polygon_t next; + + _cairo_polygon_init (&next, NULL, 0); + status = _cairo_path_fixed_fill_to_polygon (&clip_path->path, + clip_path->tolerance, + &next); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) + status = _cairo_polygon_intersect (&polygon, fill_rule, + &next, clip_path->fill_rule); + _cairo_polygon_fini (&next); + if (unlikely (status)) + goto cleanup_polygon; + + fill_rule = CAIRO_FILL_RULE_WINDING; + } + + clip_path = clip_path->prev; + } + + _cairo_polygon_translate (&polygon, -extents->x, -extents->y); + status = _cairo_composite_rectangles_init_for_polygon (&composite, surface, + CAIRO_OPERATOR_ADD, + &_cairo_pattern_white.base, + &polygon, + NULL); + if (unlikely (status)) + goto cleanup_polygon; + + status = composite_polygon (compositor, &composite, + &polygon, fill_rule, antialias); + _cairo_composite_rectangles_fini (&composite); + _cairo_polygon_fini (&polygon); + if (unlikely (status)) + goto error; + + _cairo_polygon_init (&polygon, &box, 1); + + clip_path = clip->path; + antialias = clip_path->antialias == CAIRO_ANTIALIAS_DEFAULT ? CAIRO_ANTIALIAS_NONE : CAIRO_ANTIALIAS_DEFAULT; + clip_path = clip_path->prev; + while (clip_path) { + if (clip_path->antialias == antialias) { + if (polygon.num_edges == 0) { + status = _cairo_path_fixed_fill_to_polygon (&clip_path->path, + clip_path->tolerance, + &polygon); + + fill_rule = clip_path->fill_rule; + polygon.limits = NULL; + polygon.num_limits = 0; + } else { + cairo_polygon_t next; + + _cairo_polygon_init (&next, NULL, 0); + status = _cairo_path_fixed_fill_to_polygon (&clip_path->path, + clip_path->tolerance, + &next); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) + status = _cairo_polygon_intersect (&polygon, fill_rule, + &next, clip_path->fill_rule); + _cairo_polygon_fini (&next); + fill_rule = CAIRO_FILL_RULE_WINDING; + } + if (unlikely (status)) + goto error; + } + + clip_path = clip_path->prev; + } + + if (polygon.num_edges) { + _cairo_polygon_translate (&polygon, -extents->x, -extents->y); + status = _cairo_composite_rectangles_init_for_polygon (&composite, surface, + CAIRO_OPERATOR_IN, + &_cairo_pattern_white.base, + &polygon, + NULL); + if (unlikely (status)) + goto cleanup_polygon; + + status = composite_polygon (compositor, &composite, + &polygon, fill_rule, antialias); + _cairo_composite_rectangles_fini (&composite); + _cairo_polygon_fini (&polygon); + if (unlikely (status)) + goto error; + } + + return surface; + +cleanup_polygon: + _cairo_polygon_fini (&polygon); +error: + cairo_surface_destroy (surface); + return _cairo_int_surface_create_in_error (status); +} + +static cairo_int_status_t +fixup_unbounded_mask (const cairo_spans_compositor_t *compositor, + const cairo_composite_rectangles_t *extents, + cairo_boxes_t *boxes) +{ + cairo_composite_rectangles_t composite; + cairo_surface_t *clip; + cairo_int_status_t status; + + TRACE((stderr, "%s\n", __FUNCTION__)); + + clip = get_clip_surface (compositor, extents->surface, extents->clip, + &extents->unbounded); + if (unlikely (clip->status)) { + if ((cairo_int_status_t)clip->status == CAIRO_INT_STATUS_NOTHING_TO_DO) + return CAIRO_STATUS_SUCCESS; + + return clip->status; + } + + status = _cairo_composite_rectangles_init_for_boxes (&composite, + extents->surface, + CAIRO_OPERATOR_CLEAR, + &_cairo_pattern_clear.base, + boxes, + NULL); + if (unlikely (status)) + goto cleanup_clip; + + _cairo_pattern_init_for_surface (&composite.mask_pattern.surface, clip); + composite.mask_pattern.base.filter = CAIRO_FILTER_NEAREST; + composite.mask_pattern.base.extend = CAIRO_EXTEND_NONE; + + status = composite_boxes (compositor, &composite, boxes); + + _cairo_pattern_fini (&composite.mask_pattern.base); + _cairo_composite_rectangles_fini (&composite); + +cleanup_clip: + cairo_surface_destroy (clip); + return status; +} + +static cairo_int_status_t +fixup_unbounded_polygon (const cairo_spans_compositor_t *compositor, + const cairo_composite_rectangles_t *extents, + cairo_boxes_t *boxes) +{ + cairo_polygon_t polygon, intersect; + cairo_composite_rectangles_t composite; + cairo_fill_rule_t fill_rule; + cairo_antialias_t antialias; + cairo_int_status_t status; + + TRACE((stderr, "%s\n", __FUNCTION__)); + + /* Can we treat the clip as a regular clear-polygon and use it to fill? */ + status = _cairo_clip_get_polygon (extents->clip, &polygon, + &fill_rule, &antialias); + if (status == CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + status= _cairo_polygon_init_boxes (&intersect, boxes); + if (unlikely (status)) + goto cleanup_polygon; + + status = _cairo_polygon_intersect (&polygon, fill_rule, + &intersect, CAIRO_FILL_RULE_WINDING); + _cairo_polygon_fini (&intersect); + + if (unlikely (status)) + goto cleanup_polygon; + + status = _cairo_composite_rectangles_init_for_polygon (&composite, + extents->surface, + CAIRO_OPERATOR_CLEAR, + &_cairo_pattern_clear.base, + &polygon, + NULL); + if (unlikely (status)) + goto cleanup_polygon; + + status = composite_polygon (compositor, &composite, + &polygon, fill_rule, antialias); + + _cairo_composite_rectangles_fini (&composite); +cleanup_polygon: + _cairo_polygon_fini (&polygon); + + return status; +} + +static cairo_int_status_t +fixup_unbounded_boxes (const cairo_spans_compositor_t *compositor, + const cairo_composite_rectangles_t *extents, + cairo_boxes_t *boxes) +{ + cairo_boxes_t tmp, clear; + cairo_box_t box; + cairo_int_status_t status; + + assert (boxes->is_pixel_aligned); + + TRACE ((stderr, "%s\n", __FUNCTION__)); + if (extents->bounded.width == extents->unbounded.width && + extents->bounded.height == extents->unbounded.height) + { + return CAIRO_STATUS_SUCCESS; + } + + /* subtract the drawn boxes from the unbounded area */ + _cairo_boxes_init (&clear); + + box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width); + box.p1.y = _cairo_fixed_from_int (extents->unbounded.y); + box.p2.x = _cairo_fixed_from_int (extents->unbounded.x); + box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height); + + if (boxes->num_boxes) { + _cairo_boxes_init (&tmp); + + status = _cairo_boxes_add (&tmp, CAIRO_ANTIALIAS_DEFAULT, &box); + assert (status == CAIRO_INT_STATUS_SUCCESS); + + tmp.chunks.next = &boxes->chunks; + tmp.num_boxes += boxes->num_boxes; + + status = _cairo_bentley_ottmann_tessellate_boxes (&tmp, + CAIRO_FILL_RULE_WINDING, + &clear); + tmp.chunks.next = NULL; + if (unlikely (status)) + goto error; + } else { + box.p1.x = _cairo_fixed_from_int (extents->unbounded.x); + box.p2.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width); + + status = _cairo_boxes_add (&clear, CAIRO_ANTIALIAS_DEFAULT, &box); + assert (status == CAIRO_INT_STATUS_SUCCESS); + } + + /* If we have a clip polygon, we need to intersect with that as well */ + if (extents->clip->path) { + status = fixup_unbounded_polygon (compositor, extents, &clear); + if (status == CAIRO_INT_STATUS_UNSUPPORTED) + status = fixup_unbounded_mask (compositor, extents, &clear); + } else { + /* Otherwise just intersect with the clip boxes */ + if (extents->clip->num_boxes) { + _cairo_boxes_init_for_array (&tmp, + extents->clip->boxes, + extents->clip->num_boxes); + status = _cairo_boxes_intersect (&clear, &tmp, &clear); + if (unlikely (status)) + goto error; + } + + if (clear.is_pixel_aligned) { + status = compositor->fill_boxes (extents->surface, + CAIRO_OPERATOR_CLEAR, + CAIRO_COLOR_TRANSPARENT, + &clear); + } else { + cairo_composite_rectangles_t composite; + + status = _cairo_composite_rectangles_init_for_boxes (&composite, + extents->surface, + CAIRO_OPERATOR_CLEAR, + &_cairo_pattern_clear.base, + &clear, + NULL); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { + status = composite_boxes (compositor, &composite, &clear); + _cairo_composite_rectangles_fini (&composite); + } + } + } + +error: + _cairo_boxes_fini (&clear); + return status; +} + +static cairo_surface_t * +unwrap_source (const cairo_pattern_t *pattern) +{ + cairo_rectangle_int_t limit; + + return _cairo_pattern_get_source ((cairo_surface_pattern_t *)pattern, + &limit); +} + +static cairo_bool_t +is_recording_pattern (const cairo_pattern_t *pattern) +{ + cairo_surface_t *surface; + + if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE) + return FALSE; + + surface = ((const cairo_surface_pattern_t *) pattern)->surface; + return _cairo_surface_is_recording (surface); +} + +static cairo_bool_t +recording_pattern_contains_sample (const cairo_pattern_t *pattern, + const cairo_rectangle_int_t *sample) +{ + cairo_recording_surface_t *surface; + + if (! is_recording_pattern (pattern)) + return FALSE; + + if (pattern->extend == CAIRO_EXTEND_NONE) + return TRUE; + + surface = (cairo_recording_surface_t *) unwrap_source (pattern); + if (surface->unbounded) + return TRUE; + + return _cairo_rectangle_contains_rectangle (&surface->extents, sample); +} + +static cairo_bool_t +op_reduces_to_source (const cairo_composite_rectangles_t *extents, + cairo_bool_t no_mask) +{ + if (extents->op == CAIRO_OPERATOR_SOURCE) + return TRUE; + + if (extents->surface->is_clear) + return extents->op == CAIRO_OPERATOR_OVER || extents->op == CAIRO_OPERATOR_ADD; + + if (no_mask && extents->op == CAIRO_OPERATOR_OVER) + return _cairo_pattern_is_opaque (&extents->source_pattern.base, + &extents->source_sample_area); + + return FALSE; +} + +static cairo_status_t +upload_boxes (const cairo_spans_compositor_t *compositor, + const cairo_composite_rectangles_t *extents, + cairo_boxes_t *boxes) +{ + cairo_surface_t *dst = extents->surface; + const cairo_surface_pattern_t *source = &extents->source_pattern.surface; + cairo_surface_t *src; + cairo_rectangle_int_t limit; + cairo_int_status_t status; + int tx, ty; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + src = _cairo_pattern_get_source(source, &limit); + if (!(src->type == CAIRO_SURFACE_TYPE_IMAGE || src->type == dst->type)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (! _cairo_matrix_is_integer_translation (&source->base.matrix, &tx, &ty)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* Check that the data is entirely within the image */ + if (extents->bounded.x + tx < limit.x || extents->bounded.y + ty < limit.y) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (extents->bounded.x + extents->bounded.width + tx > limit.x + limit.width || + extents->bounded.y + extents->bounded.height + ty > limit.y + limit.height) + return CAIRO_INT_STATUS_UNSUPPORTED; + + tx += limit.x; + ty += limit.y; + + if (src->type == CAIRO_SURFACE_TYPE_IMAGE) + status = compositor->draw_image_boxes (dst, + (cairo_image_surface_t *)src, + boxes, tx, ty); + else + status = compositor->copy_boxes (dst, src, boxes, &extents->bounded, + tx, ty); + + return status; +} + +static cairo_bool_t +_clip_is_region (const cairo_clip_t *clip) +{ + int i; + + if (clip->is_region) + return TRUE; + + if (clip->path) + return FALSE; + + for (i = 0; i < clip->num_boxes; i++) { + const cairo_box_t *b = &clip->boxes[i]; + if (!_cairo_fixed_is_integer (b->p1.x | b->p1.y | b->p2.x | b->p2.y)) + return FALSE; + } + + return TRUE; +} + +static cairo_int_status_t +composite_aligned_boxes (const cairo_spans_compositor_t *compositor, + const cairo_composite_rectangles_t *extents, + cairo_boxes_t *boxes) +{ + cairo_surface_t *dst = extents->surface; + cairo_operator_t op = extents->op; + const cairo_pattern_t *source = &extents->source_pattern.base; + cairo_int_status_t status; + cairo_bool_t need_clip_mask = ! _clip_is_region (extents->clip); + cairo_bool_t op_is_source; + cairo_bool_t no_mask; + cairo_bool_t inplace; + + TRACE ((stderr, "%s: need_clip_mask=%d, is-bounded=%d\n", + __FUNCTION__, need_clip_mask, extents->is_bounded)); + if (need_clip_mask && ! extents->is_bounded) { + TRACE ((stderr, "%s: unsupported clip\n", __FUNCTION__)); + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + no_mask = extents->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID && + CAIRO_COLOR_IS_OPAQUE (&extents->mask_pattern.solid.color); + op_is_source = op_reduces_to_source (extents, no_mask); + inplace = ! need_clip_mask && op_is_source && no_mask; + + TRACE ((stderr, "%s: op-is-source=%d [op=%d], no-mask=%d, inplace=%d\n", + __FUNCTION__, op_is_source, op, no_mask, inplace)); + + if (op == CAIRO_OPERATOR_SOURCE && (need_clip_mask || ! no_mask)) { + /* SOURCE with a mask is actually a LERP in cairo semantics */ + if ((compositor->flags & CAIRO_SPANS_COMPOSITOR_HAS_LERP) == 0) { + TRACE ((stderr, "%s: unsupported lerp\n", __FUNCTION__)); + return CAIRO_INT_STATUS_UNSUPPORTED; + } + } + + /* Are we just copying a recording surface? */ + if (inplace && + recording_pattern_contains_sample (&extents->source_pattern.base, + &extents->source_sample_area)) + { + cairo_clip_t *recording_clip; + const cairo_pattern_t *source = &extents->source_pattern.base; + const cairo_matrix_t *m; + cairo_matrix_t matrix; + + /* XXX could also do tiling repeat modes... */ + + /* first clear the area about to be overwritten */ + if (! dst->is_clear) { + status = compositor->fill_boxes (dst, + CAIRO_OPERATOR_CLEAR, + CAIRO_COLOR_TRANSPARENT, + boxes); + if (unlikely (status)) + return status; + + dst->is_clear = TRUE; + } + + m = &source->matrix; + if (_cairo_surface_has_device_transform (dst)) { + cairo_matrix_multiply (&matrix, + &source->matrix, + &dst->device_transform); + m = &matrix; + } + + recording_clip = _cairo_clip_from_boxes (boxes); + status = _cairo_recording_surface_replay_with_clip (unwrap_source (source), + m, dst, recording_clip); + _cairo_clip_destroy (recording_clip); + + return status; + } + + status = CAIRO_INT_STATUS_UNSUPPORTED; + if (! need_clip_mask && no_mask && source->type == CAIRO_PATTERN_TYPE_SOLID) { + const cairo_color_t *color; + + color = &((cairo_solid_pattern_t *) source)->color; + if (op_is_source) + op = CAIRO_OPERATOR_SOURCE; + status = compositor->fill_boxes (dst, op, color, boxes); + } else if (inplace && source->type == CAIRO_PATTERN_TYPE_SURFACE) { + status = upload_boxes (compositor, extents, boxes); + } + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + cairo_surface_t *src; + cairo_surface_t *mask = NULL; + int src_x, src_y; + int mask_x = 0, mask_y = 0; + + /* All typical cases will have been resolved before now... */ + if (need_clip_mask) { + mask = get_clip_surface (compositor, dst, extents->clip, + &extents->bounded); + if (unlikely (mask->status)) + return mask->status; + + mask_x = -extents->bounded.x; + mask_y = -extents->bounded.y; + } + + /* XXX but this is still ugly */ + if (! no_mask) { + src = compositor->pattern_to_surface (dst, + &extents->mask_pattern.base, + TRUE, + &extents->bounded, + &extents->mask_sample_area, + &src_x, &src_y); + if (unlikely (src->status)) { + cairo_surface_destroy (mask); + return src->status; + } + + if (mask != NULL) { + status = compositor->composite_boxes (mask, CAIRO_OPERATOR_IN, + src, NULL, + src_x, src_y, + 0, 0, + mask_x, mask_y, + boxes, &extents->bounded); + + cairo_surface_destroy (src); + } else { + mask = src; + mask_x = src_x; + mask_y = src_y; + } + } + + src = compositor->pattern_to_surface (dst, source, FALSE, + &extents->bounded, + &extents->source_sample_area, + &src_x, &src_y); + if (likely (src->status == CAIRO_STATUS_SUCCESS)) { + status = compositor->composite_boxes (dst, op, src, mask, + src_x, src_y, + mask_x, mask_y, + 0, 0, + boxes, &extents->bounded); + cairo_surface_destroy (src); + } else + status = src->status; + + cairo_surface_destroy (mask); + } + + if (status == CAIRO_INT_STATUS_SUCCESS && ! extents->is_bounded) + status = fixup_unbounded_boxes (compositor, extents, boxes); + + return status; +} + +static cairo_bool_t +composite_needs_clip (const cairo_composite_rectangles_t *composite, + const cairo_box_t *extents) +{ + return !_cairo_clip_contains_box (composite->clip, extents); +} + +static cairo_int_status_t +composite_boxes (const cairo_spans_compositor_t *compositor, + cairo_composite_rectangles_t *extents, + cairo_boxes_t *boxes) +{ + cairo_abstract_span_renderer_t renderer; + cairo_rectangular_scan_converter_t converter; + const struct _cairo_boxes_chunk *chunk; + cairo_int_status_t status; + cairo_box_t box; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + _cairo_box_from_rectangle (&box, &extents->unbounded); + if (composite_needs_clip (extents, &box)) { + TRACE ((stderr, "%s: unsupported clip\n", __FUNCTION__)); + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + _cairo_rectangular_scan_converter_init (&converter, &extents->unbounded); + for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { + const cairo_box_t *box = chunk->base; + int i; + + for (i = 0; i < chunk->count; i++) { + status = _cairo_rectangular_scan_converter_add_box (&converter, &box[i], 1); + if (unlikely (status)) + goto cleanup_converter; + } + } + + status = compositor->renderer_init (&renderer, extents, + CAIRO_ANTIALIAS_DEFAULT, FALSE); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) + status = converter.base.generate (&converter.base, &renderer.base); + compositor->renderer_fini (&renderer, status); + +cleanup_converter: + converter.base.destroy (&converter.base); + return status; +} + +static cairo_int_status_t +composite_polygon (const cairo_spans_compositor_t *compositor, + cairo_composite_rectangles_t *extents, + cairo_polygon_t *polygon, + cairo_fill_rule_t fill_rule, + cairo_antialias_t antialias) +{ + cairo_abstract_span_renderer_t renderer; + cairo_scan_converter_t *converter; + cairo_bool_t needs_clip; + cairo_int_status_t status; + + if (extents->is_bounded) + needs_clip = extents->clip->path != NULL; + else + needs_clip = !_clip_is_region (extents->clip) || extents->clip->num_boxes > 1; + TRACE ((stderr, "%s - needs_clip=%d\n", __FUNCTION__, needs_clip)); + if (needs_clip) { + TRACE ((stderr, "%s: unsupported clip\n", __FUNCTION__)); + return CAIRO_INT_STATUS_UNSUPPORTED; + converter = _cairo_clip_tor_scan_converter_create (extents->clip, + polygon, + fill_rule, antialias); + } else { + const cairo_rectangle_int_t *r = &extents->unbounded; + + if (antialias == CAIRO_ANTIALIAS_FAST) { + converter = _cairo_tor22_scan_converter_create (r->x, r->y, + r->x + r->width, + r->y + r->height, + fill_rule, antialias); + status = _cairo_tor22_scan_converter_add_polygon (converter, polygon); + } else if (antialias == CAIRO_ANTIALIAS_NONE) { + converter = _cairo_mono_scan_converter_create (r->x, r->y, + r->x + r->width, + r->y + r->height, + fill_rule); + status = _cairo_mono_scan_converter_add_polygon (converter, polygon); + } else { + converter = _cairo_tor_scan_converter_create (r->x, r->y, + r->x + r->width, + r->y + r->height, + fill_rule, antialias); + status = _cairo_tor_scan_converter_add_polygon (converter, polygon); + } + } + if (unlikely (status)) + goto cleanup_converter; + + status = compositor->renderer_init (&renderer, extents, + antialias, needs_clip); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) + status = converter->generate (converter, &renderer.base); + compositor->renderer_fini (&renderer, status); + +cleanup_converter: + converter->destroy (converter); + return status; +} + +static cairo_int_status_t +trim_extents_to_boxes (cairo_composite_rectangles_t *extents, + cairo_boxes_t *boxes) +{ + cairo_box_t box; + + _cairo_boxes_extents (boxes, &box); + return _cairo_composite_rectangles_intersect_mask_extents (extents, &box); +} + +static cairo_int_status_t +trim_extents_to_polygon (cairo_composite_rectangles_t *extents, + cairo_polygon_t *polygon) +{ + return _cairo_composite_rectangles_intersect_mask_extents (extents, + &polygon->extents); +} + +static cairo_int_status_t +clip_and_composite_boxes (const cairo_spans_compositor_t *compositor, + cairo_composite_rectangles_t *extents, + cairo_boxes_t *boxes) +{ + cairo_int_status_t status; + cairo_polygon_t polygon; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + status = trim_extents_to_boxes (extents, boxes); + if (unlikely (status)) + return status; + + if (boxes->num_boxes == 0) { + if (extents->is_bounded) + return CAIRO_STATUS_SUCCESS; + + return fixup_unbounded_boxes (compositor, extents, boxes); + } + + /* Can we reduce drawing through a clip-mask to simply drawing the clip? */ + if (extents->clip->path != NULL && extents->is_bounded) { + cairo_polygon_t polygon; + cairo_fill_rule_t fill_rule; + cairo_antialias_t antialias; + cairo_clip_t *clip; + + clip = _cairo_clip_copy (extents->clip); + clip = _cairo_clip_intersect_boxes (clip, boxes); + if (_cairo_clip_is_all_clipped (clip)) + return CAIRO_INT_STATUS_NOTHING_TO_DO; + + status = _cairo_clip_get_polygon (clip, &polygon, + &fill_rule, &antialias); + _cairo_clip_path_destroy (clip->path); + clip->path = NULL; + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { + cairo_clip_t *saved_clip = extents->clip; + extents->clip = clip; + + status = clip_and_composite_polygon (compositor, extents, &polygon, + fill_rule, antialias); + + clip = extents->clip; + extents->clip = saved_clip; + + _cairo_polygon_fini (&polygon); + } + _cairo_clip_destroy (clip); + + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + } + + if (boxes->is_pixel_aligned) { + status = composite_aligned_boxes (compositor, extents, boxes); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + } + + status = composite_boxes (compositor, extents, boxes); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + status = _cairo_polygon_init_boxes (&polygon, boxes); + if (unlikely (status)) + return status; + + status = composite_polygon (compositor, extents, &polygon, + CAIRO_FILL_RULE_WINDING, + CAIRO_ANTIALIAS_DEFAULT); + _cairo_polygon_fini (&polygon); + + return status; +} + +static cairo_int_status_t +clip_and_composite_polygon (const cairo_spans_compositor_t *compositor, + cairo_composite_rectangles_t *extents, + cairo_polygon_t *polygon, + cairo_fill_rule_t fill_rule, + cairo_antialias_t antialias) +{ + cairo_int_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + /* XXX simply uses polygon limits.point extemities, tessellation? */ + status = trim_extents_to_polygon (extents, polygon); + if (unlikely (status)) + return status; + + if (_cairo_polygon_is_empty (polygon)) { + cairo_boxes_t boxes; + + if (extents->is_bounded) + return CAIRO_STATUS_SUCCESS; + + _cairo_boxes_init (&boxes); + extents->bounded.width = extents->bounded.height = 0; + return fixup_unbounded_boxes (compositor, extents, &boxes); + } + + if (extents->is_bounded && extents->clip->path) { + cairo_polygon_t clipper; + cairo_antialias_t clip_antialias; + cairo_fill_rule_t clip_fill_rule; + + TRACE((stderr, "%s - combining shape with clip polygon\n", + __FUNCTION__)); + + status = _cairo_clip_get_polygon (extents->clip, + &clipper, + &clip_fill_rule, + &clip_antialias); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { + cairo_clip_t *old_clip; + + if (clip_antialias == antialias) { + status = _cairo_polygon_intersect (polygon, fill_rule, + &clipper, clip_fill_rule); + _cairo_polygon_fini (&clipper); + if (unlikely (status)) + return status; + + old_clip = extents->clip; + extents->clip = _cairo_clip_copy_region (extents->clip); + _cairo_clip_destroy (old_clip); + + status = trim_extents_to_polygon (extents, polygon); + if (unlikely (status)) + return status; + + fill_rule = CAIRO_FILL_RULE_WINDING; + } else { + _cairo_polygon_fini (&clipper); + } + } + } + + return composite_polygon (compositor, extents, + polygon, fill_rule, antialias); +} + +/* high-level compositor interface */ + +static cairo_int_status_t +_cairo_spans_compositor_paint (const cairo_compositor_t *_compositor, + cairo_composite_rectangles_t *extents) +{ + const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor; + cairo_boxes_t boxes; + cairo_int_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + _cairo_clip_steal_boxes (extents->clip, &boxes); + status = clip_and_composite_boxes (compositor, extents, &boxes); + _cairo_clip_unsteal_boxes (extents->clip, &boxes); + + return status; +} + +static cairo_int_status_t +_cairo_spans_compositor_mask (const cairo_compositor_t *_compositor, + cairo_composite_rectangles_t *extents) +{ + const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor; + cairo_int_status_t status; + cairo_boxes_t boxes; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + _cairo_clip_steal_boxes (extents->clip, &boxes); + status = clip_and_composite_boxes (compositor, extents, &boxes); + _cairo_clip_unsteal_boxes (extents->clip, &boxes); + + return status; +} + +static cairo_int_status_t +_cairo_spans_compositor_stroke (const cairo_compositor_t *_compositor, + cairo_composite_rectangles_t *extents, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias) +{ + const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor; + cairo_int_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + TRACE_ (_cairo_debug_print_path (stderr, path)); + TRACE_ (_cairo_debug_print_clip (stderr, extents->clip)); + + status = CAIRO_INT_STATUS_UNSUPPORTED; + if (_cairo_path_fixed_stroke_is_rectilinear (path)) { + cairo_boxes_t boxes; + + _cairo_boxes_init (&boxes); + if (! _cairo_clip_contains_rectangle (extents->clip, &extents->mask)) + _cairo_boxes_limit (&boxes, + extents->clip->boxes, + extents->clip->num_boxes); + + status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path, + style, + ctm, + antialias, + &boxes); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) + status = clip_and_composite_boxes (compositor, extents, &boxes); + _cairo_boxes_fini (&boxes); + } + + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + cairo_polygon_t polygon; + cairo_box_t limits; + cairo_fill_rule_t fill_rule = CAIRO_FILL_RULE_WINDING; + + if (! _cairo_rectangle_contains_rectangle (&extents->unbounded, + &extents->mask)) + { + if (extents->clip->num_boxes == 1) { + _cairo_polygon_init (&polygon, extents->clip->boxes, 1); + } else { + _cairo_box_from_rectangle (&limits, &extents->unbounded); + _cairo_polygon_init (&polygon, &limits, 1); + } + } + else + { + _cairo_polygon_init (&polygon, NULL, 0); + } + status = _cairo_path_fixed_stroke_to_polygon (path, + style, + ctm, ctm_inverse, + tolerance, + &polygon); + TRACE_ (_cairo_debug_print_polygon (stderr, &polygon)); + polygon.num_limits = 0; + + if (status == CAIRO_INT_STATUS_SUCCESS && extents->clip->num_boxes > 1) { + status = _cairo_polygon_intersect_with_boxes (&polygon, &fill_rule, + extents->clip->boxes, + extents->clip->num_boxes); + } + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { + cairo_clip_t *saved_clip = extents->clip; + + if (extents->is_bounded) { + extents->clip = _cairo_clip_copy_path (extents->clip); + extents->clip = _cairo_clip_intersect_box(extents->clip, + &polygon.extents); + } + + status = clip_and_composite_polygon (compositor, extents, &polygon, + fill_rule, antialias); + + if (extents->is_bounded) { + _cairo_clip_destroy (extents->clip); + extents->clip = saved_clip; + } + } + _cairo_polygon_fini (&polygon); + } + + return status; +} + +static cairo_int_status_t +_cairo_spans_compositor_fill (const cairo_compositor_t *_compositor, + cairo_composite_rectangles_t *extents, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor; + cairo_int_status_t status; + + TRACE((stderr, "%s op=%d, antialias=%d\n", __FUNCTION__, extents->op, antialias)); + + status = CAIRO_INT_STATUS_UNSUPPORTED; + if (_cairo_path_fixed_fill_is_rectilinear (path)) { + cairo_boxes_t boxes; + + TRACE((stderr, "%s - rectilinear\n", __FUNCTION__)); + + _cairo_boxes_init (&boxes); + if (! _cairo_clip_contains_rectangle (extents->clip, &extents->mask)) + _cairo_boxes_limit (&boxes, + extents->clip->boxes, + extents->clip->num_boxes); + status = _cairo_path_fixed_fill_rectilinear_to_boxes (path, + fill_rule, + antialias, + &boxes); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) + status = clip_and_composite_boxes (compositor, extents, &boxes); + _cairo_boxes_fini (&boxes); + } + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + cairo_polygon_t polygon; + cairo_box_t limits; + + TRACE((stderr, "%s - polygon\n", __FUNCTION__)); + + if (! _cairo_rectangle_contains_rectangle (&extents->unbounded, + &extents->mask)) + { + TRACE((stderr, "%s - clipping to bounds\n", __FUNCTION__)); + if (extents->clip->num_boxes == 1) { + _cairo_polygon_init (&polygon, extents->clip->boxes, 1); + } else { + _cairo_box_from_rectangle (&limits, &extents->unbounded); + _cairo_polygon_init (&polygon, &limits, 1); + } + } + else + { + _cairo_polygon_init (&polygon, NULL, 0); + } + + status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon); + TRACE_ (_cairo_debug_print_polygon (stderr, &polygon)); + polygon.num_limits = 0; + + if (status == CAIRO_INT_STATUS_SUCCESS && extents->clip->num_boxes > 1) { + TRACE((stderr, "%s - polygon intersect with %d clip boxes\n", + __FUNCTION__, extents->clip->num_boxes)); + status = _cairo_polygon_intersect_with_boxes (&polygon, &fill_rule, + extents->clip->boxes, + extents->clip->num_boxes); + } + TRACE_ (_cairo_debug_print_polygon (stderr, &polygon)); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { + cairo_clip_t *saved_clip = extents->clip; + + if (extents->is_bounded) { + TRACE((stderr, "%s - polygon discard clip boxes\n", + __FUNCTION__)); + extents->clip = _cairo_clip_copy_path (extents->clip); + extents->clip = _cairo_clip_intersect_box(extents->clip, + &polygon.extents); + } + + status = clip_and_composite_polygon (compositor, extents, &polygon, + fill_rule, antialias); + + if (extents->is_bounded) { + _cairo_clip_destroy (extents->clip); + extents->clip = saved_clip; + } + } + _cairo_polygon_fini (&polygon); + + TRACE((stderr, "%s - polygon status=%d\n", __FUNCTION__, status)); + } + + return status; +} + +void +_cairo_spans_compositor_init (cairo_spans_compositor_t *compositor, + const cairo_compositor_t *delegate) +{ + compositor->base.delegate = delegate; + + compositor->base.paint = _cairo_spans_compositor_paint; + compositor->base.mask = _cairo_spans_compositor_mask; + compositor->base.fill = _cairo_spans_compositor_fill; + compositor->base.stroke = _cairo_spans_compositor_stroke; + compositor->base.glyphs = NULL; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-spans-private.h b/local/recipes/libs/cairo/source/src/cairo-spans-private.h new file mode 100644 index 0000000000..653183fb1c --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-spans-private.h @@ -0,0 +1,210 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright (c) 2008 M Joonas Pihlaja + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef CAIRO_SPANS_PRIVATE_H +#define CAIRO_SPANS_PRIVATE_H +#include "cairo-types-private.h" +#include "cairo-compiler-private.h" + +/* Number of bits of precision used for alpha. */ +#define CAIRO_SPANS_UNIT_COVERAGE_BITS 8 +#define CAIRO_SPANS_UNIT_COVERAGE ((1 << CAIRO_SPANS_UNIT_COVERAGE_BITS)-1) + +/* A structure representing an open-ended horizontal span of constant + * pixel coverage. */ +typedef struct _cairo_half_open_span { + int32_t x; /* The inclusive x-coordinate of the start of the span. */ + uint8_t coverage; /* The pixel coverage for the pixels to the right. */ + uint8_t inverse; /* between regular mask and clip */ +} cairo_half_open_span_t; + +/* Span renderer interface. Instances of renderers are provided by + * surfaces if they want to composite spans instead of trapezoids. */ +typedef struct _cairo_span_renderer cairo_span_renderer_t; +struct _cairo_span_renderer { + /* Private status variable. */ + cairo_status_t status; + + /* Called to destroy the renderer. */ + cairo_destroy_func_t destroy; + + /* Render the spans on row y of the destination by whatever compositing + * method is required. */ + cairo_status_t + (*render_rows) (void *abstract_renderer, + int y, int height, + const cairo_half_open_span_t *coverages, + unsigned num_coverages); + + /* Called after all rows have been rendered to perform whatever + * final rendering step is required. This function is called just + * once before the renderer is destroyed. */ + cairo_status_t (*finish) (void *abstract_renderer); +}; + +/* Scan converter interface. */ +typedef struct _cairo_scan_converter cairo_scan_converter_t; +struct _cairo_scan_converter { + /* Destroy this scan converter. */ + cairo_destroy_func_t destroy; + + /* Generates coverage spans for rows for the added edges and calls + * the renderer function for each row. After generating spans the + * only valid thing to do with the converter is to destroy it. */ + cairo_status_t (*generate) (void *abstract_converter, + cairo_span_renderer_t *renderer); + + /* Private status. Read with _cairo_scan_converter_status(). */ + cairo_status_t status; +}; + +/* Scan converter constructors. */ + +cairo_private cairo_scan_converter_t * +_cairo_tor_scan_converter_create (int xmin, + int ymin, + int xmax, + int ymax, + cairo_fill_rule_t fill_rule, + cairo_antialias_t antialias); +cairo_private cairo_status_t +_cairo_tor_scan_converter_add_polygon (void *converter, + const cairo_polygon_t *polygon); + +cairo_private cairo_scan_converter_t * +_cairo_tor22_scan_converter_create (int xmin, + int ymin, + int xmax, + int ymax, + cairo_fill_rule_t fill_rule, + cairo_antialias_t antialias); +cairo_private cairo_status_t +_cairo_tor22_scan_converter_add_polygon (void *converter, + const cairo_polygon_t *polygon); + +cairo_private cairo_scan_converter_t * +_cairo_mono_scan_converter_create (int xmin, + int ymin, + int xmax, + int ymax, + cairo_fill_rule_t fill_rule); +cairo_private cairo_status_t +_cairo_mono_scan_converter_add_polygon (void *converter, + const cairo_polygon_t *polygon); + +cairo_private cairo_scan_converter_t * +_cairo_clip_tor_scan_converter_create (cairo_clip_t *clip, + cairo_polygon_t *polygon, + cairo_fill_rule_t fill_rule, + cairo_antialias_t antialias); + +typedef struct _cairo_rectangular_scan_converter { + cairo_scan_converter_t base; + + cairo_box_t extents; + + struct _cairo_rectangular_scan_converter_chunk { + struct _cairo_rectangular_scan_converter_chunk *next; + void *base; + int count; + int size; + } chunks, *tail; + char buf[CAIRO_STACK_BUFFER_SIZE]; + int num_rectangles; +} cairo_rectangular_scan_converter_t; + +cairo_private void +_cairo_rectangular_scan_converter_init (cairo_rectangular_scan_converter_t *self, + const cairo_rectangle_int_t *extents); + +cairo_private cairo_status_t +_cairo_rectangular_scan_converter_add_box (cairo_rectangular_scan_converter_t *self, + const cairo_box_t *box, + int dir); + +typedef struct _cairo_botor_scan_converter { + cairo_scan_converter_t base; + + cairo_box_t extents; + cairo_fill_rule_t fill_rule; + + int xmin, xmax; + + struct _cairo_botor_scan_converter_chunk { + struct _cairo_botor_scan_converter_chunk *next; + void *base; + int count; + int size; + } chunks, *tail; + char buf[CAIRO_STACK_BUFFER_SIZE]; + int num_edges; +} cairo_botor_scan_converter_t; + +cairo_private void +_cairo_botor_scan_converter_init (cairo_botor_scan_converter_t *self, + const cairo_box_t *extents, + cairo_fill_rule_t fill_rule); + +cairo_private cairo_status_t +_cairo_botor_scan_converter_add_polygon (cairo_botor_scan_converter_t *converter, + const cairo_polygon_t *polygon); + +/* cairo-spans.c: */ + +cairo_private cairo_scan_converter_t * +_cairo_scan_converter_create_in_error (cairo_status_t error); + +cairo_private cairo_status_t +_cairo_scan_converter_status (void *abstract_converter); + +cairo_private cairo_status_t +_cairo_scan_converter_set_error (void *abstract_converter, + cairo_status_t error); + +cairo_private cairo_span_renderer_t * +_cairo_span_renderer_create_in_error (cairo_status_t error); + +cairo_private cairo_status_t +_cairo_span_renderer_status (void *abstract_renderer); + +/* Set the renderer into an error state. This sets all the method + * pointers except ->destroy() of the renderer to no-op + * implementations that just return the error status. */ +cairo_private cairo_status_t +_cairo_span_renderer_set_error (void *abstract_renderer, + cairo_status_t error); + +cairo_private cairo_status_t +_cairo_surface_composite_polygon (cairo_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *pattern, + cairo_fill_rule_t fill_rule, + cairo_antialias_t antialias, + const cairo_composite_rectangles_t *rects, + cairo_polygon_t *polygon, + cairo_region_t *clip_region); + +#endif /* CAIRO_SPANS_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-spans.c b/local/recipes/libs/cairo/source/src/cairo-spans.c new file mode 100644 index 0000000000..711c0c1068 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-spans.c @@ -0,0 +1,262 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright (c) 2008 M Joonas Pihlaja + * + * 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. + */ +#include "cairoint.h" + +#include "cairo-composite-rectangles-private.h" +#include "cairo-clip-private.h" +#include "cairo-error-private.h" +#include "cairo-fixed-private.h" +#include "cairo-types-private.h" + +static void +_cairo_nil_destroy (void *abstract) +{ + (void) abstract; +} + +static cairo_status_t +_cairo_nil_scan_converter_generate (void *abstract_converter, + cairo_span_renderer_t *renderer) +{ + (void) abstract_converter; + (void) renderer; + return _cairo_scan_converter_status (abstract_converter); +} + +cairo_status_t +_cairo_scan_converter_status (void *abstract_converter) +{ + cairo_scan_converter_t *converter = abstract_converter; + return converter->status; +} + +cairo_status_t +_cairo_scan_converter_set_error (void *abstract_converter, + cairo_status_t error) +{ + cairo_scan_converter_t *converter = abstract_converter; + if (error == CAIRO_STATUS_SUCCESS) + ASSERT_NOT_REACHED; + if (converter->status == CAIRO_STATUS_SUCCESS) { + converter->generate = _cairo_nil_scan_converter_generate; + converter->status = error; + } + return converter->status; +} + +static void +_cairo_nil_scan_converter_init (cairo_scan_converter_t *converter, + cairo_status_t status) +{ + converter->destroy = _cairo_nil_destroy; + converter->status = CAIRO_STATUS_SUCCESS; + status = _cairo_scan_converter_set_error (converter, status); +} + +cairo_scan_converter_t * +_cairo_scan_converter_create_in_error (cairo_status_t status) +{ +#define RETURN_NIL {\ + static cairo_scan_converter_t nil;\ + _cairo_nil_scan_converter_init (&nil, status);\ + return &nil;\ + } + switch (status) { + case CAIRO_STATUS_SUCCESS: + case CAIRO_STATUS_LAST_STATUS: + ASSERT_NOT_REACHED; + break; + case CAIRO_STATUS_INVALID_RESTORE: RETURN_NIL; + case CAIRO_STATUS_INVALID_POP_GROUP: RETURN_NIL; + case CAIRO_STATUS_NO_CURRENT_POINT: RETURN_NIL; + case CAIRO_STATUS_INVALID_MATRIX: RETURN_NIL; + case CAIRO_STATUS_INVALID_STATUS: RETURN_NIL; + case CAIRO_STATUS_NULL_POINTER: RETURN_NIL; + case CAIRO_STATUS_INVALID_STRING: RETURN_NIL; + case CAIRO_STATUS_INVALID_PATH_DATA: RETURN_NIL; + case CAIRO_STATUS_READ_ERROR: RETURN_NIL; + case CAIRO_STATUS_WRITE_ERROR: RETURN_NIL; + case CAIRO_STATUS_SURFACE_FINISHED: RETURN_NIL; + case CAIRO_STATUS_SURFACE_TYPE_MISMATCH: RETURN_NIL; + case CAIRO_STATUS_PATTERN_TYPE_MISMATCH: RETURN_NIL; + case CAIRO_STATUS_INVALID_CONTENT: RETURN_NIL; + case CAIRO_STATUS_INVALID_FORMAT: RETURN_NIL; + case CAIRO_STATUS_INVALID_VISUAL: RETURN_NIL; + case CAIRO_STATUS_FILE_NOT_FOUND: RETURN_NIL; + case CAIRO_STATUS_INVALID_DASH: RETURN_NIL; + case CAIRO_STATUS_INVALID_DSC_COMMENT: RETURN_NIL; + case CAIRO_STATUS_INVALID_INDEX: RETURN_NIL; + case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE: RETURN_NIL; + case CAIRO_STATUS_TEMP_FILE_ERROR: RETURN_NIL; + case CAIRO_STATUS_INVALID_STRIDE: RETURN_NIL; + case CAIRO_STATUS_FONT_TYPE_MISMATCH: RETURN_NIL; + case CAIRO_STATUS_USER_FONT_IMMUTABLE: RETURN_NIL; + case CAIRO_STATUS_USER_FONT_ERROR: RETURN_NIL; + case CAIRO_STATUS_NEGATIVE_COUNT: RETURN_NIL; + case CAIRO_STATUS_INVALID_CLUSTERS: RETURN_NIL; + case CAIRO_STATUS_INVALID_SLANT: RETURN_NIL; + case CAIRO_STATUS_INVALID_WEIGHT: RETURN_NIL; + case CAIRO_STATUS_NO_MEMORY: RETURN_NIL; + case CAIRO_STATUS_INVALID_SIZE: RETURN_NIL; + case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED: RETURN_NIL; + case CAIRO_STATUS_DEVICE_TYPE_MISMATCH: RETURN_NIL; + case CAIRO_STATUS_DEVICE_ERROR: RETURN_NIL; + case CAIRO_STATUS_INVALID_MESH_CONSTRUCTION: RETURN_NIL; + case CAIRO_STATUS_DEVICE_FINISHED: RETURN_NIL; + case CAIRO_STATUS_JBIG2_GLOBAL_MISSING: + case CAIRO_STATUS_PNG_ERROR: + case CAIRO_STATUS_FREETYPE_ERROR: + case CAIRO_STATUS_WIN32_GDI_ERROR: + case CAIRO_STATUS_TAG_ERROR: + case CAIRO_STATUS_DWRITE_ERROR: + case CAIRO_STATUS_SVG_FONT_ERROR: + default: + break; + } + status = CAIRO_STATUS_NO_MEMORY; + RETURN_NIL; +#undef RETURN_NIL +} + +static cairo_status_t +_cairo_nil_span_renderer_render_rows ( + void *abstract_renderer, + int y, + int height, + const cairo_half_open_span_t *coverages, + unsigned num_coverages) +{ + (void) y; + (void) height; + (void) coverages; + (void) num_coverages; + return _cairo_span_renderer_status (abstract_renderer); +} + +static cairo_status_t +_cairo_nil_span_renderer_finish (void *abstract_renderer) +{ + return _cairo_span_renderer_status (abstract_renderer); +} + +cairo_status_t +_cairo_span_renderer_status (void *abstract_renderer) +{ + cairo_span_renderer_t *renderer = abstract_renderer; + return renderer->status; +} + +cairo_status_t +_cairo_span_renderer_set_error ( + void *abstract_renderer, + cairo_status_t error) +{ + cairo_span_renderer_t *renderer = abstract_renderer; + if (error == CAIRO_STATUS_SUCCESS) { + ASSERT_NOT_REACHED; + } + if (renderer->status == CAIRO_STATUS_SUCCESS) { + renderer->render_rows = _cairo_nil_span_renderer_render_rows; + renderer->finish = _cairo_nil_span_renderer_finish; + renderer->status = error; + } + return renderer->status; +} + +static void +_cairo_nil_span_renderer_init (cairo_span_renderer_t *renderer, + cairo_status_t status) +{ + renderer->destroy = _cairo_nil_destroy; + renderer->status = CAIRO_STATUS_SUCCESS; + status = _cairo_span_renderer_set_error (renderer, status); +} + +cairo_span_renderer_t * +_cairo_span_renderer_create_in_error (cairo_status_t status) +{ +#define RETURN_NIL {\ + static cairo_span_renderer_t nil;\ + _cairo_nil_span_renderer_init (&nil, status);\ + return &nil;\ + } + switch (status) { + case CAIRO_STATUS_SUCCESS: + case CAIRO_STATUS_LAST_STATUS: + ASSERT_NOT_REACHED; + break; + case CAIRO_STATUS_INVALID_RESTORE: RETURN_NIL; + case CAIRO_STATUS_INVALID_POP_GROUP: RETURN_NIL; + case CAIRO_STATUS_NO_CURRENT_POINT: RETURN_NIL; + case CAIRO_STATUS_INVALID_MATRIX: RETURN_NIL; + case CAIRO_STATUS_INVALID_STATUS: RETURN_NIL; + case CAIRO_STATUS_NULL_POINTER: RETURN_NIL; + case CAIRO_STATUS_INVALID_STRING: RETURN_NIL; + case CAIRO_STATUS_INVALID_PATH_DATA: RETURN_NIL; + case CAIRO_STATUS_READ_ERROR: RETURN_NIL; + case CAIRO_STATUS_WRITE_ERROR: RETURN_NIL; + case CAIRO_STATUS_SURFACE_FINISHED: RETURN_NIL; + case CAIRO_STATUS_SURFACE_TYPE_MISMATCH: RETURN_NIL; + case CAIRO_STATUS_PATTERN_TYPE_MISMATCH: RETURN_NIL; + case CAIRO_STATUS_INVALID_CONTENT: RETURN_NIL; + case CAIRO_STATUS_INVALID_FORMAT: RETURN_NIL; + case CAIRO_STATUS_INVALID_VISUAL: RETURN_NIL; + case CAIRO_STATUS_FILE_NOT_FOUND: RETURN_NIL; + case CAIRO_STATUS_INVALID_DASH: RETURN_NIL; + case CAIRO_STATUS_INVALID_DSC_COMMENT: RETURN_NIL; + case CAIRO_STATUS_INVALID_INDEX: RETURN_NIL; + case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE: RETURN_NIL; + case CAIRO_STATUS_TEMP_FILE_ERROR: RETURN_NIL; + case CAIRO_STATUS_INVALID_STRIDE: RETURN_NIL; + case CAIRO_STATUS_FONT_TYPE_MISMATCH: RETURN_NIL; + case CAIRO_STATUS_USER_FONT_IMMUTABLE: RETURN_NIL; + case CAIRO_STATUS_USER_FONT_ERROR: RETURN_NIL; + case CAIRO_STATUS_NEGATIVE_COUNT: RETURN_NIL; + case CAIRO_STATUS_INVALID_CLUSTERS: RETURN_NIL; + case CAIRO_STATUS_INVALID_SLANT: RETURN_NIL; + case CAIRO_STATUS_INVALID_WEIGHT: RETURN_NIL; + case CAIRO_STATUS_NO_MEMORY: RETURN_NIL; + case CAIRO_STATUS_INVALID_SIZE: RETURN_NIL; + case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED: RETURN_NIL; + case CAIRO_STATUS_DEVICE_TYPE_MISMATCH: RETURN_NIL; + case CAIRO_STATUS_DEVICE_ERROR: RETURN_NIL; + case CAIRO_STATUS_INVALID_MESH_CONSTRUCTION: RETURN_NIL; + case CAIRO_STATUS_DEVICE_FINISHED: RETURN_NIL; + case CAIRO_STATUS_JBIG2_GLOBAL_MISSING: RETURN_NIL; + case CAIRO_STATUS_PNG_ERROR: RETURN_NIL; + case CAIRO_STATUS_FREETYPE_ERROR: RETURN_NIL; + case CAIRO_STATUS_WIN32_GDI_ERROR: RETURN_NIL; + case CAIRO_STATUS_TAG_ERROR: RETURN_NIL; + case CAIRO_STATUS_DWRITE_ERROR: RETURN_NIL; + case CAIRO_STATUS_SVG_FONT_ERROR: RETURN_NIL; + default: + break; + } + status = CAIRO_STATUS_NO_MEMORY; + RETURN_NIL; +#undef RETURN_NIL +} diff --git a/local/recipes/libs/cairo/source/src/cairo-spline.c b/local/recipes/libs/cairo/source/src/cairo-spline.c new file mode 100644 index 0000000000..6f50a637a9 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-spline.c @@ -0,0 +1,424 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + */ + +#include "cairoint.h" + +#include "cairo-box-inline.h" +#include "cairo-slope-private.h" + +cairo_bool_t +_cairo_spline_intersects (const cairo_point_t *a, + const cairo_point_t *b, + const cairo_point_t *c, + const cairo_point_t *d, + const cairo_box_t *box) +{ + cairo_box_t bounds; + + if (_cairo_box_contains_point (box, a) || + _cairo_box_contains_point (box, b) || + _cairo_box_contains_point (box, c) || + _cairo_box_contains_point (box, d)) + { + return TRUE; + } + + bounds.p2 = bounds.p1 = *a; + _cairo_box_add_point (&bounds, b); + _cairo_box_add_point (&bounds, c); + _cairo_box_add_point (&bounds, d); + + if (bounds.p2.x <= box->p1.x || bounds.p1.x >= box->p2.x || + bounds.p2.y <= box->p1.y || bounds.p1.y >= box->p2.y) + { + return FALSE; + } + +#if 0 /* worth refining? */ + bounds.p2 = bounds.p1 = *a; + _cairo_box_add_curve_to (&bounds, b, c, d); + if (bounds.p2.x <= box->p1.x || bounds.p1.x >= box->p2.x || + bounds.p2.y <= box->p1.y || bounds.p1.y >= box->p2.y) + { + return FALSE; + } +#endif + + return TRUE; +} + +cairo_bool_t +_cairo_spline_init (cairo_spline_t *spline, + cairo_spline_add_point_func_t add_point_func, + void *closure, + const cairo_point_t *a, const cairo_point_t *b, + const cairo_point_t *c, const cairo_point_t *d) +{ + /* If both tangents are zero, this is just a straight line */ + if (a->x == b->x && a->y == b->y && c->x == d->x && c->y == d->y) + return FALSE; + + spline->add_point_func = add_point_func; + spline->closure = closure; + + spline->knots.a = *a; + spline->knots.b = *b; + spline->knots.c = *c; + spline->knots.d = *d; + + if (a->x != b->x || a->y != b->y) + _cairo_slope_init (&spline->initial_slope, &spline->knots.a, &spline->knots.b); + else if (a->x != c->x || a->y != c->y) + _cairo_slope_init (&spline->initial_slope, &spline->knots.a, &spline->knots.c); + else if (a->x != d->x || a->y != d->y) + _cairo_slope_init (&spline->initial_slope, &spline->knots.a, &spline->knots.d); + else + return FALSE; + + if (c->x != d->x || c->y != d->y) + _cairo_slope_init (&spline->final_slope, &spline->knots.c, &spline->knots.d); + else if (b->x != d->x || b->y != d->y) + _cairo_slope_init (&spline->final_slope, &spline->knots.b, &spline->knots.d); + else + return FALSE; /* just treat this as a straight-line from a -> d */ + + /* XXX if the initial, final and vector are all equal, this is just a line */ + + return TRUE; +} + +static cairo_status_t +_cairo_spline_add_point (cairo_spline_t *spline, + const cairo_point_t *point, + const cairo_point_t *knot) +{ + cairo_point_t *prev; + cairo_slope_t slope; + + prev = &spline->last_point; + if (prev->x == point->x && prev->y == point->y) + return CAIRO_STATUS_SUCCESS; + + _cairo_slope_init (&slope, point, knot); + + spline->last_point = *point; + return spline->add_point_func (spline->closure, point, &slope); +} + +static void +_lerp_half (const cairo_point_t *a, const cairo_point_t *b, cairo_point_t *result) +{ + result->x = a->x + ((b->x - a->x) >> 1); + result->y = a->y + ((b->y - a->y) >> 1); +} + +static void +_de_casteljau (cairo_spline_knots_t *s1, cairo_spline_knots_t *s2) +{ + cairo_point_t ab, bc, cd; + cairo_point_t abbc, bccd; + cairo_point_t final; + + _lerp_half (&s1->a, &s1->b, &ab); + _lerp_half (&s1->b, &s1->c, &bc); + _lerp_half (&s1->c, &s1->d, &cd); + _lerp_half (&ab, &bc, &abbc); + _lerp_half (&bc, &cd, &bccd); + _lerp_half (&abbc, &bccd, &final); + + s2->a = final; + s2->b = bccd; + s2->c = cd; + s2->d = s1->d; + + s1->b = ab; + s1->c = abbc; + s1->d = final; +} + +/* Return an upper bound on the error (squared) that could result from + * approximating a spline as a line segment connecting the two endpoints. */ +static double +_cairo_spline_error_squared (const cairo_spline_knots_t *knots) +{ + double bdx, bdy, berr; + double cdx, cdy, cerr; + + /* We are going to compute the distance (squared) between each of the b + * and c control points and the segment a-b. The maximum of these two + * distances will be our approximation error. */ + + bdx = _cairo_fixed_to_double (knots->b.x - knots->a.x); + bdy = _cairo_fixed_to_double (knots->b.y - knots->a.y); + + cdx = _cairo_fixed_to_double (knots->c.x - knots->a.x); + cdy = _cairo_fixed_to_double (knots->c.y - knots->a.y); + + if (knots->a.x != knots->d.x || knots->a.y != knots->d.y) { + /* Intersection point (px): + * px = p1 + u(p2 - p1) + * (p - px) ∙ (p2 - p1) = 0 + * Thus: + * u = ((p - p1) ∙ (p2 - p1)) / ∥p2 - p1∥²; + */ + + double dx, dy, u, v; + + dx = _cairo_fixed_to_double (knots->d.x - knots->a.x); + dy = _cairo_fixed_to_double (knots->d.y - knots->a.y); + v = dx * dx + dy * dy; + + u = bdx * dx + bdy * dy; + if (u <= 0) { + /* bdx -= 0; + * bdy -= 0; + */ + } else if (u >= v) { + bdx -= dx; + bdy -= dy; + } else { + bdx -= u/v * dx; + bdy -= u/v * dy; + } + + u = cdx * dx + cdy * dy; + if (u <= 0) { + /* cdx -= 0; + * cdy -= 0; + */ + } else if (u >= v) { + cdx -= dx; + cdy -= dy; + } else { + cdx -= u/v * dx; + cdy -= u/v * dy; + } + } + + berr = bdx * bdx + bdy * bdy; + cerr = cdx * cdx + cdy * cdy; + if (berr > cerr) + return berr; + else + return cerr; +} + +static cairo_status_t +_cairo_spline_decompose_into (cairo_spline_knots_t *s1, + double tolerance_squared, + cairo_spline_t *result) +{ + cairo_spline_knots_t s2; + cairo_status_t status; + + if (_cairo_spline_error_squared (s1) < tolerance_squared) + return _cairo_spline_add_point (result, &s1->a, &s1->b); + + _de_casteljau (s1, &s2); + + status = _cairo_spline_decompose_into (s1, tolerance_squared, result); + if (unlikely (status)) + return status; + + return _cairo_spline_decompose_into (&s2, tolerance_squared, result); +} + +cairo_status_t +_cairo_spline_decompose (cairo_spline_t *spline, double tolerance) +{ + cairo_spline_knots_t s1; + cairo_status_t status; + + s1 = spline->knots; + spline->last_point = s1.a; + status = _cairo_spline_decompose_into (&s1, tolerance * tolerance, spline); + if (unlikely (status)) + return status; + + return spline->add_point_func (spline->closure, + &spline->knots.d, &spline->final_slope); +} + +/* Note: this function is only good for computing bounds in device space. */ +cairo_status_t +_cairo_spline_bound (cairo_spline_add_point_func_t add_point_func, + void *closure, + const cairo_point_t *p0, const cairo_point_t *p1, + const cairo_point_t *p2, const cairo_point_t *p3) +{ + double x0, x1, x2, x3; + double y0, y1, y2, y3; + double a, b, c; + double t[4]; + int t_num = 0, i; + cairo_status_t status; + + x0 = _cairo_fixed_to_double (p0->x); + y0 = _cairo_fixed_to_double (p0->y); + x1 = _cairo_fixed_to_double (p1->x); + y1 = _cairo_fixed_to_double (p1->y); + x2 = _cairo_fixed_to_double (p2->x); + y2 = _cairo_fixed_to_double (p2->y); + x3 = _cairo_fixed_to_double (p3->x); + y3 = _cairo_fixed_to_double (p3->y); + + /* The spline can be written as a polynomial of the four points: + * + * (1-t)³p0 + 3t(1-t)²p1 + 3t²(1-t)p2 + t³p3 + * + * for 0≤t≤1. Now, the X and Y components of the spline follow the + * same polynomial but with x and y replaced for p. To find the + * bounds of the spline, we just need to find the X and Y bounds. + * To find the bound, we take the derivative and equal it to zero, + * and solve to find the t's that give the extreme points. + * + * Here is the derivative of the curve, sorted on t: + * + * 3t²(-p0+3p1-3p2+p3) + 2t(3p0-6p1+3p2) -3p0+3p1 + * + * Let: + * + * a = -p0+3p1-3p2+p3 + * b = p0-2p1+p2 + * c = -p0+p1 + * + * Gives: + * + * a.t² + 2b.t + c = 0 + * + * With: + * + * delta = b*b - a*c + * + * the extreme points are at -c/2b if a is zero, at (-b±√delta)/a if + * delta is positive, and at -b/a if delta is zero. + */ + +#define ADD(t0) \ + { \ + double _t0 = (t0); \ + if (0 < _t0 && _t0 < 1) \ + t[t_num++] = _t0; \ + } + +#define FIND_EXTREMES(a,b,c) \ + { \ + if (a == 0) { \ + if (b != 0) \ + ADD (-c / (2*b)); \ + } else { \ + double b2 = b * b; \ + double delta = b2 - a * c; \ + if (delta > 0) { \ + cairo_bool_t feasible; \ + double _2ab = 2 * a * b; \ + /* We are only interested in solutions t that satisfy 0= 0) \ + feasible = delta > b2 && delta < a*a + b2 + _2ab; \ + else if (-b / a >= 1) \ + feasible = delta < b2 && delta > a*a + b2 + _2ab; \ + else \ + feasible = delta < b2 || delta < a*a + b2 + _2ab; \ + \ + if (unlikely (feasible)) { \ + double sqrt_delta = sqrt (delta); \ + ADD ((-b - sqrt_delta) / a); \ + ADD ((-b + sqrt_delta) / a); \ + } \ + } else if (delta == 0) { \ + ADD (-b / a); \ + } \ + } \ + } + + /* Find X extremes */ + a = -x0 + 3*x1 - 3*x2 + x3; + b = x0 - 2*x1 + x2; + c = -x0 + x1; + FIND_EXTREMES (a, b, c); + + /* Find Y extremes */ + a = -y0 + 3*y1 - 3*y2 + y3; + b = y0 - 2*y1 + y2; + c = -y0 + y1; + FIND_EXTREMES (a, b, c); + + status = add_point_func (closure, p0, NULL); + if (unlikely (status)) + return status; + + for (i = 0; i < t_num; i++) { + cairo_point_t p; + double x, y; + double t_1_0, t_0_1; + double t_2_0, t_0_2; + double t_3_0, t_2_1_3, t_1_2_3, t_0_3; + + t_1_0 = t[i]; /* t */ + t_0_1 = 1 - t_1_0; /* (1 - t) */ + + t_2_0 = t_1_0 * t_1_0; /* t * t */ + t_0_2 = t_0_1 * t_0_1; /* (1 - t) * (1 - t) */ + + t_3_0 = t_2_0 * t_1_0; /* t * t * t */ + t_2_1_3 = t_2_0 * t_0_1 * 3; /* t * t * (1 - t) * 3 */ + t_1_2_3 = t_1_0 * t_0_2 * 3; /* t * (1 - t) * (1 - t) * 3 */ + t_0_3 = t_0_1 * t_0_2; /* (1 - t) * (1 - t) * (1 - t) */ + + /* Bezier polynomial */ + x = x0 * t_0_3 + + x1 * t_1_2_3 + + x2 * t_2_1_3 + + x3 * t_3_0; + y = y0 * t_0_3 + + y1 * t_1_2_3 + + y2 * t_2_1_3 + + y3 * t_3_0; + + p.x = _cairo_fixed_from_double (x); + p.y = _cairo_fixed_from_double (y); + status = add_point_func (closure, &p, NULL); + if (unlikely (status)) + return status; + } + + return add_point_func (closure, p3, NULL); +} diff --git a/local/recipes/libs/cairo/source/src/cairo-stroke-dash-private.h b/local/recipes/libs/cairo/source/src/cairo-stroke-dash-private.h new file mode 100644 index 0000000000..75c000cd73 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-stroke-dash-private.h @@ -0,0 +1,70 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Chris Wilson + */ + +#ifndef CAIRO_STROKE_DASH_PRIVATE_H +#define CAIRO_STROKE_DASH_PRIVATE_H + +#include "cairoint.h" + +CAIRO_BEGIN_DECLS + +typedef struct _cairo_stroker_dash { + cairo_bool_t dashed; + unsigned int dash_index; + cairo_bool_t dash_on; + cairo_bool_t dash_starts_on; + double dash_remain; + + double dash_offset; + const double *dashes; + unsigned int num_dashes; +} cairo_stroker_dash_t; + +cairo_private void +_cairo_stroker_dash_init (cairo_stroker_dash_t *dash, + const cairo_stroke_style_t *style); + +cairo_private void +_cairo_stroker_dash_start (cairo_stroker_dash_t *dash); + +cairo_private void +_cairo_stroker_dash_step (cairo_stroker_dash_t *dash, double step); + +CAIRO_END_DECLS + +#endif /* CAIRO_STROKE_DASH_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-stroke-dash.c b/local/recipes/libs/cairo/source/src/cairo-stroke-dash.c new file mode 100644 index 0000000000..9494010f56 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-stroke-dash.c @@ -0,0 +1,96 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Chris Wilson + */ + +#include "cairoint.h" + +#include "cairo-stroke-dash-private.h" + +void +_cairo_stroker_dash_start (cairo_stroker_dash_t *dash) +{ + double offset; + cairo_bool_t on = TRUE; + unsigned int i = 0; + + if (! dash->dashed) + return; + + offset = dash->dash_offset; + + /* We stop searching for a starting point as soon as the + offset reaches zero. Otherwise when an initial dash + segment shrinks to zero it will be skipped over. */ + while (offset > 0.0 && offset >= dash->dashes[i]) { + offset -= dash->dashes[i]; + on = !on; + if (++i == dash->num_dashes) + i = 0; + } + + dash->dash_index = i; + dash->dash_on = dash->dash_starts_on = on; + dash->dash_remain = dash->dashes[i] - offset; +} + +void +_cairo_stroker_dash_step (cairo_stroker_dash_t *dash, double step) +{ + dash->dash_remain -= step; + if (dash->dash_remain < CAIRO_FIXED_ERROR_DOUBLE) { + if (++dash->dash_index == dash->num_dashes) + dash->dash_index = 0; + + dash->dash_on = ! dash->dash_on; + dash->dash_remain += dash->dashes[dash->dash_index]; + } +} + +void +_cairo_stroker_dash_init (cairo_stroker_dash_t *dash, + const cairo_stroke_style_t *style) +{ + dash->dashed = style->dash != NULL; + if (! dash->dashed) + return; + + dash->dashes = style->dash; + dash->num_dashes = style->num_dashes; + dash->dash_offset = style->dash_offset; + + _cairo_stroker_dash_start (dash); +} diff --git a/local/recipes/libs/cairo/source/src/cairo-stroke-style.c b/local/recipes/libs/cairo/source/src/cairo-stroke-style.c new file mode 100644 index 0000000000..fed8aec55f --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-stroke-style.c @@ -0,0 +1,358 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Carl Worth + */ + +#include "cairoint.h" +#include "cairo-error-private.h" + +void +_cairo_stroke_style_init (cairo_stroke_style_t *style) +{ + VG (VALGRIND_MAKE_MEM_UNDEFINED (style, sizeof (cairo_stroke_style_t))); + + style->line_width = CAIRO_GSTATE_LINE_WIDTH_DEFAULT; + style->line_cap = CAIRO_GSTATE_LINE_CAP_DEFAULT; + style->line_join = CAIRO_GSTATE_LINE_JOIN_DEFAULT; + style->miter_limit = CAIRO_GSTATE_MITER_LIMIT_DEFAULT; + + style->dash = NULL; + style->num_dashes = 0; + style->dash_offset = 0.0; + + style->is_hairline = FALSE; +} + +cairo_status_t +_cairo_stroke_style_init_copy (cairo_stroke_style_t *style, + const cairo_stroke_style_t *other) +{ + if (CAIRO_INJECT_FAULT ()) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + VG (VALGRIND_MAKE_MEM_UNDEFINED (style, sizeof (cairo_stroke_style_t))); + + style->line_width = other->line_width; + style->line_cap = other->line_cap; + style->line_join = other->line_join; + style->miter_limit = other->miter_limit; + + style->num_dashes = other->num_dashes; + + if (other->dash == NULL) { + style->dash = NULL; + } else { + style->dash = _cairo_malloc_ab (style->num_dashes, sizeof (double)); + if (unlikely (style->dash == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + memcpy (style->dash, other->dash, + style->num_dashes * sizeof (double)); + } + + style->dash_offset = other->dash_offset; + + style->is_hairline = other->is_hairline; + + return CAIRO_STATUS_SUCCESS; +} + +void +_cairo_stroke_style_fini (cairo_stroke_style_t *style) +{ + free (style->dash); + style->dash = NULL; + + style->num_dashes = 0; + + VG (VALGRIND_MAKE_MEM_UNDEFINED (style, sizeof (cairo_stroke_style_t))); +} + +/* + * For a stroke in the given style, compute the maximum distance + * from the path that vertices could be generated. In the case + * of rotation in the ctm, the distance will not be exact. + */ +void +_cairo_stroke_style_max_distance_from_path (const cairo_stroke_style_t *style, + const cairo_path_fixed_t *path, + const cairo_matrix_t *ctm, + double *dx, double *dy) +{ + double style_expansion = 0.5; + + if (style->line_cap == CAIRO_LINE_CAP_SQUARE) + style_expansion = M_SQRT1_2; + + if (style->line_join == CAIRO_LINE_JOIN_MITER && + ! path->stroke_is_rectilinear && + style_expansion < M_SQRT2 * style->miter_limit) + { + style_expansion = M_SQRT2 * style->miter_limit; + } + + style_expansion *= style->line_width; + + if (_cairo_matrix_has_unity_scale (ctm)) { + *dx = *dy = style_expansion; + } else { + *dx = style_expansion * hypot (ctm->xx, ctm->xy); + *dy = style_expansion * hypot (ctm->yy, ctm->yx); + } +} + +void +_cairo_stroke_style_max_line_distance_from_path (const cairo_stroke_style_t *style, + const cairo_path_fixed_t *path, + const cairo_matrix_t *ctm, + double *dx, double *dy) +{ + double style_expansion = 0.5 * style->line_width; + if (_cairo_matrix_has_unity_scale (ctm)) { + *dx = *dy = style_expansion; + } else { + *dx = style_expansion * hypot (ctm->xx, ctm->xy); + *dy = style_expansion * hypot (ctm->yy, ctm->yx); + } +} + +void +_cairo_stroke_style_max_join_distance_from_path (const cairo_stroke_style_t *style, + const cairo_path_fixed_t *path, + const cairo_matrix_t *ctm, + double *dx, double *dy) +{ + double style_expansion = 0.5; + + if (style->line_join == CAIRO_LINE_JOIN_MITER && + ! path->stroke_is_rectilinear && + style_expansion < M_SQRT2 * style->miter_limit) + { + style_expansion = M_SQRT2 * style->miter_limit; + } + + style_expansion *= style->line_width; + + if (_cairo_matrix_has_unity_scale (ctm)) { + *dx = *dy = style_expansion; + } else { + *dx = style_expansion * hypot (ctm->xx, ctm->xy); + *dy = style_expansion * hypot (ctm->yy, ctm->yx); + } +} +/* + * Computes the period of a dashed stroke style. + * Returns 0 for non-dashed styles. + */ +double +_cairo_stroke_style_dash_period (const cairo_stroke_style_t *style) +{ + double period; + unsigned int i; + + period = 0.0; + for (i = 0; i < style->num_dashes; i++) + period += style->dash[i]; + + if (style->num_dashes & 1) + period *= 2.0; + + return period; +} + +/* + * Coefficient of the linear approximation (minimizing square difference) + * of the surface covered by round caps + * + * This can be computed in the following way: + * the area inside the circle with radius w/2 and the region -d/2 <= x <= d/2 is: + * f(w,d) = 2 * integrate (sqrt (w*w/4 - x*x), x, -d/2, d/2) + * The square difference to a generic linear approximation (c*d) in the range (0,w) would be: + * integrate ((f(w,d) - c*d)^2, d, 0, w) + * To minimize this difference it is sufficient to find a solution of the differential with + * respect to c: + * solve ( diff (integrate ((f(w,d) - c*d)^2, d, 0, w), c), c) + * Which leads to c = 9/32*pi*w + * Since we're not interested in the true area, but just in a coverage estimate, + * we always divide the real area by the line width (w). + * The same computation for square caps would be + * f(w,d) = 2 * integrate(w/2, x, -d/2, d/2) + * c = 1*w + * but in this case it would not be an approximation, since f is already linear in d. + */ +#define ROUND_MINSQ_APPROXIMATION (9*M_PI/32) + +/* + * Computes the length of the "on" part of a dashed stroke style, + * taking into account also line caps. + * Returns 0 for non-dashed styles. + */ +double +_cairo_stroke_style_dash_stroked (const cairo_stroke_style_t *style) +{ + double stroked, cap_scale; + unsigned int i; + + switch (style->line_cap) { + default: ASSERT_NOT_REACHED; + case CAIRO_LINE_CAP_BUTT: cap_scale = 0.0; break; + case CAIRO_LINE_CAP_ROUND: cap_scale = ROUND_MINSQ_APPROXIMATION; break; + case CAIRO_LINE_CAP_SQUARE: cap_scale = 1.0; break; + } + + stroked = 0.0; + if (style->num_dashes & 1) { + /* Each dash element is used both as on and as off. The order in which they are summed is + * irrelevant, so sum the coverage of one dash element, taken both on and off at each iteration */ + for (i = 0; i < style->num_dashes; i++) + stroked += style->dash[i] + cap_scale * MIN (style->dash[i], style->line_width); + } else { + /* Even (0, 2, ...) dashes are on and simply counted for the coverage, odd dashes are off, thus + * their coverage is approximated based on the area covered by the caps of adjacent on dases. */ + for (i = 0; i + 1 < style->num_dashes; i += 2) + stroked += style->dash[i] + cap_scale * MIN (style->dash[i+1], style->line_width); + } + + return stroked; +} + +/* + * Verifies if _cairo_stroke_style_dash_approximate should be used to generate + * an approximation of the dash pattern in the specified style, when used for + * stroking a path with the given CTM and tolerance. + * Always %FALSE for non-dashed styles. + */ +cairo_bool_t +_cairo_stroke_style_dash_can_approximate (const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + double tolerance) +{ + double period; + + if (! style->num_dashes) + return FALSE; + + period = _cairo_stroke_style_dash_period (style); + return _cairo_matrix_transformed_circle_major_axis (ctm, period) < tolerance; +} + +/* + * Create a 2-dashes approximation of a dashed style, by making the "on" and "off" + * parts respect the original ratio. + */ +void +_cairo_stroke_style_dash_approximate (const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + double tolerance, + double *dash_offset, + double *dashes, + unsigned int *num_dashes) +{ + double coverage, scale, offset; + cairo_bool_t on = TRUE; + unsigned int i = 0; + + coverage = _cairo_stroke_style_dash_stroked (style) / _cairo_stroke_style_dash_period (style); + coverage = MIN (coverage, 1.0); + scale = tolerance / _cairo_matrix_transformed_circle_major_axis (ctm, 1.0); + + /* We stop searching for a starting point as soon as the + * offset reaches zero. Otherwise when an initial dash + * segment shrinks to zero it will be skipped over. */ + offset = style->dash_offset; + while (offset > 0.0 && offset >= style->dash[i]) { + offset -= style->dash[i]; + on = !on; + if (++i == style->num_dashes) + i = 0; + } + + *num_dashes = 2; + + /* + * We want to create a new dash pattern with the same relative coverage, + * but composed of just 2 elements with total length equal to scale. + * Based on the formula in _cairo_stroke_style_dash_stroked: + * scale * coverage = dashes[0] + cap_scale * MIN (dashes[1], line_width) + * = MIN (dashes[0] + cap_scale * (scale - dashes[0]), + * dashes[0] + cap_scale * line_width) = + * = MIN (dashes[0] * (1 - cap_scale) + cap_scale * scale, + * dashes[0] + cap_scale * line_width) + * + * Solving both cases we get: + * dashes[0] = scale * (coverage - cap_scale) / (1 - cap_scale) + * when scale - dashes[0] <= line_width + * dashes[0] = scale * coverage - cap_scale * line_width + * when scale - dashes[0] > line_width. + * + * Comparing the two cases we get: + * second > first + * second > scale * (coverage - cap_scale) / (1 - cap_scale) + * second - cap_scale * second - scale * coverage + scale * cap_scale > 0 + * (scale * coverage - cap_scale * line_width) - cap_scale * second - scale * coverage + scale * cap_scale > 0 + * - line_width - second + scale > 0 + * scale - second > line_width + * which is the condition for the second solution to be the valid one. + * So when second > first, the second solution is the correct one (i.e. + * the solution is always MAX (first, second). + */ + switch (style->line_cap) { + default: + ASSERT_NOT_REACHED; + dashes[0] = 0.0; + break; + + case CAIRO_LINE_CAP_BUTT: + /* Simplified formula (substituting 0 for cap_scale): */ + dashes[0] = scale * coverage; + break; + + case CAIRO_LINE_CAP_ROUND: + dashes[0] = MAX(scale * (coverage - ROUND_MINSQ_APPROXIMATION) / (1.0 - ROUND_MINSQ_APPROXIMATION), + scale * coverage - ROUND_MINSQ_APPROXIMATION * style->line_width); + break; + + case CAIRO_LINE_CAP_SQUARE: + /* + * Special attention is needed to handle the case cap_scale == 1 (since the first solution + * is either indeterminate or -inf in this case). Since dash lengths are always >=0, using + * 0 as first solution always leads to the correct solution. + */ + dashes[0] = MAX(0.0, scale * coverage - style->line_width); + break; + } + + dashes[1] = scale - dashes[0]; + + *dash_offset = on ? 0.0 : dashes[0]; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-surface-backend-private.h b/local/recipes/libs/cairo/source/src/cairo-surface-backend-private.h new file mode 100644 index 0000000000..856c596c86 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-surface-backend-private.h @@ -0,0 +1,257 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + */ + +#ifndef CAIRO_SURFACE_BACKEND_PRIVATE_H +#define CAIRO_SURFACE_BACKEND_PRIVATE_H + +#include "cairo-compiler-private.h" +#include "cairo-error-private.h" +#include "cairo-pattern-private.h" + +CAIRO_BEGIN_DECLS + +struct _cairo_surface_backend { + cairo_surface_type_t type; + + cairo_warn cairo_status_t + (*finish) (void *surface); + + cairo_t * + (*create_context) (void *surface); + + cairo_surface_t * + (*create_similar) (void *surface, + cairo_content_t content, + int width, + int height); + cairo_surface_t * + (*create_similar_image) (void *surface, + cairo_format_t format, + int width, + int height); + + cairo_image_surface_t * + (*map_to_image) (void *surface, + const cairo_rectangle_int_t *extents); + cairo_int_status_t + (*unmap_image) (void *surface, + cairo_image_surface_t *image); + + cairo_surface_t * + (*source) (void *abstract_surface, + cairo_rectangle_int_t *extents); + + cairo_warn cairo_status_t + (*acquire_source_image) (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra); + + cairo_warn void + (*release_source_image) (void *abstract_surface, + cairo_image_surface_t *image_out, + void *image_extra); + + cairo_surface_t * + (*snapshot) (void *surface); + + cairo_warn cairo_int_status_t + (*copy_page) (void *surface); + + cairo_warn cairo_int_status_t + (*show_page) (void *surface); + + /* Get the extents of the current surface. For many surface types + * this will be as simple as { x=0, y=0, width=surface->width, + * height=surface->height}. + * + * If this function is not implemented, or if it returns + * FALSE the surface is considered to be + * boundless and infinite bounds are used for it. + */ + cairo_bool_t + (*get_extents) (void *surface, + cairo_rectangle_int_t *extents); + + void + (*get_font_options) (void *surface, + cairo_font_options_t *options); + + cairo_warn cairo_status_t + (*flush) (void *surface, + unsigned flags); + + cairo_warn cairo_status_t + (*mark_dirty_rectangle) (void *surface, + int x, + int y, + int width, + int height); + + cairo_warn cairo_int_status_t + (*paint) (void *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip); + + cairo_warn cairo_int_status_t + (*mask) (void *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_clip_t *clip); + + cairo_warn cairo_int_status_t + (*stroke) (void *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip); + + cairo_warn cairo_int_status_t + (*fill) (void *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip); + + cairo_warn cairo_int_status_t + (*fill_stroke) (void *surface, + cairo_operator_t fill_op, + const cairo_pattern_t *fill_source, + cairo_fill_rule_t fill_rule, + double fill_tolerance, + cairo_antialias_t fill_antialias, + const cairo_path_fixed_t*path, + cairo_operator_t stroke_op, + const cairo_pattern_t *stroke_source, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *stroke_ctm, + const cairo_matrix_t *stroke_ctm_inverse, + double stroke_tolerance, + cairo_antialias_t stroke_antialias, + const cairo_clip_t *clip); + + cairo_warn cairo_int_status_t + (*show_glyphs) (void *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip); + + cairo_bool_t + (*has_show_text_glyphs) (void *surface); + + cairo_warn cairo_int_status_t + (*show_text_glyphs) (void *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const char *utf8, + int utf8_len, + cairo_glyph_t *glyphs, + int num_glyphs, + const cairo_text_cluster_t *clusters, + int num_clusters, + cairo_text_cluster_flags_t cluster_flags, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip); + + const char ** + (*get_supported_mime_types) (void *surface); + + cairo_warn cairo_int_status_t + (*tag) (void *surface, + cairo_bool_t begin, + const char *tag_name, + const char *attributes); + + cairo_bool_t + (*supports_color_glyph) (void *surface, + cairo_scaled_font_t *scaled_font, + unsigned long glyph_index); + + /* Paginated surfaces only. During the analysis stage, if any + * recording surfaces used as a source are to be replayed, this + * function will be called at the begining and end of the replay. + * + * @recording_surface - the recording surface used as a source + * @source_type - a type indicating the combination of drawing + * operation and source type + * @begin - TRUE when called before the replay, FALSE when called + * after the replay has finished. + */ + cairo_warn cairo_int_status_t + (*analyze_recording_surface)(void *surface, + const cairo_surface_pattern_t *recording_surface_pattern, + unsigned int region_id, + cairo_analysis_source_t source_type, + cairo_bool_t begin); + + cairo_warn cairo_int_status_t + (*command_id) (void *surface, + unsigned int recording_id, + unsigned int command_id); + +}; + +cairo_private cairo_status_t +_cairo_surface_default_acquire_source_image (void *surface, + cairo_image_surface_t **image_out, + void **image_extra); + +cairo_private void +_cairo_surface_default_release_source_image (void *surface, + cairo_image_surface_t *image, + void *image_extra); + +cairo_private cairo_surface_t * +_cairo_surface_default_source (void *surface, + cairo_rectangle_int_t *extents); + +CAIRO_END_DECLS + +#endif /* CAIRO_SURFACE_BACKEND_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-surface-clipper-private.h b/local/recipes/libs/cairo/source/src/cairo-surface-clipper-private.h new file mode 100644 index 0000000000..e5b00af7c6 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-surface-clipper-private.h @@ -0,0 +1,71 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Chris Wilson + */ + +#ifndef CAIRO_SURFACE_CLIPPER_PRIVATE_H +#define CAIRO_SURFACE_CLIPPER_PRIVATE_H + +#include "cairo-types-private.h" +#include "cairo-clip-private.h" + +CAIRO_BEGIN_DECLS + +typedef struct _cairo_surface_clipper cairo_surface_clipper_t; + +typedef cairo_status_t +(*cairo_surface_clipper_intersect_clip_path_func_t) (cairo_surface_clipper_t *, + cairo_path_fixed_t *, + cairo_fill_rule_t, + double, + cairo_antialias_t); +struct _cairo_surface_clipper { + cairo_clip_t *clip; + cairo_surface_clipper_intersect_clip_path_func_t intersect_clip_path; +}; + +cairo_private cairo_status_t +_cairo_surface_clipper_set_clip (cairo_surface_clipper_t *clipper, + const cairo_clip_t *clip); + +cairo_private void +_cairo_surface_clipper_init (cairo_surface_clipper_t *clipper, + cairo_surface_clipper_intersect_clip_path_func_t intersect); + +cairo_private void +_cairo_surface_clipper_reset (cairo_surface_clipper_t *clipper); + +CAIRO_END_DECLS + +#endif /* CAIRO_SURFACE_CLIPPER_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-surface-clipper.c b/local/recipes/libs/cairo/source/src/cairo-surface-clipper.c new file mode 100644 index 0000000000..5309362c68 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-surface-clipper.c @@ -0,0 +1,196 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Chris Wilson + */ + +#include "cairoint.h" + +#include "cairo-clip-inline.h" +#include "cairo-surface-clipper-private.h" + +/* A collection of routines to facilitate vector surface clipping */ + +/* XXX Eliminate repeated paths and nested clips */ + +static cairo_status_t +_cairo_path_fixed_add_box (cairo_path_fixed_t *path, + const cairo_box_t *box) +{ + cairo_status_t status; + + status = _cairo_path_fixed_move_to (path, box->p1.x, box->p1.y); + if (unlikely (status)) + return status; + + status = _cairo_path_fixed_line_to (path, box->p2.x, box->p1.y); + if (unlikely (status)) + return status; + + status = _cairo_path_fixed_line_to (path, box->p2.x, box->p2.y); + if (unlikely (status)) + return status; + + status = _cairo_path_fixed_line_to (path, box->p1.x, box->p2.y); + if (unlikely (status)) + return status; + + return _cairo_path_fixed_close_path (path); +} + +static cairo_status_t +_cairo_surface_clipper_intersect_clip_boxes (cairo_surface_clipper_t *clipper, + const cairo_clip_t *clip) +{ + cairo_path_fixed_t path; + cairo_status_t status; + int i; + + if (clip->num_boxes == 0) + return CAIRO_STATUS_SUCCESS; + + /* Reconstruct the path for the clip boxes. + * XXX maybe a new clipper callback? + */ + + _cairo_path_fixed_init (&path); + for (i = 0; i < clip->num_boxes; i++) { + status = _cairo_path_fixed_add_box (&path, &clip->boxes[i]); + if (unlikely (status)) { + _cairo_path_fixed_fini (&path); + return status; + } + } + + status = clipper->intersect_clip_path (clipper, &path, + CAIRO_FILL_RULE_WINDING, + 0., + CAIRO_ANTIALIAS_DEFAULT); + _cairo_path_fixed_fini (&path); + + return status; +} + +static cairo_status_t +_cairo_surface_clipper_intersect_clip_path_recursive (cairo_surface_clipper_t *clipper, + cairo_clip_path_t *clip_path, + cairo_clip_path_t *end) +{ + cairo_status_t status; + + if (clip_path->prev != end) { + status = + _cairo_surface_clipper_intersect_clip_path_recursive (clipper, + clip_path->prev, + end); + if (unlikely (status)) + return status; + } + + return clipper->intersect_clip_path (clipper, + &clip_path->path, + clip_path->fill_rule, + clip_path->tolerance, + clip_path->antialias); +} + +cairo_status_t +_cairo_surface_clipper_set_clip (cairo_surface_clipper_t *clipper, + const cairo_clip_t *clip) +{ + cairo_status_t status; + cairo_bool_t incremental = FALSE; + + if (_cairo_clip_equal (clip, clipper->clip)) + return CAIRO_STATUS_SUCCESS; + + /* all clipped out state should never propagate this far */ + assert (!_cairo_clip_is_all_clipped (clip)); + + /* XXX Is this an incremental clip? */ + if (clipper->clip && clip && + clip->num_boxes == clipper->clip->num_boxes && + memcmp (clip->boxes, clipper->clip->boxes, + sizeof (cairo_box_t) * clip->num_boxes) == 0) + { + cairo_clip_path_t *clip_path = clip->path; + while (clip_path != NULL && clip_path != clipper->clip->path) + clip_path = clip_path->prev; + + if (clip_path) { + incremental = TRUE; + status = _cairo_surface_clipper_intersect_clip_path_recursive (clipper, + clip->path, + clipper->clip->path); + } + } + + _cairo_clip_destroy (clipper->clip); + clipper->clip = _cairo_clip_copy (clip); + + if (incremental) + return status; + + status = clipper->intersect_clip_path (clipper, NULL, 0, 0, 0); + if (unlikely (status)) + return status; + + if (clip == NULL) + return CAIRO_STATUS_SUCCESS; + + status = _cairo_surface_clipper_intersect_clip_boxes (clipper, clip); + if (unlikely (status)) + return status; + + if (clip->path != NULL) { + status = _cairo_surface_clipper_intersect_clip_path_recursive (clipper, + clip->path, + NULL); + } + + return status; +} + +void +_cairo_surface_clipper_init (cairo_surface_clipper_t *clipper, + cairo_surface_clipper_intersect_clip_path_func_t func) +{ + clipper->clip = NULL; + clipper->intersect_clip_path = func; +} + +void +_cairo_surface_clipper_reset (cairo_surface_clipper_t *clipper) +{ + _cairo_clip_destroy (clipper->clip); + clipper->clip = NULL; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-surface-fallback-private.h b/local/recipes/libs/cairo/source/src/cairo-surface-fallback-private.h new file mode 100644 index 0000000000..ecf7b0edf2 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-surface-fallback-private.h @@ -0,0 +1,95 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Joonas Pihlaja + * Chris Wilson + */ + +#ifndef CAIRO_SURFACE_FALLBACK_PRIVATE_H +#define CAIRO_SURFACE_FALLBACK_PRIVATE_H + +#include "cairoint.h" + +CAIRO_BEGIN_DECLS + +cairo_private cairo_int_status_t +_cairo_surface_fallback_paint (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip); + +cairo_private cairo_int_status_t +_cairo_surface_fallback_mask (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_clip_t *clip); + +cairo_private cairo_int_status_t +_cairo_surface_fallback_stroke (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t*style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip); + +cairo_private cairo_int_status_t +_cairo_surface_fallback_fill (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip); + +cairo_private cairo_int_status_t +_cairo_surface_fallback_glyphs (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip); + +CAIRO_END_DECLS + +#endif /* CAIRO_SURFACE_FALLBACK_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-surface-fallback.c b/local/recipes/libs/cairo/source/src/cairo-surface-fallback.c new file mode 100644 index 0000000000..a0af159692 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-surface-fallback.c @@ -0,0 +1,115 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Joonas Pihlaja + * Chris Wilson + */ + +#include "cairoint.h" + +#include "cairo-compositor-private.h" +#include "cairo-surface-fallback-private.h" + +cairo_int_status_t +_cairo_surface_fallback_paint (void *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip) +{ + return _cairo_compositor_paint (&_cairo_fallback_compositor, + surface, op, source, clip); +} + +cairo_int_status_t +_cairo_surface_fallback_mask (void *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_clip_t *clip) +{ + return _cairo_compositor_mask (&_cairo_fallback_compositor, + surface, op, source, mask, clip); +} + +cairo_int_status_t +_cairo_surface_fallback_stroke (void *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t*path, + const cairo_stroke_style_t*style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + return _cairo_compositor_stroke (&_cairo_fallback_compositor, + surface, op, source, path, + style, ctm,ctm_inverse, + tolerance, antialias, clip); +} + +cairo_int_status_t +_cairo_surface_fallback_fill (void *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + return _cairo_compositor_fill (&_cairo_fallback_compositor, + surface, op, source, path, + fill_rule, tolerance, antialias, + clip); +} + +cairo_int_status_t +_cairo_surface_fallback_glyphs (void *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip) +{ + return _cairo_compositor_glyphs (&_cairo_fallback_compositor, + surface, op, source, + glyphs, num_glyphs, scaled_font, + clip); +} diff --git a/local/recipes/libs/cairo/source/src/cairo-surface-inline.h b/local/recipes/libs/cairo/source/src/cairo-surface-inline.h new file mode 100644 index 0000000000..85fbc9192b --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-surface-inline.h @@ -0,0 +1,60 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + */ + +#ifndef CAIRO_SURFACE_INLINE_H +#define CAIRO_SURFACE_INLINE_H + +#include "cairo-surface-private.h" + +static inline cairo_status_t +__cairo_surface_flush (cairo_surface_t *surface, unsigned flags) +{ + cairo_status_t status = CAIRO_STATUS_SUCCESS; + if (surface->backend->flush) + status = surface->backend->flush (surface, flags); + return status; +} + +static inline cairo_surface_t * +_cairo_surface_reference (cairo_surface_t *surface) +{ + if (!CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count)) + _cairo_reference_count_inc (&surface->ref_count); + return surface; +} + +#endif /* CAIRO_SURFACE_INLINE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-surface-observer-inline.h b/local/recipes/libs/cairo/source/src/cairo-surface-observer-inline.h new file mode 100644 index 0000000000..07b94770d4 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-surface-observer-inline.h @@ -0,0 +1,59 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Intel Corporation. + * + * Contributor(s): + * Chris Wilson + */ + +#ifndef CAIRO_SURFACE_OBSERVER_INLINE_H +#define CAIRO_SURFACE_OBSERVER_INLINE_H + +#include "cairo-surface-observer-private.h" + +static inline cairo_surface_t * +_cairo_surface_observer_get_target (cairo_surface_t *surface) +{ + return ((cairo_surface_observer_t *) surface)->target; +} + +static inline cairo_bool_t +_cairo_surface_is_observer (cairo_surface_t *surface) +{ + return surface->backend->type == (cairo_surface_type_t)CAIRO_INTERNAL_SURFACE_TYPE_OBSERVER; +} + +static inline cairo_bool_t +_cairo_device_is_observer (cairo_device_t *device) +{ + return device->backend->type == (cairo_device_type_t)CAIRO_INTERNAL_DEVICE_TYPE_OBSERVER; +} + +#endif /* CAIRO_SURFACE_OBSERVER_INLINE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-surface-observer-private.h b/local/recipes/libs/cairo/source/src/cairo-surface-observer-private.h new file mode 100644 index 0000000000..6ed0c18d17 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-surface-observer-private.h @@ -0,0 +1,208 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Intel Corporation. + * + * Contributor(s): + * Chris Wilson + */ + +#ifndef CAIRO_SURFACE_OBSERVER_PRIVATE_H +#define CAIRO_SURFACE_OBSERVER_PRIVATE_H + +#include "cairoint.h" + +#include "cairo-device-private.h" +#include "cairo-list-private.h" +#include "cairo-recording-surface-private.h" +#include "cairo-surface-private.h" +#include "cairo-surface-backend-private.h" +#include "cairo-time-private.h" + +struct stat { + double min, max, sum, sum_sq; + unsigned count; +}; + +#define NUM_OPERATORS (CAIRO_OPERATOR_HSL_LUMINOSITY+1) +#define NUM_CAPS (CAIRO_LINE_CAP_SQUARE+1) +#define NUM_JOINS (CAIRO_LINE_JOIN_BEVEL+1) +#define NUM_ANTIALIAS (CAIRO_ANTIALIAS_BEST+1) +#define NUM_FILL_RULE (CAIRO_FILL_RULE_EVEN_ODD+1) + +struct extents { + struct stat area; + unsigned int bounded, unbounded; +}; + +struct pattern { + unsigned int type[8]; /* native/record/other surface/gradients */ +}; + +struct path { + unsigned int type[5]; /* empty/pixel/rectilinear/straight/curved */ +}; + +struct clip { + unsigned int type[6]; /* none, region, boxes, single path, polygon, general */ +}; + +typedef struct _cairo_observation cairo_observation_t; +typedef struct _cairo_observation_record cairo_observation_record_t; +typedef struct _cairo_device_observer cairo_device_observer_t; + +struct _cairo_observation_record { + cairo_content_t target_content; + int target_width; + int target_height; + + int index; + cairo_operator_t op; + int source; + int mask; + int num_glyphs; + int path; + int fill_rule; + double tolerance; + int antialias; + int clip; + cairo_time_t elapsed; +}; + +struct _cairo_observation { + int num_surfaces; + int num_contexts; + int num_sources_acquired; + + /* XXX put interesting stats here! */ + + struct paint { + cairo_time_t elapsed; + unsigned int count; + struct extents extents; + unsigned int operators[NUM_OPERATORS]; + struct pattern source; + struct clip clip; + unsigned int noop; + + cairo_observation_record_t slowest; + } paint; + + struct mask { + cairo_time_t elapsed; + unsigned int count; + struct extents extents; + unsigned int operators[NUM_OPERATORS]; + struct pattern source; + struct pattern mask; + struct clip clip; + unsigned int noop; + + cairo_observation_record_t slowest; + } mask; + + struct fill { + cairo_time_t elapsed; + unsigned int count; + struct extents extents; + unsigned int operators[NUM_OPERATORS]; + struct pattern source; + struct path path; + unsigned int antialias[NUM_ANTIALIAS]; + unsigned int fill_rule[NUM_FILL_RULE]; + struct clip clip; + unsigned int noop; + + cairo_observation_record_t slowest; + } fill; + + struct stroke { + cairo_time_t elapsed; + unsigned int count; + struct extents extents; + unsigned int operators[NUM_OPERATORS]; + unsigned int caps[NUM_CAPS]; + unsigned int joins[NUM_CAPS]; + unsigned int antialias[NUM_ANTIALIAS]; + struct pattern source; + struct path path; + struct stat line_width; + struct clip clip; + unsigned int noop; + + cairo_observation_record_t slowest; + } stroke; + + struct glyphs { + cairo_time_t elapsed; + unsigned int count; + struct extents extents; + unsigned int operators[NUM_OPERATORS]; + struct pattern source; + struct clip clip; + unsigned int noop; + + cairo_observation_record_t slowest; + } glyphs; + + cairo_array_t timings; + cairo_recording_surface_t *record; +}; + +struct _cairo_device_observer { + cairo_device_t base; + cairo_device_t *target; + + cairo_observation_t log; +}; + +struct callback_list { + cairo_list_t link; + + cairo_surface_observer_callback_t func; + void *data; +}; + +struct _cairo_surface_observer { + cairo_surface_t base; + cairo_surface_t *target; + + cairo_observation_t log; + + cairo_list_t paint_callbacks; + cairo_list_t mask_callbacks; + cairo_list_t fill_callbacks; + cairo_list_t stroke_callbacks; + cairo_list_t glyphs_callbacks; + + cairo_list_t flush_callbacks; + cairo_list_t finish_callbacks; +}; + +#endif /* CAIRO_SURFACE_OBSERVER_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-surface-observer.c b/local/recipes/libs/cairo/source/src/cairo-surface-observer.c new file mode 100644 index 0000000000..9ff21fc271 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-surface-observer.c @@ -0,0 +1,2301 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Intel Corporation. + * + * Contributor(s): + * Chris Wilson + */ + +#include "cairoint.h" + +#include "cairo-surface-observer-private.h" +#include "cairo-surface-observer-inline.h" + +#include "cairo-array-private.h" +#include "cairo-combsort-inline.h" +#include "cairo-composite-rectangles-private.h" +#include "cairo-error-private.h" +#include "cairo-image-surface-private.h" +#include "cairo-list-inline.h" +#include "cairo-pattern-private.h" +#include "cairo-output-stream-private.h" +#include "cairo-recording-surface-private.h" +#include "cairo-surface-subsurface-inline.h" +#include "cairo-reference-count-private.h" + +#if CAIRO_HAS_SCRIPT_SURFACE +#include "cairo-script-private.h" +#endif + +/** + * SECTION:cairo-surface-observer + * @Title: Surface Observer + * @Short_Description: Observing other surfaces + * @See_Also: #cairo_surface_t + * + * A surface that exists solely to watch what another surface is doing. + **/ + +/** + * CAIRO_HAS_OBSERVER_SURFACE: + * + * Defined if the observer surface backend is available. + * This macro can be used to conditionally compile backend-specific code. + * + * Since: 1.12 + **/ + +static const cairo_surface_backend_t _cairo_surface_observer_backend; + +/* observation/stats */ + +static void init_stats (struct stat *s) +{ + s->min = HUGE_VAL; + s->max = -HUGE_VAL; +} + +static void init_extents (struct extents *e) +{ + init_stats (&e->area); +} + +static void init_pattern (struct pattern *p) +{ +} + +static void init_path (struct path *p) +{ +} + +static void init_clip (struct clip *c) +{ +} + +static void init_paint (struct paint *p) +{ + init_extents (&p->extents); + init_pattern (&p->source); + init_clip (&p->clip); +} + +static void init_mask (struct mask *m) +{ + init_extents (&m->extents); + init_pattern (&m->source); + init_pattern (&m->mask); + init_clip (&m->clip); +} + +static void init_fill (struct fill *f) +{ + init_extents (&f->extents); + init_pattern (&f->source); + init_path (&f->path); + init_clip (&f->clip); +} + +static void init_stroke (struct stroke *s) +{ + init_extents (&s->extents); + init_pattern (&s->source); + init_path (&s->path); + init_clip (&s->clip); +} + +static void init_glyphs (struct glyphs *g) +{ + init_extents (&g->extents); + init_pattern (&g->source); + init_clip (&g->clip); +} + +static cairo_status_t +log_init (cairo_observation_t *log, + cairo_bool_t record) +{ + memset (log, 0, sizeof(*log)); + + init_paint (&log->paint); + init_mask (&log->mask); + init_fill (&log->fill); + init_stroke (&log->stroke); + init_glyphs (&log->glyphs); + + _cairo_array_init (&log->timings, sizeof (cairo_observation_record_t)); + + if (record) { + log->record = (cairo_recording_surface_t *) + cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL); + if (unlikely (log->record->base.status)) + return log->record->base.status; + + log->record->optimize_clears = FALSE; + } + + return CAIRO_STATUS_SUCCESS; +} + +static void +log_fini (cairo_observation_t *log) +{ + _cairo_array_fini (&log->timings); + cairo_surface_destroy (&log->record->base); +} + +static cairo_surface_t* +get_pattern_surface (const cairo_pattern_t *pattern) +{ + return ((cairo_surface_pattern_t *)pattern)->surface; +} + +static int +classify_pattern (const cairo_pattern_t *pattern, + const cairo_surface_t *target) +{ + int classify; + + switch (pattern->type) { + case CAIRO_PATTERN_TYPE_SURFACE: + if (get_pattern_surface (pattern)->type == target->type) + classify = 0; + else if (get_pattern_surface (pattern)->type == CAIRO_SURFACE_TYPE_RECORDING) + classify = 1; + else + classify = 2; + break; + default: + case CAIRO_PATTERN_TYPE_SOLID: + classify = 3; + break; + case CAIRO_PATTERN_TYPE_LINEAR: + classify = 4; + break; + case CAIRO_PATTERN_TYPE_RADIAL: + classify = 5; + break; + case CAIRO_PATTERN_TYPE_MESH: + classify = 6; + break; + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + classify = 7; + break; + } + return classify; +} + +static void +add_pattern (struct pattern *stats, + const cairo_pattern_t *pattern, + const cairo_surface_t *target) +{ + stats->type[classify_pattern(pattern, target)]++; +} + +static int +classify_path (const cairo_path_fixed_t *path, + cairo_bool_t is_fill) +{ + int classify; + + /* XXX improve for stroke */ + classify = -1; + if (is_fill) { + if (path->fill_is_empty) + classify = 0; + else if (_cairo_path_fixed_fill_is_rectilinear (path)) + classify = path->fill_maybe_region ? 1 : 2; + } else { + if (_cairo_path_fixed_stroke_is_rectilinear (path)) + classify = 2; + } + if (classify == -1) + classify = 3 + (path->has_curve_to != 0); + + return classify; +} + +static void +add_path (struct path *stats, + const cairo_path_fixed_t *path, + cairo_bool_t is_fill) +{ + stats->type[classify_path(path, is_fill)]++; +} + +static int +classify_clip (const cairo_clip_t *clip) +{ + int classify; + + if (clip == NULL) + classify = 0; + else if (_cairo_clip_is_region (clip)) + classify = 1; + else if (clip->path == NULL) + classify = 2; + else if (clip->path->prev == NULL) + classify = 3; + else if (_cairo_clip_is_polygon (clip)) + classify = 4; + else + classify = 5; + + return classify; +} + +static void +add_clip (struct clip *stats, + const cairo_clip_t *clip) +{ + stats->type[classify_clip (clip)]++; +} + +static void +stats_add (struct stat *s, double v) +{ + if (v < s->min) + s->min = v; + if (v > s->max) + s->max = v; + s->sum += v; + s->sum_sq += v*v; + s->count++; +} + +static void +add_extents (struct extents *stats, + const cairo_composite_rectangles_t *extents) +{ + const cairo_rectangle_int_t *r = extents->is_bounded ? &extents->bounded :&extents->unbounded; + stats_add (&stats->area, r->width * r->height); + stats->bounded += extents->is_bounded != 0; + stats->unbounded += extents->is_bounded == 0; +} + +/* device interface */ + +static void +_cairo_device_observer_lock (void *_device) +{ + cairo_device_observer_t *device = (cairo_device_observer_t *) _device; + cairo_status_t ignored; + + /* cairo_device_acquire() can fail for nil and finished + * devices. We don't care about observing them. */ + ignored = cairo_device_acquire (device->target); +} + +static void +_cairo_device_observer_unlock (void *_device) +{ + cairo_device_observer_t *device = (cairo_device_observer_t *) _device; + cairo_device_release (device->target); +} + +static cairo_status_t +_cairo_device_observer_flush (void *_device) +{ + cairo_device_observer_t *device = (cairo_device_observer_t *) _device; + + if (device->target == NULL) + return CAIRO_STATUS_SUCCESS; + + cairo_device_flush (device->target); + return device->target->status; +} + +static void +_cairo_device_observer_finish (void *_device) +{ + cairo_device_observer_t *device = (cairo_device_observer_t *) _device; + log_fini (&device->log); + cairo_device_finish (device->target); +} + +static void +_cairo_device_observer_destroy (void *_device) +{ + cairo_device_observer_t *device = (cairo_device_observer_t *) _device; + cairo_device_destroy (device->target); + free (device); +} + +static const cairo_device_backend_t _cairo_device_observer_backend = { + CAIRO_INTERNAL_DEVICE_TYPE_OBSERVER, + + _cairo_device_observer_lock, + _cairo_device_observer_unlock, + + _cairo_device_observer_flush, + _cairo_device_observer_finish, + _cairo_device_observer_destroy, +}; + +static cairo_device_t * +_cairo_device_create_observer_internal (cairo_device_t *target, + cairo_bool_t record) +{ + cairo_device_observer_t *device; + cairo_status_t status; + + device = _cairo_calloc (sizeof (cairo_device_observer_t)); + if (unlikely (device == NULL)) + return _cairo_device_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + _cairo_device_init (&device->base, &_cairo_device_observer_backend); + status = log_init (&device->log, record); + if (unlikely (status)) { + free (device); + return _cairo_device_create_in_error (status); + } + + device->target = cairo_device_reference (target); + + return &device->base; +} + +/* surface interface */ + +static cairo_device_observer_t * +to_device (cairo_surface_observer_t *suface) +{ + return (cairo_device_observer_t *)suface->base.device; +} + +static cairo_surface_t * +_cairo_surface_create_observer_internal (cairo_device_t *device, + cairo_surface_t *target) +{ + cairo_surface_observer_t *surface; + cairo_status_t status; + + surface = _cairo_calloc (sizeof (cairo_surface_observer_t)); + if (unlikely (surface == NULL)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + _cairo_surface_init (&surface->base, + &_cairo_surface_observer_backend, device, + target->content, + target->is_vector); + + status = log_init (&surface->log, + ((cairo_device_observer_t *)device)->log.record != NULL); + if (unlikely (status)) { + free (surface); + return _cairo_surface_create_in_error (status); + } + + surface->target = cairo_surface_reference (target); + surface->base.type = surface->target->type; + surface->base.is_clear = surface->target->is_clear; + + cairo_list_init (&surface->paint_callbacks); + cairo_list_init (&surface->mask_callbacks); + cairo_list_init (&surface->fill_callbacks); + cairo_list_init (&surface->stroke_callbacks); + cairo_list_init (&surface->glyphs_callbacks); + + cairo_list_init (&surface->flush_callbacks); + cairo_list_init (&surface->finish_callbacks); + + surface->log.num_surfaces++; + to_device (surface)->log.num_surfaces++; + + return &surface->base; +} + +static inline void +do_callbacks (cairo_surface_observer_t *surface, cairo_list_t *head) +{ + struct callback_list *cb; + + cairo_list_foreach_entry (cb, struct callback_list, head, link) + cb->func (&surface->base, surface->target, cb->data); +} + + +static cairo_status_t +_cairo_surface_observer_finish (void *abstract_surface) +{ + cairo_surface_observer_t *surface = abstract_surface; + + do_callbacks (surface, &surface->finish_callbacks); + + cairo_surface_destroy (surface->target); + log_fini (&surface->log); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_surface_t * +_cairo_surface_observer_create_similar (void *abstract_other, + cairo_content_t content, + int width, int height) +{ + cairo_surface_observer_t *other = abstract_other; + cairo_surface_t *target, *surface; + + target = NULL; + if (other->target->backend->create_similar) + target = other->target->backend->create_similar (other->target, content, + width, height); + if (target == NULL) + target = _cairo_image_surface_create_with_content (content, + width, height); + + surface = _cairo_surface_create_observer_internal (other->base.device, + target); + cairo_surface_destroy (target); + + return surface; +} + +static cairo_surface_t * +_cairo_surface_observer_create_similar_image (void *other, + cairo_format_t format, + int width, int height) +{ + cairo_surface_observer_t *surface = other; + + if (surface->target->backend->create_similar_image) + return surface->target->backend->create_similar_image (surface->target, + format, + width, height); + + return NULL; +} + +static cairo_image_surface_t * +_cairo_surface_observer_map_to_image (void *abstract_surface, + const cairo_rectangle_int_t *extents) +{ + cairo_surface_observer_t *surface = abstract_surface; + return _cairo_surface_map_to_image (surface->target, extents); +} + +static cairo_int_status_t +_cairo_surface_observer_unmap_image (void *abstract_surface, + cairo_image_surface_t *image) +{ + cairo_surface_observer_t *surface = abstract_surface; + return _cairo_surface_unmap_image (surface->target, image); +} + +static void +record_target (cairo_observation_record_t *r, + cairo_surface_t *target) +{ + cairo_rectangle_int_t extents; + + r->target_content = target->content; + if (_cairo_surface_get_extents (target, &extents)) { + r->target_width = extents.width; + r->target_height = extents.height; + } else { + r->target_width = -1; + r->target_height = -1; + } +} + +static cairo_observation_record_t * +record_paint (cairo_observation_record_t *r, + cairo_surface_t *target, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip, + cairo_time_t elapsed) +{ + record_target (r, target); + + r->op = op; + r->source = classify_pattern (source, target); + r->mask = -1; + r->num_glyphs = -1; + r->path = -1; + r->fill_rule = -1; + r->tolerance = -1; + r->antialias = -1; + r->clip = classify_clip (clip); + r->elapsed = elapsed; + + return r; +} + +static cairo_observation_record_t * +record_mask (cairo_observation_record_t *r, + cairo_surface_t *target, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_clip_t *clip, + cairo_time_t elapsed) +{ + record_target (r, target); + + r->op = op; + r->source = classify_pattern (source, target); + r->mask = classify_pattern (mask, target); + r->num_glyphs = -1; + r->path = -1; + r->fill_rule = -1; + r->tolerance = -1; + r->antialias = -1; + r->clip = classify_clip (clip); + r->elapsed = elapsed; + + return r; +} + +static cairo_observation_record_t * +record_fill (cairo_observation_record_t *r, + cairo_surface_t *target, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip, + cairo_time_t elapsed) +{ + record_target (r, target); + + r->op = op; + r->source = classify_pattern (source, target); + r->mask = -1; + r->num_glyphs = -1; + r->path = classify_path (path, TRUE); + r->fill_rule = fill_rule; + r->tolerance = tolerance; + r->antialias = antialias; + r->clip = classify_clip (clip); + r->elapsed = elapsed; + + return r; +} + +static cairo_observation_record_t * +record_stroke (cairo_observation_record_t *r, + cairo_surface_t *target, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip, + cairo_time_t elapsed) +{ + record_target (r, target); + + r->op = op; + r->source = classify_pattern (source, target); + r->mask = -1; + r->num_glyphs = -1; + r->path = classify_path (path, FALSE); + r->fill_rule = -1; + r->tolerance = tolerance; + r->antialias = antialias; + r->clip = classify_clip (clip); + r->elapsed = elapsed; + + return r; +} + +static cairo_observation_record_t * +record_glyphs (cairo_observation_record_t *r, + cairo_surface_t *target, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip, + cairo_time_t elapsed) +{ + record_target (r, target); + + r->op = op; + r->source = classify_pattern (source, target); + r->mask = -1; + r->path = -1; + r->num_glyphs = num_glyphs; + r->fill_rule = -1; + r->tolerance = -1; + r->antialias = -1; + r->clip = classify_clip (clip); + r->elapsed = elapsed; + + return r; +} + +static void +add_record (cairo_observation_t *log, + cairo_observation_record_t *r) +{ + cairo_int_status_t status; + + r->index = log->record ? log->record->commands.num_elements : 0; + + status = _cairo_array_append (&log->timings, r); + assert (status == CAIRO_INT_STATUS_SUCCESS); +} + +static void +_cairo_surface_sync (cairo_surface_t *target, int x, int y) +{ + cairo_rectangle_int_t extents; + + extents.x = x; + extents.y = y; + extents.width = 1; + extents.height = 1; + + _cairo_surface_unmap_image (target, + _cairo_surface_map_to_image (target, + &extents)); +} + +static void +midpt (const cairo_composite_rectangles_t *extents, int *x, int *y) +{ + *x = extents->bounded.x + extents->bounded.width / 2; + *y = extents->bounded.y + extents->bounded.height / 2; +} + +static void +add_record_paint (cairo_observation_t *log, + cairo_surface_t *target, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip, + cairo_time_t elapsed) +{ + cairo_observation_record_t record; + cairo_int_status_t status; + + add_record (log, + record_paint (&record, target, op, source, clip, elapsed)); + + /* We have to bypass the high-level surface layer in case it tries to be + * too smart and discard operations; we need to record exactly what just + * happened on the target. + */ + if (log->record) { + status = log->record->base.backend->paint (&log->record->base, + op, source, clip); + assert (status == CAIRO_INT_STATUS_SUCCESS); + } + + if (_cairo_time_gt (elapsed, log->paint.slowest.elapsed)) + log->paint.slowest = record; + log->paint.elapsed = _cairo_time_add (log->paint.elapsed, elapsed); +} + +static cairo_int_status_t +_cairo_surface_observer_paint (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip) +{ + cairo_surface_observer_t *surface = abstract_surface; + cairo_device_observer_t *device = to_device (surface); + cairo_composite_rectangles_t composite; + cairo_int_status_t status; + cairo_time_t t; + int x, y; + + /* XXX device locking */ + + surface->log.paint.count++; + surface->log.paint.operators[op]++; + add_pattern (&surface->log.paint.source, source, surface->target); + add_clip (&surface->log.paint.clip, clip); + + device->log.paint.count++; + device->log.paint.operators[op]++; + add_pattern (&device->log.paint.source, source, surface->target); + add_clip (&device->log.paint.clip, clip); + + status = _cairo_composite_rectangles_init_for_paint (&composite, + surface->target, + op, source, + clip); + if (unlikely (status)) { + surface->log.paint.noop++; + device->log.paint.noop++; + return status; + } + + midpt (&composite, &x, &y); + + add_extents (&surface->log.paint.extents, &composite); + add_extents (&device->log.paint.extents, &composite); + _cairo_composite_rectangles_fini (&composite); + + t = _cairo_time_get (); + status = _cairo_surface_paint (surface->target, + op, source, + clip); + if (unlikely (status)) + return status; + + _cairo_surface_sync (surface->target, x, y); + t = _cairo_time_get_delta (t); + + add_record_paint (&surface->log, surface->target, op, source, clip, t); + add_record_paint (&device->log, surface->target, op, source, clip, t); + + do_callbacks (surface, &surface->paint_callbacks); + + return CAIRO_STATUS_SUCCESS; +} + +static void +add_record_mask (cairo_observation_t *log, + cairo_surface_t *target, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_clip_t *clip, + cairo_time_t elapsed) +{ + cairo_observation_record_t record; + cairo_int_status_t status; + + add_record (log, + record_mask (&record, target, op, source, mask, clip, elapsed)); + + if (log->record) { + status = log->record->base.backend->mask (&log->record->base, + op, source, mask, clip); + assert (status == CAIRO_INT_STATUS_SUCCESS); + } + + if (_cairo_time_gt (elapsed, log->mask.slowest.elapsed)) + log->mask.slowest = record; + log->mask.elapsed = _cairo_time_add (log->mask.elapsed, elapsed); +} + +static cairo_int_status_t +_cairo_surface_observer_mask (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_clip_t *clip) +{ + cairo_surface_observer_t *surface = abstract_surface; + cairo_device_observer_t *device = to_device (surface); + cairo_composite_rectangles_t composite; + cairo_int_status_t status; + cairo_time_t t; + int x, y; + + surface->log.mask.count++; + surface->log.mask.operators[op]++; + add_pattern (&surface->log.mask.source, source, surface->target); + add_pattern (&surface->log.mask.mask, mask, surface->target); + add_clip (&surface->log.mask.clip, clip); + + device->log.mask.count++; + device->log.mask.operators[op]++; + add_pattern (&device->log.mask.source, source, surface->target); + add_pattern (&device->log.mask.mask, mask, surface->target); + add_clip (&device->log.mask.clip, clip); + + status = _cairo_composite_rectangles_init_for_mask (&composite, + surface->target, + op, source, mask, + clip); + if (unlikely (status)) { + surface->log.mask.noop++; + device->log.mask.noop++; + return status; + } + + midpt (&composite, &x, &y); + + add_extents (&surface->log.mask.extents, &composite); + add_extents (&device->log.mask.extents, &composite); + _cairo_composite_rectangles_fini (&composite); + + t = _cairo_time_get (); + status = _cairo_surface_mask (surface->target, + op, source, mask, + clip); + if (unlikely (status)) + return status; + + _cairo_surface_sync (surface->target, x, y); + t = _cairo_time_get_delta (t); + + add_record_mask (&surface->log, + surface->target, op, source, mask, clip, + t); + add_record_mask (&device->log, + surface->target, op, source, mask, clip, + t); + + do_callbacks (surface, &surface->mask_callbacks); + + return CAIRO_STATUS_SUCCESS; +} + +static void +add_record_fill (cairo_observation_t *log, + cairo_surface_t *target, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip, + cairo_time_t elapsed) +{ + cairo_observation_record_t record; + cairo_int_status_t status; + + add_record (log, + record_fill (&record, + target, op, source, + path, fill_rule, tolerance, antialias, + clip, elapsed)); + + if (log->record) { + status = log->record->base.backend->fill (&log->record->base, + op, source, + path, fill_rule, + tolerance, antialias, + clip); + assert (status == CAIRO_INT_STATUS_SUCCESS); + } + + if (_cairo_time_gt (elapsed, log->fill.slowest.elapsed)) + log->fill.slowest = record; + log->fill.elapsed = _cairo_time_add (log->fill.elapsed, elapsed); +} + +static cairo_int_status_t +_cairo_surface_observer_fill (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_surface_observer_t *surface = abstract_surface; + cairo_device_observer_t *device = to_device (surface); + cairo_composite_rectangles_t composite; + cairo_int_status_t status; + cairo_time_t t; + int x, y; + + surface->log.fill.count++; + surface->log.fill.operators[op]++; + surface->log.fill.fill_rule[fill_rule]++; + surface->log.fill.antialias[antialias]++; + add_pattern (&surface->log.fill.source, source, surface->target); + add_path (&surface->log.fill.path, path, TRUE); + add_clip (&surface->log.fill.clip, clip); + + device->log.fill.count++; + device->log.fill.operators[op]++; + device->log.fill.fill_rule[fill_rule]++; + device->log.fill.antialias[antialias]++; + add_pattern (&device->log.fill.source, source, surface->target); + add_path (&device->log.fill.path, path, TRUE); + add_clip (&device->log.fill.clip, clip); + + status = _cairo_composite_rectangles_init_for_fill (&composite, + surface->target, + op, source, path, + clip); + if (unlikely (status)) { + surface->log.fill.noop++; + device->log.fill.noop++; + return status; + } + + midpt (&composite, &x, &y); + + add_extents (&surface->log.fill.extents, &composite); + add_extents (&device->log.fill.extents, &composite); + _cairo_composite_rectangles_fini (&composite); + + t = _cairo_time_get (); + status = _cairo_surface_fill (surface->target, + op, source, path, + fill_rule, tolerance, antialias, + clip); + if (unlikely (status)) + return status; + + _cairo_surface_sync (surface->target, x, y); + t = _cairo_time_get_delta (t); + + add_record_fill (&surface->log, + surface->target, op, source, path, + fill_rule, tolerance, antialias, + clip, t); + + add_record_fill (&device->log, + surface->target, op, source, path, + fill_rule, tolerance, antialias, + clip, t); + + do_callbacks (surface, &surface->fill_callbacks); + + return CAIRO_STATUS_SUCCESS; +} + +static void +add_record_stroke (cairo_observation_t *log, + cairo_surface_t *target, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip, + cairo_time_t elapsed) +{ + cairo_observation_record_t record; + cairo_int_status_t status; + + add_record (log, + record_stroke (&record, + target, op, source, + path, style, ctm,ctm_inverse, + tolerance, antialias, + clip, elapsed)); + + if (log->record) { + status = log->record->base.backend->stroke (&log->record->base, + op, source, + path, style, ctm,ctm_inverse, + tolerance, antialias, + clip); + assert (status == CAIRO_INT_STATUS_SUCCESS); + } + + if (_cairo_time_gt (elapsed, log->stroke.slowest.elapsed)) + log->stroke.slowest = record; + log->stroke.elapsed = _cairo_time_add (log->stroke.elapsed, elapsed); +} + +static cairo_int_status_t +_cairo_surface_observer_stroke (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_surface_observer_t *surface = abstract_surface; + cairo_device_observer_t *device = to_device (surface); + cairo_composite_rectangles_t composite; + cairo_int_status_t status; + cairo_time_t t; + int x, y; + + surface->log.stroke.count++; + surface->log.stroke.operators[op]++; + surface->log.stroke.antialias[antialias]++; + surface->log.stroke.caps[style->line_cap]++; + surface->log.stroke.joins[style->line_join]++; + add_pattern (&surface->log.stroke.source, source, surface->target); + add_path (&surface->log.stroke.path, path, FALSE); + add_clip (&surface->log.stroke.clip, clip); + + device->log.stroke.count++; + device->log.stroke.operators[op]++; + device->log.stroke.antialias[antialias]++; + device->log.stroke.caps[style->line_cap]++; + device->log.stroke.joins[style->line_join]++; + add_pattern (&device->log.stroke.source, source, surface->target); + add_path (&device->log.stroke.path, path, FALSE); + add_clip (&device->log.stroke.clip, clip); + + status = _cairo_composite_rectangles_init_for_stroke (&composite, + surface->target, + op, source, + path, style, ctm, + clip); + if (unlikely (status)) { + surface->log.stroke.noop++; + device->log.stroke.noop++; + return status; + } + + midpt (&composite, &x, &y); + + add_extents (&surface->log.stroke.extents, &composite); + add_extents (&device->log.stroke.extents, &composite); + _cairo_composite_rectangles_fini (&composite); + + t = _cairo_time_get (); + status = _cairo_surface_stroke (surface->target, + op, source, path, + style, ctm, ctm_inverse, + tolerance, antialias, + clip); + if (unlikely (status)) + return status; + + _cairo_surface_sync (surface->target, x, y); + t = _cairo_time_get_delta (t); + + add_record_stroke (&surface->log, + surface->target, op, source, path, + style, ctm,ctm_inverse, + tolerance, antialias, + clip, t); + + add_record_stroke (&device->log, + surface->target, op, source, path, + style, ctm,ctm_inverse, + tolerance, antialias, + clip, t); + + do_callbacks (surface, &surface->stroke_callbacks); + + return CAIRO_STATUS_SUCCESS; +} + +static void +add_record_glyphs (cairo_observation_t *log, + cairo_surface_t *target, + cairo_operator_t op, + const cairo_pattern_t*source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip, + cairo_time_t elapsed) +{ + cairo_observation_record_t record; + cairo_int_status_t status; + + add_record (log, + record_glyphs (&record, + target, op, source, + glyphs, num_glyphs, scaled_font, + clip, elapsed)); + + if (log->record) { + status = log->record->base.backend->show_text_glyphs (&log->record->base, + op, source, + NULL, 0, + glyphs, num_glyphs, + NULL, 0, 0, + scaled_font, + clip); + assert (status == CAIRO_INT_STATUS_SUCCESS); + } + + if (_cairo_time_gt (elapsed, log->glyphs.slowest.elapsed)) + log->glyphs.slowest = record; + log->glyphs.elapsed = _cairo_time_add (log->glyphs.elapsed, elapsed); +} + +static cairo_int_status_t +_cairo_surface_observer_glyphs (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip) +{ + cairo_surface_observer_t *surface = abstract_surface; + cairo_device_observer_t *device = to_device (surface); + cairo_composite_rectangles_t composite; + cairo_int_status_t status; + cairo_glyph_t *dev_glyphs; + cairo_time_t t; + int x, y; + + surface->log.glyphs.count++; + surface->log.glyphs.operators[op]++; + add_pattern (&surface->log.glyphs.source, source, surface->target); + add_clip (&surface->log.glyphs.clip, clip); + + device->log.glyphs.count++; + device->log.glyphs.operators[op]++; + add_pattern (&device->log.glyphs.source, source, surface->target); + add_clip (&device->log.glyphs.clip, clip); + + status = _cairo_composite_rectangles_init_for_glyphs (&composite, + surface->target, + op, source, + scaled_font, + glyphs, num_glyphs, + clip, + NULL); + if (unlikely (status)) { + surface->log.glyphs.noop++; + device->log.glyphs.noop++; + return status; + } + + midpt (&composite, &x, &y); + + add_extents (&surface->log.glyphs.extents, &composite); + add_extents (&device->log.glyphs.extents, &composite); + _cairo_composite_rectangles_fini (&composite); + + /* XXX We have to copy the glyphs, because the backend is allowed to + * modify! */ + dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); + if (unlikely (dev_glyphs == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + memcpy (dev_glyphs, glyphs, num_glyphs * sizeof (cairo_glyph_t)); + + t = _cairo_time_get (); + status = _cairo_surface_show_text_glyphs (surface->target, op, source, + NULL, 0, + dev_glyphs, num_glyphs, + NULL, 0, 0, + scaled_font, + clip); + free (dev_glyphs); + if (unlikely (status)) + return status; + + _cairo_surface_sync (surface->target, x, y); + t = _cairo_time_get_delta (t); + + add_record_glyphs (&surface->log, + surface->target, op, source, + glyphs, num_glyphs, scaled_font, + clip, t); + + add_record_glyphs (&device->log, + surface->target, op, source, + glyphs, num_glyphs, scaled_font, + clip, t); + + do_callbacks (surface, &surface->glyphs_callbacks); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_surface_observer_flush (void *abstract_surface, unsigned flags) +{ + cairo_surface_observer_t *surface = abstract_surface; + + do_callbacks (surface, &surface->flush_callbacks); + return _cairo_surface_flush (surface->target, flags); +} + +static cairo_status_t +_cairo_surface_observer_mark_dirty (void *abstract_surface, + int x, int y, + int width, int height) +{ + cairo_surface_observer_t *surface = abstract_surface; + cairo_status_t status; + + status = CAIRO_STATUS_SUCCESS; + if (surface->target->backend->mark_dirty_rectangle) + status = surface->target->backend->mark_dirty_rectangle (surface->target, + x,y, width,height); + + return status; +} + +static cairo_int_status_t +_cairo_surface_observer_copy_page (void *abstract_surface) +{ + cairo_surface_observer_t *surface = abstract_surface; + cairo_status_t status; + + status = CAIRO_STATUS_SUCCESS; + if (surface->target->backend->copy_page) + status = surface->target->backend->copy_page (surface->target); + + return status; +} + +static cairo_int_status_t +_cairo_surface_observer_show_page (void *abstract_surface) +{ + cairo_surface_observer_t *surface = abstract_surface; + cairo_status_t status; + + status = CAIRO_STATUS_SUCCESS; + if (surface->target->backend->show_page) + status = surface->target->backend->show_page (surface->target); + + return status; +} + +static cairo_bool_t +_cairo_surface_observer_get_extents (void *abstract_surface, + cairo_rectangle_int_t *extents) +{ + cairo_surface_observer_t *surface = abstract_surface; + return _cairo_surface_get_extents (surface->target, extents); +} + +static void +_cairo_surface_observer_get_font_options (void *abstract_surface, + cairo_font_options_t *options) +{ + cairo_surface_observer_t *surface = abstract_surface; + + if (surface->target->backend->get_font_options != NULL) + surface->target->backend->get_font_options (surface->target, options); +} + +static cairo_surface_t * +_cairo_surface_observer_source (void *abstract_surface, + cairo_rectangle_int_t *extents) +{ + cairo_surface_observer_t *surface = abstract_surface; + return _cairo_surface_get_source (surface->target, extents); +} + +static cairo_status_t +_cairo_surface_observer_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) +{ + cairo_surface_observer_t *surface = abstract_surface; + + surface->log.num_sources_acquired++; + to_device (surface)->log.num_sources_acquired++; + + return _cairo_surface_acquire_source_image (surface->target, + image_out, image_extra); +} + +static void +_cairo_surface_observer_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) +{ + cairo_surface_observer_t *surface = abstract_surface; + + _cairo_surface_release_source_image (surface->target, image, image_extra); +} + +static cairo_surface_t * +_cairo_surface_observer_snapshot (void *abstract_surface) +{ + cairo_surface_observer_t *surface = abstract_surface; + + /* XXX hook onto the snapshot so that we measure number of reads */ + + if (surface->target->backend->snapshot) + return surface->target->backend->snapshot (surface->target); + + return NULL; +} + +static cairo_t * +_cairo_surface_observer_create_context(void *target) +{ + cairo_surface_observer_t *surface = target; + + if (_cairo_surface_is_subsurface (&surface->base)) + surface = (cairo_surface_observer_t *) + _cairo_surface_subsurface_get_target (&surface->base); + + surface->log.num_contexts++; + to_device (surface)->log.num_contexts++; + + return surface->target->backend->create_context (target); +} + +static const cairo_surface_backend_t _cairo_surface_observer_backend = { + CAIRO_INTERNAL_SURFACE_TYPE_OBSERVER, + _cairo_surface_observer_finish, + + _cairo_surface_observer_create_context, + + _cairo_surface_observer_create_similar, + _cairo_surface_observer_create_similar_image, + _cairo_surface_observer_map_to_image, + _cairo_surface_observer_unmap_image, + + _cairo_surface_observer_source, + _cairo_surface_observer_acquire_source_image, + _cairo_surface_observer_release_source_image, + _cairo_surface_observer_snapshot, + + _cairo_surface_observer_copy_page, + _cairo_surface_observer_show_page, + + _cairo_surface_observer_get_extents, + _cairo_surface_observer_get_font_options, + + _cairo_surface_observer_flush, + _cairo_surface_observer_mark_dirty, + + _cairo_surface_observer_paint, + _cairo_surface_observer_mask, + _cairo_surface_observer_stroke, + _cairo_surface_observer_fill, + NULL, /* fill-stroke */ + _cairo_surface_observer_glyphs, +}; + +/** + * cairo_surface_create_observer: + * @target: an existing surface for which the observer will watch + * @mode: sets the mode of operation (normal vs. record) + * + * Create a new surface that exists solely to watch another is doing. In + * the process it will log operations and times, which are fast, which are + * slow, which are frequent, etc. + * + * The @mode parameter can be set to either %CAIRO_SURFACE_OBSERVER_NORMAL + * or %CAIRO_SURFACE_OBSERVER_RECORD_OPERATIONS, to control whether or not + * the internal observer should record operations. + * + * Return value: a pointer to the newly allocated surface. The caller + * owns the surface and should call cairo_surface_destroy() when done + * with it. + * + * This function always returns a valid pointer, but it will return a + * pointer to a "nil" surface if @other is already in an error state + * or any other error occurs. + * + * Since: 1.12 + **/ +cairo_surface_t * +cairo_surface_create_observer (cairo_surface_t *target, + cairo_surface_observer_mode_t mode) +{ + cairo_device_t *device; + cairo_surface_t *surface; + cairo_bool_t record; + + if (unlikely (target->status)) + return _cairo_surface_create_in_error (target->status); + if (unlikely (target->finished)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + + record = mode & CAIRO_SURFACE_OBSERVER_RECORD_OPERATIONS; + device = _cairo_device_create_observer_internal (target->device, record); + if (unlikely (device->status)) + return _cairo_surface_create_in_error (device->status); + + surface = _cairo_surface_create_observer_internal (device, target); + cairo_device_destroy (device); + + return surface; +} + +static cairo_status_t +_cairo_surface_observer_add_callback (cairo_list_t *head, + cairo_surface_observer_callback_t func, + void *data) +{ + struct callback_list *cb; + + cb = _cairo_calloc (sizeof (*cb)); + if (unlikely (cb == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + cairo_list_add (&cb->link, head); + cb->func = func; + cb->data = data; + + return CAIRO_STATUS_SUCCESS; +} + +/** + * cairo_surface_observer_add_paint_callback: + * @abstract_surface: a #cairo_surface_observer_t + * @func: callback function for paint operations + * @data: closure to pass to the callback + * + * Adds a callback for paint operations on the observed surface. + * + * Returns: the status of the surface + * + * Since: 1.12 + **/ +cairo_status_t +cairo_surface_observer_add_paint_callback (cairo_surface_t *abstract_surface, + cairo_surface_observer_callback_t func, + void *data) +{ + cairo_surface_observer_t *surface; + + if (unlikely (CAIRO_REFERENCE_COUNT_IS_INVALID (&abstract_surface->ref_count))) + return abstract_surface->status; + + if (! _cairo_surface_is_observer (abstract_surface)) + return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + + surface = (cairo_surface_observer_t *)abstract_surface; + return _cairo_surface_observer_add_callback (&surface->paint_callbacks, + func, data); +} + +/** + * cairo_surface_observer_add_mask_callback: + * @abstract_surface: a #cairo_surface_observer_t + * @func: callback function for mask operations + * @data: closure to pass to the callback + * + * Adds a callback for mask operations on the observed surface. + * + * Returns: the status of the surface + * + * Since: 1.12 + **/ +cairo_status_t +cairo_surface_observer_add_mask_callback (cairo_surface_t *abstract_surface, + cairo_surface_observer_callback_t func, + void *data) +{ + cairo_surface_observer_t *surface; + + if (unlikely (CAIRO_REFERENCE_COUNT_IS_INVALID (&abstract_surface->ref_count))) + return abstract_surface->status; + + if (! _cairo_surface_is_observer (abstract_surface)) + return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + + surface = (cairo_surface_observer_t *)abstract_surface; + return _cairo_surface_observer_add_callback (&surface->mask_callbacks, + func, data); +} + +/** + * cairo_surface_observer_add_fill_callback: + * @abstract_surface: a #cairo_surface_observer_t + * @func: callback function for fill operations + * @data: closure to pass to the callback + * + * Adds a callback for fill operations on the observed surface. + * + * Returns: the status of the surface + * + * Since: 1.12 + **/ +cairo_status_t +cairo_surface_observer_add_fill_callback (cairo_surface_t *abstract_surface, + cairo_surface_observer_callback_t func, + void *data) +{ + cairo_surface_observer_t *surface; + + if (unlikely (CAIRO_REFERENCE_COUNT_IS_INVALID (&abstract_surface->ref_count))) + return abstract_surface->status; + + if (! _cairo_surface_is_observer (abstract_surface)) + return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + + surface = (cairo_surface_observer_t *)abstract_surface; + return _cairo_surface_observer_add_callback (&surface->fill_callbacks, + func, data); +} + +/** + * cairo_surface_observer_add_stroke_callback: + * @abstract_surface: a #cairo_surface_observer_t + * @func: callback function for stroke operations + * @data: closure to pass to the callback + * + * Adds a callback for stroke operations on the observed surface. + * + * Returns: the status of the surface + * + * Since: 1.12 + **/ +cairo_status_t +cairo_surface_observer_add_stroke_callback (cairo_surface_t *abstract_surface, + cairo_surface_observer_callback_t func, + void *data) +{ + cairo_surface_observer_t *surface; + + if (unlikely (CAIRO_REFERENCE_COUNT_IS_INVALID (&abstract_surface->ref_count))) + return abstract_surface->status; + + if (! _cairo_surface_is_observer (abstract_surface)) + return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + + surface = (cairo_surface_observer_t *)abstract_surface; + return _cairo_surface_observer_add_callback (&surface->stroke_callbacks, + func, data); +} + +/** + * cairo_surface_observer_add_glyphs_callback: + * @abstract_surface: a #cairo_surface_observer_t + * @func: callback function for glyph operations + * @data: closure to pass to the callback + * + * Adds a callback for glyph operations on the observed surface. + * + * Returns: the status of the surface + * + * Since: 1.10 + **/ +cairo_status_t +cairo_surface_observer_add_glyphs_callback (cairo_surface_t *abstract_surface, + cairo_surface_observer_callback_t func, + void *data) +{ + cairo_surface_observer_t *surface; + + if (unlikely (CAIRO_REFERENCE_COUNT_IS_INVALID (&abstract_surface->ref_count))) + return abstract_surface->status; + + if (! _cairo_surface_is_observer (abstract_surface)) + return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + + surface = (cairo_surface_observer_t *)abstract_surface; + return _cairo_surface_observer_add_callback (&surface->glyphs_callbacks, + func, data); +} + +/** + * cairo_surface_observer_add_flush_callback: + * @abstract_surface: a #cairo_surface_observer_t + * @func: callback for flush operations + * @data: closure to pass to the callback + * + * Adds a callback for flush operations on the observed surface. + * + * Returns: the status of the surface + * + * Since: 1.10 + **/ +cairo_status_t +cairo_surface_observer_add_flush_callback (cairo_surface_t *abstract_surface, + cairo_surface_observer_callback_t func, + void *data) +{ + cairo_surface_observer_t *surface; + + if (unlikely (CAIRO_REFERENCE_COUNT_IS_INVALID (&abstract_surface->ref_count))) + return abstract_surface->status; + + if (! _cairo_surface_is_observer (abstract_surface)) + return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + + surface = (cairo_surface_observer_t *)abstract_surface; + return _cairo_surface_observer_add_callback (&surface->flush_callbacks, + func, data); +} + +/** + * cairo_surface_observer_add_finish_callback: + * @abstract_surface: a #cairo_surface_observer_t + * @func: callback function for the finish operation + * @data: closure to pass to the callback + * + * Adds a callback for finish operations on the observed surface. + * + * Returns: the status of the surface + * + * Since: 1.10 + **/ +cairo_status_t +cairo_surface_observer_add_finish_callback (cairo_surface_t *abstract_surface, + cairo_surface_observer_callback_t func, + void *data) +{ + cairo_surface_observer_t *surface; + + if (unlikely (CAIRO_REFERENCE_COUNT_IS_INVALID (&abstract_surface->ref_count))) + return abstract_surface->status; + + if (! _cairo_surface_is_observer (abstract_surface)) + return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + + surface = (cairo_surface_observer_t *)abstract_surface; + return _cairo_surface_observer_add_callback (&surface->finish_callbacks, + func, data); +} + +static void +print_extents (cairo_output_stream_t *stream, const struct extents *e) +{ + _cairo_output_stream_printf (stream, + " extents: total %g, avg %g [unbounded %d]\n", + e->area.sum, + e->area.sum / e->area.count, + e->unbounded); +} + +static inline int ordercmp (int a, int b, const unsigned int *array) +{ + /* high to low */ + return array[b] - array[a]; +} +CAIRO_COMBSORT_DECLARE_WITH_DATA (sort_order, int, ordercmp) + +static void +print_array (cairo_output_stream_t *stream, + const unsigned int *array, + const char **names, + int count) +{ + int order[64]; + int i, j; + + assert (count < ARRAY_LENGTH (order)); + for (i = j = 0; i < count; i++) { + if (array[i] != 0) + order[j++] = i; + } + + sort_order (order, j, (void *)array); + for (i = 0; i < j; i++) + _cairo_output_stream_printf (stream, " %d %s%s", + array[order[i]], names[order[i]], + i < j -1 ? "," : ""); +} + +static const char *operator_names[] = { + "CLEAR", /* CAIRO_OPERATOR_CLEAR */ + + "SOURCE", /* CAIRO_OPERATOR_SOURCE */ + "OVER", /* CAIRO_OPERATOR_OVER */ + "IN", /* CAIRO_OPERATOR_IN */ + "OUT", /* CAIRO_OPERATOR_OUT */ + "ATOP", /* CAIRO_OPERATOR_ATOP */ + + "DEST", /* CAIRO_OPERATOR_DEST */ + "DEST_OVER", /* CAIRO_OPERATOR_DEST_OVER */ + "DEST_IN", /* CAIRO_OPERATOR_DEST_IN */ + "DEST_OUT", /* CAIRO_OPERATOR_DEST_OUT */ + "DEST_ATOP", /* CAIRO_OPERATOR_DEST_ATOP */ + + "XOR", /* CAIRO_OPERATOR_XOR */ + "ADD", /* CAIRO_OPERATOR_ADD */ + "SATURATE", /* CAIRO_OPERATOR_SATURATE */ + + "MULTIPLY", /* CAIRO_OPERATOR_MULTIPLY */ + "SCREEN", /* CAIRO_OPERATOR_SCREEN */ + "OVERLAY", /* CAIRO_OPERATOR_OVERLAY */ + "DARKEN", /* CAIRO_OPERATOR_DARKEN */ + "LIGHTEN", /* CAIRO_OPERATOR_LIGHTEN */ + "DODGE", /* CAIRO_OPERATOR_COLOR_DODGE */ + "BURN", /* CAIRO_OPERATOR_COLOR_BURN */ + "HARD_LIGHT", /* CAIRO_OPERATOR_HARD_LIGHT */ + "SOFT_LIGHT", /* CAIRO_OPERATOR_SOFT_LIGHT */ + "DIFFERENCE", /* CAIRO_OPERATOR_DIFFERENCE */ + "EXCLUSION", /* CAIRO_OPERATOR_EXCLUSION */ + "HSL_HUE", /* CAIRO_OPERATOR_HSL_HUE */ + "HSL_SATURATION", /* CAIRO_OPERATOR_HSL_SATURATION */ + "HSL_COLOR", /* CAIRO_OPERATOR_HSL_COLOR */ + "HSL_LUMINOSITY" /* CAIRO_OPERATOR_HSL_LUMINOSITY */ +}; +static void +print_operators (cairo_output_stream_t *stream, unsigned int *array) +{ + _cairo_output_stream_printf (stream, " op:"); + print_array (stream, array, operator_names, NUM_OPERATORS); + _cairo_output_stream_printf (stream, "\n"); +} + +static const char *fill_rule_names[] = { + "non-zero", + "even-odd", +}; +static void +print_fill_rule (cairo_output_stream_t *stream, unsigned int *array) +{ + _cairo_output_stream_printf (stream, " fill rule:"); + print_array (stream, array, fill_rule_names, ARRAY_LENGTH(fill_rule_names)); + _cairo_output_stream_printf (stream, "\n"); +} + +static const char *cap_names[] = { + "butt", /* CAIRO_LINE_CAP_BUTT */ + "round", /* CAIRO_LINE_CAP_ROUND */ + "square" /* CAIRO_LINE_CAP_SQUARE */ +}; +static void +print_line_caps (cairo_output_stream_t *stream, unsigned int *array) +{ + _cairo_output_stream_printf (stream, " caps:"); + print_array (stream, array, cap_names, NUM_CAPS); + _cairo_output_stream_printf (stream, "\n"); +} + +static const char *join_names[] = { + "miter", /* CAIRO_LINE_JOIN_MITER */ + "round", /* CAIRO_LINE_JOIN_ROUND */ + "bevel", /* CAIRO_LINE_JOIN_BEVEL */ +}; +static void +print_line_joins (cairo_output_stream_t *stream, unsigned int *array) +{ + _cairo_output_stream_printf (stream, " joins:"); + print_array (stream, array, join_names, NUM_JOINS); + _cairo_output_stream_printf (stream, "\n"); +} + +static const char *antialias_names[] = { + "default", + "none", + "gray", + "subpixel", + "fast", + "good", + "best" +}; +static void +print_antialias (cairo_output_stream_t *stream, unsigned int *array) +{ + _cairo_output_stream_printf (stream, " antialias:"); + print_array (stream, array, antialias_names, NUM_ANTIALIAS); + _cairo_output_stream_printf (stream, "\n"); +} + +static const char *pattern_names[] = { + "native", + "record", + "other surface", + "solid", + "linear", + "radial", + "mesh", + "raster" +}; +static void +print_pattern (cairo_output_stream_t *stream, + const char *name, + const struct pattern *p) +{ + _cairo_output_stream_printf (stream, " %s:", name); + print_array (stream, p->type, pattern_names, ARRAY_LENGTH (pattern_names)); + _cairo_output_stream_printf (stream, "\n"); +} + +static const char *path_names[] = { + "empty", + "pixel-aligned", + "rectliinear", + "straight", + "curved", +}; +static void +print_path (cairo_output_stream_t *stream, + const struct path *p) +{ + _cairo_output_stream_printf (stream, " path:"); + print_array (stream, p->type, path_names, ARRAY_LENGTH (path_names)); + _cairo_output_stream_printf (stream, "\n"); +} + +static const char *clip_names[] = { + "none", + "region", + "boxes", + "single path", + "polygon", + "general", +}; +static void +print_clip (cairo_output_stream_t *stream, const struct clip *c) +{ + _cairo_output_stream_printf (stream, " clip:"); + print_array (stream, c->type, clip_names, ARRAY_LENGTH (clip_names)); + _cairo_output_stream_printf (stream, "\n"); +} + +static void +print_record (cairo_output_stream_t *stream, + cairo_observation_record_t *r) +{ + _cairo_output_stream_printf (stream, " op: %s\n", operator_names[r->op]); + _cairo_output_stream_printf (stream, " source: %s\n", + pattern_names[r->source]); + if (r->mask != -1) + _cairo_output_stream_printf (stream, " mask: %s\n", + pattern_names[r->mask]); + if (r->num_glyphs != -1) + _cairo_output_stream_printf (stream, " num_glyphs: %d\n", + r->num_glyphs); + if (r->path != -1) + _cairo_output_stream_printf (stream, " path: %s\n", + path_names[r->path]); + if (r->fill_rule != -1) + _cairo_output_stream_printf (stream, " fill rule: %s\n", + fill_rule_names[r->fill_rule]); + if (r->antialias != -1) + _cairo_output_stream_printf (stream, " antialias: %s\n", + antialias_names[r->antialias]); + _cairo_output_stream_printf (stream, " clip: %s\n", clip_names[r->clip]); + _cairo_output_stream_printf (stream, " elapsed: %f ns\n", + _cairo_time_to_ns (r->elapsed)); +} + +static double percent (cairo_time_t a, cairo_time_t b) +{ + /* Fake %.1f */ + return _cairo_round (_cairo_time_to_s (a) * 1000 / + _cairo_time_to_s (b)) / 10; +} + +static cairo_bool_t +replay_record (cairo_observation_t *log, + cairo_observation_record_t *r, + cairo_device_t *script) +{ +#if CAIRO_HAS_SCRIPT_SURFACE + cairo_surface_t *surface; + cairo_int_status_t status; + + if (log->record == NULL || script == NULL) + return FALSE; + + surface = cairo_script_surface_create (script, + r->target_content, + r->target_width, + r->target_height); + status = + _cairo_recording_surface_replay_one (log->record, r->index, surface); + cairo_surface_destroy (surface); + + assert (status == CAIRO_INT_STATUS_SUCCESS); + + return TRUE; +#else + return FALSE; +#endif +} + +static cairo_time_t +_cairo_observation_total_elapsed (cairo_observation_t *log) +{ + cairo_time_t total; + + total = log->paint.elapsed; + total = _cairo_time_add (total, log->mask.elapsed); + total = _cairo_time_add (total, log->fill.elapsed); + total = _cairo_time_add (total, log->stroke.elapsed); + total = _cairo_time_add (total, log->glyphs.elapsed); + + return total; +} + +static void +_cairo_observation_print (cairo_output_stream_t *stream, + cairo_observation_t *log) +{ + cairo_device_t *script; + cairo_time_t total; + +#if CAIRO_HAS_SCRIPT_SURFACE + script = _cairo_script_context_create_internal (stream); + _cairo_script_context_attach_snapshots (script, FALSE); +#else + script = NULL; +#endif + + total = _cairo_observation_total_elapsed (log); + + _cairo_output_stream_printf (stream, "elapsed: %f\n", + _cairo_time_to_ns (total)); + _cairo_output_stream_printf (stream, "surfaces: %d\n", + log->num_surfaces); + _cairo_output_stream_printf (stream, "contexts: %d\n", + log->num_contexts); + _cairo_output_stream_printf (stream, "sources acquired: %d\n", + log->num_sources_acquired); + + + _cairo_output_stream_printf (stream, "paint: count %d [no-op %d], elapsed %f [%f%%]\n", + log->paint.count, log->paint.noop, + _cairo_time_to_ns (log->paint.elapsed), + percent (log->paint.elapsed, total)); + if (log->paint.count) { + print_extents (stream, &log->paint.extents); + print_operators (stream, log->paint.operators); + print_pattern (stream, "source", &log->paint.source); + print_clip (stream, &log->paint.clip); + + _cairo_output_stream_printf (stream, "slowest paint: %f%%\n", + percent (log->paint.slowest.elapsed, + log->paint.elapsed)); + print_record (stream, &log->paint.slowest); + + _cairo_output_stream_printf (stream, "\n"); + if (replay_record (log, &log->paint.slowest, script)) + _cairo_output_stream_printf (stream, "\n\n"); + } + + _cairo_output_stream_printf (stream, "mask: count %d [no-op %d], elapsed %f [%f%%]\n", + log->mask.count, log->mask.noop, + _cairo_time_to_ns (log->mask.elapsed), + percent (log->mask.elapsed, total)); + if (log->mask.count) { + print_extents (stream, &log->mask.extents); + print_operators (stream, log->mask.operators); + print_pattern (stream, "source", &log->mask.source); + print_pattern (stream, "mask", &log->mask.mask); + print_clip (stream, &log->mask.clip); + + _cairo_output_stream_printf (stream, "slowest mask: %f%%\n", + percent (log->mask.slowest.elapsed, + log->mask.elapsed)); + print_record (stream, &log->mask.slowest); + + _cairo_output_stream_printf (stream, "\n"); + if (replay_record (log, &log->mask.slowest, script)) + _cairo_output_stream_printf (stream, "\n\n"); + } + + _cairo_output_stream_printf (stream, "fill: count %d [no-op %d], elaspsed %f [%f%%]\n", + log->fill.count, log->fill.noop, + _cairo_time_to_ns (log->fill.elapsed), + percent (log->fill.elapsed, total)); + if (log->fill.count) { + print_extents (stream, &log->fill.extents); + print_operators (stream, log->fill.operators); + print_pattern (stream, "source", &log->fill.source); + print_path (stream, &log->fill.path); + print_fill_rule (stream, log->fill.fill_rule); + print_antialias (stream, log->fill.antialias); + print_clip (stream, &log->fill.clip); + + _cairo_output_stream_printf (stream, "slowest fill: %f%%\n", + percent (log->fill.slowest.elapsed, + log->fill.elapsed)); + print_record (stream, &log->fill.slowest); + + _cairo_output_stream_printf (stream, "\n"); + if (replay_record (log, &log->fill.slowest, script)) + _cairo_output_stream_printf (stream, "\n\n"); + } + + _cairo_output_stream_printf (stream, "stroke: count %d [no-op %d], elapsed %f [%f%%]\n", + log->stroke.count, log->stroke.noop, + _cairo_time_to_ns (log->stroke.elapsed), + percent (log->stroke.elapsed, total)); + if (log->stroke.count) { + print_extents (stream, &log->stroke.extents); + print_operators (stream, log->stroke.operators); + print_pattern (stream, "source", &log->stroke.source); + print_path (stream, &log->stroke.path); + print_antialias (stream, log->stroke.antialias); + print_line_caps (stream, log->stroke.caps); + print_line_joins (stream, log->stroke.joins); + print_clip (stream, &log->stroke.clip); + + _cairo_output_stream_printf (stream, "slowest stroke: %f%%\n", + percent (log->stroke.slowest.elapsed, + log->stroke.elapsed)); + print_record (stream, &log->stroke.slowest); + + _cairo_output_stream_printf (stream, "\n"); + if (replay_record (log, &log->stroke.slowest, script)) + _cairo_output_stream_printf (stream, "\n\n"); + } + + _cairo_output_stream_printf (stream, "glyphs: count %d [no-op %d], elasped %f [%f%%]\n", + log->glyphs.count, log->glyphs.noop, + _cairo_time_to_ns (log->glyphs.elapsed), + percent (log->glyphs.elapsed, total)); + if (log->glyphs.count) { + print_extents (stream, &log->glyphs.extents); + print_operators (stream, log->glyphs.operators); + print_pattern (stream, "source", &log->glyphs.source); + print_clip (stream, &log->glyphs.clip); + + _cairo_output_stream_printf (stream, "slowest glyphs: %f%%\n", + percent (log->glyphs.slowest.elapsed, + log->glyphs.elapsed)); + print_record (stream, &log->glyphs.slowest); + + _cairo_output_stream_printf (stream, "\n"); + if (replay_record (log, &log->glyphs.slowest, script)) + _cairo_output_stream_printf (stream, "\n\n"); + } + + cairo_device_destroy (script); +} + +/** + * cairo_surface_observer_print: + * @abstract_surface: a #cairo_surface_observer_t + * @write_func: callback for writing on a stream + * @closure: data to pass to @write_func + * + * Prints the observer log using the given callback. + * + * Returns: the status of the print operation + * + * Since: 1.12 + **/ +cairo_status_t +cairo_surface_observer_print (cairo_surface_t *abstract_surface, + cairo_write_func_t write_func, + void *closure) +{ + cairo_output_stream_t *stream; + cairo_surface_observer_t *surface; + + if (unlikely (abstract_surface->status)) + return abstract_surface->status; + + if (unlikely (! _cairo_surface_is_observer (abstract_surface))) + return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + + surface = (cairo_surface_observer_t *) abstract_surface; + + stream = _cairo_output_stream_create (write_func, NULL, closure); + _cairo_observation_print (stream, &surface->log); + return _cairo_output_stream_destroy (stream); +} + +/** + * cairo_surface_observer_elapsed: + * @abstract_surface: a #cairo_surface_observer_t + * + * Returns the total observation time. + * + * Returns: the elapsed time, in nanoseconds + * + * Since: 1.12 + **/ +double +cairo_surface_observer_elapsed (cairo_surface_t *abstract_surface) +{ + cairo_surface_observer_t *surface; + + if (unlikely (CAIRO_REFERENCE_COUNT_IS_INVALID (&abstract_surface->ref_count))) + return -1; + + if (! _cairo_surface_is_observer (abstract_surface)) + return -1; + + surface = (cairo_surface_observer_t *) abstract_surface; + return _cairo_time_to_ns (_cairo_observation_total_elapsed (&surface->log)); +} + +/** + * cairo_device_observer_print: + * @abstract_device: the observed #cairo_device_t + * @write_func: the write function + * @closure: data to pass to the @write_func + * + * Prints the device log using the given function. + * + * Returns: the status after the operation + * + * Since: 1.12 + **/ +cairo_status_t +cairo_device_observer_print (cairo_device_t *abstract_device, + cairo_write_func_t write_func, + void *closure) +{ + cairo_output_stream_t *stream; + cairo_device_observer_t *device; + + if (unlikely (abstract_device->status)) + return abstract_device->status; + + if (unlikely (! _cairo_device_is_observer (abstract_device))) + return _cairo_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH); + + device = (cairo_device_observer_t *) abstract_device; + + stream = _cairo_output_stream_create (write_func, NULL, closure); + _cairo_observation_print (stream, &device->log); + return _cairo_output_stream_destroy (stream); +} + +/** + * cairo_device_observer_elapsed: + * @abstract_device: the observed #cairo_device_t + * + * Returns the total elapsed time of the observation. + * + * Returns: the elapsed time, in nanoseconds. + * + * Since: 1.12 + **/ +double +cairo_device_observer_elapsed (cairo_device_t *abstract_device) +{ + cairo_device_observer_t *device; + + if (unlikely (CAIRO_REFERENCE_COUNT_IS_INVALID (&abstract_device->ref_count))) + return -1; + + if (! _cairo_device_is_observer (abstract_device)) + return -1; + + device = (cairo_device_observer_t *) abstract_device; + return _cairo_time_to_ns (_cairo_observation_total_elapsed (&device->log)); +} + +/** + * cairo_device_observer_paint_elapsed: + * @abstract_device: the observed #cairo_device_t + * + * Returns the elapsed time of the paint operations. + * + * Returns: the elapsed time, in nanoseconds. + * + * Since: 1.12 + **/ +double +cairo_device_observer_paint_elapsed (cairo_device_t *abstract_device) +{ + cairo_device_observer_t *device; + + if (unlikely (CAIRO_REFERENCE_COUNT_IS_INVALID (&abstract_device->ref_count))) + return -1; + + if (! _cairo_device_is_observer (abstract_device)) + return -1; + + device = (cairo_device_observer_t *) abstract_device; + return _cairo_time_to_ns (device->log.paint.elapsed); +} + +/** + * cairo_device_observer_mask_elapsed: + * @abstract_device: the observed #cairo_device_t + * + * Returns the elapsed time of the mask operations. + * + * Returns: the elapsed time, in nanoseconds + * + * Since: 1.12 + **/ +double +cairo_device_observer_mask_elapsed (cairo_device_t *abstract_device) +{ + cairo_device_observer_t *device; + + if (unlikely (CAIRO_REFERENCE_COUNT_IS_INVALID (&abstract_device->ref_count))) + return -1; + + if (! _cairo_device_is_observer (abstract_device)) + return -1; + + device = (cairo_device_observer_t *) abstract_device; + return _cairo_time_to_ns (device->log.mask.elapsed); +} + +/** + * cairo_device_observer_fill_elapsed: + * @abstract_device: the observed #cairo_device_t + * + * Returns the elapsed time of the fill operations. + * + * Returns: the elapsed time, in nanoseconds. + * + * Since: 1.12 + **/ +double +cairo_device_observer_fill_elapsed (cairo_device_t *abstract_device) +{ + cairo_device_observer_t *device; + + if (unlikely (CAIRO_REFERENCE_COUNT_IS_INVALID (&abstract_device->ref_count))) + return -1; + + if (! _cairo_device_is_observer (abstract_device)) + return -1; + + device = (cairo_device_observer_t *) abstract_device; + return _cairo_time_to_ns (device->log.fill.elapsed); +} + +/** + * cairo_device_observer_stroke_elapsed: + * @abstract_device: the observed #cairo_device_t + * + * Returns the elapsed time of the stroke operations. + * + * Returns: the elapsed time, in nanoseconds. + * + * Since: 1.12 + **/ +double +cairo_device_observer_stroke_elapsed (cairo_device_t *abstract_device) +{ + cairo_device_observer_t *device; + + if (unlikely (CAIRO_REFERENCE_COUNT_IS_INVALID (&abstract_device->ref_count))) + return -1; + + if (! _cairo_device_is_observer (abstract_device)) + return -1; + + device = (cairo_device_observer_t *) abstract_device; + return _cairo_time_to_ns (device->log.stroke.elapsed); +} + +/** + * cairo_device_observer_glyphs_elapsed: + * @abstract_device: the observed #cairo_device_t + * + * Returns the elapsed time of the glyph operations. + * + * Returns: the elapsed time, in nanoseconds. + * + * Since: 1.12 + **/ +double +cairo_device_observer_glyphs_elapsed (cairo_device_t *abstract_device) +{ + cairo_device_observer_t *device; + + if (unlikely (CAIRO_REFERENCE_COUNT_IS_INVALID (&abstract_device->ref_count))) + return -1; + + if (! _cairo_device_is_observer (abstract_device)) + return -1; + + device = (cairo_device_observer_t *) abstract_device; + return _cairo_time_to_ns (device->log.glyphs.elapsed); +} diff --git a/local/recipes/libs/cairo/source/src/cairo-surface-offset-private.h b/local/recipes/libs/cairo/source/src/cairo-surface-offset-private.h new file mode 100644 index 0000000000..310ba5691c --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-surface-offset-private.h @@ -0,0 +1,95 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2009 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Chris Wilson + */ + +#ifndef CAIRO_SURFACE_OFFSET_PRIVATE_H +#define CAIRO_SURFACE_OFFSET_PRIVATE_H + +#include "cairo-types-private.h" + +CAIRO_BEGIN_DECLS + +cairo_private cairo_status_t +_cairo_surface_offset_paint (cairo_surface_t *target, + int x, int y, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip); + +cairo_private cairo_status_t +_cairo_surface_offset_mask (cairo_surface_t *target, + int x, int y, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_clip_t *clip); + +cairo_private cairo_status_t +_cairo_surface_offset_stroke (cairo_surface_t *surface, + int x, int y, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip); + +cairo_private cairo_status_t +_cairo_surface_offset_fill (cairo_surface_t *surface, + int x, int y, + cairo_operator_t op, + const cairo_pattern_t*source, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip); + +cairo_private cairo_status_t +_cairo_surface_offset_glyphs (cairo_surface_t *surface, + int x, int y, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_scaled_font_t *scaled_font, + cairo_glyph_t *glyphs, + int num_glyphs, + const cairo_clip_t *clip); + +#endif /* CAIRO_SURFACE_OFFSET_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-surface-offset.c b/local/recipes/libs/cairo/source/src/cairo-surface-offset.c new file mode 100644 index 0000000000..98f57f2980 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-surface-offset.c @@ -0,0 +1,308 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * Copyright © 2007 Adrian Johnson + * Copyright © 2009 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Chris Wilson + */ + +#include "cairoint.h" + +#include "cairo-clip-inline.h" +#include "cairo-error-private.h" +#include "cairo-pattern-private.h" +#include "cairo-surface-offset-private.h" + +/* A collection of routines to facilitate drawing to an alternate surface. */ + +static void +_copy_transformed_pattern (cairo_pattern_t *pattern, + const cairo_pattern_t *original, + const cairo_matrix_t *ctm_inverse) +{ + _cairo_pattern_init_static_copy (pattern, original); + + if (! _cairo_matrix_is_identity (ctm_inverse)) + _cairo_pattern_transform (pattern, ctm_inverse); +} + +cairo_status_t +_cairo_surface_offset_paint (cairo_surface_t *target, + int x, int y, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip) +{ + cairo_status_t status; + cairo_clip_t *dev_clip = (cairo_clip_t *) clip; + cairo_pattern_union_t source_copy; + + if (unlikely (target->status)) + return target->status; + + if (_cairo_clip_is_all_clipped (clip)) + return CAIRO_STATUS_SUCCESS; + + if (x | y) { + cairo_matrix_t m; + + dev_clip = _cairo_clip_copy_with_translation (clip, -x, -y); + + cairo_matrix_init_translate (&m, x, y); + _copy_transformed_pattern (&source_copy.base, source, &m); + source = &source_copy.base; + } + + status = _cairo_surface_paint (target, op, source, dev_clip); + + if (dev_clip != clip) + _cairo_clip_destroy (dev_clip); + + return status; +} + +cairo_status_t +_cairo_surface_offset_mask (cairo_surface_t *target, + int x, int y, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_clip_t *clip) +{ + cairo_status_t status; + cairo_clip_t *dev_clip = (cairo_clip_t *) clip; + cairo_pattern_union_t source_copy; + cairo_pattern_union_t mask_copy; + + if (unlikely (target->status)) + return target->status; + + if (_cairo_clip_is_all_clipped (clip)) + return CAIRO_STATUS_SUCCESS; + + if (x | y) { + cairo_matrix_t m; + + dev_clip = _cairo_clip_copy_with_translation (clip, -x, -y); + + cairo_matrix_init_translate (&m, x, y); + _copy_transformed_pattern (&source_copy.base, source, &m); + _copy_transformed_pattern (&mask_copy.base, mask, &m); + source = &source_copy.base; + mask = &mask_copy.base; + } + + status = _cairo_surface_mask (target, op, + source, mask, + dev_clip); + + if (dev_clip != clip) + _cairo_clip_destroy (dev_clip); + + return status; +} + +cairo_status_t +_cairo_surface_offset_stroke (cairo_surface_t *surface, + int x, int y, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t*stroke_style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_path_fixed_t path_copy, *dev_path = (cairo_path_fixed_t *) path; + cairo_clip_t *dev_clip = (cairo_clip_t *) clip; + cairo_matrix_t dev_ctm = *ctm; + cairo_matrix_t dev_ctm_inverse = *ctm_inverse; + cairo_pattern_union_t source_copy; + cairo_status_t status; + + if (unlikely (surface->status)) + return surface->status; + + if (_cairo_clip_is_all_clipped (clip)) + return CAIRO_STATUS_SUCCESS; + + if (x | y) { + cairo_matrix_t m; + + dev_clip = _cairo_clip_copy_with_translation (clip, -x, -y); + + status = _cairo_path_fixed_init_copy (&path_copy, dev_path); + if (unlikely (status)) + goto FINISH; + + _cairo_path_fixed_translate (&path_copy, + _cairo_fixed_from_int (-x), + _cairo_fixed_from_int (-y)); + dev_path = &path_copy; + + cairo_matrix_init_translate (&m, -x, -y); + cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m); + + cairo_matrix_init_translate (&m, x, y); + _copy_transformed_pattern (&source_copy.base, source, &m); + source = &source_copy.base; + cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse); + } + + status = _cairo_surface_stroke (surface, op, source, + dev_path, stroke_style, + &dev_ctm, &dev_ctm_inverse, + tolerance, antialias, + dev_clip); + +FINISH: + if (dev_path != path) + _cairo_path_fixed_fini (dev_path); + if (dev_clip != clip) + _cairo_clip_destroy (dev_clip); + + return status; +} + +cairo_status_t +_cairo_surface_offset_fill (cairo_surface_t *surface, + int x, int y, + cairo_operator_t op, + const cairo_pattern_t*source, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_status_t status; + cairo_path_fixed_t path_copy, *dev_path = (cairo_path_fixed_t *) path; + cairo_clip_t *dev_clip = (cairo_clip_t *) clip; + cairo_pattern_union_t source_copy; + + if (unlikely (surface->status)) + return surface->status; + + if (_cairo_clip_is_all_clipped (clip)) + return CAIRO_STATUS_SUCCESS; + + if (x | y) { + cairo_matrix_t m; + + dev_clip = _cairo_clip_copy_with_translation (clip, -x, -y); + + status = _cairo_path_fixed_init_copy (&path_copy, dev_path); + if (unlikely (status)) + goto FINISH; + + _cairo_path_fixed_translate (&path_copy, + _cairo_fixed_from_int (-x), + _cairo_fixed_from_int (-y)); + dev_path = &path_copy; + + cairo_matrix_init_translate (&m, x, y); + _copy_transformed_pattern (&source_copy.base, source, &m); + source = &source_copy.base; + } + + status = _cairo_surface_fill (surface, op, source, + dev_path, fill_rule, + tolerance, antialias, + dev_clip); + +FINISH: + if (dev_path != path) + _cairo_path_fixed_fini (dev_path); + if (dev_clip != clip) + _cairo_clip_destroy (dev_clip); + + return status; +} + +cairo_status_t +_cairo_surface_offset_glyphs (cairo_surface_t *surface, + int x, int y, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_scaled_font_t *scaled_font, + cairo_glyph_t *glyphs, + int num_glyphs, + const cairo_clip_t *clip) +{ + cairo_status_t status; + cairo_clip_t *dev_clip = (cairo_clip_t *) clip; + cairo_pattern_union_t source_copy; + cairo_glyph_t *dev_glyphs; + int i; + + if (unlikely (surface->status)) + return surface->status; + + if (_cairo_clip_is_all_clipped (clip)) + return CAIRO_STATUS_SUCCESS; + + dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); + if (dev_glyphs == NULL) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + memcpy (dev_glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs); + + if (x | y) { + cairo_matrix_t m; + + dev_clip = _cairo_clip_copy_with_translation (clip, -x, -y); + + cairo_matrix_init_translate (&m, x, y); + _copy_transformed_pattern (&source_copy.base, source, &m); + source = &source_copy.base; + + for (i = 0; i < num_glyphs; i++) { + dev_glyphs[i].x -= x; + dev_glyphs[i].y -= y; + } + } + + status = _cairo_surface_show_text_glyphs (surface, op, source, + NULL, 0, + dev_glyphs, num_glyphs, + NULL, 0, 0, + scaled_font, + dev_clip); + + if (dev_clip != clip) + _cairo_clip_destroy (dev_clip); + free (dev_glyphs); + + return status; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-surface-private.h b/local/recipes/libs/cairo/source/src/cairo-surface-private.h new file mode 100644 index 0000000000..35b559f9c6 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-surface-private.h @@ -0,0 +1,125 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + */ + +#ifndef CAIRO_SURFACE_PRIVATE_H +#define CAIRO_SURFACE_PRIVATE_H + +#include "cairo.h" + +#include "cairo-types-private.h" +#include "cairo-list-private.h" +#include "cairo-reference-count-private.h" +#include "cairo-clip-private.h" +#include "cairo-surface-backend-private.h" + +typedef void (*cairo_surface_func_t) (cairo_surface_t *); + +struct _cairo_surface { + const cairo_surface_backend_t *backend; + cairo_device_t *device; + + /* We allow surfaces to override the backend->type by shoving something + * else into surface->type. This is for "wrapper" surfaces that want to + * hide their internal type from the user-level API. */ + cairo_surface_type_t type; + + cairo_content_t content; + + cairo_reference_count_t ref_count; + cairo_status_t status; + unsigned int unique_id; + unsigned int serial; + cairo_damage_t *damage; + + unsigned _finishing : 1; + unsigned finished : 1; + unsigned is_clear : 1; + unsigned has_font_options : 1; + unsigned owns_device : 1; + unsigned is_vector : 1; + + cairo_user_data_array_t user_data; + cairo_user_data_array_t mime_data; + + cairo_matrix_t device_transform; + cairo_matrix_t device_transform_inverse; + cairo_list_t device_transform_observers; + + /* The actual resolution of the device, in dots per inch. */ + double x_resolution; + double y_resolution; + + /* The resolution that should be used when generating image-based + * fallback; generally only used by the analysis/paginated + * surfaces + */ + double x_fallback_resolution; + double y_fallback_resolution; + + /* A "snapshot" surface is immutable. See _cairo_surface_snapshot. */ + cairo_surface_t *snapshot_of; + cairo_surface_func_t snapshot_detach; + /* current snapshots of this surface*/ + cairo_list_t snapshots; + /* place upon snapshot list */ + cairo_list_t snapshot; + + /* + * Surface font options, falling back to backend's default options, + * and set using _cairo_surface_set_font_options(), and propagated by + * cairo_surface_create_similar(). + */ + cairo_font_options_t font_options; + + cairo_pattern_t *foreground_source; + cairo_bool_t foreground_used; +}; + +cairo_private cairo_surface_t * +_cairo_surface_create_in_error (cairo_status_t status); + +cairo_private cairo_surface_t * +_cairo_int_surface_create_in_error (cairo_int_status_t status); + +cairo_private cairo_surface_t * +_cairo_surface_get_source (cairo_surface_t *surface, + cairo_rectangle_int_t *extents); + +cairo_private cairo_status_t +_cairo_surface_flush (cairo_surface_t *surface, unsigned flags); + +#endif /* CAIRO_SURFACE_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-surface-snapshot-inline.h b/local/recipes/libs/cairo/source/src/cairo-surface-snapshot-inline.h new file mode 100644 index 0000000000..bf89c772b4 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-surface-snapshot-inline.h @@ -0,0 +1,67 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Intel Corporation. + * + * Contributor(s): + * Chris Wilson + */ + +#ifndef CAIRO_SURFACE_SNAPSHOT_INLINE_H +#define CAIRO_SURFACE_SNAPSHOT_INLINE_H + +#include "cairo-surface-snapshot-private.h" +#include "cairo-surface-inline.h" + +static inline cairo_bool_t +_cairo_surface_snapshot_is_reused (cairo_surface_t *surface) +{ + return CAIRO_REFERENCE_COUNT_GET_VALUE (&surface->ref_count) > 2; +} + +static inline cairo_surface_t * +_cairo_surface_snapshot_get_target (cairo_surface_t *surface) +{ + cairo_surface_snapshot_t *snapshot = (cairo_surface_snapshot_t *) surface; + cairo_surface_t *target; + + CAIRO_MUTEX_LOCK (snapshot->mutex); + target = _cairo_surface_reference (snapshot->target); + CAIRO_MUTEX_UNLOCK (snapshot->mutex); + + return target; +} + +static inline cairo_bool_t +_cairo_surface_is_snapshot (cairo_surface_t *surface) +{ + return surface->backend->type == (cairo_surface_type_t)CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT; +} + +#endif /* CAIRO_SURFACE_SNAPSHOT_INLINE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-surface-snapshot-private.h b/local/recipes/libs/cairo/source/src/cairo-surface-snapshot-private.h new file mode 100644 index 0000000000..58bee7b49d --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-surface-snapshot-private.h @@ -0,0 +1,51 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Intel Corporation. + * + * Contributor(s): + * Chris Wilson + */ + +#ifndef CAIRO_SURFACE_SNAPSHOT_PRIVATE_H +#define CAIRO_SURFACE_SNAPSHOT_PRIVATE_H + +#include "cairo-mutex-private.h" +#include "cairo-surface-private.h" +#include "cairo-surface-backend-private.h" + +struct _cairo_surface_snapshot { + cairo_surface_t base; + + cairo_mutex_t mutex; + cairo_surface_t *target; + cairo_surface_t *clone; +}; + +#endif /* CAIRO_SURFACE_SNAPSHOT_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-surface-snapshot.c b/local/recipes/libs/cairo/source/src/cairo-surface-snapshot.c new file mode 100644 index 0000000000..dd4a253644 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-surface-snapshot.c @@ -0,0 +1,295 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2009 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Chris Wilson + */ + +#include "cairoint.h" + +#include "cairo-error-private.h" +#include "cairo-image-surface-private.h" +#include "cairo-surface-snapshot-inline.h" + +static cairo_status_t +_cairo_surface_snapshot_finish (void *abstract_surface) +{ + cairo_surface_snapshot_t *surface = abstract_surface; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + if (surface->clone != NULL) { + cairo_surface_finish (surface->clone); + status = surface->clone->status; + + cairo_surface_destroy (surface->clone); + } + + CAIRO_MUTEX_FINI (surface->mutex); + + return status; +} + +static cairo_status_t +_cairo_surface_snapshot_flush (void *abstract_surface, unsigned flags) +{ + cairo_surface_snapshot_t *surface = abstract_surface; + cairo_surface_t *target; + cairo_status_t status; + + target = _cairo_surface_snapshot_get_target (&surface->base); + status = target->status; + if (status == CAIRO_STATUS_SUCCESS) + status = _cairo_surface_flush (target, flags); + cairo_surface_destroy (target); + + return status; +} + +static cairo_surface_t * +_cairo_surface_snapshot_source (void *abstract_surface, + cairo_rectangle_int_t *extents) +{ + cairo_surface_snapshot_t *surface = abstract_surface; + return _cairo_surface_get_source (surface->target, extents); /* XXX racy */ +} + +struct snapshot_extra { + cairo_surface_t *target; + void *extra; +}; + +static cairo_status_t +_cairo_surface_snapshot_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **extra_out) +{ + cairo_surface_snapshot_t *surface = abstract_surface; + struct snapshot_extra *extra; + cairo_status_t status; + + extra = _cairo_calloc (sizeof (*extra)); + if (unlikely (extra == NULL)) { + *extra_out = NULL; + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + extra->target = _cairo_surface_snapshot_get_target (&surface->base); + status = _cairo_surface_acquire_source_image (extra->target, image_out, &extra->extra); + if (unlikely (status)) { + cairo_surface_destroy (extra->target); + free (extra); + extra = NULL; + } + + *extra_out = extra; + return status; +} + +static void +_cairo_surface_snapshot_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *_extra) +{ + struct snapshot_extra *extra = _extra; + + _cairo_surface_release_source_image (extra->target, image, extra->extra); + cairo_surface_destroy (extra->target); + free (extra); +} + +static cairo_bool_t +_cairo_surface_snapshot_get_extents (void *abstract_surface, + cairo_rectangle_int_t *extents) +{ + cairo_surface_snapshot_t *surface = abstract_surface; + cairo_surface_t *target; + cairo_bool_t bounded; + + target = _cairo_surface_snapshot_get_target (&surface->base); + bounded = _cairo_surface_get_extents (target, extents); + cairo_surface_destroy (target); + + return bounded; +} + +static const cairo_surface_backend_t _cairo_surface_snapshot_backend = { + CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT, + _cairo_surface_snapshot_finish, + NULL, + + NULL, /* create similar */ + NULL, /* create similar image */ + NULL, /* map to image */ + NULL, /* unmap image */ + + _cairo_surface_snapshot_source, + _cairo_surface_snapshot_acquire_source_image, + _cairo_surface_snapshot_release_source_image, + NULL, /* snapshot */ + + NULL, /* copy_page */ + NULL, /* show_page */ + + _cairo_surface_snapshot_get_extents, + NULL, /* get-font-options */ + + _cairo_surface_snapshot_flush, +}; + +static void +_cairo_surface_snapshot_copy_on_write (cairo_surface_t *surface) +{ + cairo_surface_snapshot_t *snapshot = (cairo_surface_snapshot_t *) surface; + cairo_image_surface_t *image; + cairo_surface_t *clone; + void *extra; + cairo_status_t status; + + TRACE ((stderr, "%s: target=%d\n", + __FUNCTION__, snapshot->target->unique_id)); + + /* We need to make an image copy of the original surface since the + * snapshot may exceed the lifetime of the original device, i.e. + * when we later need to use the snapshot the data may have already + * been lost. + */ + + CAIRO_MUTEX_LOCK (snapshot->mutex); + + if (snapshot->target->backend->snapshot != NULL) { + clone = snapshot->target->backend->snapshot (snapshot->target); + if (clone != NULL) { + assert (clone->status || ! _cairo_surface_is_snapshot (clone)); + goto done; + } + } + + /* XXX copy to a similar surface, leave acquisition till later? + * We should probably leave such decisions to the backend in case we + * rely upon devices/connections like Xlib. + */ + status = _cairo_surface_acquire_source_image (snapshot->target, &image, &extra); + if (unlikely (status)) { + snapshot->target = _cairo_surface_create_in_error (status); + status = _cairo_surface_set_error (surface, status); + goto unlock; + } + clone = image->base.backend->snapshot (&image->base); + _cairo_surface_release_source_image (snapshot->target, image, extra); + +done: + status = _cairo_surface_set_error (surface, clone->status); + snapshot->target = snapshot->clone = clone; + snapshot->base.type = clone->type; +unlock: + CAIRO_MUTEX_UNLOCK (snapshot->mutex); +} + +/** + * _cairo_surface_snapshot: + * @surface: a #cairo_surface_t + * + * Make an immutable reference to @surface. It is an error to call a + * surface-modifying function on the result of this function. The + * resulting 'snapshot' is a lazily copied-on-write surface i.e. it + * remains a reference to the original surface until that surface is + * written to again, at which time a copy is made of the original surface + * and the snapshot then points to that instead. Multiple snapshots of the + * same unmodified surface point to the same copy. + * + * The caller owns the return value and should call + * cairo_surface_destroy() when finished with it. This function will not + * return %NULL, but will return a nil surface instead. + * + * Return value: The snapshot surface. Note that the return surface + * may not necessarily be of the same type as @surface. + **/ +cairo_surface_t * +_cairo_surface_snapshot (cairo_surface_t *surface) +{ + cairo_surface_snapshot_t *snapshot; + cairo_status_t status; + + TRACE ((stderr, "%s: target=%d\n", __FUNCTION__, surface->unique_id)); + + if (unlikely (surface->status)) + return _cairo_surface_create_in_error (surface->status); + + if (unlikely (surface->finished)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + + if (surface->snapshot_of != NULL) + return cairo_surface_reference (surface); + + if (_cairo_surface_is_snapshot (surface)) + return cairo_surface_reference (surface); + + snapshot = (cairo_surface_snapshot_t *) + _cairo_surface_has_snapshot (surface, &_cairo_surface_snapshot_backend); + if (snapshot != NULL) + return cairo_surface_reference (&snapshot->base); + + snapshot = _cairo_calloc (sizeof (cairo_surface_snapshot_t)); + if (unlikely (snapshot == NULL)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + + _cairo_surface_init (&snapshot->base, + &_cairo_surface_snapshot_backend, + NULL, /* device */ + surface->content, + surface->is_vector); + snapshot->base.type = surface->type; + + CAIRO_MUTEX_INIT (snapshot->mutex); + snapshot->target = surface; + snapshot->clone = NULL; + + status = _cairo_surface_copy_mime_data (&snapshot->base, surface); + if (unlikely (status)) { + cairo_surface_destroy (&snapshot->base); + return _cairo_surface_create_in_error (status); + } + + snapshot->base.device_transform = surface->device_transform; + snapshot->base.device_transform_inverse = surface->device_transform_inverse; + + _cairo_surface_attach_snapshot (surface, + &snapshot->base, + _cairo_surface_snapshot_copy_on_write); + + return &snapshot->base; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-surface-subsurface-inline.h b/local/recipes/libs/cairo/source/src/cairo-surface-subsurface-inline.h new file mode 100644 index 0000000000..0cd09e63e7 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-surface-subsurface-inline.h @@ -0,0 +1,72 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Intel Corporation. + * + * Contributor(s): + * Chris Wilson + */ + +#ifndef CAIRO_SURFACE_SUBSURFACE_INLINE_H +#define CAIRO_SURFACE_SUBSURFACE_INLINE_H + +#include "cairo-surface-subsurface-private.h" + +static inline cairo_surface_t * +_cairo_surface_subsurface_get_target (cairo_surface_t *surface) +{ + return ((cairo_surface_subsurface_t *) surface)->target; +} + +static inline void +_cairo_surface_subsurface_offset (cairo_surface_t *surface, + int *x, int *y) +{ + cairo_surface_subsurface_t *ss = (cairo_surface_subsurface_t *) surface; + *x += ss->extents.x; + *y += ss->extents.y; +} + +static inline cairo_surface_t * +_cairo_surface_subsurface_get_target_with_offset (cairo_surface_t *surface, + int *x, int *y) +{ + cairo_surface_subsurface_t *ss = (cairo_surface_subsurface_t *) surface; + *x += ss->extents.x; + *y += ss->extents.y; + return ss->target; +} + +static inline cairo_bool_t +_cairo_surface_is_subsurface (cairo_surface_t *surface) +{ + return surface->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE; +} + +#endif /* CAIRO_SURFACE_SUBSURFACE_INLINE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-surface-subsurface-private.h b/local/recipes/libs/cairo/source/src/cairo-surface-subsurface-private.h new file mode 100644 index 0000000000..89c5cc01b9 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-surface-subsurface-private.h @@ -0,0 +1,55 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Intel Corporation. + * + * Contributor(s): + * Chris Wilson + */ + +#ifndef CAIRO_SURFACE_SUBSURFACE_PRIVATE_H +#define CAIRO_SURFACE_SUBSURFACE_PRIVATE_H + +#include "cairo-surface-private.h" +#include "cairo-surface-backend-private.h" + +struct _cairo_surface_subsurface { + cairo_surface_t base; + + cairo_rectangle_int_t extents; + + cairo_surface_t *target; + cairo_surface_t *snapshot; +}; + +cairo_private void +_cairo_surface_subsurface_set_snapshot (cairo_surface_t *surface, + cairo_surface_t *snapshot); + +#endif /* CAIRO_SURFACE_SUBSURFACE_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-surface-subsurface.c b/local/recipes/libs/cairo/source/src/cairo-surface-subsurface.c new file mode 100644 index 0000000000..9818c7296b --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-surface-subsurface.c @@ -0,0 +1,589 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Intel Corporation. + * + * Contributor(s): + * Chris Wilson + */ + +#include "cairoint.h" + +#include "cairo-clip-inline.h" +#include "cairo-error-private.h" +#include "cairo-image-surface-private.h" +#include "cairo-recording-surface-private.h" +#include "cairo-surface-offset-private.h" +#include "cairo-surface-snapshot-private.h" +#include "cairo-surface-subsurface-private.h" + +static const cairo_surface_backend_t _cairo_surface_subsurface_backend; + +static cairo_status_t +_cairo_surface_subsurface_finish (void *abstract_surface) +{ + cairo_surface_subsurface_t *surface = abstract_surface; + + cairo_surface_destroy (surface->target); + cairo_surface_destroy (surface->snapshot); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_surface_t * +_cairo_surface_subsurface_create_similar (void *other, + cairo_content_t content, + int width, int height) +{ + cairo_surface_subsurface_t *surface = other; + + if (surface->target->backend->create_similar == NULL) + return NULL; + + return surface->target->backend->create_similar (surface->target, content, width, height); +} + +static cairo_surface_t * +_cairo_surface_subsurface_create_similar_image (void *other, + cairo_format_t format, + int width, int height) +{ + cairo_surface_subsurface_t *surface = other; + + if (surface->target->backend->create_similar_image == NULL) + return NULL; + + return surface->target->backend->create_similar_image (surface->target, + format, + width, height); +} + +static cairo_image_surface_t * +_cairo_surface_subsurface_map_to_image (void *abstract_surface, + const cairo_rectangle_int_t *extents) +{ + cairo_surface_subsurface_t *surface = abstract_surface; + cairo_rectangle_int_t target_extents; + + target_extents.x = extents->x + surface->extents.x; + target_extents.y = extents->y + surface->extents.y; + target_extents.width = extents->width; + target_extents.height = extents->height; + + return _cairo_surface_map_to_image (surface->target, &target_extents); +} + +static cairo_int_status_t +_cairo_surface_subsurface_unmap_image (void *abstract_surface, + cairo_image_surface_t *image) +{ + cairo_surface_subsurface_t *surface = abstract_surface; + return _cairo_surface_unmap_image (surface->target, image); +} + +static cairo_int_status_t +_cairo_surface_subsurface_paint (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip) +{ + cairo_surface_subsurface_t *surface = abstract_surface; + cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height }; + cairo_status_t status; + cairo_clip_t *target_clip; + + target_clip = _cairo_clip_copy_intersect_rectangle (clip, &rect); + status = _cairo_surface_offset_paint (surface->target, + -surface->extents.x, -surface->extents.y, + op, source, target_clip); + _cairo_clip_destroy (target_clip); + return status; +} + +static cairo_int_status_t +_cairo_surface_subsurface_mask (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_clip_t *clip) +{ + cairo_surface_subsurface_t *surface = abstract_surface; + cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height }; + cairo_status_t status; + cairo_clip_t *target_clip; + + target_clip = _cairo_clip_copy_intersect_rectangle (clip, &rect); + status = _cairo_surface_offset_mask (surface->target, + -surface->extents.x, -surface->extents.y, + op, source, mask, target_clip); + _cairo_clip_destroy (target_clip); + return status; +} + +static cairo_int_status_t +_cairo_surface_subsurface_fill (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_surface_subsurface_t *surface = abstract_surface; + cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height }; + cairo_status_t status; + cairo_clip_t *target_clip; + + target_clip = _cairo_clip_copy_intersect_rectangle (clip, &rect); + status = _cairo_surface_offset_fill (surface->target, + -surface->extents.x, -surface->extents.y, + op, source, path, fill_rule, tolerance, antialias, + target_clip); + _cairo_clip_destroy (target_clip); + return status; +} + +static cairo_int_status_t +_cairo_surface_subsurface_stroke (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_surface_subsurface_t *surface = abstract_surface; + cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height }; + cairo_status_t status; + cairo_clip_t *target_clip; + + target_clip = _cairo_clip_copy_intersect_rectangle (clip, &rect); + status = _cairo_surface_offset_stroke (surface->target, + -surface->extents.x, -surface->extents.y, + op, source, path, stroke_style, ctm, ctm_inverse, + tolerance, antialias, + target_clip); + _cairo_clip_destroy (target_clip); + return status; +} + +static cairo_int_status_t +_cairo_surface_subsurface_glyphs (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip) +{ + cairo_surface_subsurface_t *surface = abstract_surface; + cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height }; + cairo_status_t status; + cairo_clip_t *target_clip; + + target_clip = _cairo_clip_copy_intersect_rectangle (clip, &rect); + status = _cairo_surface_offset_glyphs (surface->target, + -surface->extents.x, -surface->extents.y, + op, source, + scaled_font, glyphs, num_glyphs, + target_clip); + _cairo_clip_destroy (target_clip); + return status; +} + +static cairo_status_t +_cairo_surface_subsurface_flush (void *abstract_surface, unsigned flags) +{ + cairo_surface_subsurface_t *surface = abstract_surface; + return _cairo_surface_flush (surface->target, flags); +} + +static cairo_status_t +_cairo_surface_subsurface_mark_dirty (void *abstract_surface, + int x, int y, + int width, int height) +{ + cairo_surface_subsurface_t *surface = abstract_surface; + cairo_status_t status; + + status = CAIRO_STATUS_SUCCESS; + if (surface->target->backend->mark_dirty_rectangle != NULL) { + cairo_rectangle_int_t rect, extents; + + rect.x = x; + rect.y = y; + rect.width = width; + rect.height = height; + + extents.x = extents.y = 0; + extents.width = surface->extents.width; + extents.height = surface->extents.height; + + if (_cairo_rectangle_intersect (&rect, &extents)) { + status = surface->target->backend->mark_dirty_rectangle (surface->target, + rect.x + surface->extents.x, + rect.y + surface->extents.y, + rect.width, rect.height); + } + } + + return status; +} + +static cairo_bool_t +_cairo_surface_subsurface_get_extents (void *abstract_surface, + cairo_rectangle_int_t *extents) +{ + cairo_surface_subsurface_t *surface = abstract_surface; + + extents->x = 0; + extents->y = 0; + extents->width = surface->extents.width; + extents->height = surface->extents.height; + + return TRUE; +} + +static void +_cairo_surface_subsurface_get_font_options (void *abstract_surface, + cairo_font_options_t *options) +{ + cairo_surface_subsurface_t *surface = abstract_surface; + + if (surface->target->backend->get_font_options != NULL) + surface->target->backend->get_font_options (surface->target, options); +} + +static cairo_surface_t * +_cairo_surface_subsurface_source (void *abstract_surface, + cairo_rectangle_int_t *extents) +{ + cairo_surface_subsurface_t *surface = abstract_surface; + cairo_surface_t *source; + + source = _cairo_surface_get_source (surface->target, extents); + if (extents) + *extents = surface->extents; + + return source; +} + +static cairo_status_t +_cairo_surface_subsurface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **extra_out) +{ + cairo_surface_subsurface_t *surface = abstract_surface; + cairo_surface_pattern_t pattern; + cairo_surface_t *image; + cairo_status_t status; + + image = _cairo_image_surface_create_with_content (surface->base.content, + surface->extents.width, + surface->extents.height); + if (unlikely (image->status)) + return image->status; + + _cairo_pattern_init_for_surface (&pattern, surface->target); + cairo_matrix_init_translate (&pattern.base.matrix, + surface->extents.x, + surface->extents.y); + pattern.base.filter = CAIRO_FILTER_NEAREST; + status = _cairo_surface_paint (image, + CAIRO_OPERATOR_SOURCE, + &pattern.base, NULL); + _cairo_pattern_fini (&pattern.base); + if (unlikely (status)) { + cairo_surface_destroy (image); + return status; + } + + *image_out = (cairo_image_surface_t *)image; + *extra_out = NULL; + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_surface_subsurface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *abstract_extra) +{ + cairo_surface_destroy (&image->base); +} + +static cairo_surface_t * +_cairo_surface_subsurface_snapshot (void *abstract_surface) +{ + cairo_surface_subsurface_t *surface = abstract_surface; + cairo_surface_pattern_t pattern; + cairo_surface_t *clone; + cairo_status_t status; + + TRACE ((stderr, "%s: target=%d\n", __FUNCTION__, surface->target->unique_id)); + + clone = _cairo_surface_create_scratch (surface->target, + surface->target->content, + surface->extents.width, + surface->extents.height, + NULL); + if (unlikely (clone->status)) + return clone; + + _cairo_pattern_init_for_surface (&pattern, surface->target); + cairo_matrix_init_translate (&pattern.base.matrix, + surface->extents.x, surface->extents.y); + pattern.base.filter = CAIRO_FILTER_NEAREST; + status = _cairo_surface_paint (clone, + CAIRO_OPERATOR_SOURCE, + &pattern.base, NULL); + _cairo_pattern_fini (&pattern.base); + + if (unlikely (status)) { + cairo_surface_destroy (clone); + clone = _cairo_surface_create_in_error (status); + } + + return clone; +} + +static cairo_t * +_cairo_surface_subsurface_create_context(void *target) +{ + cairo_surface_subsurface_t *surface = target; + return surface->target->backend->create_context (&surface->base); +} + +static const cairo_surface_backend_t _cairo_surface_subsurface_backend = { + CAIRO_SURFACE_TYPE_SUBSURFACE, + _cairo_surface_subsurface_finish, + + _cairo_surface_subsurface_create_context, + + _cairo_surface_subsurface_create_similar, + _cairo_surface_subsurface_create_similar_image, + _cairo_surface_subsurface_map_to_image, + _cairo_surface_subsurface_unmap_image, + + _cairo_surface_subsurface_source, + _cairo_surface_subsurface_acquire_source_image, + _cairo_surface_subsurface_release_source_image, + _cairo_surface_subsurface_snapshot, + + NULL, /* copy_page */ + NULL, /* show_page */ + + _cairo_surface_subsurface_get_extents, + _cairo_surface_subsurface_get_font_options, + + _cairo_surface_subsurface_flush, + _cairo_surface_subsurface_mark_dirty, + + _cairo_surface_subsurface_paint, + _cairo_surface_subsurface_mask, + _cairo_surface_subsurface_stroke, + _cairo_surface_subsurface_fill, + NULL, /* fill/stroke */ + _cairo_surface_subsurface_glyphs, +}; + +/** + * cairo_surface_create_for_rectangle: + * @target: an existing surface for which the sub-surface will point to + * @x: the x-origin of the sub-surface from the top-left of the target surface (in device-space units) + * @y: the y-origin of the sub-surface from the top-left of the target surface (in device-space units) + * @width: width of the sub-surface (in device-space units) + * @height: height of the sub-surface (in device-space units) + * + * Create a new surface that is a rectangle within the target surface. + * All operations drawn to this surface are then clipped and translated + * onto the target surface. Nothing drawn via this sub-surface outside of + * its bounds is drawn onto the target surface, making this a useful method + * for passing constrained child surfaces to library routines that draw + * directly onto the parent surface, i.e. with no further backend allocations, + * double buffering or copies. + * + * The semantics of subsurfaces have not been finalized yet + * unless the rectangle is in full device units, is contained within + * the extents of the target surface, and the target or subsurface's + * device transforms are not changed. + * + * Return value: a pointer to the newly allocated surface. The caller + * owns the surface and should call cairo_surface_destroy() when done + * with it. + * + * This function always returns a valid pointer, but it will return a + * pointer to a "nil" surface if @other is already in an error state + * or any other error occurs. + * + * Since: 1.10 + **/ +cairo_surface_t * +cairo_surface_create_for_rectangle (cairo_surface_t *target, + double x, double y, + double width, double height) +{ + cairo_surface_subsurface_t *surface; + + if (unlikely (width < 0 || height < 0)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); + + if (unlikely (target->status)) + return _cairo_surface_create_in_error (target->status); + if (unlikely (target->finished)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + + surface = _cairo_calloc (sizeof (cairo_surface_subsurface_t)); + if (unlikely (surface == NULL)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + x *= target->device_transform.xx; + y *= target->device_transform.yy; + + width *= target->device_transform.xx; + height *= target->device_transform.yy; + + x += target->device_transform.x0; + y += target->device_transform.y0; + + _cairo_surface_init (&surface->base, + &_cairo_surface_subsurface_backend, + NULL, /* device */ + target->content, + target->is_vector); + + /* XXX forced integer alignment */ + surface->extents.x = ceil (x); + surface->extents.y = ceil (y); + surface->extents.width = floor (x + width) - surface->extents.x; + surface->extents.height = floor (y + height) - surface->extents.y; + if ((surface->extents.width | surface->extents.height) < 0) + surface->extents.width = surface->extents.height = 0; + + if (target->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) { + /* Maintain subsurfaces as 1-depth */ + cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) target; + surface->extents.x += sub->extents.x; + surface->extents.y += sub->extents.y; + target = sub->target; + } + + surface->target = cairo_surface_reference (target); + surface->base.type = surface->target->type; + + surface->snapshot = NULL; + + cairo_surface_set_device_scale (&surface->base, + target->device_transform.xx, + target->device_transform.yy); + + return &surface->base; +} + +cairo_surface_t * +_cairo_surface_create_for_rectangle_int (cairo_surface_t *target, + const cairo_rectangle_int_t *extents) +{ + cairo_surface_subsurface_t *surface; + + if (unlikely (target->status)) + return _cairo_surface_create_in_error (target->status); + if (unlikely (target->finished)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + + assert (target->backend->type != CAIRO_SURFACE_TYPE_SUBSURFACE); + + surface = _cairo_calloc (sizeof (cairo_surface_subsurface_t)); + if (unlikely (surface == NULL)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + _cairo_surface_init (&surface->base, + &_cairo_surface_subsurface_backend, + NULL, /* device */ + target->content, + target->is_vector); + + surface->extents = *extents; + surface->extents.x *= target->device_transform.xx; + surface->extents.y *= target->device_transform.yy; + surface->extents.width *= target->device_transform.xx; + surface->extents.height *= target->device_transform.yy; + surface->extents.x += target->device_transform.x0; + surface->extents.y += target->device_transform.y0; + + surface->target = cairo_surface_reference (target); + surface->base.type = surface->target->type; + + surface->snapshot = NULL; + + cairo_surface_set_device_scale (&surface->base, + target->device_transform.xx, + target->device_transform.yy); + + return &surface->base; +} +/* XXX observe mark-dirty */ + +static void +_cairo_surface_subsurface_detach_snapshot (cairo_surface_t *surface) +{ + cairo_surface_subsurface_t *ss = (cairo_surface_subsurface_t *) surface; + + TRACE ((stderr, "%s: target=%d\n", __FUNCTION__, ss->target->unique_id)); + + cairo_surface_destroy (ss->snapshot); + ss->snapshot = NULL; +} + +void +_cairo_surface_subsurface_set_snapshot (cairo_surface_t *surface, + cairo_surface_t *snapshot) +{ + cairo_surface_subsurface_t *ss = (cairo_surface_subsurface_t *) surface; + + TRACE ((stderr, "%s: target=%d, snapshot=%d\n", __FUNCTION__, + ss->target->unique_id, snapshot->unique_id)); + + /* FIXME: attaching the subsurface as a snapshot to its target creates + * a reference cycle. Let's make this call as a no-op until that bug + * is fixed. + */ + return; + + if (ss->snapshot) + _cairo_surface_detach_snapshot (ss->snapshot); + + ss->snapshot = cairo_surface_reference (snapshot); + + _cairo_surface_attach_snapshot (ss->target, &ss->base, + _cairo_surface_subsurface_detach_snapshot); +} diff --git a/local/recipes/libs/cairo/source/src/cairo-surface-wrapper-private.h b/local/recipes/libs/cairo/source/src/cairo-surface-wrapper-private.h new file mode 100644 index 0000000000..016402d7ea --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-surface-wrapper-private.h @@ -0,0 +1,213 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2009 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Chris Wilson + */ + +#ifndef CAIRO_SURFACE_WRAPPER_PRIVATE_H +#define CAIRO_SURFACE_WRAPPER_PRIVATE_H + +#include "cairoint.h" +#include "cairo-types-private.h" +#include "cairo-recording-surface-private.h" +#include "cairo-surface-backend-private.h" + +CAIRO_BEGIN_DECLS + +struct _cairo_surface_wrapper { + cairo_surface_t *target; + + cairo_matrix_t transform; + + cairo_bool_t has_extents; + cairo_rectangle_int_t extents; + const cairo_clip_t *clip; + + unsigned int source_region_id; + unsigned int mask_region_id; + + cairo_bool_t needs_transform; +}; + +cairo_private void +_cairo_surface_wrapper_init (cairo_surface_wrapper_t *wrapper, + cairo_surface_t *target); + +cairo_private void +_cairo_surface_wrapper_intersect_extents (cairo_surface_wrapper_t *wrapper, + const cairo_rectangle_int_t *extents); + +cairo_private void +_cairo_surface_wrapper_set_inverse_transform (cairo_surface_wrapper_t *wrapper, + const cairo_matrix_t *transform); + +cairo_private void +_cairo_surface_wrapper_set_clip (cairo_surface_wrapper_t *wrapper, + const cairo_clip_t *clip); + +cairo_private void +_cairo_surface_wrapper_fini (cairo_surface_wrapper_t *wrapper); + +static inline cairo_bool_t +_cairo_surface_wrapper_has_fill_stroke (cairo_surface_wrapper_t *wrapper) +{ + return wrapper->target->backend->fill_stroke != NULL; +} + +cairo_private cairo_status_t +_cairo_surface_wrapper_acquire_source_image (cairo_surface_wrapper_t *wrapper, + cairo_image_surface_t **image_out, + void **image_extra); + +cairo_private void +_cairo_surface_wrapper_release_source_image (cairo_surface_wrapper_t *wrapper, + cairo_image_surface_t *image, + void *image_extra); + + +cairo_private cairo_status_t +_cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper, + cairo_operator_t op, + const cairo_pattern_t *source, + unsigned int source_region_id, + const cairo_clip_t *clip); + +cairo_private cairo_status_t +_cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper, + cairo_operator_t op, + const cairo_pattern_t *source, + unsigned int source_region_id, + const cairo_pattern_t *mask, + unsigned int mask_region_id, + const cairo_clip_t *clip); + +cairo_private cairo_status_t +_cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper, + cairo_operator_t op, + const cairo_pattern_t *source, + unsigned int source_region_id, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip); + +cairo_private cairo_status_t +_cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper, + cairo_operator_t fill_op, + const cairo_pattern_t *fill_source, + unsigned int fill_region_id, + cairo_fill_rule_t fill_rule, + double fill_tolerance, + cairo_antialias_t fill_antialias, + const cairo_path_fixed_t *path, + cairo_operator_t stroke_op, + const cairo_pattern_t *stroke_source, + unsigned int stroke_region_id, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *stroke_ctm, + const cairo_matrix_t *stroke_ctm_inverse, + double stroke_tolerance, + cairo_antialias_t stroke_antialias, + const cairo_clip_t *clip); + +cairo_private cairo_status_t +_cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper, + cairo_operator_t op, + const cairo_pattern_t *source, + unsigned int source_region_id, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip); + +cairo_private cairo_status_t +_cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper, + cairo_operator_t op, + const cairo_pattern_t *source, + unsigned int source_region_id, + const char *utf8, + int utf8_len, + const cairo_glyph_t *glyphs, + int num_glyphs, + const cairo_text_cluster_t *clusters, + int num_clusters, + cairo_text_cluster_flags_t cluster_flags, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip); + +cairo_private cairo_status_t +_cairo_surface_wrapper_tag (cairo_surface_wrapper_t *wrapper, + cairo_bool_t begin, + const char *tag_name, + const char *attributes); + +cairo_private cairo_surface_t * +_cairo_surface_wrapper_create_similar (cairo_surface_wrapper_t *wrapper, + cairo_content_t content, + int width, + int height); +cairo_private cairo_bool_t +_cairo_surface_wrapper_get_extents (cairo_surface_wrapper_t *wrapper, + cairo_rectangle_int_t *extents); + +cairo_private void +_cairo_surface_wrapper_get_font_options (cairo_surface_wrapper_t *wrapper, + cairo_font_options_t *options); + +cairo_private cairo_surface_t * +_cairo_surface_wrapper_snapshot (cairo_surface_wrapper_t *wrapper); + +cairo_private cairo_bool_t +_cairo_surface_wrapper_has_show_text_glyphs (cairo_surface_wrapper_t *wrapper); + +static inline cairo_bool_t +_cairo_surface_wrapper_is_active (cairo_surface_wrapper_t *wrapper) +{ + return wrapper->target != (cairo_surface_t *) 0; +} + +cairo_private cairo_bool_t +_cairo_surface_wrapper_get_target_extents (cairo_surface_wrapper_t *wrapper, + cairo_bool_t surface_is_unbounded, + cairo_rectangle_int_t *extents); + +CAIRO_END_DECLS + +#endif /* CAIRO_SURFACE_WRAPPER_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-surface-wrapper.c b/local/recipes/libs/cairo/source/src/cairo-surface-wrapper.c new file mode 100644 index 0000000000..29c19c5a5f --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-surface-wrapper.c @@ -0,0 +1,711 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * Copyright © 2007 Adrian Johnson + * Copyright © 2009 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Chris Wilson + */ + +#include "cairoint.h" + +#include "cairo-clip-inline.h" +#include "cairo-error-private.h" +#include "cairo-pattern-private.h" +#include "cairo-surface-wrapper-private.h" + +/* A collection of routines to facilitate surface wrapping */ + +static void +_copy_transformed_pattern (cairo_pattern_t *pattern, + const cairo_pattern_t *original, + const cairo_matrix_t *ctm_inverse, + unsigned int region_id) +{ + _cairo_pattern_init_static_copy (pattern, original); + + if (! _cairo_matrix_is_identity (ctm_inverse)) + _cairo_pattern_transform (pattern, ctm_inverse); + + if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { + cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern; + surface_pattern->region_array_id = region_id; + } +} + +cairo_status_t +_cairo_surface_wrapper_acquire_source_image (cairo_surface_wrapper_t *wrapper, + cairo_image_surface_t **image_out, + void **image_extra) +{ + if (unlikely (wrapper->target->status)) + return wrapper->target->status; + + return _cairo_surface_acquire_source_image (wrapper->target, + image_out, image_extra); +} + +void +_cairo_surface_wrapper_release_source_image (cairo_surface_wrapper_t *wrapper, + cairo_image_surface_t *image, + void *image_extra) +{ + _cairo_surface_release_source_image (wrapper->target, image, image_extra); +} + +static void +_cairo_surface_wrapper_get_transform (cairo_surface_wrapper_t *wrapper, + cairo_matrix_t *m) +{ + cairo_matrix_init_identity (m); + + if (! _cairo_matrix_is_identity (&wrapper->transform)) + cairo_matrix_multiply (m, &wrapper->transform, m); + + if (! _cairo_matrix_is_identity (&wrapper->target->device_transform)) + cairo_matrix_multiply (m, &wrapper->target->device_transform, m); +} + +static void +_cairo_surface_wrapper_get_inverse_transform (cairo_surface_wrapper_t *wrapper, + cairo_matrix_t *m) +{ + cairo_matrix_init_identity (m); + + if (! _cairo_matrix_is_identity (&wrapper->target->device_transform_inverse)) + cairo_matrix_multiply (m, &wrapper->target->device_transform_inverse, m); + + if (! _cairo_matrix_is_identity (&wrapper->transform)) { + cairo_matrix_t inv; + cairo_status_t status; + + inv = wrapper->transform; + status = cairo_matrix_invert (&inv); + assert (status == CAIRO_STATUS_SUCCESS); + cairo_matrix_multiply (m, &inv, m); + } +} + +static cairo_clip_t * +_cairo_surface_wrapper_get_clip (cairo_surface_wrapper_t *wrapper, + const cairo_clip_t *clip) +{ + cairo_clip_t *copy; + cairo_matrix_t m; + + copy = _cairo_clip_copy (clip); + if (wrapper->has_extents) { + copy = _cairo_clip_intersect_rectangle (copy, &wrapper->extents); + } + _cairo_surface_wrapper_get_transform (wrapper, &m); + copy = _cairo_clip_transform (copy, &m); + if (wrapper->clip) + copy = _cairo_clip_intersect_clip (copy, wrapper->clip); + + return copy; +} + +cairo_status_t +_cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper, + cairo_operator_t op, + const cairo_pattern_t *source, + unsigned int source_region_id, + const cairo_clip_t *clip) +{ + cairo_status_t status; + cairo_clip_t *dev_clip; + cairo_pattern_union_t source_copy; + + if (unlikely (wrapper->target->status)) + return wrapper->target->status; + + dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip); + if (_cairo_clip_is_all_clipped (dev_clip)) + return CAIRO_INT_STATUS_NOTHING_TO_DO; + + if (wrapper->needs_transform || source_region_id != 0) { + cairo_matrix_t m; + + _cairo_surface_wrapper_get_transform (wrapper, &m); + + status = cairo_matrix_invert (&m); + assert (status == CAIRO_STATUS_SUCCESS); + + _copy_transformed_pattern (&source_copy.base, source, &m, source_region_id); + source = &source_copy.base; + } + + status = _cairo_surface_paint (wrapper->target, op, source, dev_clip); + + _cairo_clip_destroy (dev_clip); + return status; +} + +cairo_status_t +_cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper, + cairo_operator_t op, + const cairo_pattern_t *source, + unsigned int source_region_id, + const cairo_pattern_t *mask, + unsigned int mask_region_id, + const cairo_clip_t *clip) +{ + cairo_status_t status; + cairo_clip_t *dev_clip; + cairo_pattern_union_t source_copy; + cairo_pattern_union_t mask_copy; + + if (unlikely (wrapper->target->status)) + return wrapper->target->status; + + dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip); + if (_cairo_clip_is_all_clipped (dev_clip)) + return CAIRO_INT_STATUS_NOTHING_TO_DO; + + if (wrapper->needs_transform || source_region_id != 0 || mask_region_id != 0) { + cairo_matrix_t m; + + _cairo_surface_wrapper_get_transform (wrapper, &m); + + status = cairo_matrix_invert (&m); + assert (status == CAIRO_STATUS_SUCCESS); + + _copy_transformed_pattern (&source_copy.base, source, &m, source_region_id); + source = &source_copy.base; + + _copy_transformed_pattern (&mask_copy.base, mask, &m, mask_region_id); + mask = &mask_copy.base; + } + + status = _cairo_surface_mask (wrapper->target, op, source, mask, dev_clip); + + _cairo_clip_destroy (dev_clip); + return status; +} + +cairo_status_t +_cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper, + cairo_operator_t op, + const cairo_pattern_t *source, + unsigned int source_region_id, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_status_t status; + cairo_path_fixed_t path_copy, *dev_path = (cairo_path_fixed_t *) path; + cairo_clip_t *dev_clip; + cairo_matrix_t dev_ctm = *ctm; + cairo_matrix_t dev_ctm_inverse = *ctm_inverse; + cairo_pattern_union_t source_copy; + + if (unlikely (wrapper->target->status)) + return wrapper->target->status; + + dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip); + if (_cairo_clip_is_all_clipped (dev_clip)) + return CAIRO_INT_STATUS_NOTHING_TO_DO; + + if (wrapper->needs_transform || source_region_id != 0) { + cairo_matrix_t m; + + _cairo_surface_wrapper_get_transform (wrapper, &m); + + status = _cairo_path_fixed_init_copy (&path_copy, dev_path); + if (unlikely (status)) + goto FINISH; + + _cairo_path_fixed_transform (&path_copy, &m); + dev_path = &path_copy; + + cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m); + + status = cairo_matrix_invert (&m); + assert (status == CAIRO_STATUS_SUCCESS); + + cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse); + + _copy_transformed_pattern (&source_copy.base, source, &m, source_region_id); + source = &source_copy.base; + } + + status = _cairo_surface_stroke (wrapper->target, op, source, + dev_path, stroke_style, + &dev_ctm, &dev_ctm_inverse, + tolerance, antialias, + dev_clip); + + FINISH: + if (dev_path != path) + _cairo_path_fixed_fini (dev_path); + _cairo_clip_destroy (dev_clip); + return status; +} + +cairo_status_t +_cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper, + cairo_operator_t fill_op, + const cairo_pattern_t *fill_source, + unsigned int fill_region_id, + cairo_fill_rule_t fill_rule, + double fill_tolerance, + cairo_antialias_t fill_antialias, + const cairo_path_fixed_t *path, + cairo_operator_t stroke_op, + const cairo_pattern_t *stroke_source, + unsigned int stroke_region_id, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *stroke_ctm, + const cairo_matrix_t *stroke_ctm_inverse, + double stroke_tolerance, + cairo_antialias_t stroke_antialias, + const cairo_clip_t *clip) +{ + cairo_status_t status; + cairo_path_fixed_t path_copy, *dev_path = (cairo_path_fixed_t *)path; + cairo_matrix_t dev_ctm = *stroke_ctm; + cairo_matrix_t dev_ctm_inverse = *stroke_ctm_inverse; + cairo_clip_t *dev_clip; + cairo_pattern_union_t stroke_source_copy; + cairo_pattern_union_t fill_source_copy; + + if (unlikely (wrapper->target->status)) + return wrapper->target->status; + + dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip); + if (_cairo_clip_is_all_clipped (dev_clip)) + return CAIRO_INT_STATUS_NOTHING_TO_DO; + + if (wrapper->needs_transform || fill_region_id != 0 || stroke_region_id != 0) { + cairo_matrix_t m; + + _cairo_surface_wrapper_get_transform (wrapper, &m); + + status = _cairo_path_fixed_init_copy (&path_copy, dev_path); + if (unlikely (status)) + goto FINISH; + + _cairo_path_fixed_transform (&path_copy, &m); + dev_path = &path_copy; + + cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m); + + status = cairo_matrix_invert (&m); + assert (status == CAIRO_STATUS_SUCCESS); + + cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse); + + _copy_transformed_pattern (&stroke_source_copy.base, stroke_source, &m, fill_region_id); + stroke_source = &stroke_source_copy.base; + + _copy_transformed_pattern (&fill_source_copy.base, fill_source, &m, stroke_region_id); + fill_source = &fill_source_copy.base; + } + + status = _cairo_surface_fill_stroke (wrapper->target, + fill_op, fill_source, fill_rule, + fill_tolerance, fill_antialias, + dev_path, + stroke_op, stroke_source, + stroke_style, + &dev_ctm, &dev_ctm_inverse, + stroke_tolerance, stroke_antialias, + dev_clip); + + FINISH: + if (dev_path != path) + _cairo_path_fixed_fini (dev_path); + _cairo_clip_destroy (dev_clip); + return status; +} + +cairo_status_t +_cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper, + cairo_operator_t op, + const cairo_pattern_t *source, + unsigned int source_region_id, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_status_t status; + cairo_path_fixed_t path_copy, *dev_path = (cairo_path_fixed_t *) path; + cairo_pattern_union_t source_copy; + cairo_clip_t *dev_clip; + + if (unlikely (wrapper->target->status)) + return wrapper->target->status; + + dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip); + if (_cairo_clip_is_all_clipped (dev_clip)) + return CAIRO_INT_STATUS_NOTHING_TO_DO; + + if (wrapper->needs_transform || source_region_id != 0) { + cairo_matrix_t m; + + _cairo_surface_wrapper_get_transform (wrapper, &m); + + status = _cairo_path_fixed_init_copy (&path_copy, dev_path); + if (unlikely (status)) + goto FINISH; + + _cairo_path_fixed_transform (&path_copy, &m); + dev_path = &path_copy; + + status = cairo_matrix_invert (&m); + assert (status == CAIRO_STATUS_SUCCESS); + + _copy_transformed_pattern (&source_copy.base, source, &m, source_region_id); + source = &source_copy.base; + } + + status = _cairo_surface_fill (wrapper->target, op, source, + dev_path, fill_rule, + tolerance, antialias, + dev_clip); + + FINISH: + if (dev_path != path) + _cairo_path_fixed_fini (dev_path); + _cairo_clip_destroy (dev_clip); + return status; +} + +cairo_status_t +_cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper, + cairo_operator_t op, + const cairo_pattern_t *source, + unsigned int source_region_id, + const char *utf8, + int utf8_len, + const cairo_glyph_t *glyphs, + int num_glyphs, + const cairo_text_cluster_t *clusters, + int num_clusters, + cairo_text_cluster_flags_t cluster_flags, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip) +{ + cairo_status_t status; + cairo_clip_t *dev_clip; + cairo_glyph_t stack_glyphs [CAIRO_STACK_ARRAY_LENGTH(cairo_glyph_t)]; + cairo_glyph_t *dev_glyphs = stack_glyphs; + cairo_scaled_font_t *dev_scaled_font = scaled_font; + cairo_pattern_union_t source_copy; + cairo_font_options_t options; + + if (unlikely (wrapper->target->status)) + return wrapper->target->status; + + dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip); + if (_cairo_clip_is_all_clipped (dev_clip)) + return CAIRO_INT_STATUS_NOTHING_TO_DO; + + cairo_surface_get_font_options (wrapper->target, &options); + cairo_font_options_merge (&options, &scaled_font->options); + + if (wrapper->needs_transform || source_region_id != 0) { + cairo_matrix_t m; + int i; + + _cairo_surface_wrapper_get_transform (wrapper, &m); + + if (! _cairo_matrix_is_translation (&m)) { + cairo_matrix_t ctm; + + _cairo_matrix_multiply (&ctm, + &m, + &scaled_font->ctm); + dev_scaled_font = cairo_scaled_font_create (scaled_font->font_face, + &scaled_font->font_matrix, + &ctm, &options); + } + + if (num_glyphs > ARRAY_LENGTH (stack_glyphs)) { + dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); + if (unlikely (dev_glyphs == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto FINISH; + } + } + + for (i = 0; i < num_glyphs; i++) { + dev_glyphs[i] = glyphs[i]; + cairo_matrix_transform_point (&m, + &dev_glyphs[i].x, + &dev_glyphs[i].y); + } + + status = cairo_matrix_invert (&m); + assert (status == CAIRO_STATUS_SUCCESS); + + _copy_transformed_pattern (&source_copy.base, source, &m, source_region_id); + source = &source_copy.base; + } else { + if (! cairo_font_options_equal (&options, &scaled_font->options)) { + dev_scaled_font = cairo_scaled_font_create (scaled_font->font_face, + &scaled_font->font_matrix, + &scaled_font->ctm, + &options); + } + + /* show_text_glyphs is special because _cairo_surface_show_text_glyphs is allowed + * to modify the glyph array that's passed in. We must always + * copy the array before handing it to the backend. + */ + if (num_glyphs > ARRAY_LENGTH (stack_glyphs)) { + dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); + if (unlikely (dev_glyphs == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto FINISH; + } + } + + memcpy (dev_glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs); + } + + status = _cairo_surface_show_text_glyphs (wrapper->target, op, source, + utf8, utf8_len, + dev_glyphs, num_glyphs, + clusters, num_clusters, + cluster_flags, + dev_scaled_font, + dev_clip); + FINISH: + _cairo_clip_destroy (dev_clip); + if (dev_glyphs != stack_glyphs) + free (dev_glyphs); + if (dev_scaled_font != scaled_font) + cairo_scaled_font_destroy (dev_scaled_font); + return status; +} + +cairo_status_t +_cairo_surface_wrapper_tag (cairo_surface_wrapper_t *wrapper, + cairo_bool_t begin, + const char *tag_name, + const char *attributes) +{ + if (unlikely (wrapper->target->status)) + return wrapper->target->status; + + + return _cairo_surface_tag (wrapper->target, begin, tag_name, attributes); +} + +cairo_surface_t * +_cairo_surface_wrapper_create_similar (cairo_surface_wrapper_t *wrapper, + cairo_content_t content, + int width, + int height) +{ + return _cairo_surface_create_scratch (wrapper->target, + content, width, height, NULL); +} + +cairo_bool_t +_cairo_surface_wrapper_get_extents (cairo_surface_wrapper_t *wrapper, + cairo_rectangle_int_t *extents) +{ + if (wrapper->has_extents) { + if (_cairo_surface_get_extents (wrapper->target, extents)) + _cairo_rectangle_intersect (extents, &wrapper->extents); + else + *extents = wrapper->extents; + + return TRUE; + } else { + return _cairo_surface_get_extents (wrapper->target, extents); + } +} + +static cairo_bool_t +_cairo_surface_wrapper_needs_device_transform (cairo_surface_wrapper_t *wrapper) +{ + return + (wrapper->has_extents && (wrapper->extents.x | wrapper->extents.y)) || + ! _cairo_matrix_is_identity (&wrapper->transform) || + ! _cairo_matrix_is_identity (&wrapper->target->device_transform); +} + +void +_cairo_surface_wrapper_intersect_extents (cairo_surface_wrapper_t *wrapper, + const cairo_rectangle_int_t *extents) +{ + if (! wrapper->has_extents) { + wrapper->extents = *extents; + wrapper->has_extents = TRUE; + } else + _cairo_rectangle_intersect (&wrapper->extents, extents); + + wrapper->needs_transform = + _cairo_surface_wrapper_needs_device_transform (wrapper); +} + +void +_cairo_surface_wrapper_set_inverse_transform (cairo_surface_wrapper_t *wrapper, + const cairo_matrix_t *transform) +{ + cairo_status_t status; + + if (transform == NULL || _cairo_matrix_is_identity (transform)) { + cairo_matrix_init_identity (&wrapper->transform); + + wrapper->needs_transform = + _cairo_surface_wrapper_needs_device_transform (wrapper); + } else { + wrapper->transform = *transform; + status = cairo_matrix_invert (&wrapper->transform); + /* should always be invertible unless given pathological input */ + assert (status == CAIRO_STATUS_SUCCESS); + + wrapper->needs_transform = TRUE; + } +} + +void +_cairo_surface_wrapper_set_clip (cairo_surface_wrapper_t *wrapper, + const cairo_clip_t *clip) +{ + wrapper->clip = clip; +} + +void +_cairo_surface_wrapper_get_font_options (cairo_surface_wrapper_t *wrapper, + cairo_font_options_t *options) +{ + cairo_surface_get_font_options (wrapper->target, options); +} + +cairo_surface_t * +_cairo_surface_wrapper_snapshot (cairo_surface_wrapper_t *wrapper) +{ + if (wrapper->target->backend->snapshot) + return wrapper->target->backend->snapshot (wrapper->target); + + return NULL; +} + +cairo_bool_t +_cairo_surface_wrapper_has_show_text_glyphs (cairo_surface_wrapper_t *wrapper) +{ + return cairo_surface_has_show_text_glyphs (wrapper->target); +} + +void +_cairo_surface_wrapper_init (cairo_surface_wrapper_t *wrapper, + cairo_surface_t *target) +{ + wrapper->target = cairo_surface_reference (target); + cairo_matrix_init_identity (&wrapper->transform); + wrapper->has_extents = FALSE; + wrapper->extents.x = wrapper->extents.y = 0; + wrapper->clip = NULL; + wrapper->source_region_id = 0; + wrapper->mask_region_id = 0; + + wrapper->needs_transform = FALSE; + if (target) { + wrapper->needs_transform = + ! _cairo_matrix_is_identity (&target->device_transform); + } +} + +void +_cairo_surface_wrapper_fini (cairo_surface_wrapper_t *wrapper) +{ + cairo_surface_destroy (wrapper->target); +} + +cairo_bool_t +_cairo_surface_wrapper_get_target_extents (cairo_surface_wrapper_t *wrapper, + cairo_bool_t surface_is_unbounded, + cairo_rectangle_int_t *extents) +{ + cairo_rectangle_int_t clip; + cairo_bool_t has_clip = FALSE; + + if (!surface_is_unbounded) + has_clip = _cairo_surface_get_extents (wrapper->target, &clip); + + if (wrapper->clip) { + if (has_clip) { + if (! _cairo_rectangle_intersect (&clip, + _cairo_clip_get_extents (wrapper->clip))) + return FALSE; + } else { + has_clip = TRUE; + clip = *_cairo_clip_get_extents (wrapper->clip); + } + } + + if (has_clip && wrapper->needs_transform) { + cairo_matrix_t m; + double x1, y1, x2, y2; + + _cairo_surface_wrapper_get_inverse_transform (wrapper, &m); + + x1 = clip.x; + y1 = clip.y; + x2 = clip.x + clip.width; + y2 = clip.y + clip.height; + + _cairo_matrix_transform_bounding_box (&m, &x1, &y1, &x2, &y2, NULL); + + clip.x = floor (x1); + clip.y = floor (y1); + clip.width = ceil (x2) - clip.x; + clip.height = ceil (y2) - clip.y; + } + + if (has_clip) { + if (wrapper->has_extents) { + *extents = wrapper->extents; + return _cairo_rectangle_intersect (extents, &clip); + } else { + *extents = clip; + return TRUE; + } + } else if (wrapper->has_extents) { + *extents = wrapper->extents; + return TRUE; + } else { + _cairo_unbounded_rectangle_init (extents); + return TRUE; + } +} diff --git a/local/recipes/libs/cairo/source/src/cairo-surface.c b/local/recipes/libs/cairo/source/src/cairo-surface.c new file mode 100644 index 0000000000..86c1837b9b --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-surface.c @@ -0,0 +1,3196 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + */ + +#include "cairoint.h" + +#include "cairo-array-private.h" +#include "cairo-clip-inline.h" +#include "cairo-clip-private.h" +#include "cairo-damage-private.h" +#include "cairo-device-private.h" +#include "cairo-error-private.h" +#include "cairo-list-inline.h" +#include "cairo-image-surface-inline.h" +#include "cairo-recording-surface-private.h" +#include "cairo-region-private.h" +#include "cairo-surface-inline.h" + +/** + * SECTION:cairo-surface + * @Title: cairo_surface_t + * @Short_Description: Base class for surfaces + * @See_Also: #cairo_t, #cairo_pattern_t + * + * #cairo_surface_t is the abstract type representing all different drawing + * targets that cairo can render to. The actual drawings are + * performed using a cairo context. + * + * A cairo surface is created by using backend-specific + * constructors, typically of the form + * cairo_backend_surface_create(). + * + * Most surface types allow accessing the surface without using Cairo + * functions. If you do this, keep in mind that it is mandatory that you call + * cairo_surface_flush() before reading from or writing to the surface and that + * you must use cairo_surface_mark_dirty() after modifying it. + * + * Directly modifying an image surface + * + * void + * modify_image_surface (cairo_surface_t *surface) + * { + * unsigned char *data; + * int width, height, stride; + * + * // flush to ensure all writing to the image was done + * cairo_surface_flush (surface); + * + * // modify the image + * data = cairo_image_surface_get_data (surface); + * width = cairo_image_surface_get_width (surface); + * height = cairo_image_surface_get_height (surface); + * stride = cairo_image_surface_get_stride (surface); + * modify_image_data (data, width, height, stride); + * + * // mark the image dirty so Cairo clears its caches. + * cairo_surface_mark_dirty (surface); + * } + * + * + * Note that for other surface types it might be necessary to acquire the + * surface's device first. See cairo_device_acquire() for a discussion of + * devices. + **/ + +#define DEFINE_NIL_SURFACE(status, name) \ +const cairo_surface_t name = { \ + NULL, /* backend */ \ + NULL, /* device */ \ + CAIRO_SURFACE_TYPE_IMAGE, /* type */ \ + CAIRO_CONTENT_COLOR, /* content */ \ + CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ \ + status, /* status */ \ + 0, /* unique id */ \ + 0, /* serial */ \ + NULL, /* damage */ \ + FALSE, /* _finishing */ \ + FALSE, /* finished */ \ + TRUE, /* is_clear */ \ + FALSE, /* has_font_options */ \ + FALSE, /* owns_device */ \ + FALSE, /* is_vector */ \ + { 0, 0, 0, NULL, }, /* user_data */ \ + { 0, 0, 0, NULL, }, /* mime_data */ \ + { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, /* device_transform */ \ + { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, /* device_transform_inverse */ \ + { NULL, NULL }, /* device_transform_observers */ \ + 0.0, /* x_resolution */ \ + 0.0, /* y_resolution */ \ + 0.0, /* x_fallback_resolution */ \ + 0.0, /* y_fallback_resolution */ \ + NULL, /* snapshot_of */ \ + NULL, /* snapshot_detach */ \ + { NULL, NULL }, /* snapshots */ \ + { NULL, NULL }, /* snapshot */ \ + { /* font options begin */\ + CAIRO_ANTIALIAS_DEFAULT, /* antialias */ \ + CAIRO_SUBPIXEL_ORDER_DEFAULT, /* subpixel_order */ \ + CAIRO_LCD_FILTER_DEFAULT, /* lcd_filter */ \ + CAIRO_HINT_STYLE_DEFAULT, /* hint_style */ \ + CAIRO_HINT_METRICS_DEFAULT, /* hint_metrics */ \ + CAIRO_ROUND_GLYPH_POS_DEFAULT, /* round_glyph_positions */ \ + NULL, /* variations */ \ + CAIRO_COLOR_MODE_DEFAULT, /* color mode */ \ + CAIRO_COLOR_PALETTE_DEFAULT, /* color palette */ \ + NULL, 0, /* custom palette */ \ + }, /* font_options end */ \ + NULL, /* foreground_source */ \ + FALSE, /* foreground_used */ \ +} + +/* XXX error object! */ + +static DEFINE_NIL_SURFACE(CAIRO_STATUS_NO_MEMORY, _cairo_surface_nil); +static DEFINE_NIL_SURFACE(CAIRO_STATUS_SURFACE_TYPE_MISMATCH, _cairo_surface_nil_surface_type_mismatch); +static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_STATUS, _cairo_surface_nil_invalid_status); +static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_CONTENT, _cairo_surface_nil_invalid_content); +static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_FORMAT, _cairo_surface_nil_invalid_format); +static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_VISUAL, _cairo_surface_nil_invalid_visual); +static DEFINE_NIL_SURFACE(CAIRO_STATUS_FILE_NOT_FOUND, _cairo_surface_nil_file_not_found); +static DEFINE_NIL_SURFACE(CAIRO_STATUS_TEMP_FILE_ERROR, _cairo_surface_nil_temp_file_error); +static DEFINE_NIL_SURFACE(CAIRO_STATUS_READ_ERROR, _cairo_surface_nil_read_error); +static DEFINE_NIL_SURFACE(CAIRO_STATUS_WRITE_ERROR, _cairo_surface_nil_write_error); +static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_STRIDE, _cairo_surface_nil_invalid_stride); +static DEFINE_NIL_SURFACE(CAIRO_STATUS_INVALID_SIZE, _cairo_surface_nil_invalid_size); +static DEFINE_NIL_SURFACE(CAIRO_STATUS_DEVICE_TYPE_MISMATCH, _cairo_surface_nil_device_type_mismatch); +static DEFINE_NIL_SURFACE(CAIRO_STATUS_DEVICE_ERROR, _cairo_surface_nil_device_error); +static DEFINE_NIL_SURFACE(CAIRO_STATUS_PNG_ERROR, _cairo_surface_nil_png_error); + +static DEFINE_NIL_SURFACE(CAIRO_INT_STATUS_UNSUPPORTED, _cairo_surface_nil_unsupported); +static DEFINE_NIL_SURFACE(CAIRO_INT_STATUS_NOTHING_TO_DO, _cairo_surface_nil_nothing_to_do); + +static void _cairo_surface_finish_snapshots (cairo_surface_t *surface); +static void _cairo_surface_finish (cairo_surface_t *surface); + +/** + * _cairo_surface_set_error: + * @surface: a surface + * @status: a status value indicating an error + * + * Atomically sets surface->status to @status and calls _cairo_error; + * Does nothing if status is %CAIRO_STATUS_SUCCESS or any of the internal + * status values. + * + * All assignments of an error status to surface->status should happen + * through _cairo_surface_set_error(). Note that due to the nature of + * the atomic operation, it is not safe to call this function on the + * nil objects. + * + * The purpose of this function is to allow the user to set a + * breakpoint in _cairo_error() to generate a stack trace for when the + * user causes cairo to detect an error. + * + * Return value: the error status. + **/ +cairo_int_status_t +_cairo_surface_set_error (cairo_surface_t *surface, + cairo_int_status_t status) +{ + /* NOTHING_TO_DO is magic. We use it to break out of the inner-most + * surface function, but anything higher just sees "success". + */ + if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) + status = CAIRO_INT_STATUS_SUCCESS; + + if (status == CAIRO_INT_STATUS_SUCCESS || + status >= (int)CAIRO_INT_STATUS_LAST_STATUS) + return status; + + /* Don't overwrite an existing error. This preserves the first + * error, which is the most significant. */ + _cairo_status_set_error (&surface->status, (cairo_status_t)status); + + return _cairo_error (status); +} + +/** + * cairo_surface_get_type: + * @surface: a #cairo_surface_t + * + * This function returns the type of the backend used to create + * a surface. See #cairo_surface_type_t for available types. + * + * Return value: The type of @surface. + * + * Since: 1.2 + **/ +cairo_surface_type_t +cairo_surface_get_type (cairo_surface_t *surface) +{ + /* We don't use surface->backend->type here so that some of the + * special "wrapper" surfaces such as cairo_paginated_surface_t + * can override surface->type with the type of the "child" + * surface. */ + return surface->type; +} + +/** + * cairo_surface_get_content: + * @surface: a #cairo_surface_t + * + * This function returns the content type of @surface which indicates + * whether the surface contains color and/or alpha information. See + * #cairo_content_t. + * + * Return value: The content type of @surface. + * + * Since: 1.2 + **/ +cairo_content_t +cairo_surface_get_content (cairo_surface_t *surface) +{ + return surface->content; +} + +/** + * cairo_surface_status: + * @surface: a #cairo_surface_t + * + * Checks whether an error has previously occurred for this + * surface. + * + * Return value: %CAIRO_STATUS_SUCCESS, %CAIRO_STATUS_NULL_POINTER, + * %CAIRO_STATUS_NO_MEMORY, %CAIRO_STATUS_READ_ERROR, + * %CAIRO_STATUS_INVALID_CONTENT, %CAIRO_STATUS_INVALID_FORMAT, or + * %CAIRO_STATUS_INVALID_VISUAL. + * + * Since: 1.0 + **/ +cairo_status_t +cairo_surface_status (cairo_surface_t *surface) +{ + return surface->status; +} + +static unsigned int +_cairo_surface_allocate_unique_id (void) +{ + static cairo_atomic_int_t unique_id; + +#if CAIRO_NO_MUTEX + if (++unique_id == 0) + unique_id = 1; + return unique_id; +#else + int old, id; + + do { + old = _cairo_atomic_uint_get (&unique_id); + id = old + 1; + if (id == 0) + id = 1; + } while (! _cairo_atomic_uint_cmpxchg (&unique_id, old, id)); + + return id; +#endif +} + +/** + * cairo_surface_get_device: + * @surface: a #cairo_surface_t + * + * This function returns the device for a @surface. + * See #cairo_device_t. + * + * Return value: The device for @surface or %NULL if the surface does + * not have an associated device. + * + * Since: 1.10 + **/ +cairo_device_t * +cairo_surface_get_device (cairo_surface_t *surface) +{ + if (unlikely (surface->status)) + return _cairo_device_create_in_error (surface->status); + + return surface->device; +} + +static cairo_bool_t +_cairo_surface_has_snapshots (cairo_surface_t *surface) +{ + return ! cairo_list_is_empty (&surface->snapshots); +} + +static cairo_bool_t +_cairo_surface_has_mime_data (cairo_surface_t *surface) +{ + return surface->mime_data.num_elements != 0; +} + +static void +_cairo_surface_detach_mime_data (cairo_surface_t *surface) +{ + if (! _cairo_surface_has_mime_data (surface)) + return; + + _cairo_user_data_array_fini (&surface->mime_data); + _cairo_user_data_array_init (&surface->mime_data); +} + +static void +_cairo_surface_detach_snapshots (cairo_surface_t *surface) +{ + while (_cairo_surface_has_snapshots (surface)) { + _cairo_surface_detach_snapshot (cairo_list_first_entry (&surface->snapshots, + cairo_surface_t, + snapshot)); + } +} + +void +_cairo_surface_detach_snapshot (cairo_surface_t *snapshot) +{ + assert (snapshot->snapshot_of != NULL); + + snapshot->snapshot_of = NULL; + cairo_list_del (&snapshot->snapshot); + + if (snapshot->snapshot_detach != NULL) + snapshot->snapshot_detach (snapshot); + + cairo_surface_destroy (snapshot); +} + +void +_cairo_surface_attach_snapshot (cairo_surface_t *surface, + cairo_surface_t *snapshot, + cairo_surface_func_t detach_func) +{ + assert (surface != snapshot); + assert (snapshot->snapshot_of != surface); + + cairo_surface_reference (snapshot); + + if (snapshot->snapshot_of != NULL) + _cairo_surface_detach_snapshot (snapshot); + + snapshot->snapshot_of = surface; + snapshot->snapshot_detach = detach_func; + + cairo_list_add (&snapshot->snapshot, &surface->snapshots); + + assert (_cairo_surface_has_snapshot (surface, snapshot->backend) == snapshot); +} + +cairo_surface_t * +_cairo_surface_has_snapshot (cairo_surface_t *surface, + const cairo_surface_backend_t *backend) +{ + cairo_surface_t *snapshot; + + cairo_list_foreach_entry (snapshot, cairo_surface_t, + &surface->snapshots, snapshot) + { + if (snapshot->backend == backend) + return snapshot; + } + + return NULL; +} + +cairo_status_t +_cairo_surface_begin_modification (cairo_surface_t *surface) +{ + assert (surface->status == CAIRO_STATUS_SUCCESS); + assert (! surface->finished); + + return _cairo_surface_flush (surface, 1); +} + +void +_cairo_surface_init (cairo_surface_t *surface, + const cairo_surface_backend_t *backend, + cairo_device_t *device, + cairo_content_t content, + cairo_bool_t is_vector) +{ + CAIRO_MUTEX_INITIALIZE (); + + surface->backend = backend; + surface->device = cairo_device_reference (device); + surface->content = content; + surface->type = backend->type; + surface->is_vector = is_vector; + + CAIRO_REFERENCE_COUNT_INIT (&surface->ref_count, 1); + surface->status = CAIRO_STATUS_SUCCESS; + surface->unique_id = _cairo_surface_allocate_unique_id (); + surface->finished = FALSE; + surface->_finishing = FALSE; + surface->is_clear = FALSE; + surface->serial = 0; + surface->damage = NULL; + surface->owns_device = (device != NULL); + + _cairo_user_data_array_init (&surface->user_data); + _cairo_user_data_array_init (&surface->mime_data); + + cairo_matrix_init_identity (&surface->device_transform); + cairo_matrix_init_identity (&surface->device_transform_inverse); + cairo_list_init (&surface->device_transform_observers); + + surface->x_resolution = CAIRO_SURFACE_RESOLUTION_DEFAULT; + surface->y_resolution = CAIRO_SURFACE_RESOLUTION_DEFAULT; + + surface->x_fallback_resolution = CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT; + surface->y_fallback_resolution = CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT; + + cairo_list_init (&surface->snapshots); + surface->snapshot_of = NULL; + + surface->has_font_options = FALSE; + + surface->foreground_source = NULL; + surface->foreground_used = FALSE; +} + +static void +_cairo_surface_copy_similar_properties (cairo_surface_t *surface, + cairo_surface_t *other) +{ + if (other->has_font_options || other->backend != surface->backend) { + cairo_font_options_t options; + + cairo_surface_get_font_options (other, &options); + _cairo_surface_set_font_options (surface, &options); + _cairo_font_options_fini (&options); + } + + cairo_surface_set_fallback_resolution (surface, + other->x_fallback_resolution, + other->y_fallback_resolution); +} + +/** + * cairo_surface_create_similar: + * @other: an existing surface used to select the backend of the new surface + * @content: the content for the new surface + * @width: width of the new surface, (in device-space units) + * @height: height of the new surface (in device-space units) + * + * Create a new surface that is as compatible as possible with an + * existing surface. For example the new surface will have the same + * device scale, fallback resolution and font options as + * @other. Generally, the new surface will also use the same backend + * as @other, unless that is not possible for some reason. The type of + * the returned surface may be examined with + * cairo_surface_get_type(). + * + * Initially the surface contents are all 0 (transparent if contents + * have transparency, black otherwise.) + * + * Use cairo_surface_create_similar_image() if you need an image surface + * which can be painted quickly to the target surface. + * + * Return value: a pointer to the newly allocated surface. The caller + * owns the surface and should call cairo_surface_destroy() when done + * with it. + * + * This function always returns a valid pointer, but it will return a + * pointer to a "nil" surface if @other is already in an error state + * or any other error occurs. + * + * Since: 1.0 + **/ +cairo_surface_t * +cairo_surface_create_similar (cairo_surface_t *other, + cairo_content_t content, + int width, + int height) +{ + cairo_surface_t *surface; + cairo_status_t status; + cairo_solid_pattern_t pattern; + + if (unlikely (other->status)) + return _cairo_surface_create_in_error (other->status); + if (unlikely (other->finished)) + return _cairo_surface_create_in_error (CAIRO_STATUS_SURFACE_FINISHED); + if (unlikely (width < 0 || height < 0)) + return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE); + if (unlikely (! CAIRO_CONTENT_VALID (content))) + return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_CONTENT); + + /* We inherit the device scale, so create a larger surface */ + width = width * other->device_transform.xx; + height = height * other->device_transform.yy; + + surface = NULL; + if (other->backend->create_similar) + surface = other->backend->create_similar (other, content, width, height); + if (surface == NULL) + surface = cairo_surface_create_similar_image (other, + _cairo_format_from_content (content), + width, height); + + if (unlikely (surface->status)) + return surface; + + _cairo_surface_copy_similar_properties (surface, other); + cairo_surface_set_device_scale (surface, + other->device_transform.xx, + other->device_transform.yy); + + if (unlikely (surface->status)) + return surface; + + _cairo_pattern_init_solid (&pattern, CAIRO_COLOR_TRANSPARENT); + status = _cairo_surface_paint (surface, + CAIRO_OPERATOR_CLEAR, + &pattern.base, NULL); + if (unlikely (status)) { + cairo_surface_destroy (surface); + surface = _cairo_surface_create_in_error (status); + } + + assert (surface->is_clear); + + return surface; +} + +/** + * cairo_surface_create_similar_image: + * @other: an existing surface used to select the preference of the new surface + * @format: the format for the new surface + * @width: width of the new surface, (in pixels) + * @height: height of the new surface (in pixels) + * + * Create a new image surface that is as compatible as possible for uploading + * to and the use in conjunction with an existing surface. However, this surface + * can still be used like any normal image surface. Unlike + * cairo_surface_create_similar() the new image surface won't inherit + * the device scale from @other. + * + * Initially the surface contents are all 0 (transparent if contents + * have transparency, black otherwise.) + * + * Use cairo_surface_create_similar() if you don't need an image surface. + * + * Return value: a pointer to the newly allocated image surface. The caller + * owns the surface and should call cairo_surface_destroy() when done + * with it. + * + * This function always returns a valid pointer, but it will return a + * pointer to a "nil" surface if @other is already in an error state + * or any other error occurs. + * + * Since: 1.12 + **/ +cairo_surface_t * +cairo_surface_create_similar_image (cairo_surface_t *other, + cairo_format_t format, + int width, + int height) +{ + cairo_surface_t *image; + + if (unlikely (other->status)) + return _cairo_surface_create_in_error (other->status); + if (unlikely (other->finished)) + return _cairo_surface_create_in_error (CAIRO_STATUS_SURFACE_FINISHED); + + if (unlikely (width < 0 || height < 0)) + return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE); + if (unlikely (! CAIRO_FORMAT_VALID (format))) + return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_FORMAT); + + image = NULL; + if (other->backend->create_similar_image) + image = other->backend->create_similar_image (other, + format, width, height); + if (image == NULL) + image = cairo_image_surface_create (format, width, height); + + assert (image->is_clear); + + return image; +} + +/** + * _cairo_surface_map_to_image: + * @surface: an existing surface used to extract the image from + * @extents: limit the extraction to an rectangular region + * + * Returns an image surface that is the most efficient mechanism for + * modifying the backing store of the target surface. The region + * retrieved is limited to @extents. + * + * Note, the use of the original surface as a target or source whilst + * it is mapped is undefined. The result of mapping the surface + * multiple times is undefined. Calling cairo_surface_destroy() or + * cairo_surface_finish() on the resulting image surface results in + * undefined behavior. Changing the device transform of the image + * surface or of @surface before the image surface is unmapped results + * in undefined behavior. + * + * Assumes that @surface is valid (CAIRO_STATUS_SUCCESS, + * non-finished). + * + * Return value: a pointer to the newly allocated image surface. The + * caller must use _cairo_surface_unmap_image() to destroy this image + * surface. + * + * This function always returns a valid pointer, but it will return a + * pointer to a "nil" surface if @other is already in an error state + * or any other error occurs. + * + * The returned image might have a %CAIRO_FORMAT_INVALID format. + **/ +cairo_image_surface_t * +_cairo_surface_map_to_image (cairo_surface_t *surface, + const cairo_rectangle_int_t *extents) +{ + cairo_image_surface_t *image = NULL; + + assert (extents != NULL); + + /* TODO: require map_to_image != NULL */ + if (surface->backend->map_to_image) + image = surface->backend->map_to_image (surface, extents); + + if (image == NULL) + image = _cairo_image_surface_clone_subimage (surface, extents); + + return image; +} + +/** + * _cairo_surface_unmap_image: + * @surface: the surface passed to _cairo_surface_map_to_image(). + * @image: the currently mapped image + * + * Unmaps the image surface as returned from + * _cairo_surface_map_to_image(). + * + * The content of the image will be uploaded to the target surface. + * Afterwards, the image is destroyed. + * + * Using an image surface which wasn't returned by + * _cairo_surface_map_to_image() results in undefined behavior. + * + * An image surface in error status can be passed to + * _cairo_surface_unmap_image(). + * + * Return value: the unmap status. + * + * Even if the unmap status is not successful, @image is destroyed. + **/ +cairo_int_status_t +_cairo_surface_unmap_image (cairo_surface_t *surface, + cairo_image_surface_t *image) +{ + cairo_surface_pattern_t pattern; + cairo_rectangle_int_t extents; + cairo_clip_t *clip; + cairo_int_status_t status; + + /* map_to_image can return error surfaces */ + if (unlikely (image->base.status)) { + status = image->base.status; + goto destroy; + } + + /* If the image is untouched just skip the update */ + if (image->base.serial == 0) { + status = CAIRO_STATUS_SUCCESS; + goto destroy; + } + + /* TODO: require unmap_image != NULL */ + if (surface->backend->unmap_image && + ! _cairo_image_surface_is_clone (image)) + { + status = surface->backend->unmap_image (surface, image); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + } + + _cairo_pattern_init_for_surface (&pattern, &image->base); + pattern.base.filter = CAIRO_FILTER_NEAREST; + + /* We have to apply the translate from map_to_image's extents.x and .y */ + cairo_matrix_init_translate (&pattern.base.matrix, + image->base.device_transform.x0, + image->base.device_transform.y0); + + /* And we also have to clip the operation to the image's extents */ + extents.x = image->base.device_transform_inverse.x0; + extents.y = image->base.device_transform_inverse.y0; + extents.width = image->width; + extents.height = image->height; + clip = _cairo_clip_intersect_rectangle (NULL, &extents); + + status = _cairo_surface_paint (surface, + CAIRO_OPERATOR_SOURCE, + &pattern.base, + clip); + + _cairo_pattern_fini (&pattern.base); + _cairo_clip_destroy (clip); + +destroy: + cairo_surface_finish (&image->base); + cairo_surface_destroy (&image->base); + + return status; +} + +/** + * cairo_surface_map_to_image: + * @surface: an existing surface used to extract the image from + * @extents: limit the extraction to an rectangular region + * + * Returns an image surface that is the most efficient mechanism for + * modifying the backing store of the target surface. The region retrieved + * may be limited to the @extents or %NULL for the whole surface + * + * Note, the use of the original surface as a target or source whilst + * it is mapped is undefined. The result of mapping the surface + * multiple times is undefined. Calling cairo_surface_destroy() or + * cairo_surface_finish() on the resulting image surface results in + * undefined behavior. Changing the device transform of the image + * surface or of @surface before the image surface is unmapped results + * in undefined behavior. + * + * Return value: a pointer to the newly allocated image surface. The caller + * must use cairo_surface_unmap_image() to destroy this image surface. + * + * This function always returns a valid pointer, but it will return a + * pointer to a "nil" surface if @other is already in an error state + * or any other error occurs. If the returned pointer does not have an + * error status, it is guaranteed to be an image surface whose format + * is not %CAIRO_FORMAT_INVALID. + * + * Since: 1.12 + **/ +cairo_surface_t * +cairo_surface_map_to_image (cairo_surface_t *surface, + const cairo_rectangle_int_t *extents) +{ + cairo_rectangle_int_t rect; + cairo_image_surface_t *image; + cairo_status_t status; + + if (unlikely (surface->status)) + return _cairo_surface_create_in_error (surface->status); + if (unlikely (surface->finished)) + return _cairo_surface_create_in_error (CAIRO_STATUS_SURFACE_FINISHED); + + if (extents == NULL) { + if (unlikely (! surface->backend->get_extents (surface, &rect))) + return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE); + + extents = ▭ + } else { + cairo_rectangle_int_t surface_extents; + + /* If this surface is bounded, we can't map parts + * that are outside of it. */ + if (likely (surface->backend->get_extents (surface, &surface_extents))) { + if (unlikely (! _cairo_rectangle_contains_rectangle (&surface_extents, extents))) + return _cairo_surface_create_in_error (CAIRO_STATUS_INVALID_SIZE); + } + } + + image = _cairo_surface_map_to_image (surface, extents); + + status = image->base.status; + if (unlikely (status)) { + cairo_surface_destroy (&image->base); + return _cairo_surface_create_in_error (status); + } + + if (image->format == CAIRO_FORMAT_INVALID) { + cairo_surface_destroy (&image->base); + image = _cairo_image_surface_clone_subimage (surface, extents); + } + + return &image->base; +} + +/** + * cairo_surface_unmap_image: + * @surface: the surface passed to cairo_surface_map_to_image(). + * @image: the currently mapped image + * + * Unmaps the image surface as returned from #cairo_surface_map_to_image(). + * + * The content of the image will be uploaded to the target surface. + * Afterwards, the image is destroyed. + * + * Using an image surface which wasn't returned by cairo_surface_map_to_image() + * results in undefined behavior. + * + * Since: 1.12 + **/ +void +cairo_surface_unmap_image (cairo_surface_t *surface, + cairo_surface_t *image) +{ + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + + if (unlikely (surface->status)) { + status = surface->status; + goto error; + } + if (unlikely (surface->finished)) { + status = _cairo_error (CAIRO_STATUS_SURFACE_FINISHED); + goto error; + } + if (unlikely (image->status)) { + status = image->status; + goto error; + } + if (unlikely (image->finished)) { + status = _cairo_error (CAIRO_STATUS_SURFACE_FINISHED); + goto error; + } + if (unlikely (! _cairo_surface_is_image (image))) { + status = _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + goto error; + } + + status = _cairo_surface_unmap_image (surface, + (cairo_image_surface_t *) image); + if (unlikely (status)) + _cairo_surface_set_error (surface, status); + + return; + +error: + _cairo_surface_set_error (surface, status); + cairo_surface_finish (image); + cairo_surface_destroy (image); +} + +cairo_surface_t * +_cairo_surface_create_scratch (cairo_surface_t *other, + cairo_content_t content, + int width, + int height, + const cairo_color_t *color) +{ + cairo_surface_t *surface; + cairo_status_t status; + cairo_solid_pattern_t pattern; + + if (unlikely (other->status)) + return _cairo_surface_create_in_error (other->status); + + surface = NULL; + if (other->backend->create_similar) + surface = other->backend->create_similar (other, content, width, height); + if (surface == NULL) + surface = cairo_surface_create_similar_image (other, + _cairo_format_from_content (content), + width, height); + + if (unlikely (surface->status)) + return surface; + + _cairo_surface_copy_similar_properties (surface, other); + + if (unlikely (surface->status)) + return surface; + + if (color) { + _cairo_pattern_init_solid (&pattern, color); + status = _cairo_surface_paint (surface, + color == CAIRO_COLOR_TRANSPARENT ? + CAIRO_OPERATOR_CLEAR : CAIRO_OPERATOR_SOURCE, + &pattern.base, NULL); + if (unlikely (status)) { + cairo_surface_destroy (surface); + surface = _cairo_surface_create_in_error (status); + } + } + + return surface; +} + +/** + * cairo_surface_reference: + * @surface: a #cairo_surface_t + * + * Increases the reference count on @surface by one. This prevents + * @surface from being destroyed until a matching call to + * cairo_surface_destroy() is made. + * + * Use cairo_surface_get_reference_count() to get the number of + * references to a #cairo_surface_t. + * + * Return value: the referenced #cairo_surface_t. + * + * Since: 1.0 + **/ +cairo_surface_t * +cairo_surface_reference (cairo_surface_t *surface) +{ + if (surface == NULL || + CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count)) + return surface; + + assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count)); + + _cairo_reference_count_inc (&surface->ref_count); + + return surface; +} + +/** + * cairo_surface_destroy: + * @surface: a #cairo_surface_t + * + * Decreases the reference count on @surface by one. If the result is + * zero, then @surface and all associated resources are freed. See + * cairo_surface_reference(). + * + * Since: 1.0 + **/ +void +cairo_surface_destroy (cairo_surface_t *surface) +{ + if (surface == NULL || + CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count)) + return; + + assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count)); + + if (! _cairo_reference_count_dec_and_test (&surface->ref_count)) + return; + + assert (surface->snapshot_of == NULL); + + if (! surface->finished) { + _cairo_surface_finish_snapshots (surface); + /* We may have been referenced by a snapshot prior to have + * detaching it with the copy-on-write. + */ + if (CAIRO_REFERENCE_COUNT_GET_VALUE (&surface->ref_count)) + return; + + _cairo_surface_finish (surface); + } + + if (surface->damage) + _cairo_damage_destroy (surface->damage); + + _cairo_user_data_array_fini (&surface->user_data); + _cairo_user_data_array_fini (&surface->mime_data); + + if (surface->foreground_source) + cairo_pattern_destroy (surface->foreground_source); + + if (surface->owns_device) + cairo_device_destroy (surface->device); + + if (surface->has_font_options) + _cairo_font_options_fini (&surface->font_options); + + assert (surface->snapshot_of == NULL); + assert (! _cairo_surface_has_snapshots (surface)); + /* paranoid check that nobody took a reference whilst finishing */ + assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count)); + + free (surface); +} + +/** + * cairo_surface_get_reference_count: + * @surface: a #cairo_surface_t + * + * Returns the current reference count of @surface. + * + * Return value: the current reference count of @surface. If the + * object is a nil object, 0 will be returned. + * + * Since: 1.4 + **/ +unsigned int +cairo_surface_get_reference_count (cairo_surface_t *surface) +{ + if (surface == NULL || + CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count)) + return 0; + + return CAIRO_REFERENCE_COUNT_GET_VALUE (&surface->ref_count); +} + +static void +_cairo_surface_finish_snapshots (cairo_surface_t *surface) +{ + cairo_status_t status; + + /* update the snapshots *before* we declare the surface as finished */ + surface->_finishing = TRUE; + status = _cairo_surface_flush (surface, 0); + (void) status; +} + +static void +_cairo_surface_finish (cairo_surface_t *surface) +{ + cairo_status_t status; + + /* call finish even if in error mode */ + if (surface->backend->finish) { + status = surface->backend->finish (surface); + if (unlikely (status)) + _cairo_surface_set_error (surface, status); + } + + surface->finished = TRUE; + + assert (surface->snapshot_of == NULL); + assert (!_cairo_surface_has_snapshots (surface)); +} + +/** + * cairo_surface_finish: + * @surface: the #cairo_surface_t to finish + * + * This function finishes the surface and drops all references to + * external resources. For example, for the Xlib backend it means + * that cairo will no longer access the drawable, which can be freed. + * After calling cairo_surface_finish() the only valid operations on a + * surface are checking status, getting and setting user, referencing + * and destroying, and flushing and finishing it. + * Further drawing to the surface will not affect the + * surface but will instead trigger a %CAIRO_STATUS_SURFACE_FINISHED + * error. + * + * When the last call to cairo_surface_destroy() decreases the + * reference count to zero, cairo will call cairo_surface_finish() if + * it hasn't been called already, before freeing the resources + * associated with the surface. + * + * Since: 1.0 + **/ +void +cairo_surface_finish (cairo_surface_t *surface) +{ + if (surface == NULL) + return; + + if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count)) + return; + + if (surface->finished) + return; + + /* We have to be careful when decoupling potential reference cycles */ + cairo_surface_reference (surface); + + _cairo_surface_finish_snapshots (surface); + /* XXX need to block and wait for snapshot references */ + _cairo_surface_finish (surface); + + cairo_surface_destroy (surface); +} + +/** + * _cairo_surface_release_device_reference: + * @surface: a #cairo_surface_t + * + * This function makes @surface release the reference to its device. The + * function is intended to be used for avoiding cycling references for + * surfaces that are owned by their device, for example cache surfaces. + * Note that the @surface will still assume that the device is available. + * So it is the caller's responsibility to ensure the device stays around + * until the @surface is destroyed. Just calling cairo_surface_finish() is + * not enough. + **/ +void +_cairo_surface_release_device_reference (cairo_surface_t *surface) +{ + assert (surface->owns_device); + + cairo_device_destroy (surface->device); + surface->owns_device = FALSE; +} + +/** + * cairo_surface_get_user_data: + * @surface: a #cairo_surface_t + * @key: the address of the #cairo_user_data_key_t the user data was + * attached to + * + * Return user data previously attached to @surface using the specified + * key. If no user data has been attached with the given key this + * function returns %NULL. + * + * Return value: the user data previously attached or %NULL. + * + * Since: 1.0 + **/ +void * +cairo_surface_get_user_data (cairo_surface_t *surface, + const cairo_user_data_key_t *key) +{ + /* Prevent reads of the array during teardown */ + if (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count)) + return NULL; + + return _cairo_user_data_array_get_data (&surface->user_data, key); +} + +/** + * cairo_surface_set_user_data: + * @surface: a #cairo_surface_t + * @key: the address of a #cairo_user_data_key_t to attach the user data to + * @user_data: the user data to attach to the surface + * @destroy: a #cairo_destroy_func_t which will be called when the + * surface is destroyed or when new user data is attached using the + * same key. + * + * Attach user data to @surface. To remove user data from a surface, + * call this function with the key that was used to set it and %NULL + * for @data. + * + * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a + * slot could not be allocated for the user data. + * + * Since: 1.0 + **/ +cairo_status_t +cairo_surface_set_user_data (cairo_surface_t *surface, + const cairo_user_data_key_t *key, + void *user_data, + cairo_destroy_func_t destroy) +{ + if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count)) + return surface->status; + + if (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count)) + return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED); + + return _cairo_user_data_array_set_data (&surface->user_data, + key, user_data, destroy); +} + +/** + * cairo_surface_get_mime_data: + * @surface: a #cairo_surface_t + * @mime_type: the mime type of the image data + * @data: the image data to attached to the surface + * @length: the length of the image data + * + * Return mime data previously attached to @surface using the + * specified mime type. If no data has been attached with the given + * mime type, @data is set %NULL. + * + * Since: 1.10 + **/ +void +cairo_surface_get_mime_data (cairo_surface_t *surface, + const char *mime_type, + const unsigned char **data, + unsigned long *length) +{ + cairo_user_data_slot_t *slots; + int i, num_slots; + + *data = NULL; + *length = 0; + + /* Prevent reads of the array during teardown */ + if (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count)) + return; + + /* The number of mime-types attached to a surface is usually small, + * typically zero. Therefore it is quicker to do a strcmp() against + * each key than it is to intern the string (i.e. compute a hash, + * search the hash table, and do a final strcmp). + */ + num_slots = surface->mime_data.num_elements; + slots = _cairo_array_index (&surface->mime_data, 0); + for (i = 0; i < num_slots; i++) { + if (slots[i].key != NULL && strcmp ((char *) slots[i].key, mime_type) == 0) { + cairo_mime_data_t *mime_data = slots[i].user_data; + + *data = mime_data->data; + *length = mime_data->length; + return; + } + } +} + +static void +_cairo_mime_data_destroy (void *ptr) +{ + cairo_mime_data_t *mime_data = ptr; + + if (! _cairo_reference_count_dec_and_test (&mime_data->ref_count)) + return; + + if (mime_data->destroy && mime_data->closure) + mime_data->destroy (mime_data->closure); + + free (mime_data); +} + + +static const char *_cairo_surface_image_mime_types[] = { + CAIRO_MIME_TYPE_JPEG, + CAIRO_MIME_TYPE_PNG, + CAIRO_MIME_TYPE_JP2, + CAIRO_MIME_TYPE_JBIG2, + CAIRO_MIME_TYPE_CCITT_FAX, +}; + +cairo_bool_t +_cairo_surface_has_mime_image (cairo_surface_t *surface) +{ + cairo_user_data_slot_t *slots; + int i, j, num_slots; + + /* Prevent reads of the array during teardown */ + if (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count)) + return FALSE; + + /* The number of mime-types attached to a surface is usually small, + * typically zero. Therefore it is quicker to do a strcmp() against + * each key than it is to intern the string (i.e. compute a hash, + * search the hash table, and do a final strcmp). + */ + num_slots = surface->mime_data.num_elements; + slots = _cairo_array_index (&surface->mime_data, 0); + for (i = 0; i < num_slots; i++) { + if (slots[i].key != NULL) { + for (j = 0; j < ARRAY_LENGTH (_cairo_surface_image_mime_types); j++) { + if (strcmp ((char *) slots[i].key, _cairo_surface_image_mime_types[j]) == 0) + return TRUE; + } + } + } + + return FALSE; +} + +/** + * CAIRO_MIME_TYPE_CCITT_FAX: + * + * Group 3 or Group 4 CCITT facsimile encoding (International + * Telecommunication Union, Recommendations T.4 and T.6.) + * + * Since: 1.16 + **/ + +/** + * CAIRO_MIME_TYPE_CCITT_FAX_PARAMS: + * + * Decode parameters for Group 3 or Group 4 CCITT facsimile encoding. + * See [CCITT Fax Images][ccitt]. + * + * Since: 1.16 + **/ + +/** + * CAIRO_MIME_TYPE_EPS: + * + * Encapsulated PostScript file. + * [Encapsulated PostScript File Format Specification](http://wwwimages.adobe.com/content/dam/Adobe/endevnet/postscript/pdfs/5002.EPSF_Spec.pdf) + * + * Since: 1.16 + **/ + +/** + * CAIRO_MIME_TYPE_EPS_PARAMS: + * + * Embedding parameters Encapsulated PostScript data. + * See [Embedding EPS files][eps]. + * + * Since: 1.16 + **/ + +/** + * CAIRO_MIME_TYPE_JBIG2: + * + * Joint Bi-level Image Experts Group image coding standard (ISO/IEC 11544). + * + * Since: 1.14 + **/ + +/** + * CAIRO_MIME_TYPE_JBIG2_GLOBAL: + * + * Joint Bi-level Image Experts Group image coding standard (ISO/IEC 11544) global segment. + * + * Since: 1.14 + **/ + +/** + * CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID: + * + * An unique identifier shared by a JBIG2 global segment and all JBIG2 images + * that depend on the global segment. + * + * Since: 1.14 + **/ + +/** + * CAIRO_MIME_TYPE_JP2: + * + * The Joint Photographic Experts Group (JPEG) 2000 image coding standard (ISO/IEC 15444-1). + * + * Since: 1.10 + **/ + +/** + * CAIRO_MIME_TYPE_JPEG: + * + * The Joint Photographic Experts Group (JPEG) image coding standard (ISO/IEC 10918-1). + * + * Since: 1.10 + **/ + +/** + * CAIRO_MIME_TYPE_PNG: + * + * The Portable Network Graphics image file format (ISO/IEC 15948). + * + * Since: 1.10 + **/ + +/** + * CAIRO_MIME_TYPE_URI: + * + * URI for an image file (unofficial MIME type). + * + * Since: 1.10 + **/ + +/** + * CAIRO_MIME_TYPE_UNIQUE_ID: + * + * Unique identifier for a surface (cairo specific MIME type). All surfaces with + * the same unique identifier will only be embedded once. + * + * Since: 1.12 + **/ + +/** + * cairo_surface_set_mime_data: + * @surface: a #cairo_surface_t + * @mime_type: the MIME type of the image data + * @data: the image data to attach to the surface + * @length: the length of the image data + * @destroy: a #cairo_destroy_func_t which will be called when the + * surface is destroyed or when new image data is attached using the + * same mime type. + * @closure: the data to be passed to the @destroy notifier + * + * Attach an image in the format @mime_type to @surface. To remove + * the data from a surface, call this function with same mime type + * and %NULL for @data. + * + * The attached image (or filename) data can later be used by backends + * which support it (currently: PDF, PS, SVG and Win32 Printing + * surfaces) to emit this data instead of making a snapshot of the + * @surface. This approach tends to be faster and requires less + * memory and disk space. + * + * The recognized MIME types are the following: %CAIRO_MIME_TYPE_JPEG, + * %CAIRO_MIME_TYPE_PNG, %CAIRO_MIME_TYPE_JP2, %CAIRO_MIME_TYPE_URI, + * %CAIRO_MIME_TYPE_UNIQUE_ID, %CAIRO_MIME_TYPE_JBIG2, + * %CAIRO_MIME_TYPE_JBIG2_GLOBAL, %CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID, + * %CAIRO_MIME_TYPE_CCITT_FAX, %CAIRO_MIME_TYPE_CCITT_FAX_PARAMS. + * + * See corresponding backend surface docs for details about which MIME + * types it can handle. Caution: the associated MIME data will be + * discarded if you draw on the surface afterwards. Use this function + * with care. + * + * Even if a backend supports a MIME type, that does not mean cairo + * will always be able to use the attached MIME data. For example, if + * the backend does not natively support the compositing operation used + * to apply the MIME data to the backend. In that case, the MIME data + * will be ignored. Therefore, to apply an image in all cases, it is best + * to create an image surface which contains the decoded image data and + * then attach the MIME data to that. This ensures the image will always + * be used while still allowing the MIME data to be used whenever + * possible. + * + * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a + * slot could not be allocated for the user data. + * + * Since: 1.10 + **/ +cairo_status_t +cairo_surface_set_mime_data (cairo_surface_t *surface, + const char *mime_type, + const unsigned char *data, + unsigned long length, + cairo_destroy_func_t destroy, + void *closure) +{ + cairo_status_t status; + cairo_mime_data_t *mime_data; + + if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count)) + return surface->status; + + if (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count)) + return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED); + + if (unlikely (surface->status)) + return surface->status; + if (unlikely (surface->finished)) + return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + + status = _cairo_intern_string (&mime_type, -1); + if (unlikely (status)) + return _cairo_surface_set_error (surface, status); + + if (data != NULL) { + mime_data = _cairo_calloc (sizeof (cairo_mime_data_t)); + if (unlikely (mime_data == NULL)) + return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_NO_MEMORY)); + + CAIRO_REFERENCE_COUNT_INIT (&mime_data->ref_count, 1); + + mime_data->data = (unsigned char *) data; + mime_data->length = length; + mime_data->destroy = destroy; + mime_data->closure = closure; + } else + mime_data = NULL; + + status = _cairo_user_data_array_set_data (&surface->mime_data, + (cairo_user_data_key_t *) mime_type, + mime_data, + _cairo_mime_data_destroy); + if (unlikely (status)) { + free (mime_data); + + return _cairo_surface_set_error (surface, status); + } + + surface->is_clear = FALSE; + + return CAIRO_STATUS_SUCCESS; +} + +/** + * cairo_surface_supports_mime_type: + * @surface: a #cairo_surface_t + * @mime_type: the mime type + * + * Return whether @surface supports @mime_type. + * + * Return value: %TRUE if @surface supports + * @mime_type, %FALSE otherwise + * + * Since: 1.12 + **/ +cairo_bool_t +cairo_surface_supports_mime_type (cairo_surface_t *surface, + const char *mime_type) +{ + const char **types; + + if (unlikely (surface->status)) + return FALSE; + if (unlikely (surface->finished)) { + _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + return FALSE; + } + + if (surface->backend->get_supported_mime_types) { + types = surface->backend->get_supported_mime_types (surface); + if (types) { + while (*types) { + if (strcmp (*types, mime_type) == 0) + return TRUE; + types++; + } + } + } + + return FALSE; +} + +static void +_cairo_mime_data_reference (const void *key, void *elt, void *closure) +{ + cairo_mime_data_t *mime_data = elt; + + _cairo_reference_count_inc (&mime_data->ref_count); +} + +cairo_status_t +_cairo_surface_copy_mime_data (cairo_surface_t *dst, + cairo_surface_t *src) +{ + cairo_status_t status; + + if (dst->status) + return dst->status; + + if (src->status) + return _cairo_surface_set_error (dst, src->status); + + /* first copy the mime-data, discarding any already set on dst */ + status = _cairo_user_data_array_copy (&dst->mime_data, &src->mime_data); + if (unlikely (status)) + return _cairo_surface_set_error (dst, status); + + /* now increment the reference counters for the copies */ + _cairo_user_data_array_foreach (&dst->mime_data, + _cairo_mime_data_reference, + NULL); + + dst->is_clear = FALSE; + + return CAIRO_STATUS_SUCCESS; +} + +/** + * _cairo_surface_set_font_options: + * @surface: a #cairo_surface_t + * @options: a #cairo_font_options_t object that contains the + * options to use for this surface instead of backend's default + * font options. + * + * Sets the default font rendering options for the surface. + * This is useful to correctly propagate default font options when + * falling back to an image surface in a backend implementation. + * This affects the options returned in cairo_surface_get_font_options(). + * + * If @options is %NULL the surface options are reset to those of + * the backend default. + **/ +void +_cairo_surface_set_font_options (cairo_surface_t *surface, + cairo_font_options_t *options) +{ + if (surface->status) + return; + + assert (surface->snapshot_of == NULL); + + if (surface->finished) { + _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + return; + } + + if (options) { + surface->has_font_options = TRUE; + _cairo_font_options_init_copy (&surface->font_options, options); + } else { + surface->has_font_options = FALSE; + } +} + +/** + * cairo_surface_get_font_options: + * @surface: a #cairo_surface_t + * @options: a #cairo_font_options_t object into which to store + * the retrieved options. All existing values are overwritten + * + * Retrieves the default font rendering options for the surface. + * This allows display surfaces to report the correct subpixel order + * for rendering on them, print surfaces to disable hinting of + * metrics and so forth. The result can then be used with + * cairo_scaled_font_create(). + * + * Since: 1.0 + **/ +void +cairo_surface_get_font_options (cairo_surface_t *surface, + cairo_font_options_t *options) +{ + if (cairo_font_options_status (options)) + return; + + if (surface->status) { + _cairo_font_options_init_default (options); + return; + } + + if (! surface->has_font_options) { + surface->has_font_options = TRUE; + + _cairo_font_options_init_default (&surface->font_options); + + if (!surface->finished && surface->backend->get_font_options) { + surface->backend->get_font_options (surface, &surface->font_options); + } + } + + _cairo_font_options_init_copy (options, &surface->font_options); +} + +cairo_status_t +_cairo_surface_flush (cairo_surface_t *surface, unsigned flags) +{ + /* update the current snapshots *before* the user updates the surface */ + _cairo_surface_detach_snapshots (surface); + if (surface->snapshot_of != NULL) + _cairo_surface_detach_snapshot (surface); + _cairo_surface_detach_mime_data (surface); + + return __cairo_surface_flush (surface, flags); +} + +/** + * cairo_surface_flush: + * @surface: a #cairo_surface_t + * + * Do any pending drawing for the surface and also restore any temporary + * modifications cairo has made to the surface's state. This function + * must be called before switching from drawing on the surface with + * cairo to drawing on it directly with native APIs, or accessing its + * memory outside of Cairo. If the surface doesn't support direct + * access, then this function does nothing. + * + * Since: 1.0 + **/ +void +cairo_surface_flush (cairo_surface_t *surface) +{ + cairo_status_t status; + + if (surface->status) + return; + + if (surface->finished) + return; + + status = _cairo_surface_flush (surface, 0); + if (unlikely (status)) + _cairo_surface_set_error (surface, status); +} + +/** + * cairo_surface_mark_dirty: + * @surface: a #cairo_surface_t + * + * Tells cairo that drawing has been done to surface using means other + * than cairo, and that cairo should reread any cached areas. Note + * that you must call cairo_surface_flush() before doing such drawing. + * + * Since: 1.0 + **/ +void +cairo_surface_mark_dirty (cairo_surface_t *surface) +{ + cairo_rectangle_int_t extents; + + if (unlikely (surface->status)) + return; + if (unlikely (surface->finished)) { + _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + return; + } + + _cairo_surface_get_extents (surface, &extents); + cairo_surface_mark_dirty_rectangle (surface, + extents.x, extents.y, + extents.width, extents.height); +} + +/** + * cairo_surface_mark_dirty_rectangle: + * @surface: a #cairo_surface_t + * @x: X coordinate of dirty rectangle + * @y: Y coordinate of dirty rectangle + * @width: width of dirty rectangle + * @height: height of dirty rectangle + * + * Like cairo_surface_mark_dirty(), but drawing has been done only to + * the specified rectangle, so that cairo can retain cached contents + * for other parts of the surface. + * + * Any cached clip set on the surface will be reset by this function, + * to make sure that future cairo calls have the clip set that they + * expect. + * + * Since: 1.0 + **/ +void +cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface, + int x, + int y, + int width, + int height) +{ + cairo_status_t status; + + if (unlikely (surface->status)) + return; + + assert (surface->snapshot_of == NULL); + + if (unlikely (surface->finished)) { + _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + return; + } + + /* The application *should* have called cairo_surface_flush() before + * modifying the surface independently of cairo (and thus having to + * call mark_dirty()). */ + assert (! _cairo_surface_has_snapshots (surface)); + assert (! _cairo_surface_has_mime_data (surface)); + + surface->is_clear = FALSE; + surface->serial++; + + if (surface->damage) { + cairo_box_t box; + + box.p1.x = x; + box.p1.y = y; + box.p2.x = x + width; + box.p2.y = y + height; + + surface->damage = _cairo_damage_add_box (surface->damage, &box); + } + + if (surface->backend->mark_dirty_rectangle != NULL) { + /* XXX: FRAGILE: We're ignoring the scaling component of + * device_transform here. I don't know what the right thing to + * do would actually be if there were some scaling here, but + * we avoid this since device_transfom scaling is not exported + * publicly and mark_dirty is not used internally. */ + status = surface->backend->mark_dirty_rectangle (surface, + x + surface->device_transform.x0, + y + surface->device_transform.y0, + width, height); + + if (unlikely (status)) + _cairo_surface_set_error (surface, status); + } +} + +/** + * cairo_surface_set_device_scale: + * @surface: a #cairo_surface_t + * @x_scale: a scale factor in the X direction + * @y_scale: a scale factor in the Y direction + * + * Sets a scale that is multiplied to the device coordinates determined + * by the CTM when drawing to @surface. One common use for this is to + * render to very high resolution display devices at a scale factor, so + * that code that assumes 1 pixel will be a certain size will still work. + * Setting a transformation via cairo_scale() isn't + * sufficient to do this, since functions like + * cairo_device_to_user() will expose the hidden scale. + * + * Note that the scale affects drawing to the surface as well as + * using the surface in a source pattern. + * + * Since: 1.14 + **/ +void +cairo_surface_set_device_scale (cairo_surface_t *surface, + double x_scale, + double y_scale) +{ + cairo_status_t status; + + if (unlikely (surface->status)) + return; + + assert (surface->snapshot_of == NULL); + + if (unlikely (surface->finished)) { + _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + return; + } + + status = _cairo_surface_begin_modification (surface); + if (unlikely (status)) { + _cairo_surface_set_error (surface, status); + return; + } + + surface->device_transform.xx = x_scale; + surface->device_transform.yy = y_scale; + surface->device_transform.xy = 0.0; + surface->device_transform.yx = 0.0; + + surface->device_transform_inverse = surface->device_transform; + status = cairo_matrix_invert (&surface->device_transform_inverse); + /* should always be invertible unless given pathological input */ + assert (status == CAIRO_STATUS_SUCCESS); + + _cairo_observers_notify (&surface->device_transform_observers, surface); +} + +/** + * cairo_surface_get_device_scale: + * @surface: a #cairo_surface_t + * @x_scale: the scale in the X direction, in device units + * @y_scale: the scale in the Y direction, in device units + * + * This function returns the previous device scale set by + * cairo_surface_set_device_scale(). + * + * Since: 1.14 + **/ +void +cairo_surface_get_device_scale (cairo_surface_t *surface, + double *x_scale, + double *y_scale) +{ + if (x_scale) + *x_scale = surface->device_transform.xx; + if (y_scale) + *y_scale = surface->device_transform.yy; +} + +/** + * cairo_surface_set_device_offset: + * @surface: a #cairo_surface_t + * @x_offset: the offset in the X direction, in device units + * @y_offset: the offset in the Y direction, in device units + * + * Sets an offset that is added to the device coordinates determined + * by the CTM when drawing to @surface. One use case for this function + * is when we want to create a #cairo_surface_t that redirects drawing + * for a portion of an onscreen surface to an offscreen surface in a + * way that is completely invisible to the user of the cairo + * API. Setting a transformation via cairo_translate() isn't + * sufficient to do this, since functions like + * cairo_device_to_user() will expose the hidden offset. + * + * Note that the offset affects drawing to the surface as well as + * using the surface in a source pattern. + * + * Since: 1.0 + **/ +void +cairo_surface_set_device_offset (cairo_surface_t *surface, + double x_offset, + double y_offset) +{ + cairo_status_t status; + + if (unlikely (surface->status)) + return; + + assert (surface->snapshot_of == NULL); + + if (unlikely (surface->finished)) { + _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + return; + } + + status = _cairo_surface_begin_modification (surface); + if (unlikely (status)) { + _cairo_surface_set_error (surface, status); + return; + } + + surface->device_transform.x0 = x_offset; + surface->device_transform.y0 = y_offset; + + surface->device_transform_inverse = surface->device_transform; + status = cairo_matrix_invert (&surface->device_transform_inverse); + /* should always be invertible unless given pathological input */ + assert (status == CAIRO_STATUS_SUCCESS); + + _cairo_observers_notify (&surface->device_transform_observers, surface); +} + +/** + * cairo_surface_get_device_offset: + * @surface: a #cairo_surface_t + * @x_offset: the offset in the X direction, in device units + * @y_offset: the offset in the Y direction, in device units + * + * This function returns the previous device offset set by + * cairo_surface_set_device_offset(). + * + * Since: 1.2 + **/ +void +cairo_surface_get_device_offset (cairo_surface_t *surface, + double *x_offset, + double *y_offset) +{ + if (x_offset) + *x_offset = surface->device_transform.x0; + if (y_offset) + *y_offset = surface->device_transform.y0; +} + +/** + * cairo_surface_set_fallback_resolution: + * @surface: a #cairo_surface_t + * @x_pixels_per_inch: horizontal setting for pixels per inch + * @y_pixels_per_inch: vertical setting for pixels per inch + * + * Set the horizontal and vertical resolution for image fallbacks. + * + * When certain operations aren't supported natively by a backend, + * cairo will fallback by rendering operations to an image and then + * overlaying that image onto the output. For backends that are + * natively vector-oriented, this function can be used to set the + * resolution used for these image fallbacks, (larger values will + * result in more detailed images, but also larger file sizes). + * + * Some examples of natively vector-oriented backends are the ps, pdf, + * and svg backends. + * + * For backends that are natively raster-oriented, image fallbacks are + * still possible, but they are always performed at the native + * device resolution. So this function has no effect on those + * backends. + * + * Note: The fallback resolution only takes effect at the time of + * completing a page (with cairo_show_page() or cairo_copy_page()) so + * there is currently no way to have more than one fallback resolution + * in effect on a single page. + * + * The default fallback resolution is 300 pixels per inch in both + * dimensions. + * + * Since: 1.2 + **/ +void +cairo_surface_set_fallback_resolution (cairo_surface_t *surface, + double x_pixels_per_inch, + double y_pixels_per_inch) +{ + cairo_status_t status; + + if (unlikely (surface->status)) + return; + + assert (surface->snapshot_of == NULL); + + if (unlikely (surface->finished)) { + _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + return; + } + + if (x_pixels_per_inch <= 0 || y_pixels_per_inch <= 0) { + /* XXX Could delay raising the error until we fallback, but throwing + * the error here means that we can catch the real culprit. + */ + _cairo_surface_set_error (surface, CAIRO_STATUS_INVALID_MATRIX); + return; + } + + status = _cairo_surface_begin_modification (surface); + if (unlikely (status)) { + _cairo_surface_set_error (surface, status); + return; + } + + surface->x_fallback_resolution = x_pixels_per_inch; + surface->y_fallback_resolution = y_pixels_per_inch; +} + +/** + * cairo_surface_get_fallback_resolution: + * @surface: a #cairo_surface_t + * @x_pixels_per_inch: horizontal pixels per inch + * @y_pixels_per_inch: vertical pixels per inch + * + * This function returns the previous fallback resolution set by + * cairo_surface_set_fallback_resolution(), or default fallback + * resolution if never set. + * + * Since: 1.8 + **/ +void +cairo_surface_get_fallback_resolution (cairo_surface_t *surface, + double *x_pixels_per_inch, + double *y_pixels_per_inch) +{ + if (x_pixels_per_inch) + *x_pixels_per_inch = surface->x_fallback_resolution; + if (y_pixels_per_inch) + *y_pixels_per_inch = surface->y_fallback_resolution; +} + +cairo_bool_t +_cairo_surface_has_device_transform (cairo_surface_t *surface) +{ + return ! _cairo_matrix_is_identity (&surface->device_transform); +} + +/** + * _cairo_surface_acquire_source_image: + * @surface: a #cairo_surface_t + * @image_out: location to store a pointer to an image surface that + * has identical contents to @surface. This surface could be @surface + * itself, a surface held internal to @surface, or it could be a new + * surface with a copy of the relevant portion of @surface. + * @image_extra: location to store image specific backend data + * + * Gets an image surface to use when drawing as a fallback when drawing with + * @surface as a source. _cairo_surface_release_source_image() must be called + * when finished. + * + * Return value: %CAIRO_STATUS_SUCCESS if an image was stored in @image_out. + * %CAIRO_INT_STATUS_UNSUPPORTED if an image cannot be retrieved for the specified + * surface. Or %CAIRO_STATUS_NO_MEMORY. + **/ +cairo_status_t +_cairo_surface_acquire_source_image (cairo_surface_t *surface, + cairo_image_surface_t **image_out, + void **image_extra) +{ + cairo_status_t status; + + if (unlikely (surface->status)) + return surface->status; + + assert (!surface->finished); + + if (surface->backend->acquire_source_image == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = surface->backend->acquire_source_image (surface, + image_out, image_extra); + if (unlikely (status)) + return _cairo_surface_set_error (surface, status); + + _cairo_debug_check_image_surface_is_defined (&(*image_out)->base); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_surface_default_acquire_source_image (void *_surface, + cairo_image_surface_t **image_out, + void **image_extra) +{ + cairo_surface_t *surface = _surface; + cairo_rectangle_int_t extents; + + if (unlikely (! surface->backend->get_extents (surface, &extents))) + return _cairo_error (CAIRO_STATUS_INVALID_SIZE); + + *image_out = _cairo_surface_map_to_image (surface, &extents); + *image_extra = NULL; + return (*image_out)->base.status; +} + +/** + * _cairo_surface_release_source_image: + * @surface: a #cairo_surface_t + * @image_extra: same as return from the matching _cairo_surface_acquire_source_image() + * + * Releases any resources obtained with _cairo_surface_acquire_source_image() + **/ +void +_cairo_surface_release_source_image (cairo_surface_t *surface, + cairo_image_surface_t *image, + void *image_extra) +{ + assert (!surface->finished); + + if (surface->backend->release_source_image) + surface->backend->release_source_image (surface, image, image_extra); +} + +void +_cairo_surface_default_release_source_image (void *surface, + cairo_image_surface_t *image, + void *image_extra) +{ + cairo_status_t ignored; + + ignored = _cairo_surface_unmap_image (surface, image); + (void)ignored; +} + + +cairo_surface_t * +_cairo_surface_get_source (cairo_surface_t *surface, + cairo_rectangle_int_t *extents) +{ + assert (surface->backend->source); + return surface->backend->source (surface, extents); +} + +cairo_surface_t * +_cairo_surface_default_source (void *surface, + cairo_rectangle_int_t *extents) +{ + if (extents) + _cairo_surface_get_extents(surface, extents); + return surface; +} + +static cairo_status_t +_pattern_has_error (const cairo_pattern_t *pattern) +{ + const cairo_surface_pattern_t *spattern; + + if (unlikely (pattern->status)) + return pattern->status; + + if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE) + return CAIRO_STATUS_SUCCESS; + + spattern = (const cairo_surface_pattern_t *) pattern; + if (unlikely (spattern->surface->status)) + return spattern->surface->status; + + if (unlikely (spattern->surface->finished)) + return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_bool_t +nothing_to_do (cairo_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source) +{ + if (_cairo_pattern_is_clear (source)) { + if (op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD) + return TRUE; + + if (op == CAIRO_OPERATOR_SOURCE) + op = CAIRO_OPERATOR_CLEAR; + } + + if (op == CAIRO_OPERATOR_CLEAR && surface->is_clear) + return TRUE; + + if (op == CAIRO_OPERATOR_ATOP && (surface->content & CAIRO_CONTENT_COLOR) ==0) + return TRUE; + + return FALSE; +} + +cairo_status_t +_cairo_surface_paint (cairo_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip) +{ + cairo_int_status_t status; + cairo_bool_t is_clear; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + if (unlikely (surface->status)) + return surface->status; + if (unlikely (surface->finished)) + return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + + if (_cairo_clip_is_all_clipped (clip)) + return CAIRO_STATUS_SUCCESS; + + status = _pattern_has_error (source); + if (unlikely (status)) + return status; + + if (nothing_to_do (surface, op, source)) + return CAIRO_STATUS_SUCCESS; + + status = _cairo_surface_begin_modification (surface); + if (unlikely (status)) + return status; + + if (source->is_foreground_marker && surface->foreground_source) { + source = surface->foreground_source; + surface->foreground_used = TRUE; + } + + status = surface->backend->paint (surface, op, source, clip); + is_clear = op == CAIRO_OPERATOR_CLEAR && clip == NULL; + if (status != CAIRO_INT_STATUS_NOTHING_TO_DO || is_clear) { + surface->is_clear = is_clear; + surface->serial++; + } + + return _cairo_surface_set_error (surface, status); +} + +cairo_status_t +_cairo_surface_mask (cairo_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_clip_t *clip) +{ + cairo_int_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + if (unlikely (surface->status)) + return surface->status; + if (unlikely (surface->finished)) + return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + + if (_cairo_clip_is_all_clipped (clip)) + return CAIRO_STATUS_SUCCESS; + + /* If the mask is blank, this is just an expensive no-op */ + if (_cairo_pattern_is_clear (mask) && + _cairo_operator_bounded_by_mask (op)) + { + return CAIRO_STATUS_SUCCESS; + } + + status = _pattern_has_error (source); + if (unlikely (status)) + return status; + + status = _pattern_has_error (mask); + if (unlikely (status)) + return status; + + if (nothing_to_do (surface, op, source)) + return CAIRO_STATUS_SUCCESS; + + status = _cairo_surface_begin_modification (surface); + if (unlikely (status)) + return status; + + if (source->is_foreground_marker && surface->foreground_source) { + source = surface->foreground_source; + surface->foreground_used = TRUE; + } + + status = surface->backend->mask (surface, op, source, mask, clip); + if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) { + surface->is_clear = FALSE; + surface->serial++; + } + + return _cairo_surface_set_error (surface, status); +} + +cairo_status_t +_cairo_surface_fill_stroke (cairo_surface_t *surface, + cairo_operator_t fill_op, + const cairo_pattern_t *fill_source, + cairo_fill_rule_t fill_rule, + double fill_tolerance, + cairo_antialias_t fill_antialias, + cairo_path_fixed_t *path, + cairo_operator_t stroke_op, + const cairo_pattern_t *stroke_source, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *stroke_ctm, + const cairo_matrix_t *stroke_ctm_inverse, + double stroke_tolerance, + cairo_antialias_t stroke_antialias, + const cairo_clip_t *clip) +{ + cairo_int_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + if (unlikely (surface->status)) + return surface->status; + if (unlikely (surface->finished)) + return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + + if (_cairo_clip_is_all_clipped (clip)) + return CAIRO_STATUS_SUCCESS; + + if (surface->is_clear && + fill_op == CAIRO_OPERATOR_CLEAR && + stroke_op == CAIRO_OPERATOR_CLEAR) + { + return CAIRO_STATUS_SUCCESS; + } + + status = _pattern_has_error (fill_source); + if (unlikely (status)) + return status; + + status = _pattern_has_error (stroke_source); + if (unlikely (status)) + return status; + + status = _cairo_surface_begin_modification (surface); + if (unlikely (status)) + return status; + + if (fill_source->is_foreground_marker && surface->foreground_source) { + fill_source = surface->foreground_source; + surface->foreground_used = TRUE; + } + + if (stroke_source->is_foreground_marker && surface->foreground_source) { + stroke_source = surface->foreground_source; + surface->foreground_used = TRUE; + } + + if (surface->backend->fill_stroke) { + cairo_matrix_t dev_ctm = *stroke_ctm; + cairo_matrix_t dev_ctm_inverse = *stroke_ctm_inverse; + + status = surface->backend->fill_stroke (surface, + fill_op, fill_source, fill_rule, + fill_tolerance, fill_antialias, + path, + stroke_op, stroke_source, + stroke_style, + &dev_ctm, &dev_ctm_inverse, + stroke_tolerance, stroke_antialias, + clip); + + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + goto FINISH; + } + + status = _cairo_surface_fill (surface, fill_op, fill_source, path, + fill_rule, fill_tolerance, fill_antialias, + clip); + if (unlikely (status)) + goto FINISH; + + status = _cairo_surface_stroke (surface, stroke_op, stroke_source, path, + stroke_style, stroke_ctm, stroke_ctm_inverse, + stroke_tolerance, stroke_antialias, + clip); + if (unlikely (status)) + goto FINISH; + + FINISH: + if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) { + surface->is_clear = FALSE; + surface->serial++; + } + + return _cairo_surface_set_error (surface, status); +} + +cairo_status_t +_cairo_surface_stroke (cairo_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_int_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + if (unlikely (surface->status)) + return surface->status; + if (unlikely (surface->finished)) + return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + + if (_cairo_clip_is_all_clipped (clip)) + return CAIRO_STATUS_SUCCESS; + + status = _pattern_has_error (source); + if (unlikely (status)) + return status; + + if (nothing_to_do (surface, op, source)) + return CAIRO_STATUS_SUCCESS; + + status = _cairo_surface_begin_modification (surface); + if (unlikely (status)) + return status; + + if (source->is_foreground_marker && surface->foreground_source) { + source = surface->foreground_source; + surface->foreground_used = TRUE; + } + + status = surface->backend->stroke (surface, op, source, + path, stroke_style, + ctm, ctm_inverse, + tolerance, antialias, + clip); + if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) { + surface->is_clear = FALSE; + surface->serial++; + } + + return _cairo_surface_set_error (surface, status); +} + +cairo_status_t +_cairo_surface_fill (cairo_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_int_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + if (unlikely (surface->status)) + return surface->status; + if (unlikely (surface->finished)) + return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + + if (_cairo_clip_is_all_clipped (clip)) + return CAIRO_STATUS_SUCCESS; + + status = _pattern_has_error (source); + if (unlikely (status)) + return status; + + if (nothing_to_do (surface, op, source)) + return CAIRO_STATUS_SUCCESS; + + status = _cairo_surface_begin_modification (surface); + if (unlikely (status)) + return status; + + if (source->is_foreground_marker && surface->foreground_source) { + source = surface->foreground_source; + surface->foreground_used = TRUE; + } + + status = surface->backend->fill (surface, op, source, + path, fill_rule, + tolerance, antialias, + clip); + if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) { + surface->is_clear = FALSE; + surface->serial++; + } + + return _cairo_surface_set_error (surface, status); +} + +/** + * cairo_surface_copy_page: + * @surface: a #cairo_surface_t + * + * Emits the current page for backends that support multiple pages, + * but doesn't clear it, so that the contents of the current page will + * be retained for the next page. Use cairo_surface_show_page() if you + * want to get an empty page after the emission. + * + * There is a convenience function for this that takes a #cairo_t, + * namely cairo_copy_page(). + * + * Since: 1.6 + **/ +void +cairo_surface_copy_page (cairo_surface_t *surface) +{ + if (unlikely (surface->status)) + return; + + assert (surface->snapshot_of == NULL); + + if (unlikely (surface->finished)) { + _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED); + return; + } + + /* It's fine if some backends don't implement copy_page */ + if (surface->backend->copy_page == NULL) + return; + + _cairo_surface_set_error (surface, surface->backend->copy_page (surface)); +} + +/** + * cairo_surface_show_page: + * @surface: a #cairo_Surface_t + * + * Emits and clears the current page for backends that support multiple + * pages. Use cairo_surface_copy_page() if you don't want to clear the page. + * + * There is a convenience function for this that takes a #cairo_t, + * namely cairo_show_page(). + * + * Since: 1.6 + **/ +void +cairo_surface_show_page (cairo_surface_t *surface) +{ + cairo_status_t status; + + if (unlikely (surface->status)) + return; + + if (unlikely (surface->finished)) { + _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED); + return; + } + + status = _cairo_surface_begin_modification (surface); + if (unlikely (status)) { + _cairo_surface_set_error (surface, status); + return; + } + + /* It's fine if some backends don't implement show_page */ + if (surface->backend->show_page == NULL) + return; + + _cairo_surface_set_error (surface, surface->backend->show_page (surface)); +} + +/** + * _cairo_surface_get_extents: + * @surface: the #cairo_surface_t to fetch extents for + * + * This function returns a bounding box for the surface. The surface + * bounds are defined as a region beyond which no rendering will + * possibly be recorded, in other words, it is the maximum extent of + * potentially usable coordinates. + * + * For vector surfaces, (PDF, PS, SVG and recording-surfaces), the surface + * might be conceived as unbounded, but we force the user to provide a + * maximum size at the time of surface_create. So get_extents uses + * that size. + * + * Note: The coordinates returned are in "backend" space rather than + * "surface" space. That is, they are relative to the true (0,0) + * origin rather than the device_transform origin. This might seem a + * bit inconsistent with other #cairo_surface_t interfaces, but all + * current callers are within the surface layer where backend space is + * desired. + * + * This behavior would have to be changed is we ever exported a public + * variant of this function. + **/ +cairo_bool_t +_cairo_surface_get_extents (cairo_surface_t *surface, + cairo_rectangle_int_t *extents) +{ + cairo_bool_t bounded; + + if (unlikely (surface->status)) + goto zero_extents; + if (unlikely (surface->finished)) { + _cairo_surface_set_error(surface, CAIRO_STATUS_SURFACE_FINISHED); + goto zero_extents; + } + + bounded = FALSE; + if (surface->backend->get_extents != NULL) + bounded = surface->backend->get_extents (surface, extents); + + if (! bounded) + _cairo_unbounded_rectangle_init (extents); + + return bounded; + +zero_extents: + extents->x = extents->y = 0; + extents->width = extents->height = 0; + return TRUE; +} + +/** + * cairo_surface_has_show_text_glyphs: + * @surface: a #cairo_surface_t + * + * Returns whether the surface supports + * sophisticated cairo_show_text_glyphs() operations. That is, + * whether it actually uses the provided text and cluster data + * to a cairo_show_text_glyphs() call. + * + * Note: Even if this function returns %FALSE, a + * cairo_show_text_glyphs() operation targeted at @surface will + * still succeed. It just will + * act like a cairo_show_glyphs() operation. Users can use this + * function to avoid computing UTF-8 text and cluster mapping if the + * target surface does not use it. + * + * Return value: %TRUE if @surface supports + * cairo_show_text_glyphs(), %FALSE otherwise + * + * Since: 1.8 + **/ +cairo_bool_t +cairo_surface_has_show_text_glyphs (cairo_surface_t *surface) +{ + if (unlikely (surface->status)) + return FALSE; + + if (unlikely (surface->finished)) { + _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED); + return FALSE; + } + + if (surface->backend->has_show_text_glyphs) + return surface->backend->has_show_text_glyphs (surface); + else + return surface->backend->show_text_glyphs != NULL; +} + +#define GLYPH_CACHE_SIZE 64 + +static inline cairo_int_status_t +ensure_scaled_glyph (cairo_scaled_font_t *scaled_font, + cairo_color_t *foreground_color, + cairo_scaled_glyph_t **glyph_cache, + cairo_glyph_t *glyph, + cairo_scaled_glyph_t **scaled_glyph) +{ + int cache_index; + cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; + + cache_index = glyph->index % GLYPH_CACHE_SIZE; + *scaled_glyph = glyph_cache[cache_index]; + if (*scaled_glyph == NULL || _cairo_scaled_glyph_index (*scaled_glyph) != glyph->index) { + status = _cairo_scaled_glyph_lookup (scaled_font, + glyph->index, + CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE, + foreground_color, + scaled_glyph); + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + /* If the color surface not available, ensure scaled_glyph is not NULL. */ + status = _cairo_scaled_glyph_lookup (scaled_font, + glyph->index, + CAIRO_SCALED_GLYPH_INFO_SURFACE, + NULL, /* foreground color */ + scaled_glyph); + } + if (unlikely (status)) + status = _cairo_scaled_font_set_error (scaled_font, status); + + glyph_cache[cache_index] = *scaled_glyph; + } + + return status; +} + +static inline cairo_int_status_t +composite_one_color_glyph (cairo_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip, + cairo_glyph_t *glyph, + cairo_scaled_glyph_t *scaled_glyph, + double x_scale, + double y_scale) +{ + cairo_int_status_t status; + cairo_image_surface_t *glyph_surface; + cairo_pattern_t *pattern; + cairo_matrix_t matrix; + int has_color; + + status = CAIRO_INT_STATUS_SUCCESS; + + has_color = scaled_glyph->has_info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE; + if (has_color) + glyph_surface = scaled_glyph->color_surface; + else + glyph_surface = scaled_glyph->surface; + + if (glyph_surface->width && glyph_surface->height) { + int x, y; + /* round glyph locations to the nearest pixels */ + /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */ + x = _cairo_lround (glyph->x * x_scale - glyph_surface->base.device_transform.x0); + y = _cairo_lround (glyph->y * y_scale - glyph_surface->base.device_transform.y0); + + pattern = cairo_pattern_create_for_surface ((cairo_surface_t *)glyph_surface); + cairo_matrix_init_translate (&matrix, - x, - y); + cairo_matrix_scale (&matrix, x_scale, y_scale); + cairo_pattern_set_matrix (pattern, &matrix); + if (op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_CLEAR || !has_color) + status = _cairo_surface_mask (surface, op, pattern, pattern, clip); + else + status = _cairo_surface_paint (surface, op, pattern, clip); + cairo_pattern_destroy (pattern); + } + + return status; +} + +static cairo_int_status_t +composite_color_glyphs (cairo_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + char *utf8, + int *utf8_len, + cairo_glyph_t *glyphs, + int *num_glyphs, + cairo_text_cluster_t *clusters, + int *num_clusters, + cairo_text_cluster_flags_t cluster_flags, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip) +{ + cairo_int_status_t status; + int i, j; + cairo_scaled_glyph_t *scaled_glyph; + int remaining_clusters = 0; + int remaining_glyphs = 0; + int remaining_bytes = 0; + int glyph_pos = 0; + int byte_pos = 0; + int gp; + cairo_scaled_glyph_t *glyph_cache[GLYPH_CACHE_SIZE]; + cairo_color_t *foreground_color = NULL; + double x_scale = 1.0; + double y_scale = 1.0; + + if (surface->is_vector) { + cairo_font_face_t *font_face; + cairo_matrix_t font_matrix; + cairo_matrix_t ctm; + cairo_font_options_t font_options; + + x_scale = surface->x_fallback_resolution / surface->x_resolution; + y_scale = surface->y_fallback_resolution / surface->y_resolution; + font_face = cairo_scaled_font_get_font_face (scaled_font); + cairo_scaled_font_get_font_matrix (scaled_font, &font_matrix); + cairo_scaled_font_get_ctm (scaled_font, &ctm); + _cairo_font_options_init_default (&font_options); + cairo_scaled_font_get_font_options (scaled_font, &font_options); + cairo_matrix_scale (&ctm, x_scale, y_scale); + scaled_font = cairo_scaled_font_create (font_face, + &font_matrix, + &ctm, + &font_options); + } + + if (source->type == CAIRO_PATTERN_TYPE_SOLID) + foreground_color = &((cairo_solid_pattern_t *) source)->color; + + memset (glyph_cache, 0, sizeof (glyph_cache)); + + status = CAIRO_INT_STATUS_SUCCESS; + + _cairo_scaled_font_freeze_cache (scaled_font); + + if (clusters) { + + if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD) + glyph_pos = *num_glyphs - 1; + + for (i = 0; i < *num_clusters; i++) { + cairo_bool_t skip_cluster = TRUE; + + for (j = 0; j < clusters[i].num_glyphs; j++) { + if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD) + gp = glyph_pos - j; + else + gp = glyph_pos + j; + + status = ensure_scaled_glyph (scaled_font, foreground_color, glyph_cache, + &glyphs[gp], &scaled_glyph); + if (unlikely (status)) + goto UNLOCK; + + if ((scaled_glyph->has_info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) != 0) { + cairo_bool_t supports_color_glyph = FALSE; + + if (surface->backend->supports_color_glyph) { + _cairo_scaled_font_thaw_cache (scaled_font); + supports_color_glyph = _cairo_surface_supports_color_glyph (surface, scaled_font, glyphs[gp].index); + + memset (glyph_cache, 0, sizeof (glyph_cache)); + _cairo_scaled_font_freeze_cache (scaled_font); + } + + if (!supports_color_glyph) { + skip_cluster = FALSE; + break; + } + } + } + + if (skip_cluster) { + memmove (utf8 + remaining_bytes, utf8 + byte_pos, clusters[i].num_bytes); + remaining_bytes += clusters[i].num_bytes; + byte_pos += clusters[i].num_bytes; + for (j = 0; j < clusters[i].num_glyphs; j++, remaining_glyphs++) { + if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD) + glyphs[*num_glyphs - 1 - remaining_glyphs] = glyphs[glyph_pos--]; + else + glyphs[remaining_glyphs] = glyphs[glyph_pos++]; + } + clusters[remaining_clusters++] = clusters[i]; + continue; + } + + for (j = 0; j < clusters[i].num_glyphs; j++) { + if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD) + gp = glyph_pos - j; + else + gp = glyph_pos + j; + + status = ensure_scaled_glyph (scaled_font, foreground_color, glyph_cache, + &glyphs[gp], &scaled_glyph); + if (unlikely (status)) + goto UNLOCK; + + status = composite_one_color_glyph (surface, op, source, clip, + &glyphs[gp], scaled_glyph, + x_scale, y_scale); + if (unlikely (status && status != CAIRO_INT_STATUS_NOTHING_TO_DO)) + goto UNLOCK; + } + + if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD) + glyph_pos -= clusters[i].num_glyphs; + else + glyph_pos += clusters[i].num_glyphs; + + byte_pos += clusters[i].num_bytes; + } + + if (cluster_flags & CAIRO_TEXT_CLUSTER_FLAG_BACKWARD) { + memmove (utf8, utf8 + *utf8_len - remaining_bytes, remaining_bytes); + memmove (glyphs, glyphs + (*num_glyphs - remaining_glyphs), sizeof (cairo_glyph_t) * remaining_glyphs); + } + + *utf8_len = remaining_bytes; + *num_glyphs = remaining_glyphs; + *num_clusters = remaining_clusters; + + } else { + + for (glyph_pos = 0; glyph_pos < *num_glyphs; glyph_pos++) { + status = ensure_scaled_glyph (scaled_font, foreground_color, glyph_cache, + &glyphs[glyph_pos], &scaled_glyph); + if (unlikely (status)) + goto UNLOCK; + + if ((scaled_glyph->has_info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) == 0) { + glyphs[remaining_glyphs++] = glyphs[glyph_pos]; + continue; + } + + status = composite_one_color_glyph (surface, op, source, clip, + &glyphs[glyph_pos], scaled_glyph, + x_scale, y_scale); + if (unlikely (status && status != CAIRO_INT_STATUS_NOTHING_TO_DO)) + goto UNLOCK; + } + + *num_glyphs = remaining_glyphs; + } + +UNLOCK: + _cairo_scaled_font_thaw_cache (scaled_font); + + if (surface->is_vector) + cairo_scaled_font_destroy (scaled_font); + + return status; +} + +/* Note: the backends may modify the contents of the glyph array as long as + * they do not return %CAIRO_INT_STATUS_UNSUPPORTED. This makes it possible to + * avoid copying the array again and again, and edit it in-place. + * Backends are in fact free to use the array as a generic buffer as they + * see fit. + * + * For show_glyphs backend method, and NOT for show_text_glyphs method, + * when they do return UNSUPPORTED, they may adjust remaining_glyphs to notify + * that they have successfully rendered some of the glyphs (from the beginning + * of the array), but not all. If they don't touch remaining_glyphs, it + * defaults to all glyphs. + * + * See commits 5a9642c5746fd677aed35ce620ce90b1029b1a0c and + * 1781e6018c17909311295a9cc74b70500c6b4d0a for the rationale. + */ +cairo_status_t +_cairo_surface_show_text_glyphs (cairo_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const char *utf8, + int utf8_len, + cairo_glyph_t *glyphs, + int num_glyphs, + const cairo_text_cluster_t *clusters, + int num_clusters, + cairo_text_cluster_flags_t cluster_flags, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip) +{ + cairo_int_status_t status; + char *utf8_copy = NULL; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + if (unlikely (surface->status)) + return surface->status; + if (unlikely (surface->finished)) + return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + + if (num_glyphs == 0 && utf8_len == 0) + return CAIRO_STATUS_SUCCESS; + + if (_cairo_clip_is_all_clipped (clip)) + return CAIRO_STATUS_SUCCESS; + + status = _pattern_has_error (source); + if (unlikely (status)) + return status; + + status = cairo_scaled_font_status (scaled_font); + if (unlikely (status)) + return status; + + if (!(_cairo_scaled_font_has_color_glyphs (scaled_font) && + scaled_font->options.color_mode != CAIRO_COLOR_MODE_NO_COLOR)) + { + if (nothing_to_do (surface, op, source)) + return CAIRO_STATUS_SUCCESS; + } + + status = _cairo_surface_begin_modification (surface); + if (unlikely (status)) + return status; + + if (source->is_foreground_marker && surface->foreground_source) + source = surface->foreground_source; + + if (_cairo_scaled_font_has_color_glyphs (scaled_font) && + scaled_font->options.color_mode != CAIRO_COLOR_MODE_NO_COLOR) + { + utf8_copy = malloc (sizeof (char) * utf8_len); + memcpy (utf8_copy, utf8, sizeof (char) * utf8_len); + utf8 = utf8_copy; + + status = composite_color_glyphs (surface, op, + source, + (char *)utf8, &utf8_len, + glyphs, &num_glyphs, + (cairo_text_cluster_t *)clusters, &num_clusters, cluster_flags, + scaled_font, + clip); + + if (unlikely (status && status != CAIRO_INT_STATUS_NOTHING_TO_DO)) + goto DONE; + + if (num_glyphs == 0) + goto DONE; + } else { + utf8_copy = NULL; + } + + /* The logic here is duplicated in _cairo_analysis_surface show_glyphs and + * show_text_glyphs. Keep in synch. */ + if (clusters) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + /* A real show_text_glyphs call. Try show_text_glyphs backend + * method first */ + if (surface->backend->show_text_glyphs != NULL) { + status = surface->backend->show_text_glyphs (surface, op, + source, + utf8, utf8_len, + glyphs, num_glyphs, + clusters, num_clusters, cluster_flags, + scaled_font, + clip); + } + if (status == CAIRO_INT_STATUS_UNSUPPORTED && + surface->backend->show_glyphs) + { + status = surface->backend->show_glyphs (surface, op, + source, + glyphs, num_glyphs, + scaled_font, + clip); + } + } else { + /* A mere show_glyphs call. Try show_glyphs backend method first */ + if (surface->backend->show_glyphs != NULL) { + status = surface->backend->show_glyphs (surface, op, + source, + glyphs, num_glyphs, + scaled_font, + clip); + } else if (surface->backend->show_text_glyphs != NULL) { + /* Intentionally only try show_text_glyphs method for show_glyphs + * calls if backend does not have show_glyphs. If backend has + * both methods implemented, we don't fallback from show_glyphs to + * show_text_glyphs, and hence the backend can assume in its + * show_text_glyphs call that clusters is not NULL (which also + * implies that UTF-8 is not NULL, unless the text is + * zero-length). + */ + status = surface->backend->show_text_glyphs (surface, op, + source, + utf8, utf8_len, + glyphs, num_glyphs, + clusters, num_clusters, cluster_flags, + scaled_font, + clip); + } + } + +DONE: + if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) { + surface->is_clear = FALSE; + surface->serial++; + } + + if (utf8_copy) + free (utf8_copy); + + return _cairo_surface_set_error (surface, status); +} + +cairo_status_t +_cairo_surface_tag (cairo_surface_t *surface, + cairo_bool_t begin, + const char *tag_name, + const char *attributes) +{ + cairo_int_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + if (unlikely (surface->status)) + return surface->status; + if (unlikely (surface->finished)) + return _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + + if (surface->backend->tag == NULL) + return CAIRO_STATUS_SUCCESS; + + status = surface->backend->tag (surface, begin, tag_name, attributes); + surface->is_clear = FALSE; + + return _cairo_surface_set_error (surface, status); +} + +cairo_bool_t +_cairo_surface_supports_color_glyph (cairo_surface_t *surface, + cairo_scaled_font_t *scaled_font, + unsigned long glyph_index) +{ + if (surface->backend->supports_color_glyph != NULL) + return surface->backend->supports_color_glyph (surface, scaled_font, glyph_index); + + return FALSE; +} + +/** + * _cairo_surface_set_resolution: + * @surface: the surface + * @x_res: x resolution, in dpi + * @y_res: y resolution, in dpi + * + * Set the actual surface resolution of @surface to the given x and y DPI. + * Mainly used for correctly computing the scale factor when fallback + * rendering needs to take place in the paginated surface. + **/ +void +_cairo_surface_set_resolution (cairo_surface_t *surface, + double x_res, + double y_res) +{ + if (surface->status) + return; + + surface->x_resolution = x_res; + surface->y_resolution = y_res; +} + +/** + * _cairo_surface_create_in_error: + * @status: the error status + * + * Return an appropriate static error surface for the error status. + * On error, surface creation functions should always return a surface + * created with _cairo_surface_create_in_error() instead of a new surface + * in an error state. This simplifies internal code as no refcounting has + * to be done. + **/ +cairo_surface_t * +_cairo_surface_create_in_error (cairo_status_t status) +{ + assert (status < CAIRO_STATUS_LAST_STATUS); + switch (status) { + case CAIRO_STATUS_NO_MEMORY: + return (cairo_surface_t *) &_cairo_surface_nil; + case CAIRO_STATUS_SURFACE_TYPE_MISMATCH: + return (cairo_surface_t *) &_cairo_surface_nil_surface_type_mismatch; + case CAIRO_STATUS_INVALID_STATUS: + return (cairo_surface_t *) &_cairo_surface_nil_invalid_status; + case CAIRO_STATUS_INVALID_CONTENT: + return (cairo_surface_t *) &_cairo_surface_nil_invalid_content; + case CAIRO_STATUS_INVALID_FORMAT: + return (cairo_surface_t *) &_cairo_surface_nil_invalid_format; + case CAIRO_STATUS_INVALID_VISUAL: + return (cairo_surface_t *) &_cairo_surface_nil_invalid_visual; + case CAIRO_STATUS_READ_ERROR: + return (cairo_surface_t *) &_cairo_surface_nil_read_error; + case CAIRO_STATUS_WRITE_ERROR: + return (cairo_surface_t *) &_cairo_surface_nil_write_error; + case CAIRO_STATUS_FILE_NOT_FOUND: + return (cairo_surface_t *) &_cairo_surface_nil_file_not_found; + case CAIRO_STATUS_TEMP_FILE_ERROR: + return (cairo_surface_t *) &_cairo_surface_nil_temp_file_error; + case CAIRO_STATUS_INVALID_STRIDE: + return (cairo_surface_t *) &_cairo_surface_nil_invalid_stride; + case CAIRO_STATUS_INVALID_SIZE: + return (cairo_surface_t *) &_cairo_surface_nil_invalid_size; + case CAIRO_STATUS_DEVICE_TYPE_MISMATCH: + return (cairo_surface_t *) &_cairo_surface_nil_device_type_mismatch; + case CAIRO_STATUS_DEVICE_ERROR: + return (cairo_surface_t *) &_cairo_surface_nil_device_error; + case CAIRO_STATUS_PNG_ERROR: + return (cairo_surface_t *) &_cairo_surface_nil_png_error; + case CAIRO_STATUS_SUCCESS: + case CAIRO_STATUS_LAST_STATUS: + ASSERT_NOT_REACHED; + /* fall-through */ + case CAIRO_STATUS_INVALID_RESTORE: + case CAIRO_STATUS_INVALID_POP_GROUP: + case CAIRO_STATUS_NO_CURRENT_POINT: + case CAIRO_STATUS_INVALID_MATRIX: + case CAIRO_STATUS_NULL_POINTER: + case CAIRO_STATUS_INVALID_STRING: + case CAIRO_STATUS_INVALID_PATH_DATA: + case CAIRO_STATUS_SURFACE_FINISHED: + case CAIRO_STATUS_PATTERN_TYPE_MISMATCH: + case CAIRO_STATUS_INVALID_DASH: + case CAIRO_STATUS_INVALID_DSC_COMMENT: + case CAIRO_STATUS_INVALID_INDEX: + case CAIRO_STATUS_CLIP_NOT_REPRESENTABLE: + case CAIRO_STATUS_FONT_TYPE_MISMATCH: + case CAIRO_STATUS_USER_FONT_IMMUTABLE: + case CAIRO_STATUS_USER_FONT_ERROR: + case CAIRO_STATUS_NEGATIVE_COUNT: + case CAIRO_STATUS_INVALID_CLUSTERS: + case CAIRO_STATUS_INVALID_SLANT: + case CAIRO_STATUS_INVALID_WEIGHT: + case CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED: + case CAIRO_STATUS_INVALID_MESH_CONSTRUCTION: + case CAIRO_STATUS_DEVICE_FINISHED: + case CAIRO_STATUS_JBIG2_GLOBAL_MISSING: + case CAIRO_STATUS_FREETYPE_ERROR: + case CAIRO_STATUS_WIN32_GDI_ERROR: + case CAIRO_INT_STATUS_DWRITE_ERROR: + case CAIRO_STATUS_TAG_ERROR: + case CAIRO_STATUS_SVG_FONT_ERROR: + default: + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_surface_t *) &_cairo_surface_nil; + } +} + +cairo_surface_t * +_cairo_int_surface_create_in_error (cairo_int_status_t status) +{ + if (status < CAIRO_INT_STATUS_LAST_STATUS) + return _cairo_surface_create_in_error (status); + + switch ((int)status) { + case CAIRO_INT_STATUS_UNSUPPORTED: + return (cairo_surface_t *) &_cairo_surface_nil_unsupported; + case CAIRO_INT_STATUS_NOTHING_TO_DO: + return (cairo_surface_t *) &_cairo_surface_nil_nothing_to_do; + default: + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_surface_t *) &_cairo_surface_nil; + } +} + +/* LocalWords: rasterized + */ diff --git a/local/recipes/libs/cairo/source/src/cairo-svg-glyph-render.c b/local/recipes/libs/cairo/source/src/cairo-svg-glyph-render.c new file mode 100644 index 0000000000..d0448bbda5 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-svg-glyph-render.c @@ -0,0 +1,3244 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2022 Adrian Johnson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Adrian Johnson. + * + * Contributor(s): + * Adrian Johnson + */ + +#include "cairoint.h" +#include "cairo-array-private.h" +#include "cairo-ft-private.h" +#include "cairo-pattern-private.h" +#include "cairo-scaled-font-subsets-private.h" + +#include +#include +#include + +#if HAVE_FT_SVG_DOCUMENT + +#include +#include FT_COLOR_H + +/* #define SVG_RENDER_PRINT_FUNCTIONS 1 */ + +#define WHITE_SPACE_CHARS " \n\r\t\v\f" + +typedef struct { + const char *name; + int red; + int green; + int blue; +} color_name_t; + +/* Must be sorted */ +static color_name_t color_names[] = { + { "aliceblue", 240, 248, 255 }, + { "antiquewhite", 250, 235, 215 }, + { "aqua", 0, 255, 255 }, + { "aquamarine", 127, 255, 212 }, + { "azure", 240, 255, 255 }, + { "beige", 245, 245, 220 }, + { "bisque", 255, 228, 196 }, + { "black", 0, 0, 0 }, + { "blanchedalmond", 255, 235, 205 }, + { "blue", 0, 0, 255 }, + { "blueviolet", 138, 43, 226 }, + { "brown", 165, 42, 42 }, + { "burlywood", 222, 184, 135 }, + { "cadetblue", 95, 158, 160 }, + { "chartreuse", 127, 255, 0 }, + { "chocolate", 210, 105, 30 }, + { "coral", 255, 127, 80 }, + { "cornflowerblue", 100, 149, 237 }, + { "cornsilk", 255, 248, 220 }, + { "crimson", 220, 20, 60 }, + { "cyan", 0, 255, 255 }, + { "darkblue", 0, 0, 139 }, + { "darkcyan", 0, 139, 139 }, + { "darkgoldenrod", 184, 134, 11 }, + { "darkgray", 169, 169, 169 }, + { "darkgreen", 0, 100, 0 }, + { "darkgrey", 169, 169, 169 }, + { "darkkhaki", 189, 183, 107 }, + { "darkmagenta", 139, 0, 139 }, + { "darkolivegreen", 85, 107, 47 }, + { "darkorange", 255, 140, 0 }, + { "darkorchid", 153, 50, 204 }, + { "darkred", 139, 0, 0 }, + { "darksalmon", 233, 150, 122 }, + { "darkseagreen", 143, 188, 143 }, + { "darkslateblue", 72, 61, 139 }, + { "darkslategray", 47, 79, 79 }, + { "darkslategrey", 47, 79, 79 }, + { "darkturquoise", 0, 206, 209 }, + { "darkviolet", 148, 0, 211 }, + { "deeppink", 255, 20, 147 }, + { "deepskyblue", 0, 191, 255 }, + { "dimgray", 105, 105, 105 }, + { "dimgrey", 105, 105, 105 }, + { "dodgerblue", 30, 144, 255 }, + { "firebrick", 178, 34, 34 }, + { "floralwhite", 255, 250, 240 }, + { "forestgreen", 34, 139, 34 }, + { "fuchsia", 255, 0, 255 }, + { "gainsboro", 220, 220, 220 }, + { "ghostwhite", 248, 248, 255 }, + { "gold", 255, 215, 0 }, + { "goldenrod", 218, 165, 32 }, + { "gray", 128, 128, 128 }, + { "green", 0, 128, 0 }, + { "greenyellow", 173, 255, 47 }, + { "grey", 128, 128, 128 }, + { "honeydew", 240, 255, 240 }, + { "hotpink", 255, 105, 180 }, + { "indianred", 205, 92, 92 }, + { "indigo", 75, 0, 130 }, + { "ivory", 255, 255, 240 }, + { "khaki", 240, 230, 140 }, + { "lavender", 230, 230, 250 }, + { "lavenderblush", 255, 240, 245 }, + { "lawngreen", 124, 252, 0 }, + { "lemonchiffon", 255, 250, 205 }, + { "lightblue", 173, 216, 230 }, + { "lightcoral", 240, 128, 128 }, + { "lightcyan", 224, 255, 255 }, + { "lightgoldenrodyellow", 250, 250, 210 }, + { "lightgray", 211, 211, 211 }, + { "lightgreen", 144, 238, 144 }, + { "lightgrey", 211, 211, 211 }, + { "lightpink", 255, 182, 193 }, + { "lightsalmon", 255, 160, 122 }, + { "lightseagreen", 32, 178, 170 }, + { "lightskyblue", 135, 206, 250 }, + { "lightslategray", 119, 136, 153 }, + { "lightslategrey", 119, 136, 153 }, + { "lightsteelblue", 176, 196, 222 }, + { "lightyellow", 255, 255, 224 }, + { "lime", 0, 255, 0 }, + { "limegreen", 50, 205, 50 }, + { "linen", 250, 240, 230 }, + { "magenta", 255, 0, 255 }, + { "maroon", 128, 0, 0 }, + { "mediumaquamarine", 102, 205, 170 }, + { "mediumblue", 0, 0, 205 }, + { "mediumorchid", 186, 85, 211 }, + { "mediumpurple", 147, 112, 219 }, + { "mediumseagreen", 60, 179, 113 }, + { "mediumslateblue", 123, 104, 238 }, + { "mediumspringgreen", 0, 250, 154 }, + { "mediumturquoise", 72, 209, 204 }, + { "mediumvioletred", 199, 21, 133 }, + { "midnightblue", 25, 25, 112 }, + { "mintcream", 245, 255, 250 }, + { "mistyrose", 255, 228, 225 }, + { "moccasin", 255, 228, 181 }, + { "navajowhite", 255, 222, 173 }, + { "navy", 0, 0, 128 }, + { "oldlace", 253, 245, 230 }, + { "olive", 128, 128, 0 }, + { "olivedrab", 107, 142, 35 }, + { "orange", 255, 165, 0 }, + { "orangered", 255, 69, 0 }, + { "orchid", 218, 112, 214 }, + { "palegoldenrod", 238, 232, 170 }, + { "palegreen", 152, 251, 152 }, + { "paleturquoise", 175, 238, 238 }, + { "palevioletred", 219, 112, 147 }, + { "papayawhip", 255, 239, 213 }, + { "peachpuff", 255, 218, 185 }, + { "peru", 205, 133, 63 }, + { "pink", 255, 192, 203 }, + { "plum", 221, 160, 221 }, + { "powderblue", 176, 224, 230 }, + { "purple", 128, 0, 128 }, + { "red", 255, 0, 0 }, + { "rosybrown", 188, 143, 143 }, + { "royalblue", 65, 105, 225 }, + { "saddlebrown", 139, 69, 19 }, + { "salmon", 250, 128, 114 }, + { "sandybrown", 244, 164, 96 }, + { "seagreen", 46, 139, 87 }, + { "seashell", 255, 245, 238 }, + { "sienna", 160, 82, 45 }, + { "silver", 192, 192, 192 }, + { "skyblue", 135, 206, 235 }, + { "slateblue", 106, 90, 205 }, + { "slategray", 112, 128, 144 }, + { "slategrey", 112, 128, 144 }, + { "snow", 255, 250, 250 }, + { "springgreen", 0, 255, 127 }, + { "steelblue", 70, 130, 180 }, + { "tan", 210, 180, 140 }, + { "teal", 0, 128, 128 }, + { "thistle", 216, 191, 216 }, + { "tomato", 255, 99, 71 }, + { "turquoise", 64, 224, 208 }, + { "violet", 238, 130, 238 }, + { "wheat", 245, 222, 179 }, + { "white", 255, 255, 255 }, + { "whitesmoke", 245, 245, 245 }, + { "yellow", 255, 255, 0 }, + { "yellowgreen", 154, 205, 50 } +}; + +typedef struct { + char *name; + char *value; +} svg_attribute_t; + +typedef enum { + CONTAINER_ELEMENT, + EMPTY_ELEMENT, + PROCESSING_INSTRUCTION, + DOCTYPE, + CDATA, + COMMENT +} tag_type_t; + +#define TOP_ELEMENT_TAG "_top" + +typedef struct _cairo_svg_element { + cairo_hash_entry_t base; + tag_type_t type; + char *tag; + char *id; + cairo_array_t attributes; /* svg_attribute_t */ + cairo_array_t children; /* cairo_svg_element_t* */ + cairo_array_t content; /* char */ + cairo_pattern_t *pattern; /* defined if a paint server */ + struct _cairo_svg_element *next; /* next on element stack */ +} cairo_svg_element_t; + +typedef struct _cairo_svg_color { + enum { RGB, FOREGROUND } type; + double red; + double green; + double blue; +} cairo_svg_color_t; + +typedef struct _cairo_svg_paint { + enum { PAINT_COLOR, PAINT_SERVER, PAINT_NONE } type; + cairo_svg_color_t color; + cairo_svg_element_t *paint_server; +} cairo_svg_paint_t; + +typedef enum { + GS_RENDER, + GS_NO_RENDER, + GS_COMPUTE_BBOX, + GS_CLIP +} gs_mode_t; + +typedef struct _cairo_svg_graphics_state { + cairo_svg_paint_t fill; + cairo_svg_paint_t stroke; + cairo_svg_color_t color; + double fill_opacity; + double stroke_opacity; + double opacity; + cairo_fill_rule_t fill_rule; + cairo_fill_rule_t clip_rule; + cairo_path_t *clip_path; + char *dash_array; + double dash_offset; + gs_mode_t mode; + struct { + double x; + double y; + double width; + double height; + } bbox; + struct _cairo_svg_graphics_state *next; +} cairo_svg_graphics_state_t; + +typedef enum { + BUILD_PATTERN_NONE, + BUILD_PATTERN_LINEAR, + BUILD_PATTERN_RADIAL +} build_pattern_t; + +typedef struct _cairo_svg_glyph_render { + cairo_svg_element_t *tree; + cairo_hash_table_t *ids; + cairo_svg_graphics_state_t *graphics_state; + cairo_t *cr; + double units_per_em; + struct { + cairo_svg_element_t *paint_server; + cairo_pattern_t *pattern; + build_pattern_t type; + } build_pattern; + int render_element_tree_depth; + int num_palette_entries; + FT_Color* palette; + + /* Viewport */ + double width; + double height; + cairo_bool_t view_port_set; + + cairo_pattern_t *foreground_marker; + cairo_pattern_t *foreground_source; + cairo_bool_t foreground_source_used; + + int debug; /* 0 = quiet, 1 = errors, 2 = warnings, 3 = info */ +} cairo_svg_glyph_render_t; + + +#define SVG_RENDER_ERROR 1 +#define SVG_RENDER_WARNING 2 +#define SVG_RENDER_INFO 3 + +#define print_error(render, ...) cairo_svg_glyph_render_printf(render, SVG_RENDER_ERROR, ##__VA_ARGS__) +#define print_warning(render, ...) cairo_svg_glyph_render_printf(render, SVG_RENDER_WARNING, ##__VA_ARGS__) +#define print_info(render, ...) cairo_svg_glyph_render_printf(render, SVG_RENDER_INFO, ##__VA_ARGS__) + +static void +cairo_svg_glyph_render_printf (cairo_svg_glyph_render_t *svg_render, + int level, + const char *fmt, ...) CAIRO_PRINTF_FORMAT (3, 4); + +static void +cairo_svg_glyph_render_printf (cairo_svg_glyph_render_t *svg_render, + int level, + const char *fmt, ...) +{ + va_list ap; + + if (svg_render->debug >= level ) { + switch (level) { + case SVG_RENDER_ERROR: + printf("ERROR: "); + break; + case SVG_RENDER_WARNING: + printf("WARNING: "); + break; + } + va_start (ap, fmt); + vprintf (fmt, ap); + va_end (ap); + printf ("\n"); + } +} + +static cairo_bool_t +string_equal (const char *s1, const char *s2) +{ + if (s1 && s2) + return strcmp (s1, s2) == 0; + + if (!s1 && !s2) + return TRUE; + + return FALSE; +} + +static cairo_bool_t +string_match (const char **p, const char *str) +{ + if (*p && strncmp (*p, str, strlen (str)) == 0) { + *p += strlen (str); + return TRUE; + } + return FALSE; +} + +static const char * +skip_space (const char *p) +{ + while (*p && _cairo_isspace (*p)) + p++; + + return p; +} + +/* Skip over character c and and whitespace before or after. Returns + * NULL if c not found. */ +static const char * +skip_char (const char *p, char c) +{ + while (_cairo_isspace (*p)) + p++; + + if (*p != c) + return NULL; + + p++; + + while (_cairo_isspace (*p)) + p++; + + return p; +} + +static int +_color_name_compare (const void *a, const void *b) +{ + const color_name_t *a_color = a; + const color_name_t *b_color = b; + + return strcmp (a_color->name, b_color->name); +} + +static void +init_element_id_key (cairo_svg_element_t *element) +{ + element->base.hash = _cairo_hash_string (element->id); +} + +static cairo_bool_t +_element_id_equal (const void *key_a, const void *key_b) +{ + const cairo_svg_element_t *a = key_a; + const cairo_svg_element_t *b = key_b; + + return string_equal (a->id, b->id); +} + +/* Find element with the "id" attribute matching id. id may have the + * '#' prefix. It will be stripped before searching. + */ +static cairo_svg_element_t * +lookup_element (cairo_svg_glyph_render_t *svg_render, const char *id) +{ + cairo_svg_element_t key; + + if (!id || strlen (id) < 1) + return NULL; + + key.id = (char *)(id[0] == '#' ? id + 1 : id); + init_element_id_key (&key); + return _cairo_hash_table_lookup (svg_render->ids, &key.base); +} + +/* Find element with the "id" attribute matching url where url is of + * the form "url(#id)". + */ +static cairo_svg_element_t * +lookup_url_element (cairo_svg_glyph_render_t *svg_render, const char *url) +{ + const char *p = url; + cairo_svg_element_t *element = NULL; + + if (p && string_match (&p, "url")) { + p = skip_char (p, '('); + if (!p) + return NULL; + + const char *end = strpbrk(p, WHITE_SPACE_CHARS ")"); + if (end) { + char *id = _cairo_strndup (p, end - p); + element = lookup_element (svg_render, id); + free (id); + } + } + return element; +} + +static const char * +get_attribute (const cairo_svg_element_t *element, const char *name) +{ + svg_attribute_t attr; + int num_elems, i; + + num_elems = _cairo_array_num_elements (&element->attributes); + for (i = 0; i < num_elems; i++) { + _cairo_array_copy_element (&element->attributes, i, &attr); + if (string_equal (attr.name, name)) + return attr.value; + } + return NULL; +} + +static const char * +get_href_attribute (const cairo_svg_element_t *element) +{ + svg_attribute_t attr; + int num_elems, i, len; + + /* SVG2 requires the href attribute to be "href". Older versions + * used "xlink:href". I have seen at least one font that used an + * alternative name space eg "ns1:href". To keep things simple we + * search for an attribute named "href" or ending in ":href". + */ + num_elems = _cairo_array_num_elements (&element->attributes); + for (i = 0; i < num_elems; i++) { + _cairo_array_copy_element (&element->attributes, i, &attr); + if (string_equal (attr.name, "href")) + return attr.value; + + len = strlen (attr.name); + if (len > 4 && string_equal (attr.name + len - 5, ":href")) + return attr.value; + } + return NULL; +} + +/* Get a float attribute or float percentage. If attribute is a + * percentage, the returned value is percentage * scale. Does not + * modify value if it returns FALSE. This allows value to be set to a + * default before calling get_float_attribute(), then used without + * checking the return value of this function. + */ +static cairo_bool_t +get_float_or_percent_attribute (const cairo_svg_element_t *element, + const char *name, + double scale, + double *value) +{ + const char *p; + char *end; + double v; + + p = get_attribute (element, name); + if (p) { + v = _cairo_strtod (p, &end); + if (end != p) { + *value = v; + if (*end == '%') + *value *= scale / 100.0; + return TRUE; + } + } + return FALSE; +} + +/* Does not modify value if it returns FALSE. This allows value to be + * set to a default before calling get_float_attribute(), then used + * without checking the return value of this function. + */ +static cairo_bool_t +get_float_attribute (const cairo_svg_element_t *element, const char *name, double *value) +{ + const char *p; + char *end; + double v; + + p = get_attribute (element, name); + if (p) { + v = _cairo_strtod (p, &end); + if (end != p) { + *value = v; + return TRUE; + } + } + return FALSE; +} + +static cairo_fill_rule_t +get_fill_rule_attribute (const cairo_svg_element_t *element, const char *name, cairo_fill_rule_t default_value) +{ + const char *p; + + p = get_attribute (element, name); + if (string_equal (p, "nonzero")) + return CAIRO_FILL_RULE_WINDING; + else if (string_equal (p, "evenodd")) + return CAIRO_FILL_RULE_EVEN_ODD; + else + return default_value; +} + +static void +free_elements (cairo_svg_glyph_render_t *svg_render, + cairo_svg_element_t *element) +{ + int num_elems; + + num_elems = _cairo_array_num_elements (&element->children); + for (int i = 0; i < num_elems; i++) { + cairo_svg_element_t *child; + _cairo_array_copy_element (&element->children, i, &child); + free_elements (svg_render, child); + } + _cairo_array_fini (&element->children); + + num_elems = _cairo_array_num_elements (&element->attributes); + for (int i = 0; i < num_elems; i++) { + svg_attribute_t *attr = _cairo_array_index (&element->attributes, i); + free (attr->name); + free (attr->value); + } + _cairo_array_fini (&element->attributes); + _cairo_array_fini (&element->content); + + free (element->tag); + + if (element->id) { + _cairo_hash_table_remove (svg_render->ids, &element->base); + free (element->id); + } + + if (element->pattern) + cairo_pattern_destroy (element->pattern); + + free (element); +} + +#if SVG_RENDER_PRINT_FUNCTIONS + +static void indent(int level) +{ + for (int i = 1; i < level; i++) + printf(" "); +} + +static void +print_element (cairo_svg_element_t *element, cairo_bool_t recurse, int level) +{ + char *content = strndup (_cairo_array_index_const (&element->content, 0), + _cairo_array_num_elements (&element->content)); + + indent(level); + if (element->type == COMMENT) { + printf("\n", content); + } else if (element->type == CDATA) { + printf("\n", content); + } else if (element->type == DOCTYPE) { + printf("\n", content); + } else if (element->type == PROCESSING_INSTRUCTION) { + printf("\n", content); + } else { + cairo_bool_t top_element = string_equal (element->tag, TOP_ELEMENT_TAG); + + if (!top_element) { + printf("<%s", element->tag); + int num_elems = _cairo_array_num_elements (&element->attributes); + for (int i = 0; i < num_elems; i++) { + svg_attribute_t *attr = _cairo_array_index (&element->attributes, i); + printf(" %s=\"%s\"", attr->name, attr->value); + } + if (num_elems > 0) + printf(" "); + + if (element->type == EMPTY_ELEMENT) + printf("/>\n"); + else + printf(">\n"); + } + + if (element->type == CONTAINER_ELEMENT) { + if (recurse) { + int num_elems = _cairo_array_num_elements (&element->children); + for (int i = 0; i < num_elems; i++) { + cairo_svg_element_t *child; + _cairo_array_copy_element (&element->children, i, &child); + print_element (child, TRUE, level + 1); + } + } + if (!top_element) + printf("\n", element->tag); + } + } + free (content); +} +#endif + +static const char * +parse_list_of_floats (const char *p, + int num_required, + int num_optional, + cairo_bool_t *have_optional, + va_list ap) +{ + double d; + double *dp; + char *end; + const char *q = NULL; + int num_found = 0; + + for (int i = 0; i < num_required + num_optional; i++) { + while (p && (*p == ',' || _cairo_isspace (*p))) + p++; + + if (!p) + break; + + d = _cairo_strtod (p, &end); + if (end == p) { + p = NULL; + break; + } + p = end; + dp = va_arg (ap, double *); + *dp = d; + num_found++; + if (num_found == num_required) + q = p; + } + + if (num_optional > 0) { + if (num_found == num_required + num_optional) { + *have_optional = TRUE; + } else { + *have_optional = FALSE; + /* restore pointer to end of required floats */ + p = q; + } + } + + return p; +} + +static const char * +get_floats (const char *p, + int num_required, + int num_optional, + cairo_bool_t *have_optional, + ...) +{ + va_list ap; + + va_start (ap, have_optional); + p = parse_list_of_floats (p, num_required, num_optional, have_optional, ap); + va_end (ap); + return p; +} + +static const char * +get_path_params (const char *p, int num_params, ...) +{ + va_list ap; + + va_start (ap, num_params); + p = parse_list_of_floats (p, num_params, 0, NULL, ap); + va_end (ap); + return p; +} + +static cairo_bool_t +get_color (cairo_svg_glyph_render_t *svg_render, + const char *s, + cairo_svg_color_t *color) +{ + int len, matched; + unsigned r = 0, g = 0, b = 0; + + if (!s) + return FALSE; + + len = strlen(s); + + if (string_equal (s, "inherit")) { + return FALSE; + } else if (string_equal (s, "currentColor") || + string_equal (s, "context-fill") || + string_equal (s, "context-stroke")) + { + *color = svg_render->graphics_state->color; + return TRUE; + } else if (len > 0 && s[0] == '#') { + if (len == 4) { + matched = sscanf (s + 1, "%1x%1x%1x", &r, &g, &b); + if (matched == 3) { + /* Each digit is repeated to convert to 6 digits. eg 0x123 -> 0x112233 */ + color->type = RGB; + color->red = 0x11*r/255.0; + color->green = 0x11*g/255.0; + color->blue = 0x11*b/255.0; + return TRUE; + } + } else if (len == 7) { + matched = sscanf (s + 1, "%2x%2x%2x", &r, &g, &b); + if (matched == 3) { + color->type = RGB; + color->red = r/255.0; + color->green = g/255.0; + color->blue = b/255.0; + return TRUE; + } + } + } else if (strncmp (s, "rgb", 3) == 0) { + matched = sscanf (s, "rgb ( %u , %u , %u )", &r, &g, &b); + if (matched == 3) { + color->type = RGB; + color->red = r/255.0; + color->green = g/255.0; + color->blue = b/255.0; + return TRUE; + } + } else if (strncmp (s, "var", 3) == 0) { + /* CPAL palettes colors. eg "var(--color0, yellow)" */ + s += 3; + s = skip_char (s, '('); + if (!string_match (&s, "--color")) + return FALSE; + + char *end; + int entry = strtol (s, &end, 10); + if (end == s) + return FALSE; + + if (svg_render->palette && entry >= 0 && entry < svg_render->num_palette_entries) { + FT_Color *palette_color = &svg_render->palette[entry]; + color->type = RGB; + color->red = palette_color->red / 255.0; + color->green = palette_color->green/ 255.0; + color->blue = palette_color->blue / 255.0; + return TRUE; + } else { + /* Fallback color */ + s = skip_char (end, ','); + if (!s) + return FALSE; + + end = strpbrk(s, WHITE_SPACE_CHARS ")"); + if (!end || end == s) + return FALSE; + + char *fallback = _cairo_strndup (s, end - s); + cairo_bool_t success = get_color (svg_render, fallback, color); + free (fallback); + return success; + } + } else { + const color_name_t *color_name; + color_name_t color_name_key; + + color_name_key.name = (char *) s; + color_name = bsearch (&color_name_key, + color_names, + ARRAY_LENGTH (color_names), + sizeof (color_name_t), + _color_name_compare); + if (color_name) { + color->type = RGB; + color->red = color_name->red/255.0; + color->green = color_name->green/255.0; + color->blue = color_name->blue/255.0; + return TRUE; + } + } + return FALSE; +} + +static void +get_paint (cairo_svg_glyph_render_t *svg_render, + const char *p, + cairo_svg_paint_t *paint) +{ + cairo_svg_element_t *element; + + if (string_match (&p, "none")) { + paint->type = PAINT_NONE; + paint->paint_server = NULL; + } else if (p && strncmp (p, "url", 3) == 0) { + element = lookup_url_element (svg_render, p); + if (element) { + paint->type = PAINT_SERVER; + paint->paint_server = element; + } + } else { + if (get_color (svg_render, p, &paint->color)) { + paint->type = PAINT_COLOR; + paint->paint_server = NULL; + } + } +} + +#ifdef SVG_RENDER_PRINT_FUNCTIONS + +static void +print_color (cairo_svg_color_t *color) +{ + switch (color->type) { + case FOREGROUND_COLOR: + printf("foreground"); + break; + case RGB: + printf("#%02x%02x%02x", + (int)(color->red*255), + (int)(color->red*255), + (int)(color->red*255)); + break; + } +} + +static void +print_paint (cairo_svg_paint_t *paint) +{ + printf("Paint: "); + switch (paint->type) { + case PAINT_COLOR: + printf("color: "); + print_color (&paint->color); + break; + case PAINT_SERVER: + printf("server: %s", paint->paint_server->tag); + break; + case PAINT_NONE: + printf("none"); + break; + } + printf("\n"); +} + +#endif + +static void +parse_error (cairo_svg_glyph_render_t *svg_render, + const char *string, + const char *location, + const char *fmt, + ...) CAIRO_PRINTF_FORMAT (4, 5); + +static void +parse_error (cairo_svg_glyph_render_t *svg_render, + const char *string, + const char *location, + const char *fmt, + ...) +{ + va_list ap; + const int context = 40; + const char *start; + const char *end; + + if (svg_render->debug >= SVG_RENDER_ERROR) { + printf("ERROR: "); + va_start (ap, fmt); + vprintf (fmt, ap); + va_end (ap); + putchar ('\n'); + start = location - context; + if (start < string) + start = string; + + end = location + strlen (location); + if (end - location > context) + end = location + context; + + for (const char *p = start; p < end; p++) { + if (_cairo_isspace (*p)) + putchar (' '); + else + putchar (*p); + } + putchar ('\n'); + + for (int i = 0; i < location - start; i++) + putchar(' '); + putchar ('^'); + putchar ('\n'); + printf (" at position %td\n", location - string); + } +} + +static cairo_bool_t +append_attribute (cairo_svg_element_t *element, svg_attribute_t *attribute) +{ + const char *p; + const char *end; + svg_attribute_t attr; + + memset (&attr, 0, sizeof (attr)); + if (string_equal (attribute->name, "style")) { + /* split style into individual attributes */ + p = attribute->value; + while (*p) { + end = strchr (p, ':'); + if (!end || end == p) + break; + attr.name = _cairo_strndup (p, end - p); + p = end + 1; + p = skip_space(p); + end = strchr (p, ';'); + if (!end) + end = strchr (p, 0); + if (end == p) + goto split_style_fail; + + attr.value = _cairo_strndup (p, end - p); + if (*end) + p = end + 1; + + if (_cairo_array_append (&element->attributes, &attr)) + goto split_style_fail; + + memset (&attr, 0, sizeof (attr)); + p = skip_space (p); + } + } + + if (_cairo_array_append (&element->attributes, attribute)) + return FALSE; + + return TRUE; + + split_style_fail: + free (attr.name); + free (attr.value); + return FALSE; +} + +static cairo_bool_t +add_child_element (cairo_svg_glyph_render_t *svg_render, + cairo_svg_element_t *parent, + cairo_svg_element_t *child) +{ + cairo_status_t status; + const char* id; + + id = get_attribute (child, "id"); + if (id) { + child->id = strdup (id); + init_element_id_key (child); + status = _cairo_hash_table_insert (svg_render->ids, &child->base); + if (unlikely (status)) + return FALSE; + } + + status = _cairo_array_append (&parent->children, &child); + return status == CAIRO_STATUS_SUCCESS; +} + +static cairo_svg_element_t * +create_element (tag_type_t type, char *tag) +{ + cairo_svg_element_t *elem; + cairo_status_t status; + + elem = _cairo_calloc (sizeof (cairo_svg_element_t)); + if (unlikely (elem == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + return NULL; + } + + elem->type = type; + elem->tag = tag; + elem->id = NULL; + _cairo_array_init (&elem->attributes, sizeof(svg_attribute_t)); + _cairo_array_init (&elem->children, sizeof(cairo_svg_element_t *)); + _cairo_array_init (&elem->content, sizeof(char)); + elem->pattern = NULL; + elem->next = NULL; + + return elem; +} + +static const char * +parse_attributes (cairo_svg_glyph_render_t *svg_render, + const char *attributes, + cairo_svg_element_t *element) +{ + svg_attribute_t attr; + char quote_char; + const char *p; + const char *end; + + p = attributes; + memset (&attr, 0, sizeof (svg_attribute_t)); + p = skip_space (p); + while (*p && *p != '/' && *p != '>' && *p != '?') { + end = strpbrk(p, WHITE_SPACE_CHARS "="); + if (!end) { + parse_error (svg_render, attributes, p, "Could not find '='"); + goto fail; + } + + if (end == p) { + parse_error (svg_render, attributes, p, "Missing attribute name"); + goto fail; + } + + attr.name = _cairo_strndup (p, end - p); + p = end; + + p = skip_space (p); + if (*p != '=') { + parse_error (svg_render, attributes, p, "Expected '='"); + goto fail; + } + + p++; + p = skip_space (p); + if (*p == '\"' || *p == '\'') { + quote_char = *p; + } else { + parse_error (svg_render, attributes, p, "Could not find '\"' or '''"); + goto fail; + } + + p++; + end = strchr (p, quote_char); + if (!end) { + parse_error (svg_render, attributes, p, "Could not find '%c'", quote_char); + goto fail; + } + + attr.value = _cairo_strndup (p, end - p); + p = end + 1; + + if (!append_attribute (element, &attr)) + goto fail; + + memset (&attr, 0, sizeof (svg_attribute_t)); + + p = skip_space (p); + } + + return p; + + fail: + free (attr.name); + free (attr.value); + return NULL; +} + +static cairo_bool_t +parse_svg (cairo_svg_glyph_render_t *svg_render, + const char *svg_document) +{ + const char *p = svg_document; + const char *end; + int nesting; /* when > 0 we parse content */ + cairo_svg_element_t *open_elem; /* Stack of open elements */ + cairo_svg_element_t *new_elem = NULL; + char *name; + cairo_status_t status; + + /* Create top level element to use as a container for all top + * level elements in the document and push it on the stack. */ + open_elem = create_element (CONTAINER_ELEMENT, strdup(TOP_ELEMENT_TAG)); + + /* We don't want to add content to the top level container. There + * should only be whitesapce between tags. */ + nesting = 0; + + while (*p) { + if (nesting > 0) { + /* In an open element. Anything before the next '<' is content */ + end = strchr (p, '<'); + if (!end) { + parse_error (svg_render, svg_document, p, "Could not find '<'"); + goto fail; + } + status = _cairo_array_append_multiple (&open_elem->content, p, end - p); + p = end; + + } else { + p = skip_space (p); + if (*p == 0) + break; /* end of document */ + } + + /* We should now be at the start of a tag */ + if (*p != '<') { + parse_error (svg_render, svg_document, p, "Could not find '<'"); + goto fail; + } + + p++; + if (*p == '!') { + p++; + if (string_match (&p, "[CDATA[")) { + new_elem = create_element (CDATA, NULL); + end = strstr (p, "]]>"); + if (!end) { + parse_error (svg_render, svg_document, p, "Could not find ']]>'"); + goto fail; + } + + status = _cairo_array_append_multiple (&new_elem->content, p, end - p); + p = end + 3; + } else if (string_match (&p, "--")) { + new_elem = create_element (COMMENT, NULL); + end = strstr (p, "-->"); + if (!end) { + parse_error (svg_render, svg_document, p, "Could not find '-->'"); + goto fail; + } + + status = _cairo_array_append_multiple (&new_elem->content, p, end - p); + p = end + 3; + } else if (string_match (&p, "DOCTYPE")) { + new_elem = create_element (DOCTYPE, NULL); + end = strchr (p, '>'); + if (!end) { + parse_error (svg_render, svg_document, p, "Could not find '>'"); + goto fail; + } + + status = _cairo_array_append_multiple (&new_elem->content, p, end - p); + p = end + 1; + } else { + parse_error (svg_render, svg_document, p, "Invalid"); + goto fail; + } + + if (!add_child_element (svg_render, open_elem, new_elem)) + goto fail; + + new_elem = NULL; + continue; + } + + if (*p == '?') { + p++; + new_elem = create_element (PROCESSING_INSTRUCTION, NULL); + end = strstr (p, "?>"); + if (!end) { + parse_error (svg_render, svg_document, p, "Could not find '?>'"); + goto fail; + } + + status = _cairo_array_append_multiple (&new_elem->content, p, end - p); + p = end + 2; + + if (!add_child_element (svg_render, open_elem, new_elem)) + goto fail; + + new_elem = NULL; + continue; + } + + if (*p == '/') { + /* Closing tag */ + p++; + + /* find end of tag name */ + end = strpbrk(p, WHITE_SPACE_CHARS ">"); + if (!end) { + parse_error (svg_render, svg_document, p, "Could not find '>'"); + goto fail; + } + + name = _cairo_strndup (p, end - p); + p = end; + p = skip_space (p); + if (*p != '>') { + parse_error (svg_render, svg_document, p, "Could not find '>'"); + free (name); + goto fail; + } + + p++; + if (nesting == 0) { + parse_error (svg_render, svg_document, p, "parse_elements: parsed but no matching start tag", name); + free (name); + goto fail; + } + if (!string_equal (name, open_elem->tag)) { + parse_error (svg_render, svg_document, p, + "parse_elements: found but current open tag is <%s>", + name, open_elem->tag); + free (name); + goto fail; + } + + /* pop top element on open elements stack into new_elem */ + new_elem = open_elem; + open_elem = open_elem->next; + new_elem->next = NULL; + nesting--; + + free (name); + if (!add_child_element (svg_render, open_elem, new_elem)) + goto fail; + + new_elem = NULL; + continue; + } + + /* We should now be in a start or empty element tag */ + + /* find end of tag name */ + end = strpbrk(p, WHITE_SPACE_CHARS "/>"); + if (!end) { + parse_error (svg_render, svg_document, p, "Could not find '>'"); + goto fail; + } + + name = _cairo_strndup (p, end - p); + p = end; + + new_elem = create_element (CONTAINER_ELEMENT, name); + p = parse_attributes (svg_render, p, new_elem); + if (!p) + goto fail; + + p = skip_space (p); + if (*p == '/') { + new_elem->type = EMPTY_ELEMENT; + p++; + } + + if (!p || *p != '>') { + print_error (svg_render, "Could not find '>'"); + goto fail; + } + + p++; + if (new_elem->type == EMPTY_ELEMENT) { + if (!add_child_element (svg_render, open_elem, new_elem)) + goto fail; + + new_elem = NULL; + } else { + /* push new elem onto open elements stack */ + new_elem->next = open_elem; + open_elem = new_elem; + new_elem = NULL; + nesting++; + } + } + + if (nesting != 0) { + parse_error (svg_render, svg_document, p, "Missing closing tag for <%s>", open_elem->tag); + goto fail; + } + + svg_render->tree = open_elem; + return TRUE; + + fail: + if (new_elem) + free_elements (svg_render, new_elem); + + while (open_elem) { + cairo_svg_element_t *elem = open_elem; + open_elem = open_elem->next; + free_elements (svg_render, elem); + } + + return FALSE; +} + +static cairo_bool_t +parse_transform (const char *p, cairo_matrix_t *matrix) +{ + cairo_matrix_t m; + double x, y, a; + cairo_bool_t have_optional; + + cairo_matrix_init_identity (matrix); + while (p) { + while (p && (*p == ',' || _cairo_isspace (*p))) + p++; + + if (!p || *p == 0) + break; + + if (string_match (&p, "matrix")) { + p = skip_char (p, '('); + if (!p) + break; + + p = get_floats (p, 6, 0, NULL, &m.xx, &m.yx, &m.xy, &m.yy, &m.x0, &m.y0); + if (!p) + break; + + p = skip_char (p, ')'); + if (!p) + break; + + cairo_matrix_multiply (matrix, &m, matrix); + + } else if (string_match (&p, "translate")) { + p = skip_char (p, '('); + if (!p) + break; + + p = get_floats (p, 1, 1, &have_optional, &x, &y); + if (!p) + break; + + p = skip_char (p, ')'); + if (!p) + break; + + if (!have_optional) + y = 0; + + cairo_matrix_translate (matrix, x, y); + + } else if (string_match (&p, "scale")) { + p = skip_char (p, '('); + if (!p) + break; + + p = get_floats (p, 1, 1, &have_optional, &x, &y); + if (!p) + break; + + p = skip_char (p, ')'); + if (!p) + break; + + if (!have_optional) + y = x; + + cairo_matrix_scale (matrix, x, y); + + } else if (string_match (&p, "rotate")) { + p = skip_char (p, '('); + if (!p) + break; + + p = get_floats (p, 1, 2, &have_optional, &a, &x, &y); + if (!p) + break; + + p = skip_char (p, ')'); + if (!p) + break; + + if (!have_optional) { + x = 0; + y = 0; + } + + a *= M_PI/180.0; + cairo_matrix_translate (matrix, x, y); + cairo_matrix_rotate (matrix, a); + cairo_matrix_translate (matrix, -x, -y); + + } else if (string_match (&p, "skewX")) { + p = skip_char (p, '('); + if (!p) + break; + + p = get_floats (p, 1, 0, NULL, &a); + if (!p) + break; + + p = skip_char (p, ')'); + if (!p) + break; + + a *= M_PI/180.0; + cairo_matrix_init_identity (&m); + m.xy = tan (a); + cairo_matrix_multiply (matrix, &m, matrix); + + } else if (string_match (&p, "skewY")) { + p = skip_char (p, '('); + if (!p) + break; + + p = get_floats (p, 1, 0, NULL, &a); + if (!p) + break; + + p = skip_char (p, ')'); + if (!p) + break; + + a *= M_PI/180.0; + cairo_matrix_init_identity (&m); + m.yx = tan (a); + cairo_matrix_multiply (matrix, &m, matrix); + + } else { + break; + } + } + return p != NULL; +} + +static void +render_element_tree (cairo_svg_glyph_render_t *svg_render, + cairo_svg_element_t *element, + cairo_svg_element_t *display_element, + cairo_bool_t children_only); + +static cairo_pattern_t * +create_pattern (cairo_svg_glyph_render_t *svg_render, + cairo_svg_element_t *paint_server) +{ + cairo_pattern_t *pattern = NULL; + + if (paint_server) { + svg_render->build_pattern.paint_server = paint_server; + render_element_tree (svg_render, paint_server, NULL, FALSE); + pattern = svg_render->build_pattern.pattern; + svg_render->build_pattern.pattern = NULL; + svg_render->build_pattern.paint_server = NULL; + svg_render->build_pattern.type = BUILD_PATTERN_NONE; + } + + if (!pattern) + pattern = cairo_pattern_create_rgb (0, 0, 0); + + return pattern; +} + +static cairo_bool_t +render_element_svg (cairo_svg_glyph_render_t *svg_render, + cairo_svg_element_t *element, + cairo_bool_t end_tag) +{ + double width, height; + double vb_x, vb_y, vb_height, vb_width; + const char *p; + const char *end; + + if (end_tag) + return FALSE; + + /* Default viewport width, height is EM square */ + if (!get_float_or_percent_attribute (element, "width", svg_render->units_per_em, &width)) + width = svg_render->units_per_em; + + if (!get_float_or_percent_attribute (element, "height", svg_render->units_per_em, &height)) + height = svg_render->units_per_em; + + /* Transform viewport to unit square, centering it if width != height. */ + if (width > height) { + cairo_scale (svg_render->cr, 1.0/width, 1.0/width); + cairo_translate (svg_render->cr, 0, (width - height)/2.0); + } else { + cairo_scale (svg_render->cr, 1.0/height, 1.0/height); + cairo_translate (svg_render->cr, (height - width)/2.0, 0); + } + + svg_render->width = width; + svg_render->height = height; + + p = get_attribute (element, "viewBox"); + if (p) { + /* Transform viewport to viewbox */ + end = get_path_params (p, 4, &vb_x, &vb_y, &vb_width, &vb_height); + if (!end) { + print_warning (svg_render, "viewBox expected 4 numbers: %s", p); + return FALSE; + } + cairo_translate (svg_render->cr, -vb_x * width/vb_width, -vb_y * width/vb_width); + cairo_scale (svg_render->cr, width/vb_width, height/vb_height); + svg_render->width = vb_width; + svg_render->height = vb_height; + } + + svg_render->view_port_set = TRUE; + return TRUE; +} + +static cairo_bool_t +render_element_clip_path (cairo_svg_glyph_render_t *svg_render, + cairo_svg_element_t *element, + cairo_bool_t end_tag) +{ + cairo_svg_graphics_state_t *gs = svg_render->graphics_state; + const char *p; + + if (end_tag || gs->mode != GS_CLIP || svg_render->build_pattern.type != BUILD_PATTERN_NONE) { + return FALSE; + } + + p = get_attribute (element, "clipPathUnits"); + if (string_equal (p, "objectBoundingBox")) { + cairo_translate (svg_render->cr, + svg_render->graphics_state->bbox.x, + svg_render->graphics_state->bbox.y); + cairo_scale (svg_render->cr, + svg_render->graphics_state->bbox.width, + svg_render->graphics_state->bbox.height); + } + + return TRUE; +} + +static void +apply_gradient_attributes (cairo_svg_glyph_render_t *svg_render, + cairo_svg_element_t *element) +{ + cairo_pattern_t *pattern = svg_render->build_pattern.pattern; + cairo_bool_t object_bbox = TRUE; + cairo_matrix_t transform; + cairo_matrix_t mat; + const char *p; + + if (!pattern) + return; + + p = get_attribute (element, "gradientUnits"); + if (string_equal (p, "userSpaceOnUse")) + object_bbox = FALSE; + + cairo_matrix_init_identity (&mat); + if (object_bbox) { + cairo_matrix_translate (&mat, + svg_render->graphics_state->bbox.x, + svg_render->graphics_state->bbox.y); + cairo_matrix_scale (&mat, + svg_render->graphics_state->bbox.width, + svg_render->graphics_state->bbox.height); + } + + p = get_attribute (element, "gradientTransform"); + if (parse_transform (p, &transform)) + cairo_matrix_multiply (&mat, &transform, &mat); + + if (cairo_matrix_invert (&mat) == CAIRO_STATUS_SUCCESS) + cairo_pattern_set_matrix (pattern, &mat); + + p = get_attribute (element, "spreadMethod"); + if (string_equal (p, "reflect")) + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REFLECT); + else if (string_equal (p, "repeat")) + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT); +} + +static cairo_bool_t +render_element_linear_gradient (cairo_svg_glyph_render_t *svg_render, + cairo_svg_element_t *element, + cairo_bool_t end_tag) +{ + double x1, y1, x2, y2; + + if (svg_render->build_pattern.paint_server != element || + end_tag || + svg_render->build_pattern.type != BUILD_PATTERN_NONE) + return FALSE; + + /* FIXME default value for userSpaceOnUse? */ + double width = 1.0; + double height = 1.0; + + if (!get_float_or_percent_attribute (element, "x1", width, &x1)) + x1 = 0.0; + + if (!get_float_or_percent_attribute (element, "y1", height, &y1)) + y1 = 0.0; + + if (!get_float_or_percent_attribute (element, "x2", width, &x2)) + x2 = width; + + if (!get_float_or_percent_attribute (element, "y2", height, &y2)) + y2 = 0.0; + + if (svg_render->build_pattern.pattern) + abort(); + + svg_render->build_pattern.pattern = cairo_pattern_create_linear (x1, y1, x2, y2); + svg_render->build_pattern.type = BUILD_PATTERN_LINEAR; + apply_gradient_attributes (svg_render, element); + return TRUE; +} + +static cairo_bool_t +render_element_radial_gradient (cairo_svg_glyph_render_t *svg_render, + cairo_svg_element_t *element, + cairo_bool_t end_tag) +{ + double cx, cy, r, fx, fy; + + if (svg_render->build_pattern.paint_server != element || + end_tag || + svg_render->build_pattern.type != BUILD_PATTERN_NONE) + return FALSE; + + /* FIXME default value for userSpaceOnUse? */ + double width = 1.0; + double height = 1.0; + + if (!get_float_or_percent_attribute (element, "cx", width, &cx)) + cx = 0.5 * width; + + if (!get_float_or_percent_attribute (element, "cy", height, &cy)) + cy = 0.5 * height; + + if (!get_float_or_percent_attribute (element, "r", width, &r)) + r = 0.5 * width; + + if (!get_float_or_percent_attribute (element, "fx", width, &fx)) + fx = cx; + + if (!get_float_or_percent_attribute (element, "fy", height, &fy)) + fy = cy; + + svg_render->build_pattern.pattern = cairo_pattern_create_radial (fx, fy, 0, cx, cy, r); + svg_render->build_pattern.type = BUILD_PATTERN_RADIAL; + apply_gradient_attributes (svg_render, element); + return TRUE; +} + +static cairo_bool_t +render_element_stop (cairo_svg_glyph_render_t *svg_render, + cairo_svg_element_t *element, + cairo_bool_t end_tag) +{ + double offset, opacity; + cairo_pattern_t *pattern = svg_render->build_pattern.pattern; + + if (!pattern) + return FALSE; + + if (cairo_pattern_get_type (pattern) != CAIRO_PATTERN_TYPE_LINEAR && + cairo_pattern_get_type (pattern) != CAIRO_PATTERN_TYPE_RADIAL) + return FALSE; + + if (!get_float_or_percent_attribute (element, "offset", 1.0, &offset)) + return FALSE; + + if (!get_float_attribute (element, "stop-opacity", &opacity)) + opacity = 1.0; + + cairo_svg_color_t color; + get_color (svg_render, "black", &color); + get_color (svg_render, get_attribute(element, "stop-color"), &color); + if (color.type == RGB) { + cairo_pattern_add_color_stop_rgba (pattern, + offset, + color.red, + color.green, + color.blue, + opacity); + } else { /* color.type == FOREGROUND */ + double red, green, blue, alpha; + if (cairo_pattern_get_rgba (svg_render->foreground_source, &red, &green, &blue, &alpha) == CAIRO_STATUS_SUCCESS) { + svg_render->foreground_source_used = TRUE; + } else { + red = green = blue = 0; + alpha = 1; + } + cairo_pattern_add_color_stop_rgba (pattern, offset, red, green, blue, alpha); + } + return TRUE; +} + +static cairo_bool_t +render_element_g (cairo_svg_glyph_render_t *svg_render, + cairo_svg_element_t *element, + cairo_bool_t end_tag) +{ + if (svg_render->graphics_state->mode == GS_NO_RENDER || + svg_render->build_pattern.type != BUILD_PATTERN_NONE) + return FALSE; + + if (!end_tag) { + cairo_push_group (svg_render->cr); + } else { + cairo_pop_group_to_source (svg_render->cr); + cairo_paint_with_alpha (svg_render->cr, svg_render->graphics_state->opacity); + } + return TRUE; +} + +typedef struct { + const char *data; /* current position in base64 data */ + char buf[3]; /* decode buffer */ + int buf_pos; /* current position in buf_pos. */ +} base64_decode_t; + +static cairo_status_t +_read_png_from_base64 (void *closure, unsigned char *data, unsigned int length) +{ + base64_decode_t *decode = closure; + int n, c; + unsigned val; + + while (length) { + if (decode->buf_pos >= 0) { + *data++ = decode->buf[decode->buf_pos++]; + length--; + if (decode->buf_pos == 3) + decode->buf_pos = -1; + } + if (length > 0 && decode->buf_pos < 0) { + n = 0; + val = 0; + while (*decode->data && n < 4) { + c = *decode->data++; + if (c >='A' && c <='Z') { + val = (val << 6) | (c -'A'); + n++; + } else if (c >='a' && c <='z') { + val = (val << 6) | (c -'a' + 26); + n++; + } else if (c >='0' && c <='9') { + val = (val << 6) | (c -'0' + 52); + n++; + } else if (c =='+') { + val = (val << 6) | 62; + n++; + } else if (c =='/') { + val = (val << 6) | 63; + n++; + } else if (c == '=') { + val = (val << 6); + n++; + } + } + if (n < 4) + return CAIRO_STATUS_READ_ERROR; + + decode->buf[0] = val >> 16; + decode->buf[1] = val >> 8; + decode->buf[2] = val >> 0; + decode->buf_pos = 0; + } + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_bool_t +render_element_image (cairo_svg_glyph_render_t *svg_render, + cairo_svg_element_t *element, + cairo_bool_t end_tag) +{ + double x, y, width, height; + int w, h; + const char *data; + cairo_surface_t *surface; + base64_decode_t decode; + + if (svg_render->graphics_state->mode == GS_NO_RENDER || + svg_render->build_pattern.type != BUILD_PATTERN_NONE) + return FALSE; + + if (!get_float_attribute (element, "x", &x)) + x = 0; + + if (!get_float_attribute (element, "y", &y)) + y = 0; + + if (!get_float_attribute (element, "width", &width)) + return FALSE; + + if (!get_float_attribute (element, "height", &height)) + return FALSE; + + data = get_href_attribute (element); + if (!data) + return FALSE; + + if (!string_match (&data, "data:image/png;base64,")) + return FALSE; + + decode.data = data; + decode.buf_pos = -1; + surface = cairo_image_surface_create_from_png_stream (_read_png_from_base64, &decode); + if (cairo_surface_status (surface)) { + print_warning (svg_render, "Unable to decode PNG"); + cairo_surface_destroy (surface); + return FALSE; + } + + w = cairo_image_surface_get_width (surface); + h = cairo_image_surface_get_height (surface); + + if (w > 0 && h > 0) { + cairo_translate (svg_render->cr, x, y); + cairo_scale (svg_render->cr, width/w, height/h); + cairo_set_source_surface (svg_render->cr, surface, 0, 0); + cairo_paint (svg_render->cr); + } + + cairo_surface_destroy (surface); + + return FALSE; +} + +static cairo_bool_t +render_element_use (cairo_svg_glyph_render_t *svg_render, + cairo_svg_element_t *element, + cairo_bool_t end_tag) +{ + double x = 0; + double y = 0; + const char *id; + + if (end_tag || svg_render->graphics_state->mode == GS_NO_RENDER || + svg_render->build_pattern.type != BUILD_PATTERN_NONE) + return FALSE; + + get_float_attribute (element, "x", &x); + get_float_attribute (element, "y", &y); + + id = get_href_attribute (element); + if (!id) + return FALSE; + + cairo_svg_element_t *use_element = lookup_element (svg_render, id); + cairo_translate (svg_render->cr, x, y); + render_element_tree (svg_render, use_element, NULL, FALSE); + return TRUE; +} + +static cairo_bool_t +draw_path (cairo_svg_glyph_render_t *svg_render) +{ + cairo_svg_graphics_state_t *gs = svg_render->graphics_state; + cairo_pattern_t *pattern; + cairo_bool_t opacity_group = FALSE; + + if (gs->mode == GS_COMPUTE_BBOX) { + cairo_set_source_rgb (svg_render->cr, 0, 0, 0); + cairo_set_fill_rule (svg_render->cr, gs->fill_rule); + cairo_fill (svg_render->cr); + return FALSE; + } else if (gs->mode == GS_CLIP) { + return FALSE; + } + + if (gs->opacity < 1.0) { + cairo_push_group (svg_render->cr); + opacity_group = TRUE; + } + + cairo_path_t *path = cairo_copy_path (svg_render->cr); + cairo_new_path (svg_render->cr); + + if (gs->fill.type != PAINT_NONE) { + cairo_bool_t group = FALSE; + if (gs->fill.type == PAINT_COLOR) { + if (gs->fill.color.type == RGB) { + cairo_set_source_rgba (svg_render->cr, + gs->fill.color.red, + gs->fill.color.green, + gs->fill.color.blue, + gs->fill_opacity); + } else if (gs->fill.color.type == FOREGROUND) { + cairo_set_source (svg_render->cr, svg_render->foreground_marker); + if (gs->fill_opacity < 1.0) + group = TRUE; + } + } else if (gs->fill.type == PAINT_SERVER) { + pattern = create_pattern (svg_render, gs->fill.paint_server); + cairo_set_source (svg_render->cr, pattern); + cairo_pattern_destroy (pattern); + if (gs->fill_opacity < 1.0) + group = TRUE; + } + + if (group) + cairo_push_group (svg_render->cr); + + cairo_append_path (svg_render->cr, path); + cairo_set_fill_rule (svg_render->cr, gs->fill_rule); + cairo_fill (svg_render->cr); + if (group) { + cairo_pop_group_to_source (svg_render->cr); + cairo_paint_with_alpha (svg_render->cr, gs->fill_opacity); + } + } + + if (gs->stroke.type != PAINT_NONE) { + cairo_bool_t group = FALSE; + if (gs->stroke.type == PAINT_COLOR) { + if (gs->stroke.color.type == RGB) { + cairo_set_source_rgba (svg_render->cr, + gs->stroke.color.red, + gs->stroke.color.green, + gs->stroke.color.blue, + gs->stroke_opacity); + } else if (gs->fill.color.type == FOREGROUND) { + cairo_set_source (svg_render->cr, svg_render->foreground_marker); + if (gs->fill_opacity < 1.0) + group = TRUE; + } + } else if (gs->stroke.type == PAINT_SERVER) { + pattern = create_pattern (svg_render, gs->stroke.paint_server); + cairo_set_source (svg_render->cr, pattern); + cairo_pattern_destroy (pattern); + if (gs->stroke_opacity < 1.0) + group = TRUE; + } + + if (group) + cairo_push_group (svg_render->cr); + + cairo_append_path (svg_render->cr, path); + cairo_stroke (svg_render->cr); + + if (group) { + cairo_pop_group_to_source (svg_render->cr); + cairo_paint_with_alpha (svg_render->cr, gs->stroke_opacity); + } + } + + cairo_path_destroy (path); + + if (opacity_group) { + cairo_pop_group_to_source (svg_render->cr); + cairo_paint_with_alpha (svg_render->cr, gs->opacity); + } + return TRUE; +} + +static void +elliptical_arc (cairo_svg_glyph_render_t *svg_render, + double cx, + double cy, + double rx, + double ry, + double angle1, + double angle2) +{ + cairo_save (svg_render->cr); + cairo_translate (svg_render->cr, cx, cy); + cairo_scale (svg_render->cr, rx, ry); + cairo_arc (svg_render->cr, 0, 0, 1, angle1, angle2); + cairo_restore (svg_render->cr); +} + +static cairo_bool_t +render_element_rect (cairo_svg_glyph_render_t *svg_render, + cairo_svg_element_t *element, + cairo_bool_t end_tag) +{ + double x = 0; + double y = 0; + double width = svg_render->width; + double height = svg_render->height; + double rx = 0; + double ry = 0; + + if (end_tag || + svg_render->graphics_state->mode == GS_NO_RENDER || + svg_render->build_pattern.type != BUILD_PATTERN_NONE) + return FALSE; + + get_float_or_percent_attribute (element, "x", svg_render->width, &x); + get_float_or_percent_attribute (element, "y", svg_render->height, &y); + get_float_or_percent_attribute (element, "width", svg_render->width, &width); + get_float_or_percent_attribute (element, "height", svg_render->height, &height); + get_float_or_percent_attribute (element, "rx", svg_render->width, &rx); + get_float_or_percent_attribute (element, "ry", svg_render->height, &ry); + + if (rx == 0 && ry == 0) { + cairo_rectangle (svg_render->cr, x, y, width, height); + } else { + cairo_move_to (svg_render->cr, x + rx, y); + cairo_line_to (svg_render->cr, x + width - rx, y); + elliptical_arc (svg_render, x + width - rx, y + ry, rx, ry, -M_PI/2, 0); + cairo_line_to (svg_render->cr, x + width, y + height - ry); + elliptical_arc (svg_render, x + width - rx, y + height - ry, rx, ry, 0, M_PI/2); + cairo_line_to (svg_render->cr, x + rx, y + height); + elliptical_arc (svg_render, x + rx, y + height - ry, rx, ry, M_PI/2, M_PI); + cairo_line_to (svg_render->cr, x, y + ry); + elliptical_arc (svg_render, x + rx, y + ry, rx, ry, M_PI, -M_PI/2); + } + + draw_path (svg_render); + return TRUE; +} + +static cairo_bool_t +render_element_circle (cairo_svg_glyph_render_t *svg_render, + cairo_svg_element_t *element, + cairo_bool_t end_tag) +{ + double cx = 0; + double cy = 0; + double r = 0; + + if (end_tag || + svg_render->graphics_state->mode == GS_NO_RENDER || + svg_render->build_pattern.type != BUILD_PATTERN_NONE) + return FALSE; + + get_float_or_percent_attribute (element, "cx", svg_render->width, &cx); + get_float_or_percent_attribute (element, "cy", svg_render->height, &cy); + get_float_or_percent_attribute (element, "r", svg_render->width, &r); + + cairo_arc (svg_render->cr, cx, cy, r, 0, 2*M_PI); + + draw_path (svg_render); + return TRUE; +} + +static cairo_bool_t +render_element_ellipse (cairo_svg_glyph_render_t *svg_render, + cairo_svg_element_t *element, + cairo_bool_t end_tag) +{ + double cx = 0; + double cy = 0; + double rx = 0; + double ry = 0; + + if (end_tag || + svg_render->graphics_state->mode == GS_NO_RENDER || + svg_render->build_pattern.type != BUILD_PATTERN_NONE) + return FALSE; + + get_float_or_percent_attribute (element, "cx", svg_render->width, &cx); + get_float_or_percent_attribute (element, "cy", svg_render->height, &cy); + get_float_or_percent_attribute (element, "rx", svg_render->width, &rx); + get_float_or_percent_attribute (element, "ry", svg_render->height, &ry); + + elliptical_arc (svg_render, cx, cy, rx, ry, 0, 2*M_PI); + draw_path (svg_render); + return TRUE; +} + +static cairo_bool_t +render_element_line (cairo_svg_glyph_render_t *svg_render, + cairo_svg_element_t *element, + cairo_bool_t end_tag) +{ + double x1 = 0; + double y1 = 0; + double x2 = 0; + double y2 = 0; + + if (end_tag || + svg_render->graphics_state->mode == GS_NO_RENDER || + svg_render->build_pattern.type != BUILD_PATTERN_NONE) + return FALSE; + + get_float_or_percent_attribute (element, "x1", svg_render->width, &x1); + get_float_or_percent_attribute (element, "y1", svg_render->height, &y1); + get_float_or_percent_attribute (element, "x2", svg_render->width, &x2); + get_float_or_percent_attribute (element, "y2", svg_render->height, &y2); + + cairo_move_to (svg_render->cr, x1, y1); + cairo_line_to (svg_render->cr, x2, y2); + + draw_path (svg_render); + return TRUE; +} + +static cairo_bool_t +render_element_polyline (cairo_svg_glyph_render_t *svg_render, + cairo_svg_element_t *element, + cairo_bool_t end_tag) +{ + const char *p; + const char *end; + double x, y; + cairo_bool_t have_move = FALSE; + + if (end_tag || + svg_render->graphics_state->mode == GS_NO_RENDER || + svg_render->build_pattern.type != BUILD_PATTERN_NONE) + return FALSE; + + p = get_attribute (element, "points"); + do { + end = get_path_params (p, 2, &x, &y); + if (!end) { + print_warning (svg_render, "points expected 2 numbers: %s", p); + break; + } + p = end; + if (!have_move) { + cairo_move_to (svg_render->cr, x, y); + have_move = TRUE; + } else { + cairo_line_to (svg_render->cr, x, y); + } + p = skip_space (p); + } while (p && *p); + + if (string_equal (element->tag, "polygon")) + cairo_close_path (svg_render->cr); + + draw_path (svg_render); + return TRUE; +} + +static double +angle_between_vectors (double ux, + double uy, + double vx, + double vy) +{ + double dot = ux*vx + uy*vy; + double umag = sqrt (ux*ux + uy*uy); + double vmag = sqrt (vx*vx + vy*vy); + double c = dot/(umag*vmag); + if (c > 1.0) + c = 1.0; + + if (c < -1.0) + c = -1.0; + + double a = acos (c); + if (ux * vy - uy * vx < 0.0) + a = -a; + + return a; +} + +static void +arc_path (cairo_t *cr, + double x1, double y1, + double x2, double y2, + double rx, double ry, + double rotate, + cairo_bool_t large_flag, + cairo_bool_t sweep_flag) +{ + double x1_, y1_, cx_, cy_; + double xm, ym, cx, cy; + double a, b, d; + double ux, uy, vx, vy; + double theta, delta_theta; + double epsilon; + cairo_matrix_t ctm; + + cairo_get_matrix (cr, &ctm); + epsilon = _cairo_matrix_transformed_circle_major_axis (&ctm, cairo_get_tolerance (cr)); + + rotate *= M_PI/180.0; + + /* Convert endpoint to center parameterization. + * See SVG 1.1 Appendix F.6. Step numbers are the steps in the appendix. + */ + + rx = fabs (rx); + ry = fabs (ry); + if (rx < epsilon || ry < epsilon) { + cairo_line_to (cr, x2, y2); + return; + } + + if (fabs(x1 - x2) < epsilon && fabs(y1 - y2) < epsilon) { + cairo_line_to (cr, x2, y2); + return; + } + + /* Step 1 */ + xm = (x1 - x2)/2; + ym = (y1 - y2)/2; + x1_ = xm * cos (rotate) + ym * sin (rotate); + y1_ = xm * -sin (rotate) + ym * cos (rotate); + + d = (x1_*x1_)/(rx*rx) + (y1_*y1_)/(ry*ry); + if (d > 1.0) { + d = sqrt (d); + rx *= d; + ry *= d; + } + + /* Step 2 */ + a = (rx*rx * y1_*y1_) + (ry*ry * x1_*x1_); + if (a == 0.0) + return; + + b = (rx*rx * ry*ry) / a - 1.0; + if (b < 0) + b = 0.0; + + d = sqrt(b); + if (large_flag == sweep_flag) + d = -d; + + cx_ = d * rx*y1_/ry; + cy_ = d * -ry*x1_/rx; + + /* Step 3 */ + cx = cx_ * cos (rotate) - cy_ * sin (rotate) + (x1 + x2)/2; + cy = cx_ * sin (rotate) + cy_ * cos (rotate) + (y1 + y2)/2; + + /* Step 4 */ + ux = (x1_ - cx_)/rx; + uy = (y1_ - cy_)/ry; + vx = (-x1_ - cx_)/rx; + vy = (-y1_ - cy_)/ry; + theta = angle_between_vectors (1.0, 0, ux, uy); + delta_theta = angle_between_vectors (ux, uy, vx, vy); + + if (!sweep_flag && delta_theta > 0) + delta_theta -= 2 * M_PI; + else if (sweep_flag && delta_theta < 0) + delta_theta += 2 * M_PI; + + /* Now we can call cairo_arc() */ + cairo_save (cr); + cairo_translate (cr, cx, cy); + cairo_scale (cr, rx, ry); + cairo_rotate (cr, theta); + if (delta_theta >= 0.0) + cairo_arc (cr, 0, 0, 1, 0, delta_theta); + else + cairo_arc_negative (cr, 0, 0, 1, 0, delta_theta); + cairo_restore (cr); +} + +static void +get_current_point (cairo_svg_glyph_render_t *svg_render, double *x, double *y) +{ + if (cairo_has_current_point (svg_render->cr)) { + cairo_get_current_point (svg_render->cr, x, y); + } else { + *x = 0; + *y = 0; + } +} + +static void +reflect_point (double origin_x, double origin_y, double *x, double *y) +{ + *x = 2*origin_x - *x; + *y = 2*origin_y - *y; +} + +static cairo_bool_t +render_element_path (cairo_svg_glyph_render_t *svg_render, + cairo_svg_element_t *element, + cairo_bool_t end_tag) +{ + double cur_x, cur_y; + double last_cp_x, last_cp_y; + double x, y, x1, y1, x2, y2; + double qx1, qy1, qx2, qy2; + double rx, ry, rotate, large_flag, sweep_flag; + cairo_bool_t rel, have_move; + enum { CUBIC, QUADRATIC, OTHER } last_op; + + if (end_tag || + svg_render->graphics_state->mode == GS_NO_RENDER || + svg_render->build_pattern.type != BUILD_PATTERN_NONE) + return FALSE; + + last_op = OTHER; + const char *p = get_attribute (element, "d"); + const char *end; + int op; + + while (p) { + while (p && _cairo_isspace (*p)) + p++; + + if (!p || *p == 0) + break; + + op = *p; + switch (op) { + case 'M': + case 'm': + rel = op == 'm'; + p++; + have_move = FALSE; + do { + end = get_path_params (p, 2, &x, &y); + if (!end) { + print_warning (svg_render, "path %c expected 2 numbers: %s", op, p); + break; + } + p = end; + if (rel) { + get_current_point (svg_render, &cur_x, &cur_y); + x += cur_x; + y += cur_y; + } + if (!have_move) { + cairo_move_to (svg_render->cr, x, y); + have_move = TRUE; + } else { + cairo_line_to (svg_render->cr, x, y); + } + p = skip_space (p); + } while (p && *p && !_cairo_isalpha(*p)); + last_op = OTHER; + break; + case 'Z': + case 'z': + p++; + cairo_close_path (svg_render->cr); + last_op = OTHER; + break; + case 'L': + case 'l': + rel = op == 'l'; + p++; + do { + end = get_path_params (p, 2, &x, &y); + if (!end) { + print_warning (svg_render, "path %c expected 2 numbers: %s", op, p); + break; + } + p = end; + if (rel) { + get_current_point (svg_render, &cur_x, &cur_y); + x += cur_x; + y += cur_y; + } + cairo_line_to (svg_render->cr, x, y); + p = skip_space (p); + } while (p && *p && !_cairo_isalpha(*p)); + last_op = OTHER; + break; + case 'H': + case 'h': + rel = op == 'h'; + p++; + do { + end = get_path_params (p, 1, &x1); + if (!end) { + print_warning (svg_render, "path %c expected a number: %s", op, p); + break; + } + p = end; + get_current_point (svg_render, &cur_x, &cur_y); + if (rel) { + x1 += cur_x; + } + cairo_line_to (svg_render->cr, x1, cur_y); + p = skip_space (p); + } while (p && *p && !_cairo_isalpha(*p)); + last_op = OTHER; + break; + case 'V': + case 'v': + rel = op == 'v'; + p++; + do { + end = get_path_params (p, 1, &y1); + if (!end) { + print_warning (svg_render, "path %c expected a number: %s", op, p); + break; + } + p = end; + get_current_point (svg_render, &cur_x, &cur_y); + if (rel) { + y1 += cur_y; + } + cairo_line_to (svg_render->cr, cur_x, y1); + p = skip_space (p); + } while (p && *p && !_cairo_isalpha(*p)); + last_op = OTHER; + break; + case 'C': + case 'c': + rel = op == 'c'; + p++; + do { + end = get_path_params (p, 6, &x1, &y1, &x2, &y2, &x, &y); + if (!end) { + print_warning (svg_render, "path %c expected 6 numbers: %s", op, p); + break; + } + p = end; + if (rel) { + get_current_point (svg_render, &cur_x, &cur_y); + x1 += cur_x; + y1 += cur_y; + x2 += cur_x; + y2 += cur_y; + x += cur_x; + y += cur_y; + } + cairo_curve_to (svg_render->cr, x1, y1, x2, y2, x, y); + p = skip_space (p); + } while (p && *p && !_cairo_isalpha(*p)); + last_op = CUBIC; + last_cp_x = x2; + last_cp_y = y2; + break; + case 'S': + case 's': + rel = op == 's'; + p++; + do { + end = get_path_params (p, 4, &x2, &y2, &x, &y); + if (!end) { + print_warning (svg_render, "path %c expected 4 numbers: %s", op, p); + break; + } + p = end; + get_current_point (svg_render, &cur_x, &cur_y); + if (rel) { + x2 += cur_x; + y2 += cur_y; + x += cur_x; + y += cur_y; + } + if (last_op == CUBIC) { + x1 = last_cp_x; + y1 = last_cp_y; + reflect_point (cur_x, cur_y, &x1, &y1); + } else { + x1 = cur_x; + y1 = cur_y; + } + cairo_curve_to (svg_render->cr, x1, y1, x2, y2, x, y); + last_op = CUBIC; + last_cp_x = x2; + last_cp_y = y2; + p = skip_space (p); + } while (p && *p && !_cairo_isalpha(*p)); + break; + case 'Q': + case 'q': + rel = op == 'q'; + p++; + do { + end = get_path_params (p, 4, &x1, &y1, &x, &y); + if (!end) { + print_warning (svg_render, "path %c expected 4 numbers: %s", op, p); + break; + } + p = end; + get_current_point (svg_render, &cur_x, &cur_y); + if (rel) { + x1 += cur_x; + y1 += cur_y; + x += cur_x; + y += cur_y; + } + qx1 = cur_x + (x1 - cur_x)*2/3; + qy1 = cur_y + (y1 - cur_y)*2/3; + qx2 = x + (x1 - x)*2/3; + qy2 = y + (y1 - y)*2/3; + cairo_curve_to (svg_render->cr, qx1, qy1, qx2, qy2, x, y); + p = skip_space (p); + } while (p && *p && !_cairo_isalpha(*p)); + last_op = QUADRATIC; + last_cp_x = x1; + last_cp_y = y1; + break; + case 'T': + case 't': + rel = op == 't'; + p++; + do { + end = get_path_params (p, 2, &x, &y); + if (!end) { + print_warning (svg_render, "path %c expected 2 numbers: %s", op, p); + break; + } + p = end; + get_current_point (svg_render, &cur_x, &cur_y); + if (rel) { + x += cur_x; + y += cur_y; + } + if (last_op == QUADRATIC) { + x1 = last_cp_x; + y1 = last_cp_y; + reflect_point (cur_x, cur_y, &x1, &y1); + } else { + x1 = cur_x; + y1 = cur_y; + } + qx1 = cur_x + (x1 - cur_x)*2/3; + qy1 = cur_y + (y1 - cur_y)*2/3; + qx2 = x + (x1 - x)*2/3; + qy2 = y + (y1 - y)*2/3; + cairo_curve_to (svg_render->cr, qx1, qy1, qx2, qy2, x, y); + last_op = QUADRATIC; + last_cp_x = x1; + last_cp_y = y1; + p = skip_space (p); + } while (p && *p && *p && !_cairo_isalpha(*p)); + break; + case 'A': + case 'a': + rel = op == 'a'; + p++; + do { + end = get_path_params (p, 7, &rx, &ry, &rotate, &large_flag, &sweep_flag, &x, &y); + if (!end) { + print_warning (svg_render, "path %c expected 7 numbers: %s", op, p); + break; + } + p = end; + get_current_point (svg_render, &cur_x, &cur_y); + if (rel) { + x += cur_x; + y += cur_y; + } + arc_path (svg_render->cr, + cur_x, cur_y, + x, y, + rx, ry, + rotate, + large_flag > 0.5, + sweep_flag > 0.5); + p = skip_space (p); + } while (p && *p && !_cairo_isalpha(*p)); + last_op = OTHER; + break; + default: + p = NULL; + break; + } + } + + draw_path (svg_render); + return TRUE; +} + +static void +init_graphics_state (cairo_svg_glyph_render_t *svg_render) +{ + cairo_svg_graphics_state_t *gs; + + gs = _cairo_calloc (sizeof (cairo_svg_graphics_state_t)); + get_paint (svg_render, "black", &gs->fill); + get_paint (svg_render, "none", &gs->stroke); + gs->color.type = FOREGROUND; + gs->fill_opacity = 1.0; + gs->stroke_opacity = 1.0; + gs->opacity = 1.0; + gs->fill_rule = CAIRO_FILL_RULE_WINDING; + gs->clip_rule = CAIRO_FILL_RULE_WINDING; + gs->clip_path = NULL; + gs->dash_array = NULL; + gs->dash_offset = 0.0; + gs->mode = GS_RENDER; + gs->bbox.x = 0; + gs->bbox.y = 0; + gs->bbox.width = 0; + gs->bbox.height = 0; + gs->next = NULL; + + svg_render->graphics_state = gs; + + cairo_save (svg_render->cr); + cairo_set_source_rgb (svg_render->cr, 0, 0, 0); + cairo_set_line_width (svg_render->cr, 1.0); + cairo_set_line_cap (svg_render->cr, CAIRO_LINE_CAP_BUTT); + cairo_set_line_join (svg_render->cr, CAIRO_LINE_JOIN_MITER); + cairo_set_miter_limit (svg_render->cr, 4.0); +} + +#define MAX_DASHES 100 +static void update_dash (cairo_svg_glyph_render_t *svg_render, + cairo_svg_element_t *element) +{ + cairo_svg_graphics_state_t *gs = svg_render->graphics_state; + const char *p; + char *end; + double value; + double dash_array[MAX_DASHES]; + int num_dashes = 0; + cairo_bool_t not_zero = FALSE; + + if (gs->dash_array == NULL || string_equal (gs->dash_array, "none")) { + cairo_set_dash (svg_render->cr, NULL, 0, 0); + return; + } + + p = gs->dash_array; + while (*p && num_dashes < MAX_DASHES) { + while (*p && (*p == ',' || _cairo_isspace (*p))) + p++; + + if (*p == 0) + break; + + value = _cairo_strtod (p, &end); + if (end == p) + break; + + p = end; + if (*p == '%') { + value *= svg_render->width / 100.0; + p++; + } + + if (value < 0.0) + return; + + if (value > 0.0) + not_zero = TRUE; + + dash_array[num_dashes++] = value; + } + + if (not_zero) + cairo_set_dash (svg_render->cr, dash_array, num_dashes, gs->dash_offset); +} + +static cairo_bool_t +pattern_requires_bbox (cairo_svg_glyph_render_t *svg_render, + cairo_svg_element_t *paint_server) +{ + const char *p; + + if (string_equal (paint_server->tag, "linearGradient") || + string_equal (paint_server->tag, "radialGradient")) + { + p = get_attribute (paint_server, "gradientUnits"); + if (string_equal (p, "userSpaceOnUse")) + return FALSE; + + return TRUE; + } + return FALSE; +} + +static cairo_bool_t +clip_requires_bbox (cairo_svg_glyph_render_t *svg_render, + const char *clip_path) +{ + cairo_svg_element_t *element; + const char *p; + + if (clip_path && strncmp (clip_path, "url", 3) == 0) { + element = lookup_url_element (svg_render, clip_path); + if (element) { + p = get_attribute (element, "clipPathUnits"); + if (string_equal (p, "objectBoundingBox")) + return TRUE; + } + } + return FALSE; +} + +static cairo_bool_t +need_bbox (cairo_svg_glyph_render_t *svg_render, + cairo_svg_element_t *element) +{ + cairo_svg_graphics_state_t *gs = svg_render->graphics_state; + cairo_bool_t fill_needs_bbox = FALSE; + cairo_bool_t stroke_needs_bbox = FALSE; + cairo_bool_t clip_needs_bbox = FALSE; + + if (gs->mode != GS_RENDER) + return FALSE; + + if (gs->fill.type == PAINT_SERVER && pattern_requires_bbox (svg_render, gs->fill.paint_server)) + fill_needs_bbox = TRUE; + + if (gs->stroke.type == PAINT_SERVER && pattern_requires_bbox (svg_render, gs->stroke.paint_server)) + stroke_needs_bbox = TRUE; + + if (clip_requires_bbox (svg_render, get_attribute (element, "clip-path"))) + clip_needs_bbox = TRUE; + + if (string_equal (element->tag, "circle") || + string_equal (element->tag, "ellipse") || + string_equal (element->tag, "path") || + string_equal (element->tag, "polygon") || + string_equal (element->tag, "rect")) + { + return fill_needs_bbox || stroke_needs_bbox || clip_needs_bbox; + } + + if (string_equal (element->tag, "line") || + string_equal (element->tag, "polyline")) + { + return stroke_needs_bbox || clip_needs_bbox; + } + + if (string_equal (element->tag, "g") || + string_equal (element->tag, "image") || + string_equal (element->tag, "use")) + { + return clip_needs_bbox; + } + + return FALSE; +} + +static cairo_bool_t +call_element (cairo_svg_glyph_render_t *svg_render, + cairo_svg_element_t *element, + cairo_bool_t end_tag); + +static void +update_graphics_state (cairo_svg_glyph_render_t *svg_render, + cairo_svg_element_t *element) +{ + double value; + const char *p; + cairo_svg_graphics_state_t *gs = svg_render->graphics_state; + + p = get_attribute (element, "transform"); + if (p) { + cairo_matrix_t m; + if (parse_transform (p, &m)) + cairo_transform (svg_render->cr, &m); + } + + /* The transform is all we need for bbox computation. The SVG spec + * excludes clipping and stroke-width from the bbox. */ + if (gs->mode == GS_COMPUTE_BBOX) + return; + + p = get_attribute (element, "color"); + if (p) + get_color (svg_render, p, &gs->color); + + if (!get_float_attribute (element, "opacity", &gs->opacity)) + gs->opacity = 1.0; + + p = get_attribute (element, "fill"); + if (p) { + get_paint (svg_render, p, &gs->fill); + } + + get_float_attribute (element, "fill-opacity", &gs->fill_opacity); + + gs->fill_rule = get_fill_rule_attribute (element, "fill-rule", gs->fill_rule); + + gs->clip_rule = get_fill_rule_attribute (element, "fill-rule", gs->clip_rule); + + p = get_attribute (element, "stroke"); + if (p) + get_paint (svg_render, p, &gs->stroke); + + if (get_float_or_percent_attribute (element, "stroke-width", svg_render->width, &value)) + cairo_set_line_width (svg_render->cr, value); + + p = get_attribute (element, "stroke-linecap"); + if (string_equal (p, "butt")) + cairo_set_line_cap (svg_render->cr, CAIRO_LINE_CAP_BUTT); + else if (string_equal (p, "round")) + cairo_set_line_cap (svg_render->cr, CAIRO_LINE_CAP_ROUND); + else if (string_equal (p, "square")) + cairo_set_line_cap (svg_render->cr, CAIRO_LINE_CAP_SQUARE); + + p = get_attribute (element, "stroke-linejoin"); + if (string_equal (p, "miter")) + cairo_set_line_join (svg_render->cr, CAIRO_LINE_JOIN_MITER); + else if (string_equal (p, "round")) + cairo_set_line_join (svg_render->cr, CAIRO_LINE_JOIN_ROUND); + else if (string_equal (p, "bevel")) + cairo_set_line_join (svg_render->cr, CAIRO_LINE_JOIN_BEVEL); + + if (get_float_attribute (element, "stroke-miterlimit", &value)) + cairo_set_miter_limit (svg_render->cr, value); + + p = get_attribute (element, "stroke-dasharray"); + if (p) { + free (gs->dash_array); + gs->dash_array = strdup (p); + } + + get_float_or_percent_attribute (element, "stroke-dashoffset", svg_render->width, &gs->dash_offset); + update_dash (svg_render, element); + + /* Some elements may need the bounding box of the element thay are + * applied to. As this recursively calls render_element on the + * same element while we are in render_element and setting up the + * graphics state, we check gs->mode to avoid re-entering the + * compute bbox code. The GS_COMPUTE_MODE flag is also used by + * render functions to ignore patterns and strokes (SVG spec + * ignores stroke with in bbox calculations) and just use a solid + * color. + */ + if (gs->mode == GS_RENDER && need_bbox (svg_render, element)) { + cairo_surface_t *recording = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL); + cairo_t *old_cr = svg_render->cr; + svg_render->cr = cairo_create (recording); + gs_mode_t old_mode = gs->mode; + gs->mode = GS_COMPUTE_BBOX; + /* To avoid recursing back into this function, we call the + * element directory then use render_element_tree to render + * the children */ + call_element (svg_render, element, FALSE); + render_element_tree (svg_render, element, NULL, TRUE); + if (element->type == CONTAINER_ELEMENT) + call_element (svg_render, element, TRUE); + gs->mode = old_mode; + cairo_destroy (svg_render->cr); + svg_render->cr = old_cr; + cairo_recording_surface_ink_extents (recording, + &gs->bbox.x, + &gs->bbox.y, + &gs->bbox.width, + &gs->bbox.height); + cairo_surface_destroy (recording); + } + + /* clip-path may require bbox */ + p = get_attribute (element, "clip-path"); + if (p && strncmp (p, "url", 3) == 0) { + element = lookup_url_element (svg_render, p); + if (element) { + gs_mode_t old_mode = gs->mode; + gs->mode = GS_CLIP; + render_element_tree (svg_render, element, NULL, FALSE); + cairo_set_fill_rule (svg_render->cr, gs->clip_rule); + cairo_clip (svg_render->cr); + gs->mode = old_mode; + } + } +} + +static void +save_graphics_state (cairo_svg_glyph_render_t *svg_render) +{ + cairo_svg_graphics_state_t *gs; + + cairo_save (svg_render->cr); + + gs = _cairo_calloc (sizeof (cairo_svg_graphics_state_t)); + gs->fill = svg_render->graphics_state->fill; + gs->stroke = svg_render->graphics_state->stroke; + gs->color = svg_render->graphics_state->color; + gs->fill_opacity = svg_render->graphics_state->fill_opacity; + gs->stroke_opacity = svg_render->graphics_state->stroke_opacity; + gs->opacity = svg_render->graphics_state->opacity; + gs->fill_rule = svg_render->graphics_state->fill_rule; + gs->clip_rule = svg_render->graphics_state->clip_rule; + gs->clip_path = NULL; + gs->dash_array = NULL; + if (svg_render->graphics_state->dash_array) + gs->dash_array = strdup (svg_render->graphics_state->dash_array); + gs->dash_offset = svg_render->graphics_state->dash_offset; + gs->mode = svg_render->graphics_state->mode; + gs->bbox = svg_render->graphics_state->bbox; + gs->next = svg_render->graphics_state; + svg_render->graphics_state = gs; +} + +static void +restore_graphics_state (cairo_svg_glyph_render_t *svg_render) +{ + cairo_svg_graphics_state_t *gs; + + gs = svg_render->graphics_state; + svg_render->graphics_state = gs->next; + if (gs->clip_path) + cairo_path_destroy (gs->clip_path); + free (gs->dash_array); + free (gs); + + cairo_restore (svg_render->cr); +} + +/* render function returns TRUE if render_element_tree() is to render + * the child nodes, FALSE if render_element_tree() is to skip the + * child nodes. + */ +struct render_func { + const char *tag; + cairo_bool_t (*render) (cairo_svg_glyph_render_t *, cairo_svg_element_t *, cairo_bool_t); +}; + +/* Must be sorted */ +static const struct render_func render_funcs[] = { + { "circle", render_element_circle }, + { "clipPath", render_element_clip_path }, + { "defs", NULL }, + { "desc", NULL }, + { "ellipse", render_element_ellipse }, + { "g", render_element_g }, + { "image", render_element_image }, + { "line", render_element_line }, + { "linearGradient", render_element_linear_gradient }, + { "metadata", NULL }, + { "path", render_element_path }, + { "polygon", render_element_polyline }, + { "polyline", render_element_polyline }, + { "radialGradient", render_element_radial_gradient }, + { "rect", render_element_rect }, + { "stop", render_element_stop }, + { "svg", render_element_svg }, + { "title", NULL }, + { "use", render_element_use }, +}; + +static int +_render_func_compare (const void *a, const void *b) +{ + const struct render_func *render_func_a = a; + const struct render_func *render_func_b = b; + + return strcmp (render_func_a->tag, render_func_b->tag); +} + +static cairo_bool_t +call_element (cairo_svg_glyph_render_t *svg_render, + cairo_svg_element_t *element, + cairo_bool_t end_tag) +{ + const struct render_func *func; + struct render_func key; + cairo_bool_t recurse = FALSE; + + key.tag = element->tag; + key.render = NULL; + func = bsearch (&key, + render_funcs, + ARRAY_LENGTH (render_funcs), + sizeof (struct render_func), + _render_func_compare); + if (func) { + if (func->render) { + recurse = func->render (svg_render, element, end_tag); + } + } else { + print_warning (svg_render, "Unsupported element: %s", element->tag); + } + + return recurse; +} + +static cairo_bool_t +render_element (cairo_svg_glyph_render_t *svg_render, + cairo_svg_element_t *element, + cairo_bool_t end_tag, + cairo_svg_element_t *display_element) +{ + cairo_bool_t recurse = FALSE; + cairo_svg_graphics_state_t *gs; + + /* Ignore elements if we have not seen "". Ignore + * "" if we have seen it */ + if (svg_render->view_port_set) { + if (string_equal (element->tag, "svg")) + return FALSE; + } else { + if (!string_equal (element->tag, "svg")) + return FALSE; + } + + if (element->type == EMPTY_ELEMENT || + (element->type == CONTAINER_ELEMENT && !end_tag)) + { + save_graphics_state (svg_render); + update_graphics_state (svg_render, element); + } + + gs = svg_render->graphics_state; + if (gs->mode == GS_NO_RENDER && element == display_element) + gs->mode = GS_RENDER; + + recurse = call_element (svg_render, element, end_tag); + + if (element->type == EMPTY_ELEMENT || + (element->type == CONTAINER_ELEMENT && end_tag)) + { + restore_graphics_state (svg_render); + } + + return recurse; +} + +#define MAX_DEPTH 100 + +static void +render_element_tree (cairo_svg_glyph_render_t *svg_render, + cairo_svg_element_t *element, + cairo_svg_element_t *display_element, + cairo_bool_t children_only) +{ + if (!element) + return; + + /* Avoid circular references by limiting the number of recursive + * calls to this function. */ + if (svg_render->render_element_tree_depth > MAX_DEPTH) + return; + + svg_render->render_element_tree_depth++; + if (element->type == EMPTY_ELEMENT && !children_only) { + render_element (svg_render, element, FALSE, display_element); + + } else if (element->type == CONTAINER_ELEMENT) { + int num_elems; + cairo_bool_t recurse = TRUE;; + + if (!children_only) + recurse = render_element (svg_render, element, FALSE, display_element); + + /* We only render the children if the parent returned + * success. This is how we avoid rendering non display + * elements like gradients, , and anything not + * implemented. */ + if (recurse) { + num_elems = _cairo_array_num_elements (&element->children); + for (int i = 0; i < num_elems; i++) { + cairo_svg_element_t *child; + _cairo_array_copy_element (&element->children, i, &child); + render_element_tree (svg_render, child, display_element, FALSE); + } + } + + if (!children_only) + render_element (svg_render, element, TRUE, display_element); + } + svg_render->render_element_tree_depth--; +} + +static void +render_element_tree_id (cairo_svg_glyph_render_t *svg_render, + const char *element_id) +{ + cairo_svg_element_t *glyph_element = NULL; + + if (element_id) + glyph_element = lookup_element (svg_render, element_id); + + if (glyph_element) + svg_render->graphics_state->mode = GS_NO_RENDER; + else + svg_render->graphics_state->mode = GS_RENDER; + + render_element_tree (svg_render, svg_render->tree, glyph_element, TRUE); +} + +cairo_status_t +_cairo_render_svg_glyph (const char *svg_document, + unsigned long first_glyph, + unsigned long last_glyph, + unsigned long glyph, + double units_per_em, + FT_Color *palette, + int num_palette_entries, + cairo_t *cr, + cairo_pattern_t *foreground_source, + cairo_bool_t *foreground_source_used) +{ + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + cairo_svg_glyph_render_t *svg_render = _cairo_calloc (sizeof (cairo_svg_glyph_render_t)); + if (unlikely (svg_render == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + svg_render->tree = NULL; + svg_render->ids = _cairo_hash_table_create (_element_id_equal); + if (unlikely (svg_render->ids == NULL)) { + free (svg_render); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + svg_render->debug = 0; + const char *s = getenv ("CAIRO_DEBUG_SVG_RENDER"); + if (s) { + if (strlen (s) > 0) + svg_render->debug = atoi (s); + else + svg_render->debug = SVG_RENDER_ERROR; + } + + svg_render->cr = cr; + svg_render->units_per_em = units_per_em; + svg_render->build_pattern.paint_server = NULL; + svg_render->build_pattern.pattern = NULL; + svg_render->build_pattern.type = BUILD_PATTERN_NONE; + svg_render->render_element_tree_depth = 0; + svg_render->view_port_set = FALSE; + svg_render->num_palette_entries = num_palette_entries; + svg_render->palette = palette; + + svg_render->foreground_marker = _cairo_pattern_create_foreground_marker (); + svg_render->foreground_source = cairo_pattern_reference (foreground_source);; + svg_render->foreground_source_used = FALSE; + + init_graphics_state (svg_render); + + print_info (svg_render, "Glyph ID: %ld", glyph); + print_info (svg_render, "Palette Entries: %d", num_palette_entries); + print_info (svg_render, "Units per EM: %f", units_per_em); + print_info (svg_render, "SVG Document:\n%s\n", svg_document); + + /* First parse elements into a tree and populate ids hash table */ + if (!parse_svg (svg_render, svg_document)) { + print_error (svg_render, "Parse SVG document failed"); + status = CAIRO_STATUS_SVG_FONT_ERROR; + goto cleanup; + } + +#if SVG_RENDER_PRINT_FUNCTIONS + printf("\nTREE\n"); + if (svg_render->tree) { + print_element (svg_render->tree, TRUE, 0); + printf("\n"); + } +#endif + + /* Next, render glyph */ + if (first_glyph == last_glyph) { + /* Render whole document */ + render_element_tree_id (svg_render, NULL); + } else { + /* Render element with id "glyphID" where ID is glyph number. */ + + char glyph_id[30]; + snprintf(glyph_id, sizeof(glyph_id), "#glyph%ld", glyph); + render_element_tree_id (svg_render, glyph_id); + } + + cleanup: + if (svg_render->build_pattern.pattern) + cairo_pattern_destroy (svg_render->build_pattern.pattern); + + if (svg_render->tree) + free_elements (svg_render, svg_render->tree); + + while (svg_render->graphics_state) + restore_graphics_state (svg_render); + + cairo_pattern_destroy (svg_render->foreground_marker); + cairo_pattern_destroy (svg_render->foreground_source); + *foreground_source_used = svg_render->foreground_source_used; + + /* The hash entry for each element with an id is removed by + * free_elements() */ + _cairo_hash_table_destroy (svg_render->ids); + + free (svg_render); + + return status; +} + +#ifdef DEBUG_SVG_RENDER + +/** + * _cairo_debug_svg_render: + * + * Debug function for cairo-svg-glyph-render.c. Allows invoking the renderer from outside + * cairo to test with SVG documents, and to facilitate comparison with librsvg rendering. + * The viewport is . + * + * @cr: render target + * @svg_document: SVG Document + * @element: element within svg_document to render (eg "#glyph8"), or NULL to render entire document. + * @debug_level: 0 - quiet, 1 - print errors, 2 - print warnings, 3 - info + * @return TRUE on success, ie no errors, FALSE if error + **/ +cairo_public cairo_bool_t +_cairo_debug_svg_render (cairo_t *cr, + const char *svg_document, + const char *element, + double units_per_em, + int debug_level); + +cairo_bool_t +_cairo_debug_svg_render (cairo_t *cr, + const char *svg_document, + const char *element, + double units_per_em, + int debug_level) +{ + cairo_status_t status; + cairo_bool_t foreground_source_used; + cairo_pattern_t *foreground = _cairo_pattern_create_foreground_marker (); + + status = _cairo_render_svg_glyph (svg_document, + 1, 1, 1, + units_per_em, + NULL, 0, + cr, + foreground, + &foreground_source_used); + cairo_pattern_destroy (foreground); + + return status == CAIRO_STATUS_SUCCESS; +} + +#endif /* DEBUG_SVG_RENDER */ + +#endif /* HAVE_FT_SVG_DOCUMENT */ diff --git a/local/recipes/libs/cairo/source/src/cairo-svg-surface-private.h b/local/recipes/libs/cairo/source/src/cairo-svg-surface-private.h new file mode 100644 index 0000000000..e2a194081b --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-svg-surface-private.h @@ -0,0 +1,63 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2004 Red Hat, Inc + * Copyright © 2005-2006 Emmanuel Pacaud + * Copyright © 2006 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Kristian Høgsberg + * Emmanuel Pacaud + * Carl Worth + */ + +#ifndef CAIRO_SVG_SURFACE_PRIVATE_H +#define CAIRO_SVG_SURFACE_PRIVATE_H + +#include "cairo-svg.h" + +#include "cairo-surface-private.h" + +struct _cairo_svg_surface_start { + cairo_surface_t base; + + cairo_bool_t force_fallbacks; +}; + +static inline void +_cairo_svg_surface_set_force_fallbacks (void *abstract_surface, + cairo_bool_t force_fallbacks) +{ + struct _cairo_svg_surface_start *surface = (struct _cairo_svg_surface_start *) abstract_surface; + + surface->force_fallbacks = force_fallbacks; +} + +#endif /* CAIRO_SVG_SURFACE_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-svg-surface.c b/local/recipes/libs/cairo/source/src/cairo-svg-surface.c new file mode 100644 index 0000000000..249f46f531 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-svg-surface.c @@ -0,0 +1,4421 @@ +/* vim: set sw=4 sts=4: -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2004 Red Hat, Inc + * Copyright © 2005-2007 Emmanuel Pacaud + * Copyright © 2006 Red Hat, Inc + * Copyright © 2020-2021 Anton Danilkin + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Kristian Høgsberg + * Emmanuel Pacaud + * Carl Worth + * Anton Danilkin + */ + +#include "cairoint.h" + +#include "cairo-svg.h" + +#include "cairo-array-private.h" +#include "cairo-default-context-private.h" +#include "cairo-error-private.h" +#include "cairo-image-info-private.h" +#include "cairo-image-surface-private.h" +#include "cairo-recording-surface-inline.h" +#include "cairo-output-stream-private.h" +#include "cairo-paginated-private.h" +#include "cairo-scaled-font-subsets-private.h" +#include "cairo-surface-clipper-private.h" +#include "cairo-surface-snapshot-inline.h" +#include "cairo-svg-surface-private.h" + +/** + * SECTION:cairo-svg + * @Title: SVG Surfaces + * @Short_Description: Rendering SVG documents + * @See_Also: #cairo_surface_t + * + * The SVG surface is used to render cairo graphics to + * SVG files and is a multi-page vector surface backend. + **/ + +typedef struct _cairo_svg_source_surface { + cairo_hash_entry_t base; + unsigned int id; + unsigned char *unique_id; + unsigned long unique_id_length; + cairo_bool_t transitive_paint_used; +} cairo_svg_source_surface_t; + +/* + * _cairo_svg_paint_element and _cairo_svg_paint are used to implement paints in transformed recording patterns. + */ + +typedef struct _cairo_svg_paint_element { + unsigned int source_id; + cairo_matrix_t matrix; +} cairo_svg_paint_element_t; + +typedef struct _cairo_svg_paint { + cairo_hash_entry_t base; + unsigned int source_id; + cairo_array_t paint_elements; + cairo_box_double_t box; +} cairo_svg_paint_t; + +static void +_cairo_svg_source_surface_init_key (cairo_svg_source_surface_t *source_surface) +{ + if (source_surface->unique_id && source_surface->unique_id_length > 0) { + source_surface->base.hash = _cairo_hash_bytes (_CAIRO_HASH_INIT_VALUE, + source_surface->unique_id, + source_surface->unique_id_length); + } else { + source_surface->base.hash = source_surface->id; + } +} + +static cairo_bool_t +_cairo_svg_source_surface_equal (const void *key_a, const void *key_b) +{ + const cairo_svg_source_surface_t *a = key_a; + const cairo_svg_source_surface_t *b = key_b; + + if (a->unique_id && b->unique_id && a->unique_id_length == b->unique_id_length) { + return memcmp (a->unique_id, b->unique_id, a->unique_id_length) == 0; + } + + return a->id == b->id; +} + +static void +_cairo_svg_source_surface_pluck (void *entry, void *closure) +{ + cairo_svg_source_surface_t *source_surface = entry; + cairo_hash_table_t *patterns = closure; + + _cairo_hash_table_remove (patterns, &source_surface->base); + free (source_surface->unique_id); + free (source_surface); +} + +static void +_cairo_svg_paint_init_key (cairo_svg_paint_t *paint) +{ + paint->base.hash = paint->source_id; +} + +static cairo_bool_t +_cairo_svg_paint_equal (const void *key_a, const void *key_b) +{ + const cairo_svg_paint_t *a = key_a; + const cairo_svg_paint_t *b = key_b; + + return a->source_id == b->source_id; +} + +static void +_cairo_svg_paint_pluck (void *entry, void *closure) +{ + cairo_svg_paint_t *paint = entry; + cairo_hash_table_t *patterns = closure; + + _cairo_hash_table_remove (patterns, &paint->base); + _cairo_array_fini (&paint->paint_elements); + free (paint); +} + +static void +_cairo_svg_paint_box_add_padding (cairo_box_double_t *box) +{ + double width = box->p2.x - box->p1.x; + double height = box->p2.y - box->p1.y; + + box->p1.x -= width / 10.0; + box->p1.y -= height / 10.0; + box->p2.x += width / 10.0; + box->p2.y += height / 10.0; +} + +enum cairo_svg_stream_element_type { + CAIRO_SVG_STREAM_ELEMENT_TYPE_TEXT, + CAIRO_SVG_STREAM_ELEMENT_TYPE_PAINT_DEPENDENT, +}; + +enum cairo_svg_stream_paint_dependent_element_type { + CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_RECTANGLE, + CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_RECTANGLE_AT_ORIGIN, + CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_TRANSLATION, + CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_INVERSE_TRANSLATION, +}; + +typedef struct _cairo_svg_stream_element { + enum cairo_svg_stream_element_type type; + union { + struct { + cairo_output_stream_t *output_stream; + } text; + struct { + unsigned int source_id; + enum cairo_svg_stream_paint_dependent_element_type type; + } paint_dependent; + }; +} cairo_svg_stream_element_t; + +typedef struct _cairo_svg_stream { + cairo_status_t status; + cairo_array_t elements; +} cairo_svg_stream_t; + +static cairo_svg_stream_t +_cairo_svg_stream_create () +{ + cairo_svg_stream_t svg_stream; + svg_stream.status = CAIRO_STATUS_SUCCESS; + _cairo_array_init (&svg_stream.elements, sizeof (cairo_svg_stream_element_t)); + return svg_stream; +} + +static void +_cairo_svg_stream_write (cairo_svg_stream_t *svg_stream, + const void *data, + size_t length) +{ + cairo_status_t status; + + cairo_svg_stream_element_t *last_element = NULL; + if (svg_stream->elements.num_elements > 0) { + last_element = _cairo_array_index (&svg_stream->elements, + svg_stream->elements.num_elements - 1); + } + + if (last_element == NULL || last_element->type != CAIRO_SVG_STREAM_ELEMENT_TYPE_TEXT) { + cairo_svg_stream_element_t element; + element.type = CAIRO_SVG_STREAM_ELEMENT_TYPE_TEXT; + element.text.output_stream = _cairo_memory_stream_create(); + status = _cairo_array_append (&svg_stream->elements, &element); + if (unlikely (status)) { + if (svg_stream->status == CAIRO_STATUS_SUCCESS) { + svg_stream->status = status; + } + return; + } + last_element = _cairo_array_index (&svg_stream->elements, + svg_stream->elements.num_elements - 1); + } + + _cairo_output_stream_write (last_element->text.output_stream, data, length); +} + +static void CAIRO_PRINTF_FORMAT (2, 0) +_cairo_svg_stream_printf (cairo_svg_stream_t *svg_stream, + const char *fmt, + ...) +{ + cairo_status_t status; + + cairo_svg_stream_element_t *last_element = NULL; + if (svg_stream->elements.num_elements > 0) { + last_element = _cairo_array_index (&svg_stream->elements, + svg_stream->elements.num_elements - 1); + } + + if (last_element == NULL || last_element->type != CAIRO_SVG_STREAM_ELEMENT_TYPE_TEXT) { + cairo_svg_stream_element_t element; + element.type = CAIRO_SVG_STREAM_ELEMENT_TYPE_TEXT; + element.text.output_stream = _cairo_memory_stream_create(); + status = _cairo_array_append (&svg_stream->elements, &element); + if (unlikely (status)) { + if (svg_stream->status == CAIRO_STATUS_SUCCESS) { + svg_stream->status = status; + } + return; + } + last_element = _cairo_array_index (&svg_stream->elements, + svg_stream->elements.num_elements - 1); + } + + va_list ap; + va_start (ap, fmt); + _cairo_output_stream_vprintf (last_element->text.output_stream, fmt, ap); + va_end (ap); +} + +static void +_cairo_svg_stream_append_paint_dependent (cairo_svg_stream_t *svg_stream, + unsigned int source_id, + enum cairo_svg_stream_paint_dependent_element_type type) +{ + cairo_status_t status; + + cairo_svg_stream_element_t element; + element.type = CAIRO_SVG_STREAM_ELEMENT_TYPE_PAINT_DEPENDENT; + element.paint_dependent.source_id = source_id; + element.paint_dependent.type = type; + status = _cairo_array_append (&svg_stream->elements, &element); + if (svg_stream->status == CAIRO_STATUS_SUCCESS) { + svg_stream->status = status; + } +} + +static void +_cairo_svg_stream_copy (cairo_svg_stream_t *from, + cairo_svg_stream_t *to) +{ + cairo_status_t status; + + if (unlikely (from->status)) { + if (to->status == CAIRO_STATUS_SUCCESS) { + to->status = from->status; + } + return; + } + + for (unsigned int i = 0; i < from->elements.num_elements; i++) { + cairo_svg_stream_element_t *element = _cairo_array_index (&from->elements, i); + cairo_svg_stream_element_t element_copy = *element; + if (element->type == CAIRO_SVG_STREAM_ELEMENT_TYPE_TEXT) { + element_copy.text.output_stream = _cairo_memory_stream_create (); + _cairo_memory_stream_copy (element->text.output_stream, element_copy.text.output_stream); + if (to->status == CAIRO_STATUS_SUCCESS) { + to->status = element->text.output_stream->status; + } + } + status = _cairo_array_append (&to->elements, &element_copy); + if (unlikely (status)) { + if (to->status == CAIRO_STATUS_SUCCESS) { + to->status = status; + } + return; + } + } +} + +static void +_cairo_svg_stream_copy_to_output_stream (cairo_svg_stream_t *from, + cairo_output_stream_t *to, + cairo_hash_table_t *paints) +{ + if (unlikely (from->status)) { + if (to->status == CAIRO_STATUS_SUCCESS) { + to->status = from->status; + } + return; + } + + for (unsigned int i = 0; i < from->elements.num_elements; i++) { + cairo_svg_stream_element_t *element = _cairo_array_index (&from->elements, i); + if (element->type == CAIRO_SVG_STREAM_ELEMENT_TYPE_TEXT) { + _cairo_memory_stream_copy (element->text.output_stream, to); + } + if (element->type == CAIRO_SVG_STREAM_ELEMENT_TYPE_PAINT_DEPENDENT) { + cairo_svg_paint_t paint_key; + paint_key.source_id = element->paint_dependent.source_id; + _cairo_svg_paint_init_key (&paint_key); + + cairo_svg_paint_t *found_paint_entry = _cairo_hash_table_lookup (paints, + &paint_key.base); + assert (found_paint_entry); + + switch (element->paint_dependent.type) { + case CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_RECTANGLE: + _cairo_output_stream_printf (to, + " x=\"%f\" y=\"%f\" width=\"%f\" height=\"%f\"", + found_paint_entry->box.p1.x, + found_paint_entry->box.p1.y, + found_paint_entry->box.p2.x - found_paint_entry->box.p1.x, + found_paint_entry->box.p2.y - found_paint_entry->box.p1.y); + break; + case CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_RECTANGLE_AT_ORIGIN: + _cairo_output_stream_printf (to, + " x=\"0\" y=\"0\" width=\"%f\" height=\"%f\"", + found_paint_entry->box.p2.x - found_paint_entry->box.p1.x, + found_paint_entry->box.p2.y - found_paint_entry->box.p1.y); + break; + case CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_TRANSLATION: + _cairo_output_stream_printf (to, + " transform=\"translate(%f, %f)\"", + found_paint_entry->box.p1.x, + found_paint_entry->box.p1.y); + break; + case CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_INVERSE_TRANSLATION: + _cairo_output_stream_printf (to, + " transform=\"translate(%f, %f)\"", + -found_paint_entry->box.p1.x, + -found_paint_entry->box.p1.y); + break; + } + } + } +} + +static cairo_status_t +_cairo_svg_stream_destroy (cairo_svg_stream_t *svg_stream) +{ + cairo_status_t status = svg_stream->status; + for (unsigned int i = 0; i < svg_stream->elements.num_elements; i++) { + cairo_svg_stream_element_t *element = _cairo_array_index (&svg_stream->elements, i); + if (element->type == CAIRO_SVG_STREAM_ELEMENT_TYPE_TEXT) { + cairo_status_t element_status = _cairo_output_stream_destroy (element->text.output_stream); + if (status == CAIRO_STATUS_SUCCESS) { + status = element_status; + } + } + } + _cairo_array_fini (&svg_stream->elements); + return status; +} + +/** + * CAIRO_HAS_SVG_SURFACE: + * + * Defined if the SVG surface backend is available. + * This macro can be used to conditionally compile backend-specific code. + * + * Since: 1.2 + **/ + +static const unsigned int invalid_pattern_id = -1; + +static const cairo_svg_version_t _cairo_svg_versions[] = +{ + CAIRO_SVG_VERSION_1_1, + CAIRO_SVG_VERSION_1_2 +}; + +#define CAIRO_SVG_VERSION_LAST ARRAY_LENGTH (_cairo_svg_versions) + +static const char *_cairo_svg_supported_mime_types[] = +{ + CAIRO_MIME_TYPE_JPEG, + CAIRO_MIME_TYPE_PNG, + CAIRO_MIME_TYPE_UNIQUE_ID, + CAIRO_MIME_TYPE_URI, + NULL +}; + +static void +_cairo_svg_surface_emit_path (cairo_svg_stream_t *output, + const cairo_path_fixed_t *path, + const cairo_matrix_t *ctm_inverse); + +static const char * _cairo_svg_version_strings[CAIRO_SVG_VERSION_LAST] = +{ + "SVG 1.1", + "SVG 1.2" +}; + +static const char * _cairo_svg_unit_strings[] = +{ + "", + "em", + "ex", + "px", + "in", + "cm", + "mm", + "pt", + "pc", + "%" +}; + +enum cairo_svg_filter { + CAIRO_SVG_FILTER_REMOVE_COLOR, + CAIRO_SVG_FILTER_REMOVE_COLOR_AND_INVERT_ALPHA, + CAIRO_SVG_FILTER_COLOR_TO_ALPHA, + CAIRO_SVG_FILTER_LAST_STATIC_FILTER, + CAIRO_SVG_FILTER_OVER, + CAIRO_SVG_FILTER_IN, + CAIRO_SVG_FILTER_OUT, + CAIRO_SVG_FILTER_ATOP, + CAIRO_SVG_FILTER_XOR, + CAIRO_SVG_FILTER_ADD, + CAIRO_SVG_FILTER_MULTIPLY, + CAIRO_SVG_FILTER_SCREEN, + CAIRO_SVG_FILTER_OVERLAY, + CAIRO_SVG_FILTER_DARKEN, + CAIRO_SVG_FILTER_LIGHTEN, + CAIRO_SVG_FILTER_COLOR_DODGE, + CAIRO_SVG_FILTER_COLOR_BURN, + CAIRO_SVG_FILTER_HARD_LIGHT, + CAIRO_SVG_FILTER_SOFT_LIGHT, + CAIRO_SVG_FILTER_DIFFERENCE, + CAIRO_SVG_FILTER_EXCLUSION, + CAIRO_SVG_FILTER_HUE, + CAIRO_SVG_FILTER_SATURATION, + CAIRO_SVG_FILTER_COLOR, + CAIRO_SVG_FILTER_LUMINOSITY, +}; + +typedef struct _cairo_svg_page { + cairo_svg_stream_t xml_node; +} cairo_svg_page_t; + +typedef struct _cairo_svg_document { + cairo_output_stream_t *output_stream; + unsigned long refcount; + cairo_surface_t *owner; + cairo_bool_t finished; + + double width; + double height; + cairo_svg_unit_t unit; + + cairo_svg_stream_t xml_node_defs; + cairo_svg_stream_t xml_node_glyphs; + cairo_svg_stream_t xml_node_filters; + + unsigned int linear_pattern_id; + unsigned int radial_pattern_id; + unsigned int pattern_id; + unsigned int clip_id; + unsigned int mask_id; + unsigned int compositing_group_id; + unsigned int filter_id; + + cairo_bool_t filters_emitted[CAIRO_SVG_FILTER_LAST_STATIC_FILTER]; + + cairo_svg_version_t svg_version; + + cairo_scaled_font_subsets_t *font_subsets; + + cairo_hash_table_t *paints; +} cairo_svg_document_t; + +// Must be compatible with the struct _cairo_svg_surface_start. +typedef struct _cairo_svg_surface { + cairo_surface_t base; + + cairo_bool_t force_fallbacks; + + unsigned int source_id; + unsigned int depth; + + double width; + double height; + cairo_bool_t surface_bounded; + + cairo_svg_document_t *document; + + cairo_svg_stream_t xml_node; + cairo_array_t page_set; + + cairo_hash_table_t *source_surfaces; + + cairo_surface_clipper_t clipper; + cairo_svg_stream_t *current_clipper_stream; + unsigned int clip_level; + + cairo_bool_t transitive_paint_used; + + cairo_paginated_mode_t paginated_mode; +} cairo_svg_surface_t; + +static cairo_status_t +_cairo_svg_document_create (cairo_output_stream_t *stream, + double width, + double height, + cairo_svg_version_t version, + cairo_svg_document_t **document_out); + +static cairo_status_t +_cairo_svg_document_destroy (cairo_svg_document_t *document); + +static cairo_status_t +_cairo_svg_document_finish (cairo_svg_document_t *document); + +static cairo_svg_document_t * +_cairo_svg_document_reference (cairo_svg_document_t *document); + +static cairo_surface_t * +_cairo_svg_surface_create_for_document (cairo_svg_document_t *document, + cairo_content_t content, + double width, + double height, + cairo_bool_t bounded); + +static cairo_surface_t * +_cairo_svg_surface_create_for_stream_internal (cairo_output_stream_t *stream, + double width, + double height, + cairo_svg_version_t version); + +static cairo_status_t +_cairo_svg_surface_emit_composite_pattern (cairo_svg_stream_t *output, + cairo_svg_surface_t *surface, + cairo_surface_pattern_t *pattern, + unsigned int pattern_id, + const cairo_matrix_t *parent_matrix); + +static cairo_status_t +_cairo_svg_surface_emit_paint (cairo_svg_stream_t *output, + cairo_svg_surface_t *surface, + const cairo_pattern_t *source, + cairo_bool_t at_origin); + +static const cairo_surface_backend_t cairo_svg_surface_backend; +static const cairo_paginated_surface_backend_t cairo_svg_surface_paginated_backend; + +/** + * cairo_svg_surface_create_for_stream: + * @write_func: a #cairo_write_func_t to accept the output data, may be %NULL + * to indicate a no-op @write_func. With a no-op @write_func, + * the surface may be queried or used as a source without + * generating any temporary files. + * @closure: the closure argument for @write_func + * @width_in_points: width of the surface, in points (1 point == 1/72.0 inch) + * @height_in_points: height of the surface, in points (1 point == 1/72.0 inch) + * + * Creates a SVG surface of the specified size in points to be written + * incrementally to the stream represented by @write_func and @closure. + * + * Return value: a pointer to the newly created surface. The caller + * owns the surface and should call cairo_surface_destroy() when done + * with it. + * + * This function always returns a valid pointer, but it will return a + * pointer to a "nil" surface if an error such as out of memory + * occurs. You can use cairo_surface_status() to check for this. + * + * Since: 1.2 + **/ +cairo_surface_t * +cairo_svg_surface_create_for_stream (cairo_write_func_t write_func, + void *closure, + double width, + double height) +{ + cairo_output_stream_t *stream; + + stream = _cairo_output_stream_create (write_func, NULL, closure); + if (_cairo_output_stream_get_status (stream)) + return _cairo_surface_create_in_error (_cairo_output_stream_destroy (stream)); + + return _cairo_svg_surface_create_for_stream_internal (stream, width, height, CAIRO_SVG_VERSION_1_1); +} + +/** + * cairo_svg_surface_create: + * @filename: a filename for the SVG output (must be writable), %NULL may be + * used to specify no output. This will generate a SVG surface that + * may be queried and used as a source, without generating a + * temporary file. + * @width_in_points: width of the surface, in points (1 point == 1/72.0 inch) + * @height_in_points: height of the surface, in points (1 point == 1/72.0 inch) + * + * Creates a SVG surface of the specified size in points to be written + * to @filename. + * + * The SVG surface backend recognizes the following MIME types for the + * data attached to a surface (see cairo_surface_set_mime_data()) when + * it is used as a source pattern for drawing on this surface: + * %CAIRO_MIME_TYPE_JPEG, %CAIRO_MIME_TYPE_PNG, + * %CAIRO_MIME_TYPE_URI. If any of them is specified, the SVG backend + * emits a href with the content of MIME data instead of a surface + * snapshot (PNG, Base64-encoded) in the corresponding image tag. + * + * The unofficial MIME type %CAIRO_MIME_TYPE_URI is examined + * first. If present, the URI is emitted as is: assuring the + * correctness of URI is left to the client code. + * + * If %CAIRO_MIME_TYPE_URI is not present, but %CAIRO_MIME_TYPE_JPEG + * or %CAIRO_MIME_TYPE_PNG is specified, the corresponding data is + * Base64-encoded and emitted. + * + * If %CAIRO_MIME_TYPE_UNIQUE_ID is present, all surfaces with the same + * unique identifier will only be embedded once. + * + * Return value: a pointer to the newly created surface. The caller + * owns the surface and should call cairo_surface_destroy() when done + * with it. + * + * This function always returns a valid pointer, but it will return a + * pointer to a "nil" surface if an error such as out of memory + * occurs. You can use cairo_surface_status() to check for this. + * + * Since: 1.2 + **/ +cairo_surface_t * +cairo_svg_surface_create (const char *filename, + double width, + double height) +{ + cairo_output_stream_t *stream; + + stream = _cairo_output_stream_create_for_filename (filename); + if (_cairo_output_stream_get_status (stream)) + return _cairo_surface_create_in_error (_cairo_output_stream_destroy (stream)); + + return _cairo_svg_surface_create_for_stream_internal (stream, width, height, CAIRO_SVG_VERSION_1_1); +} + +static cairo_bool_t +_cairo_surface_is_svg (cairo_surface_t *surface) +{ + return surface->backend == &cairo_svg_surface_backend; +} + +/* If the abstract_surface is a paginated surface, and that paginated + * surface's target is a svg_surface, then set svg_surface to that + * target. Otherwise return FALSE. + */ +static cairo_bool_t +_extract_svg_surface (cairo_surface_t *surface, + cairo_svg_surface_t **svg_surface) +{ + cairo_surface_t *target; + + if (surface->status) + return FALSE; + if (surface->finished) { + (void) _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + return FALSE; + } + + if (!_cairo_surface_is_paginated (surface)) { + (void) _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); + return FALSE; + } + + target = _cairo_paginated_surface_get_target (surface); + if (target->status) { + (void) _cairo_surface_set_error (surface, target->status); + return FALSE; + } + if (target->finished) { + (void) _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + return FALSE; + } + + if (!_cairo_surface_is_svg (target)) { + (void) _cairo_surface_set_error (surface, _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); + return FALSE; + } + + *svg_surface = (cairo_svg_surface_t *) target; + return TRUE; +} + +/** + * cairo_svg_surface_restrict_to_version: + * @surface: a SVG #cairo_surface_t + * @version: SVG version + * + * Restricts the generated SVG file to @version. See cairo_svg_get_versions() + * for a list of available version values that can be used here. + * + * This function should only be called before any drawing operations + * have been performed on the given surface. The simplest way to do + * this is to call this function immediately after creating the + * surface. + * + * Since: 1.2 + **/ +void +cairo_svg_surface_restrict_to_version (cairo_surface_t *abstract_surface, + cairo_svg_version_t version) +{ + cairo_svg_surface_t *surface; + + if (! _extract_svg_surface (abstract_surface, &surface)) + return; + + if (version < CAIRO_SVG_VERSION_LAST) + surface->document->svg_version = version; +} + +/** + * cairo_svg_get_versions: + * @versions: supported version list + * @num_versions: list length + * + * Used to retrieve the list of supported versions. See + * cairo_svg_surface_restrict_to_version(). + * + * Since: 1.2 + **/ +void +cairo_svg_get_versions (cairo_svg_version_t const **versions, + int *num_versions) +{ + if (versions != NULL) + *versions = _cairo_svg_versions; + + if (num_versions != NULL) + *num_versions = CAIRO_SVG_VERSION_LAST; +} + +/** + * cairo_svg_version_to_string: + * @version: a version id + * + * Get the string representation of the given @version id. This function + * will return %NULL if @version isn't valid. See cairo_svg_get_versions() + * for a way to get the list of valid version ids. + * + * Return value: the string associated to given version. + * + * Since: 1.2 + **/ +const char * +cairo_svg_version_to_string (cairo_svg_version_t version) +{ + if (version >= CAIRO_SVG_VERSION_LAST) + return NULL; + + return _cairo_svg_version_strings[version]; +} + +/** + * cairo_svg_surface_set_document_unit: + * @surface: a SVG #cairo_surface_t + * @unit: SVG unit + * + * Use the specified unit for the width and height of the generated SVG file. + * See #cairo_svg_unit_t for a list of available unit values that can be used + * here. + * + * This function can be called at any time before generating the SVG file. + * + * However to minimize the risk of ambiguities it's recommended to call it + * before any drawing operations have been performed on the given surface, to + * make it clearer what the unit used in the drawing operations is. + * + * The simplest way to do this is to call this function immediately after + * creating the SVG surface. + * + * Note if this function is never called, the default unit for SVG documents + * generated by cairo will be user unit. + * + * Since: 1.16 + **/ +void +cairo_svg_surface_set_document_unit (cairo_surface_t *abstract_surface, + cairo_svg_unit_t unit) +{ + cairo_svg_surface_t *surface; + + if (! _extract_svg_surface (abstract_surface, &surface)) + return; + + if (unit <= CAIRO_SVG_UNIT_PERCENT) + surface->document->unit = unit; +} + +/** + * cairo_svg_surface_get_document_unit: + * @surface: a SVG #cairo_surface_t + * + * Get the unit of the SVG surface. + * + * If the surface passed as an argument is not a SVG surface, the function + * sets the error status to CAIRO_STATUS_SURFACE_TYPE_MISMATCH and returns + * CAIRO_SVG_UNIT_USER. + * + * Return value: the SVG unit of the SVG surface. + * + * Since: 1.16 + **/ +cairo_svg_unit_t +cairo_svg_surface_get_document_unit (cairo_surface_t *abstract_surface) +{ + cairo_svg_surface_t *surface; + + if (! _extract_svg_surface (abstract_surface, &surface)) { + _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + return CAIRO_SVG_UNIT_USER; + } + + return surface->document->unit; +} + +static void +_cairo_svg_paint_compute (cairo_svg_document_t *document, cairo_svg_paint_t *paint) { + for (unsigned int i = 0; i < paint->paint_elements.num_elements; i++) { + cairo_svg_paint_element_t *paint_element = _cairo_array_index (&paint->paint_elements, i); + + cairo_svg_paint_t paint_key; + paint_key.source_id = paint_element->source_id; + _cairo_svg_paint_init_key (&paint_key); + + cairo_svg_paint_t *found_paint_entry = _cairo_hash_table_lookup (document->paints, + &paint_key.base); + assert (found_paint_entry); + + _cairo_svg_paint_compute (document, found_paint_entry); + + cairo_box_double_t box = found_paint_entry->box; + _cairo_matrix_transform_bounding_box (&paint_element->matrix, + &box.p1.x, &box.p1.y, + &box.p2.x, &box.p2.y, + NULL); + _cairo_svg_paint_box_add_padding (&box); + + if (i == 0) { + paint->box = box; + } else { + paint->box.p1.x = MIN (paint->box.p1.x, box.p1.x); + paint->box.p1.y = MIN (paint->box.p1.y, box.p1.y); + paint->box.p2.x = MAX (paint->box.p2.x, box.p2.x); + paint->box.p2.y = MAX (paint->box.p2.y, box.p2.y); + } + } + _cairo_array_truncate (&paint->paint_elements, 0); +} + +static void +_cairo_svg_paint_compute_func (void *entry, void *closure) +{ + cairo_svg_paint_t *paint = entry; + cairo_svg_document_t *document = closure; + + _cairo_svg_paint_compute (document, paint); +} + +static cairo_status_t +_cairo_svg_surface_add_source_surface (cairo_svg_surface_t *surface, + cairo_surface_t *source_surface, + cairo_bool_t *is_new, + cairo_svg_source_surface_t **result_source_surface) +{ + cairo_status_t status; + + cairo_svg_source_surface_t source_surface_key; + source_surface_key.id = source_surface->unique_id; + cairo_surface_get_mime_data (source_surface, + CAIRO_MIME_TYPE_UNIQUE_ID, + (const unsigned char **) &source_surface_key.unique_id, + &source_surface_key.unique_id_length); + _cairo_svg_source_surface_init_key (&source_surface_key); + + cairo_svg_source_surface_t *found_source_surface_entry = _cairo_hash_table_lookup (surface->source_surfaces, + &source_surface_key.base); + if (found_source_surface_entry) { + *is_new = FALSE; + *result_source_surface = found_source_surface_entry; + return CAIRO_STATUS_SUCCESS; + } + + unsigned char *unique_id = NULL; + unsigned long unique_id_length = 0; + if (source_surface_key.unique_id && source_surface_key.unique_id_length > 0) { + unique_id = _cairo_malloc (source_surface_key.unique_id_length); + if (unique_id == NULL) { + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + unique_id_length = source_surface_key.unique_id_length; + memcpy (unique_id, source_surface_key.unique_id, unique_id_length); + } else { + unique_id = NULL; + unique_id_length = 0; + } + + cairo_svg_source_surface_t *source_surface_entry = _cairo_calloc (sizeof (cairo_svg_source_surface_t)); + if (source_surface_entry == NULL) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto fail; + } + source_surface_entry->id = source_surface_key.id; + source_surface_entry->unique_id_length = unique_id_length; + source_surface_entry->unique_id = unique_id; + _cairo_svg_source_surface_init_key (source_surface_entry); + status = _cairo_hash_table_insert (surface->source_surfaces, &source_surface_entry->base); + if (unlikely (status)) { + goto fail; + } + + *is_new = TRUE; + *result_source_surface = source_surface_entry; + return CAIRO_STATUS_SUCCESS; + + fail: + free (unique_id); + free (source_surface_entry); + return status; +} + +static cairo_bool_t +_cairo_svg_surface_cliprect_covers_surface (cairo_svg_surface_t *surface, + cairo_path_fixed_t *path) +{ + cairo_box_t box; + + return surface->surface_bounded && + _cairo_path_fixed_is_box (path, &box) && + box.p1.x <= 0 && + box.p1.y <= 0 && + _cairo_fixed_to_double (box.p2.x) >= surface->width && + _cairo_fixed_to_double (box.p2.y) >= surface->height; +} + +static cairo_status_t +_cairo_svg_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_svg_surface_t *surface = cairo_container_of (clipper, + cairo_svg_surface_t, + clipper); + cairo_svg_document_t *document = surface->document; + + if (path == NULL) { + for (unsigned int i = 0; i < surface->clip_level; i++) { + _cairo_svg_stream_printf (surface->current_clipper_stream, "\n"); + } + surface->clip_level = 0; + return CAIRO_STATUS_SUCCESS; + } + + /* skip trivial whole-page clips */ + if (_cairo_svg_surface_cliprect_covers_surface (surface, path)) { + return CAIRO_STATUS_SUCCESS; + } + + _cairo_svg_stream_printf (&document->xml_node_defs, + "\n", + document->clip_id); + + _cairo_svg_stream_printf (&document->xml_node_defs, + "xml_node_defs, path, NULL); + _cairo_svg_stream_printf (&document->xml_node_defs, "/>\n"); + + _cairo_svg_stream_printf (&document->xml_node_defs, "\n"); + + _cairo_svg_stream_printf (surface->current_clipper_stream, + "\n", + document->clip_id); + + document->clip_id++; + surface->clip_level++; + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_svg_surface_reset_clip (cairo_svg_surface_t *surface) +{ + _cairo_surface_clipper_reset (&surface->clipper); + if (surface->current_clipper_stream != NULL) { + for (unsigned int i = 0; i < surface->clip_level; i++) { + _cairo_svg_stream_printf (surface->current_clipper_stream, "\n"); + } + } + surface->clip_level = 0; +} + +static cairo_status_t +_cairo_svg_surface_set_clip (cairo_svg_surface_t *surface, + cairo_svg_stream_t *clipper_stream, + const cairo_clip_t *clip) +{ + if (surface->current_clipper_stream != clipper_stream) { + _cairo_svg_surface_reset_clip (surface); + surface->current_clipper_stream = clipper_stream; + } + return _cairo_surface_clipper_set_clip (&surface->clipper, clip); +} + +static cairo_surface_t * +_cairo_svg_surface_create_for_document (cairo_svg_document_t *document, + cairo_content_t content, + double width, + double height, + cairo_bool_t bounded) +{ + cairo_svg_surface_t *surface; + cairo_surface_t *paginated; + cairo_status_t status; + + surface = _cairo_calloc (sizeof (cairo_svg_surface_t)); + if (unlikely (surface == NULL)) { + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + } + + _cairo_surface_init (&surface->base, + &cairo_svg_surface_backend, + NULL, /* device */ + content, + TRUE); /* is_vector */ + + surface->source_id = surface->base.unique_id; + surface->depth = 0; + + surface->width = width; + surface->height = height; + surface->surface_bounded = bounded; + + surface->document = _cairo_svg_document_reference (document); + + surface->xml_node = _cairo_svg_stream_create (); + _cairo_array_init (&surface->page_set, sizeof (cairo_svg_page_t)); + + surface->source_surfaces = _cairo_hash_table_create (_cairo_svg_source_surface_equal); + if (unlikely (surface->source_surfaces == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CLEANUP; + } + + _cairo_surface_clipper_init (&surface->clipper, _cairo_svg_surface_clipper_intersect_clip_path); + surface->current_clipper_stream = NULL; + surface->clip_level = 0; + surface->transitive_paint_used = FALSE; + + surface->paginated_mode = CAIRO_PAGINATED_MODE_ANALYZE; + + surface->force_fallbacks = FALSE; + + + paginated = _cairo_paginated_surface_create (&surface->base, + surface->base.content, + &cairo_svg_surface_paginated_backend); + status = paginated->status; + if (status == CAIRO_STATUS_SUCCESS) { + /* paginated keeps the only reference to surface now, drop ours */ + cairo_surface_destroy (&surface->base); + return paginated; + } + + /* ignore status as we are on the error path */ + CLEANUP: + (void) _cairo_svg_stream_destroy (&surface->xml_node); + (void) _cairo_svg_document_destroy (document); + + free (surface); + + return _cairo_surface_create_in_error (status); +} + +static cairo_surface_t * +_cairo_svg_surface_create_for_stream_internal (cairo_output_stream_t *stream, + double width, + double height, + cairo_svg_version_t version) +{ + cairo_svg_document_t *document; + cairo_surface_t *surface; + cairo_status_t status; + + status = _cairo_svg_document_create (stream, + width, height, version, + &document); + if (unlikely (status)) { + surface = _cairo_surface_create_in_error (status); + /* consume the output stream on behalf of caller */ + status = _cairo_output_stream_destroy (stream); + return surface; + } + + surface = _cairo_svg_surface_create_for_document (document, CAIRO_CONTENT_COLOR_ALPHA, + width, height, TRUE); + if (surface->status) { + return surface; + } + + document->owner = surface; + status = _cairo_svg_document_destroy (document); + /* the ref count should be 2 at this point */ + assert (status == CAIRO_STATUS_SUCCESS); + + return surface; +} + +static cairo_svg_page_t * +_cairo_svg_surface_store_page (cairo_svg_surface_t *surface) +{ + _cairo_svg_surface_reset_clip (surface); + cairo_svg_page_t page; + page.xml_node = surface->xml_node; + if (_cairo_array_append (&surface->page_set, &page)) { + return NULL; + } + surface->xml_node = _cairo_svg_stream_create (); + return _cairo_array_index (&surface->page_set, + surface->page_set.num_elements - 1); +} + +static cairo_int_status_t +_cairo_svg_surface_copy_page (void *abstract_surface) +{ + cairo_svg_surface_t *surface = abstract_surface; + + cairo_svg_page_t *page = _cairo_svg_surface_store_page (surface); + if (unlikely (page == NULL)) { + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + _cairo_svg_stream_copy (&page->xml_node, &surface->xml_node); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_svg_surface_show_page (void *abstract_surface) +{ + cairo_svg_surface_t *surface = abstract_surface; + + cairo_svg_page_t *page = _cairo_svg_surface_store_page (surface); + if (unlikely (page == NULL)) { + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_svg_surface_emit_transform (cairo_svg_stream_t *output, + char const *attribute_name, + const cairo_matrix_t *object_matrix, + const cairo_matrix_t *parent_matrix) +{ + cairo_matrix_t matrix = *object_matrix; + + if (parent_matrix != NULL) { + cairo_matrix_multiply (&matrix, &matrix, parent_matrix); + } + + if (!_cairo_matrix_is_identity (&matrix)) { + _cairo_svg_stream_printf (output, + " %s=\"matrix(%f, %f, %f, %f, %f, %f)\"", + attribute_name, + matrix.xx, matrix.yx, + matrix.xy, matrix.yy, + matrix.x0, matrix.y0); + } +} + +typedef struct { + cairo_svg_stream_t *output; + const cairo_matrix_t *ctm_inverse; +} svg_path_info_t; + +static cairo_status_t +_cairo_svg_path_move_to (void *closure, + const cairo_point_t *point) +{ + svg_path_info_t *info = closure; + double x = _cairo_fixed_to_double (point->x); + double y = _cairo_fixed_to_double (point->y); + + if (info->ctm_inverse) + cairo_matrix_transform_point (info->ctm_inverse, &x, &y); + + _cairo_svg_stream_printf (info->output, "M %f %f ", x, y); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_svg_path_line_to (void *closure, + const cairo_point_t *point) +{ + svg_path_info_t *info = closure; + double x = _cairo_fixed_to_double (point->x); + double y = _cairo_fixed_to_double (point->y); + + if (info->ctm_inverse) + cairo_matrix_transform_point (info->ctm_inverse, &x, &y); + + _cairo_svg_stream_printf (info->output, "L %f %f ", x, y); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_svg_path_curve_to (void *closure, + const cairo_point_t *b, + const cairo_point_t *c, + const cairo_point_t *d) +{ + svg_path_info_t *info = closure; + double bx = _cairo_fixed_to_double (b->x); + double by = _cairo_fixed_to_double (b->y); + double cx = _cairo_fixed_to_double (c->x); + double cy = _cairo_fixed_to_double (c->y); + double dx = _cairo_fixed_to_double (d->x); + double dy = _cairo_fixed_to_double (d->y); + + if (info->ctm_inverse) { + cairo_matrix_transform_point (info->ctm_inverse, &bx, &by); + cairo_matrix_transform_point (info->ctm_inverse, &cx, &cy); + cairo_matrix_transform_point (info->ctm_inverse, &dx, &dy); + } + + _cairo_svg_stream_printf (info->output, + "C %f %f %f %f %f %f ", + bx, by, cx, cy, dx, dy); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_svg_path_close_path (void *closure) +{ + svg_path_info_t *info = closure; + + _cairo_svg_stream_printf (info->output, "Z "); + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_svg_surface_emit_path (cairo_svg_stream_t *output, + const cairo_path_fixed_t *path, + const cairo_matrix_t *ctm_inverse) +{ + cairo_status_t status; + svg_path_info_t info; + + _cairo_svg_stream_printf (output, " d=\""); + + info.output = output; + info.ctm_inverse = ctm_inverse; + status = _cairo_path_fixed_interpret (path, + _cairo_svg_path_move_to, + _cairo_svg_path_line_to, + _cairo_svg_path_curve_to, + _cairo_svg_path_close_path, + &info); + assert (status == CAIRO_STATUS_SUCCESS); + + _cairo_svg_stream_printf (output, "\""); +} + +static cairo_int_status_t +_cairo_svg_document_emit_outline_glyph_data (cairo_svg_document_t *document, + cairo_scaled_font_t *scaled_font, + unsigned long glyph_index) +{ + cairo_scaled_glyph_t *scaled_glyph; + cairo_int_status_t status; + + status = _cairo_scaled_glyph_lookup (scaled_font, + glyph_index, + CAIRO_SCALED_GLYPH_INFO_METRICS | CAIRO_SCALED_GLYPH_INFO_PATH, + NULL, /* foreground color */ + &scaled_glyph); + if (unlikely (status)) { + return status; + } + + if (_cairo_path_fixed_size (scaled_glyph->path) != 0) { + _cairo_svg_stream_printf (&document->xml_node_glyphs, + "xml_node_glyphs, + scaled_glyph->path, + NULL); + + _cairo_svg_stream_printf (&document->xml_node_glyphs, + "/>\n"); + } + + return status; +} + +static cairo_int_status_t +_cairo_svg_document_emit_bitmap_glyph_data (cairo_svg_document_t *document, + cairo_scaled_font_t *scaled_font, + unsigned long glyph_index) +{ + cairo_status_t status; + + cairo_scaled_glyph_t *scaled_glyph; + status = _cairo_scaled_glyph_lookup (scaled_font, + glyph_index, + CAIRO_SCALED_GLYPH_INFO_METRICS | CAIRO_SCALED_GLYPH_INFO_SURFACE, + NULL, /* foreground color */ + &scaled_glyph); + if (unlikely (status)) { + return status; + } + + cairo_bool_t use_recording_surface = (scaled_glyph->has_info & CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE) != 0; + cairo_matrix_t glyph_matrix = scaled_glyph->surface->base.device_transform_inverse; + cairo_image_surface_t *glyph_image_surface = scaled_glyph->surface; + + // Attempt to recognize a common pattern for a bitmap font and extract the original glyph image from it + cairo_surface_t *extracted_surface; + cairo_image_surface_t *extracted_image = NULL; + void *extracted_image_extra; + if (use_recording_surface) { + cairo_recording_surface_t *recording_surface = (cairo_recording_surface_t *) scaled_glyph->recording_surface; + if (recording_surface->commands.num_elements == 1) { + cairo_command_t *command = *((cairo_command_t **) _cairo_array_index (&recording_surface->commands, 0)); + if (command->header.type == CAIRO_COMMAND_MASK && + command->header.op == CAIRO_OPERATOR_OVER && + command->header.clip == NULL && + command->mask.source.base.type == CAIRO_PATTERN_TYPE_SOLID && + _cairo_color_equal (&command->mask.source.solid.color, _cairo_stock_color (CAIRO_STOCK_BLACK)) && + command->mask.mask.base.extend == CAIRO_EXTEND_NONE && + command->mask.mask.base.type == CAIRO_PATTERN_TYPE_SURFACE && + command->mask.mask.surface.surface->type == CAIRO_SURFACE_TYPE_IMAGE) { + extracted_surface = command->mask.mask.surface.surface; + if (_cairo_surface_acquire_source_image (extracted_surface, + &extracted_image, + &extracted_image_extra) == CAIRO_STATUS_SUCCESS) { + if (extracted_image->format == CAIRO_FORMAT_A1 || extracted_image->format == CAIRO_FORMAT_A8) { + use_recording_surface = FALSE; + glyph_image_surface = extracted_image; + glyph_matrix = command->mask.mask.base.matrix; + status = cairo_matrix_invert (&glyph_matrix); + assert (status == CAIRO_STATUS_SUCCESS); + } + } + } + } + } + + cairo_surface_t *paginated_surface = _cairo_svg_surface_create_for_document (document, + CAIRO_CONTENT_COLOR_ALPHA, + 0, + 0, + FALSE); + cairo_svg_surface_t *svg_surface = (cairo_svg_surface_t *) _cairo_paginated_surface_get_target (paginated_surface); + status = paginated_surface->status; + if (unlikely (status)) { + goto cleanup; + } + + unsigned int source_id = svg_surface->base.unique_id; + + cairo_surface_set_fallback_resolution (paginated_surface, + document->owner->x_fallback_resolution, + document->owner->y_fallback_resolution); + + cairo_svg_stream_t temporary_stream = _cairo_svg_stream_create (); + + unsigned int mask_id = document->mask_id++; + + _cairo_svg_stream_printf (&temporary_stream, + "\n", + mask_id); + + cairo_pattern_t *pattern = cairo_pattern_create_for_surface (use_recording_surface ? scaled_glyph->recording_surface + : &glyph_image_surface->base); + _cairo_svg_surface_emit_composite_pattern (&temporary_stream, + svg_surface, + (cairo_surface_pattern_t *) pattern, + invalid_pattern_id, + NULL); + cairo_pattern_destroy (pattern); + + _cairo_svg_stream_printf (&temporary_stream, "\n"); + + _cairo_svg_stream_copy (&temporary_stream, &document->xml_node_defs); + + status = _cairo_svg_stream_destroy (&temporary_stream); + if (unlikely (status)) { + goto cleanup; + } + + svg_surface->transitive_paint_used = TRUE; + + _cairo_svg_stream_printf (&document->xml_node_glyphs, "xml_node_glyphs, + source_id, + CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_RECTANGLE); + _cairo_svg_stream_printf (&document->xml_node_glyphs, + " mask=\"url(#mask-%d)\"", + mask_id); + if (!use_recording_surface) { + _cairo_svg_surface_emit_transform (&document->xml_node_glyphs, + "transform", + &glyph_matrix, + NULL); + } + _cairo_svg_stream_printf (&document->xml_node_glyphs, "/>\n"); + + cairo_svg_paint_t *paint_entry = _cairo_calloc (sizeof (cairo_svg_paint_t)); + if (paint_entry == NULL) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto cleanup; + } + paint_entry->source_id = source_id; + paint_entry->box.p1.x = 0; + paint_entry->box.p1.y = 0; + paint_entry->box.p2.x = glyph_image_surface->width; + paint_entry->box.p2.y = glyph_image_surface->height; + if (use_recording_surface) { + _cairo_matrix_transform_bounding_box (&glyph_matrix, + &paint_entry->box.p1.x, &paint_entry->box.p1.y, + &paint_entry->box.p2.x, &paint_entry->box.p2.y, + NULL); + } + _cairo_svg_paint_box_add_padding (&paint_entry->box); + _cairo_array_init (&paint_entry->paint_elements, sizeof (cairo_svg_paint_element_t)); + _cairo_svg_paint_init_key (paint_entry); + status = _cairo_hash_table_insert (document->paints, &paint_entry->base); + if (unlikely (status)) { + goto cleanup; + } + + cleanup: + if (status == CAIRO_STATUS_SUCCESS) { + status = cairo_surface_status (paginated_surface); + } + cairo_surface_destroy (paginated_surface); + + if (extracted_image != NULL) { + _cairo_surface_release_source_image (extracted_surface, extracted_image, extracted_image_extra); + } + + return status; +} + +static cairo_int_status_t +_cairo_svg_document_emit_glyph (cairo_svg_document_t *document, + cairo_scaled_font_t *scaled_font, + unsigned long scaled_font_glyph_index, + unsigned int font_id, + unsigned int subset_glyph_index) +{ + cairo_int_status_t status; + + _cairo_svg_stream_printf (&document->xml_node_glyphs, + "\n", + font_id, + subset_glyph_index); + + status = _cairo_svg_document_emit_outline_glyph_data (document, + scaled_font, + scaled_font_glyph_index); + if (status == CAIRO_INT_STATUS_UNSUPPORTED) + status = _cairo_svg_document_emit_bitmap_glyph_data (document, + scaled_font, + scaled_font_glyph_index); + if (unlikely (status)) + return status; + + _cairo_svg_stream_printf (&document->xml_node_glyphs, "\n"); + + return CAIRO_INT_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_svg_document_emit_font_subset (cairo_scaled_font_subset_t *font_subset, + void *closure) +{ + cairo_svg_document_t *document = closure; + cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; + unsigned int i; + + _cairo_scaled_font_freeze_cache (font_subset->scaled_font); + for (i = 0; i < font_subset->num_glyphs; i++) { + status = _cairo_svg_document_emit_glyph (document, + font_subset->scaled_font, + font_subset->glyphs[i], + font_subset->font_id, i); + if (unlikely (status)) + break; + } + _cairo_scaled_font_thaw_cache (font_subset->scaled_font); + + return status; +} + +static cairo_status_t +_cairo_svg_document_emit_font_subsets (cairo_svg_document_t *document) +{ + cairo_status_t status; + + status = _cairo_scaled_font_subsets_foreach_scaled (document->font_subsets, + _cairo_svg_document_emit_font_subset, + document); + _cairo_scaled_font_subsets_destroy (document->font_subsets); + document->font_subsets = NULL; + + return status; +} + +static cairo_bool_t +_cairo_svg_surface_are_operation_and_pattern_supported (cairo_svg_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *pattern) +{ + if (surface->force_fallbacks) { + return FALSE; + } + + if (op == CAIRO_OPERATOR_SATURATE) { + return FALSE; + } + + /* SVG 1.1 does not support these operators. We already have code for them for SVG 2 + * that can be enabled when SVG 2 becomes widespread. */ + if (op == CAIRO_OPERATOR_OVERLAY || + op == CAIRO_OPERATOR_COLOR_DODGE || + op == CAIRO_OPERATOR_COLOR_BURN || + op == CAIRO_OPERATOR_HARD_LIGHT || + op == CAIRO_OPERATOR_SOFT_LIGHT || + op == CAIRO_OPERATOR_DIFFERENCE || + op == CAIRO_OPERATOR_EXCLUSION || + op == CAIRO_OPERATOR_HSL_HUE || + op == CAIRO_OPERATOR_HSL_SATURATION || + op == CAIRO_OPERATOR_HSL_COLOR || + op == CAIRO_OPERATOR_HSL_LUMINOSITY) { + return FALSE; + } + + if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { + /* Do not cause stack overflow because of too deep or infinite recording surfaces. */ + if (((cairo_surface_pattern_t *) pattern)->surface->type == CAIRO_SURFACE_TYPE_RECORDING && + surface->depth > 1000) { + return FALSE; + } + /* SVG doesn't support extends reflect and pad for surface pattern. */ + if (pattern->extend != CAIRO_EXTEND_NONE && pattern->extend != CAIRO_EXTEND_REPEAT) { + return FALSE; + } + } + + /* SVG 1.1 does not support the focal point (fx, fy) that is outside of the circle defined by (cx, cy) and r. */ + if (pattern->type == CAIRO_PATTERN_TYPE_RADIAL) { + cairo_radial_pattern_t *radial_pattern = (cairo_radial_pattern_t *) pattern; + double max_radius; + if (radial_pattern->cd1.radius > radial_pattern->cd2.radius) { + max_radius = radial_pattern->cd1.radius; + } else { + max_radius = radial_pattern->cd2.radius; + } + cairo_point_double_t c1 = radial_pattern->cd1.center; + cairo_point_double_t c2 = radial_pattern->cd2.center; + if ((c1.x - c2.x) * (c1.x - c2.x) + (c1.y - c2.y) * (c1.y - c2.y) >= max_radius * max_radius) { + return FALSE; + } + } + + if (pattern->type == CAIRO_PATTERN_TYPE_MESH) { + return FALSE; + } + + if (pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) { + return FALSE; + } + + return TRUE; +} + +static cairo_status_t +_cairo_svg_surface_finish (void *abstract_surface) +{ + cairo_status_t status, final_status; + cairo_svg_surface_t *surface = abstract_surface; + + if (_cairo_paginated_surface_get_target (surface->document->owner) == &surface->base) { + final_status = _cairo_svg_document_finish (surface->document); + } else { + final_status = CAIRO_STATUS_SUCCESS; + } + + status = _cairo_svg_stream_destroy (&surface->xml_node); + if (final_status == CAIRO_STATUS_SUCCESS) { + final_status = status; + } + + for (unsigned int i = 0; i < surface->page_set.num_elements; i++) { + cairo_svg_page_t *page = _cairo_array_index (&surface->page_set, i); + status = _cairo_svg_stream_destroy (&page->xml_node); + if (final_status == CAIRO_STATUS_SUCCESS) { + final_status = status; + } + } + _cairo_array_fini (&surface->page_set); + + _cairo_surface_clipper_reset (&surface->clipper); + + _cairo_hash_table_foreach (surface->source_surfaces, _cairo_svg_source_surface_pluck, surface->source_surfaces); + _cairo_hash_table_destroy (surface->source_surfaces); + + status = _cairo_svg_document_destroy (surface->document); + if (final_status == CAIRO_STATUS_SUCCESS) { + final_status = status; + } + + return final_status; +} + +static const char * +_cairo_svg_surface_emit_static_filter (cairo_svg_document_t *document, enum cairo_svg_filter filter) +{ + if (!document->filters_emitted[filter]) { + document->filters_emitted[filter] = TRUE; + if (filter == CAIRO_SVG_FILTER_REMOVE_COLOR) { + // (r, g, b, a) -> (1, 1, 1, a) + _cairo_svg_stream_printf (&document->xml_node_filters, + "\n" + "\n" + "\n"); + } else if (filter == CAIRO_SVG_FILTER_REMOVE_COLOR_AND_INVERT_ALPHA) { + // (r, g, b, a) -> (1, 1, 1, 1 - a) + _cairo_svg_stream_printf (&document->xml_node_filters, + "\n" + "\n" + "\n"); + } else if (filter == CAIRO_SVG_FILTER_COLOR_TO_ALPHA) { + // (r, g, b, a) -> (1, 1, 1, 0.2126 * r + 0.7152 * g + 0.0722 * b) + _cairo_svg_stream_printf (&document->xml_node_filters, + "\n" + "\n" + "\n"); + } + } + + if (filter == CAIRO_SVG_FILTER_REMOVE_COLOR) { + return "remove-color"; + } else if (filter == CAIRO_SVG_FILTER_REMOVE_COLOR_AND_INVERT_ALPHA) { + return "remove-color-and-invert-alpha"; + } else if (filter == CAIRO_SVG_FILTER_COLOR_TO_ALPHA) { + return "color-to-alpha"; + } else { + ASSERT_NOT_REACHED; + } + return FALSE; /* squelch warning */ +} + +#define _CAIRO_SVG_SURFACE_OUTPUT_FE_COMPOSITE_FILTER(operation) \ + _cairo_svg_stream_printf (&surface->document->xml_node_filters, \ + "\n" \ + "document->xml_node_filters, \ + surface->source_id, \ + CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_RECTANGLE_AT_ORIGIN); \ + _cairo_svg_stream_printf (&surface->document->xml_node_filters, \ + "/>\n" \ + "document->xml_node_filters, \ + surface->source_id, \ + CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_RECTANGLE_AT_ORIGIN); \ + _cairo_svg_stream_printf (&surface->document->xml_node_filters, \ + "/>\n" \ + "\n" \ + "\n", \ + filter_id, \ + source_compositing_group_id, \ + destination_compositing_group_id); + +#define _CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER(mode) \ + _cairo_svg_stream_printf (&surface->document->xml_node_filters, \ + "\n" \ + "document->xml_node_filters, \ + surface->source_id, \ + CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_RECTANGLE_AT_ORIGIN); \ + _cairo_svg_stream_printf (&surface->document->xml_node_filters, \ + "/>\n" \ + "document->xml_node_filters, \ + surface->source_id, \ + CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_RECTANGLE_AT_ORIGIN); \ + _cairo_svg_stream_printf (&surface->document->xml_node_filters, \ + "/>\n" \ + "\n" \ + "\n", \ + filter_id, \ + source_compositing_group_id, \ + destination_compositing_group_id); + +static unsigned int +_cairo_svg_surface_emit_parametric_filter (cairo_svg_surface_t *surface, + enum cairo_svg_filter filter, + unsigned int source_compositing_group_id, + unsigned int destination_compositing_group_id) +{ + unsigned int filter_id = surface->document->filter_id++; + switch (filter) { + case CAIRO_SVG_FILTER_OVER: + _CAIRO_SVG_SURFACE_OUTPUT_FE_COMPOSITE_FILTER ("over") + break; + case CAIRO_SVG_FILTER_IN: + _CAIRO_SVG_SURFACE_OUTPUT_FE_COMPOSITE_FILTER ("in") + break; + case CAIRO_SVG_FILTER_OUT: + _CAIRO_SVG_SURFACE_OUTPUT_FE_COMPOSITE_FILTER ("out") + break; + case CAIRO_SVG_FILTER_ATOP: + _CAIRO_SVG_SURFACE_OUTPUT_FE_COMPOSITE_FILTER ("atop") + break; + case CAIRO_SVG_FILTER_XOR: + _CAIRO_SVG_SURFACE_OUTPUT_FE_COMPOSITE_FILTER ("xor") + break; + case CAIRO_SVG_FILTER_ADD: + // This can also be done with , but it is not in SVG 1.1 + _cairo_svg_stream_printf (&surface->document->xml_node_filters, + "\n" + "document->xml_node_filters, + surface->source_id, + CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_RECTANGLE_AT_ORIGIN); + _cairo_svg_stream_printf (&surface->document->xml_node_filters, + "/>\n" + "document->xml_node_filters, + surface->source_id, + CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_RECTANGLE_AT_ORIGIN); + _cairo_svg_stream_printf (&surface->document->xml_node_filters, + "/>\n" + "\n" + "\n"); + break; + case CAIRO_SVG_FILTER_MULTIPLY: + _CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("multiply") + break; + case CAIRO_SVG_FILTER_SCREEN: + _CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("screen") + break; + case CAIRO_SVG_FILTER_OVERLAY: + _CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("overlay") + break; + case CAIRO_SVG_FILTER_DARKEN: + _CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("darken") + break; + case CAIRO_SVG_FILTER_LIGHTEN: + _CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("lighten") + break; + case CAIRO_SVG_FILTER_COLOR_DODGE: + _CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("color-dodge") + break; + case CAIRO_SVG_FILTER_COLOR_BURN: + _CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("color-burn") + break; + case CAIRO_SVG_FILTER_HARD_LIGHT: + _CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("hard-light") + break; + case CAIRO_SVG_FILTER_SOFT_LIGHT: + _CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("soft-light") + break; + case CAIRO_SVG_FILTER_DIFFERENCE: + _CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("difference") + break; + case CAIRO_SVG_FILTER_EXCLUSION: + _CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("exclusion") + break; + case CAIRO_SVG_FILTER_HUE: + _CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("hue") + break; + case CAIRO_SVG_FILTER_SATURATION: + _CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("saturation") + break; + case CAIRO_SVG_FILTER_COLOR: + _CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("color") + break; + case CAIRO_SVG_FILTER_LUMINOSITY: + _CAIRO_SVG_SURFACE_OUTPUT_FE_BLEND_FILTER ("luminosity") + break; + case CAIRO_SVG_FILTER_REMOVE_COLOR: + case CAIRO_SVG_FILTER_REMOVE_COLOR_AND_INVERT_ALPHA: + case CAIRO_SVG_FILTER_COLOR_TO_ALPHA: + case CAIRO_SVG_FILTER_LAST_STATIC_FILTER: + default: + ASSERT_NOT_REACHED; + } + return filter_id; +} + +typedef struct { + cairo_svg_stream_t *output; + unsigned int in_mem; + unsigned int trailing; + unsigned char src[3]; +} base64_write_closure_t; + +static char const base64_table[64] = +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static cairo_status_t +base64_write_func (void *closure, + const unsigned char *data, + unsigned int length) +{ + base64_write_closure_t *info = (base64_write_closure_t *) closure; + unsigned int i; + unsigned char *src; + + src = info->src; + + if (info->in_mem + length < 3) { + for (i = 0; i < length; i++) { + src[i + info->in_mem] = *data++; + } + info->in_mem += length; + return CAIRO_STATUS_SUCCESS; + } + + do { + unsigned char dst[4]; + + for (i = info->in_mem; i < 3; i++) { + src[i] = *data++; + length--; + } + info->in_mem = 0; + + dst[0] = base64_table[src[0] >> 2]; + dst[1] = base64_table[(src[0] & 0x03) << 4 | src[1] >> 4]; + dst[2] = base64_table[(src[1] & 0x0f) << 2 | src[2] >> 6]; + dst[3] = base64_table[src[2] & 0xfc >> 2]; + /* Special case for the last missing bits */ + switch (info->trailing) { + case 2: + dst[2] = '='; + /* fall through */ + case 1: + dst[3] = '='; + default: + break; + } + _cairo_svg_stream_write (info->output, dst, 4); + } while (length >= 3); + + for (i = 0; i < length; i++) { + src[i] = *data++; + } + info->in_mem = length; + + return info->output->status; +} + +static cairo_int_status_t +_cairo_surface_base64_encode_jpeg (cairo_surface_t *surface, + cairo_svg_stream_t *output) +{ + const unsigned char *mime_data; + unsigned long mime_data_length; + cairo_image_info_t image_info; + base64_write_closure_t info; + cairo_status_t status; + + cairo_surface_get_mime_data (surface, CAIRO_MIME_TYPE_JPEG, + &mime_data, &mime_data_length); + if (mime_data == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_image_info_get_jpeg_info (&image_info, mime_data, mime_data_length); + if (unlikely (status)) + return status; + + if (image_info.num_components == 4) + return CAIRO_INT_STATUS_UNSUPPORTED; + + _cairo_svg_stream_printf (output, "data:image/jpeg;base64,"); + + info.output = output; + info.in_mem = 0; + info.trailing = 0; + + status = base64_write_func (&info, mime_data, mime_data_length); + if (unlikely (status)) + return status; + + if (info.in_mem > 0) { + memset (info.src + info.in_mem, 0, 3 - info.in_mem); + info.trailing = 3 - info.in_mem; + info.in_mem = 3; + status = base64_write_func (&info, NULL, 0); + } + + return status; +} + +static cairo_int_status_t +_cairo_surface_base64_encode_png (cairo_surface_t *surface, + cairo_svg_stream_t *output) +{ + const unsigned char *mime_data; + unsigned long mime_data_length; + base64_write_closure_t info; + cairo_status_t status; + + cairo_surface_get_mime_data (surface, CAIRO_MIME_TYPE_PNG, + &mime_data, &mime_data_length); + if (unlikely (surface->status)) + return surface->status; + if (mime_data == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + _cairo_svg_stream_printf (output, "data:image/png;base64,"); + + info.output = output; + info.in_mem = 0; + info.trailing = 0; + + status = base64_write_func (&info, mime_data, mime_data_length); + if (unlikely (status)) + return status; + + if (info.in_mem > 0) { + memset (info.src + info.in_mem, 0, 3 - info.in_mem); + info.trailing = 3 - info.in_mem; + info.in_mem = 3; + status = base64_write_func (&info, NULL, 0); + } + + return status; +} + +static cairo_int_status_t +_cairo_surface_base64_encode (cairo_surface_t *surface, + cairo_svg_stream_t *output) +{ + cairo_int_status_t status; + base64_write_closure_t info; + + status = _cairo_surface_base64_encode_jpeg (surface, output); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + status = _cairo_surface_base64_encode_png (surface, output); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + info.output = output; + info.in_mem = 0; + info.trailing = 0; + + _cairo_svg_stream_printf (info.output, "data:image/png;base64,"); + + status = cairo_surface_write_to_png_stream (surface, base64_write_func, + (void *) &info); + + if (unlikely (status)) + return status; + + if (info.in_mem > 0) { + memset (info.src + info.in_mem, 0, 3 - info.in_mem); + info.trailing = 3 - info.in_mem; + info.in_mem = 3; + status = base64_write_func (&info, NULL, 0); + } + + return status; +} + +/** + * _cairo_svg_surface_emit_attr_value: + * + * Write the value to output the stream as a sequence of characters, + * while escaping those which have special meaning in the XML + * attribute's value context: & and ". + **/ +static void +_cairo_svg_surface_emit_attr_value (cairo_svg_stream_t *stream, + const unsigned char *value, + unsigned int length) +{ + const unsigned char *p; + const unsigned char *q; + unsigned int i; + + /* we'll accumulate non-special chars in [q, p) range */ + p = value; + q = p; + for (i = 0; i < length; i++, p++) { + if (*p == '&' || *p == '"') { + /* flush what's left before special char */ + if (p != q) { + _cairo_svg_stream_write (stream, q, p - q); + q = p + 1; + } + + if (*p == '&') + _cairo_svg_stream_printf (stream, "&"); + else // p == '"' + _cairo_svg_stream_printf (stream, """); + } + } + + /* flush the trailing chars if any */ + if (p != q) + _cairo_svg_stream_write (stream, q, p - q); +} + +static cairo_status_t +_cairo_svg_surface_emit_surface (cairo_svg_document_t *document, + cairo_surface_t *surface, + unsigned int source_id) +{ + cairo_rectangle_int_t extents; + cairo_bool_t is_bounded; + cairo_status_t status; + const unsigned char *uri; + unsigned long uri_len; + + is_bounded = _cairo_surface_get_extents (surface, &extents); + assert (is_bounded); + + _cairo_svg_stream_printf (&document->xml_node_defs, + "xml_node_defs, " xlink:href=\""); + cairo_surface_get_mime_data (surface, CAIRO_MIME_TYPE_URI, + &uri, &uri_len); + if (uri != NULL) { + _cairo_svg_surface_emit_attr_value (&document->xml_node_defs, + uri, uri_len); + } else { + status = _cairo_surface_base64_encode (surface, + &document->xml_node_defs); + if (unlikely (status)) + return status; + } + _cairo_svg_stream_printf (&document->xml_node_defs, "\""); + } + + _cairo_svg_stream_printf (&document->xml_node_defs, "/>\n"); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_svg_surface_emit_composite_surface_pattern (cairo_svg_stream_t *output, + cairo_svg_surface_t *surface, + cairo_surface_pattern_t *pattern, + unsigned int pattern_id, + const cairo_matrix_t *parent_matrix) +{ + cairo_status_t status; + + cairo_matrix_t p2u = pattern->base.matrix; + status = cairo_matrix_invert (&p2u); + /* cairo_pattern_set_matrix ensures the matrix is invertible */ + assert (status == CAIRO_STATUS_SUCCESS); + + cairo_bool_t is_new; + cairo_svg_source_surface_t *source_surface; + status = _cairo_svg_surface_add_source_surface (surface, + pattern->surface, + &is_new, + &source_surface); + if (unlikely (status)) { + return status; + } + unsigned int source_id = source_surface->id; + + if (is_new) { + status = _cairo_svg_surface_emit_surface (surface->document, + pattern->surface, + source_id); + if (unlikely (status)) { + return status; + } + } + + if (pattern_id != invalid_pattern_id) { + cairo_rectangle_int_t extents; + cairo_bool_t is_bounded; + + is_bounded = _cairo_surface_get_extents (pattern->surface, &extents); + assert (is_bounded); + + _cairo_svg_stream_printf (output, + "\n"); + } + + _cairo_svg_stream_printf (output, + "surface->content == CAIRO_CONTENT_ALPHA) { + cairo_bool_t can_skip_filter = FALSE; + if (pattern->surface->backend && + pattern->surface->backend->type == CAIRO_SURFACE_TYPE_IMAGE && + (((cairo_image_surface_t *) pattern->surface)->format == CAIRO_FORMAT_A1 || + ((cairo_image_surface_t *) pattern->surface)->format == CAIRO_FORMAT_A8)) { + can_skip_filter = TRUE; + } + if (!can_skip_filter) { + _cairo_svg_stream_printf (output, + " filter=\"url(#filter-%s)\"", + _cairo_svg_surface_emit_static_filter (surface->document, + CAIRO_SVG_FILTER_COLOR_TO_ALPHA)); + } + } + if (pattern_id == invalid_pattern_id) { + _cairo_svg_surface_emit_transform (output, + "transform", + &p2u, + parent_matrix); + } + _cairo_svg_stream_printf (output, "/>\n"); + + if (pattern_id != invalid_pattern_id) { + _cairo_svg_stream_printf (output, "\n"); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_svg_surface_emit_recording_surface (cairo_svg_surface_t *surface, + cairo_recording_surface_t *source, + unsigned int source_id, + cairo_bool_t *transitive_paint_used) +{ + cairo_status_t status; + cairo_svg_document_t *document = surface->document; + + cairo_surface_t *paginated_surface = _cairo_svg_surface_create_for_document (document, + source->base.content, + 0, + 0, + FALSE); + cairo_svg_surface_t *svg_surface = (cairo_svg_surface_t *) _cairo_paginated_surface_get_target (paginated_surface); + if (unlikely (paginated_surface->status)) { + return paginated_surface->status; + } + + svg_surface->source_id = source_id; + svg_surface->depth = surface->depth + 1; + + cairo_rectangle_int_t extents; + cairo_bool_t bounded = _cairo_surface_get_extents (&source->base, &extents); + + cairo_surface_set_fallback_resolution (paginated_surface, + document->owner->x_fallback_resolution, + document->owner->y_fallback_resolution); + + if (source->base.content == CAIRO_CONTENT_COLOR) { + _cairo_svg_surface_emit_paint (&svg_surface->xml_node, svg_surface, &_cairo_pattern_black.base, FALSE); + } + status = _cairo_recording_surface_replay (&source->base, paginated_surface); + if (unlikely (status)) { + cairo_surface_destroy (paginated_surface); + return status; + } + + cairo_surface_show_page (paginated_surface); + status = cairo_surface_status (paginated_surface); + if (unlikely (status)) { + cairo_surface_destroy (paginated_surface); + return status; + } + + unsigned int clip_id; + if (bounded) { + clip_id = document->clip_id++; + + _cairo_svg_stream_printf (&document->xml_node_defs, + "\n" + "\n" + "\n", + clip_id, + extents.x, + extents.y, + extents.width, + extents.height); + } + + _cairo_svg_stream_printf (&document->xml_node_defs, + "xml_node_defs, + " clip-path=\"url(#clip-%d)\"", + clip_id); + } + + if (source->base.content == CAIRO_CONTENT_ALPHA) { + _cairo_svg_stream_printf (&document->xml_node_defs, + " filter=\"url(#filter-%s)\"", + _cairo_svg_surface_emit_static_filter (document, CAIRO_SVG_FILTER_REMOVE_COLOR)); + } + + _cairo_svg_stream_printf (&document->xml_node_defs, ">\n"); + + if (svg_surface->xml_node.elements.num_elements > 0) { + cairo_svg_page_t *page = _cairo_svg_surface_store_page (svg_surface); + if (unlikely (page == NULL)) { + cairo_surface_destroy (paginated_surface); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + } + + if (svg_surface->page_set.num_elements > 0) { + cairo_svg_page_t *page = _cairo_array_index (&svg_surface->page_set, svg_surface->page_set.num_elements - 1); + _cairo_svg_stream_copy (&page->xml_node, &document->xml_node_defs); + } + + _cairo_svg_stream_printf (&document->xml_node_defs, "\n"); + + *transitive_paint_used = svg_surface->transitive_paint_used; + + status = cairo_surface_status (paginated_surface); + cairo_surface_destroy (paginated_surface); + + return status; +} + +static cairo_recording_surface_t * +_cairo_svg_surface_to_recording_surface (const cairo_surface_pattern_t *pattern) +{ + cairo_surface_t *surface = pattern->surface; + if (_cairo_surface_is_paginated (surface)) + surface = _cairo_paginated_surface_get_recording (surface); + if (_cairo_surface_is_snapshot (surface)) + surface = _cairo_surface_snapshot_get_target (surface); + return (cairo_recording_surface_t *) surface; +} + +static cairo_bool_t +_cairo_svg_surface_svg_pattern_should_be_used (const cairo_pattern_t *pattern) +{ + cairo_rectangle_int_t extents; + return pattern->type == CAIRO_PATTERN_TYPE_SURFACE && + pattern->extend == CAIRO_EXTEND_REPEAT && + _cairo_surface_get_extents (((cairo_surface_pattern_t *) pattern)->surface, &extents); +} + +static cairo_bool_t +_cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (const cairo_pattern_t *pattern) +{ + return pattern->type == CAIRO_PATTERN_TYPE_SURFACE && !_cairo_svg_surface_svg_pattern_should_be_used (pattern); +} + +static cairo_status_t +_cairo_svg_surface_emit_composite_recording_pattern (cairo_svg_stream_t *output, + cairo_svg_surface_t *surface, + cairo_surface_pattern_t *pattern, + unsigned int pattern_id, + const cairo_matrix_t *parent_matrix) +{ + cairo_status_t status; + cairo_svg_document_t *document = surface->document; + + cairo_matrix_t p2u = pattern->base.matrix; + status = cairo_matrix_invert (&p2u); + /* cairo_pattern_set_matrix ensures the matrix is invertible */ + assert (status == CAIRO_STATUS_SUCCESS); + + cairo_bool_t is_new; + cairo_svg_source_surface_t *source_surface; + status = _cairo_svg_surface_add_source_surface (surface, + pattern->surface, + &is_new, + &source_surface); + if (unlikely (status)) { + return status; + } + unsigned int source_id = source_surface->id; + + cairo_recording_surface_t *recording_surface = _cairo_svg_surface_to_recording_surface (pattern); + if (is_new) { + status = _cairo_svg_surface_emit_recording_surface (surface, + recording_surface, + source_id, + &source_surface->transitive_paint_used); + if (unlikely (status)) { + return status; + } + + if (source_surface->transitive_paint_used) { + cairo_svg_paint_t *paint_entry = _cairo_calloc (sizeof (cairo_svg_paint_t)); + if (paint_entry == NULL) { + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + paint_entry->source_id = source_id; + _cairo_array_init (&paint_entry->paint_elements, sizeof (cairo_svg_paint_element_t)); + _cairo_svg_paint_init_key (paint_entry); + status = _cairo_hash_table_insert (document->paints, &paint_entry->base); + if (unlikely (status)) { + return status; + } + } + } + + if (source_surface->transitive_paint_used) { + cairo_svg_paint_t paint_key; + paint_key.source_id = source_id; + _cairo_svg_paint_init_key (&paint_key); + + cairo_svg_paint_t *found_paint_entry = _cairo_hash_table_lookup (document->paints, + &paint_key.base); + assert (found_paint_entry); + + cairo_svg_paint_element_t paint_element; + paint_element.source_id = surface->source_id; + paint_element.matrix = pattern->base.matrix; + if (parent_matrix != NULL) { + cairo_matrix_t parent_matrix_inverse = *parent_matrix; + status = cairo_matrix_invert (&parent_matrix_inverse); + /* cairo_pattern_set_matrix ensures the matrix is invertible */ + assert (status == CAIRO_STATUS_SUCCESS); + cairo_matrix_multiply (&paint_element.matrix, &parent_matrix_inverse, &paint_element.matrix); + } + status = _cairo_array_append (&found_paint_entry->paint_elements, &paint_element); + if (unlikely (status)) { + return status; + } + + surface->transitive_paint_used = TRUE; + } + + if (pattern_id != invalid_pattern_id) { + assert (!recording_surface->unbounded); + _cairo_svg_stream_printf (output, + "extents_pixels.x, + recording_surface->extents_pixels.y, + recording_surface->extents_pixels.width, + recording_surface->extents_pixels.height, + recording_surface->extents_pixels.x, + recording_surface->extents_pixels.y, + recording_surface->extents_pixels.width, + recording_surface->extents_pixels.height); + _cairo_svg_surface_emit_transform (output, "patternTransform", &p2u, parent_matrix); + _cairo_svg_stream_printf (output, ">\n"); + } + + _cairo_svg_stream_printf (output, + "\n"); + + if (pattern_id != invalid_pattern_id) { + _cairo_svg_stream_printf (output, "\n"); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_svg_surface_emit_composite_pattern (cairo_svg_stream_t *output, + cairo_svg_surface_t *surface, + cairo_surface_pattern_t *pattern, + unsigned int pattern_id, + const cairo_matrix_t *parent_matrix) +{ + if (pattern_id != invalid_pattern_id) { + assert (_cairo_svg_surface_svg_pattern_should_be_used (&pattern->base)); + } + + if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) { + return _cairo_svg_surface_emit_composite_recording_pattern (output, + surface, + pattern, + pattern_id, + parent_matrix); + } else { + return _cairo_svg_surface_emit_composite_surface_pattern (output, + surface, + pattern, + pattern_id, + parent_matrix); + } +} + +static cairo_status_t +_cairo_svg_surface_emit_solid_pattern (cairo_svg_surface_t *surface, + cairo_solid_pattern_t *pattern, + cairo_svg_stream_t *output, + cairo_bool_t is_stroke) +{ + _cairo_svg_stream_printf (output, + is_stroke ? " stroke=\"rgb(%f%%, %f%%, %f%%)\" stroke-opacity=\"%f\"" + : " fill=\"rgb(%f%%, %f%%, %f%%)\" fill-opacity=\"%f\"", + pattern->color.red * 100.0, + pattern->color.green * 100.0, + pattern->color.blue * 100.0, + pattern->color.alpha); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_svg_surface_emit_surface_pattern (cairo_svg_surface_t *surface, + cairo_surface_pattern_t *pattern, + cairo_svg_stream_t *output, + cairo_bool_t is_stroke, + const cairo_matrix_t *parent_matrix) +{ + cairo_svg_document_t *document = surface->document; + cairo_status_t status; + + unsigned int pattern_id = document->pattern_id++; + + status = _cairo_svg_surface_emit_composite_pattern (&document->xml_node_defs, + surface, + pattern, + pattern_id, + parent_matrix); + if (unlikely (status)) + return status; + + _cairo_svg_stream_printf (output, + is_stroke ? " stroke=\"url(#pattern-%d)\"" + : " fill=\"url(#pattern-%d)\"", + pattern_id); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_svg_surface_emit_pattern_stops (cairo_svg_stream_t *output, + const cairo_gradient_pattern_t *pattern, + double start_offset, + cairo_bool_t reverse_stops, + cairo_bool_t emulate_reflect) +{ + cairo_gradient_stop_t *stops; + unsigned int n_stops; + + if (pattern->n_stops < 1) { + return CAIRO_STATUS_SUCCESS; + } + + if (pattern->n_stops == 1) { + _cairo_svg_stream_printf (output, + "\n", + pattern->stops[0].offset, + pattern->stops[0].color.red * 100.0, + pattern->stops[0].color.green * 100.0, + pattern->stops[0].color.blue * 100.0, + pattern->stops[0].color.alpha); + return CAIRO_STATUS_SUCCESS; + } + + if (emulate_reflect || reverse_stops) { + n_stops = emulate_reflect ? pattern->n_stops * 2 - 2 : pattern->n_stops; + stops = _cairo_malloc_ab (n_stops, sizeof (cairo_gradient_stop_t)); + if (unlikely (stops == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + for (unsigned int i = 0; i < pattern->n_stops; i++) { + if (reverse_stops) { + stops[i] = pattern->stops[pattern->n_stops - i - 1]; + stops[i].offset = 1.0 - stops[i].offset; + } else { + stops[i] = pattern->stops[i]; + } + if (emulate_reflect) { + stops[i].offset *= 0.5; + if (i > 0 && i < pattern->n_stops - 1) { + if (reverse_stops) { + stops[i + pattern->n_stops - 1] = pattern->stops[i]; + stops[i + pattern->n_stops - 1].offset = 0.5 + 0.5 * stops[i + pattern->n_stops - 1].offset; + } else { + stops[i + pattern->n_stops - 1] = pattern->stops[pattern->n_stops - i - 1]; + stops[i + pattern->n_stops - 1].offset = 1.0 - 0.5 * stops[i + pattern->n_stops - 1].offset; + } + } + } + } + } else { + n_stops = pattern->n_stops; + stops = pattern->stops; + } + + if (start_offset >= 0.0) { + for (unsigned int i = 0; i < n_stops; i++) { + _cairo_svg_stream_printf (output, + "\n", + start_offset + (1.0 - start_offset) * stops[i].offset, + stops[i].color.red * 100.0, + stops[i].color.green * 100.0, + stops[i].color.blue * 100.0, + stops[i].color.alpha); + } + } else { + cairo_bool_t found = FALSE; + unsigned int offset_index; + cairo_color_stop_t offset_color_start, offset_color_stop; + + for (unsigned int i = 0; i <= n_stops; i++) { + double x1 = i == n_stops ? stops[0].offset + 1 : stops[i].offset; + cairo_color_stop_t *color1 = i == n_stops ? &stops[0].color : &stops[i].color; + if (x1 >= -start_offset) { + if (i > 0) { + double x0 = stops[i - 1].offset; + cairo_color_stop_t *color0 = &stops[i - 1].color; + if (x0 != x1) { + offset_color_start.red = color0->red + (color1->red - color0->red) + * (-start_offset - x0) / (x1 - x0); + offset_color_start.green = color0->green + (color1->green - color0->green) + * (-start_offset - x0) / (x1 - x0); + offset_color_start.blue = color0->blue + (color1->blue - color0->blue) + * (-start_offset - x0) / (x1 - x0); + offset_color_start.alpha = color0->alpha + (color1->alpha - color0->alpha) + * (-start_offset - x0) / (x1 - x0); + offset_color_stop = offset_color_start; + } else { + offset_color_stop = stops[i - 1].color; + offset_color_start = stops[i].color; + } + } else { + offset_color_stop = offset_color_start = stops[i].color; + } + offset_index = i; + found = TRUE; + break; + } + } + + if (!found) { + offset_index = n_stops - 1; + offset_color_stop = offset_color_start = stops[offset_index].color; + } + + _cairo_svg_stream_printf (output, + "\n", + offset_color_start.red * 100.0, + offset_color_start.green * 100.0, + offset_color_start.blue * 100.0, + offset_color_start.alpha); + for (unsigned int i = offset_index; i < n_stops; i++) { + _cairo_svg_stream_printf (output, + "\n", + stops[i].offset + start_offset, + stops[i].color.red * 100.0, + stops[i].color.green * 100.0, + stops[i].color.blue * 100.0, + stops[i].color.alpha); + } + for (unsigned int i = 0; i < offset_index; i++) { + _cairo_svg_stream_printf (output, + "\n", + 1.0 + stops[i].offset + start_offset, + stops[i].color.red * 100.0, + stops[i].color.green * 100.0, + stops[i].color.blue * 100.0, + stops[i].color.alpha); + } + + _cairo_svg_stream_printf (output, + "\n", + offset_color_stop.red * 100.0, + offset_color_stop.green * 100.0, + offset_color_stop.blue * 100.0, + offset_color_stop.alpha); + + } + + if (reverse_stops || emulate_reflect) { + free (stops); + } + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_svg_surface_emit_pattern_extend (cairo_svg_stream_t *output, + cairo_pattern_t *pattern) +{ + switch (pattern->extend) { + case CAIRO_EXTEND_REPEAT: + _cairo_svg_stream_printf (output, " spreadMethod=\"repeat\""); + break; + case CAIRO_EXTEND_REFLECT: + _cairo_svg_stream_printf (output, " spreadMethod=\"reflect\""); + break; + case CAIRO_EXTEND_NONE: + case CAIRO_EXTEND_PAD: + break; + } +} + +static cairo_status_t +_cairo_svg_surface_emit_linear_pattern (cairo_svg_surface_t *surface, + cairo_linear_pattern_t *pattern, + cairo_svg_stream_t *output, + cairo_bool_t is_stroke, + const cairo_matrix_t *parent_matrix) +{ + cairo_status_t status; + cairo_svg_document_t *document = surface->document; + + cairo_matrix_t p2u = pattern->base.base.matrix; + status = cairo_matrix_invert (&p2u); + /* cairo_pattern_set_matrix ensures the matrix is invertible */ + assert (status == CAIRO_STATUS_SUCCESS); + + unsigned int linear_pattern_id = document->linear_pattern_id++; + + _cairo_svg_stream_printf (&document->xml_node_defs, + "pd1.x, pattern->pd1.y, + pattern->pd2.x, pattern->pd2.y); + + _cairo_svg_surface_emit_pattern_extend (&document->xml_node_defs, &pattern->base.base); + _cairo_svg_surface_emit_transform (&document->xml_node_defs, "gradientTransform", &p2u, parent_matrix); + _cairo_svg_stream_printf (&document->xml_node_defs, ">\n"); + + status = _cairo_svg_surface_emit_pattern_stops (&document->xml_node_defs, + &pattern->base, + 0.0, + FALSE, + FALSE); + if (unlikely (status)) + return status; + + _cairo_svg_stream_printf (&document->xml_node_defs, + "\n"); + + _cairo_svg_stream_printf (output, + is_stroke ? " stroke=\"url(#linear-pattern-%d)\"" + : " fill=\"url(#linear-pattern-%d)\"", + linear_pattern_id); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_svg_surface_emit_radial_pattern (cairo_svg_surface_t *surface, + cairo_radial_pattern_t *pattern, + cairo_svg_stream_t *output, + cairo_bool_t is_stroke, + const cairo_matrix_t *parent_matrix) +{ + cairo_status_t status; + cairo_svg_document_t *document = surface->document; + + cairo_extend_t extend = pattern->base.base.extend; + + cairo_bool_t reverse_stops; + cairo_circle_double_t *c0, *c1; + if (pattern->cd1.radius < pattern->cd2.radius) { + c0 = &pattern->cd1; + c1 = &pattern->cd2; + reverse_stops = FALSE; + } else { + c0 = &pattern->cd2; + c1 = &pattern->cd1; + reverse_stops = TRUE; + } + + double x0 = c0->center.x; + double y0 = c0->center.y; + double r0 = c0->radius; + double x1 = c1->center.x; + double y1 = c1->center.y; + double r1 = c1->radius; + + cairo_matrix_t p2u = pattern->base.base.matrix; + status = cairo_matrix_invert (&p2u); + /* cairo_pattern_set_matrix ensures the matrix is invertible */ + assert (status == CAIRO_STATUS_SUCCESS); + + unsigned int radial_pattern_id = document->radial_pattern_id++; + + double start_offset; + cairo_bool_t emulate_reflect = FALSE; + + double fx = (r1 * x0 - r0 * x1) / (r1 - r0); + double fy = (r1 * y0 - r0 * y1) / (r1 - r0); + + /* SVG doesn't support the inner circle and use instead a gradient focal. + * That means we need to emulate the cairo behaviour by processing the + * cairo gradient stops. + * The CAIRO_EXTEND_NONE and CAIRO_EXTEND_PAD modes are quite easy to handle, + * it's just a matter of stop position translation and calculation of + * the corresponding SVG radial gradient focal. + * The CAIRO_EXTEND_REFLECT and CAIRO_EXTEND_REPEAT modes require to compute a new + * radial gradient, with an new outer circle, equal to r1 - r0 in the CAIRO_EXTEND_REPEAT + * case, and 2 * r1 - r0 in the CAIRO_EXTEND_REFLECT case, and a new gradient stop + * list that maps to the original cairo stop list. + */ + if ((extend == CAIRO_EXTEND_REFLECT || extend == CAIRO_EXTEND_REPEAT) && r0 > 0.0) { + double r_org = r1; + + if (extend == CAIRO_EXTEND_REFLECT) { + r1 = 2.0 * r1 - r0; + emulate_reflect = TRUE; + } + + start_offset = fmod (r1, r1 - r0) / (r1 - r0) - 1.0; + double r = r1 - r0; + + /* New position of outer circle. */ + double x = r * (x1 - fx) / r_org + fx; + double y = r * (y1 - fy) / r_org + fy; + + x1 = x; + y1 = y; + r1 = r; + r0 = 0.0; + } else { + start_offset = r0 / r1; + } + + _cairo_svg_stream_printf (&document->xml_node_defs, + "xml_node_defs, " spreadMethod=\"repeat\""); + } else { + _cairo_svg_surface_emit_pattern_extend (&document->xml_node_defs, &pattern->base.base); + } + _cairo_svg_surface_emit_transform (&document->xml_node_defs, "gradientTransform", &p2u, parent_matrix); + _cairo_svg_stream_printf (&document->xml_node_defs, ">\n"); + + /* To support cairo's EXTEND_NONE, (for which SVG has no similar + * notion), we add transparent color stops on either end of the + * user-provided stops. */ + if (extend == CAIRO_EXTEND_NONE) { + _cairo_svg_stream_printf (&document->xml_node_defs, + "\n"); + if (r0 != 0.0) { + _cairo_svg_stream_printf (&document->xml_node_defs, + "\n", + r0 / r1); + } + } + status = _cairo_svg_surface_emit_pattern_stops (&document->xml_node_defs, + &pattern->base, + start_offset, + reverse_stops, + emulate_reflect); + if (unlikely (status)) { + return status; + } + + if (pattern->base.base.extend == CAIRO_EXTEND_NONE) { + _cairo_svg_stream_printf (&document->xml_node_defs, + "\n"); + } + + _cairo_svg_stream_printf (&document->xml_node_defs, + "\n"); + + _cairo_svg_stream_printf (output, + is_stroke ? " stroke=\"url(#radial-pattern-%d)\"" + : " fill=\"url(#radial-pattern-%d)\"", + radial_pattern_id); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_svg_surface_emit_pattern (cairo_svg_surface_t *surface, + const cairo_pattern_t *pattern, + cairo_svg_stream_t *output, + cairo_bool_t is_stroke, + const cairo_matrix_t *parent_matrix) +{ + switch (pattern->type) { + case CAIRO_PATTERN_TYPE_SOLID: + return _cairo_svg_surface_emit_solid_pattern (surface, (cairo_solid_pattern_t *) pattern, + output, is_stroke); + + case CAIRO_PATTERN_TYPE_SURFACE: + return _cairo_svg_surface_emit_surface_pattern (surface, (cairo_surface_pattern_t *) pattern, + output, is_stroke, parent_matrix); + + case CAIRO_PATTERN_TYPE_LINEAR: + return _cairo_svg_surface_emit_linear_pattern (surface, (cairo_linear_pattern_t *) pattern, + output, is_stroke, parent_matrix); + + case CAIRO_PATTERN_TYPE_RADIAL: + return _cairo_svg_surface_emit_radial_pattern (surface, (cairo_radial_pattern_t *) pattern, + output, is_stroke, parent_matrix); + + case CAIRO_PATTERN_TYPE_MESH: + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + ASSERT_NOT_REACHED; + } + return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH); +} + +static cairo_status_t +_cairo_svg_surface_emit_fill_style (cairo_svg_stream_t *output, + cairo_svg_surface_t *surface, + const cairo_pattern_t *source, + cairo_fill_rule_t fill_rule, + const cairo_matrix_t *parent_matrix) +{ + _cairo_svg_stream_printf (output, + " fill-rule=\"%s\"", + fill_rule == CAIRO_FILL_RULE_EVEN_ODD ? "evenodd" : "nonzero"); + return _cairo_svg_surface_emit_pattern (surface, source, output, FALSE, parent_matrix); +} + +static cairo_status_t +_cairo_svg_surface_emit_stroke_style (cairo_svg_stream_t *output, + cairo_svg_surface_t *surface, + const cairo_pattern_t *source, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *parent_matrix) +{ + cairo_status_t status; + const char *line_cap, *line_join; + unsigned int i; + + switch (stroke_style->line_cap) { + case CAIRO_LINE_CAP_BUTT: + line_cap = "butt"; + break; + case CAIRO_LINE_CAP_ROUND: + line_cap = "round"; + break; + case CAIRO_LINE_CAP_SQUARE: + line_cap = "square"; + break; + default: + ASSERT_NOT_REACHED; + } + + switch (stroke_style->line_join) { + case CAIRO_LINE_JOIN_MITER: + line_join = "miter"; + break; + case CAIRO_LINE_JOIN_ROUND: + line_join = "round"; + break; + case CAIRO_LINE_JOIN_BEVEL: + line_join = "bevel"; + break; + default: + ASSERT_NOT_REACHED; + } + + if (stroke_style->is_hairline) { + _cairo_svg_stream_printf (output, + " stroke-width=\"1px\"" + " stroke-linecap=\"%s\"" + " stroke-linejoin=\"%s\"" + " style=\"vector-effect: non-scaling-stroke\"", + line_cap, + line_join); + } else { + _cairo_svg_stream_printf (output, + " stroke-width=\"%f\"" + " stroke-linecap=\"%s\"" + " stroke-linejoin=\"%s\"", + stroke_style->line_width, + line_cap, + line_join); + } + + status = _cairo_svg_surface_emit_pattern (surface, source, output, TRUE, parent_matrix); + if (unlikely (status)) { + return status; + } + + if (stroke_style->num_dashes > 0) { + _cairo_svg_stream_printf (output, " stroke-dasharray=\""); + for (i = 0; i < stroke_style->num_dashes; i++) { + _cairo_svg_stream_printf (output, + "%f", + stroke_style->dash[i]); + _cairo_svg_stream_printf (output, i + 1 < stroke_style->num_dashes ? " " : "\""); + } + if (stroke_style->dash_offset != 0.0) { + _cairo_svg_stream_printf (output, + " stroke-dashoffset=\"%f\"", + stroke_style->dash_offset); + } + } + + _cairo_svg_stream_printf (output, + " stroke-miterlimit=\"%f\"", + stroke_style->miter_limit); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_bool_t +_cairo_svg_surface_get_extents (void *abstract_surface, + cairo_rectangle_int_t *rectangle) +{ + cairo_svg_surface_t *surface = abstract_surface; + + rectangle->x = 0; + rectangle->y = 0; + + /* XXX: The conversion to integers here is pretty bogus, (not to + * mention the arbitrary limitation of width to a short(!). We + * may need to come up with a better interface for get_size. + */ + rectangle->width = ceil (surface->width); + rectangle->height = ceil (surface->height); + + return surface->surface_bounded; +} + +static cairo_status_t +_cairo_svg_surface_emit_paint (cairo_svg_stream_t *output, + cairo_svg_surface_t *surface, + const cairo_pattern_t *source, + cairo_bool_t at_origin) +{ + cairo_status_t status; + + if (_cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (source)) { + return _cairo_svg_surface_emit_composite_pattern (output, + surface, + (cairo_surface_pattern_t *) source, + invalid_pattern_id, + NULL); + } + + surface->transitive_paint_used = TRUE; + + _cairo_svg_stream_printf (output, "source_id, + CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_RECTANGLE_AT_ORIGIN); + } else { + _cairo_svg_stream_append_paint_dependent (output, + surface->source_id, + CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_RECTANGLE); + } + status = _cairo_svg_surface_emit_pattern (surface, source, output, FALSE, NULL); + if (unlikely (status)) { + return status; + } + _cairo_svg_stream_printf (output, "/>\n"); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_svg_surface_do_operator (cairo_svg_stream_t *output, + cairo_svg_surface_t *surface, + cairo_operator_t op, + const cairo_clip_t *clip, + cairo_svg_stream_t *mask_stream, + cairo_svg_stream_t *source_stream, + cairo_svg_stream_t *destination_stream) +{ + cairo_status_t status; + cairo_svg_document_t *document = surface->document; + + // For operators that do not always produce opaque output, we first need to emit a black paint + // if the content does not have alpha + if (surface->base.content == CAIRO_CONTENT_COLOR && (op == CAIRO_OPERATOR_CLEAR || + op == CAIRO_OPERATOR_SOURCE || + op == CAIRO_OPERATOR_IN || + op == CAIRO_OPERATOR_OUT || + op == CAIRO_OPERATOR_DEST_IN || + op == CAIRO_OPERATOR_DEST_OUT || + op == CAIRO_OPERATOR_DEST_ATOP || + op == CAIRO_OPERATOR_XOR)) { + _cairo_svg_surface_emit_paint (output, surface, &_cairo_pattern_black.base, FALSE); + } + + if (op == CAIRO_OPERATOR_CLEAR) { + /* + * The result is the same as one of the SOURCE operation application with the same arguments, + * but with an empty source. + */ + + status = _cairo_svg_stream_destroy (source_stream); + if (unlikely (status)) { + (void) _cairo_svg_stream_destroy (destination_stream); + (void) _cairo_svg_stream_destroy (mask_stream); + return status; + } + cairo_svg_stream_t empty_stream = _cairo_svg_stream_create (); + return _cairo_svg_surface_do_operator (output, + surface, + CAIRO_OPERATOR_SOURCE, + clip, + mask_stream, + &empty_stream, + destination_stream); + } + + if (op == CAIRO_OPERATOR_SOURCE) { + /* + * Below we use the "Bounded" equation with SOURCE as the operation from the "Clipping and masking" section + * of https://cairographics.org/operators/: + * result = source LEPR_(clip IN mask) destination + * + * It is equivalent to: + * result = (source IN (clip IN mask)) ADD (destination IN (NOT (clip IN mask))) + * + * 1. We put the clip masked with the mask into the SVG group `lerp_compositing_group`. + * 2. `positive_lerp_mask` is an SVG mask with `lerp_compositing_group`. + * 3. `negative_lerp_mask` is an SVG mask with inverted `lerp_compositing_group`. + * 5. We put the source masked with `positive_lerp_mask` into the SVG group `lerped_source_compositing_group`. + * 6. We put the destination masked with `negative_lerp_mask` into + * the SVG group `lerped_destination_compositing_group`. + * 7. The result is addition of `lerped_source_compositing_group` and `lerped_destination_compositing_group`. + */ + + unsigned int lerp_compositing_group_id = document->compositing_group_id++; + _cairo_svg_stream_printf (&document->xml_node_defs, + "xml_node_defs, + surface->source_id, + CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_INVERSE_TRANSLATION); + _cairo_svg_stream_printf (&document->xml_node_defs, ">\n"); + _cairo_svg_surface_emit_paint (&document->xml_node_defs, surface, &_cairo_pattern_clear.base, FALSE); + status = _cairo_svg_surface_set_clip (surface, &document->xml_node_defs, clip); + if (unlikely (status)) { + (void) _cairo_svg_stream_destroy (destination_stream); + (void) _cairo_svg_stream_destroy (source_stream); + (void) _cairo_svg_stream_destroy (mask_stream); + return status; + } + _cairo_svg_stream_copy (mask_stream, &document->xml_node_defs); + status = _cairo_svg_stream_destroy (mask_stream); + if (unlikely (status)) { + (void) _cairo_svg_stream_destroy (destination_stream); + (void) _cairo_svg_stream_destroy (source_stream); + return status; + } + _cairo_svg_surface_reset_clip (surface); + _cairo_svg_stream_printf (&document->xml_node_defs, "\n"); + + unsigned int positive_lerp_mask_id = document->mask_id++; + _cairo_svg_stream_printf (&document->xml_node_defs, + "\n", + positive_lerp_mask_id); + _cairo_svg_stream_printf (&document->xml_node_defs, + "\n", + lerp_compositing_group_id); + _cairo_svg_stream_printf (&document->xml_node_defs, "\n"); + + unsigned int negative_lerp_mask_id = document->mask_id++; + _cairo_svg_stream_printf (&document->xml_node_defs, + "\n", + negative_lerp_mask_id); + _cairo_svg_stream_printf (&document->xml_node_defs, + "\n", + lerp_compositing_group_id, + _cairo_svg_surface_emit_static_filter (document, + CAIRO_SVG_FILTER_REMOVE_COLOR_AND_INVERT_ALPHA)); + _cairo_svg_stream_printf (&document->xml_node_defs, "\n"); + + unsigned int lerped_source_compositing_group_id = document->compositing_group_id++; + _cairo_svg_stream_printf (&document->xml_node_defs, + "\n", + lerped_source_compositing_group_id, + positive_lerp_mask_id); + _cairo_svg_stream_printf (&document->xml_node_defs, "xml_node_defs, + surface->source_id, + CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_INVERSE_TRANSLATION); + _cairo_svg_stream_printf (&document->xml_node_defs, ">\n"); + _cairo_svg_stream_copy (source_stream, &document->xml_node_defs); + status = _cairo_svg_stream_destroy (source_stream); + if (unlikely (status)) { + (void) _cairo_svg_stream_destroy (destination_stream); + return status; + } + _cairo_svg_stream_printf (&document->xml_node_defs, "\n"); + _cairo_svg_stream_printf (&document->xml_node_defs, "\n"); + + unsigned int lerped_destination_compositing_group_id = document->compositing_group_id++; + _cairo_svg_stream_printf (&document->xml_node_defs, + "\n", + lerped_destination_compositing_group_id, + negative_lerp_mask_id); + _cairo_svg_stream_printf (&document->xml_node_defs, "xml_node_defs, + surface->source_id, + CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_INVERSE_TRANSLATION); + _cairo_svg_stream_printf (&document->xml_node_defs, ">\n"); + _cairo_svg_stream_copy (destination_stream, &document->xml_node_defs); + status = _cairo_svg_stream_destroy (destination_stream); + if (unlikely (status)) { + return status; + } + _cairo_svg_stream_printf (&document->xml_node_defs, "\n"); + _cairo_svg_stream_printf (&document->xml_node_defs, "\n"); + + _cairo_svg_stream_printf (&surface->xml_node, + "xml_node, + surface->source_id, + CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_TRANSLATION); + _cairo_svg_stream_printf (&surface->xml_node, ">\n"); + status = _cairo_svg_surface_emit_paint (&surface->xml_node, surface, &_cairo_pattern_black.base, TRUE); + if (unlikely (status)) { + return status; + } + _cairo_svg_stream_printf (&surface->xml_node, "\n"); + + return CAIRO_STATUS_SUCCESS; + } + + if (op == CAIRO_OPERATOR_DEST) { + /* + * The result is the destination. + */ + + _cairo_svg_stream_copy (destination_stream, &surface->xml_node); + status = _cairo_svg_stream_destroy (destination_stream); + if (unlikely (status)) { + (void) _cairo_svg_stream_destroy (source_stream); + (void) _cairo_svg_stream_destroy (mask_stream); + return status; + } + status = _cairo_svg_stream_destroy (source_stream); + if (unlikely (status)) { + (void) _cairo_svg_stream_destroy (source_stream); + return status; + } + status = _cairo_svg_stream_destroy (source_stream); + if (unlikely (status)) { + return status; + } + return CAIRO_STATUS_SUCCESS; + } + + /* + * Below we use the "XRender" equation from the "Clipping and masking" section + * of https://cairographics.org/operators/: + * result = ((source IN mask) OP destination) LERP_clip destination + * + * It is equivalent to: + * result = (((source IN mask) OP destination) IN clip) ADD (destination IN (NOT clip)) + * + * 1. We put the clip into the SVG group `lerp_compositing_group`. + * 2. `positive_lerp_mask` is an SVG mask with `lerp_compositing_group`. + * 3. `negative_lerp_mask` is an SVG mask with inverted `lerp_compositing_group`. + * 4. We put the mask into the SVG mask `mask_mask`. + * 5. We put the source masked with `mask_mask` into the SVG group `masked_source_compositing_group`. + * 6. We put the destination into the SVG group `destination_compositing_group`. + * 7. `lerped_operation_compositing_group` is an SVG group of operation applied to + * (`masked_source_compositing_group`, `destination_compositing_group`) + * masked with `positive_lerp_mask`. + * 8. `lerped_destination_compositing_group` is an SVG group of `destination_compositing_group` + * masked with `negative_lerp_mask`. + * 9. The result is addition of `lerped_operation_compositing_group` and `lerped_destination_compositing_group`. + */ + + unsigned int lerp_compositing_group_id = document->compositing_group_id++; + _cairo_svg_stream_printf (&document->xml_node_defs, + "xml_node_defs, + surface->source_id, + CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_INVERSE_TRANSLATION); + _cairo_svg_stream_printf (&document->xml_node_defs, ">\n"); + _cairo_svg_surface_emit_paint (&document->xml_node_defs, surface, &_cairo_pattern_clear.base, FALSE); + status = _cairo_svg_surface_set_clip (surface, &document->xml_node_defs, clip); + if (unlikely (status)) { + (void) _cairo_svg_stream_destroy (destination_stream); + (void) _cairo_svg_stream_destroy (source_stream); + (void) _cairo_svg_stream_destroy (mask_stream); + return status; + } + status = _cairo_svg_surface_emit_paint (&document->xml_node_defs, surface, &_cairo_pattern_white.base, FALSE); + if (unlikely (status)) { + (void) _cairo_svg_stream_destroy (destination_stream); + (void) _cairo_svg_stream_destroy (source_stream); + (void) _cairo_svg_stream_destroy (mask_stream); + return status; + } + _cairo_svg_surface_reset_clip (surface); + _cairo_svg_stream_printf (&document->xml_node_defs, "\n"); + + unsigned int positive_lerp_mask_id = document->mask_id++; + _cairo_svg_stream_printf (&document->xml_node_defs, + "\n", + positive_lerp_mask_id); + _cairo_svg_stream_printf (&document->xml_node_defs, + "\n", + lerp_compositing_group_id); + _cairo_svg_stream_printf (&document->xml_node_defs, "\n"); + + unsigned int negative_lerp_mask_id = document->mask_id++; + _cairo_svg_stream_printf (&document->xml_node_defs, + "\n", + negative_lerp_mask_id); + _cairo_svg_stream_printf (&document->xml_node_defs, + "\n", + lerp_compositing_group_id, + _cairo_svg_surface_emit_static_filter (document, + CAIRO_SVG_FILTER_REMOVE_COLOR_AND_INVERT_ALPHA)); + _cairo_svg_stream_printf (&document->xml_node_defs, "\n"); + + unsigned int mask_mask_id = document->mask_id++; + _cairo_svg_stream_printf (&document->xml_node_defs, + "\n", + mask_mask_id); + _cairo_svg_stream_printf (&document->xml_node_defs, "xml_node_defs, + surface->source_id, + CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_INVERSE_TRANSLATION); + _cairo_svg_stream_printf (&document->xml_node_defs, ">\n"); + _cairo_svg_stream_copy (mask_stream, &document->xml_node_defs); + status = _cairo_svg_stream_destroy (mask_stream); + if (unlikely (status)) { + (void) _cairo_svg_stream_destroy (source_stream); + (void) _cairo_svg_stream_destroy (destination_stream); + return status; + } + _cairo_svg_stream_printf (&document->xml_node_defs, "\n"); + _cairo_svg_stream_printf (&document->xml_node_defs, "\n"); + + unsigned int masked_source_compositing_group_id = document->compositing_group_id++; + _cairo_svg_stream_printf (&document->xml_node_defs, + "\n", + masked_source_compositing_group_id, + mask_mask_id); + _cairo_svg_stream_printf (&document->xml_node_defs, "xml_node_defs, + surface->source_id, + CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_INVERSE_TRANSLATION); + _cairo_svg_stream_printf (&document->xml_node_defs, ">\n"); + _cairo_svg_stream_copy (source_stream, &document->xml_node_defs); + status = _cairo_svg_stream_destroy (source_stream); + if (unlikely (status)) { + (void) _cairo_svg_stream_destroy (destination_stream); + return status; + } + _cairo_svg_stream_printf (&document->xml_node_defs, "\n"); + _cairo_svg_stream_printf (&document->xml_node_defs, "\n"); + + unsigned int destination_compositing_group_id = document->compositing_group_id++; + _cairo_svg_stream_printf (&document->xml_node_defs, + "xml_node_defs, + surface->source_id, + CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_INVERSE_TRANSLATION); + _cairo_svg_stream_printf (&document->xml_node_defs, ">\n"); + _cairo_svg_stream_copy (destination_stream, &document->xml_node_defs); + status = _cairo_svg_stream_destroy (destination_stream); + if (unlikely (status)) { + return status; + } + _cairo_svg_stream_printf (&document->xml_node_defs, "\n"); + + unsigned int lerped_operation_compositing_group_id = document->compositing_group_id++; + _cairo_svg_stream_printf (&document->xml_node_defs, + "xml_node_defs, + " filter=\"url(#filter-%d)\" mask=\"url(#mask-%d)\">\n", + filter_id, + positive_lerp_mask_id); + status = _cairo_svg_surface_emit_paint (&document->xml_node_defs, surface, &_cairo_pattern_black.base, TRUE); + if (unlikely (status)) { + return status; + } + _cairo_svg_stream_printf (&document->xml_node_defs, "\n"); + + unsigned int lerped_destination_compositing_group_id = document->compositing_group_id++; + _cairo_svg_stream_printf (&document->xml_node_defs, + "\n", + lerped_destination_compositing_group_id, + negative_lerp_mask_id); + _cairo_svg_stream_printf (&document->xml_node_defs, + "\n", + destination_compositing_group_id); + _cairo_svg_stream_printf (&document->xml_node_defs, "\n"); + + _cairo_svg_stream_printf (&surface->xml_node, + "xml_node, + surface->source_id, + CAIRO_SVG_STREAM_PAINT_DEPENDENT_ELEMENT_TYPE_TRANSLATION); + _cairo_svg_stream_printf (&surface->xml_node, ">\n"); + status = _cairo_svg_surface_emit_paint (&surface->xml_node, surface, &_cairo_pattern_black.base, TRUE); + if (unlikely (status)) { + return status; + } + _cairo_svg_stream_printf (&surface->xml_node, "\n"); + + return CAIRO_STATUS_SUCCESS; +} + +#define _CAIRO_SVG_SURFACE_CALL_OPERATOR_IMPL(OPERATOR_IMPL, SOURCE, ...) \ + if (op == CAIRO_OPERATOR_OVER) { \ + status = _cairo_svg_surface_set_clip (surface, &surface->xml_node, clip); \ + if (unlikely (status)) { \ + return status; \ + } \ + return OPERATOR_IMPL (&surface->xml_node, surface, SOURCE, ## __VA_ARGS__); \ + } else { \ + _cairo_svg_surface_reset_clip (surface); \ + cairo_svg_stream_t mask_stream = _cairo_svg_stream_create (); \ + status = OPERATOR_IMPL (&mask_stream, surface, &_cairo_pattern_white.base, ## __VA_ARGS__); \ + if (unlikely (status)) { \ + (void) _cairo_svg_stream_destroy (&mask_stream); \ + return status; \ + } \ + cairo_svg_stream_t source_stream = _cairo_svg_stream_create (); \ + status = _cairo_svg_surface_emit_paint (&source_stream, \ + surface, \ + SOURCE, \ + FALSE); \ + if (unlikely (status)) { \ + (void) _cairo_svg_stream_destroy (&source_stream); \ + (void) _cairo_svg_stream_destroy (&mask_stream); \ + return status; \ + } \ + cairo_svg_stream_t destination_stream = surface->xml_node; \ + surface->xml_node = _cairo_svg_stream_create (); \ + return _cairo_svg_surface_do_operator (&surface->xml_node, \ + surface, \ + op, \ + clip, \ + &mask_stream, \ + &source_stream, \ + &destination_stream); \ + } + +static cairo_int_status_t +_cairo_svg_surface_paint_impl (cairo_svg_stream_t *output, + cairo_svg_surface_t *surface, + const cairo_pattern_t *source) +{ + return _cairo_svg_surface_emit_paint (output, surface, source, FALSE); +} + +static cairo_int_status_t +_cairo_svg_surface_paint (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip) +{ + cairo_status_t status; + cairo_svg_surface_t *surface = abstract_surface; + + /* Emulation of clear and source operators, when no clipping region + * is defined. We just delete existing content of surface root node, + * and exit early if operator is clear. + */ + if ((op == CAIRO_OPERATOR_CLEAR || op == CAIRO_OPERATOR_SOURCE) && clip == NULL) { + switch (surface->paginated_mode) { + case CAIRO_PAGINATED_MODE_ANALYZE: + return CAIRO_STATUS_SUCCESS; + case CAIRO_PAGINATED_MODE_RENDER: + status = _cairo_svg_stream_destroy (&surface->xml_node); + if (unlikely (status)) { + return status; + } + + surface->xml_node = _cairo_svg_stream_create (); + + if (op == CAIRO_OPERATOR_CLEAR) { + return CAIRO_STATUS_SUCCESS; + } + break; + case CAIRO_PAGINATED_MODE_FALLBACK: + ASSERT_NOT_REACHED; + } + } else if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) { + return _cairo_svg_surface_are_operation_and_pattern_supported (surface, op, source) + ? CAIRO_STATUS_SUCCESS + : CAIRO_INT_STATUS_UNSUPPORTED; + } + + _CAIRO_SVG_SURFACE_CALL_OPERATOR_IMPL (_cairo_svg_surface_paint_impl, + source) +} + +static cairo_int_status_t +_cairo_svg_surface_mask_impl (cairo_svg_stream_t *output, + cairo_svg_surface_t *surface, + const cairo_pattern_t *source, + const cairo_pattern_t *mask) +{ + cairo_status_t status; + cairo_svg_document_t *document = surface->document; + + /* _cairo_svg_surface_emit_paint() will output a pattern definition to + * document->xml_node_defs so we need to write the mask element to + * a temporary stream and then copy that to xml_node_defs. */ + cairo_svg_stream_t temporary_stream = _cairo_svg_stream_create (); + + unsigned int mask_id = document->mask_id++; + + _cairo_svg_stream_printf (&temporary_stream, + "\n", + mask_id); + _cairo_svg_stream_printf (&temporary_stream, + "\n", + _cairo_svg_surface_emit_static_filter (document, CAIRO_SVG_FILTER_REMOVE_COLOR)); + status = _cairo_svg_surface_emit_paint (&temporary_stream, surface, mask, FALSE); + if (unlikely (status)) { + (void) _cairo_svg_stream_destroy (&temporary_stream); + return status; + } + _cairo_svg_stream_printf (&temporary_stream, "\n"); + _cairo_svg_stream_printf (&temporary_stream, "\n"); + + _cairo_svg_stream_copy (&temporary_stream, &document->xml_node_defs); + + status = _cairo_svg_stream_destroy (&temporary_stream); + if (unlikely (status)) { + return status; + } + + _cairo_svg_stream_printf (output, + "\n", + mask_id); + + status = _cairo_svg_surface_emit_paint (output, surface, source, FALSE); + if (unlikely (status)) { + return status; + } + + _cairo_svg_stream_printf (output, "\n"); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_svg_surface_mask (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_clip_t *clip) +{ + cairo_status_t status; + cairo_svg_surface_t *surface = abstract_surface; + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) { + return _cairo_svg_surface_are_operation_and_pattern_supported (surface, op, source) && + _cairo_svg_surface_are_operation_and_pattern_supported (surface, op, mask) + ? CAIRO_STATUS_SUCCESS + : CAIRO_INT_STATUS_UNSUPPORTED; + } + + _CAIRO_SVG_SURFACE_CALL_OPERATOR_IMPL (_cairo_svg_surface_mask_impl, + source, + mask) +} + +static cairo_int_status_t +_cairo_svg_surface_stroke_impl (cairo_svg_stream_t *output, + cairo_svg_surface_t *surface, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_status_t status; + + cairo_bool_t svg_clip_or_svg_mask_should_be_used = _cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (source); + unsigned int mask_id; + cairo_svg_stream_t *output_stream = output; + if (svg_clip_or_svg_mask_should_be_used) { + mask_id = surface->document->mask_id++; + + output_stream = &surface->document->xml_node_defs; + + _cairo_svg_stream_printf (output_stream, + "\n", + mask_id); + } + + _cairo_svg_stream_printf (output_stream, "\n"); + + if (svg_clip_or_svg_mask_should_be_used) { + _cairo_svg_stream_printf (output_stream, "\n"); + + _cairo_svg_stream_printf (output, + "\n", + mask_id); + + status = _cairo_svg_surface_emit_composite_pattern (output, + surface, + (cairo_surface_pattern_t *) source, + invalid_pattern_id, + NULL); + if (unlikely (status)) { + return status; + } + + _cairo_svg_stream_printf (output, "\n"); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_svg_surface_stroke (void *abstract_dst, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_svg_surface_t *surface = abstract_dst; + cairo_status_t status; + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) { + return _cairo_svg_surface_are_operation_and_pattern_supported (surface, op, source) + ? CAIRO_STATUS_SUCCESS + : CAIRO_INT_STATUS_UNSUPPORTED; + } + + _CAIRO_SVG_SURFACE_CALL_OPERATOR_IMPL (_cairo_svg_surface_stroke_impl, + source, + path, + stroke_style, + ctm, + ctm_inverse, + tolerance, + antialias) +} + +static cairo_int_status_t +_cairo_svg_surface_fill_impl (cairo_svg_stream_t *output, + cairo_svg_surface_t *surface, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_status_t status; + + if (_cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (source)) { + _cairo_svg_stream_printf (&surface->document->xml_node_defs, + "\n", + surface->document->clip_id); + + _cairo_svg_stream_printf (&surface->document->xml_node_defs, + "document->xml_node_defs, path, NULL); + _cairo_svg_stream_printf (&surface->document->xml_node_defs, "/>\n"); + + _cairo_svg_stream_printf (&surface->document->xml_node_defs, "\n"); + + _cairo_svg_stream_printf (output, + "\n", + surface->document->clip_id++); + + status = _cairo_svg_surface_emit_composite_pattern (output, + surface, + (cairo_surface_pattern_t *) source, + invalid_pattern_id, + NULL); + if (unlikely (status)) { + return status; + } + + _cairo_svg_stream_printf (output, ""); + } else { + _cairo_svg_stream_printf (output, "\n"); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_svg_surface_fill (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_svg_surface_t *surface = abstract_surface; + cairo_status_t status; + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) { + return _cairo_svg_surface_are_operation_and_pattern_supported (surface, op, source) + ? CAIRO_STATUS_SUCCESS + : CAIRO_INT_STATUS_UNSUPPORTED; + } + + _CAIRO_SVG_SURFACE_CALL_OPERATOR_IMPL (_cairo_svg_surface_fill_impl, + source, + path, + fill_rule, + tolerance, + antialias) +} + +static cairo_int_status_t +_cairo_svg_surface_fill_stroke (void *abstract_surface, + cairo_operator_t fill_op, + const cairo_pattern_t *fill_source, + cairo_fill_rule_t fill_rule, + double fill_tolerance, + cairo_antialias_t fill_antialias, + const cairo_path_fixed_t *path, + cairo_operator_t stroke_op, + const cairo_pattern_t *stroke_source, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *stroke_ctm, + const cairo_matrix_t *stroke_ctm_inverse, + double stroke_tolerance, + cairo_antialias_t stroke_antialias, + const cairo_clip_t *clip) +{ + cairo_svg_surface_t *surface = abstract_surface; + cairo_status_t status; + + if (_cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (fill_source) || + _cairo_svg_surface_svg_clip_or_svg_mask_should_be_used (stroke_source) || + fill_op != CAIRO_OPERATOR_OVER || + stroke_op != CAIRO_OPERATOR_OVER) { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) { + return _cairo_svg_surface_are_operation_and_pattern_supported (surface, fill_op, fill_source) + && _cairo_svg_surface_are_operation_and_pattern_supported (surface, stroke_op, stroke_source) + ? CAIRO_STATUS_SUCCESS + : CAIRO_INT_STATUS_UNSUPPORTED; + } + + status = _cairo_svg_surface_set_clip (surface, &surface->xml_node, clip); + if (unlikely (status)) { + return status; + } + + _cairo_svg_stream_printf (&surface->xml_node, "xml_node, surface, + fill_source, fill_rule, stroke_ctm_inverse); + if (unlikely (status)) { + return status; + } + + status = _cairo_svg_surface_emit_stroke_style (&surface->xml_node, surface, + stroke_source, stroke_style, stroke_ctm_inverse); + if (unlikely (status)) { + return status; + } + + _cairo_svg_surface_emit_path (&surface->xml_node, path, stroke_ctm_inverse); + + _cairo_svg_surface_emit_transform (&surface->xml_node, "transform", stroke_ctm, NULL); + + _cairo_svg_stream_printf (&surface->xml_node, "/>\n"); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_svg_surface_show_glyphs_impl (cairo_svg_stream_t *output, + cairo_svg_surface_t *surface, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font) +{ + cairo_status_t status; + cairo_svg_document_t *document = surface->document; + + if (num_glyphs <= 0) { + return CAIRO_STATUS_SUCCESS; + } + + /* FIXME it's probably possible to apply a source of a gradient to + * a group of symbols, but I don't know how yet. Gradients or patterns + * are translated by x and y properties of use element. */ + if (source->type != CAIRO_PATTERN_TYPE_SOLID) { + goto fallback; + } + + _cairo_svg_stream_printf (output, "\n"); + + for (int i = 0; i < num_glyphs; i++) { + cairo_scaled_font_subsets_glyph_t subset_glyph; + + status = _cairo_scaled_font_subsets_map_glyph (document->font_subsets, + scaled_font, + glyphs[i].index, + NULL, + 0, + &subset_glyph); + if ((cairo_int_status_t) status == CAIRO_INT_STATUS_UNSUPPORTED) { + _cairo_svg_stream_printf (output, "\n"); + + glyphs += i; + num_glyphs -= i; + goto fallback; + } + + if (unlikely (status)) { + return status; + } + + _cairo_svg_stream_printf (output, + "\n", + subset_glyph.font_id, + subset_glyph.subset_glyph_index, + glyphs[i].x, glyphs[i].y); + } + + _cairo_svg_stream_printf (output, "\n"); + + return CAIRO_STATUS_SUCCESS; + + fallback:; + cairo_path_fixed_t path; + + _cairo_path_fixed_init (&path); + + status = _cairo_scaled_font_glyph_path (scaled_font, + (cairo_glyph_t *) glyphs, + num_glyphs, &path); + if (unlikely (status)) { + _cairo_path_fixed_fini (&path); + return status; + } + + status = _cairo_svg_surface_fill_impl (output, + surface, + source, + &path, + CAIRO_FILL_RULE_WINDING, + 0.0, + CAIRO_ANTIALIAS_DEFAULT); + + _cairo_path_fixed_fini (&path); + + return status; +} + +static cairo_int_status_t +_cairo_svg_surface_show_glyphs (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip) +{ + cairo_svg_surface_t *surface = abstract_surface; + cairo_int_status_t status; + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) { + return _cairo_svg_surface_are_operation_and_pattern_supported (surface, op, source) + ? CAIRO_STATUS_SUCCESS + : CAIRO_INT_STATUS_UNSUPPORTED; + } + + _CAIRO_SVG_SURFACE_CALL_OPERATOR_IMPL (_cairo_svg_surface_show_glyphs_impl, + source, + glyphs, + num_glyphs, + scaled_font) +} + +static void +_cairo_svg_surface_get_font_options (void *abstract_surface, + cairo_font_options_t *options) +{ + _cairo_font_options_init_default (options); + + cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE); + cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF); + cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_GRAY); + _cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_OFF); +} + + +static const char ** +_cairo_svg_surface_get_supported_mime_types (void *abstract_surface) +{ + return _cairo_svg_supported_mime_types; +} + +static const cairo_surface_backend_t cairo_svg_surface_backend = { + CAIRO_SURFACE_TYPE_SVG, + _cairo_svg_surface_finish, + + _cairo_default_context_create, + + NULL, /* create_similar: handled by wrapper */ + NULL, /* create_similar_image */ + NULL, /* map to image */ + NULL, /* unmap image */ + + _cairo_surface_default_source, + NULL, /* acquire_source_image */ + NULL, /* release_source_image */ + NULL, /* snapshot */ + + _cairo_svg_surface_copy_page, + _cairo_svg_surface_show_page, + + _cairo_svg_surface_get_extents, + _cairo_svg_surface_get_font_options, + + NULL, /* flush */ + NULL, /* mark dirty rectangle */ + + _cairo_svg_surface_paint, + _cairo_svg_surface_mask, + _cairo_svg_surface_stroke, + _cairo_svg_surface_fill, + _cairo_svg_surface_fill_stroke, + _cairo_svg_surface_show_glyphs, + NULL, /* has_show_text_glyphs */ + NULL, /* show_text_glyphs */ + _cairo_svg_surface_get_supported_mime_types, +}; + +static cairo_status_t +_cairo_svg_document_create (cairo_output_stream_t *output_stream, + double width, + double height, + cairo_svg_version_t version, + cairo_svg_document_t **document_out) +{ + cairo_svg_document_t *document; + + if (output_stream->status) { + return output_stream->status; + } + + document = _cairo_calloc (sizeof (cairo_svg_document_t)); + if (unlikely (document == NULL)) { + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + document->output_stream = output_stream; + document->refcount = 1; + document->owner = NULL; + document->finished = FALSE; + + document->width = width; + document->height = height; + document->unit = CAIRO_SVG_UNIT_USER; + + document->xml_node_defs = _cairo_svg_stream_create (); + document->xml_node_glyphs = _cairo_svg_stream_create (); + document->xml_node_filters = _cairo_svg_stream_create (); + + document->linear_pattern_id = 0; + document->radial_pattern_id = 0; + document->pattern_id = 0; + document->clip_id = 0; + document->mask_id = 0; + document->compositing_group_id = 0; + document->filter_id = 0; + + for (enum cairo_svg_filter filter = 0; filter < CAIRO_SVG_FILTER_LAST_STATIC_FILTER; filter++) { + document->filters_emitted[filter] = FALSE; + } + + document->svg_version = version; + + /* The use of defs for font glyphs imposes no per-subset limit. */ + document->font_subsets = _cairo_scaled_font_subsets_create_scaled (); + if (unlikely (document->font_subsets == NULL)) { + (void) _cairo_svg_stream_destroy(&document->xml_node_defs); + (void) _cairo_svg_stream_destroy(&document->xml_node_glyphs); + (void) _cairo_svg_stream_destroy(&document->xml_node_filters); + free (document); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + document->paints = _cairo_hash_table_create (_cairo_svg_paint_equal); + if (unlikely (document->paints == NULL)) { + (void) _cairo_svg_stream_destroy(&document->xml_node_defs); + (void) _cairo_svg_stream_destroy(&document->xml_node_glyphs); + (void) _cairo_svg_stream_destroy(&document->xml_node_filters); + _cairo_scaled_font_subsets_destroy (document->font_subsets); + free (document); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + *document_out = document; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_svg_document_t * +_cairo_svg_document_reference (cairo_svg_document_t *document) +{ + document->refcount++; + + return document; +} + +static cairo_status_t +_cairo_svg_document_destroy (cairo_svg_document_t *document) +{ + cairo_status_t status; + + document->refcount--; + if (document->refcount > 0) + return CAIRO_STATUS_SUCCESS; + + status = _cairo_svg_document_finish (document); + + free (document); + + return status; +} + +static cairo_status_t +_cairo_svg_document_finish (cairo_svg_document_t *document) +{ + if (document->finished) { + return CAIRO_STATUS_SUCCESS; + } + document->finished = TRUE; + + cairo_status_t status, final_status = CAIRO_STATUS_SUCCESS; + + cairo_output_stream_t *output = document->output_stream; + + /* + * Should we add DOCTYPE? + * + * Google says no. + * + * http://tech.groups.yahoo.com/group/svg-developers/message/48562: + * There's a bunch of issues, but just to pick a few: + * - they'll give false positives. + * - they'll give false negatives. + * - they're namespace-unaware. + * - they don't wildcard. + * So when they say OK they really haven't checked anything, when + * they say NOT OK they might be on crack, and like all + * namespace-unaware things they're a dead branch of the XML tree. + * + * http://jwatt.org/svg/authoring/: + * Unfortunately the SVG DTDs are a source of so many issues that the + * SVG WG has decided not to write one for the upcoming SVG 1.2 + * standard. In fact SVG WG members are even telling people not to use + * a DOCTYPE declaration in SVG 1.0 and 1.1 documents. + */ + + _cairo_output_stream_printf (output, + "\n" + "\n", + document->width, _cairo_svg_unit_strings[document->unit], + document->height, _cairo_svg_unit_strings[document->unit], + document->width, document->height); + + status = _cairo_svg_document_emit_font_subsets (document); + if (final_status == CAIRO_STATUS_SUCCESS) { + final_status = status; + } + + cairo_svg_surface_t *surface = NULL; + if (document->owner != NULL) { + surface = (cairo_svg_surface_t *) _cairo_paginated_surface_get_target (document->owner); + + if (surface->xml_node.elements.num_elements > 0) { + cairo_svg_page_t *page = _cairo_svg_surface_store_page (surface); + if (final_status == CAIRO_STATUS_SUCCESS && page == NULL) { + final_status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + } + + if (surface->transitive_paint_used) { + cairo_svg_paint_t *paint_entry = _cairo_calloc (sizeof (cairo_svg_paint_t)); + if (paint_entry == NULL) { + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + paint_entry->source_id = surface->source_id; + paint_entry->box.p1.x = 0; + paint_entry->box.p1.y = 0; + paint_entry->box.p2.x = document->width; + paint_entry->box.p2.y = document->height; + _cairo_svg_paint_box_add_padding (&paint_entry->box); + _cairo_array_init (&paint_entry->paint_elements, sizeof (cairo_svg_paint_element_t)); + _cairo_svg_paint_init_key (paint_entry); + status = _cairo_hash_table_insert (document->paints, &paint_entry->base); + if (unlikely (status)) { + return status; + } + } + } + + _cairo_hash_table_foreach (document->paints, _cairo_svg_paint_compute_func, document); + + if (document->xml_node_filters.elements.num_elements > 0 || + document->xml_node_glyphs.elements.num_elements > 0 || + document->xml_node_defs.elements.num_elements > 0) { + _cairo_output_stream_printf (output, "\n"); + _cairo_svg_stream_copy_to_output_stream (&document->xml_node_filters, output, document->paints); + if (document->xml_node_glyphs.elements.num_elements > 0) { + _cairo_output_stream_printf (output, "\n"); + _cairo_svg_stream_copy_to_output_stream (&document->xml_node_glyphs, output, document->paints); + _cairo_output_stream_printf (output, "\n"); + } + _cairo_svg_stream_copy_to_output_stream (&document->xml_node_defs, output, document->paints); + _cairo_output_stream_printf (output, "\n"); + } + + if (document->owner != NULL) { + if (surface->page_set.num_elements == 1) { + cairo_svg_page_t *page = _cairo_array_index (&surface->page_set, 0); + _cairo_svg_stream_copy_to_output_stream (&page->xml_node, output, document->paints); + } else if (surface->page_set.num_elements > 1) { + _cairo_output_stream_printf (output, "\n"); + for (unsigned int i = 0; i < surface->page_set.num_elements; i++) { + cairo_svg_page_t *page = _cairo_array_index (&surface->page_set, i); + _cairo_output_stream_printf (output, "\n"); + _cairo_svg_stream_copy_to_output_stream (&page->xml_node, output, document->paints); + _cairo_output_stream_printf (output, "\n"); + } + _cairo_output_stream_printf (output, "\n"); + } + } + + _cairo_output_stream_printf (output, "\n"); + + status = _cairo_svg_stream_destroy (&document->xml_node_defs); + if (final_status == CAIRO_STATUS_SUCCESS) { + final_status = status; + } + + status = _cairo_svg_stream_destroy (&document->xml_node_glyphs); + if (final_status == CAIRO_STATUS_SUCCESS) { + final_status = status; + } + + status = _cairo_svg_stream_destroy (&document->xml_node_filters); + if (final_status == CAIRO_STATUS_SUCCESS) { + final_status = status; + } + + _cairo_hash_table_foreach (document->paints, _cairo_svg_paint_pluck, document->paints); + _cairo_hash_table_destroy (document->paints); + + status = _cairo_output_stream_destroy (output); + if (final_status == CAIRO_STATUS_SUCCESS) { + final_status = status; + } + + return final_status; +} + +static cairo_int_status_t +_cairo_svg_surface_set_paginated_mode (void *abstract_surface, + cairo_paginated_mode_t paginated_mode) +{ + cairo_svg_surface_t *surface = abstract_surface; + + surface->paginated_mode = paginated_mode; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_bool_t +_cairo_svg_surface_supports_fine_grained_fallbacks (void *abstract_surface) +{ + return TRUE; +} + +static const cairo_paginated_surface_backend_t cairo_svg_surface_paginated_backend = { + NULL /*_cairo_svg_surface_start_page*/, + _cairo_svg_surface_set_paginated_mode, + NULL, /* _cairo_svg_surface_set_bounding_box */ + NULL, /* _cairo_svg_surface_set_fallback_images_required */ + _cairo_svg_surface_supports_fine_grained_fallbacks, +}; diff --git a/local/recipes/libs/cairo/source/src/cairo-svg.h b/local/recipes/libs/cairo/source/src/cairo-svg.h new file mode 100644 index 0000000000..7745eec90a --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-svg.h @@ -0,0 +1,130 @@ +/* cairo - a vector graphics library with display and print output + * + * cairo-svg.h + * + * Copyright © 2005 Emmanuel Pacaud + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + */ + +#ifndef CAIRO_SVG_H +#define CAIRO_SVG_H + +#include "cairo.h" + +#if CAIRO_HAS_SVG_SURFACE + +CAIRO_BEGIN_DECLS + +/** + * cairo_svg_version_t: + * @CAIRO_SVG_VERSION_1_1: The version 1.1 of the SVG specification. (Since 1.2) + * @CAIRO_SVG_VERSION_1_2: The version 1.2 of the SVG specification. (Since 1.2) + * + * #cairo_svg_version_t is used to describe the version number of the SVG + * specification that a generated SVG file will conform to. + * + * Since: 1.2 + **/ +typedef enum _cairo_svg_version { + CAIRO_SVG_VERSION_1_1, + CAIRO_SVG_VERSION_1_2 +} cairo_svg_version_t; + +/** + * cairo_svg_unit_t: + * @CAIRO_SVG_UNIT_USER: User unit, a value in the current coordinate system. + * If used in the root element for the initial coordinate systems it + * corresponds to pixels. (Since 1.16) + * @CAIRO_SVG_UNIT_EM: The size of the element's font. (Since 1.16) + * @CAIRO_SVG_UNIT_EX: The x-height of the element’s font. (Since 1.16) + * @CAIRO_SVG_UNIT_PX: Pixels (1px = 1/96th of 1in). (Since 1.16) + * @CAIRO_SVG_UNIT_IN: Inches (1in = 2.54cm = 96px). (Since 1.16) + * @CAIRO_SVG_UNIT_CM: Centimeters (1cm = 96px/2.54). (Since 1.16) + * @CAIRO_SVG_UNIT_MM: Millimeters (1mm = 1/10th of 1cm). (Since 1.16) + * @CAIRO_SVG_UNIT_PT: Points (1pt = 1/72th of 1in). (Since 1.16) + * @CAIRO_SVG_UNIT_PC: Picas (1pc = 1/6th of 1in). (Since 1.16) + * @CAIRO_SVG_UNIT_PERCENT: Percent, a value that is some fraction of another + * reference value. (Since 1.16) + * + * #cairo_svg_unit_t is used to describe the units valid for coordinates and + * lengths in the SVG specification. + * + * See also: + * - [SVG Units](https://www.w3.org/TR/SVG/coords.html#Units) + * - [SVG Types](https://www.w3.org/TR/SVG/types.html#DataTypeLength) + * - [CSS Length](https://www.w3.org/TR/css-values-3/#lengths) + * + * Since: 1.16 + **/ +typedef enum _cairo_svg_unit { + CAIRO_SVG_UNIT_USER = 0, + CAIRO_SVG_UNIT_EM, + CAIRO_SVG_UNIT_EX, + CAIRO_SVG_UNIT_PX, + CAIRO_SVG_UNIT_IN, + CAIRO_SVG_UNIT_CM, + CAIRO_SVG_UNIT_MM, + CAIRO_SVG_UNIT_PT, + CAIRO_SVG_UNIT_PC, + CAIRO_SVG_UNIT_PERCENT +} cairo_svg_unit_t; + +cairo_public cairo_surface_t * +cairo_svg_surface_create (const char *filename, + double width_in_points, + double height_in_points); + +cairo_public cairo_surface_t * +cairo_svg_surface_create_for_stream (cairo_write_func_t write_func, + void *closure, + double width_in_points, + double height_in_points); + +cairo_public void +cairo_svg_surface_restrict_to_version (cairo_surface_t *surface, + cairo_svg_version_t version); + +cairo_public void +cairo_svg_get_versions (cairo_svg_version_t const **versions, + int *num_versions); + +cairo_public const char * +cairo_svg_version_to_string (cairo_svg_version_t version); + +cairo_public void +cairo_svg_surface_set_document_unit (cairo_surface_t *surface, + cairo_svg_unit_t unit); + +cairo_public cairo_svg_unit_t +cairo_svg_surface_get_document_unit (cairo_surface_t *surface); + +CAIRO_END_DECLS + +#else /* CAIRO_HAS_SVG_SURFACE */ +# error Cairo was not compiled with support for the svg backend +#endif /* CAIRO_HAS_SVG_SURFACE */ + +#endif /* CAIRO_SVG_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-tag-attributes-private.h b/local/recipes/libs/cairo/source/src/cairo-tag-attributes-private.h new file mode 100644 index 0000000000..5853f9a0d7 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-tag-attributes-private.h @@ -0,0 +1,131 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2016 Adrian Johnson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Adrian Johnson. + * + * Contributor(s): + * Adrian Johnson + */ + +#ifndef CAIRO_TAG_ATTRIBUTES_PRIVATE_H +#define CAIRO_TAG_ATTRIBUTES_PRIVATE_H + +#include "cairo-array-private.h" +#include "cairo-error-private.h" +#include "cairo-types-private.h" + +typedef enum { + TAG_LINK_INVALID = 0, + TAG_LINK_EMPTY, + TAG_LINK_DEST, + TAG_LINK_URI, + TAG_LINK_FILE, + TAG_LINK_PAGE, + TAG_LINK_DEST_AND_URI, +} cairo_tag_link_type_t; + +typedef struct _cairo_content_attrs { + char *id; + char *tag_name; +} cairo_content_attrs_t; + +typedef struct _cairo_content_ref_attrs { + char *ref; +} cairo_content_ref_attrs_t; + +typedef struct _cairo_link_attrs { + cairo_tag_link_type_t link_type; + cairo_array_t rects; + char *dest; + char *uri; + char *file; + int page; + cairo_bool_t has_pos; + cairo_point_double_t pos; + char *id; + char *ref; + int link_page; +} cairo_link_attrs_t; + +typedef struct _cairo_dest_attrs { + char *name; + double x; + double y; + cairo_bool_t x_valid; + cairo_bool_t y_valid; + cairo_bool_t internal; +} cairo_dest_attrs_t; + +typedef struct _cairo_ccitt_params { + int columns; + int rows; + int k; + cairo_bool_t end_of_line; + cairo_bool_t encoded_byte_align; + cairo_bool_t end_of_block; + cairo_bool_t black_is_1; + int damaged_rows_before_error; +} cairo_ccitt_params_t; + +typedef struct _cairo_eps_params { + cairo_box_double_t bbox; +} cairo_eps_params_t; + +cairo_private cairo_int_status_t +_cairo_tag_parse_link_attributes (const char *attributes, cairo_link_attrs_t *link_attrs); + +cairo_private cairo_int_status_t +_cairo_tag_parse_dest_attributes (const char *attributes, cairo_dest_attrs_t *dest_attrs); + +cairo_private cairo_int_status_t +_cairo_tag_parse_content_attributes (const char *attributes, cairo_content_attrs_t *content_attrs); + +cairo_private cairo_int_status_t +_cairo_tag_parse_content_ref_attributes (const char *attributes, cairo_content_ref_attrs_t *content_ref_attrs); + +cairo_private cairo_int_status_t +_cairo_tag_parse_ccitt_params (const char *attributes, cairo_ccitt_params_t *dest_attrs); + +cairo_private cairo_int_status_t +_cairo_tag_parse_eps_params (const char *attributes, cairo_eps_params_t *dest_attrs); + +cairo_private void +_cairo_tag_free_link_attributes (cairo_link_attrs_t *link_attrs); + +cairo_private void +_cairo_tag_free_dest_attributes (cairo_dest_attrs_t *link_attrs); + +cairo_private void +_cairo_tag_free_content_attributes (cairo_content_attrs_t *link_attrs); + +cairo_private void +_cairo_tag_free_content_ref_attributes (cairo_content_ref_attrs_t *link_attrs); + +#endif /* CAIRO_TAG_ATTRIBUTES_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-tag-attributes.c b/local/recipes/libs/cairo/source/src/cairo-tag-attributes.c new file mode 100644 index 0000000000..70ccd674fb --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-tag-attributes.c @@ -0,0 +1,857 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2016 Adrian Johnson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Adrian Johnson. + * + * Contributor(s): + * Adrian Johnson + */ + +#include "cairoint.h" + +#include "cairo-array-private.h" +#include "cairo-list-inline.h" +#include "cairo-tag-attributes-private.h" +#include "cairo-tag-stack-private.h" + +#include + +typedef enum { + ATTRIBUTE_BOOL, /* Either true/false or 1/0 may be used. */ + ATTRIBUTE_INT, + ATTRIBUTE_FLOAT, /* Decimal separator is in current locale. */ + ATTRIBUTE_STRING, /* Enclose in single quotes. String escapes: + * \' - single quote + * \\ - backslash + */ +} attribute_type_t; + +typedef struct _attribute_spec { + const char *name; + attribute_type_t type; + int array_size; /* 0 = scalar, -1 = variable size array */ +} attribute_spec_t; + +/* + * id [optional] content id + * content [optional] One or more content ids + */ +static const attribute_spec_t _content_attrib_spec[] = { + { "tag_name", ATTRIBUTE_STRING }, + { "id", ATTRIBUTE_STRING }, + { NULL } +}; + +/* + * id [optional] content id + * content [optional] One or more content ids + */ +static const attribute_spec_t _content_ref_attrib_spec[] = { + { "ref", ATTRIBUTE_STRING }, + { NULL } +}; + +/* + * name [required] Unique name of this destination (UTF-8) + * x [optional] x coordinate of destination on page. Default is x coord of + * extents of operations enclosed by the dest begin/end tags. + * y [optional] y coordinate of destination on page. Default is y coord of + * extents of operations enclosed by the dest begin/end tags. + * internal [optional] If true, the name may be optimized out of the PDF where + * possible. Default false. + */ +static const attribute_spec_t _dest_attrib_spec[] = { + { "name", ATTRIBUTE_STRING }, + { "x", ATTRIBUTE_FLOAT }, + { "y", ATTRIBUTE_FLOAT }, + { "internal", ATTRIBUTE_BOOL }, + { NULL } +}; + +/* + * rect [optional] One or more rectangles to define link region. Default + * is the extents of the operations enclosed by the link begin/end tags. + * Each rectangle is specified by four array elements: x, y, width, height. + * ie the array size must be a multiple of four. + * + * Internal Links + * -------------- + * either: + * dest - name of dest tag in the PDF file to link to (UTF8) + * or + * page - Page number in the PDF file to link to + * pos - [optional] Position of destination on page. Default is 0,0. + * + * URI Links + * --------- + * uri [required] Uniform resource identifier (ASCII). + + * File Links + * ---------- + * file - [required] File name of PDF file to link to. + * either: + * dest - name of dest tag in the PDF file to link to (UTF8) + * or + * page - Page number in the PDF file to link to + * pos - [optional] Position of destination on page. Default is 0,0. + */ +static const attribute_spec_t _link_attrib_spec[] = +{ + { "rect", ATTRIBUTE_FLOAT, -1 }, + { "dest", ATTRIBUTE_STRING }, + { "uri", ATTRIBUTE_STRING }, + { "file", ATTRIBUTE_STRING }, + { "page", ATTRIBUTE_INT }, + { "pos", ATTRIBUTE_FLOAT, 2 }, + { "id", ATTRIBUTE_STRING }, + { "ref", ATTRIBUTE_STRING }, + { "link_page", ATTRIBUTE_INT }, + { NULL } +}; + +/* + * Required: + * Columns - width of the image in pixels. + * Rows - height of the image in scan lines. + * + * Optional: + * K - An integer identifying the encoding scheme used. < 0 is 2 dimensional + * Group 4, = 0 is Group3 1 dimensional, > 0 is mixed 1 and 2 dimensional + * encoding. Default: 0. + * EndOfLine - If true end-of-line bit patterns are present. Default: false. + * EncodedByteAlign - If true the end of line is padded with 0 bits so the next + * line begins on a byte boundary. Default: false. + * EndOfBlock - If true the data contains an end-of-block pattern. Default: true. + * BlackIs1 - If true 1 bits are black pixels. Default: false. + * DamagedRowsBeforeError - Number of damages rows tolerated before an error + * occurs. Default: 0. + */ +static const attribute_spec_t _ccitt_params_spec[] = +{ + { "Columns", ATTRIBUTE_INT }, + { "Rows", ATTRIBUTE_INT }, + { "K", ATTRIBUTE_INT }, + { "EndOfLine", ATTRIBUTE_BOOL }, + { "EncodedByteAlign", ATTRIBUTE_BOOL }, + { "EndOfBlock", ATTRIBUTE_BOOL }, + { "BlackIs1", ATTRIBUTE_BOOL }, + { "DamagedRowsBeforeError", ATTRIBUTE_INT }, + { NULL } +}; + +/* + * bbox - Bounding box of EPS file. The format is [ llx lly urx ury ] + * llx - lower left x xoordinate + * lly - lower left y xoordinate + * urx - upper right x xoordinate + * ury - upper right y xoordinate + * all coordinates are in PostScript coordinates. + */ +static const attribute_spec_t _eps_params_spec[] = +{ + { "bbox", ATTRIBUTE_FLOAT, 4 }, + { NULL } +}; + +typedef union { + cairo_bool_t b; + int i; + double f; + char *s; +} attrib_val_t; + +typedef struct _attribute { + char *name; + attribute_type_t type; + int array_len; /* 0 = scalar */ + attrib_val_t scalar; + cairo_array_t array; /* array of attrib_val_t */ + cairo_list_t link; +} attribute_t; + +static const char * +skip_space (const char *p) +{ + while (_cairo_isspace (*p)) + p++; + + return p; +} + +static const char * +parse_bool (const char *p, cairo_bool_t *b) +{ + if (*p == '1') { + *b = TRUE; + return p + 1; + } else if (*p == '0') { + *b = FALSE; + return p + 1; + } else if (strcmp (p, "true") == 0) { + *b = TRUE; + return p + 4; + } else if (strcmp (p, "false") == 0) { + *b = FALSE; + return p + 5; + } + + return NULL; +} + +static const char * +parse_int (const char *p, int *i) +{ + int n; + + if (sscanf(p, "%d%n", i, &n) > 0) + return p + n; + + return NULL; +} + +static const char * +parse_float (const char *p, double *d) +{ + int n; + const char *start = p; + cairo_bool_t has_decimal_point = FALSE; + + while (*p) { + if (*p == '.' || *p == ']' || _cairo_isspace (*p)) + break; + p++; + } + + if (*p == '.') + has_decimal_point = TRUE; + + if (has_decimal_point) { + char *end; + *d = _cairo_strtod (start, &end); + if (end && end != start) + return end; + + } else { + if (sscanf(start, "%lf%n", d, &n) > 0) + return start + n; + } + + return NULL; +} + +static const char * +decode_string (const char *p, int *len, char *s) +{ + if (*p != '\'') + return NULL; + + p++; + if (! *p) + return NULL; + + *len = 0; + while (*p) { + if (*p == '\\') { + p++; + if (*p) { + if (s) + *s++ = *p; + p++; + (*len)++; + } + } else if (*p == '\'') { + return p + 1; + } else { + if (s) + *s++ = *p; + p++; + (*len)++; + } + } + + return NULL; +} + +static const char * +parse_string (const char *p, char **s) +{ + const char *end; + int len; + + end = decode_string (p, &len, NULL); + if (!end) + return NULL; + + *s = _cairo_malloc (len + 1); + decode_string (p, &len, *s); + (*s)[len] = 0; + + return end; +} + +static const char * +parse_scalar (const char *p, attribute_type_t type, attrib_val_t *scalar) +{ + switch (type) { + case ATTRIBUTE_BOOL: + return parse_bool (p, &scalar->b); + case ATTRIBUTE_INT: + return parse_int (p, &scalar->i); + case ATTRIBUTE_FLOAT: + return parse_float (p, &scalar->f); + case ATTRIBUTE_STRING: + return parse_string (p, &scalar->s); + } + + return NULL; +} + +static cairo_int_status_t +parse_array (const char *attributes, const char *p, attribute_type_t type, cairo_array_t *array, const char **end) +{ + attrib_val_t val; + cairo_int_status_t status; + + p = skip_space (p); + if (! *p) + goto error; + + if (*p++ != '[') + goto error; + + while (TRUE) { + p = skip_space (p); + if (! *p) + goto error; + + if (*p == ']') { + *end = p + 1; + return CAIRO_INT_STATUS_SUCCESS; + } + + p = parse_scalar (p, type, &val); + if (!p) + goto error; + + status = _cairo_array_append (array, &val); + if (unlikely (status)) + return status; + } + + error: + return _cairo_tag_error ( + "while parsing attributes: \"%s\". Error parsing array", attributes); +} + +static cairo_int_status_t +parse_name (const char *attributes, const char *p, const char **end, char **s) +{ + const char *p2; + char *name; + int len; + + if (! _cairo_isalpha (*p)) + return _cairo_tag_error ( + "while parsing attributes: \"%s\". Error parsing name." + " \"%s\" does not start with an alphabetic character", + attributes, p); + + p2 = p; + while (_cairo_isalpha (*p2) || _cairo_isdigit (*p2) || *p2 == '_') + p2++; + + len = p2 - p; + name = _cairo_strndup (p, len); + if (unlikely (name == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + *s = name; + *end = p2; + + return CAIRO_INT_STATUS_SUCCESS; +} + +static cairo_int_status_t +parse_attributes (const char *attributes, const attribute_spec_t *attrib_def, cairo_list_t *list) +{ + const attribute_spec_t *def; + attribute_t *attrib; + char *name = NULL; + cairo_int_status_t status; + const char *p = attributes; + + if (! p) + return CAIRO_INT_STATUS_SUCCESS; + + while (*p) { + p = skip_space (p); + if (! *p) + break; + + status = parse_name (attributes, p, &p, &name); + if (status) + return status; + + def = attrib_def; + while (def->name) { + if (strcmp (name, def->name) == 0) + break; + def++; + } + + if (! def->name) { + status = _cairo_tag_error ( + "while parsing attributes: \"%s\". Unknown attribute name \"%s\"", + attributes, name); + goto fail1; + } + + attrib = _cairo_calloc (sizeof (attribute_t)); + if (unlikely (attrib == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto fail1; + } + + attrib->name = name; + attrib->type = def->type; + _cairo_array_init (&attrib->array, sizeof(attrib_val_t)); + + p = skip_space (p); + if (def->type == ATTRIBUTE_BOOL && *p != '=') { + attrib->scalar.b = TRUE; + } else { + if (*p++ != '=') { + status = _cairo_tag_error ( + "while parsing attributes: \"%s\". Expected '=' after \"%s\"", + attributes, name); + goto fail2; + } + + if (def->array_size == 0) { + const char *s = p; + p = parse_scalar (p, def->type, &attrib->scalar); + if (!p) { + status = _cairo_tag_error ( + "while parsing attributes: \"%s\". Error parsing \"%s\"", + attributes, s); + goto fail2; + } + + attrib->array_len = 0; + } else { + status = parse_array (attributes, p, def->type, &attrib->array, &p); + if (unlikely (status)) + goto fail2; + + attrib->array_len = _cairo_array_num_elements (&attrib->array); + if (def->array_size > 0 && attrib->array_len != def->array_size) { + status = _cairo_tag_error ( + "while parsing attributes: \"%s\". Expected %d elements in array. Found %d", + attributes, def->array_size, attrib->array_len); + goto fail2; + } + } + } + + cairo_list_add_tail (&attrib->link, list); + } + + return CAIRO_INT_STATUS_SUCCESS; + + fail2: + _cairo_array_fini (&attrib->array); + if (attrib->type == ATTRIBUTE_STRING) + free (attrib->scalar.s); + free (attrib); + fail1: + free (name); + + return status; +} + +static void +free_attributes_list (cairo_list_t *list) +{ + attribute_t *attr, *next; + + cairo_list_foreach_entry_safe (attr, next, attribute_t, list, link) + { + cairo_list_del (&attr->link); + free (attr->name); + _cairo_array_fini (&attr->array); + if (attr->type == ATTRIBUTE_STRING) + free (attr->scalar.s); + free (attr); + } +} + +cairo_int_status_t +_cairo_tag_parse_content_attributes (const char *attributes, cairo_content_attrs_t *content_attrs) +{ + cairo_list_t list; + cairo_int_status_t status; + attribute_t *attr; + + cairo_list_init (&list); + status = parse_attributes (attributes, _content_attrib_spec, &list); + if (unlikely (status)) + goto cleanup; + + memset (content_attrs, 0, sizeof (cairo_content_attrs_t)); + cairo_list_foreach_entry (attr, attribute_t, &list, link) + { + if (strcmp (attr->name, "tag_name") == 0) { + content_attrs->tag_name = strdup (attr->scalar.s); + } else if (strcmp (attr->name, "id") == 0) { + content_attrs->id = strdup (attr->scalar.s); + } + } + + if (! content_attrs->tag_name) { + status = _cairo_tag_error ("CONTENT attributes: \"%s\" missing tag_name attribute", + attributes); + } else if (! content_attrs->tag_name) { + status = _cairo_tag_error ("CONTENT attributes: \"%s\" missing id attribute", + attributes); + } + + cleanup: + free_attributes_list (&list); + + return status; +} + +cairo_int_status_t +_cairo_tag_parse_content_ref_attributes (const char *attributes, cairo_content_ref_attrs_t *content_ref_attrs) +{ + cairo_list_t list; + cairo_int_status_t status; + attribute_t *attr; + + cairo_list_init (&list); + status = parse_attributes (attributes, _content_ref_attrib_spec, &list); + if (unlikely (status)) + goto cleanup; + + memset (content_ref_attrs, 0, sizeof (cairo_content_ref_attrs_t)); + cairo_list_foreach_entry (attr, attribute_t, &list, link) + { + if (strcmp (attr->name, "ref") == 0) { + content_ref_attrs->ref = strdup (attr->scalar.s); + } + } + + if (! content_ref_attrs->ref) { + status = _cairo_tag_error ("CONTENT_REF attributes: \"%s\" missing ref attribute", + attributes); + } + + cleanup: + free_attributes_list (&list); + + return status; +} + +cairo_int_status_t +_cairo_tag_parse_link_attributes (const char *attributes, cairo_link_attrs_t *link_attrs) +{ + cairo_list_t list; + cairo_int_status_t status; + attribute_t *attr; + attrib_val_t val; + cairo_bool_t invalid_combination = FALSE; + + cairo_list_init (&list); + status = parse_attributes (attributes, _link_attrib_spec, &list); + if (unlikely (status)) + return status; + + memset (link_attrs, 0, sizeof (cairo_link_attrs_t)); + _cairo_array_init (&link_attrs->rects, sizeof (cairo_rectangle_t)); + + cairo_list_foreach_entry (attr, attribute_t, &list, link) { + if (strcmp (attr->name, "dest") == 0) { + link_attrs->dest = strdup (attr->scalar.s); + + } else if (strcmp (attr->name, "page") == 0) { + link_attrs->page = attr->scalar.i; + if (link_attrs->page < 1) { + status = _cairo_tag_error ("Link attributes: \"%s\" page must be >= 1", attributes); + goto cleanup; + } + + } else if (strcmp (attr->name, "pos") == 0) { + _cairo_array_copy_element (&attr->array, 0, &val); + link_attrs->pos.x = val.f; + _cairo_array_copy_element (&attr->array, 1, &val); + link_attrs->pos.y = val.f; + link_attrs->has_pos = TRUE; + + } else if (strcmp (attr->name, "uri") == 0) { + link_attrs->uri = strdup (attr->scalar.s); + + } else if (strcmp (attr->name, "file") == 0) { + link_attrs->file = strdup (attr->scalar.s); + + } else if (strcmp (attr->name, "rect") == 0) { + cairo_rectangle_t rect; + int i; + int num_elem = _cairo_array_num_elements (&attr->array); + if (num_elem == 0 || num_elem % 4 != 0) { + status = _cairo_tag_error ("Link attributes: \"%s\" rect array size must be multiple of 4", + attributes); + goto cleanup; + } + + for (i = 0; i < num_elem; i += 4) { + _cairo_array_copy_element (&attr->array, i, &val); + rect.x = val.f; + _cairo_array_copy_element (&attr->array, i+1, &val); + rect.y = val.f; + _cairo_array_copy_element (&attr->array, i+2, &val); + rect.width = val.f; + _cairo_array_copy_element (&attr->array, i+3, &val); + rect.height = val.f; + status = _cairo_array_append (&link_attrs->rects, &rect); + if (unlikely (status)) + goto cleanup; + } + } else if (strcmp (attr->name, "id") == 0) { + link_attrs->id = strdup (attr->scalar.s); + } else if (strcmp (attr->name, "ref") == 0) { + link_attrs->ref = strdup (attr->scalar.s); + } else if (strcmp (attr->name, "link_page") == 0) { + link_attrs->link_page = attr->scalar.i; + if (link_attrs->link_page < 1) { + status = _cairo_tag_error ("Link attributes: \"%s\" page must be >= 1", attributes); + goto cleanup; + } + } + } + + if (link_attrs->file) { + link_attrs->link_type = TAG_LINK_FILE; + if (link_attrs->uri) + invalid_combination = TRUE; + else if (link_attrs->dest && (link_attrs->page || link_attrs->has_pos)) + invalid_combination = TRUE; + + } else if (link_attrs->uri && link_attrs->dest) { + link_attrs->link_type = TAG_LINK_DEST_AND_URI; + if (link_attrs->page || link_attrs->has_pos || link_attrs->file) + invalid_combination = TRUE; + + } else if (link_attrs->uri) { + link_attrs->link_type = TAG_LINK_URI; + if (link_attrs->dest || link_attrs->page || link_attrs->has_pos || link_attrs->file) + invalid_combination = TRUE; + + } else if (link_attrs->dest) { + link_attrs->link_type = TAG_LINK_DEST; + if (link_attrs->uri || link_attrs->page || link_attrs->has_pos) + invalid_combination = TRUE; + + } else if (link_attrs->page) { + link_attrs->link_type = TAG_LINK_PAGE; + if (link_attrs->uri || link_attrs->dest) + invalid_combination = TRUE; + + } else { + link_attrs->link_type = TAG_LINK_EMPTY; + if (link_attrs->has_pos) + invalid_combination = TRUE; + } + + if (invalid_combination) { + status = _cairo_tag_error ( + "Link attributes: \"%s\" invalid combination of attributes", attributes); + } + + cleanup: + free_attributes_list (&list); + if (unlikely (status)) { + free (link_attrs->dest); + free (link_attrs->uri); + free (link_attrs->file); + _cairo_array_fini (&link_attrs->rects); + } + + return status; +} + +cairo_int_status_t +_cairo_tag_parse_dest_attributes (const char *attributes, cairo_dest_attrs_t *dest_attrs) +{ + cairo_list_t list; + cairo_int_status_t status; + attribute_t *attr; + + memset (dest_attrs, 0, sizeof (cairo_dest_attrs_t)); + cairo_list_init (&list); + status = parse_attributes (attributes, _dest_attrib_spec, &list); + if (unlikely (status)) + goto cleanup; + + cairo_list_foreach_entry (attr, attribute_t, &list, link) + { + if (strcmp (attr->name, "name") == 0) { + dest_attrs->name = strdup (attr->scalar.s); + } else if (strcmp (attr->name, "x") == 0) { + dest_attrs->x = attr->scalar.f; + dest_attrs->x_valid = TRUE; + } else if (strcmp (attr->name, "y") == 0) { + dest_attrs->y = attr->scalar.f; + dest_attrs->y_valid = TRUE; + } else if (strcmp (attr->name, "internal") == 0) { + dest_attrs->internal = attr->scalar.b; + } + } + + if (! dest_attrs->name) + status = _cairo_tag_error ("Destination attributes: \"%s\" missing name attribute", + attributes); + + cleanup: + free_attributes_list (&list); + + return status; +} + +cairo_int_status_t +_cairo_tag_parse_ccitt_params (const char *attributes, cairo_ccitt_params_t *ccitt_params) +{ + cairo_list_t list; + cairo_int_status_t status; + attribute_t *attr; + + ccitt_params->columns = -1; + ccitt_params->rows = -1; + + /* set defaults */ + ccitt_params->k = 0; + ccitt_params->end_of_line = FALSE; + ccitt_params->encoded_byte_align = FALSE; + ccitt_params->end_of_block = TRUE; + ccitt_params->black_is_1 = FALSE; + ccitt_params->damaged_rows_before_error = 0; + + cairo_list_init (&list); + status = parse_attributes (attributes, _ccitt_params_spec, &list); + if (unlikely (status)) + goto cleanup; + + cairo_list_foreach_entry (attr, attribute_t, &list, link) + { + if (strcmp (attr->name, "Columns") == 0) { + ccitt_params->columns = attr->scalar.i; + } else if (strcmp (attr->name, "Rows") == 0) { + ccitt_params->rows = attr->scalar.i; + } else if (strcmp (attr->name, "K") == 0) { + ccitt_params->k = attr->scalar.i; + } else if (strcmp (attr->name, "EndOfLine") == 0) { + ccitt_params->end_of_line = attr->scalar.b; + } else if (strcmp (attr->name, "EncodedByteAlign") == 0) { + ccitt_params->encoded_byte_align = attr->scalar.b; + } else if (strcmp (attr->name, "EndOfBlock") == 0) { + ccitt_params->end_of_block = attr->scalar.b; + } else if (strcmp (attr->name, "BlackIs1") == 0) { + ccitt_params->black_is_1 = attr->scalar.b; + } else if (strcmp (attr->name, "DamagedRowsBeforeError") == 0) { + ccitt_params->damaged_rows_before_error = attr->scalar.b; + } + } + + cleanup: + free_attributes_list (&list); + + return status; +} + +cairo_int_status_t +_cairo_tag_parse_eps_params (const char *attributes, cairo_eps_params_t *eps_params) +{ + cairo_list_t list; + cairo_int_status_t status; + attribute_t *attr; + attrib_val_t val; + + cairo_list_init (&list); + status = parse_attributes (attributes, _eps_params_spec, &list); + if (unlikely (status)) + goto cleanup; + + cairo_list_foreach_entry (attr, attribute_t, &list, link) + { + if (strcmp (attr->name, "bbox") == 0) { + _cairo_array_copy_element (&attr->array, 0, &val); + eps_params->bbox.p1.x = val.f; + _cairo_array_copy_element (&attr->array, 1, &val); + eps_params->bbox.p1.y = val.f; + _cairo_array_copy_element (&attr->array, 2, &val); + eps_params->bbox.p2.x = val.f; + _cairo_array_copy_element (&attr->array, 3, &val); + eps_params->bbox.p2.y = val.f; + } + } + + cleanup: + free_attributes_list (&list); + + return status; +} + +void +_cairo_tag_free_link_attributes (cairo_link_attrs_t *link_attrs) +{ + _cairo_array_fini (&link_attrs->rects); + free (link_attrs->dest); + free (link_attrs->uri); + free (link_attrs->file); + free (link_attrs->id); + free (link_attrs->ref); +} + +void +_cairo_tag_free_dest_attributes (cairo_dest_attrs_t *dest_attrs) +{ + free (dest_attrs->name); +} + +void +_cairo_tag_free_content_attributes (cairo_content_attrs_t *content_attrs) +{ + free (content_attrs->id); + free (content_attrs->tag_name); +} + +void +_cairo_tag_free_content_ref_attributes (cairo_content_ref_attrs_t *content_ref_attrs) +{ + free (content_ref_attrs->ref); +} diff --git a/local/recipes/libs/cairo/source/src/cairo-tag-stack-private.h b/local/recipes/libs/cairo/source/src/cairo-tag-stack-private.h new file mode 100644 index 0000000000..b3878ddb2e --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-tag-stack-private.h @@ -0,0 +1,122 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2016 Adrian Johnson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Adrian Johnson. + * + * Contributor(s): + * Adrian Johnson + */ + +#ifndef CAIRO_TAG_STACK_PRIVATE_H +#define CAIRO_TAG_STACK_PRIVATE_H + +#include "cairo-error-private.h" +#include "cairo-list-inline.h" + +/* The type of a single tag */ +typedef enum { + TAG_TYPE_INVALID = 0, + TAG_TYPE_STRUCTURE = 1, + TAG_TYPE_LINK = 2, + TAG_TYPE_DEST = 4, + TAG_TYPE_CONTENT = 8, + TAG_TYPE_CONTENT_REF = 16, + TAG_TYPE_ARTIFACT = 16, +} cairo_tag_type_t; + +/* The type of the structure tree. */ +typedef enum _cairo_tag_stack_structure_type { + TAG_TREE_TYPE_TAGGED, /* compliant with Tagged PDF */ + TAG_TREE_TYPE_STRUCTURE, /* valid structure but not 'Tagged PDF' compliant */ + TAG_TREE_TYPE_LINK_ONLY, /* contains Link tags only */ + TAG_TREE_TYPE_NO_TAGS, /* no tags used */ + TAG_TREE_TYPE_INVALID, /* invalid tag structure */ +} cairo_tag_stack_structure_type_t; + +typedef struct _cairo_tag_stack_elem { + char *name; + char *attributes; + void *data; + cairo_list_t link; + +} cairo_tag_stack_elem_t; + +typedef struct _cairo_tag_stack { + cairo_list_t list; + cairo_tag_stack_structure_type_t type; + int size; + +} cairo_tag_stack_t; + +cairo_private void +_cairo_tag_stack_init (cairo_tag_stack_t *stack); + +cairo_private void +_cairo_tag_stack_fini (cairo_tag_stack_t *stack); + +cairo_private cairo_tag_stack_structure_type_t +_cairo_tag_stack_get_structure_type (cairo_tag_stack_t *stack); + +cairo_private cairo_int_status_t +_cairo_tag_stack_push (cairo_tag_stack_t *stack, + const char *name, + const char *attributes); + +cairo_private void +_cairo_tag_stack_set_top_data (cairo_tag_stack_t *stack, + void *data); + +cairo_private cairo_int_status_t +_cairo_tag_stack_pop (cairo_tag_stack_t *stack, + const char *name, + cairo_tag_stack_elem_t **elem); + +cairo_private cairo_tag_stack_elem_t * +_cairo_tag_stack_top_elem (cairo_tag_stack_t *stack); + +cairo_private void +_cairo_tag_stack_foreach (cairo_tag_stack_t *stack, + void (*func)(cairo_tag_stack_elem_t *elem, + void *closure), + void *closure); + +cairo_private void +_cairo_tag_stack_free_elem (cairo_tag_stack_elem_t *elem); + +cairo_private cairo_tag_type_t +_cairo_tag_get_type (const char *name); + +cairo_private cairo_status_t +_cairo_tag_error (const char *fmt, ...) CAIRO_PRINTF_FORMAT (1, 2); + +cairo_private void +_cairo_tag_warning (const char *fmt, ...) CAIRO_PRINTF_FORMAT (1, 2); + +#endif /* CAIRO_TAG_STACK_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-tag-stack.c b/local/recipes/libs/cairo/source/src/cairo-tag-stack.c new file mode 100644 index 0000000000..0d32f4fab9 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-tag-stack.c @@ -0,0 +1,347 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2016 Adrian Johnson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Adrian Johnson. + * + * Contributor(s): + * Adrian Johnson + */ + +#include "cairoint.h" + +#include "cairo-tag-stack-private.h" + +/* Tagged PDF must have one of these tags at the top level */ +static const char * _cairo_tag_stack_tagged_pdf_top_level_element_list[] = +{ + "Document", + "Part", + "Art", + "Sect", + "Div", + NULL +}; + +/* List of valid tag names. Table numbers reference PDF 32000 */ +static const char * _cairo_tag_stack_struct_pdf_list[] = +{ + /* Table 333 - Grouping Elements */ + "Document", + "Part", + "Art", + "Sect", + "Div", + "BlockQuote", + "Caption", + "TOC", + "TOCI", + "Index", + "NonStruct", + "Private", + + /* Table 335 - Standard structure types for paragraphlike elements */ + "P", "H", + "H1", "H2", "H3", "H4", "H5", "H6", + + /* Table 336 - Standard structure types for list elements */ + "L", "LI", "Lbl", "LBody", + + /* Table 337 - Standard structure types for table elements */ + "Table", + "TR", "TH", "TD", + "THead", "TBody", "TFoot", + + /* Table 338 - Standard structure types for inline-level structure elements */ + "Span", + "Quote", + "Note", + "Reference", + "BibEntry", + "Code", + "Link", /* CAIRO_TAG_LINK */ + "Annot", + "Ruby", + "Warichu", + + /* Table 339 - Standard structure types for Ruby and Warichu elements */ + "RB", "RT", "RP", + "WT", "WP", + + /* Table 340 - Standard structure types for illustration elements */ + "Figure", + "Formula", + "Form", + + /* Section 14.8.2.2.2 - Artifacts */ + "Artifact", + + NULL +}; + +/* List of cairo specific tag names */ +static const char * _cairo_tag_stack_cairo_tag_list[] = +{ + CAIRO_TAG_DEST, + CAIRO_TAG_CONTENT, + CAIRO_TAG_CONTENT_REF, + NULL +}; + +void +_cairo_tag_stack_init (cairo_tag_stack_t *stack) +{ + cairo_list_init (&stack->list); + stack->type = TAG_TREE_TYPE_NO_TAGS; + stack->size = 0; +} + +void +_cairo_tag_stack_fini (cairo_tag_stack_t *stack) +{ + while (! cairo_list_is_empty (&stack->list)) { + cairo_tag_stack_elem_t *elem; + + elem = cairo_list_first_entry (&stack->list, cairo_tag_stack_elem_t, link); + cairo_list_del (&elem->link); + free (elem->name); + free (elem->attributes); + free (elem); + } +} + +cairo_tag_stack_structure_type_t +_cairo_tag_stack_get_structure_type (cairo_tag_stack_t *stack) +{ + return stack->type; +} + +static cairo_bool_t +name_in_list (const char *name, const char **list) +{ + if (! name) + return FALSE; + + while (*list) { + if (strcmp (name, *list) == 0) + return TRUE; + list++; + } + + return FALSE; +} + +cairo_int_status_t +_cairo_tag_stack_push (cairo_tag_stack_t *stack, + const char *name, + const char *attributes) +{ + cairo_tag_stack_elem_t *elem; + + if (! name_in_list (name, _cairo_tag_stack_struct_pdf_list) && + ! name_in_list (name, _cairo_tag_stack_cairo_tag_list)) + { + stack->type = TAG_TYPE_INVALID; + return _cairo_tag_error ("Invalid tag: %s", name); + } + + cairo_tag_stack_elem_t *top = _cairo_tag_stack_top_elem (stack); + if (top && + (strcmp (top->name, CAIRO_TAG_CONTENT) == 0 || + strcmp (top->name, CAIRO_TAG_CONTENT_REF) == 0 || + strcmp (top->name, "Artifact") == 0)) + { + return _cairo_tag_error ("%s tag can not contain nested tags", + (strcmp (top->name, CAIRO_TAG_CONTENT) == 0) ? "CAIRO_TAG_CONTENT" : + ((strcmp (top->name, CAIRO_TAG_CONTENT_REF) == 0) ? "CAIRO_TAG_CONTENT_REF" : top->name)); + } + + if (stack->type == TAG_TREE_TYPE_NO_TAGS) { + if (name_in_list (name, _cairo_tag_stack_tagged_pdf_top_level_element_list)) + stack->type = TAG_TREE_TYPE_TAGGED; + else if (strcmp (name, "Link") == 0) + stack->type = TAG_TREE_TYPE_LINK_ONLY; + else if (name_in_list (name, _cairo_tag_stack_struct_pdf_list)) + stack->type = TAG_TREE_TYPE_STRUCTURE; + } else { + if (stack->type == TAG_TREE_TYPE_LINK_ONLY && + (strcmp (name, "Link") != 0) && + name_in_list (name, _cairo_tag_stack_struct_pdf_list)) + { + stack->type = TAG_TREE_TYPE_STRUCTURE; + } + } + + elem = _cairo_calloc (sizeof(cairo_tag_stack_elem_t)); + if (unlikely (elem == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + elem->name = strdup (name); + if (unlikely (elem->name == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + if (attributes) { + elem->attributes = strdup (attributes); + if (unlikely (elem->attributes == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } else { + elem->attributes = NULL; + } + + elem->data = NULL; + + cairo_list_add_tail (&elem->link, &stack->list); + stack->size++; + + return CAIRO_STATUS_SUCCESS; +} + +cairo_private void +_cairo_tag_stack_set_top_data (cairo_tag_stack_t *stack, + void *data) +{ + cairo_tag_stack_elem_t *top; + + top = _cairo_tag_stack_top_elem (stack); + if (top) + top->data = data; +} + +cairo_int_status_t +_cairo_tag_stack_pop (cairo_tag_stack_t *stack, + const char *name, + cairo_tag_stack_elem_t **elem) +{ + cairo_tag_stack_elem_t *top; + + top = _cairo_tag_stack_top_elem (stack); + if (!top) { + stack->type = TAG_TYPE_INVALID; + return _cairo_tag_error ("cairo_tag_end(\"%s\") no matching begin tag", name); + } + + cairo_list_del (&top->link); + stack->size--; + if (strcmp (top->name, name) != 0) { + cairo_status_t status = + _cairo_tag_error ("cairo_tag_end(\"%s\") does not matching previous begin tag \"%s\"", + name, top->name); + stack->type = TAG_TYPE_INVALID; + _cairo_tag_stack_free_elem (top); + return status; + } + + if (elem) + *elem = top; + else + _cairo_tag_stack_free_elem (top); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_tag_stack_elem_t * +_cairo_tag_stack_top_elem (cairo_tag_stack_t *stack) +{ + if (cairo_list_is_empty (&stack->list)) + return NULL; + + return cairo_list_last_entry (&stack->list, cairo_tag_stack_elem_t, link); +} + +void +_cairo_tag_stack_foreach (cairo_tag_stack_t *stack, + void (*func)(cairo_tag_stack_elem_t *elem, + void *closure), + void *closure) +{ + cairo_tag_stack_elem_t *elem; + + cairo_list_foreach_entry (elem, cairo_tag_stack_elem_t, &stack->list, link) { + func (elem, closure); + } +} + +void +_cairo_tag_stack_free_elem (cairo_tag_stack_elem_t *elem) +{ + free (elem->name); + free (elem->attributes); + free (elem); +} + +cairo_tag_type_t +_cairo_tag_get_type (const char *name) +{ + if (! name_in_list (name, _cairo_tag_stack_struct_pdf_list) && + ! name_in_list (name, _cairo_tag_stack_cairo_tag_list)) + return TAG_TYPE_INVALID; + + if (strcmp(name, "Link") == 0) + return (TAG_TYPE_LINK | TAG_TYPE_STRUCTURE); + + if (strcmp(name, CAIRO_TAG_DEST) == 0) + return TAG_TYPE_DEST; + + if (strcmp(name, CAIRO_TAG_CONTENT) == 0) + return TAG_TYPE_CONTENT; + + if (strcmp(name, CAIRO_TAG_CONTENT_REF) == 0) + return TAG_TYPE_CONTENT_REF; + + return TAG_TYPE_STRUCTURE; +} + +cairo_status_t +_cairo_tag_error (const char *fmt, ...) +{ + va_list ap; + + if (getenv ("CAIRO_DEBUG_TAG") != NULL) { + printf ("TAG ERROR: "); + va_start (ap, fmt); + vprintf (fmt, ap); + va_end (ap); + printf ("\n"); + } + return _cairo_error (CAIRO_STATUS_TAG_ERROR); +} + +void +_cairo_tag_warning (const char *fmt, ...) +{ + va_list ap; + + if (getenv ("CAIRO_DEBUG_TAG") != NULL) { + printf ("TAG WARNING: "); + va_start (ap, fmt); + vprintf (fmt, ap); + va_end (ap); + printf ("\n"); + } +} diff --git a/local/recipes/libs/cairo/source/src/cairo-tee-surface.c b/local/recipes/libs/cairo/source/src/cairo-tee-surface.c new file mode 100644 index 0000000000..1739912907 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-tee-surface.c @@ -0,0 +1,625 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * Copyright © 2009 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Carl Worth + * Chris Wilson + */ + +/** + * SECTION:cairo-tee + * @Title: Tee surface + * @Short_Description: Redirect input to multiple surfaces + * @See_Also: #cairo_surface_t + * + * The "tee" surface supports redirecting all its input to multiple surfaces. + **/ + +/** + * CAIRO_HAS_TEE_SURFACE: + * + * Defined if the tee surface backend is available. + * + * Since: 1.10 + **/ + +#include "cairoint.h" + +#include "cairo-tee.h" + +#include "cairo-default-context-private.h" +#include "cairo-error-private.h" +#include "cairo-recording-surface-inline.h" +#include "cairo-surface-wrapper-private.h" +#include "cairo-array-private.h" +#include "cairo-image-surface-inline.h" + +typedef struct _cairo_tee_surface { + cairo_surface_t base; + + cairo_surface_wrapper_t primary; + cairo_array_t replicas; +} cairo_tee_surface_t; + +static cairo_surface_t * +_cairo_tee_surface_create_similar (void *abstract_surface, + cairo_content_t content, + int width, + int height) +{ + + cairo_tee_surface_t *other = abstract_surface; + cairo_surface_t *similar; + cairo_surface_t *surface; + cairo_surface_wrapper_t *replicas; + int n, num_replicas; + + similar = _cairo_surface_wrapper_create_similar (&other->primary, + content, width, height); + surface = cairo_tee_surface_create (similar); + cairo_surface_destroy (similar); + if (unlikely (surface->status)) + return surface; + + num_replicas = _cairo_array_num_elements (&other->replicas); + replicas = _cairo_array_index (&other->replicas, 0); + for (n = 0; n < num_replicas; n++) { + + similar = _cairo_surface_wrapper_create_similar (&replicas[n], + content, + width, height); + cairo_tee_surface_add (surface, similar); + cairo_surface_destroy (similar); + } + + if (unlikely (surface->status)) { + cairo_status_t status = surface->status; + cairo_surface_destroy (surface); + surface = _cairo_surface_create_in_error (status); + } + + return surface; +} + +static cairo_status_t +_cairo_tee_surface_finish (void *abstract_surface) +{ + cairo_tee_surface_t *surface = abstract_surface; + cairo_surface_wrapper_t *replicas; + int n, num_replicas; + + _cairo_surface_wrapper_fini (&surface->primary); + + num_replicas = _cairo_array_num_elements (&surface->replicas); + replicas = _cairo_array_index (&surface->replicas, 0); + for (n = 0; n < num_replicas; n++) + _cairo_surface_wrapper_fini (&replicas[n]); + + _cairo_array_fini (&surface->replicas); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_surface_t * +_cairo_tee_surface_source (void *abstract_surface, + cairo_rectangle_int_t *extents) +{ + cairo_tee_surface_t *surface = abstract_surface; + return _cairo_surface_get_source (surface->primary.target, extents); +} + +static cairo_status_t +_cairo_tee_surface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) +{ + cairo_tee_surface_t *surface = abstract_surface; + cairo_surface_wrapper_t *replicas; + int num_replicas, n; + + /* we prefer to use a real image surface if available */ + if (_cairo_surface_is_image (surface->primary.target)) { + return _cairo_surface_wrapper_acquire_source_image (&surface->primary, + image_out, image_extra); + } + + num_replicas = _cairo_array_num_elements (&surface->replicas); + replicas = _cairo_array_index (&surface->replicas, 0); + for (n = 0; n < num_replicas; n++) { + if (_cairo_surface_is_image (replicas[n].target)) { + return _cairo_surface_wrapper_acquire_source_image (&replicas[n], + image_out, + image_extra); + } + } + + return _cairo_surface_wrapper_acquire_source_image (&surface->primary, + image_out, image_extra); +} + +static void +_cairo_tee_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) +{ + cairo_tee_surface_t *surface = abstract_surface; + + _cairo_surface_wrapper_release_source_image (&surface->primary, + image, image_extra); +} + +static cairo_surface_t * +_cairo_tee_surface_snapshot (void *abstract_surface) +{ + cairo_tee_surface_t *surface = abstract_surface; + cairo_surface_wrapper_t *replicas; + int num_replicas, n; + + /* we prefer to use a recording surface for our snapshots */ + if (_cairo_surface_is_recording (surface->primary.target)) + return _cairo_surface_wrapper_snapshot (&surface->primary); + + num_replicas = _cairo_array_num_elements (&surface->replicas); + replicas = _cairo_array_index (&surface->replicas, 0); + for (n = 0; n < num_replicas; n++) { + if (_cairo_surface_is_recording (replicas[n].target)) + return _cairo_surface_wrapper_snapshot (&replicas[n]); + } + + return _cairo_surface_wrapper_snapshot (&surface->primary); +} + +static cairo_bool_t +_cairo_tee_surface_get_extents (void *abstract_surface, + cairo_rectangle_int_t *rectangle) +{ + cairo_tee_surface_t *surface = abstract_surface; + + return _cairo_surface_wrapper_get_extents (&surface->primary, rectangle); +} + +static void +_cairo_tee_surface_get_font_options (void *abstract_surface, + cairo_font_options_t *options) +{ + cairo_tee_surface_t *surface = abstract_surface; + + _cairo_surface_wrapper_get_font_options (&surface->primary, options); +} + +static cairo_int_status_t +_cairo_tee_surface_paint (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip) +{ + cairo_tee_surface_t *surface = abstract_surface; + cairo_surface_wrapper_t *replicas; + int n, num_replicas; + cairo_int_status_t status; + + num_replicas = _cairo_array_num_elements (&surface->replicas); + replicas = _cairo_array_index (&surface->replicas, 0); + for (n = 0; n < num_replicas; n++) { + status = _cairo_surface_wrapper_paint (&replicas[n], op, source, 0, clip); + if (unlikely (status)) + return status; + } + + return _cairo_surface_wrapper_paint (&surface->primary, op, source, 0, clip); +} + +static cairo_int_status_t +_cairo_tee_surface_mask (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_clip_t *clip) +{ + cairo_tee_surface_t *surface = abstract_surface; + cairo_surface_wrapper_t *replicas; + cairo_int_status_t status; + int n, num_replicas; + + num_replicas = _cairo_array_num_elements (&surface->replicas); + replicas = _cairo_array_index (&surface->replicas, 0); + for (n = 0; n < num_replicas; n++) { + status = _cairo_surface_wrapper_mask (&replicas[n], + op, source, 0, + mask, 0, + clip); + if (unlikely (status)) + return status; + } + + return _cairo_surface_wrapper_mask (&surface->primary, + op, source, 0, + mask, 0, + clip); +} + +static cairo_int_status_t +_cairo_tee_surface_stroke (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_tee_surface_t *surface = abstract_surface; + cairo_surface_wrapper_t *replicas; + cairo_int_status_t status; + int n, num_replicas; + + num_replicas = _cairo_array_num_elements (&surface->replicas); + replicas = _cairo_array_index (&surface->replicas, 0); + for (n = 0; n < num_replicas; n++) { + status = _cairo_surface_wrapper_stroke (&replicas[n], + op, source, 0, + path, style, + ctm, ctm_inverse, + tolerance, antialias, + clip); + if (unlikely (status)) + return status; + } + + return _cairo_surface_wrapper_stroke (&surface->primary, + op, source, 0, + path, style, + ctm, ctm_inverse, + tolerance, antialias, + clip); +} + +static cairo_int_status_t +_cairo_tee_surface_fill (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_tee_surface_t *surface = abstract_surface; + cairo_surface_wrapper_t *replicas; + cairo_int_status_t status; + int n, num_replicas; + + num_replicas = _cairo_array_num_elements (&surface->replicas); + replicas = _cairo_array_index (&surface->replicas, 0); + for (n = 0; n < num_replicas; n++) { + status = _cairo_surface_wrapper_fill (&replicas[n], + op, source, 0, + path, fill_rule, + tolerance, antialias, + clip); + if (unlikely (status)) + return status; + } + + return _cairo_surface_wrapper_fill (&surface->primary, + op, source, 0, + path, fill_rule, + tolerance, antialias, + clip); +} + +static cairo_bool_t +_cairo_tee_surface_has_show_text_glyphs (void *abstract_surface) +{ + return TRUE; +} + +static cairo_int_status_t +_cairo_tee_surface_show_text_glyphs (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const char *utf8, + int utf8_len, + cairo_glyph_t *glyphs, + int num_glyphs, + const cairo_text_cluster_t *clusters, + int num_clusters, + cairo_text_cluster_flags_t cluster_flags, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip) +{ + cairo_tee_surface_t *surface = abstract_surface; + cairo_surface_wrapper_t *replicas; + cairo_int_status_t status; + int n, num_replicas; + cairo_glyph_t *glyphs_copy; + + /* XXX: This copying is ugly. */ + glyphs_copy = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); + if (unlikely (glyphs_copy == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + num_replicas = _cairo_array_num_elements (&surface->replicas); + replicas = _cairo_array_index (&surface->replicas, 0); + for (n = 0; n < num_replicas; n++) { + memcpy (glyphs_copy, glyphs, sizeof (cairo_glyph_t) * num_glyphs); + status = _cairo_surface_wrapper_show_text_glyphs (&replicas[n], op, + source, 0, + utf8, utf8_len, + glyphs_copy, num_glyphs, + clusters, num_clusters, + cluster_flags, + scaled_font, + clip); + if (unlikely (status)) + goto CLEANUP; + } + + memcpy (glyphs_copy, glyphs, sizeof (cairo_glyph_t) * num_glyphs); + status = _cairo_surface_wrapper_show_text_glyphs (&surface->primary, op, + source, 0, + utf8, utf8_len, + glyphs_copy, num_glyphs, + clusters, num_clusters, + cluster_flags, + scaled_font, + clip); +CLEANUP: + free (glyphs_copy); + return status; +} + +static const cairo_surface_backend_t cairo_tee_surface_backend = { + CAIRO_SURFACE_TYPE_TEE, + _cairo_tee_surface_finish, + + _cairo_default_context_create, /* XXX */ + + _cairo_tee_surface_create_similar, + NULL, /* create similar image */ + NULL, /* map to image */ + NULL, /* unmap image */ + + _cairo_tee_surface_source, + _cairo_tee_surface_acquire_source_image, + _cairo_tee_surface_release_source_image, + _cairo_tee_surface_snapshot, + NULL, /* copy_page */ + NULL, /* show_page */ + _cairo_tee_surface_get_extents, + _cairo_tee_surface_get_font_options, + NULL, /* flush */ + NULL, /* mark_dirty_rectangle */ + + _cairo_tee_surface_paint, + _cairo_tee_surface_mask, + _cairo_tee_surface_stroke, + _cairo_tee_surface_fill, + NULL, /* fill_stroke */ + + NULL, /* show_glyphs */ + + _cairo_tee_surface_has_show_text_glyphs, + _cairo_tee_surface_show_text_glyphs +}; + +/** + * cairo_tee_surface_create: + * @primary: the primary #cairo_surface_t + * + * Creates a new "tee" surface. + * + * The @primary surface is used when querying surface options, like + * font options and extents. + * + * Operations performed on the tee surface will be replayed on any + * surface added to it. + * + * Returns: the newly created surface + * + * Since: 1.10 + **/ +cairo_surface_t * +cairo_tee_surface_create (cairo_surface_t *primary) +{ + cairo_tee_surface_t *surface; + + if (unlikely (primary->status)) + return _cairo_surface_create_in_error (primary->status); + + surface = _cairo_calloc (sizeof (cairo_tee_surface_t)); + if (unlikely (surface == NULL)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + _cairo_surface_init (&surface->base, + &cairo_tee_surface_backend, + primary->device, + primary->content, + TRUE); /* is_vector */ + + _cairo_surface_wrapper_init (&surface->primary, primary); + + _cairo_array_init (&surface->replicas, sizeof (cairo_surface_wrapper_t)); + + return &surface->base; +} + +/** + * cairo_tee_surface_add: + * @abstract_surface: a #cairo_tee_surface_t + * @target: the surface to add + * + * Adds a new target surface to the list of replicas of a + * tee surface. + * + * Since: 1.10 + **/ +void +cairo_tee_surface_add (cairo_surface_t *abstract_surface, + cairo_surface_t *target) +{ + cairo_tee_surface_t *surface; + cairo_surface_wrapper_t replica; + cairo_status_t status; + + if (unlikely (abstract_surface->status)) + return; + if (unlikely (abstract_surface->finished)) { + status = _cairo_surface_set_error (abstract_surface, + _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + return; + } + + if (abstract_surface->backend != &cairo_tee_surface_backend) { + status = _cairo_surface_set_error (abstract_surface, + _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); + return; + } + + if (unlikely (target->status)) { + status = _cairo_surface_set_error (abstract_surface, target->status); + return; + } + + surface = (cairo_tee_surface_t *) abstract_surface; + + _cairo_surface_wrapper_init (&replica, target); + status = _cairo_array_append (&surface->replicas, &replica); + if (unlikely (status)) { + _cairo_surface_wrapper_fini (&replica); + status = _cairo_surface_set_error (&surface->base, status); + } +} + +/** + * cairo_tee_surface_remove: + * @abstract_surface: a #cairo_tee_surface_t + * @target: the surface to remove + * + * Removes the given surface from the list of replicas of a + * tee surface. + * + * Since: 1.10 + **/ +void +cairo_tee_surface_remove (cairo_surface_t *abstract_surface, + cairo_surface_t *target) +{ + cairo_tee_surface_t *surface; + cairo_surface_wrapper_t *replicas; + int n, num_replicas; + + if (unlikely (abstract_surface->status)) + return; + if (unlikely (abstract_surface->finished)) { + _cairo_surface_set_error (abstract_surface, + _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + return; + } + + if (abstract_surface->backend != &cairo_tee_surface_backend) { + _cairo_surface_set_error (abstract_surface, + _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); + return; + } + + surface = (cairo_tee_surface_t *) abstract_surface; + if (target == surface->primary.target) { + _cairo_surface_set_error (abstract_surface, + _cairo_error (CAIRO_STATUS_INVALID_INDEX)); + return; + } + + num_replicas = _cairo_array_num_elements (&surface->replicas); + replicas = _cairo_array_index (&surface->replicas, 0); + for (n = 0; n < num_replicas; n++) { + if (replicas[n].target == target) + break; + } + + if (n == num_replicas) { + _cairo_surface_set_error (abstract_surface, + _cairo_error (CAIRO_STATUS_INVALID_INDEX)); + return; + } + + _cairo_surface_wrapper_fini (&replicas[n]); + for (n++; n < num_replicas; n++) + replicas[n-1] = replicas[n]; + surface->replicas.num_elements--; /* XXX: cairo_array_remove()? */ +} + +/** + * cairo_tee_surface_index: + * @abstract_surface: a #cairo_tee_surface_t + * @index: the index of the replica to retrieve + * + * Retrieves the replica surface at the given index. + * + * The primary surface used to create the #cairo_tee_surface_t is + * always set at the zero index. + * + * Returns: the surface at the given index + * + * Since: 1.10 + **/ +cairo_surface_t * +cairo_tee_surface_index (cairo_surface_t *abstract_surface, + unsigned int index) +{ + cairo_tee_surface_t *surface; + + if (unlikely (abstract_surface->status)) + return _cairo_surface_create_in_error (abstract_surface->status); + if (unlikely (abstract_surface->finished)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + + if (abstract_surface->backend != &cairo_tee_surface_backend) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); + + surface = (cairo_tee_surface_t *) abstract_surface; + if (index == 0) { + return surface->primary.target; + } else { + cairo_surface_wrapper_t *replica; + + index--; + + if (index >= _cairo_array_num_elements (&surface->replicas)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_INDEX)); + + replica = _cairo_array_index (&surface->replicas, index); + return replica->target; + } +} diff --git a/local/recipes/libs/cairo/source/src/cairo-tee.h b/local/recipes/libs/cairo/source/src/cairo-tee.h new file mode 100644 index 0000000000..58264ffff5 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-tee.h @@ -0,0 +1,66 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Chris Wilson + * + * Contributor(s): + * Chris Wilson + */ + +#ifndef CAIRO_TEE_H +#define CAIRO_TEE_H + +#include "cairo.h" + +#if CAIRO_HAS_TEE_SURFACE + +CAIRO_BEGIN_DECLS + +cairo_public cairo_surface_t * +cairo_tee_surface_create (cairo_surface_t *primary); + +cairo_public void +cairo_tee_surface_add (cairo_surface_t *abstract_surface, + cairo_surface_t *target); + +cairo_public void +cairo_tee_surface_remove (cairo_surface_t *abstract_surface, + cairo_surface_t *target); + +cairo_public cairo_surface_t * +cairo_tee_surface_index (cairo_surface_t *abstract_surface, + unsigned int index); + +CAIRO_END_DECLS + +#else /*CAIRO_HAS_TEE_SURFACE*/ +# error Cairo was not compiled with support for the TEE backend +#endif /*CAIRO_HAS_TEE_SURFACE*/ + +#endif /*CAIRO_TEE_H*/ diff --git a/local/recipes/libs/cairo/source/src/cairo-time-private.h b/local/recipes/libs/cairo/source/src/cairo-time-private.h new file mode 100644 index 0000000000..06dc912b43 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-time-private.h @@ -0,0 +1,94 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright (C) 2011 Andrea Canciani + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of the + * copyright holders not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * + * Authors: Andrea Canciani + * + */ + +#ifndef CAIRO_TIME_PRIVATE_H +#define CAIRO_TIME_PRIVATE_H + +#include "cairo-compiler-private.h" +#include "cairo-wideint-private.h" + +/* Make the base type signed for easier arithmetic */ +typedef cairo_int64_t cairo_time_t; + +#define _cairo_time_add _cairo_int64_add +#define _cairo_time_sub _cairo_int64_sub +#define _cairo_time_gt _cairo_int64_gt +#define _cairo_time_lt _cairo_int64_lt + +#define _cairo_time_to_double _cairo_int64_to_double +#define _cairo_time_from_double _cairo_double_to_int64 + +cairo_private int +_cairo_time_cmp (const void *a, + const void *b); + +cairo_private double +_cairo_time_to_s (cairo_time_t t); + +cairo_private cairo_time_t +_cairo_time_from_s (double t); + +cairo_private cairo_time_t +_cairo_time_get (void); + +static cairo_always_inline cairo_time_t +_cairo_time_get_delta (cairo_time_t t) +{ + cairo_time_t now; + + now = _cairo_time_get (); + + return _cairo_time_sub (now, t); +} + +static cairo_always_inline double +_cairo_time_to_ns (cairo_time_t t) +{ + return 1.e9 * _cairo_time_to_s (t); +} + +static cairo_always_inline cairo_time_t +_cairo_time_max (cairo_time_t a, cairo_time_t b) +{ + if (_cairo_int64_gt (a, b)) + return a; + else + return b; +} + +static cairo_always_inline cairo_time_t +_cairo_time_min (cairo_time_t a, cairo_time_t b) +{ + if (_cairo_int64_lt (a, b)) + return a; + else + return b; +} + +#endif diff --git a/local/recipes/libs/cairo/source/src/cairo-time.c b/local/recipes/libs/cairo/source/src/cairo-time.c new file mode 100644 index 0000000000..05b64e1571 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-time.c @@ -0,0 +1,196 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright (c) 2007 Netlabs + * Copyright (c) 2006 Mozilla Corporation + * Copyright (c) 2006 Red Hat, Inc. + * Copyright (c) 2011 Andrea Canciani + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * the authors not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. The authors make no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Peter Weilbacher + * Vladimir Vukicevic + * Carl Worth + * Andrea Canciani + */ + +#include "cairoint.h" + +#include "cairo-time-private.h" + +#if HAVE_CLOCK_GETTIME +#if defined(CLOCK_MONOTONIC_RAW) +#define CAIRO_CLOCK CLOCK_MONOTONIC_RAW +#elif defined(CLOCK_MONOTONIC) +#define CAIRO_CLOCK CLOCK_MONOTONIC +#endif +#endif + +#if defined(__APPLE__) +#include + +static cairo_always_inline double +_cairo_time_1s (void) +{ + mach_timebase_info_data_t freq; + + mach_timebase_info (&freq); + + return 1000000000. * freq.denom / freq.numer; +} + +cairo_time_t +_cairo_time_get (void) +{ + return mach_absolute_time (); +} + +#elif _WIN32 +#include + +static cairo_always_inline double +_cairo_time_1s (void) +{ + LARGE_INTEGER freq; + + QueryPerformanceFrequency (&freq); + + return freq.QuadPart; +} + +#ifndef HAVE_UINT64_T +static cairo_always_inline cairo_time_t +_cairo_time_from_large_integer (LARGE_INTEGER t) +{ + cairo_int64_t r; + + r = _cairo_int64_lsl (_cairo_int32_to_int64 (t.HighPart), 32); + r = _cairo_int64_add (r, _cairo_int32_to_int64 (t.LowPart)); + + return r; +} +#else +static cairo_always_inline cairo_time_t +_cairo_time_from_large_integer (LARGE_INTEGER t) +{ + return t.QuadPart; +} +#endif + +cairo_time_t +_cairo_time_get (void) +{ + LARGE_INTEGER t; + + QueryPerformanceCounter (&t); + + return _cairo_time_from_large_integer(t); +} + +#elif defined(CAIRO_CLOCK) +#include + +static cairo_always_inline double +_cairo_time_1s (void) +{ + return 1000000000; +} + +cairo_time_t +_cairo_time_get (void) +{ + struct timespec t; + cairo_time_t r; + + clock_gettime (CAIRO_CLOCK, &t); + + r = _cairo_double_to_int64 (_cairo_time_1s ()); + r = _cairo_int64_mul (r, _cairo_int32_to_int64 (t.tv_sec)); + r = _cairo_int64_add (r, _cairo_int32_to_int64 (t.tv_nsec)); + + return r; +} + +#else +#include + +static cairo_always_inline double +_cairo_time_1s (void) +{ + return 1000000; +} + +cairo_time_t +_cairo_time_get (void) +{ + struct timeval t; + cairo_time_t r; + + gettimeofday (&t, NULL); + + r = _cairo_double_to_int64 (_cairo_time_1s ()); + r = _cairo_int64_mul (r, _cairo_int32_to_int64 (t.tv_sec)); + r = _cairo_int64_add (r, _cairo_int32_to_int64 (t.tv_usec)); + + return r; +} + +#endif + +int +_cairo_time_cmp (const void *a, + const void *b) +{ + const cairo_time_t *ta = a, *tb = b; + return _cairo_int64_cmp (*ta, *tb); +} + +static double +_cairo_time_ticks_per_sec (void) +{ + static double ticks = 0; + + if (unlikely (ticks == 0)) + ticks = _cairo_time_1s (); + + return ticks; +} + +static double +_cairo_time_s_per_tick (void) +{ + static double s = 0; + + if (unlikely (s == 0)) + s = 1. / _cairo_time_ticks_per_sec (); + + return s; +} + +double +_cairo_time_to_s (cairo_time_t t) +{ + return _cairo_int64_to_double (t) * _cairo_time_s_per_tick (); +} + +cairo_time_t +_cairo_time_from_s (double t) +{ + return _cairo_double_to_int64 (t * _cairo_time_ticks_per_sec ()); +} diff --git a/local/recipes/libs/cairo/source/src/cairo-tor-scan-converter.c b/local/recipes/libs/cairo/source/src/cairo-tor-scan-converter.c new file mode 100644 index 0000000000..f29359ce4e --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-tor-scan-converter.c @@ -0,0 +1,1899 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* glitter-paths - polygon scan converter + * + * Copyright (c) 2008 M Joonas Pihlaja + * Copyright (c) 2007 David Turner + * + * 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. + */ +/* This is the Glitter paths scan converter incorporated into cairo. + * The source is from commit 734c53237a867a773640bd5b64816249fa1730f8 + * of + * + * https://gitweb.freedesktop.org/?p=users/joonas/glitter-paths + */ +/* Glitter-paths is a stand alone polygon rasteriser derived from + * David Turner's reimplementation of Tor Anderssons's 15x17 + * supersampling rasteriser from the Apparition graphics library. The + * main new feature here is cheaply choosing per-scan line between + * doing fully analytical coverage computation for an entire row at a + * time vs. using a supersampling approach. + * + * David Turner's code can be found at + * + * http://david.freetype.org/rasterizer-shootout/raster-comparison-20070813.tar.bz2 + * + * In particular this file incorporates large parts of ftgrays_tor10.h + * from raster-comparison-20070813.tar.bz2 + */ +/* Overview + * + * A scan converter's basic purpose to take polygon edges and convert + * them into an RLE compressed A8 mask. This one works in two phases: + * gathering edges and generating spans. + * + * 1) As the user feeds the scan converter edges they are vertically + * clipped and bucketted into a _polygon_ data structure. The edges + * are also snapped from the user's coordinates to the subpixel grid + * coordinates used during scan conversion. + * + * user + * | + * | edges + * V + * polygon buckets + * + * 2) Generating spans works by performing a vertical sweep of pixel + * rows from top to bottom and maintaining an _active_list_ of edges + * that intersect the row. From the active list the fill rule + * determines which edges are the left and right edges of the start of + * each span, and their contribution is then accumulated into a pixel + * coverage list (_cell_list_) as coverage deltas. Once the coverage + * deltas of all edges are known we can form spans of constant pixel + * coverage by summing the deltas during a traversal of the cell list. + * At the end of a pixel row the cell list is sent to a coverage + * blitter for rendering to some target surface. + * + * The pixel coverages are computed by either supersampling the row + * and box filtering a mono rasterisation, or by computing the exact + * coverages of edges in the active list. The supersampling method is + * used whenever some edge starts or stops within the row or there are + * edge intersections in the row. + * + * polygon bucket for \ + * current pixel row | + * | | + * | activate new edges | Repeat GRID_Y times if we + * V \ are supersampling this row, + * active list / or just once if we're computing + * | | analytical coverage. + * | coverage deltas | + * V | + * pixel coverage list / + * | + * V + * coverage blitter + */ +#include "cairoint.h" +#include "cairo-spans-private.h" +#include "cairo-error-private.h" + +#include +#include +#include +#include + +/*------------------------------------------------------------------------- + * cairo specific config + */ +#define I static + +/* Prefer cairo's status type. */ +#define GLITTER_HAVE_STATUS_T 1 +#define GLITTER_STATUS_SUCCESS CAIRO_STATUS_SUCCESS +#define GLITTER_STATUS_NO_MEMORY CAIRO_STATUS_NO_MEMORY +typedef cairo_status_t glitter_status_t; + +/* The input coordinate scale and the rasterisation grid scales. */ +#define GLITTER_INPUT_BITS CAIRO_FIXED_FRAC_BITS +#define GRID_X_BITS CAIRO_FIXED_FRAC_BITS +#define GRID_Y 15 + +/* Set glitter up to use a cairo span renderer to do the coverage + * blitting. */ +struct pool; +struct cell_list; + +/*------------------------------------------------------------------------- + * glitter-paths.h + */ + +/* "Input scaled" numbers are fixed precision reals with multiplier + * 2**GLITTER_INPUT_BITS. Input coordinates are given to glitter as + * pixel scaled numbers. These get converted to the internal grid + * scaled numbers as soon as possible. Internal overflow is possible + * if GRID_X/Y inside glitter-paths.c is larger than + * 1< +#include +#include + +/* All polygon coordinates are snapped onto a subsample grid. "Grid + * scaled" numbers are fixed precision reals with multiplier GRID_X or + * GRID_Y. */ +typedef int grid_scaled_t; +typedef int grid_scaled_x_t; +typedef int grid_scaled_y_t; + +/* Default x/y scale factors. + * You can either define GRID_X/Y_BITS to get a power-of-two scale + * or define GRID_X/Y separately. */ +#if !defined(GRID_X) && !defined(GRID_X_BITS) +# define GRID_X_BITS 8 +#endif +#if !defined(GRID_Y) && !defined(GRID_Y_BITS) +# define GRID_Y 15 +#endif + +/* Use GRID_X/Y_BITS to define GRID_X/Y if they're available. */ +#ifdef GRID_X_BITS +# define GRID_X (1 << GRID_X_BITS) +#endif +#ifdef GRID_Y_BITS +# define GRID_Y (1 << GRID_Y_BITS) +#endif + +/* The GRID_X_TO_INT_FRAC macro splits a grid scaled coordinate into + * integer and fractional parts. The integer part is floored. */ +#if defined(GRID_X_TO_INT_FRAC) + /* do nothing */ +#elif defined(GRID_X_BITS) +# define GRID_X_TO_INT_FRAC(x, i, f) \ + _GRID_TO_INT_FRAC_shift(x, i, f, GRID_X_BITS) +#else +# define GRID_X_TO_INT_FRAC(x, i, f) \ + _GRID_TO_INT_FRAC_general(x, i, f, GRID_X) +#endif + +#define _GRID_TO_INT_FRAC_general(t, i, f, m) do { \ + (i) = (t) / (m); \ + (f) = (t) % (m); \ + if ((f) < 0) { \ + --(i); \ + (f) += (m); \ + } \ +} while (0) + +#define _GRID_TO_INT_FRAC_shift(t, i, f, b) do { \ + (f) = (t) & ((1 << (b)) - 1); \ + (i) = (t) >> (b); \ +} while (0) + +/* A grid area is a real in [0,1] scaled by 2*GRID_X*GRID_Y. We want + * to be able to represent exactly areas of subpixel trapezoids whose + * vertices are given in grid scaled coordinates. The scale factor + * comes from needing to accurately represent the area 0.5*dx*dy of a + * triangle with base dx and height dy in grid scaled numbers. */ +#define GRID_XY (2*GRID_X*GRID_Y) /* Unit area on the grid. */ + +/* GRID_AREA_TO_ALPHA(area): map [0,GRID_XY] to [0,255]. */ +#if GRID_XY == 510 +# define GRID_AREA_TO_ALPHA(c) (((c)+1) >> 1) +#elif GRID_XY == 255 +# define GRID_AREA_TO_ALPHA(c) (c) +#elif GRID_XY == 64 +# define GRID_AREA_TO_ALPHA(c) (((c) << 2) | -(((c) & 0x40) >> 6)) +#elif GRID_XY == 128 +# define GRID_AREA_TO_ALPHA(c) ((((c) << 1) | -((c) >> 7)) & 255) +#elif GRID_XY == 256 +# define GRID_AREA_TO_ALPHA(c) (((c) | -((c) >> 8)) & 255) +#elif GRID_XY == 15 +# define GRID_AREA_TO_ALPHA(c) (((c) << 4) + (c)) +#elif GRID_XY == 2*256*15 +# define GRID_AREA_TO_ALPHA(c) (((c) + ((c)<<4) + 256) >> 9) +#else +# define GRID_AREA_TO_ALPHA(c) (((c)*255 + GRID_XY/2) / GRID_XY) +#endif + +#define UNROLL3(x) x x x + +struct quorem { + int32_t quo; + int64_t rem; +}; + +/* Header for a chunk of memory in a memory pool. */ +struct _pool_chunk { + /* # bytes used in this chunk. */ + size_t size; + + /* # bytes total in this chunk */ + size_t capacity; + + /* Pointer to the previous chunk or %NULL if this is the sentinel + * chunk in the pool header. */ + struct _pool_chunk *prev_chunk; + + /* Actual data starts here. Well aligned even for 64 bit types. */ + int64_t data; +}; + +/* The int64_t data member of _pool_chunk just exists to enforce alignment, + * it shouldn't be included in the allocated size for the struct. */ +#define SIZEOF_POOL_CHUNK (sizeof(struct _pool_chunk) - sizeof(int64_t)) + +/* A memory pool. This is supposed to be embedded on the stack or + * within some other structure. It may optionally be followed by an + * embedded array from which requests are fulfilled until + * malloc needs to be called to allocate a first real chunk. */ +struct pool { + /* Chunk we're allocating from. */ + struct _pool_chunk *current; + + jmp_buf *jmp; + + /* Free list of previously allocated chunks. All have >= default + * capacity. */ + struct _pool_chunk *first_free; + + /* The default capacity of a chunk. */ + size_t default_capacity; + + /* Header for the sentinel chunk. Directly following the pool + * struct should be some space for embedded elements from which + * the sentinel chunk allocates from. This is expressed as a char + * array so that the 'int64_t data' member of _pool_chunk isn't + * included. This way embedding struct pool in other structs works + * without wasting space. */ + char sentinel[SIZEOF_POOL_CHUNK]; +}; + +/* A polygon edge. */ +struct edge { + /* Next in y-bucket or active list. */ + struct edge *next, *prev; + + /* The clipped y of the top of the edge. */ + grid_scaled_y_t ytop; + + /* Number of subsample rows remaining to scan convert of this + * edge. */ + grid_scaled_y_t height_left; + + /* Original sign of the edge: +1 for downwards, -1 for upwards + * edges. */ + int dir; + int cell; + + /* Current x coordinate while the edge is on the active + * list. Initialised to the x coordinate of the top of the + * edge. The quotient is in grid_scaled_x_t units and the + * remainder is mod dy in grid_scaled_y_t units.*/ + struct quorem x; + + /* Advance of the current x when moving down a subsample line. */ + struct quorem dxdy; + + /* Advance of the current x when moving down a full pixel + * row. Only initialised when the height of the edge is large + * enough that there's a chance the edge could be stepped by a + * full row's worth of subsample rows at a time. */ + struct quorem dxdy_full; + + /* y2-y1 after orienting the edge downwards. */ + int64_t dy; +}; + +#define EDGE_Y_BUCKET_INDEX(y, ymin) (((y) - (ymin))/GRID_Y) + +/* A collection of sorted and vertically clipped edges of the polygon. + * Edges are moved from the polygon to an active list while scan + * converting. */ +struct polygon { + /* The vertical clip extents. */ + grid_scaled_y_t ymin, ymax; + + /* Array of edges all starting in the same bucket. An edge is put + * into bucket EDGE_BUCKET_INDEX(edge->ytop, polygon->ymin) when + * it is added to the polygon. */ + struct edge **y_buckets; + struct edge *y_buckets_embedded[64]; + + struct { + struct pool base[1]; + struct edge embedded[32]; + } edge_pool; +}; + +/* A cell records the effect on pixel coverage of polygon edges + * passing through a pixel. It contains two accumulators of pixel + * coverage. + * + * Consider the effects of a polygon edge on the coverage of a pixel + * it intersects and that of the following one. The coverage of the + * following pixel is the height of the edge multiplied by the width + * of the pixel, and the coverage of the pixel itself is the area of + * the trapezoid formed by the edge and the right side of the pixel. + * + * +-----------------------+-----------------------+ + * | | | + * | | | + * |_______________________|_______________________| + * | \...................|.......................|\ + * | \..................|.......................| | + * | \.................|.......................| | + * | \....covered.....|.......................| | + * | \....area.......|.......................| } covered height + * | \..............|.......................| | + * |uncovered\.............|.......................| | + * | area \............|.......................| | + * |___________\...........|.......................|/ + * | | | + * | | | + * | | | + * +-----------------------+-----------------------+ + * + * Since the coverage of the following pixel will always be a multiple + * of the width of the pixel, we can store the height of the covered + * area instead. The coverage of the pixel itself is the total + * coverage minus the area of the uncovered area to the left of the + * edge. As it's faster to compute the uncovered area we only store + * that and subtract it from the total coverage later when forming + * spans to blit. + * + * The heights and areas are signed, with left edges of the polygon + * having positive sign and right edges having negative sign. When + * two edges intersect they swap their left/rightness so their + * contribution above and below the intersection point must be + * computed separately. */ +struct cell { + struct cell *next; + int x; + int16_t uncovered_area; + int16_t covered_height; +}; + +/* A cell list represents the scan line sparsely as cells ordered by + * ascending x. It is geared towards scanning the cells in order + * using an internal cursor. */ +struct cell_list { + /* Sentinel nodes */ + struct cell head, tail; + + /* Cursor state for iterating through the cell list. */ + struct cell *cursor, *rewind; + + /* Cells in the cell list are owned by the cell list and are + * allocated from this pool. */ + struct { + struct pool base[1]; + struct cell embedded[32]; + } cell_pool; +}; + +struct cell_pair { + struct cell *cell1; + struct cell *cell2; +}; + +/* The active list contains edges in the current scan line ordered by + * the x-coordinate of the intercept of the edge and the scan line. */ +struct active_list { + /* Leftmost edge on the current scan line. */ + struct edge head, tail; + + /* A lower bound on the height of the active edges is used to + * estimate how soon some active edge ends. We can't advance the + * scan conversion by a full pixel row if an edge ends somewhere + * within it. */ + grid_scaled_y_t min_height; + int is_vertical; +}; + +struct glitter_scan_converter { + struct polygon polygon[1]; + struct active_list active[1]; + struct cell_list coverages[1]; + + cairo_half_open_span_t *spans; + cairo_half_open_span_t spans_embedded[64]; + + /* Clip box. */ + grid_scaled_x_t xmin, xmax; + grid_scaled_y_t ymin, ymax; +}; + +static struct _pool_chunk * +_pool_chunk_init( + struct _pool_chunk *p, + struct _pool_chunk *prev_chunk, + size_t capacity) +{ + p->prev_chunk = prev_chunk; + p->size = 0; + p->capacity = capacity; + return p; +} + +static struct _pool_chunk * +_pool_chunk_create(struct pool *pool, size_t size) +{ + struct _pool_chunk *p; + + p = _cairo_malloc (SIZEOF_POOL_CHUNK + size); + if (unlikely (NULL == p)) + longjmp (*pool->jmp, _cairo_error (CAIRO_STATUS_NO_MEMORY)); + + return _pool_chunk_init(p, pool->current, size); +} + +static void +pool_init(struct pool *pool, + jmp_buf *jmp, + size_t default_capacity, + size_t embedded_capacity) +{ + pool->jmp = jmp; + pool->current = (void*) pool->sentinel; + pool->first_free = NULL; + pool->default_capacity = default_capacity; + _pool_chunk_init(pool->current, NULL, embedded_capacity); +} + +static void +pool_fini(struct pool *pool) +{ + struct _pool_chunk *p = pool->current; + do { + while (NULL != p) { + struct _pool_chunk *prev = p->prev_chunk; + if (p != (void *) pool->sentinel) + free(p); + p = prev; + } + p = pool->first_free; + pool->first_free = NULL; + } while (NULL != p); +} + +/* Satisfy an allocation by first allocating a new large enough chunk + * and adding it to the head of the pool's chunk list. This function + * is called as a fallback if pool_alloc() couldn't do a quick + * allocation from the current chunk in the pool. */ +static void * +_pool_alloc_from_new_chunk( + struct pool *pool, + size_t size) +{ + struct _pool_chunk *chunk; + void *obj; + size_t capacity; + + /* If the allocation is smaller than the default chunk size then + * try getting a chunk off the free list. Force alloc of a new + * chunk for large requests. */ + capacity = size; + chunk = NULL; + if (size < pool->default_capacity) { + capacity = pool->default_capacity; + chunk = pool->first_free; + if (chunk) { + pool->first_free = chunk->prev_chunk; + _pool_chunk_init(chunk, pool->current, chunk->capacity); + } + } + + if (NULL == chunk) + chunk = _pool_chunk_create (pool, capacity); + pool->current = chunk; + + obj = ((unsigned char*)&chunk->data + chunk->size); + chunk->size += size; + return obj; +} + +/* Allocate size bytes from the pool. The first allocated address + * returned from a pool is aligned to 8 bytes. Subsequent + * addresses will maintain alignment as long as multiples of 8 are + * allocated. Returns the address of a new memory area or %NULL on + * allocation failures. The pool retains ownership of the returned + * memory. */ +inline static void * +pool_alloc (struct pool *pool, size_t size) +{ + struct _pool_chunk *chunk = pool->current; + + if (size <= chunk->capacity - chunk->size) { + void *obj = ((unsigned char*)&chunk->data + chunk->size); + chunk->size += size; + return obj; + } else { + return _pool_alloc_from_new_chunk(pool, size); + } +} + +/* Relinquish all pool_alloced memory back to the pool. */ +static void +pool_reset (struct pool *pool) +{ + /* Transfer all used chunks to the chunk free list. */ + struct _pool_chunk *chunk = pool->current; + if (chunk != (void *) pool->sentinel) { + while (chunk->prev_chunk != (void *) pool->sentinel) { + chunk = chunk->prev_chunk; + } + chunk->prev_chunk = pool->first_free; + pool->first_free = pool->current; + } + /* Reset the sentinel as the current chunk. */ + pool->current = (void *) pool->sentinel; + pool->current->size = 0; +} + +/* Rewinds the cell list's cursor to the beginning. After rewinding + * we're good to cell_list_find() the cell any x coordinate. */ +inline static void +cell_list_rewind (struct cell_list *cells) +{ + cells->cursor = &cells->head; +} + +inline static void +cell_list_maybe_rewind (struct cell_list *cells, int x) +{ + if (x < cells->cursor->x) { + cells->cursor = cells->rewind; + if (x < cells->cursor->x) + cells->cursor = &cells->head; + } +} + +inline static void +cell_list_set_rewind (struct cell_list *cells) +{ + cells->rewind = cells->cursor; +} + +static void +cell_list_init(struct cell_list *cells, jmp_buf *jmp) +{ + pool_init(cells->cell_pool.base, jmp, + 256*sizeof(struct cell), + sizeof(cells->cell_pool.embedded)); + cells->tail.next = NULL; + cells->tail.x = INT_MAX; + cells->head.x = INT_MIN; + cells->head.next = &cells->tail; + cell_list_rewind (cells); +} + +static void +cell_list_fini(struct cell_list *cells) +{ + pool_fini (cells->cell_pool.base); +} + +/* Empty the cell list. This is called at the start of every pixel + * row. */ +inline static void +cell_list_reset (struct cell_list *cells) +{ + cell_list_rewind (cells); + cells->head.next = &cells->tail; + pool_reset (cells->cell_pool.base); +} + +inline static struct cell * +cell_list_alloc (struct cell_list *cells, + struct cell *tail, + int x) +{ + struct cell *cell; + + cell = pool_alloc (cells->cell_pool.base, sizeof (struct cell)); + cell->next = tail->next; + tail->next = cell; + cell->x = x; + *(uint32_t *)&cell->uncovered_area = 0; + + return cell; +} + +/* Find a cell at the given x-coordinate. Returns %NULL if a new cell + * needed to be allocated but couldn't be. Cells must be found with + * non-decreasing x-coordinate until the cell list is rewound using + * cell_list_rewind(). Ownership of the returned cell is retained by + * the cell list. */ +inline static struct cell * +cell_list_find (struct cell_list *cells, int x) +{ + struct cell *tail = cells->cursor; + + if (tail->x == x) + return tail; + + while (1) { + UNROLL3({ + if (tail->next->x > x) + break; + tail = tail->next; + }); + } + + if (tail->x != x) + tail = cell_list_alloc (cells, tail, x); + return cells->cursor = tail; + +} + +/* Find two cells at x1 and x2. This is exactly equivalent + * to + * + * pair.cell1 = cell_list_find(cells, x1); + * pair.cell2 = cell_list_find(cells, x2); + * + * except with less function call overhead. */ +inline static struct cell_pair +cell_list_find_pair(struct cell_list *cells, int x1, int x2) +{ + struct cell_pair pair; + + pair.cell1 = cells->cursor; + while (1) { + UNROLL3({ + if (pair.cell1->next->x > x1) + break; + pair.cell1 = pair.cell1->next; + }); + } + if (pair.cell1->x != x1) + pair.cell1 = cell_list_alloc (cells, pair.cell1, x1); + + pair.cell2 = pair.cell1; + while (1) { + UNROLL3({ + if (pair.cell2->next->x > x2) + break; + pair.cell2 = pair.cell2->next; + }); + } + if (pair.cell2->x != x2) + pair.cell2 = cell_list_alloc (cells, pair.cell2, x2); + + cells->cursor = pair.cell2; + return pair; +} + +/* Add a subpixel span covering [x1, x2) to the coverage cells. */ +inline static void +cell_list_add_subspan(struct cell_list *cells, + grid_scaled_x_t x1, + grid_scaled_x_t x2) +{ + int ix1, fx1; + int ix2, fx2; + + if (x1 == x2) + return; + + GRID_X_TO_INT_FRAC(x1, ix1, fx1); + GRID_X_TO_INT_FRAC(x2, ix2, fx2); + + if (ix1 != ix2) { + struct cell_pair p; + p = cell_list_find_pair(cells, ix1, ix2); + p.cell1->uncovered_area += 2*fx1; + ++p.cell1->covered_height; + p.cell2->uncovered_area -= 2*fx2; + --p.cell2->covered_height; + } else { + struct cell *cell = cell_list_find(cells, ix1); + cell->uncovered_area += 2*(fx1-fx2); + } +} + +inline static void full_step (struct edge *e) +{ + if (e->dy == 0) + return; + + e->x.quo += e->dxdy_full.quo; + e->x.rem += e->dxdy_full.rem; + if (e->x.rem < 0) { + e->x.quo--; + e->x.rem += e->dy; + } else if (e->x.rem >= e->dy) { + ++e->x.quo; + e->x.rem -= e->dy; + } + + e->cell = e->x.quo + (e->x.rem >= e->dy/2); +} + + +/* Adds the analytical coverage of an edge crossing the current pixel + * row to the coverage cells and advances the edge's x position to the + * following row. + * + * This function is only called when we know that during this pixel row: + * + * 1) The relative order of all edges on the active list doesn't + * change. In particular, no edges intersect within this row to pixel + * precision. + * + * 2) No new edges start in this row. + * + * 3) No existing edges end mid-row. + * + * This function depends on being called with all edges from the + * active list in the order they appear on the list (i.e. with + * non-decreasing x-coordinate.) */ +static void +cell_list_render_edge(struct cell_list *cells, + struct edge *edge, + int sign) +{ + struct quorem x1, x2; + grid_scaled_x_t fx1, fx2; + int ix1, ix2; + + x1 = edge->x; + full_step (edge); + x2 = edge->x; + + /* Step back from the sample location (half-subrow) to the pixel origin */ + if (edge->dy) { + x1.quo -= edge->dxdy.quo / 2; + x1.rem -= edge->dxdy.rem / 2; + if (x1.rem < 0) { + --x1.quo; + x1.rem += edge->dy; + } else if (x1.rem >= edge->dy) { + ++x1.quo; + x1.rem -= edge->dy; + } + + x2.quo -= edge->dxdy.quo / 2; + x2.rem -= edge->dxdy.rem / 2; + if (x2.rem < 0) { + --x2.quo; + x2.rem += edge->dy; + } else if (x2.rem >= edge->dy) { + ++x2.quo; + x2.rem -= edge->dy; + } + } + + GRID_X_TO_INT_FRAC(x1.quo, ix1, fx1); + GRID_X_TO_INT_FRAC(x2.quo, ix2, fx2); + + cell_list_maybe_rewind(cells, MIN(ix1, ix2)); + + /* Edge is entirely within a column? */ + if (ix1 == ix2) { + /* We always know that ix1 is >= the cell list cursor in this + * case due to the no-intersections precondition. */ + struct cell *cell = cell_list_find(cells, ix1); + cell->covered_height += sign*GRID_Y; + cell->uncovered_area += sign*(fx1 + fx2)*GRID_Y; + return; + } + + /* Orient the edge left-to-right. */ + if (ix2 < ix1) { + struct quorem tx; + int t; + + t = ix1; + ix1 = ix2; + ix2 = t; + + t = fx1; + fx1 = fx2; + fx2 = t; + + tx = x1; + x1 = x2; + x2 = tx; + } + + /* Add coverage for all pixels [ix1,ix2] on this row crossed + * by the edge. */ + { + struct cell_pair pair; + struct quorem y; + int64_t tmp, dx; + int y_last; + + dx = (x2.quo - x1.quo) * edge->dy + (x2.rem - x1.rem); + + tmp = (ix1 + 1) * GRID_X * edge->dy; + tmp -= x1.quo * edge->dy + x1.rem; + tmp *= GRID_Y; + + y.quo = tmp / dx; + y.rem = tmp % dx; + + /* When rendering a previous edge on the active list we may + * advance the cell list cursor past the leftmost pixel of the + * current edge even though the two edges don't intersect. + * e.g. consider two edges going down and rightwards: + * + * --\_+---\_+-----+-----+---- + * \_ \_ | | + * | \_ | \_ | | + * | \_| \_| | + * | \_ \_ | + * ----+-----+-\---+-\---+---- + * + * The left edge touches cells past the starting cell of the + * right edge. Fortunately such cases are rare. + */ + + pair = cell_list_find_pair(cells, ix1, ix1+1); + pair.cell1->uncovered_area += sign*y.quo*(GRID_X + fx1); + pair.cell1->covered_height += sign*y.quo; + y_last = y.quo; + + if (ix1+1 < ix2) { + struct cell *cell = pair.cell2; + struct quorem dydx_full; + + dydx_full.quo = GRID_Y * GRID_X * edge->dy / dx; + dydx_full.rem = GRID_Y * GRID_X * edge->dy % dx; + + ++ix1; + do { + y.quo += dydx_full.quo; + y.rem += dydx_full.rem; + if (y.rem >= dx) { + y.quo++; + y.rem -= dx; + } + + cell->uncovered_area += sign*(y.quo - y_last)*GRID_X; + cell->covered_height += sign*(y.quo - y_last); + y_last = y.quo; + + ++ix1; + cell = cell_list_find(cells, ix1); + } while (ix1 != ix2); + + pair.cell2 = cell; + } + pair.cell2->uncovered_area += sign*(GRID_Y - y_last)*fx2; + pair.cell2->covered_height += sign*(GRID_Y - y_last); + } +} + +static void +polygon_init (struct polygon *polygon, jmp_buf *jmp) +{ + polygon->ymin = polygon->ymax = 0; + polygon->y_buckets = polygon->y_buckets_embedded; + pool_init (polygon->edge_pool.base, jmp, + 8192 - sizeof (struct _pool_chunk), + sizeof (polygon->edge_pool.embedded)); +} + +static void +polygon_fini (struct polygon *polygon) +{ + if (polygon->y_buckets != polygon->y_buckets_embedded) + free (polygon->y_buckets); + + pool_fini (polygon->edge_pool.base); +} + +/* Empties the polygon of all edges. The polygon is then prepared to + * receive new edges and clip them to the vertical range + * [ymin,ymax). */ +static glitter_status_t +polygon_reset (struct polygon *polygon, + grid_scaled_y_t ymin, + grid_scaled_y_t ymax) +{ + unsigned h = ymax - ymin; + unsigned num_buckets = EDGE_Y_BUCKET_INDEX(ymax + GRID_Y-1, ymin); + + pool_reset(polygon->edge_pool.base); + + if (unlikely (h > 0x7FFFFFFFU - GRID_Y)) + goto bail_no_mem; /* even if you could, you wouldn't want to. */ + + if (polygon->y_buckets != polygon->y_buckets_embedded) + free (polygon->y_buckets); + + polygon->y_buckets = polygon->y_buckets_embedded; + if (num_buckets > ARRAY_LENGTH (polygon->y_buckets_embedded)) { + polygon->y_buckets = _cairo_malloc_ab (num_buckets, + sizeof (struct edge *)); + if (unlikely (NULL == polygon->y_buckets)) + goto bail_no_mem; + } + memset (polygon->y_buckets, 0, num_buckets * sizeof (struct edge *)); + + polygon->ymin = ymin; + polygon->ymax = ymax; + return GLITTER_STATUS_SUCCESS; + +bail_no_mem: + polygon->ymin = 0; + polygon->ymax = 0; + return GLITTER_STATUS_NO_MEMORY; +} + +static void +_polygon_insert_edge_into_its_y_bucket(struct polygon *polygon, + struct edge *e) +{ + unsigned ix = EDGE_Y_BUCKET_INDEX(e->ytop, polygon->ymin); + struct edge **ptail = &polygon->y_buckets[ix]; + e->next = *ptail; + *ptail = e; +} + +static void +active_list_reset (struct active_list *active) +{ + active->head.height_left = INT_MAX; + active->head.dy = 0; + active->head.cell = INT_MIN; + active->head.prev = NULL; + active->head.next = &active->tail; + active->tail.prev = &active->head; + active->tail.next = NULL; + active->tail.cell = INT_MAX; + active->tail.height_left = INT_MAX; + active->tail.dy = 0; + active->min_height = 0; + active->is_vertical = 1; +} + +static void +active_list_init(struct active_list *active) +{ + active_list_reset(active); +} + +/* + * Merge two sorted edge lists. + * Input: + * - head_a: The head of the first list. + * - head_b: The head of the second list; head_b cannot be NULL. + * Output: + * Returns the head of the merged list. + * + * Implementation notes: + * To make it fast (in particular, to reduce to an insertion sort whenever + * one of the two input lists only has a single element) we iterate through + * a list until its head becomes greater than the head of the other list, + * then we switch their roles. As soon as one of the two lists is empty, we + * just attach the other one to the current list and exit. + * Writes to memory are only needed to "switch" lists (as it also requires + * attaching to the output list the list which we will be iterating next) and + * to attach the last non-empty list. + */ +static struct edge * +merge_sorted_edges (struct edge *head_a, struct edge *head_b) +{ + struct edge *head, **next, *prev; + int32_t x; + + prev = head_a->prev; + next = &head; + if (head_a->cell <= head_b->cell) { + head = head_a; + } else { + head = head_b; + head_b->prev = prev; + goto start_with_b; + } + + do { + x = head_b->cell; + while (head_a != NULL && head_a->cell <= x) { + prev = head_a; + next = &head_a->next; + head_a = head_a->next; + } + + head_b->prev = prev; + *next = head_b; + if (head_a == NULL) + return head; + +start_with_b: + x = head_a->cell; + while (head_b != NULL && head_b->cell <= x) { + prev = head_b; + next = &head_b->next; + head_b = head_b->next; + } + + head_a->prev = prev; + *next = head_a; + if (head_b == NULL) + return head; + } while (1); +} + +/* + * Sort (part of) a list. + * Input: + * - list: The list to be sorted; list cannot be NULL. + * - limit: Recursion limit. + * Output: + * - head_out: The head of the sorted list containing the first 2^(level+1) elements of the + * input list; if the input list has fewer elements, head_out be a sorted list + * containing all the elements of the input list. + * Returns the head of the list of unprocessed elements (NULL if the sorted list contains + * all the elements of the input list). + * + * Implementation notes: + * Special case single element list, unroll/inline the sorting of the first two elements. + * Some tail recursion is used since we iterate on the bottom-up solution of the problem + * (we start with a small sorted list and keep merging other lists of the same size to it). + */ +static struct edge * +sort_edges (struct edge *list, + unsigned int level, + struct edge **head_out) +{ + struct edge *head_other, *remaining; + unsigned int i; + + head_other = list->next; + + if (head_other == NULL) { + *head_out = list; + return NULL; + } + + remaining = head_other->next; + if (list->cell <= head_other->cell) { + *head_out = list; + head_other->next = NULL; + } else { + *head_out = head_other; + head_other->prev = list->prev; + head_other->next = list; + list->prev = head_other; + list->next = NULL; + } + + for (i = 0; i < level && remaining; i++) { + remaining = sort_edges (remaining, i, &head_other); + *head_out = merge_sorted_edges (*head_out, head_other); + } + + return remaining; +} + + static struct edge * +merge_unsorted_edges (struct edge *head, struct edge *unsorted) +{ + sort_edges (unsorted, UINT_MAX, &unsorted); + return merge_sorted_edges (head, unsorted); +} + +/* Test if the edges on the active list can be safely advanced by a + * full row without intersections or any edges ending. */ +inline static int +can_do_full_row (struct active_list *active) +{ + const struct edge *e; + int prev_x = INT_MIN; + + /* Recomputes the minimum height of all edges on the active + * list if we have been dropping edges. */ + if (active->min_height <= 0) { + int min_height = INT_MAX; + int is_vertical = 1; + + e = active->head.next; + while (NULL != e) { + if (e->height_left < min_height) + min_height = e->height_left; + is_vertical &= e->dy == 0; + e = e->next; + } + + active->is_vertical = is_vertical; + active->min_height = min_height; + } + + if (active->min_height < GRID_Y) + return 0; + + /* Check for intersections as no edges end during the next row. */ + for (e = active->head.next; e != &active->tail; e = e->next) { + int cell; + + if (e->dy) { + struct quorem x = e->x; + x.quo += e->dxdy_full.quo; + x.rem += e->dxdy_full.rem; + if (x.rem < 0) { + x.quo--; + x.rem += e->dy; + } else if (x.rem >= e->dy) { + x.quo++; + x.rem -= e->dy; + } + cell = x.quo + (x.rem >= e->dy/2); + } else + cell = e->cell; + + if (cell < prev_x) + return 0; + + prev_x = cell; + } + + return 1; +} + +/* Merges edges on the given subpixel row from the polygon to the + * active_list. */ +inline static void +active_list_merge_edges_from_bucket(struct active_list *active, + struct edge *edges) +{ + active->head.next = merge_unsorted_edges (active->head.next, edges); +} + +inline static int +polygon_fill_buckets (struct active_list *active, + struct edge *edge, + int y, + struct edge **buckets) +{ + grid_scaled_y_t min_height = active->min_height; + int is_vertical = active->is_vertical; + int max_suby = 0; + + while (edge) { + struct edge *next = edge->next; + int suby = edge->ytop - y; + if (buckets[suby]) + buckets[suby]->prev = edge; + edge->next = buckets[suby]; + edge->prev = NULL; + buckets[suby] = edge; + if (edge->height_left < min_height) + min_height = edge->height_left; + is_vertical &= edge->dy == 0; + edge = next; + if (suby > max_suby) + max_suby = suby; + } + + active->is_vertical = is_vertical; + active->min_height = min_height; + + return max_suby; +} + +static void step (struct edge *edge) +{ + if (edge->dy == 0) + return; + + edge->x.quo += edge->dxdy.quo; + edge->x.rem += edge->dxdy.rem; + if (edge->x.rem < 0) { + --edge->x.quo; + edge->x.rem += edge->dy; + } else if (edge->x.rem >= edge->dy) { + ++edge->x.quo; + edge->x.rem -= edge->dy; + } + + edge->cell = edge->x.quo + (edge->x.rem >= edge->dy/2); +} + +inline static void +sub_row (struct active_list *active, + struct cell_list *coverages, + unsigned int mask) +{ + struct edge *edge = active->head.next; + int xstart = INT_MIN, prev_x = INT_MIN; + int winding = 0; + + cell_list_rewind (coverages); + + while (&active->tail != edge) { + struct edge *next = edge->next; + int xend = edge->cell; + + if (--edge->height_left) { + step (edge); + + if (edge->cell < prev_x) { + struct edge *pos = edge->prev; + pos->next = next; + next->prev = pos; + do { + pos = pos->prev; + } while (edge->cell < pos->cell); + pos->next->prev = edge; + edge->next = pos->next; + edge->prev = pos; + pos->next = edge; + } else + prev_x = edge->cell; + active->min_height = -1; + } else { + edge->prev->next = next; + next->prev = edge->prev; + } + + winding += edge->dir; + if ((winding & mask) == 0) { + if (next->cell != xend) { + cell_list_add_subspan (coverages, xstart, xend); + xstart = INT_MIN; + } + } else if (xstart == INT_MIN) + xstart = xend; + + edge = next; + } +} + +inline static void dec (struct active_list *a, struct edge *e, int h) +{ + e->height_left -= h; + if (e->height_left == 0) { + e->prev->next = e->next; + e->next->prev = e->prev; + a->min_height = -1; + } +} + +static void +full_row (struct active_list *active, + struct cell_list *coverages, + unsigned int mask) +{ + struct edge *left = active->head.next; + + while (&active->tail != left) { + struct edge *right; + int winding; + + dec (active, left, GRID_Y); + + winding = left->dir; + right = left->next; + do { + dec (active, right, GRID_Y); + + winding += right->dir; + if ((winding & mask) == 0 && right->next->cell != right->cell) + break; + + full_step (right); + + right = right->next; + } while (1); + + cell_list_set_rewind (coverages); + cell_list_render_edge (coverages, left, +1); + cell_list_render_edge (coverages, right, -1); + + left = right->next; + } +} + +static void +_glitter_scan_converter_init(glitter_scan_converter_t *converter, jmp_buf *jmp) +{ + polygon_init(converter->polygon, jmp); + active_list_init(converter->active); + cell_list_init(converter->coverages, jmp); + converter->xmin=0; + converter->ymin=0; + converter->xmax=0; + converter->ymax=0; +} + +static void +_glitter_scan_converter_fini(glitter_scan_converter_t *self) +{ + if (self->spans != self->spans_embedded) + free (self->spans); + + polygon_fini(self->polygon); + cell_list_fini(self->coverages); + + self->xmin=0; + self->ymin=0; + self->xmax=0; + self->ymax=0; +} + +static grid_scaled_t +int_to_grid_scaled(int i, int scale) +{ + /* Clamp to max/min representable scaled number. */ + if (i >= 0) { + if (i >= INT_MAX/scale) + i = INT_MAX/scale; + } + else { + if (i <= INT_MIN/scale) + i = INT_MIN/scale; + } + return i*scale; +} + +#define int_to_grid_scaled_x(x) int_to_grid_scaled((x), GRID_X) +#define int_to_grid_scaled_y(x) int_to_grid_scaled((x), GRID_Y) + +I glitter_status_t +glitter_scan_converter_reset( + glitter_scan_converter_t *converter, + int xmin, int ymin, + int xmax, int ymax) +{ + glitter_status_t status; + int max_num_spans; + + converter->xmin = 0; converter->xmax = 0; + converter->ymin = 0; converter->ymax = 0; + + max_num_spans = xmax - xmin + 1; + + if (max_num_spans > ARRAY_LENGTH(converter->spans_embedded)) { + converter->spans = _cairo_malloc_ab (max_num_spans, + sizeof (cairo_half_open_span_t)); + if (unlikely (converter->spans == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } else + converter->spans = converter->spans_embedded; + + xmin = int_to_grid_scaled_x(xmin); + ymin = int_to_grid_scaled_y(ymin); + xmax = int_to_grid_scaled_x(xmax); + ymax = int_to_grid_scaled_y(ymax); + + active_list_reset(converter->active); + cell_list_reset(converter->coverages); + status = polygon_reset(converter->polygon, ymin, ymax); + if (status) + return status; + + converter->xmin = xmin; + converter->xmax = xmax; + converter->ymin = ymin; + converter->ymax = ymax; + return GLITTER_STATUS_SUCCESS; +} + +/* INPUT_TO_GRID_X/Y (in_coord, out_grid_scaled, grid_scale) + * These macros convert an input coordinate in the client's + * device space to the rasterisation grid. + */ +/* Gah.. this bit of ugly defines INPUT_TO_GRID_X/Y so as to use + * shifts if possible, and something saneish if not. + */ +#if !defined(INPUT_TO_GRID_Y) && defined(GRID_Y_BITS) && GRID_Y_BITS <= GLITTER_INPUT_BITS +# define INPUT_TO_GRID_Y(in, out) (out) = (in) >> (GLITTER_INPUT_BITS - GRID_Y_BITS) +#else +# define INPUT_TO_GRID_Y(in, out) INPUT_TO_GRID_general(in, out, GRID_Y) +#endif + +#if !defined(INPUT_TO_GRID_X) && defined(GRID_X_BITS) && GRID_X_BITS <= GLITTER_INPUT_BITS +# define INPUT_TO_GRID_X(in, out) (out) = (in) >> (GLITTER_INPUT_BITS - GRID_X_BITS) +#else +# define INPUT_TO_GRID_X(in, out) INPUT_TO_GRID_general(in, out, GRID_X) +#endif + +#define INPUT_TO_GRID_general(in, out, grid_scale) do { \ + long long tmp__ = (long long)(grid_scale) * (in); \ + tmp__ += 1 << (GLITTER_INPUT_BITS-1); \ + tmp__ >>= GLITTER_INPUT_BITS; \ + (out) = tmp__; \ +} while (0) + +inline static void +polygon_add_edge (struct polygon *polygon, + const cairo_edge_t *edge) +{ + struct edge *e; + grid_scaled_y_t ytop, ybot; + const cairo_point_t *p1, *p2; + + INPUT_TO_GRID_Y (edge->top, ytop); + if (ytop < polygon->ymin) + ytop = polygon->ymin; + + INPUT_TO_GRID_Y (edge->bottom, ybot); + if (ybot > polygon->ymax) + ybot = polygon->ymax; + + if (ybot <= ytop) + return; + + e = pool_alloc (polygon->edge_pool.base, sizeof (struct edge)); + + e->ytop = ytop; + e->height_left = ybot - ytop; + if (edge->line.p2.y > edge->line.p1.y) { + e->dir = edge->dir; + p1 = &edge->line.p1; + p2 = &edge->line.p2; + } else { + e->dir = -edge->dir; + p1 = &edge->line.p2; + p2 = &edge->line.p1; + } + + if (p2->x == p1->x) { + e->cell = p1->x; + e->x.quo = p1->x; + e->x.rem = 0; + e->dxdy.quo = e->dxdy.rem = 0; + e->dxdy_full.quo = e->dxdy_full.rem = 0; + e->dy = 0; + } else { + int64_t Ex, Ey, tmp; + + Ex = (int64_t)(p2->x - p1->x) * GRID_X; + Ey = (int64_t)(p2->y - p1->y) * GRID_Y * (2 << GLITTER_INPUT_BITS); + + e->dxdy.quo = Ex * (2 << GLITTER_INPUT_BITS) / Ey; + e->dxdy.rem = Ex * (2 << GLITTER_INPUT_BITS) % Ey; + + tmp = (int64_t)(2*ytop + 1) << GLITTER_INPUT_BITS; + tmp -= (int64_t)p1->y * GRID_Y * 2; + tmp *= Ex; + e->x.quo = tmp / Ey; + e->x.rem = tmp % Ey; + +#if GRID_X_BITS == GLITTER_INPUT_BITS + e->x.quo += p1->x; +#else + tmp = (int64_t)p1->x * GRID_X; + e->x.quo += tmp >> GLITTER_INPUT_BITS; + e->x.rem += ((tmp & ((1 << GLITTER_INPUT_BITS) - 1)) * Ey) / (1 << GLITTER_INPUT_BITS); +#endif + + if (e->x.rem < 0) { + e->x.quo--; + e->x.rem += Ey; + } else if (e->x.rem >= Ey) { + e->x.quo++; + e->x.rem -= Ey; + } + + if (e->height_left >= GRID_Y) { + tmp = Ex * (2 * GRID_Y << GLITTER_INPUT_BITS); + e->dxdy_full.quo = tmp / Ey; + e->dxdy_full.rem = tmp % Ey; + } else + e->dxdy_full.quo = e->dxdy_full.rem = 0; + + e->cell = e->x.quo + (e->x.rem >= Ey/2); + e->dy = Ey; + } + + _polygon_insert_edge_into_its_y_bucket (polygon, e); +} + +/* Add a new polygon edge from pixel (x1,y1) to (x2,y2) to the scan + * converter. The coordinates represent pixel positions scaled by + * 2**GLITTER_PIXEL_BITS. If this function fails then the scan + * converter should be reset or destroyed. Dir must be +1 or -1, + * with the latter reversing the orientation of the edge. */ +I void +glitter_scan_converter_add_edge (glitter_scan_converter_t *converter, + const cairo_edge_t *edge) +{ + polygon_add_edge (converter->polygon, edge); +} + +static void +step_edges (struct active_list *active, int count) +{ + struct edge *edge; + + count *= GRID_Y; + for (edge = active->head.next; edge != &active->tail; edge = edge->next) { + edge->height_left -= count; + if (! edge->height_left) { + edge->prev->next = edge->next; + edge->next->prev = edge->prev; + active->min_height = -1; + } + } +} + +static glitter_status_t +blit_a8 (struct cell_list *cells, + cairo_span_renderer_t *renderer, + cairo_half_open_span_t *spans, + int y, int height, + int xmin, int xmax) +{ + struct cell *cell = cells->head.next; + int prev_x = xmin, last_x = -1; + int16_t cover = 0, last_cover = 0; + unsigned num_spans; + + if (cell == &cells->tail) + return CAIRO_STATUS_SUCCESS; + + /* Skip cells to the left of the clip region. */ + while (cell->x < xmin) { + cover += cell->covered_height; + cell = cell->next; + } + cover *= GRID_X*2; + + /* Form the spans from the coverages and areas. */ + num_spans = 0; + for (; cell->x < xmax; cell = cell->next) { + int x = cell->x; + int16_t area; + + if (x > prev_x && cover != last_cover) { + spans[num_spans].x = prev_x; + spans[num_spans].coverage = GRID_AREA_TO_ALPHA (cover); + last_cover = cover; + last_x = prev_x; + ++num_spans; + } + + cover += cell->covered_height*GRID_X*2; + area = cover - cell->uncovered_area; + + if (area != last_cover) { + spans[num_spans].x = x; + spans[num_spans].coverage = GRID_AREA_TO_ALPHA (area); + last_cover = area; + last_x = x; + ++num_spans; + } + + prev_x = x+1; + } + + if (prev_x <= xmax && cover != last_cover) { + spans[num_spans].x = prev_x; + spans[num_spans].coverage = GRID_AREA_TO_ALPHA (cover); + last_cover = cover; + last_x = prev_x; + ++num_spans; + } + + if (last_x < xmax && last_cover) { + spans[num_spans].x = xmax; + spans[num_spans].coverage = 0; + ++num_spans; + } + + /* Dump them into the renderer. */ + return renderer->render_rows (renderer, y, height, spans, num_spans); +} + +#define GRID_AREA_TO_A1(A) ((GRID_AREA_TO_ALPHA (A) > 127) ? 255 : 0) +static glitter_status_t +blit_a1 (struct cell_list *cells, + cairo_span_renderer_t *renderer, + cairo_half_open_span_t *spans, + int y, int height, + int xmin, int xmax) +{ + struct cell *cell = cells->head.next; + int prev_x = xmin, last_x = -1; + int16_t cover = 0; + uint8_t coverage, last_cover = 0; + unsigned num_spans; + + if (cell == &cells->tail) + return CAIRO_STATUS_SUCCESS; + + /* Skip cells to the left of the clip region. */ + while (cell->x < xmin) { + cover += cell->covered_height; + cell = cell->next; + } + cover *= GRID_X*2; + + /* Form the spans from the coverages and areas. */ + num_spans = 0; + for (; cell->x < xmax; cell = cell->next) { + int x = cell->x; + int16_t area; + + coverage = GRID_AREA_TO_A1 (cover); + if (x > prev_x && coverage != last_cover) { + last_x = spans[num_spans].x = prev_x; + last_cover = spans[num_spans].coverage = coverage; + ++num_spans; + } + + cover += cell->covered_height*GRID_X*2; + area = cover - cell->uncovered_area; + + coverage = GRID_AREA_TO_A1 (area); + if (coverage != last_cover) { + last_x = spans[num_spans].x = x; + last_cover = spans[num_spans].coverage = coverage; + ++num_spans; + } + + prev_x = x+1; + } + + coverage = GRID_AREA_TO_A1 (cover); + if (prev_x <= xmax && coverage != last_cover) { + last_x = spans[num_spans].x = prev_x; + last_cover = spans[num_spans].coverage = coverage; + ++num_spans; + } + + if (last_x < xmax && last_cover) { + spans[num_spans].x = xmax; + spans[num_spans].coverage = 0; + ++num_spans; + } + if (num_spans == 1) + return CAIRO_STATUS_SUCCESS; + + /* Dump them into the renderer. */ + return renderer->render_rows (renderer, y, height, spans, num_spans); +} + + +I void +glitter_scan_converter_render(glitter_scan_converter_t *converter, + unsigned int winding_mask, + int antialias, + cairo_span_renderer_t *renderer) +{ + int i, j; + int ymax_i = converter->ymax / GRID_Y; + int ymin_i = converter->ymin / GRID_Y; + int xmin_i, xmax_i; + int h = ymax_i - ymin_i; + struct polygon *polygon = converter->polygon; + struct cell_list *coverages = converter->coverages; + struct active_list *active = converter->active; + struct edge *buckets[GRID_Y] = { 0 }; + + xmin_i = converter->xmin / GRID_X; + xmax_i = converter->xmax / GRID_X; + if (xmin_i >= xmax_i) + return; + + /* Render each pixel row. */ + for (i = 0; i < h; i = j) { + int do_full_row = 0; + + j = i + 1; + + /* Determine if we can ignore this row or use the full pixel + * stepper. */ + if (polygon_fill_buckets (active, + polygon->y_buckets[i], + (i+ymin_i)*GRID_Y, + buckets) == 0) { + if (buckets[0]) { + active_list_merge_edges_from_bucket (active, buckets[0]); + buckets[0] = NULL; + } + + if (active->head.next == &active->tail) { + active->min_height = INT_MAX; + active->is_vertical = 1; + for (; j < h && ! polygon->y_buckets[j]; j++) + ; + continue; + } + + do_full_row = can_do_full_row (active); + } + + if (do_full_row) { + /* Step by a full pixel row's worth. */ + full_row (active, coverages, winding_mask); + + if (active->is_vertical) { + while (j < h && + polygon->y_buckets[j] == NULL && + active->min_height >= 2*GRID_Y) + { + active->min_height -= GRID_Y; + j++; + } + if (j != i + 1) + step_edges (active, j - (i + 1)); + } + } else { + int sub; + + /* Subsample this row. */ + for (sub = 0; sub < GRID_Y; sub++) { + if (buckets[sub]) { + active_list_merge_edges_from_bucket (active, buckets[sub]); + buckets[sub] = NULL; + } + sub_row (active, coverages, winding_mask); + } + } + + if (antialias) + blit_a8 (coverages, renderer, converter->spans, + i+ymin_i, j-i, xmin_i, xmax_i); + else + blit_a1 (coverages, renderer, converter->spans, + i+ymin_i, j-i, xmin_i, xmax_i); + cell_list_reset (coverages); + + active->min_height -= GRID_Y; + } +} + +struct _cairo_tor_scan_converter { + cairo_scan_converter_t base; + + glitter_scan_converter_t converter[1]; + cairo_fill_rule_t fill_rule; + cairo_antialias_t antialias; + + jmp_buf jmp; +}; + +typedef struct _cairo_tor_scan_converter cairo_tor_scan_converter_t; + +static void +_cairo_tor_scan_converter_destroy (void *converter) +{ + cairo_tor_scan_converter_t *self = converter; + if (self == NULL) { + return; + } + _glitter_scan_converter_fini (self->converter); + free(self); +} + +cairo_status_t +_cairo_tor_scan_converter_add_polygon (void *converter, + const cairo_polygon_t *polygon) +{ + cairo_tor_scan_converter_t *self = converter; + int i; + +#if 0 + FILE *file = fopen ("polygon.txt", "w"); + _cairo_debug_print_polygon (file, polygon); + fclose (file); +#endif + + for (i = 0; i < polygon->num_edges; i++) + glitter_scan_converter_add_edge (self->converter, &polygon->edges[i]); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_tor_scan_converter_generate (void *converter, + cairo_span_renderer_t *renderer) +{ + cairo_tor_scan_converter_t *self = converter; + cairo_status_t status; + + if ((status = setjmp (self->jmp))) + return _cairo_scan_converter_set_error (self, _cairo_error (status)); + + glitter_scan_converter_render (self->converter, + self->fill_rule == CAIRO_FILL_RULE_WINDING ? ~0 : 1, + self->antialias != CAIRO_ANTIALIAS_NONE, + renderer); + return CAIRO_STATUS_SUCCESS; +} + +cairo_scan_converter_t * +_cairo_tor_scan_converter_create (int xmin, + int ymin, + int xmax, + int ymax, + cairo_fill_rule_t fill_rule, + cairo_antialias_t antialias) +{ + cairo_tor_scan_converter_t *self; + cairo_status_t status; + + self = _cairo_calloc (sizeof(struct _cairo_tor_scan_converter)); + if (unlikely (self == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto bail_nomem; + } + + self->base.destroy = _cairo_tor_scan_converter_destroy; + self->base.generate = _cairo_tor_scan_converter_generate; + + _glitter_scan_converter_init (self->converter, &self->jmp); + status = glitter_scan_converter_reset (self->converter, + xmin, ymin, xmax, ymax); + if (unlikely (status)) + goto bail; + + self->fill_rule = fill_rule; + self->antialias = antialias; + + return &self->base; + + bail: + self->base.destroy(&self->base); + bail_nomem: + return _cairo_scan_converter_create_in_error (status); +} diff --git a/local/recipes/libs/cairo/source/src/cairo-tor22-scan-converter.c b/local/recipes/libs/cairo/source/src/cairo-tor22-scan-converter.c new file mode 100644 index 0000000000..bbdc02f3a1 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-tor22-scan-converter.c @@ -0,0 +1,1702 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* glitter-paths - polygon scan converter + * + * Copyright (c) 2008 M Joonas Pihlaja + * Copyright (c) 2007 David Turner + * + * 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. + */ +/* This is the Glitter paths scan converter incorporated into cairo. + * The source is from commit 734c53237a867a773640bd5b64816249fa1730f8 + * of + * + * https://gitweb.freedesktop.org/?p=users/joonas/glitter-paths + */ +/* Glitter-paths is a stand alone polygon rasteriser derived from + * David Turner's reimplementation of Tor Anderssons's 15x17 + * supersampling rasteriser from the Apparition graphics library. The + * main new feature here is cheaply choosing per-scan line between + * doing fully analytical coverage computation for an entire row at a + * time vs. using a supersampling approach. + * + * David Turner's code can be found at + * + * http://david.freetype.org/rasterizer-shootout/raster-comparison-20070813.tar.bz2 + * + * In particular this file incorporates large parts of ftgrays_tor10.h + * from raster-comparison-20070813.tar.bz2 + */ +/* Overview + * + * A scan converter's basic purpose to take polygon edges and convert + * them into an RLE compressed A8 mask. This one works in two phases: + * gathering edges and generating spans. + * + * 1) As the user feeds the scan converter edges they are vertically + * clipped and bucketted into a _polygon_ data structure. The edges + * are also snapped from the user's coordinates to the subpixel grid + * coordinates used during scan conversion. + * + * user + * | + * | edges + * V + * polygon buckets + * + * 2) Generating spans works by performing a vertical sweep of pixel + * rows from top to bottom and maintaining an _active_list_ of edges + * that intersect the row. From the active list the fill rule + * determines which edges are the left and right edges of the start of + * each span, and their contribution is then accumulated into a pixel + * coverage list (_cell_list_) as coverage deltas. Once the coverage + * deltas of all edges are known we can form spans of constant pixel + * coverage by summing the deltas during a traversal of the cell list. + * At the end of a pixel row the cell list is sent to a coverage + * blitter for rendering to some target surface. + * + * The pixel coverages are computed by either supersampling the row + * and box filtering a mono rasterisation, or by computing the exact + * coverages of edges in the active list. The supersampling method is + * used whenever some edge starts or stops within the row or there are + * edge intersections in the row. + * + * polygon bucket for \ + * current pixel row | + * | | + * | activate new edges | Repeat GRID_Y times if we + * V \ are supersampling this row, + * active list / or just once if we're computing + * | | analytical coverage. + * | coverage deltas | + * V | + * pixel coverage list / + * | + * V + * coverage blitter + */ +#include "cairoint.h" +#include "cairo-spans-private.h" +#include "cairo-error-private.h" + +#include +#include +#include +#include + +/*------------------------------------------------------------------------- + * cairo specific config + */ +#define I static + +/* Prefer cairo's status type. */ +#define GLITTER_HAVE_STATUS_T 1 +#define GLITTER_STATUS_SUCCESS CAIRO_STATUS_SUCCESS +#define GLITTER_STATUS_NO_MEMORY CAIRO_STATUS_NO_MEMORY +typedef cairo_status_t glitter_status_t; + +/* The input coordinate scale and the rasterisation grid scales. */ +#define GLITTER_INPUT_BITS CAIRO_FIXED_FRAC_BITS +//#define GRID_X_BITS CAIRO_FIXED_FRAC_BITS +//#define GRID_Y 15 +#define GRID_X_BITS 2 +#define GRID_Y_BITS 2 + +/* Set glitter up to use a cairo span renderer to do the coverage + * blitting. */ +struct pool; +struct cell_list; + +/*------------------------------------------------------------------------- + * glitter-paths.h + */ + +/* "Input scaled" numbers are fixed precision reals with multiplier + * 2**GLITTER_INPUT_BITS. Input coordinates are given to glitter as + * pixel scaled numbers. These get converted to the internal grid + * scaled numbers as soon as possible. Internal overflow is possible + * if GRID_X/Y inside glitter-paths.c is larger than + * 1< +#include +#include + +/* All polygon coordinates are snapped onto a subsample grid. "Grid + * scaled" numbers are fixed precision reals with multiplier GRID_X or + * GRID_Y. */ +typedef int grid_scaled_t; +typedef int grid_scaled_x_t; +typedef int grid_scaled_y_t; + +/* Default x/y scale factors. + * You can either define GRID_X/Y_BITS to get a power-of-two scale + * or define GRID_X/Y separately. */ +#if !defined(GRID_X) && !defined(GRID_X_BITS) +# define GRID_X_BITS 8 +#endif +#if !defined(GRID_Y) && !defined(GRID_Y_BITS) +# define GRID_Y 15 +#endif + +/* Use GRID_X/Y_BITS to define GRID_X/Y if they're available. */ +#ifdef GRID_X_BITS +# define GRID_X (1 << GRID_X_BITS) +#endif +#ifdef GRID_Y_BITS +# define GRID_Y (1 << GRID_Y_BITS) +#endif + +/* The GRID_X_TO_INT_FRAC macro splits a grid scaled coordinate into + * integer and fractional parts. The integer part is floored. */ +#if defined(GRID_X_TO_INT_FRAC) + /* do nothing */ +#elif defined(GRID_X_BITS) +# define GRID_X_TO_INT_FRAC(x, i, f) \ + _GRID_TO_INT_FRAC_shift(x, i, f, GRID_X_BITS) +#else +# define GRID_X_TO_INT_FRAC(x, i, f) \ + _GRID_TO_INT_FRAC_general(x, i, f, GRID_X) +#endif + +#define _GRID_TO_INT_FRAC_general(t, i, f, m) do { \ + (i) = (t) / (m); \ + (f) = (t) % (m); \ + if ((f) < 0) { \ + --(i); \ + (f) += (m); \ + } \ +} while (0) + +#define _GRID_TO_INT_FRAC_shift(t, i, f, b) do { \ + (f) = (t) & ((1 << (b)) - 1); \ + (i) = (t) >> (b); \ +} while (0) + +/* A grid area is a real in [0,1] scaled by 2*GRID_X*GRID_Y. We want + * to be able to represent exactly areas of subpixel trapezoids whose + * vertices are given in grid scaled coordinates. The scale factor + * comes from needing to accurately represent the area 0.5*dx*dy of a + * triangle with base dx and height dy in grid scaled numbers. */ +#define GRID_XY (2*GRID_X*GRID_Y) /* Unit area on the grid. */ + +/* GRID_AREA_TO_ALPHA(area): map [0,GRID_XY] to [0,255]. */ +#if GRID_XY == 510 +# define GRID_AREA_TO_ALPHA(c) (((c)+1) >> 1) +#elif GRID_XY == 255 +# define GRID_AREA_TO_ALPHA(c) (c) +#elif GRID_XY == 64 +# define GRID_AREA_TO_ALPHA(c) (((c) << 2) | -(((c) & 0x40) >> 6)) +#elif GRID_XY == 32 +# define GRID_AREA_TO_ALPHA(c) (((c) << 3) | -(((c) & 0x20) >> 5)) +#elif GRID_XY == 128 +# define GRID_AREA_TO_ALPHA(c) ((((c) << 1) | -((c) >> 7)) & 255) +#elif GRID_XY == 256 +# define GRID_AREA_TO_ALPHA(c) (((c) | -((c) >> 8)) & 255) +#elif GRID_XY == 15 +# define GRID_AREA_TO_ALPHA(c) (((c) << 4) + (c)) +#elif GRID_XY == 2*256*15 +# define GRID_AREA_TO_ALPHA(c) (((c) + ((c)<<4) + 256) >> 9) +#else +# define GRID_AREA_TO_ALPHA(c) (((c)*255 + GRID_XY/2) / GRID_XY) +#endif + +#define UNROLL3(x) x x x + +struct quorem { + int32_t quo; + int32_t rem; +}; + +/* Header for a chunk of memory in a memory pool. */ +struct _pool_chunk { + /* # bytes used in this chunk. */ + size_t size; + + /* # bytes total in this chunk */ + size_t capacity; + + /* Pointer to the previous chunk or %NULL if this is the sentinel + * chunk in the pool header. */ + struct _pool_chunk *prev_chunk; + + /* Actual data starts here. Well aligned for pointers. */ +}; + +/* A memory pool. This is supposed to be embedded on the stack or + * within some other structure. It may optionally be followed by an + * embedded array from which requests are fulfilled until + * malloc needs to be called to allocate a first real chunk. */ +struct pool { + /* Chunk we're allocating from. */ + struct _pool_chunk *current; + + jmp_buf *jmp; + + /* Free list of previously allocated chunks. All have >= default + * capacity. */ + struct _pool_chunk *first_free; + + /* The default capacity of a chunk. */ + size_t default_capacity; + + /* Header for the sentinel chunk. Directly following the pool + * struct should be some space for embedded elements from which + * the sentinel chunk allocates from. */ + struct _pool_chunk sentinel[1]; +}; + +/* A polygon edge. */ +struct edge { + /* Next in y-bucket or active list. */ + struct edge *next, *prev; + + /* Number of subsample rows remaining to scan convert of this + * edge. */ + grid_scaled_y_t height_left; + + /* Original sign of the edge: +1 for downwards, -1 for upwards + * edges. */ + int dir; + int vertical; + + /* Current x coordinate while the edge is on the active + * list. Initialised to the x coordinate of the top of the + * edge. The quotient is in grid_scaled_x_t units and the + * remainder is mod dy in grid_scaled_y_t units.*/ + struct quorem x; + + /* Advance of the current x when moving down a subsample line. */ + struct quorem dxdy; + + /* The clipped y of the top of the edge. */ + grid_scaled_y_t ytop; + + /* y2-y1 after orienting the edge downwards. */ + grid_scaled_y_t dy; +}; + +#define EDGE_Y_BUCKET_INDEX(y, ymin) (((y) - (ymin))/GRID_Y) + +/* A collection of sorted and vertically clipped edges of the polygon. + * Edges are moved from the polygon to an active list while scan + * converting. */ +struct polygon { + /* The vertical clip extents. */ + grid_scaled_y_t ymin, ymax; + + /* Array of edges all starting in the same bucket. An edge is put + * into bucket EDGE_BUCKET_INDEX(edge->ytop, polygon->ymin) when + * it is added to the polygon. */ + struct edge **y_buckets; + struct edge *y_buckets_embedded[64]; + + struct { + struct pool base[1]; + struct edge embedded[32]; + } edge_pool; +}; + +/* A cell records the effect on pixel coverage of polygon edges + * passing through a pixel. It contains two accumulators of pixel + * coverage. + * + * Consider the effects of a polygon edge on the coverage of a pixel + * it intersects and that of the following one. The coverage of the + * following pixel is the height of the edge multiplied by the width + * of the pixel, and the coverage of the pixel itself is the area of + * the trapezoid formed by the edge and the right side of the pixel. + * + * +-----------------------+-----------------------+ + * | | | + * | | | + * |_______________________|_______________________| + * | \...................|.......................|\ + * | \..................|.......................| | + * | \.................|.......................| | + * | \....covered.....|.......................| | + * | \....area.......|.......................| } covered height + * | \..............|.......................| | + * |uncovered\.............|.......................| | + * | area \............|.......................| | + * |___________\...........|.......................|/ + * | | | + * | | | + * | | | + * +-----------------------+-----------------------+ + * + * Since the coverage of the following pixel will always be a multiple + * of the width of the pixel, we can store the height of the covered + * area instead. The coverage of the pixel itself is the total + * coverage minus the area of the uncovered area to the left of the + * edge. As it's faster to compute the uncovered area we only store + * that and subtract it from the total coverage later when forming + * spans to blit. + * + * The heights and areas are signed, with left edges of the polygon + * having positive sign and right edges having negative sign. When + * two edges intersect they swap their left/rightness so their + * contribution above and below the intersection point must be + * computed separately. */ +struct cell { + struct cell *next; + int x; + int16_t uncovered_area; + int16_t covered_height; +}; + +/* A cell list represents the scan line sparsely as cells ordered by + * ascending x. It is geared towards scanning the cells in order + * using an internal cursor. */ +struct cell_list { + /* Sentinel nodes */ + struct cell head, tail; + + /* Cursor state for iterating through the cell list. */ + struct cell *cursor, *rewind; + + /* Cells in the cell list are owned by the cell list and are + * allocated from this pool. */ + struct { + struct pool base[1]; + struct cell embedded[32]; + } cell_pool; +}; + +struct cell_pair { + struct cell *cell1; + struct cell *cell2; +}; + +/* The active list contains edges in the current scan line ordered by + * the x-coordinate of the intercept of the edge and the scan line. */ +struct active_list { + /* Leftmost edge on the current scan line. */ + struct edge head, tail; + + /* A lower bound on the height of the active edges is used to + * estimate how soon some active edge ends. We can't advance the + * scan conversion by a full pixel row if an edge ends somewhere + * within it. */ + grid_scaled_y_t min_height; + int is_vertical; +}; + +struct glitter_scan_converter { + struct polygon polygon[1]; + struct active_list active[1]; + struct cell_list coverages[1]; + + cairo_half_open_span_t *spans; + cairo_half_open_span_t spans_embedded[64]; + + /* Clip box. */ + grid_scaled_x_t xmin, xmax; + grid_scaled_y_t ymin, ymax; +}; + +/* Compute the floored division a/b. Assumes / and % perform symmetric + * division. */ +inline static struct quorem +floored_divrem(int a, int b) +{ + struct quorem qr; + qr.quo = a/b; + qr.rem = a%b; + if ((a^b)<0 && qr.rem) { + qr.quo -= 1; + qr.rem += b; + } + return qr; +} + +/* Compute the floored division (x*a)/b. Assumes / and % perform symmetric + * division. */ +static struct quorem +floored_muldivrem(int x, int a, int b) +{ + struct quorem qr; + long long xa = (long long)x*a; + qr.quo = xa/b; + qr.rem = xa%b; + if ((xa>=0) != (b>=0) && qr.rem) { + qr.quo -= 1; + qr.rem += b; + } + return qr; +} + +static struct _pool_chunk * +_pool_chunk_init( + struct _pool_chunk *p, + struct _pool_chunk *prev_chunk, + size_t capacity) +{ + p->prev_chunk = prev_chunk; + p->size = 0; + p->capacity = capacity; + return p; +} + +static struct _pool_chunk * +_pool_chunk_create(struct pool *pool, size_t size) +{ + struct _pool_chunk *p; + + p = _cairo_malloc (size + sizeof(struct _pool_chunk)); + if (unlikely (NULL == p)) + longjmp (*pool->jmp, _cairo_error (CAIRO_STATUS_NO_MEMORY)); + + return _pool_chunk_init(p, pool->current, size); +} + +static void +pool_init(struct pool *pool, + jmp_buf *jmp, + size_t default_capacity, + size_t embedded_capacity) +{ + pool->jmp = jmp; + pool->current = pool->sentinel; + pool->first_free = NULL; + pool->default_capacity = default_capacity; + _pool_chunk_init(pool->sentinel, NULL, embedded_capacity); +} + +static void +pool_fini(struct pool *pool) +{ + struct _pool_chunk *p = pool->current; + do { + while (NULL != p) { + struct _pool_chunk *prev = p->prev_chunk; + if (p != pool->sentinel) + free(p); + p = prev; + } + p = pool->first_free; + pool->first_free = NULL; + } while (NULL != p); +} + +/* Satisfy an allocation by first allocating a new large enough chunk + * and adding it to the head of the pool's chunk list. This function + * is called as a fallback if pool_alloc() couldn't do a quick + * allocation from the current chunk in the pool. */ +static void * +_pool_alloc_from_new_chunk( + struct pool *pool, + size_t size) +{ + struct _pool_chunk *chunk; + void *obj; + size_t capacity; + + /* If the allocation is smaller than the default chunk size then + * try getting a chunk off the free list. Force alloc of a new + * chunk for large requests. */ + capacity = size; + chunk = NULL; + if (size < pool->default_capacity) { + capacity = pool->default_capacity; + chunk = pool->first_free; + if (chunk) { + pool->first_free = chunk->prev_chunk; + _pool_chunk_init(chunk, pool->current, chunk->capacity); + } + } + + if (NULL == chunk) + chunk = _pool_chunk_create (pool, capacity); + pool->current = chunk; + + obj = ((unsigned char*)chunk + sizeof(*chunk) + chunk->size); + chunk->size += size; + return obj; +} + +/* Allocate size bytes from the pool. The first allocated address + * returned from a pool is aligned to sizeof(void*). Subsequent + * addresses will maintain alignment as long as multiples of void* are + * allocated. Returns the address of a new memory area or %NULL on + * allocation failures. The pool retains ownership of the returned + * memory. */ +inline static void * +pool_alloc (struct pool *pool, size_t size) +{ + struct _pool_chunk *chunk = pool->current; + + if (size <= chunk->capacity - chunk->size) { + void *obj = ((unsigned char*)chunk + sizeof(*chunk) + chunk->size); + chunk->size += size; + return obj; + } else { + return _pool_alloc_from_new_chunk(pool, size); + } +} + +/* Relinquish all pool_alloced memory back to the pool. */ +static void +pool_reset (struct pool *pool) +{ + /* Transfer all used chunks to the chunk free list. */ + struct _pool_chunk *chunk = pool->current; + if (chunk != pool->sentinel) { + while (chunk->prev_chunk != pool->sentinel) { + chunk = chunk->prev_chunk; + } + chunk->prev_chunk = pool->first_free; + pool->first_free = pool->current; + } + /* Reset the sentinel as the current chunk. */ + pool->current = pool->sentinel; + pool->sentinel->size = 0; +} + +/* Rewinds the cell list's cursor to the beginning. After rewinding + * we're good to cell_list_find() the cell any x coordinate. */ +inline static void +cell_list_rewind (struct cell_list *cells) +{ + cells->cursor = &cells->head; +} + +inline static void +cell_list_set_rewind (struct cell_list *cells) +{ + cells->rewind = cells->cursor; +} + +static void +cell_list_init(struct cell_list *cells, jmp_buf *jmp) +{ + pool_init(cells->cell_pool.base, jmp, + 256*sizeof(struct cell), + sizeof(cells->cell_pool.embedded)); + cells->tail.next = NULL; + cells->tail.x = INT_MAX; + cells->head.x = INT_MIN; + cells->head.next = &cells->tail; + cell_list_rewind (cells); +} + +static void +cell_list_fini(struct cell_list *cells) +{ + pool_fini (cells->cell_pool.base); +} + +/* Empty the cell list. This is called at the start of every pixel + * row. */ +inline static void +cell_list_reset (struct cell_list *cells) +{ + cell_list_rewind (cells); + cells->head.next = &cells->tail; + pool_reset (cells->cell_pool.base); +} + +inline static struct cell * +cell_list_alloc (struct cell_list *cells, + struct cell *tail, + int x) +{ + struct cell *cell; + + cell = pool_alloc (cells->cell_pool.base, sizeof (struct cell)); + cell->next = tail->next; + tail->next = cell; + cell->x = x; + *(uint32_t *)&cell->uncovered_area = 0; + + return cell; +} + +/* Find a cell at the given x-coordinate. Returns %NULL if a new cell + * needed to be allocated but couldn't be. Cells must be found with + * non-decreasing x-coordinate until the cell list is rewound using + * cell_list_rewind(). Ownership of the returned cell is retained by + * the cell list. */ +inline static struct cell * +cell_list_find (struct cell_list *cells, int x) +{ + struct cell *tail = cells->cursor; + + if (tail->x == x) + return tail; + + while (1) { + UNROLL3({ + if (tail->next->x > x) + break; + tail = tail->next; + }); + } + + if (tail->x != x) + tail = cell_list_alloc (cells, tail, x); + return cells->cursor = tail; + +} + +/* Find two cells at x1 and x2. This is exactly equivalent + * to + * + * pair.cell1 = cell_list_find(cells, x1); + * pair.cell2 = cell_list_find(cells, x2); + * + * except with less function call overhead. */ +inline static struct cell_pair +cell_list_find_pair(struct cell_list *cells, int x1, int x2) +{ + struct cell_pair pair; + + pair.cell1 = cells->cursor; + while (1) { + UNROLL3({ + if (pair.cell1->next->x > x1) + break; + pair.cell1 = pair.cell1->next; + }); + } + if (pair.cell1->x != x1) + pair.cell1 = cell_list_alloc (cells, pair.cell1, x1); + + pair.cell2 = pair.cell1; + while (1) { + UNROLL3({ + if (pair.cell2->next->x > x2) + break; + pair.cell2 = pair.cell2->next; + }); + } + if (pair.cell2->x != x2) + pair.cell2 = cell_list_alloc (cells, pair.cell2, x2); + + cells->cursor = pair.cell2; + return pair; +} + +/* Add a subpixel span covering [x1, x2) to the coverage cells. */ +inline static void +cell_list_add_subspan(struct cell_list *cells, + grid_scaled_x_t x1, + grid_scaled_x_t x2) +{ + int ix1, fx1; + int ix2, fx2; + + if (x1 == x2) + return; + + GRID_X_TO_INT_FRAC(x1, ix1, fx1); + GRID_X_TO_INT_FRAC(x2, ix2, fx2); + + if (ix1 != ix2) { + struct cell_pair p; + p = cell_list_find_pair(cells, ix1, ix2); + p.cell1->uncovered_area += 2*fx1; + ++p.cell1->covered_height; + p.cell2->uncovered_area -= 2*fx2; + --p.cell2->covered_height; + } else { + struct cell *cell = cell_list_find(cells, ix1); + cell->uncovered_area += 2*(fx1-fx2); + } +} + +/* Adds the analytical coverage of an edge crossing the current pixel + * row to the coverage cells and advances the edge's x position to the + * following row. + * + * This function is only called when we know that during this pixel row: + * + * 1) The relative order of all edges on the active list doesn't + * change. In particular, no edges intersect within this row to pixel + * precision. + * + * 2) No new edges start in this row. + * + * 3) No existing edges end mid-row. + * + * This function depends on being called with all edges from the + * active list in the order they appear on the list (i.e. with + * non-decreasing x-coordinate.) */ +static void +cell_list_render_edge(struct cell_list *cells, + struct edge *edge, + int sign) +{ + grid_scaled_x_t fx; + struct cell *cell; + int ix; + + GRID_X_TO_INT_FRAC(edge->x.quo, ix, fx); + + /* We always know that ix1 is >= the cell list cursor in this + * case due to the no-intersections precondition. */ + cell = cell_list_find(cells, ix); + cell->covered_height += sign*GRID_Y; + cell->uncovered_area += sign*2*fx*GRID_Y; +} + +static void +polygon_init (struct polygon *polygon, jmp_buf *jmp) +{ + polygon->ymin = polygon->ymax = 0; + polygon->y_buckets = polygon->y_buckets_embedded; + pool_init (polygon->edge_pool.base, jmp, + 8192 - sizeof (struct _pool_chunk), + sizeof (polygon->edge_pool.embedded)); +} + +static void +polygon_fini (struct polygon *polygon) +{ + if (polygon->y_buckets != polygon->y_buckets_embedded) + free (polygon->y_buckets); + + pool_fini (polygon->edge_pool.base); +} + +/* Empties the polygon of all edges. The polygon is then prepared to + * receive new edges and clip them to the vertical range + * [ymin,ymax). */ +static glitter_status_t +polygon_reset (struct polygon *polygon, + grid_scaled_y_t ymin, + grid_scaled_y_t ymax) +{ + unsigned h = ymax - ymin; + unsigned num_buckets = EDGE_Y_BUCKET_INDEX(ymax + GRID_Y-1, ymin); + + pool_reset(polygon->edge_pool.base); + + if (unlikely (h > 0x7FFFFFFFU - GRID_Y)) + goto bail_no_mem; /* even if you could, you wouldn't want to. */ + + if (polygon->y_buckets != polygon->y_buckets_embedded) + free (polygon->y_buckets); + + polygon->y_buckets = polygon->y_buckets_embedded; + if (num_buckets > ARRAY_LENGTH (polygon->y_buckets_embedded)) { + polygon->y_buckets = _cairo_malloc_ab (num_buckets, + sizeof (struct edge *)); + if (unlikely (NULL == polygon->y_buckets)) + goto bail_no_mem; + } + memset (polygon->y_buckets, 0, num_buckets * sizeof (struct edge *)); + + polygon->ymin = ymin; + polygon->ymax = ymax; + return GLITTER_STATUS_SUCCESS; + +bail_no_mem: + polygon->ymin = 0; + polygon->ymax = 0; + return GLITTER_STATUS_NO_MEMORY; +} + +static void +_polygon_insert_edge_into_its_y_bucket(struct polygon *polygon, + struct edge *e) +{ + unsigned ix = EDGE_Y_BUCKET_INDEX(e->ytop, polygon->ymin); + struct edge **ptail = &polygon->y_buckets[ix]; + e->next = *ptail; + *ptail = e; +} + +inline static void +polygon_add_edge (struct polygon *polygon, + const cairo_edge_t *edge) +{ + struct edge *e; + grid_scaled_x_t dx; + grid_scaled_y_t dy; + grid_scaled_y_t ytop, ybot; + grid_scaled_y_t ymin = polygon->ymin; + grid_scaled_y_t ymax = polygon->ymax; + + if (unlikely (edge->top >= ymax || edge->bottom <= ymin)) + return; + + e = pool_alloc (polygon->edge_pool.base, sizeof (struct edge)); + + dx = edge->line.p2.x - edge->line.p1.x; + dy = edge->line.p2.y - edge->line.p1.y; + e->dy = dy; + e->dir = edge->dir; + + ytop = edge->top >= ymin ? edge->top : ymin; + ybot = edge->bottom <= ymax ? edge->bottom : ymax; + e->ytop = ytop; + e->height_left = ybot - ytop; + + if (dx == 0) { + e->vertical = TRUE; + e->x.quo = edge->line.p1.x; + e->x.rem = 0; + e->dxdy.quo = 0; + e->dxdy.rem = 0; + } else { + e->vertical = FALSE; + e->dxdy = floored_divrem (dx, dy); + if (ytop == edge->line.p1.y) { + e->x.quo = edge->line.p1.x; + e->x.rem = 0; + } else { + e->x = floored_muldivrem (ytop - edge->line.p1.y, dx, dy); + e->x.quo += edge->line.p1.x; + } + } + + _polygon_insert_edge_into_its_y_bucket (polygon, e); + + e->x.rem -= dy; /* Bias the remainder for faster + * edge advancement. */ +} + +static void +active_list_reset (struct active_list *active) +{ + active->head.vertical = 1; + active->head.height_left = INT_MAX; + active->head.x.quo = INT_MIN; + active->head.prev = NULL; + active->head.next = &active->tail; + active->tail.prev = &active->head; + active->tail.next = NULL; + active->tail.x.quo = INT_MAX; + active->tail.height_left = INT_MAX; + active->tail.vertical = 1; + active->min_height = 0; + active->is_vertical = 1; +} + +static void +active_list_init(struct active_list *active) +{ + active_list_reset(active); +} + +/* + * Merge two sorted edge lists. + * Input: + * - head_a: The head of the first list. + * - head_b: The head of the second list; head_b cannot be NULL. + * Output: + * Returns the head of the merged list. + * + * Implementation notes: + * To make it fast (in particular, to reduce to an insertion sort whenever + * one of the two input lists only has a single element) we iterate through + * a list until its head becomes greater than the head of the other list, + * then we switch their roles. As soon as one of the two lists is empty, we + * just attach the other one to the current list and exit. + * Writes to memory are only needed to "switch" lists (as it also requires + * attaching to the output list the list which we will be iterating next) and + * to attach the last non-empty list. + */ +static struct edge * +merge_sorted_edges (struct edge *head_a, struct edge *head_b) +{ + struct edge *head, **next, *prev; + int32_t x; + + prev = head_a->prev; + next = &head; + if (head_a->x.quo <= head_b->x.quo) { + head = head_a; + } else { + head = head_b; + head_b->prev = prev; + goto start_with_b; + } + + do { + x = head_b->x.quo; + while (head_a != NULL && head_a->x.quo <= x) { + prev = head_a; + next = &head_a->next; + head_a = head_a->next; + } + + head_b->prev = prev; + *next = head_b; + if (head_a == NULL) + return head; + +start_with_b: + x = head_a->x.quo; + while (head_b != NULL && head_b->x.quo <= x) { + prev = head_b; + next = &head_b->next; + head_b = head_b->next; + } + + head_a->prev = prev; + *next = head_a; + if (head_b == NULL) + return head; + } while (1); +} + +/* + * Sort (part of) a list. + * Input: + * - list: The list to be sorted; list cannot be NULL. + * - limit: Recursion limit. + * Output: + * - head_out: The head of the sorted list containing the first 2^(level+1) elements of the + * input list; if the input list has fewer elements, head_out be a sorted list + * containing all the elements of the input list. + * Returns the head of the list of unprocessed elements (NULL if the sorted list contains + * all the elements of the input list). + * + * Implementation notes: + * Special case single element list, unroll/inline the sorting of the first two elements. + * Some tail recursion is used since we iterate on the bottom-up solution of the problem + * (we start with a small sorted list and keep merging other lists of the same size to it). + */ +static struct edge * +sort_edges (struct edge *list, + unsigned int level, + struct edge **head_out) +{ + struct edge *head_other, *remaining; + unsigned int i; + + head_other = list->next; + + if (head_other == NULL) { + *head_out = list; + return NULL; + } + + remaining = head_other->next; + if (list->x.quo <= head_other->x.quo) { + *head_out = list; + head_other->next = NULL; + } else { + *head_out = head_other; + head_other->prev = list->prev; + head_other->next = list; + list->prev = head_other; + list->next = NULL; + } + + for (i = 0; i < level && remaining; i++) { + remaining = sort_edges (remaining, i, &head_other); + *head_out = merge_sorted_edges (*head_out, head_other); + } + + return remaining; +} + +static struct edge * +merge_unsorted_edges (struct edge *head, struct edge *unsorted) +{ + sort_edges (unsorted, UINT_MAX, &unsorted); + return merge_sorted_edges (head, unsorted); +} + +/* Test if the edges on the active list can be safely advanced by a + * full row without intersections or any edges ending. */ +inline static int +can_do_full_row (struct active_list *active) +{ + const struct edge *e; + + /* Recomputes the minimum height of all edges on the active + * list if we have been dropping edges. */ + if (active->min_height <= 0) { + int min_height = INT_MAX; + int is_vertical = 1; + + e = active->head.next; + while (NULL != e) { + if (e->height_left < min_height) + min_height = e->height_left; + is_vertical &= e->vertical; + e = e->next; + } + + active->is_vertical = is_vertical; + active->min_height = min_height; + } + + if (active->min_height < GRID_Y) + return 0; + + return active->is_vertical; +} + +/* Merges edges on the given subpixel row from the polygon to the + * active_list. */ +inline static void +active_list_merge_edges_from_bucket(struct active_list *active, + struct edge *edges) +{ + active->head.next = merge_unsorted_edges (active->head.next, edges); +} + +inline static void +polygon_fill_buckets (struct active_list *active, + struct edge *edge, + int y, + struct edge **buckets) +{ + grid_scaled_y_t min_height = active->min_height; + int is_vertical = active->is_vertical; + + while (edge) { + struct edge *next = edge->next; + int suby = edge->ytop - y; + if (buckets[suby]) + buckets[suby]->prev = edge; + edge->next = buckets[suby]; + edge->prev = NULL; + buckets[suby] = edge; + if (edge->height_left < min_height) + min_height = edge->height_left; + is_vertical &= edge->vertical; + edge = next; + } + + active->is_vertical = is_vertical; + active->min_height = min_height; +} + +inline static void +sub_row (struct active_list *active, + struct cell_list *coverages, + unsigned int mask) +{ + struct edge *edge = active->head.next; + int xstart = INT_MIN, prev_x = INT_MIN; + int winding = 0; + + cell_list_rewind (coverages); + + while (&active->tail != edge) { + struct edge *next = edge->next; + int xend = edge->x.quo; + + if (--edge->height_left) { + edge->x.quo += edge->dxdy.quo; + edge->x.rem += edge->dxdy.rem; + if (edge->x.rem >= 0) { + ++edge->x.quo; + edge->x.rem -= edge->dy; + } + + if (edge->x.quo < prev_x) { + struct edge *pos = edge->prev; + pos->next = next; + next->prev = pos; + do { + pos = pos->prev; + } while (edge->x.quo < pos->x.quo); + pos->next->prev = edge; + edge->next = pos->next; + edge->prev = pos; + pos->next = edge; + } else + prev_x = edge->x.quo; + } else { + edge->prev->next = next; + next->prev = edge->prev; + } + + winding += edge->dir; + if ((winding & mask) == 0) { + if (next->x.quo != xend) { + cell_list_add_subspan (coverages, xstart, xend); + xstart = INT_MIN; + } + } else if (xstart == INT_MIN) + xstart = xend; + + edge = next; + } +} + +inline static void dec (struct edge *e, int h) +{ + e->height_left -= h; + if (e->height_left == 0) { + e->prev->next = e->next; + e->next->prev = e->prev; + } +} + +static void +full_row (struct active_list *active, + struct cell_list *coverages, + unsigned int mask) +{ + struct edge *left = active->head.next; + + while (&active->tail != left) { + struct edge *right; + int winding; + + dec (left, GRID_Y); + + winding = left->dir; + right = left->next; + do { + dec (right, GRID_Y); + + winding += right->dir; + if ((winding & mask) == 0 && right->next->x.quo != right->x.quo) + break; + + right = right->next; + } while (1); + + cell_list_set_rewind (coverages); + cell_list_render_edge (coverages, left, +1); + cell_list_render_edge (coverages, right, -1); + + left = right->next; + } +} + +static void +_glitter_scan_converter_init(glitter_scan_converter_t *converter, jmp_buf *jmp) +{ + polygon_init(converter->polygon, jmp); + active_list_init(converter->active); + cell_list_init(converter->coverages, jmp); + converter->xmin=0; + converter->ymin=0; + converter->xmax=0; + converter->ymax=0; +} + +static void +_glitter_scan_converter_fini(glitter_scan_converter_t *self) +{ + if (self->spans != self->spans_embedded) + free (self->spans); + + polygon_fini(self->polygon); + cell_list_fini(self->coverages); + + self->xmin=0; + self->ymin=0; + self->xmax=0; + self->ymax=0; +} + +static grid_scaled_t +int_to_grid_scaled(int i, int scale) +{ + /* Clamp to max/min representable scaled number. */ + if (i >= 0) { + if (i >= INT_MAX/scale) + i = INT_MAX/scale; + } + else { + if (i <= INT_MIN/scale) + i = INT_MIN/scale; + } + return i*scale; +} + +#define int_to_grid_scaled_x(x) int_to_grid_scaled((x), GRID_X) +#define int_to_grid_scaled_y(x) int_to_grid_scaled((x), GRID_Y) + +I glitter_status_t +glitter_scan_converter_reset( + glitter_scan_converter_t *converter, + int xmin, int ymin, + int xmax, int ymax) +{ + glitter_status_t status; + int max_num_spans; + + converter->xmin = 0; converter->xmax = 0; + converter->ymin = 0; converter->ymax = 0; + + max_num_spans = xmax - xmin + 1; + + if (max_num_spans > ARRAY_LENGTH(converter->spans_embedded)) { + converter->spans = _cairo_malloc_ab (max_num_spans, + sizeof (cairo_half_open_span_t)); + if (unlikely (converter->spans == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } else + converter->spans = converter->spans_embedded; + + xmin = int_to_grid_scaled_x(xmin); + ymin = int_to_grid_scaled_y(ymin); + xmax = int_to_grid_scaled_x(xmax); + ymax = int_to_grid_scaled_y(ymax); + + active_list_reset(converter->active); + cell_list_reset(converter->coverages); + status = polygon_reset(converter->polygon, ymin, ymax); + if (status) + return status; + + converter->xmin = xmin; + converter->xmax = xmax; + converter->ymin = ymin; + converter->ymax = ymax; + return GLITTER_STATUS_SUCCESS; +} + +/* INPUT_TO_GRID_X/Y (in_coord, out_grid_scaled, grid_scale) + * These macros convert an input coordinate in the client's + * device space to the rasterisation grid. + */ +/* Gah.. this bit of ugly defines INPUT_TO_GRID_X/Y so as to use + * shifts if possible, and something saneish if not. + */ +#if !defined(INPUT_TO_GRID_Y) && defined(GRID_Y_BITS) && GRID_Y_BITS <= GLITTER_INPUT_BITS +# define INPUT_TO_GRID_Y(in, out) (out) = (in) >> (GLITTER_INPUT_BITS - GRID_Y_BITS) +#else +# define INPUT_TO_GRID_Y(in, out) INPUT_TO_GRID_general(in, out, GRID_Y) +#endif + +#if !defined(INPUT_TO_GRID_X) && defined(GRID_X_BITS) && GRID_X_BITS <= GLITTER_INPUT_BITS +# define INPUT_TO_GRID_X(in, out) (out) = (in) >> (GLITTER_INPUT_BITS - GRID_X_BITS) +#else +# define INPUT_TO_GRID_X(in, out) INPUT_TO_GRID_general(in, out, GRID_X) +#endif + +#define INPUT_TO_GRID_general(in, out, grid_scale) do { \ + long long tmp__ = (long long)(grid_scale) * (in); \ + tmp__ >>= GLITTER_INPUT_BITS; \ + (out) = tmp__; \ +} while (0) + +/* Add a new polygon edge from pixel (x1,y1) to (x2,y2) to the scan + * converter. The coordinates represent pixel positions scaled by + * 2**GLITTER_PIXEL_BITS. If this function fails then the scan + * converter should be reset or destroyed. Dir must be +1 or -1, + * with the latter reversing the orientation of the edge. */ +I void +glitter_scan_converter_add_edge (glitter_scan_converter_t *converter, + const cairo_edge_t *edge) +{ + cairo_edge_t e; + + INPUT_TO_GRID_Y (edge->top, e.top); + INPUT_TO_GRID_Y (edge->bottom, e.bottom); + if (e.top >= e.bottom) + return; + + /* XXX: possible overflows if GRID_X/Y > 2**GLITTER_INPUT_BITS */ + INPUT_TO_GRID_Y (edge->line.p1.y, e.line.p1.y); + INPUT_TO_GRID_Y (edge->line.p2.y, e.line.p2.y); + if (e.line.p1.y == e.line.p2.y) + e.line.p2.y++; /* Fudge to prevent div-by-zero */ + + INPUT_TO_GRID_X (edge->line.p1.x, e.line.p1.x); + INPUT_TO_GRID_X (edge->line.p2.x, e.line.p2.x); + + e.dir = edge->dir; + + polygon_add_edge (converter->polygon, &e); +} + +static void +step_edges (struct active_list *active, int count) +{ + struct edge *edge; + + count *= GRID_Y; + for (edge = active->head.next; edge != &active->tail; edge = edge->next) { + edge->height_left -= count; + if (! edge->height_left) { + edge->prev->next = edge->next; + edge->next->prev = edge->prev; + } + } +} + +static glitter_status_t +blit_a8 (struct cell_list *cells, + cairo_span_renderer_t *renderer, + cairo_half_open_span_t *spans, + int y, int height, + int xmin, int xmax) +{ + struct cell *cell = cells->head.next; + int prev_x = xmin, last_x = -1; + int16_t cover = 0, last_cover = 0; + unsigned num_spans; + + if (cell == &cells->tail) + return CAIRO_STATUS_SUCCESS; + + /* Skip cells to the left of the clip region. */ + while (cell->x < xmin) { + cover += cell->covered_height; + cell = cell->next; + } + cover *= GRID_X*2; + + /* Form the spans from the coverages and areas. */ + num_spans = 0; + for (; cell->x < xmax; cell = cell->next) { + int x = cell->x; + int16_t area; + + if (x > prev_x && cover != last_cover) { + spans[num_spans].x = prev_x; + spans[num_spans].coverage = GRID_AREA_TO_ALPHA (cover); + last_cover = cover; + last_x = prev_x; + ++num_spans; + } + + cover += cell->covered_height*GRID_X*2; + area = cover - cell->uncovered_area; + + if (area != last_cover) { + spans[num_spans].x = x; + spans[num_spans].coverage = GRID_AREA_TO_ALPHA (area); + last_cover = area; + last_x = x; + ++num_spans; + } + + prev_x = x+1; + } + + if (prev_x <= xmax && cover != last_cover) { + spans[num_spans].x = prev_x; + spans[num_spans].coverage = GRID_AREA_TO_ALPHA (cover); + last_cover = cover; + last_x = prev_x; + ++num_spans; + } + + if (last_x < xmax && last_cover) { + spans[num_spans].x = xmax; + spans[num_spans].coverage = 0; + ++num_spans; + } + + /* Dump them into the renderer. */ + return renderer->render_rows (renderer, y, height, spans, num_spans); +} + +#define GRID_AREA_TO_A1(A) ((GRID_AREA_TO_ALPHA (A) > 127) ? 255 : 0) +static glitter_status_t +blit_a1 (struct cell_list *cells, + cairo_span_renderer_t *renderer, + cairo_half_open_span_t *spans, + int y, int height, + int xmin, int xmax) +{ + struct cell *cell = cells->head.next; + int prev_x = xmin, last_x = -1; + int16_t cover = 0; + uint8_t coverage, last_cover = 0; + unsigned num_spans; + + if (cell == &cells->tail) + return CAIRO_STATUS_SUCCESS; + + /* Skip cells to the left of the clip region. */ + while (cell->x < xmin) { + cover += cell->covered_height; + cell = cell->next; + } + cover *= GRID_X*2; + + /* Form the spans from the coverages and areas. */ + num_spans = 0; + for (; cell->x < xmax; cell = cell->next) { + int x = cell->x; + int16_t area; + + coverage = GRID_AREA_TO_A1 (cover); + if (x > prev_x && coverage != last_cover) { + last_x = spans[num_spans].x = prev_x; + last_cover = spans[num_spans].coverage = coverage; + ++num_spans; + } + + cover += cell->covered_height*GRID_X*2; + area = cover - cell->uncovered_area; + + coverage = GRID_AREA_TO_A1 (area); + if (coverage != last_cover) { + last_x = spans[num_spans].x = x; + last_cover = spans[num_spans].coverage = coverage; + ++num_spans; + } + + prev_x = x+1; + } + + coverage = GRID_AREA_TO_A1 (cover); + if (prev_x <= xmax && coverage != last_cover) { + last_x = spans[num_spans].x = prev_x; + last_cover = spans[num_spans].coverage = coverage; + ++num_spans; + } + + if (last_x < xmax && last_cover) { + spans[num_spans].x = xmax; + spans[num_spans].coverage = 0; + ++num_spans; + } + if (num_spans == 1) + return CAIRO_STATUS_SUCCESS; + + /* Dump them into the renderer. */ + return renderer->render_rows (renderer, y, height, spans, num_spans); +} + + +I void +glitter_scan_converter_render(glitter_scan_converter_t *converter, + unsigned int winding_mask, + int antialias, + cairo_span_renderer_t *renderer) +{ + int i, j; + int ymax_i = converter->ymax / GRID_Y; + int ymin_i = converter->ymin / GRID_Y; + int xmin_i, xmax_i; + int h = ymax_i - ymin_i; + struct polygon *polygon = converter->polygon; + struct cell_list *coverages = converter->coverages; + struct active_list *active = converter->active; + struct edge *buckets[GRID_Y] = { 0 }; + + xmin_i = converter->xmin / GRID_X; + xmax_i = converter->xmax / GRID_X; + if (xmin_i >= xmax_i) + return; + + /* Render each pixel row. */ + for (i = 0; i < h; i = j) { + int do_full_row = 0; + + j = i + 1; + + /* Determine if we can ignore this row or use the full pixel + * stepper. */ + if (! polygon->y_buckets[i]) { + if (active->head.next == &active->tail) { + active->min_height = INT_MAX; + active->is_vertical = 1; + for (; j < h && ! polygon->y_buckets[j]; j++) + ; + continue; + } + + do_full_row = can_do_full_row (active); + } + + if (do_full_row) { + /* Step by a full pixel row's worth. */ + full_row (active, coverages, winding_mask); + + if (active->is_vertical) { + while (j < h && + polygon->y_buckets[j] == NULL && + active->min_height >= 2*GRID_Y) + { + active->min_height -= GRID_Y; + j++; + } + if (j != i + 1) + step_edges (active, j - (i + 1)); + } + } else { + int sub; + + polygon_fill_buckets (active, + polygon->y_buckets[i], + (i+ymin_i)*GRID_Y, + buckets); + + /* Subsample this row. */ + for (sub = 0; sub < GRID_Y; sub++) { + if (buckets[sub]) { + active_list_merge_edges_from_bucket (active, buckets[sub]); + buckets[sub] = NULL; + } + + sub_row (active, coverages, winding_mask); + } + } + + if (antialias) + blit_a8 (coverages, renderer, converter->spans, + i+ymin_i, j-i, xmin_i, xmax_i); + else + blit_a1 (coverages, renderer, converter->spans, + i+ymin_i, j-i, xmin_i, xmax_i); + cell_list_reset (coverages); + + active->min_height -= GRID_Y; + } +} + +struct _cairo_tor22_scan_converter { + cairo_scan_converter_t base; + + glitter_scan_converter_t converter[1]; + cairo_fill_rule_t fill_rule; + cairo_antialias_t antialias; + + jmp_buf jmp; +}; + +typedef struct _cairo_tor22_scan_converter cairo_tor22_scan_converter_t; + +static void +_cairo_tor22_scan_converter_destroy (void *converter) +{ + cairo_tor22_scan_converter_t *self = converter; + if (self == NULL) { + return; + } + _glitter_scan_converter_fini (self->converter); + free(self); +} + +cairo_status_t +_cairo_tor22_scan_converter_add_polygon (void *converter, + const cairo_polygon_t *polygon) +{ + cairo_tor22_scan_converter_t *self = converter; + int i; + +#if 0 + FILE *file = fopen ("polygon.txt", "w"); + _cairo_debug_print_polygon (file, polygon); + fclose (file); +#endif + + for (i = 0; i < polygon->num_edges; i++) + glitter_scan_converter_add_edge (self->converter, &polygon->edges[i]); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_tor22_scan_converter_generate (void *converter, + cairo_span_renderer_t *renderer) +{ + cairo_tor22_scan_converter_t *self = converter; + cairo_status_t status; + + if ((status = setjmp (self->jmp))) + return _cairo_scan_converter_set_error (self, _cairo_error (status)); + + glitter_scan_converter_render (self->converter, + self->fill_rule == CAIRO_FILL_RULE_WINDING ? ~0 : 1, + self->antialias != CAIRO_ANTIALIAS_NONE, + renderer); + return CAIRO_STATUS_SUCCESS; +} + +cairo_scan_converter_t * +_cairo_tor22_scan_converter_create (int xmin, + int ymin, + int xmax, + int ymax, + cairo_fill_rule_t fill_rule, + cairo_antialias_t antialias) +{ + cairo_tor22_scan_converter_t *self; + cairo_status_t status; + + self = _cairo_calloc (sizeof(struct _cairo_tor22_scan_converter)); + if (unlikely (self == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto bail_nomem; + } + + self->base.destroy = _cairo_tor22_scan_converter_destroy; + self->base.generate = _cairo_tor22_scan_converter_generate; + + _glitter_scan_converter_init (self->converter, &self->jmp); + status = glitter_scan_converter_reset (self->converter, + xmin, ymin, xmax, ymax); + if (unlikely (status)) + goto bail; + + self->fill_rule = fill_rule; + self->antialias = antialias; + + return &self->base; + + bail: + self->base.destroy(&self->base); + bail_nomem: + return _cairo_scan_converter_create_in_error (status); +} diff --git a/local/recipes/libs/cairo/source/src/cairo-toy-font-face.c b/local/recipes/libs/cairo/source/src/cairo-toy-font-face.c new file mode 100644 index 0000000000..211723c412 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-toy-font-face.c @@ -0,0 +1,521 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005,2008 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Graydon Hoare + * Owen Taylor + * Behdad Esfahbod + */ + +#define _DEFAULT_SOURCE /* for strdup() */ +#include "cairoint.h" +#include "cairo-error-private.h" + + +static const cairo_font_face_t _cairo_font_face_null_pointer = { + { 0 }, /* hash_entry */ + CAIRO_STATUS_NULL_POINTER, /* status */ + CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ + { 0, 0, 0, NULL }, /* user_data */ + NULL +}; + +static const cairo_font_face_t _cairo_font_face_invalid_string = { + { 0 }, /* hash_entry */ + CAIRO_STATUS_INVALID_STRING, /* status */ + CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ + { 0, 0, 0, NULL }, /* user_data */ + NULL +}; + +static const cairo_font_face_t _cairo_font_face_invalid_slant = { + { 0 }, /* hash_entry */ + CAIRO_STATUS_INVALID_SLANT, /* status */ + CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ + { 0, 0, 0, NULL }, /* user_data */ + NULL +}; + +static const cairo_font_face_t _cairo_font_face_invalid_weight = { + { 0 }, /* hash_entry */ + CAIRO_STATUS_INVALID_WEIGHT, /* status */ + CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ + { 0, 0, 0, NULL }, /* user_data */ + NULL +}; + + +static const cairo_font_face_backend_t _cairo_toy_font_face_backend; + +static int +_cairo_toy_font_face_keys_equal (const void *key_a, + const void *key_b); + +/* We maintain a hash table from family/weight/slant => + * #cairo_font_face_t for #cairo_toy_font_t. The primary purpose of + * this mapping is to provide unique #cairo_font_face_t values so that + * our cache and mapping from #cairo_font_face_t => #cairo_scaled_font_t + * works. Once the corresponding #cairo_font_face_t objects fall out of + * downstream caches, we don't need them in this hash table anymore. + * + * Modifications to this hash table are protected by + * _cairo_toy_font_face_mutex. + */ +static cairo_hash_table_t *cairo_toy_font_face_hash_table = NULL; + +static cairo_hash_table_t * +_cairo_toy_font_face_hash_table_lock (void) +{ + CAIRO_MUTEX_LOCK (_cairo_toy_font_face_mutex); + + if (cairo_toy_font_face_hash_table == NULL) + { + cairo_toy_font_face_hash_table = + _cairo_hash_table_create (_cairo_toy_font_face_keys_equal); + + if (cairo_toy_font_face_hash_table == NULL) { + CAIRO_MUTEX_UNLOCK (_cairo_toy_font_face_mutex); + return NULL; + } + } + + return cairo_toy_font_face_hash_table; +} + +static void +_cairo_toy_font_face_hash_table_unlock (void) +{ + CAIRO_MUTEX_UNLOCK (_cairo_toy_font_face_mutex); +} + +/** + * _cairo_toy_font_face_init_key: + * + * Initialize those portions of #cairo_toy_font_face_t needed to use + * it as a hash table key, including the hash code buried away in + * font_face->base.hash_entry. No memory allocation is performed here + * so that no fini call is needed. We do this to make it easier to use + * an automatic #cairo_toy_font_face_t variable as a key. + **/ +static void +_cairo_toy_font_face_init_key (cairo_toy_font_face_t *key, + const char *family, + cairo_font_slant_t slant, + cairo_font_weight_t weight) +{ + uintptr_t hash; + + key->family = family; + key->owns_family = FALSE; + + key->slant = slant; + key->weight = weight; + + /* 1607 and 1451 are just a couple of arbitrary primes. */ + hash = _cairo_hash_string (family); + hash += ((uintptr_t) slant) * 1607; + hash += ((uintptr_t) weight) * 1451; + + key->base.hash_entry.hash = hash; +} + +static cairo_status_t +_cairo_toy_font_face_create_impl_face (cairo_toy_font_face_t *font_face, + cairo_font_face_t **impl_font_face) +{ + const cairo_font_face_backend_t * backend = CAIRO_FONT_FACE_BACKEND_DEFAULT; + cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED; + + if (unlikely (font_face->base.status)) + return font_face->base.status; + + if (backend->create_for_toy != NULL && + 0 != strncmp (font_face->family, CAIRO_USER_FONT_FAMILY_DEFAULT, + strlen (CAIRO_USER_FONT_FAMILY_DEFAULT))) + { + status = backend->create_for_toy (font_face, impl_font_face); + } + + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + backend = &_cairo_user_font_face_backend; + status = backend->create_for_toy (font_face, impl_font_face); + } + + return status; +} + +static cairo_status_t +_cairo_toy_font_face_init (cairo_toy_font_face_t *font_face, + const char *family, + cairo_font_slant_t slant, + cairo_font_weight_t weight) +{ + char *family_copy; + cairo_status_t status; + + family_copy = strdup (family); + if (unlikely (family_copy == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + _cairo_toy_font_face_init_key (font_face, family_copy, slant, weight); + font_face->owns_family = TRUE; + + _cairo_font_face_init (&font_face->base, &_cairo_toy_font_face_backend); + + status = _cairo_toy_font_face_create_impl_face (font_face, + &font_face->impl_face); + if (unlikely (status)) { + free (family_copy); + return status; + } + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_toy_font_face_fini (cairo_toy_font_face_t *font_face) +{ + /* We assert here that we own font_face->family before casting + * away the const qualifier. */ + assert (font_face->owns_family); + free ((char*) font_face->family); + + if (font_face->impl_face) + cairo_font_face_destroy (font_face->impl_face); +} + +static int +_cairo_toy_font_face_keys_equal (const void *key_a, + const void *key_b) +{ + const cairo_toy_font_face_t *face_a = key_a; + const cairo_toy_font_face_t *face_b = key_b; + + return (strcmp (face_a->family, face_b->family) == 0 && + face_a->slant == face_b->slant && + face_a->weight == face_b->weight); +} + +/** + * cairo_toy_font_face_create: + * @family: a font family name, encoded in UTF-8 + * @slant: the slant for the font + * @weight: the weight for the font + * + * Creates a font face from a triplet of family, slant, and weight. + * These font faces are used in implementation of the #cairo_t "toy" + * font API. + * + * If @family is the zero-length string "", the platform-specific default + * family is assumed. The default family then can be queried using + * cairo_toy_font_face_get_family(). + * + * The cairo_select_font_face() function uses this to create font faces. + * See that function for limitations and other details of toy font faces. + * + * Return value: a newly created #cairo_font_face_t. Free with + * cairo_font_face_destroy() when you are done using it. + * + * Since: 1.8 + **/ +cairo_font_face_t * +cairo_toy_font_face_create (const char *family, + cairo_font_slant_t slant, + cairo_font_weight_t weight) +{ + cairo_status_t status; + cairo_toy_font_face_t key, *font_face; + cairo_hash_table_t *hash_table; + + if (family == NULL) + return (cairo_font_face_t*) &_cairo_font_face_null_pointer; + + /* Make sure we've got valid UTF-8 for the family */ + status = _cairo_utf8_to_ucs4 (family, -1, NULL, NULL); + if (unlikely (status)) { + if (status == CAIRO_STATUS_INVALID_STRING) + return (cairo_font_face_t*) &_cairo_font_face_invalid_string; + + return (cairo_font_face_t*) &_cairo_font_face_nil; + } + + switch (slant) { + case CAIRO_FONT_SLANT_NORMAL: + case CAIRO_FONT_SLANT_ITALIC: + case CAIRO_FONT_SLANT_OBLIQUE: + break; + default: + return (cairo_font_face_t*) &_cairo_font_face_invalid_slant; + } + + switch (weight) { + case CAIRO_FONT_WEIGHT_NORMAL: + case CAIRO_FONT_WEIGHT_BOLD: + break; + default: + return (cairo_font_face_t*) &_cairo_font_face_invalid_weight; + } + + if (*family == '\0') + family = CAIRO_FONT_FAMILY_DEFAULT; + + hash_table = _cairo_toy_font_face_hash_table_lock (); + if (unlikely (hash_table == NULL)) + goto UNWIND; + + _cairo_toy_font_face_init_key (&key, family, slant, weight); + + /* Return existing font_face if it exists in the hash table. */ + font_face = _cairo_hash_table_lookup (hash_table, + &key.base.hash_entry); + if (font_face != NULL) { + if (font_face->base.status == CAIRO_STATUS_SUCCESS) { + cairo_font_face_reference (&font_face->base); + _cairo_toy_font_face_hash_table_unlock (); + return &font_face->base; + } + + /* remove the bad font from the hash table */ + _cairo_hash_table_remove (hash_table, &font_face->base.hash_entry); + } + + /* Otherwise create it and insert into hash table. */ + font_face = _cairo_calloc (sizeof (cairo_toy_font_face_t)); + if (unlikely (font_face == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto UNWIND_HASH_TABLE_LOCK; + } + + status = _cairo_toy_font_face_init (font_face, family, slant, weight); + if (unlikely (status)) + goto UNWIND_FONT_FACE_MALLOC; + + assert (font_face->base.hash_entry.hash == key.base.hash_entry.hash); + status = _cairo_hash_table_insert (hash_table, &font_face->base.hash_entry); + if (unlikely (status)) + goto UNWIND_FONT_FACE_INIT; + + _cairo_toy_font_face_hash_table_unlock (); + + return &font_face->base; + + UNWIND_FONT_FACE_INIT: + _cairo_toy_font_face_fini (font_face); + UNWIND_FONT_FACE_MALLOC: + free (font_face); + UNWIND_HASH_TABLE_LOCK: + _cairo_toy_font_face_hash_table_unlock (); + UNWIND: + return (cairo_font_face_t*) &_cairo_font_face_nil; +} + +static cairo_bool_t +_cairo_toy_font_face_destroy (void *abstract_face) +{ + cairo_toy_font_face_t *font_face = abstract_face; + cairo_hash_table_t *hash_table; + + hash_table = _cairo_toy_font_face_hash_table_lock (); + /* All created objects must have been mapped in the hash table. */ + assert (hash_table != NULL); + + if (! _cairo_reference_count_dec_and_test (&font_face->base.ref_count)) { + /* somebody recreated the font whilst we waited for the lock */ + _cairo_toy_font_face_hash_table_unlock (); + return FALSE; + } + + /* Font faces in SUCCESS status are guaranteed to be in the + * hashtable. Font faces in an error status are removed from the + * hashtable if they are found during a lookup, thus they should + * only be removed if they are in the hashtable. */ + if (likely (font_face->base.status == CAIRO_STATUS_SUCCESS) || + _cairo_hash_table_lookup (hash_table, &font_face->base.hash_entry) == font_face) + _cairo_hash_table_remove (hash_table, &font_face->base.hash_entry); + + _cairo_toy_font_face_hash_table_unlock (); + + _cairo_toy_font_face_fini (font_face); + return TRUE; +} + +static cairo_status_t +_cairo_toy_font_face_scaled_font_create (void *abstract_font_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **scaled_font) +{ + cairo_toy_font_face_t *font_face = (cairo_toy_font_face_t *) abstract_font_face; + + ASSERT_NOT_REACHED; + + return _cairo_font_face_set_error (&font_face->base, CAIRO_STATUS_FONT_TYPE_MISMATCH); +} + +static cairo_font_face_t * +_cairo_toy_font_face_get_implementation (void *abstract_font_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options) +{ + cairo_toy_font_face_t *font_face = abstract_font_face; + + if (font_face->impl_face) { + cairo_font_face_t *impl = font_face->impl_face; + + if (impl->backend->get_implementation != NULL) { + return impl->backend->get_implementation (impl, + font_matrix, + ctm, + options); + } + + return cairo_font_face_reference (impl); + } + + return abstract_font_face; +} + +static cairo_bool_t +_cairo_font_face_is_toy (cairo_font_face_t *font_face) +{ + return font_face->backend == &_cairo_toy_font_face_backend; +} + +/** + * cairo_toy_font_face_get_family: + * @font_face: A toy font face + * + * Gets the family name of a toy font. + * + * Return value: The family name. This string is owned by the font face + * and remains valid as long as the font face is alive (referenced). + * + * Since: 1.8 + **/ +const char * +cairo_toy_font_face_get_family (cairo_font_face_t *font_face) +{ + cairo_toy_font_face_t *toy_font_face; + + if (font_face->status) + return CAIRO_FONT_FAMILY_DEFAULT; + + toy_font_face = (cairo_toy_font_face_t *) font_face; + if (! _cairo_font_face_is_toy (font_face)) { + if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH)) + return CAIRO_FONT_FAMILY_DEFAULT; + } + assert (toy_font_face->owns_family); + return toy_font_face->family; +} + +/** + * cairo_toy_font_face_get_slant: + * @font_face: A toy font face + * + * Gets the slant a toy font. + * + * Return value: The slant value + * + * Since: 1.8 + **/ +cairo_font_slant_t +cairo_toy_font_face_get_slant (cairo_font_face_t *font_face) +{ + cairo_toy_font_face_t *toy_font_face; + + if (font_face->status) + return CAIRO_FONT_SLANT_DEFAULT; + + toy_font_face = (cairo_toy_font_face_t *) font_face; + if (! _cairo_font_face_is_toy (font_face)) { + if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH)) + return CAIRO_FONT_SLANT_DEFAULT; + } + return toy_font_face->slant; +} + +/** + * cairo_toy_font_face_get_weight: + * @font_face: A toy font face + * + * Gets the weight a toy font. + * + * Return value: The weight value + * + * Since: 1.8 + **/ +cairo_font_weight_t +cairo_toy_font_face_get_weight (cairo_font_face_t *font_face) +{ + cairo_toy_font_face_t *toy_font_face; + + if (font_face->status) + return CAIRO_FONT_WEIGHT_DEFAULT; + + toy_font_face = (cairo_toy_font_face_t *) font_face; + if (! _cairo_font_face_is_toy (font_face)) { + if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH)) + return CAIRO_FONT_WEIGHT_DEFAULT; + } + return toy_font_face->weight; +} + +static const cairo_font_face_backend_t _cairo_toy_font_face_backend = { + CAIRO_FONT_TYPE_TOY, + NULL, /* create_for_toy */ + _cairo_toy_font_face_destroy, + _cairo_toy_font_face_scaled_font_create, + _cairo_toy_font_face_get_implementation +}; + +void +_cairo_toy_font_face_reset_static_data (void) +{ + cairo_hash_table_t *hash_table; + + /* We manually acquire the lock rather than calling + * cairo_toy_font_face_hash_table_lock simply to avoid + * creating the table only to destroy it again. */ + CAIRO_MUTEX_LOCK (_cairo_toy_font_face_mutex); + hash_table = cairo_toy_font_face_hash_table; + cairo_toy_font_face_hash_table = NULL; + CAIRO_MUTEX_UNLOCK (_cairo_toy_font_face_mutex); + + if (hash_table != NULL) + _cairo_hash_table_destroy (hash_table); +} diff --git a/local/recipes/libs/cairo/source/src/cairo-traps-compositor.c b/local/recipes/libs/cairo/source/src/cairo-traps-compositor.c new file mode 100644 index 0000000000..3414fc2684 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-traps-compositor.c @@ -0,0 +1,2351 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Joonas Pihlaja + * Chris Wilson + */ + +#include "cairoint.h" + +#include "cairo-box-inline.h" +#include "cairo-boxes-private.h" +#include "cairo-clip-inline.h" +#include "cairo-clip-private.h" +#include "cairo-composite-rectangles-private.h" +#include "cairo-compositor-private.h" +#include "cairo-error-private.h" +#include "cairo-image-surface-private.h" +#include "cairo-pattern-inline.h" +#include "cairo-paginated-private.h" +#include "cairo-recording-surface-inline.h" +#include "cairo-surface-subsurface-private.h" +#include "cairo-surface-snapshot-inline.h" +#include "cairo-surface-observer-private.h" +#include "cairo-region-private.h" +#include "cairo-spans-private.h" +#include "cairo-traps-private.h" +#include "cairo-tristrip-private.h" + +typedef cairo_int_status_t +(*draw_func_t) (const cairo_traps_compositor_t *compositor, + cairo_surface_t *dst, + void *closure, + cairo_operator_t op, + cairo_surface_t *src, + int src_x, + int src_y, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents, + cairo_clip_t *clip); + +static void do_unaligned_row(void (*blt)(void *closure, + int16_t x, int16_t y, + int16_t w, int16_t h, + uint16_t coverage), + void *closure, + const cairo_box_t *b, + int tx, int y, int h, + uint16_t coverage) +{ + int x1 = _cairo_fixed_integer_part (b->p1.x) - tx; + int x2 = _cairo_fixed_integer_part (b->p2.x) - tx; + if (x2 > x1) { + if (! _cairo_fixed_is_integer (b->p1.x)) { + blt(closure, x1, y, 1, h, + coverage * (256 - _cairo_fixed_fractional_part (b->p1.x))); + x1++; + } + + if (x2 > x1) + blt(closure, x1, y, x2-x1, h, (coverage << 8) - (coverage >> 8)); + + if (! _cairo_fixed_is_integer (b->p2.x)) + blt(closure, x2, y, 1, h, + coverage * _cairo_fixed_fractional_part (b->p2.x)); + } else + blt(closure, x1, y, 1, h, + coverage * (b->p2.x - b->p1.x)); +} + +static void do_unaligned_box(void (*blt)(void *closure, + int16_t x, int16_t y, + int16_t w, int16_t h, + uint16_t coverage), + void *closure, + const cairo_box_t *b, int tx, int ty) +{ + int y1 = _cairo_fixed_integer_part (b->p1.y) - ty; + int y2 = _cairo_fixed_integer_part (b->p2.y) - ty; + if (y2 > y1) { + if (! _cairo_fixed_is_integer (b->p1.y)) { + do_unaligned_row(blt, closure, b, tx, y1, 1, + 256 - _cairo_fixed_fractional_part (b->p1.y)); + y1++; + } + + if (y2 > y1) + do_unaligned_row(blt, closure, b, tx, y1, y2-y1, 256); + + if (! _cairo_fixed_is_integer (b->p2.y)) + do_unaligned_row(blt, closure, b, tx, y2, 1, + _cairo_fixed_fractional_part (b->p2.y)); + } else + do_unaligned_row(blt, closure, b, tx, y1, 1, + b->p2.y - b->p1.y); +} + +struct blt_in { + const cairo_traps_compositor_t *compositor; + cairo_surface_t *dst; + cairo_boxes_t boxes; +}; + +static void blt_in(void *closure, + int16_t x, int16_t y, + int16_t w, int16_t h, + uint16_t coverage) +{ + struct blt_in *info = closure; + cairo_color_t color; + + if (CAIRO_ALPHA_SHORT_IS_OPAQUE (coverage)) + return; + + _cairo_box_from_integers (&info->boxes.chunks.base[0], x, y, w, h); + + _cairo_color_init_rgba (&color, 0, 0, 0, coverage / (double) 0xffff); + info->compositor->fill_boxes (info->dst, + CAIRO_OPERATOR_IN, &color, + &info->boxes); +} + +static void +add_rect_with_offset (cairo_boxes_t *boxes, int x1, int y1, int x2, int y2, int dx, int dy) +{ + cairo_box_t box; + cairo_int_status_t status; + + box.p1.x = _cairo_fixed_from_int (x1 - dx); + box.p1.y = _cairo_fixed_from_int (y1 - dy); + box.p2.x = _cairo_fixed_from_int (x2 - dx); + box.p2.y = _cairo_fixed_from_int (y2 - dy); + + status = _cairo_boxes_add (boxes, CAIRO_ANTIALIAS_DEFAULT, &box); + assert (status == CAIRO_INT_STATUS_SUCCESS); +} + +static cairo_int_status_t +combine_clip_as_traps (const cairo_traps_compositor_t *compositor, + cairo_surface_t *mask, + const cairo_clip_t *clip, + const cairo_rectangle_int_t *extents) +{ + cairo_polygon_t polygon; + cairo_fill_rule_t fill_rule; + cairo_antialias_t antialias; + cairo_traps_t traps; + cairo_surface_t *src; + cairo_box_t box; + cairo_rectangle_int_t fixup; + int src_x, src_y; + cairo_int_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + status = _cairo_clip_get_polygon (clip, &polygon, + &fill_rule, &antialias); + if (status) + return status; + + _cairo_traps_init (&traps); + status = _cairo_bentley_ottmann_tessellate_polygon (&traps, + &polygon, + fill_rule); + _cairo_polygon_fini (&polygon); + if (unlikely (status)) + return status; + + src = compositor->pattern_to_surface (mask, NULL, FALSE, + extents, NULL, + &src_x, &src_y); + if (unlikely (src->status)) { + _cairo_traps_fini (&traps); + return src->status; + } + + status = compositor->composite_traps (mask, CAIRO_OPERATOR_IN, src, + src_x, src_y, + extents->x, extents->y, + extents, + antialias, &traps); + + _cairo_traps_extents (&traps, &box); + _cairo_box_round_to_rectangle (&box, &fixup); + _cairo_traps_fini (&traps); + cairo_surface_destroy (src); + + if (unlikely (status)) + return status; + + if (! _cairo_rectangle_intersect (&fixup, extents)) + return CAIRO_STATUS_SUCCESS; + + if (fixup.width < extents->width || fixup.height < extents->height) { + cairo_boxes_t clear; + + _cairo_boxes_init (&clear); + + /* top */ + if (fixup.y != extents->y) { + add_rect_with_offset (&clear, + extents->x, extents->y, + extents->x + extents->width, + fixup.y, + extents->x, extents->y); + } + /* left */ + if (fixup.x != extents->x) { + add_rect_with_offset (&clear, + extents->x, fixup.y, + fixup.x, + fixup.y + fixup.height, + extents->x, extents->y); + } + /* right */ + if (fixup.x + fixup.width != extents->x + extents->width) { + add_rect_with_offset (&clear, + fixup.x + fixup.width, + fixup.y, + extents->x + extents->width, + fixup.y + fixup.height, + extents->x, extents->y); + } + /* bottom */ + if (fixup.y + fixup.height != extents->y + extents->height) { + add_rect_with_offset (&clear, + extents->x, + fixup.y + fixup.height, + extents->x + extents->width, + extents->y + extents->height, + extents->x, extents->y); + } + + status = compositor->fill_boxes (mask, + CAIRO_OPERATOR_CLEAR, + CAIRO_COLOR_TRANSPARENT, + &clear); + + _cairo_boxes_fini (&clear); + } + + return status; +} + +static cairo_status_t +__clip_to_surface (const cairo_traps_compositor_t *compositor, + const cairo_composite_rectangles_t *composite, + const cairo_rectangle_int_t *extents, + cairo_surface_t **surface) +{ + cairo_surface_t *mask; + cairo_polygon_t polygon; + cairo_fill_rule_t fill_rule; + cairo_antialias_t antialias; + cairo_traps_t traps; + cairo_boxes_t clear; + cairo_surface_t *src; + int src_x, src_y; + cairo_int_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + status = _cairo_clip_get_polygon (composite->clip, &polygon, + &fill_rule, &antialias); + if (status) + return status; + + _cairo_traps_init (&traps); + status = _cairo_bentley_ottmann_tessellate_polygon (&traps, + &polygon, + fill_rule); + _cairo_polygon_fini (&polygon); + if (unlikely (status)) + return status; + + mask = _cairo_surface_create_scratch (composite->surface, + CAIRO_CONTENT_ALPHA, + extents->width, + extents->height, + NULL); + if (unlikely (mask->status)) { + _cairo_traps_fini (&traps); + return status; + } + + src = compositor->pattern_to_surface (mask, NULL, FALSE, + extents, NULL, + &src_x, &src_y); + if (unlikely (status = src->status)) + goto error; + + status = compositor->acquire (mask); + if (unlikely (status)) + goto error; + + _cairo_boxes_init_from_rectangle (&clear, + 0, 0, + extents->width, + extents->height); + status = compositor->fill_boxes (mask, + CAIRO_OPERATOR_CLEAR, + CAIRO_COLOR_TRANSPARENT, + &clear); + if (unlikely (status)) + goto error_release; + + status = compositor->composite_traps (mask, CAIRO_OPERATOR_ADD, src, + src_x, src_y, + extents->x, extents->y, + extents, + antialias, &traps); + if (unlikely (status)) + goto error_release; + + compositor->release (mask); + *surface = mask; +out: + cairo_surface_destroy (src); + _cairo_traps_fini (&traps); + return status; + +error_release: + compositor->release (mask); +error: + cairo_surface_destroy (mask); + goto out; +} + +static cairo_surface_t * +traps_get_clip_surface (const cairo_traps_compositor_t *compositor, + const cairo_composite_rectangles_t *composite, + const cairo_rectangle_int_t *extents) +{ + cairo_surface_t *surface = NULL; + cairo_int_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + status = __clip_to_surface (compositor, composite, extents, &surface); + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + surface = _cairo_surface_create_scratch (composite->surface, + CAIRO_CONTENT_ALPHA, + extents->width, + extents->height, + CAIRO_COLOR_WHITE); + if (unlikely (surface->status)) + return surface; + + status = _cairo_clip_combine_with_surface (composite->clip, surface, + extents->x, extents->y); + } + if (unlikely (status)) { + cairo_surface_destroy (surface); + surface = _cairo_surface_create_in_error (status); + } + + return surface; +} + +static void blt_unaligned_boxes(const cairo_traps_compositor_t *compositor, + cairo_surface_t *surface, + int dx, int dy, + cairo_box_t *boxes, + int num_boxes) +{ + struct blt_in info; + int i; + + info.compositor = compositor; + info.dst = surface; + _cairo_boxes_init (&info.boxes); + info.boxes.num_boxes = 1; + for (i = 0; i < num_boxes; i++) { + cairo_box_t *b = &boxes[i]; + + if (! _cairo_fixed_is_integer (b->p1.x) || + ! _cairo_fixed_is_integer (b->p1.y) || + ! _cairo_fixed_is_integer (b->p2.x) || + ! _cairo_fixed_is_integer (b->p2.y)) + { + do_unaligned_box(blt_in, &info, b, dx, dy); + } + } +} + +static cairo_surface_t * +create_composite_mask (const cairo_traps_compositor_t *compositor, + cairo_surface_t *dst, + void *draw_closure, + draw_func_t draw_func, + draw_func_t mask_func, + const cairo_composite_rectangles_t *extents) +{ + cairo_surface_t *surface, *src; + cairo_int_status_t status; + int src_x, src_y; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + surface = _cairo_surface_create_scratch (dst, CAIRO_CONTENT_ALPHA, + extents->bounded.width, + extents->bounded.height, + NULL); + if (unlikely (surface->status)) + return surface; + + src = compositor->pattern_to_surface (surface, + &_cairo_pattern_white.base, + FALSE, + &extents->bounded, + &extents->bounded, + &src_x, &src_y); + if (unlikely (src->status)) { + cairo_surface_destroy (surface); + return src; + } + + status = compositor->acquire (surface); + if (unlikely (status)) { + cairo_surface_destroy (src); + cairo_surface_destroy (surface); + return _cairo_surface_create_in_error (status); + } + + if (!surface->is_clear) { + cairo_boxes_t clear; + + _cairo_boxes_init_from_rectangle (&clear, + 0, 0, + extents->bounded.width, + extents->bounded.height); + status = compositor->fill_boxes (surface, + CAIRO_OPERATOR_CLEAR, + CAIRO_COLOR_TRANSPARENT, + &clear); + if (unlikely (status)) + goto error; + + surface->is_clear = TRUE; + } + + if (mask_func) { + status = mask_func (compositor, surface, draw_closure, + CAIRO_OPERATOR_SOURCE, src, src_x, src_y, + extents->bounded.x, extents->bounded.y, + &extents->bounded, extents->clip); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { + surface->is_clear = FALSE; + goto out; + } + if (unlikely (status != CAIRO_INT_STATUS_UNSUPPORTED)) + goto error; + } + + /* Is it worth setting the clip region here? */ + status = draw_func (compositor, surface, draw_closure, + CAIRO_OPERATOR_ADD, src, src_x, src_y, + extents->bounded.x, extents->bounded.y, + &extents->bounded, NULL); + if (unlikely (status)) + goto error; + + surface->is_clear = FALSE; + if (extents->clip->path != NULL) { + status = combine_clip_as_traps (compositor, surface, + extents->clip, &extents->bounded); + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + status = _cairo_clip_combine_with_surface (extents->clip, surface, + extents->bounded.x, + extents->bounded.y); + } + if (unlikely (status)) + goto error; + } else if (extents->clip->boxes) { + blt_unaligned_boxes(compositor, surface, + extents->bounded.x, extents->bounded.y, + extents->clip->boxes, extents->clip->num_boxes); + + } + +out: + compositor->release (surface); + cairo_surface_destroy (src); + return surface; + +error: + compositor->release (surface); + if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) { + cairo_surface_destroy (surface); + surface = _cairo_surface_create_in_error (status); + } + cairo_surface_destroy (src); + return surface; +} + +/* Handles compositing with a clip surface when the operator allows + * us to combine the clip with the mask + */ +static cairo_status_t +clip_and_composite_with_mask (const cairo_traps_compositor_t *compositor, + const cairo_composite_rectangles_t*extents, + draw_func_t draw_func, + draw_func_t mask_func, + void *draw_closure, + cairo_operator_t op, + cairo_surface_t *src, + int src_x, int src_y) +{ + cairo_surface_t *dst = extents->surface; + cairo_surface_t *mask; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + mask = create_composite_mask (compositor, dst, draw_closure, + draw_func, mask_func, + extents); + if (unlikely (mask->status)) + return mask->status; + + if (mask->is_clear) + goto skip; + + if (src != NULL || dst->content != CAIRO_CONTENT_ALPHA) { + compositor->composite (dst, op, src, mask, + extents->bounded.x + src_x, + extents->bounded.y + src_y, + 0, 0, + extents->bounded.x, extents->bounded.y, + extents->bounded.width, extents->bounded.height); + } else { + compositor->composite (dst, op, mask, NULL, + 0, 0, + 0, 0, + extents->bounded.x, extents->bounded.y, + extents->bounded.width, extents->bounded.height); + } + +skip: + cairo_surface_destroy (mask); + return CAIRO_STATUS_SUCCESS; +} + +/* Handles compositing with a clip surface when we have to do the operation + * in two pieces and combine them together. + */ +static cairo_status_t +clip_and_composite_combine (const cairo_traps_compositor_t *compositor, + const cairo_composite_rectangles_t*extents, + draw_func_t draw_func, + void *draw_closure, + cairo_operator_t op, + cairo_surface_t *src, + int src_x, int src_y) +{ + cairo_surface_t *dst = extents->surface; + cairo_surface_t *tmp, *clip; + cairo_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + tmp = _cairo_surface_create_scratch (dst, dst->content, + extents->bounded.width, + extents->bounded.height, + NULL); + if (unlikely (tmp->status)) + return tmp->status; + + status = compositor->acquire (tmp); + if (unlikely (status)) { + cairo_surface_destroy (tmp); + return status; + } + + compositor->composite (tmp, + dst->is_clear ? CAIRO_OPERATOR_CLEAR : CAIRO_OPERATOR_SOURCE, + dst, NULL, + extents->bounded.x, extents->bounded.y, + 0, 0, + 0, 0, + extents->bounded.width, extents->bounded.height); + + status = draw_func (compositor, tmp, draw_closure, op, + src, src_x, src_y, + extents->bounded.x, extents->bounded.y, + &extents->bounded, NULL); + + if (unlikely (status)) + goto cleanup; + + clip = traps_get_clip_surface (compositor, extents, &extents->bounded); + if (unlikely ((status = clip->status))) + goto cleanup; + + if (dst->is_clear) { + compositor->composite (dst, CAIRO_OPERATOR_SOURCE, tmp, clip, + 0, 0, + 0, 0, + extents->bounded.x, extents->bounded.y, + extents->bounded.width, extents->bounded.height); + } else { + compositor->lerp (dst, tmp, clip, + 0, 0, + 0,0, + extents->bounded.x, extents->bounded.y, + extents->bounded.width, extents->bounded.height); + } + cairo_surface_destroy (clip); + +cleanup: + compositor->release (tmp); + cairo_surface_destroy (tmp); + + return status; +} + +/* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's + * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip)) + */ +static cairo_status_t +clip_and_composite_source (const cairo_traps_compositor_t *compositor, + cairo_surface_t *dst, + draw_func_t draw_func, + draw_func_t mask_func, + void *draw_closure, + cairo_surface_t *src, + int src_x, + int src_y, + const cairo_composite_rectangles_t *extents) +{ + cairo_surface_t *mask; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + /* Create a surface that is mask IN clip */ + mask = create_composite_mask (compositor, dst, draw_closure, + draw_func, mask_func, + extents); + if (unlikely (mask->status)) + return mask->status; + + if (mask->is_clear) + goto skip; + + if (dst->is_clear) { + compositor->composite (dst, CAIRO_OPERATOR_SOURCE, src, mask, + extents->bounded.x + src_x, extents->bounded.y + src_y, + 0, 0, + extents->bounded.x, extents->bounded.y, + extents->bounded.width, extents->bounded.height); + } else { + compositor->lerp (dst, src, mask, + extents->bounded.x + src_x, extents->bounded.y + src_y, + 0, 0, + extents->bounded.x, extents->bounded.y, + extents->bounded.width, extents->bounded.height); + } + +skip: + cairo_surface_destroy (mask); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_bool_t +can_reduce_alpha_op (cairo_operator_t op) +{ + int iop = op; + switch (iop) { + case CAIRO_OPERATOR_OVER: + case CAIRO_OPERATOR_SOURCE: + case CAIRO_OPERATOR_ADD: + return TRUE; + default: + return FALSE; + } +} + +static cairo_bool_t +reduce_alpha_op (cairo_composite_rectangles_t *extents) +{ + cairo_surface_t *dst = extents->surface; + cairo_operator_t op = extents->op; + const cairo_pattern_t *pattern = &extents->source_pattern.base; + return dst->is_clear && + dst->content == CAIRO_CONTENT_ALPHA && + _cairo_pattern_is_opaque_solid (pattern) && + can_reduce_alpha_op (op); +} + +static cairo_status_t +fixup_unbounded_with_mask (const cairo_traps_compositor_t *compositor, + const cairo_composite_rectangles_t *extents) +{ + cairo_surface_t *dst = extents->surface; + cairo_surface_t *mask; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + /* XXX can we avoid querying the clip surface again? */ + mask = traps_get_clip_surface (compositor, extents, &extents->unbounded); + if (unlikely (mask->status)) + return mask->status; + + /* top */ + if (extents->bounded.y != extents->unbounded.y) { + int x = extents->unbounded.x; + int y = extents->unbounded.y; + int width = extents->unbounded.width; + int height = extents->bounded.y - y; + + compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL, + 0, 0, + 0, 0, + x, y, + width, height); + } + + /* left */ + if (extents->bounded.x != extents->unbounded.x) { + int x = extents->unbounded.x; + int y = extents->bounded.y; + int width = extents->bounded.x - x; + int height = extents->bounded.height; + + compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL, + 0, y - extents->unbounded.y, + 0, 0, + x, y, + width, height); + } + + /* right */ + if (extents->bounded.x + extents->bounded.width != extents->unbounded.x + extents->unbounded.width) { + int x = extents->bounded.x + extents->bounded.width; + int y = extents->bounded.y; + int width = extents->unbounded.x + extents->unbounded.width - x; + int height = extents->bounded.height; + + compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL, + x - extents->unbounded.x, y - extents->unbounded.y, + 0, 0, + x, y, + width, height); + } + + /* bottom */ + if (extents->bounded.y + extents->bounded.height != extents->unbounded.y + extents->unbounded.height) { + int x = extents->unbounded.x; + int y = extents->bounded.y + extents->bounded.height; + int width = extents->unbounded.width; + int height = extents->unbounded.y + extents->unbounded.height - y; + + compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL, + 0, y - extents->unbounded.y, + 0, 0, + x, y, + width, height); + } + + cairo_surface_destroy (mask); + + return CAIRO_STATUS_SUCCESS; +} + +static void +add_rect (cairo_boxes_t *boxes, int x1, int y1, int x2, int y2) +{ + cairo_box_t box; + cairo_int_status_t status; + + box.p1.x = _cairo_fixed_from_int (x1); + box.p1.y = _cairo_fixed_from_int (y1); + box.p2.x = _cairo_fixed_from_int (x2); + box.p2.y = _cairo_fixed_from_int (y2); + + status = _cairo_boxes_add (boxes, CAIRO_ANTIALIAS_DEFAULT, &box); + assert (status == CAIRO_INT_STATUS_SUCCESS); +} + +static cairo_status_t +fixup_unbounded (const cairo_traps_compositor_t *compositor, + cairo_composite_rectangles_t *extents, + cairo_boxes_t *boxes) +{ + cairo_surface_t *dst = extents->surface; + cairo_boxes_t clear, tmp; + cairo_box_t box; + cairo_int_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + if (extents->bounded.width == extents->unbounded.width && + extents->bounded.height == extents->unbounded.height) + { + return CAIRO_STATUS_SUCCESS; + } + + assert (extents->clip->path == NULL); + + /* subtract the drawn boxes from the unbounded area */ + _cairo_boxes_init (&clear); + + box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width); + box.p1.y = _cairo_fixed_from_int (extents->unbounded.y); + box.p2.x = _cairo_fixed_from_int (extents->unbounded.x); + box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height); + + if (boxes == NULL) { + if (extents->bounded.width == 0 || extents->bounded.height == 0) { + goto empty; + } else { + /* top */ + if (extents->bounded.y != extents->unbounded.y) { + add_rect (&clear, + extents->unbounded.x, extents->unbounded.y, + extents->unbounded.x + extents->unbounded.width, + extents->bounded.y); + } + /* left */ + if (extents->bounded.x != extents->unbounded.x) { + add_rect (&clear, + extents->unbounded.x, extents->bounded.y, + extents->bounded.x, + extents->bounded.y + extents->bounded.height); + } + /* right */ + if (extents->bounded.x + extents->bounded.width != extents->unbounded.x + extents->unbounded.width) { + add_rect (&clear, + extents->bounded.x + extents->bounded.width, + extents->bounded.y, + extents->unbounded.x + extents->unbounded.width, + extents->bounded.y + extents->bounded.height); + } + /* bottom */ + if (extents->bounded.y + extents->bounded.height != extents->unbounded.y + extents->unbounded.height) { + add_rect (&clear, + extents->unbounded.x, + extents->bounded.y + extents->bounded.height, + extents->unbounded.x + extents->unbounded.width, + extents->unbounded.y + extents->unbounded.height); + } + } + } else if (boxes->num_boxes) { + _cairo_boxes_init (&tmp); + + assert (boxes->is_pixel_aligned); + + status = _cairo_boxes_add (&tmp, CAIRO_ANTIALIAS_DEFAULT, &box); + assert (status == CAIRO_INT_STATUS_SUCCESS); + + tmp.chunks.next = &boxes->chunks; + tmp.num_boxes += boxes->num_boxes; + + status = _cairo_bentley_ottmann_tessellate_boxes (&tmp, + CAIRO_FILL_RULE_WINDING, + &clear); + tmp.chunks.next = NULL; + if (unlikely (status)) + goto error; + } else { +empty: + box.p1.x = _cairo_fixed_from_int (extents->unbounded.x); + box.p2.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width); + + status = _cairo_boxes_add (&clear, CAIRO_ANTIALIAS_DEFAULT, &box); + assert (status == CAIRO_INT_STATUS_SUCCESS); + } + + /* Now intersect with the clip boxes */ + if (extents->clip->num_boxes) { + _cairo_boxes_init_for_array (&tmp, + extents->clip->boxes, + extents->clip->num_boxes); + status = _cairo_boxes_intersect (&clear, &tmp, &clear); + if (unlikely (status)) + goto error; + } + + status = compositor->fill_boxes (dst, + CAIRO_OPERATOR_CLEAR, + CAIRO_COLOR_TRANSPARENT, + &clear); + +error: + _cairo_boxes_fini (&clear); + return status; +} + +enum { + NEED_CLIP_REGION = 0x1, + NEED_CLIP_SURFACE = 0x2, + FORCE_CLIP_REGION = 0x4, +}; + +static cairo_bool_t +need_bounded_clip (cairo_composite_rectangles_t *extents) +{ + unsigned int flags = 0; + + if (extents->clip->num_boxes > 1 || + extents->mask.width > extents->unbounded.width || + extents->mask.height > extents->unbounded.height) + { + flags |= NEED_CLIP_REGION; + } + + if (extents->clip->num_boxes > 1 || + extents->mask.width > extents->bounded.width || + extents->mask.height > extents->bounded.height) + { + flags |= FORCE_CLIP_REGION; + } + + if (! _cairo_clip_is_region (extents->clip)) + flags |= NEED_CLIP_SURFACE; + + return flags; +} + +static cairo_bool_t +need_unbounded_clip (cairo_composite_rectangles_t *extents) +{ + unsigned int flags = 0; + if (! extents->is_bounded) { + flags |= NEED_CLIP_REGION; + if (! _cairo_clip_is_region (extents->clip)) + flags |= NEED_CLIP_SURFACE; + } + if (extents->clip->path != NULL) + flags |= NEED_CLIP_SURFACE; + return flags; +} + +static cairo_status_t +clip_and_composite (const cairo_traps_compositor_t *compositor, + cairo_composite_rectangles_t *extents, + draw_func_t draw_func, + draw_func_t mask_func, + void *draw_closure, + unsigned int need_clip) +{ + cairo_surface_t *dst = extents->surface; + cairo_operator_t op = extents->op; + cairo_pattern_t *source = &extents->source_pattern.base; + cairo_surface_t *src; + int src_x, src_y; + cairo_region_t *clip_region = NULL; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + if (reduce_alpha_op (extents)) { + op = CAIRO_OPERATOR_ADD; + source = NULL; + } + + if (op == CAIRO_OPERATOR_CLEAR) { + op = CAIRO_OPERATOR_DEST_OUT; + source = NULL; + } + + compositor->acquire (dst); + + if (need_clip & NEED_CLIP_REGION) { + const cairo_rectangle_int_t *limit; + + if ((need_clip & FORCE_CLIP_REGION) == 0) + limit = &extents->unbounded; + else + limit = &extents->destination; + + clip_region = _cairo_clip_get_region (extents->clip); + if (clip_region != NULL && + cairo_region_contains_rectangle (clip_region, + limit) == CAIRO_REGION_OVERLAP_IN) + clip_region = NULL; + + if (clip_region != NULL) { + status = compositor->set_clip_region (dst, clip_region); + if (unlikely (status)) { + compositor->release (dst); + return status; + } + } + } + + if (extents->bounded.width == 0 || extents->bounded.height == 0) + goto skip; + + src = compositor->pattern_to_surface (dst, source, FALSE, + &extents->bounded, + &extents->source_sample_area, + &src_x, &src_y); + if (unlikely (status = src->status)) + goto error; + + if (op == CAIRO_OPERATOR_SOURCE) { + status = clip_and_composite_source (compositor, dst, + draw_func, mask_func, draw_closure, + src, src_x, src_y, + extents); + } else { + if (need_clip & NEED_CLIP_SURFACE) { + if (extents->is_bounded) { + status = clip_and_composite_with_mask (compositor, extents, + draw_func, mask_func, + draw_closure, + op, src, src_x, src_y); + } else { + status = clip_and_composite_combine (compositor, extents, + draw_func, draw_closure, + op, src, src_x, src_y); + } + } else { + status = draw_func (compositor, + dst, draw_closure, + op, src, src_x, src_y, + 0, 0, + &extents->bounded, + extents->clip); + } + } + cairo_surface_destroy (src); + +skip: + if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) { + if (need_clip & NEED_CLIP_SURFACE) + status = fixup_unbounded_with_mask (compositor, extents); + else + status = fixup_unbounded (compositor, extents, NULL); + } + +error: + if (clip_region) + compositor->set_clip_region (dst, NULL); + + compositor->release (dst); + + return status; +} + +/* meta-ops */ + +typedef struct { + cairo_traps_t traps; + cairo_antialias_t antialias; +} composite_traps_info_t; + +static cairo_int_status_t +composite_traps (const cairo_traps_compositor_t *compositor, + cairo_surface_t *dst, + void *closure, + cairo_operator_t op, + cairo_surface_t *src, + int src_x, int src_y, + int dst_x, int dst_y, + const cairo_rectangle_int_t *extents, + cairo_clip_t *clip) +{ + composite_traps_info_t *info = closure; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + return compositor->composite_traps (dst, op, src, + src_x - dst_x, src_y - dst_y, + dst_x, dst_y, + extents, + info->antialias, &info->traps); +} + +typedef struct { + cairo_tristrip_t strip; + cairo_antialias_t antialias; +} composite_tristrip_info_t; + +static cairo_int_status_t +composite_tristrip (const cairo_traps_compositor_t *compositor, + cairo_surface_t *dst, + void *closure, + cairo_operator_t op, + cairo_surface_t *src, + int src_x, int src_y, + int dst_x, int dst_y, + const cairo_rectangle_int_t *extents, + cairo_clip_t *clip) +{ + composite_tristrip_info_t *info = closure; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + return compositor->composite_tristrip (dst, op, src, + src_x - dst_x, src_y - dst_y, + dst_x, dst_y, + extents, + info->antialias, &info->strip); +} + +static cairo_bool_t +is_recording_pattern (const cairo_pattern_t *pattern) +{ + cairo_surface_t *surface; + + if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE) + return FALSE; + + surface = ((const cairo_surface_pattern_t *) pattern)->surface; + surface = _cairo_surface_get_source (surface, NULL); + return _cairo_surface_is_recording (surface); +} + +static cairo_surface_t * +recording_pattern_get_surface (const cairo_pattern_t *pattern) +{ + cairo_surface_t *surface; + + surface = ((const cairo_surface_pattern_t *) pattern)->surface; + return _cairo_surface_get_source (surface, NULL); +} + +static cairo_bool_t +recording_pattern_contains_sample (const cairo_pattern_t *pattern, + const cairo_rectangle_int_t *sample) +{ + cairo_recording_surface_t *surface; + + if (! is_recording_pattern (pattern)) + return FALSE; + + if (pattern->extend == CAIRO_EXTEND_NONE) + return TRUE; + + surface = (cairo_recording_surface_t *) recording_pattern_get_surface (pattern); + if (surface->unbounded) + return TRUE; + + return _cairo_rectangle_contains_rectangle (&surface->extents, sample); +} + +static cairo_bool_t +op_reduces_to_source (cairo_composite_rectangles_t *extents) +{ + if (extents->op == CAIRO_OPERATOR_SOURCE) + return TRUE; + + if (extents->surface->is_clear) + return extents->op == CAIRO_OPERATOR_OVER || extents->op == CAIRO_OPERATOR_ADD; + + return FALSE; +} + +static cairo_status_t +composite_aligned_boxes (const cairo_traps_compositor_t *compositor, + cairo_composite_rectangles_t *extents, + cairo_boxes_t *boxes) +{ + cairo_surface_t *dst = extents->surface; + cairo_operator_t op = extents->op; + cairo_bool_t need_clip_mask = ! _cairo_clip_is_region (extents->clip); + cairo_bool_t op_is_source; + cairo_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + if (need_clip_mask && + (! extents->is_bounded || extents->op == CAIRO_OPERATOR_SOURCE)) + { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + op_is_source = op_reduces_to_source (extents); + + /* Are we just copying a recording surface? */ + if (! need_clip_mask && op_is_source && + recording_pattern_contains_sample (&extents->source_pattern.base, + &extents->source_sample_area)) + { + cairo_clip_t *recording_clip; + const cairo_pattern_t *source = &extents->source_pattern.base; + const cairo_matrix_t *m; + cairo_matrix_t matrix; + + /* XXX could also do tiling repeat modes... */ + + /* first clear the area about to be overwritten */ + if (! dst->is_clear) { + status = compositor->acquire (dst); + if (unlikely (status)) + return status; + + status = compositor->fill_boxes (dst, + CAIRO_OPERATOR_CLEAR, + CAIRO_COLOR_TRANSPARENT, + boxes); + compositor->release (dst); + if (unlikely (status)) + return status; + } + + m = &source->matrix; + if (_cairo_surface_has_device_transform (dst)) { + cairo_matrix_multiply (&matrix, + &source->matrix, + &dst->device_transform); + m = &matrix; + } + + recording_clip = _cairo_clip_from_boxes (boxes); + status = _cairo_recording_surface_replay_with_clip (recording_pattern_get_surface (source), + m, dst, recording_clip); + _cairo_clip_destroy (recording_clip); + + return status; + } + + status = compositor->acquire (dst); + if (unlikely (status)) + return status; + + if (! need_clip_mask && + (op == CAIRO_OPERATOR_CLEAR || + extents->source_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID)) + { + const cairo_color_t *color; + + if (op == CAIRO_OPERATOR_CLEAR) { + color = CAIRO_COLOR_TRANSPARENT; + } else { + color = &((cairo_solid_pattern_t *) &extents->source_pattern)->color; + if (op_is_source) + op = CAIRO_OPERATOR_SOURCE; + } + + status = compositor->fill_boxes (dst, op, color, boxes); + } + else + { + cairo_surface_t *src, *mask = NULL; + cairo_pattern_t *source = &extents->source_pattern.base; + int src_x, src_y; + int mask_x = 0, mask_y = 0; + + if (need_clip_mask) { + mask = traps_get_clip_surface (compositor, + extents, &extents->bounded); + if (unlikely (mask->status)) + return mask->status; + + mask_x = -extents->bounded.x; + mask_y = -extents->bounded.y; + + if (op == CAIRO_OPERATOR_CLEAR) { + source = NULL; + op = CAIRO_OPERATOR_DEST_OUT; + } + } else if (op_is_source) + op = CAIRO_OPERATOR_SOURCE; + + src = compositor->pattern_to_surface (dst, source, FALSE, + &extents->bounded, + &extents->source_sample_area, + &src_x, &src_y); + if (likely (src->status == CAIRO_STATUS_SUCCESS)) { + status = compositor->composite_boxes (dst, op, src, mask, + src_x, src_y, + mask_x, mask_y, + 0, 0, + boxes, &extents->bounded); + cairo_surface_destroy (src); + } else + status = src->status; + + cairo_surface_destroy (mask); + } + + if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) + status = fixup_unbounded (compositor, extents, boxes); + + compositor->release (dst); + + return status; +} + +static cairo_status_t +upload_boxes (const cairo_traps_compositor_t *compositor, + cairo_composite_rectangles_t *extents, + cairo_boxes_t *boxes) +{ + cairo_surface_t *dst = extents->surface; + const cairo_pattern_t *source = &extents->source_pattern.base; + cairo_surface_t *src; + cairo_rectangle_int_t limit; + cairo_int_status_t status; + int tx, ty; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + src = _cairo_pattern_get_source((cairo_surface_pattern_t *)source, + &limit); + if (!(src->type == CAIRO_SURFACE_TYPE_IMAGE || src->type == dst->type)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (! _cairo_matrix_is_integer_translation (&source->matrix, &tx, &ty)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* Check that the data is entirely within the image */ + if (extents->bounded.x + tx < limit.x || extents->bounded.y + ty < limit.y) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (extents->bounded.x + extents->bounded.width + tx > limit.x + limit.width || + extents->bounded.y + extents->bounded.height + ty > limit.y + limit.height) + return CAIRO_INT_STATUS_UNSUPPORTED; + + tx += limit.x; + ty += limit.y; + + if (src->type == CAIRO_SURFACE_TYPE_IMAGE) + status = compositor->draw_image_boxes (dst, + (cairo_image_surface_t *)src, + boxes, tx, ty); + else + status = compositor->copy_boxes (dst, src, boxes, &extents->bounded, + tx, ty); + + return status; +} + +static cairo_int_status_t +trim_extents_to_traps (cairo_composite_rectangles_t *extents, + cairo_traps_t *traps) +{ + cairo_box_t box; + + _cairo_traps_extents (traps, &box); + return _cairo_composite_rectangles_intersect_mask_extents (extents, &box); +} + +static cairo_int_status_t +trim_extents_to_tristrip (cairo_composite_rectangles_t *extents, + cairo_tristrip_t *strip) +{ + cairo_box_t box; + + _cairo_tristrip_extents (strip, &box); + return _cairo_composite_rectangles_intersect_mask_extents (extents, &box); +} + +static cairo_int_status_t +trim_extents_to_boxes (cairo_composite_rectangles_t *extents, + cairo_boxes_t *boxes) +{ + cairo_box_t box; + + _cairo_boxes_extents (boxes, &box); + return _cairo_composite_rectangles_intersect_mask_extents (extents, &box); +} + +static cairo_int_status_t +boxes_for_traps (cairo_boxes_t *boxes, + cairo_traps_t *traps, + cairo_antialias_t antialias) +{ + int i, j; + + /* first check that the traps are rectilinear */ + if (antialias == CAIRO_ANTIALIAS_NONE) { + for (i = 0; i < traps->num_traps; i++) { + const cairo_trapezoid_t *t = &traps->traps[i]; + if (_cairo_fixed_integer_round_down (t->left.p1.x) != + _cairo_fixed_integer_round_down (t->left.p2.x) || + _cairo_fixed_integer_round_down (t->right.p1.x) != + _cairo_fixed_integer_round_down (t->right.p2.x)) + { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + } + } else { + for (i = 0; i < traps->num_traps; i++) { + const cairo_trapezoid_t *t = &traps->traps[i]; + if (t->left.p1.x != t->left.p2.x || t->right.p1.x != t->right.p2.x) + return CAIRO_INT_STATUS_UNSUPPORTED; + } + } + + _cairo_boxes_init (boxes); + + boxes->chunks.base = (cairo_box_t *) traps->traps; + boxes->chunks.size = traps->num_traps; + + if (antialias != CAIRO_ANTIALIAS_NONE) { + for (i = j = 0; i < traps->num_traps; i++) { + /* Note the traps and boxes alias so we need to take the local copies first. */ + cairo_fixed_t x1 = traps->traps[i].left.p1.x; + cairo_fixed_t x2 = traps->traps[i].right.p1.x; + cairo_fixed_t y1 = traps->traps[i].top; + cairo_fixed_t y2 = traps->traps[i].bottom; + + if (x1 == x2 || y1 == y2) + continue; + + boxes->chunks.base[j].p1.x = x1; + boxes->chunks.base[j].p1.y = y1; + boxes->chunks.base[j].p2.x = x2; + boxes->chunks.base[j].p2.y = y2; + j++; + + if (boxes->is_pixel_aligned) { + boxes->is_pixel_aligned = + _cairo_fixed_is_integer (x1) && _cairo_fixed_is_integer (y1) && + _cairo_fixed_is_integer (x2) && _cairo_fixed_is_integer (y2); + } + } + } else { + boxes->is_pixel_aligned = TRUE; + + for (i = j = 0; i < traps->num_traps; i++) { + /* Note the traps and boxes alias so we need to take the local copies first. */ + cairo_fixed_t x1 = traps->traps[i].left.p1.x; + cairo_fixed_t x2 = traps->traps[i].right.p1.x; + cairo_fixed_t y1 = traps->traps[i].top; + cairo_fixed_t y2 = traps->traps[i].bottom; + + /* round down here to match Pixman's behavior when using traps. */ + boxes->chunks.base[j].p1.x = _cairo_fixed_round_down (x1); + boxes->chunks.base[j].p1.y = _cairo_fixed_round_down (y1); + boxes->chunks.base[j].p2.x = _cairo_fixed_round_down (x2); + boxes->chunks.base[j].p2.y = _cairo_fixed_round_down (y2); + j += (boxes->chunks.base[j].p1.x != boxes->chunks.base[j].p2.x && + boxes->chunks.base[j].p1.y != boxes->chunks.base[j].p2.y); + } + } + boxes->chunks.count = j; + boxes->num_boxes = j; + + return CAIRO_INT_STATUS_SUCCESS; +} + +static cairo_status_t +clip_and_composite_boxes (const cairo_traps_compositor_t *compositor, + cairo_composite_rectangles_t *extents, + cairo_boxes_t *boxes); + +static cairo_status_t +clip_and_composite_polygon (const cairo_traps_compositor_t *compositor, + cairo_composite_rectangles_t *extents, + cairo_polygon_t *polygon, + cairo_antialias_t antialias, + cairo_fill_rule_t fill_rule, + cairo_bool_t curvy) +{ + composite_traps_info_t traps; + cairo_surface_t *dst = extents->surface; + cairo_bool_t clip_surface = ! _cairo_clip_is_region (extents->clip); + cairo_int_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + if (polygon->num_edges == 0) { + status = CAIRO_INT_STATUS_SUCCESS; + + if (! extents->is_bounded) { + cairo_region_t *clip_region = _cairo_clip_get_region (extents->clip); + + if (clip_region && + cairo_region_contains_rectangle (clip_region, + &extents->unbounded) == CAIRO_REGION_OVERLAP_IN) + clip_region = NULL; + + if (clip_region != NULL) { + status = compositor->set_clip_region (dst, clip_region); + if (unlikely (status)) + return status; + } + + if (clip_surface) + status = fixup_unbounded_with_mask (compositor, extents); + else + status = fixup_unbounded (compositor, extents, NULL); + + if (clip_region != NULL) + compositor->set_clip_region (dst, NULL); + } + + return status; + } + + if (extents->clip->path != NULL && extents->is_bounded) { + cairo_polygon_t clipper; + cairo_fill_rule_t clipper_fill_rule; + cairo_antialias_t clipper_antialias; + + status = _cairo_clip_get_polygon (extents->clip, + &clipper, + &clipper_fill_rule, + &clipper_antialias); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { + if (clipper_antialias == antialias) { + status = _cairo_polygon_intersect (polygon, fill_rule, + &clipper, clipper_fill_rule); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { + cairo_clip_t * clip = _cairo_clip_copy_region (extents->clip); + _cairo_clip_destroy (extents->clip); + extents->clip = clip; + + fill_rule = CAIRO_FILL_RULE_WINDING; + } + _cairo_polygon_fini (&clipper); + } + } + } + + if (antialias == CAIRO_ANTIALIAS_NONE && curvy) { + cairo_boxes_t boxes; + + _cairo_boxes_init (&boxes); + status = _cairo_rasterise_polygon_to_boxes (polygon, fill_rule, &boxes); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { + assert (boxes.is_pixel_aligned); + status = clip_and_composite_boxes (compositor, extents, &boxes); + } + _cairo_boxes_fini (&boxes); + if ((status != CAIRO_INT_STATUS_UNSUPPORTED)) + return status; + } + + _cairo_traps_init (&traps.traps); + + if (antialias == CAIRO_ANTIALIAS_NONE && curvy) { + status = _cairo_rasterise_polygon_to_traps (polygon, fill_rule, antialias, &traps.traps); + } else { + status = _cairo_bentley_ottmann_tessellate_polygon (&traps.traps, polygon, fill_rule); + } + if (unlikely (status)) + goto CLEANUP_TRAPS; + + status = trim_extents_to_traps (extents, &traps.traps); + if (unlikely (status)) + goto CLEANUP_TRAPS; + + /* Use a fast path if the trapezoids consist of a set of boxes. */ + status = CAIRO_INT_STATUS_UNSUPPORTED; + if (1) { + cairo_boxes_t boxes; + + status = boxes_for_traps (&boxes, &traps.traps, antialias); + if (status == CAIRO_INT_STATUS_SUCCESS) { + status = clip_and_composite_boxes (compositor, extents, &boxes); + /* XXX need to reconstruct the traps! */ + assert (status != CAIRO_INT_STATUS_UNSUPPORTED); + } + } + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + /* Otherwise render the trapezoids to a mask and composite in the usual + * fashion. + */ + unsigned int flags = 0; + + /* For unbounded operations, the X11 server will estimate the + * affected rectangle and apply the operation to that. However, + * there are cases where this is an overestimate (e.g. the + * clip-fill-{eo,nz}-unbounded test). + * + * The clip will trim that overestimate to our expectations. + */ + if (! extents->is_bounded) + flags |= FORCE_CLIP_REGION; + + traps.antialias = antialias; + status = clip_and_composite (compositor, extents, + composite_traps, NULL, &traps, + need_unbounded_clip (extents) | flags); + } + +CLEANUP_TRAPS: + _cairo_traps_fini (&traps.traps); + + return status; +} + +struct composite_opacity_info { + const cairo_traps_compositor_t *compositor; + uint8_t op; + cairo_surface_t *dst; + cairo_surface_t *src; + int src_x, src_y; + double opacity; +}; + +static void composite_opacity(void *closure, + int16_t x, int16_t y, + int16_t w, int16_t h, + uint16_t coverage) +{ + struct composite_opacity_info *info = closure; + const cairo_traps_compositor_t *compositor = info->compositor; + cairo_surface_t *mask; + int mask_x, mask_y; + cairo_color_t color; + cairo_solid_pattern_t solid; + + _cairo_color_init_rgba (&color, 0, 0, 0, info->opacity * coverage); + _cairo_pattern_init_solid (&solid, &color); + mask = compositor->pattern_to_surface (info->dst, &solid.base, TRUE, + &_cairo_unbounded_rectangle, + &_cairo_unbounded_rectangle, + &mask_x, &mask_y); + if (likely (mask->status == CAIRO_STATUS_SUCCESS)) { + if (info->src) { + compositor->composite (info->dst, info->op, info->src, mask, + x + info->src_x, y + info->src_y, + mask_x, mask_y, + x, y, + w, h); + } else { + compositor->composite (info->dst, info->op, mask, NULL, + mask_x, mask_y, + 0, 0, + x, y, + w, h); + } + } + + cairo_surface_destroy (mask); +} + + +static cairo_int_status_t +composite_opacity_boxes (const cairo_traps_compositor_t *compositor, + cairo_surface_t *dst, + void *closure, + cairo_operator_t op, + cairo_surface_t *src, + int src_x, + int src_y, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents, + cairo_clip_t *clip) +{ + const cairo_solid_pattern_t *mask = closure; + struct composite_opacity_info info; + int i; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + info.compositor = compositor; + info.op = op; + info.dst = dst; + + info.src = src; + info.src_x = src_x; + info.src_y = src_y; + + info.opacity = mask->color.alpha / (double) 0xffff; + + /* XXX for lots of boxes create a clip region for the fully opaque areas */ + for (i = 0; i < clip->num_boxes; i++) + do_unaligned_box(composite_opacity, &info, + &clip->boxes[i], dst_x, dst_y); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +composite_boxes (const cairo_traps_compositor_t *compositor, + cairo_surface_t *dst, + void *closure, + cairo_operator_t op, + cairo_surface_t *src, + int src_x, + int src_y, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents, + cairo_clip_t *clip) +{ + cairo_traps_t traps; + cairo_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + status = _cairo_traps_init_boxes (&traps, closure); + if (unlikely (status)) + return status; + + status = compositor->composite_traps (dst, op, src, + src_x - dst_x, src_y - dst_y, + dst_x, dst_y, + extents, + CAIRO_ANTIALIAS_DEFAULT, &traps); + _cairo_traps_fini (&traps); + + return status; +} + +static cairo_status_t +clip_and_composite_boxes (const cairo_traps_compositor_t *compositor, + cairo_composite_rectangles_t *extents, + cairo_boxes_t *boxes) +{ + cairo_int_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + if (boxes->num_boxes == 0 && extents->is_bounded) + return CAIRO_STATUS_SUCCESS; + + status = trim_extents_to_boxes (extents, boxes); + if (unlikely (status)) + return status; + + if (boxes->is_pixel_aligned && extents->clip->path == NULL && + extents->source_pattern.base.type == CAIRO_PATTERN_TYPE_SURFACE && + (op_reduces_to_source (extents) || + (extents->op == CAIRO_OPERATOR_OVER && + (extents->source_pattern.surface.surface->content & CAIRO_CONTENT_ALPHA) == 0))) + { + status = upload_boxes (compositor, extents, boxes); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + } + + /* Can we reduce drawing through a clip-mask to simply drawing the clip? */ + if (extents->clip->path != NULL && extents->is_bounded) { + cairo_polygon_t polygon; + cairo_fill_rule_t fill_rule; + cairo_antialias_t antialias; + cairo_clip_t *clip; + + clip = _cairo_clip_copy (extents->clip); + clip = _cairo_clip_intersect_boxes (clip, boxes); + if (_cairo_clip_is_all_clipped (clip)) + return CAIRO_INT_STATUS_NOTHING_TO_DO; + + status = _cairo_clip_get_polygon (clip, &polygon, + &fill_rule, &antialias); + _cairo_clip_path_destroy (clip->path); + clip->path = NULL; + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { + cairo_clip_t *saved_clip = extents->clip; + extents->clip = clip; + + status = clip_and_composite_polygon (compositor, extents, &polygon, + antialias, fill_rule, FALSE); + + clip = extents->clip; + extents->clip = saved_clip; + + _cairo_polygon_fini (&polygon); + } + _cairo_clip_destroy (clip); + + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + } + + /* Use a fast path if the boxes are pixel aligned (or nearly aligned!) */ + if (boxes->is_pixel_aligned) { + status = composite_aligned_boxes (compositor, extents, boxes); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + } + + return clip_and_composite (compositor, extents, + composite_boxes, NULL, boxes, + need_unbounded_clip (extents)); +} + +static cairo_int_status_t +composite_traps_as_boxes (const cairo_traps_compositor_t *compositor, + cairo_composite_rectangles_t *extents, + composite_traps_info_t *info) +{ + cairo_boxes_t boxes; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + if (! _cairo_traps_to_boxes (&info->traps, info->antialias, &boxes)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + return clip_and_composite_boxes (compositor, extents, &boxes); +} + +static cairo_int_status_t +clip_and_composite_traps (const cairo_traps_compositor_t *compositor, + cairo_composite_rectangles_t *extents, + composite_traps_info_t *info, + unsigned flags) +{ + cairo_int_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + status = trim_extents_to_traps (extents, &info->traps); + if (unlikely (status != CAIRO_INT_STATUS_SUCCESS)) + return status; + + status = CAIRO_INT_STATUS_UNSUPPORTED; + if ((flags & FORCE_CLIP_REGION) == 0) + status = composite_traps_as_boxes (compositor, extents, info); + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + /* For unbounded operations, the X11 server will estimate the + * affected rectangle and apply the operation to that. However, + * there are cases where this is an overestimate (e.g. the + * clip-fill-{eo,nz}-unbounded test). + * + * The clip will trim that overestimate to our expectations. + */ + if (! extents->is_bounded) + flags |= FORCE_CLIP_REGION; + + status = clip_and_composite (compositor, extents, + composite_traps, NULL, info, + need_unbounded_clip (extents) | flags); + } + + return status; +} + +static cairo_int_status_t +clip_and_composite_tristrip (const cairo_traps_compositor_t *compositor, + cairo_composite_rectangles_t *extents, + composite_tristrip_info_t *info) +{ + cairo_int_status_t status; + unsigned int flags = 0; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + status = trim_extents_to_tristrip (extents, &info->strip); + if (unlikely (status != CAIRO_INT_STATUS_SUCCESS)) + return status; + + if (! extents->is_bounded) + flags |= FORCE_CLIP_REGION; + + status = clip_and_composite (compositor, extents, + composite_tristrip, NULL, info, + need_unbounded_clip (extents) | flags); + + return status; +} + +struct composite_mask { + cairo_surface_t *mask; + int mask_x, mask_y; +}; + +static cairo_int_status_t +composite_mask (const cairo_traps_compositor_t *compositor, + cairo_surface_t *dst, + void *closure, + cairo_operator_t op, + cairo_surface_t *src, + int src_x, + int src_y, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents, + cairo_clip_t *clip) +{ + struct composite_mask *data = closure; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + if (src != NULL) { + compositor->composite (dst, op, src, data->mask, + extents->x + src_x, extents->y + src_y, + extents->x + data->mask_x, extents->y + data->mask_y, + extents->x - dst_x, extents->y - dst_y, + extents->width, extents->height); + } else { + compositor->composite (dst, op, data->mask, NULL, + extents->x + data->mask_x, extents->y + data->mask_y, + 0, 0, + extents->x - dst_x, extents->y - dst_y, + extents->width, extents->height); + } + + return CAIRO_STATUS_SUCCESS; +} + +struct composite_box_info { + const cairo_traps_compositor_t *compositor; + cairo_surface_t *dst; + cairo_surface_t *src; + int src_x, src_y; + uint8_t op; +}; + +static void composite_box(void *closure, + int16_t x, int16_t y, + int16_t w, int16_t h, + uint16_t coverage) +{ + struct composite_box_info *info = closure; + const cairo_traps_compositor_t *compositor = info->compositor; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + if (! CAIRO_ALPHA_SHORT_IS_OPAQUE (coverage)) { + cairo_surface_t *mask; + cairo_color_t color; + cairo_solid_pattern_t solid; + int mask_x, mask_y; + + _cairo_color_init_rgba (&color, 0, 0, 0, coverage / (double)0xffff); + _cairo_pattern_init_solid (&solid, &color); + + mask = compositor->pattern_to_surface (info->dst, &solid.base, FALSE, + &_cairo_unbounded_rectangle, + &_cairo_unbounded_rectangle, + &mask_x, &mask_y); + + if (likely (mask->status == CAIRO_STATUS_SUCCESS)) { + compositor->composite (info->dst, info->op, info->src, mask, + x + info->src_x, y + info->src_y, + mask_x, mask_y, + x, y, + w, h); + } + + cairo_surface_destroy (mask); + } else { + compositor->composite (info->dst, info->op, info->src, NULL, + x + info->src_x, y + info->src_y, + 0, 0, + x, y, + w, h); + } +} + +static cairo_int_status_t +composite_mask_clip_boxes (const cairo_traps_compositor_t *compositor, + cairo_surface_t *dst, + void *closure, + cairo_operator_t op, + cairo_surface_t *src, + int src_x, + int src_y, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents, + cairo_clip_t *clip) +{ + struct composite_mask *data = closure; + struct composite_box_info info; + int i; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + info.compositor = compositor; + info.op = CAIRO_OPERATOR_SOURCE; + info.dst = dst; + info.src = data->mask; + info.src_x = data->mask_x; + info.src_y = data->mask_y; + + info.src_x += dst_x; + info.src_y += dst_y; + + for (i = 0; i < clip->num_boxes; i++) + do_unaligned_box(composite_box, &info, &clip->boxes[i], dst_x, dst_y); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +composite_mask_clip (const cairo_traps_compositor_t *compositor, + cairo_surface_t *dst, + void *closure, + cairo_operator_t op, + cairo_surface_t *src, + int src_x, + int src_y, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents, + cairo_clip_t *clip) +{ + struct composite_mask *data = closure; + cairo_polygon_t polygon; + cairo_fill_rule_t fill_rule; + composite_traps_info_t info; + cairo_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + status = _cairo_clip_get_polygon (clip, &polygon, + &fill_rule, &info.antialias); + if (unlikely (status)) + return status; + + _cairo_traps_init (&info.traps); + status = _cairo_bentley_ottmann_tessellate_polygon (&info.traps, + &polygon, + fill_rule); + _cairo_polygon_fini (&polygon); + if (unlikely (status)) + return status; + + status = composite_traps (compositor, dst, &info, + CAIRO_OPERATOR_SOURCE, + data->mask, + data->mask_x + dst_x, data->mask_y + dst_y, + dst_x, dst_y, + extents, NULL); + _cairo_traps_fini (&info.traps); + + return status; +} + +/* high-level compositor interface */ + +static cairo_int_status_t +_cairo_traps_compositor_paint (const cairo_compositor_t *_compositor, + cairo_composite_rectangles_t *extents) +{ + cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t*)_compositor; + cairo_boxes_t boxes; + cairo_int_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + status = compositor->check_composite (extents); + if (unlikely (status)) + return status; + + _cairo_clip_steal_boxes (extents->clip, &boxes); + status = clip_and_composite_boxes (compositor, extents, &boxes); + _cairo_clip_unsteal_boxes (extents->clip, &boxes); + + return status; +} + +static cairo_int_status_t +_cairo_traps_compositor_mask (const cairo_compositor_t *_compositor, + cairo_composite_rectangles_t *extents) +{ + const cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t*)_compositor; + cairo_int_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + status = compositor->check_composite (extents); + if (unlikely (status)) + return status; + + if (extents->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID && + extents->clip->path == NULL) { + status = clip_and_composite (compositor, extents, + composite_opacity_boxes, + composite_opacity_boxes, + &extents->mask_pattern, + need_unbounded_clip (extents)); + } else { + struct composite_mask data; + + data.mask = compositor->pattern_to_surface (extents->surface, + &extents->mask_pattern.base, + TRUE, + &extents->bounded, + &extents->mask_sample_area, + &data.mask_x, + &data.mask_y); + if (unlikely (data.mask->status)) + return data.mask->status; + + status = clip_and_composite (compositor, extents, + composite_mask, + extents->clip->path ? composite_mask_clip : composite_mask_clip_boxes, + &data, need_bounded_clip (extents)); + + cairo_surface_destroy (data.mask); + } + + return status; +} + +static cairo_int_status_t +_cairo_traps_compositor_stroke (const cairo_compositor_t *_compositor, + cairo_composite_rectangles_t *extents, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias) +{ + const cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t *)_compositor; + cairo_int_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + status = compositor->check_composite (extents); + if (unlikely (status)) + return status; + + status = CAIRO_INT_STATUS_UNSUPPORTED; + if (_cairo_path_fixed_stroke_is_rectilinear (path)) { + cairo_boxes_t boxes; + + _cairo_boxes_init_with_clip (&boxes, extents->clip); + status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path, + style, + ctm, + antialias, + &boxes); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) + status = clip_and_composite_boxes (compositor, extents, &boxes); + _cairo_boxes_fini (&boxes); + } + + if (status == CAIRO_INT_STATUS_UNSUPPORTED && 0 && + _cairo_clip_is_region (extents->clip)) /* XXX */ + { + composite_tristrip_info_t info; + + info.antialias = antialias; + _cairo_tristrip_init_with_clip (&info.strip, extents->clip); + status = _cairo_path_fixed_stroke_to_tristrip (path, style, + ctm, ctm_inverse, + tolerance, + &info.strip); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) + status = clip_and_composite_tristrip (compositor, extents, &info); + _cairo_tristrip_fini (&info.strip); + } + + if (status == CAIRO_INT_STATUS_UNSUPPORTED && + path->has_curve_to && antialias == CAIRO_ANTIALIAS_NONE) { + cairo_polygon_t polygon; + + _cairo_polygon_init_with_clip (&polygon, extents->clip); + status = _cairo_path_fixed_stroke_to_polygon (path, style, + ctm, ctm_inverse, + tolerance, + &polygon); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) + status = clip_and_composite_polygon (compositor, + extents, &polygon, + CAIRO_ANTIALIAS_NONE, + CAIRO_FILL_RULE_WINDING, + TRUE); + _cairo_polygon_fini (&polygon); + } + + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + cairo_int_status_t (*func) (const cairo_path_fixed_t *path, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_traps_t *traps); + composite_traps_info_t info; + unsigned flags; + + if (antialias == CAIRO_ANTIALIAS_BEST || antialias == CAIRO_ANTIALIAS_GOOD) { + func = _cairo_path_fixed_stroke_polygon_to_traps; + flags = 0; + } else { + func = _cairo_path_fixed_stroke_to_traps; + flags = need_bounded_clip (extents) & ~NEED_CLIP_SURFACE; + } + + info.antialias = antialias; + _cairo_traps_init_with_clip (&info.traps, extents->clip); + status = func (path, style, ctm, ctm_inverse, tolerance, &info.traps); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) + status = clip_and_composite_traps (compositor, extents, &info, flags); + _cairo_traps_fini (&info.traps); + } + + return status; +} + +static cairo_int_status_t +_cairo_traps_compositor_fill (const cairo_compositor_t *_compositor, + cairo_composite_rectangles_t *extents, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + const cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t *)_compositor; + cairo_int_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + status = compositor->check_composite (extents); + if (unlikely (status)) + return status; + + status = CAIRO_INT_STATUS_UNSUPPORTED; + if (_cairo_path_fixed_fill_is_rectilinear (path)) { + cairo_boxes_t boxes; + + _cairo_boxes_init_with_clip (&boxes, extents->clip); + status = _cairo_path_fixed_fill_rectilinear_to_boxes (path, + fill_rule, + antialias, + &boxes); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) + status = clip_and_composite_boxes (compositor, extents, &boxes); + _cairo_boxes_fini (&boxes); + } + + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + cairo_polygon_t polygon; + +#if 0 + if (extents->mask.width > extents->unbounded.width || + extents->mask.height > extents->unbounded.height) + { + cairo_box_t limits; + _cairo_box_from_rectangle (&limits, &extents->unbounded); + _cairo_polygon_init (&polygon, &limits, 1); + } + else + { + _cairo_polygon_init (&polygon, NULL, 0); + } + + status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { + status = _cairo_polygon_intersect_with_boxes (&polygon, &fill_rule, + extents->clip->boxes, + extents->clip->num_boxes); + } +#else + _cairo_polygon_init_with_clip (&polygon, extents->clip); + status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon); +#endif + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { + status = clip_and_composite_polygon (compositor, extents, &polygon, + antialias, fill_rule, path->has_curve_to); + } + _cairo_polygon_fini (&polygon); + } + + return status; +} + +static cairo_int_status_t +composite_glyphs (const cairo_traps_compositor_t *compositor, + cairo_surface_t *dst, + void *closure, + cairo_operator_t op, + cairo_surface_t *src, + int src_x, int src_y, + int dst_x, int dst_y, + const cairo_rectangle_int_t *extents, + cairo_clip_t *clip) +{ + cairo_composite_glyphs_info_t *info = closure; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + if (op == CAIRO_OPERATOR_ADD && (dst->content & CAIRO_CONTENT_COLOR) == 0) + info->use_mask = 0; + + return compositor->composite_glyphs (dst, op, src, + src_x, src_y, + dst_x, dst_y, + info); +} + +static cairo_int_status_t +_cairo_traps_compositor_glyphs (const cairo_compositor_t *_compositor, + cairo_composite_rectangles_t *extents, + cairo_scaled_font_t *scaled_font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_bool_t overlap) +{ + const cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t *)_compositor; + cairo_int_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + status = compositor->check_composite (extents); + if (unlikely (status)) + return status; + + _cairo_scaled_font_freeze_cache (scaled_font); + status = compositor->check_composite_glyphs (extents, + scaled_font, glyphs, + &num_glyphs); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { + cairo_composite_glyphs_info_t info; + + info.font = scaled_font; + info.glyphs = glyphs; + info.num_glyphs = num_glyphs; + info.use_mask = overlap || ! extents->is_bounded; + info.extents = extents->bounded; + + status = clip_and_composite (compositor, extents, + composite_glyphs, NULL, &info, + need_bounded_clip (extents) | FORCE_CLIP_REGION); + } + _cairo_scaled_font_thaw_cache (scaled_font); + + return status; +} + +void +_cairo_traps_compositor_init (cairo_traps_compositor_t *compositor, + const cairo_compositor_t *delegate) +{ + compositor->base.delegate = delegate; + + compositor->base.paint = _cairo_traps_compositor_paint; + compositor->base.mask = _cairo_traps_compositor_mask; + compositor->base.fill = _cairo_traps_compositor_fill; + compositor->base.stroke = _cairo_traps_compositor_stroke; + compositor->base.glyphs = _cairo_traps_compositor_glyphs; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-traps-private.h b/local/recipes/libs/cairo/source/src/cairo-traps-private.h new file mode 100644 index 0000000000..dcaf40d186 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-traps-private.h @@ -0,0 +1,143 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + */ + +#ifndef CAIRO_TRAPS_PRIVATE_H +#define CAIRO_TRAPS_PRIVATE_H + +#include "cairo-compiler-private.h" +#include "cairo-error-private.h" +#include "cairo-types-private.h" + +CAIRO_BEGIN_DECLS + +struct _cairo_traps { + cairo_status_t status; + + cairo_box_t bounds; + const cairo_box_t *limits; + int num_limits; + + unsigned int maybe_region : 1; /* hint: 0 implies that it cannot be */ + unsigned int has_intersections : 1; + unsigned int is_rectilinear : 1; + unsigned int is_rectangular : 1; + + int num_traps; + int traps_size; + cairo_trapezoid_t *traps; + cairo_trapezoid_t traps_embedded[16]; +}; + +/* cairo-traps.c */ +cairo_private void +_cairo_traps_init (cairo_traps_t *traps); + +cairo_private void +_cairo_traps_init_with_clip (cairo_traps_t *traps, + const cairo_clip_t *clip); + +cairo_private void +_cairo_traps_limit (cairo_traps_t *traps, + const cairo_box_t *boxes, + int num_boxes); + +cairo_private cairo_status_t +_cairo_traps_init_boxes (cairo_traps_t *traps, + const cairo_boxes_t *boxes); + +cairo_private void +_cairo_traps_clear (cairo_traps_t *traps); + +cairo_private void +_cairo_traps_fini (cairo_traps_t *traps); + +#define _cairo_traps_status(T) (T)->status + +cairo_private void +_cairo_traps_translate (cairo_traps_t *traps, int x, int y); + +cairo_private void +_cairo_traps_tessellate_triangle_with_edges (cairo_traps_t *traps, + const cairo_point_t t[3], + const cairo_point_t edges[4]); + +cairo_private void +_cairo_traps_tessellate_convex_quad (cairo_traps_t *traps, + const cairo_point_t q[4]); + +cairo_private cairo_status_t +_cairo_traps_tessellate_rectangle (cairo_traps_t *traps, + const cairo_point_t *top_left, + const cairo_point_t *bottom_right); + +cairo_private void +_cairo_traps_add_trap (cairo_traps_t *traps, + cairo_fixed_t top, cairo_fixed_t bottom, + const cairo_line_t *left, + const cairo_line_t *right); + +cairo_private int +_cairo_traps_contain (const cairo_traps_t *traps, + double x, double y); + +cairo_private void +_cairo_traps_extents (const cairo_traps_t *traps, + cairo_box_t *extents); + +cairo_private cairo_int_status_t +_cairo_traps_extract_region (cairo_traps_t *traps, + cairo_antialias_t antialias, + cairo_region_t **region); + +cairo_private cairo_bool_t +_cairo_traps_to_boxes (cairo_traps_t *traps, + cairo_antialias_t antialias, + cairo_boxes_t *boxes); + +cairo_private cairo_status_t +_cairo_traps_path (const cairo_traps_t *traps, + cairo_path_fixed_t *path); + +cairo_private cairo_int_status_t +_cairo_rasterise_polygon_to_traps (cairo_polygon_t *polygon, + cairo_fill_rule_t fill_rule, + cairo_antialias_t antialias, + cairo_traps_t *traps); + +CAIRO_END_DECLS + +#endif /* CAIRO_TRAPS_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-traps.c b/local/recipes/libs/cairo/source/src/cairo-traps.c new file mode 100644 index 0000000000..b59b96d439 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-traps.c @@ -0,0 +1,1123 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* + * Copyright © 2002 Keith Packard + * Copyright © 2007 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Keith Packard + * + * Contributor(s): + * Keith R. Packard + * Carl D. Worth + * + * 2002-07-15: Converted from XRenderCompositeDoublePoly to #cairo_trap_t. Carl D. Worth + */ + +#include "cairoint.h" + +#include "cairo-box-inline.h" +#include "cairo-boxes-private.h" +#include "cairo-error-private.h" +#include "cairo-line-private.h" +#include "cairo-region-private.h" +#include "cairo-slope-private.h" +#include "cairo-traps-private.h" +#include "cairo-spans-private.h" + +/* private functions */ + +void +_cairo_traps_init (cairo_traps_t *traps) +{ + VG (VALGRIND_MAKE_MEM_UNDEFINED (traps, sizeof (cairo_traps_t))); + + traps->status = CAIRO_STATUS_SUCCESS; + + traps->maybe_region = 1; + traps->is_rectilinear = 0; + traps->is_rectangular = 0; + + traps->num_traps = 0; + + traps->traps_size = ARRAY_LENGTH (traps->traps_embedded); + traps->traps = traps->traps_embedded; + + traps->num_limits = 0; + traps->has_intersections = FALSE; +} + +void +_cairo_traps_limit (cairo_traps_t *traps, + const cairo_box_t *limits, + int num_limits) +{ + int i; + + traps->limits = limits; + traps->num_limits = num_limits; + + traps->bounds = limits[0]; + for (i = 1; i < num_limits; i++) + _cairo_box_add_box (&traps->bounds, &limits[i]); +} + +void +_cairo_traps_init_with_clip (cairo_traps_t *traps, + const cairo_clip_t *clip) +{ + _cairo_traps_init (traps); + if (clip) + _cairo_traps_limit (traps, clip->boxes, clip->num_boxes); +} + +void +_cairo_traps_clear (cairo_traps_t *traps) +{ + traps->status = CAIRO_STATUS_SUCCESS; + + traps->maybe_region = 1; + traps->is_rectilinear = 0; + traps->is_rectangular = 0; + + traps->num_traps = 0; + traps->has_intersections = FALSE; +} + +void +_cairo_traps_fini (cairo_traps_t *traps) +{ + if (traps->traps != traps->traps_embedded) + free (traps->traps); + + VG (VALGRIND_MAKE_MEM_UNDEFINED (traps, sizeof (cairo_traps_t))); +} + +/* make room for at least one more trap */ +static cairo_bool_t +_cairo_traps_grow (cairo_traps_t *traps) +{ + cairo_trapezoid_t *new_traps; + int new_size = 4 * traps->traps_size; + + if (CAIRO_INJECT_FAULT ()) { + traps->status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + return FALSE; + } + + if (traps->traps == traps->traps_embedded) { + new_traps = _cairo_malloc_ab (new_size, sizeof (cairo_trapezoid_t)); + if (new_traps != NULL) + memcpy (new_traps, traps->traps, sizeof (traps->traps_embedded)); + } else { + new_traps = _cairo_realloc_ab (traps->traps, + new_size, sizeof (cairo_trapezoid_t)); + } + + if (unlikely (new_traps == NULL)) { + traps->status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + return FALSE; + } + + traps->traps = new_traps; + traps->traps_size = new_size; + return TRUE; +} + +void +_cairo_traps_add_trap (cairo_traps_t *traps, + cairo_fixed_t top, cairo_fixed_t bottom, + const cairo_line_t *left, + const cairo_line_t *right) +{ + cairo_trapezoid_t *trap; + + assert (left->p1.y != left->p2.y); + assert (right->p1.y != right->p2.y); + assert (bottom > top); + + if (unlikely (traps->num_traps == traps->traps_size)) { + if (unlikely (! _cairo_traps_grow (traps))) + return; + } + + trap = &traps->traps[traps->num_traps++]; + trap->top = top; + trap->bottom = bottom; + trap->left = *left; + trap->right = *right; +} + +static void +_cairo_traps_add_clipped_trap (cairo_traps_t *traps, + cairo_fixed_t _top, cairo_fixed_t _bottom, + const cairo_line_t *_left, + const cairo_line_t *_right) +{ + /* Note: With the goofy trapezoid specification, (where an + * arbitrary two points on the lines can specified for the left + * and right edges), these limit checks would not work in + * general. For example, one can imagine a trapezoid entirely + * within the limits, but with two points used to specify the left + * edge entirely to the right of the limits. Fortunately, for our + * purposes, cairo will never generate such a crazy + * trapezoid. Instead, cairo always uses for its points the + * extreme positions of the edge that are visible on at least some + * trapezoid. With this constraint, it's impossible for both + * points to be outside the limits while the relevant edge is + * entirely inside the limits. + */ + if (traps->num_limits) { + const cairo_box_t *b = &traps->bounds; + cairo_fixed_t top = _top, bottom = _bottom; + cairo_line_t left = *_left, right = *_right; + + /* Trivially reject if trapezoid is entirely to the right or + * to the left of the limits. */ + if (left.p1.x >= b->p2.x && left.p2.x >= b->p2.x) + return; + + if (right.p1.x <= b->p1.x && right.p2.x <= b->p1.x) + return; + + /* And reject if the trapezoid is entirely above or below */ + if (top >= b->p2.y || bottom <= b->p1.y) + return; + + /* Otherwise, clip the trapezoid to the limits. We only clip + * where an edge is entirely outside the limits. If we wanted + * to be more clever, we could handle cases where a trapezoid + * edge intersects the edge of the limits, but that would + * require slicing this trapezoid into multiple trapezoids, + * and I'm not sure the effort would be worth it. */ + if (top < b->p1.y) + top = b->p1.y; + + if (bottom > b->p2.y) + bottom = b->p2.y; + + if (left.p1.x <= b->p1.x && left.p2.x <= b->p1.x) + left.p1.x = left.p2.x = b->p1.x; + + if (right.p1.x >= b->p2.x && right.p2.x >= b->p2.x) + right.p1.x = right.p2.x = b->p2.x; + + /* Trivial discards for empty trapezoids that are likely to + * be produced by our tessellators (most notably convex_quad + * when given a simple rectangle). + */ + if (top >= bottom) + return; + + /* cheap colinearity check */ + if (right.p1.x <= left.p1.x && right.p1.y == left.p1.y && + right.p2.x <= left.p2.x && right.p2.y == left.p2.y) + return; + + _cairo_traps_add_trap (traps, top, bottom, &left, &right); + } else + _cairo_traps_add_trap (traps, _top, _bottom, _left, _right); +} + +static int +_compare_point_fixed_by_y (const void *av, const void *bv) +{ + const cairo_point_t *a = av, *b = bv; + int ret = a->y - b->y; + if (ret == 0) + ret = a->x - b->x; + return ret; +} + +void +_cairo_traps_tessellate_convex_quad (cairo_traps_t *traps, + const cairo_point_t q[4]) +{ + int a, b, c, d; + int i; + cairo_slope_t ab, ad; + cairo_bool_t b_left_of_d; + cairo_line_t left; + cairo_line_t right; + + /* Choose a as a point with minimal y */ + a = 0; + for (i = 1; i < 4; i++) + if (_compare_point_fixed_by_y (&q[i], &q[a]) < 0) + a = i; + + /* b and d are adjacent to a, while c is opposite */ + b = (a + 1) % 4; + c = (a + 2) % 4; + d = (a + 3) % 4; + + /* Choose between b and d so that b.y is less than d.y */ + if (_compare_point_fixed_by_y (&q[d], &q[b]) < 0) { + b = (a + 3) % 4; + d = (a + 1) % 4; + } + + /* Without freedom left to choose anything else, we have four + * cases to tessellate. + * + * First, we have to determine the Y-axis sort of the four + * vertices, (either abcd or abdc). After that we need to determine + * which edges will be "left" and which will be "right" in the + * resulting trapezoids. This can be determined by computing a + * slope comparison of ab and ad to determine if b is left of d or + * not. + * + * Note that "left of" here is in the sense of which edges should + * be the left vs. right edges of the trapezoid. In particular, b + * left of d does *not* mean that b.x is less than d.x. + * + * This should hopefully be made clear in the lame ASCII art + * below. Since the same slope comparison is used in all cases, we + * compute it before testing for the Y-value sort. */ + + /* Note: If a == b then the ab slope doesn't give us any + * information. In that case, we can replace it with the ac (or + * equivalenly the bc) slope which gives us exactly the same + * information we need. At worst the names of the identifiers ab + * and b_left_of_d are inaccurate in this case, (would be ac, and + * c_left_of_d). */ + if (q[a].x == q[b].x && q[a].y == q[b].y) + _cairo_slope_init (&ab, &q[a], &q[c]); + else + _cairo_slope_init (&ab, &q[a], &q[b]); + + _cairo_slope_init (&ad, &q[a], &q[d]); + + b_left_of_d = _cairo_slope_compare (&ab, &ad) > 0; + + if (q[c].y <= q[d].y) { + if (b_left_of_d) { + /* Y-sort is abcd and b is left of d, (slope(ab) > slope (ad)) + * + * top bot left right + * _a a a + * / / /| |\ a.y b.y ab ad + * b / b | b \ + * / / | | \ \ b.y c.y bc ad + * c / c | c \ + * | / \| \ \ c.y d.y cd ad + * d d d + */ + left.p1 = q[a]; left.p2 = q[b]; + right.p1 = q[a]; right.p2 = q[d]; + _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right); + left.p1 = q[b]; left.p2 = q[c]; + _cairo_traps_add_clipped_trap (traps, q[b].y, q[c].y, &left, &right); + left.p1 = q[c]; left.p2 = q[d]; + _cairo_traps_add_clipped_trap (traps, q[c].y, q[d].y, &left, &right); + } else { + /* Y-sort is abcd and b is right of d, (slope(ab) <= slope (ad)) + * + * a a a_ + * /| |\ \ \ a.y b.y ad ab + * / b | b \ b + * / / | | \ \ b.y c.y ad bc + * / c | c \ c + * / / |/ \ | c.y d.y ad cd + * d d d + */ + left.p1 = q[a]; left.p2 = q[d]; + right.p1 = q[a]; right.p2 = q[b]; + _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right); + right.p1 = q[b]; right.p2 = q[c]; + _cairo_traps_add_clipped_trap (traps, q[b].y, q[c].y, &left, &right); + right.p1 = q[c]; right.p2 = q[d]; + _cairo_traps_add_clipped_trap (traps, q[c].y, q[d].y, &left, &right); + } + } else { + if (b_left_of_d) { + /* Y-sort is abdc and b is left of d, (slope (ab) > slope (ad)) + * + * a a a + * // / \ |\ a.y b.y ab ad + * /b/ b \ b \ + * / / \ \ \ \ b.y d.y bc ad + * /d/ \ d \ d + * // \ / \| d.y c.y bc dc + * c c c + */ + left.p1 = q[a]; left.p2 = q[b]; + right.p1 = q[a]; right.p2 = q[d]; + _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right); + left.p1 = q[b]; left.p2 = q[c]; + _cairo_traps_add_clipped_trap (traps, q[b].y, q[d].y, &left, &right); + right.p1 = q[d]; right.p2 = q[c]; + _cairo_traps_add_clipped_trap (traps, q[d].y, q[c].y, &left, &right); + } else { + /* Y-sort is abdc and b is right of d, (slope (ab) <= slope (ad)) + * + * a a a + * /| / \ \\ a.y b.y ad ab + * / b / b \b\ + * / / / / \ \ b.y d.y ad bc + * d / d / \d\ + * |/ \ / \\ d.y c.y dc bc + * c c c + */ + left.p1 = q[a]; left.p2 = q[d]; + right.p1 = q[a]; right.p2 = q[b]; + _cairo_traps_add_clipped_trap (traps, q[a].y, q[b].y, &left, &right); + right.p1 = q[b]; right.p2 = q[c]; + _cairo_traps_add_clipped_trap (traps, q[b].y, q[d].y, &left, &right); + left.p1 = q[d]; left.p2 = q[c]; + _cairo_traps_add_clipped_trap (traps, q[d].y, q[c].y, &left, &right); + } + } +} + +static void add_tri (cairo_traps_t *traps, + int y1, int y2, + const cairo_line_t *left, + const cairo_line_t *right) +{ + if (y2 < y1) { + int tmp = y1; + y1 = y2; + y2 = tmp; + } + + if (_cairo_lines_compare_at_y (left, right, y1) > 0) { + const cairo_line_t *tmp = left; + left = right; + right = tmp; + } + + _cairo_traps_add_clipped_trap (traps, y1, y2, left, right); +} + +void +_cairo_traps_tessellate_triangle_with_edges (cairo_traps_t *traps, + const cairo_point_t t[3], + const cairo_point_t edges[4]) +{ + cairo_line_t lines[3]; + + if (edges[0].y <= edges[1].y) { + lines[0].p1 = edges[0]; + lines[0].p2 = edges[1]; + } else { + lines[0].p1 = edges[1]; + lines[0].p2 = edges[0]; + } + + if (edges[2].y <= edges[3].y) { + lines[1].p1 = edges[2]; + lines[1].p2 = edges[3]; + } else { + lines[1].p1 = edges[3]; + lines[1].p2 = edges[2]; + } + + if (t[1].y == t[2].y) { + add_tri (traps, t[0].y, t[1].y, &lines[0], &lines[1]); + return; + } + + if (t[1].y <= t[2].y) { + lines[2].p1 = t[1]; + lines[2].p2 = t[2]; + } else { + lines[2].p1 = t[2]; + lines[2].p2 = t[1]; + } + + if (((t[1].y - t[0].y) < 0) ^ ((t[2].y - t[0].y) < 0)) { + add_tri (traps, t[0].y, t[1].y, &lines[0], &lines[2]); + add_tri (traps, t[0].y, t[2].y, &lines[1], &lines[2]); + } else if (abs(t[1].y - t[0].y) < abs(t[2].y - t[0].y)) { + add_tri (traps, t[0].y, t[1].y, &lines[0], &lines[1]); + add_tri (traps, t[1].y, t[2].y, &lines[2], &lines[1]); + } else { + add_tri (traps, t[0].y, t[2].y, &lines[1], &lines[0]); + add_tri (traps, t[1].y, t[2].y, &lines[2], &lines[0]); + } +} + +/** + * _cairo_traps_init_boxes: + * @traps: a #cairo_traps_t + * @box: an array box that will each be converted to a single trapezoid + * to store in @traps. + * + * Initializes a #cairo_traps_t to contain an array of rectangular + * trapezoids. + **/ +cairo_status_t +_cairo_traps_init_boxes (cairo_traps_t *traps, + const cairo_boxes_t *boxes) +{ + cairo_trapezoid_t *trap; + const struct _cairo_boxes_chunk *chunk; + + _cairo_traps_init (traps); + + while (traps->traps_size < boxes->num_boxes) { + if (unlikely (! _cairo_traps_grow (traps))) { + _cairo_traps_fini (traps); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + } + + traps->num_traps = boxes->num_boxes; + traps->is_rectilinear = TRUE; + traps->is_rectangular = TRUE; + traps->maybe_region = boxes->is_pixel_aligned; + + trap = &traps->traps[0]; + for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { + const cairo_box_t *box; + int i; + + box = chunk->base; + for (i = 0; i < chunk->count; i++) { + trap->top = box->p1.y; + trap->bottom = box->p2.y; + + trap->left.p1 = box->p1; + trap->left.p2.x = box->p1.x; + trap->left.p2.y = box->p2.y; + + trap->right.p1.x = box->p2.x; + trap->right.p1.y = box->p1.y; + trap->right.p2 = box->p2; + + box++, trap++; + } + } + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_traps_tessellate_rectangle (cairo_traps_t *traps, + const cairo_point_t *top_left, + const cairo_point_t *bottom_right) +{ + cairo_line_t left; + cairo_line_t right; + cairo_fixed_t top, bottom; + + if (top_left->y == bottom_right->y) + return CAIRO_STATUS_SUCCESS; + + if (top_left->x == bottom_right->x) + return CAIRO_STATUS_SUCCESS; + + left.p1.x = left.p2.x = top_left->x; + left.p1.y = right.p1.y = top_left->y; + right.p1.x = right.p2.x = bottom_right->x; + left.p2.y = right.p2.y = bottom_right->y; + + top = top_left->y; + bottom = bottom_right->y; + + if (traps->num_limits) { + cairo_bool_t reversed; + int n; + + if (top >= traps->bounds.p2.y || bottom <= traps->bounds.p1.y) + return CAIRO_STATUS_SUCCESS; + + /* support counter-clockwise winding for rectangular tessellation */ + reversed = top_left->x > bottom_right->x; + if (reversed) { + right.p1.x = right.p2.x = top_left->x; + left.p1.x = left.p2.x = bottom_right->x; + } + + if (left.p1.x >= traps->bounds.p2.x || right.p1.x <= traps->bounds.p1.x) + return CAIRO_STATUS_SUCCESS; + + for (n = 0; n < traps->num_limits; n++) { + const cairo_box_t *limits = &traps->limits[n]; + cairo_line_t _left, _right; + cairo_fixed_t _top, _bottom; + + if (top >= limits->p2.y) + continue; + if (bottom <= limits->p1.y) + continue; + + /* Trivially reject if trapezoid is entirely to the right or + * to the left of the limits. */ + if (left.p1.x >= limits->p2.x) + continue; + if (right.p1.x <= limits->p1.x) + continue; + + /* Otherwise, clip the trapezoid to the limits. */ + _top = top; + if (_top < limits->p1.y) + _top = limits->p1.y; + + _bottom = bottom; + if (_bottom > limits->p2.y) + _bottom = limits->p2.y; + + if (_bottom <= _top) + continue; + + _left = left; + if (_left.p1.x < limits->p1.x) { + _left.p1.x = limits->p1.x; + _left.p1.y = limits->p1.y; + _left.p2.x = limits->p1.x; + _left.p2.y = limits->p2.y; + } + + _right = right; + if (_right.p1.x > limits->p2.x) { + _right.p1.x = limits->p2.x; + _right.p1.y = limits->p1.y; + _right.p2.x = limits->p2.x; + _right.p2.y = limits->p2.y; + } + + if (left.p1.x >= right.p1.x) + continue; + + if (reversed) + _cairo_traps_add_trap (traps, _top, _bottom, &_right, &_left); + else + _cairo_traps_add_trap (traps, _top, _bottom, &_left, &_right); + } + } else { + _cairo_traps_add_trap (traps, top, bottom, &left, &right); + } + + return traps->status; +} + +void +_cairo_traps_translate (cairo_traps_t *traps, int x, int y) +{ + cairo_fixed_t xoff, yoff; + cairo_trapezoid_t *t; + int i; + + /* Ugh. The cairo_composite/(Render) interface doesn't allow + an offset for the trapezoids. Need to manually shift all + the coordinates to align with the offset origin of the + intermediate surface. */ + + xoff = _cairo_fixed_from_int (x); + yoff = _cairo_fixed_from_int (y); + + for (i = 0, t = traps->traps; i < traps->num_traps; i++, t++) { + t->top += yoff; + t->bottom += yoff; + t->left.p1.x += xoff; + t->left.p1.y += yoff; + t->left.p2.x += xoff; + t->left.p2.y += yoff; + t->right.p1.x += xoff; + t->right.p1.y += yoff; + t->right.p2.x += xoff; + t->right.p2.y += yoff; + } +} + +void +_cairo_trapezoid_array_translate_and_scale (cairo_trapezoid_t *offset_traps, + cairo_trapezoid_t *src_traps, + int num_traps, + double tx, double ty, + double sx, double sy) +{ + int i; + cairo_fixed_t xoff = _cairo_fixed_from_double (tx); + cairo_fixed_t yoff = _cairo_fixed_from_double (ty); + + if (sx == 1.0 && sy == 1.0) { + for (i = 0; i < num_traps; i++) { + offset_traps[i].top = src_traps[i].top + yoff; + offset_traps[i].bottom = src_traps[i].bottom + yoff; + offset_traps[i].left.p1.x = src_traps[i].left.p1.x + xoff; + offset_traps[i].left.p1.y = src_traps[i].left.p1.y + yoff; + offset_traps[i].left.p2.x = src_traps[i].left.p2.x + xoff; + offset_traps[i].left.p2.y = src_traps[i].left.p2.y + yoff; + offset_traps[i].right.p1.x = src_traps[i].right.p1.x + xoff; + offset_traps[i].right.p1.y = src_traps[i].right.p1.y + yoff; + offset_traps[i].right.p2.x = src_traps[i].right.p2.x + xoff; + offset_traps[i].right.p2.y = src_traps[i].right.p2.y + yoff; + } + } else { + cairo_fixed_t xsc = _cairo_fixed_from_double (sx); + cairo_fixed_t ysc = _cairo_fixed_from_double (sy); + + for (i = 0; i < num_traps; i++) { + offset_traps[i].top = _cairo_fixed_mul (src_traps[i].top + yoff, ysc); + offset_traps[i].bottom = _cairo_fixed_mul (src_traps[i].bottom + yoff, ysc); + offset_traps[i].left.p1.x = _cairo_fixed_mul (src_traps[i].left.p1.x + xoff, xsc); + offset_traps[i].left.p1.y = _cairo_fixed_mul (src_traps[i].left.p1.y + yoff, ysc); + offset_traps[i].left.p2.x = _cairo_fixed_mul (src_traps[i].left.p2.x + xoff, xsc); + offset_traps[i].left.p2.y = _cairo_fixed_mul (src_traps[i].left.p2.y + yoff, ysc); + offset_traps[i].right.p1.x = _cairo_fixed_mul (src_traps[i].right.p1.x + xoff, xsc); + offset_traps[i].right.p1.y = _cairo_fixed_mul (src_traps[i].right.p1.y + yoff, ysc); + offset_traps[i].right.p2.x = _cairo_fixed_mul (src_traps[i].right.p2.x + xoff, xsc); + offset_traps[i].right.p2.y = _cairo_fixed_mul (src_traps[i].right.p2.y + yoff, ysc); + } + } +} + +static cairo_bool_t +_cairo_trap_contains (cairo_trapezoid_t *t, cairo_point_t *pt) +{ + cairo_slope_t slope_left, slope_pt, slope_right; + + if (t->top > pt->y) + return FALSE; + if (t->bottom < pt->y) + return FALSE; + + _cairo_slope_init (&slope_left, &t->left.p1, &t->left.p2); + _cairo_slope_init (&slope_pt, &t->left.p1, pt); + + if (_cairo_slope_compare (&slope_left, &slope_pt) < 0) + return FALSE; + + _cairo_slope_init (&slope_right, &t->right.p1, &t->right.p2); + _cairo_slope_init (&slope_pt, &t->right.p1, pt); + + if (_cairo_slope_compare (&slope_pt, &slope_right) < 0) + return FALSE; + + return TRUE; +} + +cairo_bool_t +_cairo_traps_contain (const cairo_traps_t *traps, + double x, double y) +{ + int i; + cairo_point_t point; + + point.x = _cairo_fixed_from_double (x); + point.y = _cairo_fixed_from_double (y); + + for (i = 0; i < traps->num_traps; i++) { + if (_cairo_trap_contains (&traps->traps[i], &point)) + return TRUE; + } + + return FALSE; +} + +static cairo_fixed_t +_line_compute_intersection_x_for_y (const cairo_line_t *line, + cairo_fixed_t y) +{ + return _cairo_edge_compute_intersection_x_for_y (&line->p1, &line->p2, y); +} + +void +_cairo_traps_extents (const cairo_traps_t *traps, + cairo_box_t *extents) +{ + int i; + + if (traps->num_traps == 0) { + extents->p1.x = extents->p1.y = 0; + extents->p2.x = extents->p2.y = 0; + return; + } + + extents->p1.x = extents->p1.y = INT32_MAX; + extents->p2.x = extents->p2.y = INT32_MIN; + + for (i = 0; i < traps->num_traps; i++) { + const cairo_trapezoid_t *trap = &traps->traps[i]; + + if (trap->top < extents->p1.y) + extents->p1.y = trap->top; + if (trap->bottom > extents->p2.y) + extents->p2.y = trap->bottom; + + if (trap->left.p1.x < extents->p1.x) { + cairo_fixed_t x = trap->left.p1.x; + if (trap->top != trap->left.p1.y) { + x = _line_compute_intersection_x_for_y (&trap->left, + trap->top); + if (x < extents->p1.x) + extents->p1.x = x; + } else + extents->p1.x = x; + } + if (trap->left.p2.x < extents->p1.x) { + cairo_fixed_t x = trap->left.p2.x; + if (trap->bottom != trap->left.p2.y) { + x = _line_compute_intersection_x_for_y (&trap->left, + trap->bottom); + if (x < extents->p1.x) + extents->p1.x = x; + } else + extents->p1.x = x; + } + + if (trap->right.p1.x > extents->p2.x) { + cairo_fixed_t x = trap->right.p1.x; + if (trap->top != trap->right.p1.y) { + x = _line_compute_intersection_x_for_y (&trap->right, + trap->top); + if (x > extents->p2.x) + extents->p2.x = x; + } else + extents->p2.x = x; + } + if (trap->right.p2.x > extents->p2.x) { + cairo_fixed_t x = trap->right.p2.x; + if (trap->bottom != trap->right.p2.y) { + x = _line_compute_intersection_x_for_y (&trap->right, + trap->bottom); + if (x > extents->p2.x) + extents->p2.x = x; + } else + extents->p2.x = x; + } + } +} + +static cairo_bool_t +_mono_edge_is_vertical (const cairo_line_t *line) +{ + return _cairo_fixed_integer_round_down (line->p1.x) == _cairo_fixed_integer_round_down (line->p2.x); +} + +static cairo_bool_t +_traps_are_pixel_aligned (cairo_traps_t *traps, + cairo_antialias_t antialias) +{ + int i; + + if (antialias == CAIRO_ANTIALIAS_NONE) { + for (i = 0; i < traps->num_traps; i++) { + if (! _mono_edge_is_vertical (&traps->traps[i].left) || + ! _mono_edge_is_vertical (&traps->traps[i].right)) + { + traps->maybe_region = FALSE; + return FALSE; + } + } + } else { + for (i = 0; i < traps->num_traps; i++) { + if (traps->traps[i].left.p1.x != traps->traps[i].left.p2.x || + traps->traps[i].right.p1.x != traps->traps[i].right.p2.x || + ! _cairo_fixed_is_integer (traps->traps[i].top) || + ! _cairo_fixed_is_integer (traps->traps[i].bottom) || + ! _cairo_fixed_is_integer (traps->traps[i].left.p1.x) || + ! _cairo_fixed_is_integer (traps->traps[i].right.p1.x)) + { + traps->maybe_region = FALSE; + return FALSE; + } + } + } + + return TRUE; +} + +/** + * _cairo_traps_extract_region: + * @traps: a #cairo_traps_t + * @region: a #cairo_region_t + * + * Determines if a set of trapezoids are exactly representable as a + * cairo region. If so, the passed-in region is initialized to + * the area representing the given traps. It should be finalized + * with cairo_region_fini(). If not, %CAIRO_INT_STATUS_UNSUPPORTED + * is returned. + * + * Return value: %CAIRO_STATUS_SUCCESS, %CAIRO_INT_STATUS_UNSUPPORTED + * or %CAIRO_STATUS_NO_MEMORY + **/ +cairo_int_status_t +_cairo_traps_extract_region (cairo_traps_t *traps, + cairo_antialias_t antialias, + cairo_region_t **region) +{ + cairo_rectangle_int_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)]; + cairo_rectangle_int_t *rects = stack_rects; + cairo_int_status_t status; + int i, rect_count; + + /* we only treat this a hint... */ + if (antialias != CAIRO_ANTIALIAS_NONE && ! traps->maybe_region) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (! _traps_are_pixel_aligned (traps, antialias)) { + traps->maybe_region = FALSE; + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + if (traps->num_traps > ARRAY_LENGTH (stack_rects)) { + rects = _cairo_malloc_ab (traps->num_traps, sizeof (cairo_rectangle_int_t)); + + if (unlikely (rects == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + rect_count = 0; + for (i = 0; i < traps->num_traps; i++) { + int x1, y1, x2, y2; + + if (antialias == CAIRO_ANTIALIAS_NONE) { + x1 = _cairo_fixed_integer_round_down (traps->traps[i].left.p1.x); + y1 = _cairo_fixed_integer_round_down (traps->traps[i].top); + x2 = _cairo_fixed_integer_round_down (traps->traps[i].right.p1.x); + y2 = _cairo_fixed_integer_round_down (traps->traps[i].bottom); + } else { + x1 = _cairo_fixed_integer_part (traps->traps[i].left.p1.x); + y1 = _cairo_fixed_integer_part (traps->traps[i].top); + x2 = _cairo_fixed_integer_part (traps->traps[i].right.p1.x); + y2 = _cairo_fixed_integer_part (traps->traps[i].bottom); + } + + if (x2 > x1 && y2 > y1) { + rects[rect_count].x = x1; + rects[rect_count].y = y1; + rects[rect_count].width = x2 - x1; + rects[rect_count].height = y2 - y1; + rect_count++; + } + } + + + *region = cairo_region_create_rectangles (rects, rect_count); + status = (*region)->status; + + if (rects != stack_rects) + free (rects); + + return status; +} + +cairo_bool_t +_cairo_traps_to_boxes (cairo_traps_t *traps, + cairo_antialias_t antialias, + cairo_boxes_t *boxes) +{ + int i; + + for (i = 0; i < traps->num_traps; i++) { + if (traps->traps[i].left.p1.x != traps->traps[i].left.p2.x || + traps->traps[i].right.p1.x != traps->traps[i].right.p2.x) + return FALSE; + } + + _cairo_boxes_init (boxes); + + boxes->num_boxes = traps->num_traps; + boxes->chunks.base = (cairo_box_t *) traps->traps; + boxes->chunks.count = traps->num_traps; + boxes->chunks.size = traps->num_traps; + + if (antialias != CAIRO_ANTIALIAS_NONE) { + for (i = 0; i < traps->num_traps; i++) { + /* Note the traps and boxes alias so we need to take the local copies first. */ + cairo_fixed_t x1 = traps->traps[i].left.p1.x; + cairo_fixed_t x2 = traps->traps[i].right.p1.x; + cairo_fixed_t y1 = traps->traps[i].top; + cairo_fixed_t y2 = traps->traps[i].bottom; + + boxes->chunks.base[i].p1.x = x1; + boxes->chunks.base[i].p1.y = y1; + boxes->chunks.base[i].p2.x = x2; + boxes->chunks.base[i].p2.y = y2; + + if (boxes->is_pixel_aligned) { + boxes->is_pixel_aligned = + _cairo_fixed_is_integer (x1) && _cairo_fixed_is_integer (y1) && + _cairo_fixed_is_integer (x2) && _cairo_fixed_is_integer (y2); + } + } + } else { + boxes->is_pixel_aligned = TRUE; + + for (i = 0; i < traps->num_traps; i++) { + /* Note the traps and boxes alias so we need to take the local copies first. */ + cairo_fixed_t x1 = traps->traps[i].left.p1.x; + cairo_fixed_t x2 = traps->traps[i].right.p1.x; + cairo_fixed_t y1 = traps->traps[i].top; + cairo_fixed_t y2 = traps->traps[i].bottom; + + /* round down here to match Pixman's behavior when using traps. */ + boxes->chunks.base[i].p1.x = _cairo_fixed_round_down (x1); + boxes->chunks.base[i].p1.y = _cairo_fixed_round_down (y1); + boxes->chunks.base[i].p2.x = _cairo_fixed_round_down (x2); + boxes->chunks.base[i].p2.y = _cairo_fixed_round_down (y2); + } + } + + return TRUE; +} + +/* moves trap points such that they become the actual corners of the trapezoid */ +static void +_sanitize_trap (cairo_trapezoid_t *t) +{ + cairo_trapezoid_t s = *t; + +#define FIX(lr, tb, p) \ + if (t->lr.p.y != t->tb) { \ + t->lr.p.x = s.lr.p2.x + _cairo_fixed_mul_div_floor (s.lr.p1.x - s.lr.p2.x, s.tb - s.lr.p2.y, s.lr.p1.y - s.lr.p2.y); \ + t->lr.p.y = s.tb; \ + } + FIX (left, top, p1); + FIX (left, bottom, p2); + FIX (right, top, p1); + FIX (right, bottom, p2); +} + +cairo_private cairo_status_t +_cairo_traps_path (const cairo_traps_t *traps, + cairo_path_fixed_t *path) +{ + int i; + + for (i = 0; i < traps->num_traps; i++) { + cairo_status_t status; + cairo_trapezoid_t trap = traps->traps[i]; + + if (trap.top == trap.bottom) + continue; + + _sanitize_trap (&trap); + + status = _cairo_path_fixed_move_to (path, trap.left.p1.x, trap.top); + if (unlikely (status)) return status; + status = _cairo_path_fixed_line_to (path, trap.right.p1.x, trap.top); + if (unlikely (status)) return status; + status = _cairo_path_fixed_line_to (path, trap.right.p2.x, trap.bottom); + if (unlikely (status)) return status; + status = _cairo_path_fixed_line_to (path, trap.left.p2.x, trap.bottom); + if (unlikely (status)) return status; + status = _cairo_path_fixed_close_path (path); + if (unlikely (status)) return status; + } + + return CAIRO_STATUS_SUCCESS; +} + +void +_cairo_debug_print_traps (FILE *file, const cairo_traps_t *traps) +{ + cairo_box_t extents; + int n; + +#if 0 + if (traps->has_limits) { + printf ("%s: limits=(%d, %d, %d, %d)\n", + filename, + traps->limits.p1.x, traps->limits.p1.y, + traps->limits.p2.x, traps->limits.p2.y); + } +#endif + + _cairo_traps_extents (traps, &extents); + fprintf (file, "extents=(%d, %d, %d, %d)\n", + extents.p1.x, extents.p1.y, + extents.p2.x, extents.p2.y); + + for (n = 0; n < traps->num_traps; n++) { + fprintf (file, "%d %d L:(%d, %d), (%d, %d) R:(%d, %d), (%d, %d)\n", + traps->traps[n].top, + traps->traps[n].bottom, + traps->traps[n].left.p1.x, + traps->traps[n].left.p1.y, + traps->traps[n].left.p2.x, + traps->traps[n].left.p2.y, + traps->traps[n].right.p1.x, + traps->traps[n].right.p1.y, + traps->traps[n].right.p2.x, + traps->traps[n].right.p2.y); + } +} + +struct cairo_trap_renderer { + cairo_span_renderer_t base; + cairo_traps_t *traps; +}; + +static cairo_status_t +span_to_traps (void *abstract_renderer, int y, int h, + const cairo_half_open_span_t *spans, unsigned num_spans) +{ + struct cairo_trap_renderer *r = abstract_renderer; + cairo_fixed_t top, bot; + + if (num_spans == 0) + return CAIRO_STATUS_SUCCESS; + + top = _cairo_fixed_from_int (y); + bot = _cairo_fixed_from_int (y + h); + do { + if (spans[0].coverage) { + cairo_fixed_t x0 = _cairo_fixed_from_int(spans[0].x); + cairo_fixed_t x1 = _cairo_fixed_from_int(spans[1].x); + cairo_line_t left = { { x0, top }, { x0, bot } }, + right = { { x1, top }, { x1, bot } }; + _cairo_traps_add_trap (r->traps, top, bot, &left, &right); + } + spans++; + } while (--num_spans > 1); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_int_status_t +_cairo_rasterise_polygon_to_traps (cairo_polygon_t *polygon, + cairo_fill_rule_t fill_rule, + cairo_antialias_t antialias, + cairo_traps_t *traps) +{ + struct cairo_trap_renderer renderer; + cairo_scan_converter_t *converter; + cairo_int_status_t status; + cairo_rectangle_int_t r; + + TRACE ((stderr, "%s: fill_rule=%d, antialias=%d\n", + __FUNCTION__, fill_rule, antialias)); + assert(antialias == CAIRO_ANTIALIAS_NONE); + + renderer.traps = traps; + renderer.base.render_rows = span_to_traps; + + _cairo_box_round_to_rectangle (&polygon->extents, &r); + converter = _cairo_mono_scan_converter_create (r.x, r.y, + r.x + r.width, + r.y + r.height, + fill_rule); + status = _cairo_mono_scan_converter_add_polygon (converter, polygon); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) + status = converter->generate (converter, &renderer.base); + converter->destroy (converter); + return status; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-tristrip-private.h b/local/recipes/libs/cairo/source/src/cairo-tristrip-private.h new file mode 100644 index 0000000000..ccd28799e8 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-tristrip-private.h @@ -0,0 +1,94 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Chris Wilson + */ + +#ifndef CAIRO_TRISTRIP_PRIVATE_H +#define CAIRO_TRISTRIP_PRIVATE_H + +#include "cairo-compiler-private.h" +#include "cairo-error-private.h" +#include "cairo-types-private.h" + +CAIRO_BEGIN_DECLS + +struct _cairo_tristrip { + cairo_status_t status; + + /* XXX clipping */ + + const cairo_box_t *limits; + int num_limits; + + int num_points; + int size_points; + cairo_point_t *points; + cairo_point_t points_embedded[64]; +}; + +cairo_private void +_cairo_tristrip_init (cairo_tristrip_t *strip); + +cairo_private void +_cairo_tristrip_limit (cairo_tristrip_t *strip, + const cairo_box_t *limits, + int num_limits); + +cairo_private void +_cairo_tristrip_init_with_clip (cairo_tristrip_t *strip, + const cairo_clip_t *clip); + +cairo_private void +_cairo_tristrip_translate (cairo_tristrip_t *strip, int x, int y); + +cairo_private void +_cairo_tristrip_move_to (cairo_tristrip_t *strip, + const cairo_point_t *point); + +cairo_private void +_cairo_tristrip_add_point (cairo_tristrip_t *strip, + const cairo_point_t *point); + +cairo_private void +_cairo_tristrip_extents (const cairo_tristrip_t *strip, + cairo_box_t *extents); + +cairo_private void +_cairo_tristrip_fini (cairo_tristrip_t *strip); + +#define _cairo_tristrip_status(T) ((T)->status) + +CAIRO_END_DECLS + +#endif /* CAIRO_TRISTRIP_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-tristrip.c b/local/recipes/libs/cairo/source/src/cairo-tristrip.c new file mode 100644 index 0000000000..bcf3b23716 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-tristrip.c @@ -0,0 +1,185 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* + * Copyright © 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Chris Wilson + * + * Contributor(s): + * Chris Wilson + */ + +#include "cairoint.h" + +#include "cairo-error-private.h" +#include "cairo-tristrip-private.h" + +void +_cairo_tristrip_init (cairo_tristrip_t *strip) +{ + VG (VALGRIND_MAKE_MEM_UNDEFINED (strip, sizeof (cairo_tristrip_t))); + + strip->status = CAIRO_STATUS_SUCCESS; + + strip->num_limits = 0; + strip->num_points = 0; + + strip->size_points = ARRAY_LENGTH (strip->points_embedded); + strip->points = strip->points_embedded; +} + +void +_cairo_tristrip_fini (cairo_tristrip_t *strip) +{ + if (strip->points != strip->points_embedded) + free (strip->points); + + VG (VALGRIND_MAKE_MEM_UNDEFINED (strip, sizeof (cairo_tristrip_t))); +} + + +void +_cairo_tristrip_limit (cairo_tristrip_t *strip, + const cairo_box_t *limits, + int num_limits) +{ + strip->limits = limits; + strip->num_limits = num_limits; +} + +void +_cairo_tristrip_init_with_clip (cairo_tristrip_t *strip, + const cairo_clip_t *clip) +{ + _cairo_tristrip_init (strip); + if (clip) + _cairo_tristrip_limit (strip, clip->boxes, clip->num_boxes); +} + +/* make room for at least one more trap */ +static cairo_bool_t +_cairo_tristrip_grow (cairo_tristrip_t *strip) +{ + cairo_point_t *points; + int new_size = 4 * strip->size_points; + + if (CAIRO_INJECT_FAULT ()) { + strip->status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + return FALSE; + } + + if (strip->points == strip->points_embedded) { + points = _cairo_malloc_ab (new_size, sizeof (cairo_point_t)); + if (points != NULL) + memcpy (points, strip->points, sizeof (strip->points_embedded)); + } else { + points = _cairo_realloc_ab (strip->points, + new_size, sizeof (cairo_trapezoid_t)); + } + + if (unlikely (points == NULL)) { + strip->status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + return FALSE; + } + + strip->points = points; + strip->size_points = new_size; + return TRUE; +} + +void +_cairo_tristrip_add_point (cairo_tristrip_t *strip, + const cairo_point_t *p) +{ + if (unlikely (strip->num_points == strip->size_points)) { + if (unlikely (! _cairo_tristrip_grow (strip))) + return; + } + + strip->points[strip->num_points++] = *p; +} + +/* Insert degenerate triangles to advance to the given point. The + * next point inserted must also be @p. */ +void +_cairo_tristrip_move_to (cairo_tristrip_t *strip, + const cairo_point_t *p) +{ + if (strip->num_points == 0) + return; + + _cairo_tristrip_add_point (strip, &strip->points[strip->num_points-1]); + _cairo_tristrip_add_point (strip, p); +#if 0 + /* and one more for luck! (to preserve cw/ccw ordering) */ + _cairo_tristrip_add_point (strip, p); +#endif +} + +void +_cairo_tristrip_translate (cairo_tristrip_t *strip, int x, int y) +{ + cairo_fixed_t xoff, yoff; + cairo_point_t *p; + int i; + + xoff = _cairo_fixed_from_int (x); + yoff = _cairo_fixed_from_int (y); + + for (i = 0, p = strip->points; i < strip->num_points; i++, p++) { + p->x += xoff; + p->y += yoff; + } +} + +void +_cairo_tristrip_extents (const cairo_tristrip_t *strip, + cairo_box_t *extents) +{ + int i; + + if (strip->num_points == 0) { + extents->p1.x = extents->p1.y = 0; + extents->p2.x = extents->p2.y = 0; + return; + } + + extents->p2 = extents->p1 = strip->points[0]; + for (i = 1; i < strip->num_points; i++) { + const cairo_point_t *p = &strip->points[i]; + + if (p->x < extents->p1.x) + extents->p1.x = p->x; + else if (p->x > extents->p2.x) + extents->p2.x = p->x; + + if (p->y < extents->p1.y) + extents->p1.y = p->y; + else if (p->y > extents->p2.y) + extents->p2.y = p->y; + } +} diff --git a/local/recipes/libs/cairo/source/src/cairo-truetype-subset-private.h b/local/recipes/libs/cairo/source/src/cairo-truetype-subset-private.h new file mode 100644 index 0000000000..d97cf91620 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-truetype-subset-private.h @@ -0,0 +1,212 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2006 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Kristian Høgsberg + * Adrian Johnson + */ + +#ifndef CAIRO_TRUETYPE_SUBSET_PRIVATE_H +#define CAIRO_TRUETYPE_SUBSET_PRIVATE_H + +#include "cairoint.h" + +#if CAIRO_HAS_FONT_SUBSET + +/* The structs defined here should strictly follow the TrueType + * specification and not be padded. We use only 16-bit integer + * in their definition to guarantee that. The fields of type + * "FIXED" in the TT spec are broken into two *_1 and *_2 16-bit + * parts, and 64-bit members are broken into four. + * + * The test truetype-tables in the test suite makes sure that + * these tables have the right size. Please update that test + * if you add new tables/structs that should be packed. + */ + +#define MAKE_TT_TAG(a, b, c, d) ((int)((uint32_t)a<<24 | b<<16 | c<<8 | d)) +#define TT_TAG_CFF MAKE_TT_TAG('C','F','F',' ') +#define TT_TAG_cmap MAKE_TT_TAG('c','m','a','p') +#define TT_TAG_cvt MAKE_TT_TAG('c','v','t',' ') +#define TT_TAG_fpgm MAKE_TT_TAG('f','p','g','m') +#define TT_TAG_glyf MAKE_TT_TAG('g','l','y','f') +#define TT_TAG_head MAKE_TT_TAG('h','e','a','d') +#define TT_TAG_hhea MAKE_TT_TAG('h','h','e','a') +#define TT_TAG_hmtx MAKE_TT_TAG('h','m','t','x') +#define TT_TAG_loca MAKE_TT_TAG('l','o','c','a') +#define TT_TAG_maxp MAKE_TT_TAG('m','a','x','p') +#define TT_TAG_name MAKE_TT_TAG('n','a','m','e') +#define TT_TAG_OS2 MAKE_TT_TAG('O','S','/','2') +#define TT_TAG_post MAKE_TT_TAG('p','o','s','t') +#define TT_TAG_prep MAKE_TT_TAG('p','r','e','p') + +/* All tt_* structs are big-endian */ +typedef struct _tt_cmap_index { + uint16_t platform; + uint16_t encoding; + uint32_t offset; +} tt_cmap_index_t; + +typedef struct _tt_cmap { + uint16_t version; + uint16_t num_tables; + tt_cmap_index_t index[1]; +} tt_cmap_t; + +typedef struct _segment_map { + uint16_t format; + uint16_t length; + uint16_t version; + uint16_t segCountX2; + uint16_t searchRange; + uint16_t entrySelector; + uint16_t rangeShift; + uint16_t endCount[1]; +} tt_segment_map_t; + +typedef struct _tt_head { + int16_t version_1; + int16_t version_2; + int16_t revision_1; + int16_t revision_2; + uint16_t checksum_1; + uint16_t checksum_2; + uint16_t magic_1; + uint16_t magic_2; + uint16_t flags; + uint16_t units_per_em; + int16_t created_1; + int16_t created_2; + int16_t created_3; + int16_t created_4; + int16_t modified_1; + int16_t modified_2; + int16_t modified_3; + int16_t modified_4; + int16_t x_min; /* FWORD */ + int16_t y_min; /* FWORD */ + int16_t x_max; /* FWORD */ + int16_t y_max; /* FWORD */ + uint16_t mac_style; + uint16_t lowest_rec_pppem; + int16_t font_direction_hint; + int16_t index_to_loc_format; + int16_t glyph_data_format; +} tt_head_t; + +typedef struct _tt_hhea { + int16_t version_1; + int16_t version_2; + int16_t ascender; /* FWORD */ + int16_t descender; /* FWORD */ + int16_t line_gap; /* FWORD */ + uint16_t advance_max_width; /* UFWORD */ + int16_t min_left_side_bearing; /* FWORD */ + int16_t min_right_side_bearing; /* FWORD */ + int16_t x_max_extent; /* FWORD */ + int16_t caret_slope_rise; + int16_t caret_slope_run; + int16_t reserved[5]; + int16_t metric_data_format; + uint16_t num_hmetrics; +} tt_hhea_t; + +typedef struct _tt_maxp { + int16_t version_1; + int16_t version_2; + uint16_t num_glyphs; + uint16_t max_points; + uint16_t max_contours; + uint16_t max_composite_points; + uint16_t max_composite_contours; + uint16_t max_zones; + uint16_t max_twilight_points; + uint16_t max_storage; + uint16_t max_function_defs; + uint16_t max_instruction_defs; + uint16_t max_stack_elements; + uint16_t max_size_of_instructions; + uint16_t max_component_elements; + uint16_t max_component_depth; +} tt_maxp_t; + +typedef struct _tt_name_record { + uint16_t platform; + uint16_t encoding; + uint16_t language; + uint16_t name; + uint16_t length; + uint16_t offset; +} tt_name_record_t; + +typedef struct _tt_name { + uint16_t format; + uint16_t num_records; + uint16_t strings_offset; + tt_name_record_t records[1]; +} tt_name_t; + + +/* bitmask for fsSelection field */ +#define TT_FS_SELECTION_ITALIC 1 +#define TT_FS_SELECTION_BOLD 32 + +/* _unused fields are defined in TT spec but not used by cairo */ +typedef struct _tt_os2 { + uint16_t _unused1[2]; + uint16_t usWeightClass; + uint16_t _unused2[28]; + uint16_t fsSelection; + uint16_t _unused3[11]; +} tt_os2_t; + +/* composite_glyph_t flags */ +#define TT_ARG_1_AND_2_ARE_WORDS 0x0001 +#define TT_WE_HAVE_A_SCALE 0x0008 +#define TT_MORE_COMPONENTS 0x0020 +#define TT_WE_HAVE_AN_X_AND_Y_SCALE 0x0040 +#define TT_WE_HAVE_A_TWO_BY_TWO 0x0080 + +typedef struct _tt_composite_glyph { + uint16_t flags; + uint16_t index; + uint16_t args[6]; /* 1 to 6 arguments depending on value of flags */ +} tt_composite_glyph_t; + +typedef struct _tt_glyph_data { + int16_t num_contours; + int8_t data[8]; + tt_composite_glyph_t glyph; +} tt_glyph_data_t; + +#endif /* CAIRO_HAS_FONT_SUBSET */ + +#endif /* CAIRO_TRUETYPE_SUBSET_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-truetype-subset.c b/local/recipes/libs/cairo/source/src/cairo-truetype-subset.c new file mode 100644 index 0000000000..a8551117c5 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-truetype-subset.c @@ -0,0 +1,1688 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2004 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Kristian Høgsberg + * Adrian Johnson + */ + +/* + * Useful links: + * http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6.html + * http://www.microsoft.com/typography/specs/default.htm + */ + +#define _DEFAULT_SOURCE /* for snprintf(), strdup() */ +#include "cairoint.h" + +#include "cairo-array-private.h" +#include "cairo-error-private.h" + +#if CAIRO_HAS_FONT_SUBSET + +#include "cairo-scaled-font-subsets-private.h" +#include "cairo-truetype-subset-private.h" + + +typedef struct subset_glyph subset_glyph_t; +struct subset_glyph { + int parent_index; + unsigned long location; +}; + +typedef struct _cairo_truetype_font cairo_truetype_font_t; + +typedef struct table table_t; +struct table { + unsigned long tag; + cairo_status_t (*write) (cairo_truetype_font_t *font, unsigned long tag); + int pos; /* position in the font directory */ +}; + +struct _cairo_truetype_font { + + cairo_scaled_font_subset_t *scaled_font_subset; + + table_t truetype_tables[10]; + int num_tables; + + struct { + char *font_name; + char *ps_name; + int num_glyphs_in_face; /* glyphs in font */ + long x_min, y_min, x_max, y_max; + long ascent, descent; + int units_per_em; + } base; + + subset_glyph_t *glyphs; /* array size: num_glyphs_in_face + 2 */ + const cairo_scaled_font_backend_t *backend; + unsigned int num_glyphs; /* glyphs used */ + int *widths; /* array size: num_glyphs_in_face + 1 */ + int checksum_index; + cairo_array_t output; + cairo_array_t string_offsets; + unsigned long last_offset; + unsigned long last_boundary; + int *parent_to_subset; /* array size: num_glyphs_in_face + 1 */ + cairo_status_t status; + cairo_bool_t is_pdf; +}; + +/* + * Test that the structs we define for TrueType tables have the + * correct size, ie. they are not padded. + */ +#define check(T, S) COMPILE_TIME_ASSERT (sizeof (T) == (S)) +check (tt_head_t, 54); +check (tt_hhea_t, 36); +check (tt_maxp_t, 32); +check (tt_name_record_t, 12); +check (tt_name_t, 18); +check (tt_composite_glyph_t, 16); +check (tt_glyph_data_t, 26); +#undef check + +static cairo_status_t +cairo_truetype_font_use_glyph (cairo_truetype_font_t *font, + unsigned short glyph, + unsigned short *out); + +#define SFNT_VERSION 0x00010000 +#define SFNT_STRING_MAX_LENGTH 65535 + +static cairo_status_t +_cairo_truetype_font_set_error (cairo_truetype_font_t *font, + cairo_status_t status) +{ + if (status == CAIRO_STATUS_SUCCESS || + status == (int)CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + _cairo_status_set_error (&font->status, status); + + return _cairo_error (status); +} + +static cairo_status_t +_cairo_truetype_font_create (cairo_scaled_font_subset_t *scaled_font_subset, + cairo_bool_t is_pdf, + cairo_truetype_font_t **font_return) +{ + cairo_status_t status; + cairo_bool_t is_synthetic; + cairo_truetype_font_t *font; + const cairo_scaled_font_backend_t *backend; + tt_head_t head; + tt_hhea_t hhea; + tt_maxp_t maxp; + unsigned long size; + + backend = scaled_font_subset->scaled_font->backend; + if (!backend->load_truetype_table) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* FIXME: We should either support subsetting vertical fonts, or fail on + * vertical. Currently font_options_t doesn't have vertical flag, but + * it should be added in the future. For now, the freetype backend + * returns UNSUPPORTED in load_truetype_table if the font is vertical. + * + * if (cairo_font_options_get_vertical_layout (scaled_font_subset->scaled_font)) + * return CAIRO_INT_STATUS_UNSUPPORTED; + */ + + /* We need to use a fallback font if this font differs from the glyf outlines. */ + if (backend->is_synthetic) { + status = backend->is_synthetic (scaled_font_subset->scaled_font, &is_synthetic); + if (unlikely (status)) + return status; + + if (is_synthetic) + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + size = sizeof (tt_head_t); + status = backend->load_truetype_table (scaled_font_subset->scaled_font, + TT_TAG_head, 0, + (unsigned char *) &head, + &size); + if (unlikely (status)) + return status; + + size = sizeof (tt_maxp_t); + status = backend->load_truetype_table (scaled_font_subset->scaled_font, + TT_TAG_maxp, 0, + (unsigned char *) &maxp, + &size); + if (unlikely (status)) + return status; + + size = sizeof (tt_hhea_t); + status = backend->load_truetype_table (scaled_font_subset->scaled_font, + TT_TAG_hhea, 0, + (unsigned char *) &hhea, + &size); + if (unlikely (status)) + return status; + + font = _cairo_calloc (sizeof (cairo_truetype_font_t)); + if (unlikely (font == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + font->backend = backend; + font->base.num_glyphs_in_face = be16_to_cpu (maxp.num_glyphs); + font->scaled_font_subset = scaled_font_subset; + + font->last_offset = 0; + font->last_boundary = 0; + _cairo_array_init (&font->output, sizeof (char)); + status = _cairo_array_grow_by (&font->output, 4096); + if (unlikely (status)) + goto fail1; + + /* Add 2: +1 case font does not contain .notdef, and +1 because an extra + * entry is required to contain the end location of the last glyph. + */ + font->glyphs = _cairo_calloc_ab (font->base.num_glyphs_in_face + 2, sizeof (subset_glyph_t)); + if (unlikely (font->glyphs == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto fail1; + } + + /* Add 1 in case font does not contain .notdef */ + font->parent_to_subset = _cairo_calloc_ab (font->base.num_glyphs_in_face + 1, sizeof (int)); + if (unlikely (font->parent_to_subset == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto fail2; + } + + font->is_pdf = is_pdf; + font->num_glyphs = 0; + font->base.x_min = (int16_t) be16_to_cpu (head.x_min); + font->base.y_min = (int16_t) be16_to_cpu (head.y_min); + font->base.x_max = (int16_t) be16_to_cpu (head.x_max); + font->base.y_max = (int16_t) be16_to_cpu (head.y_max); + font->base.ascent = (int16_t) be16_to_cpu (hhea.ascender); + font->base.descent = (int16_t) be16_to_cpu (hhea.descender); + font->base.units_per_em = (int16_t) be16_to_cpu (head.units_per_em); + if (font->base.units_per_em == 0) + font->base.units_per_em = 2048; + + font->base.ps_name = NULL; + font->base.font_name = NULL; + status = _cairo_truetype_read_font_name (scaled_font_subset->scaled_font, + &font->base.ps_name, + &font->base.font_name); + if (_cairo_status_is_error (status)) + goto fail3; + + /* If the PS name is not found, create a CairoFont-x-y name. */ + if (font->base.ps_name == NULL) { + font->base.ps_name = _cairo_malloc (30); + if (unlikely (font->base.ps_name == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto fail3; + } + + snprintf(font->base.ps_name, 30, "CairoFont-%u-%u", + scaled_font_subset->font_id, + scaled_font_subset->subset_id); + } + + /* Add 1 in case font does not contain .notdef */ + font->widths = _cairo_calloc_ab (font->base.num_glyphs_in_face + 1, sizeof (int)); + if (unlikely (font->widths == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto fail4; + } + + _cairo_array_init (&font->string_offsets, sizeof (unsigned long)); + status = _cairo_array_grow_by (&font->string_offsets, 10); + if (unlikely (status)) + goto fail5; + + font->status = CAIRO_STATUS_SUCCESS; + + *font_return = font; + + return CAIRO_STATUS_SUCCESS; + + fail5: + _cairo_array_fini (&font->string_offsets); + free (font->widths); + fail4: + free (font->base.ps_name); + fail3: + free (font->parent_to_subset); + free (font->base.font_name); + fail2: + free (font->glyphs); + fail1: + _cairo_array_fini (&font->output); + free (font); + + return status; +} + +static void +cairo_truetype_font_destroy (cairo_truetype_font_t *font) +{ + _cairo_array_fini (&font->string_offsets); + free (font->widths); + free (font->base.ps_name); + free (font->base.font_name); + free (font->parent_to_subset); + free (font->glyphs); + _cairo_array_fini (&font->output); + free (font); +} + +static cairo_status_t +cairo_truetype_font_allocate_write_buffer (cairo_truetype_font_t *font, + size_t length, + unsigned char **buffer) +{ + cairo_status_t status; + + if (font->status) + return font->status; + + status = _cairo_array_allocate (&font->output, length, (void **) buffer); + if (unlikely (status)) + return _cairo_truetype_font_set_error (font, status); + + return CAIRO_STATUS_SUCCESS; +} + +static void +cairo_truetype_font_write (cairo_truetype_font_t *font, + const void *data, + size_t length) +{ + cairo_status_t status; + + if (font->status) + return; + + status = _cairo_array_append_multiple (&font->output, data, length); + if (unlikely (status)) + status = _cairo_truetype_font_set_error (font, status); +} + +static void +cairo_truetype_font_write_be16 (cairo_truetype_font_t *font, + uint16_t value) +{ + uint16_t be16_value; + + if (font->status) + return; + + be16_value = cpu_to_be16 (value); + cairo_truetype_font_write (font, &be16_value, sizeof be16_value); +} + +static void +cairo_truetype_font_write_be32 (cairo_truetype_font_t *font, + uint32_t value) +{ + uint32_t be32_value; + + if (font->status) + return; + + be32_value = cpu_to_be32 (value); + cairo_truetype_font_write (font, &be32_value, sizeof be32_value); +} + +static cairo_status_t +cairo_truetype_font_align_output (cairo_truetype_font_t *font, + unsigned long *aligned) +{ + int length, pad; + unsigned char *padding; + + length = _cairo_array_num_elements (&font->output); + *aligned = (length + 3) & ~3; + pad = *aligned - length; + + if (pad) { + cairo_status_t status; + + status = cairo_truetype_font_allocate_write_buffer (font, pad, + &padding); + if (unlikely (status)) + return status; + + memset (padding, 0, pad); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +cairo_truetype_font_check_boundary (cairo_truetype_font_t *font, + unsigned long boundary) +{ + cairo_status_t status; + + if (font->status) + return font->status; + + if (boundary - font->last_offset > SFNT_STRING_MAX_LENGTH) + { + status = _cairo_array_append (&font->string_offsets, + &font->last_boundary); + if (unlikely (status)) + return _cairo_truetype_font_set_error (font, status); + + font->last_offset = font->last_boundary; + } + font->last_boundary = boundary; + + return CAIRO_STATUS_SUCCESS; +} + +typedef struct _cmap_unicode_range { + unsigned int start; + unsigned int end; +} cmap_unicode_range_t; + +static cmap_unicode_range_t winansi_unicode_ranges[] = { + { 0x0020, 0x007f }, + { 0x00a0, 0x00ff }, + { 0x0152, 0x0153 }, + { 0x0160, 0x0161 }, + { 0x0178, 0x0178 }, + { 0x017d, 0x017e }, + { 0x0192, 0x0192 }, + { 0x02c6, 0x02c6 }, + { 0x02dc, 0x02dc }, + { 0x2013, 0x2026 }, + { 0x2030, 0x2030 }, + { 0x2039, 0x203a }, + { 0x20ac, 0x20ac }, + { 0x2122, 0x2122 }, +}; + +static cairo_status_t +cairo_truetype_font_write_cmap_table (cairo_truetype_font_t *font, + unsigned long tag) +{ + int i; + unsigned int j; + int range_offset; + int num_ranges; + int entry_selector; + int length; + + num_ranges = ARRAY_LENGTH (winansi_unicode_ranges); + + length = 16 + (num_ranges + 1)*8; + for (i = 0; i < num_ranges; i++) + length += (winansi_unicode_ranges[i].end - winansi_unicode_ranges[i].start + 1)*2; + + entry_selector = 0; + while ((1 << entry_selector) <= (num_ranges + 1)) + entry_selector++; + + entry_selector--; + + cairo_truetype_font_write_be16 (font, 0); /* Table version */ + cairo_truetype_font_write_be16 (font, 1); /* Num tables */ + + cairo_truetype_font_write_be16 (font, 3); /* Platform */ + cairo_truetype_font_write_be16 (font, 1); /* Encoding */ + cairo_truetype_font_write_be32 (font, 12); /* Offset to start of table */ + + /* Output a format 4 encoding table for the winansi encoding */ + + cairo_truetype_font_write_be16 (font, 4); /* Format */ + cairo_truetype_font_write_be16 (font, length); /* Length */ + cairo_truetype_font_write_be16 (font, 0); /* Version */ + cairo_truetype_font_write_be16 (font, num_ranges*2 + 2); /* 2*segcount */ + cairo_truetype_font_write_be16 (font, (1 << (entry_selector + 1))); /* searchrange */ + cairo_truetype_font_write_be16 (font, entry_selector); /* entry selector */ + cairo_truetype_font_write_be16 (font, num_ranges*2 + 2 - (1 << (entry_selector + 1))); /* rangeshift */ + for (i = 0; i < num_ranges; i++) + cairo_truetype_font_write_be16 (font, winansi_unicode_ranges[i].end); /* end count[] */ + cairo_truetype_font_write_be16 (font, 0xffff); /* end count[] */ + + cairo_truetype_font_write_be16 (font, 0); /* reserved */ + + for (i = 0; i < num_ranges; i++) + cairo_truetype_font_write_be16 (font, winansi_unicode_ranges[i].start); /* startCode[] */ + cairo_truetype_font_write_be16 (font, 0xffff); /* startCode[] */ + + for (i = 0; i < num_ranges; i++) + cairo_truetype_font_write_be16 (font, 0x0000); /* delta[] */ + cairo_truetype_font_write_be16 (font, 1); /* delta[] */ + + range_offset = num_ranges*2 + 2; + for (i = 0; i < num_ranges; i++) { + cairo_truetype_font_write_be16 (font, range_offset); /* rangeOffset[] */ + range_offset += (winansi_unicode_ranges[i].end - winansi_unicode_ranges[i].start + 1)*2 - 2; + } + cairo_truetype_font_write_be16 (font, 0); /* rangeOffset[] */ + + for (i = 0; i < num_ranges; i++) { + for (j = winansi_unicode_ranges[i].start; j < winansi_unicode_ranges[i].end + 1; j++) { + int ch = _cairo_unicode_to_winansi (j); + int glyph; + + if (ch > 0) + glyph = font->scaled_font_subset->latin_to_subset_glyph_index[ch]; + else + glyph = 0; + cairo_truetype_font_write_be16 (font, glyph); + } + } + + return font->status; +} + +static cairo_status_t +cairo_truetype_font_write_generic_table (cairo_truetype_font_t *font, + unsigned long tag) +{ + cairo_status_t status; + unsigned char *buffer; + unsigned long size; + + if (font->status) + return font->status; + + size = 0; + status = font->backend->load_truetype_table(font->scaled_font_subset->scaled_font, + tag, 0, NULL, &size); + if (unlikely (status)) + return _cairo_truetype_font_set_error (font, status); + + status = cairo_truetype_font_allocate_write_buffer (font, size, &buffer); + if (unlikely (status)) + return _cairo_truetype_font_set_error (font, status); + + status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, + tag, 0, buffer, &size); + if (unlikely (status)) + return _cairo_truetype_font_set_error (font, status); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +cairo_truetype_font_remap_composite_glyph (cairo_truetype_font_t *font, + unsigned char *buffer, + unsigned long size) +{ + tt_glyph_data_t *glyph_data; + tt_composite_glyph_t *composite_glyph; + int num_args; + int has_more_components; + unsigned short flags; + unsigned short index; + cairo_status_t status; + unsigned char *end = buffer + size; + + if (font->status) + return font->status; + + glyph_data = (tt_glyph_data_t *) buffer; + if ((unsigned char *)(&glyph_data->data) >= end) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if ((int16_t)be16_to_cpu (glyph_data->num_contours) >= 0) + return CAIRO_STATUS_SUCCESS; + + composite_glyph = &glyph_data->glyph; + do { + if ((unsigned char *)(&composite_glyph->args[1]) > end) + return CAIRO_INT_STATUS_UNSUPPORTED; + + flags = be16_to_cpu (composite_glyph->flags); + has_more_components = flags & TT_MORE_COMPONENTS; + status = cairo_truetype_font_use_glyph (font, be16_to_cpu (composite_glyph->index), &index); + if (unlikely (status)) + return status; + + composite_glyph->index = cpu_to_be16 (index); + num_args = 1; + if (flags & TT_ARG_1_AND_2_ARE_WORDS) + num_args += 1; + + if (flags & TT_WE_HAVE_A_SCALE) + num_args += 1; + else if (flags & TT_WE_HAVE_AN_X_AND_Y_SCALE) + num_args += 2; + else if (flags & TT_WE_HAVE_A_TWO_BY_TWO) + num_args += 4; + + composite_glyph = (tt_composite_glyph_t *) &(composite_glyph->args[num_args]); + } while (has_more_components); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +cairo_truetype_font_write_glyf_table (cairo_truetype_font_t *font, + unsigned long tag) +{ + unsigned long start_offset, index, size, next; + tt_head_t header; + unsigned long begin, end; + unsigned char *buffer; + unsigned int i; + union { + unsigned char *bytes; + uint16_t *short_offsets; + uint32_t *long_offsets; + } u; + cairo_status_t status; + + if (font->status) + return font->status; + + size = sizeof (tt_head_t); + status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, + TT_TAG_head, 0, + (unsigned char*) &header, &size); + if (unlikely (status)) + return _cairo_truetype_font_set_error (font, status); + + if (be16_to_cpu (header.index_to_loc_format) == 0) + size = sizeof (int16_t) * (font->base.num_glyphs_in_face + 1); + else + size = sizeof (int32_t) * (font->base.num_glyphs_in_face + 1); + + u.bytes = _cairo_malloc (size); + if (unlikely (u.bytes == NULL)) + return _cairo_truetype_font_set_error (font, CAIRO_STATUS_NO_MEMORY); + + status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, + TT_TAG_loca, 0, u.bytes, &size); + if (unlikely (status)) { + free (u.bytes); + return _cairo_truetype_font_set_error (font, status); + } + + start_offset = _cairo_array_num_elements (&font->output); + for (i = 0; i < font->num_glyphs; i++) { + index = font->glyphs[i].parent_index; + if (be16_to_cpu (header.index_to_loc_format) == 0) { + begin = be16_to_cpu (u.short_offsets[index]) * 2; + end = be16_to_cpu (u.short_offsets[index + 1]) * 2; + } + else { + begin = be32_to_cpu (u.long_offsets[index]); + end = be32_to_cpu (u.long_offsets[index + 1]); + } + + /* quick sanity check... */ + if (end < begin) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto FAIL; + } + + size = end - begin; + status = cairo_truetype_font_align_output (font, &next); + if (unlikely (status)) + goto FAIL; + + status = cairo_truetype_font_check_boundary (font, next); + if (unlikely (status)) + goto FAIL; + + font->glyphs[i].location = next - start_offset; + + status = cairo_truetype_font_allocate_write_buffer (font, size, &buffer); + if (unlikely (status)) + goto FAIL; + + if (size > 1) { + tt_glyph_data_t *glyph_data; + int num_contours; + + status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, + TT_TAG_glyf, begin, buffer, &size); + if (unlikely (status)) + goto FAIL; + + glyph_data = (tt_glyph_data_t *) buffer; + num_contours = (int16_t)be16_to_cpu (glyph_data->num_contours); + if (num_contours < 0) { + status = cairo_truetype_font_remap_composite_glyph (font, buffer, size); + if (unlikely (status)) + goto FAIL; + } else if (num_contours == 0) { + /* num_contours == 0 is undefined in the Opentype + * spec. There are some embedded fonts that have a + * space glyph with num_contours = 0 that fails on + * some printers. The spec requires glyphs without + * contours to have a 0 size glyph entry in the loca + * table. + * + * If num_contours == 0, truncate the glyph to 0 size. + */ + _cairo_array_truncate (&font->output, _cairo_array_num_elements (&font->output) - size); + } + } + } + + status = cairo_truetype_font_align_output (font, &next); + if (unlikely (status)) + goto FAIL; + + font->glyphs[i].location = next - start_offset; + + status = font->status; +FAIL: + free (u.bytes); + + return _cairo_truetype_font_set_error (font, status); +} + +static cairo_status_t +cairo_truetype_font_write_head_table (cairo_truetype_font_t *font, + unsigned long tag) +{ + unsigned char *buffer; + unsigned long size; + cairo_status_t status; + + if (font->status) + return font->status; + + size = 0; + status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, + tag, 0, NULL, &size); + if (unlikely (status)) + return _cairo_truetype_font_set_error (font, status); + + font->checksum_index = _cairo_array_num_elements (&font->output) + 8; + status = cairo_truetype_font_allocate_write_buffer (font, size, &buffer); + if (unlikely (status)) + return _cairo_truetype_font_set_error (font, status); + + status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, + tag, 0, buffer, &size); + if (unlikely (status)) + return _cairo_truetype_font_set_error (font, status); + + /* set checkSumAdjustment to 0 for table checksum calculation */ + *(uint32_t *)(buffer + 8) = 0; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +cairo_truetype_font_write_hhea_table (cairo_truetype_font_t *font, unsigned long tag) +{ + tt_hhea_t *hhea; + unsigned long size; + cairo_status_t status; + + if (font->status) + return font->status; + + size = sizeof (tt_hhea_t); + status = cairo_truetype_font_allocate_write_buffer (font, size, (unsigned char **) &hhea); + if (unlikely (status)) + return _cairo_truetype_font_set_error (font, status); + + status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, + tag, 0, (unsigned char *) hhea, &size); + if (unlikely (status)) + return _cairo_truetype_font_set_error (font, status); + + hhea->num_hmetrics = cpu_to_be16 ((uint16_t)(font->num_glyphs)); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +cairo_truetype_font_write_hmtx_table (cairo_truetype_font_t *font, + unsigned long tag) +{ + unsigned long size; + unsigned long long_entry_size; + unsigned long short_entry_size; + short *p; + unsigned int i; + tt_hhea_t hhea; + int num_hmetrics; + cairo_status_t status; + + if (font->status) + return font->status; + + size = sizeof (tt_hhea_t); + status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, + TT_TAG_hhea, 0, + (unsigned char*) &hhea, &size); + if (unlikely (status)) + return _cairo_truetype_font_set_error (font, status); + + num_hmetrics = be16_to_cpu(hhea.num_hmetrics); + + for (i = 0; i < font->num_glyphs; i++) { + long_entry_size = 2 * sizeof (int16_t); + short_entry_size = sizeof (int16_t); + status = cairo_truetype_font_allocate_write_buffer (font, + long_entry_size, + (unsigned char **) &p); + if (unlikely (status)) + return _cairo_truetype_font_set_error (font, status); + + if (font->glyphs[i].parent_index < num_hmetrics) { + status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, + TT_TAG_hmtx, + font->glyphs[i].parent_index * long_entry_size, + (unsigned char *) p, &long_entry_size); + if (unlikely (status)) + return _cairo_truetype_font_set_error (font, status); + } + else + { + status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, + TT_TAG_hmtx, + (num_hmetrics - 1) * long_entry_size, + (unsigned char *) p, &short_entry_size); + if (unlikely (status)) + return _cairo_truetype_font_set_error (font, status); + + status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, + TT_TAG_hmtx, + num_hmetrics * long_entry_size + + (font->glyphs[i].parent_index - num_hmetrics) * short_entry_size, + (unsigned char *) (p + 1), &short_entry_size); + if (unlikely (status)) + return _cairo_truetype_font_set_error (font, status); + } + font->widths[i] = be16_to_cpu (p[0]); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +cairo_truetype_font_write_loca_table (cairo_truetype_font_t *font, + unsigned long tag) +{ + unsigned int i; + tt_head_t header; + unsigned long size; + cairo_status_t status; + + if (font->status) + return font->status; + + size = sizeof(tt_head_t); + status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, + TT_TAG_head, 0, + (unsigned char*) &header, &size); + if (unlikely (status)) + return _cairo_truetype_font_set_error (font, status); + + if (be16_to_cpu (header.index_to_loc_format) == 0) + { + for (i = 0; i < font->num_glyphs + 1; i++) + cairo_truetype_font_write_be16 (font, font->glyphs[i].location / 2); + } else { + for (i = 0; i < font->num_glyphs + 1; i++) + cairo_truetype_font_write_be32 (font, font->glyphs[i].location); + } + + return font->status; +} + +static cairo_status_t +cairo_truetype_font_write_maxp_table (cairo_truetype_font_t *font, + unsigned long tag) +{ + tt_maxp_t *maxp; + unsigned long size; + cairo_status_t status; + + if (font->status) + return font->status; + + size = sizeof (tt_maxp_t); + status = cairo_truetype_font_allocate_write_buffer (font, size, (unsigned char **) &maxp); + if (unlikely (status)) + return _cairo_truetype_font_set_error (font, status); + + status = font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, + tag, 0, (unsigned char *) maxp, &size); + if (unlikely (status)) + return _cairo_truetype_font_set_error (font, status); + + maxp->num_glyphs = cpu_to_be16 (font->num_glyphs); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +cairo_truetype_font_write_offset_table (cairo_truetype_font_t *font) +{ + cairo_status_t status; + unsigned char *table_buffer; + size_t table_buffer_length; + unsigned short search_range, entry_selector, range_shift; + + if (font->status) + return font->status; + + search_range = 1; + entry_selector = 0; + while (search_range * 2 <= font->num_tables) { + search_range *= 2; + entry_selector++; + } + search_range *= 16; + range_shift = font->num_tables * 16 - search_range; + + cairo_truetype_font_write_be32 (font, SFNT_VERSION); + cairo_truetype_font_write_be16 (font, font->num_tables); + cairo_truetype_font_write_be16 (font, search_range); + cairo_truetype_font_write_be16 (font, entry_selector); + cairo_truetype_font_write_be16 (font, range_shift); + + /* Allocate space for the table directory. Each directory entry + * will be filled in by cairo_truetype_font_update_entry() after + * the table is written. */ + table_buffer_length = font->num_tables * 16; + status = cairo_truetype_font_allocate_write_buffer (font, table_buffer_length, + &table_buffer); + if (unlikely (status)) + return _cairo_truetype_font_set_error (font, status); + + return CAIRO_STATUS_SUCCESS; +} + +static uint32_t +cairo_truetype_font_calculate_checksum (cairo_truetype_font_t *font, + unsigned long start, + unsigned long end) +{ + uint32_t *padded_end; + uint32_t *p; + uint32_t checksum; + char *data; + + checksum = 0; + data = _cairo_array_index (&font->output, 0); + p = (uint32_t *) (data + start); + padded_end = (uint32_t *) (data + ((end + 3) & ~3)); + while (p < padded_end) + checksum += be32_to_cpu(*p++); + + return checksum; +} + +static void +cairo_truetype_font_update_entry (cairo_truetype_font_t *font, + int index, + unsigned long tag, + unsigned long start, + unsigned long end) +{ + uint32_t *entry; + + entry = _cairo_array_index (&font->output, 12 + 16 * index); + entry[0] = cpu_to_be32 ((uint32_t)tag); + entry[1] = cpu_to_be32 (cairo_truetype_font_calculate_checksum (font, start, end)); + entry[2] = cpu_to_be32 ((uint32_t)start); + entry[3] = cpu_to_be32 ((uint32_t)(end - start)); +} + +static cairo_status_t +cairo_truetype_font_generate (cairo_truetype_font_t *font, + const char **data, + unsigned long *length, + const unsigned long **string_offsets, + unsigned long *num_strings) +{ + cairo_status_t status; + unsigned long start, end, next; + uint32_t checksum, *checksum_location; + int i; + + if (font->status) + return font->status; + + status = cairo_truetype_font_write_offset_table (font); + if (unlikely (status)) + goto FAIL; + + status = cairo_truetype_font_align_output (font, &start); + if (unlikely (status)) + goto FAIL; + + end = 0; + for (i = 0; i < font->num_tables; i++) { + status = font->truetype_tables[i].write (font, font->truetype_tables[i].tag); + if (unlikely (status)) + goto FAIL; + + end = _cairo_array_num_elements (&font->output); + status = cairo_truetype_font_align_output (font, &next); + if (unlikely (status)) + goto FAIL; + + cairo_truetype_font_update_entry (font, font->truetype_tables[i].pos, + font->truetype_tables[i].tag, start, end); + status = cairo_truetype_font_check_boundary (font, next); + if (unlikely (status)) + goto FAIL; + + start = next; + } + + checksum = + 0xb1b0afba - cairo_truetype_font_calculate_checksum (font, 0, end); + checksum_location = _cairo_array_index (&font->output, font->checksum_index); + *checksum_location = cpu_to_be32 (checksum); + + *data = _cairo_array_index (&font->output, 0); + *length = _cairo_array_num_elements (&font->output); + *num_strings = _cairo_array_num_elements (&font->string_offsets); + if (*num_strings != 0) + *string_offsets = _cairo_array_index (&font->string_offsets, 0); + else + *string_offsets = NULL; + + FAIL: + return _cairo_truetype_font_set_error (font, status); +} + +static cairo_status_t +cairo_truetype_font_use_glyph (cairo_truetype_font_t *font, + unsigned short glyph, + unsigned short *out) +{ + if (glyph >= font->base.num_glyphs_in_face) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (font->parent_to_subset[glyph] == 0) { + font->parent_to_subset[glyph] = font->num_glyphs; + font->glyphs[font->num_glyphs].parent_index = glyph; + font->num_glyphs++; + } + + *out = font->parent_to_subset[glyph]; + return CAIRO_STATUS_SUCCESS; +} + +static void +cairo_truetype_font_add_truetype_table (cairo_truetype_font_t *font, + unsigned long tag, + cairo_status_t (*write) (cairo_truetype_font_t *font, unsigned long tag), + int pos) +{ + font->truetype_tables[font->num_tables].tag = tag; + font->truetype_tables[font->num_tables].write = write; + font->truetype_tables[font->num_tables].pos = pos; + font->num_tables++; +} + +/* cairo_truetype_font_create_truetype_table_list() builds the list of + * truetype tables to be embedded in the subsetted font. Each call to + * cairo_truetype_font_add_truetype_table() adds a table, the callback + * for generating the table, and the position in the table directory + * to the truetype_tables array. + * + * As we write out the glyf table we remap composite glyphs. + * Remapping composite glyphs will reference the sub glyphs the + * composite glyph is made up of. The "glyf" table callback needs to + * be called first so we have all the glyphs in the subset before + * going further. + * + * The order in which tables are added to the truetype_table array + * using cairo_truetype_font_add_truetype_table() specifies the order + * in which the callback functions will be called. + * + * The tables in the table directory must be listed in alphabetical + * order. The "cvt", "fpgm", and "prep" are optional tables. They + * will only be embedded in the subset if they exist in the source + * font. "cmap" is only embedded for latin fonts. The pos parameter of + * cairo_truetype_font_add_truetype_table() specifies the position of + * the table in the table directory. + */ +static void +cairo_truetype_font_create_truetype_table_list (cairo_truetype_font_t *font) +{ + cairo_bool_t has_cvt = FALSE; + cairo_bool_t has_fpgm = FALSE; + cairo_bool_t has_prep = FALSE; + unsigned long size; + int pos; + + size = 0; + if (font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, + TT_TAG_cvt, 0, NULL, + &size) == CAIRO_INT_STATUS_SUCCESS) + has_cvt = TRUE; + + size = 0; + if (font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, + TT_TAG_fpgm, 0, NULL, + &size) == CAIRO_INT_STATUS_SUCCESS) + has_fpgm = TRUE; + + size = 0; + if (font->backend->load_truetype_table (font->scaled_font_subset->scaled_font, + TT_TAG_prep, 0, NULL, + &size) == CAIRO_INT_STATUS_SUCCESS) + has_prep = TRUE; + + font->num_tables = 0; + pos = 0; + if (font->is_pdf && font->scaled_font_subset->is_latin) + pos++; + if (has_cvt) + pos++; + if (has_fpgm) + pos++; + cairo_truetype_font_add_truetype_table (font, TT_TAG_glyf, cairo_truetype_font_write_glyf_table, pos); + + pos = 0; + if (font->is_pdf && font->scaled_font_subset->is_latin) + cairo_truetype_font_add_truetype_table (font, TT_TAG_cmap, cairo_truetype_font_write_cmap_table, pos++); + if (has_cvt) + cairo_truetype_font_add_truetype_table (font, TT_TAG_cvt, cairo_truetype_font_write_generic_table, pos++); + if (has_fpgm) + cairo_truetype_font_add_truetype_table (font, TT_TAG_fpgm, cairo_truetype_font_write_generic_table, pos++); + pos++; + cairo_truetype_font_add_truetype_table (font, TT_TAG_head, cairo_truetype_font_write_head_table, pos++); + cairo_truetype_font_add_truetype_table (font, TT_TAG_hhea, cairo_truetype_font_write_hhea_table, pos++); + cairo_truetype_font_add_truetype_table (font, TT_TAG_hmtx, cairo_truetype_font_write_hmtx_table, pos++); + cairo_truetype_font_add_truetype_table (font, TT_TAG_loca, cairo_truetype_font_write_loca_table, pos++); + cairo_truetype_font_add_truetype_table (font, TT_TAG_maxp, cairo_truetype_font_write_maxp_table, pos++); + if (has_prep) + cairo_truetype_font_add_truetype_table (font, TT_TAG_prep, cairo_truetype_font_write_generic_table, pos); +} + +static cairo_status_t +cairo_truetype_subset_init_internal (cairo_truetype_subset_t *truetype_subset, + cairo_scaled_font_subset_t *font_subset, + cairo_bool_t is_pdf) +{ + cairo_truetype_font_t *font = NULL; + cairo_status_t status; + const char *data = NULL; /* squelch bogus compiler warning */ + unsigned long length = 0; /* squelch bogus compiler warning */ + unsigned long offsets_length; + unsigned int i; + const unsigned long *string_offsets = NULL; + unsigned long num_strings = 0; + + status = _cairo_truetype_font_create (font_subset, is_pdf, &font); + if (unlikely (status)) + return status; + + for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) { + unsigned short parent_glyph = font->scaled_font_subset->glyphs[i]; + status = cairo_truetype_font_use_glyph (font, parent_glyph, &parent_glyph); + if (unlikely (status)) + goto fail1; + } + + cairo_truetype_font_create_truetype_table_list (font); + status = cairo_truetype_font_generate (font, &data, &length, + &string_offsets, &num_strings); + if (unlikely (status)) + goto fail1; + + truetype_subset->ps_name = strdup (font->base.ps_name); + if (unlikely (truetype_subset->ps_name == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto fail1; + } + + if (font->base.font_name != NULL) { + truetype_subset->family_name_utf8 = strdup (font->base.font_name); + if (unlikely (truetype_subset->family_name_utf8 == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto fail2; + } + } else { + truetype_subset->family_name_utf8 = NULL; + } + + /* The widths array returned must contain only widths for the + * glyphs in font_subset. Any subglyphs appended after + * font_subset->num_glyphs are omitted. */ + truetype_subset->widths = _cairo_calloc_ab (font->scaled_font_subset->num_glyphs, + sizeof (double)); + if (unlikely (truetype_subset->widths == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto fail3; + } + for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) + truetype_subset->widths[i] = (double)font->widths[i]/font->base.units_per_em; + + truetype_subset->x_min = (double)font->base.x_min/font->base.units_per_em; + truetype_subset->y_min = (double)font->base.y_min/font->base.units_per_em; + truetype_subset->x_max = (double)font->base.x_max/font->base.units_per_em; + truetype_subset->y_max = (double)font->base.y_max/font->base.units_per_em; + truetype_subset->ascent = (double)font->base.ascent/font->base.units_per_em; + truetype_subset->descent = (double)font->base.descent/font->base.units_per_em; + + if (length) { + truetype_subset->data = _cairo_malloc (length); + if (unlikely (truetype_subset->data == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto fail4; + } + + memcpy (truetype_subset->data, data, length); + } else + truetype_subset->data = NULL; + truetype_subset->data_length = length; + + if (num_strings) { + offsets_length = num_strings * sizeof (unsigned long); + truetype_subset->string_offsets = _cairo_malloc (offsets_length); + if (unlikely (truetype_subset->string_offsets == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto fail5; + } + + memcpy (truetype_subset->string_offsets, string_offsets, offsets_length); + truetype_subset->num_string_offsets = num_strings; + } else { + truetype_subset->string_offsets = NULL; + truetype_subset->num_string_offsets = 0; + } + + cairo_truetype_font_destroy (font); + + return CAIRO_STATUS_SUCCESS; + + fail5: + free (truetype_subset->data); + fail4: + free (truetype_subset->widths); + fail3: + free (truetype_subset->family_name_utf8); + fail2: + free (truetype_subset->ps_name); + fail1: + cairo_truetype_font_destroy (font); + + return status; +} + +cairo_status_t +_cairo_truetype_subset_init_ps (cairo_truetype_subset_t *truetype_subset, + cairo_scaled_font_subset_t *font_subset) +{ + return cairo_truetype_subset_init_internal (truetype_subset, font_subset, FALSE); +} + +cairo_status_t +_cairo_truetype_subset_init_pdf (cairo_truetype_subset_t *truetype_subset, + cairo_scaled_font_subset_t *font_subset) +{ + return cairo_truetype_subset_init_internal (truetype_subset, font_subset, TRUE); +} + +void +_cairo_truetype_subset_fini (cairo_truetype_subset_t *subset) +{ + free (subset->ps_name); + free (subset->family_name_utf8); + free (subset->widths); + free (subset->data); + free (subset->string_offsets); +} + +static cairo_int_status_t +_cairo_truetype_reverse_cmap (cairo_scaled_font_t *scaled_font, + unsigned long table_offset, + unsigned long index, + uint32_t *ucs4) +{ + cairo_status_t status; + const cairo_scaled_font_backend_t *backend; + tt_segment_map_t *map; + tt_segment_map_t map_header; + unsigned int num_segments, i; + unsigned long size; + uint16_t *start_code; + uint16_t *end_code; + uint16_t *delta; + uint16_t *range_offset; + uint16_t c; + + backend = scaled_font->backend; + size = 4; /* enough to read the two header fields we need */ + status = backend->load_truetype_table (scaled_font, + TT_TAG_cmap, table_offset, + (unsigned char *) &map_header, + &size); + if (unlikely (status)) + return status; + + /* All table formats have the same first two words */ + if (be16_to_cpu (map_header.format) != 4) + return CAIRO_INT_STATUS_UNSUPPORTED; + + size = be16_to_cpu (map_header.length); + /* minimum table size is 24 bytes */ + if (size < 24) + return CAIRO_INT_STATUS_UNSUPPORTED; + + map = _cairo_malloc (size); + if (unlikely (map == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + status = backend->load_truetype_table (scaled_font, + TT_TAG_cmap, table_offset, + (unsigned char *) map, + &size); + if (unlikely (status)) + goto fail; + + num_segments = be16_to_cpu (map->segCountX2)/2; + + /* A Format 4 cmap contains 8 uint16_t numbers and 4 arrays of + * uint16_t each num_segments long. */ + if (size < (8 + 4*num_segments)*sizeof(uint16_t)) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto fail; + } + + end_code = map->endCount; + start_code = &(end_code[num_segments + 1]); + delta = &(start_code[num_segments]); + range_offset = &(delta[num_segments]); + + /* search for glyph in segments with rangeOffset=0 */ + for (i = 0; i < num_segments; i++) { + uint16_t start = be16_to_cpu (start_code[i]); + uint16_t end = be16_to_cpu (end_code[i]); + + if (start == 0xffff && end == 0xffff) + break; + + c = index - be16_to_cpu (delta[i]); + if (range_offset[i] == 0 && c >= start && c <= end) { + *ucs4 = c; + goto found; + } + } + + /* search for glyph in segments with rangeOffset=1 */ + for (i = 0; i < num_segments; i++) { + uint16_t start = be16_to_cpu (start_code[i]); + uint16_t end = be16_to_cpu (end_code[i]); + + if (start == 0xffff && end == 0xffff) + break; + + if (range_offset[i] != 0) { + uint16_t *glyph_ids = &range_offset[i] + be16_to_cpu (range_offset[i])/2; + int range_size = end - start + 1; + uint16_t g_id_be = cpu_to_be16 (index); + int j; + + if (range_size > 0) { + if ((char*)glyph_ids + 2*range_size > (char*)map + size) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto fail; + } + + for (j = 0; j < range_size; j++) { + if (glyph_ids[j] == g_id_be) { + *ucs4 = start + j; + goto found; + } + } + } + } + } + + /* glyph not found */ + *ucs4 = -1; + +found: + status = CAIRO_STATUS_SUCCESS; + +fail: + free (map); + + return status; +} + +cairo_int_status_t +_cairo_truetype_index_to_ucs4 (cairo_scaled_font_t *scaled_font, + unsigned long index, + uint32_t *ucs4) +{ + cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED; + const cairo_scaled_font_backend_t *backend; + tt_cmap_t *cmap; + tt_cmap_t cmap_header; + int num_tables, i; + unsigned long size; + + backend = scaled_font->backend; + if (!backend->load_truetype_table) + return CAIRO_INT_STATUS_UNSUPPORTED; + + size = 4; /* only read the header fields 'version' and 'num_tables' */ + status = backend->load_truetype_table (scaled_font, + TT_TAG_cmap, 0, + (unsigned char *) &cmap_header, + &size); + if (unlikely (status)) + return status; + + num_tables = be16_to_cpu (cmap_header.num_tables); + size = 4 + num_tables * sizeof (tt_cmap_index_t); + cmap = _cairo_malloc_ab_plus_c (num_tables, sizeof (tt_cmap_index_t), 4); + if (unlikely (cmap == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + status = backend->load_truetype_table (scaled_font, + TT_TAG_cmap, 0, + (unsigned char *) cmap, + &size); + if (unlikely (status)) + goto cleanup; + + /* Find a table with Unicode mapping */ + for (i = 0; i < num_tables; i++) { + if (be16_to_cpu (cmap->index[i].platform) == 3 && + be16_to_cpu (cmap->index[i].encoding) == 1) { + status = _cairo_truetype_reverse_cmap (scaled_font, + be32_to_cpu (cmap->index[i].offset), + index, + ucs4); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + break; + } + } + +cleanup: + free (cmap); + + return status; +} + +/* + * Sanity check on font name length as some broken fonts may return very long + * strings of garbage. 127 is maximum length of a PS name. + */ +#define MAX_FONT_NAME_LENGTH 127 + +static cairo_status_t +find_name (tt_name_t *name, unsigned long size, int name_id, int platform, int encoding, int language, char **str_out) +{ + tt_name_record_t *record; + unsigned int i, len; + char *str; + char *p; + cairo_bool_t has_tag; + cairo_status_t status; + + str = NULL; + for (i = 0; i < MIN(be16_to_cpu (name->num_records), size / sizeof(name->records[0])); i++) { + record = &(name->records[i]); + if (be16_to_cpu (record->name) == name_id && + be16_to_cpu (record->platform) == platform && + be16_to_cpu (record->encoding) == encoding && + (language == -1 || be16_to_cpu (record->language) == language)) { + + len = be16_to_cpu (record->length); + if (platform == 3 && len > MAX_FONT_NAME_LENGTH*2) /* UTF-16 name */ + break; + + if (len > MAX_FONT_NAME_LENGTH) + break; + + uint16_t offset = be16_to_cpu (name->strings_offset) + be16_to_cpu (record->offset); + if (offset + len > size) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + str = _cairo_malloc (len + 1); + if (str == NULL) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + memcpy (str, + ((char*)name) + offset, + len); + str[len] = 0; + break; + } + } + if (str == NULL) { + *str_out = NULL; + return CAIRO_STATUS_SUCCESS; + } + + if (platform == 3) { /* Win platform, unicode encoding */ + /* convert to utf8 */ + int size = 0; + char *utf8; + uint16_t *u = (uint16_t *) str; + unsigned int u_len = len/2; + + for (i = 0; i < u_len; i++) + size += _cairo_ucs4_to_utf8 (be16_to_cpu(u[i]), NULL); + + utf8 = _cairo_malloc (size + 1); + if (utf8 == NULL) { + status =_cairo_error (CAIRO_STATUS_NO_MEMORY); + goto fail; + } + p = utf8; + for (i = 0; i < u_len; i++) + p += _cairo_ucs4_to_utf8 (be16_to_cpu(u[i]), p); + *p = 0; + free (str); + str = utf8; + } else if (platform == 1) { /* Mac platform, Mac Roman encoding */ + /* Replace characters above 127 with underscores. We could use + * a lookup table to convert to unicode but since most fonts + * include a unicode name this is just a rarely used fallback. */ + for (i = 0; i < len; i++) { + if ((unsigned char)str[i] > 127) + str[i] = '_'; + } + } + + /* If font name is prefixed with a PDF subset tag, strip it off. */ + p = str; + len = strlen (str); + has_tag = FALSE; + if (len > 7 && p[6] == '+') { + has_tag = TRUE; + for (i = 0; i < 6; i++) { + if (p[i] < 'A' || p[i] > 'Z') { + has_tag = FALSE; + break; + } + } + } + if (has_tag) { + p = _cairo_strndup (str + 7, len - 7); + free (str); + str = p; + } + + *str_out = str; + + return CAIRO_STATUS_SUCCESS; + + fail: + free (str); + + return status; +} + +cairo_int_status_t +_cairo_truetype_read_font_name (cairo_scaled_font_t *scaled_font, + char **ps_name_out, + char **font_name_out) +{ + cairo_status_t status; + const cairo_scaled_font_backend_t *backend; + tt_name_t *name; + unsigned long size; + char *ps_name = NULL; + char *family_name = NULL; + + backend = scaled_font->backend; + if (!backend->load_truetype_table) + return CAIRO_INT_STATUS_UNSUPPORTED; + + size = 0; + status = backend->load_truetype_table (scaled_font, + TT_TAG_name, 0, + NULL, + &size); + if (status) + return status; + + name = _cairo_malloc (size); + if (name == NULL) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + status = backend->load_truetype_table (scaled_font, + TT_TAG_name, 0, + (unsigned char *) name, + &size); + if (status) + goto fail; + + /* Find PS Name (name_id = 6). OT spec says PS name must be one of + * the following two encodings */ + status = find_name (name, size, 6, 3, 1, 0x409, &ps_name); /* win, unicode, english-us */ + if (unlikely(status)) + goto fail; + + if (!ps_name) { + status = find_name (name, size, 6, 1, 0, 0, &ps_name); /* mac, roman, english */ + if (unlikely(status)) + goto fail; + } + + /* Find Family name (name_id = 1) */ + status = find_name (name, size, 1, 3, 1, 0x409, &family_name); /* win, unicode, english-us */ + if (unlikely(status)) + goto fail; + + if (!family_name) { + status = find_name (name, size, 1, 3, 0, 0x409, &family_name); /* win, symbol, english-us */ + if (unlikely(status)) + goto fail; + } + + if (!family_name) { + status = find_name (name, size, 1, 1, 0, 0, &family_name); /* mac, roman, english */ + if (unlikely(status)) + goto fail; + } + + if (!family_name) { + status = find_name (name, size, 1, 3, 1, -1, &family_name); /* win, unicode, any language */ + if (unlikely(status)) + goto fail; + } + + status = _cairo_escape_ps_name (&ps_name); + if (unlikely(status)) + goto fail; + + free (name); + + *ps_name_out = ps_name; + *font_name_out = family_name; + + return CAIRO_STATUS_SUCCESS; + +fail: + free (name); + free (ps_name); + free (family_name); + *ps_name_out = NULL; + *font_name_out = NULL; + + return status; +} + +cairo_int_status_t +_cairo_truetype_get_style (cairo_scaled_font_t *scaled_font, + int *weight, + cairo_bool_t *bold, + cairo_bool_t *italic) +{ + cairo_status_t status; + const cairo_scaled_font_backend_t *backend; + tt_os2_t os2; + unsigned long size; + uint16_t selection; + + backend = scaled_font->backend; + if (!backend->load_truetype_table) + return CAIRO_INT_STATUS_UNSUPPORTED; + + size = 0; + status = backend->load_truetype_table (scaled_font, + TT_TAG_OS2, 0, + NULL, + &size); + if (status) + return status; + + if (size < sizeof(os2)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + size = sizeof (os2); + status = backend->load_truetype_table (scaled_font, + TT_TAG_OS2, 0, + (unsigned char *) &os2, + &size); + if (status) + return status; + + *weight = be16_to_cpu (os2.usWeightClass); + selection = be16_to_cpu (os2.fsSelection); + *bold = (selection & TT_FS_SELECTION_BOLD) ? TRUE : FALSE; + *italic = (selection & TT_FS_SELECTION_ITALIC) ? TRUE : FALSE; + + return CAIRO_STATUS_SUCCESS; +} + +#endif /* CAIRO_HAS_FONT_SUBSET */ diff --git a/local/recipes/libs/cairo/source/src/cairo-type1-fallback.c b/local/recipes/libs/cairo/source/src/cairo-type1-fallback.c new file mode 100644 index 0000000000..d0bbc62f0f --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-type1-fallback.c @@ -0,0 +1,908 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2006 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Adrian Johnson + */ + +#define _DEFAULT_SOURCE /* for snprintf(), strdup() */ +#include "cairoint.h" + +#include "cairo-array-private.h" +#include "cairo-error-private.h" + +#if CAIRO_HAS_FONT_SUBSET + +#include "cairo-type1-private.h" +#include "cairo-scaled-font-subsets-private.h" +#include "cairo-path-fixed-private.h" +#include "cairo-output-stream-private.h" + +typedef enum { + CAIRO_CHARSTRING_TYPE1, + CAIRO_CHARSTRING_TYPE2 +} cairo_charstring_type_t; + +typedef struct _cairo_type1_font { + int *widths; + + cairo_scaled_font_subset_t *scaled_font_subset; + cairo_scaled_font_t *type1_scaled_font; + + cairo_array_t contents; + + double x_min, y_min, x_max, y_max; + + const char *data; + unsigned long header_size; + unsigned long data_size; + unsigned long trailer_size; + int bbox_position; + int bbox_max_chars; + + cairo_output_stream_t *output; + + unsigned short eexec_key; + cairo_bool_t hex_encode; + int hex_column; +} cairo_type1_font_t; + +static cairo_status_t +cairo_type1_font_create (cairo_scaled_font_subset_t *scaled_font_subset, + cairo_type1_font_t **subset_return, + cairo_bool_t hex_encode) +{ + cairo_type1_font_t *font; + cairo_font_face_t *font_face; + cairo_matrix_t font_matrix; + cairo_matrix_t ctm; + cairo_font_options_t font_options; + cairo_status_t status; + + font = _cairo_calloc (sizeof (cairo_type1_font_t)); + if (unlikely (font == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + font->widths = _cairo_calloc_ab (scaled_font_subset->num_glyphs, sizeof (int)); + if (unlikely (font->widths == NULL)) { + free (font); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + font->scaled_font_subset = scaled_font_subset; + font->hex_encode = hex_encode; + + font_face = cairo_scaled_font_get_font_face (scaled_font_subset->scaled_font); + + cairo_matrix_init_scale (&font_matrix, 1000, -1000); + cairo_matrix_init_identity (&ctm); + + _cairo_font_options_init_default (&font_options); + cairo_scaled_font_get_font_options (scaled_font_subset->scaled_font, &font_options); + cairo_font_options_set_hint_style (&font_options, CAIRO_HINT_STYLE_NONE); + cairo_font_options_set_hint_metrics (&font_options, CAIRO_HINT_METRICS_OFF); + + font->type1_scaled_font = cairo_scaled_font_create (font_face, + &font_matrix, + &ctm, + &font_options); + status = font->type1_scaled_font->status; + if (unlikely (status)) + goto fail; + + _cairo_array_init (&font->contents, sizeof (unsigned char)); + font->output = NULL; + + *subset_return = font; + + return CAIRO_STATUS_SUCCESS; + +fail: + free (font->widths); + free (font); + + return status; +} + +/* Charstring commands. If the high byte is 0 the command is encoded + * with a single byte. */ +#define CHARSTRING_sbw 0x0c07 +#define CHARSTRING_rmoveto 0x0015 +#define CHARSTRING_rlineto 0x0005 +#define CHARSTRING_rcurveto 0x0008 +#define CHARSTRING_closepath 0x0009 +#define CHARSTRING_endchar 0x000e + +/* Before calling this function, the caller must allocate sufficient + * space in data (see _cairo_array_grow_by). The maximum number of + * bytes that will be used is 2. + */ +static void +charstring_encode_command (cairo_array_t *data, int command) +{ + cairo_status_t status; + unsigned int orig_size; + unsigned char buf[5]; + unsigned char *p = buf; + + if (command & 0xff00) + *p++ = command >> 8; + *p++ = command & 0x00ff; + + /* Ensure the array doesn't grow, which allows this function to + * have no possibility of failure. */ + orig_size = _cairo_array_size (data); + status = _cairo_array_append_multiple (data, buf, p - buf); + + assert (status == CAIRO_STATUS_SUCCESS); + assert (_cairo_array_size (data) == orig_size); +} + +/* Before calling this function, the caller must allocate sufficient + * space in data (see _cairo_array_grow_by). The maximum number of + * bytes that will be used is 5. + */ +static void +charstring_encode_integer (cairo_array_t *data, + int i, + cairo_charstring_type_t type) +{ + cairo_status_t status; + unsigned int orig_size; + unsigned char buf[10]; + unsigned char *p = buf; + + if (i >= -107 && i <= 107) { + *p++ = i + 139; + } else if (i >= 108 && i <= 1131) { + i -= 108; + *p++ = (i >> 8)+ 247; + *p++ = i & 0xff; + } else if (i >= -1131 && i <= -108) { + i = -i - 108; + *p++ = (i >> 8)+ 251; + *p++ = i & 0xff; + } else { + if (type == CAIRO_CHARSTRING_TYPE1) { + *p++ = 0xff; + *p++ = i >> 24; + *p++ = (i >> 16) & 0xff; + *p++ = (i >> 8) & 0xff; + *p++ = i & 0xff; + } else { + *p++ = 0xff; + *p++ = (i >> 8) & 0xff; + *p++ = i & 0xff; + *p++ = 0; + *p++ = 0; + } + } + + /* Ensure the array doesn't grow, which allows this function to + * have no possibility of failure. */ + orig_size = _cairo_array_size (data); + status = _cairo_array_append_multiple (data, buf, p - buf); + + assert (status == CAIRO_STATUS_SUCCESS); + assert (_cairo_array_size (data) == orig_size); +} + +typedef struct _ps_path_info { + cairo_array_t *data; + int current_x, current_y; + cairo_charstring_type_t type; +} t1_path_info_t; + +static cairo_status_t +_charstring_move_to (void *closure, + const cairo_point_t *point) +{ + t1_path_info_t *path_info = (t1_path_info_t *) closure; + int dx, dy; + cairo_status_t status; + + status = _cairo_array_grow_by (path_info->data, 12); + if (unlikely (status)) + return status; + + dx = _cairo_fixed_integer_part (point->x) - path_info->current_x; + dy = _cairo_fixed_integer_part (point->y) - path_info->current_y; + charstring_encode_integer (path_info->data, dx, path_info->type); + charstring_encode_integer (path_info->data, dy, path_info->type); + path_info->current_x += dx; + path_info->current_y += dy; + + charstring_encode_command (path_info->data, CHARSTRING_rmoveto); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_charstring_line_to (void *closure, + const cairo_point_t *point) +{ + t1_path_info_t *path_info = (t1_path_info_t *) closure; + int dx, dy; + cairo_status_t status; + + status = _cairo_array_grow_by (path_info->data, 12); + if (unlikely (status)) + return status; + + dx = _cairo_fixed_integer_part (point->x) - path_info->current_x; + dy = _cairo_fixed_integer_part (point->y) - path_info->current_y; + charstring_encode_integer (path_info->data, dx, path_info->type); + charstring_encode_integer (path_info->data, dy, path_info->type); + path_info->current_x += dx; + path_info->current_y += dy; + + charstring_encode_command (path_info->data, CHARSTRING_rlineto); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_charstring_curve_to (void *closure, + const cairo_point_t *point1, + const cairo_point_t *point2, + const cairo_point_t *point3) +{ + t1_path_info_t *path_info = (t1_path_info_t *) closure; + int dx1, dy1, dx2, dy2, dx3, dy3; + cairo_status_t status; + + status = _cairo_array_grow_by (path_info->data, 32); + if (unlikely (status)) + return status; + + dx1 = _cairo_fixed_integer_part (point1->x) - path_info->current_x; + dy1 = _cairo_fixed_integer_part (point1->y) - path_info->current_y; + dx2 = _cairo_fixed_integer_part (point2->x) - path_info->current_x - dx1; + dy2 = _cairo_fixed_integer_part (point2->y) - path_info->current_y - dy1; + dx3 = _cairo_fixed_integer_part (point3->x) - path_info->current_x - dx1 - dx2; + dy3 = _cairo_fixed_integer_part (point3->y) - path_info->current_y - dy1 - dy2; + charstring_encode_integer (path_info->data, dx1, path_info->type); + charstring_encode_integer (path_info->data, dy1, path_info->type); + charstring_encode_integer (path_info->data, dx2, path_info->type); + charstring_encode_integer (path_info->data, dy2, path_info->type); + charstring_encode_integer (path_info->data, dx3, path_info->type); + charstring_encode_integer (path_info->data, dy3, path_info->type); + path_info->current_x += dx1 + dx2 + dx3; + path_info->current_y += dy1 + dy2 + dy3; + charstring_encode_command (path_info->data, CHARSTRING_rcurveto); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_charstring_close_path (void *closure) +{ + cairo_status_t status; + t1_path_info_t *path_info = (t1_path_info_t *) closure; + + if (path_info->type == CAIRO_CHARSTRING_TYPE2) + return CAIRO_STATUS_SUCCESS; + + status = _cairo_array_grow_by (path_info->data, 2); + if (unlikely (status)) + return status; + + charstring_encode_command (path_info->data, CHARSTRING_closepath); + + return CAIRO_STATUS_SUCCESS; +} + +static void +charstring_encrypt (cairo_array_t *data) +{ + unsigned char *d, *end; + uint16_t c, p, r; + + r = CAIRO_TYPE1_CHARSTRING_KEY; + d = (unsigned char *) _cairo_array_index (data, 0); + end = d + _cairo_array_num_elements (data); + while (d < end) { + p = *d; + c = p ^ (r >> 8); + r = (c + r) * CAIRO_TYPE1_ENCRYPT_C1 + CAIRO_TYPE1_ENCRYPT_C2; + *d++ = c; + } +} + +static cairo_int_status_t +cairo_type1_font_create_charstring (cairo_type1_font_t *font, + int subset_index, + int glyph_index, + cairo_charstring_type_t type, + cairo_array_t *data) +{ + cairo_int_status_t status; + cairo_scaled_glyph_t *scaled_glyph; + t1_path_info_t path_info; + cairo_text_extents_t *metrics; + cairo_bool_t emit_path = TRUE; + + /* This call may return CAIRO_INT_STATUS_UNSUPPORTED for bitmap fonts. */ + status = _cairo_scaled_glyph_lookup (font->type1_scaled_font, + glyph_index, + CAIRO_SCALED_GLYPH_INFO_METRICS| + CAIRO_SCALED_GLYPH_INFO_PATH, + NULL, /* foreground color */ + &scaled_glyph); + + /* It is ok for the .notdef glyph to not have a path available. We + * just need the metrics to emit an empty glyph. */ + if (glyph_index == 0 && status == CAIRO_INT_STATUS_UNSUPPORTED) { + emit_path = FALSE; + status = _cairo_scaled_glyph_lookup (font->type1_scaled_font, + glyph_index, + CAIRO_SCALED_GLYPH_INFO_METRICS, + NULL, /* foreground color */ + &scaled_glyph); + } + if (unlikely (status)) + return status; + + metrics = &scaled_glyph->metrics; + if (subset_index == 0) { + font->x_min = metrics->x_bearing; + font->y_min = metrics->y_bearing; + font->x_max = metrics->x_bearing + metrics->width; + font->y_max = metrics->y_bearing + metrics->height; + } else { + if (metrics->x_bearing < font->x_min) + font->x_min = metrics->x_bearing; + if (metrics->y_bearing < font->y_min) + font->y_min = metrics->y_bearing; + if (metrics->x_bearing + metrics->width > font->x_max) + font->x_max = metrics->x_bearing + metrics->width; + if (metrics->y_bearing + metrics->height > font->y_max) + font->y_max = metrics->y_bearing + metrics->height; + } + font->widths[subset_index] = metrics->x_advance; + + status = _cairo_array_grow_by (data, 30); + if (unlikely (status)) + return status; + + if (type == CAIRO_CHARSTRING_TYPE1) { + charstring_encode_integer (data, (int) scaled_glyph->metrics.x_bearing, type); + charstring_encode_integer (data, (int) scaled_glyph->metrics.y_bearing, type); + charstring_encode_integer (data, (int) scaled_glyph->metrics.x_advance, type); + charstring_encode_integer (data, (int) scaled_glyph->metrics.y_advance, type); + charstring_encode_command (data, CHARSTRING_sbw); + + path_info.current_x = (int) scaled_glyph->metrics.x_bearing; + path_info.current_y = (int) scaled_glyph->metrics.y_bearing; + } else { + charstring_encode_integer (data, (int) scaled_glyph->metrics.x_advance, type); + + path_info.current_x = 0; + path_info.current_y = 0; + } + path_info.data = data; + path_info.type = type; + if (emit_path) { + status = _cairo_path_fixed_interpret (scaled_glyph->path, + _charstring_move_to, + _charstring_line_to, + _charstring_curve_to, + _charstring_close_path, + &path_info); + if (unlikely (status)) + return status; + } + + status = _cairo_array_grow_by (data, 1); + if (unlikely (status)) + return status; + charstring_encode_command (path_info.data, CHARSTRING_endchar); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +cairo_type1_font_write_charstrings (cairo_type1_font_t *font, + cairo_output_stream_t *encrypted_output) +{ + cairo_status_t status; + unsigned char zeros[] = { 0, 0, 0, 0 }; + cairo_array_t data; + unsigned int i; + int length; + + _cairo_array_init (&data, sizeof (unsigned char)); + status = _cairo_array_grow_by (&data, 1024); + if (unlikely (status)) + goto fail; + + _cairo_output_stream_printf (encrypted_output, + "2 index /CharStrings %d dict dup begin\n", + font->scaled_font_subset->num_glyphs + 1); + + _cairo_scaled_font_freeze_cache (font->type1_scaled_font); + for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) { + _cairo_array_truncate (&data, 0); + /* four "random" bytes required by encryption algorithm */ + status = _cairo_array_append_multiple (&data, zeros, 4); + if (unlikely (status)) + break; + + status = cairo_type1_font_create_charstring (font, i, + font->scaled_font_subset->glyphs[i], + CAIRO_CHARSTRING_TYPE1, + &data); + if (unlikely (status)) + break; + + charstring_encrypt (&data); + length = _cairo_array_num_elements (&data); + if (font->scaled_font_subset->glyph_names != NULL) { + _cairo_output_stream_printf (encrypted_output, "/%s %d RD ", + font->scaled_font_subset->glyph_names[i], + length); + } else if (i == 0) { + _cairo_output_stream_printf (encrypted_output, "/.notdef %d RD ", length); + } else { + _cairo_output_stream_printf (encrypted_output, "/g%d %d RD ", i, length); + } + _cairo_output_stream_write (encrypted_output, + _cairo_array_index (&data, 0), + length); + _cairo_output_stream_printf (encrypted_output, " ND\n"); + } + _cairo_scaled_font_thaw_cache (font->type1_scaled_font); + +fail: + _cairo_array_fini (&data); + return status; +} + +static void +cairo_type1_font_write_header (cairo_type1_font_t *font, + const char *name) +{ + unsigned int i; + const char spaces[50] = " "; + + _cairo_output_stream_printf (font->output, + "%%!FontType1-1.1 %s 1.0\n" + "11 dict begin\n" + "/FontName /%s def\n" + "/PaintType 0 def\n" + "/FontType 1 def\n" + "/FontMatrix [0.001 0 0 0.001 0 0] readonly def\n", + name, + name); + + /* We don't know the bbox values until after the charstrings have + * been generated. Reserve some space and fill in the bbox + * later. */ + + /* Worst case for four signed ints with spaces between each number */ + font->bbox_max_chars = 50; + + _cairo_output_stream_printf (font->output, "/FontBBox {"); + font->bbox_position = _cairo_output_stream_get_position (font->output); + _cairo_output_stream_write (font->output, spaces, font->bbox_max_chars); + + _cairo_output_stream_printf (font->output, + "} readonly def\n" + "/Encoding 256 array\n" + "0 1 255 {1 index exch /.notdef put} for\n"); + if (font->scaled_font_subset->is_latin) { + for (i = 1; i < 256; i++) { + int subset_glyph = font->scaled_font_subset->latin_to_subset_glyph_index[i]; + + if (subset_glyph > 0) { + if (font->scaled_font_subset->glyph_names != NULL) { + _cairo_output_stream_printf (font->output, "dup %d /%s put\n", + i, font->scaled_font_subset->glyph_names[subset_glyph]); + } else { + _cairo_output_stream_printf (font->output, "dup %d /g%d put\n", i, subset_glyph); + } + } + } + } else { + for (i = 1; i < font->scaled_font_subset->num_glyphs; i++) { + if (font->scaled_font_subset->glyph_names != NULL) { + _cairo_output_stream_printf (font->output, "dup %d /%s put\n", + i, font->scaled_font_subset->glyph_names[i]); + } else { + _cairo_output_stream_printf (font->output, "dup %d /g%d put\n", i, i); + } + } + } + _cairo_output_stream_printf (font->output, + "readonly def\n" + "currentdict end\n" + "currentfile eexec\n"); +} + +static cairo_status_t +cairo_type1_write_stream_encrypted (void *closure, + const unsigned char *data, + unsigned int length) +{ + const unsigned char *in, *end; + uint16_t c, p; + static const char hex_digits[16] = "0123456789abcdef"; + char digits[3]; + cairo_type1_font_t *font = closure; + + in = (const unsigned char *) data; + end = (const unsigned char *) data + length; + while (in < end) { + p = *in++; + c = p ^ (font->eexec_key >> 8); + font->eexec_key = (c + font->eexec_key) * CAIRO_TYPE1_ENCRYPT_C1 + CAIRO_TYPE1_ENCRYPT_C2; + + if (font->hex_encode) { + digits[0] = hex_digits[c >> 4]; + digits[1] = hex_digits[c & 0x0f]; + digits[2] = '\n'; + font->hex_column += 2; + + if (font->hex_column == 78) { + _cairo_output_stream_write (font->output, digits, 3); + font->hex_column = 0; + } else { + _cairo_output_stream_write (font->output, digits, 2); + } + } else { + digits[0] = c; + _cairo_output_stream_write (font->output, digits, 1); + } + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +cairo_type1_font_write_private_dict (cairo_type1_font_t *font, + const char *name) +{ + cairo_int_status_t status; + cairo_status_t status2; + cairo_output_stream_t *encrypted_output; + + font->eexec_key = CAIRO_TYPE1_PRIVATE_DICT_KEY; + font->hex_column = 0; + encrypted_output = _cairo_output_stream_create ( + cairo_type1_write_stream_encrypted, + NULL, + font); + if (_cairo_output_stream_get_status (encrypted_output)) + return _cairo_output_stream_destroy (encrypted_output); + + /* Note: the first four spaces at the start of this private dict + * are the four "random" bytes of plaintext required by the + * encryption algorithm */ + _cairo_output_stream_printf (encrypted_output, + " dup /Private 9 dict dup begin\n" + "/RD {string currentfile exch readstring pop}" + " bind executeonly def\n" + "/ND {noaccess def} executeonly def\n" + "/NP {noaccess put} executeonly def\n" + "/BlueValues [] def\n" + "/MinFeature {16 16} def\n" + "/lenIV 4 def\n" + "/password 5839 def\n"); + + status = cairo_type1_font_write_charstrings (font, encrypted_output); + if (unlikely (status)) + goto fail; + + _cairo_output_stream_printf (encrypted_output, + "end\n" + "end\n" + "readonly put\n" + "noaccess put\n" + "dup /FontName get exch definefont pop\n" + "mark currentfile closefile\n"); + + fail: + status2 = _cairo_output_stream_destroy (encrypted_output); + if (status == CAIRO_INT_STATUS_SUCCESS) + status = status2; + + return status; +} + +static void +cairo_type1_font_write_trailer(cairo_type1_font_t *font) +{ + int i; + static const char zeros[65] = + "0000000000000000000000000000000000000000000000000000000000000000\n"; + + for (i = 0; i < 8; i++) + _cairo_output_stream_write (font->output, zeros, sizeof zeros); + + _cairo_output_stream_printf (font->output, "cleartomark\n"); +} + +static cairo_status_t +cairo_type1_write_stream (void *closure, + const unsigned char *data, + unsigned int length) +{ + cairo_type1_font_t *font = closure; + + return _cairo_array_append_multiple (&font->contents, data, length); +} + +static cairo_int_status_t +cairo_type1_font_write (cairo_type1_font_t *font, + const char *name) +{ + cairo_int_status_t status; + + cairo_type1_font_write_header (font, name); + font->header_size = _cairo_output_stream_get_position (font->output); + + status = cairo_type1_font_write_private_dict (font, name); + if (unlikely (status)) + return status; + + font->data_size = _cairo_output_stream_get_position (font->output) - + font->header_size; + + cairo_type1_font_write_trailer (font); + font->trailer_size = + _cairo_output_stream_get_position (font->output) - + font->header_size - font->data_size; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +cairo_type1_font_generate (cairo_type1_font_t *font, const char *name) +{ + cairo_int_status_t status; + + status = _cairo_array_grow_by (&font->contents, 4096); + if (unlikely (status)) + return status; + + font->output = _cairo_output_stream_create (cairo_type1_write_stream, NULL, font); + if (_cairo_output_stream_get_status (font->output)) + return _cairo_output_stream_destroy (font->output); + + status = cairo_type1_font_write (font, name); + if (unlikely (status)) + return status; + + font->data = _cairo_array_index (&font->contents, 0); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +cairo_type1_font_destroy (cairo_type1_font_t *font) +{ + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + free (font->widths); + cairo_scaled_font_destroy (font->type1_scaled_font); + _cairo_array_fini (&font->contents); + if (font->output) + status = _cairo_output_stream_destroy (font->output); + free (font); + + return status; +} + +static cairo_status_t +_cairo_type1_fallback_init_internal (cairo_type1_subset_t *type1_subset, + const char *name, + cairo_scaled_font_subset_t *scaled_font_subset, + cairo_bool_t hex_encode) +{ + cairo_type1_font_t *font; + cairo_status_t status; + unsigned long length; + unsigned int i, len; + + status = cairo_type1_font_create (scaled_font_subset, &font, hex_encode); + if (unlikely (status)) + return status; + + status = cairo_type1_font_generate (font, name); + if (unlikely (status)) + goto fail1; + + type1_subset->base_font = strdup (name); + if (unlikely (type1_subset->base_font == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto fail1; + } + + type1_subset->widths = _cairo_calloc_ab (font->scaled_font_subset->num_glyphs, + sizeof (double)); + if (unlikely (type1_subset->widths == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto fail2; + } + for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) + type1_subset->widths[i] = (double)font->widths[i]/1000; + + type1_subset->x_min = (double)font->x_min/1000; + type1_subset->y_min = (double)font->y_min/1000; + type1_subset->x_max = (double)font->x_max/1000; + type1_subset->y_max = (double)font->y_max/1000; + type1_subset->ascent = (double)font->y_max/1000; + type1_subset->descent = (double)font->y_min/1000; + + length = font->header_size + font->data_size + + font->trailer_size; + type1_subset->data = _cairo_malloc (length); + if (unlikely (type1_subset->data == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto fail3; + } + memcpy (type1_subset->data, + _cairo_array_index (&font->contents, 0), length); + + len = snprintf(type1_subset->data + font->bbox_position, + font->bbox_max_chars, + "%d %d %d %d", + (int)font->x_min, + (int)font->y_min, + (int)font->x_max, + (int)font->y_max); + type1_subset->data[font->bbox_position + len] = ' '; + + type1_subset->header_length = font->header_size; + type1_subset->data_length = font->data_size; + type1_subset->trailer_length = font->trailer_size; + + return cairo_type1_font_destroy (font); + + fail3: + free (type1_subset->widths); + fail2: + free (type1_subset->base_font); + fail1: + /* status is already set, ignore further errors */ + cairo_type1_font_destroy (font); + + return status; +} + +cairo_status_t +_cairo_type1_fallback_init_binary (cairo_type1_subset_t *type1_subset, + const char *name, + cairo_scaled_font_subset_t *scaled_font_subset) +{ + return _cairo_type1_fallback_init_internal (type1_subset, + name, + scaled_font_subset, FALSE); +} + +cairo_status_t +_cairo_type1_fallback_init_hex (cairo_type1_subset_t *type1_subset, + const char *name, + cairo_scaled_font_subset_t *scaled_font_subset) +{ + return _cairo_type1_fallback_init_internal (type1_subset, + name, + scaled_font_subset, TRUE); +} + +void +_cairo_type1_fallback_fini (cairo_type1_subset_t *subset) +{ + free (subset->base_font); + free (subset->widths); + free (subset->data); +} + +cairo_status_t +_cairo_type2_charstrings_init (cairo_type2_charstrings_t *type2_subset, + cairo_scaled_font_subset_t *scaled_font_subset) +{ + cairo_type1_font_t *font; + cairo_status_t status; + unsigned int i; + cairo_array_t charstring; + + status = cairo_type1_font_create (scaled_font_subset, &font, FALSE); + if (unlikely (status)) + return status; + + _cairo_array_init (&type2_subset->charstrings, sizeof (cairo_array_t)); + + type2_subset->widths = _cairo_calloc_ab (font->scaled_font_subset->num_glyphs, sizeof (int)); + if (unlikely (type2_subset->widths == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto fail1; + } + + _cairo_scaled_font_freeze_cache (font->type1_scaled_font); + for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) { + _cairo_array_init (&charstring, sizeof (unsigned char)); + status = _cairo_array_grow_by (&charstring, 32); + if (unlikely (status)) + goto fail2; + + status = cairo_type1_font_create_charstring (font, i, + font->scaled_font_subset->glyphs[i], + CAIRO_CHARSTRING_TYPE2, + &charstring); + if (unlikely (status)) + goto fail2; + + status = _cairo_array_append (&type2_subset->charstrings, &charstring); + if (unlikely (status)) + goto fail2; + } + _cairo_scaled_font_thaw_cache (font->type1_scaled_font); + + for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) + type2_subset->widths[i] = font->widths[i]; + + type2_subset->x_min = (int) font->x_min; + type2_subset->y_min = (int) font->y_min; + type2_subset->x_max = (int) font->x_max; + type2_subset->y_max = (int) font->y_max; + type2_subset->ascent = (int) font->y_max; + type2_subset->descent = (int) font->y_min; + + return cairo_type1_font_destroy (font); + +fail2: + _cairo_scaled_font_thaw_cache (font->type1_scaled_font); + _cairo_array_fini (&charstring); + _cairo_type2_charstrings_fini (type2_subset); +fail1: + cairo_type1_font_destroy (font); + return status; +} + +void +_cairo_type2_charstrings_fini (cairo_type2_charstrings_t *type2_subset) +{ + unsigned int i, num_charstrings; + cairo_array_t *charstring; + + num_charstrings = _cairo_array_num_elements (&type2_subset->charstrings); + for (i = 0; i < num_charstrings; i++) { + charstring = _cairo_array_index (&type2_subset->charstrings, i); + _cairo_array_fini (charstring); + } + _cairo_array_fini (&type2_subset->charstrings); + + free (type2_subset->widths); +} + +#endif /* CAIRO_HAS_FONT_SUBSET */ diff --git a/local/recipes/libs/cairo/source/src/cairo-type1-glyph-names.c b/local/recipes/libs/cairo/source/src/cairo-type1-glyph-names.c new file mode 100644 index 0000000000..80ccb96269 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-type1-glyph-names.c @@ -0,0 +1,410 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2006 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Kristian Høgsberg + */ + +#include "cairoint.h" + +#if CAIRO_HAS_FONT_SUBSET + +#include "cairo-type1-private.h" +#include "cairo-scaled-font-subsets-private.h" + +#if 0 +/* + * The three tables that follow are generated using this perl code: + */ + +@ps_standard_encoding = ( + # 0 + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + # 16 + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + # 32 + "space", "exclam", "quotedbl", "numbersign", + "dollar", "percent", "ampersand", "quoteright", + "parenleft", "parenright", "asterisk", "plus", + "comma", "hyphen", "period", "slash", + # 48 + "zero", "one", "two", "three", + "four", "five", "six", "seven", + "eight", "nine", "colon", "semicolon", + "less", "equal", "greater", "question", + # 64 + "at", "A", "B", "C", + "D", "E", "F", "G", + "H", "I", "J", "K", + "L", "M", "N", "O", + # 80 + "P", "Q", "R", "S", + "T", "U", "V", "W", + "X", "Y", "Z", "bracketleft", + "backslash", "bracketright", "asciicircum", "underscore", + # 96 + "quoteleft", "a", "b", "c", + "d", "e", "f", "g", + "h", "i", "j", "k", + "l", "m", "n", "o", + # 112 + "p", "q", "r", "s", + "t", "u", "v", "w", + "x", "y", "z", "braceleft", + "bar", "braceright", "asciitilde", NULL, + # 128 + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + # 144 + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + # 160 + NULL, "exclamdown", "cent", "sterling", + "fraction", "yen", "florin", "section", + "currency", "quotesingle", "quotedblleft", "guillemotleft", + "guilsinglleft","guilsinglright","fi", "fl", + # 176 + NULL, "endash", "dagger", "daggerdbl", + "periodcentered",NULL, "paragraph", "bullet", + "quotesinglbase","quotedblbase","quotedblright","guillemotright", + "ellipsis", "perthousand", NULL, "questiondown", + # 192 + NULL, "grave", "acute", "circumflex", + "tilde", "macron", "breve", "dotaccent", + "dieresis", NULL, "ring", "cedilla", + NULL, "hungarumlaut", "ogonek", "caron", + # 208 + "emdash", NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + # 224 + NULL, "AE", NULL, "ordfeminine", + NULL, NULL, NULL, NULL, + "Lslash", "Oslash", "OE", "ordmasculine", + NULL, NULL, NULL, NULL, + # 240 + NULL, "ae", NULL, NULL, + NULL, "dotlessi", NULL, NULL, + "lslash", "oslash", "oe", "germandbls", + NULL, NULL, NULL, NULL + ); + +@winansi_encoding = ( + # 0 + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + # 16 + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, + # 32 + "space", "exclam", "quotedbl", "numbersign", + "dollar", "percent", "ampersand", "quotesingle", + "parenleft", "parenright", "asterisk", "plus", + "comma", "hyphen", "period", "slash", + # 48 + "zero", "one", "two", "three", + "four", "five", "six", "seven", + "eight", "nine", "colon", "semicolon", + "less", "equal", "greater", "question", + # 64 + "at", "A", "B", "C", + "D", "E", "F", "G", + "H", "I", "J", "K", + "L", "M", "N", "O", + # 80 + "P", "Q", "R", "S", + "T", "U", "V", "W", + "X", "Y", "Z", "bracketleft", + "backslash", "bracketright", "asciicircum", "underscore", + # 96 + "grave", "a", "b", "c", + "d", "e", "f", "g", + "h", "i", "j", "k", + "l", "m", "n", "o", + # 112 + "p", "q", "r", "s", + "t", "u", "v", "w", + "x", "y", "z", "braceleft", + "bar", "braceright", "asciitilde", NULL, + # 128 + "Euro", NULL, "quotesinglbase","florin", + "quotedblbase", "ellipsis", "dagger", "daggerdbl", + "circumflex", "perthousand", "Scaron", "guilsinglleft", + "OE", NULL, "Zcaron", NULL, + # 144 + NULL, "quoteleft", "quoteright", "quotedblleft", + "quotedblright","bullet", "endash", "emdash", + "tilde", "trademark", "scaron", "guilsinglright", + "oe", NULL, "zcaron", "Ydieresis", + # 160 + NULL, "exclamdown", "cent", "sterling", + "currency", "yen", "brokenbar", "section", + "dieresis", "copyright", "ordfeminine", "guillemotleft", + # 173 is also "hyphen" but we leave this NULL to avoid duplicate names + "logicalnot", NULL, "registered", "macron", + # 176 + "degree", "plusminus", "twosuperior", "threesuperior", + "acute", "mu", "paragraph", "periodcentered", + "cedilla", "onesuperior", "ordmasculine", "guillemotright", + "onequarter", "onehalf", "threequarters","questiondown", + # 192 + "Agrave", "Aacute", "Acircumflex", "Atilde", + "Adieresis", "Aring", "AE", "Ccedilla", + "Egrave", "Eacute", "Ecircumflex", "Edieresis", + "Igrave", "Iacute", "Icircumflex", "Idieresis", + # 208 + "Eth", "Ntilde", "Ograve", "Oacute", + "Ocircumflex", "Otilde", "Odieresis", "multiply", + "Oslash", "Ugrave", "Uacute", "Ucircumflex", + "Udieresis", "Yacute", "Thorn", "germandbls", + # 224 + "agrave", "aacute", "acircumflex", "atilde", + "adieresis", "aring", "ae", "ccedilla", + "egrave", "eacute", "ecircumflex", "edieresis", + "igrave", "iacute", "icircumflex", "idieresis", + # 240 + "eth", "ntilde", "ograve", "oacute", + "ocircumflex", "otilde", "odieresis", "divide", + "oslash", "ugrave", "uacute", "ucircumflex", + "udieresis", "yacute", "thorn", "ydieresis" +); + +sub print_offsets { + $s = qq(); + for $sym (@_) { + if (! ($sym eq NULL)) { + $ss = qq( $hash{$sym}/*$sym*/,); + } else { + $ss = qq( 0,); + } + if (length($s) + length($ss) > 78) { + print qq( $s\n); + $s = ""; + } + $s .= $ss; + } + print qq( $s\n); +} + +@combined = (@ps_standard_encoding, @winansi_encoding); +print "static const char glyph_name_symbol[] = {\n"; +%hash = (); +$s = qq( "\\0"); +$offset = 1; +for $sym (@combined) { + if (! ($sym eq NULL)) { + if (! exists $hash{$sym}) { + $hash{$sym} = $offset; + $offset += length($sym) + 1; + $ss = qq( "$sym\\0"); + if (length($s) + length($ss) > 78) { + print qq( $s\n); + $s = ""; + } + $s .= $ss; + } + } +} +print qq( $s\n); +print "};\n\n"; + +print "static const int16_t ps_standard_encoding_offset[256] = {\n"; +print_offsets(@ps_standard_encoding); +print "};\n"; + +print "static const int16_t winansi_encoding_offset[256] = {\n"; +print_offsets(@winansi_encoding); +print "};\n"; + +exit; +#endif + +static const char glyph_name_symbol[] = { + "\0" "space\0" "exclam\0" "quotedbl\0" "numbersign\0" "dollar\0" "percent\0" + "ampersand\0" "quoteright\0" "parenleft\0" "parenright\0" "asterisk\0" + "plus\0" "comma\0" "hyphen\0" "period\0" "slash\0" "zero\0" "one\0" "two\0" + "three\0" "four\0" "five\0" "six\0" "seven\0" "eight\0" "nine\0" "colon\0" + "semicolon\0" "less\0" "equal\0" "greater\0" "question\0" "at\0" "A\0" "B\0" + "C\0" "D\0" "E\0" "F\0" "G\0" "H\0" "I\0" "J\0" "K\0" "L\0" "M\0" "N\0" "O\0" + "P\0" "Q\0" "R\0" "S\0" "T\0" "U\0" "V\0" "W\0" "X\0" "Y\0" "Z\0" + "bracketleft\0" "backslash\0" "bracketright\0" "asciicircum\0" "underscore\0" + "quoteleft\0" "a\0" "b\0" "c\0" "d\0" "e\0" "f\0" "g\0" "h\0" "i\0" "j\0" + "k\0" "l\0" "m\0" "n\0" "o\0" "p\0" "q\0" "r\0" "s\0" "t\0" "u\0" "v\0" "w\0" + "x\0" "y\0" "z\0" "braceleft\0" "bar\0" "braceright\0" "asciitilde\0" + "exclamdown\0" "cent\0" "sterling\0" "fraction\0" "yen\0" "florin\0" + "section\0" "currency\0" "quotesingle\0" "quotedblleft\0" "guillemotleft\0" + "guilsinglleft\0" "guilsinglright\0" "fi\0" "fl\0" "endash\0" "dagger\0" + "daggerdbl\0" "periodcentered\0" "paragraph\0" "bullet\0" "quotesinglbase\0" + "quotedblbase\0" "quotedblright\0" "guillemotright\0" "ellipsis\0" + "perthousand\0" "questiondown\0" "grave\0" "acute\0" "circumflex\0" "tilde\0" + "macron\0" "breve\0" "dotaccent\0" "dieresis\0" "ring\0" "cedilla\0" + "hungarumlaut\0" "ogonek\0" "caron\0" "emdash\0" "AE\0" "ordfeminine\0" + "Lslash\0" "Oslash\0" "OE\0" "ordmasculine\0" "ae\0" "dotlessi\0" "lslash\0" + "oslash\0" "oe\0" "germandbls\0" "Euro\0" "Scaron\0" "Zcaron\0" "trademark\0" + "scaron\0" "zcaron\0" "Ydieresis\0" "brokenbar\0" "copyright\0" + "logicalnot\0" "registered\0" "degree\0" "plusminus\0" "twosuperior\0" + "threesuperior\0" "mu\0" "onesuperior\0" "onequarter\0" "onehalf\0" + "threequarters\0" "Agrave\0" "Aacute\0" "Acircumflex\0" "Atilde\0" + "Adieresis\0" "Aring\0" "Ccedilla\0" "Egrave\0" "Eacute\0" "Ecircumflex\0" + "Edieresis\0" "Igrave\0" "Iacute\0" "Icircumflex\0" "Idieresis\0" "Eth\0" + "Ntilde\0" "Ograve\0" "Oacute\0" "Ocircumflex\0" "Otilde\0" "Odieresis\0" + "multiply\0" "Ugrave\0" "Uacute\0" "Ucircumflex\0" "Udieresis\0" "Yacute\0" + "Thorn\0" "agrave\0" "aacute\0" "acircumflex\0" "atilde\0" "adieresis\0" + "aring\0" "ccedilla\0" "egrave\0" "eacute\0" "ecircumflex\0" "edieresis\0" + "igrave\0" "iacute\0" "icircumflex\0" "idieresis\0" "eth\0" "ntilde\0" + "ograve\0" "oacute\0" "ocircumflex\0" "otilde\0" "odieresis\0" "divide\0" + "ugrave\0" "uacute\0" "ucircumflex\0" "udieresis\0" "yacute\0" "thorn\0" + "ydieresis\0" +}; + +static const int16_t ps_standard_encoding_offset[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1/*space*/, 7/*exclam*/, 14/*quotedbl*/, 23/*numbersign*/, + 34/*dollar*/, 41/*percent*/, 49/*ampersand*/, 59/*quoteright*/, + 70/*parenleft*/, 80/*parenright*/, 91/*asterisk*/, 100/*plus*/, 105/*comma*/, + 111/*hyphen*/, 118/*period*/, 125/*slash*/, 131/*zero*/, 136/*one*/, + 140/*two*/, 144/*three*/, 150/*four*/, 155/*five*/, 160/*six*/, 164/*seven*/, + 170/*eight*/, 176/*nine*/, 181/*colon*/, 187/*semicolon*/, 197/*less*/, + 202/*equal*/, 208/*greater*/, 216/*question*/, 225/*at*/, 228/*A*/, 230/*B*/, + 232/*C*/, 234/*D*/, 236/*E*/, 238/*F*/, 240/*G*/, 242/*H*/, 244/*I*/, + 246/*J*/, 248/*K*/, 250/*L*/, 252/*M*/, 254/*N*/, 256/*O*/, 258/*P*/, + 260/*Q*/, 262/*R*/, 264/*S*/, 266/*T*/, 268/*U*/, 270/*V*/, 272/*W*/, + 274/*X*/, 276/*Y*/, 278/*Z*/, 280/*bracketleft*/, 292/*backslash*/, + 302/*bracketright*/, 315/*asciicircum*/, 327/*underscore*/, 338/*quoteleft*/, + 348/*a*/, 350/*b*/, 352/*c*/, 354/*d*/, 356/*e*/, 358/*f*/, 360/*g*/, + 362/*h*/, 364/*i*/, 366/*j*/, 368/*k*/, 370/*l*/, 372/*m*/, 374/*n*/, + 376/*o*/, 378/*p*/, 380/*q*/, 382/*r*/, 384/*s*/, 386/*t*/, 388/*u*/, + 390/*v*/, 392/*w*/, 394/*x*/, 396/*y*/, 398/*z*/, 400/*braceleft*/, + 410/*bar*/, 414/*braceright*/, 425/*asciitilde*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 436/*exclamdown*/, 447/*cent*/, 452/*sterling*/, 461/*fraction*/, 470/*yen*/, + 474/*florin*/, 481/*section*/, 489/*currency*/, 498/*quotesingle*/, + 510/*quotedblleft*/, 523/*guillemotleft*/, 537/*guilsinglleft*/, + 551/*guilsinglright*/, 566/*fi*/, 569/*fl*/, 0, 572/*endash*/, 579/*dagger*/, + 586/*daggerdbl*/, 596/*periodcentered*/, 0, 611/*paragraph*/, 621/*bullet*/, + 628/*quotesinglbase*/, 643/*quotedblbase*/, 656/*quotedblright*/, + 670/*guillemotright*/, 685/*ellipsis*/, 694/*perthousand*/, 0, + 706/*questiondown*/, 0, 719/*grave*/, 725/*acute*/, 731/*circumflex*/, + 742/*tilde*/, 748/*macron*/, 755/*breve*/, 761/*dotaccent*/, 771/*dieresis*/, + 0, 780/*ring*/, 785/*cedilla*/, 0, 793/*hungarumlaut*/, 806/*ogonek*/, + 813/*caron*/, 819/*emdash*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 826/*AE*/, 0, 829/*ordfeminine*/, 0, 0, 0, 0, 841/*Lslash*/, 848/*Oslash*/, + 855/*OE*/, 858/*ordmasculine*/, 0, 0, 0, 0, 0, 871/*ae*/, 0, 0, 0, + 874/*dotlessi*/, 0, 0, 883/*lslash*/, 890/*oslash*/, 897/*oe*/, + 900/*germandbls*/, 0, 0, 0, 0, +}; + +static const int16_t winansi_encoding_offset[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1/*space*/, 7/*exclam*/, 14/*quotedbl*/, 23/*numbersign*/, + 34/*dollar*/, 41/*percent*/, 49/*ampersand*/, 498/*quotesingle*/, + 70/*parenleft*/, 80/*parenright*/, 91/*asterisk*/, 100/*plus*/, 105/*comma*/, + 111/*hyphen*/, 118/*period*/, 125/*slash*/, 131/*zero*/, 136/*one*/, + 140/*two*/, 144/*three*/, 150/*four*/, 155/*five*/, 160/*six*/, 164/*seven*/, + 170/*eight*/, 176/*nine*/, 181/*colon*/, 187/*semicolon*/, 197/*less*/, + 202/*equal*/, 208/*greater*/, 216/*question*/, 225/*at*/, 228/*A*/, 230/*B*/, + 232/*C*/, 234/*D*/, 236/*E*/, 238/*F*/, 240/*G*/, 242/*H*/, 244/*I*/, + 246/*J*/, 248/*K*/, 250/*L*/, 252/*M*/, 254/*N*/, 256/*O*/, 258/*P*/, + 260/*Q*/, 262/*R*/, 264/*S*/, 266/*T*/, 268/*U*/, 270/*V*/, 272/*W*/, + 274/*X*/, 276/*Y*/, 278/*Z*/, 280/*bracketleft*/, 292/*backslash*/, + 302/*bracketright*/, 315/*asciicircum*/, 327/*underscore*/, 719/*grave*/, + 348/*a*/, 350/*b*/, 352/*c*/, 354/*d*/, 356/*e*/, 358/*f*/, 360/*g*/, + 362/*h*/, 364/*i*/, 366/*j*/, 368/*k*/, 370/*l*/, 372/*m*/, 374/*n*/, + 376/*o*/, 378/*p*/, 380/*q*/, 382/*r*/, 384/*s*/, 386/*t*/, 388/*u*/, + 390/*v*/, 392/*w*/, 394/*x*/, 396/*y*/, 398/*z*/, 400/*braceleft*/, + 410/*bar*/, 414/*braceright*/, 425/*asciitilde*/, 0, 911/*Euro*/, 0, + 628/*quotesinglbase*/, 474/*florin*/, 643/*quotedblbase*/, 685/*ellipsis*/, + 579/*dagger*/, 586/*daggerdbl*/, 731/*circumflex*/, 694/*perthousand*/, + 916/*Scaron*/, 537/*guilsinglleft*/, 855/*OE*/, 0, 923/*Zcaron*/, 0, 0, + 338/*quoteleft*/, 59/*quoteright*/, 510/*quotedblleft*/, + 656/*quotedblright*/, 621/*bullet*/, 572/*endash*/, 819/*emdash*/, + 742/*tilde*/, 930/*trademark*/, 940/*scaron*/, 551/*guilsinglright*/, + 897/*oe*/, 0, 947/*zcaron*/, 954/*Ydieresis*/, 0, 436/*exclamdown*/, + 447/*cent*/, 452/*sterling*/, 489/*currency*/, 470/*yen*/, 964/*brokenbar*/, + 481/*section*/, 771/*dieresis*/, 974/*copyright*/, 829/*ordfeminine*/, + 523/*guillemotleft*/, 984/*logicalnot*/, 0, 995/*registered*/, 748/*macron*/, + 1006/*degree*/, 1013/*plusminus*/, 1023/*twosuperior*/, + 1035/*threesuperior*/, 725/*acute*/, 1049/*mu*/, 611/*paragraph*/, + 596/*periodcentered*/, 785/*cedilla*/, 1052/*onesuperior*/, + 858/*ordmasculine*/, 670/*guillemotright*/, 1064/*onequarter*/, + 1075/*onehalf*/, 1083/*threequarters*/, 706/*questiondown*/, 1097/*Agrave*/, + 1104/*Aacute*/, 1111/*Acircumflex*/, 1123/*Atilde*/, 1130/*Adieresis*/, + 1140/*Aring*/, 826/*AE*/, 1146/*Ccedilla*/, 1155/*Egrave*/, 1162/*Eacute*/, + 1169/*Ecircumflex*/, 1181/*Edieresis*/, 1191/*Igrave*/, 1198/*Iacute*/, + 1205/*Icircumflex*/, 1217/*Idieresis*/, 1227/*Eth*/, 1231/*Ntilde*/, + 1238/*Ograve*/, 1245/*Oacute*/, 1252/*Ocircumflex*/, 1264/*Otilde*/, + 1271/*Odieresis*/, 1281/*multiply*/, 848/*Oslash*/, 1290/*Ugrave*/, + 1297/*Uacute*/, 1304/*Ucircumflex*/, 1316/*Udieresis*/, 1326/*Yacute*/, + 1333/*Thorn*/, 900/*germandbls*/, 1339/*agrave*/, 1346/*aacute*/, + 1353/*acircumflex*/, 1365/*atilde*/, 1372/*adieresis*/, 1382/*aring*/, + 871/*ae*/, 1388/*ccedilla*/, 1397/*egrave*/, 1404/*eacute*/, + 1411/*ecircumflex*/, 1423/*edieresis*/, 1433/*igrave*/, 1440/*iacute*/, + 1447/*icircumflex*/, 1459/*idieresis*/, 1469/*eth*/, 1473/*ntilde*/, + 1480/*ograve*/, 1487/*oacute*/, 1494/*ocircumflex*/, 1506/*otilde*/, + 1513/*odieresis*/, 1523/*divide*/, 890/*oslash*/, 1530/*ugrave*/, + 1537/*uacute*/, 1544/*ucircumflex*/, 1556/*udieresis*/, 1566/*yacute*/, + 1573/*thorn*/, 1579/*ydieresis*/, +}; + +const char * +_cairo_ps_standard_encoding_to_glyphname (int glyph) +{ + if (ps_standard_encoding_offset[glyph]) + return glyph_name_symbol + ps_standard_encoding_offset[glyph]; + else + return NULL; +} + +const char * +_cairo_winansi_to_glyphname (int glyph) +{ + if (winansi_encoding_offset[glyph]) + return glyph_name_symbol + winansi_encoding_offset[glyph]; + else + return NULL; +} + +#endif /* CAIRO_HAS_FONT_SUBSET */ diff --git a/local/recipes/libs/cairo/source/src/cairo-type1-private.h b/local/recipes/libs/cairo/source/src/cairo-type1-private.h new file mode 100644 index 0000000000..1630397bca --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-type1-private.h @@ -0,0 +1,51 @@ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2007 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Adrian Johnson + */ + +#ifndef CAIRO_TYPE1_PRIVATE_H +#define CAIRO_TYPE1_PRIVATE_H + +#include "cairoint.h" + +#if CAIRO_HAS_FONT_SUBSET + +/* Magic constants for the type1 eexec encryption */ +#define CAIRO_TYPE1_ENCRYPT_C1 ((unsigned short) 52845) +#define CAIRO_TYPE1_ENCRYPT_C2 ((unsigned short) 22719) +#define CAIRO_TYPE1_PRIVATE_DICT_KEY ((unsigned short) 55665) +#define CAIRO_TYPE1_CHARSTRING_KEY ((unsigned short) 4330) + +#endif /* CAIRO_HAS_FONT_SUBSET */ + +#endif /* CAIRO_TYPE1_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-type1-subset.c b/local/recipes/libs/cairo/source/src/cairo-type1-subset.c new file mode 100644 index 0000000000..5c3766e3af --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-type1-subset.c @@ -0,0 +1,1862 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2006 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Kristian Høgsberg + */ + +/* + * Useful links: + * http://partners.adobe.com/public/developer/en/font/T1_SPEC.PDF + */ + + +#define _DEFAULT_SOURCE /* for snprintf(), strdup() */ +#include "cairoint.h" + +#include "cairo-array-private.h" +#include "cairo-error-private.h" + +#if CAIRO_HAS_FONT_SUBSET + +#include "cairo-type1-private.h" +#include "cairo-scaled-font-subsets-private.h" +#include "cairo-output-stream-private.h" + +#include + +#define TYPE1_STACKSIZE 24 /* Defined in Type 1 Font Format */ + + +typedef struct { + int subset_index; + double width; + const char *encrypted_charstring; + int encrypted_charstring_length; +} glyph_data_t; + +typedef struct _cairo_type1_font_subset { + cairo_scaled_font_subset_t *scaled_font_subset; + + struct { + unsigned int font_id; + char *base_font; + unsigned int num_glyphs; /* Num /CharStrings in font */ + double x_min, y_min, x_max, y_max; + double ascent, descent; + double units_per_em; + + const char *data; + unsigned long header_size; + unsigned long data_size; + unsigned long trailer_size; + } base; + + /* Num glyphs in subset. May be greater than + * scaled_font_subset->num_glyphs due to glyphs required by the + * SEAC operator. */ + int num_glyphs; + + /* The glyphs and glyph_names arrays are indexed by the order of + * the Charstrings in the font. This is not necessarily the same + * order as the glyph index. The index_to_glyph_name() font backend + * function is used to map the glyph index to the glyph order in + * the Charstrings. */ + + cairo_array_t glyphs_array; + glyph_data_t *glyphs; /* pointer to first element of above array */ + cairo_array_t glyph_names_array; + char **glyph_names; /* pointer to first element of above array */ + + int num_subrs; /* Num /Subrs routines in the font */ + cairo_bool_t subset_subrs; + struct { + const char *subr_string; + int subr_length; + const char *np; + int np_length; + cairo_bool_t used; + } *subrs; /* array with num_subrs elements */ + + /* Maps scaled_font_subset index to glyphs_array. + * Array size = scaled_font_subset->num_glyphs. */ + int *scaled_subset_index_to_glyphs; + + /* Keeps track of the glyphs that will be emitted in the subset. + * Allocated size = base.num_glyphs. Number of entries = num_glyphs. + * Array values are glyph_array indexes. + */ + int *type1_subset_index_to_glyphs; + + cairo_output_stream_t *output; + cairo_array_t contents; + + const char *rd, *nd, *np; + + int lenIV; + + char *type1_data; + unsigned int type1_length; + char *type1_end; + + char *header_segment; + unsigned int header_segment_size; + char *eexec_segment; + unsigned int eexec_segment_size; + cairo_bool_t eexec_segment_is_ascii; + + char *cleartext; + char *cleartext_end; + + unsigned int header_size; + + unsigned short eexec_key; + cairo_bool_t hex_encode; + int hex_column; + + struct { + double stack[TYPE1_STACKSIZE]; + int sp; + } build_stack; + + struct { + int stack[TYPE1_STACKSIZE]; + int sp; + } ps_stack; + + +} cairo_type1_font_subset_t; + + +static cairo_status_t +_cairo_type1_font_subset_init (cairo_type1_font_subset_t *font, + cairo_scaled_font_subset_t *scaled_font_subset, + cairo_bool_t hex_encode) +{ + memset (font, 0, sizeof (*font)); + font->scaled_font_subset = scaled_font_subset; + + _cairo_array_init (&font->glyphs_array, sizeof (glyph_data_t)); + _cairo_array_init (&font->glyph_names_array, sizeof (char *)); + font->scaled_subset_index_to_glyphs = _cairo_calloc_ab (scaled_font_subset->num_glyphs, + sizeof font->scaled_subset_index_to_glyphs[0]); + if (unlikely (font->scaled_subset_index_to_glyphs == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + + font->type1_subset_index_to_glyphs = NULL; + font->base.num_glyphs = 0; + font->num_subrs = 0; + font->subset_subrs = TRUE; + font->subrs = NULL; + + font->hex_encode = hex_encode; + font->num_glyphs = 0; + + _cairo_array_init (&font->contents, sizeof (char)); + + return CAIRO_STATUS_SUCCESS; +} + +static void +cairo_type1_font_subset_use_glyph (cairo_type1_font_subset_t *font, int glyph) +{ + if (font->glyphs[glyph].subset_index >= 0) + return; + + font->glyphs[glyph].subset_index = font->num_glyphs; + font->type1_subset_index_to_glyphs[font->num_glyphs] = glyph; + font->num_glyphs++; +} + +static cairo_bool_t +is_ps_delimiter(int c) +{ + static const char delimiters[] = "()[]{}<>/% \t\r\n"; + + return strchr (delimiters, c) != NULL; +} + +static const char * +find_token (const char *buffer, const char *end, const char *token) +{ + int i, length; + /* FIXME: find substring really must be find_token */ + + if (buffer == NULL) + return NULL; + + length = strlen (token); + for (i = 0; buffer + i < end - length + 1; i++) + if (memcmp (buffer + i, token, length) == 0) + if ((i == 0 || token[0] == '/' || is_ps_delimiter(buffer[i - 1])) && + (buffer + i == end - length || is_ps_delimiter(buffer[i + length]))) + return buffer + i; + + return NULL; +} + +static cairo_status_t +cairo_type1_font_subset_find_segments (cairo_type1_font_subset_t *font) +{ + unsigned char *p; + const char *eexec_token; + unsigned int size, i; + + p = (unsigned char *) font->type1_data; + font->type1_end = font->type1_data + font->type1_length; + if (font->type1_length >= 2 && p[0] == 0x80 && p[1] == 0x01) { + if (font->type1_end < (char *)(p + 6)) + return CAIRO_INT_STATUS_UNSUPPORTED; + font->header_segment_size = + p[2] | (p[3] << 8) | (p[4] << 16) | ((unsigned int) p[5] << 24); + font->header_segment = (char *) p + 6; + + p += 6 + font->header_segment_size; + if (font->type1_end < (char *)(p + 6)) + return CAIRO_INT_STATUS_UNSUPPORTED; + font->eexec_segment_size = + p[2] | (p[3] << 8) | (p[4] << 16) | ((unsigned int) p[5] << 24); + font->eexec_segment = (char *) p + 6; + font->eexec_segment_is_ascii = (p[1] == 1); + + p += 6 + font->eexec_segment_size; + while (font->type1_end >= (char *)(p + 6) && p[1] != 0x03) { + size = p[2] | (p[3] << 8) | (p[4] << 16) | ((unsigned int) p[5] << 24); + if (font->type1_end < (char *)(p + 6 + size)) + return CAIRO_INT_STATUS_UNSUPPORTED; + p += 6 + size; + } + font->type1_end = (char *) p; + } else { + eexec_token = find_token ((char *) p, font->type1_end, "eexec"); + if (eexec_token == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + font->header_segment_size = eexec_token - (char *) p + strlen ("eexec\n"); + font->header_segment = (char *) p; + font->eexec_segment_size = font->type1_length - font->header_segment_size; + font->eexec_segment = (char *) p + font->header_segment_size; + font->eexec_segment_is_ascii = TRUE; + for (i = 0; i < 4; i++) { + if (!_cairo_isxdigit (font->eexec_segment[i])) + font->eexec_segment_is_ascii = FALSE; + } + } + + return CAIRO_STATUS_SUCCESS; +} + +/* Search for the definition of key and erase it by overwriting with spaces. + * This function is looks for definitions of the form: + * + * /key1 1234 def + * /key2 [12 34 56] def + * + * ie a key defined as an integer or array of integers. + * + */ +static void +cairo_type1_font_erase_dict_key (cairo_type1_font_subset_t *font, + const char *key) +{ + const char *start, *p, *segment_end; + + segment_end = font->header_segment + font->header_segment_size; + + start = font->header_segment; + do { + start = find_token (start, segment_end, key); + if (start) { + p = start + strlen(key); + /* skip integers or array of integers */ + while (p < segment_end && + (_cairo_isspace(*p) || + _cairo_isdigit(*p) || + *p == '[' || + *p == ']')) + { + p++; + } + + if (p + 3 < segment_end && memcmp(p, "def", 3) == 0) { + /* erase definition of the key */ + memset((char *) start, ' ', p + 3 - start); + } + start += strlen(key); + } + } while (start); +} + +static cairo_status_t +cairo_type1_font_subset_get_matrix (cairo_type1_font_subset_t *font, + const char *name, + double *a, + double *b, + double *c, + double *d) +{ + const char *start, *end, *segment_end; + int ret, s_max, i, j; + char *s; + const char *decimal_point; + int decimal_point_len; + + decimal_point = _cairo_get_locale_decimal_point (); + decimal_point_len = strlen (decimal_point); + + assert (decimal_point_len != 0); + + segment_end = font->header_segment + font->header_segment_size; + start = find_token (font->header_segment, segment_end, name); + if (start == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + end = find_token (start, segment_end, "def"); + if (end == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + s_max = end - start + 5*decimal_point_len + 1; + s = _cairo_malloc (s_max); + if (unlikely (s == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + i = 0; + j = 0; + while (i < end - start && j < s_max - decimal_point_len) { + if (start[i] == '.') { + strncpy(s + j, decimal_point, decimal_point_len + 1); + i++; + j += decimal_point_len; + } else { + s[j++] = start[i++]; + } + } + s[j] = 0; + + start = strpbrk (s, "{["); + if (!start) { + free (s); + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + start++; + ret = 0; + if (*start) + ret = sscanf(start, "%lf %lf %lf %lf", a, b, c, d); + + free (s); + + if (ret != 4) + return CAIRO_INT_STATUS_UNSUPPORTED; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +cairo_type1_font_subset_get_bbox (cairo_type1_font_subset_t *font) +{ + cairo_status_t status; + double x_min, y_min, x_max, y_max; + double xx, yx, xy, yy; + + status = cairo_type1_font_subset_get_matrix (font, "/FontBBox", + &x_min, + &y_min, + &x_max, + &y_max); + if (unlikely (status)) + return status; + + status = cairo_type1_font_subset_get_matrix (font, "/FontMatrix", + &xx, &yx, &xy, &yy); + if (unlikely (status)) + return status; + + if (yy == 0.0) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* FreeType uses 1/yy to get units per EM */ + font->base.units_per_em = 1.0/yy; + + /* If the FontMatrix is not a uniform scale the metrics we extract + * from the font won't match what FreeType returns */ + if (xx != yy || yx != 0.0 || xy != 0.0) + return CAIRO_INT_STATUS_UNSUPPORTED; + + font->base.x_min = x_min / font->base.units_per_em; + font->base.y_min = y_min / font->base.units_per_em; + font->base.x_max = x_max / font->base.units_per_em; + font->base.y_max = y_max / font->base.units_per_em; + font->base.ascent = font->base.y_max; + font->base.descent = font->base.y_min; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +cairo_type1_font_subset_get_fontname (cairo_type1_font_subset_t *font) +{ + const char *start, *end, *segment_end; + char *s; + int i; + cairo_status_t status; + + segment_end = font->header_segment + font->header_segment_size; + start = find_token (font->header_segment, segment_end, "/FontName"); + if (start == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + start += strlen ("/FontName"); + + end = find_token (start, segment_end, "def"); + if (end == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + while (end > start && _cairo_isspace(end[-1])) + end--; + + s = _cairo_malloc (end - start + 1); + if (unlikely (s == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + strncpy (s, start, end - start); + s[end - start] = 0; + + start = strchr (s, '/'); + if (!start++ || !start) { + free (s); + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + /* If font name is prefixed with a subset tag, strip it off. */ + if (strlen(start) > 7 && start[6] == '+') { + for (i = 0; i < 6; i++) { + if (start[i] < 'A' || start[i] > 'Z') + break; + } + if (i == 6) + start += 7; + } + + font->base.base_font = strdup (start); + free (s); + if (unlikely (font->base.base_font == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + status = _cairo_escape_ps_name (&font->base.base_font); + + return status; +} + +static cairo_status_t +cairo_type1_font_subset_write_header (cairo_type1_font_subset_t *font, + const char *name) +{ + const char *start, *end, *segment_end; + unsigned int i; + int glyph; + + /* FIXME: + * This function assumes that /FontName always appears + * before /Encoding. This appears to always be the case with Type1 + * fonts. + * + * The more recently added code for removing the UniqueID and XUID + * keys can not make any assumptions about the position of the + * keys in the dictionary so it is implemented by overwriting the + * key definition with spaces before we start copying the font to + * the output. + * + * This code should be rewritten to not make any assumptions about + * the order of dictionary keys. This will allow UniqueID to be + * stripped out instead of leaving a bunch of spaces in the + * output. + */ + cairo_type1_font_erase_dict_key (font, "/UniqueID"); + cairo_type1_font_erase_dict_key (font, "/XUID"); + + segment_end = font->header_segment + font->header_segment_size; + + /* Type 1 fonts created by Fontforge have some PostScript code at + * the start of the font that skips the font if the printer has a + * cached copy of the font with the same unique id. This breaks + * our subsetted font so we disable it by searching for the + * PostScript operator "known" when used to check for the + * "/UniqueID" dictionary key. We append " pop false " after it to + * pop the result of this check off the stack and replace it with + * "false" to make the PostScript code think "/UniqueID" does not + * exist. + */ + end = font->header_segment; + start = find_token (font->header_segment, segment_end, "/UniqueID"); + if (start) { + start += 9; + while (start < segment_end && _cairo_isspace (*start)) + start++; + if (start + 5 < segment_end && memcmp(start, "known", 5) == 0) { + _cairo_output_stream_write (font->output, font->header_segment, + start + 5 - font->header_segment); + _cairo_output_stream_printf (font->output, " pop false "); + end = start + 5; + } + } + + start = find_token (end, segment_end, "/FontName"); + if (start == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + _cairo_output_stream_write (font->output, end, + start - end); + + _cairo_output_stream_printf (font->output, "/FontName /%s def", name); + + end = find_token (start, segment_end, "def"); + if (end == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + end += 3; + + start = find_token (end, segment_end, "/Encoding"); + if (start == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + _cairo_output_stream_write (font->output, end, start - end); + + _cairo_output_stream_printf (font->output, + "/Encoding 256 array\n" + "0 1 255 {1 index exch /.notdef put} for\n"); + if (font->scaled_font_subset->is_latin) { + for (i = 1; i < 256; i++) { + int subset_glyph = font->scaled_font_subset->latin_to_subset_glyph_index[i]; + + if (subset_glyph > 0) { + _cairo_output_stream_printf (font->output, + "dup %d /%s put\n", + i, + _cairo_winansi_to_glyphname (i)); + } + } + } else { + for (i = 1; i < font->scaled_font_subset->num_glyphs; i++) { + glyph = font->scaled_subset_index_to_glyphs[i]; + _cairo_output_stream_printf (font->output, + "dup %d /%s put\n", + i, + font->glyph_names[glyph]); + } + } + _cairo_output_stream_printf (font->output, "readonly def"); + + end = find_token (start, segment_end, "def"); + if (end == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + end += 3; + + /* There are some buggy fonts that contain more than one /Encoding */ + if (find_token (end, segment_end, "/Encoding")) + return CAIRO_INT_STATUS_UNSUPPORTED; + + _cairo_output_stream_write (font->output, end, segment_end - end); + + return font->output->status; +} + +static int +hex_to_int (int ch) +{ + if (ch <= '9') + return ch - '0'; + else if (ch <= 'F') + return ch - 'A' + 10; + else + return ch - 'a' + 10; +} + +static cairo_status_t +cairo_type1_font_subset_write_encrypted (cairo_type1_font_subset_t *font, + const char *data, unsigned int length) +{ + const unsigned char *in, *end; + int c, p; + static const char hex_digits[16] = "0123456789abcdef"; + char digits[3]; + + in = (const unsigned char *) data; + end = (const unsigned char *) data + length; + while (in < end) { + p = *in++; + c = p ^ (font->eexec_key >> 8); + font->eexec_key = (c + font->eexec_key) * CAIRO_TYPE1_ENCRYPT_C1 + CAIRO_TYPE1_ENCRYPT_C2; + + if (font->hex_encode) { + digits[0] = hex_digits[c >> 4]; + digits[1] = hex_digits[c & 0x0f]; + digits[2] = '\n'; + font->hex_column += 2; + + if (font->hex_column == 78) { + _cairo_output_stream_write (font->output, digits, 3); + font->hex_column = 0; + } else { + _cairo_output_stream_write (font->output, digits, 2); + } + } else { + digits[0] = c; + _cairo_output_stream_write (font->output, digits, 1); + } + } + + return font->output->status; +} + +static cairo_status_t +cairo_type1_font_subset_decrypt_eexec_segment (cairo_type1_font_subset_t *font) +{ + unsigned short r = CAIRO_TYPE1_PRIVATE_DICT_KEY; + unsigned char *in, *end; + char *out; + int c, p; + unsigned int i; + + in = (unsigned char *) font->eexec_segment; + end = (unsigned char *) in + font->eexec_segment_size; + + font->cleartext = _cairo_malloc (font->eexec_segment_size + 1); + if (unlikely (font->cleartext == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + out = font->cleartext; + while (in < end) { + if (font->eexec_segment_is_ascii) { + c = *in++; + if (_cairo_isspace (c)) + continue; + c = (hex_to_int (c) << 4) | hex_to_int (*in++); + } else { + c = *in++; + } + p = c ^ (r >> 8); + r = (c + r) * CAIRO_TYPE1_ENCRYPT_C1 + CAIRO_TYPE1_ENCRYPT_C2; + + *out++ = p; + } + font->cleartext_end = out; + + /* Overwrite random bytes with spaces. + * + * The first 4 bytes of the cleartext are the random bytes + * required by the encryption algorithm. When encrypting the + * cleartext, the first ciphertext byte must not be a white space + * character and the first 4 bytes must not be an ASCII Hex + * character. Some fonts do not check that their randomly chosen + * bytes results in ciphertext that complies with this + * restriction. This may cause problems for some PDF consumers. By + * replacing the random bytes with spaces, the first four bytes of + * ciphertext will always be 0xf9, 0x83, 0xef, 0x00 which complies + * with this restriction. Using spaces also means we don't have to + * skip over the random bytes when parsing the cleartext. + */ + for (i = 0; i < 4 && i < font->eexec_segment_size; i++) + font->cleartext[i] = ' '; + + /* Ensure strtol() can not scan past the end of the cleartext */ + font->cleartext[font->eexec_segment_size] = 0; + + return CAIRO_STATUS_SUCCESS; +} + +static const char * +skip_token (const char *p, const char *end) +{ + while (p < end && _cairo_isspace(*p)) + p++; + + while (p < end && !_cairo_isspace(*p)) + p++; + + if (p == end) + return NULL; + + return p; +} + +static void +cairo_type1_font_subset_decrypt_charstring (const unsigned char *in, int size, unsigned char *out) +{ + unsigned short r = CAIRO_TYPE1_CHARSTRING_KEY; + int c, p, i; + + for (i = 0; i < size; i++) { + c = *in++; + p = c ^ (r >> 8); + r = (c + r) * CAIRO_TYPE1_ENCRYPT_C1 + CAIRO_TYPE1_ENCRYPT_C2; + *out++ = p; + } +} + +static const unsigned char * +cairo_type1_font_subset_decode_integer (const unsigned char *p, int *integer) +{ + if (*p <= 246) { + *integer = *p++ - 139; + } else if (*p <= 250) { + *integer = (p[0] - 247) * 256 + p[1] + 108; + p += 2; + } else if (*p <= 254) { + *integer = -(p[0] - 251) * 256 - p[1] - 108; + p += 2; + } else { + *integer = ((uint32_t)p[1] << 24) | (p[2] << 16) | (p[3] << 8) | p[4]; + p += 5; + } + + return p; +} + +static cairo_status_t +use_standard_encoding_glyph (cairo_type1_font_subset_t *font, int index) +{ + const char *glyph_name; + unsigned int i; + + if (index < 0 || index > 255) + return CAIRO_STATUS_SUCCESS; + + glyph_name = _cairo_ps_standard_encoding_to_glyphname (index); + if (glyph_name == NULL) + return CAIRO_STATUS_SUCCESS; + + for (i = 0; i < font->base.num_glyphs; i++) { + if (font->glyph_names[i] && strcmp (font->glyph_names[i], glyph_name) == 0) { + cairo_type1_font_subset_use_glyph (font, i); + + return CAIRO_STATUS_SUCCESS; + } + } + + return CAIRO_INT_STATUS_UNSUPPORTED; +} + + +#define TYPE1_CHARSTRING_COMMAND_HSTEM 0x01 +#define TYPE1_CHARSTRING_COMMAND_VSTEM 0x03 +#define TYPE1_CHARSTRING_COMMAND_VMOVETO 0x04 +#define TYPE1_CHARSTRING_COMMAND_RLINETO 0x05 +#define TYPE1_CHARSTRING_COMMAND_HLINETO 0x06 +#define TYPE1_CHARSTRING_COMMAND_VLINETO 0x07 +#define TYPE1_CHARSTRING_COMMAND_RRCURVETO 0x08 +#define TYPE1_CHARSTRING_COMMAND_CLOSEPATH 0x09 +#define TYPE1_CHARSTRING_COMMAND_CALLSUBR 0x0a +#define TYPE1_CHARSTRING_COMMAND_RETURN 0x0b +#define TYPE1_CHARSTRING_COMMAND_ESCAPE 0x0c +#define TYPE1_CHARSTRING_COMMAND_HSBW 0x0d +#define TYPE1_CHARSTRING_COMMAND_ENDCHAR 0x0e +#define TYPE1_CHARSTRING_COMMAND_RMOVETO 0x15 +#define TYPE1_CHARSTRING_COMMAND_HMOVETO 0x16 +#define TYPE1_CHARSTRING_COMMAND_VHCURVETO 0x1e +#define TYPE1_CHARSTRING_COMMAND_HVCURVETO 0x1f +#define TYPE1_CHARSTRING_COMMAND_DOTSECTION 0x0c00 +#define TYPE1_CHARSTRING_COMMAND_VSTEM3 0x0c01 +#define TYPE1_CHARSTRING_COMMAND_HSTEM3 0x0c02 +#define TYPE1_CHARSTRING_COMMAND_SEAC 0x0c06 +#define TYPE1_CHARSTRING_COMMAND_SBW 0x0c07 +#define TYPE1_CHARSTRING_COMMAND_DIV 0x0c0c +#define TYPE1_CHARSTRING_COMMAND_CALLOTHERSUBR 0x0c10 +#define TYPE1_CHARSTRING_COMMAND_POP 0x0c11 +#define TYPE1_CHARSTRING_COMMAND_SETCURRENTPOINT 0x0c21 + +/* Parse the charstring, including recursing into subroutines. Find + * the glyph width, subroutines called, and glyphs required by the + * SEAC operator. */ +static cairo_status_t +cairo_type1_font_subset_parse_charstring (cairo_type1_font_subset_t *font, + int glyph, + const char *encrypted_charstring, + int encrypted_charstring_length) +{ + cairo_status_t status; + unsigned char *charstring; + const unsigned char *end; + const unsigned char *p; + int command; + + charstring = _cairo_malloc (encrypted_charstring_length); + if (unlikely (charstring == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + cairo_type1_font_subset_decrypt_charstring ((const unsigned char *) + encrypted_charstring, + encrypted_charstring_length, + charstring); + end = charstring + encrypted_charstring_length; + p = charstring + font->lenIV; + status = CAIRO_STATUS_SUCCESS; + while (p < end) { + if (*p < 32) { + command = *p++; + switch (command) { + case TYPE1_CHARSTRING_COMMAND_HSTEM: + case TYPE1_CHARSTRING_COMMAND_VSTEM: + case TYPE1_CHARSTRING_COMMAND_VMOVETO: + case TYPE1_CHARSTRING_COMMAND_RLINETO: + case TYPE1_CHARSTRING_COMMAND_HLINETO: + case TYPE1_CHARSTRING_COMMAND_VLINETO: + case TYPE1_CHARSTRING_COMMAND_RRCURVETO: + case TYPE1_CHARSTRING_COMMAND_CLOSEPATH: + case TYPE1_CHARSTRING_COMMAND_RMOVETO: + case TYPE1_CHARSTRING_COMMAND_HMOVETO: + case TYPE1_CHARSTRING_COMMAND_VHCURVETO: + case TYPE1_CHARSTRING_COMMAND_HVCURVETO: + case TYPE1_CHARSTRING_COMMAND_RETURN: + case TYPE1_CHARSTRING_COMMAND_ENDCHAR: + default: + /* stack clearing operator */ + font->build_stack.sp = 0; + break; + + case TYPE1_CHARSTRING_COMMAND_CALLSUBR: + if (font->subset_subrs && font->build_stack.sp > 0) { + double int_val; + if (modf(font->build_stack.stack[--font->build_stack.sp], &int_val) == 0.0) { + int subr_num = int_val; + if (subr_num >= 0 && subr_num < font->num_subrs) { + font->subrs[subr_num].used = TRUE; + status = cairo_type1_font_subset_parse_charstring ( + font, + glyph, + font->subrs[subr_num].subr_string, + font->subrs[subr_num].subr_length); + break; + } + } + } + font->subset_subrs = FALSE; + break; + + case TYPE1_CHARSTRING_COMMAND_HSBW: + if (font->build_stack.sp < 2) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto cleanup; + } + + font->glyphs[glyph].width = font->build_stack.stack[1]/font->base.units_per_em; + font->build_stack.sp = 0; + break; + + case TYPE1_CHARSTRING_COMMAND_ESCAPE: + command = command << 8 | *p++; + switch (command) { + case TYPE1_CHARSTRING_COMMAND_DOTSECTION: + case TYPE1_CHARSTRING_COMMAND_VSTEM3: + case TYPE1_CHARSTRING_COMMAND_HSTEM3: + case TYPE1_CHARSTRING_COMMAND_SETCURRENTPOINT: + default: + /* stack clearing operator */ + font->build_stack.sp = 0; + break; + + case TYPE1_CHARSTRING_COMMAND_SEAC: + /* The seac command takes five integer arguments. The + * last two are glyph indices into the PS standard + * encoding give the names of the glyphs that this + * glyph is composed from. All we need to do is to + * make sure those glyphs are present in the subset + * under their standard names. */ + if (font->build_stack.sp < 5) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto cleanup; + } + + status = use_standard_encoding_glyph (font, font->build_stack.stack[3]); + if (unlikely (status)) + goto cleanup; + + status = use_standard_encoding_glyph (font, font->build_stack.stack[4]); + if (unlikely (status)) + goto cleanup; + + font->build_stack.sp = 0; + break; + + case TYPE1_CHARSTRING_COMMAND_SBW: + if (font->build_stack.sp < 4) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto cleanup; + } + + font->glyphs[glyph].width = font->build_stack.stack[2]/font->base.units_per_em; + font->build_stack.sp = 0; + break; + + case TYPE1_CHARSTRING_COMMAND_DIV: + if (font->build_stack.sp < 2) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto cleanup; + } else { + double num1 = font->build_stack.stack[font->build_stack.sp - 2]; + double num2 = font->build_stack.stack[font->build_stack.sp - 1]; + font->build_stack.sp--; + if (num2 == 0.0) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto cleanup; + } + font->build_stack.stack[font->build_stack.sp - 1] = num1/num2; + } + break; + + case TYPE1_CHARSTRING_COMMAND_CALLOTHERSUBR: + if (font->build_stack.sp < 1) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto cleanup; + } + + font->build_stack.sp--; + font->ps_stack.sp = 0; + while (font->build_stack.sp) + font->ps_stack.stack[font->ps_stack.sp++] = font->build_stack.stack[--font->build_stack.sp]; + + break; + + case TYPE1_CHARSTRING_COMMAND_POP: + if (font->ps_stack.sp < 1) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto cleanup; + } + + /* T1 spec states that if the interpreter does not + * support executing the callothersub, the results + * must be taken from the callothersub arguments. */ + font->build_stack.stack[font->build_stack.sp++] = font->ps_stack.stack[--font->ps_stack.sp]; + break; + } + break; + } + } else { + /* integer argument */ + if (font->build_stack.sp < TYPE1_STACKSIZE) { + int val; + p = cairo_type1_font_subset_decode_integer (p, &val); + font->build_stack.stack[font->build_stack.sp++] = val; + } else { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto cleanup; + } + } + } + +cleanup: + free (charstring); + + return status; +} + +static cairo_status_t +cairo_type1_font_subset_build_subr_list (cairo_type1_font_subset_t *font, + int subr_number, + const char *encrypted_charstring, int encrypted_charstring_length, + const char *np, int np_length) +{ + + font->subrs[subr_number].subr_string = encrypted_charstring; + font->subrs[subr_number].subr_length = encrypted_charstring_length; + font->subrs[subr_number].np = np; + font->subrs[subr_number].np_length = np_length; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +write_used_subrs (cairo_type1_font_subset_t *font, + int subr_number, + const char *subr_string, int subr_string_length, + const char *np, int np_length) +{ + cairo_status_t status; + char buffer[256]; + int length; + + if (!font->subrs[subr_number].used) + return CAIRO_STATUS_SUCCESS; + + length = snprintf (buffer, sizeof buffer, + "dup %d %d %s ", + subr_number, subr_string_length, font->rd); + status = cairo_type1_font_subset_write_encrypted (font, buffer, length); + if (unlikely (status)) + return status; + + status = cairo_type1_font_subset_write_encrypted (font, + subr_string, + subr_string_length); + if (unlikely (status)) + return status; + + if (np) { + status = cairo_type1_font_subset_write_encrypted (font, np, np_length); + } else { + length = snprintf (buffer, sizeof buffer, "%s\n", font->np); + status = cairo_type1_font_subset_write_encrypted (font, buffer, length); + } + if (unlikely (status)) + return status; + + return CAIRO_STATUS_SUCCESS; +} + +typedef cairo_status_t (*subr_func_t) (cairo_type1_font_subset_t *font, + int subr_number, + const char *subr_string, int subr_string_length, + const char *np, int np_length); + +static cairo_status_t +cairo_type1_font_for_each_subr (cairo_type1_font_subset_t *font, + const char *array_start, + const char *cleartext_end, + subr_func_t func, + const char **array_end) +{ + const char *p, *subr_string; + char *end; + int subr_num, subr_length; + const char *np; + int np_length; + cairo_status_t status; + + /* We're looking at "dup" at the start of the first subroutine. The subroutines + * definitions are on the form: + * + * dup 5 23 RD <23 binary bytes> NP + * + * or alternatively using -| and |- instead of RD and ND. + * The first number is the subroutine number. + */ + + p = array_start; + while (p + 3 < cleartext_end && strncmp (p, "dup", 3) == 0) { + p = skip_token (p, cleartext_end); + + /* get subr number */ + subr_num = strtol (p, &end, 10); + if (p == end) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (subr_num < 0 || subr_num >= font->num_subrs) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* get subr length */ + p = end; + subr_length = strtol (p, &end, 10); + if (p == end) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* Skip past -| or RD to binary data. There is exactly one space + * between the -| or RD token and the encrypted data, thus '+ 1'. */ + subr_string = skip_token (end, cleartext_end) + 1; + + np = NULL; + np_length = 0; + + /* Skip binary data and | or NP token. */ + p = skip_token (subr_string + subr_length, cleartext_end); + if (p == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + while (p < cleartext_end && _cairo_isspace(*p)) + p++; + + /* Some fonts have "noaccess put" instead of "NP" */ + if (p + 3 < cleartext_end && strncmp (p, "put", 3) == 0) { + p = skip_token (p, cleartext_end); + while (p < cleartext_end && _cairo_isspace(*p)) + p++; + + np = subr_string + subr_length; + np_length = p - np; + } + + status = func (font, subr_num, + subr_string, subr_length, np, np_length); + if (unlikely (status)) + return status; + + } + + *array_end = (char *) p; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +cairo_type1_font_subset_build_glyph_list (cairo_type1_font_subset_t *font, + int glyph_number, + const char *name, int name_length, + const char *encrypted_charstring, int encrypted_charstring_length) +{ + char *s; + glyph_data_t glyph; + cairo_status_t status; + + s = _cairo_malloc (name_length + 1); + if (unlikely (s == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + strncpy (s, name, name_length); + s[name_length] = 0; + + status = _cairo_array_append (&font->glyph_names_array, &s); + if (unlikely (status)) + return status; + + glyph.subset_index = -1; + glyph.width = 0; + glyph.encrypted_charstring = encrypted_charstring; + glyph.encrypted_charstring_length = encrypted_charstring_length; + status = _cairo_array_append (&font->glyphs_array, &glyph); + + return status; +} + +static cairo_status_t +write_used_glyphs (cairo_type1_font_subset_t *font, + int glyph_number, + const char *name, int name_length, + const char *charstring, int charstring_length) +{ + cairo_status_t status; + char buffer[256]; + int length; + unsigned int subset_id; + int ch; + const char *wa_name; + + if (font->glyphs[glyph_number].subset_index < 0) + return CAIRO_STATUS_SUCCESS; + + if (font->scaled_font_subset->is_latin) { + /* When using the WinAnsi encoding in PDF, the /Encoding array + * is ignored and instead glyphs are keyed by glyph names. To + * ensure correct rendering we replace the glyph name in the + * font with the standard name. + **/ + subset_id = font->glyphs[glyph_number].subset_index; + /* Any additional glyph included for use by the seac operator + * will either have subset_id >= font->scaled_font_subset->num_glyphs + * or will not map to a winansi name (wa_name = NULL). In this + * case the original name is used. + */ + if (subset_id > 0 && subset_id < font->scaled_font_subset->num_glyphs) { + ch = font->scaled_font_subset->to_latin_char[subset_id]; + wa_name = _cairo_winansi_to_glyphname (ch); + if (wa_name) { + name = wa_name; + name_length = strlen(name); + } + } + } + + length = snprintf (buffer, sizeof buffer, + "/%.*s %d %s ", + name_length, name, charstring_length, font->rd); + status = cairo_type1_font_subset_write_encrypted (font, buffer, length); + if (unlikely (status)) + return status; + + status = cairo_type1_font_subset_write_encrypted (font, + charstring, + charstring_length); + if (unlikely (status)) + return status; + + length = snprintf (buffer, sizeof buffer, "%s\n", font->nd); + status = cairo_type1_font_subset_write_encrypted (font, buffer, length); + if (unlikely (status)) + return status; + + return CAIRO_STATUS_SUCCESS; +} + +typedef cairo_status_t (*glyph_func_t) (cairo_type1_font_subset_t *font, + int glyph_number, + const char *name, int name_length, + const char *charstring, int charstring_length); + +static cairo_status_t +cairo_type1_font_subset_for_each_glyph (cairo_type1_font_subset_t *font, + const char *dict_start, + const char *dict_end, + glyph_func_t func, + const char **dict_out) +{ + int charstring_length, name_length; + const char *p, *charstring, *name; + char *end; + cairo_status_t status; + int glyph_count; + + /* We're looking at '/' in the name of the first glyph. The glyph + * definitions are on the form: + * + * /name 23 RD <23 binary bytes> ND + * + * or alternatively using -| and |- instead of RD and ND. + * + * We parse the glyph name and see if it is in the subset. If it + * is, we call the specified callback with the glyph name and + * glyph data, otherwise we just skip it. We need to parse + * through a glyph definition; we can't just find the next '/', + * since the binary data could contain a '/'. + */ + + p = dict_start; + glyph_count = 0; + while (*p == '/') { + name = p + 1; + p = skip_token (p, dict_end); + name_length = p - name; + + charstring_length = strtol (p, &end, 10); + if (p == end) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* Skip past -| or RD to binary data. There is exactly one space + * between the -| or RD token and the encrypted data, thus '+ 1'. */ + charstring = skip_token (end, dict_end) + 1; + + /* Skip binary data and |- or ND token. */ + p = skip_token (charstring + charstring_length, dict_end); + if (p == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + while (p < dict_end && _cairo_isspace(*p)) + p++; + + /* In case any of the skip_token() calls above reached EOF, p will + * be equal to dict_end. */ + if (p == dict_end) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = func (font, glyph_count++, + name, name_length, + charstring, charstring_length); + if (unlikely (status)) + return status; + } + + *dict_out = p; + + return CAIRO_STATUS_SUCCESS; +} + + +static cairo_status_t +cairo_type1_font_subset_write_private_dict (cairo_type1_font_subset_t *font, + const char *name) +{ + cairo_status_t status; + const char *p, *subrs, *charstrings, *array_start, *array_end, *dict_start, *dict_end; + const char *lenIV_start, *lenIV_end, *closefile_token; + char buffer[32], *lenIV_str, *subr_count_end, *glyph_count_end; + int ret, lenIV, length; + const cairo_scaled_font_backend_t *backend; + unsigned int i; + int glyph, j; + + /* The private dict holds hint information, common subroutines and + * the actual glyph definitions (charstrings). + * + * What we do here is scan directly to the /Subrs token, which + * marks the beginning of the subroutines. We read in all the + * subroutines, then move on to the /CharString token, which marks + * the beginning of the glyph definitions, and read in the charstrings. + * + * The charstrings are parsed to extract glyph widths, work out + * which subroutines are called, and to see if any extra glyphs + * need to be included due to the use of the seac glyph combining + * operator. + * + * Finally, the private dict is copied to the subset font minus the + * subroutines and charstrings not required. + */ + + /* Determine lenIV, the number of random characters at the start of + each encrypted charstring. The default is 4, but this can be + overridden in the private dict. */ + font->lenIV = 4; + if ((lenIV_start = find_token (font->cleartext, font->cleartext_end, "/lenIV")) != NULL) { + lenIV_start += 6; + lenIV_end = find_token (lenIV_start, font->cleartext_end, "def"); + if (lenIV_end == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + lenIV_str = _cairo_malloc (lenIV_end - lenIV_start + 1); + if (unlikely (lenIV_str == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + strncpy (lenIV_str, lenIV_start, lenIV_end - lenIV_start); + lenIV_str[lenIV_end - lenIV_start] = 0; + + ret = sscanf(lenIV_str, "%d", &lenIV); + free(lenIV_str); + + if (unlikely (ret <= 0)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* Apparently some fonts signal unencrypted charstrings with a negative lenIV, + though this is not part of the Type 1 Font Format specification. See, e.g. + http://lists.gnu.org/archive/html/freetype-devel/2000-06/msg00064.html. */ + if (unlikely (lenIV < 0)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + font->lenIV = lenIV; + } + + /* Find start of Subrs */ + subrs = find_token (font->cleartext, font->cleartext_end, "/Subrs"); + if (subrs == NULL) { + font->subset_subrs = FALSE; + p = font->cleartext; + array_start = NULL; + goto skip_subrs; + } + + /* Scan past /Subrs and get the array size. */ + p = subrs + strlen ("/Subrs"); + font->num_subrs = strtol (p, &subr_count_end, 10); + if (subr_count_end == p) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (font->num_subrs <= 0) + return CAIRO_INT_STATUS_UNSUPPORTED; + + font->subrs = _cairo_calloc_ab (font->num_subrs, sizeof (font->subrs[0])); + if (unlikely (font->subrs == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + /* look for "dup" which marks the beginning of the first subr */ + array_start = find_token (subr_count_end, font->cleartext_end, "dup"); + if (array_start == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* Read in the subroutines */ + status = cairo_type1_font_for_each_subr (font, + array_start, + font->cleartext_end, + cairo_type1_font_subset_build_subr_list, + &array_end); + if (unlikely(status)) + return status; + + p = array_end; +skip_subrs: + + /* Find start of CharStrings */ + charstrings = find_token (p, font->cleartext_end, "/CharStrings"); + if (charstrings == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* Scan past /CharStrings and the integer following it. */ + p = charstrings + strlen ("/CharStrings"); + strtol (p, &glyph_count_end, 10); + if (p == glyph_count_end) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* Look for a '/' which marks the beginning of the first glyph + * definition. */ + for (p = glyph_count_end; p < font->cleartext_end; p++) + if (*p == '/') + break; + if (p == font->cleartext_end) + return CAIRO_INT_STATUS_UNSUPPORTED; + dict_start = p; + + /* Now that we have the private dictionary broken down in + * sections, do the first pass through the glyph definitions to + * build a list of glyph names and charstrings. */ + status = cairo_type1_font_subset_for_each_glyph (font, + dict_start, + font->cleartext_end, + cairo_type1_font_subset_build_glyph_list, + &dict_end); + if (unlikely(status)) + return status; + + font->glyphs = _cairo_array_index (&font->glyphs_array, 0); + font->glyph_names = _cairo_array_index (&font->glyph_names_array, 0); + font->base.num_glyphs = _cairo_array_num_elements (&font->glyphs_array); + font->type1_subset_index_to_glyphs = _cairo_calloc_ab (font->base.num_glyphs, + sizeof font->type1_subset_index_to_glyphs[0]); + if (unlikely (font->type1_subset_index_to_glyphs == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + backend = font->scaled_font_subset->scaled_font->backend; + if (!backend->index_to_glyph_name) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* Find the glyph number corresponding to each glyph in the subset + * and mark it as in use */ + + for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) { + unsigned long index; + + status = backend->index_to_glyph_name (font->scaled_font_subset->scaled_font, + font->glyph_names, + font->base.num_glyphs, + font->scaled_font_subset->glyphs[i], + &index); + if (unlikely(status)) + return status; + + cairo_type1_font_subset_use_glyph (font, index); + font->scaled_subset_index_to_glyphs[i] = index; + } + + /* Go through the charstring of each glyph in use, get the glyph + * width and figure out which extra glyphs may be required by the + * seac operator (which may cause font->num_glyphs to increase + * while this loop is executing). Also subset the Subrs. */ + for (j = 0; j < font->num_glyphs; j++) { + glyph = font->type1_subset_index_to_glyphs[j]; + font->build_stack.sp = 0; + font->ps_stack.sp = 0; + status = cairo_type1_font_subset_parse_charstring (font, + glyph, + font->glyphs[glyph].encrypted_charstring, + font->glyphs[glyph].encrypted_charstring_length); + if (unlikely (status)) + return status; + } + + /* Always include the first five subroutines in case the Flex/hint mechanism is + * being used. */ + for (j = 0; j < MIN (font->num_subrs, 5); j++) { + font->subrs[j].used = TRUE; + } + + closefile_token = find_token (dict_end, font->cleartext_end, "closefile"); + if (closefile_token == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* We're ready to start outputting. First write the header, + * i.e. the public part of the font dict.*/ + status = cairo_type1_font_subset_write_header (font, name); + if (unlikely (status)) + return status; + + font->base.header_size = _cairo_output_stream_get_position (font->output); + + /* Start outputting the private dict */ + if (font->subset_subrs) { + /* First output everything up to the start of the Subrs array. */ + status = cairo_type1_font_subset_write_encrypted (font, font->cleartext, + array_start - font->cleartext); + if (unlikely (status)) + return status; + + /* Write out the subr definitions for each of the glyphs in + * the subset. */ + status = cairo_type1_font_for_each_subr (font, + array_start, + font->cleartext_end, + write_used_subrs, + &p); + if (unlikely (status)) + return status; + } else { + p = font->cleartext; + } + + /* If subr subsetting, output everything from end of subrs to + * start of /CharStrings token. If not subr subsetting, output + * everything start of private dict to start of /CharStrings + * token. */ + status = cairo_type1_font_subset_write_encrypted (font, p, charstrings - p); + if (unlikely (status)) + return status; + + /* Write out new charstring count */ + length = snprintf (buffer, sizeof buffer, + "/CharStrings %d", font->num_glyphs); + status = cairo_type1_font_subset_write_encrypted (font, buffer, length); + if (unlikely (status)) + return status; + + /* Write out text between the charstring count and the first + * charstring definition */ + status = cairo_type1_font_subset_write_encrypted (font, glyph_count_end, + dict_start - glyph_count_end); + if (unlikely (status)) + return status; + + /* Write out the charstring definitions for each of the glyphs in + * the subset. */ + status = cairo_type1_font_subset_for_each_glyph (font, + dict_start, + font->cleartext_end, + write_used_glyphs, + &p); + if (unlikely (status)) + return status; + + /* Output what's left between the end of the glyph definitions and + * the end of the private dict to the output. */ + status = cairo_type1_font_subset_write_encrypted (font, p, + closefile_token - p + strlen ("closefile") + 1); + if (unlikely (status)) + return status; + + if (font->hex_encode) + _cairo_output_stream_write (font->output, "\n", 1); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +cairo_type1_font_subset_write_trailer(cairo_type1_font_subset_t *font) +{ + const char *cleartomark_token; + int i; + static const char zeros[65] = + "0000000000000000000000000000000000000000000000000000000000000000\n"; + + + for (i = 0; i < 8; i++) + _cairo_output_stream_write (font->output, zeros, sizeof zeros); + + cleartomark_token = find_token (font->type1_data, font->type1_end, "cleartomark"); + if (cleartomark_token) { + /* Some fonts have conditional save/restore around the entire + * font dict, so we need to retain whatever postscript code + * that may come after 'cleartomark'. */ + + _cairo_output_stream_write (font->output, cleartomark_token, + font->type1_end - cleartomark_token); + if (*(font->type1_end - 1) != '\n') + _cairo_output_stream_printf (font->output, "\n"); + + } else if (!font->eexec_segment_is_ascii) { + /* Fonts embedded in PDF may omit the fixed-content portion + * that includes the 'cleartomark' operator. Type 1 in PDF is + * always binary. */ + + _cairo_output_stream_printf (font->output, "cleartomark\n"); + } else { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + /* some fonts do not have a newline at the end of the last line */ + _cairo_output_stream_printf (font->output, "\n"); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +type1_font_write (void *closure, const unsigned char *data, unsigned int length) +{ + cairo_type1_font_subset_t *font = closure; + + return _cairo_array_append_multiple (&font->contents, data, length); +} + +static cairo_status_t +cairo_type1_font_subset_write (cairo_type1_font_subset_t *font, + const char *name) +{ + cairo_status_t status; + + status = cairo_type1_font_subset_find_segments (font); + if (unlikely (status)) + return status; + + status = cairo_type1_font_subset_decrypt_eexec_segment (font); + if (unlikely (status)) + return status; + + /* Determine which glyph definition delimiters to use. */ + if (find_token (font->cleartext, font->cleartext_end, "/-|") != NULL) { + font->rd = "-|"; + font->nd = "|-"; + font->np = "|"; + } else if (find_token (font->cleartext, font->cleartext_end, "/RD") != NULL) { + font->rd = "RD"; + font->nd = "ND"; + font->np = "NP"; + } else { + /* Don't know *what* kind of font this is... */ + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + font->eexec_key = CAIRO_TYPE1_PRIVATE_DICT_KEY; + font->hex_column = 0; + + status = cairo_type1_font_subset_get_bbox (font); + if (unlikely (status)) + return status; + + status = cairo_type1_font_subset_get_fontname (font); + if (unlikely (status)) + return status; + + status = cairo_type1_font_subset_write_private_dict (font, name); + if (unlikely (status)) + return status; + + font->base.data_size = _cairo_output_stream_get_position (font->output) - + font->base.header_size; + + status = cairo_type1_font_subset_write_trailer (font); + if (unlikely (status)) + return status; + + font->base.trailer_size = + _cairo_output_stream_get_position (font->output) - + font->base.header_size - font->base.data_size; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_bool_t +check_fontdata_is_type1 (const unsigned char *data, long length) +{ + /* Test for Type 1 Binary (PFB) */ + if (length > 2 && data[0] == 0x80 && data[1] == 0x01) + return TRUE; + + /* Test for Type 1 1 ASCII (PFA) */ + if (length > 2 && data[0] == '%' && data[1] == '!') + return TRUE; + + return FALSE; +} + +static cairo_status_t +cairo_type1_font_subset_generate (void *abstract_font, + const char *name) + +{ + cairo_type1_font_subset_t *font = abstract_font; + cairo_scaled_font_t *scaled_font; + cairo_status_t status; + unsigned long data_length; + + scaled_font = font->scaled_font_subset->scaled_font; + if (!scaled_font->backend->load_type1_data) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = scaled_font->backend->load_type1_data (scaled_font, 0, NULL, &data_length); + if (status) + return CAIRO_INT_STATUS_UNSUPPORTED; + + font->type1_length = data_length; + font->type1_data = _cairo_malloc (font->type1_length); + if (unlikely (font->type1_data == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + status = scaled_font->backend->load_type1_data (scaled_font, 0, + (unsigned char *) font->type1_data, + &data_length); + if (unlikely (status)) + return status; + + if (!check_fontdata_is_type1 ((unsigned char *)font->type1_data, data_length)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_array_grow_by (&font->contents, 4096); + if (unlikely (status)) + return status; + + font->output = _cairo_output_stream_create (type1_font_write, NULL, font); + if (unlikely ((status = font->output->status))) + return status; + + status = cairo_type1_font_subset_write (font, name); + if (unlikely (status)) + return status; + + font->base.data = _cairo_array_index (&font->contents, 0); + + return status; +} + +static cairo_status_t +_cairo_type1_font_subset_fini (cairo_type1_font_subset_t *font) +{ + cairo_status_t status = CAIRO_STATUS_SUCCESS; + unsigned int i; + + /* If the subset generation failed, some of the pointers below may + * be NULL depending on at which point the error occurred. */ + + _cairo_array_fini (&font->contents); + + free (font->type1_data); + for (i = 0; i < _cairo_array_num_elements (&font->glyph_names_array); i++) { + char **s; + + s = _cairo_array_index (&font->glyph_names_array, i); + free (*s); + } + _cairo_array_fini (&font->glyph_names_array); + _cairo_array_fini (&font->glyphs_array); + + free (font->subrs); + + if (font->output != NULL) + status = _cairo_output_stream_destroy (font->output); + + free (font->base.base_font); + + free (font->scaled_subset_index_to_glyphs); + + free (font->type1_subset_index_to_glyphs); + + free (font->cleartext); + + return status; +} + +cairo_status_t +_cairo_type1_subset_init (cairo_type1_subset_t *type1_subset, + const char *name, + cairo_scaled_font_subset_t *scaled_font_subset, + cairo_bool_t hex_encode) +{ + cairo_type1_font_subset_t font; + cairo_status_t status; + cairo_bool_t is_synthetic; + unsigned long length; + unsigned int i; + char buf[30]; + int glyph; + + /* We need to use a fallback font if this font differs from the type1 outlines. */ + if (scaled_font_subset->scaled_font->backend->is_synthetic) { + status = scaled_font_subset->scaled_font->backend->is_synthetic (scaled_font_subset->scaled_font, &is_synthetic); + if (unlikely (status)) + return status; + + if (is_synthetic) + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + status = _cairo_type1_font_subset_init (&font, scaled_font_subset, hex_encode); + if (unlikely (status)) + return status; + + status = cairo_type1_font_subset_generate (&font, name); + if (unlikely (status)) + goto fail1; + + if (font.base.base_font) { + type1_subset->base_font = strdup (font.base.base_font); + } else { + snprintf(buf, sizeof (buf), "CairoFont-%u-%u", + scaled_font_subset->font_id, scaled_font_subset->subset_id); + type1_subset->base_font = strdup (buf); + } + if (unlikely (type1_subset->base_font == NULL)) + goto fail1; + + type1_subset->widths = _cairo_calloc_ab (scaled_font_subset->num_glyphs, sizeof (double)); + if (unlikely (type1_subset->widths == NULL)) + goto fail2; + + for (i = 0; i < font.scaled_font_subset->num_glyphs; i++) { + glyph = font.scaled_subset_index_to_glyphs[i]; + type1_subset->widths[i] = font.glyphs[glyph].width; + } + + type1_subset->x_min = font.base.x_min; + type1_subset->y_min = font.base.y_min; + type1_subset->x_max = font.base.x_max; + type1_subset->y_max = font.base.y_max; + type1_subset->ascent = font.base.ascent; + type1_subset->descent = font.base.descent; + + length = font.base.header_size + + font.base.data_size + + font.base.trailer_size; + type1_subset->data = _cairo_malloc (length); + if (unlikely (type1_subset->data == NULL)) + goto fail3; + + memcpy (type1_subset->data, + _cairo_array_index (&font.contents, 0), length); + + type1_subset->header_length = font.base.header_size; + type1_subset->data_length = font.base.data_size; + type1_subset->trailer_length = font.base.trailer_size; + + return _cairo_type1_font_subset_fini (&font); + + fail3: + free (type1_subset->widths); + fail2: + free (type1_subset->base_font); + fail1: + _cairo_type1_font_subset_fini (&font); + + return status; +} + +void +_cairo_type1_subset_fini (cairo_type1_subset_t *subset) +{ + free (subset->base_font); + free (subset->widths); + free (subset->data); +} + +cairo_bool_t +_cairo_type1_scaled_font_is_type1 (cairo_scaled_font_t *scaled_font) +{ + cairo_status_t status; + unsigned long length; + unsigned char buf[64]; + + if (!scaled_font->backend->load_type1_data) + return FALSE; + + status = scaled_font->backend->load_type1_data (scaled_font, 0, NULL, &length); + if (status) + return FALSE; + + /* We only need a few bytes to test for Type 1 */ + if (length > sizeof (buf)) + length = sizeof (buf); + + status = scaled_font->backend->load_type1_data (scaled_font, 0, buf, &length); + if (status) + return FALSE; + + return check_fontdata_is_type1 (buf, length); +} + +#endif /* CAIRO_HAS_FONT_SUBSET */ diff --git a/local/recipes/libs/cairo/source/src/cairo-type3-glyph-surface-private.h b/local/recipes/libs/cairo/source/src/cairo-type3-glyph-surface-private.h new file mode 100644 index 0000000000..6f40f1c25b --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-type3-glyph-surface-private.h @@ -0,0 +1,89 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2008 Adrian Johnson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Adrian Johnson. + * + * Contributor(s): + * Adrian Johnson + */ + +#ifndef CAIRO_TYPE3_GLYPH_SURFACE_PRIVATE_H +#define CAIRO_TYPE3_GLYPH_SURFACE_PRIVATE_H + +#include "cairoint.h" + +#if CAIRO_HAS_FONT_SUBSET + +#include "cairo-surface-private.h" +#include "cairo-surface-clipper-private.h" +#include "cairo-pdf-operators-private.h" + +typedef cairo_int_status_t +(*cairo_type3_glyph_surface_emit_image_t) (cairo_image_surface_t *image, + cairo_output_stream_t *stream); + +typedef struct cairo_type3_glyph_surface { + cairo_surface_t base; + + cairo_scaled_font_t *scaled_font; + cairo_output_stream_t *stream; + cairo_pdf_operators_t pdf_operators; + cairo_matrix_t cairo_to_pdf; + cairo_type3_glyph_surface_emit_image_t emit_image; + + cairo_surface_clipper_t clipper; +} cairo_type3_glyph_surface_t; + +cairo_private cairo_surface_t * +_cairo_type3_glyph_surface_create (cairo_scaled_font_t *scaled_font, + cairo_output_stream_t *stream, + cairo_type3_glyph_surface_emit_image_t emit_image, + cairo_scaled_font_subsets_t *font_subsets, + cairo_bool_t ps_output); + +cairo_private void +_cairo_type3_glyph_surface_set_font_subsets_callback (void *abstract_surface, + cairo_pdf_operators_use_font_subset_t use_font_subset, + void *closure); + +cairo_private cairo_status_t +_cairo_type3_glyph_surface_analyze_glyph (void *abstract_surface, + unsigned long glyph_index); + +cairo_private cairo_status_t +_cairo_type3_glyph_surface_emit_glyph (void *abstract_surface, + cairo_output_stream_t *stream, + unsigned long glyph_index, + cairo_box_t *bbox, + double *width); + +#endif /* CAIRO_HAS_FONT_SUBSET */ + +#endif /* CAIRO_TYPE3_GLYPH_SURFACE_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-type3-glyph-surface.c b/local/recipes/libs/cairo/source/src/cairo-type3-glyph-surface.c new file mode 100644 index 0000000000..bb77756a15 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-type3-glyph-surface.c @@ -0,0 +1,553 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2008 Adrian Johnson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Adrian Johnson. + * + * Contributor(s): + * Adrian Johnson + */ + +#include "cairoint.h" + +#if CAIRO_HAS_FONT_SUBSET + +#include "cairo-type3-glyph-surface-private.h" +#include "cairo-output-stream-private.h" +#include "cairo-recording-surface-private.h" +#include "cairo-analysis-surface-private.h" +#include "cairo-default-context-private.h" +#include "cairo-error-private.h" +#include "cairo-image-surface-private.h" +#include "cairo-surface-clipper-private.h" + +static const cairo_surface_backend_t cairo_type3_glyph_surface_backend; + +static cairo_status_t +_cairo_type3_glyph_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_type3_glyph_surface_t *surface = cairo_container_of (clipper, + cairo_type3_glyph_surface_t, + clipper); + + if (path == NULL) { + _cairo_output_stream_printf (surface->stream, "Q q\n"); + return CAIRO_STATUS_SUCCESS; + } + + return _cairo_pdf_operators_clip (&surface->pdf_operators, + path, + fill_rule); +} + +cairo_surface_t * +_cairo_type3_glyph_surface_create (cairo_scaled_font_t *scaled_font, + cairo_output_stream_t *stream, + cairo_type3_glyph_surface_emit_image_t emit_image, + cairo_scaled_font_subsets_t *font_subsets, + cairo_bool_t ps) +{ + cairo_type3_glyph_surface_t *surface; + + if (unlikely (stream != NULL && stream->status)) + return _cairo_surface_create_in_error (stream->status); + + surface = _cairo_calloc (sizeof (cairo_type3_glyph_surface_t)); + if (unlikely (surface == NULL)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + _cairo_surface_init (&surface->base, + &cairo_type3_glyph_surface_backend, + NULL, /* device */ + CAIRO_CONTENT_COLOR_ALPHA, + TRUE); /* is_vector */ + + surface->scaled_font = scaled_font; + surface->stream = stream; + surface->emit_image = emit_image; + + /* Setup the transform from the user-font device space to Type 3 + * font space. The Type 3 font space is defined by the FontMatrix + * entry in the Type 3 dictionary. In the PDF backend this is an + * identity matrix. */ + surface->cairo_to_pdf = scaled_font->scale_inverse; + + _cairo_pdf_operators_init (&surface->pdf_operators, + surface->stream, + &surface->cairo_to_pdf, + font_subsets, + ps); + + _cairo_surface_clipper_init (&surface->clipper, + _cairo_type3_glyph_surface_clipper_intersect_clip_path); + + return &surface->base; +} + +static cairo_status_t +_cairo_type3_glyph_surface_emit_image (cairo_type3_glyph_surface_t *surface, + cairo_image_surface_t *image, + cairo_matrix_t *image_matrix) +{ + cairo_status_t status; + + /* The only image type supported by Type 3 fonts are 1-bit masks */ + image = _cairo_image_surface_coerce_to_format (image, CAIRO_FORMAT_A1); + status = image->base.status; + if (unlikely (status)) + return status; + + _cairo_output_stream_printf (surface->stream, + "q %f %f %f %f %f %f cm\n", + image_matrix->xx, + image_matrix->xy, + image_matrix->yx, + image_matrix->yy, + image_matrix->x0, + image_matrix->y0); + + status = surface->emit_image (image, surface->stream); + cairo_surface_destroy (&image->base); + + _cairo_output_stream_printf (surface->stream, + "Q\n"); + + return status; +} + +static cairo_status_t +_cairo_type3_glyph_surface_emit_image_pattern (cairo_type3_glyph_surface_t *surface, + cairo_image_surface_t *image, + const cairo_matrix_t *pattern_matrix) +{ + cairo_matrix_t mat, upside_down; + cairo_status_t status; + + if (image->width == 0 || image->height == 0) + return CAIRO_STATUS_SUCCESS; + + mat = *pattern_matrix; + + /* Get the pattern space to user space matrix */ + status = cairo_matrix_invert (&mat); + + /* cairo_pattern_set_matrix ensures the matrix is invertible */ + assert (status == CAIRO_STATUS_SUCCESS); + + /* Make this a pattern space to Type 3 font space matrix */ + cairo_matrix_multiply (&mat, &mat, &surface->cairo_to_pdf); + + /* PDF images are in a 1 unit by 1 unit image space. Turn the 1 by + * 1 image upside down to convert to flip the Y-axis going from + * cairo to PDF. Then scale the image up to the required size. */ + cairo_matrix_scale (&mat, image->width, image->height); + cairo_matrix_init (&upside_down, 1, 0, 0, -1, 0, 1); + cairo_matrix_multiply (&mat, &upside_down, &mat); + + return _cairo_type3_glyph_surface_emit_image (surface, image, &mat); +} + +static cairo_status_t +_cairo_type3_glyph_surface_finish (void *abstract_surface) +{ + cairo_type3_glyph_surface_t *surface = abstract_surface; + + cairo_status_t status = _cairo_pdf_operators_fini (&surface->pdf_operators); + _cairo_surface_clipper_reset (&surface->clipper); + return status; +} + +static cairo_int_status_t +_cairo_type3_glyph_surface_paint (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip) +{ + cairo_type3_glyph_surface_t *surface = abstract_surface; + const cairo_surface_pattern_t *pattern; + cairo_image_surface_t *image; + void *image_extra; + cairo_status_t status; + + if (source->type != CAIRO_PATTERN_TYPE_SURFACE) + return CAIRO_INT_STATUS_IMAGE_FALLBACK; + + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) + return status; + + pattern = (const cairo_surface_pattern_t *) source; + if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) + return CAIRO_INT_STATUS_IMAGE_FALLBACK; + + status = _cairo_surface_acquire_source_image (pattern->surface, + &image, &image_extra); + if (unlikely (status)) + goto fail; + + status = _cairo_type3_glyph_surface_emit_image_pattern (surface, + image, + &pattern->base.matrix); + +fail: + _cairo_surface_release_source_image (pattern->surface, image, image_extra); + + return status; +} + +static cairo_int_status_t +_cairo_type3_glyph_surface_mask (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_clip_t *clip) +{ + return _cairo_type3_glyph_surface_paint (abstract_surface, + op, mask, + clip); +} + +static cairo_int_status_t +_cairo_type3_glyph_surface_stroke (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_type3_glyph_surface_t *surface = abstract_surface; + cairo_int_status_t status; + + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) + return status; + + return _cairo_pdf_operators_stroke (&surface->pdf_operators, + path, + style, + ctm, + ctm_inverse); +} + +static cairo_int_status_t +_cairo_type3_glyph_surface_fill (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_type3_glyph_surface_t *surface = abstract_surface; + cairo_int_status_t status; + + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) + return status; + + return _cairo_pdf_operators_fill (&surface->pdf_operators, + path, + fill_rule); +} + +static cairo_int_status_t +_cairo_type3_glyph_surface_show_glyphs (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip) +{ + return CAIRO_INT_STATUS_IMAGE_FALLBACK; +} + +static const cairo_surface_backend_t cairo_type3_glyph_surface_backend = { + CAIRO_INTERNAL_SURFACE_TYPE_TYPE3_GLYPH, + _cairo_type3_glyph_surface_finish, + + _cairo_default_context_create, /* XXX usable through a context? */ + + NULL, /* create similar */ + NULL, /* create similar image */ + NULL, /* map to image */ + NULL, /* unmap image */ + + NULL, /* source */ + NULL, /* acquire_source_image */ + NULL, /* release_source_image */ + NULL, /* snapshot */ + + NULL, /* copy page */ + NULL, /* show page */ + + NULL, /* _cairo_type3_glyph_surface_get_extents */ + NULL, /* _cairo_type3_glyph_surface_get_font_options */ + + NULL, /* flush */ + NULL, /* mark_dirty_rectangle */ + + _cairo_type3_glyph_surface_paint, + _cairo_type3_glyph_surface_mask, + _cairo_type3_glyph_surface_stroke, + _cairo_type3_glyph_surface_fill, + NULL, /* fill-stroke */ + _cairo_type3_glyph_surface_show_glyphs, +}; + +static void +_cairo_type3_glyph_surface_set_stream (cairo_type3_glyph_surface_t *surface, + cairo_output_stream_t *stream) +{ + surface->stream = stream; + _cairo_pdf_operators_set_stream (&surface->pdf_operators, stream); +} + +static cairo_status_t +_cairo_type3_glyph_surface_emit_fallback_image (cairo_type3_glyph_surface_t *surface, + unsigned long glyph_index) +{ + cairo_scaled_glyph_t *scaled_glyph; + cairo_status_t status; + cairo_image_surface_t *image; + cairo_matrix_t mat; + double x, y; + + status = _cairo_scaled_glyph_lookup (surface->scaled_font, + glyph_index, + CAIRO_SCALED_GLYPH_INFO_METRICS | + CAIRO_SCALED_GLYPH_INFO_SURFACE, + NULL, /* foreground color */ + &scaled_glyph); + if (unlikely (status)) + return status; + + image = scaled_glyph->surface; + if (image->width == 0 || image->height == 0) + return CAIRO_STATUS_SUCCESS; + + x = _cairo_fixed_to_double (scaled_glyph->bbox.p1.x); + y = _cairo_fixed_to_double (scaled_glyph->bbox.p2.y); + cairo_matrix_init(&mat, image->width, 0, + 0, -image->height, + x, y); + cairo_matrix_multiply (&mat, &mat, &surface->scaled_font->scale_inverse); + + return _cairo_type3_glyph_surface_emit_image (surface, image, &mat); +} + +void +_cairo_type3_glyph_surface_set_font_subsets_callback (void *abstract_surface, + cairo_pdf_operators_use_font_subset_t use_font_subset, + void *closure) +{ + cairo_type3_glyph_surface_t *surface = abstract_surface; + + if (unlikely (surface->base.status)) + return; + + _cairo_pdf_operators_set_font_subsets_callback (&surface->pdf_operators, + use_font_subset, + closure); +} + +cairo_status_t +_cairo_type3_glyph_surface_analyze_glyph (void *abstract_surface, + unsigned long glyph_index) +{ + cairo_type3_glyph_surface_t *surface = abstract_surface; + cairo_scaled_glyph_t *scaled_glyph; + cairo_int_status_t status, status2; + cairo_output_stream_t *null_stream; + + if (unlikely (surface->base.status)) + return surface->base.status; + + null_stream = _cairo_null_stream_create (); + if (unlikely (null_stream->status)) + return null_stream->status; + + _cairo_type3_glyph_surface_set_stream (surface, null_stream); + + _cairo_scaled_font_freeze_cache (surface->scaled_font); + status = _cairo_scaled_glyph_lookup (surface->scaled_font, + glyph_index, + CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE, + NULL, /* foreground color */ + &scaled_glyph); + + if (_cairo_int_status_is_error (status)) + goto cleanup; + + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + status = CAIRO_INT_STATUS_SUCCESS; + goto cleanup; + } + + status = _cairo_recording_surface_replay (scaled_glyph->recording_surface, + &surface->base); + if (unlikely (status)) + goto cleanup; + + status = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) + status = CAIRO_INT_STATUS_SUCCESS; + +cleanup: + _cairo_scaled_font_thaw_cache (surface->scaled_font); + + status2 = _cairo_output_stream_destroy (null_stream); + if (status == CAIRO_INT_STATUS_SUCCESS) + status = status2; + + return status; +} + +cairo_status_t +_cairo_type3_glyph_surface_emit_glyph (void *abstract_surface, + cairo_output_stream_t *stream, + unsigned long glyph_index, + cairo_box_t *bbox, + double *width) +{ + cairo_type3_glyph_surface_t *surface = abstract_surface; + cairo_scaled_glyph_t *scaled_glyph; + cairo_int_status_t status, status2; + double x_advance, y_advance; + cairo_matrix_t font_matrix_inverse; + + if (unlikely (surface->base.status)) + return surface->base.status; + + _cairo_type3_glyph_surface_set_stream (surface, stream); + + _cairo_scaled_font_freeze_cache (surface->scaled_font); + + /* Check if this is a color glyph and bail out if it is */ + status = _cairo_scaled_glyph_lookup (surface->scaled_font, + glyph_index, + CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE, + NULL, /* foreground color */ + &scaled_glyph); + if (status == CAIRO_INT_STATUS_SUCCESS) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto FAIL; + } status = _cairo_scaled_glyph_lookup (surface->scaled_font, + glyph_index, + CAIRO_SCALED_GLYPH_INFO_METRICS | + CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE, + NULL, /* foreground color */ + &scaled_glyph); + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + status = _cairo_scaled_glyph_lookup (surface->scaled_font, + glyph_index, + CAIRO_SCALED_GLYPH_INFO_METRICS, + NULL, /* foreground color */ + &scaled_glyph); + if (status == CAIRO_INT_STATUS_SUCCESS) + status = CAIRO_INT_STATUS_IMAGE_FALLBACK; + } + if (_cairo_int_status_is_error (status)) { + _cairo_scaled_font_thaw_cache (surface->scaled_font); + return status; + } + + x_advance = scaled_glyph->metrics.x_advance; + y_advance = scaled_glyph->metrics.y_advance; + font_matrix_inverse = surface->scaled_font->font_matrix; + status2 = cairo_matrix_invert (&font_matrix_inverse); + + /* The invertability of font_matrix is tested in + * pdf_operators_show_glyphs before any glyphs are mapped to the + * subset. */ + assert (status2 == CAIRO_INT_STATUS_SUCCESS); + + cairo_matrix_transform_distance (&font_matrix_inverse, &x_advance, &y_advance); + *width = x_advance; + + *bbox = scaled_glyph->bbox; + _cairo_matrix_transform_bounding_box_fixed (&surface->scaled_font->scale_inverse, + bbox, NULL); + + _cairo_output_stream_printf (surface->stream, + "%f 0 %f %f %f %f d1\n", + x_advance, + _cairo_fixed_to_double (bbox->p1.x), + _cairo_fixed_to_double (bbox->p1.y), + _cairo_fixed_to_double (bbox->p2.x), + _cairo_fixed_to_double (bbox->p2.y)); + + if (status == CAIRO_INT_STATUS_SUCCESS) { + cairo_output_stream_t *mem_stream; + + mem_stream = _cairo_memory_stream_create (); + status = mem_stream->status; + if (unlikely (status)) + goto FAIL; + + _cairo_type3_glyph_surface_set_stream (surface, mem_stream); + + _cairo_output_stream_printf (surface->stream, "q\n"); + status = _cairo_recording_surface_replay (scaled_glyph->recording_surface, + &surface->base); + + status2 = _cairo_pdf_operators_flush (&surface->pdf_operators); + if (status == CAIRO_INT_STATUS_SUCCESS) + status = status2; + + _cairo_output_stream_printf (surface->stream, "Q\n"); + + _cairo_type3_glyph_surface_set_stream (surface, stream); + if (status == CAIRO_INT_STATUS_SUCCESS) + _cairo_memory_stream_copy (mem_stream, stream); + + status2 = _cairo_output_stream_destroy (mem_stream); + if (status == CAIRO_INT_STATUS_SUCCESS) + status = status2; + } + + if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) + status = _cairo_type3_glyph_surface_emit_fallback_image (surface, glyph_index); + + FAIL: + _cairo_scaled_font_thaw_cache (surface->scaled_font); + + return status; +} + +#endif /* CAIRO_HAS_FONT_SUBSET */ diff --git a/local/recipes/libs/cairo/source/src/cairo-types-private.h b/local/recipes/libs/cairo/source/src/cairo-types-private.h new file mode 100644 index 0000000000..74a366c23c --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-types-private.h @@ -0,0 +1,453 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + */ + +#ifndef CAIRO_TYPES_PRIVATE_H +#define CAIRO_TYPES_PRIVATE_H + +#include "cairo.h" +#include "cairo-fixed-type-private.h" +#include "cairo-list-private.h" +#include "cairo-reference-count-private.h" + +CAIRO_BEGIN_DECLS + +/** + * SECTION:cairo-types + * @Title: Types + * @Short_Description: Generic data types + * + * This section lists generic data types used in the cairo API. + **/ + +typedef struct _cairo_array cairo_array_t; +typedef struct _cairo_backend cairo_backend_t; +typedef struct _cairo_boxes_t cairo_boxes_t; +typedef struct _cairo_cache cairo_cache_t; +typedef struct _cairo_composite_rectangles cairo_composite_rectangles_t; +typedef struct _cairo_clip cairo_clip_t; +typedef struct _cairo_clip_path cairo_clip_path_t; +typedef struct _cairo_color cairo_color_t; +typedef struct _cairo_color_stop cairo_color_stop_t; +typedef struct _cairo_contour cairo_contour_t; +typedef struct _cairo_contour_chain cairo_contour_chain_t; +typedef struct _cairo_contour_iter cairo_contour_iter_t; +typedef struct _cairo_damage cairo_damage_t; +typedef struct _cairo_device_backend cairo_device_backend_t; +typedef struct _cairo_font_face_backend cairo_font_face_backend_t; +typedef struct _cairo_gstate cairo_gstate_t; +typedef struct _cairo_gstate_backend cairo_gstate_backend_t; +typedef struct _cairo_glyph_text_info cairo_glyph_text_info_t; +typedef struct _cairo_hash_entry cairo_hash_entry_t; +typedef struct _cairo_hash_table cairo_hash_table_t; +typedef struct _cairo_image_surface cairo_image_surface_t; +typedef struct _cairo_mime_data cairo_mime_data_t; +typedef struct _cairo_observer cairo_observer_t; +typedef struct _cairo_output_stream cairo_output_stream_t; +typedef struct _cairo_paginated_surface_backend cairo_paginated_surface_backend_t; +typedef struct _cairo_path_fixed cairo_path_fixed_t; +typedef struct _cairo_rectangle_int16 cairo_glyph_size_t; +typedef struct _cairo_scaled_font_subsets cairo_scaled_font_subsets_t; +typedef struct _cairo_solid_pattern cairo_solid_pattern_t; +typedef struct _cairo_surface_attributes cairo_surface_attributes_t; +typedef struct _cairo_surface_backend cairo_surface_backend_t; +typedef struct _cairo_surface_observer cairo_surface_observer_t; +typedef struct _cairo_surface_snapshot cairo_surface_snapshot_t; +typedef struct _cairo_surface_subsurface cairo_surface_subsurface_t; +typedef struct _cairo_surface_wrapper cairo_surface_wrapper_t; +typedef struct _cairo_traps cairo_traps_t; +typedef struct _cairo_tristrip cairo_tristrip_t; +typedef struct _cairo_unscaled_font_backend cairo_unscaled_font_backend_t; +typedef struct _cairo_xlib_screen_info cairo_xlib_screen_info_t; + +typedef cairo_array_t cairo_user_data_array_t; + +typedef struct _cairo_scaled_font_private cairo_scaled_font_private_t; +typedef struct _cairo_scaled_font_backend cairo_scaled_font_backend_t; +typedef struct _cairo_scaled_glyph cairo_scaled_glyph_t; +typedef struct _cairo_scaled_glyph_private cairo_scaled_glyph_private_t; + +typedef struct cairo_compositor cairo_compositor_t; +typedef struct cairo_fallback_compositor cairo_fallback_compositor_t; +typedef struct cairo_mask_compositor cairo_mask_compositor_t; +typedef struct cairo_traps_compositor cairo_traps_compositor_t; +typedef struct cairo_spans_compositor cairo_spans_compositor_t; + +struct _cairo_observer { + cairo_list_t link; + void (*callback) (cairo_observer_t *self, void *arg); +}; + +/** + * _cairo_hash_entry: + * + * A #cairo_hash_entry_t contains both a key and a value for + * #cairo_hash_table_t. User-derived types for #cairo_hash_entry_t must + * be type-compatible with this structure (eg. they must have a + * uintptr_t as the first parameter. The easiest way to get this + * is to use: + * + * typedef _my_entry { + * cairo_hash_entry_t base; + * ... Remainder of key and value fields here .. + * } my_entry_t; + * + * which then allows a pointer to my_entry_t to be passed to any of + * the #cairo_hash_table_t functions as follows without requiring a cast: + * + * _cairo_hash_table_insert (hash_table, &my_entry->base); + * + * IMPORTANT: The caller is responsible for initializing + * my_entry->base.hash with a hash code derived from the key. The + * essential property of the hash code is that keys_equal must never + * return %TRUE for two keys that have different hashes. The best hash + * code will reduce the frequency of two keys with the same code for + * which keys_equal returns %FALSE. + * + * Which parts of the entry make up the "key" and which part make up + * the value are entirely up to the caller, (as determined by the + * computation going into base.hash as well as the keys_equal + * function). A few of the #cairo_hash_table_t functions accept an entry + * which will be used exclusively as a "key", (indicated by a + * parameter name of key). In these cases, the value-related fields of + * the entry need not be initialized if so desired. + **/ +struct _cairo_hash_entry { + uintptr_t hash; +}; + +struct _cairo_array { + unsigned int size; + unsigned int num_elements; + unsigned int element_size; + char *elements; +}; + +/** + * _cairo_lcd_filter: + * @CAIRO_LCD_FILTER_DEFAULT: Use the default LCD filter for + * font backend and target device + * @CAIRO_LCD_FILTER_NONE: Do not perform LCD filtering + * @CAIRO_LCD_FILTER_INTRA_PIXEL: Intra-pixel filter + * @CAIRO_LCD_FILTER_FIR3: FIR filter with a 3x3 kernel + * @CAIRO_LCD_FILTER_FIR5: FIR filter with a 5x5 kernel + * + * The LCD filter specifies the low-pass filter applied to LCD-optimized + * bitmaps generated with an antialiasing mode of %CAIRO_ANTIALIAS_SUBPIXEL. + * + * Note: This API was temporarily made available in the public + * interface during the 1.7.x development series, but was made private + * before 1.8. + **/ +typedef enum _cairo_lcd_filter { + CAIRO_LCD_FILTER_DEFAULT, + CAIRO_LCD_FILTER_NONE, + CAIRO_LCD_FILTER_INTRA_PIXEL, + CAIRO_LCD_FILTER_FIR3, + CAIRO_LCD_FILTER_FIR5 +} cairo_lcd_filter_t; + +typedef enum _cairo_round_glyph_positions { + CAIRO_ROUND_GLYPH_POS_DEFAULT, + CAIRO_ROUND_GLYPH_POS_ON, + CAIRO_ROUND_GLYPH_POS_OFF +} cairo_round_glyph_positions_t; + +typedef struct { + unsigned int index; + double red, green, blue, alpha; +} cairo_palette_color_t; + +struct _cairo_font_options { + cairo_antialias_t antialias; + cairo_subpixel_order_t subpixel_order; + cairo_lcd_filter_t lcd_filter; + cairo_hint_style_t hint_style; + cairo_hint_metrics_t hint_metrics; + cairo_round_glyph_positions_t round_glyph_positions; + char *variations; + cairo_color_mode_t color_mode; + unsigned int palette_index; + cairo_palette_color_t *custom_palette; + unsigned int custom_palette_size; +}; + +struct _cairo_glyph_text_info { + const char *utf8; + int utf8_len; + + const cairo_text_cluster_t *clusters; + int num_clusters; + cairo_text_cluster_flags_t cluster_flags; +}; + + +/* XXX: Right now, the _cairo_color structure puts unpremultiplied + color in the doubles and premultiplied color in the shorts. Yes, + this is crazy insane, (but at least we don't export this + madness). I'm still working on a cleaner API, but in the meantime, + at least this does prevent precision loss in color when changing + alpha. */ +struct _cairo_color { + double red; + double green; + double blue; + double alpha; + + unsigned short red_short; + unsigned short green_short; + unsigned short blue_short; + unsigned short alpha_short; +}; + +struct _cairo_color_stop { + /* unpremultiplied */ + double red; + double green; + double blue; + double alpha; + + /* unpremultipled, for convenience */ + uint16_t red_short; + uint16_t green_short; + uint16_t blue_short; + uint16_t alpha_short; +}; + +typedef enum _cairo_paginated_mode { + CAIRO_PAGINATED_MODE_ANALYZE, /* analyze page regions */ + CAIRO_PAGINATED_MODE_RENDER, /* render page contents */ + CAIRO_PAGINATED_MODE_FALLBACK /* paint fallback images */ +} cairo_paginated_mode_t; + +typedef enum _cairo_internal_surface_type { + CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT = 0x1000, + CAIRO_INTERNAL_SURFACE_TYPE_PAGINATED, + CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS, + CAIRO_INTERNAL_SURFACE_TYPE_OBSERVER, + CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK, + CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED, + CAIRO_INTERNAL_SURFACE_TYPE_TEST_WRAPPING, + CAIRO_INTERNAL_SURFACE_TYPE_NULL, + CAIRO_INTERNAL_SURFACE_TYPE_TYPE3_GLYPH, + CAIRO_INTERNAL_SURFACE_TYPE_QUARTZ_SNAPSHOT +} cairo_internal_surface_type_t; + +typedef enum _cairo_internal_device_type { + CAIRO_INTERNAL_DEVICE_TYPE_OBSERVER = 0x1000, +} cairo_device_surface_type_t; + +#define CAIRO_HAS_TEST_PAGINATED_SURFACE 1 + +typedef struct _cairo_slope { + cairo_fixed_t dx; + cairo_fixed_t dy; +} cairo_slope_t, cairo_distance_t; + +typedef struct _cairo_point_double { + double x; + double y; +} cairo_point_double_t; + +typedef struct _cairo_circle_double { + cairo_point_double_t center; + double radius; +} cairo_circle_double_t; + +typedef struct _cairo_distance_double { + double dx; + double dy; +} cairo_distance_double_t; + +typedef struct _cairo_box_double { + cairo_point_double_t p1; + cairo_point_double_t p2; +} cairo_box_double_t; + +typedef struct _cairo_line { + cairo_point_t p1; + cairo_point_t p2; +} cairo_line_t, cairo_box_t; + +typedef struct _cairo_trapezoid { + cairo_fixed_t top, bottom; + cairo_line_t left, right; +} cairo_trapezoid_t; + +typedef struct _cairo_point_int { + int x, y; +} cairo_point_int_t; + +#define CAIRO_RECT_INT_MIN (INT_MIN >> CAIRO_FIXED_FRAC_BITS) +#define CAIRO_RECT_INT_MAX (INT_MAX >> CAIRO_FIXED_FRAC_BITS) + +typedef enum _cairo_direction { + CAIRO_DIRECTION_FORWARD, + CAIRO_DIRECTION_REVERSE +} cairo_direction_t; + +typedef struct _cairo_edge { + cairo_line_t line; + int top, bottom; + int dir; +} cairo_edge_t; + +typedef struct _cairo_polygon { + cairo_status_t status; + + cairo_box_t extents; + cairo_box_t limit; + const cairo_box_t *limits; + int num_limits; + + int num_edges; + int edges_size; + cairo_edge_t *edges; + cairo_edge_t edges_embedded[32]; +} cairo_polygon_t; + +typedef cairo_warn cairo_status_t +(*cairo_spline_add_point_func_t) (void *closure, + const cairo_point_t *point, + const cairo_slope_t *tangent); + +typedef struct _cairo_spline_knots { + cairo_point_t a, b, c, d; +} cairo_spline_knots_t; + +typedef struct _cairo_spline { + cairo_spline_add_point_func_t add_point_func; + void *closure; + + cairo_spline_knots_t knots; + + cairo_slope_t initial_slope; + cairo_slope_t final_slope; + + cairo_bool_t has_point; + cairo_point_t last_point; +} cairo_spline_t; + +typedef struct _cairo_pen_vertex { + cairo_point_t point; + + cairo_slope_t slope_ccw; + cairo_slope_t slope_cw; +} cairo_pen_vertex_t; + +typedef struct _cairo_pen { + double radius; + double tolerance; + + int num_vertices; + cairo_pen_vertex_t *vertices; + cairo_pen_vertex_t vertices_embedded[32]; +} cairo_pen_t; + +typedef struct _cairo_stroke_style { + double line_width; + cairo_line_cap_t line_cap; + cairo_line_join_t line_join; + double miter_limit; + double *dash; + unsigned int num_dashes; + double dash_offset; + cairo_bool_t is_hairline; + double pre_hairline_line_width; +} cairo_stroke_style_t; + +typedef struct _cairo_format_masks { + int bpp; + unsigned long alpha_mask; + unsigned long red_mask; + unsigned long green_mask; + unsigned long blue_mask; +} cairo_format_masks_t; + +typedef enum { + CAIRO_STOCK_WHITE, + CAIRO_STOCK_BLACK, + CAIRO_STOCK_TRANSPARENT, + CAIRO_STOCK_NUM_COLORS, +} cairo_stock_t; + +typedef enum _cairo_image_transparency { + CAIRO_IMAGE_IS_OPAQUE, + CAIRO_IMAGE_HAS_BILEVEL_ALPHA, + CAIRO_IMAGE_HAS_ALPHA, + CAIRO_IMAGE_UNKNOWN +} cairo_image_transparency_t; + +typedef enum _cairo_image_color { + CAIRO_IMAGE_IS_COLOR, + CAIRO_IMAGE_IS_GRAYSCALE, + CAIRO_IMAGE_IS_MONOCHROME, + CAIRO_IMAGE_UNKNOWN_COLOR +} cairo_image_color_t; + + +struct _cairo_mime_data { + cairo_reference_count_t ref_count; + unsigned char *data; + unsigned long length; + cairo_destroy_func_t destroy; + void *closure; +}; + +/* + * A #cairo_unscaled_font_t is just an opaque handle we use in the + * glyph cache. + */ +typedef struct _cairo_unscaled_font { + cairo_hash_entry_t hash_entry; + cairo_reference_count_t ref_count; + const cairo_unscaled_font_backend_t *backend; +} cairo_unscaled_font_t; + +typedef enum _cairo_analysis_source { + CAIRO_ANALYSIS_SOURCE_PAINT, + CAIRO_ANALYSIS_SOURCE_MASK, + CAIRO_ANALYSIS_MASK_MASK, + CAIRO_ANALYSIS_SOURCE_FILL, + CAIRO_ANALYSIS_SOURCE_STROKE, + CAIRO_ANALYSIS_SOURCE_SHOW_GLYPHS, + CAIRO_ANALYSIS_SOURCE_NONE /* Used when analysis_source is not applicable. */ +} cairo_analysis_source_t; + +CAIRO_END_DECLS + +#endif /* CAIRO_TYPES_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-unicode.c b/local/recipes/libs/cairo/source/src/cairo-unicode.c new file mode 100644 index 0000000000..b96a3a2351 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-unicode.c @@ -0,0 +1,445 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * The code in this file is derived from GLib's gutf8.c and + * ultimately from libunicode. It is relicensed under the + * dual LGPL/MPL with permission of the original authors. + * + * Copyright © 1999 Tom Tromey + * Copyright © 2005 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Tom Tromey. + * and Red Hat, Inc. + * + * Contributor(s): + * Owen Taylor + */ + +#include "cairoint.h" +#include "cairo-error-private.h" + +#define UTF8_COMPUTE(Char, Mask, Len) \ + if (Char < 128) \ + { \ + Len = 1; \ + Mask = 0x7f; \ + } \ + else if ((Char & 0xe0) == 0xc0) \ + { \ + Len = 2; \ + Mask = 0x1f; \ + } \ + else if ((Char & 0xf0) == 0xe0) \ + { \ + Len = 3; \ + Mask = 0x0f; \ + } \ + else if ((Char & 0xf8) == 0xf0) \ + { \ + Len = 4; \ + Mask = 0x07; \ + } \ + else if ((Char & 0xfc) == 0xf8) \ + { \ + Len = 5; \ + Mask = 0x03; \ + } \ + else if ((Char & 0xfe) == 0xfc) \ + { \ + Len = 6; \ + Mask = 0x01; \ + } \ + else \ + Len = -1; + +#define UTF8_LENGTH(Char) \ + ((Char) < 0x80 ? 1 : \ + ((Char) < 0x800 ? 2 : \ + ((Char) < 0x10000 ? 3 : \ + ((Char) < 0x200000 ? 4 : \ + ((Char) < 0x4000000 ? 5 : 6))))) + +#define UTF8_GET(Result, Chars, Count, Mask, Len) \ + (Result) = (Chars)[0] & (Mask); \ + for ((Count) = 1; (Count) < (Len); ++(Count)) \ + { \ + if (((Chars)[(Count)] & 0xc0) != 0x80) \ + { \ + (Result) = -1; \ + break; \ + } \ + (Result) <<= 6; \ + (Result) |= ((Chars)[(Count)] & 0x3f); \ + } + +#define UNICODE_VALID(Char) \ + ((Char) < 0x110000 && \ + (((Char) & 0xFFFFF800) != 0xD800)) + +static const char utf8_skip_data[256] = { + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1 +}; + +#define UTF8_NEXT_CHAR(p) ((p) + utf8_skip_data[*(unsigned char *)(p)]) + +/* Converts a sequence of bytes encoded as UTF-8 to a Unicode character. + * If @p does not point to a valid UTF-8 encoded character, results are + * undefined. + **/ +static uint32_t +_utf8_get_char (const unsigned char *p) +{ + int i, mask = 0, len; + uint32_t result; + unsigned char c = (unsigned char) *p; + + UTF8_COMPUTE (c, mask, len); + if (len == -1) + return (uint32_t)-1; + UTF8_GET (result, p, i, mask, len); + + return result; +} + +/* Like _utf8_get_char, but take a maximum length + * and return (uint32_t)-2 on incomplete trailing character + */ +static uint32_t +_utf8_get_char_extended (const unsigned char *p, + long max_len) +{ + int i, len; + uint32_t wc = (unsigned char) *p; + + if (wc < 0x80) { + return wc; + } else if (wc < 0xc0) { + return (uint32_t)-1; + } else if (wc < 0xe0) { + len = 2; + wc &= 0x1f; + } else if (wc < 0xf0) { + len = 3; + wc &= 0x0f; + } else if (wc < 0xf8) { + len = 4; + wc &= 0x07; + } else if (wc < 0xfc) { + len = 5; + wc &= 0x03; + } else if (wc < 0xfe) { + len = 6; + wc &= 0x01; + } else { + return (uint32_t)-1; + } + + if (max_len >= 0 && len > max_len) { + for (i = 1; i < max_len; i++) { + if ((((unsigned char *)p)[i] & 0xc0) != 0x80) + return (uint32_t)-1; + } + return (uint32_t)-2; + } + + for (i = 1; i < len; ++i) { + uint32_t ch = ((unsigned char *)p)[i]; + + if ((ch & 0xc0) != 0x80) { + if (ch) + return (uint32_t)-1; + else + return (uint32_t)-2; + } + + wc <<= 6; + wc |= (ch & 0x3f); + } + + if (UTF8_LENGTH(wc) != len) + return (uint32_t)-1; + + return wc; +} + +/** + * _cairo_utf8_get_char_validated: + * @p: a UTF-8 string + * @unicode: location to store one Unicode character + * + * Decodes the first character of a valid UTF-8 string, and returns + * the number of bytes consumed. + * + * Note that the string should be valid. Do not use this without + * validating the string first. + * + * Returns: the number of bytes forming the character returned. + **/ +int +_cairo_utf8_get_char_validated (const char *p, + uint32_t *unicode) +{ + int i, mask = 0, len; + uint32_t result; + unsigned char c = (unsigned char) *p; + + UTF8_COMPUTE (c, mask, len); + if (len == -1) { + if (unicode) + *unicode = (uint32_t)-1; + return 1; + } + UTF8_GET (result, p, i, mask, len); + + if (unicode) + *unicode = result; + return len; +} + +/** + * _cairo_utf8_to_ucs4: + * @str: an UTF-8 string + * @len: length of @str in bytes, or -1 if it is nul-terminated. + * If @len is supplied and the string has an embedded nul + * byte, only the portion before the nul byte is converted. + * @result: location to store a pointer to a newly allocated UTF-32 + * string (always native endian), or %NULL. Free with free(). A 0 + * word will be written after the last character. + * @items_written: location to store number of 32-bit words + * written. (Not including the trailing 0) + * + * Converts a UTF-8 string to UCS-4. UCS-4 is an encoding of Unicode + * with 1 32-bit word per character. The string is validated to + * consist entirely of valid Unicode characters. + * + * Return value: %CAIRO_STATUS_SUCCESS if the entire string was + * successfully converted. %CAIRO_STATUS_INVALID_STRING if an + * invalid sequence was found. + **/ +cairo_status_t +_cairo_utf8_to_ucs4 (const char *str, + int len, + uint32_t **result, + int *items_written) +{ + uint32_t *str32 = NULL; + int n_chars, i; + const unsigned char *in; + const unsigned char * const ustr = (const unsigned char *) str; + + in = ustr; + n_chars = 0; + while ((len < 0 || ustr + len - in > 0) && *in) + { + uint32_t wc = _utf8_get_char_extended (in, ustr + len - in); + if (wc & 0x80000000 || !UNICODE_VALID (wc)) + return _cairo_error (CAIRO_STATUS_INVALID_STRING); + + n_chars++; + if (n_chars == INT_MAX) + return _cairo_error (CAIRO_STATUS_INVALID_STRING); + + in = UTF8_NEXT_CHAR (in); + } + + if (result) { + str32 = _cairo_malloc_ab (n_chars + 1, sizeof (uint32_t)); + if (!str32) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + in = ustr; + for (i=0; i < n_chars; i++) { + str32[i] = _utf8_get_char (in); + in = UTF8_NEXT_CHAR (in); + } + str32[i] = 0; + + *result = str32; + } + + if (items_written) + *items_written = n_chars; + + return CAIRO_STATUS_SUCCESS; +} + +/** + * _cairo_ucs4_to_utf8: + * @unicode: a UCS-4 character + * @utf8: buffer to write utf8 string into. Must have at least 4 bytes + * space available. Or %NULL. + * + * This space left intentionally blank. + * + * Return value: Number of bytes in the utf8 string or 0 if an invalid + * unicode character + **/ +int +_cairo_ucs4_to_utf8 (uint32_t unicode, + char *utf8) +{ + int bytes; + char *p; + + if (unicode < 0x80) { + if (utf8) + *utf8 = unicode; + return 1; + } else if (unicode < 0x800) { + bytes = 2; + } else if (unicode < 0x10000) { + bytes = 3; + } else if (unicode < 0x200000) { + bytes = 4; + } else { + return 0; + } + + if (!utf8) + return bytes; + + p = utf8 + bytes; + while (p > utf8) { + *--p = 0x80 | (unicode & 0x3f); + unicode >>= 6; + } + *p |= 0xf0 << (4 - bytes); + + return bytes; +} + +/** + * _cairo_ucs4_to_utf16: + * @unicode: a UCS-4 character + * @utf16: buffer to write utf16 string into. Must have at least 2 + * elements. Or %NULL. + * + * This space left intentionally blank. + * + * Return value: Number of elements in the utf16 string or 0 if an + * invalid unicode character + **/ +int +_cairo_ucs4_to_utf16 (uint32_t unicode, + uint16_t *utf16) +{ + if (unicode < 0x10000) { + if (utf16) + utf16[0] = unicode; + return 1; + } else if (unicode < 0x110000) { + if (utf16) { + utf16[0] = (unicode - 0x10000) / 0x400 + 0xd800; + utf16[1] = (unicode - 0x10000) % 0x400 + 0xdc00; + } + return 2; + } else { + return 0; + } +} + +#if CAIRO_HAS_UTF8_TO_UTF16 +/** + * _cairo_utf8_to_utf16: + * @str: an UTF-8 string + * @len: length of @str in bytes, or -1 if it is nul-terminated. + * If @len is supplied and the string has an embedded nul + * byte, only the portion before the nul byte is converted. + * @result: location to store a pointer to a newly allocated UTF-16 + * string (always native endian). Free with free(). A 0 + * word will be written after the last character. + * @items_written: location to store number of 16-bit words + * written. (Not including the trailing 0) + * + * Converts a UTF-8 string to UTF-16. UTF-16 is an encoding of Unicode + * where characters are represented either as a single 16-bit word, or + * as a pair of 16-bit "surrogates". The string is validated to + * consist entirely of valid Unicode characters. + * + * Return value: %CAIRO_STATUS_SUCCESS if the entire string was + * successfully converted. %CAIRO_STATUS_INVALID_STRING if an + * an invalid sequence was found. + **/ +cairo_status_t +_cairo_utf8_to_utf16 (const char *str, + int len, + uint16_t **result, + int *items_written) +{ + uint16_t *str16 = NULL; + int n16, i; + const unsigned char *in; + const unsigned char * const ustr = (const unsigned char *) str; + + in = ustr; + n16 = 0; + while ((len < 0 || ustr + len - in > 0) && *in) { + uint32_t wc = _utf8_get_char_extended (in, ustr + len - in); + if (wc & 0x80000000 || !UNICODE_VALID (wc)) + return _cairo_error (CAIRO_STATUS_INVALID_STRING); + + if (wc < 0x10000) + n16 += 1; + else + n16 += 2; + + if (n16 == INT_MAX - 1 || n16 == INT_MAX) + return _cairo_error (CAIRO_STATUS_INVALID_STRING); + + in = UTF8_NEXT_CHAR (in); + } + + str16 = _cairo_malloc_ab (n16 + 1, sizeof (uint16_t)); + if (!str16) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + in = ustr; + for (i = 0; i < n16;) { + uint32_t wc = _utf8_get_char (in); + + i += _cairo_ucs4_to_utf16 (wc, str16 + i); + + in = UTF8_NEXT_CHAR (in); + } + + str16[i] = 0; + + *result = str16; + if (items_written) + *items_written = n16; + + return CAIRO_STATUS_SUCCESS; +} +#endif diff --git a/local/recipes/libs/cairo/source/src/cairo-user-font-private.h b/local/recipes/libs/cairo/source/src/cairo-user-font-private.h new file mode 100644 index 0000000000..d54ef78b44 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-user-font-private.h @@ -0,0 +1,46 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2006, 2008 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Kristian Høgsberg + * Behdad Esfahbod + */ + +#ifndef CAIRO_USER_FONT_PRIVATE_H +#define CAIRO_USER_FONT_PRIVATE_H + +#include "cairo.h" +#include "cairo-compiler-private.h" + +cairo_private cairo_bool_t +_cairo_font_face_is_user (cairo_font_face_t *font_face); + +#endif /* CAIRO_USER_FONT_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-user-font.c b/local/recipes/libs/cairo/source/src/cairo-user-font.c new file mode 100644 index 0000000000..56525d5c15 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-user-font.c @@ -0,0 +1,1206 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2006, 2008 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Kristian Høgsberg + * Behdad Esfahbod + */ + +#include "cairoint.h" +#include "cairo-user-font-private.h" +#include "cairo-recording-surface-private.h" +#include "cairo-analysis-surface-private.h" +#include "cairo-error-private.h" + +/** + * SECTION:cairo-user-fonts + * @Title:User Fonts + * @Short_Description: Font support with font data provided by the user + * + * The user-font feature allows the cairo user to provide drawings for glyphs + * in a font. This is most useful in implementing fonts in non-standard + * formats, like SVG fonts and Flash fonts, but can also be used by games and + * other application to draw "funky" fonts. + **/ + +/** + * CAIRO_HAS_USER_FONT: + * + * Defined if the user font backend is available. + * This macro can be used to conditionally compile backend-specific code. + * The user font backend is always built in versions of cairo that support + * this feature (1.8 and later). + * + * Since: 1.8 + **/ + +typedef struct _cairo_user_scaled_font_methods { + cairo_user_scaled_font_init_func_t init; + cairo_user_scaled_font_render_glyph_func_t render_color_glyph; + cairo_user_scaled_font_render_glyph_func_t render_glyph; + cairo_user_scaled_font_unicode_to_glyph_func_t unicode_to_glyph; + cairo_user_scaled_font_text_to_glyphs_func_t text_to_glyphs; +} cairo_user_scaled_font_methods_t; + +typedef struct _cairo_user_font_face { + cairo_font_face_t base; + + /* Set to true after first scaled font is created. At that point, + * the scaled_font_methods cannot change anymore. */ + cairo_bool_t immutable; + cairo_bool_t has_color; + cairo_user_scaled_font_methods_t scaled_font_methods; +} cairo_user_font_face_t; + +typedef struct _cairo_user_scaled_font { + cairo_scaled_font_t base; + + cairo_text_extents_t default_glyph_extents; + + /* space to compute extents in, and factors to convert back to user space */ + cairo_matrix_t extent_scale; + double extent_x_scale; + double extent_y_scale; + + /* multiplier for metrics hinting */ + double snap_x_scale; + double snap_y_scale; + + cairo_pattern_t *foreground_marker; + cairo_pattern_t *foreground_pattern; + cairo_bool_t foreground_marker_used; + cairo_bool_t foreground_colors_used; + +} cairo_user_scaled_font_t; + +/* #cairo_user_scaled_font_t */ + +static cairo_surface_t * +_cairo_user_scaled_font_create_recording_surface (cairo_user_scaled_font_t *scaled_font, + cairo_bool_t color, + const cairo_color_t *foreground_color) +{ + cairo_content_t content; + + if (color) { + content = CAIRO_CONTENT_COLOR_ALPHA; + } else { + content = scaled_font->base.options.antialias == CAIRO_ANTIALIAS_SUBPIXEL ? + CAIRO_CONTENT_COLOR_ALPHA : + CAIRO_CONTENT_ALPHA; + } + + if (scaled_font->foreground_pattern) + cairo_pattern_destroy (scaled_font->foreground_pattern); + + scaled_font->foreground_marker_used = FALSE; + scaled_font->foreground_colors_used = FALSE; + if (foreground_color) { + scaled_font->foreground_pattern = _cairo_pattern_create_solid (foreground_color); + } else { + scaled_font->foreground_pattern = cairo_pattern_create_rgb (0, 0, 0); + } + + return cairo_recording_surface_create (content, NULL); +} + +static cairo_t * +_cairo_user_scaled_font_create_recording_context (const cairo_user_scaled_font_t *scaled_font, + cairo_surface_t *recording_surface, + cairo_bool_t color) +{ + cairo_t *cr; + + cr = cairo_create (recording_surface); + + if (!_cairo_matrix_is_scale_0 (&scaled_font->base.scale)) { + cairo_matrix_t scale; + scale = scaled_font->base.scale; + scale.x0 = scale.y0 = 0.; + cairo_set_matrix (cr, &scale); + } + + cairo_set_font_size (cr, 1.0); + cairo_set_font_options (cr, &scaled_font->base.options); + if (!color) + cairo_set_source_rgb (cr, 1., 1., 1.); + + return cr; +} + +static cairo_int_status_t +_cairo_user_scaled_glyph_init_record_glyph (cairo_user_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph, + const cairo_color_t *foreground_color) +{ + cairo_user_font_face_t *face = + (cairo_user_font_face_t *) scaled_font->base.font_face; + cairo_text_extents_t extents = scaled_font->default_glyph_extents; + cairo_surface_t *recording_surface = NULL; + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + cairo_t *cr; + cairo_bool_t foreground_used = FALSE; + + if (!face->scaled_font_methods.render_color_glyph && !face->scaled_font_methods.render_glyph) + return CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED; + + /* special case for 0 rank matrix (as in _cairo_scaled_font_init): empty surface */ + if (_cairo_matrix_is_scale_0 (&scaled_font->base.scale)) { + recording_surface = _cairo_user_scaled_font_create_recording_surface (scaled_font, FALSE, foreground_color); + _cairo_scaled_glyph_set_recording_surface (scaled_glyph, + &scaled_font->base, + recording_surface, + NULL); + } else { + status = CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED; + + if (face->scaled_font_methods.render_color_glyph && + scaled_font->base.options.color_mode != CAIRO_COLOR_MODE_NO_COLOR) + { + recording_surface = _cairo_user_scaled_font_create_recording_surface (scaled_font, TRUE, foreground_color); + + cr = _cairo_user_scaled_font_create_recording_context (scaled_font, recording_surface, TRUE); + status = face->scaled_font_methods.render_color_glyph ((cairo_scaled_font_t *)scaled_font, + _cairo_scaled_glyph_index(scaled_glyph), + cr, &extents); + if (status == CAIRO_INT_STATUS_SUCCESS) { + status = cairo_status (cr); + scaled_glyph->color_glyph = TRUE; + scaled_glyph->color_glyph_set = TRUE; + } + + cairo_destroy (cr); + foreground_used = scaled_font->foreground_marker_used || scaled_font->foreground_colors_used; + } + + if (status == (cairo_int_status_t)CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED && + face->scaled_font_methods.render_glyph) { + if (recording_surface) + cairo_surface_destroy (recording_surface); + recording_surface = _cairo_user_scaled_font_create_recording_surface (scaled_font, FALSE, foreground_color); + recording_surface->device_transform.x0 = .25 * _cairo_scaled_glyph_xphase (scaled_glyph); + recording_surface->device_transform.y0 = .25 * _cairo_scaled_glyph_yphase (scaled_glyph); + + cr = _cairo_user_scaled_font_create_recording_context (scaled_font, recording_surface, FALSE); + + status = face->scaled_font_methods.render_glyph ((cairo_scaled_font_t *)scaled_font, + _cairo_scaled_glyph_index(scaled_glyph), + cr, &extents); + if (status == CAIRO_INT_STATUS_SUCCESS) { + status = cairo_status (cr); + scaled_glyph->color_glyph = FALSE; + scaled_glyph->color_glyph_set = TRUE; + } + + cairo_destroy (cr); + foreground_used = FALSE; + } + + if (status != CAIRO_INT_STATUS_SUCCESS) { + if (recording_surface) + cairo_surface_destroy (recording_surface); + return status; + } + + _cairo_scaled_glyph_set_recording_surface (scaled_glyph, + &scaled_font->base, + recording_surface, + foreground_used ? foreground_color : NULL); + } + + /* set metrics */ + + if (extents.width == 0.) { + cairo_box_t bbox; + double x1, y1, x2, y2; + double x_scale, y_scale; + + /* Compute extents.x/y/width/height from recording_surface, + * in font space. + */ + status = _cairo_recording_surface_get_bbox ((cairo_recording_surface_t *) recording_surface, + &bbox, + &scaled_font->extent_scale); + if (unlikely (status)) + return status; + + _cairo_box_to_doubles (&bbox, &x1, &y1, &x2, &y2); + + x_scale = scaled_font->extent_x_scale; + y_scale = scaled_font->extent_y_scale; + extents.x_bearing = x1 * x_scale; + extents.y_bearing = y1 * y_scale; + extents.width = (x2 - x1) * x_scale; + extents.height = (y2 - y1) * y_scale; + } + + if (scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF) { + extents.x_advance = _cairo_lround (extents.x_advance / scaled_font->snap_x_scale) * scaled_font->snap_x_scale; + extents.y_advance = _cairo_lround (extents.y_advance / scaled_font->snap_y_scale) * scaled_font->snap_y_scale; + } + + _cairo_scaled_glyph_set_metrics (scaled_glyph, + &scaled_font->base, + &extents); + + return status; +} + +static cairo_int_status_t +_cairo_user_scaled_glyph_init_surface (cairo_user_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph, + cairo_scaled_glyph_info_t info, + const cairo_color_t *foreground_color) +{ + cairo_surface_t *surface; + cairo_format_t format; + int width, height; + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + cairo_bool_t foreground_used; + + /* TODO + * extend the glyph cache to support argb glyphs. + * need to figure out the semantics and interaction with subpixel + * rendering first. + */ + + /* Only one info type at a time handled in this function */ + assert (info == CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE || info == CAIRO_SCALED_GLYPH_INFO_SURFACE); + + width = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x) - + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x); + height = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y) - + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y); + + if (info == CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) { + format = CAIRO_FORMAT_ARGB32; + } else { + switch (scaled_font->base.options.antialias) { + default: + case CAIRO_ANTIALIAS_DEFAULT: + case CAIRO_ANTIALIAS_FAST: + case CAIRO_ANTIALIAS_GOOD: + case CAIRO_ANTIALIAS_GRAY: + format = CAIRO_FORMAT_A8; + break; + case CAIRO_ANTIALIAS_NONE: + format = CAIRO_FORMAT_A1; + break; + case CAIRO_ANTIALIAS_BEST: + case CAIRO_ANTIALIAS_SUBPIXEL: + format = CAIRO_FORMAT_ARGB32; + break; + } + } + surface = cairo_image_surface_create (format, width, height); + + cairo_surface_set_device_offset (surface, + - _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x), + - _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y)); + + if (info == CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) { + status = _cairo_recording_surface_replay_with_foreground_color (scaled_glyph->recording_surface, + surface, + foreground_color, + &foreground_used); + + } else { + status = _cairo_recording_surface_replay (scaled_glyph->recording_surface, surface); + foreground_used = FALSE; + } + if (unlikely (status)) { + cairo_surface_destroy(surface); + return status; + } + + foreground_used = foreground_used || scaled_glyph->recording_uses_foreground_color; + + if (info == CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) { + _cairo_scaled_glyph_set_color_surface (scaled_glyph, + &scaled_font->base, + (cairo_image_surface_t *)surface, + foreground_used ? foreground_color : NULL); + surface = NULL; + } else { + _cairo_scaled_glyph_set_surface (scaled_glyph, + &scaled_font->base, + (cairo_image_surface_t *) surface); + surface = NULL; + } + + if (surface) + cairo_surface_destroy (surface); + + return status; +} + +static void +_cairo_user_scaled_glyph_fini (void *abstract_font) +{ + cairo_user_scaled_font_t *scaled_font = abstract_font; + + if (scaled_font->foreground_pattern) + cairo_pattern_destroy (scaled_font->foreground_pattern); + + if (scaled_font->foreground_marker) + cairo_pattern_destroy (scaled_font->foreground_marker); +} + +static cairo_int_status_t +_cairo_user_scaled_glyph_init (void *abstract_font, + cairo_scaled_glyph_t *scaled_glyph, + cairo_scaled_glyph_info_t info, + const cairo_color_t *foreground_color) +{ + cairo_int_status_t status = CAIRO_STATUS_SUCCESS; + cairo_user_scaled_font_t *scaled_font = abstract_font; + + if (!scaled_glyph->recording_surface || (info & CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE)) { + status = _cairo_user_scaled_glyph_init_record_glyph (scaled_font, scaled_glyph, foreground_color); + if (status) + return status; + } + + if (info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) { + if (!scaled_glyph->color_glyph ) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_user_scaled_glyph_init_surface (scaled_font, + scaled_glyph, + CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE, + foreground_color); + if (status) + return status; + } + + if (info & CAIRO_SCALED_GLYPH_INFO_SURFACE) { + status = _cairo_user_scaled_glyph_init_surface (scaled_font, + scaled_glyph, + CAIRO_SCALED_GLYPH_INFO_SURFACE, + NULL); + if (status) + return status; + } + + if (info & CAIRO_SCALED_GLYPH_INFO_PATH) { + cairo_path_fixed_t *path = _cairo_path_fixed_create (); + if (!path) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + status = _cairo_recording_surface_get_path (scaled_glyph->recording_surface, path); + if (unlikely (status)) { + _cairo_path_fixed_destroy (path); + return status; + } + + _cairo_scaled_glyph_set_path (scaled_glyph, + &scaled_font->base, + path); + } + + return status; +} + +static unsigned long +_cairo_user_ucs4_to_index (void *abstract_font, + uint32_t ucs4) +{ + cairo_user_scaled_font_t *scaled_font = abstract_font; + cairo_user_font_face_t *face = + (cairo_user_font_face_t *) scaled_font->base.font_face; + unsigned long glyph = 0; + + if (face->scaled_font_methods.unicode_to_glyph) { + cairo_status_t status; + + status = face->scaled_font_methods.unicode_to_glyph (&scaled_font->base, + ucs4, &glyph); + + if (status == CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED) + goto not_implemented; + + if (status != CAIRO_STATUS_SUCCESS) { + status = _cairo_scaled_font_set_error (&scaled_font->base, status); + glyph = 0; + } + + } else { +not_implemented: + glyph = ucs4; + } + + return glyph; +} + +static cairo_bool_t +_cairo_user_has_color_glyphs (void *abstract_font) +{ + cairo_user_scaled_font_t *scaled_font = abstract_font; + cairo_user_font_face_t *face = + (cairo_user_font_face_t *) scaled_font->base.font_face; + + return face->has_color; +} + +static cairo_int_status_t +_cairo_user_text_to_glyphs (void *abstract_font, + double x, + double y, + const char *utf8, + int utf8_len, + cairo_glyph_t **glyphs, + int *num_glyphs, + cairo_text_cluster_t **clusters, + int *num_clusters, + cairo_text_cluster_flags_t *cluster_flags) +{ + cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED; + + cairo_user_scaled_font_t *scaled_font = abstract_font; + cairo_user_font_face_t *face = + (cairo_user_font_face_t *) scaled_font->base.font_face; + + if (face->scaled_font_methods.text_to_glyphs) { + int i; + cairo_glyph_t *orig_glyphs = *glyphs; + int orig_num_glyphs = *num_glyphs; + + status = face->scaled_font_methods.text_to_glyphs (&scaled_font->base, + utf8, utf8_len, + glyphs, num_glyphs, + clusters, num_clusters, cluster_flags); + + if (status != CAIRO_INT_STATUS_SUCCESS && + status != CAIRO_INT_STATUS_USER_FONT_NOT_IMPLEMENTED) + return status; + + if (status == CAIRO_INT_STATUS_USER_FONT_NOT_IMPLEMENTED || + *num_glyphs < 0) { + if (orig_glyphs != *glyphs) { + cairo_glyph_free (*glyphs); + *glyphs = orig_glyphs; + } + *num_glyphs = orig_num_glyphs; + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + /* Convert from font space to user space and add x,y */ + for (i = 0; i < *num_glyphs; i++) { + double gx = (*glyphs)[i].x; + double gy = (*glyphs)[i].y; + + cairo_matrix_transform_point (&scaled_font->base.font_matrix, + &gx, &gy); + + (*glyphs)[i].x = gx + x; + (*glyphs)[i].y = gy + y; + } + } + + return status; +} + +static cairo_status_t +_cairo_user_font_face_scaled_font_create (void *abstract_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **scaled_font); + +static cairo_status_t +_cairo_user_font_face_create_for_toy (cairo_toy_font_face_t *toy_face, + cairo_font_face_t **font_face) +{ + return _cairo_font_face_twin_create_for_toy (toy_face, font_face); +} + +static const cairo_scaled_font_backend_t _cairo_user_scaled_font_backend = { + CAIRO_FONT_TYPE_USER, + _cairo_user_scaled_glyph_fini, + _cairo_user_scaled_glyph_init, + _cairo_user_text_to_glyphs, + _cairo_user_ucs4_to_index, + NULL, /* load_truetype_table */ + NULL, /* index_to_ucs4 */ + NULL, /* is_synthetic */ + NULL, /* index_to_glyph_name */ + NULL, /* load_type1_data */ + _cairo_user_has_color_glyphs, +}; + +/* #cairo_user_font_face_t */ + +static cairo_status_t +_cairo_user_font_face_scaled_font_create (void *abstract_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **scaled_font) +{ + cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_user_font_face_t *font_face = abstract_face; + cairo_user_scaled_font_t *user_scaled_font = NULL; + cairo_font_extents_t font_extents = {1., 0., 1., 1., 0.}; + + font_face->immutable = TRUE; + + user_scaled_font = _cairo_calloc (sizeof (cairo_user_scaled_font_t)); + if (unlikely (user_scaled_font == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + status = _cairo_scaled_font_init (&user_scaled_font->base, + &font_face->base, + font_matrix, ctm, options, + &_cairo_user_scaled_font_backend); + + if (unlikely (status)) { + free (user_scaled_font); + return status; + } + + user_scaled_font->foreground_pattern = NULL; + user_scaled_font->foreground_marker = _cairo_pattern_create_foreground_marker (); + + /* XXX metrics hinting? */ + + /* compute a normalized version of font scale matrix to compute + * extents in. This is to minimize error caused by the cairo_fixed_t + * representation. */ + { + double fixed_scale, x_scale, y_scale; + + user_scaled_font->snap_x_scale = 1.0; + user_scaled_font->snap_y_scale = 1.0; + user_scaled_font->extent_scale = user_scaled_font->base.scale_inverse; + status = _cairo_matrix_compute_basis_scale_factors (&user_scaled_font->extent_scale, + &x_scale, &y_scale, + 1); + if (status == CAIRO_STATUS_SUCCESS) { + + if (x_scale == 0) x_scale = 1.; + if (y_scale == 0) y_scale = 1.; + + user_scaled_font->snap_x_scale = x_scale; + user_scaled_font->snap_y_scale = y_scale; + + /* since glyphs are pretty much 1.0x1.0, we can reduce error by + * scaling to a larger square. say, 1024.x1024. */ + fixed_scale = 1024.; + x_scale /= fixed_scale; + y_scale /= fixed_scale; + + cairo_matrix_scale (&user_scaled_font->extent_scale, 1. / x_scale, 1. / y_scale); + + user_scaled_font->extent_x_scale = x_scale; + user_scaled_font->extent_y_scale = y_scale; + } + } + + if (status == CAIRO_STATUS_SUCCESS && + font_face->scaled_font_methods.init != NULL) + { + /* Lock the scaled_font mutex such that user doesn't accidentally try + * to use it just yet. */ + CAIRO_MUTEX_LOCK (user_scaled_font->base.mutex); + + /* Give away fontmap lock such that user-font can use other fonts */ + status = _cairo_scaled_font_register_placeholder_and_unlock_font_map (&user_scaled_font->base); + if (status == CAIRO_STATUS_SUCCESS) { + cairo_surface_t *recording_surface; + cairo_t *cr; + + recording_surface = _cairo_user_scaled_font_create_recording_surface (user_scaled_font, FALSE, NULL); + cr = _cairo_user_scaled_font_create_recording_context (user_scaled_font, recording_surface, FALSE); + cairo_surface_destroy (recording_surface); + + status = font_face->scaled_font_methods.init (&user_scaled_font->base, + cr, + &font_extents); + + if (status == CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED) + status = CAIRO_STATUS_SUCCESS; + + if (status == CAIRO_STATUS_SUCCESS) + status = cairo_status (cr); + + cairo_destroy (cr); + + _cairo_scaled_font_unregister_placeholder_and_lock_font_map (&user_scaled_font->base); + } + + CAIRO_MUTEX_UNLOCK (user_scaled_font->base.mutex); + } + + if (status == CAIRO_STATUS_SUCCESS) + status = _cairo_scaled_font_set_metrics (&user_scaled_font->base, &font_extents); + + if (status != CAIRO_STATUS_SUCCESS) { + _cairo_scaled_font_fini (&user_scaled_font->base); + free (user_scaled_font); + } else { + user_scaled_font->default_glyph_extents.x_bearing = 0.; + user_scaled_font->default_glyph_extents.y_bearing = -font_extents.ascent; + user_scaled_font->default_glyph_extents.width = 0.; + user_scaled_font->default_glyph_extents.height = font_extents.ascent + font_extents.descent; + user_scaled_font->default_glyph_extents.x_advance = font_extents.max_x_advance; + user_scaled_font->default_glyph_extents.y_advance = 0.; + + *scaled_font = &user_scaled_font->base; + } + + return status; +} + +const cairo_font_face_backend_t _cairo_user_font_face_backend = { + CAIRO_FONT_TYPE_USER, + _cairo_user_font_face_create_for_toy, + _cairo_font_face_destroy, + _cairo_user_font_face_scaled_font_create +}; + + +cairo_bool_t +_cairo_font_face_is_user (cairo_font_face_t *font_face) +{ + return font_face->backend == &_cairo_user_font_face_backend; +} + +/* Implement the public interface */ + +/** + * cairo_user_font_face_create: + * + * Creates a new user font-face. + * + * Use the setter functions to associate callbacks with the returned + * user font. The only mandatory callback is render_glyph. + * + * After the font-face is created, the user can attach arbitrary data + * (the actual font data) to it using cairo_font_face_set_user_data() + * and access it from the user-font callbacks by using + * cairo_scaled_font_get_font_face() followed by + * cairo_font_face_get_user_data(). + * + * Return value: a newly created #cairo_font_face_t. Free with + * cairo_font_face_destroy() when you are done using it. + * + * Since: 1.8 + **/ +cairo_font_face_t * +cairo_user_font_face_create (void) +{ + cairo_user_font_face_t *font_face; + + font_face = _cairo_calloc (sizeof (cairo_user_font_face_t)); + if (!font_face) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_font_face_t *)&_cairo_font_face_nil; + } + + _cairo_font_face_init (&font_face->base, &_cairo_user_font_face_backend); + + font_face->immutable = FALSE; + font_face->has_color = FALSE; + memset (&font_face->scaled_font_methods, 0, sizeof (font_face->scaled_font_methods)); + + return &font_face->base; +} + +/* User-font method setters */ + + +/** + * cairo_user_font_face_set_init_func: + * @font_face: A user font face + * @init_func: The init callback, or %NULL + * + * Sets the scaled-font initialization function of a user-font. + * See #cairo_user_scaled_font_init_func_t for details of how the callback + * works. + * + * The font-face should not be immutable or a %CAIRO_STATUS_USER_FONT_IMMUTABLE + * error will occur. A user font-face is immutable as soon as a scaled-font + * is created from it. + * + * Since: 1.8 + **/ +void +cairo_user_font_face_set_init_func (cairo_font_face_t *font_face, + cairo_user_scaled_font_init_func_t init_func) +{ + cairo_user_font_face_t *user_font_face; + + if (font_face->status) + return; + + if (! _cairo_font_face_is_user (font_face)) { + if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH)) + return; + } + + user_font_face = (cairo_user_font_face_t *) font_face; + if (user_font_face->immutable) { + if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_USER_FONT_IMMUTABLE)) + return; + } + user_font_face->scaled_font_methods.init = init_func; +} + +/** + * cairo_user_font_face_set_render_color_glyph_func: + * @font_face: A user font face + * @render_glyph_func: The render_glyph callback, or %NULL + * + * Sets the color glyph rendering function of a user-font. + * See #cairo_user_scaled_font_render_glyph_func_t for details of how the callback + * works. + * + * The font-face should not be immutable or a %CAIRO_STATUS_USER_FONT_IMMUTABLE + * error will occur. A user font-face is immutable as soon as a scaled-font + * is created from it. + * + * The render_glyph callback is the only mandatory callback of a + * user-font. At least one of + * cairo_user_font_face_set_render_color_glyph_func() or + * cairo_user_font_face_set_render_glyph_func() must be called to set + * a render callback. If both callbacks are set, the color glyph + * render callback is invoked first. If the color glyph render + * callback returns %CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED, the + * non-color version of the callback is invoked. + * + * If the callback is %NULL and a glyph is tried to be rendered using + * @font_face, a %CAIRO_STATUS_USER_FONT_ERROR will occur. + * + * Since: 1.18 + **/ +void +cairo_user_font_face_set_render_color_glyph_func (cairo_font_face_t *font_face, + cairo_user_scaled_font_render_glyph_func_t render_glyph_func) +{ + cairo_user_font_face_t *user_font_face; + + if (font_face->status) + return; + + if (! _cairo_font_face_is_user (font_face)) { + if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH)) + return; + } + + user_font_face = (cairo_user_font_face_t *) font_face; + if (user_font_face->immutable) { + if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_USER_FONT_IMMUTABLE)) + return; + } + user_font_face->scaled_font_methods.render_color_glyph = render_glyph_func; + user_font_face->has_color = render_glyph_func ? TRUE : FALSE; +} + +/** + * cairo_user_font_face_set_render_glyph_func: + * @font_face: A user font face + * @render_glyph_func: The render_glyph callback, or %NULL + * + * Sets the glyph rendering function of a user-font. + * See #cairo_user_scaled_font_render_glyph_func_t for details of how the callback + * works. + * + * The font-face should not be immutable or a %CAIRO_STATUS_USER_FONT_IMMUTABLE + * error will occur. A user font-face is immutable as soon as a scaled-font + * is created from it. + * + * The render_glyph callback is the only mandatory callback of a + * user-font. At least one of + * cairo_user_font_face_set_render_color_glyph_func() or + * cairo_user_font_face_set_render_glyph_func() must be called to set + * a render callback. If both callbacks are set, the color glyph + * render callback is invoked first. If the color glyph render + * callback returns %CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED, the + * non-color version of the callback is invoked. + * + * If the callback is %NULL and a glyph is tried to be rendered using + * @font_face, a %CAIRO_STATUS_USER_FONT_ERROR will occur. + * + * Since: 1.8 + **/ +void +cairo_user_font_face_set_render_glyph_func (cairo_font_face_t *font_face, + cairo_user_scaled_font_render_glyph_func_t render_glyph_func) +{ + cairo_user_font_face_t *user_font_face; + + if (font_face->status) + return; + + if (! _cairo_font_face_is_user (font_face)) { + if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH)) + return; + } + + user_font_face = (cairo_user_font_face_t *) font_face; + if (user_font_face->immutable) { + if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_USER_FONT_IMMUTABLE)) + return; + } + user_font_face->scaled_font_methods.render_glyph = render_glyph_func; +} + +/** + * cairo_user_font_face_set_text_to_glyphs_func: + * @font_face: A user font face + * @text_to_glyphs_func: The text_to_glyphs callback, or %NULL + * + * Sets th text-to-glyphs conversion function of a user-font. + * See #cairo_user_scaled_font_text_to_glyphs_func_t for details of how the callback + * works. + * + * The font-face should not be immutable or a %CAIRO_STATUS_USER_FONT_IMMUTABLE + * error will occur. A user font-face is immutable as soon as a scaled-font + * is created from it. + * + * Since: 1.8 + **/ +void +cairo_user_font_face_set_text_to_glyphs_func (cairo_font_face_t *font_face, + cairo_user_scaled_font_text_to_glyphs_func_t text_to_glyphs_func) +{ + cairo_user_font_face_t *user_font_face; + + if (font_face->status) + return; + + if (! _cairo_font_face_is_user (font_face)) { + if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH)) + return; + } + + user_font_face = (cairo_user_font_face_t *) font_face; + if (user_font_face->immutable) { + if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_USER_FONT_IMMUTABLE)) + return; + } + user_font_face->scaled_font_methods.text_to_glyphs = text_to_glyphs_func; +} + +/** + * cairo_user_font_face_set_unicode_to_glyph_func: + * @font_face: A user font face + * @unicode_to_glyph_func: The unicode_to_glyph callback, or %NULL + * + * Sets the unicode-to-glyph conversion function of a user-font. + * See #cairo_user_scaled_font_unicode_to_glyph_func_t for details of how the callback + * works. + * + * The font-face should not be immutable or a %CAIRO_STATUS_USER_FONT_IMMUTABLE + * error will occur. A user font-face is immutable as soon as a scaled-font + * is created from it. + * + * Since: 1.8 + **/ +void +cairo_user_font_face_set_unicode_to_glyph_func (cairo_font_face_t *font_face, + cairo_user_scaled_font_unicode_to_glyph_func_t unicode_to_glyph_func) +{ + cairo_user_font_face_t *user_font_face; + if (font_face->status) + return; + + if (! _cairo_font_face_is_user (font_face)) { + if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH)) + return; + } + + user_font_face = (cairo_user_font_face_t *) font_face; + if (user_font_face->immutable) { + if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_USER_FONT_IMMUTABLE)) + return; + } + user_font_face->scaled_font_methods.unicode_to_glyph = unicode_to_glyph_func; +} + +/* User-font method getters */ + +/** + * cairo_user_font_face_get_init_func: + * @font_face: A user font face + * + * Gets the scaled-font initialization function of a user-font. + * + * Return value: The init callback of @font_face + * or %NULL if none set or an error has occurred. + * + * Since: 1.8 + **/ +cairo_user_scaled_font_init_func_t +cairo_user_font_face_get_init_func (cairo_font_face_t *font_face) +{ + cairo_user_font_face_t *user_font_face; + + if (font_face->status) + return NULL; + + if (! _cairo_font_face_is_user (font_face)) { + if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH)) + return NULL; + } + + user_font_face = (cairo_user_font_face_t *) font_face; + return user_font_face->scaled_font_methods.init; +} + +/** + * cairo_user_font_face_get_render_color_glyph_func: + * @font_face: A user font face + * + * Gets the color glyph rendering function of a user-font. + * + * Return value: The render_glyph callback of @font_face + * or %NULL if none set or an error has occurred. + * + * Since: 1.18 + **/ +cairo_user_scaled_font_render_glyph_func_t +cairo_user_font_face_get_render_color_glyph_func (cairo_font_face_t *font_face) +{ + cairo_user_font_face_t *user_font_face; + + if (font_face->status) + return NULL; + + if (! _cairo_font_face_is_user (font_face)) { + if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH)) + return NULL; + } + + user_font_face = (cairo_user_font_face_t *) font_face; + return user_font_face->scaled_font_methods.render_color_glyph; +} + +/** + * cairo_user_font_face_get_render_glyph_func: + * @font_face: A user font face + * + * Gets the glyph rendering function of a user-font. + * + * Return value: The render_glyph callback of @font_face + * or %NULL if none set or an error has occurred. + * + * Since: 1.8 + **/ +cairo_user_scaled_font_render_glyph_func_t +cairo_user_font_face_get_render_glyph_func (cairo_font_face_t *font_face) +{ + cairo_user_font_face_t *user_font_face; + + if (font_face->status) + return NULL; + + if (! _cairo_font_face_is_user (font_face)) { + if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH)) + return NULL; + } + + user_font_face = (cairo_user_font_face_t *) font_face; + return user_font_face->scaled_font_methods.render_glyph; +} + +/** + * cairo_user_font_face_get_text_to_glyphs_func: + * @font_face: A user font face + * + * Gets the text-to-glyphs conversion function of a user-font. + * + * Return value: The text_to_glyphs callback of @font_face + * or %NULL if none set or an error occurred. + * + * Since: 1.8 + **/ +cairo_user_scaled_font_text_to_glyphs_func_t +cairo_user_font_face_get_text_to_glyphs_func (cairo_font_face_t *font_face) +{ + cairo_user_font_face_t *user_font_face; + + if (font_face->status) + return NULL; + + if (! _cairo_font_face_is_user (font_face)) { + if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH)) + return NULL; + } + + user_font_face = (cairo_user_font_face_t *) font_face; + return user_font_face->scaled_font_methods.text_to_glyphs; +} + +/** + * cairo_user_font_face_get_unicode_to_glyph_func: + * @font_face: A user font face + * + * Gets the unicode-to-glyph conversion function of a user-font. + * + * Return value: The unicode_to_glyph callback of @font_face + * or %NULL if none set or an error occurred. + * + * Since: 1.8 + **/ +cairo_user_scaled_font_unicode_to_glyph_func_t +cairo_user_font_face_get_unicode_to_glyph_func (cairo_font_face_t *font_face) +{ + cairo_user_font_face_t *user_font_face; + + if (font_face->status) + return NULL; + + if (! _cairo_font_face_is_user (font_face)) { + if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH)) + return NULL; + } + + user_font_face = (cairo_user_font_face_t *) font_face; + return user_font_face->scaled_font_methods.unicode_to_glyph; +} + +/** + * cairo_user_scaled_font_get_foreground_marker: + * @scaled_font: A user scaled font + * + * Gets the foreground pattern of the glyph currently being + * rendered. A #cairo_user_scaled_font_render_glyph_func_t function + * that has been set with + * cairo_user_font_face_set_render_color_glyph_func() may call this + * function to retrieve the current foreground pattern for the glyph + * being rendered. The function should not be called outside of a + * cairo_user_font_face_set_render_color_glyph_func() callback. + * + * The foreground marker pattern contains an internal marker to + * indicate that it is to be substituted with the current source when + * rendered to a surface. Querying the foreground marker will reveal a + * solid black color, however this is not representative of the color + * that will actually be used. Similarly, setting a solid black color + * will render black, not the foreground pattern when the glyph is + * painted to a surface. Using the foreground marker as the source + * instead of cairo_user_scaled_font_get_foreground_source() in a + * color render callback has the following benefits: + * + * 1. Cairo only needs to call the render callback once as it can + * cache the recording. Cairo will substitute the actual foreground + * color when rendering the recording. + * + * 2. On backends that have the concept of a foreground color in fonts such as + * PDF, PostScript, and SVG, cairo can generate more optimal + * output. The glyph can be included in an embedded font. + * + * The one drawback of the using foreground marker is the render + * callback can not access the color components of the pattern as the + * actual foreground pattern is not available at the time the render + * callback is invoked. If the render callback needs to query the + * foreground pattern, use + * cairo_user_scaled_font_get_foreground_source(). + * + * If the render callback simply wants to call cairo_set_source() with + * the foreground pattern, + * cairo_user_scaled_font_get_foreground_marker() is the preferred + * function to use as it results in better performance than + * cairo_user_scaled_font_get_foreground_source(). + * + * Return value: the current foreground source marker pattern. This + * object is owned by cairo. This object must not be modified or used + * outside of a color render callback. To keep a reference to it, + * you must call cairo_pattern_reference(). + * + * Since: 1.18 + **/ +cairo_pattern_t * +cairo_user_scaled_font_get_foreground_marker (cairo_scaled_font_t *scaled_font) +{ + cairo_user_scaled_font_t *user_scaled_font; + + if (scaled_font->backend != &_cairo_user_scaled_font_backend) + return _cairo_pattern_create_in_error (CAIRO_STATUS_FONT_TYPE_MISMATCH); + + user_scaled_font = (cairo_user_scaled_font_t *)scaled_font; + return user_scaled_font->foreground_marker; +} + +/** + * cairo_user_scaled_font_get_foreground_source: + * @scaled_font: A user scaled font + * + * Gets the foreground pattern of the glyph currently being + * rendered. A #cairo_user_scaled_font_render_glyph_func_t function + * that has been set with + * cairo_user_font_face_set_render_color_glyph_func() may call this + * function to retrieve the current foreground pattern for the glyph + * being rendered. The function should not be called outside of a + * cairo_user_font_face_set_render_color_glyph_func() callback. + * + * This function returns the current source at the time the glyph is + * rendered. Compared with + * cairo_user_scaled_font_get_foreground_marker(), this function + * returns the actual source pattern that will be used to render the + * glyph. The render callback is free to query the pattern and + * extract color components or other pattern data. For example if the + * render callback wants to create a gradient stop based on colors in + * the foreground source pattern, it will need to use this function in + * order to be able to query the colors in the foreground pattern. + * + * While this function does not have the restrictions on using the + * pattern that cairo_user_scaled_font_get_foreground_marker() has, it + * does incur a performance penalty. If a render callback calls this + * function: + * + * 1. Cairo will call the render callback whenever the current pattern + * of the context in which the glyph is rendered changes. + * + * 2. On backends that support font embedding (PDF, PostScript, and + * SVG), cairo can not embed this glyph in a font. Instead the glyph + * will be emitted as an image or sequence of drawing operations each + * time it is used. + * + * Return value: the current foreground source pattern. This object is + * owned by cairo. To keep a reference to it, you must call + * cairo_pattern_reference(). + * + * Since: 1.18 + **/ +cairo_pattern_t * +cairo_user_scaled_font_get_foreground_source (cairo_scaled_font_t *scaled_font) +{ + cairo_user_scaled_font_t *user_scaled_font; + + if (scaled_font->backend != &_cairo_user_scaled_font_backend) + return _cairo_pattern_create_in_error (CAIRO_STATUS_FONT_TYPE_MISMATCH); + + user_scaled_font = (cairo_user_scaled_font_t *)scaled_font; + user_scaled_font->foreground_colors_used = TRUE; + return user_scaled_font->foreground_pattern; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-version.c b/local/recipes/libs/cairo/source/src/cairo-version.c new file mode 100644 index 0000000000..0b0d2123c3 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-version.c @@ -0,0 +1,254 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + */ + +#include "cairoint.h" + +/** + * SECTION:cairo-version + * @Title: Version Information + * @Short_Description: Compile-time and run-time version checks. + * + * Cairo has a three-part version number scheme. In this scheme, we use + * even vs. odd numbers to distinguish fixed points in the software + * vs. in-progress development, (such as from git instead of a tar file, + * or as a "snapshot" tar file as opposed to a "release" tar file). + * + * + * _____ Major. Always 1, until we invent a new scheme. + * / ___ Minor. Even/Odd = Release/Snapshot (tar files) or Branch/Head (git) + * | / _ Micro. Even/Odd = Tar-file/git + * | | / + * 1.0.0 + * + * + * Here are a few examples of versions that one might see. + * + * Releases + * -------- + * 1.0.0 - A major release + * 1.0.2 - A subsequent maintenance release + * 1.2.0 - Another major release + *   + * Snapshots + * --------- + * 1.1.2 - A snapshot (working toward the 1.2.0 release) + *   + * In-progress development (eg. from git) + * -------------------------------------- + * 1.0.1 - Development on a maintenance branch (toward 1.0.2 release) + * 1.1.1 - Development on head (toward 1.1.2 snapshot and 1.2.0 release) + * + * + * + * Compatibility + * + * The API/ABI compatibility guarantees for various versions are as + * follows. First, let's assume some cairo-using application code that is + * successfully using the API/ABI "from" one version of cairo. Then let's + * ask the question whether this same code can be moved "to" the API/ABI + * of another version of cairo. + * + * Moving from a release to any later version (release, snapshot, + * development) is always guaranteed to provide compatibility. + * + * Moving from a snapshot to any later version is not guaranteed to + * provide compatibility, since snapshots may introduce new API that ends + * up being removed before the next release. + * + * Moving from an in-development version (odd micro component) to any + * later version is not guaranteed to provide compatibility. In fact, + * there's not even a guarantee that the code will even continue to work + * with the same in-development version number. This is because these + * numbers don't correspond to any fixed state of the software, but + * rather the many states between snapshots and releases. + * + * + * + * Examining the version + * + * Cairo provides the ability to examine the version at either + * compile-time or run-time and in both a human-readable form as well as + * an encoded form suitable for direct comparison. Cairo also provides the + * macro CAIRO_VERSION_ENCODE() to perform the encoding. + * + * + * Compile-time + * ------------ + * #CAIRO_VERSION_STRING Human-readable + * #CAIRO_VERSION Encoded, suitable for comparison + *   + * Run-time + * -------- + * cairo_version_string() Human-readable + * cairo_version() Encoded, suitable for comparison + * + * + * For example, checking that the cairo version is greater than or equal + * to 1.0.0 could be achieved at compile-time or run-time as follows: + * + * + * ##if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 0, 0) + * printf ("Compiling with suitable cairo version: %s\n", %CAIRO_VERSION_STRING); + * ##endif + * + * if (cairo_version() >= CAIRO_VERSION_ENCODE(1, 0, 0)) + * printf ("Running with suitable cairo version: %s\n", cairo_version_string ()); + * + * + * + * + **/ + +/** + * CAIRO_VERSION: + * + * The version of cairo available at compile-time, encoded using + * CAIRO_VERSION_ENCODE(). + * + * Since: 1.0 + **/ + +/** + * CAIRO_VERSION_MAJOR: + * + * The major component of the version of cairo available at compile-time. + * + * Since: 1.0 + **/ + +/** + * CAIRO_VERSION_MINOR: + * + * The minor component of the version of cairo available at compile-time. + * + * Since: 1.0 + **/ + +/** + * CAIRO_VERSION_MICRO: + * + * The micro component of the version of cairo available at compile-time. + * + * Since: 1.0 + **/ + +/** + * CAIRO_VERSION_STRING: + * + * A human-readable string literal containing the version of cairo available + * at compile-time, in the form of "X.Y.Z". + * + * Since: 1.8 + **/ + +/** + * CAIRO_VERSION_ENCODE: + * @major: the major component of the version number + * @minor: the minor component of the version number + * @micro: the micro component of the version number + * + * This macro encodes the given cairo version into an integer. The numbers + * returned by %CAIRO_VERSION and cairo_version() are encoded using this macro. + * Two encoded version numbers can be compared as integers. The encoding ensures + * that later versions compare greater than earlier versions. + * + * Returns: the encoded version. + * + * Since: 1.0 + **/ + +/** + * CAIRO_VERSION_STRINGIZE: + * @major: the major component of the version number + * @minor: the minor component of the version number + * @micro: the micro component of the version number + * + * This macro encodes the given cairo version into an string. The numbers + * returned by %CAIRO_VERSION_STRING and cairo_version_string() are encoded using this macro. + * The parameters to this macro must expand to numerical literals. + * + * Returns: a string literal containing the version. + * + * Since: 1.8 + **/ + +/** + * cairo_version: + * + * Returns the version of the cairo library encoded in a single + * integer as per %CAIRO_VERSION_ENCODE. The encoding ensures that + * later versions compare greater than earlier versions. + * + * A run-time comparison to check that cairo's version is greater than + * or equal to version X.Y.Z could be performed as follows: + * + * + * if (cairo_version() >= CAIRO_VERSION_ENCODE(X,Y,Z)) {...} + * + * + * See also cairo_version_string() as well as the compile-time + * equivalents %CAIRO_VERSION and %CAIRO_VERSION_STRING. + * + * Return value: the encoded version. + * + * Since: 1.0 + **/ +int +cairo_version (void) +{ + return CAIRO_VERSION; +} + +/** + * cairo_version_string: + * + * Returns the version of the cairo library as a human-readable string + * of the form "X.Y.Z". + * + * See also cairo_version() as well as the compile-time equivalents + * %CAIRO_VERSION_STRING and %CAIRO_VERSION. + * + * Return value: a string containing the version. + * + * Since: 1.0 + **/ +const char* +cairo_version_string (void) +{ + return CAIRO_VERSION_STRING; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-version.h b/local/recipes/libs/cairo/source/src/cairo-version.h new file mode 100644 index 0000000000..7a7efd1669 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-version.h @@ -0,0 +1,8 @@ +#ifndef CAIRO_VERSION_H +#define CAIRO_VERSION_H + +#define CAIRO_VERSION_MAJOR 1 +#define CAIRO_VERSION_MINOR 18 +#define CAIRO_VERSION_MICRO 4 + +#endif diff --git a/local/recipes/libs/cairo/source/src/cairo-wideint-private.h b/local/recipes/libs/cairo/source/src/cairo-wideint-private.h new file mode 100644 index 0000000000..3f5491bb1c --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-wideint-private.h @@ -0,0 +1,338 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2004 Keith Packard + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Keith Packard + * + * Contributor(s): + * Keith R. Packard + * + */ + +#ifndef CAIRO_WIDEINT_H +#define CAIRO_WIDEINT_H + +#include "cairo-wideint-type-private.h" + +#include "cairo-compiler-private.h" + +/* + * 64-bit datatypes. Two separate implementations, one using + * built-in 64-bit signed/unsigned types another implemented + * as a pair of 32-bit ints + */ + +#define I cairo_private cairo_const + +#if !HAVE_UINT64_T + +cairo_uquorem64_t I +_cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den); + +cairo_uint64_t I _cairo_double_to_uint64 (double i); +double I _cairo_uint64_to_double (cairo_uint64_t i); +cairo_int64_t I _cairo_double_to_int64 (double i); +double I _cairo_int64_to_double (cairo_uint64_t i); + +cairo_uint64_t I _cairo_uint32_to_uint64 (uint32_t i); +#define _cairo_uint64_to_uint32(a) ((a).lo) +cairo_uint64_t I _cairo_uint64_add (cairo_uint64_t a, cairo_uint64_t b); +cairo_uint64_t I _cairo_uint64_sub (cairo_uint64_t a, cairo_uint64_t b); +cairo_uint64_t I _cairo_uint64_mul (cairo_uint64_t a, cairo_uint64_t b); +cairo_uint64_t I _cairo_uint32x32_64_mul (uint32_t a, uint32_t b); +cairo_uint64_t I _cairo_uint64_lsl (cairo_uint64_t a, int shift); +cairo_uint64_t I _cairo_uint64_rsl (cairo_uint64_t a, int shift); +cairo_uint64_t I _cairo_uint64_rsa (cairo_uint64_t a, int shift); +int I _cairo_uint64_lt (cairo_uint64_t a, cairo_uint64_t b); +int I _cairo_uint64_cmp (cairo_uint64_t a, cairo_uint64_t b); +int I _cairo_uint64_eq (cairo_uint64_t a, cairo_uint64_t b); +cairo_uint64_t I _cairo_uint64_negate (cairo_uint64_t a); +#define _cairo_uint64_is_zero(a) ((a).hi == 0 && (a).lo == 0) +#define _cairo_uint64_negative(a) (((int32_t) ((a).hi)) < 0) +cairo_uint64_t I _cairo_uint64_not (cairo_uint64_t a); + +#define _cairo_uint64_to_int64(i) (i) +#define _cairo_int64_to_uint64(i) (i) + +cairo_int64_t I _cairo_int32_to_int64(int32_t i); +#define _cairo_int64_to_int32(a) ((int32_t) _cairo_uint64_to_uint32(a)) +#define _cairo_int64_add(a,b) _cairo_uint64_add (a,b) +#define _cairo_int64_sub(a,b) _cairo_uint64_sub (a,b) +#define _cairo_int64_mul(a,b) _cairo_uint64_mul (a,b) +cairo_int64_t I _cairo_int32x32_64_mul (int32_t a, int32_t b); +int I _cairo_int64_lt (cairo_int64_t a, cairo_int64_t b); +int I _cairo_int64_cmp (cairo_int64_t a, cairo_int64_t b); +#define _cairo_int64_is_zero(a) _cairo_uint64_is_zero (a) +#define _cairo_int64_eq(a,b) _cairo_uint64_eq (a,b) +#define _cairo_int64_lsl(a,b) _cairo_uint64_lsl (a,b) +#define _cairo_int64_rsl(a,b) _cairo_uint64_rsl (a,b) +#define _cairo_int64_rsa(a,b) _cairo_uint64_rsa (a,b) +#define _cairo_int64_negate(a) _cairo_uint64_negate(a) +#define _cairo_int64_negative(a) (((int32_t) ((a).hi)) < 0) +#define _cairo_int64_not(a) _cairo_uint64_not(a) + +#else + +static inline cairo_uquorem64_t +_cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den) +{ + cairo_uquorem64_t qr; + + qr.quo = num / den; + qr.rem = num % den; + return qr; +} + +/* + * These need to be functions or gcc will complain when used on the + * result of a function: + * + * warning: cast from function call of type ‘#cairo_uint64_t’ to + * non-matching type ‘double’ + */ +static cairo_always_inline cairo_const cairo_uint64_t _cairo_double_to_uint64 (double i) { return i; } +static cairo_always_inline cairo_const double _cairo_uint64_to_double (cairo_uint64_t i) { return i; } + +static cairo_always_inline cairo_int64_t I _cairo_double_to_int64 (double i) { return i; } +static cairo_always_inline double I _cairo_int64_to_double (cairo_int64_t i) { return i; } + +#define _cairo_uint32_to_uint64(i) ((uint64_t) (i)) +#define _cairo_uint64_to_uint32(i) ((uint32_t) (i)) +#define _cairo_uint64_add(a,b) ((a) + (b)) +#define _cairo_uint64_sub(a,b) ((a) - (b)) +#define _cairo_uint64_mul(a,b) ((a) * (b)) +#define _cairo_uint32x32_64_mul(a,b) ((uint64_t) (a) * (b)) +#define _cairo_uint64_lsl(a,b) ((a) << (b)) +#define _cairo_uint64_rsl(a,b) ((uint64_t) (a) >> (b)) +#define _cairo_uint64_rsa(a,b) ((uint64_t) ((int64_t) (a) >> (b))) +#define _cairo_uint64_lt(a,b) ((a) < (b)) +#define _cairo_uint64_cmp(a,b) ((a) == (b) ? 0 : (a) < (b) ? -1 : 1) +#define _cairo_uint64_is_zero(a) ((a) == 0) +#define _cairo_uint64_eq(a,b) ((a) == (b)) +#define _cairo_uint64_negate(a) ((uint64_t) -((int64_t) (a))) +#define _cairo_uint64_negative(a) ((int64_t) (a) < 0) +#define _cairo_uint64_not(a) (~(a)) + +#define _cairo_uint64_to_int64(i) ((int64_t) (i)) +#define _cairo_int64_to_uint64(i) ((uint64_t) (i)) + +#define _cairo_int32_to_int64(i) ((int64_t) (i)) +#define _cairo_int64_to_int32(i) ((int32_t) (i)) +#define _cairo_int64_add(a,b) ((a) + (b)) +#define _cairo_int64_sub(a,b) ((a) - (b)) +#define _cairo_int64_mul(a,b) ((a) * (b)) +#define _cairo_int32x32_64_mul(a,b) ((int64_t) (a) * (b)) +#define _cairo_int64_lt(a,b) ((a) < (b)) +#define _cairo_int64_cmp(a,b) ((a) == (b) ? 0 : (a) < (b) ? -1 : 1) +#define _cairo_int64_is_zero(a) ((a) == 0) +#define _cairo_int64_eq(a,b) ((a) == (b)) +#define _cairo_int64_lsl(a,b) ((a) << (b)) +#define _cairo_int64_rsl(a,b) ((int64_t) ((uint64_t) (a) >> (b))) +#define _cairo_int64_rsa(a,b) ((int64_t) (a) >> (b)) +#define _cairo_int64_negate(a) (-(a)) +#define _cairo_int64_negative(a) ((a) < 0) +#define _cairo_int64_not(a) (~(a)) + +#endif + +/* + * 64-bit comparisons derived from lt or eq + */ +#define _cairo_uint64_le(a,b) (!_cairo_uint64_gt(a,b)) +#define _cairo_uint64_ne(a,b) (!_cairo_uint64_eq(a,b)) +#define _cairo_uint64_ge(a,b) (!_cairo_uint64_lt(a,b)) +#define _cairo_uint64_gt(a,b) _cairo_uint64_lt(b,a) + +#define _cairo_int64_le(a,b) (!_cairo_int64_gt(a,b)) +#define _cairo_int64_ne(a,b) (!_cairo_int64_eq(a,b)) +#define _cairo_int64_ge(a,b) (!_cairo_int64_lt(a,b)) +#define _cairo_int64_gt(a,b) _cairo_int64_lt(b,a) + +/* + * As the C implementation always computes both, create + * a function which returns both for the 'native' type as well + */ + +static inline cairo_quorem64_t +_cairo_int64_divrem (cairo_int64_t num, cairo_int64_t den) +{ + int num_neg = _cairo_int64_negative (num); + int den_neg = _cairo_int64_negative (den); + cairo_uquorem64_t uqr; + cairo_quorem64_t qr; + + if (num_neg) + num = _cairo_int64_negate (num); + if (den_neg) + den = _cairo_int64_negate (den); + uqr = _cairo_uint64_divrem (num, den); + if (num_neg) + qr.rem = _cairo_int64_negate (uqr.rem); + else + qr.rem = uqr.rem; + if (num_neg != den_neg) + qr.quo = (cairo_int64_t) _cairo_int64_negate (uqr.quo); + else + qr.quo = (cairo_int64_t) uqr.quo; + return qr; +} + +static inline int32_t +_cairo_int64_32_div (cairo_int64_t num, int32_t den) +{ +#if !HAVE_UINT64_T + return _cairo_int64_to_int32 + (_cairo_int64_divrem (num, _cairo_int32_to_int64 (den)).quo); +#else + return num / den; +#endif +} + +/* + * 128-bit datatypes. Again, provide two implementations in + * case the machine has a native 128-bit datatype. GCC supports int128_t + * on ia64 + */ + +#if !HAVE_UINT128_T + +cairo_uint128_t I _cairo_uint32_to_uint128 (uint32_t i); +cairo_uint128_t I _cairo_uint64_to_uint128 (cairo_uint64_t i); +#define _cairo_uint128_to_uint64(a) ((a).lo) +#define _cairo_uint128_to_uint32(a) _cairo_uint64_to_uint32(_cairo_uint128_to_uint64(a)) +cairo_uint128_t I _cairo_uint128_add (cairo_uint128_t a, cairo_uint128_t b); +cairo_uint128_t I _cairo_uint128_sub (cairo_uint128_t a, cairo_uint128_t b); +cairo_uint128_t I _cairo_uint128_mul (cairo_uint128_t a, cairo_uint128_t b); +cairo_uint128_t I _cairo_uint64x64_128_mul (cairo_uint64_t a, cairo_uint64_t b); +cairo_uint128_t I _cairo_uint128_lsl (cairo_uint128_t a, int shift); +cairo_uint128_t I _cairo_uint128_rsl (cairo_uint128_t a, int shift); +cairo_uint128_t I _cairo_uint128_rsa (cairo_uint128_t a, int shift); +int I _cairo_uint128_lt (cairo_uint128_t a, cairo_uint128_t b); +int I _cairo_uint128_cmp (cairo_uint128_t a, cairo_uint128_t b); +int I _cairo_uint128_eq (cairo_uint128_t a, cairo_uint128_t b); +#define _cairo_uint128_is_zero(a) (_cairo_uint64_is_zero ((a).hi) && _cairo_uint64_is_zero ((a).lo)) +cairo_uint128_t I _cairo_uint128_negate (cairo_uint128_t a); +#define _cairo_uint128_negative(a) (_cairo_uint64_negative(a.hi)) +cairo_uint128_t I _cairo_uint128_not (cairo_uint128_t a); + +#define _cairo_uint128_to_int128(i) (i) +#define _cairo_int128_to_uint128(i) (i) + +cairo_int128_t I _cairo_int32_to_int128 (int32_t i); +cairo_int128_t I _cairo_int64_to_int128 (cairo_int64_t i); +#define _cairo_int128_to_int64(a) ((cairo_int64_t) (a).lo) +#define _cairo_int128_to_int32(a) _cairo_int64_to_int32(_cairo_int128_to_int64(a)) +#define _cairo_int128_add(a,b) _cairo_uint128_add(a,b) +#define _cairo_int128_sub(a,b) _cairo_uint128_sub(a,b) +#define _cairo_int128_mul(a,b) _cairo_uint128_mul(a,b) +cairo_int128_t I _cairo_int64x64_128_mul (cairo_int64_t a, cairo_int64_t b); +#define _cairo_int64x32_128_mul(a, b) _cairo_int64x64_128_mul(a, _cairo_int32_to_int64(b)) +#define _cairo_int128_lsl(a,b) _cairo_uint128_lsl(a,b) +#define _cairo_int128_rsl(a,b) _cairo_uint128_rsl(a,b) +#define _cairo_int128_rsa(a,b) _cairo_uint128_rsa(a,b) +int I _cairo_int128_lt (cairo_int128_t a, cairo_int128_t b); +int I _cairo_int128_cmp (cairo_int128_t a, cairo_int128_t b); +#define _cairo_int128_is_zero(a) _cairo_uint128_is_zero (a) +#define _cairo_int128_eq(a,b) _cairo_uint128_eq (a,b) +#define _cairo_int128_negate(a) _cairo_uint128_negate(a) +#define _cairo_int128_negative(a) (_cairo_uint128_negative(a)) +#define _cairo_int128_not(a) _cairo_uint128_not(a) + +#else /* !HAVE_UINT128_T */ + +#define _cairo_uint32_to_uint128(i) ((uint128_t) (i)) +#define _cairo_uint64_to_uint128(i) ((uint128_t) (i)) +#define _cairo_uint128_to_uint64(i) ((uint64_t) (i)) +#define _cairo_uint128_to_uint32(i) ((uint32_t) (i)) +#define _cairo_uint128_add(a,b) ((a) + (b)) +#define _cairo_uint128_sub(a,b) ((a) - (b)) +#define _cairo_uint128_mul(a,b) ((a) * (b)) +#define _cairo_uint64x64_128_mul(a,b) ((uint128_t) (a) * (b)) +#define _cairo_uint128_lsl(a,b) ((a) << (b)) +#define _cairo_uint128_rsl(a,b) ((uint128_t) (a) >> (b)) +#define _cairo_uint128_rsa(a,b) ((uint128_t) ((int128_t) (a) >> (b))) +#define _cairo_uint128_lt(a,b) ((a) < (b)) +#define _cairo_uint128_cmp(a,b) ((a) == (b) ? 0 : (a) < (b) ? -1 : 1) +#define _cairo_uint128_is_zero(a) ((a) == 0) +#define _cairo_uint128_eq(a,b) ((a) == (b)) +#define _cairo_uint128_negate(a) ((uint128_t) -((int128_t) (a))) +#define _cairo_uint128_negative(a) ((int128_t) (a) < 0) +#define _cairo_uint128_not(a) (~(a)) + +#define _cairo_uint128_to_int128(i) ((int128_t) (i)) +#define _cairo_int128_to_uint128(i) ((uint128_t) (i)) + +#define _cairo_int32_to_int128(i) ((int128_t) (i)) +#define _cairo_int64_to_int128(i) ((int128_t) (i)) +#define _cairo_int128_to_int64(i) ((int64_t) (i)) +#define _cairo_int128_to_int32(i) ((int32_t) (i)) +#define _cairo_int128_add(a,b) ((a) + (b)) +#define _cairo_int128_sub(a,b) ((a) - (b)) +#define _cairo_int128_mul(a,b) ((a) * (b)) +#define _cairo_int64x64_128_mul(a,b) ((int128_t) (a) * (b)) +#define _cairo_int64x32_128_mul(a, b) _cairo_int64x64_128_mul(a, _cairo_int32_to_int64(b)) +#define _cairo_int128_lt(a,b) ((a) < (b)) +#define _cairo_int128_cmp(a,b) ((a) == (b) ? 0 : (a) < (b) ? -1 : 1) +#define _cairo_int128_is_zero(a) ((a) == 0) +#define _cairo_int128_eq(a,b) ((a) == (b)) +#define _cairo_int128_lsl(a,b) ((a) << (b)) +#define _cairo_int128_rsl(a,b) ((int128_t) ((uint128_t) (a) >> (b))) +#define _cairo_int128_rsa(a,b) ((int128_t) (a) >> (b)) +#define _cairo_int128_negate(a) (-(a)) +#define _cairo_int128_negative(a) ((a) < 0) +#define _cairo_int128_not(a) (~(a)) + +#endif /* HAVE_UINT128_T */ + +cairo_uquorem128_t I +_cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den); + +cairo_quorem128_t I +_cairo_int128_divrem (cairo_int128_t num, cairo_int128_t den); + +cairo_uquorem64_t I +_cairo_uint_96by64_32x64_divrem (cairo_uint128_t num, + cairo_uint64_t den); + +cairo_quorem64_t I +_cairo_int_96by64_32x64_divrem (cairo_int128_t num, + cairo_int64_t den); + +#define _cairo_uint128_le(a,b) (!_cairo_uint128_gt(a,b)) +#define _cairo_uint128_ne(a,b) (!_cairo_uint128_eq(a,b)) +#define _cairo_uint128_ge(a,b) (!_cairo_uint128_lt(a,b)) +#define _cairo_uint128_gt(a,b) _cairo_uint128_lt(b,a) + +#define _cairo_int128_le(a,b) (!_cairo_int128_gt(a,b)) +#define _cairo_int128_ne(a,b) (!_cairo_int128_eq(a,b)) +#define _cairo_int128_ge(a,b) (!_cairo_int128_lt(a,b)) +#define _cairo_int128_gt(a,b) _cairo_int128_lt(b,a) + +#undef I + +#endif /* CAIRO_WIDEINT_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-wideint-type-private.h b/local/recipes/libs/cairo/source/src/cairo-wideint-type-private.h new file mode 100644 index 0000000000..a1a2269f87 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-wideint-type-private.h @@ -0,0 +1,156 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2004 Keith Packard + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Keith Packard + * + * Contributor(s): + * Keith R. Packard + * + */ + +#ifndef CAIRO_WIDEINT_TYPE_H +#define CAIRO_WIDEINT_TYPE_H + +#include "cairo.h" + +#include "config.h" + +#if HAVE_STDINT_H +# include +#elif HAVE_INTTYPES_H +# include +#elif HAVE_SYS_INT_TYPES_H +# include +#elif defined(_MSC_VER) + typedef __int8 int8_t; + typedef unsigned __int8 uint8_t; + typedef __int16 int16_t; + typedef unsigned __int16 uint16_t; + typedef __int32 int32_t; + typedef unsigned __int32 uint32_t; + typedef __int64 int64_t; + typedef unsigned __int64 uint64_t; +# ifndef HAVE_UINT64_T +# define HAVE_UINT64_T 1 +# endif +#else +#error Cannot find definitions for fixed-width integral types (uint8_t, uint32_t, etc.) +#endif + +#ifndef INT16_MIN +# define INT16_MIN (-32767-1) +#endif +#ifndef INT16_MAX +# define INT16_MAX (32767) +#endif +#ifndef UINT16_MAX +# define UINT16_MAX (65535) +#endif +#ifndef INT32_MIN +# define INT32_MIN (-2147483647-1) +#endif +#ifndef INT32_MAX +# define INT32_MAX (2147483647) +#endif +#ifndef UINT32_MAX +# define UINT32_MAX (4294967295U) +#endif + +#if HAVE_BYTESWAP_H +# include +#endif +#ifndef bswap_16 +# define bswap_16(p) \ + (((((uint16_t)(p)) & 0x00ff) << 8) | \ + (((uint16_t)(p)) >> 8)); +#endif +#ifndef bswap_32 +# define bswap_32(p) \ + (((((uint32_t)(p)) & 0x000000ff) << 24) | \ + ((((uint32_t)(p)) & 0x0000ff00) << 8) | \ + ((((uint32_t)(p)) & 0x00ff0000) >> 8) | \ + ((((uint32_t)(p))) >> 24)); +#endif + + +#if !HAVE_UINT64_T + +typedef struct _cairo_uint64 { + uint32_t lo, hi; +} cairo_uint64_t, cairo_int64_t; + +#else + +typedef uint64_t cairo_uint64_t; +typedef int64_t cairo_int64_t; + +#endif + +typedef struct _cairo_uquorem64 { + cairo_uint64_t quo; + cairo_uint64_t rem; +} cairo_uquorem64_t; + +typedef struct _cairo_quorem64 { + cairo_int64_t quo; + cairo_int64_t rem; +} cairo_quorem64_t; + +/* gcc has a non-standard name. */ +#if HAVE___UINT128_T && !HAVE_UINT128_T +typedef __uint128_t uint128_t; +typedef __int128_t int128_t; +#define HAVE_UINT128_T 1 +#endif + +#if !HAVE_UINT128_T + +typedef struct cairo_uint128 { + cairo_uint64_t lo, hi; +} cairo_uint128_t, cairo_int128_t; + +#else + +typedef uint128_t cairo_uint128_t; +typedef int128_t cairo_int128_t; + +#endif + +typedef struct _cairo_uquorem128 { + cairo_uint128_t quo; + cairo_uint128_t rem; +} cairo_uquorem128_t; + +typedef struct _cairo_quorem128 { + cairo_int128_t quo; + cairo_int128_t rem; +} cairo_quorem128_t; + + +#endif /* CAIRO_WIDEINT_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-wideint.c b/local/recipes/libs/cairo/source/src/cairo-wideint.c new file mode 100644 index 0000000000..2e056fa36a --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-wideint.c @@ -0,0 +1,852 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2004 Keith Packard + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Keith Packard + * + * Contributor(s): + * Keith R. Packard + */ + +#include "cairoint.h" + +#if HAVE_UINT64_T + +#define uint64_lo32(i) ((i) & 0xffffffff) +#define uint64_hi32(i) ((i) >> 32) +#define uint64_lo(i) ((i) & 0xffffffff) +#define uint64_hi(i) ((i) >> 32) +#define uint64_shift32(i) ((i) << 32) +#define uint64_carry32 (((uint64_t) 1) << 32) + +#define _cairo_uint32s_to_uint64(h,l) ((uint64_t) (h) << 32 | (l)) + +#else + +#define uint64_lo32(i) ((i).lo) +#define uint64_hi32(i) ((i).hi) + +static cairo_uint64_t +uint64_lo (cairo_uint64_t i) +{ + cairo_uint64_t s; + + s.lo = i.lo; + s.hi = 0; + return s; +} + +static cairo_uint64_t +uint64_hi (cairo_uint64_t i) +{ + cairo_uint64_t s; + + s.lo = i.hi; + s.hi = 0; + return s; +} + +static cairo_uint64_t +uint64_shift32 (cairo_uint64_t i) +{ + cairo_uint64_t s; + + s.lo = 0; + s.hi = i.lo; + return s; +} + +static const cairo_uint64_t uint64_carry32 = { 0, 1 }; + +cairo_uint64_t +_cairo_double_to_uint64 (double i) +{ + cairo_uint64_t q; + + q.hi = i * (1. / 4294967296.); + q.lo = i - q.hi * 4294967296.; + return q; +} + +double +_cairo_uint64_to_double (cairo_uint64_t i) +{ + return i.hi * 4294967296. + i.lo; +} + +cairo_int64_t +_cairo_double_to_int64 (double i) +{ + cairo_uint64_t q; + + q.hi = i * (1. / INT32_MAX); + q.lo = i - q.hi * (double)INT32_MAX; + return q; +} + +double +_cairo_int64_to_double (cairo_int64_t i) +{ + return i.hi * INT32_MAX + i.lo; +} + +cairo_uint64_t +_cairo_uint32_to_uint64 (uint32_t i) +{ + cairo_uint64_t q; + + q.lo = i; + q.hi = 0; + return q; +} + +cairo_int64_t +_cairo_int32_to_int64 (int32_t i) +{ + cairo_uint64_t q; + + q.lo = i; + q.hi = i < 0 ? -1 : 0; + return q; +} + +static cairo_uint64_t +_cairo_uint32s_to_uint64 (uint32_t h, uint32_t l) +{ + cairo_uint64_t q; + + q.lo = l; + q.hi = h; + return q; +} + +cairo_uint64_t +_cairo_uint64_add (cairo_uint64_t a, cairo_uint64_t b) +{ + cairo_uint64_t s; + + s.hi = a.hi + b.hi; + s.lo = a.lo + b.lo; + if (s.lo < a.lo) + s.hi++; + return s; +} + +cairo_uint64_t +_cairo_uint64_sub (cairo_uint64_t a, cairo_uint64_t b) +{ + cairo_uint64_t s; + + s.hi = a.hi - b.hi; + s.lo = a.lo - b.lo; + if (s.lo > a.lo) + s.hi--; + return s; +} + +#define uint32_lo(i) ((i) & 0xffff) +#define uint32_hi(i) ((i) >> 16) +#define uint32_carry16 ((1) << 16) + +cairo_uint64_t +_cairo_uint32x32_64_mul (uint32_t a, uint32_t b) +{ + cairo_uint64_t s; + + uint16_t ah, al, bh, bl; + uint32_t r0, r1, r2, r3; + + al = uint32_lo (a); + ah = uint32_hi (a); + bl = uint32_lo (b); + bh = uint32_hi (b); + + r0 = (uint32_t) al * bl; + r1 = (uint32_t) al * bh; + r2 = (uint32_t) ah * bl; + r3 = (uint32_t) ah * bh; + + r1 += uint32_hi(r0); /* no carry possible */ + r1 += r2; /* but this can carry */ + if (r1 < r2) /* check */ + r3 += uint32_carry16; + + s.hi = r3 + uint32_hi(r1); + s.lo = (uint32_lo (r1) << 16) + uint32_lo (r0); + return s; +} + +cairo_int64_t +_cairo_int32x32_64_mul (int32_t a, int32_t b) +{ + cairo_int64_t s; + s = _cairo_uint32x32_64_mul ((uint32_t) a, (uint32_t) b); + if (a < 0) + s.hi -= b; + if (b < 0) + s.hi -= a; + return s; +} + +cairo_uint64_t +_cairo_uint64_mul (cairo_uint64_t a, cairo_uint64_t b) +{ + cairo_uint64_t s; + + s = _cairo_uint32x32_64_mul (a.lo, b.lo); + s.hi += a.lo * b.hi + a.hi * b.lo; + return s; +} + +cairo_uint64_t +_cairo_uint64_lsl (cairo_uint64_t a, int shift) +{ + if (shift >= 32) + { + a.hi = a.lo; + a.lo = 0; + shift -= 32; + } + if (shift) + { + a.hi = a.hi << shift | a.lo >> (32 - shift); + a.lo = a.lo << shift; + } + return a; +} + +cairo_uint64_t +_cairo_uint64_rsl (cairo_uint64_t a, int shift) +{ + if (shift >= 32) + { + a.lo = a.hi; + a.hi = 0; + shift -= 32; + } + if (shift) + { + a.lo = a.lo >> shift | a.hi << (32 - shift); + a.hi = a.hi >> shift; + } + return a; +} + +#define _cairo_uint32_rsa(a,n) ((uint32_t) (((int32_t) (a)) >> (n))) + +cairo_int64_t +_cairo_uint64_rsa (cairo_int64_t a, int shift) +{ + if (shift >= 32) + { + a.lo = a.hi; + a.hi = _cairo_uint32_rsa (a.hi, 31); + shift -= 32; + } + if (shift) + { + a.lo = a.lo >> shift | a.hi << (32 - shift); + a.hi = _cairo_uint32_rsa (a.hi, shift); + } + return a; +} + +int +_cairo_uint64_lt (cairo_uint64_t a, cairo_uint64_t b) +{ + return (a.hi < b.hi || + (a.hi == b.hi && a.lo < b.lo)); +} + +int +_cairo_uint64_eq (cairo_uint64_t a, cairo_uint64_t b) +{ + return a.hi == b.hi && a.lo == b.lo; +} + +int +_cairo_int64_lt (cairo_int64_t a, cairo_int64_t b) +{ + if (_cairo_int64_negative (a) && !_cairo_int64_negative (b)) + return 1; + if (!_cairo_int64_negative (a) && _cairo_int64_negative (b)) + return 0; + return _cairo_uint64_lt (a, b); +} + +int +_cairo_uint64_cmp (cairo_uint64_t a, cairo_uint64_t b) +{ + if (a.hi < b.hi) + return -1; + else if (a.hi > b.hi) + return 1; + else if (a.lo < b.lo) + return -1; + else if (a.lo > b.lo) + return 1; + else + return 0; +} + +int +_cairo_int64_cmp (cairo_int64_t a, cairo_int64_t b) +{ + if (_cairo_int64_negative (a) && !_cairo_int64_negative (b)) + return -1; + if (!_cairo_int64_negative (a) && _cairo_int64_negative (b)) + return 1; + + return _cairo_uint64_cmp (a, b); +} + +cairo_uint64_t +_cairo_uint64_not (cairo_uint64_t a) +{ + a.lo = ~a.lo; + a.hi = ~a.hi; + return a; +} + +cairo_uint64_t +_cairo_uint64_negate (cairo_uint64_t a) +{ + a.lo = ~a.lo; + a.hi = ~a.hi; + if (++a.lo == 0) + ++a.hi; + return a; +} + +/* + * Simple bit-at-a-time divide. + */ +cairo_uquorem64_t +_cairo_uint64_divrem (cairo_uint64_t num, cairo_uint64_t den) +{ + cairo_uquorem64_t qr; + cairo_uint64_t bit; + cairo_uint64_t quo; + + bit = _cairo_uint32_to_uint64 (1); + + /* normalize to make den >= num, but not overflow */ + while (_cairo_uint64_lt (den, num) && (den.hi & 0x80000000) == 0) + { + bit = _cairo_uint64_lsl (bit, 1); + den = _cairo_uint64_lsl (den, 1); + } + quo = _cairo_uint32_to_uint64 (0); + + /* generate quotient, one bit at a time */ + while (bit.hi | bit.lo) + { + if (_cairo_uint64_le (den, num)) + { + num = _cairo_uint64_sub (num, den); + quo = _cairo_uint64_add (quo, bit); + } + bit = _cairo_uint64_rsl (bit, 1); + den = _cairo_uint64_rsl (den, 1); + } + qr.quo = quo; + qr.rem = num; + return qr; +} + +#endif /* !HAVE_UINT64_T */ + +#if HAVE_UINT128_T +cairo_uquorem128_t +_cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den) +{ + cairo_uquorem128_t qr; + + qr.quo = num / den; + qr.rem = num % den; + return qr; +} + +#else + +cairo_uint128_t +_cairo_uint32_to_uint128 (uint32_t i) +{ + cairo_uint128_t q; + + q.lo = _cairo_uint32_to_uint64 (i); + q.hi = _cairo_uint32_to_uint64 (0); + return q; +} + +cairo_int128_t +_cairo_int32_to_int128 (int32_t i) +{ + cairo_int128_t q; + + q.lo = _cairo_int32_to_int64 (i); + q.hi = _cairo_int32_to_int64 (i < 0 ? -1 : 0); + return q; +} + +cairo_uint128_t +_cairo_uint64_to_uint128 (cairo_uint64_t i) +{ + cairo_uint128_t q; + + q.lo = i; + q.hi = _cairo_uint32_to_uint64 (0); + return q; +} + +cairo_int128_t +_cairo_int64_to_int128 (cairo_int64_t i) +{ + cairo_int128_t q; + + q.lo = i; + q.hi = _cairo_int32_to_int64 (_cairo_int64_negative(i) ? -1 : 0); + return q; +} + +cairo_uint128_t +_cairo_uint128_add (cairo_uint128_t a, cairo_uint128_t b) +{ + cairo_uint128_t s; + + s.hi = _cairo_uint64_add (a.hi, b.hi); + s.lo = _cairo_uint64_add (a.lo, b.lo); + if (_cairo_uint64_lt (s.lo, a.lo)) + s.hi = _cairo_uint64_add (s.hi, _cairo_uint32_to_uint64 (1)); + return s; +} + +cairo_uint128_t +_cairo_uint128_sub (cairo_uint128_t a, cairo_uint128_t b) +{ + cairo_uint128_t s; + + s.hi = _cairo_uint64_sub (a.hi, b.hi); + s.lo = _cairo_uint64_sub (a.lo, b.lo); + if (_cairo_uint64_gt (s.lo, a.lo)) + s.hi = _cairo_uint64_sub (s.hi, _cairo_uint32_to_uint64(1)); + return s; +} + +cairo_uint128_t +_cairo_uint64x64_128_mul (cairo_uint64_t a, cairo_uint64_t b) +{ + cairo_uint128_t s; + uint32_t ah, al, bh, bl; + cairo_uint64_t r0, r1, r2, r3; + + al = uint64_lo32 (a); + ah = uint64_hi32 (a); + bl = uint64_lo32 (b); + bh = uint64_hi32 (b); + + r0 = _cairo_uint32x32_64_mul (al, bl); + r1 = _cairo_uint32x32_64_mul (al, bh); + r2 = _cairo_uint32x32_64_mul (ah, bl); + r3 = _cairo_uint32x32_64_mul (ah, bh); + + r1 = _cairo_uint64_add (r1, uint64_hi (r0)); /* no carry possible */ + r1 = _cairo_uint64_add (r1, r2); /* but this can carry */ + if (_cairo_uint64_lt (r1, r2)) /* check */ + r3 = _cairo_uint64_add (r3, uint64_carry32); + + s.hi = _cairo_uint64_add (r3, uint64_hi(r1)); + s.lo = _cairo_uint64_add (uint64_shift32 (r1), + uint64_lo (r0)); + return s; +} + +cairo_int128_t +_cairo_int64x64_128_mul (cairo_int64_t a, cairo_int64_t b) +{ + cairo_int128_t s; + s = _cairo_uint64x64_128_mul (_cairo_int64_to_uint64(a), + _cairo_int64_to_uint64(b)); + if (_cairo_int64_negative (a)) + s.hi = _cairo_uint64_sub (s.hi, + _cairo_int64_to_uint64 (b)); + if (_cairo_int64_negative (b)) + s.hi = _cairo_uint64_sub (s.hi, + _cairo_int64_to_uint64 (a)); + return s; +} + +cairo_uint128_t +_cairo_uint128_mul (cairo_uint128_t a, cairo_uint128_t b) +{ + cairo_uint128_t s; + + s = _cairo_uint64x64_128_mul (a.lo, b.lo); + s.hi = _cairo_uint64_add (s.hi, + _cairo_uint64_mul (a.lo, b.hi)); + s.hi = _cairo_uint64_add (s.hi, + _cairo_uint64_mul (a.hi, b.lo)); + return s; +} + +cairo_uint128_t +_cairo_uint128_lsl (cairo_uint128_t a, int shift) +{ + if (shift >= 64) + { + a.hi = a.lo; + a.lo = _cairo_uint32_to_uint64 (0); + shift -= 64; + } + if (shift) + { + a.hi = _cairo_uint64_add (_cairo_uint64_lsl (a.hi, shift), + _cairo_uint64_rsl (a.lo, (64 - shift))); + a.lo = _cairo_uint64_lsl (a.lo, shift); + } + return a; +} + +cairo_uint128_t +_cairo_uint128_rsl (cairo_uint128_t a, int shift) +{ + if (shift >= 64) + { + a.lo = a.hi; + a.hi = _cairo_uint32_to_uint64 (0); + shift -= 64; + } + if (shift) + { + a.lo = _cairo_uint64_add (_cairo_uint64_rsl (a.lo, shift), + _cairo_uint64_lsl (a.hi, (64 - shift))); + a.hi = _cairo_uint64_rsl (a.hi, shift); + } + return a; +} + +cairo_uint128_t +_cairo_uint128_rsa (cairo_int128_t a, int shift) +{ + if (shift >= 64) + { + a.lo = a.hi; + a.hi = _cairo_uint64_rsa (a.hi, 64-1); + shift -= 64; + } + if (shift) + { + a.lo = _cairo_uint64_add (_cairo_uint64_rsl (a.lo, shift), + _cairo_uint64_lsl (a.hi, (64 - shift))); + a.hi = _cairo_uint64_rsa (a.hi, shift); + } + return a; +} + +int +_cairo_uint128_lt (cairo_uint128_t a, cairo_uint128_t b) +{ + return (_cairo_uint64_lt (a.hi, b.hi) || + (_cairo_uint64_eq (a.hi, b.hi) && + _cairo_uint64_lt (a.lo, b.lo))); +} + +int +_cairo_int128_lt (cairo_int128_t a, cairo_int128_t b) +{ + if (_cairo_int128_negative (a) && !_cairo_int128_negative (b)) + return 1; + if (!_cairo_int128_negative (a) && _cairo_int128_negative (b)) + return 0; + return _cairo_uint128_lt (a, b); +} + +int +_cairo_uint128_cmp (cairo_uint128_t a, cairo_uint128_t b) +{ + int cmp; + + cmp = _cairo_uint64_cmp (a.hi, b.hi); + if (cmp) + return cmp; + return _cairo_uint64_cmp (a.lo, b.lo); +} + +int +_cairo_int128_cmp (cairo_int128_t a, cairo_int128_t b) +{ + if (_cairo_int128_negative (a) && !_cairo_int128_negative (b)) + return -1; + if (!_cairo_int128_negative (a) && _cairo_int128_negative (b)) + return 1; + + return _cairo_uint128_cmp (a, b); +} + +int +_cairo_uint128_eq (cairo_uint128_t a, cairo_uint128_t b) +{ + return (_cairo_uint64_eq (a.hi, b.hi) && + _cairo_uint64_eq (a.lo, b.lo)); +} + +#if HAVE_UINT64_T +#define _cairo_msbset64(q) (q & ((uint64_t) 1 << 63)) +#else +#define _cairo_msbset64(q) (q.hi & ((uint32_t) 1 << 31)) +#endif + +cairo_uquorem128_t +_cairo_uint128_divrem (cairo_uint128_t num, cairo_uint128_t den) +{ + cairo_uquorem128_t qr; + cairo_uint128_t bit; + cairo_uint128_t quo; + + bit = _cairo_uint32_to_uint128 (1); + + /* normalize to make den >= num, but not overflow */ + while (_cairo_uint128_lt (den, num) && !_cairo_msbset64(den.hi)) + { + bit = _cairo_uint128_lsl (bit, 1); + den = _cairo_uint128_lsl (den, 1); + } + quo = _cairo_uint32_to_uint128 (0); + + /* generate quotient, one bit at a time */ + while (_cairo_uint128_ne (bit, _cairo_uint32_to_uint128(0))) + { + if (_cairo_uint128_le (den, num)) + { + num = _cairo_uint128_sub (num, den); + quo = _cairo_uint128_add (quo, bit); + } + bit = _cairo_uint128_rsl (bit, 1); + den = _cairo_uint128_rsl (den, 1); + } + qr.quo = quo; + qr.rem = num; + return qr; +} + +cairo_uint128_t +_cairo_uint128_negate (cairo_uint128_t a) +{ + a.lo = _cairo_uint64_not (a.lo); + a.hi = _cairo_uint64_not (a.hi); + return _cairo_uint128_add (a, _cairo_uint32_to_uint128 (1)); +} + +cairo_uint128_t +_cairo_uint128_not (cairo_uint128_t a) +{ + a.lo = _cairo_uint64_not (a.lo); + a.hi = _cairo_uint64_not (a.hi); + return a; +} + +#endif /* !HAVE_UINT128_T */ + +cairo_quorem128_t +_cairo_int128_divrem (cairo_int128_t num, cairo_int128_t den) +{ + int num_neg = _cairo_int128_negative (num); + int den_neg = _cairo_int128_negative (den); + cairo_uquorem128_t uqr; + cairo_quorem128_t qr; + + if (num_neg) + num = _cairo_int128_negate (num); + if (den_neg) + den = _cairo_int128_negate (den); + uqr = _cairo_uint128_divrem (num, den); + if (num_neg) + qr.rem = _cairo_int128_negate (uqr.rem); + else + qr.rem = uqr.rem; + if (num_neg != den_neg) + qr.quo = _cairo_int128_negate (uqr.quo); + else + qr.quo = uqr.quo; + return qr; +} + +/** + * _cairo_uint_96by64_32x64_divrem: + * + * Compute a 32 bit quotient and 64 bit remainder of a 96 bit unsigned + * dividend and 64 bit divisor. If the quotient doesn't fit into 32 + * bits then the returned remainder is equal to the divisor, and the + * quotient is the largest representable 64 bit integer. It is an + * error to call this function with the high 32 bits of @num being + * non-zero. + **/ +cairo_uquorem64_t +_cairo_uint_96by64_32x64_divrem (cairo_uint128_t num, + cairo_uint64_t den) +{ + cairo_uquorem64_t result; + cairo_uint64_t B = _cairo_uint32s_to_uint64 (1, 0); + + /* These are the high 64 bits of the *96* bit numerator. We're + * going to represent the numerator as xB + y, where x is a 64, + * and y is a 32 bit number. */ + cairo_uint64_t x = _cairo_uint128_to_uint64 (_cairo_uint128_rsl(num, 32)); + + /* Initialise the result to indicate overflow. */ + result.quo = _cairo_uint32s_to_uint64 (-1U, -1U); + result.rem = den; + + /* Don't bother if the quotient is going to overflow. */ + if (_cairo_uint64_ge (x, den)) { + return /* overflow */ result; + } + + if (_cairo_uint64_lt (x, B)) { + /* When the final quotient is known to fit in 32 bits, then + * num < 2^64 if and only if den < 2^32. */ + return _cairo_uint64_divrem (_cairo_uint128_to_uint64 (num), den); + } + else { + /* Denominator is >= 2^32. the numerator is >= 2^64, and the + * division won't overflow: need two divrems. Write the + * numerator and denominator as + * + * num = xB + y x : 64 bits, y : 32 bits + * den = uB + v u, v : 32 bits + */ + uint32_t y = _cairo_uint128_to_uint32 (num); + uint32_t u = uint64_hi32 (den); + uint32_t v = _cairo_uint64_to_uint32 (den); + + /* Compute a lower bound approximate quotient of num/den + * from x/(u+1). Then we have + * + * x = q(u+1) + r ; q : 32 bits, r <= u : 32 bits. + * + * xB + y = q(u+1)B + (rB+y) + * = q(uB + B + v - v) + (rB+y) + * = q(uB + v) + qB - qv + (rB+y) + * = q(uB + v) + q(B-v) + (rB+y) + * + * The true quotient of num/den then is q plus the + * contribution of q(B-v) + (rB+y). The main contribution + * comes from the term q(B-v), with the term (rB+y) only + * contributing at most one part. + * + * The term q(B-v) must fit into 64 bits, since q fits into 32 + * bits on account of being a lower bound to the true + * quotient, and as B-v <= 2^32, we may safely use a single + * 64/64 bit division to find its contribution. */ + + cairo_uquorem64_t quorem; + cairo_uint64_t remainder; /* will contain final remainder */ + uint32_t quotient; /* will contain final quotient. */ + uint32_t q; + uint32_t r; + + /* Approximate quotient by dividing the high 64 bits of num by + * u+1. Watch out for overflow of u+1. */ + if (u+1) { + quorem = _cairo_uint64_divrem (x, _cairo_uint32_to_uint64 (u+1)); + q = _cairo_uint64_to_uint32 (quorem.quo); + r = _cairo_uint64_to_uint32 (quorem.rem); + } + else { + q = uint64_hi32 (x); + r = _cairo_uint64_to_uint32 (x); + } + quotient = q; + + /* Add the main term's contribution to quotient. Note B-v = + * -v as an uint32 (unless v = 0) */ + if (v) + quorem = _cairo_uint64_divrem (_cairo_uint32x32_64_mul (q, -v), den); + else + quorem = _cairo_uint64_divrem (_cairo_uint32s_to_uint64 (q, 0), den); + quotient += _cairo_uint64_to_uint32 (quorem.quo); + + /* Add the contribution of the subterm and start computing the + * true remainder. */ + remainder = _cairo_uint32s_to_uint64 (r, y); + if (_cairo_uint64_ge (remainder, den)) { + remainder = _cairo_uint64_sub (remainder, den); + quotient++; + } + + /* Add the contribution of the main term's remainder. The + * funky test here checks that remainder + main_rem >= den, + * taking into account overflow of the addition. */ + remainder = _cairo_uint64_add (remainder, quorem.rem); + if (_cairo_uint64_ge (remainder, den) || + _cairo_uint64_lt (remainder, quorem.rem)) + { + remainder = _cairo_uint64_sub (remainder, den); + quotient++; + } + + result.quo = _cairo_uint32_to_uint64 (quotient); + result.rem = remainder; + } + return result; +} + +cairo_quorem64_t +_cairo_int_96by64_32x64_divrem (cairo_int128_t num, cairo_int64_t den) +{ + int num_neg = _cairo_int128_negative (num); + int den_neg = _cairo_int64_negative (den); + cairo_uint64_t nonneg_den; + cairo_uquorem64_t uqr; + cairo_quorem64_t qr; + + if (num_neg) + num = _cairo_int128_negate (num); + if (den_neg) + nonneg_den = _cairo_int64_negate (den); + else + nonneg_den = den; + + uqr = _cairo_uint_96by64_32x64_divrem (num, nonneg_den); + if (_cairo_uint64_eq (uqr.rem, nonneg_den)) { + /* bail on overflow. */ + qr.quo = _cairo_uint32s_to_uint64 (0x7FFFFFFF, -1U); + qr.rem = den; + return qr; + } + + if (num_neg) + qr.rem = _cairo_int64_negate (uqr.rem); + else + qr.rem = uqr.rem; + if (num_neg != den_neg) + qr.quo = _cairo_int64_negate (uqr.quo); + else + qr.quo = uqr.quo; + return qr; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-win32.h b/local/recipes/libs/cairo/source/src/cairo-win32.h new file mode 100644 index 0000000000..db4cac69f4 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-win32.h @@ -0,0 +1,116 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Owen Taylor + */ + +#ifndef _CAIRO_WIN32_H_ +#define _CAIRO_WIN32_H_ + +#include "cairo.h" + +#if CAIRO_HAS_WIN32_SURFACE + +#include + +CAIRO_BEGIN_DECLS + +cairo_public cairo_surface_t * +cairo_win32_surface_create (HDC hdc); + +cairo_public cairo_surface_t * +cairo_win32_surface_create_with_format (HDC hdc, + cairo_format_t format); + +cairo_public cairo_surface_t * +cairo_win32_printing_surface_create (HDC hdc); + +cairo_public cairo_surface_t * +cairo_win32_surface_create_with_ddb (HDC hdc, + cairo_format_t format, + int width, + int height); + +cairo_public cairo_surface_t * +cairo_win32_surface_create_with_dib (cairo_format_t format, + int width, + int height); + +cairo_public HDC +cairo_win32_surface_get_dc (cairo_surface_t *surface); + +cairo_public cairo_surface_t * +cairo_win32_surface_get_image (cairo_surface_t *surface); + +#if CAIRO_HAS_WIN32_FONT + +/* + * Win32 font support + */ + +cairo_public cairo_font_face_t * +cairo_win32_font_face_create_for_logfontw (LOGFONTW *logfont); + +cairo_public cairo_font_face_t * +cairo_win32_font_face_create_for_hfont (HFONT font); + +cairo_public cairo_font_face_t * +cairo_win32_font_face_create_for_logfontw_hfont (LOGFONTW *logfont, HFONT font); + +cairo_public cairo_status_t +cairo_win32_scaled_font_select_font (cairo_scaled_font_t *scaled_font, + HDC hdc); + +cairo_public void +cairo_win32_scaled_font_done_font (cairo_scaled_font_t *scaled_font); + +cairo_public double +cairo_win32_scaled_font_get_metrics_factor (cairo_scaled_font_t *scaled_font); + +cairo_public void +cairo_win32_scaled_font_get_logical_to_device (cairo_scaled_font_t *scaled_font, + cairo_matrix_t *logical_to_device); + +cairo_public void +cairo_win32_scaled_font_get_device_to_logical (cairo_scaled_font_t *scaled_font, + cairo_matrix_t *device_to_logical); + +#endif /* CAIRO_HAS_WIN32_FONT */ + +CAIRO_END_DECLS + +#else /* CAIRO_HAS_WIN32_SURFACE */ +# error Cairo was not compiled with support for the win32 backend +#endif /* CAIRO_HAS_WIN32_SURFACE */ + +#endif /* _CAIRO_WIN32_H_ */ diff --git a/local/recipes/libs/cairo/source/src/cairo-xcb-connection-core.c b/local/recipes/libs/cairo/source/src/cairo-xcb-connection-core.c new file mode 100644 index 0000000000..71d2e515b3 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-xcb-connection-core.c @@ -0,0 +1,284 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * Contributor(s): + * Chris Wilson + */ + +#include "cairoint.h" + +#include "cairo-xcb-private.h" + +#include + +xcb_pixmap_t +_cairo_xcb_connection_create_pixmap (cairo_xcb_connection_t *connection, + uint8_t depth, + xcb_drawable_t drawable, + uint16_t width, + uint16_t height) +{ + xcb_pixmap_t pixmap = xcb_generate_id (connection->xcb_connection); + + assert (width > 0); + assert (height > 0); + xcb_create_pixmap (connection->xcb_connection, + depth, pixmap, drawable, + width, height); + return pixmap; +} + +xcb_gcontext_t +_cairo_xcb_connection_create_gc (cairo_xcb_connection_t *connection, + xcb_drawable_t drawable, + uint32_t value_mask, + uint32_t *values) +{ + xcb_gcontext_t gc = xcb_generate_id (connection->xcb_connection); + xcb_create_gc (connection->xcb_connection, gc, drawable, + value_mask, values); + return gc; +} + +void +_cairo_xcb_connection_change_gc (cairo_xcb_connection_t *connection, + xcb_gcontext_t gc, + uint32_t value_mask, + uint32_t *values) +{ + xcb_change_gc (connection->xcb_connection, gc, + value_mask, values); +} + +void +_cairo_xcb_connection_copy_area (cairo_xcb_connection_t *connection, + xcb_drawable_t src, + xcb_drawable_t dst, + xcb_gcontext_t gc, + int16_t src_x, + int16_t src_y, + int16_t dst_x, + int16_t dst_y, + uint16_t width, + uint16_t height) +{ + xcb_copy_area (connection->xcb_connection, src, dst, gc, + src_x, src_y, dst_x, dst_y, width, height); +} + +void +_cairo_xcb_connection_poly_fill_rectangle (cairo_xcb_connection_t *connection, + xcb_drawable_t dst, + xcb_gcontext_t gc, + uint32_t num_rectangles, + xcb_rectangle_t *rectangles) +{ + xcb_poly_fill_rectangle (connection->xcb_connection, dst, gc, + num_rectangles, rectangles); +} + +void +_cairo_xcb_connection_put_image (cairo_xcb_connection_t *connection, + xcb_drawable_t dst, + xcb_gcontext_t gc, + uint16_t width, + uint16_t height, + int16_t dst_x, + int16_t dst_y, + uint8_t depth, + uint32_t stride, + void *data) +{ + const uint32_t req_size = 18; + uint32_t length = height * stride; + uint32_t len = (req_size + length) >> 2; + + if (len < connection->maximum_request_length) { + xcb_put_image (connection->xcb_connection, XCB_IMAGE_FORMAT_Z_PIXMAP, + dst, gc, width, height, dst_x, dst_y, 0, depth, + length, data); + } else { + int rows = (connection->maximum_request_length - req_size - 4) / stride; + if (rows > 0) { + do { + if (rows > height) + rows = height; + + length = rows * stride; + + xcb_put_image (connection->xcb_connection, XCB_IMAGE_FORMAT_Z_PIXMAP, + dst, gc, width, rows, dst_x, dst_y, 0, depth, length, data); + + height -= rows; + dst_y += rows; + data = (char *) data + length; + } while (height); + } else { + ASSERT_NOT_REACHED; + } + } +} + +static void +_cairo_xcb_connection_do_put_subimage (cairo_xcb_connection_t *connection, + xcb_drawable_t dst, + xcb_gcontext_t gc, + int16_t src_x, + int16_t src_y, + uint16_t width, + uint16_t height, + uint16_t cpp, + int stride, + int16_t dst_x, + int16_t dst_y, + uint8_t depth, + void *_data) +{ + xcb_protocol_request_t xcb_req = { + 0 /* count */, + 0 /* ext */, + XCB_PUT_IMAGE /* opcode */, + 1 /* isvoid (doesn't cause a reply) */ + }; + xcb_put_image_request_t req; + struct iovec vec_stack[CAIRO_STACK_ARRAY_LENGTH (struct iovec)]; + struct iovec *vec = vec_stack; + uint32_t len = 0; + uint8_t *data = _data; + int n = 3; + /* Two extra entries are needed for xcb, two for us */ + int entries_needed = height + 2 + 2; + + req.format = XCB_IMAGE_FORMAT_Z_PIXMAP; + req.drawable = dst; + req.gc = gc; + req.width = width; + req.height = height; + req.dst_x = dst_x; + req.dst_y = dst_y; + req.left_pad = 0; + req.depth = depth; + req.pad0[0] = 0; + req.pad0[1] = 0; + + if (entries_needed > ARRAY_LENGTH (vec_stack)) { + vec = _cairo_malloc_ab (entries_needed, sizeof (struct iovec)); + if (unlikely (vec == NULL)) { + /* XXX loop over ARRAY_LENGTH (vec_stack) */ + return; + } + } + + data += src_y * stride + src_x * cpp; + /* vec[1] will be used in XCB if it has to use BigRequests or insert a sync, + * vec[0] is used if the internal queue needs to be flushed. */ + vec[2].iov_base = (char *) &req; + vec[2].iov_len = sizeof (req); + + /* Now comes the actual data */ + while (height--) { + vec[n].iov_base = data; + vec[n].iov_len = cpp * width; + len += cpp * width; + data += stride; + n++; + } + + /* And again some padding */ + vec[n].iov_base = 0; + vec[n].iov_len = -len & 3; + n++; + + /* For efficiency reasons, this functions writes the request "directly" to + * the xcb connection to avoid having to copy the data around. */ + assert (n == entries_needed); + xcb_req.count = n - 2; + xcb_send_request (connection->xcb_connection, 0, &vec[2], &xcb_req); + + if (vec != vec_stack) + free (vec); +} + +void +_cairo_xcb_connection_put_subimage (cairo_xcb_connection_t *connection, + xcb_drawable_t dst, + xcb_gcontext_t gc, + int16_t src_x, + int16_t src_y, + uint16_t width, + uint16_t height, + uint16_t cpp, + int stride, + int16_t dst_x, + int16_t dst_y, + uint8_t depth, + void *_data) +{ + const uint32_t req_size = sizeof(xcb_put_image_request_t); + uint32_t length = height * cpp * width; + uint32_t len = (req_size + length) >> 2; + + if (len < connection->maximum_request_length) { + _cairo_xcb_connection_do_put_subimage (connection, dst, gc, src_x, src_y, + width, height, cpp, stride, dst_x, dst_y, depth, _data); + } else { + int rows = (connection->maximum_request_length - req_size - 4) / (cpp * width); + if (rows > 0) { + do { + if (rows > height) + rows = height; + + _cairo_xcb_connection_do_put_subimage (connection, dst, gc, src_x, src_y, + width, rows, cpp, stride, dst_x, dst_y, depth, _data); + + height -= rows; + dst_y += rows; + _data = (char *) _data + stride * rows; + } while (height); + } else { + ASSERT_NOT_REACHED; + } + } +} + +xcb_get_image_reply_t * +_cairo_xcb_connection_get_image (cairo_xcb_connection_t *connection, + xcb_drawable_t src, + int16_t src_x, + int16_t src_y, + uint16_t width, + uint16_t height) +{ + return xcb_get_image_reply (connection->xcb_connection, + xcb_get_image (connection->xcb_connection, + XCB_IMAGE_FORMAT_Z_PIXMAP, + src, + src_x, src_y, + width, height, + (uint32_t) -1), + NULL); +} diff --git a/local/recipes/libs/cairo/source/src/cairo-xcb-connection-render.c b/local/recipes/libs/cairo/source/src/cairo-xcb-connection-render.c new file mode 100644 index 0000000000..e27b2b3b2c --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-xcb-connection-render.c @@ -0,0 +1,297 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * Contributor(s): + * Chris Wilson + */ + +#include "cairoint.h" + +#include "cairo-xcb-private.h" + +#include + +void +_cairo_xcb_connection_render_create_picture (cairo_xcb_connection_t *connection, + xcb_render_picture_t picture, + xcb_drawable_t drawable, + xcb_render_pictformat_t format, + uint32_t value_mask, + uint32_t *value_list) +{ + assert (connection->flags & CAIRO_XCB_HAS_RENDER); + xcb_render_create_picture (connection->xcb_connection, picture, drawable, + format, value_mask, value_list); +} + +void +_cairo_xcb_connection_render_change_picture (cairo_xcb_connection_t *connection, + xcb_render_picture_t picture, + uint32_t value_mask, + uint32_t *value_list) +{ + assert (connection->flags & CAIRO_XCB_HAS_RENDER); + xcb_render_change_picture (connection->xcb_connection, picture, + value_mask, value_list); +} + +void +_cairo_xcb_connection_render_set_picture_clip_rectangles (cairo_xcb_connection_t *connection, + xcb_render_picture_t picture, + int16_t clip_x_origin, + int16_t clip_y_origin, + uint32_t rectangles_len, + xcb_rectangle_t *rectangles) +{ + assert (connection->flags & CAIRO_XCB_HAS_RENDER); + xcb_render_set_picture_clip_rectangles (connection->xcb_connection, picture, + clip_x_origin, clip_y_origin, + rectangles_len, rectangles); +} + +void +_cairo_xcb_connection_render_free_picture (cairo_xcb_connection_t *connection, + xcb_render_picture_t picture) +{ + assert (connection->flags & CAIRO_XCB_HAS_RENDER); + xcb_render_free_picture (connection->xcb_connection, picture); +} + +void +_cairo_xcb_connection_render_composite (cairo_xcb_connection_t *connection, + uint8_t op, + xcb_render_picture_t src, + xcb_render_picture_t mask, + xcb_render_picture_t dst, + int16_t src_x, + int16_t src_y, + int16_t mask_x, + int16_t mask_y, + int16_t dst_x, + int16_t dst_y, + uint16_t width, + uint16_t height) +{ + assert (connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE); + xcb_render_composite (connection->xcb_connection, op, src, mask, dst, + src_x, src_y, mask_x, mask_y, dst_x, dst_y, width, height); +} + +void +_cairo_xcb_connection_render_trapezoids (cairo_xcb_connection_t *connection, + uint8_t op, + xcb_render_picture_t src, + xcb_render_picture_t dst, + xcb_render_pictformat_t mask_format, + int16_t src_x, + int16_t src_y, + uint32_t traps_len, + xcb_render_trapezoid_t *traps) +{ + assert (connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS); + xcb_render_trapezoids (connection->xcb_connection, op, src, dst, + mask_format, src_x, src_y, traps_len, traps); +} + +void +_cairo_xcb_connection_render_create_glyph_set (cairo_xcb_connection_t *connection, + xcb_render_glyphset_t id, + xcb_render_pictformat_t format) +{ + assert (connection->flags & CAIRO_XCB_HAS_RENDER); + xcb_render_create_glyph_set (connection->xcb_connection, id, format); +} + +void +_cairo_xcb_connection_render_free_glyph_set (cairo_xcb_connection_t *connection, + xcb_render_glyphset_t glyphset) +{ + assert (connection->flags & CAIRO_XCB_HAS_RENDER); + xcb_render_free_glyph_set (connection->xcb_connection, glyphset); +} + +void +_cairo_xcb_connection_render_add_glyphs (cairo_xcb_connection_t *connection, + xcb_render_glyphset_t glyphset, + uint32_t num_glyphs, + uint32_t *glyphs_id, + xcb_render_glyphinfo_t *glyphs, + uint32_t data_len, + uint8_t *data) +{ + assert (connection->flags & CAIRO_XCB_HAS_RENDER); + xcb_render_add_glyphs (connection->xcb_connection, glyphset, num_glyphs, + glyphs_id, glyphs, data_len, data); +} + +void +_cairo_xcb_connection_render_free_glyphs (cairo_xcb_connection_t *connection, + xcb_render_glyphset_t glyphset, + uint32_t num_glyphs, + xcb_render_glyph_t *glyphs) +{ + assert (connection->flags & CAIRO_XCB_HAS_RENDER); + xcb_render_free_glyphs (connection->xcb_connection, glyphset, num_glyphs, glyphs); +} + +void +_cairo_xcb_connection_render_composite_glyphs_8 (cairo_xcb_connection_t *connection, + uint8_t op, + xcb_render_picture_t src, + xcb_render_picture_t dst, + xcb_render_pictformat_t mask_format, + xcb_render_glyphset_t glyphset, + int16_t src_x, + int16_t src_y, + uint32_t glyphcmds_len, + uint8_t *glyphcmds) +{ + assert (connection->flags & CAIRO_XCB_HAS_RENDER); + xcb_render_composite_glyphs_8 (connection->xcb_connection, op, src, dst, mask_format, + glyphset, src_x, src_y, glyphcmds_len, glyphcmds); +} + +void +_cairo_xcb_connection_render_composite_glyphs_16 (cairo_xcb_connection_t *connection, + uint8_t op, + xcb_render_picture_t src, + xcb_render_picture_t dst, + xcb_render_pictformat_t mask_format, + xcb_render_glyphset_t glyphset, + int16_t src_x, + int16_t src_y, + uint32_t glyphcmds_len, + uint8_t *glyphcmds) +{ + assert (connection->flags & CAIRO_XCB_HAS_RENDER); + xcb_render_composite_glyphs_16 (connection->xcb_connection, op, src, dst, mask_format, + glyphset, src_x, src_y, glyphcmds_len, glyphcmds); +} + +void +_cairo_xcb_connection_render_composite_glyphs_32 (cairo_xcb_connection_t *connection, + uint8_t op, + xcb_render_picture_t src, + xcb_render_picture_t dst, + xcb_render_pictformat_t mask_format, + xcb_render_glyphset_t glyphset, + int16_t src_x, + int16_t src_y, + uint32_t glyphcmds_len, + uint8_t *glyphcmds) +{ + assert (connection->flags & CAIRO_XCB_HAS_RENDER); + xcb_render_composite_glyphs_32 (connection->xcb_connection, op, src, dst, mask_format, + glyphset, src_x, src_y, glyphcmds_len, glyphcmds); +} + +void +_cairo_xcb_connection_render_fill_rectangles (cairo_xcb_connection_t *connection, + uint8_t op, + xcb_render_picture_t dst, + xcb_render_color_t color, + uint32_t num_rects, + xcb_rectangle_t *rects) +{ + assert (connection->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES); + xcb_render_fill_rectangles (connection->xcb_connection, op, dst, color, + num_rects, rects); +} + +void +_cairo_xcb_connection_render_set_picture_transform (cairo_xcb_connection_t *connection, + xcb_render_picture_t picture, + xcb_render_transform_t *transform) +{ + assert (connection->flags & CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM); + xcb_render_set_picture_transform (connection->xcb_connection, picture, *transform); +} + +void +_cairo_xcb_connection_render_set_picture_filter (cairo_xcb_connection_t *connection, + xcb_render_picture_t picture, + uint16_t filter_len, + char *filter) +{ + assert (connection->flags & CAIRO_XCB_RENDER_HAS_FILTERS); + xcb_render_set_picture_filter (connection->xcb_connection, picture, + filter_len, filter, 0, NULL); +} + +void +_cairo_xcb_connection_render_create_solid_fill (cairo_xcb_connection_t *connection, + xcb_render_picture_t picture, + xcb_render_color_t color) +{ + assert (connection->flags & CAIRO_XCB_RENDER_HAS_GRADIENTS); + xcb_render_create_solid_fill (connection->xcb_connection, picture, color); +} + +void +_cairo_xcb_connection_render_create_linear_gradient (cairo_xcb_connection_t *connection, + xcb_render_picture_t picture, + xcb_render_pointfix_t p1, + xcb_render_pointfix_t p2, + uint32_t num_stops, + xcb_render_fixed_t *stops, + xcb_render_color_t *colors) +{ + assert (connection->flags & CAIRO_XCB_RENDER_HAS_GRADIENTS); + xcb_render_create_linear_gradient (connection->xcb_connection, picture, + p1, p2, num_stops, stops, colors); +} + +void +_cairo_xcb_connection_render_create_radial_gradient (cairo_xcb_connection_t *connection, + xcb_render_picture_t picture, + xcb_render_pointfix_t inner, + xcb_render_pointfix_t outer, + xcb_render_fixed_t inner_radius, + xcb_render_fixed_t outer_radius, + uint32_t num_stops, + xcb_render_fixed_t *stops, + xcb_render_color_t *colors) +{ + assert (connection->flags & CAIRO_XCB_RENDER_HAS_GRADIENTS); + xcb_render_create_radial_gradient (connection->xcb_connection, picture, + inner, outer, inner_radius, outer_radius, + num_stops, stops, colors); +} + +void +_cairo_xcb_connection_render_create_conical_gradient (cairo_xcb_connection_t *connection, + xcb_render_picture_t picture, + xcb_render_pointfix_t center, + xcb_render_fixed_t angle, + uint32_t num_stops, + xcb_render_fixed_t *stops, + xcb_render_color_t *colors) +{ + assert (connection->flags & CAIRO_XCB_RENDER_HAS_GRADIENTS); + xcb_render_create_conical_gradient (connection->xcb_connection, picture, + center, angle, num_stops, stops, colors); +} diff --git a/local/recipes/libs/cairo/source/src/cairo-xcb-connection-shm.c b/local/recipes/libs/cairo/source/src/cairo-xcb-connection-shm.c new file mode 100644 index 0000000000..140a73cd0c --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-xcb-connection-shm.c @@ -0,0 +1,114 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * Contributor(s): + * Chris Wilson + */ + +#include "cairoint.h" + +#if CAIRO_HAS_XCB_SHM_FUNCTIONS + +#include "cairo-xcb-private.h" + +#include +#include + +uint32_t +_cairo_xcb_connection_shm_attach (cairo_xcb_connection_t *connection, + uint32_t id, + cairo_bool_t readonly) +{ + uint32_t segment = xcb_generate_id (connection->xcb_connection); + assert (connection->flags & CAIRO_XCB_HAS_SHM); + xcb_shm_attach (connection->xcb_connection, segment, id, readonly); + return segment; +} + +void +_cairo_xcb_connection_shm_put_image (cairo_xcb_connection_t *connection, + xcb_drawable_t dst, + xcb_gcontext_t gc, + uint16_t total_width, + uint16_t total_height, + int16_t src_x, + int16_t src_y, + uint16_t width, + uint16_t height, + int16_t dst_x, + int16_t dst_y, + uint8_t depth, + uint32_t shm, + uint32_t offset) +{ + assert (connection->flags & CAIRO_XCB_HAS_SHM); + xcb_shm_put_image (connection->xcb_connection, dst, gc, total_width, total_height, + src_x, src_y, width, height, dst_x, dst_y, depth, + XCB_IMAGE_FORMAT_Z_PIXMAP, 0, shm, offset); +} + +cairo_status_t +_cairo_xcb_connection_shm_get_image (cairo_xcb_connection_t *connection, + xcb_drawable_t src, + int16_t src_x, + int16_t src_y, + uint16_t width, + uint16_t height, + uint32_t shmseg, + uint32_t offset) +{ + xcb_shm_get_image_reply_t *reply; + + assert (connection->flags & CAIRO_XCB_HAS_SHM); + reply = xcb_shm_get_image_reply (connection->xcb_connection, + xcb_shm_get_image (connection->xcb_connection, + src, + src_x, src_y, + width, height, + (uint32_t) -1, + XCB_IMAGE_FORMAT_Z_PIXMAP, + shmseg, offset), + NULL); + free (reply); + + if (!reply) { + /* an error here should be impossible */ + return _cairo_error (CAIRO_STATUS_READ_ERROR); + } + + return CAIRO_STATUS_SUCCESS; +} + +void +_cairo_xcb_connection_shm_detach (cairo_xcb_connection_t *connection, + uint32_t segment) +{ + assert (connection->flags & CAIRO_XCB_HAS_SHM); + xcb_shm_detach (connection->xcb_connection, segment); +} + +#endif /* CAIRO_HAS_XCB_SHM_FUNCTIONS */ diff --git a/local/recipes/libs/cairo/source/src/cairo-xcb-connection.c b/local/recipes/libs/cairo/source/src/cairo-xcb-connection.c new file mode 100644 index 0000000000..016ca1c0cd --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-xcb-connection.c @@ -0,0 +1,952 @@ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * Authors: + * Chris Wilson + */ + + +#include "cairoint.h" + +#include "cairo-xcb-private.h" +#include "cairo-hash-private.h" +#include "cairo-freelist-private.h" +#include "cairo-list-inline.h" + +#include +#include +#include + +#if CAIRO_HAS_XCB_SHM_FUNCTIONS +#include +#include +#include +#endif + +typedef struct _cairo_xcb_xrender_format { + cairo_hash_entry_t key; + xcb_render_pictformat_t xrender_format; +} cairo_xcb_xrender_format_t; + +typedef struct _cairo_xcb_xid { + cairo_list_t link; + uint32_t xid; +} cairo_xcb_xid_t; + +#define XCB_RENDER_AT_LEAST(V, major, minor) \ + (((V)->major_version > major) || \ + (((V)->major_version == major) && ((V)->minor_version >= minor))) + +#define XCB_RENDER_HAS_CREATE_PICTURE(surface) XCB_RENDER_AT_LEAST((surface), 0, 0) +#define XCB_RENDER_HAS_COMPOSITE(surface) XCB_RENDER_AT_LEAST((surface), 0, 0) +#define XCB_RENDER_HAS_COMPOSITE_TEXT(surface) XCB_RENDER_AT_LEAST((surface), 0, 0) + +#define XCB_RENDER_HAS_FILL_RECTANGLES(surface) XCB_RENDER_AT_LEAST((surface), 0, 1) + +#define XCB_RENDER_HAS_DISJOINT(surface) XCB_RENDER_AT_LEAST((surface), 0, 2) +#define XCB_RENDER_HAS_CONJOINT(surface) XCB_RENDER_AT_LEAST((surface), 0, 2) + +#define XCB_RENDER_HAS_TRAPEZOIDS(surface) XCB_RENDER_AT_LEAST((surface), 0, 4) +#define XCB_RENDER_HAS_TRIANGLES(surface) XCB_RENDER_AT_LEAST((surface), 0, 4) +#define XCB_RENDER_HAS_TRISTRIP(surface) XCB_RENDER_AT_LEAST((surface), 0, 4) +#define XCB_RENDER_HAS_TRIFAN(surface) XCB_RENDER_AT_LEAST((surface), 0, 4) + +#define XCB_RENDER_HAS_PICTURE_TRANSFORM(surface) XCB_RENDER_AT_LEAST((surface), 0, 6) +#define XCB_RENDER_HAS_FILTERS(surface) XCB_RENDER_AT_LEAST((surface), 0, 6) +#define XCB_RENDER_HAS_FILTER_GOOD(surface) FALSE +#define XCB_RENDER_HAS_FILTER_BEST(surface) FALSE +#define XCB_RENDER_HAS_SUBPIXEL_ORDER(surface) XCB_RENDER_AT_LEAST((surface), 0, 6) + +#define XCB_RENDER_HAS_EXTENDED_REPEAT(surface) XCB_RENDER_AT_LEAST((surface), 0, 10) +#define XCB_RENDER_HAS_GRADIENTS(surface) XCB_RENDER_AT_LEAST((surface), 0, 10) + +#define XCB_RENDER_HAS_PDF_OPERATORS(surface) XCB_RENDER_AT_LEAST((surface), 0, 11) + +static cairo_list_t connections; + +static cairo_status_t +_cairo_xcb_connection_find_visual_formats (cairo_xcb_connection_t *connection, + const xcb_render_query_pict_formats_reply_t *formats) +{ + xcb_render_pictscreen_iterator_t screens; + xcb_render_pictdepth_iterator_t depths; + xcb_render_pictvisual_iterator_t visuals; + + for (screens = xcb_render_query_pict_formats_screens_iterator (formats); + screens.rem; + xcb_render_pictscreen_next (&screens)) + { + for (depths = xcb_render_pictscreen_depths_iterator (screens.data); + depths.rem; + xcb_render_pictdepth_next (&depths)) + { + for (visuals = xcb_render_pictdepth_visuals_iterator (depths.data); + visuals.rem; + xcb_render_pictvisual_next (&visuals)) + { + cairo_xcb_xrender_format_t *f; + cairo_status_t status; + + f = _cairo_calloc (sizeof (cairo_xcb_xrender_format_t)); + if (unlikely (f == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + f->key.hash = visuals.data->visual; + f->xrender_format = visuals.data->format; + status = _cairo_hash_table_insert (connection->visual_to_xrender_format, + &f->key); + if (unlikely (status)) + return status; + } + } + } + + return CAIRO_STATUS_SUCCESS; +} + +#if 0 +static xcb_format_t * +find_format_for_depth (const xcb_setup_t *setup, uint8_t depth) +{ + xcb_format_t *fmt = xcb_setup_pixmap_formats (setup); + xcb_format_t *fmtend = fmt + xcb_setup_pixmap_formats_length (setup); + + for (; fmt != fmtend; ++fmt) + if (fmt->depth == depth) + return fmt; + + return 0; +} +#endif + +static cairo_status_t +_cairo_xcb_connection_parse_xrender_formats (cairo_xcb_connection_t *connection, + const xcb_render_query_pict_formats_reply_t *formats) +{ + xcb_render_pictforminfo_iterator_t i; + cairo_status_t status; + + for (i = xcb_render_query_pict_formats_formats_iterator (formats); + i.rem; + xcb_render_pictforminfo_next (&i)) + { + cairo_format_masks_t masks; + pixman_format_code_t pixman_format; + + if (i.data->type != XCB_RENDER_PICT_TYPE_DIRECT) + continue; + + masks.alpha_mask = + (unsigned long) i.data->direct.alpha_mask << i.data->direct.alpha_shift; + masks.red_mask = + (unsigned long) i.data->direct.red_mask << i.data->direct.red_shift; + masks.green_mask = + (unsigned long) i.data->direct.green_mask << i.data->direct.green_shift; + masks.blue_mask = + (unsigned long) i.data->direct.blue_mask << i.data->direct.blue_shift; + masks.bpp = i.data->depth; + + if (_pixman_format_from_masks (&masks, &pixman_format)) { + cairo_hash_entry_t key; + + key.hash = pixman_format; + if (! _cairo_hash_table_lookup (connection->xrender_formats, &key)) { + cairo_xcb_xrender_format_t *f; + + f = _cairo_calloc (sizeof (cairo_xcb_xrender_format_t)); + if (unlikely (f == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + f->key.hash = pixman_format; + f->xrender_format = i.data->id; + status = _cairo_hash_table_insert (connection->xrender_formats, + &f->key); + if (unlikely (status)) + return status; + +#if 0 + printf ("xrender %x -> (%lx, %lx, %lx, %lx, %d) %x [%d, %d]\n", + i.data->id, + masks.alpha_mask, + masks.red_mask, + masks.green_mask, + masks.blue_mask, + masks.bpp, + pixman_format, + PIXMAN_FORMAT_DEPTH(pixman_format), + PIXMAN_FORMAT_BPP(pixman_format)); +#endif + } + } + } + + status = _cairo_xcb_connection_find_visual_formats (connection, formats); + if (unlikely (status)) + return status; + + connection->standard_formats[CAIRO_FORMAT_A1] = + _cairo_xcb_connection_get_xrender_format (connection, PIXMAN_a1); + + connection->standard_formats[CAIRO_FORMAT_A8] = + _cairo_xcb_connection_get_xrender_format (connection, PIXMAN_a8); + + connection->standard_formats[CAIRO_FORMAT_RGB24] = + _cairo_xcb_connection_get_xrender_format (connection, + PIXMAN_FORMAT (24, + PIXMAN_TYPE_ARGB, + 0, 8, 8, 8)); + if (connection->standard_formats[CAIRO_FORMAT_RGB24] == XCB_NONE) { + connection->standard_formats[CAIRO_FORMAT_RGB24] = + _cairo_xcb_connection_get_xrender_format (connection, + PIXMAN_FORMAT (24, PIXMAN_TYPE_ABGR, + 0, 8, 8, 8)); + } + + connection->standard_formats[CAIRO_FORMAT_ARGB32] = + _cairo_xcb_connection_get_xrender_format (connection, PIXMAN_a8r8g8b8); + if (connection->standard_formats[CAIRO_FORMAT_ARGB32] == XCB_NONE) { + connection->standard_formats[CAIRO_FORMAT_ARGB32] = + _cairo_xcb_connection_get_xrender_format (connection, PIXMAN_a8b8g8r8); + } + + return CAIRO_STATUS_SUCCESS; +} + +/* + * We require support for depth 1, 8, 24 and 32 pixmaps + */ +#define DEPTH_MASK(d) ((uint32_t)(1) << ((d) - 1)) +#define REQUIRED_DEPTHS (DEPTH_MASK(1) | \ + DEPTH_MASK(8) | \ + DEPTH_MASK(24) | \ + DEPTH_MASK(32)) +static cairo_bool_t +pixmap_depths_usable (cairo_xcb_connection_t *connection, + uint32_t missing, + xcb_drawable_t root) +{ + xcb_connection_t *c = connection->xcb_connection; + xcb_void_cookie_t create_cookie[32]; + xcb_pixmap_t pixmap; + cairo_bool_t success = TRUE; + int depth, i, j; + + pixmap = xcb_generate_id (connection->xcb_connection); + + for (depth = 1, i = 0; depth <= 32; depth++) { + if (missing & DEPTH_MASK(depth)) { + create_cookie[i] = xcb_create_pixmap_checked (c, depth, pixmap, root, 1, 1); + xcb_free_pixmap (c, pixmap); + if (!create_cookie[i].sequence) { + success = FALSE; + break; + } + i++; + } + } + + for (j = 0; j < i; j++) { + xcb_generic_error_t *create_error = xcb_request_check (c, create_cookie[j]); + success &= create_error == NULL; + free (create_error); + } + + return success; +} + +static cairo_bool_t +has_required_depths (cairo_xcb_connection_t *connection) +{ + xcb_screen_iterator_t screens; + + for (screens = xcb_setup_roots_iterator (connection->root); + screens.rem; + xcb_screen_next (&screens)) + { + xcb_depth_iterator_t depths; + uint32_t missing = REQUIRED_DEPTHS; + + for (depths = xcb_screen_allowed_depths_iterator (screens.data); + depths.rem; + xcb_depth_next (&depths)) + { + missing &= ~DEPTH_MASK (depths.data->depth); + } + if (missing == 0) + continue; + + /* + * Ok, this is ugly. It should be sufficient at this + * point to just return false, but Xinerama is broken at + * this point and only advertises depths which have an + * associated visual. Of course, the other depths still + * work, but the only way to find out is to try them. + */ + if (! pixmap_depths_usable (connection, missing, screens.data->root)) + return FALSE; + } + + return TRUE; +} + +static xcb_render_query_version_reply_t * +_render_restrict_env(xcb_render_query_version_reply_t *version) +{ + const char *env; + + if (version == NULL) + return NULL; + + env = getenv ("CAIRO_DEBUG"); + if (env != NULL) + env = strstr (env, "xrender-version="); + if (env != NULL) { + int max_render_major, max_render_minor; + + env += sizeof ("xrender-version=") - 1; + if (sscanf (env, "%d.%d", &max_render_major, &max_render_minor) != 2) + max_render_major = max_render_minor = -1; + + if (max_render_major < 0 || max_render_minor < 0) { + free (version); + return NULL; + } + + if (max_render_major < (int) version->major_version || + (max_render_major == (int) version->major_version && + max_render_minor < (int) version->minor_version)) + { + version->major_version = max_render_major; + version->minor_version = max_render_minor; + } + } + + return version; +} + +static cairo_status_t +_cairo_xcb_connection_query_render (cairo_xcb_connection_t *connection) +{ + xcb_connection_t *c = connection->xcb_connection; + xcb_render_query_version_cookie_t version_cookie; + xcb_render_query_pict_formats_cookie_t formats_cookie; + xcb_render_query_version_reply_t *version; + xcb_render_query_pict_formats_reply_t *formats; + cairo_status_t status; + cairo_bool_t present; + + version_cookie = xcb_render_query_version (c, XCB_RENDER_MAJOR_VERSION, XCB_RENDER_MINOR_VERSION); + formats_cookie = xcb_render_query_pict_formats (c); + + present = has_required_depths (connection); + version = xcb_render_query_version_reply (c, version_cookie, 0); + formats = xcb_render_query_pict_formats_reply (c, formats_cookie, 0); + + version = _render_restrict_env (version); + + if (! present || version == NULL || formats == NULL) { + free (version); + free (formats); + return CAIRO_STATUS_SUCCESS; + } + + /* always true if the extension is present (i.e. >= 0.0) */ + connection->flags |= CAIRO_XCB_HAS_RENDER; + connection->flags |= CAIRO_XCB_RENDER_HAS_COMPOSITE; + connection->flags |= CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS; + + if (XCB_RENDER_HAS_FILL_RECTANGLES (version)) + connection->flags |= CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES; + + if (XCB_RENDER_HAS_TRAPEZOIDS (version)) + connection->flags |= CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS; + + if (XCB_RENDER_HAS_PICTURE_TRANSFORM (version)) + connection->flags |= CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM; + + if (XCB_RENDER_HAS_FILTERS (version)) + connection->flags |= CAIRO_XCB_RENDER_HAS_FILTERS; + + if (XCB_RENDER_HAS_FILTER_GOOD (version)) + connection->flags |= CAIRO_XCB_RENDER_HAS_FILTER_GOOD; + + if (XCB_RENDER_HAS_FILTER_BEST (version)) + connection->flags |= CAIRO_XCB_RENDER_HAS_FILTER_BEST; + + if (XCB_RENDER_HAS_PDF_OPERATORS (version)) + connection->flags |= CAIRO_XCB_RENDER_HAS_PDF_OPERATORS; + + if (XCB_RENDER_HAS_EXTENDED_REPEAT (version)) + connection->flags |= CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT; + + if (XCB_RENDER_HAS_GRADIENTS (version)) + connection->flags |= CAIRO_XCB_RENDER_HAS_GRADIENTS; + + if (XCB_RENDER_HAS_SUBPIXEL_ORDER (version)) { + uint32_t screen; + uint32_t *subpixel = xcb_render_query_pict_formats_subpixels(formats); + + /* The spec explicitly allows to have too few entries in the reply... */ + for (screen = 0; screen < formats->num_subpixel && screen < connection->root->roots_len; screen++) + connection->subpixel_orders[screen] = subpixel[screen]; + } + + free (version); + + status = _cairo_xcb_connection_parse_xrender_formats (connection, formats); + free (formats); + + return status; +} + +#if 0 +static void +_cairo_xcb_connection_query_cairo (cairo_xcb_connection_t *connection) +{ + xcb_connection_t *c = connection->xcb_connection; + xcb_cairo_query_version_reply_t *version; + + version = xcb_cairo_query_version_reply (c, + xcb_cairo_query_version (c, 0, 0), + 0); + + free (version); +} +#endif + +#if CAIRO_HAS_XCB_SHM_FUNCTIONS +static cairo_bool_t +can_use_shm (cairo_xcb_connection_t *connection) +{ + cairo_bool_t success = TRUE; + xcb_connection_t *c = connection->xcb_connection; + xcb_void_cookie_t cookie[2]; + xcb_generic_error_t *error; + int shmid; + uint32_t shmseg; + void *ptr; + + shmid = shmget (IPC_PRIVATE, 0x1000, IPC_CREAT | 0600); + if (shmid == -1) + return FALSE; + + ptr = shmat (shmid, NULL, 0); + if (ptr == (char *) -1) { + shmctl (shmid, IPC_RMID, NULL); + return FALSE; + } + + shmseg = xcb_generate_id (connection->xcb_connection); + cookie[0] = xcb_shm_attach_checked (c, shmseg, shmid, FALSE); + cookie[1] = xcb_shm_detach_checked (c, shmseg); + + error = xcb_request_check (c, cookie[0]); + if (error != NULL) + success = FALSE; + + error = xcb_request_check (c, cookie[1]); + if (error != NULL) + success = FALSE; + + shmctl (shmid, IPC_RMID, NULL); + shmdt (ptr); + + return success; +} + +static void +_cairo_xcb_connection_query_shm (cairo_xcb_connection_t *connection) +{ + xcb_connection_t *c = connection->xcb_connection; + xcb_shm_query_version_reply_t *version; + + version = xcb_shm_query_version_reply (c, xcb_shm_query_version (c), 0); + if (version == NULL) + return; + + free (version); + + if (can_use_shm (connection)) + connection->flags |= CAIRO_XCB_HAS_SHM; +} +#endif + +static cairo_status_t +_device_flush (void *device) +{ + cairo_xcb_connection_t *connection = device; + cairo_status_t status; + + status = cairo_device_acquire (&connection->device); + if (unlikely (status)) + return status; + +#if CAIRO_HAS_XCB_SHM_FUNCTIONS + _cairo_xcb_connection_shm_mem_pools_flush (connection); +#endif + + xcb_flush (connection->xcb_connection); + + cairo_device_release (&connection->device); + return CAIRO_STATUS_SUCCESS; +} + +static void +_pluck_xrender_format (void *entry, + void *closure) +{ + _cairo_hash_table_remove (closure, entry); + free (entry); +} + +static void +_device_finish (void *device) +{ + cairo_xcb_connection_t *connection = device; + cairo_bool_t was_cached = FALSE; + + if (! cairo_list_is_empty (&connection->link)) { + CAIRO_MUTEX_LOCK (_cairo_xcb_connections_mutex); + cairo_list_del (&connection->link); + CAIRO_MUTEX_UNLOCK (_cairo_xcb_connections_mutex); + was_cached = TRUE; + } + + while (! cairo_list_is_empty (&connection->fonts)) { + cairo_xcb_font_t *font; + + font = cairo_list_first_entry (&connection->fonts, + cairo_xcb_font_t, + link); + _cairo_xcb_font_close (font); + } + + while (! cairo_list_is_empty (&connection->screens)) { + cairo_xcb_screen_t *screen; + + screen = cairo_list_first_entry (&connection->screens, + cairo_xcb_screen_t, + link); + _cairo_xcb_screen_finish (screen); + } + +#if CAIRO_HAS_XCB_SHM_FUNCTIONS + /* _cairo_xcb_screen_finish finishes surfaces. If any of those surfaces had + * a fallback image, we might have done a SHM PutImage. */ + _cairo_xcb_connection_shm_mem_pools_flush (connection); +#endif + + if (was_cached) + cairo_device_destroy (device); +} + +static void +_device_destroy (void *device) +{ + cairo_xcb_connection_t *connection = device; + + _cairo_hash_table_foreach (connection->xrender_formats, + _pluck_xrender_format, connection->xrender_formats); + _cairo_hash_table_destroy (connection->xrender_formats); + + _cairo_hash_table_foreach (connection->visual_to_xrender_format, + _pluck_xrender_format, + connection->visual_to_xrender_format); + _cairo_hash_table_destroy (connection->visual_to_xrender_format); + +#if CAIRO_HAS_XCB_SHM_FUNCTIONS + _cairo_xcb_connection_shm_mem_pools_fini (connection); +#endif + _cairo_freepool_fini (&connection->shm_info_freelist); + + CAIRO_MUTEX_FINI (connection->shm_mutex); + CAIRO_MUTEX_FINI (connection->screens_mutex); + + free (connection->subpixel_orders); + free (connection); +} + +static const cairo_device_backend_t _cairo_xcb_device_backend = { + CAIRO_DEVICE_TYPE_XCB, + + NULL, NULL, /* lock, unlock */ + + _device_flush, + _device_finish, + _device_destroy, +}; + +cairo_xcb_connection_t * +_cairo_xcb_connection_get (xcb_connection_t *xcb_connection) +{ + cairo_xcb_connection_t *connection; + const xcb_query_extension_reply_t *ext; + cairo_status_t status; + + CAIRO_MUTEX_INITIALIZE (); + + CAIRO_MUTEX_LOCK (_cairo_xcb_connections_mutex); + if (connections.next == NULL) { + /* XXX _cairo_init () */ + cairo_list_init (&connections); + } + + cairo_list_foreach_entry (connection, + cairo_xcb_connection_t, + &connections, + link) + { + if (connection->xcb_connection == xcb_connection) { + /* Maintain MRU order. */ + if (connections.next != &connection->link) + cairo_list_move (&connection->link, &connections); + + goto unlock; + } + } + + connection = _cairo_calloc (sizeof (cairo_xcb_connection_t)); + if (unlikely (connection == NULL)) + goto unlock; + + _cairo_device_init (&connection->device, &_cairo_xcb_device_backend); + + connection->xcb_connection = xcb_connection; + + cairo_list_init (&connection->fonts); + cairo_list_init (&connection->screens); + cairo_list_init (&connection->link); + connection->xrender_formats = _cairo_hash_table_create (NULL); + if (connection->xrender_formats == NULL) { + CAIRO_MUTEX_FINI (connection->device.mutex); + free (connection); + connection = NULL; + goto unlock; + } + + connection->visual_to_xrender_format = _cairo_hash_table_create (NULL); + if (connection->visual_to_xrender_format == NULL) { + _cairo_hash_table_destroy (connection->xrender_formats); + CAIRO_MUTEX_FINI (connection->device.mutex); + free (connection); + connection = NULL; + goto unlock; + } + + cairo_list_init (&connection->shm_pools); + cairo_list_init (&connection->shm_pending); + _cairo_freepool_init (&connection->shm_info_freelist, + sizeof (cairo_xcb_shm_info_t)); + + connection->maximum_request_length = + xcb_get_maximum_request_length (xcb_connection); + + CAIRO_MUTEX_INIT (connection->shm_mutex); + CAIRO_MUTEX_INIT (connection->screens_mutex); + + CAIRO_MUTEX_LOCK (connection->device.mutex); + + connection->flags = 0; + connection->force_precision = -1; + + xcb_prefetch_extension_data (xcb_connection, &xcb_big_requests_id); + xcb_prefetch_extension_data (xcb_connection, &xcb_render_id); +#if CAIRO_HAS_XCB_SHM_FUNCTIONS + xcb_prefetch_extension_data (xcb_connection, &xcb_shm_id); +#endif +#if 0 + xcb_prefetch_extension_data (xcb_connection, &xcb_cairo_id); +#endif + + xcb_prefetch_maximum_request_length (xcb_connection); + + connection->root = xcb_get_setup (xcb_connection); + connection->render = NULL; + connection->subpixel_orders = _cairo_calloc_ab (connection->root->roots_len, + sizeof(*connection->subpixel_orders)); + if (unlikely (connection->subpixel_orders == NULL)) { + CAIRO_MUTEX_UNLOCK (connection->device.mutex); + _cairo_xcb_connection_destroy (connection); + connection = NULL; + goto unlock; + } + + ext = xcb_get_extension_data (xcb_connection, &xcb_render_id); + if (ext != NULL && ext->present) { + status = _cairo_xcb_connection_query_render (connection); + if (unlikely (status)) { + CAIRO_MUTEX_UNLOCK (connection->device.mutex); + _cairo_xcb_connection_destroy (connection); + connection = NULL; + goto unlock; + } + + connection->render = ext; + } + +#if 0 + ext = xcb_get_extension_data (connection, &xcb_cairo_id); + if (ext != NULL && ext->present) + _cairo_xcb_connection_query_cairo (connection); +#endif + + connection->shm = NULL; +#if CAIRO_HAS_XCB_SHM_FUNCTIONS + ext = xcb_get_extension_data (xcb_connection, &xcb_shm_id); + if (ext != NULL && ext->present) { + _cairo_xcb_connection_query_shm (connection); + connection->shm = ext; + } +#endif + + connection->original_flags = connection->flags; + + CAIRO_MUTEX_UNLOCK (connection->device.mutex); + + cairo_list_add (&connection->link, &connections); +unlock: + CAIRO_MUTEX_UNLOCK (_cairo_xcb_connections_mutex); + + return connection; +} + +xcb_render_pictformat_t +_cairo_xcb_connection_get_xrender_format (cairo_xcb_connection_t *connection, + pixman_format_code_t pixman_format) +{ + cairo_hash_entry_t key; + cairo_xcb_xrender_format_t *format; + + key.hash = pixman_format; + format = _cairo_hash_table_lookup (connection->xrender_formats, &key); + return format ? format->xrender_format : XCB_NONE; +} + +xcb_render_pictformat_t +_cairo_xcb_connection_get_xrender_format_for_visual (cairo_xcb_connection_t *connection, + const xcb_visualid_t visual) +{ + cairo_hash_entry_t key; + cairo_xcb_xrender_format_t *format; + + key.hash = visual; + format = _cairo_hash_table_lookup (connection->visual_to_xrender_format, &key); + return format ? format->xrender_format : XCB_NONE; +} + +/** + * cairo_xcb_device_get_connection: + * @device: a #cairo_device_t for the XCB backend + * + * Get the connection for the XCB device. + * + * Returns: the #xcb_connection_t for the connection + * + * Since: 1.12 + **/ +xcb_connection_t * +cairo_xcb_device_get_connection (cairo_device_t *device) +{ + if (device->backend->type != CAIRO_DEVICE_TYPE_XCB) + return NULL; + + return ((cairo_xcb_connection_t *)device)->xcb_connection; +} + +/* public (debug) interface */ + +/** + * cairo_xcb_device_debug_cap_xshm_version: + * @device: a #cairo_device_t for the XCB backend + * @major_version: major version to restrict to + * @minor_version: minor version to restrict to + * + * Restricts all future XCB surfaces for this devices to the specified version + * of the SHM extension. This function exists solely for debugging purpose. + * It let's you find out how cairo would behave with an older version of + * the SHM extension. + * + * Use the special values -1 and -1 for disabling the SHM extension. + * + * Since: 1.12 + **/ +void +cairo_xcb_device_debug_cap_xshm_version (cairo_device_t *device, + int major_version, + int minor_version) +{ + cairo_xcb_connection_t *connection = (cairo_xcb_connection_t *) device; + + if (device->backend->type != CAIRO_DEVICE_TYPE_XCB) { + cairo_status_t status; + + status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH); + (void) status; + return; + } + + /* First reset all the SHM flags to their original value. This works + * because we only ever clear bits after the connection was created. + */ + connection->flags |= (connection->original_flags & CAIRO_XCB_SHM_MASK); + + /* clear any flags that are inappropriate for the desired version */ + if (major_version < 0 && minor_version < 0) { + connection->flags &= ~(CAIRO_XCB_HAS_SHM); + } +} + +/** + * cairo_xcb_device_debug_cap_xrender_version: + * @device: a #cairo_device_t for the XCB backend + * @major_version: major version to restrict to + * @minor_version: minor version to restrict to + * + * Restricts all future XCB surfaces for this devices to the specified version + * of the RENDER extension. This function exists solely for debugging purpose. + * It let's you find out how cairo would behave with an older version of + * the RENDER extension. + * + * Use the special values -1 and -1 for disabling the RENDER extension. + * + * Since: 1.12 + **/ +void +cairo_xcb_device_debug_cap_xrender_version (cairo_device_t *device, + int major_version, + int minor_version) +{ + cairo_xcb_connection_t *connection = (cairo_xcb_connection_t *) device; + + if (device->backend->type != CAIRO_DEVICE_TYPE_XCB) { + cairo_status_t status; + + status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH); + (void) status; + return; + } + + /* First reset all the RENDER flags to their original value. This works + * because we only ever clear bits after the connection was created. + */ + connection->flags |= (connection->original_flags & CAIRO_XCB_RENDER_MASK); + + /* clear any flags that are inappropriate for the desired version */ + if (major_version < 0 && minor_version < 0) { + connection->flags &= ~(CAIRO_XCB_HAS_RENDER | + CAIRO_XCB_RENDER_HAS_COMPOSITE | + CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS | + CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES | + CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS | + CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM | + CAIRO_XCB_RENDER_HAS_FILTERS | + CAIRO_XCB_RENDER_HAS_FILTER_GOOD | + CAIRO_XCB_RENDER_HAS_FILTER_BEST | + CAIRO_XCB_RENDER_HAS_PDF_OPERATORS | + CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT | + CAIRO_XCB_RENDER_HAS_GRADIENTS); + } else { + xcb_render_query_version_reply_t version; + + version.major_version = major_version; + version.minor_version = minor_version; + + if (! XCB_RENDER_HAS_FILL_RECTANGLES (&version)) + connection->flags &= ~CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES; + + if (! XCB_RENDER_HAS_TRAPEZOIDS (&version)) + connection->flags &= ~CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS; + + if (! XCB_RENDER_HAS_PICTURE_TRANSFORM (&version)) + connection->flags &= ~CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM; + + if (! XCB_RENDER_HAS_FILTERS (&version)) + connection->flags &= ~CAIRO_XCB_RENDER_HAS_FILTERS; + + if (! XCB_RENDER_HAS_PDF_OPERATORS (&version)) + connection->flags &= ~CAIRO_XCB_RENDER_HAS_PDF_OPERATORS; + + if (! XCB_RENDER_HAS_EXTENDED_REPEAT (&version)) + connection->flags &= ~CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT; + + if (! XCB_RENDER_HAS_GRADIENTS (&version)) + connection->flags &= ~CAIRO_XCB_RENDER_HAS_GRADIENTS; + } +} + +/** + * cairo_xcb_device_debug_set_precision: + * @device: a #cairo_device_t for the XCB backend + * @precision: the precision to use + * + * Render supports two modes of precision when rendering trapezoids. Set + * the precision to the desired mode. + * + * Since: 1.12 + **/ +void +cairo_xcb_device_debug_set_precision (cairo_device_t *device, + int precision) +{ + if (device == NULL || device->status) + return; + if (device->backend->type != CAIRO_DEVICE_TYPE_XCB) { + cairo_status_t status; + + status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH); + (void) status; + return; + } + + ((cairo_xcb_connection_t *) device)->force_precision = precision; +} + +/** + * cairo_xcb_device_debug_get_precision: + * @device: a #cairo_device_t for the XCB backend + * + * Get the Xrender precision mode. + * + * Returns: the render precision mode + * + * Since: 1.12 + **/ +int +cairo_xcb_device_debug_get_precision (cairo_device_t *device) +{ + if (device == NULL || device->status) + return -1; + if (device->backend->type != CAIRO_DEVICE_TYPE_XCB) { + cairo_status_t status; + + status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH); + (void) status; + return -1; + } + + return ((cairo_xcb_connection_t *) device)->force_precision; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-xcb-private.h b/local/recipes/libs/cairo/source/src/cairo-xcb-private.h new file mode 100644 index 0000000000..95805f8a93 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-xcb-private.h @@ -0,0 +1,773 @@ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2009 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributors(s): + * Chris Wilson + */ + +#ifndef CAIRO_XCB_PRIVATE_H +#define CAIRO_XCB_PRIVATE_H + +#include "cairoint.h" + +#include "cairo-xcb.h" + +#include "cairo-cache-private.h" +#include "cairo-compiler-private.h" +#include "cairo-device-private.h" +#include "cairo-error-private.h" +#include "cairo-freelist-private.h" +#include "cairo-list-private.h" +#include "cairo-mutex-private.h" +#include "cairo-pattern-private.h" +#include "cairo-reference-count-private.h" +#include "cairo-scaled-font-private.h" +#include "cairo-spans-private.h" +#include "cairo-surface-private.h" + +#include +#include +#include +#include + +#define XLIB_COORD_MAX 32767 + +/* maximum number of cached GC's */ +#define GC_CACHE_SIZE 4 + +#define CAIRO_XCB_RENDER_AT_LEAST(major, minor) \ + ((XCB_RENDER_MAJOR_VERSION > major) || \ + ((XCB_RENDER_MAJOR_VERSION == major) && (XCB_RENDER_MINOR_VERSION >= minor))) + +typedef struct _cairo_xcb_connection cairo_xcb_connection_t; +typedef struct _cairo_xcb_font cairo_xcb_font_t; +typedef struct _cairo_xcb_screen cairo_xcb_screen_t; +typedef struct _cairo_xcb_surface cairo_xcb_surface_t; +typedef struct _cairo_xcb_picture cairo_xcb_picture_t; +typedef struct _cairo_xcb_shm_mem_pool cairo_xcb_shm_mem_pool_t; +typedef struct _cairo_xcb_shm_info cairo_xcb_shm_info_t; +typedef struct _cairo_xcb_resources cairo_xcb_resources_t; + +struct _cairo_xcb_shm_info { + cairo_xcb_connection_t *connection; + uint32_t shm; + uint32_t offset; + size_t size; + void *mem; + cairo_xcb_shm_mem_pool_t *pool; + xcb_get_input_focus_cookie_t sync; + cairo_list_t pending; +}; + +struct _cairo_xcb_surface { + cairo_surface_t base; + cairo_image_surface_t *fallback; + cairo_boxes_t fallback_damage; + + cairo_xcb_connection_t *connection; + cairo_xcb_screen_t *screen; + + xcb_drawable_t drawable; + cairo_bool_t owns_pixmap; + + cairo_bool_t deferred_clear; + cairo_color_t deferred_clear_color; + + int width; + int height; + int depth; + + xcb_render_picture_t picture; + xcb_render_pictformat_t xrender_format; + pixman_format_code_t pixman_format; + uint32_t precision; + + cairo_list_t link; +}; + +struct _cairo_xcb_picture { + cairo_surface_t base; + + cairo_xcb_screen_t *screen; + xcb_render_picture_t picture; + xcb_render_pictformat_t xrender_format; + pixman_format_code_t pixman_format; + + int width, height; + + cairo_extend_t extend; + cairo_filter_t filter; + cairo_bool_t has_component_alpha; + xcb_render_transform_t transform; + + int x0, y0; + int x, y; + + cairo_list_t link; +}; + +#if CAIRO_HAS_XLIB_XCB_FUNCTIONS +typedef struct _cairo_xlib_xcb_surface { + cairo_surface_t base; + + cairo_xcb_surface_t *xcb; + + /* original settings for query */ + void *display; + void *screen; + void *visual; + void *format; +} cairo_xlib_xcb_surface_t; +#endif + + +enum { + GLYPHSET_INDEX_ARGB32, + GLYPHSET_INDEX_A8, + GLYPHSET_INDEX_A1, + NUM_GLYPHSETS +}; + +typedef struct _cairo_xcb_font_glyphset_free_glyphs { + xcb_render_glyphset_t glyphset; + int glyph_count; + xcb_render_glyph_t glyph_indices[128]; +} cairo_xcb_font_glyphset_free_glyphs_t; + +typedef struct _cairo_xcb_font_glyphset_info { + xcb_render_glyphset_t glyphset; + cairo_format_t format; + xcb_render_pictformat_t xrender_format; + cairo_xcb_font_glyphset_free_glyphs_t *pending_free_glyphs; +} cairo_xcb_font_glyphset_info_t; + +struct _cairo_xcb_font { + cairo_scaled_font_private_t base; + cairo_scaled_font_t *scaled_font; + cairo_xcb_connection_t *connection; + cairo_xcb_font_glyphset_info_t glyphset_info[NUM_GLYPHSETS]; + cairo_list_t link; +}; + +struct _cairo_xcb_screen { + cairo_xcb_connection_t *connection; + + xcb_screen_t *xcb_screen; + xcb_render_sub_pixel_t subpixel_order; + + xcb_gcontext_t gc[GC_CACHE_SIZE]; + uint8_t gc_depths[GC_CACHE_SIZE]; + + cairo_surface_t *stock_colors[CAIRO_STOCK_NUM_COLORS]; + struct { + cairo_surface_t *picture; + cairo_color_t color; + } solid_cache[16]; + int solid_cache_size; + + cairo_cache_t linear_pattern_cache; + cairo_cache_t radial_pattern_cache; + cairo_freelist_t pattern_cache_entry_freelist; + + cairo_list_t link; + cairo_list_t surfaces; + cairo_list_t pictures; + + cairo_bool_t has_font_options; + cairo_font_options_t font_options; +}; + +struct _cairo_xcb_connection { + cairo_device_t device; + + xcb_connection_t *xcb_connection; + + xcb_render_pictformat_t standard_formats[5]; + cairo_hash_table_t *xrender_formats; + cairo_hash_table_t *visual_to_xrender_format; + + unsigned int maximum_request_length; + unsigned int flags; + unsigned int original_flags; + + int force_precision; + + const xcb_setup_t *root; + const xcb_query_extension_reply_t *render; + const xcb_query_extension_reply_t *shm; + xcb_render_sub_pixel_t *subpixel_orders; + + cairo_mutex_t shm_mutex; + cairo_list_t shm_pools; + cairo_list_t shm_pending; + cairo_freepool_t shm_info_freelist; + + cairo_mutex_t screens_mutex; + cairo_list_t screens; + + cairo_list_t fonts; + + cairo_list_t link; +}; + +struct _cairo_xcb_resources { + cairo_bool_t xft_antialias; + int xft_lcdfilter; + cairo_bool_t xft_hinting; + int xft_hintstyle; + int xft_rgba; +}; + +enum { + CAIRO_XCB_HAS_RENDER = 0x0001, + CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES = 0x0002, + CAIRO_XCB_RENDER_HAS_COMPOSITE = 0x0004, + CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS = 0x0008, + CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS = 0x0010, + CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM = 0x0020, + CAIRO_XCB_RENDER_HAS_FILTERS = 0x0040, + CAIRO_XCB_RENDER_HAS_PDF_OPERATORS = 0x0080, + CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT = 0x0100, + CAIRO_XCB_RENDER_HAS_GRADIENTS = 0x0200, + CAIRO_XCB_RENDER_HAS_FILTER_GOOD = 0x0400, + CAIRO_XCB_RENDER_HAS_FILTER_BEST = 0x0800, + + CAIRO_XCB_HAS_SHM = 0x80000000, + + CAIRO_XCB_RENDER_MASK = CAIRO_XCB_HAS_RENDER | + CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES | + CAIRO_XCB_RENDER_HAS_COMPOSITE | + CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS | + CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS | + CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM | + CAIRO_XCB_RENDER_HAS_FILTERS | + CAIRO_XCB_RENDER_HAS_PDF_OPERATORS | + CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT | + CAIRO_XCB_RENDER_HAS_GRADIENTS | + CAIRO_XCB_RENDER_HAS_FILTER_GOOD | + CAIRO_XCB_RENDER_HAS_FILTER_BEST, + CAIRO_XCB_SHM_MASK = CAIRO_XCB_HAS_SHM +}; + +#define CAIRO_XCB_SHM_SMALL_IMAGE 8192 + +cairo_private extern const cairo_surface_backend_t _cairo_xcb_surface_backend; + +/** + * _cairo_surface_is_xcb: + * @surface: a #cairo_surface_t + * + * Checks if a surface is an #cairo_xcb_surface_t + * + * Return value: %TRUE if the surface is an xcb surface + **/ +static inline cairo_bool_t +_cairo_surface_is_xcb (const cairo_surface_t *surface) +{ + /* _cairo_surface_nil sets a NULL backend so be safe */ + return surface->backend && surface->backend->type == CAIRO_SURFACE_TYPE_XCB; +} + +cairo_private cairo_xcb_connection_t * +_cairo_xcb_connection_get (xcb_connection_t *connection); + +static inline cairo_xcb_connection_t * +_cairo_xcb_connection_reference (cairo_xcb_connection_t *connection) +{ + return (cairo_xcb_connection_t *) cairo_device_reference (&connection->device); +} + +cairo_private xcb_render_pictformat_t +_cairo_xcb_connection_get_xrender_format (cairo_xcb_connection_t *connection, + pixman_format_code_t pixman_format); + +cairo_private xcb_render_pictformat_t +_cairo_xcb_connection_get_xrender_format_for_visual (cairo_xcb_connection_t *connection, + const xcb_visualid_t visual); + +static inline cairo_status_t cairo_warn +_cairo_xcb_connection_acquire (cairo_xcb_connection_t *connection) +{ + return cairo_device_acquire (&connection->device); +} + +static inline void +_cairo_xcb_connection_release (cairo_xcb_connection_t *connection) +{ + cairo_device_release (&connection->device); +} + +static inline void +_cairo_xcb_connection_destroy (cairo_xcb_connection_t *connection) +{ + cairo_device_destroy (&connection->device); +} + +cairo_private cairo_int_status_t +_cairo_xcb_connection_allocate_shm_info (cairo_xcb_connection_t *display, + size_t size, + cairo_bool_t might_reuse, + cairo_xcb_shm_info_t **shm_info_out); + +cairo_private void +_cairo_xcb_shm_info_destroy (cairo_xcb_shm_info_t *shm_info); + +cairo_private void +_cairo_xcb_connection_shm_mem_pools_flush (cairo_xcb_connection_t *connection); + +cairo_private void +_cairo_xcb_connection_shm_mem_pools_fini (cairo_xcb_connection_t *connection); + +cairo_private void +_cairo_xcb_font_close (cairo_xcb_font_t *font); + +cairo_private cairo_xcb_screen_t * +_cairo_xcb_screen_get (xcb_connection_t *connection, + xcb_screen_t *screen); + +cairo_private void +_cairo_xcb_screen_finish (cairo_xcb_screen_t *screen); + +cairo_private xcb_gcontext_t +_cairo_xcb_screen_get_gc (cairo_xcb_screen_t *screen, + xcb_drawable_t drawable, + int depth); + +cairo_private void +_cairo_xcb_screen_put_gc (cairo_xcb_screen_t *screen, int depth, xcb_gcontext_t gc); + +cairo_private cairo_font_options_t * +_cairo_xcb_screen_get_font_options (cairo_xcb_screen_t *screen); + +cairo_private cairo_status_t +_cairo_xcb_screen_store_linear_picture (cairo_xcb_screen_t *screen, + const cairo_linear_pattern_t *linear, + cairo_surface_t *picture); + +cairo_private cairo_surface_t * +_cairo_xcb_screen_lookup_linear_picture (cairo_xcb_screen_t *screen, + const cairo_linear_pattern_t *linear); + +cairo_private cairo_status_t +_cairo_xcb_screen_store_radial_picture (cairo_xcb_screen_t *screen, + const cairo_radial_pattern_t *radial, + cairo_surface_t *picture); + +cairo_private cairo_surface_t * +_cairo_xcb_screen_lookup_radial_picture (cairo_xcb_screen_t *screen, + const cairo_radial_pattern_t *radial); + +cairo_private cairo_surface_t * +_cairo_xcb_surface_create_similar_image (void *abstrct_other, + cairo_format_t format, + int width, + int height); + +cairo_private cairo_surface_t * +_cairo_xcb_surface_create_similar (void *abstract_other, + cairo_content_t content, + int width, + int height); + +cairo_private cairo_surface_t * +_cairo_xcb_surface_create_internal (cairo_xcb_screen_t *screen, + xcb_drawable_t drawable, + cairo_bool_t owns_pixmap, + pixman_format_code_t pixman_format, + xcb_render_pictformat_t xrender_format, + int width, + int height); + +cairo_private_no_warn cairo_bool_t +_cairo_xcb_surface_get_extents (void *abstract_surface, + cairo_rectangle_int_t *extents); + +cairo_private cairo_int_status_t +_cairo_xcb_render_compositor_paint (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *extents); + +cairo_private cairo_int_status_t +_cairo_xcb_render_compositor_mask (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *extents); + +cairo_private cairo_int_status_t +_cairo_xcb_render_compositor_stroke (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *extents, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias); + +cairo_private cairo_int_status_t +_cairo_xcb_render_compositor_fill (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *extents, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias); + +cairo_private cairo_int_status_t +_cairo_xcb_render_compositor_glyphs (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *extents, + cairo_scaled_font_t *scaled_font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_bool_t overlap); +cairo_private void +_cairo_xcb_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font); + +cairo_private void +_cairo_xcb_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph, + cairo_scaled_font_t *scaled_font); + +cairo_private cairo_status_t +_cairo_xcb_surface_clear (cairo_xcb_surface_t *dst); + +cairo_private cairo_status_t +_cairo_xcb_surface_core_copy_boxes (cairo_xcb_surface_t *dst, + const cairo_pattern_t *src_pattern, + const cairo_rectangle_int_t *extents, + const cairo_boxes_t *boxes); + +cairo_private cairo_status_t +_cairo_xcb_surface_core_fill_boxes (cairo_xcb_surface_t *dst, + const cairo_color_t *color, + cairo_boxes_t *boxes); + +cairo_private xcb_pixmap_t +_cairo_xcb_connection_create_pixmap (cairo_xcb_connection_t *connection, + uint8_t depth, + xcb_drawable_t drawable, + uint16_t width, + uint16_t height); + +cairo_private xcb_gcontext_t +_cairo_xcb_connection_create_gc (cairo_xcb_connection_t *connection, + xcb_drawable_t drawable, + uint32_t value_mask, + uint32_t *values); + +cairo_private void +_cairo_xcb_connection_change_gc (cairo_xcb_connection_t *connection, + xcb_gcontext_t gc, + uint32_t value_mask, + uint32_t *values); + +cairo_private void +_cairo_xcb_connection_copy_area (cairo_xcb_connection_t *connection, + xcb_drawable_t src, + xcb_drawable_t dst, + xcb_gcontext_t gc, + int16_t src_x, + int16_t src_y, + int16_t dst_x, + int16_t dst_y, + uint16_t width, + uint16_t height); + +cairo_private void +_cairo_xcb_connection_put_image (cairo_xcb_connection_t *connection, + xcb_drawable_t dst, + xcb_gcontext_t gc, + uint16_t width, + uint16_t height, + int16_t dst_x, + int16_t dst_y, + uint8_t depth, + uint32_t length, + void *data); + +cairo_private void +_cairo_xcb_connection_put_subimage (cairo_xcb_connection_t *connection, + xcb_drawable_t dst, + xcb_gcontext_t gc, + int16_t src_x, + int16_t src_y, + uint16_t width, + uint16_t height, + uint16_t cpp, + int stride, + int16_t dst_x, + int16_t dst_y, + uint8_t depth, + void *data); + +cairo_private xcb_get_image_reply_t * +_cairo_xcb_connection_get_image (cairo_xcb_connection_t *connection, + xcb_drawable_t src, + int16_t src_x, + int16_t src_y, + uint16_t width, + uint16_t height); + +cairo_private void +_cairo_xcb_connection_poly_fill_rectangle (cairo_xcb_connection_t *connection, + xcb_drawable_t dst, + xcb_gcontext_t gc, + uint32_t num_rectangles, + xcb_rectangle_t *rectangles); + +cairo_private cairo_status_t +_cairo_xcb_shm_image_create (cairo_xcb_connection_t *connection, + pixman_format_code_t pixman_format, + int width, int height, + cairo_image_surface_t **image_out, + cairo_xcb_shm_info_t **shm_info_out); + +#if CAIRO_HAS_XCB_SHM_FUNCTIONS +cairo_private uint32_t +_cairo_xcb_connection_shm_attach (cairo_xcb_connection_t *connection, + uint32_t id, + cairo_bool_t readonly); + +cairo_private void +_cairo_xcb_connection_shm_put_image (cairo_xcb_connection_t *connection, + xcb_drawable_t dst, + xcb_gcontext_t gc, + uint16_t total_width, + uint16_t total_height, + int16_t src_x, + int16_t src_y, + uint16_t width, + uint16_t height, + int16_t dst_x, + int16_t dst_y, + uint8_t depth, + uint32_t shm, + uint32_t offset); + +cairo_private cairo_status_t +_cairo_xcb_connection_shm_get_image (cairo_xcb_connection_t *connection, + xcb_drawable_t src, + int16_t src_x, + int16_t src_y, + uint16_t width, + uint16_t height, + uint32_t shmseg, + uint32_t offset); + +cairo_private void +_cairo_xcb_connection_shm_detach (cairo_xcb_connection_t *connection, + uint32_t segment); +#else +static inline void +_cairo_xcb_connection_shm_put_image (cairo_xcb_connection_t *connection, + xcb_drawable_t dst, + xcb_gcontext_t gc, + uint16_t total_width, + uint16_t total_height, + int16_t src_x, + int16_t src_y, + uint16_t width, + uint16_t height, + int16_t dst_x, + int16_t dst_y, + uint8_t depth, + uint32_t shm, + uint32_t offset) +{ + ASSERT_NOT_REACHED; +} +#endif + +cairo_private void +_cairo_xcb_connection_render_create_picture (cairo_xcb_connection_t *connection, + xcb_render_picture_t picture, + xcb_drawable_t drawable, + xcb_render_pictformat_t format, + uint32_t value_mask, + uint32_t *value_list); + +cairo_private void +_cairo_xcb_connection_render_change_picture (cairo_xcb_connection_t *connection, + xcb_render_picture_t picture, + uint32_t value_mask, + uint32_t *value_list); + +cairo_private void +_cairo_xcb_connection_render_set_picture_clip_rectangles (cairo_xcb_connection_t *connection, + xcb_render_picture_t picture, + int16_t clip_x_origin, + int16_t clip_y_origin, + uint32_t rectangles_len, + xcb_rectangle_t *rectangles); + +cairo_private void +_cairo_xcb_connection_render_free_picture (cairo_xcb_connection_t *connection, + xcb_render_picture_t picture); + +cairo_private void +_cairo_xcb_connection_render_composite (cairo_xcb_connection_t *connection, + uint8_t op, + xcb_render_picture_t src, + xcb_render_picture_t mask, + xcb_render_picture_t dst, + int16_t src_x, + int16_t src_y, + int16_t mask_x, + int16_t mask_y, + int16_t dst_x, + int16_t dst_y, + uint16_t width, + uint16_t height); + +cairo_private void +_cairo_xcb_connection_render_trapezoids (cairo_xcb_connection_t *connection, + uint8_t op, + xcb_render_picture_t src, + xcb_render_picture_t dst, + xcb_render_pictformat_t mask_format, + int16_t src_x, + int16_t src_y, + uint32_t traps_len, + xcb_render_trapezoid_t *traps); + +cairo_private void +_cairo_xcb_connection_render_create_glyph_set (cairo_xcb_connection_t *connection, + xcb_render_glyphset_t id, + xcb_render_pictformat_t format); + +cairo_private void +_cairo_xcb_connection_render_free_glyph_set (cairo_xcb_connection_t *connection, + xcb_render_glyphset_t glyphset); + +cairo_private void +_cairo_xcb_connection_render_add_glyphs (cairo_xcb_connection_t *connection, + xcb_render_glyphset_t glyphset, + uint32_t num_glyphs, + uint32_t *glyphs_id, + xcb_render_glyphinfo_t *glyphs, + uint32_t data_len, + uint8_t *data); + +cairo_private void +_cairo_xcb_connection_render_free_glyphs (cairo_xcb_connection_t *connection, + xcb_render_glyphset_t glyphset, + uint32_t num_glyphs, + xcb_render_glyph_t *glyphs); + +cairo_private void +_cairo_xcb_connection_render_composite_glyphs_8 (cairo_xcb_connection_t *connection, + uint8_t op, + xcb_render_picture_t src, + xcb_render_picture_t dst, + xcb_render_pictformat_t mask_format, + xcb_render_glyphset_t glyphset, + int16_t src_x, + int16_t src_y, + uint32_t glyphcmds_len, + uint8_t *glyphcmds); + +cairo_private void +_cairo_xcb_connection_render_composite_glyphs_16 (cairo_xcb_connection_t *connection, + uint8_t op, + xcb_render_picture_t src, + xcb_render_picture_t dst, + xcb_render_pictformat_t mask_format, + xcb_render_glyphset_t glyphset, + int16_t src_x, + int16_t src_y, + uint32_t glyphcmds_len, + uint8_t *glyphcmds); + +cairo_private void +_cairo_xcb_connection_render_composite_glyphs_32 (cairo_xcb_connection_t *connection, + uint8_t op, + xcb_render_picture_t src, + xcb_render_picture_t dst, + xcb_render_pictformat_t mask_format, + xcb_render_glyphset_t glyphset, + int16_t src_x, + int16_t src_y, + uint32_t glyphcmds_len, + uint8_t *glyphcmds); + +cairo_private void +_cairo_xcb_connection_render_fill_rectangles (cairo_xcb_connection_t *connection, + uint8_t op, + xcb_render_picture_t dst, + xcb_render_color_t color, + uint32_t num_rects, + xcb_rectangle_t *rects); + +cairo_private void +_cairo_xcb_connection_render_set_picture_transform (cairo_xcb_connection_t *connection, + xcb_render_picture_t picture, + xcb_render_transform_t *transform); + +cairo_private void +_cairo_xcb_connection_render_set_picture_filter (cairo_xcb_connection_t *connection, + xcb_render_picture_t picture, + uint16_t filter_len, + char *filter); + +cairo_private void +_cairo_xcb_connection_render_create_solid_fill (cairo_xcb_connection_t *connection, + xcb_render_picture_t picture, + xcb_render_color_t color); + +cairo_private void +_cairo_xcb_connection_render_create_linear_gradient (cairo_xcb_connection_t *connection, + xcb_render_picture_t picture, + xcb_render_pointfix_t p1, + xcb_render_pointfix_t p2, + uint32_t num_stops, + xcb_render_fixed_t *stops, + xcb_render_color_t *colors); + +cairo_private void +_cairo_xcb_connection_render_create_radial_gradient (cairo_xcb_connection_t *connection, + xcb_render_picture_t picture, + xcb_render_pointfix_t inner, + xcb_render_pointfix_t outer, + xcb_render_fixed_t inner_radius, + xcb_render_fixed_t outer_radius, + uint32_t num_stops, + xcb_render_fixed_t *stops, + xcb_render_color_t *colors); + +cairo_private void +_cairo_xcb_connection_render_create_conical_gradient (cairo_xcb_connection_t *c, + xcb_render_picture_t picture, + xcb_render_pointfix_t center, + xcb_render_fixed_t angle, + uint32_t num_stops, + xcb_render_fixed_t *stops, + xcb_render_color_t *colors); + +cairo_private void +_cairo_xcb_resources_get (cairo_xcb_screen_t *screen, + cairo_xcb_resources_t *resources); + +#endif /* CAIRO_XCB_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-xcb-resources.c b/local/recipes/libs/cairo/source/src/cairo-xcb-resources.c new file mode 100644 index 0000000000..1877758c25 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-xcb-resources.c @@ -0,0 +1,281 @@ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2014 Lukas Lalinsky + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * Authors: + * Lukas Lalinsky + * + * Partially on code from xftdpy.c + * + * Copyright © 2000 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "cairoint.h" + +#include "cairo-xcb-private.h" + +#include "cairo-fontconfig-private.h" + +static void +parse_boolean (const char *v, cairo_bool_t *out) +{ + char c0, c1; + + c0 = *v; + if (c0 == 't' || c0 == 'T' || c0 == 'y' || c0 == 'Y' || c0 == '1') + *out = TRUE; + if (c0 == 'f' || c0 == 'F' || c0 == 'n' || c0 == 'N' || c0 == '0') + *out = FALSE; + if (c0 == 'o') { + c1 = v[1]; + if (c1 == 'n' || c1 == 'N') + *out = TRUE; + if (c1 == 'f' || c1 == 'F') + *out = FALSE; + } +} + +static void +parse_integer (const char *v, int *out) +{ + char *e; + int value; + +#if CAIRO_HAS_FC_FONT + if (FcNameConstant ((FcChar8 *) v, out)) + return; +#endif + + value = strtol (v, &e, 0); + if (e != v) + *out = value; +} + +static char * +skip_spaces(char *str) +{ + while (*str == ' ' || *str == '\t' || *str == '\n') + str++; + return str; +} + +struct resource_parser { + int buffer_size; + int bytes_in_buffer; + char* buffer; + cairo_xcb_resources_t *resources; +}; + +static cairo_bool_t +resource_parse_line (char *name, cairo_xcb_resources_t *resources) +{ + char *value; + + value = strchr (name, ':'); + if (value == NULL) + return FALSE; + + *value++ = 0; + + name = skip_spaces (name); + value = skip_spaces (value); + + if (strcmp (name, "Xft.antialias") == 0) + parse_boolean (value, &(resources->xft_antialias)); + else if (strcmp (name, "Xft.lcdfilter") == 0) + parse_integer (value, &(resources->xft_lcdfilter)); + else if (strcmp (name, "Xft.rgba") == 0) + parse_integer (value, &(resources->xft_rgba)); + else if (strcmp (name, "Xft.hinting") == 0) + parse_boolean (value, &(resources->xft_hinting)); + else if (strcmp (name, "Xft.hintstyle") == 0) + parse_integer (value, &(resources->xft_hintstyle)); + + return TRUE; +} + +static int +resource_parse_lines (struct resource_parser *parser) +{ + char *line, *newline; + + line = parser->buffer; + while (1) { + newline = strchr (line, '\n'); + if (newline == NULL) + break; + + *newline++ = 0; + + if (! resource_parse_line (line, parser->resources)) + break; + + line = newline; + } + + return line - parser->buffer; +} + +static void +resource_parser_init (struct resource_parser *parser, cairo_xcb_resources_t *resources) +{ + parser->buffer_size = 0; + parser->bytes_in_buffer = 0; + parser->buffer = NULL; + parser->resources = resources; +} + +static cairo_bool_t +resource_parser_update (struct resource_parser *parser, const char *data, int length) +{ + int bytes_parsed; + + if (parser->bytes_in_buffer + length + 1 > parser->buffer_size) { + parser->buffer_size = parser->bytes_in_buffer + length + 1; + parser->buffer = realloc(parser->buffer, parser->buffer_size); + if (! parser->buffer) { + parser->buffer_size = 0; + parser->bytes_in_buffer = 0; + return FALSE; + } + } + + memmove (parser->buffer + parser->bytes_in_buffer, data, length); + parser->bytes_in_buffer += length; + parser->buffer[parser->bytes_in_buffer] = 0; + + bytes_parsed = resource_parse_lines (parser); + + if (parser->bytes_in_buffer > bytes_parsed) { + memmove (parser->buffer, parser->buffer + bytes_parsed, parser->bytes_in_buffer - bytes_parsed); + parser->bytes_in_buffer -= bytes_parsed; + } else { + parser->bytes_in_buffer = 0; + } + + return TRUE; +} + +static void +resource_parser_done (struct resource_parser *parser) +{ + if (parser->bytes_in_buffer > 0) { + parser->buffer[parser->bytes_in_buffer] = 0; + resource_parse_line (parser->buffer, parser->resources); + } + + free (parser->buffer); +} + +static void +get_resources(xcb_connection_t *connection, xcb_screen_t *screen, cairo_xcb_resources_t *resources) +{ + xcb_get_property_cookie_t cookie; + xcb_get_property_reply_t *reply; + struct resource_parser parser; + int offset; + cairo_bool_t has_more_data; + + resources->xft_antialias = TRUE; + resources->xft_lcdfilter = -1; + resources->xft_hinting = TRUE; + resources->xft_hintstyle = FC_HINT_FULL; + resources->xft_rgba = FC_RGBA_UNKNOWN; + + resource_parser_init (&parser, resources); + + offset = 0; + has_more_data = FALSE; + do { + cookie = xcb_get_property (connection, 0, screen->root, XCB_ATOM_RESOURCE_MANAGER, XCB_ATOM_STRING, offset, 1024); + reply = xcb_get_property_reply (connection, cookie, NULL); + + if (reply) { + if (reply->format == 8 && reply->type == XCB_ATOM_STRING) { + char *value = (char *) xcb_get_property_value (reply); + int length = xcb_get_property_value_length (reply); + + offset += length / 4; /* X needs the offset in 'long' units */ + has_more_data = reply->bytes_after > 0; + + if (! resource_parser_update (&parser, value, length)) + has_more_data = FALSE; /* early exit on error */ + } + + free (reply); + } + } while (has_more_data); + + resource_parser_done (&parser); +} + +void +_cairo_xcb_resources_get (cairo_xcb_screen_t *screen, cairo_xcb_resources_t *resources) +{ + get_resources (screen->connection->xcb_connection, screen->xcb_screen, resources); + + if (resources->xft_rgba == FC_RGBA_UNKNOWN) { + switch (screen->subpixel_order) { + case XCB_RENDER_SUB_PIXEL_UNKNOWN: + resources->xft_rgba = FC_RGBA_UNKNOWN; + break; + case XCB_RENDER_SUB_PIXEL_HORIZONTAL_RGB: + resources->xft_rgba = FC_RGBA_RGB; + break; + case XCB_RENDER_SUB_PIXEL_HORIZONTAL_BGR: + resources->xft_rgba = FC_RGBA_BGR; + break; + case XCB_RENDER_SUB_PIXEL_VERTICAL_RGB: + resources->xft_rgba = FC_RGBA_VRGB; + break; + case XCB_RENDER_SUB_PIXEL_VERTICAL_BGR: + resources->xft_rgba = FC_RGBA_VBGR; + break; + case XCB_RENDER_SUB_PIXEL_NONE: + resources->xft_rgba = FC_RGBA_NONE; + break; + } + } +} diff --git a/local/recipes/libs/cairo/source/src/cairo-xcb-screen.c b/local/recipes/libs/cairo/source/src/cairo-xcb-screen.c new file mode 100644 index 0000000000..0ed880d660 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-xcb-screen.c @@ -0,0 +1,494 @@ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2008 Chris Wilson + * Copyright © 2009 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * Authors: + * Chris Wilson + */ + +#include "cairoint.h" + +#include "cairo-xcb-private.h" +#include "cairo-list-inline.h" + +#include "cairo-fontconfig-private.h" + +static void +_cairo_xcb_init_screen_font_options (cairo_xcb_screen_t *screen) +{ + cairo_xcb_resources_t res; + cairo_antialias_t antialias; + cairo_subpixel_order_t subpixel_order; + cairo_lcd_filter_t lcd_filter; + cairo_hint_style_t hint_style; + + _cairo_xcb_resources_get (screen, &res); + + /* the rest of the code in this function is copied from + _cairo_xlib_init_screen_font_options in cairo-xlib-screen.c */ + + if (res.xft_hinting) { + switch (res.xft_hintstyle) { + case FC_HINT_NONE: + hint_style = CAIRO_HINT_STYLE_NONE; + break; + case FC_HINT_SLIGHT: + hint_style = CAIRO_HINT_STYLE_SLIGHT; + break; + case FC_HINT_MEDIUM: + hint_style = CAIRO_HINT_STYLE_MEDIUM; + break; + case FC_HINT_FULL: + hint_style = CAIRO_HINT_STYLE_FULL; + break; + default: + hint_style = CAIRO_HINT_STYLE_DEFAULT; + } + } else { + hint_style = CAIRO_HINT_STYLE_NONE; + } + + switch (res.xft_rgba) { + case FC_RGBA_RGB: + subpixel_order = CAIRO_SUBPIXEL_ORDER_RGB; + break; + case FC_RGBA_BGR: + subpixel_order = CAIRO_SUBPIXEL_ORDER_BGR; + break; + case FC_RGBA_VRGB: + subpixel_order = CAIRO_SUBPIXEL_ORDER_VRGB; + break; + case FC_RGBA_VBGR: + subpixel_order = CAIRO_SUBPIXEL_ORDER_VBGR; + break; + case FC_RGBA_UNKNOWN: + case FC_RGBA_NONE: + default: + subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT; + } + + switch (res.xft_lcdfilter) { + case FC_LCD_NONE: + lcd_filter = CAIRO_LCD_FILTER_NONE; + break; + case FC_LCD_DEFAULT: + lcd_filter = CAIRO_LCD_FILTER_FIR5; + break; + case FC_LCD_LIGHT: + lcd_filter = CAIRO_LCD_FILTER_FIR3; + break; + case FC_LCD_LEGACY: + lcd_filter = CAIRO_LCD_FILTER_INTRA_PIXEL; + break; + default: + lcd_filter = CAIRO_LCD_FILTER_DEFAULT; + break; + } + + if (res.xft_antialias) { + if (subpixel_order == CAIRO_SUBPIXEL_ORDER_DEFAULT) + antialias = CAIRO_ANTIALIAS_GRAY; + else + antialias = CAIRO_ANTIALIAS_SUBPIXEL; + } else { + antialias = CAIRO_ANTIALIAS_NONE; + } + + cairo_font_options_set_hint_style (&screen->font_options, hint_style); + cairo_font_options_set_antialias (&screen->font_options, antialias); + cairo_font_options_set_subpixel_order (&screen->font_options, subpixel_order); + _cairo_font_options_set_lcd_filter (&screen->font_options, lcd_filter); + cairo_font_options_set_hint_metrics (&screen->font_options, CAIRO_HINT_METRICS_ON); +} + +struct pattern_cache_entry { + cairo_cache_entry_t key; + cairo_xcb_screen_t *screen; + cairo_pattern_union_t pattern; + cairo_surface_t *picture; +}; + +void +_cairo_xcb_screen_finish (cairo_xcb_screen_t *screen) +{ + int i; + + CAIRO_MUTEX_LOCK (screen->connection->screens_mutex); + cairo_list_del (&screen->link); + CAIRO_MUTEX_UNLOCK (screen->connection->screens_mutex); + + while (! cairo_list_is_empty (&screen->surfaces)) { + cairo_surface_t *surface; + + surface = &cairo_list_first_entry (&screen->surfaces, + cairo_xcb_surface_t, + link)->base; + + cairo_surface_finish (surface); + } + + while (! cairo_list_is_empty (&screen->pictures)) { + cairo_surface_t *surface; + + surface = &cairo_list_first_entry (&screen->pictures, + cairo_xcb_picture_t, + link)->base; + + cairo_surface_finish (surface); + } + + for (i = 0; i < screen->solid_cache_size; i++) + cairo_surface_destroy (screen->solid_cache[i].picture); + + for (i = 0; i < ARRAY_LENGTH (screen->stock_colors); i++) + cairo_surface_destroy (screen->stock_colors[i]); + + for (i = 0; i < ARRAY_LENGTH (screen->gc); i++) { + if (screen->gc_depths[i] != 0) + xcb_free_gc (screen->connection->xcb_connection, screen->gc[i]); + } + + _cairo_cache_fini (&screen->linear_pattern_cache); + _cairo_cache_fini (&screen->radial_pattern_cache); + _cairo_freelist_fini (&screen->pattern_cache_entry_freelist); + + free (screen); +} + +static cairo_bool_t +_linear_pattern_cache_entry_equal (const void *A, const void *B) +{ + const struct pattern_cache_entry *a = A, *b = B; + + return _cairo_linear_pattern_equal (&a->pattern.gradient.linear, + &b->pattern.gradient.linear); +} + +static cairo_bool_t +_radial_pattern_cache_entry_equal (const void *A, const void *B) +{ + const struct pattern_cache_entry *a = A, *b = B; + + return _cairo_radial_pattern_equal (&a->pattern.gradient.radial, + &b->pattern.gradient.radial); +} + +static void +_pattern_cache_entry_destroy (void *closure) +{ + struct pattern_cache_entry *entry = closure; + + _cairo_pattern_fini (&entry->pattern.base); + cairo_surface_destroy (entry->picture); + _cairo_freelist_free (&entry->screen->pattern_cache_entry_freelist, entry); +} + +static int _get_screen_index(cairo_xcb_connection_t *xcb_connection, + xcb_screen_t *xcb_screen) +{ + int idx = 0; + xcb_screen_iterator_t iter = xcb_setup_roots_iterator(xcb_connection->root); + for (; iter.rem; xcb_screen_next(&iter), idx++) + if (iter.data->root == xcb_screen->root) + return idx; + + ASSERT_NOT_REACHED; +} + +cairo_xcb_screen_t * +_cairo_xcb_screen_get (xcb_connection_t *xcb_connection, + xcb_screen_t *xcb_screen) +{ + cairo_xcb_connection_t *connection; + cairo_xcb_screen_t *screen; + cairo_status_t status; + int screen_idx; + int i; + + connection = _cairo_xcb_connection_get (xcb_connection); + if (unlikely (connection == NULL)) + return NULL; + + CAIRO_MUTEX_LOCK (connection->screens_mutex); + + cairo_list_foreach_entry (screen, + cairo_xcb_screen_t, + &connection->screens, + link) + { + if (screen->xcb_screen == xcb_screen) { + /* Maintain list in MRU order */ + if (&screen->link != connection->screens.next) + cairo_list_move (&screen->link, &connection->screens); + + goto unlock; + } + } + + screen = _cairo_calloc (sizeof (cairo_xcb_screen_t)); + if (unlikely (screen == NULL)) + goto unlock; + + screen_idx = _get_screen_index(connection, xcb_screen); + + screen->connection = connection; + screen->xcb_screen = xcb_screen; + screen->has_font_options = FALSE; + screen->subpixel_order = connection->subpixel_orders[screen_idx]; + + _cairo_freelist_init (&screen->pattern_cache_entry_freelist, + sizeof (struct pattern_cache_entry)); + cairo_list_init (&screen->link); + cairo_list_init (&screen->surfaces); + cairo_list_init (&screen->pictures); + + memset (screen->gc_depths, 0, sizeof (screen->gc_depths)); + memset (screen->gc, 0, sizeof (screen->gc)); + + screen->solid_cache_size = 0; + for (i = 0; i < ARRAY_LENGTH (screen->stock_colors); i++) + screen->stock_colors[i] = NULL; + + status = _cairo_cache_init (&screen->linear_pattern_cache, + _linear_pattern_cache_entry_equal, + NULL, + _pattern_cache_entry_destroy, + 16); + if (unlikely (status)) + goto error_screen; + + status = _cairo_cache_init (&screen->radial_pattern_cache, + _radial_pattern_cache_entry_equal, + NULL, + _pattern_cache_entry_destroy, + 4); + if (unlikely (status)) + goto error_linear; + + cairo_list_add (&screen->link, &connection->screens); + +unlock: + CAIRO_MUTEX_UNLOCK (connection->screens_mutex); + + return screen; + +error_linear: + _cairo_cache_fini (&screen->linear_pattern_cache); +error_screen: + CAIRO_MUTEX_UNLOCK (connection->screens_mutex); + free (screen); + + return NULL; +} + +static xcb_gcontext_t +_create_gc (cairo_xcb_screen_t *screen, + xcb_drawable_t drawable) +{ + uint32_t values[] = { 0 }; + + return _cairo_xcb_connection_create_gc (screen->connection, drawable, + XCB_GC_GRAPHICS_EXPOSURES, + values); +} + +xcb_gcontext_t +_cairo_xcb_screen_get_gc (cairo_xcb_screen_t *screen, + xcb_drawable_t drawable, + int depth) +{ + int i; + + assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->device.mutex)); + + for (i = 0; i < ARRAY_LENGTH (screen->gc); i++) { + if (screen->gc_depths[i] == depth) { + screen->gc_depths[i] = 0; + return screen->gc[i]; + } + } + + return _create_gc (screen, drawable); +} + +void +_cairo_xcb_screen_put_gc (cairo_xcb_screen_t *screen, int depth, xcb_gcontext_t gc) +{ + int i; + + assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->device.mutex)); + + for (i = 0; i < ARRAY_LENGTH (screen->gc); i++) { + if (screen->gc_depths[i] == 0) + break; + } + + if (i == ARRAY_LENGTH (screen->gc)) { + /* perform random substitution to ensure fair caching over depths */ + i = rand () % ARRAY_LENGTH (screen->gc); + xcb_free_gc (screen->connection->xcb_connection, screen->gc[i]); + } + + screen->gc[i] = gc; + screen->gc_depths[i] = depth; +} + +cairo_status_t +_cairo_xcb_screen_store_linear_picture (cairo_xcb_screen_t *screen, + const cairo_linear_pattern_t *linear, + cairo_surface_t *picture) +{ + struct pattern_cache_entry *entry; + cairo_status_t status; + + assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->device.mutex)); + + entry = _cairo_freelist_alloc (&screen->pattern_cache_entry_freelist); + if (unlikely (entry == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + entry->key.hash = _cairo_linear_pattern_hash (_CAIRO_HASH_INIT_VALUE, linear); + entry->key.size = 1; + + status = _cairo_pattern_init_copy (&entry->pattern.base, &linear->base.base); + if (unlikely (status)) { + _cairo_freelist_free (&screen->pattern_cache_entry_freelist, entry); + return status; + } + + entry->picture = cairo_surface_reference (picture); + entry->screen = screen; + + status = _cairo_cache_insert (&screen->linear_pattern_cache, + &entry->key); + if (unlikely (status)) { + cairo_surface_destroy (picture); + _cairo_freelist_free (&screen->pattern_cache_entry_freelist, entry); + return status; + } + + return CAIRO_STATUS_SUCCESS; +} + +cairo_surface_t * +_cairo_xcb_screen_lookup_linear_picture (cairo_xcb_screen_t *screen, + const cairo_linear_pattern_t *linear) +{ + cairo_surface_t *picture = NULL; + struct pattern_cache_entry tmpl; + struct pattern_cache_entry *entry; + + assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->device.mutex)); + + tmpl.key.hash = _cairo_linear_pattern_hash (_CAIRO_HASH_INIT_VALUE, linear); + _cairo_pattern_init_static_copy (&tmpl.pattern.base, &linear->base.base); + + entry = _cairo_cache_lookup (&screen->linear_pattern_cache, &tmpl.key); + if (entry != NULL) + picture = cairo_surface_reference (entry->picture); + + return picture; +} + +cairo_status_t +_cairo_xcb_screen_store_radial_picture (cairo_xcb_screen_t *screen, + const cairo_radial_pattern_t *radial, + cairo_surface_t *picture) +{ + struct pattern_cache_entry *entry; + cairo_status_t status; + + assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->device.mutex)); + + entry = _cairo_freelist_alloc (&screen->pattern_cache_entry_freelist); + if (unlikely (entry == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + entry->key.hash = _cairo_radial_pattern_hash (_CAIRO_HASH_INIT_VALUE, radial); + entry->key.size = 1; + + status = _cairo_pattern_init_copy (&entry->pattern.base, &radial->base.base); + if (unlikely (status)) { + _cairo_freelist_free (&screen->pattern_cache_entry_freelist, entry); + return status; + } + + entry->picture = cairo_surface_reference (picture); + entry->screen = screen; + + status = _cairo_cache_insert (&screen->radial_pattern_cache, &entry->key); + if (unlikely (status)) { + cairo_surface_destroy (picture); + _cairo_freelist_free (&screen->pattern_cache_entry_freelist, entry); + return status; + } + + return CAIRO_STATUS_SUCCESS; +} + +cairo_surface_t * +_cairo_xcb_screen_lookup_radial_picture (cairo_xcb_screen_t *screen, + const cairo_radial_pattern_t *radial) +{ + cairo_surface_t *picture = NULL; + struct pattern_cache_entry tmpl; + struct pattern_cache_entry *entry; + + assert (CAIRO_MUTEX_IS_LOCKED (screen->connection->device.mutex)); + + tmpl.key.hash = _cairo_radial_pattern_hash (_CAIRO_HASH_INIT_VALUE, radial); + _cairo_pattern_init_static_copy (&tmpl.pattern.base, &radial->base.base); + + entry = _cairo_cache_lookup (&screen->radial_pattern_cache, &tmpl.key); + if (entry != NULL) + picture = cairo_surface_reference (entry->picture); + + return picture; +} + +cairo_font_options_t * +_cairo_xcb_screen_get_font_options (cairo_xcb_screen_t *screen) +{ + if (! screen->has_font_options) { + _cairo_font_options_init_default (&screen->font_options); + _cairo_font_options_set_round_glyph_positions (&screen->font_options, CAIRO_ROUND_GLYPH_POS_ON); + + /* XXX: This is disabled because something seems to be merging + font options incorrectly for xcb. This effectively reverts + the changes brought in git e691d242, and restores ~150 tests + to resume passing. See mailing list archives for Sep 17, + 2014 for more discussion. */ + if (0 && ! _cairo_xcb_connection_acquire (screen->connection)) { + _cairo_xcb_init_screen_font_options (screen); + _cairo_xcb_connection_release (screen->connection); + } + + screen->has_font_options = TRUE; + } + + return &screen->font_options; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-xcb-shm.c b/local/recipes/libs/cairo/source/src/cairo-xcb-shm.c new file mode 100644 index 0000000000..4037eaa720 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-xcb-shm.c @@ -0,0 +1,346 @@ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2007 Chris Wilson + * Copyright © 2009 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributors(s): + * Chris Wilson + */ + +#include "cairoint.h" + +/** + * CAIRO_HAS_XCB_SHM_FUNCTIONS: + * + * Defined if Cairo has SHM functions for XCB. + * This macro can be used to conditionally compile backend-specific code. + * + * Since: 1.10 + **/ + +#if CAIRO_HAS_XCB_SHM_FUNCTIONS + +#include "cairo-xcb-private.h" +#include "cairo-list-inline.h" +#include "cairo-mempool-private.h" + +#include +#include +#include +#include + +#define CAIRO_MAX_SHM_MEMORY (16*1024*1024) + +/* a simple buddy allocator for memory pools + * XXX fragmentation? use Doug Lea's malloc? + */ + +typedef struct _cairo_xcb_shm_mem_block cairo_xcb_shm_mem_block_t; + +typedef enum { + PENDING_WAIT, + PENDING_POLL +} shm_wait_type_t; + +struct _cairo_xcb_shm_mem_pool { + int shmid; + uint32_t shmseg; + void *shm; + + cairo_mempool_t mem; + + cairo_list_t link; +}; + +static void +_cairo_xcb_shm_mem_pool_destroy (cairo_xcb_shm_mem_pool_t *pool) +{ + cairo_list_del (&pool->link); + + shmdt (pool->shm); + _cairo_mempool_fini (&pool->mem); + + free (pool); +} + +static void +_cairo_xcb_shm_info_finalize (cairo_xcb_shm_info_t *shm_info) +{ + cairo_xcb_connection_t *connection = shm_info->connection; + + assert (CAIRO_MUTEX_IS_LOCKED (connection->shm_mutex)); + + _cairo_mempool_free (&shm_info->pool->mem, shm_info->mem); + _cairo_freepool_free (&connection->shm_info_freelist, shm_info); + + /* scan for old, unused pools - hold at least one in reserve */ + if (! cairo_list_is_singular (&connection->shm_pools)) + { + cairo_xcb_shm_mem_pool_t *pool, *next; + cairo_list_t head; + + cairo_list_init (&head); + cairo_list_move (connection->shm_pools.next, &head); + + cairo_list_foreach_entry_safe (pool, next, cairo_xcb_shm_mem_pool_t, + &connection->shm_pools, link) + { + if (pool->mem.free_bytes == pool->mem.max_bytes) { + _cairo_xcb_connection_shm_detach (connection, pool->shmseg); + _cairo_xcb_shm_mem_pool_destroy (pool); + } + } + + cairo_list_move (head.next, &connection->shm_pools); + } +} + +static void +_cairo_xcb_shm_process_pending (cairo_xcb_connection_t *connection, shm_wait_type_t wait) +{ + cairo_xcb_shm_info_t *info, *next; + xcb_get_input_focus_reply_t *reply; + + assert (CAIRO_MUTEX_IS_LOCKED (connection->shm_mutex)); + cairo_list_foreach_entry_safe (info, next, cairo_xcb_shm_info_t, + &connection->shm_pending, pending) + { + switch (wait) { + case PENDING_WAIT: + reply = xcb_wait_for_reply (connection->xcb_connection, + info->sync.sequence, NULL); + break; + case PENDING_POLL: + if (! xcb_poll_for_reply (connection->xcb_connection, + info->sync.sequence, + (void **) &reply, NULL)) + /* We cannot be sure the server finished with this image yet, so + * try again later. All other shm info are guaranteed to have a + * larger sequence number and thus don't have to be checked. */ + return; + break; + default: + /* silence Clang static analyzer warning */ + ASSERT_NOT_REACHED; + reply = NULL; + } + + free (reply); + cairo_list_del (&info->pending); + _cairo_xcb_shm_info_finalize (info); + } +} + +cairo_int_status_t +_cairo_xcb_connection_allocate_shm_info (cairo_xcb_connection_t *connection, + size_t size, + cairo_bool_t might_reuse, + cairo_xcb_shm_info_t **shm_info_out) +{ + cairo_xcb_shm_info_t *shm_info; + cairo_xcb_shm_mem_pool_t *pool, *next; + size_t bytes, maxbits = 16, minbits = 8; + size_t shm_allocated = 0; + void *mem = NULL; + cairo_status_t status; + + assert (connection->flags & CAIRO_XCB_HAS_SHM); + + CAIRO_MUTEX_LOCK (connection->shm_mutex); + _cairo_xcb_shm_process_pending (connection, PENDING_POLL); + + if (might_reuse) { + cairo_list_foreach_entry (shm_info, cairo_xcb_shm_info_t, + &connection->shm_pending, pending) { + if (shm_info->size >= size) { + cairo_list_del (&shm_info->pending); + CAIRO_MUTEX_UNLOCK (connection->shm_mutex); + + xcb_discard_reply (connection->xcb_connection, shm_info->sync.sequence); + shm_info->sync.sequence = XCB_NONE; + + *shm_info_out = shm_info; + return CAIRO_STATUS_SUCCESS; + } + } + } + + cairo_list_foreach_entry_safe (pool, next, cairo_xcb_shm_mem_pool_t, + &connection->shm_pools, link) + { + if (pool->mem.free_bytes > size) { + mem = _cairo_mempool_alloc (&pool->mem, size); + if (mem != NULL) { + /* keep the active pools towards the front */ + cairo_list_move (&pool->link, &connection->shm_pools); + goto allocate_shm_info; + } + } + /* scan for old, unused pools */ + if (pool->mem.free_bytes == pool->mem.max_bytes) { + _cairo_xcb_connection_shm_detach (connection, + pool->shmseg); + _cairo_xcb_shm_mem_pool_destroy (pool); + } else { + shm_allocated += pool->mem.max_bytes; + } + } + + if (unlikely (shm_allocated >= CAIRO_MAX_SHM_MEMORY)) { + CAIRO_MUTEX_UNLOCK (connection->shm_mutex); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + pool = _cairo_calloc (sizeof (cairo_xcb_shm_mem_pool_t)); + if (unlikely (pool == NULL)) { + CAIRO_MUTEX_UNLOCK (connection->shm_mutex); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + bytes = 1 << maxbits; + while (bytes <= size) + bytes <<= 1, maxbits++; + bytes <<= 3; + + do { + pool->shmid = shmget (IPC_PRIVATE, bytes, IPC_CREAT | 0600); + if (pool->shmid != -1) + break; + + /* If the allocation failed because we asked for too much memory, we try + * again with a smaller request, as long as our allocation still fits. */ + bytes >>= 1; + if (errno != EINVAL || bytes < size) + break; + } while (TRUE); + if (pool->shmid == -1) { + int err = errno; + if (! (err == EINVAL || err == ENOMEM)) + connection->flags &= ~CAIRO_XCB_HAS_SHM; + free (pool); + CAIRO_MUTEX_UNLOCK (connection->shm_mutex); + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + pool->shm = shmat (pool->shmid, NULL, 0); + if (unlikely (pool->shm == (char *) -1)) { + shmctl (pool->shmid, IPC_RMID, NULL); + free (pool); + CAIRO_MUTEX_UNLOCK (connection->shm_mutex); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + status = _cairo_mempool_init (&pool->mem, pool->shm, bytes, + minbits, maxbits - minbits + 1); + if (unlikely (status)) { + shmdt (pool->shm); + free (pool); + CAIRO_MUTEX_UNLOCK (connection->shm_mutex); + return status; + } + + pool->shmseg = _cairo_xcb_connection_shm_attach (connection, pool->shmid, FALSE); + shmctl (pool->shmid, IPC_RMID, NULL); + + cairo_list_add (&pool->link, &connection->shm_pools); + mem = _cairo_mempool_alloc (&pool->mem, size); + + allocate_shm_info: + shm_info = _cairo_freepool_alloc (&connection->shm_info_freelist); + if (unlikely (shm_info == NULL)) { + _cairo_mempool_free (&pool->mem, mem); + CAIRO_MUTEX_UNLOCK (connection->shm_mutex); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + shm_info->connection = connection; + shm_info->pool = pool; + shm_info->shm = pool->shmseg; + shm_info->size = size; + shm_info->offset = (char *) mem - (char *) pool->shm; + shm_info->mem = mem; + shm_info->sync.sequence = XCB_NONE; + + /* scan for old, unused pools */ + cairo_list_foreach_entry_safe (pool, next, cairo_xcb_shm_mem_pool_t, + &connection->shm_pools, link) + { + if (pool->mem.free_bytes == pool->mem.max_bytes) { + _cairo_xcb_connection_shm_detach (connection, + pool->shmseg); + _cairo_xcb_shm_mem_pool_destroy (pool); + } + } + CAIRO_MUTEX_UNLOCK (connection->shm_mutex); + + *shm_info_out = shm_info; + return CAIRO_STATUS_SUCCESS; +} + +void +_cairo_xcb_shm_info_destroy (cairo_xcb_shm_info_t *shm_info) +{ + cairo_xcb_connection_t *connection = shm_info->connection; + + /* We can only return shm_info->mem to the allocator when we can be sure + * that the X server no longer reads from it. Since the X server processes + * requests in order, we send a GetInputFocus here. + * _cairo_xcb_shm_process_pending () will later check if the reply for that + * request was received and then actually mark this memory area as free. */ + + CAIRO_MUTEX_LOCK (connection->shm_mutex); + assert (shm_info->sync.sequence == XCB_NONE); + shm_info->sync = xcb_get_input_focus (connection->xcb_connection); + + cairo_list_init (&shm_info->pending); + cairo_list_add_tail (&shm_info->pending, &connection->shm_pending); + CAIRO_MUTEX_UNLOCK (connection->shm_mutex); +} + +void +_cairo_xcb_connection_shm_mem_pools_flush (cairo_xcb_connection_t *connection) +{ + CAIRO_MUTEX_LOCK (connection->shm_mutex); + _cairo_xcb_shm_process_pending (connection, PENDING_WAIT); + CAIRO_MUTEX_UNLOCK (connection->shm_mutex); +} + +void +_cairo_xcb_connection_shm_mem_pools_fini (cairo_xcb_connection_t *connection) +{ + assert (cairo_list_is_empty (&connection->shm_pending)); + while (! cairo_list_is_empty (&connection->shm_pools)) { + _cairo_xcb_shm_mem_pool_destroy (cairo_list_first_entry (&connection->shm_pools, + cairo_xcb_shm_mem_pool_t, + link)); + } +} + +#endif /* CAIRO_HAS_XCB_SHM_FUNCTIONS */ diff --git a/local/recipes/libs/cairo/source/src/cairo-xcb-surface-core.c b/local/recipes/libs/cairo/source/src/cairo-xcb-surface-core.c new file mode 100644 index 0000000000..660e6d05a3 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-xcb-surface-core.c @@ -0,0 +1,641 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * Contributor(s): + * Chris Wilson + */ + +#include "cairoint.h" + +#include "cairo-boxes-private.h" +#include "cairo-xcb-private.h" +#include "cairo-image-surface-private.h" +#include "cairo-surface-backend-private.h" + +/* XXX dithering */ + +typedef struct _cairo_xcb_pixmap { + cairo_surface_t base; + + cairo_xcb_connection_t *connection; + cairo_xcb_screen_t *screen; + + cairo_surface_t *owner; + xcb_pixmap_t pixmap; + int width; + int height; + int depth; + int x0, y0; + cairo_bool_t repeat; +} cairo_xcb_pixmap_t; + +static cairo_status_t +_cairo_xcb_pixmap_finish (void *abstract_surface) +{ + cairo_xcb_pixmap_t *surface = abstract_surface; + cairo_status_t status; + + if (surface->owner != NULL) { + cairo_surface_destroy (surface->owner); + } else { + status = _cairo_xcb_connection_acquire (surface->connection); + if (unlikely (status)) + return status; + + xcb_free_pixmap (surface->connection->xcb_connection, + surface->pixmap); + _cairo_xcb_connection_release (surface->connection); + } + + return CAIRO_STATUS_SUCCESS; +} + +static const cairo_surface_backend_t _cairo_xcb_pixmap_backend = { + CAIRO_SURFACE_TYPE_XCB, + _cairo_xcb_pixmap_finish, +}; + +static cairo_xcb_pixmap_t * +_cairo_xcb_pixmap_create (cairo_xcb_surface_t *target, + int width, int height) +{ + cairo_xcb_pixmap_t *surface; + + surface = _cairo_calloc (sizeof (cairo_xcb_pixmap_t)); + if (unlikely (surface == NULL)) + return (cairo_xcb_pixmap_t *) + _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + _cairo_surface_init (&surface->base, + &_cairo_xcb_pixmap_backend, + NULL, + target->base.content, + FALSE); /* is_vector */ + + surface->connection = target->connection; + surface->screen = target->screen; + surface->owner = NULL; + surface->width = width; + surface->height = height; + surface->depth = target->depth; + surface->x0 = surface->y0 = 0; + surface->repeat = FALSE; + + surface->pixmap = + _cairo_xcb_connection_create_pixmap (surface->connection, + surface->depth, + target->drawable, + width, height); + + return surface; +} + +static cairo_xcb_pixmap_t * +_cairo_xcb_pixmap_copy (cairo_xcb_surface_t *target) +{ + cairo_xcb_pixmap_t *surface; + + surface = _cairo_calloc (sizeof (cairo_xcb_pixmap_t)); + if (unlikely (surface == NULL)) + return (cairo_xcb_pixmap_t *) + _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + _cairo_surface_init (&surface->base, + &_cairo_xcb_pixmap_backend, + NULL, + target->base.content, + FALSE); /* is_vector */ + + surface->connection = target->connection; + surface->screen = target->screen; + surface->pixmap = target->drawable; + surface->owner = cairo_surface_reference (&target->base); + surface->width = target->width; + surface->height = target->height; + surface->depth = target->depth; + surface->x0 = surface->y0 = 0; + surface->repeat = FALSE; + + return surface; +} + +#if CAIRO_HAS_XCB_SHM_FUNCTIONS +static cairo_status_t +_cairo_xcb_shm_image_create_shm (cairo_xcb_connection_t *connection, + pixman_format_code_t pixman_format, + int width, int height, + cairo_image_surface_t **image_out, + cairo_xcb_shm_info_t **shm_info_out) +{ + cairo_surface_t *image = NULL; + cairo_xcb_shm_info_t *shm_info = NULL; + cairo_status_t status; + size_t size, stride; + + if (! (connection->flags & CAIRO_XCB_HAS_SHM)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (unlikely (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + stride = CAIRO_STRIDE_FOR_WIDTH_BPP (width, PIXMAN_FORMAT_BPP (pixman_format)); + size = stride * height; + if (size <= CAIRO_XCB_SHM_SMALL_IMAGE) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_xcb_connection_allocate_shm_info (connection, size, + FALSE, &shm_info); + if (unlikely (status)) + return status; + + image = _cairo_image_surface_create_with_pixman_format (shm_info->mem, + pixman_format, + width, height, + stride); + status = image->status; + if (unlikely (status)) { + _cairo_xcb_shm_info_destroy (shm_info); + return status; + } + + status = _cairo_user_data_array_set_data (&image->user_data, + (const cairo_user_data_key_t *) connection, + shm_info, + (cairo_destroy_func_t) _cairo_xcb_shm_info_destroy); + + if (unlikely (status)) { + cairo_surface_destroy (image); + _cairo_xcb_shm_info_destroy (shm_info); + return status; + } + + *image_out = (cairo_image_surface_t *) image; + *shm_info_out = shm_info; + return CAIRO_STATUS_SUCCESS; +} +#else +static cairo_status_t +_cairo_xcb_shm_image_create_shm (cairo_xcb_connection_t *connection, + pixman_format_code_t pixman_format, + int width, int height, + cairo_image_surface_t **image_out, + cairo_xcb_shm_info_t **shm_info_out) +{ + return CAIRO_INT_STATUS_UNSUPPORTED; +} +#endif + +cairo_status_t +_cairo_xcb_shm_image_create (cairo_xcb_connection_t *connection, + pixman_format_code_t pixman_format, + int width, int height, + cairo_image_surface_t **image_out, + cairo_xcb_shm_info_t **shm_info_out) +{ + cairo_surface_t *image = NULL; + cairo_xcb_shm_info_t *shm_info = NULL; + cairo_status_t status; + + status = _cairo_xcb_shm_image_create_shm (connection, + pixman_format, + width, + height, + image_out, + shm_info_out); + + if (status != CAIRO_STATUS_SUCCESS) { + image = _cairo_image_surface_create_with_pixman_format (NULL, + pixman_format, + width, height, + 0); + status = image->status; + if (unlikely (status)) + return status; + + *image_out = (cairo_image_surface_t *) image; + *shm_info_out = shm_info; + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_xcb_pixmap_t * +_pixmap_from_image (cairo_xcb_surface_t *target, + xcb_render_pictformat_t format, + cairo_image_surface_t *image, + cairo_xcb_shm_info_t *shm_info) +{ + xcb_gcontext_t gc; + cairo_xcb_pixmap_t *pixmap; + + pixmap = _cairo_xcb_pixmap_create (target, + image->width, + image->height); + if (unlikely (pixmap->base.status)) + return pixmap; + + gc = _cairo_xcb_screen_get_gc (target->screen, pixmap->pixmap, image->depth); + + if (shm_info != NULL) { + _cairo_xcb_connection_shm_put_image (target->connection, + pixmap->pixmap, gc, + image->width, image->height, + 0, 0, + image->width, image->height, + 0, 0, + image->depth, + shm_info->shm, + shm_info->offset); + } else { + int len; + + /* Do we need to trim the image? */ + len = CAIRO_STRIDE_FOR_WIDTH_BPP (image->width, + PIXMAN_FORMAT_BPP (image->pixman_format)); + if (len == image->stride) { + _cairo_xcb_connection_put_image (target->connection, + pixmap->pixmap, gc, + image->width, image->height, + 0, 0, + image->depth, + image->stride, + image->data); + } else { + _cairo_xcb_connection_put_subimage (target->connection, + pixmap->pixmap, gc, + 0, 0, + image->width, image->height, + PIXMAN_FORMAT_BPP (image->pixman_format) / 8, + image->stride, + 0, 0, + image->depth, + image->data); + + } + } + + _cairo_xcb_screen_put_gc (target->screen, image->depth, gc); + + return pixmap; +} + +static cairo_xcb_pixmap_t * +_render_to_pixmap (cairo_xcb_surface_t *target, + const cairo_pattern_t *pattern, + const cairo_rectangle_int_t *extents) +{ + cairo_image_surface_t *image; + cairo_xcb_shm_info_t *shm_info; + cairo_pattern_union_t copy; + cairo_status_t status; + cairo_xcb_pixmap_t *pixmap; + + status = _cairo_xcb_shm_image_create (target->screen->connection, + target->pixman_format, + extents->width, extents->height, + &image, &shm_info); + if (unlikely (status)) + return (cairo_xcb_pixmap_t *) _cairo_surface_create_in_error (status); + + _cairo_pattern_init_static_copy (©.base, pattern); + cairo_matrix_translate (©.base.matrix, -extents->x, -extents->y); + status = _cairo_surface_paint (&image->base, + CAIRO_OPERATOR_SOURCE, + ©.base, + NULL); + if (unlikely (status)) { + cairo_surface_destroy (&image->base); + return (cairo_xcb_pixmap_t *) _cairo_surface_create_in_error (status); + } + + pixmap = _pixmap_from_image (target, target->xrender_format, image, shm_info); + cairo_surface_destroy (&image->base); + + if (unlikely (pixmap->base.status)) + return pixmap; + + pixmap->x0 = -extents->x; + pixmap->y0 = -extents->y; + return pixmap; +} + +static cairo_xcb_pixmap_t * +_copy_to_pixmap (cairo_xcb_surface_t *source) +{ + cairo_xcb_pixmap_t *pixmap; + + /* If the source may be a window, we need to copy it and its children + * via a temporary pixmap so that we can IncludeInferiors on the source + * and use ClipByChildren on the destination. + */ + if (source->owns_pixmap) { + pixmap = _cairo_xcb_pixmap_copy (source); + if (unlikely (pixmap->base.status)) + return pixmap; + } else { + uint32_t values[1]; + xcb_gcontext_t gc; + + pixmap = _cairo_xcb_pixmap_create (source, + source->width, + source->height); + if (unlikely (pixmap->base.status)) + return pixmap; + + gc = _cairo_xcb_screen_get_gc (source->screen, + pixmap->pixmap, + pixmap->depth); + + values[0] = TRUE; + _cairo_xcb_connection_change_gc (pixmap->connection, gc, + XCB_GC_SUBWINDOW_MODE, values); + + _cairo_xcb_connection_copy_area (pixmap->connection, + source->drawable, + pixmap->pixmap, gc, + 0, 0, + 0, 0, + source->width, + source->height); + + values[0] = FALSE; + _cairo_xcb_connection_change_gc (pixmap->connection, gc, + XCB_GC_SUBWINDOW_MODE, values); + + _cairo_xcb_screen_put_gc (source->screen, + pixmap->depth, + gc); + } + + return pixmap; +} +static cairo_xcb_pixmap_t * +_cairo_xcb_surface_pixmap (cairo_xcb_surface_t *target, + const cairo_surface_pattern_t *pattern, + const cairo_rectangle_int_t *extents, + int tx, int ty) +{ + cairo_surface_t *source; + cairo_xcb_pixmap_t *pixmap; + + source = pattern->surface; + pixmap = (cairo_xcb_pixmap_t *) + _cairo_surface_has_snapshot (source, &_cairo_xcb_pixmap_backend); + if (pixmap != NULL && pixmap->screen == target->screen) + return (cairo_xcb_pixmap_t *) cairo_surface_reference (&pixmap->base); + + if (_cairo_surface_is_xcb(source) && + ((cairo_xcb_surface_t *) source)->screen == target->screen) + { + cairo_xcb_surface_t *xcb_source = (cairo_xcb_surface_t *) source; + + if (xcb_source->depth == target->depth) + pixmap = _copy_to_pixmap (xcb_source); + } +#if CAIRO_HAS_XLIB_XCB_FUNCTIONS + else if (source->type == CAIRO_SURFACE_TYPE_XLIB && + ((cairo_xlib_xcb_surface_t *) source)->xcb->screen == target->screen) + { + cairo_xcb_surface_t *xcb_source = ((cairo_xlib_xcb_surface_t *) source)->xcb; + + if (xcb_source->depth == target->depth) + pixmap = _copy_to_pixmap (xcb_source); + } +#endif + + if (pixmap == NULL) { + cairo_rectangle_int_t rect; + + if (! _cairo_surface_get_extents (source, &rect)) { + rect.x = rect.y = 0; + rect.width = target->width; + rect.height = target->height; + } + + pixmap = _render_to_pixmap (target, &pattern->base, &rect); + } + + if (unlikely (pixmap->base.status)) + return pixmap; + + _cairo_surface_attach_snapshot (source, &pixmap->base, NULL); + + if (pattern->base.extend != CAIRO_EXTEND_NONE) { + if (extents->x < 0 || extents->y < 0 || + extents->x + extents->width > pixmap->width || + extents->y + extents->height > pixmap->height) + { + pixmap->repeat = TRUE; + } + } + + pixmap->x0 += tx; + pixmap->y0 += ty; + + return pixmap; +} + +static cairo_xcb_pixmap_t * +_cairo_xcb_pixmap_for_pattern (cairo_xcb_surface_t *target, + const cairo_pattern_t *pattern, + const cairo_rectangle_int_t *extents) +{ + int tx, ty; + + switch (pattern->type) { + case CAIRO_PATTERN_TYPE_SURFACE: + /* Core can only perform a native, unscaled blit, but can handle tiles */ + if (_cairo_matrix_is_integer_translation (&pattern->matrix, &tx, &ty)) { + switch (pattern->extend) { + case CAIRO_EXTEND_NONE: + case CAIRO_EXTEND_REPEAT: + return _cairo_xcb_surface_pixmap (target, + (cairo_surface_pattern_t *) pattern, + extents, tx, ty); + + default: + case CAIRO_EXTEND_PAD: + case CAIRO_EXTEND_REFLECT: + break; + } + } + /* fallthrough */ + case CAIRO_PATTERN_TYPE_LINEAR: + case CAIRO_PATTERN_TYPE_RADIAL: + case CAIRO_PATTERN_TYPE_MESH: + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + return _render_to_pixmap (target, pattern, extents); + + default: + case CAIRO_PATTERN_TYPE_SOLID: + ASSERT_NOT_REACHED; + return NULL; + } +} + +cairo_status_t +_cairo_xcb_surface_core_copy_boxes (cairo_xcb_surface_t *dst, + const cairo_pattern_t *src_pattern, + const cairo_rectangle_int_t *extents, + const cairo_boxes_t *boxes) +{ + cairo_xcb_pixmap_t *src; + const struct _cairo_boxes_chunk *chunk; + xcb_gcontext_t gc; + cairo_status_t status; + + status = _cairo_xcb_connection_acquire (dst->connection); + if (unlikely (status)) + return status; + + src = _cairo_xcb_pixmap_for_pattern (dst, src_pattern, extents); + status = src->base.status; + if (unlikely (status)) + goto CLEANUP_CONNECTION; + + assert (src->depth == dst->depth); + + gc = _cairo_xcb_screen_get_gc (dst->screen, src->pixmap, src->depth); + + if (src->repeat) { + uint32_t mask = + XCB_GC_FILL_STYLE | + XCB_GC_TILE | + XCB_GC_TILE_STIPPLE_ORIGIN_X | + XCB_GC_TILE_STIPPLE_ORIGIN_Y; + uint32_t values[] = { + XCB_FILL_STYLE_TILED, + src->pixmap, + - src->x0, - src->y0, + }; + xcb_rectangle_t *xcb_rects; + + _cairo_xcb_connection_change_gc (dst->connection, gc, mask, values); + + for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { + int i; + + xcb_rects = (xcb_rectangle_t *) chunk->base; + + for (i = 0; i < chunk->count; i++) { + int x1 = _cairo_fixed_integer_round (chunk->base[i].p1.x); + int x2 = _cairo_fixed_integer_round (chunk->base[i].p2.x); + int y1 = _cairo_fixed_integer_round (chunk->base[i].p1.y); + int y2 = _cairo_fixed_integer_round (chunk->base[i].p2.y); + + xcb_rects[i].x = x1; + xcb_rects[i].y = y1; + xcb_rects[i].width = x2 - x1; + xcb_rects[i].height = y2 - y1; + } + _cairo_xcb_connection_poly_fill_rectangle (dst->connection, + dst->drawable, + gc, chunk->count, xcb_rects); + } + + values[0] = 0; + _cairo_xcb_connection_change_gc (dst->connection, gc, XCB_GC_FILL_STYLE, values); + } else { + for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { + int i; + + for (i = 0; i < chunk->count; i++) { + int x1 = _cairo_fixed_integer_round (chunk->base[i].p1.x); + int x2 = _cairo_fixed_integer_round (chunk->base[i].p2.x); + int y1 = _cairo_fixed_integer_round (chunk->base[i].p1.y); + int y2 = _cairo_fixed_integer_round (chunk->base[i].p2.y); + + _cairo_xcb_connection_copy_area (dst->connection, + src->pixmap, + dst->drawable, gc, + src->x0 + x1, + src->y0 + y1, + x1, y1, + x2 - x1, y2 - y1); + } + } + } + + _cairo_xcb_screen_put_gc (dst->screen, src->depth, gc); + cairo_surface_destroy (&src->base); + + CLEANUP_CONNECTION: + _cairo_xcb_connection_release (dst->connection); + + return status; +} + +cairo_status_t +_cairo_xcb_surface_core_fill_boxes (cairo_xcb_surface_t *dst, + const cairo_color_t *color, + cairo_boxes_t *boxes) +{ + struct _cairo_boxes_chunk *chunk; + xcb_gcontext_t gc; + cairo_status_t status; + + status = _cairo_xcb_connection_acquire (dst->connection); + if (unlikely (status)) + return status; + + gc = _cairo_xcb_screen_get_gc (dst->screen, dst->drawable, dst->depth); + +#if 0 + xcb_pixmap_t source; + + source = _dither_source (dst, color); + XSetTSOrigin (surface->dpy, gc, 0, 0); + XSetTile (surface->dpy, gc, source); +#endif + + for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { + xcb_rectangle_t *xcb_rects; + int i; + + xcb_rects = (xcb_rectangle_t *) chunk->base; + for (i = 0; i < chunk->count; i++) { + int x1 = _cairo_fixed_integer_round (chunk->base[i].p1.x); + int x2 = _cairo_fixed_integer_round (chunk->base[i].p2.x); + int y1 = _cairo_fixed_integer_round (chunk->base[i].p1.y); + int y2 = _cairo_fixed_integer_round (chunk->base[i].p2.y); + + xcb_rects[i].x = x1; + xcb_rects[i].y = y1; + xcb_rects[i].width = x2 - x1; + xcb_rects[i].height = y2 - y1; + } + + _cairo_xcb_connection_poly_fill_rectangle (dst->connection, + dst->drawable, gc, + chunk->count, xcb_rects); + } + + _cairo_xcb_screen_put_gc (dst->screen, dst->depth, gc); + _cairo_xcb_connection_release (dst->connection); + + return CAIRO_STATUS_SUCCESS; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-xcb-surface-render.c b/local/recipes/libs/cairo/source/src/cairo-xcb-surface-render.c new file mode 100644 index 0000000000..2777c3cda3 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-xcb-surface-render.c @@ -0,0 +1,4877 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2009 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * Contributor(s): + * Chris Wilson + */ + +#include "cairoint.h" + +#include "cairo-xcb-private.h" + +#include "cairo-boxes-private.h" +#include "cairo-clip-inline.h" +#include "cairo-clip-private.h" +#include "cairo-composite-rectangles-private.h" +#include "cairo-image-surface-inline.h" +#include "cairo-image-surface-private.h" +#include "cairo-list-inline.h" +#include "cairo-region-private.h" +#include "cairo-surface-offset-private.h" +#include "cairo-surface-snapshot-inline.h" +#include "cairo-surface-subsurface-private.h" +#include "cairo-traps-private.h" +#include "cairo-recording-surface-inline.h" +#include "cairo-paginated-private.h" +#include "cairo-pattern-inline.h" + +#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */ + +static cairo_status_t +_clip_and_composite_boxes (cairo_xcb_surface_t *dst, + cairo_operator_t op, + const cairo_pattern_t *src, + cairo_boxes_t *boxes, + cairo_composite_rectangles_t *extents); + +static inline cairo_xcb_connection_t * +_picture_to_connection (cairo_xcb_picture_t *picture) +{ + return (cairo_xcb_connection_t *) picture->base.device; +} + +static void +_cairo_xcb_surface_ensure_picture (cairo_xcb_surface_t *surface); + +static uint32_t +hars_petruska_f54_1_random (void) +{ +#define rol(x,k) ((x << k) | (x >> (32-k))) + static uint32_t x; + return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849; +#undef rol +} + +static cairo_status_t +_cairo_xcb_picture_finish (void *abstract_surface) +{ + cairo_xcb_picture_t *surface = abstract_surface; + cairo_xcb_connection_t *connection = _picture_to_connection (surface); + cairo_status_t status; + + status = _cairo_xcb_connection_acquire (connection); + cairo_list_del (&surface->link); + if (unlikely (status)) + return status; + + _cairo_xcb_connection_render_free_picture (connection, surface->picture); + + _cairo_xcb_connection_release (connection); + + return CAIRO_STATUS_SUCCESS; +} + +static const cairo_surface_backend_t _cairo_xcb_picture_backend = { + CAIRO_SURFACE_TYPE_XCB, + _cairo_xcb_picture_finish, +}; + +static const struct xcb_render_transform_t identity_transform = { + 1 << 16, 0, 0, + 0, 1 << 16, 0, + 0, 0, 1 << 16, +}; + +static cairo_xcb_picture_t * +_cairo_xcb_picture_create (cairo_xcb_screen_t *screen, + pixman_format_code_t pixman_format, + xcb_render_pictformat_t xrender_format, + int width, int height) +{ + cairo_xcb_picture_t *surface; + + surface = _cairo_calloc (sizeof (cairo_xcb_picture_t)); + if (unlikely (surface == NULL)) + return (cairo_xcb_picture_t *) + _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + _cairo_surface_init (&surface->base, + &_cairo_xcb_picture_backend, + &screen->connection->device, + _cairo_content_from_pixman_format (pixman_format), + FALSE); /* is_vector */ + + cairo_list_add (&surface->link, &screen->pictures); + + surface->screen = screen; + surface->picture = xcb_generate_id (screen->connection->xcb_connection); + surface->pixman_format = pixman_format; + surface->xrender_format = xrender_format; + + surface->x0 = surface->y0 = 0; + surface->x = surface->y = 0; + surface->width = width; + surface->height = height; + + surface->transform = identity_transform; + surface->extend = CAIRO_EXTEND_NONE; + surface->filter = CAIRO_FILTER_NEAREST; + surface->has_component_alpha = FALSE; + + return surface; +} + +static inline cairo_bool_t +_operator_is_supported (uint32_t flags, cairo_operator_t op) +{ + if (op <= CAIRO_OPERATOR_SATURATE) + return TRUE; + + /* Can we use PDF operators? */ +#if CAIRO_XCB_RENDER_AT_LEAST(0, 11) + if (op <= CAIRO_OPERATOR_HSL_LUMINOSITY) + return flags & CAIRO_XCB_RENDER_HAS_PDF_OPERATORS; +#endif + + return FALSE; +} + +static int +_render_operator (cairo_operator_t op) +{ +#define C(x,y) case CAIRO_OPERATOR_##x: return XCB_RENDER_PICT_OP_##y + switch (op) { + C(CLEAR, CLEAR); + C(SOURCE, SRC); + + C(OVER, OVER); + C(IN, IN); + C(OUT, OUT); + C(ATOP, ATOP); + + C(DEST, DST); + C(DEST_OVER, OVER_REVERSE); + C(DEST_IN, IN_REVERSE); + C(DEST_OUT, OUT_REVERSE); + C(DEST_ATOP, ATOP_REVERSE); + + C(XOR, XOR); + C(ADD, ADD); + C(SATURATE, SATURATE); + + /* PDF operators were added in RENDER 0.11, check if the xcb headers have + * the defines, else fall through to the default case. */ +#if CAIRO_XCB_RENDER_AT_LEAST(0, 11) +#define BLEND(x,y) C(x,y) +#else +#define BLEND(x,y) case CAIRO_OPERATOR_##x: +#endif + BLEND(MULTIPLY, MULTIPLY); + BLEND(SCREEN, SCREEN); + BLEND(OVERLAY, OVERLAY); + BLEND(DARKEN, DARKEN); + BLEND(LIGHTEN, LIGHTEN); + BLEND(COLOR_DODGE, COLOR_DODGE); + BLEND(COLOR_BURN, COLOR_BURN); + BLEND(HARD_LIGHT, HARD_LIGHT); + BLEND(SOFT_LIGHT, SOFT_LIGHT); + BLEND(DIFFERENCE, DIFFERENCE); + BLEND(EXCLUSION, EXCLUSION); + BLEND(HSL_HUE, HSL_HUE); + BLEND(HSL_SATURATION, HSL_SATURATION); + BLEND(HSL_COLOR, HSL_COLOR); + BLEND(HSL_LUMINOSITY, HSL_LUMINOSITY); + + default: + ASSERT_NOT_REACHED; + return XCB_RENDER_PICT_OP_OVER; + } +} + +static cairo_status_t +_cairo_xcb_surface_set_clip_region (cairo_xcb_surface_t *surface, + cairo_region_t *region) +{ + xcb_rectangle_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (xcb_rectangle_t)]; + xcb_rectangle_t *rects = stack_rects; + int i, num_rects; + + num_rects = cairo_region_num_rectangles (region); + + if (num_rects > ARRAY_LENGTH (stack_rects)) { + rects = _cairo_malloc_ab (num_rects, sizeof (xcb_rectangle_t)); + if (unlikely (rects == NULL)) { + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + } + + for (i = 0; i < num_rects; i++) { + cairo_rectangle_int_t rect; + + cairo_region_get_rectangle (region, i, &rect); + + rects[i].x = rect.x; + rects[i].y = rect.y; + rects[i].width = rect.width; + rects[i].height = rect.height; + } + + _cairo_xcb_connection_render_set_picture_clip_rectangles (surface->connection, + surface->picture, + 0, 0, + num_rects, rects); + + if (rects != stack_rects) + free (rects); + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_xcb_surface_clear_clip_region (cairo_xcb_surface_t *surface) +{ + uint32_t values[] = { XCB_NONE }; + _cairo_xcb_connection_render_change_picture (surface->connection, + surface->picture, + XCB_RENDER_CP_CLIP_MASK, + values); +} + +static void +_cairo_xcb_surface_set_precision (cairo_xcb_surface_t *surface, + cairo_antialias_t antialias) +{ + cairo_xcb_connection_t *connection = surface->connection; + uint32_t precision; + + if (connection->force_precision != -1) + precision = connection->force_precision; + else switch (antialias) { + default: + case CAIRO_ANTIALIAS_DEFAULT: + case CAIRO_ANTIALIAS_GRAY: + case CAIRO_ANTIALIAS_NONE: + case CAIRO_ANTIALIAS_FAST: + case CAIRO_ANTIALIAS_GOOD: + precision = XCB_RENDER_POLY_MODE_IMPRECISE; + break; + case CAIRO_ANTIALIAS_SUBPIXEL: + case CAIRO_ANTIALIAS_BEST: + precision = XCB_RENDER_POLY_MODE_PRECISE; + break; + } + + if (surface->precision != precision) { + _cairo_xcb_connection_render_change_picture (connection, + surface->picture, + XCB_RENDER_CP_POLY_MODE, + &precision); + surface->precision = precision; + } +} + + +static void +_cairo_xcb_surface_ensure_picture (cairo_xcb_surface_t *surface) +{ + assert (surface->fallback == NULL); + if (surface->picture == XCB_NONE) { + uint32_t values[1]; + uint32_t flags = 0; + + if (surface->precision != XCB_RENDER_POLY_MODE_PRECISE) { + flags |= XCB_RENDER_CP_POLY_MODE; + values[0] = surface->precision; + } + + surface->picture = xcb_generate_id (surface->connection->xcb_connection); + _cairo_xcb_connection_render_create_picture (surface->connection, + surface->picture, + surface->drawable, + surface->xrender_format, + flags, values); + } +} + +static cairo_xcb_picture_t * +_picture_from_image (cairo_xcb_surface_t *target, + xcb_render_pictformat_t format, + cairo_image_surface_t *image, + cairo_xcb_shm_info_t *shm_info) +{ + xcb_pixmap_t pixmap; + xcb_gcontext_t gc; + cairo_xcb_picture_t *picture; + + pixmap = _cairo_xcb_connection_create_pixmap (target->connection, + image->depth, + target->drawable, + image->width, image->height); + + gc = _cairo_xcb_screen_get_gc (target->screen, pixmap, image->depth); + + if (shm_info != NULL) { + _cairo_xcb_connection_shm_put_image (target->connection, + pixmap, gc, + image->width, image->height, + 0, 0, + image->width, image->height, + 0, 0, + image->depth, + shm_info->shm, + shm_info->offset); + } else { + int len; + + /* Do we need to trim the image? */ + len = CAIRO_STRIDE_FOR_WIDTH_BPP (image->width, PIXMAN_FORMAT_BPP (image->pixman_format)); + if (len == image->stride) { + _cairo_xcb_connection_put_image (target->connection, + pixmap, gc, + image->width, image->height, + 0, 0, + image->depth, + image->stride, + image->data); + } else { + _cairo_xcb_connection_put_subimage (target->connection, + pixmap, gc, + 0, 0, + image->width, image->height, + PIXMAN_FORMAT_BPP (image->pixman_format) / 8, + image->stride, + 0, 0, + image->depth, + image->data); + + } + } + + _cairo_xcb_screen_put_gc (target->screen, image->depth, gc); + + picture = _cairo_xcb_picture_create (target->screen, + image->pixman_format, format, + image->width, image->height); + if (likely (picture->base.status == CAIRO_STATUS_SUCCESS)) { + _cairo_xcb_connection_render_create_picture (target->connection, + picture->picture, pixmap, format, + 0, 0); + } + + xcb_free_pixmap (target->connection->xcb_connection, pixmap); + + return picture; +} + +static cairo_bool_t +_pattern_is_supported (uint32_t flags, + const cairo_pattern_t *pattern) + +{ + if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) + return TRUE; + + switch (pattern->extend) { + default: + ASSERT_NOT_REACHED; + case CAIRO_EXTEND_NONE: + case CAIRO_EXTEND_REPEAT: + break; + case CAIRO_EXTEND_PAD: + case CAIRO_EXTEND_REFLECT: + if ((flags & CAIRO_XCB_RENDER_HAS_EXTENDED_REPEAT) == 0) + return FALSE; + } + + if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { + switch (pattern->filter) { + case CAIRO_FILTER_FAST: + case CAIRO_FILTER_NEAREST: + return (flags & CAIRO_XCB_RENDER_HAS_PICTURE_TRANSFORM) || + _cairo_matrix_is_integer_translation (&pattern->matrix, NULL, NULL); + case CAIRO_FILTER_GOOD: + return flags & CAIRO_XCB_RENDER_HAS_FILTER_GOOD; + case CAIRO_FILTER_BEST: + return flags & CAIRO_XCB_RENDER_HAS_FILTER_BEST; + case CAIRO_FILTER_BILINEAR: + case CAIRO_FILTER_GAUSSIAN: + default: + return flags & CAIRO_XCB_RENDER_HAS_FILTERS; + } + } else if (pattern->type == CAIRO_PATTERN_TYPE_MESH) { + return FALSE; + } else { /* gradient */ + if ((flags & CAIRO_XCB_RENDER_HAS_GRADIENTS) == 0) + return FALSE; + + /* The RENDER specification says that the inner circle has to be + * completely contained inside the outer one. */ + if (pattern->type == CAIRO_PATTERN_TYPE_RADIAL && + ! _cairo_radial_pattern_focus_is_inside ((cairo_radial_pattern_t *) pattern)) + { + return FALSE; + } + return TRUE; + } +} + +static void +_cairo_xcb_picture_set_matrix (cairo_xcb_picture_t *picture, + const cairo_matrix_t *matrix, + cairo_filter_t filter, + double xc, double yc) +{ + xcb_render_transform_t transform; + pixman_transform_t *pixman_transform; + cairo_int_status_t ignored; + + /* Casting between pixman_transform_t and xcb_render_transform_t is safe + * because they happen to be the exact same type. + */ + pixman_transform = (pixman_transform_t *) &transform; + + picture->x = picture->x0; + picture->y = picture->y0; + ignored = _cairo_matrix_to_pixman_matrix_offset (matrix, filter, xc, yc, + pixman_transform, + &picture->x, &picture->y); + (void) ignored; + + if (memcmp (&picture->transform, &transform, sizeof (xcb_render_transform_t))) { + _cairo_xcb_connection_render_set_picture_transform (_picture_to_connection (picture), + picture->picture, + &transform); + + picture->transform = transform; + } +} + +static void +_cairo_xcb_picture_set_filter (cairo_xcb_picture_t *picture, + cairo_filter_t filter) +{ + const char *render_filter; + int len; + + if (picture->filter == filter) + return; + + switch (filter) { + case CAIRO_FILTER_FAST: + render_filter = "fast"; + len = strlen ("fast"); + break; + + case CAIRO_FILTER_GOOD: + render_filter = "good"; + len = strlen ("good"); + break; + + case CAIRO_FILTER_BEST: + render_filter = "best"; + len = strlen ("best"); + break; + + case CAIRO_FILTER_NEAREST: + render_filter = "nearest"; + len = strlen ("nearest"); + break; + + case CAIRO_FILTER_BILINEAR: + render_filter = "bilinear"; + len = strlen ("bilinear"); + break; + + default: + ASSERT_NOT_REACHED; + case CAIRO_FILTER_GAUSSIAN: + render_filter = "best"; + len = strlen ("best"); + break; + } + + _cairo_xcb_connection_render_set_picture_filter (_picture_to_connection (picture), + picture->picture, + len, (char *) render_filter); + picture->filter = filter; +} + +static void +_cairo_xcb_picture_set_extend (cairo_xcb_picture_t *picture, + cairo_extend_t extend) +{ + uint32_t pa[1]; + + if (picture->extend == extend) + return; + + switch (extend) { + default: + ASSERT_NOT_REACHED; + case CAIRO_EXTEND_NONE: + pa[0] = XCB_RENDER_REPEAT_NONE; + break; + + case CAIRO_EXTEND_REPEAT: + pa[0] = XCB_RENDER_REPEAT_NORMAL; + break; + + case CAIRO_EXTEND_REFLECT: + pa[0] = XCB_RENDER_REPEAT_REFLECT; + break; + + case CAIRO_EXTEND_PAD: + pa[0] = XCB_RENDER_REPEAT_PAD; + break; + } + + _cairo_xcb_connection_render_change_picture (_picture_to_connection (picture), + picture->picture, + XCB_RENDER_CP_REPEAT, pa); + picture->extend = extend; +} + +static void +_cairo_xcb_picture_set_component_alpha (cairo_xcb_picture_t *picture, + cairo_bool_t ca) +{ + uint32_t pa[1]; + + if (picture->has_component_alpha == ca) + return; + + pa[0] = ca; + + _cairo_xcb_connection_render_change_picture (_picture_to_connection (picture), + picture->picture, + XCB_RENDER_CP_COMPONENT_ALPHA, + pa); + picture->has_component_alpha = ca; +} + +static cairo_xcb_picture_t * +_solid_picture (cairo_xcb_surface_t *target, + const cairo_color_t *color) +{ + xcb_render_color_t xcb_color; + xcb_render_pictformat_t xrender_format; + cairo_xcb_picture_t *picture; + + xcb_color.red = color->red_short; + xcb_color.green = color->green_short; + xcb_color.blue = color->blue_short; + xcb_color.alpha = color->alpha_short; + + xrender_format = target->screen->connection->standard_formats[CAIRO_FORMAT_ARGB32]; + picture = _cairo_xcb_picture_create (target->screen, + PIXMAN_a8r8g8b8, + xrender_format, + -1, -1); + if (unlikely (picture->base.status)) + return picture; + + if (target->connection->flags & CAIRO_XCB_RENDER_HAS_GRADIENTS) { + _cairo_xcb_connection_render_create_solid_fill (target->connection, + picture->picture, + xcb_color); + } else { + xcb_pixmap_t pixmap; + uint32_t values[] = { XCB_RENDER_REPEAT_NORMAL }; + + pixmap = _cairo_xcb_connection_create_pixmap (target->connection, + 32, target->drawable, 1, 1); + _cairo_xcb_connection_render_create_picture (target->connection, + picture->picture, + pixmap, + xrender_format, + XCB_RENDER_CP_REPEAT, + values); + if (target->connection->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES) { + xcb_rectangle_t rect; + + rect.x = rect.y = 0; + rect.width = rect.height = 1; + + _cairo_xcb_connection_render_fill_rectangles (_picture_to_connection (picture), + XCB_RENDER_PICT_OP_SRC, + picture->picture, + xcb_color, 1, &rect); + } else { + xcb_gcontext_t gc; + uint32_t pixel; + + gc = _cairo_xcb_screen_get_gc (target->screen, pixmap, 32); + + /* XXX byte ordering? */ + pixel = (((uint32_t)color->alpha_short >> 8) << 24) | + ((color->red_short >> 8) << 16) | + ((color->green_short >> 8) << 8) | + ((color->blue_short >> 8) << 0); + + _cairo_xcb_connection_put_image (target->connection, + pixmap, gc, + 1, 1, 0, 0, + 32, 4, &pixel); + + _cairo_xcb_screen_put_gc (target->screen, 32, gc); + } + + xcb_free_pixmap (target->connection->xcb_connection, pixmap); + } + + return picture; +} + +static cairo_xcb_picture_t * +_cairo_xcb_transparent_picture (cairo_xcb_surface_t *target) +{ + cairo_xcb_picture_t *picture; + + picture = (cairo_xcb_picture_t *) target->screen->stock_colors[CAIRO_STOCK_TRANSPARENT]; + if (picture == NULL) { + picture = _solid_picture (target, CAIRO_COLOR_TRANSPARENT); + target->screen->stock_colors[CAIRO_STOCK_TRANSPARENT] = &picture->base; + } + + return (cairo_xcb_picture_t *) cairo_surface_reference (&picture->base); +} + +static cairo_xcb_picture_t * +_cairo_xcb_black_picture (cairo_xcb_surface_t *target) +{ + cairo_xcb_picture_t *picture; + + picture = (cairo_xcb_picture_t *) target->screen->stock_colors[CAIRO_STOCK_BLACK]; + if (picture == NULL) { + picture = _solid_picture (target, CAIRO_COLOR_BLACK); + target->screen->stock_colors[CAIRO_STOCK_BLACK] = &picture->base; + } + + return (cairo_xcb_picture_t *) cairo_surface_reference (&picture->base); +} + +static cairo_xcb_picture_t * +_cairo_xcb_white_picture (cairo_xcb_surface_t *target) +{ + cairo_xcb_picture_t *picture; + + picture = (cairo_xcb_picture_t *) target->screen->stock_colors[CAIRO_STOCK_WHITE]; + if (picture == NULL) { + picture = _solid_picture (target, CAIRO_COLOR_WHITE); + target->screen->stock_colors[CAIRO_STOCK_WHITE] = &picture->base; + } + + return (cairo_xcb_picture_t *) cairo_surface_reference (&picture->base); +} + +static cairo_xcb_picture_t * +_cairo_xcb_solid_picture (cairo_xcb_surface_t *target, + const cairo_solid_pattern_t *pattern) +{ + cairo_xcb_picture_t *picture; + cairo_xcb_screen_t *screen; + int i, n_cached; + + if (pattern->color.alpha_short <= 0x00ff) + return _cairo_xcb_transparent_picture (target); + + if (pattern->color.alpha_short >= 0xff00) { + if (pattern->color.red_short <= 0x00ff && + pattern->color.green_short <= 0x00ff && + pattern->color.blue_short <= 0x00ff) + { + return _cairo_xcb_black_picture (target); + } + + if (pattern->color.red_short >= 0xff00 && + pattern->color.green_short >= 0xff00 && + pattern->color.blue_short >= 0xff00) + { + return _cairo_xcb_white_picture (target); + } + } + + screen = target->screen; + n_cached = screen->solid_cache_size; + for (i = 0; i < n_cached; i++) { + if (_cairo_color_equal (&screen->solid_cache[i].color, &pattern->color)) { + return (cairo_xcb_picture_t *) cairo_surface_reference (screen->solid_cache[i].picture); + } + } + + picture = _solid_picture (target, &pattern->color); + if (unlikely (picture->base.status)) + return picture; + + if (screen->solid_cache_size < ARRAY_LENGTH (screen->solid_cache)) { + i = screen->solid_cache_size++; + } else { + i = hars_petruska_f54_1_random () % ARRAY_LENGTH (screen->solid_cache); + cairo_surface_destroy (screen->solid_cache[i].picture); + } + screen->solid_cache[i].picture = cairo_surface_reference (&picture->base); + screen->solid_cache[i].color = pattern->color; + + return picture; +} + +static cairo_xcb_picture_t * +_render_to_picture (cairo_xcb_surface_t *target, + const cairo_pattern_t *pattern, + const cairo_rectangle_int_t *extents) +{ + cairo_image_surface_t *image; + cairo_xcb_shm_info_t *shm_info; + cairo_pattern_union_t copy; + cairo_status_t status; + cairo_xcb_picture_t *picture; + pixman_format_code_t pixman_format; + xcb_render_pictformat_t xrender_format; + + /* XXX handle extend modes via tiling? */ + /* XXX alpha-only masks? */ + + pixman_format = PIXMAN_a8r8g8b8; + xrender_format = target->screen->connection->standard_formats[CAIRO_FORMAT_ARGB32]; + + status = _cairo_xcb_shm_image_create (target->screen->connection, + pixman_format, + extents->width, extents->height, + &image, &shm_info); + if (unlikely (status)) + return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status); + + _cairo_pattern_init_static_copy (©.base, pattern); + cairo_matrix_translate (©.base.matrix, extents->x, extents->y); + status = _cairo_surface_paint (&image->base, + CAIRO_OPERATOR_SOURCE, + ©.base, + NULL); + if (unlikely (status)) { + cairo_surface_destroy (&image->base); + return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status); + } + + picture = _picture_from_image (target, xrender_format, image, shm_info); + cairo_surface_destroy (&image->base); + + if (unlikely (picture->base.status)) + return picture; + + _cairo_xcb_picture_set_component_alpha (picture, pattern->has_component_alpha); + picture->x = -extents->x; + picture->y = -extents->y; + + return picture; +} + +static xcb_render_fixed_t * +_gradient_to_xcb (const cairo_gradient_pattern_t *gradient, + unsigned int *n_stops, + char *buf, unsigned int buflen) +{ + xcb_render_fixed_t *stops; + xcb_render_color_t *colors; + unsigned int i; + + assert (gradient->n_stops > 0); + *n_stops = MAX (gradient->n_stops, 2); + + if (*n_stops * (sizeof (xcb_render_fixed_t) + sizeof (xcb_render_color_t)) < buflen) + { + stops = (xcb_render_fixed_t *) buf; + } + else + { + stops = + _cairo_malloc_ab (*n_stops, + sizeof (xcb_render_fixed_t) + sizeof (xcb_render_color_t)); + if (unlikely (stops == NULL)) + return NULL; + } + + colors = (xcb_render_color_t *) (stops + *n_stops); + for (i = 0; i < gradient->n_stops; i++) { + stops[i] = + _cairo_fixed_16_16_from_double (gradient->stops[i].offset); + + colors[i].red = gradient->stops[i].color.red_short; + colors[i].green = gradient->stops[i].color.green_short; + colors[i].blue = gradient->stops[i].color.blue_short; + colors[i].alpha = gradient->stops[i].color.alpha_short; + } + + /* RENDER does not support gradients with less than 2 stops. If a + * gradient has only a single stop, duplicate it to make RENDER + * happy. */ + if (gradient->n_stops == 1) { + stops[1] = _cairo_fixed_16_16_from_double (gradient->stops[0].offset); + + colors[1].red = gradient->stops[0].color.red_short; + colors[1].green = gradient->stops[0].color.green_short; + colors[1].blue = gradient->stops[0].color.blue_short; + colors[1].alpha = gradient->stops[0].color.alpha_short; + } + + return stops; +} + +static cairo_xcb_picture_t * +_cairo_xcb_linear_picture (cairo_xcb_surface_t *target, + const cairo_linear_pattern_t *pattern, + const cairo_rectangle_int_t *extents) +{ + char buf[CAIRO_STACK_BUFFER_SIZE]; + xcb_render_fixed_t *stops; + xcb_render_color_t *colors; + xcb_render_pointfix_t p1, p2; + cairo_matrix_t matrix; + cairo_circle_double_t extremes[2]; + cairo_xcb_picture_t *picture; + cairo_status_t status; + unsigned int n_stops; + + _cairo_gradient_pattern_fit_to_range (&pattern->base, PIXMAN_MAX_INT >> 1, &matrix, extremes); + + picture = (cairo_xcb_picture_t *) + _cairo_xcb_screen_lookup_linear_picture (target->screen, pattern); + if (picture != NULL) + goto setup_picture; + + stops = _gradient_to_xcb (&pattern->base, &n_stops, buf, sizeof (buf)); + if (unlikely (stops == NULL)) + return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY); + + picture = _cairo_xcb_picture_create (target->screen, + target->screen->connection->standard_formats[CAIRO_FORMAT_ARGB32], + PIXMAN_a8r8g8b8, + -1, -1); + if (unlikely (picture->base.status)) { + if (stops != (xcb_render_fixed_t *) buf) + free (stops); + return picture; + } + picture->filter = CAIRO_FILTER_DEFAULT; + + colors = (xcb_render_color_t *) (stops + n_stops); + + p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x); + p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y); + p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x); + p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y); + + _cairo_xcb_connection_render_create_linear_gradient (target->connection, + picture->picture, + p1, p2, + n_stops, + stops, colors); + + if (stops != (xcb_render_fixed_t *) buf) + free (stops); + + status = _cairo_xcb_screen_store_linear_picture (target->screen, + pattern, + &picture->base); + if (unlikely (status)) { + cairo_surface_destroy (&picture->base); + return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status); + } + +setup_picture: + _cairo_xcb_picture_set_matrix (picture, &matrix, + pattern->base.base.filter, + extents->x + extents->width/2., + extents->y + extents->height/2.); + _cairo_xcb_picture_set_filter (picture, pattern->base.base.filter); + _cairo_xcb_picture_set_extend (picture, pattern->base.base.extend); + _cairo_xcb_picture_set_component_alpha (picture, + pattern->base.base.has_component_alpha); + + return picture; +} + +static cairo_xcb_picture_t * +_cairo_xcb_radial_picture (cairo_xcb_surface_t *target, + const cairo_radial_pattern_t *pattern, + const cairo_rectangle_int_t *extents) +{ + char buf[CAIRO_STACK_BUFFER_SIZE]; + xcb_render_fixed_t *stops; + xcb_render_color_t *colors; + xcb_render_pointfix_t p1, p2; + xcb_render_fixed_t r1, r2; + cairo_matrix_t matrix; + cairo_circle_double_t extremes[2]; + cairo_xcb_picture_t *picture; + cairo_status_t status; + unsigned int n_stops; + + _cairo_gradient_pattern_fit_to_range (&pattern->base, PIXMAN_MAX_INT >> 1, &matrix, extremes); + + picture = (cairo_xcb_picture_t *) + _cairo_xcb_screen_lookup_radial_picture (target->screen, pattern); + if (picture != NULL) + goto setup_picture; + + stops = _gradient_to_xcb (&pattern->base, &n_stops, buf, sizeof (buf)); + if (unlikely (stops == NULL)) + return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY); + + picture = _cairo_xcb_picture_create (target->screen, + target->screen->connection->standard_formats[CAIRO_FORMAT_ARGB32], + PIXMAN_a8r8g8b8, + -1, -1); + if (unlikely (picture->base.status)) { + if (stops != (xcb_render_fixed_t *) buf) + free (stops); + return picture; + } + picture->filter = CAIRO_FILTER_DEFAULT; + + colors = (xcb_render_color_t *) (stops + n_stops); + + p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x); + p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y); + p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x); + p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y); + + r1 = _cairo_fixed_16_16_from_double (extremes[0].radius); + r2 = _cairo_fixed_16_16_from_double (extremes[1].radius); + + _cairo_xcb_connection_render_create_radial_gradient (target->connection, + picture->picture, + p1, p2, r1, r2, + n_stops, + stops, colors); + + if (stops != (xcb_render_fixed_t *) buf) + free (stops); + + status = _cairo_xcb_screen_store_radial_picture (target->screen, + pattern, + &picture->base); + if (unlikely (status)) { + cairo_surface_destroy (&picture->base); + return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status); + } + +setup_picture: + _cairo_xcb_picture_set_matrix (picture, &matrix, + pattern->base.base.filter, + extents->x + extents->width/2., + extents->y + extents->height/2.); + _cairo_xcb_picture_set_filter (picture, pattern->base.base.filter); + _cairo_xcb_picture_set_extend (picture, pattern->base.base.extend); + _cairo_xcb_picture_set_component_alpha (picture, + pattern->base.base.has_component_alpha); + + return picture; +} + +static cairo_xcb_picture_t * +_copy_to_picture (cairo_xcb_surface_t *source) +{ + cairo_xcb_picture_t *picture; + uint32_t values[] = { 0, 1 }; + + if (source->deferred_clear) { + cairo_status_t status = _cairo_xcb_surface_clear (source); + if (unlikely (status)) + return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status); + } + + picture = _cairo_xcb_picture_create (source->screen, + source->xrender_format, + source->pixman_format, + source->width, + source->height); + if (unlikely (picture->base.status)) + return picture; + + _cairo_xcb_connection_render_create_picture (source->connection, + picture->picture, + source->drawable, + source->xrender_format, + XCB_RENDER_CP_GRAPHICS_EXPOSURE | + XCB_RENDER_CP_SUBWINDOW_MODE, + values); + + return picture; +} + +static void +_cairo_xcb_surface_setup_surface_picture(cairo_xcb_picture_t *picture, + const cairo_surface_pattern_t *pattern, + const cairo_rectangle_int_t *extents) +{ + cairo_filter_t filter; + + filter = pattern->base.filter; + if (filter != CAIRO_FILTER_NEAREST && + _cairo_matrix_is_pixel_exact (&pattern->base.matrix)) + { + filter = CAIRO_FILTER_NEAREST; + } + _cairo_xcb_picture_set_filter (picture, filter); + + _cairo_xcb_picture_set_matrix (picture, + &pattern->base.matrix, filter, + extents->x + extents->width/2., + extents->y + extents->height/2.); + + + _cairo_xcb_picture_set_extend (picture, pattern->base.extend); + _cairo_xcb_picture_set_component_alpha (picture, pattern->base.has_component_alpha); +} + +static cairo_xcb_picture_t * +record_to_picture (cairo_surface_t *target, + const cairo_surface_pattern_t *pattern, + const cairo_rectangle_int_t *extents) +{ + cairo_surface_pattern_t tmp_pattern; + cairo_xcb_picture_t *picture; + cairo_status_t status; + cairo_matrix_t matrix; + cairo_surface_t *tmp; + cairo_surface_t *source; + cairo_rectangle_int_t limit; + cairo_extend_t extend; + + /* XXX: The following was once more or less copied from cairo-xlibs-ource.c, + * record_source() and recording_pattern_get_surface(), can we share a + * single version? + */ + + /* First get the 'real' recording surface and figure out the size for tmp */ + source = _cairo_pattern_get_source (pattern, &limit); + assert (_cairo_surface_is_recording (source)); + + if (! _cairo_matrix_is_identity (&pattern->base.matrix)) { + double x1, y1, x2, y2; + + matrix = pattern->base.matrix; + status = cairo_matrix_invert (&matrix); + assert (status == CAIRO_STATUS_SUCCESS); + + x1 = limit.x; + y1 = limit.y; + x2 = limit.x + limit.width; + y2 = limit.y + limit.height; + + _cairo_matrix_transform_bounding_box (&matrix, + &x1, &y1, &x2, &y2, NULL); + + limit.x = floor (x1); + limit.y = floor (y1); + limit.width = ceil (x2) - limit.x; + limit.height = ceil (y2) - limit.y; + } + extend = pattern->base.extend; + if (_cairo_rectangle_contains_rectangle (&limit, extents)) + extend = CAIRO_EXTEND_NONE; + if (extend == CAIRO_EXTEND_NONE && ! _cairo_rectangle_intersect (&limit, extents)) + return _cairo_xcb_transparent_picture ((cairo_xcb_surface_t *) target); + + /* Now draw the recording surface to an xcb surface */ + tmp = _cairo_surface_create_scratch (target, + source->content, + limit.width, + limit.height, + CAIRO_COLOR_TRANSPARENT); + if (tmp->status != CAIRO_STATUS_SUCCESS) { + return (cairo_xcb_picture_t *) tmp; + } + + cairo_matrix_init_translate (&matrix, limit.x, limit.y); + cairo_matrix_multiply (&matrix, &matrix, &pattern->base.matrix); + + status = _cairo_recording_surface_replay_with_clip (source, + &matrix, tmp, + NULL); + if (unlikely (status)) { + cairo_surface_destroy (tmp); + return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status); + } + + /* Now that we have drawn this to an xcb surface, try again with that */ + _cairo_pattern_init_static_copy (&tmp_pattern.base, &pattern->base); + tmp_pattern.surface = tmp; + cairo_matrix_init_translate (&tmp_pattern.base.matrix, -limit.x, -limit.y); + + picture = _copy_to_picture ((cairo_xcb_surface_t *) tmp); + if (picture->base.status == CAIRO_STATUS_SUCCESS) + _cairo_xcb_surface_setup_surface_picture (picture, &tmp_pattern, extents); + cairo_surface_destroy (tmp); + return picture; +} + +static cairo_xcb_picture_t * +_cairo_xcb_surface_picture (cairo_xcb_surface_t *target, + const cairo_surface_pattern_t *pattern, + const cairo_rectangle_int_t *extents) +{ + cairo_surface_t *source = pattern->surface; + cairo_xcb_picture_t *picture; + + picture = (cairo_xcb_picture_t *) + _cairo_surface_has_snapshot (source, &_cairo_xcb_picture_backend); + if (picture != NULL) { + if (picture->screen == target->screen) { + picture = (cairo_xcb_picture_t *) cairo_surface_reference (&picture->base); + _cairo_xcb_surface_setup_surface_picture (picture, pattern, extents); + return picture; + } + picture = NULL; + } + + if (source->type == CAIRO_SURFACE_TYPE_XCB) + { + if (_cairo_surface_is_xcb(source)) { + cairo_xcb_surface_t *xcb = (cairo_xcb_surface_t *) source; + if (xcb->screen == target->screen && xcb->fallback == NULL) { + picture = _copy_to_picture ((cairo_xcb_surface_t *) source); + if (unlikely (picture->base.status)) + return picture; + } + } else if (source->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) { + cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source; + cairo_xcb_surface_t *xcb = (cairo_xcb_surface_t *) sub->target; + + /* XXX repeat interval with source clipping? */ + if (FALSE && xcb->screen == target->screen && xcb->fallback == NULL) { + xcb_rectangle_t rect; + + picture = _copy_to_picture (xcb); + if (unlikely (picture->base.status)) + return picture; + + rect.x = sub->extents.x; + rect.y = sub->extents.y; + rect.width = sub->extents.width; + rect.height = sub->extents.height; + + _cairo_xcb_connection_render_set_picture_clip_rectangles (xcb->connection, + picture->picture, + 0, 0, + 1, &rect); + picture->x0 = rect.x; + picture->y0 = rect.y; + picture->width = rect.width; + picture->height = rect.height; + } + } else if (_cairo_surface_is_snapshot (source)) { + cairo_surface_snapshot_t *snap = (cairo_surface_snapshot_t *) source; + cairo_xcb_surface_t *xcb = (cairo_xcb_surface_t *) snap->target; + + if (xcb->screen == target->screen && xcb->fallback == NULL) { + picture = _copy_to_picture (xcb); + if (unlikely (picture->base.status)) + return picture; + } + } + } +#if CAIRO_HAS_XLIB_XCB_FUNCTIONS + else if (source->type == CAIRO_SURFACE_TYPE_XLIB) + { + if (source->backend->type == CAIRO_SURFACE_TYPE_XLIB) { + cairo_xcb_surface_t *xcb = ((cairo_xlib_xcb_surface_t *) source)->xcb; + if (xcb->screen == target->screen && xcb->fallback == NULL) { + picture = _copy_to_picture (xcb); + if (unlikely (picture->base.status)) + return picture; + } + } else if (source->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) { + cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source; + cairo_xcb_surface_t *xcb = ((cairo_xlib_xcb_surface_t *) sub->target)->xcb; + + if (FALSE && xcb->screen == target->screen && xcb->fallback == NULL) { + xcb_rectangle_t rect; + + picture = _copy_to_picture (xcb); + if (unlikely (picture->base.status)) + return picture; + + rect.x = sub->extents.x; + rect.y = sub->extents.y; + rect.width = sub->extents.width; + rect.height = sub->extents.height; + + _cairo_xcb_connection_render_set_picture_clip_rectangles (xcb->connection, + picture->picture, + 0, 0, + 1, &rect); + picture->x0 = rect.x; + picture->y0 = rect.y; + picture->width = rect.width; + picture->height = rect.height; + } + } else if (_cairo_surface_is_snapshot (source)) { + cairo_surface_snapshot_t *snap = (cairo_surface_snapshot_t *) source; + cairo_xcb_surface_t *xcb = ((cairo_xlib_xcb_surface_t *) snap->target)->xcb; + + if (xcb->screen == target->screen && xcb->fallback == NULL) { + picture = _copy_to_picture (xcb); + if (unlikely (picture->base.status)) + return picture; + } + } + } +#endif + else if (source->type == CAIRO_SURFACE_TYPE_RECORDING) + { + /* We have to skip the call to attach_snapshot() because we possibly + * only drew part of the recording surface. + * TODO: When can we safely attach a snapshot? + */ + return record_to_picture(&target->base, pattern, extents); + } + + if (picture == NULL) { + cairo_image_surface_t *image; + void *image_extra; + cairo_status_t status; + + status = _cairo_surface_acquire_source_image (source, &image, &image_extra); + if (unlikely (status)) + return (cairo_xcb_picture_t *) _cairo_surface_create_in_error (status); + + if (image->format != CAIRO_FORMAT_INVALID && + image->format < ARRAY_LENGTH (target->screen->connection->standard_formats)) { + xcb_render_pictformat_t format; + + format = target->screen->connection->standard_formats[image->format]; + + picture = _picture_from_image (target, format, image, NULL); + _cairo_surface_release_source_image (source, image, image_extra); + } else { + cairo_image_surface_t *conv; + xcb_render_pictformat_t render_format; + + /* XXX XRenderPutImage! */ + + conv = _cairo_image_surface_coerce (image); + _cairo_surface_release_source_image (source, image, image_extra); + if (unlikely (conv->base.status)) + return (cairo_xcb_picture_t *) conv; + + render_format = target->screen->connection->standard_formats[conv->format]; + picture = _picture_from_image (target, render_format, conv, NULL); + cairo_surface_destroy (&conv->base); + } + + if (unlikely (picture->base.status)) + return picture; + } + + /* XXX: This causes too many problems and bugs, let's skip it for now. */ +#if 0 + _cairo_surface_attach_snapshot (source, + &picture->base, + NULL); +#endif + + _cairo_xcb_surface_setup_surface_picture (picture, pattern, extents); + return picture; +} + +static cairo_xcb_picture_t * +_cairo_xcb_picture_for_pattern (cairo_xcb_surface_t *target, + const cairo_pattern_t *pattern, + const cairo_rectangle_int_t *extents) +{ + if (pattern == NULL) + return _cairo_xcb_white_picture (target); + + if (! _pattern_is_supported (target->connection->flags, pattern)) + return _render_to_picture (target, pattern, extents); + + switch (pattern->type) { + case CAIRO_PATTERN_TYPE_SOLID: + return _cairo_xcb_solid_picture (target, (cairo_solid_pattern_t *) pattern); + + case CAIRO_PATTERN_TYPE_LINEAR: + return _cairo_xcb_linear_picture (target, + (cairo_linear_pattern_t *) pattern, + extents); + + case CAIRO_PATTERN_TYPE_RADIAL: + return _cairo_xcb_radial_picture (target, + (cairo_radial_pattern_t *) pattern, + extents); + + case CAIRO_PATTERN_TYPE_SURFACE: + return _cairo_xcb_surface_picture (target, + (cairo_surface_pattern_t *) pattern, + extents); + default: + ASSERT_NOT_REACHED; + case CAIRO_PATTERN_TYPE_MESH: + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + return _render_to_picture (target, pattern, extents); + } +} + +COMPILE_TIME_ASSERT (sizeof (xcb_rectangle_t) <= sizeof (cairo_box_t)); + +static cairo_status_t +_render_fill_boxes (void *abstract_dst, + cairo_operator_t op, + const cairo_color_t *color, + cairo_boxes_t *boxes) +{ + cairo_xcb_surface_t *dst = abstract_dst; + xcb_rectangle_t stack_xrects[CAIRO_STACK_ARRAY_LENGTH (xcb_rectangle_t)]; + xcb_rectangle_t *xrects = stack_xrects; + xcb_render_color_t render_color; + int render_op = _render_operator (op); + struct _cairo_boxes_chunk *chunk; + int max_count; + + render_color.red = color->red_short; + render_color.green = color->green_short; + render_color.blue = color->blue_short; + render_color.alpha = color->alpha_short; + + max_count = 0; + for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { + if (chunk->count > max_count) + max_count = chunk->count; + } + if (max_count > ARRAY_LENGTH (stack_xrects)) { + xrects = _cairo_malloc_ab (max_count, sizeof (xcb_rectangle_t)); + if (unlikely (xrects == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { + int i, j; + + for (i = j = 0; i < chunk->count; i++) { + int x1 = _cairo_fixed_integer_round_down (chunk->base[i].p1.x); + int y1 = _cairo_fixed_integer_round_down (chunk->base[i].p1.y); + int x2 = _cairo_fixed_integer_round_down (chunk->base[i].p2.x); + int y2 = _cairo_fixed_integer_round_down (chunk->base[i].p2.y); + + if (x2 > x1 && y2 > y1) { + xrects[j].x = x1; + xrects[j].y = y1; + xrects[j].width = x2 - x1; + xrects[j].height = y2 - y1; + j++; + } + } + + if (j) { + _cairo_xcb_connection_render_fill_rectangles + (dst->connection, + render_op, dst->picture, + render_color, j, xrects); + } + } + + if (xrects != stack_xrects) + free (xrects); + + return CAIRO_STATUS_SUCCESS; +} + +/* pixel aligned, non-overlapping boxes */ +static cairo_int_status_t +_render_composite_boxes (cairo_xcb_surface_t *dst, + cairo_operator_t op, + const cairo_pattern_t *src_pattern, + const cairo_pattern_t *mask_pattern, + const cairo_rectangle_int_t *extents, + const cairo_boxes_t *boxes) +{ + cairo_xcb_picture_t *src, *mask; + const struct _cairo_boxes_chunk *chunk; + xcb_rectangle_t stack_boxes[CAIRO_STACK_ARRAY_LENGTH (xcb_rectangle_t)]; + xcb_rectangle_t *clip_boxes; + cairo_rectangle_int_t stack_extents; + cairo_status_t status; + int num_boxes; + int render_op; + + render_op = _render_operator (op); + + if (src_pattern == NULL) { + src_pattern = mask_pattern; + mask_pattern = NULL; + } + + /* amalgamate into a single Composite call by setting a clip region */ + clip_boxes = stack_boxes; + if (boxes->num_boxes > ARRAY_LENGTH (stack_boxes)) { + clip_boxes = _cairo_malloc_ab (boxes->num_boxes, sizeof (xcb_rectangle_t)); + if (unlikely (clip_boxes == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + src = _cairo_xcb_picture_for_pattern (dst, src_pattern, extents); + status = src->base.status; + if (unlikely (status)) + goto cleanup_boxes; + + num_boxes = 0; + for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { + const cairo_box_t *box = chunk->base; + int i; + + for (i = 0; i < chunk->count; i++) { + int x = _cairo_fixed_integer_round_down (box[i].p1.x); + int y = _cairo_fixed_integer_round_down (box[i].p1.y); + int width = _cairo_fixed_integer_round_down (box[i].p2.x) - x; + int height = _cairo_fixed_integer_round_down (box[i].p2.y) - y; + + if (width && height) { + clip_boxes[num_boxes].x = x; + clip_boxes[num_boxes].y = y; + clip_boxes[num_boxes].width = width; + clip_boxes[num_boxes].height = height; + num_boxes++; + } + } + } + + if (num_boxes) { + if (num_boxes > 1) { + _cairo_xcb_connection_render_set_picture_clip_rectangles (dst->connection, + dst->picture, + 0, 0, + num_boxes, + clip_boxes); + } else { + stack_extents.x = clip_boxes[0].x; + stack_extents.y = clip_boxes[0].y; + stack_extents.width = clip_boxes[0].width; + stack_extents.height = clip_boxes[0].height; + extents = &stack_extents; + } + + if (mask_pattern != NULL) { + mask = _cairo_xcb_picture_for_pattern (dst, mask_pattern, extents); + status = mask->base.status; + if (unlikely (status)) + goto cleanup_clip; + + _cairo_xcb_connection_render_composite (dst->connection, + render_op, + src->picture, + mask->picture, + dst->picture, + src->x + extents->x, src->y + extents->y, + mask->x + extents->x, mask->y + extents->y, + extents->x, extents->y, + extents->width, extents->height); + + cairo_surface_destroy (&mask->base); + } else { + _cairo_xcb_connection_render_composite (dst->connection, + render_op, + src->picture, + XCB_NONE, + dst->picture, + src->x + extents->x, src->y + extents->y, + 0, 0, + extents->x, extents->y, + extents->width, extents->height); + } + +cleanup_clip: + + if (num_boxes > 1) + _cairo_xcb_surface_clear_clip_region (dst); + } + + cairo_surface_destroy (&src->base); + +cleanup_boxes: + + if (clip_boxes != stack_boxes) + free (clip_boxes); + + return status; +} + + +#define CAIRO_FIXED_16_16_MIN _cairo_fixed_from_int (-32768) +#define CAIRO_FIXED_16_16_MAX _cairo_fixed_from_int (32767) + +static cairo_bool_t +_line_exceeds_16_16 (const cairo_line_t *line) +{ + return + line->p1.x <= CAIRO_FIXED_16_16_MIN || + line->p1.x >= CAIRO_FIXED_16_16_MAX || + + line->p2.x <= CAIRO_FIXED_16_16_MIN || + line->p2.x >= CAIRO_FIXED_16_16_MAX || + + line->p1.y <= CAIRO_FIXED_16_16_MIN || + line->p1.y >= CAIRO_FIXED_16_16_MAX || + + line->p2.y <= CAIRO_FIXED_16_16_MIN || + line->p2.y >= CAIRO_FIXED_16_16_MAX; +} + +static void +_project_line_x_onto_16_16 (const cairo_line_t *line, + cairo_fixed_t top, + cairo_fixed_t bottom, + xcb_render_linefix_t *out) +{ + cairo_point_double_t p1, p2; + double m; + + p1.x = _cairo_fixed_to_double (line->p1.x); + p1.y = _cairo_fixed_to_double (line->p1.y); + + p2.x = _cairo_fixed_to_double (line->p2.x); + p2.y = _cairo_fixed_to_double (line->p2.y); + + m = (p2.x - p1.x) / (p2.y - p1.y); + out->p1.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (top - line->p1.y)); + out->p2.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (bottom - line->p1.y)); +} + +typedef struct { + cairo_traps_t traps; + cairo_antialias_t antialias; +} composite_traps_info_t; + +COMPILE_TIME_ASSERT (sizeof (xcb_render_trapezoid_t) <= sizeof (cairo_trapezoid_t)); + +static cairo_int_status_t +_composite_traps (void *closure, + cairo_xcb_surface_t *dst, + cairo_operator_t op, + const cairo_pattern_t *pattern, + int dst_x, int dst_y, + const cairo_rectangle_int_t *extents, + cairo_clip_t *clip) +{ + composite_traps_info_t *info = closure; + const cairo_traps_t *traps = &info->traps; + cairo_xcb_picture_t *src; + cairo_format_t format; + xcb_render_pictformat_t xrender_format; + xcb_render_trapezoid_t *xtraps; + int render_reference_x, render_reference_y; + cairo_status_t status; + int i; + + if (dst->deferred_clear) { + status = _cairo_xcb_surface_clear (dst); + if (unlikely (status)) + return status; + } + + src = _cairo_xcb_picture_for_pattern (dst, pattern, extents); + if (unlikely (src->base.status)) + return src->base.status; + + if (info->antialias == CAIRO_ANTIALIAS_NONE) + format = CAIRO_FORMAT_A1; + else + format = CAIRO_FORMAT_A8; + xrender_format = dst->screen->connection->standard_formats[format]; + + xtraps = (xcb_render_trapezoid_t *) traps->traps; + for (i = 0; i < traps->num_traps; i++) { + cairo_trapezoid_t t = traps->traps[i]; + + /* top/bottom will be clamped to surface bounds */ + xtraps[i].top = _cairo_fixed_to_16_16 (t.top); + xtraps[i].top -= dst_y << 16; + xtraps[i].bottom = _cairo_fixed_to_16_16 (t.bottom); + xtraps[i].bottom -= dst_y << 16; + + /* However, all the other coordinates will have been left untouched so + * as not to introduce numerical error. Recompute them if they + * exceed the 16.16 limits. + */ + if (unlikely (_line_exceeds_16_16 (&t.left))) { + _project_line_x_onto_16_16 (&t.left, + t.top, + t.bottom, + &xtraps[i].left); + xtraps[i].left.p1.y = xtraps[i].top; + xtraps[i].left.p2.y = xtraps[i].bottom; + } else { + xtraps[i].left.p1.x = _cairo_fixed_to_16_16 (t.left.p1.x); + xtraps[i].left.p1.y = _cairo_fixed_to_16_16 (t.left.p1.y); + xtraps[i].left.p2.x = _cairo_fixed_to_16_16 (t.left.p2.x); + xtraps[i].left.p2.y = _cairo_fixed_to_16_16 (t.left.p2.y); + } + xtraps[i].left.p1.x -= dst_x << 16; + xtraps[i].left.p1.y -= dst_y << 16; + xtraps[i].left.p2.x -= dst_x << 16; + xtraps[i].left.p2.y -= dst_y << 16; + + if (unlikely (_line_exceeds_16_16 (&t.right))) { + _project_line_x_onto_16_16 (&t.right, + t.top, + t.bottom, + &xtraps[i].right); + xtraps[i].right.p1.y = xtraps[i].top; + xtraps[i].right.p2.y = xtraps[i].bottom; + } else { + xtraps[i].right.p1.x = _cairo_fixed_to_16_16 (t.right.p1.x); + xtraps[i].right.p1.y = _cairo_fixed_to_16_16 (t.right.p1.y); + xtraps[i].right.p2.x = _cairo_fixed_to_16_16 (t.right.p2.x); + xtraps[i].right.p2.y = _cairo_fixed_to_16_16 (t.right.p2.y); + } + xtraps[i].right.p1.x -= dst_x << 16; + xtraps[i].right.p1.y -= dst_y << 16; + xtraps[i].right.p2.x -= dst_x << 16; + xtraps[i].right.p2.y -= dst_y << 16; + } + + if (xtraps[0].left.p1.y < xtraps[0].left.p2.y) { + render_reference_x = xtraps[0].left.p1.x >> 16; + render_reference_y = xtraps[0].left.p1.y >> 16; + } else { + render_reference_x = xtraps[0].left.p2.x >> 16; + render_reference_y = xtraps[0].left.p2.y >> 16; + } + render_reference_x += src->x + dst_x; + render_reference_y += src->y + dst_y; + + _cairo_xcb_surface_set_precision (dst, info->antialias); + _cairo_xcb_connection_render_trapezoids (dst->connection, + _render_operator (op), + src->picture, + dst->picture, + xrender_format, + render_reference_x, + render_reference_y, + traps->num_traps, xtraps); + + cairo_surface_destroy (&src->base); + + return CAIRO_STATUS_SUCCESS; +} + +/* low-level composite driver */ + +static cairo_xcb_surface_t * +get_clip_surface (const cairo_clip_t *clip, + cairo_xcb_surface_t *target, + int *tx, int *ty) +{ + cairo_surface_t *surface; + cairo_status_t status; + + surface = _cairo_surface_create_scratch (&target->base, + CAIRO_CONTENT_ALPHA, + clip->extents.width, + clip->extents.height, + CAIRO_COLOR_WHITE); + if (unlikely (surface->status)) + return (cairo_xcb_surface_t *) surface; + + assert (surface->backend == &_cairo_xcb_surface_backend); + status = _cairo_clip_combine_with_surface (clip, surface, + clip->extents.x, clip->extents.y); + if (unlikely (status)) { + cairo_surface_destroy (surface); + surface = _cairo_surface_create_in_error (status); + } + + *tx = clip->extents.x; + *ty = clip->extents.y; + + return (cairo_xcb_surface_t *) surface; +} + +typedef cairo_int_status_t +(*xcb_draw_func_t) (void *closure, + cairo_xcb_surface_t *dst, + cairo_operator_t op, + const cairo_pattern_t *src, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents, + cairo_clip_t *clip); + +static void do_unaligned_row(void (*blt)(void *closure, + int16_t x, int16_t y, + int16_t w, int16_t h, + uint16_t coverage), + void *closure, + const cairo_box_t *b, + int tx, int y, int h, + uint16_t coverage) +{ + int x1 = _cairo_fixed_integer_part (b->p1.x) - tx; + int x2 = _cairo_fixed_integer_part (b->p2.x) - tx; + if (x2 > x1) { + if (! _cairo_fixed_is_integer (b->p1.x)) { + blt(closure, x1, y, 1, h, + coverage * (256 - _cairo_fixed_fractional_part (b->p1.x))); + x1++; + } + + if (x2 > x1) + blt(closure, x1, y, x2-x1, h, (coverage << 8) - (coverage >> 8)); + + if (! _cairo_fixed_is_integer (b->p2.x)) + blt(closure, x2, y, 1, h, + coverage * _cairo_fixed_fractional_part (b->p2.x)); + } else + blt(closure, x1, y, 1, h, + coverage * (b->p2.x - b->p1.x)); +} + +static void do_unaligned_box(void (*blt)(void *closure, + int16_t x, int16_t y, + int16_t w, int16_t h, + uint16_t coverage), + void *closure, + const cairo_box_t *b, int tx, int ty) +{ + int y1 = _cairo_fixed_integer_part (b->p1.y) - ty; + int y2 = _cairo_fixed_integer_part (b->p2.y) - ty; + if (y2 > y1) { + if (! _cairo_fixed_is_integer (b->p1.y)) { + do_unaligned_row(blt, closure, b, tx, y1, 1, + 256 - _cairo_fixed_fractional_part (b->p1.y)); + y1++; + } + + if (y2 > y1) + do_unaligned_row(blt, closure, b, tx, y1, y2-y1, 256); + + if (! _cairo_fixed_is_integer (b->p2.y)) + do_unaligned_row(blt, closure, b, tx, y2, 1, + _cairo_fixed_fractional_part (b->p2.y)); + } else + do_unaligned_row(blt, closure, b, tx, y1, 1, + b->p2.y - b->p1.y); +} + + +static void blt_in(void *closure, + int16_t x, int16_t y, + int16_t w, int16_t h, + uint16_t coverage) +{ + cairo_xcb_surface_t *mask = closure; + xcb_render_color_t color; + xcb_rectangle_t rect; + + if (coverage == 0xffff) + return; + + color.red = color.green = color.blue = 0; + color.alpha = coverage; + + rect.x = x; + rect.y = y; + rect.width = w; + rect.height = h; + + _cairo_xcb_connection_render_fill_rectangles (mask->connection, + XCB_RENDER_PICT_OP_IN, + mask->picture, + color, 1, &rect); +} + +static cairo_xcb_surface_t * +_create_composite_mask (cairo_clip_t *clip, + xcb_draw_func_t draw_func, + xcb_draw_func_t mask_func, + void *draw_closure, + cairo_xcb_surface_t *dst, + const cairo_rectangle_int_t*extents) +{ + cairo_xcb_surface_t *surface; + cairo_bool_t need_clip_combine; + cairo_int_status_t status; + + surface = (cairo_xcb_surface_t *) + _cairo_xcb_surface_create_similar (dst, CAIRO_CONTENT_ALPHA, + extents->width, extents->height); + if (unlikely (surface->base.status)) + return surface; + + _cairo_xcb_surface_ensure_picture (surface); + + surface->deferred_clear_color = *CAIRO_COLOR_TRANSPARENT; + surface->deferred_clear = TRUE; + surface->base.is_clear = TRUE; + + if (mask_func) { + status = mask_func (draw_closure, surface, + CAIRO_OPERATOR_ADD, NULL, + extents->x, extents->y, + extents, clip); + if (likely (status != CAIRO_INT_STATUS_UNSUPPORTED)) + return surface; + } + + /* Is it worth setting the clip region here? */ + status = draw_func (draw_closure, surface, + CAIRO_OPERATOR_ADD, NULL, + extents->x, extents->y, + extents, NULL); + if (unlikely (status)) { + cairo_surface_destroy (&surface->base); + return (cairo_xcb_surface_t *) _cairo_surface_create_in_error (status); + } + + if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES) { + int i; + + for (i = 0; i < clip->num_boxes; i++) { + cairo_box_t *b = &clip->boxes[i]; + + if (! _cairo_fixed_is_integer (b->p1.x) || + ! _cairo_fixed_is_integer (b->p1.y) || + ! _cairo_fixed_is_integer (b->p2.x) || + ! _cairo_fixed_is_integer (b->p2.y)) + { + do_unaligned_box(blt_in, surface, b, extents->x, extents->y); + } + } + + need_clip_combine = clip->path != NULL; + } else + need_clip_combine = ! _cairo_clip_is_region (clip); + + if (need_clip_combine) { + status = _cairo_clip_combine_with_surface (clip, &surface->base, + extents->x, extents->y); + if (unlikely (status)) { + cairo_surface_destroy (&surface->base); + return (cairo_xcb_surface_t *) _cairo_surface_create_in_error (status); + } + } + + return surface; +} + +/* Handles compositing with a clip surface when the operator allows + * us to combine the clip with the mask + */ +static cairo_status_t +_clip_and_composite_with_mask (cairo_clip_t *clip, + cairo_operator_t op, + const cairo_pattern_t *pattern, + xcb_draw_func_t draw_func, + xcb_draw_func_t mask_func, + void *draw_closure, + cairo_xcb_surface_t *dst, + const cairo_rectangle_int_t*extents) +{ + cairo_xcb_surface_t *mask; + cairo_xcb_picture_t *src; + + mask = _create_composite_mask (clip, + draw_func, mask_func, draw_closure, + dst, extents); + if (unlikely (mask->base.status)) + return mask->base.status; + + if (pattern != NULL || dst->base.content != CAIRO_CONTENT_ALPHA) { + src = _cairo_xcb_picture_for_pattern (dst, pattern, extents); + if (unlikely (src->base.status)) { + cairo_surface_destroy (&mask->base); + return src->base.status; + } + + _cairo_xcb_connection_render_composite (dst->connection, + _render_operator (op), + src->picture, + mask->picture, + dst->picture, + extents->x + src->x, extents->y + src->y, + 0, 0, + extents->x, extents->y, + extents->width, extents->height); + + cairo_surface_destroy (&src->base); + } else { + _cairo_xcb_connection_render_composite (dst->connection, + _render_operator (op), + mask->picture, + XCB_NONE, + dst->picture, + 0, 0, + 0, 0, + extents->x, extents->y, + extents->width, extents->height); + } + cairo_surface_destroy (&mask->base); + + return CAIRO_STATUS_SUCCESS; +} + +/* Handles compositing with a clip surface when we have to do the operation + * in two pieces and combine them together. + */ +static cairo_status_t +_clip_and_composite_combine (cairo_clip_t *clip, + cairo_operator_t op, + const cairo_pattern_t *pattern, + xcb_draw_func_t draw_func, + void *draw_closure, + cairo_xcb_surface_t *dst, + const cairo_rectangle_int_t*extents) +{ + cairo_xcb_surface_t *tmp; + cairo_xcb_surface_t *clip_surface; + int clip_x = 0, clip_y = 0; + xcb_render_picture_t clip_picture; + cairo_status_t status; + + tmp = (cairo_xcb_surface_t *) + _cairo_xcb_surface_create_similar (dst, dst->base.content, + extents->width, extents->height); + if (unlikely (tmp->base.status)) + return tmp->base.status; + + /* create_similar() could have done a fallback to an image surface */ + assert (tmp->base.backend == &_cairo_xcb_surface_backend); + + _cairo_xcb_surface_ensure_picture (tmp); + + if (pattern == NULL) { + status = (*draw_func) (draw_closure, tmp, + CAIRO_OPERATOR_ADD, NULL, + extents->x, extents->y, + extents, NULL); + } else { + /* Initialize the temporary surface from the destination surface */ + if (! dst->base.is_clear || + (dst->connection->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES) == 0) + { + /* XCopyArea may actually be quicker here. + * A good driver should translate if appropriate. + */ + _cairo_xcb_connection_render_composite (dst->connection, + XCB_RENDER_PICT_OP_SRC, + dst->picture, + XCB_NONE, + tmp->picture, + extents->x, extents->y, + 0, 0, + 0, 0, + extents->width, extents->height); + } + else + { + xcb_render_color_t clear; + xcb_rectangle_t xrect; + + clear.red = clear.green = clear.blue = clear.alpha = 0; + + xrect.x = xrect.y = 0; + xrect.width = extents->width; + xrect.height = extents->height; + + _cairo_xcb_connection_render_fill_rectangles (dst->connection, + XCB_RENDER_PICT_OP_CLEAR, + dst->picture, + clear, 1, &xrect); + } + + status = (*draw_func) (draw_closure, tmp, op, pattern, + extents->x, extents->y, + extents, NULL); + } + if (unlikely (status)) + goto CLEANUP_SURFACE; + + clip_surface = get_clip_surface (clip, dst, &clip_x, &clip_y); + status = clip_surface->base.status; + if (unlikely (status)) + goto CLEANUP_SURFACE; + + assert (clip_surface->base.backend == &_cairo_xcb_surface_backend); + clip_picture = clip_surface->picture; + assert (clip_picture != XCB_NONE); + + if (dst->base.is_clear) { + _cairo_xcb_connection_render_composite (dst->connection, + XCB_RENDER_PICT_OP_SRC, + tmp->picture, clip_picture, dst->picture, + 0, 0, + 0, 0, + extents->x, extents->y, + extents->width, extents->height); + } else { + /* Punch the clip out of the destination */ + _cairo_xcb_connection_render_composite (dst->connection, + XCB_RENDER_PICT_OP_OUT_REVERSE, + clip_picture, XCB_NONE, dst->picture, + extents->x - clip_x, + extents->y - clip_y, + 0, 0, + extents->x, extents->y, + extents->width, extents->height); + + /* Now add the two results together */ + _cairo_xcb_connection_render_composite (dst->connection, + XCB_RENDER_PICT_OP_ADD, + tmp->picture, clip_picture, dst->picture, + 0, 0, + extents->x - clip_x, + extents->y - clip_y, + extents->x, extents->y, + extents->width, extents->height); + } + cairo_surface_destroy (&clip_surface->base); + + CLEANUP_SURFACE: + cairo_surface_destroy (&tmp->base); + + return status; +} + +/* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's + * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip)) + */ +static cairo_status_t +_clip_and_composite_source (cairo_clip_t *clip, + const cairo_pattern_t *pattern, + xcb_draw_func_t draw_func, + xcb_draw_func_t mask_func, + void *draw_closure, + cairo_xcb_surface_t *dst, + const cairo_rectangle_int_t *extents) +{ + cairo_xcb_surface_t *mask; + cairo_xcb_picture_t *src; + + /* Create a surface that is mask IN clip */ + mask = _create_composite_mask (clip, + draw_func, mask_func, draw_closure, + dst, extents); + if (unlikely (mask->base.status)) + return mask->base.status; + + src = _cairo_xcb_picture_for_pattern (dst, pattern, extents); + if (unlikely (src->base.status)) { + cairo_surface_destroy (&mask->base); + return src->base.status; + } + + if (dst->base.is_clear) { + _cairo_xcb_connection_render_composite (dst->connection, + XCB_RENDER_PICT_OP_SRC, + src->picture, + mask->picture, + dst->picture, + extents->x + src->x, extents->y + src->y, + 0, 0, + extents->x, extents->y, + extents->width, extents->height); + } else { + /* Compute dest' = dest OUT (mask IN clip) */ + _cairo_xcb_connection_render_composite (dst->connection, + XCB_RENDER_PICT_OP_OUT_REVERSE, + mask->picture, + XCB_NONE, + dst->picture, + 0, 0, 0, 0, + extents->x, extents->y, + extents->width, extents->height); + + /* Now compute (src IN (mask IN clip)) ADD dest' */ + _cairo_xcb_connection_render_composite (dst->connection, + XCB_RENDER_PICT_OP_ADD, + src->picture, + mask->picture, + dst->picture, + extents->x + src->x, extents->y + src->y, + 0, 0, + extents->x, extents->y, + extents->width, extents->height); + } + + cairo_surface_destroy (&src->base); + cairo_surface_destroy (&mask->base); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_bool_t +can_reduce_alpha_op (cairo_operator_t op) +{ + int iop = op; + switch (iop) { + case CAIRO_OPERATOR_OVER: + case CAIRO_OPERATOR_SOURCE: + case CAIRO_OPERATOR_ADD: + return TRUE; + default: + return FALSE; + } +} + +static cairo_bool_t +reduce_alpha_op (cairo_surface_t *dst, + cairo_operator_t op, + const cairo_pattern_t *pattern) +{ + return dst->is_clear && + dst->content == CAIRO_CONTENT_ALPHA && + _cairo_pattern_is_opaque_solid (pattern) && + can_reduce_alpha_op (op); +} + +static cairo_status_t +_cairo_xcb_surface_fixup_unbounded (cairo_xcb_surface_t *dst, + const cairo_composite_rectangles_t *rects) +{ + xcb_rectangle_t xrects[4]; + int n; + + if (rects->bounded.width == rects->unbounded.width && + rects->bounded.height == rects->unbounded.height) + { + return CAIRO_STATUS_SUCCESS; + } + + n = 0; + if (rects->bounded.width == 0 || rects->bounded.height == 0) { + xrects[n].x = rects->unbounded.x; + xrects[n].width = rects->unbounded.width; + xrects[n].y = rects->unbounded.y; + xrects[n].height = rects->unbounded.height; + n++; + } else { + /* top */ + if (rects->bounded.y != rects->unbounded.y) { + xrects[n].x = rects->unbounded.x; + xrects[n].width = rects->unbounded.width; + xrects[n].y = rects->unbounded.y; + xrects[n].height = rects->bounded.y - rects->unbounded.y; + n++; + } + /* left */ + if (rects->bounded.x != rects->unbounded.x) { + xrects[n].x = rects->unbounded.x; + xrects[n].width = rects->bounded.x - rects->unbounded.x; + xrects[n].y = rects->bounded.y; + xrects[n].height = rects->bounded.height; + n++; + } + /* right */ + if (rects->bounded.x + rects->bounded.width != rects->unbounded.x + rects->unbounded.width) { + xrects[n].x = rects->bounded.x + rects->bounded.width; + xrects[n].width = rects->unbounded.x + rects->unbounded.width - xrects[n].x; + xrects[n].y = rects->bounded.y; + xrects[n].height = rects->bounded.height; + n++; + } + /* bottom */ + if (rects->bounded.y + rects->bounded.height != rects->unbounded.y + rects->unbounded.height) { + xrects[n].x = rects->unbounded.x; + xrects[n].width = rects->unbounded.width; + xrects[n].y = rects->bounded.y + rects->bounded.height; + xrects[n].height = rects->unbounded.y + rects->unbounded.height - xrects[n].y; + n++; + } + } + + if (dst->connection->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES) { + xcb_render_color_t color; + + color.red = 0; + color.green = 0; + color.blue = 0; + color.alpha = 0; + + _cairo_xcb_connection_render_fill_rectangles (dst->connection, + XCB_RENDER_PICT_OP_CLEAR, + dst->picture, + color, n, xrects); + } else { + int i; + cairo_xcb_picture_t *src; + + src = _cairo_xcb_transparent_picture (dst); + if (unlikely (src->base.status)) + return src->base.status; + + for (i = 0; i < n; i++) { + _cairo_xcb_connection_render_composite (dst->connection, + XCB_RENDER_PICT_OP_CLEAR, + src->picture, XCB_NONE, dst->picture, + 0, 0, + 0, 0, + xrects[i].x, xrects[i].y, + xrects[i].width, xrects[i].height); + } + cairo_surface_destroy (&src->base); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_xcb_surface_fixup_unbounded_with_mask (cairo_xcb_surface_t *dst, + const cairo_composite_rectangles_t *rects, + cairo_clip_t *clip) +{ + cairo_xcb_surface_t *mask; + int mask_x = 0, mask_y = 0; + + mask = get_clip_surface (clip, dst, &mask_x, &mask_y); + if (unlikely (mask->base.status)) + return mask->base.status; + + /* top */ + if (rects->bounded.y != rects->unbounded.y) { + int x = rects->unbounded.x; + int y = rects->unbounded.y; + int width = rects->unbounded.width; + int height = rects->bounded.y - y; + + _cairo_xcb_connection_render_composite (dst->connection, + XCB_RENDER_PICT_OP_OUT_REVERSE, + mask->picture, XCB_NONE, dst->picture, + x - mask_x, y - mask_y, + 0, 0, + x, y, + width, height); + } + + /* left */ + if (rects->bounded.x != rects->unbounded.x) { + int x = rects->unbounded.x; + int y = rects->bounded.y; + int width = rects->bounded.x - x; + int height = rects->bounded.height; + + _cairo_xcb_connection_render_composite (dst->connection, + XCB_RENDER_PICT_OP_OUT_REVERSE, + mask->picture, XCB_NONE, dst->picture, + x - mask_x, y - mask_y, + 0, 0, + x, y, + width, height); + } + + /* right */ + if (rects->bounded.x + rects->bounded.width != rects->unbounded.x + rects->unbounded.width) { + int x = rects->bounded.x + rects->bounded.width; + int y = rects->bounded.y; + int width = rects->unbounded.x + rects->unbounded.width - x; + int height = rects->bounded.height; + + _cairo_xcb_connection_render_composite (dst->connection, + XCB_RENDER_PICT_OP_OUT_REVERSE, + mask->picture, XCB_NONE, dst->picture, + x - mask_x, y - mask_y, + 0, 0, + x, y, + width, height); + } + + /* bottom */ + if (rects->bounded.y + rects->bounded.height != rects->unbounded.y + rects->unbounded.height) { + int x = rects->unbounded.x; + int y = rects->bounded.y + rects->bounded.height; + int width = rects->unbounded.width; + int height = rects->unbounded.y + rects->unbounded.height - y; + + _cairo_xcb_connection_render_composite (dst->connection, + XCB_RENDER_PICT_OP_OUT_REVERSE, + mask->picture, XCB_NONE, dst->picture, + x - mask_x, y - mask_y, + 0, 0, + x, y, + width, height); + } + + cairo_surface_destroy (&mask->base); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_xcb_surface_fixup_unbounded_boxes (cairo_xcb_surface_t *dst, + const cairo_composite_rectangles_t *extents, + cairo_clip_t *clip, + cairo_boxes_t *boxes) +{ + cairo_boxes_t clear; + cairo_box_t box; + cairo_status_t status; + struct _cairo_boxes_chunk *chunk; + int i; + + if (boxes->num_boxes <= 1 && clip == NULL) + return _cairo_xcb_surface_fixup_unbounded (dst, extents); + + _cairo_boxes_init (&clear); + + box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width); + box.p1.y = _cairo_fixed_from_int (extents->unbounded.y); + box.p2.x = _cairo_fixed_from_int (extents->unbounded.x); + box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height); + + if (clip == NULL) { + cairo_boxes_t tmp; + + _cairo_boxes_init (&tmp); + + status = _cairo_boxes_add (&tmp, CAIRO_ANTIALIAS_DEFAULT, &box); + assert (status == CAIRO_STATUS_SUCCESS); + + tmp.chunks.next = &boxes->chunks; + tmp.num_boxes += boxes->num_boxes; + + status = _cairo_bentley_ottmann_tessellate_boxes (&tmp, + CAIRO_FILL_RULE_WINDING, + &clear); + + tmp.chunks.next = NULL; + } else { + _cairo_boxes_init_with_clip (&clear, clip); + + status = _cairo_boxes_add (&clear, CAIRO_ANTIALIAS_DEFAULT, &box); + assert (status == CAIRO_STATUS_SUCCESS); + + for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { + for (i = 0; i < chunk->count; i++) { + status = _cairo_boxes_add (&clear, + CAIRO_ANTIALIAS_DEFAULT, + &chunk->base[i]); + if (unlikely (status)) { + _cairo_boxes_fini (&clear); + return status; + } + } + } + + status = _cairo_bentley_ottmann_tessellate_boxes (&clear, + CAIRO_FILL_RULE_WINDING, + &clear); + } + + if (likely (status == CAIRO_STATUS_SUCCESS)) { + if (dst->connection->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES) + status = _render_fill_boxes (dst, + CAIRO_OPERATOR_CLEAR, + CAIRO_COLOR_TRANSPARENT, + &clear); + else + status = _cairo_xcb_surface_core_fill_boxes (dst, + CAIRO_COLOR_TRANSPARENT, + &clear); + } + + _cairo_boxes_fini (&clear); + + return status; +} + +cairo_status_t +_cairo_xcb_surface_clear (cairo_xcb_surface_t *dst) +{ + xcb_gcontext_t gc; + xcb_rectangle_t rect; + cairo_status_t status; + + status = _cairo_xcb_connection_acquire (dst->connection); + if (unlikely (status)) + return status; + + rect.x = rect.y = 0; + rect.width = dst->width; + rect.height = dst->height; + + if (dst->connection->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES) { + xcb_render_color_t color; + uint8_t op; + + color.red = dst->deferred_clear_color.red_short; + color.green = dst->deferred_clear_color.green_short; + color.blue = dst->deferred_clear_color.blue_short; + color.alpha = dst->deferred_clear_color.alpha_short; + + if (color.alpha == 0) + op = XCB_RENDER_PICT_OP_CLEAR; + else + op = XCB_RENDER_PICT_OP_SRC; + + _cairo_xcb_surface_ensure_picture (dst); + _cairo_xcb_connection_render_fill_rectangles (dst->connection, + op, dst->picture, color, + 1, &rect); + } else { + gc = _cairo_xcb_screen_get_gc (dst->screen, dst->drawable, dst->depth); + + /* XXX color */ + _cairo_xcb_connection_poly_fill_rectangle (dst->connection, + dst->drawable, gc, + 1, &rect); + + _cairo_xcb_screen_put_gc (dst->screen, dst->depth, gc); + } + + _cairo_xcb_connection_release (dst->connection); + + dst->deferred_clear = FALSE; + return CAIRO_STATUS_SUCCESS; +} + +enum { + NEED_CLIP_REGION = 0x1, + NEED_CLIP_SURFACE = 0x2, + FORCE_CLIP_REGION = 0x4, +}; + +static cairo_bool_t +need_bounded_clip (cairo_composite_rectangles_t *extents) +{ + unsigned int flags = NEED_CLIP_REGION; + if (! _cairo_clip_is_region (extents->clip)) + flags |= NEED_CLIP_SURFACE; + return flags; +} + +static cairo_bool_t +need_unbounded_clip (cairo_composite_rectangles_t *extents) +{ + unsigned int flags = 0; + if (! extents->is_bounded) { + flags |= NEED_CLIP_REGION; + if (! _cairo_clip_is_region (extents->clip)) + flags |= NEED_CLIP_SURFACE; + } + if (extents->clip->path != NULL) + flags |= NEED_CLIP_SURFACE; + return flags; +} + +static cairo_status_t +_clip_and_composite (cairo_xcb_surface_t *dst, + cairo_operator_t op, + const cairo_pattern_t *src, + xcb_draw_func_t draw_func, + xcb_draw_func_t mask_func, + void *draw_closure, + cairo_composite_rectangles_t*extents, + unsigned int need_clip) +{ + cairo_region_t *clip_region = NULL; + cairo_status_t status; + + status = _cairo_xcb_connection_acquire (dst->connection); + if (unlikely (status)) + return status; + + if (dst->deferred_clear) { + status = _cairo_xcb_surface_clear (dst); + if (unlikely (status)) { + _cairo_xcb_connection_release (dst->connection); + return status; + } + } + + _cairo_xcb_surface_ensure_picture (dst); + + if (need_clip & NEED_CLIP_REGION) { + clip_region = _cairo_clip_get_region (extents->clip); + if ((need_clip & FORCE_CLIP_REGION) == 0 && clip_region != NULL && + cairo_region_contains_rectangle (clip_region, + &extents->unbounded) == CAIRO_REGION_OVERLAP_IN) + clip_region = NULL; + if (clip_region != NULL) { + status = _cairo_xcb_surface_set_clip_region (dst, clip_region); + if (unlikely (status)) { + _cairo_xcb_connection_release (dst->connection); + return status; + } + } + } + + if (reduce_alpha_op (&dst->base, op, src)) { + op = CAIRO_OPERATOR_ADD; + src = NULL; + } + + if (extents->bounded.width != 0 && extents->bounded.height != 0) { + if (op == CAIRO_OPERATOR_SOURCE) { + status = _clip_and_composite_source (extents->clip, src, + draw_func, mask_func, draw_closure, + dst, &extents->bounded); + } else { + if (op == CAIRO_OPERATOR_CLEAR) { + op = CAIRO_OPERATOR_DEST_OUT; + src = NULL; + } + + if (need_clip & NEED_CLIP_SURFACE) { + if (extents->is_bounded) { + status = _clip_and_composite_with_mask (extents->clip, op, src, + draw_func, + mask_func, + draw_closure, + dst, &extents->bounded); + } else { + status = _clip_and_composite_combine (extents->clip, op, src, + draw_func, draw_closure, + dst, &extents->bounded); + } + } else { + status = draw_func (draw_closure, + dst, op, src, + 0, 0, + &extents->bounded, + extents->clip); + } + } + } + + if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) { + if (need_clip & NEED_CLIP_SURFACE) + status = _cairo_xcb_surface_fixup_unbounded_with_mask (dst, extents, extents->clip); + else + status = _cairo_xcb_surface_fixup_unbounded (dst, extents); + } + + if (clip_region) + _cairo_xcb_surface_clear_clip_region (dst); + + _cairo_xcb_connection_release (dst->connection); + + return status; +} + +static cairo_status_t +_core_boxes (cairo_xcb_surface_t *dst, + cairo_operator_t op, + const cairo_pattern_t *src, + cairo_boxes_t *boxes, + const cairo_composite_rectangles_t *extents) +{ + if (! boxes->is_pixel_aligned) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (! _cairo_clip_is_region (extents->clip)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (op == CAIRO_OPERATOR_CLEAR) + return _cairo_xcb_surface_core_fill_boxes (dst, CAIRO_COLOR_TRANSPARENT, boxes); + + if (op == CAIRO_OPERATOR_OVER) { + if (dst->base.is_clear || _cairo_pattern_is_opaque (src, &extents->bounded)) + op = CAIRO_OPERATOR_SOURCE; + } + if (op != CAIRO_OPERATOR_SOURCE) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (src->type == CAIRO_PATTERN_TYPE_SOLID) { + return _cairo_xcb_surface_core_fill_boxes (dst, + &((cairo_solid_pattern_t *) src)->color, + boxes); + } + + return _cairo_xcb_surface_core_copy_boxes (dst, src, &extents->bounded, boxes); +} + +static cairo_status_t +_composite_boxes (cairo_xcb_surface_t *dst, + cairo_operator_t op, + const cairo_pattern_t *src, + cairo_boxes_t *boxes, + const cairo_composite_rectangles_t *extents) +{ + cairo_clip_t *clip = extents->clip; + cairo_bool_t need_clip_mask = ! _cairo_clip_is_region (clip); + cairo_status_t status; + + /* If the boxes are not pixel-aligned, we will need to compute a real mask */ + if (! boxes->is_pixel_aligned) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (need_clip_mask && + (! extents->is_bounded || op == CAIRO_OPERATOR_SOURCE)) + { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + status = _cairo_xcb_connection_acquire (dst->connection); + if (unlikely (status)) + return status; + + _cairo_xcb_surface_ensure_picture (dst); + if (dst->connection->flags & CAIRO_XCB_RENDER_HAS_FILL_RECTANGLES && ! need_clip_mask && + (op == CAIRO_OPERATOR_CLEAR || src->type == CAIRO_PATTERN_TYPE_SOLID)) + { + const cairo_color_t *color; + + if (op == CAIRO_OPERATOR_CLEAR) + color = CAIRO_COLOR_TRANSPARENT; + else + color = &((cairo_solid_pattern_t *) src)->color; + + status = _render_fill_boxes (dst, op, color, boxes); + } + else + { + cairo_surface_pattern_t mask; + + if (need_clip_mask) { + cairo_xcb_surface_t *clip_surface; + int clip_x = 0, clip_y = 0; + + clip_surface = get_clip_surface (extents->clip, dst, + &clip_x, &clip_y); + if (unlikely (clip_surface->base.status)) + return clip_surface->base.status; + + _cairo_pattern_init_for_surface (&mask, &clip_surface->base); + mask.base.filter = CAIRO_FILTER_NEAREST; + cairo_matrix_init_translate (&mask.base.matrix, + -clip_x, + -clip_y); + cairo_surface_destroy (&clip_surface->base); + + if (op == CAIRO_OPERATOR_CLEAR) { + src = NULL; + op = CAIRO_OPERATOR_DEST_OUT; + } + } + + status = _render_composite_boxes (dst, op, src, + need_clip_mask ? &mask.base : NULL, + &extents->bounded, boxes); + + if (need_clip_mask) + _cairo_pattern_fini (&mask.base); + } + + if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) { + status = + _cairo_xcb_surface_fixup_unbounded_boxes (dst, extents, + clip, boxes); + } + + _cairo_xcb_connection_release (dst->connection); + + return status; +} + +static cairo_bool_t +cairo_boxes_for_each_box (cairo_boxes_t *boxes, + cairo_bool_t (*func) (cairo_box_t *box, + void *data), + void *data) +{ + struct _cairo_boxes_chunk *chunk; + int i; + + for (chunk = &boxes->chunks; chunk != NULL; chunk = chunk->next) { + for (i = 0; i < chunk->count; i++) + if (! func (&chunk->base[i], data)) + return FALSE; + } + + return TRUE; +} + +struct _image_contains_box { + int width, height; + int tx, ty; +}; + +static cairo_bool_t image_contains_box (cairo_box_t *box, void *closure) +{ + struct _image_contains_box *data = closure; + + /* The box is pixel-aligned so the truncation is safe. */ + return + _cairo_fixed_integer_part (box->p1.x) + data->tx >= 0 && + _cairo_fixed_integer_part (box->p1.y) + data->ty >= 0 && + _cairo_fixed_integer_part (box->p2.x) + data->tx <= data->width && + _cairo_fixed_integer_part (box->p2.y) + data->ty <= data->height; +} + +struct _image_upload_box { + cairo_xcb_surface_t *surface; + cairo_image_surface_t *image; + xcb_gcontext_t gc; + int tx, ty; +}; + +static cairo_bool_t image_upload_box (cairo_box_t *box, void *closure) +{ + const struct _image_upload_box *iub = closure; + /* The box is pixel-aligned so the truncation is safe. */ + int x = _cairo_fixed_integer_part (box->p1.x); + int y = _cairo_fixed_integer_part (box->p1.y); + int width = _cairo_fixed_integer_part (box->p2.x - box->p1.x); + int height = _cairo_fixed_integer_part (box->p2.y - box->p1.y); + int bpp = PIXMAN_FORMAT_BPP (iub->image->pixman_format); + int len = CAIRO_STRIDE_FOR_WIDTH_BPP (width, bpp); + if (len == iub->image->stride) { + _cairo_xcb_connection_put_image (iub->surface->connection, + iub->surface->drawable, + iub->gc, + width, height, + x, y, + iub->image->depth, + iub->image->stride, + iub->image->data + + (y + iub->ty) * iub->image->stride + + (x + iub->tx) * bpp/8); + } else { + _cairo_xcb_connection_put_subimage (iub->surface->connection, + iub->surface->drawable, + iub->gc, + x + iub->tx, + y + iub->ty, + width, height, + bpp / 8, + iub->image->stride, + x, y, + iub->image->depth, + iub->image->data); + } + + return TRUE; +} + +static cairo_status_t +_upload_image_inplace (cairo_xcb_surface_t *surface, + const cairo_pattern_t *source, + cairo_boxes_t *boxes) +{ + const cairo_surface_pattern_t *pattern; + struct _image_contains_box icb; + struct _image_upload_box iub; + cairo_image_surface_t *image; + cairo_status_t status; + int tx, ty; + + if (! boxes->is_pixel_aligned) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (source->type != CAIRO_PATTERN_TYPE_SURFACE) + return CAIRO_INT_STATUS_UNSUPPORTED; + + pattern = (const cairo_surface_pattern_t *) source; + if (! _cairo_surface_is_image (pattern->surface)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* Have we already upload this image to a pixmap? */ + { + cairo_xcb_picture_t *snapshot; + + snapshot = (cairo_xcb_picture_t *) + _cairo_surface_has_snapshot (pattern->surface, &_cairo_xcb_picture_backend); + if (snapshot != NULL) { + if (snapshot->screen == surface->screen) + return CAIRO_INT_STATUS_UNSUPPORTED; + } + } + + image = (cairo_image_surface_t *) pattern->surface; + if (image->format == CAIRO_FORMAT_INVALID) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (image->depth != surface->depth) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (! _cairo_matrix_is_integer_translation (&source->matrix, &tx, &ty)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* Check that the data is entirely within the image */ + icb.width = image->width; + icb.height = image->height; + icb.tx = tx; + icb.ty = ty; + if (! cairo_boxes_for_each_box (boxes, image_contains_box, &icb)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (surface->deferred_clear) { + status = _cairo_xcb_surface_clear (surface); + if (unlikely (status)) + return status; + } + + status = _cairo_xcb_connection_acquire (surface->connection); + if (unlikely (status)) + return status; + + iub.surface = surface; + iub.image = image; + iub.gc = _cairo_xcb_screen_get_gc (surface->screen, + surface->drawable, + image->depth); + iub.tx = tx; + iub.ty = ty; + cairo_boxes_for_each_box (boxes, image_upload_box, &iub); + + _cairo_xcb_screen_put_gc (surface->screen, image->depth, iub.gc); + _cairo_xcb_connection_release (surface->connection); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +trim_extents_to_traps (cairo_composite_rectangles_t *extents, + cairo_traps_t *traps) +{ + cairo_box_t box; + + /* X trims the affected area to the extents of the trapezoids, so + * we need to compensate when fixing up the unbounded area. + */ + _cairo_traps_extents (traps, &box); + return _cairo_composite_rectangles_intersect_mask_extents (extents, &box); +} + +static cairo_bool_t +_mono_edge_is_vertical (const cairo_line_t *line) +{ + return _cairo_fixed_integer_round_down (line->p1.x) == _cairo_fixed_integer_round_down (line->p2.x); +} + +static cairo_bool_t +_traps_are_pixel_aligned (cairo_traps_t *traps, + cairo_antialias_t antialias) +{ + int i; + + if (antialias == CAIRO_ANTIALIAS_NONE) { + for (i = 0; i < traps->num_traps; i++) { + if (! _mono_edge_is_vertical (&traps->traps[i].left) || + ! _mono_edge_is_vertical (&traps->traps[i].right)) + { + traps->maybe_region = FALSE; + return FALSE; + } + } + } else { + for (i = 0; i < traps->num_traps; i++) { + if (traps->traps[i].left.p1.x != traps->traps[i].left.p2.x || + traps->traps[i].right.p1.x != traps->traps[i].right.p2.x || + ! _cairo_fixed_is_integer (traps->traps[i].top) || + ! _cairo_fixed_is_integer (traps->traps[i].bottom) || + ! _cairo_fixed_is_integer (traps->traps[i].left.p1.x) || + ! _cairo_fixed_is_integer (traps->traps[i].right.p1.x)) + { + traps->maybe_region = FALSE; + return FALSE; + } + } + } + + return TRUE; +} + +static void +_boxes_for_traps (cairo_boxes_t *boxes, + cairo_traps_t *traps, + cairo_antialias_t antialias) +{ + int i, j; + + _cairo_boxes_init (boxes); + + boxes->chunks.base = (cairo_box_t *) traps->traps; + boxes->chunks.size = traps->num_traps; + + if (antialias != CAIRO_ANTIALIAS_NONE) { + for (i = j = 0; i < traps->num_traps; i++) { + /* Note the traps and boxes alias so we need to take the local copies first. */ + cairo_fixed_t x1 = traps->traps[i].left.p1.x; + cairo_fixed_t x2 = traps->traps[i].right.p1.x; + cairo_fixed_t y1 = traps->traps[i].top; + cairo_fixed_t y2 = traps->traps[i].bottom; + + if (x1 == x2 || y1 == y2) + continue; + + boxes->chunks.base[j].p1.x = x1; + boxes->chunks.base[j].p1.y = y1; + boxes->chunks.base[j].p2.x = x2; + boxes->chunks.base[j].p2.y = y2; + j++; + + if (boxes->is_pixel_aligned) { + boxes->is_pixel_aligned = + _cairo_fixed_is_integer (x1) && _cairo_fixed_is_integer (y1) && + _cairo_fixed_is_integer (x2) && _cairo_fixed_is_integer (y2); + } + } + } else { + boxes->is_pixel_aligned = TRUE; + + for (i = j = 0; i < traps->num_traps; i++) { + /* Note the traps and boxes alias so we need to take the local copies first. */ + cairo_fixed_t x1 = traps->traps[i].left.p1.x; + cairo_fixed_t x2 = traps->traps[i].right.p1.x; + cairo_fixed_t y1 = traps->traps[i].top; + cairo_fixed_t y2 = traps->traps[i].bottom; + + /* round down here to match Pixman's behavior when using traps. */ + boxes->chunks.base[j].p1.x = _cairo_fixed_round_down (x1); + boxes->chunks.base[j].p1.y = _cairo_fixed_round_down (y1); + boxes->chunks.base[j].p2.x = _cairo_fixed_round_down (x2); + boxes->chunks.base[j].p2.y = _cairo_fixed_round_down (y2); + + j += (boxes->chunks.base[j].p1.x != boxes->chunks.base[j].p2.x && + boxes->chunks.base[j].p1.y != boxes->chunks.base[j].p2.y); + } + } + + boxes->num_boxes = j; + boxes->chunks.count = j; +} + +static cairo_status_t +_composite_polygon (cairo_xcb_surface_t *dst, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_polygon_t *polygon, + cairo_antialias_t antialias, + cairo_fill_rule_t fill_rule, + cairo_composite_rectangles_t *extents) +{ + composite_traps_info_t traps; + cairo_bool_t clip_surface = ! _cairo_clip_is_region (extents->clip); + cairo_region_t *clip_region = _cairo_clip_get_region (extents->clip); + cairo_status_t status; + + if (polygon->num_edges == 0) { + status = CAIRO_STATUS_SUCCESS; + + if (! extents->is_bounded) { + if (cairo_region_contains_rectangle (clip_region, &extents->unbounded) == CAIRO_REGION_OVERLAP_IN) + clip_region = NULL; + + if (clip_surface == FALSE) { + if (clip_region != NULL) { + status = _cairo_xcb_surface_set_clip_region (dst, clip_region); + if (unlikely (status)) + return status; + } + + status = _cairo_xcb_surface_fixup_unbounded (dst, extents); + + if (clip_region != NULL) + _cairo_xcb_surface_clear_clip_region (dst); + } else { + status = _cairo_xcb_surface_fixup_unbounded_with_mask (dst, + extents, + extents->clip); + } + } + + return status; + } + + if (extents->clip->path != NULL && extents->is_bounded) { + cairo_polygon_t clipper; + cairo_fill_rule_t clipper_fill_rule; + cairo_antialias_t clipper_antialias; + + status = _cairo_clip_get_polygon (extents->clip, + &clipper, + &clipper_fill_rule, + &clipper_antialias); + if (likely (status == CAIRO_STATUS_SUCCESS)) { + if (clipper_antialias == antialias) { + status = _cairo_polygon_intersect (polygon, fill_rule, + &clipper, clipper_fill_rule); + if (likely (status == CAIRO_STATUS_SUCCESS)) { + cairo_clip_t * clip = _cairo_clip_copy_region (extents->clip); + _cairo_clip_destroy (extents->clip); + extents->clip = clip; + + fill_rule = CAIRO_FILL_RULE_WINDING; + } + _cairo_polygon_fini (&clipper); + } + } + } + + _cairo_traps_init (&traps.traps); + + status = _cairo_bentley_ottmann_tessellate_polygon (&traps.traps, polygon, fill_rule); + if (unlikely (status)) + goto CLEANUP_TRAPS; + + if (traps.traps.has_intersections) { + if (traps.traps.is_rectangular) + status = _cairo_bentley_ottmann_tessellate_rectangular_traps (&traps.traps, CAIRO_FILL_RULE_WINDING); + else if (traps.traps.is_rectilinear) + status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (&traps.traps, CAIRO_FILL_RULE_WINDING); + else + status = _cairo_bentley_ottmann_tessellate_traps (&traps.traps, CAIRO_FILL_RULE_WINDING); + if (unlikely (status)) + goto CLEANUP_TRAPS; + } + + /* Use a fast path if the trapezoids consist of a simple region, + * but we can only do this if we do not have a clip surface, or can + * substitute the mask with the clip. + */ + if (traps.traps.maybe_region && + _traps_are_pixel_aligned (&traps.traps, antialias) && + (! clip_surface || + (extents->is_bounded && op != CAIRO_OPERATOR_SOURCE))) + { + cairo_boxes_t boxes; + + _boxes_for_traps (&boxes, &traps.traps, antialias); + status = _clip_and_composite_boxes (dst, op, source, &boxes, extents); + } + else + { + /* Otherwise render the trapezoids to a mask and composite in the usual + * fashion. + */ + traps.antialias = antialias; + status = trim_extents_to_traps (extents, &traps.traps); + if (likely (status == CAIRO_STATUS_SUCCESS)) { + unsigned int flags = 0; + + /* For unbounded operations, the X11 server will estimate the + * affected rectangle and apply the operation to that. However, + * there are cases where this is an overestimate (e.g. the + * clip-fill-{eo,nz}-unbounded test). + * + * The clip will trim that overestimate to our expectations. + */ + if (! extents->is_bounded) + flags |= FORCE_CLIP_REGION; + + status = _clip_and_composite (dst, op, source, _composite_traps, + NULL, &traps, extents, + need_unbounded_clip (extents) | flags); + } + } + +CLEANUP_TRAPS: + _cairo_traps_fini (&traps.traps); + + return status; +} + +static cairo_status_t +_clip_and_composite_boxes (cairo_xcb_surface_t *dst, + cairo_operator_t op, + const cairo_pattern_t *src, + cairo_boxes_t *boxes, + cairo_composite_rectangles_t *extents) +{ + composite_traps_info_t info; + cairo_int_status_t status; + + if (boxes->num_boxes == 0 && extents->is_bounded) + return CAIRO_STATUS_SUCCESS; + + if (boxes->is_pixel_aligned && _cairo_clip_is_region (extents->clip) && + (op == CAIRO_OPERATOR_SOURCE || + (dst->base.is_clear && (op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD)))) + { + if (boxes->num_boxes == 1 && + extents->bounded.width == dst->width && + extents->bounded.height == dst->height) + { + op = CAIRO_OPERATOR_SOURCE; + dst->deferred_clear = FALSE; + } + + status = _upload_image_inplace (dst, src, boxes); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + } + + /* Can we reduce drawing through a clip-mask to simply drawing the clip? */ + if (dst->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS && + extents->clip->path != NULL && extents->is_bounded) { + cairo_polygon_t polygon; + cairo_fill_rule_t fill_rule; + cairo_antialias_t antialias; + cairo_clip_t *clip; + + clip = _cairo_clip_copy (extents->clip); + clip = _cairo_clip_intersect_boxes (clip, boxes); + if (_cairo_clip_is_all_clipped (clip)) + return CAIRO_INT_STATUS_NOTHING_TO_DO; + + status = _cairo_clip_get_polygon (clip, &polygon, + &fill_rule, &antialias); + _cairo_clip_path_destroy (clip->path); + clip->path = NULL; + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { + cairo_clip_t *saved_clip = extents->clip; + extents->clip = clip; + status = _composite_polygon (dst, op, src, + &polygon, + antialias, + fill_rule, + extents); + clip = extents->clip; + extents->clip = saved_clip; + _cairo_polygon_fini (&polygon); + } + if (clip) + _cairo_clip_destroy (clip); + + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + } + + if (dst->deferred_clear) { + status = _cairo_xcb_surface_clear (dst); + if (unlikely (status)) + return status; + } + + if (boxes->is_pixel_aligned && + _cairo_clip_is_region (extents->clip) && + op == CAIRO_OPERATOR_SOURCE) { + status = _upload_image_inplace (dst, src, boxes); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + } + + if ((dst->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) == 0) + return _core_boxes (dst, op, src, boxes, extents); + + /* Use a fast path if the boxes are pixel aligned */ + status = _composite_boxes (dst, op, src, boxes, extents); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + return status; + + if ((dst->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS) == 0) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* Otherwise render via a mask and composite in the usual fashion. */ + status = _cairo_traps_init_boxes (&info.traps, boxes); + if (unlikely (status)) + return status; + + info.antialias = CAIRO_ANTIALIAS_DEFAULT; + status = trim_extents_to_traps (extents, &info.traps); + if (status == CAIRO_INT_STATUS_SUCCESS) { + status = _clip_and_composite (dst, op, src, + _composite_traps, NULL, &info, + extents, need_unbounded_clip (extents)); + } + + _cairo_traps_fini (&info.traps); + return status; +} + +static cairo_int_status_t +_composite_mask (void *closure, + cairo_xcb_surface_t *dst, + cairo_operator_t op, + const cairo_pattern_t *src_pattern, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents, + cairo_clip_t *clip) +{ + const cairo_pattern_t *mask_pattern = closure; + cairo_xcb_picture_t *src, *mask = NULL; + cairo_status_t status; + + if (dst->base.is_clear) { + if (op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD) + op = CAIRO_OPERATOR_SOURCE; + } + + if (op == CAIRO_OPERATOR_SOURCE && clip == NULL) + dst->deferred_clear = FALSE; + + if (dst->deferred_clear) { + status = _cairo_xcb_surface_clear (dst); + if (unlikely (status)) + return status; + } + + if (src_pattern != NULL) { + src = _cairo_xcb_picture_for_pattern (dst, src_pattern, extents); + if (unlikely (src->base.status)) + return src->base.status; + + mask = _cairo_xcb_picture_for_pattern (dst, mask_pattern, extents); + if (unlikely (mask->base.status)) { + cairo_surface_destroy (&src->base); + return mask->base.status; + } + + _cairo_xcb_connection_render_composite (dst->connection, + _render_operator (op), + src->picture, + mask->picture, + dst->picture, + extents->x + src->x, extents->y + src->y, + extents->x + mask->x, extents->y + mask->y, + extents->x - dst_x, extents->y - dst_y, + extents->width, extents->height); + cairo_surface_destroy (&mask->base); + cairo_surface_destroy (&src->base); + } else { + src = _cairo_xcb_picture_for_pattern (dst, mask_pattern, extents); + if (unlikely (src->base.status)) + return src->base.status; + + _cairo_xcb_connection_render_composite (dst->connection, + _render_operator (op), + src->picture, + XCB_NONE, + dst->picture, + extents->x + src->x, extents->y + src->y, + 0, 0, + extents->x - dst_x, extents->y - dst_y, + extents->width, extents->height); + cairo_surface_destroy (&src->base); + } + + return CAIRO_STATUS_SUCCESS; +} + +struct composite_box_info { + cairo_xcb_surface_t *dst; + cairo_xcb_picture_t *src; + uint8_t op; +}; + +static void composite_box(void *closure, + int16_t x, int16_t y, + int16_t w, int16_t h, + uint16_t coverage) +{ + struct composite_box_info *info = closure; + + if (coverage < 0xff00) { + cairo_xcb_picture_t *mask; + cairo_color_t color; + + color.red_short = color.green_short = color.blue_short = 0; + color.alpha_short = coverage; + + mask = _solid_picture (info->dst, &color); + if (likely (mask->base.status == CAIRO_STATUS_SUCCESS)) { + _cairo_xcb_connection_render_composite (info->dst->connection, + info->op, + info->src->picture, + mask->picture, + info->dst->picture, + x + info->src->x, y + info->src->y, + 0, 0, + x, y, + w, h); + } + cairo_surface_destroy (&mask->base); + } else { + _cairo_xcb_connection_render_composite (info->dst->connection, + info->op, + info->src->picture, + XCB_NONE, + info->dst->picture, + x + info->src->x, y + info->src->y, + 0, 0, + x, y, + w, h); + } +} + +static cairo_int_status_t +_composite_mask_clip_boxes (void *closure, + cairo_xcb_surface_t *dst, + cairo_operator_t op, + const cairo_pattern_t *src_pattern, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents, + cairo_clip_t *clip) +{ + struct composite_box_info info; + cairo_status_t status; + int i; + + assert (src_pattern == NULL); + assert (op == CAIRO_OPERATOR_ADD); + assert (dst->base.is_clear); + + if (clip->num_boxes > 1) { + status = _cairo_xcb_surface_clear (dst); + if (unlikely (status)) + return status; + } + + info.op = XCB_RENDER_PICT_OP_SRC; + info.dst = dst; + info.src = _cairo_xcb_picture_for_pattern (dst, closure, extents); + if (unlikely (info.src->base.status)) + return info.src->base.status; + + info.src->x += dst_x; + info.src->y += dst_y; + + for (i = 0; i < clip->num_boxes; i++) + do_unaligned_box(composite_box, &info, &clip->boxes[i], dst_x, dst_y); + cairo_surface_destroy (&info.src->base); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_composite_mask_clip (void *closure, + cairo_xcb_surface_t *dst, + cairo_operator_t op, + const cairo_pattern_t *src_pattern, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents, + cairo_clip_t *clip) +{ + const cairo_pattern_t *mask_pattern = closure; + cairo_polygon_t polygon; + cairo_fill_rule_t fill_rule; + composite_traps_info_t info; + cairo_status_t status; + + assert (src_pattern == NULL); + assert (op == CAIRO_OPERATOR_ADD); + assert (dst->base.is_clear); + + status = _cairo_clip_get_polygon (clip, &polygon, + &fill_rule, &info.antialias); + if (unlikely (status)) + return status; + + _cairo_traps_init (&info.traps); + status = _cairo_bentley_ottmann_tessellate_polygon (&info.traps, + &polygon, + fill_rule); + _cairo_polygon_fini (&polygon); + if (unlikely (status)) + return status; + + if (info.traps.has_intersections) { + if (info.traps.is_rectangular) + status = _cairo_bentley_ottmann_tessellate_rectangular_traps (&info.traps, CAIRO_FILL_RULE_WINDING); + else if (info.traps.is_rectilinear) + status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (&info.traps, CAIRO_FILL_RULE_WINDING); + else + status = _cairo_bentley_ottmann_tessellate_traps (&info.traps, CAIRO_FILL_RULE_WINDING); + if (unlikely (status)) { + _cairo_traps_fini (&info.traps); + return status; + } + } + + status = _composite_traps (&info, + dst, CAIRO_OPERATOR_SOURCE, mask_pattern, + dst_x, dst_y, + extents, NULL); + _cairo_traps_fini (&info.traps); + + return status; +} + +struct composite_opacity_info { + uint8_t op; + cairo_xcb_surface_t *dst; + cairo_xcb_picture_t *src; + double opacity; +}; + +static void composite_opacity(void *closure, + int16_t x, int16_t y, + int16_t w, int16_t h, + uint16_t coverage) +{ + struct composite_opacity_info *info = closure; + cairo_xcb_picture_t *mask; + cairo_color_t color; + + color.red_short = color.green_short = color.blue_short = 0; + color.alpha_short = info->opacity * coverage; + + mask = _solid_picture (info->dst, &color); + if (likely (mask->base.status == CAIRO_STATUS_SUCCESS)) { + if (info->src) { + _cairo_xcb_connection_render_composite (info->dst->connection, + info->op, + info->src->picture, + mask->picture, + info->dst->picture, + x + info->src->x, y + info->src->y, + 0, 0, + x, y, + w, h); + } else { + _cairo_xcb_connection_render_composite (info->dst->connection, + info->op, + mask->picture, + XCB_NONE, + info->dst->picture, + 0, 0, + 0, 0, + x, y, + w, h); + } + } + + cairo_surface_destroy (&mask->base); +} + +static cairo_int_status_t +_composite_opacity_boxes (void *closure, + cairo_xcb_surface_t *dst, + cairo_operator_t op, + const cairo_pattern_t *src_pattern, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents, + cairo_clip_t *clip) +{ + const cairo_solid_pattern_t *mask_pattern = closure; + struct composite_opacity_info info; + cairo_status_t status; + int i; + + if (dst->base.is_clear) { + if (op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD) + op = CAIRO_OPERATOR_SOURCE; + } + + if (op == CAIRO_OPERATOR_SOURCE && + (clip == NULL || + (clip->extents.width >= extents->width && + clip->extents.height >= extents->height))) + dst->deferred_clear = FALSE; + + if (dst->deferred_clear) { + status = _cairo_xcb_surface_clear (dst); + if (unlikely (status)) + return status; + } + + info.op = _render_operator (op); + info.dst = dst; + + if (src_pattern != NULL) { + info.src = _cairo_xcb_picture_for_pattern (dst, src_pattern, extents); + if (unlikely (info.src->base.status)) + return info.src->base.status; + } else + info.src = NULL; + + info.opacity = mask_pattern->color.alpha; + + /* XXX for lots of boxes create a clip region for the fully opaque areas */ + if (clip) { + for (i = 0; i < clip->num_boxes; i++) + do_unaligned_box(composite_opacity, &info, + &clip->boxes[i], dst_x, dst_y); + } else { + composite_opacity(&info, + extents->x - dst_x, + extents->y - dst_y, + extents->width, + extents->height, + 0xffff); + } + cairo_surface_destroy (&info.src->base); + + return CAIRO_STATUS_SUCCESS; +} + +/* high level rasteriser -> compositor */ + +cairo_int_status_t +_cairo_xcb_render_compositor_paint (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *composite) +{ + cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) composite->surface; + cairo_operator_t op = composite->op; + cairo_pattern_t *source = &composite->source_pattern.base; + cairo_boxes_t boxes; + cairo_status_t status; + + if (unlikely (! _operator_is_supported (surface->connection->flags, op))) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if ((surface->connection->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS | + CAIRO_XCB_RENDER_HAS_COMPOSITE)) == 0) + { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + if (composite->clip == NULL && + source->type == CAIRO_PATTERN_TYPE_SOLID && + (op == CAIRO_OPERATOR_SOURCE || + op == CAIRO_OPERATOR_CLEAR || + (surface->base.is_clear && + (op == CAIRO_OPERATOR_ADD || op == CAIRO_OPERATOR_OVER)))) + { + surface->deferred_clear = TRUE; + surface->deferred_clear_color = composite->source_pattern.solid.color; + return CAIRO_STATUS_SUCCESS; + } + + _cairo_clip_steal_boxes(composite->clip, &boxes); + status = _clip_and_composite_boxes (surface, op, source, &boxes, composite); + _cairo_clip_unsteal_boxes (composite->clip, &boxes); + + return status; +} + +cairo_int_status_t +_cairo_xcb_render_compositor_mask (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *composite) +{ + cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) composite->surface; + cairo_operator_t op = composite->op; + cairo_pattern_t *source = &composite->source_pattern.base; + cairo_pattern_t *mask = &composite->mask_pattern.base; + cairo_status_t status; + + if (unlikely (! _operator_is_supported (surface->connection->flags, op))) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if ((surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) == 0) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (mask->type == CAIRO_PATTERN_TYPE_SOLID && + composite->clip->path == NULL && + ! _cairo_clip_is_region (composite->clip)) { + status = _clip_and_composite (surface, op, source, + _composite_opacity_boxes, + _composite_opacity_boxes, + (void *) mask, + composite, need_unbounded_clip (composite)); + } else { + xcb_draw_func_t mask_func = NULL; + if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS) + mask_func = composite->clip->path ? _composite_mask_clip : _composite_mask_clip_boxes; + status = _clip_and_composite (surface, op, source, + _composite_mask, mask_func, + (void *) mask, + composite, need_bounded_clip (composite)); + } + + return status; +} + +static cairo_int_status_t +_cairo_xcb_surface_render_stroke_as_polygon (cairo_xcb_surface_t *dst, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + cairo_composite_rectangles_t *extents) +{ + cairo_polygon_t polygon; + cairo_status_t status; + + _cairo_polygon_init_with_clip (&polygon, extents->clip); + status = _cairo_path_fixed_stroke_to_polygon (path, + stroke_style, + ctm, ctm_inverse, + tolerance, + &polygon); + if (likely (status == CAIRO_STATUS_SUCCESS)) { + status = _composite_polygon (dst, op, source, + &polygon, antialias, + CAIRO_FILL_RULE_WINDING, + extents); + } + _cairo_polygon_fini (&polygon); + + return status; +} + +static cairo_status_t +_cairo_xcb_surface_render_stroke_via_mask (cairo_xcb_surface_t *dst, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + cairo_composite_rectangles_t *extents) +{ + cairo_surface_t *image; + cairo_status_t status; + cairo_clip_t *clip; + int x, y; + + x = extents->bounded.x; + y = extents->bounded.y; + image = _cairo_xcb_surface_create_similar_image (dst, CAIRO_FORMAT_A8, + extents->bounded.width, + extents->bounded.height); + if (unlikely (image->status)) + return image->status; + + clip = _cairo_clip_copy_region (extents->clip); + status = _cairo_surface_offset_stroke (image, x, y, + CAIRO_OPERATOR_ADD, + &_cairo_pattern_white.base, + path, stroke_style, + ctm, ctm_inverse, + tolerance, antialias, + clip); + _cairo_clip_destroy (clip); + if (likely (status == CAIRO_STATUS_SUCCESS)) { + cairo_surface_pattern_t mask; + + _cairo_pattern_init_for_surface (&mask, image); + mask.base.filter = CAIRO_FILTER_NEAREST; + + cairo_matrix_init_translate (&mask.base.matrix, -x, -y); + status = _clip_and_composite (dst, op, source, + _composite_mask, NULL, &mask.base, + extents, need_bounded_clip (extents)); + _cairo_pattern_fini (&mask.base); + } + + cairo_surface_finish (image); + cairo_surface_destroy (image); + + return status; +} + +cairo_int_status_t +_cairo_xcb_render_compositor_stroke (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *composite, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) composite->surface; + cairo_operator_t op = composite->op; + cairo_pattern_t *source = &composite->source_pattern.base; + cairo_int_status_t status; + + if (unlikely (! _operator_is_supported (surface->connection->flags, op))) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if ((surface->connection->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS | + CAIRO_XCB_RENDER_HAS_COMPOSITE)) == 0) + { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + status = CAIRO_INT_STATUS_UNSUPPORTED; + if (_cairo_path_fixed_stroke_is_rectilinear (path)) { + cairo_boxes_t boxes; + + _cairo_boxes_init_with_clip (&boxes, composite->clip); + status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path, + style, + ctm, + antialias, + &boxes); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { + status = _clip_and_composite_boxes (surface, op, source, + &boxes, composite); + } + _cairo_boxes_fini (&boxes); + } + + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS) { + status = _cairo_xcb_surface_render_stroke_as_polygon (surface, op, source, + path, style, + ctm, ctm_inverse, + tolerance, antialias, + composite); + } else if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) { + status = _cairo_xcb_surface_render_stroke_via_mask (surface, op, source, + path, style, + ctm, ctm_inverse, + tolerance, antialias, + composite); + } else { + ASSERT_NOT_REACHED; + } + } + + return status; +} + +static cairo_status_t +_cairo_xcb_surface_render_fill_as_polygon (cairo_xcb_surface_t *dst, + cairo_operator_t op, + const cairo_pattern_t*source, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + cairo_composite_rectangles_t *extents) +{ + cairo_polygon_t polygon; + cairo_status_t status; + + _cairo_polygon_init_with_clip (&polygon, extents->clip); + status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon); + if (likely (status == CAIRO_STATUS_SUCCESS)) { + status = _composite_polygon (dst, op, source, + &polygon, + antialias, + fill_rule, + extents); + } + _cairo_polygon_fini (&polygon); + + return status; +} + +static cairo_status_t +_cairo_xcb_surface_render_fill_via_mask (cairo_xcb_surface_t *dst, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + cairo_composite_rectangles_t *extents) +{ + cairo_surface_t *image; + cairo_status_t status; + cairo_clip_t *clip; + int x, y; + + x = extents->bounded.x; + y = extents->bounded.y; + image = _cairo_xcb_surface_create_similar_image (dst, CAIRO_FORMAT_A8, + extents->bounded.width, + extents->bounded.height); + if (unlikely (image->status)) + return image->status; + + clip = _cairo_clip_copy_region (extents->clip); + status = _cairo_surface_offset_fill (image, x, y, + CAIRO_OPERATOR_ADD, + &_cairo_pattern_white.base, + path, fill_rule, tolerance, antialias, + clip); + _cairo_clip_destroy (clip); + if (likely (status == CAIRO_STATUS_SUCCESS)) { + cairo_surface_pattern_t mask; + + _cairo_pattern_init_for_surface (&mask, image); + mask.base.filter = CAIRO_FILTER_NEAREST; + + cairo_matrix_init_translate (&mask.base.matrix, -x, -y); + status = _clip_and_composite (dst, op, source, + _composite_mask, NULL, &mask.base, + extents, need_bounded_clip (extents)); + + _cairo_pattern_fini (&mask.base); + } + + cairo_surface_finish (image); + cairo_surface_destroy (image); + + return status; +} + +cairo_int_status_t +_cairo_xcb_render_compositor_fill (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *composite, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) composite->surface; + cairo_operator_t op = composite->op; + cairo_pattern_t *source = &composite->source_pattern.base; + cairo_int_status_t status; + + if (unlikely (! _operator_is_supported (surface->connection->flags, op))) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if ((surface->connection->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS | + CAIRO_XCB_RENDER_HAS_COMPOSITE)) == 0) + { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + status = CAIRO_INT_STATUS_UNSUPPORTED; + if (_cairo_path_fixed_fill_is_rectilinear (path)) { + cairo_boxes_t boxes; + + _cairo_boxes_init_with_clip (&boxes, composite->clip); + status = _cairo_path_fixed_fill_rectilinear_to_boxes (path, + fill_rule, + antialias, + &boxes); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { + status = _clip_and_composite_boxes (surface, op, source, + &boxes, composite); + } + _cairo_boxes_fini (&boxes); + } + + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_TRAPEZOIDS) { + status = _cairo_xcb_surface_render_fill_as_polygon (surface, op, source, path, + fill_rule, tolerance, antialias, + composite); + } else if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE) { + status = _cairo_xcb_surface_render_fill_via_mask (surface, op, source, path, + fill_rule, tolerance, antialias, + composite); + } else { + ASSERT_NOT_REACHED; + } + } + + return status; +} + +static cairo_status_t +_cairo_xcb_surface_render_glyphs_via_mask (cairo_xcb_surface_t *dst, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_scaled_font_t *scaled_font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_composite_rectangles_t *extents) +{ + cairo_surface_t *image; + cairo_content_t content; + cairo_status_t status; + cairo_clip_t *clip; + int x, y; + + content = CAIRO_CONTENT_ALPHA; + if (scaled_font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL) + content = CAIRO_CONTENT_COLOR_ALPHA; + + x = extents->bounded.x; + y = extents->bounded.y; + image = _cairo_xcb_surface_create_similar_image (dst, + _cairo_format_from_content (content), + extents->bounded.width, + extents->bounded.height); + if (unlikely (image->status)) + return image->status; + + clip = _cairo_clip_copy_region (extents->clip); + status = _cairo_surface_offset_glyphs (image, x, y, + CAIRO_OPERATOR_ADD, + &_cairo_pattern_white.base, + scaled_font, glyphs, num_glyphs, + clip); + _cairo_clip_destroy (clip); + if (likely (status == CAIRO_STATUS_SUCCESS)) { + cairo_surface_pattern_t mask; + + _cairo_pattern_init_for_surface (&mask, image); + mask.base.filter = CAIRO_FILTER_NEAREST; + if (content & CAIRO_CONTENT_COLOR) + mask.base.has_component_alpha = TRUE; + + cairo_matrix_init_translate (&mask.base.matrix, -x, -y); + status = _clip_and_composite (dst, op, source, + _composite_mask, NULL, &mask.base, + extents, need_bounded_clip (extents)); + + _cairo_pattern_fini (&mask.base); + } + + cairo_surface_finish (image); + cairo_surface_destroy (image); + + return status; +} + +/* Build a struct of the same size of #cairo_glyph_t that can be used both as + * an input glyph with double coordinates, and as "working" glyph with + * integer from-current-point offsets. */ +typedef union { + cairo_glyph_t d; + unsigned long index; + struct { + unsigned long index; + int x; + int y; + } i; +} cairo_xcb_glyph_t; + +/* compile-time assert that #cairo_xcb_glyph_t is the same size as #cairo_glyph_t */ +COMPILE_TIME_ASSERT (sizeof (cairo_xcb_glyph_t) == sizeof (cairo_glyph_t)); + +typedef struct { + cairo_scaled_font_t *font; + cairo_xcb_glyph_t *glyphs; + int num_glyphs; + cairo_bool_t use_mask; +} composite_glyphs_info_t; + +static cairo_status_t +_can_composite_glyphs (cairo_xcb_surface_t *dst, + cairo_rectangle_int_t *extents, + cairo_scaled_font_t *scaled_font, + cairo_glyph_t *glyphs, + int *num_glyphs) +{ +#define GLYPH_CACHE_SIZE 64 + cairo_box_t bbox_cache[GLYPH_CACHE_SIZE]; + unsigned long glyph_cache[GLYPH_CACHE_SIZE]; +#undef GLYPH_CACHE_SIZE + cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_glyph_t *glyphs_end, *valid_glyphs; + const int max_glyph_size = dst->connection->maximum_request_length - 64; + + /* We must initialize the cache with values that cannot match the + * "hash" to guarantee that when compared for the first time they + * will result in a mismatch. The hash function is simply modulus, + * so we cannot use 0 in glyph_cache[0], but we can use it in all + * other array cells. + */ + memset (glyph_cache, 0, sizeof (glyph_cache)); + glyph_cache[0] = 1; + + /* Scan for oversized glyphs or glyphs outside the representable + * range and fallback in that case, discard glyphs outside of the + * image. + */ + valid_glyphs = glyphs; + for (glyphs_end = glyphs + *num_glyphs; glyphs != glyphs_end; glyphs++) { + double x1, y1, x2, y2; + cairo_scaled_glyph_t *glyph; + cairo_box_t *bbox; + int width, height, len; + int g; + + g = glyphs->index % ARRAY_LENGTH (glyph_cache); + if (glyph_cache[g] != glyphs->index) { + status = _cairo_scaled_glyph_lookup (scaled_font, + glyphs->index, + CAIRO_SCALED_GLYPH_INFO_METRICS, + NULL, /* foreground color */ + &glyph); + if (unlikely (status)) + break; + + glyph_cache[g] = glyphs->index; + bbox_cache[g] = glyph->bbox; + } + bbox = &bbox_cache[g]; + + /* Drop glyphs outside the clipping */ + x1 = _cairo_fixed_to_double (bbox->p1.x); + y1 = _cairo_fixed_to_double (bbox->p1.y); + y2 = _cairo_fixed_to_double (bbox->p2.y); + x2 = _cairo_fixed_to_double (bbox->p2.x); + if (unlikely (glyphs->x + x2 <= extents->x || + glyphs->y + y2 <= extents->y || + glyphs->x + x1 >= extents->x + extents->width || + glyphs->y + y1 >= extents->y + extents->height)) + { + (*num_glyphs)--; + continue; + } + + /* XRenderAddGlyph does not handle a glyph surface larger than + * the extended maximum XRequest size. + */ + width = _cairo_fixed_integer_ceil (bbox->p2.x - bbox->p1.x); + height = _cairo_fixed_integer_ceil (bbox->p2.y - bbox->p1.y); + len = CAIRO_STRIDE_FOR_WIDTH_BPP (width, 32) * height; + if (unlikely (len >= max_glyph_size)) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + break; + } + + /* The glyph coordinates must be representable in an int16_t. + * When possible, they will be expressed as an offset from the + * previous glyph, otherwise they will be an offset from the + * operation extents or from the surface origin. If the last + * two options are not valid, fallback. + */ + if (unlikely (glyphs->x > INT16_MAX || + glyphs->y > INT16_MAX || + glyphs->x - extents->x < INT16_MIN || + glyphs->y - extents->y < INT16_MIN)) + { + status = CAIRO_INT_STATUS_UNSUPPORTED; + break; + } + + + if (unlikely (valid_glyphs != glyphs)) + *valid_glyphs = *glyphs; + valid_glyphs++; + } + + if (unlikely (valid_glyphs != glyphs)) { + for (; glyphs != glyphs_end; glyphs++) { + *valid_glyphs = *glyphs; + valid_glyphs++; + } + } + + return status; +} + +/* Start a new element for the first glyph, + * or for any glyph that has unexpected position, + * or if current element has too many glyphs + * (Xrender limits each element to 252 glyphs, we limit them to 128) + * + * These same conditions need to be mirrored between + * _cairo_xcb_surface_emit_glyphs and _emit_glyph_chunks + */ +#define _start_new_glyph_elt(count, glyph) \ + (((count) & 127) == 0 || (glyph)->i.x || (glyph)->i.y) + +/* sz_xGlyphtElt required alignment to a 32-bit boundary, so ensure we have + * enough room for padding */ +typedef struct { + uint8_t len; + uint8_t pad1; + uint16_t pad2; + int16_t deltax; + int16_t deltay; +} x_glyph_elt_t; +#define _cairo_sz_x_glyph_elt_t (sizeof (x_glyph_elt_t) + 4) + +static void +_cairo_xcb_font_destroy (cairo_xcb_font_t *font) +{ + int i; + + for (i = 0; i < NUM_GLYPHSETS; i++) { + cairo_xcb_font_glyphset_info_t *info; + + info = &font->glyphset_info[i]; + free (info->pending_free_glyphs); + } + + cairo_list_del (&font->base.link); + cairo_list_del (&font->link); + + _cairo_xcb_connection_destroy (font->connection); + + free (font); +} + +static void +_cairo_xcb_font_fini (cairo_scaled_font_private_t *abstract_private, + cairo_scaled_font_t *scaled_font) +{ + cairo_xcb_font_t *font_private = (cairo_xcb_font_t *)abstract_private; + cairo_xcb_connection_t *connection; + cairo_bool_t have_connection; + cairo_status_t status; + int i; + + connection = font_private->connection; + + status = _cairo_xcb_connection_acquire (connection); + have_connection = status == CAIRO_STATUS_SUCCESS; + + for (i = 0; i < NUM_GLYPHSETS; i++) { + cairo_xcb_font_glyphset_info_t *info; + + info = &font_private->glyphset_info[i]; + if (info->glyphset && status == CAIRO_STATUS_SUCCESS) { + _cairo_xcb_connection_render_free_glyph_set (connection, + info->glyphset); + } + } + + if (have_connection) + _cairo_xcb_connection_release (connection); + + _cairo_xcb_font_destroy (font_private); +} + + +static cairo_xcb_font_t * +_cairo_xcb_font_create (cairo_xcb_connection_t *connection, + cairo_scaled_font_t *font) +{ + cairo_xcb_font_t *priv; + int i; + + priv = _cairo_calloc (sizeof (cairo_xcb_font_t)); + if (unlikely (priv == NULL)) + return NULL; + + _cairo_scaled_font_attach_private (font, &priv->base, connection, + _cairo_xcb_font_fini); + + priv->scaled_font = font; + priv->connection = _cairo_xcb_connection_reference (connection); + cairo_list_add (&priv->link, &connection->fonts); + + for (i = 0; i < NUM_GLYPHSETS; i++) { + cairo_xcb_font_glyphset_info_t *info = &priv->glyphset_info[i]; + switch (i) { + case GLYPHSET_INDEX_ARGB32: info->format = CAIRO_FORMAT_ARGB32; break; + case GLYPHSET_INDEX_A8: info->format = CAIRO_FORMAT_A8; break; + case GLYPHSET_INDEX_A1: info->format = CAIRO_FORMAT_A1; break; + default: ASSERT_NOT_REACHED; break; + } + info->xrender_format = 0; + info->glyphset = XCB_NONE; + info->pending_free_glyphs = NULL; + } + + return priv; +} + +void +_cairo_xcb_font_close (cairo_xcb_font_t *font) +{ + cairo_scaled_font_t *scaled_font; + + scaled_font = font->scaled_font; + + //scaled_font->surface_private = NULL; + _cairo_scaled_font_reset_cache (scaled_font); + + _cairo_xcb_font_destroy (font); +} + +static void +_cairo_xcb_render_free_glyphs (cairo_xcb_connection_t *connection, + cairo_xcb_font_glyphset_free_glyphs_t *to_free) +{ + _cairo_xcb_connection_render_free_glyphs (connection, + to_free->glyphset, + to_free->glyph_count, + to_free->glyph_indices); +} + +static int +_cairo_xcb_get_glyphset_index_for_format (cairo_format_t format) +{ + if (format == CAIRO_FORMAT_A8) + return GLYPHSET_INDEX_A8; + if (format == CAIRO_FORMAT_A1) + return GLYPHSET_INDEX_A1; + + assert (format == CAIRO_FORMAT_ARGB32); + return GLYPHSET_INDEX_ARGB32; +} + + + +static inline cairo_xcb_font_t * +_cairo_xcb_font_get (const cairo_xcb_connection_t *c, + cairo_scaled_font_t *font) +{ + return (cairo_xcb_font_t *)_cairo_scaled_font_find_private (font, c); +} + + +static cairo_xcb_font_glyphset_info_t * +_cairo_xcb_scaled_font_get_glyphset_info_for_format (cairo_xcb_connection_t *c, + cairo_scaled_font_t *font, + cairo_format_t format) +{ + cairo_xcb_font_t *priv; + cairo_xcb_font_glyphset_info_t *info; + int glyphset_index; + + glyphset_index = _cairo_xcb_get_glyphset_index_for_format (format); + + priv = _cairo_xcb_font_get (c, font); + if (priv == NULL) { + priv = _cairo_xcb_font_create (c, font); + if (priv == NULL) + return NULL; + } + + info = &priv->glyphset_info[glyphset_index]; + if (info->glyphset == XCB_NONE) { + info->glyphset = xcb_generate_id (c->xcb_connection); + info->xrender_format = c->standard_formats[info->format]; + + _cairo_xcb_connection_render_create_glyph_set (c, + info->glyphset, + info->xrender_format); + } + + return info; +} + +static cairo_bool_t +_cairo_xcb_glyphset_info_has_pending_free_glyph ( + cairo_xcb_font_glyphset_info_t *info, + unsigned long glyph_index) +{ + if (info->pending_free_glyphs != NULL) { + cairo_xcb_font_glyphset_free_glyphs_t *to_free; + int i; + + to_free = info->pending_free_glyphs; + for (i = 0; i < to_free->glyph_count; i++) { + if (to_free->glyph_indices[i] == glyph_index) { + to_free->glyph_count--; + memmove (&to_free->glyph_indices[i], + &to_free->glyph_indices[i+1], + (to_free->glyph_count - i) * sizeof (to_free->glyph_indices[0])); + return TRUE; + } + } + } + + return FALSE; +} + +typedef struct { + cairo_scaled_glyph_private_t base; + + cairo_xcb_font_glyphset_info_t *glyphset; +} cairo_xcb_glyph_private_t; + +static cairo_xcb_font_glyphset_info_t * +_cairo_xcb_scaled_font_get_glyphset_info_for_pending_free_glyph (cairo_xcb_connection_t *c, + cairo_scaled_font_t *font, + unsigned long glyph_index, + cairo_image_surface_t *surface) +{ + cairo_xcb_font_t *priv; + int i; + + priv = _cairo_xcb_font_get (c, font); + if (priv == NULL) + return NULL; + + if (surface != NULL) { + i = _cairo_xcb_get_glyphset_index_for_format (surface->format); + + if (_cairo_xcb_glyphset_info_has_pending_free_glyph ( + &priv->glyphset_info[i], + glyph_index)) + { + return &priv->glyphset_info[i]; + } + } else { + for (i = 0; i < NUM_GLYPHSETS; i++) { + if (_cairo_xcb_glyphset_info_has_pending_free_glyph ( + &priv->glyphset_info[i], + glyph_index)) + { + return &priv->glyphset_info[i]; + } + } + } + + return NULL; +} + +static void +_cairo_xcb_glyph_fini (cairo_scaled_glyph_private_t *glyph_private, + cairo_scaled_glyph_t *glyph, + cairo_scaled_font_t *font) +{ + cairo_xcb_glyph_private_t *priv = (cairo_xcb_glyph_private_t *)glyph_private; + + if (! font->finished) { + cairo_xcb_font_glyphset_info_t *info = priv->glyphset; + cairo_xcb_font_glyphset_free_glyphs_t *to_free; + cairo_xcb_font_t *font_private; + + font_private = _cairo_xcb_font_get (glyph_private->key, font); + assert (font_private); + + to_free = info->pending_free_glyphs; + if (to_free != NULL && + to_free->glyph_count == ARRAY_LENGTH (to_free->glyph_indices)) + { + _cairo_xcb_render_free_glyphs (font_private->connection, to_free); + to_free = info->pending_free_glyphs = NULL; + } + + if (to_free == NULL) { + to_free = _cairo_calloc (sizeof (cairo_xcb_font_glyphset_free_glyphs_t)); + if (unlikely (to_free == NULL)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return; /* XXX cannot propagate failure */ + } + + to_free->glyphset = info->glyphset; + to_free->glyph_count = 0; + info->pending_free_glyphs = to_free; + } + + to_free->glyph_indices[to_free->glyph_count++] = + _cairo_scaled_glyph_index (glyph); + } + + cairo_list_del (&glyph_private->link); + free (glyph_private); +} + + +static cairo_status_t +_cairo_xcb_glyph_attach (cairo_xcb_connection_t *c, + cairo_scaled_glyph_t *glyph, + cairo_xcb_font_glyphset_info_t *info) +{ + cairo_xcb_glyph_private_t *priv; + + priv = _cairo_calloc (sizeof (*priv)); + if (unlikely (priv == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + _cairo_scaled_glyph_attach_private (glyph, &priv->base, c, + _cairo_xcb_glyph_fini); + priv->glyphset = info; + + glyph->dev_private = info; + glyph->dev_private_key = c; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_xcb_surface_add_glyph (cairo_xcb_connection_t *connection, + cairo_scaled_font_t *font, + cairo_scaled_glyph_t **scaled_glyph_out) +{ + xcb_render_glyphinfo_t glyph_info; + uint32_t glyph_index; + uint8_t *data; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_scaled_glyph_t *scaled_glyph = *scaled_glyph_out; + cairo_image_surface_t *glyph_surface = scaled_glyph->surface; + cairo_bool_t already_had_glyph_surface; + cairo_xcb_font_glyphset_info_t *info; + + glyph_index = _cairo_scaled_glyph_index (scaled_glyph); + + /* check to see if we have a pending XRenderFreeGlyph for this glyph */ + info = _cairo_xcb_scaled_font_get_glyphset_info_for_pending_free_glyph (connection, font, glyph_index, glyph_surface); + if (info != NULL) + return _cairo_xcb_glyph_attach (connection, scaled_glyph, info); + + if (glyph_surface == NULL) { + status = _cairo_scaled_glyph_lookup (font, + glyph_index, + CAIRO_SCALED_GLYPH_INFO_METRICS | + CAIRO_SCALED_GLYPH_INFO_SURFACE, + NULL, /* foreground color */ + scaled_glyph_out); + if (unlikely (status)) + return status; + + scaled_glyph = *scaled_glyph_out; + glyph_surface = scaled_glyph->surface; + already_had_glyph_surface = FALSE; + } else { + already_had_glyph_surface = TRUE; + } + + info = _cairo_xcb_scaled_font_get_glyphset_info_for_format (connection, + font, + glyph_surface->format); + if (unlikely (info == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto BAIL; + } + +#if 0 + /* If the glyph surface has zero height or width, we create + * a clear 1x1 surface, to avoid various X server bugs. + */ + if (glyph_surface->width == 0 || glyph_surface->height == 0) { + cairo_surface_t *tmp_surface; + + tmp_surface = cairo_image_surface_create (info->format, 1, 1); + status = tmp_surface->status; + if (unlikely (status)) + goto BAIL; + + tmp_surface->device_transform = glyph_surface->base.device_transform; + tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse; + + glyph_surface = (cairo_image_surface_t *) tmp_surface; + } +#endif + + /* If the glyph format does not match the font format, then we + * create a temporary surface for the glyph image with the font's + * format. + */ + if (glyph_surface->format != info->format) { + glyph_surface = _cairo_image_surface_coerce_to_format (glyph_surface, + info->format); + status = glyph_surface->base.status; + if (unlikely (status)) + goto BAIL; + } + + /* XXX: FRAGILE: We're ignore device_transform scaling here. A bug? */ + glyph_info.x = _cairo_lround (glyph_surface->base.device_transform.x0); + glyph_info.y = _cairo_lround (glyph_surface->base.device_transform.y0); + glyph_info.width = glyph_surface->width; + glyph_info.height = glyph_surface->height; + glyph_info.x_off = scaled_glyph->x_advance; + glyph_info.y_off = scaled_glyph->y_advance; + + data = glyph_surface->data; + + /* flip formats around */ + switch (_cairo_xcb_get_glyphset_index_for_format (scaled_glyph->surface->format)) { + case GLYPHSET_INDEX_A1: + /* local bitmaps are always stored with bit == byte */ + if (_cairo_is_little_endian() != (connection->root->bitmap_format_bit_order == XCB_IMAGE_ORDER_LSB_FIRST)) { + int c = glyph_surface->stride * glyph_surface->height; + const uint8_t *d; + uint8_t *new, *n; + + if (c == 0) + break; + + new = _cairo_malloc (c); + if (unlikely (new == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto BAIL; + } + + n = new; + d = data; + do { + uint8_t b = *d++; + b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55); + b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33); + b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f); + *n++ = b; + } while (--c); + data = new; + } + break; + + case GLYPHSET_INDEX_A8: + break; + + case GLYPHSET_INDEX_ARGB32: + if (_cairo_is_little_endian() != (connection->root->image_byte_order == XCB_IMAGE_ORDER_LSB_FIRST)) { + unsigned int c = glyph_surface->stride * glyph_surface->height / 4; + const uint32_t *d; + uint32_t *new, *n; + + if (c == 0) + break; + + new = _cairo_malloc (4 * c); + if (unlikely (new == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto BAIL; + } + + n = new; + d = (uint32_t *) data; + do { + *n++ = bswap_32 (*d); + d++; + } while (--c); + data = (uint8_t *) new; + } + break; + + default: + ASSERT_NOT_REACHED; + break; + } + /* XXX assume X server wants pixman padding. Xft assumes this as well */ + + _cairo_xcb_connection_render_add_glyphs (connection, + info->glyphset, + 1, &glyph_index, &glyph_info, + glyph_surface->stride * glyph_surface->height, + data); + + if (data != glyph_surface->data) + free (data); + + status = _cairo_xcb_glyph_attach (connection, scaled_glyph, info); + + BAIL: + if (glyph_surface != scaled_glyph->surface) + cairo_surface_destroy (&glyph_surface->base); + + /* If the scaled glyph didn't already have a surface attached + * to it, release the created surface now that we have it + * uploaded to the X server. If the surface has already been + * there (e.g. because image backend requested it), leave it in + * the cache + */ + if (! already_had_glyph_surface) + _cairo_scaled_glyph_set_surface (scaled_glyph, font, NULL); + + return status; +} + +typedef void (*cairo_xcb_render_composite_text_func_t) + (cairo_xcb_connection_t *connection, + uint8_t op, + xcb_render_picture_t src, + xcb_render_picture_t dst, + xcb_render_pictformat_t mask_format, + xcb_render_glyphset_t glyphset, + int16_t src_x, + int16_t src_y, + uint32_t len, + uint8_t *cmd); + + +static cairo_status_t +_emit_glyphs_chunk (cairo_xcb_surface_t *dst, + cairo_operator_t op, + cairo_xcb_picture_t *src, + /* info for this chunk */ + cairo_xcb_glyph_t *glyphs, + int num_glyphs, + int width, + int estimated_req_size, + cairo_xcb_font_glyphset_info_t *info, + xcb_render_pictformat_t mask_format) +{ + cairo_xcb_render_composite_text_func_t composite_text_func; + uint8_t stack_buf[CAIRO_STACK_BUFFER_SIZE]; + uint8_t *buf = stack_buf; + x_glyph_elt_t *elt = NULL; /* silence compiler */ + uint32_t len; + int i; + + if (estimated_req_size > ARRAY_LENGTH (stack_buf)) { + buf = _cairo_malloc (estimated_req_size); + if (unlikely (buf == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + len = 0; + for (i = 0; i < num_glyphs; i++) { + if (_start_new_glyph_elt (i, &glyphs[i])) { + if (len & 3) + len += 4 - (len & 3); + + elt = (x_glyph_elt_t *) (buf + len); + elt->len = 0; + elt->deltax = glyphs[i].i.x; + elt->deltay = glyphs[i].i.y; + len += sizeof (x_glyph_elt_t); + } + + switch (width) { + case 1: *(uint8_t *) (buf + len) = glyphs[i].index; break; + case 2: *(uint16_t *) (buf + len) = glyphs[i].index; break; + default: + case 4: *(uint32_t *) (buf + len) = glyphs[i].index; break; + } + len += width; + elt->len++; + } + if (len & 3) + len += 4 - (len & 3); + + switch (width) { + case 1: + composite_text_func = _cairo_xcb_connection_render_composite_glyphs_8; + break; + case 2: + composite_text_func = _cairo_xcb_connection_render_composite_glyphs_16; + break; + default: + case 4: + composite_text_func = _cairo_xcb_connection_render_composite_glyphs_32; + break; + } + composite_text_func (dst->connection, + _render_operator (op), + src->picture, + dst->picture, + mask_format, + info->glyphset, + src->x + glyphs[0].i.x, + src->y + glyphs[0].i.y, + len, buf); + + if (buf != stack_buf) + free (buf); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_composite_glyphs (void *closure, + cairo_xcb_surface_t *dst, + cairo_operator_t op, + const cairo_pattern_t *pattern, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents, + cairo_clip_t *clip) +{ + composite_glyphs_info_t *info = closure; + cairo_scaled_glyph_t *glyph_cache[64]; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_fixed_t x = 0, y = 0; + cairo_xcb_font_glyphset_info_t *glyphset_info = NULL, *this_glyphset_info; + const unsigned int max_request_size = dst->connection->maximum_request_length - 64; + cairo_xcb_picture_t *src; + + unsigned long max_index = 0; + int width = 1; + + unsigned int request_size = 0; + int i; + + if (dst->deferred_clear) { + status = _cairo_xcb_surface_clear (dst); + if (unlikely (status)) + return status; + } + + src = _cairo_xcb_picture_for_pattern (dst, pattern, extents); + if (unlikely (src->base.status)) + return src->base.status; + + memset (glyph_cache, 0, sizeof (glyph_cache)); + + for (i = 0; i < info->num_glyphs; i++) { + cairo_scaled_glyph_t *glyph; + unsigned long glyph_index = info->glyphs[i].index; + int cache_index = glyph_index % ARRAY_LENGTH (glyph_cache); + int old_width = width; + int this_x, this_y; + + glyph = glyph_cache[cache_index]; + if (glyph == NULL || + _cairo_scaled_glyph_index (glyph) != glyph_index) + { + status = _cairo_scaled_glyph_lookup (info->font, + glyph_index, + CAIRO_SCALED_GLYPH_INFO_METRICS, + NULL, /* foreground color */ + &glyph); + if (unlikely (status)) { + cairo_surface_destroy (&src->base); + return status; + } + + /* Send unseen glyphs to the server */ + if (glyph->dev_private_key != dst->connection) { + status = _cairo_xcb_surface_add_glyph (dst->connection, + info->font, + &glyph); + if (unlikely (status)) { + cairo_surface_destroy (&src->base); + return status; + } + } + + glyph_cache[cache_index] = glyph; + } + + this_x = _cairo_lround (info->glyphs[i].d.x) - dst_x; + this_y = _cairo_lround (info->glyphs[i].d.y) - dst_y; + + this_glyphset_info = glyph->dev_private; + if (glyphset_info == NULL) + glyphset_info = this_glyphset_info; + + /* Update max glyph index */ + if (glyph_index > max_index) { + max_index = glyph_index; + if (max_index >= 65536) + width = 4; + else if (max_index >= 256) + width = 2; + if (width != old_width) + request_size += (width - old_width) * i; + } + + /* If we will pass the max request size by adding this glyph, + * flush current glyphs. Note that we account for a + * possible element being added below. + * + * Also flush if changing glyphsets, as Xrender limits one mask + * format per request, so we can either break up, or use a + * wide-enough mask format. We do the former. One reason to + * prefer the latter is the fact that Xserver ADDs all glyphs + * to the mask first, and then composes that to final surface, + * though it's not a big deal. + * + * If the glyph has a coordinate which cannot be represented + * as a 16-bit offset from the previous glyph, flush the + * current chunk. The current glyph will be the first one in + * the next chunk, thus its coordinates will be an offset from + * the destination origin. This offset is guaranteed to be + * representable as 16-bit offset in _can_composite_glyphs(). + */ + if (request_size + width > max_request_size - _cairo_sz_x_glyph_elt_t || + this_x - x > INT16_MAX || this_x - x < INT16_MIN || + this_y - y > INT16_MAX || this_y - y < INT16_MIN || + this_glyphset_info != glyphset_info) + { + status = _emit_glyphs_chunk (dst, op, src, + info->glyphs, i, + old_width, request_size, + glyphset_info, + info->use_mask ? glyphset_info->xrender_format : 0); + if (unlikely (status)) { + cairo_surface_destroy (&src->base); + return status; + } + + info->glyphs += i; + info->num_glyphs -= i; + i = 0; + + max_index = info->glyphs[0].index; + width = max_index < 256 ? 1 : max_index < 65536 ? 2 : 4; + + request_size = 0; + + x = y = 0; + glyphset_info = this_glyphset_info; + } + + /* Convert absolute glyph position to relative-to-current-point + * position */ + info->glyphs[i].i.x = this_x - x; + info->glyphs[i].i.y = this_y - y; + + /* Start a new element for the first glyph, + * or for any glyph that has unexpected position, + * or if current element has too many glyphs. + * + * These same conditions are mirrored in _emit_glyphs_chunk(). + */ + if (_start_new_glyph_elt (i, &info->glyphs[i])) + request_size += _cairo_sz_x_glyph_elt_t; + + /* adjust current-position */ + x = this_x + glyph->x_advance; + y = this_y + glyph->y_advance; + + request_size += width; + } + + if (i) { + status = _emit_glyphs_chunk (dst, op, src, + info->glyphs, i, + width, request_size, + glyphset_info, + info->use_mask ? glyphset_info->xrender_format : 0); + } + + cairo_surface_destroy (&src->base); + + return status; +} + +cairo_int_status_t +_cairo_xcb_render_compositor_glyphs (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *composite, + cairo_scaled_font_t *scaled_font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_bool_t overlap) +{ + cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) composite->surface; + cairo_operator_t op = composite->op; + cairo_pattern_t *source = &composite->source_pattern.base; + cairo_int_status_t status; + + if (unlikely (! _operator_is_supported (surface->connection->flags, op))) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if ((surface->connection->flags & (CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS | CAIRO_XCB_RENDER_HAS_COMPOSITE)) == 0) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = CAIRO_INT_STATUS_UNSUPPORTED; + if (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE_GLYPHS) { + _cairo_scaled_font_freeze_cache (scaled_font); + + status = _can_composite_glyphs (surface, &composite->bounded, + scaled_font, glyphs, &num_glyphs); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { + composite_glyphs_info_t info; + unsigned flags = 0; + + info.font = scaled_font; + info.glyphs = (cairo_xcb_glyph_t *) glyphs; + info.num_glyphs = num_glyphs; + info.use_mask = + overlap || + ! composite->is_bounded || + ! _cairo_clip_is_region(composite->clip); + + if (composite->mask.width > composite->unbounded.width || + composite->mask.height > composite->unbounded.height) + { + /* Glyphs are tricky since we do not directly control the + * geometry and their inked extents depend on the + * individual glyph-surface size. We must set a clip region + * so that the X server can trim the glyphs appropriately. + */ + flags |= FORCE_CLIP_REGION; + } + status = _clip_and_composite (surface, op, source, + _composite_glyphs, NULL, + &info, composite, + need_bounded_clip (composite) | + flags); + } + + _cairo_scaled_font_thaw_cache (scaled_font); + } + + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + assert (surface->connection->flags & CAIRO_XCB_RENDER_HAS_COMPOSITE); + status = + _cairo_xcb_surface_render_glyphs_via_mask (surface, op, source, + scaled_font, glyphs, num_glyphs, + composite); + } + + return status; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-xcb-surface.c b/local/recipes/libs/cairo/source/src/cairo-xcb-surface.c new file mode 100644 index 0000000000..302d3fbe09 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-xcb-surface.c @@ -0,0 +1,1510 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2009 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Behdad Esfahbod + * Carl D. Worth + * Chris Wilson + * Karl Tomlinson , Mozilla Corporation + */ + +#include "cairoint.h" + +#include "cairo-xcb.h" +#include "cairo-xcb-private.h" + +#include "cairo-composite-rectangles-private.h" +#include "cairo-default-context-private.h" +#include "cairo-image-surface-inline.h" +#include "cairo-list-inline.h" +#include "cairo-surface-backend-private.h" +#include "cairo-compositor-private.h" + +/** + * SECTION:cairo-xcb + * @Title: XCB Surfaces + * @Short_Description: X Window System rendering using the XCB library + * @See_Also: #cairo_surface_t + * + * The XCB surface is used to render cairo graphics to X Window System + * windows and pixmaps using the XCB library. + * + * Note that the XCB surface automatically takes advantage of the X render + * extension if it is available. + **/ + +/** + * CAIRO_HAS_XCB_SURFACE: + * + * Defined if the xcb surface backend is available. + * This macro can be used to conditionally compile backend-specific code. + * + * Since: 1.12 + **/ + +cairo_surface_t * +_cairo_xcb_surface_create_similar (void *abstract_other, + cairo_content_t content, + int width, + int height) +{ + cairo_xcb_surface_t *other = abstract_other; + cairo_xcb_surface_t *surface; + cairo_xcb_connection_t *connection; + xcb_pixmap_t pixmap; + cairo_status_t status; + + if (unlikely(width > XLIB_COORD_MAX || + height > XLIB_COORD_MAX || + width <= 0 || + height <= 0)) + return cairo_image_surface_create (_cairo_format_from_content (content), + width, height); + + if ((other->connection->flags & CAIRO_XCB_HAS_RENDER) == 0) + return _cairo_xcb_surface_create_similar_image (other, + _cairo_format_from_content (content), + width, height); + + connection = other->connection; + status = _cairo_xcb_connection_acquire (connection); + if (unlikely (status)) + return _cairo_surface_create_in_error (status); + + if (content == other->base.content) { + pixmap = _cairo_xcb_connection_create_pixmap (connection, + other->depth, + other->drawable, + width, height); + + surface = (cairo_xcb_surface_t *) + _cairo_xcb_surface_create_internal (other->screen, + pixmap, TRUE, + other->pixman_format, + other->xrender_format, + width, height); + } else { + cairo_format_t format; + pixman_format_code_t pixman_format; + + /* XXX find a compatible xrender format */ + switch (content) { + case CAIRO_CONTENT_ALPHA: + pixman_format = PIXMAN_a8; + format = CAIRO_FORMAT_A8; + break; + case CAIRO_CONTENT_COLOR: + pixman_format = PIXMAN_x8r8g8b8; + format = CAIRO_FORMAT_RGB24; + break; + default: + ASSERT_NOT_REACHED; + case CAIRO_CONTENT_COLOR_ALPHA: + pixman_format = PIXMAN_a8r8g8b8; + format = CAIRO_FORMAT_ARGB32; + break; + } + + pixmap = _cairo_xcb_connection_create_pixmap (connection, + PIXMAN_FORMAT_DEPTH (pixman_format), + other->drawable, + width, height); + + surface = (cairo_xcb_surface_t *) + _cairo_xcb_surface_create_internal (other->screen, + pixmap, TRUE, + pixman_format, + connection->standard_formats[format], + width, height); + } + + if (unlikely (surface->base.status)) + xcb_free_pixmap (connection->xcb_connection, pixmap); + + _cairo_xcb_connection_release (connection); + + return &surface->base; +} + +cairo_surface_t * +_cairo_xcb_surface_create_similar_image (void *abstract_other, + cairo_format_t format, + int width, + int height) +{ + cairo_xcb_surface_t *other = abstract_other; + cairo_xcb_connection_t *connection = other->connection; + + cairo_xcb_shm_info_t *shm_info; + cairo_image_surface_t *image; + cairo_status_t status; + pixman_format_code_t pixman_format; + + if (unlikely(width > XLIB_COORD_MAX || + height > XLIB_COORD_MAX || + width <= 0 || + height <= 0)) + return NULL; + + pixman_format = _cairo_format_to_pixman_format_code (format); + + status = _cairo_xcb_shm_image_create (connection, pixman_format, + width, height, &image, + &shm_info); + if (unlikely (status)) + return _cairo_surface_create_in_error (status); + + if (! image->base.is_clear) { + memset (image->data, 0, image->stride * image->height); + image->base.is_clear = TRUE; + } + + return &image->base; +} + +static cairo_status_t +_cairo_xcb_surface_finish (void *abstract_surface) +{ + cairo_xcb_surface_t *surface = abstract_surface; + cairo_status_t status; + + if (surface->fallback != NULL) { + cairo_surface_finish (&surface->fallback->base); + cairo_surface_destroy (&surface->fallback->base); + } + _cairo_boxes_fini (&surface->fallback_damage); + + cairo_list_del (&surface->link); + + status = _cairo_xcb_connection_acquire (surface->connection); + if (status == CAIRO_STATUS_SUCCESS) { + if (surface->picture != XCB_NONE) { + _cairo_xcb_connection_render_free_picture (surface->connection, + surface->picture); + } + + if (surface->owns_pixmap) + xcb_free_pixmap (surface->connection->xcb_connection, surface->drawable); + _cairo_xcb_connection_release (surface->connection); + } + + _cairo_xcb_connection_destroy (surface->connection); + + return status; +} + +static void +_destroy_image (pixman_image_t *image, void *data) +{ + free (data); +} + +#if CAIRO_HAS_XCB_SHM_FUNCTIONS +static cairo_surface_t * +_cairo_xcb_surface_create_shm_image (cairo_xcb_connection_t *connection, + pixman_format_code_t pixman_format, + int width, int height, + cairo_bool_t might_reuse, + cairo_xcb_shm_info_t **shm_info_out) +{ + cairo_surface_t *image; + cairo_xcb_shm_info_t *shm_info; + cairo_int_status_t status; + size_t stride; + + *shm_info_out = NULL; + + stride = CAIRO_STRIDE_FOR_WIDTH_BPP (width, + PIXMAN_FORMAT_BPP (pixman_format)); + status = _cairo_xcb_connection_allocate_shm_info (connection, + stride * height, + might_reuse, + &shm_info); + if (unlikely (status)) { + if (status == CAIRO_INT_STATUS_UNSUPPORTED) + return NULL; + + return _cairo_surface_create_in_error (status); + } + + image = _cairo_image_surface_create_with_pixman_format (shm_info->mem, + pixman_format, + width, height, + stride); + if (unlikely (image->status)) { + _cairo_xcb_shm_info_destroy (shm_info); + return image; + } + + status = _cairo_user_data_array_set_data (&image->user_data, + (const cairo_user_data_key_t *) connection, + shm_info, + (cairo_destroy_func_t) _cairo_xcb_shm_info_destroy); + if (unlikely (status)) { + cairo_surface_destroy (image); + _cairo_xcb_shm_info_destroy (shm_info); + return _cairo_surface_create_in_error (status); + } + + *shm_info_out = shm_info; + return image; +} +#endif + +static cairo_surface_t * +_get_shm_image (cairo_xcb_surface_t *surface, + int x, int y, + int width, int height) +{ +#if CAIRO_HAS_XCB_SHM_FUNCTIONS + cairo_xcb_shm_info_t *shm_info; + cairo_surface_t *image; + cairo_status_t status; + + if ((surface->connection->flags & CAIRO_XCB_HAS_SHM) == 0) + return NULL; + + image = _cairo_xcb_surface_create_shm_image (surface->connection, + surface->pixman_format, + width, height, + TRUE, + &shm_info); + if (unlikely (image == NULL || image->status)) + goto done; + + status = _cairo_xcb_connection_shm_get_image (surface->connection, + surface->drawable, + x, y, + width, height, + shm_info->shm, + shm_info->offset); + if (unlikely (status)) { + cairo_surface_destroy (image); + image = _cairo_surface_create_in_error (status); + } + +done: + return image; +#else + return NULL; +#endif +} + +static cairo_surface_t * +_get_image (cairo_xcb_surface_t *surface, + cairo_bool_t use_shm, + int x, int y, + int width, int height) +{ + cairo_surface_t *image; + cairo_xcb_connection_t *connection; + xcb_get_image_reply_t *reply; + cairo_int_status_t status; + + assert (surface->fallback == NULL); + assert (x >= 0); + assert (y >= 0); + assert (x + width <= surface->width); + assert (y + height <= surface->height); + + if (surface->deferred_clear) { + image = + _cairo_image_surface_create_with_pixman_format (NULL, + surface->pixman_format, + width, height, + 0); + if (surface->deferred_clear_color.alpha_short > 0x00ff) { + cairo_solid_pattern_t solid; + + _cairo_pattern_init_solid (&solid, &surface->deferred_clear_color); + status = _cairo_surface_paint (image, + CAIRO_OPERATOR_SOURCE, + &solid.base, + NULL); + if (unlikely (status)) { + cairo_surface_destroy (image); + image = _cairo_surface_create_in_error (status); + } + } + return image; + } + + connection = surface->connection; + + status = _cairo_xcb_connection_acquire (connection); + if (unlikely (status)) + return _cairo_surface_create_in_error (status); + + if (use_shm) { + image = _get_shm_image (surface, x, y, width, height); + if (image) { + if (image->status == CAIRO_STATUS_SUCCESS) { + _cairo_xcb_connection_release (connection); + return image; + } + cairo_surface_destroy (image); + } + } + + reply =_cairo_xcb_connection_get_image (connection, + surface->drawable, + x, y, + width, height); + + if (reply == NULL && ! surface->owns_pixmap) { + /* xcb_get_image_t from a window is dangerous because it can + * produce errors if the window is unmapped or partially + * outside the screen. We could check for errors and + * retry, but to keep things simple, we just create a + * temporary pixmap + * + * If we hit this fallback too often, we should remember so and + * skip the round-trip from the above GetImage request, + * similar to what cairo-xlib does. + */ + xcb_pixmap_t pixmap; + xcb_gcontext_t gc; + + gc = _cairo_xcb_screen_get_gc (surface->screen, + surface->drawable, + surface->depth); + pixmap = _cairo_xcb_connection_create_pixmap (connection, + surface->depth, + surface->drawable, + width, height); + + /* XXX IncludeInferiors? */ + _cairo_xcb_connection_copy_area (connection, + surface->drawable, + pixmap, gc, + x, y, + 0, 0, + width, height); + + _cairo_xcb_screen_put_gc (surface->screen, surface->depth, gc); + + reply = _cairo_xcb_connection_get_image (connection, + pixmap, + 0, 0, + width, height); + xcb_free_pixmap (connection->xcb_connection, pixmap); + } + + if (unlikely (reply == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto FAIL; + } + + /* XXX byte swap */ + /* XXX format conversion */ + assert (reply->depth == surface->depth); + + image = _cairo_image_surface_create_with_pixman_format + (xcb_get_image_data (reply), + surface->pixman_format, + width, height, + CAIRO_STRIDE_FOR_WIDTH_BPP (width, + PIXMAN_FORMAT_BPP (surface->pixman_format))); + status = image->status; + if (unlikely (status)) { + free (reply); + goto FAIL; + } + + /* XXX */ + pixman_image_set_destroy_function (((cairo_image_surface_t *)image)->pixman_image, _destroy_image, reply); + + _cairo_xcb_connection_release (connection); + + return image; + +FAIL: + _cairo_xcb_connection_release (connection); + return _cairo_surface_create_in_error (status); +} + +static cairo_surface_t * +_cairo_xcb_surface_source (void *abstract_surface, + cairo_rectangle_int_t *extents) +{ + cairo_xcb_surface_t *surface = abstract_surface; + + if (extents) { + extents->x = extents->y = 0; + extents->width = surface->width; + extents->height = surface->height; + } + + return &surface->base; +} + +static cairo_status_t +_cairo_xcb_surface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) +{ + cairo_xcb_surface_t *surface = abstract_surface; + cairo_surface_t *image; + + if (surface->fallback != NULL) { + image = cairo_surface_reference (&surface->fallback->base); + goto DONE; + } + + image = _cairo_surface_has_snapshot (&surface->base, + &_cairo_image_surface_backend); + if (image != NULL) { + image = cairo_surface_reference (image); + goto DONE; + } + + image = _get_image (surface, FALSE, 0, 0, surface->width, surface->height); + if (unlikely (image->status)) + return image->status; + + _cairo_surface_attach_snapshot (&surface->base, image, NULL); + +DONE: + *image_out = (cairo_image_surface_t *) image; + *image_extra = NULL; + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_xcb_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) +{ + cairo_surface_destroy (&image->base); +} + +cairo_bool_t +_cairo_xcb_surface_get_extents (void *abstract_surface, + cairo_rectangle_int_t *extents) +{ + cairo_xcb_surface_t *surface = abstract_surface; + + extents->x = extents->y = 0; + extents->width = surface->width; + extents->height = surface->height; + return TRUE; +} + +static void +_cairo_xcb_surface_get_font_options (void *abstract_surface, + cairo_font_options_t *options) +{ + cairo_xcb_surface_t *surface = abstract_surface; + + *options = *_cairo_xcb_screen_get_font_options (surface->screen); +} + +static cairo_status_t +_put_shm_image (cairo_xcb_surface_t *surface, + xcb_gcontext_t gc, + cairo_image_surface_t *image) +{ +#if CAIRO_HAS_XCB_SHM_FUNCTIONS + cairo_xcb_shm_info_t *shm_info; + + shm_info = _cairo_user_data_array_get_data (&image->base.user_data, + (const cairo_user_data_key_t *) surface->connection); + if (shm_info == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + _cairo_xcb_connection_shm_put_image (surface->connection, + surface->drawable, + gc, + surface->width, surface->height, + 0, 0, + image->width, image->height, + image->base.device_transform_inverse.x0, + image->base.device_transform_inverse.y0, + image->depth, + shm_info->shm, + shm_info->offset); + + return CAIRO_STATUS_SUCCESS; +#else + return CAIRO_INT_STATUS_UNSUPPORTED; +#endif +} + +static cairo_status_t +_put_image (cairo_xcb_surface_t *surface, + cairo_image_surface_t *image) +{ + cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; + + /* XXX track damaged region? */ + + status = _cairo_xcb_connection_acquire (surface->connection); + if (unlikely (status)) + return status; + + if (image->pixman_format == surface->pixman_format) { + xcb_gcontext_t gc; + + assert (image->depth == surface->depth); + assert (image->stride == (int) CAIRO_STRIDE_FOR_WIDTH_BPP (image->width, PIXMAN_FORMAT_BPP (image->pixman_format))); + + gc = _cairo_xcb_screen_get_gc (surface->screen, + surface->drawable, + surface->depth); + + status = _put_shm_image (surface, gc, image); + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + _cairo_xcb_connection_put_image (surface->connection, + surface->drawable, gc, + image->width, image->height, + image->base.device_transform_inverse.x0, + image->base.device_transform_inverse.y0, + image->depth, + image->stride, + image->data); + status = CAIRO_STATUS_SUCCESS; + } + + _cairo_xcb_screen_put_gc (surface->screen, surface->depth, gc); + } else { + ASSERT_NOT_REACHED; + } + + _cairo_xcb_connection_release (surface->connection); + return status; +} + +static cairo_int_status_t +_put_shm_image_boxes (cairo_xcb_surface_t *surface, + cairo_image_surface_t *image, + xcb_gcontext_t gc, + cairo_boxes_t *boxes) +{ +#if CAIRO_HAS_XCB_SHM_FUNCTIONS + cairo_xcb_shm_info_t *shm_info; + + shm_info = _cairo_user_data_array_get_data (&image->base.user_data, + (const cairo_user_data_key_t *) surface->connection); + if (shm_info != NULL) { + struct _cairo_boxes_chunk *chunk; + + for (chunk = &boxes->chunks; chunk; chunk = chunk->next) { + int i; + + for (i = 0; i < chunk->count; i++) { + cairo_box_t *b = &chunk->base[i]; + int x = _cairo_fixed_integer_part (b->p1.x); + int y = _cairo_fixed_integer_part (b->p1.y); + int width = _cairo_fixed_integer_part (b->p2.x - b->p1.x); + int height = _cairo_fixed_integer_part (b->p2.y - b->p1.y); + + _cairo_xcb_connection_shm_put_image (surface->connection, + surface->drawable, + gc, + surface->width, surface->height, + x, y, + width, height, + x, y, + image->depth, + shm_info->shm, + shm_info->offset); + } + } + return CAIRO_INT_STATUS_SUCCESS; + } +#endif + + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_status_t +_put_image_boxes (cairo_xcb_surface_t *surface, + cairo_image_surface_t *image, + cairo_boxes_t *boxes) +{ + cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; + xcb_gcontext_t gc; + + if (boxes->num_boxes == 0) + return CAIRO_STATUS_SUCCESS; + + /* XXX track damaged region? */ + + status = _cairo_xcb_connection_acquire (surface->connection); + if (unlikely (status)) + return status; + + assert (image->pixman_format == surface->pixman_format); + assert (image->depth == surface->depth); + assert (image->stride == (int) CAIRO_STRIDE_FOR_WIDTH_BPP (image->width, PIXMAN_FORMAT_BPP (image->pixman_format))); + + gc = _cairo_xcb_screen_get_gc (surface->screen, + surface->drawable, + surface->depth); + + status = _put_shm_image_boxes (surface, image, gc, boxes); + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + struct _cairo_boxes_chunk *chunk; + + for (chunk = &boxes->chunks; chunk; chunk = chunk->next) { + int i; + + for (i = 0; i < chunk->count; i++) { + cairo_box_t *b = &chunk->base[i]; + int x = _cairo_fixed_integer_part (b->p1.x); + int y = _cairo_fixed_integer_part (b->p1.y); + int width = _cairo_fixed_integer_part (b->p2.x - b->p1.x); + int height = _cairo_fixed_integer_part (b->p2.y - b->p1.y); + _cairo_xcb_connection_put_subimage (surface->connection, + surface->drawable, gc, + x, y, + width, height, + PIXMAN_FORMAT_BPP (image->pixman_format) / 8, + image->stride, + x, y, + image->depth, + image->data); + + } + } + status = CAIRO_STATUS_SUCCESS; + } + + _cairo_xcb_screen_put_gc (surface->screen, surface->depth, gc); + _cairo_xcb_connection_release (surface->connection); + return status; +} + +static cairo_status_t +_cairo_xcb_surface_flush (void *abstract_surface, + unsigned flags) +{ + cairo_xcb_surface_t *surface = abstract_surface; + cairo_status_t status; + + if (flags) + return CAIRO_STATUS_SUCCESS; + + if (likely (surface->fallback == NULL)) { + status = CAIRO_STATUS_SUCCESS; + if (! surface->base.finished && surface->deferred_clear) + status = _cairo_xcb_surface_clear (surface); + + return status; + } + + status = surface->base.status; + if (status == CAIRO_STATUS_SUCCESS && + (! surface->base._finishing || ! surface->owns_pixmap)) { + status = cairo_surface_status (&surface->fallback->base); + + if (status == CAIRO_STATUS_SUCCESS) + status = _cairo_bentley_ottmann_tessellate_boxes (&surface->fallback_damage, + CAIRO_FILL_RULE_WINDING, + &surface->fallback_damage); + + if (status == CAIRO_STATUS_SUCCESS) + status = _put_image_boxes (surface, + surface->fallback, + &surface->fallback_damage); + + if (status == CAIRO_STATUS_SUCCESS && ! surface->base._finishing) { + _cairo_surface_attach_snapshot (&surface->base, + &surface->fallback->base, + cairo_surface_finish); + } + } + + _cairo_boxes_clear (&surface->fallback_damage); + cairo_surface_destroy (&surface->fallback->base); + surface->fallback = NULL; + + return status; +} + +static cairo_image_surface_t * +_cairo_xcb_surface_map_to_image (void *abstract_surface, + const cairo_rectangle_int_t *extents) +{ + cairo_xcb_surface_t *surface = abstract_surface; + cairo_surface_t *image; + cairo_status_t status; + + if (surface->fallback) + return _cairo_surface_map_to_image (&surface->fallback->base, extents); + + image = _get_image (surface, TRUE, + extents->x, extents->y, + extents->width, extents->height); + status = cairo_surface_status (image); + if (unlikely (status)) { + cairo_surface_destroy(image); + return _cairo_image_surface_create_in_error (status); + } + + /* Do we have a deferred clear and this image surface does NOT cover the + * whole xcb surface? Have to apply the clear in that case, else + * uploading the image will handle the problem for us. + */ + if (surface->deferred_clear && + ! (extents->width == surface->width && + extents->height == surface->height)) { + status = _cairo_xcb_surface_clear (surface); + if (unlikely (status)) { + cairo_surface_destroy(image); + return _cairo_image_surface_create_in_error (status); + } + } + surface->deferred_clear = FALSE; + + cairo_surface_set_device_offset (image, -extents->x, -extents->y); + return (cairo_image_surface_t *) image; +} + +static cairo_int_status_t +_cairo_xcb_surface_unmap (void *abstract_surface, + cairo_image_surface_t *image) +{ + cairo_xcb_surface_t *surface = abstract_surface; + cairo_int_status_t status; + + if (surface->fallback) + return _cairo_surface_unmap_image (&surface->fallback->base, image); + + status = _put_image (abstract_surface, image); + + cairo_surface_finish (&image->base); + cairo_surface_destroy (&image->base); + + return status; +} + +static cairo_surface_t * +_cairo_xcb_surface_fallback (cairo_xcb_surface_t *surface, + cairo_composite_rectangles_t *composite) +{ + cairo_image_surface_t *image; + cairo_status_t status; + + status = _cairo_composite_rectangles_add_to_damage (composite, + &surface->fallback_damage); + if (unlikely (status)) + return _cairo_surface_create_in_error (status); + + if (surface->fallback) + return &surface->fallback->base; + + image = (cairo_image_surface_t *) + _get_image (surface, TRUE, 0, 0, surface->width, surface->height); + + if (image->base.status != CAIRO_STATUS_SUCCESS) + return &image->base; + + /* If there was a deferred clear, _get_image applied it */ + surface->deferred_clear = FALSE; + + surface->fallback = image; + + return &surface->fallback->base; +} + +static cairo_int_status_t +_cairo_xcb_fallback_compositor_paint (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *extents) +{ + cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) extents->surface; + cairo_surface_t *fallback = _cairo_xcb_surface_fallback (surface, extents); + + return _cairo_surface_paint (fallback, extents->op, + &extents->source_pattern.base, + extents->clip); +} + +static cairo_int_status_t +_cairo_xcb_fallback_compositor_mask (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *extents) +{ + cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) extents->surface; + cairo_surface_t *fallback = _cairo_xcb_surface_fallback (surface, extents); + + return _cairo_surface_mask (fallback, extents->op, + &extents->source_pattern.base, + &extents->mask_pattern.base, + extents->clip); +} + +static cairo_int_status_t +_cairo_xcb_fallback_compositor_stroke (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *extents, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) extents->surface; + cairo_surface_t *fallback = _cairo_xcb_surface_fallback (surface, extents); + + return _cairo_surface_stroke (fallback, extents->op, + &extents->source_pattern.base, + path, style, ctm, ctm_inverse, + tolerance, antialias, + extents->clip); +} + +static cairo_int_status_t +_cairo_xcb_fallback_compositor_fill (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *extents, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) extents->surface; + cairo_surface_t *fallback = _cairo_xcb_surface_fallback (surface, extents); + + return _cairo_surface_fill (fallback, extents->op, + &extents->source_pattern.base, + path, fill_rule, tolerance, + antialias, extents->clip); +} + +static cairo_int_status_t +_cairo_xcb_fallback_compositor_glyphs (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *extents, + cairo_scaled_font_t *scaled_font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_bool_t overlap) +{ + cairo_xcb_surface_t *surface = (cairo_xcb_surface_t *) extents->surface; + cairo_surface_t *fallback = _cairo_xcb_surface_fallback (surface, extents); + + return _cairo_surface_show_text_glyphs (fallback, extents->op, + &extents->source_pattern.base, + NULL, 0, glyphs, num_glyphs, + NULL, 0, 0, + scaled_font, extents->clip); +} + +static const cairo_compositor_t _cairo_xcb_fallback_compositor = { + &__cairo_no_compositor, + + _cairo_xcb_fallback_compositor_paint, + _cairo_xcb_fallback_compositor_mask, + _cairo_xcb_fallback_compositor_stroke, + _cairo_xcb_fallback_compositor_fill, + _cairo_xcb_fallback_compositor_glyphs, +}; + +static const cairo_compositor_t _cairo_xcb_render_compositor = { + &_cairo_xcb_fallback_compositor, + + _cairo_xcb_render_compositor_paint, + _cairo_xcb_render_compositor_mask, + _cairo_xcb_render_compositor_stroke, + _cairo_xcb_render_compositor_fill, + _cairo_xcb_render_compositor_glyphs, +}; + +static inline const cairo_compositor_t * +get_compositor (cairo_surface_t **s) +{ + cairo_xcb_surface_t *surface = (cairo_xcb_surface_t * )*s; + if (surface->fallback) { + *s = &surface->fallback->base; + return ((cairo_image_surface_t *) *s)->compositor; + } + + return &_cairo_xcb_render_compositor; +} + +static cairo_int_status_t +_cairo_xcb_surface_paint (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip) +{ + cairo_surface_t *surface = abstract_surface; + const cairo_compositor_t *compositor = get_compositor (&surface); + return _cairo_compositor_paint (compositor, surface, op, source, clip); +} + +static cairo_int_status_t +_cairo_xcb_surface_mask (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_clip_t *clip) +{ + cairo_surface_t *surface = abstract_surface; + const cairo_compositor_t *compositor = get_compositor (&surface); + return _cairo_compositor_mask (compositor, surface, op, source, mask, clip); +} + +static cairo_int_status_t +_cairo_xcb_surface_stroke (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_surface_t *surface = abstract_surface; + const cairo_compositor_t *compositor = get_compositor (&surface); + return _cairo_compositor_stroke (compositor, surface, op, source, + path, style, ctm, ctm_inverse, + tolerance, antialias, clip); +} + +static cairo_int_status_t +_cairo_xcb_surface_fill (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t*path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_surface_t *surface = abstract_surface; + const cairo_compositor_t *compositor = get_compositor (&surface); + return _cairo_compositor_fill (compositor, surface, op, + source, path, fill_rule, + tolerance, antialias, clip); +} + +static cairo_int_status_t +_cairo_xcb_surface_glyphs (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip) +{ + cairo_surface_t *surface = abstract_surface; + const cairo_compositor_t *compositor = get_compositor (&surface); + return _cairo_compositor_glyphs (compositor, surface, op, + source, glyphs, num_glyphs, + scaled_font, clip); +} + +const cairo_surface_backend_t _cairo_xcb_surface_backend = { + CAIRO_SURFACE_TYPE_XCB, + _cairo_xcb_surface_finish, + _cairo_default_context_create, + + _cairo_xcb_surface_create_similar, + _cairo_xcb_surface_create_similar_image, + _cairo_xcb_surface_map_to_image, + _cairo_xcb_surface_unmap, + + _cairo_xcb_surface_source, + _cairo_xcb_surface_acquire_source_image, + _cairo_xcb_surface_release_source_image, + NULL, /* snapshot */ + + + NULL, /* copy_page */ + NULL, /* show_page */ + + _cairo_xcb_surface_get_extents, + _cairo_xcb_surface_get_font_options, + + _cairo_xcb_surface_flush, + NULL, + + _cairo_xcb_surface_paint, + _cairo_xcb_surface_mask, + _cairo_xcb_surface_stroke, + _cairo_xcb_surface_fill, + NULL, /* fill-stroke */ + _cairo_xcb_surface_glyphs, +}; + +cairo_surface_t * +_cairo_xcb_surface_create_internal (cairo_xcb_screen_t *screen, + xcb_drawable_t drawable, + cairo_bool_t owns_pixmap, + pixman_format_code_t pixman_format, + xcb_render_pictformat_t xrender_format, + int width, + int height) +{ + cairo_xcb_surface_t *surface; + + surface = _cairo_calloc (sizeof (cairo_xcb_surface_t)); + if (unlikely (surface == NULL)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + _cairo_surface_init (&surface->base, + &_cairo_xcb_surface_backend, + &screen->connection->device, + _cairo_content_from_pixman_format (pixman_format), + FALSE); /* is_vector */ + + surface->connection = _cairo_xcb_connection_reference (screen->connection); + surface->screen = screen; + cairo_list_add (&surface->link, &screen->surfaces); + + surface->drawable = drawable; + surface->owns_pixmap = owns_pixmap; + + surface->deferred_clear = FALSE; + surface->deferred_clear_color = *CAIRO_COLOR_TRANSPARENT; + + surface->width = width; + surface->height = height; + surface->depth = PIXMAN_FORMAT_DEPTH (pixman_format); + + surface->picture = XCB_NONE; + if (screen->connection->force_precision != -1) + surface->precision = screen->connection->force_precision; + else + surface->precision = XCB_RENDER_POLY_MODE_IMPRECISE; + + surface->pixman_format = pixman_format; + surface->xrender_format = xrender_format; + + surface->fallback = NULL; + _cairo_boxes_init (&surface->fallback_damage); + + return &surface->base; +} + +static xcb_screen_t * +_cairo_xcb_screen_from_visual (xcb_connection_t *connection, + xcb_visualtype_t *visual, + int *depth) +{ + xcb_depth_iterator_t d; + xcb_screen_iterator_t s; + + s = xcb_setup_roots_iterator (xcb_get_setup (connection)); + for (; s.rem; xcb_screen_next (&s)) { + if (s.data->root_visual == visual->visual_id) { + *depth = s.data->root_depth; + return s.data; + } + + d = xcb_screen_allowed_depths_iterator(s.data); + for (; d.rem; xcb_depth_next (&d)) { + xcb_visualtype_iterator_t v = xcb_depth_visuals_iterator (d.data); + + for (; v.rem; xcb_visualtype_next (&v)) { + if (v.data->visual_id == visual->visual_id) { + *depth = d.data->depth; + return s.data; + } + } + } + } + + return NULL; +} + +/** + * cairo_xcb_surface_create: + * @connection: an XCB connection + * @drawable: an XCB drawable + * @visual: the visual to use for drawing to @drawable. The depth + * of the visual must match the depth of the drawable. + * Currently, only TrueColor visuals are fully supported. + * @width: the current width of @drawable + * @height: the current height of @drawable + * + * Creates an XCB surface that draws to the given drawable. + * The way that colors are represented in the drawable is specified + * by the provided visual. + * + * Note: If @drawable is a Window, then the function + * cairo_xcb_surface_set_size() must be called whenever the size of the + * window changes. + * + * When @drawable is a Window containing child windows then drawing to + * the created surface will be clipped by those child windows. When + * the created surface is used as a source, the contents of the + * children will be included. + * + * Return value: a pointer to the newly created surface. The caller + * owns the surface and should call cairo_surface_destroy() when done + * with it. + * + * This function always returns a valid pointer, but it will return a + * pointer to a "nil" surface if an error such as out of memory + * occurs. You can use cairo_surface_status() to check for this. + * + * Since: 1.12 + **/ +cairo_surface_t * +cairo_xcb_surface_create (xcb_connection_t *connection, + xcb_drawable_t drawable, + xcb_visualtype_t *visual, + int width, + int height) +{ + cairo_xcb_screen_t *screen; + xcb_screen_t *xcb_screen; + cairo_format_masks_t image_masks; + pixman_format_code_t pixman_format; + xcb_render_pictformat_t xrender_format; + int depth; + + if (xcb_connection_has_error (connection)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_WRITE_ERROR)); + + if (unlikely (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); + if (unlikely (width <= 0 || height <= 0)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); + + xcb_screen = _cairo_xcb_screen_from_visual (connection, visual, &depth); + if (unlikely (xcb_screen == NULL)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL)); + + image_masks.alpha_mask = 0; + image_masks.red_mask = visual->red_mask; + image_masks.green_mask = visual->green_mask; + image_masks.blue_mask = visual->blue_mask; + if (depth == 32) /* XXX visuals have no alpha! */ + image_masks.alpha_mask = + 0xffffffff & ~(visual->red_mask | visual->green_mask | visual->blue_mask); + if (depth > 16) + image_masks.bpp = 32; + else if (depth > 8) + image_masks.bpp = 16; + else if (depth > 1) + image_masks.bpp = 8; + else + image_masks.bpp = 1; + + if (! _pixman_format_from_masks (&image_masks, &pixman_format)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); + + screen = _cairo_xcb_screen_get (connection, xcb_screen); + if (unlikely (screen == NULL)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + xrender_format = + _cairo_xcb_connection_get_xrender_format_for_visual (screen->connection, + visual->visual_id); + + return _cairo_xcb_surface_create_internal (screen, drawable, FALSE, + pixman_format, + xrender_format, + width, height); +} + +/** + * cairo_xcb_surface_create_for_bitmap: + * @connection: an XCB connection + * @screen: the XCB screen associated with @bitmap + * @bitmap: an XCB drawable (a Pixmap with depth 1) + * @width: the current width of @bitmap + * @height: the current height of @bitmap + * + * Creates an XCB surface that draws to the given bitmap. + * This will be drawn to as a %CAIRO_FORMAT_A1 object. + * + * Return value: a pointer to the newly created surface. The caller + * owns the surface and should call cairo_surface_destroy() when done + * with it. + * + * This function always returns a valid pointer, but it will return a + * pointer to a "nil" surface if an error such as out of memory + * occurs. You can use cairo_surface_status() to check for this. + * + * Since: 1.12 + **/ +cairo_surface_t * +cairo_xcb_surface_create_for_bitmap (xcb_connection_t *connection, + xcb_screen_t *screen, + xcb_pixmap_t bitmap, + int width, + int height) +{ + cairo_xcb_screen_t *cairo_xcb_screen; + + if (xcb_connection_has_error (connection)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_WRITE_ERROR)); + + if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); + if (unlikely (width <= 0 || height <= 0)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); + + cairo_xcb_screen = _cairo_xcb_screen_get (connection, screen); + if (unlikely (cairo_xcb_screen == NULL)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + return _cairo_xcb_surface_create_internal (cairo_xcb_screen, bitmap, FALSE, + PIXMAN_a1, + cairo_xcb_screen->connection->standard_formats[CAIRO_FORMAT_A1], + width, height); +} + +/** + * cairo_xcb_surface_create_with_xrender_format: + * @connection: an XCB connection + * @drawable: an XCB drawable + * @screen: the XCB screen associated with @drawable + * @format: the picture format to use for drawing to @drawable. The + * depth of @format mush match the depth of the drawable. + * @width: the current width of @drawable + * @height: the current height of @drawable + * + * Creates an XCB surface that draws to the given drawable. + * The way that colors are represented in the drawable is specified + * by the provided picture format. + * + * Note: If @drawable is a Window, then the function + * cairo_xcb_surface_set_size() must be called whenever the size of the + * window changes. + * + * When @drawable is a Window containing child windows then drawing to + * the created surface will be clipped by those child windows. When + * the created surface is used as a source, the contents of the + * children will be included. + * + * Return value: a pointer to the newly created surface. The caller + * owns the surface and should call cairo_surface_destroy() when done + * with it. + * + * This function always returns a valid pointer, but it will return a + * pointer to a "nil" surface if an error such as out of memory + * occurs. You can use cairo_surface_status() to check for this. + * + * Since: 1.12 + **/ +cairo_surface_t * +cairo_xcb_surface_create_with_xrender_format (xcb_connection_t *connection, + xcb_screen_t *screen, + xcb_drawable_t drawable, + xcb_render_pictforminfo_t *format, + int width, + int height) +{ + cairo_xcb_screen_t *cairo_xcb_screen; + cairo_format_masks_t image_masks; + pixman_format_code_t pixman_format; + + if (xcb_connection_has_error (connection)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_WRITE_ERROR)); + + if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); + if (unlikely (width <= 0 || height <= 0)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); + + image_masks.alpha_mask = + (unsigned long) format->direct.alpha_mask << format->direct.alpha_shift; + image_masks.red_mask = + (unsigned long) format->direct.red_mask << format->direct.red_shift; + image_masks.green_mask = + (unsigned long) format->direct.green_mask << format->direct.green_shift; + image_masks.blue_mask = + (unsigned long) format->direct.blue_mask << format->direct.blue_shift; +#if 0 + image_masks.bpp = format->depth; +#else + if (format->depth > 16) + image_masks.bpp = 32; + else if (format->depth > 8) + image_masks.bpp = 16; + else if (format->depth > 1) + image_masks.bpp = 8; + else + image_masks.bpp = 1; +#endif + + if (! _pixman_format_from_masks (&image_masks, &pixman_format)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); + + cairo_xcb_screen = _cairo_xcb_screen_get (connection, screen); + if (unlikely (cairo_xcb_screen == NULL)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + return _cairo_xcb_surface_create_internal (cairo_xcb_screen, + drawable, + FALSE, + pixman_format, + format->id, + width, height); +} + +/* This does the necessary fixup when a surface's drawable or size changed. */ +static void +_drawable_changed (cairo_xcb_surface_t *surface) +{ + _cairo_surface_set_error (&surface->base, + _cairo_surface_begin_modification (&surface->base)); + _cairo_boxes_clear (&surface->fallback_damage); + cairo_surface_destroy (&surface->fallback->base); + + surface->deferred_clear = FALSE; + surface->fallback = NULL; +} + +/** + * cairo_xcb_surface_set_size: + * @surface: a #cairo_surface_t for the XCB backend + * @width: the new width of the surface + * @height: the new height of the surface + * + * Informs cairo of the new size of the XCB drawable underlying the + * surface. For a surface created for a window (rather than a pixmap), + * this function must be called each time the size of the window + * changes. (For a subwindow, you are normally resizing the window + * yourself, but for a toplevel window, it is necessary to listen for + * ConfigureNotify events.) + * + * A pixmap can never change size, so it is never necessary to call + * this function on a surface created for a pixmap. + * + * If cairo_surface_flush() wasn't called, some pending operations + * might be discarded. + * + * Since: 1.12 + **/ +void +cairo_xcb_surface_set_size (cairo_surface_t *abstract_surface, + int width, + int height) +{ + cairo_xcb_surface_t *surface; + + if (unlikely (abstract_surface->status)) + return; + if (unlikely (abstract_surface->finished)) { + _cairo_surface_set_error (abstract_surface, + _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + return; + } + + + if ( !_cairo_surface_is_xcb(abstract_surface)) { + _cairo_surface_set_error (abstract_surface, + _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); + return; + } + + if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX || width <= 0 || height <= 0) { + _cairo_surface_set_error (abstract_surface, + _cairo_error (CAIRO_STATUS_INVALID_SIZE)); + return; + } + + surface = (cairo_xcb_surface_t *) abstract_surface; + + _drawable_changed(surface); + surface->width = width; + surface->height = height; +} + +/** + * cairo_xcb_surface_set_drawable: + * @surface: a #cairo_surface_t for the XCB backend + * @drawable: the new drawable of the surface + * @width: the new width of the surface + * @height: the new height of the surface + * + * Informs cairo of the new drawable and size of the XCB drawable underlying the + * surface. + * + * If cairo_surface_flush() wasn't called, some pending operations + * might be discarded. + * + * Since: 1.12 + **/ +void +cairo_xcb_surface_set_drawable (cairo_surface_t *abstract_surface, + xcb_drawable_t drawable, + int width, + int height) +{ + cairo_xcb_surface_t *surface; + + if (unlikely (abstract_surface->status)) + return; + if (unlikely (abstract_surface->finished)) { + _cairo_surface_set_error (abstract_surface, + _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + return; + } + + + if ( !_cairo_surface_is_xcb(abstract_surface)) { + _cairo_surface_set_error (abstract_surface, + _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); + return; + } + + if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX || width <= 0 || height <= 0) { + _cairo_surface_set_error (abstract_surface, + _cairo_error (CAIRO_STATUS_INVALID_SIZE)); + return; + } + + surface = (cairo_xcb_surface_t *) abstract_surface; + + /* XXX: and what about this case? */ + if (surface->owns_pixmap) + return; + + _drawable_changed (surface); + + if (surface->drawable != drawable) { + cairo_status_t status; + status = _cairo_xcb_connection_acquire (surface->connection); + if (unlikely (status)) + return; + + if (surface->picture != XCB_NONE) { + _cairo_xcb_connection_render_free_picture (surface->connection, + surface->picture); + surface->picture = XCB_NONE; + } + + _cairo_xcb_connection_release (surface->connection); + + surface->drawable = drawable; + } + surface->width = width; + surface->height = height; +} diff --git a/local/recipes/libs/cairo/source/src/cairo-xcb.h b/local/recipes/libs/cairo/source/src/cairo-xcb.h new file mode 100644 index 0000000000..e321d8482c --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-xcb.h @@ -0,0 +1,116 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2009 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Chris Wilson + */ + +#ifndef CAIRO_XCB_H +#define CAIRO_XCB_H + +#include "cairo.h" + +#if CAIRO_HAS_XCB_SURFACE + +#include +#include + +CAIRO_BEGIN_DECLS + +cairo_public cairo_surface_t * +cairo_xcb_surface_create (xcb_connection_t *connection, + xcb_drawable_t drawable, + xcb_visualtype_t *visual, + int width, + int height); + +cairo_public cairo_surface_t * +cairo_xcb_surface_create_for_bitmap (xcb_connection_t *connection, + xcb_screen_t *screen, + xcb_pixmap_t bitmap, + int width, + int height); + +cairo_public cairo_surface_t * +cairo_xcb_surface_create_with_xrender_format (xcb_connection_t *connection, + xcb_screen_t *screen, + xcb_drawable_t drawable, + xcb_render_pictforminfo_t *format, + int width, + int height); + +cairo_public void +cairo_xcb_surface_set_size (cairo_surface_t *surface, + int width, + int height); + +cairo_public void +cairo_xcb_surface_set_drawable (cairo_surface_t *surface, + xcb_drawable_t drawable, + int width, + int height); + +cairo_public xcb_connection_t * +cairo_xcb_device_get_connection (cairo_device_t *device); + +/* debug interface */ + +cairo_public void +cairo_xcb_device_debug_cap_xshm_version (cairo_device_t *device, + int major_version, + int minor_version); + +cairo_public void +cairo_xcb_device_debug_cap_xrender_version (cairo_device_t *device, + int major_version, + int minor_version); + +/* + * @precision: -1 implies automatically choose based on antialiasing mode, + * any other value overrides and sets the corresponding PolyMode. + */ +cairo_public void +cairo_xcb_device_debug_set_precision (cairo_device_t *device, + int precision); + +cairo_public int +cairo_xcb_device_debug_get_precision (cairo_device_t *device); + +CAIRO_END_DECLS + +#else /* CAIRO_HAS_XCB_SURFACE */ +# error Cairo was not compiled with support for the xcb backend +#endif /* CAIRO_HAS_XCB_SURFACE */ + +#endif /* CAIRO_XCB_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-xlib-core-compositor.c b/local/recipes/libs/cairo/source/src/cairo-xlib-core-compositor.c new file mode 100644 index 0000000000..1392999617 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-xlib-core-compositor.c @@ -0,0 +1,653 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Behdad Esfahbod + * Chris Wilson + * Karl Tomlinson , Mozilla Corporation + */ + +/* The original X drawing API was very restrictive in what it could handle, + * pixel-aligned fill/blits are all that map into Cairo's drawing model. + */ + +#include "cairoint.h" + +#if !CAIRO_HAS_XLIB_XCB_FUNCTIONS + +#include "cairo-xlib-private.h" +#include "cairo-xlib-surface-private.h" + +#include "cairo-boxes-private.h" +#include "cairo-clip-inline.h" +#include "cairo-compositor-private.h" +#include "cairo-image-surface-private.h" +#include "cairo-pattern-private.h" +#include "cairo-region-private.h" +#include "cairo-surface-offset-private.h" + +/* the low-level interface */ + +static cairo_int_status_t +acquire (void *abstract_dst) +{ + cairo_xlib_surface_t *dst = abstract_dst; + return _cairo_xlib_display_acquire (dst->base.device, &dst->display); +} + +static cairo_int_status_t +release (void *abstract_dst) +{ + cairo_xlib_surface_t *dst = abstract_dst; + + cairo_device_release (&dst->display->base); + dst->display = NULL; + + return CAIRO_STATUS_SUCCESS; +} + +struct _fill_box { + Display *dpy; + Drawable drawable; + GC gc; + //cairo_surface_t *dither = NULL; +}; + +static cairo_bool_t fill_box (cairo_box_t *box, void *closure) +{ + struct _fill_box *data = closure; + int x = _cairo_fixed_integer_part (box->p1.x); + int y = _cairo_fixed_integer_part (box->p1.y); + int width = _cairo_fixed_integer_part (box->p2.x - box->p1.x); + int height = _cairo_fixed_integer_part (box->p2.y - box->p1.y); + + XFillRectangle (data->dpy, data->drawable, data->gc, x, y, width, height); + return TRUE; +} + +static void +_characterize_field (uint32_t mask, int *width, int *shift) +{ + *width = _cairo_popcount (mask); + /* The final '& 31' is to force a 0 mask to result in 0 shift. */ + *shift = _cairo_popcount ((mask - 1) & ~mask) & 31; +} + +static uint32_t +color_to_pixel (cairo_xlib_surface_t *dst, + const cairo_color_t *color) +{ + uint32_t rgba = 0; + int width, shift; + + _characterize_field (dst->a_mask, &width, &shift); + rgba |= color->alpha_short >> (16 - width) << shift; + + _characterize_field (dst->r_mask, &width, &shift); + rgba |= color->red_short >> (16 - width) << shift; + + _characterize_field (dst->g_mask, &width, &shift); + rgba |= color->green_short >> (16 - width) << shift; + + _characterize_field (dst->b_mask, &width, &shift); + rgba |= color->blue_short >> (16 - width) << shift; + + return rgba; +} + +static cairo_int_status_t +_fill_box_init (struct _fill_box *fb, + cairo_xlib_surface_t *dst, + const cairo_color_t *color) +{ + cairo_int_status_t status; + + status = _cairo_xlib_surface_get_gc (dst->display, dst, &fb->gc); + if (unlikely (status)) + return status; + + fb->dpy = dst->display->display; + fb->drawable = dst->drawable; + + if (dst->visual && dst->visual->class != TrueColor && 0) { +#if 0 + cairo_solid_pattern_t solid; + cairo_surface_attributes_t attrs; + + _cairo_pattern_init_solid (&solid, color); + status = _cairo_pattern_acquire_surface (&solid.base, &dst->base, + 0, 0, + ARRAY_LENGTH (dither_pattern[0]), + ARRAY_LENGTH (dither_pattern), + CAIRO_PATTERN_ACQUIRE_NONE, + &dither, + &attrs); + if (unlikely (status)) { + _cairo_xlib_surface_put_gc (dst->display, dst, fb.gc); + return status; + } + + XSetTSOrigin (fb->dpy, fb->gc, + - (dst->base.device_transform.x0 + attrs.x_offset), + - (dst->base.device_transform.y0 + attrs.y_offset)); + XSetTile (fb->dpy, fb->gc, ((cairo_xlib_surface_t *) dither)->drawable); +#endif + } else { + XGCValues gcv; + + gcv.foreground = color_to_pixel (dst, color); + gcv.fill_style = FillSolid; + + XChangeGC (fb->dpy, fb->gc, GCFillStyle | GCForeground, &gcv); + } + + return CAIRO_INT_STATUS_SUCCESS; +} + +static void +_fill_box_fini (struct _fill_box *fb, + cairo_xlib_surface_t *dst) +{ + _cairo_xlib_surface_put_gc (dst->display, dst, fb->gc); + //cairo_surface_destroy (fb->dither); +} + +cairo_int_status_t +_cairo_xlib_core_fill_boxes (cairo_xlib_surface_t *dst, + const cairo_color_t *color, + cairo_boxes_t *boxes) +{ + cairo_int_status_t status; + struct _fill_box fb; + + status = _fill_box_init (&fb, dst, color); + if (unlikely (status)) + return status; + + _cairo_boxes_for_each_box (boxes, fill_box, &fb); + + _fill_box_fini (&fb, dst); + return CAIRO_STATUS_SUCCESS; +} + +cairo_int_status_t +_cairo_xlib_core_fill_rectangles (cairo_xlib_surface_t *dst, + const cairo_color_t *color, + int num_rects, + cairo_rectangle_int_t *rects) +{ + cairo_int_status_t status; + struct _fill_box fb; + int i; + + status = _fill_box_init (&fb, dst, color); + if (unlikely (status)) + return status; + + for (i = 0; i < num_rects; i++) + XFillRectangle (fb.dpy, fb.drawable, fb.gc, + rects[i].x, rects[i].y, + rects[i].width, rects[i].height); + + _fill_box_fini (&fb, dst); + return CAIRO_STATUS_SUCCESS; +} + +struct _fallback_box { + cairo_xlib_surface_t *dst; + cairo_format_t format; + const cairo_pattern_t *pattern; +}; + +static cairo_bool_t fallback_box (cairo_box_t *box, void *closure) +{ + struct _fallback_box *data = closure; + int x = _cairo_fixed_integer_part (box->p1.x); + int y = _cairo_fixed_integer_part (box->p1.y); + int width = _cairo_fixed_integer_part (box->p2.x - box->p1.x); + int height = _cairo_fixed_integer_part (box->p2.y - box->p1.y); + cairo_surface_t *image; + cairo_status_t status; + + /* XXX for EXTEND_NONE and if the box is wholly outside we can just fill */ + + image = cairo_surface_create_similar_image (&data->dst->base, data->format, + width, height); + status = _cairo_surface_offset_paint (image, x, y, + CAIRO_OPERATOR_SOURCE, + data->pattern, NULL); + if (status == CAIRO_STATUS_SUCCESS) { + status = _cairo_xlib_surface_draw_image (data->dst, + (cairo_image_surface_t *)image, + 0, 0, + width, height, + x, y); + } + cairo_surface_destroy (image); + + return status == CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +fallback_boxes (cairo_xlib_surface_t *dst, + const cairo_pattern_t *pattern, + cairo_boxes_t *boxes) +{ + struct _fallback_box fb; + + /* XXX create_similar_image using pixman_format? */ + switch (dst->depth) { + case 8: fb.format = CAIRO_FORMAT_A8; break; + case 16: fb.format = CAIRO_FORMAT_RGB16_565; break; + case 24: fb.format = CAIRO_FORMAT_RGB24; break; + case 30: fb.format = CAIRO_FORMAT_RGB30; break; + case 32: fb.format = CAIRO_FORMAT_ARGB32; break; + default: return CAIRO_INT_STATUS_UNSUPPORTED; + } + + fb.dst = dst; + fb.pattern = pattern; + + if (! _cairo_boxes_for_each_box (boxes, fallback_box, &fb)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +render_boxes (cairo_xlib_surface_t *dst, + const cairo_pattern_t *pattern, + cairo_boxes_t *boxes) +{ + if (pattern->filter != CAIRO_FILTER_NEAREST) + return fallback_boxes (dst, pattern, boxes); + + switch (pattern->extend) { + default: + case CAIRO_EXTEND_NONE: + case CAIRO_EXTEND_REFLECT: + case CAIRO_EXTEND_PAD: + return fallback_boxes (dst, pattern, boxes); + + case CAIRO_EXTEND_REPEAT: /* XXX Use tiling */ + return fallback_boxes (dst, pattern, boxes); + } +} + +/* the mid-level: converts boxes into drawing operations */ + +struct _box_data { + Display *dpy; + cairo_xlib_surface_t *dst; + cairo_surface_t *src; + GC gc; + int tx, ty; + int width, height; +}; + +static cairo_bool_t source_contains_box (cairo_box_t *box, void *closure) +{ + struct _box_data *data = closure; + + /* The box is pixel-aligned so the truncation is safe. */ + return + _cairo_fixed_integer_part (box->p1.x) + data->tx >= 0 && + _cairo_fixed_integer_part (box->p1.y) + data->ty >= 0 && + _cairo_fixed_integer_part (box->p2.x) + data->tx <= data->width && + _cairo_fixed_integer_part (box->p2.y) + data->ty <= data->height; +} + +static cairo_bool_t image_upload_box (cairo_box_t *box, void *closure) +{ + const struct _box_data *iub = closure; + int x = _cairo_fixed_integer_part (box->p1.x); + int y = _cairo_fixed_integer_part (box->p1.y); + int width = _cairo_fixed_integer_part (box->p2.x - box->p1.x); + int height = _cairo_fixed_integer_part (box->p2.y - box->p1.y); + + return _cairo_xlib_surface_draw_image (iub->dst, + (cairo_image_surface_t *)iub->src, + x + iub->tx, y + iub->ty, + width, height, + x, y) == CAIRO_STATUS_SUCCESS; +} + +static cairo_bool_t +surface_matches_image_format (cairo_xlib_surface_t *surface, + cairo_image_surface_t *image) +{ + cairo_format_masks_t format; + + return (_pixman_format_to_masks (image->pixman_format, &format) && + (format.alpha_mask == surface->a_mask || surface->a_mask == 0) && + (format.red_mask == surface->r_mask || surface->r_mask == 0) && + (format.green_mask == surface->g_mask || surface->g_mask == 0) && + (format.blue_mask == surface->b_mask || surface->b_mask == 0)); +} + +static cairo_status_t +upload_image_inplace (cairo_xlib_surface_t *dst, + const cairo_pattern_t *source, + cairo_boxes_t *boxes) +{ + const cairo_surface_pattern_t *pattern; + struct _box_data iub; + cairo_image_surface_t *image; + + if (source->type != CAIRO_PATTERN_TYPE_SURFACE) + return CAIRO_INT_STATUS_UNSUPPORTED; + + pattern = (const cairo_surface_pattern_t *) source; + if (pattern->surface->type != CAIRO_SURFACE_TYPE_IMAGE) + return CAIRO_INT_STATUS_UNSUPPORTED; + + image = (cairo_image_surface_t *) pattern->surface; + if (image->format == CAIRO_FORMAT_INVALID) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (image->depth != dst->depth) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (! surface_matches_image_format (dst, image)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* XXX subsurface */ + + if (! _cairo_matrix_is_integer_translation (&source->matrix, + &iub.tx, &iub.ty)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + iub.dst = dst; + iub.src = &image->base; + iub.width = image->width; + iub.height = image->height; + + /* First check that the data is entirely within the image */ + if (! _cairo_boxes_for_each_box (boxes, source_contains_box, &iub)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (! _cairo_boxes_for_each_box (boxes, image_upload_box, &iub)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_bool_t copy_box (cairo_box_t *box, void *closure) +{ + const struct _box_data *cb = closure; + int x = _cairo_fixed_integer_part (box->p1.x); + int y = _cairo_fixed_integer_part (box->p1.y); + int width = _cairo_fixed_integer_part (box->p2.x - box->p1.x); + int height = _cairo_fixed_integer_part (box->p2.y - box->p1.y); + + XCopyArea (cb->dpy, + ((cairo_xlib_surface_t *)cb->src)->drawable, + cb->dst->drawable, + cb->gc, + x + cb->tx, y + cb->ty, + width, height, + x, y); + return TRUE; +} + +static cairo_status_t +copy_boxes (cairo_xlib_surface_t *dst, + const cairo_pattern_t *source, + cairo_boxes_t *boxes) +{ + const cairo_surface_pattern_t *pattern; + struct _box_data cb; + cairo_xlib_surface_t *src; + cairo_status_t status; + + if (source->type != CAIRO_PATTERN_TYPE_SURFACE) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* XXX subsurface */ + + pattern = (const cairo_surface_pattern_t *) source; + if (pattern->surface->backend->type != CAIRO_SURFACE_TYPE_XLIB) + return CAIRO_INT_STATUS_UNSUPPORTED; + + src = (cairo_xlib_surface_t *) pattern->surface; + if (src->depth != dst->depth) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* We can only have a single control for subwindow_mode on the + * GC. If we have a Window destination, we need to set ClipByChildren, + * but if we have a Window source, we need IncludeInferiors. If we have + * both a Window destination and source, we must fallback. There is + * no convenient way to detect if a drawable is a Pixmap or Window, + * therefore we can only rely on those surfaces that we created + * ourselves to be Pixmaps, and treat everything else as a potential + * Window. + */ + if (! src->owns_pixmap && ! dst->owns_pixmap) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (! _cairo_xlib_surface_same_screen (dst, src)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (! _cairo_matrix_is_integer_translation (&source->matrix, + &cb.tx, &cb.ty)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + cb.dpy = dst->display->display; + cb.dst = dst; + cb.src = &src->base; + cb.width = src->width; + cb.height = src->height; + + /* First check that the data is entirely within the image */ + if (! _cairo_boxes_for_each_box (boxes, source_contains_box, &cb)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_xlib_surface_get_gc (dst->display, dst, &cb.gc); + if (unlikely (status)) + return status; + + if (! src->owns_pixmap) { + XGCValues gcv; + + gcv.subwindow_mode = IncludeInferiors; + XChangeGC (dst->display->display, cb.gc, GCSubwindowMode, &gcv); + } + + status = CAIRO_STATUS_SUCCESS; + if (! _cairo_boxes_for_each_box (boxes, copy_box, &cb)) + status = CAIRO_INT_STATUS_UNSUPPORTED; + + if (! src->owns_pixmap) { + XGCValues gcv; + + gcv.subwindow_mode = ClipByChildren; + XChangeGC (dst->display->display, cb.gc, GCSubwindowMode, &gcv); + } + + _cairo_xlib_surface_put_gc (dst->display, dst, cb.gc); + + return status; +} + +static cairo_status_t +draw_boxes (cairo_composite_rectangles_t *extents, + cairo_boxes_t *boxes) +{ + cairo_xlib_surface_t *dst = (cairo_xlib_surface_t *)extents->surface; + cairo_operator_t op = extents->op; + const cairo_pattern_t *src = &extents->source_pattern.base; + cairo_int_status_t status; + + if (boxes->num_boxes == 0 && extents->is_bounded) + return CAIRO_STATUS_SUCCESS; + + if (! boxes->is_pixel_aligned) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (op == CAIRO_OPERATOR_CLEAR) + op = CAIRO_OPERATOR_SOURCE; + + if (op == CAIRO_OPERATOR_OVER && + _cairo_pattern_is_opaque (src, &extents->bounded)) + op = CAIRO_OPERATOR_SOURCE; + + if (dst->base.is_clear && op == CAIRO_OPERATOR_OVER) + op = CAIRO_OPERATOR_SOURCE; + + if (op != CAIRO_OPERATOR_SOURCE) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = acquire (dst); + if (unlikely (status)) + return status; + + if (src->type == CAIRO_PATTERN_TYPE_SOLID) { + status = _cairo_xlib_core_fill_boxes + (dst, &((cairo_solid_pattern_t *) src)->color, boxes); + } else { + status = upload_image_inplace (dst, src, boxes); + if (status == CAIRO_INT_STATUS_UNSUPPORTED) + status = copy_boxes (dst, src, boxes); + if (status == CAIRO_INT_STATUS_UNSUPPORTED) + status = render_boxes (dst, src, boxes); + } + + release (dst); + + return status; +} + +/* high-level compositor interface */ + +static cairo_int_status_t +_cairo_xlib_core_compositor_paint (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *extents) +{ + cairo_int_status_t status; + + status = CAIRO_INT_STATUS_UNSUPPORTED; + if (_cairo_clip_is_region (extents->clip)) { + cairo_boxes_t boxes; + + _cairo_clip_steal_boxes (extents->clip, &boxes); + status = draw_boxes (extents, &boxes); + _cairo_clip_unsteal_boxes (extents->clip, &boxes); + } + + return status; +} + +static cairo_int_status_t +_cairo_xlib_core_compositor_stroke (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *extents, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_int_status_t status; + + status = CAIRO_INT_STATUS_UNSUPPORTED; + if (extents->clip->path == NULL && + _cairo_path_fixed_stroke_is_rectilinear (path)) { + cairo_boxes_t boxes; + + _cairo_boxes_init_with_clip (&boxes, extents->clip); + status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path, + style, + ctm, + antialias, + &boxes); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) + status = draw_boxes (extents, &boxes); + _cairo_boxes_fini (&boxes); + } + + return status; +} + +static cairo_int_status_t +_cairo_xlib_core_compositor_fill (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *extents, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_int_status_t status; + + status = CAIRO_INT_STATUS_UNSUPPORTED; + if (extents->clip->path == NULL && + _cairo_path_fixed_fill_is_rectilinear (path)) { + cairo_boxes_t boxes; + + _cairo_boxes_init_with_clip (&boxes, extents->clip); + status = _cairo_path_fixed_fill_rectilinear_to_boxes (path, + fill_rule, + antialias, + &boxes); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) + status = draw_boxes (extents, &boxes); + _cairo_boxes_fini (&boxes); + } + + return status; +} + +const cairo_compositor_t * +_cairo_xlib_core_compositor_get (void) +{ + static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT; + static cairo_compositor_t compositor; + + if (_cairo_atomic_init_once_enter(&once)) { + compositor.delegate = _cairo_xlib_fallback_compositor_get (); + + compositor.paint = _cairo_xlib_core_compositor_paint; + compositor.mask = NULL; + compositor.fill = _cairo_xlib_core_compositor_fill; + compositor.stroke = _cairo_xlib_core_compositor_stroke; + compositor.glyphs = NULL; /* XXX PolyGlyph? */ + + _cairo_atomic_init_once_leave(&once); + } + + return &compositor; +} + +#endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */ diff --git a/local/recipes/libs/cairo/source/src/cairo-xlib-display.c b/local/recipes/libs/cairo/source/src/cairo-xlib-display.c new file mode 100644 index 0000000000..8b2ffe8e1e --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-xlib-display.c @@ -0,0 +1,667 @@ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2007 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Chris Wilson. + * + * Contributor(s): + * Karl Tomlinson , Mozilla Corporation + */ + +#include "cairoint.h" + +#if !CAIRO_HAS_XLIB_XCB_FUNCTIONS + +#include "cairo-xlib-private.h" +#include "cairo-xlib-xrender-private.h" +#include "cairo-freelist-private.h" +#include "cairo-error-private.h" +#include "cairo-list-inline.h" + +#include /* For XESetCloseDisplay */ + +typedef int (*cairo_xlib_error_func_t) (Display *display, + XErrorEvent *event); + +static cairo_xlib_display_t *_cairo_xlib_display_list; + +static int +_noop_error_handler (Display *display, + XErrorEvent *event) +{ + return False; /* return value is ignored */ +} + +static void +_cairo_xlib_display_finish (void *abstract_display) +{ + cairo_xlib_display_t *display = abstract_display; + Display *dpy = display->display; + + _cairo_xlib_display_fini_shm (display); + + if (! cairo_device_acquire (&display->base)) { + cairo_xlib_error_func_t old_handler; + + /* protect the notifies from triggering XErrors */ + XSync (dpy, False); + old_handler = XSetErrorHandler (_noop_error_handler); + + while (! cairo_list_is_empty (&display->fonts)) { + _cairo_xlib_font_close (cairo_list_first_entry (&display->fonts, + cairo_xlib_font_t, + link)); + } + + while (! cairo_list_is_empty (&display->screens)) { + _cairo_xlib_screen_destroy (display, + cairo_list_first_entry (&display->screens, + cairo_xlib_screen_t, + link)); + } + + XSync (dpy, False); + XSetErrorHandler (old_handler); + + cairo_device_release (&display->base); + } +} + +static void +_cairo_xlib_display_destroy (void *abstract_display) +{ + cairo_xlib_display_t *display = abstract_display; + + free (display); +} + +static int +_cairo_xlib_close_display (Display *dpy, XExtCodes *codes) +{ + cairo_xlib_display_t *display, **prev, *next; + + CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex); + for (display = _cairo_xlib_display_list; display; display = display->next) + if (display->display == dpy) + break; + CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex); + if (display == NULL) + return 0; + + cairo_device_finish (&display->base); + + /* + * Unhook from the global list + */ + CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex); + prev = &_cairo_xlib_display_list; + for (display = _cairo_xlib_display_list; display; display = next) { + next = display->next; + if (display->display == dpy) { + *prev = next; + break; + } else + prev = &display->next; + } + CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex); + + display->display = NULL; /* catch any later invalid access */ + cairo_device_destroy (&display->base); + + /* Return value in accordance with requirements of + * XESetCloseDisplay */ + return 0; +} + +static const cairo_device_backend_t _cairo_xlib_device_backend = { + CAIRO_DEVICE_TYPE_XLIB, + + NULL, + NULL, + + NULL, /* flush */ + _cairo_xlib_display_finish, + _cairo_xlib_display_destroy, +}; + +static void _cairo_xlib_display_select_compositor (cairo_xlib_display_t *display) +{ +#if 1 + if (display->render_major > 0 || display->render_minor >= 4) + display->compositor = _cairo_xlib_traps_compositor_get (); + else if (display->render_major > 0 || display->render_minor >= 0) + display->compositor = _cairo_xlib_mask_compositor_get (); + else + display->compositor = _cairo_xlib_core_compositor_get (); +#else + display->compositor = _cairo_xlib_fallback_compositor_get (); +#endif +} + +/** + * _cairo_xlib_device_create: + * @dpy: the display to create the device for + * + * Gets the device belonging to @dpy, or creates it if it doesn't exist yet. + * + * Returns: the device belonging to @dpy + **/ +cairo_device_t * +_cairo_xlib_device_create (Display *dpy) +{ + cairo_xlib_display_t *display; + cairo_xlib_display_t **prev; + cairo_device_t *device; + XExtCodes *codes; + const char *env; + + CAIRO_MUTEX_INITIALIZE (); + + /* There is an apparent deadlock between this mutex and the + * mutex for the display, but it's actually safe. For the + * app to call XCloseDisplay() while any other thread is + * inside this function would be an error in the logic + * app, and the CloseDisplay hook is the only other place we + * acquire this mutex. + */ + CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex); + + for (prev = &_cairo_xlib_display_list; (display = *prev); prev = &(*prev)->next) + { + if (display->display == dpy) { + /* + * MRU the list + */ + if (prev != &_cairo_xlib_display_list) { + *prev = display->next; + display->next = _cairo_xlib_display_list; + _cairo_xlib_display_list = display; + } + device = cairo_device_reference (&display->base); + goto UNLOCK; + } + } + + display = _cairo_calloc (sizeof (cairo_xlib_display_t)); + if (unlikely (display == NULL)) { + device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY); + goto UNLOCK; + } + + _cairo_device_init (&display->base, &_cairo_xlib_device_backend); + + display->display = dpy; + cairo_list_init (&display->screens); + cairo_list_init (&display->fonts); + display->closed = FALSE; + + /* Xlib calls out to the extension close_display hooks in LIFO + * order. So we have to ensure that all extensions that we depend + * on in our close_display hook are properly initialized before we + * add our hook. For now, that means Render, so we call into its + * QueryVersion function to ensure it gets initialized. + */ + display->render_major = display->render_minor = -1; + XRenderQueryVersion (dpy, &display->render_major, &display->render_minor); + env = getenv ("CAIRO_DEBUG"); + if (env != NULL && (env = strstr (env, "xrender-version=")) != NULL) { + int max_render_major, max_render_minor; + + env += sizeof ("xrender-version=") - 1; + if (sscanf (env, "%d.%d", &max_render_major, &max_render_minor) != 2) + max_render_major = max_render_minor = -1; + + if (max_render_major < display->render_major || + (max_render_major == display->render_major && + max_render_minor < display->render_minor)) + { + display->render_major = max_render_major; + display->render_minor = max_render_minor; + } + } + + _cairo_xlib_display_select_compositor (display); + + display->white = NULL; + memset (display->alpha, 0, sizeof (display->alpha)); + memset (display->solid, 0, sizeof (display->solid)); + memset (display->solid_cache, 0, sizeof (display->solid_cache)); + memset (display->last_solid_cache, 0, sizeof (display->last_solid_cache)); + + memset (display->cached_xrender_formats, 0, + sizeof (display->cached_xrender_formats)); + + display->force_precision = -1; + + _cairo_xlib_display_init_shm (display); + + /* Prior to Render 0.10, there is no protocol support for gradients and + * we call function stubs instead, which would silently consume the drawing. + */ +#if RENDER_MAJOR == 0 && RENDER_MINOR < 10 + display->buggy_gradients = TRUE; +#else + display->buggy_gradients = FALSE; +#endif + display->buggy_pad_reflect = FALSE; + display->buggy_repeat = FALSE; + + /* This buggy_repeat condition is very complicated because there + * are multiple X server code bases (with multiple versioning + * schemes within a code base), and multiple bugs. + * + * The X servers: + * + * 1. The Vendor=="XFree86" code base with release numbers such + * as 4.7.0 (VendorRelease==40700000). + * + * 2. The Vendor=="X.Org" code base (a descendant of the + * XFree86 code base). It originally had things like + * VendorRelease==60700000 for release 6.7.0 but then changed + * its versioning scheme so that, for example, + * VendorRelease==10400000 for the 1.4.0 X server within the + * X.Org 7.3 release. + * + * The bugs: + * + * 1. The original bug that led to the buggy_repeat + * workaround. This was a bug that Owen Taylor investigated, + * understood well, and characterized against various X + * servers. Confirmed X servers with this bug include: + * + * "XFree86" <= 40500000 + * "X.Org" <= 60802000 (only with old numbering >= 60700000) + * + * 2. A separate bug resulting in a crash of the X server when + * using cairo's extend-reflect test case, (which, surprisingly + * enough was not passing RepeatReflect to the X server, but + * instead using RepeatNormal in a workaround). Nobody to date + * has understood the bug well, but it appears to be gone as of + * the X.Org 1.4.0 server. This bug is coincidentally avoided + * by using the same buggy_repeat workaround. Confirmed X + * servers with this bug include: + * + * "X.org" == 60900000 (old versioning scheme) + * "X.org" < 10400000 (new numbering scheme) + * + * For the old-versioning-scheme X servers we don't know + * exactly when second the bug started, but since bug 1 is + * present through 6.8.2 and bug 2 is present in 6.9.0 it seems + * safest to just blacklist all old-versioning-scheme X servers, + * (just using VendorRelease < 70000000), as buggy_repeat=TRUE. + */ + if (_cairo_xlib_vendor_is_xorg (dpy)) { + if (VendorRelease (dpy) >= 60700000) { + if (VendorRelease (dpy) < 70000000) + display->buggy_repeat = TRUE; + + /* We know that gradients simply do not work in early Xorg servers */ + if (VendorRelease (dpy) < 70200000) + display->buggy_gradients = TRUE; + + /* And the extended repeat modes were not fixed until much later */ + display->buggy_pad_reflect = TRUE; + } else { + if (VendorRelease (dpy) < 10400000) + display->buggy_repeat = TRUE; + + /* Too many bugs in the early drivers */ + if (VendorRelease (dpy) < 10699000) + display->buggy_pad_reflect = TRUE; + } + } else if (strstr (ServerVendor (dpy), "XFree86") != NULL) { + if (VendorRelease (dpy) <= 40500000) + display->buggy_repeat = TRUE; + + display->buggy_gradients = TRUE; + display->buggy_pad_reflect = TRUE; + } + + codes = XAddExtension (dpy); + if (unlikely (codes == NULL)) { + device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY); + free (display); + goto UNLOCK; + } + + XESetCloseDisplay (dpy, codes->extension, _cairo_xlib_close_display); + cairo_device_reference (&display->base); /* add one for the CloseDisplay */ + + display->next = _cairo_xlib_display_list; + _cairo_xlib_display_list = display; + + device = &display->base; + +UNLOCK: + CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex); + return device; +} + +cairo_status_t +_cairo_xlib_display_acquire (cairo_device_t *device, cairo_xlib_display_t **display) +{ + cairo_status_t status; + + status = cairo_device_acquire (device); + if (status) + return status; + + *display = (cairo_xlib_display_t *) device; + return CAIRO_STATUS_SUCCESS; +} + +XRenderPictFormat * +_cairo_xlib_display_get_xrender_format_for_pixman(cairo_xlib_display_t *display, + pixman_format_code_t format) +{ + Display *dpy = display->display; + XRenderPictFormat tmpl; + int mask; + + /* No equivalent in X11 yet. */ + if (format == PIXMAN_rgba_float || format == PIXMAN_rgb_float) + return NULL; + +#define MASK(x) ((1<<(x))-1) + + tmpl.depth = PIXMAN_FORMAT_DEPTH(format); + mask = PictFormatType | PictFormatDepth; + + switch (PIXMAN_FORMAT_TYPE(format)) { + case PIXMAN_TYPE_ARGB: + tmpl.type = PictTypeDirect; + + tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format)); + if (PIXMAN_FORMAT_A(format)) + tmpl.direct.alpha = (PIXMAN_FORMAT_R(format) + + PIXMAN_FORMAT_G(format) + + PIXMAN_FORMAT_B(format)); + + tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format)); + tmpl.direct.red = (PIXMAN_FORMAT_G(format) + + PIXMAN_FORMAT_B(format)); + + tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format)); + tmpl.direct.green = PIXMAN_FORMAT_B(format); + + tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format)); + tmpl.direct.blue = 0; + + mask |= PictFormatRed | PictFormatRedMask; + mask |= PictFormatGreen | PictFormatGreenMask; + mask |= PictFormatBlue | PictFormatBlueMask; + mask |= PictFormatAlpha | PictFormatAlphaMask; + break; + + case PIXMAN_TYPE_ABGR: + tmpl.type = PictTypeDirect; + + tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format)); + if (tmpl.direct.alphaMask) + tmpl.direct.alpha = (PIXMAN_FORMAT_B(format) + + PIXMAN_FORMAT_G(format) + + PIXMAN_FORMAT_R(format)); + + tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format)); + tmpl.direct.blue = (PIXMAN_FORMAT_G(format) + + PIXMAN_FORMAT_R(format)); + + tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format)); + tmpl.direct.green = PIXMAN_FORMAT_R(format); + + tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format)); + tmpl.direct.red = 0; + + mask |= PictFormatRed | PictFormatRedMask; + mask |= PictFormatGreen | PictFormatGreenMask; + mask |= PictFormatBlue | PictFormatBlueMask; + mask |= PictFormatAlpha | PictFormatAlphaMask; + break; + + case PIXMAN_TYPE_BGRA: + tmpl.type = PictTypeDirect; + + tmpl.direct.blueMask = MASK(PIXMAN_FORMAT_B(format)); + tmpl.direct.blue = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format)); + + tmpl.direct.greenMask = MASK(PIXMAN_FORMAT_G(format)); + tmpl.direct.green = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format) - + PIXMAN_FORMAT_G(format)); + + tmpl.direct.redMask = MASK(PIXMAN_FORMAT_R(format)); + tmpl.direct.red = (PIXMAN_FORMAT_BPP(format) - PIXMAN_FORMAT_B(format) - + PIXMAN_FORMAT_G(format) - PIXMAN_FORMAT_R(format)); + + tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format)); + tmpl.direct.alpha = 0; + + mask |= PictFormatRed | PictFormatRedMask; + mask |= PictFormatGreen | PictFormatGreenMask; + mask |= PictFormatBlue | PictFormatBlueMask; + mask |= PictFormatAlpha | PictFormatAlphaMask; + break; + + case PIXMAN_TYPE_A: + tmpl.type = PictTypeDirect; + + tmpl.direct.alpha = 0; + tmpl.direct.alphaMask = MASK(PIXMAN_FORMAT_A(format)); + + mask |= PictFormatAlpha | PictFormatAlphaMask; + break; + + case PIXMAN_TYPE_COLOR: + case PIXMAN_TYPE_GRAY: + /* XXX Find matching visual/colormap */ + tmpl.type = PictTypeIndexed; + //tmpl.colormap = screen->visuals[PIXMAN_FORMAT_VIS(format)].vid; + //mask |= PictFormatColormap; + return NULL; + } +#undef MASK + + /* XXX caching? */ + return XRenderFindFormat(dpy, mask, &tmpl, 0); +} + +XRenderPictFormat * +_cairo_xlib_display_get_xrender_format (cairo_xlib_display_t *display, + cairo_format_t format) +{ + XRenderPictFormat *xrender_format; + + xrender_format = display->cached_xrender_formats[format]; + if (xrender_format == NULL) { + int pict_format = PictStandardNUM; + + switch (format) { + case CAIRO_FORMAT_A1: + pict_format = PictStandardA1; break; + case CAIRO_FORMAT_A8: + pict_format = PictStandardA8; break; + case CAIRO_FORMAT_RGB24: + pict_format = PictStandardRGB24; break; + case CAIRO_FORMAT_RGB16_565: + xrender_format = _cairo_xlib_display_get_xrender_format_for_pixman(display, + PIXMAN_r5g6b5); + break; + case CAIRO_FORMAT_RGB30: + xrender_format = _cairo_xlib_display_get_xrender_format_for_pixman(display, + PIXMAN_x2r10g10b10); + break; + case CAIRO_FORMAT_RGBA128F: + xrender_format = _cairo_xlib_display_get_xrender_format_for_pixman(display, + PIXMAN_rgba_float); + break; + case CAIRO_FORMAT_RGB96F: + xrender_format = _cairo_xlib_display_get_xrender_format_for_pixman(display, + PIXMAN_rgb_float); + break; + case CAIRO_FORMAT_INVALID: + default: + ASSERT_NOT_REACHED; + case CAIRO_FORMAT_ARGB32: + pict_format = PictStandardARGB32; break; + } + if (pict_format != PictStandardNUM) + xrender_format = + XRenderFindStandardFormat (display->display, pict_format); + display->cached_xrender_formats[format] = xrender_format; + } + + return xrender_format; +} + +cairo_xlib_screen_t * +_cairo_xlib_display_get_screen (cairo_xlib_display_t *display, + Screen *screen) +{ + cairo_xlib_screen_t *info; + + cairo_list_foreach_entry (info, cairo_xlib_screen_t, &display->screens, link) { + if (info->screen == screen) { + if (display->screens.next != &info->link) + cairo_list_move (&info->link, &display->screens); + return info; + } + } + + return NULL; +} + +cairo_bool_t +_cairo_xlib_display_has_repeat (cairo_device_t *device) +{ + return ! ((cairo_xlib_display_t *) device)->buggy_repeat; +} + +cairo_bool_t +_cairo_xlib_display_has_reflect (cairo_device_t *device) +{ + return ! ((cairo_xlib_display_t *) device)->buggy_pad_reflect; +} + +cairo_bool_t +_cairo_xlib_display_has_gradients (cairo_device_t *device) +{ + return ! ((cairo_xlib_display_t *) device)->buggy_gradients; +} + +/** + * cairo_xlib_device_debug_cap_xrender_version: + * @device: a #cairo_device_t for the Xlib backend + * @major_version: major version to restrict to + * @minor_version: minor version to restrict to + * + * Restricts all future Xlib surfaces for this devices to the specified version + * of the RENDER extension. This function exists solely for debugging purpose. + * It lets you find out how cairo would behave with an older version of + * the RENDER extension. + * + * Use the special values -1 and -1 for disabling the RENDER extension. + * + * Since: 1.12 + **/ +void +cairo_xlib_device_debug_cap_xrender_version (cairo_device_t *device, + int major_version, + int minor_version) +{ + cairo_xlib_display_t *display = (cairo_xlib_display_t *) device; + + if (device == NULL || device->status) + return; + + if (device->backend->type != CAIRO_DEVICE_TYPE_XLIB) + return; + + if (major_version < display->render_major || + (major_version == display->render_major && + minor_version < display->render_minor)) + { + display->render_major = major_version; + display->render_minor = minor_version; + } + + _cairo_xlib_display_select_compositor (display); +} + +/** + * cairo_xlib_device_debug_set_precision: + * @device: a #cairo_device_t for the Xlib backend + * @precision: the precision to use + * + * Render supports two modes of precision when rendering trapezoids. Set + * the precision to the desired mode. + * + * Since: 1.12 + **/ +void +cairo_xlib_device_debug_set_precision (cairo_device_t *device, + int precision) +{ + if (device == NULL || device->status) + return; + if (device->backend->type != CAIRO_DEVICE_TYPE_XLIB) { + cairo_status_t status; + + status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH); + (void) status; + return; + } + + ((cairo_xlib_display_t *) device)->force_precision = precision; +} + +/** + * cairo_xlib_device_debug_get_precision: + * @device: a #cairo_device_t for the Xlib backend + * + * Get the Xrender precision mode. + * + * Returns: the render precision mode + * + * Since: 1.12 + **/ +int +cairo_xlib_device_debug_get_precision (cairo_device_t *device) +{ + if (device == NULL || device->status) + return -1; + if (device->backend->type != CAIRO_DEVICE_TYPE_XLIB) { + cairo_status_t status; + + status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH); + (void) status; + return -1; + } + + return ((cairo_xlib_display_t *) device)->force_precision; +} + +#endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */ diff --git a/local/recipes/libs/cairo/source/src/cairo-xlib-fallback-compositor.c b/local/recipes/libs/cairo/source/src/cairo-xlib-fallback-compositor.c new file mode 100644 index 0000000000..ed2845db57 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-xlib-fallback-compositor.c @@ -0,0 +1,248 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Behdad Esfahbod + * Chris Wilson + * Karl Tomlinson , Mozilla Corporation + */ + +#include "cairoint.h" + +#if !CAIRO_HAS_XLIB_XCB_FUNCTIONS + +#include "cairo-xlib-private.h" + +#include "cairo-compositor-private.h" +#include "cairo-image-surface-private.h" +#include "cairo-surface-offset-private.h" + +static const cairo_compositor_t * +_get_compositor (cairo_surface_t *surface) +{ + return ((cairo_image_surface_t *)surface)->compositor; +} + +static cairo_bool_t +unclipped (cairo_xlib_surface_t *xlib, cairo_clip_t *clip) +{ + cairo_rectangle_int_t r; + + r.x = r.y = 0; + r.width = xlib->width; + r.height = xlib->height; + return _cairo_clip_contains_rectangle (clip, &r); +} + +static cairo_int_status_t +_cairo_xlib_shm_compositor_paint (const cairo_compositor_t *_compositor, + cairo_composite_rectangles_t *extents) +{ + cairo_xlib_surface_t *xlib = (cairo_xlib_surface_t *)extents->surface; + cairo_int_status_t status; + cairo_surface_t *shm; + cairo_bool_t overwrite; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + overwrite = + extents->op <= CAIRO_OPERATOR_SOURCE && unclipped (xlib, extents->clip); + + shm = _cairo_xlib_surface_get_shm (xlib, overwrite); + if (shm == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_compositor_paint (_get_compositor (shm), shm, + extents->op, + &extents->source_pattern.base, + extents->clip); + if (unlikely (status)) + return status; + + xlib->base.is_clear = + extents->op == CAIRO_OPERATOR_CLEAR && unclipped (xlib, extents->clip); + xlib->base.serial++; + xlib->fallback++; + return CAIRO_INT_STATUS_NOTHING_TO_DO; +} + +static cairo_int_status_t +_cairo_xlib_shm_compositor_mask (const cairo_compositor_t *_compositor, + cairo_composite_rectangles_t *extents) +{ + cairo_xlib_surface_t *xlib = (cairo_xlib_surface_t *)extents->surface; + cairo_int_status_t status; + cairo_surface_t *shm; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + shm = _cairo_xlib_surface_get_shm (xlib, FALSE); + if (shm == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_compositor_mask (_get_compositor (shm), shm, + extents->op, + &extents->source_pattern.base, + &extents->mask_pattern.base, + extents->clip); + if (unlikely (status)) + return status; + + xlib->base.is_clear = FALSE; + xlib->base.serial++; + xlib->fallback++; + return CAIRO_INT_STATUS_NOTHING_TO_DO; +} + +static cairo_int_status_t +_cairo_xlib_shm_compositor_stroke (const cairo_compositor_t *_compositor, + cairo_composite_rectangles_t *extents, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_xlib_surface_t *xlib = (cairo_xlib_surface_t *)extents->surface; + cairo_int_status_t status; + cairo_surface_t *shm; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + shm = _cairo_xlib_surface_get_shm (xlib, FALSE); + if (shm == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_compositor_stroke (_get_compositor (shm), shm, + extents->op, + &extents->source_pattern.base, + path, style, + ctm, ctm_inverse, + tolerance, + antialias, + extents->clip); + if (unlikely (status)) + return status; + + xlib->base.is_clear = FALSE; + xlib->base.serial++; + xlib->fallback++; + return CAIRO_INT_STATUS_NOTHING_TO_DO; +} + +static cairo_int_status_t +_cairo_xlib_shm_compositor_fill (const cairo_compositor_t *_compositor, + cairo_composite_rectangles_t *extents, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_xlib_surface_t *xlib = (cairo_xlib_surface_t *)extents->surface; + cairo_int_status_t status; + cairo_surface_t *shm; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + shm = _cairo_xlib_surface_get_shm (xlib, FALSE); + if (shm == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_compositor_fill (_get_compositor (shm), shm, + extents->op, + &extents->source_pattern.base, + path, + fill_rule, tolerance, antialias, + extents->clip); + if (unlikely (status)) + return status; + + xlib->base.is_clear = FALSE; + xlib->base.serial++; + xlib->fallback++; + return CAIRO_INT_STATUS_NOTHING_TO_DO; +} + +static cairo_int_status_t +_cairo_xlib_shm_compositor_glyphs (const cairo_compositor_t *_compositor, + cairo_composite_rectangles_t *extents, + cairo_scaled_font_t *scaled_font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_bool_t overlap) +{ + cairo_xlib_surface_t *xlib = (cairo_xlib_surface_t *)extents->surface; + cairo_int_status_t status; + cairo_surface_t *shm; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + shm = _cairo_xlib_surface_get_shm (xlib, FALSE); + if (shm == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_compositor_glyphs (_get_compositor (shm), shm, + extents->op, + &extents->source_pattern.base, + glyphs, num_glyphs, scaled_font, + extents->clip); + if (unlikely (status)) + return status; + + xlib->base.is_clear = FALSE; + xlib->base.serial++; + xlib->fallback++; + return CAIRO_INT_STATUS_NOTHING_TO_DO; +} + +static const cairo_compositor_t _cairo_xlib_shm_compositor = { + &_cairo_fallback_compositor, + + _cairo_xlib_shm_compositor_paint, + _cairo_xlib_shm_compositor_mask, + _cairo_xlib_shm_compositor_stroke, + _cairo_xlib_shm_compositor_fill, + _cairo_xlib_shm_compositor_glyphs, +}; + +const cairo_compositor_t * +_cairo_xlib_fallback_compositor_get (void) +{ + return &_cairo_xlib_shm_compositor; +} + +#endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */ diff --git a/local/recipes/libs/cairo/source/src/cairo-xlib-private.h b/local/recipes/libs/cairo/source/src/cairo-xlib-private.h new file mode 100644 index 0000000000..e8900030b1 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-xlib-private.h @@ -0,0 +1,472 @@ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributors(s): + * Chris Wilson + * Karl Tomlinson , Mozilla Corporation + */ + +#ifndef CAIRO_XLIB_PRIVATE_H +#define CAIRO_XLIB_PRIVATE_H + +#include "cairo-xlib-xrender-private.h" +#include "cairo-xlib.h" + +#include "cairo-compiler-private.h" +#include "cairo-device-private.h" +#include "cairo-freelist-type-private.h" +#include "cairo-list-private.h" +#include "cairo-reference-count-private.h" +#include "cairo-types-private.h" +#include "cairo-scaled-font-private.h" +#include "cairo-surface-private.h" + +#include +#include + +typedef struct _cairo_xlib_display cairo_xlib_display_t; +typedef struct _cairo_xlib_shm_display cairo_xlib_shm_display_t; +typedef struct _cairo_xlib_screen cairo_xlib_screen_t; +typedef struct _cairo_xlib_source cairo_xlib_source_t; +typedef struct _cairo_xlib_proxy cairo_xlib_proxy_t; +typedef struct _cairo_xlib_surface cairo_xlib_surface_t; + +/* size of color cube */ +#define CUBE_SIZE 6 +/* size of gray ramp */ +#define RAMP_SIZE 16 +/* maximum number of cached GC's */ +#define GC_CACHE_SIZE 4 +/* maximum width/height of an X11 drawable */ +#define XLIB_COORD_MAX 32767 + +struct _cairo_xlib_display { + cairo_device_t base; + + cairo_xlib_display_t *next; + + Display *display; + cairo_list_t screens; + cairo_list_t fonts; + + cairo_xlib_shm_display_t *shm; + + const cairo_compositor_t *compositor; + + int render_major; + int render_minor; + XRenderPictFormat *cached_xrender_formats[CAIRO_FORMAT_RGBA128F + 1]; + + int force_precision; + + cairo_surface_t *white; + cairo_surface_t *alpha[256]; + cairo_surface_t *solid[32]; + uint32_t solid_cache[32]; /* low 16 are opaque, high 16 transparent */ + struct { + uint32_t color; + int index; + } last_solid_cache[2]; + + /* TRUE if the server has a bug with repeating pictures + * + * https://bugs.freedesktop.org/show_bug.cgi?id=3566 + * + * We can't test for this because it depends on whether the + * picture is in video memory or not. + * + * We also use this variable as a guard against a second + * independent bug with transformed repeating pictures: + * + * https://lists.freedesktop.org/archives/cairo/2004-September/001839.html + * + * Both are fixed in xorg >= 6.9 and hopefully in > 6.8.2, so + * we can reuse the test for now. + */ + unsigned int buggy_gradients : 1; + unsigned int buggy_pad_reflect : 1; + unsigned int buggy_repeat : 1; + unsigned int closed :1; +}; + +typedef struct _cairo_xlib_visual_info { + cairo_list_t link; + VisualID visualid; + struct { uint8_t a, r, g, b; } colors[256]; + uint8_t cube_to_pseudocolor[CUBE_SIZE][CUBE_SIZE][CUBE_SIZE]; + uint8_t field8_to_cube[256]; + int8_t dither8_to_cube[256]; + uint8_t gray8_to_pseudocolor[256]; +} cairo_xlib_visual_info_t; + +struct _cairo_xlib_screen { + cairo_list_t link; + + cairo_device_t *device; + Screen *screen; + + cairo_list_t surfaces; + + cairo_bool_t has_font_options; + cairo_font_options_t font_options; + + GC gc[GC_CACHE_SIZE]; + uint8_t gc_depths[GC_CACHE_SIZE]; + + cairo_list_t visuals; +}; + +enum { + GLYPHSET_INDEX_ARGB32, + GLYPHSET_INDEX_A8, + GLYPHSET_INDEX_A1, + NUM_GLYPHSETS +}; + +typedef struct _cairo_xlib_font_glyphset { + GlyphSet glyphset; + cairo_format_t format; + XRenderPictFormat *xrender_format; + struct _cairo_xlib_font_glyphset_free_glyphs { + int count; + unsigned long indices[128]; + } to_free; +} cairo_xlib_font_glyphset_t; + +typedef struct _cairo_xlib_font { + cairo_scaled_font_private_t base; + cairo_scaled_font_t *font; + cairo_device_t *device; + cairo_list_t link; + cairo_xlib_font_glyphset_t glyphset[NUM_GLYPHSETS]; +} cairo_xlib_font_t; + +struct _cairo_xlib_surface { + cairo_surface_t base; + + Picture picture; + Drawable drawable; + + const cairo_compositor_t *compositor; + cairo_surface_t *shm; + int fallback; + + cairo_xlib_display_t *display; + cairo_xlib_screen_t *screen; + cairo_list_t link; + + Display *dpy; /* only valid between acquire/release */ + cairo_bool_t owns_pixmap; + Visual *visual; + + int use_pixmap; + + int width; + int height; + int depth; + + int precision; + XRenderPictFormat *xrender_format; + /* XXX pixman_format instead of masks? */ + uint32_t a_mask; + uint32_t r_mask; + uint32_t g_mask; + uint32_t b_mask; + + struct _cairo_xlib_source { + cairo_surface_t base; + + Picture picture; + Pixmap pixmap; + Display *dpy; + + unsigned int filter:3; + unsigned int extend:3; + unsigned int has_matrix:1; + unsigned int has_component_alpha:1; + } embedded_source; +}; + +struct _cairo_xlib_proxy { + struct _cairo_xlib_source source; + cairo_surface_t *owner; +}; + +inline static cairo_bool_t +_cairo_xlib_vendor_is_xorg (Display *dpy) +{ + const char *const vendor = ServerVendor (dpy); + return strstr (vendor, "X.Org") || strstr (vendor, "Xorg"); +} + +cairo_private cairo_status_t +_cairo_xlib_surface_get_gc (cairo_xlib_display_t *display, + cairo_xlib_surface_t *surface, + GC *gc); + +cairo_private cairo_device_t * +_cairo_xlib_device_create (Display *display); + +cairo_private void +_cairo_xlib_display_init_shm (cairo_xlib_display_t *display); + +cairo_private void +_cairo_xlib_display_fini_shm (cairo_xlib_display_t *display); + +cairo_private cairo_xlib_screen_t * +_cairo_xlib_display_get_screen (cairo_xlib_display_t *display, + Screen *screen); + +cairo_private cairo_status_t +_cairo_xlib_display_acquire (cairo_device_t *device, + cairo_xlib_display_t **display); + +cairo_private cairo_bool_t +_cairo_xlib_display_has_repeat (cairo_device_t *device); + +cairo_private cairo_bool_t +_cairo_xlib_display_has_reflect (cairo_device_t *device); + +cairo_private cairo_bool_t +_cairo_xlib_display_has_gradients (cairo_device_t *device); + +cairo_private void +_cairo_xlib_display_set_precision(cairo_device_t *device, + int precision); + +cairo_private XRenderPictFormat * +_cairo_xlib_display_get_xrender_format (cairo_xlib_display_t *display, + cairo_format_t format); + +cairo_private XRenderPictFormat * +_cairo_xlib_display_get_xrender_format_for_pixman (cairo_xlib_display_t *display, + pixman_format_code_t format); + +cairo_private cairo_status_t +_cairo_xlib_screen_get (Display *dpy, + Screen *screen, + cairo_xlib_screen_t **out); + +cairo_private void +_cairo_xlib_screen_destroy (cairo_xlib_display_t *display, + cairo_xlib_screen_t *info); + +cairo_private GC +_cairo_xlib_screen_get_gc (cairo_xlib_display_t *display, + cairo_xlib_screen_t *info, + int depth, + Drawable drawable); +cairo_private void +_cairo_xlib_screen_put_gc (cairo_xlib_display_t *display, + cairo_xlib_screen_t *info, + int depth, + GC gc); + +cairo_private cairo_font_options_t * +_cairo_xlib_screen_get_font_options (cairo_xlib_screen_t *info); + +cairo_private cairo_status_t +_cairo_xlib_screen_get_visual_info (cairo_xlib_display_t *display, + cairo_xlib_screen_t *info, + Visual *visual, + cairo_xlib_visual_info_t **out); + +cairo_private cairo_status_t +_cairo_xlib_visual_info_create (Display *dpy, + int screen, + VisualID visualid, + cairo_xlib_visual_info_t **out); + +cairo_private void +_cairo_xlib_visual_info_destroy (cairo_xlib_visual_info_t *info); + +cairo_private const cairo_compositor_t * +_cairo_xlib_core_compositor_get (void); + +cairo_private const cairo_compositor_t * +_cairo_xlib_fallback_compositor_get (void); + +cairo_private const cairo_compositor_t * +_cairo_xlib_mask_compositor_get (void); + +cairo_private const cairo_compositor_t * +_cairo_xlib_traps_compositor_get (void); + +cairo_private void +_cairo_xlib_surface_ensure_picture (cairo_xlib_surface_t *surface); + +cairo_private void +_cairo_xlib_surface_set_precision (cairo_xlib_surface_t *surface, + cairo_antialias_t antialias); + +cairo_private cairo_int_status_t +_cairo_xlib_surface_set_attributes (cairo_xlib_display_t *display, + cairo_xlib_surface_t *surface, + cairo_surface_attributes_t *attributes, + double xc, + double yc); + +cairo_private cairo_status_t +_cairo_xlib_surface_draw_image (cairo_xlib_surface_t *surface, + cairo_image_surface_t *image, + int src_x, + int src_y, + int width, + int height, + int dst_x, + int dst_y); + +cairo_private cairo_surface_t * +_cairo_xlib_source_create_for_pattern (cairo_surface_t *dst, + const cairo_pattern_t *pattern, + cairo_bool_t is_mask, + const cairo_rectangle_int_t *extents, + const cairo_rectangle_int_t *sample, + int *src_x, int *src_y); + +cairo_private void +_cairo_xlib_font_close (cairo_xlib_font_t *font); + +#define CAIRO_RENDER_AT_LEAST(surface, major, minor) \ + (((surface)->render_major > major) || \ + (((surface)->render_major == major) && ((surface)->render_minor >= minor))) + +#define CAIRO_RENDER_HAS_CREATE_PICTURE(surface) CAIRO_RENDER_AT_LEAST((surface), 0, 0) +#define CAIRO_RENDER_HAS_COMPOSITE(surface) CAIRO_RENDER_AT_LEAST((surface), 0, 0) +#define CAIRO_RENDER_HAS_COMPOSITE_TEXT(surface) CAIRO_RENDER_AT_LEAST((surface), 0, 0) + +#define CAIRO_RENDER_HAS_FILL_RECTANGLES(surface) CAIRO_RENDER_AT_LEAST((surface), 0, 1) + +#define CAIRO_RENDER_HAS_DISJOINT(surface) CAIRO_RENDER_AT_LEAST((surface), 0, 2) +#define CAIRO_RENDER_HAS_CONJOINT(surface) CAIRO_RENDER_AT_LEAST((surface), 0, 2) + +#define CAIRO_RENDER_HAS_TRAPEZOIDS(surface) CAIRO_RENDER_AT_LEAST((surface), 0, 4) +#define CAIRO_RENDER_HAS_TRIANGLES(surface) CAIRO_RENDER_AT_LEAST((surface), 0, 4) +#define CAIRO_RENDER_HAS_TRISTRIP(surface) CAIRO_RENDER_AT_LEAST((surface), 0, 4) +#define CAIRO_RENDER_HAS_TRIFAN(surface) CAIRO_RENDER_AT_LEAST((surface), 0, 4) + +#define CAIRO_RENDER_HAS_PICTURE_TRANSFORM(surface) CAIRO_RENDER_AT_LEAST((surface), 0, 6) +#define CAIRO_RENDER_HAS_FILTERS(surface) CAIRO_RENDER_AT_LEAST((surface), 0, 6) +#define CAIRO_RENDER_HAS_FILTER_GOOD(surface) FALSE +#define CAIRO_RENDER_HAS_FILTER_BEST(surface) FALSE + +#define CAIRO_RENDER_HAS_EXTENDED_REPEAT(surface) CAIRO_RENDER_AT_LEAST((surface), 0, 10) +#define CAIRO_RENDER_HAS_GRADIENTS(surface) CAIRO_RENDER_AT_LEAST((surface), 0, 10) + +#define CAIRO_RENDER_HAS_PDF_OPERATORS(surface) CAIRO_RENDER_AT_LEAST((surface), 0, 11) + +#define CAIRO_RENDER_SUPPORTS_OPERATOR(surface, op) \ + ((op) <= CAIRO_OPERATOR_SATURATE || \ + (CAIRO_RENDER_HAS_PDF_OPERATORS(surface) && \ + (op) <= CAIRO_OPERATOR_HSL_LUMINOSITY)) + +/* + * Return whether two xlib surfaces share the same + * screen. Both core and Render drawing require this + * when using multiple drawables in an operation. + */ +static inline cairo_bool_t +_cairo_xlib_surface_same_screen (cairo_xlib_surface_t *dst, + cairo_xlib_surface_t *src) +{ + return dst->screen == src->screen; +} + +cairo_private cairo_int_status_t +_cairo_xlib_core_fill_boxes (cairo_xlib_surface_t *dst, + const cairo_color_t *color, + cairo_boxes_t *boxes); + +cairo_private cairo_int_status_t +_cairo_xlib_core_fill_rectangles (cairo_xlib_surface_t *dst, + const cairo_color_t *color, + int num_rects, + cairo_rectangle_int_t *rects); + +static inline void +_cairo_xlib_surface_put_gc (cairo_xlib_display_t *display, + cairo_xlib_surface_t *surface, + GC gc) +{ + _cairo_xlib_screen_put_gc (display, + surface->screen, + surface->depth, + gc); +} + +cairo_private cairo_surface_t * +_cairo_xlib_surface_create_similar_shm (void *surface, + cairo_format_t format, + int width, int height); + +cairo_private cairo_surface_t * +_cairo_xlib_surface_get_shm (cairo_xlib_surface_t *surface, + cairo_bool_t overwrite); + +cairo_private cairo_int_status_t +_cairo_xlib_surface_put_shm (cairo_xlib_surface_t *surface); + +cairo_private cairo_surface_t * +_cairo_xlib_surface_create_shm (cairo_xlib_surface_t *other, + pixman_format_code_t format, + int width, int height); + +cairo_private cairo_surface_t * +_cairo_xlib_surface_create_shm__image (cairo_xlib_surface_t *surface, + pixman_format_code_t format, + int width, int height); + +cairo_private void +_cairo_xlib_shm_surface_get_ximage (cairo_surface_t *surface, + XImage *ximage); + +cairo_private void * +_cairo_xlib_shm_surface_get_obdata (cairo_surface_t *surface); + +cairo_private void +_cairo_xlib_shm_surface_mark_active (cairo_surface_t *shm); + +cairo_private cairo_bool_t +_cairo_xlib_shm_surface_is_active (cairo_surface_t *surface); + +cairo_private cairo_bool_t +_cairo_xlib_shm_surface_is_idle (cairo_surface_t *surface); + +cairo_private Pixmap +_cairo_xlib_shm_surface_get_pixmap (cairo_surface_t *surface); + +cairo_private XRenderPictFormat * +_cairo_xlib_shm_surface_get_xrender_format (cairo_surface_t *surface); + +cairo_private pixman_format_code_t +_pixman_format_for_xlib_surface (cairo_xlib_surface_t *surface); + +#endif /* CAIRO_XLIB_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-xlib-render-compositor.c b/local/recipes/libs/cairo/source/src/cairo-xlib-render-compositor.c new file mode 100644 index 0000000000..a870c00e1d --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-xlib-render-compositor.c @@ -0,0 +1,2024 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Behdad Esfahbod + * Chris Wilson + * Karl Tomlinson , Mozilla Corporation + */ + +#include "cairoint.h" + +#if !CAIRO_HAS_XLIB_XCB_FUNCTIONS + +#include "cairo-xlib-private.h" + +#include "cairo-compositor-private.h" +#include "cairo-damage-private.h" +#include "cairo-image-surface-private.h" +#include "cairo-list-inline.h" +#include "cairo-pattern-private.h" +#include "cairo-pixman-private.h" +#include "cairo-traps-private.h" +#include "cairo-tristrip-private.h" + +static cairo_int_status_t +check_composite (const cairo_composite_rectangles_t *extents) +{ + cairo_xlib_display_t *display = ((cairo_xlib_surface_t *)extents->surface)->display; + + if (! CAIRO_RENDER_SUPPORTS_OPERATOR (display, extents->op)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +acquire (void *abstract_dst) +{ + cairo_xlib_surface_t *dst = abstract_dst; + cairo_int_status_t status; + + status = _cairo_xlib_display_acquire (dst->base.device, &dst->display); + if (unlikely (status)) + return status; + + dst->dpy = dst->display->display; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +release (void *abstract_dst) +{ + cairo_xlib_surface_t *dst = abstract_dst; + + cairo_device_release (&dst->display->base); + dst->dpy = NULL; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +set_clip_region (void *_surface, + cairo_region_t *region) +{ + cairo_xlib_surface_t *surface = _surface; + + _cairo_xlib_surface_ensure_picture (surface); + + if (region != NULL) { + XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)]; + XRectangle *rects = stack_rects; + int n_rects, i; + + n_rects = cairo_region_num_rectangles (region); + if (n_rects > ARRAY_LENGTH (stack_rects)) { + rects = _cairo_malloc_ab (n_rects, sizeof (XRectangle)); + if (unlikely (rects == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + for (i = 0; i < n_rects; i++) { + cairo_rectangle_int_t rect; + + cairo_region_get_rectangle (region, i, &rect); + + rects[i].x = rect.x; + rects[i].y = rect.y; + rects[i].width = rect.width; + rects[i].height = rect.height; + } + XRenderSetPictureClipRectangles (surface->dpy, + surface->picture, + 0, 0, + rects, n_rects); + if (rects != stack_rects) + free (rects); + } else { + XRenderPictureAttributes pa; + pa.clip_mask = None; + XRenderChangePicture (surface->dpy, + surface->picture, + CPClipMask, &pa); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +copy_image_boxes (void *_dst, + cairo_image_surface_t *image, + cairo_boxes_t *boxes, + int dx, int dy) +{ + cairo_xlib_surface_t *dst = _dst; + struct _cairo_boxes_chunk *chunk; + cairo_int_status_t status; + Pixmap src; + GC gc; + int i, j; + + assert (image->depth == dst->depth); + + status = acquire (dst); + if (unlikely (status)) + return status; + + status = _cairo_xlib_surface_get_gc (dst->display, dst, &gc); + if (unlikely (status)) { + release (dst); + return status; + } + + src = _cairo_xlib_shm_surface_get_pixmap (&image->base); + if (boxes->num_boxes == 1) { + int x1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.x); + int y1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.y); + int x2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.x); + int y2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.y); + + _cairo_xlib_shm_surface_mark_active (&image->base); + XCopyArea (dst->dpy, src, dst->drawable, gc, + x1 + dx, y1 + dy, + x2 - x1, y2 - y1, + x1, y1); + } else { + XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)]; + XRectangle *rects = stack_rects; + + if (boxes->num_boxes > ARRAY_LENGTH (stack_rects)) { + rects = _cairo_malloc_ab (boxes->num_boxes, sizeof (XRectangle)); + if (unlikely (rects == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + j = 0; + for (chunk = &boxes->chunks; chunk; chunk = chunk->next) { + for (i = 0; i < chunk->count; i++) { + int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x); + int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y); + int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x); + int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y); + + if (x2 > x1 && y2 > y1) { + rects[j].x = x1; + rects[j].y = y1; + rects[j].width = x2 - x1; + rects[j].height = y2 - y1; + j++; + } + } + } + + XSetClipRectangles (dst->dpy, gc, 0, 0, rects, j, Unsorted); + _cairo_xlib_shm_surface_mark_active (&image->base); + XCopyArea (dst->dpy, src, dst->drawable, gc, + 0, 0, image->width, image->height, -dx, -dy); + XSetClipMask (dst->dpy, gc, None); + + if (rects != stack_rects) + free (rects); + } + + _cairo_xlib_surface_put_gc (dst->display, dst, gc); + release (dst); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_bool_t +boxes_cover_surface (cairo_boxes_t *boxes, + cairo_xlib_surface_t *surface) +{ + cairo_box_t *b; + + if (boxes->num_boxes != 1) + return FALSE; + + b = &boxes->chunks.base[0]; + + if (_cairo_fixed_integer_part (b->p1.x) > 0 || + _cairo_fixed_integer_part (b->p1.y) > 0) + return FALSE; + + if (_cairo_fixed_integer_part (b->p2.x) < surface->width || + _cairo_fixed_integer_part (b->p2.y) < surface->height) + return FALSE; + + return TRUE; +} + +static cairo_int_status_t +draw_image_boxes (void *_dst, + cairo_image_surface_t *image, + cairo_boxes_t *boxes, + int dx, int dy) +{ + cairo_xlib_surface_t *dst = _dst; + struct _cairo_boxes_chunk *chunk; + cairo_image_surface_t *shm = NULL; + cairo_int_status_t status; + int i; + + if (image->base.device == dst->base.device) { + if (image->depth != dst->depth) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (_cairo_xlib_shm_surface_get_pixmap (&image->base)) + return copy_image_boxes (dst, image, boxes, dx, dy); + + goto draw_image_boxes; + } + + if (boxes_cover_surface (boxes, dst)) + shm = (cairo_image_surface_t *) _cairo_xlib_surface_get_shm (dst, TRUE); + if (shm) { + for (chunk = &boxes->chunks; chunk; chunk = chunk->next) { + for (i = 0; i < chunk->count; i++) { + cairo_box_t *b = &chunk->base[i]; + cairo_rectangle_int_t r; + + r.x = _cairo_fixed_integer_part (b->p1.x); + r.y = _cairo_fixed_integer_part (b->p1.y); + r.width = _cairo_fixed_integer_part (b->p2.x) - r.x; + r.height = _cairo_fixed_integer_part (b->p2.y) - r.y; + + if (shm->pixman_format != image->pixman_format || + ! pixman_blt ((uint32_t *)image->data, (uint32_t *)shm->data, + image->stride / sizeof (uint32_t), + shm->stride / sizeof (uint32_t), + PIXMAN_FORMAT_BPP (image->pixman_format), + PIXMAN_FORMAT_BPP (shm->pixman_format), + r.x + dx, r.y + dy, + r.x, r.y, + r.width, r.height)) + { + pixman_image_composite32 (PIXMAN_OP_SRC, + image->pixman_image, NULL, shm->pixman_image, + r.x + dx, r.y + dy, + 0, 0, + r.x, r.y, + r.width, r.height); + } + + shm->base.damage = + _cairo_damage_add_rectangle (shm->base.damage, &r); + } + } + dst->base.is_clear = FALSE; + dst->fallback++; + dst->base.serial++; + return CAIRO_INT_STATUS_NOTHING_TO_DO; + } + + if (image->depth == dst->depth && + ((cairo_xlib_display_t *)dst->display)->shm) { + cairo_box_t extents; + cairo_rectangle_int_t r; + + _cairo_boxes_extents (boxes, &extents); + _cairo_box_round_to_rectangle (&extents, &r); + + shm = (cairo_image_surface_t *) + _cairo_xlib_surface_create_shm (dst, image->pixman_format, + r.width, r.height); + if (shm) { + int tx = -r.x, ty = -r.y; + + assert (shm->pixman_format == image->pixman_format); + for (chunk = &boxes->chunks; chunk; chunk = chunk->next) { + for (i = 0; i < chunk->count; i++) { + cairo_box_t *b = &chunk->base[i]; + + r.x = _cairo_fixed_integer_part (b->p1.x); + r.y = _cairo_fixed_integer_part (b->p1.y); + r.width = _cairo_fixed_integer_part (b->p2.x) - r.x; + r.height = _cairo_fixed_integer_part (b->p2.y) - r.y; + + if (! pixman_blt ((uint32_t *)image->data, (uint32_t *)shm->data, + image->stride / sizeof (uint32_t), + shm->stride / sizeof (uint32_t), + PIXMAN_FORMAT_BPP (image->pixman_format), + PIXMAN_FORMAT_BPP (shm->pixman_format), + r.x + dx, r.y + dy, + r.x + tx, r.y + ty, + r.width, r.height)) + { + pixman_image_composite32 (PIXMAN_OP_SRC, + image->pixman_image, NULL, shm->pixman_image, + r.x + dx, r.y + dy, + 0, 0, + r.x + tx, r.y + ty, + r.width, r.height); + } + } + } + + dx = tx; + dy = ty; + image = shm; + + if (_cairo_xlib_shm_surface_get_pixmap (&image->base)) { + status = copy_image_boxes (dst, image, boxes, dx, dy); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) + goto out; + } + } + } + +draw_image_boxes: + status = CAIRO_STATUS_SUCCESS; + for (chunk = &boxes->chunks; chunk; chunk = chunk->next) { + for (i = 0; i < chunk->count; i++) { + cairo_box_t *b = &chunk->base[i]; + int x1 = _cairo_fixed_integer_part (b->p1.x); + int y1 = _cairo_fixed_integer_part (b->p1.y); + int x2 = _cairo_fixed_integer_part (b->p2.x); + int y2 = _cairo_fixed_integer_part (b->p2.y); + if (_cairo_xlib_surface_draw_image (dst, image, + x1 + dx, y1 + dy, + x2 - x1, y2 - y1, + x1, y1)) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto out; + } + } + } + +out: + cairo_surface_destroy (&shm->base); + return status; +} + +static cairo_int_status_t +copy_boxes (void *_dst, + cairo_surface_t *_src, + cairo_boxes_t *boxes, + const cairo_rectangle_int_t *extents, + int dx, int dy) +{ + cairo_xlib_surface_t *dst = _dst; + cairo_xlib_surface_t *src = (cairo_xlib_surface_t *)_src; + struct _cairo_boxes_chunk *chunk; + cairo_int_status_t status; + GC gc; + Drawable d; + int i, j; + + if (! _cairo_xlib_surface_same_screen (dst, src)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (dst->depth != src->depth) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = acquire (dst); + if (unlikely (status)) + return status; + + status = _cairo_xlib_surface_get_gc (dst->display, dst, &gc); + if (unlikely (status)) { + release (dst); + return status; + } + + if (src->fallback && src->shm->damage->dirty) { + assert (src != dst); + d = _cairo_xlib_shm_surface_get_pixmap (src->shm); + assert (d != 0); + } else { + if (! src->owns_pixmap) { + XGCValues gcv; + + gcv.subwindow_mode = IncludeInferiors; + XChangeGC (dst->display->display, gc, GCSubwindowMode, &gcv); + } + d = src->drawable; + } + + if (boxes->num_boxes == 1) { + int x1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.x); + int y1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.y); + int x2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.x); + int y2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.y); + + XCopyArea (dst->dpy, d, dst->drawable, gc, + x1 + dx, y1 + dy, + x2 - x1, y2 - y1, + x1, y1); + } else { + /* We can only have a single control for subwindow_mode on the + * GC. If we have a Window destination, we need to set ClipByChildren, + * but if we have a Window source, we need IncludeInferiors. If we have + * both a Window destination and source, we must fallback. There is + * no convenient way to detect if a drawable is a Pixmap or Window, + * therefore we can only rely on those surfaces that we created + * ourselves to be Pixmaps, and treat everything else as a potential + * Window. + */ + if (src == dst || (!src->owns_pixmap && !dst->owns_pixmap)) { + for (chunk = &boxes->chunks; chunk; chunk = chunk->next) { + for (i = 0; i < chunk->count; i++) { + int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x); + int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y); + int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x); + int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y); + XCopyArea (dst->dpy, d, dst->drawable, gc, + x1 + dx, y1 + dy, + x2 - x1, y2 - y1, + x1, y1); + } + } + } else { + XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)]; + XRectangle *rects = stack_rects; + + if (boxes->num_boxes > ARRAY_LENGTH (stack_rects)) { + rects = _cairo_malloc_ab (boxes->num_boxes, sizeof (XRectangle)); + if (unlikely (rects == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + j = 0; + for (chunk = &boxes->chunks; chunk; chunk = chunk->next) { + for (i = 0; i < chunk->count; i++) { + int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x); + int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y); + int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x); + int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y); + + rects[j].x = x1; + rects[j].y = y1; + rects[j].width = x2 - x1; + rects[j].height = y2 - y1; + j++; + } + } + assert (j == boxes->num_boxes); + + XSetClipRectangles (dst->dpy, gc, 0, 0, rects, j, Unsorted); + + XCopyArea (dst->dpy, d, dst->drawable, gc, + extents->x + dx, extents->y + dy, + extents->width, extents->height, + extents->x, extents->y); + + XSetClipMask (dst->dpy, gc, None); + + if (rects != stack_rects) + free (rects); + } + } + + if (src->fallback && src->shm->damage->dirty) { + _cairo_xlib_shm_surface_mark_active (src->shm); + } else if (! src->owns_pixmap) { + XGCValues gcv; + + gcv.subwindow_mode = ClipByChildren; + XChangeGC (dst->display->display, gc, GCSubwindowMode, &gcv); + } + + _cairo_xlib_surface_put_gc (dst->display, dst, gc); + release (dst); + return CAIRO_STATUS_SUCCESS; +} + +static int +_render_operator (cairo_operator_t op) +{ + switch (op) { + case CAIRO_OPERATOR_CLEAR: + return PictOpClear; + + case CAIRO_OPERATOR_SOURCE: + return PictOpSrc; + case CAIRO_OPERATOR_OVER: + return PictOpOver; + case CAIRO_OPERATOR_IN: + return PictOpIn; + case CAIRO_OPERATOR_OUT: + return PictOpOut; + case CAIRO_OPERATOR_ATOP: + return PictOpAtop; + + case CAIRO_OPERATOR_DEST: + return PictOpDst; + case CAIRO_OPERATOR_DEST_OVER: + return PictOpOverReverse; + case CAIRO_OPERATOR_DEST_IN: + return PictOpInReverse; + case CAIRO_OPERATOR_DEST_OUT: + return PictOpOutReverse; + case CAIRO_OPERATOR_DEST_ATOP: + return PictOpAtopReverse; + + case CAIRO_OPERATOR_XOR: + return PictOpXor; + case CAIRO_OPERATOR_ADD: + return PictOpAdd; + case CAIRO_OPERATOR_SATURATE: + return PictOpSaturate; + + case CAIRO_OPERATOR_MULTIPLY: + return PictOpMultiply; + case CAIRO_OPERATOR_SCREEN: + return PictOpScreen; + case CAIRO_OPERATOR_OVERLAY: + return PictOpOverlay; + case CAIRO_OPERATOR_DARKEN: + return PictOpDarken; + case CAIRO_OPERATOR_LIGHTEN: + return PictOpLighten; + case CAIRO_OPERATOR_COLOR_DODGE: + return PictOpColorDodge; + case CAIRO_OPERATOR_COLOR_BURN: + return PictOpColorBurn; + case CAIRO_OPERATOR_HARD_LIGHT: + return PictOpHardLight; + case CAIRO_OPERATOR_SOFT_LIGHT: + return PictOpSoftLight; + case CAIRO_OPERATOR_DIFFERENCE: + return PictOpDifference; + case CAIRO_OPERATOR_EXCLUSION: + return PictOpExclusion; + case CAIRO_OPERATOR_HSL_HUE: + return PictOpHSLHue; + case CAIRO_OPERATOR_HSL_SATURATION: + return PictOpHSLSaturation; + case CAIRO_OPERATOR_HSL_COLOR: + return PictOpHSLColor; + case CAIRO_OPERATOR_HSL_LUMINOSITY: + return PictOpHSLLuminosity; + + default: + ASSERT_NOT_REACHED; + return PictOpOver; + } +} + +static cairo_bool_t +fill_reduces_to_source (cairo_operator_t op, + const cairo_color_t *color, + cairo_xlib_surface_t *dst) +{ + if (dst->base.is_clear || CAIRO_COLOR_IS_OPAQUE (color)) { + if (op == CAIRO_OPERATOR_OVER) + return TRUE; + if (op == CAIRO_OPERATOR_ADD) + return (dst->base.content & CAIRO_CONTENT_COLOR) == 0; + } + + return FALSE; +} + +static cairo_int_status_t +fill_rectangles (void *abstract_surface, + cairo_operator_t op, + const cairo_color_t *color, + cairo_rectangle_int_t *rects, + int num_rects) +{ + cairo_xlib_surface_t *dst = abstract_surface; + XRenderColor render_color; + int i; + + //X_DEBUG ((display->display, "fill_rectangles (dst=%x)", (unsigned int) surface->drawable)); + + if (fill_reduces_to_source (op, color, dst)) + op = CAIRO_OPERATOR_SOURCE; + + if (!CAIRO_RENDER_HAS_FILL_RECTANGLES(dst->display)) { + cairo_int_status_t status; + + status = CAIRO_INT_STATUS_UNSUPPORTED; + if (op == CAIRO_OPERATOR_SOURCE) + status = _cairo_xlib_core_fill_rectangles (dst, color, num_rects, rects); + return status; + } + + render_color.red = color->red_short; + render_color.green = color->green_short; + render_color.blue = color->blue_short; + render_color.alpha = color->alpha_short; + + _cairo_xlib_surface_ensure_picture (dst); + if (num_rects == 1) { + /* Take advantage of the protocol compaction that libXrender performs + * to amalgamate sequences of XRenderFillRectangle(). + */ + XRenderFillRectangle (dst->dpy, + _render_operator (op), + dst->picture, + &render_color, + rects->x, rects->y, + rects->width, rects->height); + } else { + XRectangle stack_xrects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)]; + XRectangle *xrects = stack_xrects; + + if (num_rects > ARRAY_LENGTH (stack_xrects)) { + xrects = _cairo_malloc_ab (num_rects, sizeof (XRectangle)); + if (unlikely (xrects == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + for (i = 0; i < num_rects; i++) { + xrects[i].x = rects[i].x; + xrects[i].y = rects[i].y; + xrects[i].width = rects[i].width; + xrects[i].height = rects[i].height; + } + + XRenderFillRectangles (dst->dpy, + _render_operator (op), + dst->picture, + &render_color, xrects, num_rects); + + if (xrects != stack_xrects) + free (xrects); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +fill_boxes (void *abstract_surface, + cairo_operator_t op, + const cairo_color_t *color, + cairo_boxes_t *boxes) +{ + cairo_xlib_surface_t *dst = abstract_surface; + XRenderColor render_color; + + if (fill_reduces_to_source (op, color, dst)) + op = CAIRO_OPERATOR_SOURCE; + + if (!CAIRO_RENDER_HAS_FILL_RECTANGLES(dst->display)) { + cairo_int_status_t status; + + status = CAIRO_INT_STATUS_UNSUPPORTED; + if (op == CAIRO_OPERATOR_SOURCE) + status = _cairo_xlib_core_fill_boxes (dst, color, boxes); + return status; + } + + render_color.red = color->red_short; + render_color.green = color->green_short; + render_color.blue = color->blue_short; + render_color.alpha = color->alpha_short; + + _cairo_xlib_surface_ensure_picture (dst); + if (boxes->num_boxes == 1) { + int x1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.x); + int y1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.y); + int x2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.x); + int y2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.y); + + /* Take advantage of the protocol compaction that libXrender performs + * to amalgamate sequences of XRenderFillRectangle(). + */ + XRenderFillRectangle (dst->dpy, + _render_operator (op), + dst->picture, + &render_color, + x1, y1, + x2 - x1, y2 - y1); + } else { + XRectangle stack_xrects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)]; + XRectangle *xrects = stack_xrects; + struct _cairo_boxes_chunk *chunk; + int i, j; + + if (boxes->num_boxes > ARRAY_LENGTH (stack_xrects)) { + xrects = _cairo_malloc_ab (boxes->num_boxes, sizeof (XRectangle)); + if (unlikely (xrects == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + j = 0; + for (chunk = &boxes->chunks; chunk; chunk = chunk->next) { + for (i = 0; i < chunk->count; i++) { + int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x); + int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y); + int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x); + int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y); + + xrects[j].x = x1; + xrects[j].y = y1; + xrects[j].width = x2 - x1; + xrects[j].height = y2 - y1; + j++; + } + } + + XRenderFillRectangles (dst->dpy, + _render_operator (op), + dst->picture, + &render_color, xrects, j); + + if (xrects != stack_xrects) + free (xrects); + } + + return CAIRO_STATUS_SUCCESS; +} + +#if 0 +check_composite () + operation = _categorize_composite_operation (dst, op, src_pattern, + mask_pattern != NULL); + if (operation == DO_UNSUPPORTED) + return UNSUPPORTED ("unsupported operation"); + + //X_DEBUG ((display->display, "composite (dst=%x)", (unsigned int) dst->drawable)); + + operation = _recategorize_composite_operation (dst, op, src, &src_attr, + mask_pattern != NULL); + if (operation == DO_UNSUPPORTED) { + status = UNSUPPORTED ("unsupported operation"); + goto BAIL; + } +#endif + +static cairo_int_status_t +composite (void *abstract_dst, + cairo_operator_t op, + cairo_surface_t *abstract_src, + cairo_surface_t *abstract_mask, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height) +{ + cairo_xlib_surface_t *dst = abstract_dst; + cairo_xlib_source_t *src = (cairo_xlib_source_t *)abstract_src; + + op = _render_operator (op); + + _cairo_xlib_surface_ensure_picture (dst); + if (abstract_mask) { + cairo_xlib_source_t *mask = (cairo_xlib_source_t *)abstract_mask; + + XRenderComposite (dst->dpy, op, + src->picture, mask->picture, dst->picture, + src_x, src_y, + mask_x, mask_y, + dst_x, dst_y, + width, height); + } else { + XRenderComposite (dst->dpy, op, + src->picture, 0, dst->picture, + src_x, src_y, + 0, 0, + dst_x, dst_y, + width, height); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +lerp (void *abstract_dst, + cairo_surface_t *abstract_src, + cairo_surface_t *abstract_mask, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height) +{ + cairo_xlib_surface_t *dst = abstract_dst; + cairo_xlib_source_t *src = (cairo_xlib_source_t *)abstract_src; + cairo_xlib_source_t *mask = (cairo_xlib_source_t *)abstract_mask; + + _cairo_xlib_surface_ensure_picture (dst); + XRenderComposite (dst->dpy, PictOpOutReverse, + mask->picture, None, dst->picture, + mask_x, mask_y, + 0, 0, + dst_x, dst_y, + width, height); + XRenderComposite (dst->dpy, PictOpAdd, + src->picture, mask->picture, dst->picture, + src_x, src_y, + mask_x, mask_y, + dst_x, dst_y, + width, height); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +composite_boxes (void *abstract_dst, + cairo_operator_t op, + cairo_surface_t *abstract_src, + cairo_surface_t *abstract_mask, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + cairo_boxes_t *boxes, + const cairo_rectangle_int_t *extents) +{ + cairo_xlib_surface_t *dst = abstract_dst; + Picture src = ((cairo_xlib_source_t *)abstract_src)->picture; + Picture mask = abstract_mask ? ((cairo_xlib_source_t *)abstract_mask)->picture : 0; + XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)]; + XRectangle *rects = stack_rects; + struct _cairo_boxes_chunk *chunk; + int i, j; + + op = _render_operator (op); + _cairo_xlib_surface_ensure_picture (dst); + if (boxes->num_boxes == 1) { + int x1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.x); + int y1 = _cairo_fixed_integer_part (boxes->chunks.base[0].p1.y); + int x2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.x); + int y2 = _cairo_fixed_integer_part (boxes->chunks.base[0].p2.y); + + XRenderComposite (dst->dpy, op, + src, mask, dst->picture, + x1 + src_x, y1 + src_y, + x1 + mask_x, y1 + mask_y, + x1 - dst_x, y1 - dst_y, + x2 - x1, y2 - y1); + return CAIRO_STATUS_SUCCESS; + } + + if (boxes->num_boxes > ARRAY_LENGTH (stack_rects)) { + rects = _cairo_malloc_ab (boxes->num_boxes, sizeof (XRectangle)); + if (unlikely (rects == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + j = 0; + for (chunk = &boxes->chunks; chunk; chunk = chunk->next) { + for (i = 0; i < chunk->count; i++) { + int x1 = _cairo_fixed_integer_part (chunk->base[i].p1.x); + int y1 = _cairo_fixed_integer_part (chunk->base[i].p1.y); + int x2 = _cairo_fixed_integer_part (chunk->base[i].p2.x); + int y2 = _cairo_fixed_integer_part (chunk->base[i].p2.y); + + rects[j].x = x1 - dst_x; + rects[j].y = y1 - dst_y; + rects[j].width = x2 - x1; + rects[j].height = y2 - y1; + j++; + } + } + assert (j == boxes->num_boxes); + + XRenderSetPictureClipRectangles (dst->dpy, + dst->picture, + 0, 0, + rects, j); + if (rects != stack_rects) + free (rects); + + XRenderComposite (dst->dpy, op, + src, mask, dst->picture, + extents->x + src_x, extents->y + src_y, + extents->x + mask_x, extents->y + mask_y, + extents->x - dst_x, extents->y - dst_y, + extents->width, extents->height); + + set_clip_region (dst, NULL); + + return CAIRO_STATUS_SUCCESS; +} + +/* font rendering */ + +void +_cairo_xlib_font_close (cairo_xlib_font_t *priv) +{ + cairo_xlib_display_t *display = (cairo_xlib_display_t *)priv->base.key; + int i; + + /* XXX All I really want is to do is zap my glyphs... */ + _cairo_scaled_font_reset_cache (priv->font); + + for (i = 0; i < NUM_GLYPHSETS; i++) { + cairo_xlib_font_glyphset_t *info; + + info = &priv->glyphset[i]; + if (info->glyphset) + XRenderFreeGlyphSet (display->display, info->glyphset); + } + + /* XXX locking */ + cairo_list_del (&priv->link); + cairo_list_del (&priv->base.link); + free (priv); +} + +static void +_cairo_xlib_font_fini (cairo_scaled_font_private_t *abstract_private, + cairo_scaled_font_t *font) +{ + cairo_xlib_font_t *priv = (cairo_xlib_font_t *) abstract_private; + cairo_status_t status; + cairo_xlib_display_t *display; + int i; + + cairo_list_del (&priv->base.link); + cairo_list_del (&priv->link); + + status = _cairo_xlib_display_acquire (priv->device, &display); + if (unlikely (status)) /* this should be impossible but leak just in case */ + goto BAIL; + + for (i = 0; i < NUM_GLYPHSETS; i++) { + cairo_xlib_font_glyphset_t *info; + + info = &priv->glyphset[i]; + if (info->glyphset) + XRenderFreeGlyphSet (display->display, info->glyphset); + } + + cairo_device_release (&display->base); +BAIL: + cairo_device_destroy (priv->device); + free (priv); +} + +static cairo_xlib_font_t * +_cairo_xlib_font_create (cairo_xlib_display_t *display, + cairo_scaled_font_t *font) +{ + cairo_xlib_font_t *priv; + int i; + + priv = _cairo_calloc (sizeof (cairo_xlib_font_t)); + if (unlikely (priv == NULL)) + return NULL; + + _cairo_scaled_font_attach_private (font, &priv->base, display, + _cairo_xlib_font_fini); + + priv->device = cairo_device_reference (&display->base); + priv->font = font; + cairo_list_add (&priv->link, &display->fonts); + + for (i = 0; i < NUM_GLYPHSETS; i++) { + cairo_xlib_font_glyphset_t *info = &priv->glyphset[i]; + switch (i) { + case GLYPHSET_INDEX_ARGB32: info->format = CAIRO_FORMAT_ARGB32; break; + case GLYPHSET_INDEX_A8: info->format = CAIRO_FORMAT_A8; break; + case GLYPHSET_INDEX_A1: info->format = CAIRO_FORMAT_A1; break; + default: ASSERT_NOT_REACHED; break; + } + info->xrender_format = NULL; + info->glyphset = None; + info->to_free.count = 0; + } + + return priv; +} + +static int +_cairo_xlib_get_glyphset_index_for_format (cairo_format_t format) +{ + if (format == CAIRO_FORMAT_A8) + return GLYPHSET_INDEX_A8; + if (format == CAIRO_FORMAT_A1) + return GLYPHSET_INDEX_A1; + + assert (format == CAIRO_FORMAT_ARGB32); + return GLYPHSET_INDEX_ARGB32; +} + +static inline cairo_xlib_font_t * +_cairo_xlib_font_get (const cairo_xlib_display_t *display, + cairo_scaled_font_t *font) +{ + return (cairo_xlib_font_t *)_cairo_scaled_font_find_private (font, display); +} + +typedef struct { + cairo_scaled_glyph_private_t base; + + + cairo_xlib_font_glyphset_t *glyphset; +} cairo_xlib_glyph_private_t; + +static void +_cairo_xlib_glyph_fini (cairo_scaled_glyph_private_t *glyph_private, + cairo_scaled_glyph_t *glyph, + cairo_scaled_font_t *font) +{ + cairo_xlib_glyph_private_t *priv = (cairo_xlib_glyph_private_t *)glyph_private; + + if (! font->finished) { + cairo_xlib_font_t *font_private; + struct _cairo_xlib_font_glyphset_free_glyphs *to_free; + cairo_xlib_font_glyphset_t *info; + + font_private = _cairo_xlib_font_get (glyph_private->key, font); + assert (font_private); + + info = priv->glyphset; + to_free = &info->to_free; + if (to_free->count == ARRAY_LENGTH (to_free->indices)) { + cairo_xlib_display_t *display; + + if (_cairo_xlib_display_acquire (font_private->device, + &display) == CAIRO_STATUS_SUCCESS) { + XRenderFreeGlyphs (display->display, + info->glyphset, + to_free->indices, + to_free->count); + cairo_device_release (&display->base); + } + + to_free->count = 0; + } + + to_free->indices[to_free->count++] = glyph->hash_entry.hash; + } + + cairo_list_del (&glyph_private->link); + free (glyph_private); +} + +static cairo_status_t +_cairo_xlib_glyph_attach (cairo_xlib_display_t *display, + cairo_scaled_glyph_t *glyph, + cairo_xlib_font_glyphset_t *info) +{ + cairo_xlib_glyph_private_t *priv; + + priv = _cairo_calloc (sizeof (*priv)); + if (unlikely (priv == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + _cairo_scaled_glyph_attach_private (glyph, &priv->base, display, + _cairo_xlib_glyph_fini); + priv->glyphset = info; + + glyph->dev_private = info; + glyph->dev_private_key = display; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_xlib_font_glyphset_t * +_cairo_xlib_font_get_glyphset_info_for_format (cairo_xlib_display_t *display, + cairo_scaled_font_t *font, + cairo_format_t format) +{ + cairo_xlib_font_t *priv; + cairo_xlib_font_glyphset_t *info; + int glyphset_index; + + glyphset_index = _cairo_xlib_get_glyphset_index_for_format (format); + + priv = _cairo_xlib_font_get (display, font); + if (priv == NULL) { + priv = _cairo_xlib_font_create (display, font); + if (priv == NULL) + return NULL; + } + + info = &priv->glyphset[glyphset_index]; + if (info->glyphset == None) { + info->xrender_format = + _cairo_xlib_display_get_xrender_format (display, info->format); + info->glyphset = XRenderCreateGlyphSet (display->display, + info->xrender_format); + } + + return info; +} + +static cairo_bool_t +has_pending_free_glyph (cairo_xlib_font_glyphset_t *info, + unsigned long glyph_index) +{ + struct _cairo_xlib_font_glyphset_free_glyphs *to_free; + int i; + + to_free = &info->to_free; + for (i = 0; i < to_free->count; i++) { + if (to_free->indices[i] == glyph_index) { + to_free->count--; + memmove (&to_free->indices[i], + &to_free->indices[i+1], + (to_free->count - i) * sizeof (to_free->indices[0])); + return TRUE; + } + } + + return FALSE; +} + +static cairo_xlib_font_glyphset_t * +find_pending_free_glyph (cairo_xlib_display_t *display, + cairo_scaled_font_t *font, + unsigned long glyph_index, + cairo_image_surface_t *surface) +{ + cairo_xlib_font_t *priv; + int i; + + priv = _cairo_xlib_font_get (display, font); + if (priv == NULL) + return NULL; + + if (surface != NULL) { + i = _cairo_xlib_get_glyphset_index_for_format (surface->format); + if (has_pending_free_glyph (&priv->glyphset[i], glyph_index)) + return &priv->glyphset[i]; + } else { + for (i = 0; i < NUM_GLYPHSETS; i++) { + if (has_pending_free_glyph (&priv->glyphset[i], glyph_index)) + return &priv->glyphset[i]; + } + } + + return NULL; +} + +static cairo_status_t +_cairo_xlib_surface_add_glyph (cairo_xlib_display_t *display, + cairo_scaled_font_t *font, + cairo_scaled_glyph_t **pscaled_glyph) +{ + XGlyphInfo glyph_info; + unsigned long glyph_index; + unsigned char *data; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_scaled_glyph_t *glyph = *pscaled_glyph; + cairo_image_surface_t *glyph_surface = glyph->surface; + cairo_bool_t already_had_glyph_surface; + cairo_xlib_font_glyphset_t *info; + + glyph_index = glyph->hash_entry.hash; + + /* check to see if we have a pending XRenderFreeGlyph for this glyph */ + info = find_pending_free_glyph (display, font, glyph_index, glyph_surface); + if (info != NULL) + return _cairo_xlib_glyph_attach (display, glyph, info); + + if (glyph_surface == NULL) { + status = _cairo_scaled_glyph_lookup (font, + glyph_index, + CAIRO_SCALED_GLYPH_INFO_METRICS | + CAIRO_SCALED_GLYPH_INFO_SURFACE, + NULL, /* foreground color */ + pscaled_glyph); + if (unlikely (status)) + return status; + + glyph = *pscaled_glyph; + glyph_surface = glyph->surface; + already_had_glyph_surface = FALSE; + } else { + already_had_glyph_surface = TRUE; + } + + info = _cairo_xlib_font_get_glyphset_info_for_format (display, font, + glyph_surface->format); + +#if 0 + /* If the glyph surface has zero height or width, we create + * a clear 1x1 surface, to avoid various X server bugs. + */ + if (glyph_surface->width == 0 || glyph_surface->height == 0) { + cairo_surface_t *tmp_surface; + + tmp_surface = cairo_image_surface_create (info->format, 1, 1); + status = tmp_surface->status; + if (unlikely (status)) + goto BAIL; + + tmp_surface->device_transform = glyph_surface->base.device_transform; + tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse; + + glyph_surface = (cairo_image_surface_t *) tmp_surface; + } +#endif + + /* If the glyph format does not match the font format, then we + * create a temporary surface for the glyph image with the font's + * format. + */ + if (glyph_surface->format != info->format) { + cairo_surface_pattern_t pattern; + cairo_surface_t *tmp_surface; + + tmp_surface = cairo_image_surface_create (info->format, + glyph_surface->width, + glyph_surface->height); + status = tmp_surface->status; + if (unlikely (status)) + goto BAIL; + + tmp_surface->device_transform = glyph_surface->base.device_transform; + tmp_surface->device_transform_inverse = glyph_surface->base.device_transform_inverse; + + _cairo_pattern_init_for_surface (&pattern, &glyph_surface->base); + status = _cairo_surface_paint (tmp_surface, + CAIRO_OPERATOR_SOURCE, &pattern.base, + NULL); + _cairo_pattern_fini (&pattern.base); + + glyph_surface = (cairo_image_surface_t *) tmp_surface; + + if (unlikely (status)) + goto BAIL; + } + + /* XXX: FRAGILE: We're ignore device_transform scaling here. A bug? */ + glyph_info.x = _cairo_lround (glyph_surface->base.device_transform.x0); + glyph_info.y = _cairo_lround (glyph_surface->base.device_transform.y0); + glyph_info.width = glyph_surface->width; + glyph_info.height = glyph_surface->height; + glyph_info.xOff = glyph->x_advance; + glyph_info.yOff = glyph->y_advance; + + data = glyph_surface->data; + + /* flip formats around */ + switch (_cairo_xlib_get_glyphset_index_for_format (glyph->surface->format)) { + case GLYPHSET_INDEX_A1: + /* local bitmaps are always stored with bit == byte */ + if (_cairo_is_little_endian() != (BitmapBitOrder (display->display) == LSBFirst)) { + int c = glyph_surface->stride * glyph_surface->height; + unsigned char *d; + unsigned char *new, *n; + + if (c == 0) + break; + + new = _cairo_malloc (c); + if (!new) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto BAIL; + } + n = new; + d = data; + do { + char b = *d++; + b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55); + b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33); + b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f); + *n++ = b; + } while (--c); + data = new; + } + break; + case GLYPHSET_INDEX_A8: + break; + case GLYPHSET_INDEX_ARGB32: + if (_cairo_is_little_endian() != (ImageByteOrder (display->display) == LSBFirst)) { + unsigned int c = glyph_surface->stride * glyph_surface->height / 4; + const uint32_t *d; + uint32_t *new, *n; + + if (c == 0) + break; + + new = _cairo_malloc (4 * c); + if (unlikely (new == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto BAIL; + } + n = new; + d = (uint32_t *) data; + do { + *n++ = bswap_32 (*d); + d++; + } while (--c); + data = (uint8_t *) new; + } + break; + default: + ASSERT_NOT_REACHED; + break; + } + /* XXX assume X server wants pixman padding. Xft assumes this as well */ + + XRenderAddGlyphs (display->display, info->glyphset, + &glyph_index, &glyph_info, 1, + (char *) data, + glyph_surface->stride * glyph_surface->height); + + if (data != glyph_surface->data) + free (data); + + status = _cairo_xlib_glyph_attach (display, glyph, info); + + BAIL: + if (glyph_surface != glyph->surface) + cairo_surface_destroy (&glyph_surface->base); + + /* if the scaled glyph didn't already have a surface attached + * to it, release the created surface now that we have it + * uploaded to the X server. If the surface has already been + * there (eg. because image backend requested it), leave it in + * the cache + */ + if (!already_had_glyph_surface) + _cairo_scaled_glyph_set_surface (glyph, font, NULL); + + return status; +} + +typedef void (*cairo_xrender_composite_text_func_t) + (Display *dpy, + int op, + Picture src, + Picture dst, + _Xconst XRenderPictFormat *maskFormat, + int xSrc, + int ySrc, + int xDst, + int yDst, + _Xconst XGlyphElt8 *elts, + int nelt); + +/* Build a struct of the same size of #cairo_glyph_t that can be used both as + * an input glyph with double coordinates, and as "working" glyph with + * integer from-current-point offsets. */ +typedef union { + cairo_glyph_t d; + unsigned long index; + struct { + unsigned long index; + int x; + int y; + } i; +} cairo_xlib_glyph_t; + +/* compile-time assert that #cairo_xlib_glyph_t is the same size as #cairo_glyph_t */ +COMPILE_TIME_ASSERT (sizeof (cairo_xlib_glyph_t) == sizeof (cairo_glyph_t)); + +/* Start a new element for the first glyph, + * or for any glyph that has unexpected position, + * or if current element has too many glyphs + * (Xrender limits each element to 252 glyphs, we limit them to 128) + * + * These same conditions need to be mirrored between + * _cairo_xlib_surface_emit_glyphs and _emit_glyph_chunks + */ +#define _start_new_glyph_elt(count, glyph) \ + (((count) & 127) == 0 || (glyph)->i.x || (glyph)->i.y) + +static cairo_status_t +_emit_glyphs_chunk (cairo_xlib_display_t *display, + cairo_xlib_surface_t *dst, + int dst_x, int dst_y, + cairo_xlib_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *font, + cairo_bool_t use_mask, + cairo_operator_t op, + cairo_xlib_source_t *src, + int src_x, int src_y, + /* info for this chunk */ + int num_elts, + int width, + cairo_xlib_font_glyphset_t *info) +{ + /* Which XRenderCompositeText function to use */ + cairo_xrender_composite_text_func_t composite_text_func; + int size; + + /* Element buffer stuff */ + XGlyphElt8 *elts; + XGlyphElt8 stack_elts[CAIRO_STACK_ARRAY_LENGTH (XGlyphElt8)]; + + /* Reuse the input glyph array for output char generation */ + char *char8 = (char *) glyphs; + unsigned short *char16 = (unsigned short *) glyphs; + unsigned int *char32 = (unsigned int *) glyphs; + + int i; + int nelt; /* Element index */ + int n; /* Num output glyphs in current element */ + int j; /* Num output glyphs so far */ + + switch (width) { + case 1: + /* don't cast the 8-variant, to catch possible mismatches */ + composite_text_func = XRenderCompositeText8; + size = sizeof (char); + break; + case 2: + composite_text_func = (cairo_xrender_composite_text_func_t) XRenderCompositeText16; + size = sizeof (unsigned short); + break; + default: + case 4: + composite_text_func = (cairo_xrender_composite_text_func_t) XRenderCompositeText32; + size = sizeof (unsigned int); + } + + /* Allocate element array */ + if (num_elts <= ARRAY_LENGTH (stack_elts)) { + elts = stack_elts; + } else { + elts = _cairo_malloc_ab (num_elts, sizeof (XGlyphElt8)); + if (unlikely (elts == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + /* Fill them in */ + nelt = 0; + n = 0; + j = 0; + for (i = 0; i < num_glyphs; i++) { + /* Start a new element for first output glyph, + * or for any glyph that has unexpected position, + * or if current element has too many glyphs. + * + * These same conditions are mirrored in _cairo_xlib_surface_emit_glyphs() + */ + if (_start_new_glyph_elt (j, &glyphs[i])) { + if (j) { + elts[nelt].nchars = n; + nelt++; + n = 0; + } + elts[nelt].chars = char8 + size * j; + elts[nelt].glyphset = info->glyphset; + elts[nelt].xOff = glyphs[i].i.x; + elts[nelt].yOff = glyphs[i].i.y; + } + + switch (width) { + case 1: char8 [j] = (char) glyphs[i].index; break; + case 2: char16[j] = (unsigned short) glyphs[i].index; break; + default: + case 4: char32[j] = (unsigned int) glyphs[i].index; break; + } + + n++; + j++; + } + + if (n) { + elts[nelt].nchars = n; + nelt++; + } + + /* Check that we agree with _cairo_xlib_surface_emit_glyphs() on the + * expected number of xGlyphElts. */ + assert (nelt == num_elts); + + composite_text_func (display->display, op, + src->picture, + dst->picture, + use_mask ? info->xrender_format : NULL, + src_x + elts[0].xOff + dst_x, + src_y + elts[0].yOff + dst_y, + elts[0].xOff, elts[0].yOff, + (XGlyphElt8 *) elts, nelt); + + if (elts != stack_elts) + free (elts); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +check_composite_glyphs (const cairo_composite_rectangles_t *extents, + cairo_scaled_font_t *font, + cairo_glyph_t *glyphs, + int *num_glyphs) +{ + cairo_xlib_surface_t *dst = (cairo_xlib_surface_t *)extents->surface; + cairo_xlib_display_t *display = dst->display; + int max_request_size, size; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + if (! CAIRO_RENDER_SUPPORTS_OPERATOR (display, extents->op)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* The glyph coordinates must be representable in an int16_t. + * When possible, they will be expressed as an offset from the + * previous glyph, otherwise they will be an offset from the + * surface origin. If we can't guarantee this to be possible, + * fallback. + */ + if (extents->bounded.x + extents->bounded.width > INT16_MAX || + extents->bounded.y + extents->bounded.height> INT16_MAX || + extents->bounded.x < INT16_MIN || + extents->bounded.y < INT16_MIN) + { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + /* Approximate the size of the largest glyph and fallback if we can not + * upload it to the xserver. + */ + size = ceil (font->max_scale); + size = 4 * size * size; + max_request_size = (XExtendedMaxRequestSize (display->display) ? XExtendedMaxRequestSize (display->display) + : XMaxRequestSize (display->display)) * 4 - + sz_xRenderAddGlyphsReq - + sz_xGlyphInfo - + 8; + if (size >= max_request_size) + return CAIRO_INT_STATUS_UNSUPPORTED; + + return CAIRO_STATUS_SUCCESS; +} + +/* sz_xGlyphtElt required alignment to a 32-bit boundary, so ensure we have + * enough room for padding */ +#define _cairo_sz_xGlyphElt (sz_xGlyphElt + 4) + +#define PHASE(x) ((int)(floor (4 * (x + 0.125)) - 4 * floor (x + 0.125))) +#define POSITION(x) ((int) floor (x + 0.125)) + +static cairo_int_status_t +composite_glyphs (void *surface, + cairo_operator_t op, + cairo_surface_t *_src, + int src_x, + int src_y, + int dst_x, + int dst_y, + cairo_composite_glyphs_info_t *info) +{ + cairo_xlib_surface_t *dst = surface; + cairo_xlib_glyph_t *glyphs = (cairo_xlib_glyph_t *)info->glyphs; + cairo_xlib_source_t *src = (cairo_xlib_source_t *)_src; + cairo_xlib_display_t *display = dst->display; + cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; + cairo_scaled_glyph_t *glyph; + cairo_fixed_t x = dst_x, y = dst_y; + cairo_xlib_font_glyphset_t *glyphset = NULL, *this_glyphset_info; + + unsigned long max_index = 0; + int width = 1; + int num_elts = 0; + int num_out_glyphs = 0; + int num_glyphs = info->num_glyphs; + + int max_request_size = XMaxRequestSize (display->display) * 4 + - MAX (sz_xRenderCompositeGlyphs8Req, + MAX(sz_xRenderCompositeGlyphs16Req, + sz_xRenderCompositeGlyphs32Req)); + int request_size = 0; + int i; + + op = _render_operator (op), + _cairo_xlib_surface_ensure_picture (dst); + for (i = 0; i < num_glyphs; i++) { + unsigned long xphase, yphase; + int this_x, this_y; + int old_width; + + xphase = PHASE(glyphs[i].d.x); + yphase = PHASE(glyphs[i].d.y); + + glyphs[i].index |= (xphase << 24) | (yphase << 26); + + status = _cairo_scaled_glyph_lookup (info->font, + glyphs[i].index, + CAIRO_SCALED_GLYPH_INFO_METRICS, + NULL, /* foreground color */ + &glyph); + if (unlikely (status)) + return status; + + this_x = POSITION (glyphs[i].d.x); + this_y = POSITION (glyphs[i].d.y); + + /* Send unsent glyphs to the server */ + if (glyph->dev_private_key != display) { + status = _cairo_xlib_surface_add_glyph (display, info->font, &glyph); + if (unlikely (status)) + return status; + } + + this_glyphset_info = glyph->dev_private; + if (!glyphset) + glyphset = this_glyphset_info; + + /* The invariant here is that we can always flush the glyphs + * accumulated before this one, using old_width, and they + * would fit in the request. + */ + old_width = width; + + /* Update max glyph index */ + if (glyphs[i].index > max_index) { + max_index = glyphs[i].index; + if (max_index >= 65536) + width = 4; + else if (max_index >= 256) + width = 2; + if (width != old_width) + request_size += (width - old_width) * num_out_glyphs; + } + + /* If we will pass the max request size by adding this glyph, + * flush current glyphs. Note that we account for a + * possible element being added below. + * + * Also flush if changing glyphsets, as Xrender limits one mask + * format per request, so we can either break up, or use a + * wide-enough mask format. We do the former. One reason to + * prefer the latter is the fact that Xserver ADDs all glyphs + * to the mask first, and then composes that to final surface, + * though it's not a big deal. + * + * If the glyph has a coordinate which cannot be represented + * as a 16-bit offset from the previous glyph, flush the + * current chunk. The current glyph will be the first one in + * the next chunk, thus its coordinates will be an offset from + * the destination origin. This offset is guaranteed to be + * representable as 16-bit offset (otherwise we would have + * fallen back). + */ + if (request_size + width > max_request_size - _cairo_sz_xGlyphElt || + this_x - x > INT16_MAX || this_x - x < INT16_MIN || + this_y - y > INT16_MAX || this_y - y < INT16_MIN || + (this_glyphset_info != glyphset)) { + status = _emit_glyphs_chunk (display, dst, dst_x, dst_y, + glyphs, i, info->font, info->use_mask, + op, src, src_x, src_y, + num_elts, old_width, glyphset); + if (unlikely (status)) + return status; + + glyphs += i; + num_glyphs -= i; + i = 0; + max_index = glyphs[i].index; + width = max_index < 256 ? 1 : max_index < 65536 ? 2 : 4; + request_size = 0; + num_elts = 0; + num_out_glyphs = 0; + x = y = 0; + glyphset = this_glyphset_info; + } + + /* Convert absolute glyph position to relative-to-current-point + * position */ + glyphs[i].i.x = this_x - x; + glyphs[i].i.y = this_y - y; + + /* Start a new element for the first glyph, + * or for any glyph that has unexpected position, + * or if current element has too many glyphs. + * + * These same conditions are mirrored in _emit_glyphs_chunk(). + */ + if (_start_new_glyph_elt (num_out_glyphs, &glyphs[i])) { + num_elts++; + request_size += _cairo_sz_xGlyphElt; + } + + /* adjust current-position */ + x = this_x + glyph->x_advance; + y = this_y + glyph->y_advance; + + num_out_glyphs++; + request_size += width; + } + + if (num_elts) { + status = _emit_glyphs_chunk (display, dst, dst_x, dst_y, + glyphs, i, info->font, info->use_mask, + op, src, src_x, src_y, + num_elts, width, glyphset); + } + + return status; +} + +const cairo_compositor_t * +_cairo_xlib_mask_compositor_get (void) +{ + static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT; + static cairo_mask_compositor_t compositor; + + if (_cairo_atomic_init_once_enter(&once)) { + _cairo_mask_compositor_init (&compositor, + _cairo_xlib_fallback_compositor_get ()); + + compositor.acquire = acquire; + compositor.release = release; + compositor.set_clip_region = set_clip_region; + compositor.pattern_to_surface = _cairo_xlib_source_create_for_pattern; + compositor.draw_image_boxes = draw_image_boxes; + compositor.fill_rectangles = fill_rectangles; + compositor.fill_boxes = fill_boxes; + compositor.copy_boxes = copy_boxes; + compositor.check_composite = check_composite; + compositor.composite = composite; + //compositor.check_composite_boxes = check_composite_boxes; + compositor.composite_boxes = composite_boxes; + compositor.check_composite_glyphs = check_composite_glyphs; + compositor.composite_glyphs = composite_glyphs; + + _cairo_atomic_init_once_leave(&once); + } + + return &compositor.base; +} + +#define CAIRO_FIXED_16_16_MIN -32768 +#define CAIRO_FIXED_16_16_MAX 32767 + +static cairo_bool_t +line_exceeds_16_16 (const cairo_line_t *line) +{ + return + line->p1.x < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) || + line->p1.x > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX) || + line->p2.x < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) || + line->p2.x > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX) || + line->p1.y < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) || + line->p1.y > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX) || + line->p2.y < _cairo_fixed_from_int (CAIRO_FIXED_16_16_MIN) || + line->p2.y > _cairo_fixed_from_int (CAIRO_FIXED_16_16_MAX); +} + +static void +project_line_x_onto_16_16 (const cairo_line_t *line, + cairo_fixed_t top, + cairo_fixed_t bottom, + XLineFixed *out) +{ + cairo_point_double_t p1, p2; + double m; + + p1.x = _cairo_fixed_to_double (line->p1.x); + p1.y = _cairo_fixed_to_double (line->p1.y); + + p2.x = _cairo_fixed_to_double (line->p2.x); + p2.y = _cairo_fixed_to_double (line->p2.y); + + m = (p2.x - p1.x) / (p2.y - p1.y); + out->p1.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (top - line->p1.y)); + out->p2.x = _cairo_fixed_16_16_from_double (p1.x + m * _cairo_fixed_to_double (bottom - line->p1.y)); +} +#if 0 +static cairo_int_status_T +check_composite_trapezoids () +{ + operation = _categorize_composite_operation (dst, op, pattern, TRUE); + if (operation == DO_UNSUPPORTED) + return UNSUPPORTED ("unsupported operation"); + + operation = _recategorize_composite_operation (dst, op, src, + &attributes, TRUE); + if (operation == DO_UNSUPPORTED) { + status = UNSUPPORTED ("unsupported operation"); + goto BAIL; + } + +} +#endif + +static cairo_int_status_t +composite_traps (void *abstract_dst, + cairo_operator_t op, + cairo_surface_t *abstract_src, + int src_x, + int src_y, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents, + cairo_antialias_t antialias, + cairo_traps_t *traps) +{ + cairo_xlib_surface_t *dst = abstract_dst; + cairo_xlib_display_t *display = dst->display; + cairo_xlib_source_t *src = (cairo_xlib_source_t *)abstract_src; + XRenderPictFormat *pict_format; + XTrapezoid xtraps_stack[CAIRO_STACK_ARRAY_LENGTH (XTrapezoid)]; + XTrapezoid *xtraps = xtraps_stack; + int dx, dy; + int i; + + //X_DEBUG ((display->display, "composite_trapezoids (dst=%x)", (unsigned int) dst->drawable)); + + if (traps->num_traps == 0) + return CAIRO_STATUS_SUCCESS; + + if (dst->base.is_clear && + (op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD)) + { + op = CAIRO_OPERATOR_SOURCE; + } + + pict_format = + _cairo_xlib_display_get_xrender_format (display, + antialias == CAIRO_ANTIALIAS_NONE ? CAIRO_FORMAT_A1 : CAIRO_FORMAT_A8); + + if (traps->num_traps > ARRAY_LENGTH (xtraps_stack)) { + xtraps = _cairo_malloc_ab (traps->num_traps, sizeof (XTrapezoid)); + if (unlikely (xtraps == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + dx = -dst_x << 16; + dy = -dst_y << 16; + for (i = 0; i < traps->num_traps; i++) { + cairo_trapezoid_t *t = &traps->traps[i]; + + /* top/bottom will be clamped to surface bounds */ + xtraps[i].top = _cairo_fixed_to_16_16(t->top) + dy; + xtraps[i].bottom = _cairo_fixed_to_16_16(t->bottom) + dy; + + /* However, all the other coordinates will have been left untouched so + * as not to introduce numerical error. Recompute them if they + * exceed the 16.16 limits. + */ + if (unlikely (line_exceeds_16_16 (&t->left))) { + project_line_x_onto_16_16 (&t->left, t->top, t->bottom, + &xtraps[i].left); + xtraps[i].left.p1.x += dx; + xtraps[i].left.p2.x += dx; + xtraps[i].left.p1.y = xtraps[i].top; + xtraps[i].left.p2.y = xtraps[i].bottom; + } else { + xtraps[i].left.p1.x = _cairo_fixed_to_16_16(t->left.p1.x) + dx; + xtraps[i].left.p1.y = _cairo_fixed_to_16_16(t->left.p1.y) + dy; + xtraps[i].left.p2.x = _cairo_fixed_to_16_16(t->left.p2.x) + dx; + xtraps[i].left.p2.y = _cairo_fixed_to_16_16(t->left.p2.y) + dy; + } + + if (unlikely (line_exceeds_16_16 (&t->right))) { + project_line_x_onto_16_16 (&t->right, t->top, t->bottom, + &xtraps[i].right); + xtraps[i].right.p1.x += dx; + xtraps[i].right.p2.x += dx; + xtraps[i].right.p1.y = xtraps[i].top; + xtraps[i].right.p2.y = xtraps[i].bottom; + } else { + xtraps[i].right.p1.x = _cairo_fixed_to_16_16(t->right.p1.x) + dx; + xtraps[i].right.p1.y = _cairo_fixed_to_16_16(t->right.p1.y) + dy; + xtraps[i].right.p2.x = _cairo_fixed_to_16_16(t->right.p2.x) + dx; + xtraps[i].right.p2.y = _cairo_fixed_to_16_16(t->right.p2.y) + dy; + } + } + + if (xtraps[0].left.p1.y < xtraps[0].left.p2.y) { + src_x += _cairo_fixed_16_16_floor (xtraps[0].left.p1.x); + src_y += _cairo_fixed_16_16_floor (xtraps[0].left.p1.y); + } else { + src_x += _cairo_fixed_16_16_floor (xtraps[0].left.p2.x); + src_y += _cairo_fixed_16_16_floor (xtraps[0].left.p2.y); + } + src_x += dst_x; + src_y += dst_y; + + _cairo_xlib_surface_ensure_picture (dst); + _cairo_xlib_surface_set_precision (dst, antialias); + XRenderCompositeTrapezoids (dst->dpy, + _render_operator (op), + src->picture, dst->picture, + pict_format, + src_x, src_y, + xtraps, traps->num_traps); + + if (xtraps != xtraps_stack) + free (xtraps); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +composite_tristrip (void *abstract_dst, + cairo_operator_t op, + cairo_surface_t *abstract_src, + int src_x, + int src_y, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents, + cairo_antialias_t antialias, + cairo_tristrip_t *strip) +{ + cairo_xlib_surface_t *dst = abstract_dst; + cairo_xlib_display_t *display = dst->display; + cairo_xlib_source_t *src = (cairo_xlib_source_t *)abstract_src; + XRenderPictFormat *pict_format; + XPointFixed points_stack[CAIRO_STACK_ARRAY_LENGTH (XPointFixed)]; + XPointFixed *points = points_stack; + int dx, dy; + int i; + + //X_DEBUG ((display->display, "composite_trapezoids (dst=%x)", (unsigned int) dst->drawable)); + + pict_format = + _cairo_xlib_display_get_xrender_format (display, + antialias == CAIRO_ANTIALIAS_NONE ? CAIRO_FORMAT_A1 : CAIRO_FORMAT_A8); + + if (strip->num_points > ARRAY_LENGTH (points_stack)) { + points = _cairo_malloc_ab (strip->num_points, sizeof (XPointFixed)); + if (unlikely (points == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + dx = -dst_x << 16; + dy = -dst_y << 16; + for (i = 0; i < strip->num_points; i++) { + cairo_point_t *p = &strip->points[i]; + + points[i].x = _cairo_fixed_to_16_16(p->x) + dx; + points[i].y = _cairo_fixed_to_16_16(p->y) + dy; + } + + src_x += _cairo_fixed_16_16_floor (points[0].x) + dst_x; + src_y += _cairo_fixed_16_16_floor (points[0].y) + dst_y; + + _cairo_xlib_surface_ensure_picture (dst); + _cairo_xlib_surface_set_precision (dst, antialias); + XRenderCompositeTriStrip (dst->dpy, + _render_operator (op), + src->picture, dst->picture, + pict_format, + src_x, src_y, + points, strip->num_points); + + if (points != points_stack) + free (points); + + return CAIRO_STATUS_SUCCESS; +} + +const cairo_compositor_t * +_cairo_xlib_traps_compositor_get (void) +{ + static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT; + static cairo_traps_compositor_t compositor; + + if (_cairo_atomic_init_once_enter(&once)) { + _cairo_traps_compositor_init (&compositor, + _cairo_xlib_mask_compositor_get ()); + + compositor.acquire = acquire; + compositor.release = release; + compositor.set_clip_region = set_clip_region; + compositor.pattern_to_surface = _cairo_xlib_source_create_for_pattern; + compositor.draw_image_boxes = draw_image_boxes; + compositor.copy_boxes = copy_boxes; + compositor.fill_boxes = fill_boxes; + compositor.check_composite = check_composite; + compositor.composite = composite; + compositor.lerp = lerp; + //compositor.check_composite_boxes = check_composite_boxes; + compositor.composite_boxes = composite_boxes; + //compositor.check_composite_traps = check_composite_traps; + compositor.composite_traps = composite_traps; + //compositor.check_composite_tristrip = check_composite_tristrip; + compositor.composite_tristrip = composite_tristrip; + compositor.check_composite_glyphs = check_composite_glyphs; + compositor.composite_glyphs = composite_glyphs; + + _cairo_atomic_init_once_leave(&once); + } + + return &compositor.base; +} + +#endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */ diff --git a/local/recipes/libs/cairo/source/src/cairo-xlib-screen.c b/local/recipes/libs/cairo/source/src/cairo-xlib-screen.c new file mode 100644 index 0000000000..cd8e2a75db --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-xlib-screen.c @@ -0,0 +1,467 @@ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Partially on code from xftdpy.c + * + * Copyright © 2000 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "cairoint.h" + +#if !CAIRO_HAS_XLIB_XCB_FUNCTIONS + +#include "cairo-xlib-private.h" +#include "cairo-xlib-xrender-private.h" + +#include "cairo-xlib-surface-private.h" +#include "cairo-error-private.h" +#include "cairo-list-inline.h" + +#include "cairo-fontconfig-private.h" + +static int +parse_boolean (const char *v) +{ + char c0, c1; + + c0 = *v; + if (c0 == 't' || c0 == 'T' || c0 == 'y' || c0 == 'Y' || c0 == '1') + return 1; + if (c0 == 'f' || c0 == 'F' || c0 == 'n' || c0 == 'N' || c0 == '0') + return 0; + if (c0 == 'o') + { + c1 = v[1]; + if (c1 == 'n' || c1 == 'N') + return 1; + if (c1 == 'f' || c1 == 'F') + return 0; + } + + return -1; +} + +static cairo_bool_t +get_boolean_default (Display *dpy, + const char *option, + cairo_bool_t *value) +{ + char *v; + int i; + + v = XGetDefault (dpy, "Xft", option); + if (v) { + i = parse_boolean (v); + if (i >= 0) { + *value = i; + return TRUE; + } + } + + return FALSE; +} + +static cairo_bool_t +get_integer_default (Display *dpy, + const char *option, + int *value) +{ + char *v, *e; + + v = XGetDefault (dpy, "Xft", option); + if (v) { +#if CAIRO_HAS_FC_FONT + if (FcNameConstant ((FcChar8 *) v, value)) + return TRUE; +#endif + + *value = strtol (v, &e, 0); + if (e != v) + return TRUE; + } + + return FALSE; +} + +static void +_cairo_xlib_init_screen_font_options (Display *dpy, + cairo_xlib_screen_t *info) +{ + cairo_bool_t xft_hinting; + cairo_bool_t xft_antialias; + int xft_hintstyle; + int xft_rgba; + int xft_lcdfilter; + cairo_antialias_t antialias; + cairo_subpixel_order_t subpixel_order; + cairo_lcd_filter_t lcd_filter; + cairo_hint_style_t hint_style; + + if (!get_boolean_default (dpy, "antialias", &xft_antialias)) + xft_antialias = TRUE; + + if (!get_integer_default (dpy, "lcdfilter", &xft_lcdfilter)) { + /* -1 is an non-existant Fontconfig constant used to differentiate + * the case when no lcdfilter property is available. + */ + xft_lcdfilter = -1; + } + + if (!get_boolean_default (dpy, "hinting", &xft_hinting)) + xft_hinting = TRUE; + + if (!get_integer_default (dpy, "hintstyle", &xft_hintstyle)) + xft_hintstyle = FC_HINT_FULL; + + if (!get_integer_default (dpy, "rgba", &xft_rgba)) + { + cairo_xlib_display_t *display = (cairo_xlib_display_t *) info->device; + + xft_rgba = FC_RGBA_UNKNOWN; + +#if RENDER_MAJOR > 0 || RENDER_MINOR >= 6 + if (display->render_major > 0 || display->render_minor >= 6) { + int render_order = XRenderQuerySubpixelOrder (dpy, + XScreenNumberOfScreen (info->screen)); + + switch (render_order) { + default: + case SubPixelUnknown: + xft_rgba = FC_RGBA_UNKNOWN; + break; + case SubPixelHorizontalRGB: + xft_rgba = FC_RGBA_RGB; + break; + case SubPixelHorizontalBGR: + xft_rgba = FC_RGBA_BGR; + break; + case SubPixelVerticalRGB: + xft_rgba = FC_RGBA_VRGB; + break; + case SubPixelVerticalBGR: + xft_rgba = FC_RGBA_VBGR; + break; + case SubPixelNone: + xft_rgba = FC_RGBA_NONE; + break; + } + } +#endif + } + + if (xft_hinting) { + switch (xft_hintstyle) { + case FC_HINT_NONE: + hint_style = CAIRO_HINT_STYLE_NONE; + break; + case FC_HINT_SLIGHT: + hint_style = CAIRO_HINT_STYLE_SLIGHT; + break; + case FC_HINT_MEDIUM: + hint_style = CAIRO_HINT_STYLE_MEDIUM; + break; + case FC_HINT_FULL: + hint_style = CAIRO_HINT_STYLE_FULL; + break; + default: + hint_style = CAIRO_HINT_STYLE_DEFAULT; + } + } else { + hint_style = CAIRO_HINT_STYLE_NONE; + } + + switch (xft_rgba) { + case FC_RGBA_RGB: + subpixel_order = CAIRO_SUBPIXEL_ORDER_RGB; + break; + case FC_RGBA_BGR: + subpixel_order = CAIRO_SUBPIXEL_ORDER_BGR; + break; + case FC_RGBA_VRGB: + subpixel_order = CAIRO_SUBPIXEL_ORDER_VRGB; + break; + case FC_RGBA_VBGR: + subpixel_order = CAIRO_SUBPIXEL_ORDER_VBGR; + break; + case FC_RGBA_UNKNOWN: + case FC_RGBA_NONE: + default: + subpixel_order = CAIRO_SUBPIXEL_ORDER_DEFAULT; + } + + switch (xft_lcdfilter) { + case FC_LCD_NONE: + lcd_filter = CAIRO_LCD_FILTER_NONE; + break; + case FC_LCD_DEFAULT: + lcd_filter = CAIRO_LCD_FILTER_FIR5; + break; + case FC_LCD_LIGHT: + lcd_filter = CAIRO_LCD_FILTER_FIR3; + break; + case FC_LCD_LEGACY: + lcd_filter = CAIRO_LCD_FILTER_INTRA_PIXEL; + break; + default: + lcd_filter = CAIRO_LCD_FILTER_DEFAULT; + break; + } + + if (xft_antialias) { + if (subpixel_order == CAIRO_SUBPIXEL_ORDER_DEFAULT) + antialias = CAIRO_ANTIALIAS_GRAY; + else + antialias = CAIRO_ANTIALIAS_SUBPIXEL; + } else { + antialias = CAIRO_ANTIALIAS_NONE; + } + + cairo_font_options_set_hint_style (&info->font_options, hint_style); + cairo_font_options_set_antialias (&info->font_options, antialias); + cairo_font_options_set_subpixel_order (&info->font_options, subpixel_order); + _cairo_font_options_set_lcd_filter (&info->font_options, lcd_filter); + cairo_font_options_set_hint_metrics (&info->font_options, CAIRO_HINT_METRICS_ON); +} + +void +_cairo_xlib_screen_destroy (cairo_xlib_display_t *display, + cairo_xlib_screen_t *info) +{ + Display *dpy; + int i; + + dpy = display->display; + + while (! cairo_list_is_empty (&info->surfaces)) { + cairo_xlib_surface_t *surface; + + surface = cairo_list_first_entry (&info->surfaces, + cairo_xlib_surface_t, + link); + cairo_surface_finish (&surface->base); + } + + for (i = 0; i < ARRAY_LENGTH (info->gc); i++) { + if (info->gc_depths[i] != 0) { + XFreeGC (dpy, info->gc[i]); + info->gc_depths[i] = 0; + } + } + + while (! cairo_list_is_empty (&info->visuals)) { + _cairo_xlib_visual_info_destroy (cairo_list_first_entry (&info->visuals, + cairo_xlib_visual_info_t, + link)); + } + + cairo_list_del (&info->link); + + free (info); +} + +cairo_status_t +_cairo_xlib_screen_get (Display *dpy, + Screen *screen, + cairo_xlib_screen_t **out) +{ + cairo_xlib_display_t *display; + cairo_device_t *device; + cairo_xlib_screen_t *info; + cairo_status_t status; + + device = _cairo_xlib_device_create (dpy); + status = device->status; + if (unlikely (status)) + goto CLEANUP_DEVICE; + + status = _cairo_xlib_display_acquire (device, &display); + if (unlikely (status)) + goto CLEANUP_DEVICE; + + info = _cairo_xlib_display_get_screen (display, screen); + if (info != NULL) { + *out = info; + goto CLEANUP_DISPLAY; + } + + info = _cairo_calloc (sizeof (cairo_xlib_screen_t)); + if (unlikely (info == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CLEANUP_DISPLAY; + } + + info->device = device; + info->screen = screen; + info->has_font_options = FALSE; + memset (info->gc_depths, 0, sizeof (info->gc_depths)); + memset (info->gc, 0, sizeof (info->gc)); + + cairo_list_init (&info->surfaces); + cairo_list_init (&info->visuals); + cairo_list_add (&info->link, &display->screens); + + *out = info; + + CLEANUP_DISPLAY: + cairo_device_release (&display->base); + + CLEANUP_DEVICE: + cairo_device_destroy (device); + return status; +} + +GC +_cairo_xlib_screen_get_gc (cairo_xlib_display_t *display, + cairo_xlib_screen_t *info, + int depth, + Drawable drawable) +{ + GC gc = NULL; + int i; + + for (i = 0; i < ARRAY_LENGTH (info->gc); i++) { + if (info->gc_depths[i] == depth) { + info->gc_depths[i] = 0; + gc = info->gc[i]; + break; + } + } + + if (gc == NULL) { + XGCValues gcv; + + gcv.graphics_exposures = False; + gcv.fill_style = FillTiled; + gc = XCreateGC (display->display, + drawable, + GCGraphicsExposures | GCFillStyle, &gcv); + } + + return gc; +} + +void +_cairo_xlib_screen_put_gc (cairo_xlib_display_t *display, + cairo_xlib_screen_t *info, + int depth, + GC gc) +{ + int i; + + for (i = 0; i < ARRAY_LENGTH (info->gc); i++) { + if (info->gc_depths[i] == 0) + break; + } + + if (i == ARRAY_LENGTH (info->gc)) { + /* perform random substitution to ensure fair caching over depths */ + i = rand () % ARRAY_LENGTH (info->gc); + XFreeGC(display->display, info->gc[i]); + } + + info->gc[i] = gc; + info->gc_depths[i] = depth; +} + +cairo_status_t +_cairo_xlib_screen_get_visual_info (cairo_xlib_display_t *display, + cairo_xlib_screen_t *info, + Visual *v, + cairo_xlib_visual_info_t **out) +{ + cairo_xlib_visual_info_t *visual; + cairo_status_t status; + + cairo_list_foreach_entry (visual, + cairo_xlib_visual_info_t, + &info->visuals, + link) + { + if (visual->visualid == v->visualid) { + *out = visual; + return CAIRO_STATUS_SUCCESS; + } + } + + status = _cairo_xlib_visual_info_create (display->display, + XScreenNumberOfScreen (info->screen), + v->visualid, + &visual); + if (unlikely (status)) + return status; + + cairo_list_add (&visual->link, &info->visuals); + *out = visual; + return CAIRO_STATUS_SUCCESS; +} + +cairo_font_options_t * +_cairo_xlib_screen_get_font_options (cairo_xlib_screen_t *info) +{ + if (! info->has_font_options) { + _cairo_font_options_init_default (&info->font_options); + _cairo_font_options_set_round_glyph_positions (&info->font_options, CAIRO_ROUND_GLYPH_POS_ON); + + if (info->screen != NULL) { + cairo_xlib_display_t *display; + + if (! _cairo_xlib_display_acquire (info->device, &display)) { + _cairo_xlib_init_screen_font_options (display->display, + info); + cairo_device_release (&display->base); + } + } + + info->has_font_options = TRUE; + } + + return &info->font_options; +} + +#endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */ diff --git a/local/recipes/libs/cairo/source/src/cairo-xlib-source.c b/local/recipes/libs/cairo/source/src/cairo-xlib-source.c new file mode 100644 index 0000000000..69416d7d89 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-xlib-source.c @@ -0,0 +1,1171 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Behdad Esfahbod + * Chris Wilson + * Karl Tomlinson , Mozilla Corporation + */ +#include "cairoint.h" + +#if !CAIRO_HAS_XLIB_XCB_FUNCTIONS + +#include "cairo-xlib-private.h" +#include "cairo-xlib-surface-private.h" + +#include "cairo-error-private.h" +#include "cairo-image-surface-inline.h" +#include "cairo-paginated-private.h" +#include "cairo-pattern-inline.h" +#include "cairo-recording-surface-private.h" +#include "cairo-surface-backend-private.h" +#include "cairo-surface-offset-private.h" +#include "cairo-surface-observer-private.h" +#include "cairo-surface-snapshot-inline.h" +#include "cairo-surface-subsurface-inline.h" + +#define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */ + +static cairo_xlib_surface_t * +unwrap_source (const cairo_surface_pattern_t *pattern) +{ + cairo_rectangle_int_t limits; + return (cairo_xlib_surface_t *)_cairo_pattern_get_source (pattern, &limits); +} + +static cairo_status_t +_cairo_xlib_source_finish (void *abstract_surface) +{ + cairo_xlib_source_t *source = abstract_surface; + + XRenderFreePicture (source->dpy, source->picture); + if (source->pixmap) + XFreePixmap (source->dpy, source->pixmap); + return CAIRO_STATUS_SUCCESS; +} + +static const cairo_surface_backend_t cairo_xlib_source_backend = { + CAIRO_SURFACE_TYPE_XLIB, + _cairo_xlib_source_finish, + NULL, /* read-only wrapper */ +}; + +static cairo_status_t +_cairo_xlib_proxy_finish (void *abstract_surface) +{ + cairo_xlib_proxy_t *proxy = abstract_surface; + + _cairo_xlib_shm_surface_mark_active (proxy->owner); + XRenderFreePicture (proxy->source.dpy, proxy->source.picture); + if (proxy->source.pixmap) + XFreePixmap (proxy->source.dpy, proxy->source.pixmap); + cairo_surface_destroy (proxy->owner); + return CAIRO_STATUS_SUCCESS; +} + +static const cairo_surface_backend_t cairo_xlib_proxy_backend = { + CAIRO_SURFACE_TYPE_XLIB, + _cairo_xlib_proxy_finish, + NULL, /* read-only wrapper */ +}; + +static cairo_surface_t * +source (cairo_xlib_surface_t *dst, Picture picture, Pixmap pixmap) +{ + cairo_xlib_source_t *source; + + if (picture == None) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + source = _cairo_calloc (sizeof (*source)); + if (unlikely (source == NULL)) { + XRenderFreePicture (dst->display->display, picture); + if (pixmap) + XFreePixmap (dst->display->display, pixmap); + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + } + + _cairo_surface_init (&source->base, + &cairo_xlib_source_backend, + NULL, /* device */ + CAIRO_CONTENT_COLOR_ALPHA, + FALSE); /* is_vector */ + + /* The source exists only within an operation */ + source->picture = picture; + source->pixmap = pixmap; + source->dpy = dst->display->display; + + return &source->base; +} + +static uint32_t +hars_petruska_f54_1_random (void) +{ +#define rol(x,k) ((x << k) | (x >> (32-k))) + static uint32_t x; + return x = (x ^ rol (x, 5) ^ rol (x, 24)) + 0x37798849; +#undef rol +} + +static const XTransform identity = { + { + { 1 << 16, 0x00000, 0x00000 }, + { 0x00000, 1 << 16, 0x00000 }, + { 0x00000, 0x00000, 1 << 16 }, + } +}; + +static cairo_bool_t +picture_set_matrix (cairo_xlib_display_t *display, + Picture picture, + const cairo_matrix_t *matrix, + cairo_filter_t filter, + double xc, + double yc, + int *x_offset, + int *y_offset) +{ + XTransform xtransform; + pixman_transform_t *pixman_transform; + cairo_int_status_t status; + + /* Casting between pixman_transform_t and XTransform is safe because + * they happen to be the exact same type. + */ + pixman_transform = (pixman_transform_t *) &xtransform; + status = _cairo_matrix_to_pixman_matrix_offset (matrix, filter, xc, yc, + pixman_transform, + x_offset, y_offset); + if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) + return TRUE; + if (unlikely (status != CAIRO_INT_STATUS_SUCCESS)) + return FALSE; + + if (memcmp (&xtransform, &identity, sizeof (XTransform)) == 0) + return TRUE; + + /* a late check in case we perturb the matrix too far */ + if (! CAIRO_RENDER_HAS_PICTURE_TRANSFORM (display)) + return FALSE; + + XRenderSetPictureTransform (display->display, picture, &xtransform); + return TRUE; +} + +static cairo_status_t +picture_set_filter (Display *dpy, + Picture picture, + cairo_filter_t filter) +{ + const char *render_filter; + + switch (filter) { + case CAIRO_FILTER_FAST: + render_filter = FilterFast; + break; + case CAIRO_FILTER_GOOD: + render_filter = FilterGood; + break; + case CAIRO_FILTER_BEST: + render_filter = FilterBest; + break; + case CAIRO_FILTER_NEAREST: + render_filter = FilterNearest; + break; + case CAIRO_FILTER_BILINEAR: + render_filter = FilterBilinear; + break; + case CAIRO_FILTER_GAUSSIAN: + /* XXX: The GAUSSIAN value has no implementation in cairo + * whatsoever, so it was really a mistake to have it in the + * API. We could fix this by officially deprecating it, or + * else inventing semantics and providing an actual + * implementation for it. */ + default: + render_filter = FilterBest; + break; + } + + XRenderSetPictureFilter (dpy, picture, (char *) render_filter, NULL, 0); + return CAIRO_STATUS_SUCCESS; +} + +static int +extend_to_repeat (cairo_extend_t extend) +{ + switch (extend) { + default: + ASSERT_NOT_REACHED; + case CAIRO_EXTEND_NONE: + return RepeatNone; + case CAIRO_EXTEND_REPEAT: + return RepeatNormal; + case CAIRO_EXTEND_REFLECT: + return RepeatReflect; + case CAIRO_EXTEND_PAD: + return RepeatPad; + } +} + +static cairo_bool_t +picture_set_properties (cairo_xlib_display_t *display, + Picture picture, + const cairo_pattern_t *pattern, + const cairo_matrix_t *matrix, + const cairo_rectangle_int_t *extents, + int *x_off, int *y_off) +{ + XRenderPictureAttributes pa; + int mask = 0; + + if (! picture_set_matrix (display, picture, matrix, pattern->filter, + extents->x + extents->width / 2, + extents->y + extents->height / 2, + x_off, y_off)) + return FALSE; + + picture_set_filter (display->display, picture, pattern->filter); + + if (pattern->has_component_alpha) { + pa.component_alpha = 1; + mask |= CPComponentAlpha; + } + + if (pattern->extend != CAIRO_EXTEND_NONE) { + pa.repeat = extend_to_repeat (pattern->extend); + mask |= CPRepeat; + } + + if (mask) + XRenderChangePicture (display->display, picture, mask, &pa); + + return TRUE; +} + +static cairo_surface_t * +render_pattern (cairo_xlib_surface_t *dst, + const cairo_pattern_t *pattern, + cairo_bool_t is_mask, + const cairo_rectangle_int_t *extents, + int *src_x, int *src_y) +{ + Display *dpy = dst->display->display; + cairo_xlib_surface_t *src; + cairo_image_surface_t *image; + cairo_status_t status; + cairo_rectangle_int_t map_extents; + + src = (cairo_xlib_surface_t *) + _cairo_surface_create_scratch (&dst->base, + is_mask ? CAIRO_CONTENT_ALPHA : CAIRO_CONTENT_COLOR_ALPHA, + extents->width, + extents->height, + NULL); + if (src->base.type != CAIRO_SURFACE_TYPE_XLIB) { + cairo_surface_destroy (&src->base); + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + } + + map_extents = *extents; + map_extents.x = map_extents.y = 0; + + image = _cairo_surface_map_to_image (&src->base, &map_extents); + status = _cairo_surface_offset_paint (&image->base, extents->x, extents->y, + CAIRO_OPERATOR_SOURCE, pattern, + NULL); + status = _cairo_surface_unmap_image (&src->base, image); + if (unlikely (status)) { + cairo_surface_destroy (&src->base); + return _cairo_surface_create_in_error (status); + } + + status = _cairo_xlib_surface_put_shm (src); + if (unlikely (status)) { + cairo_surface_destroy (&src->base); + return _cairo_surface_create_in_error (status); + } + + src->picture = XRenderCreatePicture (dpy, + src->drawable, src->xrender_format, + 0, NULL); + + *src_x = -extents->x; + *src_y = -extents->y; + return &src->base; +} + +static cairo_surface_t * +gradient_source (cairo_xlib_surface_t *dst, + const cairo_gradient_pattern_t *gradient, + cairo_bool_t is_mask, + const cairo_rectangle_int_t *extents, + int *src_x, int *src_y) +{ + cairo_xlib_display_t *display = dst->display; + cairo_matrix_t matrix = gradient->base.matrix; + char buf[CAIRO_STACK_BUFFER_SIZE]; + cairo_circle_double_t extremes[2]; + XFixed *stops; + XRenderColor *colors; + Picture picture; + unsigned int i, n_stops; + + /* The RENDER specification says that the inner circle has + * to be completely contained inside the outer one. */ + if (gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL && + ! _cairo_radial_pattern_focus_is_inside ((cairo_radial_pattern_t *) gradient)) + return render_pattern (dst, &gradient->base, is_mask, extents, src_x, src_y); + + assert (gradient->n_stops > 0); + n_stops = MAX (gradient->n_stops, 2); + + if (n_stops < sizeof (buf) / (sizeof (XFixed) + sizeof (XRenderColor))) + { + stops = (XFixed *) buf; + } + else + { + stops = + _cairo_malloc_ab (n_stops, + sizeof (XFixed) + sizeof (XRenderColor)); + if (unlikely (stops == NULL)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + } + + colors = (XRenderColor *) (stops + n_stops); + for (i = 0; i < gradient->n_stops; i++) { + stops[i] = + _cairo_fixed_16_16_from_double (gradient->stops[i].offset); + + colors[i].red = gradient->stops[i].color.red_short; + colors[i].green = gradient->stops[i].color.green_short; + colors[i].blue = gradient->stops[i].color.blue_short; + colors[i].alpha = gradient->stops[i].color.alpha_short; + } + + /* RENDER does not support gradients with less than 2 + * stops. If a gradient has only a single stop, duplicate + * it to make RENDER happy. */ + if (gradient->n_stops == 1) { + stops[1] = + _cairo_fixed_16_16_from_double (gradient->stops[0].offset); + + colors[1].red = gradient->stops[0].color.red_short; + colors[1].green = gradient->stops[0].color.green_short; + colors[1].blue = gradient->stops[0].color.blue_short; + colors[1].alpha = gradient->stops[0].color.alpha_short; + } + +#if 0 + /* For some weird reason the X server is sometimes getting + * CreateGradient requests with bad length. So far I've only seen + * XRenderCreateLinearGradient request with 4 stops sometime end up + * with length field matching 0 stops at the server side. I've + * looked at the libXrender code and I can't see anything that + * could cause this behavior. However, for some reason having a + * XSync call here seems to avoid the issue so I'll keep it here + * until it's solved. + */ + XSync (display->display, False); +#endif + + _cairo_gradient_pattern_fit_to_range (gradient, PIXMAN_MAX_INT >> 1, &matrix, extremes); + + if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) { + XLinearGradient grad; + + grad.p1.x = _cairo_fixed_16_16_from_double (extremes[0].center.x); + grad.p1.y = _cairo_fixed_16_16_from_double (extremes[0].center.y); + grad.p2.x = _cairo_fixed_16_16_from_double (extremes[1].center.x); + grad.p2.y = _cairo_fixed_16_16_from_double (extremes[1].center.y); + + picture = XRenderCreateLinearGradient (display->display, &grad, + stops, colors, + n_stops); + } else { + XRadialGradient grad; + + grad.inner.x = _cairo_fixed_16_16_from_double (extremes[0].center.x); + grad.inner.y = _cairo_fixed_16_16_from_double (extremes[0].center.y); + grad.inner.radius = _cairo_fixed_16_16_from_double (extremes[0].radius); + grad.outer.x = _cairo_fixed_16_16_from_double (extremes[1].center.x); + grad.outer.y = _cairo_fixed_16_16_from_double (extremes[1].center.y); + grad.outer.radius = _cairo_fixed_16_16_from_double (extremes[1].radius); + + picture = XRenderCreateRadialGradient (display->display, &grad, + stops, colors, + n_stops); + } + + if (stops != (XFixed *) buf) + free (stops); + + *src_x = *src_y = 0; + if (! picture_set_properties (display, picture, + &gradient->base, &gradient->base.matrix, + extents, + src_x, src_y)) { + XRenderFreePicture (display->display, picture); + return render_pattern (dst, &gradient->base, is_mask, extents, src_x, src_y); + } + + return source (dst, picture, None); +} + +static cairo_surface_t * +color_source (cairo_xlib_surface_t *dst, const cairo_color_t *color) +{ + Display *dpy = dst->display->display; + XRenderColor xcolor; + Picture picture; + Pixmap pixmap = None; + + xcolor.red = color->red_short; + xcolor.green = color->green_short; + xcolor.blue = color->blue_short; + xcolor.alpha = color->alpha_short; + + if (CAIRO_RENDER_HAS_GRADIENTS(dst->display)) { + picture = XRenderCreateSolidFill (dpy, &xcolor); + } else { + XRenderPictureAttributes pa; + int mask = 0; + + pa.repeat = RepeatNormal; + mask |= CPRepeat; + + pixmap = XCreatePixmap (dpy, dst->drawable, 1, 1, 32); + picture = XRenderCreatePicture (dpy, pixmap, + _cairo_xlib_display_get_xrender_format (dst->display, CAIRO_FORMAT_ARGB32), + mask, &pa); + + if (CAIRO_RENDER_HAS_FILL_RECTANGLES(dst->display)) { + XRectangle r = { 0, 0, 1, 1}; + XRenderFillRectangles (dpy, PictOpSrc, picture, &xcolor, &r, 1); + } else { + XGCValues gcv; + GC gc; + + gc = _cairo_xlib_screen_get_gc (dst->display, dst->screen, + 32, pixmap); + if (unlikely (gc == NULL)) { + XFreePixmap (dpy, pixmap); + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + } + + gcv.foreground = 0; + gcv.foreground |= (uint32_t)color->alpha_short >> 8 << 24; + gcv.foreground |= color->red_short >> 8 << 16; + gcv.foreground |= color->green_short >> 8 << 8; + gcv.foreground |= color->blue_short >> 8 << 0; + gcv.fill_style = FillSolid; + + XChangeGC (dpy, gc, GCFillStyle | GCForeground, &gcv); + XFillRectangle (dpy, pixmap, gc, 0, 0, 1, 1); + + _cairo_xlib_screen_put_gc (dst->display, dst->screen, 32, gc); + } + } + + return source (dst, picture, pixmap); +} + +static cairo_surface_t * +alpha_source (cairo_xlib_surface_t *dst, uint8_t alpha) +{ + cairo_xlib_display_t *display = dst->display; + + if (display->alpha[alpha] == NULL) { + cairo_color_t color; + + color.red_short = color.green_short = color.blue_short = 0; + color.alpha_short = alpha << 8 | alpha; + + display->alpha[alpha] = color_source (dst, &color); + } + + return cairo_surface_reference (display->alpha[alpha]); +} + +static cairo_surface_t * +white_source (cairo_xlib_surface_t *dst) +{ + cairo_xlib_display_t *display = dst->display; + + if (display->white == NULL) + display->white = color_source (dst, CAIRO_COLOR_WHITE); + + return cairo_surface_reference (display->white); +} + +static cairo_surface_t * +opaque_source (cairo_xlib_surface_t *dst, const cairo_color_t *color) +{ + cairo_xlib_display_t *display = dst->display; + uint32_t pixel = + 0xff000000 | + color->red_short >> 8 << 16 | + color->green_short >> 8 << 8 | + color->blue_short >> 8 << 0; + int i; + + if (display->last_solid_cache[0].color == pixel) + return cairo_surface_reference (display->solid[display->last_solid_cache[0].index]); + + for (i = 0; i < 16; i++) { + if (display->solid_cache[i] == pixel) + goto done; + } + + i = hars_petruska_f54_1_random () % 16; + cairo_surface_destroy (display->solid[i]); + + display->solid[i] = color_source (dst, color); + display->solid_cache[i] = pixel; + +done: + display->last_solid_cache[0].color = pixel; + display->last_solid_cache[0].index = i; + return cairo_surface_reference (display->solid[i]); +} + +static cairo_surface_t * +transparent_source (cairo_xlib_surface_t *dst, const cairo_color_t *color) +{ + cairo_xlib_display_t *display = dst->display; + uint32_t pixel = + (uint32_t)color->alpha_short >> 8 << 24 | + color->red_short >> 8 << 16 | + color->green_short >> 8 << 8 | + color->blue_short >> 8 << 0; + int i; + + if (display->last_solid_cache[1].color == pixel) { + assert (display->solid[display->last_solid_cache[1].index]); + return cairo_surface_reference (display->solid[display->last_solid_cache[1].index]); + } + + for (i = 16; i < 32; i++) { + if (display->solid_cache[i] == pixel) + goto done; + } + + i = 16 + (hars_petruska_f54_1_random () % 16); + cairo_surface_destroy (display->solid[i]); + + display->solid[i] = color_source (dst, color); + display->solid_cache[i] = pixel; + +done: + display->last_solid_cache[1].color = pixel; + display->last_solid_cache[1].index = i; + assert (display->solid[i]); + return cairo_surface_reference (display->solid[i]); +} + +static cairo_surface_t * +solid_source (cairo_xlib_surface_t *dst, + const cairo_color_t *color) +{ + if ((color->red_short | color->green_short | color->blue_short) <= 0xff) + return alpha_source (dst, color->alpha_short >> 8); + + if (CAIRO_ALPHA_SHORT_IS_OPAQUE (color->alpha_short)) { + if (color->red_short >= 0xff00 && color->green_short >= 0xff00 && color->blue_short >= 0xff00) + return white_source (dst); + + return opaque_source (dst, color); + } else + return transparent_source (dst, color); +} + +static cairo_xlib_source_t *init_source (cairo_xlib_surface_t *dst, + cairo_xlib_surface_t *src) +{ + Display *dpy = dst->display->display; + cairo_xlib_source_t *source = &src->embedded_source; + + /* As these are frequent and meant to be fast, we track pictures for + * native surface and minimise update requests. + */ + if (source->picture == None) { + XRenderPictureAttributes pa; + + _cairo_surface_init (&source->base, + &cairo_xlib_source_backend, + NULL, /* device */ + CAIRO_CONTENT_COLOR_ALPHA, + FALSE); /* is_vector */ + + pa.subwindow_mode = IncludeInferiors; + source->picture = XRenderCreatePicture (dpy, + src->drawable, + src->xrender_format, + CPSubwindowMode, &pa); + + source->has_component_alpha = 0; + source->has_matrix = 0; + source->filter = CAIRO_FILTER_NEAREST; + source->extend = CAIRO_EXTEND_NONE; + } + + return (cairo_xlib_source_t *) cairo_surface_reference (&source->base); +} + +static cairo_surface_t * +embedded_source (cairo_xlib_surface_t *dst, + const cairo_surface_pattern_t *pattern, + const cairo_rectangle_int_t *extents, + int *src_x, int *src_y, + cairo_xlib_source_t *source) +{ + Display *dpy = dst->display->display; + cairo_int_status_t status; + XTransform xtransform; + XRenderPictureAttributes pa; + unsigned mask = 0; + + status = _cairo_matrix_to_pixman_matrix_offset (&pattern->base.matrix, + pattern->base.filter, + extents->x + extents->width / 2, + extents->y + extents->height / 2, + (pixman_transform_t *)&xtransform, + src_x, src_y); + + if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) { + if (source->has_matrix) { + source->has_matrix = 0; + memcpy (&xtransform, &identity, sizeof (identity)); + status = CAIRO_INT_STATUS_SUCCESS; + } + } else + source->has_matrix = 1; + if (status == CAIRO_INT_STATUS_SUCCESS) + XRenderSetPictureTransform (dpy, source->picture, &xtransform); + + if (source->filter != pattern->base.filter) { + picture_set_filter (dpy, source->picture, pattern->base.filter); + source->filter = pattern->base.filter; + } + + if (source->has_component_alpha != pattern->base.has_component_alpha) { + pa.component_alpha = pattern->base.has_component_alpha; + mask |= CPComponentAlpha; + source->has_component_alpha = pattern->base.has_component_alpha; + } + + if (source->extend != pattern->base.extend) { + pa.repeat = extend_to_repeat (pattern->base.extend); + mask |= CPRepeat; + source->extend = pattern->base.extend; + } + + if (mask) + XRenderChangePicture (dpy, source->picture, mask, &pa); + + return &source->base; +} + +static cairo_surface_t * +subsurface_source (cairo_xlib_surface_t *dst, + const cairo_surface_pattern_t *pattern, + cairo_bool_t is_mask, + const cairo_rectangle_int_t *extents, + const cairo_rectangle_int_t *sample, + int *src_x, int *src_y) +{ + cairo_surface_subsurface_t *sub; + cairo_xlib_surface_t *src; + cairo_xlib_source_t *source; + Display *dpy = dst->display->display; + cairo_int_status_t status; + cairo_surface_pattern_t local_pattern; + XTransform xtransform; + XRenderPictureAttributes pa; + unsigned mask = 0; + + sub = (cairo_surface_subsurface_t *) pattern->surface; + + if (sample->x >= 0 && sample->y >= 0 && + sample->x + sample->width <= sub->extents.width && + sample->y + sample->height <= sub->extents.height) + { + src = (cairo_xlib_surface_t *) sub->target; + status = _cairo_surface_flush (&src->base, 0); + if (unlikely (status)) + return _cairo_surface_create_in_error (status); + + if (pattern->base.filter == CAIRO_FILTER_NEAREST && + _cairo_matrix_is_translation (&pattern->base.matrix)) + { + *src_x += pattern->base.matrix.x0 + sub->extents.x; + *src_y += pattern->base.matrix.y0 + sub->extents.y; + + _cairo_xlib_surface_ensure_picture (src); + return cairo_surface_reference (&src->base); + } + else + { + cairo_surface_pattern_t local_pattern = *pattern; + local_pattern.base.matrix.x0 += sub->extents.x; + local_pattern.base.matrix.y0 += sub->extents.y; + local_pattern.base.extend = CAIRO_EXTEND_NONE; + return embedded_source (dst, &local_pattern, extents, + src_x, src_y, init_source (dst, src)); + } + } + + if (sub->snapshot && sub->snapshot->type == CAIRO_SURFACE_TYPE_XLIB) { + src = (cairo_xlib_surface_t *) cairo_surface_reference (sub->snapshot); + source = &src->embedded_source; + } else { + src = (cairo_xlib_surface_t *) + _cairo_surface_create_scratch (&dst->base, + sub->base.content, + sub->extents.width, + sub->extents.height, + NULL); + if (src->base.type != CAIRO_SURFACE_TYPE_XLIB) { + cairo_surface_destroy (&src->base); + return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY); + } + + _cairo_pattern_init_for_surface (&local_pattern, sub->target); + cairo_matrix_init_translate (&local_pattern.base.matrix, + sub->extents.x, sub->extents.y); + local_pattern.base.filter = CAIRO_FILTER_NEAREST; + status = _cairo_surface_paint (&src->base, + CAIRO_OPERATOR_SOURCE, + &local_pattern.base, + NULL); + _cairo_pattern_fini (&local_pattern.base); + + if (unlikely (status)) { + cairo_surface_destroy (&src->base); + return _cairo_surface_create_in_error (status); + } + + _cairo_xlib_surface_ensure_picture (src); + _cairo_surface_subsurface_set_snapshot (&sub->base, &src->base); + + source = &src->embedded_source; + source->has_component_alpha = 0; + source->has_matrix = 0; + source->filter = CAIRO_FILTER_NEAREST; + source->extend = CAIRO_EXTEND_NONE; + } + + status = _cairo_matrix_to_pixman_matrix_offset (&pattern->base.matrix, + pattern->base.filter, + extents->x + extents->width / 2, + extents->y + extents->height / 2, + (pixman_transform_t *)&xtransform, + src_x, src_y); + if (status == CAIRO_INT_STATUS_NOTHING_TO_DO) { + if (source->has_matrix) { + source->has_matrix = 0; + memcpy (&xtransform, &identity, sizeof (identity)); + status = CAIRO_INT_STATUS_SUCCESS; + } + } else + source->has_matrix = 1; + if (status == CAIRO_INT_STATUS_SUCCESS) + XRenderSetPictureTransform (dpy, src->picture, &xtransform); + + if (source->filter != pattern->base.filter) { + picture_set_filter (dpy, src->picture, pattern->base.filter); + source->filter = pattern->base.filter; + } + + if (source->has_component_alpha != pattern->base.has_component_alpha) { + pa.component_alpha = pattern->base.has_component_alpha; + mask |= CPComponentAlpha; + source->has_component_alpha = pattern->base.has_component_alpha; + } + + if (source->extend != pattern->base.extend) { + pa.repeat = extend_to_repeat (pattern->base.extend); + mask |= CPRepeat; + source->extend = pattern->base.extend; + } + + if (mask) + XRenderChangePicture (dpy, src->picture, mask, &pa); + + return &src->base; +} + +static cairo_surface_t * +native_source (cairo_xlib_surface_t *dst, + const cairo_surface_pattern_t *pattern, + cairo_bool_t is_mask, + const cairo_rectangle_int_t *extents, + const cairo_rectangle_int_t *sample, + int *src_x, int *src_y) +{ + cairo_xlib_surface_t *src; + cairo_int_status_t status; + + if (_cairo_surface_is_subsurface (pattern->surface)) + return subsurface_source (dst, pattern, is_mask, + extents, sample, + src_x, src_y); + + src = unwrap_source (pattern); + status = _cairo_surface_flush (&src->base, 0); + if (unlikely (status)) + return _cairo_surface_create_in_error (status); + + if (pattern->base.filter == CAIRO_FILTER_NEAREST && + sample->x >= 0 && sample->y >= 0 && + sample->x + sample->width <= src->width && + sample->y + sample->height <= src->height && + _cairo_matrix_is_translation (&pattern->base.matrix)) + { + *src_x += pattern->base.matrix.x0; + *src_y += pattern->base.matrix.y0; + _cairo_xlib_surface_ensure_picture (src); + return cairo_surface_reference (&src->base); + } + + return embedded_source (dst, pattern, extents, src_x, src_y, + init_source (dst, src)); +} + +static cairo_surface_t * +recording_pattern_get_surface (const cairo_pattern_t *pattern) +{ + cairo_surface_t *surface; + + surface = ((const cairo_surface_pattern_t *) pattern)->surface; + + if (_cairo_surface_is_paginated (surface)) + return cairo_surface_reference (_cairo_paginated_surface_get_recording (surface)); + + if (_cairo_surface_is_snapshot (surface)) + return _cairo_surface_snapshot_get_target (surface); + + return cairo_surface_reference (surface); +} + +static cairo_surface_t * +record_source (cairo_xlib_surface_t *dst, + const cairo_surface_pattern_t *pattern, + cairo_bool_t is_mask, + const cairo_rectangle_int_t *extents, + const cairo_rectangle_int_t *sample, + int *src_x, int *src_y) +{ + cairo_xlib_surface_t *src; + cairo_surface_t *recording; + cairo_matrix_t matrix, m; + cairo_status_t status; + cairo_rectangle_int_t upload, limit; + + upload = *sample; + if (_cairo_surface_get_extents (pattern->surface, &limit) && + ! _cairo_rectangle_intersect (&upload, &limit)) + { + if (pattern->base.extend == CAIRO_EXTEND_NONE) + return alpha_source (dst, 0); + + upload = limit; + } + + src = (cairo_xlib_surface_t *) + _cairo_surface_create_scratch (&dst->base, + pattern->surface->content, + upload.width, + upload.height, + NULL); + if (src->base.type != CAIRO_SURFACE_TYPE_XLIB) { + cairo_surface_destroy (&src->base); + return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY); + } + + cairo_matrix_init_translate (&matrix, upload.x, upload.y); + recording = recording_pattern_get_surface (&pattern->base), + status = _cairo_recording_surface_replay_with_clip (recording, + &matrix, &src->base, + NULL); + cairo_surface_destroy (recording); + if (unlikely (status)) { + cairo_surface_destroy (&src->base); + return _cairo_surface_create_in_error (status); + } + + matrix = pattern->base.matrix; + if (upload.x | upload.y) { + cairo_matrix_init_translate (&m, -upload.x, -upload.y); + cairo_matrix_multiply (&matrix, &matrix, &m); + } + + _cairo_xlib_surface_ensure_picture (src); + if (! picture_set_properties (src->display, src->picture, + &pattern->base, &matrix, extents, + src_x, src_y)) + { + cairo_surface_destroy (&src->base); + return render_pattern (dst, &pattern->base, is_mask, + extents, src_x, src_y); + } + + return &src->base; +} + +static cairo_surface_t * +surface_source (cairo_xlib_surface_t *dst, + const cairo_surface_pattern_t *pattern, + cairo_bool_t is_mask, + const cairo_rectangle_int_t *extents, + const cairo_rectangle_int_t *sample, + int *src_x, int *src_y) +{ + cairo_surface_t *src; + cairo_xlib_surface_t *xsrc; + cairo_surface_pattern_t local_pattern; + cairo_status_t status; + cairo_rectangle_int_t upload, limit; + + src = pattern->surface; + if (src->type == CAIRO_SURFACE_TYPE_IMAGE && + src->device == dst->base.device && + _cairo_xlib_shm_surface_get_pixmap (src)) { + cairo_xlib_proxy_t *proxy; + + proxy = _cairo_calloc (sizeof(*proxy)); + if (unlikely (proxy == NULL)) + return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY); + + _cairo_surface_init (&proxy->source.base, + &cairo_xlib_proxy_backend, + dst->base.device, + src->content, + src->is_vector); + + proxy->source.dpy = dst->display->display; + proxy->source.picture = XRenderCreatePicture (proxy->source.dpy, + _cairo_xlib_shm_surface_get_pixmap (src), + _cairo_xlib_shm_surface_get_xrender_format (src), + 0, NULL); + proxy->source.pixmap = None; + + proxy->source.has_component_alpha = 0; + proxy->source.has_matrix = 0; + proxy->source.filter = CAIRO_FILTER_NEAREST; + proxy->source.extend = CAIRO_EXTEND_NONE; + proxy->owner = cairo_surface_reference (src); + + return embedded_source (dst, pattern, extents, src_x, src_y, + &proxy->source); + } + + upload = *sample; + if (_cairo_surface_get_extents (pattern->surface, &limit)) { + if (pattern->base.extend == CAIRO_EXTEND_NONE) { + if (! _cairo_rectangle_intersect (&upload, &limit)) + return alpha_source (dst, 0); + } else if (pattern->base.extend == CAIRO_EXTEND_PAD) { + if (! _cairo_rectangle_intersect (&upload, &limit)) + upload = limit; + } else { + if (upload.x < limit.x || + upload.x + upload.width > limit.x + limit.width || + upload.y < limit.y || + upload.y + upload.height > limit.y + limit.height) + { + upload = limit; + } + } + } + + xsrc = (cairo_xlib_surface_t *) + _cairo_surface_create_scratch (&dst->base, + src->content, + upload.width, + upload.height, + NULL); + if (xsrc->base.type != CAIRO_SURFACE_TYPE_XLIB) { + cairo_surface_destroy (src); + cairo_surface_destroy (&xsrc->base); + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + } + + if (_cairo_surface_is_image (src)) { + status = _cairo_xlib_surface_draw_image (xsrc, (cairo_image_surface_t *)src, + upload.x, upload.y, + upload.width, upload.height, + 0, 0); + } else { + cairo_image_surface_t *image; + cairo_rectangle_int_t map_extents = { 0,0, upload.width,upload.height }; + + image = _cairo_surface_map_to_image (&xsrc->base, &map_extents); + + _cairo_pattern_init_for_surface (&local_pattern, pattern->surface); + cairo_matrix_init_translate (&local_pattern.base.matrix, + upload.x, upload.y); + + status = _cairo_surface_paint (&image->base, + CAIRO_OPERATOR_SOURCE, + &local_pattern.base, + NULL); + _cairo_pattern_fini (&local_pattern.base); + + status = _cairo_surface_unmap_image (&xsrc->base, image); + if (unlikely (status)) { + cairo_surface_destroy (&xsrc->base); + return _cairo_surface_create_in_error (status); + } + + status = _cairo_xlib_surface_put_shm (xsrc); + if (unlikely (status)) { + cairo_surface_destroy (&xsrc->base); + return _cairo_surface_create_in_error (status); + } + } + + _cairo_pattern_init_static_copy (&local_pattern.base, &pattern->base); + if (upload.x | upload.y) { + cairo_matrix_t m; + cairo_matrix_init_translate (&m, -upload.x, -upload.y); + cairo_matrix_multiply (&local_pattern.base.matrix, + &local_pattern.base.matrix, + &m); + } + + *src_x = *src_y = 0; + _cairo_xlib_surface_ensure_picture (xsrc); + if (! picture_set_properties (xsrc->display, + xsrc->picture, + &local_pattern.base, + &local_pattern.base.matrix, + extents, + src_x, src_y)) + { + cairo_surface_destroy (&xsrc->base); + return render_pattern (dst, &pattern->base, + is_mask, extents, + src_x, src_y); + } + + return &xsrc->base; +} + +static cairo_bool_t +pattern_is_supported (cairo_xlib_display_t *display, + const cairo_pattern_t *pattern) +{ + if (pattern->type == CAIRO_PATTERN_TYPE_MESH) + return FALSE; + + if (display->buggy_pad_reflect) { + if (pattern->extend == CAIRO_EXTEND_REPEAT || pattern->extend == CAIRO_EXTEND_PAD) + return FALSE; + } + + if (display->buggy_gradients) { + if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR || pattern->type == CAIRO_PATTERN_TYPE_RADIAL) + return FALSE; + } + + switch (pattern->filter) { + case CAIRO_FILTER_FAST: + case CAIRO_FILTER_NEAREST: + return CAIRO_RENDER_HAS_PICTURE_TRANSFORM (display) || + _cairo_matrix_is_integer_translation (&pattern->matrix, NULL, NULL); + case CAIRO_FILTER_GOOD: + return CAIRO_RENDER_HAS_FILTER_GOOD (display); + case CAIRO_FILTER_BEST: + return CAIRO_RENDER_HAS_FILTER_BEST (display); + case CAIRO_FILTER_BILINEAR: + case CAIRO_FILTER_GAUSSIAN: + default: + return CAIRO_RENDER_HAS_FILTERS (display); + } +} + +cairo_surface_t * +_cairo_xlib_source_create_for_pattern (cairo_surface_t *_dst, + const cairo_pattern_t *pattern, + cairo_bool_t is_mask, + const cairo_rectangle_int_t *extents, + const cairo_rectangle_int_t *sample, + int *src_x, int *src_y) +{ + cairo_xlib_surface_t *dst = (cairo_xlib_surface_t *)_dst; + + *src_x = *src_y = 0; + + if (pattern == NULL || pattern->type == CAIRO_PATTERN_TYPE_SOLID) { + if (pattern == NULL) + pattern = &_cairo_pattern_white.base; + + return solid_source (dst, &((cairo_solid_pattern_t *)pattern)->color); + } + + if (pattern_is_supported (dst->display, pattern)) { + if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { + cairo_surface_pattern_t *spattern = (cairo_surface_pattern_t *)pattern; + if (spattern->surface->type == CAIRO_SURFACE_TYPE_XLIB && + _cairo_xlib_surface_same_screen (dst, + unwrap_source (spattern))) + return native_source (dst, spattern, is_mask, + extents, sample, + src_x, src_y); + + if (spattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) + return record_source (dst, spattern, is_mask, + extents, sample, + src_x, src_y); + + return surface_source (dst, spattern, is_mask, + extents, sample, + src_x, src_y); + } + + if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR || + pattern->type == CAIRO_PATTERN_TYPE_RADIAL) + { + cairo_gradient_pattern_t *gpattern = (cairo_gradient_pattern_t *)pattern; + return gradient_source (dst, gpattern, is_mask, extents, src_x, src_y); + } + } + + return render_pattern (dst, pattern, is_mask, extents, src_x, src_y); +} + +#endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */ diff --git a/local/recipes/libs/cairo/source/src/cairo-xlib-surface-private.h b/local/recipes/libs/cairo/source/src/cairo-xlib-surface-private.h new file mode 100644 index 0000000000..83d9b63cc4 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-xlib-surface-private.h @@ -0,0 +1,44 @@ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + */ + +#ifndef CAIRO_XLIB_SURFACE_PRIVATE_H +#define CAIRO_XLIB_SURFACE_PRIVATE_H + +#include "cairo-xlib-xrender-private.h" +#include "cairo-xlib.h" +#include "cairo-xlib-private.h" + +#include "cairo-surface-private.h" +#include "cairo-surface-backend-private.h" + + +#endif /* CAIRO_XLIB_SURFACE_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-xlib-surface-shm.c b/local/recipes/libs/cairo/source/src/cairo-xlib-surface-shm.c new file mode 100644 index 0000000000..85a036938a --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-xlib-surface-shm.c @@ -0,0 +1,1466 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Chris Wilson + */ + +#include "cairoint.h" + +#if !CAIRO_HAS_XLIB_XCB_FUNCTIONS + +#include "cairo-xlib-private.h" +#include "cairo-xlib-surface-private.h" + +#if !HAVE_X11_EXTENSIONS_XSHM_H || !(HAVE_X11_EXTENSIONS_SHMPROTO_H || HAVE_X11_EXTENSIONS_SHMSTR_H) +void _cairo_xlib_display_init_shm (cairo_xlib_display_t *display) +{ + display->shm = NULL; +} + +cairo_surface_t * +_cairo_xlib_surface_get_shm (cairo_xlib_surface_t *surface, + cairo_bool_t overwrite) +{ + return NULL; +} + +cairo_int_status_t +_cairo_xlib_surface_put_shm (cairo_xlib_surface_t *surface) +{ + assert (!surface->fallback); + return CAIRO_INT_STATUS_SUCCESS; +} + +cairo_surface_t * +_cairo_xlib_surface_create_shm (cairo_xlib_surface_t *other, + pixman_format_code_t format, + int width, int height) +{ + return NULL; +} + +cairo_surface_t * +_cairo_xlib_surface_create_shm__image (cairo_xlib_surface_t *surface, + pixman_format_code_t format, + int width, int height) +{ + return NULL; +} + +cairo_surface_t * +_cairo_xlib_surface_create_similar_shm (void *other, + cairo_format_t format, + int width, int height) +{ + return cairo_image_surface_create (format, width, height); +} + +void +_cairo_xlib_shm_surface_mark_active (cairo_surface_t *_shm) +{ + ASSERT_NOT_REACHED; +} + +void +_cairo_xlib_shm_surface_get_ximage (cairo_surface_t *surface, + XImage *ximage) +{ + ASSERT_NOT_REACHED; +} + +void * +_cairo_xlib_shm_surface_get_obdata (cairo_surface_t *surface) +{ + ASSERT_NOT_REACHED; + return NULL; +} + +Pixmap +_cairo_xlib_shm_surface_get_pixmap (cairo_surface_t *surface) +{ + ASSERT_NOT_REACHED; + return 0; +} + +XRenderPictFormat * +_cairo_xlib_shm_surface_get_xrender_format (cairo_surface_t *surface) +{ + ASSERT_NOT_REACHED; + return NULL; +} + +cairo_bool_t +_cairo_xlib_shm_surface_is_active (cairo_surface_t *surface) +{ + ASSERT_NOT_REACHED; + return FALSE; +} + +cairo_bool_t +_cairo_xlib_shm_surface_is_idle (cairo_surface_t *surface) +{ + ASSERT_NOT_REACHED; + return TRUE; +} + +void _cairo_xlib_display_fini_shm (cairo_xlib_display_t *display) {} + +#else + +#include "cairo-damage-private.h" +#include "cairo-default-context-private.h" +#include "cairo-image-surface-private.h" +#include "cairo-list-inline.h" +#include "cairo-mempool-private.h" + +#include +#include +#include +#if HAVE_X11_EXTENSIONS_SHMPROTO_H +#include +#elif HAVE_X11_EXTENSIONS_SHMSTR_H +#include +#endif +#include +#include + +#define MIN_PIXMAP_SIZE 4096 + +#define MIN_BITS 8 +#define MIN_SIZE (1<<(MIN_BITS-1)) + +typedef struct _cairo_xlib_shm cairo_xlib_shm_t; +typedef struct _cairo_xlib_shm_info cairo_xlib_shm_info_t; +typedef struct _cairo_xlib_shm_surface cairo_xlib_shm_surface_t; + +struct _cairo_xlib_shm { + cairo_mempool_t mem; + + XShmSegmentInfo shm; + unsigned long attached; + cairo_list_t link; +}; + +struct _cairo_xlib_shm_info { + unsigned long last_request; + void *mem; + size_t size; + cairo_xlib_shm_t *pool; +}; + +struct _cairo_xlib_shm_surface { + cairo_image_surface_t image; + + cairo_list_t link; + cairo_xlib_shm_info_t *info; + Pixmap pixmap; + unsigned long active; + int idle; +}; + +/* the parent is always given by index/2 */ +#define PQ_PARENT_INDEX(i) ((i) >> 1) +#define PQ_FIRST_ENTRY 1 + +/* left and right children are index * 2 and (index * 2) +1 respectively */ +#define PQ_LEFT_CHILD_INDEX(i) ((i) << 1) + +#define PQ_TOP(pq) ((pq)->elements[PQ_FIRST_ENTRY]) + +struct pqueue { + int size, max_size; + cairo_xlib_shm_info_t **elements; +}; + +struct _cairo_xlib_shm_display { + int has_pixmaps; + int opcode; + int event; + + Window window; + unsigned long last_request; + unsigned long last_event; + + cairo_list_t surfaces; + + cairo_list_t pool; + struct pqueue info; +}; + +static inline cairo_bool_t +seqno_passed (unsigned long a, unsigned long b) +{ + return (long)(b - a) >= 0; +} + +static inline cairo_bool_t +seqno_before (unsigned long a, unsigned long b) +{ + return (long)(b - a) > 0; +} + +static inline cairo_bool_t +seqno_after (unsigned long a, unsigned long b) +{ + return (long)(a - b) > 0; +} + +static inline cairo_status_t +_pqueue_init (struct pqueue *pq) +{ + pq->max_size = 32; + pq->size = 0; + + pq->elements = _cairo_malloc_ab (pq->max_size, + sizeof (cairo_xlib_shm_info_t *)); + if (unlikely (pq->elements == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + PQ_TOP(pq) = NULL; + return CAIRO_STATUS_SUCCESS; +} + +static inline void +_pqueue_fini (struct pqueue *pq) +{ + free (pq->elements); +} + +static cairo_status_t +_pqueue_grow (struct pqueue *pq) +{ + cairo_xlib_shm_info_t **new_elements; + + new_elements = _cairo_realloc_ab (pq->elements, + 2 * pq->max_size, + sizeof (cairo_xlib_shm_info_t *)); + if (unlikely (new_elements == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + pq->elements = new_elements; + pq->max_size *= 2; + return CAIRO_STATUS_SUCCESS; +} + +static void +_pqueue_shrink (struct pqueue *pq, int min_size) +{ + cairo_xlib_shm_info_t **new_elements; + + if (min_size > pq->max_size) + return; + + new_elements = _cairo_realloc_ab (pq->elements, + min_size, + sizeof (cairo_xlib_shm_info_t *)); + if (unlikely (new_elements == NULL)) + return; + + pq->elements = new_elements; + pq->max_size = min_size; +} + +static inline cairo_status_t +_pqueue_push (struct pqueue *pq, cairo_xlib_shm_info_t *info) +{ + cairo_xlib_shm_info_t **elements; + int i, parent; + + if (unlikely (pq->size + 1 == pq->max_size)) { + cairo_status_t status; + + status = _pqueue_grow (pq); + if (unlikely (status)) + return status; + } + + elements = pq->elements; + + for (i = ++pq->size; + i != PQ_FIRST_ENTRY && + info->last_request < elements[parent = PQ_PARENT_INDEX (i)]->last_request; + i = parent) + { + elements[i] = elements[parent]; + } + + elements[i] = info; + + return CAIRO_STATUS_SUCCESS; +} + +static inline void +_pqueue_pop (struct pqueue *pq) +{ + cairo_xlib_shm_info_t **elements = pq->elements; + cairo_xlib_shm_info_t *tail; + int child, i; + + tail = elements[pq->size--]; + if (pq->size == 0) { + elements[PQ_FIRST_ENTRY] = NULL; + _pqueue_shrink (pq, 32); + return; + } + + for (i = PQ_FIRST_ENTRY; + (child = PQ_LEFT_CHILD_INDEX (i)) <= pq->size; + i = child) + { + if (child != pq->size && + elements[child+1]->last_request < elements[child]->last_request) + { + child++; + } + + if (elements[child]->last_request >= tail->last_request) + break; + + elements[i] = elements[child]; + } + elements[i] = tail; +} + +static cairo_bool_t _x_error_occurred; + +static int +_check_error_handler (Display *display, + XErrorEvent *event) +{ + _x_error_occurred = TRUE; + return False; /* ignored */ +} + +static cairo_bool_t +can_use_shm (Display *dpy, int *has_pixmap) +{ + XShmSegmentInfo shm; + int (*old_handler) (Display *display, XErrorEvent *event); + Status success; + int major, minor; + + if (! XShmQueryExtension (dpy)) + return FALSE; + + XShmQueryVersion (dpy, &major, &minor, has_pixmap); + + shm.shmid = shmget (IPC_PRIVATE, 0x1000, IPC_CREAT | 0600); + if (shm.shmid == -1) + return FALSE; + + shm.readOnly = FALSE; + shm.shmaddr = shmat (shm.shmid, NULL, 0); + if (shm.shmaddr == (char *) -1) { + shmctl (shm.shmid, IPC_RMID, NULL); + return FALSE; + } + + assert (CAIRO_MUTEX_IS_LOCKED (_cairo_xlib_display_mutex)); + _x_error_occurred = FALSE; + + XLockDisplay (dpy); + XSync (dpy, False); + old_handler = XSetErrorHandler (_check_error_handler); + + success = XShmAttach (dpy, &shm); + if (success) + XShmDetach (dpy, &shm); + + XSync (dpy, False); + XSetErrorHandler (old_handler); + XUnlockDisplay (dpy); + + shmctl (shm.shmid, IPC_RMID, NULL); + shmdt (shm.shmaddr); + + return success && ! _x_error_occurred; +} + +static inline Display * +peek_display (cairo_device_t *device) +{ + return ((cairo_xlib_display_t *)device)->display; +} + +static inline unsigned long +peek_processed (cairo_device_t *device) +{ + return LastKnownRequestProcessed (peek_display(device)); +} + +static void +_cairo_xlib_display_shm_pool_destroy (cairo_xlib_display_t *display, + cairo_xlib_shm_t *pool) +{ + shmdt (pool->shm.shmaddr); + if (display->display) /* may be called after CloseDisplay */ + XShmDetach (display->display, &pool->shm); + + _cairo_mempool_fini (&pool->mem); + + cairo_list_del (&pool->link); + free (pool); +} + +static void send_event(cairo_xlib_display_t *display, + cairo_xlib_shm_info_t *info, + unsigned long seqno) +{ + XShmCompletionEvent ev; + + if (! seqno_after (seqno, display->shm->last_event)) + return; + + ev.type = display->shm->event; + ev.send_event = 1; /* XXX or lie? */ + ev.serial = XNextRequest (display->display); + ev.drawable = display->shm->window; + ev.major_code = display->shm->opcode; + ev.minor_code = X_ShmPutImage; + ev.shmseg = info->pool->shm.shmid; + ev.offset = (char *)info->mem - (char *)info->pool->shm.shmaddr; + + XSendEvent (display->display, ev.drawable, False, 0, (XEvent *)&ev); + + display->shm->last_event = ev.serial; +} + +static void _cairo_xlib_display_sync (cairo_xlib_display_t *display) +{ + cairo_xlib_shm_info_t *info; + struct pqueue *pq = &display->shm->info; + + XSync (display->display, False); + + while ((info = PQ_TOP(pq))) { + _cairo_mempool_free (&info->pool->mem, info->mem); + _pqueue_pop (&display->shm->info); + free (info); + } +} + +static void +_cairo_xlib_shm_info_cleanup (cairo_xlib_display_t *display) +{ + cairo_xlib_shm_info_t *info; + Display *dpy = display->display; + struct pqueue *pq = &display->shm->info; + unsigned long processed; + + if (PQ_TOP(pq) == NULL) + return; + + XEventsQueued (dpy, QueuedAfterReading); + processed = LastKnownRequestProcessed (dpy); + + info = PQ_TOP(pq); + do { + if (! seqno_passed (info->last_request, processed)) { + send_event (display, info, display->shm->last_request); + return; + } + + _cairo_mempool_free (&info->pool->mem, info->mem); + _pqueue_pop (&display->shm->info); + free (info); + } while ((info = PQ_TOP(pq))); +} + +static cairo_xlib_shm_t * +_cairo_xlib_shm_info_find (cairo_xlib_display_t *display, size_t size, + void **ptr, unsigned long *last_request) +{ + cairo_xlib_shm_info_t *info; + struct pqueue *pq = &display->shm->info; + + if (PQ_TOP(pq) == NULL) + return NULL; + + info = PQ_TOP(pq); + do { + cairo_xlib_shm_t *pool = info->pool; + + *last_request = info->last_request; + + _pqueue_pop (&display->shm->info); + _cairo_mempool_free (&pool->mem, info->mem); + free (info); + + if (pool->mem.free_bytes >= size) { + void *mem = _cairo_mempool_alloc (&pool->mem, size); + if (mem != NULL) { + *ptr = mem; + return pool; + } + } + } while ((info = PQ_TOP(pq))); + + return NULL; +} + +static cairo_xlib_shm_t * +_cairo_xlib_shm_pool_find (cairo_xlib_display_t *display, + size_t size, + void **ptr) +{ + cairo_xlib_shm_t *pool; + + cairo_list_foreach_entry (pool, cairo_xlib_shm_t, &display->shm->pool, link) { + if (pool->mem.free_bytes >= size) { + void *mem = _cairo_mempool_alloc (&pool->mem, size); + if (mem != NULL) { + *ptr = mem; + return pool; + } + } + } + + return NULL; +} + +static void +_cairo_xlib_shm_pool_cleanup (cairo_xlib_display_t *display) +{ + cairo_xlib_shm_t *pool, *next; + unsigned long processed; + + processed = LastKnownRequestProcessed (display->display); + + cairo_list_foreach_entry_safe (pool, next, cairo_xlib_shm_t, + &display->shm->pool, link) { + if (! seqno_passed (pool->attached, processed)) + break; + + if (pool->mem.free_bytes == pool->mem.max_bytes) + _cairo_xlib_display_shm_pool_destroy (display, pool); + } +} + +static cairo_xlib_shm_t * +_cairo_xlib_shm_pool_create(cairo_xlib_display_t *display, + size_t size, void **ptr) +{ + Display *dpy = display->display; + cairo_xlib_shm_t *pool; + size_t bytes, maxbits = 16, minbits = MIN_BITS; + Status success; + + pool = _cairo_calloc (sizeof (cairo_xlib_shm_t)); + if (pool == NULL) + return NULL; + + bytes = 1 << maxbits; + while (bytes <= size) + bytes <<= 1, maxbits++; + bytes <<= 3; + + minbits += (maxbits - 16) / 2; + + pool->shm.shmid = shmget (IPC_PRIVATE, bytes, IPC_CREAT | 0600); + while (pool->shm.shmid == -1 && bytes >= 2*size) { + bytes >>= 1; + pool->shm.shmid = shmget (IPC_PRIVATE, bytes, IPC_CREAT | 0600); + } + if (pool->shm.shmid == -1) + goto cleanup; + + pool->shm.readOnly = FALSE; + pool->shm.shmaddr = shmat (pool->shm.shmid, NULL, 0); + if (pool->shm.shmaddr == (char *) -1) { + shmctl (pool->shm.shmid, IPC_RMID, NULL); + goto cleanup; + } + + pool->attached = XNextRequest (dpy); + success = XShmAttach (dpy, &pool->shm); +#if !IPC_RMID_DEFERRED_RELEASE + XSync (dpy, FALSE); +#endif + shmctl (pool->shm.shmid, IPC_RMID, NULL); + + if (! success) + goto cleanup_shm; + + if (_cairo_mempool_init (&pool->mem, pool->shm.shmaddr, bytes, + minbits, maxbits - minbits + 1)) + goto cleanup_detach; + + cairo_list_add (&pool->link, &display->shm->pool); + + *ptr = _cairo_mempool_alloc (&pool->mem, size); + assert (*ptr != NULL); + return pool; + +cleanup_detach: + XShmDetach (dpy, &pool->shm); +cleanup_shm: + shmdt (pool->shm.shmaddr); +cleanup: + free (pool); + return NULL; +} + +static cairo_xlib_shm_info_t * +_cairo_xlib_shm_info_create (cairo_xlib_display_t *display, + size_t size, cairo_bool_t will_sync) +{ + cairo_xlib_shm_info_t *info; + cairo_xlib_shm_t *pool; + unsigned long last_request = 0; + void *mem = NULL; + + _cairo_xlib_shm_info_cleanup (display); + pool = _cairo_xlib_shm_pool_find (display, size, &mem); + _cairo_xlib_shm_pool_cleanup (display); + + if (pool == NULL && will_sync) + pool = _cairo_xlib_shm_info_find (display, size, &mem, &last_request); + if (pool == NULL) + pool = _cairo_xlib_shm_pool_create (display, size, &mem); + if (pool == NULL) + return NULL; + + assert (mem != NULL); + + info = _cairo_calloc (sizeof (*info)); + if (info == NULL) { + _cairo_mempool_free (&pool->mem, mem); + return NULL; + } + + info->pool = pool; + info->mem = mem; + info->size = size; + info->last_request = last_request; + + return info; +} + +static cairo_status_t +_cairo_xlib_shm_surface_flush (void *abstract_surface, unsigned flags) +{ + cairo_xlib_shm_surface_t *shm = abstract_surface; + cairo_xlib_display_t *display; + Display *dpy; + cairo_status_t status; + + if (shm->active == 0) + return CAIRO_STATUS_SUCCESS; + + if (shm->image.base._finishing) + return CAIRO_STATUS_SUCCESS; + + if (seqno_passed (shm->active, peek_processed (shm->image.base.device))) { + shm->active = 0; + return CAIRO_STATUS_SUCCESS; + } + + status = _cairo_xlib_display_acquire (shm->image.base.device, &display); + if (unlikely (status)) + return status; + + send_event (display, shm->info, shm->active); + + dpy = display->display; + XEventsQueued (dpy, QueuedAfterReading); + while (! seqno_passed (shm->active, LastKnownRequestProcessed (dpy))) { + LockDisplay(dpy); + _XReadEvents(dpy); + UnlockDisplay(dpy); + } + + cairo_device_release (&display->base); + shm->active = 0; + + return CAIRO_STATUS_SUCCESS; +} + +static inline cairo_bool_t +active (cairo_xlib_shm_surface_t *shm, Display *dpy) +{ + return (shm->active && + ! seqno_passed (shm->active, LastKnownRequestProcessed (dpy))); +} + +static cairo_status_t +_cairo_xlib_shm_surface_finish (void *abstract_surface) +{ + cairo_xlib_shm_surface_t *shm = abstract_surface; + cairo_xlib_display_t *display; + cairo_status_t status; + + if (shm->image.base.damage) { + _cairo_damage_destroy (shm->image.base.damage); + shm->image.base.damage = _cairo_damage_create_in_error (CAIRO_STATUS_SURFACE_FINISHED); + } + + status = _cairo_xlib_display_acquire (shm->image.base.device, &display); + if (unlikely (status)) + return status; + + if (shm->pixmap) + XFreePixmap (display->display, shm->pixmap); + + if (active (shm, display->display)) { + shm->info->last_request = shm->active; + _pqueue_push (&display->shm->info, shm->info); + if (seqno_before (display->shm->last_request, shm->active)) + display->shm->last_request = shm->active; + } else { + _cairo_mempool_free (&shm->info->pool->mem, shm->info->mem); + free (shm->info); + + _cairo_xlib_shm_pool_cleanup (display); + } + + cairo_list_del (&shm->link); + + cairo_device_release (&display->base); + return _cairo_image_surface_finish (abstract_surface); +} + +static const cairo_surface_backend_t cairo_xlib_shm_surface_backend = { + CAIRO_SURFACE_TYPE_IMAGE, + _cairo_xlib_shm_surface_finish, + + _cairo_default_context_create, + + _cairo_image_surface_create_similar, + NULL, /* create similar image */ + _cairo_image_surface_map_to_image, + _cairo_image_surface_unmap_image, + + _cairo_image_surface_source, + _cairo_image_surface_acquire_source_image, + _cairo_image_surface_release_source_image, + _cairo_image_surface_snapshot, + + NULL, /* copy_page */ + NULL, /* show_page */ + + _cairo_image_surface_get_extents, + _cairo_image_surface_get_font_options, + + _cairo_xlib_shm_surface_flush, + NULL, + + _cairo_image_surface_paint, + _cairo_image_surface_mask, + _cairo_image_surface_stroke, + _cairo_image_surface_fill, + NULL, /* fill-stroke */ + _cairo_image_surface_glyphs, +}; + +static cairo_bool_t +has_shm (cairo_xlib_surface_t *surface) +{ + cairo_xlib_display_t *display = (cairo_xlib_display_t *)surface->base.device; + return display->shm != NULL; +} + +static int +has_shm_pixmaps (cairo_xlib_surface_t *surface) +{ + cairo_xlib_display_t *display = (cairo_xlib_display_t *)surface->base.device; + if (!display->shm) + return 0; + + return display->shm->has_pixmaps; +} + +static cairo_xlib_shm_surface_t * +_cairo_xlib_shm_surface_create (cairo_xlib_surface_t *other, + pixman_format_code_t format, + int width, int height, + cairo_bool_t will_sync, + int create_pixmap) +{ + cairo_xlib_shm_surface_t *shm; + cairo_xlib_display_t *display; + pixman_image_t *image; + int stride, size; + + if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX) + return NULL; + + stride = CAIRO_STRIDE_FOR_WIDTH_BPP (width, PIXMAN_FORMAT_BPP(format)); + size = stride * height; + if (size < MIN_SIZE) + return NULL; + + shm = _cairo_calloc (sizeof (*shm)); + if (unlikely (shm == NULL)) + return (cairo_xlib_shm_surface_t *)_cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY); + + _cairo_surface_init (&shm->image.base, + &cairo_xlib_shm_surface_backend, + other->base.device, + _cairo_content_from_pixman_format (format), + FALSE); /* is_vector */ + + if (_cairo_xlib_display_acquire (other->base.device, &display)) + goto cleanup_shm; + + shm->info = _cairo_xlib_shm_info_create (display, size, will_sync); + if (shm->info == NULL) + goto cleanup_display; + + image = pixman_image_create_bits (format, width, height, + (uint32_t *) shm->info->mem, stride); + if (image == NULL) + goto cleanup_info; + + _cairo_image_surface_init (&shm->image, image, format); + + shm->pixmap = 0; + if (create_pixmap && size >= create_pixmap) { + shm->pixmap = XShmCreatePixmap (display->display, + other->drawable, + shm->info->mem, + &shm->info->pool->shm, + shm->image.width, + shm->image.height, + shm->image.depth); + } + shm->active = shm->info->last_request; + shm->idle = -5; + + assert (shm->active == 0 || will_sync); + + cairo_list_add (&shm->link, &display->shm->surfaces); + + cairo_device_release (&display->base); + + return shm; + +cleanup_info: + _cairo_mempool_free (&shm->info->pool->mem, shm->info->mem); + free(shm->info); +cleanup_display: + cairo_device_release (&display->base); +cleanup_shm: + free (shm); + return NULL; +} + +static void +_cairo_xlib_surface_update_shm (cairo_xlib_surface_t *surface) +{ + cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *)surface->shm; + cairo_xlib_display_t *display; + cairo_damage_t *damage; + GC gc; + + damage = _cairo_damage_reduce (surface->base.damage); + surface->base.damage = _cairo_damage_create(); + + if (_cairo_xlib_display_acquire (surface->base.device, &display)) + goto cleanup_damage; + + if (_cairo_xlib_surface_get_gc (display, surface, &gc)) + goto cleanup_display; + + if (! surface->owns_pixmap) { + XGCValues gcv; + + gcv.subwindow_mode = IncludeInferiors; + XChangeGC (display->display, gc, GCSubwindowMode, &gcv); + } + + if (damage->region) { + XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)]; + XRectangle *rects = stack_rects; + cairo_rectangle_int_t r; + int n_rects, i; + + n_rects = cairo_region_num_rectangles (damage->region); + if (n_rects == 0) { + } else if (n_rects == 1) { + cairo_region_get_rectangle (damage->region, 0, &r); + XCopyArea (display->display, + surface->drawable, shm->pixmap, gc, + r.x, r.y, + r.width, r.height, + r.x, r.y); + } else { + if (n_rects > ARRAY_LENGTH (stack_rects)) { + rects = _cairo_malloc_ab (n_rects, sizeof (XRectangle)); + if (unlikely (rects == NULL)) { + rects = stack_rects; + n_rects = ARRAY_LENGTH (stack_rects); + } + } + for (i = 0; i < n_rects; i++) { + cairo_region_get_rectangle (damage->region, i, &r); + + rects[i].x = r.x; + rects[i].y = r.y; + rects[i].width = r.width; + rects[i].height = r.height; + } + XSetClipRectangles (display->display, gc, 0, 0, rects, i, YXBanded); + + XCopyArea (display->display, + surface->drawable, shm->pixmap, gc, + 0, 0, + shm->image.width, shm->image.height, + 0, 0); + + if (damage->status == CAIRO_STATUS_SUCCESS && damage->region) + XSetClipMask (display->display, gc, None); + } + } else { + XCopyArea (display->display, + surface->drawable, shm->pixmap, gc, + 0, 0, + shm->image.width, shm->image.height, + 0, 0); + } + + if (! surface->owns_pixmap) { + XGCValues gcv; + + gcv.subwindow_mode = ClipByChildren; + XChangeGC (display->display, gc, GCSubwindowMode, &gcv); + } + + _cairo_xlib_display_sync (display); + shm->active = 0; + shm->idle--; + + _cairo_xlib_surface_put_gc (display, surface, gc); +cleanup_display: + cairo_device_release (&display->base); +cleanup_damage: + _cairo_damage_destroy (damage); +} + +static void +_cairo_xlib_surface_clear_shm (cairo_xlib_surface_t *surface) +{ + cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *)surface->shm; + + assert (shm->active == 0); + + _cairo_damage_destroy (surface->base.damage); + surface->base.damage = _cairo_damage_create(); + + memset (shm->image.data, 0, shm->image.stride * shm->image.height); + shm->image.base.is_clear = TRUE; +} + +static void inc_idle (cairo_surface_t *surface) +{ + cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *)surface; + shm->idle++; +} + +static void dec_idle (cairo_surface_t *surface) +{ + cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *)surface; + shm->idle--; +} + +cairo_surface_t * +_cairo_xlib_surface_get_shm (cairo_xlib_surface_t *surface, + cairo_bool_t overwrite) +{ + if (surface->fallback) { + assert (surface->base.damage); + assert (surface->shm); + assert (surface->shm->damage); + goto done; + } + + if (surface->shm == NULL) { + pixman_format_code_t pixman_format; + cairo_bool_t will_sync; + + if (! has_shm_pixmaps (surface)) + return NULL; + + if ((surface->width | surface->height) < 32) + return NULL; + + pixman_format = _pixman_format_for_xlib_surface (surface); + if (pixman_format == 0) + return NULL; + + will_sync = !surface->base.is_clear && !overwrite; + + surface->shm = + &_cairo_xlib_shm_surface_create (surface, pixman_format, + surface->width, surface->height, + will_sync, 1)->image.base; + if (surface->shm == NULL) + return NULL; + + assert (surface->base.damage == NULL); + if (surface->base.serial || !surface->owns_pixmap) { + cairo_rectangle_int_t rect; + + rect.x = rect.y = 0; + rect.width = surface->width; + rect.height = surface->height; + + surface->base.damage = + _cairo_damage_add_rectangle (NULL, &rect); + } else + surface->base.damage = _cairo_damage_create (); + + surface->shm->damage = _cairo_damage_create (); + } + + if (overwrite) { + _cairo_damage_destroy (surface->base.damage); + surface->base.damage = _cairo_damage_create (); + } + + if (!surface->base.is_clear && surface->base.damage->dirty) + _cairo_xlib_surface_update_shm (surface); + + _cairo_xlib_shm_surface_flush (surface->shm, 1); + + if (surface->base.is_clear && surface->base.damage->dirty) + _cairo_xlib_surface_clear_shm (surface); + +done: + dec_idle(surface->shm); + return surface->shm; +} + +cairo_int_status_t +_cairo_xlib_surface_put_shm (cairo_xlib_surface_t *surface) +{ + cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS; + + if (!surface->fallback) { + if (surface->shm) + inc_idle (surface->shm); + return CAIRO_INT_STATUS_SUCCESS; + } + + if (surface->shm->damage->dirty) { + cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *) surface->shm; + cairo_xlib_display_t *display; + cairo_damage_t *damage; + GC gc; + + status = _cairo_xlib_display_acquire (surface->base.device, &display); + if (unlikely (status)) + return status; + + damage = _cairo_damage_reduce (shm->image.base.damage); + shm->image.base.damage = _cairo_damage_create (); + + TRACE ((stderr, "%s: flushing damage x %d\n", __FUNCTION__, + damage->region ? cairo_region_num_rectangles (damage->region) : 0)); + if (damage->status == CAIRO_STATUS_SUCCESS && damage->region) { + XRectangle stack_rects[CAIRO_STACK_ARRAY_LENGTH (XRectangle)]; + XRectangle *rects = stack_rects; + cairo_rectangle_int_t r; + int n_rects, i; + + n_rects = cairo_region_num_rectangles (damage->region); + if (n_rects == 0) + goto out; + + status = _cairo_xlib_surface_get_gc (display, surface, &gc); + if (unlikely (status)) + goto out; + + if (n_rects == 1) { + cairo_region_get_rectangle (damage->region, 0, &r); + _cairo_xlib_shm_surface_mark_active (surface->shm); + XCopyArea (display->display, + shm->pixmap, surface->drawable, gc, + r.x, r.y, + r.width, r.height, + r.x, r.y); + } else { + if (n_rects > ARRAY_LENGTH (stack_rects)) { + rects = _cairo_malloc_ab (n_rects, sizeof (XRectangle)); + if (unlikely (rects == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + _cairo_xlib_surface_put_gc (display, surface, gc); + goto out; + } + } + for (i = 0; i < n_rects; i++) { + cairo_region_get_rectangle (damage->region, i, &r); + + rects[i].x = r.x; + rects[i].y = r.y; + rects[i].width = r.width; + rects[i].height = r.height; + } + XSetClipRectangles (display->display, gc, 0, 0, rects, i, YXBanded); + + _cairo_xlib_shm_surface_mark_active (surface->shm); + XCopyArea (display->display, + shm->pixmap, surface->drawable, gc, + 0, 0, + shm->image.width, shm->image.height, + 0, 0); + + if (damage->status == CAIRO_STATUS_SUCCESS && damage->region) + XSetClipMask (display->display, gc, None); + } + + _cairo_xlib_surface_put_gc (display, surface, gc); + } + +out: + _cairo_damage_destroy (damage); + cairo_device_release (&display->base); + } + + return status; +} + +cairo_surface_t * +_cairo_xlib_surface_create_shm (cairo_xlib_surface_t *other, + pixman_format_code_t format, + int width, int height) +{ + cairo_surface_t *surface; + + surface = NULL; + if (has_shm (other)) + surface = &_cairo_xlib_shm_surface_create (other, format, width, height, + FALSE, has_shm_pixmaps (other))->image.base; + + return surface; +} + +cairo_surface_t * +_cairo_xlib_surface_create_shm__image (cairo_xlib_surface_t *surface, + pixman_format_code_t format, + int width, int height) +{ + if (! has_shm(surface)) + return NULL; + + return &_cairo_xlib_shm_surface_create (surface, format, width, height, + FALSE, 0)->image.base; +} + +cairo_surface_t * +_cairo_xlib_surface_create_similar_shm (void *other, + cairo_format_t format, + int width, int height) +{ + cairo_surface_t *surface; + + surface = _cairo_xlib_surface_create_shm (other, + _cairo_format_to_pixman_format_code (format), + width, height); + if (surface) { + if (! surface->is_clear) { + cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *) surface; + assert (shm->active == 0); + memset (shm->image.data, 0, shm->image.stride * shm->image.height); + shm->image.base.is_clear = TRUE; + } + } else + surface = cairo_image_surface_create (format, width, height); + + return surface; +} + +void +_cairo_xlib_shm_surface_mark_active (cairo_surface_t *_shm) +{ + cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *) _shm; + cairo_xlib_display_t *display = (cairo_xlib_display_t *) _shm->device; + + shm->active = XNextRequest (display->display); +} + +void +_cairo_xlib_shm_surface_get_ximage (cairo_surface_t *surface, + XImage *ximage) +{ + cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *) surface; + int native_byte_order = _cairo_is_little_endian () ? LSBFirst : MSBFirst; + cairo_format_masks_t image_masks; + int ret; + + ret = _pixman_format_to_masks (shm->image.pixman_format, &image_masks); + assert (ret); + + ximage->width = shm->image.width; + ximage->height = shm->image.height; + ximage->format = ZPixmap; + ximage->data = (char *) shm->image.data; + ximage->obdata = (char *)&shm->info->pool->shm; + ximage->byte_order = native_byte_order; + ximage->bitmap_unit = 32; /* always for libpixman */ + ximage->bitmap_bit_order = native_byte_order; + ximage->bitmap_pad = 32; /* always for libpixman */ + ximage->depth = shm->image.depth; + ximage->bytes_per_line = shm->image.stride; + ximage->bits_per_pixel = image_masks.bpp; + ximage->red_mask = image_masks.red_mask; + ximage->green_mask = image_masks.green_mask; + ximage->blue_mask = image_masks.blue_mask; + ximage->xoffset = 0; + + ret = XInitImage (ximage); + assert (ret != 0); +} + +void * +_cairo_xlib_shm_surface_get_obdata (cairo_surface_t *surface) +{ + cairo_xlib_display_t *display = (cairo_xlib_display_t *) surface->device; + cairo_xlib_shm_surface_t *shm = (cairo_xlib_shm_surface_t *) surface; + + display->shm->last_event = shm->active = XNextRequest (display->display); + return &shm->info->pool->shm; +} + +Pixmap +_cairo_xlib_shm_surface_get_pixmap (cairo_surface_t *surface) +{ + cairo_xlib_shm_surface_t *shm; + + shm = (cairo_xlib_shm_surface_t *) surface; + return shm->pixmap; +} + +XRenderPictFormat * +_cairo_xlib_shm_surface_get_xrender_format (cairo_surface_t *surface) +{ + cairo_xlib_shm_surface_t *shm; + + shm = (cairo_xlib_shm_surface_t *) surface; + if (shm->image.format != CAIRO_FORMAT_INVALID) + return _cairo_xlib_display_get_xrender_format ((cairo_xlib_display_t *)surface->device, + shm->image.format); + + return _cairo_xlib_display_get_xrender_format_for_pixman((cairo_xlib_display_t *)surface->device, + shm->image.pixman_format); +} + +cairo_bool_t +_cairo_xlib_shm_surface_is_active (cairo_surface_t *surface) +{ + cairo_xlib_shm_surface_t *shm; + + shm = (cairo_xlib_shm_surface_t *) surface; + if (shm->active == 0) + return FALSE; + + if (seqno_passed (shm->active, peek_processed (shm->image.base.device))) { + shm->active = 0; + return FALSE; + } + + return TRUE; +} + +cairo_bool_t +_cairo_xlib_shm_surface_is_idle (cairo_surface_t *surface) +{ + cairo_xlib_shm_surface_t *shm; + + shm = (cairo_xlib_shm_surface_t *) surface; + return shm->idle > 0; +} + +#define XORG_VERSION_ENCODE(major,minor,patch,snap) \ + (((major) * 10000000) + ((minor) * 100000) + ((patch) * 1000) + snap) + +static cairo_bool_t +has_broken_send_shm_event (cairo_xlib_display_t *display, + cairo_xlib_shm_display_t *shm) +{ + Display *dpy = display->display; + int (*old_handler) (Display *display, XErrorEvent *event); + XShmCompletionEvent ev; + XShmSegmentInfo info; + + info.shmid = shmget (IPC_PRIVATE, 0x1000, IPC_CREAT | 0600); + if (info.shmid == -1) + return TRUE; + + info.readOnly = FALSE; + info.shmaddr = shmat (info.shmid, NULL, 0); + if (info.shmaddr == (char *) -1) { + shmctl (info.shmid, IPC_RMID, NULL); + return TRUE; + } + + ev.type = shm->event; + ev.send_event = 1; + ev.serial = 1; + ev.drawable = shm->window; + ev.major_code = shm->opcode; + ev.minor_code = X_ShmPutImage; + + ev.shmseg = info.shmid; + ev.offset = 0; + + assert (CAIRO_MUTEX_IS_LOCKED (_cairo_xlib_display_mutex)); + _x_error_occurred = FALSE; + + XLockDisplay (dpy); + XSync (dpy, False); + old_handler = XSetErrorHandler (_check_error_handler); + + XShmAttach (dpy, &info); + XSendEvent (dpy, ev.drawable, False, 0, (XEvent *)&ev); + XShmDetach (dpy, &info); + + XSync (dpy, False); + XSetErrorHandler (old_handler); + XUnlockDisplay (dpy); + + shmctl (info.shmid, IPC_RMID, NULL); + shmdt (info.shmaddr); + + return _x_error_occurred; +} + +static cairo_bool_t +xorg_has_buggy_send_shm_completion_event(cairo_xlib_display_t *display, + cairo_xlib_shm_display_t *shm) +{ + Display *dpy = display->display; + + /* As libXext sets the SEND_EVENT bit in the ShmCompletionEvent, + * the Xserver may crash if it does not take care when processing + * the event type. For instance versions of Xorg prior to 1.11.1 + * exhibited this bug, and was fixed by: + * + * commit 2d2dce558d24eeea0eb011ec9ebaa6c5c2273c39 + * Author: Sam Spilsbury + * Date: Wed Sep 14 09:58:34 2011 +0800 + * + * Remove the SendEvent bit (0x80) before doing range checks on event type. + */ + if (_cairo_xlib_vendor_is_xorg (dpy) && + VendorRelease (dpy) < XORG_VERSION_ENCODE(1,11,0,1)) + return TRUE; + + /* For everyone else check that no error is generated */ + return has_broken_send_shm_event (display, shm); +} + +void +_cairo_xlib_display_init_shm (cairo_xlib_display_t *display) +{ + cairo_xlib_shm_display_t *shm; + XSetWindowAttributes attr; + XExtCodes *codes; + int has_pixmap, scr; + + display->shm = NULL; + + if (!can_use_shm (display->display, &has_pixmap)) + return; + + shm = _cairo_calloc (sizeof (*shm)); + if (unlikely (shm == NULL)) + return; + + codes = XInitExtension (display->display, SHMNAME); + if (codes == NULL) { + free (shm); + return; + } + + shm->opcode = codes ->major_opcode; + shm->event = codes->first_event; + + if (unlikely (_pqueue_init (&shm->info))) { + free (shm); + return; + } + + scr = DefaultScreen (display->display); + attr.override_redirect = 1; + shm->window = XCreateWindow (display->display, + DefaultRootWindow (display->display), -1, -1, + 1, 1, 0, + DefaultDepth (display->display, scr), + InputOutput, + DefaultVisual (display->display, scr), + CWOverrideRedirect, &attr); + shm->last_event = 0; + shm->last_request = 0; + + if (xorg_has_buggy_send_shm_completion_event(display, shm)) + has_pixmap = 0; + + shm->has_pixmaps = has_pixmap ? MIN_PIXMAP_SIZE : 0; + cairo_list_init (&shm->pool); + + cairo_list_init (&shm->surfaces); + + display->shm = shm; +} + +void +_cairo_xlib_display_fini_shm (cairo_xlib_display_t *display) +{ + cairo_xlib_shm_display_t *shm = display->shm; + + if (shm == NULL) + return; + + while (!cairo_list_is_empty (&shm->surfaces)) + cairo_surface_finish (&cairo_list_first_entry (&shm->surfaces, + cairo_xlib_shm_surface_t, + link)->image.base); + + _pqueue_fini (&shm->info); + + while (!cairo_list_is_empty (&shm->pool)) { + cairo_xlib_shm_t *pool; + + pool = cairo_list_first_entry (&shm->pool, cairo_xlib_shm_t, link); + _cairo_xlib_display_shm_pool_destroy (display, pool); + } + + if (display->display) + XDestroyWindow (display->display, shm->window); + + free (shm); + display->shm = NULL; +} +#endif +#endif diff --git a/local/recipes/libs/cairo/source/src/cairo-xlib-surface.c b/local/recipes/libs/cairo/source/src/cairo-xlib-surface.c new file mode 100644 index 0000000000..fac2911998 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-xlib-surface.c @@ -0,0 +1,2389 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Behdad Esfahbod + * Chris Wilson + * Karl Tomlinson , Mozilla Corporation + */ + +/* Heed well the words of Owen Taylor: + * "Any patch that works around a render bug, or claims to, without a + * specific reference to the bug filed in bugzilla.freedesktop.org will + * never pass approval." + */ + +#include "cairoint.h" + +/** + * CAIRO_HAS_XLIB_XCB_FUNCTIONS: + * + * Defined if Cairo has support for XCB integration with Xlib. + * This macro can be used to conditionally compile backend-specific code. + * + * Since: 1.10 + **/ + +#if !CAIRO_HAS_XLIB_XCB_FUNCTIONS + +#include "cairo-xlib-private.h" +#include "cairo-xlib-surface-private.h" + +#include "cairo-compositor-private.h" +#include "cairo-clip-private.h" +#include "cairo-damage-private.h" +#include "cairo-default-context-private.h" +#include "cairo-error-private.h" +#include "cairo-image-surface-private.h" +#include "cairo-list-inline.h" +#include "cairo-pattern-private.h" +#include "cairo-pixman-private.h" +#include "cairo-region-private.h" +#include "cairo-scaled-font-private.h" +#include "cairo-surface-snapshot-private.h" +#include "cairo-surface-subsurface-private.h" + +#include /* for XDestroyImage */ + +#include +#include +#include + +#define DEBUG 0 + +#if DEBUG +#define UNSUPPORTED(reason) \ + fprintf (stderr, \ + "cairo-xlib: hit unsupported operation %s(), line %d: %s\n", \ + __FUNCTION__, __LINE__, reason), \ + CAIRO_INT_STATUS_UNSUPPORTED +#else +#define UNSUPPORTED(reason) CAIRO_INT_STATUS_UNSUPPORTED +#endif + +#if DEBUG +#include +static void CAIRO_PRINTF_FORMAT (2, 3) +_x_bread_crumb (Display *dpy, + const char *fmt, + ...) +{ + xReq *req; + char buf[2048]; + unsigned int len, len_dwords; + va_list ap; + + va_start (ap, fmt); + len = vsnprintf (buf, sizeof (buf), fmt, ap); + va_end (ap); + + buf[len++] = '\0'; + while (len & 3) + buf[len++] = '\0'; + + LockDisplay (dpy); + GetEmptyReq (NoOperation, req); + + len_dwords = len >> 2; + SetReqLen (req, len_dwords, len_dwords); + Data (dpy, buf, len); + + UnlockDisplay (dpy); + SyncHandle (); +} +#define X_DEBUG(x) _x_bread_crumb x +#else +#define X_DEBUG(x) +#endif + +/** + * SECTION:cairo-xlib + * @Title: XLib Surfaces + * @Short_Description: X Window System rendering using XLib + * @See_Also: #cairo_surface_t + * + * The XLib surface is used to render cairo graphics to X Window System + * windows and pixmaps using the XLib library. + * + * Note that the XLib surface automatically takes advantage of X render extension + * if it is available. + **/ + +/** + * CAIRO_HAS_XLIB_SURFACE: + * + * Defined if the Xlib surface backend is available. + * This macro can be used to conditionally compile backend-specific code. + * + * Since: 1.0 + **/ + +/** + * SECTION:cairo-xlib-xrender + * @Title: XLib-XRender Backend + * @Short_Description: X Window System rendering using XLib and the X Render extension + * @See_Also: #cairo_surface_t + * + * The XLib surface is used to render cairo graphics to X Window System + * windows and pixmaps using the XLib and Xrender libraries. + * + * Note that the XLib surface automatically takes advantage of X Render extension + * if it is available. + **/ + +/** + * CAIRO_HAS_XLIB_XRENDER_SURFACE: + * + * Defined if the XLib/XRender surface functions are available. + * This macro can be used to conditionally compile backend-specific code. + * + * Since: 1.6 + **/ + +/* Xlib doesn't define a typedef, so define one ourselves */ +typedef int (*cairo_xlib_error_func_t) (Display *display, + XErrorEvent *event); + +static cairo_surface_t * +_cairo_xlib_surface_create_internal (cairo_xlib_screen_t *screen, + Drawable drawable, + Visual *visual, + XRenderPictFormat *xrender_format, + int width, + int height, + int depth); + +static cairo_bool_t +_cairo_surface_is_xlib (cairo_surface_t *surface); + +/* + * Instead of taking two round trips for each blending request, + * assume that if a particular drawable fails GetImage that it will + * fail for a "while"; use temporary pixmaps to avoid the errors + */ + +#define CAIRO_ASSUME_PIXMAP 20 + +static Visual * +_visual_for_xrender_format(Screen *screen, + XRenderPictFormat *xrender_format) +{ + int d, v; + + /* XXX Consider searching through the list of known cairo_visual_t for + * the reverse mapping. + */ + + for (d = 0; d < screen->ndepths; d++) { + Depth *d_info = &screen->depths[d]; + + if (d_info->depth != xrender_format->depth) + continue; + + for (v = 0; v < d_info->nvisuals; v++) { + Visual *visual = &d_info->visuals[v]; + + switch (visual->class) { + case TrueColor: + if (xrender_format->type != PictTypeDirect) + continue; + break; + + case DirectColor: + /* Prefer TrueColor to DirectColor. + * (XRenderFindVisualFormat considers both TrueColor and DirectColor + * Visuals to match the same PictFormat.) + */ + continue; + + case StaticGray: + case GrayScale: + case StaticColor: + case PseudoColor: + if (xrender_format->type != PictTypeIndexed) + continue; + break; + } + + if (xrender_format == + XRenderFindVisualFormat (DisplayOfScreen(screen), visual)) + return visual; + } + } + + return NULL; +} + +static cairo_content_t +_xrender_format_to_content (XRenderPictFormat *xrender_format) +{ + cairo_content_t content; + + /* This only happens when using a non-Render server. Let's punt + * and say there's no alpha here. */ + if (xrender_format == NULL) + return CAIRO_CONTENT_COLOR; + + content = 0; + if (xrender_format->direct.alphaMask) + content |= CAIRO_CONTENT_ALPHA; + if (xrender_format->direct.redMask | + xrender_format->direct.greenMask | + xrender_format->direct.blueMask) + content |= CAIRO_CONTENT_COLOR; + + return content; +} + +static cairo_surface_t * +_cairo_xlib_surface_create_similar (void *abstract_src, + cairo_content_t content, + int width, + int height) +{ + cairo_xlib_surface_t *src = abstract_src; + XRenderPictFormat *xrender_format; + cairo_xlib_surface_t *surface; + cairo_xlib_display_t *display; + Pixmap pix; + + if (width > XLIB_COORD_MAX || height > XLIB_COORD_MAX) + return NULL; + + if (width == 0 || height == 0) + return NULL; + + if (_cairo_xlib_display_acquire (src->base.device, &display)) + return NULL; + + /* If we never found an XRenderFormat or if it isn't compatible + * with the content being requested, then we fallback to just + * constructing a cairo_format_t instead, (which will fairly + * arbitrarily pick a visual/depth for the similar surface. + */ + xrender_format = NULL; + if (src->xrender_format && + _xrender_format_to_content (src->xrender_format) == content) + { + xrender_format = src->xrender_format; + } + if (xrender_format == NULL) { + xrender_format = + _cairo_xlib_display_get_xrender_format (display, + _cairo_format_from_content (content)); + } + if (xrender_format) { + Visual *visual; + + /* We've got a compatible XRenderFormat now, which means the + * similar surface will match the existing surface as closely in + * visual/depth etc. as possible. */ + pix = XCreatePixmap (display->display, src->drawable, + width, height, xrender_format->depth); + + if (xrender_format == src->xrender_format) + visual = src->visual; + else + visual = _visual_for_xrender_format(src->screen->screen, + xrender_format); + + surface = (cairo_xlib_surface_t *) + _cairo_xlib_surface_create_internal (src->screen, pix, visual, + xrender_format, + width, height, + xrender_format->depth); + } + else + { + Screen *screen = src->screen->screen; + int depth; + + /* No compatible XRenderFormat, see if we can make an ordinary pixmap, + * so that we can still accelerate blits with XCopyArea(). */ + if (content != CAIRO_CONTENT_COLOR) { + cairo_device_release (&display->base); + return NULL; + } + + depth = DefaultDepthOfScreen (screen); + + pix = XCreatePixmap (display->display, RootWindowOfScreen (screen), + width <= 0 ? 1 : width, height <= 0 ? 1 : height, + depth); + + surface = (cairo_xlib_surface_t *) + _cairo_xlib_surface_create_internal (src->screen, pix, + DefaultVisualOfScreen (screen), + NULL, + width, height, depth); + } + + if (likely (surface->base.status == CAIRO_STATUS_SUCCESS)) + surface->owns_pixmap = TRUE; + else + XFreePixmap (display->display, pix); + + cairo_device_release (&display->base); + + return &surface->base; +} + +static void +_cairo_xlib_surface_discard_shm (cairo_xlib_surface_t *surface) +{ + if (surface->shm == NULL) + return; + + /* Force the flush for an external surface */ + if (!surface->owns_pixmap) + cairo_surface_flush (surface->shm); + + cairo_surface_finish (surface->shm); + cairo_surface_destroy (surface->shm); + surface->shm = NULL; + + _cairo_damage_destroy (surface->base.damage); + surface->base.damage = NULL; + + surface->fallback = 0; +} + +static cairo_status_t +_cairo_xlib_surface_finish (void *abstract_surface) +{ + cairo_xlib_surface_t *surface = abstract_surface; + cairo_status_t status; + cairo_xlib_display_t *display; + + cairo_list_del (&surface->link); + + status = _cairo_xlib_display_acquire (surface->base.device, &display); + if (unlikely (status)) + return status; + + X_DEBUG ((display->display, "finish (drawable=%x)", (unsigned int) surface->drawable)); + + if (surface->embedded_source.picture) + XRenderFreePicture (display->display, surface->embedded_source.picture); + if (surface->picture) + XRenderFreePicture (display->display, surface->picture); + + _cairo_xlib_surface_discard_shm (surface); + + if (surface->owns_pixmap) + XFreePixmap (display->display, surface->drawable); + + cairo_device_release (&display->base); + + return status; +} + +cairo_status_t +_cairo_xlib_surface_get_gc (cairo_xlib_display_t *display, + cairo_xlib_surface_t *surface, + GC *gc) +{ + *gc = _cairo_xlib_screen_get_gc (display, + surface->screen, + surface->depth, + surface->drawable); + if (unlikely (*gc == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + return CAIRO_STATUS_SUCCESS; +} + +static int +_noop_error_handler (Display *display, + XErrorEvent *event) +{ + return False; /* return value is ignored */ +} + +static void +_swap_ximage_2bytes (XImage *ximage) +{ + int i, j; + char *line = ximage->data; + + for (j = ximage->height; j; j--) { + uint16_t *p = (uint16_t *) line; + for (i = ximage->width; i; i--) { + *p = bswap_16 (*p); + p++; + } + + line += ximage->bytes_per_line; + } +} + +static void +_swap_ximage_3bytes (XImage *ximage) +{ + int i, j; + char *line = ximage->data; + + for (j = ximage->height; j; j--) { + uint8_t *p = (uint8_t *) line; + for (i = ximage->width; i; i--) { + uint8_t tmp; + tmp = p[2]; + p[2] = p[0]; + p[0] = tmp; + p += 3; + } + + line += ximage->bytes_per_line; + } +} + +static void +_swap_ximage_4bytes (XImage *ximage) +{ + int i, j; + char *line = ximage->data; + + for (j = ximage->height; j; j--) { + uint32_t *p = (uint32_t *) line; + for (i = ximage->width; i; i--) { + *p = bswap_32 (*p); + p++; + } + + line += ximage->bytes_per_line; + } +} + +static void +_swap_ximage_nibbles (XImage *ximage) +{ + int i, j; + char *line = ximage->data; + + for (j = ximage->height; j; j--) { + uint8_t *p = (uint8_t *) line; + for (i = (ximage->width + 1) / 2; i; i--) { + *p = ((*p >> 4) & 0xf) | ((*p << 4) & ~0xf); + p++; + } + + line += ximage->bytes_per_line; + } +} + +static void +_swap_ximage_bits (XImage *ximage) +{ + int i, j; + char *line = ximage->data; + int unit = ximage->bitmap_unit; + int line_bytes = ((ximage->width + unit - 1) & ~(unit - 1)) / 8; + + for (j = ximage->height; j; j--) { + char *p = line; + + for (i = line_bytes; i; i--) { + char b = *p; + b = ((b << 1) & 0xaa) | ((b >> 1) & 0x55); + b = ((b << 2) & 0xcc) | ((b >> 2) & 0x33); + b = ((b << 4) & 0xf0) | ((b >> 4) & 0x0f); + *p = b; + + p++; + } + + line += ximage->bytes_per_line; + } +} + +static void +_swap_ximage_to_native (XImage *ximage) +{ + int unit_bytes = 0; + int native_byte_order = _cairo_is_little_endian () ? LSBFirst : MSBFirst; + + if (ximage->bits_per_pixel == 1 && + ximage->bitmap_bit_order != native_byte_order) + { + _swap_ximage_bits (ximage); + if (ximage->bitmap_bit_order == ximage->byte_order) + return; + } + + if (ximage->byte_order == native_byte_order) + return; + + switch (ximage->bits_per_pixel) { + case 1: + unit_bytes = ximage->bitmap_unit / 8; + break; + case 4: + _swap_ximage_nibbles (ximage); + /* fall-through */ + case 8: + case 16: + case 20: + case 24: + case 28: + case 30: + case 32: + unit_bytes = (ximage->bits_per_pixel + 7) / 8; + break; + default: + /* This could be hit on some rare but possible cases. */ + ASSERT_NOT_REACHED; + } + + switch (unit_bytes) { + case 1: + break; + case 2: + _swap_ximage_2bytes (ximage); + break; + case 3: + _swap_ximage_3bytes (ximage); + break; + case 4: + _swap_ximage_4bytes (ximage); + break; + default: + ASSERT_NOT_REACHED; + } +} + + +/* Given a mask, (with a single sequence of contiguous 1 bits), return + * the number of 1 bits in 'width' and the number of 0 bits to its + * right in 'shift'. */ +static void +_characterize_field (uint32_t mask, int *width, int *shift) +{ + *width = _cairo_popcount (mask); + /* The final '& 31' is to force a 0 mask to result in 0 shift. */ + *shift = _cairo_popcount ((mask - 1) & ~mask) & 31; +} + +/* Convert a field of 'width' bits to 'new_width' bits with correct + * rounding. */ +static inline uint32_t +_resize_field (uint32_t field, int width, int new_width) +{ + if (width == 0) + return 0; + + if (width >= new_width) { + return field >> (width - new_width); + } else { + uint32_t result = field << (new_width - width); + + while (width < new_width) { + result |= result >> width; + width <<= 1; + } + return result; + } +} + +static inline uint32_t +_adjust_field (uint32_t field, int adjustment) +{ + return MIN (255, MAX(0, (int)field + adjustment)); +} + +/* Given a shifted field value, (described by 'width' and 'shift), + * resize it 8-bits and return that value. + * + * Note that the original field value must not have any non-field bits + * set. + */ +static inline uint32_t +_field_to_8 (uint32_t field, int width, int shift) +{ + return _resize_field (field >> shift, width, 8); +} + +static inline uint32_t +_field_to_8_undither (uint32_t field, int width, int shift, + int dither_adjustment) +{ + return _adjust_field (_field_to_8 (field, width, shift), - dither_adjustment>>width); +} + +/* Given an 8-bit value, convert it to a field of 'width', shift it up + * to 'shift, and return it. */ +static inline uint32_t +_field_from_8 (uint32_t field, int width, int shift) +{ + return _resize_field (field, 8, width) << shift; +} + +static inline uint32_t +_field_from_8_dither (uint32_t field, int width, int shift, + int8_t dither_adjustment) +{ + return _field_from_8 (_adjust_field (field, dither_adjustment>>width), width, shift); +} + +static inline uint32_t +_pseudocolor_from_rgb888_dither (cairo_xlib_visual_info_t *visual_info, + uint32_t r, uint32_t g, uint32_t b, + int8_t dither_adjustment) +{ + if (r == g && g == b) { + dither_adjustment /= RAMP_SIZE; + return visual_info->gray8_to_pseudocolor[_adjust_field (r, dither_adjustment)]; + } else { + dither_adjustment = visual_info->dither8_to_cube[dither_adjustment+128]; + return visual_info->cube_to_pseudocolor[visual_info->field8_to_cube[_adjust_field (r, dither_adjustment)]] + [visual_info->field8_to_cube[_adjust_field (g, dither_adjustment)]] + [visual_info->field8_to_cube[_adjust_field (b, dither_adjustment)]]; + } +} + +static inline uint32_t +_pseudocolor_to_rgb888 (cairo_xlib_visual_info_t *visual_info, + uint32_t pixel) +{ + uint32_t r, g, b; + pixel &= 0xff; + r = visual_info->colors[pixel].r; + g = visual_info->colors[pixel].g; + b = visual_info->colors[pixel].b; + return (r << 16) | + (g << 8) | + (b ); +} + +/* should range from -128 to 127 */ +#define X 16 +static const int8_t dither_pattern[4][4] = { + {-8*X, +0*X, -6*X, +2*X}, + {+4*X, -4*X, +6*X, -2*X}, + {-5*X, +4*X, -7*X, +1*X}, + {+7*X, -1*X, +5*X, -3*X} +}; +#undef X + +static int bits_per_pixel(cairo_xlib_surface_t *surface) +{ + if (surface->depth > 16) + return 32; + else if (surface->depth > 8) + return 16; + else if (surface->depth > 1) + return 8; + else + return 1; +} + +pixman_format_code_t +_pixman_format_for_xlib_surface (cairo_xlib_surface_t *surface) +{ + cairo_format_masks_t masks; + pixman_format_code_t format; + + masks.bpp = bits_per_pixel (surface); + masks.alpha_mask = surface->a_mask; + masks.red_mask = surface->r_mask; + masks.green_mask = surface->g_mask; + masks.blue_mask = surface->b_mask; + if (! _pixman_format_from_masks (&masks, &format)) + return 0; + + return format; +} + +static cairo_surface_t * +_get_image_surface (cairo_xlib_surface_t *surface, + const cairo_rectangle_int_t *extents, + int try_shm) +{ + cairo_int_status_t status; + cairo_image_surface_t *image = NULL; + XImage *ximage; + pixman_format_code_t pixman_format; + cairo_xlib_display_t *display; + + assert (extents->x >= 0); + assert (extents->y >= 0); + assert (extents->x + extents->width <= surface->width); + assert (extents->y + extents->height <= surface->height); + + if (surface->base.is_clear || + (surface->base.serial == 0 && surface->owns_pixmap)) + { + pixman_format = _pixman_format_for_xlib_surface (surface); + if (pixman_format) + { + return _cairo_image_surface_create_with_pixman_format (NULL, + pixman_format, + extents->width, + extents->height, + 0); + } + } + + if (surface->shm) { + cairo_image_surface_t *src = (cairo_image_surface_t *) surface->shm; + cairo_surface_t *dst; + cairo_surface_pattern_t pattern; + + dst = cairo_image_surface_create (src->format, + extents->width, extents->height); + if (unlikely (dst->status)) + return dst; + + _cairo_pattern_init_for_surface (&pattern, &src->base); + cairo_matrix_init_translate (&pattern.base.matrix, + extents->x, extents->y); + status = _cairo_surface_paint (dst, CAIRO_OPERATOR_SOURCE, &pattern.base, NULL); + _cairo_pattern_fini (&pattern.base); + if (unlikely (status)) { + cairo_surface_destroy (dst); + dst = _cairo_surface_create_in_error (status); + } + + return dst; + } + + status = _cairo_xlib_display_acquire (surface->base.device, &display); + if (status) + return _cairo_surface_create_in_error (status); + + pixman_format = _pixman_format_for_xlib_surface (surface); + if (try_shm && pixman_format) { + image = (cairo_image_surface_t *) + _cairo_xlib_surface_create_shm__image (surface, pixman_format, + extents->width, extents->height); + if (image && image->base.status == CAIRO_STATUS_SUCCESS) { + cairo_xlib_error_func_t old_handler; + XImage shm_image; + Bool success; + + _cairo_xlib_shm_surface_get_ximage (&image->base, &shm_image); + + XSync (display->display, False); + old_handler = XSetErrorHandler (_noop_error_handler); + success = XShmGetImage (display->display, + surface->drawable, + &shm_image, + extents->x, extents->y, + AllPlanes); + XSetErrorHandler (old_handler); + + if (success) { + cairo_device_release (&display->base); + return &image->base; + } + + cairo_surface_destroy (&image->base); + image = NULL; + } + } + + if (surface->use_pixmap == 0) { + cairo_xlib_error_func_t old_handler; + + XSync (display->display, False); + old_handler = XSetErrorHandler (_noop_error_handler); + + ximage = XGetImage (display->display, + surface->drawable, + extents->x, extents->y, + extents->width, extents->height, + AllPlanes, ZPixmap); + + XSetErrorHandler (old_handler); + + /* If we get an error, the surface must have been a window, + * so retry with the safe code path. + */ + if (!ximage) + surface->use_pixmap = CAIRO_ASSUME_PIXMAP; + } else { + surface->use_pixmap--; + ximage = NULL; + } + + if (ximage == NULL) { + /* XGetImage from a window is dangerous because it can + * produce errors if the window is unmapped or partially + * outside the screen. We could check for errors and + * retry, but to keep things simple, we just create a + * temporary pixmap + */ + Pixmap pixmap; + GC gc; + + status = _cairo_xlib_surface_get_gc (display, surface, &gc); + if (unlikely (status)) + goto BAIL; + + pixmap = XCreatePixmap (display->display, + surface->drawable, + extents->width, extents->height, + surface->depth); + if (pixmap) { + XGCValues gcv; + + gcv.subwindow_mode = IncludeInferiors; + XChangeGC (display->display, gc, GCSubwindowMode, &gcv); + + XCopyArea (display->display, surface->drawable, pixmap, gc, + extents->x, extents->y, + extents->width, extents->height, + 0, 0); + + gcv.subwindow_mode = ClipByChildren; + XChangeGC (display->display, gc, GCSubwindowMode, &gcv); + + ximage = XGetImage (display->display, + pixmap, + 0, 0, + extents->width, extents->height, + AllPlanes, ZPixmap); + + XFreePixmap (display->display, pixmap); + } + + _cairo_xlib_surface_put_gc (display, surface, gc); + + if (ximage == NULL) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto BAIL; + } + } + + _swap_ximage_to_native (ximage); + + /* We can't use pixman to simply write to image if: + * (a) the pixels are not appropriately aligned, + * (b) pixman does not the pixel format, or + * (c) if the image is palettized and we need to convert. + */ + if (pixman_format && + ximage->bitmap_unit == 32 && ximage->bitmap_pad == 32 && + (surface->visual == NULL || surface->visual->class == TrueColor)) + { + image = (cairo_image_surface_t*) + _cairo_image_surface_create_with_pixman_format ((unsigned char *) ximage->data, + pixman_format, + ximage->width, + ximage->height, + ximage->bytes_per_line); + status = image->base.status; + if (unlikely (status)) + goto BAIL; + + /* Let the surface take ownership of the data */ + _cairo_image_surface_assume_ownership_of_data (image); + ximage->data = NULL; + } else { + /* The visual we are dealing with is not supported by the + * standard pixman formats. So we must first convert the data + * to a supported format. */ + + cairo_format_t format; + unsigned char *data; + uint32_t *row; + uint32_t in_pixel, out_pixel; + unsigned int rowstride; + uint32_t a_mask=0, r_mask=0, g_mask=0, b_mask=0; + int a_width=0, r_width=0, g_width=0, b_width=0; + int a_shift=0, r_shift=0, g_shift=0, b_shift=0; + int x, y, x0, y0, x_off, y_off; + cairo_xlib_visual_info_t *visual_info = NULL; + + if (surface->visual == NULL || surface->visual->class == TrueColor) { + cairo_bool_t has_alpha; + cairo_bool_t has_color; + + has_alpha = surface->a_mask; + has_color = (surface->r_mask || + surface->g_mask || + surface->b_mask); + + if (has_color) { + if (has_alpha) { + format = CAIRO_FORMAT_ARGB32; + } else { + format = CAIRO_FORMAT_RGB24; + } + } else { + /* XXX: Using CAIRO_FORMAT_A8 here would be more + * efficient, but would require slightly different code in + * the image conversion to put the alpha channel values + * into the right place. */ + format = CAIRO_FORMAT_ARGB32; + } + + a_mask = surface->a_mask; + r_mask = surface->r_mask; + g_mask = surface->g_mask; + b_mask = surface->b_mask; + + _characterize_field (a_mask, &a_width, &a_shift); + _characterize_field (r_mask, &r_width, &r_shift); + _characterize_field (g_mask, &g_width, &g_shift); + _characterize_field (b_mask, &b_width, &b_shift); + + } else { + format = CAIRO_FORMAT_RGB24; + + status = _cairo_xlib_screen_get_visual_info (display, + surface->screen, + surface->visual, + &visual_info); + if (unlikely (status)) + goto BAIL; + } + + image = (cairo_image_surface_t *) cairo_image_surface_create + (format, ximage->width, ximage->height); + status = image->base.status; + if (unlikely (status)) + goto BAIL; + + data = cairo_image_surface_get_data (&image->base); + rowstride = cairo_image_surface_get_stride (&image->base) >> 2; + row = (uint32_t *) data; + x0 = extents->x + surface->base.device_transform.x0; + y0 = extents->y + surface->base.device_transform.y0; + for (y = 0, y_off = y0 % ARRAY_LENGTH (dither_pattern); + y < ximage->height; + y++, y_off = (y_off+1) % ARRAY_LENGTH (dither_pattern)) { + const int8_t *dither_row = dither_pattern[y_off]; + for (x = 0, x_off = x0 % ARRAY_LENGTH (dither_pattern[0]); + x < ximage->width; + x++, x_off = (x_off+1) % ARRAY_LENGTH (dither_pattern[0])) { + int dither_adjustment = dither_row[x_off]; + + in_pixel = XGetPixel (ximage, x, y); + if (visual_info == NULL) { + out_pixel = ( + (uint32_t)_field_to_8 (in_pixel & a_mask, a_width, a_shift) << 24 | + _field_to_8_undither (in_pixel & r_mask, r_width, r_shift, dither_adjustment) << 16 | + _field_to_8_undither (in_pixel & g_mask, g_width, g_shift, dither_adjustment) << 8 | + _field_to_8_undither (in_pixel & b_mask, b_width, b_shift, dither_adjustment)); + } else { + /* Undithering pseudocolor does not look better */ + out_pixel = _pseudocolor_to_rgb888 (visual_info, in_pixel); + } + row[x] = out_pixel; + } + row += rowstride; + } + cairo_surface_mark_dirty (&image->base); + } + + BAIL: + if (ximage) + XDestroyImage (ximage); + + cairo_device_release (&display->base); + + if (unlikely (status)) { + if (image) + cairo_surface_destroy (&image->base); + return _cairo_surface_create_in_error (status); + } + + return &image->base; +} + +void +_cairo_xlib_surface_set_precision (cairo_xlib_surface_t *surface, + cairo_antialias_t antialias) +{ + cairo_xlib_display_t *display = surface->display; + int precision; + + if (display->force_precision != -1) + precision = display->force_precision; + else switch (antialias) { + default: + case CAIRO_ANTIALIAS_DEFAULT: + case CAIRO_ANTIALIAS_GRAY: + case CAIRO_ANTIALIAS_NONE: + case CAIRO_ANTIALIAS_FAST: + case CAIRO_ANTIALIAS_GOOD: + precision = PolyModeImprecise; + break; + case CAIRO_ANTIALIAS_BEST: + case CAIRO_ANTIALIAS_SUBPIXEL: + precision = PolyModePrecise; + break; + } + + if (surface->precision != precision) { + XRenderPictureAttributes pa; + + pa.poly_mode = precision; + XRenderChangePicture (display->display, surface->picture, + CPPolyMode, &pa); + + surface->precision = precision; + } +} + +void +_cairo_xlib_surface_ensure_picture (cairo_xlib_surface_t *surface) +{ + cairo_xlib_display_t *display = surface->display; + XRenderPictureAttributes pa; + int mask = 0; + + if (surface->picture) + return; + + if (display->force_precision != -1) + pa.poly_mode = display->force_precision; + else + pa.poly_mode = PolyModeImprecise; + if (pa.poly_mode) + mask |= CPPolyMode; + + surface->precision = pa.poly_mode; + surface->picture = XRenderCreatePicture (display->display, + surface->drawable, + surface->xrender_format, + mask, &pa); +} + +cairo_status_t +_cairo_xlib_surface_draw_image (cairo_xlib_surface_t *surface, + cairo_image_surface_t *image, + int src_x, + int src_y, + int width, + int height, + int dst_x, + int dst_y) +{ + cairo_xlib_display_t *display; + XImage ximage; + cairo_format_masks_t image_masks; + int native_byte_order = _cairo_is_little_endian () ? LSBFirst : MSBFirst; + cairo_surface_t *shm_image = NULL; + pixman_image_t *pixman_image = NULL; + cairo_status_t status; + cairo_bool_t own_data = FALSE; + cairo_bool_t is_rgb_image; + GC gc; + + ximage.width = image->width; + ximage.height = image->height; + ximage.format = ZPixmap; + ximage.byte_order = native_byte_order; + ximage.bitmap_unit = 32; /* always for libpixman */ + ximage.bitmap_bit_order = native_byte_order; + ximage.bitmap_pad = 32; /* always for libpixman */ + ximage.depth = surface->depth; + ximage.red_mask = surface->r_mask; + ximage.green_mask = surface->g_mask; + ximage.blue_mask = surface->b_mask; + ximage.xoffset = 0; + ximage.obdata = NULL; + + status = _cairo_xlib_display_acquire (surface->base.device, &display); + if (unlikely (status)) + return status; + + is_rgb_image = _pixman_format_to_masks (image->pixman_format, &image_masks); + + if (is_rgb_image && + (image_masks.alpha_mask == surface->a_mask || surface->a_mask == 0) && + (image_masks.red_mask == surface->r_mask || surface->r_mask == 0) && + (image_masks.green_mask == surface->g_mask || surface->g_mask == 0) && + (image_masks.blue_mask == surface->b_mask || surface->b_mask == 0)) + { + int ret; + + ximage.bits_per_pixel = image_masks.bpp; + ximage.bytes_per_line = image->stride; + ximage.data = (char *)image->data; + if (image->base.device != surface->base.device) { + /* If PutImage will break the image up into chunks, prefer to + * send it all in one pass with ShmPutImage. For larger images, + * it is further advantageous to reduce the number of copies, + * albeit at the expense of more SHM bookkeeping. + */ + int max_request_size = XExtendedMaxRequestSize (display->display); + if (max_request_size == 0) + max_request_size = XMaxRequestSize (display->display); + if (max_request_size > 8192) + max_request_size = 8192; + if (width * height * 4 > max_request_size) { + shm_image = _cairo_xlib_surface_create_shm__image (surface, + image->pixman_format, + width, height); + if (shm_image && shm_image->status == CAIRO_STATUS_SUCCESS) { + cairo_image_surface_t *clone = (cairo_image_surface_t *) shm_image; + pixman_image_composite32 (PIXMAN_OP_SRC, + image->pixman_image, NULL, clone->pixman_image, + src_x, src_y, + 0, 0, + 0, 0, + width, height); + ximage.obdata = _cairo_xlib_shm_surface_get_obdata (shm_image); + ximage.data = (char *)clone->data; + ximage.bytes_per_line = clone->stride; + ximage.width = width; + ximage.height = height; + src_x = src_y = 0; + } + } + } else + ximage.obdata = _cairo_xlib_shm_surface_get_obdata (&image->base); + + ret = XInitImage (&ximage); + assert (ret != 0); + } + else if (surface->visual == NULL || surface->visual->class == TrueColor) + { + pixman_format_code_t intermediate_format; + int ret; + + image_masks.alpha_mask = surface->a_mask; + image_masks.red_mask = surface->r_mask; + image_masks.green_mask = surface->g_mask; + image_masks.blue_mask = surface->b_mask; + image_masks.bpp = bits_per_pixel (surface); + ret = _pixman_format_from_masks (&image_masks, &intermediate_format); + assert (ret); + + shm_image = _cairo_xlib_surface_create_shm__image (surface, + intermediate_format, + width, height); + if (shm_image && shm_image->status == CAIRO_STATUS_SUCCESS) { + cairo_image_surface_t *clone = (cairo_image_surface_t *) shm_image; + + pixman_image_composite32 (PIXMAN_OP_SRC, + image->pixman_image, + NULL, + clone->pixman_image, + src_x, src_y, + 0, 0, + 0, 0, + width, height); + + ximage.data = (char *) clone->data; + ximage.obdata = _cairo_xlib_shm_surface_get_obdata (&clone->base); + ximage.bytes_per_line = clone->stride; + } else { + pixman_image = pixman_image_create_bits (intermediate_format, + width, height, NULL, 0); + if (pixman_image == NULL) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto BAIL; + } + + pixman_image_composite32 (PIXMAN_OP_SRC, + image->pixman_image, + NULL, + pixman_image, + src_x, src_y, + 0, 0, + 0, 0, + width, height); + + ximage.data = (char *) pixman_image_get_data (pixman_image); + ximage.bytes_per_line = pixman_image_get_stride (pixman_image); + } + + ximage.width = width; + ximage.height = height; + ximage.bits_per_pixel = image_masks.bpp; + + ret = XInitImage (&ximage); + assert (ret != 0); + + src_x = src_y = 0; + } + else + { + unsigned int stride, rowstride; + int x, y, x0, y0, x_off, y_off; + uint32_t in_pixel, out_pixel, *row; + int i_a_width=0, i_r_width=0, i_g_width=0, i_b_width=0; + int i_a_shift=0, i_r_shift=0, i_g_shift=0, i_b_shift=0; + int o_a_width=0, o_r_width=0, o_g_width=0, o_b_width=0; + int o_a_shift=0, o_r_shift=0, o_g_shift=0, o_b_shift=0; + cairo_xlib_visual_info_t *visual_info = NULL; + cairo_bool_t true_color; + int ret; + + ximage.bits_per_pixel = bits_per_pixel(surface); + stride = CAIRO_STRIDE_FOR_WIDTH_BPP (ximage.width, + ximage.bits_per_pixel); + ximage.bytes_per_line = stride; + ximage.data = _cairo_malloc_ab (stride, ximage.height); + if (unlikely (ximage.data == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto BAIL; + } + + own_data = TRUE; + + ret = XInitImage (&ximage); + assert (ret != 0); + + _characterize_field (image_masks.alpha_mask, &i_a_width, &i_a_shift); + _characterize_field (image_masks.red_mask , &i_r_width, &i_r_shift); + _characterize_field (image_masks.green_mask, &i_g_width, &i_g_shift); + _characterize_field (image_masks.blue_mask , &i_b_width, &i_b_shift); + + true_color = surface->visual == NULL || + surface->visual->class == TrueColor; + if (true_color) { + _characterize_field (surface->a_mask, &o_a_width, &o_a_shift); + _characterize_field (surface->r_mask, &o_r_width, &o_r_shift); + _characterize_field (surface->g_mask, &o_g_width, &o_g_shift); + _characterize_field (surface->b_mask, &o_b_width, &o_b_shift); + } else { + status = _cairo_xlib_screen_get_visual_info (display, + surface->screen, + surface->visual, + &visual_info); + if (unlikely (status)) + goto BAIL; + } + + rowstride = image->stride >> 2; + row = (uint32_t *) image->data; + x0 = dst_x + surface->base.device_transform.x0; + y0 = dst_y + surface->base.device_transform.y0; + for (y = 0, y_off = y0 % ARRAY_LENGTH (dither_pattern); + y < ximage.height; + y++, y_off = (y_off+1) % ARRAY_LENGTH (dither_pattern)) + { + const int8_t *dither_row = dither_pattern[y_off]; + + for (x = 0, x_off = x0 % ARRAY_LENGTH (dither_pattern[0]); + x < ximage.width; + x++, x_off = (x_off+1) % ARRAY_LENGTH (dither_pattern[0])) + { + int dither_adjustment = dither_row[x_off]; + int a, r, g, b; + + if (image_masks.bpp == 1) + in_pixel = !! (((uint8_t*)row)[x/8] & (1 << (x & 7))); + else if (image_masks.bpp <= 8) + in_pixel = ((uint8_t*)row)[x]; + else if (image_masks.bpp <= 16) + in_pixel = ((uint16_t*)row)[x]; + else if (image_masks.bpp <= 24) +#ifdef WORDS_BIGENDIAN + in_pixel = ((uint8_t*)row)[3 * x] << 16 | + ((uint8_t*)row)[3 * x + 1] << 8 | + ((uint8_t*)row)[3 * x + 2]; +#else + in_pixel = ((uint8_t*)row)[3 * x] | + ((uint8_t*)row)[3 * x + 1] << 8 | + ((uint8_t*)row)[3 * x + 2] << 16; +#endif + else + in_pixel = row[x]; + + /* If the incoming image has no alpha channel, then the input + * is opaque and the output should have the maximum alpha value. + * For all other channels, their absence implies 0. + */ + if (image_masks.alpha_mask == 0x0) + a = 0xff; + else + a = _field_to_8 (in_pixel & image_masks.alpha_mask, i_a_width, i_a_shift); + r = _field_to_8 (in_pixel & image_masks.red_mask , i_r_width, i_r_shift); + g = _field_to_8 (in_pixel & image_masks.green_mask, i_g_width, i_g_shift); + b = _field_to_8 (in_pixel & image_masks.blue_mask , i_b_width, i_b_shift); + + if (true_color) { + out_pixel = _field_from_8 (a, o_a_width, o_a_shift) | + _field_from_8_dither (r, o_r_width, o_r_shift, dither_adjustment) | + _field_from_8_dither (g, o_g_width, o_g_shift, dither_adjustment) | + _field_from_8_dither (b, o_b_width, o_b_shift, dither_adjustment); + } else { + out_pixel = _pseudocolor_from_rgb888_dither (visual_info, r, g, b, dither_adjustment); + } + + XPutPixel (&ximage, x, y, out_pixel); + } + + row += rowstride; + } + } + + status = _cairo_xlib_surface_get_gc (display, surface, &gc); + if (unlikely (status)) + goto BAIL; + + if (ximage.obdata) + XShmPutImage (display->display, surface->drawable, gc, &ximage, + src_x, src_y, dst_x, dst_y, width, height, True); + else + XPutImage (display->display, surface->drawable, gc, &ximage, + src_x, src_y, dst_x, dst_y, width, height); + + _cairo_xlib_surface_put_gc (display, surface, gc); + + BAIL: + cairo_device_release (&display->base); + + if (own_data) + free (ximage.data); + if (shm_image) + cairo_surface_destroy (shm_image); + if (pixman_image) + pixman_image_unref (pixman_image); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_surface_t * +_cairo_xlib_surface_source(void *abstract_surface, + cairo_rectangle_int_t *extents) +{ + cairo_xlib_surface_t *surface = abstract_surface; + + if (extents) { + extents->x = extents->y = 0; + extents->width = surface->width; + extents->height = surface->height; + } + + return &surface->base; +} + +static cairo_status_t +_cairo_xlib_surface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) +{ + cairo_xlib_surface_t *surface = abstract_surface; + cairo_rectangle_int_t extents; + + *image_extra = NULL; + *image_out = (cairo_image_surface_t *) + _cairo_xlib_surface_get_shm (abstract_surface, FALSE); + if (*image_out) + return (*image_out)->base.status; + + extents.x = extents.y = 0; + extents.width = surface->width; + extents.height = surface->height; + + *image_out = (cairo_image_surface_t*) + _get_image_surface (surface, &extents, TRUE); + return (*image_out)->base.status; +} + +static cairo_surface_t * +_cairo_xlib_surface_snapshot (void *abstract_surface) +{ + cairo_xlib_surface_t *surface = abstract_surface; + cairo_rectangle_int_t extents; + + extents.x = extents.y = 0; + extents.width = surface->width; + extents.height = surface->height; + + return _get_image_surface (surface, &extents, FALSE); +} + +static void +_cairo_xlib_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image, + void *image_extra) +{ + cairo_xlib_surface_t *surface = abstract_surface; + + if (&image->base == surface->shm) + return; + + cairo_surface_destroy (&image->base); +} + +static cairo_image_surface_t * +_cairo_xlib_surface_map_to_image (void *abstract_surface, + const cairo_rectangle_int_t *extents) +{ + cairo_xlib_surface_t *surface = abstract_surface; + cairo_surface_t *image; + + image = _cairo_xlib_surface_get_shm (abstract_surface, FALSE); + if (image) { + assert (surface->base.damage); + surface->fallback++; + return _cairo_image_surface_map_to_image (image, extents); + } + + image = _get_image_surface (abstract_surface, extents, TRUE); + cairo_surface_set_device_offset (image, -extents->x, -extents->y); + + return (cairo_image_surface_t *) image; +} + +static cairo_int_status_t +_cairo_xlib_surface_unmap_image (void *abstract_surface, + cairo_image_surface_t *image) +{ + cairo_xlib_surface_t *surface = abstract_surface; + cairo_int_status_t status; + + if (surface->shm) { + cairo_rectangle_int_t r; + + assert (surface->fallback); + assert (surface->base.damage); + + r.x = image->base.device_transform_inverse.x0; + r.y = image->base.device_transform_inverse.y0; + r.width = image->width; + r.height = image->height; + + TRACE ((stderr, "%s: adding damage (%d,%d)x(%d,%d)\n", + __FUNCTION__, r.x, r.y, r.width, r.height)); + surface->shm->damage = + _cairo_damage_add_rectangle (surface->shm->damage, &r); + + return _cairo_image_surface_unmap_image (surface->shm, image); + } + + status = _cairo_xlib_surface_draw_image (abstract_surface, image, + 0, 0, + image->width, image->height, + image->base.device_transform_inverse.x0, + image->base.device_transform_inverse.y0); + + cairo_surface_finish (&image->base); + cairo_surface_destroy (&image->base); + + return status; +} + +static cairo_status_t +_cairo_xlib_surface_flush (void *abstract_surface, + unsigned flags) +{ + cairo_xlib_surface_t *surface = abstract_surface; + cairo_int_status_t status; + + if (flags) + return CAIRO_STATUS_SUCCESS; + + status = _cairo_xlib_surface_put_shm (surface); + if (unlikely (status)) + return status; + + surface->fallback >>= 1; + if (surface->shm && _cairo_xlib_shm_surface_is_idle (surface->shm)) + _cairo_xlib_surface_discard_shm (surface); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_bool_t +_cairo_xlib_surface_get_extents (void *abstract_surface, + cairo_rectangle_int_t *rectangle) +{ + cairo_xlib_surface_t *surface = abstract_surface; + + rectangle->x = 0; + rectangle->y = 0; + + rectangle->width = surface->width; + rectangle->height = surface->height; + + return TRUE; +} + +static void +_cairo_xlib_surface_get_font_options (void *abstract_surface, + cairo_font_options_t *options) +{ + cairo_xlib_surface_t *surface = abstract_surface; + + *options = *_cairo_xlib_screen_get_font_options (surface->screen); +} + +static inline cairo_int_status_t +get_compositor (cairo_xlib_surface_t **surface, + const cairo_compositor_t **compositor) +{ + cairo_xlib_surface_t *s = *surface; + cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;; + + if (s->fallback) { + assert (s->base.damage != NULL); + assert (s->shm != NULL); + assert (s->shm->damage != NULL); + if (! _cairo_xlib_shm_surface_is_active (s->shm)) { + *surface = (cairo_xlib_surface_t *) s->shm; + *compositor = ((cairo_image_surface_t *) s->shm)->compositor; + s->fallback++; + } else { + status = _cairo_xlib_surface_put_shm (s); + s->fallback = 0; + *compositor = s->compositor; + } + } else + *compositor = s->compositor; + + return status; +} + +static cairo_int_status_t +_cairo_xlib_surface_paint (void *_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip) +{ + cairo_xlib_surface_t *surface = _surface; + const cairo_compositor_t *compositor; + cairo_int_status_t status; + + status = get_compositor (&surface, &compositor); + if (unlikely (status)) + return status; + + return _cairo_compositor_paint (compositor, &surface->base, + op, source, + clip); +} + +static cairo_int_status_t +_cairo_xlib_surface_mask (void *_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_clip_t *clip) +{ + cairo_xlib_surface_t *surface = _surface; + const cairo_compositor_t *compositor; + cairo_int_status_t status; + + status = get_compositor (&surface, &compositor); + if (unlikely (status)) + return status; + + return _cairo_compositor_mask (compositor, &surface->base, + op, source, mask, + clip); +} + +static cairo_int_status_t +_cairo_xlib_surface_stroke (void *_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_xlib_surface_t *surface = _surface; + const cairo_compositor_t *compositor; + cairo_int_status_t status; + + status = get_compositor (&surface, &compositor); + if (unlikely (status)) + return status; + + return _cairo_compositor_stroke (compositor, &surface->base, + op, source, + path, style, ctm, ctm_inverse, + tolerance, antialias, + clip); +} + +static cairo_int_status_t +_cairo_xlib_surface_fill (void *_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_xlib_surface_t *surface = _surface; + const cairo_compositor_t *compositor; + cairo_int_status_t status; + + status = get_compositor (&surface, &compositor); + if (unlikely (status)) + return status; + + return _cairo_compositor_fill (compositor, &surface->base, + op, source, + path, fill_rule, tolerance, antialias, + clip); +} + +static cairo_int_status_t +_cairo_xlib_surface_glyphs (void *_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip) +{ + cairo_xlib_surface_t *surface = _surface; + const cairo_compositor_t *compositor; + cairo_int_status_t status; + + status = get_compositor (&surface, &compositor); + if (unlikely (status)) + return status; + + return _cairo_compositor_glyphs (compositor, &surface->base, + op, source, + glyphs, num_glyphs, scaled_font, + clip); +} + +static const cairo_surface_backend_t cairo_xlib_surface_backend = { + CAIRO_SURFACE_TYPE_XLIB, + _cairo_xlib_surface_finish, + + _cairo_default_context_create, + + _cairo_xlib_surface_create_similar, + _cairo_xlib_surface_create_similar_shm, + _cairo_xlib_surface_map_to_image, + _cairo_xlib_surface_unmap_image, + + _cairo_xlib_surface_source, + _cairo_xlib_surface_acquire_source_image, + _cairo_xlib_surface_release_source_image, + _cairo_xlib_surface_snapshot, + + NULL, /* copy_page */ + NULL, /* show_page */ + + _cairo_xlib_surface_get_extents, + _cairo_xlib_surface_get_font_options, + + _cairo_xlib_surface_flush, + NULL, /* mark_dirty_rectangle */ + + _cairo_xlib_surface_paint, + _cairo_xlib_surface_mask, + _cairo_xlib_surface_stroke, + _cairo_xlib_surface_fill, + NULL, /* fill-stroke */ + _cairo_xlib_surface_glyphs, +}; + +/** + * _cairo_surface_is_xlib: + * @surface: a #cairo_surface_t + * + * Checks if a surface is a #cairo_xlib_surface_t + * + * Return value: True if the surface is an xlib surface + **/ +static cairo_bool_t +_cairo_surface_is_xlib (cairo_surface_t *surface) +{ + return surface->backend == &cairo_xlib_surface_backend; +} + +static cairo_surface_t * +_cairo_xlib_surface_create_internal (cairo_xlib_screen_t *screen, + Drawable drawable, + Visual *visual, + XRenderPictFormat *xrender_format, + int width, + int height, + int depth) +{ + cairo_xlib_surface_t *surface; + cairo_xlib_display_t *display; + cairo_status_t status; + + if (depth == 0) { + if (xrender_format) { + depth = xrender_format->depth; + + /* XXX find matching visual for core/dithering fallbacks? */ + } else if (visual) { + Screen *scr = screen->screen; + + if (visual == DefaultVisualOfScreen (scr)) { + depth = DefaultDepthOfScreen (scr); + } else { + int j, k; + + /* This is ugly, but we have to walk over all visuals + * for the display to find the correct depth. + */ + depth = 0; + for (j = 0; j < scr->ndepths; j++) { + Depth *d = &scr->depths[j]; + for (k = 0; k < d->nvisuals; k++) { + if (&d->visuals[k] == visual) { + depth = d->depth; + goto found; + } + } + } + } + } + + if (depth == 0) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL)); + +found: + ; + } + + surface = _cairo_calloc (sizeof (cairo_xlib_surface_t)); + if (unlikely (surface == NULL)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + status = _cairo_xlib_display_acquire (screen->device, &display); + if (unlikely (status)) { + free (surface); + return _cairo_surface_create_in_error (_cairo_error (status)); + } + + surface->display = display; + if (CAIRO_RENDER_HAS_CREATE_PICTURE (display)) { + if (!xrender_format) { + if (visual) { + xrender_format = XRenderFindVisualFormat (display->display, visual); + } else if (depth == 1) { + xrender_format = + _cairo_xlib_display_get_xrender_format (display, + CAIRO_FORMAT_A1); + } + } + } + + cairo_device_release (&display->base); + + _cairo_surface_init (&surface->base, + &cairo_xlib_surface_backend, + screen->device, + _xrender_format_to_content (xrender_format), + FALSE); /* is_vector */ + + surface->screen = screen; + surface->compositor = display->compositor; + surface->shm = NULL; + surface->fallback = 0; + + surface->drawable = drawable; + surface->owns_pixmap = FALSE; + surface->use_pixmap = 0; + surface->width = width; + surface->height = height; + + surface->picture = None; + surface->precision = PolyModePrecise; + + surface->embedded_source.picture = None; + + surface->visual = visual; + surface->xrender_format = xrender_format; + surface->depth = depth; + + /* + * Compute the pixel format masks from either a XrenderFormat or + * else from a visual; failing that we assume the drawable is an + * alpha-only pixmap as it could only have been created that way + * through the cairo_xlib_surface_create_for_bitmap function. + */ + if (xrender_format) { + surface->a_mask = (unsigned long) + surface->xrender_format->direct.alphaMask + << surface->xrender_format->direct.alpha; + surface->r_mask = (unsigned long) + surface->xrender_format->direct.redMask + << surface->xrender_format->direct.red; + surface->g_mask = (unsigned long) + surface->xrender_format->direct.greenMask + << surface->xrender_format->direct.green; + surface->b_mask = (unsigned long) + surface->xrender_format->direct.blueMask + << surface->xrender_format->direct.blue; + } else if (visual) { + surface->a_mask = 0; + surface->r_mask = visual->red_mask; + surface->g_mask = visual->green_mask; + surface->b_mask = visual->blue_mask; + } else { + if (depth < 32) + surface->a_mask = (1 << depth) - 1; + else + surface->a_mask = 0xffffffff; + surface->r_mask = 0; + surface->g_mask = 0; + surface->b_mask = 0; + } + + cairo_list_add (&surface->link, &screen->surfaces); + + return &surface->base; +} + +static Screen * +_cairo_xlib_screen_from_visual (Display *dpy, Visual *visual) +{ + int s, d, v; + + for (s = 0; s < ScreenCount (dpy); s++) { + Screen *screen; + + screen = ScreenOfDisplay (dpy, s); + if (visual == DefaultVisualOfScreen (screen)) + return screen; + + for (d = 0; d < screen->ndepths; d++) { + Depth *depth; + + depth = &screen->depths[d]; + for (v = 0; v < depth->nvisuals; v++) + if (visual == &depth->visuals[v]) + return screen; + } + } + + return NULL; +} + +static cairo_bool_t valid_size (int width, int height) +{ + /* Note: the minimum surface size allowed in the X protocol is 1x1. + * However, as we historically did not check the minimum size we + * allowed applications to lie and set the correct size later (one hopes). + * To preserve compatibility we must allow applications to use + * 0x0 surfaces. + */ + return (width >= 0 && width <= XLIB_COORD_MAX && + height >= 0 && height <= XLIB_COORD_MAX); +} + +/** + * cairo_xlib_surface_create: + * @dpy: an X Display + * @drawable: an X Drawable, (a Pixmap or a Window) + * @visual: the visual to use for drawing to @drawable. The depth + * of the visual must match the depth of the drawable. + * Currently, only TrueColor visuals are fully supported. + * @width: the current width of @drawable. + * @height: the current height of @drawable. + * + * Creates an Xlib surface that draws to the given drawable. + * The way that colors are represented in the drawable is specified + * by the provided visual. + * + * Note: If @drawable is a Window, then the function + * cairo_xlib_surface_set_size() must be called whenever the size of the + * window changes. + * + * When @drawable is a Window containing child windows then drawing to + * the created surface will be clipped by those child windows. When + * the created surface is used as a source, the contents of the + * children will be included. + * + * Return value: the newly created surface + * + * Since: 1.0 + **/ +cairo_surface_t * +cairo_xlib_surface_create (Display *dpy, + Drawable drawable, + Visual *visual, + int width, + int height) +{ + Screen *scr; + cairo_xlib_screen_t *screen; + cairo_status_t status; + + if (! valid_size (width, height)) { + /* you're lying, and you know it! */ + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); + } + + scr = _cairo_xlib_screen_from_visual (dpy, visual); + if (scr == NULL) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL)); + + status = _cairo_xlib_screen_get (dpy, scr, &screen); + if (unlikely (status)) + return _cairo_surface_create_in_error (status); + + X_DEBUG ((dpy, "create (drawable=%x)", (unsigned int) drawable)); + + return _cairo_xlib_surface_create_internal (screen, drawable, + visual, NULL, + width, height, 0); +} + +/** + * cairo_xlib_surface_create_for_bitmap: + * @dpy: an X Display + * @bitmap: an X Drawable, (a depth-1 Pixmap) + * @screen: the X Screen associated with @bitmap + * @width: the current width of @bitmap. + * @height: the current height of @bitmap. + * + * Creates an Xlib surface that draws to the given bitmap. + * This will be drawn to as a %CAIRO_FORMAT_A1 object. + * + * Return value: the newly created surface + * + * Since: 1.0 + **/ +cairo_surface_t * +cairo_xlib_surface_create_for_bitmap (Display *dpy, + Pixmap bitmap, + Screen *scr, + int width, + int height) +{ + cairo_xlib_screen_t *screen; + cairo_status_t status; + + if (! valid_size (width, height)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); + + status = _cairo_xlib_screen_get (dpy, scr, &screen); + if (unlikely (status)) + return _cairo_surface_create_in_error (status); + + X_DEBUG ((dpy, "create_for_bitmap (drawable=%x)", (unsigned int) bitmap)); + + return _cairo_xlib_surface_create_internal (screen, bitmap, + NULL, NULL, + width, height, 1); +} + +#if CAIRO_HAS_XLIB_XRENDER_SURFACE +/** + * cairo_xlib_surface_create_with_xrender_format: + * @dpy: an X Display + * @drawable: an X Drawable, (a Pixmap or a Window) + * @screen: the X Screen associated with @drawable + * @format: the picture format to use for drawing to @drawable. The depth + * of @format must match the depth of the drawable. + * @width: the current width of @drawable. + * @height: the current height of @drawable. + * + * Creates an Xlib surface that draws to the given drawable. + * The way that colors are represented in the drawable is specified + * by the provided picture format. + * + * Note: If @drawable is a Window, then the function + * cairo_xlib_surface_set_size() must be called whenever the size of the + * window changes. + * + * Return value: the newly created surface + * + * Since: 1.0 + **/ +cairo_surface_t * +cairo_xlib_surface_create_with_xrender_format (Display *dpy, + Drawable drawable, + Screen *scr, + XRenderPictFormat *format, + int width, + int height) +{ + cairo_xlib_screen_t *screen; + cairo_status_t status; + + if (! valid_size (width, height)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); + + status = _cairo_xlib_screen_get (dpy, scr, &screen); + if (unlikely (status)) + return _cairo_surface_create_in_error (status); + + X_DEBUG ((dpy, "create_with_xrender_format (drawable=%x)", (unsigned int) drawable)); + + return _cairo_xlib_surface_create_internal (screen, drawable, + _visual_for_xrender_format (scr, format), + format, width, height, 0); +} + +/** + * cairo_xlib_surface_get_xrender_format: + * @surface: an xlib surface + * + * Gets the X Render picture format that @surface uses for rendering with the + * X Render extension. If the surface was created by + * cairo_xlib_surface_create_with_xrender_format() originally, the return + * value is the format passed to that constructor. + * + * Return value: the XRenderPictFormat* associated with @surface, + * or %NULL if the surface is not an xlib surface + * or if the X Render extension is not available. + * + * Since: 1.6 + **/ +XRenderPictFormat * +cairo_xlib_surface_get_xrender_format (cairo_surface_t *surface) +{ + cairo_xlib_surface_t *xlib_surface = (cairo_xlib_surface_t *) surface; + + /* Throw an error for a non-xlib surface */ + if (! _cairo_surface_is_xlib (surface)) { + _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + return NULL; + } + + return xlib_surface->xrender_format; +} +#endif + +/** + * cairo_xlib_surface_set_size: + * @surface: a #cairo_surface_t for the XLib backend + * @width: the new width of the surface + * @height: the new height of the surface + * + * Informs cairo of the new size of the X Drawable underlying the + * surface. For a surface created for a Window (rather than a Pixmap), + * this function must be called each time the size of the window + * changes. (For a subwindow, you are normally resizing the window + * yourself, but for a toplevel window, it is necessary to listen for + * ConfigureNotify events.) + * + * A Pixmap can never change size, so it is never necessary to call + * this function on a surface created for a Pixmap. + * + * Since: 1.0 + **/ +void +cairo_xlib_surface_set_size (cairo_surface_t *abstract_surface, + int width, + int height) +{ + cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface; + cairo_status_t status; + + if (unlikely (abstract_surface->status)) + return; + if (unlikely (abstract_surface->finished)) { + _cairo_surface_set_error (abstract_surface, + _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + return; + } + + if (! _cairo_surface_is_xlib (abstract_surface)) { + _cairo_surface_set_error (abstract_surface, + _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); + return; + } + + if (surface->width == width && surface->height == height) + return; + + if (! valid_size (width, height)) { + _cairo_surface_set_error (abstract_surface, + _cairo_error (CAIRO_STATUS_INVALID_SIZE)); + return; + } + + status = _cairo_surface_flush (abstract_surface, 0); + if (unlikely (status)) { + _cairo_surface_set_error (abstract_surface, status); + return; + } + + _cairo_xlib_surface_discard_shm (surface); + + surface->width = width; + surface->height = height; +} + +/** + * cairo_xlib_surface_set_drawable: + * @surface: a #cairo_surface_t for the XLib backend + * @drawable: the new drawable for the surface + * @width: the width of the new drawable + * @height: the height of the new drawable + * + * Informs cairo of a new X Drawable underlying the + * surface. The drawable must match the display, screen + * and format of the existing drawable or the application + * will get X protocol errors and will probably terminate. + * No checks are done by this function to ensure this + * compatibility. + * + * Since: 1.0 + **/ +void +cairo_xlib_surface_set_drawable (cairo_surface_t *abstract_surface, + Drawable drawable, + int width, + int height) +{ + cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *)abstract_surface; + cairo_status_t status; + + if (unlikely (abstract_surface->status)) + return; + if (unlikely (abstract_surface->finished)) { + status = _cairo_surface_set_error (abstract_surface, + _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + return; + } + + if (! _cairo_surface_is_xlib (abstract_surface)) { + status = _cairo_surface_set_error (abstract_surface, + _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); + return; + } + + if (! valid_size (width, height)) { + status = _cairo_surface_set_error (abstract_surface, + _cairo_error (CAIRO_STATUS_INVALID_SIZE)); + return; + } + + /* XXX: and what about this case? */ + if (surface->owns_pixmap) + return; + + status = _cairo_surface_flush (abstract_surface, 0); + if (unlikely (status)) { + _cairo_surface_set_error (abstract_surface, status); + return; + } + + if (surface->drawable != drawable) { + cairo_xlib_display_t *display; + + status = _cairo_xlib_display_acquire (surface->base.device, &display); + if (unlikely (status)) + return; + + X_DEBUG ((display->display, "set_drawable (drawable=%x)", (unsigned int) drawable)); + + if (surface->picture != None) { + XRenderFreePicture (display->display, surface->picture); + if (unlikely (status)) { + status = _cairo_surface_set_error (&surface->base, status); + return; + } + + surface->picture = None; + } + + cairo_device_release (&display->base); + + surface->drawable = drawable; + } + + if (surface->width != width || surface->height != height) { + _cairo_xlib_surface_discard_shm (surface); + + surface->width = width; + surface->height = height; + } +} + +/** + * cairo_xlib_surface_get_display: + * @surface: a #cairo_xlib_surface_t + * + * Get the X Display for the underlying X Drawable. + * + * Return value: the display. + * + * Since: 1.2 + **/ +Display * +cairo_xlib_surface_get_display (cairo_surface_t *abstract_surface) +{ + if (! _cairo_surface_is_xlib (abstract_surface)) { + _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + return NULL; + } + + return ((cairo_xlib_display_t *) abstract_surface->device)->display; +} + +/** + * cairo_xlib_surface_get_drawable: + * @surface: a #cairo_xlib_surface_t + * + * Get the underlying X Drawable used for the surface. + * + * Return value: the drawable. + * + * Since: 1.2 + **/ +Drawable +cairo_xlib_surface_get_drawable (cairo_surface_t *abstract_surface) +{ + cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface; + + if (! _cairo_surface_is_xlib (abstract_surface)) { + _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + return 0; + } + + return surface->drawable; +} + +/** + * cairo_xlib_surface_get_screen: + * @surface: a #cairo_xlib_surface_t + * + * Get the X Screen for the underlying X Drawable. + * + * Return value: the screen. + * + * Since: 1.2 + **/ +Screen * +cairo_xlib_surface_get_screen (cairo_surface_t *abstract_surface) +{ + cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface; + + if (! _cairo_surface_is_xlib (abstract_surface)) { + _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + return NULL; + } + + return surface->screen->screen; +} + +/** + * cairo_xlib_surface_get_visual: + * @surface: a #cairo_xlib_surface_t + * + * Gets the X Visual associated with @surface, suitable for use with the + * underlying X Drawable. If @surface was created by + * cairo_xlib_surface_create(), the return value is the Visual passed to that + * constructor. + * + * Return value: the Visual or %NULL if there is no appropriate Visual for + * @surface. + * + * Since: 1.2 + **/ +Visual * +cairo_xlib_surface_get_visual (cairo_surface_t *surface) +{ + cairo_xlib_surface_t *xlib_surface = (cairo_xlib_surface_t *) surface; + + if (! _cairo_surface_is_xlib (surface)) { + _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + return NULL; + } + + return xlib_surface->visual; +} + +/** + * cairo_xlib_surface_get_depth: + * @surface: a #cairo_xlib_surface_t + * + * Get the number of bits used to represent each pixel value. + * + * Return value: the depth of the surface in bits. + * + * Since: 1.2 + **/ +int +cairo_xlib_surface_get_depth (cairo_surface_t *abstract_surface) +{ + cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface; + + if (! _cairo_surface_is_xlib (abstract_surface)) { + _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + return 0; + } + + return surface->depth; +} + +/** + * cairo_xlib_surface_get_width: + * @surface: a #cairo_xlib_surface_t + * + * Get the width of the X Drawable underlying the surface in pixels. + * + * Return value: the width of the surface in pixels. + * + * Since: 1.2 + **/ +int +cairo_xlib_surface_get_width (cairo_surface_t *abstract_surface) +{ + cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface; + + if (! _cairo_surface_is_xlib (abstract_surface)) { + _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + return 0; + } + + return surface->width; +} + +/** + * cairo_xlib_surface_get_height: + * @surface: a #cairo_xlib_surface_t + * + * Get the height of the X Drawable underlying the surface in pixels. + * + * Return value: the height of the surface in pixels. + * + * Since: 1.2 + **/ +int +cairo_xlib_surface_get_height (cairo_surface_t *abstract_surface) +{ + cairo_xlib_surface_t *surface = (cairo_xlib_surface_t *) abstract_surface; + + if (! _cairo_surface_is_xlib (abstract_surface)) { + _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + return 0; + } + + return surface->height; +} + +#endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */ diff --git a/local/recipes/libs/cairo/source/src/cairo-xlib-visual.c b/local/recipes/libs/cairo/source/src/cairo-xlib-visual.c new file mode 100644 index 0000000000..055e441e4a --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-xlib-visual.c @@ -0,0 +1,194 @@ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2008 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Carl D. Worth + */ + +#include "cairoint.h" + +#if !CAIRO_HAS_XLIB_XCB_FUNCTIONS + +#include "cairo-xlib-private.h" + +#include "cairo-error-private.h" +#include "cairo-list-inline.h" + +/* A perceptual distance metric between two colors. No sqrt needed + * since the square of the distance is still a valid metric. */ + +/* XXX: This is currently using linear distance in RGB space which is + * decidedly not perceptually linear. If someone cared a lot about the + * quality, they might choose something else here. Then again, they + * might also choose not to use a PseudoColor visual... */ +static inline int +_color_distance (unsigned short r1, unsigned short g1, unsigned short b1, + unsigned short r2, unsigned short g2, unsigned short b2) +{ + r1 >>= 8; g1 >>= 8; b1 >>= 8; + r2 >>= 8; g2 >>= 8; b2 >>= 8; + + return ((r2 - r1) * (r2 - r1) + + (g2 - g1) * (g2 - g1) + + (b2 - b1) * (b2 - b1)); +} + +cairo_status_t +_cairo_xlib_visual_info_create (Display *dpy, + int screen, + VisualID visualid, + cairo_xlib_visual_info_t **out) +{ + cairo_xlib_visual_info_t *info; + Colormap colormap = DefaultColormap (dpy, screen); + XColor color; + int gray, red, green, blue; + int i, j, distance, min_distance = 0; + XColor colors[256]; + unsigned short cube_index_to_short[CUBE_SIZE]; + unsigned short ramp_index_to_short[RAMP_SIZE]; + unsigned char gray_to_pseudocolor[RAMP_SIZE]; + + for (i = 0; i < CUBE_SIZE; i++) + cube_index_to_short[i] = (0xffff * i + ((CUBE_SIZE-1)>>1)) / (CUBE_SIZE-1); + for (i = 0; i < RAMP_SIZE; i++) + ramp_index_to_short[i] = (0xffff * i + ((RAMP_SIZE-1)>>1)) / (RAMP_SIZE-1); + + info = _cairo_calloc (sizeof (cairo_xlib_visual_info_t)); + if (unlikely (info == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + cairo_list_init (&info->link); + info->visualid = visualid; + + /* Allocate a gray ramp and a color cube. + * Give up as soon as failures start. */ + + for (gray = 0; gray < RAMP_SIZE; gray++) { + color.red = color.green = color.blue = ramp_index_to_short[gray]; + if (! XAllocColor (dpy, colormap, &color)) + goto DONE_ALLOCATE; + } + + /* XXX: Could do this in a more clever order to have the best + * possible results from early failure. Could also choose a cube + * uniformly distributed in a better space than RGB. */ + for (red = 0; red < CUBE_SIZE; red++) { + for (green = 0; green < CUBE_SIZE; green++) { + for (blue = 0; blue < CUBE_SIZE; blue++) { + color.red = cube_index_to_short[red]; + color.green = cube_index_to_short[green]; + color.blue = cube_index_to_short[blue]; + color.pixel = 0; + color.flags = 0; + color.pad = 0; + if (! XAllocColor (dpy, colormap, &color)) + goto DONE_ALLOCATE; + } + } + } + DONE_ALLOCATE: + + for (i = 0; i < ARRAY_LENGTH (colors); i++) + colors[i].pixel = i; + XQueryColors (dpy, colormap, colors, ARRAY_LENGTH (colors)); + + /* Search for nearest colors within allocated colormap. */ + for (gray = 0; gray < RAMP_SIZE; gray++) { + for (i = 0; i < 256; i++) { + distance = _color_distance (ramp_index_to_short[gray], + ramp_index_to_short[gray], + ramp_index_to_short[gray], + colors[i].red, + colors[i].green, + colors[i].blue); + if (i == 0 || distance < min_distance) { + gray_to_pseudocolor[gray] = colors[i].pixel; + min_distance = distance; + if (!min_distance) + break; + } + } + } + for (red = 0; red < CUBE_SIZE; red++) { + for (green = 0; green < CUBE_SIZE; green++) { + for (blue = 0; blue < CUBE_SIZE; blue++) { + for (i = 0; i < 256; i++) { + distance = _color_distance (cube_index_to_short[red], + cube_index_to_short[green], + cube_index_to_short[blue], + colors[i].red, + colors[i].green, + colors[i].blue); + if (i == 0 || distance < min_distance) { + info->cube_to_pseudocolor[red][green][blue] = colors[i].pixel; + min_distance = distance; + if (!min_distance) + break; + } + } + } + } + } + + for (i = 0, j = 0; i < 256; i++) { + if (j < CUBE_SIZE - 1 && (((i<<8)+i) - (int)cube_index_to_short[j]) > ((int)cube_index_to_short[j+1] - ((i<<8)+i))) + j++; + info->field8_to_cube[i] = j; + + info->dither8_to_cube[i] = ((int)i - 128) / (CUBE_SIZE - 1); + } + for (i = 0, j = 0; i < 256; i++) { + if (j < RAMP_SIZE - 1 && (((i<<8)+i) - (int)ramp_index_to_short[j]) > ((int)ramp_index_to_short[j+1] - ((i<<8)+i))) + j++; + info->gray8_to_pseudocolor[i] = gray_to_pseudocolor[j]; + } + + for (i = 0; i < 256; i++) { + info->colors[i].a = 0xff; + info->colors[i].r = colors[i].red >> 8; + info->colors[i].g = colors[i].green >> 8; + info->colors[i].b = colors[i].blue >> 8; + } + + *out = info; + return CAIRO_STATUS_SUCCESS; +} + +void +_cairo_xlib_visual_info_destroy (cairo_xlib_visual_info_t *info) +{ + /* No need for XFreeColors() whilst using DefaultColormap */ + _cairo_list_del (&info->link); + free (info); +} + +#endif /* !CAIRO_HAS_XLIB_XCB_FUNCTIONS */ diff --git a/local/recipes/libs/cairo/source/src/cairo-xlib-xcb-surface.c b/local/recipes/libs/cairo/source/src/cairo-xlib-xcb-surface.c new file mode 100644 index 0000000000..4fa9f28832 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-xlib-xcb-surface.c @@ -0,0 +1,848 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2009 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Chris Wilson + */ + +#include "cairoint.h" + +#if CAIRO_HAS_XLIB_XCB_FUNCTIONS + +#include "cairo-xlib.h" +#include "cairo-xcb.h" + +#include "cairo-xcb-private.h" +#include "cairo-xlib-xrender-private.h" + +#include "cairo-default-context-private.h" +#include "cairo-list-inline.h" +#include "cairo-image-surface-private.h" +#include "cairo-surface-backend-private.h" + +#include +#include /* For XESetCloseDisplay */ + +struct cairo_xlib_xcb_display_t { + cairo_device_t base; + + Display *dpy; + cairo_device_t *xcb_device; + XExtCodes *codes; + + cairo_list_t link; +}; +typedef struct cairo_xlib_xcb_display_t cairo_xlib_xcb_display_t; + +/* List of all #cairo_xlib_xcb_display_t alive, + * protected by _cairo_xlib_display_mutex */ +static cairo_list_t displays; + +static cairo_surface_t * +_cairo_xlib_xcb_surface_create (void *dpy, + void *scr, + void *visual, + void *format, + cairo_surface_t *xcb); + +static cairo_surface_t * +_cairo_xlib_xcb_surface_create_similar (void *abstract_other, + cairo_content_t content, + int width, + int height) +{ + cairo_xlib_xcb_surface_t *other = abstract_other; + cairo_surface_t *xcb; + + xcb = other->xcb->base.backend->create_similar (other->xcb, content, width, height); + if (unlikely (xcb == NULL || xcb->status)) + return xcb; + + return _cairo_xlib_xcb_surface_create (other->display, other->screen, NULL, NULL, xcb); +} + +static cairo_status_t +_cairo_xlib_xcb_surface_finish (void *abstract_surface) +{ + cairo_xlib_xcb_surface_t *surface = abstract_surface; + cairo_status_t status; + + cairo_surface_finish (&surface->xcb->base); + status = surface->xcb->base.status; + cairo_surface_destroy (&surface->xcb->base); + surface->xcb = NULL; + + return status; +} + +static cairo_surface_t * +_cairo_xlib_xcb_surface_create_similar_image (void *abstract_other, + cairo_format_t format, + int width, + int height) +{ + cairo_xlib_xcb_surface_t *surface = abstract_other; + return cairo_surface_create_similar_image (&surface->xcb->base, format, width, height); +} + +static cairo_image_surface_t * +_cairo_xlib_xcb_surface_map_to_image (void *abstract_surface, + const cairo_rectangle_int_t *extents) +{ + cairo_xlib_xcb_surface_t *surface = abstract_surface; + return _cairo_surface_map_to_image (&surface->xcb->base, extents); +} + +static cairo_int_status_t +_cairo_xlib_xcb_surface_unmap (void *abstract_surface, + cairo_image_surface_t *image) +{ + cairo_xlib_xcb_surface_t *surface = abstract_surface; + return _cairo_surface_unmap_image (&surface->xcb->base, image); +} + +static cairo_surface_t * +_cairo_xlib_xcb_surface_source (void *abstract_surface, + cairo_rectangle_int_t *extents) +{ + cairo_xlib_xcb_surface_t *surface = abstract_surface; + return _cairo_surface_get_source (&surface->xcb->base, extents); +} + +static cairo_status_t +_cairo_xlib_xcb_surface_acquire_source_image (void *abstract_surface, + cairo_image_surface_t **image_out, + void **image_extra) +{ + cairo_xlib_xcb_surface_t *surface = abstract_surface; + return _cairo_surface_acquire_source_image (&surface->xcb->base, + image_out, image_extra); +} + +static void +_cairo_xlib_xcb_surface_release_source_image (void *abstract_surface, + cairo_image_surface_t *image_out, + void *image_extra) +{ + cairo_xlib_xcb_surface_t *surface = abstract_surface; + _cairo_surface_release_source_image (&surface->xcb->base, image_out, image_extra); +} + +static cairo_bool_t +_cairo_xlib_xcb_surface_get_extents (void *abstract_surface, + cairo_rectangle_int_t *extents) +{ + cairo_xlib_xcb_surface_t *surface = abstract_surface; + return _cairo_surface_get_extents (&surface->xcb->base, extents); +} + +static void +_cairo_xlib_xcb_surface_get_font_options (void *abstract_surface, + cairo_font_options_t *options) +{ + cairo_xlib_xcb_surface_t *surface = abstract_surface; + cairo_surface_get_font_options (&surface->xcb->base, options); +} + +static cairo_int_status_t +_cairo_xlib_xcb_surface_paint (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip) +{ + cairo_xlib_xcb_surface_t *surface = abstract_surface; + return _cairo_surface_paint (&surface->xcb->base, op, source, clip); +} + +static cairo_int_status_t +_cairo_xlib_xcb_surface_mask (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_clip_t *clip) +{ + cairo_xlib_xcb_surface_t *surface = abstract_surface; + return _cairo_surface_mask (&surface->xcb->base, op, source, mask, clip); +} + +static cairo_int_status_t +_cairo_xlib_xcb_surface_stroke (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_xlib_xcb_surface_t *surface = abstract_surface; + return _cairo_surface_stroke (&surface->xcb->base, + op, source, path, style, ctm, ctm_inverse, + tolerance, antialias, clip); +} + +static cairo_int_status_t +_cairo_xlib_xcb_surface_fill (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_xlib_xcb_surface_t *surface = abstract_surface; + return _cairo_surface_fill (&surface->xcb->base, + op, source, path, + fill_rule, tolerance, + antialias, clip); +} + +static cairo_int_status_t +_cairo_xlib_xcb_surface_glyphs (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip) +{ + cairo_xlib_xcb_surface_t *surface = abstract_surface; + return _cairo_surface_show_text_glyphs (&surface->xcb->base, op, source, + NULL, 0, + glyphs, num_glyphs, + NULL, 0, 0, + scaled_font, clip); +} + +static cairo_status_t +_cairo_xlib_xcb_surface_flush (void *abstract_surface, unsigned flags) +{ + cairo_xlib_xcb_surface_t *surface = abstract_surface; + /* We have to call cairo_surface_flush() to make sure snapshots are detached */ + return _cairo_surface_flush (&surface->xcb->base, flags); +} + +static cairo_status_t +_cairo_xlib_xcb_surface_mark_dirty (void *abstract_surface, + int x, int y, + int width, int height) +{ + cairo_xlib_xcb_surface_t *surface = abstract_surface; + cairo_surface_mark_dirty_rectangle (&surface->xcb->base, x, y, width, height); + return cairo_surface_status (&surface->xcb->base); +} + +static const cairo_surface_backend_t _cairo_xlib_xcb_surface_backend = { + CAIRO_SURFACE_TYPE_XLIB, + _cairo_xlib_xcb_surface_finish, + + _cairo_default_context_create, /* XXX */ + + _cairo_xlib_xcb_surface_create_similar, + _cairo_xlib_xcb_surface_create_similar_image, + _cairo_xlib_xcb_surface_map_to_image, + _cairo_xlib_xcb_surface_unmap, + + _cairo_xlib_xcb_surface_source, + _cairo_xlib_xcb_surface_acquire_source_image, + _cairo_xlib_xcb_surface_release_source_image, + NULL, /* snapshot */ + + NULL, /* copy_page */ + NULL, /* show_page */ + + _cairo_xlib_xcb_surface_get_extents, + _cairo_xlib_xcb_surface_get_font_options, + + _cairo_xlib_xcb_surface_flush, + _cairo_xlib_xcb_surface_mark_dirty, + + _cairo_xlib_xcb_surface_paint, + _cairo_xlib_xcb_surface_mask, + _cairo_xlib_xcb_surface_stroke, + _cairo_xlib_xcb_surface_fill, + NULL, /* fill_stroke */ + _cairo_xlib_xcb_surface_glyphs, +}; + +static void +_cairo_xlib_xcb_display_finish (void *abstract_display) +{ + cairo_xlib_xcb_display_t *display = (cairo_xlib_xcb_display_t *) abstract_display; + + CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex); + cairo_list_del (&display->link); + CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex); + + cairo_device_destroy (display->xcb_device); + display->xcb_device = NULL; + + XESetCloseDisplay (display->dpy, display->codes->extension, NULL); + /* Drop the reference from _cairo_xlib_xcb_device_create */ + cairo_device_destroy (&display->base); +} + +static int +_cairo_xlib_xcb_close_display(Display *dpy, XExtCodes *codes) +{ + cairo_xlib_xcb_display_t *display; + + CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex); + cairo_list_foreach_entry (display, + cairo_xlib_xcb_display_t, + &displays, + link) + { + if (display->dpy == dpy) + { + /* _cairo_xlib_xcb_display_finish will lock the mutex again + * -> deadlock (This mutex isn't recursive) */ + cairo_device_reference (&display->base); + CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex); + + /* Make sure the xcb and xlib-xcb devices are finished */ + cairo_device_finish (display->xcb_device); + cairo_device_finish (&display->base); + + cairo_device_destroy (&display->base); + return 0; + } + } + CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex); + + return 0; +} + +static const cairo_device_backend_t _cairo_xlib_xcb_device_backend = { + CAIRO_DEVICE_TYPE_XLIB, + + NULL, + NULL, + + NULL, /* flush */ + _cairo_xlib_xcb_display_finish, + free, /* destroy */ +}; + +static cairo_device_t * +_cairo_xlib_xcb_device_create (Display *dpy, cairo_device_t *xcb_device) +{ + cairo_xlib_xcb_display_t *display = NULL; + cairo_device_t *device; + + if (xcb_device == NULL) + return NULL; + + CAIRO_MUTEX_INITIALIZE (); + + CAIRO_MUTEX_LOCK (_cairo_xlib_display_mutex); + if (displays.next == NULL) { + cairo_list_init (&displays); + } + + cairo_list_foreach_entry (display, + cairo_xlib_xcb_display_t, + &displays, + link) + { + if (display->dpy == dpy) { + /* Maintain MRU order. */ + if (displays.next != &display->link) + cairo_list_move (&display->link, &displays); + + /* Grab a reference for our caller */ + device = cairo_device_reference (&display->base); + assert (display->xcb_device == xcb_device); + goto unlock; + } + } + + display = _cairo_malloc (sizeof (cairo_xlib_xcb_display_t)); + if (unlikely (display == NULL)) { + device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY); + goto unlock; + } + + display->codes = XAddExtension (dpy); + if (unlikely (display->codes == NULL)) { + device = _cairo_device_create_in_error (CAIRO_STATUS_NO_MEMORY); + free (display); + goto unlock; + } + + _cairo_device_init (&display->base, &_cairo_xlib_xcb_device_backend); + + XESetCloseDisplay (dpy, display->codes->extension, _cairo_xlib_xcb_close_display); + /* Add a reference for _cairo_xlib_xcb_display_finish. This basically means + * that the device's reference count never drops to zero + * as long as our Display* is alive. We need this because there is no + * "XDelExtension" to undo XAddExtension and having lots of registered + * extensions slows down libX11. */ + cairo_device_reference (&display->base); + + display->dpy = dpy; + display->xcb_device = cairo_device_reference(xcb_device); + + cairo_list_add (&display->link, &displays); + device = &display->base; + +unlock: + CAIRO_MUTEX_UNLOCK (_cairo_xlib_display_mutex); + + return device; +} + +static cairo_surface_t * +_cairo_xlib_xcb_surface_create (void *dpy, + void *scr, + void *visual, + void *format, + cairo_surface_t *xcb) +{ + cairo_xlib_xcb_surface_t *surface; + + if (unlikely (xcb->status)) + return xcb; + + surface = _cairo_malloc (sizeof (*surface)); + if (unlikely (surface == NULL)) { + cairo_surface_destroy (xcb); + return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY); + } + + _cairo_surface_init (&surface->base, + &_cairo_xlib_xcb_surface_backend, + _cairo_xlib_xcb_device_create (dpy, xcb->device), + xcb->content, + FALSE); /* is_vector */ + + /* _cairo_surface_init() got another reference to the device, drop ours */ + cairo_device_destroy (surface->base.device); + + surface->display = dpy; + surface->screen = scr; + surface->visual = visual; + surface->format = format; + surface->xcb = (cairo_xcb_surface_t *) xcb; + + return &surface->base; +} + +static Screen * +_cairo_xlib_screen_from_visual (Display *dpy, Visual *visual) +{ + int s, d, v; + + for (s = 0; s < ScreenCount (dpy); s++) { + Screen *screen; + + screen = ScreenOfDisplay (dpy, s); + if (visual == DefaultVisualOfScreen (screen)) + return screen; + + for (d = 0; d < screen->ndepths; d++) { + Depth *depth; + + depth = &screen->depths[d]; + for (v = 0; v < depth->nvisuals; v++) + if (visual == &depth->visuals[v]) + return screen; + } + } + + return NULL; +} + +cairo_surface_t * +cairo_xlib_surface_create (Display *dpy, + Drawable drawable, + Visual *visual, + int width, + int height) +{ + Screen *scr; + xcb_visualtype_t xcb_visual; + + scr = _cairo_xlib_screen_from_visual (dpy, visual); + if (scr == NULL) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_VISUAL)); + + xcb_visual.visual_id = visual->visualid; +#if defined(__cplusplus) || defined(c_plusplus) + xcb_visual._class = visual->c_class; +#else + xcb_visual._class = visual->class; +#endif + xcb_visual.bits_per_rgb_value = visual->bits_per_rgb; + xcb_visual.colormap_entries = visual->map_entries; + xcb_visual.red_mask = visual->red_mask; + xcb_visual.green_mask = visual->green_mask; + xcb_visual.blue_mask = visual->blue_mask; + + return _cairo_xlib_xcb_surface_create (dpy, scr, visual, NULL, + cairo_xcb_surface_create (XGetXCBConnection (dpy), + drawable, + &xcb_visual, + width, height)); +} + +static xcb_screen_t * +_cairo_xcb_screen_from_root (xcb_connection_t *connection, + xcb_window_t id) +{ + xcb_screen_iterator_t s; + + s = xcb_setup_roots_iterator (xcb_get_setup (connection)); + for (; s.rem; xcb_screen_next (&s)) { + if (s.data->root == id) + return s.data; + } + + return NULL; +} + +cairo_surface_t * +cairo_xlib_surface_create_for_bitmap (Display *dpy, + Pixmap bitmap, + Screen *scr, + int width, + int height) +{ + xcb_connection_t *connection = XGetXCBConnection (dpy); + xcb_screen_t *screen = _cairo_xcb_screen_from_root (connection, (xcb_window_t) scr->root); + return _cairo_xlib_xcb_surface_create (dpy, scr, NULL, NULL, + cairo_xcb_surface_create_for_bitmap (connection, + screen, + bitmap, + width, height)); +} + +#if CAIRO_HAS_XLIB_XRENDER_SURFACE +cairo_surface_t * +cairo_xlib_surface_create_with_xrender_format (Display *dpy, + Drawable drawable, + Screen *scr, + XRenderPictFormat *format, + int width, + int height) +{ + xcb_render_pictforminfo_t xcb_format; + xcb_connection_t *connection; + xcb_screen_t *screen; + + xcb_format.id = format->id; + xcb_format.type = format->type; + xcb_format.depth = format->depth; + xcb_format.direct.red_shift = format->direct.red; + xcb_format.direct.red_mask = format->direct.redMask; + xcb_format.direct.green_shift = format->direct.green; + xcb_format.direct.green_mask = format->direct.greenMask; + xcb_format.direct.blue_shift = format->direct.blue; + xcb_format.direct.blue_mask = format->direct.blueMask; + xcb_format.direct.alpha_shift = format->direct.alpha; + xcb_format.direct.alpha_mask = format->direct.alphaMask; + xcb_format.colormap = format->colormap; + + connection = XGetXCBConnection (dpy); + screen = _cairo_xcb_screen_from_root (connection, (xcb_window_t) scr->root); + + return _cairo_xlib_xcb_surface_create (dpy, scr, NULL, format, + cairo_xcb_surface_create_with_xrender_format (connection, screen, + drawable, + &xcb_format, + width, height)); +} + +XRenderPictFormat * +cairo_xlib_surface_get_xrender_format (cairo_surface_t *surface) +{ + cairo_xlib_xcb_surface_t *xlib_surface = (cairo_xlib_xcb_surface_t *) surface; + + /* Throw an error for a non-xlib surface */ + if (surface->type != CAIRO_SURFACE_TYPE_XLIB) { + _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + return NULL; + } + + return xlib_surface->format; +} +#endif + +void +cairo_xlib_surface_set_size (cairo_surface_t *abstract_surface, + int width, + int height) +{ + cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface; + cairo_status_t status; + + if (unlikely (abstract_surface->status)) + return; + if (unlikely (abstract_surface->finished)) { + status = _cairo_surface_set_error (abstract_surface, + _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + return; + } + + if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) { + status = _cairo_surface_set_error (abstract_surface, + CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + return; + } + + cairo_xcb_surface_set_size (&surface->xcb->base, width, height); + if (unlikely (surface->xcb->base.status)) { + status = _cairo_surface_set_error (abstract_surface, + _cairo_error (surface->xcb->base.status)); + } +} + +void +cairo_xlib_surface_set_drawable (cairo_surface_t *abstract_surface, + Drawable drawable, + int width, + int height) +{ + cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *)abstract_surface; + cairo_status_t status; + + if (unlikely (abstract_surface->status)) + return; + if (unlikely (abstract_surface->finished)) { + status = _cairo_surface_set_error (abstract_surface, + _cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + return; + } + + if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) { + status = _cairo_surface_set_error (abstract_surface, + CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + return; + } + + cairo_xcb_surface_set_drawable (&surface->xcb->base, drawable, width, height); + if (unlikely (surface->xcb->base.status)) { + status = _cairo_surface_set_error (abstract_surface, + _cairo_error (surface->xcb->base.status)); + } +} + +Display * +cairo_xlib_surface_get_display (cairo_surface_t *abstract_surface) +{ + cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface; + + if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) { + _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + return NULL; + } + + return surface->display; +} + +Drawable +cairo_xlib_surface_get_drawable (cairo_surface_t *abstract_surface) +{ + cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface; + + if (unlikely (abstract_surface->finished)) { + _cairo_error_throw (CAIRO_STATUS_SURFACE_FINISHED); + return 0; + } + if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) { + _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + return 0; + } + /* This can happen when e.g. create_similar falls back to an image surface + * because we don't have the RENDER extension. */ + if (surface->xcb->base.type != CAIRO_SURFACE_TYPE_XCB) { + _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + return 0; + } + + return surface->xcb->drawable; +} + +Screen * +cairo_xlib_surface_get_screen (cairo_surface_t *abstract_surface) +{ + cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface; + + if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) { + _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + return NULL; + } + + return surface->screen; +} + +Visual * +cairo_xlib_surface_get_visual (cairo_surface_t *abstract_surface) +{ + cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface; + + if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) { + _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + return NULL; + } + + return surface->visual; +} + +int +cairo_xlib_surface_get_depth (cairo_surface_t *abstract_surface) +{ + cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface; + + if (unlikely (abstract_surface->finished)) { + _cairo_error_throw (CAIRO_STATUS_SURFACE_FINISHED); + return 0; + } + if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) { + _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + return 0; + } + /* This can happen when e.g. create_similar falls back to an image surface + * because we don't have the RENDER extension. */ + if (surface->xcb->base.type != CAIRO_SURFACE_TYPE_XCB) { + _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + return 0; + } + + return surface->xcb->depth; +} + +int +cairo_xlib_surface_get_width (cairo_surface_t *abstract_surface) +{ + cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface; + + if (unlikely (abstract_surface->finished)) { + _cairo_error_throw (CAIRO_STATUS_SURFACE_FINISHED); + return 0; + } + if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) { + _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + return 0; + } + /* This can happen when e.g. create_similar falls back to an image surface + * because we don't have the RENDER extension. */ + if (surface->xcb->base.type != CAIRO_SURFACE_TYPE_XCB) { + _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + return 0; + } + + return surface->xcb->width; +} + +int +cairo_xlib_surface_get_height (cairo_surface_t *abstract_surface) +{ + cairo_xlib_xcb_surface_t *surface = (cairo_xlib_xcb_surface_t *) abstract_surface; + + if (unlikely (abstract_surface->finished)) { + _cairo_error_throw (CAIRO_STATUS_SURFACE_FINISHED); + return 0; + } + if (surface->base.type != CAIRO_SURFACE_TYPE_XLIB) { + _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + return 0; + } + /* This can happen when e.g. create_similar falls back to an image surface + * because we don't have the RENDER extension. */ + if (surface->xcb->base.type != CAIRO_SURFACE_TYPE_XCB) { + _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + return 0; + } + + return surface->xcb->height; +} + +void +cairo_xlib_device_debug_cap_xrender_version (cairo_device_t *device, + int major, int minor) +{ + cairo_xlib_xcb_display_t *display = (cairo_xlib_xcb_display_t *) device; + + if (device == NULL || device->status) + return; + + if (device->backend->type != CAIRO_DEVICE_TYPE_XLIB) + return; + + cairo_xcb_device_debug_cap_xrender_version (display->xcb_device, + major, minor); +} + +void +cairo_xlib_device_debug_set_precision (cairo_device_t *device, + int precision) +{ + cairo_xlib_xcb_display_t *display = (cairo_xlib_xcb_display_t *) device; + + if (device == NULL || device->status) + return; + if (device->backend->type != CAIRO_DEVICE_TYPE_XLIB) { + cairo_status_t status; + + status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH); + (void) status; + return; + } + + cairo_xcb_device_debug_set_precision (display->xcb_device, precision); +} + +int +cairo_xlib_device_debug_get_precision (cairo_device_t *device) +{ + cairo_xlib_xcb_display_t *display = (cairo_xlib_xcb_display_t *) device; + + if (device == NULL || device->status) + return -1; + if (device->backend->type != CAIRO_DEVICE_TYPE_XLIB) { + cairo_status_t status; + + status = _cairo_device_set_error (device, CAIRO_STATUS_DEVICE_TYPE_MISMATCH); + (void) status; + return -1; + } + + return cairo_xcb_device_debug_get_precision (display->xcb_device); +} + +#endif /* CAIRO_HAS_XLIB_XCB_FUNCTIONS */ diff --git a/local/recipes/libs/cairo/source/src/cairo-xlib-xrender-private.h b/local/recipes/libs/cairo/source/src/cairo-xlib-xrender-private.h new file mode 100644 index 0000000000..90769467b2 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-xlib-xrender-private.h @@ -0,0 +1,1173 @@ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2007 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + */ + +#ifndef CAIRO_XLIB_XRENDER_PRIVATE_H +#define CAIRO_XLIB_XRENDER_PRIVATE_H + +#include "cairo-features.h" +#include "cairo-compiler-private.h" + +#include + +/* These prototypes are used when defining interfaces missing from the + * render headers. As it happens, it is the case that all libxrender + * functions take a pointer as first argument. */ + +__attribute__((__unused__)) static void _void_consume (void *p, ...) { } +__attribute__((__unused__)) static void * _voidp_consume (void *p, ...) { return (void *)0; } +__attribute__((__unused__)) static int _int_consume (void *p, ...) { return 0; } +__attribute__((__unused__)) static void _void_consume_free (Display *p, XID n) { } + + +#if CAIRO_HAS_XLIB_XRENDER_SURFACE + +#include "cairo-xlib-xrender.h" + +#include +#include + +/* We require Render >= 0.6. The following defines were only added in + * 0.10. Make sure they are defined. + */ + +/* Filters included in 0.10 */ +#ifndef FilterConvolution +#define FilterConvolution "convolution" +#endif + +/* Extended repeat attributes included in 0.10 */ +#ifndef RepeatNone +#define RepeatNone 0 +#define RepeatNormal 1 +#define RepeatPad 2 +#define RepeatReflect 3 +#endif + + +#ifndef PictOptBlendMinimum +/* + * Operators only available in version 0.11 + */ +#define PictOpBlendMinimum 0x30 +#define PictOpMultiply 0x30 +#define PictOpScreen 0x31 +#define PictOpOverlay 0x32 +#define PictOpDarken 0x33 +#define PictOpLighten 0x34 +#define PictOpColorDodge 0x35 +#define PictOpColorBurn 0x36 +#define PictOpHardLight 0x37 +#define PictOpSoftLight 0x38 +#define PictOpDifference 0x39 +#define PictOpExclusion 0x3a +#define PictOpHSLHue 0x3b +#define PictOpHSLSaturation 0x3c +#define PictOpHSLColor 0x3d +#define PictOpHSLLuminosity 0x3e +#define PictOpBlendMaximum 0x3e +#endif + +#if !HAVE_XRENDERCREATESOLIDFILL +#define XRenderCreateSolidFill _int_consume +#endif + +#if !HAVE_XRENDERCREATELINEARGRADIENT +#define XRenderCreateLinearGradient _int_consume + +typedef struct _XLinearGradient { + XPointFixed p1; + XPointFixed p2; +} XLinearGradient; +#endif + +#if !HAVE_XRENDERCREATERADIALGRADIENT +#define XRenderCreateRadialGradient _int_consume + +typedef struct _XCircle { + XFixed x; + XFixed y; + XFixed radius; +} XCircle; +typedef struct _XRadialGradient { + XCircle inner; + XCircle outer; +} XRadialGradient; +#endif + +#if !HAVE_XRENDERCREATECONICALGRADIENT +#define XRenderCreateConicalGradient _int_consume + +typedef struct _XConicalGradient { + XPointFixed center; + XFixed angle; /* in degrees */ +} XConicalGradient; +#endif + + +#else /* !CAIRO_HAS_XLIB_XRENDER_SURFACE */ + +/* Provide dummy symbols and macros to get it compile and take the fallback + * route, just like as if Xrender is not available in the server at run-time. */ + + +/* Functions */ + +#define XRenderQueryExtension _int_consume +#define XRenderQueryVersion _int_consume +#define XRenderQueryFormats _int_consume +#define XRenderQuerySubpixelOrder _int_consume +#define XRenderSetSubpixelOrder _int_consume +#define XRenderFindVisualFormat _voidp_consume +#define XRenderFindFormat _voidp_consume +#define XRenderFindStandardFormat _voidp_consume +#define XRenderQueryPictIndexValues _voidp_consume +#define XRenderCreatePicture _int_consume +#define XRenderChangePicture _void_consume +#define XRenderSetPictureClipRectangles _void_consume +#define XRenderSetPictureClipRegion _void_consume +#define XRenderSetPictureTransform _void_consume +#define XRenderFreePicture _void_consume_free +#define XRenderComposite _void_consume +#define XRenderCreateGlyphSet _int_consume +#define XRenderReferenceGlyphSet _int_consume +#define XRenderFreeGlyphSet _void_consume_free +#define XRenderAddGlyphs _void_consume +#define XRenderFreeGlyphs _void_consume +#define XRenderCompositeString8 _void_consume +#define XRenderCompositeString16 _void_consume +#define XRenderCompositeString32 _void_consume +#define XRenderCompositeText8 (cairo_xrender_composite_text_func_t) _void_consume +#define XRenderCompositeText16 _void_consume +#define XRenderCompositeText32 _void_consume +#define XRenderFillRectangle _void_consume +#define XRenderFillRectangles _void_consume +#define XRenderCompositeTrapezoids _void_consume +#define XRenderCompositeTriangles _void_consume +#define XRenderCompositeTriStrip _void_consume +#define XRenderCompositeTriFan _void_consume +#define XRenderCompositeDoublePoly _void_consume +#define XRenderParseColor _int_consume +#define XRenderCreateCursor _int_consume +#define XRenderQueryFilters _voidp_consume +#define XRenderSetPictureFilter _void_consume +#define XRenderCreateAnimCursor _int_consume +#define XRenderAddTraps _void_consume +#define XRenderCreateSolidFill _int_consume +#define XRenderCreateLinearGradient _int_consume +#define XRenderCreateRadialGradient _int_consume +#define XRenderCreateConicalGradient _int_consume + +#define cairo_xlib_surface_create_with_xrender_format _voidp_consume + + + +/* The rest of this file is copied from various Xrender header files, with + * the following copyright/license information: + * + * Copyright © 2000 SuSE, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of SuSE not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. SuSE makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE + * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Keith Packard, SuSE, Inc. + */ + + +/* Copied from X11/extensions/render.h */ + +typedef unsigned long Glyph; +typedef unsigned long GlyphSet; +typedef unsigned long Picture; +typedef unsigned long PictFormat; + +#define BadPictFormat 0 +#define BadPicture 1 +#define BadPictOp 2 +#define BadGlyphSet 3 +#define BadGlyph 4 +#define RenderNumberErrors (BadGlyph+1) + +#define PictTypeIndexed 0 +#define PictTypeDirect 1 + +#define PictOpMinimum 0 +#define PictOpClear 0 +#define PictOpSrc 1 +#define PictOpDst 2 +#define PictOpOver 3 +#define PictOpOverReverse 4 +#define PictOpIn 5 +#define PictOpInReverse 6 +#define PictOpOut 7 +#define PictOpOutReverse 8 +#define PictOpAtop 9 +#define PictOpAtopReverse 10 +#define PictOpXor 11 +#define PictOpAdd 12 +#define PictOpSaturate 13 +#define PictOpMaximum 13 + +/* + * Operators only available in version 0.2 + */ +#define PictOpDisjointMinimum 0x10 +#define PictOpDisjointClear 0x10 +#define PictOpDisjointSrc 0x11 +#define PictOpDisjointDst 0x12 +#define PictOpDisjointOver 0x13 +#define PictOpDisjointOverReverse 0x14 +#define PictOpDisjointIn 0x15 +#define PictOpDisjointInReverse 0x16 +#define PictOpDisjointOut 0x17 +#define PictOpDisjointOutReverse 0x18 +#define PictOpDisjointAtop 0x19 +#define PictOpDisjointAtopReverse 0x1a +#define PictOpDisjointXor 0x1b +#define PictOpDisjointMaximum 0x1b + +#define PictOpConjointMinimum 0x20 +#define PictOpConjointClear 0x20 +#define PictOpConjointSrc 0x21 +#define PictOpConjointDst 0x22 +#define PictOpConjointOver 0x23 +#define PictOpConjointOverReverse 0x24 +#define PictOpConjointIn 0x25 +#define PictOpConjointInReverse 0x26 +#define PictOpConjointOut 0x27 +#define PictOpConjointOutReverse 0x28 +#define PictOpConjointAtop 0x29 +#define PictOpConjointAtopReverse 0x2a +#define PictOpConjointXor 0x2b +#define PictOpConjointMaximum 0x2b + +/* + * Operators only available in version 0.11 + */ +#define PictOpBlendMinimum 0x30 +#define PictOpMultiply 0x30 +#define PictOpScreen 0x31 +#define PictOpOverlay 0x32 +#define PictOpDarken 0x33 +#define PictOpLighten 0x34 +#define PictOpColorDodge 0x35 +#define PictOpColorBurn 0x36 +#define PictOpHardLight 0x37 +#define PictOpSoftLight 0x38 +#define PictOpDifference 0x39 +#define PictOpExclusion 0x3a +#define PictOpHSLHue 0x3b +#define PictOpHSLSaturation 0x3c +#define PictOpHSLColor 0x3d +#define PictOpHSLLuminosity 0x3e +#define PictOpBlendMaximum 0x3e + +#define PolyEdgeSharp 0 +#define PolyEdgeSmooth 1 + +#define PolyModePrecise 0 +#define PolyModeImprecise 1 + +#define CPRepeat (1 << 0) +#define CPAlphaMap (1 << 1) +#define CPAlphaXOrigin (1 << 2) +#define CPAlphaYOrigin (1 << 3) +#define CPClipXOrigin (1 << 4) +#define CPClipYOrigin (1 << 5) +#define CPClipMask (1 << 6) +#define CPGraphicsExposure (1 << 7) +#define CPSubwindowMode (1 << 8) +#define CPPolyEdge (1 << 9) +#define CPPolyMode (1 << 10) +#define CPDither (1 << 11) +#define CPComponentAlpha (1 << 12) +#define CPLastBit 12 + +/* Filters included in 0.6 */ +#define FilterNearest "nearest" +#define FilterBilinear "bilinear" +/* Filters included in 0.10 */ +#define FilterConvolution "convolution" + +#define FilterFast "fast" +#define FilterGood "good" +#define FilterBest "best" + +#define FilterAliasNone -1 + +/* Subpixel orders included in 0.6 */ +#define SubPixelUnknown 0 +#define SubPixelHorizontalRGB 1 +#define SubPixelHorizontalBGR 2 +#define SubPixelVerticalRGB 3 +#define SubPixelVerticalBGR 4 +#define SubPixelNone 5 + +/* Extended repeat attributes included in 0.10 */ +#define RepeatNone 0 +#define RepeatNormal 1 +#define RepeatPad 2 +#define RepeatReflect 3 + + + +/* Copied from X11/extensions/Xrender.h */ + +typedef struct { + short red; + short redMask; + short green; + short greenMask; + short blue; + short blueMask; + short alpha; + short alphaMask; +} XRenderDirectFormat; + +typedef struct { + PictFormat id; + int type; + int depth; + XRenderDirectFormat direct; + Colormap colormap; +} XRenderPictFormat; + +#define PictFormatID (1 << 0) +#define PictFormatType (1 << 1) +#define PictFormatDepth (1 << 2) +#define PictFormatRed (1 << 3) +#define PictFormatRedMask (1 << 4) +#define PictFormatGreen (1 << 5) +#define PictFormatGreenMask (1 << 6) +#define PictFormatBlue (1 << 7) +#define PictFormatBlueMask (1 << 8) +#define PictFormatAlpha (1 << 9) +#define PictFormatAlphaMask (1 << 10) +#define PictFormatColormap (1 << 11) + +typedef struct _XRenderPictureAttributes { + int repeat; + Picture alpha_map; + int alpha_x_origin; + int alpha_y_origin; + int clip_x_origin; + int clip_y_origin; + Pixmap clip_mask; + Bool graphics_exposures; + int subwindow_mode; + int poly_edge; + int poly_mode; + Atom dither; + Bool component_alpha; +} XRenderPictureAttributes; + +typedef struct { + unsigned short red; + unsigned short green; + unsigned short blue; + unsigned short alpha; +} XRenderColor; + +typedef struct _XGlyphInfo { + unsigned short width; + unsigned short height; + short x; + short y; + short xOff; + short yOff; +} XGlyphInfo; + +typedef struct _XGlyphElt8 { + GlyphSet glyphset; + _Xconst char *chars; + int nchars; + int xOff; + int yOff; +} XGlyphElt8; + +typedef struct _XGlyphElt16 { + GlyphSet glyphset; + _Xconst unsigned short *chars; + int nchars; + int xOff; + int yOff; +} XGlyphElt16; + +typedef struct _XGlyphElt32 { + GlyphSet glyphset; + _Xconst unsigned int *chars; + int nchars; + int xOff; + int yOff; +} XGlyphElt32; + +typedef double XDouble; + +typedef struct _XPointDouble { + XDouble x, y; +} XPointDouble; + +#define XDoubleToFixed(f) ((XFixed) ((f) * 65536)) +#define XFixedToDouble(f) (((XDouble) (f)) / 65536) + +typedef int XFixed; + +typedef struct _XPointFixed { + XFixed x, y; +} XPointFixed; + +typedef struct _XLineFixed { + XPointFixed p1, p2; +} XLineFixed; + +typedef struct _XTriangle { + XPointFixed p1, p2, p3; +} XTriangle; + +typedef struct _XCircle { + XFixed x; + XFixed y; + XFixed radius; +} XCircle; + +typedef struct _XTrapezoid { + XFixed top, bottom; + XLineFixed left, right; +} XTrapezoid; + +typedef struct _XTransform { + XFixed matrix[3][3]; +} XTransform; + +typedef struct _XFilters { + int nfilter; + char **filter; + int nalias; + short *alias; +} XFilters; + +typedef struct _XIndexValue { + unsigned long pixel; + unsigned short red, green, blue, alpha; +} XIndexValue; + +typedef struct _XAnimCursor { + Cursor cursor; + unsigned long delay; +} XAnimCursor; + +typedef struct _XSpanFix { + XFixed left, right, y; +} XSpanFix; + +typedef struct _XTrap { + XSpanFix top, bottom; +} XTrap; + +typedef struct _XLinearGradient { + XPointFixed p1; + XPointFixed p2; +} XLinearGradient; + +typedef struct _XRadialGradient { + XCircle inner; + XCircle outer; +} XRadialGradient; + +typedef struct _XConicalGradient { + XPointFixed center; + XFixed angle; /* in degrees */ +} XConicalGradient; + +#define PictStandardARGB32 0 +#define PictStandardRGB24 1 +#define PictStandardA8 2 +#define PictStandardA4 3 +#define PictStandardA1 4 +#define PictStandardNUM 5 + + + +/* Copied from X11/extensions/renderproto.h */ + +#include + +#define Window CARD32 +#define Drawable CARD32 +#define Font CARD32 +#define Pixmap CARD32 +#define Cursor CARD32 +#define Colormap CARD32 +#define GContext CARD32 +#define Atom CARD32 +#define VisualID CARD32 +#define Time CARD32 +#define KeyCode CARD8 +#define KeySym CARD32 + +#define Picture CARD32 +#define PictFormat CARD32 +#define Fixed INT32 +#define Glyphset CARD32 +#define Glyph CARD32 + +/* + * data structures + */ + +typedef struct { + CARD16 red B16; + CARD16 redMask B16; + CARD16 green B16; + CARD16 greenMask B16; + CARD16 blue B16; + CARD16 blueMask B16; + CARD16 alpha B16; + CARD16 alphaMask B16; +} xDirectFormat; + +#define sz_xDirectFormat 16 + +typedef struct { + PictFormat id B32; + CARD8 type; + CARD8 depth; + CARD16 pad1 B16; + xDirectFormat direct; + Colormap colormap; +} xPictFormInfo; + +#define sz_xPictFormInfo 28 + +typedef struct { + VisualID visual; + PictFormat format; +} xPictVisual; + +#define sz_xPictVisual 8 + +typedef struct { + CARD8 depth; + CARD8 pad1; + CARD16 nPictVisuals B16; + CARD32 pad2 B32; +} xPictDepth; + +#define sz_xPictDepth 8 + +typedef struct { + CARD32 nDepth B32; + PictFormat fallback B32; +} xPictScreen; + +#define sz_xPictScreen 8 + +typedef struct { + CARD32 pixel B32; + CARD16 red B16; + CARD16 green B16; + CARD16 blue B16; + CARD16 alpha B16; +} xIndexValue; + +#define sz_xIndexValue 12 + +typedef struct { + CARD16 red B16; + CARD16 green B16; + CARD16 blue B16; + CARD16 alpha B16; +} xRenderColor; + +#define sz_xRenderColor 8 + +typedef struct { + Fixed x B32; + Fixed y B32; +} xPointFixed; + +#define sz_xPointFixed 8 + +typedef struct { + xPointFixed p1; + xPointFixed p2; +} xLineFixed; + +#define sz_xLineFixed 16 + +typedef struct { + xPointFixed p1, p2, p3; +} xTriangle; + +#define sz_xTriangle 24 + +typedef struct { + Fixed top B32; + Fixed bottom B32; + xLineFixed left; + xLineFixed right; +} xTrapezoid; + +#define sz_xTrapezoid 40 + +typedef struct { + CARD16 width B16; + CARD16 height B16; + INT16 x B16; + INT16 y B16; + INT16 xOff B16; + INT16 yOff B16; +} xGlyphInfo; + +#define sz_xGlyphInfo 12 + +typedef struct { + CARD8 len; + CARD8 pad1; + CARD16 pad2; + INT16 deltax; + INT16 deltay; +} xGlyphElt; + +#define sz_xGlyphElt 8 + +typedef struct { + Fixed l, r, y; +} xSpanFix; + +#define sz_xSpanFix 12 + +typedef struct { + xSpanFix top, bot; +} xTrap; + +#define sz_xTrap 24 + +/* + * requests and replies + */ +typedef struct { + CARD8 reqType; + CARD8 renderReqType; + CARD16 length B16; + CARD32 majorVersion B32; + CARD32 minorVersion B32; +} xRenderQueryVersionReq; + +#define sz_xRenderQueryVersionReq 12 + +typedef struct { + BYTE type; /* X_Reply */ + BYTE pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 majorVersion B32; + CARD32 minorVersion B32; + CARD32 pad2 B32; + CARD32 pad3 B32; + CARD32 pad4 B32; + CARD32 pad5 B32; +} xRenderQueryVersionReply; + +#define sz_xRenderQueryVersionReply 32 + +typedef struct { + CARD8 reqType; + CARD8 renderReqType; + CARD16 length B16; +} xRenderQueryPictFormatsReq; + +#define sz_xRenderQueryPictFormatsReq 4 + +typedef struct { + BYTE type; /* X_Reply */ + BYTE pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 numFormats B32; + CARD32 numScreens B32; + CARD32 numDepths B32; + CARD32 numVisuals B32; + CARD32 numSubpixel B32; /* Version 0.6 */ + CARD32 pad5 B32; +} xRenderQueryPictFormatsReply; + +#define sz_xRenderQueryPictFormatsReply 32 + +typedef struct { + CARD8 reqType; + CARD8 renderReqType; + CARD16 length B16; + PictFormat format B32; +} xRenderQueryPictIndexValuesReq; + +#define sz_xRenderQueryPictIndexValuesReq 8 + +typedef struct { + BYTE type; /* X_Reply */ + BYTE pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 numIndexValues; + CARD32 pad2 B32; + CARD32 pad3 B32; + CARD32 pad4 B32; + CARD32 pad5 B32; + CARD32 pad6 B32; +} xRenderQueryPictIndexValuesReply; + +#define sz_xRenderQueryPictIndexValuesReply 32 + +typedef struct { + CARD8 reqType; + CARD8 renderReqType; + CARD16 length B16; + Picture pid B32; + Drawable drawable B32; + PictFormat format B32; + CARD32 mask B32; +} xRenderCreatePictureReq; + +#define sz_xRenderCreatePictureReq 20 + +typedef struct { + CARD8 reqType; + CARD8 renderReqType; + CARD16 length B16; + Picture picture B32; + CARD32 mask B32; +} xRenderChangePictureReq; + +#define sz_xRenderChangePictureReq 12 + +typedef struct { + CARD8 reqType; + CARD8 renderReqType; + CARD16 length B16; + Picture picture B32; + INT16 xOrigin B16; + INT16 yOrigin B16; +} xRenderSetPictureClipRectanglesReq; + +#define sz_xRenderSetPictureClipRectanglesReq 12 + +typedef struct { + CARD8 reqType; + CARD8 renderReqType; + CARD16 length B16; + Picture picture B32; +} xRenderFreePictureReq; + +#define sz_xRenderFreePictureReq 8 + +typedef struct { + CARD8 reqType; + CARD8 renderReqType; + CARD16 length B16; + CARD8 op; + CARD8 pad1; + CARD16 pad2 B16; + Picture src B32; + Picture mask B32; + Picture dst B32; + INT16 xSrc B16; + INT16 ySrc B16; + INT16 xMask B16; + INT16 yMask B16; + INT16 xDst B16; + INT16 yDst B16; + CARD16 width B16; + CARD16 height B16; +} xRenderCompositeReq; + +#define sz_xRenderCompositeReq 36 + +typedef struct { + CARD8 reqType; + CARD8 renderReqType; + CARD16 length B16; + Picture src B32; + Picture dst B32; + CARD32 colorScale B32; + CARD32 alphaScale B32; + INT16 xSrc B16; + INT16 ySrc B16; + INT16 xDst B16; + INT16 yDst B16; + CARD16 width B16; + CARD16 height B16; +} xRenderScaleReq; + +#define sz_xRenderScaleReq 32 + +typedef struct { + CARD8 reqType; + CARD8 renderReqType; + CARD16 length B16; + CARD8 op; + CARD8 pad1; + CARD16 pad2 B16; + Picture src B32; + Picture dst B32; + PictFormat maskFormat B32; + INT16 xSrc B16; + INT16 ySrc B16; +} xRenderTrapezoidsReq; + +#define sz_xRenderTrapezoidsReq 24 + +typedef struct { + CARD8 reqType; + CARD8 renderReqType; + CARD16 length B16; + CARD8 op; + CARD8 pad1; + CARD16 pad2 B16; + Picture src B32; + Picture dst B32; + PictFormat maskFormat B32; + INT16 xSrc B16; + INT16 ySrc B16; +} xRenderTrianglesReq; + +#define sz_xRenderTrianglesReq 24 + +typedef struct { + CARD8 reqType; + CARD8 renderReqType; + CARD16 length B16; + CARD8 op; + CARD8 pad1; + CARD16 pad2 B16; + Picture src B32; + Picture dst B32; + PictFormat maskFormat B32; + INT16 xSrc B16; + INT16 ySrc B16; +} xRenderTriStripReq; + +#define sz_xRenderTriStripReq 24 + +typedef struct { + CARD8 reqType; + CARD8 renderReqType; + CARD16 length B16; + CARD8 op; + CARD8 pad1; + CARD16 pad2 B16; + Picture src B32; + Picture dst B32; + PictFormat maskFormat B32; + INT16 xSrc B16; + INT16 ySrc B16; +} xRenderTriFanReq; + +#define sz_xRenderTriFanReq 24 + +typedef struct { + CARD8 reqType; + CARD8 renderReqType; + CARD16 length B16; + Glyphset gsid B32; + PictFormat format B32; +} xRenderCreateGlyphSetReq; + +#define sz_xRenderCreateGlyphSetReq 12 + +typedef struct { + CARD8 reqType; + CARD8 renderReqType; + CARD16 length B16; + Glyphset gsid B32; + Glyphset existing B32; +} xRenderReferenceGlyphSetReq; + +#define sz_xRenderReferenceGlyphSetReq 24 + +typedef struct { + CARD8 reqType; + CARD8 renderReqType; + CARD16 length B16; + Glyphset glyphset B32; +} xRenderFreeGlyphSetReq; + +#define sz_xRenderFreeGlyphSetReq 8 + +typedef struct { + CARD8 reqType; + CARD8 renderReqType; + CARD16 length B16; + Glyphset glyphset B32; + CARD32 nglyphs; +} xRenderAddGlyphsReq; + +#define sz_xRenderAddGlyphsReq 12 + +typedef struct { + CARD8 reqType; + CARD8 renderReqType; + CARD16 length B16; + Glyphset glyphset B32; +} xRenderFreeGlyphsReq; + +#define sz_xRenderFreeGlyphsReq 8 + +typedef struct { + CARD8 reqType; + CARD8 renderReqType; + CARD16 length B16; + CARD8 op; + CARD8 pad1; + CARD16 pad2 B16; + Picture src B32; + Picture dst B32; + PictFormat maskFormat B32; + Glyphset glyphset B32; + INT16 xSrc B16; + INT16 ySrc B16; +} xRenderCompositeGlyphsReq, xRenderCompositeGlyphs8Req, +xRenderCompositeGlyphs16Req, xRenderCompositeGlyphs32Req; + +#define sz_xRenderCompositeGlyphs8Req 28 +#define sz_xRenderCompositeGlyphs16Req 28 +#define sz_xRenderCompositeGlyphs32Req 28 + +/* 0.1 and higher */ + +typedef struct { + CARD8 reqType; + CARD8 renderReqType; + CARD16 length B16; + CARD8 op; + CARD8 pad1; + CARD16 pad2 B16; + Picture dst B32; + xRenderColor color; +} xRenderFillRectanglesReq; + +#define sz_xRenderFillRectanglesReq 20 + +/* 0.5 and higher */ + +typedef struct { + CARD8 reqType; + CARD8 renderReqType; + CARD16 length B16; + Cursor cid B32; + Picture src B32; + CARD16 x B16; + CARD16 y B16; +} xRenderCreateCursorReq; + +#define sz_xRenderCreateCursorReq 16 + +/* 0.6 and higher */ + +/* + * This can't use an array because 32-bit values may be in bitfields + */ +typedef struct { + Fixed matrix11 B32; + Fixed matrix12 B32; + Fixed matrix13 B32; + Fixed matrix21 B32; + Fixed matrix22 B32; + Fixed matrix23 B32; + Fixed matrix31 B32; + Fixed matrix32 B32; + Fixed matrix33 B32; +} xRenderTransform; + +#define sz_xRenderTransform 36 + +typedef struct { + CARD8 reqType; + CARD8 renderReqType; + CARD16 length B16; + Picture picture B32; + xRenderTransform transform; +} xRenderSetPictureTransformReq; + +#define sz_xRenderSetPictureTransformReq 44 + +typedef struct { + CARD8 reqType; + CARD8 renderReqType; + CARD16 length B16; + Drawable drawable B32; +} xRenderQueryFiltersReq; + +#define sz_xRenderQueryFiltersReq 8 + +typedef struct { + BYTE type; /* X_Reply */ + BYTE pad1; + CARD16 sequenceNumber B16; + CARD32 length B32; + CARD32 numAliases B32; /* LISTofCARD16 */ + CARD32 numFilters B32; /* LISTofSTRING8 */ + CARD32 pad2 B32; + CARD32 pad3 B32; + CARD32 pad4 B32; + CARD32 pad5 B32; +} xRenderQueryFiltersReply; + +#define sz_xRenderQueryFiltersReply 32 + +typedef struct { + CARD8 reqType; + CARD8 renderReqType; + CARD16 length B16; + Picture picture B32; + CARD16 nbytes B16; /* number of bytes in name */ + CARD16 pad B16; +} xRenderSetPictureFilterReq; + +#define sz_xRenderSetPictureFilterReq 12 + +/* 0.8 and higher */ + +typedef struct { + Cursor cursor B32; + CARD32 delay B32; +} xAnimCursorElt; + +#define sz_xAnimCursorElt 8 + +typedef struct { + CARD8 reqType; + CARD8 renderReqType; + CARD16 length B16; + Cursor cid B32; +} xRenderCreateAnimCursorReq; + +#define sz_xRenderCreateAnimCursorReq 8 + +/* 0.9 and higher */ + +typedef struct { + CARD8 reqType; + CARD8 renderReqType; + CARD16 length B16; + Picture picture; + INT16 xOff B16; + INT16 yOff B16; +} xRenderAddTrapsReq; + +#define sz_xRenderAddTrapsReq 12 + +/* 0.10 and higher */ + +typedef struct { + CARD8 reqType; + CARD8 renderReqType; + CARD16 length B16; + Picture pid B32; + xRenderColor color; +} xRenderCreateSolidFillReq; + +#define sz_xRenderCreateSolidFillReq 16 + +typedef struct { + CARD8 reqType; + CARD8 renderReqType; + CARD16 length B16; + Picture pid B32; + xPointFixed p1; + xPointFixed p2; + CARD32 nStops; +} xRenderCreateLinearGradientReq; + +#define sz_xRenderCreateLinearGradientReq 28 + +typedef struct { + CARD8 reqType; + CARD8 renderReqType; + CARD16 length B16; + Picture pid B32; + xPointFixed inner; + xPointFixed outer; + Fixed inner_radius; + Fixed outer_radius; + CARD32 nStops; +} xRenderCreateRadialGradientReq; + +#define sz_xRenderCreateRadialGradientReq 36 + +typedef struct { + CARD8 reqType; + CARD8 renderReqType; + CARD16 length B16; + Picture pid B32; + xPointFixed center; + Fixed angle; /* in degrees */ + CARD32 nStops; +} xRenderCreateConicalGradientReq; + +#define sz_xRenderCreateConicalGradientReq 24 + +#undef Window +#undef Drawable +#undef Font +#undef Pixmap +#undef Cursor +#undef Colormap +#undef GContext +#undef Atom +#undef VisualID +#undef Time +#undef KeyCode +#undef KeySym + +#undef Picture +#undef PictFormat +#undef Fixed +#undef Glyphset +#undef Glyph + + +#endif /* CAIRO_HAS_XLIB_XRENDER_SURFACE */ + +#endif /* CAIRO_XLIB_XRENDER_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-xlib-xrender.h b/local/recipes/libs/cairo/source/src/cairo-xlib-xrender.h new file mode 100644 index 0000000000..b34b057de4 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-xlib-xrender.h @@ -0,0 +1,66 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + */ + +#ifndef CAIRO_XLIB_XRENDER_H +#define CAIRO_XLIB_XRENDER_H + +#include "cairo.h" + +#if CAIRO_HAS_XLIB_XRENDER_SURFACE + +#include +#include + +CAIRO_BEGIN_DECLS + +cairo_public cairo_surface_t * +cairo_xlib_surface_create_with_xrender_format (Display *dpy, + Drawable drawable, + Screen *screen, + XRenderPictFormat *format, + int width, + int height); + +cairo_public XRenderPictFormat * +cairo_xlib_surface_get_xrender_format (cairo_surface_t *surface); + +CAIRO_END_DECLS + +#else /* CAIRO_HAS_XLIB_XRENDER_SURFACE */ +# error Cairo was not compiled with support for the xlib XRender backend +#endif /* CAIRO_HAS_XLIB_XRENDER_SURFACE */ + +#endif /* CAIRO_XLIB_XRENDER_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo-xlib.h b/local/recipes/libs/cairo/source/src/cairo-xlib.h new file mode 100644 index 0000000000..ecf8d6c86b --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo-xlib.h @@ -0,0 +1,118 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + */ + +#ifndef CAIRO_XLIB_H +#define CAIRO_XLIB_H + +#include "cairo.h" + +#if CAIRO_HAS_XLIB_SURFACE + +#include + +CAIRO_BEGIN_DECLS + +cairo_public cairo_surface_t * +cairo_xlib_surface_create (Display *dpy, + Drawable drawable, + Visual *visual, + int width, + int height); + +cairo_public cairo_surface_t * +cairo_xlib_surface_create_for_bitmap (Display *dpy, + Pixmap bitmap, + Screen *screen, + int width, + int height); + +cairo_public void +cairo_xlib_surface_set_size (cairo_surface_t *surface, + int width, + int height); + +cairo_public void +cairo_xlib_surface_set_drawable (cairo_surface_t *surface, + Drawable drawable, + int width, + int height); + +cairo_public Display * +cairo_xlib_surface_get_display (cairo_surface_t *surface); + +cairo_public Drawable +cairo_xlib_surface_get_drawable (cairo_surface_t *surface); + +cairo_public Screen * +cairo_xlib_surface_get_screen (cairo_surface_t *surface); + +cairo_public Visual * +cairo_xlib_surface_get_visual (cairo_surface_t *surface); + +cairo_public int +cairo_xlib_surface_get_depth (cairo_surface_t *surface); + +cairo_public int +cairo_xlib_surface_get_width (cairo_surface_t *surface); + +cairo_public int +cairo_xlib_surface_get_height (cairo_surface_t *surface); + +/* debug interface */ + +cairo_public void +cairo_xlib_device_debug_cap_xrender_version (cairo_device_t *device, + int major_version, + int minor_version); + +/* + * @precision: -1 implies automatically choose based on antialiasing mode, + * any other value overrides and sets the corresponding PolyMode. + */ +cairo_public void +cairo_xlib_device_debug_set_precision (cairo_device_t *device, + int precision); + +cairo_public int +cairo_xlib_device_debug_get_precision (cairo_device_t *device); + +CAIRO_END_DECLS + +#else /* CAIRO_HAS_XLIB_SURFACE */ +# error Cairo was not compiled with support for the xlib backend +#endif /* CAIRO_HAS_XLIB_SURFACE */ + +#endif /* CAIRO_XLIB_H */ diff --git a/local/recipes/libs/cairo/source/src/cairo.c b/local/recipes/libs/cairo/source/src/cairo.c new file mode 100644 index 0000000000..78c60df5cf --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo.c @@ -0,0 +1,4371 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Chris Wilson + */ + +#include "cairoint.h" +#include "cairo-private.h" + +#include "cairo-backend-private.h" +#include "cairo-error-private.h" +#include "cairo-path-private.h" +#include "cairo-pattern-private.h" +#include "cairo-surface-private.h" +#include "cairo-surface-backend-private.h" + +#include + +/** + * SECTION:cairo + * @Title: cairo_t + * @Short_Description: The cairo drawing context + * @See_Also: #cairo_surface_t + * + * #cairo_t is the main object used when drawing with cairo. To + * draw with cairo, you create a #cairo_t, set the target surface, + * and drawing options for the #cairo_t, create shapes with + * functions like cairo_move_to() and cairo_line_to(), and then + * draw shapes with cairo_stroke() or cairo_fill(). + * + * #cairo_t's can be pushed to a stack via cairo_save(). + * They may then safely be changed, without losing the current state. + * Use cairo_restore() to restore to the saved state. + **/ + +/** + * SECTION:cairo-text + * @Title: text + * @Short_Description: Rendering text and glyphs + * @See_Also: #cairo_font_face_t, #cairo_scaled_font_t, cairo_text_path(), + * cairo_glyph_path() + * + * The functions with text in their name form cairo's + * toy text API. The toy API takes UTF-8 encoded + * text and is limited in its functionality to rendering simple + * left-to-right text with no advanced features. That means for example + * that most complex scripts like Hebrew, Arabic, and Indic scripts are + * out of question. No kerning or correct positioning of diacritical marks + * either. The font selection is pretty limited too and doesn't handle the + * case that the selected font does not cover the characters in the text. + * This set of functions are really that, a toy text API, for testing and + * demonstration purposes. Any serious application should avoid them. + * + * The functions with glyphs in their name form cairo's + * low-level text API. The low-level API relies on + * the user to convert text to a set of glyph indexes and positions. This + * is a very hard problem and is best handled by external libraries, like + * the pangocairo that is part of the Pango text layout and rendering library. + * Pango is available from http://www.pango.org/. + **/ + +/** + * SECTION:cairo-transforms + * @Title: Transformations + * @Short_Description: Manipulating the current transformation matrix + * @See_Also: #cairo_matrix_t + * + * The current transformation matrix, ctm, is a + * two-dimensional affine transformation that maps all coordinates and other + * drawing instruments from the user space into the + * surface's canonical coordinate system, also known as the device + * space. + **/ + +/** + * SECTION:cairo-tag + * @Title: Tags and Links + * @Short_Description: Hyperlinks and document structure + * @See_Also: #cairo_pdf_surface_t + * + * The tag functions provide the ability to specify hyperlinks and + * document logical structure on supported backends. The following tags are supported: + * * [Link][link] - Create a hyperlink + * * [Destinations][dest] - Create a hyperlink destination + * * [Document Structure Tags][doc-struct] - Create PDF Document Structure + * + * # Link Tags # {#link} + * A hyperlink is specified by enclosing the hyperlink text with the %CAIRO_TAG_LINK tag. + * + * For example: + * + * cairo_tag_begin (cr, CAIRO_TAG_LINK, "uri='https://cairographics.org'"); + * cairo_move_to (cr, 50, 50); + * cairo_show_text (cr, "This is a link to the cairo website."); + * cairo_tag_end (cr, CAIRO_TAG_LINK); + * + * + * The PDF backend uses one or more rectangles to define the clickable + * area of the link. By default cairo will use the extents of the + * drawing operations enclosed by the begin/end link tags to define the + * clickable area. In some cases, such as a link split across two + * lines, the default rectangle is undesirable. + * + * @rect: [optional] The "rect" attribute allows the application to + * specify one or more rectangles that form the clickable region. The + * value of this attribute is an array of floats. Each rectangle is + * specified by four elements in the array: x, y, width, height. The + * array size must be a multiple of four. + * + * An example of creating a link with user specified clickable region: + * + * struct text { + * const char *s; + * double x, y; + * }; + * const struct text text1 = { "This link is split", 450, 70 }; + * const struct text text2 = { "across two lines", 50, 70 }; + * cairo_text_extents_t text1_extents; + * cairo_text_extents_t text2_extents; + * char attribs[100]; + * + * cairo_text_extents (cr, text1.s, &text1_extents); + * cairo_text_extents (cr, text2.s, &text2_extents); + * sprintf (attribs, + * "rect=[%f %f %f %f %f %f %f %f] uri='https://cairographics.org'", + * text1_extents.x_bearing + text1.x, + * text1_extents.y_bearing + text1.y, + * text1_extents.width, + * text1_extents.height, + * text2_extents.x_bearing + text2.x, + * text2_extents.y_bearing + text2.y, + * text2_extents.width, + * text2_extents.height); + * + * cairo_tag_begin (cr, CAIRO_TAG_LINK, attribs); + * cairo_move_to (cr, text1.x, text1.y); + * cairo_show_text (cr, text1.s); + * cairo_move_to (cr, text2.x, text2.y); + * cairo_show_text (cr, text2.s); + * cairo_tag_end (cr, CAIRO_TAG_LINK); + * + * + * There are three types of links. Each type has its own attributes as detailed below. + * * [Internal Links][internal-link] - A link to a location in the same document + * * [URI Links][uri-link] - A link to a Uniform resource identifier + * * [File Links][file-link] - A link to a location in another document + * + * ## Internal Links ## {#internal-link} + * An internal link is a link to a location in the same document. The destination + * is specified with either: + * + * @dest: a UTF-8 string specifying the destination in the PDF file to link + * to. Destinations are created with the %CAIRO_TAG_DEST tag. + * + * or the two attributes: + * + * @page: An integer specifying the page number in the PDF file to link to. + * + * @pos: [optional] An array of two floats specifying the x,y position + * on the page. + * + * An example of the link attributes to link to a page and x,y position: + * + * "page=3 pos=[3.1 6.2]" + * + * + * ## URI Links ## {#uri-link} + * A URI link is a link to a Uniform Resource Identifier ([RFC 2396](http://tools.ietf.org/html/rfc2396)). + * + * A URI is specified with the following attribute: + * + * @uri: An ASCII string specifying the URI. + * + * An example of the link attributes to the cairo website: + * + * "uri='https://cairographics.org'" + * + * + * ## File Links ## {#file-link} + * A file link is a link a location in another PDF file. + * + * The file attribute (required) specifies the name of the PDF file: + * + * @file: File name of PDF file to link to. + * + * The position is specified by either: + * + * @dest: a UTF-8 string specifying the named destination in the PDF file. + * + * or + * + * @page: An integer specifying the page number in the PDF file. + * + * @pos: [optional] An array of two floats specifying the x,y + * position on the page. Position coordinates in external files are in PDF + * coordinates (0,0 at bottom left). + * + * An example of the link attributes to PDF file: + * + * "file='document.pdf' page=16 pos=[25 40]" + * + * + * # Destination Tags # {#dest} + * + * A destination is specified by enclosing the destination drawing + * operations with the %CAIRO_TAG_DEST tag. + * + * @name: [required] A UTF-8 string specifying the name of this destination. + * + * @x: [optional] A float specifying the x coordinate of destination + * position on this page. If not specified the default + * x coordinate is the left side of the extents of the + * operations enclosed by the %CAIRO_TAG_DEST begin/end tags. If + * no operations are enclosed, the x coordidate is 0. + * + * @y: [optional] A float specifying the y coordinate of destination + * position on this page. If not specified the default + * y coordinate is the top of the extents of the + * operations enclosed by the %CAIRO_TAG_DEST begin/end tags. If + * no operations are enclosed, the y coordidate is 0. + * + * @internal: A boolean that if true, the destination name may be + * omitted from PDF where possible. In this case, links + * refer directly to the page and position instead of via + * the named destination table. Note that if this + * destination is referenced by another PDF (see [File Links][file-link]), + * this attribute must be false. Default is false. + * + * + * /* Create a hyperlink */ + * cairo_tag_begin (cr, CAIRO_TAG_LINK, "dest='mydest' internal"); + * cairo_move_to (cr, 50, 50); + * cairo_show_text (cr, "This is a hyperlink."); + * cairo_tag_end (cr, CAIRO_TAG_LINK); + * + * /* Create a destination */ + * cairo_tag_begin (cr, CAIRO_TAG_DEST, "name='mydest'"); + * cairo_move_to (cr, 50, 250); + * cairo_show_text (cr, "This paragraph is the destination of the above link."); + * cairo_tag_end (cr, CAIRO_TAG_DEST); + * + * + * # Document Structure (PDF) # {#doc-struct} + * + * The document structure tags provide a means of specifying structural information + * such as headers, paragraphs, tables, and figures. The inclusion of structural information facilitates: + * * Extraction of text and graphics for copy and paste + * * Reflow of text and graphics in the viewer + * * Processing text eg searching and indexing + * * Conversion to other formats + * * Accessability support + * + * The list of structure types is specified in section 14.8.4 of the + * [PDF Reference](http://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/PDF32000_2008.pdf). + * + * Note the PDF "Link" structure tag is the same as the cairo %CAIRO_TAG_LINK tag. + * + * The following example creates a document structure for a document containing two section, each with + * a header and a paragraph. + * + * + * cairo_tag_begin (cr, "Document", NULL); + * + * cairo_tag_begin (cr, "Sect", NULL); + * cairo_tag_begin (cr, "H1", NULL); + * cairo_show_text (cr, "Heading 1"); + * cairo_tag_end (cr, "H1"); + * + * cairo_tag_begin (cr, "P", NULL); + * cairo_show_text (cr, "Paragraph 1"); + * cairo_tag_end (cr, "P"); + * cairo_tag_end (cr, "Sect"); + * + * cairo_tag_begin (cr, "Sect", NULL); + * cairo_tag_begin (cr, "H1", NULL); + * cairo_show_text (cr, "Heading 2"); + * cairo_tag_end (cr, "H1"); + * + * cairo_tag_begin (cr, "P", NULL); + * cairo_show_text (cr, "Paragraph 2"); + * cairo_tag_end (cr, "P"); + * cairo_tag_end (cr, "Sect"); + * + * cairo_tag_end (cr, "Document"); + * + * + **/ + +#define DEFINE_NIL_CONTEXT(status) \ + { \ + CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ \ + status, /* status */ \ + { 0, 0, 0, NULL }, /* user_data */ \ + NULL \ + } + +static const cairo_t _cairo_nil[] = { + DEFINE_NIL_CONTEXT (CAIRO_STATUS_NO_MEMORY), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_INVALID_RESTORE), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_INVALID_POP_GROUP), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_NO_CURRENT_POINT), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_INVALID_MATRIX), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_INVALID_STATUS), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_NULL_POINTER), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_INVALID_STRING), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_INVALID_PATH_DATA), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_READ_ERROR), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_WRITE_ERROR), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_SURFACE_FINISHED), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_SURFACE_TYPE_MISMATCH), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_PATTERN_TYPE_MISMATCH), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_INVALID_CONTENT), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_INVALID_FORMAT), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_INVALID_VISUAL), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_FILE_NOT_FOUND), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_INVALID_DASH), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_INVALID_DSC_COMMENT), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_INVALID_INDEX), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_TEMP_FILE_ERROR), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_INVALID_STRIDE), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_FONT_TYPE_MISMATCH), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_USER_FONT_IMMUTABLE), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_USER_FONT_ERROR), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_NEGATIVE_COUNT), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_INVALID_CLUSTERS), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_INVALID_SLANT), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_INVALID_WEIGHT), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_INVALID_SIZE), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_DEVICE_TYPE_MISMATCH), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_DEVICE_ERROR), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_INVALID_MESH_CONSTRUCTION), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_DEVICE_FINISHED), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_JBIG2_GLOBAL_MISSING), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_PNG_ERROR), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_FREETYPE_ERROR), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_WIN32_GDI_ERROR), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_TAG_ERROR), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_DWRITE_ERROR), + DEFINE_NIL_CONTEXT (CAIRO_STATUS_SVG_FONT_ERROR) +}; +COMPILE_TIME_ASSERT (ARRAY_LENGTH (_cairo_nil) == CAIRO_STATUS_LAST_STATUS - 1); + +/** + * _cairo_set_error: + * @cr: a cairo context + * @status: a status value indicating an error + * + * Atomically sets cr->status to @status and calls _cairo_error; + * Does nothing if status is %CAIRO_STATUS_SUCCESS. + * + * All assignments of an error status to cr->status should happen + * through _cairo_set_error(). Note that due to the nature of the atomic + * operation, it is not safe to call this function on the nil objects. + * + * The purpose of this function is to allow the user to set a + * breakpoint in _cairo_error() to generate a stack trace for when the + * user causes cairo to detect an error. + **/ +static void +_cairo_set_error (cairo_t *cr, cairo_status_t status) +{ + /* Don't overwrite an existing error. This preserves the first + * error, which is the most significant. */ + _cairo_status_set_error (&cr->status, _cairo_error (status)); +} + +cairo_t * +_cairo_create_in_error (cairo_status_t status) +{ + cairo_t *cr; + + assert (status != CAIRO_STATUS_SUCCESS); + + cr = (cairo_t *) &_cairo_nil[status - CAIRO_STATUS_NO_MEMORY]; + assert (status == cr->status); + + return cr; +} + +/** + * cairo_create: + * @target: target surface for the context + * + * Creates a new #cairo_t with all graphics state parameters set to + * default values and with @target as a target surface. The target + * surface should be constructed with a backend-specific function such + * as cairo_image_surface_create() (or any other + * cairo_backend_surface_create() + * variant). + * + * This function references @target, so you can immediately + * call cairo_surface_destroy() on it if you don't need to + * maintain a separate reference to it. + * + * Return value: a newly allocated #cairo_t with a reference + * count of 1. The initial reference count should be released + * with cairo_destroy() when you are done using the #cairo_t. + * This function never returns %NULL. If memory cannot be + * allocated, a special #cairo_t object will be returned on + * which cairo_status() returns %CAIRO_STATUS_NO_MEMORY. If + * you attempt to target a surface which does not support + * writing (such as #cairo_mime_surface_t) then a + * %CAIRO_STATUS_WRITE_ERROR will be raised. You can use this + * object normally, but no drawing will be done. + * + * Since: 1.0 + **/ +cairo_t * +cairo_create (cairo_surface_t *target) +{ + if (unlikely (target == NULL)) + return _cairo_create_in_error (_cairo_error (CAIRO_STATUS_NULL_POINTER)); + if (unlikely (target->status)) + return _cairo_create_in_error (target->status); + if (unlikely (target->finished)) + return _cairo_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); + + if (target->backend->create_context == NULL) + return _cairo_create_in_error (_cairo_error (CAIRO_STATUS_WRITE_ERROR)); + + return target->backend->create_context (target); + +} + +void +_cairo_init (cairo_t *cr, + const cairo_backend_t *backend) +{ + CAIRO_REFERENCE_COUNT_INIT (&cr->ref_count, 1); + cr->status = CAIRO_STATUS_SUCCESS; + _cairo_user_data_array_init (&cr->user_data); + + cr->backend = backend; +} + +/** + * cairo_reference: + * @cr: a #cairo_t + * + * Increases the reference count on @cr by one. This prevents + * @cr from being destroyed until a matching call to cairo_destroy() + * is made. + * + * Use cairo_get_reference_count() to get the number of references to + * a #cairo_t. + * + * Return value: the referenced #cairo_t. + * + * Since: 1.0 + **/ +cairo_t * +cairo_reference (cairo_t *cr) +{ + if (cr == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (&cr->ref_count)) + return cr; + + assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&cr->ref_count)); + + _cairo_reference_count_inc (&cr->ref_count); + + return cr; +} + +void +_cairo_fini (cairo_t *cr) +{ + _cairo_user_data_array_fini (&cr->user_data); +} + +/** + * cairo_destroy: + * @cr: a #cairo_t + * + * Decreases the reference count on @cr by one. If the result + * is zero, then @cr and all associated resources are freed. + * See cairo_reference(). + * + * Since: 1.0 + **/ +void +cairo_destroy (cairo_t *cr) +{ + if (cr == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (&cr->ref_count)) + return; + + assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&cr->ref_count)); + + if (! _cairo_reference_count_dec_and_test (&cr->ref_count)) + return; + + cr->backend->destroy (cr); +} + +/** + * cairo_get_user_data: + * @cr: a #cairo_t + * @key: the address of the #cairo_user_data_key_t the user data was + * attached to + * + * Return user data previously attached to @cr using the specified + * key. If no user data has been attached with the given key this + * function returns %NULL. + * + * Return value: the user data previously attached or %NULL. + * + * Since: 1.4 + **/ +void * +cairo_get_user_data (cairo_t *cr, + const cairo_user_data_key_t *key) +{ + return _cairo_user_data_array_get_data (&cr->user_data, key); +} + +/** + * cairo_set_user_data: + * @cr: a #cairo_t + * @key: the address of a #cairo_user_data_key_t to attach the user data to + * @user_data: the user data to attach to the #cairo_t + * @destroy: a #cairo_destroy_func_t which will be called when the + * #cairo_t is destroyed or when new user data is attached using the + * same key. + * + * Attach user data to @cr. To remove user data from a surface, + * call this function with the key that was used to set it and %NULL + * for @data. + * + * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a + * slot could not be allocated for the user data. + * + * Since: 1.4 + **/ +cairo_status_t +cairo_set_user_data (cairo_t *cr, + const cairo_user_data_key_t *key, + void *user_data, + cairo_destroy_func_t destroy) +{ + if (CAIRO_REFERENCE_COUNT_IS_INVALID (&cr->ref_count)) + return cr->status; + + return _cairo_user_data_array_set_data (&cr->user_data, + key, user_data, destroy); +} + +/** + * cairo_get_reference_count: + * @cr: a #cairo_t + * + * Returns the current reference count of @cr. + * + * Return value: the current reference count of @cr. If the + * object is a nil object, 0 will be returned. + * + * Since: 1.4 + **/ +unsigned int +cairo_get_reference_count (cairo_t *cr) +{ + if (cr == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (&cr->ref_count)) + return 0; + + return CAIRO_REFERENCE_COUNT_GET_VALUE (&cr->ref_count); +} + +/** + * cairo_save: + * @cr: a #cairo_t + * + * Makes a copy of the current state of @cr and saves it + * on an internal stack of saved states for @cr. When + * cairo_restore() is called, @cr will be restored to + * the saved state. Multiple calls to cairo_save() and + * cairo_restore() can be nested; each call to cairo_restore() + * restores the state from the matching paired cairo_save(). + * + * It isn't necessary to clear all saved states before + * a #cairo_t is freed. If the reference count of a #cairo_t + * drops to zero in response to a call to cairo_destroy(), + * any saved states will be freed along with the #cairo_t. + * + * Since: 1.0 + **/ +void +cairo_save (cairo_t *cr) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->save (cr); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_restore: + * @cr: a #cairo_t + * + * Restores @cr to the state saved by a preceding call to + * cairo_save() and removes that state from the stack of + * saved states. + * + * Since: 1.0 + **/ +void +cairo_restore (cairo_t *cr) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->restore (cr); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_push_group: + * @cr: a cairo context + * + * Temporarily redirects drawing to an intermediate surface known as a + * group. The redirection lasts until the group is completed by a call + * to cairo_pop_group() or cairo_pop_group_to_source(). These calls + * provide the result of any drawing to the group as a pattern, + * (either as an explicit object, or set as the source pattern). + * + * This group functionality can be convenient for performing + * intermediate compositing. One common use of a group is to render + * objects as opaque within the group, (so that they occlude each + * other), and then blend the result with translucence onto the + * destination. + * + * Groups can be nested arbitrarily deep by making balanced calls to + * cairo_push_group()/cairo_pop_group(). Each call pushes/pops the new + * target group onto/from a stack. + * + * The cairo_push_group() function calls cairo_save() so that any + * changes to the graphics state will not be visible outside the + * group, (the pop_group functions call cairo_restore()). + * + * By default the intermediate group will have a content type of + * %CAIRO_CONTENT_COLOR_ALPHA. Other content types can be chosen for + * the group by using cairo_push_group_with_content() instead. + * + * As an example, here is how one might fill and stroke a path with + * translucence, but without any portion of the fill being visible + * under the stroke: + * + * + * cairo_push_group (cr); + * cairo_set_source (cr, fill_pattern); + * cairo_fill_preserve (cr); + * cairo_set_source (cr, stroke_pattern); + * cairo_stroke (cr); + * cairo_pop_group_to_source (cr); + * cairo_paint_with_alpha (cr, alpha); + * + * + * Since: 1.2 + **/ +void +cairo_push_group (cairo_t *cr) +{ + cairo_push_group_with_content (cr, CAIRO_CONTENT_COLOR_ALPHA); +} + +/** + * cairo_push_group_with_content: + * @cr: a cairo context + * @content: a #cairo_content_t indicating the type of group that + * will be created + * + * Temporarily redirects drawing to an intermediate surface known as a + * group. The redirection lasts until the group is completed by a call + * to cairo_pop_group() or cairo_pop_group_to_source(). These calls + * provide the result of any drawing to the group as a pattern, + * (either as an explicit object, or set as the source pattern). + * + * The group will have a content type of @content. The ability to + * control this content type is the only distinction between this + * function and cairo_push_group() which you should see for a more + * detailed description of group rendering. + * + * Since: 1.2 + **/ +void +cairo_push_group_with_content (cairo_t *cr, cairo_content_t content) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->push_group (cr, content); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_pop_group: + * @cr: a cairo context + * + * Terminates the redirection begun by a call to cairo_push_group() or + * cairo_push_group_with_content() and returns a new pattern + * containing the results of all drawing operations performed to the + * group. + * + * The cairo_pop_group() function calls cairo_restore(), (balancing a + * call to cairo_save() by the push_group function), so that any + * changes to the graphics state will not be visible outside the + * group. + * + * Return value: a newly created (surface) pattern containing the + * results of all drawing operations performed to the group. The + * caller owns the returned object and should call + * cairo_pattern_destroy() when finished with it. + * + * Since: 1.2 + **/ +cairo_pattern_t * +cairo_pop_group (cairo_t *cr) +{ + cairo_pattern_t *group_pattern; + + if (unlikely (cr->status)) + return _cairo_pattern_create_in_error (cr->status); + + group_pattern = cr->backend->pop_group (cr); + if (unlikely (group_pattern->status)) + _cairo_set_error (cr, group_pattern->status); + + return group_pattern; +} + +/** + * cairo_pop_group_to_source: + * @cr: a cairo context + * + * Terminates the redirection begun by a call to cairo_push_group() or + * cairo_push_group_with_content() and installs the resulting pattern + * as the source pattern in the given cairo context. + * + * The behavior of this function is equivalent to the sequence of + * operations: + * + * + * cairo_pattern_t *group = cairo_pop_group (cr); + * cairo_set_source (cr, group); + * cairo_pattern_destroy (group); + * + * + * but is more convenient as their is no need for a variable to store + * the short-lived pointer to the pattern. + * + * The cairo_pop_group() function calls cairo_restore(), (balancing a + * call to cairo_save() by the push_group function), so that any + * changes to the graphics state will not be visible outside the + * group. + * + * Since: 1.2 + **/ +void +cairo_pop_group_to_source (cairo_t *cr) +{ + cairo_pattern_t *group_pattern; + + group_pattern = cairo_pop_group (cr); + cairo_set_source (cr, group_pattern); + cairo_pattern_destroy (group_pattern); +} + +/** + * cairo_set_operator: + * @cr: a #cairo_t + * @op: a compositing operator, specified as a #cairo_operator_t + * + * Sets the compositing operator to be used for all drawing + * operations. See #cairo_operator_t for details on the semantics of + * each available compositing operator. + * + * The default operator is %CAIRO_OPERATOR_OVER. + * + * Since: 1.0 + **/ +void +cairo_set_operator (cairo_t *cr, cairo_operator_t op) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->set_operator (cr, op); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + + +#if 0 +/* + * cairo_set_opacity: + * @cr: a #cairo_t + * @opacity: the level of opacity to use when compositing + * + * Sets the compositing opacity to be used for all drawing + * operations. The effect is to fade out the operations + * using the alpha value. + * + * The default opacity is 1. + */ +void +cairo_set_opacity (cairo_t *cr, double opacity) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->set_opacity (cr, opacity); + if (unlikely (status)) + _cairo_set_error (cr, status); +} +#endif + +/** + * cairo_set_source_rgb: + * @cr: a cairo context + * @red: red component of color + * @green: green component of color + * @blue: blue component of color + * + * Sets the source pattern within @cr to an opaque color. This opaque + * color will then be used for any subsequent drawing operation until + * a new source pattern is set. + * + * The color components are floating point numbers in the range 0 to + * 1. If the values passed in are outside that range, they will be + * clamped. + * + * The default source pattern is opaque black, (that is, it is + * equivalent to cairo_set_source_rgb(cr, 0.0, 0.0, 0.0)). + * + * Since: 1.0 + **/ +void +cairo_set_source_rgb (cairo_t *cr, double red, double green, double blue) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->set_source_rgba (cr, red, green, blue, 1.); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_set_source_rgba: + * @cr: a cairo context + * @red: red component of color + * @green: green component of color + * @blue: blue component of color + * @alpha: alpha component of color + * + * Sets the source pattern within @cr to a translucent color. This + * color will then be used for any subsequent drawing operation until + * a new source pattern is set. + * + * The color and alpha components are floating point numbers in the + * range 0 to 1. If the values passed in are outside that range, they + * will be clamped. + * + * Note that the color and alpha values are not premultiplied. + * + * The default source pattern is opaque black, (that is, it is + * equivalent to cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0)). + * + * Since: 1.0 + **/ +void +cairo_set_source_rgba (cairo_t *cr, + double red, double green, double blue, + double alpha) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->set_source_rgba (cr, red, green, blue, alpha); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_set_source_surface: + * @cr: a cairo context + * @surface: a surface to be used to set the source pattern + * @x: User-space X coordinate for surface origin + * @y: User-space Y coordinate for surface origin + * + * This is a convenience function for creating a pattern from @surface + * and setting it as the source in @cr with cairo_set_source(). + * + * The @x and @y parameters give the user-space coordinate at which + * the surface origin should appear. (The surface origin is its + * upper-left corner before any transformation has been applied.) The + * @x and @y parameters are negated and then set as translation values + * in the pattern matrix. + * + * Other than the initial translation pattern matrix, as described + * above, all other pattern attributes, (such as its extend mode), are + * set to the default values as in cairo_pattern_create_for_surface(). + * The resulting pattern can be queried with cairo_get_source() so + * that these attributes can be modified if desired, (eg. to create a + * repeating pattern with cairo_pattern_set_extend()). + * + * Since: 1.0 + **/ +void +cairo_set_source_surface (cairo_t *cr, + cairo_surface_t *surface, + double x, + double y) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + if (unlikely (surface == NULL)) { + _cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER); + return; + } + + status = cr->backend->set_source_surface (cr, surface, x, y); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_set_source: + * @cr: a cairo context + * @source: a #cairo_pattern_t to be used as the source for + * subsequent drawing operations. + * + * Sets the source pattern within @cr to @source. This pattern + * will then be used for any subsequent drawing operation until a new + * source pattern is set. + * + * Note: The pattern's transformation matrix will be locked to the + * user space in effect at the time of cairo_set_source(). This means + * that further modifications of the current transformation matrix + * will not affect the source pattern. See cairo_pattern_set_matrix(). + * + * The default source pattern is a solid pattern that is opaque black, + * (that is, it is equivalent to cairo_set_source_rgb(cr, 0.0, 0.0, + * 0.0)). + * + * Since: 1.0 + **/ +void +cairo_set_source (cairo_t *cr, cairo_pattern_t *source) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + if (unlikely (source == NULL)) { + _cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER); + return; + } + + if (unlikely (source->status)) { + _cairo_set_error (cr, source->status); + return; + } + + status = cr->backend->set_source (cr, source); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_get_source: + * @cr: a cairo context + * + * Gets the current source pattern for @cr. + * + * Return value: the current source pattern. This object is owned by + * cairo. To keep a reference to it, you must call + * cairo_pattern_reference(). + * + * Since: 1.0 + **/ +cairo_pattern_t * +cairo_get_source (cairo_t *cr) +{ + if (unlikely (cr->status)) + return _cairo_pattern_create_in_error (cr->status); + + return cr->backend->get_source (cr); +} + +/** + * cairo_set_tolerance: + * @cr: a #cairo_t + * @tolerance: the tolerance, in device units (typically pixels) + * + * Sets the tolerance used when converting paths into trapezoids. + * Curved segments of the path will be subdivided until the maximum + * deviation between the original path and the polygonal approximation + * is less than @tolerance. The default value is 0.1. A larger + * value will give better performance, a smaller value, better + * appearance. (Reducing the value from the default value of 0.1 + * is unlikely to improve appearance significantly.) The accuracy of paths + * within Cairo is limited by the precision of its internal arithmetic, and + * the prescribed @tolerance is restricted to the smallest + * representable internal value. + * + * Since: 1.0 + **/ +void +cairo_set_tolerance (cairo_t *cr, double tolerance) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->set_tolerance (cr, tolerance); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_set_antialias: + * @cr: a #cairo_t + * @antialias: the new antialiasing mode + * + * Set the antialiasing mode of the rasterizer used for drawing shapes. + * This value is a hint, and a particular backend may or may not support + * a particular value. At the current time, no backend supports + * %CAIRO_ANTIALIAS_SUBPIXEL when drawing shapes. + * + * Note that this option does not affect text rendering, instead see + * cairo_font_options_set_antialias(). + * + * Since: 1.0 + **/ +void +cairo_set_antialias (cairo_t *cr, cairo_antialias_t antialias) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->set_antialias (cr, antialias); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_set_fill_rule: + * @cr: a #cairo_t + * @fill_rule: a fill rule, specified as a #cairo_fill_rule_t + * + * Set the current fill rule within the cairo context. The fill rule + * is used to determine which regions are inside or outside a complex + * (potentially self-intersecting) path. The current fill rule affects + * both cairo_fill() and cairo_clip(). See #cairo_fill_rule_t for details + * on the semantics of each available fill rule. + * + * The default fill rule is %CAIRO_FILL_RULE_WINDING. + * + * Since: 1.0 + **/ +void +cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->set_fill_rule (cr, fill_rule); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_set_line_width: + * @cr: a #cairo_t + * @width: a line width + * + * Sets the current line width within the cairo context. The line + * width value specifies the diameter of a pen that is circular in + * user space, (though device-space pen may be an ellipse in general + * due to scaling/shear/rotation of the CTM). + * + * Note: When the description above refers to user space and CTM it + * refers to the user space and CTM in effect at the time of the + * stroking operation, not the user space and CTM in effect at the + * time of the call to cairo_set_line_width(). The simplest usage + * makes both of these spaces identical. That is, if there is no + * change to the CTM between a call to cairo_set_line_width() and the + * stroking operation, then one can just pass user-space values to + * cairo_set_line_width() and ignore this note. + * + * As with the other stroke parameters, the current line width is + * examined by cairo_stroke(), and cairo_stroke_extents(), but does not have + * any effect during path construction. + * + * The default line width value is 2.0. + * + * Since: 1.0 + **/ +void +cairo_set_line_width (cairo_t *cr, double width) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + if (width < 0.) + width = 0.; + + status = cr->backend->set_line_width (cr, width); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_set_hairline: + * @cr: a #cairo_t + * @set_hairline: whether or not to set hairline mode + * + * Sets lines within the cairo context to be hairlines. + * Hairlines are logically zero-width lines that are drawn at the + * thinnest renderable width possible in the current context. + * + * On surfaces with native hairline support, the native hairline + * functionality will be used. Surfaces that support hairlines include: + * - pdf/ps: Encoded as 0-width line. + * - win32_printing: Rendered with PS_COSMETIC pen. + * - svg: Encoded as 1px non-scaling-stroke. + * - script: Encoded with set-hairline function. + * + * Cairo will always render hairlines at 1 device unit wide, even if + * an anisotropic scaling was applied to the stroke width. In the wild, + * handling of this situation is not well-defined. Some PDF, PS, and SVG + * renderers match Cairo's output, but some very popular implementations + * (Acrobat, Chrome, rsvg) will scale the hairline unevenly. + * As such, best practice is to reset any anisotropic scaling before calling + * cairo_stroke(). See https://cairographics.org/cookbook/ellipses/ + * for an example. + * + * Since: 1.18 + **/ +void +cairo_set_hairline (cairo_t *cr, cairo_bool_t set_hairline) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->set_hairline (cr, set_hairline); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_set_line_cap: + * @cr: a cairo context + * @line_cap: a line cap style + * + * Sets the current line cap style within the cairo context. See + * #cairo_line_cap_t for details about how the available line cap + * styles are drawn. + * + * As with the other stroke parameters, the current line cap style is + * examined by cairo_stroke(), and cairo_stroke_extents(), but does not have + * any effect during path construction. + * + * The default line cap style is %CAIRO_LINE_CAP_BUTT. + * + * Since: 1.0 + **/ +void +cairo_set_line_cap (cairo_t *cr, cairo_line_cap_t line_cap) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->set_line_cap (cr, line_cap); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_set_line_join: + * @cr: a cairo context + * @line_join: a line join style + * + * Sets the current line join style within the cairo context. See + * #cairo_line_join_t for details about how the available line join + * styles are drawn. + * + * As with the other stroke parameters, the current line join style is + * examined by cairo_stroke(), and cairo_stroke_extents(), but does not have + * any effect during path construction. + * + * The default line join style is %CAIRO_LINE_JOIN_MITER. + * + * Since: 1.0 + **/ +void +cairo_set_line_join (cairo_t *cr, cairo_line_join_t line_join) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->set_line_join (cr, line_join); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_set_dash: + * @cr: a cairo context + * @dashes: an array specifying alternate lengths of on and off stroke portions + * @num_dashes: the length of the dashes array + * @offset: an offset into the dash pattern at which the stroke should start + * + * Sets the dash pattern to be used by cairo_stroke(). A dash pattern + * is specified by @dashes, an array of positive values. Each value + * provides the length of alternate "on" and "off" portions of the + * stroke. The @offset specifies an offset into the pattern at which + * the stroke begins. + * + * Each "on" segment will have caps applied as if the segment were a + * separate sub-path. In particular, it is valid to use an "on" length + * of 0.0 with %CAIRO_LINE_CAP_ROUND or %CAIRO_LINE_CAP_SQUARE in order + * to distributed dots or squares along a path. + * + * Note: The length values are in user-space units as evaluated at the + * time of stroking. This is not necessarily the same as the user + * space at the time of cairo_set_dash(). + * + * If @num_dashes is 0 dashing is disabled. + * + * If @num_dashes is 1 a symmetric pattern is assumed with alternating + * on and off portions of the size specified by the single value in + * @dashes. + * + * If any value in @dashes is negative, or if all values are 0, then + * @cr will be put into an error state with a status of + * %CAIRO_STATUS_INVALID_DASH. + * + * Since: 1.0 + **/ +void +cairo_set_dash (cairo_t *cr, + const double *dashes, + int num_dashes, + double offset) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->set_dash (cr, dashes, num_dashes, offset); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_get_dash_count: + * @cr: a #cairo_t + * + * This function returns the length of the dash array in @cr (0 if dashing + * is not currently in effect). + * + * See also cairo_set_dash() and cairo_get_dash(). + * + * Return value: the length of the dash array, or 0 if no dash array set. + * + * Since: 1.4 + **/ +int +cairo_get_dash_count (cairo_t *cr) +{ + int num_dashes; + + if (unlikely (cr->status)) + return 0; + + cr->backend->get_dash (cr, NULL, &num_dashes, NULL); + + return num_dashes; +} + +/** + * cairo_get_dash: + * @cr: a #cairo_t + * @dashes: return value for the dash array, or %NULL + * @offset: return value for the current dash offset, or %NULL + * + * Gets the current dash array. If not %NULL, @dashes should be big + * enough to hold at least the number of values returned by + * cairo_get_dash_count(). + * + * Since: 1.4 + **/ +void +cairo_get_dash (cairo_t *cr, + double *dashes, + double *offset) +{ + if (unlikely (cr->status)) + return; + + cr->backend->get_dash (cr, dashes, NULL, offset); +} + +/** + * cairo_set_miter_limit: + * @cr: a cairo context + * @limit: miter limit to set + * + * Sets the current miter limit within the cairo context. + * + * If the current line join style is set to %CAIRO_LINE_JOIN_MITER + * (see cairo_set_line_join()), the miter limit is used to determine + * whether the lines should be joined with a bevel instead of a miter. + * Cairo divides the length of the miter by the line width. + * If the result is greater than the miter limit, the style is + * converted to a bevel. + * + * As with the other stroke parameters, the current line miter limit is + * examined by cairo_stroke(), and cairo_stroke_extents(), but does not have + * any effect during path construction. + * + * The default miter limit value is 10.0, which will convert joins + * with interior angles less than 11 degrees to bevels instead of + * miters. For reference, a miter limit of 2.0 makes the miter cutoff + * at 60 degrees, and a miter limit of 1.414 makes the cutoff at 90 + * degrees. + * + * A miter limit for a desired angle can be computed as: miter limit = + * 1/sin(angle/2) + * + * Since: 1.0 + **/ +void +cairo_set_miter_limit (cairo_t *cr, double limit) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->set_miter_limit (cr, limit); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_translate: + * @cr: a cairo context + * @tx: amount to translate in the X direction + * @ty: amount to translate in the Y direction + * + * Modifies the current transformation matrix (CTM) by translating the + * user-space origin by (@tx, @ty). This offset is interpreted as a + * user-space coordinate according to the CTM in place before the new + * call to cairo_translate(). In other words, the translation of the + * user-space origin takes place after any existing transformation. + * + * Since: 1.0 + **/ +void +cairo_translate (cairo_t *cr, double tx, double ty) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->translate (cr, tx, ty); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_scale: + * @cr: a cairo context + * @sx: scale factor for the X dimension + * @sy: scale factor for the Y dimension + * + * Modifies the current transformation matrix (CTM) by scaling the X + * and Y user-space axes by @sx and @sy respectively. The scaling of + * the axes takes place after any existing transformation of user + * space. + * + * Since: 1.0 + **/ +void +cairo_scale (cairo_t *cr, double sx, double sy) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->scale (cr, sx, sy); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_rotate: + * @cr: a cairo context + * @angle: angle (in radians) by which the user-space axes will be + * rotated + * + * Modifies the current transformation matrix (CTM) by rotating the + * user-space axes by @angle radians. The rotation of the axes takes + * places after any existing transformation of user space. The + * rotation direction for positive angles is from the positive X axis + * toward the positive Y axis. + * + * Since: 1.0 + **/ +void +cairo_rotate (cairo_t *cr, double angle) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->rotate (cr, angle); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_transform: + * @cr: a cairo context + * @matrix: a transformation to be applied to the user-space axes + * + * Modifies the current transformation matrix (CTM) by applying + * @matrix as an additional transformation. The new transformation of + * user space takes place after any existing transformation. + * + * Since: 1.0 + **/ +void +cairo_transform (cairo_t *cr, + const cairo_matrix_t *matrix) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->transform (cr, matrix); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_set_matrix: + * @cr: a cairo context + * @matrix: a transformation matrix from user space to device space + * + * Modifies the current transformation matrix (CTM) by setting it + * equal to @matrix. + * + * Since: 1.0 + **/ +void +cairo_set_matrix (cairo_t *cr, + const cairo_matrix_t *matrix) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->set_matrix (cr, matrix); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_identity_matrix: + * @cr: a cairo context + * + * Resets the current transformation matrix (CTM) by setting it equal + * to the identity matrix. That is, the user-space and device-space + * axes will be aligned and one user-space unit will transform to one + * device-space unit. + * + * Since: 1.0 + **/ +void +cairo_identity_matrix (cairo_t *cr) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->set_identity_matrix (cr); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_user_to_device: + * @cr: a cairo context + * @x: X value of coordinate (in/out parameter) + * @y: Y value of coordinate (in/out parameter) + * + * Transform a coordinate from user space to device space by + * multiplying the given point by the current transformation matrix + * (CTM). + * + * Since: 1.0 + **/ +void +cairo_user_to_device (cairo_t *cr, double *x, double *y) +{ + if (unlikely (cr->status)) + return; + + cr->backend->user_to_device (cr, x, y); +} + +/** + * cairo_user_to_device_distance: + * @cr: a cairo context + * @dx: X component of a distance vector (in/out parameter) + * @dy: Y component of a distance vector (in/out parameter) + * + * Transform a distance vector from user space to device space. This + * function is similar to cairo_user_to_device() except that the + * translation components of the CTM will be ignored when transforming + * (@dx,@dy). + * + * Since: 1.0 + **/ +void +cairo_user_to_device_distance (cairo_t *cr, double *dx, double *dy) +{ + if (unlikely (cr->status)) + return; + + cr->backend->user_to_device_distance (cr, dx, dy); +} + +/** + * cairo_device_to_user: + * @cr: a cairo + * @x: X value of coordinate (in/out parameter) + * @y: Y value of coordinate (in/out parameter) + * + * Transform a coordinate from device space to user space by + * multiplying the given point by the inverse of the current + * transformation matrix (CTM). + * + * Since: 1.0 + **/ +void +cairo_device_to_user (cairo_t *cr, double *x, double *y) +{ + if (unlikely (cr->status)) + return; + + cr->backend->device_to_user (cr, x, y); +} + +/** + * cairo_device_to_user_distance: + * @cr: a cairo context + * @dx: X component of a distance vector (in/out parameter) + * @dy: Y component of a distance vector (in/out parameter) + * + * Transform a distance vector from device space to user space. This + * function is similar to cairo_device_to_user() except that the + * translation components of the inverse CTM will be ignored when + * transforming (@dx,@dy). + * + * Since: 1.0 + **/ +void +cairo_device_to_user_distance (cairo_t *cr, double *dx, double *dy) +{ + if (unlikely (cr->status)) + return; + + cr->backend->device_to_user_distance (cr, dx, dy); +} + +/** + * cairo_new_path: + * @cr: a cairo context + * + * Clears the current path. After this call there will be no path and + * no current point. + * + * Since: 1.0 + **/ +void +cairo_new_path (cairo_t *cr) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->new_path (cr); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_new_sub_path: + * @cr: a cairo context + * + * Begin a new sub-path. Note that the existing path is not + * affected. After this call there will be no current point. + * + * In many cases, this call is not needed since new sub-paths are + * frequently started with cairo_move_to(). + * + * A call to cairo_new_sub_path() is particularly useful when + * beginning a new sub-path with one of the cairo_arc() calls. This + * makes things easier as it is no longer necessary to manually + * compute the arc's initial coordinates for a call to + * cairo_move_to(). + * + * Since: 1.2 + **/ +void +cairo_new_sub_path (cairo_t *cr) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->new_sub_path (cr); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_move_to: + * @cr: a cairo context + * @x: the X coordinate of the new position + * @y: the Y coordinate of the new position + * + * Begin a new sub-path. After this call the current point will be (@x, + * @y). + * + * Since: 1.0 + **/ +void +cairo_move_to (cairo_t *cr, double x, double y) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->move_to (cr, x, y); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_line_to: + * @cr: a cairo context + * @x: the X coordinate of the end of the new line + * @y: the Y coordinate of the end of the new line + * + * Adds a line to the path from the current point to position (@x, @y) + * in user-space coordinates. After this call the current point + * will be (@x, @y). + * + * If there is no current point before the call to cairo_line_to() + * this function will behave as cairo_move_to(@cr, @x, @y). + * + * Since: 1.0 + **/ +void +cairo_line_to (cairo_t *cr, double x, double y) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->line_to (cr, x, y); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_curve_to: + * @cr: a cairo context + * @x1: the X coordinate of the first control point + * @y1: the Y coordinate of the first control point + * @x2: the X coordinate of the second control point + * @y2: the Y coordinate of the second control point + * @x3: the X coordinate of the end of the curve + * @y3: the Y coordinate of the end of the curve + * + * Adds a cubic Bézier spline to the path from the current point to + * position (@x3, @y3) in user-space coordinates, using (@x1, @y1) and + * (@x2, @y2) as the control points. After this call the current point + * will be (@x3, @y3). + * + * If there is no current point before the call to cairo_curve_to() + * this function will behave as if preceded by a call to + * cairo_move_to(@cr, @x1, @y1). + * + * Since: 1.0 + **/ +void +cairo_curve_to (cairo_t *cr, + double x1, double y1, + double x2, double y2, + double x3, double y3) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->curve_to (cr, + x1, y1, + x2, y2, + x3, y3); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_arc: + * @cr: a cairo context + * @xc: X position of the center of the arc + * @yc: Y position of the center of the arc + * @radius: the radius of the arc + * @angle1: the start angle, in radians + * @angle2: the end angle, in radians + * + * Adds a circular arc of the given @radius to the current path. The + * arc is centered at (@xc, @yc), begins at @angle1 and proceeds in + * the direction of increasing angles to end at @angle2. If @angle2 is + * less than @angle1 it will be progressively increased by + * 2*M_PI until it is greater than @angle1. + * + * If there is a current point, an initial line segment will be added + * to the path to connect the current point to the beginning of the + * arc. If this initial line is undesired, it can be avoided by + * calling cairo_new_sub_path() before calling cairo_arc(). + * + * Angles are measured in radians. An angle of 0.0 is in the direction + * of the positive X axis (in user space). An angle of + * M_PI/2.0 radians (90 degrees) is in the + * direction of the positive Y axis (in user space). Angles increase + * in the direction from the positive X axis toward the positive Y + * axis. So with the default transformation matrix, angles increase in + * a clockwise direction. + * + * (To convert from degrees to radians, use degrees * (M_PI / + * 180.).) + * + * This function gives the arc in the direction of increasing angles; + * see cairo_arc_negative() to get the arc in the direction of + * decreasing angles. + * + * The arc is circular in user space. To achieve an elliptical arc, + * you can scale the current transformation matrix by different + * amounts in the X and Y directions. For example, to draw an ellipse + * in the box given by @x, @y, @width, @height: + * + * + * cairo_save (cr); + * cairo_translate (cr, x + width / 2., y + height / 2.); + * cairo_scale (cr, width / 2., height / 2.); + * cairo_arc (cr, 0., 0., 1., 0., 2 * M_PI); + * cairo_restore (cr); + * + * + * Since: 1.0 + **/ +void +cairo_arc (cairo_t *cr, + double xc, double yc, + double radius, + double angle1, double angle2) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + if (angle2 < angle1) { + /* increase angle2 by multiples of full circle until it + * satisfies angle2 >= angle1 */ + angle2 = fmod (angle2 - angle1, 2 * M_PI); + if (angle2 < 0) + angle2 += 2 * M_PI; + angle2 += angle1; + } + + status = cr->backend->arc (cr, xc, yc, radius, angle1, angle2, TRUE); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_arc_negative: + * @cr: a cairo context + * @xc: X position of the center of the arc + * @yc: Y position of the center of the arc + * @radius: the radius of the arc + * @angle1: the start angle, in radians + * @angle2: the end angle, in radians + * + * Adds a circular arc of the given @radius to the current path. The + * arc is centered at (@xc, @yc), begins at @angle1 and proceeds in + * the direction of decreasing angles to end at @angle2. If @angle2 is + * greater than @angle1 it will be progressively decreased by + * 2*M_PI until it is less than @angle1. + * + * See cairo_arc() for more details. This function differs only in the + * direction of the arc between the two angles. + * + * Since: 1.0 + **/ +void +cairo_arc_negative (cairo_t *cr, + double xc, double yc, + double radius, + double angle1, double angle2) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + if (angle2 > angle1) { + /* decrease angle2 by multiples of full circle until it + * satisfies angle2 <= angle1 */ + angle2 = fmod (angle2 - angle1, 2 * M_PI); + if (angle2 > 0) + angle2 -= 2 * M_PI; + angle2 += angle1; + } + + status = cr->backend->arc (cr, xc, yc, radius, angle1, angle2, FALSE); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/* XXX: NYI +void +cairo_arc_to (cairo_t *cr, + double x1, double y1, + double x2, double y2, + double radius) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->arc_to (cr, x1, y1, x2, y2, radius); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +void +cairo_rel_arc_to (cairo_t *cr, + double dx1, double dy1, + double dx2, double dy2, + double radius) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->rel_arc_to (cr, dx1, dy1, dx2, dy2, radius); + if (unlikely (status)) + _cairo_set_error (cr, status); +} +*/ + +/** + * cairo_rel_move_to: + * @cr: a cairo context + * @dx: the X offset + * @dy: the Y offset + * + * Begin a new sub-path. After this call the current point will offset + * by (@x, @y). + * + * Given a current point of (x, y), cairo_rel_move_to(@cr, @dx, @dy) + * is logically equivalent to cairo_move_to(@cr, x + @dx, y + @dy). + * + * It is an error to call this function with no current point. Doing + * so will cause @cr to shutdown with a status of + * %CAIRO_STATUS_NO_CURRENT_POINT. + * + * Since: 1.0 + **/ +void +cairo_rel_move_to (cairo_t *cr, double dx, double dy) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->rel_move_to (cr, dx, dy); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_rel_line_to: + * @cr: a cairo context + * @dx: the X offset to the end of the new line + * @dy: the Y offset to the end of the new line + * + * Relative-coordinate version of cairo_line_to(). Adds a line to the + * path from the current point to a point that is offset from the + * current point by (@dx, @dy) in user space. After this call the + * current point will be offset by (@dx, @dy). + * + * Given a current point of (x, y), cairo_rel_line_to(@cr, @dx, @dy) + * is logically equivalent to cairo_line_to(@cr, x + @dx, y + @dy). + * + * It is an error to call this function with no current point. Doing + * so will cause @cr to shutdown with a status of + * %CAIRO_STATUS_NO_CURRENT_POINT. + * + * Since: 1.0 + **/ +void +cairo_rel_line_to (cairo_t *cr, double dx, double dy) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->rel_line_to (cr, dx, dy); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_rel_curve_to: + * @cr: a cairo context + * @dx1: the X offset to the first control point + * @dy1: the Y offset to the first control point + * @dx2: the X offset to the second control point + * @dy2: the Y offset to the second control point + * @dx3: the X offset to the end of the curve + * @dy3: the Y offset to the end of the curve + * + * Relative-coordinate version of cairo_curve_to(). All offsets are + * relative to the current point. Adds a cubic Bézier spline to the + * path from the current point to a point offset from the current + * point by (@dx3, @dy3), using points offset by (@dx1, @dy1) and + * (@dx2, @dy2) as the control points. After this call the current + * point will be offset by (@dx3, @dy3). + * + * Given a current point of (x, y), cairo_rel_curve_to(@cr, @dx1, + * @dy1, @dx2, @dy2, @dx3, @dy3) is logically equivalent to + * cairo_curve_to(@cr, x+@dx1, y+@dy1, x+@dx2, y+@dy2, x+@dx3, y+@dy3). + * + * It is an error to call this function with no current point. Doing + * so will cause @cr to shutdown with a status of + * %CAIRO_STATUS_NO_CURRENT_POINT. + * + * Since: 1.0 + **/ +void +cairo_rel_curve_to (cairo_t *cr, + double dx1, double dy1, + double dx2, double dy2, + double dx3, double dy3) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->rel_curve_to (cr, + dx1, dy1, + dx2, dy2, + dx3, dy3); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_rectangle: + * @cr: a cairo context + * @x: the X coordinate of the top left corner of the rectangle + * @y: the Y coordinate to the top left corner of the rectangle + * @width: the width of the rectangle + * @height: the height of the rectangle + * + * Adds a closed sub-path rectangle of the given size to the current + * path at position (@x, @y) in user-space coordinates. + * + * This function is logically equivalent to: + * + * cairo_move_to (cr, x, y); + * cairo_rel_line_to (cr, width, 0); + * cairo_rel_line_to (cr, 0, height); + * cairo_rel_line_to (cr, -width, 0); + * cairo_close_path (cr); + * + * + * Since: 1.0 + **/ +void +cairo_rectangle (cairo_t *cr, + double x, double y, + double width, double height) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->rectangle (cr, x, y, width, height); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +#if 0 +/* XXX: NYI */ +void +cairo_stroke_to_path (cairo_t *cr) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + /* The code in _cairo_recording_surface_get_path has a poorman's stroke_to_path */ + + status = _cairo_gstate_stroke_path (cr->gstate); + if (unlikely (status)) + _cairo_set_error (cr, status); +} +#endif + +/** + * cairo_close_path: + * @cr: a cairo context + * + * Adds a line segment to the path from the current point to the + * beginning of the current sub-path, (the most recent point passed to + * cairo_move_to()), and closes this sub-path. After this call the + * current point will be at the joined endpoint of the sub-path. + * + * The behavior of cairo_close_path() is distinct from simply calling + * cairo_line_to() with the equivalent coordinate in the case of + * stroking. When a closed sub-path is stroked, there are no caps on + * the ends of the sub-path. Instead, there is a line join connecting + * the final and initial segments of the sub-path. + * + * If there is no current point before the call to cairo_close_path(), + * this function will have no effect. + * + * Note: As of cairo version 1.2.4 any call to cairo_close_path() will + * place an explicit MOVE_TO element into the path immediately after + * the CLOSE_PATH element, (which can be seen in cairo_copy_path() for + * example). This can simplify path processing in some cases as it may + * not be necessary to save the "last move_to point" during processing + * as the MOVE_TO immediately after the CLOSE_PATH will provide that + * point. + * + * Since: 1.0 + **/ +void +cairo_close_path (cairo_t *cr) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->close_path (cr); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_path_extents: + * @cr: a cairo context + * @x1: left of the resulting extents + * @y1: top of the resulting extents + * @x2: right of the resulting extents + * @y2: bottom of the resulting extents + * + * Computes a bounding box in user-space coordinates covering the + * points on the current path. If the current path is empty, returns + * an empty rectangle ((0,0), (0,0)). Stroke parameters, fill rule, + * surface dimensions and clipping are not taken into account. + * + * Contrast with cairo_fill_extents() and cairo_stroke_extents() which + * return the extents of only the area that would be "inked" by + * the corresponding drawing operations. + * + * The result of cairo_path_extents() is defined as equivalent to the + * limit of cairo_stroke_extents() with %CAIRO_LINE_CAP_ROUND as the + * line width approaches 0.0, (but never reaching the empty-rectangle + * returned by cairo_stroke_extents() for a line width of 0.0). + * + * Specifically, this means that zero-area sub-paths such as + * cairo_move_to();cairo_line_to() segments, (even degenerate cases + * where the coordinates to both calls are identical), will be + * considered as contributing to the extents. However, a lone + * cairo_move_to() will not contribute to the results of + * cairo_path_extents(). + * + * Since: 1.6 + **/ +void +cairo_path_extents (cairo_t *cr, + double *x1, double *y1, double *x2, double *y2) +{ + if (unlikely (cr->status)) { + if (x1) + *x1 = 0.0; + if (y1) + *y1 = 0.0; + if (x2) + *x2 = 0.0; + if (y2) + *y2 = 0.0; + + return; + } + + cr->backend->path_extents (cr, x1, y1, x2, y2); +} + +/** + * cairo_paint: + * @cr: a cairo context + * + * A drawing operator that paints the current source everywhere within + * the current clip region. + * + * Since: 1.0 + **/ +void +cairo_paint (cairo_t *cr) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->paint (cr); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_paint_with_alpha: + * @cr: a cairo context + * @alpha: alpha value, between 0 (transparent) and 1 (opaque) + * + * A drawing operator that paints the current source everywhere within + * the current clip region using a mask of constant alpha value + * @alpha. The effect is similar to cairo_paint(), but the drawing + * is faded out using the alpha value. + * + * Since: 1.0 + **/ +void +cairo_paint_with_alpha (cairo_t *cr, + double alpha) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->paint_with_alpha (cr, alpha); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_mask: + * @cr: a cairo context + * @pattern: a #cairo_pattern_t + * + * A drawing operator that paints the current source + * using the alpha channel of @pattern as a mask. (Opaque + * areas of @pattern are painted with the source, transparent + * areas are not painted.) + * + * Since: 1.0 + **/ +void +cairo_mask (cairo_t *cr, + cairo_pattern_t *pattern) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + if (unlikely (pattern == NULL)) { + _cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER); + return; + } + + if (unlikely (pattern->status)) { + _cairo_set_error (cr, pattern->status); + return; + } + + status = cr->backend->mask (cr, pattern); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_mask_surface: + * @cr: a cairo context + * @surface: a #cairo_surface_t + * @surface_x: X coordinate at which to place the origin of @surface + * @surface_y: Y coordinate at which to place the origin of @surface + * + * A drawing operator that paints the current source + * using the alpha channel of @surface as a mask. (Opaque + * areas of @surface are painted with the source, transparent + * areas are not painted.) + * + * Since: 1.0 + **/ +void +cairo_mask_surface (cairo_t *cr, + cairo_surface_t *surface, + double surface_x, + double surface_y) +{ + cairo_pattern_t *pattern; + cairo_matrix_t matrix; + + if (unlikely (cr->status)) + return; + + pattern = cairo_pattern_create_for_surface (surface); + + cairo_matrix_init_translate (&matrix, - surface_x, - surface_y); + cairo_pattern_set_matrix (pattern, &matrix); + + cairo_mask (cr, pattern); + + cairo_pattern_destroy (pattern); +} + +/** + * cairo_stroke: + * @cr: a cairo context + * + * A drawing operator that strokes the current path according to the + * current line width, line join, line cap, and dash settings. After + * cairo_stroke(), the current path will be cleared from the cairo + * context. See cairo_set_line_width(), cairo_set_line_join(), + * cairo_set_line_cap(), cairo_set_dash(), and + * cairo_stroke_preserve(). + * + * Note: Degenerate segments and sub-paths are treated specially and + * provide a useful result. These can result in two different + * situations: + * + * 1. Zero-length "on" segments set in cairo_set_dash(). If the cap + * style is %CAIRO_LINE_CAP_ROUND or %CAIRO_LINE_CAP_SQUARE then these + * segments will be drawn as circular dots or squares respectively. In + * the case of %CAIRO_LINE_CAP_SQUARE, the orientation of the squares + * is determined by the direction of the underlying path. + * + * 2. A sub-path created by cairo_move_to() followed by either a + * cairo_close_path() or one or more calls to cairo_line_to() to the + * same coordinate as the cairo_move_to(). If the cap style is + * %CAIRO_LINE_CAP_ROUND then these sub-paths will be drawn as circular + * dots. Note that in the case of %CAIRO_LINE_CAP_SQUARE a degenerate + * sub-path will not be drawn at all, (since the correct orientation + * is indeterminate). + * + * In no case will a cap style of %CAIRO_LINE_CAP_BUTT cause anything + * to be drawn in the case of either degenerate segments or sub-paths. + * + * Since: 1.0 + **/ +void +cairo_stroke (cairo_t *cr) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->stroke (cr); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_stroke_preserve: + * @cr: a cairo context + * + * A drawing operator that strokes the current path according to the + * current line width, line join, line cap, and dash settings. Unlike + * cairo_stroke(), cairo_stroke_preserve() preserves the path within the + * cairo context. + * + * See cairo_set_line_width(), cairo_set_line_join(), + * cairo_set_line_cap(), cairo_set_dash(), and + * cairo_stroke_preserve(). + * + * Since: 1.0 + **/ +void +cairo_stroke_preserve (cairo_t *cr) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->stroke_preserve (cr); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_fill: + * @cr: a cairo context + * + * A drawing operator that fills the current path according to the + * current fill rule, (each sub-path is implicitly closed before being + * filled). After cairo_fill(), the current path will be cleared from + * the cairo context. See cairo_set_fill_rule() and + * cairo_fill_preserve(). + * + * Since: 1.0 + **/ +void +cairo_fill (cairo_t *cr) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->fill (cr); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_fill_preserve: + * @cr: a cairo context + * + * A drawing operator that fills the current path according to the + * current fill rule, (each sub-path is implicitly closed before being + * filled). Unlike cairo_fill(), cairo_fill_preserve() preserves the + * path within the cairo context. + * + * See cairo_set_fill_rule() and cairo_fill(). + * + * Since: 1.0 + **/ +void +cairo_fill_preserve (cairo_t *cr) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->fill_preserve (cr); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_copy_page: + * @cr: a cairo context + * + * Emits the current page for backends that support multiple pages, but + * doesn't clear it, so, the contents of the current page will be retained + * for the next page too. Use cairo_show_page() if you want to get an + * empty page after the emission. + * + * This is a convenience function that simply calls + * cairo_surface_copy_page() on @cr's target. + * + * Since: 1.0 + **/ +void +cairo_copy_page (cairo_t *cr) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->copy_page (cr); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_show_page: + * @cr: a cairo context + * + * Emits and clears the current page for backends that support multiple + * pages. Use cairo_copy_page() if you don't want to clear the page. + * + * This is a convenience function that simply calls + * cairo_surface_show_page() on @cr's target. + * + * Since: 1.0 + **/ +void +cairo_show_page (cairo_t *cr) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->show_page (cr); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_in_stroke: + * @cr: a cairo context + * @x: X coordinate of the point to test + * @y: Y coordinate of the point to test + * + * Tests whether the given point is inside the area that would be + * affected by a cairo_stroke() operation given the current path and + * stroking parameters. Surface dimensions and clipping are not taken + * into account. + * + * See cairo_stroke(), cairo_set_line_width(), cairo_set_line_join(), + * cairo_set_line_cap(), cairo_set_dash(), and + * cairo_stroke_preserve(). + * + * Return value: A non-zero value if the point is inside, or zero if + * outside. + * + * Since: 1.0 + **/ +cairo_bool_t +cairo_in_stroke (cairo_t *cr, double x, double y) +{ + cairo_status_t status; + cairo_bool_t inside = FALSE; + + if (unlikely (cr->status)) + return FALSE; + + status = cr->backend->in_stroke (cr, x, y, &inside); + if (unlikely (status)) + _cairo_set_error (cr, status); + + return inside; +} + +/** + * cairo_in_fill: + * @cr: a cairo context + * @x: X coordinate of the point to test + * @y: Y coordinate of the point to test + * + * Tests whether the given point is inside the area that would be + * affected by a cairo_fill() operation given the current path and + * filling parameters. Surface dimensions and clipping are not taken + * into account. + * + * See cairo_fill(), cairo_set_fill_rule() and cairo_fill_preserve(). + * + * Return value: A non-zero value if the point is inside, or zero if + * outside. + * + * Since: 1.0 + **/ +cairo_bool_t +cairo_in_fill (cairo_t *cr, double x, double y) +{ + cairo_status_t status; + cairo_bool_t inside = FALSE; + + if (unlikely (cr->status)) + return FALSE; + + status = cr->backend->in_fill (cr, x, y, &inside); + if (unlikely (status)) + _cairo_set_error (cr, status); + + return inside; +} + +/** + * cairo_stroke_extents: + * @cr: a cairo context + * @x1: left of the resulting extents + * @y1: top of the resulting extents + * @x2: right of the resulting extents + * @y2: bottom of the resulting extents + * + * Computes a bounding box in user coordinates covering the area that + * would be affected, (the "inked" area), by a cairo_stroke() + * operation given the current path and stroke parameters. + * If the current path is empty, returns an empty rectangle ((0,0), (0,0)). + * Surface dimensions and clipping are not taken into account. + * + * Note that if the line width is set to exactly zero, then + * cairo_stroke_extents() will return an empty rectangle. Contrast with + * cairo_path_extents() which can be used to compute the non-empty + * bounds as the line width approaches zero. + * + * Note that cairo_stroke_extents() must necessarily do more work to + * compute the precise inked areas in light of the stroke parameters, + * so cairo_path_extents() may be more desirable for sake of + * performance if non-inked path extents are desired. + * + * See cairo_stroke(), cairo_set_line_width(), cairo_set_line_join(), + * cairo_set_line_cap(), cairo_set_dash(), and + * cairo_stroke_preserve(). + * + * Since: 1.0 + **/ +void +cairo_stroke_extents (cairo_t *cr, + double *x1, double *y1, double *x2, double *y2) +{ + cairo_status_t status; + + if (unlikely (cr->status)) { + if (x1) + *x1 = 0.0; + if (y1) + *y1 = 0.0; + if (x2) + *x2 = 0.0; + if (y2) + *y2 = 0.0; + + return; + } + + status = cr->backend->stroke_extents (cr, x1, y1, x2, y2); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_fill_extents: + * @cr: a cairo context + * @x1: left of the resulting extents + * @y1: top of the resulting extents + * @x2: right of the resulting extents + * @y2: bottom of the resulting extents + * + * Computes a bounding box in user coordinates covering the area that + * would be affected, (the "inked" area), by a cairo_fill() operation + * given the current path and fill parameters. If the current path is + * empty, returns an empty rectangle ((0,0), (0,0)). Surface + * dimensions and clipping are not taken into account. + * + * Contrast with cairo_path_extents(), which is similar, but returns + * non-zero extents for some paths with no inked area, (such as a + * simple line segment). + * + * Note that cairo_fill_extents() must necessarily do more work to + * compute the precise inked areas in light of the fill rule, so + * cairo_path_extents() may be more desirable for sake of performance + * if the non-inked path extents are desired. + * + * See cairo_fill(), cairo_set_fill_rule() and cairo_fill_preserve(). + * + * Since: 1.0 + **/ +void +cairo_fill_extents (cairo_t *cr, + double *x1, double *y1, double *x2, double *y2) +{ + cairo_status_t status; + + if (unlikely (cr->status)) { + if (x1) + *x1 = 0.0; + if (y1) + *y1 = 0.0; + if (x2) + *x2 = 0.0; + if (y2) + *y2 = 0.0; + + return; + } + + status = cr->backend->fill_extents (cr, x1, y1, x2, y2); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_clip: + * @cr: a cairo context + * + * Establishes a new clip region by intersecting the current clip + * region with the current path as it would be filled by cairo_fill() + * and according to the current fill rule (see cairo_set_fill_rule()). + * + * After cairo_clip(), the current path will be cleared from the cairo + * context. + * + * The current clip region affects all drawing operations by + * effectively masking out any changes to the surface that are outside + * the current clip region. + * + * Calling cairo_clip() can only make the clip region smaller, never + * larger. But the current clip is part of the graphics state, so a + * temporary restriction of the clip region can be achieved by + * calling cairo_clip() within a cairo_save()/cairo_restore() + * pair. The only other means of increasing the size of the clip + * region is cairo_reset_clip(). + * + * Since: 1.0 + **/ +void +cairo_clip (cairo_t *cr) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->clip (cr); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_clip_preserve: + * @cr: a cairo context + * + * Establishes a new clip region by intersecting the current clip + * region with the current path as it would be filled by cairo_fill() + * and according to the current fill rule (see cairo_set_fill_rule()). + * + * Unlike cairo_clip(), cairo_clip_preserve() preserves the path within + * the cairo context. + * + * The current clip region affects all drawing operations by + * effectively masking out any changes to the surface that are outside + * the current clip region. + * + * Calling cairo_clip_preserve() can only make the clip region smaller, never + * larger. But the current clip is part of the graphics state, so a + * temporary restriction of the clip region can be achieved by + * calling cairo_clip_preserve() within a cairo_save()/cairo_restore() + * pair. The only other means of increasing the size of the clip + * region is cairo_reset_clip(). + * + * Since: 1.0 + **/ +void +cairo_clip_preserve (cairo_t *cr) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->clip_preserve (cr); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_reset_clip: + * @cr: a cairo context + * + * Reset the current clip region to its original, unrestricted + * state. That is, set the clip region to an infinitely large shape + * containing the target surface. Equivalently, if infinity is too + * hard to grasp, one can imagine the clip region being reset to the + * exact bounds of the target surface. + * + * Note that code meant to be reusable should not call + * cairo_reset_clip() as it will cause results unexpected by + * higher-level code which calls cairo_clip(). Consider using + * cairo_save() and cairo_restore() around cairo_clip() as a more + * robust means of temporarily restricting the clip region. + * + * Since: 1.0 + **/ +void +cairo_reset_clip (cairo_t *cr) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->reset_clip (cr); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_clip_extents: + * @cr: a cairo context + * @x1: left of the resulting extents + * @y1: top of the resulting extents + * @x2: right of the resulting extents + * @y2: bottom of the resulting extents + * + * Computes a bounding box in user coordinates covering the area inside the + * current clip. + * + * Since: 1.4 + **/ +void +cairo_clip_extents (cairo_t *cr, + double *x1, double *y1, + double *x2, double *y2) +{ + cairo_status_t status; + + if (x1) + *x1 = 0.0; + if (y1) + *y1 = 0.0; + if (x2) + *x2 = 0.0; + if (y2) + *y2 = 0.0; + + if (unlikely (cr->status)) + return; + + status = cr->backend->clip_extents (cr, x1, y1, x2, y2); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_in_clip: + * @cr: a cairo context + * @x: X coordinate of the point to test + * @y: Y coordinate of the point to test + * + * Tests whether the given point is inside the area that would be + * visible through the current clip, i.e. the area that would be filled by + * a cairo_paint() operation. + * + * See cairo_clip(), and cairo_clip_preserve(). + * + * Return value: A non-zero value if the point is inside, or zero if + * outside. + * + * Since: 1.10 + **/ +cairo_bool_t +cairo_in_clip (cairo_t *cr, double x, double y) +{ + cairo_status_t status; + cairo_bool_t inside = FALSE; + + if (unlikely (cr->status)) + return FALSE; + + status = cr->backend->in_clip (cr, x, y, &inside); + if (unlikely (status)) + _cairo_set_error (cr, status); + + return inside; +} + +/** + * cairo_copy_clip_rectangle_list: + * @cr: a cairo context + * + * Gets the current clip region as a list of rectangles in user coordinates. + * Never returns %NULL. + * + * The status in the list may be %CAIRO_STATUS_CLIP_NOT_REPRESENTABLE to + * indicate that the clip region cannot be represented as a list of + * user-space rectangles. The status may have other values to indicate + * other errors. + * + * Returns: the current clip region as a list of rectangles in user coordinates, + * which should be destroyed using cairo_rectangle_list_destroy(). + * + * Since: 1.4 + **/ +cairo_rectangle_list_t * +cairo_copy_clip_rectangle_list (cairo_t *cr) +{ + if (unlikely (cr->status)) + return _cairo_rectangle_list_create_in_error (cr->status); + + return cr->backend->clip_copy_rectangle_list (cr); +} + +/** + * CAIRO_TAG_DEST: + * + * Create a destination for a hyperlink. Destination tag attributes + * are detailed at [Destinations][dest]. + * + * Since: 1.16 + **/ + +/** + * CAIRO_TAG_LINK: + * + * Create hyperlink. Link tag attributes are detailed at + * [Links][link]. + * + * Since: 1.16 + **/ + +/** + * CAIRO_TAG_CONTENT: + * + * Create a content tag. + * + * Since: 1.18 + **/ + +/** + * CAIRO_TAG_CONTENT_REF: + * + * Create a content reference tag. + * + * Since: 1.18 + **/ + +/** + * cairo_tag_begin: + * @cr: a cairo context + * @tag_name: tag name + * @attributes: tag attributes + * + * Marks the beginning of the @tag_name structure. Call + * cairo_tag_end() with the same @tag_name to mark the end of the + * structure. + * + * The attributes string is of the form "key1=value2 key2=value2 ...". + * Values may be boolean (true/false or 1/0), integer, float, string, + * or an array. + * + * String values are enclosed in single quotes + * ('). Single quotes and backslashes inside the string should be + * escaped with a backslash. + * + * Boolean values may be set to true by only + * specifying the key. eg the attribute string "key" is the equivalent + * to "key=true". + * + * Arrays are enclosed in '[]'. eg "rect=[1.2 4.3 2.0 3.0]". + * + * If no attributes are required, @attributes can be an empty string or NULL. + * + * See [Tags and Links Description][cairo-Tags-and-Links.description] + * for the list of tags and attributes. + * + * Invalid nesting of tags or invalid attributes will cause @cr to + * shutdown with a status of %CAIRO_STATUS_TAG_ERROR. + * + * See cairo_tag_end(). + * + * Since: 1.16 + **/ +void +cairo_tag_begin (cairo_t *cr, const char *tag_name, const char *attributes) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->tag_begin (cr, tag_name, attributes); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_tag_end: + * @cr: a cairo context + * @tag_name: tag name + * + * Marks the end of the @tag_name structure. + * + * Invalid nesting of tags will cause @cr to shutdown with a status of + * %CAIRO_STATUS_TAG_ERROR. + * + * See cairo_tag_begin(). + * + * Since: 1.16 + **/ +cairo_public void +cairo_tag_end (cairo_t *cr, const char *tag_name) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->tag_end (cr, tag_name); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_select_font_face: + * @cr: a #cairo_t + * @family: a font family name, encoded in UTF-8 + * @slant: the slant for the font + * @weight: the weight for the font + * + * Note: The cairo_select_font_face() function call is part of what + * the cairo designers call the "toy" text API. It is convenient for + * short demos and simple programs, but it is not expected to be + * adequate for serious text-using applications. + * + * Selects a family and style of font from a simplified description as + * a family name, slant and weight. Cairo provides no operation to + * list available family names on the system (this is a "toy", + * remember), but the standard CSS2 generic family names, ("serif", + * "sans-serif", "cursive", "fantasy", "monospace"), are likely to + * work as expected. + * + * If @family starts with the string "\@cairo:", or if no native font + * backends are compiled in, cairo will use an internal font family. + * The internal font family recognizes many modifiers in the @family + * string, most notably, it recognizes the string "monospace". That is, + * the family name "\@cairo:monospace" will use the monospace version of + * the internal font family. + * + * For "real" font selection, see the font-backend-specific + * font_face_create functions for the font backend you are using. (For + * example, if you are using the freetype-based cairo-ft font backend, + * see cairo_ft_font_face_create_for_ft_face() or + * cairo_ft_font_face_create_for_pattern().) The resulting font face + * could then be used with cairo_scaled_font_create() and + * cairo_set_scaled_font(). + * + * Similarly, when using the "real" font support, you can call + * directly into the underlying font system, (such as fontconfig or + * freetype), for operations such as listing available fonts, etc. + * + * It is expected that most applications will need to use a more + * comprehensive font handling and text layout library, (for example, + * pango), in conjunction with cairo. + * + * If text is drawn without a call to cairo_select_font_face(), (nor + * cairo_set_font_face() nor cairo_set_scaled_font()), the default + * family is platform-specific, but is essentially "sans-serif". + * Default slant is %CAIRO_FONT_SLANT_NORMAL, and default weight is + * %CAIRO_FONT_WEIGHT_NORMAL. + * + * This function is equivalent to a call to cairo_toy_font_face_create() + * followed by cairo_set_font_face(). + * + * Since: 1.0 + **/ +void +cairo_select_font_face (cairo_t *cr, + const char *family, + cairo_font_slant_t slant, + cairo_font_weight_t weight) +{ + cairo_font_face_t *font_face; + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + font_face = cairo_toy_font_face_create (family, slant, weight); + if (unlikely (font_face->status)) { + _cairo_set_error (cr, font_face->status); + return; + } + + status = cr->backend->set_font_face (cr, font_face); + cairo_font_face_destroy (font_face); + + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_font_extents: + * @cr: a #cairo_t + * @extents: a #cairo_font_extents_t object into which the results + * will be stored. + * + * Gets the font extents for the currently selected font. + * + * Since: 1.0 + **/ +void +cairo_font_extents (cairo_t *cr, + cairo_font_extents_t *extents) +{ + cairo_status_t status; + + extents->ascent = 0.0; + extents->descent = 0.0; + extents->height = 0.0; + extents->max_x_advance = 0.0; + extents->max_y_advance = 0.0; + + if (unlikely (cr->status)) + return; + + status = cr->backend->font_extents (cr, extents); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_set_font_face: + * @cr: a #cairo_t + * @font_face: a #cairo_font_face_t, or %NULL to restore to the default font + * + * Replaces the current #cairo_font_face_t object in the #cairo_t with + * @font_face. The replaced font face in the #cairo_t will be + * destroyed if there are no other references to it. + * + * Since: 1.0 + **/ +void +cairo_set_font_face (cairo_t *cr, + cairo_font_face_t *font_face) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->set_font_face (cr, font_face); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_get_font_face: + * @cr: a #cairo_t + * + * Gets the current font face for a #cairo_t. + * + * Return value: the current font face. This object is owned by + * cairo. To keep a reference to it, you must call + * cairo_font_face_reference(). + * + * This function never returns %NULL. If memory cannot be allocated, a + * special "nil" #cairo_font_face_t object will be returned on which + * cairo_font_face_status() returns %CAIRO_STATUS_NO_MEMORY. Using + * this nil object will cause its error state to propagate to other + * objects it is passed to, (for example, calling + * cairo_set_font_face() with a nil font will trigger an error that + * will shutdown the #cairo_t object). + * + * Since: 1.0 + **/ +cairo_font_face_t * +cairo_get_font_face (cairo_t *cr) +{ + if (unlikely (cr->status)) + return (cairo_font_face_t*) &_cairo_font_face_nil; + + return cr->backend->get_font_face (cr); +} + +/** + * cairo_set_font_size: + * @cr: a #cairo_t + * @size: the new font size, in user space units + * + * Sets the current font matrix to a scale by a factor of @size, replacing + * any font matrix previously set with cairo_set_font_size() or + * cairo_set_font_matrix(). This results in a font size of @size user space + * units. (More precisely, this matrix will result in the font's + * em-square being a @size by @size square in user space.) + * + * If text is drawn without a call to cairo_set_font_size(), (nor + * cairo_set_font_matrix() nor cairo_set_scaled_font()), the default + * font size is 10.0. + * + * Since: 1.0 + **/ +void +cairo_set_font_size (cairo_t *cr, double size) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->set_font_size (cr, size); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_set_font_matrix: + * @cr: a #cairo_t + * @matrix: a #cairo_matrix_t describing a transform to be applied to + * the current font. + * + * Sets the current font matrix to @matrix. The font matrix gives a + * transformation from the design space of the font (in this space, + * the em-square is 1 unit by 1 unit) to user space. Normally, a + * simple scale is used (see cairo_set_font_size()), but a more + * complex font matrix can be used to shear the font + * or stretch it unequally along the two axes + * + * Since: 1.0 + **/ +void +cairo_set_font_matrix (cairo_t *cr, + const cairo_matrix_t *matrix) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cr->backend->set_font_matrix (cr, matrix); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_get_font_matrix: + * @cr: a #cairo_t + * @matrix: return value for the matrix + * + * Stores the current font matrix into @matrix. See + * cairo_set_font_matrix(). + * + * Since: 1.0 + **/ +void +cairo_get_font_matrix (cairo_t *cr, cairo_matrix_t *matrix) +{ + if (unlikely (cr->status)) { + cairo_matrix_init_identity (matrix); + return; + } + + cr->backend->get_font_matrix (cr, matrix); +} + +/** + * cairo_set_font_options: + * @cr: a #cairo_t + * @options: font options to use + * + * Sets a set of custom font rendering options for the #cairo_t. + * Rendering options are derived by merging these options with the + * options derived from underlying surface; if the value in @options + * has a default value (like %CAIRO_ANTIALIAS_DEFAULT), then the value + * from the surface is used. + * + * Since: 1.0 + **/ +void +cairo_set_font_options (cairo_t *cr, + const cairo_font_options_t *options) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + status = cairo_font_options_status ((cairo_font_options_t *) options); + if (unlikely (status)) { + _cairo_set_error (cr, status); + return; + } + + status = cr->backend->set_font_options (cr, options); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_get_font_options: + * @cr: a #cairo_t + * @options: a #cairo_font_options_t object into which to store + * the retrieved options. All existing values are overwritten + * + * Retrieves font rendering options set via #cairo_set_font_options. + * Note that the returned options do not include any options derived + * from the underlying surface; they are literally the options + * passed to cairo_set_font_options(). + * + * Since: 1.0 + **/ +void +cairo_get_font_options (cairo_t *cr, + cairo_font_options_t *options) +{ + /* check that we aren't trying to overwrite the nil object */ + if (cairo_font_options_status (options)) + return; + + if (unlikely (cr->status)) { + _cairo_font_options_init_default (options); + return; + } + + cr->backend->get_font_options (cr, options); +} + +/** + * cairo_set_scaled_font: + * @cr: a #cairo_t + * @scaled_font: a #cairo_scaled_font_t + * + * Replaces the current font face, font matrix, and font options in + * the #cairo_t with those of the #cairo_scaled_font_t. Except for + * some translation, the current CTM of the #cairo_t should be the + * same as that of the #cairo_scaled_font_t, which can be accessed + * using cairo_scaled_font_get_ctm(). + * + * Since: 1.2 + **/ +void +cairo_set_scaled_font (cairo_t *cr, + const cairo_scaled_font_t *scaled_font) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + if (scaled_font == NULL) { + _cairo_set_error (cr, _cairo_error (CAIRO_STATUS_NULL_POINTER)); + return; + } + + status = scaled_font->status; + if (unlikely (status)) { + _cairo_set_error (cr, status); + return; + } + + status = cr->backend->set_scaled_font (cr, (cairo_scaled_font_t *) scaled_font); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_get_scaled_font: + * @cr: a #cairo_t + * + * Gets the current scaled font for a #cairo_t. + * + * Return value: the current scaled font. This object is owned by + * cairo. To keep a reference to it, you must call + * cairo_scaled_font_reference(). + * + * This function never returns %NULL. If memory cannot be allocated, a + * special "nil" #cairo_scaled_font_t object will be returned on which + * cairo_scaled_font_status() returns %CAIRO_STATUS_NO_MEMORY. Using + * this nil object will cause its error state to propagate to other + * objects it is passed to, (for example, calling + * cairo_set_scaled_font() with a nil font will trigger an error that + * will shutdown the #cairo_t object). + * + * Since: 1.4 + **/ +cairo_scaled_font_t * +cairo_get_scaled_font (cairo_t *cr) +{ + if (unlikely (cr->status)) + return _cairo_scaled_font_create_in_error (cr->status); + + return cr->backend->get_scaled_font (cr); +} + +/** + * cairo_text_extents: + * @cr: a #cairo_t + * @utf8: a NUL-terminated string of text encoded in UTF-8, or %NULL + * @extents: a #cairo_text_extents_t object into which the results + * will be stored + * + * Gets the extents for a string of text. The extents describe a + * user-space rectangle that encloses the "inked" portion of the text, + * (as it would be drawn by cairo_show_text()). Additionally, the + * x_advance and y_advance values indicate the amount by which the + * current point would be advanced by cairo_show_text(). + * + * Note that whitespace characters do not directly contribute to the + * size of the rectangle (extents.width and extents.height). They do + * contribute indirectly by changing the position of non-whitespace + * characters. In particular, trailing whitespace characters are + * likely to not affect the size of the rectangle, though they will + * affect the x_advance and y_advance values. + * + * Since: 1.0 + **/ +void +cairo_text_extents (cairo_t *cr, + const char *utf8, + cairo_text_extents_t *extents) +{ + cairo_status_t status; + cairo_scaled_font_t *scaled_font; + cairo_glyph_t *glyphs = NULL; + int num_glyphs = 0; + double x, y; + + extents->x_bearing = 0.0; + extents->y_bearing = 0.0; + extents->width = 0.0; + extents->height = 0.0; + extents->x_advance = 0.0; + extents->y_advance = 0.0; + + if (unlikely (cr->status)) + return; + + if (utf8 == NULL) + return; + + scaled_font = cairo_get_scaled_font (cr); + if (unlikely (scaled_font->status)) { + _cairo_set_error (cr, scaled_font->status); + return; + } + + cairo_get_current_point (cr, &x, &y); + status = cairo_scaled_font_text_to_glyphs (scaled_font, + x, y, + utf8, -1, + &glyphs, &num_glyphs, + NULL, NULL, NULL); + + if (likely (status == CAIRO_STATUS_SUCCESS)) { + status = cr->backend->glyph_extents (cr, + glyphs, num_glyphs, + extents); + } + cairo_glyph_free (glyphs); + + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_glyph_extents: + * @cr: a #cairo_t + * @glyphs: an array of #cairo_glyph_t objects + * @num_glyphs: the number of elements in @glyphs + * @extents: a #cairo_text_extents_t object into which the results + * will be stored + * + * Gets the extents for an array of glyphs. The extents describe a + * user-space rectangle that encloses the "inked" portion of the + * glyphs, (as they would be drawn by cairo_show_glyphs()). + * Additionally, the x_advance and y_advance values indicate the + * amount by which the current point would be advanced by + * cairo_show_glyphs(). + * + * Note that whitespace glyphs do not contribute to the size of the + * rectangle (extents.width and extents.height). + * + * Since: 1.0 + **/ +void +cairo_glyph_extents (cairo_t *cr, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_text_extents_t *extents) +{ + cairo_status_t status; + + extents->x_bearing = 0.0; + extents->y_bearing = 0.0; + extents->width = 0.0; + extents->height = 0.0; + extents->x_advance = 0.0; + extents->y_advance = 0.0; + + if (unlikely (cr->status)) + return; + + if (num_glyphs == 0) + return; + + if (unlikely (num_glyphs < 0)) { + _cairo_set_error (cr, CAIRO_STATUS_NEGATIVE_COUNT); + return; + } + + if (unlikely (glyphs == NULL)) { + _cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER); + return; + } + + status = cr->backend->glyph_extents (cr, glyphs, num_glyphs, extents); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_show_text: + * @cr: a cairo context + * @utf8: a NUL-terminated string of text encoded in UTF-8, or %NULL + * + * A drawing operator that generates the shape from a string of UTF-8 + * characters, rendered according to the current font_face, font_size + * (font_matrix), and font_options. + * + * This function first computes a set of glyphs for the string of + * text. The first glyph is placed so that its origin is at the + * current point. The origin of each subsequent glyph is offset from + * that of the previous glyph by the advance values of the previous + * glyph. + * + * After this call the current point is moved to the origin of where + * the next glyph would be placed in this same progression. That is, + * the current point will be at the origin of the final glyph offset + * by its advance values. This allows for easy display of a single + * logical string with multiple calls to cairo_show_text(). + * + * Note: The cairo_show_text() function call is part of what the cairo + * designers call the "toy" text API. It is convenient for short demos + * and simple programs, but it is not expected to be adequate for + * serious text-using applications. See cairo_show_glyphs() for the + * "real" text display API in cairo. + * + * Since: 1.0 + **/ +void +cairo_show_text (cairo_t *cr, const char *utf8) +{ + cairo_text_extents_t extents; + cairo_status_t status; + cairo_glyph_t *glyphs, *last_glyph; + cairo_text_cluster_t *clusters; + int utf8_len, num_glyphs, num_clusters; + cairo_text_cluster_flags_t cluster_flags; + double x, y; + cairo_bool_t has_show_text_glyphs; + cairo_glyph_t stack_glyphs[CAIRO_STACK_ARRAY_LENGTH (cairo_glyph_t)]; + cairo_text_cluster_t stack_clusters[CAIRO_STACK_ARRAY_LENGTH (cairo_text_cluster_t)]; + cairo_scaled_font_t *scaled_font; + cairo_glyph_text_info_t info, *i; + + if (unlikely (cr->status)) + return; + + if (utf8 == NULL) + return; + + scaled_font = cairo_get_scaled_font (cr); + if (unlikely (scaled_font->status)) { + _cairo_set_error (cr, scaled_font->status); + return; + } + + utf8_len = strlen (utf8); + + has_show_text_glyphs = + cairo_surface_has_show_text_glyphs (cairo_get_target (cr)); + + glyphs = stack_glyphs; + num_glyphs = ARRAY_LENGTH (stack_glyphs); + + if (has_show_text_glyphs) { + clusters = stack_clusters; + num_clusters = ARRAY_LENGTH (stack_clusters); + } else { + clusters = NULL; + num_clusters = 0; + } + + cairo_get_current_point (cr, &x, &y); + status = cairo_scaled_font_text_to_glyphs (scaled_font, + x, y, + utf8, utf8_len, + &glyphs, &num_glyphs, + has_show_text_glyphs ? &clusters : NULL, &num_clusters, + &cluster_flags); + if (unlikely (status)) + goto BAIL; + + if (num_glyphs == 0) + return; + + i = NULL; + if (has_show_text_glyphs) { + info.utf8 = utf8; + info.utf8_len = utf8_len; + info.clusters = clusters; + info.num_clusters = num_clusters; + info.cluster_flags = cluster_flags; + i = &info; + } + + status = cr->backend->glyphs (cr, glyphs, num_glyphs, i); + if (unlikely (status)) + goto BAIL; + + last_glyph = &glyphs[num_glyphs - 1]; + status = cr->backend->glyph_extents (cr, last_glyph, 1, &extents); + if (unlikely (status)) + goto BAIL; + + x = last_glyph->x + extents.x_advance; + y = last_glyph->y + extents.y_advance; + cr->backend->move_to (cr, x, y); + + BAIL: + if (glyphs != stack_glyphs) + cairo_glyph_free (glyphs); + if (clusters != stack_clusters) + cairo_text_cluster_free (clusters); + + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_show_glyphs: + * @cr: a cairo context + * @glyphs: array of glyphs to show + * @num_glyphs: number of glyphs to show + * + * A drawing operator that generates the shape from an array of glyphs, + * rendered according to the current font face, font size + * (font matrix), and font options. + * + * Since: 1.0 + **/ +void +cairo_show_glyphs (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + if (num_glyphs == 0) + return; + + if (num_glyphs < 0) { + _cairo_set_error (cr, CAIRO_STATUS_NEGATIVE_COUNT); + return; + } + + if (glyphs == NULL) { + _cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER); + return; + } + + status = cr->backend->glyphs (cr, glyphs, num_glyphs, NULL); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_show_text_glyphs: + * @cr: a cairo context + * @utf8: a string of text encoded in UTF-8 + * @utf8_len: length of @utf8 in bytes, or -1 if it is NUL-terminated + * @glyphs: array of glyphs to show + * @num_glyphs: number of glyphs to show + * @clusters: array of cluster mapping information + * @num_clusters: number of clusters in the mapping + * @cluster_flags: cluster mapping flags + * + * This operation has rendering effects similar to cairo_show_glyphs() + * but, if the target surface supports it, uses the provided text and + * cluster mapping to embed the text for the glyphs shown in the output. + * If the target does not support the extended attributes, this function + * acts like the basic cairo_show_glyphs() as if it had been passed + * @glyphs and @num_glyphs. + * + * The mapping between @utf8 and @glyphs is provided by an array of + * clusters. Each cluster covers a number of + * text bytes and glyphs, and neighboring clusters cover neighboring + * areas of @utf8 and @glyphs. The clusters should collectively cover @utf8 + * and @glyphs in entirety. + * + * The first cluster always covers bytes from the beginning of @utf8. + * If @cluster_flags do not have the %CAIRO_TEXT_CLUSTER_FLAG_BACKWARD + * set, the first cluster also covers the beginning + * of @glyphs, otherwise it covers the end of the @glyphs array and + * following clusters move backward. + * + * See #cairo_text_cluster_t for constraints on valid clusters. + * + * Since: 1.8 + **/ +void +cairo_show_text_glyphs (cairo_t *cr, + const char *utf8, + int utf8_len, + const cairo_glyph_t *glyphs, + int num_glyphs, + const cairo_text_cluster_t *clusters, + int num_clusters, + cairo_text_cluster_flags_t cluster_flags) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + /* A slew of sanity checks */ + + /* Special case for NULL and -1 */ + if (utf8 == NULL && utf8_len == -1) + utf8_len = 0; + + /* No NULLs for non-zeros */ + if ((num_glyphs && glyphs == NULL) || + (utf8_len && utf8 == NULL) || + (num_clusters && clusters == NULL)) { + _cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER); + return; + } + + /* A -1 for utf8_len means NUL-terminated */ + if (utf8_len == -1) + utf8_len = strlen (utf8); + + /* Apart from that, no negatives */ + if (num_glyphs < 0 || utf8_len < 0 || num_clusters < 0) { + _cairo_set_error (cr, CAIRO_STATUS_NEGATIVE_COUNT); + return; + } + + if (num_glyphs == 0 && utf8_len == 0) + return; + + if (utf8) { + /* Make sure clusters cover the entire glyphs and utf8 arrays, + * and that cluster boundaries are UTF-8 boundaries. */ + status = _cairo_validate_text_clusters (utf8, utf8_len, + glyphs, num_glyphs, + clusters, num_clusters, cluster_flags); + if (status == CAIRO_STATUS_INVALID_CLUSTERS) { + /* Either got invalid UTF-8 text, or cluster mapping is bad. + * Differentiate those. */ + + cairo_status_t status2; + + status2 = _cairo_utf8_to_ucs4 (utf8, utf8_len, NULL, NULL); + if (status2) + status = status2; + } else { + cairo_glyph_text_info_t info; + + info.utf8 = utf8; + info.utf8_len = utf8_len; + info.clusters = clusters; + info.num_clusters = num_clusters; + info.cluster_flags = cluster_flags; + + status = cr->backend->glyphs (cr, glyphs, num_glyphs, &info); + } + } else { + status = cr->backend->glyphs (cr, glyphs, num_glyphs, NULL); + } + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_text_path: + * @cr: a cairo context + * @utf8: a NUL-terminated string of text encoded in UTF-8, or %NULL + * + * Adds closed paths for text to the current path. The generated + * path if filled, achieves an effect similar to that of + * cairo_show_text(). + * + * Text conversion and positioning is done similar to cairo_show_text(). + * + * Like cairo_show_text(), After this call the current point is + * moved to the origin of where the next glyph would be placed in + * this same progression. That is, the current point will be at + * the origin of the final glyph offset by its advance values. + * This allows for chaining multiple calls to to cairo_text_path() + * without having to set current point in between. + * + * Note: The cairo_text_path() function call is part of what the cairo + * designers call the "toy" text API. It is convenient for short demos + * and simple programs, but it is not expected to be adequate for + * serious text-using applications. See cairo_glyph_path() for the + * "real" text path API in cairo. + * + * Since: 1.0 + **/ +void +cairo_text_path (cairo_t *cr, const char *utf8) +{ + cairo_status_t status; + cairo_text_extents_t extents; + cairo_glyph_t stack_glyphs[CAIRO_STACK_ARRAY_LENGTH (cairo_glyph_t)]; + cairo_glyph_t *glyphs, *last_glyph; + cairo_scaled_font_t *scaled_font; + int num_glyphs; + double x, y; + + if (unlikely (cr->status)) + return; + + if (utf8 == NULL) + return; + + + glyphs = stack_glyphs; + num_glyphs = ARRAY_LENGTH (stack_glyphs); + + scaled_font = cairo_get_scaled_font (cr); + if (unlikely (scaled_font->status)) { + _cairo_set_error (cr, scaled_font->status); + return; + } + + cairo_get_current_point (cr, &x, &y); + status = cairo_scaled_font_text_to_glyphs (scaled_font, + x, y, + utf8, -1, + &glyphs, &num_glyphs, + NULL, NULL, NULL); + + if (num_glyphs == 0) + return; + + status = cr->backend->glyph_path (cr, glyphs, num_glyphs); + + if (unlikely (status)) + goto BAIL; + + last_glyph = &glyphs[num_glyphs - 1]; + status = cr->backend->glyph_extents (cr, last_glyph, 1, &extents); + + if (unlikely (status)) + goto BAIL; + + x = last_glyph->x + extents.x_advance; + y = last_glyph->y + extents.y_advance; + cr->backend->move_to (cr, x, y); + + BAIL: + if (glyphs != stack_glyphs) + cairo_glyph_free (glyphs); + + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_glyph_path: + * @cr: a cairo context + * @glyphs: array of glyphs to show + * @num_glyphs: number of glyphs to show + * + * Adds closed paths for the glyphs to the current path. The generated + * path if filled, achieves an effect similar to that of + * cairo_show_glyphs(). + * + * Since: 1.0 + **/ +void +cairo_glyph_path (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + if (num_glyphs == 0) + return; + + if (unlikely (num_glyphs < 0)) { + _cairo_set_error (cr, CAIRO_STATUS_NEGATIVE_COUNT); + return; + } + + if (unlikely (glyphs == NULL)) { + _cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER); + return; + } + + status = cr->backend->glyph_path (cr, glyphs, num_glyphs); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_get_operator: + * @cr: a cairo context + * + * Gets the current compositing operator for a cairo context. + * + * Return value: the current compositing operator. + * + * Since: 1.0 + **/ +cairo_operator_t +cairo_get_operator (cairo_t *cr) +{ + if (unlikely (cr->status)) + return CAIRO_GSTATE_OPERATOR_DEFAULT; + + return cr->backend->get_operator (cr); +} + +#if 0 +/* + * cairo_get_opacity: + * @cr: a cairo context + * + * Gets the current compositing opacity for a cairo context. + * + * Return value: the current compositing opacity. + * + * Since: TBD + **/ +double +cairo_get_opacity (cairo_t *cr) +{ + if (unlikely (cr->status)) + return 1.; + + return cr->backend->get_opacity (cr); +} +#endif + +/** + * cairo_get_tolerance: + * @cr: a cairo context + * + * Gets the current tolerance value, as set by cairo_set_tolerance(). + * + * Return value: the current tolerance value. + * + * Since: 1.0 + **/ +double +cairo_get_tolerance (cairo_t *cr) +{ + if (unlikely (cr->status)) + return CAIRO_GSTATE_TOLERANCE_DEFAULT; + + return cr->backend->get_tolerance (cr); +} + +/** + * cairo_get_antialias: + * @cr: a cairo context + * + * Gets the current shape antialiasing mode, as set by + * cairo_set_antialias(). + * + * Return value: the current shape antialiasing mode. + * + * Since: 1.0 + **/ +cairo_antialias_t +cairo_get_antialias (cairo_t *cr) +{ + if (unlikely (cr->status)) + return CAIRO_ANTIALIAS_DEFAULT; + + return cr->backend->get_antialias (cr); +} + +/** + * cairo_has_current_point: + * @cr: a cairo context + * + * Returns whether a current point is defined on the current path. + * See cairo_get_current_point() for details on the current point. + * + * Return value: whether a current point is defined. + * + * Since: 1.6 + **/ +cairo_bool_t +cairo_has_current_point (cairo_t *cr) +{ + if (unlikely (cr->status)) + return FALSE; + + return cr->backend->has_current_point (cr); +} + +/** + * cairo_get_current_point: + * @cr: a cairo context + * @x: return value for X coordinate of the current point + * @y: return value for Y coordinate of the current point + * + * Gets the current point of the current path, which is + * conceptually the final point reached by the path so far. + * + * The current point is returned in the user-space coordinate + * system. If there is no defined current point or if @cr is in an + * error status, @x and @y will both be set to 0.0. It is possible to + * check this in advance with cairo_has_current_point(). + * + * Most path construction functions alter the current point. See the + * following for details on how they affect the current point: + * cairo_new_path(), cairo_new_sub_path(), + * cairo_append_path(), cairo_close_path(), + * cairo_move_to(), cairo_line_to(), cairo_curve_to(), + * cairo_rel_move_to(), cairo_rel_line_to(), cairo_rel_curve_to(), + * cairo_arc(), cairo_arc_negative(), cairo_rectangle(), + * cairo_text_path(), cairo_glyph_path(). + * + * Some functions use and alter the current point but do not + * otherwise change current path: + * cairo_show_text(). + * + * Some functions unset the current path and as a result, current point: + * cairo_fill(), cairo_stroke(). + * + * Since: 1.0 + **/ +void +cairo_get_current_point (cairo_t *cr, double *x_ret, double *y_ret) +{ + double x, y; + + x = y = 0; + if (cr->status == CAIRO_STATUS_SUCCESS && + cr->backend->has_current_point (cr)) + { + cr->backend->get_current_point (cr, &x, &y); + } + + if (x_ret) + *x_ret = x; + if (y_ret) + *y_ret = y; +} + +/** + * cairo_get_fill_rule: + * @cr: a cairo context + * + * Gets the current fill rule, as set by cairo_set_fill_rule(). + * + * Return value: the current fill rule. + * + * Since: 1.0 + **/ +cairo_fill_rule_t +cairo_get_fill_rule (cairo_t *cr) +{ + if (unlikely (cr->status)) + return CAIRO_GSTATE_FILL_RULE_DEFAULT; + + return cr->backend->get_fill_rule (cr); +} + +/** + * cairo_get_line_width: + * @cr: a cairo context + * + * This function returns the current line width value exactly as set by + * cairo_set_line_width(). Note that the value is unchanged even if + * the CTM has changed between the calls to cairo_set_line_width() and + * cairo_get_line_width(). + * + * Return value: the current line width. + * + * Since: 1.0 + **/ +double +cairo_get_line_width (cairo_t *cr) +{ + if (unlikely (cr->status)) + return CAIRO_GSTATE_LINE_WIDTH_DEFAULT; + + return cr->backend->get_line_width (cr); +} + +/** + * cairo_get_hairline: + * @cr: a cairo context + * + * Returns whether or not hairline mode is set, as set by cairo_set_hairline(). + * + * Return value: whether hairline mode is set. + * + * Since: 1.18 + **/ +cairo_bool_t +cairo_get_hairline (cairo_t *cr) +{ + if (unlikely (cr->status)) + return FALSE; + + return cr->backend->get_hairline (cr); +} + +/** + * cairo_get_line_cap: + * @cr: a cairo context + * + * Gets the current line cap style, as set by cairo_set_line_cap(). + * + * Return value: the current line cap style. + * + * Since: 1.0 + **/ +cairo_line_cap_t +cairo_get_line_cap (cairo_t *cr) +{ + if (unlikely (cr->status)) + return CAIRO_GSTATE_LINE_CAP_DEFAULT; + + return cr->backend->get_line_cap (cr); +} + +/** + * cairo_get_line_join: + * @cr: a cairo context + * + * Gets the current line join style, as set by cairo_set_line_join(). + * + * Return value: the current line join style. + * + * Since: 1.0 + **/ +cairo_line_join_t +cairo_get_line_join (cairo_t *cr) +{ + if (unlikely (cr->status)) + return CAIRO_GSTATE_LINE_JOIN_DEFAULT; + + return cr->backend->get_line_join (cr); +} + +/** + * cairo_get_miter_limit: + * @cr: a cairo context + * + * Gets the current miter limit, as set by cairo_set_miter_limit(). + * + * Return value: the current miter limit. + * + * Since: 1.0 + **/ +double +cairo_get_miter_limit (cairo_t *cr) +{ + if (unlikely (cr->status)) + return CAIRO_GSTATE_MITER_LIMIT_DEFAULT; + + return cr->backend->get_miter_limit (cr); +} + +/** + * cairo_get_matrix: + * @cr: a cairo context + * @matrix: return value for the matrix + * + * Stores the current transformation matrix (CTM) into @matrix. + * + * Since: 1.0 + **/ +void +cairo_get_matrix (cairo_t *cr, cairo_matrix_t *matrix) +{ + if (unlikely (cr->status)) { + cairo_matrix_init_identity (matrix); + return; + } + + cr->backend->get_matrix (cr, matrix); +} + +/** + * cairo_get_target: + * @cr: a cairo context + * + * Gets the target surface for the cairo context as passed to + * cairo_create(). + * + * This function will always return a valid pointer, but the result + * can be a "nil" surface if @cr is already in an error state, + * (ie. cairo_status() != %CAIRO_STATUS_SUCCESS). + * A nil surface is indicated by cairo_surface_status() + * != %CAIRO_STATUS_SUCCESS. + * + * Return value: the target surface. This object is owned by cairo. To + * keep a reference to it, you must call cairo_surface_reference(). + * + * Since: 1.0 + **/ +cairo_surface_t * +cairo_get_target (cairo_t *cr) +{ + if (unlikely (cr->status)) + return _cairo_surface_create_in_error (cr->status); + + return cr->backend->get_original_target (cr); +} + +/** + * cairo_get_group_target: + * @cr: a cairo context + * + * Gets the current destination surface for the context. This is either + * the original target surface as passed to cairo_create() or the target + * surface for the current group as started by the most recent call to + * cairo_push_group() or cairo_push_group_with_content(). + * + * This function will always return a valid pointer, but the result + * can be a "nil" surface if @cr is already in an error state, + * (ie. cairo_status() != %CAIRO_STATUS_SUCCESS). + * A nil surface is indicated by cairo_surface_status() + * != %CAIRO_STATUS_SUCCESS. + * + * Return value: the target surface. This object is owned by cairo. To + * keep a reference to it, you must call cairo_surface_reference(). + * + * Since: 1.2 + **/ +cairo_surface_t * +cairo_get_group_target (cairo_t *cr) +{ + if (unlikely (cr->status)) + return _cairo_surface_create_in_error (cr->status); + + return cr->backend->get_current_target (cr); +} + +/** + * cairo_copy_path: + * @cr: a cairo context + * + * Creates a copy of the current path and returns it to the user as a + * #cairo_path_t. See #cairo_path_data_t for hints on how to iterate + * over the returned data structure. + * + * This function will always return a valid pointer, but the result + * will have no data (data==%NULL and + * num_data==0), if either of the following + * conditions hold: + * + * + * If there is insufficient memory to copy the path. In this + * case path->status will be set to + * %CAIRO_STATUS_NO_MEMORY. + * If @cr is already in an error state. In this case + * path->status will contain the same status that + * would be returned by cairo_status(). + * + * + * Return value: the copy of the current path. The caller owns the + * returned object and should call cairo_path_destroy() when finished + * with it. + * + * Since: 1.0 + **/ +cairo_path_t * +cairo_copy_path (cairo_t *cr) +{ + if (unlikely (cr->status)) + return _cairo_path_create_in_error (cr->status); + + return cr->backend->copy_path (cr); +} + +/** + * cairo_copy_path_flat: + * @cr: a cairo context + * + * Gets a flattened copy of the current path and returns it to the + * user as a #cairo_path_t. See #cairo_path_data_t for hints on + * how to iterate over the returned data structure. + * + * This function is like cairo_copy_path() except that any curves + * in the path will be approximated with piecewise-linear + * approximations, (accurate to within the current tolerance + * value). That is, the result is guaranteed to not have any elements + * of type %CAIRO_PATH_CURVE_TO which will instead be replaced by a + * series of %CAIRO_PATH_LINE_TO elements. + * + * This function will always return a valid pointer, but the result + * will have no data (data==%NULL and + * num_data==0), if either of the following + * conditions hold: + * + * + * If there is insufficient memory to copy the path. In this + * case path->status will be set to + * %CAIRO_STATUS_NO_MEMORY. + * If @cr is already in an error state. In this case + * path->status will contain the same status that + * would be returned by cairo_status(). + * + * + * Return value: the copy of the current path. The caller owns the + * returned object and should call cairo_path_destroy() when finished + * with it. + * + * Since: 1.0 + **/ +cairo_path_t * +cairo_copy_path_flat (cairo_t *cr) +{ + if (unlikely (cr->status)) + return _cairo_path_create_in_error (cr->status); + + return cr->backend->copy_path_flat (cr); +} + +/** + * cairo_append_path: + * @cr: a cairo context + * @path: path to be appended + * + * Append the @path onto the current path. The @path may be either the + * return value from one of cairo_copy_path() or + * cairo_copy_path_flat() or it may be constructed manually. See + * #cairo_path_t for details on how the path data structure should be + * initialized, and note that path->status must be + * initialized to %CAIRO_STATUS_SUCCESS. + * + * Since: 1.0 + **/ +void +cairo_append_path (cairo_t *cr, + const cairo_path_t *path) +{ + cairo_status_t status; + + if (unlikely (cr->status)) + return; + + if (unlikely (path == NULL)) { + _cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER); + return; + } + + if (unlikely (path->status)) { + if (path->status > CAIRO_STATUS_SUCCESS && + path->status <= CAIRO_STATUS_LAST_STATUS) + _cairo_set_error (cr, path->status); + else + _cairo_set_error (cr, CAIRO_STATUS_INVALID_STATUS); + return; + } + + if (path->num_data == 0) + return; + + if (unlikely (path->data == NULL)) { + _cairo_set_error (cr, CAIRO_STATUS_NULL_POINTER); + return; + } + + status = cr->backend->append_path (cr, path); + if (unlikely (status)) + _cairo_set_error (cr, status); +} + +/** + * cairo_status: + * @cr: a cairo context + * + * Checks whether an error has previously occurred for this context. + * + * Returns: the current status of this context, see #cairo_status_t + * + * Since: 1.0 + **/ +cairo_status_t +cairo_status (cairo_t *cr) +{ + return cr->status; +} diff --git a/local/recipes/libs/cairo/source/src/cairo.h b/local/recipes/libs/cairo/source/src/cairo.h new file mode 100644 index 0000000000..89e4a070e6 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairo.h @@ -0,0 +1,3348 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + */ + +#ifndef CAIRO_H +#define CAIRO_H + +#include "cairo-version.h" +#include "cairo-features.h" +#include "cairo-deprecated.h" + +#ifdef __cplusplus +# define CAIRO_BEGIN_DECLS extern "C" { +# define CAIRO_END_DECLS } +#else +# define CAIRO_BEGIN_DECLS +# define CAIRO_END_DECLS +#endif + +#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(CAIRO_WIN32_STATIC_BUILD) +# define _cairo_export __declspec(dllexport) +# define _cairo_import __declspec(dllimport) +#elif defined(__GNUC__) && (__GNUC__ >= 4) +# define _cairo_export __attribute__((__visibility__("default"))) +# define _cairo_import +#else +# define _cairo_export +# define _cairo_import +#endif + +#ifdef CAIRO_COMPILATION +# define _cairo_api _cairo_export +#else +# define _cairo_api _cairo_import +#endif + +#define cairo_public _cairo_api extern + +CAIRO_BEGIN_DECLS + +#define CAIRO_VERSION_ENCODE(major, minor, micro) ( \ + ((major) * 10000) \ + + ((minor) * 100) \ + + ((micro) * 1)) + +#define CAIRO_VERSION CAIRO_VERSION_ENCODE( \ + CAIRO_VERSION_MAJOR, \ + CAIRO_VERSION_MINOR, \ + CAIRO_VERSION_MICRO) + + +#define CAIRO_VERSION_STRINGIZE_(major, minor, micro) \ + #major"."#minor"."#micro +#define CAIRO_VERSION_STRINGIZE(major, minor, micro) \ + CAIRO_VERSION_STRINGIZE_(major, minor, micro) + +#define CAIRO_VERSION_STRING CAIRO_VERSION_STRINGIZE( \ + CAIRO_VERSION_MAJOR, \ + CAIRO_VERSION_MINOR, \ + CAIRO_VERSION_MICRO) + + +cairo_public int +cairo_version (void); + +cairo_public const char* +cairo_version_string (void); + +/** + * cairo_bool_t: + * + * #cairo_bool_t is used for boolean values. Returns of type + * #cairo_bool_t will always be either 0 or 1, but testing against + * these values explicitly is not encouraged; just use the + * value as a boolean condition. + * + * + * if (cairo_in_stroke (cr, x, y)) { + * /* do something */ + * } + * + * + * Since: 1.0 + **/ +typedef int cairo_bool_t; + +/** + * cairo_t: + * + * A #cairo_t contains the current state of the rendering device, + * including coordinates of yet to be drawn shapes. + * + * Cairo contexts, as #cairo_t objects are named, are central to + * cairo and all drawing with cairo is always done to a #cairo_t + * object. + * + * Memory management of #cairo_t is done with + * cairo_reference() and cairo_destroy(). + * + * Since: 1.0 + **/ +typedef struct _cairo cairo_t; + +/** + * cairo_surface_t: + * + * A #cairo_surface_t represents an image, either as the destination + * of a drawing operation or as source when drawing onto another + * surface. To draw to a #cairo_surface_t, create a cairo context + * with the surface as the target, using cairo_create(). + * + * There are different subtypes of #cairo_surface_t for + * different drawing backends; for example, cairo_image_surface_create() + * creates a bitmap image in memory. + * The type of a surface can be queried with cairo_surface_get_type(). + * + * The initial contents of a surface after creation depend upon the manner + * of its creation. If cairo creates the surface and backing storage for + * the user, it will be initially cleared; for example, + * cairo_image_surface_create() and cairo_surface_create_similar(). + * Alternatively, if the user passes in a reference to some backing storage + * and asks cairo to wrap that in a #cairo_surface_t, then the contents are + * not modified; for example, cairo_image_surface_create_for_data() and + * cairo_xlib_surface_create(). + * + * Memory management of #cairo_surface_t is done with + * cairo_surface_reference() and cairo_surface_destroy(). + * + * Since: 1.0 + **/ +typedef struct _cairo_surface cairo_surface_t; + +/** + * cairo_device_t: + * + * A #cairo_device_t represents the driver interface for drawing + * operations to a #cairo_surface_t. There are different subtypes of + * #cairo_device_t for different drawing backends. + * + * The type of a device can be queried with cairo_device_get_type(). + * + * Memory management of #cairo_device_t is done with + * cairo_device_reference() and cairo_device_destroy(). + * + * Since: 1.10 + **/ +typedef struct _cairo_device cairo_device_t; + +/** + * cairo_matrix_t: + * @xx: xx component of the affine transformation + * @yx: yx component of the affine transformation + * @xy: xy component of the affine transformation + * @yy: yy component of the affine transformation + * @x0: X translation component of the affine transformation + * @y0: Y translation component of the affine transformation + * + * A #cairo_matrix_t holds an affine transformation, such as a scale, + * rotation, shear, or a combination of those. The transformation of + * a point (x, y) is given by: + * + * x_new = xx * x + xy * y + x0; + * y_new = yx * x + yy * y + y0; + * + * + * Since: 1.0 + **/ +typedef struct _cairo_matrix { + double xx; double yx; + double xy; double yy; + double x0; double y0; +} cairo_matrix_t; + +/** + * cairo_pattern_t: + * + * A #cairo_pattern_t represents a source when drawing onto a + * surface. There are different subtypes of #cairo_pattern_t, + * for different types of sources; for example, + * cairo_pattern_create_rgb() creates a pattern for a solid + * opaque color. + * + * Other than various + * cairo_pattern_create_type() + * functions, some of the pattern types can be implicitly created using various + * cairo_set_source_type() functions; + * for example cairo_set_source_rgb(). + * + * The type of a pattern can be queried with cairo_pattern_get_type(). + * + * Memory management of #cairo_pattern_t is done with + * cairo_pattern_reference() and cairo_pattern_destroy(). + * + * Since: 1.0 + **/ +typedef struct _cairo_pattern cairo_pattern_t; + +/** + * cairo_destroy_func_t: + * @data: The data element being destroyed. + * + * #cairo_destroy_func_t the type of function which is called when a + * data element is destroyed. It is passed the pointer to the data + * element and should free any memory and resources allocated for it. + * + * Since: 1.0 + **/ +typedef void (*cairo_destroy_func_t) (void *data); + +/** + * cairo_user_data_key_t: + * @unused: not used; ignore. + * + * #cairo_user_data_key_t is used for attaching user data to cairo + * data structures. The actual contents of the struct is never used, + * and there is no need to initialize the object; only the unique + * address of a #cairo_data_key_t object is used. Typically, you + * would just use the address of a static #cairo_data_key_t object. + * + * Since: 1.0 + **/ +typedef struct _cairo_user_data_key { + int unused; +} cairo_user_data_key_t; + +/** + * cairo_status_t: + * @CAIRO_STATUS_SUCCESS: no error has occurred (Since 1.0) + * @CAIRO_STATUS_NO_MEMORY: out of memory (Since 1.0) + * @CAIRO_STATUS_INVALID_RESTORE: cairo_restore() called without matching cairo_save() (Since 1.0) + * @CAIRO_STATUS_INVALID_POP_GROUP: no saved group to pop, i.e. cairo_pop_group() without matching cairo_push_group() (Since 1.0) + * @CAIRO_STATUS_NO_CURRENT_POINT: no current point defined (Since 1.0) + * @CAIRO_STATUS_INVALID_MATRIX: invalid matrix (not invertible) (Since 1.0) + * @CAIRO_STATUS_INVALID_STATUS: invalid value for an input #cairo_status_t (Since 1.0) + * @CAIRO_STATUS_NULL_POINTER: %NULL pointer (Since 1.0) + * @CAIRO_STATUS_INVALID_STRING: input string not valid UTF-8 (Since 1.0) + * @CAIRO_STATUS_INVALID_PATH_DATA: input path data not valid (Since 1.0) + * @CAIRO_STATUS_READ_ERROR: error while reading from input stream (Since 1.0) + * @CAIRO_STATUS_WRITE_ERROR: error while writing to output stream (Since 1.0) + * @CAIRO_STATUS_SURFACE_FINISHED: target surface has been finished (Since 1.0) + * @CAIRO_STATUS_SURFACE_TYPE_MISMATCH: the surface type is not appropriate for the operation (Since 1.0) + * @CAIRO_STATUS_PATTERN_TYPE_MISMATCH: the pattern type is not appropriate for the operation (Since 1.0) + * @CAIRO_STATUS_INVALID_CONTENT: invalid value for an input #cairo_content_t (Since 1.0) + * @CAIRO_STATUS_INVALID_FORMAT: invalid value for an input #cairo_format_t (Since 1.0) + * @CAIRO_STATUS_INVALID_VISUAL: invalid value for an input Visual* (Since 1.0) + * @CAIRO_STATUS_FILE_NOT_FOUND: file not found (Since 1.0) + * @CAIRO_STATUS_INVALID_DASH: invalid value for a dash setting (Since 1.0) + * @CAIRO_STATUS_INVALID_DSC_COMMENT: invalid value for a DSC comment (Since 1.2) + * @CAIRO_STATUS_INVALID_INDEX: invalid index passed to getter (Since 1.4) + * @CAIRO_STATUS_CLIP_NOT_REPRESENTABLE: clip region not representable in desired format (Since 1.4) + * @CAIRO_STATUS_TEMP_FILE_ERROR: error creating or writing to a temporary file (Since 1.6) + * @CAIRO_STATUS_INVALID_STRIDE: invalid value for stride (Since 1.6) + * @CAIRO_STATUS_FONT_TYPE_MISMATCH: the font type is not appropriate for the operation (Since 1.8) + * @CAIRO_STATUS_USER_FONT_IMMUTABLE: the user-font is immutable (Since 1.8) + * @CAIRO_STATUS_USER_FONT_ERROR: error occurred in a user-font callback function (Since 1.8) + * @CAIRO_STATUS_NEGATIVE_COUNT: negative number used where it is not allowed (Since 1.8) + * @CAIRO_STATUS_INVALID_CLUSTERS: input clusters do not represent the accompanying text and glyph array (Since 1.8) + * @CAIRO_STATUS_INVALID_SLANT: invalid value for an input #cairo_font_slant_t (Since 1.8) + * @CAIRO_STATUS_INVALID_WEIGHT: invalid value for an input #cairo_font_weight_t (Since 1.8) + * @CAIRO_STATUS_INVALID_SIZE: invalid value (typically too big) for the size of the input (surface, pattern, etc.) (Since 1.10) + * @CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED: user-font method not implemented (Since 1.10) + * @CAIRO_STATUS_DEVICE_TYPE_MISMATCH: the device type is not appropriate for the operation (Since 1.10) + * @CAIRO_STATUS_DEVICE_ERROR: an operation to the device caused an unspecified error (Since 1.10) + * @CAIRO_STATUS_INVALID_MESH_CONSTRUCTION: a mesh pattern + * construction operation was used outside of a + * cairo_mesh_pattern_begin_patch()/cairo_mesh_pattern_end_patch() + * pair (Since 1.12) + * @CAIRO_STATUS_DEVICE_FINISHED: target device has been finished (Since 1.12) + * @CAIRO_STATUS_JBIG2_GLOBAL_MISSING: %CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID has been used on at least one image + * but no image provided %CAIRO_MIME_TYPE_JBIG2_GLOBAL (Since 1.14) + * @CAIRO_STATUS_PNG_ERROR: error occurred in libpng while reading from or writing to a PNG file (Since 1.16) + * @CAIRO_STATUS_FREETYPE_ERROR: error occurred in libfreetype (Since 1.16) + * @CAIRO_STATUS_WIN32_GDI_ERROR: error occurred in the Windows Graphics Device Interface (Since 1.16) + * @CAIRO_STATUS_TAG_ERROR: invalid tag name, attributes, or nesting (Since 1.16) + * @CAIRO_STATUS_DWRITE_ERROR: error occurred in the Windows Direct Write API (Since 1.18) + * @CAIRO_STATUS_SVG_FONT_ERROR: error occurred in OpenType-SVG font rendering (Since 1.18) + * @CAIRO_STATUS_LAST_STATUS: this is a special value indicating the number of + * status values defined in this enumeration. When using this value, note + * that the version of cairo at run-time may have additional status values + * defined than the value of this symbol at compile-time. (Since 1.10) + * + * #cairo_status_t is used to indicate errors that can occur when + * using Cairo. In some cases it is returned directly by functions. + * but when using #cairo_t, the last error, if any, is stored in + * the context and can be retrieved with cairo_status(). + * + * New entries may be added in future versions. Use cairo_status_to_string() + * to get a human-readable representation of an error message. + * + * Since: 1.0 + **/ +typedef enum _cairo_status { + CAIRO_STATUS_SUCCESS = 0, + + CAIRO_STATUS_NO_MEMORY, + CAIRO_STATUS_INVALID_RESTORE, + CAIRO_STATUS_INVALID_POP_GROUP, + CAIRO_STATUS_NO_CURRENT_POINT, + CAIRO_STATUS_INVALID_MATRIX, + CAIRO_STATUS_INVALID_STATUS, + CAIRO_STATUS_NULL_POINTER, + CAIRO_STATUS_INVALID_STRING, + CAIRO_STATUS_INVALID_PATH_DATA, + CAIRO_STATUS_READ_ERROR, + CAIRO_STATUS_WRITE_ERROR, + CAIRO_STATUS_SURFACE_FINISHED, + CAIRO_STATUS_SURFACE_TYPE_MISMATCH, + CAIRO_STATUS_PATTERN_TYPE_MISMATCH, + CAIRO_STATUS_INVALID_CONTENT, + CAIRO_STATUS_INVALID_FORMAT, + CAIRO_STATUS_INVALID_VISUAL, + CAIRO_STATUS_FILE_NOT_FOUND, + CAIRO_STATUS_INVALID_DASH, + CAIRO_STATUS_INVALID_DSC_COMMENT, + CAIRO_STATUS_INVALID_INDEX, + CAIRO_STATUS_CLIP_NOT_REPRESENTABLE, + CAIRO_STATUS_TEMP_FILE_ERROR, + CAIRO_STATUS_INVALID_STRIDE, + CAIRO_STATUS_FONT_TYPE_MISMATCH, + CAIRO_STATUS_USER_FONT_IMMUTABLE, + CAIRO_STATUS_USER_FONT_ERROR, + CAIRO_STATUS_NEGATIVE_COUNT, + CAIRO_STATUS_INVALID_CLUSTERS, + CAIRO_STATUS_INVALID_SLANT, + CAIRO_STATUS_INVALID_WEIGHT, + CAIRO_STATUS_INVALID_SIZE, + CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED, + CAIRO_STATUS_DEVICE_TYPE_MISMATCH, + CAIRO_STATUS_DEVICE_ERROR, + CAIRO_STATUS_INVALID_MESH_CONSTRUCTION, + CAIRO_STATUS_DEVICE_FINISHED, + CAIRO_STATUS_JBIG2_GLOBAL_MISSING, + CAIRO_STATUS_PNG_ERROR, + CAIRO_STATUS_FREETYPE_ERROR, + CAIRO_STATUS_WIN32_GDI_ERROR, + CAIRO_STATUS_TAG_ERROR, + CAIRO_STATUS_DWRITE_ERROR, + CAIRO_STATUS_SVG_FONT_ERROR, + + CAIRO_STATUS_LAST_STATUS +} cairo_status_t; + +/** + * cairo_content_t: + * @CAIRO_CONTENT_COLOR: The surface will hold color content only. (Since 1.0) + * @CAIRO_CONTENT_ALPHA: The surface will hold alpha content only. (Since 1.0) + * @CAIRO_CONTENT_COLOR_ALPHA: The surface will hold color and alpha content. (Since 1.0) + * + * #cairo_content_t is used to describe the content that a surface will + * contain, whether color information, alpha information (translucence + * vs. opacity), or both. + * + * Note: The large values here are designed to keep #cairo_content_t + * values distinct from #cairo_format_t values so that the + * implementation can detect the error if users confuse the two types. + * + * Since: 1.0 + **/ +typedef enum _cairo_content { + CAIRO_CONTENT_COLOR = 0x1000, + CAIRO_CONTENT_ALPHA = 0x2000, + CAIRO_CONTENT_COLOR_ALPHA = 0x3000 +} cairo_content_t; + +/** + * cairo_format_t: + * @CAIRO_FORMAT_INVALID: no such format exists or is supported. + * @CAIRO_FORMAT_ARGB32: each pixel is a 32-bit quantity, with + * alpha in the upper 8 bits, then red, then green, then blue. + * The 32-bit quantities are stored native-endian. Pre-multiplied + * alpha is used. (That is, 50% transparent red is 0x80800000, + * not 0x80ff0000.) (Since 1.0) + * @CAIRO_FORMAT_RGB24: each pixel is a 32-bit quantity, with + * the upper 8 bits unused. Red, Green, and Blue are stored + * in the remaining 24 bits in that order. (Since 1.0) + * @CAIRO_FORMAT_A8: each pixel is a 8-bit quantity holding + * an alpha value. (Since 1.0) + * @CAIRO_FORMAT_A1: each pixel is a 1-bit quantity holding + * an alpha value. Pixels are packed together into 32-bit + * quantities. The ordering of the bits matches the + * endianness of the platform. On a big-endian machine, the + * first pixel is in the uppermost bit, on a little-endian + * machine the first pixel is in the least-significant bit. (Since 1.0) + * @CAIRO_FORMAT_RGB16_565: each pixel is a 16-bit quantity + * with red in the upper 5 bits, then green in the middle + * 6 bits, and blue in the lower 5 bits. (Since 1.2) + * @CAIRO_FORMAT_RGB30: like RGB24 but with 10bpc. (Since 1.12) + * @CAIRO_FORMAT_RGB96F: 3 floats, R, G, B. (Since 1.17.2) + * @CAIRO_FORMAT_RGBA128F: 4 floats, R, G, B, A. (Since 1.17.2) + * + * #cairo_format_t is used to identify the memory format of + * image data. + * + * New entries may be added in future versions. + * + * Since: 1.0 + **/ +typedef enum _cairo_format { + CAIRO_FORMAT_INVALID = -1, + CAIRO_FORMAT_ARGB32 = 0, + CAIRO_FORMAT_RGB24 = 1, + CAIRO_FORMAT_A8 = 2, + CAIRO_FORMAT_A1 = 3, + CAIRO_FORMAT_RGB16_565 = 4, + CAIRO_FORMAT_RGB30 = 5, + CAIRO_FORMAT_RGB96F = 6, + CAIRO_FORMAT_RGBA128F = 7 +} cairo_format_t; + +/** + * cairo_dither_t: + * @CAIRO_DITHER_NONE: No dithering. + * @CAIRO_DITHER_DEFAULT: Default choice at cairo compile time. Currently NONE. + * @CAIRO_DITHER_FAST: Fastest dithering algorithm supported by the backend + * @CAIRO_DITHER_GOOD: An algorithm with smoother dithering than FAST + * @CAIRO_DITHER_BEST: Best algorithm available in the backend + * + * Dither is an intentionally applied form of noise used to randomize + * quantization error, preventing large-scale patterns such as color banding + * in images (e.g. for gradients). Ordered dithering applies a precomputed + * threshold matrix to spread the errors smoothly. + * + * #cairo_dither_t is modeled on pixman dithering algorithm choice. + * As of Pixman 0.40, FAST corresponds to a 8x8 ordered bayer noise and GOOD + * and BEST use an ordered 64x64 precomputed blue noise. + * + * Since: 1.18 + **/ +typedef enum _cairo_dither { + CAIRO_DITHER_NONE, + CAIRO_DITHER_DEFAULT, + CAIRO_DITHER_FAST, + CAIRO_DITHER_GOOD, + CAIRO_DITHER_BEST +} cairo_dither_t; + +cairo_public void +cairo_pattern_set_dither (cairo_pattern_t *pattern, cairo_dither_t dither); + +cairo_public cairo_dither_t +cairo_pattern_get_dither (cairo_pattern_t *pattern); + +/** + * cairo_write_func_t: + * @closure: the output closure + * @data: the buffer containing the data to write + * @length: the amount of data to write + * + * #cairo_write_func_t is the type of function which is called when a + * backend needs to write data to an output stream. It is passed the + * closure which was specified by the user at the time the write + * function was registered, the data to write and the length of the + * data in bytes. The write function should return + * %CAIRO_STATUS_SUCCESS if all the data was successfully written, + * %CAIRO_STATUS_WRITE_ERROR otherwise. + * + * Returns: the status code of the write operation + * + * Since: 1.0 + **/ +typedef cairo_status_t (*cairo_write_func_t) (void *closure, + const unsigned char *data, + unsigned int length); + +/** + * cairo_read_func_t: + * @closure: the input closure + * @data: the buffer into which to read the data + * @length: the amount of data to read + * + * #cairo_read_func_t is the type of function which is called when a + * backend needs to read data from an input stream. It is passed the + * closure which was specified by the user at the time the read + * function was registered, the buffer to read the data into and the + * length of the data in bytes. The read function should return + * %CAIRO_STATUS_SUCCESS if all the data was successfully read, + * %CAIRO_STATUS_READ_ERROR otherwise. + * + * Returns: the status code of the read operation + * + * Since: 1.0 + **/ +typedef cairo_status_t (*cairo_read_func_t) (void *closure, + unsigned char *data, + unsigned int length); + +/** + * cairo_rectangle_int_t: + * @x: X coordinate of the left side of the rectangle + * @y: Y coordinate of the top side of the rectangle + * @width: width of the rectangle + * @height: height of the rectangle + * + * A data structure for holding a rectangle with integer coordinates. + * + * Since: 1.10 + **/ + +typedef struct _cairo_rectangle_int { + int x, y; + int width, height; +} cairo_rectangle_int_t; + + +/* Functions for manipulating state objects */ +cairo_public cairo_t * +cairo_create (cairo_surface_t *target); + +cairo_public cairo_t * +cairo_reference (cairo_t *cr); + +cairo_public void +cairo_destroy (cairo_t *cr); + +cairo_public unsigned int +cairo_get_reference_count (cairo_t *cr); + +cairo_public void * +cairo_get_user_data (cairo_t *cr, + const cairo_user_data_key_t *key); + +cairo_public cairo_status_t +cairo_set_user_data (cairo_t *cr, + const cairo_user_data_key_t *key, + void *user_data, + cairo_destroy_func_t destroy); + +cairo_public void +cairo_save (cairo_t *cr); + +cairo_public void +cairo_restore (cairo_t *cr); + +cairo_public void +cairo_push_group (cairo_t *cr); + +cairo_public void +cairo_push_group_with_content (cairo_t *cr, cairo_content_t content); + +cairo_public cairo_pattern_t * +cairo_pop_group (cairo_t *cr); + +cairo_public void +cairo_pop_group_to_source (cairo_t *cr); + +/* Modify state */ + +/** + * cairo_operator_t: + * @CAIRO_OPERATOR_CLEAR: clear destination layer (bounded) (Since 1.0) + * @CAIRO_OPERATOR_SOURCE: replace destination layer (bounded) (Since 1.0) + * @CAIRO_OPERATOR_OVER: draw source layer on top of destination layer + * (bounded) (Since 1.0) + * @CAIRO_OPERATOR_IN: draw source where there was destination content + * (unbounded) (Since 1.0) + * @CAIRO_OPERATOR_OUT: draw source where there was no destination + * content (unbounded) (Since 1.0) + * @CAIRO_OPERATOR_ATOP: draw source on top of destination content and + * only there (Since 1.0) + * @CAIRO_OPERATOR_DEST: ignore the source (Since 1.0) + * @CAIRO_OPERATOR_DEST_OVER: draw destination on top of source (Since 1.0) + * @CAIRO_OPERATOR_DEST_IN: leave destination only where there was + * source content (unbounded) (Since 1.0) + * @CAIRO_OPERATOR_DEST_OUT: leave destination only where there was no + * source content (Since 1.0) + * @CAIRO_OPERATOR_DEST_ATOP: leave destination on top of source content + * and only there (unbounded) (Since 1.0) + * @CAIRO_OPERATOR_XOR: source and destination are shown where there is only + * one of them (Since 1.0) + * @CAIRO_OPERATOR_ADD: source and destination layers are accumulated (Since 1.0) + * @CAIRO_OPERATOR_SATURATE: like over, but assuming source and dest are + * disjoint geometries (Since 1.0) + * @CAIRO_OPERATOR_MULTIPLY: source and destination layers are multiplied. + * This causes the result to be at least as dark as the darker inputs. (Since 1.10) + * @CAIRO_OPERATOR_SCREEN: source and destination are complemented and + * multiplied. This causes the result to be at least as light as the lighter + * inputs. (Since 1.10) + * @CAIRO_OPERATOR_OVERLAY: multiplies or screens, depending on the + * lightness of the destination color. (Since 1.10) + * @CAIRO_OPERATOR_DARKEN: replaces the destination with the source if it + * is darker, otherwise keeps the source. (Since 1.10) + * @CAIRO_OPERATOR_LIGHTEN: replaces the destination with the source if it + * is lighter, otherwise keeps the source. (Since 1.10) + * @CAIRO_OPERATOR_COLOR_DODGE: brightens the destination color to reflect + * the source color. (Since 1.10) + * @CAIRO_OPERATOR_COLOR_BURN: darkens the destination color to reflect + * the source color. (Since 1.10) + * @CAIRO_OPERATOR_HARD_LIGHT: Multiplies or screens, dependent on source + * color. (Since 1.10) + * @CAIRO_OPERATOR_SOFT_LIGHT: Darkens or lightens, dependent on source + * color. (Since 1.10) + * @CAIRO_OPERATOR_DIFFERENCE: Takes the difference of the source and + * destination color. (Since 1.10) + * @CAIRO_OPERATOR_EXCLUSION: Produces an effect similar to difference, but + * with lower contrast. (Since 1.10) + * @CAIRO_OPERATOR_HSL_HUE: Creates a color with the hue of the source + * and the saturation and luminosity of the target. (Since 1.10) + * @CAIRO_OPERATOR_HSL_SATURATION: Creates a color with the saturation + * of the source and the hue and luminosity of the target. Painting with + * this mode onto a gray area produces no change. (Since 1.10) + * @CAIRO_OPERATOR_HSL_COLOR: Creates a color with the hue and saturation + * of the source and the luminosity of the target. This preserves the gray + * levels of the target and is useful for coloring monochrome images or + * tinting color images. (Since 1.10) + * @CAIRO_OPERATOR_HSL_LUMINOSITY: Creates a color with the luminosity of + * the source and the hue and saturation of the target. This produces an + * inverse effect to @CAIRO_OPERATOR_HSL_COLOR. (Since 1.10) + * + * #cairo_operator_t is used to set the compositing operator for all cairo + * drawing operations. + * + * The default operator is %CAIRO_OPERATOR_OVER. + * + * The operators marked as unbounded modify their + * destination even outside of the mask layer (that is, their effect is not + * bound by the mask layer). However, their effect can still be limited by + * way of clipping. + * + * To keep things simple, the operator descriptions here + * document the behavior for when both source and destination are either fully + * transparent or fully opaque. The actual implementation works for + * translucent layers too. + * For a more detailed explanation of the effects of each operator, including + * the mathematical definitions, see + * https://cairographics.org/operators/. + * + * Since: 1.0 + **/ +typedef enum _cairo_operator { + CAIRO_OPERATOR_CLEAR, + + CAIRO_OPERATOR_SOURCE, + CAIRO_OPERATOR_OVER, + CAIRO_OPERATOR_IN, + CAIRO_OPERATOR_OUT, + CAIRO_OPERATOR_ATOP, + + CAIRO_OPERATOR_DEST, + CAIRO_OPERATOR_DEST_OVER, + CAIRO_OPERATOR_DEST_IN, + CAIRO_OPERATOR_DEST_OUT, + CAIRO_OPERATOR_DEST_ATOP, + + CAIRO_OPERATOR_XOR, + CAIRO_OPERATOR_ADD, + CAIRO_OPERATOR_SATURATE, + + CAIRO_OPERATOR_MULTIPLY, + CAIRO_OPERATOR_SCREEN, + CAIRO_OPERATOR_OVERLAY, + CAIRO_OPERATOR_DARKEN, + CAIRO_OPERATOR_LIGHTEN, + CAIRO_OPERATOR_COLOR_DODGE, + CAIRO_OPERATOR_COLOR_BURN, + CAIRO_OPERATOR_HARD_LIGHT, + CAIRO_OPERATOR_SOFT_LIGHT, + CAIRO_OPERATOR_DIFFERENCE, + CAIRO_OPERATOR_EXCLUSION, + CAIRO_OPERATOR_HSL_HUE, + CAIRO_OPERATOR_HSL_SATURATION, + CAIRO_OPERATOR_HSL_COLOR, + CAIRO_OPERATOR_HSL_LUMINOSITY +} cairo_operator_t; + +cairo_public void +cairo_set_operator (cairo_t *cr, cairo_operator_t op); + +cairo_public void +cairo_set_source (cairo_t *cr, cairo_pattern_t *source); + +cairo_public void +cairo_set_source_rgb (cairo_t *cr, double red, double green, double blue); + +cairo_public void +cairo_set_source_rgba (cairo_t *cr, + double red, double green, double blue, + double alpha); + +cairo_public void +cairo_set_source_surface (cairo_t *cr, + cairo_surface_t *surface, + double x, + double y); + +cairo_public void +cairo_set_tolerance (cairo_t *cr, double tolerance); + +/** + * cairo_antialias_t: + * @CAIRO_ANTIALIAS_DEFAULT: Use the default antialiasing for + * the subsystem and target device, since 1.0 + * @CAIRO_ANTIALIAS_NONE: Use a bilevel alpha mask, since 1.0 + * @CAIRO_ANTIALIAS_GRAY: Perform single-color antialiasing (using + * shades of gray for black text on a white background, for example), since 1.0 + * @CAIRO_ANTIALIAS_SUBPIXEL: Perform antialiasing by taking + * advantage of the order of subpixel elements on devices + * such as LCD panels, since 1.0 + * @CAIRO_ANTIALIAS_FAST: Hint that the backend should perform some + * antialiasing but prefer speed over quality, since 1.12 + * @CAIRO_ANTIALIAS_GOOD: The backend should balance quality against + * performance, since 1.12 + * @CAIRO_ANTIALIAS_BEST: Hint that the backend should render at the highest + * quality, sacrificing speed if necessary, since 1.12 + * + * Specifies the type of antialiasing to do when rendering text or shapes. + * + * As it is not necessarily clear from the above what advantages a particular + * antialias method provides, since 1.12, there is also a set of hints: + * @CAIRO_ANTIALIAS_FAST: Allow the backend to degrade raster quality for speed + * @CAIRO_ANTIALIAS_GOOD: A balance between speed and quality + * @CAIRO_ANTIALIAS_BEST: A high-fidelity, but potentially slow, raster mode + * + * These make no guarantee on how the backend will perform its rasterisation + * (if it even rasterises!), nor that they have any differing effect other + * than to enable some form of antialiasing. In the case of glyph rendering, + * @CAIRO_ANTIALIAS_FAST and @CAIRO_ANTIALIAS_GOOD will be mapped to + * @CAIRO_ANTIALIAS_GRAY, with @CAIRO_ANTALIAS_BEST being equivalent to + * @CAIRO_ANTIALIAS_SUBPIXEL. + * + * The interpretation of @CAIRO_ANTIALIAS_DEFAULT is left entirely up to + * the backend, typically this will be similar to @CAIRO_ANTIALIAS_GOOD. + * + * Since: 1.0 + **/ +typedef enum _cairo_antialias { + CAIRO_ANTIALIAS_DEFAULT, + + /* method */ + CAIRO_ANTIALIAS_NONE, + CAIRO_ANTIALIAS_GRAY, + CAIRO_ANTIALIAS_SUBPIXEL, + + /* hints */ + CAIRO_ANTIALIAS_FAST, + CAIRO_ANTIALIAS_GOOD, + CAIRO_ANTIALIAS_BEST +} cairo_antialias_t; + +cairo_public void +cairo_set_antialias (cairo_t *cr, cairo_antialias_t antialias); + +/** + * cairo_fill_rule_t: + * @CAIRO_FILL_RULE_WINDING: If the path crosses the ray from + * left-to-right, counts +1. If the path crosses the ray + * from right to left, counts -1. (Left and right are determined + * from the perspective of looking along the ray from the starting + * point.) If the total count is non-zero, the point will be filled. (Since 1.0) + * @CAIRO_FILL_RULE_EVEN_ODD: Counts the total number of + * intersections, without regard to the orientation of the contour. If + * the total number of intersections is odd, the point will be + * filled. (Since 1.0) + * + * #cairo_fill_rule_t is used to select how paths are filled. For both + * fill rules, whether or not a point is included in the fill is + * determined by taking a ray from that point to infinity and looking + * at intersections with the path. The ray can be in any direction, + * as long as it doesn't pass through the end point of a segment + * or have a tricky intersection such as intersecting tangent to the path. + * (Note that filling is not actually implemented in this way. This + * is just a description of the rule that is applied.) + * + * The default fill rule is %CAIRO_FILL_RULE_WINDING. + * + * New entries may be added in future versions. + * + * Since: 1.0 + **/ +typedef enum _cairo_fill_rule { + CAIRO_FILL_RULE_WINDING, + CAIRO_FILL_RULE_EVEN_ODD +} cairo_fill_rule_t; + +cairo_public void +cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule); + +cairo_public void +cairo_set_line_width (cairo_t *cr, double width); + +cairo_public void +cairo_set_hairline (cairo_t *cr, cairo_bool_t set_hairline); + +/** + * cairo_line_cap_t: + * @CAIRO_LINE_CAP_BUTT: start(stop) the line exactly at the start(end) point (Since 1.0) + * @CAIRO_LINE_CAP_ROUND: use a round ending, the center of the circle is the end point (Since 1.0) + * @CAIRO_LINE_CAP_SQUARE: use squared ending, the center of the square is the end point (Since 1.0) + * + * Specifies how to render the endpoints of the path when stroking. + * + * The default line cap style is %CAIRO_LINE_CAP_BUTT. + * + * Since: 1.0 + **/ +typedef enum _cairo_line_cap { + CAIRO_LINE_CAP_BUTT, + CAIRO_LINE_CAP_ROUND, + CAIRO_LINE_CAP_SQUARE +} cairo_line_cap_t; + +cairo_public void +cairo_set_line_cap (cairo_t *cr, cairo_line_cap_t line_cap); + +/** + * cairo_line_join_t: + * @CAIRO_LINE_JOIN_MITER: use a sharp (angled) corner, see + * cairo_set_miter_limit() (Since 1.0) + * @CAIRO_LINE_JOIN_ROUND: use a rounded join, the center of the circle is the + * joint point (Since 1.0) + * @CAIRO_LINE_JOIN_BEVEL: use a cut-off join, the join is cut off at half + * the line width from the joint point (Since 1.0) + * + * Specifies how to render the junction of two lines when stroking. + * + * The default line join style is %CAIRO_LINE_JOIN_MITER. + * + * Since: 1.0 + **/ +typedef enum _cairo_line_join { + CAIRO_LINE_JOIN_MITER, + CAIRO_LINE_JOIN_ROUND, + CAIRO_LINE_JOIN_BEVEL +} cairo_line_join_t; + +cairo_public void +cairo_set_line_join (cairo_t *cr, cairo_line_join_t line_join); + +cairo_public void +cairo_set_dash (cairo_t *cr, + const double *dashes, + int num_dashes, + double offset); + +cairo_public void +cairo_set_miter_limit (cairo_t *cr, double limit); + +cairo_public void +cairo_translate (cairo_t *cr, double tx, double ty); + +cairo_public void +cairo_scale (cairo_t *cr, double sx, double sy); + +cairo_public void +cairo_rotate (cairo_t *cr, double angle); + +cairo_public void +cairo_transform (cairo_t *cr, + const cairo_matrix_t *matrix); + +cairo_public void +cairo_set_matrix (cairo_t *cr, + const cairo_matrix_t *matrix); + +cairo_public void +cairo_identity_matrix (cairo_t *cr); + +cairo_public void +cairo_user_to_device (cairo_t *cr, double *x, double *y); + +cairo_public void +cairo_user_to_device_distance (cairo_t *cr, double *dx, double *dy); + +cairo_public void +cairo_device_to_user (cairo_t *cr, double *x, double *y); + +cairo_public void +cairo_device_to_user_distance (cairo_t *cr, double *dx, double *dy); + +/* Path creation functions */ +cairo_public void +cairo_new_path (cairo_t *cr); + +cairo_public void +cairo_move_to (cairo_t *cr, double x, double y); + +cairo_public void +cairo_new_sub_path (cairo_t *cr); + +cairo_public void +cairo_line_to (cairo_t *cr, double x, double y); + +cairo_public void +cairo_curve_to (cairo_t *cr, + double x1, double y1, + double x2, double y2, + double x3, double y3); + +cairo_public void +cairo_arc (cairo_t *cr, + double xc, double yc, + double radius, + double angle1, double angle2); + +cairo_public void +cairo_arc_negative (cairo_t *cr, + double xc, double yc, + double radius, + double angle1, double angle2); + +/* XXX: NYI +cairo_public void +cairo_arc_to (cairo_t *cr, + double x1, double y1, + double x2, double y2, + double radius); +*/ + +cairo_public void +cairo_rel_move_to (cairo_t *cr, double dx, double dy); + +cairo_public void +cairo_rel_line_to (cairo_t *cr, double dx, double dy); + +cairo_public void +cairo_rel_curve_to (cairo_t *cr, + double dx1, double dy1, + double dx2, double dy2, + double dx3, double dy3); + +cairo_public void +cairo_rectangle (cairo_t *cr, + double x, double y, + double width, double height); + +/* XXX: NYI +cairo_public void +cairo_stroke_to_path (cairo_t *cr); +*/ + +cairo_public void +cairo_close_path (cairo_t *cr); + +cairo_public void +cairo_path_extents (cairo_t *cr, + double *x1, double *y1, + double *x2, double *y2); + +/* Painting functions */ +cairo_public void +cairo_paint (cairo_t *cr); + +cairo_public void +cairo_paint_with_alpha (cairo_t *cr, + double alpha); + +cairo_public void +cairo_mask (cairo_t *cr, + cairo_pattern_t *pattern); + +cairo_public void +cairo_mask_surface (cairo_t *cr, + cairo_surface_t *surface, + double surface_x, + double surface_y); + +cairo_public void +cairo_stroke (cairo_t *cr); + +cairo_public void +cairo_stroke_preserve (cairo_t *cr); + +cairo_public void +cairo_fill (cairo_t *cr); + +cairo_public void +cairo_fill_preserve (cairo_t *cr); + +cairo_public void +cairo_copy_page (cairo_t *cr); + +cairo_public void +cairo_show_page (cairo_t *cr); + +/* Insideness testing */ +cairo_public cairo_bool_t +cairo_in_stroke (cairo_t *cr, double x, double y); + +cairo_public cairo_bool_t +cairo_in_fill (cairo_t *cr, double x, double y); + +cairo_public cairo_bool_t +cairo_in_clip (cairo_t *cr, double x, double y); + +/* Rectangular extents */ +cairo_public void +cairo_stroke_extents (cairo_t *cr, + double *x1, double *y1, + double *x2, double *y2); + +cairo_public void +cairo_fill_extents (cairo_t *cr, + double *x1, double *y1, + double *x2, double *y2); + +/* Clipping */ +cairo_public void +cairo_reset_clip (cairo_t *cr); + +cairo_public void +cairo_clip (cairo_t *cr); + +cairo_public void +cairo_clip_preserve (cairo_t *cr); + +cairo_public void +cairo_clip_extents (cairo_t *cr, + double *x1, double *y1, + double *x2, double *y2); + +/** + * cairo_rectangle_t: + * @x: X coordinate of the left side of the rectangle + * @y: Y coordinate of the top side of the rectangle + * @width: width of the rectangle + * @height: height of the rectangle + * + * A data structure for holding a rectangle. + * + * Since: 1.4 + **/ +typedef struct _cairo_rectangle { + double x, y, width, height; +} cairo_rectangle_t; + +/** + * cairo_rectangle_list_t: + * @status: Error status of the rectangle list + * @rectangles: Array containing the rectangles + * @num_rectangles: Number of rectangles in this list + * + * A data structure for holding a dynamically allocated + * array of rectangles. + * + * Since: 1.4 + **/ +typedef struct _cairo_rectangle_list { + cairo_status_t status; + cairo_rectangle_t *rectangles; + int num_rectangles; +} cairo_rectangle_list_t; + +cairo_public cairo_rectangle_list_t * +cairo_copy_clip_rectangle_list (cairo_t *cr); + +cairo_public void +cairo_rectangle_list_destroy (cairo_rectangle_list_t *rectangle_list); + +/* Logical structure tagging functions */ + +#define CAIRO_TAG_DEST "cairo.dest" +#define CAIRO_TAG_LINK "Link" +#define CAIRO_TAG_CONTENT "cairo.content" +#define CAIRO_TAG_CONTENT_REF "cairo.content_ref" + +cairo_public void +cairo_tag_begin (cairo_t *cr, const char *tag_name, const char *attributes); + +cairo_public void +cairo_tag_end (cairo_t *cr, const char *tag_name); + +/* Font/Text functions */ + +/** + * cairo_scaled_font_t: + * + * A #cairo_scaled_font_t is a font scaled to a particular size and device + * resolution. A #cairo_scaled_font_t is most useful for low-level font + * usage where a library or application wants to cache a reference + * to a scaled font to speed up the computation of metrics. + * + * There are various types of scaled fonts, depending on the + * font backend they use. The type of a + * scaled font can be queried using cairo_scaled_font_get_type(). + * + * Memory management of #cairo_scaled_font_t is done with + * cairo_scaled_font_reference() and cairo_scaled_font_destroy(). + * + * Since: 1.0 + **/ +typedef struct _cairo_scaled_font cairo_scaled_font_t; + +/** + * cairo_font_face_t: + * + * A #cairo_font_face_t specifies all aspects of a font other + * than the size or font matrix (a font matrix is used to distort + * a font by shearing it or scaling it unequally in the two + * directions) . A font face can be set on a #cairo_t by using + * cairo_set_font_face(); the size and font matrix are set with + * cairo_set_font_size() and cairo_set_font_matrix(). + * + * There are various types of font faces, depending on the + * font backend they use. The type of a + * font face can be queried using cairo_font_face_get_type(). + * + * Memory management of #cairo_font_face_t is done with + * cairo_font_face_reference() and cairo_font_face_destroy(). + * + * Since: 1.0 + **/ +typedef struct _cairo_font_face cairo_font_face_t; + +/** + * cairo_glyph_t: + * @index: glyph index in the font. The exact interpretation of the + * glyph index depends on the font technology being used. + * @x: the offset in the X direction between the origin used for + * drawing or measuring the string and the origin of this glyph. + * @y: the offset in the Y direction between the origin used for + * drawing or measuring the string and the origin of this glyph. + * + * The #cairo_glyph_t structure holds information about a single glyph + * when drawing or measuring text. A font is (in simple terms) a + * collection of shapes used to draw text. A glyph is one of these + * shapes. There can be multiple glyphs for a single character + * (alternates to be used in different contexts, for example), or a + * glyph can be a ligature of multiple + * characters. Cairo doesn't expose any way of converting input text + * into glyphs, so in order to use the Cairo interfaces that take + * arrays of glyphs, you must directly access the appropriate + * underlying font system. + * + * Note that the offsets given by @x and @y are not cumulative. When + * drawing or measuring text, each glyph is individually positioned + * with respect to the overall origin + * + * Since: 1.0 + **/ +typedef struct { + unsigned long index; + double x; + double y; +} cairo_glyph_t; + +cairo_public cairo_glyph_t * +cairo_glyph_allocate (int num_glyphs); + +cairo_public void +cairo_glyph_free (cairo_glyph_t *glyphs); + +/** + * cairo_text_cluster_t: + * @num_bytes: the number of bytes of UTF-8 text covered by cluster + * @num_glyphs: the number of glyphs covered by cluster + * + * The #cairo_text_cluster_t structure holds information about a single + * text cluster. A text cluster is a minimal + * mapping of some glyphs corresponding to some UTF-8 text. + * + * For a cluster to be valid, both @num_bytes and @num_glyphs should + * be non-negative, and at least one should be non-zero. + * Note that clusters with zero glyphs are not as well supported as + * normal clusters. For example, PDF rendering applications typically + * ignore those clusters when PDF text is being selected. + * + * See cairo_show_text_glyphs() for how clusters are used in advanced + * text operations. + * + * Since: 1.8 + **/ +typedef struct { + int num_bytes; + int num_glyphs; +} cairo_text_cluster_t; + +cairo_public cairo_text_cluster_t * +cairo_text_cluster_allocate (int num_clusters); + +cairo_public void +cairo_text_cluster_free (cairo_text_cluster_t *clusters); + +/** + * cairo_text_cluster_flags_t: + * @CAIRO_TEXT_CLUSTER_FLAG_BACKWARD: The clusters in the cluster array + * map to glyphs in the glyph array from end to start. (Since 1.8) + * + * Specifies properties of a text cluster mapping. + * + * Since: 1.8 + **/ +typedef enum _cairo_text_cluster_flags { + CAIRO_TEXT_CLUSTER_FLAG_BACKWARD = 0x00000001 +} cairo_text_cluster_flags_t; + +/** + * cairo_text_extents_t: + * @x_bearing: the horizontal distance from the origin to the + * leftmost part of the glyphs as drawn. Positive if the + * glyphs lie entirely to the right of the origin. + * @y_bearing: the vertical distance from the origin to the + * topmost part of the glyphs as drawn. Positive only if the + * glyphs lie completely below the origin; will usually be + * negative. + * @width: width of the glyphs as drawn + * @height: height of the glyphs as drawn + * @x_advance:distance to advance in the X direction + * after drawing these glyphs + * @y_advance: distance to advance in the Y direction + * after drawing these glyphs. Will typically be zero except + * for vertical text layout as found in East-Asian languages. + * + * The #cairo_text_extents_t structure stores the extents of a single + * glyph or a string of glyphs in user-space coordinates. Because text + * extents are in user-space coordinates, they are mostly, but not + * entirely, independent of the current transformation matrix. If you call + * cairo_scale(cr, 2.0, 2.0), text will + * be drawn twice as big, but the reported text extents will not be + * doubled. They will change slightly due to hinting (so you can't + * assume that metrics are independent of the transformation matrix), + * but otherwise will remain unchanged. + * + * Since: 1.0 + **/ +typedef struct { + double x_bearing; + double y_bearing; + double width; + double height; + double x_advance; + double y_advance; +} cairo_text_extents_t; + +/** + * cairo_font_extents_t: + * @ascent: the distance that the font extends above the baseline. + * Note that this is not always exactly equal to the maximum + * of the extents of all the glyphs in the font, but rather + * is picked to express the font designer's intent as to + * how the font should align with elements above it. + * @descent: the distance that the font extends below the baseline. + * This value is positive for typical fonts that include + * portions below the baseline. Note that this is not always + * exactly equal to the maximum of the extents of all the + * glyphs in the font, but rather is picked to express the + * font designer's intent as to how the font should + * align with elements below it. + * @height: the recommended vertical distance between baselines when + * setting consecutive lines of text with the font. This + * is greater than @ascent+@descent by a + * quantity known as the line spacing + * or external leading. When space + * is at a premium, most fonts can be set with only + * a distance of @ascent+@descent between lines. + * @max_x_advance: the maximum distance in the X direction that + * the origin is advanced for any glyph in the font. + * @max_y_advance: the maximum distance in the Y direction that + * the origin is advanced for any glyph in the font. + * This will be zero for normal fonts used for horizontal + * writing. (The scripts of East Asia are sometimes written + * vertically.) + * + * The #cairo_font_extents_t structure stores metric information for + * a font. Values are given in the current user-space coordinate + * system. + * + * Because font metrics are in user-space coordinates, they are + * mostly, but not entirely, independent of the current transformation + * matrix. If you call cairo_scale(cr, 2.0, 2.0), + * text will be drawn twice as big, but the reported text extents will + * not be doubled. They will change slightly due to hinting (so you + * can't assume that metrics are independent of the transformation + * matrix), but otherwise will remain unchanged. + * + * Since: 1.0 + **/ +typedef struct { + double ascent; + double descent; + double height; + double max_x_advance; + double max_y_advance; +} cairo_font_extents_t; + +/** + * cairo_font_slant_t: + * @CAIRO_FONT_SLANT_NORMAL: Upright font style, since 1.0 + * @CAIRO_FONT_SLANT_ITALIC: Italic font style, since 1.0 + * @CAIRO_FONT_SLANT_OBLIQUE: Oblique font style, since 1.0 + * + * Specifies variants of a font face based on their slant. + * + * Since: 1.0 + **/ +typedef enum _cairo_font_slant { + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_SLANT_ITALIC, + CAIRO_FONT_SLANT_OBLIQUE +} cairo_font_slant_t; + +/** + * cairo_font_weight_t: + * @CAIRO_FONT_WEIGHT_NORMAL: Normal font weight, since 1.0 + * @CAIRO_FONT_WEIGHT_BOLD: Bold font weight, since 1.0 + * + * Specifies variants of a font face based on their weight. + * + * Since: 1.0 + **/ +typedef enum _cairo_font_weight { + CAIRO_FONT_WEIGHT_NORMAL, + CAIRO_FONT_WEIGHT_BOLD +} cairo_font_weight_t; + +/** + * cairo_subpixel_order_t: + * @CAIRO_SUBPIXEL_ORDER_DEFAULT: Use the default subpixel order for + * for the target device, since 1.0 + * @CAIRO_SUBPIXEL_ORDER_RGB: Subpixel elements are arranged horizontally + * with red at the left, since 1.0 + * @CAIRO_SUBPIXEL_ORDER_BGR: Subpixel elements are arranged horizontally + * with blue at the left, since 1.0 + * @CAIRO_SUBPIXEL_ORDER_VRGB: Subpixel elements are arranged vertically + * with red at the top, since 1.0 + * @CAIRO_SUBPIXEL_ORDER_VBGR: Subpixel elements are arranged vertically + * with blue at the top, since 1.0 + * + * The subpixel order specifies the order of color elements within + * each pixel on the display device when rendering with an + * antialiasing mode of %CAIRO_ANTIALIAS_SUBPIXEL. + * + * Since: 1.0 + **/ +typedef enum _cairo_subpixel_order { + CAIRO_SUBPIXEL_ORDER_DEFAULT, + CAIRO_SUBPIXEL_ORDER_RGB, + CAIRO_SUBPIXEL_ORDER_BGR, + CAIRO_SUBPIXEL_ORDER_VRGB, + CAIRO_SUBPIXEL_ORDER_VBGR +} cairo_subpixel_order_t; + +/** + * cairo_hint_style_t: + * @CAIRO_HINT_STYLE_DEFAULT: Use the default hint style for + * font backend and target device, since 1.0 + * @CAIRO_HINT_STYLE_NONE: Do not hint outlines, since 1.0 + * @CAIRO_HINT_STYLE_SLIGHT: Hint outlines slightly to improve + * contrast while retaining good fidelity to the original + * shapes, since 1.0 + * @CAIRO_HINT_STYLE_MEDIUM: Hint outlines with medium strength + * giving a compromise between fidelity to the original shapes + * and contrast, since 1.0 + * @CAIRO_HINT_STYLE_FULL: Hint outlines to maximize contrast, since 1.0 + * + * Specifies the type of hinting to do on font outlines. Hinting + * is the process of fitting outlines to the pixel grid in order + * to improve the appearance of the result. Since hinting outlines + * involves distorting them, it also reduces the faithfulness + * to the original outline shapes. Not all of the outline hinting + * styles are supported by all font backends. + * + * New entries may be added in future versions. + * + * Since: 1.0 + **/ +typedef enum _cairo_hint_style { + CAIRO_HINT_STYLE_DEFAULT, + CAIRO_HINT_STYLE_NONE, + CAIRO_HINT_STYLE_SLIGHT, + CAIRO_HINT_STYLE_MEDIUM, + CAIRO_HINT_STYLE_FULL +} cairo_hint_style_t; + +/** + * cairo_hint_metrics_t: + * @CAIRO_HINT_METRICS_DEFAULT: Hint metrics in the default + * manner for the font backend and target device, since 1.0 + * @CAIRO_HINT_METRICS_OFF: Do not hint font metrics, since 1.0 + * @CAIRO_HINT_METRICS_ON: Hint font metrics, since 1.0 + * + * Specifies whether to hint font metrics; hinting font metrics + * means quantizing them so that they are integer values in + * device space. Doing this improves the consistency of + * letter and line spacing, however it also means that text + * will be laid out differently at different zoom factors. + * + * Since: 1.0 + **/ +typedef enum _cairo_hint_metrics { + CAIRO_HINT_METRICS_DEFAULT, + CAIRO_HINT_METRICS_OFF, + CAIRO_HINT_METRICS_ON +} cairo_hint_metrics_t; + +/** + * cairo_color_mode_t: + * @CAIRO_COLOR_MODE_DEFAULT: Use the default color mode for + * font backend and target device, since 1.18. + * @CAIRO_COLOR_MODE_NO_COLOR: Disable rendering color glyphs. Glyphs are + * always rendered as outline glyphs, since 1.18. + * @CAIRO_COLOR_MODE_COLOR: Enable rendering color glyphs. If the font + * contains a color presentation for a glyph, and when supported by + * the font backend, the glyph will be rendered in color, since 1.18. + * + * Specifies if color fonts are to be rendered using the color + * glyphs or outline glyphs. Glyphs that do not have a color + * presentation, and non-color fonts are not affected by this font + * option. + * + * Since: 1.18 + **/ +typedef enum _cairo_color_mode { + CAIRO_COLOR_MODE_DEFAULT, + CAIRO_COLOR_MODE_NO_COLOR, + CAIRO_COLOR_MODE_COLOR +} cairo_color_mode_t; + +/** + * cairo_font_options_t: + * + * An opaque structure holding all options that are used when + * rendering fonts. + * + * Individual features of a #cairo_font_options_t can be set or + * accessed using functions named + * cairo_font_options_set_feature_name() and + * cairo_font_options_get_feature_name(), like + * cairo_font_options_set_antialias() and + * cairo_font_options_get_antialias(). + * + * New features may be added to a #cairo_font_options_t in the + * future. For this reason, cairo_font_options_copy(), + * cairo_font_options_equal(), cairo_font_options_merge(), and + * cairo_font_options_hash() should be used to copy, check + * for equality, merge, or compute a hash value of + * #cairo_font_options_t objects. + * + * Since: 1.0 + **/ +typedef struct _cairo_font_options cairo_font_options_t; + +cairo_public cairo_font_options_t * +cairo_font_options_create (void); + +cairo_public cairo_font_options_t * +cairo_font_options_copy (const cairo_font_options_t *original); + +cairo_public void +cairo_font_options_destroy (cairo_font_options_t *options); + +cairo_public cairo_status_t +cairo_font_options_status (cairo_font_options_t *options); + +cairo_public void +cairo_font_options_merge (cairo_font_options_t *options, + const cairo_font_options_t *other); +cairo_public cairo_bool_t +cairo_font_options_equal (const cairo_font_options_t *options, + const cairo_font_options_t *other); + +cairo_public unsigned long +cairo_font_options_hash (const cairo_font_options_t *options); + +cairo_public void +cairo_font_options_set_antialias (cairo_font_options_t *options, + cairo_antialias_t antialias); +cairo_public cairo_antialias_t +cairo_font_options_get_antialias (const cairo_font_options_t *options); + +cairo_public void +cairo_font_options_set_subpixel_order (cairo_font_options_t *options, + cairo_subpixel_order_t subpixel_order); +cairo_public cairo_subpixel_order_t +cairo_font_options_get_subpixel_order (const cairo_font_options_t *options); + +cairo_public void +cairo_font_options_set_hint_style (cairo_font_options_t *options, + cairo_hint_style_t hint_style); +cairo_public cairo_hint_style_t +cairo_font_options_get_hint_style (const cairo_font_options_t *options); + +cairo_public void +cairo_font_options_set_hint_metrics (cairo_font_options_t *options, + cairo_hint_metrics_t hint_metrics); +cairo_public cairo_hint_metrics_t +cairo_font_options_get_hint_metrics (const cairo_font_options_t *options); + +cairo_public const char * +cairo_font_options_get_variations (cairo_font_options_t *options); + +cairo_public void +cairo_font_options_set_variations (cairo_font_options_t *options, + const char *variations); + +#define CAIRO_COLOR_PALETTE_DEFAULT 0 + +cairo_public void +cairo_font_options_set_color_mode (cairo_font_options_t *options, + cairo_color_mode_t color_mode); + +cairo_public cairo_color_mode_t +cairo_font_options_get_color_mode (const cairo_font_options_t *options); + +cairo_public unsigned int +cairo_font_options_get_color_palette (const cairo_font_options_t *options); + +cairo_public void +cairo_font_options_set_color_palette (cairo_font_options_t *options, + unsigned int palette_index); + +cairo_public void +cairo_font_options_set_custom_palette_color (cairo_font_options_t *options, + unsigned int index, + double red, double green, + double blue, double alpha); + +cairo_public cairo_status_t +cairo_font_options_get_custom_palette_color (cairo_font_options_t *options, + unsigned int index, + double *red, double *green, + double *blue, double *alpha); + +/* This interface is for dealing with text as text, not caring about the + font object inside the cairo_t. */ + +cairo_public void +cairo_select_font_face (cairo_t *cr, + const char *family, + cairo_font_slant_t slant, + cairo_font_weight_t weight); + +cairo_public void +cairo_set_font_size (cairo_t *cr, double size); + +cairo_public void +cairo_set_font_matrix (cairo_t *cr, + const cairo_matrix_t *matrix); + +cairo_public void +cairo_get_font_matrix (cairo_t *cr, + cairo_matrix_t *matrix); + +cairo_public void +cairo_set_font_options (cairo_t *cr, + const cairo_font_options_t *options); + +cairo_public void +cairo_get_font_options (cairo_t *cr, + cairo_font_options_t *options); + +cairo_public void +cairo_set_font_face (cairo_t *cr, cairo_font_face_t *font_face); + +cairo_public cairo_font_face_t * +cairo_get_font_face (cairo_t *cr); + +cairo_public void +cairo_set_scaled_font (cairo_t *cr, + const cairo_scaled_font_t *scaled_font); + +cairo_public cairo_scaled_font_t * +cairo_get_scaled_font (cairo_t *cr); + +cairo_public void +cairo_show_text (cairo_t *cr, const char *utf8); + +cairo_public void +cairo_show_glyphs (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs); + +cairo_public void +cairo_show_text_glyphs (cairo_t *cr, + const char *utf8, + int utf8_len, + const cairo_glyph_t *glyphs, + int num_glyphs, + const cairo_text_cluster_t *clusters, + int num_clusters, + cairo_text_cluster_flags_t cluster_flags); + +cairo_public void +cairo_text_path (cairo_t *cr, const char *utf8); + +cairo_public void +cairo_glyph_path (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs); + +cairo_public void +cairo_text_extents (cairo_t *cr, + const char *utf8, + cairo_text_extents_t *extents); + +cairo_public void +cairo_glyph_extents (cairo_t *cr, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_text_extents_t *extents); + +cairo_public void +cairo_font_extents (cairo_t *cr, + cairo_font_extents_t *extents); + +/* Generic identifier for a font style */ + +cairo_public cairo_font_face_t * +cairo_font_face_reference (cairo_font_face_t *font_face); + +cairo_public void +cairo_font_face_destroy (cairo_font_face_t *font_face); + +cairo_public unsigned int +cairo_font_face_get_reference_count (cairo_font_face_t *font_face); + +cairo_public cairo_status_t +cairo_font_face_status (cairo_font_face_t *font_face); + + +/** + * cairo_font_type_t: + * @CAIRO_FONT_TYPE_TOY: The font was created using cairo's toy font api (Since: 1.2) + * @CAIRO_FONT_TYPE_FT: The font is of type FreeType (Since: 1.2) + * @CAIRO_FONT_TYPE_WIN32: The font is of type Win32 (Since: 1.2) + * @CAIRO_FONT_TYPE_QUARTZ: The font is of type Quartz (Since: 1.6, in 1.2 and + * 1.4 it was named CAIRO_FONT_TYPE_ATSUI) + * @CAIRO_FONT_TYPE_USER: The font was create using cairo's user font api (Since: 1.8) + * @CAIRO_FONT_TYPE_DWRITE: The font is of type Win32 DWrite (Since: 1.18) + * + * #cairo_font_type_t is used to describe the type of a given font + * face or scaled font. The font types are also known as "font + * backends" within cairo. + * + * The type of a font face is determined by the function used to + * create it, which will generally be of the form + * cairo_type_font_face_create(). + * The font face type can be queried with cairo_font_face_get_type() + * + * The various #cairo_font_face_t functions can be used with a font face + * of any type. + * + * The type of a scaled font is determined by the type of the font + * face passed to cairo_scaled_font_create(). The scaled font type can + * be queried with cairo_scaled_font_get_type() + * + * The various #cairo_scaled_font_t functions can be used with scaled + * fonts of any type, but some font backends also provide + * type-specific functions that must only be called with a scaled font + * of the appropriate type. These functions have names that begin with + * cairo_type_scaled_font() + * such as cairo_ft_scaled_font_lock_face(). + * + * The behavior of calling a type-specific function with a scaled font + * of the wrong type is undefined. + * + * New entries may be added in future versions. + * + * Since: 1.2 + **/ +typedef enum _cairo_font_type { + CAIRO_FONT_TYPE_TOY, + CAIRO_FONT_TYPE_FT, + CAIRO_FONT_TYPE_WIN32, + CAIRO_FONT_TYPE_QUARTZ, + CAIRO_FONT_TYPE_USER, + CAIRO_FONT_TYPE_DWRITE +} cairo_font_type_t; + +cairo_public cairo_font_type_t +cairo_font_face_get_type (cairo_font_face_t *font_face); + +cairo_public void * +cairo_font_face_get_user_data (cairo_font_face_t *font_face, + const cairo_user_data_key_t *key); + +cairo_public cairo_status_t +cairo_font_face_set_user_data (cairo_font_face_t *font_face, + const cairo_user_data_key_t *key, + void *user_data, + cairo_destroy_func_t destroy); + +/* Portable interface to general font features. */ + +cairo_public cairo_scaled_font_t * +cairo_scaled_font_create (cairo_font_face_t *font_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options); + +cairo_public cairo_scaled_font_t * +cairo_scaled_font_reference (cairo_scaled_font_t *scaled_font); + +cairo_public void +cairo_scaled_font_destroy (cairo_scaled_font_t *scaled_font); + +cairo_public unsigned int +cairo_scaled_font_get_reference_count (cairo_scaled_font_t *scaled_font); + +cairo_public cairo_status_t +cairo_scaled_font_status (cairo_scaled_font_t *scaled_font); + +cairo_public cairo_font_type_t +cairo_scaled_font_get_type (cairo_scaled_font_t *scaled_font); + +cairo_public void * +cairo_scaled_font_get_user_data (cairo_scaled_font_t *scaled_font, + const cairo_user_data_key_t *key); + +cairo_public cairo_status_t +cairo_scaled_font_set_user_data (cairo_scaled_font_t *scaled_font, + const cairo_user_data_key_t *key, + void *user_data, + cairo_destroy_func_t destroy); + +cairo_public void +cairo_scaled_font_extents (cairo_scaled_font_t *scaled_font, + cairo_font_extents_t *extents); + +cairo_public void +cairo_scaled_font_text_extents (cairo_scaled_font_t *scaled_font, + const char *utf8, + cairo_text_extents_t *extents); + +cairo_public void +cairo_scaled_font_glyph_extents (cairo_scaled_font_t *scaled_font, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_text_extents_t *extents); + +cairo_public cairo_status_t +cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font, + double x, + double y, + const char *utf8, + int utf8_len, + cairo_glyph_t **glyphs, + int *num_glyphs, + cairo_text_cluster_t **clusters, + int *num_clusters, + cairo_text_cluster_flags_t *cluster_flags); + +cairo_public cairo_font_face_t * +cairo_scaled_font_get_font_face (cairo_scaled_font_t *scaled_font); + +cairo_public void +cairo_scaled_font_get_font_matrix (cairo_scaled_font_t *scaled_font, + cairo_matrix_t *font_matrix); + +cairo_public void +cairo_scaled_font_get_ctm (cairo_scaled_font_t *scaled_font, + cairo_matrix_t *ctm); + +cairo_public void +cairo_scaled_font_get_scale_matrix (cairo_scaled_font_t *scaled_font, + cairo_matrix_t *scale_matrix); + +cairo_public void +cairo_scaled_font_get_font_options (cairo_scaled_font_t *scaled_font, + cairo_font_options_t *options); + + +/* Toy fonts */ + +cairo_public cairo_font_face_t * +cairo_toy_font_face_create (const char *family, + cairo_font_slant_t slant, + cairo_font_weight_t weight); + +cairo_public const char * +cairo_toy_font_face_get_family (cairo_font_face_t *font_face); + +cairo_public cairo_font_slant_t +cairo_toy_font_face_get_slant (cairo_font_face_t *font_face); + +cairo_public cairo_font_weight_t +cairo_toy_font_face_get_weight (cairo_font_face_t *font_face); + + +/* User fonts */ + +cairo_public cairo_font_face_t * +cairo_user_font_face_create (void); + +/* User-font method signatures */ + +/** + * cairo_user_scaled_font_init_func_t: + * @scaled_font: the scaled-font being created + * @cr: a cairo context, in font space + * @extents: font extents to fill in, in font space + * + * #cairo_user_scaled_font_init_func_t is the type of function which is + * called when a scaled-font needs to be created for a user font-face. + * + * The cairo context @cr is not used by the caller, but is prepared in font + * space, similar to what the cairo contexts passed to the render_glyph + * method will look like. The callback can use this context for extents + * computation for example. After the callback is called, @cr is checked + * for any error status. + * + * The @extents argument is where the user font sets the font extents for + * @scaled_font. It is in font space, which means that for most cases its + * ascent and descent members should add to 1.0. @extents is preset to + * hold a value of 1.0 for ascent, height, and max_x_advance, and 0.0 for + * descent and max_y_advance members. + * + * The callback is optional. If not set, default font extents as described + * in the previous paragraph will be used. + * + * Note that @scaled_font is not fully initialized at this + * point and trying to use it for text operations in the callback will result + * in deadlock. + * + * Returns: %CAIRO_STATUS_SUCCESS upon success, or an error status on error. + * + * Since: 1.8 + **/ +typedef cairo_status_t (*cairo_user_scaled_font_init_func_t) (cairo_scaled_font_t *scaled_font, + cairo_t *cr, + cairo_font_extents_t *extents); + +/** + * cairo_user_scaled_font_render_glyph_func_t: + * @scaled_font: user scaled-font + * @glyph: glyph code to render + * @cr: cairo context to draw to, in font space + * @extents: glyph extents to fill in, in font space + * + * #cairo_user_scaled_font_render_glyph_func_t is the type of function which + * is called when a user scaled-font needs to render a glyph. + * + * The callback is mandatory, and expected to draw the glyph with code @glyph to + * the cairo context @cr. @cr is prepared such that the glyph drawing is done in + * font space. That is, the matrix set on @cr is the scale matrix of @scaled_font. + * The @extents argument is where the user font sets the font extents for + * @scaled_font. However, if user prefers to draw in user space, they can + * achieve that by changing the matrix on @cr. + * + * All cairo rendering operations to @cr are permitted. However, when + * this callback is set with + * cairo_user_font_face_set_render_glyph_func(), the result is + * undefined if any source other than the default source on @cr is + * used. That means, glyph bitmaps should be rendered using + * cairo_mask() instead of cairo_paint(). + * + * When this callback is set with + * cairo_user_font_face_set_render_color_glyph_func(), the default + * source is black. Setting the source is a valid + * operation. cairo_user_scaled_font_get_foreground_marker() or + * cairo_user_scaled_font_get_foreground_source() may be called to + * obtain the current source at the time the glyph is rendered. + * + * Other non-default settings on @cr include a font size of 1.0 (given that + * it is set up to be in font space), and font options corresponding to + * @scaled_font. + * + * The @extents argument is preset to have x_bearing, + * width, and y_advance of zero, + * y_bearing set to -font_extents.ascent, + * height to font_extents.ascent+font_extents.descent, + * and x_advance to font_extents.max_x_advance. + * The only field user needs to set in majority of cases is + * x_advance. + * If the width field is zero upon the callback returning + * (which is its preset value), the glyph extents are automatically computed + * based on the drawings done to @cr. This is in most cases exactly what the + * desired behavior is. However, if for any reason the callback sets the + * extents, it must be ink extents, and include the extents of all drawing + * done to @cr in the callback. + * + * Where both color and non-color callbacks has been set using + * cairo_user_font_face_set_render_color_glyph_func(), and + * cairo_user_font_face_set_render_glyph_func(), the color glyph + * callback will be called first. If the color glyph callback returns + * %CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED, any drawing operations are + * discarded and the non-color callback will be called. This is the + * only case in which the %CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED may + * be returned from a render callback. This fallback sequence allows a + * user font face to contain a combination of both color and non-color + * glyphs. + * + * Returns: %CAIRO_STATUS_SUCCESS upon success, + * %CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED if fallback options should be tried, + * or %CAIRO_STATUS_USER_FONT_ERROR or any other error status on error. + * + * Since: 1.8 + **/ +typedef cairo_status_t (*cairo_user_scaled_font_render_glyph_func_t) (cairo_scaled_font_t *scaled_font, + unsigned long glyph, + cairo_t *cr, + cairo_text_extents_t *extents); + +/** + * cairo_user_scaled_font_text_to_glyphs_func_t: + * @scaled_font: the scaled-font being created + * @utf8: a string of text encoded in UTF-8 + * @utf8_len: length of @utf8 in bytes + * @glyphs: pointer to array of glyphs to fill, in font space + * @num_glyphs: pointer to number of glyphs + * @clusters: pointer to array of cluster mapping information to fill, or %NULL + * @num_clusters: pointer to number of clusters + * @cluster_flags: pointer to location to store cluster flags corresponding to the + * output @clusters + * + * #cairo_user_scaled_font_text_to_glyphs_func_t is the type of function which + * is called to convert input text to an array of glyphs. This is used by the + * cairo_show_text() operation. + * + * Using this callback the user-font has full control on glyphs and their + * positions. That means, it allows for features like ligatures and kerning, + * as well as complex shaping required for scripts like + * Arabic and Indic. + * + * The @num_glyphs argument is preset to the number of glyph entries available + * in the @glyphs buffer. If the @glyphs buffer is %NULL, the value of + * @num_glyphs will be zero. If the provided glyph array is too short for + * the conversion (or for convenience), a new glyph array may be allocated + * using cairo_glyph_allocate() and placed in @glyphs. Upon return, + * @num_glyphs should contain the number of generated glyphs. If the value + * @glyphs points at has changed after the call, the caller will free the + * allocated glyph array using cairo_glyph_free(). The caller will also free + * the original value of @glyphs, so the callback shouldn't do so. + * The callback should populate the glyph indices and positions (in font space) + * assuming that the text is to be shown at the origin. + * + * If @clusters is not %NULL, @num_clusters and @cluster_flags are also + * non-%NULL, and cluster mapping should be computed. The semantics of how + * cluster array allocation works is similar to the glyph array. That is, + * if @clusters initially points to a non-%NULL value, that array may be used + * as a cluster buffer, and @num_clusters points to the number of cluster + * entries available there. If the provided cluster array is too short for + * the conversion (or for convenience), a new cluster array may be allocated + * using cairo_text_cluster_allocate() and placed in @clusters. In this case, + * the original value of @clusters will still be freed by the caller. Upon + * return, @num_clusters should contain the number of generated clusters. + * If the value @clusters points at has changed after the call, the caller + * will free the allocated cluster array using cairo_text_cluster_free(). + * + * The callback is optional. If @num_glyphs is negative upon + * the callback returning or if the return value + * is %CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED, the unicode_to_glyph callback + * is tried. See #cairo_user_scaled_font_unicode_to_glyph_func_t. + * + * Note: While cairo does not impose any limitation on glyph indices, + * some applications may assume that a glyph index fits in a 16-bit + * unsigned integer. As such, it is advised that user-fonts keep their + * glyphs in the 0 to 65535 range. Furthermore, some applications may + * assume that glyph 0 is a special glyph-not-found glyph. User-fonts + * are advised to use glyph 0 for such purposes and do not use that + * glyph value for other purposes. + * + * Returns: %CAIRO_STATUS_SUCCESS upon success, + * %CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED if fallback options should be tried, + * or %CAIRO_STATUS_USER_FONT_ERROR or any other error status on error. + * + * Since: 1.8 + **/ +typedef cairo_status_t (*cairo_user_scaled_font_text_to_glyphs_func_t) (cairo_scaled_font_t *scaled_font, + const char *utf8, + int utf8_len, + cairo_glyph_t **glyphs, + int *num_glyphs, + cairo_text_cluster_t **clusters, + int *num_clusters, + cairo_text_cluster_flags_t *cluster_flags); + +/** + * cairo_user_scaled_font_unicode_to_glyph_func_t: + * @scaled_font: the scaled-font being created + * @unicode: input unicode character code-point + * @glyph_index: output glyph index + * + * #cairo_user_scaled_font_unicode_to_glyph_func_t is the type of function which + * is called to convert an input Unicode character to a single glyph. + * This is used by the cairo_show_text() operation. + * + * This callback is used to provide the same functionality as the + * text_to_glyphs callback does (see #cairo_user_scaled_font_text_to_glyphs_func_t) + * but has much less control on the output, + * in exchange for increased ease of use. The inherent assumption to using + * this callback is that each character maps to one glyph, and that the + * mapping is context independent. It also assumes that glyphs are positioned + * according to their advance width. These mean no ligatures, kerning, or + * complex scripts can be implemented using this callback. + * + * The callback is optional, and only used if text_to_glyphs callback is not + * set or fails to return glyphs. If this callback is not set or if it returns + * %CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED, an identity mapping from Unicode + * code-points to glyph indices is assumed. + * + * Note: While cairo does not impose any limitation on glyph indices, + * some applications may assume that a glyph index fits in a 16-bit + * unsigned integer. As such, it is advised that user-fonts keep their + * glyphs in the 0 to 65535 range. Furthermore, some applications may + * assume that glyph 0 is a special glyph-not-found glyph. User-fonts + * are advised to use glyph 0 for such purposes and do not use that + * glyph value for other purposes. + * + * Returns: %CAIRO_STATUS_SUCCESS upon success, + * %CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED if fallback options should be tried, + * or %CAIRO_STATUS_USER_FONT_ERROR or any other error status on error. + * + * Since: 1.8 + **/ +typedef cairo_status_t (*cairo_user_scaled_font_unicode_to_glyph_func_t) (cairo_scaled_font_t *scaled_font, + unsigned long unicode, + unsigned long *glyph_index); + +/* User-font method setters */ + +cairo_public void +cairo_user_font_face_set_init_func (cairo_font_face_t *font_face, + cairo_user_scaled_font_init_func_t init_func); + +cairo_public void +cairo_user_font_face_set_render_glyph_func (cairo_font_face_t *font_face, + cairo_user_scaled_font_render_glyph_func_t render_glyph_func); + +cairo_public void +cairo_user_font_face_set_render_color_glyph_func (cairo_font_face_t *font_face, + cairo_user_scaled_font_render_glyph_func_t render_glyph_func); + +cairo_public void +cairo_user_font_face_set_text_to_glyphs_func (cairo_font_face_t *font_face, + cairo_user_scaled_font_text_to_glyphs_func_t text_to_glyphs_func); + +cairo_public void +cairo_user_font_face_set_unicode_to_glyph_func (cairo_font_face_t *font_face, + cairo_user_scaled_font_unicode_to_glyph_func_t unicode_to_glyph_func); + +/* User-font method getters */ + +cairo_public cairo_user_scaled_font_init_func_t +cairo_user_font_face_get_init_func (cairo_font_face_t *font_face); + +cairo_public cairo_user_scaled_font_render_glyph_func_t +cairo_user_font_face_get_render_glyph_func (cairo_font_face_t *font_face); + +cairo_public cairo_user_scaled_font_render_glyph_func_t +cairo_user_font_face_get_render_color_glyph_func (cairo_font_face_t *font_face); + +cairo_public cairo_user_scaled_font_text_to_glyphs_func_t +cairo_user_font_face_get_text_to_glyphs_func (cairo_font_face_t *font_face); + +cairo_public cairo_user_scaled_font_unicode_to_glyph_func_t +cairo_user_font_face_get_unicode_to_glyph_func (cairo_font_face_t *font_face); + +cairo_public cairo_pattern_t * +cairo_user_scaled_font_get_foreground_marker (cairo_scaled_font_t *scaled_font); + +cairo_public cairo_pattern_t * +cairo_user_scaled_font_get_foreground_source (cairo_scaled_font_t *scaled_font); + +/* Query functions */ + +cairo_public cairo_operator_t +cairo_get_operator (cairo_t *cr); + +cairo_public cairo_pattern_t * +cairo_get_source (cairo_t *cr); + +cairo_public double +cairo_get_tolerance (cairo_t *cr); + +cairo_public cairo_antialias_t +cairo_get_antialias (cairo_t *cr); + +cairo_public cairo_bool_t +cairo_has_current_point (cairo_t *cr); + +cairo_public void +cairo_get_current_point (cairo_t *cr, double *x, double *y); + +cairo_public cairo_fill_rule_t +cairo_get_fill_rule (cairo_t *cr); + +cairo_public double +cairo_get_line_width (cairo_t *cr); + +cairo_public cairo_bool_t +cairo_get_hairline (cairo_t *cr); + +cairo_public cairo_line_cap_t +cairo_get_line_cap (cairo_t *cr); + +cairo_public cairo_line_join_t +cairo_get_line_join (cairo_t *cr); + +cairo_public double +cairo_get_miter_limit (cairo_t *cr); + +cairo_public int +cairo_get_dash_count (cairo_t *cr); + +cairo_public void +cairo_get_dash (cairo_t *cr, double *dashes, double *offset); + +cairo_public void +cairo_get_matrix (cairo_t *cr, cairo_matrix_t *matrix); + +cairo_public cairo_surface_t * +cairo_get_target (cairo_t *cr); + +cairo_public cairo_surface_t * +cairo_get_group_target (cairo_t *cr); + +/** + * cairo_path_data_type_t: + * @CAIRO_PATH_MOVE_TO: A move-to operation, since 1.0 + * @CAIRO_PATH_LINE_TO: A line-to operation, since 1.0 + * @CAIRO_PATH_CURVE_TO: A curve-to operation, since 1.0 + * @CAIRO_PATH_CLOSE_PATH: A close-path operation, since 1.0 + * + * #cairo_path_data_t is used to describe the type of one portion + * of a path when represented as a #cairo_path_t. + * See #cairo_path_data_t for details. + * + * Since: 1.0 + **/ +typedef enum _cairo_path_data_type { + CAIRO_PATH_MOVE_TO, + CAIRO_PATH_LINE_TO, + CAIRO_PATH_CURVE_TO, + CAIRO_PATH_CLOSE_PATH +} cairo_path_data_type_t; + +/** + * cairo_path_data_t: + * + * #cairo_path_data_t is used to represent the path data inside a + * #cairo_path_t. + * + * The data structure is designed to try to balance the demands of + * efficiency and ease-of-use. A path is represented as an array of + * #cairo_path_data_t, which is a union of headers and points. + * + * Each portion of the path is represented by one or more elements in + * the array, (one header followed by 0 or more points). The length + * value of the header is the number of array elements for the current + * portion including the header, (ie. length == 1 + # of points), and + * where the number of points for each element type is as follows: + * + * + * %CAIRO_PATH_MOVE_TO: 1 point + * %CAIRO_PATH_LINE_TO: 1 point + * %CAIRO_PATH_CURVE_TO: 3 points + * %CAIRO_PATH_CLOSE_PATH: 0 points + * + * + * The semantics and ordering of the coordinate values are consistent + * with cairo_move_to(), cairo_line_to(), cairo_curve_to(), and + * cairo_close_path(). + * + * Here is sample code for iterating through a #cairo_path_t: + * + * + * int i; + * cairo_path_t *path; + * cairo_path_data_t *data; + *   + * path = cairo_copy_path (cr); + *   + * for (i=0; i < path->num_data; i += path->data[i].header.length) { + * data = &path->data[i]; + * switch (data->header.type) { + * case CAIRO_PATH_MOVE_TO: + * do_move_to_things (data[1].point.x, data[1].point.y); + * break; + * case CAIRO_PATH_LINE_TO: + * do_line_to_things (data[1].point.x, data[1].point.y); + * break; + * case CAIRO_PATH_CURVE_TO: + * do_curve_to_things (data[1].point.x, data[1].point.y, + * data[2].point.x, data[2].point.y, + * data[3].point.x, data[3].point.y); + * break; + * case CAIRO_PATH_CLOSE_PATH: + * do_close_path_things (); + * break; + * } + * } + * cairo_path_destroy (path); + * + * + * As of cairo 1.4, cairo does not mind if there are more elements in + * a portion of the path than needed. Such elements can be used by + * users of the cairo API to hold extra values in the path data + * structure. For this reason, it is recommended that applications + * always use data->header.length to + * iterate over the path data, instead of hardcoding the number of + * elements for each element type. + * + * Since: 1.0 + **/ +typedef union _cairo_path_data_t cairo_path_data_t; +union _cairo_path_data_t { + struct { + cairo_path_data_type_t type; + int length; + } header; + struct { + double x, y; + } point; +}; + +/** + * cairo_path_t: + * @status: the current error status + * @data: the elements in the path + * @num_data: the number of elements in the data array + * + * A data structure for holding a path. This data structure serves as + * the return value for cairo_copy_path() and + * cairo_copy_path_flat() as well the input value for + * cairo_append_path(). + * + * See #cairo_path_data_t for hints on how to iterate over the + * actual data within the path. + * + * The num_data member gives the number of elements in the data + * array. This number is larger than the number of independent path + * portions (defined in #cairo_path_data_type_t), since the data + * includes both headers and coordinates for each portion. + * + * Since: 1.0 + **/ +typedef struct cairo_path { + cairo_status_t status; + cairo_path_data_t *data; + int num_data; +} cairo_path_t; + +cairo_public cairo_path_t * +cairo_copy_path (cairo_t *cr); + +cairo_public cairo_path_t * +cairo_copy_path_flat (cairo_t *cr); + +cairo_public void +cairo_append_path (cairo_t *cr, + const cairo_path_t *path); + +cairo_public void +cairo_path_destroy (cairo_path_t *path); + +/* Error status queries */ + +cairo_public cairo_status_t +cairo_status (cairo_t *cr); + +cairo_public const char * +cairo_status_to_string (cairo_status_t status); + +/* Backend device manipulation */ + +cairo_public cairo_device_t * +cairo_device_reference (cairo_device_t *device); + +/** + * cairo_device_type_t: + * @CAIRO_DEVICE_TYPE_DRM: The device is of type Direct Render Manager, since 1.10 + * @CAIRO_DEVICE_TYPE_GL: The device is of type OpenGL, since 1.10 + * @CAIRO_DEVICE_TYPE_SCRIPT: The device is of type script, since 1.10 + * @CAIRO_DEVICE_TYPE_XCB: The device is of type xcb, since 1.10 + * @CAIRO_DEVICE_TYPE_XLIB: The device is of type xlib, since 1.10 + * @CAIRO_DEVICE_TYPE_XML: The device is of type XML, since 1.10 + * @CAIRO_DEVICE_TYPE_COGL: The device is of type cogl, since 1.12 + * @CAIRO_DEVICE_TYPE_WIN32: The device is of type win32, since 1.12 + * @CAIRO_DEVICE_TYPE_INVALID: The device is invalid, since 1.10 + * + * #cairo_device_type_t is used to describe the type of a given + * device. The devices types are also known as "backends" within cairo. + * + * The device type can be queried with cairo_device_get_type() + * + * The various #cairo_device_t functions can be used with devices of + * any type, but some backends also provide type-specific functions + * that must only be called with a device of the appropriate + * type. These functions have names that begin with + * cairo_type_device such as + * cairo_xcb_device_debug_cap_xrender_version(). + * + * The behavior of calling a type-specific function with a device of + * the wrong type is undefined. + * + * New entries may be added in future versions. + * + * Since: 1.10 + **/ +typedef enum _cairo_device_type { + CAIRO_DEVICE_TYPE_DRM, + CAIRO_DEVICE_TYPE_GL, + CAIRO_DEVICE_TYPE_SCRIPT, + CAIRO_DEVICE_TYPE_XCB, + CAIRO_DEVICE_TYPE_XLIB, + CAIRO_DEVICE_TYPE_XML, + CAIRO_DEVICE_TYPE_COGL, + CAIRO_DEVICE_TYPE_WIN32, + + CAIRO_DEVICE_TYPE_INVALID = -1 +} cairo_device_type_t; + +cairo_public cairo_device_type_t +cairo_device_get_type (cairo_device_t *device); + +cairo_public cairo_status_t +cairo_device_status (cairo_device_t *device); + +cairo_public cairo_status_t +cairo_device_acquire (cairo_device_t *device); + +cairo_public void +cairo_device_release (cairo_device_t *device); + +cairo_public void +cairo_device_flush (cairo_device_t *device); + +cairo_public void +cairo_device_finish (cairo_device_t *device); + +cairo_public void +cairo_device_destroy (cairo_device_t *device); + +cairo_public unsigned int +cairo_device_get_reference_count (cairo_device_t *device); + +cairo_public void * +cairo_device_get_user_data (cairo_device_t *device, + const cairo_user_data_key_t *key); + +cairo_public cairo_status_t +cairo_device_set_user_data (cairo_device_t *device, + const cairo_user_data_key_t *key, + void *user_data, + cairo_destroy_func_t destroy); + + +/* Surface manipulation */ + +cairo_public cairo_surface_t * +cairo_surface_create_similar (cairo_surface_t *other, + cairo_content_t content, + int width, + int height); + +cairo_public cairo_surface_t * +cairo_surface_create_similar_image (cairo_surface_t *other, + cairo_format_t format, + int width, + int height); + +cairo_public cairo_surface_t * +cairo_surface_map_to_image (cairo_surface_t *surface, + const cairo_rectangle_int_t *extents); + +cairo_public void +cairo_surface_unmap_image (cairo_surface_t *surface, + cairo_surface_t *image); + +cairo_public cairo_surface_t * +cairo_surface_create_for_rectangle (cairo_surface_t *target, + double x, + double y, + double width, + double height); + +/** + * cairo_surface_observer_mode_t: + * @CAIRO_SURFACE_OBSERVER_NORMAL: no recording is done + * @CAIRO_SURFACE_OBSERVER_RECORD_OPERATIONS: operations are recorded + * + * Whether operations should be recorded. + * + * Since: 1.12 + **/ +typedef enum { + CAIRO_SURFACE_OBSERVER_NORMAL = 0, + CAIRO_SURFACE_OBSERVER_RECORD_OPERATIONS = 0x1 +} cairo_surface_observer_mode_t; + +cairo_public cairo_surface_t * +cairo_surface_create_observer (cairo_surface_t *target, + cairo_surface_observer_mode_t mode); + +/** + * cairo_surface_observer_callback_t: + * @observer: the #cairo_surface_observer_t + * @target: the observed surface + * @data: closure used when adding the callback + * + * A generic callback function for surface operations. + * + * Since: 1.12 + **/ +typedef void (*cairo_surface_observer_callback_t) (cairo_surface_t *observer, + cairo_surface_t *target, + void *data); + +cairo_public cairo_status_t +cairo_surface_observer_add_paint_callback (cairo_surface_t *abstract_surface, + cairo_surface_observer_callback_t func, + void *data); + +cairo_public cairo_status_t +cairo_surface_observer_add_mask_callback (cairo_surface_t *abstract_surface, + cairo_surface_observer_callback_t func, + void *data); + +cairo_public cairo_status_t +cairo_surface_observer_add_fill_callback (cairo_surface_t *abstract_surface, + cairo_surface_observer_callback_t func, + void *data); + +cairo_public cairo_status_t +cairo_surface_observer_add_stroke_callback (cairo_surface_t *abstract_surface, + cairo_surface_observer_callback_t func, + void *data); + +cairo_public cairo_status_t +cairo_surface_observer_add_glyphs_callback (cairo_surface_t *abstract_surface, + cairo_surface_observer_callback_t func, + void *data); + +cairo_public cairo_status_t +cairo_surface_observer_add_flush_callback (cairo_surface_t *abstract_surface, + cairo_surface_observer_callback_t func, + void *data); + +cairo_public cairo_status_t +cairo_surface_observer_add_finish_callback (cairo_surface_t *abstract_surface, + cairo_surface_observer_callback_t func, + void *data); + +cairo_public cairo_status_t +cairo_surface_observer_print (cairo_surface_t *abstract_surface, + cairo_write_func_t write_func, + void *closure); +cairo_public double +cairo_surface_observer_elapsed (cairo_surface_t *abstract_surface); + +cairo_public cairo_status_t +cairo_device_observer_print (cairo_device_t *abstract_device, + cairo_write_func_t write_func, + void *closure); + +cairo_public double +cairo_device_observer_elapsed (cairo_device_t *abstract_device); + +cairo_public double +cairo_device_observer_paint_elapsed (cairo_device_t *abstract_device); + +cairo_public double +cairo_device_observer_mask_elapsed (cairo_device_t *abstract_device); + +cairo_public double +cairo_device_observer_fill_elapsed (cairo_device_t *abstract_device); + +cairo_public double +cairo_device_observer_stroke_elapsed (cairo_device_t *abstract_device); + +cairo_public double +cairo_device_observer_glyphs_elapsed (cairo_device_t *abstract_device); + +cairo_public cairo_surface_t * +cairo_surface_reference (cairo_surface_t *surface); + +cairo_public void +cairo_surface_finish (cairo_surface_t *surface); + +cairo_public void +cairo_surface_destroy (cairo_surface_t *surface); + +cairo_public cairo_device_t * +cairo_surface_get_device (cairo_surface_t *surface); + +cairo_public unsigned int +cairo_surface_get_reference_count (cairo_surface_t *surface); + +cairo_public cairo_status_t +cairo_surface_status (cairo_surface_t *surface); + +/** + * cairo_surface_type_t: + * @CAIRO_SURFACE_TYPE_IMAGE: The surface is of type image, since 1.2 + * @CAIRO_SURFACE_TYPE_PDF: The surface is of type pdf, since 1.2 + * @CAIRO_SURFACE_TYPE_PS: The surface is of type ps, since 1.2 + * @CAIRO_SURFACE_TYPE_XLIB: The surface is of type xlib, since 1.2 + * @CAIRO_SURFACE_TYPE_XCB: The surface is of type xcb, since 1.2 + * @CAIRO_SURFACE_TYPE_GLITZ: The surface is of type glitz, since 1.2, deprecated 1.18 + * (glitz support have been removed, this surface type will never be set by cairo) + * @CAIRO_SURFACE_TYPE_QUARTZ: The surface is of type quartz, since 1.2 + * @CAIRO_SURFACE_TYPE_WIN32: The surface is of type win32, since 1.2 + * @CAIRO_SURFACE_TYPE_BEOS: The surface is of type beos, since 1.2, deprecated 1.18 + * (beos support have been removed, this surface type will never be set by cairo) + * @CAIRO_SURFACE_TYPE_DIRECTFB: The surface is of type directfb, since 1.2, deprecated 1.18 + * (directfb support have been removed, this surface type will never be set by cairo) + * @CAIRO_SURFACE_TYPE_SVG: The surface is of type svg, since 1.2 + * @CAIRO_SURFACE_TYPE_OS2: The surface is of type os2, since 1.4, deprecated 1.18 + * (os2 support have been removed, this surface type will never be set by cairo) + * @CAIRO_SURFACE_TYPE_WIN32_PRINTING: The surface is a win32 printing surface, since 1.6 + * @CAIRO_SURFACE_TYPE_QUARTZ_IMAGE: The surface is of type quartz_image, since 1.6 + * @CAIRO_SURFACE_TYPE_SCRIPT: The surface is of type script, since 1.10 + * @CAIRO_SURFACE_TYPE_QT: The surface is of type Qt, since 1.10, deprecated 1.18 + * (Ot support have been removed, this surface type will never be set by cairo) + * @CAIRO_SURFACE_TYPE_RECORDING: The surface is of type recording, since 1.10 + * @CAIRO_SURFACE_TYPE_VG: The surface is a OpenVG surface, since 1.10, deprecated 1.18 + * (OpenVG support have been removed, this surface type will never be set by cairo) + * @CAIRO_SURFACE_TYPE_GL: The surface is of type OpenGL, since 1.10, deprecated 1.18 + * (OpenGL support have been removed, this surface type will never be set by cairo) + * @CAIRO_SURFACE_TYPE_DRM: The surface is of type Direct Render Manager, since 1.10, deprecated 1.18 + * (DRM support have been removed, this surface type will never be set by cairo) + * @CAIRO_SURFACE_TYPE_TEE: The surface is of type 'tee' (a multiplexing surface), since 1.10 + * @CAIRO_SURFACE_TYPE_XML: The surface is of type XML (for debugging), since 1.10 + * @CAIRO_SURFACE_TYPE_SKIA: The surface is of type Skia, since 1.10, deprecated 1.18 + * (Skia support have been removed, this surface type will never be set by cairo) + * @CAIRO_SURFACE_TYPE_SUBSURFACE: The surface is a subsurface created with + * cairo_surface_create_for_rectangle(), since 1.10 + * @CAIRO_SURFACE_TYPE_COGL: This surface is of type Cogl, since 1.12, deprecated 1.18 + * (Cogl support have been removed, this surface type will never be set by cairo) + * + * #cairo_surface_type_t is used to describe the type of a given + * surface. The surface types are also known as "backends" or "surface + * backends" within cairo. + * + * The type of a surface is determined by the function used to create + * it, which will generally be of the form + * cairo_type_surface_create(), + * (though see cairo_surface_create_similar() as well). + * + * The surface type can be queried with cairo_surface_get_type() + * + * The various #cairo_surface_t functions can be used with surfaces of + * any type, but some backends also provide type-specific functions + * that must only be called with a surface of the appropriate + * type. These functions have names that begin with + * cairo_type_surface such as cairo_image_surface_get_width(). + * + * The behavior of calling a type-specific function with a surface of + * the wrong type is undefined. + * + * New entries may be added in future versions. + * + * Since: 1.2 + **/ +typedef enum _cairo_surface_type { + CAIRO_SURFACE_TYPE_IMAGE, + CAIRO_SURFACE_TYPE_PDF, + CAIRO_SURFACE_TYPE_PS, + CAIRO_SURFACE_TYPE_XLIB, + CAIRO_SURFACE_TYPE_XCB, + CAIRO_SURFACE_TYPE_GLITZ, + CAIRO_SURFACE_TYPE_QUARTZ, + CAIRO_SURFACE_TYPE_WIN32, + CAIRO_SURFACE_TYPE_BEOS, + CAIRO_SURFACE_TYPE_DIRECTFB, + CAIRO_SURFACE_TYPE_SVG, + CAIRO_SURFACE_TYPE_OS2, + CAIRO_SURFACE_TYPE_WIN32_PRINTING, + CAIRO_SURFACE_TYPE_QUARTZ_IMAGE, + CAIRO_SURFACE_TYPE_SCRIPT, + CAIRO_SURFACE_TYPE_QT, + CAIRO_SURFACE_TYPE_RECORDING, + CAIRO_SURFACE_TYPE_VG, + CAIRO_SURFACE_TYPE_GL, + CAIRO_SURFACE_TYPE_DRM, + CAIRO_SURFACE_TYPE_TEE, + CAIRO_SURFACE_TYPE_XML, + CAIRO_SURFACE_TYPE_SKIA, + CAIRO_SURFACE_TYPE_SUBSURFACE, + CAIRO_SURFACE_TYPE_COGL +} cairo_surface_type_t; + +cairo_public cairo_surface_type_t +cairo_surface_get_type (cairo_surface_t *surface); + +cairo_public cairo_content_t +cairo_surface_get_content (cairo_surface_t *surface); + +#if CAIRO_HAS_PNG_FUNCTIONS + +cairo_public cairo_status_t +cairo_surface_write_to_png (cairo_surface_t *surface, + const char *filename); + +cairo_public cairo_status_t +cairo_surface_write_to_png_stream (cairo_surface_t *surface, + cairo_write_func_t write_func, + void *closure); + +#endif + +cairo_public void * +cairo_surface_get_user_data (cairo_surface_t *surface, + const cairo_user_data_key_t *key); + +cairo_public cairo_status_t +cairo_surface_set_user_data (cairo_surface_t *surface, + const cairo_user_data_key_t *key, + void *user_data, + cairo_destroy_func_t destroy); + +#define CAIRO_MIME_TYPE_JPEG "image/jpeg" +#define CAIRO_MIME_TYPE_PNG "image/png" +#define CAIRO_MIME_TYPE_JP2 "image/jp2" +#define CAIRO_MIME_TYPE_URI "text/x-uri" +#define CAIRO_MIME_TYPE_UNIQUE_ID "application/x-cairo.uuid" +#define CAIRO_MIME_TYPE_JBIG2 "application/x-cairo.jbig2" +#define CAIRO_MIME_TYPE_JBIG2_GLOBAL "application/x-cairo.jbig2-global" +#define CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID "application/x-cairo.jbig2-global-id" +#define CAIRO_MIME_TYPE_CCITT_FAX "image/g3fax" +#define CAIRO_MIME_TYPE_CCITT_FAX_PARAMS "application/x-cairo.ccitt.params" +#define CAIRO_MIME_TYPE_EPS "application/postscript" +#define CAIRO_MIME_TYPE_EPS_PARAMS "application/x-cairo.eps.params" + +cairo_public void +cairo_surface_get_mime_data (cairo_surface_t *surface, + const char *mime_type, + const unsigned char **data, + unsigned long *length); + +cairo_public cairo_status_t +cairo_surface_set_mime_data (cairo_surface_t *surface, + const char *mime_type, + const unsigned char *data, + unsigned long length, + cairo_destroy_func_t destroy, + void *closure); + +cairo_public cairo_bool_t +cairo_surface_supports_mime_type (cairo_surface_t *surface, + const char *mime_type); + +cairo_public void +cairo_surface_get_font_options (cairo_surface_t *surface, + cairo_font_options_t *options); + +cairo_public void +cairo_surface_flush (cairo_surface_t *surface); + +cairo_public void +cairo_surface_mark_dirty (cairo_surface_t *surface); + +cairo_public void +cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface, + int x, + int y, + int width, + int height); + +cairo_public void +cairo_surface_set_device_scale (cairo_surface_t *surface, + double x_scale, + double y_scale); + +cairo_public void +cairo_surface_get_device_scale (cairo_surface_t *surface, + double *x_scale, + double *y_scale); + +cairo_public void +cairo_surface_set_device_offset (cairo_surface_t *surface, + double x_offset, + double y_offset); + +cairo_public void +cairo_surface_get_device_offset (cairo_surface_t *surface, + double *x_offset, + double *y_offset); + +cairo_public void +cairo_surface_set_fallback_resolution (cairo_surface_t *surface, + double x_pixels_per_inch, + double y_pixels_per_inch); + +cairo_public void +cairo_surface_get_fallback_resolution (cairo_surface_t *surface, + double *x_pixels_per_inch, + double *y_pixels_per_inch); + +cairo_public void +cairo_surface_copy_page (cairo_surface_t *surface); + +cairo_public void +cairo_surface_show_page (cairo_surface_t *surface); + +cairo_public cairo_bool_t +cairo_surface_has_show_text_glyphs (cairo_surface_t *surface); + +/* Image-surface functions */ + +cairo_public cairo_surface_t * +cairo_image_surface_create (cairo_format_t format, + int width, + int height); + +cairo_public int +cairo_format_stride_for_width (cairo_format_t format, + int width); + +cairo_public cairo_surface_t * +cairo_image_surface_create_for_data (unsigned char *data, + cairo_format_t format, + int width, + int height, + int stride); + +cairo_public unsigned char * +cairo_image_surface_get_data (cairo_surface_t *surface); + +cairo_public cairo_format_t +cairo_image_surface_get_format (cairo_surface_t *surface); + +cairo_public int +cairo_image_surface_get_width (cairo_surface_t *surface); + +cairo_public int +cairo_image_surface_get_height (cairo_surface_t *surface); + +cairo_public int +cairo_image_surface_get_stride (cairo_surface_t *surface); + +#if CAIRO_HAS_PNG_FUNCTIONS + +cairo_public cairo_surface_t * +cairo_image_surface_create_from_png (const char *filename); + +cairo_public cairo_surface_t * +cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func, + void *closure); + +#endif + +/* Recording-surface functions */ + +cairo_public cairo_surface_t * +cairo_recording_surface_create (cairo_content_t content, + const cairo_rectangle_t *extents); + +cairo_public void +cairo_recording_surface_ink_extents (cairo_surface_t *surface, + double *x0, + double *y0, + double *width, + double *height); + +cairo_public cairo_bool_t +cairo_recording_surface_get_extents (cairo_surface_t *surface, + cairo_rectangle_t *extents); + +/* raster-source pattern (callback) functions */ + +/** + * cairo_raster_source_acquire_func_t: + * @pattern: the pattern being rendered from + * @callback_data: the user data supplied during creation + * @target: the rendering target surface + * @extents: rectangular region of interest in pixels in sample space + * + * #cairo_raster_source_acquire_func_t is the type of function which is + * called when a pattern is being rendered from. It should create a surface + * that provides the pixel data for the region of interest as defined by + * extents, though the surface itself does not have to be limited to that + * area. For convenience the surface should probably be of image type, + * created with cairo_surface_create_similar_image() for the target (which + * enables the number of copies to be reduced during transfer to the + * device). Another option, might be to return a similar surface to the + * target for explicit handling by the application of a set of cached sources + * on the device. The region of sample data provided should be defined using + * cairo_surface_set_device_offset() to specify the top-left corner of the + * sample data (along with width and height of the surface). + * + * Returns: a #cairo_surface_t + * + * Since: 1.12 + **/ +typedef cairo_surface_t * +(*cairo_raster_source_acquire_func_t) (cairo_pattern_t *pattern, + void *callback_data, + cairo_surface_t *target, + const cairo_rectangle_int_t *extents); + +/** + * cairo_raster_source_release_func_t: + * @pattern: the pattern being rendered from + * @callback_data: the user data supplied during creation + * @surface: the surface created during acquire + * + * #cairo_raster_source_release_func_t is the type of function which is + * called when the pixel data is no longer being access by the pattern + * for the rendering operation. Typically this function will simply + * destroy the surface created during acquire. + * + * Since: 1.12 + **/ +typedef void +(*cairo_raster_source_release_func_t) (cairo_pattern_t *pattern, + void *callback_data, + cairo_surface_t *surface); + +/** + * cairo_raster_source_snapshot_func_t: + * @pattern: the pattern being rendered from + * @callback_data: the user data supplied during creation + * + * #cairo_raster_source_snapshot_func_t is the type of function which is + * called when the pixel data needs to be preserved for later use + * during printing. This pattern will be accessed again later, and it + * is expected to provide the pixel data that was current at the time + * of snapshotting. + * + * Return value: CAIRO_STATUS_SUCCESS on success, or one of the + * #cairo_status_t error codes for failure. + * + * Since: 1.12 + **/ +typedef cairo_status_t +(*cairo_raster_source_snapshot_func_t) (cairo_pattern_t *pattern, + void *callback_data); + +/** + * cairo_raster_source_copy_func_t: + * @pattern: the #cairo_pattern_t that was copied to + * @callback_data: the user data supplied during creation + * @other: the #cairo_pattern_t being used as the source for the copy + * + * #cairo_raster_source_copy_func_t is the type of function which is + * called when the pattern gets copied as a normal part of rendering. + * + * Return value: CAIRO_STATUS_SUCCESS on success, or one of the + * #cairo_status_t error codes for failure. + * + * Since: 1.12 + **/ +typedef cairo_status_t +(*cairo_raster_source_copy_func_t) (cairo_pattern_t *pattern, + void *callback_data, + const cairo_pattern_t *other); + +/** + * cairo_raster_source_finish_func_t: + * @pattern: the pattern being rendered from + * @callback_data: the user data supplied during creation + * + * #cairo_raster_source_finish_func_t is the type of function which is + * called when the pattern (or a copy thereof) is no longer required. + * + * Since: 1.12 + **/ +typedef void +(*cairo_raster_source_finish_func_t) (cairo_pattern_t *pattern, + void *callback_data); + +cairo_public cairo_pattern_t * +cairo_pattern_create_raster_source (void *user_data, + cairo_content_t content, + int width, int height); + +cairo_public void +cairo_raster_source_pattern_set_callback_data (cairo_pattern_t *pattern, + void *data); + +cairo_public void * +cairo_raster_source_pattern_get_callback_data (cairo_pattern_t *pattern); + +cairo_public void +cairo_raster_source_pattern_set_acquire (cairo_pattern_t *pattern, + cairo_raster_source_acquire_func_t acquire, + cairo_raster_source_release_func_t release); + +cairo_public void +cairo_raster_source_pattern_get_acquire (cairo_pattern_t *pattern, + cairo_raster_source_acquire_func_t *acquire, + cairo_raster_source_release_func_t *release); +cairo_public void +cairo_raster_source_pattern_set_snapshot (cairo_pattern_t *pattern, + cairo_raster_source_snapshot_func_t snapshot); + +cairo_public cairo_raster_source_snapshot_func_t +cairo_raster_source_pattern_get_snapshot (cairo_pattern_t *pattern); + +cairo_public void +cairo_raster_source_pattern_set_copy (cairo_pattern_t *pattern, + cairo_raster_source_copy_func_t copy); + +cairo_public cairo_raster_source_copy_func_t +cairo_raster_source_pattern_get_copy (cairo_pattern_t *pattern); + +cairo_public void +cairo_raster_source_pattern_set_finish (cairo_pattern_t *pattern, + cairo_raster_source_finish_func_t finish); + +cairo_public cairo_raster_source_finish_func_t +cairo_raster_source_pattern_get_finish (cairo_pattern_t *pattern); + +/* Pattern creation functions */ + +cairo_public cairo_pattern_t * +cairo_pattern_create_rgb (double red, double green, double blue); + +cairo_public cairo_pattern_t * +cairo_pattern_create_rgba (double red, double green, double blue, + double alpha); + +cairo_public cairo_pattern_t * +cairo_pattern_create_for_surface (cairo_surface_t *surface); + +cairo_public cairo_pattern_t * +cairo_pattern_create_linear (double x0, double y0, + double x1, double y1); + +cairo_public cairo_pattern_t * +cairo_pattern_create_radial (double cx0, double cy0, double radius0, + double cx1, double cy1, double radius1); + +cairo_public cairo_pattern_t * +cairo_pattern_create_mesh (void); + +cairo_public cairo_pattern_t * +cairo_pattern_reference (cairo_pattern_t *pattern); + +cairo_public void +cairo_pattern_destroy (cairo_pattern_t *pattern); + +cairo_public unsigned int +cairo_pattern_get_reference_count (cairo_pattern_t *pattern); + +cairo_public cairo_status_t +cairo_pattern_status (cairo_pattern_t *pattern); + +cairo_public void * +cairo_pattern_get_user_data (cairo_pattern_t *pattern, + const cairo_user_data_key_t *key); + +cairo_public cairo_status_t +cairo_pattern_set_user_data (cairo_pattern_t *pattern, + const cairo_user_data_key_t *key, + void *user_data, + cairo_destroy_func_t destroy); + +/** + * cairo_pattern_type_t: + * @CAIRO_PATTERN_TYPE_SOLID: The pattern is a solid (uniform) + * color. It may be opaque or translucent, since 1.2. + * @CAIRO_PATTERN_TYPE_SURFACE: The pattern is a based on a surface (an image), since 1.2. + * @CAIRO_PATTERN_TYPE_LINEAR: The pattern is a linear gradient, since 1.2. + * @CAIRO_PATTERN_TYPE_RADIAL: The pattern is a radial gradient, since 1.2. + * @CAIRO_PATTERN_TYPE_MESH: The pattern is a mesh, since 1.12. + * @CAIRO_PATTERN_TYPE_RASTER_SOURCE: The pattern is a user pattern providing raster data, since 1.12. + * + * #cairo_pattern_type_t is used to describe the type of a given pattern. + * + * The type of a pattern is determined by the function used to create + * it. The cairo_pattern_create_rgb() and cairo_pattern_create_rgba() + * functions create SOLID patterns. The remaining + * cairo_pattern_create functions map to pattern types in obvious + * ways. + * + * The pattern type can be queried with cairo_pattern_get_type() + * + * Most #cairo_pattern_t functions can be called with a pattern of any + * type, (though trying to change the extend or filter for a solid + * pattern will have no effect). A notable exception is + * cairo_pattern_add_color_stop_rgb() and + * cairo_pattern_add_color_stop_rgba() which must only be called with + * gradient patterns (either LINEAR or RADIAL). Otherwise the pattern + * will be shutdown and put into an error state. + * + * New entries may be added in future versions. + * + * Since: 1.2 + **/ +typedef enum _cairo_pattern_type { + CAIRO_PATTERN_TYPE_SOLID, + CAIRO_PATTERN_TYPE_SURFACE, + CAIRO_PATTERN_TYPE_LINEAR, + CAIRO_PATTERN_TYPE_RADIAL, + CAIRO_PATTERN_TYPE_MESH, + CAIRO_PATTERN_TYPE_RASTER_SOURCE +} cairo_pattern_type_t; + +cairo_public cairo_pattern_type_t +cairo_pattern_get_type (cairo_pattern_t *pattern); + +cairo_public void +cairo_pattern_add_color_stop_rgb (cairo_pattern_t *pattern, + double offset, + double red, double green, double blue); + +cairo_public void +cairo_pattern_add_color_stop_rgba (cairo_pattern_t *pattern, + double offset, + double red, double green, double blue, + double alpha); + +cairo_public void +cairo_mesh_pattern_begin_patch (cairo_pattern_t *pattern); + +cairo_public void +cairo_mesh_pattern_end_patch (cairo_pattern_t *pattern); + +cairo_public void +cairo_mesh_pattern_curve_to (cairo_pattern_t *pattern, + double x1, double y1, + double x2, double y2, + double x3, double y3); + +cairo_public void +cairo_mesh_pattern_line_to (cairo_pattern_t *pattern, + double x, double y); + +cairo_public void +cairo_mesh_pattern_move_to (cairo_pattern_t *pattern, + double x, double y); + +cairo_public void +cairo_mesh_pattern_set_control_point (cairo_pattern_t *pattern, + unsigned int point_num, + double x, double y); + +cairo_public void +cairo_mesh_pattern_set_corner_color_rgb (cairo_pattern_t *pattern, + unsigned int corner_num, + double red, double green, double blue); + +cairo_public void +cairo_mesh_pattern_set_corner_color_rgba (cairo_pattern_t *pattern, + unsigned int corner_num, + double red, double green, double blue, + double alpha); + +cairo_public void +cairo_pattern_set_matrix (cairo_pattern_t *pattern, + const cairo_matrix_t *matrix); + +cairo_public void +cairo_pattern_get_matrix (cairo_pattern_t *pattern, + cairo_matrix_t *matrix); + +/** + * cairo_extend_t: + * @CAIRO_EXTEND_NONE: pixels outside of the source pattern + * are fully transparent (Since 1.0) + * @CAIRO_EXTEND_REPEAT: the pattern is tiled by repeating (Since 1.0) + * @CAIRO_EXTEND_REFLECT: the pattern is tiled by reflecting + * at the edges (Since 1.0; but only implemented for surface patterns since 1.6) + * @CAIRO_EXTEND_PAD: pixels outside of the pattern copy + * the closest pixel from the source (Since 1.2; but only + * implemented for surface patterns since 1.6) + * + * #cairo_extend_t is used to describe how pattern color/alpha will be + * determined for areas "outside" the pattern's natural area, (for + * example, outside the surface bounds or outside the gradient + * geometry). + * + * Mesh patterns are not affected by the extend mode. + * + * The default extend mode is %CAIRO_EXTEND_NONE for surface patterns + * and %CAIRO_EXTEND_PAD for gradient patterns. + * + * New entries may be added in future versions. + * + * Since: 1.0 + **/ +typedef enum _cairo_extend { + CAIRO_EXTEND_NONE, + CAIRO_EXTEND_REPEAT, + CAIRO_EXTEND_REFLECT, + CAIRO_EXTEND_PAD +} cairo_extend_t; + +cairo_public void +cairo_pattern_set_extend (cairo_pattern_t *pattern, cairo_extend_t extend); + +cairo_public cairo_extend_t +cairo_pattern_get_extend (cairo_pattern_t *pattern); + +/** + * cairo_filter_t: + * @CAIRO_FILTER_FAST: A high-performance filter, with quality similar + * to %CAIRO_FILTER_NEAREST (Since 1.0) + * @CAIRO_FILTER_GOOD: A reasonable-performance filter, with quality + * similar to %CAIRO_FILTER_BILINEAR (Since 1.0) + * @CAIRO_FILTER_BEST: The highest-quality available, performance may + * not be suitable for interactive use. (Since 1.0) + * @CAIRO_FILTER_NEAREST: Nearest-neighbor filtering (Since 1.0) + * @CAIRO_FILTER_BILINEAR: Linear interpolation in two dimensions (Since 1.0) + * @CAIRO_FILTER_GAUSSIAN: This filter value is currently + * unimplemented, and should not be used in current code. (Since 1.0) + * + * #cairo_filter_t is used to indicate what filtering should be + * applied when reading pixel values from patterns. See + * cairo_pattern_set_filter() for indicating the desired filter to be + * used with a particular pattern. + * + * Since: 1.0 + **/ +typedef enum _cairo_filter { + CAIRO_FILTER_FAST, + CAIRO_FILTER_GOOD, + CAIRO_FILTER_BEST, + CAIRO_FILTER_NEAREST, + CAIRO_FILTER_BILINEAR, + CAIRO_FILTER_GAUSSIAN +} cairo_filter_t; + +cairo_public void +cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter); + +cairo_public cairo_filter_t +cairo_pattern_get_filter (cairo_pattern_t *pattern); + +cairo_public cairo_status_t +cairo_pattern_get_rgba (cairo_pattern_t *pattern, + double *red, double *green, + double *blue, double *alpha); + +cairo_public cairo_status_t +cairo_pattern_get_surface (cairo_pattern_t *pattern, + cairo_surface_t **surface); + + +cairo_public cairo_status_t +cairo_pattern_get_color_stop_rgba (cairo_pattern_t *pattern, + int index, double *offset, + double *red, double *green, + double *blue, double *alpha); + +cairo_public cairo_status_t +cairo_pattern_get_color_stop_count (cairo_pattern_t *pattern, + int *count); + +cairo_public cairo_status_t +cairo_pattern_get_linear_points (cairo_pattern_t *pattern, + double *x0, double *y0, + double *x1, double *y1); + +cairo_public cairo_status_t +cairo_pattern_get_radial_circles (cairo_pattern_t *pattern, + double *x0, double *y0, double *r0, + double *x1, double *y1, double *r1); + +cairo_public cairo_status_t +cairo_mesh_pattern_get_patch_count (cairo_pattern_t *pattern, + unsigned int *count); + +cairo_public cairo_path_t * +cairo_mesh_pattern_get_path (cairo_pattern_t *pattern, + unsigned int patch_num); + +cairo_public cairo_status_t +cairo_mesh_pattern_get_corner_color_rgba (cairo_pattern_t *pattern, + unsigned int patch_num, + unsigned int corner_num, + double *red, double *green, + double *blue, double *alpha); + +cairo_public cairo_status_t +cairo_mesh_pattern_get_control_point (cairo_pattern_t *pattern, + unsigned int patch_num, + unsigned int point_num, + double *x, double *y); + +/* Matrix functions */ + +cairo_public void +cairo_matrix_init (cairo_matrix_t *matrix, + double xx, double yx, + double xy, double yy, + double x0, double y0); + +cairo_public void +cairo_matrix_init_identity (cairo_matrix_t *matrix); + +cairo_public void +cairo_matrix_init_translate (cairo_matrix_t *matrix, + double tx, double ty); + +cairo_public void +cairo_matrix_init_scale (cairo_matrix_t *matrix, + double sx, double sy); + +cairo_public void +cairo_matrix_init_rotate (cairo_matrix_t *matrix, + double radians); + +cairo_public void +cairo_matrix_translate (cairo_matrix_t *matrix, double tx, double ty); + +cairo_public void +cairo_matrix_scale (cairo_matrix_t *matrix, double sx, double sy); + +cairo_public void +cairo_matrix_rotate (cairo_matrix_t *matrix, double radians); + +cairo_public cairo_status_t +cairo_matrix_invert (cairo_matrix_t *matrix); + +cairo_public void +cairo_matrix_multiply (cairo_matrix_t *result, + const cairo_matrix_t *a, + const cairo_matrix_t *b); + +cairo_public void +cairo_matrix_transform_distance (const cairo_matrix_t *matrix, + double *dx, double *dy); + +cairo_public void +cairo_matrix_transform_point (const cairo_matrix_t *matrix, + double *x, double *y); + +/* Region functions */ + +/** + * cairo_region_t: + * + * A #cairo_region_t represents a set of integer-aligned rectangles. + * + * It allows set-theoretical operations like cairo_region_union() and + * cairo_region_intersect() to be performed on them. + * + * Memory management of #cairo_region_t is done with + * cairo_region_reference() and cairo_region_destroy(). + * + * Since: 1.10 + **/ +typedef struct _cairo_region cairo_region_t; + +/** + * cairo_region_overlap_t: + * @CAIRO_REGION_OVERLAP_IN: The contents are entirely inside the region. (Since 1.10) + * @CAIRO_REGION_OVERLAP_OUT: The contents are entirely outside the region. (Since 1.10) + * @CAIRO_REGION_OVERLAP_PART: The contents are partially inside and + * partially outside the region. (Since 1.10) + * + * Used as the return value for cairo_region_contains_rectangle(). + * + * Since: 1.10 + **/ +typedef enum _cairo_region_overlap { + CAIRO_REGION_OVERLAP_IN, /* completely inside region */ + CAIRO_REGION_OVERLAP_OUT, /* completely outside region */ + CAIRO_REGION_OVERLAP_PART /* partly inside region */ +} cairo_region_overlap_t; + +cairo_public cairo_region_t * +cairo_region_create (void); + +cairo_public cairo_region_t * +cairo_region_create_rectangle (const cairo_rectangle_int_t *rectangle); + +cairo_public cairo_region_t * +cairo_region_create_rectangles (const cairo_rectangle_int_t *rects, + int count); + +cairo_public cairo_region_t * +cairo_region_copy (const cairo_region_t *original); + +cairo_public cairo_region_t * +cairo_region_reference (cairo_region_t *region); + +cairo_public void +cairo_region_destroy (cairo_region_t *region); + +cairo_public cairo_bool_t +cairo_region_equal (const cairo_region_t *a, const cairo_region_t *b); + +cairo_public cairo_status_t +cairo_region_status (const cairo_region_t *region); + +cairo_public void +cairo_region_get_extents (const cairo_region_t *region, + cairo_rectangle_int_t *extents); + +cairo_public int +cairo_region_num_rectangles (const cairo_region_t *region); + +cairo_public void +cairo_region_get_rectangle (const cairo_region_t *region, + int nth, + cairo_rectangle_int_t *rectangle); + +cairo_public cairo_bool_t +cairo_region_is_empty (const cairo_region_t *region); + +cairo_public cairo_region_overlap_t +cairo_region_contains_rectangle (const cairo_region_t *region, + const cairo_rectangle_int_t *rectangle); + +cairo_public cairo_bool_t +cairo_region_contains_point (const cairo_region_t *region, int x, int y); + +cairo_public void +cairo_region_translate (cairo_region_t *region, int dx, int dy); + +cairo_public cairo_status_t +cairo_region_subtract (cairo_region_t *dst, const cairo_region_t *other); + +cairo_public cairo_status_t +cairo_region_subtract_rectangle (cairo_region_t *dst, + const cairo_rectangle_int_t *rectangle); + +cairo_public cairo_status_t +cairo_region_intersect (cairo_region_t *dst, const cairo_region_t *other); + +cairo_public cairo_status_t +cairo_region_intersect_rectangle (cairo_region_t *dst, + const cairo_rectangle_int_t *rectangle); + +cairo_public cairo_status_t +cairo_region_union (cairo_region_t *dst, const cairo_region_t *other); + +cairo_public cairo_status_t +cairo_region_union_rectangle (cairo_region_t *dst, + const cairo_rectangle_int_t *rectangle); + +cairo_public cairo_status_t +cairo_region_xor (cairo_region_t *dst, const cairo_region_t *other); + +cairo_public cairo_status_t +cairo_region_xor_rectangle (cairo_region_t *dst, + const cairo_rectangle_int_t *rectangle); + +/* Functions to be used while debugging (not intended for use in production code) */ +cairo_public void +cairo_debug_reset_static_data (void); + + +CAIRO_END_DECLS + +#endif /* CAIRO_H */ diff --git a/local/recipes/libs/cairo/source/src/cairoint.h b/local/recipes/libs/cairo/source/src/cairoint.h new file mode 100644 index 0000000000..be1a4ba2af --- /dev/null +++ b/local/recipes/libs/cairo/source/src/cairoint.h @@ -0,0 +1,2005 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + */ + +/* + * These definitions are solely for use by the implementation of cairo + * and constitute no kind of standard. If you need any of these + * functions, please drop me a note. Either the library needs new + * functionality, or there's a way to do what you need using the + * existing published interfaces. cworth@cworth.org + */ + +#ifndef _CAIROINT_H_ +#define _CAIROINT_H_ + +#include "config.h" + +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#define _USE_MATH_DEFINES +#endif +#include +#include +#include + +#include "cairo.h" +#include + +#include "cairo-compiler-private.h" +#include "cairo-error-private.h" + +#if CAIRO_HAS_PDF_SURFACE || \ + CAIRO_HAS_PS_SURFACE || \ + CAIRO_HAS_SCRIPT_SURFACE +#define CAIRO_HAS_DEFLATE_STREAM 1 +#endif + +#if CAIRO_HAS_PS_SURFACE || \ + CAIRO_HAS_PDF_SURFACE || \ + CAIRO_HAS_SVG_SURFACE || \ + CAIRO_HAS_WIN32_SURFACE +#define CAIRO_HAS_FONT_SUBSET 1 +#endif + +#if CAIRO_HAS_PS_SURFACE || \ + CAIRO_HAS_PDF_SURFACE || \ + CAIRO_HAS_FONT_SUBSET +#define CAIRO_HAS_PDF_OPERATORS 1 +#endif + +CAIRO_BEGIN_DECLS + +#undef MIN +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +#undef MAX +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + +#if _XOPEN_SOURCE >= 600 || defined (_ISOC99_SOURCE) +#define ISFINITE(x) isfinite (x) +#else +#define ISFINITE(x) ((x) * (x) >= 0.) /* check for NaNs */ +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#ifndef M_SQRT2 +#define M_SQRT2 1.41421356237309504880 +#endif + +#ifndef M_SQRT1_2 +#define M_SQRT1_2 0.707106781186547524400844362104849039 +#endif + +#undef ARRAY_LENGTH +#define ARRAY_LENGTH(__array) ((int) (sizeof (__array) / sizeof (__array[0]))) + +#undef STRINGIFY +#undef STRINGIFY_ARG +#define STRINGIFY(macro_or_string) STRINGIFY_ARG (macro_or_string) +#define STRINGIFY_ARG(contents) #contents + +#if defined (__GNUC__) +#define cairo_container_of(ptr, type, member) ({ \ + const __typeof__ (((type *) 0)->member) *mptr__ = (ptr); \ + (type *) ((char *) mptr__ - offsetof (type, member)); \ +}) +#else +#define cairo_container_of(ptr, type, member) \ + ((type *)((char *) (ptr) - (char *) &((type *)0)->member)) +#endif + + +#define ASSERT_NOT_REACHED \ +do { \ + assert (!"reached"); \ +} while (0) +#define COMPILE_TIME_ASSERT1(condition, line) \ + typedef int compile_time_assertion_at_line_##line##_failed [(condition)?1:-1] +#define COMPILE_TIME_ASSERT0(condition, line) COMPILE_TIME_ASSERT1(condition, line) +#define COMPILE_TIME_ASSERT(condition) COMPILE_TIME_ASSERT0(condition, __LINE__) + +#define CAIRO_ALPHA_IS_CLEAR(alpha) ((alpha) <= ((double)0x00ff / (double)0xffff)) +#define CAIRO_ALPHA_SHORT_IS_CLEAR(alpha) ((alpha) <= 0x00ff) + +#define CAIRO_ALPHA_IS_OPAQUE(alpha) ((alpha) >= ((double)0xff00 / (double)0xffff)) +#define CAIRO_ALPHA_SHORT_IS_OPAQUE(alpha) ((alpha) >= 0xff00) +#define CAIRO_ALPHA_IS_ZERO(alpha) ((alpha) <= 0.0) + +#define CAIRO_COLOR_IS_CLEAR(color) CAIRO_ALPHA_SHORT_IS_CLEAR ((color)->alpha_short) +#define CAIRO_COLOR_IS_OPAQUE(color) CAIRO_ALPHA_SHORT_IS_OPAQUE ((color)->alpha_short) + +/* Reverse the bits in a byte with 7 operations (no 64-bit): + * Devised by Sean Anderson, July 13, 2001. + * Source: http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith32Bits + */ +#define CAIRO_BITSWAP8(c) ((((c) * 0x0802LU & 0x22110LU) | ((c) * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16) + +/* Return the number of 1 bits in mask. + * + * GCC 3.4 supports a "population count" builtin, which on many targets is + * implemented with a single instruction. There is a fallback definition + * in libgcc in case a target does not have one, which should be just as + * good as the open-coded solution below, (which is "HACKMEM 169"). + */ +static inline int cairo_const +_cairo_popcount (uint32_t mask) +{ +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) + return __builtin_popcount (mask); +#else + register int y; + + y = (mask >> 1) &033333333333; + y = mask - y - ((y >>1) & 033333333333); + return (((y + (y >> 3)) & 030707070707) % 077); +#endif +} + +static cairo_always_inline cairo_bool_t +_cairo_is_little_endian (void) +{ + static const int i = 1; + return *((char *) &i) == 0x01; +} + +#ifdef WORDS_BIGENDIAN +#define CAIRO_BITSWAP8_IF_LITTLE_ENDIAN(c) (c) +#else +#define CAIRO_BITSWAP8_IF_LITTLE_ENDIAN(c) CAIRO_BITSWAP8(c) +#endif + +#ifdef WORDS_BIGENDIAN + +#define cpu_to_be16(v) (v) +#define be16_to_cpu(v) (v) +#define cpu_to_be32(v) (v) +#define be32_to_cpu(v) (v) + +#else + +static inline uint16_t cairo_const +cpu_to_be16(uint16_t v) +{ + return (v << 8) | (v >> 8); +} + +static inline uint16_t cairo_const +be16_to_cpu(uint16_t v) +{ + return cpu_to_be16 (v); +} + +static inline uint32_t cairo_const +cpu_to_be32(uint32_t v) +{ + return (v >> 24) | ((v >> 8) & 0xff00) | ((v << 8) & 0xff0000) | (v << 24); +} + +static inline uint32_t cairo_const +be32_to_cpu(uint32_t v) +{ + return cpu_to_be32 (v); +} + +#endif + +/* Unaligned big endian access + */ + +static inline uint16_t get_unaligned_be16 (const unsigned char *p) +{ + return p[0] << 8 | p[1]; +} + +static inline uint32_t get_unaligned_be32 (const unsigned char *p) +{ + return (uint32_t)p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; +} + +static inline void put_unaligned_be16 (uint16_t v, unsigned char *p) +{ + p[0] = (v >> 8) & 0xff; + p[1] = v & 0xff; +} + +static inline void put_unaligned_be32 (uint32_t v, unsigned char *p) +{ + p[0] = (v >> 24) & 0xff; + p[1] = (v >> 16) & 0xff; + p[2] = (v >> 8) & 0xff; + p[3] = v & 0xff; +} + +#include "cairo-ctype-inline.h" +#include "cairo-types-private.h" +#include "cairo-cache-private.h" +#include "cairo-reference-count-private.h" +#include "cairo-spans-private.h" +#include "cairo-surface-private.h" + +cairo_private void +_cairo_box_from_doubles (cairo_box_t *box, + double *x1, double *y1, + double *x2, double *y2); + +cairo_private void +_cairo_box_to_doubles (const cairo_box_t *box, + double *x1, double *y1, + double *x2, double *y2); + +cairo_private void +_cairo_box_from_rectangle (cairo_box_t *box, + const cairo_rectangle_int_t *rectangle); + +cairo_private void +_cairo_box_round_to_rectangle (const cairo_box_t *box, + cairo_rectangle_int_t *rectangle); + +cairo_private void +_cairo_box_add_curve_to (cairo_box_t *extents, + const cairo_point_t *a, + const cairo_point_t *b, + const cairo_point_t *c, + const cairo_point_t *d); + +cairo_private void +_cairo_boxes_get_extents (const cairo_box_t *boxes, + int num_boxes, + cairo_box_t *extents); + +cairo_private extern const cairo_rectangle_int_t _cairo_empty_rectangle; +cairo_private extern const cairo_rectangle_int_t _cairo_unbounded_rectangle; + +static inline void +_cairo_unbounded_rectangle_init (cairo_rectangle_int_t *rect) +{ + *rect = _cairo_unbounded_rectangle; +} + +cairo_private_no_warn cairo_bool_t +_cairo_rectangle_intersect (cairo_rectangle_int_t *dst, + const cairo_rectangle_int_t *src); + +static inline cairo_bool_t +_cairo_rectangle_intersects (const cairo_rectangle_int_t *dst, + const cairo_rectangle_int_t *src) +{ + return !(src->x >= dst->x + dst->width || + src->x + src->width <= dst->x || + src->y >= dst->y + dst->height || + src->y + src->height <= dst->y); +} + +static inline cairo_bool_t +_cairo_rectangle_contains_rectangle (const cairo_rectangle_int_t *a, + const cairo_rectangle_int_t *b) +{ + return (a->x <= b->x && + a->x + a->width >= b->x + b->width && + a->y <= b->y && + a->y + a->height >= b->y + b->height); +} + +cairo_private void +_cairo_rectangle_int_from_double (cairo_rectangle_int_t *recti, + const cairo_rectangle_t *rectf); + +/* Extends the dst rectangle to also contain src. + * If one of the rectangles is empty, the result is undefined + */ +cairo_private void +_cairo_rectangle_union (cairo_rectangle_int_t *dst, + const cairo_rectangle_int_t *src); + +cairo_private cairo_bool_t +_cairo_box_intersects_line_segment (const cairo_box_t *box, + cairo_line_t *line) cairo_pure; + +cairo_private cairo_bool_t +_cairo_spline_intersects (const cairo_point_t *a, + const cairo_point_t *b, + const cairo_point_t *c, + const cairo_point_t *d, + const cairo_box_t *box) cairo_pure; + +typedef struct { + const cairo_user_data_key_t *key; + void *user_data; + cairo_destroy_func_t destroy; +} cairo_user_data_slot_t; + +cairo_private void +_cairo_user_data_array_init (cairo_user_data_array_t *array); + +cairo_private void +_cairo_user_data_array_fini (cairo_user_data_array_t *array); + +cairo_private void * +_cairo_user_data_array_get_data (cairo_user_data_array_t *array, + const cairo_user_data_key_t *key); + +cairo_private cairo_status_t +_cairo_user_data_array_set_data (cairo_user_data_array_t *array, + const cairo_user_data_key_t *key, + void *user_data, + cairo_destroy_func_t destroy); + +cairo_private cairo_status_t +_cairo_user_data_array_copy (cairo_user_data_array_t *dst, + const cairo_user_data_array_t *src); + +cairo_private void +_cairo_user_data_array_foreach (cairo_user_data_array_t *array, + void (*func) (const void *key, + void *elt, + void *closure), + void *closure); + +#define _CAIRO_HASH_INIT_VALUE 5381 + +cairo_private uintptr_t +_cairo_hash_string (const char *c); + +cairo_private uintptr_t +_cairo_hash_bytes (uintptr_t hash, + const void *bytes, + unsigned int length); + +cairo_private uintptr_t +_cairo_hash_uintptr (uintptr_t hash, + uintptr_t u); + +/* We use bits 24-27 to store phases for subpixel positions */ +#define _cairo_scaled_glyph_index(g) ((unsigned long)((g)->hash_entry.hash & 0xffffff)) +#define _cairo_scaled_glyph_xphase(g) (int)(((g)->hash_entry.hash >> 24) & 3) +#define _cairo_scaled_glyph_yphase(g) (int)(((g)->hash_entry.hash >> 26) & 3) +#define _cairo_scaled_glyph_set_index(g, i) ((g)->hash_entry.hash = (i)) + +#include "cairo-scaled-font-private.h" + +struct _cairo_font_face { + /* hash_entry must be first */ + cairo_hash_entry_t hash_entry; + cairo_status_t status; + cairo_reference_count_t ref_count; + cairo_user_data_array_t user_data; + const cairo_font_face_backend_t *backend; +}; + +cairo_private void +_cairo_default_context_reset_static_data (void); + +cairo_private void +_cairo_toy_font_face_reset_static_data (void); + +cairo_private void +_cairo_ft_font_reset_static_data (void); + +cairo_private void +_cairo_win32_font_reset_static_data (void); + +/* the font backend interface */ + +struct _cairo_unscaled_font_backend { + cairo_bool_t (*destroy) (void *unscaled_font); +}; + +/* #cairo_toy_font_face_t - simple family/slant/weight font faces used for + * the built-in font API + */ + +typedef struct _cairo_toy_font_face { + cairo_font_face_t base; + const char *family; + cairo_bool_t owns_family; + cairo_font_slant_t slant; + cairo_font_weight_t weight; + + cairo_font_face_t *impl_face; /* The non-toy font face this actually uses */ +} cairo_toy_font_face_t; + +typedef enum _cairo_scaled_glyph_info { + CAIRO_SCALED_GLYPH_INFO_METRICS = (1 << 0), + CAIRO_SCALED_GLYPH_INFO_SURFACE = (1 << 1), + CAIRO_SCALED_GLYPH_INFO_PATH = (1 << 2), + CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE = (1 << 3), + CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE = (1 << 4) +} cairo_scaled_glyph_info_t; + +typedef struct _cairo_scaled_font_subset { + cairo_scaled_font_t *scaled_font; + unsigned int font_id; + unsigned int subset_id; + + /* Index of glyphs array is subset_glyph_index. + * Value of glyphs array is scaled_font_glyph_index. + */ + unsigned long *glyphs; + char **utf8; + char **glyph_names; + int *to_latin_char; + unsigned long *latin_to_subset_glyph_index; + unsigned int num_glyphs; + cairo_bool_t is_composite; + cairo_bool_t is_scaled; + cairo_bool_t is_latin; +} cairo_scaled_font_subset_t; + +struct _cairo_scaled_font_backend { + cairo_font_type_t type; + + void + (*fini) (void *scaled_font); + + /* + * Get the requested glyph info. + * @scaled_font: a #cairo_scaled_font_t + * @scaled_glyph: a #cairo_scaled_glyph_t the glyph + * @info: a #cairo_scaled_glyph_info_t which information to retrieve + * %CAIRO_SCALED_GLYPH_INFO_METRICS - glyph metrics and bounding box + * %CAIRO_SCALED_GLYPH_INFO_SURFACE - surface holding glyph image + * %CAIRO_SCALED_GLYPH_INFO_PATH - path holding glyph outline in device space + * %CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE - surface holding recording of glyph + * %CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE - surface holding color glyph image + * @foreground_color - foreground color to use when rendering color fonts. Use NULL + * if not requesting CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE or foreground color is unknown. + */ + cairo_warn cairo_int_status_t + (*scaled_glyph_init) (void *scaled_font, + cairo_scaled_glyph_t *scaled_glyph, + cairo_scaled_glyph_info_t info, + const cairo_color_t *foreground_color); + + /* A backend only needs to implement this or ucs4_to_index(), not + * both. This allows the backend to do something more sophisticated + * then just converting characters one by one. + */ + cairo_warn cairo_int_status_t + (*text_to_glyphs) (void *scaled_font, + double x, + double y, + const char *utf8, + int utf8_len, + cairo_glyph_t **glyphs, + int *num_glyphs, + cairo_text_cluster_t **clusters, + int *num_clusters, + cairo_text_cluster_flags_t *cluster_flags); + + /* Get the glyph index for the given unicode code point. + * @scaled_font: a #cairo_scaled_font_t + * @ucs4: unicode code point + * Returns glyph index or 0 if not found. + */ + unsigned long + (*ucs4_to_index) (void *scaled_font, + uint32_t ucs4); + + /* Read data from a sfnt font table. + * @scaled_font: font + * @tag: 4 byte table name specifying the table to read. + * @offset: offset into the table + * @buffer: buffer to write data into. Caller must ensure there is sufficient space. + * If NULL, return the size of the table in @length. + * @length: If @buffer is NULL, the size of the table will be returned in @length. + * If @buffer is not null, @length specifies the number of bytes to read. + * + * If less than @length bytes are available to read this function + * returns CAIRO_INT_STATUS_UNSUPPORTED. Note that requesting more + * bytes than are available in the table may continue reading data + * from the following table and return success. If this is + * undesirable the caller should first query the table size. If an + * error occurs the output value of @length is undefined. + * + * Returns CAIRO_INT_STATUS_UNSUPPORTED if not a sfnt style font or table not found. + */ + cairo_warn cairo_int_status_t + (*load_truetype_table)(void *scaled_font, + unsigned long tag, + long offset, + unsigned char *buffer, + unsigned long *length); + + /* ucs4 is set to -1 if the unicode character could not be found + * for the glyph */ + cairo_warn cairo_int_status_t + (*index_to_ucs4)(void *scaled_font, + unsigned long index, + uint32_t *ucs4); + + /* Determine if this scaled font differs from the outlines in the font tables. + * eg synthesized bold/italic or a non default variant of a variable font. + * @scaled_font: font + * @is_sythetic: returns TRUE if scaled font is synthetic + * Returns cairo status + */ + cairo_warn cairo_int_status_t + (*is_synthetic)(void *scaled_font, + cairo_bool_t *is_synthetic); + + /* For type 1 fonts, return the glyph name for a given glyph index. + * A glyph index and list of glyph names in the Type 1 fonts is provided. + * The function returns the index of the glyph in the list of glyph names. + * @scaled_font: font + * @glyph_names: the names of each glyph in the Type 1 font in the + * order they appear in the CharStrings array + * @num_glyph_names: the number of names in the glyph_names array + * @glyph_index: the given glyph index + * @glyph_array_index: (index into glyph_names) the glyph name corresponding + * to the glyph_index + */ + cairo_warn cairo_int_status_t + (*index_to_glyph_name)(void *scaled_font, + char **glyph_names, + int num_glyph_names, + unsigned long glyph_index, + unsigned long *glyph_array_index); + + /* Read data from a PostScript font. + * @scaled_font: font + * @offset: offset into the table + * @buffer: buffer to write data into. Caller must ensure there is sufficient space. + * If NULL, return the size of the table in @length. + * @length: If @buffer is NULL, the size of the table will be returned in @length. + * If @buffer is not null, @length specifies the number of bytes to read. + * + * If less than @length bytes are available to read this function + * returns CAIRO_INT_STATUS_UNSUPPORTED. If an error occurs the + * output value of @length is undefined. + * + * Returns CAIRO_INT_STATUS_UNSUPPORTED if not a Type 1 font. + */ + cairo_warn cairo_int_status_t + (*load_type1_data) (void *scaled_font, + long offset, + unsigned char *buffer, + unsigned long *length); + + /* Check if font has any color glyphs. + * @scaled_font: font + * Returns TRUE if font contains any color glyphs + */ + cairo_bool_t + (*has_color_glyphs) (void *scaled_font); +}; + +struct _cairo_font_face_backend { + cairo_font_type_t type; + + cairo_warn cairo_status_t + (*create_for_toy) (cairo_toy_font_face_t *toy_face, + cairo_font_face_t **font_face); + + /* The destroy() function is allowed to resurrect the font face + * by re-referencing. This is needed for the FreeType backend. + */ + cairo_bool_t + (*destroy) (void *font_face); + + cairo_warn cairo_status_t + (*scaled_font_create) (void *font_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **scaled_font); + + cairo_font_face_t * + (*get_implementation) (void *font_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options); +}; + +extern const cairo_private struct _cairo_font_face_backend _cairo_user_font_face_backend; + +/* concrete font backends */ +#if CAIRO_HAS_FT_FONT + +extern const cairo_private struct _cairo_font_face_backend _cairo_ft_font_face_backend; + +#endif + +#if CAIRO_HAS_WIN32_FONT + +extern const cairo_private struct _cairo_font_face_backend _cairo_win32_font_face_backend; + +#endif + +#if CAIRO_HAS_DWRITE_FONT + +extern const cairo_private struct _cairo_font_face_backend _cairo_dwrite_font_face_backend; + +#endif + +#if CAIRO_HAS_QUARTZ_FONT + +extern const cairo_private struct _cairo_font_face_backend _cairo_quartz_font_face_backend; + +#endif + +#define CAIRO_EXTEND_SURFACE_DEFAULT CAIRO_EXTEND_NONE +#define CAIRO_EXTEND_GRADIENT_DEFAULT CAIRO_EXTEND_PAD +#define CAIRO_FILTER_DEFAULT CAIRO_FILTER_GOOD + +extern const cairo_private cairo_solid_pattern_t _cairo_pattern_clear; +extern const cairo_private cairo_solid_pattern_t _cairo_pattern_black; +extern const cairo_private cairo_solid_pattern_t _cairo_pattern_white; + +struct _cairo_surface_attributes { + cairo_matrix_t matrix; + cairo_extend_t extend; + cairo_filter_t filter; + cairo_bool_t has_component_alpha; + int x_offset; + int y_offset; + void *extra; +}; + +#define CAIRO_FONT_SLANT_DEFAULT CAIRO_FONT_SLANT_NORMAL +#define CAIRO_FONT_WEIGHT_DEFAULT CAIRO_FONT_WEIGHT_NORMAL + +#define CAIRO_WIN32_FONT_FAMILY_DEFAULT "Arial" +#define CAIRO_DWRITE_FONT_FAMILY_DEFAULT "Arial" +#define CAIRO_QUARTZ_FONT_FAMILY_DEFAULT "Helvetica" +#define CAIRO_FT_FONT_FAMILY_DEFAULT "" +#define CAIRO_USER_FONT_FAMILY_DEFAULT "@cairo:" + +#if CAIRO_HAS_DWRITE_FONT + +#define CAIRO_FONT_FAMILY_DEFAULT CAIRO_DWRITE_FONT_FAMILY_DEFAULT +#define CAIRO_FONT_FACE_BACKEND_DEFAULT &_cairo_dwrite_font_face_backend + +#elif CAIRO_HAS_WIN32_FONT + +#define CAIRO_FONT_FAMILY_DEFAULT CAIRO_WIN32_FONT_FAMILY_DEFAULT +#define CAIRO_FONT_FACE_BACKEND_DEFAULT &_cairo_win32_font_face_backend + +#elif CAIRO_HAS_QUARTZ_FONT + +#define CAIRO_FONT_FAMILY_DEFAULT CAIRO_QUARTZ_FONT_FAMILY_DEFAULT +#define CAIRO_FONT_FACE_BACKEND_DEFAULT &_cairo_quartz_font_face_backend + +#elif CAIRO_HAS_FT_FONT + +#define CAIRO_FONT_FAMILY_DEFAULT CAIRO_FT_FONT_FAMILY_DEFAULT +#define CAIRO_FONT_FACE_BACKEND_DEFAULT &_cairo_ft_font_face_backend + +#else + +#define CAIRO_FONT_FAMILY_DEFAULT CAIRO_FT_FONT_FAMILY_DEFAULT +#define CAIRO_FONT_FACE_BACKEND_DEFAULT &_cairo_user_font_face_backend + +#endif + +#define CAIRO_GSTATE_OPERATOR_DEFAULT CAIRO_OPERATOR_OVER +#define CAIRO_GSTATE_TOLERANCE_DEFAULT 0.1 +#define CAIRO_GSTATE_FILL_RULE_DEFAULT CAIRO_FILL_RULE_WINDING +#define CAIRO_GSTATE_LINE_WIDTH_DEFAULT 2.0 +#define CAIRO_GSTATE_LINE_CAP_DEFAULT CAIRO_LINE_CAP_BUTT +#define CAIRO_GSTATE_LINE_JOIN_DEFAULT CAIRO_LINE_JOIN_MITER +#define CAIRO_GSTATE_MITER_LIMIT_DEFAULT 10.0 +#define CAIRO_GSTATE_DEFAULT_FONT_SIZE 10.0 + +#define CAIRO_SURFACE_RESOLUTION_DEFAULT 72.0 +#define CAIRO_SURFACE_FALLBACK_RESOLUTION_DEFAULT 300.0 + +typedef struct _cairo_stroke_face { + cairo_point_t ccw; + cairo_point_t point; + cairo_point_t cw; + cairo_slope_t dev_vector; + cairo_point_double_t dev_slope; + cairo_point_double_t usr_vector; + double length; +} cairo_stroke_face_t; + +/* cairo.c */ + +static inline double cairo_const +_cairo_restrict_value (double value, double min, double max) +{ + if (value < min) + return min; + else if (value > max) + return max; + else + return value; +} + +/* C99 round() rounds to the nearest integral value with halfway cases rounded + * away from 0. _cairo_round rounds halfway cases toward positive infinity. + * This matches the rounding behaviour of _cairo_lround. */ +static inline double cairo_const +_cairo_round (double r) +{ + return floor (r + .5); +} + +#if DISABLE_SOME_FLOATING_POINT +cairo_private int +_cairo_lround (double d) cairo_const; +#else +static inline int cairo_const +_cairo_lround (double r) +{ + return _cairo_round (r); +} +#endif + +cairo_private uint16_t +_cairo_half_from_float (float f) cairo_const; + +cairo_private cairo_bool_t +_cairo_operator_bounded_by_mask (cairo_operator_t op) cairo_const; + +cairo_private cairo_bool_t +_cairo_operator_bounded_by_source (cairo_operator_t op) cairo_const; + +enum { + CAIRO_OPERATOR_BOUND_BY_MASK = 1 << 1, + CAIRO_OPERATOR_BOUND_BY_SOURCE = 1 << 2, +}; + +cairo_private uint32_t +_cairo_operator_bounded_by_either (cairo_operator_t op) cairo_const; +/* cairo-color.c */ +cairo_private const cairo_color_t * +_cairo_stock_color (cairo_stock_t stock) cairo_pure; + +#define CAIRO_COLOR_WHITE _cairo_stock_color (CAIRO_STOCK_WHITE) +#define CAIRO_COLOR_BLACK _cairo_stock_color (CAIRO_STOCK_BLACK) +#define CAIRO_COLOR_TRANSPARENT _cairo_stock_color (CAIRO_STOCK_TRANSPARENT) + +cairo_private uint16_t +_cairo_color_double_to_short (double d) cairo_const; + +cairo_private void +_cairo_color_init_rgba (cairo_color_t *color, + double red, double green, double blue, + double alpha); + +cairo_private void +_cairo_color_multiply_alpha (cairo_color_t *color, + double alpha); + +cairo_private void +_cairo_color_get_rgba (cairo_color_t *color, + double *red, + double *green, + double *blue, + double *alpha); + +cairo_private void +_cairo_color_get_rgba_premultiplied (cairo_color_t *color, + double *red, + double *green, + double *blue, + double *alpha); + +cairo_private cairo_bool_t +_cairo_color_equal (const cairo_color_t *color_a, + const cairo_color_t *color_b) cairo_pure; + +cairo_private cairo_bool_t +_cairo_color_stop_equal (const cairo_color_stop_t *color_a, + const cairo_color_stop_t *color_b) cairo_pure; + +cairo_private cairo_content_t +_cairo_color_get_content (const cairo_color_t *color) cairo_pure; + +/* cairo-font-face.c */ + +extern const cairo_private cairo_font_face_t _cairo_font_face_nil; +extern const cairo_private cairo_font_face_t _cairo_font_face_nil_file_not_found; + +cairo_private void +_cairo_font_face_init (cairo_font_face_t *font_face, + const cairo_font_face_backend_t *backend); + +cairo_private cairo_bool_t +_cairo_font_face_destroy (void *abstract_face); + +cairo_private cairo_status_t +_cairo_font_face_set_error (cairo_font_face_t *font_face, + cairo_status_t status); + +cairo_private void +_cairo_unscaled_font_init (cairo_unscaled_font_t *font, + const cairo_unscaled_font_backend_t *backend); + +cairo_private_no_warn cairo_unscaled_font_t * +_cairo_unscaled_font_reference (cairo_unscaled_font_t *font); + +cairo_private void +_cairo_unscaled_font_destroy (cairo_unscaled_font_t *font); + +/* cairo-font-face-twin.c */ + +cairo_private cairo_font_face_t * +_cairo_font_face_twin_create_fallback (void); + +cairo_private cairo_status_t +_cairo_font_face_twin_create_for_toy (cairo_toy_font_face_t *toy_face, + cairo_font_face_t **font_face); + +/* cairo-font-face-twin-data.c */ + +extern const cairo_private int8_t _cairo_twin_outlines[]; +extern const cairo_private uint16_t _cairo_twin_charmap[128]; + +/* cairo-font-options.c */ + +cairo_private void +_cairo_font_options_init_default (cairo_font_options_t *options); + +cairo_private void +_cairo_font_options_init_copy (cairo_font_options_t *options, + const cairo_font_options_t *other); + +cairo_private cairo_bool_t +_cairo_font_options_compare (const cairo_font_options_t *a, + const cairo_font_options_t *b); + +cairo_private void +_cairo_font_options_fini (cairo_font_options_t *options); + +cairo_private void +_cairo_font_options_set_lcd_filter (cairo_font_options_t *options, + cairo_lcd_filter_t lcd_filter); + +cairo_private cairo_lcd_filter_t +_cairo_font_options_get_lcd_filter (const cairo_font_options_t *options); + +cairo_private void +_cairo_font_options_set_round_glyph_positions (cairo_font_options_t *options, + cairo_round_glyph_positions_t round); + +cairo_private cairo_round_glyph_positions_t +_cairo_font_options_get_round_glyph_positions (const cairo_font_options_t *options); + +/* cairo-hull.c */ +cairo_private cairo_status_t +_cairo_hull_compute (cairo_pen_vertex_t *vertices, int *num_vertices); + +/* cairo-lzw.c */ +cairo_private unsigned char * +_cairo_lzw_compress (unsigned char *data, unsigned long *size_in_out); + +/* cairo-misc.c */ +cairo_private cairo_status_t +_cairo_validate_text_clusters (const char *utf8, + int utf8_len, + const cairo_glyph_t *glyphs, + int num_glyphs, + const cairo_text_cluster_t *clusters, + int num_clusters, + cairo_text_cluster_flags_t cluster_flags); + +cairo_private unsigned long +_cairo_string_hash (const char *str, int len); + +cairo_private cairo_status_t +_cairo_intern_string (const char **str_inout, int len); + +cairo_private void +_cairo_intern_string_reset_static_data (void); + +cairo_private const char * +_cairo_get_locale_decimal_point (void); + +cairo_private double +_cairo_strtod (const char *nptr, char **endptr); + +#ifdef HAVE_STRNDUP +#define _cairo_strndup strndup +#else +cairo_private char * +_cairo_strndup (const char *s, size_t n); +#endif + +/* cairo-path-fixed.c */ +cairo_private cairo_path_fixed_t * +_cairo_path_fixed_create (void); + +cairo_private void +_cairo_path_fixed_init (cairo_path_fixed_t *path); + +cairo_private cairo_status_t +_cairo_path_fixed_init_copy (cairo_path_fixed_t *path, + const cairo_path_fixed_t *other); + +cairo_private void +_cairo_path_fixed_fini (cairo_path_fixed_t *path); + +cairo_private void +_cairo_path_fixed_destroy (cairo_path_fixed_t *path); + +cairo_private cairo_status_t +_cairo_path_fixed_move_to (cairo_path_fixed_t *path, + cairo_fixed_t x, + cairo_fixed_t y); + +cairo_private void +_cairo_path_fixed_new_sub_path (cairo_path_fixed_t *path); + +cairo_private cairo_status_t +_cairo_path_fixed_rel_move_to (cairo_path_fixed_t *path, + cairo_fixed_t dx, + cairo_fixed_t dy); + +cairo_private cairo_status_t +_cairo_path_fixed_line_to (cairo_path_fixed_t *path, + cairo_fixed_t x, + cairo_fixed_t y); + +cairo_private cairo_status_t +_cairo_path_fixed_rel_line_to (cairo_path_fixed_t *path, + cairo_fixed_t dx, + cairo_fixed_t dy); + +cairo_private cairo_status_t +_cairo_path_fixed_curve_to (cairo_path_fixed_t *path, + cairo_fixed_t x0, cairo_fixed_t y0, + cairo_fixed_t x1, cairo_fixed_t y1, + cairo_fixed_t x2, cairo_fixed_t y2); + +cairo_private cairo_status_t +_cairo_path_fixed_rel_curve_to (cairo_path_fixed_t *path, + cairo_fixed_t dx0, cairo_fixed_t dy0, + cairo_fixed_t dx1, cairo_fixed_t dy1, + cairo_fixed_t dx2, cairo_fixed_t dy2); + +cairo_private cairo_status_t +_cairo_path_fixed_close_path (cairo_path_fixed_t *path); + +cairo_private cairo_bool_t +_cairo_path_fixed_get_current_point (cairo_path_fixed_t *path, + cairo_fixed_t *x, + cairo_fixed_t *y); + +typedef cairo_status_t +(cairo_path_fixed_move_to_func_t) (void *closure, + const cairo_point_t *point); + +typedef cairo_status_t +(cairo_path_fixed_line_to_func_t) (void *closure, + const cairo_point_t *point); + +typedef cairo_status_t +(cairo_path_fixed_curve_to_func_t) (void *closure, + const cairo_point_t *p0, + const cairo_point_t *p1, + const cairo_point_t *p2); + +typedef cairo_status_t +(cairo_path_fixed_close_path_func_t) (void *closure); + +cairo_private cairo_status_t +_cairo_path_fixed_interpret (const cairo_path_fixed_t *path, + cairo_path_fixed_move_to_func_t *move_to, + cairo_path_fixed_line_to_func_t *line_to, + cairo_path_fixed_curve_to_func_t *curve_to, + cairo_path_fixed_close_path_func_t *close_path, + void *closure); + +cairo_private cairo_status_t +_cairo_path_fixed_interpret_flat (const cairo_path_fixed_t *path, + cairo_path_fixed_move_to_func_t *move_to, + cairo_path_fixed_line_to_func_t *line_to, + cairo_path_fixed_close_path_func_t *close_path, + void *closure, + double tolerance); + + +cairo_private cairo_bool_t +_cairo_path_bounder_extents (const cairo_path_fixed_t *path, + cairo_box_t *box); + +cairo_private cairo_bool_t +_cairo_path_fixed_extents (const cairo_path_fixed_t *path, + cairo_box_t *box); + +cairo_private void +_cairo_path_fixed_approximate_clip_extents (const cairo_path_fixed_t *path, + cairo_rectangle_int_t *extents); + +cairo_private void +_cairo_path_fixed_approximate_fill_extents (const cairo_path_fixed_t *path, + cairo_rectangle_int_t *extents); + +cairo_private void +_cairo_path_fixed_fill_extents (const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_rectangle_int_t *extents); + +cairo_private void +_cairo_path_fixed_approximate_stroke_extents (const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + cairo_bool_t vector, + cairo_rectangle_int_t *extents); + +cairo_private cairo_status_t +_cairo_path_fixed_stroke_extents (const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_rectangle_int_t *extents); + +cairo_private void +_cairo_path_fixed_transform (cairo_path_fixed_t *path, + const cairo_matrix_t *matrix); + +cairo_private cairo_bool_t +_cairo_path_fixed_is_box (const cairo_path_fixed_t *path, + cairo_box_t *box); + +cairo_private cairo_bool_t +_cairo_path_fixed_is_rectangle (const cairo_path_fixed_t *path, + cairo_box_t *box); + +/* cairo-path-in-fill.c */ +cairo_private cairo_bool_t +_cairo_path_fixed_in_fill (const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + double x, + double y); + +/* cairo-path-fill.c */ +cairo_private cairo_status_t +_cairo_path_fixed_fill_to_polygon (const cairo_path_fixed_t *path, + double tolerance, + cairo_polygon_t *polygon); + +cairo_private cairo_status_t +_cairo_path_fixed_fill_rectilinear_to_polygon (const cairo_path_fixed_t *path, + cairo_antialias_t antialias, + cairo_polygon_t *polygon); + +cairo_private cairo_status_t +_cairo_path_fixed_fill_rectilinear_to_boxes (const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + cairo_antialias_t antialias, + cairo_boxes_t *boxes); + +cairo_private cairo_region_t * +_cairo_path_fixed_fill_rectilinear_to_region (const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + const cairo_rectangle_int_t *extents); + +cairo_private cairo_status_t +_cairo_path_fixed_fill_to_traps (const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_traps_t *traps); + +/* cairo-path-stroke.c */ +cairo_private cairo_status_t +_cairo_path_fixed_stroke_to_polygon (const cairo_path_fixed_t *path, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_polygon_t *polygon); + +cairo_private cairo_int_status_t +_cairo_path_fixed_stroke_to_tristrip (const cairo_path_fixed_t *path, + const cairo_stroke_style_t*style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_tristrip_t *strip); + +cairo_private cairo_status_t +_cairo_path_fixed_stroke_dashed_to_polygon (const cairo_path_fixed_t *path, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_polygon_t *polygon); + +cairo_private cairo_int_status_t +_cairo_path_fixed_stroke_rectilinear_to_boxes (const cairo_path_fixed_t *path, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + cairo_antialias_t antialias, + cairo_boxes_t *boxes); + +cairo_private cairo_int_status_t +_cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t *path, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_traps_t *traps); + +cairo_private cairo_int_status_t +_cairo_path_fixed_stroke_polygon_to_traps (const cairo_path_fixed_t *path, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_traps_t *traps); + +cairo_private cairo_status_t +_cairo_path_fixed_stroke_to_shaper (cairo_path_fixed_t *path, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_status_t (*add_triangle) (void *closure, + const cairo_point_t triangle[3]), + cairo_status_t (*add_triangle_fan) (void *closure, + const cairo_point_t *midpt, + const cairo_point_t *points, + int npoints), + cairo_status_t (*add_quad) (void *closure, + const cairo_point_t quad[4]), + void *closure); + +/* cairo-scaled-font.c */ + +cairo_private void +_cairo_scaled_font_freeze_cache (cairo_scaled_font_t *scaled_font); + +cairo_private void +_cairo_scaled_font_thaw_cache (cairo_scaled_font_t *scaled_font); + +cairo_private void +_cairo_scaled_font_reset_cache (cairo_scaled_font_t *scaled_font); + +cairo_private cairo_status_t +_cairo_scaled_font_set_error (cairo_scaled_font_t *scaled_font, + cairo_status_t status); + +cairo_private cairo_scaled_font_t * +_cairo_scaled_font_create_in_error (cairo_status_t status); + +cairo_private void +_cairo_scaled_font_reset_static_data (void); + +cairo_private cairo_status_t +_cairo_scaled_font_register_placeholder_and_unlock_font_map (cairo_scaled_font_t *scaled_font); + +cairo_private void +_cairo_scaled_font_unregister_placeholder_and_lock_font_map (cairo_scaled_font_t *scaled_font); + +cairo_private cairo_status_t +_cairo_scaled_font_init (cairo_scaled_font_t *scaled_font, + cairo_font_face_t *font_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + const cairo_scaled_font_backend_t *backend); + +cairo_private cairo_status_t +_cairo_scaled_font_set_metrics (cairo_scaled_font_t *scaled_font, + cairo_font_extents_t *fs_metrics); + +/* This should only be called on an error path by a scaled_font constructor */ +cairo_private void +_cairo_scaled_font_fini (cairo_scaled_font_t *scaled_font); + +cairo_private cairo_status_t +_cairo_scaled_font_font_extents (cairo_scaled_font_t *scaled_font, + cairo_font_extents_t *extents); + +cairo_private cairo_status_t +_cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t *scaled_font, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_rectangle_int_t *extents, + cairo_bool_t *overlap); + +cairo_private cairo_bool_t +_cairo_scaled_font_glyph_approximate_extents (cairo_scaled_font_t *scaled_font, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_rectangle_int_t *extents); + +cairo_private cairo_status_t +_cairo_scaled_font_show_glyphs (cairo_scaled_font_t *scaled_font, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_surface_t *surface, + int source_x, + int source_y, + int dest_x, + int dest_y, + unsigned int width, + unsigned int height, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_region_t *clip_region); + +cairo_private cairo_status_t +_cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_path_fixed_t *path); + +cairo_private void +_cairo_scaled_glyph_set_metrics (cairo_scaled_glyph_t *scaled_glyph, + cairo_scaled_font_t *scaled_font, + cairo_text_extents_t *fs_metrics); + +cairo_private void +_cairo_scaled_glyph_set_surface (cairo_scaled_glyph_t *scaled_glyph, + cairo_scaled_font_t *scaled_font, + cairo_image_surface_t *surface); + +cairo_private void +_cairo_scaled_glyph_set_path (cairo_scaled_glyph_t *scaled_glyph, + cairo_scaled_font_t *scaled_font, + cairo_path_fixed_t *path); + +cairo_private void +_cairo_scaled_glyph_set_recording_surface (cairo_scaled_glyph_t *scaled_glyph, + cairo_scaled_font_t *scaled_font, + cairo_surface_t *recording_surface, + const cairo_color_t *foreground_color); + +cairo_private void +_cairo_scaled_glyph_set_color_surface (cairo_scaled_glyph_t *scaled_glyph, + cairo_scaled_font_t *scaled_font, + cairo_image_surface_t *surface, + const cairo_color_t *foreground_color); + +cairo_private cairo_int_status_t +_cairo_scaled_glyph_lookup (cairo_scaled_font_t *scaled_font, + unsigned long index, + cairo_scaled_glyph_info_t info, + const cairo_color_t *foreground_color, + cairo_scaled_glyph_t **scaled_glyph_ret); + +cairo_private double +_cairo_scaled_font_get_max_scale (cairo_scaled_font_t *scaled_font); + +cairo_private void +_cairo_scaled_font_map_destroy (void); + +/* cairo-stroke-style.c */ + +cairo_private void +_cairo_stroke_style_init (cairo_stroke_style_t *style); + +cairo_private cairo_status_t +_cairo_stroke_style_init_copy (cairo_stroke_style_t *style, + const cairo_stroke_style_t *other); + +cairo_private void +_cairo_stroke_style_fini (cairo_stroke_style_t *style); + +cairo_private void +_cairo_stroke_style_max_distance_from_path (const cairo_stroke_style_t *style, + const cairo_path_fixed_t *path, + const cairo_matrix_t *ctm, + double *dx, double *dy); +cairo_private void +_cairo_stroke_style_max_line_distance_from_path (const cairo_stroke_style_t *style, + const cairo_path_fixed_t *path, + const cairo_matrix_t *ctm, + double *dx, double *dy); + +cairo_private void +_cairo_stroke_style_max_join_distance_from_path (const cairo_stroke_style_t *style, + const cairo_path_fixed_t *path, + const cairo_matrix_t *ctm, + double *dx, double *dy); + +cairo_private double +_cairo_stroke_style_dash_period (const cairo_stroke_style_t *style); + +cairo_private double +_cairo_stroke_style_dash_stroked (const cairo_stroke_style_t *style); + +cairo_private cairo_bool_t +_cairo_stroke_style_dash_can_approximate (const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + double tolerance); + +cairo_private void +_cairo_stroke_style_dash_approximate (const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + double tolerance, + double *dash_offset, + double *dashes, + unsigned int *num_dashes); + + +/* cairo-surface.c */ + +cairo_private cairo_bool_t +_cairo_surface_has_mime_image (cairo_surface_t *surface); + +cairo_private cairo_status_t +_cairo_surface_copy_mime_data (cairo_surface_t *dst, + cairo_surface_t *src); + +cairo_private_no_warn cairo_int_status_t +_cairo_surface_set_error (cairo_surface_t *surface, + cairo_int_status_t status); + +cairo_private void +_cairo_surface_set_resolution (cairo_surface_t *surface, + double x_res, + double y_res); + +cairo_private cairo_surface_t * +_cairo_surface_create_for_rectangle_int (cairo_surface_t *target, + const cairo_rectangle_int_t *extents); + +cairo_private cairo_surface_t * +_cairo_surface_create_scratch (cairo_surface_t *other, + cairo_content_t content, + int width, + int height, + const cairo_color_t *color); + +cairo_private void +_cairo_surface_init (cairo_surface_t *surface, + const cairo_surface_backend_t *backend, + cairo_device_t *device, + cairo_content_t content, + cairo_bool_t is_vector); + +cairo_private void +_cairo_surface_set_font_options (cairo_surface_t *surface, + cairo_font_options_t *options); + +cairo_private cairo_status_t +_cairo_surface_paint (cairo_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip); + +cairo_private cairo_image_surface_t * +_cairo_surface_map_to_image (cairo_surface_t *surface, + const cairo_rectangle_int_t *extents); + +cairo_private_no_warn cairo_int_status_t +_cairo_surface_unmap_image (cairo_surface_t *surface, + cairo_image_surface_t *image); + +cairo_private cairo_status_t +_cairo_surface_mask (cairo_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_clip_t *clip); + +cairo_private cairo_status_t +_cairo_surface_fill_stroke (cairo_surface_t *surface, + cairo_operator_t fill_op, + const cairo_pattern_t *fill_source, + cairo_fill_rule_t fill_rule, + double fill_tolerance, + cairo_antialias_t fill_antialias, + cairo_path_fixed_t *path, + cairo_operator_t stroke_op, + const cairo_pattern_t *stroke_source, + const cairo_stroke_style_t *stroke_style, + const cairo_matrix_t *stroke_ctm, + const cairo_matrix_t *stroke_ctm_inverse, + double stroke_tolerance, + cairo_antialias_t stroke_antialias, + const cairo_clip_t *clip); + +cairo_private cairo_status_t +_cairo_surface_stroke (cairo_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip); + +cairo_private cairo_status_t +_cairo_surface_fill (cairo_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip); + +cairo_private cairo_status_t +_cairo_surface_show_text_glyphs (cairo_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const char *utf8, + int utf8_len, + cairo_glyph_t *glyphs, + int num_glyphs, + const cairo_text_cluster_t *clusters, + int num_clusters, + cairo_text_cluster_flags_t cluster_flags, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip); + +cairo_private cairo_status_t +_cairo_surface_tag (cairo_surface_t *surface, + cairo_bool_t begin, + const char *tag_name, + const char *attributes); + +cairo_private cairo_bool_t +_cairo_surface_supports_color_glyph (cairo_surface_t *surface, + cairo_scaled_font_t *scaled_font, + unsigned long glyph_index); + +cairo_private cairo_status_t +_cairo_surface_acquire_source_image (cairo_surface_t *surface, + cairo_image_surface_t **image_out, + void **image_extra); + +cairo_private void +_cairo_surface_release_source_image (cairo_surface_t *surface, + cairo_image_surface_t *image, + void *image_extra); + +cairo_private cairo_surface_t * +_cairo_surface_snapshot (cairo_surface_t *surface); + +cairo_private void +_cairo_surface_attach_snapshot (cairo_surface_t *surface, + cairo_surface_t *snapshot, + cairo_surface_func_t detach_func); + +cairo_private cairo_surface_t * +_cairo_surface_has_snapshot (cairo_surface_t *surface, + const cairo_surface_backend_t *backend); + +cairo_private void +_cairo_surface_detach_snapshot (cairo_surface_t *snapshot); + +cairo_private cairo_status_t +_cairo_surface_begin_modification (cairo_surface_t *surface); + +cairo_private_no_warn cairo_bool_t +_cairo_surface_get_extents (cairo_surface_t *surface, + cairo_rectangle_int_t *extents); + +cairo_private cairo_bool_t +_cairo_surface_has_device_transform (cairo_surface_t *surface) cairo_pure; + +cairo_private void +_cairo_surface_release_device_reference (cairo_surface_t *surface); + +/* cairo-image-surface.c */ + +/* XXX: In cairo 1.2.0 we added a new %CAIRO_FORMAT_RGB16_565 but + * neglected to adjust this macro. The net effect is that it's + * impossible to externally create an image surface with this + * format. This is perhaps a good thing since we also neglected to fix + * up things like cairo_surface_write_to_png() for the new format + * (-Wswitch-enum will tell you where). Is it obvious that format was + * added in haste? + * + * The reason for the new format was to allow the xlib backend to be + * used on X servers with a 565 visual. So the new format did its job + * for that, even without being considered "valid" for the sake of + * things like cairo_image_surface_create(). + * + * Since 1.2.0 we ran into the same situation with X servers with BGR + * visuals. This time we invented #cairo_internal_format_t instead, + * (see it for more discussion). + * + * The punchline is that %CAIRO_FORMAT_VALID must not consider any + * internal format to be valid. Also we need to decide if the + * RGB16_565 should be moved to instead be an internal format. If so, + * this macro need not change for it. (We probably will need to leave + * an RGB16_565 value in the header files for the sake of code that + * might have that value in it.) + * + * If we do decide to start fully supporting RGB16_565 as an external + * format, then %CAIRO_FORMAT_VALID needs to be adjusted to include + * it. But that should not happen before all necessary code is fixed + * to support it (at least cairo_surface_write_to_png() and a few spots + * in cairo-xlib-surface.c--again see -Wswitch-enum). + */ +#define CAIRO_FORMAT_VALID(format) ((format) >= CAIRO_FORMAT_ARGB32 && \ + (format) <= CAIRO_FORMAT_RGBA128F) + +/* pixman-required stride alignment in bytes. */ +#define CAIRO_STRIDE_ALIGNMENT (sizeof (uint32_t)) +#define CAIRO_STRIDE_FOR_WIDTH_BPP(w,bpp) \ + ((((bpp)*(w)+7)/8 + CAIRO_STRIDE_ALIGNMENT-1) & -CAIRO_STRIDE_ALIGNMENT) + +#define CAIRO_CONTENT_VALID(content) ((content) && \ + (((content) & ~(CAIRO_CONTENT_COLOR | \ + CAIRO_CONTENT_ALPHA | \ + CAIRO_CONTENT_COLOR_ALPHA))\ + == 0)) + +cairo_private int +_cairo_format_bits_per_pixel (cairo_format_t format) cairo_const; + +cairo_private cairo_format_t +_cairo_format_from_content (cairo_content_t content) cairo_const; + +cairo_private cairo_format_t +_cairo_format_from_pixman_format (pixman_format_code_t pixman_format); + +cairo_private cairo_content_t +_cairo_content_from_format (cairo_format_t format) cairo_const; + +cairo_private cairo_content_t +_cairo_content_from_pixman_format (pixman_format_code_t pixman_format); + +cairo_private cairo_surface_t * +_cairo_image_surface_create_for_pixman_image (pixman_image_t *pixman_image, + pixman_format_code_t pixman_format); + +cairo_private pixman_format_code_t +_cairo_format_to_pixman_format_code (cairo_format_t format); + +cairo_private cairo_bool_t +_pixman_format_from_masks (cairo_format_masks_t *masks, + pixman_format_code_t *format_ret); + +cairo_private cairo_bool_t +_pixman_format_to_masks (pixman_format_code_t pixman_format, + cairo_format_masks_t *masks); + + +cairo_private void +_cairo_image_scaled_glyph_fini (cairo_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph); + +cairo_private void +_cairo_image_reset_static_data (void); + +cairo_private void +_cairo_image_compositor_reset_static_data (void); + +cairo_private cairo_surface_t * +_cairo_image_surface_create_with_pixman_format (unsigned char *data, + pixman_format_code_t pixman_format, + int width, + int height, + int stride); + +cairo_private cairo_surface_t * +_cairo_image_surface_create_with_content (cairo_content_t content, + int width, + int height); + +cairo_private void +_cairo_image_surface_assume_ownership_of_data (cairo_image_surface_t *surface); + +cairo_private cairo_image_surface_t * +_cairo_image_surface_coerce (cairo_image_surface_t *surface); + +cairo_private cairo_image_surface_t * +_cairo_image_surface_coerce_to_format (cairo_image_surface_t *surface, + cairo_format_t format); + +cairo_private cairo_image_transparency_t +_cairo_image_analyze_transparency (cairo_image_surface_t *image); + +cairo_private cairo_image_color_t +_cairo_image_analyze_color (cairo_image_surface_t *image); + +/* cairo-pen.c */ +cairo_private int +_cairo_pen_vertices_needed (double tolerance, + double radius, + const cairo_matrix_t *matrix); + +cairo_private cairo_status_t +_cairo_pen_init (cairo_pen_t *pen, + double radius, + double tolerance, + const cairo_matrix_t *ctm); + +cairo_private void +_cairo_pen_init_empty (cairo_pen_t *pen); + +cairo_private cairo_status_t +_cairo_pen_init_copy (cairo_pen_t *pen, const cairo_pen_t *other); + +cairo_private void +_cairo_pen_fini (cairo_pen_t *pen); + +cairo_private cairo_status_t +_cairo_pen_add_points (cairo_pen_t *pen, cairo_point_t *point, int num_points); + +cairo_private int +_cairo_pen_find_active_cw_vertex_index (const cairo_pen_t *pen, + const cairo_slope_t *slope); + +cairo_private int +_cairo_pen_find_active_ccw_vertex_index (const cairo_pen_t *pen, + const cairo_slope_t *slope); + +cairo_private void +_cairo_pen_find_active_cw_vertices (const cairo_pen_t *pen, + const cairo_slope_t *in, + const cairo_slope_t *out, + int *start, int *stop); + +cairo_private void +_cairo_pen_find_active_ccw_vertices (const cairo_pen_t *pen, + const cairo_slope_t *in, + const cairo_slope_t *out, + int *start, int *stop); + +/* cairo-polygon.c */ +cairo_private void +_cairo_polygon_init (cairo_polygon_t *polygon, + const cairo_box_t *boxes, + int num_boxes); + +cairo_private void +_cairo_polygon_init_with_clip (cairo_polygon_t *polygon, + const cairo_clip_t *clip); + +cairo_private cairo_status_t +_cairo_polygon_init_boxes (cairo_polygon_t *polygon, + const cairo_boxes_t *boxes); + +cairo_private cairo_status_t +_cairo_polygon_init_box_array (cairo_polygon_t *polygon, + cairo_box_t *boxes, + int num_boxes); + +cairo_private void +_cairo_polygon_limit (cairo_polygon_t *polygon, + const cairo_box_t *limits, + int num_limits); + +cairo_private void +_cairo_polygon_limit_to_clip (cairo_polygon_t *polygon, + const cairo_clip_t *clip); + +cairo_private void +_cairo_polygon_fini (cairo_polygon_t *polygon); + +cairo_private_no_warn cairo_status_t +_cairo_polygon_add_line (cairo_polygon_t *polygon, + const cairo_line_t *line, + int top, int bottom, + int dir); + +cairo_private_no_warn cairo_status_t +_cairo_polygon_add_external_edge (void *polygon, + const cairo_point_t *p1, + const cairo_point_t *p2); + +cairo_private_no_warn cairo_status_t +_cairo_polygon_add_contour (cairo_polygon_t *polygon, + const cairo_contour_t *contour); + +cairo_private void +_cairo_polygon_translate (cairo_polygon_t *polygon, int dx, int dy); + +cairo_private cairo_status_t +_cairo_polygon_reduce (cairo_polygon_t *polygon, + cairo_fill_rule_t fill_rule); + +cairo_private cairo_status_t +_cairo_polygon_intersect (cairo_polygon_t *a, int winding_a, + cairo_polygon_t *b, int winding_b); + +cairo_private cairo_status_t +_cairo_polygon_intersect_with_boxes (cairo_polygon_t *polygon, + cairo_fill_rule_t *winding, + cairo_box_t *boxes, + int num_boxes); + +static inline cairo_bool_t +_cairo_polygon_is_empty (const cairo_polygon_t *polygon) +{ + return + polygon->num_edges == 0 || + polygon->extents.p2.x <= polygon->extents.p1.x; +} + +#define _cairo_polygon_status(P) ((cairo_polygon_t *) (P))->status + +/* cairo-spline.c */ +cairo_private cairo_bool_t +_cairo_spline_init (cairo_spline_t *spline, + cairo_spline_add_point_func_t add_point_func, + void *closure, + const cairo_point_t *a, const cairo_point_t *b, + const cairo_point_t *c, const cairo_point_t *d); + +cairo_private cairo_status_t +_cairo_spline_decompose (cairo_spline_t *spline, double tolerance); + +cairo_private cairo_status_t +_cairo_spline_bound (cairo_spline_add_point_func_t add_point_func, + void *closure, + const cairo_point_t *p0, const cairo_point_t *p1, + const cairo_point_t *p2, const cairo_point_t *p3); + +/* cairo-matrix.c */ +cairo_private void +_cairo_matrix_get_affine (const cairo_matrix_t *matrix, + double *xx, double *yx, + double *xy, double *yy, + double *x0, double *y0); + +cairo_private void +_cairo_matrix_transform_bounding_box (const cairo_matrix_t *matrix, + double *x1, double *y1, + double *x2, double *y2, + cairo_bool_t *is_tight); + +cairo_private void +_cairo_matrix_transform_bounding_box_fixed (const cairo_matrix_t *matrix, + cairo_box_t *bbox, + cairo_bool_t *is_tight); + +cairo_private cairo_bool_t +_cairo_matrix_is_invertible (const cairo_matrix_t *matrix) cairo_pure; + +cairo_private cairo_bool_t +_cairo_matrix_is_scale_0 (const cairo_matrix_t *matrix) cairo_pure; + +cairo_private double +_cairo_matrix_compute_determinant (const cairo_matrix_t *matrix) cairo_pure; + +cairo_private cairo_status_t +_cairo_matrix_compute_basis_scale_factors (const cairo_matrix_t *matrix, + double *sx, double *sy, int x_major); + +static inline cairo_bool_t +_cairo_matrix_is_identity (const cairo_matrix_t *matrix) +{ + return (matrix->xx == 1.0 && matrix->yx == 0.0 && + matrix->xy == 0.0 && matrix->yy == 1.0 && + matrix->x0 == 0.0 && matrix->y0 == 0.0); +} + +static inline cairo_bool_t +_cairo_matrix_is_translation (const cairo_matrix_t *matrix) +{ + return (matrix->xx == 1.0 && matrix->yx == 0.0 && + matrix->xy == 0.0 && matrix->yy == 1.0); +} + +static inline cairo_bool_t +_cairo_matrix_is_scale (const cairo_matrix_t *matrix) +{ + return matrix->yx == 0.0 && matrix->xy == 0.0; +} + +cairo_private cairo_bool_t +_cairo_matrix_is_integer_translation(const cairo_matrix_t *matrix, + int *itx, int *ity); + +cairo_private cairo_bool_t +_cairo_matrix_has_unity_scale (const cairo_matrix_t *matrix); + +cairo_private cairo_bool_t +_cairo_matrix_is_pixel_exact (const cairo_matrix_t *matrix) cairo_pure; + +cairo_private double +_cairo_matrix_transformed_circle_major_axis (const cairo_matrix_t *matrix, + double radius) cairo_pure; + +cairo_private cairo_bool_t +_cairo_matrix_is_pixman_translation (const cairo_matrix_t *matrix, + cairo_filter_t filter, + int *out_x_offset, + int *out_y_offset); + +cairo_private cairo_status_t +_cairo_matrix_to_pixman_matrix_offset (const cairo_matrix_t *matrix, + cairo_filter_t filter, + double xc, + double yc, + pixman_transform_t *out_transform, + int *out_x_offset, + int *out_y_offset); + +cairo_private void +_cairo_debug_print_matrix (FILE *file, const cairo_matrix_t *matrix); + +cairo_private void +_cairo_debug_print_rect (FILE *file, const cairo_rectangle_int_t *rect); + +cairo_private const char * +_cairo_debug_operator_to_string (cairo_operator_t op); + +cairo_private const char * +_cairo_debug_status_to_string (cairo_int_status_t status); + +cairo_private cairo_status_t +_cairo_bentley_ottmann_tessellate_rectilinear_polygon (cairo_traps_t *traps, + const cairo_polygon_t *polygon, + cairo_fill_rule_t fill_rule); + +cairo_private cairo_status_t +_cairo_bentley_ottmann_tessellate_polygon (cairo_traps_t *traps, + const cairo_polygon_t *polygon, + cairo_fill_rule_t fill_rule); + +cairo_private cairo_status_t +_cairo_bentley_ottmann_tessellate_traps (cairo_traps_t *traps, + cairo_fill_rule_t fill_rule); + +cairo_private cairo_status_t +_cairo_bentley_ottmann_tessellate_rectangular_traps (cairo_traps_t *traps, + cairo_fill_rule_t fill_rule); + +cairo_private cairo_status_t +_cairo_bentley_ottmann_tessellate_boxes (const cairo_boxes_t *in, + cairo_fill_rule_t fill_rule, + cairo_boxes_t *out); + +cairo_private cairo_status_t +_cairo_bentley_ottmann_tessellate_rectilinear_traps (cairo_traps_t *traps, + cairo_fill_rule_t fill_rule); + +cairo_private cairo_status_t +_cairo_bentley_ottmann_tessellate_rectilinear_polygon_to_boxes (const cairo_polygon_t *polygon, + cairo_fill_rule_t fill_rule, + cairo_boxes_t *boxes); + +cairo_private void +_cairo_trapezoid_array_translate_and_scale (cairo_trapezoid_t *offset_traps, + cairo_trapezoid_t *src_traps, + int num_traps, + double tx, double ty, + double sx, double sy); + +cairo_private void +_cairo_clip_reset_static_data (void); + +cairo_private void +_cairo_pattern_reset_static_data (void); + +/* cairo-unicode.c */ + +cairo_private int +_cairo_utf8_get_char_validated (const char *p, + uint32_t *unicode); + +cairo_private cairo_status_t +_cairo_utf8_to_ucs4 (const char *str, + int len, + uint32_t **result, + int *items_written); + +cairo_private int +_cairo_ucs4_to_utf8 (uint32_t unicode, + char *utf8); + +cairo_private int +_cairo_ucs4_to_utf16 (uint32_t unicode, + uint16_t *utf16); + +#if _WIN32 || CAIRO_HAS_WIN32_FONT || CAIRO_HAS_QUARTZ_FONT || CAIRO_HAS_PDF_OPERATORS +# define CAIRO_HAS_UTF8_TO_UTF16 1 +#endif +#if CAIRO_HAS_UTF8_TO_UTF16 +cairo_private cairo_status_t +_cairo_utf8_to_utf16 (const char *str, + int len, + uint16_t **result, + int *items_written); +#endif + +cairo_private void +_cairo_matrix_multiply (cairo_matrix_t *r, + const cairo_matrix_t *a, + const cairo_matrix_t *b); + +/* cairo-observer.c */ + +cairo_private void +_cairo_observers_notify (cairo_list_t *observers, void *arg); + +/* Open a file with a UTF-8 filename */ +cairo_private cairo_status_t +_cairo_fopen (const char *filename, const char *mode, FILE **file_out); + +cairo_private FILE * +_cairo_tmpfile (void); + +#include "cairo-mutex-private.h" +#include "cairo-fixed-private.h" +#include "cairo-wideint-private.h" +#include "cairo-malloc-private.h" +#include "cairo-hash-private.h" + +#if HAVE_VALGRIND +#include + +#define VG(x) x + +cairo_private void +_cairo_debug_check_image_surface_is_defined (const cairo_surface_t *surface); + +#else + +#define VG(x) +#define _cairo_debug_check_image_surface_is_defined(X) + +#endif + +cairo_private void +_cairo_debug_print_path (FILE *stream, const cairo_path_fixed_t *path); + +cairo_private void +_cairo_debug_print_polygon (FILE *stream, cairo_polygon_t *polygon); + +cairo_private void +_cairo_debug_print_traps (FILE *file, const cairo_traps_t *traps); + +cairo_private void +_cairo_debug_print_clip (FILE *stream, const cairo_clip_t *clip); + +#if 0 +#define TRACE(x) fprintf (stderr, "%s: ", __FILE__), fprintf x +#define TRACE_(x) x +#else +#define TRACE(x) +#define TRACE_(x) +#endif + +CAIRO_END_DECLS + +#endif diff --git a/local/recipes/libs/cairo/source/src/check-doc-syntax.awk b/local/recipes/libs/cairo/source/src/check-doc-syntax.awk new file mode 100644 index 0000000000..1fa8b8d223 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/check-doc-syntax.awk @@ -0,0 +1,106 @@ +BEGIN { + name_found = 1 + SECTION_DOC = 0 + PUBLIC_DOC = 1 + PRIVATE_DOC = 2 +} + +function log_msg(severity, msg) +{ + printf "%s (%d): %s: %s %s\n", FILENAME, FNR, severity, doc_name, msg +} + +function log_error(msg) +{ + log_msg("ERROR", msg) +} + +function log_warning(msg) +{ + log_msg("WARNING", msg) +} + +/^\/\*\*$/ { + in_doc = 1 + doc_line = 0 +} + +/^(\/\*\*$| \*[ \t]| \*$| \*\*\/$)/ { + valid_doc = 1 +} + +in_doc { + if (!valid_doc) + log_error("bad line: '" $0 "'") + valid_doc = 0 + + doc_line++ + if (doc_line == 2) { + # new doc name. Did we find the previous one? + # (macros are not expected to be found in the same place as + # their documentation) + if (!name_found && doc_name !~ /CAIRO_/) + log_warning("not found") + doc_name = $2 + if (doc_name ~ /^SECTION:.*$/) { + doc_type = SECTION_DOC + name_found = 1 + } else if (tolower(doc_name) ~ /^cairo_[a-z0-9_]*:$/) { + doc_type = PUBLIC_DOC + name_found = 0 + real_name = substr(doc_name, 1, length(doc_name) - 1) + } else if (tolower(doc_name) ~ /^_[a-z0-9_]*:$/) { + doc_type = PRIVATE_DOC + name_found = 0 + real_name = substr(doc_name, 1, length(doc_name) - 1) + } else { + log_error("invalid doc id (should be 'cairo_...:')") + name_found = 1 + } + } +} + +!in_doc { + regex = "(^|[ \\t\\*])" real_name "([ ;()]|$)" + if ($0 ~ regex) + name_found = 1 +} + +/^ \* Since: ([0-9]*.[0-9]*|TBD)$/ { + if (doc_has_since != 0) { + log_error("Duplicate 'Since' field") + } + doc_has_since = doc_line +} + +/^ \*\*\// { + if (doc_type == PUBLIC_DOC) { + if (!doc_has_since) { + # private types can start with cairo_ + if (doc_name ~ /^cairo_.*_t:$/) + log_warning("missing 'Since' field (is it a private type?)") + else + log_error("missing 'Since' field") + } else if (doc_has_since != doc_line - 1) + log_warning("misplaced 'Since' field (should be right before the end of the comment)") + } else { + if (doc_has_since) + log_warning("'Since' field in non-public element") + } + + in_doc = 0 + doc_has_since = 0 + doc_type = 0 +} + +/\*\// { + if (in_doc) { + in_doc = 0 + log_error("documentation comment not closed with **/") + } +} + +END { + if (!name_found) + log_warning("not found") +} diff --git a/local/recipes/libs/cairo/source/src/check-doc-syntax.sh b/local/recipes/libs/cairo/source/src/check-doc-syntax.sh new file mode 100755 index 0000000000..57bbc91fdc --- /dev/null +++ b/local/recipes/libs/cairo/source/src/check-doc-syntax.sh @@ -0,0 +1,82 @@ +#!/bin/sh + +LC_ALL=C +export LC_ALL + +if grep --version 2>/dev/null | grep GNU >/dev/null; then + : +else + echo "GNU grep not found; skipping test" + exit 0 +fi + +test -z "$srcdir" && srcdir=. +stat=0 + +echo Checking documentation for incorrect syntax + +cd "$srcdir" + +if test "x$SGML_DOCS" = x; then + FILES=$all_cairo_files + if test "x$FILES" = x; then + FILES=`find . -name 'cairo*.h' -or -name 'cairo*.c' -or -name 'cairo*.cpp'` + fi +fi + +enum_regexp="\([^%@']\|^\)\<\(FALSE\|TRUE\|NULL\|CAIRO_[0-9A-Z_]*\)\($\|[^(A-Za-z0-9_]\)" +if test "x$SGML_DOCS" = x; then + enum_regexp='^[^:]*:[/ ][*]\(\|[ \t].*\)'$enum_regexp\($\|[^:]\) +fi +if echo $FILES | xargs grep . /dev/null | sed -e '//,/<\/programlisting>/d' -e '/\|\[/,/\]\|/d' | grep "$enum_regexp" | grep -v '#####'; then + stat=1 + echo Error: some macros in the docs are not prefixed by percent sign. + echo Fix this by searching for the following regexp in the above files: + echo " '$enum_regexp'" +fi >&2 + +type_regexp="\( .*[^#']\| \|^\)\\($\|[^:]$\|[^:].\)" +if test "x$SGML_DOCS" = x; then + type_regexp='^[^:]*:[/ ][*]'$type_regexp +else + type_regexp='\(.'$type_regexp'\)\|\('$type_regexp'.\)' +fi + +if echo $FILES | xargs grep . /dev/null | sed -e '//,/<\/programlisting>/d' -e '/\|\[/,/\]\|/d' | grep -v "@Title" | grep "$type_regexp" | grep -v '#####'; then + stat=1 + echo Error: some type names in the docs are not prefixed by hash sign, + echo neither are the only token in the doc line followed by colon. + echo Fix this by searching for the following regexp in the above files: + echo " '$type_regexp'" +fi >&2 + +func_regexp="\([^#']\|^\)\<\(cairo_[][<>/0-9a-z_]*\>[^][<>(]\)" +if test "x$SGML_DOCS" = x; then + func_regexp='^[^:]*:[/ ][*]\(\|[ \t].*\)'$func_regexp +fi + +# We need to filter out gtk-doc markup errors for program listings. +if echo $FILES | xargs grep . /dev/null | sed -e '//,/<\/programlisting>/d' -e '/\|\[/,/\]\|/d' | grep "$func_regexp" | grep -v '^[^:]*: [*] [a-z_0-9]*:$' | grep -v '#####'; then + stat=1 + echo Error: some function names in the docs are not followed by parentheses. + echo Fix this by searching for the following regexp in the above files: + echo " '$func_regexp'" +fi >&2 + +note_regexp='\' +if echo $FILES | xargs grep "$note_regexp" /dev/null; then + stat=1 + echo Error: some source files contain the string 'NOTE'. + echo Be civil and replace it by 'Note' please. +fi >&2 + +# Only run the syntax checker on the source files (not doc/) +if test -e ./check-doc-syntax.awk; then + if echo $FILES | xargs awk -f ./check-doc-syntax.awk ; then + : + else + stat=1 + fi >&2 +fi + +exit $stat diff --git a/local/recipes/libs/cairo/source/src/check-headers.sh b/local/recipes/libs/cairo/source/src/check-headers.sh new file mode 100755 index 0000000000..b4f14571d8 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/check-headers.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +LC_ALL=C +export LC_ALL + +test -z "$srcdir" && srcdir=. +stat=0 + +echo Checking public headers for missing cairo_public decorators + +cd "$srcdir" +FILES=$all_cairo_headers +if test "x$FILES" = x; then + FILES=`find . -name 'cairo*.h' ! -name '*-private.h' ! -name 'cairoint.h' ! -name '*-inline.h'` +fi + +grep -B 1 '^cairo_.*[ ]\+(' /dev/null $FILES | +awk ' +/^--$/ { context=""; public=0; next; } +/:cairo_.*[ ]+\(/ { if (!public) {print context; print; print "--";} next; } +/-cairo_public.*[ ]/ {public=1;} +{ context=$0; } +' | +sed 's/[.]h-/.h:/' | +grep . >&2 && stat=1 + +exit $stat diff --git a/local/recipes/libs/cairo/source/src/check-preprocessor-syntax.sh b/local/recipes/libs/cairo/source/src/check-preprocessor-syntax.sh new file mode 100755 index 0000000000..fa0fa715ff --- /dev/null +++ b/local/recipes/libs/cairo/source/src/check-preprocessor-syntax.sh @@ -0,0 +1,59 @@ +#!/bin/sh + +LC_ALL=C +export LC_ALL + +test -z "$srcdir" && srcdir=. +cd "$srcdir" +stat=0 + + +HEADERS=$all_cairo_headers +test "x$HEADERS" = x && HEADERS=`find . -name 'cairo*.h' ! -name 'cairo*-private.h' ! -name 'cairo*-inline.h' ! -name 'cairoint.h'` + +PRIVATE=$all_cairo_private +test "x$PRIVATE" = x && PRIVATE=`find . -name 'cairo*-private.h' -or -name 'cairo*-inline.h' -or -name 'cairoint.h'` + +SOURCES=$all_cairo_sources +test "x$SOURCES" = x && SOURCES=`find . -name 'cairo*.c' -or -name 'cairo*.cpp'` + +ALL="/dev/null $HEADERS $PRIVATE $SOURCES" + +echo 'Checking that public header files #include "cairo.h" first (or none)' + +for x in $HEADERS; do + grep '#.*\' "$x" /dev/null | head -n 1 +done | +grep -v '"cairo[.]h"' | +grep -v 'cairo[.]h:' | +grep . >&2 && stat=1 + + +echo 'Checking that private header files #include "some cairo header" first (or none)' + +for x in $PRIVATE; do + grep '#.*\' "$x" /dev/null | head -n 1 +done | +grep -v '"cairo.*[.]h"' | +grep -v 'cairoint[.]h:' | +grep . >&2 && stat=1 + + +echo 'Checking that source files #include "cairoint.h" first (or none)' + +for x in $SOURCES; do + grep '#.*\' "$x" /dev/null | head -n 1 +done | +grep -v '"cairoint[.]h"' | +grep . >&2 && stat=1 + + +echo 'Checking that there is no #include ' +grep '^[^*]#.*\.*<.*cairo' $ALL >&2 && stat=1 + + +echo 'Checking that feature conditionals are used with #if only (not #ifdef)' +grep '#ifdef CAIRO_HAS_' $ALL && stat=1 +grep '#if.*defined[ ]*(CAIRO_HAS_' $ALL && stat=1 + +exit $stat diff --git a/local/recipes/libs/cairo/source/src/meson.build b/local/recipes/libs/cairo/source/src/meson.build new file mode 100644 index 0000000000..ac06ac61a0 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/meson.build @@ -0,0 +1,287 @@ +cairo_sources = [ + 'cairo-analysis-surface.c', + 'cairo-arc.c', + 'cairo-array.c', + 'cairo-atomic.c', + 'cairo-base64-stream.c', + 'cairo-base85-stream.c', + 'cairo-bentley-ottmann-rectangular.c', + 'cairo-bentley-ottmann-rectilinear.c', + 'cairo-bentley-ottmann.c', + 'cairo-botor-scan-converter.c', + 'cairo-boxes-intersect.c', + 'cairo-boxes.c', + 'cairo-cache.c', + 'cairo-clip-boxes.c', + 'cairo-clip-polygon.c', + 'cairo-clip-region.c', + 'cairo-clip-surface.c', + 'cairo-clip-tor-scan-converter.c', + 'cairo-clip.c', + 'cairo-color.c', + 'cairo-composite-rectangles.c', + 'cairo-compositor.c', + 'cairo-contour.c', + 'cairo-damage.c', + 'cairo-debug.c', + 'cairo-default-context.c', + 'cairo-device.c', + 'cairo-error.c', + 'cairo-fallback-compositor.c', + 'cairo-fixed.c', + 'cairo-font-face-twin-data.c', + 'cairo-font-face-twin.c', + 'cairo-font-face.c', + 'cairo-font-options.c', + 'cairo-freed-pool.c', + 'cairo-freelist.c', + 'cairo-gstate.c', + 'cairo-hash.c', + 'cairo-hull.c', + 'cairo-image-compositor.c', + 'cairo-image-info.c', + 'cairo-image-source.c', + 'cairo-image-surface.c', + 'cairo-line.c', + 'cairo-lzw.c', + 'cairo-mask-compositor.c', + 'cairo-matrix.c', + 'cairo-mempool.c', + 'cairo-mesh-pattern-rasterizer.c', + 'cairo-misc.c', + 'cairo-mono-scan-converter.c', + 'cairo-mutex.c', + 'cairo-no-compositor.c', + 'cairo-observer.c', + 'cairo-output-stream.c', + 'cairo-paginated-surface.c', + 'cairo-path-bounds.c', + 'cairo-path-fill.c', + 'cairo-path-fixed.c', + 'cairo-path-in-fill.c', + 'cairo-path-stroke-boxes.c', + 'cairo-path-stroke-polygon.c', + 'cairo-path-stroke-traps.c', + 'cairo-path-stroke-tristrip.c', + 'cairo-path-stroke.c', + 'cairo-path.c', + 'cairo-pattern.c', + 'cairo-pen.c', + 'cairo-polygon-intersect.c', + 'cairo-polygon-reduce.c', + 'cairo-polygon.c', + 'cairo-raster-source-pattern.c', + 'cairo-recording-surface.c', + 'cairo-rectangle.c', + 'cairo-rectangular-scan-converter.c', + 'cairo-region.c', + 'cairo-rtree.c', + 'cairo-scaled-font.c', + 'cairo-shape-mask-compositor.c', + 'cairo-slope.c', + 'cairo-spans-compositor.c', + 'cairo-spans.c', + 'cairo-spline.c', + 'cairo-stroke-dash.c', + 'cairo-stroke-style.c', + 'cairo-surface-clipper.c', + 'cairo-surface-fallback.c', + 'cairo-surface-observer.c', + 'cairo-surface-offset.c', + 'cairo-surface-snapshot.c', + 'cairo-surface-subsurface.c', + 'cairo-surface-wrapper.c', + 'cairo-surface.c', + 'cairo-time.c', + 'cairo-tor-scan-converter.c', + 'cairo-tor22-scan-converter.c', + 'cairo-toy-font-face.c', + 'cairo-traps-compositor.c', + 'cairo-traps.c', + 'cairo-tristrip.c', + 'cairo-unicode.c', + 'cairo-user-font.c', + 'cairo-version.c', + 'cairo-wideint.c', + 'cairo.c', + 'cairo-cff-subset.c', + 'cairo-scaled-font-subsets.c', + 'cairo-truetype-subset.c', + 'cairo-type1-fallback.c', + 'cairo-type1-glyph-names.c', + 'cairo-type1-subset.c', + 'cairo-type3-glyph-surface.c', + 'cairo-pdf-operators.c', + 'cairo-pdf-shading.c', + 'cairo-tag-attributes.c', + 'cairo-tag-stack.c', + 'cairo-deflate-stream.c', +] + +cairo_headers = [ + 'cairo.h', + 'cairo-version.h', + 'cairo-deprecated.h', +] + +cairo_feature_sources = { + 'cairo-png': [ + 'cairo-png.c', + ], + 'cairo-ft': [ + 'cairo-ft-font.c', + 'cairo-colr-glyph-render.c', + 'cairo-svg-glyph-render.c' + ], + + 'cairo-xlib': [ + 'cairo-xlib-display.c', + 'cairo-xlib-core-compositor.c', + 'cairo-xlib-fallback-compositor.c', + 'cairo-xlib-render-compositor.c', + 'cairo-xlib-screen.c', + 'cairo-xlib-source.c', + 'cairo-xlib-surface.c', + 'cairo-xlib-surface-shm.c', + 'cairo-xlib-visual.c', + 'cairo-xlib-xcb-surface.c', + ], + 'cairo-xcb': [ + 'cairo-xcb-connection.c', + 'cairo-xcb-connection-core.c', + 'cairo-xcb-connection-render.c', + 'cairo-xcb-connection-shm.c', + 'cairo-xcb-screen.c', + 'cairo-xcb-shm.c', + 'cairo-xcb-surface.c', + 'cairo-xcb-surface-core.c', + 'cairo-xcb-surface-render.c', + 'cairo-xcb-resources.c', + ], + 'cairo-quartz': [ + 'cairo-quartz-surface.c', + ], + 'cairo-quartz-image': [ + 'cairo-quartz-image-surface.c', + ], + 'cairo-quartz-font': [ + 'cairo-quartz-font.c', + ], + 'cairo-win32': [ + 'win32/cairo-win32-debug.c', + 'win32/cairo-win32-device.c', + 'win32/cairo-win32-gdi-compositor.c', + 'win32/cairo-win32-system.c', + 'win32/cairo-win32-surface.c', + 'win32/cairo-win32-display-surface.c', + 'win32/cairo-win32-printing-surface.c', + ], + 'cairo-win32-font': [ + 'win32/cairo-win32-font.c', + ], + 'cairo-dwrite-font': [ + 'win32/cairo-dwrite-font.cpp', + ], + 'cairo-script': [ + 'cairo-script-surface.c', + ], + 'cairo-ps': [ + 'cairo-ps-surface.c', + ], + 'cairo-pdf': [ + 'cairo-pdf-surface.c', + 'cairo-pdf-interchange.c', + ], + 'cairo-svg': [ + 'cairo-svg-surface.c', + ], + 'cairo-tee': [ + 'cairo-tee-surface.c', + ], +} + +cairo_feature_headers = { + 'cairo-ps': ['cairo-ps.h'], + 'cairo-pdf': ['cairo-pdf.h'], + 'cairo-svg': ['cairo-svg.h'], + 'cairo-ft': ['cairo-ft.h'], + 'cairo-xlib': ['cairo-xlib.h'], + 'cairo-xlib-xrender': ['cairo-xlib-xrender.h'], + 'cairo-xcb': ['cairo-xcb.h'], + 'cairo-quartz': ['cairo-quartz.h'], + 'cairo-quartz-image': ['cairo-quartz-image.h'], + 'cairo-win32': ['cairo-win32.h'], + 'cairo-dwrite-font': ['cairo-dwrite.h'], + 'cairo-gl': ['cairo-gl.h'], + 'cairo-script': ['cairo-script.h'], + 'cairo-tee': ['cairo-tee.h'], + 'cairo-vg': ['cairo-vg.h'], +} + +cairo_no_warn_c_args = cc.get_supported_arguments([ + '-Wno-attributes', + '-Wno-unused-but-set-variable', + '-Wno-missing-field-initializers', + '-Wno-unused-parameter', + '-Wno-long-long', +]) + +foreach feature: built_features + source_key = feature.get('source-key', feature.get('name')) + cairo_sources += cairo_feature_sources.get(source_key, []) + cairo_headers += cairo_feature_headers.get(source_key, []) +endforeach + +incsrc = include_directories('.') + +cairo_static_args = [] +if get_option('default_library') == 'static' and host_machine.system() == 'windows' + cairo_static_args += ['-DCAIRO_WIN32_STATIC_BUILD'] + add_project_arguments('-DCAIRO_WIN32_STATIC_BUILD', language: 'c') +endif + +libcairo = library('cairo', cairo_sources, + dependencies: deps, + c_args: cairo_no_warn_c_args + pthread_c_args + ['-DCAIRO_COMPILATION'], + cpp_args: cairo_no_warn_c_args + pthread_c_args + ['-DCAIRO_COMPILATION'], + link_args: extra_link_args, + gnu_symbol_visibility: 'hidden', + soversion: cairo_version_sonum, + version: cairo_libversion, + install: true, + include_directories: incbase, +) + +cairo_features_file = configure_file(output: 'cairo-features.h', configuration: feature_conf) +cairo_headers += [cairo_features_file] + +libcairo_dep = declare_dependency(link_with: libcairo, + dependencies: deps, + include_directories: incsrc, + compile_args: cairo_static_args, +) + +pkgmod.generate(libcairo, + description: 'Multi-platform 2D graphics library', + subdirs: [meson.project_name()], +) + +meson.override_dependency('cairo', libcairo_dep) + +install_headers(cairo_headers, subdir: 'cairo') + +shell = find_program('sh', required: false) +if shell.found() + test_scripts = [ + 'check-doc-syntax.sh', + 'check-headers.sh', + 'check-preprocessor-syntax.sh', + ] + + foreach test_script: test_scripts + test(test_script, shell, + args: [test_script], + suite: ['fast', 'lint'], + workdir: meson.current_source_dir()) + endforeach +endif diff --git a/local/recipes/libs/cairo/source/src/test-base-compositor-surface.c b/local/recipes/libs/cairo/source/src/test-base-compositor-surface.c new file mode 100644 index 0000000000..00e3d0c561 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/test-base-compositor-surface.c @@ -0,0 +1,825 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2002 University of Southern California + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Joonas Pihlaja + * Chris Wilson + */ + +#include "cairoint.h" + +#include "test-compositor-surface-private.h" + +#include "cairo-clip-private.h" +#include "cairo-composite-rectangles-private.h" +#include "cairo-compositor-private.h" +#include "cairo-error-private.h" +#include "cairo-image-surface-private.h" +#include "cairo-region-private.h" +#include "cairo-traps-private.h" + +/* The intention is that this is a surface that just works, and most + * important of all does not try to be clever! + */ + +typedef cairo_int_status_t +(*draw_func_t) (cairo_image_surface_t *dst, + void *closure, + cairo_operator_t op, + const cairo_pattern_t *pattern, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents); + +static pixman_op_t +_pixman_operator (cairo_operator_t op) +{ + switch ((int) op) { + case CAIRO_OPERATOR_CLEAR: + return PIXMAN_OP_CLEAR; + + case CAIRO_OPERATOR_SOURCE: + return PIXMAN_OP_SRC; + case CAIRO_OPERATOR_OVER: + return PIXMAN_OP_OVER; + case CAIRO_OPERATOR_IN: + return PIXMAN_OP_IN; + case CAIRO_OPERATOR_OUT: + return PIXMAN_OP_OUT; + case CAIRO_OPERATOR_ATOP: + return PIXMAN_OP_ATOP; + + case CAIRO_OPERATOR_DEST: + return PIXMAN_OP_DST; + case CAIRO_OPERATOR_DEST_OVER: + return PIXMAN_OP_OVER_REVERSE; + case CAIRO_OPERATOR_DEST_IN: + return PIXMAN_OP_IN_REVERSE; + case CAIRO_OPERATOR_DEST_OUT: + return PIXMAN_OP_OUT_REVERSE; + case CAIRO_OPERATOR_DEST_ATOP: + return PIXMAN_OP_ATOP_REVERSE; + + case CAIRO_OPERATOR_XOR: + return PIXMAN_OP_XOR; + case CAIRO_OPERATOR_ADD: + return PIXMAN_OP_ADD; + case CAIRO_OPERATOR_SATURATE: + return PIXMAN_OP_SATURATE; + + case CAIRO_OPERATOR_MULTIPLY: + return PIXMAN_OP_MULTIPLY; + case CAIRO_OPERATOR_SCREEN: + return PIXMAN_OP_SCREEN; + case CAIRO_OPERATOR_OVERLAY: + return PIXMAN_OP_OVERLAY; + case CAIRO_OPERATOR_DARKEN: + return PIXMAN_OP_DARKEN; + case CAIRO_OPERATOR_LIGHTEN: + return PIXMAN_OP_LIGHTEN; + case CAIRO_OPERATOR_COLOR_DODGE: + return PIXMAN_OP_COLOR_DODGE; + case CAIRO_OPERATOR_COLOR_BURN: + return PIXMAN_OP_COLOR_BURN; + case CAIRO_OPERATOR_HARD_LIGHT: + return PIXMAN_OP_HARD_LIGHT; + case CAIRO_OPERATOR_SOFT_LIGHT: + return PIXMAN_OP_SOFT_LIGHT; + case CAIRO_OPERATOR_DIFFERENCE: + return PIXMAN_OP_DIFFERENCE; + case CAIRO_OPERATOR_EXCLUSION: + return PIXMAN_OP_EXCLUSION; + case CAIRO_OPERATOR_HSL_HUE: + return PIXMAN_OP_HSL_HUE; + case CAIRO_OPERATOR_HSL_SATURATION: + return PIXMAN_OP_HSL_SATURATION; + case CAIRO_OPERATOR_HSL_COLOR: + return PIXMAN_OP_HSL_COLOR; + case CAIRO_OPERATOR_HSL_LUMINOSITY: + return PIXMAN_OP_HSL_LUMINOSITY; + + default: + ASSERT_NOT_REACHED; + return PIXMAN_OP_OVER; + } +} + +static cairo_image_surface_t * +create_composite_mask (cairo_image_surface_t *dst, + void *draw_closure, + draw_func_t draw_func, + const cairo_composite_rectangles_t *extents) +{ + cairo_image_surface_t *surface; + cairo_int_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + surface = (cairo_image_surface_t *) + _cairo_image_surface_create_with_pixman_format (NULL, PIXMAN_a8, + extents->bounded.width, + extents->bounded.height, + 0); + if (unlikely (surface->base.status)) + return surface; + + status = draw_func (surface, draw_closure, + CAIRO_OPERATOR_ADD, &_cairo_pattern_white.base, + extents->bounded.x, extents->bounded.y, + &extents->bounded); + if (unlikely (status)) + goto error; + + status = _cairo_clip_combine_with_surface (extents->clip, + &surface->base, + extents->bounded.x, + extents->bounded.y); + if (unlikely (status)) + goto error; + + return surface; + +error: + cairo_surface_destroy (&surface->base); + return (cairo_image_surface_t *)_cairo_surface_create_in_error (status); +} + +/* Handles compositing with a clip surface when the operator allows + * us to combine the clip with the mask + */ +static cairo_status_t +clip_and_composite_with_mask (const cairo_composite_rectangles_t*extents, + draw_func_t draw_func, + void *draw_closure) +{ + cairo_image_surface_t *dst = (cairo_image_surface_t *)extents->surface; + cairo_image_surface_t *mask; + pixman_image_t *src; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + int src_x, src_y; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + mask = create_composite_mask (dst, draw_closure, draw_func, extents); + if (unlikely (mask->base.status)) + return mask->base.status; + + src = _pixman_image_for_pattern (dst, + &extents->source_pattern.base, FALSE, + &extents->bounded, + &extents->source_sample_area, + &src_x, &src_y); + if (unlikely (src == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto error; + } + + pixman_image_composite32 (_pixman_operator (extents->op), + src, mask->pixman_image, dst->pixman_image, + extents->bounded.x + src_x, + extents->bounded.y + src_y, + 0, 0, + extents->bounded.x, extents->bounded.y, + extents->bounded.width, extents->bounded.height); + + pixman_image_unref (src); +error: + cairo_surface_destroy (&mask->base); + return status; +} + +/* Handles compositing with a clip surface when we have to do the operation + * in two pieces and combine them together. + */ +static cairo_status_t +clip_and_composite_combine (const cairo_composite_rectangles_t*extents, + draw_func_t draw_func, + void *draw_closure) +{ + cairo_image_surface_t *dst = (cairo_image_surface_t *)extents->surface; + cairo_image_surface_t *tmp, *clip; + int clip_x, clip_y; + cairo_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + tmp = (cairo_image_surface_t *) + _cairo_image_surface_create_with_pixman_format (NULL, + dst->pixman_format, + extents->bounded.width, + extents->bounded.height, + 0); + if (unlikely (tmp->base.status)) + return tmp->base.status; + + pixman_image_composite32 (PIXMAN_OP_SRC, + dst->pixman_image, NULL, tmp->pixman_image, + extents->bounded.x, extents->bounded.y, + 0, 0, + 0, 0, + extents->bounded.width, extents->bounded.height); + + status = draw_func (tmp, draw_closure, + extents->op, &extents->source_pattern.base, + extents->bounded.x, extents->bounded.y, + &extents->bounded); + if (unlikely (status)) + goto error; + + clip = (cairo_image_surface_t *) + _cairo_clip_get_surface (extents->clip, &dst->base, &clip_x, &clip_y); + if (unlikely (clip->base.status)) + goto error; + + pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE, + clip->pixman_image, NULL, dst->pixman_image, + extents->bounded.x - clip_x, extents->bounded.y - clip_y, + 0, 0, + extents->bounded.x, extents->bounded.y, + extents->bounded.width, extents->bounded.height); + pixman_image_composite32 (PIXMAN_OP_ADD, + tmp->pixman_image, clip->pixman_image, dst->pixman_image, + 0, 0, + extents->bounded.x - clip_x, extents->bounded.y - clip_y, + extents->bounded.x, extents->bounded.y, + extents->bounded.width, extents->bounded.height); + + cairo_surface_destroy (&clip->base); + + error: + cairo_surface_destroy (&tmp->base); + + return status; +} + +/* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's + * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip)) + */ +static cairo_status_t +clip_and_composite_source (const cairo_composite_rectangles_t *extents, + draw_func_t draw_func, + void *draw_closure) +{ + cairo_image_surface_t *dst = (cairo_image_surface_t *)extents->surface; + cairo_image_surface_t *mask; + pixman_image_t *src; + int src_x, src_y; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + mask = create_composite_mask (dst, draw_closure, draw_func, extents); + if (unlikely (mask->base.status)) + return mask->base.status; + + pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE, + mask->pixman_image, NULL, dst->pixman_image, + 0, 0, + 0, 0, + extents->bounded.x, extents->bounded.y, + extents->bounded.width, extents->bounded.height); + + src = _pixman_image_for_pattern (dst, + &extents->source_pattern.base, FALSE, + &extents->bounded, + &extents->source_sample_area, + &src_x, &src_y); + if (unlikely (src == NULL)) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto error; + } + + pixman_image_composite32 (PIXMAN_OP_ADD, + src, mask->pixman_image, dst->pixman_image, + extents->bounded.x + src_x, extents->bounded.y + src_y, + 0, 0, + extents->bounded.x, extents->bounded.y, + extents->bounded.width, extents->bounded.height); + + pixman_image_unref (src); + +error: + cairo_surface_destroy (&mask->base); + return status; +} + +static cairo_status_t +fixup_unbounded (const cairo_composite_rectangles_t *extents) +{ + cairo_image_surface_t *dst = (cairo_image_surface_t *)extents->surface; + pixman_image_t *mask; + int mask_x, mask_y; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + if (! _cairo_clip_is_region (extents->clip)) { + cairo_image_surface_t *clip; + + clip = (cairo_image_surface_t *) + _cairo_clip_get_surface (extents->clip, &dst->base, + &mask_x, &mask_y); + if (unlikely (clip->base.status)) + return clip->base.status; + + mask = pixman_image_ref (clip->pixman_image); + cairo_surface_destroy (&clip->base); + } else { + mask_x = mask_y = 0; + mask = _pixman_image_for_color (CAIRO_COLOR_WHITE); + if (unlikely (mask == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + /* top */ + if (extents->bounded.y != extents->unbounded.y) { + int x = extents->unbounded.x; + int y = extents->unbounded.y; + int width = extents->unbounded.width; + int height = extents->bounded.y - y; + + pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE, + mask, NULL, dst->pixman_image, + x - mask_x, y - mask_y, + 0, 0, + x, y, + width, height); + } + + /* left */ + if (extents->bounded.x != extents->unbounded.x) { + int x = extents->unbounded.x; + int y = extents->bounded.y; + int width = extents->bounded.x - x; + int height = extents->bounded.height; + + pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE, + mask, NULL, dst->pixman_image, + x - mask_x, y - mask_y, + 0, 0, + x, y, + width, height); + } + + /* right */ + if (extents->bounded.x + extents->bounded.width != extents->unbounded.x + extents->unbounded.width) { + int x = extents->bounded.x + extents->bounded.width; + int y = extents->bounded.y; + int width = extents->unbounded.x + extents->unbounded.width - x; + int height = extents->bounded.height; + + pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE, + mask, NULL, dst->pixman_image, + x - mask_x, y - mask_y, + 0, 0, + x, y, + width, height); + } + + /* bottom */ + if (extents->bounded.y + extents->bounded.height != extents->unbounded.y + extents->unbounded.height) { + int x = extents->unbounded.x; + int y = extents->bounded.y + extents->bounded.height; + int width = extents->unbounded.width; + int height = extents->unbounded.y + extents->unbounded.height - y; + + pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE, + mask, NULL, dst->pixman_image, + x - mask_x, y - mask_y, + 0, 0, + x, y, + width, height); + } + + pixman_image_unref (mask); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +set_clip_region (cairo_composite_rectangles_t *extents) +{ + cairo_image_surface_t *dst = (cairo_image_surface_t *) extents->surface; + cairo_region_t *region = _cairo_clip_get_region (extents->clip); + pixman_region32_t *rgn = region ? ®ion->rgn : NULL; + if (! pixman_image_set_clip_region32 (dst->pixman_image, rgn)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +clip_and_composite (cairo_composite_rectangles_t *extents, + draw_func_t draw_func, + void *draw_closure) +{ + cairo_status_t status; + + status = set_clip_region (extents); + if (unlikely (status)) + return status; + + if (extents->op == CAIRO_OPERATOR_SOURCE) { + status = clip_and_composite_source (extents, draw_func, draw_closure); + } else { + if (extents->op == CAIRO_OPERATOR_CLEAR) { + extents->source_pattern.solid = _cairo_pattern_white; + extents->op = CAIRO_OPERATOR_DEST_OUT; + } + if (! _cairo_clip_is_region (extents->clip)) { + if (extents->is_bounded) + status = clip_and_composite_with_mask (extents, draw_func, draw_closure); + else + status = clip_and_composite_combine (extents, draw_func, draw_closure); + } else { + status = draw_func ((cairo_image_surface_t *) extents->surface, + draw_closure, + extents->op, + &extents->source_pattern.base, + 0, 0, + &extents->bounded); + } + } + + if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) + status = fixup_unbounded (extents); + + return status; +} + +/* high-level compositor interface */ + +static cairo_int_status_t +composite_paint (cairo_image_surface_t *dst, + void *closure, + cairo_operator_t op, + const cairo_pattern_t *pattern, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents) +{ + cairo_rectangle_int_t sample; + pixman_image_t *src; + int src_x, src_y; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + _cairo_pattern_sampled_area (pattern, extents, &sample); + src = _pixman_image_for_pattern (dst, + pattern, FALSE, + extents, &sample, + &src_x, &src_y); + if (unlikely (src == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + TRACE ((stderr, "%s: src=(%d, %d), dst=(%d, %d) size=%dx%d\n", __FUNCTION__, + extents->x + src_x, extents->y + src_y, + extents->x - dst_x, extents->y - dst_y, + extents->width, extents->height)); + + pixman_image_composite32 (_pixman_operator (op), + src, NULL, dst->pixman_image, + extents->x + src_x, extents->y + src_y, + 0, 0, + extents->x - dst_x, extents->y - dst_y, + extents->width, extents->height); + + pixman_image_unref (src); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +base_compositor_paint (const cairo_compositor_t *_compositor, + cairo_composite_rectangles_t *extents) +{ + TRACE ((stderr, "%s\n", __FUNCTION__)); + return clip_and_composite (extents, composite_paint, NULL); +} + +static cairo_int_status_t +composite_mask (cairo_image_surface_t *dst, + void *closure, + cairo_operator_t op, + const cairo_pattern_t *pattern, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents) +{ + cairo_rectangle_int_t sample; + pixman_image_t *src, *mask; + int src_x, src_y; + int mask_x, mask_y; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + _cairo_pattern_sampled_area (pattern, extents, &sample); + src = _pixman_image_for_pattern (dst, pattern, FALSE, + extents, &sample, + &src_x, &src_y); + if (unlikely (src == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + _cairo_pattern_sampled_area (closure, extents, &sample); + mask = _pixman_image_for_pattern (dst, closure, TRUE, + extents, &sample, + &mask_x, &mask_y); + if (unlikely (mask == NULL)) { + pixman_image_unref (src); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + pixman_image_composite32 (_pixman_operator (op), + src, mask, dst->pixman_image, + extents->x + src_x, extents->y + src_y, + extents->x + mask_x, extents->y + mask_y, + extents->x - dst_x, extents->y - dst_y, + extents->width, extents->height); + + pixman_image_unref (mask); + pixman_image_unref (src); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +base_compositor_mask (const cairo_compositor_t *_compositor, + cairo_composite_rectangles_t *extents) +{ + TRACE ((stderr, "%s\n", __FUNCTION__)); + return clip_and_composite (extents, composite_mask, &extents->mask_pattern.base); +} + +typedef struct { + cairo_traps_t traps; + cairo_antialias_t antialias; +} composite_traps_info_t; + +static cairo_int_status_t +composite_traps (cairo_image_surface_t *dst, + void *closure, + cairo_operator_t op, + const cairo_pattern_t *pattern, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents) +{ + composite_traps_info_t *info = closure; + cairo_rectangle_int_t sample; + pixman_image_t *src, *mask; + int src_x, src_y; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + _cairo_pattern_sampled_area (pattern, extents, &sample); + src = _pixman_image_for_pattern (dst, pattern, FALSE, + extents, &sample, + &src_x, &src_y); + if (unlikely (src == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + mask = pixman_image_create_bits (info->antialias == CAIRO_ANTIALIAS_NONE ? PIXMAN_a1 : PIXMAN_a8, + extents->width, extents->height, + NULL, 0); + if (unlikely (mask == NULL)) { + pixman_image_unref (src); + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + + _pixman_image_add_traps (mask, extents->x, extents->y, &info->traps); + pixman_image_composite32 (_pixman_operator (op), + src, mask, dst->pixman_image, + extents->x + src_x - dst_x, extents->y + src_y - dst_y, + 0, 0, + extents->x - dst_x, extents->y - dst_y, + extents->width, extents->height); + + pixman_image_unref (mask); + pixman_image_unref (src); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +trim_extents_to_traps (cairo_composite_rectangles_t *extents, + cairo_traps_t *traps) +{ + cairo_box_t box; + + /* X trims the affected area to the extents of the trapezoids, so + * we need to compensate when fixing up the unbounded area. + */ + _cairo_traps_extents (traps, &box); + return _cairo_composite_rectangles_intersect_mask_extents (extents, &box); +} + +static cairo_int_status_t +base_compositor_stroke (const cairo_compositor_t *_compositor, + cairo_composite_rectangles_t *extents, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias) +{ + composite_traps_info_t info; + cairo_int_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + info.antialias = antialias; + _cairo_traps_init_with_clip (&info.traps, extents->clip); + status = _cairo_path_fixed_stroke_polygon_to_traps (path, style, + ctm, ctm_inverse, + tolerance, + &info.traps); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) + status = trim_extents_to_traps (extents, &info.traps); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) + status = clip_and_composite (extents, composite_traps, &info); + _cairo_traps_fini (&info.traps); + + return status; +} + +static cairo_int_status_t +base_compositor_fill (const cairo_compositor_t *_compositor, + cairo_composite_rectangles_t *extents, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + composite_traps_info_t info; + cairo_int_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + info.antialias = antialias; + _cairo_traps_init_with_clip (&info.traps, extents->clip); + status = _cairo_path_fixed_fill_to_traps (path, + fill_rule, tolerance, + &info.traps); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) + status = trim_extents_to_traps (extents, &info.traps); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) + status = clip_and_composite (extents, composite_traps, &info); + _cairo_traps_fini (&info.traps); + + return status; +} + +static cairo_int_status_t +composite_glyphs (cairo_image_surface_t *dst, + void *closure, + cairo_operator_t op, + const cairo_pattern_t *pattern, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents) +{ + cairo_composite_glyphs_info_t *info = closure; + pixman_image_t *mask; + cairo_status_t status; + int i; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + mask = pixman_image_create_bits (PIXMAN_a8, + extents->width, extents->height, + NULL, 0); + if (unlikely (mask == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + status = CAIRO_STATUS_SUCCESS; + _cairo_scaled_font_freeze_cache (info->font); + for (i = 0; i < info->num_glyphs; i++) { + cairo_image_surface_t *glyph_surface; + cairo_scaled_glyph_t *scaled_glyph; + unsigned long glyph_index = info->glyphs[i].index; + int x, y; + + status = _cairo_scaled_glyph_lookup (info->font, glyph_index, + CAIRO_SCALED_GLYPH_INFO_SURFACE, + NULL, /* foreground color */ + &scaled_glyph); + + if (unlikely (status)) + break; + + glyph_surface = scaled_glyph->surface; + if (glyph_surface->width && glyph_surface->height) { + /* round glyph locations to the nearest pixel */ + /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */ + x = _cairo_lround (info->glyphs[i].x - + glyph_surface->base.device_transform.x0); + y = _cairo_lround (info->glyphs[i].y - + glyph_surface->base.device_transform.y0); + + pixman_image_composite32 (PIXMAN_OP_ADD, + glyph_surface->pixman_image, NULL, mask, + 0, 0, + 0, 0, + x - extents->x, y - extents->y, + glyph_surface->width, + glyph_surface->height); + } + } + _cairo_scaled_font_thaw_cache (info->font); + + if (status == CAIRO_STATUS_SUCCESS) { + cairo_rectangle_int_t sample; + pixman_image_t *src; + int src_x, src_y; + + _cairo_pattern_sampled_area (pattern, extents, &sample); + src = _pixman_image_for_pattern (dst, pattern, FALSE, + extents, &sample, + &src_x, &src_y); + if (src != NULL) { + dst_x = extents->x - dst_x; + dst_y = extents->y - dst_y; + pixman_image_composite32 (_pixman_operator (op), + src, mask, dst->pixman_image, + src_x + dst_x, src_y + dst_y, + 0, 0, + dst_x, dst_y, + extents->width, extents->height); + pixman_image_unref (src); + } else + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + } + pixman_image_unref (mask); + + return status; +} + +static cairo_int_status_t +base_compositor_glyphs (const cairo_compositor_t *_compositor, + cairo_composite_rectangles_t *extents, + cairo_scaled_font_t *scaled_font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_bool_t overlap) +{ + cairo_composite_glyphs_info_t info; + + info.font = scaled_font; + info.glyphs = glyphs; + info.num_glyphs = num_glyphs; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + return clip_and_composite (extents, composite_glyphs, &info); +} + +static const cairo_compositor_t base_compositor = { + &__cairo_no_compositor, + + base_compositor_paint, + base_compositor_mask, + base_compositor_stroke, + base_compositor_fill, + base_compositor_glyphs, +}; + +cairo_surface_t * +_cairo_test_base_compositor_surface_create (cairo_content_t content, + int width, + int height) +{ + return test_compositor_surface_create (&base_compositor, + content, width, height); +} diff --git a/local/recipes/libs/cairo/source/src/test-compositor-surface-private.h b/local/recipes/libs/cairo/source/src/test-compositor-surface-private.h new file mode 100644 index 0000000000..491f241bac --- /dev/null +++ b/local/recipes/libs/cairo/source/src/test-compositor-surface-private.h @@ -0,0 +1,56 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Intel Corporation + * + * Contributor(s): + * Chris Wilson + */ + +#ifndef TEST_COMPOSITOR_SURFACE_PRIVATE_H +#define TEST_COMPOSITOR_SURFACE_PRIVATE_H + +#include "cairo.h" + +#include "test-compositor-surface.h" + +#include "cairo-compiler-private.h" +#include "cairo-compositor-private.h" + +CAIRO_BEGIN_DECLS + +cairo_private cairo_surface_t * +test_compositor_surface_create (const cairo_compositor_t *compositor, + cairo_content_t content, + int width, + int height); + +CAIRO_END_DECLS + +#endif /* TEST_COMPOSITOR_SURFACE_PRIVATE H */ diff --git a/local/recipes/libs/cairo/source/src/test-compositor-surface.c b/local/recipes/libs/cairo/source/src/test-compositor-surface.c new file mode 100644 index 0000000000..4518f509c8 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/test-compositor-surface.c @@ -0,0 +1,265 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Intel Corporation + * + * Contributor(s): + * Chris Wilson + */ + +#include "cairoint.h" + +#include "test-compositor-surface-private.h" + +#include "cairo-compositor-private.h" +#include "cairo-default-context-private.h" +#include "cairo-error-private.h" +#include "cairo-image-surface-private.h" +#include "cairo-surface-backend-private.h" + +typedef struct _test_compositor_surface { + cairo_image_surface_t base; +} test_compositor_surface_t; + +static const cairo_surface_backend_t test_compositor_surface_backend; + +cairo_surface_t * +test_compositor_surface_create (const cairo_compositor_t *compositor, + cairo_content_t content, + int width, + int height) +{ + test_compositor_surface_t *surface; + pixman_image_t *pixman_image; + pixman_format_code_t pixman_format; + + switch (content) { + case CAIRO_CONTENT_ALPHA: + pixman_format = PIXMAN_a8; + break; + case CAIRO_CONTENT_COLOR: + pixman_format = PIXMAN_x8r8g8b8; + break; + case CAIRO_CONTENT_COLOR_ALPHA: + pixman_format = PIXMAN_a8r8g8b8; + break; + default: + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT)); + } + + pixman_image = pixman_image_create_bits (pixman_format, width, height, + NULL, 0); + if (unlikely (pixman_image == NULL)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + surface = _cairo_calloc (sizeof (test_compositor_surface_t)); + if (unlikely (surface == NULL)) { + pixman_image_unref (pixman_image); + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + } + + _cairo_surface_init (&surface->base.base, + &test_compositor_surface_backend, + NULL, /* device */ + content, + FALSE); /* is_vector */ + _cairo_image_surface_init (&surface->base, pixman_image, pixman_format); + + surface->base.compositor = compositor; + + return &surface->base.base; +} + +static cairo_surface_t * +test_compositor_surface_create_similar (void *abstract_surface, + cairo_content_t content, + int width, + int height) +{ + test_compositor_surface_t *surface = abstract_surface; + + return test_compositor_surface_create (surface->base.compositor, + content, width, height); +} + +static cairo_int_status_t +test_compositor_surface_paint (void *_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip) +{ + test_compositor_surface_t *surface = _surface; + return _cairo_compositor_paint (surface->base.compositor, + _surface, op, source, + clip); +} + +static cairo_int_status_t +test_compositor_surface_mask (void *_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_clip_t *clip) +{ + test_compositor_surface_t *surface = _surface; + return _cairo_compositor_mask (surface->base.compositor, + _surface, op, source, mask, + clip); +} + +static cairo_int_status_t +test_compositor_surface_stroke (void *_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + test_compositor_surface_t *surface = _surface; + if (antialias == CAIRO_ANTIALIAS_DEFAULT) + antialias = CAIRO_ANTIALIAS_BEST; + return _cairo_compositor_stroke (surface->base.compositor, + _surface, op, source, + path, style, ctm, ctm_inverse, + tolerance, antialias, + clip); +} + +static cairo_int_status_t +test_compositor_surface_fill (void *_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + test_compositor_surface_t *surface = _surface; + if (antialias == CAIRO_ANTIALIAS_DEFAULT) + antialias = CAIRO_ANTIALIAS_BEST; + return _cairo_compositor_fill (surface->base.compositor, + _surface, op, source, + path, fill_rule, tolerance, antialias, + clip); +} + +static cairo_int_status_t +test_compositor_surface_glyphs (void *_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip) +{ + test_compositor_surface_t *surface = _surface; + return _cairo_compositor_glyphs (surface->base.compositor, + _surface, op, source, + glyphs, num_glyphs, scaled_font, + clip); +} + +static const cairo_surface_backend_t test_compositor_surface_backend = { + CAIRO_SURFACE_TYPE_IMAGE, + _cairo_image_surface_finish, + _cairo_default_context_create, + + test_compositor_surface_create_similar, + NULL, /* create similar image */ + _cairo_image_surface_map_to_image, + _cairo_image_surface_unmap_image, + + _cairo_image_surface_source, + _cairo_image_surface_acquire_source_image, + _cairo_image_surface_release_source_image, + _cairo_image_surface_snapshot, + + NULL, /* copy_page */ + NULL, /* show_page */ + + _cairo_image_surface_get_extents, + _cairo_image_surface_get_font_options, + + NULL, /* flush */ + NULL, /* mark_dirty_rectangle */ + + test_compositor_surface_paint, + test_compositor_surface_mask, + test_compositor_surface_stroke, + test_compositor_surface_fill, + NULL, /* fill/stroke */ + test_compositor_surface_glyphs, +}; + +static const cairo_compositor_t * +get_fallback_compositor (void) +{ + return &_cairo_fallback_compositor; +} + +cairo_surface_t * +_cairo_test_fallback_compositor_surface_create (cairo_content_t content, + int width, + int height) +{ + return test_compositor_surface_create (get_fallback_compositor(), + content, width, height); +} + +cairo_surface_t * +_cairo_test_mask_compositor_surface_create (cairo_content_t content, + int width, + int height) +{ + return test_compositor_surface_create (_cairo_image_mask_compositor_get(), + content, width, height); +} + +cairo_surface_t * +_cairo_test_traps_compositor_surface_create (cairo_content_t content, + int width, + int height) +{ + return test_compositor_surface_create (_cairo_image_traps_compositor_get(), + content, width, height); +} + +cairo_surface_t * +_cairo_test_spans_compositor_surface_create (cairo_content_t content, + int width, + int height) +{ + return test_compositor_surface_create (_cairo_image_spans_compositor_get(), + content, width, height); +} diff --git a/local/recipes/libs/cairo/source/src/test-compositor-surface.h b/local/recipes/libs/cairo/source/src/test-compositor-surface.h new file mode 100644 index 0000000000..8d8af2d540 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/test-compositor-surface.h @@ -0,0 +1,71 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Intel Corporation + * + * Contributor(s): + * Chris Wilson + */ + +#ifndef TEST_COMPOSITOR_SURFACE_H +#define TEST_COMPOSITOR_SURFACE_H + +#include "cairo.h" + +CAIRO_BEGIN_DECLS + +cairo_surface_t * +_cairo_test_fallback_compositor_surface_create (cairo_content_t content, + int width, + int height); + + +cairo_surface_t * +_cairo_test_mask_compositor_surface_create (cairo_content_t content, + int width, + int height); + +cairo_surface_t * +_cairo_test_traps_compositor_surface_create (cairo_content_t content, + int width, + int height); + +cairo_surface_t * +_cairo_test_spans_compositor_surface_create (cairo_content_t content, + int width, + int height); + +cairo_surface_t * +_cairo_test_base_compositor_surface_create (cairo_content_t content, + int width, + int height); + +CAIRO_END_DECLS + +#endif /* TEST_COMPOSITOR_SURFACE_H */ diff --git a/local/recipes/libs/cairo/source/src/test-null-compositor-surface.c b/local/recipes/libs/cairo/source/src/test-null-compositor-surface.c new file mode 100644 index 0000000000..ad2a35968e --- /dev/null +++ b/local/recipes/libs/cairo/source/src/test-null-compositor-surface.c @@ -0,0 +1,487 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Intel Corporation + * + * Contributor(s): + * Chris Wilson + */ + + +#include "cairoint.h" + +#include "test-null-compositor-surface.h" + +#include "cairo-compositor-private.h" +#include "cairo-default-context-private.h" +#include "cairo-error-private.h" +#include "cairo-image-surface-private.h" +#include "cairo-surface-backend-private.h" +#include "cairo-spans-compositor-private.h" +#include "cairo-spans-private.h" + +typedef struct _test_compositor_surface { + cairo_image_surface_t base; +} test_compositor_surface_t; + +static const cairo_surface_backend_t test_compositor_surface_backend; + +static cairo_surface_t * +test_compositor_surface_create (const cairo_compositor_t *compositor, + cairo_content_t content, + int width, + int height) +{ + test_compositor_surface_t *surface; + pixman_image_t *pixman_image; + pixman_format_code_t pixman_format; + + switch (content) { + case CAIRO_CONTENT_ALPHA: + pixman_format = PIXMAN_a8; + break; + case CAIRO_CONTENT_COLOR: + pixman_format = PIXMAN_x8r8g8b8; + break; + case CAIRO_CONTENT_COLOR_ALPHA: + pixman_format = PIXMAN_a8r8g8b8; + break; + default: + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_CONTENT)); + } + + pixman_image = pixman_image_create_bits (pixman_format, width, height, + NULL, 0); + if (unlikely (pixman_image == NULL)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + surface = _cairo_calloc (sizeof (test_compositor_surface_t)); + if (unlikely (surface == NULL)) { + pixman_image_unref (pixman_image); + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + } + + _cairo_surface_init (&surface->base.base, + &test_compositor_surface_backend, + NULL, /* device */ + content, + FALSE); /* is_vector */ + _cairo_image_surface_init (&surface->base, pixman_image, pixman_format); + + surface->base.compositor = compositor; + + return &surface->base.base; +} + +static cairo_surface_t * +test_compositor_surface_create_similar (void *abstract_surface, + cairo_content_t content, + int width, + int height) +{ + test_compositor_surface_t *surface = abstract_surface; + + return test_compositor_surface_create (surface->base.compositor, + content, width, height); +} + +static cairo_int_status_t +test_compositor_surface_paint (void *_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip) +{ + test_compositor_surface_t *surface = _surface; + return _cairo_compositor_paint (surface->base.compositor, + _surface, op, source, + clip); +} + +static cairo_int_status_t +test_compositor_surface_mask (void *_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_clip_t *clip) +{ + test_compositor_surface_t *surface = _surface; + return _cairo_compositor_mask (surface->base.compositor, + _surface, op, source, mask, + clip); +} + +static cairo_int_status_t +test_compositor_surface_stroke (void *_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + test_compositor_surface_t *surface = _surface; + return _cairo_compositor_stroke (surface->base.compositor, + _surface, op, source, + path, style, ctm, ctm_inverse, + tolerance, antialias, + clip); +} + +static cairo_int_status_t +test_compositor_surface_fill (void *_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + test_compositor_surface_t *surface = _surface; + return _cairo_compositor_fill (surface->base.compositor, + _surface, op, source, + path, fill_rule, tolerance, antialias, + clip); +} + +static cairo_int_status_t +test_compositor_surface_glyphs (void *_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip) +{ + test_compositor_surface_t *surface = _surface; + return _cairo_compositor_glyphs (surface->base.compositor, + _surface, op, source, + glyphs, num_glyphs, scaled_font, + clip); +} + +static const cairo_surface_backend_t test_compositor_surface_backend = { + CAIRO_SURFACE_TYPE_IMAGE, + _cairo_image_surface_finish, + _cairo_default_context_create, + + test_compositor_surface_create_similar, + NULL, /* create similar image */ + _cairo_image_surface_map_to_image, + _cairo_image_surface_unmap_image, + + _cairo_image_surface_source, + _cairo_image_surface_acquire_source_image, + _cairo_image_surface_release_source_image, + NULL, /* snapshot */ + + NULL, /* copy_page */ + NULL, /* show_page */ + + _cairo_image_surface_get_extents, + _cairo_image_surface_get_font_options, + + NULL, /* flush */ + NULL, /* mark_dirty_rectangle */ + + test_compositor_surface_paint, + test_compositor_surface_mask, + test_compositor_surface_stroke, + test_compositor_surface_fill, + NULL, /* fill/stroke */ + test_compositor_surface_glyphs, +}; + +static cairo_int_status_t +acquire (void *abstract_dst) +{ + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +release (void *abstract_dst) +{ + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +set_clip_region (void *_surface, + cairo_region_t *region) +{ + return CAIRO_STATUS_SUCCESS; +} + +static cairo_surface_t * +pattern_to_surface (cairo_surface_t *dst, + const cairo_pattern_t *pattern, + cairo_bool_t is_mask, + const cairo_rectangle_int_t *extents, + const cairo_rectangle_int_t *sample, + int *src_x, int *src_y) +{ + return cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0); +} + +static cairo_int_status_t +fill_boxes (void *_dst, + cairo_operator_t op, + const cairo_color_t *color, + cairo_boxes_t *boxes) +{ + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +draw_image_boxes (void *_dst, + cairo_image_surface_t *image, + cairo_boxes_t *boxes, + int dx, int dy) +{ + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +composite (void *_dst, + cairo_operator_t op, + cairo_surface_t *abstract_src, + cairo_surface_t *abstract_mask, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height) +{ + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +lerp (void *_dst, + cairo_surface_t *abstract_src, + cairo_surface_t *abstract_mask, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height) +{ + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +composite_boxes (void *_dst, + cairo_operator_t op, + cairo_surface_t *abstract_src, + cairo_surface_t *abstract_mask, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + cairo_boxes_t *boxes, + const cairo_rectangle_int_t *extents) +{ + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +composite_traps (void *_dst, + cairo_operator_t op, + cairo_surface_t *abstract_src, + int src_x, + int src_y, + int dst_x, + int dst_y, + const cairo_rectangle_int_t *extents, + cairo_antialias_t antialias, + cairo_traps_t *traps) +{ + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +check_composite_glyphs (const cairo_composite_rectangles_t *extents, + cairo_scaled_font_t *scaled_font, + cairo_glyph_t *glyphs, + int *num_glyphs) +{ + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +composite_glyphs (void *_dst, + cairo_operator_t op, + cairo_surface_t *_src, + int src_x, + int src_y, + int dst_x, + int dst_y, + cairo_composite_glyphs_info_t *info) +{ + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +spans (void *abstract_renderer, + int y, int height, + const cairo_half_open_span_t *spans, + unsigned num_spans) +{ + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +finish_spans (void *abstract_renderer) +{ + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +span_renderer_init (cairo_abstract_span_renderer_t *_r, + const cairo_composite_rectangles_t *composite, + cairo_antialias_t antialias, + cairo_bool_t needs_clip) +{ + cairo_span_renderer_t *r = (cairo_span_renderer_t *)_r; + r->render_rows = spans; + r->finish = finish_spans; + return CAIRO_STATUS_SUCCESS; +} + +static void +span_renderer_fini (cairo_abstract_span_renderer_t *_r, + cairo_int_status_t status) +{ +} + +static const cairo_compositor_t * +no_fallback_compositor_get (void) +{ + return &__cairo_no_compositor; +} + +static cairo_int_status_t +check_composite (const cairo_composite_rectangles_t *extents) +{ + return CAIRO_STATUS_SUCCESS; +} + +static const cairo_compositor_t * +no_traps_compositor_get (void) +{ + static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT; + static cairo_traps_compositor_t compositor; + + if (_cairo_atomic_init_once_enter(&once)) { + _cairo_traps_compositor_init (&compositor, + no_fallback_compositor_get ()); + + compositor.acquire = acquire; + compositor.release = release; + compositor.set_clip_region = set_clip_region; + compositor.pattern_to_surface = pattern_to_surface; + compositor.draw_image_boxes = draw_image_boxes; + //compositor.copy_boxes = copy_boxes; + compositor.fill_boxes = fill_boxes; + compositor.check_composite = check_composite; + compositor.composite = composite; + compositor.lerp = lerp; + //compositor.check_composite_boxes = check_composite_boxes; + compositor.composite_boxes = composite_boxes; + //compositor.check_composite_traps = check_composite_traps; + compositor.composite_traps = composite_traps; + compositor.check_composite_glyphs = check_composite_glyphs; + compositor.composite_glyphs = composite_glyphs; + + _cairo_atomic_init_once_leave(&once); + } + + return &compositor.base; +} + +static const cairo_compositor_t * +no_spans_compositor_get (void) +{ + static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT; + static cairo_spans_compositor_t compositor; + + if (_cairo_atomic_init_once_enter(&once)) { + _cairo_spans_compositor_init (&compositor, + no_traps_compositor_get()); + + //compositor.acquire = acquire; + //compositor.release = release; + compositor.fill_boxes = fill_boxes; + //compositor.check_composite_boxes = check_composite_boxes; + compositor.composite_boxes = composite_boxes; + //compositor.check_span_renderer = check_span_renderer; + compositor.renderer_init = span_renderer_init; + compositor.renderer_fini = span_renderer_fini; + + _cairo_atomic_init_once_leave(&once); + } + + return &compositor.base; +} + +cairo_surface_t * +_cairo_test_no_fallback_compositor_surface_create (cairo_content_t content, + int width, + int height) +{ + return test_compositor_surface_create (no_fallback_compositor_get(), + content, width, height); +} + +cairo_surface_t * +_cairo_test_no_traps_compositor_surface_create (cairo_content_t content, + int width, + int height) +{ + return test_compositor_surface_create (no_traps_compositor_get(), + content, width, height); +} + +cairo_surface_t * +_cairo_test_no_spans_compositor_surface_create (cairo_content_t content, + int width, + int height) +{ + return test_compositor_surface_create (no_spans_compositor_get(), + content, width, height); +} diff --git a/local/recipes/libs/cairo/source/src/test-null-compositor-surface.h b/local/recipes/libs/cairo/source/src/test-null-compositor-surface.h new file mode 100644 index 0000000000..52d864b28d --- /dev/null +++ b/local/recipes/libs/cairo/source/src/test-null-compositor-surface.h @@ -0,0 +1,60 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2011 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Intel Corporation + * + * Contributor(s): + * Chris Wilson + */ + +#ifndef TEST_NULL_COMPOSITOR_SURFACE_H +#define TEST_NULL_COMPOSITOR_SURFACE_H + +#include "cairo.h" + +CAIRO_BEGIN_DECLS + +cairo_surface_t * +_cairo_test_no_fallback_compositor_surface_create (cairo_content_t content, + int width, + int height); + +cairo_surface_t * +_cairo_test_no_traps_compositor_surface_create (cairo_content_t content, + int width, + int height); + +cairo_surface_t * +_cairo_test_no_spans_compositor_surface_create (cairo_content_t content, + int width, + int height); + +CAIRO_END_DECLS + +#endif /* TEST_NULL_COMPOSITOR_SURFACE_H */ diff --git a/local/recipes/libs/cairo/source/src/test-paginated-surface.c b/local/recipes/libs/cairo/source/src/test-paginated-surface.c new file mode 100644 index 0000000000..d33594d4be --- /dev/null +++ b/local/recipes/libs/cairo/source/src/test-paginated-surface.c @@ -0,0 +1,289 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Carl Worth + */ + +/* This isn't a "real" surface, but just something to be used by the + * test suite to help exercise the paginated-surface paths in cairo. + * + * The defining feature of this backend is that it uses a paginated + * surface to record all operations, and then replays everything to an + * image surface. + * + * It's possible that this code might serve as a good starting point + * for someone working on bringing up a new paginated-surface-based + * backend. + */ + +#include "cairoint.h" + +#include "test-paginated-surface.h" + +#include "cairo-default-context-private.h" +#include "cairo-error-private.h" +#include "cairo-paginated-private.h" +#include "cairo-surface-backend-private.h" + +typedef struct _test_paginated_surface { + cairo_surface_t base; + cairo_surface_t *target; + cairo_paginated_mode_t paginated_mode; +} test_paginated_surface_t; + +static const cairo_surface_backend_t test_paginated_surface_backend; +static const cairo_paginated_surface_backend_t test_paginated_surface_paginated_backend; + +cairo_surface_t * +_cairo_test_paginated_surface_create (cairo_surface_t *target) +{ + cairo_status_t status; + cairo_surface_t *paginated; + test_paginated_surface_t *surface; + + status = cairo_surface_status (target); + if (unlikely (status)) + return _cairo_surface_create_in_error (status); + + surface = _cairo_calloc (sizeof (test_paginated_surface_t)); + if (unlikely (surface == NULL)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + _cairo_surface_init (&surface->base, + &test_paginated_surface_backend, + NULL, /* device */ + target->content, + TRUE); /* is_vector */ + + surface->target = cairo_surface_reference (target); + + paginated = _cairo_paginated_surface_create (&surface->base, + target->content, + &test_paginated_surface_paginated_backend); + status = paginated->status; + if (status == CAIRO_STATUS_SUCCESS) { + /* paginated keeps the only reference to surface now, drop ours */ + cairo_surface_destroy (&surface->base); + return paginated; + } + + cairo_surface_destroy (target); + free (surface); + return _cairo_surface_create_in_error (status); +} + +static cairo_status_t +_test_paginated_surface_finish (void *abstract_surface) +{ + test_paginated_surface_t *surface = abstract_surface; + + cairo_surface_destroy (surface->target); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_bool_t +_test_paginated_surface_get_extents (void *abstract_surface, + cairo_rectangle_int_t *rectangle) +{ + test_paginated_surface_t *surface = abstract_surface; + + return _cairo_surface_get_extents (surface->target, rectangle); +} + +static cairo_int_status_t +_test_paginated_surface_paint (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip) +{ + test_paginated_surface_t *surface = abstract_surface; + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) + return CAIRO_STATUS_SUCCESS; + + return _cairo_surface_paint (surface->target, op, source, clip); +} + +static cairo_int_status_t +_test_paginated_surface_mask (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_clip_t *clip) +{ + test_paginated_surface_t *surface = abstract_surface; + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) + return CAIRO_STATUS_SUCCESS; + + return _cairo_surface_mask (surface->target, + op, source, mask, clip); +} + +static cairo_int_status_t +_test_paginated_surface_stroke (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + test_paginated_surface_t *surface = abstract_surface; + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) + return CAIRO_STATUS_SUCCESS; + + return _cairo_surface_stroke (surface->target, op, source, + path, style, + ctm, ctm_inverse, + tolerance, antialias, + clip); +} + +static cairo_int_status_t +_test_paginated_surface_fill (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + test_paginated_surface_t *surface = abstract_surface; + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) + return CAIRO_STATUS_SUCCESS; + + return _cairo_surface_fill (surface->target, op, source, + path, fill_rule, + tolerance, antialias, + clip); +} + +static cairo_bool_t +_test_paginated_surface_has_show_text_glyphs (void *abstract_surface) +{ + test_paginated_surface_t *surface = abstract_surface; + + return cairo_surface_has_show_text_glyphs (surface->target); +} + +static cairo_int_status_t +_test_paginated_surface_show_text_glyphs (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const char *utf8, + int utf8_len, + cairo_glyph_t *glyphs, + int num_glyphs, + const cairo_text_cluster_t *clusters, + int num_clusters, + cairo_text_cluster_flags_t cluster_flags, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip) +{ + test_paginated_surface_t *surface = abstract_surface; + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) + return CAIRO_STATUS_SUCCESS; + + return _cairo_surface_show_text_glyphs (surface->target, op, source, + utf8, utf8_len, + glyphs, num_glyphs, + clusters, num_clusters, + cluster_flags, + scaled_font, + clip); +} + + +static cairo_int_status_t +_test_paginated_surface_set_paginated_mode (void *abstract_surface, + cairo_paginated_mode_t mode) +{ + test_paginated_surface_t *surface = abstract_surface; + + surface->paginated_mode = mode; + + return CAIRO_STATUS_SUCCESS; +} + +static const cairo_surface_backend_t test_paginated_surface_backend = { + CAIRO_INTERNAL_SURFACE_TYPE_TEST_PAGINATED, + _test_paginated_surface_finish, + _cairo_default_context_create, + + /* Since we are a paginated user, we get to regard most of the + * surface backend interface as historical cruft and ignore it. */ + + NULL, /* create_similar */ + NULL, /* create similar image */ + NULL, /* map to image */ + NULL, /* unmap image */ + + _cairo_surface_default_source, + NULL, /* acquire_source_image */ + NULL, /* release_source_image */ + NULL, /* snapshot */ + + NULL, /* copy_page */ + NULL, /* show_page */ + + _test_paginated_surface_get_extents, + NULL, /* get_font_options */ + + NULL, /* flush */ + NULL, /* mark_dirty_rectangle */ + + /* Here is the more "modern" section of the surface backend + * interface which is mostly just drawing functions */ + + _test_paginated_surface_paint, + _test_paginated_surface_mask, + _test_paginated_surface_stroke, + _test_paginated_surface_fill, + NULL, /* fill-stroke */ + NULL, /* replaced by show_text_glyphs */ + _test_paginated_surface_has_show_text_glyphs, + _test_paginated_surface_show_text_glyphs +}; + +static const cairo_paginated_surface_backend_t test_paginated_surface_paginated_backend = { + NULL, /* start_page */ + _test_paginated_surface_set_paginated_mode +}; diff --git a/local/recipes/libs/cairo/source/src/test-paginated-surface.h b/local/recipes/libs/cairo/source/src/test-paginated-surface.h new file mode 100644 index 0000000000..2bd98aa5ee --- /dev/null +++ b/local/recipes/libs/cairo/source/src/test-paginated-surface.h @@ -0,0 +1,48 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Carl Worth + */ + +#ifndef TEST_PAGINATED_SURFACE_H +#define TEST_PAGINATED_SURFACE_H + +#include "cairo.h" + +CAIRO_BEGIN_DECLS + +cairo_surface_t * +_cairo_test_paginated_surface_create (cairo_surface_t *target); + +CAIRO_END_DECLS + +#endif /* TEST_PAGINATED_SURFACE_H */ diff --git a/local/recipes/libs/cairo/source/src/win32/cairo-dwrite-font.cpp b/local/recipes/libs/cairo/source/src/win32/cairo-dwrite-font.cpp new file mode 100644 index 0000000000..bf5191967e --- /dev/null +++ b/local/recipes/libs/cairo/source/src/win32/cairo-dwrite-font.cpp @@ -0,0 +1,2494 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2010 Mozilla Foundation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is the Mozilla Foundation + * + * Contributor(s): + * Bas Schouten + */ + +#include "cairoint.h" + +#include "cairo-win32-private.h" +#include "cairo-pattern-private.h" +#include "cairo-surface-private.h" +#include "cairo-image-surface-private.h" +#include "cairo-clip-private.h" +#include "cairo-win32-refptr.hpp" +#include "cairo-dwrite-private.hpp" +#include "cairo-truetype-subset-private.h" +#include "cairo-scaled-font-subsets-private.h" +#include "cairo-dwrite.h" + +#include +#include + +#include + +/** + * SECTION:cairo-dwrite-fonts + * @Title: DWrite Fonts + * @Short_Description: Font support for Microsoft DirectWrite + * @See_Also: #cairo_font_face_t + * + * The Microsoft DirectWrite font backend is primarily used to render text on + * Microsoft Windows systems. + **/ + +/** + * CAIRO_HAS_DWRITE_FONT: + * + * Defined if the Microsoft DWrite font backend is available. + * This macro can be used to conditionally compile backend-specific code. + * + * Since: 1.18 + **/ + +typedef HRESULT (WINAPI*D2D1CreateFactoryFunc)( + D2D1_FACTORY_TYPE factoryType, + REFIID iid, + CONST D2D1_FACTORY_OPTIONS *pFactoryOptions, + void **factory +); + +#define CAIRO_INT_STATUS_SUCCESS (cairo_int_status_t)CAIRO_STATUS_SUCCESS + +// Forward declarations +cairo_int_status_t +_dwrite_draw_glyphs_to_gdi_surface_d2d(cairo_win32_surface_t *surface, + DWRITE_MATRIX *transform, + DWRITE_GLYPH_RUN *run, + COLORREF color, + const RECT &area); + +static cairo_int_status_t +_dwrite_draw_glyphs_to_gdi_surface_gdi(cairo_win32_surface_t *surface, + DWRITE_MATRIX *transform, + DWRITE_GLYPH_RUN *run, + COLORREF color, + cairo_dwrite_scaled_font_t *scaled_font, + const RECT &area); + +/** + * _cairo_dwrite_error: + * @hr HRESULT code + * @context: context string to display along with the error + * + * Helper function to print a human readable form a HRESULT. + * + * Return value: A cairo status code for the error code + **/ +static cairo_int_status_t +_cairo_dwrite_error (HRESULT hr, const char *context) +{ + void *lpMsgBuf; + + if (!FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_IGNORE_INSERTS | + FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + hr, + MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPWSTR) &lpMsgBuf, + 0, NULL)) { + fprintf (stderr, "%s: Unknown DWrite error HRESULT=0x%08lx\n", context, (unsigned long)hr); + } else { + fprintf (stderr, "%s: %S\n", context, (wchar_t *)lpMsgBuf); + LocalFree (lpMsgBuf); + } + fflush (stderr); + + return (cairo_int_status_t)_cairo_error (CAIRO_STATUS_DWRITE_ERROR); +} + +class D2DFactory +{ +public: + static RefPtr Instance() + { + if (!mFactoryInstance) { +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-function-type" +#endif + HMODULE d2d1 = _cairo_win32_load_library_from_system32 (L"d2d1.dll"); + D2D1CreateFactoryFunc createD2DFactory = (D2D1CreateFactoryFunc) + GetProcAddress(d2d1, "D2D1CreateFactory"); +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + if (createD2DFactory) { + D2D1_FACTORY_OPTIONS options; + options.debugLevel = D2D1_DEBUG_LEVEL_NONE; + createD2DFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, + __uuidof(ID2D1Factory), + &options, + (void**)&mFactoryInstance); + } + } + return mFactoryInstance; + } + + static RefPtr Instance4() + { + if (!mFactoryInstance4) { + if (Instance()) { + Instance()->QueryInterface(&mFactoryInstance4); + } + } + return mFactoryInstance4; + } + + static RefPtr RenderTarget() + { + if (!mRenderTarget) { + if (!Instance()) { + return NULL; + } + // Create a DC render target. + D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties( + D2D1_RENDER_TARGET_TYPE_DEFAULT, + D2D1::PixelFormat( + DXGI_FORMAT_B8G8R8A8_UNORM, + D2D1_ALPHA_MODE_PREMULTIPLIED), + 0, + 0, + D2D1_RENDER_TARGET_USAGE_NONE, + D2D1_FEATURE_LEVEL_DEFAULT + ); + + Instance()->CreateDCRenderTarget(&props, &mRenderTarget); + } + return mRenderTarget; + } + +private: + static RefPtr mFactoryInstance; + static RefPtr mFactoryInstance4; + static RefPtr mRenderTarget; +}; + +class WICImagingFactory +{ +public: + static RefPtr Instance() + { + if (!mFactoryInstance) { + CoInitialize(NULL); + CoCreateInstance(CLSID_WICImagingFactory, + NULL, + CLSCTX_INPROC_SERVER, + IID_PPV_ARGS(&mFactoryInstance)); + } + return mFactoryInstance; + } +private: + static RefPtr mFactoryInstance; +}; + + +RefPtr DWriteFactory::mFactoryInstance; +RefPtr DWriteFactory::mFactoryInstance1; +RefPtr DWriteFactory::mFactoryInstance2; +RefPtr DWriteFactory::mFactoryInstance3; +RefPtr DWriteFactory::mFactoryInstance4; + +RefPtr WICImagingFactory::mFactoryInstance; +RefPtr DWriteFactory::mSystemCollection; +RefPtr DWriteFactory::mDefaultRenderingParams; + +RefPtr D2DFactory::mFactoryInstance; +RefPtr D2DFactory::mRenderTarget; + +static RefPtr +_create_rendering_params(IDWriteRenderingParams *params, + const cairo_font_options_t *options, + cairo_antialias_t antialias) +{ + if (!params) + params = DWriteFactory::DefaultRenderingParams(); + FLOAT gamma = params->GetGamma(); + FLOAT enhanced_contrast = params->GetEnhancedContrast(); + FLOAT clear_type_level = params->GetClearTypeLevel(); + DWRITE_PIXEL_GEOMETRY pixel_geometry = params->GetPixelGeometry(); + DWRITE_RENDERING_MODE rendering_mode = params->GetRenderingMode(); + + cairo_bool_t modified = FALSE; + switch (antialias) { + case CAIRO_ANTIALIAS_NONE: + if (rendering_mode != DWRITE_RENDERING_MODE_ALIASED) { + rendering_mode = DWRITE_RENDERING_MODE_ALIASED; + modified = TRUE; + } + break; + case CAIRO_ANTIALIAS_FAST: + case CAIRO_ANTIALIAS_GRAY: + if (clear_type_level) { + clear_type_level = 0; + modified = TRUE; + } + break; + default: + break; + } + auto subpixel_order = cairo_font_options_get_subpixel_order (options); + switch (subpixel_order) { + case CAIRO_SUBPIXEL_ORDER_RGB: + if (pixel_geometry != DWRITE_PIXEL_GEOMETRY_RGB) { + pixel_geometry = DWRITE_PIXEL_GEOMETRY_RGB; + modified = TRUE; + } + break; + case CAIRO_SUBPIXEL_ORDER_BGR: + if (pixel_geometry != DWRITE_PIXEL_GEOMETRY_BGR) { + pixel_geometry = DWRITE_PIXEL_GEOMETRY_BGR; + modified = TRUE; + } + break; + default: + break; + } + if (!modified) + return params; + + HRESULT hr; + RefPtr params1; + hr = params->QueryInterface(¶ms1); + if (FAILED(hr)) { + RefPtr ret; + DWriteFactory::Instance()->CreateCustomRenderingParams(gamma, enhanced_contrast, clear_type_level, pixel_geometry, rendering_mode, &ret); + return ret; + } + + FLOAT grayscaleEnhancedContrast = params1->GetGrayscaleEnhancedContrast(); + RefPtr params2; + hr = params->QueryInterface(¶ms2); + if (FAILED(hr)) { + RefPtr ret; + DWriteFactory::Instance1()->CreateCustomRenderingParams(gamma, enhanced_contrast, grayscaleEnhancedContrast, clear_type_level, pixel_geometry, rendering_mode, &ret); + return ret; + } + + DWRITE_GRID_FIT_MODE gridFitMode = params2->GetGridFitMode(); + RefPtr params3; + hr = params->QueryInterface(¶ms3); + if (FAILED(hr)) { + RefPtr ret; + DWriteFactory::Instance2()->CreateCustomRenderingParams(gamma, enhanced_contrast, grayscaleEnhancedContrast, clear_type_level, pixel_geometry, rendering_mode, gridFitMode, &ret); + return ret; + } + + DWRITE_RENDERING_MODE1 rendering_mode1 = params3->GetRenderingMode1(); + if (antialias == CAIRO_ANTIALIAS_NONE) + rendering_mode1 = DWRITE_RENDERING_MODE1_ALIASED; + RefPtr ret; + DWriteFactory::Instance3()->CreateCustomRenderingParams(gamma, enhanced_contrast, grayscaleEnhancedContrast, clear_type_level, pixel_geometry, rendering_mode1, gridFitMode, &ret); + return ret; +} + +/* Functions #cairo_font_face_backend_t */ +static cairo_status_t +_cairo_dwrite_font_face_create_for_toy (cairo_toy_font_face_t *toy_face, + cairo_font_face_t **font_face); +static cairo_bool_t +_cairo_dwrite_font_face_destroy (void *font_face); + +static cairo_status_t +_cairo_dwrite_font_face_scaled_font_create (void *abstract_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **font); + +const cairo_font_face_backend_t _cairo_dwrite_font_face_backend = { + CAIRO_FONT_TYPE_DWRITE, + _cairo_dwrite_font_face_create_for_toy, + _cairo_dwrite_font_face_destroy, + _cairo_dwrite_font_face_scaled_font_create +}; + +/* Functions #cairo_scaled_font_backend_t */ + +static void _cairo_dwrite_scaled_font_fini(void *scaled_font); + +static cairo_warn cairo_int_status_t +_cairo_dwrite_scaled_glyph_init(void *scaled_font, + cairo_scaled_glyph_t *scaled_glyph, + cairo_scaled_glyph_info_t info, + const cairo_color_t *foreground_color); + +static cairo_int_status_t +_cairo_dwrite_load_truetype_table(void *scaled_font, + unsigned long tag, + long offset, + unsigned char *buffer, + unsigned long *length); + +static unsigned long +_cairo_dwrite_ucs4_to_index(void *scaled_font, + uint32_t ucs4); + +static cairo_int_status_t +_cairo_dwrite_is_synthetic(void *scaled_font, + cairo_bool_t *is_synthetic); + +static cairo_bool_t +_cairo_dwrite_has_color_glyphs(void *scaled_font); + +static const cairo_scaled_font_backend_t _cairo_dwrite_scaled_font_backend = { + CAIRO_FONT_TYPE_DWRITE, + _cairo_dwrite_scaled_font_fini, + _cairo_dwrite_scaled_glyph_init, + NULL, /* text_to_glyphs */ + _cairo_dwrite_ucs4_to_index, + _cairo_dwrite_load_truetype_table, + NULL, /* index_to_ucs4 */ + _cairo_dwrite_is_synthetic, + NULL, /* index_to_glyph_name */ + NULL, /* load_type1_data */ + _cairo_dwrite_has_color_glyphs +}; + +/* Helper conversion functions */ + + +/** + * _cairo_dwrite_matrix_from_matrix: + * Get a DirectWrite matrix from a cairo matrix. Note that DirectWrite uses row + * vectors where cairo uses column vectors. Hence the transposition. + * + * \param Cairo matrix + * \return DirectWrite matrix + **/ +static DWRITE_MATRIX +_cairo_dwrite_matrix_from_matrix(const cairo_matrix_t *matrix) +{ + DWRITE_MATRIX dwmat; + dwmat.m11 = (FLOAT)matrix->xx; + dwmat.m12 = (FLOAT)matrix->yx; + dwmat.m21 = (FLOAT)matrix->xy; + dwmat.m22 = (FLOAT)matrix->yy; + dwmat.dx = (FLOAT)matrix->x0; + dwmat.dy = (FLOAT)matrix->y0; + return dwmat; +} + +/* Helper functions for cairo_dwrite_scaled_glyph_init() */ +static cairo_int_status_t +_cairo_dwrite_scaled_font_init_glyph_metrics + (cairo_dwrite_scaled_font_t *scaled_font, cairo_scaled_glyph_t *scaled_glyph); + +static cairo_int_status_t +_cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph, + const cairo_color_t *foreground_color); + +static cairo_int_status_t +_cairo_dwrite_scaled_font_init_glyph_surface + (cairo_dwrite_scaled_font_t *scaled_font, cairo_scaled_glyph_t *scaled_glyph); + +static cairo_int_status_t +_cairo_dwrite_scaled_font_init_glyph_path + (cairo_dwrite_scaled_font_t *scaled_font, cairo_scaled_glyph_t *scaled_glyph); + +/* implement the font backend interface */ + +static cairo_status_t +_cairo_dwrite_font_face_create_for_toy (cairo_toy_font_face_t *toy_face, + cairo_font_face_t **font_face) +{ + WCHAR *face_name; + int face_name_len; + + if (!DWriteFactory::Instance()) { + return (cairo_status_t)CAIRO_INT_STATUS_UNSUPPORTED; + } + + face_name_len = MultiByteToWideChar(CP_UTF8, 0, toy_face->family, -1, NULL, 0); + face_name = new WCHAR[face_name_len]; + MultiByteToWideChar(CP_UTF8, 0, toy_face->family, -1, face_name, face_name_len); + + RefPtr family = DWriteFactory::FindSystemFontFamily(face_name); + delete[] face_name; + if (!family) { + /* If the family is not found, use the default that should always exist. */ + face_name_len = MultiByteToWideChar(CP_UTF8, 0, CAIRO_FONT_FAMILY_DEFAULT, -1, NULL, 0); + face_name = new WCHAR[face_name_len]; + MultiByteToWideChar(CP_UTF8, 0, CAIRO_FONT_FAMILY_DEFAULT, -1, face_name, face_name_len); + + family = DWriteFactory::FindSystemFontFamily(face_name); + delete[] face_name; + if (!family) { + *font_face = (cairo_font_face_t*)&_cairo_font_face_nil; + return (cairo_status_t)CAIRO_INT_STATUS_UNSUPPORTED; + } + } + + DWRITE_FONT_WEIGHT weight; + switch (toy_face->weight) { + case CAIRO_FONT_WEIGHT_BOLD: + weight = DWRITE_FONT_WEIGHT_BOLD; + break; + case CAIRO_FONT_WEIGHT_NORMAL: + default: + weight = DWRITE_FONT_WEIGHT_NORMAL; + break; + } + + DWRITE_FONT_STYLE style; + switch (toy_face->slant) { + case CAIRO_FONT_SLANT_ITALIC: + style = DWRITE_FONT_STYLE_ITALIC; + break; + case CAIRO_FONT_SLANT_OBLIQUE: + style = DWRITE_FONT_STYLE_OBLIQUE; + break; + case CAIRO_FONT_SLANT_NORMAL: + default: + style = DWRITE_FONT_STYLE_NORMAL; + break; + } + + RefPtr font; + HRESULT hr = family->GetFirstMatchingFont(weight, DWRITE_FONT_STRETCH_NORMAL, style, &font); + if (FAILED(hr)) + return (cairo_status_t)_cairo_dwrite_error (hr, "GetFirstMatchingFont failed"); + + RefPtr dwriteface; + hr = font->CreateFontFace(&dwriteface); + if (FAILED(hr)) + return (cairo_status_t)_cairo_dwrite_error (hr, "CreateFontFace failed"); + + *font_face = cairo_dwrite_font_face_create_for_dwrite_fontface(dwriteface); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_bool_t +_cairo_dwrite_font_face_destroy (void *font_face) +{ + cairo_dwrite_font_face_t *dwrite_font_face = static_cast(font_face); + if (dwrite_font_face->dwriteface) + dwrite_font_face->dwriteface->Release(); + if (dwrite_font_face->rendering_params) + dwrite_font_face->rendering_params->Release(); + return TRUE; +} + +static inline unsigned short +read_short(const char *buf) +{ + return be16_to_cpu(*(unsigned short*)buf); +} + +void +_cairo_dwrite_glyph_run_from_glyphs(cairo_glyph_t *glyphs, + int num_glyphs, + cairo_dwrite_scaled_font_t *scaled_font, + AutoDWriteGlyphRun *run, + cairo_bool_t *transformed) +{ + run->allocate(num_glyphs); + + UINT16 *indices = const_cast(run->glyphIndices); + FLOAT *advances = const_cast(run->glyphAdvances); + DWRITE_GLYPH_OFFSET *offsets = const_cast(run->glyphOffsets); + + run->bidiLevel = 0; + run->fontFace = scaled_font->dwriteface; + run->glyphCount = num_glyphs; + run->isSideways = FALSE; + + if (scaled_font->mat.xy == 0 && scaled_font->mat.yx == 0 && + scaled_font->mat.xx == scaled_font->base.font_matrix.xx && + scaled_font->mat.yy == scaled_font->base.font_matrix.yy) { + // Fast route, don't actually use a transform but just + // set the correct font size. + *transformed = 0; + + run->fontEmSize = (FLOAT)scaled_font->base.font_matrix.yy; + + for (int i = 0; i < num_glyphs; i++) { + indices[i] = (WORD) glyphs[i].index; + + offsets[i].ascenderOffset = -(FLOAT)(glyphs[i].y); + offsets[i].advanceOffset = (FLOAT)(glyphs[i].x); + advances[i] = 0.0; + } + } else { + *transformed = 1; + // Transforming positions by the inverse matrix, then by the original + // matrix later may introduce small errors, especially because the + // D2D matrix is single-precision whereas the cairo one is double. + // This is a problem when glyph positions were originally at exactly + // half-pixel locations, which eventually round to whole pixels for + // GDI rendering - the errors introduced here cause them to round in + // unpredictable directions, instead of all rounding in a consistent + // way, leading to poor glyph spacing (bug 675383). + // To mitigate this, nudge the positions by a tiny amount to try and + // ensure that after the two transforms, they'll still round in a + // consistent direction. + const double EPSILON = 0.0001; + for (int i = 0; i < num_glyphs; i++) { + indices[i] = (WORD) glyphs[i].index; + double x = glyphs[i].x + EPSILON; + double y = glyphs[i].y; + cairo_matrix_transform_point(&scaled_font->mat_inverse, &x, &y); + // Since we will multiply by our ctm matrix later for rotation effects + // and such, adjust positions by the inverse matrix now. Y-axis is + // inverted! Therefor the offset is -y. + offsets[i].ascenderOffset = -(FLOAT)y; + offsets[i].advanceOffset = (FLOAT)x; + advances[i] = 0.0; + } + // The font matrix takes care of the scaling if we have a transform, + // emSize should be 1. + run->fontEmSize = 1.0f; + } +} + +#define GASP_TAG 0x70736167 +#define GASP_DOGRAY 0x2 + +static cairo_bool_t +do_grayscale(IDWriteFontFace *dwface, unsigned int ppem) +{ + void *tableContext; + char *tableData; + UINT32 tableSize; + BOOL exists; + dwface->TryGetFontTable(GASP_TAG, (const void**)&tableData, &tableSize, &tableContext, &exists); + + if (exists) { + if (tableSize < 4) { + dwface->ReleaseFontTable(tableContext); + return true; + } + struct gaspRange { + unsigned short maxPPEM; // Stored big-endian + unsigned short behavior; // Stored big-endian + }; + unsigned short numRanges = read_short(tableData + 2); + if (tableSize < (UINT)4 + numRanges * 4) { + dwface->ReleaseFontTable(tableContext); + return true; + } + gaspRange *ranges = (gaspRange *)(tableData + 4); + for (int i = 0; i < numRanges; i++) { + if (be16_to_cpu(ranges[i].maxPPEM) > ppem) { + if (!(be16_to_cpu(ranges[i].behavior) & GASP_DOGRAY)) { + dwface->ReleaseFontTable(tableContext); + return false; + } + break; + } + } + dwface->ReleaseFontTable(tableContext); + } + return true; +} + +static void +set_dwrite_axes_from_string (const char *string, + DWRITE_FONT_AXIS_VALUE *dwrite_axes, + UINT32 count) +{ + const char *p = string; + + while (p && *p) { + const char *start; + const char *end, *end2; + DWRITE_FONT_AXIS_TAG tag; + double value; + + while (_cairo_isspace (*p)) p++; + + start = p; + end = strchr (p, ','); + if (end && (end - p < 6)) + goto skip; + + tag = DWRITE_MAKE_FONT_AXIS_TAG (p[0], p[1], p[2], p[3]); + + p += 4; + while (_cairo_isspace (*p)) p++; + if (*p == '=') p++; + + if (p - start < 5) + goto skip; + + value = _cairo_strtod (p, (char **) &end2); + + while (end2 && _cairo_isspace (*end2)) end2++; + + if (end2 && (*end2 != ',' && *end2 != '\0')) + goto skip; + + for (UINT32 i = 0; i < count; i++) { + if (dwrite_axes[i].axisTag == tag) { + dwrite_axes[i].value = value; + break; + } + } + +skip: + p = end ? end + 1 : NULL; + } +} + +static cairo_status_t +_cairo_dwrite_font_face_scaled_font_create (void *abstract_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **font) +{ + cairo_status_t status; + cairo_dwrite_font_face_t *font_face = static_cast(abstract_face); + + /* Must do malloc and not C++ new, since Cairo frees this. */ + cairo_dwrite_scaled_font_t *dwrite_font = (cairo_dwrite_scaled_font_t*)_cairo_calloc( + sizeof(cairo_dwrite_scaled_font_t)); + if (unlikely(dwrite_font == NULL)) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + *font = reinterpret_cast(dwrite_font); + status = _cairo_scaled_font_init (&dwrite_font->base, + &font_face->base, + font_matrix, + ctm, + options, + &_cairo_dwrite_scaled_font_backend); + if (status) { + free(dwrite_font); + return status; + } + + if (options->variations) { + RefPtr dwriteface5; + + /* Since Windows 10 20348 */ + if (SUCCEEDED (font_face->dwriteface->QueryInterface(&dwriteface5))) { + RefPtr dwritefontresource; + + if (dwriteface5->HasVariations () && + SUCCEEDED (dwriteface5->GetFontResource (&dwritefontresource))) + { + UINT32 count = MIN (dwriteface5->GetFontAxisValueCount (), 500); + DWRITE_FONT_AXIS_VALUE *dwrite_axes = new DWRITE_FONT_AXIS_VALUE[count]; + UINT32 variables_count = 0; + + /* Sort variable axes first */ + for (UINT32 i = 0; i < count; i++) { + if (dwritefontresource->GetFontAxisAttributes (i) & DWRITE_FONT_AXIS_ATTRIBUTES_VARIABLE) { + if (variables_count != i) { + DWRITE_FONT_AXIS_VALUE swap_aux = dwrite_axes[variables_count]; + dwrite_axes[variables_count] = dwrite_axes[i]; + dwrite_axes[i] = swap_aux; + } + + variables_count++; + } + } + + if (SUCCEEDED (dwriteface5->GetFontAxisValues(dwrite_axes, count))) { + RefPtr dwriteface_new5; + + set_dwrite_axes_from_string (options->variations, dwrite_axes, variables_count); + + /* Can't use constexpr with mingw-w64 headers */ + const DWRITE_FONT_SIMULATIONS all_simulations = DWRITE_FONT_SIMULATIONS_BOLD | + DWRITE_FONT_SIMULATIONS_OBLIQUE; + if (SUCCEEDED (dwritefontresource->CreateFontFace(all_simulations, + dwrite_axes, + count, + &dwriteface_new5))) + { + dwrite_font->dwriteface = dwriteface_new5.forget().drop(); + } + } + + delete[] dwrite_axes; + } + } + } + + if (!dwrite_font->dwriteface) { + font_face->dwriteface->AddRef (); + dwrite_font->dwriteface = font_face->dwriteface; + } + + dwrite_font->mat = dwrite_font->base.ctm; + cairo_matrix_multiply(&dwrite_font->mat, &dwrite_font->mat, font_matrix); + dwrite_font->mat_inverse = dwrite_font->mat; + cairo_matrix_invert (&dwrite_font->mat_inverse); + + cairo_font_extents_t extents; + + DWRITE_FONT_METRICS metrics; + if (dwrite_font->measuring_mode == DWRITE_MEASURING_MODE_GDI_CLASSIC || + dwrite_font->measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL) { + DWRITE_MATRIX transform = _cairo_dwrite_matrix_from_matrix (&dwrite_font->mat); + dwrite_font->dwriteface->GetGdiCompatibleMetrics(1, 1, &transform, &metrics); + } else { + dwrite_font->dwriteface->GetMetrics(&metrics); + } + + extents.ascent = (FLOAT)metrics.ascent / metrics.designUnitsPerEm; + extents.descent = (FLOAT)metrics.descent / metrics.designUnitsPerEm; + extents.height = (FLOAT)(metrics.ascent + metrics.descent + metrics.lineGap) / metrics.designUnitsPerEm; + extents.max_x_advance = 14.0; + extents.max_y_advance = 0.0; + + cairo_antialias_t default_quality = CAIRO_ANTIALIAS_SUBPIXEL; + + // The following code detects the system quality at scaled_font creation time, + // this means that if cleartype settings are changed but the scaled_fonts + // are re-used, they might not adhere to the new system setting until re- + // creation. + switch (cairo_win32_get_system_text_quality()) { + case CLEARTYPE_QUALITY: + default_quality = CAIRO_ANTIALIAS_SUBPIXEL; + break; + case ANTIALIASED_QUALITY: + default_quality = CAIRO_ANTIALIAS_GRAY; + break; + case DEFAULT_QUALITY: + // _get_system_quality() seems to think aliased is default! + default_quality = CAIRO_ANTIALIAS_NONE; + break; + } + + if (default_quality == CAIRO_ANTIALIAS_GRAY) { + if (!do_grayscale(dwrite_font->dwriteface, (unsigned int)_cairo_round(font_matrix->yy))) { + default_quality = CAIRO_ANTIALIAS_NONE; + } + } + + if (options->antialias == CAIRO_ANTIALIAS_DEFAULT) { + dwrite_font->antialias_mode = default_quality; + } else { + dwrite_font->antialias_mode = options->antialias; + } + + dwrite_font->rendering_params = _create_rendering_params(font_face->rendering_params, options, dwrite_font->antialias_mode).forget().drop(); + dwrite_font->measuring_mode = font_face->measuring_mode; + + return _cairo_scaled_font_set_metrics (*font, &extents); +} + +/* Implementation #cairo_dwrite_scaled_font_backend_t */ +static void +_cairo_dwrite_scaled_font_fini(void *scaled_font) +{ + cairo_dwrite_scaled_font_t *dwrite_font = static_cast(scaled_font); + + dwrite_font->dwriteface->Release (); + + if (dwrite_font->rendering_params) + dwrite_font->rendering_params->Release(); +} + +static cairo_int_status_t +_cairo_dwrite_scaled_glyph_init(void *scaled_font, + cairo_scaled_glyph_t *scaled_glyph, + cairo_scaled_glyph_info_t info, + const cairo_color_t *foreground_color) +{ + cairo_dwrite_scaled_font_t *scaled_dwrite_font = static_cast(scaled_font); + cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED; + + if ((info & CAIRO_SCALED_GLYPH_INFO_METRICS) != 0) { + status = _cairo_dwrite_scaled_font_init_glyph_metrics (scaled_dwrite_font, scaled_glyph); + if (status) + return status; + } + + if (info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) { + status = _cairo_dwrite_scaled_font_init_glyph_color_surface (scaled_dwrite_font, scaled_glyph, foreground_color); + if (status) + return status; + } + + if (info & CAIRO_SCALED_GLYPH_INFO_SURFACE) { + status = _cairo_dwrite_scaled_font_init_glyph_surface (scaled_dwrite_font, scaled_glyph); + if (status) + return status; + } + + if ((info & CAIRO_SCALED_GLYPH_INFO_PATH) != 0) { + status = _cairo_dwrite_scaled_font_init_glyph_path (scaled_dwrite_font, scaled_glyph); + if (status) + return status; + } + + return CAIRO_INT_STATUS_SUCCESS; +} + +static unsigned long +_cairo_dwrite_ucs4_to_index(void *scaled_font, + uint32_t ucs4) +{ + cairo_dwrite_scaled_font_t *dwritesf = static_cast(scaled_font); + UINT16 index = 0; + + dwritesf->dwriteface->GetGlyphIndicesA(&ucs4, 1, &index); + return index; +} + +/* cairo_dwrite_scaled_glyph_init() helper function bodies */ +static cairo_int_status_t +_cairo_dwrite_scaled_font_init_glyph_metrics(cairo_dwrite_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph) +{ + UINT16 charIndex = (UINT16)_cairo_scaled_glyph_index (scaled_glyph); + cairo_dwrite_font_face_t *font_face = (cairo_dwrite_font_face_t*)scaled_font->base.font_face; + cairo_text_extents_t extents; + + DWRITE_GLYPH_METRICS metrics; + DWRITE_FONT_METRICS fontMetrics; + HRESULT hr; + if (font_face->measuring_mode == DWRITE_MEASURING_MODE_GDI_CLASSIC || + font_face->measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL) { + DWRITE_MATRIX transform = _cairo_dwrite_matrix_from_matrix (&scaled_font->mat); + scaled_font->dwriteface->GetGdiCompatibleMetrics(1, 1, &transform, &fontMetrics); + BOOL natural = font_face->measuring_mode == DWRITE_MEASURING_MODE_GDI_NATURAL; + hr = scaled_font->dwriteface->GetGdiCompatibleGlyphMetrics (1, 1, &transform, natural, &charIndex, 1, &metrics, FALSE); + } else { + scaled_font->dwriteface->GetMetrics(&fontMetrics); + hr = scaled_font->dwriteface->GetDesignGlyphMetrics(&charIndex, 1, &metrics); + } + if (FAILED(hr)) { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + // GetGdiCompatibleMetrics may return a glyph metrics that yields a small nagative glyph height. + INT32 glyph_width = metrics.advanceWidth - metrics.leftSideBearing - metrics.rightSideBearing; + INT32 glyph_height = metrics.advanceHeight - metrics.topSideBearing - metrics.bottomSideBearing; + glyph_width = MAX(glyph_width, 0); + glyph_height = MAX(glyph_height, 0); + + // TODO: Treat swap_xy. + extents.width = (FLOAT)glyph_width / fontMetrics.designUnitsPerEm; + extents.height = (FLOAT)glyph_height / fontMetrics.designUnitsPerEm; + extents.x_advance = (FLOAT)metrics.advanceWidth / fontMetrics.designUnitsPerEm; + extents.x_bearing = (FLOAT)metrics.leftSideBearing / fontMetrics.designUnitsPerEm; + extents.y_advance = 0.0; + extents.y_bearing = (FLOAT)(metrics.topSideBearing - metrics.verticalOriginY) / + fontMetrics.designUnitsPerEm; + + // We pad the extents here because GetDesignGlyphMetrics returns "ideal" metrics + // for the glyph outline, without accounting for hinting/gridfitting/antialiasing, + // and therefore it does not always cover all pixels that will actually be touched. + if (extents.width > 0 && extents.height > 0) { + double x = 1, y = 1; + cairo_matrix_transform_distance (&scaled_font->mat_inverse, &x, &y); + x = fabs(x); + y = fabs(y); + extents.width += x * 2; + extents.x_bearing -= x; + extents.height += y * 2; + extents.y_bearing -= y; + } + + _cairo_scaled_glyph_set_metrics (scaled_glyph, + &scaled_font->base, + &extents); + return CAIRO_INT_STATUS_SUCCESS; +} + +/* + * Stack-based helper implementing IDWriteGeometrySink. + * Used to determine the path of the glyphs. + */ + +class GeometryRecorder final + : public IDWriteGeometrySink +{ +public: + GeometryRecorder(cairo_path_fixed_t *aCairoPath, const cairo_matrix_t &matrix) + : mCairoPath(aCairoPath) + , mMatrix(matrix) {} + + IFACEMETHOD (QueryInterface)(IID const& iid, OUT void** ppObject) noexcept override + { + if (iid == __uuidof (IUnknown) || + iid == __uuidof (IDWriteGeometrySink)) + { + AddRef(); + *ppObject = this; + return S_OK; + } + + *ppObject = nullptr; + return E_NOINTERFACE; + } + + IFACEMETHOD_(ULONG, AddRef)() noexcept override + { + return 1; + } + + IFACEMETHOD_(ULONG, Release)() noexcept override + { + return 1; + } + + IFACEMETHOD_(void, SetFillMode)(D2D1_FILL_MODE fillMode) noexcept override + { + return; + } + + IFACEMETHOD (Close)() noexcept override + { + return S_OK; + } + + IFACEMETHOD_(void, SetSegmentFlags)(D2D1_PATH_SEGMENT vertexFlags) noexcept override + { + return; + } + + IFACEMETHOD_(void, BeginFigure)( + D2D1_POINT_2F startPoint, + D2D1_FIGURE_BEGIN figureBegin) noexcept override + { + double x = startPoint.x; + double y = startPoint.y; + cairo_matrix_transform_point(&mMatrix, &x, &y); + mStartPointX = _cairo_fixed_from_double(x); + mStartPointY = _cairo_fixed_from_double(y); + cairo_status_t status = _cairo_path_fixed_move_to(mCairoPath, + mStartPointX, + mStartPointY); + (void)status; /* squelch warning */ + } + + IFACEMETHOD_(void, EndFigure)( + D2D1_FIGURE_END figureEnd) noexcept override + { + if (figureEnd == D2D1_FIGURE_END_CLOSED) { + cairo_status_t status = _cairo_path_fixed_line_to(mCairoPath, + mStartPointX, + mStartPointY); + (void)status; /* squelch warning */ + } + } + + IFACEMETHOD_(void, AddBeziers)( + const D2D1_BEZIER_SEGMENT *beziers, + UINT beziersCount) noexcept override + { + for (unsigned int i = 0; i < beziersCount; i++) { + double x1 = beziers[i].point1.x; + double y1 = beziers[i].point1.y; + double x2 = beziers[i].point2.x; + double y2 = beziers[i].point2.y; + double x3 = beziers[i].point3.x; + double y3 = beziers[i].point3.y; + cairo_matrix_transform_point(&mMatrix, &x1, &y1); + cairo_matrix_transform_point(&mMatrix, &x2, &y2); + cairo_matrix_transform_point(&mMatrix, &x3, &y3); + cairo_status_t status = _cairo_path_fixed_curve_to(mCairoPath, + _cairo_fixed_from_double(x1), + _cairo_fixed_from_double(y1), + _cairo_fixed_from_double(x2), + _cairo_fixed_from_double(y2), + _cairo_fixed_from_double(x3), + _cairo_fixed_from_double(y3)); + (void)status; /* squelch warning */ + } + } + + IFACEMETHOD_(void, AddLines)( + const D2D1_POINT_2F *points, + UINT pointsCount) noexcept override + { + for (unsigned int i = 0; i < pointsCount; i++) { + double x = points[i].x; + double y = points[i].y; + cairo_matrix_transform_point(&mMatrix, &x, &y); + cairo_status_t status = _cairo_path_fixed_line_to(mCairoPath, + _cairo_fixed_from_double(x), + _cairo_fixed_from_double(y)); + (void)status; /* squelch warning */ + } + } + +private: + cairo_path_fixed_t *mCairoPath; + const cairo_matrix_t &mMatrix; + cairo_fixed_t mStartPointX; + cairo_fixed_t mStartPointY; +}; + +static cairo_int_status_t +_cairo_dwrite_scaled_font_init_glyph_path(cairo_dwrite_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph) +{ + cairo_int_status_t status; + cairo_path_fixed_t *path; + path = _cairo_path_fixed_create(); + GeometryRecorder recorder(path, scaled_font->base.scale); + + DWRITE_GLYPH_OFFSET offset; + offset.advanceOffset = 0; + offset.ascenderOffset = 0; + UINT16 glyphId = (UINT16)_cairo_scaled_glyph_index(scaled_glyph); + FLOAT advance = 0.0; + + HRESULT hr = scaled_font->dwriteface->GetGlyphRunOutline(1, + &glyphId, + &advance, + &offset, + 1, + FALSE, + FALSE, + &recorder); + if (!SUCCEEDED(hr)) + return _cairo_dwrite_error (hr, "GetGlyphRunOutline failed"); + + status = (cairo_int_status_t)_cairo_path_fixed_close_path(path); + + _cairo_scaled_glyph_set_path (scaled_glyph, + &scaled_font->base, + path); + return status; +} + +static cairo_int_status_t +_cairo_dwrite_scaled_font_init_glyph_color_surface(cairo_dwrite_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph, + const cairo_color_t *foreground_color) +{ + int width, height; + double x1, y1, x2, y2; + cairo_bool_t uses_foreground_color = FALSE; + + cairo_dwrite_font_face_t *dwrite_font_face = (cairo_dwrite_font_face_t *)scaled_font->base.font_face; + if (!dwrite_font_face->have_color) { + scaled_glyph->color_glyph = FALSE; + scaled_glyph->color_glyph_set = TRUE; + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + x1 = _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x); + y1 = _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y); + x2 = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x); + y2 = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y); + width = (int)(x2 - x1); + height = (int)(y2 - y1); + + DWRITE_GLYPH_RUN run; + FLOAT advance = 0; + UINT16 index = (UINT16)_cairo_scaled_glyph_index (scaled_glyph); + DWRITE_GLYPH_OFFSET offset; + double x = -x1 + .25 * _cairo_scaled_glyph_xphase (scaled_glyph); + double y = -y1 + .25 * _cairo_scaled_glyph_yphase (scaled_glyph); + DWRITE_MATRIX matrix; + D2D1_POINT_2F origin = {0, 0}; + RefPtr run_enumerator; + HRESULT hr; + + /* + * We transform by the inverse transformation here. This will put our glyph + * locations in the space in which we draw. Which is later transformed by + * the transformation matrix that we use. This will transform the + * glyph positions back to where they were before when drawing, but the + * glyph shapes will be transformed by the transformation matrix. + */ + cairo_matrix_transform_point(&scaled_font->mat_inverse, &x, &y); + offset.advanceOffset = (FLOAT)x; + /* Y-axis is inverted */ + offset.ascenderOffset = -(FLOAT)y; + + run.fontFace = scaled_font->dwriteface; + run.fontEmSize = 1; + run.glyphCount = 1; + run.glyphIndices = &index; + run.glyphAdvances = &advance; + run.glyphOffsets = &offset; + run.isSideways = FALSE; + run.bidiLevel = 0; + + matrix = _cairo_dwrite_matrix_from_matrix(&scaled_font->mat); + + /* The list of glyph image formats this renderer is prepared to support. */ + DWRITE_GLYPH_IMAGE_FORMATS supported_formats = static_cast( + DWRITE_GLYPH_IMAGE_FORMATS_COLR | + DWRITE_GLYPH_IMAGE_FORMATS_SVG | + DWRITE_GLYPH_IMAGE_FORMATS_PNG | + DWRITE_GLYPH_IMAGE_FORMATS_JPEG | + DWRITE_GLYPH_IMAGE_FORMATS_TIFF | + DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8); + + RefPtr fontFace2; + UINT32 palette_count = 0; + if (SUCCEEDED(scaled_font->dwriteface->QueryInterface(&fontFace2))) + palette_count = fontFace2->GetColorPaletteCount(); + + UINT32 palette_index = CAIRO_COLOR_PALETTE_DEFAULT; + if (scaled_font->base.options.palette_index < palette_count) + palette_index = scaled_font->base.options.palette_index; + + hr = DWriteFactory::Instance4()->TranslateColorGlyphRun( + origin, + &run, + NULL, /* glyphRunDescription */ + supported_formats, + dwrite_font_face->measuring_mode, + &matrix, + palette_index, + &run_enumerator); + + if (hr == DWRITE_E_NOCOLOR) { + /* No color glyphs */ + scaled_glyph->color_glyph = FALSE; + scaled_glyph->color_glyph_set = TRUE; + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + if (FAILED(hr)) + return _cairo_dwrite_error (hr, "TranslateColorGlyphRun failed"); + + /* We have a color glyph(s). Use Direct2D to render it to a bitmap */ + if (!WICImagingFactory::Instance() || !D2DFactory::Instance()) + return _cairo_dwrite_error (hr, "Instance failed"); + + RefPtr bitmap; + hr = WICImagingFactory::Instance()->CreateBitmap ((UINT)width, + (UINT)height, + GUID_WICPixelFormat32bppPBGRA, + WICBitmapCacheOnLoad, + &bitmap); + if (FAILED(hr)) + return _cairo_dwrite_error (hr, "CreateBitmap failed"); + + D2D1_RENDER_TARGET_PROPERTIES properties = D2D1::RenderTargetProperties( + D2D1_RENDER_TARGET_TYPE_DEFAULT, + D2D1::PixelFormat( + DXGI_FORMAT_B8G8R8A8_UNORM, + D2D1_ALPHA_MODE_PREMULTIPLIED), + 0, + 0, + D2D1_RENDER_TARGET_USAGE_NONE, + D2D1_FEATURE_LEVEL_DEFAULT); + + RefPtr rt; + hr = D2DFactory::Instance()->CreateWicBitmapRenderTarget (bitmap, properties, &rt); + if (FAILED(hr)) + return _cairo_dwrite_error (hr, "CreateWicBitmapRenderTarget failed"); + + RefPtr dc4; + hr = rt->QueryInterface(&dc4); + if (FAILED(hr)) + return _cairo_dwrite_error (hr, "QueryInterface(&dc4) failed"); + + RefPtr foreground_color_brush; + dc4->CreateSolidColorBrush( + D2D1::ColorF(foreground_color->red, + foreground_color->green, + foreground_color->blue, + foreground_color->alpha), &foreground_color_brush); + + RefPtr color_brush; + dc4->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black), &color_brush); + + dc4->SetDpi(96, 96); /* 1 unit = 1 pixel */ + rt->SetTransform(D2D1::Matrix3x2F(matrix.m11, + matrix.m12, + matrix.m21, + matrix.m22, + matrix.dx, + matrix.dy)); + + dc4->BeginDraw(); + dc4->Clear(NULL); /* Transparent black */ + + while (true) { + BOOL have_run; + hr = run_enumerator->MoveNext(&have_run); + if (FAILED(hr) || !have_run) + break; + + DWRITE_COLOR_GLYPH_RUN1_WORKAROUND const* color_run; + hr = run_enumerator->GetCurrentRun(reinterpret_cast(&color_run)); + if (FAILED(hr)) + return _cairo_dwrite_error (hr, "GetCurrentRun failed"); + + switch (color_run->glyphImageFormat) { + case DWRITE_GLYPH_IMAGE_FORMATS_PNG: + case DWRITE_GLYPH_IMAGE_FORMATS_JPEG: + case DWRITE_GLYPH_IMAGE_FORMATS_TIFF: + case DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8: + /* Bitmap glyphs */ + dc4->DrawColorBitmapGlyphRun(color_run->glyphImageFormat, + origin, + &color_run->glyphRun, + dwrite_font_face->measuring_mode, + D2D1_COLOR_BITMAP_GLYPH_SNAP_OPTION_DEFAULT); + break; + + case DWRITE_GLYPH_IMAGE_FORMATS_SVG: + /* SVG glyphs */ + dc4->DrawSvgGlyphRun(origin, + &color_run->glyphRun, + foreground_color_brush, + nullptr, + palette_index, + dwrite_font_face->measuring_mode); + uses_foreground_color = TRUE; + break; + case DWRITE_GLYPH_IMAGE_FORMATS_TRUETYPE: + case DWRITE_GLYPH_IMAGE_FORMATS_CFF: + case DWRITE_GLYPH_IMAGE_FORMATS_COLR: + /* Outline glyphs */ + if (color_run->paletteIndex == 0xFFFF) { + D2D1_COLOR_F color = foreground_color_brush->GetColor(); + color_brush->SetColor(&color); + uses_foreground_color = TRUE; + } else { + double red, green, blue, alpha; + cairo_status_t status; + status = cairo_font_options_get_custom_palette_color (&scaled_font->base.options, + color_run->paletteIndex, + &red, &blue, &green, &alpha); + if (status == CAIRO_STATUS_SUCCESS) { + color_brush->SetColor(D2D1::ColorF(red, blue, green, alpha)); + } else { + color_brush->SetColor(color_run->runColor); + } + } + + dc4->DrawGlyphRun(origin, + &color_run->glyphRun, + color_run->glyphRunDescription, + color_brush, + dwrite_font_face->measuring_mode); + case DWRITE_GLYPH_IMAGE_FORMATS_NONE: + break; + } + } + + hr = dc4->EndDraw(); + if (FAILED(hr)) + return _cairo_dwrite_error (hr, "EndDraw failed"); + + cairo_surface_t *image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); + int stride = cairo_image_surface_get_stride (image); + WICRect rect = { 0, 0, width, height }; + bitmap->CopyPixels(&rect, + stride, + height * stride, + cairo_image_surface_get_data (image)); + cairo_surface_mark_dirty (image); + cairo_surface_set_device_offset (image, -x1, -y1); + _cairo_scaled_glyph_set_color_surface (scaled_glyph, + &scaled_font->base, + (cairo_image_surface_t *) image, + uses_foreground_color ? foreground_color : NULL); + scaled_glyph->color_glyph = TRUE; + scaled_glyph->color_glyph_set = TRUE; + + return CAIRO_INT_STATUS_SUCCESS; +} + +// Helper for OS versions up to Windows 8 +static cairo_int_status_t +init_glyph_surface_fallback_a8 (cairo_dwrite_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph, + int width, + int height, + double x1, + double y1, + DWRITE_MATRIX *matrix, + DWRITE_GLYPH_RUN *run) +{ + RefPtr bitmap; + HRESULT hr; + + hr = WICImagingFactory::Instance()->CreateBitmap ((UINT)width, + (UINT)height, + GUID_WICPixelFormat8bppAlpha, + WICBitmapCacheOnLoad, + &bitmap); + if (FAILED(hr)) + return _cairo_dwrite_error (hr, "CreateBitmap failed"); + + D2D1_RENDER_TARGET_PROPERTIES properties = D2D1::RenderTargetProperties( + D2D1_RENDER_TARGET_TYPE_DEFAULT, + D2D1::PixelFormat( + DXGI_FORMAT_A8_UNORM, + D2D1_ALPHA_MODE_PREMULTIPLIED), + 0, + 0, + D2D1_RENDER_TARGET_USAGE_NONE, + D2D1_FEATURE_LEVEL_DEFAULT); + + RefPtr rt; + hr = D2DFactory::Instance()->CreateWicBitmapRenderTarget (bitmap, properties, &rt); + if (FAILED(hr)) + return _cairo_dwrite_error (hr, "CreateWicBitmapRenderTarget failed"); + + RefPtr brush; + hr = rt->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black, 1.0), &brush); + + rt->BeginDraw(); + + rt->SetTransform(*(D2D1_MATRIX_3X2_F*)matrix); + + rt->DrawGlyphRun({0, 0}, run, brush, scaled_font->measuring_mode); + + hr = rt->EndDraw(); + if (FAILED(hr)) + return _cairo_dwrite_error (hr, "EndDraw failed"); + + // TODO: rt->Flush()? + + cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_A8, width, height); + if (cairo_surface_status (surface)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + // Tell pixman that it should use component alpha blending when the surface is + // used as a source + pixman_image_set_component_alpha (((cairo_image_surface_t*)surface)->pixman_image, TRUE); + + int stride = cairo_image_surface_get_stride (surface); + WICRect rect = { 0, 0, width, height }; + bitmap->CopyPixels(&rect, + stride, + height * stride, + cairo_image_surface_get_data (surface)); + cairo_surface_mark_dirty (surface); + cairo_surface_set_device_offset (surface, -x1, -y1); + _cairo_scaled_glyph_set_surface (scaled_glyph, + &scaled_font->base, + (cairo_image_surface_t*)surface); + + return CAIRO_INT_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_dwrite_scaled_font_init_glyph_surface (cairo_dwrite_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph) +{ + HRESULT hr; + + double x1 = _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x); + double y1 = _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y); + double x2 = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x); + double y2 = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y); + int width = (int)(x2 - x1); + int height = (int)(y2 - y1); + + if (width <= 0) + width = 1; + if (height <= 0) + height = 1; + + FLOAT advance = 0; + UINT16 index = (UINT16)_cairo_scaled_glyph_index (scaled_glyph); + DWRITE_GLYPH_OFFSET offset; + double x = -x1 + .25 * _cairo_scaled_glyph_xphase (scaled_glyph); + double y = -y1 + .25 * _cairo_scaled_glyph_yphase (scaled_glyph); + + /* We transform by the inverse transformation here. This will put our glyph + * locations in the space in which we draw. Which is later transformed by + * the transformation matrix that we use. This will transform the + * glyph positions back to where they were before when drawing, but the + * glyph shapes will be transformed by the transformation matrix. */ + cairo_matrix_transform_point(&scaled_font->mat_inverse, &x, &y); + offset.advanceOffset = (FLOAT)x; + offset.ascenderOffset = -(FLOAT)y; /* Y axis is inverted */ + + DWRITE_MATRIX matrix = _cairo_dwrite_matrix_from_matrix(&scaled_font->mat); + + DWRITE_GLYPH_RUN run; + run.glyphCount = 1; + run.glyphAdvances = &advance; + run.fontFace = scaled_font->dwriteface; + run.fontEmSize = 1.0f; + run.bidiLevel = 0; + run.glyphIndices = &index; + run.isSideways = FALSE; + run.glyphOffsets = &offset; + + // Reduce the many Cairo antialias values to the + // three we actually care about: NONE, GRAY, RGB + enum { + ANTIALIAS_NONE, + ANTIALIAS_GRAY, + ANTIALIAS_CLEARTYPE, + } antialias = ANTIALIAS_CLEARTYPE; + + switch (scaled_font->antialias_mode) { + case CAIRO_ANTIALIAS_NONE: + antialias = ANTIALIAS_NONE; + break; + case CAIRO_ANTIALIAS_FAST: + case CAIRO_ANTIALIAS_GRAY: + antialias = ANTIALIAS_GRAY; + break; + case CAIRO_ANTIALIAS_DEFAULT: + case CAIRO_ANTIALIAS_GOOD: + case CAIRO_ANTIALIAS_BEST: + case CAIRO_ANTIALIAS_SUBPIXEL: + antialias = ANTIALIAS_CLEARTYPE; + break; + } + + // Set DWrite rendering options + + DWRITE_RENDERING_MODE rendering_mode; + DWRITE_RENDERING_MODE1 rendering_mode1; + DWRITE_TEXT_ANTIALIAS_MODE text_antialias_mode; + DWRITE_TEXTURE_TYPE texture_type; + + switch (antialias) { + case ANTIALIAS_NONE: + rendering_mode1 = DWRITE_RENDERING_MODE1_ALIASED; + rendering_mode = DWRITE_RENDERING_MODE_ALIASED; + text_antialias_mode = DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE; + texture_type = DWRITE_TEXTURE_ALIASED_1x1; + break; + case ANTIALIAS_GRAY: + rendering_mode1 = DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC; + rendering_mode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC; + text_antialias_mode = DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE; + texture_type = DWRITE_TEXTURE_ALIASED_1x1; + break; + case ANTIALIAS_CLEARTYPE: + rendering_mode1 = DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC; + rendering_mode = DWRITE_RENDERING_MODE_NATURAL_SYMMETRIC; + text_antialias_mode = DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE; + texture_type = DWRITE_TEXTURE_CLEARTYPE_3x1; + break; + } + + DWRITE_GRID_FIT_MODE grid_fit_mode = DWRITE_GRID_FIT_MODE_DEFAULT; + + switch (cairo_font_options_get_hint_style (&scaled_font->base.options)) { + case CAIRO_HINT_STYLE_DEFAULT: + grid_fit_mode = DWRITE_GRID_FIT_MODE_DEFAULT; + case CAIRO_HINT_STYLE_NONE: + grid_fit_mode = DWRITE_GRID_FIT_MODE_DISABLED; + case CAIRO_HINT_STYLE_SLIGHT: + case CAIRO_HINT_STYLE_MEDIUM: + case CAIRO_HINT_STYLE_FULL: + grid_fit_mode = DWRITE_GRID_FIT_MODE_ENABLED; + } + + cairo_subpixel_order_t subpixel_order; + subpixel_order = cairo_font_options_get_subpixel_order (&scaled_font->base.options); + + bool subpixel_order_is_vertical = false; + if (antialias == ANTIALIAS_CLEARTYPE) { + switch (subpixel_order) { + case CAIRO_SUBPIXEL_ORDER_DEFAULT: + case CAIRO_SUBPIXEL_ORDER_RGB: + case CAIRO_SUBPIXEL_ORDER_BGR: + break; + case CAIRO_SUBPIXEL_ORDER_VRGB: + case CAIRO_SUBPIXEL_ORDER_VBGR: + subpixel_order_is_vertical = true; + break; + } + } + + if (subpixel_order_is_vertical) { + // DirectWrite does not support vertical pixel geometries. + // As a workaround, apply a simmetry which swaps x and y + // coordinates, then re-swap while copying the back into + // the image surface + + // swap the two rows + std::swap (matrix.m11, matrix.m21); + std::swap (matrix.m12, matrix.m22); + } + + RefPtr dwrite_glyph_run_analysis; + if (DWriteFactory::Instance3()) { + hr = DWriteFactory::Instance3()->CreateGlyphRunAnalysis(&run, + &matrix, + rendering_mode1, + scaled_font->measuring_mode, + grid_fit_mode, + text_antialias_mode, + 0, // baselineOriginX, + 0, // baselineOriginY, + &dwrite_glyph_run_analysis); + } + else if (DWriteFactory::Instance2()) { + hr = DWriteFactory::Instance2()->CreateGlyphRunAnalysis(&run, + &matrix, + rendering_mode, + scaled_font->measuring_mode, + grid_fit_mode, + text_antialias_mode, + 0, // baselineOriginX, + 0, // baselineOriginY, + &dwrite_glyph_run_analysis); + } + else { + if (antialias == ANTIALIAS_GRAY) { + // IDWriteGlyphRunAnalysis supports gray-scale antialiasing only when + // created from IDWriteFactory2 or later. If we have IDWriteFactory + // only, fallback to rendering with Direct2D on A8 targets. + return init_glyph_surface_fallback_a8 (scaled_font, scaled_glyph, + width, height, x1, y1, &matrix, &run); + } + + hr = DWriteFactory::Instance()->CreateGlyphRunAnalysis(&run, 1, + &matrix, + rendering_mode, + scaled_font->measuring_mode, + 0, // baselineOriginX, + 0, // baselineOriginY, + &dwrite_glyph_run_analysis); + } + if (FAILED(hr)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + cairo_format_t surface_format = antialias == ANTIALIAS_NONE ? CAIRO_FORMAT_A1 : + antialias == ANTIALIAS_GRAY ? CAIRO_FORMAT_A8 : + CAIRO_FORMAT_ARGB32; + + cairo_surface_t *surface = cairo_image_surface_create (surface_format, width, height); + if (cairo_surface_status (surface)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + // Tell pixman that it should use component alpha blending when the surface is + // used as a source + pixman_image_set_component_alpha (((cairo_image_surface_t*)surface)->pixman_image, TRUE); + + // That's probably not needed right after creation + cairo_surface_flush (surface); + unsigned char *surface_data = cairo_image_surface_get_data (surface); + int surface_stride = cairo_image_surface_get_stride (surface); + + UINT32 dwrite_data_size; + BYTE *dwrite_data; + RECT dwrite_rect = { + 0, // left + 0, // top + width, // right + height // bottom + }; + + if (subpixel_order_is_vertical) { + std::swap (dwrite_rect.right, + dwrite_rect.bottom); + } + + // Whether IDWriteGlyphRunAnalysis::CreateAlphaTexture() can render directly + // on the cairo image surface (because the pixel formats match) or a separate + // buffer is needed + bool render_is_direct; + + switch (antialias) { + case ANTIALIAS_NONE: + { + dwrite_data_size = width * height; //TODO: check overflow + + dwrite_data = (BYTE*) _cairo_malloc (dwrite_data_size); + if (!dwrite_data) + return CAIRO_INT_STATUS_UNSUPPORTED; + + render_is_direct = false; + break; + } + case ANTIALIAS_GRAY: + { + // The image surface may have a stride that's bigger than width- + // account for that by passing stride as width to DWrite. Note: + // stride is a byte-size, but here pixel-size is exactly 1 byte. + dwrite_rect.right = cairo_image_surface_get_stride (surface); + + dwrite_data_size = dwrite_rect.right * height; //TODO: check overflow + dwrite_data = static_cast(surface_data); + + render_is_direct = true; + break; + } + case ANTIALIAS_CLEARTYPE: + { + dwrite_data_size = 3 * width * height; //TODO: check overflow + + dwrite_data = (BYTE*) _cairo_malloc (dwrite_data_size); + if (!dwrite_data) + return CAIRO_INT_STATUS_UNSUPPORTED; + + render_is_direct = false; + break; + } + } + + hr = dwrite_glyph_run_analysis->CreateAlphaTexture(texture_type, &dwrite_rect, dwrite_data, dwrite_data_size); + if (FAILED (hr)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + // Most of the code here was copied and adapted from cairoft-font.c + switch (antialias) { + case ANTIALIAS_NONE: + { + unsigned char *src = static_cast(dwrite_data); + unsigned char *dst = surface_data; + + for (int i = 0; i < height; i++) { + unsigned char *d = dst; + + for (int j = 0; j < width / 8; j++) { + *d = (src[0] ? (1 << 0) : 0) + + (src[1] ? (1 << 1) : 0) + + (src[2] ? (1 << 2) : 0) + + (src[3] ? (1 << 3) : 0) + + (src[4] ? (1 << 4) : 0) + + (src[5] ? (1 << 5) : 0) + + (src[6] ? (1 << 6) : 0) + + (src[7] ? (1 << 7) : 0); + + d++; + src += 8; + } + + if (width % 8 != 0) { + *d = 0; + + for (int k = 0; k < width % 8; k++) { + *d += (src[k] ? (1 << k) : 0); + } + + d++; + src += (width % 8); + } + + dst += surface_stride; + } + break; + } + case ANTIALIAS_GRAY: + { + // Nothing to do + break; + } + case ANTIALIAS_CLEARTYPE: + { + unsigned char *src = static_cast(dwrite_data); + unsigned char *dst = surface_data; + + // The alpha channel is unused for component-alpha blending. + // Here we set the alpha channel anyway so that things work + // even in case of normal blending (but one likely gets some + // color fringing) + + switch (subpixel_order) { + case CAIRO_SUBPIXEL_ORDER_DEFAULT: + case CAIRO_SUBPIXEL_ORDER_RGB: + { + for (int i = 0; i < height; i++) { + UINT32 *d = reinterpret_cast(dst); + + for (int j = 0; j < width; j++) { + // CAIRO_FORMAT_ARGB32 is BGRA on little-endian + *d = (src[2] << 0) + + (src[1] << 8) + + (src[0] << 16) + + (src[1] << 24); // unused + + d++; + src += 3; + } + + dst += surface_stride; + } + } + break; + case CAIRO_SUBPIXEL_ORDER_BGR: + { + for (int i = 0; i < height; i++) { + UINT32 *d = reinterpret_cast(dst); + + for (int j = 0; j < width; j++) { + *d = (src[0] << 0) + + (src[1] << 8) + + (src[2] << 16) + + (src[1] << 24); // unused + + d++; + src += 3; + } + + dst += surface_stride; + } + } + break; + case CAIRO_SUBPIXEL_ORDER_VRGB: + { + size_t p; + + for (int i = 0; i < height; i++) { + UINT32 *d = reinterpret_cast(dst); + + p = i * 3; + for (int j = 0; j < width; j++) { + *d = (src[p + 2] << 0) + + (src[p + 1] << 8) + + (src[p + 0] << 16) + + (src[p + 1] << 24); // unused + + d++; + p += 3 * height; + } + + dst += surface_stride; + } + } + break; + case CAIRO_SUBPIXEL_ORDER_VBGR: + { + size_t p; + + for (int i = 0; i < height; i++) { + UINT32 *d = reinterpret_cast(dst); + + p = i * 3; + for (int j = 0; j < width; j++) { + *d = (src[p + 0] << 0) + + (src[p + 1] << 8) + + (src[p + 2] << 16) + + (src[p + 1] << 24); // unused + + d++; + p += 3 * height; + } + + dst += surface_stride; + } + } + break; + } + + break; + } + } + + // That's probably not needed. cairoft-font.c doesn't do that + cairo_surface_mark_dirty (surface); + + if (!render_is_direct) { + free (dwrite_data); + } + + cairo_surface_set_device_offset (surface, -x1, -y1); + _cairo_scaled_glyph_set_surface (scaled_glyph, + &scaled_font->base, + (cairo_image_surface_t*)surface); + + return CAIRO_INT_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_dwrite_load_truetype_table(void *scaled_font, + unsigned long tag, + long offset, + unsigned char *buffer, + unsigned long *length) +{ + cairo_dwrite_scaled_font_t *dwritesf = static_cast(scaled_font); + + const void *data; + UINT32 size; + void *tableContext; + BOOL exists; + HRESULT hr; + hr = dwritesf->dwriteface->TryGetFontTable (be32_to_cpu (tag), + &data, + &size, + &tableContext, + &exists); + if (FAILED(hr)) + return _cairo_dwrite_error (hr, "TryGetFontTable failed"); + + if (!exists) { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + if (buffer && *length && (UINT32)offset < size) { + size = MIN(size - (UINT32)offset, *length); + memcpy(buffer, (const char*)data + offset, size); + } + *length = size; + + if (tableContext) { + dwritesf->dwriteface->ReleaseFontTable(tableContext); + } + return (cairo_int_status_t)CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_dwrite_is_synthetic(void *scaled_font, + cairo_bool_t *is_synthetic) +{ + cairo_dwrite_scaled_font_t *dwritesf = static_cast(scaled_font); + HRESULT hr; + cairo_int_status_t status; + + if (dwritesf->dwriteface->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE) { + *is_synthetic = FALSE; + return CAIRO_INT_STATUS_SUCCESS; + } + + RefPtr fontFace5; + if (FAILED(dwritesf->dwriteface->QueryInterface(&fontFace5))) { + /* If IDWriteFontFace5 is not available, assume this version of + * DirectWrite does not support variations. + */ + *is_synthetic = FALSE; + return CAIRO_INT_STATUS_SUCCESS; + } + + if (!fontFace5->HasVariations()) { + *is_synthetic = FALSE; + return CAIRO_INT_STATUS_SUCCESS; + } + + RefPtr fontResource; + hr = fontFace5->GetFontResource(&fontResource); + if (FAILED(hr)) + return _cairo_dwrite_error (hr, "GetFontResource failed"); + + UINT32 axis_count = fontResource->GetFontAxisCount(); + DWRITE_FONT_AXIS_VALUE *axis_defaults = new DWRITE_FONT_AXIS_VALUE[axis_count]; + DWRITE_FONT_AXIS_VALUE *axis_values = new DWRITE_FONT_AXIS_VALUE[axis_count]; + + hr = fontResource->GetDefaultFontAxisValues(axis_defaults, axis_count); + if (FAILED(hr)) { + status = _cairo_dwrite_error (hr, "GetDefaultFontAxisValues failed"); + goto cleanup; + } + + hr = fontFace5->GetFontAxisValues(axis_values, axis_count); + if (FAILED(hr)) { + status = _cairo_dwrite_error (hr, "GetFontAxisValues failed"); + goto cleanup; + } + + /* The DirectWrite documentation does not state if the tags of the returned + * defaults and values arrays are in the same order. So assume they are not. + */ + *is_synthetic = FALSE; + status = CAIRO_INT_STATUS_SUCCESS; + for (UINT32 i = 0; i< axis_count; i++) { + for (UINT32 j = 0; j < axis_count; j++) { + if (axis_values[i].axisTag == axis_defaults[j].axisTag) { + if (axis_values[i].value != axis_defaults[j].value) { + *is_synthetic = TRUE; + goto cleanup; + } + break; + } + } + } + + cleanup: + delete[] axis_defaults; + delete[] axis_values; + + return status; +} + +static cairo_bool_t +_cairo_dwrite_has_color_glyphs(void *scaled_font) +{ + cairo_dwrite_scaled_font_t *dwritesf = static_cast(scaled_font); + + return ((cairo_dwrite_font_face_t *)dwritesf->base.font_face)->have_color; +} + +/** + * cairo_dwrite_font_face_create_for_dwrite_fontface: + * @dwrite_font_face: A pointer to an #IDWriteFontFace specifying the + * DWrite font to use. + * + * Creates a new font for the DWrite font backend based on a + * DWrite font face. This font can then be used with + * cairo_set_font_face() or cairo_scaled_font_create(). + * + * Here is an example of how this function might be used: + * + * #include <cairo-dwrite.h> + * #include <dwrite.h> + * + * IDWriteFactory* dWriteFactory = NULL; + * HRESULT hr = DWriteCreateFactory( + * DWRITE_FACTORY_TYPE_SHARED, + * __uuidof(IDWriteFactory), + * reinterpret_cast<IUnknown**>(&dWriteFactory)); + * + * IDWriteFontCollection *systemCollection; + * hr = dWriteFactory->GetSystemFontCollection(&systemCollection); + * + * UINT32 idx; + * BOOL found; + * systemCollection->FindFamilyName(L"Segoe UI Emoji", &idx, &found); + * + * IDWriteFontFamily *family; + * systemCollection->GetFontFamily(idx, &family); + * + * IDWriteFont *dwritefont; + * DWRITE_FONT_WEIGHT weight = DWRITE_FONT_WEIGHT_NORMAL; + * DWRITE_FONT_STYLE style = DWRITE_FONT_STYLE_NORMAL; + * hr = family->GetFirstMatchingFont(weight, DWRITE_FONT_STRETCH_NORMAL, style, &dwritefont); + * + * IDWriteFontFace *dwriteface; + * hr = dwritefont->CreateFontFace(&dwriteface); + * + * cairo_font_face_t *face; + * face = cairo_dwrite_font_face_create_for_dwrite_fontface(dwriteface); + * cairo_set_font_face(cr, face); + * cairo_set_font_size(cr, 70); + * cairo_move_to(cr, 100, 100); + * cairo_show_text(cr, "😃"); + * + * + * Note: When printing a DWrite font to a + * #CAIRO_SURFACE_TYPE_WIN32_PRINTING surface, the printing surface + * will substitute each DWrite font with a Win32 font created from the same + * underlying font file. If the matching font file can not be found, + * the #CAIRO_SURFACE_TYPE_WIN32_PRINTING surface will convert each + * glyph to a filled path. If a DWrite font was not created from a system + * font, it is recommended that the font used to create the DWrite + * font be made available to GDI to avoid the undesirable fallback + * to emitting paths. This can be achieved using the GDI font loading functions + * such as AddFontMemResourceEx(). + * + * Return value: a newly created #cairo_font_face_t. Free with + * cairo_font_face_destroy() when you are done using it. + * + * Since: 1.18 + **/ +cairo_font_face_t * +cairo_dwrite_font_face_create_for_dwrite_fontface (IDWriteFontFace *dwrite_font_face) +{ + IDWriteFontFace *dwriteface = static_cast(dwrite_font_face); + // Must do malloc and not C++ new, since Cairo frees this. + cairo_dwrite_font_face_t *face = (cairo_dwrite_font_face_t *)_cairo_malloc(sizeof(cairo_dwrite_font_face_t)); + if (unlikely (face == NULL)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_font_face_t*)&_cairo_font_face_nil; + } + + dwriteface->AddRef(); + face->dwriteface = dwriteface; + face->have_color = false; + face->rendering_params = NULL; + face->measuring_mode = DWRITE_MEASURING_MODE_NATURAL; + + /* Ensure IDWriteFactory4 is available before enabling color fonts */ + if (DWriteFactory::Instance4()) { + RefPtr fontFace2; + if (SUCCEEDED(dwriteface->QueryInterface(&fontFace2))) { + if (fontFace2->IsColorFont()) + face->have_color = true; + } + } + + cairo_font_face_t *font_face; + font_face = (cairo_font_face_t*)face; + _cairo_font_face_init (&((cairo_dwrite_font_face_t*)font_face)->base, &_cairo_dwrite_font_face_backend); + + return font_face; +} + +/** + * cairo_dwrite_font_face_get_rendering_params: + * @font_face: The #cairo_dwrite_font_face_t object to query + * + * Gets the #IDWriteRenderingParams object of @font_face. + * + * Return value: the #IDWriteRenderingParams object or %NULL if none. + * + * Since: 1.18 + **/ +IDWriteRenderingParams * +cairo_dwrite_font_face_get_rendering_params (cairo_font_face_t *font_face) +{ + cairo_dwrite_font_face_t *dwface = reinterpret_cast(font_face); + return dwface->rendering_params; +} + +/** + * cairo_dwrite_font_face_set_rendering_params: + * @font_face: The #cairo_dwrite_font_face_t object to modify + * @params: The #IDWriteRenderingParams object + * + * Sets the #IDWriteRenderingParams object to @font_face. + * This #IDWriteRenderingParams is used to render glyphs if default values of font options are used. + * If non-defalut values of font options are specified when creating a #cairo_scaled_font_t, + * cairo creates a new #IDWriteRenderingParams object for the #cairo_scaled_font_t object by overwriting the corresponding parameters. + * + * Since: 1.18 + **/ +void +cairo_dwrite_font_face_set_rendering_params (cairo_font_face_t *font_face, IDWriteRenderingParams *params) +{ + cairo_dwrite_font_face_t *dwface = reinterpret_cast(font_face); + if (dwface->rendering_params) + dwface->rendering_params->Release(); + dwface->rendering_params = params; + if (dwface->rendering_params) + dwface->rendering_params->AddRef(); +} + +/** + * cairo_dwrite_font_face_get_measuring_mode: + * @font_face: The #cairo_dwrite_font_face_t object to query + * + * Gets the #DWRITE_MEASURING_MODE enum of @font_face. + * + * Return value: The #DWRITE_MEASURING_MODE enum of @font_face. + * + * Since: 1.18 + **/ +DWRITE_MEASURING_MODE +cairo_dwrite_font_face_get_measuring_mode (cairo_font_face_t *font_face) +{ + cairo_dwrite_font_face_t *dwface = reinterpret_cast(font_face); + return dwface->measuring_mode; +} + +/** + * cairo_dwrite_font_face_set_measuring_mode: + * @font_face: The #cairo_dwrite_font_face_t object to modify + * @mode: The #DWRITE_MEASURING_MODE enum. + * + * Sets the #DWRITE_MEASURING_MODE enum to @font_face. + * + * Since: 1.18 + **/ +void +cairo_dwrite_font_face_set_measuring_mode (cairo_font_face_t *font_face, DWRITE_MEASURING_MODE mode) +{ + cairo_dwrite_font_face_t *dwface = reinterpret_cast(font_face); + dwface->measuring_mode = mode; +} + +static cairo_int_status_t +_dwrite_draw_glyphs_to_gdi_surface_gdi(cairo_win32_surface_t *surface, + DWRITE_MATRIX *transform, + DWRITE_GLYPH_RUN *run, + COLORREF color, + cairo_dwrite_scaled_font_t *scaled_font, + const RECT &area) +{ + RefPtr gdiInterop; + DWriteFactory::Instance()->GetGdiInterop(&gdiInterop); + RefPtr rt; + HRESULT hr; + + hr = gdiInterop->CreateBitmapRenderTarget(surface->dc, + area.right - area.left, + area.bottom - area.top, + &rt); + + if (FAILED(hr)) { + if (hr == E_OUTOFMEMORY) { + return (cairo_int_status_t)CAIRO_STATUS_NO_MEMORY; + } else { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + } + + /* + * We set the number of pixels per DIP to 1.0. This is because we always want + * to draw in device pixels, and not device independent pixels. On high DPI + * systems this value will be higher than 1.0 and automatically upscale + * fonts, we don't want this since we do our own upscaling for various reasons. + */ + rt->SetPixelsPerDip(1.0); + + float x = 0, y = 0; + if (transform) { + DWRITE_MATRIX matrix = *transform; + matrix.dx -= area.left; + matrix.dy -= area.top; + rt->SetCurrentTransform(&matrix); + } else { + x = (float) -area.left; + y = (float) -area.top; + } + BitBlt(rt->GetMemoryDC(), + 0, 0, + area.right - area.left, area.bottom - area.top, + surface->dc, + area.left, area.top, + SRCCOPY | NOMIRRORBITMAP); + rt->DrawGlyphRun(x, y, scaled_font->measuring_mode, run, scaled_font->rendering_params, color); + BitBlt(surface->dc, + area.left, area.top, + area.right - area.left, area.bottom - area.top, + rt->GetMemoryDC(), + 0, 0, + SRCCOPY | NOMIRRORBITMAP); + return CAIRO_INT_STATUS_SUCCESS; +} + +cairo_int_status_t +_dwrite_draw_glyphs_to_gdi_surface_d2d(cairo_win32_surface_t *surface, + DWRITE_MATRIX *transform, + DWRITE_GLYPH_RUN *run, + COLORREF color, + const RECT &area) +{ + HRESULT hr; + + RefPtr rt = D2DFactory::RenderTarget(); + + // XXX don't we need to set RenderingParams on this RenderTarget? + + hr = rt->BindDC(surface->dc, &area); + if (FAILED(hr)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + // D2D uses 0x00RRGGBB not 0x00BBGGRR like COLORREF. + color = (color & 0xFF) << 16 | + (color & 0xFF00) | + (color & 0xFF0000) >> 16; + RefPtr brush; + hr = rt->CreateSolidColorBrush(D2D1::ColorF(color, 1.0), &brush); + if (FAILED(hr)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (transform) { + rt->SetTransform(D2D1::Matrix3x2F(transform->m11, + transform->m12, + transform->m21, + transform->m22, + transform->dx, + transform->dy)); + } + rt->BeginDraw(); + rt->DrawGlyphRun(D2D1::Point2F(0, 0), run, brush); + hr = rt->EndDraw(); + if (transform) { + rt->SetTransform(D2D1::Matrix3x2F::Identity()); + } + if (FAILED(hr)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + return CAIRO_INT_STATUS_SUCCESS; +} + +/* Surface helper function */ +cairo_int_status_t +_cairo_dwrite_show_glyphs_on_surface(void *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + cairo_clip_t *clip) +{ + // TODO: Check font & surface for types. + cairo_dwrite_scaled_font_t *dwritesf = reinterpret_cast(scaled_font); + cairo_win32_surface_t *dst = reinterpret_cast(surface); + cairo_int_status_t status; + + /* We can only handle dwrite fonts */ + if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_DWRITE) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* We can only handle opaque solid color sources */ + if (!_cairo_pattern_is_opaque_solid(source)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* We can only handle operator SOURCE or OVER with the destination + * having no alpha */ + if (op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_OVER) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* It is vital that dx values for dxy_buf are calculated from the delta of + * _logical_ x coordinates (not user x coordinates) or else the sum of all + * previous dx values may start to diverge from the current glyph's x + * coordinate due to accumulated rounding error. As a result strings could + * be painted shorter or longer than expected. */ + + AutoDWriteGlyphRun run; + run.allocate(num_glyphs); + + BOOL transform = FALSE; + _cairo_dwrite_glyph_run_from_glyphs(glyphs, num_glyphs, dwritesf, &run, &transform); + + cairo_solid_pattern_t *solid_pattern = (cairo_solid_pattern_t *)source; + COLORREF color = RGB(((int)solid_pattern->color.red_short) >> 8, + ((int)solid_pattern->color.green_short) >> 8, + ((int)solid_pattern->color.blue_short) >> 8); + + DWRITE_MATRIX matrix = _cairo_dwrite_matrix_from_matrix(&dwritesf->mat); + + DWRITE_MATRIX *mat; + if (transform) { + mat = &matrix; + } else { + mat = NULL; + } + + RefPtr runAnalysis; + HRESULT hr = DWriteFactory::Instance()-> + CreateGlyphRunAnalysis(&run, 1, mat, + DWRITE_RENDERING_MODE_ALIASED, + dwritesf->measuring_mode, + 0, // baselineOriginX, + 0, // baselineOriginY, + &runAnalysis); + if (FAILED(hr)) + return CAIRO_INT_STATUS_UNSUPPORTED; + RECT fontArea; + hr = runAnalysis->GetAlphaTextureBounds(DWRITE_TEXTURE_ALIASED_1x1, &fontArea); + if (FAILED(hr)) + return CAIRO_INT_STATUS_UNSUPPORTED; + InflateRect(&fontArea, 1, 1); + /* Needed to calculate bounding box for efficient blitting */ + RECT copyArea, dstArea = { 0, 0, dst->extents.width, dst->extents.height }; + IntersectRect(©Area, &fontArea, &dstArea); + +#ifdef CAIRO_TRY_D2D_TO_GDI + status = _dwrite_draw_glyphs_to_gdi_surface_d2d(dst, + mat, + &run, + color, + copyArea); + + if (status == (cairo_status_t)CAIRO_INT_STATUS_UNSUPPORTED) { +#endif + status = _dwrite_draw_glyphs_to_gdi_surface_gdi(dst, + mat, + &run, + color, + dwritesf, + copyArea); + +#ifdef CAIRO_TRY_D2D_TO_GDI + } +#endif + + return status; +} + +/* Check if a specific font table in a DWrite font and a scaled font is identical */ +static cairo_int_status_t +compare_font_tables (cairo_dwrite_font_face_t *dwface, + cairo_scaled_font_t *scaled_font, + unsigned long tag, + cairo_bool_t *match) +{ + unsigned long size; + cairo_int_status_t status; + unsigned char *buffer = NULL; + const void *dw_data; + UINT32 dw_size; + void *dw_tableContext = NULL; + BOOL dw_exists = FALSE; + HRESULT hr; + + hr = dwface->dwriteface->TryGetFontTable(be32_to_cpu (tag), + &dw_data, + &dw_size, + &dw_tableContext, + &dw_exists); + if (FAILED(hr)) + return _cairo_dwrite_error (hr, "TryGetFontTable failed"); + + if (!dw_exists) { + *match = FALSE; + status = CAIRO_INT_STATUS_SUCCESS; + goto cleanup; + } + + status = scaled_font->backend->load_truetype_table (scaled_font, tag, 0, NULL, &size); + if (unlikely(status)) + goto cleanup; + + if (size != dw_size) { + *match = FALSE; + status = CAIRO_INT_STATUS_SUCCESS; + goto cleanup; + } + + buffer = (unsigned char *) _cairo_malloc (size); + if (unlikely (buffer == NULL)) { + status = (cairo_int_status_t) _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto cleanup; + } + + status = scaled_font->backend->load_truetype_table (scaled_font, tag, 0, buffer, &size); + if (unlikely(status)) + goto cleanup; + + *match = memcmp (dw_data, buffer, size) == 0; + status = CAIRO_INT_STATUS_SUCCESS; + +cleanup: + free (buffer); + if (dw_tableContext) + dwface->dwriteface->ReleaseFontTable(dw_tableContext); + + return status; +} + +/* Check if a DWrite font and a scaled font areis identical + * + * DWrite does not allow accessing the entire font data using tag=0 so we compare + * two of the font tables: + * - 'name' table + * - 'head' table since this contains the checksum for the entire font + */ +static cairo_int_status_t +font_tables_match (cairo_dwrite_font_face_t *dwface, + cairo_scaled_font_t *scaled_font, + cairo_bool_t *match) +{ + cairo_int_status_t status; + + status = compare_font_tables (dwface, scaled_font, TT_TAG_name, match); + if (unlikely(status)) + return status; + + if (!*match) + return CAIRO_INT_STATUS_SUCCESS; + + status = compare_font_tables (dwface, scaled_font, TT_TAG_head, match); + if (unlikely(status)) + return status; + + return CAIRO_INT_STATUS_SUCCESS; +} + +/* + * Helper for _cairo_win32_printing_surface_show_glyphs to create a win32 equivalent + * of a dwrite scaled_font so that we can print using ExtTextOut instead of drawing + * paths or blitting glyph bitmaps. + */ +cairo_int_status_t +_cairo_dwrite_scaled_font_create_win32_scaled_font (cairo_scaled_font_t *scaled_font, + cairo_scaled_font_t **new_font) +{ + if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_DWRITE) { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + cairo_font_face_t *face = cairo_scaled_font_get_font_face (scaled_font); + if (cairo_font_face_status (face) == CAIRO_STATUS_SUCCESS && + cairo_font_face_get_type (face) == CAIRO_FONT_TYPE_TOY) + { + face = ((cairo_toy_font_face_t *)face)->impl_face; + } + + if (face == NULL || cairo_font_face_get_type (face) != CAIRO_FONT_TYPE_DWRITE) { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + cairo_dwrite_font_face_t *dwface = reinterpret_cast(face); + + RefPtr gdiInterop; + DWriteFactory::Instance()->GetGdiInterop(&gdiInterop); + if (!gdiInterop) { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + /* TODO: use scaled font? */ + + LOGFONTW logfont; + if (FAILED(gdiInterop->ConvertFontFaceToLOGFONT (dwface->dwriteface, &logfont))) { + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + /* DWrite must have been using an outline font, so we want GDI to use the same, + * even if there's also a bitmap face available + */ + logfont.lfOutPrecision = OUT_OUTLINE_PRECIS; + + cairo_font_face_t *win32_face = cairo_win32_font_face_create_for_logfontw (&logfont); + if (cairo_font_face_status (win32_face)) { + cairo_font_face_destroy (win32_face); + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + cairo_matrix_t font_matrix; + cairo_scaled_font_get_font_matrix (scaled_font, &font_matrix); + + cairo_matrix_t ctm; + cairo_scaled_font_get_ctm (scaled_font, &ctm); + + cairo_font_options_t options; + _cairo_font_options_init_default (&options); + cairo_scaled_font_get_font_options (scaled_font, &options); + + cairo_scaled_font_t *font = cairo_scaled_font_create (win32_face, + &font_matrix, + &ctm, + &options); + cairo_font_face_destroy (win32_face); + + if (cairo_scaled_font_status(font)) { + cairo_scaled_font_destroy (font); + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + cairo_bool_t match; + cairo_int_status_t status; + status = font_tables_match (dwface, font, &match); + if (status) { + cairo_scaled_font_destroy (font); + return status; + } + + /* If the font tables aren't equal, then GDI may have failed to + * find the right font and substituted a different font. + */ + if (!match) { +#if 0 + char *ps_name; + char *font_name; + status = _cairo_truetype_read_font_name (scaled_font, &ps_name, &font_name); + printf("dwrite fontname: %s PS name: %s\n", font_name, ps_name); + free (font_name); + free (ps_name); + status = _cairo_truetype_read_font_name (font, &ps_name, &font_name); + printf("win32 fontname: %s PS name: %s\n", font_name, ps_name); + free (font_name); + free (ps_name); +#endif + cairo_scaled_font_destroy (font); + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + *new_font = font; + return CAIRO_INT_STATUS_SUCCESS; +} diff --git a/local/recipes/libs/cairo/source/src/win32/cairo-dwrite-private.hpp b/local/recipes/libs/cairo/source/src/win32/cairo-dwrite-private.hpp new file mode 100644 index 0000000000..7834485f3e --- /dev/null +++ b/local/recipes/libs/cairo/source/src/win32/cairo-dwrite-private.hpp @@ -0,0 +1,236 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2010 Mozilla Foundation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is the Mozilla Foundation + * + * Contributor(s): + * Bas Schouten + */ + +#include "cairoint.h" +#include "cairo-win32-refptr.hpp" +#include +#include + +#ifdef __MINGW32__ +#include "dw-extra.h" +#else +typedef DWRITE_COLOR_GLYPH_RUN1 DWRITE_COLOR_GLYPH_RUN1_WORKAROUND; +#endif + +/* If d2d1_3.h header required for color fonts is not available, + * include our own version containing just the functions we need. + */ + +#if HAVE_D2D1_3_H +#include +#else +#include "d2d1-extra.h" +#endif + +// DirectWrite is not available on all platforms. +typedef HRESULT (WINAPI*DWriteCreateFactoryFunc)( + DWRITE_FACTORY_TYPE factoryType, + REFIID iid, + IUnknown **factory +); + +/* #cairo_scaled_font_t implementation */ +struct _cairo_dwrite_scaled_font { + cairo_scaled_font_t base; + cairo_matrix_t mat; + cairo_matrix_t mat_inverse; + cairo_antialias_t antialias_mode; + IDWriteFontFace *dwriteface; /* Can't use RefPtr because this struct is malloc'd. */ + IDWriteRenderingParams *rendering_params; /* Can't use RefPtr because this struct is malloc'd. */ + DWRITE_MEASURING_MODE measuring_mode; +}; +typedef struct _cairo_dwrite_scaled_font cairo_dwrite_scaled_font_t; + +class DWriteFactory +{ +public: + static RefPtr Instance() + { + if (!mFactoryInstance) { +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-function-type" +#endif + HMODULE dwrite = _cairo_win32_load_library_from_system32 (L"dwrite.dll"); + DWriteCreateFactoryFunc createDWriteFactory = (DWriteCreateFactoryFunc) + GetProcAddress(dwrite, "DWriteCreateFactory"); +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + if (createDWriteFactory) { + HRESULT hr = createDWriteFactory( + DWRITE_FACTORY_TYPE_SHARED, + __uuidof(IDWriteFactory), + reinterpret_cast(&mFactoryInstance)); + assert(SUCCEEDED(hr)); + } + } + return mFactoryInstance; + } + + static RefPtr Instance1() + { + if (!mFactoryInstance1) { + if (Instance()) { + Instance()->QueryInterface(&mFactoryInstance1); + } + } + return mFactoryInstance1; + } + + static RefPtr Instance2() + { + if (!mFactoryInstance2) { + if (Instance()) { + Instance()->QueryInterface(&mFactoryInstance2); + } + } + return mFactoryInstance2; + } + + static RefPtr Instance3() + { + if (!mFactoryInstance3) { + if (Instance()) { + Instance()->QueryInterface(&mFactoryInstance3); + } + } + return mFactoryInstance3; + } + + static RefPtr Instance4() + { + if (!mFactoryInstance4) { + if (Instance()) { + Instance()->QueryInterface(&mFactoryInstance4); + } + } + return mFactoryInstance4; + } + + static RefPtr SystemCollection() + { + if (!mSystemCollection) { + if (Instance()) { + HRESULT hr = Instance()->GetSystemFontCollection(&mSystemCollection); + assert(SUCCEEDED(hr)); + } + } + return mSystemCollection; + } + + static RefPtr FindSystemFontFamily(const WCHAR *aFamilyName) + { + UINT32 idx; + BOOL found; + if (!SystemCollection()) { + return NULL; + } + SystemCollection()->FindFamilyName(aFamilyName, &idx, &found); + if (!found) { + return NULL; + } + + RefPtr family; + SystemCollection()->GetFontFamily(idx, &family); + return family; + } + + static RefPtr DefaultRenderingParams() + { + if (!mDefaultRenderingParams) { + if (Instance()) { + Instance()->CreateRenderingParams(&mDefaultRenderingParams); + } + } + return mDefaultRenderingParams; + } + +private: + static RefPtr mFactoryInstance; + static RefPtr mFactoryInstance1; + static RefPtr mFactoryInstance2; + static RefPtr mFactoryInstance3; + static RefPtr mFactoryInstance4; + static RefPtr mSystemCollection; + static RefPtr mDefaultRenderingParams; +}; + +class AutoDWriteGlyphRun : public DWRITE_GLYPH_RUN +{ + static const int kNumAutoGlyphs = 256; + +public: + AutoDWriteGlyphRun() { + glyphCount = 0; + } + + ~AutoDWriteGlyphRun() { + if (glyphCount > kNumAutoGlyphs) { + delete[] glyphIndices; + delete[] glyphAdvances; + delete[] glyphOffsets; + } + } + + void allocate(int aNumGlyphs) { + glyphCount = aNumGlyphs; + if (aNumGlyphs <= kNumAutoGlyphs) { + glyphIndices = &mAutoIndices[0]; + glyphAdvances = &mAutoAdvances[0]; + glyphOffsets = &mAutoOffsets[0]; + } else { + glyphIndices = new UINT16[aNumGlyphs]; + glyphAdvances = new FLOAT[aNumGlyphs]; + glyphOffsets = new DWRITE_GLYPH_OFFSET[aNumGlyphs]; + } + } + +private: + DWRITE_GLYPH_OFFSET mAutoOffsets[kNumAutoGlyphs]; + FLOAT mAutoAdvances[kNumAutoGlyphs]; + UINT16 mAutoIndices[kNumAutoGlyphs]; +}; + +/* #cairo_font_face_t implementation */ +struct _cairo_dwrite_font_face { + cairo_font_face_t base; + IDWriteFontFace *dwriteface; /* Can't use RefPtr because this struct is malloc'd. */ + cairo_bool_t have_color; + IDWriteRenderingParams *rendering_params; /* Can't use RefPtr because this struct is malloc'd. */ + DWRITE_MEASURING_MODE measuring_mode; +}; +typedef struct _cairo_dwrite_font_face cairo_dwrite_font_face_t; diff --git a/local/recipes/libs/cairo/source/src/win32/cairo-win32-debug.c b/local/recipes/libs/cairo/source/src/win32/cairo-win32-debug.c new file mode 100644 index 0000000000..01410c8969 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/win32/cairo-win32-debug.c @@ -0,0 +1,78 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Owen Taylor + * Stuart Parmenter + * Vladimir Vukicevic + */ + +#include "cairoint.h" +#include "cairo-win32-private.h" + +#include +#include + +void +_cairo_win32_debug_dump_hrgn (HRGN rgn, char *header) +{ + RGNDATA *rd; + unsigned int z; + + if (header) + fprintf (stderr, "%s\n", header); + + if (rgn == NULL) { + fprintf (stderr, " NULL\n"); + } + + z = GetRegionData(rgn, 0, NULL); + rd = (RGNDATA*) _cairo_malloc (z); + z = GetRegionData(rgn, z, rd); + + fprintf (stderr, " %ld rects, bounds: %ld %ld %ld %ld\n", + rd->rdh.nCount, + rd->rdh.rcBound.left, + rd->rdh.rcBound.top, + rd->rdh.rcBound.right - rd->rdh.rcBound.left, + rd->rdh.rcBound.bottom - rd->rdh.rcBound.top); + + for (z = 0; z < rd->rdh.nCount; z++) { + RECT r = ((RECT*)rd->Buffer)[z]; + fprintf (stderr, " [%d]: [%ld %ld %ld %ld]\n", + z, r.left, r.top, r.right - r.left, r.bottom - r.top); + } + + free(rd); + fflush (stderr); +} diff --git a/local/recipes/libs/cairo/source/src/win32/cairo-win32-device.c b/local/recipes/libs/cairo/source/src/win32/cairo-win32-device.c new file mode 100644 index 0000000000..91ef745882 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/win32/cairo-win32-device.c @@ -0,0 +1,147 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Owen Taylor + * Stuart Parmenter + * Vladimir Vukicevic + */ + +#include "cairoint.h" + +#include "cairo-atomic-private.h" +#include "cairo-device-private.h" +#include "cairo-win32-private.h" + +#include +#include + +static cairo_device_t *__cairo_win32_device; + +static cairo_status_t +_cairo_win32_device_flush (void *device) +{ + GdiFlush (); + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_win32_device_finish (void *device) +{ +} + +static void +_cairo_win32_device_destroy (void *device) +{ + free (device); +} + +static const cairo_device_backend_t _cairo_win32_device_backend = { + CAIRO_DEVICE_TYPE_WIN32, + + NULL, NULL, /* lock, unlock */ + + _cairo_win32_device_flush, + _cairo_win32_device_finish, + _cairo_win32_device_destroy, +}; + +cairo_device_t * +_cairo_win32_device_get (void) +{ + cairo_win32_device_t *device; + + if (__cairo_win32_device) + return cairo_device_reference (__cairo_win32_device); + + device = _cairo_calloc (sizeof (*device)); + + _cairo_device_init (&device->base, &_cairo_win32_device_backend); + + device->compositor = _cairo_win32_gdi_compositor_get (); + + if (_cairo_atomic_ptr_cmpxchg ((cairo_atomic_intptr_t *)&__cairo_win32_device, NULL, device)) + return cairo_device_reference(&device->base); + + _cairo_win32_device_destroy (device); + return cairo_device_reference (__cairo_win32_device); +} + +unsigned +_cairo_win32_flags_for_dc (HDC dc, cairo_format_t format) +{ + uint32_t flags = 0; + cairo_bool_t is_display = GetDeviceCaps(dc, TECHNOLOGY) == DT_RASDISPLAY; + + if (format == CAIRO_FORMAT_RGB24 || format == CAIRO_FORMAT_ARGB32) + { + int cap = GetDeviceCaps(dc, RASTERCAPS); + if (cap & RC_BITBLT) + flags |= CAIRO_WIN32_SURFACE_CAN_BITBLT; + if (!is_display && GetDeviceCaps(dc, SHADEBLENDCAPS) != SB_NONE) + flags |= CAIRO_WIN32_SURFACE_CAN_ALPHABLEND; + + /* ARGB32 available operations are a strict subset of RGB24 + * available operations. This is because the same GDI functions + * can be used but most of them always reset alpha channel to 0 + * which is bad for ARGB32. + */ + if (format == CAIRO_FORMAT_RGB24) + { + flags |= CAIRO_WIN32_SURFACE_CAN_RGB_BRUSH; + if (cap & RC_STRETCHBLT) + flags |= CAIRO_WIN32_SURFACE_CAN_STRETCHBLT; + if (cap & RC_STRETCHDIB) + flags |= CAIRO_WIN32_SURFACE_CAN_STRETCHDIB; + } + } + + if (is_display) { + flags |= CAIRO_WIN32_SURFACE_IS_DISPLAY; + + /* These will always be possible, but the actual GetDeviceCaps + * calls will return whether they're accelerated or not. + * We may want to use our own (pixman) routines sometimes + * if they're eventually faster, but for now have GDI do + * everything. + */ +#if 0 + flags |= CAIRO_WIN32_SURFACE_CAN_BITBLT; + flags |= CAIRO_WIN32_SURFACE_CAN_ALPHABLEND; + flags |= CAIRO_WIN32_SURFACE_CAN_STRETCHBLT; + flags |= CAIRO_WIN32_SURFACE_CAN_STRETCHDIB; +#endif + } + + return flags; +} diff --git a/local/recipes/libs/cairo/source/src/win32/cairo-win32-display-surface.c b/local/recipes/libs/cairo/source/src/win32/cairo-win32-display-surface.c new file mode 100644 index 0000000000..7f0770b4fd --- /dev/null +++ b/local/recipes/libs/cairo/source/src/win32/cairo-win32-display-surface.c @@ -0,0 +1,1156 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Owen Taylor + * Stuart Parmenter + * Vladimir Vukicevic + */ + +#include "cairoint.h" + +#include "cairo-clip-private.h" +#include "cairo-composite-rectangles-private.h" +#include "cairo-compositor-private.h" +#include "cairo-damage-private.h" +#include "cairo-default-context-private.h" +#include "cairo-error-private.h" +#include "cairo-image-surface-inline.h" +#include "cairo-paginated-private.h" +#include "cairo-pattern-private.h" +#include "cairo-win32-private.h" +#include "cairo-scaled-font-subsets-private.h" +#include "cairo-surface-fallback-private.h" +#include "cairo-surface-backend-private.h" + +#include +#include + +#define PELS_72DPI ((LONG)(72. / 0.0254)) + +/** + * SECTION:cairo-win32 + * @Title: Win32 Surfaces + * @Short_Description: Microsoft Windows surface support + * @See_Also: #cairo_surface_t + * + * The Microsoft Windows surface is used to render cairo graphics to + * Microsoft Windows windows, bitmaps, and printing device contexts. + * + * The surface returned by cairo_win32_printing_surface_create() is of surface + * type %CAIRO_SURFACE_TYPE_WIN32_PRINTING and is a multi-page vector surface + * type. + * + * The surface returned by the other win32 constructors is of surface type + * %CAIRO_SURFACE_TYPE_WIN32 and is a raster surface type. + **/ + +/** + * CAIRO_HAS_WIN32_SURFACE: + * + * Defined if the Microsoft Windows surface backend is available. + * This macro can be used to conditionally compile backend-specific code. + * + * Since: 1.0 + **/ + +static const cairo_surface_backend_t cairo_win32_display_surface_backend; + +static cairo_status_t +_create_dc_and_bitmap (cairo_win32_display_surface_t *surface, + HDC original_dc, + cairo_format_t format, + int width, + int height, + unsigned char **bits_out, + int *rowstride_out) +{ + BITMAPINFO *bitmap_info = NULL; + struct { + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[2]; + } bmi_stack; + void *bits; + + int num_palette = 0; /* Quiet GCC */ + int i; + + surface->win32.dc = NULL; + surface->bitmap = NULL; + surface->is_dib = FALSE; + + switch (format) { + default: + case CAIRO_FORMAT_INVALID: + case CAIRO_FORMAT_RGB16_565: + case CAIRO_FORMAT_RGB30: + case CAIRO_FORMAT_RGB96F: + case CAIRO_FORMAT_RGBA128F: + return _cairo_error (CAIRO_STATUS_INVALID_FORMAT); + case CAIRO_FORMAT_ARGB32: + case CAIRO_FORMAT_RGB24: + num_palette = 0; + break; + + case CAIRO_FORMAT_A8: + num_palette = 256; + break; + + case CAIRO_FORMAT_A1: + num_palette = 2; + break; + } + + if (num_palette > 2) { + bitmap_info = _cairo_malloc_ab_plus_c (num_palette, sizeof(RGBQUAD), sizeof(BITMAPINFOHEADER)); + if (!bitmap_info) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + } else { + bitmap_info = (BITMAPINFO *)&bmi_stack; + } + + bitmap_info->bmiHeader.biSize = sizeof (BITMAPINFOHEADER); + bitmap_info->bmiHeader.biWidth = width == 0 ? 1 : width; + bitmap_info->bmiHeader.biHeight = height == 0 ? -1 : - height; /* top-down */ + bitmap_info->bmiHeader.biSizeImage = 0; + bitmap_info->bmiHeader.biXPelsPerMeter = PELS_72DPI; /* unused here */ + bitmap_info->bmiHeader.biYPelsPerMeter = PELS_72DPI; /* unused here */ + bitmap_info->bmiHeader.biPlanes = 1; + + switch (format) { + case CAIRO_FORMAT_INVALID: + case CAIRO_FORMAT_RGB16_565: + case CAIRO_FORMAT_RGB30: + case CAIRO_FORMAT_RGB96F: + case CAIRO_FORMAT_RGBA128F: + ASSERT_NOT_REACHED; + /* We can't create real RGB24 bitmaps because something seems to + * break if we do, especially if we don't set up an image + * fallback. It could be a bug with using a 24bpp pixman image + * (and creating one with masks). So treat them like 32bpp. + * Note: This causes problems when using BitBlt/AlphaBlend/etc! + * see end of file. + */ + case CAIRO_FORMAT_RGB24: + case CAIRO_FORMAT_ARGB32: + bitmap_info->bmiHeader.biBitCount = 32; + bitmap_info->bmiHeader.biCompression = BI_RGB; + bitmap_info->bmiHeader.biClrUsed = 0; /* unused */ + bitmap_info->bmiHeader.biClrImportant = 0; + break; + + case CAIRO_FORMAT_A8: + bitmap_info->bmiHeader.biBitCount = 8; + bitmap_info->bmiHeader.biCompression = BI_RGB; + bitmap_info->bmiHeader.biClrUsed = 256; + bitmap_info->bmiHeader.biClrImportant = 0; + + for (i = 0; i < 256; i++) { + bitmap_info->bmiColors[i].rgbBlue = i; + bitmap_info->bmiColors[i].rgbGreen = i; + bitmap_info->bmiColors[i].rgbRed = i; + bitmap_info->bmiColors[i].rgbReserved = 0; + } + break; + + case CAIRO_FORMAT_A1: + bitmap_info->bmiHeader.biBitCount = 1; + bitmap_info->bmiHeader.biCompression = BI_RGB; + bitmap_info->bmiHeader.biClrUsed = 2; + bitmap_info->bmiHeader.biClrImportant = 0; + + for (i = 0; i < 2; i++) { + bitmap_info->bmiColors[i].rgbBlue = i * 255; + bitmap_info->bmiColors[i].rgbGreen = i * 255; + bitmap_info->bmiColors[i].rgbRed = i * 255; + bitmap_info->bmiColors[i].rgbReserved = 0; + } + break; + } + + surface->win32.dc = CreateCompatibleDC (original_dc); + if (!surface->win32.dc) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "CreateCompatibleDC"); + goto FAIL; + } + + surface->bitmap = CreateDIBSection (surface->win32.dc, + bitmap_info, + DIB_RGB_COLORS, + &bits, + NULL, 0); + if (!surface->bitmap) { + _cairo_win32_print_api_error (__FUNCTION__, "CreateDIBSection"); + goto FAIL; + } + + surface->is_dib = TRUE; + + GdiFlush(); + + surface->saved_dc_bitmap = SelectObject (surface->win32.dc, + surface->bitmap); + if (!surface->saved_dc_bitmap) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "SelectObject"); + goto FAIL; + } + + if (bitmap_info && num_palette > 2) + free (bitmap_info); + + if (bits_out) + *bits_out = bits; + + if (rowstride_out) { + /* Windows bitmaps are padded to 32-bit (dword) boundaries */ + switch (format) { + case CAIRO_FORMAT_INVALID: + case CAIRO_FORMAT_RGB16_565: + case CAIRO_FORMAT_RGB30: + case CAIRO_FORMAT_RGB96F: + case CAIRO_FORMAT_RGBA128F: + ASSERT_NOT_REACHED; + case CAIRO_FORMAT_ARGB32: + case CAIRO_FORMAT_RGB24: + *rowstride_out = 4 * width; + break; + + case CAIRO_FORMAT_A8: + *rowstride_out = (width + 3) & ~3; + break; + + case CAIRO_FORMAT_A1: + *rowstride_out = ((width + 31) & ~31) / 8; + break; + } + } + + surface->win32.flags = _cairo_win32_flags_for_dc (surface->win32.dc, format); + + return CAIRO_STATUS_SUCCESS; + + FAIL: + if (bitmap_info && num_palette > 2) + free (bitmap_info); + + if (surface->saved_dc_bitmap) { + SelectObject (surface->win32.dc, surface->saved_dc_bitmap); + surface->saved_dc_bitmap = NULL; + } + + if (surface->bitmap) { + DeleteObject (surface->bitmap); + surface->bitmap = NULL; + } + + if (surface->win32.dc) { + DeleteDC (surface->win32.dc); + surface->win32.dc = NULL; + } + + return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); +} + +static cairo_surface_t * +_cairo_win32_display_surface_create_for_dc (HDC original_dc, + cairo_format_t format, + int width, + int height) +{ + cairo_status_t status; + cairo_device_t *device; + cairo_win32_display_surface_t *surface; + unsigned char *bits; + int rowstride; + + surface = _cairo_calloc (sizeof (*surface)); + if (surface == NULL) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + surface->fallback = NULL; + + status = _create_dc_and_bitmap (surface, original_dc, format, + width, height, + &bits, &rowstride); + if (status) + goto FAIL; + + surface->image = cairo_image_surface_create_for_data (bits, format, + width, height, rowstride); + status = surface->image->status; + if (status) + goto FAIL; + + _cairo_image_surface_set_parent (to_image_surface(surface->image), + &surface->win32.base); + + surface->win32.format = format; + + surface->win32.extents.x = 0; + surface->win32.extents.y = 0; + surface->win32.extents.width = width; + surface->win32.extents.height = height; + surface->win32.x_ofs = 0; + surface->win32.y_ofs = 0; + + surface->initial_clip_rgn = NULL; + surface->had_simple_clip = FALSE; + + device = _cairo_win32_device_get (); + + _cairo_surface_init (&surface->win32.base, + &cairo_win32_display_surface_backend, + device, + _cairo_content_from_format (format), + FALSE); /* is_vector */ + + cairo_device_destroy (device); + + return &surface->win32.base; + + FAIL: + if (surface->bitmap) { + SelectObject (surface->win32.dc, surface->saved_dc_bitmap); + DeleteObject (surface->bitmap); + DeleteDC (surface->win32.dc); + } + free (surface); + + return _cairo_surface_create_in_error (status); +} + +static cairo_surface_t * +_cairo_win32_display_surface_create_similar (void *abstract_src, + cairo_content_t content, + int width, + int height) +{ + cairo_win32_display_surface_t *src = abstract_src; + cairo_format_t format = _cairo_format_from_content (content); + cairo_surface_t *new_surf = NULL; + + /* We force a DIB always if: + * - we need alpha; or + * - the parent is a DIB; or + * - the parent is for printing (because we don't care about the + * bit depth at that point) + * + * We also might end up with a DIB even if a DDB is requested if + * DDB creation failed due to out of memory. + */ + if (!(src->is_dib || content & CAIRO_CONTENT_ALPHA)) { + /* try to create a ddb */ + new_surf = cairo_win32_surface_create_with_ddb (src->win32.dc, CAIRO_FORMAT_RGB24, width, height); + + if (new_surf->status) + new_surf = NULL; + } + + if (new_surf == NULL) { + new_surf = _cairo_win32_display_surface_create_for_dc (src->win32.dc, format, width, height); + } + + return new_surf; +} + +static cairo_surface_t * +_cairo_win32_display_surface_create_similar_image (void *abstract_other, + cairo_format_t format, + int width, + int height) +{ + cairo_win32_display_surface_t *surface = abstract_other; + cairo_image_surface_t *image; + + surface = (cairo_win32_display_surface_t *) + _cairo_win32_display_surface_create_for_dc (surface->win32.dc, + format, width, height); + if (surface->win32.base.status) + return &surface->win32.base; + + /* And clear in order to comply with our user API semantics */ + image = (cairo_image_surface_t *) surface->image; + if (! image->base.is_clear) { + memset (image->data, 0, image->stride * height); + image->base.is_clear = TRUE; + } + + return &image->base; +} + +static cairo_status_t +_cairo_win32_display_surface_finish (void *abstract_surface) +{ + cairo_win32_display_surface_t *surface = abstract_surface; + + if (surface->image && to_image_surface(surface->image)->parent) { + assert (to_image_surface(surface->image)->parent == &surface->win32.base); + /* Unhook ourselves first to avoid the double-unref from the image */ + to_image_surface(surface->image)->parent = NULL; + cairo_surface_finish (surface->image); + cairo_surface_destroy (surface->image); + } + + /* If we created the Bitmap and DC, destroy them */ + if (surface->bitmap) { + SelectObject (surface->win32.dc, surface->saved_dc_bitmap); + DeleteObject (surface->bitmap); + DeleteDC (surface->win32.dc); + } + + _cairo_win32_display_surface_discard_fallback (surface); + + if (surface->initial_clip_rgn) + DeleteObject (surface->initial_clip_rgn); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_image_surface_t * +_cairo_win32_display_surface_map_to_image (void *abstract_surface, + const cairo_rectangle_int_t *extents) +{ + cairo_win32_display_surface_t *surface = abstract_surface; + cairo_status_t status; + + TRACE ((stderr, "%s (surface=%d)\n", + __FUNCTION__, surface->win32.base.unique_id)); + + if (surface->image) + goto done; + + if (surface->fallback == NULL) { + surface->fallback = + _cairo_win32_display_surface_create_for_dc (surface->win32.dc, + surface->win32.format, + surface->win32.extents.x + surface->win32.extents.width, + surface->win32.extents.y + surface->win32.extents.height); + if (unlikely (status = surface->fallback->status)) + goto err; + + if (!BitBlt (to_win32_surface(surface->fallback)->dc, + surface->win32.extents.x, surface->win32.extents.y, + surface->win32.extents.width, + surface->win32.extents.height, + surface->win32.dc, + surface->win32.extents.x + surface->win32.x_ofs, /* Handling multi-monitor... */ + surface->win32.extents.y + surface->win32.y_ofs, /* ... setup on Win32 */ + SRCCOPY)) { + status = _cairo_error (CAIRO_STATUS_DEVICE_ERROR); + goto err; + } + } + + surface = to_win32_display_surface (surface->fallback); +done: + GdiFlush(); + return _cairo_surface_map_to_image (surface->image, extents); + +err: + cairo_surface_destroy (surface->fallback); + surface->fallback = NULL; + + return _cairo_image_surface_create_in_error (status); +} + +static cairo_int_status_t +_cairo_win32_display_surface_unmap_image (void *abstract_surface, + cairo_image_surface_t *image) +{ + cairo_win32_display_surface_t *surface = abstract_surface; + + /* Delay the download until the next flush, which means we also need + * to make sure our sources rare flushed. + */ + TRACE ((stderr, "%s (surface=%d)\n", + __FUNCTION__, to_win32_surface(surface)->base.unique_id)); + + if (surface->fallback) { + cairo_rectangle_int_t r; + + r.x = image->base.device_transform_inverse.x0; + r.y = image->base.device_transform_inverse.y0; + r.width = image->width; + r.height = image->height; + + TRACE ((stderr, "%s: adding damage (%d,%d)x(%d,%d)\n", + __FUNCTION__, r.x, r.y, r.width, r.height)); + surface->fallback->damage = + _cairo_damage_add_rectangle (surface->fallback->damage, &r); + surface = to_win32_display_surface (surface->fallback); + } + + return _cairo_surface_unmap_image (surface->image, image); +} + +static cairo_status_t +_cairo_win32_display_surface_flush (void *abstract_surface, unsigned flags) +{ + cairo_win32_display_surface_t *surface = abstract_surface; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + if (flags) + return CAIRO_STATUS_SUCCESS; + + TRACE ((stderr, "%s (surface=%d)\n", + __FUNCTION__, surface->win32.base.unique_id)); + if (surface->fallback == NULL) + return CAIRO_STATUS_SUCCESS; + + if (surface->fallback->damage) { + cairo_win32_display_surface_t *fallback; + cairo_damage_t *damage; + + damage = _cairo_damage_reduce (surface->fallback->damage); + surface->fallback->damage = NULL; + + fallback = to_win32_display_surface (surface->fallback); + assert (fallback->image); + + TRACE ((stderr, "%s: flushing damage x %d\n", __FUNCTION__, + damage->region ? cairo_region_num_rectangles (damage->region) : 0)); + + if (damage->status) { + if (!BitBlt (surface->win32.dc, + surface->win32.extents.x + surface->win32.x_ofs, /* Handling multi-monitor... */ + surface->win32.extents.y + surface->win32.y_ofs, /* ... setup on Win32 */ + surface->win32.extents.width, + surface->win32.extents.height, + fallback->win32.dc, + surface->win32.extents.x, surface->win32.extents.y, + SRCCOPY)) + status = _cairo_win32_print_api_error (__FUNCTION__, "BitBlt"); + } else if (damage->region) { + int n = cairo_region_num_rectangles (damage->region), i; + for (i = 0; i < n; i++) { + cairo_rectangle_int_t rect; + + cairo_region_get_rectangle (damage->region, i, &rect); + TRACE ((stderr, "%s: damage (%d,%d)x(%d,%d)\n", __FUNCTION__, + rect.x, rect.y, + rect.width, rect.height)); + if (!BitBlt (surface->win32.dc, + rect.x + surface->win32.x_ofs, /* Handling multi-monitor... */ + rect.y + surface->win32.y_ofs, /* ... setup on Win32 */ + rect.width, rect.height, + fallback->win32.dc, + rect.x, rect.y, + SRCCOPY)) { + status = _cairo_win32_print_api_error (__FUNCTION__, "BitBlt"); + break; + } + } + } + _cairo_damage_destroy (damage); + } else { + cairo_surface_destroy (surface->fallback); + surface->fallback = NULL; + } + + return status; +} + +static cairo_status_t +_cairo_win32_display_surface_mark_dirty (void *abstract_surface, + int x, int y, int width, int height) +{ + _cairo_win32_display_surface_discard_fallback (abstract_surface); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_win32_save_initial_clip (HDC hdc, cairo_win32_display_surface_t *surface) +{ + RECT rect; + int clipBoxType; + int gm; + XFORM saved_xform; + + /* GetClipBox/GetClipRgn and friends interact badly with a world transform + * set. GetClipBox returns values in logical (transformed) coordinates; + * it's unclear what GetClipRgn returns, because the region is empty in the + * case of a SIMPLEREGION clip, but I assume device (untransformed) coordinates. + * Similarly, IntersectClipRect works in logical units, whereas SelectClipRgn + * works in device units. + * + * So, avoid the whole mess and get rid of the world transform + * while we store our initial data and when we restore initial coordinates. + * + * XXX we may need to modify x/y by the ViewportOrg or WindowOrg + * here in GM_COMPATIBLE; unclear. + */ + gm = GetGraphicsMode (hdc); + if (gm == GM_ADVANCED) { + GetWorldTransform (hdc, &saved_xform); + ModifyWorldTransform (hdc, NULL, MWT_IDENTITY); + } + + clipBoxType = GetClipBox (hdc, &rect); + if (clipBoxType == ERROR) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "GetClipBox"); + SetGraphicsMode (hdc, gm); + /* XXX: Can we make a more reasonable guess at the error cause here? */ + return _cairo_error (CAIRO_STATUS_DEVICE_ERROR); + } + + surface->win32.extents.x = rect.left; + surface->win32.extents.y = rect.top; + surface->win32.extents.width = rect.right - rect.left; + surface->win32.extents.height = rect.bottom - rect.top; + + /* On multi-monitor setup, under Windows, the primary monitor always + * have origin (0,0). Any monitors that extends to the left or above + * will have coordinates in the negative range. Take this into + * account, by forcing our Win32 surface to start at extent (0,0) and + * using a device offset. Cairo does not handle extents with negative + * offsets. + */ + surface->win32.x_ofs = 0; + surface->win32.y_ofs = 0; + if ((surface->win32.extents.x < 0) || + (surface->win32.extents.y < 0)) { + /* Negative offsets occurs for (and ONLY for) the desktop DC (virtual + * desktop), when a monitor extend to the left or above the primary + * monitor. + * + * More info @ https://www.microsoft.com/msj/0697/monitor/monitor.aspx + * + * Note that any other DC, including memory DC created with + * CreateCompatibleDC() will have extents in the + * positive range. This will be taken into account later when we perform + * raster operations between the DC (may have to perform offset + * translation). + */ + surface->win32.x_ofs = surface->win32.extents.x; + surface->win32.y_ofs = surface->win32.extents.y; + surface->win32.extents.x = 0; + surface->win32.extents.y = 0; + } + + surface->initial_clip_rgn = NULL; + surface->had_simple_clip = FALSE; + + if (clipBoxType == COMPLEXREGION) { + surface->initial_clip_rgn = CreateRectRgn (0, 0, 0, 0); + if (GetClipRgn (hdc, surface->initial_clip_rgn) <= 0) { + DeleteObject(surface->initial_clip_rgn); + surface->initial_clip_rgn = NULL; + } + } else if (clipBoxType == SIMPLEREGION) { + surface->had_simple_clip = TRUE; + } + + if (gm == GM_ADVANCED) + SetWorldTransform (hdc, &saved_xform); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_status_t +_cairo_win32_display_surface_set_clip (cairo_win32_display_surface_t *surface, + cairo_clip_t *clip) +{ + char stack[512]; + cairo_rectangle_int_t extents; + int num_rects; + RGNDATA *data; + size_t data_size; + RECT *rects; + int i; + HRGN gdi_region; + cairo_status_t status; + cairo_region_t *region; + + /* The semantics we want is that any clip set by cairo combines + * is intersected with the clip on device context that the + * surface was created for. To implement this, we need to + * save the original clip when first setting a clip on surface. + */ + + assert (_cairo_clip_is_region (clip)); + region = _cairo_clip_get_region (clip); + if (region == NULL) + return CAIRO_STATUS_SUCCESS; + + cairo_region_get_extents (region, &extents); + num_rects = cairo_region_num_rectangles (region); + + /* XXX see notes in _cairo_win32_save_initial_clip -- + * this code will interact badly with a HDC which had an initial + * world transform -- we should probably manually transform the + * region rects, because SelectClipRgn takes device units, not + * logical units (unlike IntersectClipRect). + */ + + data_size = sizeof (RGNDATAHEADER) + num_rects * sizeof (RECT); + if (data_size > sizeof (stack)) { + data = _cairo_malloc (data_size); + if (!data) + return _cairo_error(CAIRO_STATUS_NO_MEMORY); + } else + data = (RGNDATA *)stack; + + data->rdh.dwSize = sizeof (RGNDATAHEADER); + data->rdh.iType = RDH_RECTANGLES; + data->rdh.nCount = num_rects; + data->rdh.nRgnSize = num_rects * sizeof (RECT); + data->rdh.rcBound.left = extents.x; + data->rdh.rcBound.top = extents.y; + data->rdh.rcBound.right = extents.x + extents.width; + data->rdh.rcBound.bottom = extents.y + extents.height; + + rects = (RECT *)data->Buffer; + for (i = 0; i < num_rects; i++) { + cairo_rectangle_int_t rect; + + cairo_region_get_rectangle (region, i, &rect); + + rects[i].left = rect.x; + rects[i].top = rect.y; + rects[i].right = rect.x + rect.width; + rects[i].bottom = rect.y + rect.height; + } + + gdi_region = ExtCreateRegion (NULL, data_size, data); + if ((char *)data != stack) + free (data); + + if (!gdi_region) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + /* AND the new region into our DC */ + status = CAIRO_STATUS_SUCCESS; + if (ExtSelectClipRgn (surface->win32.dc, gdi_region, RGN_AND) == ERROR) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "ExtSelectClipRgn"); + status = _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); + } + + DeleteObject (gdi_region); + + return status; +} + +void +_cairo_win32_display_surface_unset_clip (cairo_win32_display_surface_t *surface) +{ + XFORM saved_xform; + int gm = GetGraphicsMode (surface->win32.dc); + if (gm == GM_ADVANCED) { + GetWorldTransform (surface->win32.dc, &saved_xform); + ModifyWorldTransform (surface->win32.dc, NULL, MWT_IDENTITY); + } + + /* initial_clip_rgn will either be a real region or NULL (which means reset to no clip region) */ + SelectClipRgn (surface->win32.dc, surface->initial_clip_rgn); + + if (surface->had_simple_clip) { + /* then if we had a simple clip, intersect */ + IntersectClipRect (surface->win32.dc, + surface->win32.extents.x, + surface->win32.extents.y, + surface->win32.extents.x + surface->win32.extents.width, + surface->win32.extents.y + surface->win32.extents.height); + } + + if (gm == GM_ADVANCED) + SetWorldTransform (surface->win32.dc, &saved_xform); +} + +void +_cairo_win32_display_surface_discard_fallback (cairo_win32_display_surface_t *surface) +{ + if (surface->fallback) { + TRACE ((stderr, "%s (surface=%d)\n", + __FUNCTION__, surface->win32.base.unique_id)); + + cairo_surface_finish (surface->fallback); + cairo_surface_destroy (surface->fallback); + surface->fallback = NULL; + } +} + +static cairo_int_status_t +_cairo_win32_display_surface_paint (void *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip) +{ + cairo_win32_device_t *device = to_win32_device_from_surface (surface); + + TRACE ((stderr, "%s (surface=%d)\n", + __FUNCTION__, to_win32_surface(surface)->base.unique_id)); + + if (clip == NULL && + (op == CAIRO_OPERATOR_SOURCE || op == CAIRO_OPERATOR_CLEAR)) + _cairo_win32_display_surface_discard_fallback (surface); + + return _cairo_compositor_paint (device->compositor, + surface, op, source, clip); +} + +static cairo_int_status_t +_cairo_win32_display_surface_mask (void *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_pattern_t *mask, + const cairo_clip_t *clip) +{ + cairo_win32_device_t *device = to_win32_device_from_surface (surface); + + TRACE ((stderr, "%s (surface=%d)\n", + __FUNCTION__, to_win32_surface(surface)->base.unique_id)); + + if (clip == NULL && op == CAIRO_OPERATOR_SOURCE) + _cairo_win32_display_surface_discard_fallback (surface); + + return _cairo_compositor_mask (device->compositor, + surface, op, source, mask, clip); +} + +static cairo_int_status_t +_cairo_win32_display_surface_stroke (void *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_win32_device_t *device = to_win32_device_from_surface (surface); + + TRACE ((stderr, "%s (surface=%d)\n", + __FUNCTION__, to_win32_surface(surface)->base.unique_id)); + + return _cairo_compositor_stroke (device->compositor, surface, + op, source, path, + style, ctm, ctm_inverse, + tolerance, antialias, clip); +} + +static cairo_int_status_t +_cairo_win32_display_surface_fill (void *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_win32_device_t *device = to_win32_device_from_surface (surface); + + TRACE ((stderr, "%s (surface=%d)\n", + __FUNCTION__, to_win32_surface(surface)->base.unique_id)); + + return _cairo_compositor_fill (device->compositor, surface, + op, source, path, + fill_rule, tolerance, antialias, + clip); +} + +static cairo_int_status_t +_cairo_win32_display_surface_glyphs (void *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip) +{ + cairo_win32_device_t *device = to_win32_device_from_surface (surface); + + TRACE ((stderr, "%s (surface=%d)\n", + __FUNCTION__, to_win32_surface(surface)->base.unique_id)); + + return _cairo_compositor_glyphs (device->compositor, surface, + op, source, + glyphs, num_glyphs, scaled_font, + clip); +} + +static const cairo_surface_backend_t cairo_win32_display_surface_backend = { + CAIRO_SURFACE_TYPE_WIN32, + _cairo_win32_display_surface_finish, + + _cairo_default_context_create, + + _cairo_win32_display_surface_create_similar, + _cairo_win32_display_surface_create_similar_image, + _cairo_win32_display_surface_map_to_image, + _cairo_win32_display_surface_unmap_image, + + _cairo_surface_default_source, + _cairo_surface_default_acquire_source_image, + _cairo_surface_default_release_source_image, + NULL, /* snapshot */ + + NULL, /* copy_page */ + NULL, /* show_page */ + + _cairo_win32_surface_get_extents, + NULL, /* get_font_options */ + + _cairo_win32_display_surface_flush, + _cairo_win32_display_surface_mark_dirty, + + _cairo_win32_display_surface_paint, + _cairo_win32_display_surface_mask, + _cairo_win32_display_surface_stroke, + _cairo_win32_display_surface_fill, + NULL, /* fill/stroke */ + _cairo_win32_display_surface_glyphs, +}; + +/* Notes: + * + * Win32 alpha-understanding functions + * + * BitBlt - will copy full 32 bits from a 32bpp DIB to result + * (so it's safe to use for ARGB32->ARGB32 SOURCE blits) + * (but not safe going RGB24->ARGB32, if RGB24 is also represented + * as a 32bpp DIB, since the alpha isn't discarded!) + * + * AlphaBlend - if both the source and dest have alpha, even if AC_SRC_ALPHA isn't set, + * it will still copy over the src alpha, because the SCA value (255) will be + * multiplied by all the src components. + */ + +/** + * cairo_win32_surface_create_with_format: + * @hdc: the DC to create a surface for + * @format: format of pixels in the surface to create + * + * Creates a cairo surface that targets the given DC. The DC will be + * queried for its initial clip extents, and this will be used as the + * size of the cairo surface. + * + * Supported formats are: + * %CAIRO_FORMAT_ARGB32 + * %CAIRO_FORMAT_RGB24 + * + * Note: @format only tells cairo how to draw on the surface, not what + * the format of the surface is. Namely, cairo does not (and cannot) + * check that @hdc actually supports alpha-transparency. + * + * Return value: the newly created surface, NULL on failure + * + * Since: 1.14 + **/ +cairo_surface_t * +cairo_win32_surface_create_with_format (HDC hdc, cairo_format_t format) +{ + cairo_win32_display_surface_t *surface; + + cairo_status_t status; + cairo_device_t *device; + + switch (format) { + case CAIRO_FORMAT_INVALID: + case CAIRO_FORMAT_A8: + case CAIRO_FORMAT_A1: + case CAIRO_FORMAT_RGB16_565: + case CAIRO_FORMAT_RGB30: + case CAIRO_FORMAT_RGB96F: + case CAIRO_FORMAT_RGBA128F: + default: + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); + case CAIRO_FORMAT_ARGB32: + case CAIRO_FORMAT_RGB24: + break; + } + + surface = _cairo_calloc (sizeof (*surface)); + if (surface == NULL) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + + status = _cairo_win32_save_initial_clip (hdc, surface); + if (status) { + free (surface); + return _cairo_surface_create_in_error (status); + } + + surface->image = NULL; + surface->fallback = NULL; + surface->win32.format = format; + + surface->win32.dc = hdc; + surface->bitmap = NULL; + surface->is_dib = FALSE; + surface->saved_dc_bitmap = NULL; + + surface->win32.flags = _cairo_win32_flags_for_dc (surface->win32.dc, format); + + device = _cairo_win32_device_get (); + + _cairo_surface_init (&surface->win32.base, + &cairo_win32_display_surface_backend, + device, + _cairo_content_from_format (format), + FALSE); /* is_vector */ + + cairo_device_destroy (device); + + return &surface->win32.base; +} + +/** + * cairo_win32_surface_create: + * @hdc: the DC to create a surface for + * + * Creates a cairo surface that targets the given DC. The DC will be + * queried for its initial clip extents, and this will be used as the + * size of the cairo surface. The resulting surface will always be of + * format %CAIRO_FORMAT_RGB24; should you need another surface format, + * you will need to create one through + * cairo_win32_surface_create_with_format() or + * cairo_win32_surface_create_with_dib(). + * + * Return value: the newly created surface, NULL on failure + * + * Since: 1.0 + **/ +cairo_surface_t * +cairo_win32_surface_create (HDC hdc) +{ + return cairo_win32_surface_create_with_format (hdc, CAIRO_FORMAT_RGB24); +} + +/** + * cairo_win32_surface_create_with_dib: + * @format: format of pixels in the surface to create + * @width: width of the surface, in pixels + * @height: height of the surface, in pixels + * + * Creates a device-independent-bitmap surface not associated with + * any particular existing surface or device context. The created + * bitmap will be uninitialized. + * + * Return value: the newly created surface + * + * Since: 1.2 + **/ +cairo_surface_t * +cairo_win32_surface_create_with_dib (cairo_format_t format, + int width, + int height) +{ + if (! CAIRO_FORMAT_VALID (format)) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); + + return _cairo_win32_display_surface_create_for_dc (NULL, format, width, height); +} + +/** + * cairo_win32_surface_create_with_ddb: + * @hdc: a DC compatible with the surface to create + * @format: format of pixels in the surface to create + * @width: width of the surface, in pixels + * @height: height of the surface, in pixels + * + * Creates a device-dependent-bitmap surface not associated with + * any particular existing surface or device context. The created + * bitmap will be uninitialized. + * + * Return value: the newly created surface + * + * Since: 1.4 + **/ +cairo_surface_t * +cairo_win32_surface_create_with_ddb (HDC hdc, + cairo_format_t format, + int width, + int height) +{ + cairo_win32_display_surface_t *new_surf; + HBITMAP ddb; + HDC screen_dc, ddb_dc; + HBITMAP saved_dc_bitmap; + + switch (format) { +/* XXX handle these eventually */ + case CAIRO_FORMAT_INVALID: + case CAIRO_FORMAT_A8: + case CAIRO_FORMAT_A1: + case CAIRO_FORMAT_RGB16_565: + case CAIRO_FORMAT_RGB30: + case CAIRO_FORMAT_RGB96F: + case CAIRO_FORMAT_RGBA128F: + default: + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); + case CAIRO_FORMAT_ARGB32: + case CAIRO_FORMAT_RGB24: + break; + } + + if (!hdc) { + screen_dc = GetDC (NULL); + hdc = screen_dc; + } else { + screen_dc = NULL; + } + + ddb_dc = CreateCompatibleDC (hdc); + if (ddb_dc == NULL) { + new_surf = (cairo_win32_display_surface_t*) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + goto FINISH; + } + + ddb = CreateCompatibleBitmap (hdc, width, height); + if (ddb == NULL) { + DeleteDC (ddb_dc); + + /* Note that if an app actually does hit this out of memory + * condition, it's going to have lots of other issues, as + * video memory is probably exhausted. However, it can often + * continue using DIBs instead of DDBs. + */ + new_surf = (cairo_win32_display_surface_t*) _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + goto FINISH; + } + + saved_dc_bitmap = SelectObject (ddb_dc, ddb); + + new_surf = (cairo_win32_display_surface_t*) cairo_win32_surface_create (ddb_dc); + new_surf->bitmap = ddb; + new_surf->saved_dc_bitmap = saved_dc_bitmap; + new_surf->is_dib = FALSE; + +FINISH: + if (screen_dc) + ReleaseDC (NULL, screen_dc); + + return &new_surf->win32.base; +} diff --git a/local/recipes/libs/cairo/source/src/win32/cairo-win32-font.c b/local/recipes/libs/cairo/source/src/win32/cairo-win32-font.c new file mode 100644 index 0000000000..1412c8bbc6 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/win32/cairo-win32-font.c @@ -0,0 +1,2126 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + */ + +#include "cairoint.h" + +#include "cairo-win32-private.h" + +#include "cairo-array-private.h" +#include "cairo-error-private.h" +#include "cairo-image-surface-private.h" +#include "cairo-pattern-private.h" +#include "cairo-scaled-font-subsets-private.h" + +#include + +#define CMAP_TAG 0x70616d63 + +/** + * SECTION:cairo-win32-fonts + * @Title: Win32 GDI Fonts + * @Short_Description: Font support for Microsoft Windows + * @See_Also: #cairo_font_face_t + * + * The Microsoft Windows font backend is primarily used to render text on + * Microsoft Windows systems. + * + * Note: Win32 GDI fonts do not support color fonts. Use DWrite fonts + * if color font support is required. + **/ + +/** + * CAIRO_HAS_WIN32_FONT: + * + * Defined if the Microsoft Windows font backend is available. + * This macro can be used to conditionally compile backend-specific code. + * + * Since: 1.8 + **/ + +const cairo_scaled_font_backend_t _cairo_win32_scaled_font_backend; + +typedef struct { + cairo_scaled_font_t base; + + LOGFONTW logfont; + + BYTE quality; + + /* We do drawing and metrics computation in a "logical space" which + * is similar to font space, except that it is scaled by a factor + * of the (desired font size) * (WIN32_FONT_LOGICAL_SCALE). The multiplication + * by WIN32_FONT_LOGICAL_SCALE allows for sub-pixel precision. + */ + double logical_scale; + + /* The size we should actually request the font at from Windows; differs + * from the logical_scale because it is quantized for orthogonal + * transformations + */ + double logical_size; + + /* Transformations from device <=> logical space + */ + cairo_matrix_t logical_to_device; + cairo_matrix_t device_to_logical; + + /* We special case combinations of 90-degree-rotations, scales and + * flips ... that is transformations that take the axes to the + * axes. If preserve_axes is true, then swap_axes/swap_x/swap_y + * encode the 8 possibilities for orientation (4 rotation angles with + * and without a flip), and scale_x, scale_y the scale components. + */ + cairo_bool_t preserve_axes; + cairo_bool_t swap_axes; + cairo_bool_t swap_x; + cairo_bool_t swap_y; + double x_scale; + double y_scale; + + /* The size of the design unit of the font + */ + int em_square; + + HFONT scaled_hfont; + HFONT unscaled_hfont; + + cairo_bool_t is_bitmap; + cairo_bool_t is_type1; + cairo_bool_t delete_scaled_hfont; + cairo_bool_t has_type1_notdef_index; + unsigned long type1_notdef_index; +} cairo_win32_scaled_font_t; + +static cairo_status_t +_cairo_win32_scaled_font_set_metrics (cairo_win32_scaled_font_t *scaled_font); + +static cairo_status_t +_cairo_win32_scaled_font_init_glyph_metrics (cairo_win32_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph); + +static cairo_status_t +_cairo_win32_scaled_font_init_glyph_surface (cairo_win32_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph); + +static cairo_status_t +_cairo_win32_scaled_font_init_glyph_path (cairo_win32_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph); + +#define NEARLY_ZERO(d) (fabs(d) < (1. / 65536.)) + +static HDC +_get_global_font_dc (void) +{ + static DWORD hdc_tls_index; + HDC hdc; + + if (!hdc_tls_index) { + CAIRO_MUTEX_LOCK (_cairo_win32_font_dc_mutex); + if (!hdc_tls_index) { + hdc_tls_index = TlsAlloc (); + assert (hdc_tls_index != TLS_OUT_OF_INDEXES); + } + CAIRO_MUTEX_UNLOCK (_cairo_win32_font_dc_mutex); + } + + hdc = TlsGetValue (hdc_tls_index); + if (!hdc) { + hdc = CreateCompatibleDC (NULL); + if (!hdc) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "CreateCompatibleDC"); + return NULL; + } + + if (!SetGraphicsMode (hdc, GM_ADVANCED)) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "SetGraphicsMode"); + DeleteDC (hdc); + return NULL; + } + + if (!TlsSetValue (hdc_tls_index, hdc)) { + DeleteDC (hdc); + return NULL; + } + } + + return hdc; +} + +static cairo_status_t +_compute_transform (cairo_win32_scaled_font_t *scaled_font, + cairo_matrix_t *sc) +{ + cairo_status_t status; + + if (NEARLY_ZERO (sc->yx) && NEARLY_ZERO (sc->xy) && + !NEARLY_ZERO(sc->xx) && !NEARLY_ZERO(sc->yy)) { + scaled_font->preserve_axes = TRUE; + scaled_font->x_scale = sc->xx; + scaled_font->swap_x = (sc->xx < 0); + scaled_font->y_scale = sc->yy; + scaled_font->swap_y = (sc->yy < 0); + scaled_font->swap_axes = FALSE; + + } else if (NEARLY_ZERO (sc->xx) && NEARLY_ZERO (sc->yy) && + !NEARLY_ZERO(sc->yx) && !NEARLY_ZERO(sc->xy)) { + scaled_font->preserve_axes = TRUE; + scaled_font->x_scale = sc->yx; + scaled_font->swap_x = (sc->yx < 0); + scaled_font->y_scale = sc->xy; + scaled_font->swap_y = (sc->xy < 0); + scaled_font->swap_axes = TRUE; + + } else { + scaled_font->preserve_axes = FALSE; + scaled_font->swap_x = scaled_font->swap_y = scaled_font->swap_axes = FALSE; + } + + if (scaled_font->preserve_axes) { + if (scaled_font->swap_x) + scaled_font->x_scale = - scaled_font->x_scale; + if (scaled_font->swap_y) + scaled_font->y_scale = - scaled_font->y_scale; + + scaled_font->logical_scale = WIN32_FONT_LOGICAL_SCALE * scaled_font->y_scale; + scaled_font->logical_size = WIN32_FONT_LOGICAL_SCALE * + _cairo_lround (scaled_font->y_scale); + } + + /* The font matrix has x and y "scale" components which we extract and + * use as character scale values. + */ + cairo_matrix_init (&scaled_font->logical_to_device, + sc->xx, sc->yx, sc->xy, sc->yy, 0, 0); + + if (!scaled_font->preserve_axes) { + status = _cairo_matrix_compute_basis_scale_factors (&scaled_font->logical_to_device, + &scaled_font->x_scale, &scaled_font->y_scale, + TRUE); /* XXX: Handle vertical text */ + if (status) + return status; + + scaled_font->logical_size = + _cairo_lround (WIN32_FONT_LOGICAL_SCALE * scaled_font->y_scale); + scaled_font->logical_scale = + WIN32_FONT_LOGICAL_SCALE * scaled_font->y_scale; + } + + cairo_matrix_scale (&scaled_font->logical_to_device, + 1.0 / scaled_font->logical_scale, + 1.0 / scaled_font->logical_scale); + + scaled_font->device_to_logical = scaled_font->logical_to_device; + + status = cairo_matrix_invert (&scaled_font->device_to_logical); + if (status) + cairo_matrix_init_identity (&scaled_font->device_to_logical); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_bool_t +_have_cleartype_quality (void) +{ + OSVERSIONINFO version_info; + + version_info.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); + + if (!GetVersionEx (&version_info)) { + _cairo_win32_print_api_error (__FUNCTION__, "GetVersionEx"); + return FALSE; + } + + return (version_info.dwMajorVersion > 5 || + (version_info.dwMajorVersion == 5 && + version_info.dwMinorVersion >= 1)); /* XP or newer */ +} + +BYTE +cairo_win32_get_system_text_quality (void) +{ + BOOL font_smoothing; + UINT smoothing_type; + + if (!SystemParametersInfo (SPI_GETFONTSMOOTHING, 0, &font_smoothing, 0)) { + _cairo_win32_print_api_error (__FUNCTION__, "SystemParametersInfo"); + return DEFAULT_QUALITY; + } + + if (font_smoothing) { + if (_have_cleartype_quality ()) { + if (!SystemParametersInfo (SPI_GETFONTSMOOTHINGTYPE, + 0, &smoothing_type, 0)) { + _cairo_win32_print_api_error (__FUNCTION__, "SystemParametersInfo"); + return DEFAULT_QUALITY; + } + + if (smoothing_type == FE_FONTSMOOTHINGCLEARTYPE) + return CLEARTYPE_QUALITY; + } + + return ANTIALIASED_QUALITY; + } else { + return DEFAULT_QUALITY; + } +} + +/* If face_hfont is non-%NULL then font_matrix must be a simple scale by some + * factor S, ctm must be the identity, logfont->lfHeight must be -S, + * logfont->lfWidth, logfont->lfEscapement, logfont->lfOrientation must + * all be 0, and face_hfont is the result of calling CreateFontIndirectW on + * logfont. + */ +static cairo_status_t +_win32_scaled_font_create (LOGFONTW *logfont, + HFONT face_hfont, + cairo_font_face_t *font_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **font_out) +{ + HDC hdc; + cairo_win32_scaled_font_t *f; + cairo_matrix_t scale; + cairo_status_t status; + + hdc = _get_global_font_dc (); + if (hdc == NULL) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + f = _cairo_calloc (sizeof(cairo_win32_scaled_font_t)); + if (f == NULL) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + f->logfont = *logfont; + + /* We don't have any control over the hinting style or subpixel + * order in the Win32 font API, so we ignore those parts of + * cairo_font_options_t. We use the 'antialias' field to set + * the 'quality'. + * + * XXX: The other option we could pay attention to, but don't + * here is the hint_metrics options. + */ + if (options->antialias == CAIRO_ANTIALIAS_DEFAULT) + f->quality = cairo_win32_get_system_text_quality (); + else { + switch (options->antialias) { + case CAIRO_ANTIALIAS_NONE: + f->quality = NONANTIALIASED_QUALITY; + break; + case CAIRO_ANTIALIAS_GRAY: + case CAIRO_ANTIALIAS_FAST: + case CAIRO_ANTIALIAS_GOOD: + f->quality = ANTIALIASED_QUALITY; + break; + case CAIRO_ANTIALIAS_SUBPIXEL: + case CAIRO_ANTIALIAS_BEST: + if (_have_cleartype_quality ()) + f->quality = CLEARTYPE_QUALITY; + else + f->quality = ANTIALIASED_QUALITY; + break; + case CAIRO_ANTIALIAS_DEFAULT: + ASSERT_NOT_REACHED; + } + } + + f->em_square = 0; + f->scaled_hfont = NULL; + f->unscaled_hfont = NULL; + f->has_type1_notdef_index = FALSE; + + if (f->quality == logfont->lfQuality || + (logfont->lfQuality == DEFAULT_QUALITY && + options->antialias == CAIRO_ANTIALIAS_DEFAULT)) { + /* If face_hfont is non-NULL, then we can use it to avoid creating our + * own --- because the constraints on face_hfont mentioned above + * guarantee it was created in exactly the same way that + * _win32_scaled_font_get_scaled_hfont would create it. + */ + f->scaled_hfont = face_hfont; + } + /* don't delete the hfont if we're using the one passed in to us */ + f->delete_scaled_hfont = !f->scaled_hfont; + + cairo_matrix_multiply (&scale, font_matrix, ctm); + status = _compute_transform (f, &scale); + if (status) + goto FAIL; + + status = _cairo_scaled_font_init (&f->base, font_face, + font_matrix, ctm, options, + &_cairo_win32_scaled_font_backend); + if (status) + goto FAIL; + + status = _cairo_win32_scaled_font_set_metrics (f); + if (status) { + _cairo_scaled_font_fini (&f->base); + goto FAIL; + } + + *font_out = &f->base; + return CAIRO_STATUS_SUCCESS; + + FAIL: + free (f); + return status; +} + +static cairo_status_t +_win32_scaled_font_set_world_transform (cairo_win32_scaled_font_t *scaled_font, + HDC hdc) +{ + XFORM xform; + + _cairo_matrix_to_win32_xform (&scaled_font->logical_to_device, &xform); + + if (!SetWorldTransform (hdc, &xform)) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "SetWorldTransform"); + return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_win32_scaled_font_set_identity_transform (HDC hdc) +{ + if (!ModifyWorldTransform (hdc, NULL, MWT_IDENTITY)) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "ModifyWorldTransform"); + return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_win32_scaled_font_get_scaled_hfont (cairo_win32_scaled_font_t *scaled_font, + HFONT *hfont_out) +{ + if (!scaled_font->scaled_hfont) { + LOGFONTW logfont = scaled_font->logfont; + logfont.lfHeight = -scaled_font->logical_size; + logfont.lfWidth = 0; + logfont.lfEscapement = 0; + logfont.lfOrientation = 0; + logfont.lfQuality = scaled_font->quality; + + scaled_font->scaled_hfont = CreateFontIndirectW (&logfont); + if (!scaled_font->scaled_hfont) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "CreateFontIndirect"); + return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); + } + } + + *hfont_out = scaled_font->scaled_hfont; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_win32_scaled_font_get_unscaled_hfont (cairo_win32_scaled_font_t *scaled_font, + HDC hdc, + HFONT *hfont_out) +{ + if (scaled_font->unscaled_hfont == NULL) { + OUTLINETEXTMETRIC *otm; + unsigned int otm_size; + HFONT scaled_hfont; + LOGFONTW logfont; + cairo_status_t status; + + status = _win32_scaled_font_get_scaled_hfont (scaled_font, + &scaled_hfont); + if (status) + return status; + + if (! SelectObject (hdc, scaled_hfont)) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "SelectObject"); + return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); + } + + otm_size = GetOutlineTextMetrics (hdc, 0, NULL); + if (! otm_size) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "GetOutlineTextMetrics"); + return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); + } + + otm = _cairo_malloc (otm_size); + if (otm == NULL) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + if (! GetOutlineTextMetrics (hdc, otm_size, otm)) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "GetOutlineTextMetrics"); + free (otm); + return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); + } + + scaled_font->em_square = otm->otmEMSquare; + free (otm); + otm = NULL; + + logfont = scaled_font->logfont; + logfont.lfHeight = -scaled_font->em_square; + logfont.lfWidth = 0; + logfont.lfEscapement = 0; + logfont.lfOrientation = 0; + logfont.lfQuality = scaled_font->quality; + + scaled_font->unscaled_hfont = CreateFontIndirectW (&logfont); + if (! scaled_font->unscaled_hfont) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "CreateFontIndirect"); + return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); + } + } + + *hfont_out = scaled_font->unscaled_hfont; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_win32_scaled_font_select_unscaled_font (cairo_scaled_font_t *scaled_font, + HDC hdc) +{ + cairo_status_t status; + HFONT hfont; + HFONT old_hfont = NULL; + + status = _win32_scaled_font_get_unscaled_hfont ((cairo_win32_scaled_font_t *)scaled_font, hdc, &hfont); + if (status) + return status; + + old_hfont = SelectObject (hdc, hfont); + if (!old_hfont) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "CreateSolidBrush"); + return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); + } + + status = _win32_scaled_font_set_identity_transform (hdc); + if (status) { + SelectObject (hdc, old_hfont); + return status; + } + + SetMapMode (hdc, MM_TEXT); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_bool_t +_cairo_win32_scaled_font_is_type1 (cairo_scaled_font_t *scaled_font) +{ + cairo_win32_scaled_font_t *win32_scaled_font; + + win32_scaled_font = (cairo_win32_scaled_font_t *) scaled_font; + + return win32_scaled_font->is_type1; +} + +cairo_bool_t +_cairo_win32_scaled_font_is_bitmap (cairo_scaled_font_t *scaled_font) +{ + cairo_win32_scaled_font_t *win32_scaled_font; + + win32_scaled_font = (cairo_win32_scaled_font_t *) scaled_font; + + return win32_scaled_font->is_bitmap; +} + +static void +_cairo_win32_scaled_font_done_unscaled_font (cairo_scaled_font_t *scaled_font) +{ +} + +/* implement the font backend interface */ + +static cairo_status_t +_cairo_win32_font_face_create_for_toy (cairo_toy_font_face_t *toy_face, + cairo_font_face_t **font_face) +{ + LOGFONTW logfont; + uint16_t *face_name; + int face_name_len; + cairo_status_t status; + + status = _cairo_utf8_to_utf16 (toy_face->family, -1, + &face_name, &face_name_len); + if (status) + return status; + + if (face_name_len > LF_FACESIZE - 1) + face_name_len = LF_FACESIZE - 1; + + memcpy (logfont.lfFaceName, face_name, sizeof (uint16_t) * face_name_len); + logfont.lfFaceName[face_name_len] = 0; + free (face_name); + + logfont.lfHeight = 0; /* filled in later */ + logfont.lfWidth = 0; /* filled in later */ + logfont.lfEscapement = 0; /* filled in later */ + logfont.lfOrientation = 0; /* filled in later */ + + switch (toy_face->weight) { + case CAIRO_FONT_WEIGHT_NORMAL: + default: + logfont.lfWeight = FW_NORMAL; + break; + case CAIRO_FONT_WEIGHT_BOLD: + logfont.lfWeight = FW_BOLD; + break; + } + + switch (toy_face->slant) { + case CAIRO_FONT_SLANT_NORMAL: + default: + logfont.lfItalic = FALSE; + break; + case CAIRO_FONT_SLANT_ITALIC: + case CAIRO_FONT_SLANT_OBLIQUE: + logfont.lfItalic = TRUE; + break; + } + + logfont.lfUnderline = FALSE; + logfont.lfStrikeOut = FALSE; + /* The docs for LOGFONT discourage using this, since the + * interpretation is locale-specific, but it's not clear what + * would be a better alternative. + */ + logfont.lfCharSet = DEFAULT_CHARSET; + logfont.lfOutPrecision = OUT_DEFAULT_PRECIS; + logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS; + logfont.lfQuality = DEFAULT_QUALITY; /* filled in later */ + logfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; + + *font_face = cairo_win32_font_face_create_for_logfontw (&logfont); + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_win32_scaled_font_fini (void *abstract_font) +{ + cairo_win32_scaled_font_t *scaled_font = abstract_font; + + if (scaled_font == NULL) + return; + + if (scaled_font->scaled_hfont && scaled_font->delete_scaled_hfont) + DeleteObject (scaled_font->scaled_hfont); + + if (scaled_font->unscaled_hfont) + DeleteObject (scaled_font->unscaled_hfont); +} + +static unsigned long +_cairo_win32_scaled_font_ucs4_to_index (void *abstract_font, + uint32_t ucs4) +{ + cairo_win32_scaled_font_t *scaled_font = abstract_font; + wchar_t unicode[2]; + WORD glyph_index; + HDC hdc = NULL; + cairo_status_t status; + + hdc = _get_global_font_dc (); + assert (hdc != NULL); + + status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc); + if (status) + return 0; + + unicode[0] = ucs4; + unicode[1] = 0; + if (GetGlyphIndicesW (hdc, unicode, 1, &glyph_index, 0) == GDI_ERROR) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "GetGlyphIndices"); + glyph_index = 0; + } + + cairo_win32_scaled_font_done_font (&scaled_font->base); + + return glyph_index; +} + +static cairo_status_t +_cairo_win32_scaled_font_set_metrics (cairo_win32_scaled_font_t *scaled_font) +{ + cairo_status_t status; + cairo_font_extents_t extents; + + TEXTMETRIC metrics = {0}; + HDC hdc; + + hdc = _get_global_font_dc (); + assert (hdc != NULL); + + if (scaled_font->preserve_axes || scaled_font->base.options.hint_metrics == CAIRO_HINT_METRICS_OFF) { + /* For 90-degree rotations (including 0), we get the metrics + * from the GDI in logical space, then convert back to font space + */ + status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc); + if (status) + return status; + + if (!GetTextMetrics (hdc, &metrics)) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "GetTextMetrics"); + status = _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); + } + + cairo_win32_scaled_font_done_font (&scaled_font->base); + if (status) + return status; + + extents.ascent = metrics.tmAscent / scaled_font->logical_scale; + extents.descent = metrics.tmDescent / scaled_font->logical_scale; + + extents.height = (metrics.tmHeight + metrics.tmExternalLeading) / scaled_font->logical_scale; + extents.max_x_advance = metrics.tmMaxCharWidth / scaled_font->logical_scale; + extents.max_y_advance = 0; + + } else { + /* For all other transformations, we use the design metrics + * of the font. The GDI results from GetTextMetrics() on a + * transformed font are inexplicably large and we want to + * avoid them. + */ + status = _cairo_win32_scaled_font_select_unscaled_font (&scaled_font->base, hdc); + if (status) + return status; + GetTextMetrics (hdc, &metrics); + _cairo_win32_scaled_font_done_unscaled_font (&scaled_font->base); + + extents.ascent = (double)metrics.tmAscent / scaled_font->em_square; + extents.descent = (double)metrics.tmDescent / scaled_font->em_square; + extents.height = (double)(metrics.tmHeight + metrics.tmExternalLeading) / scaled_font->em_square; + extents.max_x_advance = (double)(metrics.tmMaxCharWidth) / scaled_font->em_square; + extents.max_y_advance = 0; + + } + + scaled_font->is_bitmap = !(metrics.tmPitchAndFamily & TMPF_VECTOR); + + /* Need to determine if this is a Type 1 font for the special + * handling in _text_to_glyphs. Unlike TrueType or OpenType, + * Type1 fonts do not have a "cmap" table (or any other table). + * However GetFontData() will retrieve a Type1 font when + * requesting that GetFontData() retrieve data from the start of + * the file. This is to distinguish Type1 from stroke fonts such + * as "Script" and "Modern". The TMPF_TRUETYPE test is redundant + * but improves performance for the most common fonts. + */ + scaled_font->is_type1 = FALSE; + if (!(metrics.tmPitchAndFamily & TMPF_TRUETYPE) && + (metrics.tmPitchAndFamily & TMPF_VECTOR)) + { + if ((GetFontData (hdc, CMAP_TAG, 0, NULL, 0) == GDI_ERROR) && + (GetFontData (hdc, 0, 0, NULL, 0) != GDI_ERROR)) + { + scaled_font->is_type1 = TRUE; + } + } + + return _cairo_scaled_font_set_metrics (&scaled_font->base, &extents); +} + +static cairo_status_t +_cairo_win32_scaled_font_init_glyph_metrics (cairo_win32_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph) +{ + static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } }; + GLYPHMETRICS metrics; + cairo_status_t status; + cairo_text_extents_t extents; + HDC hdc; + + hdc = _get_global_font_dc (); + assert (hdc != NULL); + + if (scaled_font->is_bitmap) { + /* GetGlyphOutline will not work. Assume that the glyph does not extend outside the font box. */ + cairo_font_extents_t font_extents; + INT width = 0; + UINT charIndex = _cairo_scaled_glyph_index (scaled_glyph); + + cairo_scaled_font_extents (&scaled_font->base, &font_extents); + + status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc); + if (status) + return status; + + if (!GetCharWidth32(hdc, charIndex, charIndex, &width)) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "GetCharWidth32"); + status = _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); + width = 0; + } + cairo_win32_scaled_font_done_font (&scaled_font->base); + if (status) + return status; + + extents.x_bearing = 0; + extents.y_bearing = scaled_font->base.ctm.yy * (-font_extents.ascent / scaled_font->y_scale); + extents.width = width / (WIN32_FONT_LOGICAL_SCALE * scaled_font->x_scale); + extents.height = scaled_font->base.ctm.yy * (font_extents.ascent + font_extents.descent) / scaled_font->y_scale; + extents.x_advance = extents.width; + extents.y_advance = 0; + } else if (scaled_font->preserve_axes && scaled_font->base.options.hint_metrics != CAIRO_HINT_METRICS_OFF) { + /* If we aren't rotating / skewing the axes, then we get the metrics + * from the GDI in device space and convert to font space. + */ + status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc); + if (status) + return status; + + if (GetGlyphOutlineW (hdc, _cairo_scaled_glyph_index (scaled_glyph), + GGO_METRICS | GGO_GLYPH_INDEX, + &metrics, 0, NULL, &matrix) == GDI_ERROR) { + memset (&metrics, 0, sizeof (GLYPHMETRICS)); + } else { + if (metrics.gmBlackBoxX > 0 && scaled_font->base.options.antialias != CAIRO_ANTIALIAS_NONE) { + /* The bounding box reported by Windows supposedly contains the glyph's "black" area; + * however, antialiasing (especially with ClearType) means that the actual image that + * needs to be rendered may "bleed" into the adjacent pixels, mainly on the right side. + * To avoid clipping the glyphs when drawn by _cairo_surface_fallback_show_glyphs, + * for example, or other code that uses glyph extents to determine the area to update, + * we add a pixel of "slop" to left side of the nominal "black" area returned by GDI, + * and two pixels to the right (as tests show some glyphs bleed into this column). + */ + metrics.gmptGlyphOrigin.x -= 1; + metrics.gmBlackBoxX += 3; + } + } + cairo_win32_scaled_font_done_font (&scaled_font->base); + + if (scaled_font->swap_axes) { + extents.x_bearing = - metrics.gmptGlyphOrigin.y / scaled_font->y_scale; + extents.y_bearing = metrics.gmptGlyphOrigin.x / scaled_font->x_scale; + extents.width = metrics.gmBlackBoxY / scaled_font->y_scale; + extents.height = metrics.gmBlackBoxX / scaled_font->x_scale; + extents.x_advance = metrics.gmCellIncY / scaled_font->x_scale; + extents.y_advance = metrics.gmCellIncX / scaled_font->y_scale; + } else { + extents.x_bearing = metrics.gmptGlyphOrigin.x / scaled_font->x_scale; + extents.y_bearing = - metrics.gmptGlyphOrigin.y / scaled_font->y_scale; + extents.width = metrics.gmBlackBoxX / scaled_font->x_scale; + extents.height = metrics.gmBlackBoxY / scaled_font->y_scale; + extents.x_advance = metrics.gmCellIncX / scaled_font->x_scale; + extents.y_advance = metrics.gmCellIncY / scaled_font->y_scale; + } + + if (scaled_font->swap_x) { + extents.x_bearing = (- extents.x_bearing - extents.width); + extents.x_advance = - extents.x_advance; + } + + if (scaled_font->swap_y) { + extents.y_bearing = (- extents.y_bearing - extents.height); + extents.y_advance = - extents.y_advance; + } + } else { + /* For all other transformations, we use the design metrics + * of the font. + */ + status = _cairo_win32_scaled_font_select_unscaled_font (&scaled_font->base, hdc); + if (status) + return status; + + if (GetGlyphOutlineW (hdc, _cairo_scaled_glyph_index (scaled_glyph), + GGO_METRICS | GGO_GLYPH_INDEX, + &metrics, 0, NULL, &matrix) == GDI_ERROR) { + memset (&metrics, 0, sizeof (GLYPHMETRICS)); + } + _cairo_win32_scaled_font_done_unscaled_font (&scaled_font->base); + + extents.x_bearing = (double)metrics.gmptGlyphOrigin.x / scaled_font->em_square; + extents.y_bearing = - (double)metrics.gmptGlyphOrigin.y / scaled_font->em_square; + extents.width = (double)metrics.gmBlackBoxX / scaled_font->em_square; + extents.height = (double)metrics.gmBlackBoxY / scaled_font->em_square; + extents.x_advance = (double)metrics.gmCellIncX / scaled_font->em_square; + extents.y_advance = (double)metrics.gmCellIncY / scaled_font->em_square; + } + + _cairo_scaled_glyph_set_metrics (scaled_glyph, + &scaled_font->base, + &extents); + + return CAIRO_STATUS_SUCCESS; +} + +/* Not currently used code, but may be useful in the future if we add + * back the capability to the scaled font backend interface to get the + * actual device space bbox rather than computing it from the + * font-space metrics. + */ +#if 0 +static cairo_status_t +_cairo_win32_scaled_font_glyph_bbox (void *abstract_font, + const cairo_glyph_t *glyphs, + int num_glyphs, + cairo_box_t *bbox) +{ + static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 } }; + cairo_win32_scaled_font_t *scaled_font = abstract_font; + int x1 = 0, x2 = 0, y1 = 0, y2 = 0; + + if (num_glyphs > 0) { + HDC hdc; + GLYPHMETRICS metrics; + cairo_status_t status; + int i; + + hdc = _get_global_font_dc (); + assert (hdc != NULL); + + status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc); + if (status) + return status; + + for (i = 0; i < num_glyphs; i++) { + int x = _cairo_lround (glyphs[i].x); + int y = _cairo_lround (glyphs[i].y); + + GetGlyphOutlineW (hdc, glyphs[i].index, GGO_METRICS | GGO_GLYPH_INDEX, + &metrics, 0, NULL, &matrix); + + if (i == 0 || x1 > x + metrics.gmptGlyphOrigin.x) + x1 = x + metrics.gmptGlyphOrigin.x; + if (i == 0 || y1 > y - metrics.gmptGlyphOrigin.y) + y1 = y - metrics.gmptGlyphOrigin.y; + if (i == 0 || x2 < x + metrics.gmptGlyphOrigin.x + (int)metrics.gmBlackBoxX) + x2 = x + metrics.gmptGlyphOrigin.x + (int)metrics.gmBlackBoxX; + if (i == 0 || y2 < y - metrics.gmptGlyphOrigin.y + (int)metrics.gmBlackBoxY) + y2 = y - metrics.gmptGlyphOrigin.y + (int)metrics.gmBlackBoxY; + } + + cairo_win32_scaled_font_done_font (&scaled_font->base); + } + + bbox->p1.x = _cairo_fixed_from_int (x1); + bbox->p1.y = _cairo_fixed_from_int (y1); + bbox->p2.x = _cairo_fixed_from_int (x2); + bbox->p2.y = _cairo_fixed_from_int (y2); + + return CAIRO_STATUS_SUCCESS; +} +#endif + +typedef struct { + cairo_win32_scaled_font_t *scaled_font; + HDC hdc; + + cairo_array_t glyphs; + cairo_array_t dx; + + int start_x; + int last_x; + int last_y; +} cairo_glyph_state_t; + +static void +_start_glyphs (cairo_glyph_state_t *state, + cairo_win32_scaled_font_t *scaled_font, + HDC hdc) +{ + state->hdc = hdc; + state->scaled_font = scaled_font; + + _cairo_array_init (&state->glyphs, sizeof (WCHAR)); + _cairo_array_init (&state->dx, sizeof (int)); +} + +static cairo_status_t +_flush_glyphs (cairo_glyph_state_t *state) +{ + cairo_status_t status; + int dx = 0; + WCHAR * elements; + int * dx_elements; + + status = _cairo_array_append (&state->dx, &dx); + if (status) + return status; + + elements = _cairo_array_index (&state->glyphs, 0); + dx_elements = _cairo_array_index (&state->dx, 0); + if (!ExtTextOutW (state->hdc, + state->start_x, state->last_y, + ETO_GLYPH_INDEX, + NULL, + elements, + state->glyphs.num_elements, + dx_elements)) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "CreateSolidBrush"); + return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); + } + + _cairo_array_truncate (&state->glyphs, 0); + _cairo_array_truncate (&state->dx, 0); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_add_glyph (cairo_glyph_state_t *state, + unsigned long index, + double device_x, + double device_y) +{ + cairo_status_t status; + double user_x = device_x; + double user_y = device_y; + WCHAR glyph_index = index; + int logical_x, logical_y; + + cairo_matrix_transform_point (&state->scaled_font->device_to_logical, &user_x, &user_y); + + logical_x = _cairo_lround (user_x); + logical_y = _cairo_lround (user_y); + + if (state->glyphs.num_elements > 0) { + int dx; + + if (logical_y != state->last_y) { + status = _flush_glyphs (state); + if (status) + return status; + state->start_x = logical_x; + } else { + dx = logical_x - state->last_x; + status = _cairo_array_append (&state->dx, &dx); + if (status) + return status; + } + } else { + state->start_x = logical_x; + } + + state->last_x = logical_x; + state->last_y = logical_y; + + status = _cairo_array_append (&state->glyphs, &glyph_index); + if (status) + return status; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_finish_glyphs (cairo_glyph_state_t *state) +{ + cairo_status_t status; + + status = _flush_glyphs (state); + + _cairo_array_fini (&state->glyphs); + _cairo_array_fini (&state->dx); + + return status; +} + +static cairo_status_t +_draw_glyphs_on_surface (cairo_win32_surface_t *surface, + cairo_win32_scaled_font_t *scaled_font, + COLORREF color, + int x_offset, + int y_offset, + const cairo_glyph_t *glyphs, + int num_glyphs) +{ + cairo_glyph_state_t state; + cairo_status_t status, status2; + int i; + + if (!SaveDC (surface->dc)) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "SaveDC"); + return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); + } + + status = cairo_win32_scaled_font_select_font (&scaled_font->base, surface->dc); + if (status) + goto FAIL1; + + SetTextColor (surface->dc, color); + SetTextAlign (surface->dc, TA_BASELINE | TA_LEFT); + SetBkMode (surface->dc, TRANSPARENT); + + _start_glyphs (&state, scaled_font, surface->dc); + + for (i = 0; i < num_glyphs; i++) { + status = _add_glyph (&state, glyphs[i].index, + glyphs[i].x - x_offset, glyphs[i].y - y_offset); + if (status) + goto FAIL2; + } + + FAIL2: + status2 = _finish_glyphs (&state); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; + + cairo_win32_scaled_font_done_font (&scaled_font->base); + FAIL1: + RestoreDC (surface->dc, -1); + + return status; +} + +static cairo_int_status_t +_cairo_win32_scaled_font_glyph_init (void *abstract_font, + cairo_scaled_glyph_t *scaled_glyph, + cairo_scaled_glyph_info_t info, + const cairo_color_t *foreground_color) +{ + cairo_win32_scaled_font_t *scaled_font = abstract_font; + cairo_status_t status; + + if ((info & CAIRO_SCALED_GLYPH_INFO_METRICS) != 0) { + status = _cairo_win32_scaled_font_init_glyph_metrics (scaled_font, scaled_glyph); + if (status) + return status; + } + + if (info & CAIRO_SCALED_GLYPH_INFO_COLOR_SURFACE) { + scaled_glyph->color_glyph = FALSE; + scaled_glyph->color_glyph_set = TRUE; + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + if (info & CAIRO_SCALED_GLYPH_INFO_SURFACE) { + status = _cairo_win32_scaled_font_init_glyph_surface (scaled_font, scaled_glyph); + if (status) + return status; + } + + if ((info & CAIRO_SCALED_GLYPH_INFO_PATH) != 0) { + status = _cairo_win32_scaled_font_init_glyph_path (scaled_font, scaled_glyph); + if (status) + return status; + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_win32_scaled_font_load_truetype_table (void *abstract_font, + unsigned long tag, + long offset, + unsigned char *buffer, + unsigned long *length) +{ + cairo_win32_scaled_font_t *scaled_font = abstract_font; + HDC hdc; + cairo_status_t status; + DWORD ret; + + hdc = _get_global_font_dc (); + assert (hdc != NULL); + + tag = (tag&0x000000ffu)<<24 | (tag&0x0000ff00)<<8 | (tag&0x00ff0000)>>8 | (tag&0xff000000)>>24; + status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc); + if (status) + return status; + + ret = GetFontData (hdc, tag, offset, buffer, *length); + if (ret == GDI_ERROR || (buffer && ret != *length)) + status = CAIRO_INT_STATUS_UNSUPPORTED; + else + *length = ret; + + cairo_win32_scaled_font_done_font (&scaled_font->base); + + return status; +} + +static cairo_int_status_t +_cairo_win32_scaled_font_index_to_ucs4 (void *abstract_font, + unsigned long index, + uint32_t *ucs4) +{ + cairo_win32_scaled_font_t *scaled_font = abstract_font; + GLYPHSET *glyph_set; + uint16_t *utf16 = NULL; + WORD *glyph_indices = NULL; + HDC hdc = NULL; + int res; + unsigned int i, j, num_glyphs; + cairo_status_t status; + + hdc = _get_global_font_dc (); + assert (hdc != NULL); + + status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc); + if (status) + return status; + + res = GetFontUnicodeRanges(hdc, NULL); + if (res == 0) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "GetFontUnicodeRanges"); + status = _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); + goto exit1; + } + + glyph_set = _cairo_malloc (res); + if (glyph_set == NULL) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto exit1; + } + + res = GetFontUnicodeRanges(hdc, glyph_set); + if (res == 0) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "GetFontUnicodeRanges"); + status = _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); + goto exit1; + } + + *ucs4 = (uint32_t) -1; + for (i = 0; i < glyph_set->cRanges; i++) { + num_glyphs = glyph_set->ranges[i].cGlyphs; + + utf16 = _cairo_malloc_ab (num_glyphs + 1, sizeof (uint16_t)); + if (utf16 == NULL) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto exit1; + } + + glyph_indices = _cairo_malloc_ab (num_glyphs + 1, sizeof (WORD)); + if (glyph_indices == NULL) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto exit2; + } + + for (j = 0; j < num_glyphs; j++) + utf16[j] = glyph_set->ranges[i].wcLow + j; + utf16[j] = 0; + + if (GetGlyphIndicesW (hdc, utf16, num_glyphs, glyph_indices, 0) == GDI_ERROR) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "GetGlyphIndices"); + status = _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); + goto exit2; + } + + for (j = 0; j < num_glyphs; j++) { + if (glyph_indices[j] == index) { + *ucs4 = utf16[j]; + goto exit2; + } + } + + free (glyph_indices); + glyph_indices = NULL; + free (utf16); + utf16 = NULL; + } + +exit2: + free (glyph_indices); + free (utf16); + free (glyph_set); +exit1: + cairo_win32_scaled_font_done_font (&scaled_font->base); + + return status; +} + +static cairo_int_status_t +_cairo_win32_scaled_font_is_synthetic (void *abstract_font, + cairo_bool_t *is_synthetic) +{ + cairo_win32_scaled_font_t *scaled_font = abstract_font; + cairo_status_t status; + int weight; + cairo_bool_t bold; + cairo_bool_t italic; + + *is_synthetic = FALSE; + status = _cairo_truetype_get_style (&scaled_font->base, + &weight, + &bold, + &italic); + /* If this doesn't work assume it is not synthetic to avoid + * unnecessary subsetting fallbacks. */ + if (status != CAIRO_STATUS_SUCCESS) + return CAIRO_STATUS_SUCCESS; + + if (scaled_font->logfont.lfWeight != weight || + scaled_font->logfont.lfItalic != italic) + *is_synthetic = TRUE; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_win32_scaled_font_index_to_glyph_name (void *abstract_font, + char **glyph_names, + int num_glyph_names, + unsigned long glyph_index, + unsigned long *glyph_array_index) +{ + cairo_win32_scaled_font_t *scaled_font = abstract_font; + int i; + + /* Windows puts .notdef at index 0 then numbers the remaining + * glyphs starting from 1 in the order they appear in the font. */ + + /* Find the position of .notdef in the list of glyph names. We + * only need to do this once per scaled font. */ + if (! scaled_font->has_type1_notdef_index) { + for (i = 0; i < num_glyph_names; i++) { + if (strcmp (glyph_names[i], ".notdef") == 0) { + scaled_font->type1_notdef_index = i; + scaled_font->has_type1_notdef_index = TRUE; + break; + } + } + if (! scaled_font->has_type1_notdef_index) + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + /* Once we know the position of .notdef the position of any glyph + * in the font can easily be obtained. */ + if (glyph_index == 0) + *glyph_array_index = scaled_font->type1_notdef_index; + else if (glyph_index <= scaled_font->type1_notdef_index) + *glyph_array_index = glyph_index - 1; + else if (glyph_index < (unsigned long)num_glyph_names) + *glyph_array_index = glyph_index; + else + return CAIRO_INT_STATUS_UNSUPPORTED; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_win32_scaled_font_load_type1_data (void *abstract_font, + long offset, + unsigned char *buffer, + unsigned long *length) +{ + cairo_win32_scaled_font_t *scaled_font = abstract_font; + + if (! scaled_font->is_type1) + return CAIRO_INT_STATUS_UNSUPPORTED; + + /* Using the tag 0 retrieves the entire font file. This works with + * Type 1 fonts as well as TTF/OTF fonts. */ + return _cairo_win32_scaled_font_load_truetype_table (scaled_font, + 0, + offset, + buffer, + length); +} + +cairo_surface_t * +_cairo_compute_glyph_mask (cairo_surface_t *surface, + int quality) +{ + cairo_image_surface_t *glyph; + cairo_image_surface_t *mask; + int i, j; + + glyph = (cairo_image_surface_t *)cairo_surface_map_to_image (surface, NULL); + if (unlikely (glyph->base.status)) + return &glyph->base; + + if (quality == CLEARTYPE_QUALITY) { + /* Duplicate the green channel of a 4-channel mask into the + * alpha channel, then invert the whole mask. + */ + mask = (cairo_image_surface_t *) + cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + glyph->width, glyph->height); + if (likely (mask->base.status == CAIRO_STATUS_SUCCESS)) { + for (i = 0; i < glyph->height; i++) { + uint32_t *p = (uint32_t *) (glyph->data + i * glyph->stride); + uint32_t *q = (uint32_t *) (mask->data + i * mask->stride); + + for (j = 0; j < glyph->width; j++) { + *q++ = 0xffffffff ^ (*p | ((*p & 0x0000ff00) << 16)); + p++; + } + } + } + } else { + /* Compute an alpha-mask from a using the green channel of a + * (presumed monochrome) RGB24 image. + */ + mask = (cairo_image_surface_t *) + cairo_image_surface_create (CAIRO_FORMAT_A8, + glyph->width, glyph->height); + if (likely (mask->base.status == CAIRO_STATUS_SUCCESS)) { + for (i = 0; i < glyph->height; i++) { + uint32_t *p = (uint32_t *) (glyph->data + i * glyph->stride); + uint8_t *q = (uint8_t *) (mask->data + i * mask->stride); + + for (j = 0; j < glyph->width; j++) + *q++ = 255 - ((*p++ & 0x0000ff00) >> 8); + } + } + } + + cairo_surface_unmap_image (surface, &glyph->base); + return &mask->base; +} + +static cairo_status_t +_cairo_win32_scaled_font_init_glyph_surface (cairo_win32_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph) +{ + cairo_status_t status; + cairo_glyph_t glyph; + cairo_surface_t *surface; + cairo_surface_t *image; + int width, height; + int x1, y1, x2, y2; + + x1 = _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x); + y1 = _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y); + x2 = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x); + y2 = _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y); + width = x2 - x1; + height = y2 - y1; + + surface = cairo_win32_surface_create_with_dib (CAIRO_FORMAT_RGB24, + width, height); + status = _cairo_surface_paint (surface, CAIRO_OPERATOR_SOURCE, + &_cairo_pattern_white.base, NULL); + if (status) + goto FAIL; + + glyph.index = _cairo_scaled_glyph_index (scaled_glyph); + glyph.x = -x1; + glyph.y = -y1; + status = _draw_glyphs_on_surface (to_win32_surface (surface), + scaled_font, RGB(0,0,0), + 0, 0, &glyph, 1); + if (status) + goto FAIL; + + image = _cairo_compute_glyph_mask (surface, scaled_font->quality); + status = image->status; + if (status) + goto FAIL; + + cairo_surface_set_device_offset (image, -x1, -y1); + _cairo_scaled_glyph_set_surface (scaled_glyph, + &scaled_font->base, + (cairo_image_surface_t *) image); + + FAIL: + cairo_surface_destroy (surface); + + return status; +} + +static void +_cairo_win32_transform_FIXED_to_fixed (cairo_matrix_t *matrix, + FIXED Fx, FIXED Fy, + cairo_fixed_t *fx, cairo_fixed_t *fy) +{ + double x = Fx.value + Fx.fract / 65536.0; + double y = Fy.value + Fy.fract / 65536.0; + cairo_matrix_transform_point (matrix, &x, &y); + *fx = _cairo_fixed_from_double (x); + *fy = _cairo_fixed_from_double (y); +} + +static cairo_status_t +_cairo_win32_scaled_font_init_glyph_path (cairo_win32_scaled_font_t *scaled_font, + cairo_scaled_glyph_t *scaled_glyph) +{ + static const MAT2 matrix = { { 0, 1 }, { 0, 0 }, { 0, 0 }, { 0, -1 } }; + cairo_status_t status; + GLYPHMETRICS metrics; + HDC hdc; + DWORD bytesGlyph; + unsigned char *buffer, *ptr; + cairo_path_fixed_t *path; + cairo_matrix_t transform; + cairo_fixed_t x, y; + + if (scaled_font->is_bitmap) + return CAIRO_INT_STATUS_UNSUPPORTED; + + hdc = _get_global_font_dc (); + assert (hdc != NULL); + + path = _cairo_path_fixed_create (); + if (!path) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + if (scaled_font->base.options.hint_style == CAIRO_HINT_STYLE_NONE) { + status = _cairo_win32_scaled_font_select_unscaled_font (&scaled_font->base, hdc); + transform = scaled_font->base.scale; + cairo_matrix_scale (&transform, 1.0/scaled_font->em_square, 1.0/scaled_font->em_square); + } else { + status = cairo_win32_scaled_font_select_font (&scaled_font->base, hdc); + cairo_matrix_init_identity(&transform); + } + if (status) + goto CLEANUP_PATH; + + bytesGlyph = GetGlyphOutlineW (hdc, _cairo_scaled_glyph_index (scaled_glyph), + GGO_NATIVE | GGO_GLYPH_INDEX, + &metrics, 0, NULL, &matrix); + + if (bytesGlyph == GDI_ERROR) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "GetGlyphOutline"); + status = _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); + goto CLEANUP_FONT; + } + + ptr = buffer = _cairo_malloc (bytesGlyph); + if (!buffer && bytesGlyph != 0) { + status = _cairo_error (CAIRO_STATUS_NO_MEMORY); + goto CLEANUP_FONT; + } + + if (GetGlyphOutlineW (hdc, _cairo_scaled_glyph_index (scaled_glyph), + GGO_NATIVE | GGO_GLYPH_INDEX, + &metrics, bytesGlyph, buffer, &matrix) == GDI_ERROR) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "GetGlyphOutline"); + status = _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); + goto CLEANUP_BUFFER; + } + + while (ptr < buffer + bytesGlyph) { + TTPOLYGONHEADER *header = (TTPOLYGONHEADER *)ptr; + unsigned char *endPoly = ptr + header->cb; + + ptr += sizeof (TTPOLYGONHEADER); + + _cairo_win32_transform_FIXED_to_fixed (&transform, + header->pfxStart.x, + header->pfxStart.y, + &x, &y); + status = _cairo_path_fixed_move_to (path, x, y); + if (status) + goto CLEANUP_BUFFER; + + while (ptr < endPoly) { + TTPOLYCURVE *curve = (TTPOLYCURVE *)ptr; + POINTFX *points = curve->apfx; + int i; + switch (curve->wType) { + case TT_PRIM_LINE: + for (i = 0; i < curve->cpfx; i++) { + _cairo_win32_transform_FIXED_to_fixed (&transform, + points[i].x, + points[i].y, + &x, &y); + status = _cairo_path_fixed_line_to (path, x, y); + if (status) + goto CLEANUP_BUFFER; + } + break; + case TT_PRIM_QSPLINE: + for (i = 0; i < curve->cpfx - 1; i++) { + cairo_fixed_t p1x, p1y, p2x, p2y, cx, cy, c1x, c1y, c2x, c2y; + if (! _cairo_path_fixed_get_current_point (path, &p1x, &p1y)) + goto CLEANUP_BUFFER; + _cairo_win32_transform_FIXED_to_fixed (&transform, + points[i].x, + points[i].y, + &cx, &cy); + + if (i + 1 == curve->cpfx - 1) { + _cairo_win32_transform_FIXED_to_fixed (&transform, + points[i + 1].x, + points[i + 1].y, + &p2x, &p2y); + } else { + /* records with more than one curve use interpolation for + control points, per http://support.microsoft.com/kb/q87115/ */ + _cairo_win32_transform_FIXED_to_fixed (&transform, + points[i + 1].x, + points[i + 1].y, + &x, &y); + p2x = (cx + x) / 2; + p2y = (cy + y) / 2; + } + + c1x = 2 * cx / 3 + p1x / 3; + c1y = 2 * cy / 3 + p1y / 3; + c2x = 2 * cx / 3 + p2x / 3; + c2y = 2 * cy / 3 + p2y / 3; + + status = _cairo_path_fixed_curve_to (path, c1x, c1y, c2x, c2y, p2x, p2y); + if (status) + goto CLEANUP_BUFFER; + } + break; + case TT_PRIM_CSPLINE: + for (i = 0; i < curve->cpfx - 2; i += 2) { + cairo_fixed_t x1, y1, x2, y2; + _cairo_win32_transform_FIXED_to_fixed (&transform, + points[i].x, + points[i].y, + &x, &y); + _cairo_win32_transform_FIXED_to_fixed (&transform, + points[i + 1].x, + points[i + 1].y, + &x1, &y1); + _cairo_win32_transform_FIXED_to_fixed (&transform, + points[i + 2].x, + points[i + 2].y, + &x2, &y2); + status = _cairo_path_fixed_curve_to (path, x, y, x1, y1, x2, y2); + if (status) + goto CLEANUP_BUFFER; + } + break; + } + ptr += sizeof(TTPOLYCURVE) + sizeof (POINTFX) * (curve->cpfx - 1); + } + status = _cairo_path_fixed_close_path (path); + if (status) + goto CLEANUP_BUFFER; + } + + _cairo_scaled_glyph_set_path (scaled_glyph, + &scaled_font->base, + path); + + CLEANUP_BUFFER: + free (buffer); + + CLEANUP_FONT: + if (scaled_font->base.options.hint_style == CAIRO_HINT_STYLE_NONE) + _cairo_win32_scaled_font_done_unscaled_font (&scaled_font->base); + else + cairo_win32_scaled_font_done_font (&scaled_font->base); + + CLEANUP_PATH: + if (status != CAIRO_STATUS_SUCCESS) + _cairo_path_fixed_destroy (path); + + return status; +} + +const cairo_scaled_font_backend_t _cairo_win32_scaled_font_backend = { + CAIRO_FONT_TYPE_WIN32, + _cairo_win32_scaled_font_fini, + _cairo_win32_scaled_font_glyph_init, + NULL, /* _cairo_win32_scaled_font_text_to_glyphs */ + _cairo_win32_scaled_font_ucs4_to_index, + _cairo_win32_scaled_font_load_truetype_table, + _cairo_win32_scaled_font_index_to_ucs4, + _cairo_win32_scaled_font_is_synthetic, + _cairo_win32_scaled_font_index_to_glyph_name, + _cairo_win32_scaled_font_load_type1_data +}; + +/* #cairo_win32_font_face_t */ + +typedef struct _cairo_win32_font_face cairo_win32_font_face_t; + +/* If hfont is non-%NULL then logfont->lfHeight must be -S for some S, + * logfont->lfWidth, logfont->lfEscapement, logfont->lfOrientation must + * all be 0, and hfont is the result of calling CreateFontIndirectW on + * logfont. + */ +struct _cairo_win32_font_face { + cairo_font_face_t base; + LOGFONTW logfont; + HFONT hfont; +}; + +/* We maintain a hash table from LOGFONT,HFONT => #cairo_font_face_t. + * The primary purpose of this mapping is to provide unique + * #cairo_font_face_t values so that our cache and mapping from + * #cairo_font_face_t => #cairo_scaled_font_t works. Once the + * corresponding #cairo_font_face_t objects fall out of downstream + * caches, we don't need them in this hash table anymore. + * + * Modifications to this hash table are protected by + * _cairo_win32_font_face_mutex. + */ + +static cairo_hash_table_t *cairo_win32_font_face_hash_table = NULL; + +static int +_cairo_win32_font_face_keys_equal (const void *key_a, + const void *key_b); + +static void +_cairo_win32_font_face_hash_table_destroy (void) +{ + cairo_hash_table_t *hash_table; + + /* We manually acquire the lock rather than calling + * _cairo_win32_font_face_hash_table_lock simply to avoid creating + * the table only to destroy it again. */ + CAIRO_MUTEX_LOCK (_cairo_win32_font_face_mutex); + hash_table = cairo_win32_font_face_hash_table; + cairo_win32_font_face_hash_table = NULL; + CAIRO_MUTEX_UNLOCK (_cairo_win32_font_face_mutex); + + if (hash_table != NULL) + _cairo_hash_table_destroy (hash_table); +} + +static cairo_hash_table_t * +_cairo_win32_font_face_hash_table_lock (void) +{ + CAIRO_MUTEX_LOCK (_cairo_win32_font_face_mutex); + + if (unlikely (cairo_win32_font_face_hash_table == NULL)) + { + cairo_win32_font_face_hash_table = + _cairo_hash_table_create (_cairo_win32_font_face_keys_equal); + + if (unlikely (cairo_win32_font_face_hash_table == NULL)) { + CAIRO_MUTEX_UNLOCK (_cairo_win32_font_face_mutex); + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return NULL; + } + } + + return cairo_win32_font_face_hash_table; +} + +static void +_cairo_win32_font_face_hash_table_unlock (void) +{ + CAIRO_MUTEX_UNLOCK (_cairo_win32_font_face_mutex); +} + +static cairo_bool_t +_cairo_win32_font_face_destroy (void *abstract_face) +{ + cairo_win32_font_face_t *font_face = abstract_face; + cairo_hash_table_t *hash_table; + + hash_table = _cairo_win32_font_face_hash_table_lock (); + /* All created objects must have been mapped in the hash table. */ + assert (hash_table != NULL); + + if (! _cairo_reference_count_dec_and_test (&font_face->base.ref_count)) { + /* somebody recreated the font whilst we waited for the lock */ + _cairo_win32_font_face_hash_table_unlock (); + return FALSE; + } + + /* Font faces in SUCCESS status are guaranteed to be in the + * hashtable. Font faces in an error status are removed from the + * hashtable if they are found during a lookup, thus they should + * only be removed if they are in the hashtable. */ + if (likely (font_face->base.status == CAIRO_STATUS_SUCCESS) || + _cairo_hash_table_lookup (hash_table, &font_face->base.hash_entry) == font_face) + _cairo_hash_table_remove (hash_table, &font_face->base.hash_entry); + + _cairo_win32_font_face_hash_table_unlock (); + return TRUE; +} + +static void +_cairo_win32_font_face_init_key (cairo_win32_font_face_t *key, + LOGFONTW *logfont, + HFONT font) +{ + uintptr_t hash = _CAIRO_HASH_INIT_VALUE; + + key->logfont = *logfont; + key->hfont = font; + + hash = _cairo_hash_bytes (0, logfont->lfFaceName, 2*wcslen(logfont->lfFaceName)); + hash = _cairo_hash_bytes (hash, &logfont->lfWeight, sizeof(logfont->lfWeight)); + hash = _cairo_hash_bytes (hash, &logfont->lfItalic, sizeof(logfont->lfItalic)); + + key->base.hash_entry.hash = hash; +} + +static int +_cairo_win32_font_face_keys_equal (const void *key_a, + const void *key_b) +{ + const cairo_win32_font_face_t *face_a = key_a; + const cairo_win32_font_face_t *face_b = key_b; + + if (face_a->logfont.lfWeight == face_b->logfont.lfWeight && + face_a->logfont.lfItalic == face_b->logfont.lfItalic && + face_a->logfont.lfUnderline == face_b->logfont.lfUnderline && + face_a->logfont.lfStrikeOut == face_b->logfont.lfStrikeOut && + face_a->logfont.lfCharSet == face_b->logfont.lfCharSet && + face_a->logfont.lfOutPrecision == face_b->logfont.lfOutPrecision && + face_a->logfont.lfClipPrecision == face_b->logfont.lfClipPrecision && + face_a->logfont.lfPitchAndFamily == face_b->logfont.lfPitchAndFamily && + (wcscmp (face_a->logfont.lfFaceName, face_b->logfont.lfFaceName) == 0)) + return TRUE; + else + return FALSE; +} + +/* implement the platform-specific interface */ + +static cairo_bool_t +_is_scale (const cairo_matrix_t *matrix, double scale) +{ + return matrix->xx == scale && matrix->yy == scale && + matrix->xy == 0. && matrix->yx == 0. && + matrix->x0 == 0. && matrix->y0 == 0.; +} + +static cairo_status_t +_cairo_win32_font_face_scaled_font_create (void *abstract_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options, + cairo_scaled_font_t **font) +{ + HFONT hfont = NULL; + + cairo_win32_font_face_t *font_face = abstract_face; + + if (font_face->hfont) { + /* Check whether it's OK to go ahead and use the font-face's HFONT. */ + if (_is_scale (ctm, 1.) && + _is_scale (font_matrix, -font_face->logfont.lfHeight * WIN32_FONT_LOGICAL_SCALE)) { + hfont = font_face->hfont; + } + } + + return _win32_scaled_font_create (&font_face->logfont, + hfont, + &font_face->base, + font_matrix, ctm, options, + font); +} + +const cairo_font_face_backend_t _cairo_win32_font_face_backend = { + CAIRO_FONT_TYPE_WIN32, + _cairo_win32_font_face_create_for_toy, + _cairo_win32_font_face_destroy, + _cairo_win32_font_face_scaled_font_create +}; + +/** + * cairo_win32_font_face_create_for_logfontw_hfont: + * @logfont: A #LOGFONTW structure specifying the font to use. + * If @font is %NULL then the lfHeight, lfWidth, lfOrientation and lfEscapement + * fields of this structure are ignored. Otherwise lfWidth, lfOrientation and + * lfEscapement must be zero. + * @font: An #HFONT that can be used when the font matrix is a scale by + * -lfHeight and the CTM is identity. + * + * Creates a new font for the Win32 font backend based on a + * #LOGFONT. This font can then be used with + * cairo_set_font_face() or cairo_scaled_font_create(). + * The #cairo_scaled_font_t + * returned from cairo_scaled_font_create() is also for the Win32 backend + * and can be used with functions such as cairo_win32_scaled_font_select_font(). + * + * Return value: a newly created #cairo_font_face_t. Free with + * cairo_font_face_destroy() when you are done using it. + * + * Since: 1.6 + **/ +cairo_font_face_t * +cairo_win32_font_face_create_for_logfontw_hfont (LOGFONTW *logfont, HFONT font) +{ + cairo_win32_font_face_t *font_face, key; + cairo_hash_table_t *hash_table; + cairo_status_t status; + + hash_table = _cairo_win32_font_face_hash_table_lock (); + if (unlikely (hash_table == NULL)) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + return (cairo_font_face_t *)&_cairo_font_face_nil; + } + + _cairo_win32_font_face_init_key (&key, logfont, font); + + /* Return existing unscaled font if it exists in the hash table. */ + font_face = _cairo_hash_table_lookup (hash_table, + &key.base.hash_entry); + if (font_face != NULL) { + if (font_face->base.status == CAIRO_STATUS_SUCCESS) { + cairo_font_face_reference (&font_face->base); + _cairo_win32_font_face_hash_table_unlock (); + return &font_face->base; + } + + /* remove the bad font from the hash table */ + _cairo_hash_table_remove (hash_table, &font_face->base.hash_entry); + } + + /* Otherwise create it and insert into hash table. */ + font_face = _cairo_calloc (sizeof (cairo_win32_font_face_t)); + if (!font_face) { + _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); + goto FAIL; + } + + _cairo_win32_font_face_init_key (font_face, logfont, font); + _cairo_font_face_init (&font_face->base, &_cairo_win32_font_face_backend); + + assert (font_face->base.hash_entry.hash == key.base.hash_entry.hash); + status = _cairo_hash_table_insert (hash_table, + &font_face->base.hash_entry); + if (unlikely (status)) + goto FAIL; + + _cairo_win32_font_face_hash_table_unlock (); + return &font_face->base; + +FAIL: + _cairo_win32_font_face_hash_table_unlock (); + return (cairo_font_face_t *)&_cairo_font_face_nil; +} + +/** + * cairo_win32_font_face_create_for_logfontw: + * @logfont: A #LOGFONTW structure specifying the font to use. + * The lfHeight, lfWidth, lfOrientation and lfEscapement + * fields of this structure are ignored. + * + * Creates a new font for the Win32 font backend based on a + * #LOGFONT. This font can then be used with + * cairo_set_font_face() or cairo_scaled_font_create(). + * The #cairo_scaled_font_t + * returned from cairo_scaled_font_create() is also for the Win32 backend + * and can be used with functions such as cairo_win32_scaled_font_select_font(). + * + * Return value: a newly created #cairo_font_face_t. Free with + * cairo_font_face_destroy() when you are done using it. + * + * Since: 1.0 + **/ +cairo_font_face_t * +cairo_win32_font_face_create_for_logfontw (LOGFONTW *logfont) +{ + return cairo_win32_font_face_create_for_logfontw_hfont (logfont, NULL); +} + +/** + * cairo_win32_font_face_create_for_hfont: + * @font: An #HFONT structure specifying the font to use. + * + * Creates a new font for the Win32 font backend based on a + * #HFONT. This font can then be used with + * cairo_set_font_face() or cairo_scaled_font_create(). + * The #cairo_scaled_font_t + * returned from cairo_scaled_font_create() is also for the Win32 backend + * and can be used with functions such as cairo_win32_scaled_font_select_font(). + * + * Return value: a newly created #cairo_font_face_t. Free with + * cairo_font_face_destroy() when you are done using it. + * + * Since: 1.2 + **/ +cairo_font_face_t * +cairo_win32_font_face_create_for_hfont (HFONT font) +{ + LOGFONTW logfont; + GetObjectW (font, sizeof(logfont), &logfont); + + if (logfont.lfEscapement != 0 || logfont.lfOrientation != 0 || + logfont.lfWidth != 0) { + /* We can't use this font because that optimization requires that + * lfEscapement, lfOrientation and lfWidth be zero. */ + font = NULL; + } + + return cairo_win32_font_face_create_for_logfontw_hfont (&logfont, font); +} + +static cairo_bool_t +_cairo_scaled_font_is_win32 (cairo_scaled_font_t *scaled_font) +{ + return scaled_font->backend == &_cairo_win32_scaled_font_backend; +} + +/** + * cairo_win32_scaled_font_select_font: + * @scaled_font: A #cairo_scaled_font_t from the Win32 font backend. Such an + * object can be created with cairo_win32_font_face_create_for_logfontw(). + * @hdc: a device context + * + * Selects the font into the given device context and changes the + * map mode and world transformation of the device context to match + * that of the font. This function is intended for use when using + * layout APIs such as Uniscribe to do text layout with the + * cairo font. After finishing using the device context, you must call + * cairo_win32_scaled_font_done_font() to release any resources allocated + * by this function. + * + * See cairo_win32_scaled_font_get_metrics_factor() for converting logical + * coordinates from the device context to font space. + * + * Normally, calls to SaveDC() and RestoreDC() would be made around + * the use of this function to preserve the original graphics state. + * + * Return value: %CAIRO_STATUS_SUCCESS if the operation succeeded. + * otherwise an error such as %CAIRO_STATUS_NO_MEMORY and + * the device context is unchanged. + * + * Since: 1.0 + **/ +cairo_status_t +cairo_win32_scaled_font_select_font (cairo_scaled_font_t *scaled_font, + HDC hdc) +{ + cairo_status_t status; + HFONT hfont; + HFONT old_hfont = NULL; + int old_mode; + + if (! _cairo_scaled_font_is_win32 (scaled_font)) { + return _cairo_error (CAIRO_STATUS_FONT_TYPE_MISMATCH); + } + + if (scaled_font->status) + return scaled_font->status; + + status = _win32_scaled_font_get_scaled_hfont ((cairo_win32_scaled_font_t *)scaled_font, &hfont); + if (status) + return status; + + old_hfont = SelectObject (hdc, hfont); + if (!old_hfont) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "SelectObject"); + return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); + } + + old_mode = SetGraphicsMode (hdc, GM_ADVANCED); + if (!old_mode) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "SetGraphicsMode"); + SelectObject (hdc, old_hfont); + return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); + } + + status = _win32_scaled_font_set_world_transform ((cairo_win32_scaled_font_t *)scaled_font, hdc); + if (status) { + SetGraphicsMode (hdc, old_mode); + SelectObject (hdc, old_hfont); + return status; + } + + SetMapMode (hdc, MM_TEXT); + + return CAIRO_STATUS_SUCCESS; +} + +/** + * cairo_win32_scaled_font_done_font: + * @scaled_font: A scaled font from the Win32 font backend. + * + * Releases any resources allocated by cairo_win32_scaled_font_select_font() + * + * Since: 1.0 + **/ +void +cairo_win32_scaled_font_done_font (cairo_scaled_font_t *scaled_font) +{ + if (! _cairo_scaled_font_is_win32 (scaled_font)) { + _cairo_error_throw (CAIRO_STATUS_FONT_TYPE_MISMATCH); + } +} + +/** + * cairo_win32_scaled_font_get_metrics_factor: + * @scaled_font: a scaled font from the Win32 font backend + * + * Gets a scale factor between logical coordinates in the coordinate + * space used by cairo_win32_scaled_font_select_font() (that is, the + * coordinate system used by the Windows functions to return metrics) and + * font space coordinates. + * + * Return value: factor to multiply logical units by to get font space + * coordinates. + * + * Since: 1.0 + **/ +double +cairo_win32_scaled_font_get_metrics_factor (cairo_scaled_font_t *scaled_font) +{ + if (! _cairo_scaled_font_is_win32 (scaled_font)) { + _cairo_error_throw (CAIRO_STATUS_FONT_TYPE_MISMATCH); + return 1.; + } + return 1. / ((cairo_win32_scaled_font_t *)scaled_font)->logical_scale; +} + +/** + * cairo_win32_scaled_font_get_logical_to_device: + * @scaled_font: a scaled font from the Win32 font backend + * @logical_to_device: matrix to return + * + * Gets the transformation mapping the logical space used by @scaled_font + * to device space. + * + * Since: 1.4 + **/ +void +cairo_win32_scaled_font_get_logical_to_device (cairo_scaled_font_t *scaled_font, + cairo_matrix_t *logical_to_device) +{ + cairo_win32_scaled_font_t *win_font = (cairo_win32_scaled_font_t *)scaled_font; + if (! _cairo_scaled_font_is_win32 (scaled_font)) { + _cairo_error_throw (CAIRO_STATUS_FONT_TYPE_MISMATCH); + cairo_matrix_init_identity (logical_to_device); + return; + } + *logical_to_device = win_font->logical_to_device; +} + +/** + * cairo_win32_scaled_font_get_device_to_logical: + * @scaled_font: a scaled font from the Win32 font backend + * @device_to_logical: matrix to return + * + * Gets the transformation mapping device space to the logical space + * used by @scaled_font. + * + * Since: 1.4 + **/ +void +cairo_win32_scaled_font_get_device_to_logical (cairo_scaled_font_t *scaled_font, + cairo_matrix_t *device_to_logical) +{ + cairo_win32_scaled_font_t *win_font = (cairo_win32_scaled_font_t *)scaled_font; + if (! _cairo_scaled_font_is_win32 (scaled_font)) { + _cairo_error_throw (CAIRO_STATUS_FONT_TYPE_MISMATCH); + cairo_matrix_init_identity (device_to_logical); + return; + } + *device_to_logical = win_font->device_to_logical; +} + +void +_cairo_win32_font_reset_static_data (void) +{ + _cairo_win32_font_face_hash_table_destroy (); +} diff --git a/local/recipes/libs/cairo/source/src/win32/cairo-win32-gdi-compositor.c b/local/recipes/libs/cairo/source/src/win32/cairo-win32-gdi-compositor.c new file mode 100644 index 0000000000..347cd7ed5d --- /dev/null +++ b/local/recipes/libs/cairo/source/src/win32/cairo-win32-gdi-compositor.c @@ -0,0 +1,652 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Carl D. Worth + * Behdad Esfahbod + * Chris Wilson + * Karl Tomlinson , Mozilla Corporation + */ + +/* The original X drawing API was very restrictive in what it could handle, + * pixel-aligned fill/blits are all that map into Cairo's drawing model. + */ + +#include "cairoint.h" + +#include "cairo-win32-private.h" + +#include "cairo-boxes-private.h" +#include "cairo-clip-inline.h" +#include "cairo-compositor-private.h" +#include "cairo-image-surface-private.h" +#include "cairo-pattern-private.h" +#include "cairo-region-private.h" +#include "cairo-surface-inline.h" +#include "cairo-surface-offset-private.h" + +#define PELS_72DPI ((LONG)(72. / 0.0254)) + +/* the low-level interface */ + +struct fill_box { + HDC dc; + HBRUSH brush; +}; + +static cairo_bool_t fill_box (cairo_box_t *box, void *closure) +{ + struct fill_box *fb = closure; + RECT rect; + + rect.left = _cairo_fixed_integer_part (box->p1.x); + rect.top = _cairo_fixed_integer_part (box->p1.y); + rect.right = _cairo_fixed_integer_part (box->p2.x); + rect.bottom = _cairo_fixed_integer_part (box->p2.y); + + TRACE ((stderr, "%s\n", __FUNCTION__)); + return FillRect (fb->dc, &rect, fb->brush); +} + +struct check_box { + cairo_rectangle_int_t limit; + int tx, ty; +}; + +struct copy_box { + cairo_rectangle_int_t limit; + int tx, ty; + HDC dst, src; + BLENDFUNCTION bf; +}; + +static cairo_bool_t copy_box (cairo_box_t *box, void *closure) +{ + const struct copy_box *cb = closure; + int x = _cairo_fixed_integer_part (box->p1.x); + int y = _cairo_fixed_integer_part (box->p1.y); + int width = _cairo_fixed_integer_part (box->p2.x - box->p1.x); + int height = _cairo_fixed_integer_part (box->p2.y - box->p1.y); + + TRACE ((stderr, "%s\n", __FUNCTION__)); + return BitBlt (cb->dst, x, y, width, height, + cb->src, x + cb->tx, y + cb->ty, + SRCCOPY); +} + +static cairo_bool_t alpha_box (cairo_box_t *box, void *closure) +{ + const struct copy_box *cb = closure; + int x = _cairo_fixed_integer_part (box->p1.x); + int y = _cairo_fixed_integer_part (box->p1.y); + int width = _cairo_fixed_integer_part (box->p2.x - box->p1.x); + int height = _cairo_fixed_integer_part (box->p2.y - box->p1.y); + + TRACE ((stderr, "%s\n", __FUNCTION__)); + return AlphaBlend (cb->dst, x, y, width, height, + cb->src, x + cb->tx, y + cb->ty, width, height, + cb->bf); +} + +struct upload_box { + cairo_rectangle_int_t limit; + int tx, ty; + HDC dst; + BITMAPINFO bi; + void *data; +}; + +static cairo_bool_t upload_box (cairo_box_t *box, void *closure) +{ + const struct upload_box *cb = closure; + int x = _cairo_fixed_integer_part (box->p1.x); + int y = _cairo_fixed_integer_part (box->p1.y); + int width = _cairo_fixed_integer_part (box->p2.x - box->p1.x); + int height = _cairo_fixed_integer_part (box->p2.y - box->p1.y); + int src_height = -cb->bi.bmiHeader.biHeight; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + return StretchDIBits (cb->dst, x, y + height - 1, width, -height, + x + cb->tx, src_height - (y + cb->ty - 1), + width, -height, + cb->data, &cb->bi, + DIB_RGB_COLORS, SRCCOPY); +} + +/* the mid-level: converts boxes into drawing operations */ + +static COLORREF color_to_rgb(const cairo_color_t *c) +{ + return RGB (c->red_short >> 8, c->green_short >> 8, c->blue_short >> 8); +} + +static cairo_int_status_t +fill_boxes (cairo_win32_display_surface_t *dst, + const cairo_pattern_t *src, + cairo_boxes_t *boxes) +{ + const cairo_color_t *color = &((cairo_solid_pattern_t *) src)->color; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + struct fill_box fb; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + if ((dst->win32.flags & CAIRO_WIN32_SURFACE_CAN_RGB_BRUSH) == 0) + return CAIRO_INT_STATUS_UNSUPPORTED; + + fb.dc = dst->win32.dc; + fb.brush = CreateSolidBrush (color_to_rgb(color)); + if (!fb.brush) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "CreateSolidBrush"); + return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); + } + + if (! _cairo_boxes_for_each_box (boxes, fill_box, &fb)) + status = CAIRO_INT_STATUS_UNSUPPORTED; + + DeleteObject (fb.brush); + + return status; +} + +static cairo_bool_t source_contains_box (cairo_box_t *box, void *closure) +{ + struct check_box *data = closure; + + /* The box is pixel-aligned so the truncation is safe. */ + return + _cairo_fixed_integer_part (box->p1.x) + data->tx >= data->limit.x && + _cairo_fixed_integer_part (box->p1.y) + data->ty >= data->limit.y && + _cairo_fixed_integer_part (box->p2.x) + data->tx <= data->limit.x + data->limit.width && + _cairo_fixed_integer_part (box->p2.y) + data->ty <= data->limit.y + data->limit.height; +} + +static cairo_status_t +copy_boxes (cairo_win32_display_surface_t *dst, + const cairo_pattern_t *source, + cairo_boxes_t *boxes) +{ + const cairo_surface_pattern_t *pattern; + struct copy_box cb; + cairo_surface_t *surface; + cairo_status_t status; + cairo_win32_surface_t *src; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + pattern = (const cairo_surface_pattern_t *) source; + surface = _cairo_surface_get_source (pattern->surface, &cb.limit); + if (surface->type == CAIRO_SURFACE_TYPE_IMAGE) { + surface = to_image_surface(surface)->parent; + if (surface == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + } + if (surface->type != CAIRO_SURFACE_TYPE_WIN32) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (! _cairo_matrix_is_integer_translation (&source->matrix, + &cb.tx, &cb.ty)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + src = to_win32_surface(surface); + + if (src->format != dst->win32.format && + !(src->format == CAIRO_FORMAT_ARGB32 && dst->win32.format == CAIRO_FORMAT_RGB24)) + { + /* forbid copy different surfaces unless it is from argb32 to + * rgb (dropping alpha) */ + return CAIRO_INT_STATUS_UNSUPPORTED; + } + cb.dst = dst->win32.dc; + cb.src = src->dc; + + /* First check that the data is entirely within the image */ + if (! _cairo_boxes_for_each_box (boxes, source_contains_box, &cb)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = __cairo_surface_flush (surface, 0); + if (status) + return status; + + cb.tx += cb.limit.x; + cb.ty += cb.limit.y; + status = CAIRO_STATUS_SUCCESS; + if (! _cairo_boxes_for_each_box (boxes, copy_box, &cb)) + status = CAIRO_INT_STATUS_UNSUPPORTED; + + _cairo_win32_display_surface_discard_fallback (dst); + return status; +} + +static cairo_status_t +upload_boxes (cairo_win32_display_surface_t *dst, + const cairo_pattern_t *source, + cairo_boxes_t *boxes) +{ + const cairo_surface_pattern_t *pattern; + struct upload_box cb; + cairo_surface_t *surface; + cairo_image_surface_t *image; + void *image_extra; + cairo_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + if ((dst->win32.flags & CAIRO_WIN32_SURFACE_CAN_STRETCHDIB) == 0) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (! _cairo_matrix_is_integer_translation (&source->matrix, + &cb.tx, &cb.ty)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + pattern = (const cairo_surface_pattern_t *) source; + surface = _cairo_surface_get_source (pattern->surface, &cb.limit); + + /* First check that the data is entirely within the image */ + if (! _cairo_boxes_for_each_box (boxes, source_contains_box, &cb)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (surface->type != CAIRO_SURFACE_TYPE_IMAGE) { + status = _cairo_surface_acquire_source_image (surface, + &image, &image_extra); + if (status) + return status; + } else + image = to_image_surface(surface); + + status = CAIRO_INT_STATUS_UNSUPPORTED; + if (!(image->format == CAIRO_FORMAT_ARGB32 || + image->format == CAIRO_FORMAT_RGB24)) + goto err; + if (image->stride != 4*image->width) + goto err; + + cb.dst = dst->win32.dc; + cb.data = image->data; + + cb.bi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER); + cb.bi.bmiHeader.biWidth = image->width; + cb.bi.bmiHeader.biHeight = -image->height; + cb.bi.bmiHeader.biSizeImage = 0; + cb.bi.bmiHeader.biXPelsPerMeter = PELS_72DPI; + cb.bi.bmiHeader.biYPelsPerMeter = PELS_72DPI; + cb.bi.bmiHeader.biPlanes = 1; + cb.bi.bmiHeader.biBitCount = 32; + cb.bi.bmiHeader.biCompression = BI_RGB; + cb.bi.bmiHeader.biClrUsed = 0; + cb.bi.bmiHeader.biClrImportant = 0; + + cb.tx += cb.limit.x; + cb.ty += cb.limit.y; + status = CAIRO_STATUS_SUCCESS; + if (! _cairo_boxes_for_each_box (boxes, upload_box, &cb)) + status = CAIRO_INT_STATUS_UNSUPPORTED; + + _cairo_win32_display_surface_discard_fallback (dst); +err: + if (&image->base != surface) + _cairo_surface_release_source_image (surface, image, image_extra); + + return status; +} + +static cairo_status_t +alpha_blend_boxes (cairo_win32_display_surface_t *dst, + const cairo_pattern_t *source, + cairo_boxes_t *boxes, + uint8_t alpha) +{ + const cairo_surface_pattern_t *pattern; + struct copy_box cb; + cairo_surface_t *surface; + cairo_win32_display_surface_t *src; + cairo_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + if (source->type != CAIRO_PATTERN_TYPE_SURFACE) + return CAIRO_INT_STATUS_UNSUPPORTED; + + pattern = (const cairo_surface_pattern_t *) source; + surface = _cairo_surface_get_source (pattern->surface, &cb.limit); + if (surface->type == CAIRO_SURFACE_TYPE_IMAGE) { + surface = to_image_surface(surface)->parent; + if (surface == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + } + if (surface->type != CAIRO_SURFACE_TYPE_WIN32) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (! _cairo_matrix_is_integer_translation (&source->matrix, + &cb.tx, &cb.ty)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + src = to_win32_display_surface (surface); + cb.dst = dst->win32.dc; + cb.src = src->win32.dc; + + /* First check that the data is entirely within the image */ + if (! _cairo_boxes_for_each_box (boxes, source_contains_box, &cb)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = __cairo_surface_flush (&src->win32.base, 0); + if (status) + return status; + + cb.bf.BlendOp = AC_SRC_OVER; + cb.bf.BlendFlags = 0; + cb.bf.SourceConstantAlpha = alpha; + cb.bf.AlphaFormat = (src->win32.format == CAIRO_FORMAT_ARGB32) ? AC_SRC_ALPHA : 0; + + cb.tx += cb.limit.x; + cb.ty += cb.limit.y; + status = CAIRO_STATUS_SUCCESS; + if (! _cairo_boxes_for_each_box (boxes, alpha_box, &cb)) + status = CAIRO_INT_STATUS_UNSUPPORTED; + + _cairo_win32_display_surface_discard_fallback (dst); + return status; +} + +static cairo_bool_t +can_alpha_blend (cairo_win32_display_surface_t *dst) +{ + return (dst->win32.flags & CAIRO_WIN32_SURFACE_CAN_ALPHABLEND) != 0; +} + +static cairo_status_t +draw_boxes (cairo_composite_rectangles_t *composite, + cairo_boxes_t *boxes) +{ + cairo_win32_display_surface_t *dst = to_win32_display_surface(composite->surface); + cairo_operator_t op = composite->op; + const cairo_pattern_t *src = &composite->source_pattern.base; + cairo_int_status_t status; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + if (boxes->num_boxes == 0 && composite->is_bounded) + return CAIRO_STATUS_SUCCESS; + + if (!boxes->is_pixel_aligned) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (op == CAIRO_OPERATOR_CLEAR) + op = CAIRO_OPERATOR_SOURCE; + + if (op == CAIRO_OPERATOR_OVER && + _cairo_pattern_is_opaque (src, &composite->bounded)) + op = CAIRO_OPERATOR_SOURCE; + + if (dst->win32.base.is_clear && + (op == CAIRO_OPERATOR_OVER || op == CAIRO_OPERATOR_ADD)) + op = CAIRO_OPERATOR_SOURCE; + + if (op == CAIRO_OPERATOR_SOURCE) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + if (src->type == CAIRO_PATTERN_TYPE_SURFACE) { + status = copy_boxes (dst, src, boxes); + if (status == CAIRO_INT_STATUS_UNSUPPORTED) + status = upload_boxes (dst, src, boxes); + } else if (src->type == CAIRO_PATTERN_TYPE_SOLID) { + status = fill_boxes (dst, src, boxes); + } + return status; + } + + if (op == CAIRO_OPERATOR_OVER && can_alpha_blend (dst)) + return alpha_blend_boxes (dst, src, boxes, 255); + + return CAIRO_INT_STATUS_UNSUPPORTED; +} + +static cairo_status_t +opacity_boxes (cairo_composite_rectangles_t *composite, + cairo_boxes_t *boxes) +{ + cairo_win32_display_surface_t *dst = to_win32_display_surface(composite->surface); + cairo_operator_t op = composite->op; + const cairo_pattern_t *src = &composite->source_pattern.base; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + if (composite->mask_pattern.base.type != CAIRO_PATTERN_TYPE_SOLID) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (boxes->num_boxes == 0 && composite->is_bounded) + return CAIRO_STATUS_SUCCESS; + + if (!boxes->is_pixel_aligned) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (op != CAIRO_OPERATOR_OVER) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (!can_alpha_blend (dst)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + return alpha_blend_boxes (dst, src, boxes, + composite->mask_pattern.solid.color.alpha_short >> 8); +} + +/* high-level compositor interface */ + +static cairo_bool_t check_blit (cairo_composite_rectangles_t *composite) +{ + cairo_win32_display_surface_t *dst; + + if (composite->clip->path) + return FALSE; + + dst = to_win32_display_surface (composite->surface); + if (dst->fallback) + return FALSE; + + if (dst->win32.format != CAIRO_FORMAT_RGB24 + && dst->win32.format != CAIRO_FORMAT_ARGB32) + return FALSE; + + if (dst->win32.flags & CAIRO_WIN32_SURFACE_CAN_BITBLT) + return TRUE; + + return dst->image == NULL; +} + +static cairo_int_status_t +_cairo_win32_gdi_compositor_paint (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *composite) +{ + cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED; + + if (check_blit (composite)) { + cairo_boxes_t boxes; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + _cairo_clip_steal_boxes (composite->clip, &boxes); + status = draw_boxes (composite, &boxes); + _cairo_clip_unsteal_boxes (composite->clip, &boxes); + } + + return status; +} + +static cairo_int_status_t +_cairo_win32_gdi_compositor_mask (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *composite) +{ + cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED; + + if (check_blit (composite)) { + cairo_boxes_t boxes; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + _cairo_clip_steal_boxes (composite->clip, &boxes); + status = opacity_boxes (composite, &boxes); + _cairo_clip_unsteal_boxes (composite->clip, &boxes); + } + + return status; +} + +static cairo_int_status_t +_cairo_win32_gdi_compositor_stroke (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *composite, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *ctm, + const cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_int_status_t status; + + status = CAIRO_INT_STATUS_UNSUPPORTED; + if (check_blit (composite) && + _cairo_path_fixed_stroke_is_rectilinear (path)) { + cairo_boxes_t boxes; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + _cairo_boxes_init_with_clip (&boxes, composite->clip); + status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path, + style, + ctm, + antialias, + &boxes); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) + status = draw_boxes (composite, &boxes); + _cairo_boxes_fini (&boxes); + } + + return status; +} + +static cairo_int_status_t +_cairo_win32_gdi_compositor_fill (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t *composite, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_int_status_t status; + + status = CAIRO_INT_STATUS_UNSUPPORTED; + if (check_blit (composite) && + _cairo_path_fixed_fill_is_rectilinear (path)) { + cairo_boxes_t boxes; + + TRACE ((stderr, "%s\n", __FUNCTION__)); + _cairo_boxes_init_with_clip (&boxes, composite->clip); + status = _cairo_path_fixed_fill_rectilinear_to_boxes (path, + fill_rule, + antialias, + &boxes); + if (likely (status == CAIRO_INT_STATUS_SUCCESS)) + status = draw_boxes (composite, &boxes); + _cairo_boxes_fini (&boxes); + } + + return status; +} + +static cairo_bool_t check_glyphs (cairo_composite_rectangles_t *composite, + cairo_scaled_font_t *scaled_font) +{ + if (! _cairo_clip_is_region (composite->clip)) + return FALSE; + + cairo_font_type_t type = cairo_scaled_font_get_type (scaled_font); + if (type != CAIRO_FONT_TYPE_WIN32 && type != CAIRO_FONT_TYPE_DWRITE) + return FALSE; + + if (! _cairo_pattern_is_opaque_solid (&composite->source_pattern.base)) + return FALSE; + + return (composite->op == CAIRO_OPERATOR_CLEAR || + composite->op == CAIRO_OPERATOR_SOURCE || + composite->op == CAIRO_OPERATOR_OVER); +} + +static cairo_int_status_t +_cairo_win32_gdi_compositor_glyphs (const cairo_compositor_t *compositor, + cairo_composite_rectangles_t*composite, + cairo_scaled_font_t *scaled_font, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_bool_t overlap) +{ + cairo_int_status_t status; + + status = CAIRO_INT_STATUS_UNSUPPORTED; + if (check_blit (composite) && check_glyphs (composite, scaled_font)) { + cairo_win32_display_surface_t *dst = to_win32_display_surface (composite->surface); + + TRACE ((stderr, "%s\n", __FUNCTION__)); + + if ((dst->win32.flags & CAIRO_WIN32_SURFACE_CAN_RGB_BRUSH) == 0) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_win32_display_surface_set_clip(dst, composite->clip); + if (status) + return status; + + status = _cairo_win32_surface_emit_glyphs (&dst->win32, + &composite->source_pattern.base, + glyphs, + num_glyphs, + scaled_font, + TRUE); + + _cairo_win32_display_surface_unset_clip (dst); + } + + return status; +} + +const cairo_compositor_t * +_cairo_win32_gdi_compositor_get (void) +{ + static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT; + static cairo_compositor_t compositor; + + if (_cairo_atomic_init_once_enter(&once)) { + compositor.delegate = &_cairo_fallback_compositor; + + compositor.paint = _cairo_win32_gdi_compositor_paint; + compositor.mask = _cairo_win32_gdi_compositor_mask; + compositor.fill = _cairo_win32_gdi_compositor_fill; + compositor.stroke = _cairo_win32_gdi_compositor_stroke; + compositor.glyphs = _cairo_win32_gdi_compositor_glyphs; + + _cairo_atomic_init_once_leave(&once); + } + + return &compositor; +} diff --git a/local/recipes/libs/cairo/source/src/win32/cairo-win32-printing-surface.c b/local/recipes/libs/cairo/source/src/win32/cairo-win32-printing-surface.c new file mode 100644 index 0000000000..c5b5f5cab6 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/win32/cairo-win32-printing-surface.c @@ -0,0 +1,2289 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2007, 2008 Adrian Johnson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Adrian Johnson. + * + * Contributor(s): + * Adrian Johnson + * Vladimir Vukicevic + */ + +#include "cairoint.h" + +#include "cairo-default-context-private.h" +#include "cairo-error-private.h" +#include "cairo-paginated-private.h" + +#include "cairo-clip-private.h" +#include "cairo-composite-rectangles-private.h" +#include "cairo-win32-private.h" +#include "cairo-recording-surface-inline.h" +#include "cairo-scaled-font-subsets-private.h" +#include "cairo-image-info-private.h" +#include "cairo-image-surface-inline.h" +#include "cairo-image-surface-private.h" +#include "cairo-surface-backend-private.h" +#include "cairo-surface-clipper-private.h" +#include "cairo-surface-snapshot-inline.h" +#include "cairo-surface-subsurface-private.h" + +#include + +#if !defined(POSTSCRIPT_IDENTIFY) +# define POSTSCRIPT_IDENTIFY 0x1015 +#endif + +#if !defined(PSIDENT_GDICENTRIC) +# define PSIDENT_GDICENTRIC 0x0000 +#endif + +#if !defined(GET_PS_FEATURESETTING) +# define GET_PS_FEATURESETTING 0x1019 +#endif + +#if !defined(FEATURESETTING_PSLEVEL) +# define FEATURESETTING_PSLEVEL 0x0002 +#endif + +#if !defined(GRADIENT_FILL_RECT_H) +# define GRADIENT_FILL_RECT_H 0x00 +#endif + +#if !defined(CHECKJPEGFORMAT) +# define CHECKJPEGFORMAT 0x1017 +#endif + +#if !defined(CHECKPNGFORMAT) +# define CHECKPNGFORMAT 0x1018 +#endif + +#define PELS_72DPI ((LONG)(72. / 0.0254)) + +static const char *_cairo_win32_printing_supported_mime_types[] = +{ + CAIRO_MIME_TYPE_JPEG, + CAIRO_MIME_TYPE_PNG, + NULL +}; + +static const cairo_surface_backend_t cairo_win32_printing_surface_backend; +static const cairo_paginated_surface_backend_t cairo_win32_surface_paginated_backend; + +static void +_cairo_win32_printing_surface_init_ps_mode (cairo_win32_printing_surface_t *surface) +{ + DWORD word; + INT ps_feature, ps_level; + + word = PSIDENT_GDICENTRIC; + if (ExtEscape (surface->win32.dc, POSTSCRIPT_IDENTIFY, sizeof(DWORD), (char *)&word, 0, (char *)NULL) <= 0) + return; + + ps_feature = FEATURESETTING_PSLEVEL; + if (ExtEscape (surface->win32.dc, GET_PS_FEATURESETTING, sizeof(INT), + (char *)&ps_feature, sizeof(INT), (char *)&ps_level) <= 0) + return; + + if (ps_level >= 3) + surface->win32.flags |= CAIRO_WIN32_SURFACE_CAN_RECT_GRADIENT; +} + +static void +_cairo_win32_printing_surface_init_image_support (cairo_win32_printing_surface_t *surface) +{ + DWORD word; + + word = CHECKJPEGFORMAT; + if (ExtEscape(surface->win32.dc, QUERYESCSUPPORT, sizeof(word), (char *)&word, 0, (char *)NULL) > 0) + surface->win32.flags |= CAIRO_WIN32_SURFACE_CAN_CHECK_JPEG; + + word = CHECKPNGFORMAT; + if (ExtEscape(surface->win32.dc, QUERYESCSUPPORT, sizeof(word), (char *)&word, 0, (char *)NULL) > 0) + surface->win32.flags |= CAIRO_WIN32_SURFACE_CAN_CHECK_PNG; +} + +/* When creating an EMF file, ExtTextOut with ETO_GLYPH_INDEX does not + * work unless the GDI function GdiInitializeLanguagePack() has been + * called. + * + * http://m-a-tech.blogspot.com/2009/04/emf-buffer-idiocracy.html + * + * The only information I could find on the how to use this + * undocumented function is the use in: + * + * http://src.chromium.org/viewvc/chrome/trunk/src/chrome/renderer/render_process.cc?view=markup + * + * to solve the same problem. The above code first checks if LPK.DLL + * is already loaded. If it is not it calls + * GdiInitializeLanguagePack() using the prototype + * BOOL GdiInitializeLanguagePack (int) + * and argument 0. + */ +static void +_cairo_win32_printing_surface_init_language_pack (cairo_win32_printing_surface_t *surface) +{ + typedef BOOL (WINAPI *gdi_init_lang_pack_func_t)(int); + gdi_init_lang_pack_func_t gdi_init_lang_pack; + HMODULE module; + + if (GetModuleHandleW (L"LPK.DLL")) + return; + + module = GetModuleHandleW (L"GDI32.DLL"); + if (module) { +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-function-type" +#endif + gdi_init_lang_pack = (gdi_init_lang_pack_func_t) + GetProcAddress (module, "GdiInitializeLanguagePack"); +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + if (gdi_init_lang_pack) + gdi_init_lang_pack (0); + } +} + +/** + * _cairo_win32_printing_surface_acquire_image_pattern: + * @surface: the win32 printing surface + * @pattern: A #cairo_pattern_t of type SURFACE or RASTER_SOURCE to use as the source + * @extents: extents of the operation that is using this source + * @image_pattern: returns pattern containing acquired image. The matrix (adjusted for + * the device offset of raster source) is copied from the pattern. + * @width: returns width of the pattern + * @height: returns height of pattern + * @image_extra: returns image extra for image type surface + * + * Acquire source surface or raster source pattern. + **/ +static cairo_status_t +_cairo_win32_printing_surface_acquire_image_pattern ( + cairo_win32_printing_surface_t *surface, + const cairo_pattern_t *pattern, + const cairo_rectangle_int_t *extents, + cairo_surface_pattern_t *image_pattern, + int *width, + int *height, + void **image_extra) +{ + cairo_status_t status; + cairo_image_surface_t *image; + cairo_matrix_t tm; + double x = 0; + double y = 0; + + switch (pattern->type) { + case CAIRO_PATTERN_TYPE_SURFACE: { + cairo_surface_t *surf = ((cairo_surface_pattern_t *) pattern)->surface; + + status = _cairo_surface_acquire_source_image (surf, &image, image_extra); + if (unlikely (status)) + return status; + + *width = image->width; + *height = image->height; + } break; + + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: { + cairo_surface_t *surf; + cairo_box_t box; + cairo_rectangle_int_t rect; + cairo_raster_source_pattern_t *raster; + + /* get the operation extents in pattern space */ + _cairo_box_from_rectangle (&box, extents); + _cairo_matrix_transform_bounding_box_fixed (&pattern->matrix, &box, NULL); + _cairo_box_round_to_rectangle (&box, &rect); + surf = _cairo_raster_source_pattern_acquire (pattern, &surface->win32.base, &rect); + if (!surf) + return CAIRO_INT_STATUS_UNSUPPORTED; + + assert (_cairo_surface_is_image (surf)); + image = (cairo_image_surface_t *) surf; + cairo_surface_get_device_offset (surf, &x, &y); + + raster = (cairo_raster_source_pattern_t *) pattern; + *width = raster->extents.width; + *height = raster->extents.height; + } break; + + case CAIRO_PATTERN_TYPE_SOLID: + case CAIRO_PATTERN_TYPE_LINEAR: + case CAIRO_PATTERN_TYPE_RADIAL: + case CAIRO_PATTERN_TYPE_MESH: + default: + ASSERT_NOT_REACHED; + return CAIRO_INT_STATUS_UNSUPPORTED; + } + + _cairo_pattern_init_for_surface (image_pattern, &image->base); + image_pattern->base.extend = pattern->extend; + cairo_matrix_init_translate (&tm, x, y); + status = cairo_matrix_invert (&tm); + /* translation matrices are invertibile */ + assert (status == CAIRO_STATUS_SUCCESS); + + image_pattern->base.matrix = pattern->matrix; + cairo_matrix_multiply (&image_pattern->base.matrix, &image_pattern->base.matrix, &tm); + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_win32_printing_surface_release_image_pattern (cairo_win32_printing_surface_t *surface, + const cairo_pattern_t *pattern, + cairo_surface_pattern_t *image_pattern, + void *image_extra) +{ + cairo_surface_t *surf = image_pattern->surface; + + _cairo_pattern_fini (&image_pattern->base); + switch (pattern->type) { + case CAIRO_PATTERN_TYPE_SURFACE: { + cairo_surface_pattern_t *surf_pat = (cairo_surface_pattern_t *) pattern; + cairo_image_surface_t *image = (cairo_image_surface_t *) surf; + _cairo_surface_release_source_image (surf_pat->surface, image, image_extra); + } break; + + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + _cairo_raster_source_pattern_release (pattern, surf); + break; + + case CAIRO_PATTERN_TYPE_SOLID: + case CAIRO_PATTERN_TYPE_LINEAR: + case CAIRO_PATTERN_TYPE_RADIAL: + case CAIRO_PATTERN_TYPE_MESH: + default: + ASSERT_NOT_REACHED; + break; + } +} + +static cairo_int_status_t +analyze_surface_pattern_transparency (cairo_win32_printing_surface_t *surface, + const cairo_pattern_t *pattern, + const cairo_rectangle_int_t *extents) +{ + cairo_surface_pattern_t image_pattern; + cairo_image_surface_t *image; + void *image_extra; + cairo_int_status_t status; + cairo_image_transparency_t transparency; + int pattern_width, pattern_height; + + status = _cairo_win32_printing_surface_acquire_image_pattern (surface, + pattern, + extents, + &image_pattern, + &pattern_width, + &pattern_height, + &image_extra); + if (status) + return status; + + image = (cairo_image_surface_t *)(image_pattern.surface); + transparency = _cairo_image_analyze_transparency (image); + switch (transparency) { + case CAIRO_IMAGE_UNKNOWN: + ASSERT_NOT_REACHED; + case CAIRO_IMAGE_IS_OPAQUE: + status = CAIRO_STATUS_SUCCESS; + break; + + case CAIRO_IMAGE_HAS_BILEVEL_ALPHA: + case CAIRO_IMAGE_HAS_ALPHA: + status = CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY; + break; + } + + _cairo_win32_printing_surface_release_image_pattern (surface, pattern, &image_pattern, image_extra); + + return status; +} + +static cairo_bool_t +surface_pattern_supported (const cairo_surface_pattern_t *pattern) +{ + if (_cairo_surface_is_recording (pattern->surface)) + return TRUE; + + if (pattern->surface->backend->acquire_source_image == NULL) + { + return FALSE; + } + + return TRUE; +} + +static cairo_bool_t +pattern_supported (cairo_win32_printing_surface_t *surface, const cairo_pattern_t *pattern) +{ + switch (pattern->type) { + case CAIRO_PATTERN_TYPE_SOLID: + return TRUE; + + case CAIRO_PATTERN_TYPE_LINEAR: + return surface->win32.flags & CAIRO_WIN32_SURFACE_CAN_RECT_GRADIENT; + + case CAIRO_PATTERN_TYPE_RADIAL: + case CAIRO_PATTERN_TYPE_MESH: + return FALSE; + + case CAIRO_PATTERN_TYPE_SURFACE: + return surface_pattern_supported ((cairo_surface_pattern_t *) pattern); + + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + return TRUE; + + default: + ASSERT_NOT_REACHED; + return FALSE; + } +} + +static cairo_int_status_t +_cairo_win32_printing_surface_analyze_operation (cairo_win32_printing_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *pattern, + const cairo_rectangle_int_t *extents) +{ + if (! pattern_supported (surface, pattern)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (!(op == CAIRO_OPERATOR_SOURCE || + op == CAIRO_OPERATOR_OVER || + op == CAIRO_OPERATOR_CLEAR)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { + cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern; + + if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) + return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN; + } + + if (op == CAIRO_OPERATOR_SOURCE || + op == CAIRO_OPERATOR_CLEAR) + return CAIRO_STATUS_SUCCESS; + + /* CAIRO_OPERATOR_OVER is only supported for opaque patterns. If + * the pattern contains transparency, we return + * CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY to the analysis + * surface. If the analysis surface determines that there is + * anything drawn under this operation, a fallback image will be + * used. Otherwise the operation will be replayed during the + * render stage and we blend the transarency into the white + * background to convert the pattern to opaque. + */ + + if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE || pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) + return analyze_surface_pattern_transparency (surface, pattern, extents); + + if (_cairo_pattern_is_opaque (pattern, NULL)) + return CAIRO_STATUS_SUCCESS; + else + return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY; +} + +static cairo_bool_t +_cairo_win32_printing_surface_operation_supported (cairo_win32_printing_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *pattern, + const cairo_rectangle_int_t *extents) +{ + if (_cairo_win32_printing_surface_analyze_operation (surface, op, pattern, extents) != CAIRO_INT_STATUS_UNSUPPORTED) + return TRUE; + else + return FALSE; +} + +static void +_cairo_win32_printing_surface_init_clear_color (cairo_win32_printing_surface_t *surface, + cairo_solid_pattern_t *color) +{ + if (surface->content == CAIRO_CONTENT_COLOR_ALPHA) + _cairo_pattern_init_solid (color, CAIRO_COLOR_WHITE); + else + _cairo_pattern_init_solid (color, CAIRO_COLOR_BLACK); +} + +static COLORREF +_cairo_win32_printing_surface_flatten_transparency (cairo_win32_printing_surface_t *surface, + const cairo_color_t *color) +{ + COLORREF c; + BYTE red, green, blue; + + red = color->red_short >> 8; + green = color->green_short >> 8; + blue = color->blue_short >> 8; + + if (!CAIRO_COLOR_IS_OPAQUE(color)) { + if (surface->content == CAIRO_CONTENT_COLOR_ALPHA) { + /* Blend into white */ + uint8_t one_minus_alpha = 255 - (color->alpha_short >> 8); + + red = (color->red_short >> 8) + one_minus_alpha; + green = (color->green_short >> 8) + one_minus_alpha; + blue = (color->blue_short >> 8) + one_minus_alpha; + } else { + /* Blend into black */ + red = (color->red_short >> 8); + green = (color->green_short >> 8); + blue = (color->blue_short >> 8); + } + } + c = RGB (red, green, blue); + + return c; +} + +static cairo_status_t +_cairo_win32_printing_surface_select_solid_brush (cairo_win32_printing_surface_t *surface, + const cairo_pattern_t *source) +{ + cairo_solid_pattern_t *pattern = (cairo_solid_pattern_t *) source; + COLORREF color; + + color = _cairo_win32_printing_surface_flatten_transparency (surface, + &pattern->color); + surface->brush = CreateSolidBrush (color); + if (!surface->brush) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "CreateSolidBrush"); + return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); + } + surface->old_brush = SelectObject (surface->win32.dc, surface->brush); + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_win32_printing_surface_done_solid_brush (cairo_win32_printing_surface_t *surface) +{ + if (surface->old_brush) { + SelectObject (surface->win32.dc, surface->old_brush); + DeleteObject (surface->brush); + surface->old_brush = NULL; + } +} + +static cairo_status_t +_cairo_win32_printing_surface_get_ctm_clip_box (cairo_win32_printing_surface_t *surface, + RECT *clip) +{ + XFORM xform; + + _cairo_matrix_to_win32_xform (&surface->ctm, &xform); + if (!ModifyWorldTransform (surface->win32.dc, &xform, MWT_LEFTMULTIPLY)) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "ModifyWorldTransform"); + return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); + } + GetClipBox (surface->win32.dc, clip); + + _cairo_matrix_to_win32_xform (&surface->gdi_ctm, &xform); + if (!SetWorldTransform (surface->win32.dc, &xform)) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "SetWorldTransform"); + return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_win32_printing_surface_paint_solid_pattern (cairo_win32_printing_surface_t *surface, + const cairo_pattern_t *pattern) +{ + RECT clip; + cairo_status_t status; + + GetClipBox (surface->win32.dc, &clip); + status = _cairo_win32_printing_surface_select_solid_brush (surface, pattern); + if (status) + return status; + + FillRect (surface->win32.dc, &clip, surface->brush); + _cairo_win32_printing_surface_done_solid_brush (surface); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_win32_printing_surface_paint_recording_pattern (cairo_win32_printing_surface_t *surface, + cairo_surface_pattern_t *pattern, + cairo_surface_t *source) +{ + cairo_content_t old_content; + cairo_matrix_t old_ctm; + cairo_bool_t old_has_ctm; + cairo_rectangle_int_t recording_extents; + cairo_int_status_t status; + cairo_extend_t extend; + cairo_matrix_t p2d; + XFORM xform; + int x_tile, y_tile, left, right, top, bottom; + RECT clip; + cairo_recording_surface_t *recording_surface = (cairo_recording_surface_t *) source; + cairo_box_t bbox; + cairo_bool_t is_subsurface; + + extend = cairo_pattern_get_extend (&pattern->base); + + p2d = pattern->base.matrix; + status = cairo_matrix_invert (&p2d); + /* _cairo_pattern_set_matrix guarantees invertibility */ + assert (status == CAIRO_INT_STATUS_SUCCESS); + + old_ctm = surface->ctm; + old_has_ctm = surface->has_ctm; + cairo_matrix_multiply (&p2d, &p2d, &surface->ctm); + surface->ctm = p2d; + SaveDC (surface->win32.dc); + _cairo_matrix_to_win32_xform (&p2d, &xform); + + if (recording_surface->base.backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) { + cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) recording_surface; + + recording_surface = (cairo_recording_surface_t *) (sub->target); + recording_extents = sub->extents; + is_subsurface = TRUE; + } else { + status = _cairo_recording_surface_get_bbox (recording_surface, &bbox, NULL); + if (status) + goto err; + + _cairo_box_round_to_rectangle (&bbox, &recording_extents); + } + + status = _cairo_win32_printing_surface_get_ctm_clip_box (surface, &clip); + if (status) + goto err; + + if (extend == CAIRO_EXTEND_REPEAT || extend == CAIRO_EXTEND_REFLECT) { + left = floor (clip.left / _cairo_fixed_to_double (bbox.p2.x - bbox.p1.x)); + right = ceil (clip.right / _cairo_fixed_to_double (bbox.p2.x - bbox.p1.x)); + top = floor (clip.top / _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y)); + bottom = ceil (clip.bottom / _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y)); + } else { + left = 0; + right = 1; + top = 0; + bottom = 1; + } + + old_content = surface->content; + if (recording_surface->base.content == CAIRO_CONTENT_COLOR) { + surface->content = CAIRO_CONTENT_COLOR; + status = _cairo_win32_printing_surface_paint_solid_pattern (surface, + &_cairo_pattern_black.base); + if (status) + goto err; + } + + for (y_tile = top; y_tile < bottom; y_tile++) { + for (x_tile = left; x_tile < right; x_tile++) { + cairo_matrix_t m; + double x, y; + + SaveDC (surface->win32.dc); + m = p2d; + cairo_matrix_translate (&m, + x_tile*recording_extents.width, + y_tile*recording_extents.height); + if (extend == CAIRO_EXTEND_REFLECT) { + if (x_tile % 2) { + cairo_matrix_translate (&m, recording_extents.width, 0); + cairo_matrix_scale (&m, -1, 1); + } + if (y_tile % 2) { + cairo_matrix_translate (&m, 0, recording_extents.height); + cairo_matrix_scale (&m, 1, -1); + } + } + surface->ctm = m; + surface->has_ctm = !_cairo_matrix_is_identity (&surface->ctm); + + /* Set clip path around bbox of the pattern. */ + BeginPath (surface->win32.dc); + + x = 0; + y = 0; + cairo_matrix_transform_point (&surface->ctm, &x, &y); + MoveToEx (surface->win32.dc, (int) x, (int) y, NULL); + + x = recording_extents.width; + y = 0; + cairo_matrix_transform_point (&surface->ctm, &x, &y); + LineTo (surface->win32.dc, (int) x, (int) y); + + x = recording_extents.width; + y = recording_extents.height; + cairo_matrix_transform_point (&surface->ctm, &x, &y); + LineTo (surface->win32.dc, (int) x, (int) y); + + x = 0; + y = recording_extents.height; + cairo_matrix_transform_point (&surface->ctm, &x, &y); + LineTo (surface->win32.dc, (int) x, (int) y); + + CloseFigure (surface->win32.dc); + EndPath (surface->win32.dc); + SelectClipPath (surface->win32.dc, RGN_AND); + + SaveDC (surface->win32.dc); /* Allow clip path to be reset during replay */ + status = _cairo_recording_surface_replay_region (&recording_surface->base, + pattern->region_array_id, + is_subsurface ? &recording_extents : NULL, + &surface->win32.base, + CAIRO_RECORDING_REGION_NATIVE); + assert (status != CAIRO_INT_STATUS_UNSUPPORTED); + /* Restore both the clip save and our earlier path SaveDC */ + RestoreDC (surface->win32.dc, -2); + + if (status) + goto err; + } + } + + surface->content = old_content; + surface->ctm = old_ctm; + surface->has_ctm = old_has_ctm; + RestoreDC (surface->win32.dc, -1); + + err: + return status; +} + +static cairo_int_status_t +_cairo_win32_printing_surface_check_jpeg (cairo_win32_printing_surface_t *surface, + cairo_surface_t *source, + const unsigned char **data, + unsigned long *length, + cairo_image_info_t *info) +{ + const unsigned char *mime_data; + unsigned long mime_data_length; + cairo_int_status_t status; + DWORD result; + + if (!(surface->win32.flags & CAIRO_WIN32_SURFACE_CAN_CHECK_JPEG)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_JPEG, + &mime_data, &mime_data_length); + if (mime_data == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_image_info_get_jpeg_info (info, mime_data, mime_data_length); + if (status) + return status; + + result = 0; + if (ExtEscape(surface->win32.dc, CHECKJPEGFORMAT, mime_data_length, (char *) mime_data, + sizeof(result), (char *) &result) <= 0) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (result != 1) + return CAIRO_INT_STATUS_UNSUPPORTED; + + *data = mime_data; + *length = mime_data_length; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_win32_printing_surface_check_png (cairo_win32_printing_surface_t *surface, + cairo_surface_t *source, + const unsigned char **data, + unsigned long *length, + cairo_image_info_t *info) +{ + const unsigned char *mime_data; + unsigned long mime_data_length; + + cairo_int_status_t status; + DWORD result; + + if (!(surface->win32.flags & CAIRO_WIN32_SURFACE_CAN_CHECK_PNG)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + cairo_surface_get_mime_data (source, CAIRO_MIME_TYPE_PNG, + &mime_data, &mime_data_length); + if (mime_data == NULL) + return CAIRO_INT_STATUS_UNSUPPORTED; + + status = _cairo_image_info_get_png_info (info, mime_data, mime_data_length); + if (status) + return status; + + result = 0; + if (ExtEscape(surface->win32.dc, CHECKPNGFORMAT, mime_data_length, (char *) mime_data, + sizeof(result), (char *) &result) <= 0) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (result != 1) + return CAIRO_INT_STATUS_UNSUPPORTED; + + *data = mime_data; + *length = mime_data_length; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_win32_printing_surface_paint_image_pattern (cairo_win32_printing_surface_t *surface, + const cairo_pattern_t *pattern, + const cairo_rectangle_int_t *extents) +{ + cairo_int_status_t status; + cairo_surface_pattern_t image_pattern; + cairo_image_surface_t *image; + void *image_extra; + cairo_image_surface_t *opaque_image = NULL; + BITMAPINFO bi; + cairo_matrix_t m; + int oldmode; + XFORM xform; + int x_tile, y_tile, left, right, top, bottom; + int pattern_width, pattern_height; + RECT clip; + const cairo_color_t *background_color; + const unsigned char *mime_data; + unsigned long mime_size; + cairo_image_info_t mime_info; + cairo_bool_t use_mime; + DWORD mime_type; + + /* If we can't use StretchDIBits with this surface, we can't do anything + * here. + */ + if (!(surface->win32.flags & CAIRO_WIN32_SURFACE_CAN_STRETCHDIB)) + return CAIRO_INT_STATUS_UNSUPPORTED; + + if (surface->content == CAIRO_CONTENT_COLOR_ALPHA) + background_color = CAIRO_COLOR_WHITE; + else + background_color = CAIRO_COLOR_BLACK; + + status = _cairo_win32_printing_surface_acquire_image_pattern (surface, + pattern, + extents, + &image_pattern, + &pattern_width, + &pattern_height, + &image_extra); + if (status) + return status; + + image = (cairo_image_surface_t *)(image_pattern.surface); + if (image->base.status) { + status = image->base.status; + goto CLEANUP_IMAGE; + } + + if (image->width == 0 || image->height == 0) { + status = CAIRO_STATUS_SUCCESS; + goto CLEANUP_IMAGE; + } + + mime_type = BI_JPEG; + status = _cairo_win32_printing_surface_check_jpeg (surface, + image_pattern.surface, + &mime_data, + &mime_size, + &mime_info); + if (status == CAIRO_INT_STATUS_UNSUPPORTED) { + mime_type = BI_PNG; + status = _cairo_win32_printing_surface_check_png (surface, + image_pattern.surface, + &mime_data, + &mime_size, + &mime_info); + } + if (_cairo_int_status_is_error (status)) + return status; + + use_mime = (status == CAIRO_INT_STATUS_SUCCESS); + + if (!use_mime && image->format != CAIRO_FORMAT_RGB24) { + cairo_surface_t *opaque_surface; + cairo_surface_pattern_t image_pattern; + cairo_solid_pattern_t background_pattern; + + opaque_surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, + image->width, + image->height); + if (opaque_surface->status) { + status = opaque_surface->status; + goto CLEANUP_OPAQUE_IMAGE; + } + + _cairo_pattern_init_solid (&background_pattern, + background_color); + status = _cairo_surface_paint (opaque_surface, + CAIRO_OPERATOR_SOURCE, + &background_pattern.base, + NULL); + if (status) + goto CLEANUP_OPAQUE_IMAGE; + + _cairo_pattern_init_for_surface (&image_pattern, &image->base); + status = _cairo_surface_paint (opaque_surface, + CAIRO_OPERATOR_OVER, + &image_pattern.base, + NULL); + _cairo_pattern_fini (&image_pattern.base); + if (status) + goto CLEANUP_OPAQUE_IMAGE; + + opaque_image = (cairo_image_surface_t *) opaque_surface; + } else { + opaque_image = image; + } + + bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bi.bmiHeader.biWidth = use_mime ? mime_info.width : opaque_image->width; + bi.bmiHeader.biHeight = use_mime ? - mime_info.height : -opaque_image->height; + bi.bmiHeader.biSizeImage = use_mime ? mime_size : 0; + bi.bmiHeader.biXPelsPerMeter = PELS_72DPI; + bi.bmiHeader.biYPelsPerMeter = PELS_72DPI; + bi.bmiHeader.biPlanes = 1; + bi.bmiHeader.biBitCount = 32; + bi.bmiHeader.biCompression = use_mime ? mime_type : BI_RGB; + bi.bmiHeader.biClrUsed = 0; + bi.bmiHeader.biClrImportant = 0; + + m = image_pattern.base.matrix; + status = cairo_matrix_invert (&m); + /* _cairo_pattern_set_matrix guarantees invertibility */ + assert (status == CAIRO_INT_STATUS_SUCCESS); + + cairo_matrix_multiply (&m, &m, &surface->ctm); + cairo_matrix_multiply (&m, &m, &surface->gdi_ctm); + SaveDC (surface->win32.dc); + _cairo_matrix_to_win32_xform (&m, &xform); + + if (! SetWorldTransform (surface->win32.dc, &xform)) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "SetWorldTransform"); + status = _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); + goto CLEANUP_OPAQUE_IMAGE; + } + + oldmode = SetStretchBltMode(surface->win32.dc, HALFTONE); + + GetClipBox (surface->win32.dc, &clip); + if (pattern->extend == CAIRO_EXTEND_REPEAT || pattern->extend == CAIRO_EXTEND_REFLECT) { + left = floor ( clip.left / (double) opaque_image->width); + right = ceil (clip.right / (double) opaque_image->width); + top = floor (clip.top / (double) opaque_image->height); + bottom = ceil (clip.bottom / (double) opaque_image->height); + } else { + left = 0; + right = 1; + top = 0; + bottom = 1; + } + + for (y_tile = top; y_tile < bottom; y_tile++) { + for (x_tile = left; x_tile < right; x_tile++) { + if (!StretchDIBits (surface->win32.dc, + x_tile*opaque_image->width, + y_tile*opaque_image->height, + opaque_image->width, + opaque_image->height, + 0, + 0, + use_mime ? mime_info.width : opaque_image->width, + use_mime ? mime_info.height : opaque_image->height, + use_mime ? mime_data : opaque_image->data, + &bi, + DIB_RGB_COLORS, + SRCCOPY)) + { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "StretchDIBits"); + status = _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); + goto CLEANUP_OPAQUE_IMAGE; + } + } + } + SetStretchBltMode(surface->win32.dc, oldmode); + RestoreDC (surface->win32.dc, -1); + +CLEANUP_OPAQUE_IMAGE: + if (opaque_image != image) + cairo_surface_destroy (&opaque_image->base); +CLEANUP_IMAGE: + _cairo_win32_printing_surface_release_image_pattern (surface, pattern, &image_pattern, image_extra); + + return status; +} + +static void +vertex_set_color (TRIVERTEX *vert, cairo_color_stop_t *color) +{ + /* MSDN says that the range here is 0x0000 .. 0xff00; + * that may well be a typo, but just chop the low bits + * here. */ + vert->Alpha = 0xff00; + vert->Red = color->red_short & 0xff00; + vert->Green = color->green_short & 0xff00; + vert->Blue = color->blue_short & 0xff00; +} + +static cairo_int_status_t +_cairo_win32_printing_surface_paint_linear_pattern (cairo_win32_printing_surface_t *surface, + cairo_linear_pattern_t *pattern) +{ + TRIVERTEX *vert; + GRADIENT_RECT *rect; + RECT clip; + XFORM xform; + int i, num_stops; + cairo_matrix_t mat, rot; + double p1x, p1y, p2x, p2y, xd, yd, d, sn, cs; + cairo_extend_t extend; + int range_start, range_stop, num_ranges, num_rects, stop; + int total_verts, total_rects; + cairo_status_t status; + + extend = cairo_pattern_get_extend (&pattern->base.base); + SaveDC (surface->win32.dc); + + mat = pattern->base.base.matrix; + status = cairo_matrix_invert (&mat); + /* _cairo_pattern_set_matrix guarantees invertibility */ + assert (status == CAIRO_STATUS_SUCCESS); + + cairo_matrix_multiply (&mat, &surface->ctm, &mat); + + p1x = pattern->pd1.x; + p1y = pattern->pd1.y; + p2x = pattern->pd2.x; + p2y = pattern->pd2.y; + cairo_matrix_translate (&mat, p1x, p1y); + + xd = p2x - p1x; + yd = p2y - p1y; + d = sqrt (xd*xd + yd*yd); + sn = yd/d; + cs = xd/d; + cairo_matrix_init (&rot, + cs, sn, + -sn, cs, + 0, 0); + cairo_matrix_multiply (&mat, &rot, &mat); + + _cairo_matrix_to_win32_xform (&mat, &xform); + + if (!SetWorldTransform (surface->win32.dc, &xform)) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "SetWorldTransform"); + return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); + } + + GetClipBox (surface->win32.dc, &clip); + + if (extend == CAIRO_EXTEND_REPEAT || extend == CAIRO_EXTEND_REFLECT) { + range_start = floor (clip.left / d); + range_stop = ceil (clip.right / d); + } else { + range_start = 0; + range_stop = 1; + } + num_ranges = range_stop - range_start; + num_stops = pattern->base.n_stops; + num_rects = num_stops - 1; + + /* Add an extra four points and two rectangles for EXTEND_PAD */ + vert = _cairo_malloc (sizeof (TRIVERTEX) * (num_rects*2*num_ranges + 4)); + rect = _cairo_malloc (sizeof (GRADIENT_RECT) * (num_rects*num_ranges + 2)); + + for (i = 0; i < num_ranges*num_rects; i++) { + vert[i*2].y = (LONG) clip.top; + if (i%num_rects == 0) { + stop = 0; + if (extend == CAIRO_EXTEND_REFLECT && (range_start+(i/num_rects))%2) + stop = num_rects; + vert[i*2].x = (LONG)(d*(range_start + i/num_rects)); + vertex_set_color (&vert[i*2], &pattern->base.stops[stop].color); + } else { + vert[i*2].x = vert[i*2-1].x; + vert[i*2].Red = vert[i*2-1].Red; + vert[i*2].Green = vert[i*2-1].Green; + vert[i*2].Blue = vert[i*2-1].Blue; + vert[i*2].Alpha = vert[i*2-1].Alpha; + } + + stop = i%num_rects + 1; + vert[i*2+1].x = (LONG)(d*(range_start + i/num_rects + pattern->base.stops[stop].offset)); + vert[i*2+1].y = (LONG) clip.bottom; + if (extend == CAIRO_EXTEND_REFLECT && (range_start+(i/num_rects))%2) + stop = num_rects - stop; + vertex_set_color (&vert[i*2+1], &pattern->base.stops[stop].color); + + rect[i].UpperLeft = i*2; + rect[i].LowerRight = i*2 + 1; + } + total_verts = 2*num_ranges*num_rects; + total_rects = num_ranges*num_rects; + + if (extend == CAIRO_EXTEND_PAD) { + vert[i*2].x = vert[i*2-1].x; + vert[i*2].y = (LONG) clip.top; + vert[i*2].Red = vert[i*2-1].Red; + vert[i*2].Green = vert[i*2-1].Green; + vert[i*2].Blue = vert[i*2-1].Blue; + vert[i*2].Alpha = 0xff00; + vert[i*2+1].x = clip.right; + vert[i*2+1].y = (LONG) clip.bottom; + vert[i*2+1].Red = vert[i*2-1].Red; + vert[i*2+1].Green = vert[i*2-1].Green; + vert[i*2+1].Blue = vert[i*2-1].Blue; + vert[i*2+1].Alpha = 0xff00; + rect[i].UpperLeft = i*2; + rect[i].LowerRight = i*2 + 1; + + i++; + + vert[i*2].x = clip.left; + vert[i*2].y = (LONG) clip.top; + vert[i*2].Red = vert[0].Red; + vert[i*2].Green = vert[0].Green; + vert[i*2].Blue = vert[0].Blue; + vert[i*2].Alpha = 0xff00; + vert[i*2+1].x = vert[0].x; + vert[i*2+1].y = (LONG) clip.bottom; + vert[i*2+1].Red = vert[0].Red; + vert[i*2+1].Green = vert[0].Green; + vert[i*2+1].Blue = vert[0].Blue; + vert[i*2+1].Alpha = 0xff00; + rect[i].UpperLeft = i*2; + rect[i].LowerRight = i*2 + 1; + + total_verts += 4; + total_rects += 2; + } + + if (!GradientFill (surface->win32.dc, + vert, total_verts, + rect, total_rects, + GRADIENT_FILL_RECT_H)) + { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "GradientFill"); + return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); + } + + free (rect); + free (vert); + RestoreDC (surface->win32.dc, -1); + + return 0; +} + +static cairo_int_status_t +_cairo_win32_printing_surface_paint_pattern (cairo_win32_printing_surface_t *surface, + const cairo_pattern_t *pattern, + const cairo_rectangle_int_t *extents) +{ + cairo_status_t status; + + switch (pattern->type) { + case CAIRO_PATTERN_TYPE_SOLID: + status = _cairo_win32_printing_surface_paint_solid_pattern (surface, pattern); + if (status) + return status; + break; + + case CAIRO_PATTERN_TYPE_SURFACE: { + cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern; + cairo_surface_t *source = surface_pattern->surface; + cairo_surface_t *to_destroy = NULL; + + if (_cairo_surface_is_snapshot (source)) + to_destroy = source = _cairo_surface_snapshot_get_target (source); + + if ( _cairo_surface_is_recording (source)) + status = _cairo_win32_printing_surface_paint_recording_pattern (surface, surface_pattern, source); + else + status = _cairo_win32_printing_surface_paint_image_pattern (surface, pattern, extents); + + cairo_surface_destroy (to_destroy); + + if (status) + return status; + break; + } + case CAIRO_PATTERN_TYPE_RASTER_SOURCE: + status = _cairo_win32_printing_surface_paint_image_pattern (surface, pattern, extents); + if (status) + return status; + break; + + case CAIRO_PATTERN_TYPE_LINEAR: + status = _cairo_win32_printing_surface_paint_linear_pattern (surface, (cairo_linear_pattern_t *) pattern); + if (status) + return status; + break; + + case CAIRO_PATTERN_TYPE_RADIAL: + return CAIRO_INT_STATUS_UNSUPPORTED; + break; + + case CAIRO_PATTERN_TYPE_MESH: + ASSERT_NOT_REACHED; + } + + return CAIRO_STATUS_SUCCESS; +} + +typedef struct _win32_print_path_info { + cairo_win32_printing_surface_t *surface; +} win32_path_info_t; + +static cairo_status_t +_cairo_win32_printing_surface_path_move_to (void *closure, + const cairo_point_t *point) +{ + win32_path_info_t *path_info = closure; + + if (path_info->surface->has_ctm) { + double x, y; + + x = _cairo_fixed_to_double (point->x); + y = _cairo_fixed_to_double (point->y); + cairo_matrix_transform_point (&path_info->surface->ctm, &x, &y); + MoveToEx (path_info->surface->win32.dc, (int) x, (int) y, NULL); + } else { + MoveToEx (path_info->surface->win32.dc, + _cairo_fixed_integer_part (point->x), + _cairo_fixed_integer_part (point->y), + NULL); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_win32_printing_surface_path_line_to (void *closure, + const cairo_point_t *point) +{ + win32_path_info_t *path_info = closure; + + path_info->surface->path_empty = FALSE; + if (path_info->surface->has_ctm) { + double x, y; + + x = _cairo_fixed_to_double (point->x); + y = _cairo_fixed_to_double (point->y); + cairo_matrix_transform_point (&path_info->surface->ctm, &x, &y); + LineTo (path_info->surface->win32.dc, (int) x, (int) y); + } else { + LineTo (path_info->surface->win32.dc, + _cairo_fixed_integer_part (point->x), + _cairo_fixed_integer_part (point->y)); + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_win32_printing_surface_path_curve_to (void *closure, + const cairo_point_t *b, + const cairo_point_t *c, + const cairo_point_t *d) +{ + win32_path_info_t *path_info = closure; + POINT points[3]; + + path_info->surface->path_empty = FALSE; + if (path_info->surface->has_ctm) { + double x, y; + + x = _cairo_fixed_to_double (b->x); + y = _cairo_fixed_to_double (b->y); + cairo_matrix_transform_point (&path_info->surface->ctm, &x, &y); + points[0].x = (LONG) x; + points[0].y = (LONG) y; + + x = _cairo_fixed_to_double (c->x); + y = _cairo_fixed_to_double (c->y); + cairo_matrix_transform_point (&path_info->surface->ctm, &x, &y); + points[1].x = (LONG) x; + points[1].y = (LONG) y; + + x = _cairo_fixed_to_double (d->x); + y = _cairo_fixed_to_double (d->y); + cairo_matrix_transform_point (&path_info->surface->ctm, &x, &y); + points[2].x = (LONG) x; + points[2].y = (LONG) y; + } else { + points[0].x = _cairo_fixed_integer_part (b->x); + points[0].y = _cairo_fixed_integer_part (b->y); + points[1].x = _cairo_fixed_integer_part (c->x); + points[1].y = _cairo_fixed_integer_part (c->y); + points[2].x = _cairo_fixed_integer_part (d->x); + points[2].y = _cairo_fixed_integer_part (d->y); + } + PolyBezierTo (path_info->surface->win32.dc, points, 3); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_win32_printing_surface_path_close_path (void *closure) +{ + win32_path_info_t *path_info = closure; + + CloseFigure (path_info->surface->win32.dc); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_win32_printing_surface_emit_path (cairo_win32_printing_surface_t *surface, + const cairo_path_fixed_t *path) +{ + win32_path_info_t path_info; + + path_info.surface = surface; + return _cairo_path_fixed_interpret (path, + _cairo_win32_printing_surface_path_move_to, + _cairo_win32_printing_surface_path_line_to, + _cairo_win32_printing_surface_path_curve_to, + _cairo_win32_printing_surface_path_close_path, + &path_info); +} + +static cairo_int_status_t +_cairo_win32_printing_surface_show_page (void *abstract_surface) +{ + cairo_win32_printing_surface_t *surface = abstract_surface; + + /* Undo both SaveDC's that we did in start_page */ + RestoreDC (surface->win32.dc, -2); + + /* Invalidate extents since the size of the next page is not known at + * this point. + */ + surface->extents_valid = FALSE; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_win32_printing_surface_clipper_intersect_clip_path (cairo_surface_clipper_t *clipper, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_win32_printing_surface_t *surface = cairo_container_of (clipper, + cairo_win32_printing_surface_t, + clipper); + cairo_status_t status; + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) + return CAIRO_STATUS_SUCCESS; + + if (path == NULL) { + RestoreDC (surface->win32.dc, -1); + SaveDC (surface->win32.dc); + + return CAIRO_STATUS_SUCCESS; + } + + BeginPath (surface->win32.dc); + status = _cairo_win32_printing_surface_emit_path (surface, path); + EndPath (surface->win32.dc); + + switch (fill_rule) { + case CAIRO_FILL_RULE_WINDING: + SetPolyFillMode (surface->win32.dc, WINDING); + break; + case CAIRO_FILL_RULE_EVEN_ODD: + SetPolyFillMode (surface->win32.dc, ALTERNATE); + break; + default: + ASSERT_NOT_REACHED; + } + + SelectClipPath (surface->win32.dc, RGN_AND); + + return status; +} + +static cairo_bool_t +_cairo_win32_printing_surface_get_extents (void *abstract_surface, + cairo_rectangle_int_t *rectangle) +{ + cairo_win32_printing_surface_t *surface = abstract_surface; + + if (surface->extents_valid) + *rectangle = surface->win32.extents; + + return surface->extents_valid; +} + +static void +_cairo_win32_printing_surface_get_font_options (void *abstract_surface, + cairo_font_options_t *options) +{ + _cairo_font_options_init_default (options); + + cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE); + cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF); + cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_GRAY); + _cairo_font_options_set_round_glyph_positions (options, CAIRO_ROUND_GLYPH_POS_ON); +} + +static cairo_int_status_t +_cairo_win32_printing_surface_paint (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_clip_t *clip) +{ + cairo_win32_printing_surface_t *surface = abstract_surface; + cairo_solid_pattern_t clear; + cairo_composite_rectangles_t extents; + cairo_status_t status; + + status = _cairo_composite_rectangles_init_for_paint (&extents, + &surface->win32.base, + op, source, clip); + if (unlikely (status)) + return status; + + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) + goto cleanup_composite; + + if (op == CAIRO_OPERATOR_CLEAR) { + _cairo_win32_printing_surface_init_clear_color (surface, &clear); + source = (cairo_pattern_t*) &clear; + op = CAIRO_OPERATOR_SOURCE; + } + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) { + status = _cairo_win32_printing_surface_analyze_operation (surface, op, source, &extents.bounded); + goto cleanup_composite; + } + + assert (_cairo_win32_printing_surface_operation_supported (surface, op, source, &extents.bounded)); + + status = _cairo_win32_printing_surface_paint_pattern (surface, source, &extents.bounded); + + cleanup_composite: + _cairo_composite_rectangles_fini (&extents); + return status; +} + +static int +_cairo_win32_line_cap (cairo_line_cap_t cap) +{ + switch (cap) { + case CAIRO_LINE_CAP_BUTT: + return PS_ENDCAP_FLAT; + case CAIRO_LINE_CAP_ROUND: + return PS_ENDCAP_ROUND; + case CAIRO_LINE_CAP_SQUARE: + return PS_ENDCAP_SQUARE; + default: + ASSERT_NOT_REACHED; + return 0; + } +} + +static int +_cairo_win32_line_join (cairo_line_join_t join) +{ + switch (join) { + case CAIRO_LINE_JOIN_MITER: + return PS_JOIN_MITER; + case CAIRO_LINE_JOIN_ROUND: + return PS_JOIN_ROUND; + case CAIRO_LINE_JOIN_BEVEL: + return PS_JOIN_BEVEL; + default: + ASSERT_NOT_REACHED; + return 0; + } +} + +static void +_cairo_matrix_factor_out_scale (cairo_matrix_t *m, double *scale) +{ + double s; + + s = fabs (m->xx); + if (fabs (m->xy) > s) + s = fabs (m->xy); + if (fabs (m->yx) > s) + s = fabs (m->yx); + if (fabs (m->yy) > s) + s = fabs (m->yy); + *scale = s; + s = 1.0/s; + cairo_matrix_scale (m, s, s); +} + +static cairo_int_status_t +_cairo_win32_printing_surface_stroke (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + const cairo_stroke_style_t *style, + const cairo_matrix_t *stroke_ctm, + const cairo_matrix_t *stroke_ctm_inverse, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_win32_printing_surface_t *surface = abstract_surface; + cairo_int_status_t status; + HPEN pen; + LOGBRUSH brush; + COLORREF color; + XFORM xform; + DWORD pen_style; + DWORD *dash_array; + HGDIOBJ obj; + unsigned int i; + cairo_solid_pattern_t clear; + cairo_matrix_t mat; + double scale; + cairo_composite_rectangles_t extents; + + status = _cairo_composite_rectangles_init_for_stroke (&extents, + &surface->win32.base, + op, source, + path, style, stroke_ctm, + clip); + if (unlikely (status)) + return status; + + /* use the more accurate extents */ + { + cairo_rectangle_int_t r; + cairo_box_t b; + + status = _cairo_path_fixed_stroke_extents (path, style, + stroke_ctm, stroke_ctm_inverse, + tolerance, + &r); + if (unlikely (status)) + goto cleanup_composite; + + _cairo_box_from_rectangle (&b, &r); + status = _cairo_composite_rectangles_intersect_mask_extents (&extents, &b); + if (unlikely (status)) + goto cleanup_composite; + } + + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) + goto cleanup_composite; + + if (op == CAIRO_OPERATOR_CLEAR) { + _cairo_win32_printing_surface_init_clear_color (surface, &clear); + source = (cairo_pattern_t*) &clear; + op = CAIRO_OPERATOR_SOURCE; + } + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) { + /* Win32 does not support a dash offset. */ + if (style->num_dashes > 0 && style->dash_offset != 0.0) + status = CAIRO_INT_STATUS_UNSUPPORTED; + else + status = _cairo_win32_printing_surface_analyze_operation (surface, op, source, &extents.bounded); + + goto cleanup_composite; + } + + assert (_cairo_win32_printing_surface_operation_supported (surface, op, source, &extents.bounded)); + assert (!(style->num_dashes > 0 && style->dash_offset != 0.0)); + + cairo_matrix_multiply (&mat, stroke_ctm, &surface->ctm); + _cairo_matrix_factor_out_scale (&mat, &scale); + + pen_style = style->is_hairline ? PS_COSMETIC : PS_GEOMETRIC; + dash_array = NULL; + if (style->num_dashes) { + pen_style |= PS_USERSTYLE; + dash_array = _cairo_calloc_ab (sizeof (DWORD), style->num_dashes); + for (i = 0; i < style->num_dashes; i++) { + dash_array[i] = (DWORD) (scale * style->dash[i]); + } + } else { + pen_style |= PS_SOLID; + } + + SetMiterLimit (surface->win32.dc, (FLOAT) (style->miter_limit), NULL); + if (source->type == CAIRO_PATTERN_TYPE_SOLID) { + cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source; + + + color = _cairo_win32_printing_surface_flatten_transparency (surface, + &solid->color); + } else { + /* Color not used as the pen will only be used by WidenPath() */ + color = RGB (0,0,0); + } + brush.lbStyle = BS_SOLID; + brush.lbColor = color; + brush.lbHatch = 0; + if (!style->is_hairline) { + pen_style |= _cairo_win32_line_cap (style->line_cap); + pen_style |= _cairo_win32_line_join (style->line_join); + } + pen = ExtCreatePen(pen_style, + style->is_hairline ? 1 : scale * style->line_width, + &brush, + style->num_dashes, + dash_array); + if (pen == NULL) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "ExtCreatePen"); + status = _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); + goto cleanup_composite; + } + + obj = SelectObject (surface->win32.dc, pen); + if (obj == NULL) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "SelectObject"); + status = _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); + goto cleanup_composite; + } + + BeginPath (surface->win32.dc); + status = _cairo_win32_printing_surface_emit_path (surface, path); + EndPath (surface->win32.dc); + if (unlikely (status)) + goto cleanup_composite; + + /* + * Switch to user space to set line parameters + */ + SaveDC (surface->win32.dc); + + _cairo_matrix_to_win32_xform (&mat, &xform); + xform.eDx = 0.0f; + xform.eDy = 0.0f; + + if (!ModifyWorldTransform (surface->win32.dc, &xform, MWT_LEFTMULTIPLY)) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "ModifyWorldTransform"); + status = _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); + goto cleanup_composite; + } + + if (source->type == CAIRO_PATTERN_TYPE_SOLID) { + StrokePath (surface->win32.dc); + } else { + if (!WidenPath (surface->win32.dc)) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "WidenPath"); + status = _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); + goto cleanup_composite; + } + if (!SelectClipPath (surface->win32.dc, RGN_AND)) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "SelectClipPath"); + status = _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); + goto cleanup_composite; + } + + /* Return to device space to paint the pattern */ + _cairo_matrix_to_win32_xform (&surface->gdi_ctm, &xform); + if (!SetWorldTransform (surface->win32.dc, &xform)) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "SetWorldTransform"); + status = _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); + goto cleanup_composite; + } + status = _cairo_win32_printing_surface_paint_pattern (surface, source, &extents.bounded); + } + RestoreDC (surface->win32.dc, -1); + DeleteObject (pen); + free (dash_array); + +cleanup_composite: + _cairo_composite_rectangles_fini (&extents); + return status; +} + +static cairo_int_status_t +_cairo_win32_printing_surface_fill (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + const cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias, + const cairo_clip_t *clip) +{ + cairo_win32_printing_surface_t *surface = abstract_surface; + cairo_int_status_t status; + cairo_solid_pattern_t clear; + cairo_composite_rectangles_t extents; + + status = _cairo_composite_rectangles_init_for_fill (&extents, + &surface->win32.base, + op, source, path, + clip); + if (unlikely (status)) + return status; + + /* use the more accurate extents */ + { + cairo_rectangle_int_t r; + cairo_box_t b; + + _cairo_path_fixed_fill_extents (path, + fill_rule, + tolerance, + &r); + + _cairo_box_from_rectangle (&b, &r); + status = _cairo_composite_rectangles_intersect_mask_extents (&extents, &b); + if (unlikely (status)) + goto cleanup_composite; + } + + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) + goto cleanup_composite; + + if (op == CAIRO_OPERATOR_CLEAR) { + _cairo_win32_printing_surface_init_clear_color (surface, &clear); + source = (cairo_pattern_t*) &clear; + op = CAIRO_OPERATOR_SOURCE; + } + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) { + status = _cairo_win32_printing_surface_analyze_operation (surface, op, source, &extents.bounded); + goto cleanup_composite; + } + + assert (_cairo_win32_printing_surface_operation_supported (surface, op, source, &extents.bounded)); + + surface->path_empty = TRUE; + BeginPath (surface->win32.dc); + status = _cairo_win32_printing_surface_emit_path (surface, path); + EndPath (surface->win32.dc); + + switch (fill_rule) { + case CAIRO_FILL_RULE_WINDING: + SetPolyFillMode (surface->win32.dc, WINDING); + break; + case CAIRO_FILL_RULE_EVEN_ODD: + SetPolyFillMode (surface->win32.dc, ALTERNATE); + break; + default: + ASSERT_NOT_REACHED; + } + + if (source->type == CAIRO_PATTERN_TYPE_SOLID) { + status = _cairo_win32_printing_surface_select_solid_brush (surface, source); + if (unlikely (status)) + goto cleanup_composite; + + FillPath (surface->win32.dc); + _cairo_win32_printing_surface_done_solid_brush (surface); + } else if (surface->path_empty == FALSE) { + SaveDC (surface->win32.dc); + SelectClipPath (surface->win32.dc, RGN_AND); + status = _cairo_win32_printing_surface_paint_pattern (surface, source, &extents.bounded); + RestoreDC (surface->win32.dc, -1); + } + + fflush(stderr); + +cleanup_composite: + _cairo_composite_rectangles_fini (&extents); + return status; +} + + +static cairo_int_status_t +_cairo_win32_printing_surface_emit_win32_glyphs (cairo_win32_printing_surface_t *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip) +{ + cairo_matrix_t ctm; + cairo_glyph_t *unicode_glyphs; + cairo_scaled_font_subsets_glyph_t subset_glyph; + int i, first; + cairo_bool_t sequence_is_unicode; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + + /* Where possible reverse the glyph indices back to unicode + * characters. Strings of glyphs that could not be reversed to + * unicode will be printed with ETO_GLYPH_INDEX. + * + * As _cairo_win32_scaled_font_index_to_ucs4() is a slow + * operation, the font subsetting function + * _cairo_scaled_font_subsets_map_glyph() is used to obtain + * the unicode value because it caches the reverse mapping in + * the subsets. + */ + + if (surface->has_ctm) { + for (i = 0; i < num_glyphs; i++) + cairo_matrix_transform_point (&surface->ctm, &glyphs[i].x, &glyphs[i].y); + cairo_matrix_multiply (&ctm, &scaled_font->ctm, &surface->ctm); + scaled_font = cairo_scaled_font_create (scaled_font->font_face, + &scaled_font->font_matrix, + &ctm, + &scaled_font->options); + } + + unicode_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t)); + if (unicode_glyphs == NULL) + return _cairo_error (CAIRO_STATUS_NO_MEMORY); + + memcpy (unicode_glyphs, glyphs, num_glyphs * sizeof (cairo_glyph_t)); + for (i = 0; i < num_glyphs; i++) { + status = _cairo_scaled_font_subsets_map_glyph (surface->font_subsets, + scaled_font, + glyphs[i].index, + NULL, 0, + &subset_glyph); + if (status) + goto fail; + + unicode_glyphs[i].index = subset_glyph.unicode; + } + + i = 0; + first = 0; + sequence_is_unicode = unicode_glyphs[0].index <= 0xffff; + while (i < num_glyphs) { + if (i == num_glyphs - 1 || + ((unicode_glyphs[i + 1].index < 0xffff) != sequence_is_unicode)) + { + status = _cairo_win32_surface_emit_glyphs (&surface->win32, + source, + sequence_is_unicode ? &unicode_glyphs[first] : &glyphs[first], + i - first + 1, + scaled_font, + ! sequence_is_unicode); + first = i + 1; + if (i < num_glyphs - 1) + sequence_is_unicode = unicode_glyphs[i + 1].index <= 0xffff; + } + i++; + } + +fail: + if (surface->has_ctm) + cairo_scaled_font_destroy (scaled_font); + + free (unicode_glyphs); + + return status; +} + +static cairo_int_status_t +_cairo_win32_printing_surface_show_glyphs (void *abstract_surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + const cairo_clip_t *clip) +{ + cairo_win32_printing_surface_t *surface = abstract_surface; + cairo_status_t status = CAIRO_STATUS_SUCCESS; + cairo_scaled_glyph_t *scaled_glyph; + cairo_pattern_t *opaque = NULL; + int i; + cairo_matrix_t old_ctm; + cairo_bool_t old_has_ctm; + cairo_solid_pattern_t clear; + cairo_composite_rectangles_t extents; + cairo_bool_t overlap; + cairo_scaled_font_t *local_scaled_font = NULL; + + status = _cairo_composite_rectangles_init_for_glyphs (&extents, + &surface->win32.base, + op, source, + scaled_font, + glyphs, num_glyphs, + clip, + &overlap); + if (unlikely (status)) + return status; + + status = _cairo_surface_clipper_set_clip (&surface->clipper, clip); + if (unlikely (status)) + goto cleanup_composite; + + if (op == CAIRO_OPERATOR_CLEAR) { + _cairo_win32_printing_surface_init_clear_color (surface, &clear); + source = (cairo_pattern_t*) &clear; + op = CAIRO_OPERATOR_SOURCE; + } + + if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) { + /* When printing bitmap fonts to a printer DC, Windows may + * substitute an outline font for bitmap font. As the win32 + * font backend always uses a screen DC when obtaining the + * font metrics the metrics of the substituted font will not + * match the metrics that the win32 font backend returns. + * + * If we are printing a bitmap font, use fallback images to + * ensure the font is not substituted. + */ +#if CAIRO_HAS_WIN32_FONT + if (cairo_scaled_font_get_type (scaled_font) == CAIRO_FONT_TYPE_WIN32) { + if (_cairo_win32_scaled_font_is_bitmap (scaled_font)) { + status = CAIRO_INT_STATUS_UNSUPPORTED; + goto cleanup_composite; + } else { + status = _cairo_win32_printing_surface_analyze_operation (surface, op, source, &extents.bounded); + goto cleanup_composite; + } + } +#endif + +#if CAIRO_HAS_DWRITE_FONT + if (cairo_scaled_font_get_type (scaled_font) == CAIRO_FONT_TYPE_DWRITE) { + status = _cairo_win32_printing_surface_analyze_operation (surface, op, source, &extents.bounded); + goto cleanup_composite; + } +#endif + + /* For non win32 fonts we need to check that each glyph has a + * path available. If a path is not available, + * _cairo_scaled_glyph_lookup() will return + * CAIRO_INT_STATUS_UNSUPPORTED and a fallback image will be + * used. + */ + _cairo_scaled_font_freeze_cache (scaled_font); + for (i = 0; i < num_glyphs; i++) { + status = _cairo_scaled_glyph_lookup (scaled_font, + glyphs[i].index, + CAIRO_SCALED_GLYPH_INFO_PATH, + NULL, /* foreground color */ + &scaled_glyph); + if (status) + break; + } + _cairo_scaled_font_thaw_cache (scaled_font); + if (unlikely (status)) + goto cleanup_composite; + + status = _cairo_win32_printing_surface_analyze_operation (surface, op, source, &extents.bounded); + goto cleanup_composite; + } + + if (source->type == CAIRO_PATTERN_TYPE_SOLID) { + cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) source; + COLORREF color; + + color = _cairo_win32_printing_surface_flatten_transparency (surface, + &solid->color); + opaque = cairo_pattern_create_rgb (GetRValue (color) / 255.0, + GetGValue (color) / 255.0, + GetBValue (color) / 255.0); + if (unlikely (opaque->status)) { + status = opaque->status; + goto cleanup_composite; + } + source = opaque; + } + +#if CAIRO_HAS_DWRITE_FONT + /* For a printer, the dwrite path is not desirable as it goes through the + * bitmap-blitting GDI interop route. Better to create a win32 (GDI) font + * so that ExtTextOut can be used, giving the printer driver the chance + * to do the right thing with the text. + */ + if (cairo_scaled_font_get_type (scaled_font) == CAIRO_FONT_TYPE_DWRITE) { + status = _cairo_dwrite_scaled_font_create_win32_scaled_font (scaled_font, &local_scaled_font); + if (status == CAIRO_STATUS_SUCCESS) { + scaled_font = local_scaled_font; + } else { + /* Reset status; we'll fall back to drawing glyphs as paths */ + status = CAIRO_STATUS_SUCCESS; + } + } +#endif + +#if CAIRO_HAS_WIN32_FONT + if (cairo_scaled_font_get_type (scaled_font) == CAIRO_FONT_TYPE_WIN32 && + source->type == CAIRO_PATTERN_TYPE_SOLID) + { + status = _cairo_win32_printing_surface_emit_win32_glyphs (surface, + op, + source, + glyphs, + num_glyphs, + scaled_font, + clip); + goto cleanup_composite; + } +#endif + + SaveDC (surface->win32.dc); + old_ctm = surface->ctm; + old_has_ctm = surface->has_ctm; + surface->has_ctm = TRUE; + surface->path_empty = TRUE; + _cairo_scaled_font_freeze_cache (scaled_font); + BeginPath (surface->win32.dc); + for (i = 0; i < num_glyphs; i++) { + status = _cairo_scaled_glyph_lookup (scaled_font, + glyphs[i].index, + CAIRO_SCALED_GLYPH_INFO_PATH, + NULL, /* foreground color */ + &scaled_glyph); + if (status) + break; + surface->ctm = old_ctm; + cairo_matrix_translate (&surface->ctm, glyphs[i].x, glyphs[i].y); + status = _cairo_win32_printing_surface_emit_path (surface, scaled_glyph->path); + } + EndPath (surface->win32.dc); + _cairo_scaled_font_thaw_cache (scaled_font); + surface->ctm = old_ctm; + surface->has_ctm = old_has_ctm; + if (status == CAIRO_STATUS_SUCCESS && surface->path_empty == FALSE) { + if (source->type == CAIRO_PATTERN_TYPE_SOLID) { + status = _cairo_win32_printing_surface_select_solid_brush (surface, source); + if (unlikely (status)) + goto cleanup_composite; + + SetPolyFillMode (surface->win32.dc, WINDING); + FillPath (surface->win32.dc); + _cairo_win32_printing_surface_done_solid_brush (surface); + } else { + SelectClipPath (surface->win32.dc, RGN_AND); + status = _cairo_win32_printing_surface_paint_pattern (surface, source, &extents.bounded); + } + } + RestoreDC (surface->win32.dc, -1); + + if (opaque) + cairo_pattern_destroy (opaque); + +cleanup_composite: + _cairo_composite_rectangles_fini (&extents); + + if (local_scaled_font) + cairo_scaled_font_destroy (local_scaled_font); + + return status; +} + +static const char ** +_cairo_win32_printing_surface_get_supported_mime_types (void *abstract_surface) +{ + return _cairo_win32_printing_supported_mime_types; +} + +static cairo_status_t +_cairo_win32_printing_surface_finish (void *abstract_surface) +{ + cairo_win32_printing_surface_t *surface = abstract_surface; + + if (surface->font_subsets != NULL) + _cairo_scaled_font_subsets_destroy (surface->font_subsets); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_surface_t * +_cairo_win32_printing_surface_create_similar (void *abstract_surface, + cairo_content_t content, + int width, + int height) +{ + cairo_rectangle_t extents; + + extents.x = extents.y = 0; + extents.width = width; + extents.height = height; + return cairo_recording_surface_create (content, &extents); +} + +static cairo_int_status_t +_cairo_win32_printing_surface_start_page (void *abstract_surface) +{ + cairo_win32_printing_surface_t *surface = abstract_surface; + XFORM xform; + double x_res, y_res; + cairo_matrix_t inverse_ctm; + cairo_status_t status; + RECT rect; + + /* Since the page size may be changed after _show_page() and before the + * next drawing command, the extents are set in _start_page() and invalidated + * in _show_page(). The paginated surface will obtain the extents immediately + * after calling _show_page() and before any drawing commands. At this point + * the next page will not have been setup on the DC so we return invalid + * extents and the paginated surface will create an unbounded recording surface. + * Prior to replay of the record surface, the paginated surface will call + * _start_page and we setup the correct extents. + * + * Note that we always set the extents x,y to 0 so prevent replay from translating + * the coordinates of objects. Windows will clip anything outside of the page clip + * area. + */ + GetClipBox(surface->win32.dc, &rect); + surface->win32.extents.x = 0; + surface->win32.extents.y = 0; + surface->win32.extents.width = rect.right; + surface->win32.extents.height = rect.bottom; + surface->extents_valid = TRUE; + + SaveDC (surface->win32.dc); /* Save application context first, before doing MWT */ + + /* As the logical coordinates used by GDI functions (eg LineTo) + * are integers we need to do some additional work to prevent + * rounding errors. For example the obvious way to paint a recording + * pattern is to: + * + * SaveDC() + * transform the device context DC by the pattern to device matrix + * replay the recording surface + * RestoreDC() + * + * The problem here is that if the pattern to device matrix is + * [100 0 0 100 0 0], coordinates in the recording pattern such as + * (1.56, 2.23) which correspond to (156, 223) in device space + * will be rounded to (100, 200) due to (1.56, 2.23) being + * truncated to integers. + * + * This is solved by saving the current GDI CTM in surface->ctm, + * switch the GDI CTM to identity, and transforming all + * coordinates by surface->ctm before passing them to GDI. When + * painting a recording pattern, surface->ctm is transformed by the + * pattern to device matrix. + * + * For printing device contexts where 1 unit is 1 dpi, switching + * the GDI CTM to identity maximises the possible resolution of + * coordinates. + * + * If the device context is an EMF file, using an identity + * transform often provides insufficient resolution. The workaround + * is to set the GDI CTM to a scale < 1 eg [1.0/16 0 0 1/0/16 0 0] + * and scale the cairo CTM by [16 0 0 16 0 0]. The + * SetWorldTransform function call to scale the GDI CTM by 1.0/16 + * will be recorded in the EMF followed by all the graphics + * functions by their coordinateds multiplied by 16. + * + * To support allowing the user to set a GDI CTM with scale < 1, + * we avoid switching to an identity CTM if the CTM xx and yy is < 1. + */ + SetGraphicsMode (surface->win32.dc, GM_ADVANCED); + GetWorldTransform(surface->win32.dc, &xform); + if (xform.eM11 < 1 && xform.eM22 < 1) { + cairo_matrix_init_identity (&surface->ctm); + surface->gdi_ctm.xx = xform.eM11; + surface->gdi_ctm.xy = xform.eM21; + surface->gdi_ctm.yx = xform.eM12; + surface->gdi_ctm.yy = xform.eM22; + surface->gdi_ctm.x0 = xform.eDx; + surface->gdi_ctm.y0 = xform.eDy; + } else { + surface->ctm.xx = xform.eM11; + surface->ctm.xy = xform.eM21; + surface->ctm.yx = xform.eM12; + surface->ctm.yy = xform.eM22; + surface->ctm.x0 = xform.eDx; + surface->ctm.y0 = xform.eDy; + cairo_matrix_init_identity (&surface->gdi_ctm); + if (!ModifyWorldTransform (surface->win32.dc, NULL, MWT_IDENTITY)) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "ModifyWorldTransform"); + return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); + } + } + + surface->has_ctm = !_cairo_matrix_is_identity (&surface->ctm); + surface->has_gdi_ctm = !_cairo_matrix_is_identity (&surface->gdi_ctm); + inverse_ctm = surface->ctm; + status = cairo_matrix_invert (&inverse_ctm); + if (status) + return status; + + x_res = GetDeviceCaps (surface->win32.dc, LOGPIXELSX); + y_res = GetDeviceCaps (surface->win32.dc, LOGPIXELSY); + cairo_matrix_transform_distance (&inverse_ctm, &x_res, &y_res); + _cairo_surface_set_resolution (&surface->win32.base, x_res, y_res); + + SaveDC (surface->win32.dc); /* Then save Cairo's known-good clip state, so the clip path can be reset */ + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_win32_printing_surface_set_paginated_mode (void *abstract_surface, + cairo_paginated_mode_t paginated_mode) +{ + cairo_win32_printing_surface_t *surface = abstract_surface; + + surface->paginated_mode = paginated_mode; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_bool_t +_cairo_win32_printing_surface_supports_fine_grained_fallbacks (void *abstract_surface) +{ + return TRUE; +} + +/** + * cairo_win32_printing_surface_create: + * @hdc: the DC to create a surface for + * + * Creates a cairo surface that targets the given DC. The DC will be + * queried for its initial clip extents, and this will be used as the + * size of the cairo surface. The DC should be a printing DC; + * antialiasing will be ignored, and GDI will be used as much as + * possible to draw to the surface. + * + * The returned surface will be wrapped using the paginated surface to + * provide correct complex rendering behaviour; cairo_surface_show_page() and + * associated methods must be used for correct output. + * + * The following mime types are supported on source patterns: + * %CAIRO_MIME_TYPE_JPEG, %CAIRO_MIME_TYPE_PNG. + * + * Return value: the newly created surface + * + * Since: 1.6 + **/ +cairo_surface_t * +cairo_win32_printing_surface_create (HDC hdc) +{ + cairo_win32_printing_surface_t *surface; + cairo_surface_t *paginated; + + surface = _cairo_calloc (sizeof (cairo_win32_printing_surface_t)); + if (surface == NULL) + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + +#if 0 + if (_cairo_win32_save_initial_clip (hdc, surface) != CAIRO_STATUS_SUCCESS) { + free (surface); + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + } +#endif + + _cairo_surface_clipper_init (&surface->clipper, + _cairo_win32_printing_surface_clipper_intersect_clip_path); + + surface->win32.format = CAIRO_FORMAT_RGB24; + surface->content = CAIRO_CONTENT_COLOR_ALPHA; + + surface->win32.dc = hdc; + surface->extents_valid = FALSE; + + surface->brush = NULL; + surface->old_brush = NULL; + surface->font_subsets = _cairo_scaled_font_subsets_create_scaled (); + if (surface->font_subsets == NULL) { + free (surface); + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + } + + surface->win32.flags = _cairo_win32_flags_for_dc (surface->win32.dc, CAIRO_FORMAT_RGB24); + surface->win32.flags |= CAIRO_WIN32_SURFACE_FOR_PRINTING; + + _cairo_win32_printing_surface_init_ps_mode (surface); + _cairo_win32_printing_surface_init_image_support (surface); + _cairo_win32_printing_surface_init_language_pack (surface); + _cairo_surface_init (&surface->win32.base, + &cairo_win32_printing_surface_backend, + NULL, /* device */ + CAIRO_CONTENT_COLOR_ALPHA, + TRUE); /* is_vector */ + + paginated = _cairo_paginated_surface_create (&surface->win32.base, + CAIRO_CONTENT_COLOR_ALPHA, + &cairo_win32_surface_paginated_backend); + + /* paginated keeps the only reference to surface now, drop ours */ + cairo_surface_destroy (&surface->win32.base); + + return paginated; +} + +cairo_bool_t +_cairo_surface_is_win32_printing (const cairo_surface_t *surface) +{ + return surface->backend && surface->backend->type == CAIRO_SURFACE_TYPE_WIN32_PRINTING; +} + +static const cairo_surface_backend_t cairo_win32_printing_surface_backend = { + CAIRO_SURFACE_TYPE_WIN32_PRINTING, + _cairo_win32_printing_surface_finish, + + _cairo_default_context_create, + + _cairo_win32_printing_surface_create_similar, + NULL, /* create similar image */ + NULL, /* map to image */ + NULL, /* unmap image */ + + _cairo_surface_default_source, + NULL, /* acquire_source_image */ + NULL, /* release_source_image */ + NULL, /* snapshot */ + + NULL, /* copy_page */ + _cairo_win32_printing_surface_show_page, + + _cairo_win32_printing_surface_get_extents, + _cairo_win32_printing_surface_get_font_options, + + NULL, /* flush */ + NULL, /* mark_dirty_rectangle */ + + _cairo_win32_printing_surface_paint, + NULL, /* mask */ + _cairo_win32_printing_surface_stroke, + _cairo_win32_printing_surface_fill, + NULL, /* fill/stroke */ + _cairo_win32_printing_surface_show_glyphs, + NULL, /* has_show_text_glyphs */ + NULL, /* show_text_glyphs */ + _cairo_win32_printing_surface_get_supported_mime_types, +}; + +static const cairo_paginated_surface_backend_t cairo_win32_surface_paginated_backend = { + _cairo_win32_printing_surface_start_page, + _cairo_win32_printing_surface_set_paginated_mode, + NULL, /* set_bounding_box */ + NULL, /* _cairo_win32_printing_surface_has_fallback_images, */ + _cairo_win32_printing_surface_supports_fine_grained_fallbacks, +}; diff --git a/local/recipes/libs/cairo/source/src/win32/cairo-win32-private.h b/local/recipes/libs/cairo/source/src/win32/cairo-win32-private.h new file mode 100644 index 0000000000..a9eda8fdbe --- /dev/null +++ b/local/recipes/libs/cairo/source/src/win32/cairo-win32-private.h @@ -0,0 +1,258 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Owen Taylor + */ + +#ifndef CAIRO_WIN32_PRIVATE_H +#define CAIRO_WIN32_PRIVATE_H + +#include "cairo-win32.h" + +#include "cairoint.h" + +#include "cairo-device-private.h" +#include "cairo-surface-clipper-private.h" +#include "cairo-surface-private.h" + +#define WIN32_FONT_LOGICAL_SCALE 32 + +CAIRO_BEGIN_DECLS + +/* Surface DC flag values */ +enum { + /* If this is a surface created for printing or not */ + CAIRO_WIN32_SURFACE_FOR_PRINTING = (1<<0), + + /* Whether the DC is a display DC or not */ + CAIRO_WIN32_SURFACE_IS_DISPLAY = (1<<1), + + /* Whether we can use BitBlt with this surface */ + CAIRO_WIN32_SURFACE_CAN_BITBLT = (1<<2), + + /* Whether we can use AlphaBlend with this surface */ + CAIRO_WIN32_SURFACE_CAN_ALPHABLEND = (1<<3), + + /* Whether we can use StretchBlt with this surface */ + CAIRO_WIN32_SURFACE_CAN_STRETCHBLT = (1<<4), + + /* Whether we can use StretchDIBits with this surface */ + CAIRO_WIN32_SURFACE_CAN_STRETCHDIB = (1<<5), + + /* Whether we can use GradientFill rectangles with this surface */ + CAIRO_WIN32_SURFACE_CAN_RECT_GRADIENT = (1<<6), + + /* Whether we can use the CHECKJPEGFORMAT escape function */ + CAIRO_WIN32_SURFACE_CAN_CHECK_JPEG = (1<<7), + + /* Whether we can use the CHECKPNGFORMAT escape function */ + CAIRO_WIN32_SURFACE_CAN_CHECK_PNG = (1<<8), + + /* Whether we can use gdi drawing with solid rgb brush with this surface */ + CAIRO_WIN32_SURFACE_CAN_RGB_BRUSH = (1<<9), +}; + +typedef struct _cairo_win32_surface { + cairo_surface_t base; + + cairo_format_t format; + HDC dc; + + /* Surface DC flags */ + unsigned flags; + + /* We use the x and y parts of extents for situations where + * we're not supposed to draw to the entire surface. + * For example, during a paint event a program will get + * a DC that has been clipped to the dirty region. + * A cairo surface constructed for that DC will have extents + * that match bounds of the clipped region. + */ + cairo_rectangle_int_t extents; + + /* Offset added to extents, used when the extents start with a negative + * offset, which can occur on Windows for, and only for, desktop DC. This + * occurs when you have multiple monitors, and at least one monitor + * extends to the left, or above, the primaty monitor. The primary + * monitor on Windows always starts with offset (0,0), and any other points + * to the left, or above, have negative offsets. So the 'desktop DC' is + * in fact a 'virtual desktop' which can start with extents in the negative + * range. + * + * Why use new variables, and not the device transform? Simply because since + * the device transform functions are exposed, a lot of 3rd party libraries + * simply overwrite those, disregarding the prior content, instead of actually + * adding the offset. GTK for example simply resets the device transform of the + * desktop cairo surface to zero. So make some private member variables for + * this, which will not be fiddled with externally. + */ + int x_ofs, y_ofs; +} cairo_win32_surface_t; +#define to_win32_surface(S) ((cairo_win32_surface_t *)(S)) + +typedef struct _cairo_win32_display_surface { + cairo_win32_surface_t win32; + + /* We create off-screen surfaces as DIBs or DDBs, based on what we created + * originally */ + HBITMAP bitmap; + cairo_bool_t is_dib; + + /* Used to save the initial 1x1 monochrome bitmap for the DC to + * select back into the DC before deleting the DC and our + * bitmap. For Windows XP, this doesn't seem to be necessary + * ... we can just delete the DC and that automatically unselects + * our bitmap. But it's standard practice so apparently is needed + * on some versions of Windows. + */ + HBITMAP saved_dc_bitmap; + cairo_surface_t *image; + cairo_surface_t *fallback; + + HRGN initial_clip_rgn; + cairo_bool_t had_simple_clip; +} cairo_win32_display_surface_t; +#define to_win32_display_surface(S) ((cairo_win32_display_surface_t *)(S)) + +typedef struct _cairo_win32_printing_surface { + cairo_win32_surface_t win32; + + cairo_surface_clipper_t clipper; + + cairo_paginated_mode_t paginated_mode; + cairo_content_t content; + cairo_bool_t path_empty; + cairo_bool_t has_ctm; + cairo_matrix_t ctm; + cairo_bool_t has_gdi_ctm; + cairo_matrix_t gdi_ctm; + cairo_bool_t extents_valid; + HBRUSH brush, old_brush; + cairo_scaled_font_subsets_t *font_subsets; +} cairo_win32_printing_surface_t; +#define to_win32_printing_surface(S) ((cairo_win32_printing_surface_t *)(S)) + +typedef struct _cairo_win32_device { + cairo_device_t base; + + const cairo_compositor_t *compositor; +} cairo_win32_device_t; +#define to_win32_device(D) ((cairo_win32_device_t *)(D)) +#define to_win32_device_from_surface(S) to_win32_device(((cairo_surface_t *)(S))->device) + +cairo_private cairo_device_t * +_cairo_win32_device_get (void); + +const cairo_compositor_t * +_cairo_win32_gdi_compositor_get (void); + +cairo_status_t +_cairo_win32_print_api_error (const char *context, const char *api); + +cairo_bool_t +_cairo_surface_is_win32 (const cairo_surface_t *surface); + +cairo_bool_t +_cairo_surface_is_win32_printing (const cairo_surface_t *surface); + +cairo_private void +_cairo_win32_display_surface_discard_fallback (cairo_win32_display_surface_t *surface); + +cairo_bool_t +_cairo_win32_surface_get_extents (void *abstract_surface, + cairo_rectangle_int_t *rectangle); + +uint32_t +_cairo_win32_flags_for_dc (HDC dc, cairo_format_t format); + +cairo_int_status_t +_cairo_win32_surface_emit_glyphs (cairo_win32_surface_t *dst, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + cairo_bool_t glyph_indexing); + +static inline void +_cairo_matrix_to_win32_xform (const cairo_matrix_t *m, + XFORM *xform) +{ + xform->eM11 = (FLOAT) m->xx; + xform->eM21 = (FLOAT) m->xy; + xform->eM12 = (FLOAT) m->yx; + xform->eM22 = (FLOAT) m->yy; + xform->eDx = (FLOAT) m->x0; + xform->eDy = (FLOAT) m->y0; +} + +cairo_status_t +_cairo_win32_display_surface_set_clip (cairo_win32_display_surface_t *surface, + cairo_clip_t *clip); + +void +_cairo_win32_display_surface_unset_clip (cairo_win32_display_surface_t *surface); + +void +_cairo_win32_debug_dump_hrgn (HRGN rgn, char *header); + +cairo_bool_t +_cairo_win32_scaled_font_is_type1 (cairo_scaled_font_t *scaled_font); + +cairo_bool_t +_cairo_win32_scaled_font_is_bitmap (cairo_scaled_font_t *scaled_font); + +cairo_public BYTE +cairo_win32_get_system_text_quality (void); + +HMODULE +_cairo_win32_load_library_from_system32 (const wchar_t *name); + +#if CAIRO_HAS_DWRITE_FONT + +cairo_int_status_t +_cairo_dwrite_show_glyphs_on_surface (void *surface, + cairo_operator_t op, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + cairo_clip_t *clip); + +cairo_int_status_t +_cairo_dwrite_scaled_font_create_win32_scaled_font (cairo_scaled_font_t *scaled_font, + cairo_scaled_font_t **new_font); + +#endif /* CAIRO_HAS_DWRITE_FONT */ + +CAIRO_END_DECLS + +#endif /* CAIRO_WIN32_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/src/win32/cairo-win32-refptr.hpp b/local/recipes/libs/cairo/source/src/win32/cairo-win32-refptr.hpp new file mode 100644 index 0000000000..e361e4cf7f --- /dev/null +++ b/local/recipes/libs/cairo/source/src/win32/cairo-win32-refptr.hpp @@ -0,0 +1,178 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* Cairo - a vector graphics library with display and print output + * + * Copyright 2010 Mozilla Foundation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is the Mozilla Foundation + * + * Contributor(s): + * Bas Schouten + */ +#ifndef CAIRO_WIN32_REFPTR_H +#define CAIRO_WIN32_REFPTR_H + +template class TemporaryRef; + +/* + * RefPtr points to a refcounted thing that has AddRef and Release + * methods to increase/decrease the refcount, respectively. After a + * RefPtr is assigned a T*, the T* can be used through the RefPtr + * as if it were a T*. + * + * A RefPtr can forget its underlying T*, which results in the T* + * being wrapped in a temporary object until the T* is either + * re-adopted from or released by the temporary. + */ +template +class RefPtr +{ + // To allow them to use unref() + friend class TemporaryRef; + + struct dontRef {}; + +public: + RefPtr() : ptr(0) { } + RefPtr(const RefPtr& o) : ptr(ref(o.ptr)) {} + RefPtr(const TemporaryRef& o) : ptr(o.drop()) {} + RefPtr(T* t) : ptr(ref(t)) {} + + template + RefPtr(const RefPtr& o) : ptr(ref(o.get())) {} + + ~RefPtr() { unref(ptr); } + + RefPtr& operator=(const RefPtr& o) { + assign(ref(o.ptr)); + return *this; + } + RefPtr& operator=(const TemporaryRef& o) { + assign(o.drop()); + return *this; + } + RefPtr& operator=(T* t) { + assign(ref(t)); + return *this; + } + + template + RefPtr& operator=(const RefPtr& o) { + assign(ref(o.get())); + return *this; + } + + TemporaryRef forget() { + T* tmp = ptr; + ptr = 0; + return TemporaryRef(tmp, dontRef()); + } + + T* get() const { return ptr; } + operator T*() const { return ptr; } + T* operator->() const { return ptr; } + T& operator*() const { return *ptr; } + template + operator TemporaryRef() { return TemporaryRef(ptr); } + + /** + * WARNING for ease of use, passing a reference will release/clear out ptr! + * We null out the ptr before returning its address so people passing byref + * as input will most likely get functions returning errors rather than accessing + * freed memory. Further more accessing it after this point if it hasn't + * been set will produce a null pointer dereference. + */ + T** operator&() + { + if (ptr) { + ptr->Release(); + ptr = NULL; + } + return &ptr; + } + +private: + void assign(T* t) { + unref(ptr); + ptr = t; + } + + T* ptr; + + static inline T* ref(T* t) { + if (t) { + t->AddRef(); + } + return t; + } + + static inline void unref(T* t) { + if (t) { + t->Release(); + } + } +}; + +/* + * TemporaryRef represents an object that holds a temporary + * reference to a T. TemporaryRef objects can't be manually ref'd or + * unref'd (being temporaries, not lvalues), so can only relinquish + * references to other objects, or unref on destruction. + */ +template +class TemporaryRef +{ + // To allow it to construct TemporaryRef from a bare T* + friend class RefPtr; + + typedef typename RefPtr::dontRef dontRef; + +public: + TemporaryRef(T* t) : ptr(RefPtr::ref(t)) {} + TemporaryRef(const TemporaryRef& o) : ptr(o.drop()) {} + + template + TemporaryRef(const TemporaryRef& o) : ptr(o.drop()) {} + + ~TemporaryRef() { RefPtr::unref(ptr); } + + T* drop() const { + T* tmp = ptr; + ptr = 0; + return tmp; + } + +private: + TemporaryRef(T* t, const dontRef&) : ptr(t) {} + + mutable T* ptr; + + TemporaryRef(); + TemporaryRef& operator=(const TemporaryRef&); +}; + +#endif diff --git a/local/recipes/libs/cairo/source/src/win32/cairo-win32-surface.c b/local/recipes/libs/cairo/source/src/win32/cairo-win32-surface.c new file mode 100644 index 0000000000..e1ac515580 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/win32/cairo-win32-surface.c @@ -0,0 +1,301 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2012 Intel Corporation + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Owen Taylor + * Stuart Parmenter + * Vladimir Vukicevic + */ + +#include "cairoint.h" + +#include "cairo-backend-private.h" +#include "cairo-default-context-private.h" +#include "cairo-error-private.h" +#include "cairo-image-surface-private.h" +#include "cairo-paginated-private.h" +#include "cairo-pattern-private.h" +#include "cairo-win32-private.h" +#include "cairo-scaled-font-subsets-private.h" +#include "cairo-surface-fallback-private.h" +#include "cairo-surface-backend-private.h" + +#include +#include + +/** + * SECTION:cairo-win32 + * @Title: Win32 Surfaces + * @Short_Description: Microsoft Windows surface support + * @See_Also: #cairo_surface_t + * + * The Microsoft Windows surface is used to render cairo graphics to + * Microsoft Windows windows, bitmaps, and printing device contexts. + * + * The surface returned by cairo_win32_printing_surface_create() is of surface + * type %CAIRO_SURFACE_TYPE_WIN32_PRINTING and is a multi-page vector surface + * type. + * + * The surface returned by the other win32 constructors is of surface type + * %CAIRO_SURFACE_TYPE_WIN32 and is a raster surface type. + **/ + +/** + * CAIRO_HAS_WIN32_SURFACE: + * + * Defined if the Microsoft Windows surface backend is available. + * This macro can be used to conditionally compile backend-specific code. + * + * Since: 1.0 + **/ + +cairo_bool_t +_cairo_win32_surface_get_extents (void *abstract_surface, + cairo_rectangle_int_t *rectangle) +{ + cairo_win32_surface_t *surface = abstract_surface; + + *rectangle = surface->extents; + return TRUE; +} + +/** + * cairo_win32_surface_get_dc: + * @surface: a #cairo_surface_t + * + * Returns the HDC associated with this surface, or %NULL if none. + * Also returns %NULL if the surface is not a win32 surface. + * + * A call to cairo_surface_flush() is required before using the HDC to + * ensure that all pending drawing operations are finished and to + * restore any temporary modification cairo has made to its state. A + * call to cairo_surface_mark_dirty() is required after the state or + * the content of the HDC has been modified. + * + * Return value: HDC or %NULL if no HDC available. + * + * Since: 1.2 + **/ +HDC +cairo_win32_surface_get_dc (cairo_surface_t *surface) +{ + if (surface->backend == NULL) + return NULL; + + if (surface->backend->type == CAIRO_SURFACE_TYPE_WIN32) + return to_win32_surface(surface)->dc; + + if (_cairo_surface_is_paginated (surface)) { + cairo_surface_t *target = _cairo_paginated_surface_get_target (surface); + if (target->backend->type == CAIRO_SURFACE_TYPE_WIN32_PRINTING) + return to_win32_surface(target)->dc; + } + + return NULL; +} + +/** + * _cairo_surface_is_win32: + * @surface: a #cairo_surface_t + * + * Checks if a surface is an #cairo_win32_surface_t + * + * Return value: %TRUE if the surface is an win32 surface + **/ +cairo_bool_t +_cairo_surface_is_win32 (const cairo_surface_t *surface) +{ + /* _cairo_surface_nil sets a NULL backend so be safe */ + return surface->backend && surface->backend->type == CAIRO_SURFACE_TYPE_WIN32; +} + +/** + * cairo_win32_surface_get_image: + * @surface: a #cairo_surface_t + * + * Returns a #cairo_surface_t image surface that refers to the same bits + * as the DIB of the Win32 surface. If the passed-in win32 surface + * is not a DIB surface, %NULL is returned. + * + * Return value: a #cairo_surface_t (owned by the win32 #cairo_surface_t), + * or %NULL if the win32 surface is not a DIB. + * + * Since: 1.4 + **/ +cairo_surface_t * +cairo_win32_surface_get_image (cairo_surface_t *surface) +{ + + if (! _cairo_surface_is_win32 (surface)) { + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH)); + } + + GdiFlush(); + return to_win32_display_surface(surface)->image; +} + +#define STACK_GLYPH_SIZE 256 +cairo_int_status_t +_cairo_win32_surface_emit_glyphs (cairo_win32_surface_t *dst, + const cairo_pattern_t *source, + cairo_glyph_t *glyphs, + int num_glyphs, + cairo_scaled_font_t *scaled_font, + cairo_bool_t glyph_indexing) +{ +#if CAIRO_HAS_DWRITE_FONT + if (scaled_font->backend->type == CAIRO_FONT_TYPE_DWRITE) { + if (!glyph_indexing) return CAIRO_INT_STATUS_UNSUPPORTED; + + // FIXME: fake values for params that aren't currently passed in here + cairo_operator_t op = CAIRO_OPERATOR_SOURCE; + cairo_clip_t *clip = NULL; + return _cairo_dwrite_show_glyphs_on_surface (dst, op, source, glyphs, num_glyphs, scaled_font, clip /* , glyph_indexing */ ); + } +#endif +#if CAIRO_HAS_WIN32_FONT + WORD glyph_buf_stack[STACK_GLYPH_SIZE]; + WORD *glyph_buf = glyph_buf_stack; + int dxy_buf_stack[2 * STACK_GLYPH_SIZE]; + int *dxy_buf = dxy_buf_stack; + + BOOL win_result = 0; + int i, j; + + cairo_solid_pattern_t *solid_pattern; + COLORREF color; + + cairo_matrix_t device_to_logical; + + int start_x, start_y; + double user_x, user_y; + int logical_x, logical_y; + unsigned int glyph_index_option; + + /* We can only handle win32 fonts */ + assert (cairo_scaled_font_get_type (scaled_font) == CAIRO_FONT_TYPE_WIN32); + + /* We can only handle opaque solid color sources and destinations */ + assert (_cairo_pattern_is_opaque_solid(source)); + assert (dst->format == CAIRO_FORMAT_RGB24); + + solid_pattern = (cairo_solid_pattern_t *)source; + color = RGB(((int)solid_pattern->color.red_short) >> 8, + ((int)solid_pattern->color.green_short) >> 8, + ((int)solid_pattern->color.blue_short) >> 8); + + cairo_win32_scaled_font_get_device_to_logical(scaled_font, &device_to_logical); + + SaveDC(dst->dc); + + cairo_win32_scaled_font_select_font(scaled_font, dst->dc); + SetTextColor(dst->dc, color); + SetTextAlign(dst->dc, TA_BASELINE | TA_LEFT); + SetBkMode(dst->dc, TRANSPARENT); + + if (num_glyphs > STACK_GLYPH_SIZE) { + glyph_buf = (WORD *) _cairo_malloc_ab (num_glyphs, sizeof(WORD)); + dxy_buf = (int *) _cairo_malloc_abc (num_glyphs, sizeof(int), 2); + } + + /* It is vital that dx values for dxy_buf are calculated from the delta of + * _logical_ x coordinates (not user x coordinates) or else the sum of all + * previous dx values may start to diverge from the current glyph's x + * coordinate due to accumulated rounding error. As a result strings could + * be painted shorter or longer than expected. */ + + user_x = glyphs[0].x; + user_y = glyphs[0].y; + + cairo_matrix_transform_point(&device_to_logical, + &user_x, &user_y); + + logical_x = _cairo_lround (user_x); + logical_y = _cairo_lround (user_y); + + start_x = logical_x; + start_y = logical_y; + + for (i = 0, j = 0; i < num_glyphs; ++i, j = 2 * i) { + glyph_buf[i] = (WORD) glyphs[i].index; + if (i == num_glyphs - 1) { + dxy_buf[j] = 0; + dxy_buf[j+1] = 0; + } else { + double next_user_x = glyphs[i+1].x; + double next_user_y = glyphs[i+1].y; + int next_logical_x, next_logical_y; + + cairo_matrix_transform_point(&device_to_logical, + &next_user_x, &next_user_y); + + next_logical_x = _cairo_lround (next_user_x); + next_logical_y = _cairo_lround (next_user_y); + + dxy_buf[j] = _cairo_lround (next_logical_x - logical_x); + dxy_buf[j+1] = _cairo_lround (next_logical_y - logical_y); + + logical_x = next_logical_x; + logical_y = next_logical_y; + } + } + + if (glyph_indexing) + glyph_index_option = ETO_GLYPH_INDEX; + else + glyph_index_option = 0; + + win_result = ExtTextOutW(dst->dc, + start_x, + start_y, + glyph_index_option | ETO_PDY, + NULL, + glyph_buf, + num_glyphs, + dxy_buf); + if (!win_result) { + fprintf (stderr, "%s:%s\n", __FUNCTION__, "ExtTextOut"); + } + + RestoreDC(dst->dc, -1); + + if (glyph_buf != glyph_buf_stack) { + free(glyph_buf); + free(dxy_buf); + } + return (win_result) ? CAIRO_STATUS_SUCCESS : CAIRO_INT_STATUS_UNSUPPORTED; +#else + return CAIRO_INT_STATUS_UNSUPPORTED; +#endif +} +#undef STACK_GLYPH_SIZE diff --git a/local/recipes/libs/cairo/source/src/win32/cairo-win32-system.c b/local/recipes/libs/cairo/source/src/win32/cairo-win32-system.c new file mode 100644 index 0000000000..c5ef24e8d4 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/win32/cairo-win32-system.c @@ -0,0 +1,172 @@ +/* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ +/* Cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Owen Taylor + * Stuart Parmenter + * Vladimir Vukicevic + */ + +/* This file should include code that is system-specific, not + * feature-specific. For example, the DLL initialization/finalization + * code on Win32 or OS/2 must live here (not in cairo-whatever-surface.c). + * Same about possible ELF-specific code. + * + * And no other function should live here. + */ + +#include "cairoint.h" + +#include + +/** + * _cairo_win32_print_api_error: + * @context: context string to display along with the error + * @api: name of the failing api + * + * Helper function to dump out a human readable form of the + * current error code. + * + * Return value: A cairo status code for the error code + **/ +cairo_status_t +_cairo_win32_print_api_error (const char *context, const char *api) +{ + const DWORD lang_id = MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT); + const DWORD flags = FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_IGNORE_INSERTS | + FORMAT_MESSAGE_FROM_SYSTEM; + const DWORD last_error = GetLastError (); + void *lpMsgBuf = NULL; + + if (!FormatMessageW (flags, NULL, last_error, lang_id, (LPWSTR) &lpMsgBuf, 0, NULL)) { + fprintf (stderr, "%s: %s failed with error code %lu\n", context, api, last_error); + } + else { + fprintf (stderr, "%s: %s failed - %S\n", context, api, (wchar_t *)lpMsgBuf); + LocalFree (lpMsgBuf); + } + + return _cairo_error (CAIRO_STATUS_WIN32_GDI_ERROR); +} + +/** + * _cairo_win32_load_library_from_system32: + * @name: name of the module to load from System32 + * + * Helper function to load system modules in the System32 + * folder. + * + * Return value: An module HANDLE, NULL on error. + **/ +HMODULE +_cairo_win32_load_library_from_system32 (const wchar_t *name) +{ + HMODULE module_handle; + + module_handle = LoadLibraryExW (name, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32); + if (module_handle == NULL) { + DWORD code = GetLastError(); + if (code == ERROR_INVALID_PARAMETER) { + /* Support for flag LOAD_LIBRARY_SEARCH_SYSTEM32 was backported + * to Windows Vista / 7 with Update KB2533623. If the flag is + * not supported, simply use LoadLibrary */ + return LoadLibraryW (name); + } + } + + return module_handle; +} + +#if CAIRO_MUTEX_IMPL_WIN32 + +static void NTAPI +cairo_win32_tls_callback (PVOID hinstance, DWORD dwReason, PVOID lpvReserved) +{ + switch (dwReason) { + case DLL_PROCESS_ATTACH: + CAIRO_MUTEX_INITIALIZE (); + break; + + case DLL_PROCESS_DETACH: + if (lpvReserved == NULL) { + CAIRO_MUTEX_FINALIZE (); + } + break; + } +} + +#ifdef _MSC_VER + +#ifdef _M_IX86 +# define SYMBOL_PREFIX "_" +#else +# define SYMBOL_PREFIX "" +#endif + +#ifdef __cplusplus +# define EXTERN_C_BEGIN extern "C" { +# define EXTERN_C_END } +# define EXTERN_CONST extern const +#else +# define EXTERN_C_BEGIN +# define EXTERN_C_END +# define EXTERN_CONST const +#endif + +#define DEFINE_TLS_CALLBACK(func) \ +__pragma (section (".CRT$XLD", long, read)) \ + \ +static void NTAPI func (PVOID, DWORD, PVOID); \ + \ +EXTERN_C_BEGIN \ +__declspec (allocate (".CRT$XLD")) \ +EXTERN_CONST PIMAGE_TLS_CALLBACK _ptr_##func = func; \ +EXTERN_C_END \ + \ +__pragma (comment (linker, "/INCLUDE:" SYMBOL_PREFIX "_tls_used")) \ +__pragma (comment (linker, "/INCLUDE:" SYMBOL_PREFIX "_ptr_" #func)) + +#else /* _MSC_VER */ + +#define DEFINE_TLS_CALLBACK(func) \ +static void NTAPI func (PVOID, DWORD, PVOID); \ + \ +__attribute__ ((used, section (".CRT$XLD"))) \ +static const PIMAGE_TLS_CALLBACK _ptr_##func = func; + + +#endif /* !_MSC_VER */ + +DEFINE_TLS_CALLBACK (cairo_win32_tls_callback); + +#endif /* CAIRO_MUTEX_IMPL_WIN32 */ diff --git a/local/recipes/libs/cairo/source/src/win32/d2d1-extra.h b/local/recipes/libs/cairo/source/src/win32/d2d1-extra.h new file mode 100644 index 0000000000..16099d8346 --- /dev/null +++ b/local/recipes/libs/cairo/source/src/win32/d2d1-extra.h @@ -0,0 +1,111 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ + +/* Mingw-w64 does not have d2d1_2.h and d2d2_3.h. + * + * + * We only need the definitions of two functions: + * ID2D1DeviceContext4::DrawColorBitmapGlyphRun() + * ID2D1DeviceContext4::DrawSvgGlyphRun() + * + * But we need to include all the prior functions in the same struct, + * and parent structs, so that the functions are in the correct position + * in the vtable. The parameters of the unused functions are not + * required as we only need a function in the struct to create a + * function pointer in the vtable. + */ + +#ifndef D2D1_EXTRA_H +#define D2D1_EXTRA_H + +#include + +interface ID2D1DeviceContext1; +interface ID2D1DeviceContext2; +interface ID2D1DeviceContext3; +interface ID2D1DeviceContext4; +interface ID2D1SvgGlyphStyle; + +enum D2D1_COLOR_BITMAP_GLYPH_SNAP_OPTION { + D2D1_COLOR_BITMAP_GLYPH_SNAP_OPTION_DEFAULT, + D2D1_COLOR_BITMAP_GLYPH_SNAP_OPTION_DISABLE, + D2D1_COLOR_BITMAP_GLYPH_SNAP_OPTION_FORCE_DWORD +}; + +DEFINE_GUID(IID_ID2D1DeviceContext1, 0xd37f57e4, 0x6908, 0x459f, 0xa1, 0x99, 0xe7, 0x2f, 0x24, 0xf7, 0x99, 0x87); +MIDL_INTERFACE("d37f57e4-6908-459f-a199-e72f24f79987") +ID2D1DeviceContext1 : public ID2D1DeviceContext +{ + virtual void STDMETHODCALLTYPE CreateFilledGeometryRealization() = 0; + virtual void STDMETHODCALLTYPE CreateStrokedGeometryRealization() = 0; + virtual void STDMETHODCALLTYPE DrawGeometryRealization() = 0; +}; +__CRT_UUID_DECL(ID2D1DeviceContext1, 0xd37f57e4, 0x6908, 0x459f, 0xa1, 0x99, 0xe7, 0x2f, 0x24, 0xf7, 0x99, 0x87) + +DEFINE_GUID(IID_ID2D1DeviceContext2, 0x394ea6a3, 0x0c34, 0x4321, 0x95, 0x0b, 0x6c, 0xa2, 0x0f, 0x0b, 0xe6, 0xc7); +MIDL_INTERFACE("394ea6a3-0c34-4321-950b-6ca20f0be6c7") +ID2D1DeviceContext2 : public ID2D1DeviceContext1 +{ + virtual void STDMETHODCALLTYPE CreateInk() = 0; + virtual void STDMETHODCALLTYPE CreateInkStyle() = 0; + virtual void STDMETHODCALLTYPE CreateGradientMesh() = 0; + virtual void STDMETHODCALLTYPE CreateImageSourceFromWic() = 0; + virtual void STDMETHODCALLTYPE CreateLookupTable3D() = 0; + virtual void STDMETHODCALLTYPE CreateImageSourceFromDxgi() = 0; + virtual void STDMETHODCALLTYPE GetGradientMeshWorldBounds() = 0; + virtual void STDMETHODCALLTYPE DrawInk() = 0; + virtual void STDMETHODCALLTYPE DrawGradientMesh() = 0; + virtual void STDMETHODCALLTYPE DrawGdiMetafile() = 0; + virtual void STDMETHODCALLTYPE CreateTransformedImageSource() = 0; +}; +__CRT_UUID_DECL(ID2D1DeviceContext2, 0x394ea6a3, 0x0c34, 0x4321, 0x95, 0x0b, 0x6c, 0xa2, 0x0f, 0x0b, 0xe6, 0xc7) + + +DEFINE_GUID(IID_ID2D1DeviceContext3, 0x235a7496, 0x8351, 0x414c, 0xbc, 0xd4, 0x66, 0x72, 0xab, 0x2d, 0x8e, 0x00); +MIDL_INTERFACE("235a7496-8351-414c-bcd4-6672ab2d8e00") +ID2D1DeviceContext3 : public ID2D1DeviceContext2 +{ + virtual void STDMETHODCALLTYPE CreateSpriteBatch() = 0; + virtual void STDMETHODCALLTYPE DrawSpriteBatch() = 0; +}; +__CRT_UUID_DECL(ID2D1DeviceContext3, 0x235a7496, 0x8351, 0x414c, 0xbc, 0xd4, 0x66, 0x72, 0xab, 0x2d, 0x8e, 0x00) + + +DEFINE_GUID(IID_ID2D1SvgGlyphStyle, 0xaf671749, 0xd241, 0x4db8, 0x8e, 0x41, 0xdc, 0xc2, 0xe5, 0xc1, 0xa4, 0x38); +MIDL_INTERFACE("af671749-d241-4db8-8e41-dcc2e5c1a438") +ID2D1SvgGlyphStyle : public ID2D1Resource +{ + virtual void STDMETHODCALLTYPE SetFill() = 0; + virtual void STDMETHODCALLTYPE GetFill() = 0; + virtual void STDMETHODCALLTYPE SetStroke() = 0; + virtual void STDMETHODCALLTYPE GetStrokeDashesCount() = 0; + virtual void STDMETHODCALLTYPE GetStroke() = 0; +}; +__CRT_UUID_DECL(ID2D1SvgGlyphStyle, 0xaf671749, 0xd241, 0x4db8, 0x8e, 0x41, 0xdc, 0xc2, 0xe5, 0xc1, 0xa4, 0x38) + + +DEFINE_GUID(IID_ID2D1DeviceContext4, 0x8c427831, 0x3d90, 0x4476, 0xb6, 0x47, 0xc4, 0xfa, 0xe3, 0x49, 0xe4, 0xdb); +MIDL_INTERFACE("8c427831-3d90-4476-b647-c4fae349e4db") +ID2D1DeviceContext4 : public ID2D1DeviceContext3 +{ + virtual void STDMETHODCALLTYPE CreateSvgGlyphStyle() = 0; + virtual void STDMETHODCALLTYPE DrawText() = 0; + virtual void STDMETHODCALLTYPE DrawTextLayout() = 0; + virtual void STDMETHODCALLTYPE DrawColorBitmapGlyphRun( + DWRITE_GLYPH_IMAGE_FORMATS glyphImageFormat, + D2D1_POINT_2F baselineOrigin, + const DWRITE_GLYPH_RUN *glyphRun, + DWRITE_MEASURING_MODE measuringMode, + D2D1_COLOR_BITMAP_GLYPH_SNAP_OPTION bitmapSnapOption) = 0; + + virtual void STDMETHODCALLTYPE DrawSvgGlyphRun( + D2D1_POINT_2F baselineOrigin, + const DWRITE_GLYPH_RUN *glyphRun, + ID2D1Brush *defaultFillBrush, + ID2D1SvgGlyphStyle *svgGlyphStyle, + UINT32 colorPaletteIndex, + DWRITE_MEASURING_MODE measuringMode) = 0; + +}; +__CRT_UUID_DECL(ID2D1DeviceContext4, 0x8c427831, 0x3d90, 0x4476, 0xb6, 0x47, 0xc4, 0xfa, 0xe3, 0x49, 0xe4, 0xdb) + +#endif diff --git a/local/recipes/libs/cairo/source/src/win32/dw-extra.h b/local/recipes/libs/cairo/source/src/win32/dw-extra.h new file mode 100644 index 0000000000..a9daced21b --- /dev/null +++ b/local/recipes/libs/cairo/source/src/win32/dw-extra.h @@ -0,0 +1,30 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ + +/* MinGW workarounds + * + * It doesn't define operators for DWRITE_GLYPH_IMAGE_FORMATS. + * The DWRITE_COLOR_GLYPH_RUN struct isn't valid. + * + */ + +#ifndef DWRITE_EXTRA_H +#define DWRITE_EXTRA_H + +#if defined(__MINGW64_VERSION_MAJOR) && __MINGW64_VERSION_MAJOR < 10 + +typedef struct DWRITE_COLOR_GLYPH_RUN1_WORKAROUND DWRITE_COLOR_GLYPH_RUN1_WORKAROUND; +struct DWRITE_COLOR_GLYPH_RUN1_WORKAROUND : DWRITE_COLOR_GLYPH_RUN +{ + DWRITE_GLYPH_IMAGE_FORMATS glyphImageFormat; + DWRITE_MEASURING_MODE measuringMode; +}; + +#else +typedef DWRITE_COLOR_GLYPH_RUN1 DWRITE_COLOR_GLYPH_RUN1_WORKAROUND; +#endif + +#if !defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 11 +DEFINE_ENUM_FLAG_OPERATORS(DWRITE_GLYPH_IMAGE_FORMATS); +#endif + +#endif /* DWRITE_EXTRA_H */ diff --git a/local/recipes/libs/cairo/source/subprojects/.gitignore b/local/recipes/libs/cairo/source/subprojects/.gitignore new file mode 100644 index 0000000000..cd557edb70 --- /dev/null +++ b/local/recipes/libs/cairo/source/subprojects/.gitignore @@ -0,0 +1,11 @@ +/expat-*/ +/freetype2 +/glib +/gperf +/fontconfig +/libffi +/proxy-libintl +/zlib-* +/packagecache +/pixman +/libpng* diff --git a/local/recipes/libs/cairo/source/subprojects/expat.wrap b/local/recipes/libs/cairo/source/subprojects/expat.wrap new file mode 100644 index 0000000000..36be273c6e --- /dev/null +++ b/local/recipes/libs/cairo/source/subprojects/expat.wrap @@ -0,0 +1,13 @@ +[wrap-file] +directory = expat-2.6.0 +source_url = https://github.com/libexpat/libexpat/releases/download/R_2_6_0/expat-2.6.0.tar.xz +source_filename = expat-2.6.0.tar.bz2 +source_hash = cb5f5a8ea211e1cabd59be0a933a52e3c02cc326e86a4d387d8d218e7ee47a3e +patch_filename = expat_2.6.0-1_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/expat_2.6.0-1/get_patch +patch_hash = 7452665b0cf413f87fae1dc4d5c779bc2c8f0ccf3ba637140c9d46eacf521604 +source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/expat_2.6.0-1/expat-2.6.0.tar.bz2 +wrapdb_version = 2.6.0-1 + +[provide] +expat = expat_dep diff --git a/local/recipes/libs/cairo/source/subprojects/fontconfig.wrap b/local/recipes/libs/cairo/source/subprojects/fontconfig.wrap new file mode 100644 index 0000000000..7dc4168117 --- /dev/null +++ b/local/recipes/libs/cairo/source/subprojects/fontconfig.wrap @@ -0,0 +1,10 @@ +[wrap-file] +directory = fontconfig-2.14.2 +source_url = https://www.freedesktop.org/software/fontconfig/release/fontconfig-2.14.2.tar.xz +source_filename = fontconfig-2.14.2.tar.xz +source_hash = dba695b57bce15023d2ceedef82062c2b925e51f5d4cc4aef736cf13f60a468b +source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/fontconfig_2.14.2-1/fontconfig-2.14.2.tar.xz +wrapdb_version = 2.14.2-1 + +[provide] +fontconfig = fontconfig_dep diff --git a/local/recipes/libs/cairo/source/subprojects/freetype2.wrap b/local/recipes/libs/cairo/source/subprojects/freetype2.wrap new file mode 100644 index 0000000000..e3554c9a12 --- /dev/null +++ b/local/recipes/libs/cairo/source/subprojects/freetype2.wrap @@ -0,0 +1,11 @@ +[wrap-file] +directory = freetype-2.13.2 +source_url = https://download.savannah.gnu.org/releases/freetype/freetype-2.13.2.tar.xz +source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/freetype2_2.13.2-1/freetype-2.13.2.tar.xz +source_filename = freetype-2.13.2.tar.xz +source_hash = 12991c4e55c506dd7f9b765933e62fd2be2e06d421505d7950a132e4f1bb484d +wrapdb_version = 2.13.2-1 + +[provide] +freetype2 = freetype_dep +freetype = freetype_dep diff --git a/local/recipes/libs/cairo/source/subprojects/glib.wrap b/local/recipes/libs/cairo/source/subprojects/glib.wrap new file mode 100644 index 0000000000..51d9cf8d47 --- /dev/null +++ b/local/recipes/libs/cairo/source/subprojects/glib.wrap @@ -0,0 +1,10 @@ +[wrap-file] +directory = glib-2.74.0 +source_url = https://download.gnome.org/sources/glib/2.74/glib-2.74.0.tar.xz +source_filename = glib-2.74.0.tar.xz +source_hash = 3652c7f072d7b031a6b5edd623f77ebc5dcd2ae698598abcc89ff39ca75add30 +wrapdb_version = 2.74.0-1 + +[provide] +dependency_names = gthread-2.0, gobject-2.0, gmodule-no-export-2.0, gmodule-export-2.0, gmodule-2.0, glib-2.0, gio-2.0, gio-windows-2.0, gio-unix-2.0 +program_names = glib-genmarshal, glib-mkenums, glib-compile-schemas, glib-compile-resources, gio-querymodules, gdbus-codegen diff --git a/local/recipes/libs/cairo/source/subprojects/pixman.wrap b/local/recipes/libs/cairo/source/subprojects/pixman.wrap new file mode 100644 index 0000000000..6ce238b84d --- /dev/null +++ b/local/recipes/libs/cairo/source/subprojects/pixman.wrap @@ -0,0 +1,10 @@ +[wrap-file] +directory = pixman-0.43.4 +source_url = https://www.cairographics.org/releases/pixman-0.43.4.tar.gz +source_filename = pixman-0.43.4.tar.gz +source_hash = a0624db90180c7ddb79fc7a9151093dc37c646d8c38d3f232f767cf64b85a226 +source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/pixman_0.43.4-1/pixman-0.43.4.tar.gz +wrapdb_version = 0.43.4-1 + +[provide] +pixman-1 = idep_pixman diff --git a/local/recipes/libs/cairo/source/subprojects/zlib.wrap b/local/recipes/libs/cairo/source/subprojects/zlib.wrap new file mode 100644 index 0000000000..aa14de1774 --- /dev/null +++ b/local/recipes/libs/cairo/source/subprojects/zlib.wrap @@ -0,0 +1,13 @@ +[wrap-file] +directory = zlib-1.3.1 +source_url = http://zlib.net/fossils/zlib-1.3.1.tar.gz +source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/zlib_1.3.1-1/zlib-1.3.1.tar.gz +source_filename = zlib-1.3.1.tar.gz +source_hash = 9a93b2b7dfdac77ceba5a558a580e74667dd6fede4585b91eefb60f03b72df23 +patch_filename = zlib_1.3.1-1_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/zlib_1.3.1-1/get_patch +patch_hash = e79b98eb24a75392009cec6f99ca5cdca9881ff20bfa174e8b8926d5c7a47095 +wrapdb_version = 1.3.1-1 + +[provide] +zlib = zlib_dep diff --git a/local/recipes/libs/cairo/source/test/.gitignore b/local/recipes/libs/cairo/source/test/.gitignore new file mode 100644 index 0000000000..5ffeedc288 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/.gitignore @@ -0,0 +1,38 @@ +TAGS +tags +.deps +.libs +output +Makefile +Makefile.in +ref.hash +ref.list +any2ppm +.any2ppm +.any2ppm.pid +.any2ppm.errors +cairo-test-constructors.c +cairo-test-trace +cairo-test-suite +pdf2png +ps2png +svg2png +callgrind.out.* +valgrind-log +*.manifest +*.gcda +*.gcno +*.exe +*.exe.so +*.obj +*.ilk +*.pdb +*.la +*.lo +*.log +*.suo +*.trs +*.o +*~ +.*.sw? +make-cairo-test-constructors diff --git a/local/recipes/libs/cairo/source/test/.valgrind-suppressions b/local/recipes/libs/cairo/source/test/.valgrind-suppressions new file mode 100644 index 0000000000..f481a2f007 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/.valgrind-suppressions @@ -0,0 +1,577 @@ +{ + in dl.so + Memcheck:Cond + fun:_dl_relocate_object + } +{ + bugs in libpng/libz + Memcheck:Cond + obj:/usr/lib/libz.so.1.2.2.2 + obj:/usr/lib/libz.so.1.2.2.2 + fun:deflate + } +{ + bugs in libpng/libz + Memcheck:Cond + obj:/usr/lib/libz.so.1.2.3 + obj:/usr/lib/libz.so.1.2.3 + fun:deflate + } +{ + bugs in libpng/libz + Memcheck:Cond + obj:/usr/lib/libz.so.1.2.3.3 + } +{ + bugs in libpng/libz + Memcheck:Value8 + obj:/usr/lib/libz.so.1.2.3.3 + } +{ + cairo's write_png triggers apparent bugs in libpng/libz + Memcheck:Cond + obj:/usr/lib/libz.so.1.2.2.2 + obj:/usr/lib/libz.so.1.2.2.2 + fun:deflate + fun:png_write_finish_row + fun:png_write_filtered_row + fun:png_write_find_filter + fun:png_write_row + fun:png_write_image + fun:write_png + } +{ + cairo's write_png_argb32 triggers apparent bugs in libpng/libz + Memcheck:Cond + obj:/usr/lib/libz.so.1.2.3 + obj:/usr/lib/libz.so.1.2.3 + fun:deflate + obj:/usr/lib/libpng12.so.0.1.2.8 + obj:/usr/lib/libpng12.so.0.1.2.8 + obj:/usr/lib/libpng12.so.0.1.2.8 + fun:png_write_row + fun:png_write_image + fun:write_png +} +{ + cairo's write_png_argb32 triggers apparent bugs in libpng/libz + Memcheck:Cond + obj:/usr/lib/libz.so.1.2.2.2 + obj:/usr/lib/libz.so.1.2.2.2 + fun:deflate + fun:png_write_finish_row + fun:png_write_filtered_row + fun:png_write_find_filter + fun:png_write_row + fun:png_write_image + fun:write_png_argb32 + } +{ + cairo's _cairo_pdf_surface_paint triggers apparent bugs in libz + Memcheck:Cond + obj:/usr/lib/libz.so.1.2.3 + obj:/usr/lib/libz.so.1.2.3 + fun:deflate + fun:compress2 + fun:compress + fun:compress_dup + fun:emit_image + fun:emit_surface_pattern + fun:emit_pattern + fun:_cairo_pdf_surface_paint +} +{ + cairo's _cairo_pdf_surface_paint triggers apparent bugs in libz + Memcheck:Cond + obj:/usr/lib/libz.so.1.2.3 + obj:/usr/lib/libz.so.1.2.3 + fun:deflate + fun:compress2 + fun:compress + fun:compress_dup + fun:emit_pattern + fun:_cairo_pdf_surface_paint +} +{ + cairo's _cairo_pdf_surface_paint triggers apparent bugs in libz + Memcheck:Cond + fun:deflate_slow + fun:deflate +} +{ + cairo's _cairo_pdf_surface_paint triggers apparent bugs in libz + Memcheck:Value4 + fun:deflate_slow + fun:deflate +} +{ + cairo's _cairo_pdf_surface_paint triggers apparent bugs in libz + Memcheck:Value4 + fun:compress_block + fun:_tr_flush_block + fun:deflate_slow + fun:deflate +} +{ + cairo's _cairo_pdf_surface_paint triggers apparent bugs in libz + Memcheck:Value4 + fun:crc32 + obj:/usr/lib/libpng12.so.0.15.0 + fun:png_write_chunk_data + fun:png_write_chunk +} +{ + cairo's _cairo_pdf_surface_paint triggers apparent bugs in libz + Memcheck:Value4 + fun:base64_write_func + fun:stream_write_func + obj:/usr/lib/libpng12.so.0.15.0 + fun:png_write_chunk_data + fun:png_write_chunk +} +{ + pthread initialization strstr bug + Memcheck:Cond + fun:strstr + fun:__pthread_initialize_minimal + obj:/lib/libpthread-2.3.5.so + obj:/lib/libpthread-2.3.5.so + fun:call_init + fun:_dl_init + obj:/lib/ld-2.3.5.so +} +{ + Pixman reads padding bytes that are never initialized + Memcheck:Cond + fun:fbBltOne + fun:fbCompositeSolidMask_nx1xn + fun:_cairo_pixman_composite + fun:_cairo_image_surface_composite + fun:_cairo_surface_composite + fun:_cairo_ft_scaled_font_show_glyphs + fun:_cairo_scaled_font_show_glyphs + fun:_cairo_gstate_show_glyphs_draw_func + fun:_cairo_gstate_clip_and_composite + fun:_cairo_gstate_show_glyphs + fun:cairo_show_text + fun:draw +} +{ + XXX: I have no idea what might be causing this + Memcheck:Free + fun:free + fun:free_mem + fun:__libc_freeres + fun:_vgw_freeres + fun:exit + fun:__libc_start_main +} +{ + XrmGetStringDatabase is fairly obnoxious about leaving reachable memory around + Memcheck:Leak + fun:malloc + fun:_XlcAddCT + fun:_XlcInitCTInfo + fun:initialize + fun:initialize + fun:_XlcCreateLC + fun:_XlcUtf8Loader + fun:_XOpenLC + fun:_XrmInitParseInfo + fun:NewDatabase + fun:XrmGetStringDatabase +} +{ + XrmGetStringDatabase is fairly obnoxious about leaving reachable memory around + Memcheck:Leak + fun:malloc + fun:PutEntry + fun:GetDatabase + fun:XrmGetStringDatabase +} +{ + XrmGetStringDatabase is fairly obnoxious about leaving reachable memory around + Memcheck:Leak + fun:malloc + fun:initialize + fun:_XlcCreateLC + fun:_XlcDefaultLoader + fun:_XOpenLC + fun:_XrmInitParseInfo + fun:NewDatabase + fun:XrmGetStringDatabase +} +{ + XrmGetStringDatabase is fairly obnoxious about leaving reachable memory around + Memcheck:Leak + fun:malloc + fun:add_codeset + fun:initialize + fun:_XlcCreateLC + fun:_XlcDefaultLoader + fun:_XOpenLC + fun:_XrmInitParseInfo + fun:NewDatabase + fun:XrmGetStringDatabase +} +{ + XrmInitialize is fairly obnoxious about leaving reachable memory around + Memcheck:Leak + fun:malloc + fun:_XrmInternalStringToQuark +} +{ + XrmInitialize is fairly obnoxious about leaving reachable memory around + Memcheck:Leak + fun:malloc + obj:/usr/lib/libX11.so.6.2.0 + fun:_XrmInternalStringToQuark + fun:XrmInitialize +} +{ + XrmInitialize is fairly obnoxious about leaving reachable memory around + Memcheck:Leak + fun:malloc + fun:permalloc + fun:_XrmInternalStringToQuark +} +{ + XrmGetStringDatabase is fairly obnoxious about leaving reachable memory around + Memcheck:Leak + fun:malloc + fun:_XlcSetConverter + fun:_XlcDefaultLoader + fun:_XOpenLC + fun:_XrmInitParseInfo + fun:NewDatabase + fun:XrmGetStringDatabase +} +{ + XrmGetStringDatabase is fairly obnoxious about leaving reachable memory around + Memcheck:Leak + fun:malloc + fun:_XlcCreateDefaultCharSet + fun:_XlcAddCT + fun:_XlcInitCTInfo + fun:initialize + fun:initialize + fun:_XlcCreateLC + fun:_XlcUtf8Loader + fun:_XOpenLC + fun:_XrmInitParseInfo + fun:NewDatabase + fun:XrmGetStringDatabase +} +{ + XrmGetStringDatabase is fairly obnoxious about leaving reachable memory around + Memcheck:Leak + fun:realloc + fun:add_codeset + fun:initialize + fun:_XlcCreateLC + fun:_XlcDefaultLoader + fun:_XOpenLC + fun:_XrmInitParseInfo + fun:NewDatabase + fun:XrmGetStringDatabase +} +{ + XrmGetStringDatabase is fairly obnoxious about leaving reachable memory around + Memcheck:Leak + fun:realloc + fun:add_codeset + fun:load_generic + fun:initialize + fun:_XlcCreateLC + fun:_XlcDefaultLoader + fun:_XOpenLC +} +{ + XrmGetStringDatabase is fairly obnoxious about leaving reachable memory around + Memcheck:Leak + fun:malloc + fun:add_codeset + fun:load_generic + fun:initialize + fun:_XlcCreateLC + fun:_XlcDefaultLoader + fun:_XOpenLC +} +{ + XrmGetStringDatabase is fairly obnoxious about leaving reachable memory around + Memcheck:Leak + fun:malloc + fun:load_generic + fun:initialize + fun:_XlcCreateLC + fun:_XlcDefaultLoader + fun:_XOpenLC +} +{ + XrmGetStringDatabase is fairly obnoxious about leaving reachable memory around + Memcheck:Leak + fun:malloc + fun:_XlcAddCharSet + fun:_XlcAddCT + fun:_XlcInitCTInfo + fun:initialize + fun:initialize + fun:_XlcCreateLC + fun:_XlcUtf8Loader + fun:_XOpenLC + fun:_XrmInitParseInfo + fun:NewDatabase + fun:XrmGetStringDatabase +} +{ + XrmGetStringDatabase is fairly obnoxious about leaving reachable memory around + Memcheck:Leak + fun:malloc + fun:_XlcCreateLocaleDataBase + fun:initialize + fun:initialize + fun:_XlcCreateLC + fun:_XlcUtf8Loader + fun:_XOpenLC + fun:_XrmInitParseInfo + fun:NewDatabase + fun:XrmGetStringDatabase +} +{ + XrmGetStringDatabase is fairly obnoxious about leaving reachable memory around + Memcheck:Leak + fun:malloc + fun:_XlcSetConverter + fun:_XlcInitCTInfo + fun:initialize + fun:initialize + fun:_XlcCreateLC + fun:_XlcUtf8Loader + fun:_XOpenLC + fun:_XrmInitParseInfo + fun:NewDatabase + fun:XrmGetStringDatabase +} +{ + pthread initialization seems to leave some memory possibly lost + Memcheck:Leak + fun:calloc + obj:/lib/ld-2.3.6.so + obj:/lib/ld-2.3.6.so + fun:_dl_allocate_tls + fun:__pthread_initialize_minimal + obj:/usr/lib/debug/libpthread-0.10.so + obj:/usr/lib/debug/libpthread-0.10.so + obj:/lib/ld-2.3.6.so + obj:/lib/ld-2.3.6.so + obj:/lib/ld-2.3.6.so +} +{ + pthread initialization seems to leave some memory still reachable + Memcheck:Leak + fun:calloc + fun:_dl_tls_setup + fun:__pthread_initialize_minimal + obj:/usr/lib/debug/libpthread-0.10.so + obj:/usr/lib/debug/libpthread-0.10.so + obj:/lib/ld-2.3.6.so + obj:/lib/ld-2.3.6.so + obj:/lib/ld-2.3.6.so +} +{ + pthread initialization seems to leave some memory possibly lost + Memcheck:Leak + fun:memalign + obj:/lib/ld-2.3.6.so + fun:_dl_allocate_tls + fun:__pthread_initialize_minimal + obj:/usr/lib/debug/libpthread-0.10.so + obj:/usr/lib/debug/libpthread-0.10.so + obj:/lib/ld-2.3.6.so + obj:/lib/ld-2.3.6.so + obj:/lib/ld-2.3.6.so +} +{ + XrmGet*Database is fairly obnoxious about leaving reachable memory around + Memcheck:Leak + fun:malloc + fun:_XlcAddCT + fun:_XlcInitCTInfo + fun:initialize + fun:initialize + fun:_XlcCreateLC + fun:_XlcUtf8Loader + fun:_XOpenLC + fun:_XrmInitParseInfo + fun:NewDatabase +} +{ + XrmGet*Database is fairly obnoxious about leaving reachable memory around + Memcheck:Leak + fun:malloc + fun:PutEntry + fun:GetDatabase +} +{ + XrmGet*Database is fairly obnoxious about leaving reachable memory around + Memcheck:Leak + fun:malloc + fun:initialize + fun:_XlcCreateLC + fun:_XlcDefaultLoader + fun:_XOpenLC + fun:_XrmInitParseInfo + fun:NewDatabase +} +{ + XrmGet*Database is fairly obnoxious about leaving reachable memory around + Memcheck:Leak + fun:malloc + fun:add_codeset + fun:initialize + fun:_XlcCreateLC + fun:_XlcDefaultLoader + fun:_XOpenLC + fun:_XrmInitParseInfo + fun:NewDatabase +} +{ + XrmGet*Database is fairly obnoxious about leaving reachable memory around + Memcheck:Leak + fun:malloc + fun:_XlcAddCharSet + fun:_XlcAddCT + fun:_XlcInitCTInfo + fun:initialize + fun:initialize + fun:_XlcCreateLC + fun:_XlcUtf8Loader + fun:_XOpenLC + fun:_XrmInitParseInfo + fun:NewDatabase +} +{ + XrmGet*Database is fairly obnoxious about leaving reachable memory around + Memcheck:Leak + fun:realloc + fun:add_codeset + fun:initialize + fun:_XlcCreateLC + fun:_XlcDefaultLoader + fun:_XOpenLC + fun:_XrmInitParseInfo + fun:NewDatabase +} +{ + XrmGet*Database is fairly obnoxious about leaving reachable memory around + Memcheck:Leak + fun:malloc + fun:_XlcCreateDefaultCharSet + fun:_XlcAddCT + fun:_XlcInitCTInfo + fun:initialize + fun:initialize + fun:_XlcCreateLC + fun:_XlcUtf8Loader + fun:_XOpenLC + fun:_XrmInitParseInfo + fun:NewDatabase +} +{ + XrmGet*Database is fairly obnoxious about leaving reachable memory around + Memcheck:Leak + fun:malloc + fun:_XlcCreateDefaultCharSet + fun:_XlcAddCT + fun:_XlcInitCTInfo + fun:initialize + fun:initialize + fun:_XlcCreateLC + fun:_XlcUtf8Loader + fun:_XOpenLC + fun:_XrmInitParseInfo + fun:NewDatabase +} +{ + XrmGet*Database is fairly obnoxious about leaving reachable memory around + Memcheck:Leak + fun:malloc + fun:_XlcAddCT + fun:_XlcInitCTInfo + fun:initialize + fun:initialize + fun:_XlcCreateLC + fun:_XlcUtf8Loader + fun:_XOpenLC + fun:_XrmInitParseInfo + fun:NewDatabase +} +{ + XrmGet*Database is fairly obnoxious about leaving reachable memory around + Memcheck:Leak + fun:malloc + fun:_XlcCreateLocaleDataBase + fun:initialize + fun:initialize + fun:_XlcCreateLC + fun:_XlcUtf8Loader + fun:_XOpenLC + fun:_XrmInitParseInfo + fun:NewDatabase +} +{ + XrmGet*Database is fairly obnoxious about leaving reachable memory around + Memcheck:Leak + fun:malloc + fun:_XlcCreateDefaultCharSet + fun:_XlcAddCT + fun:_XlcInitCTInfo + fun:initialize + fun:initialize + fun:_XlcCreateLC + fun:_XlcUtf8Loader + fun:_XOpenLC + fun:_XrmInitParseInfo + fun:NewDatabase +} +{ + XrmGet*Database is fairly obnoxious about leaving reachable memory around + Memcheck:Leak + fun:malloc + fun:_XlcSetConverter + fun:_XlcInitCTInfo + fun:initialize + fun:initialize + fun:_XlcCreateLC + fun:_XlcUtf8Loader + fun:_XOpenLC + fun:_XrmInitParseInfo + fun:NewDatabase +} +{ + XrmGet*Database is fairly obnoxious about leaving reachable memory around + Memcheck:Leak + fun:malloc + fun:_XlcSetConverter + fun:_XlcDefaultLoader + fun:_XOpenLC + fun:_XrmInitParseInfo + fun:NewDatabase +} +{ + XrmGet*Database is fairly obnoxious about leaving reachable memory around + Memcheck:Leak + fun:malloc + fun:_XlcSetConverter + fun:_XlcAddUtf8Converters + fun:_XlcDefaultLoader + fun:_XOpenLC + fun:_XrmInitParseInfo + fun:NewDatabase +} +{ + Xau chooses not to free its static data... + Memcheck:Leak + fun:malloc + fun:XauFileName +} diff --git a/local/recipes/libs/cairo/source/test/6x13.pcf b/local/recipes/libs/cairo/source/test/6x13.pcf new file mode 100644 index 0000000000..1325ae64fd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/6x13.pcf differ diff --git a/local/recipes/libs/cairo/source/test/COPYING b/local/recipes/libs/cairo/source/test/COPYING new file mode 100644 index 0000000000..3db71fb08e --- /dev/null +++ b/local/recipes/libs/cairo/source/test/COPYING @@ -0,0 +1,26 @@ +Cairo is free software. + +These tests are mainly available under a liberal MIT license to simplify +any use of the code for reference purposes. Please check the opening comment +of each file for copyright and licensing information. + +The test suite also bundles some fonts for use by the test suite. The +fonts included, their licenses, and why we use them in the test suite +are as follows: + + Font License Distinguishing feature + -------- ------------- ---------------------- + 6x13.pcf Public Domain Bitmap font + + +The test suite also bundles some images for use by the test suite. The +images included, their licenses, and why we use them in the test suite +are as follows: + + Image License Distinguishing feature + ------------- ------------- ------------------------- + romedalen.jpg Public Domain Bitmap image (image/jpeg) + romedalen.png Public Domain Bitmap image (image/png) + +The kind contributors of the bundled files are (in alphabetical order): +Øyvind KolÃ¥s Author of the original romedalen shot. diff --git a/local/recipes/libs/cairo/source/test/README b/local/recipes/libs/cairo/source/test/README new file mode 100644 index 0000000000..e8b5ff6cc5 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/README @@ -0,0 +1,343 @@ +How to use cairo's test suite +============================= +Using this test should be as simple as running: + + meson test -C $builddir -v + +assuming that the cairo distribution in the directory above has been +configured and built in $builddir. The test suite here will use the +locally compiled library rather than installed version. + +The above command runs some source code as well as the rendering +tests. All the rendering tests are in a single meson test named +"cairo". It can be run with: + + meson test -C $builddir -v cairo + +The results of the test suite run are summarized in an index.html file +written to $builddir, which, when viewed in a web browser makes it +quite easy to visually see any failed renderings alongside the +corresponding reference image, (and a diff image as well). + +As some browsers do not permit Javascript to read from the local +filesystem, the view-test-results.py script in the $builddir can used +to view the results. It starts a http server serving the current +directory before displaying the test results in a browser. + +The test suite needs to be run before any code is committed and before +any release. See below for hints and rules governing the use of the suite. + +Running specific tests +---------------------- +During development it is desirable to only run a single test or groups +of related tests. Individual tests can be run by specifying the tests +names as arguments to the cairo test. + + meson test -v cairo --test-args "record-neg-extents-unbounded record-neg-extents-bounded" + +The test suite is built as a single binary, "cairo-test-suite", which +can be run directly instead of via meson. This may be more convenient +when specifying multiple test arguments. The executable needs to be +run in $builddir/test in order to find the image conversion +executables. Simply running the executable will run all tests. eg + + cd $builddir/test + ./cairo-test-suite + +Normally the executable will use the locally compiled library. But if +you have a LD_LIBRARY_PATH defined or built cairo with an -rpath, the +executable may not link with the locally compiled library. + +Individual tests can be run be specifying the tests names as arguments +to cairo-test-suite. For example, to run specific tests: + + ./cairo-test-suite record-neg-extents-unbounded record-neg-extents-bounded + +Or if you want to run all paint.* related tests you can use: + + ./cairo-test-suite paint + +Or if you want to check the current status of known failures: + + ./cairo-test-suite XFAIL + +Or to run a subset of tests, use the -k option to run only the tests +that include the given keyword: + + ./cairo-test-suite -k downscale + +The -l option lists all tests available. For convenience, the file +"completion.bash" in $builddir can be sourced to provide bash +completion of the test names in cairo-test-suite. + +By default, each test that is run will be tested on all backends that +have been built. The CAIRO_TEST_TARGET environment variable can be +used to select specific backends. For example: + + CAIRO_TEST_TARGET=pdf ./cairo-test-suite text-rotate + +Each test is run twice on each backend, once for each format. The +CAIRO_TEST_TARGET_FORMAT environment variable selects a single +format. The formats are "rgba" and "rgb". For example to run the +text-rotate test only on the image backend and only for the "rgba" +format: + + CAIRO_TEST_TARGET=image CAIRO_TEST_TARGET_FORMAT=rgba ./cairo-test-suite text-rotate + +Running tests under modified environments or tools +-------------------------------------------------- +To run tests under in gdb, one can simply run the cairo-suite-suite in +gdb. Usually a specific test will be desired. eg + + CAIRO_TEST_TARGET=image CAIRO_TEST_TARGET_FORMAT=rgba gdb --args ./cairo-test-suite text-rotate + +The cairo test suite runs each test in a child process so that crashes +do not stop the test. When running the test suite under tools, the "-f" +option disables forking. eg to run a test under valgrind: + + CAIRO_TEST_TARGET=image CAIRO_TEST_TARGET_FORMAT=rgba valgrind ./cairo-test-suite -f text-rotate + +The cairo test suite detects if it is running under gdb and disables +forking. Hence the reason the gdb example above did not use "-f". + +Complete list of test options +----------------------------- +cairo-test-suite options: + + ./cairo-test-suite [-afkxsl] [test-names|keywords ...] + + -a all; run the full set of tests. By default the test suite + skips similar surface and device offset testing. + -f foreground; do not fork + -k match tests by keyword + -l list only; just list selected test case names without executing + -s include slow, long running tests + -x exit on first failure + +Environment Variables: + +CAIRO_TEST_TARGET + Run the test only the the listed targets. eg + CAIRO_TEST_TARGET="image" + CAIRO_TEST_TARGET="pdf,ps3,ps2" + +CAIRO_TEST_TARGET_FORMAT + Run the test only the the listed targets. eg + CAIRO_TEST_TARGET_FORMAT="rgba" + CAIRO_TEST_TARGET_FORMAT="rgba,rgb" + +CAIRO_TEST_MODE + May contain a list of one or more of the following options + "full" - equivalent to the "-a" option + "similar" + "offset" + "scale" + "foreground" - equivalent to the "-f" option + "exit-on-failure" - equivalent to the "-x" option + eg + CAIRO_TEST_MODE="full,foreground" + +CAIRO_TESTS + A list of test to run. This is equivalent to listing the tests as + arguments to cairo=test-suite. eg + CAIRO_TESTS="record-neg-extents-unbounded record-neg-extents-bounded" + The tests may be separated by any of " \t,:;". + +srcdir + The test suite needs to find the "test" directory in the source + tree. The srcdir environment variable can be used to specify the + location of this directory. If this environment variable is not set, + the binary looks for the directory "srcdir" in the current + directory. The meson build system symlinks "srcdir" in the + $builddir/test directory to the "test" directory in the source + tree. If this is not found the binary defaults to the current + directory. + +CAIRO_REF_DIR + The directory containing the reference images. By default the test + suite looks for "reference" in $srcdir. For convenience, you can set + CAIRO_REF_DIR to point at a previous test directory, relative to the + current test directory, and any previous output will be used by + preference as reference images. + +CAIRO_TEST_TIMEOUT + The maximum time, in seconds, an indivdual test may run before it is + stopped. The default is 60 seconds. + +Getting the elusive zero failures +--------------------------------- +It's generally been very difficult to achieve a test run with zero +failures. The difficulties stem from the various versions of the many +libraries that the test suite depends on, (it depends on a lot more +than cairo itself), as well as fonts and other system-specific +settings. If your system differs significantly from the system on +which the reference images were generated, then you will likely see +the test suite reporting "failures", (even if cairo is working just +fine). + +Since the test suite must pass the Continuous Integration test in the +Gitlab instance hosting the cairo repository, the easiest way to get a +new or updated test to pass is to extract the test output from the +cairo gitlab CI to use as reference images. + +What if I can't make my system match? +------------------------------------- +For one reason or another, you may be unable to get a clean run of the +test suite even if cairo is working properly, (for example, you might +be on a system without freetype). In this case, it's still useful to +be able to determine if code changes you make to cairo result in any +regressions to the test suite. But it's hard to notice regressions if +there are many failures both before and after your changes. + +For this scenario, you can capture the output of a run of the test +suite before your changes, and then use the CAIRO_REF_DIR environment +variable to use that output as the reference images for a run after +your changes. The process looks like this: + + # Before code change there may be failures we don't care about + cd $builddir/test + ./cairo-test-suite + + # Let's save those output images + mkdir /some/directory/ + cp -r output /some/directory/ + + # hack, hack, hack + + # Now to see if nothing changed: + CAIRO_REF_DIR=/some/directory/ ./cairo-test-suite + +Best practices for cairo developers +=================================== +If we all follow the guidelines below, then both the test suite and +cairo itself will stay much healthier, and we'll all have a lot more +fun hacking on cairo. + +Before creating a Merge Request +------------------------------- +After pushing your branch to your cairo fork on gitlab.freedesktop.org, +check that the CI passes. A MR cannot be merged until the CI passes. + +It is likely that you will need to download test output images from +the Gitlab CI to use as reference images in order to get CI to pass. + +The reference image filenames have the form: + +.*.ref.png for correct images that pass. + +.*.xfail.png for incorrect images due to bugs. + +The .ref.png is the most general image that all backends +and formats for the test will be required to match. + +When comparing test output to the reference images, the test suite +performs a perceptual diff which permits some minor pixel differences +that are not visually discernible. Some targets may have differences +that exceed the threshold of the perceptual diff but still appear the +same as the reference image when eyeballed. In these cases, target +specific reference images can be created that override the general +reference image for the specific target. + +Reference images for specific backends can be created using filenames of the form: + ..ref.png + +eg clip.pdf.ref.png + +The target name "ps" can be used for both "ps2" and "ps3" targets. + +Reference images for specific formats can be created using filenames of the form: + ...ref.png + +eg + clip.pdf.argb32.ref.png + clip.pdf.rgb24.ref.png + +The recommended practice for creating reference images for a new test is: + +1. Create a .ref.png reference image from .image.argb32.out.png +output. + +2. Push to gitlab and check the CI result. + +3. If the image target fails, copy the .image.argb32.out.png output +from CI and use as the reference image. + +4. Once the image target passes in CI, check that the other targets +pass. If any fail, create ..ref.png reference images if the +output appears correct. + +5. If a target output is incorrect, try to determine if the cairo +target output is correct. eg view pdf files in Adobe Reader. If the +cairo target output is correct, it can be assumed the image converson +from target to png is buggy. File a bug against the conversion tool +and create a ..xfail.png reference image. + +In all cases, before creating a reference image from test output, the +image should be viewed to ensure that it is correct. + +When a new bug is found +----------------------- +A new test case should be added by imitating the style of an existing +test. This means adding the following files: + + new-bug.c + reference/new-bug.ref.png + reference/new-bug.xfail.png + +Where new-bug.c is a minimal program to demonstrate the bug, following +the style of existing tests. The new-bug.ref.png image should contain +the desired result of new-bug.c if the bug were fixed while +new-bug.xfail.png contains the current results of the test. + +"meson.build" should be edited by adding new-bug.c to test_sources. +And last but not least, don't forget to "git add" the new files. + +When a new feature is added +--------------------------- +It's important for the regression suite to keep pace with development +of the library. So a new test should be added for each new feature. +The work involved is similar the work described above for new bugs. +The only distinction is that the test is expected to pass so it +should not need a new-bug.xfail.png file. + +While working on a test +----------------------- +Before a bugfix or feature is ready, it may be useful to compare +output from different builds. For convenience, you can set +CAIRO_REF_DIR to point at a previous test directory, relative +to the current test directory, and any previous output will be +used by preference as reference images. + +When a bug is fixed +------------------- +The fix should be verified by running the test suite which should +result in an "unexpected pass" for the test of interest. Rejoice as +appropriate, then remove the relevant xfail.png file from git. + +Before releasing +---------------- +All tests should return a result of PASS for all supported (those enabled by +default) backends, meaning all known bugs are fixed, resulting in the happy +message: + + All XX tests passed + +Some notes on limitations in poppler +==================================== +One of the difficulties of our current test infrastructure is that we +rely on external tools to convert cairo's vector output (PDF, +PostScript, and SVG), into an image that can be used for the image +comparison. This means that any bugs in that conversion tool will +result in false negatives in the test suite. + +Here's the rule: If a cairo-pdf test reports a failure, but viewing +the resulting PDF file with acroread suggests that the PDF itself is +correct, then there's likely a bug in poppler. In this case, we can +simply report the poppler bug. Once we've done this, we can capture +poppler's buggy output as a pdf-specific reference image (as +reference/*.xfail.png) so that the test suite will regard the test as +passing, (and we'll ensure there is no regression). + +Once the poppler bug gets fixed, the test suite will start reporting a +false negative again, and this will be easy to fix by simply removing +the pdf-specific reference image. diff --git a/local/recipes/libs/cairo/source/test/a1-bug.c b/local/recipes/libs/cairo/source/test/a1-bug.c new file mode 100644 index 0000000000..8e00d40e3f --- /dev/null +++ b/local/recipes/libs/cairo/source/test/a1-bug.c @@ -0,0 +1,61 @@ +/* + * 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. + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + static const struct point { + double x; + double y; + } xy[] = { + { 627.016212, 221.749777 }, + { 756.120787, 221.749777 }, + { 756.120787, 557.602766 }, + { 626.952721, 557.602766 }, + { 626.548456, 493.315729 }, + }; + unsigned int i; + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + for (i = 0; i < ARRAY_LENGTH (xy); i++) + cairo_line_to (cr, xy[i].x, xy[i].y); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_fill_preserve (cr); + + cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (a1_bug, + "Check the fidelity of the rasterisation.", + "a1, raster", /* keywords */ + "target=raster", /* requirements */ + 1000, 800, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/a1-clip.c b/local/recipes/libs/cairo/source/test/a1-clip.c new file mode 100644 index 0000000000..0e84cd39b8 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/a1-clip.c @@ -0,0 +1,175 @@ +/* + * Copyright © 2008 Red Hat, Inc. + * + * 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: Carl D. Worth + */ + +#include "cairo-test.h" + +#define POINTS 10 +#define STEP (1.0 / POINTS) +#define PAD 1 +#define WIDTH (PAD + POINTS * 2 + PAD) +#define HEIGHT (WIDTH) + +static cairo_test_status_t +paint (cairo_t *cr, int width, int height) +{ + int i, j; + + /* Fill background white */ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + /* Draw in black */ + cairo_set_source_rgb (cr, 0, 0, 0); + + cairo_translate (cr, PAD, PAD); + cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); + + for (i = 0; i < POINTS; i++) + for (j = 0; j < POINTS; j++) { + cairo_save (cr); + cairo_rectangle (cr, 2 * i + i * STEP, 2 * j + j * STEP, 1, 1); + cairo_clip (cr); + cairo_paint (cr); + cairo_restore (cr); + } + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +fill_equal (cairo_t *cr, int width, int height) +{ + int i, j; + + /* Fill background white */ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + /* Draw in black */ + cairo_set_source_rgb (cr, 0, 0, 0); + + cairo_translate (cr, PAD, PAD); + cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); + + for (i = 0; i < POINTS; i++) + for (j = 0; j < POINTS; j++) { + cairo_save (cr); + cairo_rectangle (cr, 2 * i + i * STEP, 2 * j + j * STEP, 1, 1); + cairo_clip_preserve (cr); + cairo_fill (cr); + cairo_restore (cr); + } + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +fill (cairo_t *cr, int width, int height) +{ + int i, j; + + /* Fill background white */ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + /* Draw in black */ + cairo_set_source_rgb (cr, 0, 0, 0); + + cairo_translate (cr, PAD, PAD); + cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); + + for (i = 0; i < POINTS; i++) + for (j = 0; j < POINTS; j++) { + cairo_save (cr); + cairo_rectangle (cr, 2 * i + i * STEP, 2 * j + j * STEP, 1, 1); + cairo_clip (cr); + cairo_rectangle (cr, 2 * i, 2 * j, 2, 2); + cairo_fill (cr); + cairo_restore (cr); + } + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +stroke (cairo_t *cr, int width, int height) +{ + int i, j; + + /* Fill background white */ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + /* Draw in black */ + cairo_set_source_rgb (cr, 0, 0, 0); + + cairo_translate (cr, PAD, PAD); + cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); + + cairo_set_line_width (cr, 2); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + + for (i = 0; i < POINTS; i++) + for (j = 0; j < POINTS; j++) { + cairo_save (cr); + cairo_rectangle (cr, 2 * i + i * STEP, 2 * j + j * STEP, 1, 1); + cairo_clip (cr); + cairo_move_to (cr, 2 * i, 2 * j + 1); + cairo_line_to (cr, 2 * i + 2, 2 * j + 1); + cairo_stroke (cr); + cairo_restore (cr); + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (a1_clip_paint, + "Test sample position when drawing trapezoids with ANTIALIAS_NONE", + "alpha, clip", /* keywords */ + "target=raster", /* requirements */ + WIDTH, HEIGHT, + NULL, paint) + +CAIRO_TEST (a1_clip_fill, + "Test sample position when drawing trapezoids with ANTIALIAS_NONE", + "alpha, clip", /* keywords */ + "target=raster", /* requirements */ + WIDTH, HEIGHT, + NULL, fill) + +CAIRO_TEST (a1_clip_fill_equal, + "Test sample position when drawing trapezoids with ANTIALIAS_NONE", + "alpha, clip", /* keywords */ + "target=raster", /* requirements */ + WIDTH, HEIGHT, + NULL, fill_equal) + +CAIRO_TEST (a1_clip_stroke, + "Test sample position when drawing trapezoids with ANTIALIAS_NONE", + "alpha, clip", /* keywords */ + "target=raster", /* requirements */ + WIDTH, HEIGHT, + NULL, stroke) diff --git a/local/recipes/libs/cairo/source/test/a1-fill.c b/local/recipes/libs/cairo/source/test/a1-fill.c new file mode 100644 index 0000000000..8c8b8c8ae0 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/a1-fill.c @@ -0,0 +1,67 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +/* Exercise https://bugs.freedesktop.org/show_bug.cgi?id=31604 */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *a1; + cairo_t *cr2; + + a1 = cairo_image_surface_create (CAIRO_FORMAT_A1, 100, 100); + cr2 = cairo_create (a1); + cairo_surface_destroy (a1); + + cairo_set_operator (cr2, CAIRO_OPERATOR_SOURCE); + cairo_rectangle (cr2, 10, 10, 80, 80); + cairo_set_source_rgb (cr2, 1, 1, 1); + cairo_fill (cr2); + cairo_rectangle (cr2, 20, 20, 60, 60); + cairo_set_source_rgb (cr2, 0, 0, 0); + cairo_fill (cr2); + + a1 = cairo_surface_reference (cairo_get_target (cr2)); + cairo_destroy (cr2); + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_mask_surface (cr, a1, 0, 0); + cairo_surface_destroy (a1); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (a1_fill, + "Test filling of an a1-surface and use as mask", + "a1, alpha, fill, mask", /* keywords */ + "target=raster", /* requirements */ + 100, 100, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/a1-image-sample.c b/local/recipes/libs/cairo/source/test/a1-image-sample.c new file mode 100644 index 0000000000..3c349af817 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/a1-image-sample.c @@ -0,0 +1,73 @@ +/* + * Copyright © 2008 Red Hat, Inc. + * + * 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: Carl D. Worth + */ + +#include "cairo-test.h" + +#define POINTS 10 +#define STEP (1.0 / POINTS) +#define PAD 1 +#define WIDTH (PAD + POINTS * 2 + PAD) +#define HEIGHT (WIDTH) + +/* A single, black pixel */ +static const uint32_t black_pixel = 0xff000000; + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + int i, j; + cairo_surface_t *surface; + + surface = cairo_image_surface_create_for_data ((unsigned char *) &black_pixel, + CAIRO_FORMAT_ARGB32, + 1, 1, 4); + + /* Fill background white */ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_translate (cr, PAD, PAD); + + for (i = 0; i < POINTS; i++) + for (j = 0; j < POINTS; j++) { + cairo_set_source_surface (cr, surface, + 2 * i + i * STEP, 2 * j + j * STEP); + cairo_pattern_set_filter (cairo_get_source (cr), + CAIRO_FILTER_NEAREST); + cairo_paint (cr); + } + + cairo_surface_destroy (surface); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (a1_image_sample, + "Test sample position when drawing images with FILTER_NEAREST", + "image, alpha", /* keywords */ + "target=raster", /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/a1-mask-sample.c b/local/recipes/libs/cairo/source/test/a1-mask-sample.c new file mode 100644 index 0000000000..4214e8f40e --- /dev/null +++ b/local/recipes/libs/cairo/source/test/a1-mask-sample.c @@ -0,0 +1,83 @@ +/* + * Copyright © 2008 Red Hat, Inc. + * Copyright © 2010 Intel Corporation + * + * 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: Carl D. Worth + * Chris Wilson + */ + +#include "cairo-test.h" + +#define POINTS 10 +#define STEP (1.0 / POINTS) +#define PAD 1 +#define WIDTH (PAD + POINTS * 2 + PAD) +#define HEIGHT (WIDTH) + +/* A single, opaque pixel */ +static const uint32_t black_pixel = 0xffffffff; + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface; + cairo_pattern_t *mask; + int i, j; + + surface = cairo_image_surface_create_for_data ((unsigned char *) &black_pixel, + CAIRO_FORMAT_A8, + 1, 1, 4); + mask = cairo_pattern_create_for_surface (surface); + cairo_pattern_set_filter (mask, CAIRO_FILTER_NEAREST); + cairo_surface_destroy (surface); + + /* Fill background white */ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_translate (cr, PAD, PAD); + + cairo_set_source_rgb (cr, 0, 0, 0); + for (i = 0; i < POINTS; i++) { + for (j = 0; j < POINTS; j++) { + cairo_matrix_t m; + + cairo_matrix_init_translate (&m, + -(2 * i + i * STEP), + -(2 * j + j * STEP)); + cairo_pattern_set_matrix (mask, &m); + cairo_mask (cr, mask); + } + } + + cairo_pattern_destroy (mask); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (a1_mask_sample, + "Test sample position when masking with FILTER_NEAREST", + "image, alpha", /* keywords */ + "target=raster", /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/a1-mask.c b/local/recipes/libs/cairo/source/test/a1-mask.c new file mode 100644 index 0000000000..c52aa9dd9f --- /dev/null +++ b/local/recipes/libs/cairo/source/test/a1-mask.c @@ -0,0 +1,202 @@ +/* + * Copyright © Jeff Muizelaar + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * JEFF MUIZELAAR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Jeff Muizelaar + * Carl Worth + * Chris Wilson + */ + +#include "cairo-test.h" + +#define MASK_WIDTH 10 +#define MASK_HEIGHT 8 + +#ifdef WORDS_BIGENDIAN +#define MASK 0x28, 0x55 +#else +#define MASK 0x14, 0xAA +#endif +static unsigned char mask[(MASK_WIDTH + 7) / 8 * MASK_HEIGHT] = { + MASK, + MASK, + MASK, + MASK, + MASK, + MASK, + MASK, + MASK, +}; + +static cairo_test_status_t +check_status (const cairo_test_context_t *ctx, + cairo_status_t status, + cairo_status_t expected) +{ + if (status == expected) + return CAIRO_TEST_SUCCESS; + + cairo_test_log (ctx, + "Error: Expected status value %d (%s), received %d (%s)\n", + expected, + cairo_status_to_string (expected), + status, + cairo_status_to_string (status)); + return CAIRO_TEST_FAILURE; +} + +static cairo_test_status_t +test_surface_with_width_and_stride (const cairo_test_context_t *ctx, + int width, int stride, + cairo_status_t expected) +{ + cairo_test_status_t status; + cairo_surface_t *surface; + cairo_t *cr; + int len; + unsigned char *data; + + cairo_test_log (ctx, + "Creating surface with width %d and stride %d\n", + width, stride); + + len = stride; + if (len < 0) + len = -len; + data = xmalloc (len); + + surface = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_A1, + width, 1, stride); + cr = cairo_create (surface); + + cairo_paint (cr); + + status = check_status (ctx, cairo_surface_status (surface), expected); + if (status) + goto BAIL; + + status = check_status (ctx, cairo_status (cr), expected); + if (status) + goto BAIL; + + BAIL: + cairo_destroy (cr); + cairo_surface_destroy (surface); + free (data); + return status; +} + +static cairo_test_status_t +draw (cairo_t *cr, int dst_width, int dst_height) +{ + unsigned char *mask_aligned; + cairo_surface_t *surface; + + surface = cairo_image_surface_create (CAIRO_FORMAT_A1, + MASK_WIDTH, + MASK_HEIGHT); + + mask_aligned = cairo_image_surface_get_data (surface); + if (mask_aligned != NULL) { + int stride = cairo_image_surface_get_stride (surface), row; + const unsigned char *src = mask; + unsigned char *dst = mask_aligned; + for (row = 0; row < MASK_HEIGHT; row++) { + memcpy (dst, src, (MASK_WIDTH + 7) / 8); + src += (MASK_WIDTH + 7) / 8; + dst += stride; + } + } + cairo_surface_mark_dirty (surface); + + /* Paint background blue */ + cairo_set_source_rgb (cr, 0, 0, 1); /* blue */ + cairo_paint (cr); + + /* Then paint red through our mask */ + cairo_set_source_rgb (cr, 1, 0, 0); /* red */ + cairo_mask_surface (cr, surface, 0, 0); + cairo_surface_destroy (surface); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + cairo_test_status_t status = CAIRO_TEST_SUCCESS; + int test_width; + + /* first check the API strictness */ + for (test_width = 0; test_width < 40; test_width++) { + int test_stride = (test_width + 7) / 8; + int stride = cairo_format_stride_for_width (CAIRO_FORMAT_A1, + test_width); + cairo_status_t expected; + + /* First create a surface using the width as the stride, + * (most of these should fail). + */ + expected = (stride == test_stride) ? + CAIRO_STATUS_SUCCESS : CAIRO_STATUS_INVALID_STRIDE; + + status = test_surface_with_width_and_stride (ctx, + test_width, + test_stride, + expected); + if (status) + return status; + + status = test_surface_with_width_and_stride (ctx, + test_width, + -test_stride, + expected); + if (status) + return status; + + + /* Then create a surface using the correct stride, + * (should always succeed). + */ + status = test_surface_with_width_and_stride (ctx, + test_width, + stride, + CAIRO_STATUS_SUCCESS); + if (status) + return status; + + status = test_surface_with_width_and_stride (ctx, + test_width, + -stride, + CAIRO_STATUS_SUCCESS); + if (status) + return status; + } + + return status; +} + +CAIRO_TEST (a1_mask, + "test masks of CAIRO_FORMAT_A1", + "alpha, mask", /* keywords */ + NULL, /* requirements */ + MASK_WIDTH, MASK_HEIGHT, + preamble, draw) diff --git a/local/recipes/libs/cairo/source/test/a1-rasterisation.c b/local/recipes/libs/cairo/source/test/a1-rasterisation.c new file mode 100644 index 0000000000..b59090ab5e --- /dev/null +++ b/local/recipes/libs/cairo/source/test/a1-rasterisation.c @@ -0,0 +1,101 @@ +/* + * Copyright 2010 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +/* + * Test the fidelity of the rasterisation, paying careful attention to rounding. + */ + +#include "../src/cairo-fixed-type-private.h" +#define PRECISION (int)(1 << CAIRO_FIXED_FRAC_BITS) + +#define WIDTH ((PRECISION/2+1)*3) +#define HEIGHT ((PRECISION/2+1)*3) + +#define SUBPIXEL(v) ((v)/(double)(PRECISION/2)) + +static cairo_test_status_t +rectangles (cairo_t *cr, int width, int height) +{ + int x, y; + + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); + + for (x = 0; x < WIDTH; x += 3) { + for (y = 0; y < HEIGHT; y += 3) { + cairo_rectangle (cr, x + SUBPIXEL (y/3) - .5, y + SUBPIXEL (x/3) - .5, .5, .5); + } + } + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +triangles (cairo_t *cr, int width, int height) +{ + int x, y; + + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); + + for (x = 0; x < WIDTH; x += 3) { + for (y = 0; y < HEIGHT; y += 3) { + /* a rectangle with a diagonal to force tessellation */ + cairo_move_to (cr, x + SUBPIXEL (y/3) - .5, y + SUBPIXEL (x/3) - .5); + cairo_rel_line_to (cr, .5, .5); + cairo_rel_line_to (cr, 0, -.5); + cairo_rel_line_to (cr, -.5, 0); + cairo_rel_line_to (cr, 0, .5); + cairo_rel_line_to (cr, .5, 0); + } + } + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (a1_rasterisation_rectangles, + "Check the fidelity of the rasterisation.", + "rasterisation", /* keywords */ + "target=raster", /* requirements */ + WIDTH, HEIGHT, + NULL, rectangles) + +CAIRO_TEST (a1_rasterisation_triangles, + "Check the fidelity of the rasterisation.", + "rasterisation", /* keywords */ + "target=raster", /* requirements */ + WIDTH, HEIGHT, + NULL, triangles) diff --git a/local/recipes/libs/cairo/source/test/a1-sample.c b/local/recipes/libs/cairo/source/test/a1-sample.c new file mode 100644 index 0000000000..977dfc832f --- /dev/null +++ b/local/recipes/libs/cairo/source/test/a1-sample.c @@ -0,0 +1,59 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +#define WIDTH (256) //CAIRO_FIXED_ONE +#define HEIGHT (WIDTH) + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + int i, j; + + /* Fill background white */ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); + cairo_set_source_rgb (cr, 0, 0, 0); + + /* Only the single rectangle that covers the centre pixel should be filled*/ + for (i = 0; i < 256; i++) + for (j = 0; j < 256; j++) { + cairo_rectangle (cr, i + i/256., j + j/256., 1/256., 1/256.); + cairo_fill (cr); + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (a1_sample, + "Tests unantialiased rendering of a quantum box", + " alpha", /* keywords */ + "target=raster", /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/a1-traps-sample.c b/local/recipes/libs/cairo/source/test/a1-traps-sample.c new file mode 100644 index 0000000000..5bb97bb4ca --- /dev/null +++ b/local/recipes/libs/cairo/source/test/a1-traps-sample.c @@ -0,0 +1,64 @@ +/* + * Copyright © 2008 Red Hat, Inc. + * + * 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: Carl D. Worth + */ + +#include "cairo-test.h" + +#define POINTS 10 +#define STEP (1.0 / POINTS) +#define PAD 1 +#define WIDTH (PAD + POINTS * 2 + PAD) +#define HEIGHT (WIDTH) + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + int i, j; + + /* Fill background white */ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + /* Draw in black */ + cairo_set_source_rgb (cr, 0, 0, 0); + + cairo_translate (cr, PAD, PAD); + cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); + + for (i = 0; i < POINTS; i++) + for (j = 0; j < POINTS; j++) { + cairo_rectangle (cr, 2 * i + i * STEP, 2 * j + j * STEP, 1, 1); + cairo_fill (cr); + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (a1_traps_sample, + "Test sample position when drawing trapezoids with ANTIALIAS_NONE", + "alpha, traps", /* keywords */ + "target=raster", /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/a8-clear.c b/local/recipes/libs/cairo/source/test/a8-clear.c new file mode 100644 index 0000000000..1459f833e2 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/a8-clear.c @@ -0,0 +1,64 @@ +/* + * Copyright © 2010 Intel Corporation + * + * 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: Chris Wilson + * + * Based on a bug snippet by Jeremy Moles + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *mask; + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_paint (cr); + + cairo_push_group_with_content (cr, CAIRO_CONTENT_ALPHA); + { + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_move_to (cr, 0, 0); + cairo_line_to (cr, width, height); + cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); + cairo_set_line_width (cr, 10); + cairo_stroke (cr); + } + mask = cairo_pop_group (cr); + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_mask (cr, mask); + cairo_pattern_destroy (mask); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (a8_clear, + "Test clear on an a8 surface", + "a8, clear", /* keywords */ + NULL, /* requirements */ + 40, 40, + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/a8-mask.c b/local/recipes/libs/cairo/source/test/a8-mask.c new file mode 100644 index 0000000000..ec708121ea --- /dev/null +++ b/local/recipes/libs/cairo/source/test/a8-mask.c @@ -0,0 +1,201 @@ +/* + * Copyright © Jeff Muizelaar + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * JEFF MUIZELAAR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Jeff Muizelaar + * Carl Worth + */ + +#include "cairo-test.h" + +#define MASK_WIDTH 8 +#define MASK_HEIGHT 8 + +static unsigned char mask[MASK_WIDTH * MASK_HEIGHT] = { + 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, + 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, +}; + +static cairo_test_status_t +check_status (const cairo_test_context_t *ctx, + cairo_status_t status, + cairo_status_t expected) +{ + if (status == expected) + return CAIRO_TEST_SUCCESS; + + cairo_test_log (ctx, + "Error: Expected status value %d (%s), received %d (%s)\n", + expected, + cairo_status_to_string (expected), + status, + cairo_status_to_string (status)); + return CAIRO_TEST_FAILURE; +} + +static cairo_test_status_t +test_surface_with_width_and_stride (const cairo_test_context_t *ctx, + int width, int stride, + cairo_status_t expected) +{ + cairo_test_status_t status; + cairo_surface_t *surface; + cairo_t *cr; + int len; + unsigned char *data; + + cairo_test_log (ctx, + "Creating surface with width %d and stride %d\n", + width, stride); + + len = stride; + if (len < 0) + len = -len; + data = xmalloc (len); + + surface = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_A8, + width, 1, stride); + cr = cairo_create (surface); + + cairo_paint (cr); + + status = check_status (ctx, cairo_surface_status (surface), expected); + if (status) + goto BAIL; + + status = check_status (ctx, cairo_status (cr), expected); + if (status) + goto BAIL; + + BAIL: + cairo_destroy (cr); + cairo_surface_destroy (surface); + free (data); + return status; +} + +static cairo_test_status_t +draw (cairo_t *cr, int dst_width, int dst_height) +{ + int stride, row; + unsigned char *src, *dst, *mask_aligned; + cairo_surface_t *surface; + + /* Now test actually drawing through our mask data, allocating and + * copying with the proper stride. */ + stride = cairo_format_stride_for_width (CAIRO_FORMAT_A8, + MASK_WIDTH); + + mask_aligned = xmalloc (stride * MASK_HEIGHT); + + src = mask; + dst = mask_aligned; + for (row = 0; row < MASK_HEIGHT; row++) { + memcpy (dst, src, MASK_WIDTH); + src += MASK_WIDTH; + dst += stride; + } + + surface = cairo_image_surface_create_for_data (mask_aligned, + CAIRO_FORMAT_A8, + MASK_WIDTH, + MASK_HEIGHT, + stride); + + /* Paint background blue */ + cairo_set_source_rgb (cr, 0, 0, 1); /* blue */ + cairo_paint (cr); + + /* Then paint red through our mask */ + cairo_set_source_rgb (cr, 1, 0, 0); /* red */ + cairo_mask_surface (cr, surface, 0, 0); + cairo_surface_destroy (surface); + + free (mask_aligned); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + cairo_test_status_t status = CAIRO_TEST_SUCCESS; + int test_width; + + for (test_width = 0; test_width < 40; test_width++) { + int stride = cairo_format_stride_for_width (CAIRO_FORMAT_A8, + test_width); + cairo_status_t expected; + + /* First create a surface using the width as the stride, + * (most of these should fail). + */ + expected = (stride == test_width) ? + CAIRO_STATUS_SUCCESS : CAIRO_STATUS_INVALID_STRIDE; + + status = test_surface_with_width_and_stride (ctx, + test_width, + test_width, + expected); + if (status) + return status; + + status = test_surface_with_width_and_stride (ctx, + test_width, + -test_width, + expected); + if (status) + return status; + + + /* Then create a surface using the correct stride, + * (should always succeed). + */ + status = test_surface_with_width_and_stride (ctx, + test_width, + stride, + CAIRO_STATUS_SUCCESS); + if (status) + return status; + + status = test_surface_with_width_and_stride (ctx, + test_width, + -stride, + CAIRO_STATUS_SUCCESS); + if (status) + return status; + } + + return status; +} + +CAIRO_TEST (a8_mask, + "test masks of CAIRO_FORMAT_A8", + "alpha, mask", /* keywords */ + NULL, /* requirements */ + 8, 8, + preamble, draw) diff --git a/local/recipes/libs/cairo/source/test/aliasing.c b/local/recipes/libs/cairo/source/test/aliasing.c new file mode 100644 index 0000000000..73c1f1ae28 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/aliasing.c @@ -0,0 +1,100 @@ +/* + * Copyright 2010 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +/* A fun little test to explore color fringing in various experimental + * subpixel rasterisation techniques. + */ + +#define WIDTH 60 +#define HEIGHT 40 + +static const struct color { + double red, green, blue; +} color[] = { + { 1, 1, 1 }, + { 0, 0, 0 }, + { 1, 0, 0 }, + { 0, 1, 0 }, + { 0, 0, 1 }, + { 1, 1, 0 }, + { 0, 1, 1 }, + { 1, 0, 1 }, + { .5, .5, .5 }, +}; + +#define NUM_COLORS ARRAY_LENGTH (color) + +static void +object (cairo_t *cr, const struct color *fg, const struct color *bg) +{ + cairo_set_source_rgb (cr, bg->red, bg->green, bg->blue); + cairo_rectangle (cr, 0, 0, WIDTH, HEIGHT); + cairo_fill (cr); + + cairo_set_source_rgb (cr, fg->red, fg->green, fg->blue); + cairo_save (cr); + cairo_scale (cr, WIDTH, HEIGHT); + cairo_arc (cr, .5, .5, .5 - 4. / MAX (WIDTH, HEIGHT), 0, 2 * M_PI); + cairo_fill (cr); + cairo_arc (cr, .5, .5, .5 - 2. / MAX (WIDTH, HEIGHT), 0, 2 * M_PI); + cairo_restore (cr); + cairo_set_line_width (cr, 1.); + cairo_stroke (cr); + + cairo_set_source_rgb (cr, bg->red, bg->green, bg->blue); + cairo_set_line_width (cr, 4.); + cairo_move_to (cr, 4, HEIGHT-4); + cairo_line_to (cr, WIDTH-12, 4); + cairo_move_to (cr, 12, HEIGHT-4); + cairo_line_to (cr, WIDTH-4, 4); + cairo_stroke (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + unsigned int i, j; + + for (i = 0; i < NUM_COLORS; i++) { + for (j = 0; j < NUM_COLORS; j++) { + cairo_save (cr); + cairo_translate (cr, i * WIDTH, j * HEIGHT); + object (cr, &color[i], &color[j]); + cairo_restore (cr); + } + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (aliasing, + "Check for subpixel aliasing and color fringing", + "rasterisation", /* keywords */ + "target=raster", /* requirements */ + NUM_COLORS * WIDTH, NUM_COLORS * HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/alpha-similar.c b/local/recipes/libs/cairo/source/test/alpha-similar.c new file mode 100644 index 0000000000..86c6ae39db --- /dev/null +++ b/local/recipes/libs/cairo/source/test/alpha-similar.c @@ -0,0 +1,74 @@ +/* + * Copyright 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_surface_t * +create_source (cairo_surface_t *target, int width, int height) +{ + cairo_surface_t *similar; + cairo_t *cr; + + similar = cairo_surface_create_similar (target, + CAIRO_CONTENT_ALPHA, + width, height); + cr = cairo_create (similar); + cairo_surface_destroy (similar); + + cairo_set_source_rgba (cr, 1, 0, 0, .5); + cairo_paint (cr); + + similar = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + + return similar; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *source; + + source = create_source (cairo_get_target (cr), width, height); + cairo_set_source_surface (cr, source, 0, 0); + cairo_surface_destroy (source); + + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +/* + * XFAIL: discrepancy between backends in applying color components of a pure + * alpha surface + */ +CAIRO_TEST (alpha_similar, + "Tests creation of similar alpha surfaces" + "\nApplication of a pure-alpha similar source is inconsistent across backends.", + "alpha, similar", /* keywords */ + NULL, /* requirements */ + 10, 10, + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/any2ppm.c b/local/recipes/libs/cairo/source/test/any2ppm.c new file mode 100644 index 0000000000..f601ec8359 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/any2ppm.c @@ -0,0 +1,900 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + * + * Contributor(s): + * Carlos Garcia Campos + * + * Adapted from pdf2png.c: + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Kristian Høgsberg + */ + +#include "config.h" + +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#include + +#include + +#if CAIRO_HAS_INTERPRETER +#include +#endif + +#if CAIRO_CAN_TEST_PDF_SURFACE +#include +#endif + +#if CAIRO_CAN_TEST_SVG_SURFACE +#define RSVG_DISABLE_DEPRECATION_WARNINGS +#include +#ifndef RSVG_CAIRO_H +#include +#endif +#endif + +#if CAIRO_HAS_SPECTRE +#include +#endif + +#include + +#if HAVE_FCNTL_H +#include +#endif + +#if HAVE_UNISTD_H && HAVE_SIGNAL_H && HAVE_SYS_STAT_H && HAVE_SYS_SOCKET_H && (HAVE_POLL_H || HAVE_SYS_POLL_H) && HAVE_SYS_UN_H +#include +#include +#include +#include + +#if defined(HAVE_POLL_H) +#include +#elif defined(HAVE_SYS_POLL_H) +#include +#endif + +#define SOCKET_PATH "./.any2ppm" +#define TIMEOUT 60000 /* 60 seconds */ + +#if HAVE_FORK +#define CAN_RUN_AS_DAEMON 1 +#endif +#endif + +#define ARRAY_LENGTH(__array) ((int) (sizeof (__array) / sizeof (__array[0]))) + +static int +_cairo_writen (int fd, char *buf, int len) +{ + while (len) { + int ret; + + ret = write (fd, buf, len); + if (ret == -1) { + int err = errno; + switch (err) { + case EINTR: + case EAGAIN: + continue; + default: + return 0; + } + } + len -= ret; + buf += ret; + } + + return 1; +} + +static int +_cairo_write (int fd, + char *buf, int maxlen, int buflen, + const unsigned char *src, int srclen) +{ + if (buflen < 0) + return buflen; + + while (srclen) { + int len; + + len = buflen + srclen; + if (len > maxlen) + len = maxlen; + len -= buflen; + + memcpy (buf + buflen, src, len); + buflen += len; + srclen -= len; + src += len; + + if (buflen == maxlen) { + if (! _cairo_writen (fd, buf, buflen)) + return -1; + + buflen = 0; + } + } + + return buflen; +} + +static const char * +write_ppm (cairo_surface_t *surface, int fd) +{ + char buf[4096]; + cairo_format_t format; + const char *format_str; + const unsigned char *data; + int len; + int width, height, stride; + int i, j; + + data = cairo_image_surface_get_data (surface); + height = cairo_image_surface_get_height (surface); + width = cairo_image_surface_get_width (surface); + stride = cairo_image_surface_get_stride (surface); + format = cairo_image_surface_get_format (surface); + if (format == CAIRO_FORMAT_ARGB32) { + /* see if we can convert to a standard ppm type and trim a few bytes */ + const unsigned char *alpha = data; + for (j = height; j--; alpha += stride) { + for (i = 0; i < width; i++) { + if ((*(unsigned int *) (alpha+4*i) & 0xff000000) != 0xff000000) + goto done; + } + } + format = CAIRO_FORMAT_RGB24; + done: ; + } + + switch (format) { + case CAIRO_FORMAT_ARGB32: + /* XXX need true alpha for svg */ + format_str = "P7"; + break; + case CAIRO_FORMAT_RGB24: + format_str = "P6"; + break; + case CAIRO_FORMAT_A8: + format_str = "P5"; + break; + case CAIRO_FORMAT_A1: + case CAIRO_FORMAT_RGB16_565: + case CAIRO_FORMAT_RGB30: + case CAIRO_FORMAT_RGB96F: + case CAIRO_FORMAT_RGBA128F: + case CAIRO_FORMAT_INVALID: + default: + return "unhandled image format"; + } + + len = sprintf (buf, "%s %d %d 255\n", format_str, width, height); + for (j = 0; j < height; j++) { + const unsigned int *row = (unsigned int *) (data + stride * j); + + switch ((int) format) { + case CAIRO_FORMAT_ARGB32: + len = _cairo_write (fd, + buf, sizeof (buf), len, + (unsigned char *) row, 4 * width); + break; + case CAIRO_FORMAT_RGB24: + for (i = 0; i < width; i++) { + unsigned char rgb[3]; + unsigned int p = *row++; + rgb[0] = (p & 0xff0000) >> 16; + rgb[1] = (p & 0x00ff00) >> 8; + rgb[2] = (p & 0x0000ff) >> 0; + len = _cairo_write (fd, + buf, sizeof (buf), len, + rgb, 3); + } + break; + case CAIRO_FORMAT_A8: + len = _cairo_write (fd, + buf, sizeof (buf), len, + (unsigned char *) row, width); + break; + } + if (len < 0) + return "write failed"; + } + + if (len && ! _cairo_writen (fd, buf, len)) + return "write failed"; + + return NULL; +} + +#if CAIRO_HAS_INTERPRETER +static cairo_surface_t * +_create_image (void *closure, + cairo_content_t content, + double width, double height, + long uid) +{ + cairo_surface_t **out = closure; + cairo_format_t format; + switch (content) { + case CAIRO_CONTENT_ALPHA: + format = CAIRO_FORMAT_A8; + break; + case CAIRO_CONTENT_COLOR: + format = CAIRO_FORMAT_RGB24; + break; + default: + case CAIRO_CONTENT_COLOR_ALPHA: + format = CAIRO_FORMAT_ARGB32; + break; + } + *out = cairo_image_surface_create (format, width, height); + return cairo_surface_reference (*out); +} + +static const char * +_cairo_script_render_page (const char *filename, + cairo_surface_t **surface_out) +{ + cairo_script_interpreter_t *csi; + cairo_surface_t *surface = NULL; + cairo_status_t status; + const cairo_script_interpreter_hooks_t hooks = { + &surface, + _create_image, + NULL, /* surface_destroy */ + NULL, /* context_create */ + NULL, /* context_destroy */ + NULL, /* show_page */ + NULL /* copy_page */ + }; + + csi = cairo_script_interpreter_create (); + cairo_script_interpreter_install_hooks (csi, &hooks); + status = cairo_script_interpreter_run (csi, filename); + if (status) { + cairo_surface_destroy (surface); + surface = NULL; + } + status = cairo_script_interpreter_destroy (csi); + if (surface == NULL) + return "cairo-script interpreter failed"; + + if (status == CAIRO_STATUS_SUCCESS) + status = cairo_surface_status (surface); + if (status) { + cairo_surface_destroy (surface); + return cairo_status_to_string (status); + } + + *surface_out = surface; + return NULL; +} + +static const char * +cs_convert (char **argv, int fd) +{ + const char *err; + cairo_surface_t *surface = NULL; /* silence compiler warning */ + + err = _cairo_script_render_page (argv[0], &surface); + if (err != NULL) + return err; + + err = write_ppm (surface, fd); + cairo_surface_destroy (surface); + + return err; +} +#else +static const char * +cs_convert (char **argv, int fd) +{ + return "compiled without CairoScript support."; +} +#endif + +#if CAIRO_CAN_TEST_PDF_SURFACE +/* adapted from pdf2png.c */ +static const char * +_poppler_render_page (const char *filename, + const char *page_label, + cairo_surface_t **surface_out) +{ + PopplerDocument *document; + PopplerPage *page; + double width, height; + GError *error = NULL; + gchar *absolute, *uri; + cairo_surface_t *surface; + cairo_t *cr; + cairo_status_t status; + + if (g_path_is_absolute (filename)) { + absolute = g_strdup (filename); + } else { + gchar *dir = g_get_current_dir (); + absolute = g_build_filename (dir, filename, (gchar *) 0); + g_free (dir); + } + + uri = g_filename_to_uri (absolute, NULL, &error); + g_free (absolute); + if (uri == NULL) + return error->message; /* XXX g_error_free (error) */ + + document = poppler_document_new_from_file (uri, NULL, &error); + g_free (uri); + if (document == NULL) + return error->message; /* XXX g_error_free (error) */ + + page = poppler_document_get_page_by_label (document, page_label); + g_object_unref (document); + if (page == NULL) + return "page not found"; + + poppler_page_get_size (page, &width, &height); + + surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height); + cr = cairo_create (surface); + + cairo_set_source_rgb (cr, 1., 1., 1.); + cairo_paint (cr); + cairo_push_group_with_content (cr, CAIRO_CONTENT_COLOR_ALPHA); + + poppler_page_render (page, cr); + g_object_unref (page); + + cairo_pop_group_to_source (cr); + cairo_paint (cr); + + status = cairo_status (cr); + cairo_destroy (cr); + + if (status) { + cairo_surface_destroy (surface); + return cairo_status_to_string (status); + } + + *surface_out = surface; + return NULL; +} + +static const char * +pdf_convert (char **argv, int fd) +{ + const char *err; + cairo_surface_t *surface = NULL; /* silence compiler warning */ + + err = _poppler_render_page (argv[0], argv[1], &surface); + if (err != NULL) + return err; + + err = write_ppm (surface, fd); + cairo_surface_destroy (surface); + + return err; +} +#else +static const char * +pdf_convert (char **argv, int fd) +{ + return "compiled without PDF support."; +} +#endif + +#if CAIRO_CAN_TEST_SVG_SURFACE +static const char * +_rsvg_render_page (const char *filename, + cairo_surface_t **surface_out) +{ + RsvgHandle *handle; + RsvgDimensionData dimensions; + GError *error = NULL; + cairo_surface_t *surface; + cairo_t *cr; + cairo_status_t status; + + handle = rsvg_handle_new_from_file (filename, &error); + if (handle == NULL) + return error->message; /* XXX g_error_free */ + + rsvg_handle_set_dpi (handle, 72.0); + rsvg_handle_get_dimensions (handle, &dimensions); + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + dimensions.width, + dimensions.height); + cr = cairo_create (surface); + + rsvg_handle_render_cairo (handle, cr); + g_object_unref (handle); + + status = cairo_status (cr); + cairo_destroy (cr); + + if (status) { + cairo_surface_destroy (surface); + return cairo_status_to_string (status); + } + + *surface_out = surface; + return NULL; +} + +static const char * +svg_convert (char **argv, int fd) +{ + const char *err; + cairo_surface_t *surface = NULL; /* silence compiler warning */ + + err = _rsvg_render_page (argv[0], &surface); + if (err != NULL) + return err; + + err = write_ppm (surface, fd); + cairo_surface_destroy (surface); + + return err; +} +#else +static const char * +svg_convert (char **argv, int fd) +{ + return "compiled without SVG support."; +} +#endif + +#if CAIRO_HAS_SPECTRE +static const char * +_spectre_render_page (const char *filename, + const char *page_label, + cairo_surface_t **surface_out) +{ + static const cairo_user_data_key_t key; + + SpectreDocument *document; + SpectreStatus status; + int width, height, stride; + unsigned char *pixels; + cairo_surface_t *surface; + + document = spectre_document_new (); + spectre_document_load (document, filename); + status = spectre_document_status (document); + if (status) { + spectre_document_free (document); + return spectre_status_to_string (status); + } + + if (page_label) { + SpectrePage *page; + SpectreRenderContext *rc; + + page = spectre_document_get_page_by_label (document, page_label); + spectre_document_free (document); + if (page == NULL) + return "page not found"; + + spectre_page_get_size (page, &width, &height); + rc = spectre_render_context_new (); + spectre_render_context_set_page_size (rc, width, height); + spectre_page_render (page, rc, &pixels, &stride); + spectre_render_context_free (rc); + status = spectre_page_status (page); + spectre_page_free (page); + if (status) { + free (pixels); + return spectre_status_to_string (status); + } + } else { + spectre_document_get_page_size (document, &width, &height); + spectre_document_render (document, &pixels, &stride); + spectre_document_free (document); + } + + surface = cairo_image_surface_create_for_data (pixels, + CAIRO_FORMAT_RGB24, + width, height, + stride); + cairo_surface_set_user_data (surface, &key, + pixels, (cairo_destroy_func_t) free); + *surface_out = surface; + return NULL; +} + +static const char * +ps_convert (char **argv, int fd) +{ + const char *err; + cairo_surface_t *surface = NULL; /* silence compiler warning */ + + err = _spectre_render_page (argv[0], argv[1], &surface); + if (err != NULL) + return err; + + err = write_ppm (surface, fd); + cairo_surface_destroy (surface); + + return err; +} +#else +static const char * +ps_convert (char **argv, int fd) +{ + return "compiled without PostScript support."; +} +#endif + +static const char * +convert (char **argv, int fd) +{ + static const struct converter { + const char *type; + const char *(*func) (char **, int); + } converters[] = { + { "cs", cs_convert }, + { "pdf", pdf_convert }, + { "ps", ps_convert }, + { "svg", svg_convert }, + { NULL, NULL } + }; + const struct converter *converter = converters; + char *type; + + type = strrchr (argv[0], '.'); + if (type == NULL) + return "no file extension"; + type++; + + while (converter->type) { + if (strcmp (type, converter->type) == 0) + return converter->func (argv, fd); + converter++; + } + return "no converter"; +} + +#if CAN_RUN_AS_DAEMON +static int +_getline (int fd, char **linep, size_t *lenp) +{ + char *line; + size_t len, i; + ssize_t ret; + + line = *linep; + if (line == NULL) { + line = malloc (1024); + if (line == NULL) + return -1; + line[0] = '\0'; + len = 1024; + } else + len = *lenp; + + /* XXX simple, but ugly! */ + i = 0; + do { + if (i == len - 1) { + char *nline; + + nline = realloc (line, len + 1024); + if (nline == NULL) + goto out; + + line = nline; + len += 1024; + } + + ret = read (fd, line + i, 1); + if (ret == -1 || ret == 0) + goto out; + } while (line[i++] != '\n'); + +out: + line[i] = '\0'; + *linep = line; + *lenp = len; + return i-1; +} + +static int +split_line (char *line, char *argv[], int max_argc) +{ + int i = 0; + + max_argc--; /* leave one spare for the trailing NULL */ + + argv[i++] = line; + while (i < max_argc && (line = strchr (line, ' ')) != NULL) { + *line++ = '\0'; + argv[i++] = line; + } + + /* chomp the newline */ + line = strchr (argv[i-1], '\n'); + if (line != NULL) + *line = '\0'; + + argv[i] = NULL; + + return i; +} + +static int +any2ppm_daemon_exists (void) +{ + struct stat st; + int fd; + char buf[80]; + int pid; + int ret; + + if (stat (SOCKET_PATH, &st) < 0) + return 0; + + fd = open (SOCKET_PATH ".pid", O_RDONLY); + if (fd < 0) + return 0; + + pid = 0; + ret = read (fd, buf, sizeof (buf) - 1); + if (ret > 0) { + buf[ret] = '\0'; + pid = atoi (buf); + } + close (fd); + + return pid > 0 && kill (pid, 0) == 0; +} + +static int +write_pid_file (void) +{ + int fd; + char buf[80]; + int ret; + + fd = open (SOCKET_PATH ".pid", O_CREAT | O_TRUNC | O_WRONLY, 0666); + if (fd < 0) + return 0; + + ret = sprintf (buf, "%d\n", getpid ()); + ret = write (fd, buf, ret) == ret; + close (fd); + + return ret; +} + +static int +open_devnull_to_fd (int want_fd, int flags) +{ + int error; + int got_fd; + + close (want_fd); + + got_fd = open("/dev/null", flags | O_CREAT, 0700); + if (got_fd == -1) + return -1; + + error = dup2 (got_fd, want_fd); + close (got_fd); + + return error; +} + +static int +daemonize (void) +{ + void (*oldhup) (int); + + /* Let the parent go. */ + switch (fork ()) { + case -1: return -1; + case 0: break; + default: _exit (0); + } + + /* Become session leader. */ + if (setsid () == -1) + return -1; + + /* Refork to yield session leadership. */ + oldhup = signal (SIGHUP, SIG_IGN); + + switch (fork ()) { /* refork to yield session leadership. */ + case -1: return -1; + case 0: break; + default: _exit (0); + } + + signal (SIGHUP, oldhup); + + /* Establish stdio. */ + if (open_devnull_to_fd (0, O_RDONLY) == -1) + return -1; + if (open_devnull_to_fd (1, O_WRONLY | O_APPEND) == -1) + return -1; + if (dup2 (1, 2) == -1) + return -1; + + return 0; +} + +static const char * +any2ppm_daemon (void) +{ + int timeout = TIMEOUT; + struct pollfd pfd; + int sk, fd; + long flags; + struct sockaddr_un addr; + char *line = NULL; + size_t len = 0; + +#ifdef SIGPIPE + signal (SIGPIPE, SIG_IGN); +#endif + + /* XXX racy! */ + if (getenv ("ANY2PPM_FORCE") == NULL && any2ppm_daemon_exists ()) + return "any2ppm daemon already running"; + + unlink (SOCKET_PATH); + + sk = socket (PF_UNIX, SOCK_STREAM, 0); + if (sk == -1) + return "unable to create socket"; + + memset (&addr, 0, sizeof (addr)); + addr.sun_family = AF_UNIX; + strcpy (addr.sun_path, SOCKET_PATH); + if (bind (sk, (struct sockaddr *) &addr, sizeof (addr)) == -1) { + close (sk); + return "unable to bind socket"; + } + + flags = fcntl (sk, F_GETFL); + if (flags == -1 || fcntl (sk, F_SETFL, flags | O_NONBLOCK) == -1) { + close (sk); + return "unable to set socket to non-blocking"; + } + + if (listen (sk, 5) == -1) { + close (sk); + return "unable to listen on socket"; + } + + /* ready for client connection - detach from parent/terminal */ + if (getenv ("ANY2PPM_NODAEMON") == NULL && daemonize () == -1) { + close (sk); + return "unable to detach from parent"; + } + + if (! write_pid_file ()) { + close (sk); + return "unable to write pid file"; + } + + if (getenv ("ANY2PPM_TIMEOUT") != NULL) { + timeout = atoi (getenv ("ANY2PPM_TIMEOUT")); + if (timeout == 0) + timeout = -1; + if (timeout > 0) + timeout *= 1000; /* convert env (in seconds) to milliseconds */ + } + + pfd.fd = sk; + pfd.events = POLLIN; + pfd.revents = 0; /* valgrind */ + while (poll (&pfd, 1, timeout) > 0) { + while ((fd = accept (sk, NULL, NULL)) != -1) { + if (_getline (fd, &line, &len) != -1) { + char *argv[10]; + + if (split_line (line, argv, ARRAY_LENGTH (argv)) > 0) { + const char *err; + + err = convert (argv, fd); + if (err != NULL) { + FILE *file = fopen (".any2ppm.errors", "a"); + if (file != NULL) { + fprintf (file, + "Failed to convert '%s': %s\n", + argv[0], err); + fclose (file); + } + } + } + } + close (fd); + } + } + close (sk); + unlink (SOCKET_PATH); + unlink (SOCKET_PATH ".pid"); + + free (line); + return NULL; +} +#else +static const char * +any2ppm_daemon (void) +{ + return "daemon not compiled in."; +} +#endif + +int +main (int argc, char **argv) +{ + const char *err; + +#if CAIRO_CAN_TEST_PDF_SURFACE || CAIRO_CAN_TEST_SVG_SURFACE +#if GLIB_MAJOR_VERSION <= 2 && GLIB_MINOR_VERSION <= 34 + g_type_init (); +#endif +#endif + +#if defined(_WIN32) && !defined (__CYGWIN__) + _setmode (1, _O_BINARY); +#endif + + if (argc == 1) + err = any2ppm_daemon (); + else + err = convert (argv + 1, 1); + if (err != NULL) { + fprintf (stderr, "Failed to run converter: %s\n", err); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/local/recipes/libs/cairo/source/test/api-special-cases.c b/local/recipes/libs/cairo/source/test/api-special-cases.c new file mode 100644 index 0000000000..d926aa6520 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/api-special-cases.c @@ -0,0 +1,1943 @@ +/* + * Copyright © 2010 Red Hat Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Benjamin Otte + */ + +/* + * WHAT THIS TEST DOES + * + * This test tests that for all public APIs Cairo behaves correct, consistent + * and most of all doesn't crash. It does this by calling all APIs that take + * surfaces or contexts and calling them on specially prepared arguments that + * should fail when called on this function. + * + * ADDING NEW FUNCTIONS + * + * You need (for adding the function cairo_surface_foo): + * 1) A surface_test_func_t named test_cairo_surface_foo that gets passed the + * prepared surface and has the job of calling the function and checking + * the return value (if one exists) for correctness. The top of this file + * contains all these shim functions. + * 2) Knowledge if the function behaves like a setter or like a getter. A + * setter should set an error status on the surface, a getter does not + * modify the function. + * 3) Knowledge if the function only works for a specific surface type and for + * which one. + * 4) An entry in the tests array using the TEST() macro. It takes as arguments: + * - The function name + * - TRUE if the function modifies the surface, FALSE otherwise + * - the surface type for which the function is valid or -1 if it is valid + * for all surface types. + * + * FIXING FAILURES + * + * The test will dump failures notices into the api-special-cases.log file (when + * it doesn't crash). These should be pretty self-explanatory. Usually it is + * enough to just add a new check to the function it complained about. + */ + +#include "config.h" + +#include +#include + +#include "cairo-test.h" + +#if CAIRO_HAS_PDF_SURFACE +#include +#endif +#if CAIRO_HAS_PS_SURFACE +#include +#endif +#if CAIRO_HAS_QUARTZ_SURFACE +#define Cursor QuartzCursor +#include +#undef Cursor +#endif +#if CAIRO_HAS_SVG_SURFACE +#include +#endif +#if CAIRO_HAS_TEE_SURFACE +#include +#endif +#if CAIRO_HAS_XCB_SURFACE +#include +#endif +#if CAIRO_HAS_XLIB_SURFACE +#define Cursor XCursor +#include +#undef Cursor +#endif + +#define surface_has_type(surface,type) (cairo_surface_get_type (surface) == (type)) + +typedef cairo_test_status_t (* surface_test_func_t) (cairo_surface_t *surface); +typedef cairo_test_status_t (* context_test_func_t) (cairo_t *cr); + +static cairo_test_status_t +test_cairo_reference (cairo_t *cr) +{ + cairo_destroy (cairo_reference (cr)); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_get_reference_count (cairo_t *cr) +{ + unsigned int refcount = cairo_get_reference_count (cr); + if (refcount > 0) + return CAIRO_TEST_SUCCESS; + /* inert error context have a refcount of 0 */ + return cairo_status (cr) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR; +} + +static cairo_test_status_t +test_cairo_set_user_data (cairo_t *cr) +{ + static cairo_user_data_key_t key; + cairo_status_t status; + + status = cairo_set_user_data (cr, &key, &key, NULL); + if (status == CAIRO_STATUS_NO_MEMORY) + return CAIRO_TEST_NO_MEMORY; + else if (status) + return CAIRO_TEST_SUCCESS; + + if (cairo_get_user_data (cr, &key) != &key) + return CAIRO_TEST_ERROR; + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_save (cairo_t *cr) +{ + cairo_save (cr); + cairo_restore (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_push_group (cairo_t *cr) +{ + cairo_pattern_t *pattern; + cairo_status_t status; + + cairo_push_group (cr); + pattern = cairo_pop_group (cr); + status = cairo_pattern_status (pattern); + cairo_pattern_destroy (pattern); + + return status == CAIRO_STATUS_SUCCESS || status == cairo_status (cr) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR; +} + +static cairo_test_status_t +test_cairo_push_group_with_content (cairo_t *cr) +{ + cairo_push_group_with_content (cr, CAIRO_CONTENT_COLOR_ALPHA); + cairo_pop_group_to_source (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_set_operator (cairo_t *cr) +{ + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_set_source (cairo_t *cr) +{ + cairo_pattern_t *source = cairo_pattern_create_rgb (0, 0, 0); + cairo_set_source (cr, source); + cairo_pattern_destroy (source); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_set_source_rgb (cairo_t *cr) +{ + cairo_set_source_rgb (cr, 0, 0, 0); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_set_source_rgba (cairo_t *cr) +{ + cairo_set_source_rgba (cr, 0, 0, 0, 1); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_set_source_surface (cairo_t *cr) +{ + cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1); + cairo_set_source_surface (cr, surface, 0, 0); + cairo_surface_destroy (surface); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_set_tolerance (cairo_t *cr) +{ + cairo_set_tolerance (cr, 42); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_set_antialias (cairo_t *cr) +{ + cairo_set_antialias (cr, CAIRO_ANTIALIAS_BEST); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_set_fill_rule (cairo_t *cr) +{ + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_set_line_width (cairo_t *cr) +{ + cairo_set_line_width (cr, 42); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_set_line_cap (cairo_t *cr) +{ + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_set_line_join (cairo_t *cr) +{ + cairo_set_line_join (cr, CAIRO_LINE_JOIN_BEVEL); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_set_dash (cairo_t *cr) +{ + cairo_set_dash (cr, NULL, 0, 0); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_set_miter_limit (cairo_t *cr) +{ + cairo_set_miter_limit (cr, 2); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_translate (cairo_t *cr) +{ + cairo_translate (cr, 2, 2); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_scale (cairo_t *cr) +{ + cairo_scale (cr, 2, 2); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_rotate (cairo_t *cr) +{ + cairo_rotate (cr, 2); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_transform (cairo_t *cr) +{ + cairo_matrix_t matrix; + + cairo_matrix_init_translate (&matrix, 1, 1); + cairo_transform (cr, &matrix); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_set_matrix (cairo_t *cr) +{ + cairo_matrix_t matrix; + + cairo_matrix_init_translate (&matrix, 1, 1); + cairo_set_matrix (cr, &matrix); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_identity_matrix (cairo_t *cr) +{ + cairo_identity_matrix (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_user_to_device (cairo_t *cr) +{ + double x = 42, y = 42; + + cairo_user_to_device (cr, &x, &y); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_user_to_device_distance (cairo_t *cr) +{ + double x = 42, y = 42; + + cairo_user_to_device_distance (cr, &x, &y); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_device_to_user (cairo_t *cr) +{ + double x = 42, y = 42; + + cairo_device_to_user (cr, &x, &y); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_device_to_user_distance (cairo_t *cr) +{ + double x = 42, y = 42; + + cairo_device_to_user_distance (cr, &x, &y); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_new_path (cairo_t *cr) +{ + cairo_new_path (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_move_to (cairo_t *cr) +{ + cairo_move_to (cr, 2, 2); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_new_sub_path (cairo_t *cr) +{ + cairo_new_sub_path (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_line_to (cairo_t *cr) +{ + cairo_line_to (cr, 2, 2); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_curve_to (cairo_t *cr) +{ + cairo_curve_to (cr, 2, 2, 3, 3, 4, 4); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_arc (cairo_t *cr) +{ + cairo_arc (cr, 2, 2, 3, 0, 2 * M_PI); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_arc_negative (cairo_t *cr) +{ + cairo_arc_negative (cr, 2, 2, 3, 0, 2 * M_PI); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_rel_move_to (cairo_t *cr) +{ + cairo_rel_move_to (cr, 2, 2); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_rel_line_to (cairo_t *cr) +{ + cairo_rel_line_to (cr, 2, 2); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_rel_curve_to (cairo_t *cr) +{ + cairo_rel_curve_to (cr, 2, 2, 3, 3, 4, 4); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_rectangle (cairo_t *cr) +{ + cairo_rectangle (cr, 2, 2, 3, 3); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_close_path (cairo_t *cr) +{ + cairo_close_path (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_path_extents (cairo_t *cr) +{ + double x1, y1, x2, y2; + cairo_path_extents (cr, &x1, &y1, &x2, &y2); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_paint (cairo_t *cr) +{ + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_paint_with_alpha (cairo_t *cr) +{ + cairo_paint_with_alpha (cr, 0.5); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_mask (cairo_t *cr) +{ + cairo_pattern_t *pattern; + + pattern = cairo_pattern_create_rgb (0.5, 0.5, 0.5); + cairo_mask (cr, pattern); + + cairo_pattern_destroy (pattern); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_mask_surface (cairo_t *cr) +{ + cairo_surface_t *surface; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1); + cairo_mask_surface (cr, surface, 0, 0); + + cairo_surface_destroy (surface); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_stroke (cairo_t *cr) +{ + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_stroke_preserve (cairo_t *cr) +{ + cairo_stroke_preserve (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_fill (cairo_t *cr) +{ + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_fill_preserve (cairo_t *cr) +{ + cairo_fill_preserve (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_copy_page (cairo_t *cr) +{ + cairo_copy_page (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_show_page (cairo_t *cr) +{ + cairo_show_page (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_in_stroke (cairo_t *cr) +{ + cairo_in_stroke (cr, 1, 1); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_in_fill (cairo_t *cr) +{ + cairo_in_fill (cr, 1, 1); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_in_clip (cairo_t *cr) +{ + cairo_in_clip (cr, 1, 1); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_stroke_extents (cairo_t *cr) +{ + double x1, y1, x2, y2; + cairo_stroke_extents (cr, &x1, &y1, &x2, &y2); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_fill_extents (cairo_t *cr) +{ + double x1, y1, x2, y2; + cairo_fill_extents (cr, &x1, &y1, &x2, &y2); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_reset_clip (cairo_t *cr) +{ + cairo_reset_clip (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_clip (cairo_t *cr) +{ + cairo_clip (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_clip_preserve (cairo_t *cr) +{ + cairo_clip_preserve (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_clip_extents (cairo_t *cr) +{ + double x1, y1, x2, y2; + cairo_clip_extents (cr, &x1, &y1, &x2, &y2); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_copy_clip_rectangle_list (cairo_t *cr) +{ + cairo_rectangle_list_destroy (cairo_copy_clip_rectangle_list (cr)); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_select_font_face (cairo_t *cr) +{ + cairo_select_font_face (cr, "Arial", CAIRO_FONT_SLANT_ITALIC, CAIRO_FONT_WEIGHT_BOLD); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_set_font_size (cairo_t *cr) +{ + cairo_set_font_size (cr, 42); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_set_font_matrix (cairo_t *cr) +{ + cairo_matrix_t matrix; + + cairo_matrix_init_translate (&matrix, 1, 1); + cairo_set_font_matrix (cr, &matrix); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_get_font_matrix (cairo_t *cr) +{ + cairo_matrix_t matrix; + + cairo_get_font_matrix (cr, &matrix); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_set_font_options (cairo_t *cr) +{ + cairo_font_options_t *opt = cairo_font_options_create (); + cairo_set_font_options (cr, opt); + cairo_font_options_destroy (opt); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_get_font_options (cairo_t *cr) +{ + cairo_font_options_t *opt = cairo_font_options_create (); + cairo_get_font_options (cr, opt); + cairo_font_options_destroy (opt); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_set_font_face (cairo_t *cr) +{ + cairo_set_font_face (cr, cairo_get_font_face (cr)); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_set_scaled_font (cairo_t *cr) +{ + cairo_set_scaled_font (cr, cairo_get_scaled_font (cr)); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_show_text (cairo_t *cr) +{ + cairo_show_text (cr, "Cairo"); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_show_glyphs (cairo_t *cr) +{ + cairo_glyph_t glyph; + + glyph.index = 65; + glyph.x = 0; + glyph.y = 0; + + cairo_show_glyphs (cr, &glyph, 1); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_show_text_glyphs (cairo_t *cr) +{ + cairo_glyph_t glyph; + cairo_text_cluster_t cluster; + + glyph.index = 65; + glyph.x = 0; + glyph.y = 0; + + cluster.num_bytes = 1; + cluster.num_glyphs = 1; + + cairo_show_text_glyphs (cr, "a", -1, &glyph, 1, &cluster, 1, 0); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_text_path (cairo_t *cr) +{ + cairo_text_path (cr, "Cairo"); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_glyph_path (cairo_t *cr) +{ + cairo_glyph_t glyph; + + glyph.index = 65; + glyph.x = 0; + glyph.y = 0; + + cairo_glyph_path (cr, &glyph, 1); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_text_extents (cairo_t *cr) +{ + cairo_text_extents_t extents; + + cairo_text_extents (cr, "Cairo", &extents); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_glyph_extents (cairo_t *cr) +{ + cairo_glyph_t glyph; + cairo_text_extents_t extents; + + glyph.index = 65; + glyph.x = 0; + glyph.y = 0; + + cairo_glyph_extents (cr, &glyph, 1, &extents); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_font_extents (cairo_t *cr) +{ + cairo_font_extents_t extents; + + cairo_font_extents (cr, &extents); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_get_operator (cairo_t *cr) +{ + cairo_get_operator (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_get_source (cairo_t *cr) +{ + cairo_get_source (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_get_tolerance (cairo_t *cr) +{ + cairo_get_tolerance (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_get_antialias (cairo_t *cr) +{ + cairo_get_antialias (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_has_current_point (cairo_t *cr) +{ + cairo_has_current_point (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_get_current_point (cairo_t *cr) +{ + double x, y; + + cairo_get_current_point (cr, &x, &y); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_get_fill_rule (cairo_t *cr) +{ + cairo_get_fill_rule (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_get_line_width (cairo_t *cr) +{ + cairo_get_line_width (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_get_line_cap (cairo_t *cr) +{ + cairo_get_line_cap (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_get_line_join (cairo_t *cr) +{ + cairo_get_line_join (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_get_miter_limit (cairo_t *cr) +{ + cairo_get_miter_limit (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_get_dash_count (cairo_t *cr) +{ + cairo_get_dash_count (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_get_dash (cairo_t *cr) +{ + double dashes[42]; + double offset; + + cairo_get_dash (cr, &dashes[0], &offset); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_get_matrix (cairo_t *cr) +{ + cairo_matrix_t matrix; + + cairo_get_matrix (cr, &matrix); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_get_target (cairo_t *cr) +{ + cairo_get_target (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_get_group_target (cairo_t *cr) +{ + cairo_get_group_target (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_copy_path (cairo_t *cr) +{ + cairo_path_destroy (cairo_copy_path (cr)); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_copy_path_flat (cairo_t *cr) +{ + cairo_path_destroy (cairo_copy_path_flat (cr)); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_append_path (cairo_t *cr) +{ + cairo_path_data_t data[3]; + cairo_path_t path; + + path.status = CAIRO_STATUS_SUCCESS; + path.data = &data[0]; + path.num_data = ARRAY_LENGTH(data); + + data[0].header.type = CAIRO_PATH_MOVE_TO; + data[0].header.length = 2; + data[1].point.x = 1; + data[1].point.y = 2; + data[2].header.type = CAIRO_PATH_CLOSE_PATH; + data[2].header.length = 1; + + cairo_append_path (cr, &path); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_surface_create_similar (cairo_surface_t *surface) +{ + cairo_surface_t *similar; + + similar = cairo_surface_create_similar (surface, CAIRO_CONTENT_ALPHA, 100, 100); + + cairo_surface_destroy (similar); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_surface_create_for_rectangle (cairo_surface_t *surface) +{ + cairo_surface_t *similar; + + similar = cairo_surface_create_for_rectangle (surface, 1, 1, 8, 8); + + cairo_surface_destroy (similar); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_surface_reference (cairo_surface_t *surface) +{ + cairo_surface_destroy (cairo_surface_reference (surface)); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_surface_finish (cairo_surface_t *surface) +{ + cairo_surface_finish (surface); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_surface_get_device (cairo_surface_t *surface) +{ + /* cairo_device_t *device = */cairo_surface_get_device (surface); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_surface_get_reference_count (cairo_surface_t *surface) +{ + unsigned int refcount = cairo_surface_get_reference_count (surface); + if (refcount > 0) + return CAIRO_TEST_SUCCESS; + /* inert error surfaces have a refcount of 0 */ + return cairo_surface_status (surface) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR; +} + +static cairo_test_status_t +test_cairo_surface_status (cairo_surface_t *surface) +{ + cairo_status_t status = cairo_surface_status (surface); + return status < CAIRO_STATUS_LAST_STATUS ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR; +} + +static cairo_test_status_t +test_cairo_surface_get_type (cairo_surface_t *surface) +{ + /* cairo_surface_type_t type = */cairo_surface_get_type (surface); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_surface_get_content (cairo_surface_t *surface) +{ + cairo_content_t content = cairo_surface_get_content (surface); + + switch (content) { + case CAIRO_CONTENT_COLOR: + case CAIRO_CONTENT_ALPHA: + case CAIRO_CONTENT_COLOR_ALPHA: + return CAIRO_TEST_SUCCESS; + default: + return CAIRO_TEST_ERROR; + } +} + +static cairo_test_status_t +test_cairo_surface_set_user_data (cairo_surface_t *surface) +{ + static cairo_user_data_key_t key; + cairo_status_t status; + + status = cairo_surface_set_user_data (surface, &key, &key, NULL); + if (status == CAIRO_STATUS_NO_MEMORY) + return CAIRO_TEST_NO_MEMORY; + else if (status) + return CAIRO_TEST_SUCCESS; + + if (cairo_surface_get_user_data (surface, &key) != &key) + return CAIRO_TEST_ERROR; + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_surface_set_mime_data (cairo_surface_t *surface) +{ + const char *mimetype = "text/x-uri"; + const char *data = "https://www.cairographics.org"; + cairo_status_t status; + + status = cairo_surface_set_mime_data (surface, + mimetype, + (const unsigned char *) data, + strlen (data), + NULL, NULL); + return status ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR; +} + +static cairo_test_status_t +test_cairo_surface_get_mime_data (cairo_surface_t *surface) +{ + const char *mimetype = "text/x-uri"; + const unsigned char *data; + unsigned long length; + + cairo_surface_get_mime_data (surface, mimetype, &data, &length); + return data == NULL && length == 0 ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR; +} + +static cairo_test_status_t +test_cairo_surface_get_font_options (cairo_surface_t *surface) +{ + cairo_font_options_t *options; + cairo_status_t status; + + options = cairo_font_options_create (); + if (likely (!cairo_font_options_status (options))) + cairo_surface_get_font_options (surface, options); + status = cairo_font_options_status (options); + cairo_font_options_destroy (options); + return status ? CAIRO_TEST_ERROR : CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_surface_flush (cairo_surface_t *surface) +{ + cairo_surface_flush (surface); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_surface_mark_dirty (cairo_surface_t *surface) +{ + cairo_surface_mark_dirty (surface); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface) +{ + cairo_surface_mark_dirty_rectangle (surface, 1, 1, 8, 8); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_surface_set_device_offset (cairo_surface_t *surface) +{ + cairo_surface_set_device_offset (surface, 5, 5); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_surface_get_device_offset (cairo_surface_t *surface) +{ + double x, y; + + cairo_surface_get_device_offset (surface, &x, &y); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_surface_set_fallback_resolution (cairo_surface_t *surface) +{ + cairo_surface_set_fallback_resolution (surface, 42, 42); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_surface_get_fallback_resolution (cairo_surface_t *surface) +{ + double x, y; + + cairo_surface_get_fallback_resolution (surface, &x, &y); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_surface_copy_page (cairo_surface_t *surface) +{ + cairo_surface_copy_page (surface); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_surface_show_page (cairo_surface_t *surface) +{ + cairo_surface_show_page (surface); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_surface_has_show_text_glyphs (cairo_surface_t *surface) +{ + cairo_surface_has_show_text_glyphs (surface); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_image_surface_get_data (cairo_surface_t *surface) +{ + unsigned char *data = cairo_image_surface_get_data (surface); + return data == NULL || surface_has_type (surface, CAIRO_SURFACE_TYPE_IMAGE) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR; +} + +static cairo_test_status_t +test_cairo_image_surface_get_format (cairo_surface_t *surface) +{ + cairo_format_t format = cairo_image_surface_get_format (surface); + return format == CAIRO_FORMAT_INVALID || surface_has_type (surface, CAIRO_SURFACE_TYPE_IMAGE) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR; +} + +static cairo_test_status_t +test_cairo_image_surface_get_width (cairo_surface_t *surface) +{ + unsigned int width = cairo_image_surface_get_width (surface); + return width == 0 || surface_has_type (surface, CAIRO_SURFACE_TYPE_IMAGE) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR; +} + +static cairo_test_status_t +test_cairo_image_surface_get_height (cairo_surface_t *surface) +{ + unsigned int height = cairo_image_surface_get_height (surface); + return height == 0 || surface_has_type (surface, CAIRO_SURFACE_TYPE_IMAGE) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR; +} + +static cairo_test_status_t +test_cairo_image_surface_get_stride (cairo_surface_t *surface) +{ + unsigned int stride = cairo_image_surface_get_stride (surface); + return stride == 0 || surface_has_type (surface, CAIRO_SURFACE_TYPE_IMAGE) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR; +} + +#if CAIRO_HAS_PNG_FUNCTIONS + +static cairo_test_status_t +test_cairo_surface_write_to_png (cairo_surface_t *surface) +{ + cairo_status_t status; + + status = cairo_surface_write_to_png (surface, "/this/file/will/definitely/not/exist.png"); + + return status ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR; +} + +static cairo_status_t +write_func_that_always_fails (void *closure, const unsigned char *data, unsigned int length) +{ + return CAIRO_STATUS_WRITE_ERROR; +} + +static cairo_test_status_t +test_cairo_surface_write_to_png_stream (cairo_surface_t *surface) +{ + cairo_status_t status; + + status = cairo_surface_write_to_png_stream (surface, + write_func_that_always_fails, + NULL); + + return status && status != CAIRO_STATUS_WRITE_ERROR ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR; +} + +#endif /* CAIRO_HAS_PNG_FUNCTIONS */ + +static cairo_test_status_t +test_cairo_recording_surface_ink_extents (cairo_surface_t *surface) +{ + double x, y, w, h; + + cairo_recording_surface_ink_extents (surface, &x, &y, &w, &h); + return x == 0 && y == 0 && w == 0 && h == 0 ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR; +} + +#if CAIRO_HAS_TEE_SURFACE + +static cairo_test_status_t +test_cairo_tee_surface_add (cairo_surface_t *surface) +{ + cairo_surface_t *image = cairo_image_surface_create (CAIRO_FORMAT_A8, 10, 10); + + cairo_tee_surface_add (surface, image); + cairo_surface_destroy (image); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_tee_surface_remove (cairo_surface_t *surface) +{ + cairo_surface_t *image = cairo_image_surface_create (CAIRO_FORMAT_A8, 10, 10); + + cairo_tee_surface_remove (surface, image); + cairo_surface_destroy (image); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_tee_surface_index (cairo_surface_t *surface) +{ + cairo_surface_t *master; + cairo_status_t status; + + master = cairo_tee_surface_index (surface, 0); + status = cairo_surface_status (master); + cairo_surface_destroy (master); + return status ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR; +} + +#endif /* CAIRO_HAS_TEE_SURFACE */ + +#if CAIRO_HAS_PDF_SURFACE + +static cairo_test_status_t +test_cairo_pdf_surface_restrict_to_version (cairo_surface_t *surface) +{ + cairo_pdf_surface_restrict_to_version (surface, CAIRO_PDF_VERSION_1_4); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_pdf_surface_set_size (cairo_surface_t *surface) +{ + cairo_pdf_surface_set_size (surface, 5, 5); + return CAIRO_TEST_SUCCESS; +} + +#endif /* CAIRO_HAS_PDF_SURFACE */ + +#if CAIRO_HAS_PS_SURFACE + +static cairo_test_status_t +test_cairo_ps_surface_restrict_to_level (cairo_surface_t *surface) +{ + cairo_ps_surface_restrict_to_level (surface, CAIRO_PS_LEVEL_2); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_ps_surface_set_eps (cairo_surface_t *surface) +{ + cairo_ps_surface_set_eps (surface, TRUE); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_ps_surface_get_eps (cairo_surface_t *surface) +{ + cairo_bool_t eps = cairo_ps_surface_get_eps (surface); + return eps ? CAIRO_TEST_ERROR : CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_ps_surface_set_size (cairo_surface_t *surface) +{ + cairo_ps_surface_set_size (surface, 5, 5); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_ps_surface_dsc_comment (cairo_surface_t *surface) +{ + cairo_ps_surface_dsc_comment (surface, "54, 74, 90, 2010"); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_ps_surface_dsc_begin_setup (cairo_surface_t *surface) +{ + cairo_ps_surface_dsc_begin_setup (surface); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_ps_surface_dsc_begin_page_setup (cairo_surface_t *surface) +{ + cairo_ps_surface_dsc_begin_page_setup (surface); + return CAIRO_TEST_SUCCESS; +} + +#endif /* CAIRO_HAS_PS_SURFACE */ + +#if CAIRO_HAS_QUARTZ_SURFACE + +static cairo_test_status_t +test_cairo_quartz_surface_get_cg_context (cairo_surface_t *surface) +{ + CGContextRef context = cairo_quartz_surface_get_cg_context (surface); + return context == NULL || surface_has_type (surface, CAIRO_SURFACE_TYPE_QUARTZ) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR; +} + +#endif /* CAIRO_HAS_QUARTZ_SURFACE */ + +#if CAIRO_HAS_SVG_SURFACE + +static cairo_test_status_t +test_cairo_svg_surface_restrict_to_version (cairo_surface_t *surface) +{ + cairo_svg_surface_restrict_to_version (surface, CAIRO_SVG_VERSION_1_1); + return CAIRO_TEST_SUCCESS; +} + +#endif /* CAIRO_HAS_SVG_SURFACE */ + +#if CAIRO_HAS_XCB_SURFACE + +static cairo_test_status_t +test_cairo_xcb_surface_set_size (cairo_surface_t *surface) +{ + cairo_xcb_surface_set_size (surface, 5, 5); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_xcb_surface_set_drawable (cairo_surface_t *surface) +{ + cairo_xcb_surface_set_drawable (surface, 0, 5, 5); + return CAIRO_TEST_SUCCESS; +} + +#endif + +#if CAIRO_HAS_XLIB_SURFACE + +static cairo_test_status_t +test_cairo_xlib_surface_set_size (cairo_surface_t *surface) +{ + cairo_xlib_surface_set_size (surface, 5, 5); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_xlib_surface_set_drawable (cairo_surface_t *surface) +{ + cairo_xlib_surface_set_drawable (surface, 0, 5, 5); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_cairo_xlib_surface_get_display (cairo_surface_t *surface) +{ + Display *display = cairo_xlib_surface_get_display (surface); + return display == NULL || surface_has_type (surface, CAIRO_SURFACE_TYPE_XLIB) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR; +} + +static cairo_test_status_t +test_cairo_xlib_surface_get_screen (cairo_surface_t *surface) +{ + Screen *screen = cairo_xlib_surface_get_screen (surface); + return screen == NULL || surface_has_type (surface, CAIRO_SURFACE_TYPE_XLIB) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR; +} + +static cairo_test_status_t +test_cairo_xlib_surface_get_visual (cairo_surface_t *surface) +{ + Visual *visual = cairo_xlib_surface_get_visual (surface); + return visual == NULL || surface_has_type (surface, CAIRO_SURFACE_TYPE_XLIB) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR; +} + +static cairo_test_status_t +test_cairo_xlib_surface_get_drawable (cairo_surface_t *surface) +{ + Drawable drawable = cairo_xlib_surface_get_drawable (surface); + return drawable == 0 || surface_has_type (surface, CAIRO_SURFACE_TYPE_XLIB) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR; +} + +static cairo_test_status_t +test_cairo_xlib_surface_get_depth (cairo_surface_t *surface) +{ + int depth = cairo_xlib_surface_get_depth (surface); + return depth == 0 || surface_has_type (surface, CAIRO_SURFACE_TYPE_XLIB) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR; +} + +static cairo_test_status_t +test_cairo_xlib_surface_get_width (cairo_surface_t *surface) +{ + int width = cairo_xlib_surface_get_width (surface); + return width == 0 || surface_has_type (surface, CAIRO_SURFACE_TYPE_XLIB) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR; +} + +static cairo_test_status_t +test_cairo_xlib_surface_get_height (cairo_surface_t *surface) +{ + int height = cairo_xlib_surface_get_height (surface); + return height == 0 || surface_has_type (surface, CAIRO_SURFACE_TYPE_XLIB) ? CAIRO_TEST_SUCCESS : CAIRO_TEST_ERROR; +} + +#endif + +#define TEST(name) { #name, test_ ## name } + +struct { + const char *name; + context_test_func_t func; +} context_tests[] = { + TEST (cairo_reference), + TEST (cairo_get_reference_count), + TEST (cairo_set_user_data), + TEST (cairo_save), + TEST (cairo_push_group), + TEST (cairo_push_group_with_content), + TEST (cairo_set_operator), + TEST (cairo_set_source), + TEST (cairo_set_source_rgb), + TEST (cairo_set_source_rgba), + TEST (cairo_set_source_surface), + TEST (cairo_set_tolerance), + TEST (cairo_set_antialias), + TEST (cairo_set_fill_rule), + TEST (cairo_set_line_width), + TEST (cairo_set_line_cap), + TEST (cairo_set_line_join), + TEST (cairo_set_dash), + TEST (cairo_set_miter_limit), + TEST (cairo_translate), + TEST (cairo_scale), + TEST (cairo_rotate), + TEST (cairo_transform), + TEST (cairo_set_matrix), + TEST (cairo_identity_matrix), + TEST (cairo_user_to_device), + TEST (cairo_user_to_device_distance), + TEST (cairo_device_to_user), + TEST (cairo_device_to_user_distance), + TEST (cairo_new_path), + TEST (cairo_move_to), + TEST (cairo_new_sub_path), + TEST (cairo_line_to), + TEST (cairo_curve_to), + TEST (cairo_arc), + TEST (cairo_arc_negative), + TEST (cairo_rel_move_to), + TEST (cairo_rel_line_to), + TEST (cairo_rel_curve_to), + TEST (cairo_rectangle), + TEST (cairo_close_path), + TEST (cairo_path_extents), + TEST (cairo_paint), + TEST (cairo_paint_with_alpha), + TEST (cairo_mask), + TEST (cairo_mask_surface), + TEST (cairo_stroke), + TEST (cairo_stroke_preserve), + TEST (cairo_fill), + TEST (cairo_fill_preserve), + TEST (cairo_copy_page), + TEST (cairo_show_page), + TEST (cairo_in_stroke), + TEST (cairo_in_fill), + TEST (cairo_in_clip), + TEST (cairo_stroke_extents), + TEST (cairo_fill_extents), + TEST (cairo_reset_clip), + TEST (cairo_clip), + TEST (cairo_clip_preserve), + TEST (cairo_clip_extents), + TEST (cairo_copy_clip_rectangle_list), + TEST (cairo_select_font_face), + TEST (cairo_set_font_size), + TEST (cairo_set_font_matrix), + TEST (cairo_get_font_matrix), + TEST (cairo_set_font_options), + TEST (cairo_get_font_options), + TEST (cairo_set_font_face), + TEST (cairo_set_scaled_font), + TEST (cairo_show_text), + TEST (cairo_show_glyphs), + TEST (cairo_show_text_glyphs), + TEST (cairo_text_path), + TEST (cairo_glyph_path), + TEST (cairo_text_extents), + TEST (cairo_glyph_extents), + TEST (cairo_font_extents), + TEST (cairo_get_operator), + TEST (cairo_get_source), + TEST (cairo_get_tolerance), + TEST (cairo_get_antialias), + TEST (cairo_has_current_point), + TEST (cairo_get_current_point), + TEST (cairo_get_fill_rule), + TEST (cairo_get_line_width), + TEST (cairo_get_line_cap), + TEST (cairo_get_line_join), + TEST (cairo_get_miter_limit), + TEST (cairo_get_dash_count), + TEST (cairo_get_dash), + TEST (cairo_get_matrix), + TEST (cairo_get_target), + TEST (cairo_get_group_target), + TEST (cairo_copy_path), + TEST (cairo_copy_path_flat), + TEST (cairo_append_path), +}; + +#undef TEST + +#define TEST(name, surface_type, sets_status) { #name, test_ ## name, surface_type, sets_status } + +struct { + const char *name; + surface_test_func_t func; + int surface_type; /* cairo_surface_type_t or -1 */ + cairo_bool_t modifies_surface; +} surface_tests[] = { + TEST (cairo_surface_create_similar, -1, FALSE), + TEST (cairo_surface_create_for_rectangle, -1, FALSE), + TEST (cairo_surface_reference, -1, FALSE), + TEST (cairo_surface_finish, -1, TRUE), + TEST (cairo_surface_get_device, -1, FALSE), + TEST (cairo_surface_get_reference_count, -1, FALSE), + TEST (cairo_surface_status, -1, FALSE), + TEST (cairo_surface_get_type, -1, FALSE), + TEST (cairo_surface_get_content, -1, FALSE), + TEST (cairo_surface_set_user_data, -1, FALSE), + TEST (cairo_surface_set_mime_data, -1, TRUE), + TEST (cairo_surface_get_mime_data, -1, FALSE), + TEST (cairo_surface_get_font_options, -1, FALSE), + TEST (cairo_surface_flush, -1, TRUE), + TEST (cairo_surface_mark_dirty, -1, TRUE), + TEST (cairo_surface_mark_dirty_rectangle, -1, TRUE), + TEST (cairo_surface_set_device_offset, -1, TRUE), + TEST (cairo_surface_get_device_offset, -1, FALSE), + TEST (cairo_surface_set_fallback_resolution, -1, TRUE), + TEST (cairo_surface_get_fallback_resolution, -1, FALSE), + TEST (cairo_surface_copy_page, -1, TRUE), + TEST (cairo_surface_show_page, -1, TRUE), + TEST (cairo_surface_has_show_text_glyphs, -1, FALSE), + TEST (cairo_image_surface_get_data, CAIRO_SURFACE_TYPE_IMAGE, FALSE), + TEST (cairo_image_surface_get_format, CAIRO_SURFACE_TYPE_IMAGE, FALSE), + TEST (cairo_image_surface_get_width, CAIRO_SURFACE_TYPE_IMAGE, FALSE), + TEST (cairo_image_surface_get_height, CAIRO_SURFACE_TYPE_IMAGE, FALSE), + TEST (cairo_image_surface_get_stride, CAIRO_SURFACE_TYPE_IMAGE, FALSE), +#if CAIRO_HAS_PNG_FUNCTIONS + TEST (cairo_surface_write_to_png, -1, FALSE), + TEST (cairo_surface_write_to_png_stream, -1, FALSE), +#endif + TEST (cairo_recording_surface_ink_extents, CAIRO_SURFACE_TYPE_RECORDING, FALSE), +#if CAIRO_HAS_TEE_SURFACE + TEST (cairo_tee_surface_add, CAIRO_SURFACE_TYPE_TEE, TRUE), + TEST (cairo_tee_surface_remove, CAIRO_SURFACE_TYPE_TEE, TRUE), + TEST (cairo_tee_surface_index, CAIRO_SURFACE_TYPE_TEE, FALSE), +#endif +#if CAIRO_HAS_PDF_SURFACE + TEST (cairo_pdf_surface_restrict_to_version, CAIRO_SURFACE_TYPE_PDF, TRUE), + TEST (cairo_pdf_surface_set_size, CAIRO_SURFACE_TYPE_PDF, TRUE), +#endif +#if CAIRO_HAS_PS_SURFACE + TEST (cairo_ps_surface_restrict_to_level, CAIRO_SURFACE_TYPE_PS, TRUE), + TEST (cairo_ps_surface_set_eps, CAIRO_SURFACE_TYPE_PS, TRUE), + TEST (cairo_ps_surface_get_eps, CAIRO_SURFACE_TYPE_PS, FALSE), + TEST (cairo_ps_surface_set_size, CAIRO_SURFACE_TYPE_PS, TRUE), + TEST (cairo_ps_surface_dsc_comment, CAIRO_SURFACE_TYPE_PS, TRUE), + TEST (cairo_ps_surface_dsc_begin_setup, CAIRO_SURFACE_TYPE_PS, TRUE), + TEST (cairo_ps_surface_dsc_begin_page_setup, CAIRO_SURFACE_TYPE_PS, TRUE), +#endif +#if CAIRO_HAS_QUARTZ_SURFACE + TEST (cairo_quartz_surface_get_cg_context, CAIRO_SURFACE_TYPE_QUARTZ, FALSE), +#endif +#if CAIRO_HAS_SVG_SURFACE + TEST (cairo_svg_surface_restrict_to_version, CAIRO_SURFACE_TYPE_SVG, TRUE), +#endif +#if CAIRO_HAS_XCB_SURFACE + TEST (cairo_xcb_surface_set_size, CAIRO_SURFACE_TYPE_XCB, TRUE), + TEST (cairo_xcb_surface_set_drawable, CAIRO_SURFACE_TYPE_XCB, TRUE), +#endif +#if CAIRO_HAS_XLIB_SURFACE + TEST (cairo_xlib_surface_set_size, CAIRO_SURFACE_TYPE_XLIB, TRUE), + TEST (cairo_xlib_surface_set_drawable, CAIRO_SURFACE_TYPE_XLIB, TRUE), + TEST (cairo_xlib_surface_get_display, CAIRO_SURFACE_TYPE_XLIB, FALSE), + TEST (cairo_xlib_surface_get_drawable, CAIRO_SURFACE_TYPE_XLIB, FALSE), + TEST (cairo_xlib_surface_get_screen, CAIRO_SURFACE_TYPE_XLIB, FALSE), + TEST (cairo_xlib_surface_get_visual, CAIRO_SURFACE_TYPE_XLIB, FALSE), + TEST (cairo_xlib_surface_get_depth, CAIRO_SURFACE_TYPE_XLIB, FALSE), + TEST (cairo_xlib_surface_get_width, CAIRO_SURFACE_TYPE_XLIB, FALSE), + TEST (cairo_xlib_surface_get_height, CAIRO_SURFACE_TYPE_XLIB, FALSE), +#endif +}; + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + cairo_surface_t *surface; + cairo_t *cr; + cairo_test_status_t test_status; + cairo_status_t status_before, status_after; + unsigned int i; + + /* Test an error surface */ + for (i = 0; i < ARRAY_LENGTH (surface_tests); i++) { + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, INT_MAX, INT_MAX); + status_before = cairo_surface_status (surface); + assert (status_before); + + test_status = surface_tests[i].func (surface); + + status_after = cairo_surface_status (surface); + cairo_surface_destroy (surface); + + if (test_status != CAIRO_TEST_SUCCESS) { + cairo_test_log (ctx, + "Failed test %s with %d\n", + surface_tests[i].name, (int) test_status); + return test_status; + } + + if (status_before != status_after) { + cairo_test_log (ctx, + "Failed test %s: Modified surface status from %u (%s) to %u (%s)\n", + surface_tests[i].name, + status_before, cairo_status_to_string (status_before), + status_after, cairo_status_to_string (status_after)); + return CAIRO_TEST_ERROR; + } + } + + /* Test an error context */ + for (i = 0; i < ARRAY_LENGTH (context_tests); i++) { + cr = cairo_create (NULL); + status_before = cairo_status (cr); + assert (status_before); + + test_status = context_tests[i].func (cr); + + status_after = cairo_status (cr); + cairo_destroy (cr); + + if (test_status != CAIRO_TEST_SUCCESS) { + cairo_test_log (ctx, + "Failed test %s with %d\n", + context_tests[i].name, (int) test_status); + return test_status; + } + + if (status_before != status_after) { + cairo_test_log (ctx, + "Failed test %s: Modified context status from %u (%s) to %u (%s)\n", + context_tests[i].name, + status_before, cairo_status_to_string (status_before), + status_after, cairo_status_to_string (status_after)); + return CAIRO_TEST_ERROR; + } + } + + /* Test a context for an error surface */ + for (i = 0; i < ARRAY_LENGTH (context_tests); i++) { + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, INT_MAX, INT_MAX); + cr = cairo_create (surface); + cairo_surface_destroy (surface); + status_before = cairo_status (cr); + assert (status_before); + + test_status = context_tests[i].func (cr); + + status_after = cairo_status (cr); + cairo_destroy (cr); + + if (test_status != CAIRO_TEST_SUCCESS) { + cairo_test_log (ctx, + "Failed test %s with %d\n", + context_tests[i].name, (int) test_status); + return test_status; + } + + if (status_before != status_after) { + cairo_test_log (ctx, + "Failed test %s: Modified context status from %u (%s) to %u (%s)\n", + context_tests[i].name, + status_before, cairo_status_to_string (status_before), + status_after, cairo_status_to_string (status_after)); + return CAIRO_TEST_ERROR; + } + } + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +test_context (const cairo_test_context_t *ctx, cairo_t *cr, const char *name, unsigned int i) +{ + cairo_test_status_t test_status; + cairo_status_t status_before, status_after; + + /* Make sure that there is a current point */ + cairo_move_to (cr, 0, 0); + + status_before = cairo_status (cr); + test_status = context_tests[i].func (cr); + status_after = cairo_status (cr); + + if (test_status != CAIRO_TEST_SUCCESS) { + cairo_test_log (ctx, + "Failed test %s on %s with %d\n", + context_tests[i].name, name, (int) test_status); + return test_status; + } + + if (status_after != CAIRO_STATUS_SURFACE_FINISHED && status_before != status_after) { + cairo_test_log (ctx, + "Failed test %s on %s: Modified context status from %u (%s) to %u (%s)\n", + context_tests[i].name, name, + status_before, cairo_status_to_string (status_before), + status_after, cairo_status_to_string (status_after)); + return CAIRO_TEST_ERROR; + } + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_surface_t *similar, *target; + cairo_test_status_t test_status; + cairo_status_t status; + cairo_t *cr2; + unsigned int i; + + target = cairo_get_target (cr); + + /* Test a finished similar surface */ + for (i = 0; i < ARRAY_LENGTH (surface_tests); i++) { + similar = cairo_surface_create_similar (target, + cairo_surface_get_content (target), + 10, 10); + cairo_surface_finish (similar); + test_status = surface_tests[i].func (similar); + status = cairo_surface_status (similar); + cairo_surface_destroy (similar); + + if (test_status != CAIRO_TEST_SUCCESS) { + cairo_test_log (ctx, + "Failed test %s with %d\n", + surface_tests[i].name, (int) test_status); + return test_status; + } + + if (surface_tests[i].modifies_surface && + strcmp (surface_tests[i].name, "cairo_surface_finish") && + strcmp (surface_tests[i].name, "cairo_surface_flush") && + status != CAIRO_STATUS_SURFACE_FINISHED) { + cairo_test_log (ctx, + "Failed test %s: Finished surface not set into error state\n", + surface_tests[i].name); + return CAIRO_TEST_ERROR; + } + } + + /* Test a context for a finished similar surface */ + for (i = 0; i < ARRAY_LENGTH (context_tests); i++) { + similar = cairo_surface_create_similar (target, + cairo_surface_get_content (target), + 10, 10); + cairo_surface_finish (similar); + cr2 = cairo_create (similar); + test_status = test_context (ctx, cr2, "finished surface", i); + cairo_surface_destroy (similar); + cairo_destroy (cr2); + + if (test_status != CAIRO_TEST_SUCCESS) + return test_status; + } + + /* Test a context for a similar surface finished later */ + for (i = 0; i < ARRAY_LENGTH (context_tests); i++) { + similar = cairo_surface_create_similar (target, + cairo_surface_get_content (target), + 10, 10); + cr2 = cairo_create (similar); + cairo_surface_finish (similar); + test_status = test_context (ctx, cr2, "finished surface after create", i); + cairo_surface_destroy (similar); + cairo_destroy (cr2); + + if (test_status != CAIRO_TEST_SUCCESS) + return test_status; + } + + /* Test a context for a similar surface finished later with a path */ + for (i = 0; i < ARRAY_LENGTH (context_tests); i++) { + similar = cairo_surface_create_similar (target, + cairo_surface_get_content (target), + 10, 10); + cr2 = cairo_create (similar); + cairo_rectangle (cr2, 2, 2, 4, 4); + cairo_surface_finish (similar); + test_status = test_context (ctx, cr2, "finished surface with path", i); + cairo_surface_destroy (similar); + cairo_destroy (cr2); + + if (test_status != CAIRO_TEST_SUCCESS) + return test_status; + } + + /* Test a normal surface for functions that have the wrong type */ + for (i = 0; i < ARRAY_LENGTH (surface_tests); i++) { + cairo_status_t desired_status; + + if (surface_tests[i].surface_type == -1) + continue; + similar = cairo_surface_create_similar (target, + cairo_surface_get_content (target), + 10, 10); + if (cairo_surface_get_type (similar) == (cairo_surface_type_t) surface_tests[i].surface_type) { + cairo_surface_destroy (similar); + continue; + } + + test_status = surface_tests[i].func (similar); + status = cairo_surface_status (similar); + cairo_surface_destroy (similar); + + if (test_status != CAIRO_TEST_SUCCESS) { + cairo_test_log (ctx, + "Failed test %s with %d\n", + surface_tests[i].name, (int) test_status); + return test_status; + } + + desired_status = surface_tests[i].modifies_surface ? CAIRO_STATUS_SURFACE_TYPE_MISMATCH : CAIRO_STATUS_SUCCESS; + if (status != desired_status) { + cairo_test_log (ctx, + "Failed test %s: Surface status should be %u (%s), but is %u (%s)\n", + surface_tests[i].name, + desired_status, cairo_status_to_string (desired_status), + status, cairo_status_to_string (status)); + return CAIRO_TEST_ERROR; + } + } + + /* 565-compatible gray background */ + cairo_set_source_rgb (cr, 0.51613, 0.55555, 0.51613); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (api_special_cases, + "Check surface functions properly handle wrong surface arguments", + "api", /* keywords */ + NULL, /* requirements */ + 10, 10, + preamble, draw) diff --git a/local/recipes/libs/cairo/source/test/arc-direction.c b/local/recipes/libs/cairo/source/test/arc-direction.c new file mode 100644 index 0000000000..92c1a8d367 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/arc-direction.c @@ -0,0 +1,105 @@ +/* + * Copyright © 2012 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +#define SIZE (2 * 20) +#define PAD (2) + +static cairo_test_status_t +draw_arcs (cairo_t *cr) +{ + double start = M_PI/12, stop = 2*start; + + cairo_move_to (cr, SIZE/2, SIZE/2); + cairo_arc (cr, SIZE/2, SIZE/2, SIZE/2, start, stop); + cairo_fill (cr); + + cairo_translate (cr, SIZE+PAD, 0); + cairo_move_to (cr, SIZE/2, SIZE/2); + cairo_arc (cr, SIZE/2, SIZE/2, SIZE/2, 2*M_PI-stop, 2*M_PI-start); + cairo_fill (cr); + + cairo_translate (cr, 0, SIZE+PAD); + cairo_move_to (cr, SIZE/2, SIZE/2); + cairo_arc_negative (cr, SIZE/2, SIZE/2, SIZE/2, 2*M_PI-stop, 2*M_PI-start); + cairo_fill (cr); + + cairo_translate (cr, -SIZE-PAD, 0); + cairo_move_to (cr, SIZE/2, SIZE/2); + cairo_arc_negative (cr, SIZE/2, SIZE/2, SIZE/2, start, stop); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_save (cr); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_restore (cr); + + cairo_save (cr); + cairo_translate (cr, PAD, PAD); + draw_arcs(cr); + cairo_restore (cr); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_translate (cr, 2*SIZE+3*PAD, 0); + cairo_save (cr); + cairo_translate (cr, 2*SIZE+2*PAD, PAD); + cairo_scale (cr, -1, 1); + draw_arcs(cr); + cairo_restore (cr); + + cairo_set_source_rgb (cr, 1, 0, 1); + cairo_translate (cr, 0, 2*SIZE+3*PAD); + cairo_save (cr); + cairo_translate (cr, 2*SIZE+2*PAD, 2*SIZE+2*PAD); + cairo_scale (cr, -1, -1); + draw_arcs(cr); + cairo_restore (cr); + + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_translate (cr, -(2*SIZE+3*PAD), 0); + cairo_save (cr); + cairo_translate (cr, PAD, 2*SIZE+2*PAD); + cairo_scale (cr, 1, -1); + draw_arcs(cr); + cairo_restore (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (arc_direction, + "Test drawing positive/negative arcs", + "arc, fill", /* keywords */ + NULL, /* requirements */ + 2*(3*PAD + 2*SIZE), 2*(3*PAD + 2*SIZE), + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/arc-infinite-loop.c b/local/recipes/libs/cairo/source/test/arc-infinite-loop.c new file mode 100644 index 0000000000..8b469eacff --- /dev/null +++ b/local/recipes/libs/cairo/source/test/arc-infinite-loop.c @@ -0,0 +1,61 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright 2010 Andrea Canciani + * + * 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: Andrea Canciani + */ + +#include "cairo-test.h" +#include + +#define SIZE 8 + +/* + cairo_arc can hang in an infinite loop if given huge (so big that + adding/subtracting 4*M_PI to them doesn't change the value because + of floating point rounding). + + The purpose of this test is to check that cairo doesn't hang or crash. +*/ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + /* Check if the code that guarantees start <= end hangs */ + cairo_arc (cr, 0, 0, 1, 1024 / DBL_EPSILON * M_PI, 0); + + /* Check if the code that handles huge angles hangs */ + cairo_arc (cr, 0, 0, 1, 0, 1024 / DBL_EPSILON * M_PI); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (arc_infinite_loop, + "Test cairo_arc with huge angles", + "arc", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/arc-looping-dash.c b/local/recipes/libs/cairo/source/test/arc-looping-dash.c new file mode 100644 index 0000000000..ff5556a548 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/arc-looping-dash.c @@ -0,0 +1,79 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright 2010 Andrea Canciani + * + * 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: Andrea Canciani + */ + +#include "cairo-test.h" + +#define SIZE 32 + +/* + When cairo_arc is used to draw an arc of more than 2pi radians + (i.e. a circle "looping over itself"), various different behaviors + are possible: + + - draw exactly a circle (an arc of 2pi radians) + + - draw an arc such that the current point is the expected one and + that does at least a complete circle (an arc of [2pi, 4pi) + radians) + + - draw an arc with the original number of loops + + This test produces different results for each of these three cases. +*/ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + double dashes[] = { 0.3, 7 }; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_save (cr); + + cairo_translate (cr, SIZE * .5, SIZE * .5); + cairo_scale (cr, SIZE * 3 / 8., SIZE * 3 / 8.); + + cairo_arc (cr, 0, 0, 1, 0, 11 * M_PI); + + cairo_set_line_width (cr, 8. / SIZE); + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_set_dash (cr, dashes, 2, 0); + cairo_stroke (cr); + + cairo_restore (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (arc_looping_dash, + "Test cairo_arc for angles describing more than a complete circle", + "arc", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/big-empty-box.c b/local/recipes/libs/cairo/source/test/big-empty-box.c new file mode 100644 index 0000000000..4ea91a1ba2 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/big-empty-box.c @@ -0,0 +1,64 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +/* + * The mystery of the disappearing box, similar to big-little-box. + * + * The issue is that we failed to tighten the initial approximated bounds + * after tessellating the path. + */ + +#include "cairo-test.h" + +#define SIZE 60 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 0, 1); + cairo_paint (cr); + + /* Set an unbounded operator so that we can see how accurate the bounded + * extents were. + */ + cairo_set_operator (cr, CAIRO_OPERATOR_IN); + cairo_set_source_rgb (cr, 1, 1, 1); + + /* Wind several boxes together that reduce to nothing */ + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + cairo_rectangle (cr, 0, 0, SIZE, SIZE); + cairo_rectangle (cr, 0, 0, SIZE, SIZE); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (big_empty_box, + "Tests that we tighten the bounds after tessellation.", + "fill", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/big-empty-triangle.c b/local/recipes/libs/cairo/source/test/big-empty-triangle.c new file mode 100644 index 0000000000..4c02c87a5b --- /dev/null +++ b/local/recipes/libs/cairo/source/test/big-empty-triangle.c @@ -0,0 +1,75 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +/* + * A variation on + * + * https://bugzilla.mozilla.org/show_bug.cgi?id=668921 + * + * The issue is that we failed to tighten the initial approximated bounds + * after tessellating the path. + */ + +#include "cairo-test.h" + +#define SIZE 60 + +static void +triangle (cairo_t *cr, double x, double y, double h) +{ + cairo_move_to (cr, x, y); + cairo_line_to (cr, x+h/2, y+h); + cairo_line_to (cr, x+h, y); + cairo_close_path (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 0, 1); + cairo_paint (cr); + + /* Set an unbounded operator so that we can see how accurate the bounded + * extents were. + */ + cairo_set_operator (cr, CAIRO_OPERATOR_IN); + cairo_set_source_rgb (cr, 1, 1, 1); + + /* Wind several triangles together that reduce to nothing */ + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + triangle (cr, 0, 0, SIZE); + triangle (cr, 0, 0, SIZE); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (big_empty_triangle, + "Tests that we tighten the bounds after tessellation.", + "fill", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/big-line.c b/local/recipes/libs/cairo/source/test/big-line.c new file mode 100644 index 0000000000..6260fba126 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/big-line.c @@ -0,0 +1,62 @@ +/* + * Copyright © 2008 Novell, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Novell, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Novell, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Larry Ewing + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 1, 1, 0); + cairo_move_to (cr, 50, 50); + cairo_rel_line_to (cr, 50000, 50000); + cairo_stroke (cr); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_move_to (cr, 50, 50); + cairo_rel_line_to (cr, -50000, 50000); + cairo_stroke (cr); + + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_move_to (cr, 50, 50); + cairo_rel_line_to (cr, 50000, -50000); + cairo_stroke (cr); + + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_move_to (cr, 50, 50); + cairo_rel_line_to (cr, -50000, -50000); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (big_line, + "Test drawing of simple lines with positive and negative coordinates > 2^16", + "stroke, line", /* keywords */ + NULL, /* requirements */ + 100, 100, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/big-little-box.c b/local/recipes/libs/cairo/source/test/big-little-box.c new file mode 100644 index 0000000000..1787ee539a --- /dev/null +++ b/local/recipes/libs/cairo/source/test/big-little-box.c @@ -0,0 +1,69 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +/* + * This attempts to exercise the bug found in + * + * https://bugzilla.mozilla.org/show_bug.cgi?id=668921 + * + * and also identified by Taekyun Kim. + * + * The issue is that we failed to tighten the initial approximated bounds + * after tessellating the path. + */ + +#include "cairo-test.h" + +#define SIZE 60 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 0, 1); + cairo_paint (cr); + + /* Set an unbounded operator so that we can see how accurate the bounded + * extents were. + */ + cairo_set_operator (cr, CAIRO_OPERATOR_IN); + cairo_set_source_rgb (cr, 1, 1, 1); + + /* Wind several boxes together that reduce to just one */ + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + cairo_rectangle (cr, 0, 0, SIZE, SIZE); + cairo_rectangle (cr, 0, 0, SIZE, SIZE); + cairo_rectangle (cr, SIZE/2 - 20, SIZE/2 - 20, 40, 40); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (big_little_box, + "Tests that we tighten the bounds after tessellation.", + "fill", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/big-little-triangle.c b/local/recipes/libs/cairo/source/test/big-little-triangle.c new file mode 100644 index 0000000000..27eb2325e7 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/big-little-triangle.c @@ -0,0 +1,76 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +/* + * A variation on + * + * https://bugzilla.mozilla.org/show_bug.cgi?id=668921 + * + * The issue is that we failed to tighten the initial approximated bounds + * after tessellating the path. + */ + +#include "cairo-test.h" + +#define SIZE 60 + +static void +triangle (cairo_t *cr, double x, double y, double h) +{ + cairo_move_to (cr, x, y); + cairo_line_to (cr, x+h/2, y+h); + cairo_line_to (cr, x+h, y); + cairo_close_path (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 0, 1); + cairo_paint (cr); + + /* Set an unbounded operator so that we can see how accurate the bounded + * extents were. + */ + cairo_set_operator (cr, CAIRO_OPERATOR_IN); + cairo_set_source_rgb (cr, 1, 1, 1); + + /* Wind several triangles together that reduce to just one */ + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + triangle (cr, 0, 0, SIZE); + triangle (cr, 0, 0, SIZE); + triangle (cr, SIZE/2-20, SIZE/2 - 20, 40); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (big_little_triangle, + "Tests that we tighten the bounds after tessellation.", + "fill", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/big-trap.c b/local/recipes/libs/cairo/source/test/big-trap.c new file mode 100644 index 0000000000..a59a38ea30 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/big-trap.c @@ -0,0 +1,92 @@ +/* + * Copyright © 2006 Mozilla Corporation + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Mozilla Corporation not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Mozilla Corporation makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * MOZILLA CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL MOZILLA CORPORATION BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Vladimir Vukicevic + */ + +#include "cairo-test.h" + +/* This test was originally written to exercise a bug in pixman in + * which it would scribble all over memory when given a particular + * (and bogus) trapezoid. However, a recent change to + * _cairo_fixed_from_double changed the details of the bogus trapezoid + * (it overflows in a different way now), so the bug is being masked. + * + * According to Vladimir, (https://lists.freedesktop.org/archives/cairo/2006-November/008482.html): + * + * Before the change, the two trapezoids that were generated were: + * + * Trap[0]: T: 0x80000000 B: 0x80000003 + * L: [(0x000a0000, 0x80000000) (0x00080000, 0x00080000)] + * R: [(0x01360000, 0x80000000) (0x01380000, 0x00080000)] + * Trap[1]: T: 0x80000003 B: 0x00080000 + * L: [(0x000a0000, 0x80000000) (0x00080000, 0x00080000)] + * R: [(0x01360000, 0x80000000) (0x01380000, 0x00080000)] + * + * After the change, the L/R coordinates are identical for both traps, but + * the top and bottom change: + * + * Trap[0]: t: 0x80000000 b: 0xfda80003 + * l: [(0x000a0000, 0x80000000) (0x00080000, 0x00080000)] + * r: [(0x01360000, 0x80000000) (0x01380000, 0x00080000)] + * Trap[1]: t: 0xfda80003 b: 0x00080000 + * l: [(0x000a0000, 0x80000000) (0x00080000, 0x00080000)] + * r: [(0x01360000, 0x80000000) (0x01380000, 0x00080000)] + * + * I think the fix we want here is to rewrite this test to call + * directly into pixman with the trapezoid of interest, (which will + * require adding a new way to configure cairo for "testing" which + * will prevent the hiding of internal library symbols. + */ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1,1,1); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0,0,0); + + /* Note that without the clip, this doesn't crash... */ + cairo_new_path (cr); + cairo_rectangle (cr, 0, 0, width, height); + cairo_clip (cr); + + cairo_new_path (cr); + cairo_line_to (cr, 8.0, 8.0); + cairo_line_to (cr, 312.0, 8.0); + cairo_line_to (cr, 310.0, 31378756.2666666666); + cairo_line_to (cr, 10.0, 31378756.2666666666); + cairo_line_to (cr, 8.0, 8.0); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +/* XFAIL: range overflow of fixed-point */ +CAIRO_TEST (big_trap, + "Test oversize trapezoid with a clip region" + "\nTest needs to be adjusted to trigger the original bug", + "trap", /* keywords */ + NULL, /* requirements */ + 100, 100, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/bilevel-image.c b/local/recipes/libs/cairo/source/test/bilevel-image.c new file mode 100644 index 0000000000..4feff0e7a5 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/bilevel-image.c @@ -0,0 +1,63 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +#define RGBx 0xffff0000, 0xff00ff00, 0xff0000ff, 0x00000000 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + uint32_t data[] = { + RGBx, RGBx, RGBx, + RGBx, RGBx, RGBx, + RGBx, RGBx, RGBx, + RGBx, RGBx, RGBx, + }; + cairo_surface_t *mask; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + mask = cairo_image_surface_create_for_data ((unsigned char *) data, + CAIRO_FORMAT_ARGB32, 12, 4, 48); + + cairo_set_source_surface (cr, mask, 0, 0); + cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); + + cairo_paint (cr); + + cairo_surface_finish (mask); /* data goes out of scope */ + cairo_surface_destroy (mask); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (bilevel_image, + "Test that PS can embed an RGB image with a bilevel alpha channel.", + "alpha, ps", /* keywords */ + NULL, /* requirements */ + 12, 4, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/bitmap-font.c b/local/recipes/libs/cairo/source/test/bitmap-font.c new file mode 100644 index 0000000000..f9d753954a --- /dev/null +++ b/local/recipes/libs/cairo/source/test/bitmap-font.c @@ -0,0 +1,226 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +#include +#include +#include + +#define FONT "6x13.pcf" +#define TEXT_SIZE 13 + +static cairo_bool_t +font_extents_equal (const cairo_font_extents_t *A, + const cairo_font_extents_t *B) +{ + return + CAIRO_TEST_DOUBLE_EQUALS (A->ascent, B->ascent) && + CAIRO_TEST_DOUBLE_EQUALS (A->descent, B->descent) && + CAIRO_TEST_DOUBLE_EQUALS (A->height, B->height) && + CAIRO_TEST_DOUBLE_EQUALS (A->max_x_advance, B->max_x_advance) && + CAIRO_TEST_DOUBLE_EQUALS (A->max_y_advance, B->max_y_advance); +} + +static cairo_test_status_t +check_font_extents (const cairo_test_context_t *ctx, cairo_t *cr, const char *comment) +{ + cairo_font_extents_t font_extents, ref_font_extents = {11, 2, 13, 6, 0}; + cairo_status_t status; + + memset (&font_extents, 0xff, sizeof (cairo_font_extents_t)); + cairo_font_extents (cr, &font_extents); + + status = cairo_status (cr); + if (status) + return cairo_test_status_from_status (ctx, status); + + if (! font_extents_equal (&font_extents, &ref_font_extents)) { + cairo_test_log (ctx, "Error: %s: cairo_font_extents(); extents (%g, %g, %g, %g, %g)\n", + comment, + font_extents.ascent, font_extents.descent, + font_extents.height, + font_extents.max_x_advance, font_extents.max_y_advance); + return CAIRO_TEST_FAILURE; + } + + return CAIRO_TEST_SUCCESS; +} + +#if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#endif + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + FcPattern *pattern; + cairo_font_face_t *font_face; + cairo_font_extents_t font_extents; + cairo_font_options_t *font_options; + cairo_status_t status; + char *filename; + int face_count; + struct stat stat_buf; + + xasprintf (&filename, "%s/%s", ctx->srcdir, FONT); + + if (stat (filename, &stat_buf) || ! S_ISREG (stat_buf.st_mode)) { + cairo_test_log (ctx, "Error finding font: %s: file not found?\n", filename); + return CAIRO_TEST_FAILURE; + } + + pattern = FcFreeTypeQuery ((unsigned char *)filename, 0, NULL, &face_count); + if (! pattern) { + cairo_test_log (ctx, "FcFreeTypeQuery failed.\n"); + free (filename); + return cairo_test_status_from_status (ctx, CAIRO_STATUS_NO_MEMORY); + } + + font_face = cairo_ft_font_face_create_for_pattern (pattern); + FcPatternDestroy (pattern); + + status = cairo_font_face_status (font_face); + if (status) { + cairo_test_log (ctx, "Error creating font face for %s: %s\n", + filename, + cairo_status_to_string (status)); + free (filename); + return cairo_test_status_from_status (ctx, status); + } + + free (filename); + if (cairo_font_face_get_type (font_face) != CAIRO_FONT_TYPE_FT) { + cairo_test_log (ctx, "Unexpected value from cairo_font_face_get_type: %d (expected %d)\n", + cairo_font_face_get_type (font_face), CAIRO_FONT_TYPE_FT); + cairo_font_face_destroy (font_face); + return CAIRO_TEST_FAILURE; + } + + cairo_set_font_face (cr, font_face); + cairo_font_face_destroy (font_face); + cairo_set_font_size (cr, 13); + + font_options = cairo_font_options_create (); + +#define CHECK_FONT_EXTENTS(comment) do {\ + cairo_test_status_t test_status; \ + test_status = check_font_extents (ctx, cr, (comment)); \ + if (test_status != CAIRO_TEST_SUCCESS) { \ + cairo_font_options_destroy (font_options); \ + return test_status; \ + } \ +} while (0) + + cairo_font_extents (cr, &font_extents); + CHECK_FONT_EXTENTS ("default"); + + cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_ON); + cairo_set_font_options (cr, font_options); + + CHECK_FONT_EXTENTS ("HINT_METRICS_ON"); + + cairo_move_to (cr, 1, font_extents.ascent - 1); + cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); /* blue */ + + cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE); + cairo_set_font_options (cr, font_options); + CHECK_FONT_EXTENTS ("HINT_METRICS_ON HINT_STYLE_NONE"); + cairo_show_text (cr, "the "); + + cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_SLIGHT); + cairo_set_font_options (cr, font_options); + CHECK_FONT_EXTENTS ("HINT_METRICS_ON HINT_STYLE_SLIGHT"); + cairo_show_text (cr, "quick "); + + cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_MEDIUM); + cairo_set_font_options (cr, font_options); + CHECK_FONT_EXTENTS ("HINT_METRICS_ON HINT_STYLE_MEDIUM"); + cairo_show_text (cr, "brown"); + + cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_FULL); + cairo_set_font_options (cr, font_options); + CHECK_FONT_EXTENTS ("HINT_METRICS_ON HINT_STYLE_FULL"); + cairo_show_text (cr, " fox"); + + /* Switch from show_text to text_path/fill to exercise bug #7889 */ + cairo_text_path (cr, " jumps over a lazy dog"); + cairo_fill (cr); + + /* And test it rotated as well for the sake of bug #7888 */ + + cairo_translate (cr, width, height); + cairo_rotate (cr, M_PI); + + cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_DEFAULT); + cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_OFF); + cairo_set_font_options (cr, font_options); + CHECK_FONT_EXTENTS ("HINT_METRICS_OFF"); + + cairo_move_to (cr, 1, font_extents.height - font_extents.descent - 1); + + cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE); + cairo_set_font_options (cr, font_options); + CHECK_FONT_EXTENTS ("HINT_METRICS_OFF HINT_STYLE_NONE"); + cairo_show_text (cr, "the "); + + cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_SLIGHT); + cairo_set_font_options (cr, font_options); + CHECK_FONT_EXTENTS ("HINT_METRICS_OFF HINT_STYLE_SLIGHT"); + cairo_show_text (cr, "quick"); + + cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_MEDIUM); + cairo_set_font_options (cr, font_options); + CHECK_FONT_EXTENTS ("HINT_METRICS_OFF HINT_STYLE_MEDIUM"); + cairo_show_text (cr, " brown"); + + cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_FULL); + cairo_set_font_options (cr, font_options); + CHECK_FONT_EXTENTS ("HINT_METRICS_OFF HINT_STYLE_FULL"); + cairo_show_text (cr, " fox"); + + cairo_text_path (cr, " jumps over"); + cairo_text_path (cr, " a lazy dog"); + cairo_fill (cr); + + cairo_font_options_destroy (font_options); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (bitmap_font, + "Test drawing with a font consisting only of bitmaps" + "\nThe PDF and PS backends embed a slightly distorted font for the rotated case.", + "text", /* keywords */ + "ft", /* requirements */ + 246 + 1, 2 * TEXT_SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/buffer-diff.c b/local/recipes/libs/cairo/source/test/buffer-diff.c new file mode 100644 index 0000000000..0796ca42a6 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/buffer-diff.c @@ -0,0 +1,273 @@ +/* imagediff - Compare two images + * + * Copyright © 2004 Richard D. Worth + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of Richard Worth + * not be used in advertising or publicity pertaining to distribution + * of the software without specific, written prior permission. + * Richard Worth makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * RICHARD WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL RICHARD WORTH BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Richard D. Worth */ + +#include "config.h" + +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#include + +#include "cairo-test.h" + +#include "pdiff.h" +#include "buffer-diff.h" + +/* Don't allow any differences greater than this value, even if pdiff + * claims that the images are identical */ +#define PERCEPTUAL_DIFF_THRESHOLD 25 + +/* Compare two buffers, returning the number of pixels that are + * different and the maximum difference of any single color channel in + * result_ret. + * + * This function should be rewritten to compare all formats supported by + * cairo_format_t. + */ +static void +buffer_diff_core (const unsigned char *_buf_a, int stride_a, cairo_format_t format_a, + const unsigned char *_buf_b, int stride_b, cairo_format_t format_b, + unsigned char *_buf_diff, int stride_diff, cairo_format_t format_diff, + int width, + int height, + buffer_diff_result_t *result_ret) +{ + const uint32_t *buf_a = (const uint32_t*) _buf_a; + const uint32_t *buf_b = (const uint32_t*) _buf_b; + uint32_t *buf_diff = (uint32_t*) _buf_diff; + int x, y; + buffer_diff_result_t result = {0, 0}; + + assert (format_a == CAIRO_FORMAT_RGB24 || format_a == CAIRO_FORMAT_ARGB32); + assert (format_b == CAIRO_FORMAT_RGB24 || format_b == CAIRO_FORMAT_ARGB32); + assert (format_diff == CAIRO_FORMAT_RGB24 || format_diff == CAIRO_FORMAT_ARGB32); + + stride_a /= sizeof (uint32_t); + stride_b /= sizeof (uint32_t); + stride_diff /= sizeof (uint32_t); + for (y = 0; y < height; y++) { + const uint32_t *row_a = buf_a + y * stride_a; + const uint32_t *row_b = buf_b + y * stride_b; + uint32_t *row = buf_diff + y * stride_diff; + + for (x = 0; x < width; x++) { + uint32_t pixel_a = row_a[x]; + uint32_t pixel_b = row_b[x]; + /* convert pixel data to ARGB32 if necessary */ + if (format_a == CAIRO_FORMAT_RGB24) + pixel_a |= 0xff000000; + if (format_b == CAIRO_FORMAT_RGB24) + pixel_b |= 0xff000000; + + /* check if the pixels are the same */ + if (pixel_a != pixel_b) { + int channel; + uint32_t diff_pixel = 0; + + /* calculate a difference value for all 4 channels */ + for (channel = 0; channel < 4; channel++) { + int value_a = (pixel_a >> (channel*8)) & 0xff; + int value_b = (pixel_b >> (channel*8)) & 0xff; + unsigned int diff; + diff = abs (value_a - value_b); + if (diff > result.max_diff) + result.max_diff = diff; + diff *= 4; /* emphasize */ + if (diff) + diff += 128; /* make sure it's visible */ + if (diff > 255) + diff = 255; + diff_pixel |= diff << (channel*8); + } + + result.pixels_changed++; + if ((diff_pixel & 0x00ffffff) == 0) { + /* alpha only difference, convert to luminance */ + uint8_t alpha = diff_pixel >> 24; + diff_pixel = alpha * 0x010101; + } + row[x] = diff_pixel; + } else { + row[x] = 0; + } + row[x] |= 0xff000000; /* Set ALPHA to 100% (opaque) */ + } + } + + *result_ret = result; +} + +/* Compares two image surfaces + * + * Provides number of pixels changed and maximum single-channel + * difference in result. + * + * Also fills in a "diff" surface intended to visually show where the + * images differ. + */ +static void +compare_surfaces (const cairo_test_context_t *ctx, + cairo_surface_t *surface_a, + cairo_surface_t *surface_b, + cairo_surface_t *surface_diff, + buffer_diff_result_t *result) +{ + /* These default values were taken straight from the + * perceptualdiff program. We'll probably want to tune these as + * necessary. */ + double gamma = 2.2; + double luminance = 100.0; + double field_of_view = 45.0; + int discernible_pixels_changed; + + /* First, we run cairo's old buffer_diff algorithm which looks for + * pixel-perfect images, (we do this first since the test suite + * runs about 3x slower if we run pdiff_compare first). + */ + buffer_diff_core (cairo_image_surface_get_data (surface_a), + cairo_image_surface_get_stride (surface_a), + cairo_image_surface_get_format (surface_a), + cairo_image_surface_get_data (surface_b), + cairo_image_surface_get_stride (surface_b), + cairo_image_surface_get_format (surface_b), + cairo_image_surface_get_data (surface_diff), + cairo_image_surface_get_stride (surface_diff), + cairo_image_surface_get_format (surface_diff), + cairo_image_surface_get_width (surface_a), + cairo_image_surface_get_height (surface_a), + result); + if (result->pixels_changed == 0) + return; + + cairo_test_log (ctx, + "%d pixels differ (with maximum difference of %d) from reference image\n", + result->pixels_changed, result->max_diff); + + /* Then, if there are any different pixels, we give the pdiff code + * a crack at the images. If it decides that there are no visually + * discernible differences in any pixels, then we accept this + * result as good enough. + * + * Only let pdiff have a crack at the comparison if the max difference + * is lower than a threshold, otherwise some problems could be masked. + */ + if (result->max_diff < PERCEPTUAL_DIFF_THRESHOLD) { + discernible_pixels_changed = pdiff_compare (surface_a, surface_b, + gamma, luminance, field_of_view); + if (discernible_pixels_changed == 0) { + result->pixels_changed = 0; + cairo_test_log (ctx, + "But perceptual diff finds no visually discernible difference.\n" + "Accepting result.\n"); + } + } +} + +void +buffer_diff_noalpha (const unsigned char *buf_a, + const unsigned char *buf_b, + unsigned char *buf_diff, + int width, + int height, + int stride, + buffer_diff_result_t *result) +{ + buffer_diff_core(buf_a, stride, CAIRO_FORMAT_RGB24, + buf_b, stride, CAIRO_FORMAT_RGB24, + buf_diff, stride, CAIRO_FORMAT_RGB24, + width, height, + result); +} + +static cairo_bool_t +same_size (cairo_surface_t *a, cairo_surface_t *b) +{ + unsigned int width_a, height_a; + unsigned int width_b, height_b; + + width_a = cairo_image_surface_get_width (a); + height_a = cairo_image_surface_get_height (a); + + width_b = cairo_image_surface_get_width (b); + height_b = cairo_image_surface_get_height (b); + + return width_a == width_b && height_a == height_b; +} + +/* Image comparison code courtesy of Richard Worth + * Returns number of pixels changed, (or -1 on error). + * Also saves a "diff" image intended to visually show where the + * images differ. + * + * The return value simply indicates whether a check was successfully + * made, (as opposed to a file-not-found condition or similar). It + * does not indicate anything about how much the images differ. For + * that, see result. + * + * One failure mode is if the two images provided do not have the same + * dimensions. In this case, this function will return + * CAIRO_STATUS_SURFACE_TYPE_MISMATCH (which is a bit of an abuse, but + * oh well). + */ +cairo_status_t +image_diff (const cairo_test_context_t *ctx, + cairo_surface_t *surface_a, + cairo_surface_t *surface_b, + cairo_surface_t *surface_diff, + buffer_diff_result_t *result) +{ + if (cairo_surface_status (surface_a)) + return cairo_surface_status (surface_a); + + if (cairo_surface_status (surface_b)) + return cairo_surface_status (surface_b); + + if (cairo_surface_status (surface_diff)) + return cairo_surface_status (surface_diff); + + if (! same_size (surface_a, surface_b) || + ! same_size (surface_a, surface_diff)) + { + cairo_test_log (ctx, "Error: Image size mismatch\n"); + return CAIRO_STATUS_SURFACE_TYPE_MISMATCH; + } + + compare_surfaces (ctx, surface_a, surface_b, surface_diff, result); + + return CAIRO_STATUS_SUCCESS; +} + +cairo_bool_t +image_diff_is_failure (const buffer_diff_result_t *result, + unsigned int tolerance) +{ + return result->pixels_changed && + result->max_diff > tolerance; +} diff --git a/local/recipes/libs/cairo/source/test/buffer-diff.h b/local/recipes/libs/cairo/source/test/buffer-diff.h new file mode 100644 index 0000000000..2cbb8959ce --- /dev/null +++ b/local/recipes/libs/cairo/source/test/buffer-diff.h @@ -0,0 +1,73 @@ +/* imagediff - Compare two images + * + * Copyright © 2004 Richard D. Worth + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of the authors + * not be used in advertising or publicity pertaining to distribution + * of the software without specific, written prior permission. + * The authors make no representations about the suitability of this + * software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Richard D. Worth + * Carl Worth + */ + +#ifndef BUFFER_DIFF_H +#define BUFFER_DIFF_H + +#include "cairo-test.h" + +typedef struct _buffer_diff_result { + unsigned int pixels_changed; + unsigned int max_diff; +} buffer_diff_result_t; + +/* Compares two image buffers ignoring the alpha channel. + * + * Provides number of pixels changed and maximum single-channel + * difference in result. + * + * Also fills in a "diff" buffer intended to visually show where the + * images differ. + */ +void +buffer_diff_noalpha (const unsigned char *buf_a, + const unsigned char *buf_b, + unsigned char *buf_diff, + int width, + int height, + int stride, + buffer_diff_result_t *result); + +/* The central algorithm to compare two images, and return the differences + * in the surface_diff. + * + * Provides number of pixels changed and maximum single-channel + * difference in result. + */ +cairo_status_t +image_diff (const cairo_test_context_t *ctx, + cairo_surface_t *surface_a, + cairo_surface_t *surface_b, + cairo_surface_t *surface_diff, + buffer_diff_result_t *result); + +cairo_bool_t +image_diff_is_failure (const buffer_diff_result_t *result, + unsigned int tolerance); + +#endif diff --git a/local/recipes/libs/cairo/source/test/bug-277.c b/local/recipes/libs/cairo/source/test/bug-277.c new file mode 100644 index 0000000000..f4de539a44 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/bug-277.c @@ -0,0 +1,94 @@ +/* + * Copyright © 2022 Uli Schlachter + * + * 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: Uli Schlachter + */ + +#include "cairo-test.h" +#include "cairo-script.h" + +struct write_data { + cairo_bool_t finished; + cairo_test_status_t test_status; +}; + +static cairo_surface_t* +create_recording_surface () +{ + /* Create a non-empty recording surface with arbitrary content */ + cairo_surface_t *surf = cairo_recording_surface_create (CAIRO_CONTENT_COLOR, NULL); + cairo_t *cr = cairo_create (surf); + + cairo_move_to (cr, 0, 0); + cairo_line_to (cr, 10, 0); + cairo_stroke (cr); + + cairo_destroy (cr); + return surf; +} + +static cairo_status_t +write_func(void *closure, const unsigned char* bytes, unsigned int length) +{ + struct write_data *data = closure; + (void) bytes; (void) length; + + if (data->finished) + data->test_status = CAIRO_TEST_ERROR; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + struct write_data write_data = { FALSE, CAIRO_TEST_SUCCESS }; + cairo_device_t *script_device = cairo_script_create_for_stream (write_func, &write_data); + cairo_surface_t *recording = create_recording_surface (); + cairo_surface_t *script; + cairo_t *cr; + + /* Draw the recording surface to a script surface */ + script = cairo_script_surface_create (script_device, CAIRO_CONTENT_COLOR, 5, 5); + cr = cairo_test_create (script, ctx); + cairo_set_source_surface (cr, recording, 0, 0); + cairo_paint (cr); + cairo_destroy (cr); + cairo_surface_destroy (script); + + /* Finish the script device; no further writing allowed afterwards */ + cairo_device_finish (script_device); + write_data.finished = TRUE; + cairo_device_destroy (script_device); + + cairo_surface_destroy (recording); + + return write_data.test_status; +} + +CAIRO_TEST (bug_277, + "Regression test: Script surface emitting test after finish()", + NULL, /* keywords */ + NULL, /* requirements */ + 0, 0, + preamble, NULL) diff --git a/local/recipes/libs/cairo/source/test/bug-361.c b/local/recipes/libs/cairo/source/test/bug-361.c new file mode 100644 index 0000000000..a0499223ee --- /dev/null +++ b/local/recipes/libs/cairo/source/test/bug-361.c @@ -0,0 +1,111 @@ +/* + * Copyright © 2019 Uli Schlachter + * + * 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. + */ + +#include "cairo-test.h" + +/* This is basically gears.shape.arrow */ +static void +shape (cairo_t *cr, double width, double height) +{ + double shaft_length = height / 2; + double shaft_width = width / 2; + double head_width = width; + double head_length = height - shaft_length; + + cairo_move_to (cr, width / 2, 0); + cairo_rel_line_to (cr, head_width / 2, head_length); + cairo_rel_line_to (cr, -(head_width - shaft_width) / 2, 0); + cairo_rel_line_to (cr, 0, shaft_length); + cairo_rel_line_to (cr, -shaft_width, 0); + cairo_rel_line_to (cr, 0, -shaft_length); + cairo_rel_line_to (cr, -(head_width - shaft_width) / 2, 0); + cairo_close_path (cr); +} + +/* This is basically the drawing routine of wibox.container.background */ +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + double bw = 1.5; + + cairo_push_group_with_content (cr, CAIRO_CONTENT_COLOR_ALPHA); + + /* Draw background */ + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_paint (cr); + + /* Create shape */ + cairo_translate (cr, bw, bw); + shape (cr, width - 2 * bw, height - 2 * bw); + cairo_translate (cr, -bw, -bw); + + /* Now do the border */ + + cairo_push_group_with_content (cr, CAIRO_CONTENT_ALPHA); + + /* Mark everything as "is border" */ + cairo_set_source_rgba (cr, 0, 0, 0, 1); + cairo_paint (cr); + + /* Remove inside of the shape */ + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgba (cr, 0, 0, 0, 0); + cairo_fill_preserve (cr); + + cairo_pattern_t *mask = cairo_pop_group (cr); + + /* Now actually draw the border via the mask */ + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_mask (cr, mask); + + cairo_pattern_destroy (mask); + + /* We now have the right content in a temporary surface. Copy it to the + * target surface. Needs another mask. + */ + cairo_push_group_with_content (cr, CAIRO_CONTENT_ALPHA); + + cairo_set_line_width (cr, 2 * bw); + cairo_set_source_rgba (cr, 0, 0, 0, 1); + cairo_stroke_preserve (cr); + cairo_fill (cr); + + mask = cairo_pop_group (cr); + cairo_pop_group_to_source (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_mask (cr, mask); + + cairo_pattern_destroy (mask); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (bug_361, + "Bug 361 (Problem with SVG backend and masks)", + "mask, operator", /* keywords */ + NULL, /* requirements */ + 100, 100, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/bug-40410.c b/local/recipes/libs/cairo/source/test/bug-40410.c new file mode 100644 index 0000000000..2d6e512c03 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/bug-40410.c @@ -0,0 +1,72 @@ +/* + * Copyright © 2011 Krzysztof KosiÅ„ski + * + * 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: Krzysztof KosiÅ„ski + */ + +#include "cairo-test.h" + +#define WIDTH 300 +#define HEIGHT 100 + +/* + * The bug appears to be triggered if: + * 1. There is more than one subpath + * 2. All subpaths are axis-aligned rectangles + * 3. Only one of the subpaths is within surface bounds + * + * Tweaking any of the coordinates so that there is at least one + * non-axis-aligned segment or removing the second subpath (the one that is + * outside the surface bounds) causes the bug to disappear. + */ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1,1,1); + cairo_paint (cr); + + cairo_move_to (cr, 10.3, 10.6); + cairo_line_to (cr, 10.3, 150.2); + cairo_line_to (cr, 290.1, 150.2); + cairo_line_to (cr, 290.1, 10.6); + cairo_close_path (cr); + + cairo_move_to (cr, 10.3, 180.7); + cairo_line_to (cr, 10.3, 230.2); + cairo_line_to (cr, 290.1, 230.2); + cairo_line_to (cr, 290.1, 180.7); + cairo_close_path (cr); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (bug_40410, + "Exercises a bug found in 1.10.2 (and never again!)", + "fill", /* keywords */ + "target=raster", /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/bug-431.c b/local/recipes/libs/cairo/source/test/bug-431.c new file mode 100644 index 0000000000..717b03b7fe --- /dev/null +++ b/local/recipes/libs/cairo/source/test/bug-431.c @@ -0,0 +1,68 @@ +/* + * Copyright © 2021 Lome More + * + * 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. + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_matrix_t test_matrix; + test_matrix.xx = 614; + test_matrix.yx = 0; + test_matrix.xy = 0; + test_matrix.yy = -794; + test_matrix.x0 = -1.3831; + test_matrix.y0 = 793; + cairo_set_matrix(cr, &test_matrix); + + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_surface_t *png_surface = cairo_test_create_surface_from_png (ctx, "romedalen.png"); + cairo_pattern_t *png_pattern = cairo_pattern_create_for_surface(png_surface); + cairo_matrix_t matrix; + matrix.xx = 1228; + matrix.yx = 0; + matrix.xy = 0; + matrix.yy = -1590; + matrix.x0 = 0; + matrix.y0 = 1590; + cairo_pattern_set_matrix (png_pattern, &matrix); + cairo_pattern_t *mask_pattern = cairo_pattern_create_rgba (1.0, 1.0, 1.0, 0.15); + cairo_save(cr); + cairo_set_source(cr, png_pattern); + cairo_mask(cr, mask_pattern); + cairo_restore(cr); + + cairo_surface_destroy (png_surface); + cairo_pattern_destroy (png_pattern); + cairo_pattern_destroy (mask_pattern); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (bug_431, + "Bug 431 (Different result on SVG surface)", + "", /* keywords */ + NULL, /* requirements */ + 128, 96, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/bug-448.c b/local/recipes/libs/cairo/source/test/bug-448.c new file mode 100644 index 0000000000..1a459ab5fc --- /dev/null +++ b/local/recipes/libs/cairo/source/test/bug-448.c @@ -0,0 +1,76 @@ +/* + * Copyright © 2020 Ben Pfaff & Uli Schlachter + * + * 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. + * + * Authors: + * Ben Pfaff + * Uli Schlachter + */ + +#include "cairo-test.h" + +static cairo_surface_t* +draw_recording () +{ + cairo_surface_t *recording; + cairo_rectangle_t extents; + cairo_t *cr; + + extents.x = 0; + extents.y = 0; + extents.width = 10; + extents.height = 10; + + recording = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, &extents); + + cr = cairo_create(recording); + cairo_tag_begin (cr, CAIRO_TAG_DEST, "name='dest'"); + cairo_rectangle (cr, 3, 3, 4, 4); + cairo_stroke (cr); + cairo_tag_end (cr, CAIRO_TAG_DEST); + cairo_destroy(cr); + + return recording; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *recording; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + recording = draw_recording (); + cairo_set_source_surface (cr, recording, 0, 0); + cairo_paint (cr); + cairo_surface_destroy (recording); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (bug_448, + "Exercises a bug with the tag API", + "pdf", /* keywords */ + NULL, /* requirements */ + 10, 10, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/bug-51910.c b/local/recipes/libs/cairo/source/test/bug-51910.c new file mode 100644 index 0000000000..37881de3e3 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/bug-51910.c @@ -0,0 +1,91 @@ +/* + * Copyright © 2012 Intel Corporation + * + * 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. + */ + +#include "cairo-test.h" + +/* An error in xlib pattern transformation discovered by Albertas VyÅ¡niauskas */ + +static cairo_pattern_t * +source(void) +{ + cairo_surface_t *surface; + cairo_pattern_t *pattern; + cairo_matrix_t matrix; + cairo_t *cr; + int i; + + surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 32, 32); + cr = cairo_create (surface); + cairo_surface_destroy (surface); + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_set_source_rgb (cr, .5, .5, .5); + cairo_set_line_width (cr, 2); + + for (i = -1; i <= 8; i++) { + cairo_move_to (cr, -34 + 8*i, 34); + cairo_rel_line_to (cr, 36, -36); + cairo_stroke (cr); + } + + pattern = cairo_pattern_create_for_surface (cairo_get_target (cr)); + cairo_destroy (cr); + + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT); + + cairo_matrix_init_translate(&matrix, 14.1, 0); + cairo_pattern_set_matrix(pattern, &matrix); + + return pattern; +} + + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *pattern; + int i; + + cairo_paint (cr); + + pattern = source (); + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + + for (i = 0; i < 8; i++) { + cairo_rectangle (cr, 3.5*i, 32*i, 256, 32); + cairo_fill (cr); + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (bug_51910, + "A bug in the xlib pattern transformation", + " paint", /* keywords */ + NULL, /* requirements */ + 256, 256, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/bug-535.c b/local/recipes/libs/cairo/source/test/bug-535.c new file mode 100644 index 0000000000..5283b2ec7d --- /dev/null +++ b/local/recipes/libs/cairo/source/test/bug-535.c @@ -0,0 +1,51 @@ +/* + * Copyright © 2022 Uli Schlachter, Antony Lee + * + * 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: Uli Schlachter + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + // Once upon a time, the "rectangle detection" in cairo-script was triggered + // by this degenerate rectangle and produces CAIRO_STATUS_INVALID_PATH_DATA. + + cairo_move_to (cr, 0, 0); + cairo_line_to (cr, 9, 0); + cairo_fill (cr); + + // Fill the whole surface so that argb32 and rgb24 can share a ref image + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (bug_535, + "Regression test for bug #535 in cairo-svg", + "degenerate", /* keywords */ + NULL, /* requirements */ + 1, 1, + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/bug-75705.c b/local/recipes/libs/cairo/source/test/bug-75705.c new file mode 100644 index 0000000000..e140ff9931 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/bug-75705.c @@ -0,0 +1,32 @@ +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + double dsh[2] = {1,3}; + + cairo_set_source_rgba (cr, 0, 0, 0, 1); + cairo_paint (cr); + + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + + cairo_move_to (cr, 3, 3); + /* struct glitter_scan_converter spans_embedded array size is 64 */ + cairo_line_to (cr, 65+3, 3); + + cairo_set_antialias (cr, CAIRO_ANTIALIAS_FAST); + cairo_set_tolerance (cr, 1); + + cairo_set_dash (cr, dsh, 2, 0); + cairo_set_line_width (cr, 2); + + cairo_stroke (cr); + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (bug_75705, + "Bug 75705 (exercise tor22-scan-converter)", + "dash, stroke, antialias", /* keywords */ + NULL, /* requirements */ + 72, 8, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/bug-84115.c b/local/recipes/libs/cairo/source/test/bug-84115.c new file mode 100644 index 0000000000..4db113c5c1 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/bug-84115.c @@ -0,0 +1,61 @@ +/* + * Copyright © 2011 Krzysztof KosiÅ„ski + * + * 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: Krzysztof KosiÅ„ski + */ + +#include "cairo-test.h" + +#define WIDTH 800 +#define HEIGHT 800 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + double lw = 800; + int n = 0; + + cairo_set_source_rgb (cr, 1,1,1); + cairo_paint (cr); + + cairo_set_source_rgba (cr, 0, 0, 0, .4); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + do { + cairo_set_line_width(cr, lw); + cairo_arc(cr, WIDTH/2, HEIGHT/2, lw/2, + 2*M_PI*(13*n + 1) / 130, 2*M_PI*(13*n + 12) / 130); + cairo_stroke(cr); + + n++; + lw /= 1.1; + } while (lw > 0.5); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (bug_84115, + "Exercises a bug found in stroke generation using trapezoids", + "stroke", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/bug-bo-collins.c b/local/recipes/libs/cairo/source/test/bug-bo-collins.c new file mode 100644 index 0000000000..cf6d688e31 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/bug-bo-collins.c @@ -0,0 +1,76 @@ +/* + * Copyright © 2012 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + + cairo_translate (cr, 0, 0); + cairo_save (cr); + cairo_rectangle (cr, 10, 10, 20, 20); + cairo_rectangle (cr, 20, 10, -10, 10); + cairo_clip (cr); + cairo_paint (cr); + cairo_restore (cr); + + cairo_translate (cr, 40, 0); + cairo_save (cr); + cairo_rectangle (cr, 10, 10, 20, 20); + cairo_rectangle (cr, 30, 10, -10, 10); + cairo_clip (cr); + cairo_paint (cr); + cairo_restore (cr); + + cairo_translate (cr, 0, 40); + cairo_save (cr); + cairo_rectangle (cr, 10, 10, 20, 20); + cairo_rectangle (cr, 30, 20, -10, 10); + cairo_clip (cr); + cairo_paint (cr); + cairo_restore (cr); + + cairo_translate (cr, -40, 0); + cairo_save (cr); + cairo_rectangle (cr, 10, 10, 20, 20); + cairo_rectangle (cr, 20, 20, -10, 10); + cairo_clip (cr); + cairo_paint (cr); + cairo_restore (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (bug_bo_collins, + "Exercises a bug discovered by S. Christian Collins", + "clip, rectangular", /* keywords */ + NULL, /* requirements */ + 80, 80, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/bug-bo-rectangular.c b/local/recipes/libs/cairo/source/test/bug-bo-rectangular.c new file mode 100644 index 0000000000..08e2e494aa --- /dev/null +++ b/local/recipes/libs/cairo/source/test/bug-bo-rectangular.c @@ -0,0 +1,67 @@ +/* + * Copyright 2010 Red Hat + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Intel not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Intel makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Benjamin Otte + */ + +#include "cairo-test.h" + +static void +rect (cairo_t *cr, int x1, int y1, int x2, int y2) +{ + cairo_rectangle (cr, x1, y1, x2 - x1, y2 - y1); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + + cairo_scale (cr, 1./256, 1./256); + + rect (cr, 0, 0, 29696, 7680); + rect (cr, 0, 0, -15360, 15360); + cairo_clip (cr); + + cairo_set_source_rgb (cr, 1, 0.5, 0); + cairo_paint (cr); + + rect (cr, 9984, 0, 2969, 3840); + rect (cr, 0, 3840, 9472, 7680); + cairo_clip (cr); + + rect (cr, 0, 3840, 3584, 7680); + cairo_set_source_rgb (cr, 1, 0, 0.5); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (bug_bo_rectangular, + "Tests a bug found by Benjamin Otte in the rectangular tessellator", + "tessellator", /* keywords */ + NULL, /* requirements */ + 300, 300, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/bug-bo-ricotz.c b/local/recipes/libs/cairo/source/test/bug-bo-ricotz.c new file mode 100644 index 0000000000..9524d208de --- /dev/null +++ b/local/recipes/libs/cairo/source/test/bug-bo-ricotz.c @@ -0,0 +1,74 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +/* An assertion failure found by Rico Tzschichholz */ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + + cairo_rectangle (cr, 10, 55,165, 1); + cairo_rectangle (cr, 174, 55,1, 413); + cairo_rectangle (cr, 10, 56, 1, 413); + cairo_rectangle (cr, 10, 469, 165, 1); + cairo_clip (cr); + + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + + cairo_move_to (cr, 10, 57); + cairo_curve_to (cr, 10, 55.894531, 10.894531, 55, 12, 55); + cairo_line_to (cr, 173, 55); + cairo_curve_to (cr, 174.105469, 55, 175, 55.894531, 175, 57); + cairo_line_to (cr, 175, 468); + cairo_curve_to (cr, 175, 469.105469, 174.105469, 470, 173, 470); + cairo_line_to (cr, 12, 470); + cairo_curve_to (cr, 10.894531, 470, 10, 469.105469, 10, 468); + + cairo_move_to (cr, 11, 57); + cairo_curve_to (cr, 11, 56.449219, 11.449219, 56, 12, 56); + cairo_line_to (cr, 173, 56); + cairo_curve_to (cr, 173.550781, 56, 174, 56.449219, 174, 57); + cairo_line_to (cr, 174, 468); + cairo_curve_to (cr, 174, 468.550781, 173.550781, 469, 173, 469); + cairo_line_to (cr, 12, 469); + cairo_curve_to (cr, 11.449219, 469, 11, 468.550781, 11, 468); + + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (bug_bo_ricotz, + "Exercises a bug discovered by Rico Tzschichholz", + "clip, fill", /* keywords */ + NULL, /* requirements */ + 649, 480, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/bug-extents.c b/local/recipes/libs/cairo/source/test/bug-extents.c new file mode 100644 index 0000000000..4edb4a548b --- /dev/null +++ b/local/recipes/libs/cairo/source/test/bug-extents.c @@ -0,0 +1,59 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright 2010 Andrea Canciani + * + * 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: Andrea Canciani + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_translate (cr, 0, -25); + + cairo_move_to (cr, 50, 200); + cairo_curve_to (cr, 50, 150, 100, 50, 150, 50); + cairo_curve_to (cr, 200, 50, 250, 250, 200, 250); + cairo_curve_to (cr, 150, 250, 200, 50, 50, 100); + cairo_curve_to (cr, -100, 150, 200, 150, 200, 200); + cairo_curve_to (cr, 200, 250, 50, 250, 50, 200); + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_fill_preserve (cr); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (bug_extents, + "Tests a bug in the computation of approximate extents", + "extents", /* keywords */ + NULL, /* requirements */ + 250, 250, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/bug-image-compositor.c b/local/recipes/libs/cairo/source/test/bug-image-compositor.c new file mode 100644 index 0000000000..304ea089cb --- /dev/null +++ b/local/recipes/libs/cairo/source/test/bug-image-compositor.c @@ -0,0 +1,66 @@ +/* + * Copyright © 2020 Uli Schlachter, Heiko Lewin + * + * 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: Uli Schlachter + * Author: Heiko Lewin + */ +#include "cairo-test.h" + + +/* This test reproduces an overflow of a mask-buffer in cairo-image-compositor.c */ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 0., 0., 0.); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 1., 1., 1.); + cairo_set_line_width (cr, 1.); + + cairo_pattern_t *p = cairo_pattern_create_linear (0, 0, width, height); + cairo_pattern_add_color_stop_rgb (p, 0, 0.99, 1, 1); + cairo_pattern_add_color_stop_rgb (p, 1, 1, 1, 1); + cairo_set_source (cr, p); + cairo_pattern_destroy(p); + + cairo_move_to (cr, 0.5, -1); + for (int i = 0; i < width; i+=3) { + cairo_rel_line_to (cr, 2, 2); + cairo_rel_line_to (cr, 1, -2); + } + + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + + +CAIRO_TEST (bug_image_compositor, + "Crash in image-compositor", + "stroke, stress", /* keywords */ + NULL, /* requirements */ + 10000, 1, + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/bug-seams.c b/local/recipes/libs/cairo/source/test/bug-seams.c new file mode 100644 index 0000000000..01e84ff060 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/bug-seams.c @@ -0,0 +1,120 @@ +/* + * Copyright 2010 Soeren Sandmann Pedersen + * + * 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: Soeren Sandmann + */ + +/* Exercises a case of seam appearing between two polygons in the image + * backend but not in xlib [using pixman]. + * + * The test case draws two abutting quads both individually on the + * leftm combining them with operator ADD, and in one go on the right. + * Both methods should show no signs of seaming at the common edge + * between the two quads, but the individually drawn ones have a + * slight seam. + * + * The cause of the seam is that there are slight differences in the + * output of the analytical coverage rasterization and the + * supersampling rasterization methods, both employed by + * cairo-tor-scan-converter. When drawn individually, the scan + * converter gets a partial view of the geometry at a time, so it ends + * up making different decisions about which scanlines it rasterizes + * with which method, compared to when the geometry is draw all at + * once. Though both methods produce seamless results individually + * (where applicable), they don't produce bit-exact identical results, + * and hence we get seaming where they meet. + */ + +#include "cairo-test.h" + +static void +draw_quad (cairo_t *cr, + double x1, double y1, double x2, double y2, + double x3, double y3, double x4, double y4) +{ + cairo_move_to (cr, x1, y1); + cairo_line_to (cr, x2, y2); + cairo_line_to (cr, x3, y3); + cairo_line_to (cr, x4, y4); + cairo_close_path (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + cairo_scale (cr, 20, 20); + cairo_translate (cr, 5, 1); + + /* On the left side, we have two quads drawn one at a time and + * combined with OPERATOR_ADD. This should be seamless, but + * isn't. */ + cairo_push_group (cr); + cairo_set_operator (cr, CAIRO_OPERATOR_ADD); + + cairo_set_source_rgb (cr, 0, 0.6, 0); + draw_quad (cr, + 1.50, 1.50, + 2.64, 1.63, + 1.75, 2.75, + 0.55, 2.63); + cairo_fill (cr); + draw_quad (cr, + 0.55, 2.63, + 1.75, 2.75, + 0.98, 4.11, + -0.35, 4.05); + cairo_fill (cr); + + cairo_pop_group_to_source (cr); + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_paint (cr); + + /* On the right side, we have the same two quads drawn both at the + * same time. This is seamless. */ + cairo_translate (cr, 10, 0); + + cairo_set_source_rgb (cr, 0, 0.6, 0); + draw_quad (cr, + 1.50, 1.50, + 2.64, 1.63, + 1.75, 2.75, + 0.55, 2.63); + draw_quad (cr, + 0.55, 2.63, + 1.75, 2.75, + 0.98, 4.11, + -0.35, 4.05); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (bug_seams, + "Check the fidelity of the rasterisation.", + "raster", /* keywords */ + "target=raster", /* requirements */ + 500, 300, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/bug-source-cu.c b/local/recipes/libs/cairo/source/test/bug-source-cu.c new file mode 100644 index 0000000000..4c1e2bc633 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/bug-source-cu.c @@ -0,0 +1,81 @@ +/* + * 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. + */ + +#include "cairo-test.h" + +static cairo_pattern_t * +create_pattern (cairo_surface_t *target) +{ + cairo_surface_t *surface; + cairo_pattern_t *pattern; + cairo_t *cr; + cairo_matrix_t m; + + surface = cairo_surface_create_similar(target, + cairo_surface_get_content (target), + 1000, 600); + cr = cairo_create (surface); + cairo_surface_destroy (surface); + + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_paint(cr); + + pattern = cairo_pattern_create_for_surface (cairo_get_target (cr)); + cairo_destroy(cr); + + cairo_matrix_init_translate (&m, 0, 0.1); // y offset must be non-integer + cairo_pattern_set_matrix (pattern, &m); + return pattern; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *pattern; + + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_paint (cr); + + cairo_new_path (cr); + cairo_move_to (cr, 10, 400.1); + cairo_line_to (cr, 990, 400.1); + cairo_line_to (cr, 990, 600); + cairo_line_to (cr, 10, 600); + cairo_close_path (cr); + + pattern = create_pattern (cairo_get_target (cr)); + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + + cairo_fill(cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (bug_source_cu, + "Exercises a bug discovered in the tracking of unbounded source extents", + "fill", /* keywords */ + NULL, /* requirements */ + 1000, 600, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/bug-spline.c b/local/recipes/libs/cairo/source/test/bug-spline.c new file mode 100644 index 0000000000..9a54a7c8cd --- /dev/null +++ b/local/recipes/libs/cairo/source/test/bug-spline.c @@ -0,0 +1,95 @@ +/* cc `pkg-config --cflags --libs cairo` cairo-spline-image.c -o cairo-spline-image */ + +/* Copyright © 2005 Carl Worth + * Copyright © 2012 Intel Corporation + * + * 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. + */ + +#include "cairo-test.h" + +#define WIDE_LINE_WIDTH 160 +#define NARROW_LINE_WIDTH 2 + +/* A spline showing bugs in the "contour-based stroking" in cairo 1.12 */ +static const struct spline { + struct { double x, y; } pt[5]; + double line_width; + double rgba[4]; +} splines[] = { + { + { + { 172.25, 156.185 }, + { 177.225, 164.06 }, + { 176.5, 157.5 }, + { 175.5, 159.5 }, + }, + WIDE_LINE_WIDTH, + { 1, 1, 1, 1 }, + }, + { + { + { 571.25, 247.185 }, + { 78.225, 224.06 }, + { 129.5, 312.5 }, + { 210.5, 224.5 }, + }, + NARROW_LINE_WIDTH, + { 1, 0, 0, 1 }, + } +}; + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + unsigned n; + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE); + + for (n = 0; n < ARRAY_LENGTH(splines); n++) { + cairo_set_line_width (cr, splines[n].line_width); + cairo_set_source_rgba (cr, + splines[n].rgba[0], + splines[n].rgba[1], + splines[n].rgba[2], + splines[n].rgba[3]); + + cairo_move_to (cr, splines[n].pt[0].x, splines[n].pt[0].y); + cairo_curve_to (cr, + splines[n].pt[1].x, splines[n].pt[1].y, + splines[n].pt[2].x, splines[n].pt[2].y, + splines[n].pt[3].x, splines[n].pt[3].y); + + cairo_stroke (cr); + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (bug_spline, + "Exercises a bug in the stroking of splines", + "spline, stroke", /* keywords */ + NULL, /* requirements */ + 300, 300, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/cairo-logo-font.ttx b/local/recipes/libs/cairo/source/test/cairo-logo-font.ttx new file mode 100644 index 0000000000..9e4b832c0e --- /dev/null +++ b/local/recipes/libs/cairo/source/test/cairo-logo-font.ttx @@ -0,0 +1,539 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Cairo Logo + + + Regular + + + Cairo Logo Regular + + + + + + + + + + + + + + + + + + + + <svg xmlns="http://www.w3.org/2000/svg"></svg> + + + <?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="310" height="508"> + <defs id="cairo-artwork_defs"> + <g id="hacker_emblem"> + <!-- Note: This is similar though not identical to Keith Packard's SVG version + of the hacker emblem (http://www.catb.org/hacker-emblem/glider.svg) --> + <g id="hacker_emblem_grid" fill="white" stroke="none"> + <!-- Outside: Top, Right, Bottom, Left --> + <rect x="-2.95" y="-3.05" width="6" height="0.1" /> + <rect x="2.95" y="-2.95" width="0.1" height="6" /> + <rect x="-3.05" y="2.95" width="6" height="0.1" /> + <rect x="-3.05" y="-3.05" width="0.1" height="6" /> + <!-- Vertical: Left, Right --> + <rect x="-1.05" y="-2.95" width="0.1" height="5.9" /> + <rect x="0.95" y="-2.95" width="0.1" height="5.9" /> + <!-- Horizontal: TopLeft, TopMiddle, TopRight --> + <rect x="-2.95" y="-1.05" width="1.9" height="0.1" /> + <rect x="-0.95" y="-1.05" width="1.9" height="0.1" /> + <rect x="1.05" y="-1.05" width="1.9" height="0.1" /> + <!-- Horizontal: BottomLeft, BottomMiddle, BottomRight --> + <rect x="-2.95" y="0.95" width="1.9" height="0.1" /> + <rect x="-0.95" y="0.95" width="1.9" height="0.1" /> + <rect x="1.05" y="0.95" width="1.9" height="0.1" /> + </g> + <g id="hacker_emblem_dots" fill="white"> + <circle cx="0" cy="-2" r="0.7" /> + <circle cx="2" cy="0" r="0.7" /> + <circle cx="-2" cy="2" r="0.7" /> + <circle cx="0" cy="2" r="0.7" /> + <circle cx="2" cy="2" r="0.7" /> + </g> + </g> + <g id="scarab" fill="#3B80AE"> + <g transform="translate(-150, -170)"> + <path id="scarab_head" d="M205.599,94.567c0-11.668-24.914-21.129-55.628-21.129 + c-30.723,0-55.624,9.46-55.624,21.129c0,10.203,24.901,7.346,55.624,7.346C180.685,101.913,205.599,104.233,205.599,94.567z"/> + <path id="scarab_torso" d="M136.423,161.506c0,0,12.751,12.577,13.547,13.362 + c2.262-2.232,13.545-13.362,13.545-13.362c7.135-7.036,87.111-6.399,91.066-6.363c-0.469-6.298-1.254-12.472-2.325-18.519 + c-15.183-19.279-42.811-32.225-74.485-32.225h-55.518c-31.745,0-59.439,13.011-74.598,32.37c-1.054,6-1.829,12.128-2.296,18.374 + C49.321,155.106,129.288,154.47,136.423,161.506z"/> + <path id="scarab_spine" d="M149.97,301.187c2.005-24.729,8.386-103.483,8.405-103.721 + c-0.09-0.219-6.478-15.578-8.405-20.214c-1.936,4.655-8.316,19.995-8.408,20.214C141.582,197.704,147.965,276.458,149.97,301.187z"/> + <path id="scarab_wing_left" d="M140.403,197.149l8.862-21.31l-13.686-13.499 + c-5.65-5.573-67.074-6.235-90.259-6.019l-0.006-0.622c-0.154,2.144-0.271,4.302-0.35,6.475 + c-0.076,2.207,10.392,4.706,10.392,6.717c0,2.319-10.457,5.084-10.359,7.631c2.993,73.349,48.53,131.631,104.372,132.048 + l-9.02-111.29L140.403,197.149z"/> + <path id="scarab_wing_right" d="M244.585,168.891c0-2.011,10.467-4.506,10.391-6.715 + c-0.079-2.174-0.195-4.332-0.351-6.479l-0.004,0.624c-23.186-0.216-84.608,0.445-90.26,6.017l-13.688,13.502l8.915,21.438 + l-9.017,111.29c55.854-0.417,101.378-58.698,104.373-132.049C255.04,173.976,244.585,171.209,244.585,168.891z"/> + <path id="scarab_leg_front_left" d="M44.506,141.12c-4.135-0.856-4.895-1.54-7.935-2.92 + c-9.59-3.364-10.376-5.481-16.08-11.86c-7.426-8.306-12.661-20.142-17.1-29.463c-3.576-7.525-3.984-16.409-2.86-24.273 + c0.991-6.935,7.144-12.869,12.074-18.92c5.844-7.191,10.356-14.822,17.924-21.354c7.736-6.682,23.203-9.809,26.168-19.648 + C57.86,8.819,54.334,1.766,61.482,0c-0.366,4.703,3.639,8.477,2.397,13.575c-1.129,4.627-4.368,5.811-9.611,9.099 + c-7.564,4.746-18.366,8.779-24.748,13.965c-7.175,5.827-4.369,13.771-10.569,20.057c-2.001,2.03-7.901,4.706-9.137,6.83 + c-1.861,3.199-0.297,9.572-0.116,13.12c0.425,8.284,5.588,14.244,9.555,22.045c4.152,8.141,6.429,15.409,13.411,22.519 + c4.183,4.262,11.429,4.802,16.21,10.647l-3.555,4.186L44.506,141.12z"/> + <path id="scarab_leg_middle_left" d="M43.94,191.922l-0.809-7.346 + c-9.506-4.579-10.339-9.772-20.738-12.466c-23.728-6.151-21.361,11.25-15.532,26.373c5.676,14.726,8.237,30.23,14.345,44.795 + c2.805,6.688,6.919,13.213,14.298,15.127c0.372-8.435-0.917-10.651-6.113-16.919c-4.395-5.293-3.326-12.548-6.072-18.504 + c-3.581-7.804-4.196-15.646-7.279-23.502c-1.363-3.479-8.33-13.966-6.452-17.861c3.183-6.603,9.178-0.083,12.179,2.077 + c4.218,3.036,6.467,2.223,11.681,2.898C34.041,186.673,37.005,188.756,43.94,191.922z"/> + <path id="scarab_leg_back_left" d="M65.839,257.063l-2.771-4.837 + c-6.68,8.928-6.993,16.228-10.056,23.347c-5.277,12.263-0.157,28.851,9.854,37.676c6.052,5.375,15.907,9.618,23.122,13.136 + c10.035,4.892,20.113,11.286,31.336,13.396c2.482,0.466,8.798,1.295,6.693-3.522c-0.975-2.237-8.091-4.591-10.146-5.734 + c-8.312-4.623-16.377-10.524-24.142-16.176c-9.498-6.862-20.843-11.186-28.311-20.684c-3.054-3.885-3.544-4.922-2.816-9.39 + c0.693-4.263,1.344-9.174,2.241-13.439C61.855,266.029,63.274,261.378,65.839,257.063z"/> + <path id="scarab_leg_front_right" d="M255.487,141.12c4.134-0.856,4.896-1.54,7.936-2.92 + c9.583-3.364,10.369-5.481,16.071-11.86c7.428-8.306,12.661-20.142,17.115-29.463c3.574-7.525,3.983-16.409,2.86-24.273 + c-0.992-6.935-7.157-12.869-12.087-18.92c-5.843-7.191-10.356-14.822-17.919-21.354c-7.735-6.682-23.202-9.809-26.167-19.648 + C242.135,8.819,245.66,1.766,238.511,0c0.366,4.703-3.637,8.477-2.396,13.575c1.131,4.627,4.368,5.811,9.611,9.099 + c7.563,4.746,18.367,8.779,24.747,13.965c7.17,5.827,4.362,13.771,10.563,20.057c2.001,2.03,7.901,4.706,9.139,6.83 + c1.859,3.199,0.295,9.572,0.113,13.12c-0.424,8.284-5.588,14.244-9.553,22.045c-4.152,8.141-6.431,15.409-13.404,22.519 + c-4.184,4.262-11.429,4.802-16.211,10.647l3.556,4.186L255.487,141.12z"/> + <path id="scarab_leg_middle_right" d="M256.053,191.922l0.81-7.346 + c9.507-4.579,10.34-9.772,20.73-12.466c23.741-6.151,21.374,11.25,15.534,26.373c-5.676,14.726-8.238,30.23-14.347,44.795 + c-2.804,6.688-6.911,13.213-14.291,15.127c-0.371-8.435,0.918-10.651,6.113-16.919c4.39-5.293,3.319-12.548,6.066-18.504 + c3.58-7.804,4.197-15.646,7.278-23.502c1.363-3.479,8.33-13.966,6.453-17.861c-3.184-6.603-9.179-0.083-12.181,2.077 + c-4.217,3.036-6.458,2.223-11.672,2.898C265.951,186.673,262.986,188.756,256.053,191.922z"/> + <path id="scarab_leg_back_right" d="M234.155,257.063l2.771-4.837 + c6.679,8.928,6.991,16.228,10.057,23.347c5.274,12.263,0.154,28.851-9.854,37.676c-6.055,5.375-15.903,9.618-23.117,13.136 + c-10.034,4.892-20.127,11.286-31.351,13.396c-2.481,0.466-8.789,1.295-6.691-3.522c0.976-2.237,8.092-4.591,10.146-5.734 + c8.312-4.623,16.392-10.524,24.155-16.176c9.498-6.862,20.838-11.186,28.305-20.684c3.055-3.885,3.543-4.922,2.818-9.39 + c-0.696-4.263-1.346-9.174-2.244-13.439C238.137,266.029,236.718,261.378,234.155,257.063z"/> + </g> + </g> + <radialGradient id="gradient_radial_dung" + cx="0" cy="0" r="60" + fx="0" fy="0" gradientUnits="userSpaceOnUse" + > + <stop offset="0" stop-color="#9a9a9a" /> + <stop offset="0.70" stop-color="#bababa" /> + <stop offset="0.95" stop-color="#FFFFFF" /> + </radialGradient> + <g id="dung"> + <circle cx="0" cy="0" r="60" fill="url(#gradient_radial_dung)" /> + <g transform="translate(-61, -61)"> + <!-- rough equivalent: <circle cx="0" cy="0" r="60" stroke="#8a8a8a" stroke-width="2" /> --> + <path fill="#8a8a8a" d="M0,61c0,33.636,27.364,61,61,61s61-27.364,61-61S94.636,0,61,0S0,27.364,0,61z + M2,61C2,28.467,28.467,2,61,2c32.532,0,59,26.467,59,59c0,32.533-26.468,59-59,59C28.467,120,2,93.533,2,61z"/> + </g> + <use xlink:href="#hacker_emblem" x="0" y="0" transform="scale(9)" /> + </g> + + <!-- scarab dimensions: 300x340 --> + <!-- dung dimensions: 120x120 (radius: 60) --> + <!-- scarab and dung dimensions: 300x400 --> + + <g id="cairo_logo"> + <!-- dimensions: 300x400, centered --> + <!-- The logo (scarab and dung), with the center-point of the bounding box at (0,0) --> + <use xlink:href="#dung" x="0" y="0" transform="translate(0, -140)" /> + <use xlink:href="#scarab" x="0" y="0" transform="translate(0, 30)" /> + </g> + <g id="cairo_logo_dung-centered"> + <!-- The logo (scarab and dung), with the dung at (0,0), the scarab below --> + <use xlink:href="#dung" x="0" y="0" /> + <use xlink:href="#scarab" x="0" y="0" transform="translate(0,170)" /> + </g> + <g id="cairo_logo_scarab-centered"> + <!-- The logo (scarab and dung), with the scarab's rotational center at (0,0), the dung above --> + <!-- The scarab's rotational center in this case is not the center of its bounding box, + but is calculated to be the intersection-point of the torso, spine and wings --> + <use xlink:href="#dung" x="0" y="0" transform="translate(0, -175.85)" /> + <use xlink:href="#scarab" x="0" y="0" transform="translate(0, -5.85)" /> + </g> + <g id="cairo_logo_top-centered"> + <!-- The logo (scarab and dung), with the top-center point of the bounding box at (0,0) --> + <use xlink:href="#dung" x="0" y="0" transform="translate(0, 60)" /> + <use xlink:href="#scarab" x="0" y="0" transform="translate(0, 230)" /><!-- (0,170+60) --> + </g> + <g id="cairo_logo_bottom-centered"> + <!-- The logo (scarab and dung), with the bottom-center point of the bounding box at (0,0) --> + <use xlink:href="#dung" x="0" y="0" transform="translate(0, -340)" /> + <use xlink:href="#scarab" x="0" y="0" transform="translate(0, -170)" /> + </g> + <g id="cairo_logo_right-centered"> + <!-- The logo (scarab and dung), with the right-center point of the bounding box at (0,0) --> + <use xlink:href="#dung" x="0" y="0" transform="translate(-150, -140)" /> + <use xlink:href="#scarab" x="0" y="0" transform="translate(-150, 30)" /> + </g> + <g id="cairo_logo_left-centered"> + <!-- The logo (scarab and dung), with the left-center point of the bounding box at (0,0) --> + <use xlink:href="#dung" x="0" y="0" transform="translate(150, -140)" /> + <use xlink:href="#scarab" x="0" y="0" transform="translate(150, 30)" /> + </g> + <g id="cairo_logo_topleft-centered"> + <!-- The logo (scarab and dung), with the top-left point of the bounding box at (0,0) --> + <use xlink:href="#dung" x="0" y="0" transform="translate(150, 60)" /> + <use xlink:href="#scarab" x="0" y="0" transform="translate(150, 230)" /><!-- (150, 170+60) --> + </g> + <g id="cairo_logo_topright-centered"> + <!-- The logo (scarab and dung), with the top-right point of the bounding box at (0,0) --> + <use xlink:href="#dung" x="0" y="0" transform="translate(-150, 60)" /> + <use xlink:href="#scarab" x="0" y="0" transform="translate(-150, 230)" /><!-- (-150,170+60) --> + </g> + <g id="cairo_logo_bottomleft-centered"> + <!-- The logo (scarab and dung), with the bottom-left point of the bounding box at (0,0) --> + <use xlink:href="#dung" x="0" y="0" transform="translate(150, -340)" /> + <use xlink:href="#scarab" x="0" y="0" transform="translate(150, -170)" /> + </g> + <g id="cairo_logo_bottomright-centered"> + <!-- The logo (scarab and dung), with the bottom-right point of the bounding box at (0,0) --> + <use xlink:href="#dung" x="0" y="0" transform="translate(-150, -340)" /> + <use xlink:href="#scarab" x="0" y="0" transform="translate(-150, -170)" /> + </g> + + <g id="cairo_text" transform="translate(0,-97)"> + <g transform="scale(0.1484,0.1484)"> <g transform="translate(-1139,-208.5)"> + <!-- 63 (c), advance 444, 0 horiBearing 38,522 --> + <path transform="translate(65,0)" d=" + M 412, 433 + C 385, 422 336, 413 298, 413 + C 142, 413 38, 525 38, 680 + C 38, 826 144, 947 298, 947 + C 332, 947 377, 944 416, 926 + L 409, 842 + C 380, 861 340, 871 308, 871 + C 187, 871 138, 771 138, 680 + C 138, 583 197, 489 302, 489 + C 332, 489 368, 496 404, 511 + L 412, 433 " /> + <!-- 61 (a), advance 556, 0 horiBearing 46,522 --> + <path transform="translate(486.75,0)" d=" + M 109, 541 + C 147, 509 204, 489 257, 489 + C 351, 489 383, 534 383, 622 + C 346, 620 320, 620 283, 620 + C 186, 620 46, 660 46, 788 + C 46, 899 123, 947 233, 947 + C 319, 947 369, 900 391, 869 + L 393, 869 + L 393, 935 + L 481, 935 + C 479, 920 477, 893 477, 835 + L 477, 624 + C 477, 485 418, 413 272, 413 + C 207, 413 151, 433 104, 461 + L 109, 541 + M 383, 737 + C 383, 813 334, 871 241, 871 + C 198, 871 146, 842 146, 788 + C 146, 698 272, 690 323, 690 + C 343, 690 363, 692 383, 692 + L 383, 737 " /> + <!-- 69 (i), advance 278, 0 horiBearing 86,730 --> + <path transform="translate(1000,0)" d=" + M 92, 935 + L 186, 935 + L 186, 425 + L 92, 425 + L 92, 935 + M 88, 261 + A 51, 51 0 1 1 190,261 + A 51, 51 0 1 1 88,261" /> + <!-- 72 (r), advance 389, 0 horiBearing 80,522 --> + <path transform="translate(1234.25,0)" d=" + M 80, 935 + L 174, 935 + L 174, 703 + C 174, 575 229, 495 313, 495 + C 329, 495 348, 497 365, 504 + L 365, 420 + C 345, 416 331, 413 303, 413 + C 249, 413 195, 451 170, 504 + L 168, 504 + L 168, 425 + L 80, 425 + L 80, 935 " /> + <!-- 6f (o), advance 611, 0 horiBearing 46,522 --> + <path transform="translate(1610,0)" d=" + M 46, 680 + C 46, 826 152, 947 306, 947 + C 459, 947 565, 826 565, 680 + C 565, 525 461, 413 306, 413 + C 150, 413 46, 525 46, 680 + M 146, 680 + C 146, 583 205, 489 306, 489 + C 406, 489 465, 583 465, 680 + C 465, 771 416, 871 306, 871 + C 195, 871 146, 771 146, 680 " /> + <!-- bounds: 38, 205 <-> 2232, 947 --> + </g> </g> + </g> + + <!-- scaled by 0.72, shifted around to hit pixel boundaries --> + <g id="cairo_text_small" transform="translate(0,-71)"> + <g transform="scale(0.085,0.085)"> <g transform="translate(-1139,-208.5)"> + <!-- 63 (c), advance 444, 0 horiBearing 38,522 --> + <path transform="translate(-151,0)" d=" + M 412, 433 + C 385, 422 336, 413 298, 413 + C 142, 413 38, 525 38, 680 + C 38, 826 144, 947 298, 947 + C 332, 947 377, 944 416, 926 + L 409, 842 + C 380, 861 340, 871 308, 871 + C 187, 871 138, 771 138, 680 + C 138, 583 197, 489 302, 489 + C 332, 489 368, 496 404, 511 + L 412, 433 " /> + <!-- 61 (a), advance 556, 0 horiBearing 46,522 --> + <path transform="translate(379.5,0)" d=" + M 109, 541 + C 147, 509 204, 489 257, 489 + C 351, 489 383, 534 383, 622 + C 346, 620 320, 620 283, 620 + C 186, 620 46, 660 46, 788 + C 46, 899 123, 947 233, 947 + C 319, 947 369, 900 391, 869 + L 393, 869 + L 393, 935 + L 481, 935 + C 479, 920 477, 893 477, 835 + L 477, 624 + C 477, 485 418, 413 272, 413 + C 207, 413 151, 433 104, 461 + L 109, 541 + M 383, 737 + C 383, 813 334, 871 241, 871 + C 198, 871 146, 842 146, 788 + C 146, 698 272, 690 323, 690 + C 343, 690 363, 692 383, 692 + L 383, 737 " /> + <!-- 69 (i), advance 278, 0 horiBearing 86,730 --> + <path transform="translate(1000,0)" d=" + M 92, 935 + L 186, 935 + L 186, 425 + L 92, 425 + L 92, 935 + M 88, 261 + A 51, 51 0 1 1 190,261 + A 51, 51 0 1 1 88,261" /> + <!-- 72 (r), advance 389, 0 horiBearing 80,522 --> + <path transform="translate(1341.5,0)" d=" + M 80, 935 + L 174, 935 + L 174, 703 + C 174, 575 229, 495 313, 495 + C 329, 495 348, 497 365, 504 + L 365, 420 + C 345, 416 331, 413 303, 413 + C 249, 413 195, 451 170, 504 + L 168, 504 + L 168, 425 + L 80, 425 + L 80, 935 " /> + <!-- 6f (o), advance 611, 0 horiBearing 46,522 --> + <path transform="translate(1826,0)" d=" + M 46, 680 + C 46, 826 152, 947 306, 947 + C 459, 947 565, 826 565, 680 + C 565, 525 461, 413 306, 413 + C 150, 413 46, 525 46, 680 + M 146, 680 + C 146, 583 205, 489 306, 489 + C 406, 489 465, 583 465, 680 + C 465, 771 416, 871 306, 871 + C 195, 871 146, 771 146, 680 " /> + <!-- bounds: 38, 205 <-> 2232, 947 --> + </g> </g> + </g> + + <g id="cairo_logo_with_text"> + <!-- The logo (scarab and dung), with the text 'cairo' below, the dot of the 'i' positioned between the hind legs of the scarab --> + <!-- dimensions: 300x490, centered --> + <use xlink:href="#cairo_logo_top-centered" transform="translate(0, -245)" /> + <use xlink:href="#cairo_text" transform="translate(0, 245)" /> + </g> + + <g id="cairo_banner"> + <!-- The logo on the left, the text 'cairo' in the center, and a mirror image of the logo on the right --> + <!-- The logos are scaled such that the scarab body nearly matches the height of the text characters (excepting the 'i') + and the dung should nearly aligns with the dot of the 'i'. The bottoms of the logos are aligned with the bottom of the text. --> + <!-- dimensions: 370x88, centered --> + <use xlink:href="#cairo_logo_bottomleft-centered" transform="translate(-180, 40), scale(0.1944)" /> + <use xlink:href="#cairo_text_small" transform="translate(0, 42)" fill="black" /> + <use xlink:href="#cairo_logo_bottomleft-centered" transform="translate(180, 40), scale(0.1944), scale(-1, 1)" /> + </g> + </defs> + <g transform="translate(5, -500)"> + <use xlink:href="#cairo_logo_with_text" transform="translate(150, 245)" /> + </g> +</svg> + + + + + + diff --git a/local/recipes/libs/cairo/source/test/cairo-svg-test-color.ttx b/local/recipes/libs/cairo/source/test/cairo-svg-test-color.ttx new file mode 100644 index 0000000000..a915a704b7 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/cairo-svg-test-color.ttx @@ -0,0 +1,362 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Cairo Svg Test Color + + + Regular + + + Cairo Svg Test Color 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="var(--color0, red)" /> +</svg> + + + <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> + <rect x="100" y="-750" width="800" height="500" + fill="var(--color1, blue)" /> +</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="currentColor" fill-opacity="0.5" /> +</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="currentColor" 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> + <linearGradient id="grad" x1="33%" x21="66%"> + <stop offset="0%" stop-color="currentColor" stop-opacity="0.3" /> + <stop offset="100%" stop-color="red" stop-opacity="0.3" /> + </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="currentColor" stop-opacity="1" /> + <stop offset="100%" stop-color="blue" 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="50%" cy="50%" + fx="0.75" fy="0.35" r="0.5"> + <stop offset="0%" stop-color="currentColor" stop-opacity="0.5" /> + <stop offset="100%" stop-color="blue" stop-opacity="0.5" /> + </radialGradient> + </defs> + <rect x="100" y="-900" width="800" height="800" fill="url(#grad)" /> +</svg> + + + + diff --git a/local/recipes/libs/cairo/source/test/cairo-svg-test-doc.ttx b/local/recipes/libs/cairo/source/test/cairo-svg-test-doc.ttx new file mode 100644 index 0000000000..c2cdb2817c --- /dev/null +++ b/local/recipes/libs/cairo/source/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, +iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAABhWlDQ1BJQ0MgcHJvZmlsZQAAKJF9 +kT1Iw0AYht+m1opUHOwgopChOlkQFXXUKhShQqkVWnUwufQPmjQkKS6OgmvBwZ/FqoOLs64OroIg ++APi6OSk6CIlfpcUWsR4x3EP733vy913gFAvM9XsGANUzTJS8ZiYya6KwVd0YggBmtMSM/W5ZDIB +z/F1Dx/f76I8y7vuz9Gj5EwG+ETiWaYbFvEG8dSmpXPeJw6zoqQQnxOPGnRB4keuyy6/cS44LPDM +sJFOzROHicVCG8ttzIqGSjxJHFFUjfKFjMsK5y3OarnKmvfkLwzltJVlrtMaRByLWEISImRUUUIZ +FqK0a6SYSNF5zMM/4PiT5JLJVQIjxwIqUCE5fvA/+N1bMz8x7iaFYkDgxbY/hoHgLtCo2fb3sW03 +TgD/M3CltfyVOjDzSXqtpUWOgN5t4OK6pcl7wOUO0P+kS4bkSH5aQj4PvJ/RN2WBvluge83tW/Mc +pw9AmnqVuAEODoGRAmWve7y7q71v/9Y0+/cDaP1yo4gSHTAAAAAGYktHRAD/AP8A/6C9p5MAAAAJ +cEhZcwAALiMAAC4jAXilP3YAAAAHdElNRQfmBh0FBzE5rnzLAAAAGXRFWHRDb21tZW50AENyZWF0 +ZWQgd2l0aCBHSU1QV4EOFwAAF45JREFUaN5NmnmPZOd13n/vdrdau6p6X2cjw5FIarMjAYmDwP7H +Buz4K/ib8IMFQaAgtiVLoRRSociZIWc4Pb1Xda237vIu+eNWD91AoYHuu9R7luc85zlHfPyzvwxC +CJRSzUdKpJAIKVBSIZVESoGUGqkkQggIASkE2miMiTGRQWmNkAqlNVobBMDmPgApwVmHrWu894QQ +CCHgvcMHh6stdVVh6xpra5xzeO/xLry/NtBcj5AIIRFSEbzFe49+OIQQAgDnPSiBbL4KUki0Nmhj +EFIhmz8jCGhtMFHzP6kNSjbPkVJuDNC88OGLSCnRujlYAELwBB/w3uOURWlFXSlUrTYHCVhrsdbi +nYMQmpcTCMGDbyxklELnqxVZlhEnMe00RmtNXlT4zT1CiM2XUkitUUo1X5RAYwSNVM0hpJSNR1Tj +GQDvHMH7H7wYxSitQIBznrquCD6g/A/etNbi6sYrVVUhpaSuKpxrjOGdJwgAj6Ixnp7f3xOcY7uX +koiSSHq2tmIqJ5nmDgSEjSWEEO89h5CNbRrT/uAJuTm0kCBEY3sB3nmEkGjTeLDxkCd4R+0tbO5H +GYRonqOsbV4QAhiNEDThJj3Ob8LNe4IQ6LquSSJBMb+DJEbLDqv5HEFgf2vAfSFwm9AQgBQCAc0D +mtMhnGvCSza5JVXjPSEEMki8dwQNUor3BxZC4JxDSYXXAS003nlq6sZwm+u0VoSgYRMB3nu89yjv +sbbJI2stuixLYi2JtCB4j/OerNXG2pp8MeNkZ4/7UlA4scmaTXw/eEgqpNKbsFIo80P4KaXe3+G9 +33jQN/GNQAiIohgjIkIIOGubCPAe4SRBBqTSGEBKiXNNoldVSV1VgMOHJo908BatBFpKUAofwPqA +1IY4Sbi6vODw6JhZrcitINBY6n1ia4UypvGA1Jtc2RxISgQNmDjnmuOH5lCB0ACB0htLO5QySKUJ +/gHRNogZNO1EESlQQuCQfPXqbYN4zuKcQ7MJF6M1QRkCAakU7U6XVtYijlMuLy94/PgJN+tAXoEy +5j3SSalQ2qB0hNIKIR5gXDWhhAAhiIxBCEHw7j38eu+xwRMCTV7JxstJ6pBCYG1NL1KIakm5XiDi +mKJyWA9pnJDna4Jv7tEASkmM1mBiRJSCVAQfEErT7Q+RAi4vLzk9OeWm1NRe8IDDSjfJ+YDryugm +R4RAbpI2iAYctNIELwnBbzzUWDiEJokfwjGKElItSOqcYrHAC0Wr08V7qOoCrSDa1C4fAjiHbGqC +IIkNWRqhdESSddAmoi4rAoJWp4fSEefn33O8FZHGGi3VxitgjEZrjRQCfIMkG5gjCFBKNcWMQBAC +ROO5wMYAQqC1xhiDkpJRS7DFgipfESUt+oMRUZxS1RZb1yhtqF1A6wit9cPHgJBEJiJNIlZWEJuI +yGjanS7tdpe6LljM5tzf3fP2u1f86NOf8tXFErEpeloJpGxCFATOe0QIiOAJtoFv5wLONcgFzWGt +d3jvfvCcr9lSBevxFfm6Imv1iJIMtKGoAx5JCJbaB1br4n2RDSGgIxNTWY8yMVJKtjoJ66pExm28 +k2iTEJAcnD4ijiPOv39D+vVXPPvwYy6XnkBjTUkDpw+1QkqBtxYTxzjvCIALHufY5IoHIQk4rHfs +dWKicsLlu7fErT7HHzwj7XSxtSXPS2qviPMlaE0R9HvkZINoWinF/XxJGhuEaSGATqqxviROeoQQ +iGNDvfaYTTH7/uKSk0dPuL+eouOMdqeLtTVCgKstaZq8x3wdpyRJRgAm9xOyrIVUEhU30FyVOU92 +2qwuX3F3fU2vNyLt9DFCUeUlJmkTqIi1opUYpG8xWVmUVCA9nuY5WghBWVm8MqRJipMGIQVtbTDU +xKJiPZ8xn9xxP5kwnU4pqpKXL1+xv3vI9WxJvbQkaUZQEYaAK0ustSzXOXHWwtY1rU6HNElZLleb +QgrClfzouM/tyy8Zj8cMBiN2Dk+R0lB7CEGwXMyJsERRwBkJnR7VbIzRDe+rbQM6OooilFJcXFxx +cBhhIkeBwtUOQk2IPMFbnHWUZUlVV3gfuLy+JW31SJUgVoJgK7TSIAVKR9wsl0Qm4ur8Lds7O8zr +mrqucOucxbrEuprjYZtqUvLq5UtGox2ybg+TtUmzLs5DsVqQhhVSwMpKtDLkziCFRKkG/bRSeEB1 +Or3PlJJ0OxmDwQC3nFBbx83tFdI7itJSV5YgoaprDo+PMUazWq+pqpp22iJKE9I0Y11WGAkhOG5u +b2lnGb1uC7xltcxZr5cc7QwZdlv0WgnVcsLk8px3Fxc8OjxEKUmcthju7KKlJNaANORlwNclJoq4 +mJcUVUUIDoJAiA2r9iFQWUdZOySO8WxJ4RaUZcVUgI5bmCxj2O3SHu7g6wrrHM55ptN7autpLZc4 +F9je2WXQHTCezEhjTb5eEBvJ6ekJ08USgsOohnvNbs4RtmBrsMUTLSmqnJ7uIao1dr0k6/YpdMTa +KtK0xlaeiY02sKtwLsKHGuEE4NFFsabVarNcLvAIFkVBXlr29w4Y7WwTxTHWVSgpGN/cYG2FkIok +a1FaT1Hm6EJTVo502aKqSlpJhNYSay11XXBzfc79dMn29pDx7B5XFWhfo2NDnKT84oMPmU/GCJ2Q +z2csxzcgFT4I2tqx9BXnF+dcsEUAlIkxG1JceY+UBm1tTVmWFDZjPJujTIJdTFgs7jk6O6XdH7Cc +jnn93bfkec5ytaSqa7r9PtoYBr0+Uilmy5wojhhu9XF1TUdq4iRBiYaEvru44uZyTRJFrFZLcCW9 +TpvgPOvlmuNnz6nLgmK+YD65Z7UsSA3IakUlYF44fGbQRqG02iBohSkjnKtRaZp99sBiy9rSymKq +suTkyTP6gyHju1tmiyXOeW5ubwhAK2sgd3s0xDpHu92h1e5SVTVb3TbgWeRrILAzGpDnBWkSs9Vt +s7e7w93dLVtbA2bTOVoKiqpECkEaa/qDIc7VrGdTyvUauxxj6zU+2yIn2XSfDTnVWiOlIASPare7 +nyVZhlaGTq+D95bKOgajHebzBXd3dzhXM53OqF2g3+txdnKM957T00ebqhozGu3gPThviYxmvV6j +pWBvMCBqtYmiiEgrdGTYHY3w3lFXFVVVNdcK6G0N6Q62aPeGvLt4y+W7c/Ki4ODpc+5KSWFBbIio +EHLDrmn6JJMkRElKlCbsbG/T7XTZPzxECFiuc4IUSKVBabZ3dzg+OsQGSZS2yIuSbn9IXVmGwx5P +Hh1T1Y40S7m5uWY2ueObV9/y5ZdfIkTARDE+NN5vt9t89NGHZO02zjUE9Ysvv+Ty4gohAov5HCEV +O8enTArPJK9/0BWspSwLrK0b5m4MstPpkmUtojgmzVJMknF0ckbtAsZE5HlBkIr9/X263S5eaNZF +xf7+EU+fPuN+MmU8mbAzHNLLYqy1dNKMrW6XTq9HnMScHu3x6GiP5WKOdZ4oikizDneTGds7O7R7 +PfJ1gVaal6++ZTqbk3b7YAwrJ3l5s8CHhik4a7GuJnjXkM2HRi6K40ZiAawXDHf2sNbhbM1qtaLT +6zEajUizlE6nizYR1lqKokAISVXkeG/xdUmxXnJ7e0O+XJKvC+I44c33b3BViatL5vMZL168Ynt3 +j9HuPt2tEVmnx8nJKTpJGe3to6RmOp1ikgQrJPOiJjIxQj60uQ42bLmRsDTKGLSta6q6ot3ukLZb +dHpdrs/PcR463S7tTgcQZGnGzu4OSimODvaZzqbYOqfMFzw63CXSithEHIz6VFXByeE+OjKkUUwW +KSIJ88kdKsroDwacX92ymM0xCsqypNVqcXV923AoJNu7e0ynC7q9PlcFSCdxoekilWp0MqObFpsK +tHOOJIpx1pLECYvplFanRxtPVVbsbO8RfM1oNOLo6AgtYTmd0sliBr0OnVZCGmuKfM79dMwnHz1D +6ojz80t6/S6nhzsIW6OVRMnAwc4A7xzfvXjBsN+j085wzrNeF3RpxIbZdMZZf8Dh8SnLdUmgBOFR +SiLUxhNCoFQjFnqt0UI0SBBFjToopcboCGMUjx7v0e20ubg4Zzq+RVRrXr/6LWmy4os/X/Hhk0/4 ++PlHDIcj7u6nvP7+nJ9+8hPSNKXX67EzHDRs4eaK1XJBEhsePz4CV/Hk9IDeYEQSRdxcXbHK16Ak +dW0J3jOe3NHK2lzOVljnUdIgRGi4nFJoJRAhNAVSKdT27t5nAogjw2g0QiIpigJrLVGSkOc5q+k9 +j/e3+OJ3v+Vv/lPCzWSKefZjnjx9gp19QXvwjJNHH/DyxUuGo20CgeFwQDttMZ1O6PW7fPrpx+wP +O9ze3fL5//0NxfI1l2+vyVpdnPfMZ3MGo22q2tJptdC60bEupjlq0wlKKfEERAhoJTfXNH2QfIAv +V1u8tUgpKMuCyeSOf/vNv/DqxZ/5+U8/4Wd/8R/Z2TmmOxiSxA3XYfUVx/spn//bb1kUFqTi8uoa +KTXdThcdR8RxzLOPfkTtIK+/ZpG9pvXjH/PX/+UJP3oy5nf/+hu0EkRJgrUehcRvZM77+YLKBYRq +FEylFMIHQnCb6GlUmqZTFBJvLSF4rq6vWa6WpGnC3e01MlhOjo/wCFaV5We//Av+9E3Ojz95znH9 +Lfu7I5ZrwcvzObUXdPtbxGlCUa6Z3t/j6oqqsgx3D7k8/4aTk4R8PMZe/G9qVqTdbc4eP+H08WOU +gHfnbxnfXHH+/Rtm0ynzvMR5j3WNfPSgkTVCh9wIhs3fVK/X/0wpiRABrRSj7R0m41v6vQ5PHj9i +sViQr5ZU64LHHzxDygFvvr+hnQlurhf8+ncVl1c3fPyTT7k4/55ev4+taiIpMFGE94Hto2P+z7/+ +gZ09wVYn4Xh/i6S1x6//+2v+89/8A8YY0sjQ63RYrXLa7RadTod5aVk7gZCNpEQIKCXRSqE3B7G2 +xvmADsFD8EihKaoSISVFkXN48IgkTWi125y/u+T65o6vX7zi5z/5hJ//4u9YlTV//uYlMvwzs/mM +u6tLkiQjzws0gdIYTBTT6kjy2ZRvX7/mxZuc58+7BCJqb/nrf/wn4jTi3ZvXVEWJc56j0xMuzs9Z +LJa4oBGqoSONZB1QUqKVRCIJwRGC+He61kZSCc4RxRFPHp8RxxF7e3sEPLfXl1gXcM7xzavvOH93 +yUcf/5hPfvIxq7ImGR0ymy+5v5/T73fo9PtUtmKd50ghuXz3jmxrl6dnR3z46ackWcLNxQXfvXrF +1cUllXXsDgc8+w8fkSQR88ktN+N76mxIFBncpv8RG91ZblRO7wJBuAbVet3+Z0IEyrJECMn+4RFn +Z8csp2PiNGV7e4dBv88f/vA51zfXGK0RSuGC4upmzHg65+76mtV8yt7+AdujEaPBFrvbA9ZFRVVW +XF9eUaA5e3TG3s6Ir776E19/+Sdurm/QStGKIp48e8bR6Qm2rpHB4XXE3Kn3Cv+DOmm0QiuJ2IjZ +1jnqukInaUK318X7RiVZTO9ZzLpYH4iNYb1aoaKYf/jH/8YfP/+c8XiMMobHaUpeW6qywkSaODFs +7++TKEkaa5TUdDpdhFTc3N0xnc1YLNd8/vvPeX1+zv3tDVIKep02R4f7HB4fsVrMqYqCTneLarwm +ULyfADTyKygpwHmss43M5DzBe1S/3/vMe0ddlmgJVVXQ7/e5H485f/ManOPq6pLF7J7BcMTN7d2G +ERumk3t6W0Nur67I87zRiyNDN0tot7usiop35++4ur7Z9Cwd2qkh2BKjFc+envH4yRO2Bn20aurG +anbP/XTBi8tGO5Abyi5EIDbNEOlBuHbObaZeHrV/ePhZbCK0bhqUOIp+GKAEy2q15OzxI7Z3hjx9 ++hQhIF/l1NY2Ek8cc3p2wu3NNUJp+r0erazFfD7j5nbMYj7F1o7jsxOkaITtar1CS8FgOKCVRiym +93zxxy+Yjm9YLuZc3M6ZrJvZoPUO5y1aSiJj0FJhbd2M47x/fyAdRQajDc5BZAxGKxaLBUfHh1y+ +fc3Hz59zdnZGq52hpGRvf588X5NXnjgyPHp8hneOJ49OubtfcPntKxa3V9TWQoBur8tf/vJXKK1Z +zCYs7u85ODig3+tw+uQxs8kYt7VFVRaslguKouY2t7iHISgerRWYhkI9iN1CiM1wtMkVaXREp9sh +jhPanTZJHINzWOs4ODjg6xcv+d3vf0++LqitByHobg1ZFyWrPOf25oadnW3OTo+5f/eKePySX23V +/LJToe6+w5YF7W6HLEtIohjrPL1ej0cffIiR4n3NODl7RJpmZN0t8spuBPJmSqaEBNcMiKT8gcI3 +478GftXJ6elnSknW+Yq6rOj1+qzzFdZ7nK3ZHvRYTO+pqpI46+AC9HoDDvZ2kcEzm004PNhn5/CY +k8dP+dPXrxFVSStOWe8+47/+3d/T63W5fvuWm5s78vUaISVZq0UUZ6yLNbfv3vLm9UuMifnucsLa +gVSNOK2UQmvZKIuyGaIGAt55bO3eq5bq8eMnn9m62kyTPHe3N0RRBELSbreROuLs7BGd7oDVaoXz +8MEHTynWCyKt2R5uoZUhTlNaWYuqrPgfv/4XcpHwq7/9ew729xChJk2a4dDh/jZbo23m8zlVsWI+ +uSafT7BVxar03C1LShcQUv4wVRYCrQ1s2G7wnrq2m6ruEYAOeKRUuFDhnKPVbuGcY2d/n939fYSz +TOcL3nz7DfvHZ5w83uZufM9gMMTVNdY6TJKwWMwp8jX9wRbBRIyefYi3FdZVYD1vX7/BRDFJp0Or +04Zqyer+gmpd4p2nN9xneTenqCZIodHGUJZlM3uUBu9BCI9sxi5oJfFaI72nrmt0CAJJM7fwQJRm +nD56RL5cYmtLGhmyWNLfek6VL1iMr5lNbhlujzBa0e1uka/XBO+ZTWfc3tyg45i6toxvr8niBjK7 +w22wBUorFtNbynyBy+e0sgyRDKhEyvLdmEgrPArBhpV7h4p0M9YDlHgYk0ucD+ACwjnUzu7OZ943 +o6v21hbBB6hrBtu7fP2nP5K1OxweHWNEYDgaUeVLWt0es8mEqizJ12u8h/HknqqquHz7lt3hgKIq +sSE0CocQ4GuSLGG9mGPLHOMK2qMDkt4eXqcsCsd3r99Q1jUog6dpgR+2JYw2TY5s9i6stbjNFNpa +i272TmC0vcvt1SXaaOh2eP3i//Hs+SeMhkMWyzXbwz62XLF3csZqsaDXbqG0Il8tGK8WoGOG2/v8 +6q/+CrynnWUgAnVdcXf9PVmkWY0d2/tHFIslRC2K2pFkEeuipKwdelO1MXKjmDSVW0uJ180YPNCI +ELXzVPUPhVEmSUwcxVycv6VYr6mrmqoseP7JT7Flwbu355R1zbffvUHomLIsieMILQWtWHOwM+J4 +u88gctjVlPl8jtQKExsIjvViiqtKymJN1t3CASbbwqkEGyR5UZF1+iAVi/EYpTVJ2oJN57dpmpol +hc0GxkPteJjdCwK6KBqpppVlrJYrnK3ZPzri/O05CDg6Pubi7ffs7x9QW0d+e0cnizGy2R+x64Jg +SzpZRtbrsrawXkwpVjNsXSG8RzbbL1TFGiEVrd4QW1ekWZegYmrrWS3mrNc5cdqC4DcTY0WSpiht +QP6wnPPweb+AAOj5bEaaxqxWK+LY0N3q8+LrF0Ra8+jJI6aTCe1WxjpfkqZHpFpT5Qv6wz5VndNO +U0wWEyUt4labWDQvtc7jfcDXFVKAwqG0bnRbExGlbWSUEIKgrNbcXl7Q6XbJPWBrImMgTZteXan3 +7e/Dz4PqGAL4EJp+xDmPNhqtIxbTBd5Zkm6LgODq4pzR7gGtVsY//6//yc9+8ilGSWrv6PSGSKVI +kpg0zVBJRqpjXAhUdY0gEKxGbQQ1rTVJ1kLHMVIn1M7hPdzfj6mLHCEF1joiqXDOvl9KeL/+sYFe +ABFoFnLqBr61c5bgJQhDZWvy5ZI0idneO+D1qxfsHx5z/uY7fvqLX9BODJfv3rG3PYTQwkQpcWQQ +WmPiDGUSlNZY7xuq4z1qM3qWWiHY/JYaKSTW1qzzkuVsSl0WdLp98Ip8k8RShPdKifeBsBEa2Czd +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, +iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAABhWlDQ1BJQ0MgcHJvZmlsZQAAKJF9 +kT1Iw0AYht+m1opUHOwgopChOlkQFXXUKhShQqkVWnUwufQPmjQkKS6OgmvBwZ/FqoOLs64OroIg ++APi6OSk6CIlfpcUWsR4x3EP733vy913gFAvM9XsGANUzTJS8ZiYya6KwVd0YggBmtMSM/W5ZDIB +z/F1Dx/f76I8y7vuz9Gj5EwG+ETiWaYbFvEG8dSmpXPeJw6zoqQQnxOPGnRB4keuyy6/cS44LPDM +sJFOzROHicVCG8ttzIqGSjxJHFFUjfKFjMsK5y3OarnKmvfkLwzltJVlrtMaRByLWEISImRUUUIZ +FqK0a6SYSNF5zMM/4PiT5JLJVQIjxwIqUCE5fvA/+N1bMz8x7iaFYkDgxbY/hoHgLtCo2fb3sW03 +TgD/M3CltfyVOjDzSXqtpUWOgN5t4OK6pcl7wOUO0P+kS4bkSH5aQj4PvJ/RN2WBvluge83tW/Mc +pw9AmnqVuAEODoGRAmWve7y7q71v/9Y0+/cDaP1yo4gSHTAAAAAGYktHRAD/AP8A/6C9p5MAAAAJ +cEhZcwAALiMAAC4jAXilP3YAAAAHdElNRQfmBh0FBzE5rnzLAAAAGXRFWHRDb21tZW50AENyZWF0 +ZWQgd2l0aCBHSU1QV4EOFwAAF45JREFUaN5NmnmPZOd13n/vdrdau6p6X2cjw5FIarMjAYmDwP7H +Buz4K/ib8IMFQaAgtiVLoRRSociZIWc4Pb1Xda237vIu+eNWD91AoYHuu9R7luc85zlHfPyzvwxC +CJRSzUdKpJAIKVBSIZVESoGUGqkkQggIASkE2miMiTGRQWmNkAqlNVobBMDmPgApwVmHrWu894QQ +CCHgvcMHh6stdVVh6xpra5xzeO/xLry/NtBcj5AIIRFSEbzFe49+OIQQAgDnPSiBbL4KUki0Nmhj +EFIhmz8jCGhtMFHzP6kNSjbPkVJuDNC88OGLSCnRujlYAELwBB/w3uOURWlFXSlUrTYHCVhrsdbi +nYMQmpcTCMGDbyxklELnqxVZlhEnMe00RmtNXlT4zT1CiM2XUkitUUo1X5RAYwSNVM0hpJSNR1Tj +GQDvHMH7H7wYxSitQIBznrquCD6g/A/etNbi6sYrVVUhpaSuKpxrjOGdJwgAj6Ixnp7f3xOcY7uX +koiSSHq2tmIqJ5nmDgSEjSWEEO89h5CNbRrT/uAJuTm0kCBEY3sB3nmEkGjTeLDxkCd4R+0tbO5H +GYRonqOsbV4QAhiNEDThJj3Ob8LNe4IQ6LquSSJBMb+DJEbLDqv5HEFgf2vAfSFwm9AQgBQCAc0D +mtMhnGvCSza5JVXjPSEEMki8dwQNUor3BxZC4JxDSYXXAS003nlq6sZwm+u0VoSgYRMB3nu89yjv +sbbJI2stuixLYi2JtCB4j/OerNXG2pp8MeNkZ4/7UlA4scmaTXw/eEgqpNKbsFIo80P4KaXe3+G9 +33jQN/GNQAiIohgjIkIIOGubCPAe4SRBBqTSGEBKiXNNoldVSV1VgMOHJo908BatBFpKUAofwPqA +1IY4Sbi6vODw6JhZrcitINBY6n1ia4UypvGA1Jtc2RxISgQNmDjnmuOH5lCB0ACB0htLO5QySKUJ +/gHRNogZNO1EESlQQuCQfPXqbYN4zuKcQ7MJF6M1QRkCAakU7U6XVtYijlMuLy94/PgJN+tAXoEy +5j3SSalQ2qB0hNIKIR5gXDWhhAAhiIxBCEHw7j38eu+xwRMCTV7JxstJ6pBCYG1NL1KIakm5XiDi +mKJyWA9pnJDna4Jv7tEASkmM1mBiRJSCVAQfEErT7Q+RAi4vLzk9OeWm1NRe8IDDSjfJ+YDryugm +R4RAbpI2iAYctNIELwnBbzzUWDiEJokfwjGKElItSOqcYrHAC0Wr08V7qOoCrSDa1C4fAjiHbGqC +IIkNWRqhdESSddAmoi4rAoJWp4fSEefn33O8FZHGGi3VxitgjEZrjRQCfIMkG5gjCFBKNcWMQBAC +ROO5wMYAQqC1xhiDkpJRS7DFgipfESUt+oMRUZxS1RZb1yhtqF1A6wit9cPHgJBEJiJNIlZWEJuI +yGjanS7tdpe6LljM5tzf3fP2u1f86NOf8tXFErEpeloJpGxCFATOe0QIiOAJtoFv5wLONcgFzWGt +d3jvfvCcr9lSBevxFfm6Imv1iJIMtKGoAx5JCJbaB1br4n2RDSGgIxNTWY8yMVJKtjoJ66pExm28 +k2iTEJAcnD4ijiPOv39D+vVXPPvwYy6XnkBjTUkDpw+1QkqBtxYTxzjvCIALHufY5IoHIQk4rHfs +dWKicsLlu7fErT7HHzwj7XSxtSXPS2qviPMlaE0R9HvkZINoWinF/XxJGhuEaSGATqqxviROeoQQ +iGNDvfaYTTH7/uKSk0dPuL+eouOMdqeLtTVCgKstaZq8x3wdpyRJRgAm9xOyrIVUEhU30FyVOU92 +2qwuX3F3fU2vNyLt9DFCUeUlJmkTqIi1opUYpG8xWVmUVCA9nuY5WghBWVm8MqRJipMGIQVtbTDU +xKJiPZ8xn9xxP5kwnU4pqpKXL1+xv3vI9WxJvbQkaUZQEYaAK0ustSzXOXHWwtY1rU6HNElZLleb +QgrClfzouM/tyy8Zj8cMBiN2Dk+R0lB7CEGwXMyJsERRwBkJnR7VbIzRDe+rbQM6OooilFJcXFxx +cBhhIkeBwtUOQk2IPMFbnHWUZUlVV3gfuLy+JW31SJUgVoJgK7TSIAVKR9wsl0Qm4ur8Lds7O8zr +mrqucOucxbrEuprjYZtqUvLq5UtGox2ybg+TtUmzLs5DsVqQhhVSwMpKtDLkziCFRKkG/bRSeEB1 +Or3PlJJ0OxmDwQC3nFBbx83tFdI7itJSV5YgoaprDo+PMUazWq+pqpp22iJKE9I0Y11WGAkhOG5u +b2lnGb1uC7xltcxZr5cc7QwZdlv0WgnVcsLk8px3Fxc8OjxEKUmcthju7KKlJNaANORlwNclJoq4 +mJcUVUUIDoJAiA2r9iFQWUdZOySO8WxJ4RaUZcVUgI5bmCxj2O3SHu7g6wrrHM55ptN7autpLZc4 +F9je2WXQHTCezEhjTb5eEBvJ6ekJ08USgsOohnvNbs4RtmBrsMUTLSmqnJ7uIao1dr0k6/YpdMTa +KtK0xlaeiY02sKtwLsKHGuEE4NFFsabVarNcLvAIFkVBXlr29w4Y7WwTxTHWVSgpGN/cYG2FkIok +a1FaT1Hm6EJTVo502aKqSlpJhNYSay11XXBzfc79dMn29pDx7B5XFWhfo2NDnKT84oMPmU/GCJ2Q +z2csxzcgFT4I2tqx9BXnF+dcsEUAlIkxG1JceY+UBm1tTVmWFDZjPJujTIJdTFgs7jk6O6XdH7Cc +jnn93bfkec5ytaSqa7r9PtoYBr0+Uilmy5wojhhu9XF1TUdq4iRBiYaEvru44uZyTRJFrFZLcCW9 +TpvgPOvlmuNnz6nLgmK+YD65Z7UsSA3IakUlYF44fGbQRqG02iBohSkjnKtRaZp99sBiy9rSymKq +suTkyTP6gyHju1tmiyXOeW5ubwhAK2sgd3s0xDpHu92h1e5SVTVb3TbgWeRrILAzGpDnBWkSs9Vt +s7e7w93dLVtbA2bTOVoKiqpECkEaa/qDIc7VrGdTyvUauxxj6zU+2yIn2XSfDTnVWiOlIASPare7 +nyVZhlaGTq+D95bKOgajHebzBXd3dzhXM53OqF2g3+txdnKM957T00ebqhozGu3gPThviYxmvV6j +pWBvMCBqtYmiiEgrdGTYHY3w3lFXFVVVNdcK6G0N6Q62aPeGvLt4y+W7c/Ki4ODpc+5KSWFBbIio +EHLDrmn6JJMkRElKlCbsbG/T7XTZPzxECFiuc4IUSKVBabZ3dzg+OsQGSZS2yIuSbn9IXVmGwx5P +Hh1T1Y40S7m5uWY2ueObV9/y5ZdfIkTARDE+NN5vt9t89NGHZO02zjUE9Ysvv+Ty4gohAov5HCEV +O8enTArPJK9/0BWspSwLrK0b5m4MstPpkmUtojgmzVJMknF0ckbtAsZE5HlBkIr9/X263S5eaNZF +xf7+EU+fPuN+MmU8mbAzHNLLYqy1dNKMrW6XTq9HnMScHu3x6GiP5WKOdZ4oikizDneTGds7O7R7 +PfJ1gVaal6++ZTqbk3b7YAwrJ3l5s8CHhik4a7GuJnjXkM2HRi6K40ZiAawXDHf2sNbhbM1qtaLT +6zEajUizlE6nizYR1lqKokAISVXkeG/xdUmxXnJ7e0O+XJKvC+I44c33b3BViatL5vMZL168Ynt3 +j9HuPt2tEVmnx8nJKTpJGe3to6RmOp1ikgQrJPOiJjIxQj60uQ42bLmRsDTKGLSta6q6ot3ukLZb +dHpdrs/PcR463S7tTgcQZGnGzu4OSimODvaZzqbYOqfMFzw63CXSithEHIz6VFXByeE+OjKkUUwW +KSIJ88kdKsroDwacX92ymM0xCsqypNVqcXV923AoJNu7e0ynC7q9PlcFSCdxoekilWp0MqObFpsK +tHOOJIpx1pLECYvplFanRxtPVVbsbO8RfM1oNOLo6AgtYTmd0sliBr0OnVZCGmuKfM79dMwnHz1D +6ojz80t6/S6nhzsIW6OVRMnAwc4A7xzfvXjBsN+j085wzrNeF3RpxIbZdMZZf8Dh8SnLdUmgBOFR +SiLUxhNCoFQjFnqt0UI0SBBFjToopcboCGMUjx7v0e20ubg4Zzq+RVRrXr/6LWmy4os/X/Hhk0/4 ++PlHDIcj7u6nvP7+nJ9+8hPSNKXX67EzHDRs4eaK1XJBEhsePz4CV/Hk9IDeYEQSRdxcXbHK16Ak +dW0J3jOe3NHK2lzOVljnUdIgRGi4nFJoJRAhNAVSKdT27t5nAogjw2g0QiIpigJrLVGSkOc5q+k9 +j/e3+OJ3v+Vv/lPCzWSKefZjnjx9gp19QXvwjJNHH/DyxUuGo20CgeFwQDttMZ1O6PW7fPrpx+wP +O9ze3fL5//0NxfI1l2+vyVpdnPfMZ3MGo22q2tJptdC60bEupjlq0wlKKfEERAhoJTfXNH2QfIAv +V1u8tUgpKMuCyeSOf/vNv/DqxZ/5+U8/4Wd/8R/Z2TmmOxiSxA3XYfUVx/spn//bb1kUFqTi8uoa +KTXdThcdR8RxzLOPfkTtIK+/ZpG9pvXjH/PX/+UJP3oy5nf/+hu0EkRJgrUehcRvZM77+YLKBYRq +FEylFMIHQnCb6GlUmqZTFBJvLSF4rq6vWa6WpGnC3e01MlhOjo/wCFaV5We//Av+9E3Ojz95znH9 +Lfu7I5ZrwcvzObUXdPtbxGlCUa6Z3t/j6oqqsgx3D7k8/4aTk4R8PMZe/G9qVqTdbc4eP+H08WOU +gHfnbxnfXHH+/Rtm0ynzvMR5j3WNfPSgkTVCh9wIhs3fVK/X/0wpiRABrRSj7R0m41v6vQ5PHj9i +sViQr5ZU64LHHzxDygFvvr+hnQlurhf8+ncVl1c3fPyTT7k4/55ev4+taiIpMFGE94Hto2P+z7/+ +gZ09wVYn4Xh/i6S1x6//+2v+89/8A8YY0sjQ63RYrXLa7RadTod5aVk7gZCNpEQIKCXRSqE3B7G2 +xvmADsFD8EihKaoSISVFkXN48IgkTWi125y/u+T65o6vX7zi5z/5hJ//4u9YlTV//uYlMvwzs/mM +u6tLkiQjzws0gdIYTBTT6kjy2ZRvX7/mxZuc58+7BCJqb/nrf/wn4jTi3ZvXVEWJc56j0xMuzs9Z +LJa4oBGqoSONZB1QUqKVRCIJwRGC+He61kZSCc4RxRFPHp8RxxF7e3sEPLfXl1gXcM7xzavvOH93 +yUcf/5hPfvIxq7ImGR0ymy+5v5/T73fo9PtUtmKd50ghuXz3jmxrl6dnR3z46ackWcLNxQXfvXrF +1cUllXXsDgc8+w8fkSQR88ktN+N76mxIFBncpv8RG91ZblRO7wJBuAbVet3+Z0IEyrJECMn+4RFn +Z8csp2PiNGV7e4dBv88f/vA51zfXGK0RSuGC4upmzHg65+76mtV8yt7+AdujEaPBFrvbA9ZFRVVW +XF9eUaA5e3TG3s6Ir776E19/+Sdurm/QStGKIp48e8bR6Qm2rpHB4XXE3Kn3Cv+DOmm0QiuJ2IjZ +1jnqukInaUK318X7RiVZTO9ZzLpYH4iNYb1aoaKYf/jH/8YfP/+c8XiMMobHaUpeW6qywkSaODFs +7++TKEkaa5TUdDpdhFTc3N0xnc1YLNd8/vvPeX1+zv3tDVIKep02R4f7HB4fsVrMqYqCTneLarwm +ULyfADTyKygpwHmss43M5DzBe1S/3/vMe0ddlmgJVVXQ7/e5H485f/ManOPq6pLF7J7BcMTN7d2G +ERumk3t6W0Nur67I87zRiyNDN0tot7usiop35++4ur7Z9Cwd2qkh2BKjFc+envH4yRO2Bn20aurG +anbP/XTBi8tGO5Abyi5EIDbNEOlBuHbObaZeHrV/ePhZbCK0bhqUOIp+GKAEy2q15OzxI7Z3hjx9 ++hQhIF/l1NY2Ek8cc3p2wu3NNUJp+r0erazFfD7j5nbMYj7F1o7jsxOkaITtar1CS8FgOKCVRiym +93zxxy+Yjm9YLuZc3M6ZrJvZoPUO5y1aSiJj0FJhbd2M47x/fyAdRQajDc5BZAxGKxaLBUfHh1y+ +fc3Hz59zdnZGq52hpGRvf588X5NXnjgyPHp8hneOJ49OubtfcPntKxa3V9TWQoBur8tf/vJXKK1Z +zCYs7u85ODig3+tw+uQxs8kYt7VFVRaslguKouY2t7iHISgerRWYhkI9iN1CiM1wtMkVaXREp9sh +jhPanTZJHINzWOs4ODjg6xcv+d3vf0++LqitByHobg1ZFyWrPOf25oadnW3OTo+5f/eKePySX23V +/LJToe6+w5YF7W6HLEtIohjrPL1ej0cffIiR4n3NODl7RJpmZN0t8spuBPJmSqaEBNcMiKT8gcI3 +478GftXJ6elnSknW+Yq6rOj1+qzzFdZ7nK3ZHvRYTO+pqpI46+AC9HoDDvZ2kcEzm004PNhn5/CY +k8dP+dPXrxFVSStOWe8+47/+3d/T63W5fvuWm5s78vUaISVZq0UUZ6yLNbfv3vLm9UuMifnucsLa +gVSNOK2UQmvZKIuyGaIGAt55bO3eq5bq8eMnn9m62kyTPHe3N0RRBELSbreROuLs7BGd7oDVaoXz +8MEHTynWCyKt2R5uoZUhTlNaWYuqrPgfv/4XcpHwq7/9ew729xChJk2a4dDh/jZbo23m8zlVsWI+ +uSafT7BVxar03C1LShcQUv4wVRYCrQ1s2G7wnrq2m6ruEYAOeKRUuFDhnKPVbuGcY2d/n939fYSz +TOcL3nz7DfvHZ5w83uZufM9gMMTVNdY6TJKwWMwp8jX9wRbBRIyefYi3FdZVYD1vX7/BRDFJp0Or +04Zqyer+gmpd4p2nN9xneTenqCZIodHGUJZlM3uUBu9BCI9sxi5oJfFaI72nrmt0CAJJM7fwQJRm +nD56RL5cYmtLGhmyWNLfek6VL1iMr5lNbhlujzBa0e1uka/XBO+ZTWfc3tyg45i6toxvr8niBjK7 +w22wBUorFtNbynyBy+e0sgyRDKhEyvLdmEgrPArBhpV7h4p0M9YDlHgYk0ucD+ACwjnUzu7OZ943 +o6v21hbBB6hrBtu7fP2nP5K1OxweHWNEYDgaUeVLWt0es8mEqizJ12u8h/HknqqquHz7lt3hgKIq +sSE0CocQ4GuSLGG9mGPLHOMK2qMDkt4eXqcsCsd3r99Q1jUog6dpgR+2JYw2TY5s9i6stbjNFNpa +i272TmC0vcvt1SXaaOh2eP3i//Hs+SeMhkMWyzXbwz62XLF3csZqsaDXbqG0Il8tGK8WoGOG2/v8 +6q/+CrynnWUgAnVdcXf9PVmkWY0d2/tHFIslRC2K2pFkEeuipKwdelO1MXKjmDSVW0uJ180YPNCI +ELXzVPUPhVEmSUwcxVycv6VYr6mrmqoseP7JT7Flwbu355R1zbffvUHomLIsieMILQWtWHOwM+J4 +u88gctjVlPl8jtQKExsIjvViiqtKymJN1t3CASbbwqkEGyR5UZF1+iAVi/EYpTVJ2oJN57dpmpol +hc0GxkPteJjdCwK6KBqpppVlrJYrnK3ZPzri/O05CDg6Pubi7ffs7x9QW0d+e0cnizGy2R+x64Jg +SzpZRtbrsrawXkwpVjNsXSG8RzbbL1TFGiEVrd4QW1ekWZegYmrrWS3mrNc5cdqC4DcTY0WSpiht +QP6wnPPweb+AAOj5bEaaxqxWK+LY0N3q8+LrF0Ra8+jJI6aTCe1WxjpfkqZHpFpT5Qv6wz5VndNO +U0wWEyUt4labWDQvtc7jfcDXFVKAwqG0bnRbExGlbWSUEIKgrNbcXl7Q6XbJPWBrImMgTZteXan3 +7e/Dz4PqGAL4EJp+xDmPNhqtIxbTBd5Zkm6LgODq4pzR7gGtVsY//6//yc9+8ilGSWrv6PSGSKVI +kpg0zVBJRqpjXAhUdY0gEKxGbQQ1rTVJ1kLHMVIn1M7hPdzfj6mLHCEF1joiqXDOvl9KeL/+sYFe +ABFoFnLqBr61c5bgJQhDZWvy5ZI0idneO+D1qxfsHx5z/uY7fvqLX9BODJfv3rG3PYTQwkQpcWQQ +WmPiDGUSlNZY7xuq4z1qM3qWWiHY/JYaKSTW1qzzkuVsSl0WdLp98Ip8k8RShPdKifeBsBEa2Czd +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/local/recipes/libs/cairo/source/test/cairo-svg-test-fill.ttx b/local/recipes/libs/cairo/source/test/cairo-svg-test-fill.ttx new file mode 100644 index 0000000000..b6867ec8fe --- /dev/null +++ b/local/recipes/libs/cairo/source/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/local/recipes/libs/cairo/source/test/cairo-svg-test-gradient.ttx b/local/recipes/libs/cairo/source/test/cairo-svg-test-gradient.ttx new file mode 100644 index 0000000000..4a7a221755 --- /dev/null +++ b/local/recipes/libs/cairo/source/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/local/recipes/libs/cairo/source/test/cairo-svg-test-path.ttx b/local/recipes/libs/cairo/source/test/cairo-svg-test-path.ttx new file mode 100644 index 0000000000..9173a537d1 --- /dev/null +++ b/local/recipes/libs/cairo/source/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/local/recipes/libs/cairo/source/test/cairo-svg-test-shapes.ttx b/local/recipes/libs/cairo/source/test/cairo-svg-test-shapes.ttx new file mode 100644 index 0000000000..15a573a64f --- /dev/null +++ b/local/recipes/libs/cairo/source/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/local/recipes/libs/cairo/source/test/cairo-svg-test-stroke.ttx b/local/recipes/libs/cairo/source/test/cairo-svg-test-stroke.ttx new file mode 100644 index 0000000000..a403da928b --- /dev/null +++ b/local/recipes/libs/cairo/source/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/local/recipes/libs/cairo/source/test/cairo-svg-test-transform.ttx b/local/recipes/libs/cairo/source/test/cairo-svg-test-transform.ttx new file mode 100644 index 0000000000..1f07c05ad9 --- /dev/null +++ b/local/recipes/libs/cairo/source/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/local/recipes/libs/cairo/source/test/cairo-test-private.h b/local/recipes/libs/cairo/source/test/cairo-test-private.h new file mode 100644 index 0000000000..cfd22de4e1 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/cairo-test-private.h @@ -0,0 +1,72 @@ +/* + * Copyright © 2004 Red Hat, Inc. + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + * Chris Wilson + */ + +#ifndef _CAIRO_TEST_PRIVATE_H_ +#define _CAIRO_TEST_PRIVATE_H_ + +#include "cairo-test.h" + +/* For communication between the core components of cairo-test and not + * for the tests themselves. + */ + +CAIRO_BEGIN_DECLS + +typedef enum { + DIRECT, + SIMILAR +} cairo_test_similar_t; + +cairo_test_similar_t +cairo_test_target_has_similar (const cairo_test_context_t *ctx, + const cairo_boilerplate_target_t *target); + +cairo_test_status_t +_cairo_test_context_run_for_target (cairo_test_context_t *ctx, + const cairo_boilerplate_target_t *target, + cairo_bool_t similar, + int dev_offset, int dev_scale); + +void +_cairo_test_context_init_for_test (cairo_test_context_t *ctx, + const cairo_test_context_t *parent, + const cairo_test_t *test); + +void +cairo_test_init (cairo_test_context_t *ctx, + const char *test_name, + const char *output); + +void +cairo_test_fini (cairo_test_context_t *ctx); + +void +_cairo_test_runner_register_tests (void); + +CAIRO_END_DECLS + +#endif /* _CAIRO_TEST_PRIVATE_H_ */ diff --git a/local/recipes/libs/cairo/source/test/cairo-test-runner.c b/local/recipes/libs/cairo/source/test/cairo-test-runner.c new file mode 100644 index 0000000000..acbb539308 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/cairo-test-runner.c @@ -0,0 +1,1162 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test-private.h" +#include "cairo-boilerplate-getopt.h" + +#include /* for version information */ + +#define SHOULD_FORK HAVE_FORK && HAVE_WAITPID +#if HAVE_UNISTD_H +#include +#endif +#if SHOULD_FORK +#if HAVE_SIGNAL_H +#include +#endif +#include +#include +#endif +#if HAVE_LIBGEN_H +#include +#endif + +#if HAVE_VALGRIND +#include +#else +#define RUNNING_ON_VALGRIND 0 +#endif + +#ifdef _MSC_VER +#include +#endif + +typedef struct _cairo_test_list { + const cairo_test_t *test; + struct _cairo_test_list *next; +} cairo_test_list_t; + +typedef struct _cairo_test_runner { + cairo_test_context_t base; + + unsigned int num_device_offsets; + unsigned int num_device_scales; + + cairo_bool_t passed; + int num_passed; + int num_skipped; + int num_failed; + int num_xfailed; + int num_error; + int num_crashed; + + unsigned int num_ignored_via_env; + + cairo_test_list_t *crashes_preamble; + cairo_test_list_t *errors_preamble; + cairo_test_list_t *fails_preamble; + + cairo_test_list_t **crashes_per_target; + cairo_test_list_t **errors_per_target; + cairo_test_list_t **fails_per_target; + + int *num_failed_per_target; + int *num_error_per_target; + int *num_crashed_per_target; + + cairo_bool_t foreground; + cairo_bool_t exit_on_failure; + cairo_bool_t list_only; + cairo_bool_t full_test; + cairo_bool_t keyword_match; + cairo_bool_t slow; + cairo_bool_t force_pass; +} cairo_test_runner_t; + +typedef enum { + GE, + GT +} cairo_test_compare_op_t; + +static cairo_test_list_t *tests; + +static void CAIRO_BOILERPLATE_PRINTF_FORMAT(2,3) +_log (cairo_test_context_t *ctx, + const char *fmt, + ...) +{ + va_list ap; + + va_start (ap, fmt); + vprintf (fmt, ap); + va_end (ap); + + va_start (ap, fmt); + cairo_test_logv (ctx, fmt, ap); + va_end (ap); +} + +static cairo_test_list_t * +_list_prepend (cairo_test_list_t *head, const cairo_test_t *test) +{ + cairo_test_list_t *list; + + list = xmalloc (sizeof (cairo_test_list_t)); + list->test = test; + list->next = head; + head = list; + + return head; +} + +static cairo_test_list_t * +_list_reverse (cairo_test_list_t *head) +{ + cairo_test_list_t *list, *next; + + for (list = head, head = NULL; list != NULL; list = next) { + next = list->next; + list->next = head; + head = list; + } + + return head; +} + +static void +_list_free (cairo_test_list_t *list) +{ + while (list != NULL) { + cairo_test_list_t *next = list->next; + free (list); + list = next; + } +} + +static cairo_bool_t +is_running_under_debugger (void) +{ +#if HAVE_UNISTD_H && HAVE_LIBGEN_H && __linux__ + char buf[1024] = { 0 }; + char buf2[1024] = { 0 }; + + sprintf (buf, "/proc/%d/exe", getppid ()); + if (readlink (buf, buf2, sizeof (buf2)) != -1 && + buf2[1023] == 0 && + strncmp (basename (buf2), "gdb", 3) == 0) + { + return TRUE; + } +#endif + + if (RUNNING_ON_VALGRIND) + return TRUE; + + return FALSE; +} + +#if SHOULD_FORK +static cairo_test_status_t +_cairo_test_wait (pid_t pid) +{ + int exitcode; + + if (waitpid (pid, &exitcode, 0) != pid) + return CAIRO_TEST_CRASHED; + + if (WIFSIGNALED (exitcode)) { + switch (WTERMSIG (exitcode)) { + case SIGINT: +#if HAVE_RAISE + raise (SIGINT); +#endif + return CAIRO_TEST_UNTESTED; + default: + return CAIRO_TEST_CRASHED; + } + } + + return WEXITSTATUS (exitcode); +} +#endif + +static cairo_test_status_t +_cairo_test_runner_preamble (cairo_test_runner_t *runner, + cairo_test_context_t *ctx) +{ +#if SHOULD_FORK + if (! runner->foreground) { + pid_t pid; + + /* fork() duplicates output buffers, so clear them */ + fflush (NULL); + + switch ((pid = fork ())) { + case -1: /* error */ + return CAIRO_TEST_UNTESTED; + + case 0: /* child */ + exit (ctx->test->preamble (ctx)); + + default: + return _cairo_test_wait (pid); + } + } +#endif + return ctx->test->preamble (ctx); +} + +static cairo_test_status_t +_cairo_test_runner_draw (cairo_test_runner_t *runner, + cairo_test_context_t *ctx, + const cairo_boilerplate_target_t *target, + cairo_bool_t similar, + int device_offset, int device_scale) +{ +#if SHOULD_FORK + if (! runner->foreground) { + pid_t pid; + + /* fork() duplicates output buffers, so clear them */ + fflush (NULL); + + switch ((pid = fork ())) { + case -1: /* error */ + return CAIRO_TEST_UNTESTED; + + case 0: /* child */ + exit (_cairo_test_context_run_for_target (ctx, target, + similar, device_offset, device_scale)); + + default: + return _cairo_test_wait (pid); + } + } +#endif + return _cairo_test_context_run_for_target (ctx, target, + similar, device_offset, device_scale); +} + +static void +append_argv (int *argc, char ***argv, const char *str) +{ + int old_argc; + char **old_argv; + cairo_bool_t doit; + const char *s, *t; + int olen; + int len; + int i; + int args_to_add = 0; + + if (str == NULL) + return; + + old_argc = *argc; + old_argv = *argv; + + doit = FALSE; + do { + if (doit) + *argv = xmalloc (olen); + + olen = sizeof (char *) * (args_to_add + *argc); + for (i = 0; i < old_argc; i++) { + len = strlen (old_argv[i]) + 1; + if (doit) { + (*argv)[i] = (char *) *argv + olen; + memcpy ((*argv)[i], old_argv[i], len); + } + olen += len; + } + + s = str; + while ((t = strpbrk (s, " \t,:;")) != NULL) { + if (t - s) { + len = t - s; + if (doit) { + (*argv)[i] = (char *) *argv + olen; + memcpy ((*argv)[i], s, len); + (*argv)[i][len] = '\0'; + } else { + olen += sizeof (char *); + } + args_to_add++; + olen += len + 1; + i++; + } + s = t + 1; + } + if (*s != '\0') { + len = strlen (s) + 1; + if (doit) { + (*argv)[i] = (char *) *argv + olen; + memcpy ((*argv)[i], s, len); + } else { + olen += sizeof (char *); + } + args_to_add++; + olen += len; + i++; + } + } while (doit++ == FALSE); + *argc = i; +} + +static void +usage (const char *argv0) +{ + fprintf (stderr, + "Usage: %s [-afkxsl] [test-names|keywords ...]\n" + "\n" + "Run the cairo conformance test suite over the given tests (all by default)\n" + "The command-line arguments are interpreted as follows:\n" + "\n" + " -a all; run the full set of tests. By default the test suite\n" + " skips similar surface and device offset testing.\n" + " -f foreground; do not fork\n" + " -k match tests by keyword\n" + " -l list only; just list selected test case names without executing\n" + " -s include slow, long running tests\n" + " -x exit on first failure\n" + "\n" + "If test names are given they are used as matches either to a specific\n" + "test case or to a keyword, so a command such as\n" + "\"%s -k text\" can be used to run all text test cases, and\n" + "\"%s text-transform\" to run the individual case.\n", + argv0, argv0, argv0); +} + +static void +_parse_cmdline (cairo_test_runner_t *runner, int *argc, char **argv[]) +{ + int c; + + while (1) { + c = _cairo_getopt (*argc, *argv, ":afklsx"); + if (c == -1) + break; + + switch (c) { + case 'a': + runner->full_test = ~0; + break; + case 'f': + runner->foreground = TRUE; + break; + case 'k': + runner->keyword_match = TRUE; + break; + case 'l': + runner->list_only = TRUE; + break; + case 's': + runner->slow = TRUE; + break; + case 'x': + runner->exit_on_failure = TRUE; + break; + default: + fprintf (stderr, "Internal error: unhandled option: %c\n", c); + /* fall-through */ + case '?': + usage ((*argv)[0]); + exit (1); + } + } + + *argc -= optind; + *argv += optind; +} + +static void +_runner_init (cairo_test_runner_t *runner) +{ + cairo_test_init (&runner->base, "cairo-test-suite", "."); + + runner->passed = TRUE; + + runner->fails_preamble = NULL; + runner->crashes_preamble = NULL; + runner->errors_preamble = NULL; + + runner->fails_per_target = xcalloc (sizeof (cairo_test_list_t *), + runner->base.num_targets); + runner->crashes_per_target = xcalloc (sizeof (cairo_test_list_t *), + runner->base.num_targets); + runner->errors_per_target = xcalloc (sizeof (cairo_test_list_t *), + runner->base.num_targets); + runner->num_failed_per_target = xcalloc (sizeof (int), + runner->base.num_targets); + runner->num_error_per_target = xcalloc (sizeof (int), + runner->base.num_targets); + runner->num_crashed_per_target = xcalloc (sizeof (int), + runner->base.num_targets); +} + +static void +_runner_print_versions (cairo_test_runner_t *runner) +{ + _log (&runner->base, + "Compiled against cairo %s, running on %s.\n", + CAIRO_VERSION_STRING, cairo_version_string ()); + _log (&runner->base, + "Compiled against pixman %s, running on %s.\n", + PIXMAN_VERSION_STRING, pixman_version_string ()); + + fflush (runner->base.log_file); +} + +static void +_runner_print_summary (cairo_test_runner_t *runner) +{ + _log (&runner->base, + "%d Passed, %d Failed [%d crashed, %d expected], %d Skipped\n", + runner->num_passed, + + runner->num_failed + runner->num_crashed + runner->num_xfailed, + runner->num_crashed, + runner->num_xfailed, + + runner->num_skipped); + if (runner->num_ignored_via_env) { + _log (&runner->base, + "%d expected failure due to special request via environment variables!\n", + runner->num_ignored_via_env); + } +} + +static void +_runner_print_details (cairo_test_runner_t *runner) +{ + cairo_test_list_t *list; + unsigned int n; + + if (runner->crashes_preamble) { + int count = 0; + + for (list = runner->crashes_preamble; list != NULL; list = list->next) + count++; + + _log (&runner->base, "Preamble: %d crashed! -", count); + + for (list = runner->crashes_preamble; list != NULL; list = list->next) { + char *name = cairo_test_get_name (list->test); + _log (&runner->base, " %s", name); + free (name); + } + _log (&runner->base, "\n"); + } + if (runner->errors_preamble) { + int count = 0; + + for (list = runner->errors_preamble; list != NULL; list = list->next) + count++; + + _log (&runner->base, "Preamble: %d error -", count); + + for (list = runner->errors_preamble; list != NULL; list = list->next) { + char *name = cairo_test_get_name (list->test); + _log (&runner->base, " %s", name); + free (name); + } + _log (&runner->base, "\n"); + } + if (runner->fails_preamble) { + int count = 0; + + for (list = runner->fails_preamble; list != NULL; list = list->next) + count++; + + _log (&runner->base, "Preamble: %d failed -", count); + + for (list = runner->fails_preamble; list != NULL; list = list->next) { + char *name = cairo_test_get_name (list->test); + _log (&runner->base, " %s", name); + free (name); + } + _log (&runner->base, "\n"); + } + + for (n = 0; n < runner->base.num_targets; n++) { + const cairo_boilerplate_target_t *target; + + target = runner->base.targets_to_test[n]; + if (runner->num_crashed_per_target[n]) { + _log (&runner->base, "%s (%s): %d crashed! -", + target->name, + cairo_boilerplate_content_name (target->content), + runner->num_crashed_per_target[n]); + + for (list = runner->crashes_per_target[n]; + list != NULL; + list = list->next) + { + char *name = cairo_test_get_name (list->test); + _log (&runner->base, " %s", name); + free (name); + } + _log (&runner->base, "\n"); + } + if (runner->num_error_per_target[n]) { + _log (&runner->base, "%s (%s): %d error -", + target->name, + cairo_boilerplate_content_name (target->content), + runner->num_error_per_target[n]); + + for (list = runner->errors_per_target[n]; + list != NULL; + list = list->next) + { + char *name = cairo_test_get_name (list->test); + _log (&runner->base, " %s", name); + free (name); + } + _log (&runner->base, "\n"); + } + + if (runner->num_failed_per_target[n]) { + _log (&runner->base, "%s (%s): %d failed -", + target->name, + cairo_boilerplate_content_name (target->content), + runner->num_failed_per_target[n]); + + for (list = runner->fails_per_target[n]; + list != NULL; + list = list->next) + { + char *name = cairo_test_get_name (list->test); + _log (&runner->base, " %s", name); + free (name); + } + _log (&runner->base, "\n"); + } + } +} + +static void +_runner_print_results (cairo_test_runner_t *runner) +{ + _runner_print_summary (runner); + _runner_print_details (runner); + + if (! runner->passed && ! runner->num_crashed) { + _log (&runner->base, +"\n" +"Note: These failures may be due to external factors.\n" +"Please read test/README -- \"Getting the elusive zero failures\".\n"); + } +} + +static cairo_test_status_t +_runner_fini (cairo_test_runner_t *runner) +{ + unsigned int n; + + _list_free (runner->crashes_preamble); + _list_free (runner->errors_preamble); + _list_free (runner->fails_preamble); + + for (n = 0; n < runner->base.num_targets; n++) { + _list_free (runner->crashes_per_target[n]); + _list_free (runner->errors_per_target[n]); + _list_free (runner->fails_per_target[n]); + } + free (runner->crashes_per_target); + free (runner->errors_per_target); + free (runner->fails_per_target); + + free (runner->num_crashed_per_target); + free (runner->num_error_per_target); + free (runner->num_failed_per_target); + + cairo_test_fini (&runner->base); + + if (runner->force_pass) + return CAIRO_TEST_SUCCESS; + + return runner->num_failed + runner->num_crashed ? + CAIRO_TEST_FAILURE : + runner->num_passed + runner->num_xfailed ? + CAIRO_TEST_SUCCESS : CAIRO_TEST_UNTESTED; +} + +static cairo_bool_t +expect_fail_due_to_env_var (cairo_test_context_t *ctx, + const cairo_boilerplate_target_t *target) +{ + const char *prefix = "CAIRO_TEST_IGNORE_"; + const char *content = cairo_boilerplate_content_name (target->content); + char *env_name; + const char *env; + cairo_bool_t result = FALSE; + char *to_replace; + + /* Construct the name of the env var */ + env_name = malloc (strlen (prefix) + strlen (target->name) + 1 + strlen (content) + 1); + if (env_name == NULL) { + fprintf(stderr, "Malloc failed, cannot check $%s%s_%s\n", prefix, target->name, content); + cairo_test_log(ctx, "Malloc failed, cannot check $%s%s_%s\n", prefix, target->name, content); + return FALSE; + } + strcpy (env_name, prefix); + strcat (env_name, target->name); + strcat (env_name, "_"); + strcat (env_name, content); + + /* Deal with some invalid characters: Replace '-' and '&' with '_' */ + while ((to_replace = strchr(env_name, '-')) != NULL) { + *to_replace = '_'; + } + while ((to_replace = strchr(env_name, '&')) != NULL) { + *to_replace = '_'; + } + + env = getenv (env_name); + + /* Look for the test name in the env var (comma separated) */ + if (env) { + for (size_t start = 0;; start += strlen (ctx->test_name)) { + char *match = strstr (env + start, ctx->test_name); + if (!match) + break; + + /* Make sure that "foo" does not match in "barfoo,foobaz" + * There must be commas around the test name (or string begin/end) + */ + if (env == match || match[-1] == ',') { + char *end = match + strlen (ctx->test_name); + if (*end == '\0' || *end == ',') { + result = TRUE; + break; + } + } + } + } + if (result) + cairo_test_log (ctx, + "Expecting '%s' to fail because it appears in $%s\n", + ctx->test_name, env_name); + + free (env_name); + + return result; +} + + +static cairo_bool_t +_version_compare (int a, cairo_test_compare_op_t op, int b) +{ + switch (op) { + case GT: return a > b; + case GE: return a >= b; + default: return FALSE; + } +} + + +static cairo_bool_t +_get_required_version (const char *str, + cairo_test_compare_op_t *op, + int *major, + int *minor, + int *micro) +{ + while (*str == ' ') + str++; + + if (strncmp (str, ">=", 2) == 0) { + *op = GE; + str += 2; + } else if (strncmp (str, ">", 1) == 0) { + *op = GT; + str += 1; + } else + return FALSE; + + while (*str == ' ') + str++; + + if (sscanf (str, "%d.%d.%d", major, minor, micro) != 3) { + *micro = 0; + if (sscanf (str, "%d.%d", major, minor) != 2) + return FALSE; + } + + return TRUE; +} + +static cairo_bool_t +_has_required_cairo_version (const char *str) +{ + cairo_test_compare_op_t op; + int major, minor, micro; + + if (! _get_required_version (str + 5 /* advance over "cairo" */, + &op, &major, &minor, µ)) + { + fprintf (stderr, "unrecognised cairo version requirement '%s'\n", str); + return FALSE; + } + + return _version_compare (cairo_version (), + op, + CAIRO_VERSION_ENCODE (major, minor, micro)); +} + +#define TEST_SIMILAR 0x1 +#define TEST_OFFSET 0x2 +#define TEST_SCALE 0x4 +int +main (int argc, char **argv) +{ + cairo_test_runner_t runner; + cairo_test_list_t *test_list; + cairo_test_status_t *target_status; + unsigned int n, m, k; + char targets[4096]; + int len; + char *cairo_tests_env; + +#ifdef _MSC_VER + /* We don't want an assert dialog, we want stderr */ + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); +#endif + + _cairo_test_runner_register_tests (); + tests = _list_reverse (tests); + + memset (&runner, 0, sizeof (runner)); + runner.num_device_offsets = 1; + runner.num_device_scales = 1; + + if (is_running_under_debugger ()) + runner.foreground = TRUE; + + if (getenv ("CAIRO_TEST_MODE")) { + const char *env = getenv ("CAIRO_TEST_MODE"); + + if (strstr (env, "full")) { + runner.full_test = ~0; + } + if (strstr (env, "similar")) { + runner.full_test |= TEST_SIMILAR; + } + if (strstr (env, "offset")) { + runner.full_test |= TEST_OFFSET; + } + if (strstr (env, "scale")) { + runner.full_test |= TEST_SCALE; + } + if (strstr (env, "foreground")) { + runner.foreground = TRUE; + } + if (strstr (env, "exit-on-failure")) { + runner.exit_on_failure = TRUE; + } + } + + if (getenv ("CAIRO_TEST_FORCE_PASS")) { + const char *env = getenv ("CAIRO_TEST_FORCE_PASS"); + + runner.force_pass = atoi (env); + } + + _parse_cmdline (&runner, &argc, &argv); + + cairo_tests_env = getenv("CAIRO_TESTS"); + append_argv (&argc, &argv, cairo_tests_env); + + if (runner.full_test & TEST_OFFSET) { + runner.num_device_offsets = 2; + } + if (runner.full_test & TEST_SCALE) { + runner.num_device_scales = 2; + } + + target_status = NULL; /* silence the compiler */ + if (! runner.list_only) { + _runner_init (&runner); + _runner_print_versions (&runner); + target_status = xmalloc (sizeof (cairo_test_status_t) * + runner.base.num_targets); + } + + for (test_list = tests; test_list != NULL; test_list = test_list->next) { + const cairo_test_t *test = test_list->test; + cairo_test_context_t ctx; + cairo_test_status_t status; + cairo_bool_t failed = FALSE, xfailed = FALSE, error = FALSE, crashed = FALSE, skipped = TRUE; + cairo_bool_t in_preamble = FALSE; + char *name = cairo_test_get_name (test); + int i; + + /* check for restricted runs */ + if (argc) { + cairo_bool_t found = FALSE; + const char *keywords = test->keywords; + + for (i = 0; i < argc; i++) { + const char *match = argv[i]; + cairo_bool_t invert = match[0] == '!'; + if (invert) + match++; + + if (runner.keyword_match) { + if (keywords != NULL && strstr (keywords, match) != NULL) { + found = ! invert; + break; + } else if (invert) { + found = TRUE; + } + } else { + /* exact match on test name */ + if (strcmp (name, match) == 0) { + found = ! invert; + break; + } else if (invert) { + found = TRUE; + } + } + } + + if (! found) { + free (name); + continue; + } + } + + /* check to see if external requirements match */ + if (test->requirements != NULL) { + const char *requirements = test->requirements; + const char *str; + + str = strstr (requirements, "slow"); + if (str != NULL && ! runner.slow) { + if (runner.list_only) + goto TEST_NEXT; + else + goto TEST_SKIPPED; + } + + str = strstr (requirements, "cairo"); + if (str != NULL && ! _has_required_cairo_version (str)) { + if (runner.list_only) + goto TEST_NEXT; + else + goto TEST_SKIPPED; + } + } + + if (runner.list_only) { + printf ("%s ", name); + goto TEST_NEXT; + } + + _cairo_test_context_init_for_test (&ctx, &runner.base, test); + memset (target_status, 0, + sizeof (cairo_test_status_t) * ctx.num_targets); + + if (ctx.test->preamble != NULL) { + status = _cairo_test_runner_preamble (&runner, &ctx); + if (getenv ("CAIRO_TEST_UGLY_HACK_TO_IGNORE_PS_FAILURES")) { + if (strcmp (ctx.test_name, "ps-eps") == 0) { + if (status == CAIRO_TEST_FAILURE) { + cairo_test_log (&ctx, "Turning FAIL into XFAIL due to env\n"); + fprintf (stderr, "Turning FAIL into XFAIL due to env\n"); + runner.num_ignored_via_env++; + status = CAIRO_TEST_XFAILURE; + } else { + fprintf (stderr, "Test was expected to fail due to an environment variable, but did not!\n"); + fprintf (stderr, "Please update the corresponding CAIRO_TEST_IGNORE_* variable.\n"); + status = CAIRO_TEST_ERROR; + } + } + } + switch (status) { + case CAIRO_TEST_SUCCESS: + in_preamble = TRUE; + skipped = FALSE; + break; + + case CAIRO_TEST_XFAILURE: + in_preamble = TRUE; + xfailed = TRUE; + goto TEST_DONE; + + case CAIRO_TEST_NEW: + case CAIRO_TEST_FAILURE: + runner.fails_preamble = _list_prepend (runner.fails_preamble, + test); + in_preamble = TRUE; + failed = TRUE; + goto TEST_DONE; + + case CAIRO_TEST_ERROR: + runner.errors_preamble = _list_prepend (runner.errors_preamble, + test); + in_preamble = TRUE; + failed = TRUE; + goto TEST_DONE; + + case CAIRO_TEST_NO_MEMORY: + case CAIRO_TEST_CRASHED: + runner.crashes_preamble = _list_prepend (runner.crashes_preamble, + test); + in_preamble = TRUE; + failed = TRUE; + goto TEST_DONE; + + case CAIRO_TEST_UNTESTED: + goto TEST_DONE; + } + } + + if (ctx.test->draw == NULL) + goto TEST_DONE; + + for (n = 0; n < ctx.num_targets; n++) { + const cairo_boilerplate_target_t *target; + cairo_bool_t target_failed = FALSE, + target_xfailed = FALSE, + target_error = FALSE, + target_crashed = FALSE, + target_skipped = TRUE; + cairo_test_similar_t has_similar; + + target = ctx.targets_to_test[n]; + + has_similar = runner.full_test & TEST_SIMILAR ? + cairo_test_target_has_similar (&ctx, target) : + DIRECT; + for (m = 0; m < runner.num_device_offsets; m++) { + for (k = 0; k < runner.num_device_scales; k++) { + int dev_offset = m * 25; + int dev_scale = k + 1; + cairo_test_similar_t similar; + + for (similar = DIRECT; similar <= has_similar; similar++) { + status = _cairo_test_runner_draw (&runner, &ctx, target, + similar, dev_offset, dev_scale); + + if (expect_fail_due_to_env_var (&ctx, target)) { + if (status == CAIRO_TEST_FAILURE) { + cairo_test_log (&ctx, "Turning FAIL into XFAIL due to env\n"); + fprintf (stderr, "Turning FAIL into XFAIL due to env\n"); + runner.num_ignored_via_env++; + status = CAIRO_TEST_XFAILURE; + } else { + fprintf (stderr, "Test was expected to fail due to an environment variable, but did not!\n"); + fprintf (stderr, "Please update the corresponding CAIRO_TEST_IGNORE_* variable.\n"); + status = CAIRO_TEST_ERROR; + } + } + if (getenv ("CAIRO_TEST_UGLY_HACK_TO_SOMETIMES_IGNORE_SCRIPT_XCB_HUGE_IMAGE_SHM")) { + if (strcmp (target->name, "script") == 0 && strcmp (ctx.test_name, "xcb-huge-image-shm") == 0) { + if (status == CAIRO_TEST_FAILURE) { + fprintf (stderr, "This time the xcb-huge-image-shm test on script surface failed.\n"); + cairo_test_log (&ctx, "Turning FAIL into XFAIL due to env\n"); + fprintf (stderr, "Turning FAIL into XFAIL due to env\n"); + runner.num_ignored_via_env++; + } else { + fprintf (stderr, "This time the xcb-huge-image-shm test on script surface did not fail.\n"); + cairo_test_log (&ctx, "Turning the status into XFAIL due to env\n"); + fprintf (stderr, "Turning the status into XFAIL due to env\n"); + } + status = CAIRO_TEST_XFAILURE; + fprintf (stderr, "If you are were getting one of the outcomes for some time, please update this code.\n"); + } + } + switch (status) { + case CAIRO_TEST_SUCCESS: + target_skipped = FALSE; + break; + case CAIRO_TEST_XFAILURE: + target_xfailed = TRUE; + break; + case CAIRO_TEST_NEW: + case CAIRO_TEST_FAILURE: + target_failed = TRUE; + break; + case CAIRO_TEST_ERROR: + target_error = TRUE; + break; + case CAIRO_TEST_NO_MEMORY: + case CAIRO_TEST_CRASHED: + target_crashed = TRUE; + break; + case CAIRO_TEST_UNTESTED: + break; + } + } + } + } + + if (target_crashed) { + target_status[n] = CAIRO_TEST_CRASHED; + runner.num_crashed_per_target[n]++; + runner.crashes_per_target[n] = _list_prepend (runner.crashes_per_target[n], + test); + crashed = TRUE; + } else if (target_error) { + target_status[n] = CAIRO_TEST_ERROR; + runner.num_error_per_target[n]++; + runner.errors_per_target[n] = _list_prepend (runner.errors_per_target[n], + test); + + error = TRUE; + } else if (target_failed) { + target_status[n] = CAIRO_TEST_FAILURE; + runner.num_failed_per_target[n]++; + runner.fails_per_target[n] = _list_prepend (runner.fails_per_target[n], + test); + + failed = TRUE; + } else if (target_xfailed) { + target_status[n] = CAIRO_TEST_XFAILURE; + xfailed = TRUE; + } else if (target_skipped) { + target_status[n] = CAIRO_TEST_UNTESTED; + } else { + target_status[n] = CAIRO_TEST_SUCCESS; + skipped = FALSE; + } + } + + TEST_DONE: + cairo_test_fini (&ctx); + TEST_SKIPPED: + targets[0] = '\0'; + if (crashed) { + if (! in_preamble) { + len = 0; + for (n = 0 ; n < runner.base.num_targets; n++) { + if (target_status[n] == CAIRO_TEST_CRASHED) { + if (strstr (targets, + runner.base.targets_to_test[n]->name) == NULL) + { + len += snprintf (targets + len, sizeof (targets) - len, + "%s, ", + runner.base.targets_to_test[n]->name); + } + } + } + targets[len-2] = '\0'; + _log (&runner.base, "\n%s: CRASH! (%s)\n", name, targets); + } else { + _log (&runner.base, "\n%s: CRASH!\n", name); + } + runner.num_crashed++; + runner.passed = FALSE; + } else if (error) { + if (! in_preamble) { + len = 0; + for (n = 0 ; n < runner.base.num_targets; n++) { + if (target_status[n] == CAIRO_TEST_ERROR) { + if (strstr (targets, + runner.base.targets_to_test[n]->name) == NULL) + { + len += snprintf (targets + len, + sizeof (targets) - len, + "%s, ", + runner.base.targets_to_test[n]->name); + } + } + } + targets[len-2] = '\0'; + _log (&runner.base, "%s: ERROR (%s)\n", name, targets); + } else { + _log (&runner.base, "%s: ERROR\n", name); + } + runner.num_error++; + runner.passed = FALSE; + } else if (failed) { + if (! in_preamble) { + len = 0; + for (n = 0 ; n < runner.base.num_targets; n++) { + if (target_status[n] == CAIRO_TEST_FAILURE) { + if (strstr (targets, + runner.base.targets_to_test[n]->name) == NULL) + { + len += snprintf (targets + len, + sizeof (targets) - len, + "%s, ", + runner.base.targets_to_test[n]->name); + } + } + } + targets[len-2] = '\0'; + _log (&runner.base, "%s: FAIL (%s)\n", name, targets); + } else { + _log (&runner.base, "%s: FAIL\n", name); + } + runner.num_failed++; + runner.passed = FALSE; + } else if (xfailed) { + _log (&runner.base, "%s: XFAIL\n", name); + runner.num_xfailed++; + } else if (skipped) { + _log (&runner.base, "%s: UNTESTED\n", name); + runner.num_skipped++; + } else { + _log (&runner.base, "%s: PASS\n", name); + runner.num_passed++; + } + fflush (runner.base.log_file); + + TEST_NEXT: + free (name); + if (runner.exit_on_failure && ! runner.passed) + break; + + } + + if (cairo_tests_env) + free(argv); + + if (runner.list_only) { + printf ("\n"); + return CAIRO_TEST_SUCCESS; + } + + for (n = 0 ; n < runner.base.num_targets; n++) { + runner.crashes_per_target[n] = _list_reverse (runner.crashes_per_target[n]); + runner.errors_per_target[n] = _list_reverse (runner.errors_per_target[n]); + runner.fails_per_target[n] = _list_reverse (runner.fails_per_target[n]); + } + + _runner_print_results (&runner); + + _list_free (tests); + free (target_status); + return _runner_fini (&runner); +} + +void +cairo_test_register (cairo_test_t *test) +{ + tests = _list_prepend (tests, test); +} diff --git a/local/recipes/libs/cairo/source/test/cairo-test-trace.c b/local/recipes/libs/cairo/source/test/cairo-test-trace.c new file mode 100644 index 0000000000..32987a7ad6 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/cairo-test-trace.c @@ -0,0 +1,1795 @@ +/* + * Copyright © 2009 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * the authors not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. The authors make no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Chris Wilson + */ + +/* + * The basic idea is that we feed the trace to multiple backends in parallel + * and compare the output at the end of each context (based on the premise + * that contexts demarcate expose events, or their logical equivalents) with + * that of the image[1] backend. Each backend is executed in a separate + * process, for robustness and to isolate the global cairo state, with the + * image data residing in shared memory and synchronising over a socket. + * + * [1] Should be reference implementation, currently the image backend is + * considered to be the reference for all other backends. + */ + +/* XXX Can't directly compare fills using spans versus trapezoidation, + * i.e. xlib vs image. Gah, kinda renders this whole scheme moot. + * How about reference platforms? + * E.g. accelerated xlib driver vs Xvfb? + * + * boilerplate->create_reference_surface()? + * boilerplate->reference->create_surface()? + * So for each backend spawn two processes, a reference and xlib + * (obviously minimising the number of reference processes when possible) + */ + +/* + * XXX Handle show-page as well as cairo_destroy()? Though arguably that is + * only relevant for paginated backends which is currently outside the + * scope of this test. + */ + +#include "cairo-test.h" +#include "buffer-diff.h" + +#include "cairo-boilerplate-getopt.h" +#include +#include "cairo-missing.h" + +#if CAIRO_HAS_SCRIPT_SURFACE +#include +#endif + +/* For basename */ +#ifdef HAVE_LIBGEN_H +#include +#endif +#include /* isspace() */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if CAIRO_HAS_REAL_PTHREAD +#include +#endif + +#if defined(HAVE_POLL_H) +#include +#elif defined(HAVE_SYS_POLL_H) +#include +#else +#error No poll.h equivalent found +#endif + +#if HAVE_FCFINI +#include +#endif + +#ifndef MAP_NORESERVE +#define MAP_NORESERVE 0 +#endif + +#define DEBUG 0 + +#define ignore_image_differences 0 /* XXX make me a cmdline option! */ +#define write_results 1 +#define write_traces 1 + +#define DATA_SIZE (256 << 20) +#define SHM_PATH_XXX "/.shmem-cairo-trace" + +typedef struct _test_trace { + /* Options from command-line */ + cairo_bool_t list_only; + char **names; + unsigned int num_names; + char **exclude_names; + unsigned int num_exclude_names; + + /* Stuff used internally */ + const cairo_boilerplate_target_t **targets; + int num_targets; +} test_trace_t; + +typedef struct _test_runner { + const char *name; + cairo_surface_t *surface; + void *closure; + uint8_t *base; + const char *trace; + pid_t pid; + int sk; + cairo_bool_t is_recording; + + cairo_script_interpreter_t *csi; + struct context_closure { + struct context_closure *next; + unsigned long id; + unsigned long start_line; + unsigned long end_line; + cairo_t *context; + cairo_surface_t *surface; + } *contexts; + + unsigned long context_id; +} test_runner_t; + +struct slave { + pid_t pid; + int fd; + unsigned long image_serial; + unsigned long image_ready; + unsigned long start_line; + unsigned long end_line; + cairo_surface_t *image; + long width, height; + cairo_surface_t *difference; + buffer_diff_result_t result; + const cairo_boilerplate_target_t *target; + const struct slave *reference; + cairo_bool_t is_recording; +}; + +struct request_image { + unsigned long id; + unsigned long start_line; + unsigned long end_line; + cairo_format_t format; + long width; + long height; + long stride; +}; + +struct surface_tag { + long width, height; +}; +static const cairo_user_data_key_t surface_tag; + +#define TARGET_NAME(T) ((T) ? (T)->name : "recording") + +#if CAIRO_HAS_REAL_PTHREAD +#define tr_die(t) t->is_recording ? pthread_exit(NULL) : exit(1) +#else +#define tr_die(t) exit(1) +#endif + +static cairo_bool_t +writen (int fd, const void *ptr, int len) +{ +#if 0 + const uint8_t *data = ptr; + while (len) { + int ret = write (fd, data, len); + if (ret < 0) { + switch (errno) { + case EAGAIN: + case EINTR: + continue; + default: + return FALSE; + } + } else if (ret == 0) { + return FALSE; + } else { + data += ret; + len -= ret; + } + } + return TRUE; +#else + int ret = send (fd, ptr, len, 0); + return ret == len; +#endif +} + +static cairo_bool_t +readn (int fd, void *ptr, int len) +{ +#if 0 + uint8_t *data = ptr; + while (len) { + int ret = read (fd, data, len); + if (ret < 0) { + switch (errno) { + case EAGAIN: + case EINTR: + continue; + default: + return FALSE; + } + } else if (ret == 0) { + return FALSE; + } else { + data += ret; + len -= ret; + } + } + return TRUE; +#else + int ret = recv (fd, ptr, len, MSG_WAITALL); + return ret == len; +#endif +} + +static cairo_format_t +format_for_content (cairo_content_t content) +{ + switch (content) { + case CAIRO_CONTENT_ALPHA: + return CAIRO_FORMAT_A8; + case CAIRO_CONTENT_COLOR: + return CAIRO_FORMAT_RGB24; + default: + case CAIRO_CONTENT_COLOR_ALPHA: + return CAIRO_FORMAT_ARGB32; + } +} + +static void +send_recording_surface (test_runner_t *tr, + int width, int height, + struct context_closure *closure) +{ +#if CAIRO_HAS_REAL_PTHREAD + const struct request_image rq = { + closure->id, + closure->start_line, + closure->end_line, + -1, + width, height, + (long) closure->surface, + }; + unsigned long offset; + unsigned long serial; + + if (DEBUG > 1) { + printf ("send-recording-surface: %lu [%lu, %lu]\n", + closure->id, + closure->start_line, + closure->end_line); + } + writen (tr->sk, &rq, sizeof (rq)); + readn (tr->sk, &offset, sizeof (offset)); + + /* signal completion */ + writen (tr->sk, &closure->id, sizeof (closure->id)); + + /* wait for image check */ + serial = 0; + readn (tr->sk, &serial, sizeof (serial)); + if (DEBUG > 1) { + printf ("send-recording-surface: serial: %lu\n", serial); + } + if (serial != closure->id) + pthread_exit (NULL); +#else + exit (1); +#endif +} + +static void * +request_image (test_runner_t *tr, + struct context_closure *closure, + cairo_format_t format, + int width, int height, int stride) +{ + const struct request_image rq = { + closure->id, + closure->start_line, + closure->end_line, + format, width, height, stride + }; + unsigned long offset = -1; + + assert (format != (cairo_format_t) -1); + + writen (tr->sk, &rq, sizeof (rq)); + readn (tr->sk, &offset, sizeof (offset)); + if (offset == (unsigned long) -1) + return NULL; + + return tr->base + offset; +} + +static void +send_surface (test_runner_t *tr, + struct context_closure *closure) +{ + cairo_surface_t *source = closure->surface; + cairo_surface_t *image; + cairo_format_t format = (cairo_format_t) -1; + cairo_t *cr; + int width, height, stride; + void *data; + unsigned long serial; + + if (DEBUG > 1) { + printf ("send-surface: '%s', is-recording? %d\n", + tr->name, tr->is_recording); + } + + if (cairo_surface_get_type (source) == CAIRO_SURFACE_TYPE_IMAGE) { + width = cairo_image_surface_get_width (source); + height = cairo_image_surface_get_height (source); + format = cairo_image_surface_get_format (source); + } else { + struct surface_tag *tag; + + tag = cairo_surface_get_user_data (source, &surface_tag); + if (tag != NULL) { + width = tag->width; + height = tag->height; + } else { + double x0, x1, y0, y1; + + /* presumably created using cairo_surface_create_similar() */ + cr = cairo_create (source); + cairo_clip_extents (cr, &x0, &y0, &x1, &y1); + cairo_destroy (cr); + + tag = xmalloc (sizeof (*tag)); + width = tag->width = x1 - x0; + height = tag->height = y1 - y0; + + if (cairo_surface_set_user_data (source, &surface_tag, tag, free)) + tr_die (tr); + } + } + + if (tr->is_recording) { + send_recording_surface (tr, width, height, closure); + return; + } + + if (format == (cairo_format_t) -1) + format = format_for_content (cairo_surface_get_content (source)); + + stride = cairo_format_stride_for_width (format, width); + + data = request_image (tr, closure, format, width, height, stride); + if (data == NULL) + tr_die (tr); + + image = cairo_image_surface_create_for_data (data, + format, + width, height, + stride); + cr = cairo_create (image); + cairo_surface_destroy (image); + + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_surface (cr, source, 0, 0); + cairo_paint (cr); + cairo_destroy (cr); + + /* signal completion */ + writen (tr->sk, &closure->id, sizeof (closure->id)); + + /* wait for image check */ + serial = 0; + readn (tr->sk, &serial, sizeof (serial)); + if (serial != closure->id) + tr_die (tr); +} + +static cairo_surface_t * +_surface_create (void *closure, + cairo_content_t content, + double width, double height, + long uid) +{ + test_runner_t *tr = closure; + cairo_surface_t *surface; + + surface = cairo_surface_create_similar (tr->surface, + content, width, height); + if (cairo_surface_get_type (surface) != CAIRO_SURFACE_TYPE_IMAGE) { + struct surface_tag *tag; + + tag = xmalloc (sizeof (*tag)); + tag->width = width; + tag->height = height; + if (cairo_surface_set_user_data (surface, &surface_tag, tag, free)) + tr_die (tr); + } + + return surface; +} + +static cairo_t * +_context_create (void *closure, cairo_surface_t *surface) +{ + test_runner_t *tr = closure; + struct context_closure *l; + + if (DEBUG) { + fprintf (stderr, "%s: starting context %lu on line %d\n", + tr->name ? tr->name : "recording" , + tr->context_id + 1, + cairo_script_interpreter_get_line_number (tr->csi)); + } + + l = xmalloc (sizeof (*l)); + l->next = tr->contexts; + l->start_line = cairo_script_interpreter_get_line_number (tr->csi); + l->end_line = l->start_line; + l->context = cairo_create (surface); + l->surface = cairo_surface_reference (surface); + l->id = ++tr->context_id; + if (l->id == 0) + l->id = ++tr->context_id; + tr->contexts = l; + + return l->context; +} + +static void +_context_destroy (void *closure, void *ptr) +{ + test_runner_t *tr = closure; + struct context_closure *l, **prev = &tr->contexts; + + while ((l = *prev) != NULL) { + if (l->context == ptr) { + if (DEBUG) { + fprintf (stderr, "%s: context %lu complete on line %d\n", + tr->name ? tr->name : "recording" , + tr->context_id, + cairo_script_interpreter_get_line_number (tr->csi)); + } + l->end_line = + cairo_script_interpreter_get_line_number (tr->csi); + if (cairo_surface_status (l->surface) == CAIRO_STATUS_SUCCESS) { + send_surface (tr, l); + } else { + fprintf (stderr, "%s: error during replay, line %lu: %s!\n", + tr->name, + l->end_line, + cairo_status_to_string (cairo_surface_status (l->surface))); + tr_die (tr); + } + + cairo_surface_destroy (l->surface); + *prev = l->next; + free (l); + return; + } + prev = &l->next; + } +} + +static void +execute (test_runner_t *tr) +{ + const cairo_script_interpreter_hooks_t hooks = { + .closure = tr, + .surface_create = _surface_create, + .context_create = _context_create, + .context_destroy = _context_destroy, + }; + pid_t ack; + + tr->csi = cairo_script_interpreter_create (); + cairo_script_interpreter_install_hooks (tr->csi, &hooks); + + ack = -1; + readn (tr->sk, &ack, sizeof (ack)); + if (ack != tr->pid) + tr_die (tr); + + cairo_script_interpreter_run (tr->csi, tr->trace); + + cairo_script_interpreter_finish (tr->csi); + if (cairo_script_interpreter_destroy (tr->csi)) + tr_die (tr); +} + +static int +spawn_socket (const char *socket_path, pid_t pid) +{ + struct sockaddr_un addr; + int sk; + + sk = socket (PF_UNIX, SOCK_STREAM, 0); + if (sk == -1) + return -1; + + memset (&addr, 0, sizeof (addr)); + addr.sun_family = AF_UNIX; + strcpy (addr.sun_path, socket_path); + + if (connect (sk, (struct sockaddr *) &addr, sizeof (addr)) == -1) + return -1; + + if (! writen (sk, &pid, sizeof (pid))) + return -1; + + return sk; +} + +static void * +spawn_shm (const char *shm_path) +{ + void *base; + int fd; + + fd = shm_open (shm_path, O_RDWR, 0); + if (fd == -1) + return MAP_FAILED; + + base = mmap (NULL, DATA_SIZE, + PROT_READ | PROT_WRITE, +#ifdef MAP_NORESERVE + MAP_SHARED | MAP_NORESERVE, +#else + MAP_SHARED, +#endif + fd, 0); + close (fd); + + return base; +} + +static int +spawn_target (const char *socket_path, + const char *shm_path, + const cairo_boilerplate_target_t *target, + const char *trace) +{ + test_runner_t tr; + pid_t pid; + + if (DEBUG) + printf ("Spawning slave '%s' for %s\n", target->name, trace); + + pid = fork (); + if (pid != 0) + return pid; + + tr.is_recording = FALSE; + tr.pid = getpid (); + + tr.sk = spawn_socket (socket_path, tr.pid); + if (tr.sk == -1) { + fprintf (stderr, "%s: Failed to open socket.\n", + target->name); + exit (-1); + } + + tr.base = spawn_shm (shm_path); + if (tr.base == MAP_FAILED) { + fprintf (stderr, "%s: Failed to map shared memory segment.\n", + target->name); + exit (-1); + } + + tr.name = target->name; + tr.contexts = NULL; + tr.context_id = 0; + tr.trace = trace; + + tr.surface = target->create_surface (NULL, + target->content, + 1, 1, + 1, 1, + CAIRO_BOILERPLATE_MODE_TEST, + &tr.closure); + if (tr.surface == NULL) { + fprintf (stderr, + "%s: Failed to create target surface.\n", + target->name); + exit (-1); + } + + execute (&tr); + + cairo_surface_destroy (tr.surface); + + if (target->cleanup) + target->cleanup (tr.closure); + + close (tr.sk); + munmap (tr.base, DATA_SIZE); + + exit (0); +} + +#if CAIRO_HAS_REAL_PTHREAD +static void +cleanup_recorder (void *arg) +{ + test_runner_t *tr = arg; + + cairo_surface_finish (tr->surface); + cairo_surface_destroy (tr->surface); + + close (tr->sk); + free (tr); +} + +static void * +record (void *arg) +{ + test_runner_t *tr = arg; + + pthread_cleanup_push (cleanup_recorder, tr); + execute (tr); + pthread_cleanup_pop (TRUE); + + return NULL; +} + +/* The recorder is special: + * 1. It doesn't generate an image, but keeps an in-memory trace to + * reconstruct any surface. + * 2. Runs in the same process, but separate thread. + */ +static pid_t +spawn_recorder (const char *socket_path, const char *trace, test_runner_t **out) +{ + test_runner_t *tr; + pthread_t id; + pthread_attr_t attr; + pid_t pid = getpid (); + + if (DEBUG) + printf ("Spawning recorder for %s\n", trace); + + tr = malloc (sizeof (*tr)); + if (tr == NULL) + return -1; + + tr->is_recording = TRUE; + tr->pid = pid; + tr->sk = spawn_socket (socket_path, tr->pid); + if (tr->sk == -1) { + free (tr); + return -1; + } + + tr->base = NULL; + tr->name = NULL; + tr->contexts = NULL; + tr->context_id = 0; + tr->trace = trace; + + tr->surface = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, + NULL); + if (tr->surface == NULL) { + cleanup_recorder (tr); + return -1; + } + + pthread_attr_init (&attr); + pthread_attr_setdetachstate (&attr, TRUE); + if (pthread_create (&id, &attr, record, tr) < 0) { + pthread_attr_destroy (&attr); + cleanup_recorder (tr); + return -1; + } + pthread_attr_destroy (&attr); + + + *out = tr; + return pid; +} +#endif + +/* XXX imagediff - is the extra expense worth it? */ +static cairo_bool_t +matches_reference (struct slave *slave) +{ + cairo_surface_t *a, *b; + + a = slave->image; + b = slave->reference->image; + + if (a == b) + return TRUE; + + if (a == NULL || b == NULL) + return FALSE; + + if (cairo_surface_status (a) || cairo_surface_status (b)) + return FALSE; + + if (cairo_surface_get_type (a) != cairo_surface_get_type (b)) + return FALSE; + + if (cairo_image_surface_get_format (a) != cairo_image_surface_get_format (b)) + return FALSE; + + if (cairo_image_surface_get_width (a) != cairo_image_surface_get_width (b)) + return FALSE; + + if (cairo_image_surface_get_height (a) != cairo_image_surface_get_height (b)) + return FALSE; + + if (cairo_image_surface_get_stride (a) != cairo_image_surface_get_stride (b)) + return FALSE; + + if (FALSE && cairo_surface_get_content (a) & CAIRO_CONTENT_COLOR) { + cairo_surface_t *diff; + int width, height, stride, size; + unsigned char *data; + cairo_status_t status; + + width = cairo_image_surface_get_width (a); + height = cairo_image_surface_get_height (a); + stride = cairo_image_surface_get_stride (a); + size = height * stride * 4; + data = malloc (size); + if (data == NULL) + return FALSE; + + diff = cairo_image_surface_create_for_data (data, + cairo_image_surface_get_format (a), + width, height, stride); + cairo_surface_set_user_data (diff, (cairo_user_data_key_t *) diff, + data, free); + + status = image_diff (NULL, a, b, diff, &slave->result); + if (status) { + cairo_surface_destroy (diff); + return FALSE; + } + + if (image_diff_is_failure (&slave->result, slave->target->error_tolerance)) { + slave->difference = diff; + return FALSE; + } else { + cairo_surface_destroy (diff); + return TRUE; + } + } else { + int width, height, stride; + const uint8_t *aa, *bb; + int x, y; + + width = cairo_image_surface_get_width (a); + height = cairo_image_surface_get_height (a); + stride = cairo_image_surface_get_stride (a); + + aa = cairo_image_surface_get_data (a); + bb = cairo_image_surface_get_data (b); + switch (cairo_image_surface_get_format (a)) { + case CAIRO_FORMAT_ARGB32: + for (y = 0; y < height; y++) { + const uint32_t *ua = (uint32_t *) aa; + const uint32_t *ub = (uint32_t *) bb; + for (x = 0; x < width; x++) { + if (ua[x] != ub[x]) { + int channel; + + for (channel = 0; channel < 4; channel++) { + int va, vb; + unsigned diff; + + va = (ua[x] >> (channel*8)) & 0xff; + vb = (ub[x] >> (channel*8)) & 0xff; + diff = abs (va - vb); + if (diff > slave->target->error_tolerance) + return FALSE; + } + } + } + aa += stride; + bb += stride; + } + break; + + case CAIRO_FORMAT_RGB24: + for (y = 0; y < height; y++) { + const uint32_t *ua = (uint32_t *) aa; + const uint32_t *ub = (uint32_t *) bb; + for (x = 0; x < width; x++) { + if ((ua[x] & 0x00ffffff) != (ub[x] & 0x00ffffff)) { + int channel; + + for (channel = 0; channel < 3; channel++) { + int va, vb; + unsigned diff; + + va = (ua[x] >> (channel*8)) & 0xff; + vb = (ub[x] >> (channel*8)) & 0xff; + diff = abs (va - vb); + if (diff > slave->target->error_tolerance) + return FALSE; + } + } + } + aa += stride; + bb += stride; + } + break; + + case CAIRO_FORMAT_A8: + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + if (aa[x] != bb[x]) { + unsigned diff = abs (aa[x] - bb[x]); + if (diff > slave->target->error_tolerance) + return FALSE; + } + } + aa += stride; + bb += stride; + } + break; + + case CAIRO_FORMAT_A1: + width /= 8; + for (y = 0; y < height; y++) { + if (memcmp (aa, bb, width)) + return FALSE; + aa += stride; + bb += stride; + } + break; + + case CAIRO_FORMAT_RGB30: + case CAIRO_FORMAT_RGB16_565: + case CAIRO_FORMAT_RGB96F: + case CAIRO_FORMAT_RGBA128F: + case CAIRO_FORMAT_INVALID: + assert (0); + } + + return TRUE; + } +} + +static cairo_bool_t +check_images (struct slave *slaves, int num_slaves) +{ + int n; + + if (ignore_image_differences) + return TRUE; + + for (n = 0; n < num_slaves; n++) { + if (slaves[n].reference == NULL) + continue; + + if (! matches_reference (&slaves[n])) + return FALSE; + } + + return TRUE; +} + +static void +write_images (const char *trace, struct slave *slave, int num_slaves) +{ + while (num_slaves--) { + if (slave->image != NULL && ! slave->is_recording) { + char *filename; + + xasprintf (&filename, "%s-%s-fail.png", + trace, slave->target->name); + cairo_surface_write_to_png (slave->image, filename); + free (filename); + + if (slave->difference) { + xasprintf (&filename, "%s-%s-diff.png", + trace, slave->target->name); + cairo_surface_write_to_png (slave->difference, filename); + free (filename); + } + } + + slave++; + } +} + +static void +write_result (const char *trace, struct slave *slave) +{ + static int index; + char *filename; + + xasprintf (&filename, "%s-%s-pass-%d-%ld-%ld.png", + trace, slave->target->name, ++index, + slave->start_line, slave->end_line); + cairo_surface_write_to_png (slave->image, filename); + free (filename); +} + +static void +write_trace (const char *trace, const char *id, struct slave *slave) +{ +#if CAIRO_HAS_SCRIPT_SURFACE + cairo_device_t *script; + char *filename; + + assert (slave->is_recording); + + xasprintf (&filename, "%s-%s.trace", trace, id); + + script = cairo_script_create (filename); + cairo_script_from_recording_surface (script, slave->image); + cairo_device_destroy (script); + + free (filename); +#endif +} + +static void +dump_traces (test_runner_t *tr, + const char *trace, + const char *target, + const char *fail) +{ +#if CAIRO_HAS_SCRIPT_SURFACE + struct context_closure *c; + + for (c = tr->contexts; c; c = c->next) { + cairo_device_t *script; + char *filename; + + xasprintf (&filename, "%s-%s-%s.%lu.trace", + trace, target, fail, c->start_line); + + script = cairo_script_create (filename); + cairo_script_from_recording_surface (script, c->surface); + cairo_device_destroy (script); + + free (filename); + } +#endif +} + +static unsigned long +allocate_image_for_slave (uint8_t *base, + unsigned long offset, + struct slave *slave) +{ + struct request_image rq; + int size; + uint8_t *data; + + assert (slave->image == NULL); + + readn (slave->fd, &rq, sizeof (rq)); + slave->image_serial = rq.id; + slave->start_line = rq.start_line; + slave->end_line = rq.end_line; + + slave->width = rq.width; + slave->height = rq.height; + + if (DEBUG > 1) { + printf ("allocate-image-for-slave: %s %lu [%lu, %lu] %ldx%ld stride=%lu => %lu, is-recording? %d\n", + TARGET_NAME (slave->target), + slave->image_serial, + slave->start_line, + slave->end_line, + slave->width, + slave->height, + rq.stride, + offset, + slave->is_recording); + } + + if (slave->is_recording) { + /* special communication with recording-surface thread */ + slave->image = cairo_surface_reference ((cairo_surface_t *) rq.stride); + } else { + size = rq.height * rq.stride; + size = (size + 4095) & -4096; + data = base + offset; + offset += size; + assert (offset <= DATA_SIZE); + + slave->image = cairo_image_surface_create_for_data (data, rq.format, + rq.width, rq.height, + rq.stride); + } + + return offset; +} + +struct error_info { + unsigned long context_id; + unsigned long start_line; + unsigned long end_line; +}; + +static cairo_bool_t +test_run (void *base, + int sk, + const char *trace, + struct slave *slaves, + int num_slaves, + struct error_info *error) +{ + struct pollfd *pfd; + int npfd, cnt, n, i; + int completion, err = 0; + cairo_bool_t ret = FALSE; + unsigned long image; + + if (DEBUG) { + printf ("Running trace '%s' over %d slaves\n", + trace, num_slaves); + } + + pfd = xcalloc (num_slaves+1, sizeof (*pfd)); + + pfd[0].fd = sk; + pfd[0].events = POLLIN; + npfd = 1; + + completion = 0; + image = 0; + while ((cnt = poll (pfd, npfd, -1)) > 0) { + if (pfd[0].revents) { + int fd; + + while ((fd = accept (sk, NULL, NULL)) != -1) { + pid_t pid; + + readn (fd, &pid, sizeof (pid)); + for (n = 0; n < num_slaves; n++) { + if (slaves[n].pid == pid) { + slaves[n].fd = fd; + break; + } + } + if (n == num_slaves) { + if (DEBUG) + printf ("unknown slave pid\n"); + goto out; + } + + pfd[npfd].fd = fd; + pfd[npfd].events = POLLIN; + npfd++; + + if (! writen (fd, &pid, sizeof (pid))) + goto out; + } + cnt--; + } + + for (n = 1; n < npfd && cnt; n++) { + if (! pfd[n].revents) + continue; + + if (pfd[n].revents & POLLHUP) { + pfd[n].events = pfd[n].revents = 0; + completion++; + continue; + } + + for (i = 0; i < num_slaves; i++) { + if (slaves[i].fd == pfd[n].fd) { + /* Communication with the slave is done in three phases, + * and we do each pass synchronously. + * + * 1. The slave requests an image buffer, which we + * allocate and then return to the slave the offset into + * the shared memory segment. + * + * 2. The slave indicates that it has finished writing + * into the shared image buffer. The slave now waits + * for the server to collate all the image data - thereby + * throttling the slaves. + * + * 3. After all slaves have finished writing their images, + * we compare them all against the reference image and, + * if satisfied, send an acknowledgement to all slaves. + */ + if (slaves[i].image_serial == 0) { + unsigned long offset; + + image = + allocate_image_for_slave (base, + offset = image, + &slaves[i]); + if (! writen (pfd[n].fd, &offset, sizeof (offset))) { + pfd[n].events = pfd[n].revents = 0; + err = 1; + completion++; + continue; + } + } else { + readn (pfd[n].fd, + &slaves[i].image_ready, + sizeof (slaves[i].image_ready)); + if (DEBUG) { + printf ("slave '%s' reports completion on %lu (expecting %lu)\n", + TARGET_NAME (slaves[i].target), + slaves[i].image_ready, + slaves[i].image_serial); + } + if (slaves[i].image_ready != slaves[i].image_serial) { + pfd[n].events = pfd[n].revents = 0; + err = 1; + completion++; + continue; + } + + /* Can anyone spell 'P·E·D·A·N·T'? */ + if (! slaves[i].is_recording) + cairo_surface_mark_dirty (slaves[i].image); + completion++; + } + + break; + } + } + + cnt--; + } + + if (completion >= num_slaves) { + if (err) { + if (DEBUG > 1) + printf ("error detected\n"); + goto out; + } + + if (DEBUG > 1) { + printf ("all saves report completion\n"); + } + if (slaves[0].end_line >= slaves[0].start_line && + ! check_images (slaves, num_slaves)) { + error->context_id = slaves[0].image_serial; + error->start_line = slaves[0].start_line; + error->end_line = slaves[0].end_line; + + if (DEBUG) { + printf ("check_images failed: %lu, [%lu, %lu]\n", + slaves[0].image_serial, + slaves[0].start_line, + slaves[0].end_line); + } + + write_images (trace, slaves, num_slaves); + + if (slaves[0].is_recording) + write_trace (trace, "fail", &slaves[0]); + + goto out; + } + + if (write_results) write_result (trace, &slaves[1]); + if (write_traces && slaves[0].is_recording) { + char buf[80]; + snprintf (buf, sizeof (buf), "%ld", slaves[0].image_serial); + write_trace (trace, buf, &slaves[0]); + } + + /* ack */ + for (i = 0; i < num_slaves; i++) { + cairo_surface_destroy (slaves[i].image); + slaves[i].image = NULL; + + if (DEBUG > 1) { + printf ("sending continuation to '%s'\n", + TARGET_NAME (slaves[i].target)); + } + if (! writen (slaves[i].fd, + &slaves[i].image_serial, + sizeof (slaves[i].image_serial))) + { + goto out; + } + + slaves[i].image_serial = 0; + slaves[i].image_ready = 0; + } + + completion = 0; + image = 0; + } + } + + ret = TRUE; + +out: + if (DEBUG) { + printf ("run complete: %d\n", ret); + } + + for (n = 0; n < num_slaves; n++) { + if (slaves[n].fd != -1) + close (slaves[n].fd); + + if (slaves[n].image == NULL) + continue; + + cairo_surface_destroy (slaves[n].image); + slaves[n].image = NULL; + + cairo_surface_destroy (slaves[n].difference); + slaves[n].difference = NULL; + + slaves[n].image_serial = 0; + slaves[n].image_ready = 0; + } + + free (pfd); + + return ret; +} + +static int +server_socket (const char *socket_path) +{ + long flags; + struct sockaddr_un addr; + int sk; + + sk = socket (PF_UNIX, SOCK_STREAM, 0); + if (sk == -1) + return -1; + + memset (&addr, 0, sizeof (addr)); + addr.sun_family = AF_UNIX; + strcpy (addr.sun_path, socket_path); + if (bind (sk, (struct sockaddr *) &addr, sizeof (addr)) == -1) { + close (sk); + return -1; + } + + flags = fcntl (sk, F_GETFL); + if (flags == -1 || fcntl (sk, F_SETFL, flags | O_NONBLOCK) == -1) { + close (sk); + return -1; + } + + if (listen (sk, 5) == -1) { + close (sk); + return -1; + } + + return sk; +} + +static int +server_shm (const char *shm_path) +{ + int fd; + + fd = shm_open (shm_path, O_RDWR | O_EXCL | O_CREAT, 0777); + if (fd == -1) + return -1; + + if (ftruncate (fd, DATA_SIZE) == -1) { + close (fd); + return -1; + } + + return fd; +} + +static cairo_bool_t +_test_trace (test_trace_t *test, + const char *trace, + const char *name, + struct error_info *error) +{ + const char *shm_path = SHM_PATH_XXX; + const cairo_boilerplate_target_t *target, *image; + struct slave *slaves, *s; + test_runner_t *recorder = NULL; + pid_t slave; + char socket_dir[] = "/tmp/cairo-test-trace.XXXXXX"; + char *socket_path; + int sk, fd; + int i, num_slaves; + void *base; + cairo_bool_t ret = FALSE; + + if (DEBUG) + printf ("setting up trace '%s'\n", trace); + + /* create a socket to control the test runners */ + if (mkdtemp (socket_dir) == NULL) { + fprintf (stderr, "Unable to create temporary name for socket\n"); + return FALSE; + } + + xasprintf (&socket_path, "%s/socket", socket_dir); + sk = server_socket (socket_path); + if (sk == -1) { + fprintf (stderr, "Unable to create socket for server\n"); + goto cleanup_paths; + } + + /* allocate some shared memory */ + fd = server_shm (shm_path); + if (fd == -1) { + fprintf (stderr, "Unable to create shared memory '%s': %s\n", + shm_path, strerror (errno)); + goto cleanup_sk; + } + + image = cairo_boilerplate_get_image_target (CAIRO_CONTENT_COLOR_ALPHA); + assert (image != NULL); + + s = slaves = xcalloc (2*test->num_targets + 1, sizeof (struct slave)); + +#if CAIRO_HAS_REAL_PTHREAD + /* set-up a recording-surface to reconstruct errors */ + slave = spawn_recorder (socket_path, trace, &recorder); + if (slave < 0) { + fprintf (stderr, "Unable to create recording surface\n"); + goto cleanup_sk; + } + + s->pid = slave; + s->is_recording = TRUE; + s->target = NULL; + s->fd = -1; + s->reference = NULL; + s++; +#endif + + /* spawn slave processes to run the trace */ + for (i = 0; i < test->num_targets; i++) { + const cairo_boilerplate_target_t *reference; + struct slave *master; + + target = test->targets[i]; + + if (DEBUG) + printf ("setting up target[%d]? '%s' (image? %d, measurable? %d)\n", + i, target->name, target == image, target->is_measurable); + + if (target == image || ! target->is_measurable) + continue; + + /* find a matching slave to use as a reference for this target */ + if (target->reference_target != NULL) { + reference = + cairo_boilerplate_get_target_by_name (target->reference_target, + target->content); + assert (reference != NULL); + } else { + reference = image; + } + for (master = slaves; master < s; master++) { + if (master->target == reference) + break; + } + + if (master == s) { + /* no match found, spawn a slave to render the reference image */ + slave = spawn_target (socket_path, shm_path, reference, trace); + if (slave < 0) + continue; + + s->pid = slave; + s->target = reference; + s->fd = -1; + s->reference = NULL; + s++; + } + + slave = spawn_target (socket_path, shm_path, target, trace); + if (slave < 0) + continue; + + s->pid = slave; + s->target = target; + s->fd = -1; + s->reference = master; + s++; + } + num_slaves = s - slaves; + if (num_slaves == 1) { + fprintf (stderr, "No targets to test\n"); + goto cleanup; + } + + base = mmap (NULL, DATA_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (base == MAP_FAILED) { + fprintf (stderr, "Unable to mmap shared memory\n"); + goto cleanup; + } + ret = test_run (base, sk, name, slaves, num_slaves, error); + munmap (base, DATA_SIZE); + +cleanup: + close (fd); + while (s-- > slaves) { + int status; + + if (s->fd != -1) + close (s->fd); + + cairo_surface_destroy (s->image); + cairo_surface_destroy (s->difference); + + if (s->is_recording) /* in-process */ + continue; + + kill (s->pid, SIGKILL); + waitpid (s->pid, &status, 0); + if (WIFSIGNALED (status) && WTERMSIG(status) != SIGKILL) { + fprintf (stderr, "%s crashed\n", s->target->name); + if (recorder) + dump_traces (recorder, trace, s->target->name, "crash"); + } + } + free (slaves); + shm_unlink (shm_path); +cleanup_sk: + close (sk); + +cleanup_paths: + remove (socket_path); + remove (socket_dir); + + free (socket_path); + return ret; +} + +static void +test_trace (test_trace_t *test, const char *trace) +{ + char *trace_cpy, *name, *dot; + + trace_cpy = xstrdup (trace); + name = basename (trace_cpy); + dot = strchr (name, '.'); + if (dot) + *dot = '\0'; + + if (test->list_only) { + printf ("%s\n", name); + } else { + struct error_info error = {0}; + cairo_bool_t ret; + + printf ("%s: ", name); + fflush (stdout); + + ret = _test_trace (test, trace, name, &error); + if (ret) { + printf ("PASS\n"); + } else { + if (error.context_id) { + printf ("FAIL (context %lu, lines [%lu, %lu])\n", + error.context_id, + error.start_line, + error.end_line); + } else { + printf ("FAIL\n"); + } + } + } + + free (trace_cpy); +} + +static cairo_bool_t +read_excludes (test_trace_t *test, const char *filename) +{ + FILE *file; + char *line = NULL; + size_t line_size = 0; + char *s, *t; + + file = fopen (filename, "r"); + if (file == NULL) + return FALSE; + + while (getline (&line, &line_size, file) != -1) { + /* terminate the line at a comment marker '#' */ + s = strchr (line, '#'); + if (s) + *s = '\0'; + + /* whitespace delimits */ + s = line; + while (*s != '\0' && isspace ((unsigned char)*s)) + s++; + + t = s; + while (*t != '\0' && ! isspace ((unsigned char)*t)) + t++; + + if (s != t) { + int i = test->num_exclude_names; + test->exclude_names = xrealloc (test->exclude_names, + sizeof (char *) * (i+1)); + test->exclude_names[i] = strndup (s, t-s); + test->num_exclude_names++; + } + } + free (line); + + fclose (file); + + return TRUE; +} + +static void +usage (const char *argv0) +{ + fprintf (stderr, +"Usage: %s [-l] [-x exclude-file] [test-names ... | traces ...]\n" +"\n" +"Run the cairo test suite over the given traces (all by default).\n" +"The command-line arguments are interpreted as follows:\n" +"\n" +" -l list only; just list selected test case names without executing\n" +" -x exclude; specify a file to read a list of traces to exclude\n" +"\n" +"If test names are given they are used as sub-string matches so a command\n" +"such as \"%s firefox\" can be used to run all firefox traces.\n" +"Alternatively, you can specify a list of filenames to execute.\n", + argv0, argv0); +} + +static void +parse_options (test_trace_t *test, int argc, char *argv[]) +{ + int c; + + test->list_only = FALSE; + test->names = NULL; + test->num_names = 0; + test->exclude_names = NULL; + test->num_exclude_names = 0; + + while (1) { + c = _cairo_getopt (argc, argv, "lx:"); + if (c == -1) + break; + + switch (c) { + case 'l': + test->list_only = TRUE; + break; + case 'x': + if (! read_excludes (test, optarg)) { + fprintf (stderr, "Invalid argument for -x (not readable file): %s\n", + optarg); + exit (1); + } + break; + default: + fprintf (stderr, "Internal error: unhandled option: %c\n", c); + /* fall-through */ + case '?': + usage (argv[0]); + exit (1); + } + } + + if (optind < argc) { + test->names = &argv[optind]; + test->num_names = argc - optind; + } +} + +static void +test_reset (test_trace_t *test) +{ + /* XXX leaking fonts again via recording-surface? */ +#if 0 + cairo_debug_reset_static_data (); +#if HAVE_FCFINI + FcFini (); +#endif +#endif +} + +static void +test_fini (test_trace_t *test) +{ + test_reset (test); + + cairo_boilerplate_free_targets (test->targets); + free (test->exclude_names); +} + +static cairo_bool_t +test_has_filenames (test_trace_t *test) +{ + unsigned int i; + + if (test->num_names == 0) + return FALSE; + + for (i = 0; i < test->num_names; i++) + if (access (test->names[i], R_OK) == 0) + return TRUE; + + return FALSE; +} + +static cairo_bool_t +test_can_run (test_trace_t *test, const char *name) +{ + unsigned int i; + char *copy, *dot; + cairo_bool_t ret; + + if (test->num_names == 0 && test->num_exclude_names == 0) + return TRUE; + + copy = xstrdup (name); + dot = strrchr (copy, '.'); + if (dot != NULL) + *dot = '\0'; + + if (test->num_names) { + ret = TRUE; + for (i = 0; i < test->num_names; i++) + if (strstr (copy, test->names[i])) + goto check_exclude; + + ret = FALSE; + goto done; + } + +check_exclude: + if (test->num_exclude_names) { + ret = FALSE; + for (i = 0; i < test->num_exclude_names; i++) + if (strstr (copy, test->exclude_names[i])) + goto done; + + ret = TRUE; + goto done; + } + +done: + free (copy); + + return ret; +} + +static void +warn_no_traces (const char *message, const char *trace_dir) +{ + fprintf (stderr, +"Error: %s '%s'.\n" +"Have you cloned the cairo-traces repository and uncompressed the traces?\n" +" git clone git://anongit.freedesktop.org/cairo-traces\n" +" cd cairo-traces && make\n" +"Or set the env.var CAIRO_TRACE_DIR to point to your traces?\n", + message, trace_dir); +} + +static void +interrupt (int sig) +{ + shm_unlink (SHM_PATH_XXX); + + signal (sig, SIG_DFL); + raise (sig); +} + +int +main (int argc, char *argv[]) +{ + test_trace_t test; + const char *trace_dir = "cairo-traces"; + unsigned int n; + + signal (SIGPIPE, SIG_IGN); + signal (SIGINT, interrupt); + + parse_options (&test, argc, argv); + + shm_unlink (SHM_PATH_XXX); + + if (getenv ("CAIRO_TRACE_DIR") != NULL) + trace_dir = getenv ("CAIRO_TRACE_DIR"); + + test.targets = cairo_boilerplate_get_targets (&test.num_targets, NULL); + + if (test_has_filenames (&test)) { + for (n = 0; n < test.num_names; n++) { + if (access (test.names[n], R_OK) == 0) { + test_trace (&test, test.names[n]); + test_reset (&test); + } + } + } else { + DIR *dir; + struct dirent *de; + int num_traces = 0; + + dir = opendir (trace_dir); + if (dir == NULL) { + warn_no_traces ("Failed to open directory", trace_dir); + test_fini (&test); + return 1; + } + + while ((de = readdir (dir)) != NULL) { + char *trace; + const char *dot; + + dot = strrchr (de->d_name, '.'); + if (dot == NULL) + continue; + if (strcmp (dot, ".trace")) + continue; + + num_traces++; + if (! test_can_run (&test, de->d_name)) + continue; + + xasprintf (&trace, "%s/%s", trace_dir, de->d_name); + test_trace (&test, trace); + test_reset (&test); + + free (trace); + + } + closedir (dir); + + if (num_traces == 0) { + warn_no_traces ("Found no traces in", trace_dir); + test_fini (&test); + return 1; + } + } + + test_fini (&test); + + return 0; +} + +void +cairo_test_logv (const cairo_test_context_t *ctx, + const char *fmt, va_list va) +{ +#if 0 + vfprintf (stderr, fmt, va); +#endif +} + +void +cairo_test_log (const cairo_test_context_t *ctx, const char *fmt, ...) +{ +#if 0 + va_list va; + + va_start (va, fmt); + vfprintf (stderr, fmt, va); + va_end (va); +#endif +} diff --git a/local/recipes/libs/cairo/source/test/cairo-test.c b/local/recipes/libs/cairo/source/test/cairo-test.c new file mode 100644 index 0000000000..49dfadb15c --- /dev/null +++ b/local/recipes/libs/cairo/source/test/cairo-test.c @@ -0,0 +1,1898 @@ +/* + * Copyright © 2004 Red Hat, Inc. + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + * Chris Wilson + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_FCFINI +#include +#endif +#if CAIRO_HAS_REAL_PTHREAD +#include +#endif +#if HAVE_SYS_STAT_H +#include +#endif + +#if HAVE_VALGRIND +#include +#else +#define RUNNING_ON_VALGRIND 0 +#endif + +#if HAVE_MEMFAULT +#include +#define MF(x) x +#else +#define MF(x) +#endif + +#include "cairo-test-private.h" + +#include "buffer-diff.h" + +#ifdef _MSC_VER +#include +#include +#define F_OK 0 +#define HAVE_MKDIR 1 +#define mkdir _mkdir +#endif + +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE !FALSE +#endif + +#if ! HAVE_ALARM || ! defined(SIGALRM) +#define alarm(X); +#endif + +static const cairo_user_data_key_t _cairo_test_context_key; + +static void +_xunlink (const cairo_test_context_t *ctx, const char *pathname); + +static const char *fail_face = "", *xfail_face="", *normal_face = ""; +static cairo_bool_t print_fail_on_stdout; +static int cairo_test_timeout = 60; + +#define NUM_DEVICE_OFFSETS 2 +#define NUM_DEVICE_SCALE 2 + +cairo_bool_t +cairo_test_mkdir (const char *path) +{ +#if ! HAVE_MKDIR + return FALSE; +#elif HAVE_MKDIR == 1 + if (mkdir (path) == 0) + return TRUE; +#elif HAVE_MKDIR == 2 + if (mkdir (path, 0770) == 0) + return TRUE; +#else +#error Bad value for HAVE_MKDIR +#endif + + return errno == EEXIST; +} + +static char * +_cairo_test_fixup_name (const char *original) +{ + char *name, *s; + + s = name = xstrdup (original); + while ((s = strchr (s, '_')) != NULL) + *s++ = '-'; + + return name; +} + +char * +cairo_test_get_name (const cairo_test_t *test) +{ + return _cairo_test_fixup_name (test->name); +} + +static void +_cairo_test_init (cairo_test_context_t *ctx, + const cairo_test_context_t *parent, + const cairo_test_t *test, + const char *test_name, + const char *output) +{ + char *log_name; + + MF (MEMFAULT_DISABLE_FAULTS ()); + +#if HAVE_FEENABLEEXCEPT + feenableexcept (FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW); +#endif + + ctx->test = test; + ctx->test_name = _cairo_test_fixup_name (test_name); + ctx->output = output; + + cairo_test_mkdir (ctx->output); + + ctx->malloc_failure = 0; +#if HAVE_MEMFAULT + if (getenv ("CAIRO_TEST_MALLOC_FAILURE")) + ctx->malloc_failure = atoi (getenv ("CAIRO_TEST_MALLOC_FAILURE")); + if (ctx->malloc_failure && ! RUNNING_ON_MEMFAULT ()) + ctx->malloc_failure = 0; +#endif + + ctx->timeout = cairo_test_timeout; + if (getenv ("CAIRO_TEST_TIMEOUT")) + ctx->timeout = atoi (getenv ("CAIRO_TEST_TIMEOUT")); + + xasprintf (&log_name, "%s/%s%s", ctx->output, ctx->test_name, CAIRO_TEST_LOG_SUFFIX); + _xunlink (NULL, log_name); + + ctx->log_file = fopen (log_name, "a"); + if (ctx->log_file == NULL) { + fprintf (stderr, "Error opening log file: %s\n", log_name); + ctx->log_file = stderr; + } + free (log_name); + + ctx->ref_name = NULL; + ctx->ref_image = NULL; + ctx->ref_image_flattened = NULL; + + if (parent != NULL) { + ctx->targets_to_test = parent->targets_to_test; + ctx->num_targets = parent->num_targets; + ctx->limited_targets = parent->limited_targets; + ctx->own_targets = FALSE; + + ctx->srcdir = parent->srcdir; + ctx->refdir = xstrdup (parent->refdir); + } else { + int tmp_num_targets; + cairo_bool_t tmp_limited_targets; + + ctx->targets_to_test = cairo_boilerplate_get_targets (&tmp_num_targets, &tmp_limited_targets); + ctx->num_targets = tmp_num_targets; + ctx->limited_targets = tmp_limited_targets; + ctx->own_targets = TRUE; + + ctx->srcdir = getenv ("srcdir"); + if (ctx->srcdir == NULL) { + ctx->srcdir = "."; +#if HAVE_SYS_STAT_H + struct stat st; + if (stat ("srcdir", &st) == 0 && (st.st_mode & S_IFDIR)) + ctx->srcdir = "srcdir"; +#endif + } + + ctx->refdir = xstrdup (getenv ("CAIRO_REF_DIR")); + if (ctx->refdir == NULL) + xasprintf (&ctx->refdir, "%s/reference", ctx->srcdir); + } + +#ifdef HAVE_UNISTD_H + if (*fail_face == '\0' && isatty (2)) { + fail_face = "\033[41;37;1m"; + xfail_face = "\033[43;37;1m"; + normal_face = "\033[m"; + if (isatty (1)) + print_fail_on_stdout = FALSE; + } +#endif + + printf ("\nTESTING %s\n", ctx->test_name); +} + +void +_cairo_test_context_init_for_test (cairo_test_context_t *ctx, + const cairo_test_context_t *parent, + const cairo_test_t *test) +{ + _cairo_test_init (ctx, parent, test, test->name, CAIRO_TEST_OUTPUT_DIR); +} + +void +cairo_test_init (cairo_test_context_t *ctx, + const char *test_name, + const char *output) +{ + _cairo_test_init (ctx, NULL, NULL, test_name, output); +} + +void +cairo_test_fini (cairo_test_context_t *ctx) +{ + if (ctx->log_file == NULL) + return; + + if (ctx->log_file != stderr) + fclose (ctx->log_file); + ctx->log_file = NULL; + + free (ctx->refdir); + free (ctx->ref_name); + cairo_surface_destroy (ctx->ref_image); + cairo_surface_destroy (ctx->ref_image_flattened); + + if (ctx->test_name != NULL) + free ((char *) ctx->test_name); + + if (ctx->own_targets) + cairo_boilerplate_free_targets (ctx->targets_to_test); + + cairo_boilerplate_fini (); + + cairo_debug_reset_static_data (); +#if HAVE_FCFINI + FcFini (); +#endif +} + +void +cairo_test_logv (const cairo_test_context_t *ctx, + const char *fmt, va_list va) +{ + FILE *file = ctx && ctx->log_file ? ctx->log_file : stderr; + vfprintf (file, fmt, va); +} + +void +cairo_test_log (const cairo_test_context_t *ctx, const char *fmt, ...) +{ + va_list va; + + va_start (va, fmt); + cairo_test_logv (ctx, fmt, va); + va_end (va); +} + +static void +_xunlink (const cairo_test_context_t *ctx, const char *pathname) +{ + if (unlink (pathname) < 0 && errno != ENOENT) { + cairo_test_log (ctx, "Error: Cannot remove %s: %s\n", + pathname, strerror (errno)); + exit (1); + } +} + +char * +cairo_test_reference_filename (const cairo_test_context_t *ctx, + const char *base_name, + const char *test_name, + const char *target_name, + const char *base_target_name, + const char *format, + const char *suffix, + const char *extension) +{ + char *ref_name = NULL; + + /* First look for a previous build for comparison. */ + if (ctx->refdir != NULL && strcmp(suffix, CAIRO_TEST_REF_SUFFIX) == 0) { + xasprintf (&ref_name, "%s/%s" CAIRO_TEST_OUT_SUFFIX "%s", + ctx->refdir, + base_name, + extension); + if (access (ref_name, F_OK) != 0) + free (ref_name); + else + goto done; + } + + if (target_name != NULL) { + /* Next look for a target/format-specific reference image. */ + xasprintf (&ref_name, "%s/reference/%s.%s.%s%s%s", + ctx->srcdir, + test_name, + target_name, + format, + suffix, + extension); + if (access (ref_name, F_OK) != 0) + free (ref_name); + else + goto done; + + /* Next, look for target-specific reference image. */ + xasprintf (&ref_name, "%s/reference/%s.%s%s%s", + ctx->srcdir, + test_name, + target_name, + suffix, + extension); + if (access (ref_name, F_OK) != 0) + free (ref_name); + else + goto done; + } + + if (base_target_name != NULL) { + /* Next look for a base/format-specific reference image. */ + xasprintf (&ref_name, "%s/reference/%s.%s.%s%s%s", + ctx->srcdir, + test_name, + base_target_name, + format, + suffix, + extension); + if (access (ref_name, F_OK) != 0) + free (ref_name); + else + goto done; + + /* Next, look for base-specific reference image. */ + xasprintf (&ref_name, "%s/reference/%s.%s%s%s", + ctx->srcdir, + test_name, + base_target_name, + suffix, + extension); + if (access (ref_name, F_OK) != 0) + free (ref_name); + else + goto done; + } + + /* Next, look for format-specific reference image. */ + xasprintf (&ref_name, "%s/reference/%s.%s%s%s", + ctx->srcdir, + test_name, + format, + suffix, + extension); + if (access (ref_name, F_OK) != 0) + free (ref_name); + else + goto done; + + /* Finally, look for the standard reference image. */ + xasprintf (&ref_name, "%s/reference/%s%s%s", ctx->srcdir, + test_name, + suffix, + extension); + if (access (ref_name, F_OK) != 0) + free (ref_name); + else + goto done; + + ref_name = NULL; + +done: + return ref_name; +} + +cairo_test_similar_t +cairo_test_target_has_similar (const cairo_test_context_t *ctx, + const cairo_boilerplate_target_t *target) +{ + cairo_surface_t *surface; + cairo_test_similar_t has_similar; + cairo_t * cr; + cairo_surface_t *similar; + cairo_status_t status; + void *closure; + char *path; + + /* ignore image intermediate targets */ + if (target->expected_type == CAIRO_SURFACE_TYPE_IMAGE) + return DIRECT; + + if (getenv ("CAIRO_TEST_IGNORE_SIMILAR")) + return DIRECT; + + xasprintf (&path, "%s/%s", + cairo_test_mkdir (ctx->output) ? ctx->output : ".", + ctx->test_name); + + has_similar = DIRECT; + do { + do { + surface = (target->create_surface) (path, + target->content, + ctx->test->width, + ctx->test->height, + ctx->test->width* NUM_DEVICE_SCALE + 25 * NUM_DEVICE_OFFSETS, + ctx->test->height* NUM_DEVICE_SCALE + 25 * NUM_DEVICE_OFFSETS, + CAIRO_BOILERPLATE_MODE_TEST, + &closure); + if (surface == NULL) + goto out; + } while (cairo_test_malloc_failure (ctx, cairo_surface_status (surface))); + + if (cairo_surface_status (surface)) + goto out; + + cr = cairo_create (surface); + cairo_push_group_with_content (cr, + cairo_boilerplate_content (target->content)); + similar = cairo_get_group_target (cr); + status = cairo_surface_status (similar); + + if (cairo_surface_get_type (similar) == cairo_surface_get_type (surface)) + has_similar = SIMILAR; + else + has_similar = DIRECT; + + cairo_destroy (cr); + cairo_surface_destroy (surface); + + if (target->cleanup) + target->cleanup (closure); + } while (! has_similar && cairo_test_malloc_failure (ctx, status)); +out: + free (path); + + return has_similar; +} + +static cairo_surface_t * +_cairo_test_flatten_reference_image (cairo_test_context_t *ctx, + cairo_bool_t flatten) +{ + cairo_surface_t *surface; + cairo_t *cr; + + if (! flatten) + return ctx->ref_image; + + if (ctx->ref_image_flattened != NULL) + return ctx->ref_image_flattened; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + cairo_image_surface_get_width (ctx->ref_image), + cairo_image_surface_get_height (ctx->ref_image)); + cr = cairo_create (surface); + cairo_surface_destroy (surface); + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_set_source_surface (cr, ctx->ref_image, 0, 0); + cairo_paint (cr); + + surface = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + + if (cairo_surface_status (surface) == CAIRO_STATUS_SUCCESS) + ctx->ref_image_flattened = surface; + return surface; +} + +cairo_surface_t * +cairo_test_get_reference_image (cairo_test_context_t *ctx, + const char *filename, + cairo_bool_t flatten) +{ + cairo_surface_t *surface; + + if (ctx->ref_name != NULL) { + if (strcmp (ctx->ref_name, filename) == 0) + return _cairo_test_flatten_reference_image (ctx, flatten); + + cairo_surface_destroy (ctx->ref_image); + ctx->ref_image = NULL; + + cairo_surface_destroy (ctx->ref_image_flattened); + ctx->ref_image_flattened = NULL; + + free (ctx->ref_name); + ctx->ref_name = NULL; + } + + surface = cairo_image_surface_create_from_png (filename); + if (cairo_surface_status (surface)) + return surface; + + ctx->ref_name = xstrdup (filename); + ctx->ref_image = surface; + return _cairo_test_flatten_reference_image (ctx, flatten); +} + +static cairo_bool_t +cairo_test_file_is_older (const char *filename, + char **ref_filenames, + int num_ref_filenames) +{ +#if HAVE_SYS_STAT_H + struct stat st; + + if (stat (filename, &st) < 0) + return FALSE; + + while (num_ref_filenames--) { + struct stat ref; + char *ref_filename = *ref_filenames++; + + if (ref_filename == NULL) + continue; + + if (stat (ref_filename++, &ref) < 0) + continue; + + if (st.st_mtime <= ref.st_mtime) + return TRUE; + } +#endif + + return FALSE; +} + +static cairo_bool_t +cairo_test_files_equal (const char *test_filename, + const char *pass_filename) +{ + FILE *test, *pass; + int t, p; + + if (test_filename == NULL || pass_filename == NULL) + return FALSE; + + test = fopen (test_filename, "rb"); + if (test == NULL) + return FALSE; + + pass = fopen (pass_filename, "rb"); + if (pass == NULL) { + fclose (test); + return FALSE; + } + + /* as simple as it gets */ + do { + t = getc (test); + p = getc (pass); + if (t != p) + break; + } while (t != EOF && p != EOF); + + fclose (pass); + fclose (test); + + return t == p; /* both EOF */ +} + +static cairo_bool_t +cairo_test_copy_file (const char *src_filename, + const char *dst_filename) +{ + FILE *src, *dst; + int c; + +#if HAVE_LINK + if (link (src_filename, dst_filename) == 0) + return TRUE; + + unlink (dst_filename); +#endif + + src = fopen (src_filename, "rb"); + if (src == NULL) + return FALSE; + + dst = fopen (dst_filename, "wb"); + if (dst == NULL) { + fclose (src); + return FALSE; + } + + /* as simple as it gets */ + while ((c = getc (src)) != EOF) + putc (c, dst); + + fclose (src); + fclose (dst); + + return TRUE; +} + +static cairo_test_status_t +cairo_test_for_target (cairo_test_context_t *ctx, + const cairo_boilerplate_target_t *target, + int dev_offset, + int dev_scale, + cairo_bool_t similar) +{ + cairo_status_t finish_status; + cairo_surface_t *surface = NULL; + cairo_t *cr; + const char *empty_str = ""; + char *offset_str; + char *scale_str; + char *base_name, *base_path; + char *out_png_path; + char *ref_path = NULL, *ref_png_path, *cmp_png_path = NULL; + char *new_path = NULL, *new_png_path; + char *xfail_path = NULL, *xfail_png_path; + char *base_ref_png_path; + char *base_new_png_path; + char *base_xfail_png_path; + char *diff_png_path; + char *test_filename = NULL, *pass_filename = NULL, *fail_filename = NULL; + cairo_test_status_t ret, test_status; + cairo_content_t expected_content; + cairo_font_options_t *font_options; + const char *format; + cairo_bool_t have_output = FALSE; + cairo_bool_t have_result = FALSE; + void *closure; + double width, height; + cairo_bool_t have_output_dir; +#if HAVE_MEMFAULT + int malloc_failure_iterations = ctx->malloc_failure; + int last_fault_count = 0; +#endif + + /* Get the strings ready that we'll need. */ + format = cairo_boilerplate_content_name (target->content); + if (dev_offset) + xasprintf (&offset_str, ".%d", dev_offset); + else + offset_str = (char *) empty_str; + + if (dev_scale != 1) + xasprintf (&scale_str, ".x%d", dev_scale); + else + scale_str = (char *) empty_str; + + xasprintf (&base_name, "%s.%s.%s%s%s%s", + ctx->test_name, + target->name, + format, + similar ? ".similar" : "", + offset_str, + scale_str); + + if (offset_str != empty_str) + free (offset_str); + if (scale_str != empty_str) + free (scale_str); + + ref_png_path = cairo_test_reference_filename (ctx, + base_name, + ctx->test_name, + target->name, + target->basename, + format, + CAIRO_TEST_REF_SUFFIX, + CAIRO_TEST_PNG_EXTENSION); + new_png_path = cairo_test_reference_filename (ctx, + base_name, + ctx->test_name, + target->name, + target->basename, + format, + CAIRO_TEST_NEW_SUFFIX, + CAIRO_TEST_PNG_EXTENSION); + xfail_png_path = cairo_test_reference_filename (ctx, + base_name, + ctx->test_name, + target->name, + target->basename, + format, + CAIRO_TEST_XFAIL_SUFFIX, + CAIRO_TEST_PNG_EXTENSION); + + base_ref_png_path = cairo_test_reference_filename (ctx, + base_name, + ctx->test_name, + NULL, NULL, + format, + CAIRO_TEST_REF_SUFFIX, + CAIRO_TEST_PNG_EXTENSION); + base_new_png_path = cairo_test_reference_filename (ctx, + base_name, + ctx->test_name, + NULL, NULL, + format, + CAIRO_TEST_NEW_SUFFIX, + CAIRO_TEST_PNG_EXTENSION); + base_xfail_png_path = cairo_test_reference_filename (ctx, + base_name, + ctx->test_name, + NULL, NULL, + format, + CAIRO_TEST_XFAIL_SUFFIX, + CAIRO_TEST_PNG_EXTENSION); + + if (target->file_extension != NULL) { + ref_path = cairo_test_reference_filename (ctx, + base_name, + ctx->test_name, + target->name, + target->basename, + format, + CAIRO_TEST_REF_SUFFIX, + target->file_extension); + new_path = cairo_test_reference_filename (ctx, + base_name, + ctx->test_name, + target->name, + target->basename, + format, + CAIRO_TEST_NEW_SUFFIX, + target->file_extension); + xfail_path = cairo_test_reference_filename (ctx, + base_name, + ctx->test_name, + target->name, + target->basename, + format, + CAIRO_TEST_XFAIL_SUFFIX, + target->file_extension); + } + + have_output_dir = cairo_test_mkdir (ctx->output); + xasprintf (&base_path, "%s/%s", + have_output_dir ? ctx->output : ".", + base_name); + xasprintf (&out_png_path, "%s" CAIRO_TEST_OUT_PNG, base_path); + xasprintf (&diff_png_path, "%s" CAIRO_TEST_DIFF_PNG, base_path); + + if (ctx->test->requirements != NULL) { + const char *required; + + required = target->is_vector ? "target=raster" : "target=vector"; + if (strstr (ctx->test->requirements, required) != NULL) { + cairo_test_log (ctx, "Error: Skipping for %s target %s\n", + target->is_vector ? "vector" : "raster", + target->name); + ret = CAIRO_TEST_UNTESTED; + goto UNWIND_STRINGS; + } + + required = target->is_recording ? "target=!recording" : "target=recording"; + if (strstr (ctx->test->requirements, required) != NULL) { + cairo_test_log (ctx, "Error: Skipping for %s target %s\n", + target->is_recording ? "recording" : "non-recording", + target->name); + ret = CAIRO_TEST_UNTESTED; + goto UNWIND_STRINGS; + } + } + + width = ctx->test->width; + height = ctx->test->height; + if (width && height) { + width *= dev_scale; + height *= dev_scale; + width += dev_offset; + height += dev_offset; + } + +#if HAVE_MEMFAULT +REPEAT: + MEMFAULT_CLEAR_FAULTS (); + MEMFAULT_RESET_LEAKS (); + ctx->last_fault_count = 0; + last_fault_count = MEMFAULT_COUNT_FAULTS (); + + /* Pre-initialise fontconfig so that the configuration is loaded without + * malloc failures (our primary goal is to test cairo fault tolerance). + */ +#if HAVE_FCINIT + FcInit (); +#endif + + MEMFAULT_ENABLE_FAULTS (); +#endif + have_output = FALSE; + have_result = FALSE; + + /* Run the actual drawing code. */ + ret = CAIRO_TEST_SUCCESS; + surface = (target->create_surface) (base_path, + target->content, + width, height, + ctx->test->width * NUM_DEVICE_SCALE + 25 * NUM_DEVICE_OFFSETS, + ctx->test->height * NUM_DEVICE_SCALE + 25 * NUM_DEVICE_OFFSETS, + CAIRO_BOILERPLATE_MODE_TEST, + &closure); + if (surface == NULL) { + cairo_test_log (ctx, "Error: Failed to set %s target\n", target->name); + ret = CAIRO_TEST_UNTESTED; + goto UNWIND_STRINGS; + } + +#if HAVE_MEMFAULT + if (ctx->malloc_failure && + MEMFAULT_COUNT_FAULTS () - last_fault_count > 0 && + cairo_surface_status (surface) == CAIRO_STATUS_NO_MEMORY) + { + goto REPEAT; + } +#endif + + if (cairo_surface_status (surface)) { + MF (MEMFAULT_PRINT_FAULTS ()); + cairo_test_log (ctx, "Error: Created an error surface: %s\n", + cairo_status_to_string (cairo_surface_status (surface))); + ret = CAIRO_TEST_FAILURE; + goto UNWIND_STRINGS; + } + + /* Check that we created a surface of the expected type. */ + if (cairo_surface_get_type (surface) != target->expected_type) { + MF (MEMFAULT_PRINT_FAULTS ()); + cairo_test_log (ctx, "Error: Created surface is of type %d (expected %d)\n", + cairo_surface_get_type (surface), target->expected_type); + ret = CAIRO_TEST_UNTESTED; + goto UNWIND_SURFACE; + } + + /* Check that we created a surface of the expected content, + * (ignore the artificial CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED value). + */ + expected_content = cairo_boilerplate_content (target->content); + + if (cairo_surface_get_content (surface) != expected_content) { + MF (MEMFAULT_PRINT_FAULTS ()); + cairo_test_log (ctx, "Error: Created surface has content %d (expected %d)\n", + cairo_surface_get_content (surface), expected_content); + ret = CAIRO_TEST_FAILURE; + goto UNWIND_SURFACE; + } + + if (cairo_surface_set_user_data (surface, + &cairo_boilerplate_output_basename_key, + base_path, + NULL)) + { +#if HAVE_MEMFAULT + cairo_surface_destroy (surface); + + if (target->cleanup) + target->cleanup (closure); + + goto REPEAT; +#else + ret = CAIRO_TEST_FAILURE; + goto UNWIND_SURFACE; +#endif + } + + cairo_surface_set_device_offset (surface, dev_offset, dev_offset); + cairo_surface_set_device_scale (surface, dev_scale, dev_scale); + + cr = cairo_create (surface); + if (cairo_set_user_data (cr, &_cairo_test_context_key, (void*) ctx, NULL)) { +#if HAVE_MEMFAULT + cairo_destroy (cr); + cairo_surface_destroy (surface); + + if (target->cleanup) + target->cleanup (closure); + + goto REPEAT; +#else + ret = CAIRO_TEST_FAILURE; + goto UNWIND_CAIRO; +#endif + } + + if (similar) + cairo_push_group_with_content (cr, expected_content); + + /* Clear to transparent (or black) depending on whether the target + * surface supports alpha. */ + cairo_save (cr); + cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); + cairo_paint (cr); + cairo_restore (cr); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + + /* Set all components of font_options to avoid backend differences + * and reduce number of needed reference images. */ + font_options = cairo_font_options_create (); + cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE); + cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_ON); + cairo_font_options_set_antialias (font_options, CAIRO_ANTIALIAS_GRAY); + cairo_set_font_options (cr, font_options); + cairo_font_options_destroy (font_options); + + cairo_save (cr); + alarm (ctx->timeout); + test_status = (ctx->test->draw) (cr, ctx->test->width, ctx->test->height); + alarm (0); + cairo_restore (cr); + + if (similar) { + cairo_pop_group_to_source (cr); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_paint (cr); + } + +#if HAVE_MEMFAULT + MEMFAULT_DISABLE_FAULTS (); + + /* repeat test after malloc failure injection */ + if (ctx->malloc_failure && + MEMFAULT_COUNT_FAULTS () - last_fault_count > 0 && + (test_status == CAIRO_TEST_NO_MEMORY || + cairo_status (cr) == CAIRO_STATUS_NO_MEMORY || + cairo_surface_status (surface) == CAIRO_STATUS_NO_MEMORY)) + { + cairo_destroy (cr); + cairo_surface_destroy (surface); + if (target->cleanup) + target->cleanup (closure); + cairo_debug_reset_static_data (); +#if HAVE_FCFINI + FcFini (); +#endif + if (MEMFAULT_COUNT_LEAKS () > 0) { + MEMFAULT_PRINT_FAULTS (); + MEMFAULT_PRINT_LEAKS (); + } + + goto REPEAT; + } +#endif + + /* Then, check all the different ways it could fail. */ + if (test_status) { + cairo_test_log (ctx, "Error: Function under test failed\n"); + ret = test_status; + goto UNWIND_CAIRO; + } + +#if HAVE_MEMFAULT + if (MEMFAULT_COUNT_FAULTS () - last_fault_count > 0 && + MEMFAULT_HAS_FAULTS ()) + { + VALGRIND_PRINTF ("Unreported memfaults..."); + MEMFAULT_PRINT_FAULTS (); + } +#endif + + if (target->finish_surface != NULL) { +#if HAVE_MEMFAULT + /* We need to re-enable faults as most recording-surface processing + * is done during cairo_surface_finish(). + */ + MEMFAULT_CLEAR_FAULTS (); + last_fault_count = MEMFAULT_COUNT_FAULTS (); + MEMFAULT_ENABLE_FAULTS (); +#endif + + /* also check for infinite loops whilst replaying */ + alarm (ctx->timeout); + finish_status = target->finish_surface (surface); + alarm (0); + +#if HAVE_MEMFAULT + MEMFAULT_DISABLE_FAULTS (); + + if (ctx->malloc_failure && + MEMFAULT_COUNT_FAULTS () - last_fault_count > 0 && + finish_status == CAIRO_STATUS_NO_MEMORY) + { + cairo_destroy (cr); + cairo_surface_destroy (surface); + if (target->cleanup) + target->cleanup (closure); + cairo_debug_reset_static_data (); +#if HAVE_FCFINI + FcFini (); +#endif + if (MEMFAULT_COUNT_LEAKS () > 0) { + MEMFAULT_PRINT_FAULTS (); + MEMFAULT_PRINT_LEAKS (); + } + + goto REPEAT; + } +#endif + if (finish_status) { + cairo_test_log (ctx, "Error: Failed to finish surface: %s\n", + cairo_status_to_string (finish_status)); + ret = CAIRO_TEST_FAILURE; + goto UNWIND_CAIRO; + } + } + + /* Skip image check for tests with no image (width,height == 0,0) */ + if (ctx->test->width != 0 && ctx->test->height != 0) { + cairo_surface_t *ref_image; + cairo_surface_t *test_image; + cairo_surface_t *diff_image; + buffer_diff_result_t result; + cairo_status_t diff_status; + + if (ref_png_path == NULL) { + cairo_test_log (ctx, "Error: Cannot find reference image for %s\n", + base_name); + + /* we may be running this test to generate reference images */ + _xunlink (ctx, out_png_path); + /* be more generous as we may need to use external renderers */ + alarm (4 * ctx->timeout); + test_image = target->get_image_surface (surface, 0, + ctx->test->width, + ctx->test->height); + alarm (0); + diff_status = cairo_surface_write_to_png (test_image, out_png_path); + cairo_surface_destroy (test_image); + if (diff_status) { + if (cairo_surface_status (test_image) == CAIRO_STATUS_INVALID_STATUS) + ret = CAIRO_TEST_CRASHED; + else + ret = CAIRO_TEST_FAILURE; + cairo_test_log (ctx, + "Error: Failed to write output image: %s\n", + cairo_status_to_string (diff_status)); + } + have_output = TRUE; + + ret = CAIRO_TEST_XFAILURE; + goto UNWIND_CAIRO; + } + + if (target->file_extension != NULL) { /* compare vector surfaces */ + char *filenames[] = { + ref_png_path, + ref_path, + new_png_path, + new_path, + xfail_png_path, + xfail_path, + base_ref_png_path, + base_new_png_path, + base_xfail_png_path, + }; + + xasprintf (&test_filename, "%s.out%s", + base_path, target->file_extension); + xasprintf (&pass_filename, "%s.pass%s", + base_path, target->file_extension); + xasprintf (&fail_filename, "%s.fail%s", + base_path, target->file_extension); + + if (cairo_test_file_is_older (pass_filename, + filenames, + ARRAY_LENGTH (filenames))) + { + _xunlink (ctx, pass_filename); + } + if (cairo_test_file_is_older (fail_filename, + filenames, + ARRAY_LENGTH (filenames))) + { + _xunlink (ctx, fail_filename); + } + + if (cairo_test_files_equal (out_png_path, ref_path)) { + cairo_test_log (ctx, "Vector surface matches reference.\n"); + have_output = FALSE; + ret = CAIRO_TEST_SUCCESS; + goto UNWIND_CAIRO; + } + if (cairo_test_files_equal (out_png_path, new_path)) { + cairo_test_log (ctx, "Vector surface matches current failure.\n"); + have_output = FALSE; + ret = CAIRO_TEST_NEW; + goto UNWIND_CAIRO; + } + if (cairo_test_files_equal (out_png_path, xfail_path)) { + cairo_test_log (ctx, "Vector surface matches known failure.\n"); + have_output = FALSE; + ret = CAIRO_TEST_XFAILURE; + goto UNWIND_CAIRO; + } + + if (cairo_test_files_equal (test_filename, pass_filename)) { + /* identical output as last known PASS */ + cairo_test_log (ctx, "Vector surface matches last pass.\n"); + have_output = TRUE; + ret = CAIRO_TEST_SUCCESS; + goto UNWIND_CAIRO; + } + if (cairo_test_files_equal (test_filename, fail_filename)) { + /* identical output as last known FAIL, fail */ + cairo_test_log (ctx, "Vector surface matches last fail.\n"); + have_result = TRUE; /* presume these were kept around as well */ + have_output = TRUE; + ret = CAIRO_TEST_FAILURE; + goto UNWIND_CAIRO; + } + } + + /* be more generous as we may need to use external renderers */ + alarm (4 * ctx->timeout); + test_image = target->get_image_surface (surface, 0, + ctx->test->width, + ctx->test->height); + alarm (0); + if (cairo_surface_status (test_image)) { + cairo_test_log (ctx, "Error: Failed to extract image: %s\n", + cairo_status_to_string (cairo_surface_status (test_image))); + if (cairo_surface_status (test_image) == CAIRO_STATUS_INVALID_STATUS) + ret = CAIRO_TEST_CRASHED; + else + ret = CAIRO_TEST_FAILURE; + cairo_surface_destroy (test_image); + goto UNWIND_CAIRO; + } + + _xunlink (ctx, out_png_path); + diff_status = cairo_surface_write_to_png (test_image, out_png_path); + if (diff_status) { + cairo_test_log (ctx, "Error: Failed to write output image: %s\n", + cairo_status_to_string (diff_status)); + cairo_surface_destroy (test_image); + ret = CAIRO_TEST_FAILURE; + goto UNWIND_CAIRO; + } + have_output = TRUE; + + /* binary compare png files (no decompression) */ + if (target->file_extension == NULL) { + char *filenames[] = { + ref_png_path, + new_png_path, + xfail_png_path, + base_ref_png_path, + base_new_png_path, + base_xfail_png_path, + }; + + xasprintf (&test_filename, "%s", out_png_path); + xasprintf (&pass_filename, "%s.pass.png", base_path); + xasprintf (&fail_filename, "%s.fail.png", base_path); + + if (cairo_test_file_is_older (pass_filename, + filenames, + ARRAY_LENGTH (filenames))) + { + _xunlink (ctx, pass_filename); + } + if (cairo_test_file_is_older (fail_filename, + filenames, + ARRAY_LENGTH (filenames))) + { + _xunlink (ctx, fail_filename); + } + + if (cairo_test_files_equal (test_filename, pass_filename)) { + cairo_test_log (ctx, "PNG file exactly matches last pass.\n"); + have_result = TRUE; + cairo_surface_destroy (test_image); + ret = CAIRO_TEST_SUCCESS; + goto UNWIND_CAIRO; + } + if (cairo_test_files_equal (out_png_path, ref_png_path)) { + cairo_test_log (ctx, "PNG file exactly matches reference image.\n"); + have_result = TRUE; + cairo_surface_destroy (test_image); + ret = CAIRO_TEST_SUCCESS; + goto UNWIND_CAIRO; + } + if (cairo_test_files_equal (out_png_path, new_png_path)) { + cairo_test_log (ctx, "PNG file exactly matches current failure image.\n"); + have_result = TRUE; + cairo_surface_destroy (test_image); + ret = CAIRO_TEST_NEW; + goto UNWIND_CAIRO; + } + if (cairo_test_files_equal (out_png_path, xfail_png_path)) { + cairo_test_log (ctx, "PNG file exactly matches known failure image.\n"); + have_result = TRUE; + cairo_surface_destroy (test_image); + ret = CAIRO_TEST_XFAILURE; + goto UNWIND_CAIRO; + } + if (cairo_test_files_equal (test_filename, fail_filename)) { + cairo_test_log (ctx, "PNG file exactly matches last fail.\n"); + have_result = TRUE; /* presume these were kept around as well */ + cairo_surface_destroy (test_image); + ret = CAIRO_TEST_FAILURE; + goto UNWIND_CAIRO; + } + } else { + if (cairo_test_files_equal (out_png_path, ref_png_path)) { + cairo_test_log (ctx, "PNG file exactly matches reference image.\n"); + have_result = TRUE; + cairo_surface_destroy (test_image); + ret = CAIRO_TEST_SUCCESS; + goto UNWIND_CAIRO; + } + if (cairo_test_files_equal (out_png_path, new_png_path)) { + cairo_test_log (ctx, "PNG file exactly matches current failure image.\n"); + have_result = TRUE; + cairo_surface_destroy (test_image); + ret = CAIRO_TEST_NEW; + goto UNWIND_CAIRO; + } + if (cairo_test_files_equal (out_png_path, xfail_png_path)) { + cairo_test_log (ctx, "PNG file exactly matches known failure image.\n"); + have_result = TRUE; + cairo_surface_destroy (test_image); + ret = CAIRO_TEST_XFAILURE; + goto UNWIND_CAIRO; + } + } + + if (cairo_test_files_equal (out_png_path, base_ref_png_path)) { + cairo_test_log (ctx, "PNG file exactly reference image.\n"); + have_result = TRUE; + cairo_surface_destroy (test_image); + ret = CAIRO_TEST_SUCCESS; + goto UNWIND_CAIRO; + } + if (cairo_test_files_equal (out_png_path, base_new_png_path)) { + cairo_test_log (ctx, "PNG file exactly current failure image.\n"); + have_result = TRUE; + cairo_surface_destroy (test_image); + ret = CAIRO_TEST_NEW; + goto UNWIND_CAIRO; + } + if (cairo_test_files_equal (out_png_path, base_xfail_png_path)) { + cairo_test_log (ctx, "PNG file exactly known failure image.\n"); + have_result = TRUE; + cairo_surface_destroy (test_image); + ret = CAIRO_TEST_XFAILURE; + goto UNWIND_CAIRO; + } + + /* first compare against the ideal reference */ + ref_image = cairo_test_get_reference_image (ctx, base_ref_png_path, + target->content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED); + if (cairo_surface_status (ref_image)) { + cairo_test_log (ctx, "Error: Cannot open reference image for %s: %s\n", + base_ref_png_path, + cairo_status_to_string (cairo_surface_status (ref_image))); + cairo_surface_destroy (test_image); + ret = CAIRO_TEST_FAILURE; + goto UNWIND_CAIRO; + } + + diff_image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + ctx->test->width, + ctx->test->height); + + cmp_png_path = base_ref_png_path; + diff_status = image_diff (ctx, + test_image, ref_image, diff_image, + &result); + _xunlink (ctx, diff_png_path); + if (diff_status || + image_diff_is_failure (&result, target->error_tolerance)) + { + /* that failed, so check against the specific backend */ + ref_image = cairo_test_get_reference_image (ctx, ref_png_path, + target->content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED); + if (cairo_surface_status (ref_image)) { + cairo_test_log (ctx, "Error: Cannot open reference image for %s: %s\n", + ref_png_path, + cairo_status_to_string (cairo_surface_status (ref_image))); + cairo_surface_destroy (test_image); + ret = CAIRO_TEST_FAILURE; + goto UNWIND_CAIRO; + } + + cmp_png_path = ref_png_path; + diff_status = image_diff (ctx, + test_image, ref_image, + diff_image, + &result); + if (diff_status) + { + cairo_test_log (ctx, "Error: Failed to compare images: %s\n", + cairo_status_to_string (diff_status)); + ret = CAIRO_TEST_FAILURE; + } + else if (image_diff_is_failure (&result, target->error_tolerance)) + { + ret = CAIRO_TEST_FAILURE; + + diff_status = cairo_surface_write_to_png (diff_image, + diff_png_path); + if (diff_status) { + cairo_test_log (ctx, "Error: Failed to write differences image: %s\n", + cairo_status_to_string (diff_status)); + } else { + have_result = TRUE; + } + + cairo_test_copy_file (test_filename, fail_filename); + } + else + { /* success */ + cairo_test_copy_file (test_filename, pass_filename); + } + } + else + { /* success */ + cairo_test_copy_file (test_filename, pass_filename); + } + + /* If failed, compare against the current image output, + * and attempt to detect systematic failures. + */ + if (ret == CAIRO_TEST_FAILURE) { + char *image_out_path; + + image_out_path = + cairo_test_reference_filename (ctx, + base_name, + ctx->test_name, + "image", + "image", + format, + CAIRO_TEST_OUT_SUFFIX, + CAIRO_TEST_PNG_EXTENSION); + if (image_out_path != NULL) { + if (cairo_test_files_equal (out_png_path, + image_out_path)) + { + ret = CAIRO_TEST_XFAILURE; + } + else + { + ref_image = + cairo_image_surface_create_from_png (image_out_path); + if (cairo_surface_status (ref_image) == CAIRO_STATUS_SUCCESS) + { + diff_status = image_diff (ctx, + test_image, ref_image, + diff_image, + &result); + if (diff_status == CAIRO_STATUS_SUCCESS && + !image_diff_is_failure (&result, target->error_tolerance)) + { + ret = CAIRO_TEST_XFAILURE; + } + + cairo_surface_destroy (ref_image); + } + } + + free (image_out_path); + } + } + + cairo_surface_destroy (test_image); + cairo_surface_destroy (diff_image); + } + + if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) { + cairo_test_log (ctx, "Error: Function under test left cairo status in an error state: %s\n", + cairo_status_to_string (cairo_status (cr))); + ret = CAIRO_TEST_ERROR; + goto UNWIND_CAIRO; + } + +UNWIND_CAIRO: + free (test_filename); + free (fail_filename); + free (pass_filename); + + test_filename = fail_filename = pass_filename = NULL; + +#if HAVE_MEMFAULT + if (ret == CAIRO_TEST_FAILURE) + MEMFAULT_PRINT_FAULTS (); +#endif + cairo_destroy (cr); +UNWIND_SURFACE: + cairo_surface_destroy (surface); + + if (target->cleanup) + target->cleanup (closure); + +#if HAVE_MEMFAULT + cairo_debug_reset_static_data (); + +#if HAVE_FCFINI + FcFini (); +#endif + + if (MEMFAULT_COUNT_LEAKS () > 0) { + if (ret != CAIRO_TEST_FAILURE) + MEMFAULT_PRINT_FAULTS (); + MEMFAULT_PRINT_LEAKS (); + } + + if (ret == CAIRO_TEST_SUCCESS && --malloc_failure_iterations > 0) + goto REPEAT; +#endif + + if (have_output) + cairo_test_log (ctx, "OUTPUT: %s\n", out_png_path); + + if (have_result) { + if (cmp_png_path == NULL) { + /* XXX presume we matched the normal ref last time */ + cmp_png_path = ref_png_path; + } + cairo_test_log (ctx, + "REFERENCE: %s\nDIFFERENCE: %s\n", + cmp_png_path, diff_png_path); + } + +UNWIND_STRINGS: + free (out_png_path); + free (ref_png_path); + free (base_ref_png_path); + free (ref_path); + free (new_png_path); + free (base_new_png_path); + free (new_path); + free (xfail_png_path); + free (base_xfail_png_path); + free (xfail_path); + free (diff_png_path); + free (base_path); + free (base_name); + + return ret; +} + +#if defined(HAVE_SIGNAL_H) && defined(HAVE_SETJMP_H) +#include +#include +/* Used to catch crashes in a test, so that we report it as such and + * continue testing, although one crash may already have corrupted memory in + * an nonrecoverable fashion. */ +static jmp_buf jmpbuf; + +static void +segfault_handler (int signal) +{ + longjmp (jmpbuf, signal); +} +#endif + +cairo_test_status_t +_cairo_test_context_run_for_target (cairo_test_context_t *ctx, + const cairo_boilerplate_target_t *target, + cairo_bool_t similar, + int dev_offset, int dev_scale) +{ + cairo_test_status_t status; + + if (target->get_image_surface == NULL) + return CAIRO_TEST_UNTESTED; + + if (similar && ! cairo_test_target_has_similar (ctx, target)) + return CAIRO_TEST_UNTESTED; + + cairo_test_log (ctx, + "Testing %s with %s%s target (dev offset %d scale: %d)\n", + ctx->test_name, + similar ? " (similar) " : "", + target->name, + dev_offset, dev_scale); + + printf ("%s.%s.%s [%dx%d]%s:\t", ctx->test_name, target->name, + cairo_boilerplate_content_name (target->content), + dev_offset, dev_scale, + similar ? " (similar)": ""); + fflush (stdout); + +#if defined(HAVE_SIGNAL_H) && defined(HAVE_SETJMP_H) + if (! RUNNING_ON_VALGRIND) { + void (* volatile old_segfault_handler)(int); + void (* volatile old_segfpe_handler)(int); +#ifdef SIGPIPE + void (* volatile old_sigpipe_handler)(int); +#endif + void (* volatile old_sigabrt_handler)(int); +#ifdef SIGALRM + void (* volatile old_sigalrm_handler)(int); +#endif + + /* Set up a checkpoint to get back to in case of segfaults. */ +#ifdef SIGSEGV + old_segfault_handler = signal (SIGSEGV, segfault_handler); +#endif +#ifdef SIGFPE + old_segfpe_handler = signal (SIGFPE, segfault_handler); +#endif +#ifdef SIGPIPE + old_sigpipe_handler = signal (SIGPIPE, segfault_handler); +#endif +#ifdef SIGABRT + old_sigabrt_handler = signal (SIGABRT, segfault_handler); +#endif +#ifdef SIGALRM + old_sigalrm_handler = signal (SIGALRM, segfault_handler); +#endif + if (0 == setjmp (jmpbuf)) + status = cairo_test_for_target (ctx, target, dev_offset, dev_scale, similar); + else + status = CAIRO_TEST_CRASHED; +#ifdef SIGSEGV + signal (SIGSEGV, old_segfault_handler); +#endif +#ifdef SIGFPE + signal (SIGFPE, old_segfpe_handler); +#endif +#ifdef SIGPIPE + signal (SIGPIPE, old_sigpipe_handler); +#endif +#ifdef SIGABRT + signal (SIGABRT, old_sigabrt_handler); +#endif +#ifdef SIGALRM + signal (SIGALRM, old_sigalrm_handler); +#endif + } else { + status = cairo_test_for_target (ctx, target, dev_offset, dev_scale, similar); + } +#else + status = cairo_test_for_target (ctx, target, dev_offset, dev_scale, similar); +#endif + + cairo_test_log (ctx, + "TEST: %s TARGET: %s FORMAT: %s OFFSET: %d SCALE: %d SIMILAR: %d RESULT: ", + ctx->test_name, target->name, + cairo_boilerplate_content_name (target->content), + dev_offset, dev_scale, similar); + switch (status) { + case CAIRO_TEST_SUCCESS: + printf ("PASS\n"); + cairo_test_log (ctx, "PASS\n"); + break; + + case CAIRO_TEST_UNTESTED: + printf ("UNTESTED\n"); + cairo_test_log (ctx, "UNTESTED\n"); + break; + + default: + case CAIRO_TEST_CRASHED: + if (print_fail_on_stdout) { + printf ("!!!CRASHED!!!\n"); + } else { + /* eat the test name */ + printf ("\r"); + fflush (stdout); + } + cairo_test_log (ctx, "CRASHED\n"); + fprintf (stderr, "%s.%s.%s [%dx%d]%s:\t%s!!!CRASHED!!!%s\n", + ctx->test_name, target->name, + cairo_boilerplate_content_name (target->content), dev_offset, dev_scale, similar ? " (similar)" : "", + fail_face, normal_face); + break; + + case CAIRO_TEST_ERROR: + if (print_fail_on_stdout) { + printf ("!!!ERROR!!!\n"); + } else { + /* eat the test name */ + printf ("\r"); + fflush (stdout); + } + cairo_test_log (ctx, "ERROR\n"); + fprintf (stderr, "%s.%s.%s [%dx%d]%s:\t%s!!!ERROR!!!%s\n", + ctx->test_name, target->name, + cairo_boilerplate_content_name (target->content), dev_offset, dev_scale, similar ? " (similar)" : "", + fail_face, normal_face); + break; + + case CAIRO_TEST_XFAILURE: + if (print_fail_on_stdout) { + printf ("XFAIL\n"); + } else { + /* eat the test name */ + printf ("\r"); + fflush (stdout); + } + fprintf (stderr, "%s.%s.%s [%dx%d]%s:\t%sXFAIL%s\n", + ctx->test_name, target->name, + cairo_boilerplate_content_name (target->content), dev_offset, dev_scale, similar ? " (similar)" : "", + xfail_face, normal_face); + cairo_test_log (ctx, "XFAIL\n"); + break; + + case CAIRO_TEST_NEW: + if (print_fail_on_stdout) { + printf ("NEW\n"); + } else { + /* eat the test name */ + printf ("\r"); + fflush (stdout); + } + fprintf (stderr, "%s.%s.%s [%dx%d]%s:\t%sNEW%s\n", + ctx->test_name, target->name, + cairo_boilerplate_content_name (target->content), dev_offset, dev_scale, similar ? " (similar)" : "", + fail_face, normal_face); + cairo_test_log (ctx, "NEW\n"); + break; + + case CAIRO_TEST_NO_MEMORY: + case CAIRO_TEST_FAILURE: + if (print_fail_on_stdout) { + printf ("FAIL\n"); + } else { + /* eat the test name */ + printf ("\r"); + fflush (stdout); + } + fprintf (stderr, "%s.%s.%s [%dx%d]%s:\t%sFAIL%s\n", + ctx->test_name, target->name, + cairo_boilerplate_content_name (target->content), dev_offset, dev_scale, similar ? " (similar)" : "", + fail_face, normal_face); + cairo_test_log (ctx, "FAIL\n"); + break; + } + fflush (stdout); + + return status; +} + +const cairo_test_context_t * +cairo_test_get_context (cairo_t *cr) +{ + return cairo_get_user_data (cr, &_cairo_test_context_key); +} + +cairo_t * +cairo_test_create (cairo_surface_t *surface, + const cairo_test_context_t *ctx) +{ + cairo_t *cr = cairo_create (surface); + cairo_set_user_data (cr, &_cairo_test_context_key, + (void*) ctx, NULL); + return cr; +} + +cairo_surface_t * +cairo_test_create_surface_from_png (const cairo_test_context_t *ctx, + const char *filename) +{ + cairo_surface_t *image; + cairo_status_t status; + char *unique_id; + + image = cairo_image_surface_create_from_png (filename); + status = cairo_surface_status (image); + if (status == CAIRO_STATUS_FILE_NOT_FOUND) { + /* expect not found when running with srcdir != builddir + * such as when 'make distcheck' is run + */ + if (ctx->srcdir) { + char *srcdir_filename; + xasprintf (&srcdir_filename, "%s/%s", ctx->srcdir, filename); + cairo_surface_destroy (image); + image = cairo_image_surface_create_from_png (srcdir_filename); + free (srcdir_filename); + } + } + unique_id = strdup(filename); + cairo_surface_set_mime_data (image, CAIRO_MIME_TYPE_UNIQUE_ID, + (unsigned char *)unique_id, strlen(unique_id), + free, unique_id); + + return image; +} + +cairo_pattern_t * +cairo_test_create_pattern_from_png (const cairo_test_context_t *ctx, + const char *filename) +{ + cairo_surface_t *image; + cairo_pattern_t *pattern; + + image = cairo_test_create_surface_from_png (ctx, filename); + + pattern = cairo_pattern_create_for_surface (image); + + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT); + + cairo_surface_destroy (image); + + return pattern; +} + +static cairo_surface_t * +_draw_check (int width, int height) +{ + cairo_surface_t *surface; + cairo_t *cr; + + surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 12, 12); + cr = cairo_create (surface); + cairo_surface_destroy (surface); + + cairo_set_source_rgb (cr, 0.75, 0.75, 0.75); /* light gray */ + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0.25, 0.25, 0.25); /* dark gray */ + cairo_rectangle (cr, width / 2, 0, width / 2, height / 2); + cairo_rectangle (cr, 0, height / 2, width / 2, height / 2); + cairo_fill (cr); + + surface = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + + return surface; +} + +void +cairo_test_paint_checkered (cairo_t *cr) +{ + cairo_surface_t *check; + + check = _draw_check (12, 12); + + cairo_save (cr); + cairo_set_source_surface (cr, check, 0, 0); + cairo_surface_destroy (check); + + cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); + cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT); + cairo_paint (cr); + + cairo_restore (cr); +} + +cairo_bool_t +cairo_test_is_target_enabled (const cairo_test_context_t *ctx, + const char *target) +{ + size_t i; + + for (i = 0; i < ctx->num_targets; i++) { + const cairo_boilerplate_target_t *t = ctx->targets_to_test[i]; + if (strcmp (t->name, target) == 0) { + /* XXX ask the target whether is it possible to run? + * e.g. the xlib backend could check whether it is able to connect + * to the Display. + */ + return t->get_image_surface != NULL; + } + } + + return FALSE; +} + +cairo_bool_t +cairo_test_malloc_failure (const cairo_test_context_t *ctx, + cairo_status_t status) +{ + if (! ctx->malloc_failure) + return FALSE; + + if (status != CAIRO_STATUS_NO_MEMORY) + return FALSE; + +#if HAVE_MEMFAULT + { + int n_faults; + + /* prevent infinite loops... */ + n_faults = MEMFAULT_COUNT_FAULTS (); + if (n_faults == ctx->last_fault_count) + return FALSE; + + ((cairo_test_context_t *) ctx)->last_fault_count = n_faults; + } +#endif + + return TRUE; +} + +cairo_test_status_t +cairo_test_status_from_status (const cairo_test_context_t *ctx, + cairo_status_t status) +{ + if (status == CAIRO_STATUS_SUCCESS) + return CAIRO_TEST_SUCCESS; + + if (cairo_test_malloc_failure (ctx, status)) + return CAIRO_TEST_NO_MEMORY; + + return CAIRO_TEST_FAILURE; +} + +#if CAIRO_HAS_FT_FONT + +#include "cairo-ft.h" + +static void +_free_face (void *face) +{ + FT_Done_Face ((FT_Face) face); +} + +static FT_Library ft_library = NULL; + +#endif + +static const cairo_user_data_key_t ft_font_key; + +cairo_test_status_t +cairo_test_ft_select_font_from_file (cairo_t *cr, + const char *filename) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); +#if CAIRO_HAS_FT_FONT + FT_Face face; + cairo_font_face_t *font_face; + char *srcdir_filename = NULL; + + if (access (filename, F_OK) != 0) { + if (ctx->srcdir) { + xasprintf (&srcdir_filename, "%s/%s", ctx->srcdir, filename); + filename = srcdir_filename; + } + } + + if (access (filename, F_OK) != 0) { + cairo_test_log (ctx, "Could not find font file: %s\n", filename); + return CAIRO_TEST_FAILURE; + } + + if (!ft_library) { + if (FT_Init_FreeType (&ft_library)) + return CAIRO_TEST_FAILURE; + } + + if (FT_New_Face (ft_library, filename, 0, &face)) { + cairo_test_log (ctx, "FT_New_Face failed loading font file: %s\n", filename); + return CAIRO_TEST_FAILURE; + } + + free (srcdir_filename); + font_face = cairo_ft_font_face_create_for_ft_face (face, 0); + if (cairo_font_face_status (font_face)) + return CAIRO_TEST_FAILURE; + + cairo_font_face_set_user_data (font_face, &ft_font_key, face, _free_face); + cairo_set_font_face (cr, font_face); + if (cairo_status (cr)) + return CAIRO_TEST_FAILURE; + + cairo_font_face_destroy (font_face); + + return CAIRO_TEST_SUCCESS; +#else + cairo_test_log (ctx, "cairo_test_ft_select_font_from_file() requires the FreeType backend\n"); + return CAIRO_TEST_FAILURE; +#endif +} diff --git a/local/recipes/libs/cairo/source/test/cairo-test.h b/local/recipes/libs/cairo/source/test/cairo-test.h new file mode 100644 index 0000000000..b706546540 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/cairo-test.h @@ -0,0 +1,333 @@ +/* + * Copyright © 2004 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#ifndef _CAIRO_TEST_H_ +#define _CAIRO_TEST_H_ + +#include "cairo-boilerplate.h" + +#include + +CAIRO_BEGIN_DECLS + +#if HAVE_STDINT_H +# include +#elif HAVE_INTTYPES_H +# include +#elif HAVE_SYS_INT_TYPES_H +# include +#elif defined(_MSC_VER) +typedef __int8 int8_t; +typedef unsigned __int8 uint8_t; +typedef __int16 int16_t; +typedef unsigned __int16 uint16_t; +typedef __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; +# ifndef HAVE_UINT64_T +# define HAVE_UINT64_T 1 +# endif +#else +#error Cannot find definitions for fixed-width integral types (uint8_t, uint32_t, \etc.) +#endif + +#ifdef _MSC_VER +#define _USE_MATH_DEFINES + +#include +#if _MSC_VER <= 1600 +#define isnan(x) _isnan(x) +#endif + +#endif + +#if HAVE_FENV_H +# include +#endif +/* The following are optional in C99, so define them if they aren't yet */ +#ifndef FE_DIVBYZERO +#define FE_DIVBYZERO 0 +#endif +#ifndef FE_INEXACT +#define FE_INEXACT 0 +#endif +#ifndef FE_INVALID +#define FE_INVALID 0 +#endif +#ifndef FE_OVERFLOW +#define FE_OVERFLOW 0 +#endif +#ifndef FE_UNDERFLOW +#define FE_UNDERFLOW 0 +#endif + +#include + +static inline double +cairo_test_NaN (void) +{ +#ifdef _MSC_VER + /* MSVC strtod("NaN", NULL) returns 0.0 */ + union { + uint32_t i[2]; + double d; + } nan = {{0xffffffff, 0x7fffffff}}; + return nan.d; +#else + return strtod("NaN", NULL); +#endif +} + +#ifndef MIN +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef MAX +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + +#define CAIRO_TEST_OUTPUT_DIR "output" + +#define CAIRO_TEST_LOG_SUFFIX ".log" + +#define CAIRO_TEST_FONT_FAMILY "DejaVu" + +/* What is a fail and what isn't? + * When running the test suite we want to detect unexpected output. This + * can be caused by a change we have made to cairo itself, or a change + * in our environment. To capture this we classify the expected output into 3 + * classes: + * + * REF -- Perfect output. + * Might be different for each backend, due to slight implementation + * differences. + * + * NEW -- A new failure. We have uncovered a bug within cairo and have + * recorded the current failure (along with the expected output + * if possible!) so we can detect any changes in our attempt to + * fix the bug. + * + * XFAIL -- An external failure. We believe the cairo output is perfect, + * but an external renderer is causing gross failure. + * (We also use this to capture current WONTFIX issues within cairo, + * such as overflow in internal coordinates, so as not to distract + * us when regression testing.) + * + * If no REF is given for a test, then it is assumed to be XFAIL. + */ +#define CAIRO_TEST_REF_SUFFIX ".ref" +#define CAIRO_TEST_XFAIL_SUFFIX ".xfail" +#define CAIRO_TEST_NEW_SUFFIX ".new" + +#define CAIRO_TEST_OUT_SUFFIX ".out" +#define CAIRO_TEST_DIFF_SUFFIX ".diff" + +#define CAIRO_TEST_PNG_EXTENSION ".png" +#define CAIRO_TEST_OUT_PNG CAIRO_TEST_OUT_SUFFIX CAIRO_TEST_PNG_EXTENSION +#define CAIRO_TEST_REF_PNG CAIRO_TEST_REF_SUFFIX CAIRO_TEST_PNG_EXTENSION +#define CAIRO_TEST_DIFF_PNG CAIRO_TEST_DIFF_SUFFIX CAIRO_TEST_PNG_EXTENSION + +typedef enum cairo_test_status { + CAIRO_TEST_SUCCESS = 0, + CAIRO_TEST_NO_MEMORY, + CAIRO_TEST_FAILURE, + CAIRO_TEST_NEW, + CAIRO_TEST_XFAILURE, + CAIRO_TEST_ERROR, + CAIRO_TEST_CRASHED, + CAIRO_TEST_UNTESTED = 77 /* match automake's skipped exit status */ +} cairo_test_status_t; + +typedef struct _cairo_test_context cairo_test_context_t; +typedef struct _cairo_test cairo_test_t; + +typedef cairo_test_status_t +(cairo_test_preamble_function_t) (cairo_test_context_t *ctx); + +typedef cairo_test_status_t +(cairo_test_draw_function_t) (cairo_t *cr, int width, int height); + +struct _cairo_test { + const char *name; + const char *description; + const char *keywords; + const char *requirements; + double width; + double height; + cairo_test_preamble_function_t *preamble; + cairo_test_draw_function_t *draw; +}; + +/* The standard test interface which works by examining result image. + * + * CAIRO_TEST() constructs a test which will be called once before (the + * preamble callback), and then once for each testable backend (the draw + * callback). The following checks will be performed for each backend: + * + * 1) If preamble() returns CAIRO_TEST_UNTESTED, the test is skipped. + * + * 2) If preamble() does not return CAIRO_TEST_SUCCESS, the test fails. + * + * 3) If draw() does not return CAIRO_TEST_SUCCESS then this backend + * fails. + * + * 4) Otherwise, if cairo_status(cr) indicates an error then this + * backend fails. + * + * 5) Otherwise, if the image size is 0, then this backend passes. + * + * 6) Otherwise, if every channel of every pixel exactly matches the + * reference image then this backend passes. If not, this backend + * fails. + * + * The overall test result is PASS if and only if there is at least + * one backend that is tested and if all tested backend pass according + * to the four criteria above. + */ +#define CAIRO_TEST(name, description, keywords, requirements, width, height, preamble, draw) \ +void _register_##name (void); \ +void _register_##name (void) { \ + static cairo_test_t test = { \ + #name, description, \ + keywords, requirements, \ + width, height, \ + preamble, draw \ + }; \ + cairo_test_register (&test); \ +} + +void +cairo_test_register (cairo_test_t *test); + +/* The full context for the test. + * For ordinary tests (using the CAIRO_TEST()->draw interface) the context + * is passed to the draw routine via user_data on the cairo_t. + * The reason why the context is not passed as an explicit parameter is that + * it is rarely required by the test itself and by removing the parameter + * we can keep the draw routines simple and serve as example code. + * + * In contrast, for the preamble phase the context is passed as the only + * parameter. + */ +struct _cairo_test_context { + const cairo_test_t *test; + const char *test_name; + + FILE *log_file; + const char *output; + const char *srcdir; /* directory containing sources and input data */ + char *refdir; /* directory containing reference images */ + + char *ref_name; /* cache of the current reference image */ + cairo_surface_t *ref_image; + cairo_surface_t *ref_image_flattened; + + size_t num_targets; + cairo_bool_t limited_targets; + const cairo_boilerplate_target_t **targets_to_test; + cairo_bool_t own_targets; + + int malloc_failure; + int last_fault_count; + + int timeout; +}; + +/* Retrieve the test context from the cairo_t, used for logging, paths etc */ +const cairo_test_context_t * +cairo_test_get_context (cairo_t *cr); + + +/* Print a message to the log file, ala printf. */ +void +cairo_test_log (const cairo_test_context_t *ctx, + const char *fmt, ...) CAIRO_BOILERPLATE_PRINTF_FORMAT(2, 3); +void +cairo_test_logv (const cairo_test_context_t *ctx, + const char *fmt, va_list ap) CAIRO_BOILERPLATE_PRINTF_FORMAT(2, 0); + +/* Helper functions that take care of finding source images even when + * building in a non-srcdir manner, (i.e. the tests will be run in a + * directory that is different from the one where the source image + * exists). */ +cairo_surface_t * +cairo_test_create_surface_from_png (const cairo_test_context_t *ctx, + const char *filename); + +cairo_pattern_t * +cairo_test_create_pattern_from_png (const cairo_test_context_t *ctx, + const char *filename); + +void +cairo_test_paint_checkered (cairo_t *cr); + +#define CAIRO_TEST_DOUBLE_EQUALS(a,b) (fabs((a)-(b)) < 0.00001) + +cairo_bool_t +cairo_test_is_target_enabled (const cairo_test_context_t *ctx, + const char *target); + +char * +cairo_test_get_name (const cairo_test_t *test); + +cairo_bool_t +cairo_test_malloc_failure (const cairo_test_context_t *ctx, + cairo_status_t status); + +cairo_test_status_t +cairo_test_status_from_status (const cairo_test_context_t *ctx, + cairo_status_t status); + +char * +cairo_test_reference_filename (const cairo_test_context_t *ctx, + const char *base_name, + const char *test_name, + const char *target_name, + const char *base_target_name, + const char *format, + const char *suffix, + const char *extension); + +cairo_surface_t * +cairo_test_get_reference_image (cairo_test_context_t *ctx, + const char *filename, + cairo_bool_t flatten); + +cairo_bool_t +cairo_test_mkdir (const char *path); + +cairo_t * +cairo_test_create (cairo_surface_t *surface, + const cairo_test_context_t *ctx); + +/* Set font face from a font file in build or src dir, using the FT backend. */ +cairo_test_status_t +cairo_test_ft_select_font_from_file (cairo_t *cr, + const char *filename); + +CAIRO_END_DECLS + +#endif diff --git a/local/recipes/libs/cairo/source/test/caps-joins-alpha.c b/local/recipes/libs/cairo/source/test/caps-joins-alpha.c new file mode 100644 index 0000000000..bbff44e572 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/caps-joins-alpha.c @@ -0,0 +1,89 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +#define LINE_WIDTH 10. +#define SIZE (5 * LINE_WIDTH) +#define PAD (2 * LINE_WIDTH) + +static void +make_path (cairo_t *cr) +{ + cairo_move_to (cr, 0., 0.); + cairo_rel_line_to (cr, 0., SIZE); + cairo_rel_line_to (cr, SIZE, 0.); + cairo_close_path (cr); + + cairo_move_to (cr, 2 * LINE_WIDTH, 0.); + cairo_rel_line_to (cr, 3 * LINE_WIDTH, 0.); + cairo_rel_line_to (cr, 0., 3 * LINE_WIDTH); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + /* First draw a checkered background */ + cairo_test_paint_checkered (cr); + + /* Then draw the original caps-joins test but with a bit of alphs thrown in. */ + cairo_set_line_width (cr, LINE_WIDTH); + + cairo_set_source_rgba (cr, 1.0, 0.0, 0.0, 0.5); /* 50% red */ + cairo_translate (cr, PAD, PAD); + + make_path (cr); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_BEVEL); + cairo_stroke (cr); + + cairo_set_source_rgba (cr, 0.0, 1.0, 0.0, 0.5); /* 50% green */ + cairo_translate (cr, SIZE + PAD, 0.); + + make_path (cr); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); + cairo_stroke (cr); + + cairo_set_source_rgba (cr, 0.0, 0.0, 1.0, 0.5); /* 50% blue */ + + cairo_translate (cr, SIZE + PAD, 0.); + + make_path (cr); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (caps_joins_alpha, + "Test caps and joins with some source alpha", + "stroke", /* keywords */ + NULL, /* requirements */ + 3 * (PAD + SIZE) + PAD, + PAD + SIZE + PAD, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/caps-joins-curve.c b/local/recipes/libs/cairo/source/test/caps-joins-curve.c new file mode 100644 index 0000000000..cf197547c2 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/caps-joins-curve.c @@ -0,0 +1,111 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +#define LINE_WIDTH 10. +#define SIZE (5 * LINE_WIDTH) +#define PAD (3 * LINE_WIDTH) + +static void +make_path (cairo_t *cr) +{ + cairo_move_to (cr, 0, 0); + cairo_rel_curve_to (cr, + -SIZE/4, SIZE/3, + -SIZE/4, SIZE/3, + 0, SIZE); + cairo_rel_curve_to (cr, + SIZE/3, -SIZE/4, + SIZE/3, -SIZE/4, + SIZE, 0); + cairo_close_path (cr); + + cairo_move_to (cr, 5 * LINE_WIDTH, 3 * LINE_WIDTH); + cairo_rel_curve_to (cr, + 0, -3 * LINE_WIDTH, + 0, -3 * LINE_WIDTH, + -3 * LINE_WIDTH, -3 * LINE_WIDTH); +} + +static void +draw_caps_joins (cairo_t *cr) +{ + cairo_save (cr); + + cairo_translate (cr, PAD, PAD); + + make_path (cr); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_BEVEL); + cairo_stroke (cr); + + cairo_translate (cr, SIZE + PAD, 0.); + + make_path (cr); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); + cairo_stroke (cr); + + cairo_translate (cr, SIZE + PAD, 0.); + + make_path (cr); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER); + cairo_stroke (cr); + + cairo_restore (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + /* We draw in the default black, so paint white first. */ + cairo_save (cr); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_restore (cr); + + cairo_set_line_width (cr, LINE_WIDTH); + + draw_caps_joins (cr); + + /* and reflect to generate the opposite vertex ordering */ + cairo_translate (cr, 0, height); + cairo_scale (cr, 1, -1); + + draw_caps_joins (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (caps_joins_curve, + "Test caps and joins on curves", + "stroke, cap, join", /* keywords */ + NULL, /* requirements */ + 3 * (PAD + SIZE) + PAD, + 2 * (PAD + SIZE) + PAD, + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/caps-joins.c b/local/recipes/libs/cairo/source/test/caps-joins.c new file mode 100644 index 0000000000..de22d03679 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/caps-joins.c @@ -0,0 +1,150 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +#define LINE_WIDTH 10. +#define SIZE (5 * LINE_WIDTH) +#define PAD (2 * LINE_WIDTH) + +static void +make_path (cairo_t *cr) +{ + cairo_move_to (cr, 0., 0.); + cairo_rel_line_to (cr, 0., SIZE); + cairo_rel_line_to (cr, SIZE, 0.); + cairo_close_path (cr); + + cairo_move_to (cr, 5 * LINE_WIDTH, 3 * LINE_WIDTH); + cairo_rel_line_to (cr, 0., -3 * LINE_WIDTH); + cairo_rel_line_to (cr, -3 * LINE_WIDTH, 0.); +} + +static void +draw_caps_joins (cairo_t *cr) +{ + cairo_save (cr); + + cairo_translate (cr, PAD, PAD); + + make_path (cr); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_BEVEL); + cairo_stroke (cr); + + cairo_translate (cr, SIZE + PAD, 0.); + + make_path (cr); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); + cairo_stroke (cr); + + cairo_translate (cr, SIZE + PAD, 0.); + + make_path (cr); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER); + cairo_stroke (cr); + + cairo_restore (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, float line_width) +{ + /* We draw in the default black, so paint white first. */ + cairo_save (cr); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_restore (cr); + + cairo_set_line_width (cr, line_width); + + draw_caps_joins (cr); + + /* and reflect to generate the opposite vertex ordering */ + cairo_translate (cr, 0, 2 * (PAD + SIZE) + PAD); + cairo_scale (cr, 1, -1); + + draw_caps_joins (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +draw_10 (cairo_t *cr, int width, int height) +{ + return draw (cr, LINE_WIDTH); +} + +static cairo_test_status_t +draw_2 (cairo_t *cr, int width, int height) +{ + return draw (cr, 2.0); +} + +static cairo_test_status_t +draw_1 (cairo_t *cr, int width, int height) +{ + return draw (cr, 1.0); +} + +static cairo_test_status_t +draw_05 (cairo_t *cr, int width, int height) +{ + return draw (cr, 0.5); +} + +CAIRO_TEST (caps_joins, + "Test caps and joins", + "stroke", /* keywords */ + NULL, /* requirements */ + 3 * (PAD + SIZE) + PAD, + 2 * (PAD + SIZE) + PAD, + NULL, draw_10) + +CAIRO_TEST (caps_joins_2, + "Test caps and joins with default line width", + "stroke", /* keywords */ + NULL, /* requirements */ + 3 * (PAD + SIZE) + PAD, + 2 * (PAD + SIZE) + PAD, + NULL, draw_2) + +CAIRO_TEST (caps_joins_1, + "Test caps and joins with hairlines", + "stroke", /* keywords */ + NULL, /* requirements */ + 3 * (PAD + SIZE) + PAD, + 2 * (PAD + SIZE) + PAD, + NULL, draw_1) + +CAIRO_TEST (caps_joins_05, + "Test caps and joins with fine lines", + "stroke", /* keywords */ + NULL, /* requirements */ + 3 * (PAD + SIZE) + PAD, + 2 * (PAD + SIZE) + PAD, + NULL, draw_05) diff --git a/local/recipes/libs/cairo/source/test/caps-sub-paths.c b/local/recipes/libs/cairo/source/test/caps-sub-paths.c new file mode 100644 index 0000000000..2310eb7526 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/caps-sub-paths.c @@ -0,0 +1,65 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +/* Test case for bug #4205: + + https://bugs.freedesktop.org/show_bug.cgi?id=4205 +*/ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + /* We draw in the default black, so paint white first. */ + cairo_save (cr); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_restore (cr); + + cairo_set_line_width (cr, 4); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + + cairo_move_to (cr, 4, 4); + cairo_line_to (cr, 4, 16); + + cairo_move_to (cr, 10, 4); + cairo_line_to (cr, 10, 16); + + cairo_move_to (cr, 16, 4); + cairo_line_to (cr, 16, 16); + + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (caps_sub_paths, + "Test that sub-paths receive caps.", + "stroke", /* keywords */ + NULL, /* requirements */ + 20, 20, + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/caps-tails-curve.c b/local/recipes/libs/cairo/source/test/caps-tails-curve.c new file mode 100644 index 0000000000..fa6aded3d9 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/caps-tails-curve.c @@ -0,0 +1,127 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +#define LINE_WIDTH 30. +#define SIZE (2 * LINE_WIDTH) +#define PAD (2 * LINE_WIDTH) + +static void +make_path (cairo_t *cr, double theta) +{ + double line_width = cairo_get_line_width (cr) / 4; + + cairo_move_to (cr, 0, 0); + cairo_rel_curve_to (cr, + SIZE/3, -SIZE/4, + SIZE/3, -SIZE/4, + SIZE, 0); + + cairo_rel_line_to (cr, + cos (theta) * line_width, + sin (theta) * line_width); +} + +static void +draw_joins (cairo_t *cr, double theta) +{ + make_path (cr, theta); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_BEVEL); + cairo_stroke (cr); + + cairo_translate (cr, SIZE + PAD, 0.); + + make_path (cr, theta); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); + cairo_stroke (cr); + + cairo_translate (cr, SIZE + PAD, 0.); + + make_path (cr, theta); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER); + cairo_stroke (cr); + + cairo_translate (cr, SIZE + PAD, 0.); +} + +static void +draw_caps_joins (cairo_t *cr, double theta) +{ + cairo_translate (cr, PAD, 0); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + draw_joins (cr, theta); + + cairo_translate (cr, PAD, 0); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + draw_joins (cr, theta); + + cairo_translate (cr, PAD, 0); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); + draw_joins (cr, theta); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const double theta[] = { + -M_PI/2, -M_PI/4, 0, M_PI/8, M_PI/3, M_PI + }; + unsigned int t; + + /* We draw in the default black, so paint white first. */ + cairo_save (cr); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_restore (cr); + + cairo_set_line_width (cr, LINE_WIDTH); + + for (t = 0; t < ARRAY_LENGTH(theta); t++) { + cairo_save (cr); + cairo_translate (cr, 0, t * (SIZE + PAD) + PAD); + draw_caps_joins (cr, theta[t]); + cairo_restore (cr); + + cairo_save (cr); + /* and reflect to generate the opposite vertex ordering */ + cairo_translate (cr, 0, height - t * (SIZE + PAD) - PAD); + cairo_scale (cr, 1, -1); + draw_caps_joins (cr, theta[t]); + cairo_restore (cr); + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (caps_tails_curve, + "Test caps and joins on short tail segments", + "stroke, cap, join", /* keywords */ + NULL, /* requirements */ + 9 * (PAD + SIZE) + 4*PAD, + 12 * (PAD + SIZE) + PAD, + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/caps.c b/local/recipes/libs/cairo/source/test/caps.c new file mode 100644 index 0000000000..87f008a7c8 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/caps.c @@ -0,0 +1,138 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +#define LINE_WIDTH 10. +#define SIZE (5 * LINE_WIDTH) +#define PAD (2 * LINE_WIDTH) + +static void +make_path (cairo_t *cr) +{ + int i; + + cairo_save (cr); + for (i = 0; i <= 3; i++) { + cairo_new_sub_path (cr); + cairo_move_to (cr, -SIZE / 2, 0.); + cairo_line_to (cr, SIZE / 2, 0.); + cairo_rotate (cr, M_PI / 4.); + } + cairo_restore (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr) +{ + cairo_save (cr); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_restore (cr); + + cairo_translate (cr, PAD + SIZE / 2., PAD + SIZE / 2.); + + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_BEVEL); + make_path (cr); + cairo_stroke (cr); + + cairo_translate (cr, 0, SIZE + PAD); + + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); + make_path (cr); + cairo_stroke (cr); + + cairo_translate (cr, 0, SIZE + PAD); + + cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER); + make_path (cr); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +draw_10 (cairo_t *cr, int width, int height) +{ + cairo_set_line_width (cr, LINE_WIDTH); + return draw (cr); +} + +static cairo_test_status_t +draw_2 (cairo_t *cr, int width, int height) +{ + cairo_set_line_width (cr, 2); + return draw (cr); +} + +static cairo_test_status_t +draw_1 (cairo_t *cr, int width, int height) +{ + cairo_set_line_width (cr, 1); + return draw (cr); +} + +static cairo_test_status_t +draw_05 (cairo_t *cr, int width, int height) +{ + cairo_set_line_width (cr, 0.5); + return draw (cr); +} + +CAIRO_TEST (caps, + "Test caps", + "stroke, caps", /* keywords */ + NULL, /* requirements */ + PAD + SIZE + PAD, + 3 * (PAD + SIZE) + PAD, + NULL, draw_10) + +CAIRO_TEST (caps_2, + "Test normal caps", + "stroke, caps", /* keywords */ + NULL, /* requirements */ + PAD + SIZE + PAD, + 3 * (PAD + SIZE) + PAD, + NULL, draw_2) + +CAIRO_TEST (caps_1, + "Test hairline caps", + "stroke, caps", /* keywords */ + NULL, /* requirements */ + PAD + SIZE + PAD, + 3 * (PAD + SIZE) + PAD, + NULL, draw_1) + +CAIRO_TEST (caps_05, + "Test fine caps", + "stroke, caps", /* keywords */ + NULL, /* requirements */ + PAD + SIZE + PAD, + 3 * (PAD + SIZE) + PAD, + NULL, draw_05) + diff --git a/local/recipes/libs/cairo/source/test/ccitt.g3 b/local/recipes/libs/cairo/source/test/ccitt.g3 new file mode 100644 index 0000000000..b5ef99e3dd --- /dev/null +++ b/local/recipes/libs/cairo/source/test/ccitt.g3 @@ -0,0 +1,2 @@ +ÿþFÙÞ#Z#™¡ôІ½©à¡è(¨Ô³ ¼b#£†GGâ:#³hÒœ‹ºœ3‹Bд#B.‚éºù1Äã¦PåÑ1ʉé¢": *ÂôÕˆ½Vš¼x»ë6o¯žþ‡^¾Ö¿è›þN—ZÑ7 D{ÿ_ÓJ÷×d{ÿkkf+ L —j•ÿØØØc_þÌöPæ(p¨2‡({(sÌõxˆˆˆˆ¨‹ˆˆˆˆÎЂB}(} +ˆ«(pDu(pQÿÿ \ No newline at end of file diff --git a/local/recipes/libs/cairo/source/test/check-pdf-structure.sh b/local/recipes/libs/cairo/source/test/check-pdf-structure.sh new file mode 100755 index 0000000000..31ae5ac2c2 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/check-pdf-structure.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +if test $# -ne 4 ; then + echo "Usage: $0 " + exit 3 +fi + +# Check for pdfinfo version >= 21.10.00 +if pdfinfo -v 2>& 1 | awk '/pdfinfo version/ { split($3,v,/[.]/); if (v[1] > 21 || (v[1] == 21 && v[2] >= 10) ) { print "yes" } } ' | grep -q 'yes'; then + pdfinfo -struct-text "$1" > "$2" + if test -f "$3" ; then + diff -u "$3" "$2" > "$4" + # diff exit codes: 0 = match, 1 = different, 2 = error + exit $? + else + exit 3 # missing ref file + fi +fi + + # pdfinfo missing or wrong version +exit 4 diff --git a/local/recipes/libs/cairo/source/test/check-refs.sh b/local/recipes/libs/cairo/source/test/check-refs.sh new file mode 100755 index 0000000000..e2e8a1a2ae --- /dev/null +++ b/local/recipes/libs/cairo/source/test/check-refs.sh @@ -0,0 +1,69 @@ +#!/bin/bash + +cd $(dirname $0)/reference || exit + +pdiff=$1 +[ -n "$pdiff" ] || pdiff=../pdiff/perceptualdiff +if [ ! -e "${pdiff}" ]; then + echo "Error: requires pdiff executable" + exit 128 +fi + +exit_code=0 + +for file in *.ref.png; do + test=$(echo $file | cut -d'.' -f1) + target=$(echo $file | cut -d'.' -f2) + format=$(echo $file | cut -d'.' -f3) + notes="" + ref="" + result="" + + if [ $target = 'base' ]; then + # Ignore the base images for this script's purposes + continue + elif [ $target = 'ref' ]; then + # This is actually the baseline reference image + continue + elif [ $format = 'ref' ]; then + # This is either a format-specific reference, or a target-specific/format-generic image + # In either case, compare it against the generic reference image + ref="$test.ref.png" + else + # Prefer the target-specific/format-generic reference image, if available + ref="$test.$target.ref.png" + if [ ! -e $ref ]; then + ref="$test.$format.ref.png" + fi + fi + + # Special cases + if [ $test = "create-from-png" ]; then + # The create-from-png test utilizes multiple reference images directly + continue + elif [ $test = "fallback-resolution" ]; then + # The fallback-resolution test generates a set of reference images; + # These won't be redundant with one another, but just ignore them all. + continue + fi + + if [ -e $ref ]; then + if cmp --silent "$ref" "$file" ; then + printf "redundant: %s and %s are byte-by-byte identical files\n" $file $ref + exit_code=1 + else + # Run perceptualdiff with minimum threshold + pdiff_output=$($pdiff $ref $file -threshold 1) + result=${pdiff_output%:*} + notes=$(echo "${pdiff_output#*: }" | tail -n 1) + if [ "$result" = "PASS" ] && [ "$notes" = "Images are binary identical" ]; then + printf "redundant: %s and %s are pixel equivalent images\n" $file $ref + exit_code=1 + notes="" + fi + fi + fi + +done + +exit $exit_code diff --git a/local/recipes/libs/cairo/source/test/checkerboard.c b/local/recipes/libs/cairo/source/test/checkerboard.c new file mode 100644 index 0000000000..aeb2efe14b --- /dev/null +++ b/local/recipes/libs/cairo/source/test/checkerboard.c @@ -0,0 +1,48 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +/* Test the basic background used extensively in the test suite. */ + +#include "cairo-test.h" + +#define HEIGHT 32 +#define WIDTH 32 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_test_paint_checkered (cr); + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (checkerboard, + "Tests the checkerboard background", + "paint", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/clear-source.c b/local/recipes/libs/cairo/source/test/clear-source.c new file mode 100644 index 0000000000..5410932fcd --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clear-source.c @@ -0,0 +1,169 @@ +/* + * Copyright 2009 Benjamin Otte + * + * 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: Benjamin Otte + */ + +#include "cairo-test.h" + +typedef enum { + CLEAR, + CLEARED, + PAINTED +} surface_type_t; + +#define SIZE 10 +#define SPACE 5 + +static cairo_surface_t * +create_surface (cairo_t *target, cairo_content_t content, surface_type_t type) +{ + cairo_surface_t *surface; + cairo_t *cr; + + surface = cairo_surface_create_similar (cairo_get_target (target), + content, + SIZE, SIZE); + + if (type == CLEAR) + return surface; + + cr = cairo_create (surface); + cairo_surface_destroy (surface); + + cairo_set_source_rgb (cr, 0.75, 0, 0); + cairo_paint (cr); + + if (type == PAINTED) + goto DONE; + + cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); + cairo_paint (cr); + +DONE: + surface = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + + return surface; +} + +static void +paint (cairo_t *cr, cairo_surface_t *surface) +{ + cairo_set_source_surface (cr, surface, 0, 0); + cairo_paint (cr); +} + +static void +fill (cairo_t *cr, cairo_surface_t *surface) +{ + cairo_set_source_surface (cr, surface, 0, 0); + cairo_rectangle (cr, -SPACE, -SPACE, SIZE + 2 * SPACE, SIZE + 2 * SPACE); + cairo_fill (cr); +} + +static void +stroke (cairo_t *cr, cairo_surface_t *surface) +{ + cairo_set_source_surface (cr, surface, 0, 0); + cairo_set_line_width (cr, 2.0); + cairo_rectangle (cr, 1, 1, SIZE - 2, SIZE - 2); + cairo_stroke (cr); +} + +static void +mask (cairo_t *cr, cairo_surface_t *surface) +{ + cairo_set_source_rgb (cr, 0, 0, 0.75); + cairo_mask_surface (cr, surface, 0, 0); +} + +static void +mask_self (cairo_t *cr, cairo_surface_t *surface) +{ + cairo_set_source_surface (cr, surface, 0, 0); + cairo_mask_surface (cr, surface, 0, 0); +} + +static void +glyphs (cairo_t *cr, cairo_surface_t *surface) +{ + cairo_set_source_surface (cr, surface, 0, 0); + cairo_select_font_face (cr, + "@cairo:", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (cr, 16); + cairo_translate (cr, 0, SIZE); + cairo_show_text (cr, "C"); +} + +typedef void (* operation_t) (cairo_t *cr, cairo_surface_t *surface); +static operation_t operations[] = { + paint, + fill, + stroke, + mask, + mask_self, + glyphs +}; + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_content_t contents[] = { CAIRO_CONTENT_COLOR_ALPHA, CAIRO_CONTENT_COLOR, CAIRO_CONTENT_ALPHA }; + unsigned int content, type, ops; + + cairo_set_source_rgb (cr, 0.5, 0.5, 0.5); + cairo_paint (cr); + cairo_translate (cr, SPACE, SPACE); + + for (type = 0; type <= PAINTED; type++) { + for (content = 0; content < ARRAY_LENGTH (contents); content++) { + cairo_surface_t *surface; + + surface = create_surface (cr, contents[content], type); + + cairo_save (cr); + for (ops = 0; ops < ARRAY_LENGTH (operations); ops++) { + cairo_save (cr); + operations[ops] (cr, surface); + cairo_restore (cr); + cairo_translate (cr, 0, SIZE + SPACE); + } + cairo_restore (cr); + cairo_translate (cr, SIZE + SPACE, 0); + + cairo_surface_destroy (surface); + } + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clear_source, + "Check painting with cleared surfaces works as expected", + NULL, /* keywords */ + NULL, /* requirements */ + (SIZE + SPACE) * 9 + SPACE, ARRAY_LENGTH (operations) * (SIZE + SPACE) + SPACE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/clear.c b/local/recipes/libs/cairo/source/test/clear.c new file mode 100644 index 0000000000..696993d3f7 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clear.c @@ -0,0 +1,86 @@ +/* + * Copyright © 2009 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_text_extents_t extents; + + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_paint (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); + + cairo_translate (cr, 2, 2); + cairo_save (cr); + cairo_rectangle (cr, 0, 0, 20, 20); + cairo_clip (cr); + cairo_rectangle (cr, 5, 5, 10, 10); + cairo_fill (cr); + cairo_restore (cr); + + cairo_translate (cr, 20, 0); + cairo_save (cr); + cairo_rectangle (cr, 0, 0, 20, 20); + cairo_clip (cr); + cairo_arc (cr, 10, 10, 8, 0, 2*M_PI); + cairo_fill (cr); + cairo_restore (cr); + + cairo_translate (cr, 0, 20); + cairo_save (cr); + cairo_rectangle (cr, 0, 0, 20, 20); + cairo_clip (cr); + cairo_text_extents (cr, "Cairo", &extents); + cairo_move_to (cr, + 10 - (extents.width/2. + extents.x_bearing), + 10 - (extents.height/2. + extents.y_bearing)); + cairo_text_path (cr, "Cairo"); + cairo_fill (cr); + cairo_restore (cr); + + cairo_translate (cr, -20, 0); + cairo_save (cr); + cairo_rectangle (cr, 0, 0, 20, 20); + cairo_clip (cr); + cairo_move_to (cr, 10, 2); + cairo_line_to (cr, 18, 18); + cairo_line_to (cr, 2, 18); + cairo_close_path (cr); + cairo_fill (cr); + cairo_restore (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clear, + "Test masked clears", + "paint, clear", /* keywords */ + NULL, /* requirements */ + 44, 44, + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/clip-all.c b/local/recipes/libs/cairo/source/test/clip-all.c new file mode 100644 index 0000000000..dc216c9cb8 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clip-all.c @@ -0,0 +1,75 @@ +/* + * Copyright © 2005 Novell, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Novell, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Novell, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Radek Doulík + */ + +#include "cairo-test.h" + +#define SIZE 10 +#define CLIP_SIZE 2 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_rectangle (cr, 0, 0, SIZE, SIZE); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_fill (cr); + + cairo_reset_clip (cr); + cairo_rectangle (cr, CLIP_SIZE, CLIP_SIZE, CLIP_SIZE, CLIP_SIZE); + cairo_clip (cr); + cairo_rectangle (cr, 3*CLIP_SIZE, 3*CLIP_SIZE, CLIP_SIZE, CLIP_SIZE); + cairo_clip (cr); + + cairo_translate (cr, .5, .5); + + cairo_reset_clip (cr); + cairo_rectangle (cr, CLIP_SIZE, CLIP_SIZE, CLIP_SIZE, CLIP_SIZE); + cairo_clip (cr); + cairo_rectangle (cr, 3*CLIP_SIZE, 3*CLIP_SIZE, CLIP_SIZE, CLIP_SIZE); + cairo_clip (cr); + + cairo_rectangle (cr, 0, 0, SIZE, SIZE); + cairo_set_source_rgb (cr, 1, 1, 0); + cairo_fill (cr); + + /* https://bugs.freedesktop.org/show_bug.cgi?id=13084 */ + cairo_select_font_face (cr, + CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + + cairo_move_to (cr, 0., SIZE); + cairo_show_text (cr, "cairo"); + + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clip_all, + "Test clipping with everything clipped out", + "clip", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/clip-complex-bug61592.c b/local/recipes/libs/cairo/source/test/clip-complex-bug61592.c new file mode 100644 index 0000000000..46f8fb8dac --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clip-complex-bug61592.c @@ -0,0 +1,60 @@ +/* + * Copyright © 2013 Uli Schlachter + * + * 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: Uli Schlachter + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE); + cairo_move_to(cr, 85, -465); + cairo_line_to(cr, 3, 4.1); + cairo_line_to(cr, -145, -25); + cairo_close_path(cr); + cairo_clip(cr); + + cairo_set_antialias(cr, CAIRO_ANTIALIAS_DEFAULT); + cairo_move_to(cr, -139, -524); + cairo_line_to(cr, 78, 44); + cairo_line_to(cr, -229, -10); + cairo_close_path(cr); + cairo_clip(cr); + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clip_complex_bug61592, + "Exercise a bug found in 1.12", + "clip", /* keywords */ + NULL, /* requirements */ + 8, 5, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/clip-complex-shape.c b/local/recipes/libs/cairo/source/test/clip-complex-shape.c new file mode 100644 index 0000000000..d7d530146e --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clip-complex-shape.c @@ -0,0 +1,114 @@ +/* + * Copyright 2011 SCore Corporation + * + * 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: Taekyun Kim + */ + +#include "cairo-test.h" + +static void +rounded_rectangle(cairo_t *cr, + double x, double y, + double width, double height, + double radius) +{ + cairo_move_to (cr, x, y + radius); + cairo_line_to (cr, x, y + height - radius); + cairo_curve_to (cr, x, y + height - radius/2.0, + x + radius/2.0, y + height, + x + radius, y + height); + cairo_line_to (cr, x + width - radius, y + height); + cairo_curve_to (cr, x + width - radius/2.0, y + height, + x + width, y + height - radius/2.0, + x + width, y + height - radius); + cairo_line_to (cr, x + width, y + radius); + cairo_curve_to (cr, x + width, y + radius/2.0, + x + width - radius/2.0, y, + x + width - radius, y); + cairo_line_to (cr, x + radius, y); + cairo_curve_to (cr, x + radius/2.0, y, x, y + radius/2.0, x, y + radius); + cairo_close_path(cr); +} + +static void +background (cairo_t *cr) +{ + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0); + cairo_paint(cr); +} + +static void +foreground (cairo_t *cr) +{ + cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 1.0); + cairo_set_operator(cr, CAIRO_OPERATOR_OVER); + cairo_rectangle(cr, 20, 20, 60, 60); + cairo_fill(cr); +} + +static cairo_test_status_t +clip_eo_mono (cairo_t *cr, int width, int height) +{ + + background (cr); + + cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE); + cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD); + rounded_rectangle(cr, 0, 0, 40, 100, 10); + rounded_rectangle(cr, 60, 0, 40, 100, 10); + cairo_clip(cr); + + foreground (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +clip_eo_aa (cairo_t *cr, int width, int height) +{ + background (cr); + + cairo_set_antialias(cr, CAIRO_ANTIALIAS_DEFAULT); + cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD); + rounded_rectangle(cr, 0, 0, 40, 100, 10); + rounded_rectangle(cr, 60, 0, 40, 100, 10); + cairo_clip(cr); + + foreground (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clip_complex_shape_eo_mono, + "Test clipping against a complex shape", + "clip", /* keywords */ + NULL, /* requirements */ + 100, 100, + NULL, clip_eo_mono) +CAIRO_TEST (clip_complex_shape_eo_aa, + "Test clipping against a complex shape", + "clip", /* keywords */ + NULL, /* requirements */ + 100, 100, + NULL, clip_eo_aa) diff --git a/local/recipes/libs/cairo/source/test/clip-contexts.c b/local/recipes/libs/cairo/source/test/clip-contexts.c new file mode 100644 index 0000000000..39d2004c01 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clip-contexts.c @@ -0,0 +1,75 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Intel Corporation not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Intel Corporation makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * INTEL CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +/* + * Jeff Muizelaar found a bug on Quartz with cairo-surface-clipper, which was + * the topmost clip path from two different contexts and finding them equally + * incorrectly concluding that the operation was a no-op. + */ + +#define SIZE 10 +#define CLIP_SIZE 2 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_t *cr2; + + /* opaque background */ + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + /* first create an empty, non-overlappiny clip */ + cr2 = cairo_create (cairo_get_target (cr)); + cairo_rectangle (cr2, 0, 0, SIZE/2-2, SIZE/2-2); + cairo_clip (cr2); + + cairo_rectangle (cr2, SIZE/2+2, SIZE/2+2, SIZE/2-2, SIZE/2-2); + cairo_clip (cr2); + + /* and apply the clip onto the surface, empty nothing should be painted */ + cairo_set_source_rgba (cr2, 1, 0, 0, .5); + cairo_paint (cr2); + + /* switch back to the original, and set only the last clip */ + cairo_rectangle (cr, SIZE/2+2, SIZE/2+2, SIZE/2-2, SIZE/2-2); + cairo_clip (cr); + + cairo_set_source_rgba (cr, 0, 0, 1, .5); + cairo_paint (cr); + + cairo_destroy (cr2); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clip_contexts, + "Test clipping with 2 separate contexts", + "clip", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/clip-device-offset.c b/local/recipes/libs/cairo/source/test/clip-device-offset.c new file mode 100644 index 0000000000..f725b8e93a --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clip-device-offset.c @@ -0,0 +1,79 @@ +/* + * Copyright © 2009 Benjamin Otte + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Benjamin Otte + */ + +#include "cairo-test.h" + +#define WIDTH 50 +#define HEIGHT 50 + +static cairo_pattern_t * +create_green_source (void) +{ + cairo_surface_t *image; + cairo_pattern_t *pattern; + cairo_t *cr; + + image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, WIDTH, HEIGHT); + cr = cairo_create (image); + cairo_surface_destroy (image); + + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_paint (cr); + + pattern = cairo_pattern_create_for_surface (cairo_get_target (cr)); + cairo_destroy (cr); + + return pattern; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *source; + double old_x, old_y; + + cairo_surface_get_device_offset (cairo_get_group_target (cr), &old_x, &old_y); + cairo_surface_set_device_offset (cairo_get_group_target (cr), old_x+5, old_y+5); + + source = create_green_source (); + cairo_set_source (cr, source); + cairo_pattern_destroy (source); + + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_rectangle (cr, 0, 0, WIDTH, HEIGHT); + cairo_clip (cr); + cairo_paint (cr); + + cairo_surface_set_device_offset (cairo_get_group_target (cr), old_x, old_y); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clip_device_offset, + "Test clipping on surfaces with device offsets", + "clip", /* keywords */ + NULL, /* requirements */ + WIDTH+10, HEIGHT+10, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/clip-disjoint-hatching.c b/local/recipes/libs/cairo/source/test/clip-disjoint-hatching.c new file mode 100644 index 0000000000..8626e80df7 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clip-disjoint-hatching.c @@ -0,0 +1,104 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +#define STEP 5 +#define WIDTH 100 +#define HEIGHT 100 + +static void hatching (cairo_t *cr) +{ + int i; + + cairo_rectangle (cr, 0, 0, WIDTH, HEIGHT); + cairo_clip (cr); + + cairo_translate (cr, WIDTH/2, HEIGHT/2); + cairo_rotate (cr, M_PI/4); + cairo_translate (cr, -WIDTH/2, -HEIGHT/2); + + for (i = 0; i < WIDTH; i += STEP) { + cairo_rectangle (cr, i, -2, 1, HEIGHT+4); + cairo_rectangle (cr, -2, i, WIDTH+4, 1); + } +} + +static void background (cairo_t *cr) +{ + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgb (cr, 1,1,1); + cairo_paint (cr); +} + +static void clip_to_grid (cairo_t *cr) +{ + int i, j; + + for (j = 0; j < HEIGHT; j += 2*STEP) { + for (i = 0; i < WIDTH; i += 2*STEP) + cairo_rectangle (cr, i, j, STEP, STEP); + + j += 2*STEP; + for (i = 0; i < WIDTH; i += 2*STEP) + cairo_rectangle (cr, i+STEP/2, j, STEP, STEP); + } + + cairo_clip (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + background (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + + cairo_save (cr); { + clip_to_grid (cr); + hatching (cr); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_fill (cr); + } cairo_restore (cr); + + cairo_translate (cr, 0.25, HEIGHT+.25); + + cairo_save (cr); { + clip_to_grid (cr); + hatching (cr); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_fill (cr); + } cairo_restore (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clip_disjoint_hatching, + "Test drawing through through an array of clips", + "clip", /* keywords */ + "target=raster", /* requirements */ + WIDTH, 2*HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/clip-disjoint-quad.c b/local/recipes/libs/cairo/source/test/clip-disjoint-quad.c new file mode 100644 index 0000000000..fe20381d77 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clip-disjoint-quad.c @@ -0,0 +1,83 @@ +/* + * Copyright © 2012 Red Hat, Inc. + * Copyright © 2012 Intel Corporation + * + * 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: Soren Sandmann + * Chris Wilson + */ + +#include "cairo-test.h" + +#define WIDTH 100 +#define HEIGHT 200 + +static void +draw_quad (cairo_t *cr, + double x1, double y1, + double x2, double y2, + double x3, double y3, + double x4, double y4) +{ + cairo_move_to (cr, x1, y1); + cairo_line_to (cr, x2, y2); + cairo_line_to (cr, x3, y3); + cairo_line_to (cr, x4, y4); + cairo_close_path (cr); + + cairo_set_source_rgb (cr, 0, 0.6, 0); + cairo_fill (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + int position[5] = {0, HEIGHT/2-10, HEIGHT/2-5, HEIGHT/2, HEIGHT-10 }; + int i; + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + for (i = 0; i < 5; i++) { + cairo_reset_clip (cr); + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_rectangle (cr, 0, 0, WIDTH/2, HEIGHT/2); + cairo_rectangle (cr, WIDTH/2, position[i], WIDTH/2, 10); + cairo_fill_preserve (cr); + cairo_clip (cr); + + cairo_set_source_rgb (cr, 1, 0, 1); + draw_quad (cr, 50, 50, 75, 75, 50, 150, 25, 75); + cairo_fill (cr); + + cairo_translate(cr, WIDTH, 0); + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clip_disjoint_quad, + "Tests a simple fill through two disjoint clips.", + "clip, fill", /* keywords */ + NULL, /* requirements */ + 5*WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/clip-disjoint.c b/local/recipes/libs/cairo/source/test/clip-disjoint.c new file mode 100644 index 0000000000..28bb963c24 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clip-disjoint.c @@ -0,0 +1,90 @@ +/* + * Copyright © 2008 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Soren Sandmann + */ + +#include "cairo-test.h" + +#define WIDTH 300 +#define HEIGHT 300 + +typedef struct { + double x, y; +} point_t; + +static void +paint_curve (cairo_t *cr) +{ + const point_t points[] = { + { 100, 320 }, { 110, -80 }, + { 180, 60 }, { 300, 170 }, + { 300, -40 } + }; + unsigned i; + + cairo_set_line_width (cr, 2); + cairo_move_to (cr, points[0].x, points[0].y); + + for (i = 1; i < ARRAY_LENGTH (points) - 2; i += 3) { + cairo_curve_to (cr, + points[i].x, points[i].y, + points[i + 1].x, points[i + 1].y, + points[i + 2].x, points[i + 2].y); + } + cairo_set_line_width (cr, 5); + cairo_stroke (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + /* Fill window with light blue */ + cairo_set_source_rgba (cr, 0.8, 0.8, 1.9, 1.0); + cairo_paint (cr); + + /* Paint curve in green */ + cairo_set_source_rgba (cr, 0.6, 0.8, 0.6, 1.0); + paint_curve (cr); + + /* Make clip region */ + cairo_rectangle (cr, 228, 131, 50, 13); + cairo_rectangle (cr, 20, 99, 200, 75); + cairo_clip_preserve (cr); + + /* Fill clip region with red */ + cairo_set_source_rgba (cr, 1.0, 0.5, 0.5, 0.8); + cairo_fill (cr); + + /* Paint curve again, this time in blue */ + cairo_set_source_rgba (cr, 0, 0, 1.0, 1.0); + paint_curve (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clip_disjoint, + "Tests stroking through two disjoint clips.", + "clip, stroke", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/clip-double-free.c b/local/recipes/libs/cairo/source/test/clip-double-free.c new file mode 100644 index 0000000000..74b9a6e6db --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clip-double-free.c @@ -0,0 +1,87 @@ +/* + * Copyright © 2011 Uli Schlachter + * + * 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: Uli Schlachter + */ + +/* + * This test wants to hit the following double free: + * + * ==10517== Invalid free() / delete / delete[] + * ==10517== at 0x4C268FE: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) + * ==10517== by 0x87FBE80: _cairo_clip_destroy (cairo-clip.c:136) + * ==10517== by 0x87FE520: _cairo_clip_intersect_boxes.part.1 (cairo-clip-private.h:92) + * ==10517== by 0x87FE79F: _cairo_clip_intersect_rectilinear_path (cairo-clip-boxes.c:266) + * ==10517== by 0x87FC29B: _cairo_clip_intersect_path.part.3 (cairo-clip.c:242) + * ==10517== by 0x8809C3A: _cairo_gstate_clip (cairo-gstate.c:1518) + * ==10517== by 0x8802E40: _cairo_default_context_clip (cairo-default-context.c:1048) + * ==10517== by 0x87FA2C6: cairo_clip (cairo.c:2380) + * ==10517== Address 0x18d44cb0 is 0 bytes inside a block of size 32 free'd + * ==10517== at 0x4C268FE: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) + * ==10517== by 0x87FE506: _cairo_clip_intersect_boxes.part.1 (cairo-clip-boxes.c:295) + * ==10517== by 0x87FE79F: _cairo_clip_intersect_rectilinear_path (cairo-clip-boxes.c:266) + * ==10517== by 0x87FC29B: _cairo_clip_intersect_path.part.3 (cairo-clip.c:242) + * ==10517== by 0x8809C3A: _cairo_gstate_clip (cairo-gstate.c:1518) + * ==10517== by 0x8802E40: _cairo_default_context_clip (cairo-default-context.c:1048) + * ==10517== by 0x87FA2C6: cairo_clip (cairo.c:2380) + * + * _cairo_clip_intersect_boxes() is called with clip->num_boxes != 0. It then + * calls _cairo_boxes_init_for_array (&clip_boxes, clip->boxes, clip->num_boxes) + * and free (clip->boxes), stealing the clip's boxes, but leaving a dangling + * pointer behind. + * Because this code already intersected the existing boxes and the new ones, we + * now have num_boxes == 0. This means that _cairo_clip_set_all_clipped() gets + * called and tries to free the clip's boxes again. + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + + /* To hit this bug, we first need a clip with + * clip->boxes != clip->embedded_boxes. + */ + cairo_rectangle (cr, 0, 0, 2, 2); + cairo_rectangle (cr, 0, 0, 1, 1); + cairo_clip (cr); + + /* Then we have to intersect this with a rectilinear path which results in + * all clipped. This path must consist of at least two boxes or we will hit + * a different code path. + */ + cairo_rectangle (cr, 10, 10, 2, 2); + cairo_rectangle (cr, 10, 10, 1, 1); + cairo_clip (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clip_double_free, + "Test a double free bug in the clipping code", + "clip", /* keywords */ + NULL, /* requirements */ + 0, 0, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/clip-draw-unbounded.c b/local/recipes/libs/cairo/source/test/clip-draw-unbounded.c new file mode 100644 index 0000000000..6b9263bebe --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clip-draw-unbounded.c @@ -0,0 +1,184 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright 2009 Chris Wilson + * Copyright 2010 Andrea Canciani + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +#define WIDTH 60 +#define HEIGHT 60 + +static void +stroke (cairo_t *cr) +{ + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_paint (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_IN); + cairo_set_source_rgb (cr, 0, 0.7, 0); + cairo_arc (cr, 10, 10, 7.5, 0, 2 * M_PI); + cairo_move_to (cr, 0, 20); + cairo_line_to (cr, 20, 0); + cairo_stroke (cr); +} + +static void +fill (cairo_t *cr) +{ + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_paint (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_IN); + cairo_set_source_rgb (cr, 0, 0.7, 0); + cairo_new_sub_path (cr); + cairo_arc (cr, 10, 10, 8.5, 0, 2 * M_PI); + cairo_new_sub_path (cr); + cairo_arc_negative (cr, 10, 10, 6.5, 2 * M_PI, 0); + + cairo_move_to (cr, -1, 19); + cairo_line_to (cr, 1, 21); + cairo_line_to (cr, 21, 1); + cairo_line_to (cr, 19, -1); + cairo_line_to (cr, -1, 19); + + cairo_fill (cr); +} + +static void +clip_simple (cairo_t *cr) +{ + cairo_rectangle (cr, 0, 0, 20, 20); + cairo_clip (cr); +} + +static void +clip_unaligned (cairo_t *cr) +{ + cairo_rectangle (cr, 0.5, 0.5, 20, 20); + cairo_clip (cr); +} + +static void +clip_aligned (cairo_t *cr) +{ + cairo_fill_rule_t orig_rule; + + orig_rule = cairo_get_fill_rule (cr); + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + cairo_rectangle (cr, 0, 0, 20, 20); + cairo_rectangle (cr, 3, 3, 10, 10); + cairo_rectangle (cr, 7, 7, 10, 10); + cairo_clip (cr); + cairo_set_fill_rule (cr, orig_rule); +} + +static void +clip_mask (cairo_t *cr) +{ + cairo_arc (cr, 10, 10, 10, 0, 2 * M_PI); + cairo_new_sub_path (cr); + cairo_arc_negative (cr, 10, 10, 5, 2 * M_PI, 0); + cairo_new_sub_path (cr); + cairo_arc (cr, 10, 10, 2, 0, 2 * M_PI); + cairo_clip (cr); +} + +static void (* const clip_funcs[])(cairo_t *cr) = { + clip_simple, + clip_unaligned, + clip_aligned, + clip_mask +}; + +static double translations[][2] = { + { 10, 10 }, + { WIDTH, 0 }, + { -WIDTH, HEIGHT }, + { WIDTH, 0 } +}; + +static cairo_test_status_t +draw (cairo_t *cr, void (*shapes)(cairo_t *)) +{ + unsigned int i; + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + for (i = 0; i < ARRAY_LENGTH (clip_funcs); i++) { + cairo_translate (cr, translations[i][0], translations[i][1]); + + cairo_save (cr); + cairo_scale (cr, 2, 2); + clip_funcs[i] (cr); + shapes (cr); + cairo_restore (cr); + } + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +draw_stroke (cairo_t *cr, int width, int height) +{ + return draw (cr, stroke); +} + +static cairo_test_status_t +draw_fill_nz (cairo_t *cr, int width, int height) +{ + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_WINDING); + return draw (cr, fill); +} + +static cairo_test_status_t +draw_fill_eo (cairo_t *cr, int width, int height) +{ + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + return draw (cr, fill); +} + +CAIRO_TEST (clip_stroke_unbounded, + "Tests unbounded stroke through complex clips.", + "clip, stroke, unbounded", /* keywords */ + NULL, /* requirements */ + 2 * WIDTH, 2 * HEIGHT, + NULL, draw_stroke) + +CAIRO_TEST (clip_fill_nz_unbounded, + "Tests unbounded fill through complex clips (with winding fill rule).", + "clip, fill, unbounded", /* keywords */ + NULL, /* requirements */ + 2 * WIDTH, 2 * HEIGHT, + NULL, draw_fill_nz) + +CAIRO_TEST (clip_fill_eo_unbounded, + "Tests unbounded fill through complex clips (with even-odd fill rule).", + "clip, fill, unbounded", /* keywords */ + NULL, /* requirements */ + 2 * WIDTH, 2 * HEIGHT, + NULL, draw_fill_eo) diff --git a/local/recipes/libs/cairo/source/test/clip-empty-group.c b/local/recipes/libs/cairo/source/test/clip-empty-group.c new file mode 100644 index 0000000000..3829c88584 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clip-empty-group.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2010 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +/* Test the handling of cairo_push_group() with everything clipped. */ +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_paint (cr); /* opaque background */ + + cairo_rectangle (cr, 20, 20, 0, 0); + cairo_clip (cr); + + cairo_push_group (cr); /* => 0x0 group */ + cairo_reset_clip (cr); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_paint (cr); + + cairo_rectangle (cr, 0, 0, width, height); + cairo_set_source_rgba (cr, 0, 1, 0, .5); + cairo_fill (cr); + + cairo_move_to (cr, 0, 20); + cairo_line_to (cr, width, 20); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_stroke (cr); + + cairo_pop_group_to_source (cr); + cairo_reset_clip (cr); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clip_empty_group, + "Test handling of groups with everything clipped", + "clip, group", /* keywords */ + NULL, /* requirements */ + 40, 40, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/clip-empty-save.c b/local/recipes/libs/cairo/source/test/clip-empty-save.c new file mode 100644 index 0000000000..35de3cb948 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clip-empty-save.c @@ -0,0 +1,68 @@ +/* + * Copyright © 2007 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +#define SIZE 10 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_paint (cr); + + cairo_reset_clip (cr); + cairo_clip (cr); + + cairo_save (cr); + + cairo_translate (cr, .5, .5); + + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_rectangle (cr, 0, 0, SIZE, SIZE); + cairo_fill_preserve (cr); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_stroke (cr); + + /* https://bugs.freedesktop.org/show_bug.cgi?id=13084 */ + cairo_select_font_face (cr, + CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + + cairo_move_to (cr, 0., SIZE); + cairo_show_text (cr, "cairo"); + + cairo_restore (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clip_empty_save, + "Test clipping with an empty clip path", + "clip", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/clip-empty.c b/local/recipes/libs/cairo/source/test/clip-empty.c new file mode 100644 index 0000000000..858b69a9e1 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clip-empty.c @@ -0,0 +1,64 @@ +/* + * Copyright © 2007 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +#define SIZE 10 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_paint (cr); + + cairo_reset_clip (cr); + cairo_clip (cr); + + cairo_translate (cr, .5, .5); + + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_rectangle (cr, 0, 0, SIZE, SIZE); + cairo_fill_preserve (cr); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_stroke (cr); + + /* https://bugs.freedesktop.org/show_bug.cgi?id=13084 */ + cairo_select_font_face (cr, + CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + + cairo_move_to (cr, 0., SIZE); + cairo_show_text (cr, "cairo"); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clip_empty, + "Test clipping with an empty clip path", + "clip", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/clip-fill-no-op.c b/local/recipes/libs/cairo/source/test/clip-fill-no-op.c new file mode 100644 index 0000000000..b686b6e0e7 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clip-fill-no-op.c @@ -0,0 +1,67 @@ +/* + * Copyright 2009 Benjamin Otte + * + * 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: Benjamin Otte + */ + +#include "cairo-test.h" + +#define WIDTH 50 +#define HEIGHT 50 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + /* Neutral gray background */ + cairo_set_source_rgb (cr, 0.5, 0.5, 0.5); + cairo_paint (cr); + + /* remove this clip operation and everything works */ + cairo_rectangle (cr, 10, 10, 30, 30); + cairo_clip (cr); + + /* remove this no-op and everything works */ + cairo_fill (cr); + + /* make the y coordinates integers and everything works */ + cairo_move_to (cr, 20, 20.101562); + cairo_line_to (cr, 30, 20.101562); + + /* This clip operation should fail to work. But with cairo 1.9, if all the + * 3 cases above happen, the clip will not work and the paint will happen. + */ + cairo_save (cr); { + cairo_set_source_rgba (cr, 1, 0.5, 0.5, 1); + cairo_clip_preserve (cr); + cairo_paint (cr); + } cairo_restore (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clip_fill_no_op, + "Exercises a bug found by Benjamin Otte whereby a no-op clip is nullified by a stroke", + "clip, fill", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/clip-fill-rule-pixel-aligned.c b/local/recipes/libs/cairo/source/test/clip-fill-rule-pixel-aligned.c new file mode 100644 index 0000000000..210afcb839 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clip-fill-rule-pixel-aligned.c @@ -0,0 +1,90 @@ +/* + * Copyright © 2004 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +#define PAD 1 +#define SIZE 5 + +static void +pixel_aligned_path (cairo_t *cr) +{ + cairo_save (cr); + { + cairo_scale (cr, SIZE, SIZE); + cairo_move_to (cr, 1, 0); + cairo_rel_line_to (cr, 1, 0); + cairo_rel_line_to (cr, 0, 3); + cairo_rel_line_to (cr, 1, 0); + cairo_rel_line_to (cr, 0, -1); + cairo_rel_line_to (cr, -3, 0); + cairo_rel_line_to (cr, 0, -1); + cairo_rel_line_to (cr, 4, 0); + cairo_rel_line_to (cr, 0, 3); + cairo_rel_line_to (cr, -3, 0); + cairo_rel_line_to (cr, 0, -4); + cairo_close_path (cr); + } + cairo_restore (cr); +} + +/* Use clipping to draw the same path twice, once with each fill rule */ +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 0, 0); /* red */ + + cairo_translate (cr, PAD, PAD); + + cairo_save (cr); + { + pixel_aligned_path (cr); + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + cairo_clip (cr); + cairo_paint (cr); + } + cairo_restore (cr); + + cairo_translate (cr, SIZE*4 + PAD, 0); + + cairo_save (cr); + { + pixel_aligned_path (cr); + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_WINDING); + cairo_clip (cr); + cairo_paint (cr); + } + cairo_restore (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clip_fill_rule_pixel_aligned, + "Tests interaction of clipping and cairo_set_fill_rule with a pixel-aligned path", + "clip", /* keywords */ + NULL, /* requirements */ + PAD + (SIZE*4) + PAD + (SIZE*4) + PAD, + PAD + (SIZE*4) + PAD, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/clip-fill-rule.c b/local/recipes/libs/cairo/source/test/clip-fill-rule.c new file mode 100644 index 0000000000..31c3ab71d9 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clip-fill-rule.c @@ -0,0 +1,87 @@ +/* + * Copyright © 2004 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +#define STAR_SIZE 20 + +static void +star_path (cairo_t *cr) +{ + cairo_move_to (cr, 10, 0); + cairo_rel_line_to (cr, 6, 20); + cairo_rel_line_to (cr, -16, -12); + cairo_rel_line_to (cr, 20, 0); + cairo_rel_line_to (cr, -16, 12); +} + +/* Use clipping to draw the same path twice, once with each fill rule */ +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 0, 0); + + cairo_translate (cr, 1, 1); + cairo_save (cr); + { + star_path (cr); + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_WINDING); + cairo_clip (cr); + cairo_paint (cr); + } + cairo_restore (cr); + + cairo_translate (cr, STAR_SIZE + 1, 0); + cairo_save (cr); + { + star_path (cr); + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + cairo_clip (cr); + cairo_paint (cr); + } + cairo_restore (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +a1_draw (cairo_t *cr, int width, int height) +{ + cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); + return draw (cr, width, height); +} + +CAIRO_TEST (clip_fill_rule, + "Tests interaction of clipping with cairo_set_fill_rule", + "clip", /* keywords */ + NULL, /* requirements */ + STAR_SIZE * 2 + 2, STAR_SIZE + 2, + NULL, draw) +CAIRO_TEST (a1_clip_fill_rule, + "Tests interaction of clipping with cairo_set_fill_rule", + "clip", /* keywords */ + "target=raster", /* requirements */ + STAR_SIZE * 2 + 2, STAR_SIZE + 2, + NULL, a1_draw) diff --git a/local/recipes/libs/cairo/source/test/clip-fill.c b/local/recipes/libs/cairo/source/test/clip-fill.c new file mode 100644 index 0000000000..331af7963f --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clip-fill.c @@ -0,0 +1,78 @@ +/* + * Copyright 2009 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +#define WIDTH 20 +#define HEIGHT 20 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + /* aligned-clip */ + cairo_save (cr); + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + cairo_rectangle (cr, 0, 0, 20, 20); + cairo_rectangle (cr, 3, 3, 10, 10); + cairo_rectangle (cr, 7, 7, 10, 10); + cairo_clip (cr); + + cairo_set_source_rgb (cr, 0.7, 0, 0); + cairo_paint (cr); + cairo_set_source_rgb (cr, 0, 0.7, 0); + cairo_arc (cr, 10, 10, 8, 0, 2 * M_PI); + cairo_fill (cr); + cairo_restore (cr); + + cairo_translate (cr, WIDTH, 0); + + /* force a clip-mask */ + cairo_save (cr); + cairo_arc (cr, 10, 10, 10, 0, 2 * M_PI); + cairo_new_sub_path (cr); + cairo_arc_negative (cr, 10, 10, 5, 2 * M_PI, 0); + cairo_new_sub_path (cr); + cairo_arc (cr, 10, 10, 2, 0, 2 * M_PI); + cairo_clip (cr); + + cairo_set_source_rgb (cr, 0, 0, 0.7); + cairo_paint (cr); + cairo_set_source_rgb (cr, 0, 0.7, 0); + cairo_arc (cr, 10, 10, 7.5, 0, 2 * M_PI); + cairo_fill (cr); + cairo_restore (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clip_fill, + "Tests filling through complex clips.", + "clip, fill", /* keywords */ + NULL, /* requirements */ + 2 * WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/clip-group-shapes.c b/local/recipes/libs/cairo/source/test/clip-group-shapes.c new file mode 100644 index 0000000000..88bb9b3dd0 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clip-group-shapes.c @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2010 M Joonas Pihlaja + * + * 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: M Joonas Pihlaja + */ +#include "cairo-test.h" + +/* Tests specific clipping fast paths and their interaction with + * groups: It shouldn't matter if the clip is set before or after + * pushing a group. + * + * There's some overlap with the following tests, but they test for + * different things: + * + * group-clip.c (tests preserving paths), clipped-group.c (tests + * clipping the same thing different ways), clip-push-group (tests + * for a specific bug). + */ + +#define GENERATE_REF 0 + +/* For determining whether we establish the clip path before or after + * pushing a group. */ +enum { + CLIP_OUTSIDE_GROUP, + CLIP_INSIDE_GROUP +}; + +typedef void (*clipper_t)(cairo_t *cr, int w, int h); + +static cairo_test_status_t +clip_and_paint (cairo_t *cr, + int w, int h, + clipper_t do_clip, + int clip_where) +{ + cairo_save (cr); { + if (GENERATE_REF) { + do_clip (cr, w, h); + cairo_paint (cr); + } else { + if (clip_where == CLIP_OUTSIDE_GROUP) + do_clip (cr, w, h); + cairo_push_group (cr); { + if (clip_where == CLIP_INSIDE_GROUP) + do_clip (cr, w, h); + cairo_paint (cr); + } + cairo_pop_group_to_source (cr); + if (clip_where == CLIP_OUTSIDE_GROUP) + cairo_reset_clip (cr); + cairo_paint (cr); + } + } + cairo_restore (cr); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +run_clip_test (cairo_t *cr, int w, int h, clipper_t do_clip) +{ + cairo_set_source_rgb (cr, 1,1,1); + cairo_paint (cr); + cairo_set_source_rgb (cr, 1,0,0); + + /* Left. */ + clip_and_paint (cr, w/2, h, do_clip, CLIP_OUTSIDE_GROUP); + + /* Right */ + cairo_translate(cr, w/2, 0); + clip_and_paint (cr, w/2, h, do_clip, CLIP_INSIDE_GROUP); + + return CAIRO_TEST_SUCCESS; +} + +static void +clip_aligned_rectangles (cairo_t *cr, int w, int h) +{ + int x1 = 0.2 * w; + int y1 = 0.2 * h; + int x2 = 0.8 * w; + int y2 = 0.8 * h; + + cairo_rectangle (cr, x1, y1, w, h); + cairo_clip (cr); + + cairo_rectangle (cr, x2, y2, -w, -h); + cairo_clip (cr); +} + +static void +clip_unaligned_rectangles (cairo_t *cr, int w, int h) +{ + /* This clip stresses the antialiased edges produced by an + * unaligned rectangular clip. The edges should be produced by + * compositing red on white with alpha = 0.5 on the sides, and with + * alpha = 0.25 in the corners. */ + int x1 = 0.2 * w; + int y1 = 0.2 * h; + int x2 = 0.8 * w; + int y2 = 0.8 * h; + + cairo_rectangle (cr, x1+0.5, y1+0.5, w, h); + cairo_clip (cr); + + cairo_rectangle (cr, x2+0.5, y2+0.5, -w, -h); + w = x2 - x1; + h = y2 - y1; + cairo_rectangle (cr, x2, y1+1, -w+1, h-1); + cairo_clip (cr); +} + +static void +clip_circles (cairo_t *cr, int w, int h) +{ + int x1 = 0.5 * w; + int y1 = 0.5 * h; + int x2 = 0.75 * w; + int y2 = 0.75 * h; + int r = 0.4*MIN(w,h); + + cairo_arc (cr, x1, y1, r, 0, 6.28); + cairo_close_path (cr); + cairo_clip (cr); + + cairo_arc (cr, x2, y2, r, 0, 6.28); + cairo_close_path (cr); + cairo_clip (cr); +} + +static cairo_test_status_t +draw_aligned_rectangles (cairo_t *cr, int width, int height) +{ + return run_clip_test (cr, width, height, clip_aligned_rectangles); +} + +static cairo_test_status_t +draw_unaligned_rectangles (cairo_t *cr, int width, int height) +{ + return run_clip_test (cr, width, height, clip_unaligned_rectangles); +} + +static cairo_test_status_t +draw_circles (cairo_t *cr, int width, int height) +{ + return run_clip_test (cr, width, height, clip_circles); +} + +CAIRO_TEST (clip_group_shapes_aligned_rectangles, + "Test clip and group interaction with aligned rectangle clips", + "clip", /* keywords */ + NULL, /* requirements */ + 200, 100, + NULL, draw_aligned_rectangles) + +CAIRO_TEST (clip_group_shapes_unaligned_rectangles, + "Test clip and group interaction with unaligned rectangle clips", + "clip", /* keywords */ + "target=raster", /* requirements */ + 200, 100, + NULL, draw_unaligned_rectangles) + +CAIRO_TEST (clip_group_shapes_circles, + "Test clip and group interaction with circular clips", + "clip", /* keywords */ + NULL, /* requirements */ + 200, 100, + NULL, draw_circles) diff --git a/local/recipes/libs/cairo/source/test/clip-image.c b/local/recipes/libs/cairo/source/test/clip-image.c new file mode 100644 index 0000000000..68ed142d64 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clip-image.c @@ -0,0 +1,95 @@ +/* + * Copyright 2009 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +#define WIDTH 20 +#define HEIGHT 20 + +static const char *png_filename = "romedalen.png"; + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_surface_t *image; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + image = cairo_test_create_surface_from_png (ctx, png_filename); + cairo_set_source_surface (cr, image, 0, 0); + cairo_surface_destroy (image); + + /* simple clip */ + cairo_save (cr); + cairo_rectangle (cr, 2, 2, 16, 16); + cairo_clip (cr); + cairo_paint (cr); + cairo_restore (cr); + + cairo_translate (cr, WIDTH, 0); + + /* unaligned clip */ + cairo_save (cr); + cairo_rectangle (cr, 2.5, 2.5, 15, 15); + cairo_clip (cr); + cairo_paint (cr); + cairo_restore (cr); + + cairo_translate (cr, -WIDTH, HEIGHT); + + /* aligned-clip */ + cairo_save (cr); + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + cairo_rectangle (cr, 0, 0, 20, 20); + cairo_rectangle (cr, 3, 3, 10, 10); + cairo_rectangle (cr, 7, 7, 10, 10); + cairo_clip (cr); + cairo_paint (cr); + cairo_restore (cr); + + cairo_translate (cr, WIDTH, 0); + + /* force a clip-mask */ + cairo_save (cr); + cairo_arc (cr, 10, 10, 10, 0, 2 * M_PI); + cairo_new_sub_path (cr); + cairo_arc_negative (cr, 10, 10, 5, 2 * M_PI, 0); + cairo_new_sub_path (cr); + cairo_arc (cr, 10, 10, 2, 0, 2 * M_PI); + cairo_clip (cr); + cairo_paint (cr); + cairo_restore (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clip_image, + "Tests painting an image through complex clips.", + "clip, paint", /* keywords */ + NULL, /* requirements */ + 2 * WIDTH, 2 * HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/clip-intersect.c b/local/recipes/libs/cairo/source/test/clip-intersect.c new file mode 100644 index 0000000000..295fbc93c0 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clip-intersect.c @@ -0,0 +1,94 @@ +/* + * Copyright 2009 Chris Wilson + * Copyright 2011 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +#define WIDTH 20 +#define HEIGHT 20 + +static void clip_mask (cairo_t *cr) +{ + cairo_move_to (cr, 10, 0); + cairo_line_to (cr, 0, 10); + cairo_line_to (cr, 10, 20); + cairo_line_to (cr, 20, 10); + cairo_clip (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + clip_mask (cr); + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_paint (cr); + cairo_reset_clip (cr); + + cairo_set_source_rgb (cr, 1, 0, 0); + + cairo_rectangle (cr, 0, 0, 4, 4); + cairo_clip (cr); + clip_mask (cr); + cairo_paint (cr); + cairo_reset_clip (cr); + + cairo_rectangle (cr, 20, 0, -4, 4); + cairo_clip (cr); + clip_mask (cr); + cairo_paint (cr); + cairo_reset_clip (cr); + + cairo_rectangle (cr, 20, 20, -4, -4); + cairo_clip (cr); + clip_mask (cr); + cairo_paint (cr); + cairo_reset_clip (cr); + + cairo_rectangle (cr, 0, 20, 4, -4); + cairo_clip (cr); + clip_mask (cr); + cairo_paint (cr); + cairo_reset_clip (cr); + + cairo_set_source_rgb (cr, 0, 0, 1); + + cairo_rectangle (cr, 8, 8, 4, 4); + cairo_clip (cr); + clip_mask (cr); + cairo_paint (cr); + cairo_reset_clip (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clip_intersect, + "Tests intersection of a simple clip with a clip-mask", + "clip, paint", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/clip-mixed-antialias.c b/local/recipes/libs/cairo/source/test/clip-mixed-antialias.c new file mode 100644 index 0000000000..23a55ff63e --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clip-mixed-antialias.c @@ -0,0 +1,128 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +#define WIDTH 200 +#define HEIGHT 200 + +/* This is an example from the wild, as silly as it is +n 52 0 429 709 rectangle +clip+ +//ANTIALIAS_NONE set-antialias +n 8 0 m 952 0 l 956.417969 0 960 3.582031 960 8 c 960 1807 l 960 1811.417969 956.417969 1815 952 1815 c 8 1815 l 3.582031 1815 0 1811.417969 0 1807 c 0 8 l 0 3.582031 3.582031 0 8 0 c h +clip+ +//EVEN_ODD set-fill-rule +n 0 0 m 480 0 l 480 708 l 0 708 l h 8 1 m 952 1 l 955.867188 1 959 4.132812 959 8 c 959 1807 l 959 1810.867188 955.867188 1814 952 1814 c 8 1814 l 4.132812 1814 1 1810.867188 1 1807 c 1 8 l 1 4.132812 4.132812 1 8 1 c h +clip+ +//WINDING set-fill-rule +//ANTIALIAS_DEFAULT set-antialias +n 960 0 m 52.5 907.5 l 52.5 1815 l 960 1815 l h +clip+ +//ANTIALIAS_NONE set-antialias +n 960 0 m 52.5 0 l 52.5 907.5 l 960 1815 l h +clip+ +*/ + +static void background (cairo_t *cr) +{ + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgb (cr, 1,1,1); + cairo_paint (cr); + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); +} + +static void clip_0 (cairo_t *cr) +{ + cairo_rectangle (cr, 5, 5, 190, 190); + cairo_clip (cr); +} + +static void clip_1 (cairo_t *cr) +{ + cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); + + cairo_arc (cr, 100, 100, 125, 0, 2*M_PI); + cairo_clip (cr); + + cairo_set_antialias (cr, CAIRO_ANTIALIAS_DEFAULT); +} + +static void +rounded_rectangle (cairo_t *cr, int x, int y, int w, int h, int r) +{ + cairo_new_sub_path (cr); + cairo_arc (cr, x + r, y + r, r, M_PI, 3 * M_PI / 2); + cairo_arc (cr, x + w - r, y + r, r, 3 *M_PI / 2, 2 * M_PI); + cairo_arc (cr, x + w - r, y + h - r, r, 0, M_PI / 2); + cairo_arc (cr, x + r, y + h - r, r, M_PI / 2, M_PI); + cairo_close_path (cr); +} + +static void clip_2 (cairo_t *cr) +{ + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + + rounded_rectangle (cr, 50, 50, 100, 100, 15); + rounded_rectangle (cr, 60, 60, 80, 80, 5); + cairo_clip (cr); + + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_WINDING); +} + +static void clip_3 (cairo_t *cr) +{ + cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); + + cairo_rectangle (cr, 40.25, 60.25, 120, 80); + cairo_rectangle (cr, 60.25, 40.25, 80, 120); + cairo_clip (cr); + + cairo_set_antialias (cr, CAIRO_ANTIALIAS_DEFAULT); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + background (cr); + + clip_0 (cr); + clip_1 (cr); + clip_2 (cr); + clip_3 (cr); + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clip_mixed_antialias, + "Test drawing through through an mixture of clips", + "clip", /* keywords */ + "target=raster", /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/clip-nesting.c b/local/recipes/libs/cairo/source/test/clip-nesting.c new file mode 100644 index 0000000000..a9227ec77c --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clip-nesting.c @@ -0,0 +1,109 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Owen Taylor + */ + +#include "cairo-test.h" +#include +#include + +#define SIZE 100 +#define BORDER 10 +#define LINE_WIDTH 20 + +static void +_propagate_status (cairo_t *dst, cairo_t *src) +{ + cairo_path_t path; + + path.status = cairo_status (src); + if (path.status) { + path.num_data = 0; + path.data = NULL; + cairo_append_path (dst, &path); + } +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *target_surface; + cairo_t *cr2, *cr3; + + target_surface = cairo_get_group_target (cr); + + cr2 = cairo_create (target_surface); + + /* Draw a diagonal line and clip to it */ + + cairo_move_to (cr2, BORDER, BORDER); + cairo_line_to (cr2, BORDER + LINE_WIDTH, BORDER); + cairo_line_to (cr2, SIZE - BORDER, SIZE - BORDER); + cairo_line_to (cr2, SIZE - BORDER - LINE_WIDTH, SIZE - BORDER); + + cairo_clip (cr2); + cairo_set_source_rgb (cr2, 0, 0, 1); /* Blue */ + cairo_paint (cr2); + + /* Clipping affects this cairo_t */ + + cairo_set_source_rgb (cr2, 1, 1, 1); /* White */ + cairo_rectangle (cr2, + SIZE / 2 - LINE_WIDTH / 2, BORDER, + LINE_WIDTH, SIZE - 2 * BORDER); + cairo_fill (cr2); + + /* But doesn't affect another cairo_t that we create temporarily for + * the same surface + */ + cr3 = cairo_create (target_surface); + cairo_set_source_rgb (cr3, 1, 1, 1); /* White */ + cairo_rectangle (cr3, + SIZE - BORDER - LINE_WIDTH, BORDER, + LINE_WIDTH, SIZE - 2 * BORDER); + cairo_fill (cr3); + + _propagate_status (cr, cr3); + cairo_destroy (cr3); + + _propagate_status (cr, cr2); + cairo_destroy (cr2); + + /* And doesn't affect anything after this cairo_t is destroyed */ + + cairo_set_source_rgb (cr, 1, 1, 1); /* White */ + cairo_rectangle (cr, + BORDER, BORDER, + LINE_WIDTH, SIZE - 2 * BORDER); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; + +} + +CAIRO_TEST (clip_nesting, + "Test clipping with multiple contexts for the same surface", + "clip", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/clip-operator.c b/local/recipes/libs/cairo/source/test/clip-operator.c new file mode 100644 index 0000000000..ac0a5e966b --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clip-operator.c @@ -0,0 +1,188 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Kristian Høgsberg + */ + +#include "cairo-test.h" +#include +#include + +#define WIDTH 16 +#define HEIGHT 16 +#define PAD 2 + +static void +draw_mask (cairo_t *cr, int x, int y) +{ + cairo_surface_t *mask_surface; + cairo_t *cr2; + + double width = (int)(0.9 * WIDTH); + double height = (int)(0.9 * HEIGHT); + x += 0.05 * WIDTH; + y += 0.05 * HEIGHT; + + mask_surface = cairo_surface_create_similar (cairo_get_group_target (cr), + CAIRO_CONTENT_ALPHA, + width, height); + cr2 = cairo_create (mask_surface); + cairo_surface_destroy (mask_surface); + + cairo_save (cr2); + cairo_set_source_rgba (cr2, 0, 0, 0, 0); /* transparent */ + cairo_set_operator (cr2, CAIRO_OPERATOR_SOURCE); + cairo_paint (cr2); + cairo_restore (cr2); + + cairo_set_source_rgb (cr2, 1, 1, 1); /* white */ + + cairo_arc (cr2, 0.5 * width, 0.5 * height, 0.45 * height, 0, 2 * M_PI); + cairo_fill (cr2); + + cairo_mask_surface (cr, cairo_get_target (cr2), x, y); + cairo_destroy (cr2); +} + +static void +draw_glyphs (cairo_t *cr, int x, int y) +{ + cairo_text_extents_t extents; + + cairo_set_font_size (cr, 0.8 * HEIGHT); + + cairo_text_extents (cr, "FG", &extents); + cairo_move_to (cr, + x + floor ((WIDTH - extents.width) / 2 + 0.5) - extents.x_bearing, + y + floor ((HEIGHT - extents.height) / 2 + 0.5) - extents.y_bearing); + cairo_show_text (cr, "FG"); +} + +static void +draw_polygon (cairo_t *cr, int x, int y) +{ + double width = (int)(0.9 * WIDTH); + double height = (int)(0.9 * HEIGHT); + x += 0.05 * WIDTH; + y += 0.05 * HEIGHT; + + cairo_new_path (cr); + cairo_move_to (cr, x, y); + cairo_line_to (cr, x, y + height); + cairo_line_to (cr, x + width / 2, y + 3 * height / 4); + cairo_line_to (cr, x + width, y + height); + cairo_line_to (cr, x + width, y); + cairo_line_to (cr, x + width / 2, y + height / 4); + cairo_close_path (cr); + cairo_fill (cr); +} + +static void +draw_rects (cairo_t *cr, int x, int y) +{ + double block_width = (int)(0.33 * WIDTH + 0.5); + double block_height = (int)(0.33 * HEIGHT + 0.5); + int i, j; + + for (i = 0; i < 3; i++) + for (j = 0; j < 3; j++) + if ((i + j) % 2 == 0) + cairo_rectangle (cr, + x + block_width * i, y + block_height * j, + block_width, block_height); + + cairo_fill (cr); +} + +static void (* const draw_funcs[])(cairo_t *cr, int x, int y) = { + draw_mask, + draw_glyphs, + draw_polygon, + draw_rects +}; + +#define N_OPERATORS (1 + CAIRO_OPERATOR_SATURATE - CAIRO_OPERATOR_CLEAR) + +#define IMAGE_WIDTH (N_OPERATORS * (WIDTH + PAD) + PAD) +#define IMAGE_HEIGHT (ARRAY_LENGTH (draw_funcs) * (HEIGHT + PAD) + PAD) + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + size_t j, x, y; + cairo_operator_t op; + cairo_pattern_t *pattern; + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (cr, 0.9 * HEIGHT); + + for (j = 0; j < ARRAY_LENGTH (draw_funcs); j++) { + for (op = CAIRO_OPERATOR_CLEAR; op < N_OPERATORS; op++) { + x = op * (WIDTH + PAD) + PAD; + y = j * (HEIGHT + PAD) + PAD; + + cairo_save (cr); + + pattern = cairo_pattern_create_linear (x + WIDTH, y, + x, y + HEIGHT); + cairo_pattern_add_color_stop_rgba (pattern, 0.2, + 0.0, 0.0, 1.0, 1.0); /* Solid blue */ + cairo_pattern_add_color_stop_rgba (pattern, 0.8, + 0.0, 0.0, 1.0, 0.0); /* Transparent blue */ + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + + cairo_rectangle (cr, x, y, WIDTH, HEIGHT); + cairo_fill (cr); + + cairo_set_operator (cr, op); + cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); + + cairo_move_to (cr, x, y); + cairo_line_to (cr, x + WIDTH, y); + cairo_line_to (cr, x, y + HEIGHT); + cairo_clip (cr); + + draw_funcs[j] (cr, x, y); + if (cairo_status (cr)) + cairo_test_log (ctx, "%d %d HERE!\n", op, (int)j); + + cairo_restore (cr); + } + } + + if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) + cairo_test_log (ctx, "%d %d .HERE!\n", op, (int)j); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clip_operator, + "Surface clipping with different operators", + "clip", /* keywords */ + NULL, /* requirements */ + IMAGE_WIDTH, IMAGE_HEIGHT, + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/clip-polygons.c b/local/recipes/libs/cairo/source/test/clip-polygons.c new file mode 100644 index 0000000000..83eb4df3a6 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clip-polygons.c @@ -0,0 +1,112 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +#define STEP 5 +#define WIDTH 100 +#define HEIGHT 100 + +static void diamond (cairo_t *cr) +{ + cairo_move_to (cr, WIDTH/2, 0); + cairo_line_to (cr, WIDTH, HEIGHT/2); + cairo_line_to (cr, WIDTH/2, HEIGHT); + cairo_line_to (cr, 0, HEIGHT/2); + cairo_close_path (cr); +} + +static void background (cairo_t *cr) +{ + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgb (cr, 1,1,1); + cairo_paint (cr); + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_set_source_rgb (cr, 0,0,0); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + background (cr); + + /* completely overlapping diamonds */ + cairo_save (cr); + diamond (cr); + cairo_clip (cr); + diamond (cr); + cairo_clip (cr); + cairo_paint (cr); + cairo_restore (cr); + + cairo_translate (cr, WIDTH, 0); + + /* partial overlap */ + cairo_save (cr); + cairo_translate (cr, -WIDTH/4, 0); + diamond (cr); + cairo_clip (cr); + cairo_translate (cr, WIDTH/2, 0); + diamond (cr); + cairo_clip (cr); + cairo_paint (cr); + cairo_restore (cr); + + cairo_translate (cr, WIDTH, 0); + + /* no overlap, but the bounding boxes must */ + cairo_save (cr); + cairo_translate (cr, -WIDTH/2 + 2, -2); + diamond (cr); + cairo_clip (cr); + cairo_translate (cr, WIDTH - 4, 4); + diamond (cr); + cairo_clip (cr); + cairo_paint (cr); + cairo_restore (cr); + + cairo_translate (cr, WIDTH, 0); + + /* completely disjoint */ + cairo_save (cr); + cairo_translate (cr, -WIDTH/2 - 1, 0); + diamond (cr); + cairo_clip (cr); + cairo_translate (cr, WIDTH + 2, 0); + diamond (cr); + cairo_clip (cr); + cairo_paint (cr); + cairo_restore (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clip_polygons, + "Test drawing through through an intersection of polygons", + "clip", /* keywords */ + "target=raster", /* requirements */ + 4*WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/clip-push-group.c b/local/recipes/libs/cairo/source/test/clip-push-group.c new file mode 100644 index 0000000000..f63ac731db --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clip-push-group.c @@ -0,0 +1,67 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +/* A test for the crash described here: + * + * https://lists.freedesktop.org/archives/cairo/2006-August/007698.html + * + * The triggering condition for this bug should be setting a + * surface-based clip and then calling cairo_push_group. + */ + +#include "cairo-test.h" + +#define SIZE 10 +#define PAD 2 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + /* An overly complex way of drawing a blue circle onto a red + * background, to trigger the bug. */ + cairo_set_source_rgb (cr, 1, 0, 0); /* red */ + cairo_paint (cr); + + cairo_arc (cr, + SIZE / 2, SIZE / 2, + SIZE / 2 - PAD, + 0, 2 * M_PI); + cairo_clip (cr); + + cairo_push_group (cr); + cairo_set_source_rgb (cr, 0, 0, 1); /* blue */ + cairo_paint (cr); + cairo_pop_group_to_source (cr); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clip_push_group, + "Test that push_group doesn't crash after setting a surface-based clip", + "clip", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/clip-rectilinear.c b/local/recipes/libs/cairo/source/test/clip-rectilinear.c new file mode 100644 index 0000000000..98db4a2c77 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clip-rectilinear.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +#define SIZE 120 + +static void L(cairo_t *cr, int w, int h) +{ + cairo_move_to (cr, 0, 0); + cairo_line_to (cr, 0, h); + cairo_line_to (cr, w, h); + cairo_line_to (cr, w, h/2); + cairo_line_to (cr, w/2, h/2); + cairo_line_to (cr, w/2, 0); + cairo_close_path (cr); +} + +static void LL(cairo_t *cr, int w, int h) +{ + cairo_save (cr); + + /* aligned */ + cairo_rectangle (cr, 0, 0, w, h); + cairo_clip (cr); + L (cr, w, h); + cairo_clip (cr); + cairo_paint (cr); + cairo_reset_clip (cr); + + /* unaligned */ + cairo_translate (cr, w+.25, .25); + cairo_rectangle (cr, 0, 0, w, h); + cairo_clip (cr); + L (cr, w, h); + cairo_clip (cr); + cairo_paint (cr); + cairo_reset_clip (cr); + + cairo_restore (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + int w = SIZE/2, h = SIZE/2; + + cairo_paint (cr); /* opaque background */ + + cairo_set_source_rgb (cr, 1, 0, 0); + LL (cr, w, h); + + cairo_translate (cr, 0, h); + cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); + + cairo_set_source_rgb (cr, 0, 0, 1); + LL (cr, w, h); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clip_rectilinear, + "Test handling of rectilinear clipping", + "clip", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/clip-shape.c b/local/recipes/libs/cairo/source/test/clip-shape.c new file mode 100644 index 0000000000..6a74a6ed59 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clip-shape.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2010 Intel Corporation + * + * 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: Chris Wilson + */ + +/* Adapted from a bug report by */ + +#include "cairo-test.h" + +static const struct xy { + double x; + double y; +} gp[] = { + { 100, 250 }, + { 100, 100 }, + { 150, 230 }, + { 239, 100 }, + { 239, 250 }, +}; + +static const double vp[3] = { 100, 144, 238.5 }; + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + int i; + + cairo_paint (cr); /* opaque background */ + + for (i = 0; i < 5; ++i) + cairo_line_to (cr, gp[i].x, gp[i].y); + cairo_close_path (cr); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_set_line_width (cr, 1.5); + cairo_stroke_preserve (cr); + cairo_clip (cr); + + for (i = 1; i < 3; ++i) { + double x1 = vp[i - 1]; + double x2 = vp[i]; + + cairo_move_to (cr, x1, 0); + cairo_line_to (cr, x1, height); + cairo_line_to (cr, x2, height); + cairo_line_to (cr, x2, 0); + cairo_close_path (cr); + + if (i & 1) + cairo_set_source_rgb (cr, 0, 1, 0); + else + cairo_set_source_rgb (cr, 1, 1, 0); + + cairo_fill (cr); + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clip_shape, + "Test handling of clipping with a non-aligned shape", + "clip", /* keywords */ + NULL, /* requirements */ + 400, 300, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/clip-stroke-no-op.c b/local/recipes/libs/cairo/source/test/clip-stroke-no-op.c new file mode 100644 index 0000000000..8eb91719bf --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clip-stroke-no-op.c @@ -0,0 +1,67 @@ +/* + * Copyright 2009 Benjamin Otte + * + * 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: Benjamin Otte + */ + +#include "cairo-test.h" + +#define WIDTH 50 +#define HEIGHT 50 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + /* Neutral gray background */ + cairo_set_source_rgb (cr, 0.5, 0.5, 0.5); + cairo_paint (cr); + + /* remove this clip operation and everything works */ + cairo_rectangle (cr, 10, 10, 30, 30); + cairo_clip (cr); + + /* remove this no-op and everything works */ + cairo_stroke (cr); + + /* make the y coordinates integers and everything works */ + cairo_move_to (cr, 20, 20.101562); + cairo_line_to (cr, 30, 20.101562); + + /* This clip operation should fail to work. But with cairo 1.9, if all the + * 3 cases above happen, the clip will not work and the paint will happen. + */ + cairo_save (cr); { + cairo_set_source_rgba (cr, 1, 0.5, 0.5, 1); + cairo_clip_preserve (cr); + cairo_paint (cr); + } cairo_restore (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clip_stroke_no_op, + "Exercises a bug found by Benjamin Otte whereby a no-op clip is nullified by a stroke", + "clip, stroke", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/clip-stroke.c b/local/recipes/libs/cairo/source/test/clip-stroke.c new file mode 100644 index 0000000000..9714dd0670 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clip-stroke.c @@ -0,0 +1,121 @@ +/* + * Copyright 2009 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +#define WIDTH 40 +#define HEIGHT 40 + +static void +shapes (cairo_t *cr) +{ + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0, 0.7, 0); + cairo_arc (cr, 10, 10, 7.5, 0, 2 * M_PI); + cairo_stroke (cr); + + cairo_set_source_rgb (cr, 0, 0.7, 0.7); + cairo_arc (cr, 10, 10, 25, 0, 2 * M_PI); + cairo_stroke (cr); + cairo_rectangle (cr, -5, -5, 30, 30); + cairo_stroke (cr); + + cairo_set_source_rgb (cr, 0.7, 0.7, 0); + cairo_save (cr); + cairo_translate (cr, 10, 10); + cairo_rotate (cr, M_PI/4); + cairo_translate (cr, -10, -10); + cairo_rectangle (cr, -5, -5, 30, 30); + cairo_stroke (cr); + cairo_restore (cr); + + cairo_set_source_rgb (cr, 0.7, 0.0, 0.7); + cairo_move_to (cr, 15, -10); + cairo_line_to (cr, 30, 10); + cairo_line_to (cr, 15, 30); + cairo_stroke (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_translate (cr, 10, 10); + + /* simple clip */ + cairo_save (cr); + cairo_rectangle (cr, 0, 0, 20, 20); + cairo_clip (cr); + shapes (cr); + cairo_restore (cr); + + cairo_translate (cr, WIDTH, 0); + + /* unaligned clip */ + cairo_save (cr); + cairo_rectangle (cr, 0.5, 0.5, 20, 20); + cairo_clip (cr); + shapes (cr); + cairo_restore (cr); + + cairo_translate (cr, -WIDTH, HEIGHT); + + /* aligned-clip */ + cairo_save (cr); + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + cairo_rectangle (cr, 0, 0, 20, 20); + cairo_rectangle (cr, 3, 3, 10, 10); + cairo_rectangle (cr, 7, 7, 10, 10); + cairo_clip (cr); + shapes (cr); + cairo_restore (cr); + + cairo_translate (cr, WIDTH, 0); + + /* force a clip-mask */ + cairo_save (cr); + cairo_arc (cr, 10, 10, 10, 0, 2 * M_PI); + cairo_new_sub_path (cr); + cairo_arc_negative (cr, 10, 10, 5, 2 * M_PI, 0); + cairo_new_sub_path (cr); + cairo_arc (cr, 10, 10, 2, 0, 2 * M_PI); + cairo_clip (cr); + shapes (cr); + cairo_restore (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clip_stroke, + "Tests stroke through complex clips.", + "clip, stroke", /* keywords */ + NULL, /* requirements */ + 2 * WIDTH, 2* HEIGHT, + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/clip-text.c b/local/recipes/libs/cairo/source/test/clip-text.c new file mode 100644 index 0000000000..ed8e107961 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clip-text.c @@ -0,0 +1,88 @@ +/* + * Copyright 2009 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +#define WIDTH 20 +#define HEIGHT 20 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const char *cairo = "Cairo"; + cairo_text_extents_t extents; + double x0, y0; + + cairo_text_extents (cr, cairo, &extents); + x0 = WIDTH/2. - (extents.width/2. + extents.x_bearing); + y0 = HEIGHT/2. - (extents.height/2. + extents.y_bearing); + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + /* aligned-clip */ + cairo_save (cr); + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + cairo_rectangle (cr, 0, 0, 20, 20); + cairo_rectangle (cr, 3, 3, 10, 10); + cairo_rectangle (cr, 7, 7, 10, 10); + cairo_clip (cr); + + cairo_set_source_rgb (cr, 0.7, 0, 0); + cairo_paint (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + + cairo_move_to (cr, x0, y0); + cairo_show_text (cr, cairo); + cairo_restore (cr); + + cairo_translate (cr, WIDTH, 0); + + /* force a clip-mask */ + cairo_save (cr); + cairo_arc (cr, 10, 10, 10, 0, 2 * M_PI); + cairo_new_sub_path (cr); + cairo_arc_negative (cr, 10, 10, 5, 2 * M_PI, 0); + cairo_new_sub_path (cr); + cairo_arc (cr, 10, 10, 2, 0, 2 * M_PI); + cairo_clip (cr); + + cairo_set_source_rgb (cr, 0, 0, 0.7); + cairo_paint (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + + cairo_move_to (cr, x0, y0); + cairo_show_text (cr, cairo); + cairo_restore (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clip_text, + "Tests drawing text through complex clips.", + "clip, text", /* keywords */ + NULL, /* requirements */ + 2 * WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/clip-twice-rectangle.c b/local/recipes/libs/cairo/source/test/clip-twice-rectangle.c new file mode 100644 index 0000000000..28f16ec84d --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clip-twice-rectangle.c @@ -0,0 +1,70 @@ +/* + * Copyright © 2010 Mozilla Corporation + * Copyright © 2010 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *mask; + cairo_t *cr2; + + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_paint (cr); + + /* clip twice, note that the intersection is smaller then the extents */ + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + cairo_rectangle (cr, 10, 10, 80, 80); + cairo_rectangle (cr, 20, 20, 60, 60); + cairo_clip (cr); + + cairo_rectangle (cr, 0, 40, 40, 30); + cairo_clip (cr); + + /* and exercise the bug found by Jeff Muizelaar */ + mask = cairo_surface_create_similar (cairo_get_target (cr), + CAIRO_CONTENT_ALPHA, + width-20, height-20); + cr2 = cairo_create (mask); + cairo_surface_destroy (mask); + + cairo_set_source_rgba (cr2, 1, 1, 1, 1); + cairo_paint (cr2); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_mask_surface (cr, cairo_get_target (cr2), 0, 0); + cairo_destroy (cr2); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clip_twice_rectangle, + "Tests clipping twice using rectangles", + "clip", /* keywords */ + NULL, /* requirements */ + 100, 100, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/clip-twice.c b/local/recipes/libs/cairo/source/test/clip-twice.c new file mode 100644 index 0000000000..641b55144e --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clip-twice.c @@ -0,0 +1,74 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Kristian Høgsberg + */ + +#include "cairo-test.h" + +#define WIDTH 64 +#define HEIGHT 64 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_new_path (cr); + cairo_arc (cr, WIDTH / 2, HEIGHT / 2, WIDTH / 3, 0, 2 * M_PI); + cairo_clip (cr); + + cairo_new_path (cr); + cairo_move_to (cr, 0, 0); + cairo_line_to (cr, WIDTH / 4, HEIGHT / 2); + cairo_line_to (cr, 0, HEIGHT); + cairo_line_to (cr, WIDTH, HEIGHT); + cairo_line_to (cr, 3 * WIDTH / 4, HEIGHT / 2); + cairo_line_to (cr, WIDTH, 0); + cairo_close_path (cr); + cairo_clip (cr); + + cairo_set_source_rgb (cr, 0, 0, 0.6); + + cairo_new_path (cr); + cairo_move_to (cr, 0, 0); + cairo_line_to (cr, 0, HEIGHT); + cairo_line_to (cr, WIDTH / 2, 3 * HEIGHT / 4); + cairo_line_to (cr, WIDTH, HEIGHT); + cairo_line_to (cr, WIDTH, 0); + cairo_line_to (cr, WIDTH / 2, HEIGHT / 4); + cairo_close_path (cr); + cairo_fill (cr); + + cairo_new_path (cr); + cairo_arc (cr, WIDTH / 2, HEIGHT / 2, WIDTH / 5, 0, 2 * M_PI); + cairo_clip (cr); + cairo_set_source_rgb (cr, 1, 1, 0); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clip_twice, + "Verifies that the clip mask is updated correctly when it constructed by setting the clip path twice.", + "clip", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/clip-unbounded.c b/local/recipes/libs/cairo/source/test/clip-unbounded.c new file mode 100644 index 0000000000..cd1c602232 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clip-unbounded.c @@ -0,0 +1,80 @@ +/* + * Copyright © 2009 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +#define SIZE 10 + +static cairo_surface_t * +create_source (cairo_surface_t *target) +{ + cairo_surface_t *similar; + cairo_t *cr; + + similar = cairo_surface_create_similar (target, + CAIRO_CONTENT_COLOR, SIZE/2, SIZE); + cr = cairo_create (similar); + cairo_surface_destroy (similar); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_paint (cr); + + similar = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + + return similar; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *source; + + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_paint (cr); + + cairo_rectangle (cr, 0, 0, SIZE/2, SIZE); + cairo_clip (cr); + + /* Draw a source rectangle outside the image, the effect should be to + * clear only within the clip region. + */ + source = create_source (cairo_get_target (cr)); + cairo_set_source_surface (cr, source, SIZE/2, 0); + cairo_surface_destroy (source); + + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clip_unbounded, + "Test handling of an unbounded fill outside the clip region", + "clip", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/clip-zero.c b/local/recipes/libs/cairo/source/test/clip-zero.c new file mode 100644 index 0000000000..302b2b1619 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clip-zero.c @@ -0,0 +1,72 @@ +/* + * Copyright © 2007 Mozilla Corporation + * + * 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: Vladimir Vukicevic + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *pat; + cairo_surface_t *surf; + + cairo_new_path (cr); + cairo_rectangle (cr, 0, 0, 0, 0); + cairo_clip (cr); + + cairo_push_group (cr); + + cairo_set_source_rgb (cr, 1, 0, 0); + + cairo_new_path (cr); + cairo_rectangle (cr, -10, 10, 20, 20); + cairo_fill_preserve (cr); + cairo_stroke_preserve (cr); + cairo_paint (cr); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); + cairo_show_text (cr, "ABC"); + + cairo_mask (cr, cairo_get_source (cr)); + + surf = cairo_surface_create_similar (cairo_get_group_target (cr), CAIRO_CONTENT_COLOR_ALPHA, 0, 0); + pat = cairo_pattern_create_for_surface (surf); + cairo_surface_destroy (surf); + + cairo_mask (cr, pat); + cairo_pattern_destroy (pat); + + cairo_pop_group_to_source (cr); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clip_zero, + "Verifies that 0x0 surfaces or clips don't cause problems.", + "clip", /* keywords */ + NULL, /* requirements */ + 0, 0, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/clipped-group.c b/local/recipes/libs/cairo/source/test/clipped-group.c new file mode 100644 index 0000000000..a66f357f8b --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clipped-group.c @@ -0,0 +1,88 @@ +/* + * Copyright © 2008 Mozilla Corporation + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Mozilla Corporation not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Mozilla Corporation makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * MOZILLA CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL MOZILLA CORPORATION BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Jeff Muizelaar + */ + +#include "cairo-test.h" + +#define WIDTH 60 +#define HEIGHT 70 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + /* fill with black so we don't need an rgb test case */ + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + /* setting a scale will ensure that the device offset is transformed */ + cairo_scale (cr, 2.1, 2.8); + cairo_set_source_rgb (cr, 1, .5,.4); + + /* all rectangles should look the same */ + + /* plain rectangle */ + cairo_rectangle (cr, 4, 4, 8, 8); + cairo_fill (cr); + + cairo_translate (cr, 10, 0); + + /* clipped rectangle */ + cairo_save (cr); + cairo_rectangle (cr, 3, 3, 9, 9); + cairo_clip (cr); + cairo_rectangle (cr, 4, 4, 8, 8); + cairo_fill (cr); + cairo_restore (cr); + + cairo_translate (cr, 0, 10); + + /* clipped and grouped rectangle */ + cairo_save (cr); + cairo_rectangle (cr, 3, 3, 9, 9); + cairo_clip (cr); + cairo_push_group (cr); + cairo_rectangle (cr, 4, 4, 8, 8); + cairo_fill (cr); + cairo_pop_group_to_source (cr); + cairo_paint (cr); + cairo_restore (cr); + + cairo_translate (cr, -10, 0); + + /* grouped rectangle */ + cairo_push_group (cr); + cairo_rectangle (cr, 4, 4, 8, 8); + cairo_fill (cr); + cairo_pop_group_to_source (cr); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clipped_group, + "Test that a clipped group ends up in the right place", + "clip", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/clipped-surface.c b/local/recipes/libs/cairo/source/test/clipped-surface.c new file mode 100644 index 0000000000..a10652dc86 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clipped-surface.c @@ -0,0 +1,63 @@ +/* + * Copyright 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +/* + * Michael Natterer (mitch) reported a bad regression with post-1.8 trunk + * with artifacts drawn whilst repainting exposed areas. + */ + +#include "cairo-test.h" + +static const char png_filename[] = "romedalen.png"; + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_surface_t *image; + + image = cairo_test_create_surface_from_png (ctx, png_filename); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_paint (cr); + + cairo_rectangle (cr, 20, 20, 10, 10); + cairo_clip (cr); + + cairo_set_source_surface (cr, image, 10, 10); + cairo_surface_destroy (image); + + cairo_rectangle (cr, 10, 10, 20, 20); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clipped_surface, + "Tests application of a clip to a source surface", + "clip", /* keywords */ + NULL, /* requirements */ + 40, 40, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/clipped-trapezoids-ref.png b/local/recipes/libs/cairo/source/test/clipped-trapezoids-ref.png new file mode 100644 index 0000000000..3fd300c04d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/clipped-trapezoids-ref.png differ diff --git a/local/recipes/libs/cairo/source/test/clipped-trapezoids.c b/local/recipes/libs/cairo/source/test/clipped-trapezoids.c new file mode 100644 index 0000000000..1f96daa8c3 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/clipped-trapezoids.c @@ -0,0 +1,95 @@ +/* + * Copyright 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + double dash[2] = { 8, 4 }; + double radius; + + radius = width; + if (height > radius) + radius = height; + + /* fill the background using a big circle */ + cairo_arc (cr, 0, 0, 4 * radius, 0, 2 * M_PI); + cairo_fill (cr); + + /* a rotated square - overlapping the corners */ + cairo_save (cr); + cairo_save (cr); + cairo_translate (cr, width/2, height/2); + cairo_rotate (cr, M_PI/4); + cairo_scale (cr, M_SQRT2, M_SQRT2); + cairo_rectangle (cr, -width/2, -height/2, width, height); + cairo_restore (cr); + cairo_set_source_rgba (cr, 0, 1, 0, .5); + cairo_set_line_width (cr, radius/2); + cairo_stroke (cr); + cairo_restore (cr); + + /* and put some circles in the corners */ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_new_sub_path (cr); + cairo_arc (cr, 0, 0, radius/4, 0, 2 * M_PI); + cairo_new_sub_path (cr); + cairo_arc (cr, width, 0, radius/4, 0, 2 * M_PI); + cairo_new_sub_path (cr); + cairo_arc (cr, width, height, radius/4, 0, 2 * M_PI); + cairo_new_sub_path (cr); + cairo_arc (cr, 0, height, radius/4, 0, 2 * M_PI); + cairo_fill (cr); + + /* a couple of pixel-aligned lines */ + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_move_to (cr, width/2, -height); + cairo_rel_line_to (cr, 0, 3*height); + cairo_move_to (cr, -width, height/2); + cairo_rel_line_to (cr, 3*width, 0); + cairo_stroke (cr); + + /* a couple of dashed diagonals */ + cairo_save (cr); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_set_dash (cr, dash, 2, 0); + cairo_set_line_width (cr, 4.); + cairo_move_to (cr, -width, -height); + cairo_line_to (cr, width+width, height+height); + cairo_move_to (cr, width+width, -height); + cairo_line_to (cr, -width, height+height); + cairo_stroke (cr); + cairo_restore (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (clipped_trapezoids, + "Tests clipping of trapezoids larger than the surface", + "clip", /* keywords */ + NULL, /* requirements */ + 40, 40, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/close-path-current-point.c b/local/recipes/libs/cairo/source/test/close-path-current-point.c new file mode 100644 index 0000000000..35f8d423bd --- /dev/null +++ b/local/recipes/libs/cairo/source/test/close-path-current-point.c @@ -0,0 +1,95 @@ +/* + * Copyright © 2009 Nis Martensen + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of the copyright holder + * not be used in advertising or publicity pertaining to distribution of + * the software without specific, written prior permission. The + * copyright holder makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without + * express or implied warranty. + * + * THE COPYRIGHT HOLDER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Nis Martensen + */ + +#include "cairo-test.h" + +#define SIZE 20 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + /* We draw in the default black, so paint white first. */ + cairo_save (cr); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_restore (cr); + + /* subpath starts with cairo_move_to */ + cairo_new_sub_path (cr); + cairo_move_to (cr, SIZE, SIZE); + cairo_rel_line_to (cr, SIZE, 0); + cairo_rel_line_to (cr, 0, SIZE); + cairo_close_path (cr); + cairo_rel_line_to (cr, 0.5 * SIZE, SIZE); + + /* subpath starts with cairo_line_to */ + cairo_new_sub_path (cr); + cairo_line_to (cr, SIZE, 3 * SIZE); + cairo_rel_line_to (cr, SIZE, 0); + cairo_rel_line_to (cr, 0, SIZE); + cairo_close_path (cr); + cairo_rel_line_to (cr, 0, SIZE); + + /* subpath starts with cairo_curve_to */ + cairo_new_sub_path (cr); + cairo_curve_to (cr, + SIZE, 5 * SIZE, + 1.5 * SIZE, 6 * SIZE, + 2 * SIZE, 5 * SIZE); + cairo_rel_line_to (cr, 0, SIZE); + cairo_close_path (cr); + cairo_rel_line_to (cr, -0.5 * SIZE, SIZE); + + /* subpath starts with cairo_arc */ + cairo_new_sub_path (cr); + cairo_arc (cr, + 1.5 * SIZE, 7 * SIZE, + 0.5 * SIZE, + M_PI, 2 * M_PI); + cairo_rel_line_to (cr, 0, SIZE); + cairo_close_path (cr); + cairo_rel_line_to (cr, -0.7 * SIZE, 0.7 * SIZE); + + /* subpath starts with cairo_arc_negative */ + cairo_new_sub_path (cr); + cairo_arc_negative (cr, + 1.5 * SIZE, 9 * SIZE, + 0.5 * SIZE, + M_PI, 2 * M_PI); + cairo_rel_line_to (cr, 0, SIZE); + cairo_close_path (cr); + cairo_rel_line_to (cr, -0.8 * SIZE, 0.3 * SIZE); + + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (close_path_current_point, + "Test some corner cases related to cairo path operations and the current point", + "path", /* keywords */ + NULL, /* requirements */ + 3 * SIZE, 11 * SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/close-path.c b/local/recipes/libs/cairo/source/test/close-path.c new file mode 100644 index 0000000000..f1f1230fa0 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/close-path.c @@ -0,0 +1,78 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" +#include + +static cairo_test_draw_function_t draw; + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_path_t *path; + + /* We draw in the default black, so paint white first. */ + cairo_save (cr); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_restore (cr); + + /* This curious approach for drawing a circle (starting with a + * closed arc) exercises a bug in which the "last move point" was + * not being set so the close_path closes to (0,0). */ + cairo_arc (cr, 8, 8, 4, 0, M_PI); + cairo_close_path (cr); + cairo_arc (cr, 8, 8, 4, M_PI, 2 * M_PI); + + cairo_fill (cr); + + cairo_translate (cr, 16, 0); + + /* Here a curve immediately after a close_to will begin from (0,0) + * when the path is obtained with cairo_copy_path_flat. */ + cairo_move_to (cr, 8, 4); + cairo_arc_negative (cr, 8, 8, 4, 3 * M_PI / 2.0, M_PI / 2.0); + cairo_close_path (cr); + cairo_curve_to (cr, + 12, 4, + 12, 12, + 8, 12); + + path = cairo_copy_path_flat (cr); + cairo_new_path (cr); + cairo_append_path (cr, path); + cairo_path_destroy (path); + + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (close_path, + "Test some corner cases related to cairo_close_path", + "path", /* keywords */ + NULL, /* requirements */ + 32, 16, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/compare-results b/local/recipes/libs/cairo/source/test/compare-results new file mode 100755 index 0000000000..97df824780 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/compare-results @@ -0,0 +1,57 @@ +#!/usr/bin/python + +# Print the difference between two results.txt files from cairo tests + +import sys + +old_filename = sys.argv[1] +new_filename = sys.argv[2] + +results = { } + +f = open(old_filename, "r") +for line in f.readlines(): + if 'RESULT:' not in line: + continue + + items = line.split(" ") + testcase = dict(zip(items[0::2], items[1::2])) + + try: + k = "%s.%s.%s" %( + testcase['TEST:'], + testcase['TARGET:'], + testcase.get('FORMAT:', '')) + results[k] = testcase['RESULT:'] + except: + print line + raise + +f = open(new_filename, "r") +for line in f.readlines(): + if 'RESULT:' not in line: + # Not a results line. Skip + continue + + items = line.split(" ") + testcase = dict(zip(items[0::2], items[1::2])) + try: + k = "%s.%s.%s" %( + testcase['TEST:'], + testcase['TARGET:'], + testcase.get('FORMAT:','')) + except: + print line + raise + + if k not in results.keys(): + # New test? Skip + continue + + old_val = results[k].strip() + new_val = testcase['RESULT:'].strip() + if old_val == new_val: + # Test didn't change. Skip + continue + + print("%s -> %s # %s" % (old_val, new_val, k)) diff --git a/local/recipes/libs/cairo/source/test/completion.bash b/local/recipes/libs/cairo/source/test/completion.bash new file mode 100644 index 0000000000..6942ea8672 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/completion.bash @@ -0,0 +1 @@ +complete -W "$(./cairo-test-suite -l)" cairo-test-suite diff --git a/local/recipes/libs/cairo/source/test/composite-integer-translate-over-repeat.c b/local/recipes/libs/cairo/source/test/composite-integer-translate-over-repeat.c new file mode 100644 index 0000000000..d9e00057b0 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/composite-integer-translate-over-repeat.c @@ -0,0 +1,84 @@ +/* + * Copyright © 2007 Mozilla Corporation + * + * 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: Vladimir Vukicevic + */ + +#include "cairo-test.h" +#include +#include + +#define SIZE 100 +#define SIZE2 20 +#define OFFSET 10 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *image; + cairo_pattern_t *pat; + cairo_t *cr2; + + image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, SIZE2, SIZE2); + cr2 = cairo_create (image); + cairo_surface_destroy (image); + + cairo_set_source_rgba (cr2, 1, 0, 0, 1); + cairo_rectangle (cr2, 0, 0, SIZE2/2, SIZE2/2); + cairo_fill (cr2); + cairo_set_source_rgba (cr2, 0, 1, 0, 1); + cairo_rectangle (cr2, SIZE2/2, 0, SIZE2/2, SIZE2/2); + cairo_fill (cr2); + cairo_set_source_rgba (cr2, 0, 0, 1, 1); + cairo_rectangle (cr2, 0, SIZE2/2, SIZE2/2, SIZE2/2); + cairo_fill (cr2); + cairo_set_source_rgba (cr2, 1, 1, 0, 1); + cairo_rectangle (cr2, SIZE2/2, SIZE2/2, SIZE2/2, SIZE2/2); + cairo_fill (cr2); + + pat = cairo_pattern_create_for_surface (cairo_get_target (cr2)); + cairo_destroy (cr2); + + cairo_pattern_set_extend (pat, CAIRO_EXTEND_REPEAT); + + cairo_set_source_rgba (cr, 0, 0, 0, 1); + cairo_rectangle (cr, 0, 0, SIZE, SIZE); + cairo_fill (cr); + + cairo_translate (cr, OFFSET, OFFSET); + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_set_source (cr, pat); + cairo_rectangle (cr, 0, 0, SIZE - OFFSET, SIZE - OFFSET); + cairo_fill (cr); + + cairo_pattern_destroy (pat); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (composite_integer_translate_over_repeat, + "Test simple compositing: integer-translation 32->32 OVER, with repeat", + "composite", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/composite-integer-translate-over.c b/local/recipes/libs/cairo/source/test/composite-integer-translate-over.c new file mode 100644 index 0000000000..1b82a3379b --- /dev/null +++ b/local/recipes/libs/cairo/source/test/composite-integer-translate-over.c @@ -0,0 +1,61 @@ +/* + * Copyright © 2006 Mozilla Corporation + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Mozilla Corporation not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Mozilla Corporation makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * MOZILLA CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL MOZILLA CORPORATION BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Vladimir Vukicevic + */ +#include "cairo-test.h" +#include +#include + +#define SIZE 100 +#define OFFSET 10 +static const char *png_filename = "romedalen.png"; + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_surface_t *image; + + image = cairo_test_create_surface_from_png (ctx, png_filename); + + cairo_set_source_rgba (cr, 0, 0, 0, 1); + cairo_rectangle (cr, 0, 0, SIZE, SIZE); + cairo_fill (cr); + + cairo_translate (cr, OFFSET, OFFSET); + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_set_source_surface (cr, image, 0, 0); + cairo_rectangle (cr, 0, 0, (SIZE-OFFSET), (SIZE-OFFSET)); + cairo_fill (cr); + + cairo_surface_destroy (image); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (composite_integer_translate_over, + "Test simple compositing: integer-translation 32->32 OVER", + "composite", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/composite-integer-translate-source.c b/local/recipes/libs/cairo/source/test/composite-integer-translate-source.c new file mode 100644 index 0000000000..e6fd933667 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/composite-integer-translate-source.c @@ -0,0 +1,64 @@ +/* + * Copyright © 2007 Mozilla Corporation + * + * 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: Vladimir Vukicevic + */ + +#include "cairo-test.h" +#include +#include + +#define SIZE 100 +#define OFFSET 10 + +static const char *png_filename = "romedalen.png"; + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_surface_t *image; + + image = cairo_test_create_surface_from_png (ctx, png_filename); + + cairo_set_source_rgba (cr, 0, 0, 0, 1); + cairo_rectangle (cr, 0, 0, SIZE, SIZE); + cairo_fill (cr); + + cairo_translate (cr, OFFSET, OFFSET); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_surface (cr, image, 0, 0); + cairo_rectangle (cr, 0, 0, SIZE - OFFSET, SIZE - OFFSET); + cairo_fill (cr); + + cairo_surface_destroy (image); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (composite_integer_translate_source, + "Test simple compositing: integer-translation 32->32 SOURCE", + "composite", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/copy-disjoint.c b/local/recipes/libs/cairo/source/test/copy-disjoint.c new file mode 100644 index 0000000000..1ddfd5a91b --- /dev/null +++ b/local/recipes/libs/cairo/source/test/copy-disjoint.c @@ -0,0 +1,87 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +/* The goal is exercise a bug that existed in the xlib backend, where + * it assumed the rectangles generated by rectangular tessallator had + * any sorting guarantees. + */ + +#define WIDTH 300 +#define HEIGHT 300 + +static cairo_surface_t * +create_source (cairo_surface_t *target) +{ + cairo_surface_t *surface; + cairo_t *cr; + + surface = cairo_surface_create_similar (target, + CAIRO_CONTENT_COLOR, + WIDTH, HEIGHT); + cr = cairo_create (surface); + cairo_surface_destroy (surface); + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + surface = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + + return surface; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *white; + int x; + + /* black background */ + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + /* white rectangles */ + white = create_source (cairo_get_target (cr)); + cairo_set_source_surface (cr, white, 0, 0); + cairo_surface_destroy (white); + + /* blit a set of rectangles that the rectangular tessellator + * will not emit sorted. */ + for (x = 0; x < WIDTH - 10; x += 15) + cairo_rectangle (cr, x, x, 10, HEIGHT - 2*x); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (copy_disjoint, + "Tests copying unsorted rectangles.", + "fill", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/copy-path.c b/local/recipes/libs/cairo/source/test/copy-path.c new file mode 100644 index 0000000000..7d7a4f467f --- /dev/null +++ b/local/recipes/libs/cairo/source/test/copy-path.c @@ -0,0 +1,314 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" +#include + +static void +scale_by_two (double *x, double *y) +{ + *x = *x * 2.0; + *y = *y * 2.0; +} + +typedef void (*munge_func_t) (double *x, double *y); + +static void +munge_and_set_path (cairo_t *cr, + cairo_path_t *path, + munge_func_t munge) +{ + int i; + cairo_path_data_t *p; + double x1, y1, x2, y2, x3, y3; + + if (path->status) { + cairo_append_path (cr, path); + return; + } + + for (i=0; i < path->num_data; i += path->data[i].header.length) { + p = &path->data[i]; + switch (p->header.type) { + case CAIRO_PATH_MOVE_TO: + x1 = p[1].point.x; y1 = p[1].point.y; + (munge) (&x1, &y1); + cairo_move_to (cr, x1, y1); + break; + case CAIRO_PATH_LINE_TO: + x1 = p[1].point.x; y1 = p[1].point.y; + (munge) (&x1, &y1); + cairo_line_to (cr, x1, y1); + break; + case CAIRO_PATH_CURVE_TO: + x1 = p[1].point.x; y1 = p[1].point.y; + x2 = p[2].point.x; y2 = p[2].point.y; + x3 = p[3].point.x; y3 = p[3].point.y; + (munge) (&x1, &y1); + (munge) (&x2, &y2); + (munge) (&x3, &y3); + cairo_curve_to (cr, + x1, y1, + x2, y2, + x3, y3); + break; + case CAIRO_PATH_CLOSE_PATH: + cairo_close_path (cr); + break; + } + } +} + +static void +make_path (cairo_t *cr) +{ + cairo_rectangle (cr, 0, 0, 5, 5); + cairo_move_to (cr, 15, 2.5); + cairo_arc (cr, 12.5, 2.5, 2.5, 0, 2 * M_PI); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_path_t *path; + cairo_t *cr_error; + + /* Ensure that calling cairo_copy_path on an in-error cairo_t will + * propagate the error. */ + cr_error = cairo_create (NULL); + path = cairo_copy_path (cr_error); + if (path->status != CAIRO_STATUS_NULL_POINTER) { + cairo_test_log (ctx, + "Error: cairo_copy_path returned status of %s rather than propagating %s\n", + cairo_status_to_string (path->status), + cairo_status_to_string (CAIRO_STATUS_NULL_POINTER)); + cairo_path_destroy (path); + cairo_destroy (cr_error); + return CAIRO_TEST_FAILURE; + } + cairo_path_destroy (path); + + path = cairo_copy_path_flat (cr_error); + if (path->status != CAIRO_STATUS_NULL_POINTER) { + cairo_test_log (ctx, + "Error: cairo_copy_path_flat returned status of %s rather than propagating %s\n", + cairo_status_to_string (path->status), + cairo_status_to_string (CAIRO_STATUS_NULL_POINTER)); + cairo_path_destroy (path); + cairo_destroy (cr_error); + return CAIRO_TEST_FAILURE; + } + cairo_path_destroy (path); + + cairo_destroy (cr_error); + + /* first check that we can copy an empty path */ + cairo_new_path (cr); + path = cairo_copy_path (cr); + if (path->status != CAIRO_STATUS_SUCCESS) { + cairo_status_t status = path->status; + cairo_test_log (ctx, + "Error: cairo_copy_path returned status of %s\n", + cairo_status_to_string (status)); + cairo_path_destroy (path); + return cairo_test_status_from_status (ctx, status); + } + if (path->num_data != 0) { + cairo_test_log (ctx, + "Error: cairo_copy_path did not copy an empty path, returned path contains %d elements\n", + path->num_data); + cairo_path_destroy (path); + return CAIRO_TEST_FAILURE; + } + cairo_append_path (cr, path); + cairo_path_destroy (path); + if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) { + cairo_test_log (ctx, + "Error: cairo_append_path failed with a copy of an empty path, returned status of %s\n", + cairo_status_to_string (cairo_status (cr))); + return cairo_test_status_from_status (ctx, cairo_status (cr)); + } + + /* We draw in the default black, so paint white first. */ + cairo_save (cr); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_restore (cr); + + /* copy path, munge, and fill */ + cairo_translate (cr, 5, 5); + make_path (cr); + path = cairo_copy_path (cr); + + cairo_new_path (cr); + munge_and_set_path (cr, path, scale_by_two); + cairo_path_destroy (path); + cairo_fill (cr); + + /* copy flattened path, munge, and fill */ + cairo_translate (cr, 0, 15); + make_path (cr); + path = cairo_copy_path_flat (cr); + + cairo_new_path (cr); + munge_and_set_path (cr, path, scale_by_two); + cairo_path_destroy (path); + cairo_fill (cr); + + /* append two copies of path, and fill */ + cairo_translate (cr, 0, 15); + cairo_scale (cr, 2.0, 2.0); + make_path (cr); + path = cairo_copy_path (cr); + + cairo_new_path (cr); + cairo_append_path (cr, path); + cairo_translate (cr, 2.5, 2.5); + cairo_append_path (cr, path); + + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + cairo_fill (cr); + + cairo_path_destroy (path); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + cairo_t *cr; + cairo_path_data_t data; + cairo_path_t path; + cairo_surface_t *surface; + cairo_status_t status; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1); + status = cairo_surface_status (surface); + if (status) { + cairo_surface_destroy (surface); + return cairo_test_status_from_status (ctx, status); + } + + /* Test a few error cases for cairo_append_path_data */ +#define CAIRO_CREATE() do {\ + cr = cairo_create (surface); \ + status = cairo_status (cr); \ + if (status) { \ + cairo_destroy (cr); \ + cairo_surface_destroy (surface); \ + return cairo_test_status_from_status (ctx, status); \ + } \ +} while (0) + CAIRO_CREATE (); + cairo_append_path (cr, NULL); + status = cairo_status (cr); + cairo_destroy (cr); + if (status != CAIRO_STATUS_NULL_POINTER) { + cairo_surface_destroy (surface); + return cairo_test_status_from_status (ctx, status); + } + + CAIRO_CREATE (); + path.status = -1; + cairo_append_path (cr, &path); + status = cairo_status (cr); + cairo_destroy (cr); + if (status != CAIRO_STATUS_INVALID_STATUS) { + cairo_surface_destroy (surface); + return cairo_test_status_from_status (ctx, status); + } + + CAIRO_CREATE (); + path.status = CAIRO_STATUS_NO_MEMORY; + cairo_append_path (cr, &path); + status = cairo_status (cr); + cairo_destroy (cr); + if (status != CAIRO_STATUS_NO_MEMORY) { + cairo_surface_destroy (surface); + return cairo_test_status_from_status (ctx, status); + } + + CAIRO_CREATE (); + path.data = NULL; + path.num_data = 0; + path.status = CAIRO_STATUS_SUCCESS; + cairo_append_path (cr, &path); + status = cairo_status (cr); + cairo_destroy (cr); + if (status != CAIRO_STATUS_SUCCESS) { + cairo_surface_destroy (surface); + return cairo_test_status_from_status (ctx, status); + } + + CAIRO_CREATE (); + path.data = NULL; + path.num_data = 1; + path.status = CAIRO_STATUS_SUCCESS; + cairo_append_path (cr, &path); + status = cairo_status (cr); + cairo_destroy (cr); + if (status != CAIRO_STATUS_NULL_POINTER) { + cairo_surface_destroy (surface); + return cairo_test_status_from_status (ctx, status); + } + + CAIRO_CREATE (); + /* Intentionally insert bogus header.length value (otherwise would be 2) */ + data.header.type = CAIRO_PATH_MOVE_TO; + data.header.length = 1; + path.data = &data; + path.num_data = 1; + cairo_append_path (cr, &path); + status = cairo_status (cr); + cairo_destroy (cr); + if (status != CAIRO_STATUS_INVALID_PATH_DATA) { + cairo_surface_destroy (surface); + return cairo_test_status_from_status (ctx, status); + } + + /* And test the degenerate case */ + CAIRO_CREATE (); + path.num_data = 0; + cairo_append_path (cr, &path); + status = cairo_status (cr); + cairo_destroy (cr); + if (status != CAIRO_STATUS_SUCCESS) { + cairo_surface_destroy (surface); + return cairo_test_status_from_status (ctx, status); + } + + cairo_surface_destroy (surface); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (copy_path, + "Tests calls to path_data functions: cairo_copy_path, cairo_copy_path_flat, and cairo_append_path", + "path", /* keywords */ + NULL, /* requirements */ + 45, 53, + preamble, draw) diff --git a/local/recipes/libs/cairo/source/test/coverage.c b/local/recipes/libs/cairo/source/test/coverage.c new file mode 100644 index 0000000000..0749fa22a7 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/coverage.c @@ -0,0 +1,508 @@ +/* + * Copyright 2010 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +/* Test the fidelity of the rasterisation, because Cairo is my favourite + * driver test suite. + */ + +#define GENERATE_REFERENCE 0 + +#define WIDTH 256 +#define HEIGHT 40 + +#include "../src/cairo-fixed-type-private.h" +#define PRECISION (1 << CAIRO_FIXED_FRAC_BITS) + +/* XXX beware multithreading! */ +static uint32_t state; + +static uint32_t +hars_petruska_f54_1_random (void) +{ +#define rol(x,k) ((x << k) | (x >> (32-k))) + return state = (state ^ rol (state, 5) ^ rol (state, 24)) + 0x37798849; +#undef rol +} + +static double +random_offset (int range, int precise, int width) +{ + double x = hars_petruska_f54_1_random() / (double) UINT32_MAX * range / width; + if (precise) + x = floor (x * PRECISION) / PRECISION; + return x; +} + +static cairo_test_status_t +rectangles (cairo_t *cr, int width, int height) +{ + int x, y, channel; + + state = 0x12345678; + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_paint (cr); + +#if GENERATE_REFERENCE + for (x = 0; x < width; x++) { + cairo_set_source_rgba (cr, 1, 1, 1, x * x * 1.0 / (width * width)); + cairo_rectangle (cr, x, 0, 1, height); + cairo_fill (cr); + } +#else + cairo_set_operator (cr, CAIRO_OPERATOR_ADD); + for (channel = 0; channel < 3; channel++) { + switch (channel) { + default: + case 0: cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); break; + case 1: cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); break; + case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break; + } + + for (x = 0; x < width; x++) { + for (y = 0; y < height; y++) { + double dx = random_offset (width - x, TRUE, width); + double dy = random_offset (width - x, TRUE, width); + cairo_rectangle (cr, x + dx, y + dy, x / (double) width, x / (double) width); + } + } + cairo_fill (cr); + } +#endif + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +rhombus (cairo_t *cr, int width, int height) +{ + int x, y; + int internal_size = width / 2; + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_paint (cr); + +#if GENERATE_REFERENCE + for (y = 0; y < internal_size; y++) { + for (x = 0; x < internal_size; x++) { + cairo_set_source_rgba (cr, 1, 1, 1, + x * y / (2. * internal_size * internal_size)); + cairo_rectangle (cr, 2*x, 2*y, 2, 2); + cairo_fill (cr); + } + } +#else + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_set_source_rgb (cr, 1, 1, 1); + + for (y = 0; y < internal_size; y++) { + double yf = y / (double) internal_size; + for (x = 0; x < internal_size; x++) { + double xf = x / (double) internal_size; + + cairo_move_to (cr, + 2*x + 1 - xf, + 2*y + 1); + cairo_line_to (cr, + 2*x + 1, + 2*y + 1 - yf); + cairo_line_to (cr, + 2*x + 1 + xf, + 2*y + 1); + cairo_line_to (cr, + 2*x + 1, + 2*y + 1 + yf); + cairo_close_path (cr); + } + } + + cairo_fill (cr); +#endif + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +intersecting_quads (cairo_t *cr, int width, int height) +{ + int x, y, channel; + + state = 0x12345678; + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_paint (cr); + +#if GENERATE_REFERENCE + for (x = 0; x < width; x++) { + cairo_set_source_rgba (cr, 1, 1, 1, x * x * 0.5 / (width * width)); + cairo_rectangle (cr, x, 0, 1, height); + cairo_fill (cr); + } +#else + cairo_set_operator (cr, CAIRO_OPERATOR_ADD); + for (channel = 0; channel < 3; channel++) { + switch (channel) { + default: + case 0: cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); break; + case 1: cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); break; + case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break; + } + + for (x = 0; x < width; x++) { + double step = x / (double) width; + for (y = 0; y < height; y++) { + double dx = random_offset (width - x, TRUE, width); + double dy = random_offset (width - x, TRUE, width); + cairo_move_to (cr, x + dx, y + dy); + cairo_rel_line_to (cr, step, step); + cairo_rel_line_to (cr, 0, -step); + cairo_rel_line_to (cr, -step, step); + cairo_close_path (cr); + } + } + cairo_fill (cr); + } +#endif + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +intersecting_triangles (cairo_t *cr, int width, int height) +{ + int x, y, channel; + + state = 0x12345678; + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_paint (cr); + +#if GENERATE_REFERENCE + for (x = 0; x < width; x++) { + cairo_set_source_rgba (cr, 1, 1, 1, x * x * 0.75 / (width * width)); + cairo_rectangle (cr, x, 0, 1, height); + cairo_fill (cr); + } +#else + cairo_set_operator (cr, CAIRO_OPERATOR_ADD); + for (channel = 0; channel < 3; channel++) { + switch (channel) { + default: + case 0: cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); break; + case 1: cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); break; + case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break; + } + + for (x = 0; x < width; x++) { + double step = x / (double) width; + for (y = 0; y < height; y++) { + double dx = random_offset (width - x, TRUE, width); + double dy = random_offset (width - x, TRUE, width); + + /* left */ + cairo_move_to (cr, x + dx, y + dy); + cairo_rel_line_to (cr, 0, step); + cairo_rel_line_to (cr, step, 0); + cairo_close_path (cr); + + /* right, mirrored */ + cairo_move_to (cr, x + dx + step, y + dy + step); + cairo_rel_line_to (cr, 0, -step); + cairo_rel_line_to (cr, -step, step); + cairo_close_path (cr); + } + } + cairo_fill (cr); + } +#endif + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +triangles (cairo_t *cr, int width, int height) +{ + int x, y, channel; + + state = 0x12345678; + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_paint (cr); + +#if GENERATE_REFERENCE + for (x = 0; x < width; x++) { + cairo_set_source_rgba (cr, 1, 1, 1, x * x * 0.5 / (width * width)); + cairo_rectangle (cr, x, 0, 1, height); + cairo_fill (cr); + } +#else + cairo_set_operator (cr, CAIRO_OPERATOR_ADD); + for (channel = 0; channel < 3; channel++) { + switch (channel) { + default: + case 0: cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); break; + case 1: cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); break; + case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break; + } + + for (x = 0; x < width; x++) { + for (y = 0; y < height; y++) { + double dx = random_offset (width - x, TRUE, width); + double dy = random_offset (width - x, TRUE, width); + cairo_move_to (cr, x + dx, y + dy); + cairo_rel_line_to (cr, x / (double) width, 0); + cairo_rel_line_to (cr, 0, x / (double) width); + cairo_close_path (cr); + } + } + cairo_fill (cr); + } +#endif + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +abutting (cairo_t *cr, int width, int height) +{ + int x, y; + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_paint (cr); + + cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.75); + +#if GENERATE_REFERENCE + cairo_paint (cr); +#else + cairo_set_operator (cr, CAIRO_OPERATOR_ADD); + + for (y = 0; y < 16; y++) { + for (x = 0; x < 16; x++) { + double theta = (y * 16 + x) * M_PI / 512; + double cx = 16 * cos (theta) + x * 16; + double cy = 16 * sin (theta) + y * 16; + + cairo_move_to (cr, x * 16, y * 16); + cairo_line_to (cr, cx, cy); + cairo_line_to (cr, (x + 1) * 16, y * 16); + cairo_fill (cr); + + cairo_move_to (cr, (x + 1) * 16, y * 16); + cairo_line_to (cr, cx, cy); + cairo_line_to (cr, (x + 1) * 16, (y + 1) * 16); + cairo_fill (cr); + + cairo_move_to (cr, (x + 1) * 16, (y + 1) * 16); + cairo_line_to (cr, cx, cy); + cairo_line_to (cr, x * 16, (y + 1) * 16); + cairo_fill (cr); + + cairo_move_to (cr, x * 16, (y + 1) * 16); + cairo_line_to (cr, cx, cy); + cairo_line_to (cr, x * 16, y * 16); + cairo_fill (cr); + } + } +#endif + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +column_triangles (cairo_t *cr, int width, int height) +{ + int x, y, i, channel; + + state = 0x12345678; + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_paint (cr); + +#if GENERATE_REFERENCE + for (x = 0; x < width; x++) { + cairo_set_source_rgba (cr, 1, 1, 1, x * 0.5 / width); + cairo_rectangle (cr, x, 0, 1, height); + cairo_fill (cr); + } +#else + cairo_set_operator (cr, CAIRO_OPERATOR_ADD); + for (channel = 0; channel < 3; channel++) { + switch (channel) { + default: + case 0: cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); break; + case 1: cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); break; + case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break; + } + + for (x = 0; x < width; x++) { + double step = x / (double) (2 * width); + for (y = 0; y < height; y++) { + for (i = 0; i < PRECISION; i++) { + double dy = random_offset (width - x, FALSE, width); + + /* + * We want to test some sharing of edges to further + * stress the rasterisers, so instead of using one + * tall triangle, it is split into two, with vertical + * edges on either side that may co-align with their + * neighbours: + * + * s --- . --- + * t | |\ | + * e | | \ | + * p --- .... | 2 * step = x / width + * \ | | + * \| | + * . --- + * |---| + * 1 / PRECISION + * + * Each column contains two triangles of width one quantum and + * total height of (x / width), thus the total area covered by all + * columns in each pixel is .5 * (x / width). + */ + + cairo_move_to (cr, x + i / (double) PRECISION, y + dy); + cairo_rel_line_to (cr, 0, step); + cairo_rel_line_to (cr, 1 / (double) PRECISION, step); + cairo_rel_line_to (cr, 0, -step); + cairo_close_path (cr); + } + cairo_fill (cr); /* do these per-pixel due to the extra volume of edges */ + } + } + } +#endif + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +row_triangles (cairo_t *cr, int width, int height) +{ + int x, y, i, channel; + + state = 0x12345678; + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_paint (cr); + +#if GENERATE_REFERENCE + for (x = 0; x < width; x++) { + cairo_set_source_rgba (cr, 1, 1, 1, x * 0.5 / width); + cairo_rectangle (cr, x, 0, 1, height); + cairo_fill (cr); + } +#else + cairo_set_operator (cr, CAIRO_OPERATOR_ADD); + for (channel = 0; channel < 3; channel++) { + switch (channel) { + default: + case 0: cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); break; + case 1: cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); break; + case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break; + } + + for (x = 0; x < width; x++) { + double step = x / (double) (2 * width); + for (y = 0; y < height; y++) { + for (i = 0; i < PRECISION; i++) { + double dx = random_offset (width - x, FALSE, width); + + /* See column_triangles() for a transposed description + * of this geometry. + */ + + cairo_move_to (cr, x + dx, y + i / (double) PRECISION); + cairo_rel_line_to (cr, step, 0); + cairo_rel_line_to (cr, step, 1 / (double) PRECISION); + cairo_rel_line_to (cr, -step, 0); + cairo_close_path (cr); + } + cairo_fill (cr); /* do these per-pixel due to the extra volume of edges */ + } + } + } +#endif + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (coverage_rectangles, + "Check the fidelity of the rasterisation.", + NULL, /* keywords */ + "target=raster", /* requirements */ + WIDTH, HEIGHT, + NULL, rectangles) + +CAIRO_TEST (coverage_rhombus, + "Check the fidelity of the rasterisation.", + NULL, /* keywords */ + "target=raster", /* requirements */ + 2*WIDTH, 2*WIDTH, + NULL, rhombus) + +CAIRO_TEST (coverage_intersecting_quads, + "Check the fidelity of the rasterisation.", + NULL, /* keywords */ + "target=raster", /* requirements */ + WIDTH, HEIGHT, + NULL, intersecting_quads) + +CAIRO_TEST (coverage_intersecting_triangles, + "Check the fidelity of the rasterisation.", + NULL, /* keywords */ + "target=raster", /* requirements */ + WIDTH, HEIGHT, + NULL, intersecting_triangles) +CAIRO_TEST (coverage_row_triangles, + "Check the fidelity of the rasterisation.", + NULL, /* keywords */ + "target=raster", /* requirements */ + WIDTH, HEIGHT, + NULL, row_triangles) +CAIRO_TEST (coverage_column_triangles, + "Check the fidelity of the rasterisation.", + NULL, /* keywords */ + "target=raster", /* requirements */ + /* Smaller height since this test does not vary by y-coordinate */ + WIDTH, 4, + NULL, column_triangles) +CAIRO_TEST (coverage_triangles, + "Check the fidelity of the rasterisation.", + NULL, /* keywords */ + "target=raster", /* requirements */ + WIDTH, HEIGHT, + NULL, triangles) +CAIRO_TEST (coverage_abutting, + "Check the fidelity of the rasterisation.", + NULL, /* keywords */ + "target=raster", /* requirements */ + 16*16, 16*16, + NULL, abutting) diff --git a/local/recipes/libs/cairo/source/test/create-for-stream.c b/local/recipes/libs/cairo/source/test/create-for-stream.c new file mode 100644 index 0000000000..06f2db2b0a --- /dev/null +++ b/local/recipes/libs/cairo/source/test/create-for-stream.c @@ -0,0 +1,335 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Kristian Høgsberg + */ + +#include "cairo-test.h" + +#include +#include +#include + +#ifndef _WIN32 +#include +#endif + +#if CAIRO_HAS_PS_SURFACE +#include +#endif + +#if CAIRO_HAS_PDF_SURFACE +#include +#endif + +#if CAIRO_HAS_SVG_SURFACE +#include +#endif + +#include "cairo-test.h" + +/* The main test suite doesn't test the *_create_for_stream + * constructors for the PDF, PS and SVG surface, so we do that here. + * We draw to an in-memory buffer using the stream constructor and + * compare the output to the contents of a file written using the + * file constructor. + */ + +#define MAX_OUTPUT_SIZE 4096 + +#define WIDTH_IN_INCHES 3 +#define HEIGHT_IN_INCHES 3 +#define WIDTH_IN_POINTS (WIDTH_IN_INCHES * 72.0) +#define HEIGHT_IN_POINTS (HEIGHT_IN_INCHES * 72.0) + +#define BASENAME "create-for-stream.out" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + /* Just draw a rectangle. */ + + cairo_rectangle (cr, width / 10., height /10., + width - 2 * width / 10., + height - 2 * height /10.); + cairo_fill (cr); + + cairo_show_page (cr); + + return CAIRO_TEST_SUCCESS; +} + +static void +draw_to (cairo_surface_t *surface) +{ + cairo_t *cr; + + cr = cairo_create (surface); + + draw (cr, WIDTH_IN_POINTS, HEIGHT_IN_POINTS); + + cairo_destroy (cr); +} + +typedef struct _write_closure { + const cairo_test_context_t *ctx; + char buffer[MAX_OUTPUT_SIZE]; + size_t index; + cairo_test_status_t status; +} write_closure_t; + +static cairo_status_t +bad_write (void *closure, + const unsigned char *data, + unsigned int length) +{ + return CAIRO_STATUS_WRITE_ERROR; +} + +static cairo_status_t +test_write (void *closure, + const unsigned char *data, + unsigned int length) +{ + write_closure_t *wc = closure; + + if (wc->index + length >= sizeof wc->buffer) { + cairo_test_log (wc->ctx, "Error: out of bounds in write callback\n"); + wc->status = CAIRO_TEST_FAILURE; + return CAIRO_STATUS_SUCCESS; + } + + memcpy (&wc->buffer[wc->index], data, length); + wc->index += length; + + return CAIRO_STATUS_SUCCESS; +} + + +typedef cairo_surface_t * +(*file_constructor_t) (const char *filename, + double width_in_points, + double height_in_points); + +typedef cairo_surface_t * +(*stream_constructor_t) (cairo_write_func_t write_func, + void *closure, + double width_in_points, + double height_in_points); + +static cairo_test_status_t +test_surface (const cairo_test_context_t *ctx, + const char *backend, + const char *filename, + file_constructor_t file_constructor, + stream_constructor_t stream_constructor) +{ + cairo_surface_t *surface; + write_closure_t wc; + char file_contents[MAX_OUTPUT_SIZE]; + cairo_status_t status; + FILE *fp; + + /* test propagation of user errors */ + surface = stream_constructor (bad_write, &wc, + WIDTH_IN_POINTS, HEIGHT_IN_POINTS); + + status = cairo_surface_status (surface); + if (status) { + cairo_test_log (ctx, + "%s: Failed to create surface for stream.\n", + backend); + return CAIRO_TEST_FAILURE; + } + + draw_to (surface); + + cairo_surface_finish (surface); + status = cairo_surface_status (surface); + cairo_surface_destroy (surface); + + if (status != CAIRO_STATUS_WRITE_ERROR) { + cairo_test_log (ctx, + "%s: Error: expected \"write error\" from bad_write(), but received \"%s\".\n", + backend, cairo_status_to_string (status)); + return CAIRO_TEST_FAILURE; + } + + /* test propagation of file errors - for now this is unix-only */ +#ifndef _WIN32 + if (access("/dev/full", W_OK) == 0) { + surface = file_constructor ("/dev/full", WIDTH_IN_POINTS, HEIGHT_IN_POINTS); + cairo_surface_finish (surface); + status = cairo_surface_status (surface); + cairo_surface_destroy (surface); + + if (status != CAIRO_STATUS_WRITE_ERROR) { + cairo_test_log (ctx, + "%s: Error: expected \"write error\" from /dev/full, but received \"%s\".\n", + backend, cairo_status_to_string (status)); + return CAIRO_TEST_FAILURE; + } + } else { + cairo_test_log (ctx, + "/dev/full does not exist; skipping write test.\n"); + } +#endif + + /* construct the real surface */ + wc.ctx = ctx; + wc.status = CAIRO_TEST_SUCCESS; + wc.index = 0; + + surface = stream_constructor (test_write, &wc, + WIDTH_IN_POINTS, HEIGHT_IN_POINTS); + + status = cairo_surface_status (surface); + if (status) { + cairo_test_log (ctx, + "%s: Failed to create surface for stream.\n", backend); + return CAIRO_TEST_FAILURE; + } + + draw_to (surface); + + cairo_surface_destroy (surface); + + if (wc.status != CAIRO_TEST_SUCCESS) { + /* Error already reported. */ + return wc.status; + } + + surface = file_constructor (filename, + WIDTH_IN_POINTS, HEIGHT_IN_POINTS); + + status = cairo_surface_status (surface); + if (status) { + cairo_test_log (ctx, "%s: Failed to create surface for file %s: %s.\n", + backend, filename, cairo_status_to_string (status)); + return CAIRO_TEST_FAILURE; + } + + draw_to (surface); + + cairo_surface_destroy (surface); + + fp = fopen (filename, "r"); + if (fp == NULL) { + cairo_test_log (ctx, "%s: Failed to open %s for reading: %s.\n", + backend, filename, strerror (errno)); + return CAIRO_TEST_FAILURE; + } + + if (fread (file_contents, 1, wc.index, fp) != wc.index) { + cairo_test_log (ctx, "%s: Failed to read %s: %s.\n", + backend, filename, strerror (errno)); + fclose (fp); + return CAIRO_TEST_FAILURE; + } + + if (memcmp (file_contents, wc.buffer, wc.index) != 0) { + cairo_test_log (ctx, "%s: Stream based output differ from file output for %s.\n", + backend, filename); + fclose (fp); + return CAIRO_TEST_FAILURE; + } + + fclose (fp); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + cairo_test_status_t status = CAIRO_TEST_UNTESTED; + cairo_test_status_t test_status; + char *filename; + const char *path = cairo_test_mkdir (CAIRO_TEST_OUTPUT_DIR) ? CAIRO_TEST_OUTPUT_DIR : "."; + +#if CAIRO_HAS_PS_SURFACE + if (cairo_test_is_target_enabled (ctx, "ps2") || + cairo_test_is_target_enabled (ctx, "ps3")) + { + if (status == CAIRO_TEST_UNTESTED) + status = CAIRO_TEST_SUCCESS; + + xasprintf (&filename, "%s/%s", path, BASENAME ".ps"); + test_status = test_surface (ctx, "ps", filename, + cairo_ps_surface_create, + cairo_ps_surface_create_for_stream); + cairo_test_log (ctx, "TEST: %s TARGET: %s RESULT: %s\n", + ctx->test->name, "ps", + test_status ? "FAIL" : "PASS"); + if (status == CAIRO_TEST_SUCCESS) + status = test_status; + free (filename); + } +#endif + +#if CAIRO_HAS_PDF_SURFACE + if (cairo_test_is_target_enabled (ctx, "pdf")) { + if (status == CAIRO_TEST_UNTESTED) + status = CAIRO_TEST_SUCCESS; + + xasprintf (&filename, "%s/%s", path, BASENAME ".pdf"); + test_status = test_surface (ctx, "pdf", filename, + cairo_pdf_surface_create, + cairo_pdf_surface_create_for_stream); + cairo_test_log (ctx, "TEST: %s TARGET: %s RESULT: %s\n", + ctx->test->name, "pdf", + test_status ? "FAIL" : "PASS"); + if (status == CAIRO_TEST_SUCCESS) + status = test_status; + free (filename); + } +#endif + +#if CAIRO_HAS_SVG_SURFACE + if (cairo_test_is_target_enabled (ctx, "svg11") || + cairo_test_is_target_enabled (ctx, "svg12")) + { + if (status == CAIRO_TEST_UNTESTED) + status = CAIRO_TEST_SUCCESS; + + xasprintf (&filename, "%s/%s", path, BASENAME ".svg"); + test_status = test_surface (ctx, "svg", filename, + cairo_svg_surface_create, + cairo_svg_surface_create_for_stream); + cairo_test_log (ctx, "TEST: %s TARGET: %s RESULT: %s\n", + ctx->test->name, "svg", + test_status ? "FAIL" : "PASS"); + if (status == CAIRO_TEST_SUCCESS) + status = test_status; + free (filename); + } +#endif + + return status; +} + +CAIRO_TEST (create_for_stream, + "Checks creating vector surfaces with user defined I/O\n", + "stream", /* keywords */ + "target=vector", /* requirements */ + 0, 0, + preamble, NULL) diff --git a/local/recipes/libs/cairo/source/test/create-from-broken-png-stream.c b/local/recipes/libs/cairo/source/test/create-from-broken-png-stream.c new file mode 100644 index 0000000000..88cce0affc --- /dev/null +++ b/local/recipes/libs/cairo/source/test/create-from-broken-png-stream.c @@ -0,0 +1,84 @@ +/* + * Copyright © 2017 Uli Schlachter + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Uli Schlachter + */ + +#include "cairo-test.h" + +#include + +static const unsigned char broken_png_data[] = { + 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, + 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, + 0x08, 0x02, 0x00, 0x00, 0x00, 0xfd, 0xd4, 0x9a, 0xff, 0x00, 0x00, 0x00, +}; +static const size_t broken_png_data_length + = sizeof(broken_png_data) / sizeof(broken_png_data[0]); + +static cairo_status_t +read_png_from_data (void *closure, unsigned char *data, unsigned int length) +{ + size_t *offset = closure; + size_t remaining = broken_png_data_length - *offset; + + if (remaining < length) + return CAIRO_STATUS_READ_ERROR; + + memcpy (data, &broken_png_data[*offset], length); + *offset += length; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + cairo_surface_t *surface; + cairo_status_t status; + cairo_status_t expected; + size_t offset = 0; + + surface = cairo_image_surface_create_from_png_stream (read_png_from_data, + &offset); + + expected = CAIRO_STATUS_PNG_ERROR; + status = cairo_surface_status (surface); + cairo_surface_destroy (surface); + if (status != expected) { + cairo_test_log (ctx, + "Error: expected error %s, but got %s\n", + cairo_status_to_string (expected), + cairo_status_to_string (status)); + + return CAIRO_TEST_FAILURE; + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (create_from_broken_png_stream, + "Tests the creation of a PNG from malformed data", + "png", /* keywords */ + NULL, /* requirements */ + 0, 0, + preamble, NULL) diff --git a/local/recipes/libs/cairo/source/test/create-from-png-16bit.c b/local/recipes/libs/cairo/source/test/create-from-png-16bit.c new file mode 100644 index 0000000000..71c13ecd3c --- /dev/null +++ b/local/recipes/libs/cairo/source/test/create-from-png-16bit.c @@ -0,0 +1,80 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2021 Manuel Stoeckl + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl Worth + * Author: Manuel Stoeckl + */ + +#include "cairo-test.h" + +#include + +#define WIDTH 2 +#define HEIGHT 2 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + char *filename; + cairo_surface_t *surface; + + xasprintf (&filename, "%s/reference/%s", + ctx->srcdir, "create-from-png-16bit.base.png"); + + surface = cairo_image_surface_create_from_png (filename); + if (cairo_surface_status (surface)) { + cairo_test_status_t result; + + result = cairo_test_status_from_status (ctx, + cairo_surface_status (surface)); + if (result == CAIRO_TEST_FAILURE) { + cairo_test_log (ctx, "Error reading PNG image %s: %s\n", + filename, + cairo_status_to_string (cairo_surface_status (surface))); + } + + free (filename); + return result; + } + + /* Pretend we modify the surface data (which detaches the PNG mime data) */ + cairo_surface_flush (surface); + cairo_surface_mark_dirty (surface); + + cairo_set_source_surface (cr, surface, 0, 0); + cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); + cairo_paint (cr); + + cairo_surface_destroy (surface); + + free (filename); + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (create_from_png_16bit, + "Tests the creation of an image surface from a 16 bit PNG file", + "png", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/create-from-png-stream.c b/local/recipes/libs/cairo/source/test/create-from-png-stream.c new file mode 100644 index 0000000000..2e9eeeeacf --- /dev/null +++ b/local/recipes/libs/cairo/source/test/create-from-png-stream.c @@ -0,0 +1,119 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl Worth + */ + +#include "cairo-test.h" + +#include +#include +#include + +#define WIDTH 2 +#define HEIGHT 2 + +static cairo_status_t +read_png_from_file (void *closure, unsigned char *data, unsigned int length) +{ + FILE *file = closure; + size_t bytes_read; + + bytes_read = fread (data, 1, length, file); + if (bytes_read != length) + return CAIRO_STATUS_READ_ERROR; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + char *filename; + FILE *file; + cairo_surface_t *surface; + cairo_status_t status; + + xasprintf (&filename, "%s/reference/%s", ctx->srcdir, + "create-from-png-stream.ref.png"); + + file = fopen (filename, "rb"); + if (file == NULL) { + cairo_test_status_t ret; + + ret = CAIRO_TEST_FAILURE; + if (errno == ENOMEM) + ret = cairo_test_status_from_status (ctx, CAIRO_STATUS_NO_MEMORY); + + if (ret != CAIRO_TEST_NO_MEMORY) + cairo_test_log (ctx, "Error: failed to open file: %s\n", filename); + + free (filename); + return ret; + } + + surface = cairo_image_surface_create_from_png_stream (read_png_from_file, + file); + + fclose (file); + + status = cairo_surface_status (surface); + if (status) { + cairo_test_status_t ret; + + cairo_surface_destroy (surface); + + ret = cairo_test_status_from_status (ctx, status); + if (ret != CAIRO_TEST_NO_MEMORY) { + cairo_test_log (ctx, + "Error: failed to create surface from PNG: %s - %s\n", + filename, + cairo_status_to_string (status)); + } + + free (filename); + + return ret; + } + + free (filename); + + /* Pretend we modify the surface data (which detaches the PNG mime data) */ + cairo_surface_flush (surface); + cairo_surface_mark_dirty (surface); + + cairo_set_source_surface (cr, surface, 0, 0); + cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); + cairo_paint (cr); + + cairo_surface_destroy (surface); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (create_from_png_stream, + "Tests the creation of an image surface from a PNG using a FILE *", + "png", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/create-from-png.c b/local/recipes/libs/cairo/source/test/create-from-png.c new file mode 100644 index 0000000000..2ca1fa2c05 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/create-from-png.c @@ -0,0 +1,320 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl Worth + */ + +#include "cairo-test.h" + +#include + +#define WIDTH 2 +#define HEIGHT 2 + +static cairo_status_t +no_memory_error (void *closure, unsigned char *data, unsigned int size) +{ + return CAIRO_STATUS_NO_MEMORY; +} + +static cairo_status_t +read_error (void *closure, unsigned char *data, unsigned int size) +{ + return CAIRO_STATUS_READ_ERROR; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + char *filename; + cairo_surface_t *surface; + + xasprintf (&filename, "%s/reference/%s", + ctx->srcdir, "create-from-png.ref.png"); + + surface = cairo_image_surface_create_from_png (filename); + if (cairo_surface_status (surface)) { + cairo_test_status_t result; + + result = cairo_test_status_from_status (ctx, + cairo_surface_status (surface)); + if (result == CAIRO_TEST_FAILURE) { + cairo_test_log (ctx, "Error reading PNG image %s: %s\n", + filename, + cairo_status_to_string (cairo_surface_status (surface))); + } + + free (filename); + return result; + } + + /* Pretend we modify the surface data (which detaches the PNG mime data) */ + cairo_surface_flush (surface); + cairo_surface_mark_dirty (surface); + + cairo_set_source_surface (cr, surface, 0, 0); + cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); + cairo_paint (cr); + + cairo_surface_destroy (surface); + + free (filename); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + char *filename; + char *path; + cairo_surface_t *surface; + cairo_status_t status; + cairo_test_status_t result = CAIRO_TEST_SUCCESS; + + surface = cairo_image_surface_create_from_png ("___THIS_FILE_DOES_NOT_EXIST___"); + if (cairo_surface_status (surface) != CAIRO_STATUS_FILE_NOT_FOUND) { + result = cairo_test_status_from_status (ctx, + cairo_surface_status (surface)); + if (result == CAIRO_TEST_FAILURE) { + cairo_test_log (ctx, "Error: expected \"file not found\", but got: %s\n", + cairo_status_to_string (cairo_surface_status (surface))); + } + } + cairo_surface_destroy (surface); + if (result != CAIRO_TEST_SUCCESS) + return result; + + surface = cairo_image_surface_create_from_png_stream (no_memory_error, NULL); + if (cairo_surface_status (surface) != CAIRO_STATUS_NO_MEMORY) { + result = cairo_test_status_from_status (ctx, + cairo_surface_status (surface)); + if (result == CAIRO_TEST_FAILURE) { + cairo_test_log (ctx, "Error: expected \"out of memory\", but got: %s\n", + cairo_status_to_string (cairo_surface_status (surface))); + } + } + cairo_surface_destroy (surface); + if (result != CAIRO_TEST_SUCCESS) + return result; + + surface = cairo_image_surface_create_from_png_stream (read_error, NULL); + if (cairo_surface_status (surface) != CAIRO_STATUS_READ_ERROR) { + result = cairo_test_status_from_status (ctx, + cairo_surface_status (surface)); + if (result == CAIRO_TEST_FAILURE) { + cairo_test_log (ctx, "Error: expected \"read error\", but got: %s\n", + cairo_status_to_string (cairo_surface_status (surface))); + } + } + cairo_surface_destroy (surface); + if (result != CAIRO_TEST_SUCCESS) + return result; + + /* cheekily test error propagation from the user write funcs as well ... */ + xasprintf (&path, "%s/reference", ctx->srcdir); + xasprintf (&filename, "%s/%s", path, "create-from-png.ref.png"); + + surface = cairo_image_surface_create_from_png (filename); + if (cairo_surface_status (surface)) { + result = cairo_test_status_from_status (ctx, + cairo_surface_status (surface)); + if (result == CAIRO_TEST_FAILURE) { + cairo_test_log (ctx, "Error reading PNG image %s: %s\n", + filename, + cairo_status_to_string (cairo_surface_status (surface))); + } + } else { + status = cairo_surface_write_to_png_stream (surface, + (cairo_write_func_t) no_memory_error, + NULL); + if (status != CAIRO_STATUS_NO_MEMORY) { + result = cairo_test_status_from_status (ctx, status); + if (result == CAIRO_TEST_FAILURE) { + cairo_test_log (ctx, "Error: expected \"out of memory\", but got: %s\n", + cairo_status_to_string (status)); + } + } + + status = cairo_surface_write_to_png_stream (surface, + (cairo_write_func_t) read_error, + NULL); + if (status != CAIRO_STATUS_READ_ERROR) { + result = cairo_test_status_from_status (ctx, status); + if (result == CAIRO_TEST_FAILURE) { + cairo_test_log (ctx, "Error: expected \"read error\", but got: %s\n", + cairo_status_to_string (status)); + } + } + + /* and check that error has not propagated to the surface */ + if (cairo_surface_status (surface)) { + result = cairo_test_status_from_status (ctx, + cairo_surface_status (surface)); + if (result == CAIRO_TEST_FAILURE) { + cairo_test_log (ctx, "Error: user write error propagated to surface: %s", + cairo_status_to_string (cairo_surface_status (surface))); + } + } + } + cairo_surface_destroy (surface); + free (filename); + if (result != CAIRO_TEST_SUCCESS) + return result; + + /* check that loading alpha/opaque PNGs generate the correct surfaces */ + /* TODO: Avoid using target-specific references as sample images */ + xasprintf (&filename, "%s/%s", path, "create-from-png.alpha.ref.png"); + surface = cairo_image_surface_create_from_png (filename); + if (cairo_surface_status (surface)) { + result = cairo_test_status_from_status (ctx, + cairo_surface_status (surface)); + if (result == CAIRO_TEST_FAILURE) { + cairo_test_log (ctx, "Error reading PNG image %s: %s\n", + filename, + cairo_status_to_string (cairo_surface_status (surface))); + } + } else if (cairo_image_surface_get_format (surface) != CAIRO_FORMAT_ARGB32) { + cairo_test_log (ctx, "Error reading PNG image %s: did not create an ARGB32 image\n", + filename); + result = CAIRO_TEST_FAILURE; + } + free (filename); + cairo_surface_destroy (surface); + if (result != CAIRO_TEST_SUCCESS) + return result; + + xasprintf (&filename, "%s/%s", path, "create-from-png.ref.png"); + surface = cairo_image_surface_create_from_png (filename); + if (cairo_surface_status (surface)) { + result = cairo_test_status_from_status (ctx, + cairo_surface_status (surface)); + if (result == CAIRO_TEST_FAILURE) { + cairo_test_log (ctx, "Error reading PNG image %s: %s\n", + filename, + cairo_status_to_string (cairo_surface_status (surface))); + } + } else if (cairo_image_surface_get_format (surface) != CAIRO_FORMAT_RGB24) { + cairo_test_log (ctx, "Error reading PNG image %s: did not create an RGB24 image\n", + filename); + result = CAIRO_TEST_FAILURE; + } + free (filename); + cairo_surface_destroy (surface); + if (result != CAIRO_TEST_SUCCESS) + return result; + + /* check paletted PNGs */ + /* TODO: Avoid using target-specific references as sample images */ + xasprintf (&filename, "%s/%s", path, "create-from-png.indexed-alpha.ref.png"); + surface = cairo_image_surface_create_from_png (filename); + if (cairo_surface_status (surface)) { + result = cairo_test_status_from_status (ctx, + cairo_surface_status (surface)); + if (result == CAIRO_TEST_FAILURE) { + cairo_test_log (ctx, "Error reading PNG image %s: %s\n", + filename, + cairo_status_to_string (cairo_surface_status (surface))); + } + } else if (cairo_image_surface_get_format (surface) != CAIRO_FORMAT_ARGB32) { + cairo_test_log (ctx, "Error reading PNG image %s: did not create an ARGB32 image\n", + filename); + result = CAIRO_TEST_FAILURE; + } + free (filename); + cairo_surface_destroy (surface); + if (result != CAIRO_TEST_SUCCESS) + return result; + + /* TODO: Avoid using target-specific references as sample images */ + xasprintf (&filename, "%s/%s", path, "create-from-png.indexed.ref.png"); + surface = cairo_image_surface_create_from_png (filename); + if (cairo_surface_status (surface)) { + result = cairo_test_status_from_status (ctx, + cairo_surface_status (surface)); + if (result == CAIRO_TEST_FAILURE) { + cairo_test_log (ctx, "Error reading PNG image %s: %s\n", + filename, + cairo_status_to_string (cairo_surface_status (surface))); + } + } else if (cairo_image_surface_get_format (surface) != CAIRO_FORMAT_RGB24) { + cairo_test_log (ctx, "Error reading PNG image %s: did not create an RGB24 image\n", + filename); + result = CAIRO_TEST_FAILURE; + } + free (filename); + cairo_surface_destroy (surface); + if (result != CAIRO_TEST_SUCCESS) + return result; + + /* check grayscale PNGs */ + /* TODO: Avoid using target-specific references as sample images */ + xasprintf (&filename, "%s/%s", path, "create-from-png.gray-alpha.ref.png"); + surface = cairo_image_surface_create_from_png (filename); + if (cairo_surface_status (surface)) { + result = cairo_test_status_from_status (ctx, + cairo_surface_status (surface)); + if (result == CAIRO_TEST_FAILURE) { + cairo_test_log (ctx, "Error reading PNG image %s: %s\n", + filename, + cairo_status_to_string (cairo_surface_status (surface))); + } + } else if (cairo_image_surface_get_format (surface) != CAIRO_FORMAT_ARGB32) { + cairo_test_log (ctx, "Error reading PNG image %s: did not create an ARGB32 image\n", + filename); + result = CAIRO_TEST_FAILURE; + } + free (filename); + cairo_surface_destroy (surface); + if (result != CAIRO_TEST_SUCCESS) + return result; + + /* TODO: Avoid using target-specific references as sample images */ + xasprintf (&filename, "%s/%s", path, "create-from-png.gray.ref.png"); + surface = cairo_image_surface_create_from_png (filename); + if (cairo_surface_status (surface)) { + result = cairo_test_status_from_status (ctx, + cairo_surface_status (surface)); + if (result == CAIRO_TEST_FAILURE) { + cairo_test_log (ctx, "Error reading PNG image %s: %s\n", + filename, + cairo_status_to_string (cairo_surface_status (surface))); + } + } else if (cairo_image_surface_get_format (surface) != CAIRO_FORMAT_RGB24) { + cairo_test_log (ctx, "Error reading PNG image %s: did not create an RGB24 image\n", + filename); + result = CAIRO_TEST_FAILURE; + } + free (filename); + cairo_surface_destroy (surface); + + free (path); + + return result; +} + +CAIRO_TEST (create_from_png, + "Tests the creation of an image surface from a PNG file", + "png", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + preamble, draw) diff --git a/local/recipes/libs/cairo/source/test/create-regions.c b/local/recipes/libs/cairo/source/test/create-regions.c new file mode 100644 index 0000000000..749595a445 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/create-regions.c @@ -0,0 +1,435 @@ +/* + * Copyright © 2023 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 "config.h" + +#include +#include +#include +#include + +#if CAIRO_HAS_PDF_SURFACE && CAIRO_HAS_PS_SURFACE && CAIRO_HAS_SVG_SURFACE + +#include +#include +#include + +#ifdef HAVE_UNISTD_H +#include +#include +#endif + +#include "cairo-test.h" +#include "buffer-diff.h" + +/* This test is to ensure that _cairo_recording_surface_replay_and_create_regions() + * works with a recording surface source re-used for multiple paginated surfaces. + * The prior use of the source with a paginated surface should not affect the region + * analysis on subsequent surfaces. + * + * If test output should only contain fallback images for unsupported + * operations. If the recording surface is incorrectly re-using the + * analysis from a different target, some operations may be missing + * from the ouput (recording surface marked the operation as supported + * when it is not) or some operations may be have fallbacks for + * natively suported opetions (recording surface marked a supported + * operation as unsupprted). + * + * To create ref images, run the test for one target at a time to + * prevent re-use of the recording surface for different targets. + */ + + +#define SIZE 40 +#define PAD 25 +#define PAGE_SIZE (SIZE*3 + PAD*4) + +/* Apply a slight rotation and use a very low fallback resolution to + * ensure fallback images are apparent in the output. */ +#define ROTATE 5 +#define FALLBACK_PPI 18 + +static void +create_recordings (cairo_operator_t op, + cairo_surface_t **recording, + cairo_surface_t **recording_group) +{ + *recording = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL); + cairo_t *cr = cairo_create (*recording); + + cairo_rotate (cr, ROTATE*M_PI/180.0); + + cairo_rectangle (cr, 0, 0, SIZE*3.0/4.0, SIZE*3.0/4.0); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_fill (cr); + + cairo_set_operator (cr, op); + + cairo_rectangle (cr, SIZE/4.0, SIZE/4.0, SIZE*3.0/4.0, SIZE*3.0/4.0); + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_fill (cr); + + cairo_destroy (cr); + + *recording_group = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL); + cr = cairo_create (*recording_group); + + cairo_set_source_surface (cr, *recording, 0, 0); + cairo_paint (cr); + + cairo_destroy (cr); +} + +static void +_xunlink (const cairo_test_context_t *ctx, const char *pathname) +{ + if (unlink (pathname) < 0 && errno != ENOENT) { + cairo_test_log (ctx, "Error: Cannot remove %s: %s\n", + pathname, strerror (errno)); + exit (1); + } +} + +static cairo_bool_t +check_result (cairo_test_context_t *ctx, + const cairo_boilerplate_target_t *target, + const char *test_name, + const char *base_name, + cairo_surface_t *surface) +{ + const char *format; + char *ref_name; + char *png_name; + char *diff_name; + cairo_surface_t *test_image, *ref_image, *diff_image; + buffer_diff_result_t result; + cairo_status_t status; + cairo_bool_t ret; + + if (target->finish_surface != NULL) { + status = target->finish_surface (surface); + if (status) { + cairo_test_log (ctx, "Error: Failed to finish surface: %s\n", + cairo_status_to_string (status)); + cairo_surface_destroy (surface); + return FALSE; + } + } + + xasprintf (&png_name, "%s.out.png", base_name); + xasprintf (&diff_name, "%s.diff.png", base_name); + + test_image = target->get_image_surface (surface, 0, PAGE_SIZE, PAGE_SIZE); + if (cairo_surface_status (test_image)) { + cairo_test_log (ctx, "Error: Failed to extract page: %s\n", + cairo_status_to_string (cairo_surface_status (test_image))); + cairo_surface_destroy (test_image); + free (png_name); + free (diff_name); + return FALSE; + } + + _xunlink (ctx, png_name); + status = cairo_surface_write_to_png (test_image, png_name); + if (status) { + cairo_test_log (ctx, "Error: Failed to write output image: %s\n", + cairo_status_to_string (status)); + cairo_surface_destroy (test_image); + free (png_name); + free (diff_name); + return FALSE; + } + + format = cairo_boilerplate_content_name (target->content); + ref_name = cairo_test_reference_filename (ctx, + base_name, + test_name, + target->name, + target->basename, + format, + CAIRO_TEST_REF_SUFFIX, + CAIRO_TEST_PNG_EXTENSION); + if (ref_name == NULL) { + cairo_test_log (ctx, "Error: Cannot find reference image for %s\n", + base_name); + cairo_surface_destroy (test_image); + free (png_name); + free (diff_name); + return FALSE; + } + + ref_image = cairo_test_get_reference_image (ctx, ref_name, + target->content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED); + if (cairo_surface_status (ref_image)) { + cairo_test_log (ctx, "Error: Cannot open reference image for %s: %s\n", + ref_name, + cairo_status_to_string (cairo_surface_status (ref_image))); + cairo_surface_destroy (ref_image); + cairo_surface_destroy (test_image); + free (png_name); + free (diff_name); + free (ref_name); + return FALSE; + } + + diff_image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + PAGE_SIZE, PAGE_SIZE); + + ret = TRUE; + status = image_diff (ctx, + test_image, ref_image, diff_image, + &result); + _xunlink (ctx, diff_name); + if (status) { + cairo_test_log (ctx, "Error: Failed to compare images: %s\n", + cairo_status_to_string (status)); + ret = FALSE; + } else if (image_diff_is_failure (&result, target->error_tolerance)) + { + ret = FALSE; + + status = cairo_surface_write_to_png (diff_image, diff_name); + if (status) { + cairo_test_log (ctx, "Error: Failed to write differences image: %s\n", + cairo_status_to_string (status)); + } + } + + cairo_surface_destroy (test_image); + cairo_surface_destroy (diff_image); + free (png_name); + free (diff_name); + free (ref_name); + + return ret; +} + +#define TEST_ROWS 2 +#define TEST_COLS 3 + +static void +draw (cairo_t *cr, cairo_surface_t *recordings[TEST_ROWS][TEST_COLS]) +{ + cairo_translate (cr, PAD, PAD); + for (int row = 0; row < TEST_ROWS; row++) { + cairo_save (cr); + for (int col = 0; col < TEST_COLS; col++) { + cairo_save (cr); + cairo_set_source_surface (cr, recordings[row][col], 0, 0); + cairo_paint (cr); + cairo_restore (cr); + cairo_translate (cr, SIZE + PAD, 0); + } + cairo_restore (cr); + cairo_translate (cr, 0, SIZE + PAD); + } +} + +#define NUM_TEST_SURFACES 3 + +typedef struct _test_surface { + const cairo_boilerplate_target_t *target; + cairo_surface_t *surface; + char *base_name; + void *closure; +} test_surface_t; + +static test_surface_t test_surfaces[NUM_TEST_SURFACES]; + +static void +init_test_surfaces() +{ + memset (test_surfaces, 0, sizeof (*test_surfaces)); + test_surfaces[0].surface = cairo_pdf_surface_create_for_stream (NULL, NULL, PAGE_SIZE, PAGE_SIZE); + test_surfaces[1].surface = cairo_ps_surface_create_for_stream (NULL, NULL, PAGE_SIZE, PAGE_SIZE); + test_surfaces[2].surface = cairo_svg_surface_create_for_stream (NULL, NULL, PAGE_SIZE, PAGE_SIZE); +} + +static void +add_test_surface (const cairo_boilerplate_target_t *target, + cairo_surface_t *surface, + char *base_name, + void *closure) +{ + for (int i = 0; i < NUM_TEST_SURFACES; i++) { + if (cairo_surface_get_type (test_surfaces[i].surface) == cairo_surface_get_type (surface)) { + cairo_surface_destroy (test_surfaces[i].surface); + test_surfaces[i].target = target; + test_surfaces[i].surface = surface; + test_surfaces[i].base_name = base_name; + test_surfaces[i].closure = closure; + break; + } + } +} + +static void +destroy_test_surfaces() +{ + for (int i = 0; i < NUM_TEST_SURFACES; i++) { + cairo_surface_destroy (test_surfaces[i].surface); + if (test_surfaces[i].target && test_surfaces[i].target->cleanup) + test_surfaces[i].target->cleanup (test_surfaces[i].closure); + if (test_surfaces[i].base_name) + free (test_surfaces[i].base_name); + } +} + + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + cairo_t *cr; + cairo_test_status_t ret = CAIRO_TEST_UNTESTED; + unsigned int i; + const char *path = cairo_test_mkdir (CAIRO_TEST_OUTPUT_DIR) ? CAIRO_TEST_OUTPUT_DIR : "."; + cairo_surface_t *recordings[TEST_ROWS][TEST_COLS]; + const char *test_name = "create-regions"; + char *base_name; + + /* Each row displays three recordings. One with operations + * supported by all paginated surfaces (OVER), one with operations + * supported by PDF but not PS or SVG surfaces (DIFFERENCE), and + * one with operations supported by SVG but not PDF or PS + * (DEST_XOR). + * + * The recordings for the first row is a single recording. The + * recordings for the second row contains the first row recording + * inside another recording to test the use of cloned recording + * surfaces. + * + * We are looking to see that fallback images are only used for + * unsupported operations. + */ + create_recordings (CAIRO_OPERATOR_OVER, &recordings[0][0], &recordings[1][0]); + create_recordings (CAIRO_OPERATOR_DIFFERENCE, &recordings[0][1], &recordings[1][1]); + create_recordings (CAIRO_OPERATOR_XOR, &recordings[0][2], &recordings[1][2]); + + init_test_surfaces(); + for (i = 0; i < ctx->num_targets; i++) { + const cairo_boilerplate_target_t *target = ctx->targets_to_test[i]; + cairo_surface_t *surface = NULL; + void *closure; + const char *format; + + /* This test only works on surfaces that support fine grained fallbacks */ + if (! (target->expected_type == CAIRO_SURFACE_TYPE_PDF || + target->expected_type == CAIRO_SURFACE_TYPE_PS || + target->expected_type ==CAIRO_SURFACE_TYPE_SVG)) + continue; + + if (! cairo_test_is_target_enabled (ctx, target->name)) + continue; + + if (ret == CAIRO_TEST_UNTESTED) + ret = CAIRO_TEST_SUCCESS; + + format = cairo_boilerplate_content_name (target->content); + base_name = NULL; + xasprintf (&base_name, "%s/%s.%s.%s", + path, test_name, + target->name, + format); + + surface = (target->create_surface) (base_name, + target->content, + PAGE_SIZE, PAGE_SIZE, + PAGE_SIZE, PAGE_SIZE, + CAIRO_BOILERPLATE_MODE_TEST, + &closure); + if (surface == NULL || cairo_surface_status (surface)) { + cairo_test_log (ctx, "Failed to generate surface: %s.%s\n", + target->name, + format); + ret = CAIRO_TEST_FAILURE; + break; + } + + cairo_surface_set_fallback_resolution (surface, FALLBACK_PPI, FALLBACK_PPI); + add_test_surface (target, surface, base_name, closure); + } + + for (int i = 0; i < NUM_TEST_SURFACES; i++) { + cairo_status_t status; + + if (test_surfaces[i].target != NULL) { + cairo_test_log (ctx, + "Testing create-regions with %s target\n", + test_surfaces[i].target->name); + printf ("%s:\t", test_surfaces[i].base_name); + fflush (stdout); + } + + cr = cairo_create (test_surfaces[i].surface); + + draw (cr, recordings); + + status = cairo_status (cr); + cairo_destroy (cr); + cairo_surface_finish (test_surfaces[i].surface); + + if (test_surfaces[i].target) { + cairo_bool_t pass = FALSE; + if (status) { + cairo_test_log (ctx, "Error: Failed to create target surface: %s\n", + cairo_status_to_string (status)); + ret = CAIRO_TEST_FAILURE; + } else { + /* extract the image and compare it to our reference */ + if (! check_result (ctx, test_surfaces[i].target, test_name, test_surfaces[i].base_name, test_surfaces[i].surface)) + ret = CAIRO_TEST_FAILURE; + else + pass = TRUE; + } + + if (pass) { + printf ("PASS\n"); + } else { + printf ("FAIL\n"); + } + fflush (stdout); + } + } + + destroy_test_surfaces(); + + for (int row = 0; row < TEST_ROWS; row++) { + for (int col = 0; col < TEST_COLS; col++) { + cairo_surface_destroy (recordings[row][col]); + } + } + + return ret; +} + +CAIRO_TEST (create_regions, + "Check region analysis when re-used with different surfaces", + "fallback", /* keywords */ + NULL, /* requirements */ + 0, 0, + preamble, NULL) + +#endif /* CAIRO_HAS_PDF_SURFACE && CAIRO_HAS_PS_SURFACE && CAIRO_HAS_SVG_SURFACE */ diff --git a/local/recipes/libs/cairo/source/test/culled-glyphs.c b/local/recipes/libs/cairo/source/test/culled-glyphs.c new file mode 100644 index 0000000000..eaa462b1c2 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/culled-glyphs.c @@ -0,0 +1,62 @@ +/* + * Copyright 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const char *text = +"This needs to be a very long string, wider than the surface, and yet wider." +"Ideally it should overflow the stack buffers, but do you really want to read " +"a message that long. No. So we compromise with around 300 glyphs that is " +"long enough to trigger the conditions as stated in " +"https://lists.cairographics.org/archives/cairo/2008-December/015976.html. " +"Happy now?"; + cairo_text_extents_t extents; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + + cairo_set_font_size (cr, 16); + cairo_text_extents (cr, text, &extents); + cairo_move_to (cr, -extents.width/2, 18); + cairo_show_text (cr, text); + + /* XXX we should exercise cairo_show_text_glyphs() as well, + * and CAIRO_TEXT_CLUSTER_BACKWARDS + */ + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (culled_glyphs, + "Tests culling of glyphs and text clusters", + "glyphs", /* keywords */ + NULL, /* requirements */ + 20, 20, + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/curve-to-as-line-to.c b/local/recipes/libs/cairo/source/test/curve-to-as-line-to.c new file mode 100644 index 0000000000..07eb005f50 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/curve-to-as-line-to.c @@ -0,0 +1,95 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +#define SIZE 30 + +/* At one point, an optimization was proposed for cairo in which a + * curve_to would be optimized as a line_to. The initial (buggy) + * implementation verified that the slopes of several segments of the + * spline's control polygon were identical, but left open the + * possibility of an anti-parallel slope for one segment. + * + * For example, given a spline with collinear control points (A,B,C,D) + * positioned as follows: + * + * C--A--B--D + * + * The code verified identical slopes for AB, CD, and AD. The missing + * check for the BC segment allowed it to be anti-parallel to the + * others as above, and hence invalid to replace this spline with the + * AD line segment. + */ +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + + cairo_set_line_width (cr, 1.0); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_BEVEL); + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */ + + cairo_translate (cr, 0, 1.0); + + /* The CABD spline as described above. We ensure that the spline + * folds over on itself outside the bounds of the image to avoid + * the reference image having the curved portion of that fold, + * (which would just be harder to match in all the backends than + * we really want). */ + cairo_move_to (cr, + 10.5, 0.5); + cairo_curve_to (cr, + 11.5, 0.5, + -25.0, 0.5, + 31.0, 0.5); + + cairo_stroke (cr); + + cairo_translate (cr, 0, 2.0); + + /* A reflected version: DBAC */ + cairo_move_to (cr, + 19.5, 0.5); + + cairo_curve_to (cr, + 18.5, 0.5, + 55.0, 0.5, + -1.0, 0.5); + + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (curve_to_as_line_to, + "Test optimization treating curve_to as line_to", + "path", /* keywords */ + NULL, /* requirements */ + 30, + 5, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/dash-caps-joins.c b/local/recipes/libs/cairo/source/test/dash-caps-joins.c new file mode 100644 index 0000000000..ace27e9b9a --- /dev/null +++ b/local/recipes/libs/cairo/source/test/dash-caps-joins.c @@ -0,0 +1,104 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +/* Test case for bug #4409: + * + * Dashes are missing initial caps + * https://bugs.freedesktop.org/show_bug.cgi?id=4409 + */ + +#include "cairo-test.h" + +#define LINE_WIDTH 10. +#define SIZE (5 * LINE_WIDTH) +#define PAD (2 * LINE_WIDTH) + +static void +make_path (cairo_t *cr) +{ + cairo_move_to (cr, 0., 0.); + cairo_rel_line_to (cr, 0., SIZE); + cairo_rel_line_to (cr, SIZE, 0.); + cairo_close_path (cr); + + cairo_move_to (cr, 2 * LINE_WIDTH, 0.); + cairo_rel_line_to (cr, 3 * LINE_WIDTH, 0.); + cairo_rel_line_to (cr, 0., 3 * LINE_WIDTH); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + double dash[] = {LINE_WIDTH, 1.5 * LINE_WIDTH}; + double dash_offset = -2 * LINE_WIDTH; + int i; + + /* We draw in the default black, so paint white first. */ + cairo_save (cr); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_restore (cr); + + for (i=0; i<2; i++) { + cairo_save (cr); + cairo_set_line_width (cr, LINE_WIDTH); + cairo_set_dash (cr, dash, ARRAY_LENGTH (dash), dash_offset); + + cairo_translate (cr, PAD, PAD); + + make_path (cr); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_BEVEL); + cairo_stroke (cr); + + cairo_translate (cr, SIZE + PAD, 0.); + + make_path (cr); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); + cairo_stroke (cr); + + cairo_translate (cr, SIZE + PAD, 0.); + + make_path (cr); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER); + cairo_stroke (cr); + + cairo_restore (cr); + cairo_translate (cr, 0., SIZE + PAD); + dash_offset = 0; + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (dash_caps_joins, + "Test caps and joins when dashing", + "dash, stroke", /* keywords */ + NULL, /* requirements */ + 3 * (PAD + SIZE) + PAD, + PAD + SIZE + PAD + SIZE + PAD, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/dash-curve.c b/local/recipes/libs/cairo/source/test/dash-curve.c new file mode 100644 index 0000000000..c319980126 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/dash-curve.c @@ -0,0 +1,66 @@ +/* + * Copyright © 2007 Jeff Smith + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Jeff Smith not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Jeff Smith makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * JEFF SMITH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL JEFF SMITH BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Jeff Smith + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + double dashes[2] = {20, 20}; + int a=0, b=0, c=0; + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + for (a=0; a<4; a++) + for (b=0; b<5; b++) + for (c=0; c<5; c++) { + cairo_move_to (cr, ((b*5)+c)*60+10, a*60+10); + cairo_rel_curve_to (cr, + 0, b*10, + 0, b*10, + c*10, b*10); + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_set_line_width (cr, 8); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + cairo_set_dash (cr, dashes, 2, a*10); + cairo_stroke_preserve (cr); + + cairo_set_source_rgb (cr, 0, 0.5, 1); + cairo_set_line_width (cr, 2); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + cairo_set_dash (cr, 0, 0, 0); + cairo_stroke (cr); + } + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (dash_curve, + "Tries to explore the state space of the dashing code along curves", + "dash, stroke", /* keywords */ + NULL, /* requirements */ + 25*60, 4*60, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/dash-infinite-loop.c b/local/recipes/libs/cairo/source/test/dash-infinite-loop.c new file mode 100644 index 0000000000..98ab62fe95 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/dash-infinite-loop.c @@ -0,0 +1,83 @@ +/* + * Copyright © 2009 M Joonas Pihlaja + * + * 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: M Joonas Pihlaja + */ + +#include "cairo-test.h" + +/* When faced with very small dash lengths the stroker is liable to + * get stuck in an infinite loop when advancing the dash offset. This + * test attempts to hit each of the locations in the stroker code + * where the dash offset is advanced in a loop. + * + * Reported to the cairo mailing list by Hans Breuer. + * https://lists.cairographics.org/archives/cairo/2009-June/017506.html + */ + +#define EPS 1e-30 +/* This should be comfortably smaller than the unit epsilon of the + * floating point type used to advance the dashing, yet not small + * enough that it underflows to zero. 1e-30 works to foil up to 80 + * bit extended precision arithmetic. We want to avoid zero dash + * lengths because those trigger special processing in the stroker. */ + +static void +do_dash (cairo_t *cr, double dx, double dy, double offset) +{ + /* Set the dash pattern to be predominantly ON so that we can + * create a reference image by just ignoring the dashing. */ + static double dash[] = { EPS, EPS/512 }; + cairo_set_dash (cr, dash, 2, offset); + cairo_move_to (cr, 10, 10); + cairo_rel_line_to (cr, dx, dy); + cairo_stroke (cr); + cairo_translate (cr, dx, dy); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + (void)width; (void)height; + + cairo_set_source_rgb (cr, 1,1,1); + cairo_paint (cr); + cairo_set_source_rgb (cr, 0,0,0); + + cairo_set_line_width (cr, 10); + + /* The following calls will wedge in various places that try + * to advance the dashing in a loop inside the stroker. */ + do_dash (cr, 30, 30, 0); /* _cairo_stroker_line_to_dashed */ + do_dash (cr, 30, 0, 0); /* _cairo_rectilinear_stroker_line_to_dashed */ + do_dash (cr, 30, 30, 1); /* _cairo_stroker_dash_start */ + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (dash_infinite_loop, + "Test dashing with extremely small dash lengths.", + "dash", + NULL, + 100, 100, + NULL, draw); diff --git a/local/recipes/libs/cairo/source/test/dash-no-dash.c b/local/recipes/libs/cairo/source/test/dash-no-dash.c new file mode 100644 index 0000000000..e03094ad46 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/dash-no-dash.c @@ -0,0 +1,87 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" +#include + +#define PAD 1 +#define LINE_WIDTH 2 +#define HEIGHT (PAD + 4 * (LINE_WIDTH + PAD)) +#define WIDTH 16 + +static void +line (cairo_t *cr) +{ + cairo_move_to (cr, PAD, 0.0); + cairo_line_to (cr, WIDTH - PAD, 0.0); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + double dash = 2.0; + + /* We draw in black, so paint white first. */ + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0, 0, 0); /* black */ + + cairo_translate (cr, 0.0, PAD + LINE_WIDTH / 2); + + /* First draw a solid line... */ + line (cr); + cairo_stroke (cr); + + cairo_translate (cr, 0.0, LINE_WIDTH + PAD); + + /* then a dashed line... */ + cairo_set_dash (cr, &dash, 1, 0.0); + line (cr); + cairo_stroke (cr); + + cairo_translate (cr, 0.0, LINE_WIDTH + PAD); + + /* back to solid... */ + cairo_set_dash (cr, NULL, 0, 0.0); + line (cr); + cairo_stroke (cr); + + cairo_translate (cr, 0.0, LINE_WIDTH + PAD); + + /* and finally, back to dashed. */ + cairo_set_dash (cr, &dash, 1, 0.0); + line (cr); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (dash_no_dash, + "Tests that we can actually turn dashing on and off again", + "dash, stroke", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/dash-offset-negative.c b/local/recipes/libs/cairo/source/test/dash-offset-negative.c new file mode 100644 index 0000000000..8766cc5762 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/dash-offset-negative.c @@ -0,0 +1,100 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Owen Taylor + */ + +#include "cairo-test.h" + +#define IMAGE_WIDTH 19 +#define IMAGE_HEIGHT 19 + +/* Basic test of dashed strokes, including a test for the negative + * dash offset bug: + * + * https://bugs.freedesktop.org/show_bug.cgi?id=2729 + */ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + double dashes[] = { 1 }; + + /* We draw in the default black, so paint white first. */ + cairo_save (cr); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_restore (cr); + + cairo_set_line_width (cr, 2); + + /* Basic 1-1 dash pattern */ + cairo_set_dash (cr, dashes, 1, 0.); + + cairo_move_to (cr, 1, 2); + cairo_line_to (cr, 18, 2); + cairo_stroke (cr); + + /* Adjust path by 0.5. Ideally this would give a constant 50% + * gray, (but does not due to the location of the regular sample + * grid points. */ + cairo_move_to (cr, 1.5, 5); + cairo_line_to (cr, 18., 5); + cairo_stroke (cr); + + /* Offset dash by 0.5, rather than the path */ + cairo_set_dash (cr, dashes, 1, 0.5); + + cairo_move_to (cr, 1, 8); + cairo_line_to (cr, 18, 8); + cairo_stroke (cr); + + /* Now, similar tests with negative dash offsets. */ + + /* Basic 1-1 dash pattern dashing */ + cairo_set_dash (cr, dashes, 1, -4); + + cairo_move_to (cr, 1, 11); + cairo_line_to (cr, 18, 11); + cairo_stroke (cr); + + /* Adjust path by 0.5 */ + cairo_move_to (cr, 1.5, 14); + cairo_line_to (cr, 18., 14); + cairo_stroke (cr); + + /* Offset dash by 0.5 */ + cairo_set_dash (cr, dashes, 1, -3.5); + + cairo_move_to (cr, 1, 17); + cairo_line_to (cr, 18, 17); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (dash_offset_negative, + "Tests cairo_set_dash with a negative offset", + "dash, stroke", /* keywords */ + NULL, /* requirements */ + IMAGE_WIDTH, IMAGE_HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/dash-offset.c b/local/recipes/libs/cairo/source/test/dash-offset.c new file mode 100644 index 0000000000..f4269ee136 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/dash-offset.c @@ -0,0 +1,83 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright 2009 Andrea Canciani + * + * 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: Andrea Canciani + */ + +#include "cairo-test.h" + +/* Lengths of the dashes of the dash patterns */ +static const double dashes[] = { 2, 2, 4, 4 }; +/* Dash offset in userspace units + * They always grow by 2, so the dash pattern is + * should be shifted by the same amount each time */ +static const double frac_offset[] = { 0, 2, 4, 6 }; +/* Dash offset relative to the whole dash pattern + * This corresponds to the non-inverted part only if + * the dash pattern has odd length, so the expected result + * is the same for every int_offset if the pattern has + * even length, and inverted each time (or shifted by half + * period, which is the same) if the pattern has odd length. */ +static const double int_offset[] = { -2, -1, 0, 1, 2 }; + +#define PAD 6 +#define STROKE_LENGTH 32 +#define IMAGE_WIDTH (PAD + (STROKE_LENGTH + PAD) * ARRAY_LENGTH (dashes)) +#define IMAGE_HEIGHT (PAD + PAD * ARRAY_LENGTH (int_offset) + PAD * ARRAY_LENGTH (frac_offset) * ARRAY_LENGTH (int_offset)) + + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + double total; + size_t i, j, k; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_set_line_width (cr, 2); + + total = 0.0; + for (k = 0; k < ARRAY_LENGTH (dashes); ++k) { + total += dashes[k]; + for (i = 0; i < ARRAY_LENGTH (frac_offset); ++i) { + for (j = 0; j < ARRAY_LENGTH (int_offset); ++j) { + cairo_set_dash (cr, dashes, k + 1, frac_offset[i] + total * int_offset[j]); + cairo_move_to (cr, (STROKE_LENGTH + PAD) * k + PAD, PAD * (i + j + ARRAY_LENGTH (frac_offset) * j + 1)); + cairo_line_to (cr, (STROKE_LENGTH + PAD) * (k + 1), PAD * (i + j + ARRAY_LENGTH (frac_offset) * j + 1)); + cairo_stroke (cr); + } + } + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (dash_offset, + "Tests dashes of different length with various offsets", + "stroke, dash", /* keywords */ + NULL, /* requirements */ + IMAGE_WIDTH, IMAGE_HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/dash-scale.c b/local/recipes/libs/cairo/source/test/dash-scale.c new file mode 100644 index 0000000000..fd51702553 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/dash-scale.c @@ -0,0 +1,120 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +#define LINE_WIDTH 8. +#define SIZE (5 * LINE_WIDTH) +#define PAD (2 * LINE_WIDTH) + +static void +make_path (cairo_t *cr) +{ + cairo_move_to (cr, 0., 0.); + cairo_rel_line_to (cr, 0., SIZE); + cairo_rel_line_to (cr, SIZE, 0.); + cairo_close_path (cr); + + cairo_move_to (cr, 2 * LINE_WIDTH, 0.); + cairo_rel_line_to (cr, 3 * LINE_WIDTH, 0.); + cairo_rel_line_to (cr, 0., 3 * LINE_WIDTH); +} + +static void +draw_three_shapes (cairo_t *cr) +{ + cairo_save (cr); + + make_path (cr); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_BEVEL); + cairo_stroke (cr); + + cairo_translate (cr, SIZE + PAD, 0.); + + make_path (cr); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); + cairo_stroke (cr); + + cairo_translate (cr, SIZE + PAD, 0.); + + make_path (cr); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER); + cairo_stroke (cr); + + cairo_restore (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + double dash[] = {1.5 * LINE_WIDTH}; + + /* We draw in the default black, so paint white first. */ + cairo_save (cr); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_restore (cr); + + cairo_translate (cr, PAD, PAD); + + cairo_set_dash (cr, dash, ARRAY_LENGTH (dash), - 2 * LINE_WIDTH); + cairo_set_line_width (cr, LINE_WIDTH); + draw_three_shapes (cr); + + cairo_translate (cr, 0, SIZE + 2 * PAD); + + cairo_save (cr); + { + cairo_set_dash (cr, dash, ARRAY_LENGTH (dash), - 2 * LINE_WIDTH); + cairo_set_line_width (cr, LINE_WIDTH); + cairo_scale (cr, 1, 2); + draw_three_shapes (cr); + } + cairo_restore (cr); + + cairo_translate (cr, 0, 2 * (SIZE + PAD)); + + cairo_save (cr); + { + cairo_scale (cr, 1, 2); + cairo_set_dash (cr, dash, ARRAY_LENGTH (dash), - 2 * LINE_WIDTH); + cairo_set_line_width (cr, LINE_WIDTH); + draw_three_shapes (cr); + } + cairo_restore (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (dash_scale, + "Test interactions of cairo_set_dash and cairo_scale, (in particular with a non-uniformly scaled pen)", + "dash, stroke, transform", /* keywords */ + NULL, /* requirements */ + 3 * (PAD + SIZE) + PAD, + PAD + 5 * SIZE + 2 * (2 * PAD) + PAD, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/dash-state.c b/local/recipes/libs/cairo/source/test/dash-state.c new file mode 100644 index 0000000000..5276aeaa64 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/dash-state.c @@ -0,0 +1,64 @@ +/* + * Copyright © 2007 Jeff Smith + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Jeff Smith not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Jeff Smith makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * JEFF SMITH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL JEFF SMITH BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Jeff Smith + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + double dashes[2] = {20, 20}; + int a=0, b=0, c=0; + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + for (a=0; a<4; a++) + for (b=0; b<5; b++) + for (c=0; c<5; c++) { + cairo_move_to (cr, ((b*5)+c)*60+10, a*60+10); + cairo_rel_line_to (cr, 0, b*10); + cairo_rel_line_to (cr, c*10, 0); + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_set_line_width (cr, 8); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + cairo_set_dash (cr, dashes, 2, a*10); + cairo_stroke_preserve (cr); + + cairo_set_source_rgb (cr, 0, 0.5, 1); + cairo_set_line_width (cr, 2); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + cairo_set_dash (cr, 0, 0, 0); + cairo_stroke (cr); + } + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (dash_state, + "Tries to explore the state space of the dashing code", + "dash, stroke", /* keywords */ + NULL, /* requirements */ + 25*60, 4*60, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/dash-zero-length.c b/local/recipes/libs/cairo/source/test/dash-zero-length.c new file mode 100644 index 0000000000..5ab944bb70 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/dash-zero-length.c @@ -0,0 +1,110 @@ +/* + * Copyright © 2006 Jeff Muizelaar + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Jeff Muizelaar. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Jeff Muizelaar. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * JEFF MUIZELAAR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL JEFF MUIZELAAR BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Jeff Muizelaar + */ + +#include "cairo-test.h" + +#define IMAGE_WIDTH 19 +#define IMAGE_HEIGHT 61 + +/* A test of the two extremes of dashing: a solid line + * and an invisible one. Also test that capping works + * on invisible lines. + */ + +static void +draw_dash (cairo_t *cr, double *dash, int num_dashes) +{ + cairo_set_dash (cr, dash, num_dashes, 0.0); + cairo_move_to (cr, 1, 2); + cairo_line_to (cr, 18, 2); + cairo_stroke (cr); + cairo_translate (cr, 0, 3); +} +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + static double solid_line[] = { 4, 0 }; + static double invisible_line[] = { 0, 4 }; + static double dotted_line[] = { 0, 6 }; + static double zero_1_of_3[] = { 0, 2, 3 }; + static double zero_2_of_3[] = { 1, 0, 3 }; + static double zero_3_of_3[] = { 1, 2, 0 }; + static double zero_1_of_4[] = { 0, 2, 3, 4 }; + static double zero_2_of_4[] = { 1, 0, 3, 4 }; + static double zero_3_of_4[] = { 1, 2, 0, 4 }; + static double zero_4_of_4[] = { 1, 2, 3, 0 }; + static double zero_1_2_of_4[] = { 0, 0, 3, 4 }; + static double zero_1_3_of_4[] = { 0, 2, 0, 4 }; +/* Clearly it would be nice to draw this one as well, but it seems to trigger a bug in ghostscript. */ +#if BUG_FIXED_IN_GHOSTSCRIPT + static double zero_1_4_of_4[] = { 0, 2, 3, 0 }; +#endif + static double zero_2_3_of_4[] = { 1, 0, 0, 4 }; + static double zero_2_4_of_4[] = { 1, 0, 3, 0 }; + static double zero_3_4_of_4[] = { 1, 2, 0, 0 }; + static double zero_1_2_3_of_4[] = { 0, 0, 0, 4 }; + static double zero_1_2_4_of_4[] = { 0, 0, 3, 0 }; + static double zero_1_3_4_of_4[] = { 0, 2, 0, 0 }; + static double zero_2_3_4_of_4[] = { 1, 0, 0, 0 }; + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_set_line_width (cr, 2); + + draw_dash (cr, solid_line, 2); + draw_dash (cr, invisible_line, 2); + + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + draw_dash (cr, dotted_line, 2); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + + draw_dash (cr, zero_1_of_3, 3); + draw_dash (cr, zero_2_of_3, 3); + draw_dash (cr, zero_3_of_3, 3); + draw_dash (cr, zero_1_of_4, 4); + draw_dash (cr, zero_2_of_4, 4); + draw_dash (cr, zero_3_of_4, 4); + draw_dash (cr, zero_4_of_4, 4); + draw_dash (cr, zero_1_2_of_4, 4); + draw_dash (cr, zero_1_3_of_4, 4); +#if BUG_FIXED_IN_GHOSTSCRIPT + draw_dash (cr, zero_1_4_of_4, 4); +#endif + draw_dash (cr, zero_2_3_of_4, 4); + draw_dash (cr, zero_2_4_of_4, 4); + draw_dash (cr, zero_3_4_of_4, 4); + draw_dash (cr, zero_1_2_3_of_4, 4); + draw_dash (cr, zero_1_2_4_of_4, 4); + draw_dash (cr, zero_1_3_4_of_4, 4); + draw_dash (cr, zero_2_3_4_of_4, 4); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (dash_zero_length, + "Tests cairo_set_dash with zero length", + "dash, stroke", /* keywords */ + NULL, /* requirements */ + IMAGE_WIDTH, IMAGE_HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/degenerate-arc.c b/local/recipes/libs/cairo/source/test/degenerate-arc.c new file mode 100644 index 0000000000..081bfa5238 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/degenerate-arc.c @@ -0,0 +1,74 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +/* This test case exercises a "Potential division by zero in cairo_arc" + * reported by Luiz Americo Pereira Camara , + * https://lists.cairographics.org/archives/cairo/2008-May/014054.html. + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + int n; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + + cairo_set_line_width (cr, 5); + cairo_set_source_rgb (cr, 0, 1, 0); + for (n = 0; n < 8; n++) { + double theta = n * 2 * M_PI / 8; + cairo_new_sub_path (cr); + cairo_arc (cr, 20, 20, 15, theta, theta); + cairo_close_path (cr); + } + cairo_stroke (cr); + + cairo_set_line_width (cr, 2); + cairo_set_source_rgb (cr, 0, 0, 1); + for (n = 0; n < 8; n++) { + double theta = n * 2 * M_PI / 8; + cairo_move_to (cr, 20, 20); + cairo_arc (cr, 20, 20, 15, theta, theta); + } + cairo_stroke (cr); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_arc (cr, 20, 20, 2, 0, 2*M_PI); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (degenerate_arc, + "Tests the behaviour of degenerate arcs", + "degenerate", /* keywords */ + NULL, /* requirements */ + 40, 40, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/degenerate-arcs.c b/local/recipes/libs/cairo/source/test/degenerate-arcs.c new file mode 100644 index 0000000000..2470828bb7 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/degenerate-arcs.c @@ -0,0 +1,57 @@ +/* + * Copyright 2010 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +#define WIDTH 20 +#define HEIGHT 20 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0.3, 0.4, 0.5); + + /* This should be equivalent to a simple rectangle, such as may be + * constructed for a rounded-rectangle with corner radii of 0... + */ + cairo_arc (cr, 5, 5, 0, M_PI, 3*M_PI/2); + cairo_arc (cr, 15, 5, 0, 3*M_PI/2, 2*M_PI); + cairo_arc (cr, 15, 15, 0, 0, M_PI/2); + cairo_arc (cr, 5, 15, 0, M_PI/2, M_PI); + + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (degenerate_arcs, + "Tests path construction using a series of degenerate (radius=0) arcs", + "arc, fill", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/degenerate-curve-to.c b/local/recipes/libs/cairo/source/test/degenerate-curve-to.c new file mode 100644 index 0000000000..a081a3bb0f --- /dev/null +++ b/local/recipes/libs/cairo/source/test/degenerate-curve-to.c @@ -0,0 +1,103 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2009 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + * Chris Wilson + */ + +#include "cairo-test.h" + +#define SIZE 30 + +/* Another attempt at avoiding unnecessary splines was made, where + * a curve-to that ended on the same point as it began were discarded. + */ +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + + cairo_set_line_width (cr, 1.0); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_BEVEL); + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */ + + /* entirely degenerate */ + cairo_move_to (cr, + 2.5, 2.5); + cairo_curve_to (cr, + 2.5, 2.5, + 2.5, 2.5, + 2.5, 2.5); + cairo_stroke (cr); + + /* horizontal */ + cairo_move_to (cr, + 5.5, 2.5); + cairo_curve_to (cr, + 22.0, 2.5, + -0.5, 2.5, + 5.5, 2.5); + cairo_stroke (cr); + + /* vertical */ + cairo_move_to (cr, + 7.5, 0.0); + cairo_curve_to (cr, + 7.5, 11.0, + 7.5, 0.0, + 7.5, 0.0); + cairo_stroke (cr); + + cairo_translate (cr, 15, 0); + + /* horizontal/vertical */ + cairo_move_to (cr, + 5.5, 0.5); + cairo_curve_to (cr, + -0.5, 0.5, + 5.5, 10.5, + 5.5, 0.5); + + cairo_translate (cr, 10, 0); + + /* vertical/horizontal */ + cairo_move_to (cr, + 5.5, 0.0); + cairo_curve_to (cr, + 5.5, 11.0, + 10.5, 0.0, + 5.5, 0.0); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (degenerate_curve_to, + "Test optimization treating degenerate curve_to as line_to", + "path", /* keywords */ + NULL, /* requirements */ + 40, + 5, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/degenerate-dash.c b/local/recipes/libs/cairo/source/test/degenerate-dash.c new file mode 100644 index 0000000000..56d2e79388 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/degenerate-dash.c @@ -0,0 +1,90 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + * + * Based on an original test case by M Joonas Pihlaja. + */ + +#include "cairo-test.h" + +#define PAD 5 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const double dashes[] = { 25, 25 }; + cairo_line_join_t joins[] = { + CAIRO_LINE_JOIN_ROUND, + CAIRO_LINE_JOIN_MITER, + CAIRO_LINE_JOIN_BEVEL + }; + cairo_line_cap_t caps[] = { + CAIRO_LINE_CAP_ROUND, + CAIRO_LINE_CAP_SQUARE, + CAIRO_LINE_CAP_BUTT, + }; + int i, j; + + cairo_set_source_rgb (cr, 1,1,1); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 1, 0, 0); + + cairo_set_dash (cr, dashes, 2, 0.); + cairo_set_line_width (cr, 10); + + cairo_translate (cr, 5 + PAD, 5 + PAD); + + for (i = 0; i < ARRAY_LENGTH (joins); i++) { + cairo_set_line_join (cr, joins[i]); + cairo_save (cr); + + for (j = 0; j < ARRAY_LENGTH (caps); j++) { + cairo_set_line_cap (cr, caps[j]); + + cairo_move_to (cr, 0, 0); + cairo_line_to (cr, 50, 0); + cairo_line_to (cr, 50,50); + cairo_stroke (cr); + + cairo_translate (cr, 75, 0); + } + cairo_restore (cr); + + cairo_translate (cr, 0, 75); + } + + return CAIRO_TEST_SUCCESS; +} + +/* + * XFAIL: needs path editing in PS to convert degenerate + * end-caps into the shapes as expected by cairo (Or maybe PS is the correct + * behaviour?) + */ +CAIRO_TEST (degenerate_dash, + "Tests the behaviour of dashed segments that end on a off-on transition", + "dash, degenerate", /* keywords */ + NULL, /* requirements */ + 210 + 2*PAD, 210 + 2*PAD, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/degenerate-linear-gradient.c b/local/recipes/libs/cairo/source/test/degenerate-linear-gradient.c new file mode 100644 index 0000000000..0d174fc899 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/degenerate-linear-gradient.c @@ -0,0 +1,81 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright 2010 Andrea Canciani + * + * 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: Andrea Canciani + */ + +#include "cairo-test.h" + +#define NUM_EXTEND 4 +#define HEIGHT 16 +#define WIDTH 16 +#define PAD 3 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *pattern; + unsigned int j; + + cairo_extend_t extend[NUM_EXTEND] = { + CAIRO_EXTEND_NONE, + CAIRO_EXTEND_REPEAT, + CAIRO_EXTEND_REFLECT, + CAIRO_EXTEND_PAD + }; + + cairo_test_paint_checkered (cr); + + pattern = cairo_pattern_create_linear (WIDTH/2, HEIGHT/2, WIDTH/2, HEIGHT/2); + + cairo_pattern_add_color_stop_rgba (pattern, 0, 1, 0, 0, 1); + cairo_pattern_add_color_stop_rgba (pattern, sqrt (1.0 / 2.0), 0, 1, 0, 0); + cairo_pattern_add_color_stop_rgba (pattern, 1, 0, 0, 1, 0.5); + + cairo_translate (cr, PAD, PAD); + + for (j = 0; j < NUM_EXTEND; j++) { + cairo_reset_clip (cr); + cairo_rectangle (cr, 0, 0, WIDTH, HEIGHT); + cairo_clip (cr); + + cairo_pattern_set_extend (pattern, extend[j]); + + cairo_set_source (cr, pattern); + cairo_paint (cr); + + cairo_translate (cr, WIDTH+PAD, 0); + } + + cairo_pattern_destroy (pattern); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (degenerate_linear_gradient, + "Tests degenerate linear gradients", + "linear, pattern, extend", /* keywords */ + NULL, /* requirements */ + (WIDTH+PAD) * NUM_EXTEND + PAD, 1*(HEIGHT + PAD) + PAD, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/degenerate-path.c b/local/recipes/libs/cairo/source/test/degenerate-path.c new file mode 100644 index 0000000000..aa5f8225b1 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/degenerate-path.c @@ -0,0 +1,120 @@ +/* + * Copyright © 2006 Jeff Muizelaar + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Jeff Muizelaar not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Jeff Muizelaar makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * JEFF MUIZELAAR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL JEFF MUIZELAAR BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Jeff Muizelaar + */ + +#include "cairo-test.h" + +#define PAD 3.0 +#define LINE_WIDTH 6.0 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_line_cap_t cap[] = { CAIRO_LINE_CAP_ROUND, CAIRO_LINE_CAP_SQUARE, CAIRO_LINE_CAP_BUTT }; + size_t i; + double dash[] = {2, 2}; + double dash_long[] = {6, 6}; + + cairo_set_source_rgb (cr, 1, 0, 0); + + for (i = 0; i < ARRAY_LENGTH (cap); i++) { + cairo_save (cr); + + cairo_set_line_cap (cr, cap[i]); + + /* simple degenerate paths */ + cairo_set_line_width (cr, LINE_WIDTH); + cairo_move_to (cr, LINE_WIDTH, LINE_WIDTH); + cairo_line_to (cr, LINE_WIDTH, LINE_WIDTH); + cairo_stroke (cr); + + cairo_translate (cr, 0, 3*PAD); + cairo_move_to (cr, LINE_WIDTH, LINE_WIDTH); + cairo_close_path (cr); + cairo_stroke (cr); + + /* degenerate paths starting with dash on */ + cairo_set_dash (cr, dash, 2, 0.); + + cairo_translate (cr, 0, 3*PAD); + cairo_move_to (cr, LINE_WIDTH, LINE_WIDTH); + cairo_line_to (cr, LINE_WIDTH, LINE_WIDTH); + cairo_stroke (cr); + + cairo_translate (cr, 0, 3*PAD); + cairo_move_to (cr, LINE_WIDTH, LINE_WIDTH); + cairo_close_path (cr); + cairo_stroke (cr); + + /* degenerate paths starting with dash off */ + /* these should not draw anything */ + cairo_set_dash (cr, dash, 2, 2.); + + cairo_translate (cr, 0, 3*PAD); + cairo_move_to (cr, LINE_WIDTH, LINE_WIDTH); + cairo_line_to (cr, LINE_WIDTH, LINE_WIDTH); + cairo_stroke (cr); + + cairo_translate (cr, 0, 3*PAD); + cairo_move_to (cr, LINE_WIDTH, LINE_WIDTH); + cairo_close_path (cr); + cairo_stroke (cr); + + /* this should draw a single degenerate sub-path + * at the end of the path */ + cairo_set_dash (cr, dash_long, 2, 6.); + + cairo_translate (cr, 0, 3*PAD); + cairo_move_to (cr, LINE_WIDTH + 6.0, LINE_WIDTH); + cairo_line_to (cr, LINE_WIDTH, LINE_WIDTH); + cairo_stroke (cr); + + /* this should draw a single degenerate sub-path + * at the end of the path. The difference between this + * and the above is that this ends with a degenerate sub-path*/ + cairo_set_dash (cr, dash_long, 2, 6.); + + cairo_translate (cr, 0, 3*PAD); + cairo_move_to (cr, LINE_WIDTH + 6.0, LINE_WIDTH); + cairo_line_to (cr, LINE_WIDTH, LINE_WIDTH); + cairo_line_to (cr, LINE_WIDTH, LINE_WIDTH); + cairo_stroke (cr); + + cairo_restore (cr); + + cairo_translate (cr, PAD+LINE_WIDTH+PAD, 0); + } + return CAIRO_TEST_SUCCESS; +} + +/* + * XFAIL: undefined behaviour in PS, needs path editing to convert degenerate + * segments into circles/rectangles as expected by cairo + */ +CAIRO_TEST (degenerate_path, + "Tests the behaviour of degenerate paths with different cap types", + "degenerate", /* keywords */ + NULL, /* requirements */ + 3*(PAD+LINE_WIDTH+PAD), 8*(LINE_WIDTH+PAD) + PAD, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/degenerate-pen.c b/local/recipes/libs/cairo/source/test/degenerate-pen.c new file mode 100644 index 0000000000..4be0a998fa --- /dev/null +++ b/local/recipes/libs/cairo/source/test/degenerate-pen.c @@ -0,0 +1,105 @@ +/* + * Copyright © 2007 Red Hat, Inc. + * + * 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: Carl D. Worth + */ + +#include "cairo-test.h" + +#define SIZE 20 +#define PAD 5 +#define WIDTH (PAD + 3 * (PAD + SIZE) + PAD) +#define HEIGHT (PAD + SIZE + PAD) + +/* We're demonstrating here a bug originally reported by Benjamin Otte + * on the cairo mailing list here, (after he ran into this problem + * with various flash animations): + * + * [cairo] Assertion `i < pen->num_vertices' failed in 1.4.10 + * https://lists.cairographics.org/archives/cairo/2007-August/011282.html + * + * The problem shows up with an extreme transformation matrix that + * collapses the pen to a single line, (which means that + * _cairo_slope_compare cannot handle adjacent vertices in the pen + * since they have parallel slope). + * + * This test case tests degenerate pens in several directions and uses + * round caps to force the stroking code to attempt to walk around the + * pen doing slope comparisons. + */ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); + + cairo_translate (cr, PAD, PAD); + + /* First compress the pen to a vertical line. */ + cairo_rectangle (cr, 0, 0, SIZE, SIZE); + cairo_curve_to (cr, SIZE / 2, 0, SIZE, SIZE / 2, SIZE, SIZE); + cairo_save (cr); + { + cairo_scale (cr, 0.000001, 1.0); + cairo_stroke (cr); + } + cairo_restore (cr); + + cairo_translate (cr, PAD + SIZE, 0); + + /* Then compress the pen to a horizontal line. */ + cairo_rectangle (cr, 0, 0, SIZE, SIZE); + cairo_curve_to (cr, SIZE / 2, 0, SIZE, SIZE / 2, SIZE, SIZE); + cairo_save (cr); + { + cairo_scale (cr, 1.0, 0.000001); + cairo_stroke (cr); + } + cairo_restore (cr); + + cairo_translate (cr, PAD + SIZE, 0); + + /* Finally a line at an angle. */ + cairo_rectangle (cr, 0, 0, SIZE, SIZE); + cairo_curve_to (cr, SIZE / 2, 0, SIZE, SIZE / 2, SIZE, SIZE); + cairo_save (cr); + { + cairo_rotate (cr, M_PI / 4.0); + cairo_scale (cr, 0.000001, 1.0); + cairo_stroke (cr); + } + cairo_restore (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (degenerate_pen, + "Test round joins with a pen that's transformed to a line", + "degenerate", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/degenerate-radial-gradient.c b/local/recipes/libs/cairo/source/test/degenerate-radial-gradient.c new file mode 100644 index 0000000000..14666450e9 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/degenerate-radial-gradient.c @@ -0,0 +1,93 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright 2010 Andrea Canciani + * + * 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: Andrea Canciani + */ + +#include "cairo-test.h" + +#define NUM_EXTEND 4 +#define HEIGHT 32 +#define WIDTH 32 +#define PAD 6 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *pattern; + unsigned int i, j; + + cairo_extend_t extend[NUM_EXTEND] = { + CAIRO_EXTEND_NONE, + CAIRO_EXTEND_REPEAT, + CAIRO_EXTEND_REFLECT, + CAIRO_EXTEND_PAD + }; + + cairo_test_paint_checkered (cr); + + cairo_translate (cr, PAD, PAD); + + for (i = 0; i < 3; i++) { + cairo_save (cr); + + for (j = 0; j < NUM_EXTEND; j++) { + cairo_reset_clip (cr); + cairo_rectangle (cr, 0, 0, WIDTH, HEIGHT); + cairo_clip (cr); + + if (i == 0) + pattern = cairo_pattern_create_radial (WIDTH/2, HEIGHT/2, 0, WIDTH/2, HEIGHT/2, 0); + else if (i == 1) + pattern = cairo_pattern_create_radial (WIDTH/2, HEIGHT/2, 2*PAD, WIDTH/2, HEIGHT/2, 2*PAD); + else if (i == 2) + pattern = cairo_pattern_create_radial (PAD, PAD, 0, WIDTH-PAD, HEIGHT-PAD, 0); + + cairo_pattern_add_color_stop_rgba (pattern, 0, 1, 0, 0, 1); + cairo_pattern_add_color_stop_rgba (pattern, sqrt (1.0 / 2.0), 0, 1, 0, 0); + cairo_pattern_add_color_stop_rgba (pattern, 1, 0, 0, 1, 0.5); + + cairo_pattern_set_extend (pattern, extend[j]); + + cairo_set_source (cr, pattern); + cairo_paint (cr); + + cairo_pattern_destroy (pattern); + + cairo_translate (cr, WIDTH+PAD, 0); + } + + cairo_restore (cr); + cairo_translate (cr, 0, HEIGHT+PAD); + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (degenerate_radial_gradient, + "Tests degenerate radial gradients", + "radial, pattern, extend", /* keywords */ + NULL, /* requirements */ + (WIDTH+PAD) * NUM_EXTEND + PAD, 3*(HEIGHT + PAD) + PAD, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/degenerate-rel-curve-to.c b/local/recipes/libs/cairo/source/test/degenerate-rel-curve-to.c new file mode 100644 index 0000000000..d7c0523c60 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/degenerate-rel-curve-to.c @@ -0,0 +1,99 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2009 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + * Chris Wilson + */ + +#include "cairo-test.h" + +#define SIZE 30 + +/* Another attempt at avoiding unnecessary splines was made, where + * a curve-to that ended on the same point as it began were discarded. + * The same bug was made to rel-curve-to as well, hence this test. + */ +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + + cairo_set_line_width (cr, 1.0); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_BEVEL); + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */ + + /* entirely degenerate */ + cairo_move_to (cr, 2.5, 2.5); + cairo_rel_curve_to (cr, + 0., 0., + 0., 0., + 0., 0.); + cairo_stroke (cr); + + /* horizontal */ + cairo_move_to (cr, 5.5, 2.5); + cairo_rel_curve_to (cr, + 10., 0., + -10., 0., + 0., 0.); + cairo_stroke (cr); + + /* vertical */ + cairo_move_to (cr, 5.5, 2.5); + cairo_rel_curve_to (cr, + 0., 10., + 0., -10., + 0., 0.); + cairo_stroke (cr); + + cairo_translate (cr, 15, 0); + + /* horizontal/vertical */ + cairo_move_to (cr, 5.5, 0.5); + cairo_rel_curve_to (cr, + -6., 0., + 0., 10., + 0., 0.); + + cairo_translate (cr, 10, 0); + + /* vertical/horizontal */ + cairo_move_to (cr, 5.5, 0.0); + cairo_rel_curve_to (cr, + 0., 11., + 5., 0., + 0., 0.); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (degenerate_rel_curve_to, + "Test optimization treating degenerate rel-curve-to as line-to", + "path", /* keywords */ + NULL, /* requirements */ + 40, + 5, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/degenerate-solid-dash.c b/local/recipes/libs/cairo/source/test/degenerate-solid-dash.c new file mode 100644 index 0000000000..293a808991 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/degenerate-solid-dash.c @@ -0,0 +1,69 @@ +/* + * Copyright © 2012 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const double dashes_1[] = { 10, 0 }; + const double dashes_2[] = { 10, 0, 10, 10}; + const double dashes_3[] = { 10, 0, 10, 0}; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + + cairo_set_line_width (cr, 6); + + cairo_set_dash (cr, NULL, 0, 0); + cairo_rectangle (cr, 10, 10, 30, 30); + cairo_stroke (cr); + + cairo_translate (cr, 50, 0); + cairo_set_dash (cr, dashes_1, 2, 0); + cairo_rectangle (cr, 10, 10, 30, 30); + cairo_stroke (cr); + + cairo_translate (cr, 0, 50); + cairo_set_dash (cr, dashes_2, 4, 0); + cairo_rectangle (cr, 10, 10, 30, 30); + cairo_stroke (cr); + + cairo_translate (cr, -50, 0); + cairo_set_dash (cr, dashes_3, 4, 0); + cairo_rectangle (cr, 10, 10, 30, 30); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (degenerate_solid_dash, + "Exercises degenerate dash ellison", + "stroke, dash", /* keywords */ + NULL, /* requirements */ + 100, 100, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/device-offset-fractional.c b/local/recipes/libs/cairo/source/test/device-offset-fractional.c new file mode 100644 index 0000000000..adc21161fc --- /dev/null +++ b/local/recipes/libs/cairo/source/test/device-offset-fractional.c @@ -0,0 +1,72 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + * Chris Wilson + */ + +#include "cairo-test.h" + +#define SIZE 10 +#define PAD 4 +#define COUNT 4 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface; + cairo_t *cr2; + int i,j; + + /* Fill the background */ + cairo_set_source_rgb (cr, 1, 1, 1); /* white */ + cairo_paint (cr); + + surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, SIZE, SIZE); + cr2 = cairo_create (surface); + cairo_surface_destroy (surface); + + cairo_set_source_rgb (cr2, 0, 0, 1); /* blue */ + cairo_paint (cr2); + + cairo_set_source_surface (cr, cairo_get_target (cr2), 0, 0); + cairo_destroy (cr2); + + for (i = 0; i < COUNT; i++) { + for (j = 0; j < COUNT; j++) { + cairo_surface_set_device_offset (surface, + -i*(SIZE+PAD+.5)-PAD, + -j*(SIZE+PAD+.5)-PAD); + cairo_paint (cr); + } + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (device_offset_fractional, + "Test using image surfaces with fractional device-offsets as sources.", + "device-offset", /* keywords */ + NULL, /* requirements */ + COUNT*(SIZE+PAD+.5)+PAD, COUNT*(SIZE+PAD+.5)+PAD, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/device-offset-positive.c b/local/recipes/libs/cairo/source/test/device-offset-positive.c new file mode 100644 index 0000000000..5afe9730d5 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/device-offset-positive.c @@ -0,0 +1,82 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" +#include + +#define SIZE 10 +#define PAD 2 + +static void +draw_square (cairo_t *cr) +{ + cairo_rectangle (cr, + PAD, PAD, + SIZE - 2 * PAD, + SIZE - 2 * PAD); + cairo_fill (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface, *target; + cairo_t *cr2; + + /* First draw a shape in blue on the original destination. */ + cairo_set_source_rgb (cr, 0, 0, 1); /* blue */ + draw_square (cr); + + /* Then, create an offset surface and repeat the drawing in red. */ + target = cairo_get_group_target (cr); + surface = cairo_surface_create_similar (target, + cairo_surface_get_content (target), + SIZE / 2, SIZE / 2); + cr2 = cairo_create (surface); + cairo_surface_destroy (surface); + + cairo_set_source_rgb (cr2, 1, 0, 0); /* red */ + draw_square (cr2); + + /* Finally, copy the offset surface to the original destination. + * The final result should be a blue square with the upper-left + * quarter red. */ + surface = cairo_surface_reference (cairo_get_target (cr2)); + cairo_destroy (cr2); + cairo_surface_set_device_offset (surface, + SIZE / 2, + SIZE / 2); + cairo_set_source_surface (cr, surface, SIZE / 2, SIZE / 2); + cairo_surface_destroy (surface); + + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (device_offset_positive, + "Simple test using a surface with a positive device-offset as a source.", + "device-offset", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/device-offset-scale.c b/local/recipes/libs/cairo/source/test/device-offset-scale.c new file mode 100644 index 0000000000..33784fa8b2 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/device-offset-scale.c @@ -0,0 +1,77 @@ +/* + * Copyright © 2008 Mozilla Corporation + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Mozilla Corporation not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Mozilla Corporation makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * MOZILLA CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL MOZILLA CORPORATION BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Michael Ventnor, Jeff Muizelaar + */ + +#include "cairo-test.h" + +#define WIDTH 20 +#define HEIGHT 20 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *second; + cairo_t *second_cr; + + /* fill with black so we don't need an rgb test case */ + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + cairo_scale (cr, 0.5, 0.5); + + /* draw the first rectangle */ + cairo_set_source_rgb (cr, 0, 0, 0.4); + cairo_rectangle (cr, 6, 6, 10, 10); + cairo_fill (cr); + + /* adjust the offset so that the second rectangle will fit on the surface */ + second = cairo_image_surface_create (CAIRO_FORMAT_A8, 10, 10); + cairo_surface_set_device_offset (second, -6, -6); + + /* draw the second rectangle: + * this rectangle should end up in the same place as the rectangle above + * independent of the device offset of the surface it is painted on*/ + second_cr = cairo_create (second); + cairo_surface_destroy (second); + cairo_rectangle (second_cr, 6, 6, 10, 10); + cairo_fill (second_cr); + + /* paint the second rectangle on top of the first rectangle */ + cairo_set_source_rgb (cr, 0.5, 0.5, 0); + cairo_mask_surface (cr, cairo_get_target (second_cr), 0, 0); + cairo_destroy (second_cr); + + return CAIRO_TEST_SUCCESS; +} + +/* + * XFAIL: complication of pre-multiplying device_offset into the pattern_matrix + * and then requiring further manipulation for SVG + */ +CAIRO_TEST (device_offset_scale, + "Test that the device-offset transform is transformed by the ctm.", + "device-offset", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/device-offset.c b/local/recipes/libs/cairo/source/test/device-offset.c new file mode 100644 index 0000000000..1bf5283bd4 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/device-offset.c @@ -0,0 +1,82 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" +#include + +#define SIZE 10 +#define PAD 2 + +static void +draw_square (cairo_t *cr) +{ + cairo_rectangle (cr, + PAD, PAD, + SIZE - 2 * PAD, + SIZE - 2 * PAD); + cairo_fill (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface, *target; + cairo_t *cr2; + + /* First draw a shape in blue on the original destination. */ + cairo_set_source_rgb (cr, 0, 0, 1); /* blue */ + draw_square (cr); + + /* Then, create an offset surface and repeat the drawing in red. */ + target = cairo_get_group_target (cr); + surface = cairo_surface_create_similar (target, + cairo_surface_get_content (target), + SIZE / 2, SIZE / 2); + cairo_surface_set_device_offset (surface, - SIZE / 2, - SIZE / 2); + cr2 = cairo_create (surface); + cairo_surface_destroy (surface); + + cairo_set_source_rgb (cr2, 1, 0, 0); /* red */ + draw_square (cr2); + + + /* Finally, copy the offset surface to the original destination. + * The final result should be a blue square with the lower-right + * quarter red. */ + cairo_set_source_surface (cr, cairo_get_target (cr2), 0, 0); + cairo_destroy (cr2); + + cairo_paint (cr); + + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (device_offset, + "Simple test using a surface with a negative device-offset as a source.", + "device-offset", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/dithergradient.c b/local/recipes/libs/cairo/source/test/dithergradient.c new file mode 100644 index 0000000000..1ad1aadc72 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/dithergradient.c @@ -0,0 +1,80 @@ +/* + * Copyright © 2023 Marc Jeanmougin + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Marc Jeanmougin + */ + +#include "cairo-test.h" + +static void +set_dither_source (cairo_t *cr, int width) +{ + cairo_pattern_t *gradient = cairo_pattern_create_linear (0, 0, width, 0); + cairo_pattern_add_color_stop_rgba (gradient, 0., 25./255, 25./255, 25./255, 1.0); + cairo_pattern_add_color_stop_rgba (gradient, 1., 45./255, 45./255, 45./255, 1.0); + + cairo_set_source (cr, gradient); + cairo_pattern_set_dither (gradient, CAIRO_DITHER_BEST); + cairo_pattern_destroy (gradient); +} + +/* History: + * + * 2023: v3 of a patch to use pixman dithering with cairo + */ +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + set_dither_source (cr, width); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +draw2 (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + set_dither_source (cr, width); + + cairo_set_operator (cr, CAIRO_OPERATOR_ADD); + for (int i = 0; i < 5; i++) { + cairo_paint (cr); + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (dithergradient, + "Testing the creation of a dithered gradient (in argb32)", + "gradient, dither", /* keywords */ + NULL, /* requirements */ + 400, 100, + NULL, draw) +CAIRO_TEST (dithergradient2, + "Testing the creation of a dithered gradient (in argb32)", + "gradient, dither", /* keywords */ + NULL, /* requirements */ + 400, 100, + NULL, draw2) diff --git a/local/recipes/libs/cairo/source/test/drunkard-tails.c b/local/recipes/libs/cairo/source/test/drunkard-tails.c new file mode 100644 index 0000000000..f55c7becf0 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/drunkard-tails.c @@ -0,0 +1,135 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +#define LINE_WIDTH 10. +#define SIZE (5 * LINE_WIDTH) +#define PAD (3 * LINE_WIDTH) + +static uint32_t state; + +static double +uniform_random (double minval, double maxval) +{ + static uint32_t const poly = 0x9a795537U; + uint32_t n = 32; + while (n-->0) + state = 2*state < state ? (2*state ^ poly) : 2*state; + return minval + state * (maxval - minval) / 4294967296.0; +} + +static void +make_path (cairo_t *cr) +{ + int i; + + state = 0xdeadbeef; + + cairo_move_to (cr, SIZE/2, SIZE/2); + for (i = 0; i < 200; i++) { + double theta = uniform_random (-M_PI, M_PI); + cairo_rel_line_to (cr, + cos (theta) * LINE_WIDTH / 4, + sin (theta) * LINE_WIDTH / 4); + } +} + +static void +draw_caps_joins (cairo_t *cr) +{ + cairo_save (cr); + + cairo_translate (cr, PAD, PAD); + + cairo_reset_clip (cr); + cairo_rectangle (cr, 0, 0, SIZE, SIZE); + cairo_clip (cr); + + make_path (cr); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_BEVEL); + cairo_stroke (cr); + + cairo_translate (cr, SIZE + PAD, 0.); + + cairo_reset_clip (cr); + cairo_rectangle (cr, 0, 0, SIZE, SIZE); + cairo_clip (cr); + + make_path (cr); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); + cairo_stroke (cr); + + cairo_translate (cr, SIZE + PAD, 0.); + + cairo_reset_clip (cr); + cairo_rectangle (cr, 0, 0, SIZE, SIZE); + cairo_clip (cr); + + make_path (cr); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER); + cairo_stroke (cr); + + cairo_restore (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + /* We draw in the default black, so paint white first. */ + cairo_save (cr); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_restore (cr); + + cairo_set_line_width (cr, LINE_WIDTH); + + draw_caps_joins (cr); + + cairo_save (cr); + /* and reflect to generate the opposite vertex ordering */ + cairo_translate (cr, 0, height); + cairo_scale (cr, 1, -1); + + draw_caps_joins (cr); + cairo_restore (cr); + + cairo_translate (cr, 0, SIZE + PAD); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (drunkard_tails, + "Test caps and joins on short tail segments", + "stroke, cap, join", /* keywords */ + NULL, /* requirements */ + 3 * (PAD + SIZE) + PAD, + 2 * (PAD + SIZE) + PAD, + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/error-setters.c b/local/recipes/libs/cairo/source/test/error-setters.c new file mode 100644 index 0000000000..ecbb78fde1 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/error-setters.c @@ -0,0 +1,90 @@ +/* + * Copyright © 2010 Red Hat Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Benjamin Otte + */ + +#include "config.h" + +#include + +#include "cairo-test.h" + +#if CAIRO_HAS_PDF_SURFACE +#include +#endif +#if CAIRO_HAS_PS_SURFACE +#include +#endif +#if CAIRO_HAS_XCB_SURFACE +#include +#endif +#if CAIRO_HAS_XLIB_SURFACE +#include +#endif + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + cairo_surface_t *surface; + + /* get the error surface */ + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, INT_MAX, INT_MAX); + +#if CAIRO_HAS_PDF_SURFACE + cairo_pdf_surface_restrict_to_version (surface, CAIRO_PDF_VERSION_1_4); + cairo_pdf_surface_set_size (surface, 0, 0); +#endif + +#if CAIRO_HAS_PS_SURFACE + cairo_ps_surface_set_eps (surface, FALSE); + cairo_ps_surface_set_size (surface, 0, 0); + cairo_ps_surface_restrict_to_level (surface, CAIRO_PS_LEVEL_2); + cairo_ps_surface_dsc_comment (surface, NULL); + cairo_ps_surface_dsc_begin_setup (surface); + cairo_ps_surface_dsc_begin_page_setup (surface); +#endif + +#if CAIRO_HAS_XCB_SURFACE + cairo_xcb_surface_set_size (surface, 0, 0); +#endif + +#if CAIRO_HAS_XLIB_SURFACE + cairo_xlib_surface_set_size (surface, 0, 0); + cairo_xlib_surface_set_drawable (surface, 0, 0, 0); +#endif + + cairo_surface_set_mime_data (surface, NULL, NULL, 0, NULL, 0); + cairo_surface_set_device_offset (surface, 0, 0); + cairo_surface_set_fallback_resolution (surface, 0, 0); + + cairo_surface_destroy (surface); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (error_setters, + "Check setters properly error out on read-only error surfaces", + NULL, /* keywords */ + NULL, /* requirements */ + 0, 0, + preamble, NULL) diff --git a/local/recipes/libs/cairo/source/test/extend-pad-border.c b/local/recipes/libs/cairo/source/test/extend-pad-border.c new file mode 100644 index 0000000000..c02ec4f00f --- /dev/null +++ b/local/recipes/libs/cairo/source/test/extend-pad-border.c @@ -0,0 +1,95 @@ +/* + * Copyright © 2007 Red Hat, Inc. + * + * 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: Behdad Esfahbod + */ + +#include "cairo-test.h" +#include +#include + +#define SIZE 90 + +/* Check the border-pixels of an EXTEND_PAD image pattern */ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface; + cairo_t * cr_surface; + int surface_size = (SIZE - 30) / 10; + + cairo_set_source_rgba (cr, 0, 0, 0, 1); + cairo_rectangle (cr, 0, 0, SIZE, SIZE); + cairo_fill (cr); + + /* Create an image surface with my favorite four colors in each + * quadrant. */ + surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, + surface_size, surface_size); + cr_surface = cairo_create (surface); + cairo_surface_destroy (surface); + + cairo_set_source_rgb (cr_surface, 1, 1, 1); + cairo_rectangle (cr_surface, + 0, 0, + surface_size / 2, surface_size / 2); + cairo_fill (cr_surface); + cairo_set_source_rgb (cr_surface, 1, 0, 0); + cairo_rectangle (cr_surface, + surface_size / 2, 0, + surface_size / 2, surface_size / 2); + cairo_fill (cr_surface); + cairo_set_source_rgb (cr_surface, 0, 1, 0); + cairo_rectangle (cr_surface, + 0, surface_size / 2, + surface_size / 2, surface_size / 2); + cairo_fill (cr_surface); + cairo_set_source_rgb (cr_surface, 0, 0, 1); + cairo_rectangle (cr_surface, + surface_size / 2, surface_size / 2, + surface_size / 2, surface_size / 2); + cairo_fill (cr_surface); + + cairo_scale (cr, 10, 10); + cairo_set_source_surface (cr, cairo_get_target (cr_surface), 1.5, 1.5); + cairo_destroy (cr_surface); + + /* Using EXTEND_REFLECT makes this test pass for image and xlib backends */ + /*cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REFLECT);*/ + + cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_PAD); + cairo_rectangle (cr, 1.5, 1.5, 6, 6); + cairo_clip (cr); + + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (extend_pad_border, + "Test CAIRO_EXTEND_PAD for surface patterns", + "extend", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/extend-pad-similar.c b/local/recipes/libs/cairo/source/test/extend-pad-similar.c new file mode 100644 index 0000000000..09a90f46dc --- /dev/null +++ b/local/recipes/libs/cairo/source/test/extend-pad-similar.c @@ -0,0 +1,82 @@ +/* + * Copyright © 2007 Red Hat, Inc. + * + * 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: Behdad Esfahbod + */ + +#include "cairo-test.h" +#include +#include + +#define SIZE 90 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface; + cairo_t *cr_surface; + + /* Create a 4-pixel similar surface with my favorite four colors in each + * quadrant. */ + surface = cairo_surface_create_similar (cairo_get_group_target (cr), + CAIRO_CONTENT_COLOR, 2, 2); + cr_surface = cairo_create (surface); + cairo_surface_destroy (surface); + + /* upper-left = white */ + cairo_set_source_rgb (cr_surface, 1, 1, 1); + cairo_rectangle (cr_surface, 0, 0, 1, 1); + cairo_fill (cr_surface); + + /* upper-right = red */ + cairo_set_source_rgb (cr_surface, 1, 0, 0); + cairo_rectangle (cr_surface, 1, 0, 1, 1); + cairo_fill (cr_surface); + + /* lower-left = green */ + cairo_set_source_rgb (cr_surface, 0, 1, 0); + cairo_rectangle (cr_surface, 0, 1, 1, 1); + cairo_fill (cr_surface); + + /* lower-right = blue */ + cairo_set_source_rgb (cr_surface, 0, 0, 1); + cairo_rectangle (cr_surface, 1, 1, 1, 1); + cairo_fill (cr_surface); + + /* Now use extend pad to cover the entire surface with those 4 colors */ + cairo_set_source_surface (cr, cairo_get_target (cr_surface), + width/2 - 1, + height/2 - 1); + cairo_destroy (cr_surface); + cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_PAD); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (extend_pad_similar, + "Test CAIRO_EXTEND_PAD for similar surface patterns", + "extend", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/extend-pad.c b/local/recipes/libs/cairo/source/test/extend-pad.c new file mode 100644 index 0000000000..f851d44a48 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/extend-pad.c @@ -0,0 +1,81 @@ +/* + * Copyright © 2007 Red Hat, Inc. + * + * 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: Behdad Esfahbod + */ + +#include "cairo-test.h" +#include +#include + +#define SIZE 90 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface; + cairo_t *cr_surface; + + /* Create a 4-pixel image surface with my favorite four colors in each + * quadrant. */ + surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 2, 2); + cr_surface = cairo_create (surface); + cairo_surface_destroy (surface); + + /* upper-left = white */ + cairo_set_source_rgb (cr_surface, 1, 1, 1); + cairo_rectangle (cr_surface, 0, 0, 1, 1); + cairo_fill (cr_surface); + + /* upper-right = red */ + cairo_set_source_rgb (cr_surface, 1, 0, 0); + cairo_rectangle (cr_surface, 1, 0, 1, 1); + cairo_fill (cr_surface); + + /* lower-left = green */ + cairo_set_source_rgb (cr_surface, 0, 1, 0); + cairo_rectangle (cr_surface, 0, 1, 1, 1); + cairo_fill (cr_surface); + + /* lower-right = blue */ + cairo_set_source_rgb (cr_surface, 0, 0, 1); + cairo_rectangle (cr_surface, 1, 1, 1, 1); + cairo_fill (cr_surface); + + /* Now use extend pad to cover the entire surface with those 4 colors */ + cairo_set_source_surface (cr, cairo_get_target (cr_surface), + width/2 - 1, + height/2 - 1); + cairo_destroy (cr_surface); + cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_PAD); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (extend_pad, + "Test CAIRO_EXTEND_PAD for surface patterns", + "extend", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/extend-reflect-similar.c b/local/recipes/libs/cairo/source/test/extend-reflect-similar.c new file mode 100644 index 0000000000..fa376a7bf2 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/extend-reflect-similar.c @@ -0,0 +1,51 @@ +#include "cairo-test.h" + +static const char *png_filename = "romedalen.png"; + +static cairo_surface_t * +clone_similar_surface (cairo_surface_t * target, cairo_surface_t *surface) +{ + cairo_t *cr; + cairo_surface_t *similar; + + similar = cairo_surface_create_similar (target, + cairo_surface_get_content (surface), + cairo_image_surface_get_width (surface), + cairo_image_surface_get_height (surface)); + cr = cairo_create (similar); + cairo_surface_destroy (similar); + cairo_set_source_surface (cr, surface, 0, 0); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_paint (cr); + similar = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + + return similar; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_surface_t *surface; + cairo_surface_t *similar; + + surface = cairo_test_create_surface_from_png (ctx, png_filename); + similar = clone_similar_surface (cairo_get_group_target (cr), surface); + cairo_set_source_surface (cr, similar, 32, 32); + cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REFLECT); + + cairo_paint (cr); + + cairo_surface_destroy (similar); + cairo_surface_destroy (surface); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (extend_reflect_similar, + "Test CAIRO_EXTEND_REFLECT for surface patterns", + "extend", /* keywords */ + NULL, /* requirements */ + 256 + 32*2, 192 + 32*2, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/extend-reflect.c b/local/recipes/libs/cairo/source/test/extend-reflect.c new file mode 100644 index 0000000000..173befc263 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/extend-reflect.c @@ -0,0 +1,29 @@ +#include "cairo-test.h" +#include +#include + +static const char *png_filename = "romedalen.png"; + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_surface_t *surface; + + surface = cairo_test_create_surface_from_png (ctx, png_filename); + cairo_set_source_surface (cr, surface, 32, 32); + cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REFLECT); + + cairo_paint (cr); + + cairo_surface_destroy (surface); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (extend_reflect, + "Test CAIRO_EXTEND_REFLECT for surface patterns", + "extend", /* keywords */ + NULL, /* requirements */ + 256 + 32*2, 192 + 32*2, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/extend-repeat-similar.c b/local/recipes/libs/cairo/source/test/extend-repeat-similar.c new file mode 100644 index 0000000000..08cfd29ab8 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/extend-repeat-similar.c @@ -0,0 +1,51 @@ +#include "cairo-test.h" + +static const char *png_filename = "romedalen.png"; + +static cairo_surface_t * +clone_similar_surface (cairo_surface_t * target, cairo_surface_t *surface) +{ + cairo_t *cr; + cairo_surface_t *similar; + + similar = cairo_surface_create_similar (target, + cairo_surface_get_content (surface), + cairo_image_surface_get_width (surface), + cairo_image_surface_get_height (surface)); + cr = cairo_create (similar); + cairo_surface_destroy (similar); + cairo_set_source_surface (cr, surface, 0, 0); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_paint (cr); + similar = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + + return similar; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_surface_t *surface; + cairo_surface_t *similar; + + surface = cairo_test_create_surface_from_png (ctx, png_filename); + similar = clone_similar_surface (cairo_get_group_target (cr), surface); + cairo_set_source_surface (cr, similar, 32, 32); + cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT); + + cairo_paint (cr); + + cairo_surface_destroy (similar); + cairo_surface_destroy (surface); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (extend_repeat_similar, + "Test CAIRO_EXTEND_REPEAT for surface patterns", + "extend", /* keywords */ + NULL, /* requirements */ + 256 + 32*2, 192 + 32*2, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/extend-repeat.c b/local/recipes/libs/cairo/source/test/extend-repeat.c new file mode 100644 index 0000000000..e6c0bccb6a --- /dev/null +++ b/local/recipes/libs/cairo/source/test/extend-repeat.c @@ -0,0 +1,27 @@ +#include "cairo-test.h" + +static const char *png_filename = "romedalen.png"; + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_surface_t *surface; + + surface = cairo_test_create_surface_from_png (ctx, png_filename); + cairo_set_source_surface (cr, surface, 32, 32); + cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT); + + cairo_paint (cr); + + cairo_surface_destroy (surface); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (extend_repeat, + "Test CAIRO_EXTEND_REPEAT for surface patterns", + "extend", /* keywords */ + NULL, /* requirements */ + 256 + 32*2, 192 + 32*2, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/extended-blend.c b/local/recipes/libs/cairo/source/test/extended-blend.c new file mode 100644 index 0000000000..9c6f07d7d6 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/extended-blend.c @@ -0,0 +1,253 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2007 Emmanuel Pacaud + * Copyright © 2008 Benjamin Otte + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Owen Taylor + * Kristian Høgsberg + * Emmanuel Pacaud + */ + +#include "cairo-test.h" +#include +#include + +#define STEPS 16 +#define START_OPERATOR CAIRO_OPERATOR_MULTIPLY +#define STOP_OPERATOR CAIRO_OPERATOR_HSL_LUMINOSITY + +#define SIZE 5 +#define COUNT 4 +#define FULL_WIDTH ((STEPS + 1) * COUNT - 1) +#define FULL_HEIGHT ((COUNT + STOP_OPERATOR - START_OPERATOR) / COUNT) * (STEPS + 1) + +static void +set_solid_pattern (cairo_t *cr, + int step, + cairo_bool_t bg, + cairo_bool_t alpha) +{ + double c, a; + + a = ((double) step) / (STEPS - 1); + if (alpha) { + c = 1; + } else { + c = a; + a = 1; + } + + if (bg) /* draw a yellow background fading in using discrete steps */ + cairo_set_source_rgba (cr, c, c, 0, a); + else /* draw a teal foreground pattern fading in using discrete steps */ + cairo_set_source_rgba (cr, 0, c, c, a); +} + +/* expects a STEP*STEP pixel rectangle */ +static void +do_blend_solid (cairo_t *cr, cairo_operator_t op, cairo_bool_t alpha) +{ + int x; + + cairo_save (cr); + cairo_scale (cr, SIZE, SIZE); + + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + for (x = 0; x < STEPS; x++) { + /* draw the background using discrete steps */ + set_solid_pattern (cr, x, TRUE, alpha); + cairo_rectangle (cr, x, 0, 1, STEPS); + cairo_fill (cr); + } + + cairo_set_operator (cr, op); + for (x = 0; x < STEPS; x++) { + /* draw an orthogonal foreground pattern using discrete steps */ + set_solid_pattern (cr, x, FALSE, alpha); + cairo_rectangle (cr, 0, x, STEPS, 1); + cairo_fill (cr); + } + + cairo_restore (cr); +} + +static void +create_patterns (cairo_t *cr, + cairo_surface_t **bg, + cairo_surface_t **fg, + cairo_bool_t alpha) +{ + cairo_t *bgcr, *fgcr; + + *bg = cairo_surface_create_similar (cairo_get_target (cr), + CAIRO_CONTENT_COLOR_ALPHA, + SIZE * STEPS, + SIZE * STEPS); + *fg = cairo_surface_create_similar (cairo_get_target (cr), + CAIRO_CONTENT_COLOR_ALPHA, + SIZE * STEPS, + SIZE * STEPS); + + bgcr = cairo_create (*bg); + fgcr = cairo_create (*fg); + + do_blend_solid (bgcr, CAIRO_OPERATOR_DEST, alpha); + do_blend_solid (fgcr, CAIRO_OPERATOR_SOURCE, alpha); + + cairo_destroy (bgcr); + cairo_destroy (fgcr); +} + +/* expects a STEP*STEP pixel rectangle */ +static void +do_blend (cairo_t *cr, cairo_operator_t op, cairo_bool_t alpha) +{ + cairo_surface_t *bg, *fg; + + create_patterns (cr, &bg, &fg, alpha); + + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_set_source_surface (cr, bg, 0, 0); + cairo_paint (cr); + + cairo_set_operator (cr, op); + cairo_set_source_surface (cr, fg, 0, 0); + cairo_paint (cr); + + cairo_surface_destroy (fg); + cairo_surface_destroy (bg); +} + +static void +do_blend_mask (cairo_t *cr, cairo_operator_t op, cairo_bool_t alpha) +{ + cairo_surface_t *bg, *fg; + + create_patterns (cr, &bg, &fg, alpha); + + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_set_source_surface (cr, bg, 0, 0); + cairo_paint (cr); + + cairo_set_operator (cr, op); + cairo_set_source_surface (cr, fg, 0, 0); + cairo_paint_with_alpha (cr, .5); + + cairo_surface_destroy (fg); + cairo_surface_destroy (bg); +} + +static cairo_test_status_t +draw (cairo_t *cr, cairo_bool_t alpha, + void (*blend)(cairo_t *, cairo_operator_t, cairo_bool_t)) +{ + size_t i = 0; + cairo_operator_t op; + + for (op = START_OPERATOR; op <= STOP_OPERATOR; op++, i++) { + cairo_save (cr); + cairo_translate (cr, + SIZE * (STEPS + 1) * (i % COUNT), + SIZE * (STEPS + 1) * (i / COUNT)); + blend (cr, op, alpha); + cairo_restore (cr); + } + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +draw_extended_blend (cairo_t *cr, int width, int height) +{ + return draw (cr, FALSE, do_blend); +} + +static cairo_test_status_t +draw_extended_blend_alpha (cairo_t *cr, int width, int height) +{ + return draw (cr, TRUE, do_blend); +} + +static cairo_test_status_t +draw_extended_blend_solid (cairo_t *cr, int width, int height) +{ + return draw (cr, FALSE, do_blend_solid); +} + +static cairo_test_status_t +draw_extended_blend_solid_alpha (cairo_t *cr, int width, int height) +{ + return draw (cr, TRUE, do_blend_solid); +} + +static cairo_test_status_t +draw_extended_blend_mask (cairo_t *cr, int width, int height) +{ + return draw (cr, FALSE, do_blend_mask); +} +static cairo_test_status_t +draw_extended_blend_alpha_mask (cairo_t *cr, int width, int height) +{ + return draw (cr, TRUE, do_blend_mask); +} + +CAIRO_TEST (extended_blend, + "Tests extended blend modes without alpha", + "operator", /* keywords */ + NULL, /* requirements */ + FULL_WIDTH * SIZE, FULL_HEIGHT * SIZE, + NULL, draw_extended_blend) + +CAIRO_TEST (extended_blend_alpha, + "Tests extended blend modes with alpha", + "operator", /* keywords */ + NULL, /* requirements */ + FULL_WIDTH * SIZE, FULL_HEIGHT * SIZE, + NULL, draw_extended_blend_alpha) + +CAIRO_TEST (extended_blend_mask, + "Tests extended blend modes with an alpha mask", + "operator,mask", /* keywords */ + NULL, /* requirements */ + FULL_WIDTH * SIZE, FULL_HEIGHT * SIZE, + NULL, draw_extended_blend_mask) +CAIRO_TEST (extended_blend_alpha_mask, + "Tests extended blend modes with an alpha mask", + "operator,mask", /* keywords */ + NULL, /* requirements */ + FULL_WIDTH * SIZE, FULL_HEIGHT * SIZE, + NULL, draw_extended_blend_alpha_mask) + + +CAIRO_TEST (extended_blend_solid, + "Tests extended blend modes on solid patterns without alpha", + "operator", /* keywords */ + NULL, /* requirements */ + FULL_WIDTH * SIZE, FULL_HEIGHT * SIZE, + NULL, draw_extended_blend_solid) + +CAIRO_TEST (extended_blend_solid_alpha, + "Tests extended blend modes on solid patterns with alpha", + "operator", /* keywords */ + NULL, /* requirements */ + FULL_WIDTH * SIZE, FULL_HEIGHT * SIZE, + NULL, draw_extended_blend_solid_alpha) diff --git a/local/recipes/libs/cairo/source/test/fallback-resolution.c b/local/recipes/libs/cairo/source/test/fallback-resolution.c new file mode 100644 index 0000000000..83020fc37c --- /dev/null +++ b/local/recipes/libs/cairo/source/test/fallback-resolution.c @@ -0,0 +1,515 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + * Chris Wilson + */ + +#include "config.h" + +#include +#include +#include + +#if CAIRO_HAS_PDF_SURFACE +#include +#endif + +#ifdef HAVE_UNISTD_H +#include +#include +#endif +#if HAVE_SYS_STAT_H +#include +#endif + +#include "cairo-test.h" +#include "buffer-diff.h" + +/* This test exists to test cairo_surface_set_fallback_resolution + * + * one more thing. + * if you can somehow incorporate cairo_show_page stuff in the + * test suite. such that fallback-resolution can actually be + * automated.. + * if we could get a callback on surface when that function is + * called, we could do cool stuff like making other backends + * draw a long strip of images, one for each page... + */ + +#define INCHES_TO_POINTS(in) ((in) * 72.0) +#define SIZE INCHES_TO_POINTS(2) + +/* cairo_set_tolerance() is not respected by the PS/PDF backends currently */ +#define SET_TOLERANCE 0 + +#define GENERATE_REFERENCE 0 + +static void +draw (cairo_t *cr, double width, double height) +{ + const char *text = "cairo"; + cairo_text_extents_t extents; + const double dash[2] = { 8, 16 }; + cairo_pattern_t *pattern; + + cairo_save (cr); + + cairo_new_path (cr); + + cairo_set_line_width (cr, .05 * SIZE / 2.0); + + cairo_arc (cr, SIZE / 2.0, SIZE / 2.0, + 0.875 * SIZE / 2.0, + 0, 2.0 * M_PI); + cairo_stroke (cr); + + /* use dashes to demonstrate bugs: + * https://bugs.freedesktop.org/show_bug.cgi?id=9189 + * https://bugs.freedesktop.org/show_bug.cgi?id=17223 + */ + cairo_save (cr); + cairo_set_dash (cr, dash, 2, 0); + cairo_arc (cr, SIZE / 2.0, SIZE / 2.0, + 0.75 * SIZE / 2.0, + 0, 2.0 * M_PI); + cairo_stroke (cr); + cairo_restore (cr); + + cairo_save (cr); + cairo_rectangle (cr, 0, 0, SIZE/2, SIZE); + cairo_clip (cr); + cairo_arc (cr, SIZE / 2.0, SIZE / 2.0, + 0.6 * SIZE / 2.0, + 0, 2.0 * M_PI); + cairo_fill (cr); + cairo_restore (cr); + + /* use a pattern to exercise bug: + * https://bugs.launchpad.net/inkscape/+bug/234546 + */ + cairo_save (cr); + cairo_rectangle (cr, SIZE/2, 0, SIZE/2, SIZE); + cairo_clip (cr); + pattern = cairo_pattern_create_linear (SIZE/2, 0, SIZE, 0); + cairo_pattern_add_color_stop_rgba (pattern, 0, 0, 0, 0, 1.); + cairo_pattern_add_color_stop_rgba (pattern, 1, 0, 0, 0, 0.); + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + cairo_arc (cr, SIZE / 2.0, SIZE / 2.0, + 0.6 * SIZE / 2.0, + 0, 2.0 * M_PI); + cairo_fill (cr); + cairo_restore (cr); + + cairo_set_source_rgb (cr, 1, 1, 1); /* white */ + cairo_set_font_size (cr, .25 * SIZE / 2.0); + cairo_text_extents (cr, text, &extents); + cairo_move_to (cr, (SIZE-extents.width)/2.0-extents.x_bearing, + (SIZE-extents.height)/2.0-extents.y_bearing); + cairo_show_text (cr, text); + + cairo_restore (cr); +} + +static void +_xunlink (const cairo_test_context_t *ctx, const char *pathname) +{ + if (unlink (pathname) < 0 && errno != ENOENT) { + cairo_test_log (ctx, "Error: Cannot remove %s: %s\n", + pathname, strerror (errno)); + exit (1); + } +} + +static cairo_bool_t +check_result (cairo_test_context_t *ctx, + const cairo_boilerplate_target_t *target, + const char *test_name, + const char *base_name, + cairo_surface_t *surface) +{ + const char *format; + char *ref_name; + char *png_name; + char *diff_name; + cairo_surface_t *test_image, *ref_image, *diff_image; + buffer_diff_result_t result; + cairo_status_t status; + cairo_bool_t ret; + + /* XXX log target, OUTPUT, REFERENCE, DIFFERENCE for index.html */ + + if (target->finish_surface != NULL) { + status = target->finish_surface (surface); + if (status) { + cairo_test_log (ctx, "Error: Failed to finish surface: %s\n", + cairo_status_to_string (status)); + cairo_surface_destroy (surface); + return FALSE; + } + } + + xasprintf (&png_name, "%s.out.png", base_name); + xasprintf (&diff_name, "%s.diff.png", base_name); + + test_image = target->get_image_surface (surface, 0, SIZE, SIZE); + if (cairo_surface_status (test_image)) { + cairo_test_log (ctx, "Error: Failed to extract page: %s\n", + cairo_status_to_string (cairo_surface_status (test_image))); + cairo_surface_destroy (test_image); + free (png_name); + free (diff_name); + return FALSE; + } + + _xunlink (ctx, png_name); + status = cairo_surface_write_to_png (test_image, png_name); + if (status) { + cairo_test_log (ctx, "Error: Failed to write output image: %s\n", + cairo_status_to_string (status)); + cairo_surface_destroy (test_image); + free (png_name); + free (diff_name); + return FALSE; + } + + format = cairo_boilerplate_content_name (target->content); + ref_name = cairo_test_reference_filename (ctx, + base_name, + test_name, + target->name, + target->basename, + format, + CAIRO_TEST_REF_SUFFIX, + CAIRO_TEST_PNG_EXTENSION); + if (ref_name == NULL) { + cairo_test_log (ctx, "Error: Cannot find reference image for %s\n", + base_name); + cairo_surface_destroy (test_image); + free (png_name); + free (diff_name); + return FALSE; + } + + + ref_image = cairo_test_get_reference_image (ctx, ref_name, + target->content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED); + if (cairo_surface_status (ref_image)) { + cairo_test_log (ctx, "Error: Cannot open reference image for %s: %s\n", + ref_name, + cairo_status_to_string (cairo_surface_status (ref_image))); + cairo_surface_destroy (ref_image); + cairo_surface_destroy (test_image); + free (png_name); + free (diff_name); + free (ref_name); + return FALSE; + } + + diff_image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + SIZE, SIZE); + + ret = TRUE; + status = image_diff (ctx, + test_image, ref_image, diff_image, + &result); + _xunlink (ctx, diff_name); + if (status) { + cairo_test_log (ctx, "Error: Failed to compare images: %s\n", + cairo_status_to_string (status)); + ret = FALSE; + } else if (image_diff_is_failure (&result, target->error_tolerance)) + { + ret = FALSE; + + status = cairo_surface_write_to_png (diff_image, diff_name); + if (status) { + cairo_test_log (ctx, "Error: Failed to write differences image: %s\n", + cairo_status_to_string (status)); + } + } + + cairo_surface_destroy (test_image); + cairo_surface_destroy (diff_image); + free (png_name); + free (diff_name); + free (ref_name); + + return ret; +} + +#if GENERATE_REFERENCE +static void +generate_reference (double ppi_x, double ppi_y, const char *filename) +{ + cairo_surface_t *surface, *target; + cairo_t *cr; + cairo_status_t status; + + surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, + SIZE*ppi_x/72, SIZE*ppi_y/72); + cr = cairo_create (surface); + cairo_surface_destroy (surface); + + /* As we wish to mimic a PDF surface, copy across the default font options + * from the PDF backend. + */ + { + cairo_surface_t *pdf; + cairo_font_options_t *options; + + options = cairo_font_options_create (); + +#if CAIRO_HAS_PDF_SURFACE + pdf = cairo_pdf_surface_create ("tmp.pdf", 1, 1); + cairo_surface_get_font_options (pdf, options); + cairo_surface_destroy (pdf); +#endif + + cairo_set_font_options (cr, options); + cairo_font_options_destroy (options); + } + +#if SET_TOLERANCE + cairo_set_tolerance (cr, 3.0); +#endif + + cairo_save (cr); { + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + } cairo_restore (cr); + + cairo_scale (cr, ppi_x/72., ppi_y/72.); + draw (cr, SIZE, SIZE); + + surface = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + + target = cairo_image_surface_create (CAIRO_FORMAT_RGB24, SIZE, SIZE); + cr = cairo_create (target); + cairo_scale (cr, 72./ppi_x, 72./ppi_y); + cairo_set_source_surface (cr, surface, 0, 0); + cairo_paint (cr); + + status = cairo_surface_write_to_png (cairo_get_target (cr), filename); + cairo_destroy (cr); + + if (status) { + fprintf (stderr, "Failed to generate reference image '%s': %s\n", + filename, cairo_status_to_string (status)); + exit (1); + } +} +#endif + +/* TODO: Split each ppi case out to its own CAIRO_TEST() test case */ +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + cairo_t *cr; + cairo_test_status_t ret = CAIRO_TEST_UNTESTED; + struct { + double x, y; + } ppi[] = { + { 576, 576 }, + { 576, 72 }, + + { 288, 288 }, + { 288, 72 }, + + { 144, 144 }, + { 144, 72 }, + + { 72, 576 }, + { 72, 288 }, + { 72, 144 }, + { 72, 72 }, + }; + unsigned int i; + int n, num_ppi; + const char *path = cairo_test_mkdir (CAIRO_TEST_OUTPUT_DIR) ? CAIRO_TEST_OUTPUT_DIR : "."; + + num_ppi = ARRAY_LENGTH (ppi); + +#if GENERATE_REFERENCE + for (n = 0; n < num_ppi; n++) { + char *ref_name; + xasprintf (&ref_name, "reference/fallback-resolution.ppi%gx%g.ref.png", + ppi[n].x, ppi[n].y); + generate_reference (ppi[n].x, ppi[n].y, ref_name); + free (ref_name); + } +#endif + + for (i = 0; i < ctx->num_targets; i++) { + const cairo_boilerplate_target_t *target = ctx->targets_to_test[i]; + cairo_surface_t *surface = NULL; + char *base_name; + void *closure; + const char *format; + cairo_status_t status; + + if (! target->is_vector) + continue; + + if (! cairo_test_is_target_enabled (ctx, target->name)) + continue; + + format = cairo_boilerplate_content_name (target->content); + xasprintf (&base_name, "%s/fallback-resolution.%s.%s", + path, target->name, + format); + + surface = (target->create_surface) (base_name, + target->content, + SIZE, SIZE, + SIZE, SIZE, + CAIRO_BOILERPLATE_MODE_TEST, + &closure); + + if (surface == NULL) { + free (base_name); + continue; + } + + if (ret == CAIRO_TEST_UNTESTED) + ret = CAIRO_TEST_SUCCESS; + + cairo_surface_destroy (surface); + if (target->cleanup) + target->cleanup (closure); + free (base_name); + + /* we need to recreate the surface for each resolution as we include + * SVG in testing which does not support the paginated interface. + */ + for (n = 0; n < num_ppi; n++) { + char *test_name; + cairo_bool_t pass; + + xasprintf (&test_name, "fallback-resolution.ppi%gx%g", + ppi[n].x, ppi[n].y); + xasprintf (&base_name, "%s/%s.%s.%s", + path, test_name, + target->name, + format); + + surface = (target->create_surface) (base_name, + target->content, + SIZE + 25, SIZE + 25, + SIZE + 25, SIZE + 25, + CAIRO_BOILERPLATE_MODE_TEST, + &closure); + if (surface == NULL || cairo_surface_status (surface)) { + cairo_test_log (ctx, "Failed to generate surface: %s.%s\n", + target->name, + format); + free (base_name); + free (test_name); + ret = CAIRO_TEST_FAILURE; + continue; + } + + cairo_test_log (ctx, + "Testing fallback-resolution %gx%g with %s target\n", + ppi[n].x, ppi[n].y, target->name); + printf ("%s:\t", base_name); + fflush (stdout); + + if (target->force_fallbacks != NULL) + target->force_fallbacks (surface, ppi[n].x, ppi[n].y); + cr = cairo_create (surface); +#if SET_TOLERANCE + cairo_set_tolerance (cr, 3.0); +#endif + + cairo_surface_set_device_offset (surface, 25, 25); + + cairo_save (cr); { + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + } cairo_restore (cr); + + /* First draw the top half in a conventional way. */ + cairo_save (cr); { + cairo_rectangle (cr, 0, 0, SIZE, SIZE / 2.0); + cairo_clip (cr); + + draw (cr, SIZE, SIZE); + } cairo_restore (cr); + + /* Then draw the bottom half in a separate group, + * (exposing a bug in 1.6.4 with the group not being + * rendered with the correct fallback resolution). */ + cairo_save (cr); { + cairo_rectangle (cr, 0, SIZE / 2.0, SIZE, SIZE / 2.0); + cairo_clip (cr); + + cairo_push_group (cr); { + draw (cr, SIZE, SIZE); + } cairo_pop_group_to_source (cr); + + cairo_paint (cr); + } cairo_restore (cr); + + status = cairo_status (cr); + cairo_destroy (cr); + + pass = FALSE; + if (status) { + cairo_test_log (ctx, "Error: Failed to create target surface: %s\n", + cairo_status_to_string (status)); + ret = CAIRO_TEST_FAILURE; + } else { + /* extract the image and compare it to our reference */ + if (! check_result (ctx, target, test_name, base_name, surface)) + ret = CAIRO_TEST_FAILURE; + else + pass = TRUE; + } + cairo_surface_destroy (surface); + if (target->cleanup) + target->cleanup (closure); + + free (base_name); + free (test_name); + + if (pass) { + printf ("PASS\n"); + } else { + printf ("FAIL\n"); + } + fflush (stdout); + } + } + + return ret; +} + +CAIRO_TEST (fallback_resolution, + "Check handling of fallback resolutions", + "fallback", /* keywords */ + NULL, /* requirements */ + 0, 0, + preamble, NULL) diff --git a/local/recipes/libs/cairo/source/test/fallback.c b/local/recipes/libs/cairo/source/test/fallback.c new file mode 100644 index 0000000000..a3cfc401c8 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/fallback.c @@ -0,0 +1,79 @@ +/* + * Copyright © 2012 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" + +#define SIZE 40 +#define WIDTH (7*SIZE) +#define HEIGHT (5*SIZE) + +#define FALLBACK_RES_X 300 +#define FALLBACK_RES_Y 150 + +static void +rectangles (cairo_t *cr) +{ + cairo_save (cr); + + cairo_rotate (cr, M_PI/8); + cairo_translate (cr, 2*SIZE, SIZE/16); + cairo_scale (cr, 1.5, 1.5); + + cairo_rectangle (cr, 0, 0, SIZE, SIZE); + cairo_set_source_rgba (cr, 1, 0, 0, 0.5); + cairo_fill (cr); + + /* Select an operator not supported by PDF/PS/SVG to trigger fallback */ + cairo_set_operator (cr, CAIRO_OPERATOR_SATURATE); + + cairo_rectangle (cr, SIZE/2, SIZE/2, SIZE, SIZE); + cairo_set_source_rgba (cr, 0, 1, 0, 0.5); + cairo_fill (cr); + + cairo_restore (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_set_fallback_resolution (cairo_get_target (cr), FALLBACK_RES_X, FALLBACK_RES_Y); + + rectangles (cr); + cairo_translate (cr, 3*SIZE, 0); + cairo_push_group (cr); + rectangles (cr); + cairo_pop_group_to_source (cr); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (fallback, + "Check that fallback images are correct when fallback resolution is not 72ppi", + "fallback", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/fill-alpha-pattern.c b/local/recipes/libs/cairo/source/test/fill-alpha-pattern.c new file mode 100644 index 0000000000..3698779c13 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/fill-alpha-pattern.c @@ -0,0 +1,87 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +#define SIZE 60 /* needs to be big to check large area effects (dithering) */ +#define PAD 2 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const double alpha = 1./3; + cairo_pattern_t *pattern; + int n; + + /* draw a simple pattern behind */ + pattern = cairo_pattern_create_linear (0, 0, width, height); + cairo_pattern_add_color_stop_rgb (pattern, 0, 1, 1, 0); + cairo_pattern_add_color_stop_rgb (pattern, 1, 1, 1, 1); + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + cairo_paint (cr); + + /* square */ + cairo_rectangle (cr, PAD, PAD, SIZE, SIZE); + cairo_set_source_rgba (cr, 1, 0, 0, alpha); + cairo_fill (cr); + + /* circle */ + cairo_translate (cr, SIZE + 2 * PAD, 0); + cairo_arc (cr, PAD + SIZE / 2., PAD + SIZE / 2., SIZE / 2., 0, 2 * M_PI); + cairo_set_source_rgba (cr, 0, 1, 0, alpha); + cairo_fill (cr); + + /* triangle */ + cairo_translate (cr, 0, SIZE + 2 * PAD); + cairo_move_to (cr, PAD + SIZE / 2, PAD); + cairo_line_to (cr, PAD + SIZE, PAD + SIZE); + cairo_line_to (cr, PAD, PAD + SIZE); + cairo_set_source_rgba (cr, 0, 0, 1, alpha); + cairo_fill (cr); + + /* star */ + cairo_translate (cr, -(SIZE + 2 * PAD) + SIZE/2., SIZE/2.); + for (n = 0; n < 5; n++) { + cairo_line_to (cr, + SIZE/2 * cos (2*n * 2*M_PI / 10), + SIZE/2 * sin (2*n * 2*M_PI / 10)); + + cairo_line_to (cr, + SIZE/4 * cos ((2*n+1)*2*M_PI / 10), + SIZE/4 * sin ((2*n+1)*2*M_PI / 10)); + } + cairo_set_source_rgba (cr, 0, 0, 0, alpha); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (fill_alpha_pattern, + "Tests using set_rgba();fill() over a linear gradient", + "fill, alpha", /* keywords */ + NULL, /* requirements */ + 2*SIZE + 4*PAD, 2*SIZE + 4*PAD, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/fill-alpha.c b/local/recipes/libs/cairo/source/test/fill-alpha.c new file mode 100644 index 0000000000..6c2948dfaf --- /dev/null +++ b/local/recipes/libs/cairo/source/test/fill-alpha.c @@ -0,0 +1,82 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +#define SIZE 60 /* needs to be big to check large area effects (dithering) */ +#define PAD 2 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const double alpha = 1./3; + int n; + + /* flatten to white */ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + /* square */ + cairo_rectangle (cr, PAD, PAD, SIZE, SIZE); + cairo_set_source_rgba (cr, 1, 0, 0, alpha); + cairo_fill (cr); + + /* circle */ + cairo_translate (cr, SIZE + 2 * PAD, 0); + cairo_arc (cr, PAD + SIZE / 2., PAD + SIZE / 2., SIZE / 2., 0, 2 * M_PI); + cairo_set_source_rgba (cr, 0, 1, 0, alpha); + cairo_fill (cr); + + /* triangle */ + cairo_translate (cr, 0, SIZE + 2 * PAD); + cairo_move_to (cr, PAD + SIZE / 2, PAD); + cairo_line_to (cr, PAD + SIZE, PAD + SIZE); + cairo_line_to (cr, PAD, PAD + SIZE); + cairo_set_source_rgba (cr, 0, 0, 1, alpha); + cairo_fill (cr); + + /* star */ + cairo_translate (cr, -(SIZE + 2 * PAD) + SIZE/2., SIZE/2.); + for (n = 0; n < 5; n++) { + cairo_line_to (cr, + SIZE/2 * cos (2*n * 2*M_PI / 10), + SIZE/2 * sin (2*n * 2*M_PI / 10)); + + cairo_line_to (cr, + SIZE/4 * cos ((2*n+1)*2*M_PI / 10), + SIZE/4 * sin ((2*n+1)*2*M_PI / 10)); + } + cairo_set_source_rgba (cr, 0, 0, 0, alpha); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (fill_alpha, + "Tests using set_rgba();fill()", + "fill, alpha", /* keywords */ + NULL, /* requirements */ + 2*SIZE + 4*PAD, 2*SIZE + 4*PAD, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/fill-and-stroke-alpha-add.c b/local/recipes/libs/cairo/source/test/fill-and-stroke-alpha-add.c new file mode 100644 index 0000000000..55cd4c6a21 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/fill-and-stroke-alpha-add.c @@ -0,0 +1,107 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +#define PAD 2 +#define SIZE 10 + +typedef void (*path_func_t) (cairo_t *cr); + +static void +rectangle (cairo_t *cr) +{ + cairo_rectangle (cr, PAD, PAD, SIZE, SIZE); +} + +static void +circle (cairo_t *cr) +{ + cairo_arc (cr, + PAD + SIZE / 2, PAD + SIZE / 2, + SIZE / 2, + 0, 2 * M_PI); +} + +/* Given a path-generating function and two possibly translucent + * patterns, fill and stroke the path with the patterns (to an + * offscreen group), then blend the result into the destination. + */ +static void +fill_and_stroke (cairo_t *cr, + path_func_t path_func, + cairo_pattern_t *fill_pattern, + cairo_pattern_t *stroke_pattern) +{ + cairo_push_group (cr); + { + (path_func) (cr); + cairo_set_source (cr, fill_pattern); + cairo_fill_preserve (cr); + + /* Use DEST_OUT to subtract stroke from fill. */ + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_set_operator (cr, CAIRO_OPERATOR_DEST_OUT); + cairo_stroke_preserve (cr); + + /* Then use ADD to draw the stroke without a seam. */ + cairo_set_source (cr, stroke_pattern); + cairo_set_operator (cr, CAIRO_OPERATOR_ADD); + cairo_stroke (cr); + } + cairo_pop_group_to_source (cr); + cairo_paint (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *blue; + cairo_pattern_t *red; + + blue = cairo_pattern_create_rgba (0.0, 0.0, 1.0, 0.8); + red = cairo_pattern_create_rgba (1.0, 0.0, 0.0, 0.2); + + cairo_test_paint_checkered (cr); + + fill_and_stroke (cr, rectangle, blue, red); + + cairo_translate (cr, SIZE + 2 * PAD, 0); + + fill_and_stroke (cr, circle, red, blue); + + cairo_pattern_destroy (blue); + cairo_pattern_destroy (red); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (fill_and_stroke_alpha_add, + "Use a group to fill/stroke a path (each with different alpha) using DEST_OUT and ADD to combine", + "fill-and-stroke, fill, stroke", /* keywords */ + NULL, /* requirements */ + 2 * SIZE + 4 * PAD, SIZE + 2 * PAD, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/fill-and-stroke-alpha.c b/local/recipes/libs/cairo/source/test/fill-and-stroke-alpha.c new file mode 100644 index 0000000000..c6d7c00629 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/fill-and-stroke-alpha.c @@ -0,0 +1,101 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +#define PAD 2 +#define SIZE 10 + +typedef void (*path_func_t) (cairo_t *cr); + +static void +rectangle (cairo_t *cr) +{ + cairo_rectangle (cr, PAD, PAD, SIZE, SIZE); +} + +static void +circle (cairo_t *cr) +{ + cairo_arc (cr, + PAD + SIZE / 2, PAD + SIZE / 2, + SIZE / 2, + 0, 2 * M_PI); +} + +/* Given a path-generating function and two opaque patterns, fill and + * stroke the path with the patterns (to an offscreen group), then + * blend the result into the destination with the given alpha + * value. + */ +static void +fill_and_stroke_alpha (cairo_t *cr, + path_func_t path_func, + cairo_pattern_t *fill_pattern, + cairo_pattern_t *stroke_pattern, + double alpha) +{ + cairo_push_group (cr); + { + (path_func) (cr); + cairo_set_source (cr, fill_pattern); + cairo_fill_preserve (cr); + cairo_set_source (cr, stroke_pattern); + cairo_stroke (cr); + } + cairo_pop_group_to_source (cr); + cairo_paint_with_alpha (cr, alpha); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *blue; + cairo_pattern_t *red; + + blue = cairo_pattern_create_rgb (0.0, 0.0, 1.0); + red = cairo_pattern_create_rgb (1.0, 0.0, 0.0); + + cairo_test_paint_checkered (cr); + + fill_and_stroke_alpha (cr, rectangle, blue, red, 0.5); + + cairo_translate (cr, SIZE + 2 * PAD, 0); + + fill_and_stroke_alpha (cr, circle, red, blue, 0.5); + + cairo_pattern_destroy (blue); + cairo_pattern_destroy (red); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (fill_and_stroke_alpha, + "Use a group to fill/stroke a path then blend the result with alpha onto the destination", + "fill-and-stroke, fill, stroke", /* keywords */ + NULL, /* requirements */ + 2 * SIZE + 4 * PAD, SIZE + 2 * PAD, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/fill-and-stroke.c b/local/recipes/libs/cairo/source/test/fill-and-stroke.c new file mode 100644 index 0000000000..c983c32994 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/fill-and-stroke.c @@ -0,0 +1,58 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +#define PAD 2 +#define SIZE 10 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_rectangle (cr, PAD, PAD, SIZE, SIZE); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_fill_preserve (cr); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_stroke (cr); + + cairo_translate (cr, SIZE + 2 * PAD, 0); + + cairo_arc (cr, + PAD + SIZE / 2, PAD + SIZE / 2, + SIZE / 2, + 0, 2 * M_PI); + cairo_fill_preserve (cr); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (fill_and_stroke, + "Tests using cairo_fill_preserve/cairo_stroke to fill/stroke the same path", + "fill-and-stroke, fill, stroke", /* keywords */ + NULL, /* requirements */ + 2 * SIZE + 4 * PAD, SIZE + 2 * PAD, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/fill-degenerate-sort-order.c b/local/recipes/libs/cairo/source/test/fill-degenerate-sort-order.c new file mode 100644 index 0000000000..d934810480 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/fill-degenerate-sort-order.c @@ -0,0 +1,77 @@ +/* + * Copyright © 2006 M Joonas Pihlaja + * + * 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: M Joonas Pihlaja + */ + +/* Bug history + * + * 2006-12-05 M Joonas Pihlaja + * + * There's currently a regression bug in the tessellation code from + * switching to the "new tessellator". The bug is caused by + * confusion in the comparator used to order events when there are + * degenerate edges. + */ + +#include "cairo-test.h" + +/* Derived from zrusin's "another" polygon in the performance suite. */ +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 0, 0); + + /* The polygon uses (43,103) as its "base point". Closed + * subpaths are simulated by going from the base point to the + * subpath's first point, doing the subpath, and returning to the + * base point. The moving to and from the base point causes + * degenerate edges which shouldn't result in anything visible. */ + cairo_move_to (cr, 43, 103); + + /* First subpath. */ + cairo_line_to (cr, 91, 101); + cairo_line_to (cr, 0, 112); + cairo_line_to (cr, 60, 0); + cairo_line_to (cr, 91, 101); + + cairo_line_to (cr, 43, 103); + + /* Second subpath. */ + cairo_line_to (cr, 176, 110); + cairo_line_to (cr, 116, 100); + cairo_line_to (cr, 176, 0); + cairo_line_to (cr, 176, 110); + + cairo_close_path (cr); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (fill_degenerate_sort_order, + "Tests the tessellator's event comparator with degenerate input", + "degenerate, fill", /* keywords */ + NULL, /* requirements */ + 190, 120, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/fill-disjoint.c b/local/recipes/libs/cairo/source/test/fill-disjoint.c new file mode 100644 index 0000000000..ea2c14fffa --- /dev/null +++ b/local/recipes/libs/cairo/source/test/fill-disjoint.c @@ -0,0 +1,63 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +/* The goal is exercise a bug that existed in the xlib backend, where + * it assumed the rectangles generated by rectangular tessallator had + * any sorting guarantees. + */ + +#define WIDTH 300 +#define HEIGHT 300 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + int x; + + /* black background */ + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + /* white rectangles */ + cairo_set_source_rgb (cr, 1, 1, 1); + + /* fill with a set of rectangles that the rectangular tessellator + * will not emit sorted. */ + for (x = 0; x < WIDTH - 10; x += 15) + cairo_rectangle (cr, x, x, 10, HEIGHT - 2*x); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (fill_disjoint, + "Tests filling unsorted rectangles.", + "fill", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/fill-empty.c b/local/recipes/libs/cairo/source/test/fill-empty.c new file mode 100644 index 0000000000..0594e57ad4 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/fill-empty.c @@ -0,0 +1,62 @@ +/* + * Copyright © 2009 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +#define SIZE 10 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 1, 0, 0); + + /* first drawn an ordinary empty path */ + cairo_save (cr); + cairo_rectangle (cr, 0, 0, SIZE, SIZE/2); + cairo_clip (cr); + cairo_fill (cr); + cairo_restore (cr); + + /* and then an unbounded empty path */ + cairo_save (cr); + cairo_rectangle (cr, 0, SIZE/2, SIZE, SIZE/2); + cairo_clip (cr); + cairo_set_operator (cr, CAIRO_OPERATOR_DEST_IN); + cairo_fill (cr); + cairo_restore (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (fill_empty, + "Test filling with an empty path", + "fill", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/fill-image.c b/local/recipes/libs/cairo/source/test/fill-image.c new file mode 100644 index 0000000000..24ee031422 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/fill-image.c @@ -0,0 +1,83 @@ +/* + * Copyright © 2006 Mozilla Corporation + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Mozilla Corporation not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Mozilla Corporation makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * MOZILLA CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL MOZILLA CORPORATION BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Vladimir Vukicevic + */ + +#include "cairo-test.h" + +#define PAD 10 +#define SIZE 100 +#define IMAGE_SIZE (SIZE-PAD*2) +#define LINE_WIDTH 10 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *image; + cairo_t *cr_image; + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + image = cairo_image_surface_create (CAIRO_FORMAT_RGB24, + IMAGE_SIZE, IMAGE_SIZE); + cr_image = cairo_create (image); + cairo_surface_destroy (image); + + /* Create the image */ + cairo_set_source_rgb (cr_image, 0, 0, 0); + cairo_paint (cr_image); + + cairo_set_source_rgb (cr_image, 0, 1, 0); + cairo_new_sub_path (cr_image); + cairo_arc (cr_image, IMAGE_SIZE/2, IMAGE_SIZE/2, IMAGE_SIZE/2 - LINE_WIDTH, 0, M_PI * 2.0); + cairo_close_path (cr_image); + cairo_new_sub_path (cr_image); + cairo_arc_negative (cr_image, IMAGE_SIZE/2, IMAGE_SIZE/2, IMAGE_SIZE/2, 0, -M_PI * 2.0); + cairo_close_path (cr_image); + cairo_fill (cr_image); + + /* Now stroke^Wfill with it */ + cairo_translate (cr, PAD, PAD); + + cairo_set_source_surface (cr, cairo_get_target (cr_image), 0, 0); + cairo_destroy (cr_image); + + cairo_new_sub_path (cr); + cairo_arc (cr, IMAGE_SIZE/2, IMAGE_SIZE/2, IMAGE_SIZE/2 - LINE_WIDTH, 0, M_PI * 2.0); + cairo_close_path (cr); + cairo_new_sub_path (cr); + cairo_arc_negative (cr, IMAGE_SIZE/2, IMAGE_SIZE/2, IMAGE_SIZE/2, 0, -M_PI * 2.0); + cairo_close_path (cr); + + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (fill_image, + "Test filling with an image source, with a non-identity CTM", + "fill, image, transform", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/fill-missed-stop.c b/local/recipes/libs/cairo/source/test/fill-missed-stop.c new file mode 100644 index 0000000000..5589337786 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/fill-missed-stop.c @@ -0,0 +1,83 @@ +/* + * Copyright © 2006 M Joonas Pihlaja + * + * 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: M Joonas Pihlaja + */ + +/* Bug history + * + * 2006-12-05 M Joonas Pihlaja + * + * The tessellator has a regression where a trapezoid may continue + * below the end of a polygon edge (i.e. the bottom of the trapezoid + * is miscomputed.) This can only happen if the right edge of a + * trapezoid stops earlier than the left edge and there is no start + * event at the end point of the right edge. + */ + +#include "cairo-test.h" + +#define SIZE 50 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 0, 0); + + cairo_translate (cr, 1, 1); + + /* What it should look like, with # marking the filled areas: + * + * |\ |\ + * |#\ |#\ + * |##\__|##\ + * \#| + * \| + * + * What it looke like with the bug, when the rightmost edge's end + * is missed: + * + * |\ |\ + * |#\ |#\ + * |##\__|##\ + * \#####| + * \####| + */ + + cairo_move_to (cr, 0, 0); + cairo_line_to (cr, SIZE/2, SIZE); + cairo_line_to (cr, SIZE/2, 0); + cairo_line_to (cr, SIZE, SIZE/2); + cairo_line_to (cr, 0, SIZE/2); + cairo_close_path (cr); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (fill_missed_stop, + "Tests that the tessellator doesn't miss stop events when generating trapezoids", + "fill", /* keywords */ + NULL, /* requirements */ + SIZE+3, SIZE+3, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/fill-rule.c b/local/recipes/libs/cairo/source/test/fill-rule.c new file mode 100644 index 0000000000..66f19b7cc9 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/fill-rule.c @@ -0,0 +1,127 @@ +/* + * Copyright © 2004 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +/* Bug history + * + * 2004-10-27 Carl Worth + * + * There's currently a regression bug in the tessellation code. This + * causes each of these simple star shapes to be filled incorrectly. + * + * It looks like right now we can get this test to pass by doing: + * + * cvs update -r 1.16 src/cairo_traps.c + * + * But we don't want to revert that change permanently since it + * really does correct some bugs. It must be that the old version of + * the code is masking some other bugs in the tessellation code. My + * current plan is to back this revision up for the next snapshot, + * but not to list the test as an expected failure since I'm + * planning on doing the new tessellator which should fix this + * problem. + * + * 2005-01-11 Carl Worth + * + * Keith committed some fixes that fix the original size-20 + * star_path: + * + * * src/cairo_wideint.c: (_cairo_int32x32_64_mul), + * (_cairo_int64x64_128_mul): + * * src/cairo_wideint.h: + * int32x32_64_mul and int64x64_128_mul are different from their + * unsigned compatriots + * + * 2005-01-12 Carl Worth + * + * Going back to the SVG test suite, however, the original star + * shape is still broken. Adding both shapes now as little_star_path + * and big_star_path. + * + */ + +#include "cairo-test.h" + +#define LITTLE_STAR_SIZE 20 +#define BIG_STAR_SIZE 80 + +/* The SVG start trimmed down, but still showing the bug (originally) */ +static void +little_star_path (cairo_t *cr) +{ + cairo_move_to (cr, 10, 0); + cairo_rel_line_to (cr, 6, 20); + cairo_rel_line_to (cr, -16, -12); + cairo_rel_line_to (cr, 20, 0); + cairo_rel_line_to (cr, -16, 12); +} + +/* The star shape from the SVG test suite. This was is still buggy even after + we got little_star_path working. */ +static void +big_star_path (cairo_t *cr) +{ + cairo_move_to (cr, 40, 0); + cairo_rel_line_to (cr, 25, 80); + cairo_rel_line_to (cr, -65, -50); + cairo_rel_line_to (cr, 80, 0); + cairo_rel_line_to (cr, -65, 50); + cairo_close_path (cr); +} + +/* Fill the same path twice, once with each fill rule */ +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 0, 0); + + cairo_translate (cr, 1, 1); + little_star_path (cr); + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_WINDING); + cairo_fill (cr); + + cairo_translate (cr, LITTLE_STAR_SIZE + 1, 0); + little_star_path (cr); + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + cairo_fill (cr); + + cairo_translate (cr, -(LITTLE_STAR_SIZE + 1), LITTLE_STAR_SIZE + 1); + big_star_path (cr); + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_WINDING); + cairo_fill (cr); + + cairo_translate (cr, BIG_STAR_SIZE + 1, 0); + big_star_path (cr); + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (fill_rule, + "Tests cairo_set_fill_rule with some star shapes", + "fill, path", /* keywords */ + NULL, /* requirements */ + BIG_STAR_SIZE * 2 + 3, BIG_STAR_SIZE + LITTLE_STAR_SIZE + 3, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/filter-bilinear-extents.c b/local/recipes/libs/cairo/source/test/filter-bilinear-extents.c new file mode 100644 index 0000000000..91ac703db6 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/filter-bilinear-extents.c @@ -0,0 +1,102 @@ +/* + * Copyright © 2008 Red Hat, Inc. + * + * 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. + * + * Authors: Carl D. Worth + * Owen Taylor + */ + +#include "cairo-test.h" + +/* This test exercises code that computes the extents of a surface + * pattern with CAIRO_FILTER_BILINEAR, (where the filtering + * effectively increases the extents of the pattern). + * + * The original bug was reported by Owen Taylor here: + * + * bad clipping with EXTEND_NONE + * https://bugs.freedesktop.org/show_bug.cgi?id=15349 + */ + +#define SCALE 10 +#define PAD 3 +#define WIDTH (PAD + 3 * SCALE + PAD) +#define HEIGHT WIDTH + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *image; + cairo_t *cr2; + + image = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 2, 2); + + /* Fill with an opaque background to avoid a separate rgb24 ref image */ + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + /* First check handling of pattern extents > surface extents */ + cairo_save (cr); + cairo_scale (cr, width/2., height/2.); + + /* Create a solid black source to merge with the background */ + cr2 = cairo_create (image); + cairo_set_source_rgb (cr2, 0, 0 ,0); + cairo_paint (cr2); + cairo_set_source_surface (cr, cairo_get_target (cr2), 0, 0); + cairo_destroy (cr2); + cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_BILINEAR); + cairo_paint (cr); + cairo_restore (cr); + + /* Then scale to smaller so we can see the full bilinear extents */ + cairo_save (cr); + cairo_translate (cr, PAD, PAD); + cairo_scale (cr, SCALE, SCALE); + cairo_translate (cr, 0.5, 0.5); + + /* Create a 2x2 blue+red checkerboard source */ + cr2 = cairo_create (image); + cairo_set_source_rgb (cr2, 1, 0 ,0); /* red */ + cairo_paint (cr2); + cairo_set_source_rgb (cr2, 0, 0, 1); /* blue */ + cairo_rectangle (cr2, 0, 1, 1, 1); + cairo_rectangle (cr2, 1, 0, 1, 1); + cairo_fill (cr2); + cairo_set_source_surface (cr, cairo_get_target (cr2), 0, 0); + cairo_destroy (cr2); + + cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_BILINEAR); + cairo_paint (cr); + cairo_restore (cr); + + cairo_surface_destroy (image); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (filter_bilinear_extents, + "Test that pattern extents are properly computed for CAIRO_FILTER_BILINEAR", + "extents", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/filter-nearest-offset.c b/local/recipes/libs/cairo/source/test/filter-nearest-offset.c new file mode 100644 index 0000000000..4df6097020 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/filter-nearest-offset.c @@ -0,0 +1,109 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +#define STAMP_WIDTH 4 +#define STAMP_HEIGHT 4 +#define PAD 1 + +#define STEPS 10 + +#define IMAGE_WIDTH (PAD + STEPS * (STAMP_WIDTH + PAD) + PAD) +#define IMAGE_HEIGHT (PAD + STEPS * (STAMP_HEIGHT + PAD) + PAD) + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface; + uint32_t data[STAMP_WIDTH * STAMP_HEIGHT] = { + 0xffffffff, 0xffffffff, 0xffff0000, 0xffff0000, + 0xffffffff, 0xffffffff, 0xffff0000, 0xffff0000, + + 0xff00ff00, 0xff00ff00, 0xff0000ff, 0xff0000ff, + 0xff00ff00, 0xff00ff00, 0xff0000ff, 0xff0000ff + }; + int i, j; + + /* fill with off-white to avoid a separate rgb24 ref image */ + cairo_save (cr); + cairo_set_source_rgb (cr, .7, .7, .7); + cairo_paint (cr); + cairo_restore (cr); + + /* Draw reference lines where the jump should be. */ + cairo_move_to (cr, PAD + STEPS / 2 * (STAMP_WIDTH + PAD), 0); + cairo_rel_line_to (cr, 0, IMAGE_HEIGHT); + cairo_move_to (cr, 0, PAD + STEPS / 2 * (STAMP_HEIGHT + PAD)); + cairo_rel_line_to (cr, IMAGE_WIDTH, 0); + cairo_set_line_width (cr, 2.0); + cairo_stroke (cr); + + surface = cairo_image_surface_create_for_data ((unsigned char *) data, + CAIRO_FORMAT_RGB24, + STAMP_WIDTH, + STAMP_HEIGHT, + STAMP_WIDTH * 4); + + for (j=0; j < STEPS; j++) { + double j_step; + + for (i=0; i < STEPS; i++) { + double i_step; + +#define GENERATE_REFERENCE_IMAGE 0 +#if GENERATE_REFERENCE_IMAGE + i_step = i >= STEPS / 2 ? 1 : 0; + j_step = j >= STEPS / 2 ? 1 : 0; +#else + i_step = i * 1.0 / STEPS; + j_step = j * 1.0 / STEPS; +#endif + + cairo_save (cr); + + cairo_set_source_surface (cr, surface, + PAD + i * (STAMP_WIDTH + PAD) + i_step, + PAD + j * (STAMP_HEIGHT + PAD) + j_step); + cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); + cairo_paint (cr); + + cairo_restore (cr); + } + } + + cairo_surface_finish (surface); /* data goes out of scope */ + cairo_surface_destroy (surface); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (filter_nearest_offset, + "Test sampling offset of CAIRO_FILTER_NEAREST" + "\nwrong sampling location for nearest-neighbor filter in libpixman and Render", + "filter", /* keywords */ + NULL, /* requirements */ + IMAGE_WIDTH, IMAGE_HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/filter-nearest-transformed.c b/local/recipes/libs/cairo/source/test/filter-nearest-transformed.c new file mode 100644 index 0000000000..ba56f7c5a0 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/filter-nearest-transformed.c @@ -0,0 +1,120 @@ +/* + * Copyright © 2008 Chris Wilson + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +/* + * We wish to check the optimization away of non-fractional translations + * for NEAREST surface patterns under a few transformations. + */ + +static const char png_filename[] = "romedalen.png"; + +/* A single, black pixel */ +static const uint32_t black_pixel = 0xff000000; + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + unsigned int i, j, k; + cairo_surface_t *surface; + cairo_pattern_t *pattern; + const cairo_matrix_t transform[] = { + { 1, 0, 0, 1, 0, 0 }, + { -1, 0, 0, 1, 8, 0 }, + { 1, 0, 0, -1, 0, 8 }, + { -1, 0, 0, -1, 8, 8 }, + }; + const cairo_matrix_t ctx_transform[] = { + { 1, 0, 0, 1, 0, 0 }, + { -1, 0, 0, 1, 14, 0 }, + { 1, 0, 0, -1, 0, 14 }, + { -1, 0, 0, -1, 14, 14 }, + }; + const double colour[][3] = { + {0, 0, 0}, + {1, 0, 0}, + {0, 1, 0}, + {0, 0, 1}, + }; + cairo_matrix_t m; + + surface = cairo_image_surface_create_for_data ((uint8_t *) &black_pixel, + CAIRO_FORMAT_ARGB32, + 1, 1, 4); + pattern = cairo_pattern_create_for_surface (surface); + cairo_surface_destroy (surface); + + cairo_pattern_set_filter (pattern, CAIRO_FILTER_NEAREST); + + surface = cairo_test_create_surface_from_png (ctx, png_filename); + + /* Fill background white */ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); + + for (k = 0; k < ARRAY_LENGTH (transform); k++) { + /* draw a "large" section from an image */ + cairo_save (cr); { + cairo_set_matrix(cr, &ctx_transform[k]); + cairo_rectangle (cr, 0, 0, 7, 7); + cairo_clip (cr); + + cairo_set_source_surface (cr, surface, + -cairo_image_surface_get_width (surface)/2., + -cairo_image_surface_get_height (surface)/2.); + cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); + cairo_paint (cr); + } cairo_restore (cr); + + cairo_set_source_rgb (cr, colour[k][0], colour[k][1], colour[k][2]); + for (j = 4; j <= 6; j++) { + for (i = 4; i <= 6; i++) { + cairo_matrix_init_translate (&m, + -(2*(i-4) + .1*i), + -(2*(j-4) + .1*j)); + cairo_matrix_multiply (&m, &m, &transform[k]); + cairo_pattern_set_matrix (pattern, &m); + cairo_mask (cr, pattern); + } + } + } + + cairo_pattern_destroy (pattern); + cairo_surface_destroy (surface); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (filter_nearest_transformed, + "Test sample position when drawing transformed images with FILTER_NEAREST", + "filter, nearest", /* keywords */ + NULL, + 14, 14, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/finer-grained-fallbacks.c b/local/recipes/libs/cairo/source/test/finer-grained-fallbacks.c new file mode 100644 index 0000000000..fa16f72f05 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/finer-grained-fallbacks.c @@ -0,0 +1,180 @@ +/* + * Copyright © 2008 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" + +#define CIRCLE_SIZE 10 +#define PAD 2 +#define WIDTH (CIRCLE_SIZE*6.5 + PAD) +#define HEIGHT (CIRCLE_SIZE*7.0 + PAD) + +static void +draw_circle (cairo_t *cr, double x, double y) +{ + cairo_save (cr); + cairo_translate (cr, x, y); + cairo_arc (cr, 0, 0, CIRCLE_SIZE / 2, 0., 2. * M_PI); + cairo_fill (cr); + cairo_restore (cr); +} + +static void +draw_image_circle (cairo_t *cr, cairo_surface_t *source, double x, double y) +{ + cairo_save (cr); + + cairo_set_source_surface (cr, source, x, y); + cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REFLECT); + cairo_rectangle (cr, x, y, CIRCLE_SIZE, CIRCLE_SIZE); + cairo_fill (cr); + + cairo_restore (cr); +} + +static void +draw_circles (cairo_t *cr) +{ + draw_circle (cr, 0, -CIRCLE_SIZE*0.1); + draw_circle (cr, CIRCLE_SIZE*0.4, CIRCLE_SIZE*0.25); + + draw_circle (cr, CIRCLE_SIZE*2, 0); + draw_circle (cr, CIRCLE_SIZE*4, 0); + draw_circle (cr, CIRCLE_SIZE*6, 0); +} + +static void +draw_image_circles (cairo_t *cr, cairo_surface_t *source) +{ + draw_image_circle (cr, source, 0, -CIRCLE_SIZE*0.1); + draw_image_circle (cr, source, CIRCLE_SIZE*0.4, CIRCLE_SIZE*0.25); + + draw_image_circle (cr, source, CIRCLE_SIZE*2, 0); + draw_image_circle (cr, source, CIRCLE_SIZE*4, 0); + draw_image_circle (cr, source, CIRCLE_SIZE*6, 0); +} + +/* For each of circle and fallback_circle we draw: + * - two overlapping + * - one isolated + * - one off the page + * - one overlapping the edge of the page. + * + * We also draw a circle and fallback_circle overlapping each other. + * + * Circles are drawn in green. An opaque color and CAIRO_OPERATOR_OVER + * is used to ensure they will be emitted as a vectors in PS/PDF. + * + * Fallback circles are drawn in red. CAIRO_OPERATOR_ADD is used to + * ensure they will be emitted as a fallback image in PS/PDF. + * + * In order to trigger a fallback for SVG, we need to use a surface with + * REFLECT. + */ +static cairo_surface_t * +surface_create (cairo_t *target) +{ + cairo_surface_t *surface; + cairo_t *cr; + + surface = cairo_surface_create_similar (cairo_get_target (target), + CAIRO_CONTENT_COLOR_ALPHA, + CIRCLE_SIZE, CIRCLE_SIZE); + cr = cairo_create (surface); + cairo_surface_destroy (surface); + + cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); + draw_circle (cr, CIRCLE_SIZE/2, CIRCLE_SIZE/2); + + surface = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + + return surface; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface; + + cairo_translate (cr, PAD, PAD); + + cairo_save (cr); + + /* Draw overlapping circle and fallback circle */ + cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + draw_circle (cr, CIRCLE_SIZE*0.5, CIRCLE_SIZE*1.5); + + cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); + cairo_set_operator (cr, CAIRO_OPERATOR_ADD); + draw_circle (cr, CIRCLE_SIZE*0.75, CIRCLE_SIZE*1.75); + + /* Draw circles */ + cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_translate (cr, CIRCLE_SIZE*2.5, CIRCLE_SIZE*0.6); + draw_circles (cr); + + /* Draw fallback circles */ + cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); + cairo_set_operator (cr, CAIRO_OPERATOR_ADD); + cairo_translate (cr, 0, CIRCLE_SIZE*2); + draw_circles (cr); + + cairo_restore (cr); + cairo_translate (cr, 0, CIRCLE_SIZE * 3.5); + + /* Draw using fallback surface */ + surface = surface_create (cr); + + cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + draw_circle (cr, CIRCLE_SIZE*0.5, CIRCLE_SIZE*1.5); + + cairo_set_operator (cr, CAIRO_OPERATOR_ADD); + draw_image_circle (cr, surface, CIRCLE_SIZE/4, CIRCLE_SIZE + CIRCLE_SIZE/4); + + /* Draw circles */ + cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_translate (cr, CIRCLE_SIZE*2.5, CIRCLE_SIZE*0.6); + draw_circles (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_ADD); + cairo_translate (cr, -CIRCLE_SIZE/2, CIRCLE_SIZE*1.5); + draw_image_circles (cr, surface); + + cairo_surface_destroy (surface); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (finer_grained_fallbacks, + "Test that multiple PS/PDF fallback images in various locations are correct", + "fallbacks", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/font-face-get-type.c b/local/recipes/libs/cairo/source/test/font-face-get-type.c new file mode 100644 index 0000000000..afbb73944d --- /dev/null +++ b/local/recipes/libs/cairo/source/test/font-face-get-type.c @@ -0,0 +1,79 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + cairo_test_status_t status = CAIRO_TEST_SUCCESS; + cairo_surface_t *surface; + cairo_t *cr; + cairo_font_face_t *font_face; + cairo_scaled_font_t *scaled_font; + + cairo_test_log (ctx, "Creating cairo context and obtaining a font face\n"); + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1); + cr = cairo_create (surface); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + + cairo_test_log (ctx, "Testing return value of cairo_font_face_get_type\n"); + + font_face = cairo_get_font_face (cr); + + if (cairo_font_face_get_type (font_face) != CAIRO_FONT_TYPE_TOY) { + cairo_test_log (ctx, "Unexpected value %d from cairo_font_face_get_type (expected %d)\n", + cairo_font_face_get_type (font_face), CAIRO_FONT_TYPE_TOY); + status = CAIRO_TEST_FAILURE; + goto done; + } + + cairo_test_log (ctx, "Testing return value of cairo_get_scaled_font\n"); + + scaled_font = cairo_get_scaled_font (cr); + + if (cairo_scaled_font_get_font_face (scaled_font) != font_face) { + cairo_test_log (ctx, "Font face returned from the scaled font is different from that returned by the context\n"); + status = CAIRO_TEST_FAILURE; + goto done; + } + +done: + cairo_destroy (cr); + cairo_surface_destroy (surface); + + return status; +} + +CAIRO_TEST (font_face_get_type, + "Check the returned type from cairo_select_font_face.", + "font", /* keywords */ + NULL, /* requirements */ + 0, 0, + preamble, NULL) diff --git a/local/recipes/libs/cairo/source/test/font-matrix-translation.c b/local/recipes/libs/cairo/source/test/font-matrix-translation.c new file mode 100644 index 0000000000..465ac7cf4c --- /dev/null +++ b/local/recipes/libs/cairo/source/test/font-matrix-translation.c @@ -0,0 +1,141 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +#define TEXT_SIZE 12 +#define PAD 4 +#define TEXT "text" + +static cairo_bool_t +text_extents_equal (const cairo_text_extents_t *A, + const cairo_text_extents_t *B) +{ + return A->x_bearing == B->x_bearing && + A->y_bearing == B->y_bearing && + A->width == B->width && + A->height == B->height && + A->x_advance == B->x_advance && + A->y_advance == B->y_advance; +} + +static cairo_test_status_t +box_text (const cairo_test_context_t *ctx, cairo_t *cr, + const char *utf8, + double x, double y) +{ + double line_width; + cairo_text_extents_t extents = {0}, scaled_extents = {0}; + cairo_scaled_font_t *scaled_font; + cairo_status_t status; + + cairo_save (cr); + + cairo_text_extents (cr, utf8, &extents); + + scaled_font = cairo_get_scaled_font (cr); + cairo_scaled_font_text_extents (scaled_font, TEXT, &scaled_extents); + status = cairo_scaled_font_status (scaled_font); + if (status) + return cairo_test_status_from_status (ctx, status); + + if (! text_extents_equal (&extents, &scaled_extents)) { + cairo_test_log (ctx, + "Error: extents differ when they shouldn't:\n" + "cairo_text_extents(); extents (%g, %g, %g, %g, %g, %g)\n" + "cairo_scaled_font_text_extents(); extents (%g, %g, %g, %g, %g, %g)\n", + extents.x_bearing, extents.y_bearing, + extents.width, extents.height, + extents.x_advance, extents.y_advance, + scaled_extents.x_bearing, scaled_extents.y_bearing, + scaled_extents.width, scaled_extents.height, + scaled_extents.x_advance, scaled_extents.y_advance); + return CAIRO_TEST_FAILURE; + } + + line_width = cairo_get_line_width (cr); + cairo_rectangle (cr, + x + extents.x_bearing - line_width / 2, + y + extents.y_bearing - line_width / 2, + extents.width + line_width, + extents.height + line_width); + cairo_stroke (cr); + + cairo_move_to (cr, x, y); + cairo_show_text (cr, utf8); + + cairo_restore (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_test_status_t status; + cairo_text_extents_t extents; + cairo_matrix_t matrix; + + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (cr, TEXT_SIZE); + + cairo_translate (cr, PAD, PAD); + cairo_set_line_width (cr, 1.0); + + cairo_text_extents (cr, TEXT, &extents); + + /* Draw text and bounding box */ + cairo_set_source_rgb (cr, 0, 0, 0); /* black */ + status = box_text (ctx, cr, TEXT, 0, - extents.y_bearing); + if (status) + return status; + + /* Then draw again with the same coordinates, but with a font + * matrix to position the text below and shifted a bit to the + * right. */ + cairo_matrix_init_translate (&matrix, TEXT_SIZE / 2, TEXT_SIZE + PAD); + cairo_matrix_scale (&matrix, TEXT_SIZE, TEXT_SIZE); + cairo_set_font_matrix (cr, &matrix); + + cairo_set_source_rgb (cr, 0, 0, 1); /* blue */ + status = box_text (ctx, cr, TEXT, 0, - extents.y_bearing); + if (status) + return status; + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (font_matrix_translation, + "Test that translation in a font matrix can be used to offset a string", + "font", /* keywords */ + NULL, /* requirements */ + 38, 34, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/font-options.c b/local/recipes/libs/cairo/source/test/font-options.c new file mode 100644 index 0000000000..cfa7584d95 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/font-options.c @@ -0,0 +1,114 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +#include + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + cairo_font_options_t *default_options; + cairo_font_options_t *nil_options; + cairo_surface_t *surface; + cairo_matrix_t identity; + cairo_t *cr; + cairo_scaled_font_t *scaled_font; + + /* first check NULL handling of cairo_font_options_t */ + default_options = cairo_font_options_create (); + assert (cairo_font_options_status (default_options) == CAIRO_STATUS_SUCCESS); + nil_options = cairo_font_options_copy (NULL); + assert (cairo_font_options_status (nil_options) == CAIRO_STATUS_NO_MEMORY); + + assert (cairo_font_options_equal (default_options, default_options)); + assert (! cairo_font_options_equal (default_options, nil_options)); + assert (! cairo_font_options_equal (NULL, nil_options)); + assert (! cairo_font_options_equal (nil_options, nil_options)); + assert (! cairo_font_options_equal (default_options, NULL)); + assert (! cairo_font_options_equal (NULL, default_options)); + + assert (cairo_font_options_hash (default_options) == cairo_font_options_hash (nil_options)); + assert (cairo_font_options_hash (NULL) == cairo_font_options_hash (nil_options)); + assert (cairo_font_options_hash (default_options) == cairo_font_options_hash (NULL)); + + cairo_font_options_merge (NULL, NULL); + cairo_font_options_merge (default_options, NULL); + cairo_font_options_merge (default_options, nil_options); + + cairo_font_options_set_antialias (NULL, CAIRO_ANTIALIAS_DEFAULT); + cairo_font_options_get_antialias (NULL); + assert (cairo_font_options_get_antialias (default_options) == CAIRO_ANTIALIAS_DEFAULT); + + cairo_font_options_set_subpixel_order (NULL, CAIRO_SUBPIXEL_ORDER_DEFAULT); + cairo_font_options_get_subpixel_order (NULL); + assert (cairo_font_options_get_subpixel_order (default_options) == CAIRO_SUBPIXEL_ORDER_DEFAULT); + + cairo_font_options_set_hint_style (NULL, CAIRO_HINT_STYLE_DEFAULT); + cairo_font_options_get_hint_style (NULL); + assert (cairo_font_options_get_hint_style (default_options) == CAIRO_HINT_STYLE_DEFAULT); + + cairo_font_options_set_hint_metrics (NULL, CAIRO_HINT_METRICS_DEFAULT); + cairo_font_options_get_hint_metrics (NULL); + assert (cairo_font_options_get_hint_metrics (default_options) == CAIRO_HINT_METRICS_DEFAULT); + + cairo_font_options_set_color_palette (NULL, CAIRO_COLOR_PALETTE_DEFAULT); + cairo_font_options_get_color_palette (NULL); + assert (cairo_font_options_get_color_palette (default_options) == CAIRO_COLOR_PALETTE_DEFAULT); + + cairo_font_options_destroy (NULL); + cairo_font_options_destroy (default_options); + cairo_font_options_destroy (nil_options); + + + /* Now try creating fonts with NULLs */ + surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 0, 0); + cr = cairo_create (surface); + cairo_surface_destroy (surface); + + cairo_matrix_init_identity (&identity); + scaled_font = cairo_scaled_font_create (cairo_get_font_face (cr), + &identity, &identity, + NULL); + assert (cairo_scaled_font_status (scaled_font) == CAIRO_STATUS_NULL_POINTER); + cairo_scaled_font_get_font_options (scaled_font, NULL); + cairo_scaled_font_destroy (scaled_font); + + assert (cairo_status (cr) == CAIRO_STATUS_SUCCESS); + cairo_get_font_options (cr, NULL); + cairo_set_font_options (cr, NULL); + assert (cairo_status (cr) == CAIRO_STATUS_NULL_POINTER); + + cairo_destroy (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (font_options, + "Check setters and getters on cairo_font_options_t.", + "font, api", /* keywords */ + NULL, /* requirements */ + 0, 0, + preamble, NULL) diff --git a/local/recipes/libs/cairo/source/test/font-variations.c b/local/recipes/libs/cairo/source/test/font-variations.c new file mode 100644 index 0000000000..a1794aa570 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/font-variations.c @@ -0,0 +1,201 @@ +/* + * Copyright © 2017 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: MAtthias Clasen + */ + +#include "cairo-test.h" + +#include + +/* This test requires freetype2 */ +#include +#include FT_FREETYPE_H +#include FT_MULTIPLE_MASTERS_H + +#if CAIRO_HAS_FC_FONT +#include +#endif + +#include "cairo-ft.h" + +#define FloatToFixed(f) ((FT_Fixed)((f)*65536)) + +static cairo_test_status_t +test_variation (cairo_test_context_t *ctx, + const char *input, + const char *tag, + int def, + float expected_value) +{ + cairo_font_face_t *font_face; + cairo_scaled_font_t *scaled_font; + cairo_matrix_t matrix; + cairo_font_options_t *options; + cairo_status_t status; + + FT_Face ft_face; + FT_MM_Var *ft_mm_var; + FT_Error ret; + FT_Fixed coords[20]; + unsigned int i; + +#if CAIRO_HAS_FC_FONT + FcPattern *pattern; + + /* we need a font that has variations */ + pattern = FcPatternBuild (NULL, + FC_FAMILY, FcTypeString, (FcChar8*)"Adobe Variable Font Prototype", + NULL); + font_face = cairo_ft_font_face_create_for_pattern (pattern); + status = cairo_font_face_status (font_face); + FcPatternDestroy (pattern); + + if (status != CAIRO_STATUS_SUCCESS) { + cairo_test_log (ctx, "Failed to create font face"); + return CAIRO_TEST_FAILURE; + } + + cairo_matrix_init_identity (&matrix); + options = cairo_font_options_create (); + if (cairo_font_options_status (options) != CAIRO_STATUS_SUCCESS) { + cairo_test_log (ctx, "Failed to create font options"); + return CAIRO_TEST_FAILURE; + } + + cairo_font_options_set_variations (options, input); + if (cairo_font_options_status (options) != CAIRO_STATUS_SUCCESS) { + cairo_test_log (ctx, "Failed to set variations"); + return CAIRO_TEST_FAILURE; + } + + if (strcmp (cairo_font_options_get_variations (options), input) != 0) { + cairo_test_log (ctx, "Failed to verify variations"); + return CAIRO_TEST_FAILURE; + } + + scaled_font = cairo_scaled_font_create (font_face, &matrix, &matrix, options); + status = cairo_scaled_font_status (scaled_font); + + if (status != CAIRO_STATUS_SUCCESS) { + cairo_test_log (ctx, "Failed to create scaled font"); + return CAIRO_TEST_FAILURE; + } + + ft_face = cairo_ft_scaled_font_lock_face (scaled_font); + if (cairo_scaled_font_status (scaled_font) != CAIRO_STATUS_SUCCESS) { + cairo_test_log (ctx, "Failed to get FT_Face"); + return CAIRO_TEST_FAILURE; + } + if (strcmp (ft_face->family_name, "Adobe Variable Font Prototype") != 0) { + cairo_test_log (ctx, "This test requires the font \"Adobe Variable Font Prototype\" (https://github.com/adobe-fonts/adobe-variable-font-prototype/releases)"); + return CAIRO_TEST_UNTESTED; + } + + ret = FT_Get_MM_Var (ft_face, &ft_mm_var); + if (ret != 0) { + cairo_test_log (ctx, "Failed to get MM"); + return CAIRO_TEST_FAILURE; + } + + ret = FT_Get_Var_Design_Coordinates (ft_face, 20, coords); + if (ret != 0) { + cairo_test_log (ctx, "Failed to get coords"); + return CAIRO_TEST_FAILURE; + } + + for (i = 0; i < ft_mm_var->num_axis; i++) { + FT_Var_Axis *axis = &ft_mm_var->axis[i]; + cairo_test_log (ctx, "axis %s, value %g\n", axis->name, coords[i] / 65536.); + } + for (i = 0; i < ft_mm_var->num_axis; i++) { + FT_Var_Axis *axis = &ft_mm_var->axis[i]; + if (axis->tag == FT_MAKE_TAG(tag[0], tag[1], tag[2], tag[3])) { + if (def) { + if (coords[i] != axis->def) { + cairo_test_log (ctx, "Axis %s: not default value (%g != %g)", + axis->name, coords[i] / 65536., axis->def / 65536.); + return CAIRO_TEST_FAILURE; + } + } + else { + if (coords[i] != FloatToFixed(expected_value)) { + cairo_test_log (ctx, "Axis %s: not expected value (%g != %g)", + axis->name, coords[i] / 65536., expected_value); + return CAIRO_TEST_FAILURE; + } + } + } + else { + } + } + + cairo_ft_scaled_font_unlock_face (scaled_font); + + cairo_scaled_font_destroy (scaled_font); + cairo_font_options_destroy (options); + cairo_font_face_destroy (font_face); + + return CAIRO_TEST_SUCCESS; +#else + return CAIRO_TEST_UNTESTED; +#endif +} + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + cairo_test_status_t status = CAIRO_TEST_SUCCESS; + struct { const char *input; + const char *tag; + int expected_default; + float expected_value; + } tests[] = { + { "wdth=200,wght=300", "wght", 0, 300.0 }, // valid + { "wdth=200.5,wght=300.5", "wght", 0, 300.5 }, // valid, using decimal dot + { "wdth 200 , wght 300", "wght", 0, 300.0 }, // valid, without = + { "wght = 200", "wght", 0, 200.0 }, // valid, whitespace and = + { "CNTR=20", "wght", 1, 0.0 }, // valid, not setting wght + { "weight=100", "wght", 1, 0.0 }, // not a valid tag + { NULL, 0 } + }; + int i; + + for (i = 0; tests[i].input; i++) { + status = test_variation (ctx, + tests[i].input, + tests[i].tag, + tests[i].expected_default, + tests[i].expected_value); + if (status != CAIRO_TEST_SUCCESS) + return status; + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (font_variations, + "Test font variations", + "fonts", /* keywords */ + NULL, /* requirements */ + 9, 11, + preamble, NULL) diff --git a/local/recipes/libs/cairo/source/test/ft-color-font.c b/local/recipes/libs/cairo/source/test/ft-color-font.c new file mode 100644 index 0000000000..d10555dcf0 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/ft-color-font.c @@ -0,0 +1,118 @@ +/* + * Copyright © 2021 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 SIZE 40 +#define HEIGHT SIZE +#define WIDTH (SIZE * 1.5) +#define FONT "Noto Color Emoji" + +static const char smiley_face_utf8[] = { 0xf0, 0x9f, 0x99, 0x82, 0x00 }; /* U+1F642 */ + +static cairo_test_status_t +set_color_emoji_font (cairo_t *cr) +{ + cairo_font_options_t *font_options; + cairo_font_face_t *font_face; + FcPattern *pattern; + FcPattern *resolved; + FcChar8 *font_name; + FcResult result; + + pattern = FcPatternCreate (); + if (pattern == NULL) + return CAIRO_TEST_NO_MEMORY; + + FcPatternAddString (pattern, FC_FAMILY, (FcChar8 *) FONT); + FcConfigSubstitute (NULL, pattern, FcMatchPattern); + + font_options = cairo_font_options_create (); + cairo_get_font_options (cr, font_options); + cairo_ft_font_options_substitute (font_options, pattern); + + FcDefaultSubstitute (pattern); + resolved = FcFontMatch (NULL, pattern, &result); + if (resolved == NULL) { + FcPatternDestroy (pattern); + return CAIRO_TEST_NO_MEMORY; + } + + if (FcPatternGetString (resolved, FC_FAMILY, 0, &font_name) == FcResultMatch) { + if (strcmp((char*)font_name, FONT) != 0) { + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_test_log (ctx, "Could not find %s font\n", FONT); + return CAIRO_TEST_UNTESTED; + } + } else { + return CAIRO_TEST_FAILURE; + } + + font_face = cairo_ft_font_face_create_for_pattern (resolved); + cairo_set_font_face (cr, font_face); + + cairo_font_options_destroy (font_options); + cairo_font_face_destroy (font_face); + FcPatternDestroy (pattern); + FcPatternDestroy (resolved); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_test_status_t result; + cairo_font_options_t *font_options; + + result = set_color_emoji_font (cr); + if (result != CAIRO_TEST_SUCCESS) + return result; + + cairo_set_font_size (cr, SIZE/2); + cairo_move_to (cr, SIZE/8, 0.7 * SIZE); + + cairo_show_text(cr, smiley_face_utf8); + + /* Show that the color mode font option can disable color rendering */ + font_options = cairo_font_options_create (); + cairo_get_font_options (cr, font_options); + 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_show_text(cr, smiley_face_utf8); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (ft_color_font, + "Test color font", + "ft, font", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/ft-font-create-for-ft-face.c b/local/recipes/libs/cairo/source/test/ft-font-create-for-ft-face.c new file mode 100644 index 0000000000..52c838dd49 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/ft-font-create-for-ft-face.c @@ -0,0 +1,228 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" +#include + +static void +_stress_font_cache (FT_Face ft_face, cairo_t *cr, int lvl); + +static cairo_font_face_t * +_load_font (FT_Face ft_face, int flags, cairo_t *cr, int lvl) +{ + cairo_font_face_t *font_face; + cairo_font_extents_t font_extents; + + _stress_font_cache (ft_face, cr, lvl+1); + + font_face = cairo_ft_font_face_create_for_ft_face (ft_face, flags); + + cairo_set_font_face (cr, font_face); + cairo_font_extents (cr, &font_extents); + + _stress_font_cache (ft_face, cr, lvl+1); + + return font_face; +} + +static void +_stress_font_cache (FT_Face ft_face, cairo_t *cr, int lvl) +{ +#define A _load_font (ft_face, 0, cr, lvl) +#define B _load_font (ft_face, FT_LOAD_NO_BITMAP, cr, lvl) +#define C _load_font (ft_face, FT_LOAD_NO_RECURSE, cr, lvl) +#define D _load_font (ft_face, FT_LOAD_FORCE_AUTOHINT, cr, lvl) + + cairo_font_face_t *font_face[4]; + + while (lvl++ < 5) { + font_face[0] = A; font_face[1] = A; + font_face[2] = A; font_face[3] = A; + cairo_font_face_destroy (font_face[0]); + cairo_font_face_destroy (font_face[1]); + cairo_font_face_destroy (font_face[2]); + cairo_font_face_destroy (font_face[3]); + + font_face[0] = A; font_face[1] = B; + font_face[2] = C; font_face[3] = D; + cairo_font_face_destroy (font_face[0]); + cairo_font_face_destroy (font_face[1]); + cairo_font_face_destroy (font_face[2]); + cairo_font_face_destroy (font_face[3]); + + font_face[0] = A; font_face[1] = B; + font_face[2] = C; font_face[3] = D; + cairo_font_face_destroy (font_face[3]); + cairo_font_face_destroy (font_face[2]); + cairo_font_face_destroy (font_face[1]); + cairo_font_face_destroy (font_face[0]); + + font_face[0] = A; + font_face[1] = A; + cairo_font_face_destroy (font_face[0]); + font_face[2] = A; + cairo_font_face_destroy (font_face[1]); + font_face[3] = A; + cairo_font_face_destroy (font_face[2]); + cairo_font_face_destroy (font_face[3]); + + font_face[0] = A; + font_face[1] = B; + cairo_font_face_destroy (font_face[0]); + font_face[2] = C; + cairo_font_face_destroy (font_face[1]); + font_face[3] = D; + cairo_font_face_destroy (font_face[2]); + cairo_font_face_destroy (font_face[3]); + } + +#undef A +#undef B +#undef C +#undef D +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + FcPattern *pattern, *resolved; + FcResult result; + cairo_font_face_t *font_face; + cairo_scaled_font_t *scaled_font; + cairo_font_options_t *font_options; + cairo_font_extents_t font_extents; + cairo_matrix_t font_matrix, ctm; + FT_Face ft_face; + + /* We're trying here to get our hands on _some_ FT_Face but we do + * not at all care which one. So we start with an empty pattern + * and do the minimal substitution on it in order to get a valid + * pattern. + * + * Do not use this in production code! */ + pattern = FcPatternCreate (); + if (! pattern) { + cairo_test_log (ctx, "FcPatternCreate failed.\n"); + return cairo_test_status_from_status (ctx, CAIRO_STATUS_NO_MEMORY); + } + + FcConfigSubstitute (NULL, pattern, FcMatchPattern); + FcDefaultSubstitute (pattern); + resolved = FcFontMatch (NULL, pattern, &result); + if (! resolved) { + FcPatternDestroy (pattern); + cairo_test_log (ctx, "FcFontMatch failed.\n"); + return cairo_test_status_from_status (ctx, CAIRO_STATUS_NO_MEMORY); + } + + font_face = cairo_ft_font_face_create_for_pattern (resolved); + if (cairo_font_face_status (font_face)) { + FcPatternDestroy (resolved); + FcPatternDestroy (pattern); + return cairo_test_status_from_status (ctx, cairo_font_face_status (font_face)); + } + + if (cairo_font_face_get_type (font_face) != CAIRO_FONT_TYPE_FT) { + cairo_test_log (ctx, "Unexpected value from cairo_font_face_get_type: %d (expected %d)\n", + cairo_font_face_get_type (font_face), CAIRO_FONT_TYPE_FT); + cairo_font_face_destroy (font_face); + FcPatternDestroy (resolved); + FcPatternDestroy (pattern); + return CAIRO_TEST_FAILURE; + } + + cairo_matrix_init_identity (&font_matrix); + + cairo_get_matrix (cr, &ctm); + + font_options = cairo_font_options_create (); + + cairo_get_font_options (cr, font_options); + + scaled_font = cairo_scaled_font_create (font_face, + &font_matrix, + &ctm, + font_options); + + cairo_font_options_destroy (font_options); + cairo_font_face_destroy (font_face); + FcPatternDestroy (pattern); + FcPatternDestroy (resolved); + + if (cairo_scaled_font_status (scaled_font)) { + return cairo_test_status_from_status (ctx, + cairo_scaled_font_status (scaled_font)); + } + + if (cairo_scaled_font_get_type (scaled_font) != CAIRO_FONT_TYPE_FT) { + cairo_test_log (ctx, "Unexpected value from cairo_scaled_font_get_type: %d (expected %d)\n", + cairo_scaled_font_get_type (scaled_font), CAIRO_FONT_TYPE_FT); + cairo_scaled_font_destroy (scaled_font); + return CAIRO_TEST_FAILURE; + } + + ft_face = cairo_ft_scaled_font_lock_face (scaled_font); + if (ft_face == NULL) { + cairo_test_log (ctx, "Failed to get an ft_face with cairo_ft_scaled_font_lock_face\n"); + cairo_scaled_font_destroy (scaled_font); + return CAIRO_TEST_FAILURE; + } + + /* phew, that was a lot of work. But at least we didn't ever have + * to call freetype directly, nor did we have to make many (any?) + * assumptions about the current system. + * + * Now, on to the simple thing we actually want to test. + */ + + cairo_save (cr); + + /* First we want to test caching behaviour */ + _stress_font_cache (ft_face, cr, 0); + + /* Set the font_face and force cairo to actually use it for + * something. */ + font_face = cairo_ft_font_face_create_for_ft_face (ft_face, 0); + cairo_set_font_face (cr, font_face); + cairo_font_extents (cr, &font_extents); + + cairo_restore (cr); + + /* Finally, even more cleanup */ + cairo_font_face_destroy (font_face); + cairo_ft_scaled_font_unlock_face (scaled_font); + cairo_scaled_font_destroy (scaled_font); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (ft_font_create_for_ft_face, + "Simple test to verify that cairo_ft_font_create_for_ft_face doesn't crash.", + "ft, font", /* keywords */ + NULL, /* requirements */ + 0, 0, + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/ft-show-glyphs-positioning.c b/local/recipes/libs/cairo/source/test/ft-show-glyphs-positioning.c new file mode 100644 index 0000000000..449f8eb1f2 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/ft-show-glyphs-positioning.c @@ -0,0 +1,191 @@ +/* + * Copyright © 2008 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 TEXT_SIZE 12 + +typedef struct { + cairo_glyph_t glyph_list[100]; + int num_glyphs; + double x; + double y; +} glyph_array_t; + +static void +glyph_array_init (glyph_array_t *glyphs, double x, double y) +{ + glyphs->num_glyphs = 0; + glyphs->x = x; + glyphs->y = y; +} + +static void +glyph_array_rel_move_to (glyph_array_t *glyphs, double x, double y) +{ + glyphs->x += x; + glyphs->y += y; +} + +static void +glyph_array_show (glyph_array_t *glyphs, cairo_t *cr) +{ + cairo_show_glyphs (cr, glyphs->glyph_list, glyphs->num_glyphs); +} + +#define DOUBLE_FROM_26_6(t) ((double)(t) / 64.0) + +static cairo_status_t +glyph_array_add_text(glyph_array_t *glyphs, cairo_t *cr, const char *s, double spacing) +{ + cairo_scaled_font_t *scaled_font; + cairo_status_t status; + FT_Face face; + unsigned long charcode; + unsigned int index; + cairo_text_extents_t extents; + const char *p; + FT_Vector kerning; + double kern_x; + int first = TRUE; + + scaled_font = cairo_get_scaled_font (cr); + status = cairo_scaled_font_status (scaled_font); + if (status) + return status; + + face = cairo_ft_scaled_font_lock_face (scaled_font); + if (face == NULL) + return CAIRO_STATUS_FONT_TYPE_MISMATCH; + + p = s; + while (*p) + { + charcode = *p; + index = FT_Get_Char_Index (face, charcode); + glyphs->glyph_list[glyphs->num_glyphs].index = index; + if (first) { + first = FALSE; + glyphs->glyph_list[glyphs->num_glyphs].x = glyphs->x; + glyphs->glyph_list[glyphs->num_glyphs].y = glyphs->y; + } else { + cairo_glyph_extents (cr, &glyphs->glyph_list[glyphs->num_glyphs - 1], 1, &extents); + FT_Get_Kerning (face, + glyphs->glyph_list[glyphs->num_glyphs - 1].index, + glyphs->glyph_list[glyphs->num_glyphs].index, + FT_KERNING_UNSCALED, + &kerning); + kern_x = DOUBLE_FROM_26_6(kerning.x); + glyphs->glyph_list[glyphs->num_glyphs].x = + glyphs->glyph_list[glyphs->num_glyphs - 1].x + extents.x_advance + kern_x + spacing; + glyphs->glyph_list[glyphs->num_glyphs].y = + glyphs->glyph_list[glyphs->num_glyphs - 1].y + extents.y_advance; + } + + cairo_glyph_extents (cr, &glyphs->glyph_list[glyphs->num_glyphs], 1, &extents); + glyphs->x = glyphs->glyph_list[glyphs->num_glyphs].x + extents.x_advance + spacing; + glyphs->y = glyphs->glyph_list[glyphs->num_glyphs].y + extents.y_advance; + p++; + glyphs->num_glyphs++; + } + + cairo_ft_scaled_font_unlock_face (scaled_font); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + glyph_array_t glyphs; + cairo_font_options_t *font_options; + cairo_status_t status; + + /* paint white so we don't need separate ref images for + * RGB24 and ARGB32 */ + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); + cairo_paint (cr); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (cr, TEXT_SIZE); + + font_options = cairo_font_options_create (); + cairo_get_font_options (cr, font_options); + cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_OFF); + cairo_set_font_options (cr, font_options); + cairo_font_options_destroy (font_options); + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + + glyph_array_init (&glyphs, 1, TEXT_SIZE); + + status = glyph_array_add_text(&glyphs, cr, "AWAY again", 0.0); + if (status) + return cairo_test_status_from_status (ctx, status); + + glyph_array_rel_move_to (&glyphs, TEXT_SIZE*1, 0.0); + status = glyph_array_add_text(&glyphs, cr, "character space", TEXT_SIZE*0.3); + if (status) + return cairo_test_status_from_status (ctx, status); + + glyph_array_show (&glyphs, cr); + + + glyph_array_init (&glyphs, 1, TEXT_SIZE*2 + 4); + + status = glyph_array_add_text(&glyphs, cr, "Increasing", 0.0); + if (status) + return cairo_test_status_from_status (ctx, status); + + glyph_array_rel_move_to (&glyphs, TEXT_SIZE*0.5, 0.0); + status = glyph_array_add_text(&glyphs, cr, "space", 0.0); + if (status) + return cairo_test_status_from_status (ctx, status); + + glyph_array_rel_move_to (&glyphs, TEXT_SIZE*1.0, 0.0); + status = glyph_array_add_text(&glyphs, cr, "between", 0.0); + if (status) + return cairo_test_status_from_status (ctx, status); + + glyph_array_rel_move_to (&glyphs, TEXT_SIZE*1.5, 0.0); + status = glyph_array_add_text(&glyphs, cr, "words", 0.0); + if (status) + return cairo_test_status_from_status (ctx, status); + + glyph_array_show (&glyphs, cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (ft_show_glyphs_positioning, + "Test that the PS/PDF glyph positioning optimizations are correct", + "ft, text", /* keywords */ + NULL, /* requirements */ + 235, (TEXT_SIZE + 4)*2, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/ft-show-glyphs-table.c b/local/recipes/libs/cairo/source/test/ft-show-glyphs-table.c new file mode 100644 index 0000000000..344392f403 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/ft-show-glyphs-table.c @@ -0,0 +1,109 @@ +/* + * Copyright © 2008 Red Hat, Inc. + * + * 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. + * + * Authors: Eugeniy Meshcheryakov + * Adrian Johnson + * Carl Worth + */ + +#include "cairo-test.h" +#include + +#define TEXT_SIZE 20 +#define PAD 10 +#define GRID_SIZE 30 +#define GRID_ROWS 10 +#define GRID_COLS 4 +#define NUM_GLYPHS (GRID_ROWS * GRID_COLS) +#define WIDTH (PAD + GRID_COLS * GRID_SIZE + PAD) +#define HEIGHT (PAD + GRID_ROWS * GRID_SIZE + PAD) + +/* This test was originally inspired by this bug report: + * + * Error when creating pdf charts for new FreeSerifItalic.ttf + * http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=%23474136 + * + * The original assertion failure was fairly boring, but the later + * glyph mispositiing was quite interesting. And it turns out that the + * _cairo_pdf_operators_show_glyphs code is fairly convoluted with a + * code path that wasn't being exercised at all by the test suite. + * + * So this is an attempt to exercise that code path. Apparently laying + * glyphs out vertically in a table like this, (so that there's a + * large change in Y position from one glyph to the next), exercises + * the code well. + */ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_font_options_t *font_options; + cairo_scaled_font_t *scaled_font; + FT_Face face; + FT_ULong charcode; + FT_UInt idx; + int i = 0; + cairo_glyph_t glyphs[NUM_GLYPHS]; + + /* paint white so we don't need separate ref images for + * RGB24 and ARGB32 */ + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); + cairo_paint (cr); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (cr, TEXT_SIZE); + + font_options = cairo_font_options_create (); + cairo_get_font_options (cr, font_options); + cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_OFF); + cairo_set_font_options (cr, font_options); + cairo_font_options_destroy (font_options); + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + + scaled_font = cairo_get_scaled_font (cr); + face = cairo_ft_scaled_font_lock_face (scaled_font); + { + charcode = FT_Get_First_Char(face, &idx); + while (idx && (i < NUM_GLYPHS)) { + glyphs[i] = (cairo_glyph_t) {idx, PAD + GRID_SIZE * (i/GRID_ROWS), PAD + TEXT_SIZE + GRID_SIZE * (i%GRID_ROWS)}; + i++; + charcode = FT_Get_Next_Char(face, charcode, &idx); + } + } + cairo_ft_scaled_font_unlock_face (scaled_font); + + cairo_show_glyphs(cr, glyphs, i); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (ft_show_glyphs_table, + "Test cairo_show_glyphs with cairo-ft backend and glyphs laid out in a table", + "ft, text", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/ft-svg-cairo-logo.c b/local/recipes/libs/cairo/source/test/ft-svg-cairo-logo.c new file mode 100644 index 0000000000..22fb25f234 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/ft-svg-cairo-logo.c @@ -0,0 +1,66 @@ +/* + * 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 FONT_SIZE 200 +#define MARGIN 5 +#define WIDTH (FONT_SIZE + MARGIN*2) +#define HEIGHT (FONT_SIZE + MARGIN*2) + +#define FONT_FILE "cairo-logo-font.ttf" + +/* Character code in font of the logo */ +#define CAIRO_LOGO_CHAR "A" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_test_status_t result; + + 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; + + cairo_set_font_size (cr, FONT_SIZE); + cairo_move_to (cr, MARGIN, FONT_SIZE + MARGIN); + + cairo_show_text (cr, CAIRO_LOGO_CHAR); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (ft_svg_cairo_logo, + "Test cairo logo SVG font", + "svgrender", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/ft-svg-color-font.c b/local/recipes/libs/cairo/source/test/ft-svg-color-font.c new file mode 100644 index 0000000000..56510feca8 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/ft-svg-color-font.c @@ -0,0 +1,146 @@ +/* + * 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 FONT_SIZE 50 +#define MARGIN 5 +#define WIDTH (FONT_SIZE*4 + MARGIN*2) +#define HEIGHT (FONT_SIZE*3 + MARGIN*5) + +/* Check the full name to ensure we got an SVG font. */ +#define FONT_FAMILY "Twitter Color Emoji" +#define FONT_FULLNAME "Twitter Color Emoji SVGinOT" + +static const char spade_utf8[] = { 0xe2, 0x99, 0xa0, 0x00 }; /* U+2660 glyph 87 */ +static const char club_utf8[] = { 0xe2, 0x99, 0xa3, 0x00 }; /* U+2663 glyph 88 */ +static const char heart_utf8[] = { 0xe2, 0x99, 0xa5, 0x00 }; /* U+2665 glyph 89 */ +static const char diamond_utf8[] = { 0xe2, 0x99, 0xa6, 0x00 }; /* U+2666 glyph 90 */ + +static cairo_test_status_t +set_color_emoji_font (cairo_t *cr) +{ + cairo_font_options_t *font_options; + cairo_font_face_t *font_face; + FcPattern *pattern; + FcPattern *resolved; + FcChar8 *font_name; + FcResult result; + + pattern = FcPatternCreate (); + if (pattern == NULL) + return CAIRO_TEST_NO_MEMORY; + + FcPatternAddString (pattern, FC_FAMILY, (FcChar8 *) FONT_FAMILY); + FcConfigSubstitute (NULL, pattern, FcMatchPattern); + + font_options = cairo_font_options_create (); + cairo_get_font_options (cr, font_options); + cairo_ft_font_options_substitute (font_options, pattern); + + FcDefaultSubstitute (pattern); + resolved = FcFontMatch (NULL, pattern, &result); + if (resolved == NULL) { + FcPatternDestroy (pattern); + return CAIRO_TEST_NO_MEMORY; + } + + if (FcPatternGetString (resolved, FC_FULLNAME, 0, &font_name) == FcResultMatch) { + if (strcmp((char*)font_name, FONT_FULLNAME) != 0) { + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_test_log (ctx, "Could not find %s font\n", FONT_FULLNAME); + return CAIRO_TEST_UNTESTED; + } + } else { + return CAIRO_TEST_FAILURE; + } + + font_face = cairo_ft_font_face_create_for_pattern (resolved); + cairo_set_font_face (cr, font_face); + + cairo_font_options_destroy (font_options); + cairo_font_face_destroy (font_face); + FcPatternDestroy (pattern); + FcPatternDestroy (resolved); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_font_options_t *font_options; + cairo_test_status_t result; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + + result = set_color_emoji_font (cr); + if (result != CAIRO_TEST_SUCCESS) + return result; + + cairo_set_font_size (cr, FONT_SIZE); + + /* Color glyphs */ + cairo_move_to (cr, MARGIN, FONT_SIZE + MARGIN); + cairo_show_text (cr, diamond_utf8); + cairo_show_text (cr, club_utf8); + cairo_show_text (cr, heart_utf8); + cairo_show_text (cr, spade_utf8); + + /* Non-color glyphs */ + 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_move_to (cr, MARGIN, FONT_SIZE*2 + MARGIN*2); + cairo_show_text (cr, diamond_utf8); + cairo_show_text (cr, club_utf8); + cairo_show_text (cr, heart_utf8); + cairo_show_text (cr, spade_utf8); + + /* Color glyph text path */ + cairo_font_options_set_color_mode (font_options, CAIRO_COLOR_MODE_COLOR); + cairo_set_font_options (cr, font_options); + cairo_font_options_destroy (font_options); + cairo_move_to (cr, MARGIN, FONT_SIZE*3 + MARGIN*3); + cairo_text_path (cr, diamond_utf8); + cairo_text_path (cr, club_utf8); + cairo_text_path (cr, heart_utf8); + cairo_text_path (cr, spade_utf8); + cairo_set_line_width (cr, 1); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (ft_svg_color_font, + "Test color font", + "svgrender", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/ft-svg-render-color.c b/local/recipes/libs/cairo/source/test/ft-svg-render-color.c new file mode 100644 index 0000000000..c7572d5b0e --- /dev/null +++ b/local/recipes/libs/cairo/source/test/ft-svg-render-color.c @@ -0,0 +1,98 @@ +/* + * Copyright © 2023 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 FONT_SIZE 50 +#define MARGIN 5 +#define WIDTH (FONT_SIZE*8 + MARGIN*9) +#define HEIGHT (FONT_SIZE*2 + MARGIN*3) + +#define FONT_FILE "cairo-svg-test-color.ttf" + +#define PALETTE_TEXT "01" +#define FOREGROUND_TEXT "234567" + + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_test_status_t result; + 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; + + cairo_set_font_size (cr, FONT_SIZE); + + cairo_save (cr); + cairo_move_to (cr, MARGIN, FONT_SIZE + MARGIN); + font_options = cairo_font_options_create (); + + /* Default palette */ + cairo_show_text (cr, PALETTE_TEXT); + + /* Palette 1 */ + cairo_font_options_set_color_palette (font_options, 1); + cairo_set_font_options (cr, font_options); + cairo_show_text (cr, PALETTE_TEXT); + + /* Palette 0, override color 0 */ + cairo_font_options_set_color_palette (font_options, 0); + cairo_font_options_set_custom_palette_color (font_options, 0, 1, 0, 1, 0.5); + cairo_set_font_options (cr, font_options); + cairo_show_text (cr, PALETTE_TEXT); + + /* Palette 1, override color 1 */ + cairo_font_options_set_color_palette (font_options, 1); + cairo_font_options_set_custom_palette_color (font_options, 1, 0, 1, 1, 0.5); + cairo_set_font_options (cr, font_options); + cairo_show_text (cr, PALETTE_TEXT); + + cairo_font_options_destroy (font_options); + cairo_restore (cr); + + cairo_move_to (cr, MARGIN, FONT_SIZE*2 + MARGIN*2); + + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_show_text (cr, FOREGROUND_TEXT); + + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (ft_svg_render_color, + "Test cairo SVG font colors", + "svgrender", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/ft-svg-render.c b/local/recipes/libs/cairo/source/test/ft-svg-render.c new file mode 100644 index 0000000000..9b0351b100 --- /dev/null +++ b/local/recipes/libs/cairo/source/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/local/recipes/libs/cairo/source/test/ft-text-antialias-none.c b/local/recipes/libs/cairo/source/test/ft-text-antialias-none.c new file mode 100644 index 0000000000..64eea64f97 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/ft-text-antialias-none.c @@ -0,0 +1,146 @@ +/* + * Copyright © 2006 Jinghua Luo + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * JINGHUA LUO DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Jinghua Luo + * Derived from: + * text-antialias-none.c, + * ft-font-create-for-ft-face.c. + * Original Author: Carl D. Worth + */ +#include "cairo-test.h" +#include + +#define WIDTH 40 +#define HEIGHT 30 +#define TEXT_SIZE 12 + +static cairo_status_t +create_scaled_font (cairo_t * cr, + cairo_scaled_font_t **out) +{ + FcPattern *pattern, *resolved; + FcResult result; + cairo_font_face_t *font_face; + cairo_scaled_font_t *scaled_font; + cairo_font_options_t *font_options; + cairo_matrix_t font_matrix, ctm; + cairo_status_t status; + double pixel_size; + + font_options = cairo_font_options_create (); + + cairo_get_font_options (cr, font_options); + + pattern = FcPatternCreate (); + if (pattern == NULL) + return CAIRO_STATUS_NO_MEMORY; + + FcPatternAddString (pattern, FC_FAMILY, (FcChar8 *) CAIRO_TEST_FONT_FAMILY " Sans"); + FcPatternAddDouble (pattern, FC_SIZE, TEXT_SIZE); + FcConfigSubstitute (NULL, pattern, FcMatchPattern); + + cairo_ft_font_options_substitute (font_options, pattern); + + FcDefaultSubstitute (pattern); + resolved = FcFontMatch (NULL, pattern, &result); + if (resolved == NULL) { + FcPatternDestroy (pattern); + return CAIRO_STATUS_NO_MEMORY; + } + + /* turn antialiasing off */ + FcPatternDel (resolved, FC_ANTIALIAS); + FcPatternAddBool (resolved, FC_ANTIALIAS, FcFalse); + + FcPatternGetDouble (resolved, FC_PIXEL_SIZE, 0, &pixel_size); + + font_face = cairo_ft_font_face_create_for_pattern (resolved); + + cairo_matrix_init_identity (&font_matrix); + cairo_matrix_scale (&font_matrix, pixel_size, pixel_size); + + cairo_get_matrix (cr, &ctm); + + scaled_font = cairo_scaled_font_create (font_face, + &font_matrix, + &ctm, + font_options); + + cairo_font_options_destroy (font_options); + cairo_font_face_destroy (font_face); + FcPatternDestroy (pattern); + FcPatternDestroy (resolved); + + status = cairo_scaled_font_status (scaled_font); + if (status) { + cairo_scaled_font_destroy (scaled_font); + return status; + } + + *out = scaled_font; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_text_extents_t extents; + cairo_scaled_font_t *scaled_font; + cairo_status_t status; + const char black[] = "black", blue[] = "blue"; + + /* We draw in the default black, so paint white first. */ + cairo_save (cr); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_restore (cr); + + status = create_scaled_font (cr, &scaled_font); + if (status) { + return cairo_test_status_from_status (cairo_test_get_context (cr), + status); + } + + cairo_set_scaled_font (cr, scaled_font); + + cairo_set_source_rgb (cr, 0, 0, 0); /* black */ + cairo_text_extents (cr, black, &extents); + cairo_move_to (cr, -extents.x_bearing, -extents.y_bearing); + cairo_show_text (cr, black); + cairo_translate (cr, 0, -extents.y_bearing + 1); + + cairo_set_source_rgb (cr, 0, 0, 1); /* blue */ + cairo_text_extents (cr, blue, &extents); + cairo_move_to (cr, -extents.x_bearing, -extents.y_bearing); + cairo_show_text (cr, blue); + + cairo_scaled_font_destroy (scaled_font); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (ft_text_antialias_none, + "Tests text rendering with no antialiasing", + "ft, text", /* keywords */ + "target=raster", /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/ft-text-vertical-layout-type1.c b/local/recipes/libs/cairo/source/test/ft-text-vertical-layout-type1.c new file mode 100644 index 0000000000..c6f26a66ab --- /dev/null +++ b/local/recipes/libs/cairo/source/test/ft-text-vertical-layout-type1.c @@ -0,0 +1,167 @@ +/* + * Copyright © 2006 Jinghua Luo + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * JINGHUA LUO DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Jinghua Luo + * Derived from: + * text-antialias-none.c, + * ft-font-create-for-ft-face.c. + * Original Author: Carl D. Worth + */ +#include "cairo-test.h" +#include + +#define WIDTH 80 +#define HEIGHT 240 +#define TEXT_SIZE 30 + +static cairo_status_t +create_scaled_font (cairo_t * cr, + cairo_scaled_font_t **out) +{ + FcPattern *pattern, *resolved; + FcResult result; + cairo_font_face_t *font_face; + cairo_scaled_font_t *scaled_font; + cairo_font_options_t *font_options; + cairo_matrix_t font_matrix, ctm; + cairo_status_t status; + double pixel_size; + + font_options = cairo_font_options_create (); + + cairo_get_font_options (cr, font_options); + + pattern = FcPatternCreate (); + if (pattern == NULL) + return CAIRO_STATUS_NO_MEMORY; + + FcPatternAddString (pattern, FC_FAMILY, (FcChar8 *)"Nimbus Sans L"); + FcPatternAddDouble (pattern, FC_PIXEL_SIZE, TEXT_SIZE); + FcConfigSubstitute (NULL, pattern, FcMatchPattern); + + cairo_ft_font_options_substitute (font_options, pattern); + + FcDefaultSubstitute (pattern); + resolved = FcFontMatch (NULL, pattern, &result); + if (resolved == NULL) { + FcPatternDestroy (pattern); + return CAIRO_STATUS_NO_MEMORY; + } + + /* set layout to vertical */ + FcPatternDel (resolved, FC_VERTICAL_LAYOUT); + FcPatternAddBool (resolved, FC_VERTICAL_LAYOUT, FcTrue); + + FcPatternGetDouble (resolved, FC_PIXEL_SIZE, 0, &pixel_size); + + font_face = cairo_ft_font_face_create_for_pattern (resolved); + + cairo_matrix_init_translate (&font_matrix, 10, 30); + cairo_matrix_rotate (&font_matrix, M_PI_2/3); + cairo_matrix_scale (&font_matrix, pixel_size, pixel_size); + + cairo_get_matrix (cr, &ctm); + + scaled_font = cairo_scaled_font_create (font_face, + &font_matrix, + &ctm, + font_options); + + cairo_font_options_destroy (font_options); + cairo_font_face_destroy (font_face); + FcPatternDestroy (pattern); + FcPatternDestroy (resolved); + + status = cairo_scaled_font_status (scaled_font); + if (status) { + cairo_scaled_font_destroy (scaled_font); + return status; + } + + *out = scaled_font; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_text_extents_t extents; + cairo_scaled_font_t *scaled_font; + cairo_status_t status; + const char text[] = "i-W"; + double line_width, x, y; + + line_width = cairo_get_line_width (cr); + + /* We draw in the default black, so paint white first. */ + cairo_save (cr); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_restore (cr); + + status = create_scaled_font (cr, &scaled_font); + if (status) { + return cairo_test_status_from_status (cairo_test_get_context (cr), + status); + } + + cairo_set_scaled_font (cr, scaled_font); + cairo_scaled_font_destroy (scaled_font); + + cairo_set_line_width (cr, 1.0); + cairo_set_source_rgb (cr, 0, 0, 0); /* black */ + cairo_text_extents (cr, text, &extents); + x = width - (extents.width + extents.x_bearing) - 5; + y = height - (extents.height + extents.y_bearing) - 5; + cairo_move_to (cr, x, y); + cairo_show_text (cr, text); + cairo_rectangle (cr, + x + extents.x_bearing - line_width / 2, + y + extents.y_bearing - line_width / 2, + extents.width + line_width, + extents.height + line_width); + cairo_stroke (cr); + + cairo_set_source_rgb (cr, 0, 0, 1); /* blue */ + cairo_text_extents (cr, text, &extents); + x = -extents.x_bearing + 5; + y = -extents.y_bearing + 5; + cairo_move_to (cr, x, y); + cairo_text_path (cr, text); + cairo_fill (cr); + cairo_rectangle (cr, + x + extents.x_bearing - line_width / 2, + y + extents.y_bearing - line_width / 2, + extents.width + line_width, + extents.height + line_width); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (ft_text_vertical_layout_type1, + "Tests text rendering for vertical layout with Type1 fonts" + "\nCan fail if an incorrect font is loaded---need to bundle the desired font", + "ft, fc, text", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/ft-text-vertical-layout-type3.c b/local/recipes/libs/cairo/source/test/ft-text-vertical-layout-type3.c new file mode 100644 index 0000000000..0cea9dd80e --- /dev/null +++ b/local/recipes/libs/cairo/source/test/ft-text-vertical-layout-type3.c @@ -0,0 +1,166 @@ +/* + * Copyright © 2006 Jinghua Luo + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * JINGHUA LUO DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Jinghua Luo + * Derived from: + * text-antialias-none.c, + * ft-font-create-for-ft-face.c. + * Original Author: Carl D. Worth + */ +#include "cairo-test.h" +#include + +#define WIDTH 80 +#define HEIGHT 200 +#define TEXT_SIZE 30 + +static cairo_status_t +create_scaled_font (cairo_t * cr, + cairo_scaled_font_t **out) +{ + FcPattern *pattern, *resolved; + FcResult result; + cairo_font_face_t *font_face; + cairo_scaled_font_t *scaled_font; + cairo_font_options_t *font_options; + cairo_matrix_t font_matrix, ctm; + cairo_status_t status; + double pixel_size; + + font_options = cairo_font_options_create (); + + cairo_get_font_options (cr, font_options); + + pattern = FcPatternCreate (); + if (pattern == NULL) + return CAIRO_STATUS_NO_MEMORY; + + FcPatternAddString (pattern, FC_FAMILY, (FcChar8 *)CAIRO_TEST_FONT_FAMILY " Sans"); + FcPatternAddDouble (pattern, FC_PIXEL_SIZE, TEXT_SIZE); + FcConfigSubstitute (NULL, pattern, FcMatchPattern); + + cairo_ft_font_options_substitute (font_options, pattern); + + FcDefaultSubstitute (pattern); + resolved = FcFontMatch (NULL, pattern, &result); + if (resolved == NULL) { + FcPatternDestroy (pattern); + return CAIRO_STATUS_NO_MEMORY; + } + + /* set layout to vertical */ + FcPatternDel (resolved, FC_VERTICAL_LAYOUT); + FcPatternAddBool (resolved, FC_VERTICAL_LAYOUT, FcTrue); + + FcPatternGetDouble (resolved, FC_PIXEL_SIZE, 0, &pixel_size); + + font_face = cairo_ft_font_face_create_for_pattern (resolved); + + cairo_matrix_init_translate (&font_matrix, 10, 30); + cairo_matrix_rotate (&font_matrix, M_PI_2/3); + cairo_matrix_scale (&font_matrix, pixel_size, pixel_size); + + cairo_get_matrix (cr, &ctm); + + scaled_font = cairo_scaled_font_create (font_face, + &font_matrix, + &ctm, + font_options); + + cairo_font_options_destroy (font_options); + cairo_font_face_destroy (font_face); + FcPatternDestroy (pattern); + FcPatternDestroy (resolved); + + status = cairo_scaled_font_status (scaled_font); + if (status) { + cairo_scaled_font_destroy (scaled_font); + return status; + } + + *out = scaled_font; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_text_extents_t extents; + cairo_scaled_font_t *scaled_font; + cairo_status_t status; + const char text[] = "i-W"; + double line_width, x, y; + + line_width = cairo_get_line_width (cr); + + /* We draw in the default black, so paint white first. */ + cairo_save (cr); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_restore (cr); + + status = create_scaled_font (cr, &scaled_font); + if (status) { + return cairo_test_status_from_status (cairo_test_get_context (cr), + status); + } + + cairo_set_scaled_font (cr, scaled_font); + cairo_scaled_font_destroy (scaled_font); + + cairo_set_line_width (cr, 1.0); + cairo_set_source_rgb (cr, 0, 0, 0); /* black */ + cairo_text_extents (cr, text, &extents); + x = width - (extents.width + extents.x_bearing) - 5; + y = height - (extents.height + extents.y_bearing) - 5; + cairo_move_to (cr, x, y); + cairo_show_text (cr, text); + cairo_rectangle (cr, + x + extents.x_bearing - line_width / 2, + y + extents.y_bearing - line_width / 2, + extents.width + line_width, + extents.height + line_width); + cairo_stroke (cr); + + cairo_set_source_rgb (cr, 0, 0, 1); /* blue */ + cairo_text_extents (cr, text, &extents); + x = -extents.x_bearing + 5; + y = -extents.y_bearing + 5; + cairo_move_to (cr, x, y); + cairo_text_path (cr, text); + cairo_fill (cr); + cairo_rectangle (cr, + x + extents.x_bearing - line_width / 2, + y + extents.y_bearing - line_width / 2, + extents.width + line_width, + extents.height + line_width); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (ft_text_vertical_layout_type3, + "Tests text rendering for vertical layout with TrueType fonts", + "ft, fc, text", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/ft-variable-font.c b/local/recipes/libs/cairo/source/test/ft-variable-font.c new file mode 100644 index 0000000000..2adba66dde --- /dev/null +++ b/local/recipes/libs/cairo/source/test/ft-variable-font.c @@ -0,0 +1,127 @@ +/* + * Copyright © 2021 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 SIZE 200 +#define HEIGHT SIZE +#define WIDTH (SIZE * 1.5) +#define FONT "Noto Sans" + +static cairo_test_status_t +set_variable_font (cairo_t *cr) +{ + cairo_font_options_t *font_options; + cairo_font_face_t *font_face; + FcPattern *pattern; + FcPattern *resolved; + FcChar8 *font_name; + FcBool variable; + FcResult result; + + pattern = FcPatternCreate (); + if (pattern == NULL) + return CAIRO_TEST_NO_MEMORY; + + FcPatternAddString (pattern, FC_FAMILY, (FcChar8 *) FONT); + FcPatternAddBool (pattern, FC_VARIABLE, TRUE); + FcConfigSubstitute (NULL, pattern, FcMatchPattern); + + font_options = cairo_font_options_create (); + cairo_get_font_options (cr, font_options); + cairo_ft_font_options_substitute (font_options, pattern); + + FcDefaultSubstitute (pattern); + resolved = FcFontMatch (NULL, pattern, &result); + if (resolved == NULL) { + FcPatternDestroy (pattern); + return CAIRO_TEST_NO_MEMORY; + } + + if (FcPatternGetString (resolved, FC_FAMILY, 0, &font_name) == FcResultMatch) { + if (strcmp((char*)font_name, FONT) != 0) { + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_test_log (ctx, "Could not find %s font\n", FONT); + return CAIRO_TEST_UNTESTED; + } + } else { + return CAIRO_TEST_FAILURE; + } + if (FcPatternGetBool (resolved, FC_VARIABLE, 0, &variable) == FcResultMatch) { + if (!variable) { + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_test_log (ctx, "Could not find %s font\n", FONT); + return CAIRO_TEST_UNTESTED; + } + } else { + return CAIRO_TEST_FAILURE; + } + + font_face = cairo_ft_font_face_create_for_pattern (resolved); + cairo_set_font_face (cr, font_face); + + cairo_font_options_destroy (font_options); + cairo_font_face_destroy (font_face); + FcPatternDestroy (pattern); + FcPatternDestroy (resolved); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_test_status_t result; + 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 = set_variable_font (cr); + if (result != CAIRO_TEST_SUCCESS) + return result; + + font_options = cairo_font_options_create (); + cairo_font_options_set_variations (font_options, "wght=700"); + cairo_set_font_options (cr, font_options); + cairo_font_options_destroy (font_options); + + cairo_set_font_size (cr, SIZE/2); + cairo_move_to (cr, SIZE/8, 0.7 * SIZE); + + cairo_show_text(cr, "Test"); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (ft_variable_font, + "Test variable font", + "ft, font", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/generate_refs.sh b/local/recipes/libs/cairo/source/test/generate_refs.sh new file mode 100755 index 0000000000..e22aa25487 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/generate_refs.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +# A very simple script. But sufficient, hopefully, for our current purposes. + +cat < + */ + +#include "cairo-test.h" + +typedef struct { + cairo_operator_t op; + double tolerance; + cairo_fill_rule_t fill_rule; + double line_width; + cairo_line_cap_t line_cap; + cairo_line_join_t line_join; + double miter_limit; + cairo_matrix_t matrix; + double dash[5]; + double dash_offset; +} settings_t; + +/* Two sets of settings, no defaults */ +static const settings_t settings[] = { + { + CAIRO_OPERATOR_IN, + 2.0, + CAIRO_FILL_RULE_EVEN_ODD, + 7.7, + CAIRO_LINE_CAP_SQUARE, + CAIRO_LINE_JOIN_ROUND, + 3.14, + {2.0, 0.0, 0.0, 2.0, 5.0, 5.0}, + {0.1, 0.2, 0.3, 0.4, 0.5}, + 2.0 + }, + { + CAIRO_OPERATOR_ATOP, + 5.25, + CAIRO_FILL_RULE_WINDING, + 2.17, + CAIRO_LINE_CAP_ROUND, + CAIRO_LINE_JOIN_BEVEL, + 1000.0, + {-3.0, 1.0, 1.0, -3.0, -4, -4}, + {1.0, 2.0, 3.0, 4.0, 5.0}, + 3.0 + } +}; + +static void +settings_set (cairo_t *cr, const settings_t *settings) +{ + cairo_set_operator (cr, settings->op); + cairo_set_tolerance (cr, settings->tolerance); + cairo_set_fill_rule (cr, settings->fill_rule); + cairo_set_line_width (cr, settings->line_width); + cairo_set_line_cap (cr, settings->line_cap); + cairo_set_line_join (cr, settings->line_join); + cairo_set_miter_limit (cr, settings->miter_limit); + cairo_set_matrix (cr, &settings->matrix); + cairo_set_dash (cr, settings->dash, 5, settings->dash_offset); +} + +static int +settings_get (cairo_t *cr, settings_t *settings) +{ + int count; + + settings->op = cairo_get_operator (cr); + settings->tolerance = cairo_get_tolerance (cr); + settings->fill_rule = cairo_get_fill_rule (cr); + settings->line_width = cairo_get_line_width (cr); + settings->line_cap = cairo_get_line_cap (cr); + settings->line_join = cairo_get_line_join (cr); + settings->miter_limit = cairo_get_miter_limit (cr); + cairo_get_matrix (cr, &settings->matrix); + + count = cairo_get_dash_count (cr); + if (count != 5) + return -1; + + cairo_get_dash (cr, settings->dash, &settings->dash_offset); + + return 0; +} + +static int +settings_equal (const settings_t *a, const settings_t *b) +{ + return (a->op == b->op && + a->tolerance == b->tolerance && + a->fill_rule == b->fill_rule && + a->line_width == b->line_width && + a->line_cap == b->line_cap && + a->line_join == b->line_join && + a->miter_limit == b->miter_limit && + a->matrix.xx == b->matrix.xx && + a->matrix.xy == b->matrix.xy && + a->matrix.x0 == b->matrix.x0 && + a->matrix.yx == b->matrix.yx && + a->matrix.yy == b->matrix.yy && + a->matrix.y0 == b->matrix.y0 && + memcmp(a->dash, b->dash, sizeof(a->dash)) == 0 && + a->dash_offset == b->dash_offset); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + settings_t check; + + settings_set (cr, &settings[0]); + + cairo_save (cr); + { + settings_set (cr, &settings[1]); + if (settings_get (cr, &check)) + return CAIRO_TEST_FAILURE; + + if (!settings_equal (&settings[1], &check)) + return CAIRO_TEST_FAILURE; + } + cairo_restore (cr); + + if (settings_get (cr, &check)) + return CAIRO_TEST_FAILURE; + + if (!settings_equal (&settings[0], &check)) + return CAIRO_TEST_FAILURE; + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (get_and_set, + "Tests calls to the most trivial cairo_get and cairo_set functions", + "api", /* keywords */ + NULL, /* requirements */ + 0, 0, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/get-clip.c b/local/recipes/libs/cairo/source/test/get-clip.c new file mode 100644 index 0000000000..f97db3f622 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/get-clip.c @@ -0,0 +1,264 @@ +/* + * Copyright © 2006 Novell, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Novell, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Novell, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Robert O'Callahan + */ + +#include "cairo-test.h" +#include + +static cairo_bool_t +check_count (const cairo_test_context_t *ctx, + const char *message, + cairo_rectangle_list_t *list, int expected) +{ + if (list->status != CAIRO_STATUS_SUCCESS) { + cairo_test_log (ctx, "Error: %s; cairo_copy_clip_rectangle_list failed with \"%s\"\n", + message, cairo_status_to_string(list->status)); + return 0; + } + + if (list->num_rectangles == expected) + return 1; + cairo_test_log (ctx, "Error: %s; expected %d rectangles, got %d\n", message, + expected, list->num_rectangles); + return 0; +} + +static cairo_bool_t +check_unrepresentable (const cairo_test_context_t *ctx, const char *message, cairo_rectangle_list_t *list) +{ + if (list->status != CAIRO_STATUS_CLIP_NOT_REPRESENTABLE) { + cairo_test_log (ctx, "Error: %s; cairo_copy_clip_rectangle_list got unexpected result \"%s\"\n" + " (we expected CAIRO_STATUS_CLIP_NOT_REPRESENTABLE)", + message, cairo_status_to_string(list->status)); + return 0; + } + return 1; +} + +static cairo_bool_t +check_rectangles_contain (const cairo_test_context_t *ctx, + const char *message, + cairo_rectangle_list_t *list, + double x, double y, double width, double height) +{ + int i; + + for (i = 0; i < list->num_rectangles; ++i) { + if (list->rectangles[i].x == x && list->rectangles[i].y == y && + list->rectangles[i].width == width && list->rectangles[i].height == height) + return 1; + } + cairo_test_log (ctx, "Error: %s; rectangle list does not contain rectangle %f,%f,%f,%f\n", + message, x, y, width, height); + return 0; +} + +static cairo_bool_t +check_clip_extents (const cairo_test_context_t *ctx, + const char *message, cairo_t *cr, + double x, double y, double width, double height) +{ + double ext_x1, ext_y1, ext_x2, ext_y2; + cairo_clip_extents (cr, &ext_x1, &ext_y1, &ext_x2, &ext_y2); + if (ext_x1 == x && ext_y1 == y && ext_x2 == x + width && ext_y2 == y + height) + return 1; + if (width == 0.0 && height == 0.0 && ext_x1 == ext_x2 && ext_y1 == ext_y2) + return 1; + cairo_test_log (ctx, "Error: %s; clip extents %f,%f,%f,%f should be %f,%f,%f,%f\n", + message, ext_x1, ext_y1, ext_x2 - ext_x1, ext_y2 - ext_y1, + x, y, width, height); + return 0; +} + +#define SIZE 100 + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + cairo_surface_t *surface; + cairo_t *cr; + cairo_rectangle_list_t *rectangle_list; + const char *phase; + cairo_bool_t completed = 0; + cairo_status_t status; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, SIZE, SIZE); + cr = cairo_create (surface); + cairo_surface_destroy (surface); + + + /* first, test basic stuff. This should not be clipped, it should + return the surface rectangle. */ + phase = "No clip set"; + rectangle_list = cairo_copy_clip_rectangle_list (cr); + if (! check_count (ctx, phase, rectangle_list, 1) || + ! check_clip_extents (ctx, phase, cr, 0, 0, SIZE, SIZE) || + ! check_rectangles_contain (ctx, phase, rectangle_list, 0, 0, SIZE, SIZE)) + { + goto FAIL; + } + cairo_rectangle_list_destroy (rectangle_list); + + /* We should get the same results after applying a clip that contains the + existing clip. */ + phase = "Clip beyond surface extents"; + cairo_save (cr); + cairo_rectangle (cr, -10, -10, SIZE + 20 , SIZE + 20); + cairo_clip (cr); + rectangle_list = cairo_copy_clip_rectangle_list (cr); + if (! check_count (ctx, phase, rectangle_list, 1) || + ! check_clip_extents (ctx, phase, cr, 0, 0, SIZE, SIZE) || + ! check_rectangles_contain (ctx, phase, rectangle_list, 0, 0, SIZE, SIZE)) + { + goto FAIL; + } + cairo_rectangle_list_destroy (rectangle_list); + cairo_restore (cr); + + /* Test simple clip rect. */ + phase = "Simple clip rect"; + cairo_save (cr); + cairo_rectangle (cr, 10, 10, 80, 80); + cairo_clip (cr); + rectangle_list = cairo_copy_clip_rectangle_list (cr); + if (! check_count (ctx, phase, rectangle_list, 1) || + ! check_clip_extents (ctx, phase, cr, 10, 10, 80, 80) || + ! check_rectangles_contain (ctx, phase, rectangle_list, 10, 10, 80, 80)) + { + goto FAIL; + } + cairo_rectangle_list_destroy (rectangle_list); + cairo_restore (cr); + + /* Test everything clipped out. */ + phase = "All clipped out"; + cairo_save (cr); + cairo_clip (cr); + rectangle_list = cairo_copy_clip_rectangle_list (cr); + if (! check_count (ctx, phase, rectangle_list, 0) || + ! check_clip_extents (ctx, phase, cr, 0, 0, 0, 0)) + { + goto FAIL; + } + cairo_rectangle_list_destroy (rectangle_list); + cairo_restore (cr); + + /* test two clip rects */ + phase = "Two clip rects"; + cairo_save (cr); + cairo_rectangle (cr, 10, 10, 10, 10); + cairo_rectangle (cr, 20, 20, 10, 10); + cairo_clip (cr); + cairo_rectangle (cr, 15, 15, 10, 10); + cairo_clip (cr); + rectangle_list = cairo_copy_clip_rectangle_list (cr); + if (! check_count (ctx, phase, rectangle_list, 2) || + ! check_clip_extents (ctx, phase, cr, 15, 15, 10, 10) || + ! check_rectangles_contain (ctx, phase, rectangle_list, 15, 15, 5, 5) || + ! check_rectangles_contain (ctx, phase, rectangle_list, 20, 20, 5, 5)) + { + goto FAIL; + } + cairo_rectangle_list_destroy (rectangle_list); + cairo_restore (cr); + + /* test non-rectangular clip */ + phase = "Nonrectangular clip"; + cairo_save (cr); + cairo_move_to (cr, 0, 0); + cairo_line_to (cr, 100, 100); + cairo_line_to (cr, 100, 0); + cairo_close_path (cr); + cairo_clip (cr); + rectangle_list = cairo_copy_clip_rectangle_list (cr); + /* can't get this in one tight user-space rectangle */ + if (! check_unrepresentable (ctx, phase, rectangle_list) || + ! check_clip_extents (ctx, phase, cr, 0, 0, 100, 100)) + { + goto FAIL; + } + cairo_rectangle_list_destroy (rectangle_list); + cairo_restore (cr); + + phase = "User space, simple scale, getting clip with same transform"; + cairo_save (cr); + cairo_scale (cr, 2, 2); + cairo_rectangle (cr, 5, 5, 40, 40); + cairo_clip (cr); + rectangle_list = cairo_copy_clip_rectangle_list (cr); + if (! check_count (ctx, phase, rectangle_list, 1) || + ! check_clip_extents (ctx, phase, cr, 5, 5, 40, 40) || + ! check_rectangles_contain (ctx, phase, rectangle_list, 5, 5, 40, 40)) + { + goto FAIL; + } + cairo_rectangle_list_destroy (rectangle_list); + cairo_restore (cr); + + phase = "User space, simple scale, getting clip with no transform"; + cairo_save (cr); + cairo_save (cr); + cairo_scale (cr, 2, 2); + cairo_rectangle (cr, 5, 5, 40, 40); + cairo_restore (cr); + cairo_clip (cr); + rectangle_list = cairo_copy_clip_rectangle_list (cr); + if (! check_count (ctx, phase, rectangle_list, 1) || + ! check_clip_extents (ctx, phase, cr, 10, 10, 80, 80) || + ! check_rectangles_contain (ctx, phase, rectangle_list, 10, 10, 80, 80)) + { + goto FAIL; + } + cairo_rectangle_list_destroy (rectangle_list); + cairo_restore (cr); + + phase = "User space, rotation, getting clip with no transform"; + cairo_save (cr); + cairo_save (cr); + cairo_rotate (cr, 12); + cairo_rectangle (cr, 5, 5, 40, 40); + cairo_restore (cr); + cairo_clip (cr); + rectangle_list = cairo_copy_clip_rectangle_list (cr); + if (! check_unrepresentable (ctx, phase, rectangle_list)) + goto FAIL; + + completed = 1; +FAIL: + cairo_rectangle_list_destroy (rectangle_list); + status = cairo_status (cr); + cairo_destroy (cr); + + if (!completed) + return CAIRO_TEST_FAILURE; + + return cairo_test_status_from_status (ctx, status); +} + +CAIRO_TEST (get_clip, + "Test cairo_copy_clip_rectangle_list and cairo_clip_extents", + "clip, extents", /* keywords */ + NULL, /* requirements */ + 0, 0, + preamble, NULL) diff --git a/local/recipes/libs/cairo/source/test/get-group-target.c b/local/recipes/libs/cairo/source/test/get-group-target.c new file mode 100644 index 0000000000..5aff19b298 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/get-group-target.c @@ -0,0 +1,85 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +#define SIZE 8 +#define PAD 2 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *group; + double x, y; + + /* First paint background in blue. */ + cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); + cairo_paint (cr); + + /* Then clip so that the group surface ends up smaller than the + * original surface. */ + cairo_rectangle (cr, PAD, PAD, width - 2 * PAD, height - 2 * PAD); + cairo_clip (cr); + + /* Paint the clipped region in red (which should all be overwritten later). */ + cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); + cairo_paint (cr); + + /* Redirect to a new group and get that surface. */ + cairo_push_group (cr); + group = cairo_get_group_target (cr); + + /* Then paint in green what we query the group surface size to be. */ + cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); + cairo_surface_get_device_offset (group, &x, &y); + /* Or rather, we calculate the group surface size based on the + * only thing we can query which is the device offset. Ideally, + * the size would always be the minimal (width - 2 * PAD, height - + * 2 * PAD) based on the clip. But currently, group targets are + * created oversized for paginated surfaces, so we only subtract + * anything from the size if there is a non-zero device offfset. + * + * The calculation below might also be less confusing if the sign + * convention on the device offset were reversed, but it is what + * it is. Oh well. */ + cairo_rectangle (cr, + -x, -y, + width + 2 * x, + height + 2 * y); + cairo_fill (cr); + + /* Finish up the group painting. */ + cairo_pop_group_to_source (cr); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (get_group_target, + "Test of both cairo_get_group_target and cairo_surface_get_device_offset", + "api", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/get-path-extents.c b/local/recipes/libs/cairo/source/test/get-path-extents.c new file mode 100644 index 0000000000..080fc34c49 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/get-path-extents.c @@ -0,0 +1,443 @@ +/* + * Copyright © 2006 Novell, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Novell, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Novell, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Robert O'Callahan + */ + +#include "cairo-test.h" +#include +#include + +enum ExtentsType { FILL, STROKE, PATH }; + +enum Relation { EQUALS, APPROX_EQUALS, CONTAINS }; + + +static cairo_bool_t within_tolerance(double x1, double y1, + double x2, double y2, + double expected_x1, double expected_y1, + double expected_x2, double expected_y2, + double tolerance) +{ + return (fabs (expected_x1 - x1) < tolerance && + fabs (expected_y1 - y1) < tolerance && + fabs (expected_x2 - x2) < tolerance && + fabs (expected_y2 - y2) < tolerance); +} + +static cairo_bool_t +check_extents (const cairo_test_context_t *ctx, + const char *message, cairo_t *cr, enum ExtentsType type, + enum Relation relation, + double x, double y, double width, double height) +{ + double ext_x1, ext_y1, ext_x2, ext_y2; + const char *type_string; + const char *relation_string; + + switch (type) { + default: + case FILL: + type_string = "fill"; + cairo_fill_extents (cr, &ext_x1, &ext_y1, &ext_x2, &ext_y2); + break; + case STROKE: + type_string = "stroke"; + cairo_stroke_extents (cr, &ext_x1, &ext_y1, &ext_x2, &ext_y2); + break; + case PATH: + type_string = "path"; + cairo_path_extents (cr, &ext_x1, &ext_y1, &ext_x2, &ext_y2); + break; + } + + /* ignore results after an error occurs */ + if (cairo_status (cr)) + return 1; + + switch (relation) { + default: + case EQUALS: + relation_string = "equal"; + if (within_tolerance(x, y, x + width, y + height, + ext_x1, ext_y1, ext_x2, ext_y2, + cairo_get_tolerance(cr))) + return 1; + break; + case APPROX_EQUALS: + relation_string = "approx. equal"; + if (within_tolerance(x, y, x + width, y + height, + ext_x1, ext_y1, ext_x2, ext_y2, + 1.)) + return 1; + break; + case CONTAINS: + relation_string = "contain"; + if (width == 0 || height == 0) { + /* odd test that doesn't really test anything... */ + return 1; + } + if (ext_x1 <= x && ext_y1 <= y && ext_x2 >= x + width && ext_y2 >= y + height) + return 1; + break; + } + + cairo_test_log (ctx, "Error: %s; %s extents (%g, %g) x (%g, %g) should %s (%g, %g) x (%g, %g)\n", + message, type_string, + ext_x1, ext_y1, ext_x2 - ext_x1, ext_y2 - ext_y1, + relation_string, + x, y, width, height); + return 0; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_surface_t *surface; + cairo_t *cr2; + const char *phase; + const char string[] = "The quick brown fox jumps over the lazy dog."; + cairo_text_extents_t extents, scaled_font_extents; + cairo_status_t status; + int errors = 0; + + surface = cairo_surface_create_similar (cairo_get_group_target (cr), + CAIRO_CONTENT_COLOR, 1000, 1000); + /* don't use cr accidentally */ + cr = NULL; + cr2 = cairo_create (surface); + cairo_surface_destroy (surface); + + cairo_set_line_width (cr2, 10); + cairo_set_line_join (cr2, CAIRO_LINE_JOIN_MITER); + cairo_set_miter_limit (cr2, 100); + + phase = "No path"; + errors += !check_extents (ctx, phase, cr2, FILL, EQUALS, 0, 0, 0, 0); + errors += !check_extents (ctx, phase, cr2, STROKE, EQUALS, 0, 0, 0, 0); + errors += !check_extents (ctx, phase, cr2, PATH, EQUALS, 0, 0, 0, 0); + + cairo_save (cr2); + + cairo_new_path (cr2); + cairo_move_to (cr2, 200, 400); + cairo_close_path (cr2); + phase = "Degenerate closed path"; + errors += !check_extents (ctx, phase, cr2, FILL, EQUALS, 0, 0, 0, 0); + errors += !check_extents (ctx, phase, cr2, STROKE, EQUALS, 0, 0, 0, 0); + errors += !check_extents (ctx, phase, cr2, PATH, EQUALS, 200, 400, 0, 0); + + cairo_new_path (cr2); + cairo_move_to (cr2, 200, 400); + cairo_rel_line_to (cr2, 0., 0.); + phase = "Degenerate line"; + errors += !check_extents (ctx, phase, cr2, FILL, EQUALS, 0, 0, 0, 0); + errors += !check_extents (ctx, phase, cr2, STROKE, EQUALS, 0, 0, 0, 0); + errors += !check_extents (ctx, phase, cr2, PATH, EQUALS, 200, 400, 0, 0); + + cairo_new_path (cr2); + cairo_move_to (cr2, 200, 400); + cairo_rel_curve_to (cr2, 0., 0., 0., 0., 0., 0.); + phase = "Degenerate curve"; + errors += !check_extents (ctx, phase, cr2, FILL, EQUALS, 0, 0, 0, 0); + errors += !check_extents (ctx, phase, cr2, STROKE, EQUALS, 0, 0, 0, 0); + errors += !check_extents (ctx, phase, cr2, PATH, EQUALS, 200, 400, 0, 0); + + cairo_new_path (cr2); + cairo_arc (cr2, 200, 400, 0., 0, 2 * M_PI); + phase = "Degenerate arc (R=0)"; + errors += !check_extents (ctx, phase, cr2, FILL, EQUALS, 0, 0, 0, 0); + errors += !check_extents (ctx, phase, cr2, STROKE, EQUALS, 0, 0, 0, 0); + errors += !check_extents (ctx, phase, cr2, PATH, EQUALS, 200, 400, 0, 0); + + cairo_new_path (cr2); + cairo_arc_negative (cr2, 200, 400, 0., 0, 2 * M_PI); + phase = "Degenerate negative arc (R=0)"; + errors += !check_extents (ctx, phase, cr2, FILL, EQUALS, 0, 0, 0, 0); + errors += !check_extents (ctx, phase, cr2, STROKE, EQUALS, 0, 0, 0, 0); + errors += !check_extents (ctx, phase, cr2, PATH, EQUALS, 200, 400, 0, 0); + + cairo_new_path (cr2); + cairo_arc (cr2, 200, 400, 10., 0, 0); + phase = "Degenerate arc (Θ=0)"; + errors += !check_extents (ctx, phase, cr2, FILL, EQUALS, 0, 0, 0, 0); + errors += !check_extents (ctx, phase, cr2, STROKE, EQUALS, 0, 0, 0, 0); + errors += !check_extents (ctx, phase, cr2, PATH, EQUALS, 210, 400, 0, 0); + + cairo_new_path (cr2); + cairo_arc_negative (cr2, 200, 400, 10., 0, 0); + phase = "Degenerate negative arc (Θ=0)"; + errors += !check_extents (ctx, phase, cr2, FILL, EQUALS, 0, 0, 0, 0); + errors += !check_extents (ctx, phase, cr2, STROKE, EQUALS, 0, 0, 0, 0); + errors += !check_extents (ctx, phase, cr2, PATH, EQUALS, 210, 400, 0, 0); + + cairo_new_path (cr2); + cairo_restore (cr2); + + /* Test that with CAIRO_LINE_CAP_ROUND, we get "dots" from + * cairo_move_to; cairo_rel_line_to(0,0) */ + cairo_save (cr2); + + cairo_set_line_cap (cr2, CAIRO_LINE_CAP_ROUND); + cairo_set_line_width (cr2, 20); + + cairo_move_to (cr2, 200, 400); + cairo_rel_line_to (cr2, 0, 0); + phase = "Single 'dot'"; + errors += !check_extents (ctx, phase, cr2, FILL, EQUALS, 0, 0, 0, 0); + errors += !check_extents (ctx, phase, cr2, STROKE, EQUALS, 190, 390, 20, 20); + errors += !check_extents (ctx, phase, cr2, PATH, EQUALS, 200, 400, 0, 0); + + /* Add another dot without starting a new path */ + cairo_move_to (cr2, 100, 500); + cairo_rel_line_to (cr2, 0, 0); + phase = "Multiple 'dots'"; + errors += !check_extents (ctx, phase, cr2, FILL, EQUALS, 0, 0, 0, 0); + errors += !check_extents (ctx, phase, cr2, STROKE, EQUALS, 90, 390, 120, 120); + errors += !check_extents (ctx, phase, cr2, PATH, EQUALS, 100, 400, 100, 100); + + cairo_new_path (cr2); + + cairo_restore (cr2); + + /* https://bugs.freedesktop.org/show_bug.cgi?id=7965 */ + phase = "A horizontal, open path"; + cairo_save (cr2); + cairo_set_line_cap (cr2, CAIRO_LINE_CAP_ROUND); + cairo_set_line_join (cr2, CAIRO_LINE_JOIN_ROUND); + cairo_move_to (cr2, 0, 180); + cairo_line_to (cr2, 750, 180); + errors += !check_extents (ctx, phase, cr2, FILL, EQUALS, 0, 0, 0, 0); + errors += !check_extents (ctx, phase, cr2, STROKE, EQUALS, -5, 175, 760, 10); + errors += !check_extents (ctx, phase, cr2, PATH, EQUALS, 0, 180, 750, 0); + cairo_new_path (cr2); + cairo_restore (cr2); + + phase = "A vertical, open path"; + cairo_save (cr2); + cairo_set_line_cap (cr2, CAIRO_LINE_CAP_ROUND); + cairo_set_line_join (cr2, CAIRO_LINE_JOIN_ROUND); + cairo_new_path (cr2); + cairo_move_to (cr2, 180, 0); + cairo_line_to (cr2, 180, 750); + errors += !check_extents (ctx, phase, cr2, FILL, EQUALS, 0, 0, 0, 0); + errors += !check_extents (ctx, phase, cr2, STROKE, EQUALS, 175, -5, 10, 760); + errors += !check_extents (ctx, phase, cr2, PATH, EQUALS, 180, 0, 0, 750); + cairo_new_path (cr2); + cairo_restore (cr2); + + phase = "A degenerate open path"; + cairo_save (cr2); + cairo_set_line_cap (cr2, CAIRO_LINE_CAP_ROUND); + cairo_set_line_join (cr2, CAIRO_LINE_JOIN_ROUND); + cairo_new_path (cr2); + cairo_move_to (cr2, 180, 0); + cairo_line_to (cr2, 180, 0); + errors += !check_extents (ctx, phase, cr2, FILL, EQUALS, 0, 0, 0, 0); + errors += !check_extents (ctx, phase, cr2, STROKE, EQUALS, 175, -5, 10, 10); + errors += !check_extents (ctx, phase, cr2, PATH, EQUALS, 180, 0, 0, 0); + cairo_new_path (cr2); + cairo_restore (cr2); + + phase = "Simple rect"; + cairo_save (cr2); + cairo_rectangle (cr2, 10, 10, 80, 80); + errors += !check_extents (ctx, phase, cr2, FILL, EQUALS, 10, 10, 80, 80); + errors += !check_extents (ctx, phase, cr2, STROKE, EQUALS, 5, 5, 90, 90); + errors += !check_extents (ctx, phase, cr2, PATH, EQUALS, 10, 10, 80, 80); + cairo_new_path (cr2); + cairo_restore (cr2); + + phase = "Two rects"; + cairo_save (cr2); + cairo_rectangle (cr2, 10, 10, 10, 10); + cairo_rectangle (cr2, 20, 20, 10, 10); + errors += !check_extents (ctx, phase, cr2, FILL, EQUALS, 10, 10, 20, 20); + errors += !check_extents (ctx, phase, cr2, STROKE, EQUALS, 5, 5, 30, 30); + errors += !check_extents (ctx, phase, cr2, PATH, EQUALS, 10, 10, 20, 20); + cairo_new_path (cr2); + cairo_restore (cr2); + + phase = "Triangle"; + cairo_save (cr2); + cairo_move_to (cr2, 10, 10); + cairo_line_to (cr2, 90, 90); + cairo_line_to (cr2, 90, 10); + cairo_close_path (cr2); + /* miter joins protrude 5*(1+sqrt(2)) above the top-left corner and to + the right of the bottom-right corner */ + errors += !check_extents (ctx, phase, cr2, FILL, EQUALS, 10, 10, 80, 80); + errors += !check_extents (ctx, phase, cr2, STROKE, CONTAINS, 0, 5, 95, 95); + errors += !check_extents (ctx, phase, cr2, PATH, CONTAINS, 10, 10, 80, 80); + cairo_new_path (cr2); + cairo_restore (cr2); + + cairo_save (cr2); + + cairo_set_line_width (cr2, 4); + + cairo_rectangle (cr2, 10, 10, 30, 30); + cairo_rectangle (cr2, 25, 10, 15, 30); + + cairo_set_fill_rule (cr2, CAIRO_FILL_RULE_EVEN_ODD); + phase = "EVEN_ODD overlapping rectangles"; + errors += !check_extents (ctx, phase, cr2, FILL, EQUALS, 10, 10, 15, 30); + errors += !check_extents (ctx, phase, cr2, STROKE, EQUALS, 8, 8, 34, 34); + errors += !check_extents (ctx, phase, cr2, PATH, EQUALS, 10, 10, 30, 30); + + /* Test other fill rule with the same path. */ + + cairo_set_fill_rule (cr2, CAIRO_FILL_RULE_WINDING); + phase = "WINDING overlapping rectangles"; + errors += !check_extents (ctx, phase, cr2, FILL, EQUALS, 10, 10, 30, 30); + errors += !check_extents (ctx, phase, cr2, STROKE, EQUALS, 8, 8, 34, 34); + errors += !check_extents (ctx, phase, cr2, PATH, EQUALS, 10, 10, 30, 30); + + /* Now, change the direction of the second rectangle and test both + * fill rules again. */ + cairo_new_path (cr2); + cairo_rectangle (cr2, 10, 10, 30, 30); + cairo_rectangle (cr2, 25, 40, 15, -30); + + cairo_set_fill_rule (cr2, CAIRO_FILL_RULE_EVEN_ODD); + phase = "EVEN_ODD overlapping rectangles"; + errors += !check_extents (ctx, phase, cr2, FILL, EQUALS, 10, 10, 15, 30); + errors += !check_extents (ctx, phase, cr2, STROKE, EQUALS, 8, 8, 34, 34); + errors += !check_extents (ctx, phase, cr2, PATH, EQUALS, 10, 10, 30, 30); + + /* Test other fill rule with the same path. */ + + cairo_set_fill_rule (cr2, CAIRO_FILL_RULE_WINDING); + phase = "WINDING overlapping rectangles"; + errors += !check_extents (ctx, phase, cr2, FILL, EQUALS, 10, 10, 15, 30); + errors += !check_extents (ctx, phase, cr2, STROKE, EQUALS, 8, 8, 34, 34); + errors += !check_extents (ctx, phase, cr2, PATH, EQUALS, 10, 10, 30, 30); + + cairo_new_path (cr2); + + cairo_restore (cr2); + + /* https://bugs.freedesktop.org/show_bug.cgi?id=7245 */ + phase = "Arc"; + cairo_save (cr2); + cairo_arc (cr2, 250.0, 250.0, 157.0, 5.147, 3.432); + cairo_set_line_width (cr2, 154.0); + errors += !check_extents (ctx, phase, cr2, STROKE, APPROX_EQUALS, 16, 38, 468, 446); + cairo_new_path (cr2); + cairo_restore (cr2); + + phase = "Text"; + cairo_save (cr2); + cairo_select_font_face (cr2, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (cr2, 12); + cairo_text_extents (cr2, string, &extents); + /* double check that the two methods of measuring the text agree... */ + cairo_scaled_font_text_extents (cairo_get_scaled_font (cr2), + string, + &scaled_font_extents); + if (memcmp (&extents, &scaled_font_extents, sizeof (extents))) { + cairo_test_log (ctx, "Error: cairo_text_extents() does not match cairo_scaled_font_text_extents() - font extents (%f, %f) x (%f, %f) should be (%f, %f) x (%f, %f)\n", + scaled_font_extents.x_bearing, + scaled_font_extents.y_bearing, + scaled_font_extents.width, + scaled_font_extents.height, + extents.x_bearing, + extents.y_bearing, + extents.width, + extents.height); + errors++; + } + + cairo_move_to (cr2, -extents.x_bearing, -extents.y_bearing); + cairo_text_path (cr2, string); + cairo_set_line_width (cr2, 2.0); + /* XXX: We'd like to be able to use EQUALS here, but currently + * when hinting is enabled freetype returns integer extents. See + * https://cairographics.org/todo */ + errors += !check_extents (ctx, phase, cr2, FILL, APPROX_EQUALS, + 0, 0, extents.width, extents.height); + errors += !check_extents (ctx, phase, cr2, STROKE, APPROX_EQUALS, + -1, -1, extents.width+2, extents.height+2); + errors += !check_extents (ctx, phase, cr2, PATH, APPROX_EQUALS, + 0, 0, extents.width, extents.height); + cairo_new_path (cr2); + cairo_restore (cr2); + + phase = "User space, simple scale, getting extents with same transform"; + cairo_save (cr2); + cairo_scale (cr2, 2, 2); + cairo_rectangle (cr2, 5, 5, 40, 40); + errors += !check_extents (ctx, phase, cr2, FILL, EQUALS, 5, 5, 40, 40); + errors += !check_extents (ctx, phase, cr2, STROKE, EQUALS, 0, 0, 50, 50); + errors += !check_extents (ctx, phase, cr2, PATH, EQUALS, 5, 5, 40, 40); + cairo_new_path (cr2); + cairo_restore (cr2); + + phase = "User space, simple scale, getting extents with no transform"; + cairo_save (cr2); + cairo_save (cr2); + cairo_scale (cr2, 2, 2); + cairo_rectangle (cr2, 5, 5, 40, 40); + cairo_restore (cr2); + errors += !check_extents (ctx, phase, cr2, FILL, EQUALS, 10, 10, 80, 80); + errors += !check_extents (ctx, phase, cr2, STROKE, EQUALS, 5, 5, 90, 90); + errors += !check_extents (ctx, phase, cr2, PATH, EQUALS, 10, 10, 80, 80); + cairo_new_path (cr2); + cairo_restore (cr2); + + phase = "User space, rotation, getting extents with transform"; + cairo_save (cr2); + cairo_rectangle (cr2, -50, -50, 50, 50); + cairo_rotate (cr2, -M_PI/4); + /* the path in user space is now (nearly) the square rotated by + 45 degrees about the origin. Thus its x1 and x2 are both nearly 0. + This should show any bugs where we just transform device-space + x1,y1 and x2,y2 to get the extents. */ + /* The largest axis-aligned square inside the rotated path has + side lengths 50*sqrt(2), so a bit over 35 on either side of + the axes. With the stroke width added to the rotated path, + the largest axis-aligned square is a bit over 38 on either side of + the axes. */ + errors += !check_extents (ctx, phase, cr2, FILL, CONTAINS, -35, -35, 35, 35); + errors += !check_extents (ctx, phase, cr2, STROKE, CONTAINS, -38, -38, 38, 38); + errors += !check_extents (ctx, phase, cr2, PATH, CONTAINS, -35, -35, 35, 35); + cairo_new_path (cr2); + cairo_restore (cr2); + + status = cairo_status (cr2); + cairo_destroy (cr2); + + if (status) + return cairo_test_status_from_status (ctx, status); + + return errors == 0 ? CAIRO_TEST_SUCCESS : CAIRO_TEST_FAILURE; +} + +CAIRO_TEST (get_path_extents, + "Test cairo_fill_extents and cairo_stroke_extents", + "extents, path", /* keywords */ + NULL, /* requirements */ + 0, 0, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/get-xrender-format.c b/local/recipes/libs/cairo/source/test/get-xrender-format.c new file mode 100644 index 0000000000..3228d57c60 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/get-xrender-format.c @@ -0,0 +1,122 @@ +/* + * Copyright © 2008 Red Hat, Inc. + * + * 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: Carl D. Worth + */ + +#include "cairo-test.h" + +#include "cairo-xlib.h" +#include "cairo-xlib-xrender.h" + +#include "cairo-boilerplate-xlib.h" + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + Display *dpy; + XRenderPictFormat *orig_format, *format; + cairo_surface_t *surface; + Pixmap pixmap; + int screen; + cairo_test_status_t result; + + result = CAIRO_TEST_UNTESTED; + + if (! cairo_test_is_target_enabled (ctx, "xlib")) + goto CLEANUP_TEST; + + dpy = XOpenDisplay (NULL); + if (! dpy) { + cairo_test_log (ctx, "Error: Cannot open display: %s, skipping.\n", + XDisplayName (NULL)); + goto CLEANUP_TEST; + } + + result = CAIRO_TEST_FAILURE; + + screen = DefaultScreen (dpy); + + cairo_test_log (ctx, "Testing with image surface.\n"); + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1); + + format = cairo_xlib_surface_get_xrender_format (surface); + if (format != NULL) { + cairo_test_log (ctx, "Error: expected NULL for image surface\n"); + goto CLEANUP_SURFACE; + } + + cairo_surface_destroy (surface); + + cairo_test_log (ctx, "Testing with non-xrender xlib surface.\n"); + + pixmap = XCreatePixmap (dpy, DefaultRootWindow (dpy), + 1, 1, DefaultDepth (dpy, screen)); + surface = cairo_xlib_surface_create (dpy, pixmap, + DefaultVisual (dpy, screen), + 1, 1); + orig_format = XRenderFindVisualFormat (dpy, DefaultVisual (dpy, screen)); + format = cairo_xlib_surface_get_xrender_format (surface); + if (format != orig_format) { + cairo_test_log (ctx, "Error: did not receive the same format as XRenderFindVisualFormat\n"); + goto CLEANUP_PIXMAP; + } + cairo_surface_destroy (surface); + XFreePixmap (dpy, pixmap); + + cairo_test_log (ctx, "Testing with xlib xrender surface.\n"); + + orig_format = XRenderFindStandardFormat (dpy, PictStandardARGB32); + pixmap = XCreatePixmap (dpy, DefaultRootWindow (dpy), + 1, 1, 32); + surface = cairo_xlib_surface_create_with_xrender_format (dpy, + pixmap, + DefaultScreenOfDisplay (dpy), + orig_format, + 1, 1); + format = cairo_xlib_surface_get_xrender_format (surface); + if (format != orig_format) { + cairo_test_log (ctx, "Error: did not receive the same format originally set\n"); + goto CLEANUP_PIXMAP; + } + + result = CAIRO_TEST_SUCCESS; + + CLEANUP_PIXMAP: + XFreePixmap (dpy, pixmap); + CLEANUP_SURFACE: + cairo_surface_destroy (surface); + + XCloseDisplay (dpy); + + CLEANUP_TEST: + return result; +} + +CAIRO_TEST (get_xrender_format, + "Check XRender specific API", + "xrender, api", /* keywords */ + NULL, /* requirements */ + 0, 0, + preamble, NULL) diff --git a/local/recipes/libs/cairo/source/test/global.jb2 b/local/recipes/libs/cairo/source/test/global.jb2 new file mode 100644 index 0000000000..5a15498535 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/global.jb2 differ diff --git a/local/recipes/libs/cairo/source/test/glyph-cache-pressure.c b/local/recipes/libs/cairo/source/test/glyph-cache-pressure.c new file mode 100644 index 0000000000..eb4f7c5c2e --- /dev/null +++ b/local/recipes/libs/cairo/source/test/glyph-cache-pressure.c @@ -0,0 +1,81 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" +#include "cairo-boilerplate-scaled-font.h" + +#define TEXT_SIZE 12 + +/* Bug history + * + * 2006-06-22 Carl Worth + * + * This is a test case to demonstrate the following bug in the xlib backend: + * + * Some characters aren't displayed when using xlib (cache usage missing freeze/thaw) + * https://bugs.freedesktop.org/show_bug.cgi?id=6955 + * + * We replicate this bug by using the cairo_scaled_font_set_max_glyphs_per_font + * function to artificially induce cache pressure. (This function was added + * for this very purpose.) + * + * 2006-06-22 Carl Worth + * + * Bug was simple enough to solve by just adding a freeze/thaw pair + * around the scaled_font's glyph cache in + * _cairo_xlib_surface_show_glyphs, (I went ahead and added + * _cairo_sacled_font_freeze/thaw_cache functions for this). + */ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + /* We draw in the default black, so paint white first. */ + cairo_save (cr); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_restore (cr); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (cr, TEXT_SIZE); + + cairo_set_source_rgb (cr, 0, 0, 0); /* black */ + + cairo_boilerplate_scaled_font_set_max_glyphs_cached (cairo_get_scaled_font (cr), 1); + + cairo_move_to (cr, 1, TEXT_SIZE); + cairo_show_text (cr, "the five boxing wizards jump quickly"); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (glyph_cache_pressure, + "Ensure that all backends behave well under artificial glyph cache pressure", + "stress", /* keywords */ + NULL, /* requirements */ + 223, TEXT_SIZE + 4, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/glyph-path.c b/local/recipes/libs/cairo/source/test/glyph-path.c new file mode 100644 index 0000000000..b61f193a19 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/glyph-path.c @@ -0,0 +1,82 @@ +/* + * Copyright © 2024 worldiety GmbH + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * worldiety not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. worldiety makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * WORLDIETY DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL WORLDIETY BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Heiko Lewin + */ +#include "cairo-test.h" + +#define WIDTH 128 +#define HEIGHT 64 + + +static cairo_test_status_t +draw(cairo_t *cr, int width, int height) { + cairo_glyph_t *glyphs = NULL; + int num_glyphs = 0; + cairo_path_t *path = NULL, *path2 = NULL; + (void)width; + (void)height; + + /* black on white color */ + cairo_set_source_rgb(cr, 1., 1., 1.); + cairo_paint(cr); + cairo_set_source_rgb(cr, 0, 0, 0); + + + /* translate to some point well outside the surface */ + cairo_translate(cr, -width * 100, 0); + + /* create a simple path to illustrate the correct behaviour */ + cairo_rectangle(cr, 0, 0, width/2.0, 2); + path = cairo_copy_path(cr); + cairo_new_path(cr); + + /* create another path from glyphs - this is broken when clipping to early */ + { + cairo_set_font_size(cr, 32); + cairo_scaled_font_t *sf = cairo_get_scaled_font(cr); + cairo_scaled_font_text_to_glyphs(sf, 0, 0, "Test", 4, &glyphs, &num_glyphs, 0, 0, 0); + cairo_glyph_path(cr, glyphs, num_glyphs); + path2 = cairo_copy_path(cr); + } + + /* translate to a visible point and draw both paths */ + cairo_identity_matrix(cr); + cairo_translate(cr, width/4.0, 48); + + cairo_append_path(cr, path); + cairo_append_path(cr, path2); + cairo_fill(cr); + + cairo_path_destroy(path); + cairo_path_destroy(path2); + free(glyphs); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (glyph_path, + "Tests cairo_glyph_path", + "text, glyph, path", /* keywords */ + "target=raster", /* should be enough */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/gradient-alpha.c b/local/recipes/libs/cairo/source/test/gradient-alpha.c new file mode 100644 index 0000000000..24cd3245f9 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/gradient-alpha.c @@ -0,0 +1,56 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *gradient; + + gradient = cairo_pattern_create_linear (0, -height, + 0, height); + cairo_pattern_add_color_stop_rgba (gradient, 0.0, + 1.0, 0.0, 0.0, + 1.0); + cairo_pattern_add_color_stop_rgba (gradient, 1.0, + 0.0, 0.0, 1.0, + 0.5); + + cairo_set_source (cr, gradient); + + cairo_paint (cr); + + cairo_pattern_destroy (gradient); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (gradient_alpha, + "Tests drawing of a gradient with various alpha values in the color stops", + "gradient, alpha", /* keywords */ + NULL, /* requirements */ + 10, 10, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/gradient-constant-alpha.c b/local/recipes/libs/cairo/source/test/gradient-constant-alpha.c new file mode 100644 index 0000000000..7640b6eb5a --- /dev/null +++ b/local/recipes/libs/cairo/source/test/gradient-constant-alpha.c @@ -0,0 +1,61 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + * Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *gradient; + + gradient = cairo_pattern_create_linear (0, 0, + 0, height); + cairo_pattern_add_color_stop_rgba (gradient, 0.0, + 1.0, 0.0, 0.0, + 0.5); + cairo_pattern_add_color_stop_rgba (gradient, 0.0, + 0.0, 1.0, 0.0, + 0.5); + cairo_pattern_add_color_stop_rgba (gradient, 1.0, + 0.0, 0.0, 1.0, + 0.5); + + cairo_set_source (cr, gradient); + + cairo_paint (cr); + + cairo_pattern_destroy (gradient); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (gradient_constant_alpha, + "Tests drawing of a gradient with constant alpha values in the color stops", + "gradient, alpha", /* keywords */ + NULL, + 10, 10, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/gradient-scale-crash.c b/local/recipes/libs/cairo/source/test/gradient-scale-crash.c new file mode 100644 index 0000000000..b265e429b6 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/gradient-scale-crash.c @@ -0,0 +1,55 @@ +/* + * Copyright © 2024 Koichi Akabe + * + * 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: Koichi Akabe + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *p = cairo_pattern_create_linear (0, 0, 0, 100); + + cairo_pattern_add_color_stop_rgb (p, 0, 1, 1, 1); + cairo_pattern_add_color_stop_rgb (p, 1, 1, 0, 0); + + cairo_matrix_t m; + cairo_matrix_init (&m, 100000, 0, 0, 100000, 0, 0); + cairo_pattern_set_matrix (p, &m); + + cairo_set_source (cr, p); + cairo_rectangle (cr, 0, 0, 100, 100); + cairo_paint (cr); + + cairo_pattern_destroy (p); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (gradient_scale_crash, + "Verify fix for https://gitlab.freedesktop.org/cairo/cairo/-/issues/789", + "gradient, pattern", /* keywords */ + NULL, /* requirements */ + 0, 0, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/gradient-zero-stops-mask.c b/local/recipes/libs/cairo/source/test/gradient-zero-stops-mask.c new file mode 100644 index 0000000000..b2a10ec341 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/gradient-zero-stops-mask.c @@ -0,0 +1,59 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright © 2007 Brian Ewins + * + * 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: Brian Ewins + * Contributor(s): + * Andrea Canciani + */ + +#include "cairo-test.h" + +/* This test case is designed to exercise the opaque test for + * gradients with no stop. + */ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *pat; + + cairo_set_source_rgb (cr, 1., 0., 0.); + + pat = cairo_pattern_create_linear (0., 0., 1., 1.); + cairo_mask (cr, pat); + cairo_pattern_destroy (pat); + + pat = cairo_pattern_create_radial (0., 0., 0., 1., 1., 1.); + cairo_mask (cr, pat); + cairo_pattern_destroy (pat); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (gradient_zero_stops_mask, + "Verifies that gradients with no stops are considered clear.", + "gradient", /* keywords */ + NULL, /* requirements */ + 2, 2, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/gradient-zero-stops.c b/local/recipes/libs/cairo/source/test/gradient-zero-stops.c new file mode 100644 index 0000000000..57a91c536e --- /dev/null +++ b/local/recipes/libs/cairo/source/test/gradient-zero-stops.c @@ -0,0 +1,58 @@ +/* + * Copyright © 2007 Brian Ewins + * + * 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: Brian Ewins + */ + +#include "cairo-test.h" + +/* This test case is designed to exercise the following bug: + * + * Crash when trying to paint gradient with no stops + * https://bugzilla.mozilla.org/show_bug.cgi?id=407104 + */ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *pat; + + pat = cairo_pattern_create_linear (0., 0., 1., 1.); + cairo_set_source (cr, pat); + cairo_paint (cr); + cairo_pattern_destroy (pat); + + pat = cairo_pattern_create_radial (0., 0., 0., 1., 1., 1.); + cairo_set_source (cr, pat); + cairo_paint (cr); + cairo_pattern_destroy (pat); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (gradient_zero_stops, + "Verifies that gradients with no stops don't cause problems.", + "gradient", /* keywords */ + NULL, /* requirements */ + 2, 2, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/group-clip.c b/local/recipes/libs/cairo/source/test/group-clip.c new file mode 100644 index 0000000000..b99d8617e4 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/group-clip.c @@ -0,0 +1,57 @@ +/* + * Copyright © Chris Wilson, 2008 + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Chris Wilson + * Larry Ewing + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_rectangle (cr, 25, 25, width, height); + cairo_clip_preserve (cr); + cairo_push_group (cr); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_fill (cr); + cairo_rectangle (cr, 0, 0, width, height); + cairo_pop_group_to_source (cr); + cairo_paint (cr); + + cairo_reset_clip (cr); + cairo_clip_preserve (cr); + cairo_set_source_rgba (cr, 1, 0, 0, .5); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (group_clip, + "test preserving paths across groups", + "group", /* keywords */ + NULL, /* requirements */ + 40 + 25, 40 + 25, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/group-paint.c b/local/recipes/libs/cairo/source/test/group-paint.c new file mode 100644 index 0000000000..38544856fe --- /dev/null +++ b/local/recipes/libs/cairo/source/test/group-paint.c @@ -0,0 +1,48 @@ +/* + * Copyright © Chris Wilson, 2008 + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_push_group (cr); + + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_paint (cr); + + cairo_pop_group_to_source (cr); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (group_paint, + "test push_group(); pop_group_to_source(); set_operator(SOURCE); paint();", + "group", /* keywords */ + NULL, /* requirements */ + 10, 10, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/group-state.c b/local/recipes/libs/cairo/source/test/group-state.c new file mode 100644 index 0000000000..a96b2e3d09 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/group-state.c @@ -0,0 +1,96 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright 2011 Andrea Canciani + * + * 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: Andrea Canciani + */ + +#include "cairo-test.h" + +#define CHECK_STATUS(status) \ + do { \ + if (cairo_status (cr) != (status)) { \ + cairo_test_log (ctx, "Expected status: %s\n", \ + cairo_status_to_string (status)); \ + cairo_test_log (ctx, "Actual status: %s\n", \ + cairo_status_to_string (cairo_status (cr))); \ + result = CAIRO_TEST_FAILURE; \ + } \ + } while (0) + +static void +reinit_cairo (cairo_t **cr) +{ + if (*cr) + cairo_destroy (*cr); + + *cr = cairo_create (cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1)); + cairo_surface_destroy (cairo_get_target (*cr)); +} + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + cairo_t *cr; + cairo_test_status_t result = CAIRO_TEST_SUCCESS; + + cr = NULL; + + reinit_cairo (&cr); + + /* cairo_restore() must fail with CAIRO_STATUS_INVALID_RESTORE if + * no matching cairo_save() call has been performed. */ + cairo_test_log (ctx, "Checking save(); push(); restore();\n"); + cairo_save (cr); + CHECK_STATUS (CAIRO_STATUS_SUCCESS); + cairo_push_group (cr); + CHECK_STATUS (CAIRO_STATUS_SUCCESS); + cairo_restore (cr); + CHECK_STATUS (CAIRO_STATUS_INVALID_RESTORE); + + + reinit_cairo (&cr); + + /* cairo_restore() must fail with CAIRO_STATUS_INVALID_RESTORE if + * no matching cairo_save() call has been performed. */ + cairo_test_log (ctx, "Checking push(); save(); pop();\n"); + cairo_push_group (cr); + CHECK_STATUS (CAIRO_STATUS_SUCCESS); + cairo_save (cr); + CHECK_STATUS (CAIRO_STATUS_SUCCESS); + cairo_pop_group_to_source (cr); + CHECK_STATUS (CAIRO_STATUS_INVALID_POP_GROUP); + + + cairo_destroy (cr); + + return result; +} + +CAIRO_TEST (group_state, + "Tests the interaction between state (cairo_save, cairo_restore) " + "and group (cairo_push_group/cairo_pop_group) API", + "api", /* keywords */ + NULL, /* requirements */ + 0, 0, + preamble, NULL) diff --git a/local/recipes/libs/cairo/source/test/group-unaligned.c b/local/recipes/libs/cairo/source/test/group-unaligned.c new file mode 100644 index 0000000000..9124a032c6 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/group-unaligned.c @@ -0,0 +1,60 @@ +/* + * Copyright © Chris Wilson, 2008 + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Chris Wilson + * Stefan Röllin + */ + +#include "cairo-test.h" + +static void +circle (cairo_t* cr, double xc, double yc, double radius) +{ + cairo_arc (cr, xc, yc, radius, 0.0, 2*M_PI); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 1, 0, 0); + circle (cr, 12.5, 12.5, 10.); + cairo_fill (cr); + + cairo_push_group (cr); + cairo_set_source_rgb (cr, 0, 0, 1); + circle (cr, 12.5, 12.5, 10.); + cairo_fill (cr); + cairo_pop_group_to_source (cr); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (group_unaligned, + "test non-integer sized sub-surface", + "group", /* keywords */ + NULL, /* requirements */ + 35.5, 35.5, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/hairline.c b/local/recipes/libs/cairo/source/test/hairline.c new file mode 100644 index 0000000000..78fdca4a67 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/hairline.c @@ -0,0 +1,199 @@ +/* + * Copyright © 2021 Rick Yorgason + * + * 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. + */ + +#include "cairo-test.h" + +/** + * draw: + * @cr: a #cairo_t + * @width: Width of the test image + * @height: Height of the test image + * @scale_width: Percentage to scale the width + * @scale_height: Percentage to scale the height + * @fit_to_scale: Whether or not to adjust the image to fit in the scale parameters + * regardless of the scale parameters + * @correct_scale: Tests if the hairlines render correctly regardless of + * whether or not the scale is set "correctly", as per + * https://cairographics.org/cookbook/ellipses/ + */ +static cairo_test_status_t +draw (cairo_t *cr, int width, int height, double scale_width, double scale_height, cairo_bool_t fit_to_scale, cairo_bool_t correct_scale) +{ + cairo_matrix_t save_matrix; + double fit_width = fit_to_scale ? scale_width : 1.0; + double fit_height = fit_to_scale ? scale_height : 1.0; + double fit_max = MAX(fit_width, fit_height); + double dash[] = {3.0}; + + if (cairo_get_hairline (cr) == TRUE) { + return CAIRO_TEST_ERROR; + } + + /* Clear background */ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_set_line_width (cr, 100.0); /* If everything is working right, this value should never get used */ + + /* Hairline sample */ + if (correct_scale) { + cairo_get_matrix (cr, &save_matrix); + } + cairo_scale (cr, scale_width, scale_height); + + cairo_set_hairline (cr, TRUE); + if (cairo_get_hairline (cr) == FALSE) { + return CAIRO_TEST_ERROR; + } + + cairo_move_to (cr, 0, 0); + cairo_line_to (cr, width/fit_width/2, height/fit_height/2); + cairo_move_to (cr, width/fit_width/2, 0); + cairo_line_to (cr, width/fit_width/2, height/fit_height/2); + cairo_move_to (cr, 0, height/fit_height/2); + cairo_line_to (cr, width/fit_width/2, height/fit_height/2); + cairo_move_to (cr, width/fit_width/4, 0); + cairo_line_to (cr, width/fit_width/2, height/fit_height/2); + cairo_arc (cr, width/fit_width/2, height/fit_height/2, width/fit_max/4, M_PI*0.5, M_PI*1.0); + + if (correct_scale) { + cairo_set_matrix (cr, &save_matrix); + } + cairo_stroke (cr); + + /* Dashed sample */ + if (correct_scale) { + cairo_get_matrix (cr, &save_matrix); + cairo_scale (cr, scale_width, scale_height); + } + cairo_set_dash (cr, dash, 1, 0); + cairo_arc (cr, width/fit_width/2, height/fit_height/2, width/fit_max/4, M_PI*1.0, M_PI*1.5); + if (correct_scale) { + cairo_set_matrix (cr, &save_matrix); + } + cairo_stroke (cr); + + /* Control sample */ + if (correct_scale) { + cairo_get_matrix (cr, &save_matrix); + cairo_scale (cr, scale_width, scale_height); + } + + cairo_set_line_width (cr, 3.0); + cairo_set_hairline (cr, FALSE); + if (cairo_get_hairline (cr) == TRUE) { + return CAIRO_TEST_ERROR; + } + + cairo_set_dash (cr, 0, 0, 0); + + cairo_move_to (cr, width/fit_width, height/fit_height); + cairo_line_to (cr, width/fit_width/2, height/fit_height/2); + cairo_move_to (cr, width/fit_width/2, height/fit_height); + cairo_line_to (cr, width/fit_width/2, height/fit_height/2); + cairo_move_to (cr, width/fit_width, height/fit_height/2); + cairo_line_to (cr, width/fit_width/2, height/fit_height/2); + cairo_move_to (cr, width/fit_width*0.75, height/fit_height); + cairo_line_to (cr, width/fit_width/2, height/fit_height/2); + cairo_arc (cr, width/fit_width/2, height/fit_height/2, width/fit_max/4, M_PI*1.5, M_PI*2.0); + + if (correct_scale) { + cairo_set_matrix (cr, &save_matrix); + } + cairo_stroke (cr); + + /* Dashed sample */ + if (correct_scale) { + cairo_get_matrix (cr, &save_matrix); + cairo_scale (cr, scale_width, scale_height); + } + cairo_set_dash (cr, dash, 1, 0); + cairo_arc (cr, width/fit_width/2, height/fit_height/2, width/fit_max/4, 0, M_PI*0.5); + if (correct_scale) { + cairo_set_matrix (cr, &save_matrix); + } + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +draw_typical (cairo_t *cr, int width, int height) +{ + return draw (cr, width, height, 1.0, 1.0, TRUE, TRUE); +} + +static cairo_test_status_t +draw_scaled (cairo_t *cr, int width, int height) +{ + return draw (cr, width, height, 0.5, 0.5, FALSE, TRUE); +} + +static cairo_test_status_t +draw_anisotropic (cairo_t *cr, int width, int height) +{ + return draw (cr, width, height, 2.0, 5.0, TRUE, TRUE); +} + +static cairo_test_status_t +draw_anisotropic_incorrect (cairo_t *cr, int width, int height) +{ + return draw (cr, width, height, 2.0, 5.0, TRUE, FALSE); +} + +CAIRO_TEST (hairline, + "Tests hairlines are drawn at a single pixel width", + "path, stroke, hairline", /* keywords */ + NULL, /* requirements */ + 49, 49, + NULL, draw_typical) + +CAIRO_TEST (hairline_big, + "Tests hairlines are drawn at a single pixel width", + "path, stroke, hairline", /* keywords */ + NULL, /* requirements */ + 99, 99, + NULL, draw_typical) + +CAIRO_TEST (hairline_scaled, + "Tests hairlines are drawn at a single pixel width", + "path, stroke, hairline", /* keywords */ + NULL, /* requirements */ + 99, 99, + NULL, draw_scaled) + +CAIRO_TEST (hairline_anisotropic, + "Tests hairlines with a really lopsided scale parameter", + "path, stroke, hairline", /* keywords */ + NULL, /* requirements */ + 99, 99, + NULL, draw_anisotropic) + +CAIRO_TEST (hairline_anisotropic_incorrect, + "Tests hairlines with a really lopsided scale parameter", + "path, stroke, hairline", /* keywords */ + NULL, /* requirements */ + 99, 99, + NULL, draw_anisotropic_incorrect) diff --git a/local/recipes/libs/cairo/source/test/half-coverage.c b/local/recipes/libs/cairo/source/test/half-coverage.c new file mode 100644 index 0000000000..38cafda757 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/half-coverage.c @@ -0,0 +1,155 @@ +/* + * Copyright 2010 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +/* Test the fidelity of the rasterisation, because Cairo is my favourite + * driver test suite. + */ + +#define SIZE 256 +#define WIDTH 2 +#define HEIGHT 10 + +static cairo_test_status_t +rectangles (cairo_t *cr, int width, int height) +{ + int i; + + cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); + cairo_paint (cr); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); + + for (i = 1; i <= SIZE; i++) { + int x, y; + + cairo_save (cr); + cairo_rectangle (cr, 0, 0, WIDTH, HEIGHT); + cairo_clip (cr); + + cairo_scale (cr, 1./SIZE, 1./SIZE); + for (x = -i; x < SIZE*WIDTH; x += 2*i) { + for (y = -i; y < SIZE*HEIGHT; y += 2*i) { + /* Add a little tile composed of two non-overlapping squares + * +--+ + * | | + * |__|__ + * | | + * | | + * +--+ + */ + cairo_rectangle (cr, x, y, i, i); + cairo_rectangle (cr, x+i, y+i, i, i); + } + } + cairo_fill (cr); + cairo_restore (cr); + + cairo_translate (cr, WIDTH, 0); + } + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +triangles (cairo_t *cr, int width, int height) +{ + int i; + + cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); + cairo_paint (cr); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); + + for (i = 1; i <= SIZE; i++) { + int x, y; + + cairo_save (cr); + cairo_rectangle (cr, 0, 0, WIDTH, HEIGHT); + cairo_clip (cr); + + cairo_scale (cr, 1./SIZE, 1./SIZE); + for (x = -i; x < SIZE*WIDTH; x += 2*i) { + for (y = -i; y < SIZE*HEIGHT; y += 2*i) { + /* Add a tile composed of four non-overlapping + * triangles. The plus and minus signs inside the + * triangles denote the orientation of the triangle's + * edges: + for clockwise and - for anticlockwise. + * + * +-----+ + * \-|+/ + * \|/ + * /|\ + * /-|-\ + * +-----+ + */ + + /* top left triangle */ + cairo_move_to (cr, x, y); + cairo_line_to (cr, x+i, y+i); + cairo_line_to (cr, x+i, y); + cairo_close_path (cr); + + /* top right triangle */ + cairo_move_to (cr, x+i, y); + cairo_line_to (cr, x+2*i, y); + cairo_line_to (cr, x+i, y+i); + cairo_close_path (cr); + + /* bottom left triangle */ + cairo_move_to (cr, x+i, y+i); + cairo_line_to (cr, x, y+2*i); + cairo_line_to (cr, x+i, y+2*i); + cairo_close_path (cr); + + /* bottom right triangle */ + cairo_move_to (cr, x+i, y+i); + cairo_line_to (cr, x+i, y+2*i); + cairo_line_to (cr, x+2*i, y+2*i); + cairo_close_path (cr); + } + } + cairo_fill (cr); + cairo_restore (cr); + + cairo_translate (cr, WIDTH, 0); + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (half_coverage_rectangles, + "Check the fidelity of the rasterisation.", + NULL, /* keywords */ + "target=raster slow", /* requirements */ + WIDTH * SIZE, HEIGHT, + NULL, rectangles) + +CAIRO_TEST (half_coverage_triangles, + "Check the fidelity of the rasterisation.", + NULL, /* keywords */ + "target=raster slow", /* requirements */ + WIDTH * SIZE, HEIGHT, + NULL, triangles) diff --git a/local/recipes/libs/cairo/source/test/halo.c b/local/recipes/libs/cairo/source/test/halo.c new file mode 100644 index 0000000000..30064e51a8 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/halo.c @@ -0,0 +1,158 @@ +/* + * Copyright 2010 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +/* Try to replicate the misbehaviour of show_glyphs() versus glyph_path() + * in the PDF backend reported by Ian Britten. + */ + +static void +halo_around_path (cairo_t *cr, const char *str) +{ + cairo_text_path (cr, str); + + cairo_set_source_rgb (cr, 0, .5, 1); + cairo_stroke_preserve (cr); + cairo_set_source_rgb (cr, 1, .5, 0); + cairo_fill (cr); +} + +static void +halo_around_text (cairo_t *cr, const char *str) +{ + double x, y; + + cairo_get_current_point (cr, &x, &y); + cairo_text_path (cr, str); + + cairo_set_source_rgb (cr, 0, .5, 1); + cairo_stroke(cr); + + cairo_set_source_rgb (cr, 1, .5, 0); + cairo_move_to (cr, x, y); + cairo_show_text (cr, str); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const char *string = "0123456789"; + cairo_text_extents_t extents; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_text_extents (cr, string, &extents); + + cairo_set_font_size (cr, 12); + cairo_set_line_width (cr, 3); + cairo_move_to (cr, 9, 4 + extents.height); + halo_around_path (cr, string); + + cairo_move_to (cr, 109, 4 + extents.height); + halo_around_text (cr, string); + + cairo_set_font_size (cr, 6); + cairo_set_line_width (cr, 3); + cairo_move_to (cr, 19 + extents.width, 20 + extents.height); + halo_around_path (cr, "0"); + + cairo_move_to (cr, 119 + extents.width, 20 + extents.height); + halo_around_text (cr, "0"); + + cairo_set_font_size (cr, 64); + cairo_set_line_width (cr, 10); + cairo_move_to (cr, 8, 70); + halo_around_path (cr, "6"); + cairo_move_to (cr, 32, 90); + halo_around_path (cr, "7"); + + cairo_move_to (cr, 108, 70); + halo_around_text (cr, "6"); + cairo_move_to (cr, 132, 90); + halo_around_text (cr, "7"); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +draw_transform (cairo_t *cr, int width, int height) +{ + const char *string = "0123456789"; + cairo_text_extents_t extents; + + cairo_translate (cr, 50, 50); + cairo_scale (cr, M_SQRT2, M_SQRT2); + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_text_extents (cr, string, &extents); + + cairo_set_line_width (cr, 3); + cairo_move_to (cr, 9, 4 + extents.height); + halo_around_path (cr, string); + + cairo_move_to (cr, 109, 4 + extents.height); + halo_around_text (cr, string); + + cairo_set_font_size (cr, 6); + cairo_set_line_width (cr, 3); + cairo_move_to (cr, 19 + extents.width, 20 + extents.height); + halo_around_path (cr, "0"); + + cairo_move_to (cr, 119 + extents.width, 20 + extents.height); + halo_around_text (cr, "0"); + + cairo_set_font_size (cr, 64); + cairo_set_line_width (cr, 10); + cairo_move_to (cr, 8, 70); + halo_around_path (cr, "6"); + cairo_move_to (cr, 32, 90); + halo_around_path (cr, "7"); + + cairo_move_to (cr, 108, 70); + halo_around_text (cr, "6"); + cairo_move_to (cr, 132, 90); + halo_around_text (cr, "7"); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (halo, + "Check the show_glyphs() vs glyph_path()", + "text", /* keywords */ + NULL, /* requirements */ + 200, 100, + NULL, draw) + +CAIRO_TEST (halo_transform, + "Check the show_glyphs() vs glyph_path()", + "text", /* keywords */ + NULL, /* requirements */ + 400, 200, + NULL, draw_transform) diff --git a/local/recipes/libs/cairo/source/test/hatchings.c b/local/recipes/libs/cairo/source/test/hatchings.c new file mode 100644 index 0000000000..ca3f2c6afa --- /dev/null +++ b/local/recipes/libs/cairo/source/test/hatchings.c @@ -0,0 +1,153 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +#define STEP 5 +#define WIDTH 100 +#define HEIGHT 100 + +static void hatching (cairo_t *cr) +{ + int i; + + cairo_rectangle (cr, 0, 0, WIDTH, HEIGHT); + cairo_clip (cr); + + for (i = 0; i < WIDTH; i += STEP) { + cairo_rectangle (cr, i-1, -2, 2, HEIGHT+4); + cairo_rectangle (cr, -2, i-1, WIDTH+4, 2); + } +} + +static void background (cairo_t *cr) +{ + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgb (cr, 1,1,1); + cairo_paint (cr); +} + +static void clip_to_quadrant (cairo_t *cr) +{ + cairo_rectangle (cr, 0, 0, WIDTH, HEIGHT); + cairo_clip (cr); +} + +static void draw_hatching (cairo_t *cr, void (*func) (cairo_t *)) +{ + cairo_save (cr); { + clip_to_quadrant (cr); + hatching (cr); + func (cr); + } cairo_restore (cr); + + cairo_translate (cr, WIDTH, 0); + + cairo_save (cr); { + clip_to_quadrant (cr); + cairo_translate (cr, 0.25, 0.25); + hatching (cr); + func (cr); + } cairo_restore (cr); + + cairo_translate (cr, WIDTH, 0); + + cairo_save (cr); { + clip_to_quadrant (cr); + cairo_translate (cr, WIDTH/2, HEIGHT/2); + cairo_rotate (cr, M_PI/4); + cairo_translate (cr, -WIDTH/2, -HEIGHT/2); + hatching (cr); + func (cr); + } cairo_restore (cr); + + cairo_translate (cr, WIDTH, 0); +} + +static void do_clip (cairo_t *cr) +{ + cairo_clip (cr); + cairo_paint (cr); +} + +static void do_clip_alpha (cairo_t *cr) +{ + cairo_clip (cr); + cairo_paint_with_alpha (cr, .5); +} + +static void hatchings (cairo_t *cr, void (*func) (cairo_t *)) +{ + cairo_save (cr); { + cairo_set_source_rgb(cr, 1, 0, 0); + cairo_set_antialias (cr, CAIRO_ANTIALIAS_DEFAULT); + draw_hatching (cr, func); + cairo_set_source_rgb(cr, 0, 0, 1); + cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); + draw_hatching (cr, func); + } cairo_restore (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + background (cr); + + + /* aligned, misaligned, diagonal; mono repeat + * x fill + * x clip; paint + * x clip; paint-alpha + * repeated, for over/source + */ + + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + + hatchings (cr, cairo_fill); + cairo_translate (cr, 0, HEIGHT); + hatchings (cr, do_clip); + cairo_translate (cr, 0, HEIGHT); + hatchings (cr, do_clip_alpha); + cairo_translate (cr, 0, HEIGHT); + + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + + hatchings (cr, cairo_fill); + cairo_translate (cr, 0, HEIGHT); + hatchings (cr, do_clip); + cairo_translate (cr, 0, HEIGHT); + hatchings (cr, do_clip_alpha); + cairo_translate (cr, 0, HEIGHT); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (hatchings, + "Test drawing through various aligned/unaliged clips", + "clip, alpha", /* keywords */ + "target=raster", /* requirements */ + 6*WIDTH, 6*HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/horizontal-clip.c b/local/recipes/libs/cairo/source/test/horizontal-clip.c new file mode 100644 index 0000000000..93127a7228 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/horizontal-clip.c @@ -0,0 +1,77 @@ +/* + * Copyright 2011 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +/* Exercises a bug spotted by Andrea Canciani where the polygon clipping + * code was hopeless broken with horizontal edges. + */ + +#include "cairo-test.h" + +#define WIDTH 16 +#define HEIGHT 26 + +#define BUGY 1 +#define BUGX (4 * BUGY * WIDTH * 256) + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + + cairo_move_to (cr, - BUGX, 6 - BUGY); + cairo_line_to (cr, + BUGX, 6 + BUGY); + cairo_line_to (cr, WIDTH + BUGX, 2 - BUGY); + cairo_line_to (cr, WIDTH - BUGX, 2 + BUGY); + cairo_fill (cr); + + cairo_move_to (cr, WIDTH + BUGX, 8 - BUGY); + cairo_line_to (cr, WIDTH - BUGX, 8 + BUGY); + cairo_line_to (cr, - BUGX, 12 - BUGY); + cairo_line_to (cr, + BUGX, 12 + BUGY); + cairo_fill (cr); + + cairo_move_to (cr, - BUGX, 14 - BUGY); + cairo_line_to (cr, + BUGX, 14 + BUGY); + cairo_line_to (cr, WIDTH + BUGX, 18 - BUGY); + cairo_line_to (cr, WIDTH - BUGX, 18 + BUGY); + cairo_fill (cr); + + cairo_move_to (cr, WIDTH + BUGX, 24 - BUGY); + cairo_line_to (cr, WIDTH - BUGX, 24 + BUGY); + cairo_line_to (cr, - BUGX, 20 - BUGY); + cairo_line_to (cr, + BUGX, 20 + BUGY); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (horizontal_clip, + "Tests intersection of a nearly horizontal lines with a clipped polygon", + "clip, fill", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/huge-linear.c b/local/recipes/libs/cairo/source/test/huge-linear.c new file mode 100644 index 0000000000..f84b4ea0cc --- /dev/null +++ b/local/recipes/libs/cairo/source/test/huge-linear.c @@ -0,0 +1,67 @@ +/* + * Copyright © 2006 Benjamin Otte + * + * 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: Benjamin Otte + */ + +#include "cairo-test.h" + +/* set this to 0.1 to make this test work */ +#define FACTOR 1.e6 + +/* XXX poppler-cairo doesn't handle gradients very well... */ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *pattern; + cairo_matrix_t mat = { + 0, -4.5254285714285709 * FACTOR, + -2.6398333333333333 * FACTOR, 0, + 0, 0 + }; + + pattern = cairo_pattern_create_linear (-16384 * FACTOR, 0, + 16384 * FACTOR, 0); + cairo_pattern_add_color_stop_rgba (pattern, + 0, 0.376471, 0.533333, 0.27451, 1); + cairo_pattern_add_color_stop_rgba (pattern, 1, 1, 1, 1, 1); + cairo_pattern_set_matrix (pattern, &mat); + + cairo_scale (cr, 0.05, 0.05); + cairo_translate (cr, 6000, 3500); + + cairo_set_source (cr, pattern); + cairo_rectangle (cr, -6000, -3500, 12000, 7000); + cairo_pattern_destroy (pattern); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (huge_linear, + "Test huge linear patterns", + "gradient, linear", /* keywords */ + NULL, /* requirements */ + 600, 350, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/huge-radial.c b/local/recipes/libs/cairo/source/test/huge-radial.c new file mode 100644 index 0000000000..21524b7a45 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/huge-radial.c @@ -0,0 +1,69 @@ +/* + * Copyright © 2006 Benjamin Otte + * Copyright © 2009 Chris Wilson + * + * 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: Benjamin Otte + * Chris Wilson + */ + +#include "cairo-test.h" + +/* set this to 0.1 to make this test work */ +#define FACTOR 1.e6 + +/* XXX poppler-cairo doesn't handle gradients very well... */ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *pattern; + cairo_matrix_t mat = { + 0, -4.5254285714285709 * FACTOR, + -2.6398333333333333 * FACTOR, 0, + 0, 0 + }; + + pattern = cairo_pattern_create_radial (0, 0, 0, + 0, 0, 16384 * FACTOR); + cairo_pattern_add_color_stop_rgba (pattern, + 0, 0.376471, 0.533333, 0.27451, 1); + cairo_pattern_add_color_stop_rgba (pattern, 1, 1, 1, 1, 1); + cairo_pattern_set_matrix (pattern, &mat); + + cairo_scale (cr, 0.05, 0.05); + cairo_translate (cr, 6000, 3500); + + cairo_set_source (cr, pattern); + cairo_rectangle (cr, -6000, -3500, 12000, 7000); + cairo_pattern_destroy (pattern); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (huge_radial, + "Test huge radial patterns", + "gradient, radial", /* keywords */ + NULL, /* requirements */ + 600, 350, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/image-bug-710072.c b/local/recipes/libs/cairo/source/test/image-bug-710072.c new file mode 100644 index 0000000000..9cf0da799a --- /dev/null +++ b/local/recipes/libs/cairo/source/test/image-bug-710072.c @@ -0,0 +1,80 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +/* + * This test case aims to reproduce the misbehaviour exhibited in + * https://bugs.launchpad.net/ubuntu/+source/cairo/+bug/710072 + * i.e. out of bounds rendering with the rectangular span compositor. + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw_aligned (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_rectangle (cr, -10, -10, 20, 20); + cairo_rectangle (cr, 5, 5, 20, 20); + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_fill_preserve (cr); + cairo_set_source_rgba (cr, 1, 0, 0, .5); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +draw_unaligned (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_rectangle (cr, -10.5, -10.5, 20, 20); + cairo_rectangle (cr, 5.5, 5.5, 20, 20); + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_fill_preserve (cr); + cairo_set_source_rgba (cr, 1, 0, 0, .5); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (image_bug_710072_aligned, + "Tests a bug where we may compute spans greater than bounded extents", + "extents, fill, stroke", /* keywords */ + NULL, /* requirements */ + 15, 15, + NULL, draw_aligned) + +CAIRO_TEST (image_bug_710072_unaligned, + "Tests a bug where we may compute spans greater than bounded extents", + "extents, fill, stroke", /* keywords */ + NULL, /* requirements */ + 15, 15, + NULL, draw_unaligned) diff --git a/local/recipes/libs/cairo/source/test/image-surface-source.c b/local/recipes/libs/cairo/source/test/image-surface-source.c new file mode 100644 index 0000000000..c7c1fdc332 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/image-surface-source.c @@ -0,0 +1,41 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +#include "surface-source.c" + +static cairo_surface_t * +create_source_surface (int size) +{ + return cairo_image_surface_create (CAIRO_FORMAT_ARGB32, size, size); +} + +CAIRO_TEST (image_surface_source, + "Test using a image surface as the source", + "source", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + preamble, draw) diff --git a/local/recipes/libs/cairo/source/test/image1.jb2 b/local/recipes/libs/cairo/source/test/image1.jb2 new file mode 100644 index 0000000000..882ca95eb1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/image1.jb2 differ diff --git a/local/recipes/libs/cairo/source/test/image2.jb2 b/local/recipes/libs/cairo/source/test/image2.jb2 new file mode 100644 index 0000000000..48e41463f2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/image2.jb2 differ diff --git a/local/recipes/libs/cairo/source/test/imagediff.c b/local/recipes/libs/cairo/source/test/imagediff.c new file mode 100644 index 0000000000..c091e76278 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/imagediff.c @@ -0,0 +1,301 @@ +/* imagediff - Compare two images + * + * Copyright © 2004 Richard D. Worth + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of Richard Worth + * not be used in advertising or publicity pertaining to distribution + * of the software without specific, written prior permission. + * Richard Worth makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * RICHARD WORTH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL RICHARD WORTH BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Richard D. Worth */ + +#include "config.h" + +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include + +#include "buffer-diff.h" + +static void +_xunlink (const char *pathname) +{ + if (unlink (pathname) < 0 && errno != ENOENT) { + fprintf (stderr, " Error: Cannot remove %s: %s\n", + pathname, strerror (errno)); + exit (1); + } +} + +void +cairo_test_logv (const cairo_test_context_t *ctx, + const char *fmt, va_list va) +{ + vfprintf (stderr, fmt, va); +} + +void +cairo_test_log (const cairo_test_context_t *ctx, const char *fmt, ...) +{ + va_list va; + + va_start (va, fmt); + vfprintf (stderr, fmt, va); + va_end (va); +} + +/* Flatten an ARGB surface by blending it over white. The resulting + * surface, (still in ARGB32 format, but with only alpha==1.0 + * everywhere) is returned in the same surface pointer. + * + * The original surface will be destroyed. + * + * The (x,y) value specify an origin of interest for the original + * image. The flattened image will be generated only from the box + * extending from (x,y) to (width,height). + */ +static void +flatten_surface (cairo_surface_t **surface, int x, int y) +{ + cairo_surface_t *flat; + cairo_t *cr; + + flat = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + cairo_image_surface_get_width (*surface) - x, + cairo_image_surface_get_height (*surface) - y); + cairo_surface_set_device_offset (flat, -x, -y); + + cr = cairo_create (flat); + cairo_surface_destroy (flat); + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_set_source_surface (cr, *surface, 0, 0); + cairo_surface_destroy (*surface); + cairo_paint (cr); + + *surface = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); +} + +/* Given an image surface, create a new surface that has the same + * contents as the sub-surface with its origin at x,y. + * + * The original surface will be destroyed. + */ +static void +extract_sub_surface (cairo_surface_t **surface, int x, int y) +{ + cairo_surface_t *sub; + cairo_t *cr; + + sub = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + cairo_image_surface_get_width (*surface) - x, + cairo_image_surface_get_height (*surface) - y); + + /* We don't use a device offset like flatten_surface. That's not + * for any important reason, (the results should be + * identical). This style just seemed more natural to me this + * time, so I'm leaving both here so I can look at both to see + * which I like better. */ + cr = cairo_create (sub); + cairo_surface_destroy (sub); + + cairo_set_source_surface (cr, *surface, -x, -y); + cairo_surface_destroy (*surface); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_paint (cr); + + *surface = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); +} + +static cairo_status_t +stdio_write_func (void *closure, const unsigned char *data, unsigned int length) +{ + FILE *file = closure; + + if (fwrite (data, 1, length, file) != length) + return CAIRO_STATUS_WRITE_ERROR; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +write_png (cairo_surface_t *surface, const char *filename) +{ + cairo_status_t status; + FILE *png_file; + + if (filename != NULL) { + png_file = fopen (filename, "wb"); + if (png_file == NULL) { + switch (errno) { + case ENOMEM: + return CAIRO_STATUS_NO_MEMORY; + default: + return CAIRO_STATUS_WRITE_ERROR; + } + } + } else + png_file = stdout; + + status = cairo_surface_write_to_png_stream (surface, + stdio_write_func, + png_file); + + if (png_file != stdout) + fclose (png_file); + + return status; +} + +static cairo_status_t +png_diff (const char *filename_a, + const char *filename_b, + const char *filename_diff, + int ax, + int ay, + int bx, + int by, + buffer_diff_result_t *result) +{ + cairo_surface_t *surface_a; + cairo_surface_t *surface_b; + cairo_surface_t *surface_diff; + cairo_status_t status; + + surface_a = cairo_image_surface_create_from_png (filename_a); + status = cairo_surface_status (surface_a); + if (status) { + fprintf (stderr, "Error: Failed to create surface from %s: %s\n", + filename_a, cairo_status_to_string (status)); + return status; + } + + surface_b = cairo_image_surface_create_from_png (filename_b); + status = cairo_surface_status (surface_b); + if (status) { + fprintf (stderr, "Error: Failed to create surface from %s: %s\n", + filename_b, cairo_status_to_string (status)); + cairo_surface_destroy (surface_a); + return status; + } + + if (ax || ay) { + extract_sub_surface (&surface_a, ax, ay); + ax = ay = 0; + } + + if (bx || by) { + extract_sub_surface (&surface_b, bx, by); + bx = by = 0; + } + + status = cairo_surface_status (surface_a); + if (status) { + fprintf (stderr, "Error: Failed to extract surface from %s: %s\n", + filename_a, cairo_status_to_string (status)); + cairo_surface_destroy (surface_a); + cairo_surface_destroy (surface_b); + return status; + } + status = cairo_surface_status (surface_b); + if (status) { + fprintf (stderr, "Error: Failed to extract surface from %s: %s\n", + filename_b, cairo_status_to_string (status)); + cairo_surface_destroy (surface_a); + cairo_surface_destroy (surface_b); + return status; + } + + surface_diff = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + cairo_image_surface_get_width (surface_a), + cairo_image_surface_get_height (surface_a)); + status = cairo_surface_status (surface_diff); + if (status) { + fprintf (stderr, + "Error: Failed to allocate surface to hold differences\n"); + cairo_surface_destroy (surface_a); + cairo_surface_destroy (surface_b); + return CAIRO_STATUS_NO_MEMORY; + } + + status = image_diff (NULL, + surface_a, surface_b, surface_diff, + result); + + if (filename_diff) + _xunlink (filename_diff); + + if (status == CAIRO_STATUS_SUCCESS && + result->pixels_changed) + { + status = write_png (surface_diff, filename_diff); + } + + cairo_surface_destroy (surface_a); + cairo_surface_destroy (surface_b); + cairo_surface_destroy (surface_diff); + + return status; +} + +int +main (int argc, char *argv[]) +{ + buffer_diff_result_t result; + cairo_status_t status; + + unsigned int ax, ay, bx, by; + + if (argc != 3 && argc != 7) { + fprintf (stderr, "Usage: %s image1.png image2.png [ax ay bx by]\n", argv[0]); + fprintf (stderr, "Computes an output image designed to present a \"visual diff\" such that even\n"); + fprintf (stderr, "small errors in single pixels are readily apparent in the output.\n"); + fprintf (stderr, "The output image is written on stdout.\n"); + exit (1); + } + + if (argc == 7) { + ax = strtoul (argv[3], NULL, 0); + ay = strtoul (argv[4], NULL, 0); + bx = strtoul (argv[5], NULL, 0); + by = strtoul (argv[6], NULL, 0); + } else { + ax = ay = bx = by = 0; + } + + status = png_diff (argv[1], argv[2], NULL, ax, ay, bx, by, &result); + + if (status) { + fprintf (stderr, "Error comparing images: %s\n", + cairo_status_to_string (status)); + return 1; + } + + if (result.pixels_changed) + fprintf (stderr, "Total pixels changed: %d with a maximum channel difference of %d.\n", + result.pixels_changed, + result.max_diff); + + return (result.pixels_changed != 0); +} diff --git a/local/recipes/libs/cairo/source/test/implicit-close.c b/local/recipes/libs/cairo/source/test/implicit-close.c new file mode 100644 index 0000000000..2529bb00f2 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/implicit-close.c @@ -0,0 +1,54 @@ +/* + * Copyright © 2009 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +#define SIZE 40 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_move_to (cr, SIZE, 0); + cairo_rel_line_to (cr, 0, SIZE); + cairo_rel_line_to (cr, -SIZE, 0); + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_fill_preserve (cr); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (implicit_close, + "Test implicitly closing paths", + "fill", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/in-fill-empty-trapezoid.c b/local/recipes/libs/cairo/source/test/in-fill-empty-trapezoid.c new file mode 100644 index 0000000000..0797399c58 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/in-fill-empty-trapezoid.c @@ -0,0 +1,109 @@ +/* + * Copyright © 2006 M Joonas Pihlaja + * + * 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: M Joonas Pihlaja + */ + +/* Bug history + * + * 2006-12-05 M Joonas Pihlaja + * + * The cairo_in_fill () function can sometimes produce false + * positives when the tessellator produces empty trapezoids + * and the query point lands exactly on a trapezoid edge. + */ + +#include "cairo-test.h" + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + int x,y; + int width = 10; + int height = 10; + cairo_surface_t *surf; + cairo_t *cr; + int false_positive_count = 0; + cairo_status_t status; + cairo_test_status_t ret; + + surf = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); + cr = cairo_create (surf); + cairo_surface_destroy (surf); + + /* Empty horizontal trapezoid. */ + cairo_move_to (cr, 0, height/3); + cairo_line_to (cr, width, height/3); + cairo_close_path (cr); + + /* Empty non-horizontal trapezoid #1. */ + cairo_move_to (cr, 0, 0); + cairo_line_to (cr, width, height/2); + cairo_close_path (cr); + + /* Empty non-horizontal trapezoid #2 intersecting #1. */ + cairo_move_to (cr, 0, height/2); + cairo_line_to (cr, width, 0); + cairo_close_path (cr); + + status = cairo_status (cr); + + /* Point sample the tessellated path. */ + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + if (cairo_in_fill (cr, x, y)) { + false_positive_count++; + } + } + } + cairo_destroy (cr); + + /* Check that everything went well. */ + ret = CAIRO_TEST_SUCCESS; + if (CAIRO_STATUS_SUCCESS != status) { + cairo_test_log (ctx, "Failed to create a test surface and path: %s\n", + cairo_status_to_string (status)); + ret = CAIRO_TEST_XFAILURE; + } + + if (0 != false_positive_count) { + cairo_test_log (ctx, "Point sampling found %d false positives " + "from cairo_in_fill()\n", + false_positive_count); + ret = CAIRO_TEST_XFAILURE; + } + + return ret; +} + +/* + * XFAIL: The cairo_in_fill () function can sometimes produce false positives + * when the tessellator produces empty trapezoids and the query point lands + * exactly on a trapezoid edge. + */ +CAIRO_TEST (in_fill_empty_trapezoid, + "Test that the tessellator isn't producing obviously empty trapezoids", + "in, trap", /* keywords */ + NULL, /* requirements */ + 0, 0, + preamble, NULL) diff --git a/local/recipes/libs/cairo/source/test/in-fill-trapezoid.c b/local/recipes/libs/cairo/source/test/in-fill-trapezoid.c new file mode 100644 index 0000000000..84b323a050 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/in-fill-trapezoid.c @@ -0,0 +1,279 @@ +/* + * Copyright © 2008 Chris Wilson + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + cairo_test_status_t ret = CAIRO_TEST_SUCCESS; + cairo_surface_t *surface; + cairo_t *cr; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0); + cr = cairo_create (surface); + cairo_surface_destroy (surface); + + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + + /* simple rectangle */ + cairo_new_path (cr); + cairo_rectangle (cr, -10, -10, 20, 20); + if (! cairo_in_fill (cr, 0, 0)) { + cairo_test_log (ctx, "Error: Failed to find point inside rectangle\n"); + ret = CAIRO_TEST_FAILURE; + } + + /* rectangular boundary tests */ + if (! cairo_in_fill (cr, -10, -10)) { + cairo_test_log (ctx, "Error: Failed to find top-left vertex inside rectangle\n"); + ret = CAIRO_TEST_FAILURE; + } + if (! cairo_in_fill (cr, -10, 10)) { + cairo_test_log (ctx, "Error: Failed to find bottom-left vertex inside rectangle\n"); + ret = CAIRO_TEST_FAILURE; + } + if (! cairo_in_fill (cr, 10, -10)) { + cairo_test_log (ctx, "Error: Failed to find top-right vertex inside rectangle\n"); + ret = CAIRO_TEST_FAILURE; + } + if (! cairo_in_fill (cr, 10, 10)) { + cairo_test_log (ctx, "Error: Failed to find bottom-right vertex inside rectangle\n"); + ret = CAIRO_TEST_FAILURE; + } + if (! cairo_in_fill (cr, -10, 0)) { + cairo_test_log (ctx, "Error: Failed to find left edge inside rectangle\n"); + ret = CAIRO_TEST_FAILURE; + } + if (! cairo_in_fill (cr, 0, -10)) { + cairo_test_log (ctx, "Error: Failed to find top edge inside rectangle\n"); + ret = CAIRO_TEST_FAILURE; + } + if (! cairo_in_fill (cr, 10, 0)) { + cairo_test_log (ctx, "Error: Failed to find right edge inside rectangle\n"); + ret = CAIRO_TEST_FAILURE; + } + if (! cairo_in_fill (cr, 0, 10)) { + cairo_test_log (ctx, "Error: Failed to find bottom edge inside rectangle\n"); + ret = CAIRO_TEST_FAILURE; + } + + /* simple circle */ + cairo_new_path (cr); + cairo_arc (cr, 0, 0, 10, 0, 2 * M_PI); + if (! cairo_in_fill (cr, 0, 0)) { + cairo_test_log (ctx, "Error: Failed to find point inside circle [even-odd]\n"); + ret = CAIRO_TEST_FAILURE; + } + + /* holey rectangle */ + cairo_new_path (cr); + cairo_rectangle (cr, -10, -10, 20, 20); + cairo_rectangle (cr, -5, -5, 10, 10); + if (cairo_in_fill (cr, 0, 0)) { + cairo_test_log (ctx, "Error: Found an unexpected point inside rectangular eo-hole\n"); + ret = CAIRO_TEST_FAILURE; + } + + /* holey circle */ + cairo_new_path (cr); + cairo_arc (cr, 0, 0, 10, 0, 2 * M_PI); + cairo_arc (cr, 0, 0, 5, 0, 2 * M_PI); + if (cairo_in_fill (cr, 0, 0)) { + cairo_test_log (ctx, "Error: Found an unexpected point inside circular eo-hole\n"); + ret = CAIRO_TEST_FAILURE; + } + + + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_WINDING); + + /* simple rectangle */ + cairo_new_path (cr); + cairo_rectangle (cr, -10, -10, 20, 20); + if (! cairo_in_fill (cr, 0, 0)) { + cairo_test_log (ctx, "Error: Failed to find point inside rectangle\n"); + ret = CAIRO_TEST_FAILURE; + } + + /* simple circle */ + cairo_new_path (cr); + cairo_arc (cr, 0, 0, 10, 0, 2 * M_PI); + if (! cairo_in_fill (cr, 0, 0)) { + cairo_test_log (ctx, "Error: Failed to find point inside circle [nonzero]\n"); + ret = CAIRO_TEST_FAILURE; + } + + /* overlapping circle/rectangle */ + cairo_new_path (cr); + cairo_rectangle (cr, -10, -10, 20, 20); + cairo_new_sub_path (cr); + cairo_arc (cr, 0, 0, 10, 0, 2 * M_PI); + if (! cairo_in_fill (cr, 0, 0)) { + cairo_test_log (ctx, "Error: Failed to find point inside circle+rectangle\n"); + ret = CAIRO_TEST_FAILURE; + } + + /* holey rectangle */ + cairo_new_path (cr); + cairo_rectangle (cr, -10, -10, 20, 20); + cairo_rectangle (cr, 5, -5, -10, 10); + if (cairo_in_fill (cr, 0, 0)) { + cairo_test_log (ctx, "Error: Found an unexpected point inside rectangular non-zero-hole\n"); + ret = CAIRO_TEST_FAILURE; + } + + /* holey circle */ + cairo_new_path (cr); + cairo_arc (cr, 0, 0, 10, 0, 2 * M_PI); + cairo_arc_negative (cr, 0, 0, 5, 0, -2 * M_PI); + if (cairo_in_fill (cr, 0, 0)) { + cairo_test_log (ctx, "Error: Found an unexpected point inside circular non-zero-hole\n"); + ret = CAIRO_TEST_FAILURE; + } + + /* not a holey circle */ + cairo_new_path (cr); + cairo_arc (cr, 0, 0, 10, 0, 2 * M_PI); + cairo_arc (cr, 0, 0, 5, 0, 2 * M_PI); + if (! cairo_in_fill (cr, 0, 0)) { + cairo_test_log (ctx, "Error: Failed to find point inside two circles\n"); + ret = CAIRO_TEST_FAILURE; + } + + /* check off-centre */ + cairo_new_path (cr); + cairo_arc (cr, 7.5, 0, 10, 0, 2 * M_PI); + cairo_arc_negative (cr, 7.5, 0, 5, 0, -2 * M_PI); + if (cairo_in_fill (cr, 7.5, 0)) { + cairo_test_log (ctx, "Error: Found an unexpected point inside off-centre-x circular non-zero-hole\n"); + ret = CAIRO_TEST_FAILURE; + } + cairo_new_path (cr); + cairo_arc (cr, 0, 7.5, 10, 0, 2 * M_PI); + cairo_arc_negative (cr, 0, 7.5, 5, 0, -2 * M_PI); + if (cairo_in_fill (cr, 0, 7.5)) { + cairo_test_log (ctx, "Error: Found an unexpected point inside off-centre-y circular non-zero-hole\n"); + ret = CAIRO_TEST_FAILURE; + } + cairo_new_path (cr); + cairo_arc (cr, 15, 0, 10, 0, 2 * M_PI); + if (! cairo_in_fill (cr, 15, 0)) { + cairo_test_log (ctx, "Error: Failed to find point inside off-centre-x circle\n"); + ret = CAIRO_TEST_FAILURE; + } + cairo_new_path (cr); + cairo_arc (cr, 0, 15, 10, 0, 2 * M_PI); + if (! cairo_in_fill (cr, 0, 15)) { + cairo_test_log (ctx, "Error: Failed to find point inside off-centre-y circle\n"); + ret = CAIRO_TEST_FAILURE; + } + + /* simple rectangle */ + cairo_new_path (cr); + cairo_rectangle (cr, 10, 0, 5, 5); + if (cairo_in_fill (cr, 0, 0)) { + cairo_test_log (ctx, "Error: Found an unexpected point outside rectangle\n"); + ret = CAIRO_TEST_FAILURE; + } + if (cairo_in_fill (cr, 20, 20)) { + cairo_test_log (ctx, "Error: Found an unexpected point outside rectangle\n"); + ret = CAIRO_TEST_FAILURE; + } + if (! cairo_in_fill (cr, 12.5, 2.5)) { + cairo_test_log (ctx, "Error: Failed to find point inside rectangle\n"); + ret = CAIRO_TEST_FAILURE; + } + + /* off-centre triangle */ + cairo_new_path (cr); + cairo_move_to (cr, 10, 0); + cairo_line_to (cr, 15, 5); + cairo_line_to (cr, 5, 5); + cairo_close_path (cr); + if (cairo_in_fill (cr, 0, 0) || + cairo_in_fill (cr, 5, 0) || + cairo_in_fill (cr, 15, 0) || + cairo_in_fill (cr, 20, 0) || + cairo_in_fill (cr, 0, 10) || + cairo_in_fill (cr, 10, 10) || + cairo_in_fill (cr, 20, 10) || + cairo_in_fill (cr, 7, 2.5) || + cairo_in_fill (cr, 13, 2.5)) + { + cairo_test_log (ctx, + "Error: Found an unexpected point outside triangle\n" + "\t(0, 0) -> %s\n" + "\t(5, 0) -> %s\n" + "\t(15, 0) -> %s\n" + "\t(20, 0) -> %s\n" + "\t(0, 10) -> %s\n" + "\t(10, 10) -> %s\n" + "\t(20, 10) -> %s\n" + "\t(7, 2.5) -> %s\n" + "\t(13, 2.5) -> %s\n", + cairo_in_fill (cr, 0, 0) ? "inside" : "outside", + cairo_in_fill (cr, 5, 0) ? "inside" : "outside", + cairo_in_fill (cr, 15, 0) ? "inside" : "outside", + cairo_in_fill (cr, 20, 0) ? "inside" : "outside", + cairo_in_fill (cr, 0, 10) ? "inside" : "outside", + cairo_in_fill (cr, 10, 10) ? "inside" : "outside", + cairo_in_fill (cr, 20, 10) ? "inside" : "outside", + cairo_in_fill (cr, 7, 2.5) ? "inside" : "outside", + cairo_in_fill (cr, 13, 2.5) ? "inside" : "outside"); + ret = CAIRO_TEST_FAILURE; + } + if (! cairo_in_fill (cr, 7.5, 2.5) || + ! cairo_in_fill (cr, 12.5, 2.5) || + ! cairo_in_fill (cr, 10, 5)) + { + cairo_test_log (ctx, + "Error: Failed to find point on triangle edge\n" + "\t(7.5, 2.5) -> %s\n" + "\t(12.5, 2.5) -> %s\n" + "\t(10, 5) -> %s\n", + cairo_in_fill (cr, 7.5, 2.5) ? "inside" : "outside", + cairo_in_fill (cr, 12.5, 2.5) ? "inside" : "outside", + cairo_in_fill (cr, 10, 5) ? "inside" : "outside"); + ret = CAIRO_TEST_FAILURE; + } + if (! cairo_in_fill (cr, 8, 2.5) || + ! cairo_in_fill (cr, 12, 2.5)) + { + cairo_test_log (ctx, "Error: Failed to find point inside triangle\n"); + ret = CAIRO_TEST_FAILURE; + } + + cairo_destroy (cr); + + return ret; +} + +CAIRO_TEST (in_fill_trapezoid, + "Test cairo_in_fill", + "in, trap", /* keywords */ + NULL, /* requirements */ + 0, 0, + preamble, NULL) diff --git a/local/recipes/libs/cairo/source/test/index.html b/local/recipes/libs/cairo/source/test/index.html new file mode 100644 index 0000000000..54c65cdc12 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/index.html @@ -0,0 +1,42 @@ + +Cairo Test Results + + + + +
    + + diff --git a/local/recipes/libs/cairo/source/test/infinite-join.c b/local/recipes/libs/cairo/source/test/infinite-join.c new file mode 100644 index 0000000000..a573f56a5b --- /dev/null +++ b/local/recipes/libs/cairo/source/test/infinite-join.c @@ -0,0 +1,72 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of the + * copyright holders not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * + * Author: Carl D. Worth + */ + +/* Test case for bug #8379: + * + * infinite loop when stroking + * https://bugs.freedesktop.org/show_bug.cgi?id=8379 + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + /* Paint white, then draw in black. */ + cairo_set_source_rgb (cr, 1, 1, 1); /* white */ + cairo_paint (cr); + cairo_set_source_rgb (cr, 0, 0, 0); /* black */ + + cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); + + /* scaling 2 times causes a slight rounding error in the ctm. + * Without that, the bug doesn't happen. */ + cairo_scale (cr, 20 / 100., 20 / 100.); + cairo_scale (cr, 1. / 20, 1. / 20); + + cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); + cairo_set_line_width (cr, 20); + + cairo_translate (cr, -18300, -13200); + + cairo_new_path (cr); + cairo_move_to (cr, 18928, 13843); + cairo_line_to (cr, 18500, 13843); + cairo_line_to (cr, 18500, 13400); + cairo_line_to (cr, 18928, 13400); + cairo_line_to (cr, 18928, 13843); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (infinite_join, + "Test case for infinite loop when stroking with round joins", + "stroke", /* keywords */ + NULL, + 8, 8, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/invalid-matrix.c b/local/recipes/libs/cairo/source/test/invalid-matrix.c new file mode 100644 index 0000000000..df0dff0f19 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/invalid-matrix.c @@ -0,0 +1,374 @@ +/* + * Copyright © 2007 Red Hat, Inc. + * + * 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: Carl Worth + */ + +#define _ISOC99_SOURCE /* for INFINITY */ + +#include "config.h" +#include "cairo-test.h" + +#if !defined(INFINITY) +#define INFINITY HUGE_VAL +#endif + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_status_t status; + cairo_surface_t *target; + cairo_font_face_t *font_face; + cairo_font_options_t *font_options; + cairo_scaled_font_t *scaled_font; + cairo_pattern_t *pattern; + cairo_t *cr2; + cairo_matrix_t identity, bogus, inf, invalid = { + 4.0, 4.0, + 4.0, 4.0, + 4.0, 4.0 + }; + +#define CHECK_STATUS(status, function_name) \ +if ((status) == CAIRO_STATUS_SUCCESS) { \ + cairo_test_log (ctx, "Error: %s with invalid matrix passed\n", \ + (function_name)); \ + return CAIRO_TEST_FAILURE; \ +} else if ((status) != CAIRO_STATUS_INVALID_MATRIX) { \ + cairo_test_log (ctx, "Error: %s with invalid matrix returned unexpected status " \ + "(%d): %s\n", \ + (function_name), \ + status, \ + cairo_status_to_string (status)); \ + return CAIRO_TEST_FAILURE; \ +} + + /* clear floating point exceptions (added by cairo_test_init()) */ +#if HAVE_FEDISABLEEXCEPT + fedisableexcept (FE_INVALID); +#endif + + /* create a bogus matrix and check results of attempted inversion */ + bogus.x0 = bogus.xy = bogus.xx = cairo_test_NaN (); + bogus.y0 = bogus.yx = bogus.yy = bogus.xx; + status = cairo_matrix_invert (&bogus); + CHECK_STATUS (status, "cairo_matrix_invert(NaN)"); + + inf.x0 = inf.xy = inf.xx = INFINITY; + inf.y0 = inf.yx = inf.yy = inf.xx; + status = cairo_matrix_invert (&inf); + CHECK_STATUS (status, "cairo_matrix_invert(infinity)"); + + /* test cairo_matrix_invert with invalid matrix */ + status = cairo_matrix_invert (&invalid); + CHECK_STATUS (status, "cairo_matrix_invert(invalid)"); + + + cairo_matrix_init_identity (&identity); + + target = cairo_get_group_target (cr); + + /* test cairo_transform with invalid matrix */ + cr2 = cairo_create (target); + cairo_transform (cr2, &invalid); + + status = cairo_status (cr2); + cairo_destroy (cr2); + CHECK_STATUS (status, "cairo_transform(invalid)"); + + /* test cairo_transform with bogus matrix */ + cr2 = cairo_create (target); + cairo_transform (cr2, &bogus); + + status = cairo_status (cr2); + cairo_destroy (cr2); + CHECK_STATUS (status, "cairo_transform(NaN)"); + + /* test cairo_transform with ∞ matrix */ + cr2 = cairo_create (target); + cairo_transform (cr2, &inf); + + status = cairo_status (cr2); + cairo_destroy (cr2); + CHECK_STATUS (status, "cairo_transform(infinity)"); + + + /* test cairo_set_matrix with invalid matrix */ + cr2 = cairo_create (target); + cairo_set_matrix (cr2, &invalid); + + status = cairo_status (cr2); + cairo_destroy (cr2); + CHECK_STATUS (status, "cairo_set_matrix(invalid)"); + + /* test cairo_set_matrix with bogus matrix */ + cr2 = cairo_create (target); + cairo_set_matrix (cr2, &bogus); + + status = cairo_status (cr2); + cairo_destroy (cr2); + CHECK_STATUS (status, "cairo_set_matrix(NaN)"); + + /* test cairo_set_matrix with ∞ matrix */ + cr2 = cairo_create (target); + cairo_set_matrix (cr2, &inf); + + status = cairo_status (cr2); + cairo_destroy (cr2); + CHECK_STATUS (status, "cairo_set_matrix(infinity)"); + + + /* test cairo_set_font_matrix with invalid matrix */ + cr2 = cairo_create (target); + cairo_set_font_matrix (cr2, &invalid); + + /* draw some text to force the font to be resolved */ + cairo_show_text (cr2, "hello"); + + status = cairo_status (cr2); + cairo_destroy (cr2); + CHECK_STATUS (status, "cairo_set_font_matrix(invalid)"); + + /* test cairo_set_font_matrix with bogus matrix */ + cr2 = cairo_create (target); + cairo_set_font_matrix (cr2, &bogus); + + /* draw some text to force the font to be resolved */ + cairo_show_text (cr2, "hello"); + + status = cairo_status (cr2); + cairo_destroy (cr2); + CHECK_STATUS (status, "cairo_set_font_matrix(NaN)"); + + /* test cairo_set_font_matrix with ∞ matrix */ + cr2 = cairo_create (target); + cairo_set_font_matrix (cr2, &inf); + + /* draw some text to force the font to be resolved */ + cairo_show_text (cr2, "hello"); + + status = cairo_status (cr2); + cairo_destroy (cr2); + CHECK_STATUS (status, "cairo_set_font_matrix(infinity)"); + + + /* test cairo_scaled_font_create with invalid matrix */ + cr2 = cairo_create (target); + font_face = cairo_get_font_face (cr2); + font_options = cairo_font_options_create (); + cairo_get_font_options (cr, font_options); + scaled_font = cairo_scaled_font_create (font_face, + &invalid, + &identity, + font_options); + status = cairo_scaled_font_status (scaled_font); + CHECK_STATUS (status, "cairo_scaled_font_create(invalid)"); + + cairo_scaled_font_destroy (scaled_font); + + scaled_font = cairo_scaled_font_create (font_face, + &identity, + &invalid, + font_options); + status = cairo_scaled_font_status (scaled_font); + CHECK_STATUS (status, "cairo_scaled_font_create(invalid)"); + + cairo_scaled_font_destroy (scaled_font); + cairo_font_options_destroy (font_options); + cairo_destroy (cr2); + + /* test cairo_scaled_font_create with bogus matrix */ + cr2 = cairo_create (target); + font_face = cairo_get_font_face (cr2); + font_options = cairo_font_options_create (); + cairo_get_font_options (cr, font_options); + scaled_font = cairo_scaled_font_create (font_face, + &bogus, + &identity, + font_options); + status = cairo_scaled_font_status (scaled_font); + CHECK_STATUS (status, "cairo_scaled_font_create(NaN)"); + + cairo_scaled_font_destroy (scaled_font); + + scaled_font = cairo_scaled_font_create (font_face, + &identity, + &bogus, + font_options); + status = cairo_scaled_font_status (scaled_font); + CHECK_STATUS (status, "cairo_scaled_font_create(NaN)"); + + cairo_scaled_font_destroy (scaled_font); + cairo_font_options_destroy (font_options); + cairo_destroy (cr2); + + /* test cairo_scaled_font_create with ∞ matrix */ + cr2 = cairo_create (target); + font_face = cairo_get_font_face (cr2); + font_options = cairo_font_options_create (); + cairo_get_font_options (cr, font_options); + scaled_font = cairo_scaled_font_create (font_face, + &inf, + &identity, + font_options); + status = cairo_scaled_font_status (scaled_font); + CHECK_STATUS (status, "cairo_scaled_font_create(infinity)"); + + cairo_scaled_font_destroy (scaled_font); + + scaled_font = cairo_scaled_font_create (font_face, + &identity, + &inf, + font_options); + status = cairo_scaled_font_status (scaled_font); + CHECK_STATUS (status, "cairo_scaled_font_create(infinity)"); + + cairo_scaled_font_destroy (scaled_font); + cairo_font_options_destroy (font_options); + cairo_destroy (cr2); + + + /* test cairo_pattern_set_matrix with invalid matrix */ + pattern = cairo_pattern_create_rgb (1.0, 1.0, 1.0); + cairo_pattern_set_matrix (pattern, &invalid); + status = cairo_pattern_status (pattern); + CHECK_STATUS (status, "cairo_pattern_set_matrix(invalid)"); + cairo_pattern_destroy (pattern); + + /* test cairo_pattern_set_matrix with bogus matrix */ + pattern = cairo_pattern_create_rgb (1.0, 1.0, 1.0); + cairo_pattern_set_matrix (pattern, &bogus); + status = cairo_pattern_status (pattern); + CHECK_STATUS (status, "cairo_pattern_set_matrix(NaN)"); + cairo_pattern_destroy (pattern); + + /* test cairo_pattern_set_matrix with ∞ matrix */ + pattern = cairo_pattern_create_rgb (1.0, 1.0, 1.0); + cairo_pattern_set_matrix (pattern, &inf); + status = cairo_pattern_status (pattern); + CHECK_STATUS (status, "cairo_pattern_set_matrix(infinity)"); + cairo_pattern_destroy (pattern); + + + /* test invalid transformations */ + cr2 = cairo_create (target); + cairo_translate (cr2, bogus.xx, bogus.yy); + CHECK_STATUS (status, "cairo_translate(NaN, NaN)"); + cairo_destroy (cr2); + + cr2 = cairo_create (target); + cairo_translate (cr2, 0, bogus.yy); + CHECK_STATUS (status, "cairo_translate(0, NaN)"); + cairo_destroy (cr2); + + cr2 = cairo_create (target); + cairo_translate (cr2, bogus.xx, 0); + CHECK_STATUS (status, "cairo_translate(NaN, 0)"); + cairo_destroy (cr2); + + cr2 = cairo_create (target); + cairo_translate (cr2, inf.xx, inf.yy); + CHECK_STATUS (status, "cairo_translate(∞, ∞)"); + cairo_destroy (cr2); + + cr2 = cairo_create (target); + cairo_translate (cr2, 0, inf.yy); + CHECK_STATUS (status, "cairo_translate(0, ∞)"); + cairo_destroy (cr2); + + cr2 = cairo_create (target); + cairo_translate (cr2, inf.xx, 0); + CHECK_STATUS (status, "cairo_translate(∞, 0)"); + cairo_destroy (cr2); + + + cr2 = cairo_create (target); + cairo_scale (cr2, bogus.xx, bogus.yy); + CHECK_STATUS (status, "cairo_scale(NaN, NaN)"); + cairo_destroy (cr2); + + cr2 = cairo_create (target); + cairo_scale (cr2, 1, bogus.yy); + CHECK_STATUS (status, "cairo_scale(1, NaN)"); + cairo_destroy (cr2); + + cr2 = cairo_create (target); + cairo_scale (cr2, bogus.xx, 1); + CHECK_STATUS (status, "cairo_scale(NaN, 1)"); + cairo_destroy (cr2); + + cr2 = cairo_create (target); + cairo_scale (cr2, inf.xx, inf.yy); + CHECK_STATUS (status, "cairo_scale(∞, ∞)"); + cairo_destroy (cr2); + + cr2 = cairo_create (target); + cairo_scale (cr2, 1, inf.yy); + CHECK_STATUS (status, "cairo_scale(1, ∞)"); + cairo_destroy (cr2); + + cr2 = cairo_create (target); + cairo_scale (cr2, inf.xx, 1); + CHECK_STATUS (status, "cairo_scale(∞, 1)"); + cairo_destroy (cr2); + + cr2 = cairo_create (target); + cairo_scale (cr2, bogus.xx, bogus.yy); + CHECK_STATUS (status, "cairo_scale(0, 0)"); + cairo_destroy (cr2); + + cr2 = cairo_create (target); + cairo_scale (cr2, 1, bogus.yy); + CHECK_STATUS (status, "cairo_scale(1, 0)"); + cairo_destroy (cr2); + + cr2 = cairo_create (target); + cairo_scale (cr2, bogus.xx, 1); + CHECK_STATUS (status, "cairo_scale(0, 1)"); + cairo_destroy (cr2); + + + cr2 = cairo_create (target); + cairo_rotate (cr2, bogus.xx); + CHECK_STATUS (status, "cairo_rotate(NaN)"); + cairo_destroy (cr2); + + cr2 = cairo_create (target); + cairo_rotate (cr2, inf.xx); + CHECK_STATUS (status, "cairo_rotate(∞)"); + cairo_destroy (cr2); + +#if HAVE_FECLEAREXCEPT + feclearexcept (FE_INVALID); +#endif + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (invalid_matrix, + "Test that all relevant public functions return CAIRO_STATUS_INVALID_MATRIX as appropriate", + "api, matrix", /* keywords */ + NULL, /* requirements */ + 0, 0, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/inverse-text.c b/local/recipes/libs/cairo/source/test/inverse-text.c new file mode 100644 index 0000000000..c8d7aea62a --- /dev/null +++ b/local/recipes/libs/cairo/source/test/inverse-text.c @@ -0,0 +1,67 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * Copyright © 2010 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + * Chris Wilson + */ + +#include "cairo-test.h" + +#define TEXT_SIZE 12 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + /* This is just the inverse of select-font-face.c */ + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 1, 1, 1); + + cairo_set_font_size (cr, TEXT_SIZE); + cairo_move_to (cr, 0, TEXT_SIZE); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Serif", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_show_text (cr, "i-am-serif"); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_show_text (cr, " i-am-sans"); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans Mono", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_show_text (cr, " i-am-mono"); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (inverse_text, + "Tests rendering of inverse text (white-on-black)", + "font, text", /* keywords */ + NULL, /* requirements */ + 192, TEXT_SIZE + 4, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/inverted-clip.c b/local/recipes/libs/cairo/source/test/inverted-clip.c new file mode 100644 index 0000000000..b05dd6b6b5 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/inverted-clip.c @@ -0,0 +1,56 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +/* An assertion failure found by Rico Tzschichholz */ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + cairo_set_source_rgb (cr, 0, 1, 0); + + cairo_arc (cr, 50, 50, 40, 0, 2 * M_PI); + cairo_clip_preserve (cr); + + cairo_paint (cr); + + cairo_rectangle (cr, 0, 0, 100, 100); + cairo_reset_clip (cr); + cairo_clip (cr); + + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (inverted_clip, + "Clip + InvertedClip should be opaque", + "clip, paint", /* keywords */ + "target=raster", /* requirements */ + 100, 100, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/joins-loop.c b/local/recipes/libs/cairo/source/test/joins-loop.c new file mode 100644 index 0000000000..f0b7bc11d3 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/joins-loop.c @@ -0,0 +1,100 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +#define LINE_WIDTH 10. +#define SIZE (8 * LINE_WIDTH) +#define PAD (1 * LINE_WIDTH) + + +static void +make_path (cairo_t *cr) +{ + cairo_move_to (cr, 0, 0); + cairo_rel_curve_to (cr, + SIZE, 0, + 0, SIZE, + SIZE, SIZE); + cairo_rel_line_to (cr, -SIZE, 0); + cairo_rel_curve_to (cr, + SIZE, 0, + 0, -SIZE, + SIZE, -SIZE); + cairo_close_path (cr); +} + +static void +draw_joins (cairo_t *cr) +{ + cairo_save (cr); + cairo_translate (cr, PAD, PAD); + + make_path (cr); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_BEVEL); + cairo_stroke (cr); + cairo_translate (cr, SIZE + PAD, 0.); + + make_path (cr); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); + cairo_stroke (cr); + cairo_translate (cr, SIZE + PAD, 0.); + + make_path (cr); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER); + cairo_stroke (cr); + cairo_translate (cr, SIZE + PAD, 0.); + + cairo_restore (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_set_line_width (cr, LINE_WIDTH); + + draw_joins (cr); + + /* and reflect to generate the opposite vertex ordering */ + cairo_translate (cr, 0, height); + cairo_scale (cr, 1, -1); + + draw_joins (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (joins_loop, + "A loopy concave shape", + "stroke", /* keywords */ + NULL, /* requirements */ + 3*(SIZE+PAD)+PAD, 2*(SIZE+PAD)+2*PAD, + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/joins-retrace.c b/local/recipes/libs/cairo/source/test/joins-retrace.c new file mode 100644 index 0000000000..9a2cf708b3 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/joins-retrace.c @@ -0,0 +1,109 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +#define LINE_WIDTH 10. +#define SIZE (8 * LINE_WIDTH) +#define PAD (1 * LINE_WIDTH) + + +static void +make_path (cairo_t *cr) +{ + cairo_move_to (cr, 0, SIZE/2 + LINE_WIDTH); + cairo_rel_line_to (cr, SIZE, 0); + cairo_rel_line_to (cr, -SIZE, 0); + cairo_close_path (cr); + + cairo_move_to (cr, 3*SIZE/4, 0); + cairo_rel_line_to (cr, -SIZE/2, SIZE); + cairo_rel_line_to (cr, SIZE/2, -SIZE); + cairo_close_path (cr); + + cairo_move_to (cr, 0, SIZE/2-LINE_WIDTH); + cairo_rel_curve_to (cr, + SIZE/2, -2*LINE_WIDTH, + SIZE/2, 2*LINE_WIDTH, + SIZE, 0); + cairo_rel_curve_to (cr, + -SIZE/2, 2*LINE_WIDTH, + -SIZE/2, -2*LINE_WIDTH, + -SIZE, 0); + cairo_close_path (cr); +} + +static void +draw_joins (cairo_t *cr) +{ + cairo_save (cr); + cairo_translate (cr, PAD, PAD); + + make_path (cr); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_BEVEL); + cairo_stroke (cr); + cairo_translate (cr, SIZE + PAD, 0.); + + make_path (cr); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); + cairo_stroke (cr); + cairo_translate (cr, SIZE + PAD, 0.); + + make_path (cr); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER); + cairo_stroke (cr); + cairo_translate (cr, SIZE + PAD, 0.); + + cairo_restore (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_set_line_width (cr, LINE_WIDTH); + + draw_joins (cr); + + /* and reflect to generate the opposite vertex ordering */ + cairo_translate (cr, 0, height); + cairo_scale (cr, 1, -1); + + draw_joins (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (joins_retrace, + "A shape that repeats upon itself", + "stroke", /* keywords */ + NULL, /* requirements */ + 3*(SIZE+PAD)+PAD, 2*(SIZE+PAD)+2*PAD, + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/joins-star.c b/local/recipes/libs/cairo/source/test/joins-star.c new file mode 100644 index 0000000000..17c1b4e668 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/joins-star.c @@ -0,0 +1,99 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +#define LINE_WIDTH 10. +#define SIZE (8 * LINE_WIDTH) +#define PAD (1 * LINE_WIDTH) + + +static void +make_path (cairo_t *cr) +{ +#define PROTRUSION 20 + cairo_move_to (cr, SIZE/2-PROTRUSION, LINE_WIDTH); + cairo_line_to (cr, SIZE-LINE_WIDTH, SIZE/2+PROTRUSION); + cairo_line_to (cr, SIZE-LINE_WIDTH, SIZE/2-PROTRUSION); + cairo_line_to (cr, SIZE/2-PROTRUSION, SIZE-LINE_WIDTH); + cairo_line_to (cr, SIZE/2+PROTRUSION, SIZE-LINE_WIDTH); + cairo_line_to (cr, LINE_WIDTH, SIZE/2-PROTRUSION); + cairo_line_to (cr, LINE_WIDTH, SIZE/2+PROTRUSION); + cairo_line_to (cr, SIZE/2+PROTRUSION, LINE_WIDTH); + cairo_close_path (cr); +} + +static void +draw_joins (cairo_t *cr) +{ + cairo_save (cr); + cairo_translate (cr, PAD, PAD); + + make_path (cr); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_BEVEL); + cairo_stroke (cr); + cairo_translate (cr, SIZE + PAD, 0.); + + make_path (cr); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); + cairo_stroke (cr); + cairo_translate (cr, SIZE + PAD, 0.); + + make_path (cr); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER); + cairo_stroke (cr); + cairo_translate (cr, SIZE + PAD, 0.); + + cairo_restore (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_set_line_width (cr, LINE_WIDTH); + + draw_joins (cr); + + /* and reflect to generate the opposite vertex ordering */ + cairo_translate (cr, 0, height); + cairo_scale (cr, 1, -1); + + draw_joins (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (joins_star, + "A nice and simple concave shape", + "stroke", /* keywords */ + NULL, /* requirements */ + 3*(SIZE+PAD)+PAD, 2*(SIZE+PAD)+PAD, + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/joins.c b/local/recipes/libs/cairo/source/test/joins.c new file mode 100644 index 0000000000..40ef72e21d --- /dev/null +++ b/local/recipes/libs/cairo/source/test/joins.c @@ -0,0 +1,109 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +#define LINE_WIDTH 12. +#define SIZE (5 * LINE_WIDTH) +#define PAD (2 * LINE_WIDTH) + +static void +make_path (cairo_t *cr) +{ + const struct { + double x, y; + } scales[] = { + { 1, 1 }, + { -1, 1 }, + { 1, -1 }, + { -1, -1 }, + }; + unsigned int i, j; + + for (j = 0; j < ARRAY_LENGTH (scales); j++) { + cairo_save (cr); + /* include reflections to flip the orientation of the join */ + cairo_scale (cr, scales[j].x, scales[j].y); + for (i = 0; i < 3; i++) { + cairo_new_sub_path (cr); + cairo_move_to (cr, 0, -9*LINE_WIDTH/4 - 2); + cairo_line_to (cr, 0, -2*LINE_WIDTH - 2); + cairo_line_to (cr, LINE_WIDTH/4, -2*LINE_WIDTH - 2); + cairo_rotate (cr, M_PI / 4.); + } + cairo_restore (cr); + } +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_line_join_t join; + + cairo_save (cr); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_restore (cr); + + cairo_set_line_width (cr, LINE_WIDTH); + cairo_translate (cr, PAD + SIZE / 2., PAD + SIZE / 2.); + + for (join = CAIRO_LINE_JOIN_MITER; join <= CAIRO_LINE_JOIN_BEVEL; join++) { + cairo_save (cr); + + cairo_set_line_join (cr, join); + + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + make_path (cr); + cairo_stroke (cr); + + cairo_translate (cr, 0, SIZE + PAD); + + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + make_path (cr); + cairo_stroke (cr); + + cairo_translate (cr, 0, SIZE + PAD); + + cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); + make_path (cr); + cairo_stroke (cr); + + cairo_restore (cr); + + cairo_translate (cr, SIZE + PAD, 0); + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (joins, + "Test joins", + "stroke, joins", /* keywords */ + NULL, /* requirements */ + 3 * (PAD + SIZE) + PAD, + 3 * (PAD + SIZE) + PAD, + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/jp2.jp2 b/local/recipes/libs/cairo/source/test/jp2.jp2 new file mode 100644 index 0000000000..fe8dd6e54a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/jp2.jp2 differ diff --git a/local/recipes/libs/cairo/source/test/jpeg.jpg b/local/recipes/libs/cairo/source/test/jpeg.jpg new file mode 100644 index 0000000000..a1bac1c812 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/jpeg.jpg differ diff --git a/local/recipes/libs/cairo/source/test/large-clip.c b/local/recipes/libs/cairo/source/test/large-clip.c new file mode 100644 index 0000000000..d2380def5a --- /dev/null +++ b/local/recipes/libs/cairo/source/test/large-clip.c @@ -0,0 +1,50 @@ +/* + * Copyright © 2008 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Soren Sandmann + */ + +#include "cairo-test.h" + +#define SIZE 100 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_paint (cr); + + cairo_rectangle (cr, 0, 0, 65536 + 25, 65536 + 25); + cairo_clip (cr); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (large_clip, + "Incorrect clipping when the clip rectangle doesn't fit in 16 bits signed", + "clip, stress", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/large-font.c b/local/recipes/libs/cairo/source/test/large-font.c new file mode 100644 index 0000000000..0a139441c4 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/large-font.c @@ -0,0 +1,73 @@ +/* + * Copyright © 2008 Red Hat, Inc. + * + * 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: Carl D. Worth + */ + +/* Bug history: + * + * 2008-05-23: Caolan McNamara noticed a bug in OpenOffice.org where, + * when using a very large font, space would be left for a + * glyph but it would actually be rendered in the wrong + * place. He wrote a minimal test case and posted the bug + * here: + * + * corrupt glyph positions with large font + * https://bugzilla.redhat.com/show_bug.cgi?id=448104 + * + * 2008-05-23: Carl Worth wrote this test for the cairo test suite to + * exercise the bug. + */ + +#include "cairo-test.h" + +#define WIDTH 800 +#define HEIGHT 800 +#define TEXT_SIZE 10000 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + /* paint white so we don't need separate ref images for + * RGB24 and ARGB32 */ + cairo_set_source_rgb (cr, 1., 1., 1.); + cairo_paint (cr); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (cr, TEXT_SIZE); + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_move_to (cr, -TEXT_SIZE / 2, TEXT_SIZE / 2); + cairo_show_text (cr, "xW"); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (large_font, + "Draws a very large font to exercise a glyph-positioning bug", + "stress, font", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/large-source-roi.c b/local/recipes/libs/cairo/source/test/large-source-roi.c new file mode 100644 index 0000000000..dfd3554d7f --- /dev/null +++ b/local/recipes/libs/cairo/source/test/large-source-roi.c @@ -0,0 +1,78 @@ +/* + * Copyright © 2009 Joonas Pihlaja + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "cairo-test.h" + +/* This test attempts to trigger failures in those clone_similar + * backend methods that have size restrictions. */ + +static cairo_surface_t * +create_large_source (int width, int height) +{ + cairo_surface_t *surface; + cairo_t *cr; + + surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height); + cr = cairo_create (surface); + cairo_surface_destroy (surface); + + cairo_set_source_rgb (cr, 1,0,0); /* red */ + cairo_paint (cr); + surface = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + + return surface; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *source; + /* Since 1cc750ed92a936d84b47cac696aaffd226e1c02e pixman will not + * paint on the source surface if source_width > 30582. */ + double source_width = 30000.0; + + cairo_set_source_rgb (cr, 1,1,1); + cairo_paint (cr); + + /* Create an excessively wide source image, all red. */ + source = create_large_source (source_width, height); + + /* Set a transform so that the source is scaled down to fit in the + * destination horizontally and then paint the entire source to + * the context. */ + cairo_scale (cr, width/source_width, 1.0); + cairo_set_source_surface (cr, source, 0, 0); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_paint (cr); + + cairo_surface_destroy (source); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (large_source_roi, + "Uses a all of a large source image.", + "stress, source", /* keywords */ + NULL, /* requirements */ + 7, 7, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/large-source.c b/local/recipes/libs/cairo/source/test/large-source.c new file mode 100644 index 0000000000..2b6b84fb48 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/large-source.c @@ -0,0 +1,100 @@ +/* + * Copyright © Chris Wilson, 2008 + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Chris Wilson + */ + +#include "cairo-test.h" + +/* This is a test case for the following bug: + * + * crafted gif file will crash firefox + * [XError: 'BadAlloc (insufficient resources for operation)'] + * https://bugzilla.mozilla.org/show_bug.cgi?id=424333 + */ + +#ifdef WORDS_BIGENDIAN +#define RED_MASK 0xA0 +#define GREEN_MASK 0xA +#else +#define RED_MASK 0x5 +#define GREEN_MASK 0x50 +#endif + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface; + unsigned char *data; + + cairo_set_source_rgb (cr, 0, 0, 1); /* blue */ + cairo_paint (cr); + + surface = cairo_image_surface_create (CAIRO_FORMAT_A1, 32000, 20); + data = cairo_image_surface_get_data (surface); + if (data != NULL) { + int stride = cairo_image_surface_get_stride (surface); + int width = cairo_image_surface_get_width (surface); + int height = cairo_image_surface_get_height (surface); + int x, y; + + for (y = 0; y < height; y++) { + for (x = 0; x < (width + 7) / 8; x++) + data[x] = RED_MASK; + data += stride; + } + cairo_surface_mark_dirty (surface); + } + + cairo_set_source_rgb (cr, 1, 0, 0); /* red */ + cairo_mask_surface (cr, surface, 0, 0); + cairo_surface_destroy (surface); + + surface = cairo_image_surface_create (CAIRO_FORMAT_A1, 20, 32000); + data = cairo_image_surface_get_data (surface); + if (data != NULL) { + int stride = cairo_image_surface_get_stride (surface); + int width = cairo_image_surface_get_width (surface); + int height = cairo_image_surface_get_height (surface); + int x, y; + + for (y = 0; y < height; y++) { + for (x = 0; x < (width + 7) / 8; x++) + data[x] = GREEN_MASK; + data += stride; + } + cairo_surface_mark_dirty (surface); + } + + cairo_set_source_rgb (cr, 0, 1, 0); /* green */ + cairo_mask_surface (cr, surface, 0, 0); + cairo_surface_destroy (surface); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (large_source, + "Exercises mozilla bug 424333 - handling of massive images", + "stress, source", /* keywords */ + NULL, /* requirements */ + 20, 20, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/large-twin-antialias-mixed.c b/local/recipes/libs/cairo/source/test/large-twin-antialias-mixed.c new file mode 100644 index 0000000000..9626a9dd2e --- /dev/null +++ b/local/recipes/libs/cairo/source/test/large-twin-antialias-mixed.c @@ -0,0 +1,97 @@ +/* + * Copyright 2009 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_scaled_font_t * +create_twin (cairo_t *cr, cairo_antialias_t antialias) +{ + cairo_font_options_t *options; + + cairo_select_font_face (cr, + "@cairo:", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + + options = cairo_font_options_create (); + cairo_font_options_set_antialias (options, antialias); + cairo_set_font_options (cr, options); + cairo_font_options_destroy (options); + + return cairo_scaled_font_reference (cairo_get_scaled_font (cr)); +} + + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_scaled_font_t *subpixel, *gray, *none; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + + cairo_set_font_size (cr, 64); + subpixel = create_twin (cr, CAIRO_ANTIALIAS_SUBPIXEL); + gray = create_twin (cr, CAIRO_ANTIALIAS_GRAY); + none = create_twin (cr, CAIRO_ANTIALIAS_NONE); + + cairo_move_to (cr, 4, 64); + cairo_set_scaled_font (cr, subpixel); + cairo_show_text (cr, "Is cairo's"); + cairo_set_scaled_font (cr, gray); + cairo_show_text (cr, " twin"); + cairo_set_scaled_font (cr, none); + cairo_show_text (cr, " giza?"); + + cairo_move_to (cr, 4, 128+16); + cairo_set_scaled_font (cr, gray); + cairo_show_text (cr, "Is cairo's"); + cairo_set_scaled_font (cr, none); + cairo_show_text (cr, " twin"); + cairo_set_scaled_font (cr, subpixel); + cairo_show_text (cr, " giza?"); + + cairo_move_to (cr, 4, 192+32); + cairo_set_scaled_font (cr, none); + cairo_show_text (cr, "Is cairo's"); + cairo_set_scaled_font (cr, gray); + cairo_show_text (cr, " twin"); + cairo_set_scaled_font (cr, subpixel); + cairo_show_text (cr, " giza?"); + + cairo_scaled_font_destroy (none); + cairo_scaled_font_destroy (gray); + cairo_scaled_font_destroy (subpixel); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (large_twin_antialias_mixed, + "Tests the internal font (with intermixed antialiasing)", + "twin, font", /* keywords */ + "target=raster", /* requirements */ + 524, 240, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/leaks.c b/local/recipes/libs/cairo/source/test/leaks.c new file mode 100644 index 0000000000..ad7c85817e --- /dev/null +++ b/local/recipes/libs/cairo/source/test/leaks.c @@ -0,0 +1,62 @@ +/* + * Copyright © 2023 Uli Schlachter + * + * 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: Uli Schlachter + */ + +#include "cairo-test.h" + + +// Once upon a time, _cairo_gstate_fini(), _cairo_scaled_font_fini_internal(), +// and _cairo_ft_scaled_font_fini() leaked font options. +static cairo_test_status_t +leaks_set_scaled_font (cairo_t *cr, int width, int height) +{ + cairo_font_options_t *opt; + cairo_matrix_t matrix; + cairo_scaled_font_t *font; + + cairo_matrix_init_identity (&matrix); + + opt = cairo_font_options_create (); + cairo_font_options_set_custom_palette_color (opt, 0, 1, 1, 1, 1); + + font = cairo_scaled_font_create (cairo_get_font_face (cr), &matrix, &matrix, opt); + + cairo_set_scaled_font (cr, font); + + cairo_font_options_destroy (opt); + cairo_scaled_font_destroy (font); + + // Fill the output so that the same ref image works for everying + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (leaks_set_scaled_font, + "Regression test for font options memory leak in cairo_set_scaled_font", + "leak", /* keywords */ + NULL, /* requirements */ + 1, 1, + NULL, leaks_set_scaled_font) diff --git a/local/recipes/libs/cairo/source/test/leaky-dash.c b/local/recipes/libs/cairo/source/test/leaky-dash.c new file mode 100644 index 0000000000..12e91ac1db --- /dev/null +++ b/local/recipes/libs/cairo/source/test/leaky-dash.c @@ -0,0 +1,64 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +/* Test case for bug #4863: + * + * stroking problems with wide dashed lines + * https://bugs.freedesktop.org/show_bug.cgi?id=4863 + */ + +#include "cairo-test.h" + +#define WIDTH 71 +#define HEIGHT 28 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + double dash[2]; + + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */ + + cairo_set_line_width (cr, 2); + dash[0] = 8.0; + dash[1] = 2.0; + + cairo_rectangle (cr, 2.0, 2.0, 67.0, 24.0); + + cairo_set_dash (cr, dash, 2, 9.0); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (leaky_dash, + "Exercises bug #4863 in which a dashed stroke leaks into half the rectangle being filled" + "\nknown bug (#4863) which has existed since the 1.0 release", + "dash, stroke", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/leaky-dashed-rectangle.c b/local/recipes/libs/cairo/source/test/leaky-dashed-rectangle.c new file mode 100644 index 0000000000..fad859a9f9 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/leaky-dashed-rectangle.c @@ -0,0 +1,86 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + * Franz Schmid + */ + +/* Test case for bug reported by Franz Schmid + * https://lists.cairographics.org/archives/cairo/2008-April/013912.html + * + * See also: https://bugs.freedesktop.org/show_bug.cgi?id=17177 + */ + +#include "cairo-test.h" + +#define WIDTH 60 +#define HEIGHT 60 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const double dash[2] = {4, 2}; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0., 0., 0); + + cairo_translate (cr, 0.5, .5); + cairo_set_line_width (cr, 1); /* This is vital to reproduce the bug. */ + + /* First check simple rectangles */ + cairo_set_source_rgb (cr, 0., 0., 0); + cairo_rectangle (cr, -WIDTH/4, -HEIGHT/4, WIDTH, HEIGHT); + cairo_stroke (cr); + cairo_rectangle (cr, WIDTH+WIDTH/4, -HEIGHT/4, -WIDTH, HEIGHT); + cairo_stroke (cr); + cairo_rectangle (cr, -WIDTH/4, HEIGHT+HEIGHT/4, WIDTH, -HEIGHT); + cairo_stroke (cr); + cairo_rectangle (cr, WIDTH+WIDTH/4, HEIGHT+HEIGHT/4, -WIDTH, -HEIGHT); + cairo_stroke (cr); + + cairo_set_dash (cr, dash, 2, 0); + + /* And now dashed. */ + cairo_set_source_rgb (cr, 1., 0., 0); + cairo_rectangle (cr, -WIDTH/4, -HEIGHT/4, WIDTH, HEIGHT); + cairo_stroke (cr); + cairo_set_source_rgb (cr, 0., 1., 0); + cairo_rectangle (cr, WIDTH+WIDTH/4, -HEIGHT/4, -WIDTH, HEIGHT); + cairo_stroke (cr); + cairo_set_source_rgb (cr, 0., 0., 1); + cairo_rectangle (cr, -WIDTH/4, HEIGHT+HEIGHT/4, WIDTH, -HEIGHT); + cairo_stroke (cr); + cairo_set_source_rgb (cr, 1., 1., 0); + cairo_rectangle (cr, WIDTH+WIDTH/4, HEIGHT+HEIGHT/4, -WIDTH, -HEIGHT); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (leaky_dashed_rectangle, + "Exercises bug in which a dashed stroke leaks in from outside the surface", + "dash, stroke", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/leaky-dashed-stroke.c b/local/recipes/libs/cairo/source/test/leaky-dashed-stroke.c new file mode 100644 index 0000000000..457d7ce705 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/leaky-dashed-stroke.c @@ -0,0 +1,166 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +/* Extracted from a test case reported by Jeff Muizelaar found whilst running + * firefox http://people.mozilla.com/~jmuizelaar/BerlinDistricts-check.svg + */ + +#include "cairo-test.h" + +#define WIDTH 205 +#define HEIGHT 260 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const double dash[2] = {.5, .5}; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 1., 0., 0); + + /* By adjusting the miter limit, we can see variations on the artifact. + * cairo_set_miter_limit (cr, 4.); + */ + + cairo_translate (cr, -720, -484); + cairo_scale (cr, 2.5, 2.5); + + cairo_set_dash (cr, dash, 2, 0); + + cairo_move_to (cr, 293.622, 330); + cairo_line_to (cr, 293.703, 337.028); + cairo_line_to (cr, 297.45, 336.851); + cairo_line_to (cr, 308.88, 342.609); + cairo_line_to (cr, 309.736, 346.107); + cairo_line_to (cr, 312.972, 348.128); + cairo_line_to (cr, 312.977, 353.478); + cairo_line_to (cr, 322.486, 359.355); + cairo_line_to (cr, 320.831, 363.642); + cairo_line_to (cr, 315.175, 367.171); + cairo_line_to (cr, 308.987, 365.715); + cairo_line_to (cr, 301.3, 365.964); + cairo_line_to (cr, 304.712, 368.852); + cairo_line_to (cr, 305.349, 373.022); + cairo_line_to (cr, 303.211, 376.551); + cairo_line_to (cr, 304.915, 382.855); + cairo_line_to (cr, 323.715, 400.475); + cairo_line_to (cr, 355.323, 424.072); + cairo_line_to (cr, 443.078, 426.534); + cairo_line_to (cr, 455.26, 400.603); + cairo_line_to (cr, 471.924, 392.604); + cairo_line_to (cr, 478.556, 390.797); + cairo_line_to (cr, 477.715, 386); + cairo_line_to (cr, 456.807, 376.507); + cairo_line_to (cr, 449.134, 368.722); + cairo_line_to (cr, 449.147, 365.847); + cairo_line_to (cr, 439.981, 361.692); + cairo_line_to (cr, 439.994, 358.603); + cairo_line_to (cr, 454.645, 336.128); + cairo_line_to (cr, 434.995, 324.005); + cairo_line_to (cr, 423.884, 319.354); + cairo_line_to (cr, 421.098, 312.569); + cairo_line_to (cr, 424.291, 305.997); + cairo_line_to (cr, 431.308, 305.069); + cairo_line_to (cr, 437.257, 296.882); + cairo_line_to (cr, 448.544, 296.808); + cairo_line_to (cr, 452.113, 290.651); + cairo_line_to (cr, 448.469, 285.483); + cairo_line_to (cr, 442.903, 282.877); + cairo_line_to (cr, 447.798, 281.124); + cairo_line_to (cr, 454.622, 274.911); + cairo_line_to (cr, 449.491, 269.978); + cairo_line_to (cr, 443.666, 253.148); + cairo_line_to (cr, 445.741, 250.834); + cairo_line_to (cr, 441.87, 247.131); + cairo_line_to (cr, 436.932, 246.203); + cairo_line_to (cr, 430.5, 251.252); + cairo_line_to (cr, 427.483, 250.751); + cairo_line_to (cr, 427.26, 253.572); + cairo_line_to (cr, 423.621, 255.539); + cairo_line_to (cr, 423.824, 257.933); + cairo_line_to (cr, 425.239, 259.582); + cairo_line_to (cr, 422.385, 261.443); + cairo_line_to (cr, 421.665, 260.53); + cairo_line_to (cr, 419.238, 262.819); + cairo_line_to (cr, 418.731, 257.849); + cairo_line_to (cr, 419.72, 255.227); + cairo_line_to (cr, 418.786, 250.258); + cairo_line_to (cr, 405.685, 235.254); + cairo_line_to (cr, 427.167, 215.127); + cairo_line_to (cr, 413.852, 196.281); + cairo_line_to (cr, 420.177, 192.379); + cairo_line_to (cr, 419.885, 185.701); + cairo_line_to (cr, 413.401, 185.428); + cairo_line_to (cr, 407.985, 186.863); + cairo_line_to (cr, 397.11, 189.112); + cairo_line_to (cr, 390.505, 186.664); + cairo_line_to (cr, 388.527, 183.694); + cairo_line_to (cr, 336.503, 221.048); + cairo_line_to (cr, 367.028, 241.656); + cairo_line_to (cr, 365.103, 244.117); + cairo_line_to (cr, 364.886, 246.792); + cairo_line_to (cr, 361.467, 247.119); + cairo_line_to (cr, 360.396, 245.525); + cairo_line_to (cr, 356.336, 245.638); + cairo_line_to (cr, 353.344, 242.122); + cairo_line_to (cr, 347.149, 242.876); + cairo_line_to (cr, 341.809, 256.652); + cairo_line_to (cr, 342.232, 268.72); + cairo_line_to (cr, 329.579, 269.095); + cairo_line_to (cr, 327.001, 271.009); + cairo_line_to (cr, 325.579, 275.598); + cairo_line_to (cr, 318.941, 277.313); + cairo_line_to (cr, 306.048, 277.231); + cairo_line_to (cr, 304.071, 276.27); + cairo_line_to (cr, 301.153, 277.175); + cairo_line_to (cr, 293.52, 277.529); + cairo_line_to (cr, 290.682, 281.947); + cairo_line_to (cr, 293.911, 286.63); + cairo_line_to (cr, 302.417, 290.547); + cairo_line_to (cr, 303.521, 294.73); + cairo_line_to (cr, 307.787, 298.088); + cairo_line_to (cr, 311.718, 299.126); + cairo_line_to (cr, 313.255, 302.146); + cairo_line_to (cr, 314.6, 306.206); + cairo_line_to (cr, 322.603, 308.96); + cairo_line_to (cr, 321.718, 314.477); + cairo_line_to (cr, 319.596, 320.341); + cairo_line_to (cr, 300.689, 323.69); + cairo_line_to (cr, 301.232, 326.789); + cairo_line_to (cr, 293.622, 330); + cairo_close_path (cr); + + cairo_stroke (cr); + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (leaky_dashed_stroke, + "Exercises bug in which a dashed stroke leaks in from outside the surface", + "dash, stroke", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/leaky-polygon.c b/local/recipes/libs/cairo/source/test/leaky-polygon.c new file mode 100644 index 0000000000..0ea7094c95 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/leaky-polygon.c @@ -0,0 +1,85 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +/* Bug history + * + * 2005-01-07 Carl Worth + * + * Bug reported: + * + * From: Chris + * Subject: [cairo] Render to image buffer artifacts + * To: cairo@cairographics.org + * Date: Fri, 07 Jan 2005 02:22:28 -0500 + * + * I've attached the code and image that shows this off. Scaling at + * different levels seems to change the corruption. + * + * For some reason there are artifacts in the alpha channel. I don't know + * if that's the only place, but the alpha channel looks bad. + * + * If you run the code and parse the attached image, directing stdout to a + * file, you can see in the lower left corner there are alpha values where + * it should be transparent. + * [...] + * + * 2005-01-11 Carl Worth + * + * I trimmed the original test case down to the code that appears here. + * + */ + +#include "cairo-test.h" + +#define WIDTH 21 +#define HEIGHT 21 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + /* We draw in the default black, so paint white first. */ + cairo_save (cr); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_restore (cr); + + cairo_scale (cr, 1.0/(1<<16), 1.0/(1<<16)); + + cairo_move_to (cr, 131072,39321); + cairo_line_to (cr, 1103072,1288088); + cairo_line_to (cr, 1179648,1294990); + cairo_close_path (cr); + + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (leaky_polygon, + "Exercises a corner case in the trapezoid rasterization in which pixels outside the trapezoids received a non-zero alpha", + "fill, trap", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/line-width-large-overlap.c b/local/recipes/libs/cairo/source/test/line-width-large-overlap.c new file mode 100644 index 0000000000..767734f6bf --- /dev/null +++ b/local/recipes/libs/cairo/source/test/line-width-large-overlap.c @@ -0,0 +1,149 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright 2011 Red Hat Inc. + * + * 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: Benjamin Otte + */ + +/* + * Test case taken from the WebKit test suite, failure originally reported + * by Zan Dobersek . WebKit test is + * LayoutTests/canvas/philip/tests/2d.path.rect.selfintersect.html + */ + +#include "cairo-test.h" + +#include + +#define LINE_WIDTH 120 +#define SIZE 100 +#define RECT_SIZE 10 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + /* fill with green so RGB and RGBA tests can share the ref image */ + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_paint (cr); + + /* red to see eventual bugs immediately */ + cairo_set_source_rgb (cr, 1, 0, 0); + + /* big line width */ + cairo_set_line_width (cr, LINE_WIDTH); + + /* rectangle that is smaller than the line width in center of image */ + cairo_rectangle (cr, + (SIZE - RECT_SIZE) / 2, + (SIZE - RECT_SIZE) / 2, + RECT_SIZE, + RECT_SIZE); + + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +/* and again slightly offset to trigger another path */ +static cairo_test_status_t +draw_offset (cairo_t *cr, int width, int height) +{ + cairo_translate (cr, .5, .5); + return draw (cr, width, height); +} + +static cairo_test_status_t +draw_rotated (cairo_t *cr, int width, int height) +{ + cairo_translate (cr, SIZE/2, SIZE/2); + cairo_rotate (cr, M_PI/4); + cairo_translate (cr, -SIZE/2, -SIZE/2); + + return draw (cr, width, height); +} + +static cairo_test_status_t +draw_flipped (cairo_t *cr, int width, int height) +{ + cairo_translate (cr, SIZE/2, SIZE/2); + cairo_scale (cr, -1, 1); + cairo_translate (cr, -SIZE/2, -SIZE/2); + + return draw (cr, width, height); +} + +static cairo_test_status_t +draw_flopped (cairo_t *cr, int width, int height) +{ + cairo_translate (cr, SIZE/2, SIZE/2); + cairo_scale (cr, 1, -1); + cairo_translate (cr, -SIZE/2, -SIZE/2); + + return draw (cr, width, height); +} + +static cairo_test_status_t +draw_dashed (cairo_t *cr, int width, int height) +{ + const double dashes[] = { 4 }; + cairo_set_dash (cr, dashes, 1, 0); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + return draw (cr, width, height); +} + +CAIRO_TEST (line_width_large_overlap, + "Test overlapping lines due to large line width", + "stroke", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) +CAIRO_TEST (line_width_large_overlap_offset, + "Test overlapping lines due to large line width", + "stroke", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw_offset) +CAIRO_TEST (line_width_large_overlap_rotated, + "Test overlapping lines due to large line width", + "stroke", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw_rotated) +CAIRO_TEST (line_width_large_overlap_flipped, + "Test overlapping lines due to large line width", + "stroke", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw_flipped) +CAIRO_TEST (line_width_large_overlap_flopped, + "Test overlapping lines due to large line width", + "stroke", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw_flopped) +CAIRO_TEST (line_width_large_overlap_dashed, + "Test overlapping lines due to large line width", + "stroke", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw_dashed) diff --git a/local/recipes/libs/cairo/source/test/line-width-overlap.c b/local/recipes/libs/cairo/source/test/line-width-overlap.c new file mode 100644 index 0000000000..ac8c234796 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/line-width-overlap.c @@ -0,0 +1,149 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright 2011 Red Hat Inc. + * + * 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: Benjamin Otte + */ + +/* + * Test case taken from the WebKit test suite, failure originally reported + * by Zan Dobersek . WebKit test is + * LayoutTests/canvas/philip/tests/2d.path.rect.selfintersect.html + */ + +#include "cairo-test.h" + +#include + +#define LINE_WIDTH 60 +#define SIZE 100 +#define RECT_SIZE 10 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + /* fill with green so RGB and RGBA tests can share the ref image */ + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_paint (cr); + + /* red to see eventual bugs immediately */ + cairo_set_source_rgb (cr, 1, 0, 0); + + /* big line width */ + cairo_set_line_width (cr, LINE_WIDTH); + + /* rectangle that is smaller than the line width in center of image */ + cairo_rectangle (cr, + (SIZE - RECT_SIZE) / 2, + (SIZE - RECT_SIZE) / 2, + RECT_SIZE, + RECT_SIZE); + + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +/* and again slightly offset to trigger another path */ +static cairo_test_status_t +draw_offset (cairo_t *cr, int width, int height) +{ + cairo_translate (cr, .5, .5); + return draw (cr, width, height); +} + +static cairo_test_status_t +draw_rotated (cairo_t *cr, int width, int height) +{ + cairo_translate (cr, SIZE/2, SIZE/2); + cairo_rotate (cr, M_PI/4); + cairo_translate (cr, -SIZE/2, -SIZE/2); + + return draw (cr, width, height); +} + +static cairo_test_status_t +draw_flipped (cairo_t *cr, int width, int height) +{ + cairo_translate (cr, SIZE/2, SIZE/2); + cairo_scale (cr, -1, 1); + cairo_translate (cr, -SIZE/2, -SIZE/2); + + return draw (cr, width, height); +} + +static cairo_test_status_t +draw_flopped (cairo_t *cr, int width, int height) +{ + cairo_translate (cr, SIZE/2, SIZE/2); + cairo_scale (cr, 1, -1); + cairo_translate (cr, -SIZE/2, -SIZE/2); + + return draw (cr, width, height); +} + +static cairo_test_status_t +draw_dashed (cairo_t *cr, int width, int height) +{ + const double dashes[] = { 4 }; + cairo_set_dash (cr, dashes, 1, 0); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + return draw (cr, width, height); +} + +CAIRO_TEST (line_width_overlap, + "Test overlapping lines due to large line width", + "stroke", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) +CAIRO_TEST (line_width_overlap_offset, + "Test overlapping lines due to large line width", + "stroke", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw_offset) +CAIRO_TEST (line_width_overlap_rotated, + "Test overlapping lines due to large line width", + "stroke", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw_rotated) +CAIRO_TEST (line_width_overlap_flipped, + "Test overlapping lines due to large line width", + "stroke", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw_flipped) +CAIRO_TEST (line_width_overlap_flopped, + "Test overlapping lines due to large line width", + "stroke", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw_flopped) +CAIRO_TEST (line_width_overlap_dashed, + "Test overlapping lines due to large line width", + "stroke", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw_dashed) diff --git a/local/recipes/libs/cairo/source/test/line-width-scale.c b/local/recipes/libs/cairo/source/test/line-width-scale.c new file mode 100644 index 0000000000..037b887fdd --- /dev/null +++ b/local/recipes/libs/cairo/source/test/line-width-scale.c @@ -0,0 +1,178 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +/* This test exercises the various interactions between + * cairo_set_line_width and cairo_scale. Specifically it shows how + * separate transformations can affect the pen for stroking compared + * to the path itself. + * + * This was inspired by an image by Maxim Shemanarev demonstrating the + * flexible-pipeline nature of his Antigrain Geometry project: + * + * http://antigrain.com/tips/line_alignment/conv_order.gif + * + * It also uncovered some behavior in cairo that I found surprising. + * Namely, cairo_set_line_width was not transforming the width + * according the the current CTM, but instead delaying that + * transformation until the time of cairo_stroke. + * + * This delayed behavior was released in cairo 1.0 so we're going to + * document this as the way cairo_set_line_width works rather than + * considering this a bug. + */ + +#define LINE_WIDTH 13 +#define SPLINE 50.0 +#define XSCALE 0.5 +#define YSCALE 2.0 +#define WIDTH (XSCALE * SPLINE * 6.0) +#define HEIGHT (YSCALE * SPLINE * 2.0) + +static void +spline_path (cairo_t *cr) +{ + cairo_save (cr); + { + cairo_move_to (cr, + - SPLINE, 0); + cairo_curve_to (cr, + - SPLINE / 4, - SPLINE, + SPLINE / 4, SPLINE, + SPLINE, 0); + } + cairo_restore (cr); +} + +/* If we scale before setting the line width or creating the path, + * then obviously both will be scaled. */ +static void +scale_then_set_line_width_and_stroke (cairo_t *cr) +{ + cairo_scale (cr, XSCALE, YSCALE); + cairo_set_line_width (cr, LINE_WIDTH); + spline_path (cr); + cairo_stroke (cr); +} + +/* This is used to verify the results of + * scale_then_set_line_width_and_stroke. + * + * It uses save/restore pairs to isolate the scaling of the path and + * line_width and ensures that both are scaled. + */ +static void +scale_path_and_line_width (cairo_t *cr) +{ + cairo_save (cr); + { + cairo_scale (cr, XSCALE, YSCALE); + spline_path (cr); + } + cairo_restore (cr); + + cairo_save (cr); + { + cairo_scale (cr, XSCALE, YSCALE); + cairo_set_line_width (cr, LINE_WIDTH); + cairo_stroke (cr); + } + cairo_restore (cr); +} + +/* This is the case that was surprising. + * + * Setting the line width before scaling doesn't change anything. The + * line width will be interpreted under the CTM in effect at the time + * of cairo_stroke, so the line width will be scaled as well as the + * path here. + */ +static void +set_line_width_then_scale_and_stroke (cairo_t *cr) +{ + cairo_set_line_width (cr, LINE_WIDTH); + cairo_scale (cr, XSCALE, YSCALE); + spline_path (cr); + cairo_stroke (cr); +} + +/* Here then is the way to achieve the alternate result. + * + * This uses save/restore pairs to isolate the scaling of the path and + * line_width and ensures that the path is scaled while the line width + * is not. + */ +static void +scale_path_not_line_width (cairo_t *cr) +{ + cairo_save (cr); + { + cairo_scale (cr, XSCALE, YSCALE); + spline_path (cr); + } + cairo_restore (cr); + + cairo_save (cr); + { + cairo_set_line_width (cr, LINE_WIDTH); + cairo_stroke (cr); + } + cairo_restore (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + int i; + void (* const figures[4]) (cairo_t *cr) = { + scale_then_set_line_width_and_stroke, + scale_path_and_line_width, + set_line_width_then_scale_and_stroke, + scale_path_not_line_width + }; + + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */ + + for (i = 0; i < 4; i++) { + cairo_save (cr); + cairo_translate (cr, + WIDTH/4 + (i % 2) * WIDTH/2, + HEIGHT/4 + (i / 2) * HEIGHT/2); + (figures[i]) (cr); + cairo_restore (cr); + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (line_width_scale, + "Tests interaction of cairo_set_line_width with cairo_scale", + "stroke", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/line-width-tolerance.c b/local/recipes/libs/cairo/source/test/line-width-tolerance.c new file mode 100644 index 0000000000..5a581ca113 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/line-width-tolerance.c @@ -0,0 +1,66 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright 2011 Red Hat Inc. + * + * 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: Benjamin Otte + */ + +/* + * Test case taken from the WebKit test suite, failure originally reported + * by Zan Dobersek at + * https://bugs.webkit.org/show_bug.cgi?id=54471 + */ + +#include "cairo-test.h" + +#include + +#define RADIUS 50 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + /* fill with green so RGB and RGBA tests can share the ref image */ + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_paint (cr); + + /* red to see eventual bugs immediately */ + cairo_set_source_rgb (cr, 1, 0, 0); + + /* stroke 3/4 of a circle where the last quarter would be this + * reference image. Keep just a 1 pixel border. Use a huge line + * width (twice the circle's radius to get it filled completely). + */ + cairo_set_line_width (cr, 2 * RADIUS); + cairo_arc (cr, 1, RADIUS - 1, RADIUS, 0, - M_PI / 2.0); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (line_width_tolerance, + "Test interaction of line width and tolerance when stroking arcs", + "stroke", /* keywords */ + NULL, /* requirements */ + RADIUS, RADIUS, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/line-width-zero.c b/local/recipes/libs/cairo/source/test/line-width-zero.c new file mode 100644 index 0000000000..421b9d2c56 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/line-width-zero.c @@ -0,0 +1,71 @@ +/* + * Copyright © 2007 Red Hat, Inc. + * + * 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: Carl Worth + */ + +#include "cairo-test.h" + +/* This is a test case for the following bug: + * + * Crash in cairo_stroke_extents when line width is 0 and line cap is ROUND + * (_cairo_pen_find_active_cw_vertex_index) + * https://bugs.freedesktop.org/show_bug.cgi?id=10231 + */ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + double x1, y1, x2, y2; + + cairo_move_to (cr, 0.0, 0.0); + cairo_line_to (cr, 100.0, 100.0); + cairo_set_line_width (cr, 0.0); + + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER); + cairo_stroke_extents (cr, &x1, &y1, &x2, &y2); + cairo_in_stroke (cr, 50, 50); + cairo_stroke_preserve (cr); + + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); + cairo_stroke_extents (cr, &x1, &y1, &x2, &y2); + cairo_in_stroke (cr, 50, 50); + cairo_stroke_preserve (cr); + + cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_BEVEL); + cairo_stroke_extents (cr, &x1, &y1, &x2, &y2); + cairo_in_stroke (cr, 50, 50); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (line_width_zero, + "Test all stroke operations and all cap,join styles with line width of zero", + "stroke", /* keywords */ + NULL, /* requirements */ + 0, 0, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/line-width.c b/local/recipes/libs/cairo/source/test/line-width.c new file mode 100644 index 0000000000..315ebc393e --- /dev/null +++ b/local/recipes/libs/cairo/source/test/line-width.c @@ -0,0 +1,77 @@ +/* + * Copyright © 2004 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +#define LINES 5 +#define LINE_LENGTH 10 +#define IMAGE_WIDTH 2 * LINE_LENGTH + 6 +#define IMAGE_HEIGHT ((LINES+4)*LINES)/2 + 2 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + int i; + + /* We draw in black, so paint white first. */ + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_translate (cr, 2, 2); + + for (i=0; i < LINES; i++) { + cairo_set_line_width (cr, i+1); + cairo_move_to (cr, 0, 0); + cairo_rel_line_to (cr, LINE_LENGTH, 0); + cairo_stroke (cr); + cairo_move_to (cr, LINE_LENGTH + 2, 0.5); + cairo_rel_line_to (cr, LINE_LENGTH, 0); + cairo_stroke (cr); + cairo_translate (cr, 0, i+3); + } + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +draw_a1 (cairo_t *cr, int width, int height) +{ + cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); + return draw (cr, width, height); +} + +CAIRO_TEST (line_width, + "Tests cairo_set_line_width", + "stroke", /* keywords */ + NULL, /* requirements */ + IMAGE_WIDTH, IMAGE_HEIGHT, + NULL, draw) +CAIRO_TEST (a1_line_width, + "Tests cairo_set_line_width", + "stroke", /* keywords */ + "target=raster", /* requirements */ + IMAGE_WIDTH, IMAGE_HEIGHT, + NULL, draw_a1) diff --git a/local/recipes/libs/cairo/source/test/linear-gradient-extend.c b/local/recipes/libs/cairo/source/test/linear-gradient-extend.c new file mode 100644 index 0000000000..b1328b4256 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/linear-gradient-extend.c @@ -0,0 +1,92 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright 2010 Andrea Canciani + * + * 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: Andrea Canciani + */ + +#include "cairo-test.h" + +#define NUM_EXTEND 4 +#define HEIGHT 16 +#define WIDTH 16 +#define PAD 3 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *pattern; + unsigned int i, j; + + cairo_extend_t extend[NUM_EXTEND] = { + CAIRO_EXTEND_NONE, + CAIRO_EXTEND_REPEAT, + CAIRO_EXTEND_REFLECT, + CAIRO_EXTEND_PAD + }; + + cairo_test_paint_checkered (cr); + + pattern = cairo_pattern_create_linear (0, 2*PAD, 0, HEIGHT - 2*PAD); + + cairo_pattern_add_color_stop_rgb (pattern, 0, 0, 0, 1); + cairo_pattern_add_color_stop_rgb (pattern, 1, 0, 0, 1); + + cairo_translate (cr, PAD, PAD); + + for (i = 0; i < 2; i++) { + cairo_save (cr); + + for (j = 0; j < NUM_EXTEND; j++) { + cairo_pattern_set_extend (pattern, extend[j]); + + cairo_reset_clip (cr); + cairo_rectangle (cr, 0, 0, WIDTH, HEIGHT); + cairo_clip (cr); + + if (i & 1) { + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_mask (cr, pattern); + } else { + cairo_set_source (cr, pattern); + cairo_paint (cr); + } + + cairo_translate (cr, WIDTH+PAD, 0); + } + + cairo_restore (cr); + cairo_translate (cr, 0, HEIGHT+PAD); + } + + cairo_pattern_destroy (pattern); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (linear_gradient_extend, + "Tests gradient to solid reduction of linear gradients", + "linear, pattern, extend", /* keywords */ + NULL, /* requirements */ + (WIDTH+PAD) * NUM_EXTEND + PAD, 2*(HEIGHT + PAD) + PAD, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/linear-gradient-large.c b/local/recipes/libs/cairo/source/test/linear-gradient-large.c new file mode 100644 index 0000000000..5646aa4851 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/linear-gradient-large.c @@ -0,0 +1,68 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright 2010 Krzysztof Kosiński + * + * 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: Krzysztof Kosiński + */ + +#include "cairo-test.h" + +/* originally reported in https://bugs.freedesktop.org/show_bug.cgi?id=29470 */ + +#define OFFSET 50 +#define SIZE 1000 + +static void mark_point(cairo_t *ct, double x, double y) +{ + cairo_rectangle(ct, x-2, y-2, 4, 4); + cairo_set_source_rgb(ct, 1,0,0); + cairo_fill(ct); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *gr = cairo_pattern_create_linear (SIZE - OFFSET, OFFSET, + OFFSET, SIZE - OFFSET); + + cairo_pattern_add_color_stop_rgb (gr, 0.0, 1, 1, 1); + cairo_pattern_add_color_stop_rgb (gr, 0.0, 0, 0, 0); + cairo_pattern_add_color_stop_rgb (gr, 1.0, 0, 0, 0); + cairo_pattern_add_color_stop_rgb (gr, 1.0, 1, 1, 1); + + cairo_set_source (cr, gr); + cairo_pattern_destroy (gr); + cairo_paint (cr); + + mark_point(cr, SIZE - OFFSET, OFFSET); + mark_point(cr, OFFSET, SIZE - OFFSET); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (linear_gradient_large, + "Tests that large linear gradients get rendered at the correct place", + "linear, pattern", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/linear-gradient-one-stop.c b/local/recipes/libs/cairo/source/test/linear-gradient-one-stop.c new file mode 100644 index 0000000000..09c4b9d237 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/linear-gradient-one-stop.c @@ -0,0 +1,90 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright 2010 Andrea Canciani + * + * 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: Andrea Canciani + */ + +#include "cairo-test.h" + +#define NUM_EXTEND 4 +#define HEIGHT 16 +#define WIDTH 16 +#define PAD 3 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *pattern; + unsigned int i, j; + + cairo_extend_t extend[NUM_EXTEND] = { + CAIRO_EXTEND_NONE, + CAIRO_EXTEND_REPEAT, + CAIRO_EXTEND_REFLECT, + CAIRO_EXTEND_PAD + }; + + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + + cairo_translate (cr, PAD, PAD); + + for (i = 0; i < 3; i++) { + cairo_save (cr); + + for (j = 0; j < NUM_EXTEND; j++) { + cairo_reset_clip (cr); + cairo_rectangle (cr, 0, 0, WIDTH, HEIGHT); + cairo_clip (cr); + + if (i == 0) + pattern = cairo_pattern_create_linear (0, 2*PAD, 0, HEIGHT - 2*PAD); + else if (i == 1) + pattern = cairo_pattern_create_linear (2*PAD, 2*PAD, HEIGHT - 2*PAD, HEIGHT - 2*PAD); + else if (i == 2) + pattern = cairo_pattern_create_linear (2*PAD, 0, HEIGHT - 2*PAD, 0); + + cairo_pattern_add_color_stop_rgb (pattern, 0.25, 0, 0, 1); + cairo_pattern_set_extend (pattern, extend[j]); + + cairo_set_source (cr, pattern); + cairo_paint (cr); + + cairo_pattern_destroy (pattern); + + cairo_translate (cr, WIDTH+PAD, 0); + } + + cairo_restore (cr); + cairo_translate (cr, 0, HEIGHT+PAD); + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (linear_gradient_one_stop, + "Tests linear gradients with a single stop", + "gradient,linear,", /* keywords */ + NULL, /* requirements */ + (WIDTH+PAD) * NUM_EXTEND + PAD, 3*(HEIGHT + PAD) + PAD, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/linear-gradient-reflect.c b/local/recipes/libs/cairo/source/test/linear-gradient-reflect.c new file mode 100644 index 0000000000..8adb587846 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/linear-gradient-reflect.c @@ -0,0 +1,67 @@ +/* + * Copyright © 2007 Tim Rowley + * + * 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: Tim Rowley + */ + +#include "cairo-test.h" +#include "stdio.h" + +#define WIDTH 50 +#define HEIGHT 50 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *pattern; + + cairo_set_source_rgb (cr, 0.5, 0.5, 0.5); + cairo_paint (cr); + + cairo_save (cr); + + pattern = cairo_pattern_create_linear (0, 0, 10.0, 0); + + cairo_pattern_add_color_stop_rgb (pattern, 0.0, + 0.0, 0.0, 1.0); + cairo_pattern_add_color_stop_rgb (pattern, 1.0, + 1.0, 0.0, 0.0); + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REFLECT); + + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + cairo_rectangle (cr, 0.0, 0.0, WIDTH, HEIGHT); + cairo_fill (cr); + + cairo_restore (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (linear_gradient_reflect, + "Tests the drawing of linear gradient with reflect", + "gradient", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/linear-gradient-subset.c b/local/recipes/libs/cairo/source/test/linear-gradient-subset.c new file mode 100644 index 0000000000..ce05e6ec1a --- /dev/null +++ b/local/recipes/libs/cairo/source/test/linear-gradient-subset.c @@ -0,0 +1,127 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Owen Taylor + */ + +#include "cairo-test.h" +#include "stdio.h" + +/* The test matrix is + * + * A) Horizontal B) 5° C) 45° D) Vertical + * 1) Rotated 0° 2) Rotated 45° C) Rotated 90° + * a) 2 stop b) 3 stop + * + * A1a B1a C1a D1a + * A2a B2a C2a D2a + * A3a B3a C3a D3a + * A1b B1b C1b D1b + * A2b B2b C2b D2b + * A3b B3b C3b D3b + */ + +static const double gradient_angles[] = { 0, 45, 90 }; +#define N_GRADIENT_ANGLES 3 +static const double rotate_angles[] = { 0, 45, 90 }; +#define N_ROTATE_ANGLES 3 +static const int n_stops[] = { 2, 3 }; +#define N_N_STOPS 2 + +#define UNIT_SIZE 6 +#define UNIT_SIZE 6 +#define PAD 1 + +#define WIDTH N_GRADIENT_ANGLES * UNIT_SIZE + (N_GRADIENT_ANGLES + 1) * PAD +#define HEIGHT N_N_STOPS * N_ROTATE_ANGLES * UNIT_SIZE + (N_N_STOPS * N_ROTATE_ANGLES + 1) * PAD + +static void +draw_unit (cairo_t *cr, + double gradient_angle, + double rotate_angle, + int n_stops) +{ + cairo_pattern_t *pattern; + + cairo_rectangle (cr, 0, 0, 1, 1); + cairo_clip (cr); + cairo_new_path(cr); + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_rectangle (cr, 0, 0, 1, 1); + cairo_fill (cr); + + cairo_translate (cr, 0.5, 0.5); + cairo_scale (cr, 1 / 1.5, 1 / 1.5); + cairo_rotate (cr, rotate_angle); + + pattern = cairo_pattern_create_linear (-0.5 * cos (gradient_angle), -0.5 * sin (gradient_angle), + 0.5 * cos (gradient_angle), 0.5 * sin (gradient_angle)); + + if (n_stops == 2) { + cairo_pattern_add_color_stop_rgb (pattern, 0.2, 0.3, 0.3, 0.3); + cairo_pattern_add_color_stop_rgb (pattern, 0.8, 1.0, 1.0, 1.0); + } else { + cairo_pattern_add_color_stop_rgb (pattern, 0.2, 1.0, 0.0, 0.0); + cairo_pattern_add_color_stop_rgb (pattern, 0.5, 1.0, 1.0, 1.0); + cairo_pattern_add_color_stop_rgb (pattern, 0.8, 0.0, 0.0, 1.0); + } + + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + cairo_rectangle (cr, -0.5, -0.5, 1, 1); + cairo_fill (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + int i, j, k; + + cairo_set_source_rgb (cr, 0.5, 0.5, 0.5); + cairo_paint (cr); + + for (i = 0; i < N_GRADIENT_ANGLES; i++) + for (j = 0; j < N_ROTATE_ANGLES; j++) + for (k = 0; k < N_N_STOPS; k++) { + cairo_save (cr); + cairo_translate (cr, + PAD + (PAD + UNIT_SIZE) * i, + PAD + (PAD + UNIT_SIZE) * (N_ROTATE_ANGLES * k + j)); + cairo_scale (cr, UNIT_SIZE, UNIT_SIZE); + + draw_unit (cr, + gradient_angles[i] * M_PI / 180., + rotate_angles[j] * M_PI / 180., + n_stops[k]); + cairo_restore (cr); + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (linear_gradient_subset, + "Tests the drawing of linear gradients", + "gradient", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/linear-gradient.c b/local/recipes/libs/cairo/source/test/linear-gradient.c new file mode 100644 index 0000000000..054d6abbc4 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/linear-gradient.c @@ -0,0 +1,132 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Owen Taylor + */ + +#include "cairo-test.h" +#include "stdio.h" + +/* The test matrix is + * + * A) Horizontal B) 5° C) 45° D) Vertical + * 1) Rotated 0° 2) Rotated 45° C) Rotated 90° + * a) 2 stop b) 3 stop + * + * A1a B1a C1a D1a + * A2a B2a C2a D2a + * A3a B3a C3a D3a + * A1b B1b C1b D1b + * A2b B2b C2b D2b + * A3b B3b C3b D3b + */ + +static const double gradient_angles[] = { 0, 45, 90 }; +#define N_GRADIENT_ANGLES 3 +static const double rotate_angles[] = { 0, 45, 90 }; +#define N_ROTATE_ANGLES 3 +static const int n_stops[] = { 2, 3 }; +#define N_N_STOPS 2 + +#define UNIT_SIZE 6 +#define UNIT_SIZE 6 +#define PAD 1 + +#define WIDTH N_GRADIENT_ANGLES * UNIT_SIZE + (N_GRADIENT_ANGLES + 1) * PAD +#define HEIGHT N_N_STOPS * N_ROTATE_ANGLES * UNIT_SIZE + (N_N_STOPS * N_ROTATE_ANGLES + 1) * PAD + +static void +draw_unit (cairo_t *cr, + double gradient_angle, + double rotate_angle, + int n_stops) +{ + cairo_pattern_t *pattern; + + cairo_rectangle (cr, 0, 0, 1, 1); + cairo_clip (cr); + cairo_new_path(cr); + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_rectangle (cr, 0, 0, 1, 1); + cairo_fill (cr); + + cairo_translate (cr, 0.5, 0.5); + cairo_scale (cr, 1 / 1.5, 1 / 1.5); + cairo_rotate (cr, rotate_angle); + + pattern = cairo_pattern_create_linear (-0.5 * cos (gradient_angle), -0.5 * sin (gradient_angle), + 0.5 * cos (gradient_angle), 0.5 * sin (gradient_angle)); + + if (n_stops == 2) { + cairo_pattern_add_color_stop_rgb (pattern, 0., + 0.3, 0.3, 0.3); + cairo_pattern_add_color_stop_rgb (pattern, 1., + 1.0, 1.0, 1.0); + } else { + cairo_pattern_add_color_stop_rgb (pattern, 0., + 1.0, 0.0, 0.0); + cairo_pattern_add_color_stop_rgb (pattern, 0.5, + 1.0, 1.0, 1.0); + cairo_pattern_add_color_stop_rgb (pattern, 1., + 0.0, 0.0, 1.0); + } + + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + cairo_rectangle (cr, -0.5, -0.5, 1, 1); + cairo_fill (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + int i, j, k; + + cairo_set_source_rgb (cr, 0.5, 0.5, 0.5); + cairo_paint (cr); + + for (i = 0; i < N_GRADIENT_ANGLES; i++) + for (j = 0; j < N_ROTATE_ANGLES; j++) + for (k = 0; k < N_N_STOPS; k++) { + cairo_save (cr); + cairo_translate (cr, + PAD + (PAD + UNIT_SIZE) * i, + PAD + (PAD + UNIT_SIZE) * (N_ROTATE_ANGLES * k + j)); + cairo_scale (cr, UNIT_SIZE, UNIT_SIZE); + + draw_unit (cr, + gradient_angles[i] * M_PI / 180., + rotate_angles[j] * M_PI / 180., + n_stops[k]); + cairo_restore (cr); + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (linear_gradient, + "Tests the drawing of linear gradients", + "gradient", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/linear-step-function.c b/local/recipes/libs/cairo/source/test/linear-step-function.c new file mode 100644 index 0000000000..da7e8ca19d --- /dev/null +++ b/local/recipes/libs/cairo/source/test/linear-step-function.c @@ -0,0 +1,60 @@ +/* + * Copyright © 2010 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *pattern; + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + pattern = cairo_pattern_create_linear (width/2, 0, width/2, 0); + cairo_pattern_add_color_stop_rgb (pattern, 0, 1, 0, 0); + cairo_pattern_add_color_stop_rgb (pattern, 1, 0, 0, 1); + cairo_set_source (cr, pattern); + + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_NONE); /* nothing */ + cairo_rectangle (cr, 0, 0, width, height/2); + cairo_fill (cr); + + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD); /* step */ + cairo_rectangle (cr, 0, height/2, width, height/2); + cairo_fill (cr); + + cairo_pattern_destroy (pattern); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (linear_step_function, + "Tests creating a step function using a linear gradient", + "gradient, linear", /* keywords */ + NULL, /* requirements */ + 40, 40, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/linear-uniform.c b/local/recipes/libs/cairo/source/test/linear-uniform.c new file mode 100644 index 0000000000..2f65535027 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/linear-uniform.c @@ -0,0 +1,63 @@ +/* + * Copyright © 2010 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *pattern; + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + /* with alpha */ + pattern = cairo_pattern_create_linear (0, 0, 0, height); + cairo_pattern_add_color_stop_rgba (pattern, 0, 1, 1, 1, .5); + cairo_pattern_add_color_stop_rgba (pattern, 1, 1, 1, 1, .5); + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + cairo_rectangle (cr, 0, 0, width/2, height); + cairo_fill (cr); + + /* without alpha */ + pattern = cairo_pattern_create_linear (0, 0, 0, height); + cairo_pattern_add_color_stop_rgb (pattern, 0, 1, 1, 1); + cairo_pattern_add_color_stop_rgb (pattern, 1, 1, 1, 1); + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + cairo_rectangle (cr, width/2, 0, width/2, height); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (linear_uniform, + "Tests handling of \"solid\" linear gradients", + "gradient, linear", /* keywords */ + NULL, /* requirements */ + 40, 40, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/long-dashed-lines.c b/local/recipes/libs/cairo/source/test/long-dashed-lines.c new file mode 100644 index 0000000000..4d6ded9a55 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/long-dashed-lines.c @@ -0,0 +1,66 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * the author not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. The author makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE AUTHOR. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + int i; + double dashes[] = {6, 3}; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + /* partially visible rectangle... */ + cairo_rectangle (cr, -0.5, -0.5, 61, 61); + + /* rectangles with intersecting segments... */ + cairo_save (cr); + cairo_translate (cr, 30, 30); + for (i = 0; i < 4; i++) { + cairo_rotate (cr, M_PI / 4); + cairo_rectangle (cr, -37, -15, 74, 30); + } + cairo_restore (cr); + + /* completely invisible rectangle */ + cairo_rectangle (cr, -5, -5, 70, 70); + + cairo_set_dash (cr, dashes, ARRAY_LENGTH (dashes), 0.); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_BEVEL); + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (long_dashed_lines, + "Exercises _cairo_box_intersects_line_segment()", + "dash, stroke, stress", /* keywords */ + NULL, /* requirements */ + 60, 60, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/long-lines.c b/local/recipes/libs/cairo/source/test/long-lines.c new file mode 100644 index 0000000000..ff28edbd81 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/long-lines.c @@ -0,0 +1,88 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Carl D. Worth + * Emmanuel Pacaud + */ + +#include "cairo-test.h" + +#define LINE_WIDTH 1. +#define SIZE 10 +#define LINE_NBR 6 +#define WIDTH (SIZE * (LINE_NBR + 1)) +#define HEIGHT (SIZE * (LINE_NBR + 1)) + + +struct { + double length; + double red, green, blue; +} lines[LINE_NBR] = { + { 100.0, 1.0, 0.0, 0.0 }, + { 10000.0, 0.0, 1.0, 0.0 }, + { 100000.0, 0.0, 0.0, 1.0 }, + { 1000000.0, 1.0, 1.0, 0.0 }, + { 10000000.0, 0.0, 1.0, 1.0 }, + { 100000000.0, 1.0, 0.0, 1.0 } +}; + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + double pos; + int i; + + /* We draw in the default black, so paint white first. */ + cairo_save (cr); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_restore (cr); + + cairo_set_line_width (cr, LINE_WIDTH); + + pos = SIZE + .5; + for (i = 0; i < LINE_NBR; i++) { + cairo_move_to (cr, pos, -lines[i].length); + cairo_line_to (cr, pos, +lines[i].length); + cairo_set_source_rgb (cr, lines[i].red, lines[i].green, lines[i].blue); + cairo_stroke (cr); + pos += SIZE; + } + + /* This should display a perfect vertically centered black line */ + cairo_move_to (cr, -1e100, HEIGHT/2); + cairo_line_to (cr, 1e100, HEIGHT/2); + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +/* XFAIL: range overflow of fixed-point */ +CAIRO_TEST (long_lines, + "Test long lines" + "\nLong lines are not drawn due to the limitations of the internal 16.16 fixed-point coordinates", + "stroke, stress", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/make-cairo-test-constructors.py b/local/recipes/libs/cairo/source/test/make-cairo-test-constructors.py new file mode 100644 index 0000000000..0e7d867bbc --- /dev/null +++ b/local/recipes/libs/cairo/source/test/make-cairo-test-constructors.py @@ -0,0 +1,37 @@ +# IMPORTANT: Keep in sync with boilerplate/make-cairo-boilerplate-constructors.py! +import argparse +import sys +import re + +if __name__=='__main__': + parser = argparse.ArgumentParser() + parser.add_argument('output') + parser.add_argument('input', nargs='+') + args = parser.parse_args() + + test_names = [] + + match_test_line = re.compile(r'^CAIRO_TEST.*') + match_test_name = re.compile(r'^CAIRO_TEST.*\((.*),.*') + + for fname in args.input: + with open(fname, 'r', encoding='utf-8') as f: + for l in f.readlines(): + if match_test_line.match(l): + test_names.append(match_test_name.match(l).group(1)) + + with open(args.output, 'w', encoding='utf-8') as f: + f.write('/* WARNING: Autogenerated file - see %s! */\n\n' % sys.argv[0]) + f.write('#include "cairo-test-private.h"\n\n') + f.write('void _cairo_test_runner_register_tests (void);\n\n') + + for test_name in test_names: + f.write('extern void _register_%s (void);\n' % test_name) + + f.write('void\n') + f.write('_cairo_test_runner_register_tests (void)\n') + f.write('{\n') + + for test_name in test_names: + f.write(' _register_%s ();\n' % test_name) + f.write('}\n') diff --git a/local/recipes/libs/cairo/source/test/make-cairo-test-constructors.sh b/local/recipes/libs/cairo/source/test/make-cairo-test-constructors.sh new file mode 100644 index 0000000000..a03d61c19a --- /dev/null +++ b/local/recipes/libs/cairo/source/test/make-cairo-test-constructors.sh @@ -0,0 +1,31 @@ +#! /bin/sh + +set -e + +if test $# -eq 0; then + echo "$0: no input files." >&2 + exit 1 +fi + +cat < + */ + +#include "cairo-test.h" + +#define WIDTH 3 +#define HEIGHT 3 + +/* A single, black pixel */ +static const uint32_t black_pixel_argb = 0xff000000; +static const uint32_t black_pixel = 0x00000000; + +static cairo_bool_t +set_pixel_black(uint8_t *data, int stride, + cairo_format_t format, int x, int y) +{ + switch (format) { + case CAIRO_FORMAT_ARGB32: + case CAIRO_FORMAT_RGB24: + *(uint32_t *)(data + y * stride + 4*x) = black_pixel_argb; + break; + case CAIRO_FORMAT_RGB16_565: + *(uint16_t *)(data + y * stride + 2*x) = black_pixel; + break; + case CAIRO_FORMAT_RGBA128F: + case CAIRO_FORMAT_RGB96F: + case CAIRO_FORMAT_RGB30: + case CAIRO_FORMAT_A8: + case CAIRO_FORMAT_A1: + case CAIRO_FORMAT_INVALID: + default: + return FALSE; + } + return TRUE; +} + +static cairo_test_status_t +all (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface; + uint8_t *data; + int stride; + cairo_format_t format; + int i, j; + + /* Fill background white */ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + surface = cairo_surface_map_to_image (cairo_get_target (cr), NULL); + cairo_surface_flush (surface); + format = cairo_image_surface_get_format (surface); + stride = cairo_image_surface_get_stride (surface); + data = cairo_image_surface_get_data (surface); + if (data) { + for (j = 0; j < HEIGHT; j++) + for (i = 0; i < WIDTH; i++) + if (! set_pixel_black (data, stride, format, i, j)) + return CAIRO_TEST_FAILURE; + } + cairo_surface_mark_dirty (surface); + cairo_surface_unmap_image (cairo_get_target (cr), surface); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +bit (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface; + cairo_rectangle_int_t extents; + cairo_format_t format; + uint8_t *data; + + extents.x = extents.y = extents.width = extents.height = 1; + + /* Fill background white */ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + surface = cairo_surface_map_to_image (cairo_get_target (cr), &extents); + cairo_surface_flush (surface); + data = cairo_image_surface_get_data (surface); + format = cairo_image_surface_get_format (surface); + if (data) { + if (! set_pixel_black (data, 0, format, 0, 0)) + return CAIRO_TEST_FAILURE; + } + cairo_surface_mark_dirty (surface); + cairo_surface_unmap_image (cairo_get_target (cr), surface); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +fill (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface; + cairo_rectangle_int_t extents; + cairo_t *cr2; + + extents.x = extents.y = extents.width = extents.height = 1; + + /* Fill background white */ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + surface = cairo_surface_map_to_image (cairo_get_target (cr), &extents); + cr2 = cairo_create (surface); + cairo_set_source_rgb (cr2, 1, 0, 0); + cairo_paint (cr2); + cairo_destroy (cr2); + cairo_surface_unmap_image (cairo_get_target (cr), surface); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (map_all_to_image, + "Test mapping a surface to an image and modifying it externally", + "image", /* keywords */ + "target=raster", /* requirements */ + WIDTH, HEIGHT, + NULL, all) +CAIRO_TEST (map_bit_to_image, + "Test mapping a surface to an image and modifying it externally", + "image", /* keywords */ + "target=raster", /* requirements */ + WIDTH, HEIGHT, + NULL, bit) +CAIRO_TEST (map_to_image_fill, + "Test mapping a surface to an image and modifying it externally", + "image", /* keywords */ + "target=raster", /* requirements */ + WIDTH, HEIGHT, + NULL, fill) diff --git a/local/recipes/libs/cairo/source/test/mask-alpha.c b/local/recipes/libs/cairo/source/test/mask-alpha.c new file mode 100644 index 0000000000..d66e0ac13f --- /dev/null +++ b/local/recipes/libs/cairo/source/test/mask-alpha.c @@ -0,0 +1,82 @@ +/* + * Copyright © 2007 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" + +#define SIZE 40 +#define PAD 2 +#define WIDTH (PAD + SIZE + PAD) +#define HEIGHT WIDTH + +/* This test is designed to test that PDF viewers use the correct + * alpha values in an Alpha SMasks. Some viewers use the color values + * instead of the alpha. The test draws a triangle and rectangle in a + * group then draws the group using cairo_mask(). The mask consists of + * a circle with the rgba (0.4, 0.4, 0.4, 0.8) and the background rgba + * (0.8, 0.8, 0.8, 0.4). + */ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *pattern; + + cairo_translate (cr, PAD, PAD); + + /* mask */ + cairo_push_group (cr); + cairo_set_source_rgba (cr, 0.8, 0.8, 0.8, 0.4); + cairo_paint (cr); + cairo_arc (cr, SIZE / 2, SIZE / 2, SIZE / 6, 0., 2. * M_PI); + cairo_set_source_rgba (cr, 0.4, 0.4, 0.4, 0.8); + cairo_fill (cr); + pattern = cairo_pop_group (cr); + + /* source */ + cairo_push_group (cr); + cairo_rectangle (cr, 0.3 * SIZE, 0.2 * SIZE, 0.5 * SIZE, 0.5 * SIZE); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_fill (cr); + cairo_move_to (cr, 0.0, 0.8 * SIZE); + cairo_rel_line_to (cr, 0.7 * SIZE, 0.0); + cairo_rel_line_to (cr, -0.375 * SIZE, -0.6 * SIZE); + cairo_close_path (cr); + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_fill (cr); + cairo_pop_group_to_source (cr); + + cairo_mask (cr, pattern); + cairo_pattern_destroy (pattern); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (mask_alpha, + "A simple test painting a group through a circle mask", + "mask, alpha", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/mask-ctm.c b/local/recipes/libs/cairo/source/test/mask-ctm.c new file mode 100644 index 0000000000..205ab06916 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/mask-ctm.c @@ -0,0 +1,80 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *mask_surface; + cairo_pattern_t *mask; + uint32_t data[] = { + 0x80000000, 0x80000000, + 0x80000000, 0x80000000, + }; + cairo_matrix_t matrix; + + mask_surface = cairo_image_surface_create_for_data ((unsigned char *) data, + CAIRO_FORMAT_ARGB32, 2, 2, 8); + mask = cairo_pattern_create_for_surface (mask_surface); + + cairo_set_source_rgb (cr, 1.0, 0, 0); + + /* We can translate with the CTM, with the pattern matrix, or with + * both. */ + + /* 1. CTM alone. */ + cairo_save (cr); + { + cairo_translate (cr, 2, 2); + cairo_mask (cr, mask); + } + cairo_restore (cr); + + /* 2. Pattern matrix alone. */ + cairo_matrix_init_translate (&matrix, -4, -4); + cairo_pattern_set_matrix (mask, &matrix); + + cairo_mask (cr, mask); + + /* 3. CTM + pattern matrix */ + cairo_translate (cr, 2, 2); + cairo_mask (cr, mask); + + cairo_pattern_destroy (mask); + + cairo_surface_finish (mask_surface); /* data goes out of scope */ + cairo_surface_destroy (mask_surface); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (mask_ctm, + "Test that cairo_mask is affected properly by the CTM", + "mask", /* keywords */ + NULL, /* requirements */ + 10, 10, + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/mask-glyphs.c b/local/recipes/libs/cairo/source/test/mask-glyphs.c new file mode 100644 index 0000000000..2e7b703011 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/mask-glyphs.c @@ -0,0 +1,187 @@ +/* + * Copyright 2009 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +#include + +static const char *png_filename = "romedalen.png"; + +#define WIDTH 800 +#define HEIGHT 600 + +static cairo_status_t +_image_to_glyphs (cairo_surface_t *image, + int channel, + int level, + cairo_scaled_font_t *scaled_font, + double tx, double ty, + cairo_glyph_t *glyphs, + int *num_glyphs) +{ + int width, height, stride; + const unsigned char *data; + int x, y, z, n; + + width = cairo_image_surface_get_width (image); + height = cairo_image_surface_get_height (image); + stride = cairo_image_surface_get_stride (image); + data = cairo_image_surface_get_data (image); + + n = 0; + for (y = 0; y < height; y++) { + const uint32_t *row = (uint32_t *) (data + y * stride); + + for (x = 0; x < width; x++) { + z = (row[x] >> channel) & 0xff; + if (z == level) { + double xx, yy, zz; + char c = n % 26 + 'a'; + int count = 1; + cairo_glyph_t *glyphs_p = &glyphs[n]; + cairo_status_t status; + + xx = 4 * (x - width/2.) + width/2.; + yy = 4 * (y - height/2.) + height/2.; + + zz = z / 1000.; + xx = xx + zz*(width/2. - xx); + yy = yy + zz*(height/2. - yy); + + cairo_scaled_font_text_to_glyphs (scaled_font, + tx + xx, ty + yy, + &c, 1, + &glyphs_p, &count, + NULL, NULL, + NULL); + status = cairo_scaled_font_status (scaled_font); + if (status) + return status; + + assert (glyphs_p == &glyphs[n]); + assert (count == 1); + n++; + } + } + } + + *num_glyphs = n; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_render_image (cairo_t *cr, + int width, int height, + cairo_surface_t *image) +{ + int ww, hh; + cairo_glyph_t *glyphs; + cairo_pattern_t *mask; + cairo_scaled_font_t *scaled_font; + double tx, ty; + const struct { + int shift; + double red; + double green; + double blue; + } channel[3] = { + { 0, 0.9, 0.3, 0.4 }, + { 8, 0.4, 0.9, 0.3 }, + { 16, 0.3, 0.4, 0.9 }, + }; + unsigned int n, i; + + ww = cairo_image_surface_get_width (image); + hh = cairo_image_surface_get_height (image); + + glyphs = cairo_glyph_allocate (ww * hh); + if (glyphs == NULL) + return CAIRO_STATUS_NO_MEMORY; + + tx = (width - ww) / 2.; + ty = (height - hh) / 2.; + + cairo_set_font_size (cr, 5); + scaled_font = cairo_get_scaled_font (cr); + + for (i = 0; i < ARRAY_LENGTH (channel); i++) { + cairo_push_group_with_content (cr, CAIRO_CONTENT_ALPHA); + for (n = 0; n < 256; n++) { + cairo_status_t status; + int num_glyphs; + + status = _image_to_glyphs (image, channel[i].shift, n, + scaled_font, + tx, ty, glyphs, &num_glyphs); + if (status) { + cairo_glyph_free (glyphs); + return status; + } + + cairo_set_source_rgba (cr, + 0, 0, 0, + .15 + .85 * n / 255.); + cairo_show_glyphs (cr, glyphs, num_glyphs); + } + mask = cairo_pop_group (cr); + cairo_set_source_rgb (cr, + channel[i].red, + channel[i].green, + channel[i].blue); + cairo_mask (cr, mask); + cairo_pattern_destroy (mask); + } + + cairo_glyph_free (glyphs); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_surface_t *image; + cairo_status_t status; + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + image = cairo_test_create_surface_from_png (ctx, png_filename); + status = cairo_surface_status (image); + if (status) + return cairo_test_status_from_status (ctx, status); + + status = _render_image (cr, width, height, image); + cairo_surface_destroy (image); + + return cairo_test_status_from_status (ctx, status); +} + +CAIRO_TEST (mask_glyphs, + "Creates a mask using a distorted array of overlapping glyphs", + "mask, glyphs", /* keywords */ + "slow", /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/mask-surface-ctm.c b/local/recipes/libs/cairo/source/test/mask-surface-ctm.c new file mode 100644 index 0000000000..064de3c54e --- /dev/null +++ b/local/recipes/libs/cairo/source/test/mask-surface-ctm.c @@ -0,0 +1,71 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *mask; + uint32_t data[] = { + 0x80000000, 0x80000000, + 0x80000000, 0x80000000, + }; + + mask = cairo_image_surface_create_for_data ((unsigned char *) data, + CAIRO_FORMAT_ARGB32, 2, 2, 8); + + cairo_set_source_rgb (cr, 1.0, 0, 0); + + /* We can translate with the CTM, with the mask_surface offset, or + * with both. */ + + /* 1. CTM alone. */ + cairo_save (cr); + { + cairo_translate (cr, 2, 2); + cairo_mask_surface (cr, mask, 0, 0); + } + cairo_restore (cr); + + /* 2. Offset alone. */ + cairo_mask_surface (cr, mask, 4, 4); + + /* 3. CTM + offset */ + cairo_translate (cr, 2, 2); + cairo_mask_surface (cr, mask, 4, 4); + + cairo_surface_finish (mask); /* data goes out of scope */ + cairo_surface_destroy (mask); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (mask_surface_ctm, + "Test that cairo_mask_surface is affected properly by the CTM", + "mask", /* keywords */ + NULL, /* requirements */ + 10, 10, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/mask-transformed-image.c b/local/recipes/libs/cairo/source/test/mask-transformed-image.c new file mode 100644 index 0000000000..13c8fe7fce --- /dev/null +++ b/local/recipes/libs/cairo/source/test/mask-transformed-image.c @@ -0,0 +1,96 @@ +/* + * Copyright 2008 Kai-Uwe Behrmann + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Kai-Uwe Behrmann not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Kai-Uwe Behrmann makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * KAI_UWE BEHRMANN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL KAI_UWE BEHRMANN BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Kai-Uwe Behrmann + * Chris Wilson + */ + +#include "cairo-test.h" + +static const char png_filename[] = "romedalen.png"; + +static cairo_surface_t * +create_mask (cairo_t *dst, int width, int height) +{ + cairo_surface_t *mask; + cairo_t *cr; + + mask = cairo_image_surface_create (CAIRO_FORMAT_A8, width, height); + cr = cairo_create (mask); + cairo_surface_destroy (mask); + + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_rectangle (cr, width/4, height/4, width/2, height/2); + cairo_fill (cr); + + mask = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + + return mask; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_surface_t *image, *mask; + + image = cairo_test_create_surface_from_png (ctx, png_filename); + mask = create_mask (cr, 40, 40); + + /* opaque background */ + cairo_paint (cr); + + /* center */ + cairo_translate (cr, + (width - cairo_image_surface_get_width (image)) / 2., + (height - cairo_image_surface_get_height (image)) / 2.); + + /* rotate 30 degree around the center */ + cairo_translate (cr, width/2., height/2.); + cairo_rotate (cr, -30 * 2 * M_PI / 360); + cairo_translate (cr, -width/2., -height/2.); + + /* place the image on our surface */ + cairo_set_source_surface (cr, image, 0, 0); + + /* reset the drawing matrix */ + cairo_identity_matrix (cr); + + /* fill nicely */ + cairo_scale (cr, width / 40., height / 40.); + + /* apply the mask */ + cairo_mask_surface (cr, mask, 0, 0); + + cairo_surface_destroy (mask); + cairo_surface_destroy (image); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (mask_transformed_image, + "Test that cairo_mask() is affected properly by the CTM and not the image", + "mask", /* keywords */ + NULL, /* requirements */ + 80, 80, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/mask-transformed-similar.c b/local/recipes/libs/cairo/source/test/mask-transformed-similar.c new file mode 100644 index 0000000000..c37deb2c0e --- /dev/null +++ b/local/recipes/libs/cairo/source/test/mask-transformed-similar.c @@ -0,0 +1,98 @@ +/* + * Copyright 2008 Kai-Uwe Behrmann + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Kai-Uwe Behrmann not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Kai-Uwe Behrmann makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * KAI_UWE BEHRMANN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL KAI_UWE BEHRMANN BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Kai-Uwe Behrmann + * Chris Wilson + */ + +#include "cairo-test.h" + +static const char png_filename[] = "romedalen.png"; + +static cairo_surface_t * +create_mask (cairo_t *dst, int width, int height) +{ + cairo_surface_t *mask; + cairo_t *cr; + + mask = cairo_surface_create_similar (cairo_get_target (dst), + CAIRO_CONTENT_ALPHA, + width, height); + cr = cairo_create (mask); + cairo_surface_destroy (mask); + + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_rectangle (cr, width/4, height/4, width/2, height/2); + cairo_fill (cr); + + mask = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + + return mask; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_surface_t *image, *mask; + + image = cairo_test_create_surface_from_png (ctx, png_filename); + mask = create_mask (cr, 40, 40); + + /* opaque background */ + cairo_paint (cr); + + /* center */ + cairo_translate (cr, + (width - cairo_image_surface_get_width (image)) / 2., + (height - cairo_image_surface_get_height (image)) / 2.); + + /* rotate 30 degree around the center */ + cairo_translate (cr, width/2., height/2.); + cairo_rotate (cr, -30 * 2 * M_PI / 360); + cairo_translate (cr, -width/2., -height/2.); + + /* place the image on our surface */ + cairo_set_source_surface (cr, image, 0, 0); + + /* reset the drawing matrix */ + cairo_identity_matrix (cr); + + /* fill nicely */ + cairo_scale (cr, width / 40., height / 40.); + + /* apply the mask */ + cairo_mask_surface (cr, mask, 0, 0); + + cairo_surface_destroy (mask); + cairo_surface_destroy (image); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (mask_transformed_similar, + "Test that cairo_mask() is affected properly by the CTM and not the image", + "mask", /* keywords */ + NULL, /* requirements */ + 80, 80, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/mask.c b/local/recipes/libs/cairo/source/test/mask.c new file mode 100644 index 0000000000..89f4c3cc2a --- /dev/null +++ b/local/recipes/libs/cairo/source/test/mask.c @@ -0,0 +1,246 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Owen Taylor + * Kristian Høgsberg + */ + +#include "cairo-test.h" +#include +#include + +#define WIDTH 16 +#define HEIGHT 16 +#define PAD 2 + +static const char *png_filename = "romedalen.png"; +static cairo_surface_t *image; + +static void +set_solid_pattern (const cairo_test_context_t *ctx, cairo_t *cr, int x, int y) +{ + cairo_set_source_rgb (cr, 0, 0, 0.6); +} + +static void +set_translucent_pattern (const cairo_test_context_t *ctx, cairo_t *cr, int x, int y) +{ + cairo_set_source_rgba (cr, 0, 0, 0.6, 0.5); +} + +static void +set_gradient_pattern (const cairo_test_context_t *ctx, cairo_t *cr, int x, int y) +{ + cairo_pattern_t *pattern; + + pattern = + cairo_pattern_create_linear (x, y, x + WIDTH, y + HEIGHT); + cairo_pattern_add_color_stop_rgba (pattern, 0, 1, 1, 1, 1); + cairo_pattern_add_color_stop_rgba (pattern, 1, 0, 0, 0.4, 1); + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); +} + +static void +set_image_pattern (const cairo_test_context_t *ctx, cairo_t *cr, int x, int y) +{ + cairo_pattern_t *pattern; + + if (image == NULL || cairo_surface_status (image)) { + cairo_surface_destroy (image); + image = cairo_test_create_surface_from_png (ctx, png_filename); + } + + pattern = cairo_pattern_create_for_surface (image); + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT); + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); +} + +static void +mask_polygon (cairo_t *cr, int x, int y) +{ + cairo_surface_t *mask_surface; + cairo_t *cr2; + + mask_surface = cairo_surface_create_similar (cairo_get_group_target (cr), + CAIRO_CONTENT_ALPHA, + WIDTH, HEIGHT); + cr2 = cairo_create (mask_surface); + cairo_surface_destroy (mask_surface); + + cairo_save (cr2); + cairo_set_operator (cr2, CAIRO_OPERATOR_CLEAR); + cairo_paint (cr2); + cairo_restore (cr2); + + cairo_set_source_rgb (cr2, 1, 1, 1); /* white */ + + cairo_new_path (cr2); + cairo_move_to (cr2, 0, 0); + cairo_line_to (cr2, 0, HEIGHT); + cairo_line_to (cr2, WIDTH / 2, 3 * HEIGHT / 4); + cairo_line_to (cr2, WIDTH, HEIGHT); + cairo_line_to (cr2, WIDTH, 0); + cairo_line_to (cr2, WIDTH / 2, HEIGHT / 4); + cairo_close_path (cr2); + cairo_fill (cr2); + + cairo_mask_surface (cr, cairo_get_target (cr2), x, y); + cairo_destroy (cr2); +} + +static void +mask_alpha (cairo_t *cr, int x, int y) +{ + cairo_paint_with_alpha (cr, 0.75); +} + +static void +mask_gradient (cairo_t *cr, int x, int y) +{ + cairo_pattern_t *pattern; + + pattern = cairo_pattern_create_linear (x, y, + x + WIDTH, y + HEIGHT); + + cairo_pattern_add_color_stop_rgba (pattern, + 0, + 1, 1, 1, 1); + cairo_pattern_add_color_stop_rgba (pattern, + 1, + 1, 1, 1, 0); + + cairo_mask (cr, pattern); + + cairo_pattern_destroy (pattern); +} + +static void +clip_none (cairo_t *cr, int x, int y) +{ +} + +static void +clip_rects (cairo_t *cr, int x, int y) +{ + int height = HEIGHT / 3; + + cairo_new_path (cr); + cairo_rectangle (cr, x, y, WIDTH, height); + cairo_rectangle (cr, x, y + 2 * height, WIDTH, height); + cairo_clip (cr); +} + +static void +clip_circle (cairo_t *cr, int x, int y) +{ + cairo_new_path (cr); + cairo_arc (cr, x + WIDTH / 2, y + HEIGHT / 2, + WIDTH / 2, 0, 2 * M_PI); + cairo_clip (cr); + cairo_new_path (cr); +} + +static void (* const pattern_funcs[])(const cairo_test_context_t *ctx, cairo_t *cr, int x, int y) = { + set_solid_pattern, + set_translucent_pattern, + set_gradient_pattern, + set_image_pattern, +}; + +static void (* const mask_funcs[])(cairo_t *cr, int x, int y) = { + mask_alpha, + mask_gradient, + mask_polygon, +}; + +static void (* const clip_funcs[])(cairo_t *cr, int x, int y) = { + clip_none, + clip_rects, + clip_circle, +}; + +#define IMAGE_WIDTH (ARRAY_LENGTH (pattern_funcs) * (WIDTH + PAD) + PAD) +#define IMAGE_HEIGHT (ARRAY_LENGTH (mask_funcs) * ARRAY_LENGTH (clip_funcs) * (HEIGHT + PAD) + PAD) + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_surface_t *tmp_surface; + size_t i, j, k; + cairo_t *cr2; + + /* Some of our drawing is unbounded, so we draw each test to + * a temporary surface and copy over. + */ + tmp_surface = cairo_surface_create_similar (cairo_get_group_target (cr), + CAIRO_CONTENT_COLOR_ALPHA, + IMAGE_WIDTH, IMAGE_HEIGHT); + cr2 = cairo_create (tmp_surface); + cairo_surface_destroy (tmp_surface); + + for (k = 0; k < ARRAY_LENGTH (clip_funcs); k++) { + for (j = 0; j < ARRAY_LENGTH (mask_funcs); j++) { + for (i = 0; i < ARRAY_LENGTH (pattern_funcs); i++) { + int x = i * (WIDTH + PAD) + PAD; + int y = (ARRAY_LENGTH (mask_funcs) * k + j) * (HEIGHT + PAD) + PAD; + + /* Clear intermediate surface we are going to be drawing onto */ + cairo_save (cr2); + cairo_set_operator (cr2, CAIRO_OPERATOR_CLEAR); + cairo_paint (cr2); + cairo_restore (cr2); + + /* draw */ + cairo_save (cr2); + + clip_funcs[k] (cr2, x, y); + pattern_funcs[i] (ctx, cr2, x, y); + mask_funcs[j] (cr2, x, y); + + cairo_restore (cr2); + + /* Copy back to the main pixmap */ + cairo_set_source_surface (cr, cairo_get_target (cr2), 0, 0); + cairo_rectangle (cr, x, y, WIDTH, HEIGHT); + cairo_fill (cr); + } + } + } + + cairo_destroy (cr2); + + cairo_surface_destroy (image); + image = NULL; + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (mask, + "Tests of cairo_mask", + "mask", /* keywords */ + NULL, /* requirements */ + IMAGE_WIDTH, IMAGE_HEIGHT, + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/mesh-pattern-accuracy.c b/local/recipes/libs/cairo/source/test/mesh-pattern-accuracy.c new file mode 100644 index 0000000000..d1f60b2fa9 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/mesh-pattern-accuracy.c @@ -0,0 +1,99 @@ +/* + * Copyright © 2009 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 SIZE 256 + +/* This test is designed to test the accuracy of the rendering of mesh + * patterns. + * + * Color accuracy is tested by a square patch covering the whole + * surface with black and white corners. + * + * Extents accuracy is checked by a small red square patch at the + * center of the surface which should measure 2x2 pixels. + */ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *pattern; + double offset; + + cairo_test_paint_checkered (cr); + + pattern = cairo_pattern_create_mesh (); + + cairo_mesh_pattern_begin_patch (pattern); + + cairo_mesh_pattern_move_to (pattern, 0, 0); + cairo_mesh_pattern_line_to (pattern, 1, 0); + cairo_mesh_pattern_line_to (pattern, 1, 1); + cairo_mesh_pattern_line_to (pattern, 0, 1); + + cairo_mesh_pattern_set_corner_color_rgb (pattern, 0, 0, 0, 0); + cairo_mesh_pattern_set_corner_color_rgb (pattern, 1, 1, 1, 1); + cairo_mesh_pattern_set_corner_color_rgb (pattern, 2, 0, 0, 0); + cairo_mesh_pattern_set_corner_color_rgb (pattern, 3, 1, 1, 1); + + cairo_mesh_pattern_end_patch (pattern); + + cairo_mesh_pattern_begin_patch (pattern); + + /* A small 1x1 red patch, that should be rendered as a 2x2 red + * square in the center of the image */ + + offset = 0.5 / SIZE; + + cairo_mesh_pattern_move_to (pattern, 0.5 + offset, 0.5 + offset); + cairo_mesh_pattern_line_to (pattern, 0.5 + offset, 0.5 - offset); + cairo_mesh_pattern_line_to (pattern, 0.5 - offset, 0.5 - offset); + cairo_mesh_pattern_line_to (pattern, 0.5 - offset, 0.5 + offset); + + cairo_mesh_pattern_set_corner_color_rgb (pattern, 0, 1, 0, 0); + cairo_mesh_pattern_set_corner_color_rgb (pattern, 1, 1, 0, 0); + cairo_mesh_pattern_set_corner_color_rgb (pattern, 2, 1, 0, 0); + cairo_mesh_pattern_set_corner_color_rgb (pattern, 3, 1, 0, 0); + + cairo_mesh_pattern_end_patch (pattern); + + cairo_scale (cr, SIZE, SIZE); + + cairo_set_source (cr, pattern); + cairo_paint (cr); + cairo_pattern_destroy (pattern); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (mesh_pattern_accuracy, + "Paint mesh pattern", + "mesh, pattern", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/mesh-pattern-conical.c b/local/recipes/libs/cairo/source/test/mesh-pattern-conical.c new file mode 100644 index 0000000000..4e87eec660 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/mesh-pattern-conical.c @@ -0,0 +1,135 @@ +/* + * Copyright © 2009 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 PAT_WIDTH 100 +#define PAT_HEIGHT 100 +#define SIZE PAT_WIDTH +#define PAD 2 +#define WIDTH (PAD + SIZE + PAD) +#define HEIGHT WIDTH + + +/* + * This test is designed to paint a mesh pattern which contains 8 + * circular sectors approximating a conical gradient. + */ + +#define CENTER_X 50 +#define CENTER_Y 50 +#define RADIUS 50 + +static void +sector_patch (cairo_pattern_t *pattern, + double angle_A, + double A_r, double A_g, double A_b, + double angle_B, + double B_r, double B_g, double B_b) +{ + double r_sin_A, r_cos_A; + double r_sin_B, r_cos_B; + double h; + + r_sin_A = RADIUS * sin (angle_A); + r_cos_A = RADIUS * cos (angle_A); + r_sin_B = RADIUS * sin (angle_B); + r_cos_B = RADIUS * cos (angle_B); + + h = 4.0/3.0 * tan ((angle_B - angle_A) / 4.0); + + cairo_mesh_pattern_begin_patch (pattern); + + cairo_mesh_pattern_move_to (pattern, CENTER_X, CENTER_Y); + cairo_mesh_pattern_line_to (pattern, + CENTER_X + r_cos_A, + CENTER_Y + r_sin_A); + + cairo_mesh_pattern_curve_to (pattern, + CENTER_X + r_cos_A - h * r_sin_A, + CENTER_Y + r_sin_A + h * r_cos_A, + CENTER_X + r_cos_B + h * r_sin_B, + CENTER_Y + r_sin_B - h * r_cos_B, + CENTER_X + r_cos_B, + CENTER_Y + r_sin_B); + + cairo_mesh_pattern_set_corner_color_rgb (pattern, 0, 1, 1, 1); + cairo_mesh_pattern_set_corner_color_rgb (pattern, 1, A_r, A_g, A_b); + cairo_mesh_pattern_set_corner_color_rgb (pattern, 2, B_r, B_g, B_b); + + cairo_mesh_pattern_end_patch (pattern); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *pattern; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_translate (cr, PAD, PAD); + + pattern = cairo_pattern_create_mesh (); + sector_patch (pattern, + 0, 1, 0, 0, + M_PI/4, 1, 1, 0); + sector_patch (pattern, + M_PI/4, 0, 1, 0, + M_PI/2, 0, 1, 1); + sector_patch (pattern, + M_PI/2, 0, 0, 1, + 3*M_PI/4, 1, 0, 1); + sector_patch (pattern, + 3*M_PI/4, 1, 0, 0, + M_PI, 1, 1, 0); + sector_patch (pattern, + -M_PI, 1, 1, 0, + -3*M_PI/4, 0, 1, 0); + sector_patch (pattern, + -3*M_PI/4, 0, 1, 0, + -M_PI/2, 0, 1, 1); + sector_patch (pattern, + -M_PI/2, 0, 1, 1, + -M_PI/4, 0, 0, 1); + sector_patch (pattern, + -M_PI/4, 0, 0, 1, + 0, 1, 0, 0); + + cairo_set_source (cr, pattern); + cairo_paint (cr); + cairo_pattern_destroy (pattern); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (mesh_pattern_conical, + "Paint a conical pattern using a mesh pattern", + "conical, mesh, pattern", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/mesh-pattern-control-points.c b/local/recipes/libs/cairo/source/test/mesh-pattern-control-points.c new file mode 100644 index 0000000000..057e7a1f66 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/mesh-pattern-control-points.c @@ -0,0 +1,114 @@ +/* + * Copyright © 2009 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" + +#define SIZE 90 +#define PAD 10 +#define WIDTH (PAD + 2 * (SIZE + PAD)) +#define HEIGHT (PAD + SIZE + PAD) + + +/* + * This test is designed to paint a two mesh patches. One with default + * control points and one with a control point at a no default + * location. The control points of both of them are drawn as squares + * to make them visible. + */ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *pattern; + unsigned int i, j; + unsigned int num_patches; + double x, y; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_translate (cr, PAD, PAD); + + pattern = cairo_pattern_create_mesh (); + cairo_mesh_pattern_begin_patch (pattern); + + cairo_mesh_pattern_move_to (pattern, 0, 0); + cairo_mesh_pattern_line_to (pattern, SIZE, 0); + cairo_mesh_pattern_line_to (pattern, SIZE, SIZE); + cairo_mesh_pattern_line_to (pattern, 0, SIZE); + + cairo_mesh_pattern_set_corner_color_rgb (pattern, 0, 1, 0, 0); + cairo_mesh_pattern_set_corner_color_rgb (pattern, 1, 0, 1, 0); + cairo_mesh_pattern_set_corner_color_rgb (pattern, 2, 0, 0, 1); + cairo_mesh_pattern_set_corner_color_rgb (pattern, 3, 1, 1, 0); + + cairo_mesh_pattern_set_control_point (pattern, 0, SIZE * .7, SIZE * .7); + cairo_mesh_pattern_set_control_point (pattern, 1, SIZE * .9, SIZE * .7); + cairo_mesh_pattern_set_control_point (pattern, 2, SIZE * .9, SIZE * .9); + cairo_mesh_pattern_set_control_point (pattern, 3, SIZE * .7, SIZE * .9); + + cairo_mesh_pattern_end_patch (pattern); + + cairo_mesh_pattern_begin_patch (pattern); + + cairo_mesh_pattern_move_to (pattern, SIZE + PAD, 0); + cairo_mesh_pattern_line_to (pattern, 2*SIZE + PAD, 0); + cairo_mesh_pattern_line_to (pattern, 2*SIZE + PAD, SIZE); + cairo_mesh_pattern_line_to (pattern, SIZE + PAD, SIZE); + + cairo_mesh_pattern_set_corner_color_rgb (pattern, 0, 1, 0, 0); + cairo_mesh_pattern_set_corner_color_rgb (pattern, 1, 0, 1, 0); + cairo_mesh_pattern_set_corner_color_rgb (pattern, 2, 0, 0, 1); + cairo_mesh_pattern_set_corner_color_rgb (pattern, 3, 1, 1, 0); + + cairo_mesh_pattern_end_patch (pattern); + + cairo_set_source (cr, pattern); + cairo_paint (cr); + + /* mark the location of the control points */ + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_mesh_pattern_get_patch_count (pattern, &num_patches); + for (i = 0; i < num_patches; i++) { + for (j = 0; j < 4; j++) { + cairo_mesh_pattern_get_control_point (pattern, i, j, &x, &y); + cairo_rectangle (cr, x - 5, y - 5, 10, 10); + cairo_fill (cr); + } + } + + cairo_pattern_destroy (pattern); + + return CAIRO_TEST_SUCCESS; +} + + +CAIRO_TEST (mesh_pattern_control_points, + "Paint mesh pattern with non default control points", + "mesh, pattern", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/mesh-pattern-fold.c b/local/recipes/libs/cairo/source/test/mesh-pattern-fold.c new file mode 100644 index 0000000000..cacd712e76 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/mesh-pattern-fold.c @@ -0,0 +1,82 @@ +/* + * Copyright © 2009 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" + +#define SIZE 100 +#define PAD 15 +#define WIDTH (5*SIZE) +#define HEIGHT (5*SIZE) + + +/* This test is designed to paint a mesh pattern which folds along + * both parameters. */ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *pattern; + + cairo_test_paint_checkered (cr); + + pattern = cairo_pattern_create_mesh (); + + cairo_mesh_pattern_begin_patch (pattern); + + cairo_mesh_pattern_move_to (pattern, 1, 1); + + cairo_mesh_pattern_curve_to (pattern, 6, 0, -1, 0, 4, 1); + cairo_mesh_pattern_curve_to (pattern, 5, 6, 5, -1, 4, 4); + cairo_mesh_pattern_curve_to (pattern, -1, 3, 6, 3, 1, 4); + cairo_mesh_pattern_curve_to (pattern, 2, -1, 2, 6, 1, 1); + + cairo_mesh_pattern_set_control_point (pattern, 0, 2, 3); + cairo_mesh_pattern_set_control_point (pattern, 1, 3, 3); + cairo_mesh_pattern_set_control_point (pattern, 2, 3, 2); + cairo_mesh_pattern_set_control_point (pattern, 3, 2, 2); + + cairo_mesh_pattern_set_corner_color_rgb (pattern, 0, 1, 0, 0); + cairo_mesh_pattern_set_corner_color_rgb (pattern, 1, 0, 0, 1); + cairo_mesh_pattern_set_corner_color_rgb (pattern, 2, 0, 0, 0); + cairo_mesh_pattern_set_corner_color_rgb (pattern, 3, 0, 1, 0); + + cairo_mesh_pattern_end_patch (pattern); + + cairo_scale (cr, SIZE, SIZE); + + cairo_set_source (cr, pattern); + cairo_paint (cr); + cairo_pattern_destroy (pattern); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (mesh_pattern_fold, + "Paint a mesh pattern with complex folds", + "mesh, pattern", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/mesh-pattern-overlap.c b/local/recipes/libs/cairo/source/test/mesh-pattern-overlap.c new file mode 100644 index 0000000000..969bc73a33 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/mesh-pattern-overlap.c @@ -0,0 +1,76 @@ +/* + * Copyright © 2009 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" + +#define SIZE 100 +#define PAD 15 +#define WIDTH (PAD + SIZE + PAD) +#define HEIGHT WIDTH + + +/* This test is designed to paint a mesh pattern with a simple + * fold. */ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *pattern; + + cairo_test_paint_checkered (cr); + + cairo_translate (cr, PAD, PAD); + + pattern = cairo_pattern_create_mesh (); + + cairo_mesh_pattern_begin_patch (pattern); + + cairo_mesh_pattern_move_to (pattern, 0, 0); + cairo_mesh_pattern_curve_to (pattern, 30, -30, 60, 30, 100, 0); + cairo_mesh_pattern_curve_to (pattern, 130, 140, 60, -40, 100, 100); + cairo_mesh_pattern_curve_to (pattern, 60, 70, 30, 130, 0, 100); + cairo_mesh_pattern_curve_to (pattern, -30, -40, 30, 140, 0, 0); + + cairo_mesh_pattern_set_corner_color_rgb (pattern, 0, 1, 0, 0); + cairo_mesh_pattern_set_corner_color_rgb (pattern, 1, 0, 1, 0); + cairo_mesh_pattern_set_corner_color_rgb (pattern, 2, 0, 0, 1); + cairo_mesh_pattern_set_corner_color_rgb (pattern, 3, 1, 1, 0); + + cairo_mesh_pattern_end_patch (pattern); + + cairo_set_source (cr, pattern); + cairo_paint (cr); + cairo_pattern_destroy (pattern); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (mesh_pattern_overlap, + "Paint a mesh pattern with a simple fold", + "mesh, pattern", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/mesh-pattern-transformed.c b/local/recipes/libs/cairo/source/test/mesh-pattern-transformed.c new file mode 100644 index 0000000000..5fe0dc048e --- /dev/null +++ b/local/recipes/libs/cairo/source/test/mesh-pattern-transformed.c @@ -0,0 +1,107 @@ +/* + * Copyright © 2009 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" + +#define PAT_WIDTH 170 +#define PAT_HEIGHT 170 +#define SIZE PAT_WIDTH +#define PAD 10 +#define WIDTH 190 +#define HEIGHT 140 + + +/* This test is designed to paint a mesh pattern containing two + * overlapping patches transformed in different ways. */ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *pattern; + + cairo_test_paint_checkered (cr); + + cairo_translate (cr, PAD, PAD); + + pattern = cairo_pattern_create_mesh (); + + cairo_mesh_pattern_begin_patch (pattern); + + cairo_mesh_pattern_move_to (pattern, 0, 0); + cairo_mesh_pattern_curve_to (pattern, 30, -30, 60, 30, 100, 0); + cairo_mesh_pattern_curve_to (pattern, 60, 30, 130, 60, 100, 100); + cairo_mesh_pattern_curve_to (pattern, 60, 70, 30, 130, 0, 100); + cairo_mesh_pattern_curve_to (pattern, 30, 70, -30, 30, 0, 0); + + cairo_mesh_pattern_set_corner_color_rgb (pattern, 0, 1, 0, 0); + cairo_mesh_pattern_set_corner_color_rgb (pattern, 1, 0, 1, 0); + cairo_mesh_pattern_set_corner_color_rgb (pattern, 2, 0, 0, 1); + cairo_mesh_pattern_set_corner_color_rgb (pattern, 3, 1, 1, 0); + + cairo_mesh_pattern_end_patch (pattern); + + cairo_mesh_pattern_begin_patch (pattern); + + cairo_mesh_pattern_move_to (pattern, 50, 50); + cairo_mesh_pattern_curve_to (pattern, 80, 20, 110, 80, 150, 50); + + cairo_mesh_pattern_curve_to (pattern, 110, 80, 180, 110, 150, 150); + + cairo_mesh_pattern_curve_to (pattern, 110, 120, 80, 180, 50, 150); + + cairo_mesh_pattern_curve_to (pattern, 80, 120, 20, 80, 50, 50); + + cairo_mesh_pattern_set_corner_color_rgba (pattern, 0, 1, 0, 0, 0.3); + cairo_mesh_pattern_set_corner_color_rgb (pattern, 1, 0, 1, 0); + cairo_mesh_pattern_set_corner_color_rgba (pattern, 2, 0, 0, 1, 0.3); + cairo_mesh_pattern_set_corner_color_rgb (pattern, 3, 1, 1, 0); + + cairo_mesh_pattern_end_patch (pattern); + + cairo_scale (cr, .5, .5); + + cairo_set_source (cr, pattern); + cairo_paint (cr); + + cairo_translate (cr, PAT_WIDTH, PAT_HEIGHT); + cairo_translate (cr, PAT_WIDTH/2, PAT_HEIGHT/2); + cairo_rotate (cr, M_PI/4); + cairo_translate (cr, -PAT_WIDTH, -PAT_HEIGHT); + cairo_set_source (cr, pattern); + cairo_paint (cr); + + cairo_pattern_destroy (pattern); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (mesh_pattern_transformed, + "Paint mesh pattern with a transformation", + "mesh, pattern", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/mesh-pattern.c b/local/recipes/libs/cairo/source/test/mesh-pattern.c new file mode 100644 index 0000000000..eccbd389aa --- /dev/null +++ b/local/recipes/libs/cairo/source/test/mesh-pattern.c @@ -0,0 +1,94 @@ +/* + * Copyright © 2009 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" + +#define PAT_WIDTH 170 +#define PAT_HEIGHT 170 +#define SIZE PAT_WIDTH +#define PAD 2 +#define WIDTH (PAD + SIZE + PAD) +#define HEIGHT WIDTH + + +/* This test is designed to paint a mesh pattern. The mesh contains + * two overlapping patches */ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *pattern; + + cairo_test_paint_checkered (cr); + + cairo_translate (cr, PAD, PAD); + cairo_translate (cr, 10, 10); + + pattern = cairo_pattern_create_mesh (); + + cairo_mesh_pattern_begin_patch (pattern); + + cairo_mesh_pattern_move_to (pattern, 0, 0); + cairo_mesh_pattern_curve_to (pattern, 30, -30, 60, 30, 100, 0); + cairo_mesh_pattern_curve_to (pattern, 60, 30, 130, 60, 100, 100); + cairo_mesh_pattern_curve_to (pattern, 60, 70, 30, 130, 0, 100); + cairo_mesh_pattern_curve_to (pattern, 30, 70, -30, 30, 0, 0); + + cairo_mesh_pattern_set_corner_color_rgb (pattern, 0, 1, 0, 0); + cairo_mesh_pattern_set_corner_color_rgb (pattern, 1, 0, 1, 0); + cairo_mesh_pattern_set_corner_color_rgb (pattern, 2, 0, 0, 1); + cairo_mesh_pattern_set_corner_color_rgb (pattern, 3, 1, 1, 0); + + cairo_mesh_pattern_end_patch (pattern); + + cairo_mesh_pattern_begin_patch (pattern); + + cairo_mesh_pattern_move_to (pattern, 50, 50); + cairo_mesh_pattern_curve_to (pattern, 80, 20, 110, 80, 150, 50); + cairo_mesh_pattern_curve_to (pattern, 110, 80, 180, 110, 150, 150); + cairo_mesh_pattern_curve_to (pattern, 110, 120, 80, 180, 50, 150); + cairo_mesh_pattern_curve_to (pattern, 80, 120, 20, 80, 50, 50); + + cairo_mesh_pattern_set_corner_color_rgba (pattern, 0, 1, 0, 0, 0.3); + cairo_mesh_pattern_set_corner_color_rgb (pattern, 1, 0, 1, 0); + cairo_mesh_pattern_set_corner_color_rgba (pattern, 2, 0, 0, 1, 0.3); + cairo_mesh_pattern_set_corner_color_rgb (pattern, 3, 1, 1, 0); + + cairo_mesh_pattern_end_patch (pattern); + + cairo_set_source (cr, pattern); + cairo_paint (cr); + cairo_pattern_destroy (pattern); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (mesh_pattern, + "Paint mesh pattern", + "mesh, pattern", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/meson.build b/local/recipes/libs/cairo/source/test/meson.build new file mode 100644 index 0000000000..786ac2a849 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/meson.build @@ -0,0 +1,702 @@ +test_sources = [ + 'a1-bug.c', + 'a1-clip.c', + 'a1-fill.c', + 'a1-image-sample.c', + 'a1-mask.c', + 'a1-mask-sample.c', + 'a1-sample.c', + 'a1-traps-sample.c', + 'a1-rasterisation.c', + 'a8-clear.c', + 'a8-mask.c', + 'aliasing.c', + 'alpha-similar.c', + 'arc-direction.c', + 'arc-infinite-loop.c', + 'arc-looping-dash.c', + 'api-special-cases.c', + 'big-line.c', + 'big-empty-box.c', + 'big-empty-triangle.c', + 'big-little-box.c', + 'big-little-triangle.c', + 'bug-spline.c', + 'big-trap.c', + 'bilevel-image.c', + 'bug-277.c', + 'bug-361.c', + 'bug-40410.c', + 'bug-431.c', + 'bug-448.c', + 'bug-535.c', + 'bug-51910.c', + 'bug-75705.c', + 'bug-84115.c', + 'bug-bo-rectangular.c', + 'bug-bo-collins.c', + 'bug-bo-ricotz.c', + 'bug-source-cu.c', + 'bug-extents.c', + 'bug-image-compositor.c', + 'bug-seams.c', + 'caps.c', + 'checkerboard.c', + 'caps-joins.c', + 'caps-joins-alpha.c', + 'caps-joins-curve.c', + 'caps-tails-curve.c', + 'caps-sub-paths.c', + 'clear.c', + 'clear-source.c', + 'clip-all.c', + 'clip-complex-bug61592.c', + 'clip-complex-shape.c', + 'clip-contexts.c', + 'clip-disjoint.c', + 'clip-disjoint-hatching.c', + 'clip-disjoint-quad.c', + 'clip-device-offset.c', + 'clip-double-free.c', + 'clip-draw-unbounded.c', + 'clip-empty.c', + 'clip-empty-group.c', + 'clip-empty-save.c', + 'clip-fill.c', + 'clip-fill-no-op.c', + 'clip-fill-rule.c', + 'clip-fill-rule-pixel-aligned.c', + 'clip-group-shapes.c', + 'clip-image.c', + 'clip-intersect.c', + 'clip-mixed-antialias.c', + 'clip-nesting.c', + 'clip-operator.c', + 'clip-push-group.c', + 'clip-polygons.c', + 'clip-rectilinear.c', + 'clip-shape.c', + 'clip-stroke.c', + 'clip-stroke-no-op.c', + 'clip-text.c', + 'clip-twice.c', + 'clip-twice-rectangle.c', + 'clip-unbounded.c', + 'clip-zero.c', + 'clipped-group.c', + 'clipped-surface.c', + 'close-path.c', + 'close-path-current-point.c', + 'composite-integer-translate-source.c', + 'composite-integer-translate-over.c', + 'composite-integer-translate-over-repeat.c', + 'copy-disjoint.c', + 'copy-path.c', + 'coverage.c', + 'create-for-stream.c', + 'create-from-broken-png-stream.c', + 'create-from-png.c', + 'create-from-png-16bit.c', + 'create-from-png-stream.c', + 'culled-glyphs.c', + 'curve-to-as-line-to.c', + 'dash-caps-joins.c', + 'dash-curve.c', + 'dash-infinite-loop.c', + 'dash-no-dash.c', + 'dash-offset.c', + 'dash-offset-negative.c', + 'dash-scale.c', + 'dash-state.c', + 'dash-zero-length.c', + 'degenerate-arc.c', + 'degenerate-arcs.c', + 'degenerate-curve-to.c', + 'degenerate-dash.c', + 'degenerate-linear-gradient.c', + 'degenerate-path.c', + 'degenerate-pen.c', + 'degenerate-radial-gradient.c', + 'degenerate-rel-curve-to.c', + 'degenerate-solid-dash.c', + 'drunkard-tails.c', + 'device-offset.c', + 'device-offset-fractional.c', + 'device-offset-positive.c', + 'device-offset-scale.c', + 'dithergradient.c', + 'error-setters.c', + 'extend-pad.c', + 'extend-pad-border.c', + 'extend-pad-similar.c', + 'extend-reflect.c', + 'extend-reflect-similar.c', + 'extend-repeat.c', + 'extend-repeat-similar.c', + 'extended-blend.c', + 'fallback.c', + 'fill-alpha.c', + 'fill-alpha-pattern.c', + 'fill-and-stroke.c', + 'fill-and-stroke-alpha.c', + 'fill-and-stroke-alpha-add.c', + 'fill-degenerate-sort-order.c', + 'fill-disjoint.c', + 'fill-empty.c', + 'fill-image.c', + 'fill-missed-stop.c', + 'fill-rule.c', + 'filter-bilinear-extents.c', + 'filter-nearest-offset.c', + 'filter-nearest-transformed.c', + 'finer-grained-fallbacks.c', + 'font-face-get-type.c', + 'font-matrix-translation.c', + 'font-options.c', + 'glyph-cache-pressure.c', + 'glyph-path.c', + 'get-and-set.c', + 'get-clip.c', + 'get-group-target.c', + 'get-path-extents.c', + 'gradient-alpha.c', + 'gradient-constant-alpha.c', + 'gradient-scale-crash.c', + 'gradient-zero-stops.c', + 'gradient-zero-stops-mask.c', + 'group-clip.c', + 'group-paint.c', + 'group-state.c', + 'group-unaligned.c', + 'hairline.c', + 'half-coverage.c', + 'halo.c', + 'hatchings.c', + 'horizontal-clip.c', + 'huge-linear.c', + 'huge-radial.c', + 'image-surface-source.c', + 'image-bug-710072.c', + 'implicit-close.c', + 'infinite-join.c', + 'in-fill-empty-trapezoid.c', + 'in-fill-trapezoid.c', + 'invalid-matrix.c', + 'inverse-text.c', + 'inverted-clip.c', + 'joins.c', + 'joins-loop.c', + 'joins-star.c', + 'joins-retrace.c', + 'large-clip.c', + 'large-font.c', + 'large-source.c', + 'large-source-roi.c', + 'large-twin-antialias-mixed.c', + 'leaks.c', + 'leaky-dash.c', + 'leaky-dashed-rectangle.c', + 'leaky-dashed-stroke.c', + 'leaky-polygon.c', + 'line-width.c', + 'line-width-large-overlap.c', + 'line-width-overlap.c', + 'line-width-scale.c', + 'line-width-tolerance.c', + 'line-width-zero.c', + 'linear-gradient.c', + 'linear-gradient-extend.c', + 'linear-gradient-large.c', + 'linear-gradient-one-stop.c', + 'linear-gradient-reflect.c', + 'linear-gradient-subset.c', + 'linear-step-function.c', + 'linear-uniform.c', + 'long-dashed-lines.c', + 'long-lines.c', + 'map-to-image.c', + 'mask.c', + 'mask-alpha.c', + 'mask-ctm.c', + 'mask-glyphs.c', + 'mask-surface-ctm.c', + 'mask-transformed-image.c', + 'mask-transformed-similar.c', + 'mesh-pattern.c', + 'mesh-pattern-accuracy.c', + 'mesh-pattern-conical.c', + 'mesh-pattern-control-points.c', + 'mesh-pattern-fold.c', + 'mesh-pattern-overlap.c', + 'mesh-pattern-transformed.c', + 'mime-data.c', + 'mime-surface-api.c', + 'miter-precision.c', + 'move-to-show-surface.c', + 'negative-stride-image.c', + 'new-sub-path.c', + 'nil-surface.c', + 'operator.c', + 'operator-alpha.c', + 'operator-alpha-alpha.c', + 'operator-clear.c', + 'operator-source.c', + 'operator-www.c', + 'outline-tolerance.c', + 'overflow.c', + 'over-above-source.c', + 'over-around-source.c', + 'over-below-source.c', + 'over-between-source.c', + 'overlapping-boxes.c', + 'overlapping-glyphs.c', + 'overlapping-dash-caps.c', + 'paint.c', + 'paint-clip-fill.c', + 'paint-repeat.c', + 'paint-source-alpha.c', + 'paint-with-alpha.c', + 'paint-with-alpha-group-clip.c', + 'partial-clip-text.c', + 'partial-coverage.c', + 'pass-through.c', + 'path-append.c', + 'path-currentpoint.c', + 'path-stroke-twice.c', + 'path-precision.c', + 'pattern-get-type.c', + 'pattern-getters.c', + 'pdf-isolated-group.c', + 'pixman-downscale.c', + 'pixman-rotate.c', + 'png.c', + 'push-group.c', + 'push-group-color.c', + 'push-group-path-offset.c', + 'radial-gradient.c', + 'radial-gradient-extend.c', + 'radial-outer-focus.c', + 'random-clips.c', + 'random-intersections-eo.c', + 'random-intersections-nonzero.c', + 'random-intersections-curves-eo.c', + 'random-intersections-curves-nz.c', + 'raster-source.c', + 'record.c', + 'record1414x.c', + 'record2x.c', + 'record90.c', + 'recordflip.c', + 'record-extend.c', + 'record-neg-extents.c', + 'record-mesh.c', + 'record-replay-extend.c', + 'record-transform-paint.c', + 'record-write-png.c', + 'recording-ink-extents.c', + 'recording-surface-pattern.c', + 'recording-surface-extend.c', + 'rectangle-rounding-error.c', + 'rectilinear-fill.c', + 'rectilinear-grid.c', + 'rectilinear-miter-limit.c', + 'rectilinear-dash.c', + 'rectilinear-dash-scale.c', + 'rectilinear-stroke.c', + 'reflected-stroke.c', + 'rel-path.c', + 'rgb24-ignore-alpha.c', + 'rotate-image-surface-paint.c', + 'rotate-stroke-box.c', + 'rotated-clip.c', + 'rounded-rectangle-fill.c', + 'rounded-rectangle-stroke.c', + 'round-join-bug-520.c', + 'sample.c', + 'scale-down-source-surface-paint.c', + 'scale-offset-image.c', + 'scale-offset-similar.c', + 'scale-source-surface-paint.c', + 'scaled-font-zero-matrix.c', + 'stroke-ctm-caps.c', + 'stroke-clipped.c', + 'stroke-image.c', + 'stroke-open-box.c', + 'select-font-face.c', + 'select-font-no-show-text.c', + 'self-copy.c', + 'self-copy-overlap.c', + 'self-intersecting.c', + 'set-source.c', + 'show-glyphs-advance.c', + 'show-glyphs-many.c', + 'show-text-current-point.c', + 'shape-general-convex.c', + 'shape-sierpinski.c', + 'shifted-operator.c', + 'simple.c', + 'skew-extreme.c', + 'smask.c', + 'smask-fill.c', + 'smask-image-mask.c', + 'smask-mask.c', + 'smask-paint.c', + 'smask-stroke.c', + 'smask-text.c', + 'smp-glyph.c', + 'solid-pattern-cache-stress.c', + 'source-clip.c', + 'source-clip-scale.c', + 'source-surface-scale-paint.c', + 'spline-decomposition.c', + 'stride-12-image.c', + 'stroke-pattern.c', + 'subsurface.c', + 'subsurface-image-repeat.c', + 'subsurface-repeat.c', + 'subsurface-reflect.c', + 'subsurface-pad.c', + 'subsurface-modify-child.c', + 'subsurface-modify-parent.c', + 'subsurface-outside-target.c', + 'subsurface-scale.c', + 'subsurface-similar-repeat.c', + 'surface-finish-twice.c', + 'surface-pattern.c', + 'surface-pattern-big-scale-down.c', + 'surface-pattern-operator.c', + 'surface-pattern-scale-down.c', + 'surface-pattern-scale-down-extend.c', + 'surface-pattern-scale-up.c', + 'text-antialias.c', + 'text-antialias-subpixel.c', + 'text-cache-crash.c', + 'text-glyph-range.c', + 'text-pattern.c', + 'text-rotate.c', + 'text-subpixel.c', + 'text-transform.c', + 'text-unhinted-metrics.c', + 'text-zero-len.c', + 'thin-lines.c', + 'tighten-bounds.c', + 'tiger.c', + 'toy-font-face.c', + 'transforms.c', + 'translate-show-surface.c', + 'trap-clip.c', + 'twin.c', + 'twin-antialias-gray.c', + 'twin-antialias-mixed.c', + 'twin-antialias-none.c', + 'twin-antialias-subpixel.c', + 'unaligned-box.c', + 'unantialiased-shapes.c', + 'unbounded-operator.c', + 'unclosed-strokes.c', + 'user-data.c', + 'user-font.c', + 'user-font-color.c', + 'user-font-mask.c', + 'user-font-proxy.c', + 'user-font-rescale.c', + 'user-font-subpixel.c', + 'world-map.c', + 'white-in-noop.c', + 'xcb-huge-image-shm.c', + 'xcb-huge-subimage.c', + 'xcb-stress-cache.c', + 'xcb-snapshot-assert.c', + 'xcomposite-projection.c', + 'xlib-expose-event.c', + 'zero-alpha.c', + 'zero-mask.c', +] + +test_pthread_sources = [ + 'pthread-same-source.c', + 'pthread-show-text.c', + 'pthread-similar.c', +] + +# Only font-variations.c is ft-specific according to Makefile.sources, the other +# depend on fontconfig +test_ft_font_sources = [ + 'font-variations.c', + 'bitmap-font.c', + 'ft-color-font.c', + 'ft-font-create-for-ft-face.c', + 'ft-show-glyphs-positioning.c', + 'ft-show-glyphs-table.c', + 'ft-text-vertical-layout-type1.c', + 'ft-text-vertical-layout-type3.c', + 'ft-text-antialias-none.c', + 'ft-variable-font.c', +] + +test_ft_svg_font_sources = [ + 'ft-svg-color-font.c', +] + +test_ft_svg_ttx_font_sources = [ + 'ft-svg-cairo-logo.c', + 'ft-svg-render.c', + 'ft-svg-render-color.c' +] + +test_quartz_sources = [ + 'quartz-surface-source.c', + 'quartz-color-font.c', +] + +test_pdf_sources = [ + 'pdf-features.c', + 'pdf-mime-data.c', + 'pdf-operators-text.c', + 'pdf-surface-source.c', + 'pdf-tagged-text.c', +] + +test_pdf_structure_sources = [ + 'pdf-structure.c', +] + +test_ps_sources = [ + 'ps-eps.c', + 'ps-features.c', + 'ps-surface-source.c', +] + +test_svg_sources = [ + 'svg-surface.c', + 'svg-clip.c', + 'svg-surface-source.c', +] + +test_xcb_sources = [ + 'xcb-surface-source.c', +] + +test_xlib_sources = [ + 'xlib-surface.c', + 'xlib-surface-source.c', +] + +test_xlib_xrender_sources = [ + 'get-xrender-format.c', +] + +test_multi_page_sources = [ + 'multi-page.c', + 'mime-unique-id.c', +] + +test_fallback_resolution_sources = [ + 'create-regions.c', + 'fallback-resolution.c', +] + +cairo_test_suite_sources = [ + 'buffer-diff.c', + 'cairo-test.c', + 'cairo-test-runner.c', +] + +cairo_test_trace_sources = [ + 'cairo-test-trace.c', + 'buffer-diff.c', +] + +imagediff_sources = [ + 'imagediff.c', + 'buffer-diff.c', +] + +png_flatten_sources = [ + 'png-flatten.c', +] + +pdf2png_sources = [ + 'pdf2png.c', +] + +svg2png_sources = [ + 'svg2png.c', +] + +ps2png_sources = [ + 'ps2png.c', +] + +test_ttx_fonts = [ + 'cairo-logo-font.ttx', + 'cairo-svg-test-color.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 +has_multipage_surfaces = false +add_fallback_resolution = false + +if conf.get('CAIRO_HAS_REAL_PTHREAD', 0) == 1 + test_sources += test_pthread_sources +endif + +if feature_conf.get('CAIRO_HAS_FT_FONT', 0) == 1 and feature_conf.get('CAIRO_HAS_FC_FONT', 0) == 1 + test_sources += test_ft_font_sources + if conf.get('HAVE_FT_SVG_DOCUMENT', 0) == 1 + test_sources += test_ft_svg_font_sources + if conf.get('CAIRO_CAN_TEST_TTX_FONT', 0) == 1 + test_sources += test_ft_svg_ttx_font_sources + endif + endif +endif + +if feature_conf.get('CAIRO_HAS_QUARTZ_SURFACE', 0) == 1 + test_sources += test_quartz_sources +endif + +if feature_conf.get('CAIRO_HAS_PDF_SURFACE', 0) == 1 + test_sources += test_pdf_sources + if host_machine.system() != 'windows' + test_sources += test_pdf_structure_sources + endif + has_multipage_surfaces = true + add_fallback_resolution = true + build_any2ppm = true +endif + +if feature_conf.get('CAIRO_HAS_PS_SURFACE', 0) == 1 + test_sources += test_ps_sources + has_multipage_surfaces = true + add_fallback_resolution = true + build_any2ppm = true +endif + +if feature_conf.get('CAIRO_HAS_SVG_SURFACE', 0) == 1 + test_sources += test_svg_sources + build_any2ppm = true + add_fallback_resolution = true +endif + +if feature_conf.get('CAIRO_HAS_XCB_SURFACE', 0) == 1 + test_sources += test_xcb_sources +endif + +if feature_conf.get('CAIRO_HAS_XLIB_SURFACE', 0) == 1 + test_sources += test_xlib_sources +endif + +if feature_conf.get('CAIRO_HAS_XLIB_XRENDER_SURFACE', 0) == 1 + test_sources += test_xlib_xrender_sources +endif + +if has_multipage_surfaces + test_sources += test_multi_page_sources +endif + +if add_fallback_resolution + test_sources += test_fallback_resolution_sources +endif + +if feature_conf.get('CAIRO_HAS_SCRIPT_SURFACE', 0) == 1 + build_any2ppm = true +endif + +cairo_test_constructors = custom_target('cairo-test-constructors.c', + input: files(test_sources), + output: 'cairo-test-constructors.c', + command: [python3, files('make-cairo-test-constructors.py')[0], '@OUTPUT@', '@INPUT@']) + +test_depends = [] + +subdir('pdiff') + +if conf.get('CAIRO_CAN_TEST_PDF_SURFACE', 0) == 1 + exe = executable('pdf2png', pdf2png_sources, + dependencies: deps + test_deps, + ) +endif + +if conf.get('CAIRO_CAN_TEST_SVG_SURFACE', 0) == 1 + exe = executable('svg2png', svg2png_sources, + dependencies: deps + test_deps, + ) +endif + +if conf.get('CAIRO_HAS_SPECTRE', 0) == 1 + exe = executable('ps2png', ps2png_sources, + dependencies: deps + test_deps, + ) +endif + +if build_any2ppm + any2ppm_exe = executable('any2ppm', 'any2ppm.c', + include_directories: [incbase], + dependencies: deps + test_deps + [libcairo_dep, libcairoscript_dep], + ) + test_depends += [any2ppm_exe] +endif + +if have_shm and conf.get('CAIRO_HAS_INTERPRETER', 0) == 1 + cairo_test_trace_exe = executable('cairo-test-trace', cairo_test_trace_sources, + include_directories: [incbase], + c_args: pthread_c_args, + link_args: extra_link_args, + dependencies: deps + test_deps + [rt_dep, libcairo_dep, cairoboilerplate_dep, libpdiff_dep, libcairomissing_dep, libcairoscript_dep]) +endif + +exe = executable('cairo-test-suite', [cairo_test_suite_sources, test_sources, cairo_test_constructors], + include_directories: [incbase], + link_args: extra_link_args, + dependencies: deps + test_deps + [libcairo_dep, cairoboilerplate_dep, + libpdiff_dep], +) + +fs = import('fs') +build_dir_files = ['completion.bash', 'index.html', 'testtable.js', 'view-test-results.py'] +foreach file : build_dir_files + fs.copyfile(file) +endforeach + +if build_machine.system() != 'windows' + run_command('ln', '-sfn', + meson.current_source_dir(), + meson.current_build_dir() / 'srcdir', + check: true) +endif + +if ttx.found() + # By default, if the output file exists, ttx creates a new name. We specify the full + # output name to make ttx overwrite the existing file instead of creating a new file. + foreach ttx_font : test_ttx_fonts + custom_target(ttx_font, + input: ttx_font, + command: [ ttx, '-q', '-o', '@OUTDIR@' / '@BASENAME@.ttf', '@INPUT@' ], + output: '@BASENAME@.ttf', + build_by_default: true) + endforeach +endif + +env = environment() + +env.set('srcdir', meson.current_source_dir()) + +test('cairo', exe, + timeout: 60 * 60, + env: env, + 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.has_define('DEBUG_SVG_RENDER') + subdir('svg') +endif diff --git a/local/recipes/libs/cairo/source/test/mime-data.c b/local/recipes/libs/cairo/source/test/mime-data.c new file mode 100644 index 0000000000..cea9d7caf8 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/mime-data.c @@ -0,0 +1,295 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +#include +#include + +/* Basic test to exercise the new mime-data embedding. */ + +static cairo_status_t +read_file (const cairo_test_context_t *ctx, + const char *filename, + unsigned char **data_out, + unsigned int *length_out) +{ + FILE *file; + unsigned char *buf; + unsigned int len; + + file = fopen (filename, "rb"); + if (file == NULL) { + char path[4096]; + + if (errno == ENOMEM) + return CAIRO_STATUS_NO_MEMORY; + + /* try again with srcdir */ + snprintf (path, sizeof (path), + "%s/%s", ctx->srcdir, filename); + file = fopen (path, "rb"); + } + if (file == NULL) { + switch (errno) { + case ENOMEM: + return CAIRO_STATUS_NO_MEMORY; + default: + return CAIRO_STATUS_FILE_NOT_FOUND; + } + } + + fseek (file, 0, SEEK_END); + len = ftell (file); + fseek (file, 0, SEEK_SET); + + buf = xmalloc (len); + *length_out = fread (buf, 1, len, file); + fclose (file); + if (*length_out != len) { + free (buf); + return CAIRO_STATUS_READ_ERROR; + } + + *data_out = buf; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_test_status_t +paint_file (cairo_t *cr, + const char *filename, const char *mime_type, + int x, int y) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_surface_t *image; + unsigned char *mime_data; + unsigned int mime_length; + cairo_status_t status; + + /* Deliberately use a non-matching MIME images, so that we can identify + * when the MIME representation is used in preference to the plain image + * surface. + */ + status = read_file (ctx, filename, &mime_data, &mime_length); + if (status) + return cairo_test_status_from_status (ctx, status); + + image = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 200, 50); + + status = cairo_surface_set_mime_data (image, mime_type, + mime_data, mime_length, + free, mime_data); + if (status) { + cairo_surface_destroy (image); + free (mime_data); + return cairo_test_status_from_status (ctx, status); + } + + cairo_set_source_surface (cr, image, x, y); + cairo_surface_destroy (image); + + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +paint_jbig2_file (cairo_t *cr, int x, int y) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_surface_t *image; + unsigned char *mime_data; + unsigned int mime_length; + cairo_status_t status; + const char jbig2_image1_filename[] = "image1.jb2"; + const char jbig2_image2_filename[] = "image2.jb2"; + const char jbig2_global_filename[] = "global.jb2"; + + /* Deliberately use a non-matching MIME images, so that we can identify + * when the MIME representation is used in preference to the plain image + * surface. + */ + + /* Image 1 */ + + status = read_file (ctx, jbig2_image1_filename, &mime_data, &mime_length); + if (status) + return cairo_test_status_from_status (ctx, status); + + image = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 200, 50); + + status = cairo_surface_set_mime_data (image, CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID, + (unsigned char *)"global", 6, NULL, NULL); + if (status) { + cairo_surface_destroy (image); + return cairo_test_status_from_status (ctx, status); + } + + status = cairo_surface_set_mime_data (image, CAIRO_MIME_TYPE_JBIG2, + mime_data, mime_length, + free, mime_data); + if (status) { + cairo_surface_destroy (image); + free (mime_data); + return cairo_test_status_from_status (ctx, status); + } + + cairo_set_source_surface (cr, image, x, y); + cairo_surface_destroy (image); + + cairo_paint (cr); + + /* Image 2 */ + + status = read_file (ctx, jbig2_image2_filename, &mime_data, &mime_length); + if (status) + return cairo_test_status_from_status (ctx, status); + + image = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 200, 50); + + status = cairo_surface_set_mime_data (image, CAIRO_MIME_TYPE_JBIG2_GLOBAL_ID, + (unsigned char *)"global", 6, NULL, NULL); + if (status) { + cairo_surface_destroy (image); + return cairo_test_status_from_status (ctx, status); + } + + status = cairo_surface_set_mime_data (image, CAIRO_MIME_TYPE_JBIG2, + mime_data, mime_length, + free, mime_data); + if (status) { + cairo_surface_destroy (image); + free (mime_data); + return cairo_test_status_from_status (ctx, status); + } + + /* Set the global data */ + status = read_file (ctx, jbig2_global_filename, &mime_data, &mime_length); + if (status) + return cairo_test_status_from_status (ctx, status); + + status = cairo_surface_set_mime_data (image, CAIRO_MIME_TYPE_JBIG2_GLOBAL, + mime_data, mime_length, + free, mime_data); + if (status) { + cairo_surface_destroy (image); + free (mime_data); + return cairo_test_status_from_status (ctx, status); + } + + cairo_set_source_surface (cr, image, x, y + 50); + cairo_surface_destroy (image); + + cairo_paint (cr); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +paint_ccitt_file (cairo_t *cr, int x, int y) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_surface_t *image; + unsigned char *mime_data; + unsigned int mime_length; + cairo_status_t status; + const char *ccitt_image_filename = "ccitt.g3"; + const char *ccitt_image_params = "Columns=200 Rows=50 K=-1"; + + /* Deliberately use a non-matching MIME images, so that we can identify + * when the MIME representation is used in preference to the plain image + * surface. + */ + + status = read_file (ctx, ccitt_image_filename, &mime_data, &mime_length); + if (status) + return cairo_test_status_from_status (ctx, status); + + image = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 200, 50); + + /* Set the CCITT image data */ + status = cairo_surface_set_mime_data (image, CAIRO_MIME_TYPE_CCITT_FAX, + mime_data, mime_length, + free, mime_data); + if (status) { + cairo_surface_destroy (image); + free (mime_data); + return cairo_test_status_from_status (ctx, status); + } + + /* Set the CCITT image parameters */ + status = cairo_surface_set_mime_data (image, CAIRO_MIME_TYPE_CCITT_FAX_PARAMS, + (unsigned char *)ccitt_image_params, + strlen (ccitt_image_params), + NULL, NULL); + if (status) { + cairo_surface_destroy (image); + return cairo_test_status_from_status (ctx, status); + } + + cairo_set_source_surface (cr, image, x, y); + cairo_surface_destroy (image); + + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const char jpg_filename[] = "jpeg.jpg"; + const char png_filename[] = "png.png"; + const char jp2_filename[] = "jp2.jp2"; + cairo_test_status_t status; + + status = paint_file (cr, jpg_filename, CAIRO_MIME_TYPE_JPEG, 0, 0); + if (status) + return status; + + status = paint_file (cr, png_filename, CAIRO_MIME_TYPE_PNG, 0, 50); + if (status) + return status; + + status = paint_file (cr, jp2_filename, CAIRO_MIME_TYPE_JP2, 0, 100); + if (status) + return status; + + status = paint_jbig2_file (cr, 0, 150); + if (status) + return status; + + status = paint_ccitt_file (cr, 0, 250); + if (status) + return status; + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (mime_data, + "Check that the mime-data embedding works", + "jpeg, api", /* keywords */ + NULL, /* requirements */ + 200, 300, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/mime-surface-api.c b/local/recipes/libs/cairo/source/test/mime-surface-api.c new file mode 100644 index 0000000000..8a8da826d8 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/mime-surface-api.c @@ -0,0 +1,151 @@ +/* + * Copyright © 2011 Uli Schlachter + * + * 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: Uli Schlachter + */ + +#include "cairo-test.h" + +static void +mime_data_destroy_func (void *data) +{ + cairo_bool_t *called = data; + *called = TRUE; +} + +static cairo_test_status_t +check_mime_data (cairo_test_context_t *ctx, cairo_surface_t *surface, + const char *mimetype, const unsigned char *data, + unsigned long length) +{ + const unsigned char *data_ret; + unsigned long length_ret; + + cairo_surface_get_mime_data (surface, mimetype, &data_ret, &length_ret); + if (data_ret != data || length_ret != length) { + cairo_test_log (ctx, + "Surface has mime data %p with length %lu, " + "but expected %p with length %lu\n", + data_ret, length_ret, data, length); + return CAIRO_TEST_ERROR; + } + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +set_and_check_mime_data (cairo_test_context_t *ctx, cairo_surface_t *surface, + const char *mimetype, const unsigned char *data, + unsigned long length, cairo_bool_t *destroy_called) +{ + cairo_status_t status; + + status = cairo_surface_set_mime_data (surface, mimetype, + data, length, + mime_data_destroy_func, + destroy_called); + if (status) { + cairo_test_log (ctx, "Could not set mime data to %s: %s\n", + data, cairo_status_to_string(status)); + return CAIRO_TEST_ERROR; + } + + return check_mime_data (ctx, surface, mimetype, data, length); +} + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + const char *mimetype = "text/x-uri"; + const char *data1 = "https://www.cairographics.org"; + const char *data2 = "https://cairographics.org/examples/"; + cairo_bool_t destroy1_called = FALSE; + cairo_bool_t destroy2_called = FALSE; + cairo_surface_t *surface; + cairo_test_status_t test_status = CAIRO_TEST_SUCCESS; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0); + if (cairo_surface_status (surface)) { + cairo_test_log (ctx, "Could not create image surface\n"); + test_status = CAIRO_TEST_ERROR; + goto out; + } + + test_status = check_mime_data (ctx, surface, mimetype, NULL, 0); + if (test_status) + goto out; + + test_status = set_and_check_mime_data (ctx, surface, mimetype, + (const unsigned char *) data1, + strlen (data1), + &destroy1_called); + if (test_status) + goto out; + + if (destroy1_called) { + cairo_test_log (ctx, "MIME data 1 destroyed too early\n"); + test_status = CAIRO_TEST_ERROR; + goto out; + } + + test_status = set_and_check_mime_data (ctx, surface, mimetype, + (const unsigned char *) data2, + strlen (data2), + &destroy2_called); + if (test_status) + goto out; + + if (!destroy1_called) { + cairo_test_log (ctx, "MIME data 1 destroy callback not called\n"); + test_status = CAIRO_TEST_ERROR; + goto out; + } + if (destroy2_called) { + cairo_test_log (ctx, "MIME data 2 destroyed too early\n"); + test_status = CAIRO_TEST_ERROR; + goto out; + } + + test_status = set_and_check_mime_data (ctx, surface, mimetype, + NULL, 0, NULL); + if (test_status) + goto out; + + if (!destroy2_called) { + cairo_test_log (ctx, "MIME data destroy callback not called\n"); + test_status = CAIRO_TEST_ERROR; + goto out; + } + +out: + cairo_surface_destroy (surface); + + return test_status; +} + +CAIRO_TEST (mime_surface_api, + "Check the mime data API", + "api", /* keywords */ + NULL, /* requirements */ + 0, 0, + preamble, NULL) diff --git a/local/recipes/libs/cairo/source/test/mime-unique-id.c b/local/recipes/libs/cairo/source/test/mime-unique-id.c new file mode 100644 index 0000000000..8d4a161334 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/mime-unique-id.c @@ -0,0 +1,528 @@ +/* + * Copyright © 2017 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 + */ + + +/* Check that source surfaces with same CAIRO_MIME_TYPE_UNIQUE_ID are + * embedded only once in PDF/PS. + * + * To exercise all the surface embedding code in PS/PDF, four types of + * source surfaces are painted on each page, each with its own UNIQUE_ID: + * - an image surface + * - a recording surface with a jpeg mime attached + * - a bounded recording surface + * - an unbounded recording surface. + * + * Four pages are generated. Each source is clipped starting with the + * smallest area on the first page increasing to the unclipped size on + * the last page. This is to ensure the output does not embed the + * source clipped to a smaller size than used on subsequent pages. + * + * The test verifies the use of UNIQUE_ID by comparing the file size + * with the expected size. + */ + +#include "cairo-test.h" + +#include +#include +#include + +#include + +#if CAIRO_HAS_PS_SURFACE +#include +#endif + +#if CAIRO_HAS_PDF_SURFACE +#include +#endif + +#define NUM_PAGES 4 + +#define WIDTH 275 +#define HEIGHT 275 + +#define BASENAME "mime-unique-id" + + +/* Expected file size to check that surfaces are embedded only once. + * SIZE_TOLERANCE should be large enough to allow some variation in + * file size due to changes to the PS/PDF surfaces while being small + * enough to catch any attempt to embed the surface more than + * once. The compressed size of each surface embedded in PDF is: + * - image: 108,774 + * - jpeg: 11,400 + * - recording: 17,518 + * + * If the size check fails, manually check the output and if the + * surfaces are still embedded only once, update the expected sizes. + * + * Note: The PS2 output will embed the image more than once due to the + * lower MAX_L2_FORM_DATA for PS2 in cairo-ps-surface.c. + */ +#define PS2_EXPECTED_SIZE 626926 +#define PS3_EXPECTED_SIZE 381555 +#define PDF_EXPECTED_SIZE 162692 +#define SIZE_TOLERANCE 5000 + +static const char *png_filename = "romedalen.png"; +static const char *jpeg_filename = "romedalen.jpg"; + +static FILE * +my_fopen (cairo_test_context_t *ctx, const char *pathname, const char *mode) +{ + FILE *f = fopen (pathname, mode); + if (f == NULL && errno == ENOENT && ctx->srcdir) { + char *srcdir_pathname; + xasprintf (&srcdir_pathname, "%s/%s", ctx->srcdir, pathname); + f = fopen (srcdir_pathname, mode); + free (srcdir_pathname); + } + return f; +} + +static cairo_test_status_t +create_image_surface (cairo_test_context_t *ctx, cairo_surface_t **surface) +{ + cairo_status_t status; + const char *unique_id = "image"; + + *surface = cairo_test_create_surface_from_png (ctx, png_filename); + status = cairo_surface_set_mime_data (*surface, CAIRO_MIME_TYPE_UNIQUE_ID, + (unsigned char *)unique_id, + strlen (unique_id), + NULL, NULL); + if (status) { + cairo_surface_destroy (*surface); + return cairo_test_status_from_status (ctx, status); + } + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +create_recording_surface_with_mime_jpg (cairo_test_context_t *ctx, cairo_surface_t **surface) +{ + cairo_status_t status; + FILE *f; + unsigned char *data; + long len; + const char *unique_id = "jpeg"; + cairo_rectangle_t extents = { 0, 0, 1, 1 }; + + *surface = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, &extents); + f = my_fopen (ctx, jpeg_filename, "rb"); + if (f == NULL) { + cairo_test_log (ctx, "Unable to open file %s\n", jpeg_filename); + return CAIRO_TEST_FAILURE; + } + + fseek (f, 0, SEEK_END); + len = ftell(f); + fseek (f, 0, SEEK_SET); + data = malloc (len); + if (fread(data, len, 1, f) != 1) { + cairo_test_log (ctx, "Unable to read file %s\n", jpeg_filename); + return CAIRO_TEST_FAILURE; + } + + fclose(f); + status = cairo_surface_set_mime_data (*surface, + CAIRO_MIME_TYPE_JPEG, + data, len, + free, data); + if (status) { + cairo_surface_destroy (*surface); + return cairo_test_status_from_status (ctx, status); + } + + status = cairo_surface_set_mime_data (*surface, CAIRO_MIME_TYPE_UNIQUE_ID, + (unsigned char *)unique_id, + strlen (unique_id), + NULL, NULL); + if (status) { + cairo_surface_destroy (*surface); + return cairo_test_status_from_status (ctx, status); + } + + return CAIRO_TEST_SUCCESS; +} + +static void +draw_tile (cairo_t *cr) +{ + cairo_move_to (cr, 10 + 5, 10); + cairo_arc (cr, 10, 10, 5, 0, 2*M_PI); + cairo_close_path (cr); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_fill (cr); + + cairo_move_to (cr, 30, 10-10*0.43); + cairo_line_to (cr, 25, 10+10*0.43); + cairo_line_to (cr, 35, 10+10*0.43); + cairo_close_path (cr); + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_fill (cr); + + cairo_rectangle (cr, 5, 25, 10, 10); + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_fill (cr); + + cairo_save (cr); + cairo_translate (cr, 30, 30); + cairo_rotate (cr, M_PI/4.0); + cairo_rectangle (cr, -5, -5, 10, 10); + cairo_set_source_rgb (cr, 1, 0, 1); + cairo_fill (cr); + cairo_restore (cr); +} + +#define RECORDING_SIZE 800 +#define TILE_SIZE 40 + +static cairo_test_status_t +create_recording_surface (cairo_test_context_t *ctx, cairo_surface_t **surface, cairo_bool_t bounded) +{ + cairo_status_t status; + int x, y; + cairo_t *cr; + cairo_matrix_t ctm; + int start, size; + const char *bounded_id = "recording bounded"; + const char *unbounded_id = "recording unbounded"; + cairo_rectangle_t extents = { 0, 0, RECORDING_SIZE, RECORDING_SIZE }; + + if (bounded) { + *surface = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, &extents); + start = 0; + size = RECORDING_SIZE; + } else { + *surface = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL); + start = RECORDING_SIZE / 2; + size = RECORDING_SIZE * 2; + } + + /* Draw each tile instead of creating a cairo pattern to make size + * of the emitted recording as large as possible. + */ + cr = cairo_create (*surface); + cairo_set_source_rgb (cr, 1, 1, 0); + cairo_paint (cr); + cairo_get_matrix (cr, &ctm); + for (y = start; y < size; y += TILE_SIZE) { + for (x = start; x < size; x += TILE_SIZE) { + draw_tile (cr); + cairo_translate (cr, TILE_SIZE, 0); + } + cairo_matrix_translate (&ctm, 0, TILE_SIZE); + cairo_set_matrix (cr, &ctm); + } + cairo_destroy (cr); + + status = cairo_surface_set_mime_data (*surface, CAIRO_MIME_TYPE_UNIQUE_ID, + (unsigned char *)(bounded ? bounded_id : unbounded_id), + strlen (bounded ? bounded_id : unbounded_id), + NULL, NULL); + if (status) { + cairo_surface_destroy (*surface); + return cairo_test_status_from_status (ctx, status); + } + + return CAIRO_TEST_SUCCESS; +} + +/* Draw @source scaled to fit @rect and clipped to a rectangle + * @clip_margin units smaller on each side. @rect will be stroked + * with a solid line and the clip rect stroked with a dashed line. + */ +static void +draw_surface (cairo_t *cr, cairo_surface_t *source, cairo_rectangle_int_t *rect, int clip_margin) +{ + cairo_surface_type_t type; + int width, height; + cairo_rectangle_t extents; + const double dashes[2] = { 2, 2 }; + + type = cairo_surface_get_type (source); + if (type == CAIRO_SURFACE_TYPE_IMAGE) { + width = cairo_image_surface_get_width (source); + height = cairo_image_surface_get_height (source); + } else { + if (cairo_recording_surface_get_extents (source, &extents)) { + width = extents.width; + height = extents.height; + } else { + width = RECORDING_SIZE; + height = RECORDING_SIZE; + } + } + + cairo_save (cr); + cairo_rectangle (cr, rect->x, rect->y, rect->width, rect->height); + cairo_stroke (cr); + cairo_rectangle (cr, + rect->x + clip_margin, + rect->y + clip_margin, + rect->width - clip_margin*2, + rect->height - clip_margin*2); + cairo_set_dash (cr, dashes, 2, 0); + cairo_stroke_preserve (cr); + cairo_clip (cr); + + cairo_translate (cr, rect->x, rect->y); + cairo_scale (cr, (double)rect->width/width, (double)rect->height/height); + cairo_set_source_surface (cr, source, 0, 0); + cairo_paint (cr); + + cairo_restore (cr); +} + +static cairo_test_status_t +draw_pages (cairo_test_context_t *ctx, cairo_surface_t *surface) +{ + cairo_t *cr; + int i; + cairo_rectangle_int_t img_rect; + cairo_rectangle_int_t jpg_rect; + cairo_rectangle_int_t bounded_rect; + cairo_rectangle_int_t unbounded_rect; + int clip_margin; + cairo_surface_t *source; + cairo_test_status_t status; + + cr = cairo_create (surface); + + /* target area to fill with the image source */ + img_rect.x = 25; + img_rect.y = 25; + img_rect.width = 100; + img_rect.height = 100; + + /* target area to fill with the recording with jpeg mime source */ + jpg_rect.x = 150; + jpg_rect.y = 25; + jpg_rect.width = 100; + jpg_rect.height = 100; + + /* target area to fill with the bounded recording source */ + bounded_rect.x = 25; + bounded_rect.y = 150; + bounded_rect.width = 100; + bounded_rect.height = 100; + + /* target area to fill with the unbounded recording source */ + unbounded_rect.x = 150; + unbounded_rect.y = 150; + unbounded_rect.width = 100; + unbounded_rect.height = 100; + + /* Draw the image and recording surface on each page. The sources + * are clipped starting with a small clip area on the first page + * and increasing to the source size on last page to ensure the + * embedded source is not clipped to the area used on the first + * page. + * + * The sources are created each time they are used to ensure + * CAIRO_MIME_TYPE_UNIQUE_ID is tested. + */ + for (i = 0; i < NUM_PAGES; i++) { + clip_margin = (NUM_PAGES - i - 1) * 5; + + status = create_image_surface (ctx, &source); + if (status) + return status; + draw_surface (cr, source, &img_rect, clip_margin); + cairo_surface_destroy (source); + + status = create_recording_surface_with_mime_jpg (ctx, &source); + if (status) + return status; + draw_surface (cr, source, &jpg_rect, clip_margin); + cairo_surface_destroy (source); + + status = create_recording_surface (ctx, &source, TRUE); + if (status) + return status; + draw_surface (cr, source, &bounded_rect, clip_margin); + cairo_surface_destroy (source); + + status = create_recording_surface (ctx, &source, FALSE); + if (status) + return status; + draw_surface (cr, source, &unbounded_rect, clip_margin); + cairo_surface_destroy (source); + + cairo_show_page (cr); + } + + cairo_destroy (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +check_file_size (cairo_test_context_t *ctx, const char *filename, long expected_size) +{ + FILE *f; + long size; + + f = my_fopen (ctx, filename, "rb"); + if (f == NULL) { + cairo_test_log (ctx, "Unable to open file %s\n", filename); + return CAIRO_TEST_FAILURE; + } + + fseek (f, 0, SEEK_END); + size = ftell (f); + fclose(f); + + if (labs(size - expected_size) > SIZE_TOLERANCE) { + cairo_test_log (ctx, + "mime-unique-id: File %s has size %ld. Expected size %ld +/- %ld." + " Check if surfaces are embedded once.\n", + filename, size, expected_size, (long)SIZE_TOLERANCE); + return CAIRO_TEST_FAILURE; + } + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + cairo_surface_t *surface; + cairo_status_t status; + char *filename; + cairo_test_status_t result = CAIRO_TEST_UNTESTED; + cairo_test_status_t test_status; + const char *path = cairo_test_mkdir (CAIRO_TEST_OUTPUT_DIR) ? CAIRO_TEST_OUTPUT_DIR : "."; + +#if CAIRO_HAS_PS_SURFACE + if (cairo_test_is_target_enabled (ctx, "ps2")) + { + xasprintf (&filename, "%s/%s.ps2.out.ps", path, BASENAME); + surface = cairo_ps_surface_create (filename, WIDTH, HEIGHT); + status = cairo_surface_status (surface); + if (status) { + cairo_test_log (ctx, "Failed to create ps surface for file %s: %s\n", + filename, cairo_status_to_string (status)); + test_status = CAIRO_TEST_FAILURE; + goto ps2_finish; + } + + cairo_ps_surface_restrict_to_level (surface, CAIRO_PS_LEVEL_2); + + test_status = draw_pages (ctx, surface); + cairo_surface_destroy (surface); + + if (test_status == CAIRO_TEST_SUCCESS) + test_status = check_file_size (ctx, filename, PS2_EXPECTED_SIZE); + + ps2_finish: + cairo_test_log (ctx, "TEST: %s TARGET: %s RESULT: %s\n", + ctx->test->name, + "ps2", + test_status ? "FAIL" : "PASS"); + + if (result == CAIRO_TEST_UNTESTED || test_status == CAIRO_TEST_FAILURE) + result = test_status; + + free (filename); + } + + if (cairo_test_is_target_enabled (ctx, "ps3")) + { + xasprintf (&filename, "%s/%s.ps3.out.ps", path, BASENAME); + surface = cairo_ps_surface_create (filename, WIDTH, HEIGHT); + status = cairo_surface_status (surface); + if (status) { + cairo_test_log (ctx, "Failed to create ps surface for file %s: %s\n", + filename, cairo_status_to_string (status)); + test_status = CAIRO_TEST_FAILURE; + goto ps3_finish; + } + + test_status = draw_pages (ctx, surface); + cairo_surface_destroy (surface); + + if (test_status == CAIRO_TEST_SUCCESS) + test_status = check_file_size (ctx, filename, PS3_EXPECTED_SIZE); + + ps3_finish: + cairo_test_log (ctx, "TEST: %s TARGET: %s RESULT: %s\n", + ctx->test->name, + "ps3", + test_status ? "FAIL" : "PASS"); + + if (result == CAIRO_TEST_UNTESTED || test_status == CAIRO_TEST_FAILURE) + result = test_status; + + free (filename); + } +#endif + +#if CAIRO_HAS_PDF_SURFACE + if (cairo_test_is_target_enabled (ctx, "pdf")) + { + xasprintf (&filename, "%s/%s.pdf.out.pdf", path, BASENAME); + surface = cairo_pdf_surface_create (filename, WIDTH, HEIGHT); + status = cairo_surface_status (surface); + if (status) { + cairo_test_log (ctx, "Failed to create pdf surface for file %s: %s\n", + filename, cairo_status_to_string (status)); + test_status = CAIRO_TEST_FAILURE; + goto pdf_finish; + } + + test_status = draw_pages (ctx, surface); + cairo_surface_destroy (surface); + + if (test_status == CAIRO_TEST_SUCCESS) + test_status = check_file_size (ctx, filename, PDF_EXPECTED_SIZE); + + + pdf_finish: + cairo_test_log (ctx, "TEST: %s TARGET: %s RESULT: %s\n", + ctx->test->name, + "pdf", + test_status ? "FAIL" : "PASS"); + + if (result == CAIRO_TEST_UNTESTED || test_status == CAIRO_TEST_FAILURE) + result = test_status; + + free (filename); + } +#endif + + return result; +} + +CAIRO_TEST (mime_unique_id, + "Check that paginated surfaces embed only one copy of surfaces with the same CAIRO_MIME_TYPE_UNIQUE_ID.", + "paginated", /* keywords */ + "target=vector", /* requirements */ + 0, 0, + preamble, NULL) diff --git a/local/recipes/libs/cairo/source/test/miter-precision.c b/local/recipes/libs/cairo/source/test/miter-precision.c new file mode 100644 index 0000000000..3bcdde00de --- /dev/null +++ b/local/recipes/libs/cairo/source/test/miter-precision.c @@ -0,0 +1,72 @@ +/* + * Copyright © 2007 Keith Packard + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Keith Packard + * + * Contributor(s): + * Keith Packard + */ +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + double xscale, yscale; + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_set_miter_limit (cr, 100000); + for (xscale = 1; xscale <= 1000; xscale += 999) + for (yscale = 1; yscale <= 1000; yscale += 999) + { + double max_scale = xscale > yscale ? xscale : yscale; + cairo_save (cr); + if (xscale > 1) + cairo_translate (cr, 50, 0); + if (yscale > 1) + cairo_translate (cr, 0, 50); + cairo_scale (cr, xscale, yscale); + cairo_set_line_width (cr, 10.0 / max_scale); + cairo_move_to (cr, 10.0 / xscale, 10.0 / yscale); + cairo_line_to (cr, 40.0 / xscale, 10.0 / yscale); + cairo_line_to (cr, 10.0 / xscale, 30.0 / yscale); + cairo_stroke (cr); + cairo_restore (cr); + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (miter_precision, + "test how cairo deals with small miters" + "\ncurrent code draws inappropriate bevels at times", + "stoke, stress", /* keywords */ + NULL, /* requirements */ + 120, 100, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/move-to-show-surface.c b/local/recipes/libs/cairo/source/test/move-to-show-surface.c new file mode 100644 index 0000000000..a52b468274 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/move-to-show-surface.c @@ -0,0 +1,78 @@ +/* + * Copyright © 2004 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +/* Bug history + * + * 2004-10-25 Carl Worth + * + * It looks like cairo_show_surface has no effect if it follows a + * call to cairo_move_to to any coordinate other than 0,0. A little + * bit of poking around suggests this isn't a regression, (at least + * not since the last pixman snapshot). + * + * 2005-04-02 Carl Worth + * + * Status: RESOLVED + * + * Inside cairo_show_surface the current point was being used as + * both source and destination offsets. After fixing that to use 0,0 + * as the source offset and the current point as the destination + * offset, the bug seems to be gone. + * + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface; + uint32_t colors[4] = { + 0xffffffff, 0xffff0000, + 0xff00ff00, 0xff0000ff + }; + int i; + + for (i=0; i < 4; i++) { + surface = cairo_image_surface_create_for_data ((unsigned char *) &colors[i], + CAIRO_FORMAT_RGB24, + 1, 1, 4); + cairo_set_source_surface (cr, surface, + i % 2, i / 2); + cairo_paint (cr); + + cairo_surface_finish (surface); /* colors will go out of scope */ + cairo_surface_destroy (surface); + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (move_to_show_surface, + "Tests calls to cairo_show_surface after cairo_move_to", + "transform", /* keywords */ + NULL, /* requirements */ + 2, 2, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/multi-page.c b/local/recipes/libs/cairo/source/test/multi-page.c new file mode 100644 index 0000000000..a3102dba39 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/multi-page.c @@ -0,0 +1,198 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +#include + +#include + +#if CAIRO_HAS_PS_SURFACE +#include +#endif + +#if CAIRO_HAS_PDF_SURFACE +#include +#endif + +/* The PostScript and PDF backends are now integrated into the main + * test suite, so we are getting good verification of most things + * there. + * + * One thing that isn't supported there yet is multi-page output. So, + * for now we have this one-off test. There's no automatic + * verififcation here yet, but you can manually view the output to + * make sure it looks happy. + */ + +#define WIDTH_IN_INCHES 3 +#define HEIGHT_IN_INCHES 3 +#define WIDTH_IN_POINTS (WIDTH_IN_INCHES * 72.0) +#define HEIGHT_IN_POINTS (HEIGHT_IN_INCHES * 72.0) +#define BASENAME "multi-page.out" + +static void +draw_smiley (cairo_t *cr, double width, double height, double smile_ratio) +{ +#define STROKE_WIDTH .04 + double size; + + double theta = M_PI / 4 * smile_ratio; + double dx = sqrt (0.005) * cos (theta); + double dy = sqrt (0.005) * sin (theta); + + cairo_save (cr); + + if (width > height) + size = height; + else + size = width; + + cairo_translate (cr, (width - size) / 2.0, (height - size) / 2.0); + cairo_scale (cr, size, size); + + /* Fill face */ + cairo_arc (cr, 0.5, 0.5, 0.5 - STROKE_WIDTH, 0, 2 * M_PI); + cairo_set_source_rgb (cr, 1, 1, 0); + cairo_fill_preserve (cr); + + cairo_set_source_rgb (cr, 0, 0, 0); + + /* Stroke face */ + cairo_set_line_width (cr, STROKE_WIDTH / 2.0); + cairo_stroke (cr); + + /* Eyes */ + cairo_set_line_width (cr, STROKE_WIDTH); + cairo_arc (cr, 0.3, 0.4, STROKE_WIDTH, 0, 2 * M_PI); + cairo_fill (cr); + cairo_arc (cr, 0.7, 0.4, STROKE_WIDTH, 0, 2 * M_PI); + cairo_fill (cr); + + /* Mouth */ + cairo_move_to (cr, + 0.35 - dx, 0.75 - dy); + cairo_curve_to (cr, + 0.35 + dx, 0.75 + dy, + 0.65 - dx, 0.75 + dy, + 0.65 + dx, 0.75 - dy); + cairo_stroke (cr); + + cairo_restore (cr); +} + +static void +draw_some_pages (cairo_surface_t *surface) +{ + cairo_t *cr; + int i; + + cr = cairo_create (surface); + +#define NUM_FRAMES 5 + for (i=0; i < NUM_FRAMES; i++) { + draw_smiley (cr, WIDTH_IN_POINTS, HEIGHT_IN_POINTS, + (double) i / (NUM_FRAMES - 1)); + + /* Duplicate the last frame onto another page. (This is just a + * way to sneak cairo_copy_page into the test). + */ + if (i == (NUM_FRAMES - 1)) + cairo_copy_page (cr); + + cairo_show_page (cr); + } + + cairo_destroy (cr); +} + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + cairo_surface_t *surface; + cairo_status_t status; + char *filename; + cairo_test_status_t result = CAIRO_TEST_UNTESTED; + const char *path = cairo_test_mkdir (CAIRO_TEST_OUTPUT_DIR) ? CAIRO_TEST_OUTPUT_DIR : "."; + +#if CAIRO_HAS_PS_SURFACE + if (cairo_test_is_target_enabled (ctx, "ps2") || + cairo_test_is_target_enabled (ctx, "ps3")) + { + if (result == CAIRO_TEST_UNTESTED) + result = CAIRO_TEST_SUCCESS; + + xasprintf (&filename, "%s/%s", path, BASENAME ".ps"); + surface = cairo_ps_surface_create (filename, + WIDTH_IN_POINTS, HEIGHT_IN_POINTS); + status = cairo_surface_status (surface); + if (status) { + cairo_test_log (ctx, "Failed to create ps surface for file %s: %s\n", + filename, cairo_status_to_string (status)); + result = CAIRO_TEST_FAILURE; + } + + draw_some_pages (surface); + + cairo_surface_destroy (surface); + + printf ("multi-page: Please check %s to ensure it looks happy.\n", filename); + free (filename); + } +#endif + +#if CAIRO_HAS_PDF_SURFACE + if (cairo_test_is_target_enabled (ctx, "pdf")) { + if (result == CAIRO_TEST_UNTESTED) + result = CAIRO_TEST_SUCCESS; + + xasprintf (&filename, "%s/%s", path, BASENAME ".pdf"); + surface = cairo_pdf_surface_create (filename, + WIDTH_IN_POINTS, HEIGHT_IN_POINTS); + status = cairo_surface_status (surface); + if (status) { + cairo_test_log (ctx, "Failed to create pdf surface for file %s: %s\n", + filename, cairo_status_to_string (status)); + result = CAIRO_TEST_FAILURE; + } + + draw_some_pages (surface); + + cairo_surface_destroy (surface); + + printf ("multi-page: Please check %s to ensure it looks happy.\n", filename); + free (filename); + } +#endif + + return result; +} + +CAIRO_TEST (multi_page, + "Check the paginated surfaces handle multiple pages.", + "paginated", /* keywords */ + "target=vector", /* requirements */ + 0, 0, + preamble, NULL) diff --git a/local/recipes/libs/cairo/source/test/negative-stride-image.c b/local/recipes/libs/cairo/source/test/negative-stride-image.c new file mode 100644 index 0000000000..dfc8d644dd --- /dev/null +++ b/local/recipes/libs/cairo/source/test/negative-stride-image.c @@ -0,0 +1,71 @@ +/* + * Copyright 2012 Andrea Canciani + * + * 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: Andrea Canciani + */ + +#include "cairo-test.h" + +static const char *png_filename = "romedalen.png"; + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_format_t format = CAIRO_FORMAT_ARGB32; + cairo_t *cr_inv; + cairo_surface_t *png, *inv; + uint8_t *data; + int stride; + + png = cairo_test_create_surface_from_png (ctx, png_filename); + + stride = cairo_format_stride_for_width (format, width); + data = xcalloc (stride, height); + inv = cairo_image_surface_create_for_data (data + stride * (height - 1), + format, width, height, -stride); + + cr_inv = cairo_create (inv); + cairo_set_source_surface (cr_inv, png, 0, 0); + cairo_paint (cr_inv); + cairo_destroy (cr_inv); + + cairo_set_source_surface (cr, inv, 0, 0); + cairo_paint (cr); + + cairo_surface_destroy (png); + + cairo_surface_finish (inv); + cairo_surface_destroy (inv); + + free (data); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (negative_stride_image, + "Test that images with a negative stride are handled correctly.", + "stride, image", /* keywords */ + NULL, /* requirements */ + 256, 192, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/new-sub-path.c b/local/recipes/libs/cairo/source/test/new-sub-path.c new file mode 100644 index 0000000000..f8f6bbe8d4 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/new-sub-path.c @@ -0,0 +1,74 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +#define SIZE 10 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); /* blue */ + + /* Test cairo_new_sub_path followed by several different + * path-modification functions in turn... + */ + + /* ... cairo_move_to */ + cairo_new_sub_path (cr); + cairo_move_to (cr, SIZE, SIZE); + cairo_line_to (cr, SIZE, 2 * SIZE); + + /* ... cairo_line_to */ + cairo_new_sub_path (cr); + cairo_line_to (cr, 2 * SIZE, 1.5 * SIZE); + cairo_line_to (cr, 3 * SIZE, 1.5 * SIZE); + + /* ... cairo_curve_to */ + cairo_new_sub_path (cr); + cairo_curve_to (cr, + 4.0 * SIZE, 1.5 * SIZE, + 4.5 * SIZE, 1.0 * SIZE, + 5.0 * SIZE, 1.5 * SIZE); + + /* ... cairo_arc */ + cairo_new_sub_path (cr); + cairo_arc (cr, + 6.5 * SIZE, 1.5 * SIZE, + 0.5 * SIZE, + 0.0, 2.0 * M_PI); + + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (new_sub_path, + "Test the cairo_new_sub_path call", + "path", /* keywords */ + NULL, /* requirements */ + 8 * SIZE, + 3 * SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/nil-surface.c b/local/recipes/libs/cairo/source/test/nil-surface.c new file mode 100644 index 0000000000..30a1f97e59 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/nil-surface.c @@ -0,0 +1,170 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" +#include + +/* Test to verify fixes for the following similar bugs: + * + * https://bugs.freedesktop.org/show_bug.cgi?id=4088 + * https://bugs.freedesktop.org/show_bug.cgi?id=3915 + * https://bugs.freedesktop.org/show_bug.cgi?id=9906 + */ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_surface_t *surface; + cairo_pattern_t *pattern; + cairo_t *cr2; + + /* + * 1. Test file-not-found from surface->pattern->cairo_t + */ + + /* Make a custom context to not interfere with the one passed in. */ + cr2 = cairo_create (cairo_get_target (cr)); + + /* First, let's make a nil surface. */ + surface = cairo_image_surface_create_from_png ("___THIS_FILE_DOES_NOT_EXIST___"); + + /* Let the error propagate into a nil pattern. */ + pattern = cairo_pattern_create_for_surface (surface); + + /* Then let it propagate into the cairo_t. */ + cairo_set_source (cr2, pattern); + cairo_paint (cr2); + + cairo_pattern_destroy (pattern); + cairo_surface_destroy (surface); + + /* Check that the error made it all that way. */ + if (cairo_status (cr2) != CAIRO_STATUS_FILE_NOT_FOUND) { + cairo_test_log (ctx, "Error: Received status of \"%s\" rather than expected \"%s\"\n", + cairo_status_to_string (cairo_status (cr2)), + cairo_status_to_string (CAIRO_STATUS_FILE_NOT_FOUND)); + cairo_destroy (cr2); + return CAIRO_TEST_FAILURE; + } + + cairo_destroy (cr2); + + /* + * 2. Test NULL pointer pattern->cairo_t + */ + cr2 = cairo_create (cairo_get_target (cr)); + + /* First, trigger the NULL pointer status. */ + pattern = cairo_pattern_create_for_surface (NULL); + + /* Then let it propagate into the cairo_t. */ + cairo_set_source (cr2, pattern); + cairo_paint (cr2); + + cairo_pattern_destroy (pattern); + + /* Check that the error made it all that way. */ + if (cairo_status (cr2) != CAIRO_STATUS_NULL_POINTER) { + cairo_test_log (ctx, "Error: Received status of \"%s\" rather than expected \"%s\"\n", + cairo_status_to_string (cairo_status (cr2)), + cairo_status_to_string (CAIRO_STATUS_NULL_POINTER)); + cairo_destroy (cr2); + return CAIRO_TEST_FAILURE; + } + + cairo_destroy (cr2); + + /* + * 3. Test that cairo_surface_finish can accept NULL or a nil + * surface without crashing. + */ + + cairo_surface_finish (NULL); + + surface = cairo_image_surface_create_from_png ("___THIS_FILE_DOES_NOT_EXIST___"); + cairo_surface_finish (surface); + cairo_surface_destroy (surface); + + /* + * 4. OK, we're straying from the original name, but it's still a + * similar kind of testing of error paths. Here we're making sure + * we can still call a cairo_get_* function after triggering an + * INVALID_RESTORE error. + */ + cr2 = cairo_create (cairo_get_target (cr)); + + /* Trigger invalid restore. */ + cairo_restore (cr2); + if (cairo_status (cr2) != CAIRO_STATUS_INVALID_RESTORE) { + cairo_test_log (ctx, "Error: Received status of \"%s\" rather than expected \"%s\"\n", + cairo_status_to_string (cairo_status (cr2)), + cairo_status_to_string (CAIRO_STATUS_INVALID_RESTORE)); + cairo_destroy (cr2); + return CAIRO_TEST_FAILURE; + } + + /* Test that we can still call cairo_get_fill_rule without crashing. */ + cairo_get_fill_rule (cr2); + + cairo_destroy (cr2); + + /* + * 5. Create a cairo_t for the NULL surface. + */ + cr2 = cairo_create (NULL); + + if (cairo_status (cr2) != CAIRO_STATUS_NULL_POINTER) { + cairo_test_log (ctx, "Error: Received status of \"%s\" rather than expected \"%s\"\n", + cairo_status_to_string (cairo_status (cr2)), + cairo_status_to_string (CAIRO_STATUS_NULL_POINTER)); + cairo_destroy (cr2); + return CAIRO_TEST_FAILURE; + } + + /* Test that get_target returns something valid */ + if (cairo_get_target (cr2) == NULL) { + cairo_test_log (ctx, "Error: cairo_get_target() returned NULL\n"); + cairo_destroy (cr2); + return CAIRO_TEST_FAILURE; + } + + /* Test that push_group doesn't crash */ + cairo_push_group (cr2); + cairo_stroke (cr2); + pattern = cairo_pop_group (cr2); + cairo_pattern_destroy (pattern); + + cairo_destroy (cr2); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (nil_surface, + "Test that nil surfaces do not make cairo crash.", + "api", /* keywords */ + NULL, /* requirements */ + 1, 1, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/operator-alpha-alpha.c b/local/recipes/libs/cairo/source/test/operator-alpha-alpha.c new file mode 100644 index 0000000000..2cef8585c5 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/operator-alpha-alpha.c @@ -0,0 +1,166 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright 2002 University of Southern California + * Copyright 2005 Red Hat, Inc. + * Copyright 2007 Emmanuel Pacaud + * Copyright 2008 Benjamin Otte + * Copyright 2008 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Owen Taylor + * Kristian Høgsberg + * Emmanuel Pacaud + * Chris Wilson + * Andrea Canciani + */ + +#include "cairo-test.h" + +#define STEPS 16 +#define START_OPERATOR CAIRO_OPERATOR_CLEAR +#define STOP_OPERATOR CAIRO_OPERATOR_HSL_LUMINOSITY + +#define SIZE 3 +#define COUNT 6 +#define FULL_WIDTH ((STEPS + 1) * COUNT - 1) +#define FULL_HEIGHT ((COUNT + STOP_OPERATOR - START_OPERATOR) / COUNT) * (STEPS + 1) + +static void +create_patterns (cairo_t *bg, cairo_t *fg) +{ + int x; + + for (x = 0; x < STEPS; x++) { + double i = (double) x / (STEPS - 1); + cairo_set_source_rgba (bg, 0, 0, 0, i); + cairo_rectangle (bg, x, 0, 1, STEPS); + cairo_fill (bg); + + cairo_set_source_rgba (fg, 0, 0, 0, i); + cairo_rectangle (fg, 0, x, STEPS, 1); + cairo_fill (fg); + } +} + +/* expects a STEP*STEP pixel rectangle */ +static void +do_composite (cairo_t *cr, cairo_operator_t op, cairo_surface_t *bg, cairo_surface_t *fg) +{ + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_surface (cr, bg, 0, 0); + cairo_paint (cr); + + cairo_set_operator (cr, op); + cairo_set_source_surface (cr, fg, 0, 0); + cairo_paint (cr); +} + +static void +subdraw (cairo_t *cr, int width, int height) +{ + size_t i = 0; + cairo_operator_t op; + cairo_t *bgcr, *fgcr; + cairo_surface_t *bg, *fg; + + bg = cairo_surface_create_similar (cairo_get_target (cr), + CAIRO_CONTENT_ALPHA, SIZE * STEPS, SIZE * STEPS); + fg = cairo_surface_create_similar (cairo_get_target (cr), + CAIRO_CONTENT_ALPHA, SIZE * STEPS, SIZE * STEPS); + bgcr = cairo_create (bg); + fgcr = cairo_create (fg); + cairo_scale (bgcr, SIZE, SIZE); + cairo_scale (fgcr, SIZE, SIZE); + create_patterns (bgcr, fgcr); + cairo_destroy (bgcr); + cairo_destroy (fgcr); + + for (op = START_OPERATOR; op <= STOP_OPERATOR; op++, i++) { + cairo_save (cr); + cairo_translate (cr, + SIZE * (STEPS + 1) * (i % COUNT), + SIZE * (STEPS + 1) * (i / COUNT)); + cairo_rectangle (cr, 0, 0, SIZE * (STEPS + 1), SIZE * (STEPS+1)); + cairo_clip (cr); + do_composite (cr, op, bg, fg); + cairo_restore (cr); + } + + cairo_surface_destroy (fg); + cairo_surface_destroy (bg); +} + + +static cairo_surface_t * +create_source (cairo_surface_t *target, int width, int height) +{ + cairo_surface_t *similar; + cairo_t *cr; + + similar = cairo_surface_create_similar (target, + CAIRO_CONTENT_ALPHA, + width, height); + cr = cairo_create (similar); + cairo_surface_destroy (similar); + + subdraw (cr, width, height); + + similar = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + + return similar; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *source; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + source = create_source (cairo_get_target (cr), width, height); + cairo_set_source_surface (cr, source, 0, 0); + cairo_surface_destroy (source); + + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (operator_alpha_alpha, + "Tests result of compositing pure-alpha surfaces" + "\nCompositing of pure-alpha sources is inconsistent across backends.", + "alpha, similar, operator", /* keywords */ + NULL, /* requirements */ + FULL_WIDTH * SIZE, FULL_HEIGHT * SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/operator-alpha.c b/local/recipes/libs/cairo/source/test/operator-alpha.c new file mode 100644 index 0000000000..1ce4ecdf26 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/operator-alpha.c @@ -0,0 +1,65 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +#define N_OPERATORS (CAIRO_OPERATOR_SATURATE + 1) +#define SIZE 10 +#define PAD 3 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + unsigned int n; + + cairo_translate (cr, PAD, PAD); + + for (n = 0; n < N_OPERATORS; n++) { + cairo_reset_clip (cr); + cairo_rectangle (cr, 0, 0, SIZE, SIZE); + cairo_clip (cr); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_rectangle (cr, 0, 0, SIZE-PAD, SIZE-PAD); + cairo_fill (cr); + + cairo_set_source_rgba (cr, 0, 0, 1, .33); + cairo_set_operator (cr, n); + cairo_rectangle (cr, PAD, PAD, SIZE-PAD, SIZE-PAD); + cairo_fill (cr); + + cairo_translate (cr, SIZE+PAD, 0); + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (operator_alpha, + "Tests using set_operator() with an non-opaque source", + "operator, alpha", /* keywords */ + NULL, /* requirements */ + (SIZE+PAD) * N_OPERATORS + PAD, SIZE + 2*PAD, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/operator-clear.c b/local/recipes/libs/cairo/source/test/operator-clear.c new file mode 100644 index 0000000000..72a32c2194 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/operator-clear.c @@ -0,0 +1,196 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Kristian Høgsberg + * Owen Taylor + */ + +#include "cairo-test.h" +#include +#include + +#define WIDTH 16 +#define HEIGHT 16 +#define PAD 2 + +static void +set_solid_pattern (cairo_t *cr, int x, int y) +{ + cairo_set_source_rgb (cr, 1.0, 0, 0.0); +} + +static void +set_gradient_pattern (cairo_t *cr, int x, int y) +{ + cairo_pattern_t *pattern; + + pattern = cairo_pattern_create_linear (x, y, x + WIDTH, y + HEIGHT); + cairo_pattern_add_color_stop_rgba (pattern, 0.2, 1, 0, 0, 1); + cairo_pattern_add_color_stop_rgba (pattern, 0.8, 1, 0, 0, 0.0); + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); +} + +static void +draw_mask (cairo_t *cr, int x, int y) +{ + cairo_surface_t *mask_surface; + cairo_t *cr2; + + double width = (int)(0.9 * WIDTH); + double height = (int)(0.9 * HEIGHT); + x += 0.05 * WIDTH; + y += 0.05 * HEIGHT; + + mask_surface = cairo_surface_create_similar (cairo_get_group_target (cr), + CAIRO_CONTENT_ALPHA, + width, height); + cr2 = cairo_create (mask_surface); + cairo_surface_destroy (mask_surface); + + cairo_set_source_rgb (cr2, 1, 1, 1); /* white */ + + cairo_arc (cr2, 0.5 * width, 0.5 * height, 0.45 * height, 0, 2 * M_PI); + cairo_fill (cr2); + + cairo_mask_surface (cr, cairo_get_target (cr2), x, y); + cairo_destroy (cr2); +} + +static void +draw_glyphs (cairo_t *cr, int x, int y) +{ + cairo_text_extents_t extents; + + cairo_set_font_size (cr, 0.8 * HEIGHT); + + cairo_text_extents (cr, "FG", &extents); + cairo_move_to (cr, + x + floor ((WIDTH - extents.width) / 2 + 0.5) - extents.x_bearing, + y + floor ((HEIGHT - extents.height) / 2 + 0.5) - extents.y_bearing); + cairo_show_text (cr, "FG"); +} + +static void +draw_polygon (cairo_t *cr, int x, int y) +{ + double width = (int)(0.9 * WIDTH); + double height = (int)(0.9 * HEIGHT); + x += 0.05 * WIDTH; + y += 0.05 * HEIGHT; + + cairo_new_path (cr); + cairo_move_to (cr, x, y); + cairo_line_to (cr, x, y + height); + cairo_line_to (cr, x + width / 2, y + 3 * height / 4); + cairo_line_to (cr, x + width, y + height); + cairo_line_to (cr, x + width, y); + cairo_line_to (cr, x + width / 2, y + height / 4); + cairo_close_path (cr); + cairo_fill (cr); +} + +static void +draw_rects (cairo_t *cr, int x, int y) +{ + double block_width = (int)(0.33 * WIDTH + 0.5); + double block_height = (int)(0.33 * HEIGHT + 0.5); + int i, j; + + for (i = 0; i < 3; i++) + for (j = 0; j < 3; j++) + if ((i + j) % 2 == 0) + cairo_rectangle (cr, + x + block_width * i, y + block_height * j, + block_width, block_height); + + cairo_fill (cr); +} + +static void (* const pattern_funcs[])(cairo_t *cr, int x, int y) = { + set_solid_pattern, + set_gradient_pattern, +}; + +static void (* const draw_funcs[])(cairo_t *cr, int x, int y) = { + draw_mask, + draw_glyphs, + draw_polygon, + draw_rects +}; + +#define IMAGE_WIDTH (ARRAY_LENGTH (pattern_funcs) * (WIDTH + PAD) + PAD) +#define IMAGE_HEIGHT (ARRAY_LENGTH (draw_funcs) * (HEIGHT + PAD) + PAD) + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + size_t i, j, x, y; + cairo_pattern_t *pattern; + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + + for (j = 0; j < ARRAY_LENGTH (draw_funcs); j++) { + for (i = 0; i < ARRAY_LENGTH (pattern_funcs); i++) { + x = i * (WIDTH + PAD) + PAD; + y = j * (HEIGHT + PAD) + PAD; + + cairo_save (cr); + + pattern = cairo_pattern_create_linear (x + WIDTH, y, + x, y + HEIGHT); + cairo_pattern_add_color_stop_rgba (pattern, 0.2, + 0.0, 0.0, 1.0, 1.0); /* Solid blue */ + cairo_pattern_add_color_stop_rgba (pattern, 0.8, + 0.0, 0.0, 1.0, 0.0); /* Transparent blue */ + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + + cairo_rectangle (cr, x, y, WIDTH, HEIGHT); + cairo_fill_preserve (cr); + cairo_clip (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); + pattern_funcs[i] (cr, x, y); + draw_funcs[j] (cr, x, y); + if (cairo_status (cr)) + cairo_test_log (ctx, "%d %d HERE!\n", (int)i, (int)j); + + cairo_restore (cr); + } + } + + if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) + cairo_test_log (ctx, "%d %d .HERE!\n", (int)i, (int)j); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (operator_clear, + "Test of CAIRO_OPERATOR_CLEAR", + "operator", /* keywords */ + NULL, /* requirements */ + IMAGE_WIDTH, IMAGE_HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/operator-source.c b/local/recipes/libs/cairo/source/test/operator-source.c new file mode 100644 index 0000000000..9330a65d1e --- /dev/null +++ b/local/recipes/libs/cairo/source/test/operator-source.c @@ -0,0 +1,250 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Kristian Høgsberg + * Owen Taylor + * Uli Schlachter + */ + +#include "cairo-test.h" +#include +#include + +#define WIDTH 16 +#define HEIGHT 16 +#define PAD 2 + +static void +set_solid_pattern (cairo_t *cr, int x, int y) +{ + cairo_set_source_rgb (cr, 1.0, 0, 0.0); +} + +static void +set_translucent_pattern (cairo_t *cr, int x, int y) +{ + cairo_set_source_rgba (cr, 1, 0, 0, 0.5); +} + +static void +set_gradient_pattern (cairo_t *cr, int x, int y) +{ + cairo_pattern_t *pattern; + + pattern = cairo_pattern_create_linear (x, y, x + WIDTH, y + HEIGHT); + cairo_pattern_add_color_stop_rgba (pattern, 0.2, 1, 0, 0, 1); + cairo_pattern_add_color_stop_rgba (pattern, 0.8, 1, 0, 0, 0.0); + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); +} + +static void +set_surface_pattern (cairo_t *cr, int x, int y) +{ + cairo_surface_t *source_surface; + cairo_t *cr2; + + double width = (int)(0.6 * WIDTH); + double height = (int)(0.6 * HEIGHT); + x += 0.2 * WIDTH; + y += 0.2 * HEIGHT; + + source_surface = cairo_surface_create_similar (cairo_get_group_target (cr), + CAIRO_CONTENT_COLOR_ALPHA, + width, height); + cr2 = cairo_create (source_surface); + cairo_surface_destroy (source_surface); + + cairo_set_source_rgb (cr2, 1, 0, 0); /* red */ + cairo_paint (cr2); + + cairo_set_source_rgb (cr2, 1, 1, 1); /* white */ + + cairo_arc (cr2, 0.5 * width, 0.5 * height, 0.5 * height, 0, 2 * M_PI); + cairo_fill (cr2); + + cairo_set_source_surface (cr, cairo_get_target (cr2), x, y); + cairo_destroy (cr2); +} + +static void +draw_mask (cairo_t *cr, int x, int y) +{ + cairo_surface_t *mask_surface; + cairo_t *cr2; + + double width = (int)(0.9 * WIDTH); + double height = (int)(0.9 * HEIGHT); + x += 0.05 * WIDTH; + y += 0.05 * HEIGHT; + + mask_surface = cairo_surface_create_similar (cairo_get_group_target (cr), + CAIRO_CONTENT_ALPHA, + width, height); + cr2 = cairo_create (mask_surface); + cairo_surface_destroy (mask_surface); + + cairo_set_source_rgb (cr2, 1, 1, 1); /* white */ + + cairo_arc (cr2, 0.5 * width, 0.5 * height, 0.45 * height, 0, 2 * M_PI); + cairo_fill (cr2); + + cairo_mask_surface (cr, cairo_get_target (cr2), x, y); + cairo_destroy (cr2); +} + +static void +draw_glyphs (cairo_t *cr, int x, int y) +{ + cairo_text_extents_t extents; + + cairo_set_font_size (cr, 0.8 * HEIGHT); + + cairo_text_extents (cr, "FG", &extents); + cairo_move_to (cr, + x + floor ((WIDTH - extents.width) / 2 + 0.5) - extents.x_bearing, + y + floor ((HEIGHT - extents.height) / 2 + 0.5) - extents.y_bearing); + cairo_show_text (cr, "FG"); +} + +static void +draw_polygon (cairo_t *cr, int x, int y) +{ + double width = (int)(0.9 * WIDTH); + double height = (int)(0.9 * HEIGHT); + x += 0.05 * WIDTH; + y += 0.05 * HEIGHT; + + cairo_new_path (cr); + cairo_move_to (cr, x, y); + cairo_line_to (cr, x, y + height); + cairo_line_to (cr, x + width / 2, y + 3 * height / 4); + cairo_line_to (cr, x + width, y + height); + cairo_line_to (cr, x + width, y); + cairo_line_to (cr, x + width / 2, y + height / 4); + cairo_close_path (cr); + cairo_fill (cr); +} + +static void +draw_rects (cairo_t *cr, int x, int y, double offset) +{ + double block_width = (int)(0.33 * WIDTH + 0.5) - offset/3; + double block_height = (int)(0.33 * HEIGHT + 0.5) - offset/3; + int i, j; + + x += offset/2; + y += offset/2; + + for (i = 0; i < 3; i++) + for (j = 0; j < 3; j++) + if ((i + j) % 2 == 0) + cairo_rectangle (cr, + x + block_width * i, y + block_height * j, + block_width, block_height); + + cairo_fill (cr); +} + +static void +draw_aligned_rects (cairo_t *cr, int x, int y) +{ + draw_rects (cr, x, y, 0); +} + +static void +draw_unaligned_rects (cairo_t *cr, int x, int y) +{ + draw_rects (cr, x, y, 2.1); +} + +static void (* const pattern_funcs[])(cairo_t *cr, int x, int y) = { + set_solid_pattern, + set_translucent_pattern, + set_gradient_pattern, + set_surface_pattern, +}; + +static void (* const draw_funcs[])(cairo_t *cr, int x, int y) = { + draw_mask, + draw_glyphs, + draw_polygon, + draw_aligned_rects, + draw_unaligned_rects +}; + +#define IMAGE_WIDTH (ARRAY_LENGTH (pattern_funcs) * (WIDTH + PAD) + PAD) +#define IMAGE_HEIGHT (ARRAY_LENGTH (draw_funcs) * (HEIGHT + PAD) + PAD) + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + size_t i, j, x, y; + cairo_pattern_t *pattern; + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + + for (j = 0; j < ARRAY_LENGTH (draw_funcs); j++) { + for (i = 0; i < ARRAY_LENGTH (pattern_funcs); i++) { + x = i * (WIDTH + PAD) + PAD; + y = j * (HEIGHT + PAD) + PAD; + + cairo_save (cr); + + pattern = cairo_pattern_create_linear (x + WIDTH, y, + x, y + HEIGHT); + cairo_pattern_add_color_stop_rgba (pattern, 0.2, + 0.0, 0.0, 1.0, 1.0); /* Solid blue */ + cairo_pattern_add_color_stop_rgba (pattern, 0.8, + 0.0, 0.0, 1.0, 0.0); /* Transparent blue */ + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + + cairo_rectangle (cr, x, y, WIDTH, HEIGHT); + cairo_fill_preserve (cr); + cairo_clip (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + pattern_funcs[i] (cr, x, y); + draw_funcs[j] (cr, x, y); + if (cairo_status (cr)) + cairo_test_log (ctx, "%d %d HERE!\n", (int)i, (int)j); + + cairo_restore (cr); + } + } + + if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) + cairo_test_log (ctx, "%d %d .HERE!\n", (int)i, (int)j); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (operator_source, + "Test of CAIRO_OPERATOR_SOURCE", + "operator", /* keywords */ + NULL, /* requirements */ + IMAGE_WIDTH, IMAGE_HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/operator-www.c b/local/recipes/libs/cairo/source/test/operator-www.c new file mode 100644 index 0000000000..4d804fced0 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/operator-www.c @@ -0,0 +1,179 @@ +/* + * Copyright © 2011 Nis Martensen + * + * 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. + */ + +#include "cairo-test.h" + +#define OPERATORS_COUNT 29 +#define WIDTH 160 +#define HEIGHT 120 + +static void +example (cairo_t *cr, const char *name) +{ + cairo_save (cr); + cairo_push_group_with_content (cr, cairo_surface_get_content (cairo_get_target (cr))); + + cairo_rectangle (cr, 0, 0, WIDTH, HEIGHT); + cairo_clip (cr); + + cairo_rectangle (cr, 0, 0, 120, 90); + cairo_set_source_rgba (cr, 0.7, 0, 0, 0.8); + cairo_fill (cr); + + if (strcmp (name, "clear") == 0) + cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); + + else if (strcmp (name, "source") == 0) + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + else if (strcmp (name, "over") == 0) + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + else if (strcmp (name, "in") == 0) + cairo_set_operator (cr, CAIRO_OPERATOR_IN); + else if (strcmp (name, "out") == 0) + cairo_set_operator (cr, CAIRO_OPERATOR_OUT); + else if (strcmp (name, "atop") == 0) + cairo_set_operator (cr, CAIRO_OPERATOR_ATOP); + + else if (strcmp (name, "dest") == 0) + cairo_set_operator (cr, CAIRO_OPERATOR_DEST); + else if (strcmp (name, "dest_over") == 0) + cairo_set_operator (cr, CAIRO_OPERATOR_DEST_OVER); + else if (strcmp (name, "dest_in") == 0) + cairo_set_operator (cr, CAIRO_OPERATOR_DEST_IN); + else if (strcmp (name, "dest_out") == 0) + cairo_set_operator (cr, CAIRO_OPERATOR_DEST_OUT); + else if (strcmp (name, "dest_atop") == 0) + cairo_set_operator (cr, CAIRO_OPERATOR_DEST_ATOP); + + else if (strcmp (name, "xor") == 0) + cairo_set_operator (cr, CAIRO_OPERATOR_XOR); + else if (strcmp (name, "add") == 0) + cairo_set_operator (cr, CAIRO_OPERATOR_ADD); + else if (strcmp (name, "saturate") == 0) + cairo_set_operator (cr, CAIRO_OPERATOR_SATURATE); + else if (strcmp (name, "multiply") == 0) + cairo_set_operator (cr, CAIRO_OPERATOR_MULTIPLY); + else if (strcmp (name, "screen") == 0) + cairo_set_operator (cr, CAIRO_OPERATOR_SCREEN); + else if (strcmp (name, "overlay") == 0) + cairo_set_operator (cr, CAIRO_OPERATOR_OVERLAY); + else if (strcmp (name, "darken") == 0) + cairo_set_operator (cr, CAIRO_OPERATOR_DARKEN); + else if (strcmp (name, "lighten") == 0) + cairo_set_operator (cr, CAIRO_OPERATOR_LIGHTEN); + else if (strcmp (name, "color_dodge") == 0) + cairo_set_operator (cr, CAIRO_OPERATOR_COLOR_DODGE); + else if (strcmp (name, "color_burn") == 0) + cairo_set_operator (cr, CAIRO_OPERATOR_COLOR_BURN); + else if (strcmp (name, "hard_light") == 0) + cairo_set_operator (cr, CAIRO_OPERATOR_HARD_LIGHT); + else if (strcmp (name, "soft_light") == 0) + cairo_set_operator (cr, CAIRO_OPERATOR_SOFT_LIGHT); + else if (strcmp (name, "difference") == 0) + cairo_set_operator (cr, CAIRO_OPERATOR_DIFFERENCE); + else if (strcmp (name, "exclusion") == 0) + cairo_set_operator (cr, CAIRO_OPERATOR_EXCLUSION); + else if (strcmp (name, "hsl_hue") == 0) + cairo_set_operator (cr, CAIRO_OPERATOR_HSL_HUE); + else if (strcmp (name, "hsl_saturation") == 0) + cairo_set_operator (cr, CAIRO_OPERATOR_HSL_SATURATION); + else if (strcmp (name, "hsl_color") == 0) + cairo_set_operator (cr, CAIRO_OPERATOR_HSL_COLOR); + else if (strcmp (name, "hsl_luminosity") == 0) + cairo_set_operator (cr, CAIRO_OPERATOR_HSL_LUMINOSITY); + + cairo_rectangle (cr, 40, 30, 120, 90); + cairo_set_source_rgba (cr, 0, 0, 0.9, 0.4); + cairo_fill (cr); + + cairo_pattern_t *pattern = cairo_pop_group (cr); + cairo_rectangle (cr, 0, 0, WIDTH, HEIGHT); + cairo_clip (cr); + // Make problems with CAIRO_CONTENT_COLOR visible + if (cairo_surface_get_content (cairo_get_target (cr)) == CAIRO_CONTENT_COLOR) { + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + } + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + cairo_paint (cr); + cairo_restore (cr); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (cr, 17); + cairo_move_to (cr, WIDTH + 20, 70); + cairo_set_source_rgb (cr, 1, 1, 0); + cairo_show_text (cr, name); + + cairo_translate (cr, 0, HEIGHT); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + example (cr, "clear"); + + example (cr, "source"); + example (cr, "over"); + example (cr, "in"); + example (cr, "out"); + example (cr, "atop"); + + example (cr, "dest"); + example (cr, "dest_over"); + example (cr, "dest_in"); + example (cr, "dest_out"); + example (cr, "dest_atop"); + + example (cr, "xor"); + example (cr, "add"); + example (cr, "saturate"); + + example (cr, "multiply"); + example (cr, "screen"); + example (cr, "overlay"); + example (cr, "darken"); + example (cr, "lighten"); + example (cr, "color_dodge"); + example (cr, "color_burn"); + example (cr, "hard_light"); + example (cr, "soft_light"); + example (cr, "difference"); + example (cr, "exclusion"); + example (cr, "hsl_hue"); + example (cr, "hsl_saturation"); + example (cr, "hsl_color"); + example (cr, "hsl_luminosity"); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (operator_www, + "Operator samples from https://cairographics.org/operators/", + "operator", /* keywords */ + NULL, /* requirements */ + WIDTH * 2, HEIGHT * OPERATORS_COUNT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/operator.c b/local/recipes/libs/cairo/source/test/operator.c new file mode 100644 index 0000000000..666fcafd6a --- /dev/null +++ b/local/recipes/libs/cairo/source/test/operator.c @@ -0,0 +1,65 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +#define N_OPERATORS (CAIRO_OPERATOR_SATURATE + 1) +#define SIZE 10 +#define PAD 3 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + unsigned int n; + + cairo_translate (cr, PAD, PAD); + + for (n = 0; n < N_OPERATORS; n++) { + cairo_reset_clip (cr); + cairo_rectangle (cr, 0, 0, SIZE, SIZE); + cairo_clip (cr); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_rectangle (cr, 0, 0, SIZE-PAD, SIZE-PAD); + cairo_fill (cr); + + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_set_operator (cr, n); + cairo_rectangle (cr, PAD, PAD, SIZE-PAD, SIZE-PAD); + cairo_fill (cr); + + cairo_translate (cr, SIZE+PAD, 0); + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (operator, + "Tests using set_operator()", + "operator", /* keywords */ + NULL, /* requirements */ + (SIZE+PAD) * N_OPERATORS + PAD, SIZE + 2*PAD, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/outline-tolerance.c b/local/recipes/libs/cairo/source/test/outline-tolerance.c new file mode 100644 index 0000000000..6453f5c965 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/outline-tolerance.c @@ -0,0 +1,52 @@ +/* + * Copyright © 2012 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +/* An assertion failure found by Rico Tzschichholz */ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_paint (cr); + cairo_set_source_rgb (cr, 1, 0, 0); + + cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER); + cairo_set_line_width (cr, 200); + cairo_set_miter_limit (cr, 1.5); + cairo_rectangle (cr, 100, 25, 1000, 0); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (outline_tolerance, + "Rectangle drawn incorrectly when it has zero height and miter limit greater than 1.414", + "stroke", /* keywords */ + NULL, /* requirements */ + 100, 50, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/over-above-source.c b/local/recipes/libs/cairo/source/test/over-above-source.c new file mode 100644 index 0000000000..7191c8da33 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/over-above-source.c @@ -0,0 +1,72 @@ +/* + * Copyright © 2007 Red Hat, Inc. + * + * 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: Carl D. Worth + */ + +#include "cairo-test.h" + +#define SIZE 40 +#define PAD 2 +#define WIDTH (PAD + SIZE + PAD) +#define HEIGHT WIDTH + +/* This test is designed to explore the interactions of "native" and + * "fallback" objects. For the ps surface, OVER with non-1.0 opacity + * will be a fallback while SOURCE will be native. For the pdf + * surface, it's the reverse where OVER is native while SOURCE is a + * fallback. */ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_translate (cr, PAD, PAD); + + /* A red triangle with SOURCE */ + cairo_move_to (cr, SIZE / 2, SIZE / 2); + cairo_rel_line_to (cr, SIZE / 2, 0); + cairo_rel_line_to (cr, -SIZE / 2, SIZE / 2); + cairo_close_path (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgba (cr, 1., 0., 0., 0.5); /* 50% red */ + + cairo_fill (cr); + + /* A green circle with OVER */ + cairo_arc (cr, SIZE / 2, SIZE / 2, SIZE / 4, 0., 2. * M_PI); + + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_set_source_rgba (cr, 0., 1., 0., 0.5); /* 50% green */ + + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (over_above_source, + "A simple test drawing a circle with OVER after a triangle drawn with SOURCE", + "operator", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/over-around-source.c b/local/recipes/libs/cairo/source/test/over-around-source.c new file mode 100644 index 0000000000..531eda8047 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/over-around-source.c @@ -0,0 +1,83 @@ +/* + * Copyright © 2007 Red Hat, Inc. + * + * 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: Carl D. Worth + */ + +#include "cairo-test.h" + +#define SIZE 40 +#define PAD 2 +#define WIDTH (PAD + SIZE + PAD) +#define HEIGHT WIDTH + +/* This test is designed to explore the interactions of "native" and + * "fallback" objects. For the ps surface, OVER with non-1.0 opacity + * will be a fallback while SOURCE will be native. For the pdf + * surface, it's the reverse where OVER is native while SOURCE is a + * fallback. */ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_translate (cr, PAD, PAD); + + /* A green triangle with OVER */ + cairo_move_to (cr, SIZE / 5, SIZE / 5); + cairo_rel_line_to (cr, SIZE / 2, 0); + cairo_rel_line_to (cr, -SIZE / 2, SIZE / 2); + cairo_close_path (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_set_source_rgba (cr, 0., 1., 0., 0.5); /* 50% green */ + + cairo_fill (cr); + + /* A red circle with SOURCE */ + cairo_arc (cr, SIZE / 2, SIZE / 2, SIZE / 4, 0., 2. * M_PI); + + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgba (cr, 1., 0., 0., 0.5); /* 50% red */ + + cairo_fill (cr); + + /* Another green triangle with OVER */ + cairo_move_to (cr, SIZE / 2, SIZE / 2); + cairo_rel_line_to (cr, SIZE / 2, 0); + cairo_rel_line_to (cr, -SIZE / 2, SIZE / 2); + cairo_close_path (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_set_source_rgba (cr, 0., 1., 0., 0.5); /* 50% green */ + + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (over_around_source, + "A simple test drawing a triangle with SOURCE between two circles drawn with OVER", + "operator", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/over-below-source.c b/local/recipes/libs/cairo/source/test/over-below-source.c new file mode 100644 index 0000000000..7fe5bd8898 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/over-below-source.c @@ -0,0 +1,72 @@ +/* + * Copyright © 2007 Red Hat, Inc. + * + * 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: Carl D. Worth + */ + +#include "cairo-test.h" + +#define SIZE 40 +#define PAD 2 +#define WIDTH (PAD + SIZE + PAD) +#define HEIGHT WIDTH + +/* This test is designed to explore the interactions of "native" and + * "fallback" objects. For the ps surface, OVER with non-1.0 opacity + * will be a fallback while SOURCE will be native. For the pdf + * surface, it's the reverse where OVER is native while SOURCE is a + * fallback. */ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_translate (cr, PAD, PAD); + + /* A green circle with OVER */ + cairo_arc (cr, SIZE / 2, SIZE / 2, SIZE / 4, 0., 2. * M_PI); + + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_set_source_rgba (cr, 0., 1., 0., 0.5); /* 50% green */ + + cairo_fill (cr); + + /* A red triangle with SOURCE */ + cairo_move_to (cr, SIZE / 2, SIZE / 2); + cairo_line_to (cr, SIZE, SIZE / 2); + cairo_line_to (cr, SIZE / 2, SIZE); + cairo_close_path (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgba (cr, 1., 0., 0., 0.5); /* 50% red */ + + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (over_below_source, + "A simple test drawing a circle with OVER before a triangle drawn with SOURCE", + "operator", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/over-between-source.c b/local/recipes/libs/cairo/source/test/over-between-source.c new file mode 100644 index 0000000000..ffb657208e --- /dev/null +++ b/local/recipes/libs/cairo/source/test/over-between-source.c @@ -0,0 +1,83 @@ +/* + * Copyright © 2007 Red Hat, Inc. + * + * 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: Carl D. Worth + */ + +#include "cairo-test.h" + +#define SIZE 40 +#define PAD 2 +#define WIDTH (PAD + SIZE + PAD) +#define HEIGHT WIDTH + +/* This test is designed to explore the interactions of "native" and + * "fallback" objects. For the ps surface, OVER with non-1.0 opacity + * will be a fallback while SOURCE will be native. For the pdf + * surface, it's the reverse where OVER is native while SOURCE is a + * fallback. */ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_translate (cr, PAD, PAD); + + /* A red triangle with SOURCE */ + cairo_move_to (cr, SIZE / 5, SIZE / 5); + cairo_rel_line_to (cr, SIZE / 2, 0); + cairo_rel_line_to (cr, -SIZE / 2, SIZE / 2); + cairo_close_path (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgba (cr, 1., 0., 0., 0.5); /* 50% red */ + + cairo_fill (cr); + + /* A green circle with OVER */ + cairo_arc (cr, SIZE / 2, SIZE / 2, SIZE / 4, 0., 2. * M_PI); + + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_set_source_rgba (cr, 0., 1., 0., 0.5); /* 50% green */ + + cairo_fill (cr); + + /* Another red triangle with SOURCE */ + cairo_move_to (cr, SIZE / 2, SIZE / 2); + cairo_rel_line_to (cr, SIZE / 2, 0); + cairo_rel_line_to (cr, -SIZE / 2, SIZE / 2); + cairo_close_path (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgba (cr, 1., 0., 0., 0.5); /* 50% red */ + + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (over_between_source, + "A simple test drawing a circle with OVER between two triangles drawn with SOURCE", + "operator", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/overflow.c b/local/recipes/libs/cairo/source/test/overflow.c new file mode 100644 index 0000000000..cc07541113 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/overflow.c @@ -0,0 +1,214 @@ +/* + * Copyright © 2021 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 + +/* Uncomment to enable faulty test data in order to force a + * failure. This allows the error logging path to be tested. + */ +/* #define FORCE_FAILURE 1 */ + +struct test_data { + uint64_t a; + uint64_t b; + uint64_t result; + cairo_bool_t overflow; +}; + +#if SIZEOF_SIZE_T == 4 +static const struct test_data add_32bit_test_data[] = { + { 0x00000000, 0x00000000, 0x00000000, 0 }, + { 0x00000001, 0x00000000, 0x00000001, 0 }, + { 0x00000000, 0x00000001, 0x00000001, 0 }, + { 0xffffffff, 0x00000001, 0x00000000, 1 }, + { 0x00000001, 0xffffffff, 0x00000000, 1 }, + { 0xfffffffe, 0x00000001, 0xffffffff, 0 }, + { 0x00000001, 0xfffffffe, 0xffffffff, 0 }, + { 0x12345678, 0x98765432, 0xaaaaaaaa, 0 }, + { 0x80000000, 0x80000000, 0x00000000, 1 }, + +#if FORCE_FAILURE + { 0x00000001, 0x00000002, 0x00000004, 1 }, +#endif +}; + +static const struct test_data mul_32bit_test_data[] = { + { 0x00000000, 0x00000000, 0x00000000, 0 }, + { 0x0000ffff, 0x0000ffff, 0xfffe0001, 0 }, + { 0x00010000, 0x00010000, 0x00000000, 1 }, + { 0x00000002, 0x80000000, 0x00000000, 1 }, + { 0x80000000, 0x00000002, 0x00000000, 1 }, + { 0xffffffff, 0x00000001, 0xffffffff, 0 }, +}; +#endif + +#if SIZEOF_SIZE_T == 8 +static const struct test_data add_64bit_test_data[] = { + { 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0 }, + { 0x0000000000000001, 0x0000000000000000, 0x0000000000000001, 0 }, + { 0x0000000000000000, 0x0000000000000001, 0x0000000000000001, 0 }, + { 0xffffffffffffffff, 0x0000000000000001, 0x0000000000000000, 1 }, + { 0x0000000000000001, 0xffffffffffffffff, 0x0000000000000000, 1 }, + { 0x0000000000000001, 0xfffffffffffffffe, 0xffffffffffffffff, 0 }, + { 0xfffffffffffffffe, 0x0000000000000001, 0xffffffffffffffff, 0 }, + { 0x123456789abcdef0, 0x987654320fedcbba, 0xaaaaaaaaaaaaaaaa, 0 }, + { 0x8000000000000000, 0x8000000000000000, 0x0000000000000000, 1 }, + +#if FORCE_FAILURE + { 0x0000000000000001, 0x0000000000000002, 0x0000000000000004, 1 }, +#endif +}; + +static const struct test_data mul_64bit_test_data[] = { + { 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0 }, + { 0x00000000ffffffff, 0x00000000ffffffff, 0xfffffffe00000001, 0 }, + { 0x0000000100000000, 0x0000000100000000, 0x0000000000000000, 1 }, + { 0x0000000000000002, 0x8000000000000000, 0x0000000000000000, 1 }, + { 0x8000000000000000, 0x0000000000000002, 0x0000000000000000, 1 }, + { 0xffffffffffffffff, 0x0000000000000001, 0xffffffffffffffff, 0 }, +}; +#endif + +static cairo_bool_t +check_if_result_fail (cairo_test_context_t *ctx, + size_t result, + cairo_bool_t overflow, + const struct test_data *data, + const char *func_name) +{ + int hex_digits = SIZEOF_SIZE_T * 2; + if (overflow != data->overflow || (!data->overflow && result != data->result)) { + cairo_test_log (ctx, "%s a = 0x%0*llx b = 0x%0*llx result = 0x%0*llx overflow = %d\n", + func_name, + hex_digits, + (unsigned long long)data->a, + hex_digits, + (unsigned long long)data->b, + hex_digits, + (unsigned long long)result, + overflow); + if (data->overflow) + cairo_test_log (ctx, "EXPECTED overflow = 1\n"); + else + cairo_test_log (ctx, "EXPECTED result = 0x%0*llx overflow = 0\n", + hex_digits, + (unsigned long long)data->result); + return TRUE; + } + return FALSE; +} + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + int i; + cairo_bool_t overflow; + size_t result; + +#if SIZEOF_SIZE_T == 4 + const struct test_data *add_data = add_32bit_test_data; + int num_add_tests = ARRAY_LENGTH(add_32bit_test_data); + const struct test_data *mul_data = mul_32bit_test_data; + int num_mul_tests = ARRAY_LENGTH(mul_32bit_test_data); +#elif SIZEOF_SIZE_T == 8 + const struct test_data *add_data = add_64bit_test_data; + int num_add_tests = ARRAY_LENGTH(add_64bit_test_data); + const struct test_data *mul_data = mul_64bit_test_data; + int num_mul_tests = ARRAY_LENGTH(mul_64bit_test_data); +#else + cairo_test_log (ctx, "sizeof(size_t) = %lld is not supported by this test\n", + (unsigned long long)sizeof(size_t)); + return CAIRO_TEST_UNTESTED; +#endif + + /* First check the fallback versions of the overflow functions. */ + for (i = 0; i < num_add_tests; i++) { + const struct test_data *data = &add_data[i]; + overflow = _cairo_fallback_add_size_t_overflow (data->a, data->b, &result); + if (check_if_result_fail (ctx, + result, + overflow, + data, + "_cairo_fallback_add_size_t_overflow")) + { + return CAIRO_TEST_FAILURE; + } + } + + for (i = 0; i < num_mul_tests; i++) { + const struct test_data *data = &mul_data[i]; + overflow = _cairo_fallback_mul_size_t_overflow (data->a, data->b, &result); + if (check_if_result_fail (ctx, + result, + overflow, + data, + "_cairo_fallback_mul_size_t_overflow")) + { + return CAIRO_TEST_FAILURE; + } + } + /* Next check the compiler builtins (if available, otherwise the + * fallback versions are tested again). This is to ensure the fallback version + * produces identical results to the compiler builtins. + */ + for (i = 0; i < num_add_tests; i++) { + const struct test_data *data = &add_data[i]; + overflow = _cairo_add_size_t_overflow (data->a, data->b, &result); + if (check_if_result_fail (ctx, + result, + overflow, + data, + "_cairo_add_size_t_overflow")) + { + return CAIRO_TEST_FAILURE; + } + } + + for (i = 0; i < num_mul_tests; i++) { + const struct test_data *data = &mul_data[i]; + overflow = _cairo_mul_size_t_overflow (data->a, data->b, &result); + if (check_if_result_fail (ctx, + result, + overflow, + data, + "_cairo_mul_size_t_overflow")) + { + return CAIRO_TEST_FAILURE; + } + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (overflow, + "Test the _cairo_*_size_t_overflow functions.", + "memory", /* keywords */ + NULL, /* requirements */ + 0, 0, + preamble, NULL) diff --git a/local/recipes/libs/cairo/source/test/overlapping-boxes.c b/local/recipes/libs/cairo/source/test/overlapping-boxes.c new file mode 100644 index 0000000000..92211ee069 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/overlapping-boxes.c @@ -0,0 +1,96 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +/* Not strictly overlapping, but it does highlight the error in + * an optimisation of fill-box handling that I frequently am + * tempted to write. + */ + +#include "cairo-test.h" + +#define WIDTH (20) +#define HEIGHT (20) + +static void +border (cairo_t *cr) +{ + cairo_rectangle (cr, 1, 1, 8, 8); + cairo_rectangle (cr, 1.25, 1.25, 7.5, 7.5); + cairo_rectangle (cr, 1.75, 1.75, 6.5, 6.5); + cairo_rectangle (cr, 2, 2, 6, 6); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + border (cr); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_fill (cr); + + cairo_translate (cr, 10, 0); + + border (cr); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_fill (cr); + + cairo_translate (cr, 0, 10); + + cairo_rectangle (cr, 0, 0, 10, 10); + cairo_clip (cr); + + border (cr); + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_set_operator (cr, CAIRO_OPERATOR_IN); + cairo_fill (cr); + + cairo_reset_clip (cr); + + cairo_translate (cr, -10, 0); + + cairo_rectangle (cr, 0, 0, 10, 10); + cairo_clip (cr); + + border (cr); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (overlapping_boxes, + "A sub-pixel double border to highlight the danger in an easy optimisation", + "fill", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/overlapping-dash-caps.c b/local/recipes/libs/cairo/source/test/overlapping-dash-caps.c new file mode 100644 index 0000000000..f7ba248c2f --- /dev/null +++ b/local/recipes/libs/cairo/source/test/overlapping-dash-caps.c @@ -0,0 +1,67 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +#define SIZE 100 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + double dashes1[] = {20, 10}; + double dashes2[] = {10, 1}; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_set_line_width (cr, 15); + + cairo_set_dash (cr, dashes1, 2, 0); + cairo_new_sub_path (cr); + cairo_arc (cr, SIZE/2, SIZE/2, SIZE/2-10, 0, 2*M_PI); + + cairo_set_source_rgba (cr, 1, 0, 0, 0.5); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + cairo_stroke (cr); + + cairo_set_dash (cr, dashes2, 2, 0); + cairo_new_sub_path (cr); + cairo_arc (cr, SIZE/2, SIZE/2, SIZE/4-5, 0, 2*M_PI); + + cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); + cairo_set_source_rgba (cr, 0, 1, 0, 0.5); + cairo_stroke (cr); + + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (overlapping_dash_caps, + "Test intersections between neighbouring dash segments", + "overlap, dash", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/overlapping-glyphs.c b/local/recipes/libs/cairo/source/test/overlapping-glyphs.c new file mode 100644 index 0000000000..93067abc7c --- /dev/null +++ b/local/recipes/libs/cairo/source/test/overlapping-glyphs.c @@ -0,0 +1,123 @@ +/* + * Copyright © 2009 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +#include + +#define TEXT_SIZE 12 +#define HEIGHT (TEXT_SIZE + 4) +#define WIDTH 50 + +#define MAX_GLYPHS 80 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_glyph_t glyphs_stack[MAX_GLYPHS], *glyphs; + const char *cairo = "Cairo"; + const char *giza = "Giza"; + cairo_text_extents_t cairo_extents; + cairo_text_extents_t giza_extents; + int count, num_glyphs; + double x0, y0; + + /* We draw in the default black, so paint white first. */ + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (cr, TEXT_SIZE); + + /* We want to overlap two strings, so compute overlapping glyphs. */ + + cairo_text_extents (cr, cairo, &cairo_extents); + cairo_text_extents (cr, giza, &giza_extents); + + x0 = WIDTH/2. - (cairo_extents.width/2. + cairo_extents.x_bearing); + y0 = HEIGHT/2. - (cairo_extents.height/2. + cairo_extents.y_bearing); + glyphs = glyphs_stack; + count = MAX_GLYPHS; + cairo_scaled_font_text_to_glyphs (cairo_get_scaled_font (cr), + x0, y0, + cairo, strlen (cairo), + &glyphs, &count, + NULL, NULL, + NULL); + assert (glyphs == glyphs_stack); + num_glyphs = count; + + x0 = WIDTH/2. - (giza_extents.width/2. + giza_extents.x_bearing); + y0 = HEIGHT/2. - (giza_extents.height/2. + giza_extents.y_bearing); + glyphs = glyphs_stack + count; + count = MAX_GLYPHS - count; + cairo_scaled_font_text_to_glyphs (cairo_get_scaled_font (cr), + x0, y0, + giza, strlen (giza), + &glyphs, &count, + NULL, NULL, + NULL); + assert (glyphs == glyphs_stack + num_glyphs); + glyphs = glyphs_stack; + num_glyphs += count; + + cairo_set_source_rgba (cr, 0, 0, 0, .5); /* translucent black, gray! */ + cairo_show_glyphs (cr, glyphs, num_glyphs); + + /* and compare with filling */ + cairo_translate (cr, 0, HEIGHT); + cairo_glyph_path (cr, glyphs, num_glyphs); + cairo_fill (cr); + + /* switch to using an unbounded operator for added complexity */ + cairo_set_operator (cr, CAIRO_OPERATOR_IN); + + cairo_translate (cr, WIDTH, -HEIGHT); + cairo_save (cr); + cairo_rectangle (cr, 0, 0, WIDTH, HEIGHT); + cairo_clip (cr); + cairo_show_glyphs (cr, glyphs, num_glyphs); + cairo_restore (cr); + + cairo_translate (cr, 0, HEIGHT); + cairo_save (cr); + cairo_rectangle (cr, 0, 0, WIDTH, HEIGHT); + cairo_clip (cr); + cairo_glyph_path (cr, glyphs, num_glyphs); + cairo_fill (cr); + cairo_restore (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (overlapping_glyphs, + "Test handing of overlapping glyphs", + "text, glyphs", /* keywords */ + NULL, /* requirements */ + 2 * WIDTH, 2 * HEIGHT, + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/paint-clip-fill.c b/local/recipes/libs/cairo/source/test/paint-clip-fill.c new file mode 100644 index 0000000000..5a9e24ffb2 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/paint-clip-fill.c @@ -0,0 +1,106 @@ +/* + * Copyright 2011 SCore Corporation + * + * 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: Taekyun Kim + */ + +#include "cairo-test.h" + +static void +rounded_rectangle(cairo_t *cr, + double x, double y, + double width, double height, + double radius) +{ + cairo_move_to (cr, x, y + radius); + cairo_line_to (cr, x, y + height - radius); + cairo_curve_to (cr, x, y + height - radius/2.0, + x + radius/2.0, y + height, + x + radius, y + height); + cairo_line_to (cr, x + width - radius, y + height); + cairo_curve_to (cr, x + width - radius/2.0, y + height, + x + width, y + height - radius/2.0, + x + width, y + height - radius); + cairo_line_to (cr, x + width, y + radius); + cairo_curve_to (cr, x + width, y + radius/2.0, + x + width - radius/2.0, y, + x + width - radius, y); + cairo_line_to (cr, x + radius, y); + cairo_curve_to (cr, x + radius/2.0, y, x, y + radius/2.0, x, y + radius); + cairo_close_path(cr); +} + +static cairo_test_status_t +draw_mono (cairo_t *cr, int width, int height) +{ + cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0); + cairo_paint(cr); + + cairo_rectangle(cr, 20, 20, 60, 60); + cairo_clip(cr); + + rounded_rectangle(cr, 0, 0, 100, 100, 10); + cairo_clip(cr); + + cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 1.0); + cairo_set_operator(cr, CAIRO_OPERATOR_OVER); + cairo_paint(cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +draw_aa (cairo_t *cr, int width, int height) +{ + cairo_set_antialias(cr, CAIRO_ANTIALIAS_DEFAULT); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0); + cairo_paint(cr); + + cairo_rectangle(cr, 20, 20, 60, 60); + cairo_clip(cr); + + rounded_rectangle(cr, 0, 0, 100, 100, 10); + cairo_clip(cr); + + cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 1.0); + cairo_set_operator(cr, CAIRO_OPERATOR_OVER); + cairo_paint(cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (paint_clip_fill_mono, + "Test reduction of a paint with a clip", + "paint, clip", /* keywords */ + NULL, /* requirements */ + 100, 100, + NULL, draw_mono) +CAIRO_TEST (paint_clip_fill_aa, + "Test reduction of a paint with a clip", + "paint, clip", /* keywords */ + NULL, /* requirements */ + 100, 100, + NULL, draw_aa) diff --git a/local/recipes/libs/cairo/source/test/paint-repeat.c b/local/recipes/libs/cairo/source/test/paint-repeat.c new file mode 100644 index 0000000000..c48d84c0e2 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/paint-repeat.c @@ -0,0 +1,61 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface; + uint32_t data[16] = { + 0xffffffff, 0xffffffff, 0xffff0000, 0xffff0000, + 0xffffffff, 0xffffffff, 0xffff0000, 0xffff0000, + + 0xff00ff00, 0xff00ff00, 0xff0000ff, 0xff0000ff, + 0xff00ff00, 0xff00ff00, 0xff0000ff, 0xff0000ff + }; + + surface = cairo_image_surface_create_for_data ((unsigned char *) data, + CAIRO_FORMAT_RGB24, 4, 4, 16); + + /* We use a non-zero offset larger than the source surface size to + * stress cairo out a bit more. */ + cairo_set_source_surface (cr, surface, 10, 10); + cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); + cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT); + cairo_paint (cr); + + cairo_surface_finish (surface); /* data will go out of scope */ + cairo_surface_destroy (surface); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (paint_repeat, + "Test calls to cairo_paint with a repeating source surface pattern", + "paint", /* keywords */ + NULL, /* requirements */ + 8, 8, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/paint-source-alpha.c b/local/recipes/libs/cairo/source/test/paint-source-alpha.c new file mode 100644 index 0000000000..cb2d488ca5 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/paint-source-alpha.c @@ -0,0 +1,63 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface; + uint32_t data[16] = { + 0x80808080, 0x80808080, 0x80800000, 0x80800000, + 0x80808080, 0x80808080, 0x80800000, 0x80800000, + + 0x80008000, 0x80008000, 0x80000080, 0x80000080, + 0x80008000, 0x80008000, 0x80000080, 0x80000080 + }; + + surface = cairo_image_surface_create_for_data ((unsigned char *) data, + CAIRO_FORMAT_ARGB32, 4, 4, 16); + + cairo_test_paint_checkered (cr); + + cairo_scale (cr, 4, 4); + + cairo_set_source_surface (cr, surface, 2 , 2); + cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); + cairo_paint (cr); + + cairo_surface_finish (surface); /* data will go out of scope */ + cairo_surface_destroy (surface); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (paint_source_alpha, + "Simple test of cairo_paint with a source surface with non-opaque alpha", + "paint, alpha", /* keywords */ + NULL, /* requirements */ + 32, 32, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/paint-with-alpha-group-clip.c b/local/recipes/libs/cairo/source/test/paint-with-alpha-group-clip.c new file mode 100644 index 0000000000..e1e438330d --- /dev/null +++ b/local/recipes/libs/cairo/source/test/paint-with-alpha-group-clip.c @@ -0,0 +1,60 @@ +/* + * Copyright © 2013 Adrian Johnson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Adrian Johnson + */ + +/* + * This attempts to exercise the bug found in + * + * https://bugs.launchpad.net/inkscape/+bug/1258265 + */ + + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_push_group (cr); + cairo_push_group (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + cairo_pop_group_to_source (cr); + cairo_paint_with_alpha (cr, 0.25); + cairo_pop_group_to_source (cr); + cairo_rectangle (cr, 5, 5, 20, 20); + cairo_clip (cr); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (paint_with_alpha_group_clip, + "Test paint with alpha and clipping", + "paint alpha clip group record", /* keywords */ + NULL, /* requirements */ + 30, 30, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/paint-with-alpha.c b/local/recipes/libs/cairo/source/test/paint-with-alpha.c new file mode 100644 index 0000000000..8daa935f7d --- /dev/null +++ b/local/recipes/libs/cairo/source/test/paint-with-alpha.c @@ -0,0 +1,148 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +static uint32_t data[16] = { + 0xffffffff, 0xffffffff, 0xffff0000, 0xffff0000, + 0xffffffff, 0xffffffff, 0xffff0000, 0xffff0000, + + 0xff00ff00, 0xff00ff00, 0xff0000ff, 0xff0000ff, + 0xff00ff00, 0xff00ff00, 0xff0000ff, 0xff0000ff +}; +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface; + + surface = cairo_image_surface_create_for_data ((unsigned char *) data, + CAIRO_FORMAT_RGB24, 4, 4, 16); + + cairo_test_paint_checkered (cr); + + cairo_scale (cr, 4, 4); + + cairo_set_source_surface (cr, surface, 2 , 2); + cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); + cairo_paint_with_alpha (cr, 0.5); + + cairo_surface_finish (surface); /* data will go out of scope */ + cairo_surface_destroy (surface); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +draw_solid_clip (cairo_t *cr, int width, int height) +{ + cairo_test_paint_checkered (cr); + + cairo_rectangle (cr, 2.5, 2.5, 27, 27); + cairo_clip (cr); + + cairo_set_source_rgb (cr, 1., 0.,0.); + cairo_paint_with_alpha (cr, 0.5); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +draw_clip (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface; + + surface = cairo_image_surface_create_for_data ((unsigned char *) data, + CAIRO_FORMAT_RGB24, 4, 4, 16); + + cairo_test_paint_checkered (cr); + + cairo_rectangle (cr, 10.5, 10.5, 11, 11); + cairo_clip (cr); + + cairo_scale (cr, 4, 4); + + cairo_set_source_surface (cr, surface, 2 , 2); + cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); + cairo_paint_with_alpha (cr, 0.5); + + cairo_surface_finish (surface); /* data will go out of scope */ + cairo_surface_destroy (surface); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +draw_clip_mask (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface; + + surface = cairo_image_surface_create_for_data ((unsigned char *) data, + CAIRO_FORMAT_RGB24, 4, 4, 16); + + cairo_test_paint_checkered (cr); + + cairo_move_to (cr, 16, 5); + cairo_line_to (cr, 5, 16); + cairo_line_to (cr, 16, 27); + cairo_line_to (cr, 27, 16); + cairo_clip (cr); + + cairo_scale (cr, 4, 4); + + cairo_set_source_surface (cr, surface, 2 , 2); + cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); + cairo_paint_with_alpha (cr, 0.5); + + cairo_surface_finish (surface); /* data will go out of scope */ + cairo_surface_destroy (surface); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (paint_with_alpha, + "Simple test of cairo_paint_with_alpha", + "paint, alpha", /* keywords */ + NULL, /* requirements */ + 32, 32, + NULL, draw) +CAIRO_TEST (paint_with_alpha_solid_clip, + "Simple test of cairo_paint_with_alpha+unaligned clip", + "paint, alpha, clip", /* keywords */ + NULL, /* requirements */ + 32, 32, + NULL, draw_solid_clip) +CAIRO_TEST (paint_with_alpha_clip, + "Simple test of cairo_paint_with_alpha+unaligned clip", + "paint, alpha, clip", /* keywords */ + NULL, /* requirements */ + 32, 32, + NULL, draw_clip) +CAIRO_TEST (paint_with_alpha_clip_mask, + "Simple test of cairo_paint_with_alpha+unaligned clip", + "paint, alpha, clip", /* keywords */ + NULL, /* requirements */ + 32, 32, + NULL, draw_clip_mask) diff --git a/local/recipes/libs/cairo/source/test/paint.c b/local/recipes/libs/cairo/source/test/paint.c new file mode 100644 index 0000000000..c5fd648e35 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/paint.c @@ -0,0 +1,48 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_paint (cr); + + cairo_translate (cr, 2, 2); + cairo_scale (cr, 0.5, 0.5); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (paint, + "Test calls to cairo_paint", + "paint", /* keywords */ + NULL, /* requirements */ + 8, 8, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/partial-clip-text.c b/local/recipes/libs/cairo/source/test/partial-clip-text.c new file mode 100644 index 0000000000..4d8bae077b --- /dev/null +++ b/local/recipes/libs/cairo/source/test/partial-clip-text.c @@ -0,0 +1,120 @@ +/* + * Copyright 2010 Igor Nikitin + * + * 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: Igor Nikitin + */ + +#include "cairo-test.h" + +#define HEIGHT 15 +#define WIDTH 40 + +static void background (cairo_t *cr) +{ + cairo_set_source_rgb( cr, 0, 0, 0 ); + cairo_paint (cr); +} + +static void text (cairo_t *cr) +{ + cairo_move_to (cr, 0, 12); + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_show_text (cr, "CAIRO"); +} + +static cairo_test_status_t +top (cairo_t *cr, int width, int height) +{ + background (cr); + + cairo_rectangle (cr, 0, 0, WIDTH, 5); + cairo_clip (cr); + + text (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +bottom (cairo_t *cr, int width, int height) +{ + background (cr); + + cairo_rectangle (cr, 0, HEIGHT-5, WIDTH, 5); + cairo_clip (cr); + + text (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +left (cairo_t *cr, int width, int height) +{ + background (cr); + + cairo_rectangle (cr, 0, 0, 10, HEIGHT); + cairo_clip (cr); + + text (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +right (cairo_t *cr, int width, int height) +{ + background (cr); + + cairo_rectangle (cr, WIDTH-10, 0, 10, HEIGHT); + cairo_clip (cr); + + text (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (partial_clip_text_top, + "Tests drawing text through a single, partial clip.", + "clip, text", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, top) +CAIRO_TEST (partial_clip_text_bottom, + "Tests drawing text through a single, partial clip.", + "clip, text", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, bottom) +CAIRO_TEST (partial_clip_text_left, + "Tests drawing text through a single, partial clip.", + "clip, text", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, left) +CAIRO_TEST (partial_clip_text_right, + "Tests drawing text through a single, partial clip.", + "clip, text", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, right) diff --git a/local/recipes/libs/cairo/source/test/partial-coverage.c b/local/recipes/libs/cairo/source/test/partial-coverage.c new file mode 100644 index 0000000000..3e64d0e125 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/partial-coverage.c @@ -0,0 +1,680 @@ +/* + * Copyright 2010 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +/* Test the sampling stratagems of the rasterisers by creating pixels + * containing minute holes and seeing how close to the expected + * coverage each rasteriser approaches. + */ + +#define SIZE 64 + +#include "../src/cairo-fixed-type-private.h" +#define SAMPLE (1 << CAIRO_FIXED_FRAC_BITS) + +static uint32_t state; + +static uint32_t +hars_petruska_f54_1_random (void) +{ +#define rol(x,k) ((x << k) | (x >> (32-k))) + return state = (state ^ rol (state, 5) ^ rol (state, 24)) + 0x37798849; +#undef rol +} + +static double +uniform_random (void) +{ + return hars_petruska_f54_1_random() / (double) UINT32_MAX; +} + +/* coverage is given in [0,sample] */ +static void +compute_occupancy (uint8_t *occupancy, int coverage, int sample) +{ + int i, c; + + if (coverage < sample/2) { + memset (occupancy, 0, sample); + if (coverage == 0) + return; + + for (i = c = 0; i < sample; i++) { + if ((sample - i) * uniform_random() < coverage - c) { + occupancy[i] = 0xff; + if (++c == coverage) + return; + } + } + } else { + coverage = sample - coverage; + memset (occupancy, 0xff, sample); + if (coverage == 0) + return; + + for (i = c = 0; i < sample; i++) { + if ((sample - i) * uniform_random() < coverage - c) { + occupancy[i] = 0; + if (++c == coverage) + return; + } + } + } +} + +static cairo_test_status_t +reference (cairo_t *cr, int width, int height) +{ + int i; + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_paint (cr); + + for (i = 0; i < SIZE*SIZE; i++) { + cairo_set_source_rgba (cr, 1., 1., 1., + i / (double) (SIZE * SIZE)); + cairo_rectangle (cr, i % SIZE, i / SIZE, 1, 1); + cairo_fill (cr); + } + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +three_quarter_reference (cairo_t *cr, int width, int height) +{ + int i; + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_paint (cr); + + for (i = 0; i < SIZE*SIZE; i++) { + cairo_set_source_rgba (cr, 1., 1., 1., + .75 * i / (double) (SIZE * SIZE)); + cairo_rectangle (cr, i % SIZE, i / SIZE, 1, 1); + cairo_fill (cr); + } + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +half_reference (cairo_t *cr, int width, int height) +{ + int i; + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_paint (cr); + + for (i = 0; i < SIZE*SIZE; i++) { + cairo_set_source_rgba (cr, 1., 1., 1., + .5 * i / (double) (SIZE * SIZE)); + cairo_rectangle (cr, i % SIZE, i / SIZE, 1, 1); + cairo_fill (cr); + } + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +rectangles (cairo_t *cr, int width, int height) +{ + uint8_t *occupancy; + int i, j, channel; + + state = 0x12345678; + occupancy = xmalloc (SAMPLE*SAMPLE); + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_paint (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_ADD); + for (channel = 0; channel < 3; channel++) { + switch (channel) { + default: + case 0: cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); break; + case 1: cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); break; + case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break; + } + + for (i = 0; i < SIZE*SIZE; i++) { + int xs, ys; + + compute_occupancy (occupancy, SAMPLE*SAMPLE * i / (SIZE * SIZE), SAMPLE*SAMPLE); + + xs = i % SIZE * SAMPLE; + ys = i / SIZE * SAMPLE; + for (j = 0; j < SAMPLE*SAMPLE; j++) { + if (occupancy[j]) { + cairo_rectangle (cr, + (j % SAMPLE + xs) / (double) SAMPLE, + (j / SAMPLE + ys) / (double) SAMPLE, + 1 / (double) SAMPLE, + 1 / (double) SAMPLE); + } + } + cairo_fill (cr); + } + } + + free (occupancy); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +intersecting_quads (cairo_t *cr, int width, int height) +{ + uint8_t *occupancy; + int i, j, channel; + + state = 0x12345678; + occupancy = xmalloc (SAMPLE*SAMPLE); + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_paint (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_ADD); + for (channel = 0; channel < 3; channel++) { + switch (channel) { + default: + case 0: cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); break; + case 1: cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); break; + case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break; + } + + for (i = 0; i < SIZE*SIZE; i++) { + int xs, ys; + + compute_occupancy (occupancy, SAMPLE*SAMPLE * i / (SIZE * SIZE), SAMPLE*SAMPLE); + + xs = i % SIZE * SAMPLE; + ys = i / SIZE * SAMPLE; + for (j = 0; j < SAMPLE*SAMPLE; j++) { + if (occupancy[j]) { + cairo_move_to (cr, + (j % SAMPLE + xs) / (double) SAMPLE, + (j / SAMPLE + ys) / (double) SAMPLE); + cairo_rel_line_to (cr, 1 / (double) SAMPLE, 1 / (double) SAMPLE); + cairo_rel_line_to (cr, 0, -1 / (double) SAMPLE); + cairo_rel_line_to (cr, -1 / (double) SAMPLE, 1 / (double) SAMPLE); + cairo_close_path (cr); + } + } + cairo_fill (cr); + } + } + + free (occupancy); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +half_triangles (cairo_t *cr, int width, int height) +{ + uint8_t *occupancy; + int i, j, channel; + + state = 0x12345678; + occupancy = xmalloc (SAMPLE*SAMPLE); + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_paint (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_ADD); + for (channel = 0; channel < 3; channel++) { + switch (channel) { + default: + case 0: cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); break; + case 1: cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); break; + case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break; + } + + for (i = 0; i < SIZE*SIZE; i++) { + int xs, ys; + + compute_occupancy (occupancy, SAMPLE*SAMPLE * i / (SIZE * SIZE), SAMPLE*SAMPLE); + + xs = i % SIZE * SAMPLE; + ys = i / SIZE * SAMPLE; + for (j = 0; j < SAMPLE*SAMPLE; j++) { + if (occupancy[j]) { + int x = j % SAMPLE + xs; + int y = j / SAMPLE + ys; + cairo_move_to (cr, x / (double) SAMPLE, y / (double) SAMPLE); + cairo_line_to (cr, (x+1) / (double) SAMPLE, (y+1) / (double) SAMPLE); + cairo_line_to (cr, (x+1) / (double) SAMPLE, y / (double) SAMPLE); + cairo_close_path (cr); + } + } + cairo_fill (cr); + } + } + + free (occupancy); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +overlap_half_triangles (cairo_t *cr, int width, int height) +{ + uint8_t *occupancy; + int i, j, channel; + + state = 0x12345678; + occupancy = xmalloc (SAMPLE*SAMPLE); + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_paint (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_ADD); + for (channel = 0; channel < 3; channel++) { + switch (channel) { + default: + case 0: cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); break; + case 1: cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); break; + case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break; + } + + for (i = 0; i < SIZE*SIZE; i++) { + int xs, ys; + + compute_occupancy (occupancy, SAMPLE/2*SAMPLE/2 * i / (SIZE * SIZE), SAMPLE/2*SAMPLE/2); + + xs = i % SIZE * SAMPLE; + ys = i / SIZE * SAMPLE; + for (j = 0; j < SAMPLE/2*SAMPLE/2; j++) { + if (occupancy[j]) { + int x = 2 * (j % (SAMPLE/2)) + xs; + int y = 2 * (j / (SAMPLE/2)) + ys; + + /* Add a 4-tile composed of two overlapping triangles. + * .__.__. + * |\ /| + * | \ / | + * . x | + * | / \ | + * |/ \| + * . . + * + * Coverage should be computable as 50% (due to counter-winding). + */ + + cairo_move_to (cr, (x) / (double) SAMPLE, (y) / (double) SAMPLE); + cairo_line_to (cr, (x) / (double) SAMPLE, (y+2) / (double) SAMPLE); + cairo_line_to (cr, (x+2) / (double) SAMPLE, (y) / (double) SAMPLE); + cairo_close_path (cr); + + cairo_move_to (cr, (x) / (double) SAMPLE, (y) / (double) SAMPLE); + cairo_line_to (cr, (x+2) / (double) SAMPLE, (y) / (double) SAMPLE); + cairo_line_to (cr, (x+2) / (double) SAMPLE, (y+2) / (double) SAMPLE); + cairo_close_path (cr); + } + } + cairo_fill (cr); + } + } + + free (occupancy); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +overlap_half_triangles_eo (cairo_t *cr, int width, int height) +{ + uint8_t *occupancy; + int i, j, channel; + + state = 0x12345678; + occupancy = xmalloc (SAMPLE*SAMPLE); + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_paint (cr); + + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + + cairo_set_operator (cr, CAIRO_OPERATOR_ADD); + for (channel = 0; channel < 3; channel++) { + switch (channel) { + default: + case 0: cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); break; + case 1: cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); break; + case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break; + } + + for (i = 0; i < SIZE*SIZE; i++) { + int xs, ys; + + compute_occupancy (occupancy, SAMPLE/2*SAMPLE/2 * i / (SIZE * SIZE), SAMPLE/2*SAMPLE/2); + + xs = i % SIZE * SAMPLE; + ys = i / SIZE * SAMPLE; + for (j = 0; j < SAMPLE/2*SAMPLE/2; j++) { + if (occupancy[j]) { + int x = 2 * (j % (SAMPLE/2)) + xs; + int y = 2 * (j / (SAMPLE/2)) + ys; + + /* Add a 4-tile composed of two overlapping triangles. + * .__.__. + * |\ /| + * | \ / | + * . x | + * | / \ | + * |/ \| + * . . + * + * Coverage should be computable as 50%, due to even-odd fill rule. + */ + + cairo_move_to (cr, (x) / (double) SAMPLE, (y) / (double) SAMPLE); + cairo_line_to (cr, (x) / (double) SAMPLE, (y+2) / (double) SAMPLE); + cairo_line_to (cr, (x+2) / (double) SAMPLE, (y) / (double) SAMPLE); + cairo_close_path (cr); + + cairo_move_to (cr, (x) / (double) SAMPLE, (y) / (double) SAMPLE); + cairo_line_to (cr, (x+2) / (double) SAMPLE, (y+2) / (double) SAMPLE); + cairo_line_to (cr, (x+2) / (double) SAMPLE, (y) / (double) SAMPLE); + cairo_close_path (cr); + } + } + cairo_fill (cr); + } + } + + free (occupancy); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +overlap_three_quarter_triangles (cairo_t *cr, int width, int height) +{ + uint8_t *occupancy; + int i, j, channel; + + state = 0x12345678; + occupancy = xmalloc (SAMPLE*SAMPLE); + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_paint (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_ADD); + for (channel = 0; channel < 3; channel++) { + switch (channel) { + default: + case 0: cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); break; + case 1: cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); break; + case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break; + } + + for (i = 0; i < SIZE*SIZE; i++) { + int xs, ys; + + compute_occupancy (occupancy, SAMPLE/2*SAMPLE/2 * i / (SIZE * SIZE), SAMPLE/2*SAMPLE/2); + + xs = i % SIZE * SAMPLE; + ys = i / SIZE * SAMPLE; + for (j = 0; j < SAMPLE/2*SAMPLE/2; j++) { + if (occupancy[j]) { + int x = 2 * (j % (SAMPLE/2)) + xs; + int y = 2 * (j / (SAMPLE/2)) + ys; + + /* Add a 4-tile composed of two overlapping triangles. + * .__.__. + * |\ /| + * | \ / | + * . x | + * | / \ | + * |/ \| + * . . + * + * Coverage should be computable as 75%. + */ + + cairo_move_to (cr, (x) / (double) SAMPLE, (y) / (double) SAMPLE); + cairo_line_to (cr, (x) / (double) SAMPLE, (y+2) / (double) SAMPLE); + cairo_line_to (cr, (x+2) / (double) SAMPLE, (y) / (double) SAMPLE); + cairo_close_path (cr); + + cairo_move_to (cr, (x) / (double) SAMPLE, (y) / (double) SAMPLE); + cairo_line_to (cr, (x+2) / (double) SAMPLE, (y+2) / (double) SAMPLE); + cairo_line_to (cr, (x+2) / (double) SAMPLE, (y) / (double) SAMPLE); + cairo_close_path (cr); + } + } + cairo_fill (cr); + } + } + + free (occupancy); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +triangles (cairo_t *cr, int width, int height) +{ + uint8_t *occupancy; + int i, j, channel; + + state = 0x12345678; + occupancy = xmalloc (SAMPLE*SAMPLE); + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_paint (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_ADD); + for (channel = 0; channel < 3; channel++) { + switch (channel) { + default: + case 0: cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); break; + case 1: cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); break; + case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break; + } + + for (i = 0; i < SIZE*SIZE; i++) { + int xs, ys; + + compute_occupancy (occupancy, SAMPLE*SAMPLE * i / (SIZE * SIZE), SAMPLE*SAMPLE); + + xs = i % SIZE * SAMPLE; + ys = i / SIZE * SAMPLE; + for (j = 0; j < SAMPLE*SAMPLE; j++) { + if (occupancy[j]) { + /* Add a tile composed of two non-overlapping triangles. + * .__. + * | /| + * |/ | + * .--. + */ + int x = j % SAMPLE + xs; + int y = j / SAMPLE + ys; + + /* top-left triangle */ + cairo_move_to (cr, (x) / (double) SAMPLE, (y) / (double) SAMPLE); + cairo_line_to (cr, (x+1) / (double) SAMPLE, (y) / (double) SAMPLE); + cairo_line_to (cr, (x) / (double) SAMPLE, (y+1) / (double) SAMPLE); + cairo_close_path (cr); + + /* bottom-right triangle */ + cairo_move_to (cr, (x) / (double) SAMPLE, (y+1) / (double) SAMPLE); + cairo_line_to (cr, (x+1) / (double) SAMPLE, (y+1) / (double) SAMPLE); + cairo_line_to (cr, (x+1) / (double) SAMPLE, (y) / (double) SAMPLE); + cairo_close_path (cr); + } + } + cairo_fill (cr); + } + } + + free (occupancy); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +intersecting_triangles (cairo_t *cr, int width, int height) +{ + uint8_t *occupancy; + int i, j, channel; + + state = 0x12345678; + occupancy = xmalloc (SAMPLE*SAMPLE); + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_paint (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_ADD); + for (channel = 0; channel < 3; channel++) { + switch (channel) { + default: + case 0: cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); break; + case 1: cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); break; + case 2: cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); break; + } + + for (i = 0; i < SIZE*SIZE; i++) { + int xs, ys; + + compute_occupancy (occupancy, SAMPLE*SAMPLE * i / (SIZE * SIZE), SAMPLE*SAMPLE); + + xs = i % SIZE * SAMPLE; + ys = i / SIZE * SAMPLE; + for (j = 0; j < SAMPLE*SAMPLE; j++) { + if (occupancy[j]) { + /* Add 2 overlapping tiles in a single cell, each composed + * of two non-overlapping triangles. + * .--. .--. + * | /| |\ | + * |/ | + | \| + * .--. .--. + */ + int x = j % SAMPLE + xs; + int y = j / SAMPLE + ys; + + /* first pair of triangles, diagonal bottom-left to top-right */ + cairo_move_to (cr, (x) / (double) SAMPLE, (y) / (double) SAMPLE); + cairo_line_to (cr, (x+1) / (double) SAMPLE, (y) / (double) SAMPLE); + cairo_line_to (cr, (x) / (double) SAMPLE, (y+1) / (double) SAMPLE); + cairo_close_path (cr); + cairo_move_to (cr, (x) / (double) SAMPLE, (y+1) / (double) SAMPLE); + cairo_line_to (cr, (x+1) / (double) SAMPLE, (y+1) / (double) SAMPLE); + cairo_line_to (cr, (x+1) / (double) SAMPLE, (y) / (double) SAMPLE); + cairo_close_path (cr); + + /* second pair of triangles, diagonal top-left to bottom-right */ + cairo_move_to (cr, (x) / (double) SAMPLE, (y) / (double) SAMPLE); + cairo_line_to (cr, (x+1) / (double) SAMPLE, (y+1) / (double) SAMPLE); + cairo_line_to (cr, (x+1) / (double) SAMPLE, (y) / (double) SAMPLE); + cairo_close_path (cr); + cairo_move_to (cr, (x) / (double) SAMPLE, (y) / (double) SAMPLE); + cairo_line_to (cr, (x+1) / (double) SAMPLE, (y+1) / (double) SAMPLE); + cairo_line_to (cr, (x) / (double) SAMPLE, (y+1) / (double) SAMPLE); + cairo_close_path (cr); + } + } + cairo_fill (cr); + } + } + + free (occupancy); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (partial_coverage_rectangles, + "Check the fidelity of the rasterisation.", + "coverage, raster", /* keywords */ + "target=raster slow", /* requirements */ + SIZE, SIZE, + NULL, rectangles) + +CAIRO_TEST (partial_coverage_intersecting_quads, + "Check the fidelity of the rasterisation.", + "coverage, raster", /* keywords */ + "target=raster slow", /* requirements */ + SIZE, SIZE, + NULL, intersecting_quads) + +CAIRO_TEST (partial_coverage_intersecting_triangles, + "Check the fidelity of the rasterisation.", + "coverage, raster", /* keywords */ + "target=raster slow", /* requirements */ + SIZE, SIZE, + NULL, intersecting_triangles) +CAIRO_TEST (partial_coverage_triangles, + "Check the fidelity of the rasterisation.", + "coverage, raster", /* keywords */ + "target=raster slow", /* requirements */ + SIZE, SIZE, + NULL, triangles) +CAIRO_TEST (partial_coverage_overlap_three_quarter_triangles, + "Check the fidelity of the rasterisation.", + "coverage, raster", /* keywords */ + "target=raster slow", /* requirements */ + SIZE, SIZE, + NULL, overlap_three_quarter_triangles) +CAIRO_TEST (partial_coverage_overlap_half_triangles_eo, + "Check the fidelity of the rasterisation.", + "coverage, raster", /* keywords */ + "target=raster slow", /* requirements */ + SIZE, SIZE, + NULL, overlap_half_triangles_eo) +CAIRO_TEST (partial_coverage_overlap_half_triangles, + "Check the fidelity of the rasterisation.", + "coverage, raster", /* keywords */ + "target=raster slow", /* requirements */ + SIZE, SIZE, + NULL, overlap_half_triangles) +CAIRO_TEST (partial_coverage_half_triangles, + "Check the fidelity of the rasterisation.", + "coverage, raster", /* keywords */ + "target=raster slow", /* requirements */ + SIZE, SIZE, + NULL, half_triangles) + +CAIRO_TEST (partial_coverage_reference, + "Check the fidelity of this test.", + "coverage, raster", /* keywords */ + "target=raster", /* requirements */ + SIZE, SIZE, + NULL, reference) +CAIRO_TEST (partial_coverage_three_quarter_reference, + "Check the fidelity of this test.", + "coverage, raster", /* keywords */ + "target=raster", /* requirements */ + SIZE, SIZE, + NULL, three_quarter_reference) +CAIRO_TEST (partial_coverage_half_reference, + "Check the fidelity of this test.", + "coverage, raster", /* keywords */ + "target=raster", /* requirements */ + SIZE, SIZE, + NULL, half_reference) diff --git a/local/recipes/libs/cairo/source/test/pass-through.c b/local/recipes/libs/cairo/source/test/pass-through.c new file mode 100644 index 0000000000..17a38db995 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/pass-through.c @@ -0,0 +1,91 @@ +/* + * Copyright 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + int n; + + for (n = 0; n < 256; n++) { + cairo_set_source_rgba (cr, 1, 1, 1, n / 255.); + cairo_rectangle (cr, 0, n, 2, 1); + cairo_fill (cr); + } + for (n = 0; n < 256; n++) { + cairo_set_source_rgb (cr, n / 255., n / 255., n / 255.); + cairo_rectangle (cr, 2, n, 2, 1); + cairo_fill (cr); + } + + cairo_translate (cr, 4, 0); + + for (n = 0; n < 256; n++) { + cairo_set_source_rgba (cr, 1, 0, 0, n / 255.); + cairo_rectangle (cr, 0, n, 2, 1); + cairo_fill (cr); + } + for (n = 0; n < 256; n++) { + cairo_set_source_rgb (cr, n / 255., 0, 0); + cairo_rectangle (cr, 2, n, 2, 1); + cairo_fill (cr); + } + + cairo_translate (cr, 4, 0); + + for (n = 0; n < 256; n++) { + cairo_set_source_rgba (cr, 0, 1, 0, n / 255.); + cairo_rectangle (cr, 0, n, 2, 1); + cairo_fill (cr); + } + for (n = 0; n < 256; n++) { + cairo_set_source_rgb (cr, 0, n / 255., 0); + cairo_rectangle (cr, 2, n, 2, 1); + cairo_fill (cr); + } + + cairo_translate (cr, 4, 0); + + for (n = 0; n < 256; n++) { + cairo_set_source_rgba (cr, 0, 0, 1, n / 255.); + cairo_rectangle (cr, 0, n, 2, 1); + cairo_fill (cr); + } + for (n = 0; n < 256; n++) { + cairo_set_source_rgb (cr, 0, 0, n / 255.); + cairo_rectangle (cr, 2, n, 2, 1); + cairo_fill (cr); + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (pass_through, + "tests pixel values", + "color", /* keywords */ + NULL, /* requirements */ + 16, 256, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/path-append.c b/local/recipes/libs/cairo/source/test/path-append.c new file mode 100644 index 0000000000..bdcc63abff --- /dev/null +++ b/local/recipes/libs/cairo/source/test/path-append.c @@ -0,0 +1,81 @@ +/* + * Copyright © 2009 Jeff Muizelaar + * Copyright © 2009 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "cairo-test.h" +#include + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_matrix_t m; + int xoffset = 50; + int yoffset = 50; + + cairo_surface_t *shadow; + cairo_t *shadow_cr; + cairo_path_t *path; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_translate (cr, 130, 130); + cairo_rotate (cr, .5);//2*M_PI*angle/360); + cairo_rectangle (cr, 0, 0, 50, 100); + cairo_get_matrix (cr, &m); + + shadow = cairo_surface_create_similar (cairo_get_target (cr), + CAIRO_CONTENT_COLOR_ALPHA, + 600 - xoffset, + 600 - yoffset); + cairo_surface_set_device_offset (shadow, xoffset, yoffset); + shadow_cr = cairo_create (shadow); + cairo_surface_destroy (shadow); + + cairo_set_source_rgb (shadow_cr, 0, 1, 0); + cairo_set_matrix (shadow_cr, &m); + + path = cairo_copy_path (cr); + cairo_new_path (shadow_cr); + cairo_append_path (shadow_cr, path); + cairo_fill (shadow_cr); + cairo_path_destroy (path); + + cairo_identity_matrix (cr); + cairo_translate (cr, 10, 50); + cairo_set_source_surface (cr, cairo_get_target (shadow_cr), 0, 0); + cairo_paint (cr); + cairo_set_matrix (cr, &m); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_fill (cr); + + cairo_destroy (shadow_cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (path_append, + "Test appending path to a context, in particular to exercise a regression in 005436", + "path", /* keywords */ + NULL, /* requirements */ + 600, 600, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/path-currentpoint.c b/local/recipes/libs/cairo/source/test/path-currentpoint.c new file mode 100644 index 0000000000..ccd44b1c86 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/path-currentpoint.c @@ -0,0 +1,89 @@ +/* + * Copyright © 2014 Google, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "cairo-test.h" + +#include + +static void +assert_point (cairo_t *cr, double expected_x, double expected_y) { + double x, y; + assert (cairo_has_current_point (cr)); + cairo_get_current_point (cr, &x, &y); + assert (x == expected_x); + assert (y == expected_y); +} + +static void +assert_point_maintained (cairo_t *cr, double expected_x, double expected_y) { + cairo_path_t *path; + + assert_point (cr, expected_x, expected_y); + + path = cairo_copy_path (cr); + + cairo_new_path (cr); + cairo_rectangle (cr, 5, 5, 10, 20); + cairo_stroke (cr); + + cairo_new_path (cr); + cairo_append_path (cr, path); + cairo_path_destroy (path); + + assert_point (cr, expected_x, expected_y); +} + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + cairo_surface_t *surface; + cairo_t *cr; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 20, 20); + cr = cairo_create (surface); + + cairo_new_path (cr); + cairo_move_to (cr, 1., 2.); + assert_point_maintained (cr, 1., 2.); + + cairo_line_to (cr, 4., 5.); + cairo_move_to (cr, 2., 1.); + assert_point_maintained (cr, 2., 1.); + + cairo_move_to (cr, 5, 5); + cairo_arc (cr, 5, 5, 10, 0, M_PI / 3); + cairo_close_path (cr); + assert_point_maintained (cr, 5, 5); + + cairo_destroy (cr); + cairo_surface_destroy (surface); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (path_currentpoint, + "Test save/restore path maintains current point", + "api", /* keywords */ + NULL, /* requirements */ + 0, 0, + preamble, NULL) diff --git a/local/recipes/libs/cairo/source/test/path-precision.c b/local/recipes/libs/cairo/source/test/path-precision.c new file mode 100644 index 0000000000..dc9371c5b7 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/path-precision.c @@ -0,0 +1,129 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + * + * Based on an example by Dirk "krit" Schulze found during WebKit integration. + */ + + /* Copyright (C) 2021 Heiko Lewin + * Added error margin for point comparisons */ + +#include "cairo-test.h" +#include "cairo-fixed-type-private.h" + +/* we know that this is an inherent limitation in cairo */ +#define FAIL CAIRO_TEST_XFAILURE + +/* Test the idempotency of path construction and copying */ + + +/* The error to be expected from double<->fixed conversions */ +#define EXPECTED_ERROR (0.5 / (1< EXPECTED_ERROR) { + return 1; + } + } + return 0; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_path_data_t path_data[] = { + { { CAIRO_PATH_MOVE_TO, 2 }, }, + { .point={ 95.000000, 40.000000 }, }, + + { { CAIRO_PATH_LINE_TO, 2 }, }, + { .point={ 94.960533, 41.255810 }, }, + + { { CAIRO_PATH_LINE_TO, 2 }, }, + { .point={ 94.842293, 42.50666 }, }, + + { { CAIRO_PATH_LINE_TO, 2 }, }, + { .point={ 94.645744, 43.747627 }, }, + + { { CAIRO_PATH_LINE_TO, 2 }, }, + { .point={ 94.371666, 44.973797 }, }, + }; + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_path_t path, *path_copy; + int i, j, n; + cairo_test_status_t result = CAIRO_TEST_SUCCESS; + + path.status = CAIRO_STATUS_SUCCESS; + path.num_data = ARRAY_LENGTH (path_data); + path.data = path_data; + + cairo_new_path (cr); + cairo_append_path (cr, &path); + path_copy = cairo_copy_path (cr); + + if (path_copy->status) + return cairo_test_status_from_status (ctx, path_copy->status); + + for (i = j = n = 0; + i < path.num_data && j < path_copy->num_data; + i += path.data[i].header.length, + j += path_copy->data[j].header.length, + n++) + { + const cairo_path_data_t *src, *dst; + + src = &path.data[i]; + dst = &path_copy->data[j]; + + if (src->header.type != dst->header.type) { + cairo_test_log (ctx, + "Paths differ in header type after %d operations.\n" + "Expected path operation %d, found %d.\n", + n, src->header.type, dst->header.type); + result = FAIL; + break; + } + + if (compare_points ((double*)&src[1].point, (double*)&dst[1].point)) { + cairo_test_log (ctx, + "Paths differ in coordinates after %d operations.\n" + "Expected point (%f, %f), found (%f, %f).\n", + n, + src[1].point.x, src[1].point.y, + dst[1].point.x, dst[1].point.y); + result = FAIL; + break; + } + } + + cairo_path_destroy (path_copy); + return result; +} + +CAIRO_TEST (path_precision, + "Check that the path append/copy is idempotent.", + "api", /* keywords */ + NULL, /* requirements */ + 0, 0, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/path-stroke-twice.c b/local/recipes/libs/cairo/source/test/path-stroke-twice.c new file mode 100644 index 0000000000..876352b0fe --- /dev/null +++ b/local/recipes/libs/cairo/source/test/path-stroke-twice.c @@ -0,0 +1,54 @@ +/* + * Copyright 2010 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +/* Exercises a bug found by alois@astro.ch: + * https://bugs.freedesktop.org/show_bug.cgi?id=26010 + * cairo_line_to optimizes away path segment + */ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_move_to (cr, 10, 10); + cairo_line_to (cr, 10, 20); + cairo_line_to (cr, 20, 30); + cairo_line_to (cr, 10, 20); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (path_stroke_twice, + "Tests stroking of a path containing a segment drawn twice", + "path, stroke", /* keywords */ + NULL, /* requirements */ + 40, 40, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/pattern-get-type.c b/local/recipes/libs/cairo/source/test/pattern-get-type.c new file mode 100644 index 0000000000..c807b14e8b --- /dev/null +++ b/local/recipes/libs/cairo/source/test/pattern-get-type.c @@ -0,0 +1,79 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +static cairo_test_status_t +preamble (cairo_test_context_t *Ctx) +{ + cairo_surface_t *surface; + cairo_pattern_t *solid_rgb, *solid_rgba, *surface_pattern, *linear, *radial, *mesh; + cairo_test_status_t result = CAIRO_TEST_SUCCESS; + + solid_rgb = cairo_pattern_create_rgb (0.0, 0.1, 0.2); + solid_rgba = cairo_pattern_create_rgba (0.3, 0.4, 0.5, 0.6); + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + 1, 1); + surface_pattern = cairo_pattern_create_for_surface (surface); + linear = cairo_pattern_create_linear (0.0, 0.0, 10.0, 10.0); + radial = cairo_pattern_create_radial (10.0, 10.0, 0.1, + 10.0, 10.0, 1.0); + mesh = cairo_pattern_create_mesh (); + + if (cairo_pattern_get_type (solid_rgb) != CAIRO_PATTERN_TYPE_SOLID) + result = CAIRO_TEST_FAILURE; + + if (cairo_pattern_get_type (solid_rgba) != CAIRO_PATTERN_TYPE_SOLID) + result = CAIRO_TEST_FAILURE; + + if (cairo_pattern_get_type (surface_pattern) != CAIRO_PATTERN_TYPE_SURFACE) + result = CAIRO_TEST_FAILURE; + + if (cairo_pattern_get_type (linear) != CAIRO_PATTERN_TYPE_LINEAR) + result = CAIRO_TEST_FAILURE; + + if (cairo_pattern_get_type (radial) != CAIRO_PATTERN_TYPE_RADIAL) + result = CAIRO_TEST_FAILURE; + + if (cairo_pattern_get_type (mesh) != CAIRO_PATTERN_TYPE_MESH) + result = CAIRO_TEST_FAILURE; + + cairo_pattern_destroy (solid_rgb); + cairo_pattern_destroy (solid_rgba); + cairo_pattern_destroy (surface_pattern); + cairo_surface_destroy (surface); + cairo_pattern_destroy (linear); + cairo_pattern_destroy (radial); + cairo_pattern_destroy (mesh); + + return result; +} + +CAIRO_TEST (pattern_get_type, + "Creating patterns of all types", + "pattern, api", /* keywords */ + NULL, /* requirements */ + 0, 0, + preamble, NULL) diff --git a/local/recipes/libs/cairo/source/test/pattern-getters.c b/local/recipes/libs/cairo/source/test/pattern-getters.c new file mode 100644 index 0000000000..49027e9130 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/pattern-getters.c @@ -0,0 +1,279 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright © 2005 Mozilla Corporation, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Mozilla Corporation not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Mozilla Corporation makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * MOZILLA CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL MOZILLA CORPORATION BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Vladimir Vukicevic + */ + +#include "cairo-test.h" +#include + +#define CHECK_SUCCESS do { \ + if (status) { \ + cairo_pattern_destroy (pat); \ + return cairo_test_status_from_status (ctx, status); \ + } \ +} while (0) + +static int +double_buf_equal (const cairo_test_context_t *ctx, double *a, double *b, int nc) +{ + int i; + for (i = 0; i < nc; i++) { + if (!CAIRO_TEST_DOUBLE_EQUALS(a[i],b[i])) { + cairo_test_log (ctx, "Error: doubles not equal: %g, %g\n", + a[i], b[i]); + return 0; + } + } + return 1; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_status_t status; + cairo_pattern_t *pat; + + /* Test pattern_get_rgba */ + { + double r, g, b, a; + pat = cairo_pattern_create_rgba (0.2, 0.3, 0.4, 0.5); + + status = cairo_pattern_get_rgba (pat, &r, &g, &b, &a); + CHECK_SUCCESS; + + if (!CAIRO_TEST_DOUBLE_EQUALS(r,0.2) || + !CAIRO_TEST_DOUBLE_EQUALS(g,0.3) || + !CAIRO_TEST_DOUBLE_EQUALS(b,0.4) || + !CAIRO_TEST_DOUBLE_EQUALS(a,0.5)) { + cairo_test_log (ctx, "Error: cairo_pattern_get_rgba returned unexpected results: %g, %g, %g, %g\n", + r, g, b, a); + cairo_pattern_destroy (pat); + return CAIRO_TEST_FAILURE; + } + + cairo_pattern_destroy (pat); + } + + /* Test pattern_get_surface */ + { + cairo_surface_t *surf; + + pat = cairo_pattern_create_for_surface (cairo_get_target (cr)); + + status = cairo_pattern_get_surface (pat, &surf); + CHECK_SUCCESS; + + if (surf != cairo_get_target (cr)) { + cairo_test_log (ctx, "Error: cairo_pattern_get_resurface returned wrong surface\n"); + cairo_pattern_destroy (pat); + return CAIRO_TEST_FAILURE; + } + + cairo_pattern_destroy (pat); + } + + /* Test get_color_stops & linear_get_points */ + { + int i; + double x0, y0, x1, y1; + double expected_values[15] = { 0.0, 0.2, 0.4, 0.2, 1.0, + 0.5, 0.4, 0.5, 0.2, 0.5, + 1.0, 0.2, 0.4, 0.5, 0.2 }; + double new_buf[15]; + + pat = cairo_pattern_create_linear (1.0, 2.0, 3.0, 4.0); + + for (i = 0; i < 3; i++) { + cairo_pattern_add_color_stop_rgba (pat, + expected_values[i*5+0], + expected_values[i*5+1], + expected_values[i*5+2], + expected_values[i*5+3], + expected_values[i*5+4]); + } + + status = cairo_pattern_get_linear_points (pat, &x0, &y0, &x1, &y1); + CHECK_SUCCESS; + + if (!CAIRO_TEST_DOUBLE_EQUALS(x0,1.0) || + !CAIRO_TEST_DOUBLE_EQUALS(y0,2.0) || + !CAIRO_TEST_DOUBLE_EQUALS(x1,3.0) || + !CAIRO_TEST_DOUBLE_EQUALS(y1,4.0)) + { + cairo_pattern_destroy (pat); + return CAIRO_TEST_FAILURE; + } + + status = cairo_pattern_get_color_stop_count (pat, &i); + CHECK_SUCCESS; + + if (i != 3) { + cairo_pattern_destroy (pat); + return CAIRO_TEST_FAILURE; + } + + for (i = 0; i < 3; i++) { + status = cairo_pattern_get_color_stop_rgba (pat, i, + &new_buf[i*5+0], + &new_buf[i*5+1], + &new_buf[i*5+2], + &new_buf[i*5+3], + &new_buf[i*5+4]); + CHECK_SUCCESS; + } + + status = cairo_pattern_get_color_stop_rgba (pat, 5, NULL, NULL, NULL, NULL, NULL); + if (status != CAIRO_STATUS_INVALID_INDEX) { + cairo_pattern_destroy (pat); + return CAIRO_TEST_FAILURE; + } + + if (!double_buf_equal (ctx, new_buf, expected_values, + ARRAY_LENGTH (expected_values))) + { + cairo_pattern_destroy (pat); + return CAIRO_TEST_FAILURE; + } + + cairo_pattern_destroy (pat); + } + + /* Test radial_get_circles */ + { + double a, b, c, d, e, f; + pat = cairo_pattern_create_radial (1, 2, 3, + 4, 5, 6); + + status = cairo_pattern_get_radial_circles (pat, &a, &b, &c, &d, &e, &f); + CHECK_SUCCESS; + + if (!CAIRO_TEST_DOUBLE_EQUALS(a,1.0) || + !CAIRO_TEST_DOUBLE_EQUALS(b,2.0) || + !CAIRO_TEST_DOUBLE_EQUALS(c,3.0) || + !CAIRO_TEST_DOUBLE_EQUALS(d,4.0) || + !CAIRO_TEST_DOUBLE_EQUALS(e,5.0) || + !CAIRO_TEST_DOUBLE_EQUALS(f,6.0)) + { + cairo_pattern_destroy (pat); + return CAIRO_TEST_FAILURE; + } + + cairo_pattern_destroy (pat); + } + + /* Test mesh getters */ + { + unsigned int count; + int i; + pat = cairo_pattern_create_mesh (); + + status = cairo_mesh_pattern_get_patch_count (pat, &count); + CHECK_SUCCESS; + + if (count != 0) { + cairo_pattern_destroy (pat); + return CAIRO_TEST_FAILURE; + } + + cairo_mesh_pattern_begin_patch (pat); + cairo_mesh_pattern_move_to (pat, 0, 0); + cairo_mesh_pattern_line_to (pat, 0, 3); + cairo_mesh_pattern_line_to (pat, 3, 3); + cairo_mesh_pattern_line_to (pat, 3, 0); + + status = cairo_mesh_pattern_get_patch_count (pat, &count); + CHECK_SUCCESS; + + if (count != 0) { + cairo_pattern_destroy (pat); + return CAIRO_TEST_FAILURE; + } + + cairo_mesh_pattern_end_patch (pat); + + status = cairo_mesh_pattern_get_patch_count (pat, &count); + CHECK_SUCCESS; + + if (count != 1) { + cairo_pattern_destroy (pat); + return CAIRO_TEST_FAILURE; + } + + for (i = 0; i < 4; i++) { + double cp_x[4] = { 1, 1, 2, 2 }; + double cp_y[4] = { 1, 2, 2, 1 }; + double x, y; + + status = cairo_mesh_pattern_get_control_point (pat, 0, i, &x, &y); + CHECK_SUCCESS; + + if (!CAIRO_TEST_DOUBLE_EQUALS(x,cp_x[i]) || + !CAIRO_TEST_DOUBLE_EQUALS(y,cp_y[i])) + { + cairo_pattern_destroy (pat); + return CAIRO_TEST_FAILURE; + } + } + + cairo_mesh_pattern_begin_patch (pat); + cairo_mesh_pattern_move_to (pat, 0, 0); + cairo_mesh_pattern_line_to (pat, 1, 0); + cairo_mesh_pattern_line_to (pat, 1, 1); + cairo_mesh_pattern_set_corner_color_rgb (pat, 0, 1, 1, 1); + cairo_mesh_pattern_end_patch (pat); + + for (i = 0; i < 4; i++) { + double corner_color[4] = { 1, 0, 0, 1 }; + double a, r, g, b; + + status = cairo_mesh_pattern_get_corner_color_rgba (pat, 1, i, + &r, &g, &b, &a); + CHECK_SUCCESS; + + if (!CAIRO_TEST_DOUBLE_EQUALS(a,corner_color[i]) || + !CAIRO_TEST_DOUBLE_EQUALS(r,corner_color[i]) || + !CAIRO_TEST_DOUBLE_EQUALS(g,corner_color[i]) || + !CAIRO_TEST_DOUBLE_EQUALS(b,corner_color[i])) + { + cairo_pattern_destroy (pat); + return CAIRO_TEST_FAILURE; + } + } + + cairo_pattern_destroy (pat); + } + + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (pattern_getters, + "Tests calls to pattern getter functions", + "pattern, api", /* keywords */ + NULL, /* requirements */ + 1, 1, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/pdf-features.c b/local/recipes/libs/cairo/source/test/pdf-features.c new file mode 100644 index 0000000000..b304cc2dc1 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/pdf-features.c @@ -0,0 +1,149 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +#include +#include +#include + +/* This test exists to test the various features of cairo-pdf.h. + * + * Currently, this test exercises the following function calls: + * + * cairo_pdf_surface_set_size + */ + +#define INCHES_TO_POINTS(in) ((in) * 72.0) +#define MM_TO_POINTS(mm) ((mm) / 25.4 * 72.0) +#define TEXT_SIZE 12 +#define BASENAME "pdf-features.out" + +static struct { + const char *page_size; + const char *page_size_alias; + const char *orientation; + double width_in_points; + double height_in_points; +} pages[] = { + {"na_letter_8.5x11in", "letter", "portrait", + INCHES_TO_POINTS(8.5), INCHES_TO_POINTS(11)}, + {"na_letter_8.5x11in", "letter", "landscape", + INCHES_TO_POINTS(11), INCHES_TO_POINTS(8.5)}, + {"iso_a4_210x297mm", "a4", "portrait", + MM_TO_POINTS(210), MM_TO_POINTS(297)}, + {"iso_a4_210x297mm", "a4", "landscape", + MM_TO_POINTS(297), MM_TO_POINTS(210)}, + {"iso_a5_148x210mm", "a5", "portrait", + MM_TO_POINTS(148), MM_TO_POINTS(210)}, + {"iso_a5_148x210mm", "a5", "landscape", + MM_TO_POINTS(210), MM_TO_POINTS(148)}, + {"iso_a6_105x148mm", "a6", "portrait", + MM_TO_POINTS(105), MM_TO_POINTS(148)}, + {"iso_a6_105x148mm", "a6", "landscape", + MM_TO_POINTS(148), MM_TO_POINTS(105)}, + {"iso_a7_74x105mm", "a7", "portrait", + MM_TO_POINTS(74), MM_TO_POINTS(105)}, + {"iso_a7_74x105mm", "a7", "landscape", + MM_TO_POINTS(105), MM_TO_POINTS(74)}, + {"iso_a8_52x74mm", "a8", "portrait", + MM_TO_POINTS(52), MM_TO_POINTS(74)}, + {"iso_a8_52x74mm", "a8", "landscape", + MM_TO_POINTS(74), MM_TO_POINTS(52)}, + {"iso_a9_37x52mm", "a9", "portrait", + MM_TO_POINTS(37), MM_TO_POINTS(52)}, + {"iso_a9_37x52mm", "a9", "landscape", + MM_TO_POINTS(52), MM_TO_POINTS(37)}, + {"iso_a10_26x37mm", "a10", "portrait", + MM_TO_POINTS(26), MM_TO_POINTS(37)}, + {"iso_a10_26x37mm", "a10", "landscape", + MM_TO_POINTS(37), MM_TO_POINTS(26)} +}; + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + cairo_surface_t *surface; + cairo_t *cr; + cairo_status_t status; + size_t i; + char *filename; + const char *path = cairo_test_mkdir (CAIRO_TEST_OUTPUT_DIR) ? CAIRO_TEST_OUTPUT_DIR : "."; + + if (! cairo_test_is_target_enabled (ctx, "pdf")) + return CAIRO_TEST_UNTESTED; + + xasprintf (&filename, "%s/%s.pdf", path, BASENAME); + + /* The initial size passed here is the default size that will be + * inheritable by each page. That is, any page for which this + * initial size applies will not have its own /MediaBox entry in + * its dictionary. */ + surface = cairo_pdf_surface_create (filename, + INCHES_TO_POINTS(8.5), + INCHES_TO_POINTS(11)); + + cr = cairo_create (surface); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (cr, TEXT_SIZE); + + for (i = 0; i < ARRAY_LENGTH (pages); i++) { + cairo_pdf_surface_set_size (surface, + pages[i].width_in_points, + pages[i].height_in_points); + + cairo_move_to (cr, TEXT_SIZE, TEXT_SIZE); + cairo_show_text (cr, pages[i].page_size); + cairo_show_text (cr, " - "); + cairo_show_text (cr, pages[i].orientation); + cairo_show_page (cr); + } + + status = cairo_status (cr); + + cairo_destroy (cr); + cairo_surface_destroy (surface); + + if (status) { + cairo_test_log (ctx, "Failed to create pdf surface for file %s: %s\n", + filename, cairo_status_to_string (status)); + free (filename); + return CAIRO_TEST_FAILURE; + } + + printf ("pdf-features: Please check %s to ensure it looks/prints correctly.\n", filename); + free (filename); + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (pdf_features, + "Check PDF specific API", + "pdf", /* keywords */ + NULL, /* requirements */ + 0, 0, + preamble, NULL) diff --git a/local/recipes/libs/cairo/source/test/pdf-isolated-group.c b/local/recipes/libs/cairo/source/test/pdf-isolated-group.c new file mode 100644 index 0000000000..e74a346a28 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/pdf-isolated-group.c @@ -0,0 +1,73 @@ +/* + * Copyright © 2012 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" + +#define SIZE 60 +#define WIDTH SIZE +#define HEIGHT SIZE + + +/* PDF transparency groups can be isolated or non-isolated. This test + * checks that the PDF output is using isolated groups. If the group + * is non-isolated the bottom half of the inner rectangle will be + * red. Note poppler-cairo currently ignores the isolated flag and + * treats the group as isolated. + * + * Refer to http://www.pdfvt.com/PDFVT_TransparencyGuide.html for an + * explanation isolated vs non-isolated. + */ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 1, 0.5, 0); + cairo_rectangle (cr, 0, SIZE/2, SIZE, SIZE/2); + cairo_fill (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_MULTIPLY); + + cairo_push_group (cr); + + cairo_set_source_rgb (cr, 0.7, 0.7, 0.7); + cairo_rectangle (cr, SIZE/4, SIZE/4, SIZE/2, SIZE/2); + cairo_fill (cr); + + cairo_pop_group_to_source (cr); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (pdf_isolated_group, + "Check that transparency groups in PDF output are isolated", + "group, operator", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/pdf-mime-data.c b/local/recipes/libs/cairo/source/test/pdf-mime-data.c new file mode 100644 index 0000000000..5052f3dac9 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/pdf-mime-data.c @@ -0,0 +1,193 @@ +/* + * Copyright © 2008 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 +#include +#include +#include + +/* This test checks that the mime data is correctly used by the PDF + * surface when embedding images.. + */ + +/* Both a *.png and *.jpg file with this name is required since we + * are not using a jpeg library */ +#define IMAGE_FILE "romedalen" + +#define BASENAME "pdf-mime-data.out" + +static cairo_test_status_t +read_file (const cairo_test_context_t *ctx, + const char *file, + unsigned char **data, + unsigned int *len) +{ + FILE *fp; + + fp = fopen (file, "rb"); + if (fp == NULL) { + char filename[4096]; + + /* try again with srcdir */ + snprintf (filename, sizeof (filename), + "%s/%s", ctx->srcdir, file); + fp = fopen (filename, "rb"); + } + if (fp == NULL) { + switch (errno) { + case ENOMEM: + cairo_test_log (ctx, "Could not create file handle for %s due to \ + lack of memory\n", file); + return CAIRO_TEST_NO_MEMORY; + default: + cairo_test_log (ctx, "Could not get the file handle for %s\n", file); + return CAIRO_TEST_FAILURE; + } + } + + fseek (fp, 0, SEEK_END); + *len = ftell(fp); + fseek (fp, 0, SEEK_SET); + *data = malloc (*len); + if (*data == NULL) { + fclose(fp); + cairo_test_log (ctx, "Could not allocate memory for buffer to read \ + from file %s\n", file); + return CAIRO_TEST_NO_MEMORY; + } + + if (fread(*data, *len, 1, fp) != 1) { + free (*data); + fclose(fp); + cairo_test_log (ctx, "Could not read data from file %s\n", file); + return CAIRO_TEST_FAILURE; + } + + fclose(fp); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + cairo_surface_t *image; + cairo_surface_t *surface; + cairo_t *cr; + cairo_status_t status, status2; + cairo_test_status_t test_status; + int width, height; + unsigned char *data; + unsigned char *out_data; + unsigned int len, out_len; + char command[4096]; + int exit_status; + char *filename; + const char *path = cairo_test_mkdir (CAIRO_TEST_OUTPUT_DIR) ? CAIRO_TEST_OUTPUT_DIR : "."; + + if (! cairo_test_is_target_enabled (ctx, "pdf")) + return CAIRO_TEST_UNTESTED; + + exit_status = system ("command -v pdfimages"); + if (exit_status) { + cairo_test_log (ctx, "pdfimages not available\n"); + return CAIRO_TEST_UNTESTED; + } + + image = cairo_test_create_surface_from_png (ctx, IMAGE_FILE ".png"); + test_status = read_file (ctx, IMAGE_FILE ".jpg", &data, &len); + if (test_status) { + return test_status; + } + + cairo_surface_set_mime_data (image, CAIRO_MIME_TYPE_JPEG, + data, len, + free, data); + width = cairo_image_surface_get_width (image); + height = cairo_image_surface_get_height (image); + + xasprintf (&filename, "%s/%s.pdf", path, BASENAME); + surface = cairo_pdf_surface_create (filename, width + 20, height + 20); + cr = cairo_create (surface); + cairo_translate (cr, 10, 10); + cairo_set_source_surface (cr, image, 0, 0); + cairo_paint (cr); + status = cairo_status (cr); + cairo_destroy (cr); + cairo_surface_finish (surface); + status2 = cairo_surface_status (surface); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; + cairo_surface_destroy (surface); + cairo_surface_destroy (image); + + if (status) { + cairo_test_log (ctx, "Failed to create pdf surface for file %s: %s\n", + filename, cairo_status_to_string (status)); + free (filename); + return CAIRO_TEST_FAILURE; + } + + printf ("pdf-mime-data: Please check %s to ensure it looks/prints correctly.\n", filename); + + sprintf (command, "pdfimages -j %s %s", filename, CAIRO_TEST_OUTPUT_DIR "/" BASENAME); + exit_status = system (command); + free (filename); + if (exit_status) { + cairo_test_log (ctx, "pdfimages failed with exit status %d\n", exit_status); + return CAIRO_TEST_FAILURE; + } + + test_status = read_file (ctx, IMAGE_FILE ".jpg", &data, &len); + if (test_status) { + return test_status; + } + + test_status = read_file (ctx, CAIRO_TEST_OUTPUT_DIR "/" BASENAME "-000.jpg", &out_data, &out_len); + if (test_status) { + return test_status; + } + + if (len != out_len || memcmp(data, out_data, len) != 0) { + free (data); + free (out_data); + cairo_test_log (ctx, "output mime data does not match source mime data\n"); + return CAIRO_TEST_FAILURE; + } + + free (data); + free (out_data); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (pdf_mime_data, + "Check mime data correctly used by PDF surface", + "pdf, mime-data", /* keywords */ + NULL, /* requirements */ + 0, 0, + preamble, NULL) diff --git a/local/recipes/libs/cairo/source/test/pdf-operators-text.c b/local/recipes/libs/cairo/source/test/pdf-operators-text.c new file mode 100644 index 0000000000..6d654d1158 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/pdf-operators-text.c @@ -0,0 +1,158 @@ +/* + * Copyright © 2021 Adrian Johnson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Adrian Johnson + */ + +/* Test pdf-operators text positioning. This test is designed to expose rounding + * errors in the PDF operations for relative positioning in very long strings. + * + * The text width is expected to match the width of the rectangle + * enclosing the text. + */ + +#include "cairo-test.h" + +#define WIDTH 10000 +#define HEIGHT 60 + +/* Using a non integer size helps expose rounding errors */ +#define FONT_SIZE 10.12345678912345 + +#define WORD "Text" +#define NUM_WORDS 450 + +#define BORDER 10 + +static cairo_user_data_key_t font_face_key; + +static cairo_status_t +user_font_init (cairo_scaled_font_t *scaled_font, + cairo_t *cr, + cairo_font_extents_t *metrics) +{ + cairo_font_face_t *font_face = cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font), + &font_face_key); + cairo_set_font_face (cr, font_face); + cairo_font_extents (cr, metrics); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +user_font_render_glyph (cairo_scaled_font_t *scaled_font, + unsigned long index, + cairo_t *cr, + cairo_text_extents_t *metrics) +{ + char text[2]; + cairo_font_face_t *font_face = cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font), + &font_face_key); + + text[0] = index; /* Only using ASCII for this test */ + text[1] = 0; + cairo_set_font_face (cr, font_face); + cairo_text_extents (cr, text, metrics); + cairo_text_path (cr, text); + cairo_fill (cr); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_font_face_t * +create_user_font_face (cairo_font_face_t *orig_font) +{ + cairo_font_face_t *user_font_face; + + user_font_face = cairo_user_font_face_create (); + cairo_user_font_face_set_init_func (user_font_face, user_font_init); + cairo_user_font_face_set_render_glyph_func (user_font_face, user_font_render_glyph); + cairo_font_face_set_user_data (user_font_face, &font_face_key, (void*) orig_font, NULL); + return user_font_face; +} + +static void +draw_text (cairo_t *cr, const char *text) +{ + cairo_text_extents_t extents; + + cairo_move_to (cr, BORDER, BORDER); + cairo_set_source_rgb (cr, 0, 0, 0); + + cairo_show_text (cr, text); + cairo_text_extents (cr, text,&extents); + + cairo_rectangle (cr, + BORDER + extents.x_bearing, + BORDER + extents.y_bearing, + extents.width, + extents.height); + cairo_set_line_width (cr, 1); + cairo_stroke (cr); +} + + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + int i; + char *text; + cairo_font_face_t *font_face; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_select_font_face (cr, "Dejavu Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + + cairo_set_font_size (cr, FONT_SIZE); + + text = malloc (strlen(WORD) * NUM_WORDS + 1); + text[0] = '\0'; + for (i = 0; i < NUM_WORDS; i++) + strcat (text, WORD); + + cairo_save (cr); + cairo_translate (cr, BORDER, BORDER); + draw_text (cr, text); + cairo_restore (cr); + + font_face = create_user_font_face (cairo_get_font_face (cr)); + cairo_set_font_face (cr, font_face); + cairo_font_face_destroy (font_face); + cairo_set_font_size (cr, FONT_SIZE); + + cairo_save (cr); + cairo_translate (cr, BORDER, BORDER*3); + draw_text (cr, text); + cairo_restore (cr); + + free (text); + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (pdf_operators_text, + "Test pdf-operators.c glyph positioning", + "pdf", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/pdf-structure.c b/local/recipes/libs/cairo/source/test/pdf-structure.c new file mode 100644 index 0000000000..a12d0305f8 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/pdf-structure.c @@ -0,0 +1,621 @@ +/* + * Copyright © 2023 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 +#include +#include + +#ifdef HAVE_UNISTD_H +#include /* __unix__ */ +#endif +#if HAVE_SYS_WAIT_H +#include +#endif + +#include +#include + +/* Test PDF logical structure + */ + +#define BASENAME "pdf-structure" + +#define PAGE_WIDTH 595 +#define PAGE_HEIGHT 842 + +#define PDF_VERSION CAIRO_PDF_VERSION_1_4 + +struct pdf_structure_test { + const char *name; + void (*func)(cairo_t *cr); +}; + +static void +text(cairo_t *cr, const char *text) +{ + double x, y; + + cairo_show_text (cr, text); + cairo_get_current_point (cr, &x, &y); + cairo_move_to (cr, 20, y + 15); +} + +static void +test_simple (cairo_t *cr) +{ + cairo_tag_begin (cr, "Document", NULL); + + cairo_tag_begin (cr, "H", ""); + text (cr, "Heading"); + cairo_tag_end (cr, "H"); + + cairo_tag_begin (cr, "Sect", NULL); + + cairo_tag_begin (cr, "P", ""); + text (cr, "Para1"); + text (cr, "Para2"); + cairo_tag_end (cr, "P"); + + cairo_tag_begin (cr, "P", ""); + text (cr, "Para3"); + + cairo_tag_begin (cr, "Note", ""); + text (cr, "Note"); + cairo_tag_end (cr, "Note"); + + text (cr, "Para4"); + cairo_tag_end (cr, "P"); + + cairo_tag_end (cr, "Sect"); + + cairo_tag_end (cr, "Document"); +} + +static void +test_simple_ref (cairo_t *cr) +{ + cairo_tag_begin (cr, CAIRO_TAG_CONTENT, "tag_name='H' id='heading'"); + text (cr, "Heading"); + cairo_tag_end (cr, CAIRO_TAG_CONTENT); + + cairo_tag_begin (cr, CAIRO_TAG_CONTENT, "tag_name='P' id='para1'"); + text (cr, "Para1"); + text (cr, "Para2"); + cairo_tag_end (cr, CAIRO_TAG_CONTENT); + + cairo_tag_begin (cr, CAIRO_TAG_CONTENT, "tag_name='P' id='para2'"); + text (cr, "Para3"); + cairo_tag_end (cr, CAIRO_TAG_CONTENT); + + cairo_tag_begin (cr, CAIRO_TAG_CONTENT, "tag_name='Note' id='note'"); + text (cr, "Note"); + cairo_tag_end (cr, CAIRO_TAG_CONTENT); + + cairo_tag_begin (cr, CAIRO_TAG_CONTENT, "tag_name='P' id='para3'"); + text (cr, "Para4"); + cairo_tag_end (cr, CAIRO_TAG_CONTENT); + + cairo_tag_begin (cr, "Document", NULL); + + cairo_tag_begin (cr, "H", ""); + cairo_tag_begin (cr, CAIRO_TAG_CONTENT_REF, "ref='heading'"); + cairo_tag_end (cr, CAIRO_TAG_CONTENT_REF); + cairo_tag_end (cr, "H"); + + cairo_tag_begin (cr, "Sect", NULL); + + cairo_tag_begin (cr, "P", ""); + cairo_tag_begin (cr, CAIRO_TAG_CONTENT_REF, "ref='para1'"); + cairo_tag_end (cr, CAIRO_TAG_CONTENT_REF); + cairo_tag_end (cr, "P"); + + cairo_tag_begin (cr, "P", ""); + + cairo_tag_begin (cr, CAIRO_TAG_CONTENT_REF, "ref='para2'"); + cairo_tag_end (cr, CAIRO_TAG_CONTENT_REF); + + cairo_tag_begin (cr, "Note", ""); + cairo_tag_begin (cr, CAIRO_TAG_CONTENT_REF, "ref='note'"); + cairo_tag_end (cr, CAIRO_TAG_CONTENT_REF); + cairo_tag_end (cr, "Note"); + + cairo_tag_begin (cr, CAIRO_TAG_CONTENT_REF, "ref='para3'"); + cairo_tag_end (cr, CAIRO_TAG_CONTENT_REF); + + cairo_tag_end (cr, "P"); + + cairo_tag_end (cr, "Sect"); + + cairo_tag_end (cr, "Document"); +} + +static void +test_group (cairo_t *cr) +{ + cairo_tag_begin (cr, "Document", NULL); + + cairo_tag_begin (cr, "H", ""); + text (cr, "Heading"); + cairo_tag_end (cr, "H"); + + cairo_tag_begin (cr, "Sect", NULL); + + cairo_push_group (cr); + + cairo_tag_begin (cr, "P", ""); + text (cr, "Para1"); + text (cr, "Para2"); + cairo_tag_end (cr, "P"); + + cairo_pop_group_to_source (cr); + cairo_paint (cr); + + cairo_tag_end (cr, "Sect"); + + cairo_tag_end (cr, "Document"); +} + +/* https://bugzilla.mozilla.org/show_bug.cgi?id=1896173 + * This particular combination of tags and groups resulted in a crash. + */ +static void +test_group2 (cairo_t *cr) +{ + cairo_tag_begin (cr, "H", ""); + text (cr, "Heading"); + cairo_tag_end (cr, "H"); + + cairo_push_group (cr); + + cairo_tag_begin (cr, "P", ""); + text (cr, "Para1"); + cairo_tag_end (cr, "P"); + + cairo_pop_group_to_source (cr); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0, 0, 0); + text (cr, "text"); +} + +/* Check that the fix for test_group2() works when there is a top level tag. */ +static void +test_group3 (cairo_t *cr) +{ + cairo_tag_begin (cr, "Document", NULL); + + cairo_tag_begin (cr, "H", ""); + text (cr, "Heading"); + cairo_tag_end (cr, "H"); + + cairo_push_group (cr); + + cairo_tag_begin (cr, "P", ""); + text (cr, "Para1"); + cairo_tag_end (cr, "P"); + + cairo_pop_group_to_source (cr); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0, 0, 0); + text (cr, "text"); + + cairo_tag_end (cr, "Document"); +} + +static void +test_group_ref (cairo_t *cr) +{ + cairo_tag_begin (cr, CAIRO_TAG_CONTENT, "tag_name='H' id='heading'"); + text (cr, "Heading"); + cairo_tag_end (cr, CAIRO_TAG_CONTENT); + + cairo_push_group (cr); + + cairo_tag_begin (cr, CAIRO_TAG_CONTENT, "tag_name='P' id='para'"); + text (cr, "Para1"); + text (cr, "Para2"); + cairo_tag_end (cr, CAIRO_TAG_CONTENT); + + cairo_pop_group_to_source (cr); + cairo_paint (cr); + + cairo_tag_begin (cr, "Document", NULL); + + cairo_tag_begin (cr, "H", ""); + cairo_tag_begin (cr, CAIRO_TAG_CONTENT_REF, "ref='heading'"); + cairo_tag_end (cr, CAIRO_TAG_CONTENT_REF); + cairo_tag_end (cr, "H"); + + cairo_tag_begin (cr, "Sect", NULL); + + cairo_tag_begin (cr, "P", ""); + cairo_tag_begin (cr, CAIRO_TAG_CONTENT_REF, "ref='para'"); + cairo_tag_end (cr, CAIRO_TAG_CONTENT_REF); + cairo_tag_end (cr, "P"); + + cairo_tag_end (cr, "Sect"); + + cairo_tag_end (cr, "Document"); + +} + +static void +test_repeated_group (cairo_t *cr) +{ + cairo_pattern_t *pat; + + cairo_tag_begin (cr, "Document", NULL); + + cairo_tag_begin (cr, "H", ""); + text (cr, "Heading"); + cairo_tag_end (cr, "H"); + + cairo_tag_begin (cr, "Sect", NULL); + + cairo_push_group (cr); + + cairo_tag_begin (cr, "P", ""); + text (cr, "Para1"); + text (cr, "Para2"); + cairo_tag_end (cr, "P"); + + pat = cairo_pop_group (cr); + + cairo_set_source (cr, pat); + cairo_paint (cr); + + cairo_translate (cr, 0, 100); + cairo_set_source (cr, pat); + cairo_rectangle (cr, 0, 0, 100, 100); + cairo_fill (cr); + + cairo_translate (cr, 0, 100); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_mask (cr, pat); + + cairo_translate (cr, 0, 100); + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_move_to (cr, 20, 0); + cairo_line_to (cr, 100, 0); + cairo_stroke (cr); + + cairo_translate (cr, 0, 100); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_move_to (cr, 20, 0); + cairo_show_text (cr, "Text"); + + cairo_tag_end (cr, "Sect"); + + cairo_tag_end (cr, "Document"); +} + +static void +test_multipage_simple (cairo_t *cr) +{ + cairo_tag_begin (cr, "Document", NULL); + + cairo_tag_begin (cr, "H", ""); + + cairo_tag_begin (cr, CAIRO_TAG_LINK, "dest='para1-dest'"); + text (cr, "Heading1"); + cairo_tag_end (cr, CAIRO_TAG_LINK); + + cairo_tag_begin (cr, CAIRO_TAG_LINK, "dest='para2-dest'"); + text (cr, "Heading2"); + cairo_tag_end (cr, CAIRO_TAG_LINK); + + cairo_tag_end (cr, "H"); + + cairo_tag_begin (cr, "Sect", NULL); + + cairo_show_page (cr); + + cairo_tag_begin (cr, "P", ""); + + cairo_tag_begin (cr, CAIRO_TAG_DEST, "name='para1-dest' internal"); + text (cr, "Para1"); + cairo_tag_end (cr, CAIRO_TAG_DEST); + + cairo_show_page (cr); + + cairo_tag_begin (cr, CAIRO_TAG_DEST, "name='para2-dest' internal"); + text (cr, "Para2"); + cairo_tag_end (cr, CAIRO_TAG_DEST); + + cairo_tag_end (cr, "P"); + + cairo_tag_end (cr, "Sect"); + + cairo_tag_end (cr, "Document"); +} + +static void +test_multipage_simple_ref (cairo_t *cr) +{ + cairo_tag_begin (cr, CAIRO_TAG_CONTENT, "tag_name='H' id='heading1'"); + text (cr, "Heading1"); + cairo_tag_end (cr, CAIRO_TAG_CONTENT); + + cairo_tag_begin (cr, CAIRO_TAG_CONTENT, "tag_name='H' id='heading2'"); + text (cr, "Heading2"); + cairo_tag_end (cr, CAIRO_TAG_CONTENT); + + cairo_show_page (cr); + + cairo_tag_begin (cr, CAIRO_TAG_DEST, "name='para1-dest' internal"); + cairo_tag_begin (cr, CAIRO_TAG_CONTENT, "tag_name='P' id='para1'"); + text (cr, "Para1"); + cairo_tag_end (cr, CAIRO_TAG_CONTENT); + cairo_tag_end (cr, CAIRO_TAG_DEST); + + cairo_show_page (cr); + + cairo_tag_begin (cr, CAIRO_TAG_DEST, "name='para2-dest' internal"); + cairo_tag_begin (cr, CAIRO_TAG_CONTENT, "tag_name='P' id='para2'"); + text (cr, "Para2"); + cairo_tag_end (cr, CAIRO_TAG_CONTENT); + cairo_tag_end (cr, CAIRO_TAG_DEST); + + cairo_tag_begin (cr, "Document", NULL); + + cairo_tag_begin (cr, "H", ""); + + cairo_tag_begin (cr, CAIRO_TAG_LINK, "dest='para1-dest' link_page=1"); + cairo_tag_begin (cr, CAIRO_TAG_CONTENT_REF, "ref='heading1'"); + cairo_tag_end (cr, CAIRO_TAG_CONTENT_REF); + cairo_tag_end (cr, CAIRO_TAG_LINK); + + cairo_tag_begin (cr, CAIRO_TAG_LINK, "dest='para2-dest' link_page=1"); + cairo_tag_begin (cr, CAIRO_TAG_CONTENT_REF, "ref='heading2'"); + cairo_tag_end (cr, CAIRO_TAG_CONTENT_REF); + cairo_tag_end (cr, CAIRO_TAG_LINK); + + cairo_tag_end (cr, "H"); + + cairo_tag_begin (cr, "Sect", NULL); + + cairo_tag_begin (cr, "P", ""); + cairo_tag_begin (cr, CAIRO_TAG_CONTENT_REF, "ref='para1'"); + cairo_tag_end (cr, CAIRO_TAG_CONTENT_REF); + cairo_tag_begin (cr, CAIRO_TAG_CONTENT_REF, "ref='para2'"); + cairo_tag_end (cr, CAIRO_TAG_CONTENT_REF); + cairo_tag_end (cr, "P"); + + cairo_tag_end (cr, "Sect"); + + cairo_tag_end (cr, "Document"); +} + +static void +test_multipage_group (cairo_t *cr) +{ + cairo_tag_begin (cr, "Document", NULL); + + cairo_tag_begin (cr, "H", ""); + text (cr, "Heading"); + cairo_tag_end (cr, "H"); + + cairo_tag_begin (cr, "Sect", NULL); + + cairo_push_group (cr); + + cairo_tag_begin (cr, "P", ""); + text (cr, "Para1"); + text (cr, "Para2"); + cairo_tag_end (cr, "P"); + + cairo_pop_group_to_source (cr); + cairo_paint (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + + cairo_show_page (cr); + + cairo_tag_begin (cr, "P", ""); + text (cr, "Para3"); + cairo_tag_end (cr, "P"); + + cairo_tag_end (cr, "Sect"); + + cairo_tag_end (cr, "Document"); +} + +/* Same as test_multipage_group but but repeat the group on the second page. */ +static void +test_multipage_group2 (cairo_t *cr) +{ + cairo_tag_begin (cr, "Document", NULL); + + cairo_tag_begin (cr, "H", ""); + text (cr, "Heading"); + cairo_tag_end (cr, "H"); + + cairo_tag_begin (cr, "Sect", NULL); + + cairo_push_group (cr); + + cairo_tag_begin (cr, "P", ""); + text (cr, "Para1"); + text (cr, "Para2"); + cairo_tag_end (cr, "P"); + + cairo_pop_group_to_source (cr); + cairo_paint (cr); + + cairo_show_page (cr); + + cairo_paint (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + + cairo_tag_begin (cr, "P", ""); + text (cr, "Para3"); + cairo_tag_end (cr, "P"); + + cairo_tag_end (cr, "Sect"); + + cairo_tag_end (cr, "Document"); +} + +static const struct pdf_structure_test pdf_structure_tests[] = { + { "simple", test_simple }, + { "simple-ref", test_simple_ref }, + { "group", test_group }, + { "group2", test_group2 }, + { "group3", test_group3 }, + { "group-ref", test_group_ref }, + { "repeated-group", test_repeated_group }, + { "multipage-simple", test_multipage_simple }, + { "multipage-simple-ref", test_multipage_simple_ref }, + { "multipage-group", test_multipage_group }, + { "multipage-group2", test_multipage_group2 }, +}; + +static cairo_test_status_t +create_pdf (cairo_test_context_t *ctx, const struct pdf_structure_test *test, const char *output) +{ + cairo_surface_t *surface; + cairo_t *cr; + cairo_status_t status, status2; + + surface = cairo_pdf_surface_create (output, PAGE_WIDTH, PAGE_HEIGHT); + + cairo_pdf_surface_restrict_to_version (surface, PDF_VERSION); + + cr = cairo_create (surface); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Serif", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (cr, 10); + cairo_move_to (cr, 20, 20); + + test->func(cr); + + status = cairo_status (cr); + cairo_destroy (cr); + cairo_surface_finish (surface); + status2 = cairo_surface_status (surface); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; + + cairo_surface_destroy (surface); + if (status) { + cairo_test_log (ctx, "Failed to create pdf surface for file %s: %s\n", + output, cairo_status_to_string (status)); + return CAIRO_TEST_FAILURE; + } + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +check_pdf (cairo_test_context_t *ctx, const struct pdf_structure_test *test, const char *output) +{ + char *command; + int ret; + cairo_test_status_t result = CAIRO_TEST_FAILURE; + + /* check-pdf-structure.sh */ + xasprintf (&command, + "%s/check-pdf-structure.sh %s %s/%s-%s.out.txt %s/%s-%s.ref.txt %s/%s-%s.diff.txt ", + ctx->srcdir, + output, + ctx->output, BASENAME, test->name, + ctx->refdir, BASENAME, test->name, + ctx->output, BASENAME, test->name); + + ret = system (command); + cairo_test_log (ctx, "%s exit code %d\n", command, + WIFEXITED (ret) ? WEXITSTATUS (ret) : -1); + + if (WIFEXITED (ret)) { + if (WEXITSTATUS (ret) == 0) + result = CAIRO_TEST_SUCCESS; + else if (WEXITSTATUS (ret) == 4) + result = CAIRO_TEST_UNTESTED; /* pdfinfo not found or wrong version */ + } + + free (command); + return result; +} + +static void +merge_test_status (cairo_test_status_t *current, cairo_test_status_t new) +{ + if (new == CAIRO_TEST_FAILURE || *current == CAIRO_TEST_FAILURE) + *current = CAIRO_TEST_FAILURE; + else if (new == CAIRO_TEST_UNTESTED) + *current = CAIRO_TEST_UNTESTED; + else + *current = new; +} + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + int i; + char *filename; + cairo_test_status_t result, all_results; + cairo_bool_t can_check = FALSE; + +/* Need a POSIX shell to run the check. */ +#ifdef __unix__ + can_check = TRUE; +#endif + + all_results = CAIRO_TEST_SUCCESS; + if (! cairo_test_is_target_enabled (ctx, "pdf")) + return CAIRO_TEST_UNTESTED; + + for (i = 0; i < ARRAY_LENGTH(pdf_structure_tests); i++) { + xasprintf (&filename, "%s/%s-%s.out.pdf", + ctx->output, + BASENAME, + pdf_structure_tests[i].name); + + result = create_pdf (ctx, &pdf_structure_tests[i], filename); + merge_test_status (&all_results, result); + + if (can_check && result == CAIRO_TEST_SUCCESS) { + result = check_pdf (ctx, &pdf_structure_tests[i], filename); + merge_test_status (&all_results, result); + } else { + merge_test_status (&all_results, CAIRO_TEST_UNTESTED); + } + } + + free (filename); + return all_results; +} + +CAIRO_TEST (pdf_structure, + "Check PDF Structure", + "pdf", /* keywords */ + NULL, /* requirements */ + 0, 0, + preamble, NULL) diff --git a/local/recipes/libs/cairo/source/test/pdf-surface-source.c b/local/recipes/libs/cairo/source/test/pdf-surface-source.c new file mode 100644 index 0000000000..354a7259a4 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/pdf-surface-source.c @@ -0,0 +1,53 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" +#include + +#include "surface-source.c" + +#define BASENAME "pdf-surface-source.out" + +static cairo_surface_t * +create_source_surface (int size) +{ + cairo_surface_t *surface; + char *filename; + const char *path = cairo_test_mkdir (CAIRO_TEST_OUTPUT_DIR) ? CAIRO_TEST_OUTPUT_DIR : "."; + + xasprintf (&filename, "%s/%s.pdf", path, BASENAME); + surface = cairo_pdf_surface_create (filename, size, size); + cairo_surface_set_fallback_resolution (surface, 72., 72.); + free (filename); + + return surface; +} + +CAIRO_TEST (pdf_surface_source, + "Test using a PDF surface as the source", + "source", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + preamble, draw) diff --git a/local/recipes/libs/cairo/source/test/pdf-tagged-text.c b/local/recipes/libs/cairo/source/test/pdf-tagged-text.c new file mode 100644 index 0000000000..094b1c8b0b --- /dev/null +++ b/local/recipes/libs/cairo/source/test/pdf-tagged-text.c @@ -0,0 +1,677 @@ +/* + * 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 + */ + +#include "cairo-test.h" + +#include +#include +#include +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#endif + +#ifdef HAVE_MMAP +#include +#endif + +#include + +#if CAIRO_HAS_PDF_SURFACE + +#include + +/* This test checks PDF with + * - tagged text + * - hyperlinks + * - document outline + * - metadata + * - thumbnails + * - page labels + */ + +#define BASENAME "pdf-tagged-text.out" + +#define PAGE_WIDTH 595 +#define PAGE_HEIGHT 842 + +#define HEADING1_SIZE 16 +#define HEADING2_SIZE 14 +#define HEADING3_SIZE 12 +#define TEXT_SIZE 12 +#define HEADING_HEIGHT 50 +#define MARGIN 50 + +struct section { + int level; + const char *heading; + int num_paragraphs; +}; + +static const struct section contents[] = { + { 0, "Chapter 1", 1 }, + { 1, "Section 1.1", 4 }, + { 2, "Section 1.1.1", 3 }, + { 1, "Section 1.2", 2 }, + { 2, "Section 1.2.1", 4 }, + { 2, "Section 1.2.2", 4 }, + { 1, "Section 1.3", 2 }, + { 0, "Chapter 2", 1 }, + { 1, "Section 2.1", 4 }, + { 2, "Section 2.1.1", 3 }, + { 1, "Section 2.2", 2 }, + { 2, "Section 2.2.1", 4 }, + { 2, "Section 2.2.2", 4 }, + { 1, "Section 2.3", 2 }, + { 0, "Chapter 3", 1 }, + { 1, "Section 3.1", 4 }, + { 2, "Section 3.1.1", 3 }, + { 1, "Section 3.2", 2 }, + { 2, "Section 3.2.1", 4 }, + { 2, "Section 3.2.2", 4 }, + { 1, "Section 3.3", 2 }, + { 0, NULL } +}; + +static const char *ipsum_lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing" + " elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." + " Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi" + " ut aliquip ex ea commodo consequat. Duis aute irure dolor in" + " reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla" + " pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa" + " qui officia deserunt mollit anim id est laborum."; + +static const char *roman_numerals[] = { + "i", "ii", "iii", "iv", "v" +}; + +#define MAX_PARAGRAPH_LINES 20 + +static const char *utf8_destination = "l\xc3\xa4nk"; + +static int paragraph_num_lines; +static char *paragraph_text[MAX_PARAGRAPH_LINES]; +static double paragraph_height; +static double line_height; +static double y_pos; +static int outline_parents[10]; +static int page_num; + +static void +layout_paragraph (cairo_t *cr) +{ + char *text, *begin, *end, *prev_end; + cairo_text_extents_t text_extents; + cairo_font_extents_t font_extents; + + cairo_select_font_face (cr, "Serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size(cr, TEXT_SIZE); + cairo_font_extents (cr, &font_extents); + line_height = font_extents.height; + paragraph_height = 0; + paragraph_num_lines = 0; + text = strdup (ipsum_lorem); + begin = text; + end = text; + prev_end = end; + while (*begin) { + end = strchr(end, ' '); + if (!end) { + paragraph_text[paragraph_num_lines++] = strdup (begin); + break; + } + *end = 0; + cairo_text_extents (cr, begin, &text_extents); + *end = ' '; + if (text_extents.width + 2*MARGIN > PAGE_WIDTH) { + int len = prev_end - begin; + char *s = xmalloc (len); + memcpy (s, begin, len); + s[len-1] = 0; + paragraph_text[paragraph_num_lines++] = s; + begin = prev_end + 1; + } + prev_end = end; + end++; + } + paragraph_height = line_height * (paragraph_num_lines + 1); + free (text); +} + +static void +draw_paragraph (cairo_t *cr) +{ + int i; + + cairo_select_font_face (cr, "Serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size(cr, TEXT_SIZE); + cairo_tag_begin (cr, "P", NULL); + for (i = 0; i < paragraph_num_lines; i++) { + cairo_move_to (cr, MARGIN, y_pos); + cairo_show_text (cr, paragraph_text[i]); + y_pos += line_height; + } + cairo_tag_end (cr, "P"); + y_pos += line_height; +} + +static void +draw_page_num (cairo_surface_t *surface, cairo_t *cr, const char *prefix, int num) +{ + char buf[100]; + + buf[0] = 0; + if (prefix) + strcat (buf, prefix); + + if (num) + sprintf (buf + strlen(buf), "%d", num); + + cairo_save (cr); + cairo_select_font_face (cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size(cr, 12); + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_move_to (cr, PAGE_WIDTH/2, PAGE_HEIGHT - MARGIN); + cairo_show_text (cr, buf); + cairo_restore (cr); + cairo_pdf_surface_set_page_label (surface, buf); +} + +static void +draw_contents (cairo_surface_t *surface, cairo_t *cr, const struct section *section) +{ + char *attrib; + + xasprintf (&attrib, "dest='%s'", section->heading); + cairo_select_font_face (cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); + switch (section->level) { + case 0: + cairo_set_font_size(cr, HEADING1_SIZE); + break; + case 1: + cairo_set_font_size(cr, HEADING2_SIZE); + break; + case 2: + cairo_set_font_size(cr, HEADING3_SIZE); + break; + } + + if (y_pos + HEADING_HEIGHT + MARGIN > PAGE_HEIGHT) { + cairo_show_page (cr); + draw_page_num (surface, cr, roman_numerals[page_num++], 0); + y_pos = MARGIN; + } + cairo_move_to (cr, MARGIN, y_pos); + cairo_save (cr); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_tag_begin (cr, "TOCI", NULL); + cairo_tag_begin (cr, "Reference", NULL); + cairo_tag_begin (cr, CAIRO_TAG_LINK, attrib); + cairo_show_text (cr, section->heading); + cairo_tag_end (cr, CAIRO_TAG_LINK); + cairo_tag_end (cr, "Reference"); + cairo_tag_end (cr, "TOCI"); + cairo_restore (cr); + y_pos += HEADING_HEIGHT; + free (attrib); +} + +static void +draw_section (cairo_surface_t *surface, cairo_t *cr, const struct section *section) +{ + int flags, i; + char *name_attrib; + char *dest_attrib; + + cairo_tag_begin (cr, "Sect", NULL); + xasprintf(&name_attrib, "name='%s'", section->heading); + xasprintf(&dest_attrib, "dest='%s'", section->heading); + cairo_select_font_face (cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); + if (section->level == 0) { + cairo_show_page (cr); + draw_page_num (surface, cr, NULL, page_num++); + cairo_set_font_size(cr, HEADING1_SIZE); + cairo_move_to (cr, MARGIN, MARGIN); + cairo_tag_begin (cr, "H1", NULL); + cairo_tag_begin (cr, CAIRO_TAG_DEST, name_attrib); + cairo_show_text (cr, section->heading); + cairo_tag_end (cr, CAIRO_TAG_DEST); + cairo_tag_end (cr, "H1"); + y_pos = MARGIN + HEADING_HEIGHT; + flags = CAIRO_PDF_OUTLINE_FLAG_BOLD | CAIRO_PDF_OUTLINE_FLAG_OPEN; + outline_parents[0] = cairo_pdf_surface_add_outline (surface, + CAIRO_PDF_OUTLINE_ROOT, + section->heading, + dest_attrib, + flags); + } else { + if (section->level == 1) { + cairo_set_font_size(cr, HEADING2_SIZE); + flags = 0; + } else { + cairo_set_font_size(cr, HEADING3_SIZE); + flags = CAIRO_PDF_OUTLINE_FLAG_ITALIC; + } + + if (y_pos + HEADING_HEIGHT + paragraph_height + MARGIN > PAGE_HEIGHT) { + cairo_show_page (cr); + draw_page_num (surface, cr, NULL, page_num++); + y_pos = MARGIN; + } + cairo_move_to (cr, MARGIN, y_pos); + if (section->level == 1) + cairo_tag_begin (cr, "H2", NULL); + else + cairo_tag_begin (cr, "H3", NULL); + cairo_tag_begin (cr, CAIRO_TAG_DEST, name_attrib); + cairo_show_text (cr, section->heading); + cairo_tag_end (cr, CAIRO_TAG_DEST); + if (section->level == 1) + cairo_tag_end (cr, "H2"); + else + cairo_tag_end (cr, "H3"); + y_pos += HEADING_HEIGHT; + outline_parents[section->level] = cairo_pdf_surface_add_outline (surface, + outline_parents[section->level - 1], + section->heading, + dest_attrib, + flags); + } + + for (i = 0; i < section->num_paragraphs; i++) { + if (y_pos + paragraph_height + MARGIN > PAGE_HEIGHT) { + cairo_show_page (cr); + draw_page_num (surface, cr, NULL, page_num++); + y_pos = MARGIN; + } + draw_paragraph (cr); + } + cairo_tag_end (cr, "Sect"); + free (name_attrib); + free (dest_attrib); +} + +static void +draw_cover (cairo_surface_t *surface, cairo_t *cr) +{ + cairo_text_extents_t text_extents; + char *attrib; + cairo_rectangle_t url_box; + const char *cairo_url = "https://www.cairographics.org/"; + const double url_box_margin = 20.0; + + cairo_tag_begin (cr, CAIRO_TAG_DEST, "name='cover' internal"); + cairo_tag_end (cr, CAIRO_TAG_DEST); + + cairo_select_font_face (cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); + cairo_set_font_size(cr, 16); + cairo_move_to (cr, PAGE_WIDTH/3, 0.15*PAGE_HEIGHT); + cairo_tag_begin (cr, "Span", NULL); + cairo_show_text (cr, "PDF Features Test"); + cairo_tag_end (cr, "Span"); + + /* Test URL link using "rect" attribute. The entire rectangle surrounding the URL should be a clickable link. */ + cairo_move_to (cr, PAGE_WIDTH/3, 0.2*PAGE_HEIGHT); + cairo_select_font_face (cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size(cr, TEXT_SIZE); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_show_text (cr, cairo_url); + cairo_text_extents (cr, cairo_url, &text_extents); + url_box.x = PAGE_WIDTH/3 - url_box_margin; + url_box.y = 0.2*PAGE_HEIGHT - url_box_margin; + url_box.width = text_extents.width + 2*url_box_margin; + url_box.height = -text_extents.height + 2*url_box_margin; + cairo_rectangle(cr, url_box.x, url_box.y, url_box.width, url_box.height); + cairo_stroke(cr); + xasprintf(&attrib, "rect=[%f %f %f %f] uri=\'%s\'", + url_box.x, url_box.y, url_box.width, url_box.height, cairo_url); + cairo_tag_begin (cr, CAIRO_TAG_LINK, attrib); + cairo_tag_end (cr, CAIRO_TAG_LINK); + free (attrib); + + /* Create link to not yet emmited page number */ + cairo_tag_begin (cr, CAIRO_TAG_LINK, "page=5"); + cairo_move_to (cr, PAGE_WIDTH/3, 0.25*PAGE_HEIGHT); + cairo_show_text (cr, "link to page 5"); + cairo_tag_end (cr, CAIRO_TAG_LINK); + + /* Create link to not yet emmited destination */ + cairo_tag_begin (cr, CAIRO_TAG_LINK, "dest='Section 3.3'"); + cairo_move_to (cr, PAGE_WIDTH/3, 0.3*PAGE_HEIGHT); + cairo_show_text (cr, "link to page section 3.3"); + cairo_tag_end (cr, CAIRO_TAG_LINK); + + /* Create link to external file */ + cairo_move_to (cr, PAGE_WIDTH/3, 0.35*PAGE_HEIGHT); + cairo_tag_begin (cr, CAIRO_TAG_LINK, "file='foo.pdf' page=1"); + cairo_show_text (cr, "link file 'foo.pdf'"); + cairo_tag_end (cr, CAIRO_TAG_LINK); + + /* Create link to missing dest */ + cairo_move_to (cr, PAGE_WIDTH/3, 0.4*PAGE_HEIGHT); + cairo_tag_begin (cr, CAIRO_TAG_LINK, "dest='I don\\'t exist'"); + cairo_show_text (cr, "link to missing dest"); + cairo_tag_end (cr, CAIRO_TAG_LINK); + + /* Create link to missing dest with URI fallback*/ + cairo_move_to (cr, PAGE_WIDTH/3, 0.45*PAGE_HEIGHT); + xasprintf(&attrib, "dest='I also don\\'t exist' uri='%s'", cairo_url); + cairo_tag_begin (cr, CAIRO_TAG_LINK, attrib); + cairo_show_text (cr, "link to missing dest with uri fallback"); + cairo_tag_end (cr, CAIRO_TAG_LINK); + free (attrib); + + /* Create link to utf8 dest */ + cairo_move_to (cr, PAGE_WIDTH/3, 0.5*PAGE_HEIGHT); + xasprintf(&attrib, "dest='%s'", utf8_destination); + cairo_tag_begin (cr, CAIRO_TAG_LINK, attrib); + cairo_show_text (cr, "link to utf8 dest"); + cairo_tag_end (cr, CAIRO_TAG_LINK); + free (attrib); + + draw_page_num (surface, cr, "cover", 0); +} + +static void +create_document (cairo_surface_t *surface, cairo_t *cr) +{ + char *attrib; + + layout_paragraph (cr); + + cairo_pdf_surface_set_thumbnail_size (surface, PAGE_WIDTH/10, PAGE_HEIGHT/10); + + cairo_pdf_surface_set_metadata (surface, CAIRO_PDF_METADATA_TITLE, "PDF Features Test"); + cairo_pdf_surface_set_metadata (surface, CAIRO_PDF_METADATA_AUTHOR, "cairo test suite"); + cairo_pdf_surface_set_metadata (surface, CAIRO_PDF_METADATA_SUBJECT, "cairo test"); + cairo_pdf_surface_set_metadata (surface, CAIRO_PDF_METADATA_KEYWORDS, + "tags, links, outline, page labels, metadata, thumbnails"); + cairo_pdf_surface_set_metadata (surface, CAIRO_PDF_METADATA_CREATOR, "pdf-features"); + cairo_pdf_surface_set_metadata (surface, CAIRO_PDF_METADATA_CREATE_DATE, "2016-01-01T12:34:56+10:30"); + cairo_pdf_surface_set_metadata (surface, CAIRO_PDF_METADATA_MOD_DATE, "2016-06-21T05:43:21Z"); + + cairo_pdf_surface_set_custom_metadata (surface, "DocumentNumber", "12345"); + /* Include some non ASCII characters */ + cairo_pdf_surface_set_custom_metadata (surface, "Document Name", "\xc2\xab""cairo test\xc2\xbb"); + /* Test unsetting custom metadata. "DocumentNumber" should not be emitted. */ + cairo_pdf_surface_set_custom_metadata (surface, "DocumentNumber", ""); + + cairo_tag_begin (cr, "Document", NULL); + + draw_cover (surface, cr); + cairo_pdf_surface_add_outline (surface, + CAIRO_PDF_OUTLINE_ROOT, + "Cover", "page=1", + CAIRO_PDF_OUTLINE_FLAG_BOLD); + + /* Create a simple link annotation. */ + cairo_tag_begin (cr, CAIRO_TAG_LINK, "uri='http://example.org' rect=[10 10 20 20]"); + cairo_tag_end (cr, CAIRO_TAG_LINK); + + /* Try to create a link annotation while the clip is empty; + * it will still be emitted. + */ + cairo_save (cr); + cairo_new_path (cr); + cairo_rectangle (cr, 100, 100, 50, 0); + cairo_clip (cr); + cairo_tag_begin (cr, CAIRO_TAG_LINK, "uri='http://example.com' rect=[100 100 20 20]"); + cairo_tag_end (cr, CAIRO_TAG_LINK); + cairo_restore (cr); + + /* An annotation whose rect has a negative coordinate. */ + cairo_tag_begin (cr, CAIRO_TAG_LINK, "uri='http://127.0.0.1/' rect=[10.0 -10.0 100.0 100.0]"); + cairo_tag_end (cr, CAIRO_TAG_LINK); + + + /* Distilled from Mozilla bug https://bugzilla.mozilla.org/show_bug.cgi?id=1725743: + * attempting to emit a Destination tag within a pushed group will lead to an + * assertion in _cairo_pdf_interchange_end_structure_tag when processing a + * following LINK tag that is outside the pushed group. + */ + + /* PushLayer */ + cairo_push_group_with_content (cr, CAIRO_CONTENT_COLOR_ALPHA); + + /* Destination */ + cairo_tag_begin (cr, CAIRO_TAG_DEST, "name='a' x=42 y=42"); + cairo_tag_end (cr, CAIRO_TAG_DEST); + + /* PopLayer */ + cairo_pop_group_to_source (cr); + cairo_paint_with_alpha (cr, 1); + cairo_set_source_rgb (cr, 0, 0, 0); + + /* Link */ + cairo_tag_begin (cr, CAIRO_TAG_LINK, "rect=[100 200 300 400] uri='http://127.0.0.1/'"); + cairo_tag_end (cr, CAIRO_TAG_LINK); + + /* End of extra Mozilla testcase. */ + + + cairo_show_page (cr); + + page_num = 0; + draw_page_num (surface, cr, roman_numerals[page_num++], 0); + y_pos = MARGIN; + + cairo_pdf_surface_add_outline (surface, + CAIRO_PDF_OUTLINE_ROOT, + "Contents", "dest='TOC'", + CAIRO_PDF_OUTLINE_FLAG_BOLD); + + cairo_tag_begin (cr, CAIRO_TAG_DEST, "name='TOC' internal"); + cairo_tag_begin (cr, "TOC", NULL); + const struct section *sect = contents; + while (sect->heading) { + draw_contents (surface, cr, sect); + sect++; + } + cairo_tag_end (cr, "TOC"); + cairo_tag_end (cr, CAIRO_TAG_DEST); + + page_num = 1; + sect = contents; + while (sect->heading) { + draw_section (surface, cr, sect); + sect++; + } + + cairo_show_page (cr); + + cairo_set_source_rgb (cr, 0, 0, 1); + + cairo_tag_begin (cr, CAIRO_TAG_LINK, "dest='cover'"); + cairo_move_to (cr, PAGE_WIDTH/3, 2*PAGE_HEIGHT/5); + cairo_show_text (cr, "link to cover"); + cairo_tag_end (cr, CAIRO_TAG_LINK); + + cairo_tag_begin (cr, CAIRO_TAG_LINK, "page=3"); + cairo_move_to (cr, PAGE_WIDTH/3, 3*PAGE_HEIGHT/5); + cairo_show_text (cr, "link to page 3"); + cairo_tag_end (cr, CAIRO_TAG_LINK); + + /* Create utf8 dest */ + cairo_move_to (cr, PAGE_WIDTH/3, 4*PAGE_HEIGHT/5); + xasprintf(&attrib, "name='%s'", utf8_destination); + cairo_tag_begin (cr, CAIRO_TAG_DEST, attrib); + cairo_show_text (cr, utf8_destination); + cairo_tag_end (cr, CAIRO_TAG_DEST); + free (attrib); + + cairo_tag_end (cr, "Document"); +} + +#ifdef HAVE_MMAP +static cairo_test_status_t +check_contains_string(cairo_test_context_t *ctx, const void *hay, size_t size, const char *needle) +{ + if (memmem(hay, size, needle, strlen(needle))) + return CAIRO_TEST_SUCCESS; + + cairo_test_log (ctx, "Failed to find expected string in generated PDF: %s\n", needle); + return CAIRO_TEST_FAILURE; +} +#endif + +static cairo_test_status_t +check_created_pdf(cairo_test_context_t *ctx, const char* filename) +{ + cairo_test_status_t result = CAIRO_TEST_SUCCESS; + int fd; + struct stat st; +#ifdef HAVE_MMAP + void *contents; +#endif + + fd = open(filename, O_RDONLY, 0); + if (fd < 0) { + cairo_test_log (ctx, "Failed to open generated PDF file %s: %s\n", filename, strerror(errno)); + return CAIRO_TEST_FAILURE; + } + + if (fstat(fd, &st) == -1) + { + cairo_test_log (ctx, "Failed to stat generated PDF file %s: %s\n", filename, strerror(errno)); + close(fd); + return CAIRO_TEST_FAILURE; + } + + if (st.st_size == 0) + { + cairo_test_log (ctx, "Generated PDF file %s is empty\n", filename); + close(fd); + return CAIRO_TEST_FAILURE; + } + +#ifdef HAVE_MMAP + contents = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (contents == NULL) + { + cairo_test_log (ctx, "Failed to mmap generated PDF file %s: %s\n", filename, strerror(errno)); + close(fd); + return CAIRO_TEST_FAILURE; + } + + /* check metadata */ + result |= check_contains_string(ctx, contents, st.st_size, "/Title (PDF Features Test)"); + result |= check_contains_string(ctx, contents, st.st_size, "/Author (cairo test suite)"); + result |= check_contains_string(ctx, contents, st.st_size, "/Creator (pdf-features)"); + result |= check_contains_string(ctx, contents, st.st_size, "/CreationDate (20160101123456+10'30')"); + result |= check_contains_string(ctx, contents, st.st_size, "/ModDate (20160621054321Z)"); + + /* check that both the example.org and example.com links were generated */ + result |= check_contains_string(ctx, contents, st.st_size, "http://example.org"); + result |= check_contains_string(ctx, contents, st.st_size, "http://example.com"); + + // TODO: add more checks + + munmap(contents, st.st_size); +#endif + + close(fd); + + return result; +} + +static cairo_test_status_t +create_pdf (cairo_test_context_t *ctx, cairo_bool_t check_output) +{ + cairo_surface_t *surface; + cairo_t *cr; + cairo_status_t status, status2; + cairo_test_status_t result; + cairo_pdf_version_t version; + char *filename; + const char *path = cairo_test_mkdir (CAIRO_TEST_OUTPUT_DIR) ? CAIRO_TEST_OUTPUT_DIR : "."; + + /* check_created_pdf() only works with version 1.4. In version 1.5 + * the text that is searched for is compressed. */ + version = check_output ? CAIRO_PDF_VERSION_1_4 : CAIRO_PDF_VERSION_1_5; + + xasprintf (&filename, "%s/%s-%s.pdf", + path, + BASENAME, + check_output ? "1.4" : "1.5"); + surface = cairo_pdf_surface_create (filename, PAGE_WIDTH, PAGE_HEIGHT); + + cairo_pdf_surface_restrict_to_version (surface, version); + + cr = cairo_create (surface); + create_document (surface, cr); + + status = cairo_status (cr); + cairo_destroy (cr); + cairo_surface_finish (surface); + status2 = cairo_surface_status (surface); + if (status == CAIRO_STATUS_SUCCESS) + status = status2; + + cairo_surface_destroy (surface); + if (status) { + cairo_test_log (ctx, "Failed to create pdf surface for file %s: %s\n", + filename, cairo_status_to_string (status)); + return CAIRO_TEST_FAILURE; + } + + result = CAIRO_TEST_SUCCESS; + if (check_output) + result = check_created_pdf(ctx, filename); + + free (filename); + + return result; +} + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + cairo_test_status_t result; + + if (! cairo_test_is_target_enabled (ctx, "pdf")) + return CAIRO_TEST_UNTESTED; + + /* Create version 1.5 PDF. This can only be manually checked */ + create_pdf (ctx, FALSE); + + /* Create version 1.4 PDF and checkout output */ + result = create_pdf (ctx, TRUE); + + + return result; +} + +CAIRO_TEST (pdf_tagged_text, + "Check tagged text, hyperlinks and PDF document features", + "pdf", /* keywords */ + NULL, /* requirements */ + 0, 0, + preamble, NULL) + +#endif /* CAIRO_HAS_PDF_SURFACE */ diff --git a/local/recipes/libs/cairo/source/test/pdf2png.c b/local/recipes/libs/cairo/source/test/pdf2png.c new file mode 100644 index 0000000000..ab39c57360 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/pdf2png.c @@ -0,0 +1,103 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Kristian Høgsberg + */ + +#include +#include +#include + +#define FAIL(msg) \ + do { fprintf (stderr, "FAIL: %s\n", msg); exit (-1); } while (0) + +#define PIXELS_PER_POINT 1 + +int main (int argc, char *argv[]) +{ + PopplerDocument *document; + PopplerPage *page; + double width, height; + const char *filename = argv[1]; + const char *output_filename = argv[2]; + const char *page_label = argv[3]; + gchar *absolute, *uri; + cairo_surface_t *surface; + cairo_t *cr; + cairo_status_t status; + GError *error = NULL; + + if (argc != 4) + FAIL ("usage: pdf2png input_file.pdf output_file.png page"); + +#if !GLIB_CHECK_VERSION(2,36,0) + g_type_init (); +#endif + + if (g_path_is_absolute(filename)) { + absolute = g_strdup (filename); + } else { + gchar *dir = g_get_current_dir (); + absolute = g_build_filename (dir, filename, (gchar *) 0); + g_free (dir); + } + + uri = g_filename_to_uri (absolute, NULL, &error); + g_free (absolute); + if (uri == NULL) + FAIL (error->message); + + document = poppler_document_new_from_file (uri, NULL, &error); + g_free (uri); + if (document == NULL) + FAIL (error->message); + + page = poppler_document_get_page_by_label (document, page_label); + g_object_unref (document); + if (page == NULL) + FAIL ("page not found"); + + poppler_page_get_size (page, &width, &height); + + surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height); + cr = cairo_create (surface); + cairo_surface_destroy (surface); + + cairo_set_source_rgb (cr, 1,1,1); + cairo_paint (cr); + cairo_push_group_with_content (cr, CAIRO_CONTENT_COLOR_ALPHA); + + poppler_page_render (page, cr); + g_object_unref (page); + + cairo_pop_group_to_source (cr); + cairo_paint (cr); + + status = cairo_surface_write_to_png (cairo_get_target (cr), + output_filename); + cairo_destroy (cr); + + if (status) + FAIL (cairo_status_to_string (status)); + + return 0; +} diff --git a/local/recipes/libs/cairo/source/test/pdiff/.gitignore b/local/recipes/libs/cairo/source/test/pdiff/.gitignore new file mode 100644 index 0000000000..f44ed659ae --- /dev/null +++ b/local/recipes/libs/cairo/source/test/pdiff/.gitignore @@ -0,0 +1,3 @@ +TAGS +tags +perceptualdiff diff --git a/local/recipes/libs/cairo/source/test/pdiff/README.txt b/local/recipes/libs/cairo/source/test/pdiff/README.txt new file mode 100644 index 0000000000..922ddafbf1 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/pdiff/README.txt @@ -0,0 +1,45 @@ +pdiff - a program that compares two images using +a perceptually based image metric. +Copyright (C) 2006 Yangli Hector Yee +yeehector@users.sourceforge.net +http://pdiff.sourceforge.net/ + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. +See the GNU General Public License for more details in the file gpl.txt. + +Build Instructions +1. Download cross platform make from http://www.cmake.org +2. Download libtiff from http://www.libtiff.org. Download libpng from http://www.libpng.org +3. Edit CMakeLists.txt to tell it where to find your tiff library +4. Type cmake . +5. Type make . (or on Windows systems cmake makes a Visual Studio +Project file) +6. To specify the install directory, use make install DESTDIR="/home/me/mydist" + +Usage + +pdiff image1.(tif | png) image2.(tif | png) [options] +-verbose : Turns on verbose mode +-fov deg: field of view, deg, in degrees. Usually between 10.0 to 85.0. +This controls how much of the screen the oberserver is seeing. Front row of +a theatre has a field of view of around 25 degrees. Back row has a field of + view of around 60 degrees. +-threshold p : Sets the number of pixels, p, to reject. For example if p is + 100, then the test fails if 100 or more pixels are perceptably different. +-gamma g : The gamma to use to convert to RGB linear space. Default is 2.2 +-luminance l: The luminance of the display the observer is seeing. Default + is 100 candela per meter squared + +Credits + +Hector Yee, project administrator and originator - hectorgon.blogspot.com +Scott Corley, for png file IO code +Mick Weiss, Linux build and release & QA +Carl Worth, Rewrite as library, depend on cairo, and port to C \ No newline at end of file diff --git a/local/recipes/libs/cairo/source/test/pdiff/args.c b/local/recipes/libs/cairo/source/test/pdiff/args.c new file mode 100644 index 0000000000..64aef6fdb2 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/pdiff/args.c @@ -0,0 +1,119 @@ +/* + Compare Args + Copyright (C) 2006 Yangli Hector Yee + + This program is free software; you can redistribute it and/or modify it under the terms of the + GNU General Public License as published by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; + if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA +*/ + +#include "args.h" +#include +#include +#include + +static const char* copyright = +"PerceptualDiff version 1.0, Copyright (C) 2006 Yangli Hector Yee\n\ +PerceptualDiff comes with ABSOLUTELY NO WARRANTY;\n\ +This is free software, and you are welcome\n\ +to redistribute it under certain conditions;\n\ +See the GPL page for details: http://www.gnu.org/copyleft/gpl.html\n\n"; + +static const char *usage = +"PeceptualDiff image1.tif image2.tif\n\n\ + Compares image1.tif and image2.tif using a perceptually based image metric\n\ + Options:\n\ +\t-verbose : Turns on verbose mode\n\ +\t-fov deg : Field of view in degrees (0.1 to 89.9)\n\ +\t-threshold p : #pixels p below which differences are ignored\n\ +\t-gamma g : Value to convert rgb into linear space (default 2.2)\n\ +\t-luminance l : White luminance (default 100.0 cdm^-2)\n\ +\n\ +\n Note: Input files can also be in the PNG format\ +\n"; + +void +args_init (args_t *args) +{ + args->surface_a = NULL; + args->surface_b = NULL; + args->Verbose = false; + args->FieldOfView = 45.0f; + args->Gamma = 2.2f; + args->ThresholdPixels = 100; + args->Luminance = 100.0f; +} + +void +args_fini (args_t *args) +{ + cairo_surface_destroy (args->surface_a); + cairo_surface_destroy (args->surface_b); +} + +bool +args_parse (args_t *args, int argc, char **argv) +{ + int i; + if (argc < 3) { + fprintf (stderr, "%s", copyright); + fprintf (stderr, "%s", usage); + return false; + } + for (i = 0; i < argc; i++) { + if (i == 1) { + args->surface_a = cairo_image_surface_create_from_png (argv[1]); + if (cairo_surface_status (args->surface_a)) + { + fprintf (stderr, "FAIL: Cannot open %s: %s\n", + argv[1], cairo_status_to_string (cairo_surface_status (args->surface_a))); + return false; + } + } else if (i == 2) { + args->surface_b = cairo_image_surface_create_from_png (argv[2]); + if (cairo_surface_status (args->surface_b)) + { + fprintf (stderr, "FAIL: Cannot open %s: %s\n", + argv[2], cairo_status_to_string (cairo_surface_status (args->surface_b))); + return false; + } + } else { + if (strstr(argv[i], "-fov")) { + if (i + 1 < argc) { + args->FieldOfView = (float) atof(argv[i + 1]); + } + } else if (strstr(argv[i], "-verbose")) { + args->Verbose = true; + } else if (strstr(argv[i], "-threshold")) { + if (i + 1 < argc) { + args->ThresholdPixels = atoi(argv[i + 1]); + } + } else if (strstr(argv[i], "-gamma")) { + if (i + 1 < argc) { + args->Gamma = (float) atof(argv[i + 1]); + } + }else if (strstr(argv[i], "-luminance")) { + if (i + 1 < argc) { + args->Luminance = (float) atof(argv[i + 1]); + } + } + } + } /* i */ + return true; +} + +void +args_print (args_t *args) +{ + printf("Field of view is %f degrees\n", args->FieldOfView); + printf("Threshold pixels is %d pixels\n", args->ThresholdPixels); + printf("The Gamma is %f\n", args->Gamma); + printf("The Display's luminance is %f candela per meter squared\n", args->Luminance); +} diff --git a/local/recipes/libs/cairo/source/test/pdiff/args.h b/local/recipes/libs/cairo/source/test/pdiff/args.h new file mode 100644 index 0000000000..338507f77c --- /dev/null +++ b/local/recipes/libs/cairo/source/test/pdiff/args.h @@ -0,0 +1,46 @@ +/* + Compare Args + Copyright (C) 2006 Yangli Hector Yee + + This program is free software; you can redistribute it and/or modify it under the terms of the + GNU General Public License as published by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; + if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA +*/ + +#ifndef _ARGS_H +#define _ARGS_H + +#include "pdiff.h" + +/* Args to pass into the comparison function */ +typedef struct _args +{ + cairo_surface_t *surface_a; /* Image A */ + cairo_surface_t *surface_b; /* Image B */ + bool Verbose; /* Print lots of text or not */ + float FieldOfView; /* Field of view in degrees */ + float Gamma; /* The gamma to convert to linear color space */ + float Luminance; /* the display's luminance */ + unsigned int ThresholdPixels; /* How many pixels different to ignore */ +} args_t; + +void +args_init (args_t *args); + +void +args_fini (args_t *args); + +bool +args_parse (args_t *args, int argc, char **argv); + +void +args_print (args_t *args); + +#endif diff --git a/local/recipes/libs/cairo/source/test/pdiff/gpl.txt b/local/recipes/libs/cairo/source/test/pdiff/gpl.txt new file mode 100644 index 0000000000..f90922eea3 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/pdiff/gpl.txt @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/local/recipes/libs/cairo/source/test/pdiff/lpyramid.c b/local/recipes/libs/cairo/source/test/pdiff/lpyramid.c new file mode 100644 index 0000000000..bd402c7dae --- /dev/null +++ b/local/recipes/libs/cairo/source/test/pdiff/lpyramid.c @@ -0,0 +1,116 @@ +/* + Laplacian Pyramid + Copyright (C) 2006 Yangli Hector Yee + + This program is free software; you can redistribute it and/or modify it under the terms of the + GNU General Public License as published by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; + if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA +*/ + +#include "lpyramid.h" +#include +#include +#include + +struct _lpyramid { + /* Successively blurred versions of the original image */ + float *levels[MAX_PYR_LEVELS]; + + int width; + int height; +}; + +static void +convolve (lpyramid_t *pyramid, float *a, const float *b) +/* convolves image b with the filter kernel and stores it in a */ +{ + int y,x,i,j; + const float Kernel[] = {0.05f, 0.25f, 0.4f, 0.25f, 0.05f}; + int width = pyramid->width; + int height = pyramid->height; + + for (y=0; y=height) ny=2*height - ny - 1; + ny *= width; + for (i=-2; i<=2; i++) { + int nx=x+i; + if (nx<0) nx=-nx; + if (nx>=width) nx=2*width - nx - 1; + sum_i += Kernel[i+2] * b[ny + nx]; + } + sum += sum_i * Kernel[j+2]; + } + *a++ = sum; + } + } +} + +/* + * Construction/Destruction + */ + +lpyramid_t * +lpyramid_create (float *image, int width, int height) +{ + lpyramid_t *pyramid; + int i; + + pyramid = malloc (sizeof (lpyramid_t)); + if (pyramid == NULL) { + fprintf (stderr, "Out of memory.\n"); + exit (1); + } + pyramid->width = width; + pyramid->height = height; + + /* Make the Laplacian pyramid by successively + * copying the earlier levels and blurring them */ + for (i=0; ilevels[i] = malloc (width * height * sizeof (float)); + if (pyramid->levels[i] == NULL) { + fprintf (stderr, "Out of memory.\n"); + exit (1); + } + if (i == 0) { + memcpy (pyramid->levels[i], image, width * height * sizeof (float)); + } else { + convolve(pyramid, pyramid->levels[i], pyramid->levels[i - 1]); + } + } + + return pyramid; +} + +void +lpyramid_destroy (lpyramid_t *pyramid) +{ + int i; + + for (i=0; ilevels[i]); + + free (pyramid); +} + +float +lpyramid_get_value (lpyramid_t *pyramid, int x, int y, int level) +{ + int index = x + y * pyramid->width; + int l = level; + if (l > MAX_PYR_LEVELS) + l = MAX_PYR_LEVELS; + return pyramid->levels[l][index]; +} diff --git a/local/recipes/libs/cairo/source/test/pdiff/lpyramid.h b/local/recipes/libs/cairo/source/test/pdiff/lpyramid.h new file mode 100644 index 0000000000..e47a66e20e --- /dev/null +++ b/local/recipes/libs/cairo/source/test/pdiff/lpyramid.h @@ -0,0 +1,32 @@ +/* + Laplacian Pyramid + Copyright (C) 2006 Yangli Hector Yee + + This program is free software; you can redistribute it and/or modify it under the terms of the + GNU General Public License as published by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; + if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA +*/ +#ifndef _LPYRAMID_H +#define _LPYRAMID_H + +#define MAX_PYR_LEVELS 8 + +typedef struct _lpyramid lpyramid_t; + +lpyramid_t * +lpyramid_create (float *image, int width, int height); + +void +lpyramid_destroy (lpyramid_t *pyramid); + +float +lpyramid_get_value (lpyramid_t *pyramid, int x, int y, int level); + +#endif /* _LPYRAMID_H */ diff --git a/local/recipes/libs/cairo/source/test/pdiff/meson.build b/local/recipes/libs/cairo/source/test/pdiff/meson.build new file mode 100644 index 0000000000..636871a1f6 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/pdiff/meson.build @@ -0,0 +1,24 @@ +libpdiff_sources = [ + 'lpyramid.c', + 'pdiff.c', +] + +perceptualdiff_sources = [ + 'args.c', + 'perceptualdiff.c', +] + +libpdiff = static_library('pdiff', libpdiff_sources, + include_directories: [incbase], + dependencies: deps + [libcairo_dep], +) + +libpdiff_dep = declare_dependency( + include_directories: include_directories('.'), + link_with: [libpdiff], +) + +perceptualdiff = executable('perceptualdiff', perceptualdiff_sources, + include_directories: [incbase], + dependencies: [libcairo_dep, libpdiff_dep], +) diff --git a/local/recipes/libs/cairo/source/test/pdiff/pdiff.c b/local/recipes/libs/cairo/source/test/pdiff/pdiff.c new file mode 100644 index 0000000000..1193698582 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/pdiff/pdiff.c @@ -0,0 +1,426 @@ +/* + Metric + Copyright (C) 2006 Yangli Hector Yee + + This program is free software; you can redistribute it and/or modify it under the terms of the + GNU General Public License as published by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; + if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA +*/ + +#include "config.h" + +#include "lpyramid.h" +#include +#include +#include +#include + +#if HAVE_STDINT_H +# include +#elif HAVE_INTTYPES_H +# include +#elif HAVE_SYS_INT_TYPES_H +# include +#elif defined(_MSC_VER) + typedef __int8 int8_t; + typedef unsigned __int8 uint8_t; + typedef __int16 int16_t; + typedef unsigned __int16 uint16_t; + typedef __int32 int32_t; + typedef unsigned __int32 uint32_t; + typedef __int64 int64_t; + typedef unsigned __int64 uint64_t; +# ifndef HAVE_UINT64_T +# define HAVE_UINT64_T 1 +# endif +# ifndef INT16_MIN +# define INT16_MIN (-32767-1) +# endif +# ifndef INT16_MAX +# define INT16_MAX (32767) +# endif +# ifndef UINT16_MAX +# define UINT16_MAX (65535) +# endif +#else +#error Cannot find definitions for fixed-width integral types (uint8_t, uint32_t, etc.) +#endif + +#include "pdiff.h" + +#ifndef M_PI +#define M_PI 3.14159265f +#endif + +#ifndef __USE_ISOC99 +#define expf exp +#define powf pow +#define fabsf fabs +#define sqrtf sqrt +#define log10f log10 +#endif + +/* + * Given the adaptation luminance, this function returns the + * threshold of visibility in cd per m^2 + * TVI means Threshold vs Intensity function + * This version comes from Ward Larson Siggraph 1997 + */ +static float +tvi (float adaptation_luminance) +{ + /* returns the threshold luminance given the adaptation luminance + units are candelas per meter squared + */ + float log_a, r, result; + log_a = log10f(adaptation_luminance); + + if (log_a < -3.94f) { + r = -2.86f; + } else if (log_a < -1.44f) { + r = powf(0.405f * log_a + 1.6f , 2.18f) - 2.86f; + } else if (log_a < -0.0184f) { + r = log_a - 0.395f; + } else if (log_a < 1.9f) { + r = powf(0.249f * log_a + 0.65f, 2.7f) - 0.72f; + } else { + r = log_a - 1.255f; + } + + result = powf(10.0f , r); + + return result; +} + +/* computes the contrast sensitivity function (Barten SPIE 1989) + * given the cycles per degree (cpd) and luminance (lum) + */ +static float +csf (float cpd, float lum) +{ + float a, b, result; + + a = 440.0f * powf((1.0f + 0.7f / lum), -0.2f); + b = 0.3f * powf((1.0f + 100.0f / lum), 0.15f); + + result = a * cpd * expf(-b * cpd) * sqrtf(1.0f + 0.06f * expf(b * cpd)); + + return result; +} + +/* + * Visual Masking Function + * from Daly 1993 + */ +static float +mask (float contrast) +{ + float a, b, result; + a = powf(392.498f * contrast, 0.7f); + b = powf(0.0153f * a, 4.0f); + result = powf(1.0f + b, 0.25f); + + return result; +} + +/* convert Adobe RGB (1998) with reference white D65 to XYZ */ +static void +AdobeRGBToXYZ (float r, float g, float b, float *x, float *y, float *z) +{ + /* matrix is from http://www.brucelindbloom.com/ */ + *x = r * 0.576700f + g * 0.185556f + b * 0.188212f; + *y = r * 0.297361f + g * 0.627355f + b * 0.0752847f; + *z = r * 0.0270328f + g * 0.0706879f + b * 0.991248f; +} + +static void +XYZToLAB (float x, float y, float z, float *L, float *A, float *B) +{ + static float xw = -1; + static float yw; + static float zw; + const float epsilon = 216.0f / 24389.0f; + const float kappa = 24389.0f / 27.0f; + float f[3]; + float r[3]; + int i; + + /* reference white */ + if (xw < 0) { + AdobeRGBToXYZ(1, 1, 1, &xw, &yw, &zw); + } + r[0] = x / xw; + r[1] = y / yw; + r[2] = z / zw; + for (i = 0; i < 3; i++) { + if (r[i] > epsilon) { + f[i] = powf(r[i], 1.0f / 3.0f); + } else { + f[i] = (kappa * r[i] + 16.0f) / 116.0f; + } + } + *L = 116.0f * f[1] - 16.0f; + *A = 500.0f * (f[0] - f[1]); + *B = 200.0f * (f[1] - f[2]); +} + +static uint32_t +_get_pixel (const uint32_t *data, int i, cairo_format_t format) +{ + if (format == CAIRO_FORMAT_ARGB32) + return data[i]; + else + return data[i] | 0xff000000; +} + +static unsigned char +_get_red (const uint32_t *data, int i, cairo_format_t format) +{ + uint32_t pixel; + uint8_t alpha; + + pixel = _get_pixel (data, i, format); + alpha = (pixel & 0xff000000) >> 24; + if (alpha == 0) + return 0; + else + return (((pixel & 0x00ff0000) >> 16) * 255 + alpha / 2) / alpha; +} + +static unsigned char +_get_green (const uint32_t *data, int i, cairo_format_t format) +{ + uint32_t pixel; + uint8_t alpha; + + pixel = _get_pixel (data, i, format); + alpha = (pixel & 0xff000000) >> 24; + if (alpha == 0) + return 0; + else + return (((pixel & 0x0000ff00) >> 8) * 255 + alpha / 2) / alpha; +} + +static unsigned char +_get_blue (const uint32_t *data, int i, cairo_format_t format) +{ + uint32_t pixel; + uint8_t alpha; + + pixel = _get_pixel (data, i, format); + alpha = (pixel & 0xff000000) >> 24; + if (alpha == 0) + return 0; + else + return (((pixel & 0x000000ff) >> 0) * 255 + alpha / 2) / alpha; +} + +static void * +xmalloc (size_t size) +{ + void *buf; + + buf = malloc (size); + if (buf == NULL) { + fprintf (stderr, "Out of memory.\n"); + exit (1); + } + + return buf; +} + +int +pdiff_compare (cairo_surface_t *surface_a, + cairo_surface_t *surface_b, + double gamma, + double luminance, + double field_of_view) +{ + unsigned int dim = (cairo_image_surface_get_width (surface_a) + * cairo_image_surface_get_height (surface_a)); + unsigned int i; + + /* assuming colorspaces are in Adobe RGB (1998) convert to XYZ */ + float *aX; + float *aY; + float *aZ; + float *bX; + float *bY; + float *bZ; + float *aLum; + float *bLum; + + float *aA; + float *bA; + float *aB; + float *bB; + + unsigned int x, y, w, h; + + lpyramid_t *la, *lb; + + float num_one_degree_pixels, pixels_per_degree, num_pixels; + unsigned int adaptation_level; + + float cpd[MAX_PYR_LEVELS]; + float F_freq[MAX_PYR_LEVELS - 2]; + float csf_max; + const uint32_t *data_a, *data_b; + cairo_format_t format_a, format_b; + + unsigned int pixels_failed; + + w = cairo_image_surface_get_width (surface_a); + h = cairo_image_surface_get_height (surface_a); + if (w < 3 || h < 3) /* too small for the Laplacian convolution */ + return -1; + + format_a = cairo_image_surface_get_format (surface_a); + format_b = cairo_image_surface_get_format (surface_b); + assert (format_a == CAIRO_FORMAT_RGB24 || format_a == CAIRO_FORMAT_ARGB32); + assert (format_b == CAIRO_FORMAT_RGB24 || format_b == CAIRO_FORMAT_ARGB32); + + aX = xmalloc (dim * sizeof (float)); + aY = xmalloc (dim * sizeof (float)); + aZ = xmalloc (dim * sizeof (float)); + bX = xmalloc (dim * sizeof (float)); + bY = xmalloc (dim * sizeof (float)); + bZ = xmalloc (dim * sizeof (float)); + aLum = xmalloc (dim * sizeof (float)); + bLum = xmalloc (dim * sizeof (float)); + + aA = xmalloc (dim * sizeof (float)); + bA = xmalloc (dim * sizeof (float)); + aB = xmalloc (dim * sizeof (float)); + bB = xmalloc (dim * sizeof (float)); + + data_a = (uint32_t *) cairo_image_surface_get_data (surface_a); + data_b = (uint32_t *) cairo_image_surface_get_data (surface_b); + for (y = 0; y < h; y++) { + for (x = 0; x < w; x++) { + float r, g, b, l; + i = x + y * w; + r = powf(_get_red (data_a, i, format_a) / 255.0f, gamma); + g = powf(_get_green (data_a, i, format_a) / 255.0f, gamma); + b = powf(_get_blue (data_a, i, format_a) / 255.0f, gamma); + + AdobeRGBToXYZ(r,g,b,&aX[i],&aY[i],&aZ[i]); + XYZToLAB(aX[i], aY[i], aZ[i], &l, &aA[i], &aB[i]); + r = powf(_get_red (data_b, i, format_b) / 255.0f, gamma); + g = powf(_get_green (data_b, i, format_b) / 255.0f, gamma); + b = powf(_get_blue (data_b, i, format_b) / 255.0f, gamma); + + AdobeRGBToXYZ(r,g,b,&bX[i],&bY[i],&bZ[i]); + XYZToLAB(bX[i], bY[i], bZ[i], &l, &bA[i], &bB[i]); + aLum[i] = aY[i] * luminance; + bLum[i] = bY[i] * luminance; + } + } + + la = lpyramid_create (aLum, w, h); + lb = lpyramid_create (bLum, w, h); + + num_one_degree_pixels = (float) (2 * tan(field_of_view * 0.5 * M_PI / 180) * 180 / M_PI); + pixels_per_degree = w / num_one_degree_pixels; + + num_pixels = 1; + adaptation_level = 0; + for (i = 0; i < MAX_PYR_LEVELS; i++) { + adaptation_level = i; + if (num_pixels > num_one_degree_pixels) break; + num_pixels *= 2; + } + + cpd[0] = 0.5f * pixels_per_degree; + for (i = 1; i < MAX_PYR_LEVELS; i++) cpd[i] = 0.5f * cpd[i - 1]; + csf_max = csf(3.248f, 100.0f); + + for (i = 0; i < MAX_PYR_LEVELS - 2; i++) F_freq[i] = csf_max / csf( cpd[i], 100.0f); + + pixels_failed = 0; + for (y = 0; y < h; y++) { + for (x = 0; x < w; x++) { + int index = x + y * w; + float contrast[MAX_PYR_LEVELS - 2]; + float F_mask[MAX_PYR_LEVELS - 2]; + float factor; + float delta; + float adapt; + bool pass; + float sum_contrast = 0; + for (i = 0; i < MAX_PYR_LEVELS - 2; i++) { + float n1 = fabsf(lpyramid_get_value (la,x,y,i) - lpyramid_get_value (la,x,y,i + 1)); + float n2 = fabsf(lpyramid_get_value (lb,x,y,i) - lpyramid_get_value (lb,x,y,i + 1)); + float numerator = (n1 > n2) ? n1 : n2; + float d1 = fabsf(lpyramid_get_value(la,x,y,i+2)); + float d2 = fabsf(lpyramid_get_value(lb,x,y,i+2)); + float denominator = (d1 > d2) ? d1 : d2; + if (denominator < 1e-5f) denominator = 1e-5f; + contrast[i] = numerator / denominator; + sum_contrast += contrast[i]; + } + if (sum_contrast < 1e-5) sum_contrast = 1e-5f; + adapt = lpyramid_get_value(la,x,y,adaptation_level) + lpyramid_get_value(lb,x,y,adaptation_level); + adapt *= 0.5f; + if (adapt < 1e-5) adapt = 1e-5f; + for (i = 0; i < MAX_PYR_LEVELS - 2; i++) { + F_mask[i] = mask(contrast[i] * csf(cpd[i], adapt)); + } + factor = 0; + for (i = 0; i < MAX_PYR_LEVELS - 2; i++) { + factor += contrast[i] * F_freq[i] * F_mask[i] / sum_contrast; + } + if (factor < 1) factor = 1; + if (factor > 10) factor = 10; + delta = fabsf(lpyramid_get_value(la,x,y,0) - lpyramid_get_value(lb,x,y,0)); + pass = true; + /* pure luminance test */ + if (delta > factor * tvi(adapt)) { + pass = false; + } else { + /* CIE delta E test with modifications */ + float color_scale = 1.0f; + float da = aA[index] - bA[index]; + float db = aB[index] - bB[index]; + float delta_e; + /* ramp down the color test in scotopic regions */ + if (adapt < 10.0f) { + color_scale = 1.0f - (10.0f - color_scale) / 10.0f; + color_scale = color_scale * color_scale; + } + da = da * da; + db = db * db; + delta_e = (da + db) * color_scale; + if (delta_e > factor) { + pass = false; + } + } + if (!pass) + pixels_failed++; + } + } + + free (aX); + free (aY); + free (aZ); + free (bX); + free (bY); + free (bZ); + free (aLum); + free (bLum); + lpyramid_destroy (la); + lpyramid_destroy (lb); + free (aA); + free (bA); + free (aB); + free (bB); + + return pixels_failed; +} diff --git a/local/recipes/libs/cairo/source/test/pdiff/pdiff.h b/local/recipes/libs/cairo/source/test/pdiff/pdiff.h new file mode 100644 index 0000000000..30fec06cf4 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/pdiff/pdiff.h @@ -0,0 +1,40 @@ +/* + Copyright (C) 2006 Yangli Hector Yee + Copyright (C) 2006 Red Hat, Inc. + + This program is free software; you can redistribute it and/or modify it under the terms of the + GNU General Public License as published by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; + if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA +*/ + +#ifndef _PDIFF_H +#define _PDIFF_H + +#include + +typedef int bool; +#ifndef true +#define true 1 +#endif +#ifndef false +#define false 0 +#endif + +/* Image comparison metric using Yee's method (and a cairo interface) + * References: A Perceptual Metric for Production Testing, Hector Yee, Journal of Graphics Tools 2004 + */ +int +pdiff_compare (cairo_surface_t *surface_a, + cairo_surface_t *surface_b, + double gamma, + double luminance, + double field_of_view); + +#endif diff --git a/local/recipes/libs/cairo/source/test/pdiff/perceptualdiff.c b/local/recipes/libs/cairo/source/test/pdiff/perceptualdiff.c new file mode 100644 index 0000000000..5850dc916d --- /dev/null +++ b/local/recipes/libs/cairo/source/test/pdiff/perceptualdiff.c @@ -0,0 +1,101 @@ +/* + PerceptualDiff - a program that compares two images using a perceptual metric + based on the paper : + A perceptual metric for production testing. Journal of graphics tools, 9(4):33-40, 2004, Hector Yee + Copyright (C) 2006 Yangli Hector Yee + + This program is free software; you can redistribute it and/or modify it under the terms of the + GNU General Public License as published by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with this program; + if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA +*/ + +#include +#include +#include +#include +#include "lpyramid.h" +#include "args.h" +#include "pdiff.h" + +static bool Yee_Compare(args_t *args) +{ + unsigned int width_a, height_a, stride_a; + unsigned char *data_a, *row_a; + uint32_t *pixel_a; + unsigned int width_b, height_b, stride_b; + unsigned char *data_b, *row_b; + uint32_t *pixel_b; + unsigned int x, y, pixels_failed; + bool identical = true; + + width_a = cairo_image_surface_get_width (args->surface_a); + height_a = cairo_image_surface_get_height (args->surface_a); + stride_a = cairo_image_surface_get_stride (args->surface_a); + data_a = cairo_image_surface_get_data (args->surface_a); + + width_b = cairo_image_surface_get_width (args->surface_b); + height_b = cairo_image_surface_get_height (args->surface_b); + stride_b = cairo_image_surface_get_stride (args->surface_b); + data_b = cairo_image_surface_get_data (args->surface_b); + + if ((width_a != width_b) || (height_a != height_b)) { + printf ("FAIL: Image dimensions do not match\n"); + return false; + } + + identical = true; + + for (y = 0; y < height_a; y++) { + row_a = data_a + y * stride_a; + row_b = data_b + y * stride_b; + pixel_a = (uint32_t *) row_a; + pixel_b = (uint32_t *) row_b; + for (x = 0; x < width_a; x++) { + if (*pixel_a != *pixel_b) { + identical = false; + } + pixel_a++; + pixel_b++; + } + } + if (identical) { + printf ("PASS: Images are binary identical\n"); + return true; + } + + pixels_failed = pdiff_compare (args->surface_a, args->surface_b, + args->Gamma, args->Luminance, + args->FieldOfView); + + if (pixels_failed < args->ThresholdPixels) { + printf ("PASS: Images are perceptually indistinguishable\n"); + return true; + } + + printf("FAIL: Images are visibly different\n" + "%d pixels are different\n", pixels_failed); + + return false; +} + +int main(int argc, char **argv) +{ + args_t args; + + args_init (&args); + + if (!args_parse (&args, argc, argv)) { + return -1; + } else { + if (args.Verbose) + args_print (&args); + } + return ! Yee_Compare(&args); +} diff --git a/local/recipes/libs/cairo/source/test/pixman-downscale.c b/local/recipes/libs/cairo/source/test/pixman-downscale.c new file mode 100644 index 0000000000..6b653d2232 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/pixman-downscale.c @@ -0,0 +1,203 @@ +/* + * Copyright © 2013 Samsung Electronics + * + * 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: Bryce Harrington + */ + +/* This test exercises scaling a png image to smaller pixel dimensions + * + * Currently, this exercises several of pixman's scaling filters. + */ + +#include "cairo-test.h" + +#include +#include + +#include + +static const char png_filename[] = "quad-color.png"; + +/* Draw an image scaled down, with antialiasing disabled */ +static cairo_test_status_t +draw (cairo_t *cr, int width, int height, cairo_filter_t filter) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_surface_t *image; + double x_scale, y_scale, scale; + + cairo_set_source_rgb (cr, 1, 1, 1); + image = cairo_test_create_surface_from_png (ctx, png_filename); + x_scale = width * 1.0 / cairo_image_surface_get_width (image); + y_scale = height * 1.0 / cairo_image_surface_get_height (image); + scale = x_scale < y_scale ? x_scale : y_scale; + + cairo_save (cr); + cairo_scale (cr, scale, scale); + cairo_set_source_surface (cr, image, 0, 0); + cairo_pattern_set_filter (cairo_get_source (cr), filter); + cairo_paint (cr); + cairo_restore (cr); + cairo_surface_destroy (image); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +draw_fast (cairo_t *cr, int width, int height) +{ + return draw (cr, width, height, CAIRO_FILTER_FAST); +} + +static cairo_test_status_t +draw_good (cairo_t *cr, int width, int height) +{ + return draw (cr, width, height, CAIRO_FILTER_GOOD); +} + +static cairo_test_status_t +draw_best (cairo_t *cr, int width, int height) +{ + return draw (cr, width, height, CAIRO_FILTER_BEST); +} + +static cairo_test_status_t +draw_nearest (cairo_t *cr, int width, int height) +{ + return draw (cr, width, height, CAIRO_FILTER_NEAREST); +} + +static cairo_test_status_t +draw_bilinear (cairo_t *cr, int width, int height) +{ + return draw (cr, width, height, CAIRO_FILTER_BILINEAR); +} + +CAIRO_TEST (pixman_downscale_fast_96, + "Tests scaling to equivalent size using the fast filter", + "image, transform, raster, downscale", /* keywords */ + NULL, /* requirements */ + 96, 96, + NULL, draw_fast) + +CAIRO_TEST (pixman_downscale_fast_95, + "Tests downscaling by a single pixel using the fast filter", + "image, transform, raster, downscale", /* keywords */ + NULL, /* requirements */ + 95, 95, + NULL, draw_fast) + +CAIRO_TEST (pixman_downscale_fast_24, + "Tests downscaling by an even multiple using the fast filter", + "image, transform, raster, downscale", /* keywords */ + NULL, /* requirements */ + 24, 24, + NULL, draw_fast) + + +CAIRO_TEST (pixman_downscale_good_96, + "Tests scaling to equivalent size using the good filter", + "image, transform, raster, downscale", /* keywords */ + NULL, /* requirements */ + 96, 96, + NULL, draw_good) + +CAIRO_TEST (pixman_downscale_good_95, + "Tests downscaling by a single pixel using the good filter", + "image, transform, raster, downscale", /* keywords */ + NULL, /* requirements */ + 95, 95, + NULL, draw_good) + +CAIRO_TEST (pixman_downscale_good_24, + "Tests downscaling by an even multiple using the good filter", + "image, transform, raster, downscale", /* keywords */ + NULL, /* requirements */ + 24, 24, + NULL, draw_good) + + +CAIRO_TEST (pixman_downscale_best_96, + "Tests scaling to equivalent size using the best filter", + "image, transform, raster, downscale", /* keywords */ + NULL, /* requirements */ + 96, 96, + NULL, draw_best) + +CAIRO_TEST (pixman_downscale_best_95, + "Tests downscaling by a single pixel using the best filter", + "image, transform, raster, downscale", /* keywords */ + NULL, /* requirements */ + 95, 95, + NULL, draw_best) + +CAIRO_TEST (pixman_downscale_best_24, + "Tests downscaling by an even multiple using the best filter", + "image, transform, raster, downscale", /* keywords */ + NULL, /* requirements */ + 24, 24, + NULL, draw_best) + + +CAIRO_TEST (pixman_downscale_nearest_96, + "Tests scaling to equivalent size using the nearest filter", + "image, transform, raster, downscale", /* keywords */ + NULL, /* requirements */ + 96, 96, + NULL, draw_nearest) + +CAIRO_TEST (pixman_downscale_nearest_95, + "Tests downscaling by a single pixel using the nearest filter", + "image, transform, raster, downscale", /* keywords */ + NULL, /* requirements */ + 95, 95, + NULL, draw_nearest) + +CAIRO_TEST (pixman_downscale_nearest_24, + "Tests downscaling by an even multiple using the nearest filter", + "image, transform, raster, downscale", /* keywords */ + NULL, /* requirements */ + 24, 24, + NULL, draw_nearest) + + +CAIRO_TEST (pixman_downscale_bilinear_96, + "Tests scaling to equivalent size using the bilinear filter", + "image, transform, raster, downscale", /* keywords */ + NULL, /* requirements */ + 96, 96, + NULL, draw_bilinear) + +CAIRO_TEST (pixman_downscale_bilinear_95, + "Tests downscaling by a single pixel using the bilinear filter", + "image, transform, raster, downscale", /* keywords */ + NULL, /* requirements */ + 95, 95, + NULL, draw_bilinear) + +CAIRO_TEST (pixman_downscale_bilinear_24, + "Tests downscaling by an even multiple using the bilinear filter", + "image, transform, raster, downscale", /* keywords */ + NULL, /* requirements */ + 24, 24, + NULL, draw_bilinear) diff --git a/local/recipes/libs/cairo/source/test/pixman-rotate.c b/local/recipes/libs/cairo/source/test/pixman-rotate.c new file mode 100644 index 0000000000..e0d0fc8852 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/pixman-rotate.c @@ -0,0 +1,92 @@ +/* + * Copyright © 2007 Red Hat, Inc. + * + * 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: Kristian Høgsberg + */ + +#include "cairo-test.h" + +#include +#include +#include +#include + +#include + +#define WIDTH 32 +#define HEIGHT WIDTH + +#define IMAGE_WIDTH (3 * WIDTH) +#define IMAGE_HEIGHT IMAGE_WIDTH + +/* Draw the word cairo at NUM_TEXT different angles */ +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *stamp; + cairo_t *cr2; + + /* Draw a translucent rectangle for reference where the rotated + * image should be. */ + cairo_new_path (cr); + cairo_rectangle (cr, WIDTH, HEIGHT, WIDTH, HEIGHT); + cairo_set_source_rgba (cr, 1, 1, 0, 0.3); + cairo_fill (cr); + +#if 1 /* Set to 0 to generate reference image */ + cairo_translate (cr, 2 * WIDTH, 2 * HEIGHT); + cairo_rotate (cr, M_PI); +#else + cairo_translate (cr, WIDTH, HEIGHT); +#endif + + stamp = cairo_surface_create_similar (cairo_get_group_target (cr), + CAIRO_CONTENT_COLOR_ALPHA, + WIDTH, HEIGHT); + cr2 = cairo_create (stamp); + cairo_surface_destroy (stamp); + { + cairo_new_path (cr2); + cairo_rectangle (cr2, WIDTH / 4, HEIGHT / 4, WIDTH / 2, HEIGHT / 2); + cairo_set_source_rgba (cr2, 1, 0, 0, 0.8); + cairo_fill (cr2); + + cairo_rectangle (cr2, 0, 0, WIDTH, HEIGHT); + cairo_set_line_width (cr2, 2); + cairo_set_source_rgb (cr2, 0, 0, 0); + cairo_stroke (cr2); + } + cairo_set_source_surface (cr, cairo_get_target (cr2), 0, 0); + cairo_destroy (cr2); + + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (pixman_rotate, + "Exposes pixman off-by-one error when rotating", + "image, transform", /* keywords */ + NULL, /* requirements */ + IMAGE_WIDTH, IMAGE_HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/png-flatten.c b/local/recipes/libs/cairo/source/test/png-flatten.c new file mode 100644 index 0000000000..2ce804ea62 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/png-flatten.c @@ -0,0 +1,77 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl Worth + */ + +#include + +#include + +int +main (int argc, char *argv[]) +{ + cairo_t *cr; + cairo_surface_t *argb, *rgb24; + cairo_status_t status; + const char *input, *output; + + if (argc != 3) { + fprintf (stderr, "usage: %s input.png output.png", argv[0]); + fprintf (stderr, "Loads a PNG image (potentially with alpha) and writes out a flattened (no alpha)\nPNG image by first blending over white.\n"); + return 1; + } + + input = argv[1]; + output = argv[2]; + + argb = cairo_image_surface_create_from_png (input); + status = cairo_surface_status (argb); + if (status) { + fprintf (stderr, "%s: Error: Failed to load %s: %s\n", + argv[0], input, cairo_status_to_string (status)); + return 1; + } + + rgb24 = cairo_image_surface_create (CAIRO_FORMAT_RGB24, + cairo_image_surface_get_width (argb), + cairo_image_surface_get_height (argb)); + + cr = cairo_create (rgb24); + + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + + cairo_set_source_surface (cr, argb, 0, 0); + cairo_paint (cr); + + cairo_destroy (cr); + + status = cairo_surface_write_to_png (rgb24, output); + if (status) { + fprintf (stderr, "%s: Error: Failed to write %s: %s\n", + argv[0], output, cairo_status_to_string (status)); + return 1; + } + + return 0; +} diff --git a/local/recipes/libs/cairo/source/test/png.c b/local/recipes/libs/cairo/source/test/png.c new file mode 100644 index 0000000000..a199d4867d --- /dev/null +++ b/local/recipes/libs/cairo/source/test/png.c @@ -0,0 +1,175 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +#include + +/* Test the idempotency of write_png->read_png */ + +#define RGB_MASK 0x00ffffff +#define BASENAME "png.out" + +static cairo_bool_t +image_surface_equals (cairo_surface_t *A, cairo_surface_t *B) +{ + if (cairo_image_surface_get_format (A) != + cairo_image_surface_get_format (B)) + return 0; + + if (cairo_image_surface_get_width (A) != + cairo_image_surface_get_width (B)) + return 0; + + if (cairo_image_surface_get_height (A) != + cairo_image_surface_get_height (B)) + return 0; + + return 1; +} + +static const char * +format_to_string (cairo_format_t format) +{ + switch (format) { + case CAIRO_FORMAT_A1: return "a1"; + case CAIRO_FORMAT_A8: return "a8"; + case CAIRO_FORMAT_RGB16_565: return "rgb16"; + case CAIRO_FORMAT_RGB24: return "rgb24"; + case CAIRO_FORMAT_RGB30: return "rgb30"; + case CAIRO_FORMAT_ARGB32: return "argb32"; + case CAIRO_FORMAT_RGB96F: return "rgb96f"; + case CAIRO_FORMAT_RGBA128F: return "rgba128f"; + case CAIRO_FORMAT_INVALID: + default: return "???"; + } +} + +static void +print_surface (const cairo_test_context_t *ctx, cairo_surface_t *surface) +{ + cairo_test_log (ctx, + "%s (%dx%d)\n", + format_to_string (cairo_image_surface_get_format (surface)), + cairo_image_surface_get_width (surface), + cairo_image_surface_get_height (surface)); +} + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + cairo_surface_t *surface0, *surface1; + cairo_status_t status; + uint32_t argb32 = 0xdeadbede; + char *filename; + const char *path = cairo_test_mkdir (CAIRO_TEST_OUTPUT_DIR) ? CAIRO_TEST_OUTPUT_DIR : "."; + + xasprintf (&filename, "%s/%s.png", path, BASENAME); + surface0 = cairo_image_surface_create_for_data ((unsigned char *) &argb32, + CAIRO_FORMAT_ARGB32, + 1, 1, 4); + status = cairo_surface_write_to_png (surface0, filename); + if (status) { + cairo_test_log (ctx, "Error writing '%s': %s\n", + filename, cairo_status_to_string (status)); + + cairo_surface_destroy (surface0); + free (filename); + return cairo_test_status_from_status (ctx, status); + } + surface1 = cairo_image_surface_create_from_png (filename); + status = cairo_surface_status (surface1); + if (status) { + cairo_test_log (ctx, "Error reading '%s': %s\n", + filename, cairo_status_to_string (status)); + + cairo_surface_destroy (surface1); + cairo_surface_destroy (surface0); + free (filename); + return cairo_test_status_from_status (ctx, status); + } + + if (! image_surface_equals (surface0, surface1)) { + cairo_test_log (ctx, "Error surface mismatch.\n"); + cairo_test_log (ctx, "to png: "); print_surface (ctx, surface0); + cairo_test_log (ctx, "from png: "); print_surface (ctx, surface1); + + cairo_surface_destroy (surface0); + cairo_surface_destroy (surface1); + free (filename); + return CAIRO_TEST_FAILURE; + } + assert (*(uint32_t *) cairo_image_surface_get_data (surface1) == argb32); + + cairo_surface_destroy (surface0); + cairo_surface_destroy (surface1); + + surface0 = cairo_image_surface_create_for_data ((unsigned char *) &argb32, + CAIRO_FORMAT_RGB24, + 1, 1, 4); + status = cairo_surface_write_to_png (surface0, filename); + if (status) { + cairo_test_log (ctx, "Error writing '%s': %s\n", + filename, cairo_status_to_string (status)); + cairo_surface_destroy (surface0); + return cairo_test_status_from_status (ctx, status); + } + surface1 = cairo_image_surface_create_from_png (filename); + status = cairo_surface_status (surface1); + if (status) { + cairo_test_log (ctx, "Error reading '%s': %s\n", + filename, cairo_status_to_string (status)); + free (filename); + + cairo_surface_destroy (surface1); + cairo_surface_destroy (surface0); + return cairo_test_status_from_status (ctx, status); + } + free (filename); + + if (! image_surface_equals (surface0, surface1)) { + cairo_test_log (ctx, "Error surface mismatch.\n"); + cairo_test_log (ctx, "to png: "); print_surface (ctx, surface0); + cairo_test_log (ctx, "from png: "); print_surface (ctx, surface1); + + cairo_surface_destroy (surface0); + cairo_surface_destroy (surface1); + return CAIRO_TEST_FAILURE; + } + assert ((*(uint32_t *) cairo_image_surface_get_data (surface1) & RGB_MASK) + == (argb32 & RGB_MASK)); + + cairo_surface_destroy (surface0); + cairo_surface_destroy (surface1); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (png, + "Check that the png export/import is idempotent.", + "png, api", /* keywords */ + NULL, /* requirements */ + 0, 0, + preamble, NULL) diff --git a/local/recipes/libs/cairo/source/test/png.png b/local/recipes/libs/cairo/source/test/png.png new file mode 100644 index 0000000000..56c428e121 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/png.png differ diff --git a/local/recipes/libs/cairo/source/test/ps-eps.c b/local/recipes/libs/cairo/source/test/ps-eps.c new file mode 100644 index 0000000000..60203a1cb0 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/ps-eps.c @@ -0,0 +1,352 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * Copyright © 2009 Adrian Johnson + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + * Adrian Johnson + * Chris Wilson + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#ifdef HAVE_UNISTD_H +#include +#include +#endif +#if HAVE_SYS_STAT_H +#include +#endif + +#include "cairo-test.h" +#include "buffer-diff.h" + +/* Test EPS output. + */ + +#define WIDTH 595 +#define HEIGHT 842 + +/* Reference Bounding Box */ +#define LLX 95 +#define LLY 687 +#define URX 155 +#define URY 747 + +static void +_xunlink (const cairo_test_context_t *ctx, const char *pathname) +{ + if (unlink (pathname) < 0 && errno != ENOENT) { + cairo_test_log (ctx, "Error: Cannot remove %s: %s\n", + pathname, strerror (errno)); + exit (1); + } +} + +static cairo_bool_t +check_result (cairo_test_context_t *ctx, + const cairo_boilerplate_target_t *target, + const char *test_name, + const char *base_name, + cairo_surface_t *surface) +{ + const char *format; + char *ref_name; + char *png_name; + char *diff_name; + cairo_surface_t *test_image, *ref_image, *diff_image; + buffer_diff_result_t result; + cairo_status_t status; + cairo_bool_t ret; + + /* XXX log target, OUTPUT, REFERENCE, DIFFERENCE for index.html */ + + if (target->finish_surface != NULL) { + status = target->finish_surface (surface); + if (status) { + cairo_test_log (ctx, "Error: Failed to finish surface: %s\n", + cairo_status_to_string (status)); + cairo_surface_destroy (surface); + return FALSE; + } + } + + xasprintf (&png_name, "%s.out.png", base_name); + xasprintf (&diff_name, "%s.diff.png", base_name); + + test_image = target->get_image_surface (surface, 0, WIDTH, HEIGHT); + if (cairo_surface_status (test_image)) { + cairo_test_log (ctx, "Error: Failed to extract page: %s\n", + cairo_status_to_string (cairo_surface_status (test_image))); + cairo_surface_destroy (test_image); + free (png_name); + free (diff_name); + return FALSE; + } + + _xunlink (ctx, png_name); + status = cairo_surface_write_to_png (test_image, png_name); + if (status) { + cairo_test_log (ctx, "Error: Failed to write output image: %s\n", + cairo_status_to_string (status)); + cairo_surface_destroy (test_image); + free (png_name); + free (diff_name); + return FALSE; + } + + format = cairo_boilerplate_content_name (target->content); + ref_name = cairo_test_reference_filename (ctx, + base_name, + test_name, + target->name, + target->basename, + format, + CAIRO_TEST_REF_SUFFIX, + CAIRO_TEST_PNG_EXTENSION); + if (ref_name == NULL) { + cairo_test_log (ctx, "Error: Cannot find reference image for %s\n", + base_name); + cairo_surface_destroy (test_image); + free (png_name); + free (diff_name); + return FALSE; + } + + ref_image = cairo_test_get_reference_image (ctx, ref_name, + target->content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED); + if (cairo_surface_status (ref_image)) { + cairo_test_log (ctx, "Error: Cannot open reference image for %s: %s\n", + ref_name, + cairo_status_to_string (cairo_surface_status (ref_image))); + cairo_surface_destroy (ref_image); + cairo_surface_destroy (test_image); + free (png_name); + free (diff_name); + free (ref_name); + return FALSE; + } + + diff_image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + WIDTH, HEIGHT); + + ret = TRUE; + status = image_diff (ctx, + test_image, ref_image, diff_image, + &result); + _xunlink (ctx, diff_name); + if (status) { + cairo_test_log (ctx, "Error: Failed to compare images: %s\n", + cairo_status_to_string (status)); + ret = FALSE; + } else if (image_diff_is_failure (&result, target->error_tolerance)) + { + ret = FALSE; + + status = cairo_surface_write_to_png (diff_image, diff_name); + if (status) { + cairo_test_log (ctx, "Error: Failed to write differences image: %s\n", + cairo_status_to_string (status)); + } + } + + cairo_surface_destroy (test_image); + cairo_surface_destroy (diff_image); + free (png_name); + free (diff_name); + free (ref_name); + + return ret; +} + + +#define DOCUMENT_BBOX "%%BoundingBox:" +#define PAGE_BBOX "%%PageBoundingBox:" + +static cairo_bool_t +check_bbox (cairo_test_context_t *ctx, + const char *base_name) +{ + char *filename; + FILE *f; + char buf[256]; + cairo_bool_t bbox_pass, page_bbox_pass; + int llx, lly, urx, ury; + int ret; + + xasprintf (&filename, "%s.out.ps", base_name); + f = fopen (filename, "r"); + if (!f) { + cairo_test_log (ctx, "Error: Cannot open EPS output: %s\n", + base_name); + free (filename); + return FALSE; + } + + bbox_pass = FALSE; + page_bbox_pass = FALSE; + while (!feof(f)) { + if (fgets (buf, sizeof(buf), f) == (char *)EOF) { + cairo_test_log (ctx, "Error: Unexpected EOF in %s\n", + filename); + break; + } + + if (strncmp (buf, DOCUMENT_BBOX, strlen (DOCUMENT_BBOX)) == 0) { + ret = sscanf (buf+strlen (DOCUMENT_BBOX), "%d %d %d %d", &llx, &lly, &urx, &ury); + if (ret == 4 && llx == LLX && lly == LLY && urx == URX && ury == URY) + bbox_pass = TRUE; + } + + if (strncmp (buf, PAGE_BBOX, strlen (PAGE_BBOX)) == 0) { + ret = sscanf (buf+strlen (PAGE_BBOX), "%d %d %d %d", &llx, &lly, &urx, &ury); + if (ret == 4 && llx == LLX && lly == LLY && urx == URX && ury == URY) + page_bbox_pass = TRUE; + } + } + fclose (f); + + if (!bbox_pass || !page_bbox_pass) { + cairo_test_log (ctx, "Error: EPS Bounding Box does not match reference Bounding Box\n"); + return FALSE; + } + + free (filename); + + return TRUE; +} + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + cairo_t *cr; + cairo_test_status_t ret = CAIRO_TEST_UNTESTED; + unsigned int i; + const char *path = cairo_test_mkdir (CAIRO_TEST_OUTPUT_DIR) ? CAIRO_TEST_OUTPUT_DIR : "."; + + for (i = 0; i < ctx->num_targets; i++) { + const cairo_boilerplate_target_t *target = ctx->targets_to_test[i]; + cairo_surface_t *surface = NULL; + char *base_name; + void *closure; + const char *format; + cairo_status_t status; + cairo_bool_t pass; + char *test_name; + + if (! cairo_test_is_target_enabled (ctx, target->name)) + continue; + + format = cairo_boilerplate_content_name (target->content); + xasprintf (&test_name, "ps-eps"); + xasprintf (&base_name, "%s/ps-eps.%s.%s", + path, target->name, format); + + surface = (target->create_surface) (base_name, + target->content, + WIDTH, HEIGHT, + WIDTH, HEIGHT, + CAIRO_BOILERPLATE_MODE_TEST, + &closure); + + if (surface == NULL) { + free (base_name); + free (test_name); + continue; + } + + cairo_ps_surface_set_eps (surface, TRUE); + if (!cairo_ps_surface_get_eps (surface)) { + cairo_surface_destroy (surface); + if (target->cleanup) + target->cleanup (closure); + + free (base_name); + free (test_name); + continue; + } + + cairo_test_log (ctx, + "Testing ps-eps with %s target\n", + target->name); + printf ("%s:\t", base_name); + fflush (stdout); + + cairo_surface_set_device_offset (surface, 25, 25); + cr = cairo_create (surface); + + cairo_new_sub_path (cr); + cairo_arc (cr, 100, 100, 25, 0, 2*M_PI); + cairo_set_line_width (cr, 10); + cairo_stroke (cr); + + cairo_show_page (cr); + + status = cairo_status (cr); + cairo_destroy (cr); + + if (status) { + cairo_test_log (ctx, "Error: Failed to create target surface: %s\n", + cairo_status_to_string (status)); + pass = FALSE; + } else { + pass = TRUE; + /* extract the image and compare it to our reference */ + if (! check_result (ctx, target, test_name, base_name, surface)) + pass = FALSE; + + /* check the bounding box of the EPS file and compare it to our reference */ + if (! check_bbox (ctx, base_name)) + pass = FALSE; + } + cairo_surface_destroy (surface); + if (target->cleanup) + target->cleanup (closure); + + free (base_name); + free (test_name); + + if (pass) { + printf ("PASS\n"); + ret = CAIRO_TEST_SUCCESS; + } else { + printf ("FAIL\n"); + ret = CAIRO_TEST_FAILURE; + } + fflush (stdout); + } + + return ret; +} + +CAIRO_TEST (ps_eps, + "Check EPS output from PS surface", + "ps, api", /* keywords */ + NULL, /* requirements */ + 0, 0, + preamble, NULL) diff --git a/local/recipes/libs/cairo/source/test/ps-features.c b/local/recipes/libs/cairo/source/test/ps-features.c new file mode 100644 index 0000000000..d1abf91fee --- /dev/null +++ b/local/recipes/libs/cairo/source/test/ps-features.c @@ -0,0 +1,166 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +#include +#include +#include + +/* This test exists to test the various features of cairo-ps.h. + * + * Currently, this test exercises the following function calls: + * + * cairo_ps_surface_set_size + * cairo_ps_surface_dsc_comment + * cairo_ps_surface_dsc_begin_setup + * cairo_ps_surface_dsc_begin_page_setup + */ + +#define INCHES_TO_POINTS(in) ((in) * 72.0) +#define MM_TO_POINTS(mm) ((mm) / 25.4 * 72.0) +#define TEXT_SIZE 12 +#define BASENAME "ps-features.out" + +static struct { + const char *page_size; + const char *page_size_alias; + const char *orientation; + double width_in_points; + double height_in_points; +} pages[] = { + {"na_letter_8.5x11in", "letter", "portrait", + INCHES_TO_POINTS(8.5), INCHES_TO_POINTS(11)}, + {"na_letter_8.5x11in", "letter", "landscape", + INCHES_TO_POINTS(11), INCHES_TO_POINTS(8.5)}, + {"iso_a4_210x297mm", "a4", "portrait", + MM_TO_POINTS(210), MM_TO_POINTS(297)}, + {"iso_a4_210x297mm", "a4", "landscape", + MM_TO_POINTS(297), MM_TO_POINTS(210)}, + {"iso_a5_148x210mm", "a5", "portrait", + MM_TO_POINTS(148), MM_TO_POINTS(210)}, + {"iso_a5_148x210mm", "a5", "landscape", + MM_TO_POINTS(210), MM_TO_POINTS(148)}, + {"iso_a6_105x148mm", "a6", "portrait", + MM_TO_POINTS(105), MM_TO_POINTS(148)}, + {"iso_a6_105x148mm", "a6", "landscape", + MM_TO_POINTS(148), MM_TO_POINTS(105)}, + {"iso_a7_74x105mm", "a7", "portrait", + MM_TO_POINTS(74), MM_TO_POINTS(105)}, + {"iso_a7_74x105mm", "a7", "landscape", + MM_TO_POINTS(105), MM_TO_POINTS(74)}, + {"iso_a8_52x74mm", "a8", "portrait", + MM_TO_POINTS(52), MM_TO_POINTS(74)}, + {"iso_a8_52x74mm", "a8", "landscape", + MM_TO_POINTS(74), MM_TO_POINTS(52)}, + {"iso_a9_37x52mm", "a9", "portrait", + MM_TO_POINTS(37), MM_TO_POINTS(52)}, + {"iso_a9_37x52mm", "a9", "landscape", + MM_TO_POINTS(52), MM_TO_POINTS(37)}, + {"iso_a10_26x37mm", "a10", "portrait", + MM_TO_POINTS(26), MM_TO_POINTS(37)}, + {"iso_a10_26x37mm", "a10", "landscape", + MM_TO_POINTS(37), MM_TO_POINTS(26)} +}; + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + cairo_surface_t *surface; + cairo_t *cr; + cairo_status_t status; + size_t i; + char dsc[255]; + char *filename; + const char *path = cairo_test_mkdir (CAIRO_TEST_OUTPUT_DIR) ? CAIRO_TEST_OUTPUT_DIR : "."; + + if (! (cairo_test_is_target_enabled (ctx, "ps2") || + cairo_test_is_target_enabled (ctx, "ps3"))) + { + return CAIRO_TEST_UNTESTED; + } + + xasprintf (&filename, "%s/%s.ps", path, BASENAME); + /* We demonstrate that the initial size doesn't matter (we're + * passing 0,0), if we use cairo_ps_surface_set_size on the first + * page. */ + surface = cairo_ps_surface_create (filename, 0, 0); + + cairo_ps_surface_dsc_comment (surface, "%%Title: ps-features"); + cairo_ps_surface_dsc_comment (surface, "%%Copyright: Copyright (C) 2006 Red Hat, Inc."); + + cairo_ps_surface_dsc_begin_setup (surface); + cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *PageSize letter"); + cairo_ps_surface_dsc_comment (surface, "%%IncludeFeature: *MediaColor White"); + + cr = cairo_create (surface); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (cr, TEXT_SIZE); + + for (i = 0; i < ARRAY_LENGTH (pages); i++) { + cairo_ps_surface_set_size (surface, + pages[i].width_in_points, + pages[i].height_in_points); + cairo_ps_surface_dsc_begin_page_setup (surface); + snprintf (dsc, 255, "%%IncludeFeature: *PageSize %s", pages[i].page_size_alias); + cairo_ps_surface_dsc_comment (surface, dsc); + if (i % 2) { + snprintf (dsc, 255, "%%IncludeFeature: *MediaType Glossy"); + cairo_ps_surface_dsc_comment (surface, dsc); + } + + cairo_move_to (cr, TEXT_SIZE, TEXT_SIZE); + cairo_show_text (cr, pages[i].page_size); + cairo_show_text (cr, " - "); + cairo_show_text (cr, pages[i].orientation); + cairo_show_page (cr); + } + + status = cairo_status (cr); + + cairo_destroy (cr); + cairo_surface_destroy (surface); + + if (status) { + cairo_test_log (ctx, "Failed to create ps surface for file %s: %s\n", + filename, cairo_status_to_string (status)); + free (filename); + return CAIRO_TEST_FAILURE; + } + + printf ("ps-features: Please check %s to ensure it looks/prints correctly.\n", filename); + free (filename); + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (ps_features, + "Check PS specific API", + "ps, api", /* keywords */ + NULL, /* requirements */ + 0, 0, + preamble, NULL) diff --git a/local/recipes/libs/cairo/source/test/ps-surface-source.c b/local/recipes/libs/cairo/source/test/ps-surface-source.c new file mode 100644 index 0000000000..16c677674c --- /dev/null +++ b/local/recipes/libs/cairo/source/test/ps-surface-source.c @@ -0,0 +1,53 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" +#include + +#include "surface-source.c" + +#define BASENAME "ps-surface-source.out" + +static cairo_surface_t * +create_source_surface (int size) +{ + cairo_surface_t *surface; + char *filename; + const char *path = cairo_test_mkdir (CAIRO_TEST_OUTPUT_DIR) ? CAIRO_TEST_OUTPUT_DIR : "."; + + xasprintf (&filename, "%s/%s.ps", path, BASENAME); + surface = cairo_ps_surface_create (filename, size, size); + cairo_surface_set_fallback_resolution (surface, 72., 72.); + free (filename); + + return surface; +} + +CAIRO_TEST (ps_surface_source, + "Test using a PS surface as the source", + "source", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + preamble, draw) diff --git a/local/recipes/libs/cairo/source/test/ps2png.c b/local/recipes/libs/cairo/source/test/ps2png.c new file mode 100644 index 0000000000..cf98aed3b1 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/ps2png.c @@ -0,0 +1,113 @@ +/* + * Copyright © 2008 Carlos Garcia Campos + * + * 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: Carlos Garcia Campos + */ + +#include +#include +#include +#include + +#define FAIL(msg) \ + do { fprintf (stderr, "FAIL: %s\n", msg); exit (-1); } while (0) + +static const char * +_spectre_render_page (const char *filename, + const char *page_label, + cairo_surface_t **surface_out) +{ + static const cairo_user_data_key_t key; + + SpectreDocument *document; + SpectreStatus status; + int width, height, stride; + unsigned char *pixels; + cairo_surface_t *surface; + + document = spectre_document_new (); + spectre_document_load (document, filename); + status = spectre_document_status (document); + if (status) { + spectre_document_free (document); + return spectre_status_to_string (status); + } + + if (page_label) { + SpectrePage *page; + SpectreRenderContext *rc; + + page = spectre_document_get_page_by_label (document, page_label); + spectre_document_free (document); + if (page == NULL) + return "page not found"; + + spectre_page_get_size (page, &width, &height); + rc = spectre_render_context_new (); + spectre_render_context_set_page_size (rc, width, height); + spectre_page_render (page, rc, &pixels, &stride); + spectre_render_context_free (rc); + status = spectre_page_status (page); + spectre_page_free (page); + if (status) { + free (pixels); + return spectre_status_to_string (status); + } + } else { + spectre_document_get_page_size (document, &width, &height); + spectre_document_render (document, &pixels, &stride); + spectre_document_free (document); + } + + surface = cairo_image_surface_create_for_data (pixels, + CAIRO_FORMAT_RGB24, + width, height, + stride); + cairo_surface_set_user_data (surface, &key, + pixels, (cairo_destroy_func_t) free); + *surface_out = surface; + return NULL; +} + +int main +(int argc, char *argv[]) +{ + const char *err; + cairo_surface_t *surface = NULL; /* silence compiler warning */ + cairo_status_t status; + + if (argc < 3 || argc > 4) + FAIL ("usage: ps2png input_file.ps output_file.png [page]"); + + err = _spectre_render_page (argv[1], argv[3], &surface); + if (err != NULL) + FAIL (err); + + status = cairo_surface_write_to_png (surface, argv[2]); + cairo_surface_destroy (surface); + + if (status != CAIRO_STATUS_SUCCESS) + FAIL (cairo_status_to_string (status)); + + return 0; +} diff --git a/local/recipes/libs/cairo/source/test/pthread-same-source.c b/local/recipes/libs/cairo/source/test/pthread-same-source.c new file mode 100644 index 0000000000..2b26d187dc --- /dev/null +++ b/local/recipes/libs/cairo/source/test/pthread-same-source.c @@ -0,0 +1,192 @@ +/* + * Copyright 2009 Benjamin Otte + * + * 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: Benjamin Otte + */ + +#define GENERATE_REFERENCE 0 + +#include "cairo-test.h" +#if !GENERATE_REFERENCE +#include +#endif + +#define N_THREADS 8 + +#define WIDTH 64 +#define HEIGHT 8 + +typedef struct { + cairo_surface_t *target; + cairo_surface_t *source; + int id; +} thread_data_t; + +static void * +draw_thread (void *arg) +{ + thread_data_t *thread_data = arg; + cairo_surface_t *surface; + cairo_pattern_t *pattern; + cairo_matrix_t pattern_matrix = { 2, 0, 0, 2, 0, 0 }; + cairo_t *cr; + int x, y; + + cr = cairo_create (thread_data->target); + cairo_surface_destroy (thread_data->target); + + pattern = cairo_pattern_create_for_surface (thread_data->source); + cairo_surface_destroy (thread_data->source); + cairo_pattern_set_extend (pattern, thread_data->id % 4); + cairo_pattern_set_filter (pattern, thread_data->id >= 4 ? CAIRO_FILTER_BILINEAR : CAIRO_FILTER_NEAREST); + cairo_pattern_set_matrix (pattern, &pattern_matrix); + + for (y = 0; y < HEIGHT; y++) { + for (x = 0; x < WIDTH; x++) { + cairo_save (cr); + cairo_translate (cr, 4 * x + 1, 4 * y + 1); + cairo_rectangle (cr, 0, 0, 2, 2); + cairo_set_source (cr, pattern); + cairo_fill (cr); + cairo_restore (cr); + } + } + cairo_pattern_destroy (pattern); + + surface = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + + return surface; +} + +static cairo_surface_t * +create_source (cairo_surface_t *similar) +{ + cairo_surface_t *source; + cairo_t *cr; + double colors[4][3] = { + { 0.75, 0, 0 }, + { 0, 0.75, 0 }, + { 0, 0, 0.75 }, + { 0.75, 0.75, 0 } + }; + int i; + + source = cairo_surface_create_similar (similar, + CAIRO_CONTENT_COLOR_ALPHA, + 2, 2); + + cr = cairo_create (source); + cairo_surface_destroy (source); + + for (i = 0; i < 4; i++) { + cairo_set_source_rgb (cr, colors[i][0], colors[i][1], colors[i][2]); + cairo_rectangle (cr, i % 2, i / 2, 1, 1); + cairo_fill (cr); + } + + source = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + + return source; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ +#if !GENERATE_REFERENCE + pthread_t threads[N_THREADS]; +#endif + thread_data_t thread_data[N_THREADS]; + cairo_test_status_t test_status = CAIRO_TEST_SUCCESS; + cairo_surface_t *source; + cairo_status_t status; + int i; + + source = create_source (cairo_get_target (cr)); + status = cairo_surface_status (source); + if (status) { + cairo_surface_destroy (source); + return cairo_test_status_from_status (cairo_test_get_context (cr), + status); + } + + cairo_set_source_rgb (cr, 0.5, 0.5, 0.5); + cairo_paint (cr); + + for (i = 0; i < N_THREADS; i++) { + thread_data[i].target = cairo_surface_create_similar (cairo_get_target (cr), + CAIRO_CONTENT_COLOR_ALPHA, + 4 * WIDTH, 4 * HEIGHT); + thread_data[i].source = cairo_surface_reference (source); + thread_data[i].id = i; +#if !GENERATE_REFERENCE + if (pthread_create (&threads[i], NULL, draw_thread, &thread_data[i]) != 0) { + threads[i] = pthread_self (); /* to indicate error */ + cairo_surface_destroy (thread_data[i].target); + cairo_surface_destroy (thread_data[i].source); + test_status = CAIRO_TEST_FAILURE; + break; + } +#else + { + cairo_surface_t *surface = draw_thread(&thread_data[i]); + cairo_set_source_surface (cr, surface, 0, 0); + cairo_surface_destroy (surface); + cairo_paint (cr); + + cairo_translate (cr, 0, 4 * HEIGHT); + } +#endif + } + + cairo_surface_destroy (source); + +#if !GENERATE_REFERENCE + for (i = 0; i < N_THREADS; i++) { + void *surface; + + if (pthread_equal (threads[i], pthread_self ())) + break; + + if (pthread_join (threads[i], &surface) == 0) { + cairo_set_source_surface (cr, surface, 0, 0); + cairo_surface_destroy (surface); + cairo_paint (cr); + + cairo_translate (cr, 0, 4 * HEIGHT); + } else { + test_status = CAIRO_TEST_FAILURE; + } + } +#endif + + return test_status; +} + +CAIRO_TEST (pthread_same_source, + "Use the same source for drawing in different threads", + "threads", /* keywords */ + NULL, /* requirements */ + 4 * WIDTH, 4 * HEIGHT * N_THREADS, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/pthread-show-text.c b/local/recipes/libs/cairo/source/test/pthread-show-text.c new file mode 100644 index 0000000000..0f076cb61e --- /dev/null +++ b/local/recipes/libs/cairo/source/test/pthread-show-text.c @@ -0,0 +1,142 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +/* Test case for bug #4299: + + Assertion fails in "cairo-font.c" when using multithreads + https://bugs.freedesktop.org/show_bug.cgi?id=4299 +*/ + +#include "cairo-test.h" + +#include +#include +#include + +#define N_THREADS 8 +#define NUM_ITERATIONS 40 + +#define WIDTH 400 +#define HEIGHT 42 + +typedef struct { + cairo_surface_t *target; + int id; +} thread_data_t; + +static void * +draw_thread (void *arg) +{ + const char *text = "Hello world. "; + thread_data_t *thread_data = arg; + cairo_surface_t *surface; + cairo_font_extents_t extents; + cairo_t *cr; + int i; + + cr = cairo_create (thread_data->target); + cairo_surface_destroy (thread_data->target); + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Serif", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (cr, NUM_ITERATIONS); + cairo_font_extents (cr, &extents); + + cairo_move_to (cr, 1, HEIGHT - extents.descent - 1); + + for (i = 0; i < NUM_ITERATIONS; i++) { + char buf[2]; + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Serif", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (cr, i); + + buf[0] = text[i%strlen(text)]; + buf[1] = '\0'; + cairo_show_text (cr, buf); + } + + surface = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + + return surface; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + pthread_t threads[N_THREADS]; + thread_data_t thread_data[N_THREADS]; + cairo_test_status_t test_status = CAIRO_TEST_SUCCESS; + int i; + + for (i = 0; i < N_THREADS; i++) { + thread_data[i].target = cairo_surface_create_similar (cairo_get_target (cr), + cairo_surface_get_content (cairo_get_target (cr)), + WIDTH, HEIGHT); + thread_data[i].id = i; + if (pthread_create (&threads[i], NULL, draw_thread, &thread_data[i]) != 0) { + threads[i] = pthread_self (); /* to indicate error */ + cairo_surface_destroy (thread_data[i].target); + test_status = CAIRO_TEST_FAILURE; + break; + } + } + + cairo_set_source_rgb (cr, 0.5, 0.5, 0.5); + cairo_paint (cr); + + for (i = 0; i < N_THREADS; i++) { + void *surface; + + if (pthread_equal (threads[i], pthread_self ())) + break; + + if (pthread_join (threads[i], &surface) == 0) { + cairo_set_source_surface (cr, surface, 0, 0); + cairo_surface_destroy (surface); + cairo_paint (cr); + + cairo_translate (cr, 0, HEIGHT); + } else { + test_status = CAIRO_TEST_FAILURE; + } + } + + return test_status; +} + +CAIRO_TEST (pthread_show_text, + "Concurrent stress test of the cairo_show_text().", + "thread, text", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT * N_THREADS, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/pthread-similar.c b/local/recipes/libs/cairo/source/test/pthread-similar.c new file mode 100644 index 0000000000..a5f5e3bf4c --- /dev/null +++ b/local/recipes/libs/cairo/source/test/pthread-similar.c @@ -0,0 +1,106 @@ +/* + * Copyright 2009 Benjamin Otte + * + * 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: Benjamin Otte + */ + +#include "cairo-test.h" +#include + +#define N_THREADS 8 + +#define WIDTH 64 +#define HEIGHT 8 + +static void * +draw_thread (void *arg) +{ + cairo_surface_t *surface = arg; + cairo_t *cr; + int x, y; + + cr = cairo_create (surface); + cairo_surface_destroy (surface); + + for (y = 0; y < HEIGHT; y++) { + for (x = 0; x < WIDTH; x++) { + cairo_rectangle (cr, x, y, 1, 1); + cairo_set_source_rgba (cr, 0, 0.75, 0.75, (double) x / WIDTH); + cairo_fill (cr); + } + } + + surface = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + + return surface; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + pthread_t threads[N_THREADS]; + cairo_test_status_t test_status = CAIRO_TEST_SUCCESS; + int i; + + for (i = 0; i < N_THREADS; i++) { + cairo_surface_t *surface; + + surface = cairo_surface_create_similar (cairo_get_target (cr), + CAIRO_CONTENT_COLOR, + WIDTH, HEIGHT); + if (pthread_create (&threads[i], NULL, draw_thread, surface) != 0) { + threads[i] = pthread_self (); + test_status = cairo_test_status_from_status (cairo_test_get_context (cr), + cairo_surface_status (surface)); + cairo_surface_destroy (surface); + break; + } + } + + for (i = 0; i < N_THREADS; i++) { + void *surface; + + if (pthread_equal (threads[i], pthread_self ())) + break; + + if (pthread_join (threads[i], &surface) == 0) { + cairo_set_source_surface (cr, surface, 0, 0); + cairo_surface_destroy (surface); + cairo_paint (cr); + + cairo_translate (cr, 0, HEIGHT); + } else { + test_status = CAIRO_TEST_FAILURE; + } + } + + return test_status; +} + +CAIRO_TEST (pthread_similar, + "Draw lots of 1x1 rectangles on similar surfaces in lots of threads", + "threads", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT * N_THREADS, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/push-group-color.c b/local/recipes/libs/cairo/source/test/push-group-color.c new file mode 100644 index 0000000000..1bc5bca9b0 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/push-group-color.c @@ -0,0 +1,141 @@ +/* + * Copyright © 2005 Mozilla Corporation + * Copyright © 2009 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Mozilla Corporation not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Mozilla Corporation makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * MOZILLA CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL MOZILLA CORPORATION BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Vladimir Vukicevic + * Chris Wilson + */ + +#include "cairo-test.h" + +#define UNIT_SIZE 100 +#define PAD 5 +#define INNER_PAD 10 + +#define WIDTH (UNIT_SIZE + PAD) + PAD +#define HEIGHT (UNIT_SIZE + PAD) + PAD + +static cairo_pattern_t * +argb32_source (void) +{ + cairo_surface_t *surface; + cairo_pattern_t *pattern; + cairo_t *cr; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 16, 16); + cr = cairo_create (surface); + cairo_surface_destroy (surface); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_rectangle (cr, 8, 0, 8, 8); + cairo_fill (cr); + + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_rectangle (cr, 0, 8, 8, 8); + cairo_fill (cr); + + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_rectangle (cr, 8, 8, 8, 8); + cairo_fill (cr); + + pattern = cairo_pattern_create_for_surface (cairo_get_target (cr)); + cairo_destroy (cr); + + return pattern; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *gradient, *image; + + cairo_set_source_rgb (cr, 1,1,1); + cairo_paint (cr); + + cairo_translate (cr, PAD, PAD); + + /* clip to the unit size */ + cairo_rectangle (cr, 0, 0, + UNIT_SIZE, UNIT_SIZE); + cairo_clip (cr); + + cairo_rectangle (cr, 0, 0, + UNIT_SIZE, UNIT_SIZE); + cairo_set_source_rgba (cr, 0, 0, 0, 1); + cairo_set_line_width (cr, 2); + cairo_stroke (cr); + + /* start a group */ + cairo_push_group_with_content (cr, CAIRO_CONTENT_COLOR); + + /* draw a gradient background */ + cairo_save (cr); + cairo_translate (cr, INNER_PAD, INNER_PAD); + cairo_new_path (cr); + cairo_rectangle (cr, 0, 0, + UNIT_SIZE - (INNER_PAD*2), UNIT_SIZE - (INNER_PAD*2)); + gradient = cairo_pattern_create_linear (UNIT_SIZE - (INNER_PAD*2), 0, + UNIT_SIZE - (INNER_PAD*2), UNIT_SIZE - (INNER_PAD*2)); + cairo_pattern_add_color_stop_rgba (gradient, 0.0, 0.3, 0.3, 0.3, 1.0); + cairo_pattern_add_color_stop_rgba (gradient, 1.0, 1.0, 1.0, 1.0, 1.0); + cairo_set_source (cr, gradient); + cairo_pattern_destroy (gradient); + cairo_fill (cr); + cairo_restore (cr); + + /* draw diamond */ + cairo_move_to (cr, UNIT_SIZE / 2, 0); + cairo_line_to (cr, UNIT_SIZE , UNIT_SIZE / 2); + cairo_line_to (cr, UNIT_SIZE / 2, UNIT_SIZE); + cairo_line_to (cr, 0 , UNIT_SIZE / 2); + cairo_close_path (cr); + cairo_set_source_rgba (cr, 0, 0, 1, 1); + cairo_fill (cr); + + /* draw circle */ + cairo_arc (cr, + UNIT_SIZE / 2, UNIT_SIZE / 2, + UNIT_SIZE / 3.5, + 0, M_PI * 2); + cairo_set_source_rgba (cr, 1, 0, 0, 1); + cairo_fill (cr); + + /* and put the image on top */ + cairo_translate (cr, UNIT_SIZE/2 - 8, UNIT_SIZE/2 - 8); + image = argb32_source (); + cairo_set_source (cr, image); + cairo_pattern_destroy (image); + cairo_paint (cr); + + cairo_pop_group_to_source (cr); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (push_group_color, + "Verify that cairo_push_group_with_content works.", + "group", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/push-group-path-offset.c b/local/recipes/libs/cairo/source/test/push-group-path-offset.c new file mode 100644 index 0000000000..6b73ca4fa3 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/push-group-path-offset.c @@ -0,0 +1,77 @@ +/* + * Copyright 2010 Red Hat Inc. + * + * 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: Benjamin Otte + */ + +#include "cairo-test.h" + +#define CLIP_OFFSET 15 +#define CLIP_SIZE 20 + +#define WIDTH 50 +#define HEIGHT 50 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + /* Neutral gray background */ + cairo_set_source_rgb (cr, 0.51613, 0.55555, 0.51613); + cairo_paint (cr); + + /* the rest uses CAIRO_OPERATOR_SOURCE so we see better when something goes wrong */ + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + + /* add a rectangle */ + cairo_rectangle (cr, CLIP_OFFSET, CLIP_OFFSET, CLIP_SIZE, CLIP_SIZE); + + /* clip to the rectangle */ + cairo_clip_preserve (cr); + + /* push a group. We now have a device offset. */ + cairo_push_group (cr); + + /* push a group again. This is where the bug used to happen. */ + cairo_push_group (cr); + + /* draw something */ + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_fill_preserve (cr); + + /* make sure the stuff we drew ends up on the output */ + cairo_pop_group_to_source (cr); + cairo_fill_preserve (cr); + + cairo_pop_group_to_source (cr); + cairo_fill_preserve (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (push_group_path_offset, + "Exercises a bug in Cairo 1.9 where existing paths applied the target's" + " device offset twice when cairo_push_group() was called.", + "group, path", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/push-group.c b/local/recipes/libs/cairo/source/test/push-group.c new file mode 100644 index 0000000000..8e6ce19245 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/push-group.c @@ -0,0 +1,113 @@ +/* + * Copyright © 2005 Mozilla Corporation + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Mozilla Corporation not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Mozilla Corporation makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * MOZILLA CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL MOZILLA CORPORATION BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Vladimir Vukicevic + */ + +#include "cairo-test.h" + +#define UNIT_SIZE 100 +#define PAD 5 +#define INNER_PAD 10 + +#define WIDTH (UNIT_SIZE + PAD) + PAD +#define HEIGHT (UNIT_SIZE + PAD) + PAD + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *gradient; + int i, j; + + gradient = cairo_pattern_create_linear (UNIT_SIZE - (INNER_PAD*2), 0, + UNIT_SIZE - (INNER_PAD*2), UNIT_SIZE - (INNER_PAD*2)); + cairo_pattern_add_color_stop_rgba (gradient, 0.0, 0.3, 0.3, 0.3, 1.0); + cairo_pattern_add_color_stop_rgba (gradient, 1.0, 1.0, 1.0, 1.0, 1.0); + + for (j = 0; j < 1; j++) { + for (i = 0; i < 1; i++) { + double x = (i * UNIT_SIZE) + (i + 1) * PAD; + double y = (j * UNIT_SIZE) + (j + 1) * PAD; + + cairo_save (cr); + + cairo_translate (cr, x, y); + + /* draw a gradient background */ + cairo_save (cr); + cairo_translate (cr, INNER_PAD, INNER_PAD); + cairo_new_path (cr); + cairo_rectangle (cr, 0, 0, + UNIT_SIZE - (INNER_PAD*2), UNIT_SIZE - (INNER_PAD*2)); + cairo_set_source (cr, gradient); + cairo_fill (cr); + cairo_restore (cr); + + /* clip to the unit size */ + cairo_rectangle (cr, 0, 0, + UNIT_SIZE, UNIT_SIZE); + cairo_clip (cr); + + cairo_rectangle (cr, 0, 0, + UNIT_SIZE, UNIT_SIZE); + cairo_set_source_rgba (cr, 0, 0, 0, 1); + cairo_set_line_width (cr, 2); + cairo_stroke (cr); + + /* start a group */ + cairo_push_group (cr); + + /* draw diamond */ + cairo_move_to (cr, UNIT_SIZE / 2, 0); + cairo_line_to (cr, UNIT_SIZE , UNIT_SIZE / 2); + cairo_line_to (cr, UNIT_SIZE / 2, UNIT_SIZE); + cairo_line_to (cr, 0 , UNIT_SIZE / 2); + cairo_close_path (cr); + cairo_set_source_rgba (cr, 0, 0, 1, 1); + cairo_fill (cr); + + /* draw circle */ + cairo_arc (cr, + UNIT_SIZE / 2, UNIT_SIZE / 2, + UNIT_SIZE / 3.5, + 0, M_PI * 2); + cairo_set_source_rgba (cr, 1, 0, 0, 1); + cairo_fill (cr); + + cairo_pop_group_to_source (cr); + cairo_paint_with_alpha (cr, 0.5); + + cairo_restore (cr); + } + } + + cairo_pattern_destroy (gradient); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (push_group, + "Verify that cairo_push_group works.", + "group", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/quad-color.png b/local/recipes/libs/cairo/source/test/quad-color.png new file mode 100644 index 0000000000..0d68a82cc2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/quad-color.png differ diff --git a/local/recipes/libs/cairo/source/test/quartz-color-font.c b/local/recipes/libs/cairo/source/test/quartz-color-font.c new file mode 100644 index 0000000000..7dae214f64 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/quartz-color-font.c @@ -0,0 +1,54 @@ +/* + * Copyright © 2022 John Ralls + * + * 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. + * + */ + +#include "cairo-test.h" +#include + +#define WIDTH 100 +#define HEIGHT 50 + +#define FONT "Apple Color Emoji" + +static const char smiley_face_utf8[] = { 0xf0, 0x9f, 0x99, 0x82, 0x00 }; /* U+1F642 */ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_select_font_face(cr, FONT, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (cr, HEIGHT/2); + cairo_move_to (cr, width/5, 2*height/3); + + cairo_show_text(cr, smiley_face_utf8); + cairo_show_text(cr, smiley_face_utf8); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (quartz_color_font, + "Test color font", + "quartz, font", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/quartz-surface-source.c b/local/recipes/libs/cairo/source/test/quartz-surface-source.c new file mode 100644 index 0000000000..b0c86d0f9a --- /dev/null +++ b/local/recipes/libs/cairo/source/test/quartz-surface-source.c @@ -0,0 +1,42 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" +#include "cairo-quartz.h" + +#include "surface-source.c" + +static cairo_surface_t * +create_source_surface (int size) +{ + return cairo_quartz_surface_create (CAIRO_FORMAT_ARGB32, size, size); +} + +CAIRO_TEST (quartz_surface_source, + "Test using a Quartz surface as the source", + "source", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + preamble, draw) diff --git a/local/recipes/libs/cairo/source/test/radial-gradient-extend.c b/local/recipes/libs/cairo/source/test/radial-gradient-extend.c new file mode 100644 index 0000000000..c32a2c37b2 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/radial-gradient-extend.c @@ -0,0 +1,92 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright 2010 Andrea Canciani + * + * 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: Andrea Canciani + */ + +#include "cairo-test.h" + +#define NUM_EXTEND 4 +#define HEIGHT 16 +#define WIDTH 16 +#define PAD 3 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *pattern; + unsigned int i, j; + + cairo_extend_t extend[NUM_EXTEND] = { + CAIRO_EXTEND_NONE, + CAIRO_EXTEND_REPEAT, + CAIRO_EXTEND_REFLECT, + CAIRO_EXTEND_PAD + }; + + cairo_test_paint_checkered (cr); + + pattern = cairo_pattern_create_radial (WIDTH / 2, HEIGHT / 2, 0, WIDTH / 2, HEIGHT / 2, 2 * PAD); + + cairo_pattern_add_color_stop_rgb (pattern, 0, 0, 0, 1); + cairo_pattern_add_color_stop_rgb (pattern, 1, 0, 0, 1); + + cairo_translate (cr, PAD, PAD); + + for (i = 0; i < 2; i++) { + cairo_save (cr); + + for (j = 0; j < NUM_EXTEND; j++) { + cairo_pattern_set_extend (pattern, extend[j]); + + cairo_reset_clip (cr); + cairo_rectangle (cr, 0, 0, WIDTH, HEIGHT); + cairo_clip (cr); + + if (i & 1) { + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_mask (cr, pattern); + } else { + cairo_set_source (cr, pattern); + cairo_paint (cr); + } + + cairo_translate (cr, WIDTH+PAD, 0); + } + + cairo_restore (cr); + cairo_translate (cr, 0, HEIGHT+PAD); + } + + cairo_pattern_destroy (pattern); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (radial_gradient_extend, + "Tests gradient to solid reduction of radial gradients", + "radial, pattern, extend", /* keywords */ + NULL, /* requirements */ + (WIDTH+PAD) * NUM_EXTEND + PAD, 2*(HEIGHT + PAD) + PAD, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/radial-gradient.c b/local/recipes/libs/cairo/source/test/radial-gradient.c new file mode 100644 index 0000000000..026876b1b9 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/radial-gradient.c @@ -0,0 +1,256 @@ +/* + * Copyright © 2005, 2007 Red Hat, Inc. + * + * 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: Carl D. Worth + */ + +#include "cairo-test.h" + +#define NUM_GRADIENTS 7 +#define NUM_EXTEND 4 +#define SIZE 120 +#define WIDTH (SIZE * NUM_GRADIENTS) +#define HEIGHT (SIZE * NUM_EXTEND) + +typedef void (*composite_t)(cairo_t *cr, cairo_pattern_t *pattern); +typedef void (*add_stops_t)(cairo_pattern_t *pattern); + +/* + * We want to test all the possible relative positions of the start + * and end circle: + * + * - The start circle can be smaller/equal/bigger than the end + * circle. A radial gradient can be classified in one of these + * three cases depending on the sign of dr. + * + * - The smaller circle can be completely inside/internally + * tangent/outside (at least in part) of the bigger circle. This + * classification is the same as the one which can be computed by + * examining the sign of a = (dx^2 + dy^2 - dr^2). + * + * - If the two circles have the same size, neither can be inside or + * internally tangent + * + * This test draws radial gradients whose circles always have the same + * centers (0, 0) and (1, 0), but with different radiuses. From left + * to right: + * + * - Small start circle completely inside the end circle + * 0.25 -> 1.75; dr = 1.5 > 0; a = 1 - 1.50^2 < 0 + * + * - Small start circle internally tangent to the end circle + * 0.50 -> 1.50; dr = 1.0 > 0; a = 1 - 1.00^2 = 0 + * + * - Small start circle outside of the end circle + * 0.50 -> 1.00; dr = 0.5 > 0; a = 1 - 0.50^2 > 0 + * + * - Start circle with the same size as the end circle + * 1.00 -> 1.00; dr = 0.0 = 0; a = 1 - 0.00^2 > 0 + * + * - Small end circle outside of the start circle + * 1.00 -> 0.50; dr = -0.5 > 0; a = 1 - 0.50^2 > 0 + * + * - Small end circle internally tangent to the start circle + * 1.50 -> 0.50; dr = -1.0 > 0; a = 1 - 1.00^2 = 0 + * + * - Small end circle completely inside the start circle + * 1.75 -> 0.25; dr = -1.5 > 0; a = 1 - 1.50^2 < 0 + * + */ + +static const double radiuses[NUM_GRADIENTS] = { + 0.25, + 0.50, + 0.50, + 1.00, + 1.00, + 1.50, + 1.75 +}; + +static cairo_pattern_t * +create_pattern (int index) +{ + double x0, x1, radius0, radius1, left, right, center; + + x0 = 0; + x1 = 1; + radius0 = radiuses[index]; + radius1 = radiuses[NUM_GRADIENTS - index - 1]; + + /* center the gradient */ + left = MIN (x0 - radius0, x1 - radius1); + right = MAX (x0 + radius0, x1 + radius1); + center = (left + right) * 0.5; + x0 -= center; + x1 -= center; + + /* scale to make it fit within a 1x1 rect centered in (0,0) */ + x0 *= 0.25; + x1 *= 0.25; + radius0 *= 0.25; + radius1 *= 0.25; + + return cairo_pattern_create_radial (x0, 0, radius0, x1, 0, radius1); +} + +static void +pattern_add_stops (cairo_pattern_t *pattern) +{ + cairo_pattern_add_color_stop_rgba (pattern, 0.0, 1, 0, 0, 0.75); + cairo_pattern_add_color_stop_rgba (pattern, sqrt (0.5), 0, 1, 0, 0); + cairo_pattern_add_color_stop_rgba (pattern, 1.0, 0, 0, 1, 1); +} + +static void +pattern_add_single_stop (cairo_pattern_t *pattern) +{ + cairo_pattern_add_color_stop_rgba (pattern, 0.25, 1, 0, 0, 1); +} + + +static cairo_test_status_t +draw (cairo_t *cr, add_stops_t add_stops, composite_t composite) +{ + int i, j; + cairo_extend_t extend[NUM_EXTEND] = { + CAIRO_EXTEND_NONE, + CAIRO_EXTEND_REPEAT, + CAIRO_EXTEND_REFLECT, + CAIRO_EXTEND_PAD + }; + + cairo_scale (cr, SIZE, SIZE); + cairo_translate (cr, 0.5, 0.5); + + for (j = 0; j < NUM_EXTEND; j++) { + cairo_save (cr); + for (i = 0; i < NUM_GRADIENTS; i++) { + cairo_pattern_t *pattern; + + pattern = create_pattern (i); + add_stops (pattern); + cairo_pattern_set_extend (pattern, extend[j]); + + cairo_save (cr); + cairo_rectangle (cr, -0.5, -0.5, 1, 1); + cairo_clip (cr); + composite (cr, pattern); + cairo_restore (cr); + cairo_pattern_destroy (pattern); + + cairo_translate (cr, 1, 0); + } + cairo_restore (cr); + cairo_translate (cr, 0, 1); + } + + return CAIRO_TEST_SUCCESS; +} + + +static void +composite_simple (cairo_t *cr, cairo_pattern_t *pattern) +{ + cairo_set_source (cr, pattern); + cairo_paint (cr); +} + +static void +composite_mask (cairo_t *cr, cairo_pattern_t *pattern) +{ + cairo_set_source_rgb (cr, 1, 0, 1); + cairo_mask (cr, pattern); +} + + +static cairo_test_status_t +draw_simple (cairo_t *cr, int width, int height) +{ + cairo_test_paint_checkered (cr); + return draw (cr, pattern_add_stops, composite_simple); +} + +static cairo_test_status_t +draw_mask (cairo_t *cr, int width, int height) +{ + cairo_test_paint_checkered (cr); + return draw (cr, pattern_add_stops, composite_mask); +} + +static cairo_test_status_t +draw_source (cairo_t *cr, int width, int height) +{ + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + return draw (cr, pattern_add_stops, composite_simple); +} + + +static cairo_test_status_t +draw_mask_source (cairo_t *cr, int width, int height) +{ + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + return draw (cr, pattern_add_stops, composite_mask); +} + +static cairo_test_status_t +draw_one_stop (cairo_t *cr, int width, int height) +{ + cairo_test_paint_checkered (cr); + return draw (cr, pattern_add_single_stop, composite_simple); +} + +CAIRO_TEST (radial_gradient, + "Simple test of radial gradients", + "gradient", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw_simple) + +CAIRO_TEST (radial_gradient_mask, + "Simple test of radial gradients using a MASK", + "gradient,mask", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw_mask) + +CAIRO_TEST (radial_gradient_source, + "Simple test of radial gradients using the SOURCE operator", + "gradient,source", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw_source) + +CAIRO_TEST (radial_gradient_mask_source, + "Simple test of radial gradients using a MASK with a SOURCE operator", + "gradient,mask,source", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw_mask_source) + +CAIRO_TEST (radial_gradient_one_stop, + "Tests radial gradients with a single stop", + "gradient,radial", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw_one_stop) diff --git a/local/recipes/libs/cairo/source/test/radial-outer-focus.c b/local/recipes/libs/cairo/source/test/radial-outer-focus.c new file mode 100644 index 0000000000..e038947451 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/radial-outer-focus.c @@ -0,0 +1,72 @@ +/* + * 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: Krzysztof Kosi\u0144ski + */ + +/* Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=40918 */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *radial; + double angle; + int i, j; + + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_paint (cr); + + angle = 0.0; + + for (i = 0; i < 4; i++) { + for (j = 0; j < 4; j++) { + cairo_save (cr); + cairo_rectangle (cr, 100*i, 100*j, 100, 100); + cairo_clip (cr); + + radial = cairo_pattern_create_radial (cos (angle), sin (angle), 0, + 0, 0, 1); + cairo_pattern_add_color_stop_rgb (radial, 0.0, 1, 0, 0); + cairo_pattern_add_color_stop_rgb (radial, 1.0, 0, 1, 0); + + cairo_translate (cr, 100*i+50, 100*j+50); + cairo_scale (cr, 50, -50); + cairo_set_source (cr, radial); + cairo_pattern_destroy (radial); + + cairo_paint(cr); + cairo_restore (cr); + + angle += M_PI/17; + } + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (radial_outer_focus, + "Exercises the condition of rendering a radial gradial on its outer focus", + "radial", /* keywords */ + NULL, /* requirements */ + 400, 400, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/random-clips.c b/local/recipes/libs/cairo/source/test/random-clips.c new file mode 100644 index 0000000000..31d7d6df04 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/random-clips.c @@ -0,0 +1,232 @@ +/* + * Copyright © 2006 M Joonas Pihlaja + * Copyright © 2011 Chris Wilson + * + * 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. + * + * Authors: + * M Joonas Pihlaja + * Chris Wilson + */ +#include "cairo-test.h" + +#define SIZE 512 +#define STEP (512+2) +#define NUM_SEGMENTS 128 + +static uint32_t state; + +static double +uniform_random (double minval, double maxval) +{ + static uint32_t const poly = 0x9a795537U; + uint32_t n = 32; + while (n-->0) + state = 2*state < state ? (2*state ^ poly) : 2*state; + return minval + state * (maxval - minval) / 4294967296.0; +} + +static void nz_path (cairo_t *cr) +{ + int i; + + state = 0xc0ffee; + + cairo_move_to (cr, 0, 0); + for (i = 0; i < NUM_SEGMENTS; i++) { + double x = uniform_random (0, SIZE); + double y = uniform_random (0, SIZE); + cairo_line_to (cr, x, y); + } + cairo_close_path (cr); +} + +static void region_path (cairo_t *cr) +{ + int i; + + state = 0xc0ffee; + + for (i = 0; i < NUM_SEGMENTS; i++) { + int x = uniform_random (0, SIZE); + int y = uniform_random (0, SIZE); + int w = uniform_random (0, 40); + int h = uniform_random (0, 40); + cairo_rectangle (cr, x, y, w, h); + } +} + +static void rectangle_path (cairo_t *cr) +{ + int i; + + state = 0xc0ffee; + + for (i = 0; i < NUM_SEGMENTS; i++) { + double x = uniform_random (0, SIZE); + double y = uniform_random (0, SIZE); + double w = uniform_random (0, 40); + double h = uniform_random (0, 40); + cairo_rectangle (cr, x, y, w, h); + } +} + +static void arc_path (cairo_t *cr) +{ + int i; + + state = 0xc0ffee; + + for (i = 0; i < NUM_SEGMENTS; i++) { + double x = uniform_random (0, SIZE); + double y = uniform_random (0, SIZE); + double r = uniform_random (0, 20); + cairo_new_sub_path (cr); + cairo_arc (cr, x, y, r, 0, 2*M_PI); + } +} + + +static void nz_fill_stroke (cairo_t *cr) +{ + nz_path (cr); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_fill_preserve (cr); + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_set_line_width (cr, 1.0); + cairo_stroke (cr); +} + +static void clip_to_quadrant (cairo_t *cr) +{ + cairo_rectangle (cr, 0, 0, SIZE, SIZE); + cairo_clip (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_WINDING); + + state = 0xc0ffee; + cairo_translate (cr, 1, 1); + + /* no clipping */ + cairo_save (cr); { + clip_to_quadrant (cr); + + nz_fill_stroke (cr); + } cairo_restore (cr); + + cairo_translate (cr, STEP, 0); + + /* random clipping */ + cairo_save (cr); { + clip_to_quadrant (cr); + + nz_path (cr); + cairo_clip (cr); + + nz_fill_stroke (cr); + + cairo_set_source_rgba (cr, 1, 1, 1, 0.5); + cairo_paint (cr); + } cairo_restore (cr); + + cairo_translate (cr, STEP, 0); + + /* regional clipping */ + cairo_save (cr); { + clip_to_quadrant (cr); + + region_path (cr); + cairo_clip (cr); + + nz_fill_stroke (cr); + + cairo_set_source_rgba (cr, 1, 1, 1, 0.5); + cairo_paint (cr); + } cairo_restore (cr); + + cairo_translate (cr, -2*STEP, STEP); + + /* rectangular clipping */ + cairo_save (cr); { + clip_to_quadrant (cr); + + rectangle_path (cr); + cairo_clip (cr); + + nz_fill_stroke (cr); + + cairo_set_source_rgba (cr, 1, 1, 1, 0.5); + cairo_paint (cr); + } cairo_restore (cr); + + cairo_translate (cr, STEP, 0); + + /* circular clipping */ + cairo_save (cr); { + clip_to_quadrant (cr); + + arc_path (cr); + cairo_clip (cr); + + nz_fill_stroke (cr); + + cairo_set_source_rgba (cr, 1, 1, 1, 0.5); + cairo_paint (cr); + } cairo_restore (cr); + + cairo_translate (cr, STEP, 0); + + /* all-of-the-above clipping */ + cairo_save (cr); { + clip_to_quadrant (cr); + + nz_path (cr); + cairo_clip (cr); + region_path (cr); + cairo_clip (cr); + rectangle_path (cr); + cairo_clip (cr); + arc_path (cr); + cairo_clip (cr); + + nz_fill_stroke (cr); + + cairo_set_source_rgba (cr, 1, 1, 1, 0.5); + cairo_paint (cr); + } cairo_restore (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (random_clip, + "Tests the clip generation and intersection computation", + "trap, clip", /* keywords */ + NULL, /* requirements */ + 3*STEP+2, 2*STEP+2, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/random-intersections-curves-eo.c b/local/recipes/libs/cairo/source/test/random-intersections-curves-eo.c new file mode 100644 index 0000000000..84e9a75ded --- /dev/null +++ b/local/recipes/libs/cairo/source/test/random-intersections-curves-eo.c @@ -0,0 +1,84 @@ +/* + * Copyright © 2006 M Joonas Pihlaja + * + * 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: M Joonas Pihlaja + */ +#include "cairo-test.h" + +#define SIZE 512 +#define NUM_SEGMENTS 128 + +static uint32_t state; + +static double +uniform_random (double minval, double maxval) +{ + static uint32_t const poly = 0x9a795537U; + uint32_t n = 32; + while (n-->0) + state = 2*state < state ? (2*state ^ poly) : 2*state; + return minval + state * (maxval - minval) / 4294967296.0; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + int i; + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + state = 0x12345678; + cairo_translate (cr, 1, 1); + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + + cairo_move_to (cr, 0, 0); + for (i = 0; i < NUM_SEGMENTS; i++) { + double y3 = uniform_random (0, SIZE); + double x3 = uniform_random (0, SIZE); + double y2 = uniform_random (-SIZE, SIZE); + double x2 = uniform_random (-SIZE, SIZE); + double y1 = uniform_random (-SIZE, SIZE); + double x1 = uniform_random (-SIZE, SIZE); + cairo_curve_to (cr, + x1, y1, + x2, y2, + x3, y3); + } + cairo_close_path (cr); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_fill_preserve (cr); + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_set_line_width (cr, 0.5); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (random_intersections_curves_eo, + "Tests the tessellator trapezoid generation and intersection computation", + "trap", /* keywords */ + NULL, /* requirements */ + SIZE+3, SIZE+3, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/random-intersections-curves-nz.c b/local/recipes/libs/cairo/source/test/random-intersections-curves-nz.c new file mode 100644 index 0000000000..5265e4a730 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/random-intersections-curves-nz.c @@ -0,0 +1,85 @@ +/* + * Copyright © 2006 M Joonas Pihlaja + * + * 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: M Joonas Pihlaja + */ +#include "cairo-test.h" + +#define SIZE 512 +#define NUM_SEGMENTS 128 + +static uint32_t state; + +static double +uniform_random (double minval, double maxval) +{ + static uint32_t const poly = 0x9a795537U; + uint32_t n = 32; + while (n-->0) + state = 2*state < state ? (2*state ^ poly) : 2*state; + return minval + state * (maxval - minval) / 4294967296.0; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + int i; + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + state = 0x12345678; + cairo_translate (cr, 1, 1); + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_WINDING); + + cairo_move_to (cr, 0, 0); + for (i = 0; i < NUM_SEGMENTS; i++) { + double y3 = uniform_random (0, SIZE); + double x3 = uniform_random (0, SIZE); + double y2 = uniform_random (-SIZE, SIZE); + double x2 = uniform_random (-SIZE, SIZE); + double y1 = uniform_random (-SIZE, SIZE); + double x1 = uniform_random (-SIZE, SIZE); + cairo_curve_to (cr, + x1, y1, + x2, y2, + x3, y3); + } + cairo_close_path (cr); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_fill_preserve (cr); + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_set_line_width (cr, 0.5); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (random_intersections_curves_nz, + "Tests the tessellator trapezoid generation and intersection computation", + "trap", /* keywords */ + NULL, /* requirements */ + SIZE+3, SIZE+3, + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/random-intersections-eo.c b/local/recipes/libs/cairo/source/test/random-intersections-eo.c new file mode 100644 index 0000000000..d35894f33c --- /dev/null +++ b/local/recipes/libs/cairo/source/test/random-intersections-eo.c @@ -0,0 +1,78 @@ +/* + * Copyright © 2006 M Joonas Pihlaja + * + * 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: M Joonas Pihlaja + */ +#include "cairo-test.h" + +#define SIZE 512 +#define NUM_SEGMENTS 128 + +static uint32_t state; + +static double +uniform_random (double minval, double maxval) +{ + static uint32_t const poly = 0x9a795537U; + uint32_t n = 32; + while (n-->0) + state = 2*state < state ? (2*state ^ poly) : 2*state; + return minval + state * (maxval - minval) / 4294967296.0; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + int i; + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + state = 0x12345678; + cairo_translate (cr, 1, 1); + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + + cairo_move_to (cr, 0, 0); + for (i = 0; i < NUM_SEGMENTS; i++) { + double x = uniform_random (0, width); + double y = uniform_random (0, height); + cairo_line_to (cr, x, y); + } + cairo_close_path (cr); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_fill_preserve (cr); + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_set_line_width (cr, 0.5); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (random_intersections_eo, + "Tests the tessellator trapezoid generation and intersection computation", + "trap", /* keywords */ + NULL, /* requirements */ + SIZE+3, SIZE+3, + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/random-intersections-nonzero.c b/local/recipes/libs/cairo/source/test/random-intersections-nonzero.c new file mode 100644 index 0000000000..cad047e04b --- /dev/null +++ b/local/recipes/libs/cairo/source/test/random-intersections-nonzero.c @@ -0,0 +1,79 @@ +/* + * Copyright © 2006 M Joonas Pihlaja + * + * 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: M Joonas Pihlaja + */ +#include "cairo-test.h" + +#define SIZE 512 +#define NUM_SEGMENTS 128 + +static uint32_t state; + +static double +uniform_random (double minval, double maxval) +{ + static uint32_t const poly = 0x9a795537U; + uint32_t n = 32; + while (n-->0) + state = 2*state < state ? (2*state ^ poly) : 2*state; + return minval + state * (maxval - minval) / 4294967296.0; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + int i; + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + state = 0x12345678; + cairo_translate (cr, 1, 1); + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_WINDING); + + cairo_move_to (cr, 0, 0); + for (i = 0; i < NUM_SEGMENTS; i++) { + double x = uniform_random (0, width); + double y = uniform_random (0, height); + cairo_line_to (cr, x, y); + } + cairo_close_path (cr); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_fill_preserve (cr); + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_set_line_width (cr, 0.5); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (random_intersections_nonzero, + "Tests the tessellator trapezoid generation and intersection computation", + "trap", /* keywords */ + NULL, /* requirements */ + SIZE+3, SIZE+3, + NULL, draw) + + diff --git a/local/recipes/libs/cairo/source/test/raster-source.c b/local/recipes/libs/cairo/source/test/raster-source.c new file mode 100644 index 0000000000..ee2a570c33 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/raster-source.c @@ -0,0 +1,147 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +#include +#include + +/* Basic test to exercise the new mime-surface callback. */ + +#define WIDTH 200 +#define HEIGHT 80 + +static char *png_filename = NULL; + +/* Lazy way of determining PNG dimensions... */ +static void +png_dimensions (const char *filename, + cairo_content_t *content, int *width, int *height) +{ + cairo_surface_t *surface; + + surface = cairo_image_surface_create_from_png (filename); + *content = cairo_surface_get_content (surface); + *width = cairo_image_surface_get_width (surface); + *height = cairo_image_surface_get_height (surface); + cairo_surface_destroy (surface); +} + +static cairo_surface_t * +png_acquire (cairo_pattern_t *pattern, void *closure, + cairo_surface_t *target, + const cairo_rectangle_int_t *extents) +{ + return cairo_image_surface_create_from_png (closure); +} + +static cairo_surface_t * +red_acquire (cairo_pattern_t *pattern, void *closure, + cairo_surface_t *target, + const cairo_rectangle_int_t *extents) +{ + cairo_surface_t *image; + cairo_t *cr; + + image = cairo_surface_create_similar_image (target, + CAIRO_FORMAT_RGB24, + extents->width, + extents->height); + cairo_surface_set_device_offset (image, extents->x, extents->y); + + cr = cairo_create (image); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_paint (cr); + cairo_destroy (cr); + + return image; +} + +static void +release (cairo_pattern_t *pattern, void *closure, cairo_surface_t *image) +{ + cairo_surface_destroy (image); +} + +static void +free_filename(void) +{ + free (png_filename); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *png, *red; + cairo_content_t content; + int png_width, png_height; + int i, j; + + if (png_filename == NULL) { + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + xasprintf (&png_filename, "%s/png.png", ctx->srcdir); + atexit (free_filename); + } + + png_dimensions (png_filename, &content, &png_width, &png_height); + + png = cairo_pattern_create_raster_source ((void*)png_filename, + content, png_width, png_height); + cairo_raster_source_pattern_set_acquire (png, png_acquire, release); + + red = cairo_pattern_create_raster_source (NULL, + CAIRO_CONTENT_COLOR, WIDTH, HEIGHT); + cairo_raster_source_pattern_set_acquire (red, red_acquire, release); + + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_paint (cr); + + cairo_translate (cr, 0, (HEIGHT-png_height)/2); + for (i = 0; i < 4; i++) { + for (j = 0; j < 4; j++) { + cairo_pattern_t *source; + if ((i ^ j) & 1) + source = red; + else + source = png; + cairo_set_source (cr, source); + cairo_rectangle (cr, i * WIDTH/4, j * png_height/4, WIDTH/4, png_height/4); + cairo_fill (cr); + } + } + + cairo_pattern_destroy (red); + cairo_pattern_destroy (png); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (raster_source, + "Check that the mime-surface embedding works", + "api", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/record-extend.c b/local/recipes/libs/cairo/source/test/record-extend.c new file mode 100644 index 0000000000..8e83871517 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/record-extend.c @@ -0,0 +1,288 @@ +/* + * Copyright © 2007 Red Hat, Inc. + * Copyright © 2011 Intel Corporation + * + * 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. + * + * Authors: + * Behdad Esfahbod + * Chris Wilson + */ + +#include "cairo-test.h" +#include +#include + +#define SIZE 90 + +/* This is written using clip+paint to exercise a bug that once was in the + * recording surface. + */ + +static cairo_surface_t * +source (cairo_surface_t *surface) +{ + cairo_t *cr; + + /* Create a 4-pixel image surface with my favorite four colors in each + * quadrant. */ + cr = cairo_create (surface); + cairo_surface_destroy (surface); + + /* upper-left = white */ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_rectangle (cr, 0, 0, 1, 1); + cairo_fill (cr); + + /* upper-right = red */ + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_rectangle (cr, 1, 0, 1, 1); + cairo_fill (cr); + + /* lower-left = green */ + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_rectangle (cr, 0, 1, 1, 1); + cairo_fill (cr); + + /* lower-right = blue */ + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_rectangle (cr, 1, 1, 1, 1); + cairo_fill (cr); + + surface = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + + return surface; +} + +static cairo_surface_t * +image (cairo_t *cr) +{ + return source (cairo_image_surface_create (CAIRO_FORMAT_RGB24, 2, 2)); +} + +static cairo_surface_t * +similar (cairo_t *cr) +{ + return source (cairo_surface_create_similar (cairo_get_target (cr), + CAIRO_CONTENT_COLOR, 2, 2)); +} + +static cairo_t * +extend (cairo_t *cr, cairo_surface_t *(*surface)(cairo_t *), cairo_extend_t mode) +{ + cairo_surface_t *s; + + cairo_set_source_rgb (cr, 0, 1, 1); + cairo_paint (cr); + + /* Now use extend modes to cover most of the surface with those 4 colors */ + s = surface (cr); + cairo_set_source_surface (cr, s, SIZE/2 - 1, SIZE/2 - 1); + cairo_surface_destroy (s); + + cairo_pattern_set_extend (cairo_get_source (cr), mode); + + cairo_rectangle (cr, 10, 10, SIZE-20, SIZE-20); + cairo_clip (cr); + cairo_paint (cr); + + return cr; +} + +static cairo_t * +extend_none (cairo_t *cr, + cairo_surface_t *(*pattern)(cairo_t *)) +{ + return extend (cr, pattern, CAIRO_EXTEND_NONE); +} + +static cairo_t * +extend_pad (cairo_t *cr, + cairo_surface_t *(*pattern)(cairo_t *)) +{ + return extend (cr, pattern, CAIRO_EXTEND_PAD); +} + +static cairo_t * +extend_repeat (cairo_t *cr, + cairo_surface_t *(*pattern)(cairo_t *)) +{ + return extend (cr, pattern, CAIRO_EXTEND_REPEAT); +} + +static cairo_t * +extend_reflect (cairo_t *cr, + cairo_surface_t *(*pattern)(cairo_t *)) +{ + return extend (cr, pattern, CAIRO_EXTEND_REFLECT); +} + +static cairo_t * +record_create (cairo_t *target) +{ + cairo_surface_t *surface; + cairo_t *cr; + + surface = cairo_recording_surface_create (cairo_surface_get_content (cairo_get_target (target)), NULL); + cr = cairo_create (surface); + cairo_surface_destroy (surface); + + return cr; +} + +static cairo_surface_t * +record_get (cairo_t *target) +{ + cairo_surface_t *surface; + + surface = cairo_surface_reference (cairo_get_target (target)); + cairo_destroy (target); + + return surface; +} + +static cairo_test_status_t +record_replay (cairo_t *cr, + cairo_t *(*func)(cairo_t *, + cairo_surface_t *(*pattern)(cairo_t *)), + cairo_surface_t *(*pattern)(cairo_t *), + int width, int height) +{ + cairo_surface_t *surface; + int x, y; + + surface = record_get (func (record_create (cr), pattern)); + + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_surface (cr, surface, 0, 0); + cairo_surface_destroy (surface); + cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_NONE); + + for (y = 0; y < height; y += 2) { + for (x = 0; x < width; x += 2) { + cairo_rectangle (cr, x, y, 2, 2); + cairo_clip (cr); + cairo_paint (cr); + cairo_reset_clip (cr); + } + } + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +record_extend_none (cairo_t *cr, int width, int height) +{ + return record_replay (cr, extend_none, image, width, height); +} + +static cairo_test_status_t +record_extend_pad (cairo_t *cr, int width, int height) +{ + return record_replay (cr, extend_pad, image, width, height); +} + +static cairo_test_status_t +record_extend_repeat (cairo_t *cr, int width, int height) +{ + return record_replay (cr, extend_repeat, image, width, height); +} + +static cairo_test_status_t +record_extend_reflect (cairo_t *cr, int width, int height) +{ + return record_replay (cr, extend_reflect, image, width, height); +} + +static cairo_test_status_t +record_extend_none_similar (cairo_t *cr, int width, int height) +{ + return record_replay (cr, extend_none, similar, width, height); +} + +static cairo_test_status_t +record_extend_pad_similar (cairo_t *cr, int width, int height) +{ + return record_replay (cr, extend_pad, similar, width, height); +} + +static cairo_test_status_t +record_extend_repeat_similar (cairo_t *cr, int width, int height) +{ + return record_replay (cr, extend_repeat, similar, width, height); +} + +static cairo_test_status_t +record_extend_reflect_similar (cairo_t *cr, int width, int height) +{ + return record_replay (cr, extend_reflect, similar, width, height); +} + +CAIRO_TEST (record_extend_none, + "Test CAIRO_EXTEND_NONE for recorded surface patterns", + "record, extend", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, record_extend_none) +CAIRO_TEST (record_extend_pad, + "Test CAIRO_EXTEND_PAD for recorded surface patterns", + "record, extend", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, record_extend_pad) +CAIRO_TEST (record_extend_repeat, + "Test CAIRO_EXTEND_REPEAT for recorded surface patterns", + "record, extend", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, record_extend_repeat) +CAIRO_TEST (record_extend_reflect, + "Test CAIRO_EXTEND_REFLECT for recorded surface patterns", + "record, extend", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, record_extend_reflect) + +CAIRO_TEST (record_extend_none_similar, + "Test CAIRO_EXTEND_NONE for recorded surface patterns", + "record, extend", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, record_extend_none_similar) +CAIRO_TEST (record_extend_pad_similar, + "Test CAIRO_EXTEND_PAD for recorded surface patterns", + "record, extend", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, record_extend_pad_similar) +CAIRO_TEST (record_extend_repeat_similar, + "Test CAIRO_EXTEND_REPEAT for recorded surface patterns", + "record, extend", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, record_extend_repeat_similar) +CAIRO_TEST (record_extend_reflect_similar, + "Test CAIRO_EXTEND_REFLECT for recorded surface patterns", + "record, extend", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, record_extend_reflect_similar) diff --git a/local/recipes/libs/cairo/source/test/record-mesh.c b/local/recipes/libs/cairo/source/test/record-mesh.c new file mode 100644 index 0000000000..754a1d430d --- /dev/null +++ b/local/recipes/libs/cairo/source/test/record-mesh.c @@ -0,0 +1,166 @@ +/* + * Copyright © 2007 Red Hat, Inc. + * Copyright © 2009 Adrian Johnson + * Copyright © 2011 Intel Corporation + * + * 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. + * + * Authors: + * Behdad Esfahbod + * Adrian Johnson + * Chris Wilson + */ + +#include "cairo-test.h" +#include +#include + +#define PAT_WIDTH 170 +#define PAT_HEIGHT 170 +#define SIZE PAT_WIDTH +#define PAD 2 +#define WIDTH (PAD + SIZE + PAD) +#define HEIGHT WIDTH + +/* This test is designed to paint a mesh pattern. The mesh contains + * two overlapping patches */ + +static cairo_pattern_t * +mesh (void) +{ + cairo_pattern_t *pattern; + + pattern = cairo_pattern_create_mesh (); + + cairo_mesh_pattern_begin_patch (pattern); + + cairo_mesh_pattern_move_to (pattern, 0, 0); + cairo_mesh_pattern_curve_to (pattern, 30, -30, 60, 30, 100, 0); + cairo_mesh_pattern_curve_to (pattern, 60, 30, 130, 60, 100, 100); + cairo_mesh_pattern_curve_to (pattern, 60, 70, 30, 130, 0, 100); + cairo_mesh_pattern_curve_to (pattern, 30, 70, -30, 30, 0, 0); + + cairo_mesh_pattern_set_corner_color_rgb (pattern, 0, 1, 0, 0); + cairo_mesh_pattern_set_corner_color_rgb (pattern, 1, 0, 1, 0); + cairo_mesh_pattern_set_corner_color_rgb (pattern, 2, 0, 0, 1); + cairo_mesh_pattern_set_corner_color_rgb (pattern, 3, 1, 1, 0); + + cairo_mesh_pattern_end_patch (pattern); + + cairo_mesh_pattern_begin_patch (pattern); + + cairo_mesh_pattern_move_to (pattern, 50, 50); + cairo_mesh_pattern_curve_to (pattern, 80, 20, 110, 80, 150, 50); + cairo_mesh_pattern_curve_to (pattern, 110, 80, 180, 110, 150, 150); + cairo_mesh_pattern_curve_to (pattern, 110, 120, 80, 180, 50, 150); + cairo_mesh_pattern_curve_to (pattern, 80, 120, 20, 80, 50, 50); + + cairo_mesh_pattern_set_corner_color_rgba (pattern, 0, 1, 0, 0, 0.3); + cairo_mesh_pattern_set_corner_color_rgb (pattern, 1, 0, 1, 0); + cairo_mesh_pattern_set_corner_color_rgba (pattern, 2, 0, 0, 1, 0.3); + cairo_mesh_pattern_set_corner_color_rgb (pattern, 3, 1, 1, 0); + + cairo_mesh_pattern_end_patch (pattern); + + return pattern; +} + +static cairo_t * +draw (cairo_t *cr) +{ + cairo_pattern_t *source; + + cairo_set_source_rgb (cr, 0, 1, 1); + cairo_paint (cr); + + source = mesh (); + cairo_set_source (cr, source); + cairo_pattern_destroy (source); + + cairo_rectangle (cr, 10, 10, SIZE-20, SIZE-20); + cairo_clip (cr); + cairo_paint (cr); + + return cr; +} + +static cairo_t * +record_create (cairo_t *target) +{ + cairo_surface_t *surface; + cairo_t *cr; + + surface = cairo_recording_surface_create (cairo_surface_get_content (cairo_get_target (target)), NULL); + cr = cairo_create (surface); + cairo_surface_destroy (surface); + + return cr; +} + +static cairo_surface_t * +record_get (cairo_t *target) +{ + cairo_surface_t *surface; + + surface = cairo_surface_reference (cairo_get_target (target)); + cairo_destroy (target); + + return surface; +} + +static cairo_test_status_t +record_replay (cairo_t *cr, cairo_t *(*func)(cairo_t *), int width, int height) +{ + cairo_surface_t *surface; + int x, y; + + surface = record_get (func (record_create (cr))); + + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_surface (cr, surface, 0, 0); + cairo_surface_destroy (surface); + cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_NONE); + + for (y = 0; y < height; y += 2) { + for (x = 0; x < width; x += 2) { + cairo_rectangle (cr, x, y, 2, 2); + cairo_clip (cr); + cairo_paint (cr); + cairo_reset_clip (cr); + } + } + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +record_mesh (cairo_t *cr, int width, int height) +{ + return record_replay (cr, draw, width, height); +} + +CAIRO_TEST (record_mesh, + "Paint mesh pattern through a recording surface", + "record,mesh,pattern", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, record_mesh) + diff --git a/local/recipes/libs/cairo/source/test/record-neg-extents.c b/local/recipes/libs/cairo/source/test/record-neg-extents.c new file mode 100644 index 0000000000..29a2aa1e61 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/record-neg-extents.c @@ -0,0 +1,217 @@ +/* + * 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. + * + * Authors: + * Adrian Johnson + */ + +#include "cairo-test.h" +#include +#include + +#define PAT_SIZE 64 +#define PAD (PAT_SIZE/8) +#define WIDTH (PAT_SIZE*4 + PAD*5) +#define HEIGHT (PAT_SIZE + PAD*2) + +/* Test case based on bug 89232 - painting a recording surface to a pdf/ps surface + * omits objects on the recording surface with negative coordinates even though + * the pattern matrix has transformed the objects to within the page extents. + * The bug is a result of pdf/ps assuming the surface extents are always + * (0,0) to (page_width, page_height). + * + * Each test has four cases of painting a recording pattern where: + * 1) recording surface origin is transformed to the center of the pattern + * 2) same as 1) but also scaled up 10x + * 3) same as 1) but also scaled down 10x + * 4) same as 1) but also rotated 45 deg + */ + + +static void +transform_extents(cairo_rectangle_t *extents, cairo_matrix_t *mat) +{ + double x1, y1, x2, y2, x, y; + +#define UPDATE_BBOX \ + x1 = x < x1 ? x : x1; \ + y1 = y < y1 ? y : y1; \ + x2 = x > x2 ? x : x2; \ + y2 = y > y2 ? y : y2; + + x = extents->x; + y = extents->y; + cairo_matrix_transform_point (mat, &x, &y); + x1 = x2 = x; + y1 = y2 = y; + + x = extents->x + extents->width; + y = extents->y; + cairo_matrix_transform_point (mat, &x, &y); + UPDATE_BBOX; + + x = extents->x; + y = extents->y + extents->height; + cairo_matrix_transform_point (mat, &x, &y); + UPDATE_BBOX; + + x = extents->x + extents->width; + y = extents->y + extents->height; + cairo_matrix_transform_point (mat, &x, &y); + UPDATE_BBOX; + + extents->x = x1; + extents->y = y1; + extents->width = x2 - extents->x; + extents->height = y2 - extents->y; + +#undef UPDATE_BBOX +} + +static cairo_pattern_t * +create_pattern (cairo_matrix_t *mat, cairo_bool_t bounded) +{ + cairo_surface_t *surf; + cairo_pattern_t *pat; + cairo_t *cr; + int border; + int square; + + if (bounded) { + cairo_rectangle_t extents = { 0, 0, PAT_SIZE, PAT_SIZE }; + transform_extents (&extents, mat); + surf = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, &extents); + } else { + surf = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL); + } + + cr = cairo_create (surf); + cairo_transform (cr, mat); + + border = PAT_SIZE/8; + square = (PAT_SIZE - 2*border)/2; + + cairo_rectangle (cr, 0, 0, PAT_SIZE, PAT_SIZE); + cairo_clip (cr); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_paint (cr); + + cairo_translate (cr, border, border); + cairo_rectangle (cr, 0, 0, square, square); + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_fill (cr); + + cairo_translate (cr, square, 0); + cairo_rectangle (cr, 0, 0, square, square); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_fill (cr); + + cairo_translate (cr, 0, square); + cairo_rectangle (cr, 0, 0, square, square); + cairo_set_source_rgb (cr, 0, 1, 1); + cairo_fill (cr); + + cairo_translate (cr, -square, 0); + cairo_rectangle (cr, 0, 0, square, square); + cairo_set_source_rgb (cr, 1, 1, 0); + cairo_fill (cr); + + cairo_destroy (cr); + + pat = cairo_pattern_create_for_surface (surf); + cairo_surface_destroy (surf); + cairo_pattern_set_matrix (pat, mat); + + return pat; +} + +static cairo_test_status_t +record_extents (cairo_t *cr, int width, int height, cairo_bool_t bounded) +{ + cairo_pattern_t *pat; + cairo_matrix_t mat; + + /* record surface extents (-PAT_SIZE/2, -PAT_SIZE/2) to (PAT_SIZE/2, PAT_SIZE/2) */ + cairo_translate (cr, PAD, PAD); + cairo_matrix_init_translate (&mat, -PAT_SIZE/2, -PAT_SIZE/2); + pat = create_pattern (&mat, bounded); + cairo_set_source (cr, pat); + cairo_pattern_destroy (pat); + cairo_paint (cr); + + /* record surface extents (-10*PAT_SIZE/2, -10*PAT_SIZE/2) to (10*PAT_SIZE/2, 10*PAT_SIZE/2) */ + cairo_translate (cr, PAT_SIZE + PAD, 0); + cairo_matrix_init_translate (&mat, -10.0*PAT_SIZE/2, -10.0*PAT_SIZE/2); + cairo_matrix_scale (&mat, 10, 10); + pat = create_pattern (&mat, bounded); + cairo_set_source (cr, pat); + cairo_pattern_destroy (pat); + cairo_paint (cr); + + /* record surface extents (-0.1*PAT_SIZE/2, -0.1*PAT_SIZE/2) to (0.1*PAT_SIZE/2, 0.1*PAT_SIZE/2) */ + cairo_translate (cr, PAT_SIZE + PAD, 0); + cairo_matrix_init_translate (&mat, -0.1*PAT_SIZE/2, -0.1*PAT_SIZE/2); + cairo_matrix_scale (&mat, 0.1, 0.1); + pat = create_pattern (&mat, bounded); + cairo_set_source (cr, pat); + cairo_pattern_destroy (pat); + cairo_paint (cr); + + /* record surface centered on (0,0) and rotated 45 deg */ + cairo_translate (cr, PAT_SIZE + PAD, 0); + cairo_matrix_init_translate (&mat, -PAT_SIZE/sqrt(2), -PAT_SIZE/sqrt(2)); + cairo_matrix_rotate (&mat, M_PI/4.0); + cairo_matrix_translate (&mat, PAT_SIZE/2, -PAT_SIZE/2); + pat = create_pattern (&mat, bounded); + cairo_set_source (cr, pat); + cairo_pattern_destroy (pat); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +record_neg_extents_bounded (cairo_t *cr, int width, int height) +{ + return record_extents(cr, width, height, TRUE); +} + +static cairo_test_status_t +record_neg_extents_unbounded (cairo_t *cr, int width, int height) +{ + return record_extents(cr, width, height, FALSE); +} + + +CAIRO_TEST (record_neg_extents_unbounded, + "Paint unbounded recording pattern with untransformed extents outside of target extents", + "record,transform,pattern", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, record_neg_extents_unbounded) +CAIRO_TEST (record_neg_extents_bounded, + "Paint bounded recording pattern with untransformed extents outside of target extents", + "record,transform,pattern", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, record_neg_extents_bounded) diff --git a/local/recipes/libs/cairo/source/test/record-replay-extend.c b/local/recipes/libs/cairo/source/test/record-replay-extend.c new file mode 100644 index 0000000000..4a41233592 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/record-replay-extend.c @@ -0,0 +1,227 @@ +/* + * 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. + * + * Authors: + * Adrian Johnson + */ + +#include "cairo-test.h" +#include +#include + +#define PAT_SIZE 32 +#define REPLAY_SIZE (PAT_SIZE*4) +#define PAD 10 +#define WIDTH (REPLAY_SIZE*4 + PAD*5) +#define HEIGHT (REPLAY_SIZE + PAD*2) + +/* Test replaying a recording surface pattern for each type of extend. */ + +static void +transform_extents(cairo_rectangle_t *extents, cairo_matrix_t *mat) +{ + double x1, y1, x2, y2, x, y; + +#define UPDATE_BBOX \ + x1 = x < x1 ? x : x1; \ + y1 = y < y1 ? y : y1; \ + x2 = x > x2 ? x : x2; \ + y2 = y > y2 ? y : y2; + + x = extents->x; + y = extents->y; + cairo_matrix_transform_point (mat, &x, &y); + x1 = x2 = x; + y1 = y2 = y; + + x = extents->x + extents->width; + y = extents->y; + cairo_matrix_transform_point (mat, &x, &y); + UPDATE_BBOX; + + x = extents->x; + y = extents->y + extents->height; + cairo_matrix_transform_point (mat, &x, &y); + UPDATE_BBOX; + + x = extents->x + extents->width; + y = extents->y + extents->height; + cairo_matrix_transform_point (mat, &x, &y); + UPDATE_BBOX; + + extents->x = x1; + extents->y = y1; + extents->width = x2 - extents->x; + extents->height = y2 - extents->y; + +#undef UPDATE_BBOX +} + +static cairo_pattern_t * +create_pattern (cairo_matrix_t *mat, cairo_extend_t extend) +{ + cairo_surface_t *surf; + cairo_pattern_t *pat; + cairo_t *cr; + cairo_rectangle_t extents = { 0, 0, PAT_SIZE, PAT_SIZE }; + + transform_extents (&extents, mat); + surf = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, &extents); + + cr = cairo_create (surf); + cairo_transform (cr, mat); + + cairo_rectangle (cr, 0, 0, PAT_SIZE/2, PAT_SIZE/2); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_fill (cr); + + cairo_translate (cr, PAT_SIZE/2, 0); + cairo_rectangle (cr, 0, 0, PAT_SIZE/2, PAT_SIZE/2); + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_fill (cr); + + cairo_translate (cr, 0, PAT_SIZE/2); + cairo_rectangle (cr, 0, 0, PAT_SIZE/2, PAT_SIZE/2); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_fill (cr); + + cairo_translate (cr, -PAT_SIZE/2, 0); + cairo_rectangle (cr, 0, 0, PAT_SIZE/2, PAT_SIZE/2); + cairo_set_source_rgb (cr, 1, 1, 0); + cairo_fill (cr); + + cairo_destroy (cr); + + pat = cairo_pattern_create_for_surface (surf); + cairo_surface_destroy (surf); + cairo_pattern_set_matrix (pat, mat); + cairo_pattern_set_extend (pat, extend); + cairo_pattern_set_filter (pat, CAIRO_FILTER_NEAREST); + + return pat; +} + +static cairo_test_status_t +record_replay_extend (cairo_t *cr, int width, int height, cairo_extend_t extend) +{ + cairo_pattern_t *pat; + cairo_matrix_t mat; + + /* record surface extents (-PAT_SIZE/2, -PAT_SIZE/2) to (PAT_SIZE/2, PAT_SIZE/2) */ + cairo_translate (cr, PAD, PAD); + cairo_matrix_init_translate (&mat, -PAT_SIZE/2, -PAT_SIZE/2); + pat = create_pattern (&mat, extend); + + /* test repeating patterns when the source is outside of the target clip */ + if (extend == CAIRO_EXTEND_REPEAT || extend == CAIRO_EXTEND_REFLECT) { + cairo_matrix_init_translate (&mat, 3*PAT_SIZE/2, 3*PAT_SIZE/2); + cairo_pattern_set_matrix (pat, &mat); + } + + cairo_set_source (cr, pat); + cairo_pattern_destroy (pat); + cairo_rectangle (cr, 0, 0, REPLAY_SIZE, REPLAY_SIZE); + cairo_fill (cr); + + /* record surface extents (-2*PAT_SIZE/2, -2*PAT_SIZE/2) to (2*PAT_SIZE/2, 2*PAT_SIZE/2) */ + cairo_translate (cr, REPLAY_SIZE + PAD, 0); + cairo_matrix_init_translate (&mat, -2.0*PAT_SIZE/2, -2.0*PAT_SIZE/2); + cairo_matrix_scale (&mat, 2, 2); + pat = create_pattern (&mat, extend); + cairo_set_source (cr, pat); + cairo_pattern_destroy (pat); + cairo_rectangle (cr, 0, 0, REPLAY_SIZE, REPLAY_SIZE); + cairo_fill (cr); + + /* record surface extents (-0.5*PAT_SIZE/2, -0.5*PAT_SIZE/2) to (0.5*PAT_SIZE/2, 0.5*PAT_SIZE/2) */ + cairo_translate (cr, REPLAY_SIZE + PAD, 0); + cairo_matrix_init_translate (&mat, -0.5*PAT_SIZE/2, -0.5*PAT_SIZE/2); + cairo_matrix_scale (&mat, 0.5, 0.5); + pat = create_pattern (&mat, extend); + cairo_set_source (cr, pat); + cairo_pattern_destroy (pat); + cairo_rectangle (cr, 0, 0, REPLAY_SIZE, REPLAY_SIZE); + cairo_fill (cr); + + /* record surface centered on (0,0) and rotated 45 deg */ + cairo_translate (cr, REPLAY_SIZE + PAD, 0); + cairo_matrix_init_translate (&mat, -PAT_SIZE/sqrt(2), -PAT_SIZE/sqrt(2)); + cairo_matrix_rotate (&mat, M_PI/4.0); + cairo_matrix_translate (&mat, PAT_SIZE/2, -PAT_SIZE/2); + pat = create_pattern (&mat, extend); + cairo_set_source (cr, pat); + cairo_pattern_destroy (pat); + cairo_rectangle (cr, 0, 0, REPLAY_SIZE, REPLAY_SIZE); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +record_replay_extend_none (cairo_t *cr, int width, int height) +{ + return record_replay_extend (cr, width, height, CAIRO_EXTEND_NONE); +} + +static cairo_test_status_t +record_replay_extend_repeat (cairo_t *cr, int width, int height) +{ + return record_replay_extend (cr, width, height, CAIRO_EXTEND_REPEAT); +} + +static cairo_test_status_t +record_replay_extend_reflect (cairo_t *cr, int width, int height) +{ + return record_replay_extend (cr, width, height, CAIRO_EXTEND_REFLECT); +} + +static cairo_test_status_t +record_replay_extend_pad (cairo_t *cr, int width, int height) +{ + return record_replay_extend (cr, width, height, CAIRO_EXTEND_PAD); +} + +CAIRO_TEST (record_replay_extend_none, + "Paint recording pattern with CAIRO_EXTEND_NONE", + "record,pattern,extend", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, record_replay_extend_none) +CAIRO_TEST (record_replay_extend_repeat, + "Paint recording pattern with CAIRO_EXTEND_REPEAT", + "record,pattern,extend", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, record_replay_extend_repeat) +CAIRO_TEST (record_replay_extend_reflect, + "Paint recording pattern with CAIRO_EXTEND_REFLECT", + "record,pattern,extend", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, record_replay_extend_reflect) +CAIRO_TEST (record_replay_extend_pad, + "Paint recording pattern with CAIRO_EXTEND_PAD", + "record,pattern,extend", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, record_replay_extend_pad) diff --git a/local/recipes/libs/cairo/source/test/record-transform-paint.c b/local/recipes/libs/cairo/source/test/record-transform-paint.c new file mode 100644 index 0000000000..0ccc2277f1 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/record-transform-paint.c @@ -0,0 +1,64 @@ +/* + * Copyright © 2021 Anton Danilkin + * + * 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. + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface2 = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL); + { + cairo_t *cr2 = cairo_create (surface2); + cairo_surface_t *surface3 = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL); + { + cairo_t *cr3 = cairo_create (surface3); + cairo_pattern_t *pattern4 = cairo_pattern_create_linear (0.0, 0.0, width, height); + cairo_pattern_add_color_stop_rgb (pattern4, 0, 0, 1, 0); + cairo_pattern_add_color_stop_rgb (pattern4, 1, 0, 0, 1); + cairo_set_source (cr3, pattern4); + cairo_paint (cr3); + } + cairo_pattern_t *pattern3 = cairo_pattern_create_for_surface (surface3); + cairo_matrix_t matrix3; + cairo_matrix_init_scale (&matrix3, 2, 2); + cairo_pattern_set_matrix (pattern3, &matrix3); + cairo_set_source (cr2, pattern3); + cairo_paint (cr2); + } + cairo_pattern_t *pattern2 = cairo_pattern_create_for_surface (surface2); + cairo_matrix_t matrix2; + cairo_matrix_init_scale (&matrix2, 5, 5); + cairo_pattern_set_matrix (pattern2, &matrix2); + cairo_set_source (cr, pattern2); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (record_transform_paint, + "Tests paint in nested transformed recording patterns", + "record, paint", /* keywords */ + NULL, /* requirements */ + 512, 512, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/record-write-png.c b/local/recipes/libs/cairo/source/test/record-write-png.c new file mode 100644 index 0000000000..da0e253bd5 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/record-write-png.c @@ -0,0 +1,136 @@ +/* + * Copyright © 2021 Matthias Clasen + * Copyright © 2021 Uli Schlachter + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: + * Matthias Clasen + * Uli Schlachter + */ + +// Test case for https://gitlab.freedesktop.org/cairo/cairo/-/merge_requests/118 +// A recording surface with a non-zero origin gets cut off when passed to +// cairo_surface_write_to_png(). + +#include "cairo-test.h" + +#include + +struct buffer { + char *data; + size_t length; +}; + +static cairo_surface_t * +prepare_recording (void) +{ + cairo_surface_t *surface; + cairo_rectangle_t rect; + cairo_t *cr; + + rect.x = -1; + rect.y = -2; + rect.width = 3; + rect.height = 4; + surface = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, &rect); + + cr = cairo_create (surface); + cairo_set_line_width (cr, 1); + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_rectangle (cr, 0.5, -0.5, 1., 1.); + cairo_stroke (cr); + cairo_destroy (cr); + + return surface; +} + +static cairo_status_t +write_callback (void *closure, const unsigned char *data, unsigned int length) +{ + struct buffer *buffer = closure; + + buffer->data = realloc (buffer->data, buffer->length + length); + memcpy (&buffer->data[buffer->length], data, length); + buffer->length += length; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +read_callback (void *closure, unsigned char *data, unsigned int length) +{ + struct buffer *buffer = closure; + + assert (buffer->length >= length); + memcpy (data, buffer->data, length); + buffer->data += length; + buffer->length -= length; + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_surface_t * +png_round_trip (cairo_surface_t *input_surface) +{ + cairo_surface_t *output_surface; + struct buffer buffer; + void *to_free; + + // Turn the surface into a PNG + buffer.data = NULL; + buffer.length = 0; + cairo_surface_write_to_png_stream (input_surface, write_callback, &buffer); + to_free = buffer.data; + + // Load the PNG again + output_surface = cairo_image_surface_create_from_png_stream (read_callback, &buffer); + + free (to_free); + return output_surface; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *recording, *surface; + + // Draw a black background so that the output does not vary with alpha + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + recording = prepare_recording (); + surface = png_round_trip (recording); + + cairo_set_source_surface (cr, surface, 0, 0); + cairo_paint (cr); + + cairo_surface_destroy (recording); + cairo_surface_destroy (surface); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (record_write_png, + "Test writing to png with non-zero origin", + "record, transform", /* keywords */ + NULL, /* requirements */ + 4, 4, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/record.c b/local/recipes/libs/cairo/source/test/record.c new file mode 100644 index 0000000000..bc5e1f72e9 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/record.c @@ -0,0 +1,502 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2011 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: + * Carl D. Worth + * Chris Wilson + */ + +#include "cairo-test.h" + +#define TEXT_SIZE 12 +#define SIZE 60 /* needs to be big to check large area effects (dithering) */ +#define PAD 2 + +#define TT_SIZE 100 +#define TT_PAD 5 +#define TT_FONT_SIZE 32.0 + +#define GENERATE_REF 0 + +static uint32_t data[16] = { + 0xffffffff, 0xffffffff, 0xffff0000, 0xffff0000, + 0xffffffff, 0xffffffff, 0xffff0000, 0xffff0000, + + 0xff00ff00, 0xff00ff00, 0xff0000ff, 0xff0000ff, + 0xff00ff00, 0xff00ff00, 0xff0000ff, 0xff0000ff +}; + +static const char *unique_id = "data"; + +static const char *png_filename = "romedalen.png"; + +static cairo_t * +paint (cairo_t *cr) +{ + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_paint (cr); + + cairo_translate (cr, 2, 2); + cairo_scale (cr, 0.5, 0.5); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_paint (cr); + + return cr; +} + +static cairo_t * +paint_alpha (cairo_t *cr) +{ + cairo_surface_t *surface; + + surface = cairo_image_surface_create_for_data ((unsigned char *) data, + CAIRO_FORMAT_RGB24, 4, 4, 16); + cairo_surface_set_mime_data (surface, CAIRO_MIME_TYPE_UNIQUE_ID, + (unsigned char *)unique_id, strlen(unique_id), + NULL, NULL); + + cairo_test_paint_checkered (cr); + + cairo_scale (cr, 4, 4); + + cairo_set_source_surface (cr, surface, 2 , 2); + cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); + cairo_paint_with_alpha (cr, 0.5); + + cairo_surface_finish (surface); /* data will go out of scope */ + cairo_surface_destroy (surface); + + return cr; +} + +static cairo_t * +paint_alpha_solid_clip (cairo_t *cr) +{ + cairo_test_paint_checkered (cr); + + cairo_rectangle (cr, 2.5, 2.5, 27, 27); + cairo_clip (cr); + + cairo_set_source_rgb (cr, 1., 0.,0.); + cairo_paint_with_alpha (cr, 0.5); + + return cr; +} + +static cairo_t * +paint_alpha_clip (cairo_t *cr) +{ + cairo_surface_t *surface; + + surface = cairo_image_surface_create_for_data ((unsigned char *) data, + CAIRO_FORMAT_RGB24, 4, 4, 16); + cairo_surface_set_mime_data (surface, CAIRO_MIME_TYPE_UNIQUE_ID, + (unsigned char *)unique_id, strlen(unique_id), + NULL, NULL); + + cairo_test_paint_checkered (cr); + + cairo_rectangle (cr, 10.5, 10.5, 11, 11); + cairo_clip (cr); + + cairo_scale (cr, 4, 4); + + cairo_set_source_surface (cr, surface, 2 , 2); + cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); + cairo_paint_with_alpha (cr, 0.5); + + cairo_surface_finish (surface); /* data will go out of scope */ + cairo_surface_destroy (surface); + + return cr; +} + +static cairo_t * +paint_alpha_clip_mask (cairo_t *cr) +{ + cairo_surface_t *surface; + + surface = cairo_image_surface_create_for_data ((unsigned char *) data, + CAIRO_FORMAT_RGB24, 4, 4, 16); + cairo_surface_set_mime_data (surface, CAIRO_MIME_TYPE_UNIQUE_ID, + (unsigned char *)unique_id, strlen(unique_id), + NULL, NULL); + + cairo_test_paint_checkered (cr); + + cairo_move_to (cr, 16, 5); + cairo_line_to (cr, 5, 16); + cairo_line_to (cr, 16, 27); + cairo_line_to (cr, 27, 16); + cairo_clip (cr); + + cairo_scale (cr, 4, 4); + + cairo_set_source_surface (cr, surface, 2 , 2); + cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); + cairo_paint_with_alpha (cr, 0.5); + + cairo_surface_finish (surface); /* data will go out of scope */ + cairo_surface_destroy (surface); + + return cr; +} + +static cairo_t * +select_font_face (cairo_t *cr) +{ + /* We draw in the default black, so paint white first. */ + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0, 0, 0); /* black */ + + cairo_set_font_size (cr, TEXT_SIZE); + cairo_move_to (cr, 0, TEXT_SIZE); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Serif", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_show_text (cr, "i-am-serif"); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_show_text (cr, " i-am-sans"); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans Mono", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_show_text (cr, " i-am-mono"); + + return cr; +} + +static cairo_t * +fill_alpha (cairo_t *cr) +{ + const double alpha = 1./3; + int n; + + /* flatten to white */ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + /* square */ + cairo_rectangle (cr, PAD, PAD, SIZE, SIZE); + cairo_set_source_rgba (cr, 1, 0, 0, alpha); + cairo_fill (cr); + + /* circle */ + cairo_translate (cr, SIZE + 2 * PAD, 0); + cairo_arc (cr, PAD + SIZE / 2., PAD + SIZE / 2., SIZE / 2., 0, 2 * M_PI); + cairo_set_source_rgba (cr, 0, 1, 0, alpha); + cairo_fill (cr); + + /* triangle */ + cairo_translate (cr, 0, SIZE + 2 * PAD); + cairo_move_to (cr, PAD + SIZE / 2, PAD); + cairo_line_to (cr, PAD + SIZE, PAD + SIZE); + cairo_line_to (cr, PAD, PAD + SIZE); + cairo_set_source_rgba (cr, 0, 0, 1, alpha); + cairo_fill (cr); + + /* star */ + cairo_translate (cr, -(SIZE + 2 * PAD) + SIZE/2., SIZE/2.); + for (n = 0; n < 5; n++) { + cairo_line_to (cr, + SIZE/2 * cos (2*n * 2*M_PI / 10), + SIZE/2 * sin (2*n * 2*M_PI / 10)); + + cairo_line_to (cr, + SIZE/4 * cos ((2*n+1)*2*M_PI / 10), + SIZE/4 * sin ((2*n+1)*2*M_PI / 10)); + } + cairo_set_source_rgba (cr, 0, 0, 0, alpha); + cairo_fill (cr); + + return cr; +} + +static cairo_t * +self_intersecting (cairo_t *cr) +{ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_translate (cr, 1.0, 1.0); + + cairo_set_source_rgb (cr, 1, 0, 0); /* red */ + + /* First draw the desired shape with a fill */ + cairo_rectangle (cr, 0.5, 0.5, 4.0, 4.0); + cairo_rectangle (cr, 3.5, 3.5, 4.0, 4.0); + cairo_rectangle (cr, 3.5, 1.5, -2.0, 2.0); + cairo_rectangle (cr, 6.5, 4.5, -2.0, 2.0); + + cairo_fill (cr); + + /* Then try the same thing with a stroke */ + cairo_translate (cr, 0, 10); + cairo_move_to (cr, 1.0, 1.0); + cairo_rel_line_to (cr, 3.0, 0.0); + cairo_rel_line_to (cr, 0.0, 6.0); + cairo_rel_line_to (cr, 3.0, 0.0); + cairo_rel_line_to (cr, 0.0, -3.0); + cairo_rel_line_to (cr, -6.0, 0.0); + cairo_close_path (cr); + + cairo_set_line_width (cr, 1.0); + cairo_stroke (cr); + + return cr; +} + +static void +draw_text_transform (cairo_t *cr) +{ + cairo_matrix_t tm; + + /* skew */ + cairo_matrix_init (&tm, 1, 0, + -0.25, 1, + 0, 0); + cairo_matrix_scale (&tm, TT_FONT_SIZE, TT_FONT_SIZE); + cairo_set_font_matrix (cr, &tm); + + cairo_new_path (cr); + cairo_move_to (cr, 50, TT_SIZE-TT_PAD); + cairo_show_text (cr, "A"); + + /* rotate and scale */ + cairo_matrix_init_rotate (&tm, M_PI / 2); + cairo_matrix_scale (&tm, TT_FONT_SIZE, TT_FONT_SIZE * 2.0); + cairo_set_font_matrix (cr, &tm); + + cairo_new_path (cr); + cairo_move_to (cr, TT_PAD, TT_PAD + 25); + cairo_show_text (cr, "A"); + + cairo_matrix_init_rotate (&tm, M_PI / 2); + cairo_matrix_scale (&tm, TT_FONT_SIZE * 2.0, TT_FONT_SIZE); + cairo_set_font_matrix (cr, &tm); + + cairo_new_path (cr); + cairo_move_to (cr, TT_PAD, TT_PAD + 50); + cairo_show_text (cr, "A"); +} + +static cairo_t * +text_transform (cairo_t *cr) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_pattern_t *pattern; + + cairo_set_source_rgb (cr, 1., 1., 1.); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0., 0., 0.); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + + draw_text_transform (cr); + + cairo_translate (cr, TT_SIZE, TT_SIZE); + cairo_rotate (cr, M_PI); + + pattern = cairo_test_create_pattern_from_png (ctx, png_filename); + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT); + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + + draw_text_transform (cr); + + return cr; +} + +/* And here begins the recording and replaying... */ + +static cairo_t * +record_create (cairo_t *target) +{ + cairo_surface_t *surface; + cairo_t *cr; + + surface = cairo_recording_surface_create (cairo_surface_get_content (cairo_get_target (target)), NULL); + cr = cairo_test_create (surface, cairo_test_get_context (target)); + cairo_surface_destroy (surface); + + return cr; +} + +static cairo_surface_t * +record_get (cairo_t *target) +{ + cairo_surface_t *surface; + + surface = cairo_surface_reference (cairo_get_target (target)); + cairo_destroy (target); + + return surface; +} + +static cairo_test_status_t +record_replay (cairo_t *cr, cairo_t *(*func)(cairo_t *), int width, int height) +{ + cairo_surface_t *surface; + int x, y; + +#if GENERATE_REF + func(cr); +#else + surface = record_get (func (record_create (cr))); + + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_surface (cr, surface, 0, 0); + cairo_surface_destroy (surface); + cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_NONE); + + for (y = 0; y < height; y += 2) { + for (x = 0; x < width; x += 2) { + cairo_rectangle (cr, x, y, 2, 2); + cairo_clip (cr); + cairo_paint (cr); + cairo_reset_clip (cr); + } + } +#endif + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +record_paint (cairo_t *cr, int width, int height) +{ + return record_replay (cr, paint, width, height); +} + +static cairo_test_status_t +record_paint_alpha (cairo_t *cr, int width, int height) +{ + return record_replay (cr, paint_alpha, width, height); +} + +static cairo_test_status_t +record_paint_alpha_solid_clip (cairo_t *cr, int width, int height) +{ + return record_replay (cr, paint_alpha_solid_clip, width, height); +} + +static cairo_test_status_t +record_paint_alpha_clip (cairo_t *cr, int width, int height) +{ + return record_replay (cr, paint_alpha_clip, width, height); +} + +static cairo_test_status_t +record_paint_alpha_clip_mask (cairo_t *cr, int width, int height) +{ + return record_replay (cr, paint_alpha_clip_mask, width, height); +} + +static cairo_test_status_t +record_fill_alpha (cairo_t *cr, int width, int height) +{ + return record_replay (cr, fill_alpha, width, height); +} + +static cairo_test_status_t +record_self_intersecting (cairo_t *cr, int width, int height) +{ + return record_replay (cr, self_intersecting, width, height); +} + +static cairo_test_status_t +record_select_font_face (cairo_t *cr, int width, int height) +{ + return record_replay (cr, select_font_face, width, height); +} + +static cairo_test_status_t +record_text_transform (cairo_t *cr, int width, int height) +{ + return record_replay (cr, text_transform, width, height); +} + +CAIRO_TEST (record_paint, + "Test replayed calls to cairo_paint", + "paint,record", /* keywords */ + NULL, /* requirements */ + 8, 8, + NULL, record_paint) +CAIRO_TEST (record_paint_alpha, + "Simple test of cairo_paint_with_alpha", + "record, paint, alpha", /* keywords */ + NULL, /* requirements */ + 32, 32, + NULL, record_paint_alpha) +CAIRO_TEST (record_paint_alpha_solid_clip, + "Simple test of cairo_paint_with_alpha+unaligned clip", + "record, paint, alpha, clip", /* keywords */ + NULL, /* requirements */ + 32, 32, + NULL, record_paint_alpha_solid_clip) +CAIRO_TEST (record_paint_alpha_clip, + "Simple test of cairo_paint_with_alpha+unaligned clip", + "record, paint, alpha, clip", /* keywords */ + NULL, /* requirements */ + 32, 32, + NULL, record_paint_alpha_clip) +CAIRO_TEST (record_paint_alpha_clip_mask, + "Simple test of cairo_paint_with_alpha+triangular clip", + "record, paint, alpha, clip", /* keywords */ + NULL, /* requirements */ + 32, 32, + NULL, record_paint_alpha_clip_mask) +CAIRO_TEST (record_fill_alpha, + "Tests using set_rgba();fill()", + "record,fill, alpha", /* keywords */ + NULL, /* requirements */ + 2*SIZE + 4*PAD, 2*SIZE + 4*PAD, + NULL, record_fill_alpha) +CAIRO_TEST (record_select_font_face, + "Tests using cairo_select_font_face to draw text in different faces", + "record, font", /* keywords */ + NULL, /* requirements */ + 192, TEXT_SIZE + 4, + NULL, record_select_font_face) +CAIRO_TEST (record_self_intersecting, + "Test strokes of self-intersecting paths", + "record, stroke, trap", /* keywords */ + NULL, /* requirements */ + 10, 20, + NULL, record_self_intersecting) +CAIRO_TEST (record_text_transform, + "Test various applications of the font matrix", + "record, text, transform", /* keywords */ + NULL, /* requirements */ + TT_SIZE, TT_SIZE, + NULL, record_text_transform) diff --git a/local/recipes/libs/cairo/source/test/record1414x.c b/local/recipes/libs/cairo/source/test/record1414x.c new file mode 100644 index 0000000000..c38857c1fb --- /dev/null +++ b/local/recipes/libs/cairo/source/test/record1414x.c @@ -0,0 +1,498 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2011 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: + * Carl D. Worth + * Chris Wilson + */ + +#include "cairo-test.h" + +#ifndef M_SQRT2 +#define M_SQRT2 1.41421345623730951 +#endif + +#define TEXT_SIZE 12 +#define SIZE 60 /* needs to be big to check large area effects (dithering) */ +#define PAD 2 + +#define TT_SIZE 100 +#define TT_PAD 5 +#define TT_FONT_SIZE 32.0 + +#define GENERATE_REF 0 + +static uint32_t data[16] = { + 0xffffffff, 0xffffffff, 0xffff0000, 0xffff0000, + 0xffffffff, 0xffffffff, 0xffff0000, 0xffff0000, + + 0xff00ff00, 0xff00ff00, 0xff0000ff, 0xff0000ff, + 0xff00ff00, 0xff00ff00, 0xff0000ff, 0xff0000ff +}; + +static const char *png_filename = "romedalen.png"; + +static cairo_t * +paint (cairo_t *cr) +{ + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_paint (cr); + + cairo_translate (cr, 2, 2); + cairo_scale (cr, 0.5, 0.5); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_paint (cr); + + return cr; +} + +static cairo_t * +paint_alpha (cairo_t *cr) +{ + cairo_surface_t *surface; + + surface = cairo_image_surface_create_for_data ((unsigned char *) data, + CAIRO_FORMAT_RGB24, 4, 4, 16); + + cairo_test_paint_checkered (cr); + + cairo_scale (cr, 4, 4); + + cairo_set_source_surface (cr, surface, 2 , 2); + cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); + cairo_paint_with_alpha (cr, 0.5); + + cairo_surface_finish (surface); /* data will go out of scope */ + cairo_surface_destroy (surface); + + return cr; +} + +static cairo_t * +paint_alpha_solid_clip (cairo_t *cr) +{ + cairo_test_paint_checkered (cr); + + cairo_rectangle (cr, 2.5, 2.5, 27, 27); + cairo_clip (cr); + + cairo_set_source_rgb (cr, 1., 0.,0.); + cairo_paint_with_alpha (cr, 0.5); + + return cr; +} + +static cairo_t * +paint_alpha_clip (cairo_t *cr) +{ + cairo_surface_t *surface; + + surface = cairo_image_surface_create_for_data ((unsigned char *) data, + CAIRO_FORMAT_RGB24, 4, 4, 16); + + cairo_test_paint_checkered (cr); + + cairo_rectangle (cr, 10.5, 10.5, 11, 11); + cairo_clip (cr); + + cairo_scale (cr, 4, 4); + + cairo_set_source_surface (cr, surface, 2 , 2); + cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); + cairo_paint_with_alpha (cr, 0.5); + + cairo_surface_finish (surface); /* data will go out of scope */ + cairo_surface_destroy (surface); + + return cr; +} + +static cairo_t * +paint_alpha_clip_mask (cairo_t *cr) +{ + cairo_surface_t *surface; + + surface = cairo_image_surface_create_for_data ((unsigned char *) data, + CAIRO_FORMAT_RGB24, 4, 4, 16); + + cairo_test_paint_checkered (cr); + + cairo_move_to (cr, 16, 5); + cairo_line_to (cr, 5, 16); + cairo_line_to (cr, 16, 27); + cairo_line_to (cr, 27, 16); + cairo_clip (cr); + + cairo_scale (cr, 4, 4); + + cairo_set_source_surface (cr, surface, 2 , 2); + cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); + cairo_paint_with_alpha (cr, 0.5); + + cairo_surface_finish (surface); /* data will go out of scope */ + cairo_surface_destroy (surface); + + return cr; +} + +static cairo_t * +select_font_face (cairo_t *cr) +{ + /* We draw in the default black, so paint white first. */ + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0, 0, 0); /* black */ + + cairo_set_font_size (cr, TEXT_SIZE); + cairo_move_to (cr, 0, TEXT_SIZE); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Serif", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_show_text (cr, "i-am-serif"); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_show_text (cr, " i-am-sans"); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans Mono", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_show_text (cr, " i-am-mono"); + + return cr; +} + +static cairo_t * +fill_alpha (cairo_t *cr) +{ + const double alpha = 1./3; + int n; + + /* flatten to white */ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + /* square */ + cairo_rectangle (cr, PAD, PAD, SIZE, SIZE); + cairo_set_source_rgba (cr, 1, 0, 0, alpha); + cairo_fill (cr); + + /* circle */ + cairo_translate (cr, SIZE + 2 * PAD, 0); + cairo_arc (cr, PAD + SIZE / 2., PAD + SIZE / 2., SIZE / 2., 0, 2 * M_PI); + cairo_set_source_rgba (cr, 0, 1, 0, alpha); + cairo_fill (cr); + + /* triangle */ + cairo_translate (cr, 0, SIZE + 2 * PAD); + cairo_move_to (cr, PAD + SIZE / 2, PAD); + cairo_line_to (cr, PAD + SIZE, PAD + SIZE); + cairo_line_to (cr, PAD, PAD + SIZE); + cairo_set_source_rgba (cr, 0, 0, 1, alpha); + cairo_fill (cr); + + /* star */ + cairo_translate (cr, -(SIZE + 2 * PAD) + SIZE/2., SIZE/2.); + for (n = 0; n < 5; n++) { + cairo_line_to (cr, + SIZE/2 * cos (2*n * 2*M_PI / 10), + SIZE/2 * sin (2*n * 2*M_PI / 10)); + + cairo_line_to (cr, + SIZE/4 * cos ((2*n+1)*2*M_PI / 10), + SIZE/4 * sin ((2*n+1)*2*M_PI / 10)); + } + cairo_set_source_rgba (cr, 0, 0, 0, alpha); + cairo_fill (cr); + + return cr; +} + +static cairo_t * +self_intersecting (cairo_t *cr) +{ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_translate (cr, 1.0, 1.0); + + cairo_set_source_rgb (cr, 1, 0, 0); /* red */ + + /* First draw the desired shape with a fill */ + cairo_rectangle (cr, 0.5, 0.5, 4.0, 4.0); + cairo_rectangle (cr, 3.5, 3.5, 4.0, 4.0); + cairo_rectangle (cr, 3.5, 1.5, -2.0, 2.0); + cairo_rectangle (cr, 6.5, 4.5, -2.0, 2.0); + + cairo_fill (cr); + + /* Then try the same thing with a stroke */ + cairo_translate (cr, 0, 10); + cairo_move_to (cr, 1.0, 1.0); + cairo_rel_line_to (cr, 3.0, 0.0); + cairo_rel_line_to (cr, 0.0, 6.0); + cairo_rel_line_to (cr, 3.0, 0.0); + cairo_rel_line_to (cr, 0.0, -3.0); + cairo_rel_line_to (cr, -6.0, 0.0); + cairo_close_path (cr); + + cairo_set_line_width (cr, 1.0); + cairo_stroke (cr); + + return cr; +} + +static void +draw_text_transform (cairo_t *cr) +{ + cairo_matrix_t tm; + + /* skew */ + cairo_matrix_init (&tm, 1, 0, + -0.25, 1, + 0, 0); + cairo_matrix_scale (&tm, TT_FONT_SIZE, TT_FONT_SIZE); + cairo_set_font_matrix (cr, &tm); + + cairo_new_path (cr); + cairo_move_to (cr, 50, TT_SIZE-TT_PAD); + cairo_show_text (cr, "A"); + + /* rotate and scale */ + cairo_matrix_init_rotate (&tm, M_PI / 2); + cairo_matrix_scale (&tm, TT_FONT_SIZE, TT_FONT_SIZE * 2.0); + cairo_set_font_matrix (cr, &tm); + + cairo_new_path (cr); + cairo_move_to (cr, TT_PAD, TT_PAD + 25); + cairo_show_text (cr, "A"); + + cairo_matrix_init_rotate (&tm, M_PI / 2); + cairo_matrix_scale (&tm, TT_FONT_SIZE * 2.0, TT_FONT_SIZE); + cairo_set_font_matrix (cr, &tm); + + cairo_new_path (cr); + cairo_move_to (cr, TT_PAD, TT_PAD + 50); + cairo_show_text (cr, "A"); +} + +static cairo_t * +text_transform (cairo_t *cr) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_pattern_t *pattern; + + cairo_set_source_rgb (cr, 1., 1., 1.); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0., 0., 0.); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + + draw_text_transform (cr); + + cairo_translate (cr, TT_SIZE, TT_SIZE); + cairo_rotate (cr, M_PI); + + pattern = cairo_test_create_pattern_from_png (ctx, png_filename); + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT); + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + + draw_text_transform (cr); + + return cr; +} + +/* And here begins the recording and replaying... */ + +static cairo_t * +record_create (cairo_t *target) +{ + cairo_surface_t *surface; + cairo_t *cr; + + surface = cairo_recording_surface_create (cairo_surface_get_content (cairo_get_target (target)), NULL); + cr = cairo_test_create (surface, cairo_test_get_context (target)); + cairo_surface_destroy (surface); + + return cr; +} + +static cairo_surface_t * +record_get (cairo_t *target) +{ + cairo_surface_t *surface; + + surface = cairo_surface_reference (cairo_get_target (target)); + cairo_destroy (target); + + return surface; +} + +static cairo_test_status_t +record_replay (cairo_t *cr, cairo_t *(*func)(cairo_t *), int width, int height) +{ + cairo_surface_t *surface; + int x, y; + +#if GENERATE_REF + cairo_scale (cr, M_SQRT2, M_SQRT2); + func (cr); +#else + surface = record_get (func (record_create (cr))); + + cairo_scale (cr, M_SQRT2, M_SQRT2); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_surface (cr, surface, 0, 0); + cairo_surface_destroy (surface); + cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_NONE); + + cairo_identity_matrix (cr); /* make sure the clip is pixel-aligned */ + for (y = 0; y < height; y += 2) { + for (x = 0; x < width; x += 2) { + cairo_rectangle (cr, x, y, 2, 2); + cairo_clip (cr); + cairo_paint (cr); + cairo_reset_clip (cr); + } + } +#endif + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +record_paint (cairo_t *cr, int width, int height) +{ + return record_replay (cr, paint, width, height); +} + +static cairo_test_status_t +record_paint_alpha (cairo_t *cr, int width, int height) +{ + return record_replay (cr, paint_alpha, width, height); +} + +static cairo_test_status_t +record_paint_alpha_solid_clip (cairo_t *cr, int width, int height) +{ + return record_replay (cr, paint_alpha_solid_clip, width, height); +} + +static cairo_test_status_t +record_paint_alpha_clip (cairo_t *cr, int width, int height) +{ + return record_replay (cr, paint_alpha_clip, width, height); +} + +static cairo_test_status_t +record_paint_alpha_clip_mask (cairo_t *cr, int width, int height) +{ + return record_replay (cr, paint_alpha_clip_mask, width, height); +} + +static cairo_test_status_t +record_fill_alpha (cairo_t *cr, int width, int height) +{ + return record_replay (cr, fill_alpha, width, height); +} + +static cairo_test_status_t +record_self_intersecting (cairo_t *cr, int width, int height) +{ + return record_replay (cr, self_intersecting, width, height); +} + +static cairo_test_status_t +record_select_font_face (cairo_t *cr, int width, int height) +{ + return record_replay (cr, select_font_face, width, height); +} + +static cairo_test_status_t +record_text_transform (cairo_t *cr, int width, int height) +{ + return record_replay (cr, text_transform, width, height); +} + +CAIRO_TEST (record1414x_paint, + "Test replayed calls to cairo_paint", + "paint, record", /* keywords */ + NULL, /* requirements */ + M_SQRT2*8, M_SQRT2*8, + NULL, record_paint) +CAIRO_TEST (record1414x_paint_alpha, + "Simple test of cairo_paint_with_alpha", + "record, paint, alpha", /* keywords */ + NULL, /* requirements */ + M_SQRT2*32, M_SQRT2*32, + NULL, record_paint_alpha) +CAIRO_TEST (record1414x_paint_alpha_solid_clip, + "Simple test of cairo_paint_with_alpha+unaligned clip", + "record, paint, alpha, clip", /* keywords */ + NULL, /* requirements */ + M_SQRT2*32, M_SQRT2*32, + NULL, record_paint_alpha_solid_clip) +CAIRO_TEST (record1414x_paint_alpha_clip, + "Simple test of cairo_paint_with_alpha+unaligned clip", + "record, paint, alpha, clip", /* keywords */ + NULL, /* requirements */ + M_SQRT2*32, M_SQRT2*32, + NULL, record_paint_alpha_clip) +CAIRO_TEST (record1414x_paint_alpha_clip_mask, + "Simple test of cairo_paint_with_alpha+triangular clip", + "record, paint, alpha, clip", /* keywords */ + NULL, /* requirements */ + M_SQRT2*32, M_SQRT2*32, + NULL, record_paint_alpha_clip_mask) +CAIRO_TEST (record1414x_fill_alpha, + "Tests using set_rgba();fill()", + "record, fill, alpha", /* keywords */ + NULL, /* requirements */ + M_SQRT2*(2*SIZE + 4*PAD), M_SQRT2*(2*SIZE + 4*PAD), + NULL, record_fill_alpha) +CAIRO_TEST (record1414x_select_font_face, + "Tests using cairo_select_font_face to draw text in different faces", + "record, font", /* keywords */ + NULL, /* requirements */ + M_SQRT2*192, M_SQRT2*(TEXT_SIZE + 4), + NULL, record_select_font_face) +CAIRO_TEST (record1414x_self_intersecting, + "Test strokes of self-intersecting paths", + "record, stroke, trap", /* keywords */ + NULL, /* requirements */ + M_SQRT2*10, M_SQRT2*20, + NULL, record_self_intersecting) +CAIRO_TEST (record1414x_text_transform, + "Test various applications of the font matrix", + "record, text, transform", /* keywords */ + NULL, /* requirements */ + M_SQRT2*TT_SIZE, M_SQRT2*TT_SIZE, + NULL, record_text_transform) diff --git a/local/recipes/libs/cairo/source/test/record2x.c b/local/recipes/libs/cairo/source/test/record2x.c new file mode 100644 index 0000000000..caca0e603b --- /dev/null +++ b/local/recipes/libs/cairo/source/test/record2x.c @@ -0,0 +1,493 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2011 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: + * Carl D. Worth + * Chris Wilson + */ + +#include "cairo-test.h" + +#define TEXT_SIZE 12 +#define SIZE 60 /* needs to be big to check large area effects (dithering) */ +#define PAD 2 + +#define TT_SIZE 100 +#define TT_PAD 5 +#define TT_FONT_SIZE 32.0 + +#define GENERATE_REF 0 + +static uint32_t data[16] = { + 0xffffffff, 0xffffffff, 0xffff0000, 0xffff0000, + 0xffffffff, 0xffffffff, 0xffff0000, 0xffff0000, + + 0xff00ff00, 0xff00ff00, 0xff0000ff, 0xff0000ff, + 0xff00ff00, 0xff00ff00, 0xff0000ff, 0xff0000ff +}; + +static const char *png_filename = "romedalen.png"; + +static cairo_t * +paint (cairo_t *cr) +{ + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_paint (cr); + + cairo_translate (cr, 2, 2); + cairo_scale (cr, 0.5, 0.5); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_paint (cr); + + return cr; +} + +static cairo_t * +paint_alpha (cairo_t *cr) +{ + cairo_surface_t *surface; + + surface = cairo_image_surface_create_for_data ((unsigned char *) data, + CAIRO_FORMAT_RGB24, 4, 4, 16); + + cairo_test_paint_checkered (cr); + + cairo_scale (cr, 4, 4); + + cairo_set_source_surface (cr, surface, 2 , 2); + cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); + cairo_paint_with_alpha (cr, 0.5); + + cairo_surface_finish (surface); /* data will go out of scope */ + cairo_surface_destroy (surface); + + return cr; +} + +static cairo_t * +paint_alpha_solid_clip (cairo_t *cr) +{ + cairo_test_paint_checkered (cr); + + cairo_rectangle (cr, 2.5, 2.5, 27, 27); + cairo_clip (cr); + + cairo_set_source_rgb (cr, 1., 0.,0.); + cairo_paint_with_alpha (cr, 0.5); + + return cr; +} + +static cairo_t * +paint_alpha_clip (cairo_t *cr) +{ + cairo_surface_t *surface; + + surface = cairo_image_surface_create_for_data ((unsigned char *) data, + CAIRO_FORMAT_RGB24, 4, 4, 16); + + cairo_test_paint_checkered (cr); + + cairo_rectangle (cr, 10.5, 10.5, 11, 11); + cairo_clip (cr); + + cairo_scale (cr, 4, 4); + + cairo_set_source_surface (cr, surface, 2 , 2); + cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); + cairo_paint_with_alpha (cr, 0.5); + + cairo_surface_finish (surface); /* data will go out of scope */ + cairo_surface_destroy (surface); + + return cr; +} + +static cairo_t * +paint_alpha_clip_mask (cairo_t *cr) +{ + cairo_surface_t *surface; + + surface = cairo_image_surface_create_for_data ((unsigned char *) data, + CAIRO_FORMAT_RGB24, 4, 4, 16); + + cairo_test_paint_checkered (cr); + + cairo_move_to (cr, 16, 5); + cairo_line_to (cr, 5, 16); + cairo_line_to (cr, 16, 27); + cairo_line_to (cr, 27, 16); + cairo_clip (cr); + + cairo_scale (cr, 4, 4); + + cairo_set_source_surface (cr, surface, 2 , 2); + cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); + cairo_paint_with_alpha (cr, 0.5); + + cairo_surface_finish (surface); /* data will go out of scope */ + cairo_surface_destroy (surface); + + return cr; +} + +static cairo_t * +select_font_face (cairo_t *cr) +{ + /* We draw in the default black, so paint white first. */ + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0, 0, 0); /* black */ + + cairo_set_font_size (cr, TEXT_SIZE); + cairo_move_to (cr, 0, TEXT_SIZE); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Serif", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_show_text (cr, "i-am-serif"); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_show_text (cr, " i-am-sans"); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans Mono", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_show_text (cr, " i-am-mono"); + + return cr; +} + +static cairo_t * +fill_alpha (cairo_t *cr) +{ + const double alpha = 1./3; + int n; + + /* flatten to white */ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + /* square */ + cairo_rectangle (cr, PAD, PAD, SIZE, SIZE); + cairo_set_source_rgba (cr, 1, 0, 0, alpha); + cairo_fill (cr); + + /* circle */ + cairo_translate (cr, SIZE + 2 * PAD, 0); + cairo_arc (cr, PAD + SIZE / 2., PAD + SIZE / 2., SIZE / 2., 0, 2 * M_PI); + cairo_set_source_rgba (cr, 0, 1, 0, alpha); + cairo_fill (cr); + + /* triangle */ + cairo_translate (cr, 0, SIZE + 2 * PAD); + cairo_move_to (cr, PAD + SIZE / 2, PAD); + cairo_line_to (cr, PAD + SIZE, PAD + SIZE); + cairo_line_to (cr, PAD, PAD + SIZE); + cairo_set_source_rgba (cr, 0, 0, 1, alpha); + cairo_fill (cr); + + /* star */ + cairo_translate (cr, -(SIZE + 2 * PAD) + SIZE/2., SIZE/2.); + for (n = 0; n < 5; n++) { + cairo_line_to (cr, + SIZE/2 * cos (2*n * 2*M_PI / 10), + SIZE/2 * sin (2*n * 2*M_PI / 10)); + + cairo_line_to (cr, + SIZE/4 * cos ((2*n+1)*2*M_PI / 10), + SIZE/4 * sin ((2*n+1)*2*M_PI / 10)); + } + cairo_set_source_rgba (cr, 0, 0, 0, alpha); + cairo_fill (cr); + + return cr; +} + +static cairo_t * +self_intersecting (cairo_t *cr) +{ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_translate (cr, 1.0, 1.0); + + cairo_set_source_rgb (cr, 1, 0, 0); /* red */ + + /* First draw the desired shape with a fill */ + cairo_rectangle (cr, 0.5, 0.5, 4.0, 4.0); + cairo_rectangle (cr, 3.5, 3.5, 4.0, 4.0); + cairo_rectangle (cr, 3.5, 1.5, -2.0, 2.0); + cairo_rectangle (cr, 6.5, 4.5, -2.0, 2.0); + + cairo_fill (cr); + + /* Then try the same thing with a stroke */ + cairo_translate (cr, 0, 10); + cairo_move_to (cr, 1.0, 1.0); + cairo_rel_line_to (cr, 3.0, 0.0); + cairo_rel_line_to (cr, 0.0, 6.0); + cairo_rel_line_to (cr, 3.0, 0.0); + cairo_rel_line_to (cr, 0.0, -3.0); + cairo_rel_line_to (cr, -6.0, 0.0); + cairo_close_path (cr); + + cairo_set_line_width (cr, 1.0); + cairo_stroke (cr); + + return cr; +} + +static void +draw_text_transform (cairo_t *cr) +{ + cairo_matrix_t tm; + + /* skew */ + cairo_matrix_init (&tm, 1, 0, + -0.25, 1, + 0, 0); + cairo_matrix_scale (&tm, TT_FONT_SIZE, TT_FONT_SIZE); + cairo_set_font_matrix (cr, &tm); + + cairo_new_path (cr); + cairo_move_to (cr, 50, TT_SIZE-TT_PAD); + cairo_show_text (cr, "A"); + + /* rotate and scale */ + cairo_matrix_init_rotate (&tm, M_PI / 2); + cairo_matrix_scale (&tm, TT_FONT_SIZE, TT_FONT_SIZE * 2.0); + cairo_set_font_matrix (cr, &tm); + + cairo_new_path (cr); + cairo_move_to (cr, TT_PAD, TT_PAD + 25); + cairo_show_text (cr, "A"); + + cairo_matrix_init_rotate (&tm, M_PI / 2); + cairo_matrix_scale (&tm, TT_FONT_SIZE * 2.0, TT_FONT_SIZE); + cairo_set_font_matrix (cr, &tm); + + cairo_new_path (cr); + cairo_move_to (cr, TT_PAD, TT_PAD + 50); + cairo_show_text (cr, "A"); +} + +static cairo_t * +text_transform (cairo_t *cr) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_pattern_t *pattern; + + cairo_set_source_rgb (cr, 1., 1., 1.); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0., 0., 0.); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + + draw_text_transform (cr); + + cairo_translate (cr, TT_SIZE, TT_SIZE); + cairo_rotate (cr, M_PI); + + pattern = cairo_test_create_pattern_from_png (ctx, png_filename); + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT); + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + + draw_text_transform (cr); + + return cr; +} + +/* And here begins the recording and replaying... */ + +static cairo_t * +record_create (cairo_t *target) +{ + cairo_surface_t *surface; + cairo_t *cr; + + surface = cairo_recording_surface_create (cairo_surface_get_content (cairo_get_target (target)), NULL); + cr = cairo_test_create (surface, cairo_test_get_context (target)); + cairo_surface_destroy (surface); + + return cr; +} + +static cairo_surface_t * +record_get (cairo_t *target) +{ + cairo_surface_t *surface; + + surface = cairo_surface_reference (cairo_get_target (target)); + cairo_destroy (target); + + return surface; +} + +static cairo_test_status_t +record_replay (cairo_t *cr, cairo_t *(*func)(cairo_t *), int width, int height) +{ + cairo_surface_t *surface; + int x, y; + +#if GENERATE_REF + cairo_scale (cr, 2, 2); + func(cr); +#else + surface = record_get (func (record_create (cr))); + + cairo_scale (cr, 2, 2); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_surface (cr, surface, 0, 0); + cairo_surface_destroy (surface); + cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_NONE); + + for (y = 0; y < height; y += 2) { + for (x = 0; x < width; x += 2) { + cairo_rectangle (cr, x, y, 2, 2); + cairo_clip (cr); + cairo_paint (cr); + cairo_reset_clip (cr); + } + } +#endif + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +record_paint (cairo_t *cr, int width, int height) +{ + return record_replay (cr, paint, width, height); +} + +static cairo_test_status_t +record_paint_alpha (cairo_t *cr, int width, int height) +{ + return record_replay (cr, paint_alpha, width, height); +} + +static cairo_test_status_t +record_paint_alpha_solid_clip (cairo_t *cr, int width, int height) +{ + return record_replay (cr, paint_alpha_solid_clip, width, height); +} + +static cairo_test_status_t +record_paint_alpha_clip (cairo_t *cr, int width, int height) +{ + return record_replay (cr, paint_alpha_clip, width, height); +} + +static cairo_test_status_t +record_paint_alpha_clip_mask (cairo_t *cr, int width, int height) +{ + return record_replay (cr, paint_alpha_clip_mask, width, height); +} + +static cairo_test_status_t +record_fill_alpha (cairo_t *cr, int width, int height) +{ + return record_replay (cr, fill_alpha, width, height); +} + +static cairo_test_status_t +record_self_intersecting (cairo_t *cr, int width, int height) +{ + return record_replay (cr, self_intersecting, width, height); +} + +static cairo_test_status_t +record_select_font_face (cairo_t *cr, int width, int height) +{ + return record_replay (cr, select_font_face, width, height); +} + +static cairo_test_status_t +record_text_transform (cairo_t *cr, int width, int height) +{ + return record_replay (cr, text_transform, width, height); +} + +CAIRO_TEST (record2x_paint, + "Test replayed calls to cairo_paint", + "paint,record", /* keywords */ + NULL, /* requirements */ + 2*8, 2*8, + NULL, record_paint) +CAIRO_TEST (record2x_paint_alpha, + "Simple test of cairo_paint_with_alpha", + "record, paint, alpha", /* keywords */ + NULL, /* requirements */ + 2*32, 2*32, + NULL, record_paint_alpha) +CAIRO_TEST (record2x_paint_alpha_solid_clip, + "Simple test of cairo_paint_with_alpha+unaligned clip", + "record, paint, alpha, clip", /* keywords */ + NULL, /* requirements */ + 2*32, 2*32, + NULL, record_paint_alpha_solid_clip) +CAIRO_TEST (record2x_paint_alpha_clip, + "Simple test of cairo_paint_with_alpha+unaligned clip", + "record, paint, alpha, clip", /* keywords */ + NULL, /* requirements */ + 2*32, 2*32, + NULL, record_paint_alpha_clip) +CAIRO_TEST (record2x_paint_alpha_clip_mask, + "Simple test of cairo_paint_with_alpha+triangular clip", + "record, paint, alpha, clip", /* keywords */ + NULL, /* requirements */ + 2*32, 2*32, + NULL, record_paint_alpha_clip_mask) +CAIRO_TEST (record2x_fill_alpha, + "Tests using set_rgba();fill()", + "record,fill, alpha", /* keywords */ + NULL, /* requirements */ + 2*(2*SIZE + 4*PAD), 2*(2*SIZE + 4*PAD), + NULL, record_fill_alpha) +CAIRO_TEST (record2x_select_font_face, + "Tests using cairo_select_font_face to draw text in different faces", + "record, font", /* keywords */ + NULL, /* requirements */ + 2*192, 2*(TEXT_SIZE + 4), + NULL, record_select_font_face) +CAIRO_TEST (record2x_self_intersecting, + "Test strokes of self-intersecting paths", + "record, stroke, trap", /* keywords */ + NULL, /* requirements */ + 2*10, 2*20, + NULL, record_self_intersecting) +CAIRO_TEST (record2x_text_transform, + "Test various applications of the font matrix", + "record, text, transform", /* keywords */ + NULL, /* requirements */ + 2*TT_SIZE, 2*TT_SIZE, + NULL, record_text_transform) diff --git a/local/recipes/libs/cairo/source/test/record90.c b/local/recipes/libs/cairo/source/test/record90.c new file mode 100644 index 0000000000..aeec5af816 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/record90.c @@ -0,0 +1,495 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2011 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: + * Carl D. Worth + * Chris Wilson + */ + +#include "cairo-test.h" + +#define TEXT_SIZE 12 +#define SIZE 60 /* needs to be big to check large area effects (dithering) */ +#define PAD 2 + +#define TT_SIZE 100 +#define TT_PAD 5 +#define TT_FONT_SIZE 32.0 + +#define GENERATE_REF 0 + +static uint32_t data[16] = { + 0xffffffff, 0xffffffff, 0xffff0000, 0xffff0000, + 0xffffffff, 0xffffffff, 0xffff0000, 0xffff0000, + + 0xff00ff00, 0xff00ff00, 0xff0000ff, 0xff0000ff, + 0xff00ff00, 0xff00ff00, 0xff0000ff, 0xff0000ff +}; + +static const char *png_filename = "romedalen.png"; + +static cairo_t * +paint (cairo_t *cr) +{ + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_paint (cr); + + cairo_translate (cr, 2, 2); + cairo_scale (cr, 0.5, 0.5); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_paint (cr); + + return cr; +} + +static cairo_t * +paint_alpha (cairo_t *cr) +{ + cairo_surface_t *surface; + + surface = cairo_image_surface_create_for_data ((unsigned char *) data, + CAIRO_FORMAT_RGB24, 4, 4, 16); + + cairo_test_paint_checkered (cr); + + cairo_scale (cr, 4, 4); + + cairo_set_source_surface (cr, surface, 2 , 2); + cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); + cairo_paint_with_alpha (cr, 0.5); + + cairo_surface_finish (surface); /* data will go out of scope */ + cairo_surface_destroy (surface); + + return cr; +} + +static cairo_t * +paint_alpha_solid_clip (cairo_t *cr) +{ + cairo_test_paint_checkered (cr); + + cairo_rectangle (cr, 2.5, 2.5, 27, 27); + cairo_clip (cr); + + cairo_set_source_rgb (cr, 1., 0.,0.); + cairo_paint_with_alpha (cr, 0.5); + + return cr; +} + +static cairo_t * +paint_alpha_clip (cairo_t *cr) +{ + cairo_surface_t *surface; + + surface = cairo_image_surface_create_for_data ((unsigned char *) data, + CAIRO_FORMAT_RGB24, 4, 4, 16); + + cairo_test_paint_checkered (cr); + + cairo_rectangle (cr, 10.5, 10.5, 11, 11); + cairo_clip (cr); + + cairo_scale (cr, 4, 4); + + cairo_set_source_surface (cr, surface, 2 , 2); + cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); + cairo_paint_with_alpha (cr, 0.5); + + cairo_surface_finish (surface); /* data will go out of scope */ + cairo_surface_destroy (surface); + + return cr; +} + +static cairo_t * +paint_alpha_clip_mask (cairo_t *cr) +{ + cairo_surface_t *surface; + + surface = cairo_image_surface_create_for_data ((unsigned char *) data, + CAIRO_FORMAT_RGB24, 4, 4, 16); + + cairo_test_paint_checkered (cr); + + cairo_move_to (cr, 16, 5); + cairo_line_to (cr, 5, 16); + cairo_line_to (cr, 16, 27); + cairo_line_to (cr, 27, 16); + cairo_clip (cr); + + cairo_scale (cr, 4, 4); + + cairo_set_source_surface (cr, surface, 2 , 2); + cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); + cairo_paint_with_alpha (cr, 0.5); + + cairo_surface_finish (surface); /* data will go out of scope */ + cairo_surface_destroy (surface); + + return cr; +} + +static cairo_t * +select_font_face (cairo_t *cr) +{ + /* We draw in the default black, so paint white first. */ + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0, 0, 0); /* black */ + + cairo_set_font_size (cr, TEXT_SIZE); + cairo_move_to (cr, 0, TEXT_SIZE); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Serif", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_show_text (cr, "i-am-serif"); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_show_text (cr, " i-am-sans"); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans Mono", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_show_text (cr, " i-am-mono"); + + return cr; +} + +static cairo_t * +fill_alpha (cairo_t *cr) +{ + const double alpha = 1./3; + int n; + + /* flatten to white */ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + /* square */ + cairo_rectangle (cr, PAD, PAD, SIZE, SIZE); + cairo_set_source_rgba (cr, 1, 0, 0, alpha); + cairo_fill (cr); + + /* circle */ + cairo_translate (cr, SIZE + 2 * PAD, 0); + cairo_arc (cr, PAD + SIZE / 2., PAD + SIZE / 2., SIZE / 2., 0, 2 * M_PI); + cairo_set_source_rgba (cr, 0, 1, 0, alpha); + cairo_fill (cr); + + /* triangle */ + cairo_translate (cr, 0, SIZE + 2 * PAD); + cairo_move_to (cr, PAD + SIZE / 2, PAD); + cairo_line_to (cr, PAD + SIZE, PAD + SIZE); + cairo_line_to (cr, PAD, PAD + SIZE); + cairo_set_source_rgba (cr, 0, 0, 1, alpha); + cairo_fill (cr); + + /* star */ + cairo_translate (cr, -(SIZE + 2 * PAD) + SIZE/2., SIZE/2.); + for (n = 0; n < 5; n++) { + cairo_line_to (cr, + SIZE/2 * cos (2*n * 2*M_PI / 10), + SIZE/2 * sin (2*n * 2*M_PI / 10)); + + cairo_line_to (cr, + SIZE/4 * cos ((2*n+1)*2*M_PI / 10), + SIZE/4 * sin ((2*n+1)*2*M_PI / 10)); + } + cairo_set_source_rgba (cr, 0, 0, 0, alpha); + cairo_fill (cr); + + return cr; +} + +static cairo_t * +self_intersecting (cairo_t *cr) +{ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_translate (cr, 1.0, 1.0); + + cairo_set_source_rgb (cr, 1, 0, 0); /* red */ + + /* First draw the desired shape with a fill */ + cairo_rectangle (cr, 0.5, 0.5, 4.0, 4.0); + cairo_rectangle (cr, 3.5, 3.5, 4.0, 4.0); + cairo_rectangle (cr, 3.5, 1.5, -2.0, 2.0); + cairo_rectangle (cr, 6.5, 4.5, -2.0, 2.0); + + cairo_fill (cr); + + /* Then try the same thing with a stroke */ + cairo_translate (cr, 0, 10); + cairo_move_to (cr, 1.0, 1.0); + cairo_rel_line_to (cr, 3.0, 0.0); + cairo_rel_line_to (cr, 0.0, 6.0); + cairo_rel_line_to (cr, 3.0, 0.0); + cairo_rel_line_to (cr, 0.0, -3.0); + cairo_rel_line_to (cr, -6.0, 0.0); + cairo_close_path (cr); + + cairo_set_line_width (cr, 1.0); + cairo_stroke (cr); + + return cr; +} + +static void +draw_text_transform (cairo_t *cr) +{ + cairo_matrix_t tm; + + /* skew */ + cairo_matrix_init (&tm, 1, 0, + -0.25, 1, + 0, 0); + cairo_matrix_scale (&tm, TT_FONT_SIZE, TT_FONT_SIZE); + cairo_set_font_matrix (cr, &tm); + + cairo_new_path (cr); + cairo_move_to (cr, 50, TT_SIZE-TT_PAD); + cairo_show_text (cr, "A"); + + /* rotate and scale */ + cairo_matrix_init_rotate (&tm, M_PI / 2); + cairo_matrix_scale (&tm, TT_FONT_SIZE, TT_FONT_SIZE * 2.0); + cairo_set_font_matrix (cr, &tm); + + cairo_new_path (cr); + cairo_move_to (cr, TT_PAD, TT_PAD + 25); + cairo_show_text (cr, "A"); + + cairo_matrix_init_rotate (&tm, M_PI / 2); + cairo_matrix_scale (&tm, TT_FONT_SIZE * 2.0, TT_FONT_SIZE); + cairo_set_font_matrix (cr, &tm); + + cairo_new_path (cr); + cairo_move_to (cr, TT_PAD, TT_PAD + 50); + cairo_show_text (cr, "A"); +} + +static cairo_t * +text_transform (cairo_t *cr) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_pattern_t *pattern; + + cairo_set_source_rgb (cr, 1., 1., 1.); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0., 0., 0.); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + + draw_text_transform (cr); + + cairo_translate (cr, TT_SIZE, TT_SIZE); + cairo_rotate (cr, M_PI); + + pattern = cairo_test_create_pattern_from_png (ctx, png_filename); + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT); + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + + draw_text_transform (cr); + + return cr; +} + +/* And here begins the recording and replaying... */ + +static cairo_t * +record_create (cairo_t *target) +{ + cairo_surface_t *surface; + cairo_t *cr; + + surface = cairo_recording_surface_create (cairo_surface_get_content (cairo_get_target (target)), NULL); + cr = cairo_test_create (surface, cairo_test_get_context (target)); + cairo_surface_destroy (surface); + + return cr; +} + +static cairo_surface_t * +record_get (cairo_t *target) +{ + cairo_surface_t *surface; + + surface = cairo_surface_reference (cairo_get_target (target)); + cairo_destroy (target); + + return surface; +} + +static cairo_test_status_t +record_replay (cairo_t *cr, cairo_t *(*func)(cairo_t *), int width, int height) +{ + cairo_surface_t *surface; + int x, y; + +#if GENERATE_REF + cairo_translate(cr, width, 0); + cairo_rotate (cr, M_PI/2); + func(cr); +#else + surface = record_get (func (record_create (cr))); + + cairo_translate(cr, width, 0); + cairo_rotate (cr, M_PI/2); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_surface (cr, surface, 0, 0); + cairo_surface_destroy (surface); + cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_NONE); + + for (y = 0; y < width; y += 2) { + for (x = 0; x < height; x += 2) { + cairo_rectangle (cr, x, y, 2, 2); + cairo_clip (cr); + cairo_paint (cr); + cairo_reset_clip (cr); + } + } +#endif + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +record_paint (cairo_t *cr, int width, int height) +{ + return record_replay (cr, paint, width, height); +} + +static cairo_test_status_t +record_paint_alpha (cairo_t *cr, int width, int height) +{ + return record_replay (cr, paint_alpha, width, height); +} + +static cairo_test_status_t +record_paint_alpha_solid_clip (cairo_t *cr, int width, int height) +{ + return record_replay (cr, paint_alpha_solid_clip, width, height); +} + +static cairo_test_status_t +record_paint_alpha_clip (cairo_t *cr, int width, int height) +{ + return record_replay (cr, paint_alpha_clip, width, height); +} + +static cairo_test_status_t +record_paint_alpha_clip_mask (cairo_t *cr, int width, int height) +{ + return record_replay (cr, paint_alpha_clip_mask, width, height); +} + +static cairo_test_status_t +record_fill_alpha (cairo_t *cr, int width, int height) +{ + return record_replay (cr, fill_alpha, width, height); +} + +static cairo_test_status_t +record_self_intersecting (cairo_t *cr, int width, int height) +{ + return record_replay (cr, self_intersecting, width, height); +} + +static cairo_test_status_t +record_select_font_face (cairo_t *cr, int width, int height) +{ + return record_replay (cr, select_font_face, width, height); +} + +static cairo_test_status_t +record_text_transform (cairo_t *cr, int width, int height) +{ + return record_replay (cr, text_transform, width, height); +} + +CAIRO_TEST (record90_paint, + "Test replayed calls to cairo_paint", + "paint,record", /* keywords */ + NULL, /* requirements */ + 8, 8, + NULL, record_paint) +CAIRO_TEST (record90_paint_alpha, + "Simple test of cairo_paint_with_alpha", + "record, paint, alpha", /* keywords */ + NULL, /* requirements */ + 2, 32, + NULL, record_paint_alpha) +CAIRO_TEST (record90_paint_alpha_solid_clip, + "Simple test of cairo_paint_with_alpha+unaligned clip", + "record, paint, alpha, clip", /* keywords */ + NULL, /* requirements */ + 32, 32, + NULL, record_paint_alpha_solid_clip) +CAIRO_TEST (record90_paint_alpha_clip, + "Simple test of cairo_paint_with_alpha+unaligned clip", + "record, paint, alpha, clip", /* keywords */ + NULL, /* requirements */ + 32, 32, + NULL, record_paint_alpha_clip) +CAIRO_TEST (record90_paint_alpha_clip_mask, + "Simple test of cairo_paint_with_alpha+triangular clip", + "record, paint, alpha, clip", /* keywords */ + NULL, /* requirements */ + 32, 32, + NULL, record_paint_alpha_clip_mask) +CAIRO_TEST (record90_fill_alpha, + "Tests using set_rgba();fill()", + "record,fill, alpha", /* keywords */ + NULL, /* requirements */ + 2*SIZE + 4*PAD, 2*SIZE + 4*PAD, + NULL, record_fill_alpha) +CAIRO_TEST (record90_select_font_face, + "Tests using cairo_select_font_face to draw text in different faces", + "record, font", /* keywords */ + NULL, /* requirements */ + TEXT_SIZE + 4, 192, + NULL, record_select_font_face) +CAIRO_TEST (record90_self_intersecting, + "Test strokes of self-intersecting paths", + "record, stroke, trap", /* keywords */ + NULL, /* requirements */ + 20, 10, + NULL, record_self_intersecting) +CAIRO_TEST (record90_text_transform, + "Test various applications of the font matrix", + "record, text, transform", /* keywords */ + NULL, /* requirements */ + TT_SIZE, TT_SIZE, + NULL, record_text_transform) diff --git a/local/recipes/libs/cairo/source/test/recordflip.c b/local/recipes/libs/cairo/source/test/recordflip.c new file mode 100644 index 0000000000..495fe9dd6f --- /dev/null +++ b/local/recipes/libs/cairo/source/test/recordflip.c @@ -0,0 +1,733 @@ +/* + * Copyright © 2011,2013 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +#define TEXT_SIZE 12 +#define SIZE 60 /* needs to be big to check large area effects (dithering) */ +#define PAD 2 + +#define TT_SIZE 100 +#define TT_PAD 5 +#define TT_FONT_SIZE 32.0 + +#define GENERATE_REF 0 + +static uint32_t data[16] = { + 0xffffffff, 0xffffffff, 0xffff0000, 0xffff0000, + 0xffffffff, 0xffffffff, 0xffff0000, 0xffff0000, + + 0xff00ff00, 0xff00ff00, 0xff0000ff, 0xff0000ff, + 0xff00ff00, 0xff00ff00, 0xff0000ff, 0xff0000ff +}; + +static const char *png_filename = "romedalen.png"; + +static cairo_t * +paint (cairo_t *cr) +{ + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_paint (cr); + + cairo_translate (cr, 2, 2); + cairo_scale (cr, 0.5, 0.5); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_paint (cr); + + return cr; +} + +static cairo_t * +paint_alpha (cairo_t *cr) +{ + cairo_surface_t *surface; + + surface = cairo_image_surface_create_for_data ((unsigned char *) data, + CAIRO_FORMAT_RGB24, 4, 4, 16); + + cairo_test_paint_checkered (cr); + + cairo_scale (cr, 4, 4); + + cairo_set_source_surface (cr, surface, 2 , 2); + cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); + cairo_paint_with_alpha (cr, 0.5); + + cairo_surface_finish (surface); /* data will go out of scope */ + cairo_surface_destroy (surface); + + return cr; +} + +static cairo_t * +paint_alpha_solid_clip (cairo_t *cr) +{ + cairo_test_paint_checkered (cr); + + cairo_rectangle (cr, 2.5, 2.5, 27, 27); + cairo_clip (cr); + + cairo_set_source_rgb (cr, 1., 0.,0.); + cairo_paint_with_alpha (cr, 0.5); + + return cr; +} + +static cairo_t * +paint_alpha_clip (cairo_t *cr) +{ + cairo_surface_t *surface; + + surface = cairo_image_surface_create_for_data ((unsigned char *) data, + CAIRO_FORMAT_RGB24, 4, 4, 16); + + cairo_test_paint_checkered (cr); + + cairo_rectangle (cr, 10.5, 10.5, 11, 11); + cairo_clip (cr); + + cairo_scale (cr, 4, 4); + + cairo_set_source_surface (cr, surface, 2 , 2); + cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); + cairo_paint_with_alpha (cr, 0.5); + + cairo_surface_finish (surface); /* data will go out of scope */ + cairo_surface_destroy (surface); + + return cr; +} + +static cairo_t * +paint_alpha_clip_mask (cairo_t *cr) +{ + cairo_surface_t *surface; + + surface = cairo_image_surface_create_for_data ((unsigned char *) data, + CAIRO_FORMAT_RGB24, 4, 4, 16); + + cairo_test_paint_checkered (cr); + + cairo_move_to (cr, 16, 5); + cairo_line_to (cr, 5, 16); + cairo_line_to (cr, 16, 27); + cairo_line_to (cr, 27, 16); + cairo_clip (cr); + + cairo_scale (cr, 4, 4); + + cairo_set_source_surface (cr, surface, 2 , 2); + cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); + cairo_paint_with_alpha (cr, 0.5); + + cairo_surface_finish (surface); /* data will go out of scope */ + cairo_surface_destroy (surface); + + return cr; +} + +static cairo_t * +select_font_face (cairo_t *cr) +{ + /* We draw in the default black, so paint white first. */ + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0, 0, 0); /* black */ + + cairo_set_font_size (cr, TEXT_SIZE); + cairo_move_to (cr, 0, TEXT_SIZE); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Serif", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_show_text (cr, "i-am-serif"); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_show_text (cr, " i-am-sans"); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans Mono", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_show_text (cr, " i-am-mono"); + + return cr; +} + +static cairo_t * +fill_alpha (cairo_t *cr) +{ + const double alpha = 1./3; + int n; + + /* flatten to white */ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + /* square */ + cairo_rectangle (cr, PAD, PAD, SIZE, SIZE); + cairo_set_source_rgba (cr, 1, 0, 0, alpha); + cairo_fill (cr); + + /* circle */ + cairo_translate (cr, SIZE + 2 * PAD, 0); + cairo_arc (cr, PAD + SIZE / 2., PAD + SIZE / 2., SIZE / 2., 0, 2 * M_PI); + cairo_set_source_rgba (cr, 0, 1, 0, alpha); + cairo_fill (cr); + + /* triangle */ + cairo_translate (cr, 0, SIZE + 2 * PAD); + cairo_move_to (cr, PAD + SIZE / 2, PAD); + cairo_line_to (cr, PAD + SIZE, PAD + SIZE); + cairo_line_to (cr, PAD, PAD + SIZE); + cairo_set_source_rgba (cr, 0, 0, 1, alpha); + cairo_fill (cr); + + /* star */ + cairo_translate (cr, -(SIZE + 2 * PAD) + SIZE/2., SIZE/2.); + for (n = 0; n < 5; n++) { + cairo_line_to (cr, + SIZE/2 * cos (2*n * 2*M_PI / 10), + SIZE/2 * sin (2*n * 2*M_PI / 10)); + + cairo_line_to (cr, + SIZE/4 * cos ((2*n+1)*2*M_PI / 10), + SIZE/4 * sin ((2*n+1)*2*M_PI / 10)); + } + cairo_set_source_rgba (cr, 0, 0, 0, alpha); + cairo_fill (cr); + + return cr; +} + +static cairo_t * +self_intersecting (cairo_t *cr) +{ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_translate (cr, 1.0, 1.0); + + cairo_set_source_rgb (cr, 1, 0, 0); /* red */ + + /* First draw the desired shape with a fill */ + cairo_rectangle (cr, 0.5, 0.5, 4.0, 4.0); + cairo_rectangle (cr, 3.5, 3.5, 4.0, 4.0); + cairo_rectangle (cr, 3.5, 1.5, -2.0, 2.0); + cairo_rectangle (cr, 6.5, 4.5, -2.0, 2.0); + + cairo_fill (cr); + + /* Then try the same thing with a stroke */ + cairo_translate (cr, 0, 10); + cairo_move_to (cr, 1.0, 1.0); + cairo_rel_line_to (cr, 3.0, 0.0); + cairo_rel_line_to (cr, 0.0, 6.0); + cairo_rel_line_to (cr, 3.0, 0.0); + cairo_rel_line_to (cr, 0.0, -3.0); + cairo_rel_line_to (cr, -6.0, 0.0); + cairo_close_path (cr); + + cairo_set_line_width (cr, 1.0); + cairo_stroke (cr); + + return cr; +} + +static void +draw_text_transform (cairo_t *cr) +{ + cairo_matrix_t tm; + + /* skew */ + cairo_matrix_init (&tm, 1, 0, + -0.25, 1, + 0, 0); + cairo_matrix_scale (&tm, TT_FONT_SIZE, TT_FONT_SIZE); + cairo_set_font_matrix (cr, &tm); + + cairo_new_path (cr); + cairo_move_to (cr, 50, TT_SIZE-TT_PAD); + cairo_show_text (cr, "A"); + + /* rotate and scale */ + cairo_matrix_init_rotate (&tm, M_PI / 2); + cairo_matrix_scale (&tm, TT_FONT_SIZE, TT_FONT_SIZE * 2.0); + cairo_set_font_matrix (cr, &tm); + + cairo_new_path (cr); + cairo_move_to (cr, TT_PAD, TT_PAD + 25); + cairo_show_text (cr, "A"); + + cairo_matrix_init_rotate (&tm, M_PI / 2); + cairo_matrix_scale (&tm, TT_FONT_SIZE * 2.0, TT_FONT_SIZE); + cairo_set_font_matrix (cr, &tm); + + cairo_new_path (cr); + cairo_move_to (cr, TT_PAD, TT_PAD + 50); + cairo_show_text (cr, "A"); +} + +static cairo_t * +text_transform (cairo_t *cr) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_pattern_t *pattern; + + cairo_set_source_rgb (cr, 1., 1., 1.); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0., 0., 0.); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + + draw_text_transform (cr); + + cairo_translate (cr, TT_SIZE, TT_SIZE); + cairo_rotate (cr, M_PI); + + pattern = cairo_test_create_pattern_from_png (ctx, png_filename); + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT); + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + + draw_text_transform (cr); + + return cr; +} + +/* And here begins the recording and replaying... */ + +static cairo_t * +record_create (cairo_t *target) +{ + cairo_surface_t *surface; + cairo_t *cr; + + surface = cairo_recording_surface_create (cairo_surface_get_content (cairo_get_target (target)), NULL); + cr = cairo_test_create (surface, cairo_test_get_context (target)); + cairo_surface_destroy (surface); + + return cr; +} + +static cairo_surface_t * +record_get (cairo_t *target) +{ + cairo_surface_t *surface; + + surface = cairo_surface_reference (cairo_get_target (target)); + cairo_destroy (target); + + return surface; +} + +static cairo_test_status_t +record_replay (cairo_t *cr, cairo_t *(*func)(cairo_t *), int width, int height) +{ + cairo_surface_t *surface; + int x, y; + +#if GENERATE_REF + { + cairo_surface_t *image; + uint8_t *data, *tmp; + int stride, bpp; + + surface = cairo_get_target (cr); + + func(cr); + + image = cairo_surface_map_to_image (surface, NULL); + + switch (cairo_image_surface_get_format (image)) { + case CAIRO_FORMAT_ARGB32: + case CAIRO_FORMAT_RGB24: + case CAIRO_FORMAT_RGB30: + bpp=4; + break; + case CAIRO_FORMAT_RGB16_565: + bpp=2; + break; + case CAIRO_FORMAT_A8: + bpp=1; + break; + case CAIRO_FORMAT_A1: + case CAIRO_FORMAT_INVALID: + default: + return CAIRO_TEST_FAILURE; + } + + data = cairo_image_surface_get_data (image); + stride = cairo_image_surface_get_stride (image); + + tmp = malloc (stride); + if (tmp == NULL) + return CAIRO_TEST_FAILURE; + + for (y = 0; y < height; y++) { + uint8_t *row = data + y * stride; + for (x = 0; x < width/2; x++) { + memcpy (tmp, row + bpp * x, bpp); + memcpy (row + bpp * x, row + bpp * (width - x - 1), bpp); + memcpy (row + bpp * (width - x - 1), tmp, bpp); + } + } + + for (y = 0; y < height/2; y++) { + memcpy (tmp, data + y * stride, stride); + memcpy (data + y * stride, data + (height - y - 1) * stride, stride); + memcpy (data + (height - y - 1) * stride, tmp, stride); + } + + free (tmp); + + cairo_surface_unmap_image (surface, image); + } +#else + surface = record_get (func (record_create (cr))); + + cairo_scale (cr, -1, -1); + cairo_translate (cr, -width, -height); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_surface (cr, surface, 0, 0); + cairo_surface_destroy (surface); + cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_NONE); + + for (y = 0; y < height; y += 2) { + for (x = 0; x < width; x += 2) { + cairo_rectangle (cr, x, y, 2, 2); + cairo_clip (cr); + cairo_paint (cr); + cairo_reset_clip (cr); + } + } +#endif + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +record_whole_replay (cairo_t *cr, cairo_t *(*func)(cairo_t *), int width, int height) +{ + cairo_surface_t *surface; + +#if GENERATE_REF + { + cairo_surface_t *image; + uint8_t *data, *tmp; + int stride, bpp; + int x, y; + + surface = cairo_get_target (cr); + + func(cr); + + image = cairo_surface_map_to_image (surface, NULL); + + switch (cairo_image_surface_get_format (image)) { + case CAIRO_FORMAT_ARGB32: + case CAIRO_FORMAT_RGB24: + case CAIRO_FORMAT_RGB30: + bpp=4; + break; + case CAIRO_FORMAT_RGB16_565: + bpp=2; + break; + case CAIRO_FORMAT_A8: + bpp=1; + break; + case CAIRO_FORMAT_A1: + case CAIRO_FORMAT_INVALID: + default: + return CAIRO_TEST_FAILURE; + } + + data = cairo_image_surface_get_data (image); + stride = cairo_image_surface_get_stride (image); + + tmp = malloc (stride); + if (tmp == NULL) + return CAIRO_TEST_FAILURE; + + for (y = 0; y < height; y++) { + uint8_t *row = data + y * stride; + for (x = 0; x < width/2; x++) { + memcpy (tmp, row + bpp * x, bpp); + memcpy (row + bpp * x, row + bpp * (width - x - 1), bpp); + memcpy (row + bpp * (width - x - 1), tmp, bpp); + } + } + + for (y = 0; y < height/2; y++) { + memcpy (tmp, data + y * stride, stride); + memcpy (data + y * stride, data + (height - y - 1) * stride, stride); + memcpy (data + (height - y - 1) * stride, tmp, stride); + } + + free (tmp); + + cairo_surface_unmap_image (surface, image); + } +#else + surface = record_get (func (record_create (cr))); + + cairo_scale (cr, -1, -1); + cairo_translate (cr, -width, -height); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_surface (cr, surface, 0, 0); + cairo_surface_destroy (surface); + cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_NONE); + + cairo_paint (cr); +#endif + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +record_paint (cairo_t *cr, int width, int height) +{ + return record_replay (cr, paint, width, height); +} + +static cairo_test_status_t +record_paint_alpha (cairo_t *cr, int width, int height) +{ + return record_replay (cr, paint_alpha, width, height); +} + +static cairo_test_status_t +record_paint_alpha_solid_clip (cairo_t *cr, int width, int height) +{ + return record_replay (cr, paint_alpha_solid_clip, width, height); +} + +static cairo_test_status_t +record_paint_alpha_clip (cairo_t *cr, int width, int height) +{ + return record_replay (cr, paint_alpha_clip, width, height); +} + +static cairo_test_status_t +record_paint_alpha_clip_mask (cairo_t *cr, int width, int height) +{ + return record_replay (cr, paint_alpha_clip_mask, width, height); +} + +static cairo_test_status_t +record_fill_alpha (cairo_t *cr, int width, int height) +{ + return record_replay (cr, fill_alpha, width, height); +} + +static cairo_test_status_t +record_self_intersecting (cairo_t *cr, int width, int height) +{ + return record_replay (cr, self_intersecting, width, height); +} + +static cairo_test_status_t +record_select_font_face (cairo_t *cr, int width, int height) +{ + return record_replay (cr, select_font_face, width, height); +} + +static cairo_test_status_t +record_text_transform (cairo_t *cr, int width, int height) +{ + return record_replay (cr, text_transform, width, height); +} + +static cairo_test_status_t +record_whole_paint (cairo_t *cr, int width, int height) +{ + return record_whole_replay (cr, paint, width, height); +} + +static cairo_test_status_t +record_whole_paint_alpha (cairo_t *cr, int width, int height) +{ + return record_whole_replay (cr, paint_alpha, width, height); +} + +static cairo_test_status_t +record_whole_paint_alpha_solid_clip (cairo_t *cr, int width, int height) +{ + return record_whole_replay (cr, paint_alpha_solid_clip, width, height); +} + +static cairo_test_status_t +record_whole_paint_alpha_clip (cairo_t *cr, int width, int height) +{ + return record_whole_replay (cr, paint_alpha_clip, width, height); +} + +static cairo_test_status_t +record_whole_paint_alpha_clip_mask (cairo_t *cr, int width, int height) +{ + return record_whole_replay (cr, paint_alpha_clip_mask, width, height); +} + +static cairo_test_status_t +record_whole_fill_alpha (cairo_t *cr, int width, int height) +{ + return record_whole_replay (cr, fill_alpha, width, height); +} + +static cairo_test_status_t +record_whole_self_intersecting (cairo_t *cr, int width, int height) +{ + return record_whole_replay (cr, self_intersecting, width, height); +} + +static cairo_test_status_t +record_whole_select_font_face (cairo_t *cr, int width, int height) +{ + return record_whole_replay (cr, select_font_face, width, height); +} + +static cairo_test_status_t +record_whole_text_transform (cairo_t *cr, int width, int height) +{ + return record_whole_replay (cr, text_transform, width, height); +} + +CAIRO_TEST (recordflip_whole_paint, + "Test replayed calls to cairo_paint", + "paint,record", /* keywords */ + NULL, /* requirements */ + 8, 8, + NULL, record_whole_paint) +CAIRO_TEST (recordflip_whole_paint_alpha, + "Simple test of cairo_paint_with_alpha", + "record, paint, alpha", /* keywords */ + NULL, /* requirements */ + 32, 32, + NULL, record_whole_paint_alpha) +CAIRO_TEST (recordflip_whole_paint_alpha_solid_clip, + "Simple test of cairo_paint_with_alpha+unaligned clip", + "record, paint, alpha, clip", /* keywords */ + NULL, /* requirements */ + 32, 32, + NULL, record_whole_paint_alpha_solid_clip) +CAIRO_TEST (recordflip_whole_paint_alpha_clip, + "Simple test of cairo_paint_with_alpha+unaligned clip", + "record, paint, alpha, clip", /* keywords */ + NULL, /* requirements */ + 32, 32, + NULL, record_whole_paint_alpha_clip) +CAIRO_TEST (recordflip_whole_paint_alpha_clip_mask, + "Simple test of cairo_paint_with_alpha+triangular clip", + "record, paint, alpha, clip", /* keywords */ + NULL, /* requirements */ + 32, 32, + NULL, record_whole_paint_alpha_clip_mask) +CAIRO_TEST (recordflip_whole_fill_alpha, + "Tests using set_rgba();fill()", + "record,fill, alpha", /* keywords */ + NULL, /* requirements */ + (2*SIZE + 4*PAD), (2*SIZE + 4*PAD), + NULL, record_whole_fill_alpha) +CAIRO_TEST (recordflip_whole_select_font_face, + "Tests using cairo_select_font_face to draw text in different faces", + "record, font", /* keywords */ + NULL, /* requirements */ + 192, (TEXT_SIZE + 4), + NULL, record_whole_select_font_face) +CAIRO_TEST (recordflip_whole_self_intersecting, + "Test strokes of self-intersecting paths", + "record, stroke, trap", /* keywords */ + NULL, /* requirements */ + 10, 20, + NULL, record_whole_self_intersecting) +CAIRO_TEST (recordflip_whole_text_transform, + "Test various applications of the font matrix", + "record, text, transform", /* keywords */ + NULL, /* requirements */ + TT_SIZE, TT_SIZE, + NULL, record_whole_text_transform) + + +CAIRO_TEST (recordflip_paint, + "Test replayed calls to cairo_paint", + "paint,record", /* keywords */ + NULL, /* requirements */ + 8, 8, + NULL, record_paint) +CAIRO_TEST (recordflip_paint_alpha, + "Simple test of cairo_paint_with_alpha", + "record, paint, alpha", /* keywords */ + NULL, /* requirements */ + 32, 32, + NULL, record_paint_alpha) +CAIRO_TEST (recordflip_paint_alpha_solid_clip, + "Simple test of cairo_paint_with_alpha+unaligned clip", + "record, paint, alpha, clip", /* keywords */ + NULL, /* requirements */ + 32, 32, + NULL, record_paint_alpha_solid_clip) +CAIRO_TEST (recordflip_paint_alpha_clip, + "Simple test of cairo_paint_with_alpha+unaligned clip", + "record, paint, alpha, clip", /* keywords */ + NULL, /* requirements */ + 32, 32, + NULL, record_paint_alpha_clip) +CAIRO_TEST (recordflip_paint_alpha_clip_mask, + "Simple test of cairo_paint_with_alpha+triangular clip", + "record, paint, alpha, clip", /* keywords */ + NULL, /* requirements */ + 32, 32, + NULL, record_paint_alpha_clip_mask) +CAIRO_TEST (recordflip_fill_alpha, + "Tests using set_rgba();fill()", + "record,fill, alpha", /* keywords */ + NULL, /* requirements */ + (2*SIZE + 4*PAD), (2*SIZE + 4*PAD), + NULL, record_fill_alpha) +CAIRO_TEST (recordflip_select_font_face, + "Tests using cairo_select_font_face to draw text in different faces", + "record, font", /* keywords */ + NULL, /* requirements */ + 192, (TEXT_SIZE + 4), + NULL, record_select_font_face) +CAIRO_TEST (recordflip_self_intersecting, + "Test strokes of self-intersecting paths", + "record, stroke, trap", /* keywords */ + NULL, /* requirements */ + 10, 20, + NULL, record_self_intersecting) +CAIRO_TEST (recordflip_text_transform, + "Test various applications of the font matrix", + "record, text, transform", /* keywords */ + NULL, /* requirements */ + TT_SIZE, TT_SIZE, + NULL, record_text_transform) diff --git a/local/recipes/libs/cairo/source/test/recording-ink-extents.c b/local/recipes/libs/cairo/source/test/recording-ink-extents.c new file mode 100644 index 0000000000..dcc905ddfc --- /dev/null +++ b/local/recipes/libs/cairo/source/test/recording-ink-extents.c @@ -0,0 +1,172 @@ +/* + * 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. + * + * Authors: + * Adrian Johnson + */ + +#include "cairo-test.h" + +/* Check cairo_recording_surface_ink_extents() returns correct extents. */ + + +static cairo_test_status_t +check_extents (cairo_test_context_t *cr, + cairo_surface_t *recording_surface, + const char * func_name, + double expected_x, double expected_y, double expected_w, double expected_h) +{ + double x, y, w, h; + cairo_recording_surface_ink_extents (recording_surface, &x, &y, &w, &h); + if (x != expected_x || + y != expected_y || + w != expected_w || + h != expected_h) + { + cairo_test_log (cr, + "%s: x: %f, y: %f, w: %f, h: %f\n" + " expected: x: %f, y: %f, w: %f, h: %f\n", + func_name, + x, y, w, h, + expected_x, expected_y, + expected_w, expected_h); + return CAIRO_TEST_ERROR; + } + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +unbounded_fill (cairo_test_context_t *test_cr) +{ + cairo_test_status_t status; + cairo_surface_t *surface; + cairo_t *cr; + + surface = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL); + cr = cairo_create (surface); + + cairo_rectangle (cr, -300, -150, 900, 600); + cairo_fill (cr); + + cairo_destroy(cr); + + status = check_extents (test_cr, surface, __func__, + -300, -150, 900, 600); + cairo_surface_destroy (surface); + return status; +} + +static cairo_test_status_t +bounded_fill (cairo_test_context_t *test_cr) +{ + cairo_test_status_t status; + cairo_surface_t *surface; + cairo_t *cr; + cairo_rectangle_t extents = { -150, -100, 300, 200 }; + + surface = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, &extents); + cr = cairo_create (surface); + + cairo_rectangle (cr, -300, -300, 650, 600); + cairo_fill (cr); + + cairo_destroy(cr); + + status = check_extents (test_cr, surface, __func__, + -150, -100, 300, 200); + cairo_surface_destroy (surface); + return status; +} + +static cairo_test_status_t +unbounded_paint (cairo_test_context_t *test_cr) +{ + cairo_test_status_t status; + cairo_surface_t *surface; + cairo_t *cr; + + surface = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL); + cr = cairo_create (surface); + + cairo_paint (cr); + + cairo_destroy(cr); + + status = check_extents (test_cr, surface, __func__, + -(1 << 23), -(1 << 23), -1, -1); + cairo_surface_destroy (surface); + return status; +} + +static cairo_test_status_t +bounded_paint (cairo_test_context_t *test_cr) +{ + cairo_test_status_t status; + cairo_surface_t *surface; + cairo_t *cr; + cairo_rectangle_t extents = { -150, -100, 300, 200 }; + + surface = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, &extents); + cr = cairo_create (surface); + + cairo_paint (cr); + + cairo_destroy(cr); + + status = check_extents (test_cr, surface, __func__, + -150, -100, 300, 200); + cairo_surface_destroy (surface); + return status; +} + +static cairo_test_status_t +preamble (cairo_test_context_t *cr) +{ + cairo_test_status_t status; + + status = unbounded_fill (cr); + if (status != CAIRO_TEST_SUCCESS) + return status; + + status = bounded_fill (cr); + if (status != CAIRO_TEST_SUCCESS) + return status; + + status = unbounded_paint (cr); + if (status != CAIRO_TEST_SUCCESS) + return status; + + status = bounded_paint (cr); + if (status != CAIRO_TEST_SUCCESS) + return status; + + return CAIRO_TEST_SUCCESS; +} + + +CAIRO_TEST (recording_ink_extents, + "Test cairo_recording_surface_ink_extents()", + "api,recording,extents", /* keywords */ + NULL, /* requirements */ + 0, 0, + preamble, NULL) diff --git a/local/recipes/libs/cairo/source/test/recording-surface-extend.c b/local/recipes/libs/cairo/source/test/recording-surface-extend.c new file mode 100644 index 0000000000..0566545301 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/recording-surface-extend.c @@ -0,0 +1,174 @@ +/* + * Copyright © 2007 Adrian Johnson + * Copyright © 2011 Intel Corporation + * + * 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. + * + * Authors: + * Adrian Johnson + * Chris Wilson + */ + +#include "cairo-test.h" + +#define PAT_WIDTH 120 +#define PAT_HEIGHT 120 +#define SIZE (PAT_WIDTH*2) +#define PAD 2 +#define WIDTH (PAD + SIZE + PAD) +#define HEIGHT WIDTH + + +/* This test is designed to test painting a recording surface pattern with + * CAIRO_EXTEND_NONE and a non identity pattern matrix. + */ +static cairo_pattern_t *create_pattern (cairo_t *target) +{ + cairo_surface_t *surface; + cairo_pattern_t *pattern; + cairo_t *cr; + + surface = cairo_surface_create_similar (cairo_get_group_target (target), + CAIRO_CONTENT_COLOR_ALPHA, + PAT_WIDTH, PAT_HEIGHT); + cr = cairo_create (surface); + cairo_surface_destroy (surface); + + cairo_set_source_rgba (cr, 1, 0, 1, 0.5); + cairo_rectangle (cr, PAT_WIDTH/6.0, PAT_HEIGHT/6.0, PAT_WIDTH/4.0, PAT_HEIGHT/4.0); + cairo_fill (cr); + + cairo_set_source_rgba (cr, 0, 1, 1, 0.5); + cairo_rectangle (cr, PAT_WIDTH/2.0, PAT_HEIGHT/2.0, PAT_WIDTH/4.0, PAT_HEIGHT/4.0); + cairo_fill (cr); + + cairo_set_line_width (cr, 1); + cairo_move_to (cr, PAT_WIDTH/6.0, 0); + cairo_line_to (cr, 0, 0); + cairo_line_to (cr, 0, PAT_HEIGHT/6.0); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_stroke (cr); + cairo_move_to (cr, PAT_WIDTH/6.0, PAT_HEIGHT); + cairo_line_to (cr, 0, PAT_HEIGHT); + cairo_line_to (cr, 0, 5*PAT_HEIGHT/6.0); + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_stroke (cr); + cairo_move_to (cr, 5*PAT_WIDTH/6.0, 0); + cairo_line_to (cr, PAT_WIDTH, 0); + cairo_line_to (cr, PAT_WIDTH, PAT_HEIGHT/6.0); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_stroke (cr); + cairo_move_to (cr, 5*PAT_WIDTH/6.0, PAT_HEIGHT); + cairo_line_to (cr, PAT_WIDTH, PAT_HEIGHT); + cairo_line_to (cr, PAT_WIDTH, 5*PAT_HEIGHT/6.0); + cairo_set_source_rgb (cr, 1, 1, 0); + cairo_stroke (cr); + + cairo_set_source_rgb (cr, 0.5, 0.5, 0.5); + cairo_set_line_width (cr, PAT_WIDTH/10.0); + + cairo_move_to (cr, 0, PAT_HEIGHT/4.0); + cairo_line_to (cr, PAT_WIDTH, PAT_HEIGHT/4.0); + cairo_stroke (cr); + + cairo_move_to (cr, PAT_WIDTH/4.0, 0); + cairo_line_to (cr, PAT_WIDTH/4.0, PAT_WIDTH); + cairo_stroke (cr); + + pattern = cairo_pattern_create_for_surface (cairo_get_target (cr)); + cairo_destroy (cr); + + return pattern; +} + +static cairo_test_status_t +draw (cairo_t *cr, cairo_extend_t extend) +{ + cairo_pattern_t *pattern; + cairo_matrix_t mat; + + cairo_translate (cr, PAD, PAD); + + pattern = create_pattern (cr); + + cairo_matrix_init_identity (&mat); + cairo_matrix_scale (&mat, 2, 1.5); + cairo_matrix_rotate (&mat, 1); + cairo_matrix_translate (&mat, -PAT_WIDTH/4.0, -PAT_WIDTH/2.0); + cairo_pattern_set_matrix (pattern, &mat); + cairo_pattern_set_extend (pattern, extend); + + cairo_set_source (cr, pattern); + cairo_paint (cr); + + cairo_pattern_destroy (pattern); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +none (cairo_t *cr, int width, int height) +{ + return draw (cr, CAIRO_EXTEND_NONE); +} + +static cairo_test_status_t +repeat (cairo_t *cr, int width, int height) +{ + return draw (cr, CAIRO_EXTEND_REPEAT); +} + +static cairo_test_status_t +reflect (cairo_t *cr, int width, int height) +{ + return draw (cr, CAIRO_EXTEND_REFLECT); +} + +static cairo_test_status_t +pad (cairo_t *cr, int width, int height) +{ + return draw (cr, CAIRO_EXTEND_PAD); +} + +CAIRO_TEST (recording_surface_extend_none, + "Paint recording surface pattern with extend modes", + "recording, extend", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, none) +CAIRO_TEST (recording_surface_extend_repeat, + "Paint recording surface pattern with extend modes", + "recording, extend", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, repeat) +CAIRO_TEST (recording_surface_extend_reflect, + "Paint recording surface pattern with extend modes", + "recording, extend", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, reflect) +CAIRO_TEST (recording_surface_extend_pad, + "Paint recording surface pattern with extend modes", + "recording, extend", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, pad) diff --git a/local/recipes/libs/cairo/source/test/recording-surface-pattern.c b/local/recipes/libs/cairo/source/test/recording-surface-pattern.c new file mode 100644 index 0000000000..5a5fee2b06 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/recording-surface-pattern.c @@ -0,0 +1,162 @@ +/* + * Copyright © 2007 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" + +#define PAT_WIDTH 120 +#define PAT_HEIGHT 120 +#define SIZE (PAT_WIDTH*2) +#define PAD 2 +#define WIDTH (PAD + SIZE + PAD) +#define HEIGHT WIDTH + + +/* This test is designed to test painting a recording surface pattern with + * CAIRO_EXTEND_NONE and a non identity pattern matrix. + */ +static cairo_pattern_t *create_pattern (cairo_t *target) +{ + cairo_surface_t *surface; + cairo_pattern_t *pattern; + cairo_t *cr; + + surface = cairo_surface_create_similar (cairo_get_group_target (target), + CAIRO_CONTENT_COLOR_ALPHA, + PAT_WIDTH, PAT_HEIGHT); + cr = cairo_create (surface); + cairo_surface_destroy (surface); + + cairo_set_source_rgba (cr, 1, 0, 1, 0.5); + cairo_rectangle (cr, PAT_WIDTH/6.0, PAT_HEIGHT/6.0, PAT_WIDTH/4.0, PAT_HEIGHT/4.0); + cairo_fill (cr); + + cairo_set_source_rgba (cr, 0, 1, 1, 0.5); + cairo_rectangle (cr, PAT_WIDTH/2.0, PAT_HEIGHT/2.0, PAT_WIDTH/4.0, PAT_HEIGHT/4.0); + cairo_fill (cr); + + cairo_set_line_width (cr, 1); + cairo_move_to (cr, PAT_WIDTH/6.0, 0); + cairo_line_to (cr, 0, 0); + cairo_line_to (cr, 0, PAT_HEIGHT/6.0); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_stroke (cr); + cairo_move_to (cr, PAT_WIDTH/6.0, PAT_HEIGHT); + cairo_line_to (cr, 0, PAT_HEIGHT); + cairo_line_to (cr, 0, 5*PAT_HEIGHT/6.0); + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_stroke (cr); + cairo_move_to (cr, 5*PAT_WIDTH/6.0, 0); + cairo_line_to (cr, PAT_WIDTH, 0); + cairo_line_to (cr, PAT_WIDTH, PAT_HEIGHT/6.0); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_stroke (cr); + cairo_move_to (cr, 5*PAT_WIDTH/6.0, PAT_HEIGHT); + cairo_line_to (cr, PAT_WIDTH, PAT_HEIGHT); + cairo_line_to (cr, PAT_WIDTH, 5*PAT_HEIGHT/6.0); + cairo_set_source_rgb (cr, 1, 1, 0); + cairo_stroke (cr); + + cairo_set_source_rgb (cr, 0.5, 0.5, 0.5); + cairo_set_line_width (cr, PAT_WIDTH/10.0); + + cairo_move_to (cr, 0, PAT_HEIGHT/4.0); + cairo_line_to (cr, PAT_WIDTH, PAT_HEIGHT/4.0); + cairo_stroke (cr); + + cairo_move_to (cr, PAT_WIDTH/4.0, 0); + cairo_line_to (cr, PAT_WIDTH/4.0, PAT_WIDTH); + cairo_stroke (cr); + + pattern = cairo_pattern_create_for_surface (cairo_get_target (cr)); + cairo_destroy (cr); + + return pattern; +} + +static cairo_test_status_t +over (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *pattern; + cairo_matrix_t mat; + + cairo_translate (cr, PAD, PAD); + + pattern = create_pattern (cr); + + cairo_matrix_init_identity (&mat); + cairo_matrix_scale (&mat, 2, 1.5); + cairo_matrix_rotate (&mat, 1); + cairo_matrix_translate (&mat, -PAT_WIDTH/4.0, -PAT_WIDTH/2.0); + cairo_pattern_set_matrix (pattern, &mat); + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_NONE); + + cairo_set_source (cr, pattern); + cairo_paint (cr); + + cairo_pattern_destroy (pattern); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +source (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *pattern; + cairo_matrix_t mat; + + cairo_translate (cr, PAD, PAD); + + pattern = create_pattern (cr); + + cairo_matrix_init_identity (&mat); + cairo_matrix_scale (&mat, 2, 1.5); + cairo_matrix_rotate (&mat, 1); + cairo_matrix_translate (&mat, -PAT_WIDTH/4.0, -PAT_WIDTH/2.0); + cairo_pattern_set_matrix (pattern, &mat); + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_NONE); + + cairo_set_source (cr, pattern); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_paint (cr); + + cairo_pattern_destroy (pattern); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (recording_surface_over, + "Paint recording surface pattern with non identity pattern matrix", + "recording", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, over) + +CAIRO_TEST (recording_surface_source, + "Paint recording surface pattern with non identity pattern matrix", + "recording", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, source) diff --git a/local/recipes/libs/cairo/source/test/rectangle-rounding-error.c b/local/recipes/libs/cairo/source/test/rectangle-rounding-error.c new file mode 100644 index 0000000000..6ad99ae208 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/rectangle-rounding-error.c @@ -0,0 +1,64 @@ +/* + * Copyright © 2005 Bertram Felgenhauer + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * the author not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. The author makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE AUTHOR. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Bertram Felgenhauer + */ + +#include "cairo-test.h" + +/* Test case for: + * + * https://bugs.freedesktop.org/show_bug.cgi?id=4137 + */ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); + cairo_set_source_rgb (cr, 0, 0, 0); + + cairo_translate(cr, -300, -300); + cairo_scale(cr, 677.0/26, 677.0/26); + cairo_translate(cr, 1, 1); + + /* this should draw a seamless 2x2 rectangle */ + cairo_rectangle(cr, 11, 11, 1, 1); + cairo_rectangle(cr, 11, 12, 1, 1); + cairo_rectangle(cr, 12, 11, 1, 1); + cairo_rectangle(cr, 12, 12, 1, 1); + + cairo_set_source_rgb(cr, 0, 0, 0); + cairo_fill(cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (rectangle_rounding_error, + "This demonstrates (or not) a rounding error that causes a gap between " + "two neighbouring rectangles.", + "trap", /* keywords */ + "target=raster", /* requirements */ + 76, 76, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/rectilinear-dash-scale.c b/local/recipes/libs/cairo/source/test/rectilinear-dash-scale.c new file mode 100644 index 0000000000..34f334561f --- /dev/null +++ b/local/recipes/libs/cairo/source/test/rectilinear-dash-scale.c @@ -0,0 +1,196 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * Copyright © 2008 Chris Wilson + * + * 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: Carl D. Worth + * Chris Wilson + * + * Based on the original test/rectilinear-stroke.c by Carl D. Worth. + */ + +#include "cairo-test.h" + +#define SIZE 50 + +static void +draw_dashes (cairo_t *cr) +{ + const double dash_square[4] = {4, 2, 2, 2}; + const double dash_butt[4] = {5, 1, 3, 1}; + + cairo_save (cr); + + cairo_set_dash (cr, dash_square, 4, 0); + + cairo_set_line_width (cr, 1.0); + cairo_translate (cr, 1, 1); + + /* Draw everything first with square caps. */ + cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); + + /* Draw horizontal and vertical segments, each in both + * directions. */ + cairo_move_to (cr, 4.5, 0.5); + cairo_rel_line_to (cr, 2.0, 0.0); + + cairo_move_to (cr, 10.5, 4.5); + cairo_rel_line_to (cr, 0.0, 2.0); + + cairo_move_to (cr, 6.5, 10.5); + cairo_rel_line_to (cr, -2.0, 0.0); + + cairo_move_to (cr, 0.5, 6.5); + cairo_rel_line_to (cr, 0.0, -2.0); + + /* Draw right angle turns in four directions. */ + cairo_move_to (cr, 0.5, 2.5); + cairo_rel_line_to (cr, 0.0, -2.0); + cairo_rel_line_to (cr, 2.0, 0.0); + + cairo_move_to (cr, 8.5, 0.5); + cairo_rel_line_to (cr, 2.0, 0.0); + cairo_rel_line_to (cr, 0.0, 2.0); + + cairo_move_to (cr, 10.5, 8.5); + cairo_rel_line_to (cr, 0.0, 2.0); + cairo_rel_line_to (cr, -2.0, 0.0); + + cairo_move_to (cr, 2.5, 10.5); + cairo_rel_line_to (cr, -2.0, 0.0); + cairo_rel_line_to (cr, 0.0, -2.0); + + cairo_stroke (cr); + + /* Draw a closed-path rectangle */ + cairo_rectangle (cr, 0.5, 12.5, 10.0, 10.0); + cairo_set_dash (cr, dash_square, 4, 2); + cairo_stroke (cr); + + cairo_translate (cr, 12, 0); + + /* Now draw the same results, but with butt caps. */ + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + cairo_set_dash (cr, dash_butt, 4, 0.0); + + /* Draw horizontal and vertical segments, each in both + * directions. */ + cairo_move_to (cr, 4.0, 0.5); + cairo_rel_line_to (cr, 3.0, 0.0); + + cairo_move_to (cr, 10.5, 4.0); + cairo_rel_line_to (cr, 0.0, 3.0); + + cairo_move_to (cr, 7.0, 10.5); + cairo_rel_line_to (cr, -3.0, 0.0); + + cairo_move_to (cr, 0.5, 7.0); + cairo_rel_line_to (cr, 0.0, -3.0); + + /* Draw right angle turns in four directions. */ + cairo_move_to (cr, 0.5, 3.0); + cairo_rel_line_to (cr, 0.0, -2.5); + cairo_rel_line_to (cr, 2.5, 0.0); + + cairo_move_to (cr, 8.0, 0.5); + cairo_rel_line_to (cr, 2.5, 0.0); + cairo_rel_line_to (cr, 0.0, 2.5); + + cairo_move_to (cr, 10.5, 8.0); + cairo_rel_line_to (cr, 0.0, 2.5); + cairo_rel_line_to (cr, -2.5, 0.0); + + cairo_move_to (cr, 3.0, 10.5); + cairo_rel_line_to (cr, -2.5, 0.0); + cairo_rel_line_to (cr, 0.0, -2.5); + + cairo_stroke (cr); + + /* Draw a closed-path rectangle */ + cairo_set_dash (cr, dash_butt, 4, 2.5); + cairo_rectangle (cr, 0.5, 12.5, 10.0, 10.0); + cairo_stroke (cr); + + cairo_restore (cr); +} + +static cairo_test_status_t +dashes (cairo_t *cr) +{ + /* Paint background white, then draw in black. */ + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + draw_dashes (cr); + + cairo_save (cr); + cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); + cairo_translate (cr, 0, SIZE); + cairo_scale (cr, 1, -1); + draw_dashes (cr); + cairo_restore (cr); + + cairo_save (cr); + cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); + cairo_translate (cr, SIZE, 0); + cairo_scale (cr, -1, 1); + draw_dashes (cr); + cairo_restore (cr); + + cairo_save (cr); + cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); + cairo_translate (cr, SIZE, SIZE); + cairo_scale (cr, -1, -1); + draw_dashes (cr); + cairo_restore (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +aligned (cairo_t *cr, int width, int height) +{ + cairo_scale (cr, 4, 2); + return dashes(cr); +} + +static cairo_test_status_t +unaligned (cairo_t *cr, int width, int height) +{ + cairo_scale (cr, 3.9, 1.9); + return dashes(cr); +} + +CAIRO_TEST (rectilinear_dash_scale, + "Test dashed rectilinear stroke operations (covering only whole pixels) after scaling", + "stroke, dash", /* keywords */ + NULL, /* requirements */ + 4*SIZE, 2*SIZE, + NULL, aligned) + +CAIRO_TEST (rectilinear_dash_scale_unaligned, + "Test dashed rectilinear stroke operations (covering partial pixels) after scaling", + "stroke, dash", /* keywords */ + NULL, /* requirements */ + 4*SIZE, 2*SIZE, + NULL, unaligned) diff --git a/local/recipes/libs/cairo/source/test/rectilinear-dash.c b/local/recipes/libs/cairo/source/test/rectilinear-dash.c new file mode 100644 index 0000000000..954a2a042b --- /dev/null +++ b/local/recipes/libs/cairo/source/test/rectilinear-dash.c @@ -0,0 +1,176 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * Copyright © 2008 Chris Wilson + * + * 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: Carl D. Worth + * Chris Wilson + * + * Based on the original test/rectilinear-stroke.c by Carl D. Worth. + */ + +#include "cairo-test.h" + +#define SIZE 50 + +static void +draw_dashes (cairo_t *cr) +{ + const double dash_square[4] = {4, 2, 2, 2}; + const double dash_butt[4] = {5, 1, 3, 1}; + + cairo_save (cr); + + cairo_set_dash (cr, dash_square, 4, 0); + + cairo_set_line_width (cr, 1.0); + cairo_translate (cr, 1, 1); + + /* Draw everything first with square caps. */ + cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); + + /* Draw horizontal and vertical segments, each in both + * directions. */ + cairo_move_to (cr, 4.5, 0.5); + cairo_rel_line_to (cr, 2.0, 0.0); + + cairo_move_to (cr, 10.5, 4.5); + cairo_rel_line_to (cr, 0.0, 2.0); + + cairo_move_to (cr, 6.5, 10.5); + cairo_rel_line_to (cr, -2.0, 0.0); + + cairo_move_to (cr, 0.5, 6.5); + cairo_rel_line_to (cr, 0.0, -2.0); + + /* Draw right angle turns in four directions. */ + cairo_move_to (cr, 0.5, 2.5); + cairo_rel_line_to (cr, 0.0, -2.0); + cairo_rel_line_to (cr, 2.0, 0.0); + + cairo_move_to (cr, 8.5, 0.5); + cairo_rel_line_to (cr, 2.0, 0.0); + cairo_rel_line_to (cr, 0.0, 2.0); + + cairo_move_to (cr, 10.5, 8.5); + cairo_rel_line_to (cr, 0.0, 2.0); + cairo_rel_line_to (cr, -2.0, 0.0); + + cairo_move_to (cr, 2.5, 10.5); + cairo_rel_line_to (cr, -2.0, 0.0); + cairo_rel_line_to (cr, 0.0, -2.0); + + cairo_stroke (cr); + + /* Draw a closed-path rectangle */ + cairo_rectangle (cr, 0.5, 12.5, 10.0, 10.0); + cairo_set_dash (cr, dash_square, 4, 2); + cairo_stroke (cr); + + cairo_translate (cr, 12, 0); + + /* Now draw the same results, but with butt caps. */ + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + cairo_set_dash (cr, dash_butt, 4, 0.0); + + /* Draw horizontal and vertical segments, each in both + * directions. */ + cairo_move_to (cr, 4.0, 0.5); + cairo_rel_line_to (cr, 3.0, 0.0); + + cairo_move_to (cr, 10.5, 4.0); + cairo_rel_line_to (cr, 0.0, 3.0); + + cairo_move_to (cr, 7.0, 10.5); + cairo_rel_line_to (cr, -3.0, 0.0); + + cairo_move_to (cr, 0.5, 7.0); + cairo_rel_line_to (cr, 0.0, -3.0); + + /* Draw right angle turns in four directions. */ + cairo_move_to (cr, 0.5, 3.0); + cairo_rel_line_to (cr, 0.0, -2.5); + cairo_rel_line_to (cr, 2.5, 0.0); + + cairo_move_to (cr, 8.0, 0.5); + cairo_rel_line_to (cr, 2.5, 0.0); + cairo_rel_line_to (cr, 0.0, 2.5); + + cairo_move_to (cr, 10.5, 8.0); + cairo_rel_line_to (cr, 0.0, 2.5); + cairo_rel_line_to (cr, -2.5, 0.0); + + cairo_move_to (cr, 3.0, 10.5); + cairo_rel_line_to (cr, -2.5, 0.0); + cairo_rel_line_to (cr, 0.0, -2.5); + + cairo_stroke (cr); + + /* Draw a closed-path rectangle */ + cairo_set_dash (cr, dash_butt, 4, 2.5); + cairo_rectangle (cr, 0.5, 12.5, 10.0, 10.0); + cairo_stroke (cr); + + cairo_restore (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + /* Paint background white, then draw in black. */ + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + draw_dashes (cr); + + cairo_save (cr); + cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); + cairo_translate (cr, 0, height); + cairo_scale (cr, 1, -1); + draw_dashes (cr); + cairo_restore (cr); + + cairo_save (cr); + cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); + cairo_translate (cr, width, 0); + cairo_scale (cr, -1, 1); + draw_dashes (cr); + cairo_restore (cr); + + cairo_save (cr); + cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); + cairo_translate (cr, width, height); + cairo_scale (cr, -1, -1); + draw_dashes (cr); + cairo_restore (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (rectilinear_dash, + "Test dashed rectilinear stroke operations (covering only whole pixels)", + "stroke, dash", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/rectilinear-fill.c b/local/recipes/libs/cairo/source/test/rectilinear-fill.c new file mode 100644 index 0000000000..3678379ee7 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/rectilinear-fill.c @@ -0,0 +1,84 @@ +/* + * Copyright © 2008 Chris Wilson + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +#define SIZE 24 + +static void +draw_rectangles (cairo_t *cr) +{ + cairo_save (cr); + + /* test constructing single rectangles */ + cairo_rectangle (cr, 0, 0, SIZE/2, 2); + cairo_fill (cr); + + cairo_rectangle (cr, 0, 5, SIZE/2, -2); + cairo_fill (cr); + + cairo_rectangle (cr, SIZE/2, 6, -SIZE/2, 2); + cairo_fill (cr); + + cairo_rectangle (cr, SIZE/2, 11, -SIZE/2, -2); + cairo_fill (cr); + + /* test constructing multiple rectangles */ + cairo_translate (cr, 0, 12); + cairo_rectangle (cr, 0, 0, SIZE/2, 2); + cairo_rectangle (cr, 0, 5, SIZE/2, -2); + cairo_rectangle (cr, SIZE/2, 6, -SIZE/2, 2); + cairo_rectangle (cr, SIZE/2, 11, -SIZE/2, -2); + cairo_fill (cr); + + cairo_restore (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + /* Paint background white, then draw in black. */ + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */ + + draw_rectangles (cr); + + /* and check using cw winding */ + cairo_translate (cr, SIZE, SIZE); + cairo_scale (cr, -1, 1); + + draw_rectangles (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (rectilinear_fill, + "Test rectilinear fill operations (covering only whole pixels)", + "fill, rectilinear", /* keywords */ + NULL, /* requirements */ + SIZE, 2 * SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/rectilinear-grid.c b/local/recipes/libs/cairo/source/test/rectilinear-grid.c new file mode 100644 index 0000000000..6d37c6b8a3 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/rectilinear-grid.c @@ -0,0 +1,92 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright 2010 Andrea Canciani + * + * 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: Andrea Canciani + */ + +#include "cairo-test.h" + +#define SIZE 52 +#define OFFSET 5 +#define DISTANCE 10.25 + +/* + This test checks that boxes not aligned to pixels are drawn + correctly. + + In particular the corners of the boxes are drawn incorrectly by + cairo-image in cairo 1.10.0, because overlapping boxes are passed to + a span converter which assumes disjoint boxes as input. + + This results in corners to be drawn with the wrong shade. +*/ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + int i; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_set_line_width (cr, 4); + cairo_translate (cr, 2*OFFSET, 2*OFFSET); + + for (i = 0; i < 4; i++) { + double x = i * DISTANCE; + + cairo_move_to (cr, x, -OFFSET-0.75); + cairo_line_to (cr, x, SIZE-3*OFFSET-0.25); + + cairo_move_to (cr, -OFFSET-0.75, x); + cairo_line_to (cr, SIZE-3*OFFSET-0.25, x); + } + + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +aligned (cairo_t *cr, int width, int height) +{ + cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); + return draw (cr, width, height); +} + +CAIRO_TEST (rectilinear_grid, + "Test rectilinear rasterizer (covering partial pixels)", + "rectilinear", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) + +CAIRO_TEST (a1_rectilinear_grid, + "Test rectilinear rasterizer (covering whole pixels)", + "rectilinear", /* keywords */ + "target=raster", /* requirements */ + SIZE, SIZE, + NULL, aligned) diff --git a/local/recipes/libs/cairo/source/test/rectilinear-miter-limit.c b/local/recipes/libs/cairo/source/test/rectilinear-miter-limit.c new file mode 100644 index 0000000000..581d98bad4 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/rectilinear-miter-limit.c @@ -0,0 +1,72 @@ +/* + * Copyright © 2008 Red Hat, Inc. + * + * 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: Carl D. Worth + */ + +#include "cairo-test.h" + +#define LINE_WIDTH 10 +#define PAD 2 +#define WIDTH (PAD + LINE_WIDTH + PAD) +#define HEIGHT (WIDTH) + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_translate (cr, PAD, PAD); + + /* Paint background white, then draw in black. */ + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */ + + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + cairo_set_line_width (cr, LINE_WIDTH); + + /* The default miter limit value of 10.0 guarantees that + * right-angle turns, (in fact, any angle greater than 11 + * degrees), gets a miter rather than a bevel join. The + * rectilinear stroke optimization was originally written in a + * buggy way that did not respect the miter limit, (that is, + * inappropriately drawing miter joins when the miter limit would + * turn them into bevels). So we draw here with a miter limit of + * 1.0 to force all miter joins into bevels. */ + cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER); + cairo_set_miter_limit (cr, 1.0); + + cairo_move_to (cr, LINE_WIDTH / 2.0, LINE_WIDTH); + cairo_rel_line_to (cr, 0, - LINE_WIDTH / 2.0); + cairo_rel_line_to (cr, LINE_WIDTH / 2.0, 0); + + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (rectilinear_miter_limit, + "Test that the rectilinear stroke optimization doesn't break cairo_set_miter_limit", + "miter, stroke, stress", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/rectilinear-stroke.c b/local/recipes/libs/cairo/source/test/rectilinear-stroke.c new file mode 100644 index 0000000000..e05ff8c2e0 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/rectilinear-stroke.c @@ -0,0 +1,139 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * 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: Carl D. Worth + */ + +#include "cairo-test.h" + +#define SIZE 25 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + /* Paint background white, then draw in black. */ + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */ + + cairo_set_line_width (cr, 1.0); + cairo_translate (cr, 1, 1); + + /* Draw everything first with square caps. */ + cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); + + /* Draw horizontal and vertical segments, each in both + * directions. */ + cairo_move_to (cr, 4.5, 0.5); + cairo_rel_line_to (cr, 2.0, 0.0); + + cairo_move_to (cr, 10.5, 4.5); + cairo_rel_line_to (cr, 0.0, 2.0); + + cairo_move_to (cr, 6.5, 10.5); + cairo_rel_line_to (cr, -2.0, 0.0); + + cairo_move_to (cr, 0.5, 6.5); + cairo_rel_line_to (cr, 0.0, -2.0); + + /* Draw right angle turns in four directions. */ + cairo_move_to (cr, 0.5, 2.5); + cairo_rel_line_to (cr, 0.0, -2.0); + cairo_rel_line_to (cr, 2.0, 0.0); + + cairo_move_to (cr, 8.5, 0.5); + cairo_rel_line_to (cr, 2.0, 0.0); + cairo_rel_line_to (cr, 0.0, 2.0); + + cairo_move_to (cr, 10.5, 8.5); + cairo_rel_line_to (cr, 0.0, 2.0); + cairo_rel_line_to (cr, -2.0, 0.0); + + cairo_move_to (cr, 2.5, 10.5); + cairo_rel_line_to (cr, -2.0, 0.0); + cairo_rel_line_to (cr, 0.0, -2.0); + + /* Draw a closed-path rectangle */ + cairo_rectangle (cr, 0.5, 12.5, 10.0, 10.0); + + cairo_stroke (cr); + + cairo_translate (cr, 12, 0); + + /* Now draw the same results, but with butt caps. */ + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + + /* Draw horizontal and vertical segments, each in both + * directions. */ + cairo_move_to (cr, 4.0, 0.5); + cairo_rel_line_to (cr, 3.0, 0.0); + + cairo_move_to (cr, 10.5, 4.0); + cairo_rel_line_to (cr, 0.0, 3.0); + + cairo_move_to (cr, 7.0, 10.5); + cairo_rel_line_to (cr, -3.0, 0.0); + + cairo_move_to (cr, 0.5, 7.0); + cairo_rel_line_to (cr, 0.0, -3.0); + + /* Draw right angle turns in four directions. */ + cairo_move_to (cr, 0.5, 3.0); + cairo_rel_line_to (cr, 0.0, -2.5); + cairo_rel_line_to (cr, 2.5, 0.0); + + cairo_move_to (cr, 8.0, 0.5); + cairo_rel_line_to (cr, 2.5, 0.0); + cairo_rel_line_to (cr, 0.0, 2.5); + + cairo_move_to (cr, 10.5, 8.0); + cairo_rel_line_to (cr, 0.0, 2.5); + cairo_rel_line_to (cr, -2.5, 0.0); + + cairo_move_to (cr, 3.0, 10.5); + cairo_rel_line_to (cr, -2.5, 0.0); + cairo_rel_line_to (cr, 0.0, -2.5); + + /* Draw a closed-path rectangle */ + cairo_rectangle (cr, 0.5, 12.5, 10.0, 10.0); + + /* Draw a path that is rectilinear initially, but not completely */ + /* We draw this out of the target window. The bug that caused this + * addition was leaks if part of the path was rectilinear but not + * completely */ + cairo_move_to (cr, 3.0, 30.5); + cairo_rel_line_to (cr, -2.5, 0.0); + cairo_rel_line_to (cr, +2.5, +2.5); + + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (rectilinear_stroke, + "Test rectilinear stroke operations (covering only whole pixels)", + "stroke", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/reference/a1-bug.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-bug.base.argb32.ref.png new file mode 100644 index 0000000000..4b08e06832 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-bug.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-bug.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-bug.base.rgb24.ref.png new file mode 100644 index 0000000000..4b08e06832 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-bug.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-bug.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-bug.image16.ref.png new file mode 100644 index 0000000000..48ce4b65a6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-bug.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-bug.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-bug.mask.argb32.ref.png new file mode 100644 index 0000000000..f9ae8a87ef Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-bug.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-bug.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-bug.mask.rgb24.ref.png new file mode 100644 index 0000000000..f9ae8a87ef Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-bug.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-bug.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/a1-bug.quartz.xfail.png new file mode 100644 index 0000000000..4ed379365a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-bug.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-bug.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-bug.ref.png new file mode 100644 index 0000000000..dc6ff931b5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-bug.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-bug.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-bug.traps.argb32.ref.png new file mode 100644 index 0000000000..4b08e06832 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-bug.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-bug.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-bug.traps.rgb24.ref.png new file mode 100644 index 0000000000..4b08e06832 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-bug.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-clip-fill-equal.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-clip-fill-equal.base.argb32.ref.png new file mode 100644 index 0000000000..384ba4a044 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-clip-fill-equal.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-clip-fill-equal.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-clip-fill-equal.base.rgb24.ref.png new file mode 100644 index 0000000000..384ba4a044 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-clip-fill-equal.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-clip-fill-equal.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-clip-fill-equal.ref.png new file mode 100644 index 0000000000..384ba4a044 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-clip-fill-equal.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-clip-fill-rule.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-clip-fill-rule.base.argb32.ref.png new file mode 100644 index 0000000000..c3ba9dd5ff Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-clip-fill-rule.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-clip-fill-rule.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-clip-fill-rule.base.rgb24.ref.png new file mode 100644 index 0000000000..6fe9346ba1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-clip-fill-rule.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-clip-fill-rule.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-clip-fill-rule.quartz.ref.png new file mode 100644 index 0000000000..c4658a804d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-clip-fill-rule.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-clip-fill-rule.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-clip-fill-rule.ref.png new file mode 100644 index 0000000000..c3ba9dd5ff Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-clip-fill-rule.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-clip-fill.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-clip-fill.base.argb32.ref.png new file mode 100644 index 0000000000..384ba4a044 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-clip-fill.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-clip-fill.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-clip-fill.base.rgb24.ref.png new file mode 100644 index 0000000000..384ba4a044 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-clip-fill.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-clip-fill.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-clip-fill.ref.png new file mode 100644 index 0000000000..384ba4a044 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-clip-fill.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-clip-paint.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-clip-paint.base.argb32.ref.png new file mode 100644 index 0000000000..384ba4a044 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-clip-paint.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-clip-paint.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-clip-paint.base.rgb24.ref.png new file mode 100644 index 0000000000..384ba4a044 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-clip-paint.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-clip-paint.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-clip-paint.ref.png new file mode 100644 index 0000000000..384ba4a044 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-clip-paint.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-clip-stroke.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-clip-stroke.base.argb32.ref.png new file mode 100644 index 0000000000..384ba4a044 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-clip-stroke.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-clip-stroke.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-clip-stroke.base.rgb24.ref.png new file mode 100644 index 0000000000..384ba4a044 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-clip-stroke.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-clip-stroke.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-clip-stroke.ref.png new file mode 100644 index 0000000000..384ba4a044 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-clip-stroke.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-fill.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-fill.base.argb32.ref.png new file mode 100644 index 0000000000..e40202bf99 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-fill.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-fill.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-fill.base.rgb24.ref.png new file mode 100644 index 0000000000..e40202bf99 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-fill.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-fill.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-fill.ref.png new file mode 100644 index 0000000000..e40202bf99 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-fill.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-image-sample.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-image-sample.base.argb32.ref.png new file mode 100644 index 0000000000..b8fd4570db Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-image-sample.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-image-sample.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-image-sample.base.rgb24.ref.png new file mode 100644 index 0000000000..b8fd4570db Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-image-sample.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-image-sample.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-image-sample.ref.png new file mode 100644 index 0000000000..b4e81eb355 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-image-sample.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-line-width.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-line-width.base.argb32.ref.png new file mode 100644 index 0000000000..35d9cad606 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-line-width.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-line-width.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-line-width.base.rgb24.ref.png new file mode 100644 index 0000000000..35d9cad606 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-line-width.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-line-width.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-line-width.pdf.ref.png new file mode 100644 index 0000000000..41a06e7697 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-line-width.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-line-width.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-line-width.ps.ref.png new file mode 100644 index 0000000000..c52f8d8749 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-line-width.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-line-width.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-line-width.quartz.ref.png new file mode 100644 index 0000000000..bf96a4c23c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-line-width.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-line-width.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-line-width.ref.png new file mode 100644 index 0000000000..35d9cad606 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-line-width.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-mask-sample.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-mask-sample.base.argb32.ref.png new file mode 100644 index 0000000000..b8fd4570db Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-mask-sample.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-mask-sample.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-mask-sample.base.rgb24.ref.png new file mode 100644 index 0000000000..b8fd4570db Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-mask-sample.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-mask-sample.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-mask-sample.ref.png new file mode 100644 index 0000000000..b4e81eb355 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-mask-sample.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-mask.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-mask.base.argb32.ref.png new file mode 100644 index 0000000000..864fc1031b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-mask.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-mask.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-mask.base.rgb24.ref.png new file mode 100644 index 0000000000..864fc1031b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-mask.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-mask.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-mask.ref.png new file mode 100644 index 0000000000..ac4d97aca2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-mask.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-rasterisation-rectangles.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-rasterisation-rectangles.base.argb32.ref.png new file mode 100644 index 0000000000..784cf873ec Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-rasterisation-rectangles.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-rasterisation-rectangles.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-rasterisation-rectangles.base.rgb24.ref.png new file mode 100644 index 0000000000..784cf873ec Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-rasterisation-rectangles.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-rasterisation-rectangles.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/a1-rasterisation-rectangles.quartz.xfail.png new file mode 100644 index 0000000000..f8f3bf8658 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-rasterisation-rectangles.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-rasterisation-rectangles.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-rasterisation-rectangles.ref.png new file mode 100644 index 0000000000..784cf873ec Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-rasterisation-rectangles.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-rasterisation-triangles.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-rasterisation-triangles.base.argb32.ref.png new file mode 100644 index 0000000000..784cf873ec Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-rasterisation-triangles.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-rasterisation-triangles.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-rasterisation-triangles.base.rgb24.ref.png new file mode 100644 index 0000000000..784cf873ec Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-rasterisation-triangles.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-rasterisation-triangles.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/a1-rasterisation-triangles.quartz.xfail.png new file mode 100644 index 0000000000..f8f3bf8658 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-rasterisation-triangles.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-rasterisation-triangles.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-rasterisation-triangles.ref.png new file mode 100644 index 0000000000..784cf873ec Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-rasterisation-triangles.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-rectilinear-grid.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-rectilinear-grid.base.argb32.ref.png new file mode 100644 index 0000000000..2dfb85e136 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-rectilinear-grid.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-rectilinear-grid.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-rectilinear-grid.base.rgb24.ref.png new file mode 100644 index 0000000000..2dfb85e136 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-rectilinear-grid.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-rectilinear-grid.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-rectilinear-grid.quartz.ref.png new file mode 100644 index 0000000000..8e9dd19613 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-rectilinear-grid.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-rectilinear-grid.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-rectilinear-grid.ref.png new file mode 100644 index 0000000000..2dfb85e136 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-rectilinear-grid.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-sample.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-sample.base.argb32.ref.png new file mode 100644 index 0000000000..4c6131ce08 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-sample.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-sample.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-sample.base.rgb24.ref.png new file mode 100644 index 0000000000..4c6131ce08 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-sample.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-sample.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/a1-sample.quartz.xfail.png new file mode 100644 index 0000000000..8f1815be3d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-sample.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-sample.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-sample.ref.png new file mode 100644 index 0000000000..4c6131ce08 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-sample.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-tiger.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-tiger.base.argb32.ref.png new file mode 100644 index 0000000000..38472822f6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-tiger.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-tiger.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-tiger.base.rgb24.ref.png new file mode 100644 index 0000000000..38472822f6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-tiger.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-tiger.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-tiger.mask.argb32.ref.png new file mode 100644 index 0000000000..9a62af7603 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-tiger.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-tiger.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-tiger.mask.rgb24.ref.png new file mode 100644 index 0000000000..9a62af7603 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-tiger.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-tiger.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/a1-tiger.quartz.xfail.png new file mode 100644 index 0000000000..da3aec6606 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-tiger.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-tiger.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-tiger.ref.png new file mode 100644 index 0000000000..cc641e2903 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-tiger.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-tiger.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-tiger.traps.argb32.ref.png new file mode 100644 index 0000000000..cc641e2903 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-tiger.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-tiger.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-tiger.traps.rgb24.ref.png new file mode 100644 index 0000000000..cc641e2903 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-tiger.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-traps-sample.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-traps-sample.base.argb32.ref.png new file mode 100644 index 0000000000..384ba4a044 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-traps-sample.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-traps-sample.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-traps-sample.base.rgb24.ref.png new file mode 100644 index 0000000000..384ba4a044 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-traps-sample.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-traps-sample.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/a1-traps-sample.quartz.xfail.png new file mode 100644 index 0000000000..c89f4fe054 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-traps-sample.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a1-traps-sample.ref.png b/local/recipes/libs/cairo/source/test/reference/a1-traps-sample.ref.png new file mode 100644 index 0000000000..384ba4a044 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a1-traps-sample.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a8-clear.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/a8-clear.base.argb32.ref.png new file mode 100644 index 0000000000..52010808c1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a8-clear.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a8-clear.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/a8-clear.base.rgb24.ref.png new file mode 100644 index 0000000000..52010808c1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a8-clear.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a8-clear.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/a8-clear.quartz.ref.png new file mode 100644 index 0000000000..5b7c67fe95 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a8-clear.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a8-clear.ref.png b/local/recipes/libs/cairo/source/test/reference/a8-clear.ref.png new file mode 100644 index 0000000000..dbf45492c2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a8-clear.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a8-clear.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/a8-clear.traps.argb32.ref.png new file mode 100644 index 0000000000..52010808c1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a8-clear.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a8-clear.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/a8-clear.traps.rgb24.ref.png new file mode 100644 index 0000000000..52010808c1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a8-clear.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a8-mask.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/a8-mask.base.argb32.ref.png new file mode 100644 index 0000000000..e0503d93e7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a8-mask.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a8-mask.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/a8-mask.base.rgb24.ref.png new file mode 100644 index 0000000000..e0503d93e7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a8-mask.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/a8-mask.ref.png b/local/recipes/libs/cairo/source/test/reference/a8-mask.ref.png new file mode 100644 index 0000000000..38556156c0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/a8-mask.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/aliasing.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/aliasing.base.argb32.ref.png new file mode 100644 index 0000000000..a88dbe2720 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/aliasing.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/aliasing.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/aliasing.base.rgb24.ref.png new file mode 100644 index 0000000000..a88dbe2720 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/aliasing.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/aliasing.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/aliasing.image16.ref.png new file mode 100644 index 0000000000..c763333377 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/aliasing.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/aliasing.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/aliasing.quartz.ref.png new file mode 100644 index 0000000000..f4b6e22178 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/aliasing.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/aliasing.ref.png b/local/recipes/libs/cairo/source/test/reference/aliasing.ref.png new file mode 100644 index 0000000000..35bdb18574 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/aliasing.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/aliasing.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/aliasing.traps.argb32.ref.png new file mode 100644 index 0000000000..a88dbe2720 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/aliasing.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/aliasing.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/aliasing.traps.rgb24.ref.png new file mode 100644 index 0000000000..a88dbe2720 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/aliasing.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/alpha-similar.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/alpha-similar.base.argb32.ref.png new file mode 100644 index 0000000000..9e1bfaace4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/alpha-similar.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/alpha-similar.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/alpha-similar.base.rgb24.ref.png new file mode 100644 index 0000000000..a1f5280a42 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/alpha-similar.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/alpha-similar.pdf.argb32.xfail.png b/local/recipes/libs/cairo/source/test/reference/alpha-similar.pdf.argb32.xfail.png new file mode 100644 index 0000000000..75aa6005ca Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/alpha-similar.pdf.argb32.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/alpha-similar.pdf.rgb24.xfail.png b/local/recipes/libs/cairo/source/test/reference/alpha-similar.pdf.rgb24.xfail.png new file mode 100644 index 0000000000..86366d26f0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/alpha-similar.pdf.rgb24.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/alpha-similar.ps.argb32.xfail.png b/local/recipes/libs/cairo/source/test/reference/alpha-similar.ps.argb32.xfail.png new file mode 100644 index 0000000000..75aa6005ca Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/alpha-similar.ps.argb32.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/alpha-similar.ps.rgb24.xfail.png b/local/recipes/libs/cairo/source/test/reference/alpha-similar.ps.rgb24.xfail.png new file mode 100644 index 0000000000..15a6aa1149 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/alpha-similar.ps.rgb24.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/alpha-similar.ref.png b/local/recipes/libs/cairo/source/test/reference/alpha-similar.ref.png new file mode 100644 index 0000000000..9e1bfaace4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/alpha-similar.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/alpha-similar.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/alpha-similar.rgb24.ref.png new file mode 100644 index 0000000000..a1f5280a42 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/alpha-similar.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/api-special-cases.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/api-special-cases.base.argb32.ref.png new file mode 100644 index 0000000000..56b88a935b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/api-special-cases.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/api-special-cases.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/api-special-cases.base.rgb24.ref.png new file mode 100644 index 0000000000..56b88a935b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/api-special-cases.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/api-special-cases.ref.png b/local/recipes/libs/cairo/source/test/reference/api-special-cases.ref.png new file mode 100644 index 0000000000..56b88a935b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/api-special-cases.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/arc-direction.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/arc-direction.base.argb32.ref.png new file mode 100644 index 0000000000..2790a2b753 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/arc-direction.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/arc-direction.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/arc-direction.base.rgb24.ref.png new file mode 100644 index 0000000000..2790a2b753 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/arc-direction.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/arc-direction.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/arc-direction.ps.ref.png new file mode 100644 index 0000000000..902ab4578e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/arc-direction.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/arc-direction.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/arc-direction.quartz.ref.png new file mode 100644 index 0000000000..43e4afc37b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/arc-direction.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/arc-direction.ref.png b/local/recipes/libs/cairo/source/test/reference/arc-direction.ref.png new file mode 100644 index 0000000000..7b14d71a22 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/arc-direction.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/arc-direction.traps.ref.png b/local/recipes/libs/cairo/source/test/reference/arc-direction.traps.ref.png new file mode 100644 index 0000000000..2790a2b753 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/arc-direction.traps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/arc-infinite-loop.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/arc-infinite-loop.base.argb32.ref.png new file mode 100644 index 0000000000..82d645f306 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/arc-infinite-loop.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/arc-infinite-loop.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/arc-infinite-loop.base.rgb24.ref.png new file mode 100644 index 0000000000..82d645f306 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/arc-infinite-loop.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/arc-infinite-loop.ref.png b/local/recipes/libs/cairo/source/test/reference/arc-infinite-loop.ref.png new file mode 100644 index 0000000000..82d645f306 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/arc-infinite-loop.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/arc-looping-dash.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/arc-looping-dash.image16.ref.png new file mode 100644 index 0000000000..addc93c136 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/arc-looping-dash.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/arc-looping-dash.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/arc-looping-dash.mask.argb32.ref.png new file mode 100644 index 0000000000..516e66ce09 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/arc-looping-dash.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/arc-looping-dash.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/arc-looping-dash.mask.rgb24.ref.png new file mode 100644 index 0000000000..516e66ce09 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/arc-looping-dash.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/arc-looping-dash.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/arc-looping-dash.pdf.ref.png new file mode 100644 index 0000000000..5195b075ea Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/arc-looping-dash.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/arc-looping-dash.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/arc-looping-dash.ps.ref.png new file mode 100644 index 0000000000..ab19b199f2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/arc-looping-dash.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/arc-looping-dash.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/arc-looping-dash.quartz.xfail.png new file mode 100644 index 0000000000..5aeffe26c4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/arc-looping-dash.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/arc-looping-dash.ref.png b/local/recipes/libs/cairo/source/test/reference/arc-looping-dash.ref.png new file mode 100644 index 0000000000..516e66ce09 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/arc-looping-dash.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/arc-looping-dash.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/arc-looping-dash.svg.ref.png new file mode 100644 index 0000000000..5195b075ea Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/arc-looping-dash.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/arc-looping-dash.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/arc-looping-dash.traps.argb32.ref.png new file mode 100644 index 0000000000..58801ccd03 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/arc-looping-dash.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/arc-looping-dash.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/arc-looping-dash.traps.rgb24.ref.png new file mode 100644 index 0000000000..58801ccd03 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/arc-looping-dash.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/big-empty-box.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/big-empty-box.base.argb32.ref.png new file mode 100644 index 0000000000..a88d3b6de5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/big-empty-box.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/big-empty-box.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/big-empty-box.base.rgb24.ref.png new file mode 100644 index 0000000000..6c2ca32f0c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/big-empty-box.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/big-empty-box.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/big-empty-box.ps.rgb24.ref.png new file mode 100644 index 0000000000..6c2ca32f0c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/big-empty-box.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/big-empty-box.ref.png b/local/recipes/libs/cairo/source/test/reference/big-empty-box.ref.png new file mode 100644 index 0000000000..a88d3b6de5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/big-empty-box.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/big-empty-triangle.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/big-empty-triangle.base.argb32.ref.png new file mode 100644 index 0000000000..a88d3b6de5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/big-empty-triangle.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/big-empty-triangle.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/big-empty-triangle.base.rgb24.ref.png new file mode 100644 index 0000000000..6c2ca32f0c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/big-empty-triangle.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/big-empty-triangle.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/big-empty-triangle.ps.rgb24.ref.png new file mode 100644 index 0000000000..6c2ca32f0c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/big-empty-triangle.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/big-empty-triangle.ref.png b/local/recipes/libs/cairo/source/test/reference/big-empty-triangle.ref.png new file mode 100644 index 0000000000..a88d3b6de5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/big-empty-triangle.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/big-line.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/big-line.base.argb32.ref.png new file mode 100644 index 0000000000..35d2e36ab7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/big-line.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/big-line.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/big-line.base.rgb24.ref.png new file mode 100644 index 0000000000..35d2e36ab7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/big-line.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/big-line.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/big-line.image16.ref.png new file mode 100644 index 0000000000..47e33b8da3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/big-line.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/big-line.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/big-line.ps.ref.png new file mode 100644 index 0000000000..f498a8ab49 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/big-line.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/big-line.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/big-line.quartz.ref.png new file mode 100644 index 0000000000..a6f72404a2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/big-line.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/big-line.ref.png b/local/recipes/libs/cairo/source/test/reference/big-line.ref.png new file mode 100644 index 0000000000..2f35bfa561 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/big-line.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/big-line.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/big-line.traps.argb32.ref.png new file mode 100644 index 0000000000..35d2e36ab7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/big-line.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/big-line.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/big-line.traps.rgb24.ref.png new file mode 100644 index 0000000000..35d2e36ab7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/big-line.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/big-little-box.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/big-little-box.base.argb32.ref.png new file mode 100644 index 0000000000..928c5e6909 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/big-little-box.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/big-little-box.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/big-little-box.base.rgb24.ref.png new file mode 100644 index 0000000000..c069d6fdc6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/big-little-box.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/big-little-box.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/big-little-box.ps.rgb24.ref.png new file mode 100644 index 0000000000..c069d6fdc6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/big-little-box.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/big-little-box.ref.png b/local/recipes/libs/cairo/source/test/reference/big-little-box.ref.png new file mode 100644 index 0000000000..928c5e6909 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/big-little-box.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/big-little-triangle.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/big-little-triangle.argb32.ref.png new file mode 100644 index 0000000000..5308ccedb9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/big-little-triangle.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/big-little-triangle.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/big-little-triangle.base.argb32.ref.png new file mode 100644 index 0000000000..5308ccedb9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/big-little-triangle.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/big-little-triangle.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/big-little-triangle.base.rgb24.ref.png new file mode 100644 index 0000000000..9e4773b2d0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/big-little-triangle.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/big-little-triangle.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/big-little-triangle.quartz.rgb24.ref.png new file mode 100644 index 0000000000..4914a4ad26 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/big-little-triangle.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/big-little-triangle.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/big-little-triangle.rgb24.ref.png new file mode 100644 index 0000000000..9e4773b2d0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/big-little-triangle.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/big-trap.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/big-trap.ps.ref.png new file mode 100644 index 0000000000..776221a505 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/big-trap.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/big-trap.ref.png b/local/recipes/libs/cairo/source/test/reference/big-trap.ref.png new file mode 100644 index 0000000000..dd91ff04bf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/big-trap.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bilevel-image.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/bilevel-image.base.argb32.ref.png new file mode 100644 index 0000000000..3fb25c2e58 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bilevel-image.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bilevel-image.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/bilevel-image.base.rgb24.ref.png new file mode 100644 index 0000000000..3fb25c2e58 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bilevel-image.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bilevel-image.ref.png b/local/recipes/libs/cairo/source/test/reference/bilevel-image.ref.png new file mode 100644 index 0000000000..cae76d69dc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bilevel-image.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bilevel-xlib-fallback.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/bilevel-xlib-fallback.rgb24.ref.png new file mode 100644 index 0000000000..3fb25c2e58 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bilevel-xlib-fallback.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bilevel-xlib-window.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/bilevel-xlib-window.rgb24.ref.png new file mode 100644 index 0000000000..3fb25c2e58 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bilevel-xlib-window.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bilevel-xlib.ref.png b/local/recipes/libs/cairo/source/test/reference/bilevel-xlib.ref.png new file mode 100644 index 0000000000..3fb25c2e58 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bilevel-xlib.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bitmap-font.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/bitmap-font.base.argb32.ref.png new file mode 100644 index 0000000000..bc2bc52e00 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bitmap-font.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bitmap-font.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/bitmap-font.base.rgb24.ref.png new file mode 100644 index 0000000000..285d742888 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bitmap-font.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bitmap-font.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/bitmap-font.ps.rgb24.ref.png new file mode 100644 index 0000000000..285d742888 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bitmap-font.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bitmap-font.ref.png b/local/recipes/libs/cairo/source/test/reference/bitmap-font.ref.png new file mode 100644 index 0000000000..0718bf96a3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bitmap-font.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-361.image16.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-361.image16.rgb24.ref.png new file mode 100644 index 0000000000..1597fd93b9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-361.image16.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-361.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-361.ref.png new file mode 100644 index 0000000000..cf03850499 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-361.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-361.xcb-window&.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-361.xcb-window&.rgb24.ref.png new file mode 100644 index 0000000000..fc04eda568 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-361.xcb-window&.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-361.xcb-window.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-361.xcb-window.rgb24.ref.png new file mode 100644 index 0000000000..fc04eda568 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-361.xcb-window.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-361.xcb.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-361.xcb.argb32.ref.png new file mode 100644 index 0000000000..79ae2ce185 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-361.xcb.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-361.xcb.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-361.xcb.rgb24.ref.png new file mode 100644 index 0000000000..fc04eda568 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-361.xcb.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-361.xlib-window.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-361.xlib-window.rgb24.ref.png new file mode 100644 index 0000000000..75e405cce3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-361.xlib-window.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-361.xlib.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-361.xlib.argb32.ref.png new file mode 100644 index 0000000000..2e64e088b5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-361.xlib.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-361.xlib.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-361.xlib.rgb24.ref.png new file mode 100644 index 0000000000..75e405cce3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-361.xlib.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-40410.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-40410.base.argb32.ref.png new file mode 100644 index 0000000000..a315935369 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-40410.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-40410.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-40410.base.rgb24.ref.png new file mode 100644 index 0000000000..a315935369 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-40410.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-40410.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-40410.ref.png new file mode 100644 index 0000000000..ae4420a70b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-40410.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-40410.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-40410.traps.argb32.ref.png new file mode 100644 index 0000000000..a315935369 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-40410.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-40410.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-40410.traps.rgb24.ref.png new file mode 100644 index 0000000000..a315935369 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-40410.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-431.image16.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-431.image16.rgb24.ref.png new file mode 100644 index 0000000000..10ebf3e62e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-431.image16.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-431.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-431.pdf.ref.png new file mode 100644 index 0000000000..2ff4b3759d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-431.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-431.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-431.pdf.rgb24.ref.png new file mode 100644 index 0000000000..57145ce322 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-431.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-431.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-431.ref.png new file mode 100644 index 0000000000..5ebddbb6d0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-431.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-431.svg.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-431.svg.rgb24.ref.png new file mode 100644 index 0000000000..9360ee2f8d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-431.svg.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-431.xlib-window.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-431.xlib-window.rgb24.ref.png new file mode 100644 index 0000000000..208bcfd39e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-431.xlib-window.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-431.xlib.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-431.xlib.rgb24.ref.png new file mode 100644 index 0000000000..208bcfd39e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-431.xlib.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-448.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-448.ref.png new file mode 100644 index 0000000000..7997f8a96c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-448.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-51910.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-51910.pdf.ref.png new file mode 100644 index 0000000000..df26fe2007 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-51910.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-51910.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-51910.ps.ref.png new file mode 100644 index 0000000000..dcac03f518 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-51910.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-51910.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-51910.quartz.ref.png new file mode 100644 index 0000000000..cc900e68ca Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-51910.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-51910.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-51910.ref.png new file mode 100644 index 0000000000..7f55eaae5e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-51910.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-51910.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-51910.svg.ref.png new file mode 100644 index 0000000000..20df15368e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-51910.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-535.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-535.ref.png new file mode 100644 index 0000000000..7d5589c1d7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-535.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-75705.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-75705.ref.png new file mode 100644 index 0000000000..c0ac5ff648 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-75705.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-84115.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-84115.pdf.ref.png new file mode 100644 index 0000000000..95b5058e22 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-84115.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-84115.ps.arg32.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-84115.ps.arg32.ref.png new file mode 100644 index 0000000000..2c2b918be8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-84115.ps.arg32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-84115.ps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-84115.ps.argb32.ref.png new file mode 100644 index 0000000000..2c2b918be8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-84115.ps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-84115.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-84115.ps.rgb24.ref.png new file mode 100644 index 0000000000..2c2b918be8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-84115.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-84115.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-84115.ref.png new file mode 100644 index 0000000000..df16257ad0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-84115.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-84115.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-84115.svg.ref.png new file mode 100644 index 0000000000..26778856ac Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-84115.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-84115.xlib.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-84115.xlib.ref.png new file mode 100644 index 0000000000..2e17a65701 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-84115.xlib.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-bo-collins.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-bo-collins.ps.ref.png new file mode 100644 index 0000000000..7e3693a10a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-bo-collins.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-bo-collins.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-bo-collins.ref.png new file mode 100644 index 0000000000..72e5c1d7c9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-bo-collins.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-bo-rectangular.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-bo-rectangular.base.argb32.ref.png new file mode 100644 index 0000000000..ffa4edef61 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-bo-rectangular.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-bo-rectangular.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-bo-rectangular.base.rgb24.ref.png new file mode 100644 index 0000000000..ffa4edef61 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-bo-rectangular.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-bo-rectangular.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-bo-rectangular.image16.ref.png new file mode 100644 index 0000000000..d468d59eff Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-bo-rectangular.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-bo-rectangular.ps.xfail.png b/local/recipes/libs/cairo/source/test/reference/bug-bo-rectangular.ps.xfail.png new file mode 100644 index 0000000000..c2314a1250 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-bo-rectangular.ps.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-bo-rectangular.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-bo-rectangular.ref.png new file mode 100644 index 0000000000..ffa4edef61 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-bo-rectangular.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-bo-ricotz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-bo-ricotz.argb32.ref.png new file mode 100644 index 0000000000..1f73469281 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-bo-ricotz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-bo-ricotz.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-bo-ricotz.base.argb32.ref.png new file mode 100644 index 0000000000..ff7a552f7c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-bo-ricotz.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-bo-ricotz.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-bo-ricotz.base.rgb24.ref.png new file mode 100644 index 0000000000..ff7a552f7c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-bo-ricotz.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-bo-ricotz.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-bo-ricotz.pdf.rgb24.ref.png new file mode 100644 index 0000000000..1f73469281 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-bo-ricotz.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-bo-ricotz.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-bo-ricotz.ps.ref.png new file mode 100644 index 0000000000..ce308e225f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-bo-ricotz.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-bo-ricotz.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-bo-ricotz.ref.png new file mode 100644 index 0000000000..0e52b24543 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-bo-ricotz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-bo-ricotz.svg.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-bo-ricotz.svg.rgb24.ref.png new file mode 100644 index 0000000000..1f73469281 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-bo-ricotz.svg.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-bo-ricotz.traps.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-bo-ricotz.traps.ref.png new file mode 100644 index 0000000000..ff7a552f7c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-bo-ricotz.traps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-extents.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-extents.base.argb32.ref.png new file mode 100644 index 0000000000..e07f8aa493 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-extents.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-extents.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-extents.base.rgb24.ref.png new file mode 100644 index 0000000000..e07f8aa493 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-extents.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-extents.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-extents.image16.ref.png new file mode 100644 index 0000000000..8eb3d4bcde Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-extents.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-extents.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-extents.pdf.ref.png new file mode 100644 index 0000000000..c3d02d7039 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-extents.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-extents.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-extents.ps.ref.png new file mode 100644 index 0000000000..2d55405652 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-extents.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-extents.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-extents.quartz.ref.png new file mode 100644 index 0000000000..193d3e746a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-extents.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-extents.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-extents.ref.png new file mode 100644 index 0000000000..e85561183d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-extents.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-extents.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-extents.traps.argb32.ref.png new file mode 100644 index 0000000000..e07f8aa493 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-extents.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-extents.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-extents.traps.rgb24.ref.png new file mode 100644 index 0000000000..e07f8aa493 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-extents.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-image-compositor.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-image-compositor.ref.png new file mode 100644 index 0000000000..939f659d2c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-image-compositor.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-image-compositor.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-image-compositor.svg.ref.png new file mode 100644 index 0000000000..8c1c30ab30 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-image-compositor.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-seams.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-seams.base.argb32.ref.png new file mode 100644 index 0000000000..ac80651201 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-seams.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-seams.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-seams.base.rgb24.ref.png new file mode 100644 index 0000000000..ac80651201 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-seams.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-seams.image.xfail.png b/local/recipes/libs/cairo/source/test/reference/bug-seams.image.xfail.png new file mode 100644 index 0000000000..99098db8cc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-seams.image.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-seams.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-seams.mask.argb32.ref.png new file mode 100644 index 0000000000..99098db8cc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-seams.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-seams.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-seams.mask.rgb24.ref.png new file mode 100644 index 0000000000..99098db8cc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-seams.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-seams.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/bug-seams.quartz.xfail.png new file mode 100644 index 0000000000..25c98b36a7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-seams.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-seams.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-seams.ref.png new file mode 100644 index 0000000000..e4e72faf49 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-seams.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-seams.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-seams.traps.argb32.ref.png new file mode 100644 index 0000000000..ac80651201 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-seams.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-seams.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-seams.traps.rgb24.ref.png new file mode 100644 index 0000000000..ac80651201 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-seams.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-seams.xlib-fallback.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-seams.xlib-fallback.ref.png new file mode 100644 index 0000000000..e81fc6caa6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-seams.xlib-fallback.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-source-cu.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-source-cu.pdf.argb32.ref.png new file mode 100644 index 0000000000..084d1974ac Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-source-cu.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-source-cu.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-source-cu.pdf.rgb24.ref.png new file mode 100644 index 0000000000..0b11626e5f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-source-cu.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-source-cu.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-source-cu.ps.ref.png new file mode 100644 index 0000000000..51bcb3eca3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-source-cu.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-source-cu.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-source-cu.ref.png new file mode 100644 index 0000000000..808feb5f29 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-source-cu.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-source-cu.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-source-cu.traps.argb32.ref.png new file mode 100644 index 0000000000..d8837c30db Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-source-cu.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-source-cu.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-source-cu.traps.rgb24.ref.png new file mode 100644 index 0000000000..75e3b326eb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-source-cu.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-spline.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-spline.ps.ref.png new file mode 100644 index 0000000000..5eb788672d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-spline.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-spline.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-spline.quartz.ref.png new file mode 100644 index 0000000000..34daba03c9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-spline.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/bug-spline.ref.png b/local/recipes/libs/cairo/source/test/reference/bug-spline.ref.png new file mode 100644 index 0000000000..26d5609535 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/bug-spline.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-05.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-05.pdf.ref.png new file mode 100644 index 0000000000..cec500a491 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-05.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-05.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-05.ps.ref.png new file mode 100644 index 0000000000..48f84ae0a9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-05.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-05.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-05.quartz.ref.png new file mode 100644 index 0000000000..c104602039 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-05.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-05.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-05.ref.png new file mode 100644 index 0000000000..946adcbfa4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-05.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-05.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-05.svg.ref.png new file mode 100644 index 0000000000..8ce8a2d2eb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-05.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-05.traps.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-05.traps.ref.png new file mode 100644 index 0000000000..409bdab07a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-05.traps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-1.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-1.pdf.ref.png new file mode 100644 index 0000000000..cec500a491 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-1.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-1.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-1.ps.ref.png new file mode 100644 index 0000000000..9fce748186 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-1.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-1.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-1.quartz.ref.png new file mode 100644 index 0000000000..668ac6950f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-1.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-1.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-1.ref.png new file mode 100644 index 0000000000..dfb111808a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-1.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-1.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-1.svg.ref.png new file mode 100644 index 0000000000..91a49f7c6d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-1.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-1.traps.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-1.traps.ref.png new file mode 100644 index 0000000000..10f7d57a3b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-1.traps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-2.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-2.pdf.ref.png new file mode 100644 index 0000000000..43821fe0fd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-2.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-2.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-2.ps.ref.png new file mode 100644 index 0000000000..2bda07b917 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-2.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-2.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-2.ref.png new file mode 100644 index 0000000000..ca420bcab6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-2.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-2.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-2.svg.ref.png new file mode 100644 index 0000000000..43821fe0fd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-2.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-2.traps.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-2.traps.ref.png new file mode 100644 index 0000000000..1c5d88574c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-2.traps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins-05.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins-05.pdf.ref.png new file mode 100644 index 0000000000..fbe8391567 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins-05.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins-05.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins-05.ps.ref.png new file mode 100644 index 0000000000..e767c40fb4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins-05.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins-05.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins-05.quartz.ref.png new file mode 100644 index 0000000000..21a8338764 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins-05.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins-05.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins-05.ref.png new file mode 100644 index 0000000000..8814acedee Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins-05.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins-05.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins-05.svg.ref.png new file mode 100644 index 0000000000..4da2b13c16 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins-05.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins-05.traps.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins-05.traps.ref.png new file mode 100644 index 0000000000..938fb6d1b2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins-05.traps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins-1.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins-1.pdf.ref.png new file mode 100644 index 0000000000..fbe8391567 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins-1.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins-1.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins-1.ps.ref.png new file mode 100644 index 0000000000..ef5ed372ca Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins-1.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins-1.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins-1.quartz.ref.png new file mode 100644 index 0000000000..8c549d3c2e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins-1.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins-1.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins-1.ref.png new file mode 100644 index 0000000000..d7cdf2c861 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins-1.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins-1.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins-1.svg.ref.png new file mode 100644 index 0000000000..159ff0e25b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins-1.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins-1.traps.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins-1.traps.ref.png new file mode 100644 index 0000000000..d9721f29f0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins-1.traps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins-2.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins-2.pdf.ref.png new file mode 100644 index 0000000000..70faca9dc8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins-2.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins-2.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins-2.ps.ref.png new file mode 100644 index 0000000000..da7e3eeafd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins-2.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins-2.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins-2.ref.png new file mode 100644 index 0000000000..1416a54e41 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins-2.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins-2.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins-2.svg.ref.png new file mode 100644 index 0000000000..70faca9dc8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins-2.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins-2.traps.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins-2.traps.ref.png new file mode 100644 index 0000000000..e7089a8de4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins-2.traps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins-alpha.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins-alpha.image16.ref.png new file mode 100644 index 0000000000..ddefea81cd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins-alpha.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins-alpha.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins-alpha.mask.argb32.ref.png new file mode 100644 index 0000000000..964a70f379 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins-alpha.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins-alpha.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins-alpha.mask.rgb24.ref.png new file mode 100644 index 0000000000..964a70f379 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins-alpha.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins-alpha.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins-alpha.quartz.ref.png new file mode 100644 index 0000000000..f4cb950540 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins-alpha.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins-alpha.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins-alpha.ref.png new file mode 100644 index 0000000000..9479bf2474 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins-alpha.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins-alpha.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins-alpha.traps.argb32.ref.png new file mode 100644 index 0000000000..e17c4a1979 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins-alpha.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins-alpha.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins-alpha.traps.rgb24.ref.png new file mode 100644 index 0000000000..e17c4a1979 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins-alpha.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins-curve.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins-curve.image16.ref.png new file mode 100644 index 0000000000..060b3dcb1c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins-curve.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins-curve.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins-curve.mask.argb32.ref.png new file mode 100644 index 0000000000..35959002c6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins-curve.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins-curve.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins-curve.mask.rgb24.ref.png new file mode 100644 index 0000000000..35959002c6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins-curve.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins-curve.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins-curve.pdf.ref.png new file mode 100644 index 0000000000..17d6b451d0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins-curve.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins-curve.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins-curve.ps.ref.png new file mode 100644 index 0000000000..7fbb826a1f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins-curve.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins-curve.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins-curve.ref.png new file mode 100644 index 0000000000..a9f66a04b8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins-curve.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins-curve.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins-curve.svg.ref.png new file mode 100644 index 0000000000..17d6b451d0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins-curve.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins-curve.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins-curve.traps.argb32.ref.png new file mode 100644 index 0000000000..7ce1acc3dd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins-curve.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins-curve.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins-curve.traps.rgb24.ref.png new file mode 100644 index 0000000000..7ce1acc3dd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins-curve.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins.base.argb32.ref.png new file mode 100644 index 0000000000..470eec3b19 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins.base.rgb24.ref.png new file mode 100644 index 0000000000..470eec3b19 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins.image16.ref.png new file mode 100644 index 0000000000..0c452f29ed Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins.pdf.ref.png new file mode 100644 index 0000000000..1faf366c77 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins.ps.ref.png new file mode 100644 index 0000000000..f6c85cef77 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins.ref.png new file mode 100644 index 0000000000..6d7122ee10 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins.traps.argb32.ref.png new file mode 100644 index 0000000000..470eec3b19 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-joins.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-joins.traps.rgb24.ref.png new file mode 100644 index 0000000000..470eec3b19 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-joins.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-sub-paths.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-sub-paths.base.argb32.ref.png new file mode 100644 index 0000000000..1e4a83f0b4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-sub-paths.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-sub-paths.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-sub-paths.base.rgb24.ref.png new file mode 100644 index 0000000000..1e4a83f0b4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-sub-paths.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-sub-paths.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-sub-paths.image16.ref.png new file mode 100644 index 0000000000..c0cc4d74b2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-sub-paths.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-sub-paths.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-sub-paths.pdf.ref.png new file mode 100644 index 0000000000..8a5816047e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-sub-paths.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-sub-paths.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-sub-paths.ps.ref.png new file mode 100644 index 0000000000..197b443cd4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-sub-paths.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-sub-paths.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-sub-paths.ref.png new file mode 100644 index 0000000000..744338957d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-sub-paths.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-sub-paths.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-sub-paths.svg.ref.png new file mode 100644 index 0000000000..8a5816047e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-sub-paths.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-sub-paths.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-sub-paths.traps.argb32.ref.png new file mode 100644 index 0000000000..1e4a83f0b4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-sub-paths.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-sub-paths.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-sub-paths.traps.rgb24.ref.png new file mode 100644 index 0000000000..1e4a83f0b4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-sub-paths.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-tails-curve.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-tails-curve.mask.argb32.ref.png new file mode 100644 index 0000000000..b0f477df96 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-tails-curve.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-tails-curve.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-tails-curve.mask.rgb24.ref.png new file mode 100644 index 0000000000..b0f477df96 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-tails-curve.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-tails-curve.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-tails-curve.pdf.ref.png new file mode 100644 index 0000000000..fa7e21fea4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-tails-curve.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-tails-curve.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-tails-curve.ps.ref.png new file mode 100644 index 0000000000..fca77c3457 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-tails-curve.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-tails-curve.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-tails-curve.quartz.ref.png new file mode 100644 index 0000000000..489300a268 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-tails-curve.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-tails-curve.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-tails-curve.ref.png new file mode 100644 index 0000000000..df036d2738 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-tails-curve.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-tails-curve.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-tails-curve.svg.ref.png new file mode 100644 index 0000000000..fa7e21fea4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-tails-curve.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-tails-curve.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-tails-curve.traps.argb32.ref.png new file mode 100644 index 0000000000..9d579998a1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-tails-curve.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-tails-curve.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-tails-curve.traps.rgb24.ref.png new file mode 100644 index 0000000000..9d579998a1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-tails-curve.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps-tails-curve.xcb.ref.png b/local/recipes/libs/cairo/source/test/reference/caps-tails-curve.xcb.ref.png new file mode 100644 index 0000000000..89022033c3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps-tails-curve.xcb.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/caps.base.argb32.ref.png new file mode 100644 index 0000000000..b3504abcb7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/caps.base.rgb24.ref.png new file mode 100644 index 0000000000..b3504abcb7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/caps.image16.ref.png new file mode 100644 index 0000000000..a33a5ef73e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/caps.pdf.ref.png new file mode 100644 index 0000000000..8ec25032a5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/caps.ps.ref.png new file mode 100644 index 0000000000..c91b8aa3b3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps.ref.png b/local/recipes/libs/cairo/source/test/reference/caps.ref.png new file mode 100644 index 0000000000..bf784fd403 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/caps.svg.ref.png new file mode 100644 index 0000000000..8ec25032a5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/caps.traps.argb32.ref.png new file mode 100644 index 0000000000..b3504abcb7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/caps.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/caps.traps.rgb24.ref.png new file mode 100644 index 0000000000..b3504abcb7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/caps.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/checkerboard.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/checkerboard.base.argb32.ref.png new file mode 100644 index 0000000000..1444bc41b7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/checkerboard.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/checkerboard.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/checkerboard.base.rgb24.ref.png new file mode 100644 index 0000000000..1444bc41b7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/checkerboard.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/checkerboard.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/checkerboard.pdf.ref.png new file mode 100644 index 0000000000..3f0391ca2a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/checkerboard.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/checkerboard.ref.png b/local/recipes/libs/cairo/source/test/reference/checkerboard.ref.png new file mode 100644 index 0000000000..1444bc41b7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/checkerboard.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/checkerboard.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/checkerboard.svg.ref.png new file mode 100644 index 0000000000..3f0391ca2a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/checkerboard.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clear-source.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clear-source.base.argb32.ref.png new file mode 100644 index 0000000000..293411c473 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clear-source.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clear-source.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clear-source.base.rgb24.ref.png new file mode 100644 index 0000000000..293411c473 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clear-source.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clear-source.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/clear-source.image16.ref.png new file mode 100644 index 0000000000..4055b95fee Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clear-source.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clear-source.pdf.xfail.png b/local/recipes/libs/cairo/source/test/reference/clear-source.pdf.xfail.png new file mode 100644 index 0000000000..8e1bdd76e5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clear-source.pdf.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clear-source.ps.xfail.png b/local/recipes/libs/cairo/source/test/reference/clear-source.ps.xfail.png new file mode 100644 index 0000000000..b515751d6c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clear-source.ps.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clear-source.ref.png b/local/recipes/libs/cairo/source/test/reference/clear-source.ref.png new file mode 100644 index 0000000000..352bf45036 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clear-source.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clear-source.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clear-source.traps.argb32.ref.png new file mode 100644 index 0000000000..293411c473 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clear-source.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clear-source.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clear-source.traps.rgb24.ref.png new file mode 100644 index 0000000000..293411c473 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clear-source.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clear.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clear.argb32.ref.png new file mode 100644 index 0000000000..64d89c1cb8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clear.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clear.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clear.base.argb32.ref.png new file mode 100644 index 0000000000..1caca6dfb2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clear.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clear.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clear.base.rgb24.ref.png new file mode 100644 index 0000000000..7d789b0bb6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clear.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clear.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clear.pdf.argb32.ref.png new file mode 100644 index 0000000000..0960f4851f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clear.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clear.ps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clear.ps.argb32.ref.png new file mode 100644 index 0000000000..0960f4851f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clear.ps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clear.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clear.quartz.argb32.ref.png new file mode 100644 index 0000000000..0013b11079 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clear.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clear.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clear.quartz.rgb24.ref.png new file mode 100644 index 0000000000..021781cb55 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clear.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clear.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clear.rgb24.ref.png new file mode 100644 index 0000000000..d59e44e113 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clear.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clear.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clear.traps.argb32.ref.png new file mode 100644 index 0000000000..1caca6dfb2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clear.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clear.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clear.traps.rgb24.ref.png new file mode 100644 index 0000000000..7d789b0bb6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clear.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-all.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-all.base.argb32.ref.png new file mode 100644 index 0000000000..1ed070cae0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-all.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-all.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-all.base.rgb24.ref.png new file mode 100644 index 0000000000..1ed070cae0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-all.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-all.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-all.ref.png new file mode 100644 index 0000000000..6c14df51f8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-all.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-complex-bug61592.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-complex-bug61592.pdf.ref.png new file mode 100644 index 0000000000..02abd0e76e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-complex-bug61592.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-complex-bug61592.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-complex-bug61592.ps.ref.png new file mode 100644 index 0000000000..b86fb18073 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-complex-bug61592.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-complex-bug61592.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-complex-bug61592.quartz.ref.png new file mode 100644 index 0000000000..3ebc707e03 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-complex-bug61592.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-complex-bug61592.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-complex-bug61592.ref.png new file mode 100644 index 0000000000..8e2e982be6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-complex-bug61592.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-complex-bug61592.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-complex-bug61592.svg.ref.png new file mode 100644 index 0000000000..02abd0e76e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-complex-bug61592.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-complex-shape-eo-aa.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-complex-shape-eo-aa.base.argb32.ref.png new file mode 100644 index 0000000000..bafbb8ad1f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-complex-shape-eo-aa.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-complex-shape-eo-aa.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-complex-shape-eo-aa.base.rgb24.ref.png new file mode 100644 index 0000000000..bafbb8ad1f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-complex-shape-eo-aa.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-complex-shape-eo-aa.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-complex-shape-eo-aa.ps.ref.png new file mode 100644 index 0000000000..07f976208b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-complex-shape-eo-aa.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-complex-shape-eo-aa.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-complex-shape-eo-aa.ref.png new file mode 100644 index 0000000000..d575aa9ad2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-complex-shape-eo-aa.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-complex-shape-eo-mono.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-complex-shape-eo-mono.base.argb32.ref.png new file mode 100644 index 0000000000..bafbb8ad1f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-complex-shape-eo-mono.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-complex-shape-eo-mono.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-complex-shape-eo-mono.base.rgb24.ref.png new file mode 100644 index 0000000000..bafbb8ad1f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-complex-shape-eo-mono.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-complex-shape-eo-mono.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-complex-shape-eo-mono.ps.ref.png new file mode 100644 index 0000000000..07f976208b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-complex-shape-eo-mono.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-complex-shape-eo-mono.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-complex-shape-eo-mono.ref.png new file mode 100644 index 0000000000..d575aa9ad2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-complex-shape-eo-mono.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-contexts.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-contexts.base.argb32.ref.png new file mode 100644 index 0000000000..0d575a6286 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-contexts.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-contexts.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-contexts.base.rgb24.ref.png new file mode 100644 index 0000000000..0d575a6286 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-contexts.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-contexts.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-contexts.ref.png new file mode 100644 index 0000000000..0d575a6286 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-contexts.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-device-offset.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-device-offset.base.argb32.ref.png new file mode 100644 index 0000000000..06be985192 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-device-offset.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-device-offset.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-device-offset.base.rgb24.ref.png new file mode 100644 index 0000000000..2419384596 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-device-offset.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-device-offset.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-device-offset.ps.rgb24.ref.png new file mode 100644 index 0000000000..2419384596 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-device-offset.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-device-offset.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-device-offset.ref.png new file mode 100644 index 0000000000..06be985192 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-device-offset.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-disjoint-hatching.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-disjoint-hatching.base.argb32.ref.png new file mode 100644 index 0000000000..55f26d0b50 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-disjoint-hatching.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-disjoint-hatching.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-disjoint-hatching.base.rgb24.ref.png new file mode 100644 index 0000000000..55f26d0b50 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-disjoint-hatching.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-disjoint-hatching.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-disjoint-hatching.mask.argb32.ref.png new file mode 100644 index 0000000000..a29f04ac92 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-disjoint-hatching.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-disjoint-hatching.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-disjoint-hatching.mask.rgb24.ref.png new file mode 100644 index 0000000000..a29f04ac92 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-disjoint-hatching.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-disjoint-hatching.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-disjoint-hatching.quartz.ref.png new file mode 100644 index 0000000000..d80913328b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-disjoint-hatching.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-disjoint-hatching.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-disjoint-hatching.ref.png new file mode 100644 index 0000000000..ff47816f8a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-disjoint-hatching.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-disjoint-hatching.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-disjoint-hatching.traps.argb32.ref.png new file mode 100644 index 0000000000..6226d931e2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-disjoint-hatching.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-disjoint-hatching.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-disjoint-hatching.traps.rgb24.ref.png new file mode 100644 index 0000000000..6226d931e2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-disjoint-hatching.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-disjoint-quad.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-disjoint-quad.pdf.ref.png new file mode 100644 index 0000000000..d24d910b6e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-disjoint-quad.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-disjoint-quad.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-disjoint-quad.ps.ref.png new file mode 100644 index 0000000000..411f8195ac Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-disjoint-quad.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-disjoint-quad.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-disjoint-quad.ref.png new file mode 100644 index 0000000000..25fbf0b1cb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-disjoint-quad.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-disjoint-quad.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-disjoint-quad.svg.ref.png new file mode 100644 index 0000000000..d24d910b6e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-disjoint-quad.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-disjoint-quad.traps.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-disjoint-quad.traps.ref.png new file mode 100644 index 0000000000..de5ceb77b6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-disjoint-quad.traps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-disjoint.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-disjoint.base.argb32.ref.png new file mode 100644 index 0000000000..74ae9d8692 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-disjoint.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-disjoint.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-disjoint.base.rgb24.ref.png new file mode 100644 index 0000000000..74ae9d8692 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-disjoint.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-disjoint.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-disjoint.image16.ref.png new file mode 100644 index 0000000000..79aaf7164a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-disjoint.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-disjoint.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-disjoint.mask.argb32.ref.png new file mode 100644 index 0000000000..4e18b7c7c6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-disjoint.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-disjoint.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-disjoint.mask.rgb24.ref.png new file mode 100644 index 0000000000..4e18b7c7c6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-disjoint.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-disjoint.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-disjoint.ps.ref.png new file mode 100644 index 0000000000..17b867f6f8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-disjoint.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-disjoint.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-disjoint.quartz.ref.png new file mode 100644 index 0000000000..6bd15031b2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-disjoint.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-disjoint.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-disjoint.ref.png new file mode 100644 index 0000000000..c0d1c06408 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-disjoint.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-disjoint.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-disjoint.traps.argb32.ref.png new file mode 100644 index 0000000000..74ae9d8692 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-disjoint.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-disjoint.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-disjoint.traps.rgb24.ref.png new file mode 100644 index 0000000000..74ae9d8692 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-disjoint.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-empty-group.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-empty-group.base.argb32.ref.png new file mode 100644 index 0000000000..a59ca472d5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-empty-group.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-empty-group.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-empty-group.base.rgb24.ref.png new file mode 100644 index 0000000000..a59ca472d5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-empty-group.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-empty-group.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-empty-group.ref.png new file mode 100644 index 0000000000..a59ca472d5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-empty-group.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-empty-save.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-empty-save.base.argb32.ref.png new file mode 100644 index 0000000000..1ed070cae0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-empty-save.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-empty-save.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-empty-save.base.rgb24.ref.png new file mode 100644 index 0000000000..1ed070cae0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-empty-save.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-empty-save.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-empty-save.ref.png new file mode 100644 index 0000000000..6c14df51f8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-empty-save.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-empty.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-empty.base.argb32.ref.png new file mode 100644 index 0000000000..1ed070cae0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-empty.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-empty.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-empty.base.rgb24.ref.png new file mode 100644 index 0000000000..1ed070cae0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-empty.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-empty.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-empty.ref.png new file mode 100644 index 0000000000..6c14df51f8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-empty.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.argb32.ref.png new file mode 100644 index 0000000000..be56f728dc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.base.argb32.ref.png new file mode 100644 index 0000000000..81ecfb9a6b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.base.rgb24.ref.png new file mode 100644 index 0000000000..d6a5939b74 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.image16.ref.png new file mode 100644 index 0000000000..e0e66ff7b8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.mask.argb32.ref.png new file mode 100644 index 0000000000..2340bdf122 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.mask.rgb24.ref.png new file mode 100644 index 0000000000..299bd72a8f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.quartz.argb32.ref.png new file mode 100644 index 0000000000..3423000952 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.quartz.rgb24.ref.png new file mode 100644 index 0000000000..1612801bd1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.rgb24.ref.png new file mode 100644 index 0000000000..e78ef0a322 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.svg.ref.png new file mode 100644 index 0000000000..f16e517c0d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.traps.argb32.ref.png new file mode 100644 index 0000000000..19b9f09099 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.traps.rgb24.ref.png new file mode 100644 index 0000000000..1ad0b176be Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.xlib-fallback.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.xlib-fallback.rgb24.ref.png new file mode 100644 index 0000000000..ec258968ef Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-eo-unbounded.xlib-fallback.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-no-op.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-no-op.base.argb32.ref.png new file mode 100644 index 0000000000..2256461a98 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-no-op.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-no-op.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-no-op.base.rgb24.ref.png new file mode 100644 index 0000000000..2256461a98 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-no-op.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-no-op.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-no-op.image16.ref.png new file mode 100644 index 0000000000..cf0c74ad8f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-no-op.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-no-op.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-no-op.ps.ref.png new file mode 100644 index 0000000000..b51490deb9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-no-op.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-no-op.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-no-op.ref.png new file mode 100644 index 0000000000..2256461a98 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-no-op.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.argb32.ref.png new file mode 100644 index 0000000000..be56f728dc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.base.argb32.ref.png new file mode 100644 index 0000000000..81ecfb9a6b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.base.rgb24.ref.png new file mode 100644 index 0000000000..d6a5939b74 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.image16.ref.png new file mode 100644 index 0000000000..e0e66ff7b8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.mask.argb32.ref.png new file mode 100644 index 0000000000..05b26282c4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.mask.rgb24.ref.png new file mode 100644 index 0000000000..9ce760b132 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.quartz.argb32.ref.png new file mode 100644 index 0000000000..3423000952 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.quartz.rgb24.ref.png new file mode 100644 index 0000000000..1612801bd1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.rgb24.ref.png new file mode 100644 index 0000000000..e78ef0a322 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.svg.ref.png new file mode 100644 index 0000000000..f16e517c0d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.traps.argb32.ref.png new file mode 100644 index 0000000000..19b9f09099 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.traps.rgb24.ref.png new file mode 100644 index 0000000000..1ad0b176be Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.xlib-fallback.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.xlib-fallback.rgb24.ref.png new file mode 100644 index 0000000000..ec258968ef Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-nz-unbounded.xlib-fallback.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-rule-pixel-aligned.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-rule-pixel-aligned.base.argb32.ref.png new file mode 100644 index 0000000000..9b82c4b5f6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-rule-pixel-aligned.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-rule-pixel-aligned.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-rule-pixel-aligned.base.rgb24.ref.png new file mode 100644 index 0000000000..0b4f068836 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-rule-pixel-aligned.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-rule-pixel-aligned.ps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-rule-pixel-aligned.ps.argb32.ref.png new file mode 100644 index 0000000000..6b946fcdfe Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-rule-pixel-aligned.ps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-rule-pixel-aligned.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-rule-pixel-aligned.ps.rgb24.ref.png new file mode 100644 index 0000000000..3ba5254759 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-rule-pixel-aligned.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-rule-pixel-aligned.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-rule-pixel-aligned.ref.png new file mode 100644 index 0000000000..66eb6852ec Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-rule-pixel-aligned.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.argb32.ref.png new file mode 100644 index 0000000000..f32db7c363 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.base.argb32.ref.png new file mode 100644 index 0000000000..cb23ea61d0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.base.rgb24.ref.png new file mode 100644 index 0000000000..5265ddea96 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.image16.ref.png new file mode 100644 index 0000000000..101449d332 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.pdf.argb32.ref.png new file mode 100644 index 0000000000..d7e2f56e18 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.ps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.ps.argb32.ref.png new file mode 100644 index 0000000000..1b8943491c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.ps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.ps.rgb24.ref.png new file mode 100644 index 0000000000..1b061b7186 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.quartz.rgb24.ref.png new file mode 100644 index 0000000000..c95f290d80 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.rgb24.ref.png new file mode 100644 index 0000000000..a7acc4fa49 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.test-paginated.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.test-paginated.rgb24.ref.png new file mode 100644 index 0000000000..d21472dc58 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.test-paginated.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.traps.argb32.ref.png new file mode 100644 index 0000000000..6b083a7872 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.traps.rgb24.ref.png new file mode 100644 index 0000000000..d21472dc58 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill-rule.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill.base.argb32.ref.png new file mode 100644 index 0000000000..72dc2298a0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill.base.rgb24.ref.png new file mode 100644 index 0000000000..72dc2298a0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill.image16.ref.png new file mode 100644 index 0000000000..24595ba2ad Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill.mask.argb32.ref.png new file mode 100644 index 0000000000..c3f27003c8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill.mask.rgb24.ref.png new file mode 100644 index 0000000000..c3f27003c8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill.ps.ref.png new file mode 100644 index 0000000000..568d2f493c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill.quartz.ref.png new file mode 100644 index 0000000000..925131082e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill.ref.png new file mode 100644 index 0000000000..7f07857258 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill.traps.argb32.ref.png new file mode 100644 index 0000000000..d6e84a3ef4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill.traps.rgb24.ref.png new file mode 100644 index 0000000000..d6e84a3ef4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-fill.xlib-fallback.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-fill.xlib-fallback.ref.png new file mode 100644 index 0000000000..064b0cfb06 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-fill.xlib-fallback.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-aligned-rectangles.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-aligned-rectangles.base.argb32.ref.png new file mode 100644 index 0000000000..cba75078a1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-aligned-rectangles.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-aligned-rectangles.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-aligned-rectangles.base.rgb24.ref.png new file mode 100644 index 0000000000..cba75078a1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-aligned-rectangles.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-aligned-rectangles.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-aligned-rectangles.ps.ref.png new file mode 100644 index 0000000000..95a1a85f74 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-aligned-rectangles.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-aligned-rectangles.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-aligned-rectangles.ref.png new file mode 100644 index 0000000000..cba75078a1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-aligned-rectangles.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-circles.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-circles.base.argb32.ref.png new file mode 100644 index 0000000000..7dd6a83538 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-circles.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-circles.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-circles.base.rgb24.ref.png new file mode 100644 index 0000000000..7dd6a83538 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-circles.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-circles.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-circles.mask.argb32.ref.png new file mode 100644 index 0000000000..7dd6a83538 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-circles.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-circles.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-circles.mask.rgb24.ref.png new file mode 100644 index 0000000000..7dd6a83538 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-circles.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-circles.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-circles.ps.ref.png new file mode 100644 index 0000000000..be6203f25d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-circles.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-circles.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-circles.quartz.ref.png new file mode 100644 index 0000000000..97f70163a6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-circles.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-circles.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-circles.ref.png new file mode 100644 index 0000000000..abb11e52e0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-circles.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-circles.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-circles.traps.argb32.ref.png new file mode 100644 index 0000000000..3b8114691e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-circles.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-circles.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-circles.traps.rgb24.ref.png new file mode 100644 index 0000000000..3b8114691e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-circles.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-unaligned-rectangles.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-unaligned-rectangles.base.argb32.ref.png new file mode 100644 index 0000000000..2ad4118247 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-unaligned-rectangles.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-unaligned-rectangles.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-unaligned-rectangles.base.rgb24.ref.png new file mode 100644 index 0000000000..2ad4118247 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-unaligned-rectangles.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-unaligned-rectangles.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-unaligned-rectangles.mask.argb32.ref.png new file mode 100644 index 0000000000..877e78bd75 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-unaligned-rectangles.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-unaligned-rectangles.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-unaligned-rectangles.mask.rgb24.ref.png new file mode 100644 index 0000000000..877e78bd75 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-unaligned-rectangles.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-unaligned-rectangles.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-unaligned-rectangles.ref.png new file mode 100644 index 0000000000..2ad4118247 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-unaligned-rectangles.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-unaligned-rectangles.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-unaligned-rectangles.traps.argb32.ref.png new file mode 100644 index 0000000000..877e78bd75 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-unaligned-rectangles.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-unaligned-rectangles.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-unaligned-rectangles.traps.rgb24.ref.png new file mode 100644 index 0000000000..877e78bd75 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-group-shapes-unaligned-rectangles.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-image.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-image.base.argb32.ref.png new file mode 100644 index 0000000000..0f71f73607 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-image.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-image.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-image.base.rgb24.ref.png new file mode 100644 index 0000000000..0f71f73607 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-image.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-image.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-image.image16.ref.png new file mode 100644 index 0000000000..770891aab1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-image.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-image.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-image.mask.argb32.ref.png new file mode 100644 index 0000000000..86c28afd72 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-image.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-image.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-image.mask.rgb24.ref.png new file mode 100644 index 0000000000..86c28afd72 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-image.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-image.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-image.pdf.ref.png new file mode 100644 index 0000000000..8893e0f08c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-image.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-image.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-image.ps.ref.png new file mode 100644 index 0000000000..b2422495f4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-image.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-image.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-image.ref.png new file mode 100644 index 0000000000..0f71f73607 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-image.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-image.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-image.svg.ref.png new file mode 100644 index 0000000000..8893e0f08c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-image.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-image.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-image.traps.argb32.ref.png new file mode 100644 index 0000000000..062c721f51 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-image.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-image.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-image.traps.rgb24.ref.png new file mode 100644 index 0000000000..062c721f51 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-image.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-intersect.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-intersect.base.argb32.ref.png new file mode 100644 index 0000000000..6627b3a502 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-intersect.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-intersect.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-intersect.base.rgb24.ref.png new file mode 100644 index 0000000000..6627b3a502 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-intersect.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-intersect.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-intersect.ps.ref.png new file mode 100644 index 0000000000..d4df3861df Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-intersect.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-intersect.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-intersect.quartz.ref.png new file mode 100644 index 0000000000..1fefe271d0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-intersect.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-intersect.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-intersect.ref.png new file mode 100644 index 0000000000..5f2de37648 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-intersect.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-intersect.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-intersect.traps.argb32.ref.png new file mode 100644 index 0000000000..2e97b54140 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-intersect.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-intersect.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-intersect.traps.rgb24.ref.png new file mode 100644 index 0000000000..2e97b54140 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-intersect.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-mixed-antialias.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-mixed-antialias.base.argb32.ref.png new file mode 100644 index 0000000000..982530cb8a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-mixed-antialias.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-mixed-antialias.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-mixed-antialias.base.rgb24.ref.png new file mode 100644 index 0000000000..982530cb8a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-mixed-antialias.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-mixed-antialias.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-mixed-antialias.ref.png new file mode 100644 index 0000000000..243c4dde64 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-mixed-antialias.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-mixed-antialias.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-mixed-antialias.traps.argb32.ref.png new file mode 100644 index 0000000000..982530cb8a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-mixed-antialias.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-mixed-antialias.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-mixed-antialias.traps.rgb24.ref.png new file mode 100644 index 0000000000..982530cb8a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-mixed-antialias.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-nesting.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-nesting.argb32.ref.png new file mode 100644 index 0000000000..c82ed463b7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-nesting.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-nesting.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-nesting.base.argb32.ref.png new file mode 100644 index 0000000000..ce0cc0d089 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-nesting.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-nesting.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-nesting.base.rgb24.ref.png new file mode 100644 index 0000000000..5247843719 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-nesting.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-nesting.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-nesting.mask.rgb24.ref.png new file mode 100644 index 0000000000..5247843719 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-nesting.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-nesting.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-nesting.pdf.argb32.ref.png new file mode 100644 index 0000000000..78ae6e0809 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-nesting.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-nesting.ps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-nesting.ps.argb32.ref.png new file mode 100644 index 0000000000..8a0239be55 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-nesting.ps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-nesting.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-nesting.ps.rgb24.ref.png new file mode 100644 index 0000000000..f9e1ac9fcc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-nesting.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-nesting.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-nesting.quartz.argb32.ref.png new file mode 100644 index 0000000000..815d37a732 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-nesting.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-nesting.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-nesting.quartz.rgb24.ref.png new file mode 100644 index 0000000000..0953e0621f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-nesting.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-nesting.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-nesting.rgb24.ref.png new file mode 100644 index 0000000000..93c5b17132 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-nesting.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-nesting.test-paginated.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-nesting.test-paginated.rgb24.ref.png new file mode 100644 index 0000000000..d087ab6c14 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-nesting.test-paginated.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-nesting.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-nesting.traps.argb32.ref.png new file mode 100644 index 0000000000..01168dfe89 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-nesting.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-nesting.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-nesting.traps.rgb24.ref.png new file mode 100644 index 0000000000..d087ab6c14 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-nesting.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-operator.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-operator.argb32.ref.png new file mode 100644 index 0000000000..e27de20a4d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-operator.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-operator.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-operator.base.argb32.ref.png new file mode 100644 index 0000000000..f7697bafe6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-operator.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-operator.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-operator.base.rgb24.ref.png new file mode 100644 index 0000000000..eed34690e4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-operator.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-operator.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-operator.image16.ref.png new file mode 100644 index 0000000000..ab8cd9b899 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-operator.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-operator.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-operator.mask.argb32.ref.png new file mode 100644 index 0000000000..8db1a07c2c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-operator.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-operator.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-operator.mask.rgb24.ref.png new file mode 100644 index 0000000000..ddd1ec3768 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-operator.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-operator.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-operator.pdf.argb32.ref.png new file mode 100644 index 0000000000..48554f83a1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-operator.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-operator.ps2.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-operator.ps2.rgb24.ref.png new file mode 100644 index 0000000000..52452993ab Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-operator.ps2.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-operator.ps3.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-operator.ps3.argb32.ref.png new file mode 100644 index 0000000000..cd207d924c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-operator.ps3.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-operator.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-operator.ps3.ref.png new file mode 100644 index 0000000000..dee12ca8cf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-operator.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-operator.ps3.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-operator.ps3.rgb24.ref.png new file mode 100644 index 0000000000..52452993ab Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-operator.ps3.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-operator.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-operator.quartz.argb32.ref.png new file mode 100644 index 0000000000..142b212ccc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-operator.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-operator.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-operator.quartz.rgb24.ref.png new file mode 100644 index 0000000000..7b8fb6aae4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-operator.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-operator.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-operator.rgb24.ref.png new file mode 100644 index 0000000000..8d6a27d9e4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-operator.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-operator.test-paginated.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-operator.test-paginated.argb32.ref.png new file mode 100644 index 0000000000..0203b1db52 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-operator.test-paginated.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-operator.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-operator.traps.argb32.ref.png new file mode 100644 index 0000000000..76f9ee8dd3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-operator.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-operator.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-operator.traps.rgb24.ref.png new file mode 100644 index 0000000000..f35c9d5d9c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-operator.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-operator.xlib-fallback.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-operator.xlib-fallback.ref.png new file mode 100644 index 0000000000..9ef8637b60 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-operator.xlib-fallback.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-polygons.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-polygons.base.argb32.ref.png new file mode 100644 index 0000000000..e139ef3f55 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-polygons.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-polygons.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-polygons.base.rgb24.ref.png new file mode 100644 index 0000000000..e139ef3f55 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-polygons.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-polygons.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-polygons.mask.argb32.ref.png new file mode 100644 index 0000000000..e139ef3f55 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-polygons.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-polygons.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-polygons.mask.rgb24.ref.png new file mode 100644 index 0000000000..e139ef3f55 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-polygons.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-polygons.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/clip-polygons.quartz.xfail.png new file mode 100644 index 0000000000..11afe6318f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-polygons.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-polygons.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-polygons.ref.png new file mode 100644 index 0000000000..1b76cd071a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-polygons.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-polygons.traps.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-polygons.traps.ref.png new file mode 100644 index 0000000000..a8c5734bc2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-polygons.traps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-push-group.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-push-group.base.argb32.ref.png new file mode 100644 index 0000000000..86724a23b8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-push-group.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-push-group.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-push-group.base.rgb24.ref.png new file mode 100644 index 0000000000..86724a23b8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-push-group.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-push-group.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-push-group.image16.ref.png new file mode 100644 index 0000000000..24f4424fc4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-push-group.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-push-group.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-push-group.pdf.ref.png new file mode 100644 index 0000000000..d6640fe456 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-push-group.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-push-group.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-push-group.ps.ref.png new file mode 100644 index 0000000000..7af9fe5266 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-push-group.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-push-group.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-push-group.quartz.ref.png new file mode 100644 index 0000000000..22e15255d4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-push-group.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-push-group.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-push-group.ref.png new file mode 100644 index 0000000000..6a90fb433f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-push-group.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-push-group.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-push-group.svg.ref.png new file mode 100644 index 0000000000..d6640fe456 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-push-group.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-push-group.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-push-group.traps.argb32.ref.png new file mode 100644 index 0000000000..de6ac632cd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-push-group.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-push-group.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-push-group.traps.rgb24.ref.png new file mode 100644 index 0000000000..de6ac632cd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-push-group.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-rectilinear.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-rectilinear.base.argb32.ref.png new file mode 100644 index 0000000000..9d910db570 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-rectilinear.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-rectilinear.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-rectilinear.base.rgb24.ref.png new file mode 100644 index 0000000000..9d910db570 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-rectilinear.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-rectilinear.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-rectilinear.mask.argb32.ref.png new file mode 100644 index 0000000000..2a27beca33 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-rectilinear.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-rectilinear.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-rectilinear.mask.rgb24.ref.png new file mode 100644 index 0000000000..2a27beca33 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-rectilinear.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-rectilinear.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-rectilinear.ps.ref.png new file mode 100644 index 0000000000..575709ab71 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-rectilinear.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-rectilinear.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-rectilinear.ref.png new file mode 100644 index 0000000000..9d910db570 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-rectilinear.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-rectilinear.traps.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-rectilinear.traps.ref.png new file mode 100644 index 0000000000..2a27beca33 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-rectilinear.traps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-rotate-image-surface-paint.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-rotate-image-surface-paint.base.argb32.ref.png new file mode 100644 index 0000000000..1093804d75 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-rotate-image-surface-paint.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-rotate-image-surface-paint.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-rotate-image-surface-paint.base.rgb24.ref.png new file mode 100644 index 0000000000..1093804d75 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-rotate-image-surface-paint.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-rotate-image-surface-paint.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-rotate-image-surface-paint.pdf.argb32.ref.png new file mode 100644 index 0000000000..764a4759a9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-rotate-image-surface-paint.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-rotate-image-surface-paint.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-rotate-image-surface-paint.pdf.rgb24.ref.png new file mode 100644 index 0000000000..764a4759a9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-rotate-image-surface-paint.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-rotate-image-surface-paint.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-rotate-image-surface-paint.ps.ref.png new file mode 100644 index 0000000000..7a52887dc2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-rotate-image-surface-paint.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-rotate-image-surface-paint.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-rotate-image-surface-paint.quartz.ref.png new file mode 100644 index 0000000000..dc81695fa9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-rotate-image-surface-paint.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-rotate-image-surface-paint.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-rotate-image-surface-paint.ref.png new file mode 100644 index 0000000000..1093804d75 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-rotate-image-surface-paint.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-rotate-image-surface-paint.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-rotate-image-surface-paint.svg.ref.png new file mode 100644 index 0000000000..764a4759a9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-rotate-image-surface-paint.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-shape.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-shape.base.argb32.ref.png new file mode 100644 index 0000000000..5d79521a98 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-shape.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-shape.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-shape.base.rgb24.ref.png new file mode 100644 index 0000000000..5d79521a98 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-shape.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-shape.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-shape.image16.ref.png new file mode 100644 index 0000000000..0ef06b2388 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-shape.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-shape.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-shape.mask.argb32.ref.png new file mode 100644 index 0000000000..03edf68f0b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-shape.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-shape.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-shape.mask.rgb24.ref.png new file mode 100644 index 0000000000..03edf68f0b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-shape.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-shape.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-shape.ps.ref.png new file mode 100644 index 0000000000..1125fb5951 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-shape.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-shape.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-shape.quartz.ref.png new file mode 100644 index 0000000000..664597b3ee Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-shape.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-shape.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-shape.ref.png new file mode 100644 index 0000000000..83190e6167 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-shape.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-shape.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-shape.traps.argb32.ref.png new file mode 100644 index 0000000000..362f24f917 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-shape.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-shape.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-shape.traps.rgb24.ref.png new file mode 100644 index 0000000000..362f24f917 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-shape.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-shape.xlib-fallback.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-shape.xlib-fallback.ref.png new file mode 100644 index 0000000000..e9aa947706 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-shape.xlib-fallback.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-stroke-no-op.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-stroke-no-op.base.argb32.ref.png new file mode 100644 index 0000000000..2256461a98 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-stroke-no-op.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-stroke-no-op.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-stroke-no-op.base.rgb24.ref.png new file mode 100644 index 0000000000..2256461a98 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-stroke-no-op.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-stroke-no-op.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-stroke-no-op.image16.ref.png new file mode 100644 index 0000000000..cf0c74ad8f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-stroke-no-op.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-stroke-no-op.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-stroke-no-op.ps.ref.png new file mode 100644 index 0000000000..b51490deb9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-stroke-no-op.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-stroke-no-op.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-stroke-no-op.ref.png new file mode 100644 index 0000000000..2256461a98 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-stroke-no-op.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.argb32.ref.png new file mode 100644 index 0000000000..51bc7c47f9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.base.argb32.ref.png new file mode 100644 index 0000000000..de0d5892f6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.base.rgb24.ref.png new file mode 100644 index 0000000000..7d204ee141 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.image16.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.image16.rgb24.ref.png new file mode 100644 index 0000000000..2dfd48bac9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.image16.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.mask.argb32.ref.png new file mode 100644 index 0000000000..274feb6417 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.mask.rgb24.ref.png new file mode 100644 index 0000000000..a9a8f7be48 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.quartz.argb32.ref.png new file mode 100644 index 0000000000..51c156a280 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.quartz.rgb24.ref.png new file mode 100644 index 0000000000..5349f84941 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.rgb24.ref.png new file mode 100644 index 0000000000..c75ccbe2b3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.svg.ref.png new file mode 100644 index 0000000000..1297523edc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.traps.argb32.ref.png new file mode 100644 index 0000000000..aea8cba705 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.traps.rgb24.ref.png new file mode 100644 index 0000000000..70cddacfaa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.xlib-fallback.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.xlib-fallback.rgb24.ref.png new file mode 100644 index 0000000000..20ebfe443c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-stroke-unbounded.xlib-fallback.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-stroke.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-stroke.base.argb32.ref.png new file mode 100644 index 0000000000..31ed15e32c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-stroke.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-stroke.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-stroke.base.rgb24.ref.png new file mode 100644 index 0000000000..31ed15e32c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-stroke.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-stroke.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-stroke.image16.ref.png new file mode 100644 index 0000000000..ad62af4060 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-stroke.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-stroke.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-stroke.mask.argb32.ref.png new file mode 100644 index 0000000000..afa7fc0dcc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-stroke.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-stroke.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-stroke.mask.rgb24.ref.png new file mode 100644 index 0000000000..afa7fc0dcc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-stroke.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-stroke.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-stroke.ps.ref.png new file mode 100644 index 0000000000..c08f333b9d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-stroke.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-stroke.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-stroke.quartz.ref.png new file mode 100644 index 0000000000..994e317075 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-stroke.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-stroke.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-stroke.ref.png new file mode 100644 index 0000000000..c29680713e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-stroke.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-stroke.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-stroke.traps.argb32.ref.png new file mode 100644 index 0000000000..36b113adca Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-stroke.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-stroke.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-stroke.traps.rgb24.ref.png new file mode 100644 index 0000000000..36b113adca Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-stroke.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-stroke.xlib-fallback.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-stroke.xlib-fallback.ref.png new file mode 100644 index 0000000000..cef5000f5a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-stroke.xlib-fallback.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-text.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-text.base.argb32.ref.png new file mode 100644 index 0000000000..e2b2ca7014 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-text.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-text.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-text.base.rgb24.ref.png new file mode 100644 index 0000000000..e2b2ca7014 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-text.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-text.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-text.image16.ref.png new file mode 100644 index 0000000000..2122954115 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-text.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-text.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-text.mask.argb32.ref.png new file mode 100644 index 0000000000..98484cdd46 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-text.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-text.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-text.mask.rgb24.ref.png new file mode 100644 index 0000000000..98484cdd46 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-text.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-text.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-text.ps.ref.png new file mode 100644 index 0000000000..86c676912f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-text.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-text.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-text.quartz.ref.png new file mode 100644 index 0000000000..96df3934fa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-text.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-text.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-text.ref.png new file mode 100644 index 0000000000..8950caa58a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-text.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-text.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-text.traps.argb32.ref.png new file mode 100644 index 0000000000..2a682981ca Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-text.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-text.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-text.traps.rgb24.ref.png new file mode 100644 index 0000000000..2a682981ca Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-text.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-twice-rectangle.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-twice-rectangle.base.argb32.ref.png new file mode 100644 index 0000000000..d0e65ead3e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-twice-rectangle.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-twice-rectangle.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-twice-rectangle.base.rgb24.ref.png new file mode 100644 index 0000000000..d0e65ead3e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-twice-rectangle.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-twice-rectangle.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-twice-rectangle.ref.png new file mode 100644 index 0000000000..d0e65ead3e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-twice-rectangle.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-twice.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-twice.argb32.ref.png new file mode 100644 index 0000000000..03dc4a5bea Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-twice.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-twice.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-twice.base.argb32.ref.png new file mode 100644 index 0000000000..a3dcca4b4c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-twice.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-twice.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-twice.base.rgb24.ref.png new file mode 100644 index 0000000000..0c4aaba37f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-twice.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-twice.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-twice.image16.ref.png new file mode 100644 index 0000000000..d5a3f455aa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-twice.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-twice.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-twice.mask.argb32.ref.png new file mode 100644 index 0000000000..828dd23b70 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-twice.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-twice.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-twice.mask.rgb24.ref.png new file mode 100644 index 0000000000..8b6baed5e8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-twice.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-twice.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-twice.pdf.argb32.ref.png new file mode 100644 index 0000000000..2a7541fe28 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-twice.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-twice.ps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-twice.ps.argb32.ref.png new file mode 100644 index 0000000000..5d29d17f7c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-twice.ps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-twice.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-twice.ps.rgb24.ref.png new file mode 100644 index 0000000000..85eb890c53 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-twice.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-twice.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-twice.quartz.argb32.ref.png new file mode 100644 index 0000000000..04b588d801 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-twice.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-twice.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-twice.quartz.rgb24.ref.png new file mode 100644 index 0000000000..eb4f62c2f1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-twice.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-twice.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-twice.rgb24.ref.png new file mode 100644 index 0000000000..c25fffa571 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-twice.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-twice.test-paginated.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-twice.test-paginated.argb32.ref.png new file mode 100644 index 0000000000..ffd59aaf84 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-twice.test-paginated.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-twice.test-paginated.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-twice.test-paginated.rgb24.ref.png new file mode 100644 index 0000000000..e3d0ae49f4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-twice.test-paginated.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-twice.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-twice.traps.argb32.ref.png new file mode 100644 index 0000000000..057fc31f8b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-twice.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-twice.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-twice.traps.rgb24.ref.png new file mode 100644 index 0000000000..6002d34cac Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-twice.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-unbounded.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-unbounded.base.argb32.ref.png new file mode 100644 index 0000000000..0b65905650 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-unbounded.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-unbounded.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-unbounded.base.rgb24.ref.png new file mode 100644 index 0000000000..2baf9f4642 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-unbounded.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-unbounded.pdf.argb32.xfail.png b/local/recipes/libs/cairo/source/test/reference/clip-unbounded.pdf.argb32.xfail.png new file mode 100644 index 0000000000..1ed070cae0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-unbounded.pdf.argb32.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-unbounded.pdf.rgb24.xfail.png b/local/recipes/libs/cairo/source/test/reference/clip-unbounded.pdf.rgb24.xfail.png new file mode 100644 index 0000000000..1ed070cae0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-unbounded.pdf.rgb24.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-unbounded.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-unbounded.ref.png new file mode 100644 index 0000000000..0b65905650 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-unbounded.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-unbounded.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-unbounded.rgb24.ref.png new file mode 100644 index 0000000000..2baf9f4642 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-unbounded.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-xlib-fallback.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-xlib-fallback.rgb24.ref.png new file mode 100644 index 0000000000..062c721f51 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-xlib-fallback.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-xlib-window.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-xlib-window.rgb24.ref.png new file mode 100644 index 0000000000..062c721f51 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-xlib-window.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clip-xlib.ref.png b/local/recipes/libs/cairo/source/test/reference/clip-xlib.ref.png new file mode 100644 index 0000000000..062c721f51 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clip-xlib.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clipped-group.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clipped-group.base.argb32.ref.png new file mode 100644 index 0000000000..bea4c751e5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clipped-group.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clipped-group.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clipped-group.base.rgb24.ref.png new file mode 100644 index 0000000000..bea4c751e5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clipped-group.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clipped-group.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/clipped-group.image16.ref.png new file mode 100644 index 0000000000..bf419f6839 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clipped-group.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clipped-group.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clipped-group.mask.argb32.ref.png new file mode 100644 index 0000000000..53b149fc8a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clipped-group.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clipped-group.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clipped-group.mask.rgb24.ref.png new file mode 100644 index 0000000000..53b149fc8a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clipped-group.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clipped-group.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/clipped-group.pdf.ref.png new file mode 100644 index 0000000000..55217cacea Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clipped-group.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clipped-group.ps2.ref.png b/local/recipes/libs/cairo/source/test/reference/clipped-group.ps2.ref.png new file mode 100644 index 0000000000..7a0f45c168 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clipped-group.ps2.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clipped-group.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/clipped-group.ps3.ref.png new file mode 100644 index 0000000000..7a0f45c168 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clipped-group.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clipped-group.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/clipped-group.quartz.ref.png new file mode 100644 index 0000000000..10e22f7a1a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clipped-group.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clipped-group.ref.png b/local/recipes/libs/cairo/source/test/reference/clipped-group.ref.png new file mode 100644 index 0000000000..245b16e568 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clipped-group.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clipped-group.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/clipped-group.svg.ref.png new file mode 100644 index 0000000000..55217cacea Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clipped-group.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clipped-group.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clipped-group.traps.argb32.ref.png new file mode 100644 index 0000000000..b25c9f4db2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clipped-group.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clipped-group.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clipped-group.traps.rgb24.ref.png new file mode 100644 index 0000000000..b25c9f4db2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clipped-group.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clipped-group.xlib-fallback.ref.png b/local/recipes/libs/cairo/source/test/reference/clipped-group.xlib-fallback.ref.png new file mode 100644 index 0000000000..e0a5dc0977 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clipped-group.xlib-fallback.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clipped-surface.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/clipped-surface.base.argb32.ref.png new file mode 100644 index 0000000000..8e8b0083eb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clipped-surface.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clipped-surface.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/clipped-surface.base.rgb24.ref.png new file mode 100644 index 0000000000..8e8b0083eb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clipped-surface.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clipped-surface.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/clipped-surface.image16.ref.png new file mode 100644 index 0000000000..e9ad5723bb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clipped-surface.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clipped-surface.ref.png b/local/recipes/libs/cairo/source/test/reference/clipped-surface.ref.png new file mode 100644 index 0000000000..7fed5a3e08 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clipped-surface.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/clipped-trapezoids.ref.png b/local/recipes/libs/cairo/source/test/reference/clipped-trapezoids.ref.png new file mode 100644 index 0000000000..975a692d8b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/clipped-trapezoids.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/close-path-current-point.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/close-path-current-point.base.argb32.ref.png new file mode 100644 index 0000000000..373eb11765 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/close-path-current-point.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/close-path-current-point.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/close-path-current-point.base.rgb24.ref.png new file mode 100644 index 0000000000..373eb11765 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/close-path-current-point.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/close-path-current-point.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/close-path-current-point.image16.ref.png new file mode 100644 index 0000000000..6aacf3e1ba Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/close-path-current-point.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/close-path-current-point.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/close-path-current-point.mask.argb32.ref.png new file mode 100644 index 0000000000..ab3124b79b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/close-path-current-point.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/close-path-current-point.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/close-path-current-point.mask.rgb24.ref.png new file mode 100644 index 0000000000..ab3124b79b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/close-path-current-point.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/close-path-current-point.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/close-path-current-point.pdf.ref.png new file mode 100644 index 0000000000..a162638ce4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/close-path-current-point.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/close-path-current-point.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/close-path-current-point.ps.ref.png new file mode 100644 index 0000000000..1442f01f7e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/close-path-current-point.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/close-path-current-point.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/close-path-current-point.quartz.ref.png new file mode 100644 index 0000000000..cd21450d9c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/close-path-current-point.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/close-path-current-point.ref.png b/local/recipes/libs/cairo/source/test/reference/close-path-current-point.ref.png new file mode 100644 index 0000000000..3ae4900313 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/close-path-current-point.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/close-path-current-point.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/close-path-current-point.svg.ref.png new file mode 100644 index 0000000000..a162638ce4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/close-path-current-point.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/close-path-current-point.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/close-path-current-point.traps.argb32.ref.png new file mode 100644 index 0000000000..373eb11765 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/close-path-current-point.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/close-path-current-point.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/close-path-current-point.traps.rgb24.ref.png new file mode 100644 index 0000000000..373eb11765 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/close-path-current-point.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/close-path.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/close-path.base.argb32.ref.png new file mode 100644 index 0000000000..b53fab2526 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/close-path.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/close-path.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/close-path.base.rgb24.ref.png new file mode 100644 index 0000000000..b53fab2526 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/close-path.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/close-path.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/close-path.pdf.argb32.ref.png new file mode 100644 index 0000000000..e57654d27e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/close-path.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/close-path.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/close-path.pdf.rgb24.ref.png new file mode 100644 index 0000000000..e57654d27e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/close-path.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/close-path.ps2.ref.png b/local/recipes/libs/cairo/source/test/reference/close-path.ps2.ref.png new file mode 100644 index 0000000000..e43821c86a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/close-path.ps2.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/close-path.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/close-path.ps3.ref.png new file mode 100644 index 0000000000..e43821c86a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/close-path.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/close-path.ref.png b/local/recipes/libs/cairo/source/test/reference/close-path.ref.png new file mode 100644 index 0000000000..5506ff8bdb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/close-path.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/close-path.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/close-path.svg.ref.png new file mode 100644 index 0000000000..e57654d27e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/close-path.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/close-path.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/close-path.traps.argb32.ref.png new file mode 100644 index 0000000000..b53fab2526 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/close-path.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/close-path.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/close-path.traps.rgb24.ref.png new file mode 100644 index 0000000000..b53fab2526 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/close-path.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-over-repeat.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-over-repeat.base.argb32.ref.png new file mode 100644 index 0000000000..c425749882 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-over-repeat.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-over-repeat.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-over-repeat.base.rgb24.ref.png new file mode 100644 index 0000000000..c425749882 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-over-repeat.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-over-repeat.ps2.ref.png b/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-over-repeat.ps2.ref.png new file mode 100644 index 0000000000..f0e7b8401e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-over-repeat.ps2.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-over-repeat.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-over-repeat.ps3.ref.png new file mode 100644 index 0000000000..f0e7b8401e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-over-repeat.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-over-repeat.ref.png b/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-over-repeat.ref.png new file mode 100644 index 0000000000..c04db2631c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-over-repeat.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-over.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-over.base.argb32.ref.png new file mode 100644 index 0000000000..7ac3ddf4c3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-over.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-over.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-over.base.rgb24.ref.png new file mode 100644 index 0000000000..7ac3ddf4c3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-over.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-over.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-over.image16.ref.png new file mode 100644 index 0000000000..acb0917db5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-over.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-over.ps2.ref.png b/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-over.ps2.ref.png new file mode 100644 index 0000000000..8c8cc0de0e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-over.ps2.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-over.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-over.ps3.ref.png new file mode 100644 index 0000000000..8c8cc0de0e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-over.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-over.ref.png b/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-over.ref.png new file mode 100644 index 0000000000..630d99351f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-over.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-source.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-source.base.argb32.ref.png new file mode 100644 index 0000000000..7ac3ddf4c3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-source.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-source.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-source.base.rgb24.ref.png new file mode 100644 index 0000000000..7ac3ddf4c3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-source.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-source.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-source.image16.ref.png new file mode 100644 index 0000000000..acb0917db5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-source.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-source.ps2.ref.png b/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-source.ps2.ref.png new file mode 100644 index 0000000000..8c8cc0de0e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-source.ps2.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-source.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-source.ps3.ref.png new file mode 100644 index 0000000000..8c8cc0de0e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-source.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-source.ref.png b/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-source.ref.png new file mode 100644 index 0000000000..da9a3986af Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/composite-integer-translate-source.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/copy-disjoint.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/copy-disjoint.base.argb32.ref.png new file mode 100644 index 0000000000..da9a3b1128 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/copy-disjoint.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/copy-disjoint.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/copy-disjoint.base.rgb24.ref.png new file mode 100644 index 0000000000..da9a3b1128 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/copy-disjoint.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/copy-disjoint.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/copy-disjoint.ps.ref.png new file mode 100644 index 0000000000..3af8905877 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/copy-disjoint.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/copy-disjoint.ref.png b/local/recipes/libs/cairo/source/test/reference/copy-disjoint.ref.png new file mode 100644 index 0000000000..da9a3b1128 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/copy-disjoint.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/copy-path.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/copy-path.base.argb32.ref.png new file mode 100644 index 0000000000..6ca6f48e63 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/copy-path.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/copy-path.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/copy-path.base.rgb24.ref.png new file mode 100644 index 0000000000..6ca6f48e63 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/copy-path.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/copy-path.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/copy-path.image16.ref.png new file mode 100644 index 0000000000..1b3cabc634 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/copy-path.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/copy-path.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/copy-path.pdf.ref.png new file mode 100644 index 0000000000..01673eeb53 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/copy-path.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/copy-path.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/copy-path.ps.ref.png new file mode 100644 index 0000000000..41423a09aa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/copy-path.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/copy-path.ref.png b/local/recipes/libs/cairo/source/test/reference/copy-path.ref.png new file mode 100644 index 0000000000..b50e9e47bf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/copy-path.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/copy-path.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/copy-path.svg.ref.png new file mode 100644 index 0000000000..01673eeb53 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/copy-path.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/copy-path.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/copy-path.traps.argb32.ref.png new file mode 100644 index 0000000000..6ca6f48e63 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/copy-path.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/copy-path.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/copy-path.traps.rgb24.ref.png new file mode 100644 index 0000000000..6ca6f48e63 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/copy-path.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/coverage-abutting.ref.png b/local/recipes/libs/cairo/source/test/reference/coverage-abutting.ref.png new file mode 100644 index 0000000000..8e37ca3130 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/coverage-abutting.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/coverage-column-triangles.ref.png b/local/recipes/libs/cairo/source/test/reference/coverage-column-triangles.ref.png new file mode 100644 index 0000000000..24ccc9f2a4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/coverage-column-triangles.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/coverage-column-triangles.xfail.png b/local/recipes/libs/cairo/source/test/reference/coverage-column-triangles.xfail.png new file mode 100644 index 0000000000..9af5253c5a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/coverage-column-triangles.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/coverage-column-triangles.xlib.xfail.png b/local/recipes/libs/cairo/source/test/reference/coverage-column-triangles.xlib.xfail.png new file mode 100644 index 0000000000..18e4af2dae Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/coverage-column-triangles.xlib.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/coverage-intersecting-quads.ref.png b/local/recipes/libs/cairo/source/test/reference/coverage-intersecting-quads.ref.png new file mode 100644 index 0000000000..f56cb55700 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/coverage-intersecting-quads.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/coverage-intersecting-quads.xlib.xfail.png b/local/recipes/libs/cairo/source/test/reference/coverage-intersecting-quads.xlib.xfail.png new file mode 100644 index 0000000000..9e8806b9d7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/coverage-intersecting-quads.xlib.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/coverage-intersecting-triangles.image.xfail.png b/local/recipes/libs/cairo/source/test/reference/coverage-intersecting-triangles.image.xfail.png new file mode 100644 index 0000000000..f67ccd5001 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/coverage-intersecting-triangles.image.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/coverage-intersecting-triangles.ref.png b/local/recipes/libs/cairo/source/test/reference/coverage-intersecting-triangles.ref.png new file mode 100644 index 0000000000..adf93dbd56 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/coverage-intersecting-triangles.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/coverage-intersecting-triangles.xlib.xfail.png b/local/recipes/libs/cairo/source/test/reference/coverage-intersecting-triangles.xlib.xfail.png new file mode 100644 index 0000000000..cf492c541d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/coverage-intersecting-triangles.xlib.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/coverage-rectangles.ref.png b/local/recipes/libs/cairo/source/test/reference/coverage-rectangles.ref.png new file mode 100644 index 0000000000..cc1d31cf88 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/coverage-rectangles.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/coverage-rectangles.xlib.xfail.png b/local/recipes/libs/cairo/source/test/reference/coverage-rectangles.xlib.xfail.png new file mode 100644 index 0000000000..4ad7ec5d22 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/coverage-rectangles.xlib.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/coverage-rhombus.ref.png b/local/recipes/libs/cairo/source/test/reference/coverage-rhombus.ref.png new file mode 100644 index 0000000000..3d3c031cf2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/coverage-rhombus.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/coverage-rhombus.xfail.png b/local/recipes/libs/cairo/source/test/reference/coverage-rhombus.xfail.png new file mode 100644 index 0000000000..cbfc10afae Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/coverage-rhombus.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/coverage-row-triangles.ref.png b/local/recipes/libs/cairo/source/test/reference/coverage-row-triangles.ref.png new file mode 100644 index 0000000000..aa61031b72 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/coverage-row-triangles.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/coverage-row-triangles.xfail.png b/local/recipes/libs/cairo/source/test/reference/coverage-row-triangles.xfail.png new file mode 100644 index 0000000000..d451ba96aa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/coverage-row-triangles.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/coverage-row-triangles.xlib.xfail.png b/local/recipes/libs/cairo/source/test/reference/coverage-row-triangles.xlib.xfail.png new file mode 100644 index 0000000000..c55db811f2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/coverage-row-triangles.xlib.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/coverage-triangles.image.ref.png b/local/recipes/libs/cairo/source/test/reference/coverage-triangles.image.ref.png new file mode 100644 index 0000000000..2094a6ddaf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/coverage-triangles.image.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/coverage-triangles.recording.ref.png b/local/recipes/libs/cairo/source/test/reference/coverage-triangles.recording.ref.png new file mode 100644 index 0000000000..2094a6ddaf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/coverage-triangles.recording.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/coverage-triangles.ref.png b/local/recipes/libs/cairo/source/test/reference/coverage-triangles.ref.png new file mode 100644 index 0000000000..f56cb55700 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/coverage-triangles.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/coverage-triangles.script.ref.png b/local/recipes/libs/cairo/source/test/reference/coverage-triangles.script.ref.png new file mode 100644 index 0000000000..2094a6ddaf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/coverage-triangles.script.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/coverage-triangles.xcb-fallback.rgb24.xfail.png b/local/recipes/libs/cairo/source/test/reference/coverage-triangles.xcb-fallback.rgb24.xfail.png new file mode 100644 index 0000000000..2094a6ddaf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/coverage-triangles.xcb-fallback.rgb24.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/coverage-triangles.xcb-render-0_0.xfail.png b/local/recipes/libs/cairo/source/test/reference/coverage-triangles.xcb-render-0_0.xfail.png new file mode 100644 index 0000000000..2094a6ddaf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/coverage-triangles.xcb-render-0_0.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/coverage-triangles.xlib-render-0_0.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/coverage-triangles.xlib-render-0_0.rgb24.ref.png new file mode 100644 index 0000000000..2094a6ddaf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/coverage-triangles.xlib-render-0_0.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/coverage-triangles.xlib-render.rgb24.xfail.png b/local/recipes/libs/cairo/source/test/reference/coverage-triangles.xlib-render.rgb24.xfail.png new file mode 100644 index 0000000000..2094a6ddaf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/coverage-triangles.xlib-render.rgb24.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/coverage-triangles.xlib.xfail.png b/local/recipes/libs/cairo/source/test/reference/coverage-triangles.xlib.xfail.png new file mode 100644 index 0000000000..aad0034349 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/coverage-triangles.xlib.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/create-from-png-16bit.base.png b/local/recipes/libs/cairo/source/test/reference/create-from-png-16bit.base.png new file mode 100644 index 0000000000..7e0f00e338 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/create-from-png-16bit.base.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/create-from-png-16bit.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/create-from-png-16bit.image16.ref.png new file mode 100644 index 0000000000..9591a12dd4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/create-from-png-16bit.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/create-from-png-16bit.ref.png b/local/recipes/libs/cairo/source/test/reference/create-from-png-16bit.ref.png new file mode 100644 index 0000000000..296c559bca Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/create-from-png-16bit.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/create-from-png-stream.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/create-from-png-stream.base.argb32.ref.png new file mode 100644 index 0000000000..0a145d918a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/create-from-png-stream.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/create-from-png-stream.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/create-from-png-stream.base.rgb24.ref.png new file mode 100644 index 0000000000..0a145d918a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/create-from-png-stream.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/create-from-png-stream.ref.png b/local/recipes/libs/cairo/source/test/reference/create-from-png-stream.ref.png new file mode 100644 index 0000000000..765adc4a48 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/create-from-png-stream.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/create-from-png.alpha.ref.png b/local/recipes/libs/cairo/source/test/reference/create-from-png.alpha.ref.png new file mode 100644 index 0000000000..a5175a1eb0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/create-from-png.alpha.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/create-from-png.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/create-from-png.base.argb32.ref.png new file mode 100644 index 0000000000..0a145d918a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/create-from-png.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/create-from-png.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/create-from-png.base.rgb24.ref.png new file mode 100644 index 0000000000..0a145d918a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/create-from-png.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/create-from-png.gray-alpha.ref.png b/local/recipes/libs/cairo/source/test/reference/create-from-png.gray-alpha.ref.png new file mode 100644 index 0000000000..f5d47dc4ba Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/create-from-png.gray-alpha.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/create-from-png.gray.ref.png b/local/recipes/libs/cairo/source/test/reference/create-from-png.gray.ref.png new file mode 100644 index 0000000000..12dc90bc37 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/create-from-png.gray.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/create-from-png.indexed-alpha.ref.png b/local/recipes/libs/cairo/source/test/reference/create-from-png.indexed-alpha.ref.png new file mode 100644 index 0000000000..9f32c6986b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/create-from-png.indexed-alpha.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/create-from-png.indexed.ref.png b/local/recipes/libs/cairo/source/test/reference/create-from-png.indexed.ref.png new file mode 100644 index 0000000000..6b1d713163 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/create-from-png.indexed.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/create-from-png.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/create-from-png.mask.argb32.ref.png new file mode 100644 index 0000000000..0a145d918a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/create-from-png.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/create-from-png.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/create-from-png.mask.rgb24.ref.png new file mode 100644 index 0000000000..0a145d918a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/create-from-png.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/create-from-png.ref.png b/local/recipes/libs/cairo/source/test/reference/create-from-png.ref.png new file mode 100644 index 0000000000..0a145d918a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/create-from-png.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/create-from-png.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/create-from-png.traps.argb32.ref.png new file mode 100644 index 0000000000..0a145d918a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/create-from-png.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/create-from-png.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/create-from-png.traps.rgb24.ref.png new file mode 100644 index 0000000000..0a145d918a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/create-from-png.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/create-regions.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/create-regions.pdf.ref.png new file mode 100644 index 0000000000..5762fbbc73 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/create-regions.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/create-regions.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/create-regions.ps.ref.png new file mode 100644 index 0000000000..0478e249d9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/create-regions.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/create-regions.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/create-regions.svg.ref.png new file mode 100644 index 0000000000..a89dfb0446 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/create-regions.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/culled-glyphs.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/culled-glyphs.base.argb32.ref.png new file mode 100644 index 0000000000..6701295be9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/culled-glyphs.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/culled-glyphs.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/culled-glyphs.base.rgb24.ref.png new file mode 100644 index 0000000000..6701295be9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/culled-glyphs.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/culled-glyphs.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/culled-glyphs.image16.ref.png new file mode 100644 index 0000000000..724cb8ff9f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/culled-glyphs.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/culled-glyphs.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/culled-glyphs.ps.ref.png new file mode 100644 index 0000000000..85daafa2ee Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/culled-glyphs.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/culled-glyphs.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/culled-glyphs.quartz.ref.png new file mode 100644 index 0000000000..4da2a6c278 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/culled-glyphs.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/culled-glyphs.ref.png b/local/recipes/libs/cairo/source/test/reference/culled-glyphs.ref.png new file mode 100644 index 0000000000..6701295be9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/culled-glyphs.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/curve-to-as-line-to.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/curve-to-as-line-to.base.argb32.ref.png new file mode 100644 index 0000000000..15589db2e9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/curve-to-as-line-to.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/curve-to-as-line-to.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/curve-to-as-line-to.base.rgb24.ref.png new file mode 100644 index 0000000000..15589db2e9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/curve-to-as-line-to.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/curve-to-as-line-to.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/curve-to-as-line-to.mask.argb32.ref.png new file mode 100644 index 0000000000..d2411832ee Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/curve-to-as-line-to.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/curve-to-as-line-to.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/curve-to-as-line-to.mask.rgb24.ref.png new file mode 100644 index 0000000000..d2411832ee Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/curve-to-as-line-to.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/curve-to-as-line-to.ps.xfail.png b/local/recipes/libs/cairo/source/test/reference/curve-to-as-line-to.ps.xfail.png new file mode 100644 index 0000000000..3f31058e33 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/curve-to-as-line-to.ps.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/curve-to-as-line-to.ref.png b/local/recipes/libs/cairo/source/test/reference/curve-to-as-line-to.ref.png new file mode 100644 index 0000000000..15589db2e9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/curve-to-as-line-to.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/curve-to-as-line-to.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/curve-to-as-line-to.traps.argb32.ref.png new file mode 100644 index 0000000000..15589db2e9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/curve-to-as-line-to.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/curve-to-as-line-to.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/curve-to-as-line-to.traps.rgb24.ref.png new file mode 100644 index 0000000000..15589db2e9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/curve-to-as-line-to.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.base.argb32.ref.png new file mode 100644 index 0000000000..b85b03360b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.base.rgb24.ref.png new file mode 100644 index 0000000000..b85b03360b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.image16.ref.png new file mode 100644 index 0000000000..1f8d04877e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.mask.argb32.ref.png new file mode 100644 index 0000000000..b09b86fcec Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.mask.rgb24.ref.png new file mode 100644 index 0000000000..b09b86fcec Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.pdf.ref.png new file mode 100644 index 0000000000..55a8c87eff Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.ps.ref.png new file mode 100644 index 0000000000..9cfdb19db3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.quartz.xfail.png new file mode 100644 index 0000000000..cd9fe93ba2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.ref.png new file mode 100644 index 0000000000..0600125bf0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.svg.ref.png new file mode 100644 index 0000000000..55a8c87eff Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.traps.argb32.ref.png new file mode 100644 index 0000000000..b85b03360b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.traps.rgb24.ref.png new file mode 100644 index 0000000000..b85b03360b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-caps-joins.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-curve.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-curve.image16.ref.png new file mode 100644 index 0000000000..d89cedace2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-curve.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-curve.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-curve.mask.argb32.ref.png new file mode 100644 index 0000000000..8bebde204a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-curve.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-curve.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-curve.mask.rgb24.ref.png new file mode 100644 index 0000000000..8bebde204a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-curve.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-curve.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-curve.pdf.ref.png new file mode 100644 index 0000000000..ef4e76b39e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-curve.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-curve.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-curve.ps.ref.png new file mode 100644 index 0000000000..b4e6d1c9a4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-curve.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-curve.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/dash-curve.quartz.xfail.png new file mode 100644 index 0000000000..52da627a79 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-curve.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-curve.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-curve.ref.png new file mode 100644 index 0000000000..8eefce2f9a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-curve.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-curve.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-curve.svg.ref.png new file mode 100644 index 0000000000..ef4e76b39e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-curve.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-curve.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-curve.traps.argb32.ref.png new file mode 100644 index 0000000000..a29f43dc6f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-curve.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-curve.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-curve.traps.rgb24.ref.png new file mode 100644 index 0000000000..a29f43dc6f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-curve.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-infinite-loop.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-infinite-loop.base.argb32.ref.png new file mode 100644 index 0000000000..c0cc7391e8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-infinite-loop.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-infinite-loop.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-infinite-loop.base.rgb24.ref.png new file mode 100644 index 0000000000..c0cc7391e8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-infinite-loop.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-infinite-loop.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-infinite-loop.pdf.ref.png new file mode 100644 index 0000000000..e329b68269 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-infinite-loop.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-infinite-loop.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-infinite-loop.ps.ref.png new file mode 100644 index 0000000000..bab313a738 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-infinite-loop.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-infinite-loop.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-infinite-loop.ref.png new file mode 100644 index 0000000000..2ae1717a1c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-infinite-loop.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-infinite-loop.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-infinite-loop.svg.ref.png new file mode 100644 index 0000000000..e329b68269 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-infinite-loop.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-infinite-loop.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-infinite-loop.traps.argb32.ref.png new file mode 100644 index 0000000000..c0cc7391e8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-infinite-loop.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-infinite-loop.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-infinite-loop.traps.rgb24.ref.png new file mode 100644 index 0000000000..c0cc7391e8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-infinite-loop.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-no-dash.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-no-dash.base.argb32.ref.png new file mode 100644 index 0000000000..c150a4f022 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-no-dash.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-no-dash.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-no-dash.base.rgb24.ref.png new file mode 100644 index 0000000000..c150a4f022 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-no-dash.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-no-dash.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-no-dash.ref.png new file mode 100644 index 0000000000..9afd045db0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-no-dash.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-offset-negative.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-offset-negative.base.argb32.ref.png new file mode 100644 index 0000000000..77b9291649 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-offset-negative.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-offset-negative.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-offset-negative.base.rgb24.ref.png new file mode 100644 index 0000000000..77b9291649 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-offset-negative.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-offset-negative.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-offset-negative.ref.png new file mode 100644 index 0000000000..df22d08b2a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-offset-negative.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-offset-negative.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-offset-negative.traps.argb32.ref.png new file mode 100644 index 0000000000..77b9291649 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-offset-negative.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-offset-negative.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-offset-negative.traps.rgb24.ref.png new file mode 100644 index 0000000000..77b9291649 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-offset-negative.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-offset.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-offset.base.argb32.ref.png new file mode 100644 index 0000000000..52600c435d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-offset.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-offset.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-offset.base.rgb24.ref.png new file mode 100644 index 0000000000..52600c435d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-offset.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-offset.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-offset.ref.png new file mode 100644 index 0000000000..52600c435d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-offset.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-scale.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-scale.image16.ref.png new file mode 100644 index 0000000000..2b4fca5607 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-scale.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-scale.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-scale.mask.argb32.ref.png new file mode 100644 index 0000000000..deef9dcd2f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-scale.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-scale.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-scale.mask.rgb24.ref.png new file mode 100644 index 0000000000..deef9dcd2f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-scale.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-scale.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-scale.pdf.ref.png new file mode 100644 index 0000000000..335551fa7f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-scale.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-scale.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-scale.ps.ref.png new file mode 100644 index 0000000000..f8c25277c4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-scale.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-scale.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/dash-scale.quartz.xfail.png new file mode 100644 index 0000000000..5a62c1cde5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-scale.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-scale.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-scale.ref.png new file mode 100644 index 0000000000..a169364fd4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-scale.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-scale.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-scale.svg.ref.png new file mode 100644 index 0000000000..335551fa7f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-scale.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-scale.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-scale.traps.argb32.ref.png new file mode 100644 index 0000000000..c87cad468a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-scale.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-scale.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-scale.traps.rgb24.ref.png new file mode 100644 index 0000000000..c87cad468a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-scale.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-state.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-state.base.argb32.ref.png new file mode 100644 index 0000000000..53341102b1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-state.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-state.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-state.base.rgb24.ref.png new file mode 100644 index 0000000000..53341102b1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-state.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-state.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-state.image16.ref.png new file mode 100644 index 0000000000..07c77daccc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-state.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-state.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-state.pdf.ref.png new file mode 100644 index 0000000000..42db6e4c03 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-state.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-state.ps2.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-state.ps2.ref.png new file mode 100644 index 0000000000..88e208c58a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-state.ps2.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-state.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-state.ps3.ref.png new file mode 100644 index 0000000000..88e208c58a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-state.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-state.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/dash-state.quartz.xfail.png new file mode 100644 index 0000000000..ef38975ca7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-state.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-state.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-state.ref.png new file mode 100644 index 0000000000..31551cfeec Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-state.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-state.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-state.svg.ref.png new file mode 100644 index 0000000000..42db6e4c03 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-state.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-state.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-state.traps.argb32.ref.png new file mode 100644 index 0000000000..53341102b1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-state.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-state.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-state.traps.rgb24.ref.png new file mode 100644 index 0000000000..53341102b1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-state.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-zero-length.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-zero-length.base.argb32.ref.png new file mode 100644 index 0000000000..367fe3c91a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-zero-length.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-zero-length.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-zero-length.base.rgb24.ref.png new file mode 100644 index 0000000000..9bd4e93b19 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-zero-length.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-zero-length.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-zero-length.mask.rgb24.ref.png new file mode 100644 index 0000000000..b14bd8dca5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-zero-length.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-zero-length.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-zero-length.pdf.argb32.ref.png new file mode 100644 index 0000000000..082eb00142 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-zero-length.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-zero-length.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-zero-length.pdf.rgb24.ref.png new file mode 100644 index 0000000000..8dcfa54643 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-zero-length.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-zero-length.ps2.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-zero-length.ps2.ref.png new file mode 100644 index 0000000000..68fd3fb2e4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-zero-length.ps2.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-zero-length.ps2.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-zero-length.ps2.rgb24.ref.png new file mode 100644 index 0000000000..8a4a40fd4f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-zero-length.ps2.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-zero-length.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-zero-length.ps3.ref.png new file mode 100644 index 0000000000..68fd3fb2e4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-zero-length.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-zero-length.ps3.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-zero-length.ps3.rgb24.ref.png new file mode 100644 index 0000000000..8a4a40fd4f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-zero-length.ps3.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-zero-length.quartz.argb32.xfail.png b/local/recipes/libs/cairo/source/test/reference/dash-zero-length.quartz.argb32.xfail.png new file mode 100644 index 0000000000..57b9260390 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-zero-length.quartz.argb32.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-zero-length.quartz.rgb24.xfail.png b/local/recipes/libs/cairo/source/test/reference/dash-zero-length.quartz.rgb24.xfail.png new file mode 100644 index 0000000000..68802c584c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-zero-length.quartz.rgb24.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-zero-length.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-zero-length.ref.png new file mode 100644 index 0000000000..fdc5f5ef22 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-zero-length.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-zero-length.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-zero-length.svg.ref.png new file mode 100644 index 0000000000..ffe19affef Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-zero-length.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-zero-length.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-zero-length.traps.argb32.ref.png new file mode 100644 index 0000000000..367fe3c91a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-zero-length.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dash-zero-length.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/dash-zero-length.traps.rgb24.ref.png new file mode 100644 index 0000000000..9bd4e93b19 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dash-zero-length.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-arc.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-arc.base.argb32.ref.png new file mode 100644 index 0000000000..9cf3b0793e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-arc.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-arc.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-arc.base.rgb24.ref.png new file mode 100644 index 0000000000..9cf3b0793e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-arc.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-arc.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-arc.image16.ref.png new file mode 100644 index 0000000000..690e4a4def Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-arc.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-arc.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-arc.mask.argb32.ref.png new file mode 100644 index 0000000000..4da4fd6e4e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-arc.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-arc.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-arc.mask.rgb24.ref.png new file mode 100644 index 0000000000..4da4fd6e4e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-arc.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-arc.ps2.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-arc.ps2.ref.png new file mode 100644 index 0000000000..f6d913460d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-arc.ps2.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-arc.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-arc.ps3.ref.png new file mode 100644 index 0000000000..f6d913460d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-arc.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-arc.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-arc.quartz.ref.png new file mode 100644 index 0000000000..a43f6c9fde Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-arc.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-arc.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-arc.ref.png new file mode 100644 index 0000000000..3242ca4e8e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-arc.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-arc.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-arc.traps.argb32.ref.png new file mode 100644 index 0000000000..9cf3b0793e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-arc.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-arc.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-arc.traps.rgb24.ref.png new file mode 100644 index 0000000000..9cf3b0793e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-arc.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-arcs.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-arcs.base.argb32.ref.png new file mode 100644 index 0000000000..fc1869dc15 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-arcs.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-arcs.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-arcs.base.rgb24.ref.png new file mode 100644 index 0000000000..fc1869dc15 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-arcs.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-arcs.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-arcs.image16.ref.png new file mode 100644 index 0000000000..595cb7b93a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-arcs.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-arcs.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-arcs.ref.png new file mode 100644 index 0000000000..fc1869dc15 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-arcs.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-arcs.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-arcs.svg.ref.png new file mode 100644 index 0000000000..d581ac17bd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-arcs.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.base.argb32.ref.png new file mode 100644 index 0000000000..b676a1a24e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.base.rgb24.ref.png new file mode 100644 index 0000000000..b676a1a24e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.image16.ref.png new file mode 100644 index 0000000000..8036d0f8ca Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.mask.argb32.ref.png new file mode 100644 index 0000000000..18ab11ecee Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.mask.rgb24.ref.png new file mode 100644 index 0000000000..18ab11ecee Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.pdf.ref.png new file mode 100644 index 0000000000..1a1b7e49b8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.ps.xfail.png b/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.ps.xfail.png new file mode 100644 index 0000000000..1c07965fd9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.ps.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.quartz.ref.png new file mode 100644 index 0000000000..04483436e6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.ref.png new file mode 100644 index 0000000000..f3fde87019 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.svg.ref.png new file mode 100644 index 0000000000..1a1b7e49b8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.traps.argb32.ref.png new file mode 100644 index 0000000000..b676a1a24e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.traps.rgb24.ref.png new file mode 100644 index 0000000000..b676a1a24e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-curve-to.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-dash.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-dash.base.argb32.ref.png new file mode 100644 index 0000000000..ab8573a1af Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-dash.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-dash.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-dash.base.rgb24.ref.png new file mode 100644 index 0000000000..ab8573a1af Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-dash.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-dash.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-dash.mask.argb32.ref.png new file mode 100644 index 0000000000..2ddfc8bbfd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-dash.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-dash.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-dash.mask.rgb24.ref.png new file mode 100644 index 0000000000..2ddfc8bbfd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-dash.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-dash.ps.xfail.png b/local/recipes/libs/cairo/source/test/reference/degenerate-dash.ps.xfail.png new file mode 100644 index 0000000000..d5f8884aa3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-dash.ps.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-dash.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/degenerate-dash.quartz.xfail.png new file mode 100644 index 0000000000..594437cca9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-dash.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-dash.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-dash.ref.png new file mode 100644 index 0000000000..e8635f1e00 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-dash.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-dash.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-dash.traps.argb32.ref.png new file mode 100644 index 0000000000..ab8573a1af Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-dash.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-dash.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-dash.traps.rgb24.ref.png new file mode 100644 index 0000000000..ab8573a1af Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-dash.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-linear-gradient.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-linear-gradient.base.argb32.ref.png new file mode 100644 index 0000000000..ceed48a722 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-linear-gradient.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-linear-gradient.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-linear-gradient.base.rgb24.ref.png new file mode 100644 index 0000000000..ceed48a722 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-linear-gradient.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-linear-gradient.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-linear-gradient.pdf.ref.png new file mode 100644 index 0000000000..faeff6cd9d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-linear-gradient.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-linear-gradient.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-linear-gradient.ref.png new file mode 100644 index 0000000000..ceed48a722 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-linear-gradient.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-linear-gradient.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-linear-gradient.svg.ref.png new file mode 100644 index 0000000000..06f18b03fb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-linear-gradient.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-path.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-path.base.argb32.ref.png new file mode 100644 index 0000000000..b0fef0e01a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-path.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-path.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-path.base.rgb24.ref.png new file mode 100644 index 0000000000..33a8ac0b8c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-path.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-path.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-path.mask.argb32.ref.png new file mode 100644 index 0000000000..0459397194 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-path.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-path.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-path.mask.rgb24.ref.png new file mode 100644 index 0000000000..07fda634a0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-path.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-path.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-path.pdf.argb32.ref.png new file mode 100644 index 0000000000..c9dd809128 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-path.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-path.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-path.pdf.rgb24.ref.png new file mode 100644 index 0000000000..65d5a532e6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-path.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-path.ps.argb32.xfail.png b/local/recipes/libs/cairo/source/test/reference/degenerate-path.ps.argb32.xfail.png new file mode 100644 index 0000000000..33d713cbd4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-path.ps.argb32.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-path.ps.rgb24.xfail.png b/local/recipes/libs/cairo/source/test/reference/degenerate-path.ps.rgb24.xfail.png new file mode 100644 index 0000000000..e73f3149be Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-path.ps.rgb24.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-path.quartz.argb32.xfail.png b/local/recipes/libs/cairo/source/test/reference/degenerate-path.quartz.argb32.xfail.png new file mode 100644 index 0000000000..302da45798 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-path.quartz.argb32.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-path.quartz.rgb24.xfail.png b/local/recipes/libs/cairo/source/test/reference/degenerate-path.quartz.rgb24.xfail.png new file mode 100644 index 0000000000..45e5df9d80 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-path.quartz.rgb24.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-path.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-path.ref.png new file mode 100644 index 0000000000..f3dafe6521 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-path.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-path.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-path.svg.ref.png new file mode 100644 index 0000000000..723d0bc3f7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-path.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-path.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-path.traps.argb32.ref.png new file mode 100644 index 0000000000..b0fef0e01a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-path.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-path.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-path.traps.rgb24.ref.png new file mode 100644 index 0000000000..33a8ac0b8c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-path.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-pen.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-pen.base.argb32.ref.png new file mode 100644 index 0000000000..103b8586ab Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-pen.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-pen.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-pen.base.rgb24.ref.png new file mode 100644 index 0000000000..103b8586ab Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-pen.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-pen.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-pen.image16.ref.png new file mode 100644 index 0000000000..55011270b6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-pen.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-pen.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-pen.pdf.argb32.ref.png new file mode 100644 index 0000000000..24e9a4f32d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-pen.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-pen.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-pen.pdf.rgb24.ref.png new file mode 100644 index 0000000000..24e9a4f32d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-pen.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-pen.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-pen.ps.ref.png new file mode 100644 index 0000000000..34d173b7d4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-pen.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-pen.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-pen.ref.png new file mode 100644 index 0000000000..ea65d22755 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-pen.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-pen.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-pen.svg.ref.png new file mode 100644 index 0000000000..24e9a4f32d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-pen.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-pen.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-pen.traps.argb32.ref.png new file mode 100644 index 0000000000..103b8586ab Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-pen.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-pen.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-pen.traps.rgb24.ref.png new file mode 100644 index 0000000000..103b8586ab Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-pen.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-radial-gradient.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-radial-gradient.base.argb32.ref.png new file mode 100644 index 0000000000..9a5213b587 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-radial-gradient.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-radial-gradient.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-radial-gradient.base.rgb24.ref.png new file mode 100644 index 0000000000..9a5213b587 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-radial-gradient.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-radial-gradient.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-radial-gradient.pdf.ref.png new file mode 100644 index 0000000000..ba47eb1a9e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-radial-gradient.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-radial-gradient.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-radial-gradient.ref.png new file mode 100644 index 0000000000..9a5213b587 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-radial-gradient.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-radial-gradient.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-radial-gradient.svg.ref.png new file mode 100644 index 0000000000..ba47eb1a9e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-radial-gradient.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.base.argb32.ref.png new file mode 100644 index 0000000000..0353520c97 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.base.rgb24.ref.png new file mode 100644 index 0000000000..0353520c97 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.image16.ref.png new file mode 100644 index 0000000000..ece8943380 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.mask.argb32.ref.png new file mode 100644 index 0000000000..c4293adf4a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.mask.rgb24.ref.png new file mode 100644 index 0000000000..c4293adf4a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.pdf.ref.png new file mode 100644 index 0000000000..5b3ef49bae Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.ps.ref.png new file mode 100644 index 0000000000..98a1fc9ec2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.quartz.ref.png new file mode 100644 index 0000000000..2d21e04809 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.ref.png new file mode 100644 index 0000000000..4284bfa5b3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.svg.ref.png new file mode 100644 index 0000000000..5b3ef49bae Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.traps.argb32.ref.png new file mode 100644 index 0000000000..0353520c97 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.traps.rgb24.ref.png new file mode 100644 index 0000000000..0353520c97 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-rel-curve-to.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-solid-dash.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/degenerate-solid-dash.quartz.xfail.png new file mode 100644 index 0000000000..799562ad50 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-solid-dash.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/degenerate-solid-dash.ref.png b/local/recipes/libs/cairo/source/test/reference/degenerate-solid-dash.ref.png new file mode 100644 index 0000000000..9511289b5a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/degenerate-solid-dash.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/device-offset-fractional.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/device-offset-fractional.base.argb32.ref.png new file mode 100644 index 0000000000..b1eef5f28a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/device-offset-fractional.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/device-offset-fractional.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/device-offset-fractional.base.rgb24.ref.png new file mode 100644 index 0000000000..b1eef5f28a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/device-offset-fractional.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/device-offset-fractional.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/device-offset-fractional.pdf.ref.png new file mode 100644 index 0000000000..7c070937df Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/device-offset-fractional.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/device-offset-fractional.pdf.xfail.png b/local/recipes/libs/cairo/source/test/reference/device-offset-fractional.pdf.xfail.png new file mode 100644 index 0000000000..50bbd343ca Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/device-offset-fractional.pdf.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/device-offset-fractional.ps2.ref.png b/local/recipes/libs/cairo/source/test/reference/device-offset-fractional.ps2.ref.png new file mode 100644 index 0000000000..5b44082c26 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/device-offset-fractional.ps2.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/device-offset-fractional.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/device-offset-fractional.ps3.ref.png new file mode 100644 index 0000000000..5b44082c26 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/device-offset-fractional.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/device-offset-fractional.ref.png b/local/recipes/libs/cairo/source/test/reference/device-offset-fractional.ref.png new file mode 100644 index 0000000000..9250d33d35 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/device-offset-fractional.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/device-offset-fractional.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/device-offset-fractional.svg.ref.png new file mode 100644 index 0000000000..7c070937df Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/device-offset-fractional.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/device-offset-positive.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/device-offset-positive.base.argb32.ref.png new file mode 100644 index 0000000000..1115bca7a2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/device-offset-positive.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/device-offset-positive.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/device-offset-positive.base.rgb24.ref.png new file mode 100644 index 0000000000..dcdd3324c5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/device-offset-positive.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/device-offset-positive.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/device-offset-positive.ps.rgb24.ref.png new file mode 100644 index 0000000000..dcdd3324c5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/device-offset-positive.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/device-offset-positive.ref.png b/local/recipes/libs/cairo/source/test/reference/device-offset-positive.ref.png new file mode 100644 index 0000000000..bdf63afddf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/device-offset-positive.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/device-offset-scale.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/device-offset-scale.base.argb32.ref.png new file mode 100644 index 0000000000..fdffbf3c67 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/device-offset-scale.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/device-offset-scale.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/device-offset-scale.base.rgb24.ref.png new file mode 100644 index 0000000000..fdffbf3c67 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/device-offset-scale.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/device-offset-scale.ref.png b/local/recipes/libs/cairo/source/test/reference/device-offset-scale.ref.png new file mode 100644 index 0000000000..66b29732e0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/device-offset-scale.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/device-offset.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/device-offset.base.argb32.ref.png new file mode 100644 index 0000000000..43ced46b20 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/device-offset.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/device-offset.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/device-offset.base.rgb24.ref.png new file mode 100644 index 0000000000..f19acba172 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/device-offset.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/device-offset.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/device-offset.ps.rgb24.ref.png new file mode 100644 index 0000000000..f19acba172 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/device-offset.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/device-offset.ref.png b/local/recipes/libs/cairo/source/test/reference/device-offset.ref.png new file mode 100644 index 0000000000..22cbfb4d73 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/device-offset.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dithergradient.image.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/dithergradient.image.argb32.ref.png new file mode 100644 index 0000000000..f67d369f0c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dithergradient.image.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dithergradient.image.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/dithergradient.image.rgb24.ref.png new file mode 100644 index 0000000000..f67d369f0c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dithergradient.image.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/dithergradient.image16.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/dithergradient.image16.rgb24.ref.png new file mode 100644 index 0000000000..91c9f5e2df Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/dithergradient.image16.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/drunkard-tails.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/drunkard-tails.base.argb32.ref.png new file mode 100644 index 0000000000..92ab0b9f45 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/drunkard-tails.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/drunkard-tails.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/drunkard-tails.base.rgb24.ref.png new file mode 100644 index 0000000000..92ab0b9f45 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/drunkard-tails.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/drunkard-tails.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/drunkard-tails.mask.argb32.ref.png new file mode 100644 index 0000000000..053e470752 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/drunkard-tails.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/drunkard-tails.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/drunkard-tails.mask.rgb24.ref.png new file mode 100644 index 0000000000..053e470752 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/drunkard-tails.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/drunkard-tails.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/drunkard-tails.ps.ref.png new file mode 100644 index 0000000000..f68c8b58c2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/drunkard-tails.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/drunkard-tails.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/drunkard-tails.quartz.ref.png new file mode 100644 index 0000000000..8e72b0a8c0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/drunkard-tails.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/drunkard-tails.ref.png b/local/recipes/libs/cairo/source/test/reference/drunkard-tails.ref.png new file mode 100644 index 0000000000..b38b897aa4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/drunkard-tails.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/drunkard-tails.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/drunkard-tails.traps.argb32.ref.png new file mode 100644 index 0000000000..92ab0b9f45 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/drunkard-tails.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/drunkard-tails.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/drunkard-tails.traps.rgb24.ref.png new file mode 100644 index 0000000000..92ab0b9f45 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/drunkard-tails.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-pad-border.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-pad-border.base.argb32.ref.png new file mode 100644 index 0000000000..f4fc524ac5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-pad-border.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-pad-border.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-pad-border.base.rgb24.ref.png new file mode 100644 index 0000000000..f4fc524ac5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-pad-border.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-pad-border.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-pad-border.image16.ref.png new file mode 100644 index 0000000000..2a1efd4d23 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-pad-border.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-pad-border.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-pad-border.pdf.ref.png new file mode 100644 index 0000000000..c22743e8fc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-pad-border.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-pad-border.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-pad-border.ps.ref.png new file mode 100644 index 0000000000..b1f4c406c3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-pad-border.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-pad-border.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-pad-border.quartz.ref.png new file mode 100644 index 0000000000..4ad67a1deb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-pad-border.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-pad-border.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-pad-border.ref.png new file mode 100644 index 0000000000..f4fc524ac5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-pad-border.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-pad-border.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-pad-border.svg.ref.png new file mode 100644 index 0000000000..c22743e8fc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-pad-border.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-pad-similar.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-pad-similar.base.argb32.ref.png new file mode 100644 index 0000000000..9345221899 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-pad-similar.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-pad-similar.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-pad-similar.base.rgb24.ref.png new file mode 100644 index 0000000000..9345221899 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-pad-similar.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-pad-similar.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/extend-pad-similar.quartz.xfail.png new file mode 100644 index 0000000000..a2cf3530c7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-pad-similar.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-pad-similar.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-pad-similar.ref.png new file mode 100644 index 0000000000..82da7b65a3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-pad-similar.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-pad.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-pad.base.argb32.ref.png new file mode 100644 index 0000000000..9345221899 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-pad.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-pad.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-pad.base.rgb24.ref.png new file mode 100644 index 0000000000..9345221899 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-pad.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-pad.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-pad.ps.ref.png new file mode 100644 index 0000000000..a249ee209b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-pad.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-pad.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/extend-pad.quartz.xfail.png new file mode 100644 index 0000000000..a2cf3530c7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-pad.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-pad.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-pad.ref.png new file mode 100644 index 0000000000..82da7b65a3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-pad.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-reflect-similar.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-reflect-similar.base.argb32.ref.png new file mode 100644 index 0000000000..5fc3448fae Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-reflect-similar.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-reflect-similar.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-reflect-similar.base.rgb24.ref.png new file mode 100644 index 0000000000..5fc3448fae Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-reflect-similar.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-reflect-similar.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-reflect-similar.image16.ref.png new file mode 100644 index 0000000000..27c6594ea0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-reflect-similar.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-reflect-similar.ps2.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-reflect-similar.ps2.ref.png new file mode 100644 index 0000000000..acaee1b5a2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-reflect-similar.ps2.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-reflect-similar.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-reflect-similar.ps3.ref.png new file mode 100644 index 0000000000..acaee1b5a2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-reflect-similar.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-reflect-similar.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-reflect-similar.ref.png new file mode 100644 index 0000000000..93a8b001be Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-reflect-similar.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-reflect.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-reflect.base.argb32.ref.png new file mode 100644 index 0000000000..5fc3448fae Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-reflect.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-reflect.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-reflect.base.rgb24.ref.png new file mode 100644 index 0000000000..5fc3448fae Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-reflect.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-reflect.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-reflect.image16.ref.png new file mode 100644 index 0000000000..27c6594ea0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-reflect.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-reflect.ps2.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-reflect.ps2.ref.png new file mode 100644 index 0000000000..acaee1b5a2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-reflect.ps2.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-reflect.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-reflect.ps3.ref.png new file mode 100644 index 0000000000..acaee1b5a2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-reflect.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-reflect.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-reflect.ref.png new file mode 100644 index 0000000000..93a8b001be Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-reflect.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-repeat-similar.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-repeat-similar.base.argb32.ref.png new file mode 100644 index 0000000000..81f0503dfd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-repeat-similar.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-repeat-similar.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-repeat-similar.base.rgb24.ref.png new file mode 100644 index 0000000000..81f0503dfd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-repeat-similar.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-repeat-similar.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-repeat-similar.image16.ref.png new file mode 100644 index 0000000000..cdc742a74d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-repeat-similar.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-repeat-similar.ps2.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-repeat-similar.ps2.ref.png new file mode 100644 index 0000000000..8218211ee9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-repeat-similar.ps2.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-repeat-similar.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-repeat-similar.ps3.ref.png new file mode 100644 index 0000000000..8218211ee9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-repeat-similar.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-repeat-similar.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-repeat-similar.ref.png new file mode 100644 index 0000000000..ee2527fade Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-repeat-similar.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-repeat.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-repeat.base.argb32.ref.png new file mode 100644 index 0000000000..81f0503dfd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-repeat.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-repeat.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-repeat.base.rgb24.ref.png new file mode 100644 index 0000000000..81f0503dfd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-repeat.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-repeat.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-repeat.image16.ref.png new file mode 100644 index 0000000000..cdc742a74d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-repeat.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-repeat.ps2.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-repeat.ps2.ref.png new file mode 100644 index 0000000000..8218211ee9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-repeat.ps2.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-repeat.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-repeat.ps3.ref.png new file mode 100644 index 0000000000..8218211ee9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-repeat.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extend-repeat.ref.png b/local/recipes/libs/cairo/source/test/reference/extend-repeat.ref.png new file mode 100644 index 0000000000..ee2527fade Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extend-repeat.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha-mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha-mask.argb32.ref.png new file mode 100644 index 0000000000..1b0eaf0cd0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha-mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha-mask.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha-mask.base.argb32.ref.png new file mode 100644 index 0000000000..a1dd2a93f7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha-mask.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha-mask.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha-mask.base.rgb24.ref.png new file mode 100644 index 0000000000..b5f12f1456 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha-mask.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha-mask.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha-mask.quartz.argb32.ref.png new file mode 100644 index 0000000000..d44145fb36 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha-mask.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha-mask.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha-mask.quartz.rgb24.ref.png new file mode 100644 index 0000000000..7949899529 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha-mask.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha-mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha-mask.rgb24.ref.png new file mode 100644 index 0000000000..b5f12f1456 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha-mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha-mask.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha-mask.svg.ref.png new file mode 100644 index 0000000000..2368f1ac0b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha-mask.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha.argb32.ref.png new file mode 100644 index 0000000000..9731b681be Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha.base.argb32.ref.png new file mode 100644 index 0000000000..4d56a21fc4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha.base.rgb24.ref.png new file mode 100644 index 0000000000..86d0e2d910 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha.image16.ref.png new file mode 100644 index 0000000000..df9646977c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha.quartz.argb32.ref.png new file mode 100644 index 0000000000..83c0ce5f76 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha.quartz.rgb24.ref.png new file mode 100644 index 0000000000..1b3dae712a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha.rgb24.ref.png new file mode 100644 index 0000000000..cbffb70cba Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha.svg.ref.png new file mode 100644 index 0000000000..0614cda868 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha.svg.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha.svg.rgb24.ref.png new file mode 100644 index 0000000000..8c35cd6ef7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-alpha.svg.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-mask.argb32.ref.png new file mode 100644 index 0000000000..59b684d252 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-mask.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-mask.base.argb32.ref.png new file mode 100644 index 0000000000..5fa78e4cc7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-mask.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-mask.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-mask.base.rgb24.ref.png new file mode 100644 index 0000000000..1c854745b2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-mask.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-mask.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-mask.quartz.argb32.ref.png new file mode 100644 index 0000000000..ab48faa0ef Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-mask.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-mask.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-mask.quartz.rgb24.ref.png new file mode 100644 index 0000000000..dcc0919c8e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-mask.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-mask.rgb24.ref.png new file mode 100644 index 0000000000..8199321d27 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-mask.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-mask.svg.ref.png new file mode 100644 index 0000000000..7c6a5db2e3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-mask.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-mask.svg.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-mask.svg.rgb24.ref.png new file mode 100644 index 0000000000..ed5f34dba0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-mask.svg.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-solid-alpha.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-solid-alpha.argb32.ref.png new file mode 100644 index 0000000000..9731b681be Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-solid-alpha.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-solid-alpha.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-solid-alpha.base.argb32.ref.png new file mode 100644 index 0000000000..4d56a21fc4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-solid-alpha.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-solid-alpha.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-solid-alpha.base.rgb24.ref.png new file mode 100644 index 0000000000..86d0e2d910 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-solid-alpha.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-solid-alpha.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-solid-alpha.image16.ref.png new file mode 100644 index 0000000000..df9646977c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-solid-alpha.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-solid-alpha.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-solid-alpha.quartz.argb32.ref.png new file mode 100644 index 0000000000..83c0ce5f76 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-solid-alpha.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-solid-alpha.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-solid-alpha.quartz.rgb24.ref.png new file mode 100644 index 0000000000..1b3dae712a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-solid-alpha.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-solid-alpha.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-solid-alpha.rgb24.ref.png new file mode 100644 index 0000000000..cbffb70cba Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-solid-alpha.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-solid.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-solid.argb32.ref.png new file mode 100644 index 0000000000..573c16a262 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-solid.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-solid.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-solid.base.argb32.ref.png new file mode 100644 index 0000000000..902ef8845b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-solid.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-solid.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-solid.base.rgb24.ref.png new file mode 100644 index 0000000000..4580e0dad8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-solid.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-solid.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-solid.image16.ref.png new file mode 100644 index 0000000000..2052ea7cb8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-solid.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-solid.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-solid.quartz.argb32.ref.png new file mode 100644 index 0000000000..14a7820774 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-solid.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-solid.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-solid.quartz.rgb24.ref.png new file mode 100644 index 0000000000..28ef8e15cb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-solid.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend-solid.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend-solid.rgb24.ref.png new file mode 100644 index 0000000000..7d85c93ef1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend-solid.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend.argb32.ref.png new file mode 100644 index 0000000000..573c16a262 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend.base.argb32.ref.png new file mode 100644 index 0000000000..902ef8845b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend.base.rgb24.ref.png new file mode 100644 index 0000000000..4580e0dad8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend.image16.ref.png new file mode 100644 index 0000000000..2052ea7cb8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend.quartz.argb32.ref.png new file mode 100644 index 0000000000..14a7820774 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend.quartz.rgb24.ref.png new file mode 100644 index 0000000000..28ef8e15cb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend.rgb24.ref.png new file mode 100644 index 0000000000..7d85c93ef1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend.svg.ref.png new file mode 100644 index 0000000000..8b98a40d11 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/extended-blend.svg.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/extended-blend.svg.rgb24.ref.png new file mode 100644 index 0000000000..6c85918b0d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/extended-blend.svg.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi144x144.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi144x144.pdf.ref.png new file mode 100644 index 0000000000..5d0b152526 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi144x144.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi144x144.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi144x144.ps.ref.png new file mode 100644 index 0000000000..c7cfa6251f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi144x144.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi144x144.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi144x144.ref.png new file mode 100644 index 0000000000..fd0666a428 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi144x144.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi144x144.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi144x144.svg.ref.png new file mode 100644 index 0000000000..5d0b152526 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi144x144.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi144x72.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi144x72.pdf.ref.png new file mode 100644 index 0000000000..551f8430b9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi144x72.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi144x72.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi144x72.ps.ref.png new file mode 100644 index 0000000000..b55fdfc495 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi144x72.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi144x72.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi144x72.ref.png new file mode 100644 index 0000000000..ec6685cc08 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi144x72.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi144x72.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi144x72.svg.ref.png new file mode 100644 index 0000000000..551f8430b9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi144x72.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi288x288.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi288x288.pdf.ref.png new file mode 100644 index 0000000000..fcd8484cf5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi288x288.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi288x288.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi288x288.ps.ref.png new file mode 100644 index 0000000000..3edfdbcdd8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi288x288.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi288x288.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi288x288.svg.ref.png new file mode 100644 index 0000000000..fcd8484cf5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi288x288.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi288x72.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi288x72.pdf.ref.png new file mode 100644 index 0000000000..107cdca6a3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi288x72.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi288x72.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi288x72.ps.ref.png new file mode 100644 index 0000000000..a4de1163af Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi288x72.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi288x72.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi288x72.ref.png new file mode 100644 index 0000000000..969c04f178 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi288x72.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi288x72.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi288x72.svg.ref.png new file mode 100644 index 0000000000..107cdca6a3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi288x72.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi576x576.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi576x576.pdf.ref.png new file mode 100644 index 0000000000..e7947b2b0f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi576x576.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi576x576.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi576x576.ps.ref.png new file mode 100644 index 0000000000..f2dcf7ce4e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi576x576.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi576x576.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi576x576.svg.ref.png new file mode 100644 index 0000000000..e7947b2b0f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi576x576.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi576x72.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi576x72.pdf.ref.png new file mode 100644 index 0000000000..b435fb8bc0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi576x72.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi576x72.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi576x72.ps.ref.png new file mode 100644 index 0000000000..8aee2a988e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi576x72.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi576x72.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi576x72.ref.png new file mode 100644 index 0000000000..bbab0653e8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi576x72.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi576x72.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi576x72.svg.ref.png new file mode 100644 index 0000000000..b435fb8bc0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi576x72.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x144.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x144.pdf.ref.png new file mode 100644 index 0000000000..753e00798a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x144.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x144.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x144.ps.ref.png new file mode 100644 index 0000000000..88e57af785 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x144.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x144.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x144.ref.png new file mode 100644 index 0000000000..3f55629672 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x144.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x144.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x144.svg.ref.png new file mode 100644 index 0000000000..753e00798a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x144.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x288.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x288.pdf.ref.png new file mode 100644 index 0000000000..eb9883dd5a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x288.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x288.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x288.ps.ref.png new file mode 100644 index 0000000000..ab149801e9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x288.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x288.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x288.ref.png new file mode 100644 index 0000000000..9d50b64d63 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x288.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x288.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x288.svg.ref.png new file mode 100644 index 0000000000..eb9883dd5a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x288.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x576.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x576.pdf.ref.png new file mode 100644 index 0000000000..b24e393cb2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x576.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x576.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x576.ps.ref.png new file mode 100644 index 0000000000..c1b592f9dc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x576.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x576.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x576.ref.png new file mode 100644 index 0000000000..7b4d62e194 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x576.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x576.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x576.svg.ref.png new file mode 100644 index 0000000000..b24e393cb2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x576.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x72.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x72.pdf.ref.png new file mode 100644 index 0000000000..8a0d6e8bf9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x72.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x72.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x72.ps.ref.png new file mode 100644 index 0000000000..8a0d6e8bf9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x72.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x72.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x72.ref.png new file mode 100644 index 0000000000..690c0af2de Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x72.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x72.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x72.svg.ref.png new file mode 100644 index 0000000000..8a0d6e8bf9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback-resolution.ppi72x72.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback.argb32.ref.png new file mode 100644 index 0000000000..ac8592ea9e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback.base.argb32.ref.png new file mode 100644 index 0000000000..c0c5f46767 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback.base.rgb24.ref.png new file mode 100644 index 0000000000..18b6a7c836 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback.image16.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback.image16.rgb24.ref.png new file mode 100644 index 0000000000..d90ab0e6be Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback.image16.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback.mask.argb32.ref.png new file mode 100644 index 0000000000..b7ce573633 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback.mask.rgb24.ref.png new file mode 100644 index 0000000000..16d3c14e47 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback.pdf.ref.png new file mode 100644 index 0000000000..2e4a4578f8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback.ps.ref.png new file mode 100644 index 0000000000..99c83e3280 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback.quartz.argb32.ref.png new file mode 100644 index 0000000000..c5f20bb816 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback.quartz.rgb24.ref.png new file mode 100644 index 0000000000..e9876a92f2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback.rgb24.ref.png new file mode 100644 index 0000000000..3b944244ae Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback.svg.ref.png new file mode 100644 index 0000000000..4a83fa1800 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback.svg.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback.svg.rgb24.ref.png new file mode 100644 index 0000000000..a352e00c1d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback.svg.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback.traps.argb32.ref.png new file mode 100644 index 0000000000..c0c5f46767 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fallback.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fallback.traps.rgb24.ref.png new file mode 100644 index 0000000000..18b6a7c836 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fallback.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-alpha-pattern.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-alpha-pattern.base.argb32.ref.png new file mode 100644 index 0000000000..4dafb8359f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-alpha-pattern.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-alpha-pattern.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-alpha-pattern.base.rgb24.ref.png new file mode 100644 index 0000000000..4dafb8359f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-alpha-pattern.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-alpha-pattern.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-alpha-pattern.image16.ref.png new file mode 100644 index 0000000000..f323c10ff7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-alpha-pattern.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-alpha-pattern.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-alpha-pattern.pdf.ref.png new file mode 100644 index 0000000000..ed7f40453d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-alpha-pattern.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-alpha-pattern.ps3.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-alpha-pattern.ps3.argb32.ref.png new file mode 100644 index 0000000000..28689a381e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-alpha-pattern.ps3.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-alpha-pattern.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-alpha-pattern.quartz.ref.png new file mode 100644 index 0000000000..431989926b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-alpha-pattern.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-alpha-pattern.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-alpha-pattern.ref.png new file mode 100644 index 0000000000..e32eb90f14 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-alpha-pattern.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-alpha-pattern.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-alpha-pattern.traps.argb32.ref.png new file mode 100644 index 0000000000..4dafb8359f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-alpha-pattern.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-alpha-pattern.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-alpha-pattern.traps.rgb24.ref.png new file mode 100644 index 0000000000..4dafb8359f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-alpha-pattern.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-alpha.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-alpha.base.argb32.ref.png new file mode 100644 index 0000000000..85df9198cb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-alpha.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-alpha.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-alpha.base.rgb24.ref.png new file mode 100644 index 0000000000..85df9198cb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-alpha.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-alpha.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-alpha.image16.ref.png new file mode 100644 index 0000000000..08252b6c9c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-alpha.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-alpha.ps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-alpha.ps.argb32.ref.png new file mode 100644 index 0000000000..24bd3b18ac Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-alpha.ps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-alpha.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-alpha.quartz.ref.png new file mode 100644 index 0000000000..858a2b3575 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-alpha.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-alpha.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-alpha.ref.png new file mode 100644 index 0000000000..25c1ac68fc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-alpha.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-alpha.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-alpha.traps.argb32.ref.png new file mode 100644 index 0000000000..85df9198cb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-alpha.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-alpha.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-alpha.traps.rgb24.ref.png new file mode 100644 index 0000000000..85df9198cb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-alpha.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha-add.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha-add.base.argb32.ref.png new file mode 100644 index 0000000000..71d2b2221d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha-add.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha-add.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha-add.base.rgb24.ref.png new file mode 100644 index 0000000000..71d2b2221d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha-add.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha-add.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha-add.image16.ref.png new file mode 100644 index 0000000000..3162c8115d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha-add.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha-add.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha-add.pdf.ref.png new file mode 100644 index 0000000000..609ed1f771 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha-add.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha-add.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha-add.ref.png new file mode 100644 index 0000000000..f10ffc2a30 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha-add.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha-add.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha-add.svg.ref.png new file mode 100644 index 0000000000..609ed1f771 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha-add.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha-add.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha-add.traps.argb32.ref.png new file mode 100644 index 0000000000..71d2b2221d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha-add.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha-add.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha-add.traps.rgb24.ref.png new file mode 100644 index 0000000000..71d2b2221d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha-add.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha.base.argb32.ref.png new file mode 100644 index 0000000000..c85b933b01 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha.base.rgb24.ref.png new file mode 100644 index 0000000000..c85b933b01 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha.image16.ref.png new file mode 100644 index 0000000000..cde5bd92d0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha.pdf.ref.png new file mode 100644 index 0000000000..e1746d5d5a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha.ref.png new file mode 100644 index 0000000000..8e811570e3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha.svg.ref.png new file mode 100644 index 0000000000..e1746d5d5a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha.traps.argb32.ref.png new file mode 100644 index 0000000000..c85b933b01 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha.traps.rgb24.ref.png new file mode 100644 index 0000000000..c85b933b01 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke-alpha.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.base.argb32.ref.png new file mode 100644 index 0000000000..3f32060f4a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.base.rgb24.ref.png new file mode 100644 index 0000000000..2797921e41 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.image16.ref.png new file mode 100644 index 0000000000..f562509f34 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.pdf.argb32.ref.png new file mode 100644 index 0000000000..81ec2f8dae Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.pdf.rgb24.ref.png new file mode 100644 index 0000000000..f0b2be5192 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.ps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.ps.argb32.ref.png new file mode 100644 index 0000000000..8cf8d9cc6b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.ps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.ps.rgb24.ref.png new file mode 100644 index 0000000000..fceda260e1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.quartz.ref.png new file mode 100644 index 0000000000..9440719191 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.ref.png new file mode 100644 index 0000000000..c71a4e5893 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.svg.ref.png new file mode 100644 index 0000000000..c836405577 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.traps.argb32.ref.png new file mode 100644 index 0000000000..3f32060f4a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.traps.rgb24.ref.png new file mode 100644 index 0000000000..2797921e41 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-and-stroke.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.argb32.ref.png new file mode 100644 index 0000000000..c43bcd5277 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.base.argb32.ref.png new file mode 100644 index 0000000000..860ee1b164 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.base.rgb24.ref.png new file mode 100644 index 0000000000..18b08fc4bd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.image16.ref.png new file mode 100644 index 0000000000..6dc207870d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.pdf.ref.png new file mode 100644 index 0000000000..20ce4b8369 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.ps.argb32.xfail.png b/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.ps.argb32.xfail.png new file mode 100644 index 0000000000..79ea63071c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.ps.argb32.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.ps.rgb24.xfail.png b/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.ps.rgb24.xfail.png new file mode 100644 index 0000000000..b4c45f9a16 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.ps.rgb24.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.quartz.argb32.ref.png new file mode 100644 index 0000000000..a8b9f15bce Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.quartz.rgb24.ref.png new file mode 100644 index 0000000000..703467cf2c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.rgb24.ref.png new file mode 100644 index 0000000000..35ebdbd139 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.traps.argb32.ref.png new file mode 100644 index 0000000000..860ee1b164 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.traps.rgb24.ref.png new file mode 100644 index 0000000000..18b08fc4bd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-degenerate-sort-order.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-disjoint.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-disjoint.base.argb32.ref.png new file mode 100644 index 0000000000..da9a3b1128 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-disjoint.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-disjoint.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-disjoint.base.rgb24.ref.png new file mode 100644 index 0000000000..da9a3b1128 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-disjoint.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-disjoint.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-disjoint.ref.png new file mode 100644 index 0000000000..da9a3b1128 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-disjoint.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-empty.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-empty.base.argb32.ref.png new file mode 100644 index 0000000000..8c26f7ebf0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-empty.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-empty.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-empty.base.rgb24.ref.png new file mode 100644 index 0000000000..dc7a8a0e42 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-empty.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-empty.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-empty.ps.rgb24.ref.png new file mode 100644 index 0000000000..dc7a8a0e42 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-empty.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-empty.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-empty.ref.png new file mode 100644 index 0000000000..8c26f7ebf0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-empty.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-image.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-image.base.argb32.ref.png new file mode 100644 index 0000000000..1e67073dff Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-image.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-image.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-image.base.rgb24.ref.png new file mode 100644 index 0000000000..1e67073dff Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-image.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-image.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-image.image16.ref.png new file mode 100644 index 0000000000..3a9b7c7942 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-image.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-image.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-image.ps.ref.png new file mode 100644 index 0000000000..1b845bc3ef Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-image.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-image.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-image.quartz.ref.png new file mode 100644 index 0000000000..141676d49e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-image.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-image.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-image.ref.png new file mode 100644 index 0000000000..e521be4fd4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-image.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-image.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-image.traps.argb32.ref.png new file mode 100644 index 0000000000..1e67073dff Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-image.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-image.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-image.traps.rgb24.ref.png new file mode 100644 index 0000000000..1e67073dff Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-image.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.base.argb32.ref.png new file mode 100644 index 0000000000..223fb360ea Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.base.rgb24.ref.png new file mode 100644 index 0000000000..f56b4b2e92 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.pdf.argb32.ref.png new file mode 100644 index 0000000000..8251b29dae Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.pdf.rgb24.ref.png new file mode 100644 index 0000000000..e9921667ee Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.ps2.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.ps2.argb32.ref.png new file mode 100644 index 0000000000..b94a70899b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.ps2.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.ps2.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.ps2.rgb24.ref.png new file mode 100644 index 0000000000..fd54c7b1ec Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.ps2.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.ps3.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.ps3.argb32.ref.png new file mode 100644 index 0000000000..b94a70899b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.ps3.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.ps3.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.ps3.rgb24.ref.png new file mode 100644 index 0000000000..fd54c7b1ec Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.ps3.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.ref.png new file mode 100644 index 0000000000..477eec9a50 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.svg.ref.png new file mode 100644 index 0000000000..1f580a498c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.traps.argb32.ref.png new file mode 100644 index 0000000000..223fb360ea Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.traps.rgb24.ref.png new file mode 100644 index 0000000000..f56b4b2e92 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-missed-stop.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-rule.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-rule.argb32.ref.png new file mode 100644 index 0000000000..9a0ea401f7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-rule.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-rule.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-rule.base.argb32.ref.png new file mode 100644 index 0000000000..e2e10d4a89 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-rule.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-rule.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-rule.base.rgb24.ref.png new file mode 100644 index 0000000000..49fb39c768 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-rule.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-rule.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-rule.image16.ref.png new file mode 100644 index 0000000000..27613f70a5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-rule.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-rule.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-rule.pdf.ref.png new file mode 100644 index 0000000000..67af05127e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-rule.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-rule.ps2.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-rule.ps2.argb32.ref.png new file mode 100644 index 0000000000..c9bdf90549 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-rule.ps2.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-rule.ps2.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-rule.ps2.rgb24.ref.png new file mode 100644 index 0000000000..617a20bdad Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-rule.ps2.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-rule.ps3.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-rule.ps3.argb32.ref.png new file mode 100644 index 0000000000..c9bdf90549 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-rule.ps3.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-rule.ps3.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-rule.ps3.rgb24.ref.png new file mode 100644 index 0000000000..617a20bdad Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-rule.ps3.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-rule.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-rule.quartz.argb32.ref.png new file mode 100644 index 0000000000..2ac534091d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-rule.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-rule.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-rule.quartz.rgb24.ref.png new file mode 100644 index 0000000000..bd671d62d4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-rule.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-rule.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-rule.rgb24.ref.png new file mode 100644 index 0000000000..70bde2de77 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-rule.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-rule.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-rule.traps.argb32.ref.png new file mode 100644 index 0000000000..e2e10d4a89 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-rule.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-rule.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-rule.traps.rgb24.ref.png new file mode 100644 index 0000000000..49fb39c768 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-rule.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-xlib-fallback.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-xlib-fallback.rgb24.ref.png new file mode 100644 index 0000000000..1e67073dff Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-xlib-fallback.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-xlib-window.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-xlib-window.rgb24.ref.png new file mode 100644 index 0000000000..1e67073dff Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-xlib-window.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill-xlib.ref.png b/local/recipes/libs/cairo/source/test/reference/fill-xlib.ref.png new file mode 100644 index 0000000000..1e67073dff Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill-xlib.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill.image.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/fill.image.argb32.ref.png new file mode 100644 index 0000000000..70c6bccc0e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill.image.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/fill.image.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/fill.image.rgb24.ref.png new file mode 100644 index 0000000000..70c6bccc0e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/fill.image.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/filter-bilinear-extents.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/filter-bilinear-extents.base.argb32.ref.png new file mode 100644 index 0000000000..797e7981f2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/filter-bilinear-extents.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/filter-bilinear-extents.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/filter-bilinear-extents.base.rgb24.ref.png new file mode 100644 index 0000000000..797e7981f2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/filter-bilinear-extents.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/filter-bilinear-extents.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/filter-bilinear-extents.image16.ref.png new file mode 100644 index 0000000000..5b7755bb36 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/filter-bilinear-extents.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/filter-bilinear-extents.pdf.xfail.png b/local/recipes/libs/cairo/source/test/reference/filter-bilinear-extents.pdf.xfail.png new file mode 100644 index 0000000000..e6c4bb4608 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/filter-bilinear-extents.pdf.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/filter-bilinear-extents.ps2.ref.png b/local/recipes/libs/cairo/source/test/reference/filter-bilinear-extents.ps2.ref.png new file mode 100644 index 0000000000..97c105c9da Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/filter-bilinear-extents.ps2.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/filter-bilinear-extents.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/filter-bilinear-extents.ps3.ref.png new file mode 100644 index 0000000000..97c105c9da Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/filter-bilinear-extents.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/filter-bilinear-extents.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/filter-bilinear-extents.quartz.xfail.png new file mode 100644 index 0000000000..312ee802da Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/filter-bilinear-extents.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/filter-bilinear-extents.ref.png b/local/recipes/libs/cairo/source/test/reference/filter-bilinear-extents.ref.png new file mode 100644 index 0000000000..797e7981f2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/filter-bilinear-extents.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/filter-nearest-offset.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/filter-nearest-offset.base.argb32.ref.png new file mode 100644 index 0000000000..8cca9a1dc4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/filter-nearest-offset.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/filter-nearest-offset.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/filter-nearest-offset.base.rgb24.ref.png new file mode 100644 index 0000000000..8cca9a1dc4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/filter-nearest-offset.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/filter-nearest-offset.pdf.xfail.png b/local/recipes/libs/cairo/source/test/reference/filter-nearest-offset.pdf.xfail.png new file mode 100644 index 0000000000..3042821f41 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/filter-nearest-offset.pdf.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/filter-nearest-offset.ps2.ref.png b/local/recipes/libs/cairo/source/test/reference/filter-nearest-offset.ps2.ref.png new file mode 100644 index 0000000000..185f779392 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/filter-nearest-offset.ps2.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/filter-nearest-offset.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/filter-nearest-offset.ps3.ref.png new file mode 100644 index 0000000000..185f779392 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/filter-nearest-offset.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/filter-nearest-offset.ref.png b/local/recipes/libs/cairo/source/test/reference/filter-nearest-offset.ref.png new file mode 100644 index 0000000000..af81aeea15 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/filter-nearest-offset.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/filter-nearest-transformed.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/filter-nearest-transformed.base.argb32.ref.png new file mode 100644 index 0000000000..24adf8bc18 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/filter-nearest-transformed.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/filter-nearest-transformed.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/filter-nearest-transformed.base.rgb24.ref.png new file mode 100644 index 0000000000..24adf8bc18 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/filter-nearest-transformed.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/filter-nearest-transformed.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/filter-nearest-transformed.image16.ref.png new file mode 100644 index 0000000000..a02e1e11b9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/filter-nearest-transformed.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/filter-nearest-transformed.pdf.xfail.png b/local/recipes/libs/cairo/source/test/reference/filter-nearest-transformed.pdf.xfail.png new file mode 100644 index 0000000000..e5b83784f0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/filter-nearest-transformed.pdf.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/filter-nearest-transformed.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/filter-nearest-transformed.quartz.xfail.png new file mode 100644 index 0000000000..7a1b55ab31 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/filter-nearest-transformed.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/filter-nearest-transformed.ref.png b/local/recipes/libs/cairo/source/test/reference/filter-nearest-transformed.ref.png new file mode 100644 index 0000000000..dc413b47e2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/filter-nearest-transformed.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.base.argb32.ref.png new file mode 100644 index 0000000000..accb01be7a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.base.rgb24.ref.png new file mode 100644 index 0000000000..0e6094cd32 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.image16.ref.png new file mode 100644 index 0000000000..3b104ef8fb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.mask.argb32.ref.png new file mode 100644 index 0000000000..8cd99d0e42 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.mask.rgb24.ref.png new file mode 100644 index 0000000000..5d6cd94f80 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.pdf.argb32.ref.png new file mode 100644 index 0000000000..f5edc140fd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.pdf.rgb24.ref.png new file mode 100644 index 0000000000..8ee9a5e625 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.ps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.ps.argb32.ref.png new file mode 100644 index 0000000000..261c460367 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.ps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.ps.rgb24.ref.png new file mode 100644 index 0000000000..8ee9a5e625 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.quartz.argb32.ref.png new file mode 100644 index 0000000000..bca4ee49c4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.quartz.rgb24.ref.png new file mode 100644 index 0000000000..0220e7f3d3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.ref.png b/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.ref.png new file mode 100644 index 0000000000..cb18717f51 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.svg.ref.png new file mode 100644 index 0000000000..532181ea14 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.traps.argb32.ref.png new file mode 100644 index 0000000000..accb01be7a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.traps.rgb24.ref.png new file mode 100644 index 0000000000..0e6094cd32 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.xlib-fallback.ref.png b/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.xlib-fallback.ref.png new file mode 100644 index 0000000000..c2af714cc2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/finer-grained-fallbacks.xlib-fallback.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/font-matrix-translation.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/font-matrix-translation.base.argb32.ref.png new file mode 100644 index 0000000000..a4a108206c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/font-matrix-translation.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/font-matrix-translation.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/font-matrix-translation.base.rgb24.ref.png new file mode 100644 index 0000000000..a4a108206c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/font-matrix-translation.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/font-matrix-translation.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/font-matrix-translation.image16.ref.png new file mode 100644 index 0000000000..f76b9ae808 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/font-matrix-translation.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/font-matrix-translation.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/font-matrix-translation.ps.ref.png new file mode 100644 index 0000000000..472e60f9ec Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/font-matrix-translation.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/font-matrix-translation.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/font-matrix-translation.quartz.ref.png new file mode 100644 index 0000000000..424e8772c0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/font-matrix-translation.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/font-matrix-translation.ref.png b/local/recipes/libs/cairo/source/test/reference/font-matrix-translation.ref.png new file mode 100644 index 0000000000..a4a108206c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/font-matrix-translation.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/font-matrix-translation.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/font-matrix-translation.svg.ref.png new file mode 100644 index 0000000000..98d8bb5bf9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/font-matrix-translation.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-color-font.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-color-font.image16.ref.png new file mode 100644 index 0000000000..f428cc0658 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-color-font.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-color-font.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-color-font.pdf.ref.png new file mode 100644 index 0000000000..a37fe13d53 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-color-font.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-color-font.ps2.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-color-font.ps2.argb32.ref.png new file mode 100644 index 0000000000..562bed74d9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-color-font.ps2.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-color-font.ps2.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-color-font.ps2.rgb24.ref.png new file mode 100644 index 0000000000..f504664501 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-color-font.ps2.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-color-font.ps3.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-color-font.ps3.argb32.ref.png new file mode 100644 index 0000000000..562bed74d9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-color-font.ps3.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-color-font.ps3.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-color-font.ps3.rgb24.ref.png new file mode 100644 index 0000000000..f504664501 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-color-font.ps3.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-color-font.recording.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-color-font.recording.ref.png new file mode 100644 index 0000000000..5035dde11b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-color-font.recording.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-color-font.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-color-font.ref.png new file mode 100644 index 0000000000..d500fc026a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-color-font.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-color-font.script.xfail.png b/local/recipes/libs/cairo/source/test/reference/ft-color-font.script.xfail.png new file mode 100644 index 0000000000..6ec7a984ea Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-color-font.script.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-positioning.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-positioning.base.argb32.ref.png new file mode 100644 index 0000000000..af6dcaf95d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-positioning.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-positioning.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-positioning.base.rgb24.ref.png new file mode 100644 index 0000000000..af6dcaf95d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-positioning.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-positioning.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-positioning.image16.ref.png new file mode 100644 index 0000000000..f3d9f0d1f1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-positioning.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-positioning.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-positioning.pdf.ref.png new file mode 100644 index 0000000000..4f8d9f7412 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-positioning.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-positioning.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-positioning.ps.ref.png new file mode 100644 index 0000000000..f4e57201d4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-positioning.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-positioning.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-positioning.ref.png new file mode 100644 index 0000000000..af6dcaf95d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-positioning.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-table.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-table.base.argb32.ref.png new file mode 100644 index 0000000000..ed69124897 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-table.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-table.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-table.base.rgb24.ref.png new file mode 100644 index 0000000000..ed69124897 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-table.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-table.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-table.image16.ref.png new file mode 100644 index 0000000000..af01a49a05 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-table.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-table.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-table.ps.ref.png new file mode 100644 index 0000000000..35a9986ebf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-table.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-table.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-table.quartz.xfail.png new file mode 100644 index 0000000000..0e131b26fe Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-table.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-table.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-table.ref.png new file mode 100644 index 0000000000..ed69124897 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-table.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-table.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-table.svg.ref.png new file mode 100644 index 0000000000..9097f6d32c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-show-glyphs-table.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-cairo-logo.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-cairo-logo.image16.ref.png new file mode 100644 index 0000000000..2edddcbdf4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-cairo-logo.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-cairo-logo.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-cairo-logo.ps.ref.png new file mode 100644 index 0000000000..48124e341c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-cairo-logo.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-cairo-logo.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-cairo-logo.ps.rgb24.ref.png new file mode 100644 index 0000000000..8ef8798bed Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-cairo-logo.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-cairo-logo.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-cairo-logo.ref.png new file mode 100644 index 0000000000..0c92934d61 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-cairo-logo.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-cairo-logo.script.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-cairo-logo.script.ref.png new file mode 100644 index 0000000000..f3514cad87 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-cairo-logo.script.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-cairo-logo.svg.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-cairo-logo.svg.rgb24.ref.png new file mode 100644 index 0000000000..9fb5d3b1bc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-cairo-logo.svg.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-color-font.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-color-font.ref.png new file mode 100644 index 0000000000..22bafde039 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-color-font.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-color.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-color.image16.ref.png new file mode 100644 index 0000000000..79177f3b14 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-color.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-color.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-color.pdf.ref.png new file mode 100644 index 0000000000..933a9ff0ff Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-color.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-color.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-color.ps.ref.png new file mode 100644 index 0000000000..4ded8cfb1b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-color.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-color.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-color.ps.rgb24.ref.png new file mode 100644 index 0000000000..b5435cea14 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-color.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-color.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-color.ref.png new file mode 100644 index 0000000000..d688c378c2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-color.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-color.script.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-color.script.ref.png new file mode 100644 index 0000000000..bbacb1ea4b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-color.script.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-color.svg.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-color.svg.rgb24.ref.png new file mode 100644 index 0000000000..fd7d767865 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-color.svg.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-doc.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-doc.image16.ref.png new file mode 100644 index 0000000000..eb9acb0dec Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-doc.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-doc.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-doc.pdf.ref.png new file mode 100644 index 0000000000..9c8aa822a4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-doc.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-doc.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-doc.ps.ref.png new file mode 100644 index 0000000000..10a12ea5da Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-doc.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-doc.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-doc.ps.rgb24.ref.png new file mode 100644 index 0000000000..f3f4099f0f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-doc.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-doc.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-doc.ref.png new file mode 100644 index 0000000000..e7ecf7f1a7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-doc.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-doc.script.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-doc.script.ref.png new file mode 100644 index 0000000000..37ffb9dffa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-doc.script.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-doc.svg.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-doc.svg.rgb24.ref.png new file mode 100644 index 0000000000..791feb9091 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-doc.svg.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-fill.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-fill.image16.ref.png new file mode 100644 index 0000000000..8ab42ed195 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-fill.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-fill.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-fill.pdf.ref.png new file mode 100644 index 0000000000..135a251a71 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-fill.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-fill.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-fill.ps.ref.png new file mode 100644 index 0000000000..35512795d5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-fill.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-fill.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-fill.ps.rgb24.ref.png new file mode 100644 index 0000000000..91a0199d15 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-fill.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-fill.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-fill.ref.png new file mode 100644 index 0000000000..a72cdd1f29 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-fill.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-fill.script.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-fill.script.ref.png new file mode 100644 index 0000000000..46884dea6a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-fill.script.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-fill.svg.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-fill.svg.rgb24.ref.png new file mode 100644 index 0000000000..ac892036a6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-fill.svg.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-gradient.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-gradient.image16.ref.png new file mode 100644 index 0000000000..e6c5f410a0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-gradient.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-gradient.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-gradient.pdf.ref.png new file mode 100644 index 0000000000..52721c8ed7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-gradient.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-gradient.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-gradient.ps.ref.png new file mode 100644 index 0000000000..9ddb9ce9bb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-gradient.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-gradient.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-gradient.ps.rgb24.ref.png new file mode 100644 index 0000000000..bca01bf6b8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-gradient.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-gradient.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-gradient.ref.png new file mode 100644 index 0000000000..d647dc06ac Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-gradient.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-gradient.script.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-gradient.script.ref.png new file mode 100644 index 0000000000..d9cb57bd31 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-gradient.script.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-gradient.svg.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-gradient.svg.rgb24.ref.png new file mode 100644 index 0000000000..6bbb38a876 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-gradient.svg.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-path.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-path.image16.ref.png new file mode 100644 index 0000000000..bf6bde2bd7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-path.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-path.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-path.ps.ref.png new file mode 100644 index 0000000000..025febd2cd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-path.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-path.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-path.ps.rgb24.ref.png new file mode 100644 index 0000000000..4000c5ebd0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-path.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-path.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-path.ref.png new file mode 100644 index 0000000000..2667059cc5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-path.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-path.script.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-path.script.ref.png new file mode 100644 index 0000000000..e2557e83de Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-path.script.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-path.svg.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-path.svg.rgb24.ref.png new file mode 100644 index 0000000000..cc3f5f5d9c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-path.svg.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-shapes.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-shapes.image16.ref.png new file mode 100644 index 0000000000..9fe4113965 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-shapes.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-shapes.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-shapes.ps.ref.png new file mode 100644 index 0000000000..6dba36080c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-shapes.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-shapes.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-shapes.ps.rgb24.ref.png new file mode 100644 index 0000000000..f9fa25a88f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-shapes.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-shapes.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-shapes.ref.png new file mode 100644 index 0000000000..209e0ddb3c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-shapes.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-shapes.script.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-shapes.script.ref.png new file mode 100644 index 0000000000..e2557e83de Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-shapes.script.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-shapes.svg.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-shapes.svg.rgb24.ref.png new file mode 100644 index 0000000000..00fa79caa3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-shapes.svg.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-stroke.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-stroke.image16.ref.png new file mode 100644 index 0000000000..8316d7488a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-stroke.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-stroke.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-stroke.ps.ref.png new file mode 100644 index 0000000000..e8fb884bd2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-stroke.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-stroke.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-stroke.ps.rgb24.ref.png new file mode 100644 index 0000000000..987562ca87 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-stroke.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-stroke.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-stroke.ref.png new file mode 100644 index 0000000000..86f1ab9b67 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-stroke.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-stroke.script.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-stroke.script.ref.png new file mode 100644 index 0000000000..6efbe7e449 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-stroke.script.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-stroke.svg.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-stroke.svg.rgb24.ref.png new file mode 100644 index 0000000000..33818db81a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-stroke.svg.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-transform.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-transform.image16.ref.png new file mode 100644 index 0000000000..48c2aa9800 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-transform.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-transform.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-transform.pdf.ref.png new file mode 100644 index 0000000000..f528dd59f1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-transform.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-transform.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-transform.ps.ref.png new file mode 100644 index 0000000000..1b14939e85 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-transform.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-transform.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-transform.ps.rgb24.ref.png new file mode 100644 index 0000000000..41b9b63877 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-transform.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-transform.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-transform.ref.png new file mode 100644 index 0000000000..dcc372aacd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-transform.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-transform.script.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-transform.script.ref.png new file mode 100644 index 0000000000..e2557e83de Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-transform.script.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-transform.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-transform.svg.ref.png new file mode 100644 index 0000000000..6d2f606b09 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-transform.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-svg-render-transform.svg.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-transform.svg.rgb24.ref.png new file mode 100644 index 0000000000..872749cc64 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-svg-render-transform.svg.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-text-antialias-none.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-text-antialias-none.base.argb32.ref.png new file mode 100644 index 0000000000..c638c9ea66 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-text-antialias-none.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-text-antialias-none.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-text-antialias-none.base.rgb24.ref.png new file mode 100644 index 0000000000..c638c9ea66 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-text-antialias-none.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-text-antialias-none.ps2.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-text-antialias-none.ps2.argb32.ref.png new file mode 100644 index 0000000000..4f7ee8324d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-text-antialias-none.ps2.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-text-antialias-none.ps3.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-text-antialias-none.ps3.argb32.ref.png new file mode 100644 index 0000000000..4f7ee8324d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-text-antialias-none.ps3.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-text-antialias-none.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-text-antialias-none.ref.png new file mode 100644 index 0000000000..bae5d95349 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-text-antialias-none.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type1.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type1.base.argb32.ref.png new file mode 100644 index 0000000000..09c4cbbbe2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type1.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type1.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type1.base.rgb24.ref.png new file mode 100644 index 0000000000..09c4cbbbe2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type1.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type1.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type1.image16.ref.png new file mode 100644 index 0000000000..4985907c90 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type1.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type1.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type1.pdf.ref.png new file mode 100644 index 0000000000..1f52ff23bd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type1.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type1.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type1.ps.ref.png new file mode 100644 index 0000000000..bb99239b8f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type1.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type1.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type1.quartz.ref.png new file mode 100644 index 0000000000..5083ac5338 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type1.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type1.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type1.ref.png new file mode 100644 index 0000000000..7a5670ee65 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type1.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type1.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type1.traps.argb32.ref.png new file mode 100644 index 0000000000..09c4cbbbe2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type1.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type1.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type1.traps.rgb24.ref.png new file mode 100644 index 0000000000..09c4cbbbe2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type1.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type1.xfail.png b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type1.xfail.png new file mode 100644 index 0000000000..063bbd9672 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type1.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type3.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type3.base.argb32.ref.png new file mode 100644 index 0000000000..82374b70be Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type3.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type3.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type3.base.rgb24.ref.png new file mode 100644 index 0000000000..82374b70be Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type3.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type3.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type3.image16.ref.png new file mode 100644 index 0000000000..a5c3c1110d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type3.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type3.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type3.mask.argb32.ref.png new file mode 100644 index 0000000000..7f7b428c1f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type3.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type3.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type3.mask.rgb24.ref.png new file mode 100644 index 0000000000..7f7b428c1f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type3.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type3.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type3.pdf.ref.png new file mode 100644 index 0000000000..cec2547ec4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type3.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type3.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type3.ps.ref.png new file mode 100644 index 0000000000..11aed7da1c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type3.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type3.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type3.quartz.ref.png new file mode 100644 index 0000000000..08ee572846 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type3.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type3.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type3.ref.png new file mode 100644 index 0000000000..0db1c0c2ea Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type3.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type3.traps.argb32.ref.png new file mode 100644 index 0000000000..82374b70be Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type3.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type3.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type3.traps.rgb24.ref.png new file mode 100644 index 0000000000..82374b70be Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-text-vertical-layout-type3.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-variable-font.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-variable-font.image16.ref.png new file mode 100644 index 0000000000..94d4d63c42 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-variable-font.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-variable-font.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-variable-font.pdf.ref.png new file mode 100644 index 0000000000..f782a8ee41 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-variable-font.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-variable-font.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-variable-font.ps.ref.png new file mode 100644 index 0000000000..1e1fdf249b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-variable-font.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-variable-font.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-variable-font.ref.png new file mode 100644 index 0000000000..49050251ac Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-variable-font.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-variable-font.script.xfail.png b/local/recipes/libs/cairo/source/test/reference/ft-variable-font.script.xfail.png new file mode 100644 index 0000000000..8463a4a38f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-variable-font.script.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ft-variable-font.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/ft-variable-font.svg.ref.png new file mode 100644 index 0000000000..eeb99d7c97 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ft-variable-font.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/get-group-target.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/get-group-target.base.argb32.ref.png new file mode 100644 index 0000000000..d162775e7b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/get-group-target.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/get-group-target.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/get-group-target.base.rgb24.ref.png new file mode 100644 index 0000000000..d162775e7b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/get-group-target.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/get-group-target.ref.png b/local/recipes/libs/cairo/source/test/reference/get-group-target.ref.png new file mode 100644 index 0000000000..316a93f319 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/get-group-target.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/glyph-cache-pressure.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/glyph-cache-pressure.base.argb32.ref.png new file mode 100644 index 0000000000..a6e1b061f4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/glyph-cache-pressure.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/glyph-cache-pressure.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/glyph-cache-pressure.base.rgb24.ref.png new file mode 100644 index 0000000000..a6e1b061f4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/glyph-cache-pressure.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/glyph-cache-pressure.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/glyph-cache-pressure.image16.ref.png new file mode 100644 index 0000000000..f3985bdf09 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/glyph-cache-pressure.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/glyph-cache-pressure.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/glyph-cache-pressure.ps.ref.png new file mode 100644 index 0000000000..e537bc535e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/glyph-cache-pressure.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/glyph-cache-pressure.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/glyph-cache-pressure.quartz.ref.png new file mode 100644 index 0000000000..6291e84b43 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/glyph-cache-pressure.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/glyph-cache-pressure.ref.png b/local/recipes/libs/cairo/source/test/reference/glyph-cache-pressure.ref.png new file mode 100644 index 0000000000..a6e1b061f4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/glyph-cache-pressure.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/glyph-cache-pressure.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/glyph-cache-pressure.svg.ref.png new file mode 100644 index 0000000000..79ddf29aa8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/glyph-cache-pressure.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/glyph-path.image.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/glyph-path.image.argb32.ref.png new file mode 100644 index 0000000000..bf61b6581d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/glyph-path.image.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/glyph-path.image.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/glyph-path.image.rgb24.ref.png new file mode 100644 index 0000000000..bf61b6581d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/glyph-path.image.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/glyph-path.image16.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/glyph-path.image16.rgb24.ref.png new file mode 100644 index 0000000000..be94f8463b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/glyph-path.image16.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/gradient-alpha.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/gradient-alpha.base.argb32.ref.png new file mode 100644 index 0000000000..f64b26a76f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/gradient-alpha.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/gradient-alpha.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/gradient-alpha.base.rgb24.ref.png new file mode 100644 index 0000000000..3c7258d954 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/gradient-alpha.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/gradient-alpha.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/gradient-alpha.pdf.argb32.ref.png new file mode 100644 index 0000000000..48ab382c11 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/gradient-alpha.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/gradient-alpha.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/gradient-alpha.pdf.rgb24.ref.png new file mode 100644 index 0000000000..27b9d209b3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/gradient-alpha.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/gradient-alpha.ps2.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/gradient-alpha.ps2.argb32.ref.png new file mode 100644 index 0000000000..37eafba3ce Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/gradient-alpha.ps2.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/gradient-alpha.ps2.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/gradient-alpha.ps2.rgb24.ref.png new file mode 100644 index 0000000000..2432c29969 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/gradient-alpha.ps2.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/gradient-alpha.ps3.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/gradient-alpha.ps3.argb32.ref.png new file mode 100644 index 0000000000..37eafba3ce Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/gradient-alpha.ps3.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/gradient-alpha.ps3.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/gradient-alpha.ps3.rgb24.ref.png new file mode 100644 index 0000000000..2432c29969 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/gradient-alpha.ps3.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/gradient-alpha.ref.png b/local/recipes/libs/cairo/source/test/reference/gradient-alpha.ref.png new file mode 100644 index 0000000000..f64b26a76f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/gradient-alpha.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/gradient-alpha.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/gradient-alpha.svg.ref.png new file mode 100644 index 0000000000..399f59694a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/gradient-alpha.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/gradient-constant-alpha.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/gradient-constant-alpha.base.argb32.ref.png new file mode 100644 index 0000000000..7f49e2c6f5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/gradient-constant-alpha.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/gradient-constant-alpha.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/gradient-constant-alpha.base.rgb24.ref.png new file mode 100644 index 0000000000..69cd5963a1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/gradient-constant-alpha.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/gradient-constant-alpha.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/gradient-constant-alpha.pdf.argb32.ref.png new file mode 100644 index 0000000000..ad2fbdaa53 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/gradient-constant-alpha.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/gradient-constant-alpha.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/gradient-constant-alpha.pdf.rgb24.ref.png new file mode 100644 index 0000000000..b1cae2d8d4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/gradient-constant-alpha.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/gradient-constant-alpha.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/gradient-constant-alpha.ps3.ref.png new file mode 100644 index 0000000000..7089f4fdc6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/gradient-constant-alpha.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/gradient-constant-alpha.ps3.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/gradient-constant-alpha.ps3.rgb24.ref.png new file mode 100644 index 0000000000..5962925f21 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/gradient-constant-alpha.ps3.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/gradient-constant-alpha.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/gradient-constant-alpha.quartz.ref.png new file mode 100644 index 0000000000..5855b679d1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/gradient-constant-alpha.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/gradient-constant-alpha.ref.png b/local/recipes/libs/cairo/source/test/reference/gradient-constant-alpha.ref.png new file mode 100644 index 0000000000..7f49e2c6f5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/gradient-constant-alpha.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/gradient-constant-alpha.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/gradient-constant-alpha.svg.ref.png new file mode 100644 index 0000000000..45a19307fc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/gradient-constant-alpha.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/gradient-zero-stops-mask.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/gradient-zero-stops-mask.base.argb32.ref.png new file mode 100644 index 0000000000..0a50f4cacc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/gradient-zero-stops-mask.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/gradient-zero-stops-mask.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/gradient-zero-stops-mask.base.rgb24.ref.png new file mode 100644 index 0000000000..21465ce4a7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/gradient-zero-stops-mask.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/gradient-zero-stops-mask.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/gradient-zero-stops-mask.ps.rgb24.ref.png new file mode 100644 index 0000000000..21465ce4a7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/gradient-zero-stops-mask.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/gradient-zero-stops-mask.ref.png b/local/recipes/libs/cairo/source/test/reference/gradient-zero-stops-mask.ref.png new file mode 100644 index 0000000000..0a50f4cacc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/gradient-zero-stops-mask.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/gradient-zero-stops.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/gradient-zero-stops.base.argb32.ref.png new file mode 100644 index 0000000000..0a50f4cacc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/gradient-zero-stops.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/gradient-zero-stops.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/gradient-zero-stops.base.rgb24.ref.png new file mode 100644 index 0000000000..21465ce4a7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/gradient-zero-stops.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/gradient-zero-stops.ps.rgb24.png b/local/recipes/libs/cairo/source/test/reference/gradient-zero-stops.ps.rgb24.png new file mode 100644 index 0000000000..21465ce4a7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/gradient-zero-stops.ps.rgb24.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/gradient-zero-stops.ref.png b/local/recipes/libs/cairo/source/test/reference/gradient-zero-stops.ref.png new file mode 100644 index 0000000000..3f1867037e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/gradient-zero-stops.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/group-clip.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/group-clip.base.argb32.ref.png new file mode 100644 index 0000000000..7b8a7532f7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/group-clip.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/group-clip.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/group-clip.base.rgb24.ref.png new file mode 100644 index 0000000000..7b8a7532f7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/group-clip.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/group-clip.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/group-clip.image16.ref.png new file mode 100644 index 0000000000..98b66efa3c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/group-clip.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/group-clip.ref.png b/local/recipes/libs/cairo/source/test/reference/group-clip.ref.png new file mode 100644 index 0000000000..7b8a7532f7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/group-clip.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/group-paint.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/group-paint.base.argb32.ref.png new file mode 100644 index 0000000000..1ed070cae0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/group-paint.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/group-paint.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/group-paint.base.rgb24.ref.png new file mode 100644 index 0000000000..1ed070cae0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/group-paint.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/group-paint.ref.png b/local/recipes/libs/cairo/source/test/reference/group-paint.ref.png new file mode 100644 index 0000000000..f2e111b88e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/group-paint.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/group-unaligned.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/group-unaligned.base.argb32.ref.png new file mode 100644 index 0000000000..451e1713f8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/group-unaligned.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/group-unaligned.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/group-unaligned.base.rgb24.ref.png new file mode 100644 index 0000000000..451e1713f8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/group-unaligned.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/group-unaligned.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/group-unaligned.image16.ref.png new file mode 100644 index 0000000000..6a60a6ea47 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/group-unaligned.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/group-unaligned.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/group-unaligned.ps.ref.png new file mode 100644 index 0000000000..2cd04f4164 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/group-unaligned.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/group-unaligned.ps.rgb24.xfail.png b/local/recipes/libs/cairo/source/test/reference/group-unaligned.ps.rgb24.xfail.png new file mode 100644 index 0000000000..5672cb0bf5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/group-unaligned.ps.rgb24.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/group-unaligned.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/group-unaligned.quartz.ref.png new file mode 100644 index 0000000000..36f37ccd11 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/group-unaligned.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/group-unaligned.ref.png b/local/recipes/libs/cairo/source/test/reference/group-unaligned.ref.png new file mode 100644 index 0000000000..6356e6c140 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/group-unaligned.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/group-unaligned.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/group-unaligned.svg.ref.png new file mode 100644 index 0000000000..4dd1b7194f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/group-unaligned.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/group-unaligned.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/group-unaligned.traps.argb32.ref.png new file mode 100644 index 0000000000..451e1713f8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/group-unaligned.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/group-unaligned.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/group-unaligned.traps.rgb24.ref.png new file mode 100644 index 0000000000..451e1713f8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/group-unaligned.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/group-unaligned.xlib-fallback.ref.png b/local/recipes/libs/cairo/source/test/reference/group-unaligned.xlib-fallback.ref.png new file mode 100644 index 0000000000..5ddbc164f5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/group-unaligned.xlib-fallback.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic-incorrect.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic-incorrect.image16.ref.png new file mode 100644 index 0000000000..c69a90d375 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic-incorrect.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic-incorrect.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic-incorrect.pdf.ref.png new file mode 100644 index 0000000000..37acfaa559 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic-incorrect.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic-incorrect.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic-incorrect.quartz.ref.png new file mode 100644 index 0000000000..ec6ded3f3f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic-incorrect.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic-incorrect.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic-incorrect.ref.png new file mode 100644 index 0000000000..54929db44e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic-incorrect.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic-incorrect.svg11.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic-incorrect.svg11.argb32.ref.png new file mode 100644 index 0000000000..22b8cd51ca Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic-incorrect.svg11.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic-incorrect.svg11.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic-incorrect.svg11.rgb24.ref.png new file mode 100644 index 0000000000..d0f0f2e255 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic-incorrect.svg11.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic-incorrect.xcb-window&.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic-incorrect.xcb-window&.ref.png new file mode 100644 index 0000000000..6c498ab469 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic-incorrect.xcb-window&.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic-incorrect.xcb-window.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic-incorrect.xcb-window.ref.png new file mode 100644 index 0000000000..6c498ab469 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic-incorrect.xcb-window.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic-incorrect.xcb.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic-incorrect.xcb.ref.png new file mode 100644 index 0000000000..6c498ab469 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic-incorrect.xcb.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic-incorrect.xlib-window.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic-incorrect.xlib-window.ref.png new file mode 100644 index 0000000000..042715325b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic-incorrect.xlib-window.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic-incorrect.xlib.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic-incorrect.xlib.ref.png new file mode 100644 index 0000000000..042715325b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic-incorrect.xlib.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic.image16.ref.png new file mode 100644 index 0000000000..a5a7217ca8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic.pdf.ref.png new file mode 100644 index 0000000000..acb2ffbcfd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic.quartz.ref.png new file mode 100644 index 0000000000..ebf9fd64d1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic.ref.png new file mode 100644 index 0000000000..bb3ba77935 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic.xcb-window&.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic.xcb-window&.ref.png new file mode 100644 index 0000000000..41a56f8086 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic.xcb-window&.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic.xcb-window.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic.xcb-window.ref.png new file mode 100644 index 0000000000..41a56f8086 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic.xcb-window.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic.xcb.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic.xcb.ref.png new file mode 100644 index 0000000000..41a56f8086 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic.xcb.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic.xlib-window.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic.xlib-window.ref.png new file mode 100644 index 0000000000..b84c2f449a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic.xlib-window.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic.xlib.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic.xlib.ref.png new file mode 100644 index 0000000000..b84c2f449a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-anisotropic.xlib.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-big.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-big.image16.ref.png new file mode 100644 index 0000000000..9d63e8e1b0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-big.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-big.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-big.pdf.ref.png new file mode 100644 index 0000000000..6ed7e7ccf6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-big.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-big.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-big.quartz.ref.png new file mode 100644 index 0000000000..1f153dd702 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-big.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-big.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-big.ref.png new file mode 100644 index 0000000000..98ea2428fa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-big.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-big.xcb-window&.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-big.xcb-window&.ref.png new file mode 100644 index 0000000000..a662668db9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-big.xcb-window&.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-big.xcb-window.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-big.xcb-window.ref.png new file mode 100644 index 0000000000..a662668db9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-big.xcb-window.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-big.xcb.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-big.xcb.ref.png new file mode 100644 index 0000000000..a662668db9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-big.xcb.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-big.xlib-window.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-big.xlib-window.ref.png new file mode 100644 index 0000000000..ce6aaaeed3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-big.xlib-window.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-big.xlib.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-big.xlib.ref.png new file mode 100644 index 0000000000..ce6aaaeed3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-big.xlib.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-scaled.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-scaled.image16.ref.png new file mode 100644 index 0000000000..5b82d0dc8a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-scaled.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-scaled.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-scaled.pdf.ref.png new file mode 100644 index 0000000000..ef0973242f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-scaled.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-scaled.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-scaled.quartz.ref.png new file mode 100644 index 0000000000..c0653a12c0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-scaled.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-scaled.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-scaled.ref.png new file mode 100644 index 0000000000..f059b4288f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-scaled.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-scaled.svg11.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-scaled.svg11.ref.png new file mode 100644 index 0000000000..f45367bb0d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-scaled.svg11.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-scaled.xcb-window&.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-scaled.xcb-window&.ref.png new file mode 100644 index 0000000000..22ba5e2910 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-scaled.xcb-window&.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-scaled.xcb-window.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-scaled.xcb-window.ref.png new file mode 100644 index 0000000000..22ba5e2910 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-scaled.xcb-window.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-scaled.xcb.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-scaled.xcb.ref.png new file mode 100644 index 0000000000..22ba5e2910 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-scaled.xcb.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-scaled.xlib-window.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-scaled.xlib-window.ref.png new file mode 100644 index 0000000000..a59338584a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-scaled.xlib-window.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline-scaled.xlib.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline-scaled.xlib.ref.png new file mode 100644 index 0000000000..a59338584a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline-scaled.xlib.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline.image16.ref.png new file mode 100644 index 0000000000..fa3318cb62 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline.pdf.ref.png new file mode 100644 index 0000000000..0a0ecb33ee Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline.quartz.ref.png new file mode 100644 index 0000000000..e51ea63c9a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline.ref.png new file mode 100644 index 0000000000..e336831156 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline.svg11.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline.svg11.ref.png new file mode 100644 index 0000000000..834f3a43a1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline.svg11.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline.xcb-window&.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline.xcb-window&.ref.png new file mode 100644 index 0000000000..1175b14a97 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline.xcb-window&.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline.xcb-window.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline.xcb-window.ref.png new file mode 100644 index 0000000000..1175b14a97 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline.xcb-window.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline.xcb.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline.xcb.ref.png new file mode 100644 index 0000000000..1175b14a97 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline.xcb.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline.xlib-window.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline.xlib-window.ref.png new file mode 100644 index 0000000000..ed55291f30 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline.xlib-window.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hairline.xlib.ref.png b/local/recipes/libs/cairo/source/test/reference/hairline.xlib.ref.png new file mode 100644 index 0000000000..ed55291f30 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hairline.xlib.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/halo-transform.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/halo-transform.base.argb32.ref.png new file mode 100644 index 0000000000..45cb90ff00 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/halo-transform.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/halo-transform.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/halo-transform.base.rgb24.ref.png new file mode 100644 index 0000000000..45cb90ff00 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/halo-transform.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/halo-transform.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/halo-transform.image16.ref.png new file mode 100644 index 0000000000..b2268f01fa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/halo-transform.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/halo-transform.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/halo-transform.ps.ref.png new file mode 100644 index 0000000000..f1d2e2bf16 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/halo-transform.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/halo-transform.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/halo-transform.quartz.ref.png new file mode 100644 index 0000000000..802b04ffe4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/halo-transform.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/halo-transform.ref.png b/local/recipes/libs/cairo/source/test/reference/halo-transform.ref.png new file mode 100644 index 0000000000..07abc4211b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/halo-transform.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/halo-transform.traps.ref.png b/local/recipes/libs/cairo/source/test/reference/halo-transform.traps.ref.png new file mode 100644 index 0000000000..45cb90ff00 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/halo-transform.traps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/halo.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/halo.base.argb32.ref.png new file mode 100644 index 0000000000..c915a242be Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/halo.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/halo.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/halo.base.rgb24.ref.png new file mode 100644 index 0000000000..c915a242be Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/halo.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/halo.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/halo.image16.ref.png new file mode 100644 index 0000000000..a813cd9211 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/halo.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/halo.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/halo.mask.argb32.ref.png new file mode 100644 index 0000000000..191ee47946 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/halo.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/halo.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/halo.mask.rgb24.ref.png new file mode 100644 index 0000000000..191ee47946 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/halo.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/halo.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/halo.ps.ref.png new file mode 100644 index 0000000000..f8d025f554 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/halo.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/halo.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/halo.quartz.ref.png new file mode 100644 index 0000000000..cffa79a6f7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/halo.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/halo.ref.png b/local/recipes/libs/cairo/source/test/reference/halo.ref.png new file mode 100644 index 0000000000..a393199f32 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/halo.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/halo.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/halo.svg.ref.png new file mode 100644 index 0000000000..af31ccfd6b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/halo.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/halo.traps.ref.png b/local/recipes/libs/cairo/source/test/reference/halo.traps.ref.png new file mode 100644 index 0000000000..c915a242be Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/halo.traps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hatchings.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/hatchings.base.argb32.ref.png new file mode 100644 index 0000000000..73e156dd3c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hatchings.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hatchings.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/hatchings.base.rgb24.ref.png new file mode 100644 index 0000000000..73e156dd3c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hatchings.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hatchings.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/hatchings.mask.argb32.ref.png new file mode 100644 index 0000000000..77fe853a82 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hatchings.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hatchings.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/hatchings.mask.rgb24.ref.png new file mode 100644 index 0000000000..77fe853a82 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hatchings.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hatchings.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/hatchings.quartz.ref.png new file mode 100644 index 0000000000..02b6a8e9a1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hatchings.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hatchings.ref.png b/local/recipes/libs/cairo/source/test/reference/hatchings.ref.png new file mode 100644 index 0000000000..215d61fa80 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hatchings.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hatchings.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/hatchings.traps.argb32.ref.png new file mode 100644 index 0000000000..3b72949c1a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hatchings.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/hatchings.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/hatchings.traps.rgb24.ref.png new file mode 100644 index 0000000000..3b72949c1a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/hatchings.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/horizontal-clip.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/horizontal-clip.base.argb32.ref.png new file mode 100644 index 0000000000..43dd07f151 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/horizontal-clip.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/horizontal-clip.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/horizontal-clip.base.rgb24.ref.png new file mode 100644 index 0000000000..43dd07f151 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/horizontal-clip.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/horizontal-clip.ref.png b/local/recipes/libs/cairo/source/test/reference/horizontal-clip.ref.png new file mode 100644 index 0000000000..43dd07f151 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/horizontal-clip.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/huge-linear.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/huge-linear.base.argb32.ref.png new file mode 100644 index 0000000000..f89217b826 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/huge-linear.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/huge-linear.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/huge-linear.base.rgb24.ref.png new file mode 100644 index 0000000000..f89217b826 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/huge-linear.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/huge-linear.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/huge-linear.image16.ref.png new file mode 100644 index 0000000000..56dc58aca6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/huge-linear.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/huge-linear.pdf.xfail.png b/local/recipes/libs/cairo/source/test/reference/huge-linear.pdf.xfail.png new file mode 100644 index 0000000000..db4cf2e9bb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/huge-linear.pdf.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/huge-linear.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/huge-linear.ps3.ref.png new file mode 100644 index 0000000000..d55239bf49 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/huge-linear.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/huge-linear.ref.png b/local/recipes/libs/cairo/source/test/reference/huge-linear.ref.png new file mode 100644 index 0000000000..c20a8b7de8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/huge-linear.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/huge-radial.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/huge-radial.base.argb32.ref.png new file mode 100644 index 0000000000..541bb309a6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/huge-radial.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/huge-radial.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/huge-radial.base.rgb24.ref.png new file mode 100644 index 0000000000..541bb309a6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/huge-radial.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/huge-radial.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/huge-radial.image16.ref.png new file mode 100644 index 0000000000..3913190fed Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/huge-radial.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/huge-radial.pdf.xfail.png b/local/recipes/libs/cairo/source/test/reference/huge-radial.pdf.xfail.png new file mode 100644 index 0000000000..db4cf2e9bb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/huge-radial.pdf.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/huge-radial.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/huge-radial.ps3.ref.png new file mode 100644 index 0000000000..c2319487b0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/huge-radial.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/huge-radial.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/huge-radial.quartz.ref.png new file mode 100644 index 0000000000..ec1db2917c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/huge-radial.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/huge-radial.ref.png b/local/recipes/libs/cairo/source/test/reference/huge-radial.ref.png new file mode 100644 index 0000000000..8246ffffc6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/huge-radial.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/huge-radial.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/huge-radial.svg.ref.png new file mode 100644 index 0000000000..3bed71d8ce Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/huge-radial.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/image-bug-710072-aligned.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/image-bug-710072-aligned.base.argb32.ref.png new file mode 100644 index 0000000000..42abd20544 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/image-bug-710072-aligned.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/image-bug-710072-aligned.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/image-bug-710072-aligned.base.rgb24.ref.png new file mode 100644 index 0000000000..42abd20544 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/image-bug-710072-aligned.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/image-bug-710072-aligned.ref.png b/local/recipes/libs/cairo/source/test/reference/image-bug-710072-aligned.ref.png new file mode 100644 index 0000000000..42abd20544 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/image-bug-710072-aligned.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/image-bug-710072-unaligned.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/image-bug-710072-unaligned.base.argb32.ref.png new file mode 100644 index 0000000000..0a5a6e6cf8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/image-bug-710072-unaligned.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/image-bug-710072-unaligned.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/image-bug-710072-unaligned.base.rgb24.ref.png new file mode 100644 index 0000000000..0a5a6e6cf8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/image-bug-710072-unaligned.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/image-bug-710072-unaligned.ref.png b/local/recipes/libs/cairo/source/test/reference/image-bug-710072-unaligned.ref.png new file mode 100644 index 0000000000..13efa30f83 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/image-bug-710072-unaligned.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/image-bug-710072-unaligned.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/image-bug-710072-unaligned.traps.argb32.ref.png new file mode 100644 index 0000000000..0a5a6e6cf8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/image-bug-710072-unaligned.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/image-bug-710072-unaligned.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/image-bug-710072-unaligned.traps.rgb24.ref.png new file mode 100644 index 0000000000..0a5a6e6cf8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/image-bug-710072-unaligned.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/image-bug-710072-unaligned.xlib-fallback.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/image-bug-710072-unaligned.xlib-fallback.rgb24.ref.png new file mode 100644 index 0000000000..0a5a6e6cf8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/image-bug-710072-unaligned.xlib-fallback.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/image-bug-710072-unaligned.xlib-window.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/image-bug-710072-unaligned.xlib-window.rgb24.ref.png new file mode 100644 index 0000000000..0a5a6e6cf8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/image-bug-710072-unaligned.xlib-window.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/image-surface-source.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/image-surface-source.base.argb32.ref.png new file mode 100644 index 0000000000..018297208e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/image-surface-source.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/image-surface-source.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/image-surface-source.base.rgb24.ref.png new file mode 100644 index 0000000000..0d68a82cc2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/image-surface-source.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/image-surface-source.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/image-surface-source.image16.ref.png new file mode 100644 index 0000000000..2a7460e284 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/image-surface-source.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/image-surface-source.ps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/image-surface-source.ps.argb32.ref.png new file mode 100644 index 0000000000..b69f5bb9d8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/image-surface-source.ps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/image-surface-source.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/image-surface-source.ps.rgb24.ref.png new file mode 100644 index 0000000000..d9af4f8623 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/image-surface-source.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/image-surface-source.ref.png b/local/recipes/libs/cairo/source/test/reference/image-surface-source.ref.png new file mode 100644 index 0000000000..018297208e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/image-surface-source.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/implicit-close.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/implicit-close.base.argb32.ref.png new file mode 100644 index 0000000000..fdd7561109 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/implicit-close.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/implicit-close.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/implicit-close.base.rgb24.ref.png new file mode 100644 index 0000000000..fdd7561109 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/implicit-close.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/implicit-close.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/implicit-close.ps.ref.png new file mode 100644 index 0000000000..66baf2480d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/implicit-close.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/implicit-close.ref.png b/local/recipes/libs/cairo/source/test/reference/implicit-close.ref.png new file mode 100644 index 0000000000..f15f8a3a03 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/implicit-close.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/implicit-close.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/implicit-close.traps.argb32.ref.png new file mode 100644 index 0000000000..fdd7561109 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/implicit-close.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/implicit-close.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/implicit-close.traps.rgb24.ref.png new file mode 100644 index 0000000000..fdd7561109 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/implicit-close.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/infinite-join.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/infinite-join.base.argb32.ref.png new file mode 100644 index 0000000000..9e7572b931 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/infinite-join.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/infinite-join.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/infinite-join.base.rgb24.ref.png new file mode 100644 index 0000000000..9e7572b931 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/infinite-join.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/infinite-join.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/infinite-join.pdf.ref.png new file mode 100644 index 0000000000..f40b4a487e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/infinite-join.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/infinite-join.ps2.ref.png b/local/recipes/libs/cairo/source/test/reference/infinite-join.ps2.ref.png new file mode 100644 index 0000000000..6fba8f4b1f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/infinite-join.ps2.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/infinite-join.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/infinite-join.ps3.ref.png new file mode 100644 index 0000000000..6fba8f4b1f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/infinite-join.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/infinite-join.ref.png b/local/recipes/libs/cairo/source/test/reference/infinite-join.ref.png new file mode 100644 index 0000000000..54a9112410 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/infinite-join.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/infinite-join.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/infinite-join.svg.ref.png new file mode 100644 index 0000000000..15038bd6e5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/infinite-join.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/infinite-join.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/infinite-join.traps.argb32.ref.png new file mode 100644 index 0000000000..9e7572b931 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/infinite-join.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/infinite-join.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/infinite-join.traps.rgb24.ref.png new file mode 100644 index 0000000000..9e7572b931 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/infinite-join.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/inverse-text.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/inverse-text.base.argb32.ref.png new file mode 100644 index 0000000000..b7bbb972f1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/inverse-text.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/inverse-text.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/inverse-text.base.rgb24.ref.png new file mode 100644 index 0000000000..b7bbb972f1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/inverse-text.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/inverse-text.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/inverse-text.mask.argb32.ref.png new file mode 100644 index 0000000000..b7bbb972f1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/inverse-text.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/inverse-text.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/inverse-text.mask.rgb24.ref.png new file mode 100644 index 0000000000..b7bbb972f1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/inverse-text.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/inverse-text.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/inverse-text.ps.ref.png new file mode 100644 index 0000000000..07071747a3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/inverse-text.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/inverse-text.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/inverse-text.quartz.ref.png new file mode 100644 index 0000000000..f57f45035d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/inverse-text.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/inverse-text.ref.png b/local/recipes/libs/cairo/source/test/reference/inverse-text.ref.png new file mode 100644 index 0000000000..b7bbb972f1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/inverse-text.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/inverse-text.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/inverse-text.svg.ref.png new file mode 100644 index 0000000000..276187eab0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/inverse-text.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/inverted-clip.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/inverted-clip.argb32.ref.png new file mode 100644 index 0000000000..f97d377d46 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/inverted-clip.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/inverted-clip.base.xfail.png b/local/recipes/libs/cairo/source/test/reference/inverted-clip.base.xfail.png new file mode 100644 index 0000000000..080b7825bd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/inverted-clip.base.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/inverted-clip.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/inverted-clip.quartz.rgb24.ref.png new file mode 100644 index 0000000000..844e467c0f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/inverted-clip.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/inverted-clip.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/inverted-clip.rgb24.ref.png new file mode 100644 index 0000000000..df945ec2eb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/inverted-clip.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/inverted-clip.traps.xfail.png b/local/recipes/libs/cairo/source/test/reference/inverted-clip.traps.xfail.png new file mode 100644 index 0000000000..5962795ac0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/inverted-clip.traps.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/inverted-clip.xfail.png b/local/recipes/libs/cairo/source/test/reference/inverted-clip.xfail.png new file mode 100644 index 0000000000..080b7825bd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/inverted-clip.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/joins-loop.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/joins-loop.base.argb32.ref.png new file mode 100644 index 0000000000..95400dfbd3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/joins-loop.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/joins-loop.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/joins-loop.base.rgb24.ref.png new file mode 100644 index 0000000000..95400dfbd3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/joins-loop.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/joins-loop.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/joins-loop.ps.ref.png new file mode 100644 index 0000000000..37b833a436 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/joins-loop.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/joins-loop.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/joins-loop.quartz.ref.png new file mode 100644 index 0000000000..f16050c907 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/joins-loop.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/joins-loop.ref.png b/local/recipes/libs/cairo/source/test/reference/joins-loop.ref.png new file mode 100644 index 0000000000..ecd6b23d0e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/joins-loop.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/joins-loop.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/joins-loop.traps.argb32.ref.png new file mode 100644 index 0000000000..95400dfbd3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/joins-loop.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/joins-loop.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/joins-loop.traps.rgb24.ref.png new file mode 100644 index 0000000000..95400dfbd3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/joins-loop.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/joins-retrace.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/joins-retrace.base.argb32.ref.png new file mode 100644 index 0000000000..efbf91a6b6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/joins-retrace.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/joins-retrace.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/joins-retrace.base.rgb24.ref.png new file mode 100644 index 0000000000..efbf91a6b6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/joins-retrace.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/joins-retrace.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/joins-retrace.mask.argb32.ref.png new file mode 100644 index 0000000000..22b0ecf9ae Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/joins-retrace.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/joins-retrace.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/joins-retrace.mask.rgb24.ref.png new file mode 100644 index 0000000000..22b0ecf9ae Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/joins-retrace.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/joins-retrace.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/joins-retrace.quartz.ref.png new file mode 100644 index 0000000000..86005c1c46 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/joins-retrace.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/joins-retrace.ref.png b/local/recipes/libs/cairo/source/test/reference/joins-retrace.ref.png new file mode 100644 index 0000000000..c21c80a6db Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/joins-retrace.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/joins-retrace.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/joins-retrace.traps.argb32.ref.png new file mode 100644 index 0000000000..efbf91a6b6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/joins-retrace.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/joins-retrace.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/joins-retrace.traps.rgb24.ref.png new file mode 100644 index 0000000000..efbf91a6b6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/joins-retrace.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/joins-star.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/joins-star.base.argb32.ref.png new file mode 100644 index 0000000000..f1de705c38 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/joins-star.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/joins-star.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/joins-star.base.rgb24.ref.png new file mode 100644 index 0000000000..f1de705c38 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/joins-star.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/joins-star.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/joins-star.ps.ref.png new file mode 100644 index 0000000000..44ad65a921 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/joins-star.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/joins-star.ref.png b/local/recipes/libs/cairo/source/test/reference/joins-star.ref.png new file mode 100644 index 0000000000..6fea13e3ec Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/joins-star.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/joins-star.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/joins-star.traps.argb32.ref.png new file mode 100644 index 0000000000..f1de705c38 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/joins-star.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/joins-star.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/joins-star.traps.rgb24.ref.png new file mode 100644 index 0000000000..f1de705c38 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/joins-star.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/joins.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/joins.base.argb32.ref.png new file mode 100644 index 0000000000..0b190c22b4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/joins.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/joins.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/joins.base.rgb24.ref.png new file mode 100644 index 0000000000..0b190c22b4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/joins.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/joins.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/joins.image16.ref.png new file mode 100644 index 0000000000..57f9bb15f2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/joins.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/joins.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/joins.mask.argb32.ref.png new file mode 100644 index 0000000000..a1d069d3d4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/joins.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/joins.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/joins.mask.rgb24.ref.png new file mode 100644 index 0000000000..a1d069d3d4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/joins.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/joins.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/joins.pdf.argb32.ref.png new file mode 100644 index 0000000000..7ad9fb92af Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/joins.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/joins.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/joins.pdf.rgb24.ref.png new file mode 100644 index 0000000000..7ad9fb92af Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/joins.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/joins.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/joins.ps.ref.png new file mode 100644 index 0000000000..0d5adea014 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/joins.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/joins.ref.png b/local/recipes/libs/cairo/source/test/reference/joins.ref.png new file mode 100644 index 0000000000..d1e34fece0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/joins.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/joins.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/joins.svg.ref.png new file mode 100644 index 0000000000..7ad9fb92af Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/joins.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/joins.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/joins.traps.argb32.ref.png new file mode 100644 index 0000000000..0b190c22b4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/joins.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/joins.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/joins.traps.rgb24.ref.png new file mode 100644 index 0000000000..0b190c22b4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/joins.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/large-clip.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/large-clip.base.argb32.ref.png new file mode 100644 index 0000000000..3c3464bed8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/large-clip.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/large-clip.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/large-clip.base.rgb24.ref.png new file mode 100644 index 0000000000..3c3464bed8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/large-clip.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/large-clip.ref.png b/local/recipes/libs/cairo/source/test/reference/large-clip.ref.png new file mode 100644 index 0000000000..9e46d2d5f6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/large-clip.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/large-font.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/large-font.base.argb32.ref.png new file mode 100644 index 0000000000..503061a9e2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/large-font.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/large-font.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/large-font.base.rgb24.ref.png new file mode 100644 index 0000000000..503061a9e2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/large-font.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/large-font.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/large-font.image16.ref.png new file mode 100644 index 0000000000..d5d11a5b7e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/large-font.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/large-font.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/large-font.ps.ref.png new file mode 100644 index 0000000000..b4fba170e9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/large-font.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/large-font.ref.png b/local/recipes/libs/cairo/source/test/reference/large-font.ref.png new file mode 100644 index 0000000000..da5c43114d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/large-font.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/large-font.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/large-font.svg.ref.png new file mode 100644 index 0000000000..ced43d4472 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/large-font.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/large-source-roi.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/large-source-roi.base.argb32.ref.png new file mode 100644 index 0000000000..216a065e1f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/large-source-roi.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/large-source-roi.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/large-source-roi.base.rgb24.ref.png new file mode 100644 index 0000000000..216a065e1f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/large-source-roi.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/large-source-roi.ref.png b/local/recipes/libs/cairo/source/test/reference/large-source-roi.ref.png new file mode 100644 index 0000000000..b8dc8b1b65 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/large-source-roi.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/large-source.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/large-source.base.argb32.ref.png new file mode 100644 index 0000000000..a54455fbb2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/large-source.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/large-source.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/large-source.base.rgb24.ref.png new file mode 100644 index 0000000000..a54455fbb2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/large-source.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/large-source.ref.png b/local/recipes/libs/cairo/source/test/reference/large-source.ref.png new file mode 100644 index 0000000000..5d96dd3232 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/large-source.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/large-twin-antialias-mixed.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/large-twin-antialias-mixed.base.argb32.ref.png new file mode 100644 index 0000000000..a0b265f337 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/large-twin-antialias-mixed.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/large-twin-antialias-mixed.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/large-twin-antialias-mixed.base.rgb24.ref.png new file mode 100644 index 0000000000..a0b265f337 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/large-twin-antialias-mixed.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/large-twin-antialias-mixed.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/large-twin-antialias-mixed.image16.ref.png new file mode 100644 index 0000000000..93f071ee4d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/large-twin-antialias-mixed.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/large-twin-antialias-mixed.ref.png b/local/recipes/libs/cairo/source/test/reference/large-twin-antialias-mixed.ref.png new file mode 100644 index 0000000000..73755ab520 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/large-twin-antialias-mixed.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/large-twin-antialias-mixed.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/large-twin-antialias-mixed.traps.argb32.ref.png new file mode 100644 index 0000000000..a0b265f337 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/large-twin-antialias-mixed.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/large-twin-antialias-mixed.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/large-twin-antialias-mixed.traps.rgb24.ref.png new file mode 100644 index 0000000000..a0b265f337 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/large-twin-antialias-mixed.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaks-set-scaled-font.ref.png b/local/recipes/libs/cairo/source/test/reference/leaks-set-scaled-font.ref.png new file mode 100644 index 0000000000..7d5589c1d7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaks-set-scaled-font.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-dash.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/leaky-dash.base.argb32.ref.png new file mode 100644 index 0000000000..0973ece7e5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-dash.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-dash.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/leaky-dash.base.rgb24.ref.png new file mode 100644 index 0000000000..0973ece7e5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-dash.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-dash.ps2.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/leaky-dash.ps2.argb32.ref.png new file mode 100644 index 0000000000..93b8640a96 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-dash.ps2.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-dash.ps2.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/leaky-dash.ps2.rgb24.ref.png new file mode 100644 index 0000000000..c11eb48076 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-dash.ps2.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-dash.ps3.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/leaky-dash.ps3.argb32.ref.png new file mode 100644 index 0000000000..93b8640a96 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-dash.ps3.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-dash.ps3.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/leaky-dash.ps3.rgb24.ref.png new file mode 100644 index 0000000000..c11eb48076 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-dash.ps3.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-dash.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/leaky-dash.quartz.xfail.png new file mode 100644 index 0000000000..96928195a1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-dash.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-dash.ref.png b/local/recipes/libs/cairo/source/test/reference/leaky-dash.ref.png new file mode 100644 index 0000000000..87facc5515 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-dash.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-dashed-rectangle.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-rectangle.base.argb32.ref.png new file mode 100644 index 0000000000..de35420984 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-rectangle.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-dashed-rectangle.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-rectangle.base.rgb24.ref.png new file mode 100644 index 0000000000..de35420984 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-rectangle.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-dashed-rectangle.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-rectangle.image16.ref.png new file mode 100644 index 0000000000..f61db4c29f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-rectangle.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-dashed-rectangle.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-rectangle.pdf.ref.png new file mode 100644 index 0000000000..72efd49545 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-rectangle.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-dashed-rectangle.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-rectangle.ps.ref.png new file mode 100644 index 0000000000..1e0a1388cb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-rectangle.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-dashed-rectangle.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-rectangle.quartz.ref.png new file mode 100644 index 0000000000..fad8588fe1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-rectangle.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-dashed-rectangle.ref.png b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-rectangle.ref.png new file mode 100644 index 0000000000..05f45846aa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-rectangle.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-dashed-rectangle.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-rectangle.traps.argb32.ref.png new file mode 100644 index 0000000000..de35420984 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-rectangle.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-dashed-rectangle.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-rectangle.traps.rgb24.ref.png new file mode 100644 index 0000000000..de35420984 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-rectangle.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-dashed-stroke.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-stroke.base.argb32.ref.png new file mode 100644 index 0000000000..da6807f779 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-stroke.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-dashed-stroke.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-stroke.base.rgb24.ref.png new file mode 100644 index 0000000000..da6807f779 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-stroke.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-dashed-stroke.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-stroke.image16.ref.png new file mode 100644 index 0000000000..f90bb23756 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-stroke.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-dashed-stroke.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-stroke.pdf.ref.png new file mode 100644 index 0000000000..6d3d9818a0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-stroke.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-dashed-stroke.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-stroke.ps.ref.png new file mode 100644 index 0000000000..7d581e916e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-stroke.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-dashed-stroke.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-stroke.quartz.ref.png new file mode 100644 index 0000000000..adbfd612ab Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-stroke.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-dashed-stroke.ref.png b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-stroke.ref.png new file mode 100644 index 0000000000..1b8569244f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-stroke.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-dashed-stroke.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-stroke.svg.ref.png new file mode 100644 index 0000000000..6d3d9818a0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-stroke.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-dashed-stroke.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-stroke.traps.argb32.ref.png new file mode 100644 index 0000000000..da6807f779 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-stroke.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-dashed-stroke.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-stroke.traps.rgb24.ref.png new file mode 100644 index 0000000000..da6807f779 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-dashed-stroke.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-polygon.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/leaky-polygon.base.argb32.ref.png new file mode 100644 index 0000000000..1cb7a3cac0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-polygon.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-polygon.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/leaky-polygon.base.rgb24.ref.png new file mode 100644 index 0000000000..1cb7a3cac0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-polygon.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-polygon.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/leaky-polygon.image16.ref.png new file mode 100644 index 0000000000..e91d0fa34d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-polygon.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-polygon.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/leaky-polygon.pdf.ref.png new file mode 100644 index 0000000000..db32c0c8ef Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-polygon.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-polygon.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/leaky-polygon.ps.ref.png new file mode 100644 index 0000000000..dd8a104347 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-polygon.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-polygon.ref.png b/local/recipes/libs/cairo/source/test/reference/leaky-polygon.ref.png new file mode 100644 index 0000000000..d2a06a3cc7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-polygon.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-polygon.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/leaky-polygon.svg.ref.png new file mode 100644 index 0000000000..db32c0c8ef Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-polygon.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-polygon.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/leaky-polygon.traps.argb32.ref.png new file mode 100644 index 0000000000..1cb7a3cac0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-polygon.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/leaky-polygon.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/leaky-polygon.traps.rgb24.ref.png new file mode 100644 index 0000000000..1cb7a3cac0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/leaky-polygon.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-dashed.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-dashed.base.argb32.ref.png new file mode 100644 index 0000000000..e6cdcc2f75 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-dashed.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-dashed.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-dashed.base.rgb24.ref.png new file mode 100644 index 0000000000..e6cdcc2f75 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-dashed.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-dashed.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-dashed.mask.argb32.ref.png new file mode 100644 index 0000000000..8cd4d31e15 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-dashed.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-dashed.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-dashed.mask.rgb24.ref.png new file mode 100644 index 0000000000..8cd4d31e15 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-dashed.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-dashed.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-dashed.quartz.xfail.png new file mode 100644 index 0000000000..78dbe59762 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-dashed.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-dashed.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-dashed.ref.png new file mode 100644 index 0000000000..12379ac03f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-dashed.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-dashed.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-dashed.traps.argb32.ref.png new file mode 100644 index 0000000000..12379ac03f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-dashed.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-dashed.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-dashed.traps.rgb24.ref.png new file mode 100644 index 0000000000..12379ac03f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-dashed.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-flipped.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-flipped.base.argb32.ref.png new file mode 100644 index 0000000000..3c3464bed8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-flipped.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-flipped.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-flipped.base.rgb24.ref.png new file mode 100644 index 0000000000..3c3464bed8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-flipped.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-flipped.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-flipped.ps.ref.png new file mode 100644 index 0000000000..89092b9cbf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-flipped.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-flipped.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-flipped.ref.png new file mode 100644 index 0000000000..3c3464bed8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-flipped.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-flopped.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-flopped.base.argb32.ref.png new file mode 100644 index 0000000000..3c3464bed8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-flopped.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-flopped.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-flopped.base.rgb24.ref.png new file mode 100644 index 0000000000..3c3464bed8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-flopped.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-flopped.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-flopped.ps.ref.png new file mode 100644 index 0000000000..89092b9cbf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-flopped.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-flopped.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-flopped.ref.png new file mode 100644 index 0000000000..3c3464bed8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-flopped.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-offset.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-offset.base.argb32.ref.png new file mode 100644 index 0000000000..3c3464bed8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-offset.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-offset.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-offset.base.rgb24.ref.png new file mode 100644 index 0000000000..3c3464bed8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-offset.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-offset.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-offset.ps.ref.png new file mode 100644 index 0000000000..89092b9cbf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-offset.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-offset.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-offset.ref.png new file mode 100644 index 0000000000..3c3464bed8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-offset.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-rotated.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-rotated.base.argb32.ref.png new file mode 100644 index 0000000000..87fe7523b9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-rotated.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-rotated.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-rotated.base.rgb24.ref.png new file mode 100644 index 0000000000..87fe7523b9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-rotated.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-rotated.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-rotated.ps.ref.png new file mode 100644 index 0000000000..5bca185a90 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-rotated.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-rotated.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-rotated.quartz.ref.png new file mode 100644 index 0000000000..5093f2c7ff Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-rotated.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-rotated.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-rotated.ref.png new file mode 100644 index 0000000000..3eeebb2542 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-rotated.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-rotated.traps.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-rotated.traps.ref.png new file mode 100644 index 0000000000..87fe7523b9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap-rotated.traps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap.ref.png new file mode 100644 index 0000000000..3c3464bed8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-large-overlap.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-overlap-dashed.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-dashed.base.argb32.ref.png new file mode 100644 index 0000000000..066b182aef Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-dashed.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-overlap-dashed.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-dashed.base.rgb24.ref.png new file mode 100644 index 0000000000..066b182aef Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-dashed.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-overlap-dashed.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-dashed.mask.argb32.ref.png new file mode 100644 index 0000000000..0de187d409 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-dashed.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-overlap-dashed.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-dashed.mask.rgb24.ref.png new file mode 100644 index 0000000000..0de187d409 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-dashed.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-overlap-dashed.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-dashed.quartz.xfail.png new file mode 100644 index 0000000000..ce8ff7bc97 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-dashed.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-overlap-dashed.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-dashed.ref.png new file mode 100644 index 0000000000..065d699587 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-dashed.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-overlap-dashed.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-dashed.traps.argb32.ref.png new file mode 100644 index 0000000000..065d699587 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-dashed.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-overlap-dashed.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-dashed.traps.rgb24.ref.png new file mode 100644 index 0000000000..065d699587 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-dashed.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-overlap-flipped.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-flipped.base.argb32.ref.png new file mode 100644 index 0000000000..13d70c8fec Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-flipped.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-overlap-flipped.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-flipped.base.rgb24.ref.png new file mode 100644 index 0000000000..13d70c8fec Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-flipped.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-overlap-flipped.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-flipped.ref.png new file mode 100644 index 0000000000..09911bc519 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-flipped.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-overlap-flopped.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-flopped.base.argb32.ref.png new file mode 100644 index 0000000000..13d70c8fec Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-flopped.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-overlap-flopped.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-flopped.base.rgb24.ref.png new file mode 100644 index 0000000000..13d70c8fec Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-flopped.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-overlap-flopped.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-flopped.ref.png new file mode 100644 index 0000000000..09911bc519 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-flopped.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-overlap-offset.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-offset.base.argb32.ref.png new file mode 100644 index 0000000000..13a138b9a1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-offset.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-overlap-offset.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-offset.base.rgb24.ref.png new file mode 100644 index 0000000000..13a138b9a1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-offset.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-overlap-offset.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-offset.ps.ref.png new file mode 100644 index 0000000000..f869ca2400 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-offset.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-overlap-offset.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-offset.ref.png new file mode 100644 index 0000000000..eafa50b1f9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-offset.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-overlap-offset.traps.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-offset.traps.ref.png new file mode 100644 index 0000000000..13a138b9a1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-offset.traps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-overlap-rotated.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-rotated.base.argb32.ref.png new file mode 100644 index 0000000000..fa7290d6cf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-rotated.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-overlap-rotated.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-rotated.base.rgb24.ref.png new file mode 100644 index 0000000000..fa7290d6cf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-rotated.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-overlap-rotated.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-rotated.ps.ref.png new file mode 100644 index 0000000000..b63bfd41eb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-rotated.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-overlap-rotated.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-rotated.ref.png new file mode 100644 index 0000000000..cce46c70ac Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-rotated.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-overlap-rotated.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-rotated.traps.argb32.ref.png new file mode 100644 index 0000000000..fa7290d6cf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-rotated.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-overlap-rotated.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-rotated.traps.rgb24.ref.png new file mode 100644 index 0000000000..fa7290d6cf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-overlap-rotated.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-overlap.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-overlap.base.argb32.ref.png new file mode 100644 index 0000000000..13d70c8fec Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-overlap.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-overlap.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-overlap.base.rgb24.ref.png new file mode 100644 index 0000000000..13d70c8fec Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-overlap.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-overlap.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-overlap.ref.png new file mode 100644 index 0000000000..13d70c8fec Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-overlap.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-scale.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-scale.base.argb32.ref.png new file mode 100644 index 0000000000..41d55b0ebd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-scale.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-scale.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-scale.base.rgb24.ref.png new file mode 100644 index 0000000000..41d55b0ebd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-scale.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-scale.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-scale.image16.ref.png new file mode 100644 index 0000000000..a784f65825 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-scale.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-scale.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-scale.pdf.ref.png new file mode 100644 index 0000000000..9aa8b1aac1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-scale.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-scale.ps2.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-scale.ps2.ref.png new file mode 100644 index 0000000000..57999b8028 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-scale.ps2.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-scale.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-scale.ps3.ref.png new file mode 100644 index 0000000000..57999b8028 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-scale.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-scale.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-scale.quartz.ref.png new file mode 100644 index 0000000000..afdc9da767 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-scale.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-scale.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-scale.ref.png new file mode 100644 index 0000000000..5767bc7d83 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-scale.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-scale.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-scale.svg.ref.png new file mode 100644 index 0000000000..9759b084b2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-scale.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-scale.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-scale.traps.argb32.ref.png new file mode 100644 index 0000000000..41d55b0ebd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-scale.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-scale.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-scale.traps.rgb24.ref.png new file mode 100644 index 0000000000..41d55b0ebd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-scale.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-tolerance.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-tolerance.base.argb32.ref.png new file mode 100644 index 0000000000..f890a52ed8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-tolerance.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-tolerance.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-tolerance.base.rgb24.ref.png new file mode 100644 index 0000000000..f890a52ed8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-tolerance.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-tolerance.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-tolerance.pdf.ref.png new file mode 100644 index 0000000000..f890a52ed8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-tolerance.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-tolerance.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-tolerance.ps.ref.png new file mode 100644 index 0000000000..34a2d97385 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-tolerance.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-tolerance.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-tolerance.ref.png new file mode 100644 index 0000000000..9c4d439870 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-tolerance.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-tolerance.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-tolerance.svg.ref.png new file mode 100644 index 0000000000..f890a52ed8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-tolerance.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-tolerance.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-tolerance.traps.argb32.ref.png new file mode 100644 index 0000000000..f890a52ed8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-tolerance.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width-tolerance.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width-tolerance.traps.rgb24.ref.png new file mode 100644 index 0000000000..f890a52ed8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width-tolerance.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width.base.argb32.ref.png new file mode 100644 index 0000000000..208d17083a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width.base.rgb24.ref.png new file mode 100644 index 0000000000..208d17083a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width.pdf.ref.png new file mode 100644 index 0000000000..3575652061 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width.ref.png new file mode 100644 index 0000000000..2a788285f2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width.traps.argb32.ref.png new file mode 100644 index 0000000000..208d17083a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/line-width.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/line-width.traps.rgb24.ref.png new file mode 100644 index 0000000000..208d17083a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/line-width.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient-extend.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient-extend.base.argb32.ref.png new file mode 100644 index 0000000000..79ce747db9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient-extend.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient-extend.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient-extend.base.rgb24.ref.png new file mode 100644 index 0000000000..79ce747db9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient-extend.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient-extend.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient-extend.pdf.ref.png new file mode 100644 index 0000000000..4c3764cd3a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient-extend.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient-extend.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient-extend.ps.ref.png new file mode 100644 index 0000000000..b638e3a504 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient-extend.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient-extend.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient-extend.ref.png new file mode 100644 index 0000000000..79ce747db9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient-extend.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient-extend.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient-extend.svg.ref.png new file mode 100644 index 0000000000..4c3764cd3a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient-extend.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient-large.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient-large.base.argb32.ref.png new file mode 100644 index 0000000000..f1f37ab474 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient-large.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient-large.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient-large.base.rgb24.ref.png new file mode 100644 index 0000000000..f1f37ab474 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient-large.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient-large.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient-large.pdf.ref.png new file mode 100644 index 0000000000..ae995a9927 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient-large.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient-large.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient-large.ps.ref.png new file mode 100644 index 0000000000..038df5df30 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient-large.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient-large.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient-large.quartz.ref.png new file mode 100644 index 0000000000..68f08297bd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient-large.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient-large.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient-large.ref.png new file mode 100644 index 0000000000..f1f37ab474 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient-large.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient-one-stop.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient-one-stop.base.argb32.ref.png new file mode 100644 index 0000000000..da02fda499 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient-one-stop.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient-one-stop.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient-one-stop.base.rgb24.ref.png new file mode 100644 index 0000000000..efc12ee716 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient-one-stop.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient-one-stop.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient-one-stop.ps.ref.png new file mode 100644 index 0000000000..3dd878e1d0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient-one-stop.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient-one-stop.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient-one-stop.ps.rgb24.ref.png new file mode 100644 index 0000000000..efc12ee716 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient-one-stop.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient-one-stop.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient-one-stop.ref.png new file mode 100644 index 0000000000..da02fda499 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient-one-stop.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient-reflect.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient-reflect.base.argb32.ref.png new file mode 100644 index 0000000000..b68dccb5eb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient-reflect.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient-reflect.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient-reflect.base.rgb24.ref.png new file mode 100644 index 0000000000..b68dccb5eb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient-reflect.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient-reflect.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient-reflect.image16.ref.png new file mode 100644 index 0000000000..de74afcb0c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient-reflect.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient-reflect.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient-reflect.pdf.argb32.ref.png new file mode 100644 index 0000000000..46e1c0f0ee Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient-reflect.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient-reflect.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient-reflect.pdf.rgb24.ref.png new file mode 100644 index 0000000000..46e1c0f0ee Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient-reflect.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient-reflect.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient-reflect.ps3.ref.png new file mode 100644 index 0000000000..ea6d25c171 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient-reflect.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient-reflect.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient-reflect.quartz.ref.png new file mode 100644 index 0000000000..89bac91da1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient-reflect.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient-reflect.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient-reflect.ref.png new file mode 100644 index 0000000000..b68dccb5eb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient-reflect.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient-subset.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient-subset.base.argb32.ref.png new file mode 100644 index 0000000000..e03d3d60f5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient-subset.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient-subset.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient-subset.base.rgb24.ref.png new file mode 100644 index 0000000000..e03d3d60f5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient-subset.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient-subset.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient-subset.image16.ref.png new file mode 100644 index 0000000000..9d04057e2d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient-subset.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient-subset.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient-subset.pdf.ref.png new file mode 100644 index 0000000000..eaf8d29762 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient-subset.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient-subset.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient-subset.ps3.ref.png new file mode 100644 index 0000000000..db0a4c0673 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient-subset.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient-subset.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient-subset.quartz.ref.png new file mode 100644 index 0000000000..70a6336e84 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient-subset.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient-subset.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient-subset.ref.png new file mode 100644 index 0000000000..fa0f62d11a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient-subset.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient-subset.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient-subset.svg.ref.png new file mode 100644 index 0000000000..f3fafb563d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient-subset.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient-subset.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient-subset.traps.argb32.ref.png new file mode 100644 index 0000000000..e03d3d60f5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient-subset.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient-subset.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient-subset.traps.rgb24.ref.png new file mode 100644 index 0000000000..e03d3d60f5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient-subset.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient.base.argb32.ref.png new file mode 100644 index 0000000000..083a9b87b9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient.base.rgb24.ref.png new file mode 100644 index 0000000000..083a9b87b9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient.image16.ref.png new file mode 100644 index 0000000000..183d3d9854 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient.pdf.ref.png new file mode 100644 index 0000000000..62f74ddb3b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient.ps3.ref.png new file mode 100644 index 0000000000..fb83dbaa12 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient.quartz.ref.png new file mode 100644 index 0000000000..5debca9bba Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient.ref.png new file mode 100644 index 0000000000..ad6d8900d3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient.svg.ref.png new file mode 100644 index 0000000000..64f71b5719 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient.traps.argb32.ref.png new file mode 100644 index 0000000000..083a9b87b9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-gradient.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-gradient.traps.rgb24.ref.png new file mode 100644 index 0000000000..083a9b87b9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-gradient.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-step-function.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-step-function.base.argb32.ref.png new file mode 100644 index 0000000000..0ed126e1d0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-step-function.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-step-function.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-step-function.base.rgb24.ref.png new file mode 100644 index 0000000000..0ed126e1d0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-step-function.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-step-function.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-step-function.mask.argb32.ref.png new file mode 100644 index 0000000000..0ed126e1d0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-step-function.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-step-function.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-step-function.mask.rgb24.ref.png new file mode 100644 index 0000000000..0ed126e1d0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-step-function.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-step-function.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-step-function.traps.argb32.ref.png new file mode 100644 index 0000000000..0ed126e1d0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-step-function.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-step-function.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-step-function.traps.rgb24.ref.png new file mode 100644 index 0000000000..0ed126e1d0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-step-function.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-step-function.xfail.png b/local/recipes/libs/cairo/source/test/reference/linear-step-function.xfail.png new file mode 100644 index 0000000000..b8afd218aa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-step-function.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-uniform.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-uniform.base.argb32.ref.png new file mode 100644 index 0000000000..94ca33615a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-uniform.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-uniform.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-uniform.base.rgb24.ref.png new file mode 100644 index 0000000000..94ca33615a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-uniform.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-uniform.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-uniform.image16.ref.png new file mode 100644 index 0000000000..7bf4bf561b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-uniform.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-uniform.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-uniform.ps.ref.png new file mode 100644 index 0000000000..0faced8c30 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-uniform.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/linear-uniform.ref.png b/local/recipes/libs/cairo/source/test/reference/linear-uniform.ref.png new file mode 100644 index 0000000000..94ca33615a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/linear-uniform.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/long-dashed-lines.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/long-dashed-lines.base.argb32.ref.png new file mode 100644 index 0000000000..ccd3d5df1d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/long-dashed-lines.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/long-dashed-lines.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/long-dashed-lines.base.rgb24.ref.png new file mode 100644 index 0000000000..ccd3d5df1d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/long-dashed-lines.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/long-dashed-lines.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/long-dashed-lines.image16.ref.png new file mode 100644 index 0000000000..8abac9b4d8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/long-dashed-lines.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/long-dashed-lines.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/long-dashed-lines.pdf.ref.png new file mode 100644 index 0000000000..8c203a4ca5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/long-dashed-lines.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/long-dashed-lines.ps2.ref.png b/local/recipes/libs/cairo/source/test/reference/long-dashed-lines.ps2.ref.png new file mode 100644 index 0000000000..7fce667e8f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/long-dashed-lines.ps2.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/long-dashed-lines.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/long-dashed-lines.ps3.ref.png new file mode 100644 index 0000000000..7fce667e8f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/long-dashed-lines.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/long-dashed-lines.ref.png b/local/recipes/libs/cairo/source/test/reference/long-dashed-lines.ref.png new file mode 100644 index 0000000000..9c7208c18b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/long-dashed-lines.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/long-dashed-lines.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/long-dashed-lines.svg.ref.png new file mode 100644 index 0000000000..8c203a4ca5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/long-dashed-lines.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/long-dashed-lines.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/long-dashed-lines.traps.argb32.ref.png new file mode 100644 index 0000000000..ccd3d5df1d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/long-dashed-lines.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/long-dashed-lines.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/long-dashed-lines.traps.rgb24.ref.png new file mode 100644 index 0000000000..ccd3d5df1d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/long-dashed-lines.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/long-lines.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/long-lines.pdf.ref.png new file mode 100644 index 0000000000..e193094079 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/long-lines.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/long-lines.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/long-lines.ps.ref.png new file mode 100644 index 0000000000..e2ffa14d89 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/long-lines.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/long-lines.ref.png b/local/recipes/libs/cairo/source/test/reference/long-lines.ref.png new file mode 100644 index 0000000000..6e96743460 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/long-lines.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/long-lines.xcb-window&.ref.png b/local/recipes/libs/cairo/source/test/reference/long-lines.xcb-window&.ref.png new file mode 100644 index 0000000000..ae94477a72 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/long-lines.xcb-window&.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/long-lines.xcb-window.ref.png b/local/recipes/libs/cairo/source/test/reference/long-lines.xcb-window.ref.png new file mode 100644 index 0000000000..ae94477a72 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/long-lines.xcb-window.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/long-lines.xcb.ref.png b/local/recipes/libs/cairo/source/test/reference/long-lines.xcb.ref.png new file mode 100644 index 0000000000..ae94477a72 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/long-lines.xcb.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/long-lines.xlib-window.ref.png b/local/recipes/libs/cairo/source/test/reference/long-lines.xlib-window.ref.png new file mode 100644 index 0000000000..ae94477a72 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/long-lines.xlib-window.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/long-lines.xlib.ref.png b/local/recipes/libs/cairo/source/test/reference/long-lines.xlib.ref.png new file mode 100644 index 0000000000..ae94477a72 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/long-lines.xlib.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/map-all-to-image.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/map-all-to-image.base.argb32.ref.png new file mode 100644 index 0000000000..c56d9698da Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/map-all-to-image.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/map-all-to-image.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/map-all-to-image.base.rgb24.ref.png new file mode 100644 index 0000000000..c56d9698da Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/map-all-to-image.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/map-all-to-image.ref.png b/local/recipes/libs/cairo/source/test/reference/map-all-to-image.ref.png new file mode 100644 index 0000000000..c56d9698da Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/map-all-to-image.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/map-all-to-xlib-fallback.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/map-all-to-xlib-fallback.rgb24.ref.png new file mode 100644 index 0000000000..c56d9698da Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/map-all-to-xlib-fallback.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/map-all-to-xlib-window.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/map-all-to-xlib-window.rgb24.ref.png new file mode 100644 index 0000000000..c56d9698da Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/map-all-to-xlib-window.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/map-all-to-xlib.ref.png b/local/recipes/libs/cairo/source/test/reference/map-all-to-xlib.ref.png new file mode 100644 index 0000000000..c56d9698da Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/map-all-to-xlib.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/map-bit-to-image.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/map-bit-to-image.base.argb32.ref.png new file mode 100644 index 0000000000..b42dcb62a8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/map-bit-to-image.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/map-bit-to-image.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/map-bit-to-image.base.rgb24.ref.png new file mode 100644 index 0000000000..b42dcb62a8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/map-bit-to-image.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/map-bit-to-image.ref.png b/local/recipes/libs/cairo/source/test/reference/map-bit-to-image.ref.png new file mode 100644 index 0000000000..b42dcb62a8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/map-bit-to-image.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/map-bit-to-xlib-fallback.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/map-bit-to-xlib-fallback.rgb24.ref.png new file mode 100644 index 0000000000..b42dcb62a8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/map-bit-to-xlib-fallback.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/map-bit-to-xlib-window.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/map-bit-to-xlib-window.rgb24.ref.png new file mode 100644 index 0000000000..b42dcb62a8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/map-bit-to-xlib-window.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/map-bit-to-xlib.ref.png b/local/recipes/libs/cairo/source/test/reference/map-bit-to-xlib.ref.png new file mode 100644 index 0000000000..b42dcb62a8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/map-bit-to-xlib.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/map-to-image-fill.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/map-to-image-fill.base.argb32.ref.png new file mode 100644 index 0000000000..c2893e0de3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/map-to-image-fill.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/map-to-image-fill.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/map-to-image-fill.base.rgb24.ref.png new file mode 100644 index 0000000000..c2893e0de3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/map-to-image-fill.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/map-to-image-fill.ref.png b/local/recipes/libs/cairo/source/test/reference/map-to-image-fill.ref.png new file mode 100644 index 0000000000..c2893e0de3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/map-to-image-fill.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-alpha.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-alpha.argb32.ref.png new file mode 100644 index 0000000000..90717f0cc6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-alpha.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-alpha.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-alpha.base.argb32.ref.png new file mode 100644 index 0000000000..a0b9017e0c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-alpha.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-alpha.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-alpha.base.rgb24.ref.png new file mode 100644 index 0000000000..d8f4b8f810 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-alpha.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-alpha.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-alpha.image16.ref.png new file mode 100644 index 0000000000..dbf121a4bb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-alpha.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-alpha.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-alpha.ps.ref.png new file mode 100644 index 0000000000..b0058dd47c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-alpha.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-alpha.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-alpha.quartz.argb32.ref.png new file mode 100644 index 0000000000..a7bfbb2a85 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-alpha.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-alpha.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-alpha.quartz.rgb24.ref.png new file mode 100644 index 0000000000..d4cc59c83e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-alpha.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-alpha.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-alpha.rgb24.ref.png new file mode 100644 index 0000000000..9999b8a4fd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-alpha.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-alpha.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-alpha.traps.argb32.ref.png new file mode 100644 index 0000000000..a0b9017e0c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-alpha.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-alpha.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-alpha.traps.rgb24.ref.png new file mode 100644 index 0000000000..d8f4b8f810 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-alpha.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-ctm.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-ctm.base.argb32.ref.png new file mode 100644 index 0000000000..07d903d157 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-ctm.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-ctm.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-ctm.base.rgb24.ref.png new file mode 100644 index 0000000000..de3fa097fa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-ctm.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-ctm.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-ctm.ps.rgb24.ref.png new file mode 100644 index 0000000000..de3fa097fa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-ctm.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-ctm.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-ctm.ref.png new file mode 100644 index 0000000000..88a0402ca8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-ctm.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-glyphs.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-glyphs.image16.ref.png new file mode 100644 index 0000000000..177e79560f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-glyphs.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-glyphs.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-glyphs.pdf.ref.png new file mode 100644 index 0000000000..673ef92d8d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-glyphs.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-glyphs.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-glyphs.ref.png new file mode 100644 index 0000000000..5beda0dbed Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-glyphs.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-surface-ctm.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-surface-ctm.base.argb32.ref.png new file mode 100644 index 0000000000..07d903d157 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-surface-ctm.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-surface-ctm.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-surface-ctm.base.rgb24.ref.png new file mode 100644 index 0000000000..de3fa097fa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-surface-ctm.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-surface-ctm.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-surface-ctm.ps.rgb24.ref.png new file mode 100644 index 0000000000..de3fa097fa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-surface-ctm.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-surface-ctm.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-surface-ctm.ref.png new file mode 100644 index 0000000000..744b1dd378 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-surface-ctm.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-transformed-image.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-transformed-image.base.argb32.ref.png new file mode 100644 index 0000000000..af84b39d35 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-transformed-image.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-transformed-image.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-transformed-image.base.rgb24.ref.png new file mode 100644 index 0000000000..af84b39d35 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-transformed-image.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-transformed-image.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-transformed-image.image16.ref.png new file mode 100644 index 0000000000..9e196eff10 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-transformed-image.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-transformed-image.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-transformed-image.pdf.ref.png new file mode 100644 index 0000000000..49c6be0713 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-transformed-image.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-transformed-image.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-transformed-image.ps.ref.png new file mode 100644 index 0000000000..fa8482aade Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-transformed-image.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-transformed-image.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-transformed-image.quartz.ref.png new file mode 100644 index 0000000000..58ac575581 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-transformed-image.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-transformed-image.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-transformed-image.ref.png new file mode 100644 index 0000000000..af84b39d35 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-transformed-image.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-transformed-image.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-transformed-image.svg.ref.png new file mode 100644 index 0000000000..35459b7ada Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-transformed-image.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-transformed-similar.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-transformed-similar.base.argb32.ref.png new file mode 100644 index 0000000000..af84b39d35 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-transformed-similar.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-transformed-similar.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-transformed-similar.base.rgb24.ref.png new file mode 100644 index 0000000000..af84b39d35 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-transformed-similar.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-transformed-similar.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-transformed-similar.image16.ref.png new file mode 100644 index 0000000000..9e196eff10 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-transformed-similar.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-transformed-similar.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-transformed-similar.pdf.ref.png new file mode 100644 index 0000000000..339c71ee18 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-transformed-similar.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-transformed-similar.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-transformed-similar.ps.ref.png new file mode 100644 index 0000000000..f0e7a24f65 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-transformed-similar.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-transformed-similar.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-transformed-similar.quartz.ref.png new file mode 100644 index 0000000000..58ac575581 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-transformed-similar.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-transformed-similar.recording.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-transformed-similar.recording.ref.png new file mode 100644 index 0000000000..33ec279972 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-transformed-similar.recording.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-transformed-similar.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-transformed-similar.ref.png new file mode 100644 index 0000000000..af84b39d35 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-transformed-similar.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-transformed-similar.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-transformed-similar.svg.ref.png new file mode 100644 index 0000000000..339c71ee18 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-transformed-similar.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-transformed-xlib-fallback.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-transformed-xlib-fallback.rgb24.ref.png new file mode 100644 index 0000000000..09eb43ae7e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-transformed-xlib-fallback.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-transformed-xlib-window.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-transformed-xlib-window.rgb24.ref.png new file mode 100644 index 0000000000..09eb43ae7e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-transformed-xlib-window.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask-transformed-xlib.ref.png b/local/recipes/libs/cairo/source/test/reference/mask-transformed-xlib.ref.png new file mode 100644 index 0000000000..09eb43ae7e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask-transformed-xlib.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/mask.argb32.ref.png new file mode 100644 index 0000000000..bc142c2ef0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/mask.base.argb32.ref.png new file mode 100644 index 0000000000..7ee6b4536e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/mask.base.rgb24.ref.png new file mode 100644 index 0000000000..b0ceb35229 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/mask.image16.ref.png new file mode 100644 index 0000000000..4ab52de262 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/mask.pdf.argb32.ref.png new file mode 100644 index 0000000000..80fd759037 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/mask.pdf.rgb24.ref.png new file mode 100644 index 0000000000..6b95459cdd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/mask.quartz.argb32.ref.png new file mode 100644 index 0000000000..ab800daf7d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/mask.rgb24.ref.png new file mode 100644 index 0000000000..c7962a3c8a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/mask.svg.ref.png new file mode 100644 index 0000000000..4737df38c1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask.svg.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/mask.svg.rgb24.ref.png new file mode 100644 index 0000000000..8bc4f8b58f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask.svg.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/mask.traps.argb32.ref.png new file mode 100644 index 0000000000..3286ce6b73 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mask.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/mask.traps.rgb24.ref.png new file mode 100644 index 0000000000..edcabaf916 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mask.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-accuracy.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-accuracy.base.argb32.ref.png new file mode 100644 index 0000000000..dfc19ff4f9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-accuracy.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-accuracy.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-accuracy.base.rgb24.ref.png new file mode 100644 index 0000000000..dfc19ff4f9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-accuracy.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-accuracy.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-accuracy.image16.ref.png new file mode 100644 index 0000000000..a82e4fbeb2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-accuracy.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-accuracy.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-accuracy.ref.png new file mode 100644 index 0000000000..dfc19ff4f9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-accuracy.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-conical.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-conical.base.argb32.ref.png new file mode 100644 index 0000000000..f5dc21dc89 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-conical.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-conical.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-conical.base.rgb24.ref.png new file mode 100644 index 0000000000..f5dc21dc89 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-conical.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-conical.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-conical.image16.ref.png new file mode 100644 index 0000000000..b8f9416eaa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-conical.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-conical.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-conical.pdf.ref.png new file mode 100644 index 0000000000..4c830b1502 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-conical.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-conical.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-conical.ps.ref.png new file mode 100644 index 0000000000..426428a9a9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-conical.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-conical.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-conical.ref.png new file mode 100644 index 0000000000..f5dc21dc89 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-conical.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-conical.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-conical.svg.ref.png new file mode 100644 index 0000000000..4c830b1502 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-conical.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-control-points.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-control-points.base.argb32.ref.png new file mode 100644 index 0000000000..841fc3ef9e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-control-points.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-control-points.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-control-points.base.rgb24.ref.png new file mode 100644 index 0000000000..841fc3ef9e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-control-points.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-control-points.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-control-points.image16.ref.png new file mode 100644 index 0000000000..b664ef90df Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-control-points.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-control-points.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-control-points.pdf.ref.png new file mode 100644 index 0000000000..f614a2c086 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-control-points.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-control-points.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-control-points.ps.ref.png new file mode 100644 index 0000000000..f37184a42e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-control-points.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-control-points.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-control-points.ref.png new file mode 100644 index 0000000000..841fc3ef9e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-control-points.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-control-points.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-control-points.svg.ref.png new file mode 100644 index 0000000000..34445d0002 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-control-points.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-fold.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-fold.base.argb32.ref.png new file mode 100644 index 0000000000..6275b82d81 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-fold.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-fold.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-fold.base.rgb24.ref.png new file mode 100644 index 0000000000..6275b82d81 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-fold.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-fold.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-fold.image16.ref.png new file mode 100644 index 0000000000..4264ad2c73 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-fold.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-fold.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-fold.pdf.ref.png new file mode 100644 index 0000000000..8cf5eb4678 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-fold.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-fold.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-fold.ps.ref.png new file mode 100644 index 0000000000..d44404df0c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-fold.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-fold.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-fold.ref.png new file mode 100644 index 0000000000..6275b82d81 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-fold.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-fold.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-fold.svg.ref.png new file mode 100644 index 0000000000..8cf5eb4678 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-fold.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-overlap.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-overlap.base.argb32.ref.png new file mode 100644 index 0000000000..1394c9ec5a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-overlap.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-overlap.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-overlap.base.rgb24.ref.png new file mode 100644 index 0000000000..1394c9ec5a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-overlap.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-overlap.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-overlap.image16.ref.png new file mode 100644 index 0000000000..a67f7ddec1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-overlap.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-overlap.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-overlap.pdf.ref.png new file mode 100644 index 0000000000..0403b04706 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-overlap.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-overlap.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-overlap.ps.ref.png new file mode 100644 index 0000000000..a90e5330fb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-overlap.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-overlap.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-overlap.ref.png new file mode 100644 index 0000000000..1394c9ec5a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-overlap.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-overlap.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-overlap.svg.ref.png new file mode 100644 index 0000000000..0403b04706 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-overlap.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-transformed.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-transformed.base.argb32.ref.png new file mode 100644 index 0000000000..9aa482f529 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-transformed.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-transformed.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-transformed.base.rgb24.ref.png new file mode 100644 index 0000000000..9aa482f529 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-transformed.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-transformed.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-transformed.image16.ref.png new file mode 100644 index 0000000000..0645b861e1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-transformed.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-transformed.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-transformed.pdf.ref.png new file mode 100644 index 0000000000..faf3f1375d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-transformed.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-transformed.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-transformed.ps.ref.png new file mode 100644 index 0000000000..d8a89b79c8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-transformed.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-transformed.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-transformed.ref.png new file mode 100644 index 0000000000..9aa482f529 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-transformed.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern-transformed.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-transformed.svg.ref.png new file mode 100644 index 0000000000..fd6b89ff19 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern-transformed.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern.base.argb32.ref.png new file mode 100644 index 0000000000..1f76639f0b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern.base.rgb24.ref.png new file mode 100644 index 0000000000..1f76639f0b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern.image16.ref.png new file mode 100644 index 0000000000..bd63538427 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern.pdf.ref.png new file mode 100644 index 0000000000..10502258f0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern.ps.ref.png new file mode 100644 index 0000000000..812432ce8d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern.ref.png new file mode 100644 index 0000000000..1f76639f0b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mesh-pattern.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/mesh-pattern.svg.ref.png new file mode 100644 index 0000000000..812432ce8d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mesh-pattern.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mime-data.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/mime-data.base.argb32.ref.png new file mode 100644 index 0000000000..03a0247a3f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mime-data.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mime-data.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/mime-data.base.rgb24.ref.png new file mode 100644 index 0000000000..03a0247a3f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mime-data.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mime-data.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/mime-data.pdf.ref.png new file mode 100644 index 0000000000..a669c8f2b8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mime-data.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mime-data.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/mime-data.ps.ref.png new file mode 100644 index 0000000000..bf834020ae Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mime-data.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mime-data.ref.png b/local/recipes/libs/cairo/source/test/reference/mime-data.ref.png new file mode 100644 index 0000000000..03a0247a3f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mime-data.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mime-data.script.ref.png b/local/recipes/libs/cairo/source/test/reference/mime-data.script.ref.png new file mode 100644 index 0000000000..e486180332 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mime-data.script.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/mime-data.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/mime-data.svg.ref.png new file mode 100644 index 0000000000..1889c6e8dd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/mime-data.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/miter-precision.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/miter-precision.base.argb32.ref.png new file mode 100644 index 0000000000..b881dd4ada Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/miter-precision.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/miter-precision.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/miter-precision.base.rgb24.ref.png new file mode 100644 index 0000000000..b881dd4ada Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/miter-precision.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/miter-precision.ps2.ref.png b/local/recipes/libs/cairo/source/test/reference/miter-precision.ps2.ref.png new file mode 100644 index 0000000000..c2b69ad6aa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/miter-precision.ps2.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/miter-precision.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/miter-precision.ps3.ref.png new file mode 100644 index 0000000000..c2b69ad6aa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/miter-precision.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/miter-precision.ref.png b/local/recipes/libs/cairo/source/test/reference/miter-precision.ref.png new file mode 100644 index 0000000000..a2c333e412 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/miter-precision.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/miter-precision.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/miter-precision.traps.argb32.ref.png new file mode 100644 index 0000000000..b881dd4ada Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/miter-precision.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/miter-precision.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/miter-precision.traps.rgb24.ref.png new file mode 100644 index 0000000000..b881dd4ada Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/miter-precision.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/move-to-show-surface.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/move-to-show-surface.base.argb32.ref.png new file mode 100644 index 0000000000..0a145d918a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/move-to-show-surface.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/move-to-show-surface.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/move-to-show-surface.base.rgb24.ref.png new file mode 100644 index 0000000000..0a145d918a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/move-to-show-surface.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/move-to-show-surface.ref.png b/local/recipes/libs/cairo/source/test/reference/move-to-show-surface.ref.png new file mode 100644 index 0000000000..765adc4a48 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/move-to-show-surface.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/negative-stride-image.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/negative-stride-image.base.argb32.ref.png new file mode 100644 index 0000000000..44284566ee Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/negative-stride-image.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/negative-stride-image.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/negative-stride-image.base.rgb24.ref.png new file mode 100644 index 0000000000..44284566ee Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/negative-stride-image.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/negative-stride-image.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/negative-stride-image.image16.ref.png new file mode 100644 index 0000000000..4b15914f26 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/negative-stride-image.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/negative-stride-image.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/negative-stride-image.ps.ref.png new file mode 100644 index 0000000000..953c9a18ea Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/negative-stride-image.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/negative-stride-image.ref.png b/local/recipes/libs/cairo/source/test/reference/negative-stride-image.ref.png new file mode 100644 index 0000000000..44284566ee Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/negative-stride-image.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/new-sub-path.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/new-sub-path.base.argb32.ref.png new file mode 100644 index 0000000000..13e0675504 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/new-sub-path.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/new-sub-path.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/new-sub-path.base.rgb24.ref.png new file mode 100644 index 0000000000..b69e4abec7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/new-sub-path.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/new-sub-path.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/new-sub-path.pdf.argb32.ref.png new file mode 100644 index 0000000000..44a70eb583 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/new-sub-path.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/new-sub-path.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/new-sub-path.pdf.rgb24.ref.png new file mode 100644 index 0000000000..73f26b2a24 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/new-sub-path.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/new-sub-path.ps2.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/new-sub-path.ps2.argb32.ref.png new file mode 100644 index 0000000000..45253dbeec Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/new-sub-path.ps2.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/new-sub-path.ps2.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/new-sub-path.ps2.rgb24.ref.png new file mode 100644 index 0000000000..bceb5b75ae Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/new-sub-path.ps2.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/new-sub-path.ps3.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/new-sub-path.ps3.argb32.ref.png new file mode 100644 index 0000000000..45253dbeec Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/new-sub-path.ps3.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/new-sub-path.ps3.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/new-sub-path.ps3.rgb24.ref.png new file mode 100644 index 0000000000..bceb5b75ae Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/new-sub-path.ps3.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/new-sub-path.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/new-sub-path.quartz.argb32.ref.png new file mode 100644 index 0000000000..20d49ba33a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/new-sub-path.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/new-sub-path.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/new-sub-path.quartz.rgb24.ref.png new file mode 100644 index 0000000000..d5baca9013 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/new-sub-path.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/new-sub-path.ref.png b/local/recipes/libs/cairo/source/test/reference/new-sub-path.ref.png new file mode 100644 index 0000000000..87a6c91c54 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/new-sub-path.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/new-sub-path.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/new-sub-path.svg.ref.png new file mode 100644 index 0000000000..d45d4a066e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/new-sub-path.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/new-sub-path.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/new-sub-path.traps.argb32.ref.png new file mode 100644 index 0000000000..13e0675504 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/new-sub-path.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/new-sub-path.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/new-sub-path.traps.rgb24.ref.png new file mode 100644 index 0000000000..b69e4abec7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/new-sub-path.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/nil-surface.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/nil-surface.base.argb32.ref.png new file mode 100644 index 0000000000..50e35a2466 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/nil-surface.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/nil-surface.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/nil-surface.base.rgb24.ref.png new file mode 100644 index 0000000000..7d5589c1d7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/nil-surface.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/nil-surface.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/nil-surface.ps.rgb24.ref.png new file mode 100644 index 0000000000..7d5589c1d7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/nil-surface.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/nil-surface.ref.png b/local/recipes/libs/cairo/source/test/reference/nil-surface.ref.png new file mode 100644 index 0000000000..79dd2bc1df Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/nil-surface.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-alpha-alpha.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-alpha-alpha.base.argb32.ref.png new file mode 100644 index 0000000000..fc173cb187 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-alpha-alpha.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-alpha-alpha.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-alpha-alpha.base.rgb24.ref.png new file mode 100644 index 0000000000..fc173cb187 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-alpha-alpha.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-alpha-alpha.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-alpha-alpha.image16.ref.png new file mode 100644 index 0000000000..31eba5f759 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-alpha-alpha.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-alpha-alpha.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-alpha-alpha.pdf.ref.png new file mode 100644 index 0000000000..fc173cb187 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-alpha-alpha.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-alpha-alpha.pdf.xfail.png b/local/recipes/libs/cairo/source/test/reference/operator-alpha-alpha.pdf.xfail.png new file mode 100644 index 0000000000..0a06685e65 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-alpha-alpha.pdf.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-alpha-alpha.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-alpha-alpha.ps.ref.png new file mode 100644 index 0000000000..fd12e9cd6f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-alpha-alpha.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-alpha-alpha.ps.xfail.png b/local/recipes/libs/cairo/source/test/reference/operator-alpha-alpha.ps.xfail.png new file mode 100644 index 0000000000..e7c4fea2df Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-alpha-alpha.ps.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-alpha-alpha.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-alpha-alpha.ref.png new file mode 100644 index 0000000000..695d0d0126 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-alpha-alpha.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-alpha-alpha.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-alpha-alpha.traps.argb32.ref.png new file mode 100644 index 0000000000..fc173cb187 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-alpha-alpha.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-alpha-alpha.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-alpha-alpha.traps.rgb24.ref.png new file mode 100644 index 0000000000..fc173cb187 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-alpha-alpha.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-alpha.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-alpha.argb32.ref.png new file mode 100644 index 0000000000..b4f3b71f0c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-alpha.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-alpha.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-alpha.base.argb32.ref.png new file mode 100644 index 0000000000..b4f3b71f0c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-alpha.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-alpha.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-alpha.base.rgb24.ref.png new file mode 100644 index 0000000000..bc7be3aeb6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-alpha.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-alpha.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-alpha.rgb24.ref.png new file mode 100644 index 0000000000..bc7be3aeb6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-alpha.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-clear.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-clear.argb32.ref.png new file mode 100644 index 0000000000..371cc27335 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-clear.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-clear.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-clear.base.argb32.ref.png new file mode 100644 index 0000000000..c49b4a8d62 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-clear.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-clear.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-clear.base.rgb24.ref.png new file mode 100644 index 0000000000..51d38d1341 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-clear.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-clear.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-clear.mask.rgb24.ref.png new file mode 100644 index 0000000000..3d58ab341f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-clear.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-clear.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-clear.pdf.argb32.ref.png new file mode 100644 index 0000000000..88255feeb5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-clear.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-clear.ps2.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-clear.ps2.argb32.ref.png new file mode 100644 index 0000000000..92b41111f2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-clear.ps2.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-clear.ps3.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-clear.ps3.argb32.ref.png new file mode 100644 index 0000000000..92b41111f2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-clear.ps3.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-clear.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-clear.quartz.argb32.ref.png new file mode 100644 index 0000000000..a76ebfc82e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-clear.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-clear.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-clear.quartz.rgb24.ref.png new file mode 100644 index 0000000000..7b44e219cd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-clear.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-clear.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-clear.rgb24.ref.png new file mode 100644 index 0000000000..f6b1b334e3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-clear.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-clear.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-clear.svg.ref.png new file mode 100644 index 0000000000..257f112eaf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-clear.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-clear.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-clear.traps.argb32.ref.png new file mode 100644 index 0000000000..c49b4a8d62 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-clear.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-clear.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-clear.traps.rgb24.ref.png new file mode 100644 index 0000000000..51d38d1341 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-clear.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-source.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-source.argb32.ref.png new file mode 100644 index 0000000000..146e541a43 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-source.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-source.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-source.base.argb32.ref.png new file mode 100644 index 0000000000..42e24f24cb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-source.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-source.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-source.base.rgb24.ref.png new file mode 100644 index 0000000000..4736d58524 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-source.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-source.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-source.image16.ref.png new file mode 100644 index 0000000000..45562603c7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-source.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-source.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-source.mask.argb32.ref.png new file mode 100644 index 0000000000..74ad1dad6a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-source.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-source.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-source.mask.rgb24.ref.png new file mode 100644 index 0000000000..c0033562b9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-source.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-source.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-source.quartz.argb32.ref.png new file mode 100644 index 0000000000..8d4f80dae4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-source.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-source.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-source.quartz.rgb24.ref.png new file mode 100644 index 0000000000..30c05c8c2a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-source.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-source.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-source.rgb24.ref.png new file mode 100644 index 0000000000..52fdd3b5bf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-source.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-source.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-source.svg.ref.png new file mode 100644 index 0000000000..376867e874 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-source.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-source.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-source.traps.argb32.ref.png new file mode 100644 index 0000000000..42e24f24cb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-source.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-source.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-source.traps.rgb24.ref.png new file mode 100644 index 0000000000..4736d58524 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-source.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-source.xlib-fallback.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-source.xlib-fallback.ref.png new file mode 100644 index 0000000000..4527ce715c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-source.xlib-fallback.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-www.image16.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-www.image16.rgb24.ref.png new file mode 100644 index 0000000000..f62070c94f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-www.image16.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-www.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-www.pdf.ref.png new file mode 100644 index 0000000000..a8cad4e4cc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-www.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-www.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-www.ref.png new file mode 100644 index 0000000000..22ae85d015 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-www.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-www.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-www.rgb24.ref.png new file mode 100644 index 0000000000..80261ceb34 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-www.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-www.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-www.svg.ref.png new file mode 100644 index 0000000000..4d70805718 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-www.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator-www.svg.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/operator-www.svg.rgb24.ref.png new file mode 100644 index 0000000000..55d24f3477 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator-www.svg.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/operator.argb32.ref.png new file mode 100644 index 0000000000..34fce987b2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/operator.base.argb32.ref.png new file mode 100644 index 0000000000..34fce987b2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/operator.base.rgb24.ref.png new file mode 100644 index 0000000000..aa6103df83 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/operator.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/operator.rgb24.ref.png new file mode 100644 index 0000000000..aa6103df83 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/operator.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/outline-tolerance.ref.png b/local/recipes/libs/cairo/source/test/reference/outline-tolerance.ref.png new file mode 100644 index 0000000000..2733836c99 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/outline-tolerance.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-above-source.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/over-above-source.argb32.ref.png new file mode 100644 index 0000000000..479437fa83 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-above-source.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-above-source.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/over-above-source.base.argb32.ref.png new file mode 100644 index 0000000000..8a0183a6e1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-above-source.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-above-source.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/over-above-source.base.rgb24.ref.png new file mode 100644 index 0000000000..85c19971dc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-above-source.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-above-source.ps2.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/over-above-source.ps2.argb32.ref.png new file mode 100644 index 0000000000..7c90d0867e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-above-source.ps2.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-above-source.ps3.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/over-above-source.ps3.argb32.ref.png new file mode 100644 index 0000000000..2c3e9fafc7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-above-source.ps3.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-above-source.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/over-above-source.quartz.argb32.ref.png new file mode 100644 index 0000000000..6ad74d7988 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-above-source.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-above-source.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/over-above-source.quartz.rgb24.ref.png new file mode 100644 index 0000000000..f70593ce08 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-above-source.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-above-source.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/over-above-source.rgb24.ref.png new file mode 100644 index 0000000000..6fc2f52486 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-above-source.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-above-source.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/over-above-source.traps.argb32.ref.png new file mode 100644 index 0000000000..8a0183a6e1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-above-source.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-above-source.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/over-above-source.traps.rgb24.ref.png new file mode 100644 index 0000000000..85c19971dc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-above-source.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-around-source.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/over-around-source.argb32.ref.png new file mode 100644 index 0000000000..abc81c771a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-around-source.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-around-source.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/over-around-source.base.argb32.ref.png new file mode 100644 index 0000000000..fca75056d7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-around-source.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-around-source.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/over-around-source.base.rgb24.ref.png new file mode 100644 index 0000000000..e8dd91d6ed Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-around-source.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-around-source.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/over-around-source.image16.ref.png new file mode 100644 index 0000000000..f571b7d1d7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-around-source.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-around-source.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/over-around-source.pdf.argb32.ref.png new file mode 100644 index 0000000000..da700af738 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-around-source.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-around-source.ps2.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/over-around-source.ps2.argb32.ref.png new file mode 100644 index 0000000000..43917597d7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-around-source.ps2.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-around-source.ps2.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/over-around-source.ps2.rgb24.ref.png new file mode 100644 index 0000000000..ee325eab34 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-around-source.ps2.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-around-source.ps3.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/over-around-source.ps3.argb32.ref.png new file mode 100644 index 0000000000..1fe11d980c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-around-source.ps3.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-around-source.ps3.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/over-around-source.ps3.rgb24.ref.png new file mode 100644 index 0000000000..ee325eab34 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-around-source.ps3.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-around-source.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/over-around-source.quartz.argb32.ref.png new file mode 100644 index 0000000000..48eddaebc0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-around-source.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-around-source.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/over-around-source.quartz.rgb24.ref.png new file mode 100644 index 0000000000..fb9b5ba04d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-around-source.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-around-source.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/over-around-source.rgb24.ref.png new file mode 100644 index 0000000000..41ade95748 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-around-source.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-around-source.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/over-around-source.traps.argb32.ref.png new file mode 100644 index 0000000000..fca75056d7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-around-source.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-around-source.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/over-around-source.traps.rgb24.ref.png new file mode 100644 index 0000000000..e8dd91d6ed Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-around-source.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-below-source.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/over-below-source.argb32.ref.png new file mode 100644 index 0000000000..5191609674 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-below-source.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-below-source.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/over-below-source.base.argb32.ref.png new file mode 100644 index 0000000000..c65936323b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-below-source.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-below-source.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/over-below-source.base.rgb24.ref.png new file mode 100644 index 0000000000..88a85acbb5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-below-source.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-below-source.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/over-below-source.pdf.argb32.ref.png new file mode 100644 index 0000000000..b9c4fe2838 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-below-source.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-below-source.ps2.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/over-below-source.ps2.argb32.ref.png new file mode 100644 index 0000000000..c05bda5406 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-below-source.ps2.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-below-source.ps2.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/over-below-source.ps2.rgb24.ref.png new file mode 100644 index 0000000000..07e10d4644 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-below-source.ps2.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-below-source.ps3.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/over-below-source.ps3.argb32.ref.png new file mode 100644 index 0000000000..c05bda5406 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-below-source.ps3.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-below-source.ps3.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/over-below-source.ps3.rgb24.ref.png new file mode 100644 index 0000000000..07e10d4644 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-below-source.ps3.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-below-source.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/over-below-source.quartz.rgb24.ref.png new file mode 100644 index 0000000000..f8b82a3eca Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-below-source.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-below-source.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/over-below-source.rgb24.ref.png new file mode 100644 index 0000000000..20ee671fac Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-below-source.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-below-source.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/over-below-source.traps.argb32.ref.png new file mode 100644 index 0000000000..c65936323b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-below-source.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-below-source.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/over-below-source.traps.rgb24.ref.png new file mode 100644 index 0000000000..88a85acbb5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-below-source.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-between-source.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/over-between-source.argb32.ref.png new file mode 100644 index 0000000000..9ba86f0e45 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-between-source.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-between-source.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/over-between-source.base.argb32.ref.png new file mode 100644 index 0000000000..a8fe66a303 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-between-source.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-between-source.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/over-between-source.base.rgb24.ref.png new file mode 100644 index 0000000000..bb77a9b97d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-between-source.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-between-source.ps2.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/over-between-source.ps2.argb32.ref.png new file mode 100644 index 0000000000..dd95940ae3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-between-source.ps2.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-between-source.ps3.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/over-between-source.ps3.argb32.ref.png new file mode 100644 index 0000000000..05dfb63b72 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-between-source.ps3.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-between-source.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/over-between-source.quartz.argb32.ref.png new file mode 100644 index 0000000000..8e7513be45 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-between-source.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-between-source.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/over-between-source.quartz.rgb24.ref.png new file mode 100644 index 0000000000..d2025455ee Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-between-source.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-between-source.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/over-between-source.rgb24.ref.png new file mode 100644 index 0000000000..b0d31e6f71 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-between-source.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-between-source.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/over-between-source.traps.argb32.ref.png new file mode 100644 index 0000000000..a8fe66a303 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-between-source.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/over-between-source.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/over-between-source.traps.rgb24.ref.png new file mode 100644 index 0000000000..bb77a9b97d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/over-between-source.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/overlapping-boxes.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/overlapping-boxes.base.argb32.ref.png new file mode 100644 index 0000000000..278e62a840 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/overlapping-boxes.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/overlapping-boxes.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/overlapping-boxes.base.rgb24.ref.png new file mode 100644 index 0000000000..f35d0e6b33 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/overlapping-boxes.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/overlapping-boxes.ps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/overlapping-boxes.ps.argb32.ref.png new file mode 100644 index 0000000000..65cb55021f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/overlapping-boxes.ps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/overlapping-boxes.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/overlapping-boxes.ps.rgb24.ref.png new file mode 100644 index 0000000000..0edeafa006 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/overlapping-boxes.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/overlapping-boxes.ref.png b/local/recipes/libs/cairo/source/test/reference/overlapping-boxes.ref.png new file mode 100644 index 0000000000..1c684381f2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/overlapping-boxes.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/overlapping-boxes.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/overlapping-boxes.traps.argb32.ref.png new file mode 100644 index 0000000000..278e62a840 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/overlapping-boxes.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/overlapping-boxes.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/overlapping-boxes.traps.rgb24.ref.png new file mode 100644 index 0000000000..f35d0e6b33 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/overlapping-boxes.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/overlapping-dash-caps.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/overlapping-dash-caps.base.argb32.ref.png new file mode 100644 index 0000000000..849a5163fa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/overlapping-dash-caps.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/overlapping-dash-caps.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/overlapping-dash-caps.base.rgb24.ref.png new file mode 100644 index 0000000000..849a5163fa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/overlapping-dash-caps.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/overlapping-dash-caps.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/overlapping-dash-caps.mask.argb32.ref.png new file mode 100644 index 0000000000..367d683575 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/overlapping-dash-caps.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/overlapping-dash-caps.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/overlapping-dash-caps.mask.rgb24.ref.png new file mode 100644 index 0000000000..367d683575 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/overlapping-dash-caps.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/overlapping-dash-caps.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/overlapping-dash-caps.quartz.ref.png new file mode 100644 index 0000000000..0d38a377c6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/overlapping-dash-caps.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/overlapping-dash-caps.ref.png b/local/recipes/libs/cairo/source/test/reference/overlapping-dash-caps.ref.png new file mode 100644 index 0000000000..1a2abf7388 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/overlapping-dash-caps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/overlapping-dash-caps.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/overlapping-dash-caps.traps.argb32.ref.png new file mode 100644 index 0000000000..849a5163fa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/overlapping-dash-caps.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/overlapping-dash-caps.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/overlapping-dash-caps.traps.rgb24.ref.png new file mode 100644 index 0000000000..849a5163fa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/overlapping-dash-caps.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.base.argb32.ref.png new file mode 100644 index 0000000000..11bf4e1111 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.base.rgb24.ref.png new file mode 100644 index 0000000000..6b65510448 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.pdf.argb32.ref.png new file mode 100644 index 0000000000..708d54acd7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.pdf.argb32.xfail.png b/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.pdf.argb32.xfail.png new file mode 100644 index 0000000000..e3e4337272 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.pdf.argb32.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.pdf.rgb24.ref.png new file mode 100644 index 0000000000..ff9e1c85c2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.pdf.rgb24.xfail.png b/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.pdf.rgb24.xfail.png new file mode 100644 index 0000000000..a3f1d70477 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.pdf.rgb24.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.ps.rgb24.ref.png new file mode 100644 index 0000000000..c4fd14661c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.quartz.argb32.ref.png new file mode 100644 index 0000000000..44200d59ee Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.quartz.rgb24.ref.png new file mode 100644 index 0000000000..d236e19a5f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.ref.png b/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.ref.png new file mode 100644 index 0000000000..4ec4ee5416 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.traps.argb32.ref.png new file mode 100644 index 0000000000..11bf4e1111 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.traps.rgb24.ref.png new file mode 100644 index 0000000000..6b65510448 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/overlapping-glyphs.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-clip-fill-aa.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-clip-fill-aa.base.argb32.ref.png new file mode 100644 index 0000000000..768322a393 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-clip-fill-aa.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-clip-fill-aa.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-clip-fill-aa.base.rgb24.ref.png new file mode 100644 index 0000000000..768322a393 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-clip-fill-aa.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-clip-fill-aa.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-clip-fill-aa.ps.ref.png new file mode 100644 index 0000000000..b6f7e82b59 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-clip-fill-aa.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-clip-fill-aa.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-clip-fill-aa.ref.png new file mode 100644 index 0000000000..a8cf417b31 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-clip-fill-aa.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-clip-fill-mono.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-clip-fill-mono.base.argb32.ref.png new file mode 100644 index 0000000000..768322a393 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-clip-fill-mono.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-clip-fill-mono.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-clip-fill-mono.base.rgb24.ref.png new file mode 100644 index 0000000000..768322a393 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-clip-fill-mono.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-clip-fill-mono.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-clip-fill-mono.ps.ref.png new file mode 100644 index 0000000000..b6f7e82b59 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-clip-fill-mono.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-clip-fill-mono.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-clip-fill-mono.ref.png new file mode 100644 index 0000000000..a8cf417b31 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-clip-fill-mono.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-repeat.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-repeat.base.argb32.ref.png new file mode 100644 index 0000000000..8cdd9b4bec Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-repeat.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-repeat.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-repeat.base.rgb24.ref.png new file mode 100644 index 0000000000..8cdd9b4bec Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-repeat.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-repeat.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-repeat.ref.png new file mode 100644 index 0000000000..2cc48f3363 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-repeat.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-source-alpha.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-source-alpha.base.argb32.ref.png new file mode 100644 index 0000000000..65d9c179bf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-source-alpha.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-source-alpha.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-source-alpha.base.rgb24.ref.png new file mode 100644 index 0000000000..65d9c179bf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-source-alpha.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-source-alpha.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-source-alpha.image16.ref.png new file mode 100644 index 0000000000..12bd89d55d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-source-alpha.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-source-alpha.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-source-alpha.pdf.ref.png new file mode 100644 index 0000000000..487b8b6227 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-source-alpha.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-source-alpha.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-source-alpha.ref.png new file mode 100644 index 0000000000..548bcd7f39 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-source-alpha.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip-mask.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip-mask.base.argb32.ref.png new file mode 100644 index 0000000000..95746ffcbe Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip-mask.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip-mask.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip-mask.base.rgb24.ref.png new file mode 100644 index 0000000000..95746ffcbe Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip-mask.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip-mask.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip-mask.mask.argb32.ref.png new file mode 100644 index 0000000000..95746ffcbe Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip-mask.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip-mask.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip-mask.mask.rgb24.ref.png new file mode 100644 index 0000000000..95746ffcbe Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip-mask.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip-mask.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip-mask.pdf.ref.png new file mode 100644 index 0000000000..35630c783b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip-mask.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip-mask.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip-mask.quartz.ref.png new file mode 100644 index 0000000000..34f46fae2c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip-mask.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip-mask.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip-mask.ref.png new file mode 100644 index 0000000000..4ee4c41acf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip-mask.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip-mask.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip-mask.traps.argb32.ref.png new file mode 100644 index 0000000000..201bd0d550 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip-mask.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip-mask.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip-mask.traps.rgb24.ref.png new file mode 100644 index 0000000000..201bd0d550 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip-mask.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip.base.argb32.ref.png new file mode 100644 index 0000000000..c1da67e013 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip.base.rgb24.ref.png new file mode 100644 index 0000000000..c1da67e013 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip.mask.argb32.ref.png new file mode 100644 index 0000000000..c1da67e013 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip.mask.rgb24.ref.png new file mode 100644 index 0000000000..c1da67e013 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip.pdf.ref.png new file mode 100644 index 0000000000..c3dabc5ce1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip.ref.png new file mode 100644 index 0000000000..4bad4e8ca5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip.traps.argb32.ref.png new file mode 100644 index 0000000000..c1da67e013 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip.traps.rgb24.ref.png new file mode 100644 index 0000000000..c1da67e013 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-clip.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-group-clip.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-group-clip.ref.png new file mode 100644 index 0000000000..e2dfb063a0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-group-clip.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-solid-clip.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-solid-clip.base.argb32.ref.png new file mode 100644 index 0000000000..59d226d1a4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-solid-clip.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-solid-clip.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-solid-clip.base.rgb24.ref.png new file mode 100644 index 0000000000..59d226d1a4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-solid-clip.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-solid-clip.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-solid-clip.mask.argb32.ref.png new file mode 100644 index 0000000000..2cd2df21cb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-solid-clip.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-solid-clip.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-solid-clip.mask.rgb24.ref.png new file mode 100644 index 0000000000..2cd2df21cb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-solid-clip.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-solid-clip.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-solid-clip.pdf.ref.png new file mode 100644 index 0000000000..034ba6d9b4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-solid-clip.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-solid-clip.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-solid-clip.ref.png new file mode 100644 index 0000000000..59d226d1a4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-solid-clip.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-solid-clip.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-solid-clip.svg.ref.png new file mode 100644 index 0000000000..034ba6d9b4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-solid-clip.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-solid-clip.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-solid-clip.traps.argb32.ref.png new file mode 100644 index 0000000000..2cd2df21cb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-solid-clip.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-solid-clip.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-solid-clip.traps.rgb24.ref.png new file mode 100644 index 0000000000..2cd2df21cb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha-solid-clip.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-with-alpha.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha.base.argb32.ref.png new file mode 100644 index 0000000000..65d9c179bf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-with-alpha.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha.base.rgb24.ref.png new file mode 100644 index 0000000000..65d9c179bf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-with-alpha.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha.image16.ref.png new file mode 100644 index 0000000000..12bd89d55d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-with-alpha.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha.pdf.ref.png new file mode 100644 index 0000000000..487b8b6227 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint-with-alpha.ref.png b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha.ref.png new file mode 100644 index 0000000000..ab7ce3e042 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint-with-alpha.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/paint.base.argb32.ref.png new file mode 100644 index 0000000000..22cc7a1ae5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/paint.base.rgb24.ref.png new file mode 100644 index 0000000000..22cc7a1ae5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/paint.ref.png b/local/recipes/libs/cairo/source/test/reference/paint.ref.png new file mode 100644 index 0000000000..fff03b363e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/paint.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-clip-text-bottom.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-bottom.base.argb32.ref.png new file mode 100644 index 0000000000..6a299d48cc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-bottom.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-clip-text-bottom.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-bottom.base.rgb24.ref.png new file mode 100644 index 0000000000..6a299d48cc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-bottom.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-clip-text-bottom.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-bottom.ps.ref.png new file mode 100644 index 0000000000..d4d82ddeea Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-bottom.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-clip-text-bottom.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-bottom.quartz.ref.png new file mode 100644 index 0000000000..7da297a11a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-bottom.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-clip-text-bottom.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-bottom.ref.png new file mode 100644 index 0000000000..6a299d48cc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-bottom.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-clip-text-bottom.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-bottom.svg.ref.png new file mode 100644 index 0000000000..267f0cc744 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-bottom.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-clip-text-left.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-left.base.argb32.ref.png new file mode 100644 index 0000000000..54a1a85862 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-left.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-clip-text-left.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-left.base.rgb24.ref.png new file mode 100644 index 0000000000..54a1a85862 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-left.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-clip-text-left.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-left.ps.ref.png new file mode 100644 index 0000000000..7387e382e0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-left.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-clip-text-left.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-left.quartz.ref.png new file mode 100644 index 0000000000..20cc556a94 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-left.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-clip-text-left.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-left.ref.png new file mode 100644 index 0000000000..54a1a85862 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-left.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-clip-text-left.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-left.svg.ref.png new file mode 100644 index 0000000000..e470880919 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-left.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-clip-text-right.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-right.base.argb32.ref.png new file mode 100644 index 0000000000..2fbdca0382 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-right.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-clip-text-right.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-right.base.rgb24.ref.png new file mode 100644 index 0000000000..2fbdca0382 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-right.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-clip-text-right.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-right.ps.ref.png new file mode 100644 index 0000000000..344ac5086c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-right.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-clip-text-right.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-right.quartz.ref.png new file mode 100644 index 0000000000..c8b14c9efc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-right.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-clip-text-right.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-right.ref.png new file mode 100644 index 0000000000..2fbdca0382 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-right.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-clip-text-right.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-right.svg.ref.png new file mode 100644 index 0000000000..9c0bdb8f9b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-right.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-clip-text-top.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-top.base.argb32.ref.png new file mode 100644 index 0000000000..d18475be3b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-top.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-clip-text-top.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-top.base.rgb24.ref.png new file mode 100644 index 0000000000..d18475be3b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-top.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-clip-text-top.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-top.ps.ref.png new file mode 100644 index 0000000000..3f0ca42f3d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-top.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-clip-text-top.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-top.quartz.ref.png new file mode 100644 index 0000000000..15c3994321 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-top.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-clip-text-top.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-top.ref.png new file mode 100644 index 0000000000..d18475be3b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-top.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-clip-text-top.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-top.svg.ref.png new file mode 100644 index 0000000000..c445867cdf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-clip-text-top.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-coverage-half-reference.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-coverage-half-reference.base.argb32.ref.png new file mode 100644 index 0000000000..17f4ff06b3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-coverage-half-reference.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-coverage-half-reference.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-coverage-half-reference.base.rgb24.ref.png new file mode 100644 index 0000000000..17f4ff06b3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-coverage-half-reference.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-coverage-half-reference.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-coverage-half-reference.ref.png new file mode 100644 index 0000000000..17f4ff06b3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-coverage-half-reference.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-coverage-half-triangles.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-coverage-half-triangles.ref.png new file mode 100644 index 0000000000..17f4ff06b3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-coverage-half-triangles.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-coverage-intersecting-quads.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-coverage-intersecting-quads.ref.png new file mode 100644 index 0000000000..17f4ff06b3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-coverage-intersecting-quads.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-coverage-intersecting-quads.xfail.png b/local/recipes/libs/cairo/source/test/reference/partial-coverage-intersecting-quads.xfail.png new file mode 100644 index 0000000000..a6635b9e81 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-coverage-intersecting-quads.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-coverage-intersecting-triangles.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-coverage-intersecting-triangles.ref.png new file mode 100644 index 0000000000..9e4a6fe42b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-coverage-intersecting-triangles.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-coverage-overlap-half-triangles-eo.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-coverage-overlap-half-triangles-eo.ref.png new file mode 100644 index 0000000000..17f4ff06b3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-coverage-overlap-half-triangles-eo.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-coverage-overlap-half-triangles.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-coverage-overlap-half-triangles.ref.png new file mode 100644 index 0000000000..17f4ff06b3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-coverage-overlap-half-triangles.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-coverage-overlap-three-quarter-triangles.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-coverage-overlap-three-quarter-triangles.ref.png new file mode 100644 index 0000000000..ea16dc4bb1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-coverage-overlap-three-quarter-triangles.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-coverage-rectangles.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-coverage-rectangles.ref.png new file mode 100644 index 0000000000..9e4a6fe42b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-coverage-rectangles.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-coverage-reference.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-coverage-reference.base.argb32.ref.png new file mode 100644 index 0000000000..9e4a6fe42b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-coverage-reference.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-coverage-reference.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-coverage-reference.base.rgb24.ref.png new file mode 100644 index 0000000000..9e4a6fe42b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-coverage-reference.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-coverage-reference.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-coverage-reference.ref.png new file mode 100644 index 0000000000..9e4a6fe42b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-coverage-reference.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-coverage-three-quarter-reference.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-coverage-three-quarter-reference.base.argb32.ref.png new file mode 100644 index 0000000000..ea16dc4bb1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-coverage-three-quarter-reference.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-coverage-three-quarter-reference.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-coverage-three-quarter-reference.base.rgb24.ref.png new file mode 100644 index 0000000000..ea16dc4bb1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-coverage-three-quarter-reference.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-coverage-three-quarter-reference.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-coverage-three-quarter-reference.ref.png new file mode 100644 index 0000000000..ea16dc4bb1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-coverage-three-quarter-reference.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/partial-coverage-triangles.ref.png b/local/recipes/libs/cairo/source/test/reference/partial-coverage-triangles.ref.png new file mode 100644 index 0000000000..9e4a6fe42b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/partial-coverage-triangles.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pass-through.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/pass-through.base.argb32.ref.png new file mode 100644 index 0000000000..058a1920fd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pass-through.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pass-through.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/pass-through.base.rgb24.ref.png new file mode 100644 index 0000000000..1be631aad7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pass-through.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pass-through.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/pass-through.ps.rgb24.ref.png new file mode 100644 index 0000000000..e98cb9ed88 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pass-through.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pass-through.ref.png b/local/recipes/libs/cairo/source/test/reference/pass-through.ref.png new file mode 100644 index 0000000000..058a1920fd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pass-through.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/path-append.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/path-append.base.argb32.ref.png new file mode 100644 index 0000000000..6fb6b2a332 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/path-append.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/path-append.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/path-append.base.rgb24.ref.png new file mode 100644 index 0000000000..6fb6b2a332 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/path-append.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/path-append.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/path-append.image16.ref.png new file mode 100644 index 0000000000..5d939bbc1b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/path-append.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/path-append.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/path-append.ps.ref.png new file mode 100644 index 0000000000..2c8df16988 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/path-append.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/path-append.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/path-append.quartz.ref.png new file mode 100644 index 0000000000..665d3ccb91 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/path-append.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/path-append.ref.png b/local/recipes/libs/cairo/source/test/reference/path-append.ref.png new file mode 100644 index 0000000000..33af231bb2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/path-append.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/path-append.test-fallback.ref.png b/local/recipes/libs/cairo/source/test/reference/path-append.test-fallback.ref.png new file mode 100644 index 0000000000..fa72ac06f3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/path-append.test-fallback.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/path-append.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/path-append.traps.argb32.ref.png new file mode 100644 index 0000000000..6fb6b2a332 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/path-append.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/path-append.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/path-append.traps.rgb24.ref.png new file mode 100644 index 0000000000..6fb6b2a332 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/path-append.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/path-append.xlib-fallback.ref.png b/local/recipes/libs/cairo/source/test/reference/path-append.xlib-fallback.ref.png new file mode 100644 index 0000000000..d34cce1250 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/path-append.xlib-fallback.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/path-stroke-twice.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/path-stroke-twice.base.argb32.ref.png new file mode 100644 index 0000000000..48dd2c7c6f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/path-stroke-twice.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/path-stroke-twice.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/path-stroke-twice.base.rgb24.ref.png new file mode 100644 index 0000000000..48dd2c7c6f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/path-stroke-twice.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/path-stroke-twice.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/path-stroke-twice.image16.ref.png new file mode 100644 index 0000000000..9f162adf33 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/path-stroke-twice.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/path-stroke-twice.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/path-stroke-twice.pdf.ref.png new file mode 100644 index 0000000000..10763bfd81 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/path-stroke-twice.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/path-stroke-twice.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/path-stroke-twice.ps.ref.png new file mode 100644 index 0000000000..23e8147433 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/path-stroke-twice.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/path-stroke-twice.ref.png b/local/recipes/libs/cairo/source/test/reference/path-stroke-twice.ref.png new file mode 100644 index 0000000000..743c6ce529 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/path-stroke-twice.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/path-stroke-twice.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/path-stroke-twice.svg.ref.png new file mode 100644 index 0000000000..10763bfd81 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/path-stroke-twice.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/path-stroke-twice.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/path-stroke-twice.traps.argb32.ref.png new file mode 100644 index 0000000000..48dd2c7c6f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/path-stroke-twice.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/path-stroke-twice.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/path-stroke-twice.traps.rgb24.ref.png new file mode 100644 index 0000000000..48dd2c7c6f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/path-stroke-twice.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pattern-getters.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/pattern-getters.base.argb32.ref.png new file mode 100644 index 0000000000..3cc39a8bed Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pattern-getters.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pattern-getters.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/pattern-getters.base.rgb24.ref.png new file mode 100644 index 0000000000..3cc39a8bed Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pattern-getters.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pattern-getters.ref.png b/local/recipes/libs/cairo/source/test/reference/pattern-getters.ref.png new file mode 100644 index 0000000000..80304b0ecd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pattern-getters.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pdf-isolated-group.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/pdf-isolated-group.base.argb32.ref.png new file mode 100644 index 0000000000..6c8522ccc1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pdf-isolated-group.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pdf-isolated-group.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/pdf-isolated-group.base.rgb24.ref.png new file mode 100644 index 0000000000..6c8522ccc1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pdf-isolated-group.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pdf-isolated-group.ref.png b/local/recipes/libs/cairo/source/test/reference/pdf-isolated-group.ref.png new file mode 100644 index 0000000000..6c8522ccc1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pdf-isolated-group.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pdf-operators-text.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/pdf-operators-text.image16.ref.png new file mode 100644 index 0000000000..e85ee006ce Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pdf-operators-text.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pdf-operators-text.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/pdf-operators-text.pdf.ref.png new file mode 100644 index 0000000000..b52b833f00 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pdf-operators-text.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pdf-operators-text.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/pdf-operators-text.ps.ref.png new file mode 100644 index 0000000000..e6c1b05a10 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pdf-operators-text.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pdf-operators-text.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/pdf-operators-text.quartz.ref.png new file mode 100644 index 0000000000..ecfa7cc5d9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pdf-operators-text.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pdf-operators-text.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/pdf-operators-text.quartz.xfail.png new file mode 100644 index 0000000000..62e006aa2b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pdf-operators-text.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pdf-operators-text.ref.png b/local/recipes/libs/cairo/source/test/reference/pdf-operators-text.ref.png new file mode 100644 index 0000000000..970f3fd996 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pdf-operators-text.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pdf-operators-text.script.xfail.png b/local/recipes/libs/cairo/source/test/reference/pdf-operators-text.script.xfail.png new file mode 100644 index 0000000000..62050a832e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pdf-operators-text.script.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pdf-operators-text.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/pdf-operators-text.svg.ref.png new file mode 100644 index 0000000000..c8b6b73a27 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pdf-operators-text.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pdf-operators-text.xcb.ref.png b/local/recipes/libs/cairo/source/test/reference/pdf-operators-text.xcb.ref.png new file mode 100644 index 0000000000..bbb8a446d8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pdf-operators-text.xcb.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pdf-operators-text.xlib.ref.png b/local/recipes/libs/cairo/source/test/reference/pdf-operators-text.xlib.ref.png new file mode 100644 index 0000000000..bbb8a446d8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pdf-operators-text.xlib.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pdf-structure-group-ref.ref.txt b/local/recipes/libs/cairo/source/test/reference/pdf-structure-group-ref.ref.txt new file mode 100644 index 0000000000..8b1d97fef9 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/reference/pdf-structure-group-ref.ref.txt @@ -0,0 +1,6 @@ +Document + H (block) + "Heading" + Sect + P (block) + "Para1Para2" diff --git a/local/recipes/libs/cairo/source/test/reference/pdf-structure-group.ref.txt b/local/recipes/libs/cairo/source/test/reference/pdf-structure-group.ref.txt new file mode 100644 index 0000000000..8b1d97fef9 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/reference/pdf-structure-group.ref.txt @@ -0,0 +1,6 @@ +Document + H (block) + "Heading" + Sect + P (block) + "Para1Para2" diff --git a/local/recipes/libs/cairo/source/test/reference/pdf-structure-group2.ref.txt b/local/recipes/libs/cairo/source/test/reference/pdf-structure-group2.ref.txt new file mode 100644 index 0000000000..f15c0bc240 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/reference/pdf-structure-group2.ref.txt @@ -0,0 +1,4 @@ +H (block) + "Heading" +P (block) + "Para1" diff --git a/local/recipes/libs/cairo/source/test/reference/pdf-structure-group3.ref.txt b/local/recipes/libs/cairo/source/test/reference/pdf-structure-group3.ref.txt new file mode 100644 index 0000000000..9db4d26d2e --- /dev/null +++ b/local/recipes/libs/cairo/source/test/reference/pdf-structure-group3.ref.txt @@ -0,0 +1,6 @@ +Document + H (block) + "Heading" + P (block) + "Para1" + "text" diff --git a/local/recipes/libs/cairo/source/test/reference/pdf-structure-multipage-group.ref.txt b/local/recipes/libs/cairo/source/test/reference/pdf-structure-multipage-group.ref.txt new file mode 100644 index 0000000000..61b470ccc4 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/reference/pdf-structure-multipage-group.ref.txt @@ -0,0 +1,8 @@ +Document + H (block) + "Heading" + Sect + P (block) + "Para1Para2" + P (block) + "Para3" diff --git a/local/recipes/libs/cairo/source/test/reference/pdf-structure-multipage-group2.ref.txt b/local/recipes/libs/cairo/source/test/reference/pdf-structure-multipage-group2.ref.txt new file mode 100644 index 0000000000..0fbed52f1d --- /dev/null +++ b/local/recipes/libs/cairo/source/test/reference/pdf-structure-multipage-group2.ref.txt @@ -0,0 +1,10 @@ +Document + H (block) + "Heading" + Sect + P (block) + "Para1Para2" + P (block) + "Para1Para2" + P (block) + "Para3" diff --git a/local/recipes/libs/cairo/source/test/reference/pdf-structure-multipage-simple-ref.ref.txt b/local/recipes/libs/cairo/source/test/reference/pdf-structure-multipage-simple-ref.ref.txt new file mode 100644 index 0000000000..5a22505c90 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/reference/pdf-structure-multipage-simple-ref.ref.txt @@ -0,0 +1,12 @@ +Document + H (block) + Link (inline) + Object 21 0 + "Heading1" + Link (inline) + Object 24 0 + "Heading2" + Sect + P (block) + "Para1" + "Para2" diff --git a/local/recipes/libs/cairo/source/test/reference/pdf-structure-multipage-simple.ref.txt b/local/recipes/libs/cairo/source/test/reference/pdf-structure-multipage-simple.ref.txt new file mode 100644 index 0000000000..4d535fbf8f --- /dev/null +++ b/local/recipes/libs/cairo/source/test/reference/pdf-structure-multipage-simple.ref.txt @@ -0,0 +1,12 @@ +Document + H (block) + Link (inline) + Object 6 0 + "Heading1" + Link (inline) + Object 8 0 + "Heading2" + Sect + P (block) + "Para1" + "Para2" diff --git a/local/recipes/libs/cairo/source/test/reference/pdf-structure-repeated-group.ref.txt b/local/recipes/libs/cairo/source/test/reference/pdf-structure-repeated-group.ref.txt new file mode 100644 index 0000000000..5292f0127b --- /dev/null +++ b/local/recipes/libs/cairo/source/test/reference/pdf-structure-repeated-group.ref.txt @@ -0,0 +1,9 @@ +Document + H (block) + "Heading" + Sect + P (block) + "Para1Para2" + P (block) + "Para1Para2" + "Para1Para2Text" diff --git a/local/recipes/libs/cairo/source/test/reference/pdf-structure-simple-ref.ref.txt b/local/recipes/libs/cairo/source/test/reference/pdf-structure-simple-ref.ref.txt new file mode 100644 index 0000000000..0b0541c0a3 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/reference/pdf-structure-simple-ref.ref.txt @@ -0,0 +1,11 @@ +Document + H (block) + "Heading" + Sect + P (block) + "Para1Para2" + P (block) + "Para3" + Note (inline) + "Note" + "Para4" diff --git a/local/recipes/libs/cairo/source/test/reference/pdf-structure-simple.ref.txt b/local/recipes/libs/cairo/source/test/reference/pdf-structure-simple.ref.txt new file mode 100644 index 0000000000..0b0541c0a3 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/reference/pdf-structure-simple.ref.txt @@ -0,0 +1,11 @@ +Document + H (block) + "Heading" + Sect + P (block) + "Para1Para2" + P (block) + "Para3" + Note (inline) + "Note" + "Para4" diff --git a/local/recipes/libs/cairo/source/test/reference/pdf-surface-source.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/pdf-surface-source.base.argb32.ref.png new file mode 100644 index 0000000000..018297208e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pdf-surface-source.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pdf-surface-source.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/pdf-surface-source.base.rgb24.ref.png new file mode 100644 index 0000000000..0d68a82cc2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pdf-surface-source.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pdf-surface-source.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/pdf-surface-source.image16.ref.png new file mode 100644 index 0000000000..2a7460e284 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pdf-surface-source.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pdf-surface-source.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/pdf-surface-source.ps.ref.png new file mode 100644 index 0000000000..6f49373161 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pdf-surface-source.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pdf-surface-source.ref.png b/local/recipes/libs/cairo/source/test/reference/pdf-surface-source.ref.png new file mode 100644 index 0000000000..018297208e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pdf-surface-source.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pdf-surface-source.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/pdf-surface-source.svg.ref.png new file mode 100644 index 0000000000..45c409681a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pdf-surface-source.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-24.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-24.pdf.ref.png new file mode 100644 index 0000000000..c6178045a2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-24.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-24.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-24.ps.ref.png new file mode 100644 index 0000000000..e861b900ae Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-24.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-24.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-24.quartz.ref.png new file mode 100644 index 0000000000..bdb78f951b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-24.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-24.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-24.ref.png new file mode 100644 index 0000000000..184a64b742 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-24.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-24.svg.ref.png new file mode 100644 index 0000000000..d21ea5a2e2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-24.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.image.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.image.rgb24.ref.png new file mode 100644 index 0000000000..5885c4bccf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.image.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.image16.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.image16.rgb24.ref.png new file mode 100644 index 0000000000..37783991d6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.image16.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.pdf.ref.png new file mode 100644 index 0000000000..71b518e1ed Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.ps2.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.ps2.ref.png new file mode 100644 index 0000000000..08983dca68 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.ps2.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.ps3.ref.png new file mode 100644 index 0000000000..08983dca68 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.quartz.ref.png new file mode 100644 index 0000000000..30547fac71 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.recording.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.recording.rgb24.ref.png new file mode 100644 index 0000000000..5885c4bccf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.recording.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.ref.png new file mode 100644 index 0000000000..1b98e8f634 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.script.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.script.ref.png new file mode 100644 index 0000000000..f3bd7ff814 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.script.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.svg.ref.png new file mode 100644 index 0000000000..777f448e3d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.test-base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.test-base.rgb24.ref.png new file mode 100644 index 0000000000..5885c4bccf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.test-base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.test-fallback.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.test-fallback.rgb24.ref.png new file mode 100644 index 0000000000..5885c4bccf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.test-fallback.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.test-mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.test-mask.rgb24.ref.png new file mode 100644 index 0000000000..5885c4bccf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.test-mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.test-paginated.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.test-paginated.rgb24.ref.png new file mode 100644 index 0000000000..5885c4bccf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.test-paginated.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.test-spans.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.test-spans.rgb24.ref.png new file mode 100644 index 0000000000..5885c4bccf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.test-spans.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.test-traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.test-traps.rgb24.ref.png new file mode 100644 index 0000000000..5885c4bccf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.test-traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.xcb-fallback.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.xcb-fallback.rgb24.ref.png new file mode 100644 index 0000000000..5885c4bccf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.xcb-fallback.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.xcb-render-0_0.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.xcb-render-0_0.rgb24.ref.png new file mode 100644 index 0000000000..5885c4bccf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.xcb-render-0_0.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.xcb-window&.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.xcb-window&.rgb24.ref.png new file mode 100644 index 0000000000..777f448e3d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.xcb-window&.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.xcb-window.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.xcb-window.rgb24.ref.png new file mode 100644 index 0000000000..777f448e3d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.xcb-window.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.xcb.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.xcb.ref.png new file mode 100644 index 0000000000..777f448e3d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.xcb.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.xlib-fallback.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.xlib-fallback.rgb24.ref.png new file mode 100644 index 0000000000..5885c4bccf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.xlib-fallback.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.xlib-render-0_0.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.xlib-render-0_0.rgb24.ref.png new file mode 100644 index 0000000000..5885c4bccf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.xlib-render-0_0.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.xlib-window.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.xlib-window.rgb24.ref.png new file mode 100644 index 0000000000..777f448e3d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.xlib-window.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.xlib.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.xlib.ref.png new file mode 100644 index 0000000000..777f448e3d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-95.xlib.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-96.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-96.ps.ref.png new file mode 100644 index 0000000000..ae867d6897 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-96.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-96.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-96.ref.png new file mode 100644 index 0000000000..0d68a82cc2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-best-96.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-24.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-24.ps.ref.png new file mode 100644 index 0000000000..e861b900ae Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-24.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-24.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-24.ref.png new file mode 100644 index 0000000000..df0f9c0d84 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-24.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-24.svg.ref.png new file mode 100644 index 0000000000..d21ea5a2e2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-24.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-95.image16.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-95.image16.rgb24.ref.png new file mode 100644 index 0000000000..9d67251e23 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-95.image16.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-95.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-95.pdf.ref.png new file mode 100644 index 0000000000..71b518e1ed Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-95.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-95.ps2.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-95.ps2.ref.png new file mode 100644 index 0000000000..08983dca68 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-95.ps2.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-95.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-95.ps3.ref.png new file mode 100644 index 0000000000..08983dca68 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-95.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-95.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-95.quartz.ref.png new file mode 100644 index 0000000000..43b477942e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-95.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-95.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-95.ref.png new file mode 100644 index 0000000000..777f448e3d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-95.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-95.script.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-95.script.ref.png new file mode 100644 index 0000000000..fa4c04c023 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-95.script.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-96.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-96.ps.ref.png new file mode 100644 index 0000000000..ae867d6897 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-96.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-96.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-96.ref.png new file mode 100644 index 0000000000..0d68a82cc2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-bilinear-96.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-fast-24.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-fast-24.ref.png new file mode 100644 index 0000000000..df0f9c0d84 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-fast-24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-fast-24.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-fast-24.svg.ref.png new file mode 100644 index 0000000000..d21ea5a2e2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-fast-24.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-fast-95.image16.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-fast-95.image16.rgb24.ref.png new file mode 100644 index 0000000000..a2b67156fd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-fast-95.image16.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-fast-95.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-fast-95.pdf.ref.png new file mode 100644 index 0000000000..71b518e1ed Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-fast-95.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-fast-95.ps2.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-fast-95.ps2.ref.png new file mode 100644 index 0000000000..af93ae72d3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-fast-95.ps2.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-fast-95.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-fast-95.ps3.ref.png new file mode 100644 index 0000000000..af93ae72d3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-fast-95.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-fast-95.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-fast-95.quartz.ref.png new file mode 100644 index 0000000000..350d7305de Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-fast-95.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-fast-95.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-fast-95.ref.png new file mode 100644 index 0000000000..3340423fce Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-fast-95.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-fast-95.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-fast-95.svg.ref.png new file mode 100644 index 0000000000..777f448e3d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-fast-95.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-fast-96.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-fast-96.ref.png new file mode 100644 index 0000000000..0d68a82cc2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-fast-96.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-24.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-24.ps.ref.png new file mode 100644 index 0000000000..e861b900ae Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-24.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-24.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-24.ref.png new file mode 100644 index 0000000000..df0f9c0d84 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-24.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-24.svg.ref.png new file mode 100644 index 0000000000..d21ea5a2e2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-24.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-95.image16.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-95.image16.rgb24.ref.png new file mode 100644 index 0000000000..9d67251e23 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-95.image16.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-95.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-95.pdf.ref.png new file mode 100644 index 0000000000..71b518e1ed Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-95.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-95.ps2.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-95.ps2.ref.png new file mode 100644 index 0000000000..08983dca68 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-95.ps2.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-95.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-95.ps3.ref.png new file mode 100644 index 0000000000..08983dca68 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-95.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-95.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-95.quartz.ref.png new file mode 100644 index 0000000000..43b477942e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-95.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-95.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-95.ref.png new file mode 100644 index 0000000000..777f448e3d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-95.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-95.script.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-95.script.ref.png new file mode 100644 index 0000000000..fa4c04c023 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-95.script.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-96.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-96.ps.ref.png new file mode 100644 index 0000000000..ae867d6897 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-96.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-96.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-96.ref.png new file mode 100644 index 0000000000..0d68a82cc2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-good-96.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-nearest-24.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-nearest-24.ref.png new file mode 100644 index 0000000000..df0f9c0d84 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-nearest-24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-nearest-24.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-nearest-24.svg.ref.png new file mode 100644 index 0000000000..d21ea5a2e2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-nearest-24.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-nearest-95.image16.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-nearest-95.image16.rgb24.ref.png new file mode 100644 index 0000000000..a2b67156fd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-nearest-95.image16.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-nearest-95.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-nearest-95.pdf.ref.png new file mode 100644 index 0000000000..71b518e1ed Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-nearest-95.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-nearest-95.ps2.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-nearest-95.ps2.ref.png new file mode 100644 index 0000000000..af93ae72d3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-nearest-95.ps2.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-nearest-95.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-nearest-95.ps3.ref.png new file mode 100644 index 0000000000..af93ae72d3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-nearest-95.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-nearest-95.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-nearest-95.quartz.ref.png new file mode 100644 index 0000000000..350d7305de Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-nearest-95.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-nearest-95.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-nearest-95.ref.png new file mode 100644 index 0000000000..3340423fce Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-nearest-95.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-nearest-95.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-nearest-95.svg.ref.png new file mode 100644 index 0000000000..777f448e3d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-nearest-95.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-downscale-nearest-96.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-nearest-96.ref.png new file mode 100644 index 0000000000..0d68a82cc2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-downscale-nearest-96.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-rotate.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-rotate.base.argb32.ref.png new file mode 100644 index 0000000000..7e47a4d8f5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-rotate.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-rotate.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-rotate.base.rgb24.ref.png new file mode 100644 index 0000000000..397acbe7e0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-rotate.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-rotate.ps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-rotate.ps.argb32.ref.png new file mode 100644 index 0000000000..e65385c29a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-rotate.ps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-rotate.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-rotate.ps.rgb24.ref.png new file mode 100644 index 0000000000..59a0f436a4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-rotate.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-rotate.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-rotate.quartz.rgb24.ref.png new file mode 100644 index 0000000000..9ef09c3513 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-rotate.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-rotate.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-rotate.ref.png new file mode 100644 index 0000000000..7e47a4d8f5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-rotate.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pixman-rotate.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/pixman-rotate.svg.ref.png new file mode 100644 index 0000000000..91d75d0f62 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pixman-rotate.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ps-eps.ref.png b/local/recipes/libs/cairo/source/test/reference/ps-eps.ref.png new file mode 100644 index 0000000000..9aadb08871 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ps-eps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ps-surface-source.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/ps-surface-source.base.argb32.ref.png new file mode 100644 index 0000000000..018297208e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ps-surface-source.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ps-surface-source.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/ps-surface-source.base.rgb24.ref.png new file mode 100644 index 0000000000..0d68a82cc2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ps-surface-source.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ps-surface-source.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/ps-surface-source.image16.ref.png new file mode 100644 index 0000000000..2a7460e284 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ps-surface-source.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ps-surface-source.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/ps-surface-source.ps.ref.png new file mode 100644 index 0000000000..6f49373161 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ps-surface-source.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ps-surface-source.ref.png b/local/recipes/libs/cairo/source/test/reference/ps-surface-source.ref.png new file mode 100644 index 0000000000..018297208e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ps-surface-source.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/ps-surface-source.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/ps-surface-source.svg.ref.png new file mode 100644 index 0000000000..45c409681a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/ps-surface-source.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pthread-same-source.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/pthread-same-source.image16.ref.png new file mode 100644 index 0000000000..67eb22f9d7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pthread-same-source.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pthread-same-source.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/pthread-same-source.quartz.ref.png new file mode 100644 index 0000000000..2cd620f433 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pthread-same-source.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pthread-same-source.ref.png b/local/recipes/libs/cairo/source/test/reference/pthread-same-source.ref.png new file mode 100644 index 0000000000..92a86c2f6e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pthread-same-source.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pthread-same-source.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/pthread-same-source.svg.ref.png new file mode 100644 index 0000000000..b64337fe83 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pthread-same-source.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pthread-show-text.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/pthread-show-text.base.argb32.ref.png new file mode 100644 index 0000000000..90d0af349a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pthread-show-text.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pthread-show-text.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/pthread-show-text.base.rgb24.ref.png new file mode 100644 index 0000000000..90d0af349a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pthread-show-text.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pthread-show-text.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/pthread-show-text.image16.ref.png new file mode 100644 index 0000000000..a1d1af57cd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pthread-show-text.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pthread-show-text.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/pthread-show-text.pdf.ref.png new file mode 100644 index 0000000000..9da49858b5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pthread-show-text.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pthread-show-text.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/pthread-show-text.ps.ref.png new file mode 100644 index 0000000000..4b6a495943 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pthread-show-text.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pthread-show-text.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/pthread-show-text.quartz.ref.png new file mode 100644 index 0000000000..5d51b40ad0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pthread-show-text.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pthread-show-text.ref.png b/local/recipes/libs/cairo/source/test/reference/pthread-show-text.ref.png new file mode 100644 index 0000000000..a359009bec Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pthread-show-text.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pthread-show-text.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/pthread-show-text.svg.ref.png new file mode 100644 index 0000000000..c6b2c3a641 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pthread-show-text.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pthread-show-text.traps.ref.png b/local/recipes/libs/cairo/source/test/reference/pthread-show-text.traps.ref.png new file mode 100644 index 0000000000..90d0af349a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pthread-show-text.traps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pthread-show-text.xlib-fallback.ref.png b/local/recipes/libs/cairo/source/test/reference/pthread-show-text.xlib-fallback.ref.png new file mode 100644 index 0000000000..d96abed47b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pthread-show-text.xlib-fallback.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pthread-similar.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/pthread-similar.base.argb32.ref.png new file mode 100644 index 0000000000..a22210db81 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pthread-similar.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pthread-similar.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/pthread-similar.base.rgb24.ref.png new file mode 100644 index 0000000000..a22210db81 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pthread-similar.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pthread-similar.ref.png b/local/recipes/libs/cairo/source/test/reference/pthread-similar.ref.png new file mode 100644 index 0000000000..c8763ba0ea Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pthread-similar.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/pthread-similar.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/pthread-similar.svg.ref.png new file mode 100644 index 0000000000..401b1fee7e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/pthread-similar.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/push-group-color.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/push-group-color.base.argb32.ref.png new file mode 100644 index 0000000000..11b1014e0f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/push-group-color.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/push-group-color.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/push-group-color.base.rgb24.ref.png new file mode 100644 index 0000000000..11b1014e0f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/push-group-color.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/push-group-color.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/push-group-color.image16.ref.png new file mode 100644 index 0000000000..6378b75ad6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/push-group-color.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/push-group-color.ps2.ref.png b/local/recipes/libs/cairo/source/test/reference/push-group-color.ps2.ref.png new file mode 100644 index 0000000000..daf827ee32 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/push-group-color.ps2.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/push-group-color.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/push-group-color.ps3.ref.png new file mode 100644 index 0000000000..291fcec8d3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/push-group-color.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/push-group-color.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/push-group-color.quartz.ref.png new file mode 100644 index 0000000000..9a46bb0f64 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/push-group-color.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/push-group-color.ref.png b/local/recipes/libs/cairo/source/test/reference/push-group-color.ref.png new file mode 100644 index 0000000000..a2842b092c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/push-group-color.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/push-group-color.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/push-group-color.svg.ref.png new file mode 100644 index 0000000000..f0cefa6ca0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/push-group-color.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/push-group-color.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/push-group-color.traps.argb32.ref.png new file mode 100644 index 0000000000..11b1014e0f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/push-group-color.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/push-group-color.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/push-group-color.traps.rgb24.ref.png new file mode 100644 index 0000000000..11b1014e0f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/push-group-color.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/push-group-path-offset.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/push-group-path-offset.base.argb32.ref.png new file mode 100644 index 0000000000..b836a9197f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/push-group-path-offset.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/push-group-path-offset.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/push-group-path-offset.base.rgb24.ref.png new file mode 100644 index 0000000000..b836a9197f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/push-group-path-offset.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/push-group-path-offset.ref.png b/local/recipes/libs/cairo/source/test/reference/push-group-path-offset.ref.png new file mode 100644 index 0000000000..b836a9197f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/push-group-path-offset.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/push-group.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/push-group.argb32.ref.png new file mode 100644 index 0000000000..28dcf0c270 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/push-group.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/push-group.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/push-group.base.argb32.ref.png new file mode 100644 index 0000000000..9d27f4508f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/push-group.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/push-group.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/push-group.base.rgb24.ref.png new file mode 100644 index 0000000000..e19694f02a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/push-group.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/push-group.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/push-group.image16.ref.png new file mode 100644 index 0000000000..9990405835 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/push-group.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/push-group.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/push-group.quartz.argb32.ref.png new file mode 100644 index 0000000000..b8de2e60a3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/push-group.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/push-group.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/push-group.quartz.rgb24.ref.png new file mode 100644 index 0000000000..74a87b1328 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/push-group.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/push-group.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/push-group.rgb24.ref.png new file mode 100644 index 0000000000..ca67068216 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/push-group.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/push-group.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/push-group.svg.ref.png new file mode 100644 index 0000000000..a7bcc1f36e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/push-group.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/push-group.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/push-group.traps.argb32.ref.png new file mode 100644 index 0000000000..9d27f4508f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/push-group.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/push-group.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/push-group.traps.rgb24.ref.png new file mode 100644 index 0000000000..e19694f02a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/push-group.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/quartz-color-font.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/quartz-color-font.quartz.rgb24.ref.png new file mode 100644 index 0000000000..00a0c4499e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/quartz-color-font.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/quartz-color-font.ref.png b/local/recipes/libs/cairo/source/test/reference/quartz-color-font.ref.png new file mode 100644 index 0000000000..0c185ae1b5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/quartz-color-font.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/quartz-surface-source.ps2.ref.png b/local/recipes/libs/cairo/source/test/reference/quartz-surface-source.ps2.ref.png new file mode 100644 index 0000000000..10231581bf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/quartz-surface-source.ps2.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/quartz-surface-source.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/quartz-surface-source.ps3.ref.png new file mode 100644 index 0000000000..10231581bf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/quartz-surface-source.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/quartz-surface-source.ref.png b/local/recipes/libs/cairo/source/test/reference/quartz-surface-source.ref.png new file mode 100644 index 0000000000..018297208e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/quartz-surface-source.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-extend.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-extend.base.argb32.ref.png new file mode 100644 index 0000000000..3d7de5e564 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-extend.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-extend.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-extend.base.rgb24.ref.png new file mode 100644 index 0000000000..3d7de5e564 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-extend.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-extend.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-extend.mask.argb32.ref.png new file mode 100644 index 0000000000..3d7de5e564 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-extend.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-extend.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-extend.mask.rgb24.ref.png new file mode 100644 index 0000000000..3d7de5e564 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-extend.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-extend.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-extend.pdf.ref.png new file mode 100644 index 0000000000..fb78785350 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-extend.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-extend.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-extend.ps3.ref.png new file mode 100644 index 0000000000..e84041eaeb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-extend.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-extend.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-extend.ref.png new file mode 100644 index 0000000000..3d7de5e564 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-extend.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-extend.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-extend.svg.ref.png new file mode 100644 index 0000000000..fb78785350 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-extend.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-extend.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-extend.traps.argb32.ref.png new file mode 100644 index 0000000000..3d7de5e564 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-extend.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-extend.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-extend.traps.rgb24.ref.png new file mode 100644 index 0000000000..3d7de5e564 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-extend.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask-source.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask-source.argb32.ref.png new file mode 100644 index 0000000000..8e41bcfee2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask-source.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask-source.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask-source.base.argb32.ref.png new file mode 100644 index 0000000000..2bf65b3d69 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask-source.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask-source.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask-source.base.rgb24.ref.png new file mode 100644 index 0000000000..55335196aa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask-source.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask-source.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask-source.image16.ref.png new file mode 100644 index 0000000000..edb93a986e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask-source.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask-source.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask-source.mask.rgb24.ref.png new file mode 100644 index 0000000000..55335196aa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask-source.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask-source.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask-source.quartz.argb32.ref.png new file mode 100644 index 0000000000..2868f17c34 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask-source.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask-source.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask-source.quartz.rgb24.ref.png new file mode 100644 index 0000000000..319f177db4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask-source.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask-source.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask-source.rgb24.ref.png new file mode 100644 index 0000000000..ddf247808b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask-source.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask-source.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask-source.svg.ref.png new file mode 100644 index 0000000000..92b13e39a7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask-source.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask-source.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask-source.traps.rgb24.ref.png new file mode 100644 index 0000000000..55335196aa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask-source.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask.base.argb32.ref.png new file mode 100644 index 0000000000..4db39aa3f4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask.base.rgb24.ref.png new file mode 100644 index 0000000000..4db39aa3f4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask.image16.ref.png new file mode 100644 index 0000000000..78712ca52e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask.quartz.ref.png new file mode 100644 index 0000000000..5c92322b67 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask.ref.png new file mode 100644 index 0000000000..4db39aa3f4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask.svg.ref.png new file mode 100644 index 0000000000..8ed24c641e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-mask.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-one-stop.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-one-stop.base.argb32.ref.png new file mode 100644 index 0000000000..fb35be61d8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-one-stop.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-one-stop.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-one-stop.base.rgb24.ref.png new file mode 100644 index 0000000000..fb35be61d8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-one-stop.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-one-stop.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-one-stop.quartz.ref.png new file mode 100644 index 0000000000..cf37c2f486 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-one-stop.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-one-stop.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-one-stop.ref.png new file mode 100644 index 0000000000..fb35be61d8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-one-stop.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-one-stop.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-one-stop.svg.ref.png new file mode 100644 index 0000000000..16ff29db8a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-one-stop.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-source.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-source.base.argb32.ref.png new file mode 100644 index 0000000000..4ab4796fae Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-source.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-source.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-source.base.rgb24.ref.png new file mode 100644 index 0000000000..afaa24118f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-source.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-source.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-source.image16.ref.png new file mode 100644 index 0000000000..f992b6f39a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-source.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-source.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-source.quartz.argb32.ref.png new file mode 100644 index 0000000000..f23c72a0a5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-source.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-source.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-source.quartz.rgb24.ref.png new file mode 100644 index 0000000000..a531f28107 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-source.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-source.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-source.ref.png new file mode 100644 index 0000000000..cf7b0c96a0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-source.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient-source.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient-source.svg.ref.png new file mode 100644 index 0000000000..fd788826cb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient-source.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient.base.argb32.ref.png new file mode 100644 index 0000000000..a2cbbc82e1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient.base.rgb24.ref.png new file mode 100644 index 0000000000..a2cbbc82e1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient.image16.ref.png new file mode 100644 index 0000000000..91202d3c40 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient.quartz.ref.png new file mode 100644 index 0000000000..c80c7619cc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient.ref.png new file mode 100644 index 0000000000..81e3a0e202 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-gradient.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-gradient.svg.ref.png new file mode 100644 index 0000000000..baf9c2ff5a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-gradient.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-outer-focus.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-outer-focus.base.argb32.ref.png new file mode 100644 index 0000000000..21f0bf6fbb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-outer-focus.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-outer-focus.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-outer-focus.base.rgb24.ref.png new file mode 100644 index 0000000000..21f0bf6fbb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-outer-focus.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-outer-focus.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-outer-focus.mask.argb32.ref.png new file mode 100644 index 0000000000..21f0bf6fbb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-outer-focus.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-outer-focus.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-outer-focus.mask.rgb24.ref.png new file mode 100644 index 0000000000..21f0bf6fbb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-outer-focus.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-outer-focus.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-outer-focus.traps.argb32.ref.png new file mode 100644 index 0000000000..21f0bf6fbb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-outer-focus.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-outer-focus.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/radial-outer-focus.traps.rgb24.ref.png new file mode 100644 index 0000000000..21f0bf6fbb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-outer-focus.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/radial-outer-focus.xfail.png b/local/recipes/libs/cairo/source/test/reference/radial-outer-focus.xfail.png new file mode 100644 index 0000000000..53e9f82388 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/radial-outer-focus.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-clip.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/random-clip.base.argb32.ref.png new file mode 100644 index 0000000000..2750fb1592 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-clip.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-clip.base.argb32.xfail.png b/local/recipes/libs/cairo/source/test/reference/random-clip.base.argb32.xfail.png new file mode 100644 index 0000000000..15f91588ec Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-clip.base.argb32.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-clip.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/random-clip.base.rgb24.ref.png new file mode 100644 index 0000000000..2750fb1592 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-clip.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-clip.base.rgb24.xfail.png b/local/recipes/libs/cairo/source/test/reference/random-clip.base.rgb24.xfail.png new file mode 100644 index 0000000000..15f91588ec Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-clip.base.rgb24.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-clip.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/random-clip.mask.argb32.ref.png new file mode 100644 index 0000000000..41643cbadd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-clip.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-clip.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/random-clip.mask.rgb24.ref.png new file mode 100644 index 0000000000..41643cbadd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-clip.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-clip.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/random-clip.pdf.argb32.ref.png new file mode 100644 index 0000000000..dc5c288cd8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-clip.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-clip.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/random-clip.pdf.rgb24.ref.png new file mode 100644 index 0000000000..dc5c288cd8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-clip.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-clip.ps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/random-clip.ps.argb32.ref.png new file mode 100644 index 0000000000..531172fbcf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-clip.ps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-clip.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/random-clip.ps.rgb24.ref.png new file mode 100644 index 0000000000..dc5c288cd8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-clip.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-clip.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/random-clip.quartz.ref.png new file mode 100644 index 0000000000..aa617d6751 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-clip.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-clip.ref.png b/local/recipes/libs/cairo/source/test/reference/random-clip.ref.png new file mode 100644 index 0000000000..dc5c288cd8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-clip.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-clip.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/random-clip.traps.argb32.ref.png new file mode 100644 index 0000000000..01cc60a4fa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-clip.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-clip.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/random-clip.traps.rgb24.ref.png new file mode 100644 index 0000000000..01cc60a4fa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-clip.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-eo.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-eo.base.argb32.ref.png new file mode 100644 index 0000000000..ee10cb4090 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-eo.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-eo.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-eo.base.rgb24.ref.png new file mode 100644 index 0000000000..ee10cb4090 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-eo.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-eo.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-eo.image16.ref.png new file mode 100644 index 0000000000..0663270f9f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-eo.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-eo.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-eo.pdf.argb32.ref.png new file mode 100644 index 0000000000..d13660fde7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-eo.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-eo.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-eo.pdf.rgb24.ref.png new file mode 100644 index 0000000000..a11e7120d3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-eo.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-eo.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-eo.ps.ref.png new file mode 100644 index 0000000000..374ace90a1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-eo.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-eo.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-eo.quartz.ref.png new file mode 100644 index 0000000000..2a44a5a5d6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-eo.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-eo.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-eo.ref.png new file mode 100644 index 0000000000..1c12f22d24 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-eo.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-eo.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-eo.traps.argb32.ref.png new file mode 100644 index 0000000000..ee10cb4090 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-eo.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-eo.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-eo.traps.rgb24.ref.png new file mode 100644 index 0000000000..ee10cb4090 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-eo.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-eo.xlib-fallback.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-eo.xlib-fallback.ref.png new file mode 100644 index 0000000000..d91af0bf28 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-eo.xlib-fallback.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.base.argb32.ref.png new file mode 100644 index 0000000000..77f8129877 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.base.rgb24.ref.png new file mode 100644 index 0000000000..77f8129877 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.image16.ref.png new file mode 100644 index 0000000000..5fbc7113b8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.pdf.argb32.ref.png new file mode 100644 index 0000000000..ab6225c8a3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.pdf.ref.png new file mode 100644 index 0000000000..a374934bca Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.pdf.rgb24.ref.png new file mode 100644 index 0000000000..71c92e21a1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.ps.ref.png new file mode 100644 index 0000000000..6cc5814fc2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.quartz.ref.png new file mode 100644 index 0000000000..cf799bba9f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.ref.png new file mode 100644 index 0000000000..f251d27051 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.traps.argb32.ref.png new file mode 100644 index 0000000000..77f8129877 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.traps.rgb24.ref.png new file mode 100644 index 0000000000..77f8129877 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.xlib-fallback.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.xlib-fallback.ref.png new file mode 100644 index 0000000000..f72f8f175b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-curves-nz.xlib-fallback.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-eo.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-eo.base.argb32.ref.png new file mode 100644 index 0000000000..037f926e4e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-eo.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-eo.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-eo.base.rgb24.ref.png new file mode 100644 index 0000000000..037f926e4e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-eo.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-eo.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-eo.image16.ref.png new file mode 100644 index 0000000000..cf214d41ad Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-eo.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-eo.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-eo.pdf.ref.png new file mode 100644 index 0000000000..43e184202f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-eo.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-eo.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-eo.ps.ref.png new file mode 100644 index 0000000000..49b359af00 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-eo.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-eo.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-eo.quartz.ref.png new file mode 100644 index 0000000000..859abb050f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-eo.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-eo.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-eo.ref.png new file mode 100644 index 0000000000..2641c0069e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-eo.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-eo.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-eo.traps.argb32.ref.png new file mode 100644 index 0000000000..037f926e4e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-eo.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-eo.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-eo.traps.rgb24.ref.png new file mode 100644 index 0000000000..037f926e4e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-eo.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-nonzero.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-nonzero.base.argb32.ref.png new file mode 100644 index 0000000000..7eb9a0a3aa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-nonzero.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-nonzero.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-nonzero.base.rgb24.ref.png new file mode 100644 index 0000000000..7eb9a0a3aa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-nonzero.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-nonzero.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-nonzero.image16.ref.png new file mode 100644 index 0000000000..370abd9d5f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-nonzero.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-nonzero.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-nonzero.pdf.ref.png new file mode 100644 index 0000000000..fce490972f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-nonzero.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-nonzero.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-nonzero.ps.ref.png new file mode 100644 index 0000000000..53a151f6fa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-nonzero.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-nonzero.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-nonzero.quartz.ref.png new file mode 100644 index 0000000000..f4310ea277 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-nonzero.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-nonzero.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-nonzero.ref.png new file mode 100644 index 0000000000..cc748d4520 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-nonzero.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-nonzero.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-nonzero.traps.argb32.ref.png new file mode 100644 index 0000000000..7eb9a0a3aa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-nonzero.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/random-intersections-nonzero.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/random-intersections-nonzero.traps.rgb24.ref.png new file mode 100644 index 0000000000..7eb9a0a3aa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/random-intersections-nonzero.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/raster-source.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/raster-source.base.argb32.ref.png new file mode 100644 index 0000000000..ac5e56063a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/raster-source.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/raster-source.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/raster-source.base.rgb24.ref.png new file mode 100644 index 0000000000..ac5e56063a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/raster-source.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/raster-source.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/raster-source.ps.ref.png new file mode 100644 index 0000000000..524477d246 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/raster-source.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/raster-source.ref.png b/local/recipes/libs/cairo/source/test/reference/raster-source.ref.png new file mode 100644 index 0000000000..ac5e56063a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/raster-source.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-extend-none-similar.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-extend-none-similar.base.argb32.ref.png new file mode 100644 index 0000000000..7d5c49fa2c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-extend-none-similar.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-extend-none-similar.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-extend-none-similar.base.rgb24.ref.png new file mode 100644 index 0000000000..7d5c49fa2c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-extend-none-similar.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-extend-none-similar.ref.png b/local/recipes/libs/cairo/source/test/reference/record-extend-none-similar.ref.png new file mode 100644 index 0000000000..d63c31c1f3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-extend-none-similar.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-extend-none-similar.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-extend-none-similar.traps.argb32.ref.png new file mode 100644 index 0000000000..7d5c49fa2c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-extend-none-similar.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-extend-none-similar.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-extend-none-similar.traps.rgb24.ref.png new file mode 100644 index 0000000000..7d5c49fa2c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-extend-none-similar.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-extend-none.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-extend-none.base.argb32.ref.png new file mode 100644 index 0000000000..d63c31c1f3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-extend-none.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-extend-none.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-extend-none.base.rgb24.ref.png new file mode 100644 index 0000000000..d63c31c1f3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-extend-none.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-extend-none.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/record-extend-none.ps.ref.png new file mode 100644 index 0000000000..4d05beb351 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-extend-none.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-extend-none.ref.png b/local/recipes/libs/cairo/source/test/reference/record-extend-none.ref.png new file mode 100644 index 0000000000..d63c31c1f3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-extend-none.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-extend-pad-similar.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-extend-pad-similar.base.argb32.ref.png new file mode 100644 index 0000000000..da3de96d3d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-extend-pad-similar.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-extend-pad-similar.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-extend-pad-similar.base.rgb24.ref.png new file mode 100644 index 0000000000..da3de96d3d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-extend-pad-similar.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-extend-pad-similar.ref.png b/local/recipes/libs/cairo/source/test/reference/record-extend-pad-similar.ref.png new file mode 100644 index 0000000000..12915255cb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-extend-pad-similar.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-extend-pad-similar.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-extend-pad-similar.traps.argb32.ref.png new file mode 100644 index 0000000000..da3de96d3d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-extend-pad-similar.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-extend-pad-similar.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-extend-pad-similar.traps.rgb24.ref.png new file mode 100644 index 0000000000..da3de96d3d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-extend-pad-similar.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-extend-pad.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-extend-pad.base.argb32.ref.png new file mode 100644 index 0000000000..12915255cb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-extend-pad.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-extend-pad.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-extend-pad.base.rgb24.ref.png new file mode 100644 index 0000000000..12915255cb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-extend-pad.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-extend-pad.ref.png b/local/recipes/libs/cairo/source/test/reference/record-extend-pad.ref.png new file mode 100644 index 0000000000..12915255cb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-extend-pad.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-extend-reflect-similar.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-extend-reflect-similar.base.argb32.ref.png new file mode 100644 index 0000000000..da3de96d3d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-extend-reflect-similar.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-extend-reflect-similar.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-extend-reflect-similar.base.rgb24.ref.png new file mode 100644 index 0000000000..da3de96d3d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-extend-reflect-similar.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-extend-reflect-similar.ref.png b/local/recipes/libs/cairo/source/test/reference/record-extend-reflect-similar.ref.png new file mode 100644 index 0000000000..aec5c9454a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-extend-reflect-similar.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-extend-reflect-similar.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-extend-reflect-similar.traps.argb32.ref.png new file mode 100644 index 0000000000..da3de96d3d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-extend-reflect-similar.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-extend-reflect-similar.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-extend-reflect-similar.traps.rgb24.ref.png new file mode 100644 index 0000000000..da3de96d3d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-extend-reflect-similar.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-extend-reflect.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-extend-reflect.base.argb32.ref.png new file mode 100644 index 0000000000..aec5c9454a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-extend-reflect.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-extend-reflect.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-extend-reflect.base.rgb24.ref.png new file mode 100644 index 0000000000..aec5c9454a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-extend-reflect.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-extend-reflect.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/record-extend-reflect.ps.ref.png new file mode 100644 index 0000000000..abdf27b9c3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-extend-reflect.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-extend-reflect.ref.png b/local/recipes/libs/cairo/source/test/reference/record-extend-reflect.ref.png new file mode 100644 index 0000000000..aec5c9454a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-extend-reflect.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-extend-repeat-similar.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-extend-repeat-similar.base.argb32.ref.png new file mode 100644 index 0000000000..da3de96d3d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-extend-repeat-similar.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-extend-repeat-similar.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-extend-repeat-similar.base.rgb24.ref.png new file mode 100644 index 0000000000..da3de96d3d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-extend-repeat-similar.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-extend-repeat-similar.ref.png b/local/recipes/libs/cairo/source/test/reference/record-extend-repeat-similar.ref.png new file mode 100644 index 0000000000..d4db9bf580 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-extend-repeat-similar.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-extend-repeat-similar.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-extend-repeat-similar.traps.argb32.ref.png new file mode 100644 index 0000000000..da3de96d3d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-extend-repeat-similar.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-extend-repeat-similar.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-extend-repeat-similar.traps.rgb24.ref.png new file mode 100644 index 0000000000..da3de96d3d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-extend-repeat-similar.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-extend-repeat.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-extend-repeat.base.argb32.ref.png new file mode 100644 index 0000000000..d4db9bf580 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-extend-repeat.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-extend-repeat.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-extend-repeat.base.rgb24.ref.png new file mode 100644 index 0000000000..d4db9bf580 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-extend-repeat.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-extend-repeat.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/record-extend-repeat.ps.ref.png new file mode 100644 index 0000000000..1f06744ef5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-extend-repeat.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-extend-repeat.ref.png b/local/recipes/libs/cairo/source/test/reference/record-extend-repeat.ref.png new file mode 100644 index 0000000000..d4db9bf580 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-extend-repeat.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-fill-alpha.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-fill-alpha.base.argb32.ref.png new file mode 100644 index 0000000000..5a2ebad01e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-fill-alpha.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-fill-alpha.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-fill-alpha.base.rgb24.ref.png new file mode 100644 index 0000000000..5a2ebad01e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-fill-alpha.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-fill-alpha.base.xfail.png b/local/recipes/libs/cairo/source/test/reference/record-fill-alpha.base.xfail.png new file mode 100644 index 0000000000..5a2ebad01e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-fill-alpha.base.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-fill-alpha.image16.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-fill-alpha.image16.rgb24.ref.png new file mode 100644 index 0000000000..8ba164e284 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-fill-alpha.image16.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-fill-alpha.ref.png b/local/recipes/libs/cairo/source/test/reference/record-fill-alpha.ref.png new file mode 100644 index 0000000000..8f72f68f45 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-fill-alpha.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-fill-alpha.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/record-fill-alpha.svg.ref.png new file mode 100644 index 0000000000..25c1ac68fc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-fill-alpha.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-fill-alpha.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-fill-alpha.traps.argb32.ref.png new file mode 100644 index 0000000000..85df9198cb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-fill-alpha.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-fill-alpha.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-fill-alpha.traps.rgb24.ref.png new file mode 100644 index 0000000000..85df9198cb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-fill-alpha.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-fill-alpha.xfail.png b/local/recipes/libs/cairo/source/test/reference/record-fill-alpha.xfail.png new file mode 100644 index 0000000000..630c02466e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-fill-alpha.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-mesh.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-mesh.base.argb32.ref.png new file mode 100644 index 0000000000..4921ba386b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-mesh.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-mesh.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-mesh.base.rgb24.ref.png new file mode 100644 index 0000000000..4921ba386b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-mesh.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-mesh.image16.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-mesh.image16.rgb24.ref.png new file mode 100644 index 0000000000..df7bd03965 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-mesh.image16.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-mesh.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-mesh.pdf.argb32.ref.png new file mode 100644 index 0000000000..0155536503 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-mesh.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-mesh.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-mesh.pdf.rgb24.ref.png new file mode 100644 index 0000000000..f69db6e060 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-mesh.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-mesh.ref.png b/local/recipes/libs/cairo/source/test/reference/record-mesh.ref.png new file mode 100644 index 0000000000..0155536503 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-mesh.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-mesh.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/record-mesh.svg.ref.png new file mode 100644 index 0000000000..6e781b1a43 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-mesh.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-neg-extents-bounded.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-neg-extents-bounded.pdf.argb32.ref.png new file mode 100644 index 0000000000..159283651a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-neg-extents-bounded.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-neg-extents-bounded.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-neg-extents-bounded.pdf.rgb24.ref.png new file mode 100644 index 0000000000..78feffbba3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-neg-extents-bounded.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-neg-extents-bounded.ref.png b/local/recipes/libs/cairo/source/test/reference/record-neg-extents-bounded.ref.png new file mode 100644 index 0000000000..6d29da1991 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-neg-extents-bounded.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-neg-extents-bounded.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/record-neg-extents-bounded.svg.ref.png new file mode 100644 index 0000000000..9f7524f847 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-neg-extents-bounded.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-neg-extents-unbounded.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-neg-extents-unbounded.pdf.argb32.ref.png new file mode 100644 index 0000000000..159283651a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-neg-extents-unbounded.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-neg-extents-unbounded.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-neg-extents-unbounded.pdf.rgb24.ref.png new file mode 100644 index 0000000000..78feffbba3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-neg-extents-unbounded.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-neg-extents-unbounded.ref.png b/local/recipes/libs/cairo/source/test/reference/record-neg-extents-unbounded.ref.png new file mode 100644 index 0000000000..5218be5024 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-neg-extents-unbounded.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-neg-extents-unbounded.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/record-neg-extents-unbounded.svg.ref.png new file mode 100644 index 0000000000..9f7524f847 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-neg-extents-unbounded.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip-mask.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip-mask.base.argb32.ref.png new file mode 100644 index 0000000000..f7bb8ffee9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip-mask.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip-mask.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip-mask.base.rgb24.ref.png new file mode 100644 index 0000000000..f7bb8ffee9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip-mask.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip-mask.base.xfail.png b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip-mask.base.xfail.png new file mode 100644 index 0000000000..f7bb8ffee9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip-mask.base.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip-mask.image16.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip-mask.image16.rgb24.ref.png new file mode 100644 index 0000000000..f069c13b84 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip-mask.image16.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip-mask.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip-mask.pdf.argb32.ref.png new file mode 100644 index 0000000000..0233e44f58 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip-mask.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip-mask.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip-mask.pdf.rgb24.ref.png new file mode 100644 index 0000000000..e57369f2db Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip-mask.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip-mask.ref.png b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip-mask.ref.png new file mode 100644 index 0000000000..0233e44f58 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip-mask.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip-mask.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip-mask.traps.argb32.ref.png new file mode 100644 index 0000000000..201bd0d550 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip-mask.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip-mask.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip-mask.traps.rgb24.ref.png new file mode 100644 index 0000000000..201bd0d550 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip-mask.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip-mask.xfail.png b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip-mask.xfail.png new file mode 100644 index 0000000000..3bc8cd5d55 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip-mask.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip.base.argb32.ref.png new file mode 100644 index 0000000000..9f6841eb1e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip.base.rgb24.ref.png new file mode 100644 index 0000000000..9f6841eb1e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip.image16.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip.image16.rgb24.ref.png new file mode 100644 index 0000000000..6eb92c3056 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip.image16.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip.pdf.argb32.ref.png new file mode 100644 index 0000000000..3303996702 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip.pdf.rgb24.ref.png new file mode 100644 index 0000000000..c3dabc5ce1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip.ref.png b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip.ref.png new file mode 100644 index 0000000000..4bad4e8ca5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip.traps.argb32.ref.png new file mode 100644 index 0000000000..c1da67e013 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip.traps.rgb24.ref.png new file mode 100644 index 0000000000..c1da67e013 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-clip.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-solid-clip.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-solid-clip.base.argb32.ref.png new file mode 100644 index 0000000000..59d226d1a4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-solid-clip.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-solid-clip.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-solid-clip.base.rgb24.ref.png new file mode 100644 index 0000000000..59d226d1a4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-solid-clip.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-solid-clip.image16.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-solid-clip.image16.rgb24.ref.png new file mode 100644 index 0000000000..111293d7ca Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-solid-clip.image16.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-solid-clip.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-solid-clip.pdf.ref.png new file mode 100644 index 0000000000..034ba6d9b4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-solid-clip.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-solid-clip.ref.png b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-solid-clip.ref.png new file mode 100644 index 0000000000..59d226d1a4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-solid-clip.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-solid-clip.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-solid-clip.svg.ref.png new file mode 100644 index 0000000000..034ba6d9b4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-solid-clip.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-solid-clip.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-solid-clip.traps.argb32.ref.png new file mode 100644 index 0000000000..2cd2df21cb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-solid-clip.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-solid-clip.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-solid-clip.traps.rgb24.ref.png new file mode 100644 index 0000000000..2cd2df21cb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha-solid-clip.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-paint-alpha.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha.base.argb32.ref.png new file mode 100644 index 0000000000..65d9c179bf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-paint-alpha.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha.base.rgb24.ref.png new file mode 100644 index 0000000000..65d9c179bf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-paint-alpha.image16.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha.image16.rgb24.ref.png new file mode 100644 index 0000000000..12bd89d55d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha.image16.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-paint-alpha.ref.png b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha.ref.png new file mode 100644 index 0000000000..487b8b6227 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-paint-alpha.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-paint.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-paint.base.argb32.ref.png new file mode 100644 index 0000000000..22cc7a1ae5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-paint.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-paint.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-paint.base.rgb24.ref.png new file mode 100644 index 0000000000..22cc7a1ae5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-paint.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-paint.ref.png b/local/recipes/libs/cairo/source/test/reference/record-paint.ref.png new file mode 100644 index 0000000000..fff03b363e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-paint.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-replay-extend-none.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-none.pdf.argb32.ref.png new file mode 100644 index 0000000000..6ca0f1009f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-none.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-replay-extend-none.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-none.pdf.rgb24.ref.png new file mode 100644 index 0000000000..3cbe86952e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-none.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-replay-extend-none.ps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-none.ps.argb32.ref.png new file mode 100644 index 0000000000..4b2f85fe99 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-none.ps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-replay-extend-none.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-none.ps.rgb24.ref.png new file mode 100644 index 0000000000..a89a45f354 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-none.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-replay-extend-none.ref.png b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-none.ref.png new file mode 100644 index 0000000000..204c76502b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-none.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-replay-extend-pad.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-pad.pdf.argb32.ref.png new file mode 100644 index 0000000000..74d3043855 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-pad.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-replay-extend-pad.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-pad.ps.rgb24.ref.png new file mode 100644 index 0000000000..cd02486699 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-pad.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-replay-extend-pad.ref.png b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-pad.ref.png new file mode 100644 index 0000000000..7acd8af499 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-pad.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-replay-extend-pad.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-pad.svg.ref.png new file mode 100644 index 0000000000..c07fa7036d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-pad.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-replay-extend-reflect.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-reflect.pdf.argb32.ref.png new file mode 100644 index 0000000000..d7845abd0d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-reflect.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-replay-extend-reflect.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-reflect.pdf.rgb24.ref.png new file mode 100644 index 0000000000..2c47015b5b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-reflect.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-replay-extend-reflect.ps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-reflect.ps.argb32.ref.png new file mode 100644 index 0000000000..32d26b0b19 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-reflect.ps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-replay-extend-reflect.ref.png b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-reflect.ref.png new file mode 100644 index 0000000000..de53e5ca41 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-reflect.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-replay-extend-reflect.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-reflect.svg.ref.png new file mode 100644 index 0000000000..903451d93b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-reflect.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-replay-extend-repeat.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-repeat.pdf.argb32.ref.png new file mode 100644 index 0000000000..4df0313894 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-repeat.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-replay-extend-repeat.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-repeat.pdf.rgb24.ref.png new file mode 100644 index 0000000000..7efac20bdb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-repeat.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-replay-extend-repeat.ps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-repeat.ps.argb32.ref.png new file mode 100644 index 0000000000..15d3d55bd7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-repeat.ps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-replay-extend-repeat.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-repeat.ps.rgb24.ref.png new file mode 100644 index 0000000000..fa25d484dc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-repeat.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-replay-extend-repeat.ref.png b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-repeat.ref.png new file mode 100644 index 0000000000..5a95d86f5e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-repeat.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-replay-extend-repeat.svg.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-repeat.svg.argb32.ref.png new file mode 100644 index 0000000000..40a697d074 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-repeat.svg.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-replay-extend-repeat.svg.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-repeat.svg.rgb24.ref.png new file mode 100644 index 0000000000..0259765319 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-replay-extend-repeat.svg.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-select-font-face.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-select-font-face.base.argb32.ref.png new file mode 100644 index 0000000000..63c7cca8a3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-select-font-face.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-select-font-face.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-select-font-face.base.rgb24.ref.png new file mode 100644 index 0000000000..63c7cca8a3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-select-font-face.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-select-font-face.image16.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-select-font-face.image16.rgb24.ref.png new file mode 100644 index 0000000000..88388e5e8a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-select-font-face.image16.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-select-font-face.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-select-font-face.pdf.argb32.ref.png new file mode 100644 index 0000000000..63c7cca8a3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-select-font-face.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-select-font-face.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-select-font-face.pdf.rgb24.ref.png new file mode 100644 index 0000000000..bb2f69f901 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-select-font-face.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-select-font-face.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/record-select-font-face.ps.ref.png new file mode 100644 index 0000000000..ab63c85edb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-select-font-face.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-select-font-face.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/record-select-font-face.quartz.ref.png new file mode 100644 index 0000000000..e26063939d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-select-font-face.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-select-font-face.ref.png b/local/recipes/libs/cairo/source/test/reference/record-select-font-face.ref.png new file mode 100644 index 0000000000..4265ea0926 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-select-font-face.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-select-font-face.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/record-select-font-face.svg.ref.png new file mode 100644 index 0000000000..2ab46d10a3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-select-font-face.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-select-font-face.xfail.png b/local/recipes/libs/cairo/source/test/reference/record-select-font-face.xfail.png new file mode 100644 index 0000000000..1f57d692ff Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-select-font-face.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-self-intersecting.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-self-intersecting.base.argb32.ref.png new file mode 100644 index 0000000000..d554d83eee Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-self-intersecting.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-self-intersecting.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-self-intersecting.base.rgb24.ref.png new file mode 100644 index 0000000000..d554d83eee Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-self-intersecting.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-self-intersecting.image16.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-self-intersecting.image16.rgb24.ref.png new file mode 100644 index 0000000000..cab3507c9c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-self-intersecting.image16.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-self-intersecting.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-self-intersecting.pdf.rgb24.ref.png new file mode 100644 index 0000000000..83eeaad583 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-self-intersecting.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-self-intersecting.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/record-self-intersecting.ps.ref.png new file mode 100644 index 0000000000..84fde01711 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-self-intersecting.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-self-intersecting.ref.png b/local/recipes/libs/cairo/source/test/reference/record-self-intersecting.ref.png new file mode 100644 index 0000000000..d554d83eee Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-self-intersecting.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-text-transform.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-text-transform.base.argb32.ref.png new file mode 100644 index 0000000000..8e74785f5f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-text-transform.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-text-transform.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-text-transform.base.rgb24.ref.png new file mode 100644 index 0000000000..8e74785f5f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-text-transform.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-text-transform.image16.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-text-transform.image16.rgb24.ref.png new file mode 100644 index 0000000000..460389928a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-text-transform.image16.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-text-transform.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-text-transform.pdf.argb32.ref.png new file mode 100644 index 0000000000..8e74785f5f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-text-transform.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-text-transform.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-text-transform.pdf.rgb24.ref.png new file mode 100644 index 0000000000..ffde12fdc1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-text-transform.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-text-transform.ps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record-text-transform.ps.argb32.ref.png new file mode 100644 index 0000000000..be4ec54149 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-text-transform.ps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-text-transform.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-text-transform.ps.rgb24.ref.png new file mode 100644 index 0000000000..be4ec54149 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-text-transform.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-text-transform.ref.png b/local/recipes/libs/cairo/source/test/reference/record-text-transform.ref.png new file mode 100644 index 0000000000..405380dd92 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-text-transform.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-text-transform.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/record-text-transform.svg.ref.png new file mode 100644 index 0000000000..684e93b92f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-text-transform.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-transform-paint.image16.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record-transform-paint.image16.rgb24.ref.png new file mode 100644 index 0000000000..f7f5805398 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-transform-paint.image16.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-transform-paint.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/record-transform-paint.pdf.ref.png new file mode 100644 index 0000000000..51526e9297 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-transform-paint.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-transform-paint.ref.png b/local/recipes/libs/cairo/source/test/reference/record-transform-paint.ref.png new file mode 100644 index 0000000000..051db262ef Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-transform-paint.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record-write-png.ref.png b/local/recipes/libs/cairo/source/test/reference/record-write-png.ref.png new file mode 100644 index 0000000000..7152a217a9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record-write-png.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-fill-alpha.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-fill-alpha.base.argb32.ref.png new file mode 100644 index 0000000000..69673434fa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-fill-alpha.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-fill-alpha.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-fill-alpha.base.rgb24.ref.png new file mode 100644 index 0000000000..69673434fa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-fill-alpha.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-fill-alpha.base.xfail.png b/local/recipes/libs/cairo/source/test/reference/record1414x-fill-alpha.base.xfail.png new file mode 100644 index 0000000000..69673434fa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-fill-alpha.base.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-fill-alpha.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-fill-alpha.pdf.argb32.ref.png new file mode 100644 index 0000000000..8d892d00bb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-fill-alpha.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-fill-alpha.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-fill-alpha.pdf.rgb24.ref.png new file mode 100644 index 0000000000..c38e2435ec Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-fill-alpha.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-fill-alpha.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-fill-alpha.ps.ref.png new file mode 100644 index 0000000000..444f353b08 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-fill-alpha.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-fill-alpha.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-fill-alpha.quartz.ref.png new file mode 100644 index 0000000000..837eaccbf2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-fill-alpha.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-fill-alpha.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-fill-alpha.ref.png new file mode 100644 index 0000000000..fb0b320b51 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-fill-alpha.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-fill-alpha.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-fill-alpha.svg.ref.png new file mode 100644 index 0000000000..4c4060331b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-fill-alpha.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-fill-alpha.xfail.png b/local/recipes/libs/cairo/source/test/reference/record1414x-fill-alpha.xfail.png new file mode 100644 index 0000000000..9393186f6e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-fill-alpha.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip-mask.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip-mask.base.argb32.ref.png new file mode 100644 index 0000000000..0ae9861d5a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip-mask.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip-mask.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip-mask.base.rgb24.ref.png new file mode 100644 index 0000000000..0ae9861d5a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip-mask.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip-mask.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip-mask.pdf.argb32.ref.png new file mode 100644 index 0000000000..5bb4bbd1c7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip-mask.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip-mask.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip-mask.pdf.rgb24.ref.png new file mode 100644 index 0000000000..b50b99280f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip-mask.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip-mask.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip-mask.ps.ref.png new file mode 100644 index 0000000000..835bf04513 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip-mask.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip-mask.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip-mask.quartz.ref.png new file mode 100644 index 0000000000..5bb4bbd1c7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip-mask.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip-mask.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip-mask.ref.png new file mode 100644 index 0000000000..78442bdbc0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip-mask.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip.base.argb32.ref.png new file mode 100644 index 0000000000..d1b57ae3c4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip.base.rgb24.ref.png new file mode 100644 index 0000000000..d1b57ae3c4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip.pdf.argb32.ref.png new file mode 100644 index 0000000000..31a2143b9f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip.pdf.rgb24.ref.png new file mode 100644 index 0000000000..1e6e1f674a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip.ps.ref.png new file mode 100644 index 0000000000..13b1163e04 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip.ref.png new file mode 100644 index 0000000000..6c11f1d963 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-clip.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-solid-clip.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-solid-clip.base.argb32.ref.png new file mode 100644 index 0000000000..86d3f51b2a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-solid-clip.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-solid-clip.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-solid-clip.base.rgb24.ref.png new file mode 100644 index 0000000000..86d3f51b2a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-solid-clip.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-solid-clip.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-solid-clip.pdf.argb32.ref.png new file mode 100644 index 0000000000..21b02b87d6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-solid-clip.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-solid-clip.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-solid-clip.pdf.rgb24.ref.png new file mode 100644 index 0000000000..d3f7e57de7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-solid-clip.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-solid-clip.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-solid-clip.ps.ref.png new file mode 100644 index 0000000000..811c8aa307 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-solid-clip.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-solid-clip.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-solid-clip.ref.png new file mode 100644 index 0000000000..7a8e594627 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-solid-clip.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-solid-clip.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-solid-clip.svg.ref.png new file mode 100644 index 0000000000..ea9be2be36 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha-solid-clip.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha.base.argb32.ref.png new file mode 100644 index 0000000000..eee74ced03 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha.base.rgb24.ref.png new file mode 100644 index 0000000000..eee74ced03 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha.pdf.argb32.ref.png new file mode 100644 index 0000000000..5d5d797988 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha.pdf.rgb24.ref.png new file mode 100644 index 0000000000..6a80a830b5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha.ps.ref.png new file mode 100644 index 0000000000..7460886e13 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha.ref.png new file mode 100644 index 0000000000..eee74ced03 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-paint-alpha.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-paint.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-paint.base.argb32.ref.png new file mode 100644 index 0000000000..e0a1341c92 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-paint.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-paint.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-paint.base.rgb24.ref.png new file mode 100644 index 0000000000..e0a1341c92 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-paint.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-paint.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-paint.ps.ref.png new file mode 100644 index 0000000000..8121e49658 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-paint.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-paint.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-paint.ps.rgb24.ref.png new file mode 100644 index 0000000000..8dcd8eba20 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-paint.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-paint.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-paint.ref.png new file mode 100644 index 0000000000..e0a1341c92 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-paint.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-paint.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-paint.svg.ref.png new file mode 100644 index 0000000000..38e79a3199 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-paint.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-select-font-face.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-select-font-face.base.argb32.ref.png new file mode 100644 index 0000000000..ac30b23a36 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-select-font-face.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-select-font-face.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-select-font-face.base.rgb24.ref.png new file mode 100644 index 0000000000..ac30b23a36 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-select-font-face.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-select-font-face.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-select-font-face.pdf.argb32.ref.png new file mode 100644 index 0000000000..ac30b23a36 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-select-font-face.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-select-font-face.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-select-font-face.pdf.rgb24.ref.png new file mode 100644 index 0000000000..cdc3ce850f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-select-font-face.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-select-font-face.ps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-select-font-face.ps.argb32.ref.png new file mode 100644 index 0000000000..37da5e1ede Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-select-font-face.ps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-select-font-face.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-select-font-face.ps.rgb24.ref.png new file mode 100644 index 0000000000..97b19be2a1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-select-font-face.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-select-font-face.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-select-font-face.quartz.ref.png new file mode 100644 index 0000000000..a3b51ffeb1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-select-font-face.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-select-font-face.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-select-font-face.ref.png new file mode 100644 index 0000000000..30c9a83e18 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-select-font-face.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-self-intersecting.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-self-intersecting.base.argb32.ref.png new file mode 100644 index 0000000000..62f91c9e77 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-self-intersecting.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-self-intersecting.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-self-intersecting.base.rgb24.ref.png new file mode 100644 index 0000000000..62f91c9e77 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-self-intersecting.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-self-intersecting.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-self-intersecting.pdf.argb32.ref.png new file mode 100644 index 0000000000..62f91c9e77 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-self-intersecting.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-self-intersecting.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-self-intersecting.pdf.rgb24.ref.png new file mode 100644 index 0000000000..5fa2debd53 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-self-intersecting.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-self-intersecting.ps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-self-intersecting.ps.argb32.ref.png new file mode 100644 index 0000000000..c6f483e59f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-self-intersecting.ps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-self-intersecting.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-self-intersecting.ps.rgb24.ref.png new file mode 100644 index 0000000000..d7e2af5640 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-self-intersecting.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-self-intersecting.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-self-intersecting.ref.png new file mode 100644 index 0000000000..62f91c9e77 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-self-intersecting.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-self-intersecting.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-self-intersecting.svg.ref.png new file mode 100644 index 0000000000..3276de5130 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-self-intersecting.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-text-transform.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-text-transform.base.argb32.ref.png new file mode 100644 index 0000000000..624e3683a5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-text-transform.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-text-transform.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-text-transform.base.rgb24.ref.png new file mode 100644 index 0000000000..624e3683a5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-text-transform.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-text-transform.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-text-transform.pdf.argb32.ref.png new file mode 100644 index 0000000000..60de60a802 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-text-transform.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-text-transform.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-text-transform.pdf.rgb24.ref.png new file mode 100644 index 0000000000..9b90c9799b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-text-transform.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-text-transform.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-text-transform.ps.ref.png new file mode 100644 index 0000000000..bbf4f52083 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-text-transform.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-text-transform.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-text-transform.quartz.ref.png new file mode 100644 index 0000000000..58e0f4f1b2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-text-transform.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record1414x-text-transform.ref.png b/local/recipes/libs/cairo/source/test/reference/record1414x-text-transform.ref.png new file mode 100644 index 0000000000..89940b0280 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record1414x-text-transform.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-fill-alpha.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-fill-alpha.base.argb32.ref.png new file mode 100644 index 0000000000..b96ff8d00c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-fill-alpha.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-fill-alpha.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-fill-alpha.base.rgb24.ref.png new file mode 100644 index 0000000000..b96ff8d00c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-fill-alpha.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-fill-alpha.base.xfail.png b/local/recipes/libs/cairo/source/test/reference/record2x-fill-alpha.base.xfail.png new file mode 100644 index 0000000000..b96ff8d00c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-fill-alpha.base.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-fill-alpha.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-fill-alpha.pdf.argb32.ref.png new file mode 100644 index 0000000000..c4d7965338 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-fill-alpha.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-fill-alpha.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-fill-alpha.pdf.rgb24.ref.png new file mode 100644 index 0000000000..9bbe8b85c8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-fill-alpha.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-fill-alpha.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-fill-alpha.ps.ref.png new file mode 100644 index 0000000000..c4d7965338 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-fill-alpha.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-fill-alpha.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-fill-alpha.quartz.ref.png new file mode 100644 index 0000000000..7ecd5717be Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-fill-alpha.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-fill-alpha.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-fill-alpha.ref.png new file mode 100644 index 0000000000..9bbe8b85c8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-fill-alpha.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-fill-alpha.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-fill-alpha.svg.ref.png new file mode 100644 index 0000000000..7ecd5717be Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-fill-alpha.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-fill-alpha.xfail.png b/local/recipes/libs/cairo/source/test/reference/record2x-fill-alpha.xfail.png new file mode 100644 index 0000000000..3b70c01949 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-fill-alpha.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-clip-mask.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-clip-mask.base.argb32.ref.png new file mode 100644 index 0000000000..ebfa1db5d2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-clip-mask.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-clip-mask.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-clip-mask.base.rgb24.ref.png new file mode 100644 index 0000000000..ebfa1db5d2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-clip-mask.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-clip-mask.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-clip-mask.pdf.argb32.ref.png new file mode 100644 index 0000000000..dd1ca05f9f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-clip-mask.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-clip-mask.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-clip-mask.pdf.rgb24.ref.png new file mode 100644 index 0000000000..f7a20d3601 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-clip-mask.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-clip-mask.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-clip-mask.ps.ref.png new file mode 100644 index 0000000000..dd1ca05f9f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-clip-mask.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-clip-mask.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-clip-mask.ref.png new file mode 100644 index 0000000000..938440b21d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-clip-mask.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-clip.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-clip.base.argb32.ref.png new file mode 100644 index 0000000000..b3829d56e7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-clip.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-clip.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-clip.base.rgb24.ref.png new file mode 100644 index 0000000000..b3829d56e7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-clip.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-clip.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-clip.pdf.argb32.ref.png new file mode 100644 index 0000000000..56dcc79ee2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-clip.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-clip.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-clip.pdf.rgb24.ref.png new file mode 100644 index 0000000000..2dc5ee4baa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-clip.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-clip.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-clip.ref.png new file mode 100644 index 0000000000..b3829d56e7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-clip.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-solid-clip.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-solid-clip.base.argb32.ref.png new file mode 100644 index 0000000000..06e350f354 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-solid-clip.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-solid-clip.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-solid-clip.base.rgb24.ref.png new file mode 100644 index 0000000000..06e350f354 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-solid-clip.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-solid-clip.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-solid-clip.pdf.argb32.ref.png new file mode 100644 index 0000000000..449bc5a977 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-solid-clip.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-solid-clip.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-solid-clip.pdf.rgb24.ref.png new file mode 100644 index 0000000000..b22ac6d38e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-solid-clip.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-solid-clip.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-solid-clip.ref.png new file mode 100644 index 0000000000..06e350f354 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-solid-clip.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-solid-clip.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-solid-clip.svg.ref.png new file mode 100644 index 0000000000..b22ac6d38e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha-solid-clip.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha.base.argb32.ref.png new file mode 100644 index 0000000000..3a02b675c4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha.base.rgb24.ref.png new file mode 100644 index 0000000000..3a02b675c4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha.pdf.argb32.ref.png new file mode 100644 index 0000000000..f53c7f9cd3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha.pdf.rgb24.ref.png new file mode 100644 index 0000000000..41b8cf1b88 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha.ref.png new file mode 100644 index 0000000000..3a02b675c4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-paint-alpha.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-paint.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-paint.base.argb32.ref.png new file mode 100644 index 0000000000..792a1d0339 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-paint.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-paint.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-paint.base.rgb24.ref.png new file mode 100644 index 0000000000..792a1d0339 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-paint.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-paint.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-paint.ref.png new file mode 100644 index 0000000000..792a1d0339 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-paint.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-select-font-face.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-select-font-face.base.argb32.ref.png new file mode 100644 index 0000000000..f0b268f5a4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-select-font-face.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-select-font-face.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-select-font-face.base.rgb24.ref.png new file mode 100644 index 0000000000..f0b268f5a4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-select-font-face.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-select-font-face.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-select-font-face.pdf.rgb24.ref.png new file mode 100644 index 0000000000..ed64d7c6a1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-select-font-face.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-select-font-face.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-select-font-face.ps.ref.png new file mode 100644 index 0000000000..71eee7c422 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-select-font-face.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-select-font-face.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-select-font-face.quartz.ref.png new file mode 100644 index 0000000000..7312eba268 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-select-font-face.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-select-font-face.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-select-font-face.ref.png new file mode 100644 index 0000000000..201f51229c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-select-font-face.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-select-font-face.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-select-font-face.svg.ref.png new file mode 100644 index 0000000000..3dd20c46da Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-select-font-face.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-self-intersecting.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-self-intersecting.base.argb32.ref.png new file mode 100644 index 0000000000..2836dae036 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-self-intersecting.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-self-intersecting.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-self-intersecting.base.rgb24.ref.png new file mode 100644 index 0000000000..2836dae036 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-self-intersecting.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-self-intersecting.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-self-intersecting.ref.png new file mode 100644 index 0000000000..2836dae036 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-self-intersecting.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-text-transform.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-text-transform.base.argb32.ref.png new file mode 100644 index 0000000000..9811c1b5fc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-text-transform.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-text-transform.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-text-transform.base.rgb24.ref.png new file mode 100644 index 0000000000..9811c1b5fc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-text-transform.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-text-transform.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-text-transform.pdf.argb32.ref.png new file mode 100644 index 0000000000..9811c1b5fc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-text-transform.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-text-transform.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-text-transform.pdf.rgb24.ref.png new file mode 100644 index 0000000000..35b5ce912b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-text-transform.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-text-transform.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-text-transform.ps.ref.png new file mode 100644 index 0000000000..f56280268f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-text-transform.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-text-transform.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-text-transform.ref.png new file mode 100644 index 0000000000..66e00858fb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-text-transform.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record2x-text-transform.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/record2x-text-transform.svg.ref.png new file mode 100644 index 0000000000..356c032920 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record2x-text-transform.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-fill-alpha.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-fill-alpha.base.argb32.ref.png new file mode 100644 index 0000000000..4c743f5fc4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-fill-alpha.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-fill-alpha.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-fill-alpha.base.rgb24.ref.png new file mode 100644 index 0000000000..4c743f5fc4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-fill-alpha.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-fill-alpha.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-fill-alpha.pdf.rgb24.ref.png new file mode 100644 index 0000000000..ee01f5f8a7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-fill-alpha.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-fill-alpha.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-fill-alpha.ref.png new file mode 100644 index 0000000000..167d7be65c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-fill-alpha.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-fill-alpha.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-fill-alpha.svg.ref.png new file mode 100644 index 0000000000..1dacde30a6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-fill-alpha.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-fill-alpha.xfail.png b/local/recipes/libs/cairo/source/test/reference/record90-fill-alpha.xfail.png new file mode 100644 index 0000000000..ad1e65c4c3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-fill-alpha.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip-mask.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip-mask.base.argb32.ref.png new file mode 100644 index 0000000000..976192c1ab Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip-mask.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip-mask.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip-mask.base.rgb24.ref.png new file mode 100644 index 0000000000..976192c1ab Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip-mask.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip-mask.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip-mask.pdf.argb32.ref.png new file mode 100644 index 0000000000..3ddf95c8b3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip-mask.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip-mask.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip-mask.pdf.rgb24.ref.png new file mode 100644 index 0000000000..e6bc20868a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip-mask.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip-mask.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip-mask.ref.png new file mode 100644 index 0000000000..5c2106ba7e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip-mask.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip-mask.xfail.png b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip-mask.xfail.png new file mode 100644 index 0000000000..bad037fee7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip-mask.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip.base.argb32.ref.png new file mode 100644 index 0000000000..d687e3b4d0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip.base.rgb24.ref.png new file mode 100644 index 0000000000..d687e3b4d0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip.pdf.argb32.ref.png new file mode 100644 index 0000000000..b7703d47d2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip.pdf.rgb24.ref.png new file mode 100644 index 0000000000..aac3c29f24 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip.ref.png new file mode 100644 index 0000000000..b7703d47d2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip.xfail.png b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip.xfail.png new file mode 100644 index 0000000000..d687e3b4d0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-clip.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-solid-clip.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-solid-clip.base.argb32.ref.png new file mode 100644 index 0000000000..48a01eaaaa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-solid-clip.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-solid-clip.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-solid-clip.base.rgb24.ref.png new file mode 100644 index 0000000000..48a01eaaaa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-solid-clip.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-solid-clip.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-solid-clip.pdf.argb32.ref.png new file mode 100644 index 0000000000..17bff57c5f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-solid-clip.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-solid-clip.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-solid-clip.pdf.rgb24.ref.png new file mode 100644 index 0000000000..260be21990 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-solid-clip.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-solid-clip.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-solid-clip.ref.png new file mode 100644 index 0000000000..17bff57c5f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-solid-clip.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-solid-clip.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-solid-clip.svg.ref.png new file mode 100644 index 0000000000..260be21990 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha-solid-clip.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha.base.argb32.ref.png new file mode 100644 index 0000000000..57aa95d370 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha.base.rgb24.ref.png new file mode 100644 index 0000000000..57aa95d370 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha.ps.ref.png new file mode 100644 index 0000000000..7b7998ebcf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha.ref.png new file mode 100644 index 0000000000..5e9cb58d9c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-paint-alpha.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-paint.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-paint.base.argb32.ref.png new file mode 100644 index 0000000000..22cc7a1ae5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-paint.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-paint.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-paint.base.rgb24.ref.png new file mode 100644 index 0000000000..22cc7a1ae5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-paint.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-paint.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-paint.ref.png new file mode 100644 index 0000000000..22cc7a1ae5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-paint.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-select-font-face.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-select-font-face.base.argb32.ref.png new file mode 100644 index 0000000000..13ed998f2f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-select-font-face.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-select-font-face.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-select-font-face.base.rgb24.ref.png new file mode 100644 index 0000000000..13ed998f2f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-select-font-face.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-select-font-face.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-select-font-face.pdf.rgb24.ref.png new file mode 100644 index 0000000000..463875d549 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-select-font-face.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-select-font-face.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-select-font-face.ps.ref.png new file mode 100644 index 0000000000..58e6625bd4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-select-font-face.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-select-font-face.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-select-font-face.quartz.ref.png new file mode 100644 index 0000000000..db14aacae1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-select-font-face.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-select-font-face.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-select-font-face.ref.png new file mode 100644 index 0000000000..883e9278a8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-select-font-face.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-select-font-face.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-select-font-face.svg.ref.png new file mode 100644 index 0000000000..c64c5090d3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-select-font-face.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-self-intersecting.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-self-intersecting.base.argb32.ref.png new file mode 100644 index 0000000000..7df179e94a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-self-intersecting.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-self-intersecting.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-self-intersecting.base.rgb24.ref.png new file mode 100644 index 0000000000..7df179e94a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-self-intersecting.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-self-intersecting.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-self-intersecting.pdf.rgb24.ref.png new file mode 100644 index 0000000000..3a960c7c68 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-self-intersecting.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-self-intersecting.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-self-intersecting.ps.ref.png new file mode 100644 index 0000000000..3bcc7fbed3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-self-intersecting.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-self-intersecting.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/record90-self-intersecting.quartz.xfail.png new file mode 100644 index 0000000000..f4f34ce3b7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-self-intersecting.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-self-intersecting.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-self-intersecting.ref.png new file mode 100644 index 0000000000..f4f34ce3b7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-self-intersecting.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-self-intersecting.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-self-intersecting.svg.ref.png new file mode 100644 index 0000000000..15ce4c005a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-self-intersecting.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-text-transform.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-text-transform.base.argb32.ref.png new file mode 100644 index 0000000000..e8fa7225f1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-text-transform.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-text-transform.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-text-transform.base.rgb24.ref.png new file mode 100644 index 0000000000..e8fa7225f1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-text-transform.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-text-transform.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-text-transform.pdf.rgb24.ref.png new file mode 100644 index 0000000000..96ff2c466f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-text-transform.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-text-transform.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-text-transform.ps.ref.png new file mode 100644 index 0000000000..2e0bbfbf8d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-text-transform.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-text-transform.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-text-transform.ref.png new file mode 100644 index 0000000000..3ea08a3959 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-text-transform.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/record90-text-transform.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/record90-text-transform.svg.ref.png new file mode 100644 index 0000000000..5fc2f40110 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/record90-text-transform.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-fill-alpha.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-fill-alpha.quartz.ref.png new file mode 100644 index 0000000000..69035ef5f0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-fill-alpha.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-fill-alpha.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-fill-alpha.ref.png new file mode 100644 index 0000000000..c80c351ba3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-fill-alpha.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-fill-alpha.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-fill-alpha.svg.ref.png new file mode 100644 index 0000000000..69035ef5f0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-fill-alpha.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-paint-alpha-clip-mask.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-paint-alpha-clip-mask.pdf.rgb24.ref.png new file mode 100644 index 0000000000..c9eaf2dd62 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-paint-alpha-clip-mask.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-paint-alpha-clip-mask.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-paint-alpha-clip-mask.quartz.ref.png new file mode 100644 index 0000000000..6f14ad3b40 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-paint-alpha-clip-mask.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-paint-alpha-clip-mask.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-paint-alpha-clip-mask.ref.png new file mode 100644 index 0000000000..b824723e38 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-paint-alpha-clip-mask.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-paint-alpha-clip.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-paint-alpha-clip.pdf.rgb24.ref.png new file mode 100644 index 0000000000..22f7dfe805 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-paint-alpha-clip.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-paint-alpha-clip.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-paint-alpha-clip.ref.png new file mode 100644 index 0000000000..d619b6d60e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-paint-alpha-clip.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-paint-alpha-solid-clip.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-paint-alpha-solid-clip.ref.png new file mode 100644 index 0000000000..10dde68c52 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-paint-alpha-solid-clip.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-paint-alpha.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-paint-alpha.ref.png new file mode 100644 index 0000000000..599acfba27 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-paint-alpha.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-paint.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-paint.ref.png new file mode 100644 index 0000000000..22cc7a1ae5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-paint.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-select-font-face.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-select-font-face.pdf.rgb24.ref.png new file mode 100644 index 0000000000..36606176ab Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-select-font-face.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-select-font-face.ps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-select-font-face.ps.argb32.ref.png new file mode 100644 index 0000000000..086e5e941e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-select-font-face.ps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-select-font-face.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-select-font-face.ps.rgb24.ref.png new file mode 100644 index 0000000000..086e5e941e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-select-font-face.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-select-font-face.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-select-font-face.quartz.ref.png new file mode 100644 index 0000000000..488d35be4e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-select-font-face.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-select-font-face.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-select-font-face.ref.png new file mode 100644 index 0000000000..aae4e9549c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-select-font-face.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-select-font-face.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-select-font-face.svg.ref.png new file mode 100644 index 0000000000..31ac171b62 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-select-font-face.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-self-intersecting.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-self-intersecting.pdf.rgb24.ref.png new file mode 100644 index 0000000000..05eb9f6adc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-self-intersecting.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-self-intersecting.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-self-intersecting.ps.ref.png new file mode 100644 index 0000000000..84fde01711 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-self-intersecting.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-self-intersecting.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-self-intersecting.ref.png new file mode 100644 index 0000000000..d554d83eee Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-self-intersecting.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-text-transform.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-text-transform.pdf.rgb24.ref.png new file mode 100644 index 0000000000..a5826a1ad7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-text-transform.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-text-transform.ps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-text-transform.ps.argb32.ref.png new file mode 100644 index 0000000000..beed4bf189 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-text-transform.ps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-text-transform.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-text-transform.ps.rgb24.ref.png new file mode 100644 index 0000000000..beed4bf189 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-text-transform.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-text-transform.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-text-transform.ref.png new file mode 100644 index 0000000000..b5703758ee Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-text-transform.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-text-transform.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-text-transform.svg.ref.png new file mode 100644 index 0000000000..4a3a1105f8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-text-transform.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-whole-fill-alpha.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-whole-fill-alpha.ref.png new file mode 100644 index 0000000000..69035ef5f0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-whole-fill-alpha.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-whole-paint-alpha-clip-mask.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-whole-paint-alpha-clip-mask.ref.png new file mode 100644 index 0000000000..6f14ad3b40 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-whole-paint-alpha-clip-mask.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-whole-paint-alpha-clip.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-whole-paint-alpha-clip.ref.png new file mode 100644 index 0000000000..d619b6d60e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-whole-paint-alpha-clip.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-whole-paint-alpha-solid-clip.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-whole-paint-alpha-solid-clip.ref.png new file mode 100644 index 0000000000..10dde68c52 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-whole-paint-alpha-solid-clip.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-whole-paint-alpha.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-whole-paint-alpha.ref.png new file mode 100644 index 0000000000..599acfba27 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-whole-paint-alpha.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-whole-paint.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-whole-paint.ref.png new file mode 100644 index 0000000000..22cc7a1ae5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-whole-paint.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-whole-select-font-face.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-whole-select-font-face.quartz.ref.png new file mode 100644 index 0000000000..488d35be4e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-whole-select-font-face.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-whole-select-font-face.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-whole-select-font-face.ref.png new file mode 100644 index 0000000000..aae4e9549c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-whole-select-font-face.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-whole-select-font-face.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-whole-select-font-face.svg.ref.png new file mode 100644 index 0000000000..31ac171b62 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-whole-select-font-face.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-whole-self-intersecting.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-whole-self-intersecting.ref.png new file mode 100644 index 0000000000..d554d83eee Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-whole-self-intersecting.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-whole-text-transform.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-whole-text-transform.ref.png new file mode 100644 index 0000000000..b5703758ee Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-whole-text-transform.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recordflip-whole-text-transform.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/recordflip-whole-text-transform.svg.ref.png new file mode 100644 index 0000000000..4a3a1105f8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recordflip-whole-text-transform.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.argb32.ref.png new file mode 100644 index 0000000000..13898879dc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.base.argb32.ref.png new file mode 100644 index 0000000000..d612250af4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.base.rgb24.ref.png new file mode 100644 index 0000000000..0a57b44e73 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.pdf.argb32.ref.png new file mode 100644 index 0000000000..aa31f48c5c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.pdf.rgb24.ref.png new file mode 100644 index 0000000000..05d40c70e2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.ps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.ps.argb32.ref.png new file mode 100644 index 0000000000..d2db401161 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.ps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.ps.rgb24.ref.png new file mode 100644 index 0000000000..1a5b908a8c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.quartz.argb32.ref.png new file mode 100644 index 0000000000..07d737a135 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.quartz.rgb24.ref.png new file mode 100644 index 0000000000..0df6935295 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.rgb24.ref.png new file mode 100644 index 0000000000..6a8b81e68a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.svg.ref.png new file mode 100644 index 0000000000..0c86fe40a4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.traps.argb32.ref.png new file mode 100644 index 0000000000..d612250af4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.traps.rgb24.ref.png new file mode 100644 index 0000000000..0a57b44e73 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-none.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-pad.argb32.xfail.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-pad.argb32.xfail.png new file mode 100644 index 0000000000..9efed65be6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-pad.argb32.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-pad.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-pad.base.argb32.ref.png new file mode 100644 index 0000000000..7ec94c5bc9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-pad.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-pad.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-pad.base.rgb24.ref.png new file mode 100644 index 0000000000..8a064cd46d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-pad.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-pad.rgb24.xfail.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-pad.rgb24.xfail.png new file mode 100644 index 0000000000..7336890c44 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-pad.rgb24.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-pad.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-pad.traps.argb32.ref.png new file mode 100644 index 0000000000..7ec94c5bc9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-pad.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-pad.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-pad.traps.rgb24.ref.png new file mode 100644 index 0000000000..8a064cd46d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-pad.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.argb32.ref.png new file mode 100644 index 0000000000..f63ccee855 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.base.argb32.ref.png new file mode 100644 index 0000000000..4699d42f45 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.base.rgb24.ref.png new file mode 100644 index 0000000000..4975d7559d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.pdf.argb32.ref.png new file mode 100644 index 0000000000..f994199b1d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.pdf.rgb24.ref.png new file mode 100644 index 0000000000..3898494112 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.ps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.ps.argb32.ref.png new file mode 100644 index 0000000000..d9f3573d1d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.ps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.ps.rgb24.ref.png new file mode 100644 index 0000000000..9e43713b23 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.quartz.argb32.ref.png new file mode 100644 index 0000000000..5e3972acf3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.quartz.rgb24.ref.png new file mode 100644 index 0000000000..bc2cdf41d5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.rgb24.ref.png new file mode 100644 index 0000000000..26d4ae9163 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.svg.ref.png new file mode 100644 index 0000000000..e975c7f7fc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.traps.argb32.ref.png new file mode 100644 index 0000000000..4699d42f45 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.traps.rgb24.ref.png new file mode 100644 index 0000000000..4975d7559d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-reflect.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.argb32.ref.png new file mode 100644 index 0000000000..99d880c8e1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.base.argb32.ref.png new file mode 100644 index 0000000000..305c022a03 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.base.rgb24.ref.png new file mode 100644 index 0000000000..c3e296cbef Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.pdf.argb32.ref.png new file mode 100644 index 0000000000..141f5c209f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.pdf.rgb24.ref.png new file mode 100644 index 0000000000..59a448c9b8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.ps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.ps.argb32.ref.png new file mode 100644 index 0000000000..b12aa1763b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.ps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.ps.rgb24.ref.png new file mode 100644 index 0000000000..870027b114 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.quartz.argb32.ref.png new file mode 100644 index 0000000000..2f6f274de2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.quartz.rgb24.ref.png new file mode 100644 index 0000000000..a8943a7065 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.rgb24.ref.png new file mode 100644 index 0000000000..474e6e9e89 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.svg.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.svg.argb32.ref.png new file mode 100644 index 0000000000..09b04846e7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.svg.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.svg.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.svg.rgb24.ref.png new file mode 100644 index 0000000000..ec87749868 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.svg.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.traps.argb32.ref.png new file mode 100644 index 0000000000..305c022a03 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.traps.rgb24.ref.png new file mode 100644 index 0000000000..c3e296cbef Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-extend-repeat.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-over.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-over.argb32.ref.png new file mode 100644 index 0000000000..13898879dc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-over.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-over.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-over.base.argb32.ref.png new file mode 100644 index 0000000000..d612250af4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-over.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-over.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-over.base.rgb24.ref.png new file mode 100644 index 0000000000..0a57b44e73 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-over.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-over.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-over.image16.ref.png new file mode 100644 index 0000000000..020289389a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-over.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-over.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-over.pdf.argb32.ref.png new file mode 100644 index 0000000000..812f9ee509 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-over.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-over.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-over.pdf.rgb24.ref.png new file mode 100644 index 0000000000..d7bf21b264 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-over.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-over.ps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-over.ps.argb32.ref.png new file mode 100644 index 0000000000..d2db401161 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-over.ps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-over.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-over.ps.rgb24.ref.png new file mode 100644 index 0000000000..1a5b908a8c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-over.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-over.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-over.quartz.argb32.ref.png new file mode 100644 index 0000000000..07d737a135 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-over.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-over.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-over.quartz.rgb24.ref.png new file mode 100644 index 0000000000..0df6935295 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-over.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-over.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-over.rgb24.ref.png new file mode 100644 index 0000000000..6a8b81e68a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-over.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-over.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-over.svg.ref.png new file mode 100644 index 0000000000..0c86fe40a4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-over.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-over.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-over.traps.argb32.ref.png new file mode 100644 index 0000000000..d612250af4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-over.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-over.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-over.traps.rgb24.ref.png new file mode 100644 index 0000000000..0a57b44e73 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-over.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-source.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-source.argb32.ref.png new file mode 100644 index 0000000000..afe658772f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-source.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-source.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-source.base.argb32.ref.png new file mode 100644 index 0000000000..3fe1057fb1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-source.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-source.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-source.base.rgb24.ref.png new file mode 100644 index 0000000000..d2605bd35e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-source.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-source.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-source.pdf.argb32.ref.png new file mode 100644 index 0000000000..d2db401161 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-source.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-source.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-source.pdf.rgb24.ref.png new file mode 100644 index 0000000000..1a5b908a8c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-source.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-source.ps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-source.ps.argb32.ref.png new file mode 100644 index 0000000000..d2db401161 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-source.ps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-source.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-source.ps.rgb24.ref.png new file mode 100644 index 0000000000..1a5b908a8c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-source.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-source.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-source.quartz.argb32.ref.png new file mode 100644 index 0000000000..bd5d7497bc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-source.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-source.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-source.quartz.rgb24.ref.png new file mode 100644 index 0000000000..ddba6f3ff4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-source.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-source.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-source.rgb24.ref.png new file mode 100644 index 0000000000..76ec389646 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-source.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-source.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-source.svg.ref.png new file mode 100644 index 0000000000..0c86fe40a4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-source.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-source.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-source.traps.argb32.ref.png new file mode 100644 index 0000000000..3fe1057fb1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-source.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/recording-surface-source.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/recording-surface-source.traps.rgb24.ref.png new file mode 100644 index 0000000000..d2605bd35e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/recording-surface-source.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectangle-rounding-error.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/rectangle-rounding-error.base.argb32.ref.png new file mode 100644 index 0000000000..6cc1b21a28 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectangle-rounding-error.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectangle-rounding-error.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/rectangle-rounding-error.base.rgb24.ref.png new file mode 100644 index 0000000000..6cc1b21a28 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectangle-rounding-error.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectangle-rounding-error.ref.png b/local/recipes/libs/cairo/source/test/reference/rectangle-rounding-error.ref.png new file mode 100644 index 0000000000..413345d7c0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectangle-rounding-error.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-dash-scale-unaligned.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-dash-scale-unaligned.pdf.ref.png new file mode 100644 index 0000000000..b05e293582 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-dash-scale-unaligned.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-dash-scale-unaligned.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-dash-scale-unaligned.ps.ref.png new file mode 100644 index 0000000000..b55a18dcc2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-dash-scale-unaligned.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-dash-scale-unaligned.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-dash-scale-unaligned.quartz.xfail.png new file mode 100644 index 0000000000..ccc1f97e99 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-dash-scale-unaligned.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-dash-scale-unaligned.ref.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-dash-scale-unaligned.ref.png new file mode 100644 index 0000000000..19dbe7f15f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-dash-scale-unaligned.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-dash-scale-unaligned.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-dash-scale-unaligned.svg.ref.png new file mode 100644 index 0000000000..63622f56e1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-dash-scale-unaligned.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-dash-scale-unaligned.traps.ref.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-dash-scale-unaligned.traps.ref.png new file mode 100644 index 0000000000..02abfaad29 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-dash-scale-unaligned.traps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-dash-scale.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-dash-scale.quartz.xfail.png new file mode 100644 index 0000000000..4e3326b394 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-dash-scale.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-dash-scale.ref.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-dash-scale.ref.png new file mode 100644 index 0000000000..1ab868c345 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-dash-scale.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-dash-scale.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-dash-scale.svg.ref.png new file mode 100644 index 0000000000..3c0c9b93a6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-dash-scale.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-dash.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-dash.base.argb32.ref.png new file mode 100644 index 0000000000..33e7851e77 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-dash.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-dash.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-dash.base.rgb24.ref.png new file mode 100644 index 0000000000..33e7851e77 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-dash.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-dash.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-dash.mask.argb32.ref.png new file mode 100644 index 0000000000..33e7851e77 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-dash.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-dash.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-dash.mask.rgb24.ref.png new file mode 100644 index 0000000000..33e7851e77 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-dash.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-dash.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-dash.quartz.xfail.png new file mode 100644 index 0000000000..f349155fb8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-dash.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-dash.ref.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-dash.ref.png new file mode 100644 index 0000000000..33e7851e77 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-dash.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-dash.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-dash.traps.argb32.ref.png new file mode 100644 index 0000000000..33e7851e77 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-dash.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-dash.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-dash.traps.rgb24.ref.png new file mode 100644 index 0000000000..33e7851e77 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-dash.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-fill.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-fill.base.argb32.ref.png new file mode 100644 index 0000000000..dbaf38368d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-fill.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-fill.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-fill.base.rgb24.ref.png new file mode 100644 index 0000000000..dbaf38368d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-fill.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-fill.ref.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-fill.ref.png new file mode 100644 index 0000000000..84b5967e25 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-fill.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-grid.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-grid.base.argb32.ref.png new file mode 100644 index 0000000000..7176cb4dd8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-grid.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-grid.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-grid.base.rgb24.ref.png new file mode 100644 index 0000000000..7176cb4dd8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-grid.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-grid.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-grid.image16.ref.png new file mode 100644 index 0000000000..4d4c4da738 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-grid.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-grid.ref.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-grid.ref.png new file mode 100644 index 0000000000..8d47ef5673 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-grid.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-grid.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-grid.traps.argb32.ref.png new file mode 100644 index 0000000000..7176cb4dd8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-grid.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-grid.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-grid.traps.rgb24.ref.png new file mode 100644 index 0000000000..7176cb4dd8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-grid.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-miter-limit.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-miter-limit.base.argb32.ref.png new file mode 100644 index 0000000000..ddf7570d68 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-miter-limit.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-miter-limit.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-miter-limit.base.rgb24.ref.png new file mode 100644 index 0000000000..ddf7570d68 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-miter-limit.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-miter-limit.ps2.ref.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-miter-limit.ps2.ref.png new file mode 100644 index 0000000000..8213060671 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-miter-limit.ps2.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-miter-limit.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-miter-limit.ps3.ref.png new file mode 100644 index 0000000000..8213060671 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-miter-limit.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-miter-limit.ref.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-miter-limit.ref.png new file mode 100644 index 0000000000..d64d581e49 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-miter-limit.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-miter-limit.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-miter-limit.svg.ref.png new file mode 100644 index 0000000000..ee8a666566 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-miter-limit.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-miter-limit.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-miter-limit.traps.argb32.ref.png new file mode 100644 index 0000000000..ddf7570d68 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-miter-limit.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-miter-limit.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-miter-limit.traps.rgb24.ref.png new file mode 100644 index 0000000000..ddf7570d68 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-miter-limit.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-stroke.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-stroke.base.argb32.ref.png new file mode 100644 index 0000000000..260909b6f5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-stroke.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-stroke.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-stroke.base.rgb24.ref.png new file mode 100644 index 0000000000..260909b6f5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-stroke.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-stroke.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-stroke.quartz.xfail.png new file mode 100644 index 0000000000..e2a508e410 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-stroke.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rectilinear-stroke.ref.png b/local/recipes/libs/cairo/source/test/reference/rectilinear-stroke.ref.png new file mode 100644 index 0000000000..0a40b0decf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rectilinear-stroke.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/reflected-stroke.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/reflected-stroke.base.argb32.ref.png new file mode 100644 index 0000000000..3b99f1cf2d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/reflected-stroke.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/reflected-stroke.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/reflected-stroke.base.rgb24.ref.png new file mode 100644 index 0000000000..3b99f1cf2d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/reflected-stroke.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/reflected-stroke.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/reflected-stroke.image16.ref.png new file mode 100644 index 0000000000..ab12737199 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/reflected-stroke.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/reflected-stroke.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/reflected-stroke.mask.argb32.ref.png new file mode 100644 index 0000000000..9a7d6bc411 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/reflected-stroke.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/reflected-stroke.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/reflected-stroke.mask.rgb24.ref.png new file mode 100644 index 0000000000..9a7d6bc411 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/reflected-stroke.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/reflected-stroke.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/reflected-stroke.pdf.ref.png new file mode 100644 index 0000000000..efae740dab Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/reflected-stroke.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/reflected-stroke.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/reflected-stroke.ps.ref.png new file mode 100644 index 0000000000..5a28eefec3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/reflected-stroke.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/reflected-stroke.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/reflected-stroke.quartz.ref.png new file mode 100644 index 0000000000..71c3673412 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/reflected-stroke.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/reflected-stroke.ref.png b/local/recipes/libs/cairo/source/test/reference/reflected-stroke.ref.png new file mode 100644 index 0000000000..c05eb96f69 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/reflected-stroke.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/reflected-stroke.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/reflected-stroke.svg.ref.png new file mode 100644 index 0000000000..efae740dab Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/reflected-stroke.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/reflected-stroke.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/reflected-stroke.traps.argb32.ref.png new file mode 100644 index 0000000000..3b99f1cf2d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/reflected-stroke.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/reflected-stroke.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/reflected-stroke.traps.rgb24.ref.png new file mode 100644 index 0000000000..3b99f1cf2d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/reflected-stroke.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rel-path.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/rel-path.base.argb32.ref.png new file mode 100644 index 0000000000..5c9cf210a2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rel-path.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rel-path.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/rel-path.base.rgb24.ref.png new file mode 100644 index 0000000000..72e975ac1c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rel-path.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rel-path.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/rel-path.mask.rgb24.ref.png new file mode 100644 index 0000000000..78d8a08842 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rel-path.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rel-path.ps2.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/rel-path.ps2.rgb24.ref.png new file mode 100644 index 0000000000..ccdcebbc6c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rel-path.ps2.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rel-path.ps3.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/rel-path.ps3.rgb24.ref.png new file mode 100644 index 0000000000..ccdcebbc6c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rel-path.ps3.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rel-path.ref.png b/local/recipes/libs/cairo/source/test/reference/rel-path.ref.png new file mode 100644 index 0000000000..67fe178a74 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rel-path.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rel-path.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/rel-path.svg.ref.png new file mode 100644 index 0000000000..4f36ad50b7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rel-path.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rel-path.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/rel-path.traps.argb32.ref.png new file mode 100644 index 0000000000..5c9cf210a2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rel-path.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rel-path.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/rel-path.traps.rgb24.ref.png new file mode 100644 index 0000000000..72e975ac1c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rel-path.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rgb24-ignore-alpha.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/rgb24-ignore-alpha.base.argb32.ref.png new file mode 100644 index 0000000000..922eddda55 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rgb24-ignore-alpha.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rgb24-ignore-alpha.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/rgb24-ignore-alpha.base.rgb24.ref.png new file mode 100644 index 0000000000..922eddda55 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rgb24-ignore-alpha.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rgb24-ignore-alpha.ref.png b/local/recipes/libs/cairo/source/test/reference/rgb24-ignore-alpha.ref.png new file mode 100644 index 0000000000..ab1d8fac77 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rgb24-ignore-alpha.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.base.argb32.ref.png new file mode 100644 index 0000000000..7f74b2b3ce Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.base.rgb24.ref.png new file mode 100644 index 0000000000..7f74b2b3ce Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.pdf.argb32.png b/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.pdf.argb32.png new file mode 100644 index 0000000000..591e9a0036 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.pdf.argb32.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.pdf.rgb24.png b/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.pdf.rgb24.png new file mode 100644 index 0000000000..c1e357e94f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.pdf.rgb24.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.ps.argb32.png b/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.ps.argb32.png new file mode 100644 index 0000000000..159a5158a3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.ps.argb32.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.quartz.ref.png new file mode 100644 index 0000000000..45b321f3b2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.ref.png b/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.ref.png new file mode 100644 index 0000000000..90746fd2ea Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.svg.ref.png new file mode 100644 index 0000000000..c1e357e94f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.traps.argb32.ref.png new file mode 100644 index 0000000000..9d991d971f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.traps.rgb24.ref.png new file mode 100644 index 0000000000..9d991d971f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.xlib-fallback.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.xlib-fallback.rgb24.ref.png new file mode 100644 index 0000000000..9d991d971f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.xlib-fallback.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.xlib-window.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.xlib-window.rgb24.ref.png new file mode 100644 index 0000000000..9d991d971f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rotate-clip-image-surface-paint.xlib-window.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rotate-clip.surface-paint.image.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/rotate-clip.surface-paint.image.argb32.ref.png new file mode 100644 index 0000000000..63e6f9625c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rotate-clip.surface-paint.image.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rotate-clip.surface-paint.image.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/rotate-clip.surface-paint.image.rgb24.ref.png new file mode 100644 index 0000000000..63e6f9625c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rotate-clip.surface-paint.image.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rotate-image-surface-paint.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/rotate-image-surface-paint.base.argb32.ref.png new file mode 100644 index 0000000000..06a482005b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rotate-image-surface-paint.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rotate-image-surface-paint.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/rotate-image-surface-paint.base.rgb24.ref.png new file mode 100644 index 0000000000..06a482005b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rotate-image-surface-paint.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rotate-image-surface-paint.pdf.xfail.png b/local/recipes/libs/cairo/source/test/reference/rotate-image-surface-paint.pdf.xfail.png new file mode 100644 index 0000000000..e1892e57b7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rotate-image-surface-paint.pdf.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rotate-image-surface-paint.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/rotate-image-surface-paint.ps.ref.png new file mode 100644 index 0000000000..4e46364e93 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rotate-image-surface-paint.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rotate-image-surface-paint.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/rotate-image-surface-paint.quartz.ref.png new file mode 100644 index 0000000000..12204471e0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rotate-image-surface-paint.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rotate-image-surface-paint.ref.png b/local/recipes/libs/cairo/source/test/reference/rotate-image-surface-paint.ref.png new file mode 100644 index 0000000000..06a482005b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rotate-image-surface-paint.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rotate-image-surface-paint.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/rotate-image-surface-paint.svg.ref.png new file mode 100644 index 0000000000..8d8d59b092 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rotate-image-surface-paint.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rotate-stroke-box.ref.png b/local/recipes/libs/cairo/source/test/reference/rotate-stroke-box.ref.png new file mode 100644 index 0000000000..ef155f0322 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rotate-stroke-box.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rotated-clip.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/rotated-clip.base.argb32.ref.png new file mode 100644 index 0000000000..e553a138c2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rotated-clip.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rotated-clip.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/rotated-clip.base.rgb24.ref.png new file mode 100644 index 0000000000..e553a138c2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rotated-clip.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rotated-clip.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/rotated-clip.image16.ref.png new file mode 100644 index 0000000000..26d9a1aa08 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rotated-clip.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rotated-clip.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/rotated-clip.mask.argb32.ref.png new file mode 100644 index 0000000000..8168f9d99a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rotated-clip.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rotated-clip.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/rotated-clip.mask.rgb24.ref.png new file mode 100644 index 0000000000..8168f9d99a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rotated-clip.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rotated-clip.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/rotated-clip.pdf.ref.png new file mode 100644 index 0000000000..fd8707ae4d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rotated-clip.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rotated-clip.ps.argb32.png b/local/recipes/libs/cairo/source/test/reference/rotated-clip.ps.argb32.png new file mode 100644 index 0000000000..e26d118786 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rotated-clip.ps.argb32.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rotated-clip.ps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/rotated-clip.ps.argb32.ref.png new file mode 100644 index 0000000000..e26d118786 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rotated-clip.ps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rotated-clip.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/rotated-clip.ps.rgb24.ref.png new file mode 100644 index 0000000000..f5468c7dee Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rotated-clip.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rotated-clip.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/rotated-clip.quartz.ref.png new file mode 100644 index 0000000000..2c88c4b1af Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rotated-clip.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rotated-clip.ref.png b/local/recipes/libs/cairo/source/test/reference/rotated-clip.ref.png new file mode 100644 index 0000000000..f5468c7dee Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rotated-clip.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rotated-clip.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/rotated-clip.traps.argb32.ref.png new file mode 100644 index 0000000000..ca0f0af71e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rotated-clip.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rotated-clip.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/rotated-clip.traps.rgb24.ref.png new file mode 100644 index 0000000000..ca0f0af71e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rotated-clip.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/round-join-bug-520-bevel.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/round-join-bug-520-bevel.pdf.ref.png new file mode 100644 index 0000000000..b1a38e12f7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/round-join-bug-520-bevel.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/round-join-bug-520-bevel.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/round-join-bug-520-bevel.quartz.ref.png new file mode 100644 index 0000000000..b8796ff1e1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/round-join-bug-520-bevel.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/round-join-bug-520-bevel.ref.png b/local/recipes/libs/cairo/source/test/reference/round-join-bug-520-bevel.ref.png new file mode 100644 index 0000000000..b888f9ba9f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/round-join-bug-520-bevel.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/round-join-bug-520-bevel.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/round-join-bug-520-bevel.svg.ref.png new file mode 100644 index 0000000000..b1a38e12f7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/round-join-bug-520-bevel.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/round-join-bug-520-round.ref.png b/local/recipes/libs/cairo/source/test/reference/round-join-bug-520-round.ref.png new file mode 100644 index 0000000000..b1a38e12f7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/round-join-bug-520-round.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/round-join-bug-520-round.xlib-window.ref.png b/local/recipes/libs/cairo/source/test/reference/round-join-bug-520-round.xlib-window.ref.png new file mode 100644 index 0000000000..14ed9cbfe9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/round-join-bug-520-round.xlib-window.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/round-join-bug-520-round.xlib.ref.png b/local/recipes/libs/cairo/source/test/reference/round-join-bug-520-round.xlib.ref.png new file mode 100644 index 0000000000..14ed9cbfe9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/round-join-bug-520-round.xlib.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-fill.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-fill.base.argb32.ref.png new file mode 100644 index 0000000000..52a355dbcf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-fill.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-fill.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-fill.base.rgb24.ref.png new file mode 100644 index 0000000000..52a355dbcf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-fill.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-fill.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-fill.image16.ref.png new file mode 100644 index 0000000000..0739e5daed Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-fill.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-fill.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-fill.ps.ref.png new file mode 100644 index 0000000000..215ad3a15c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-fill.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-fill.ref.png b/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-fill.ref.png new file mode 100644 index 0000000000..e9bab0f957 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-fill.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-fill.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-fill.traps.argb32.ref.png new file mode 100644 index 0000000000..52a355dbcf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-fill.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-fill.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-fill.traps.rgb24.ref.png new file mode 100644 index 0000000000..52a355dbcf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-fill.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-stroke.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-stroke.base.argb32.ref.png new file mode 100644 index 0000000000..490821e068 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-stroke.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-stroke.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-stroke.base.rgb24.ref.png new file mode 100644 index 0000000000..490821e068 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-stroke.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-stroke.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-stroke.image16.ref.png new file mode 100644 index 0000000000..f32a2e0694 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-stroke.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-stroke.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-stroke.mask.argb32.ref.png new file mode 100644 index 0000000000..3f2a1fb2cd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-stroke.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-stroke.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-stroke.mask.rgb24.ref.png new file mode 100644 index 0000000000..3f2a1fb2cd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-stroke.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-stroke.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-stroke.ps.ref.png new file mode 100644 index 0000000000..dd5fc97f8a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-stroke.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-stroke.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-stroke.quartz.ref.png new file mode 100644 index 0000000000..9bae1d3861 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-stroke.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-stroke.ref.png b/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-stroke.ref.png new file mode 100644 index 0000000000..a98596006b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-stroke.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-stroke.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-stroke.traps.argb32.ref.png new file mode 100644 index 0000000000..490821e068 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-stroke.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-stroke.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-stroke.traps.rgb24.ref.png new file mode 100644 index 0000000000..490821e068 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/rounded-rectangle-stroke.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/sample-diagonal.ref.png b/local/recipes/libs/cairo/source/test/reference/sample-diagonal.ref.png new file mode 100644 index 0000000000..f866c2e879 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/sample-diagonal.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/sample-horizontal.ref.png b/local/recipes/libs/cairo/source/test/reference/sample-horizontal.ref.png new file mode 100644 index 0000000000..75f866b74a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/sample-horizontal.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/sample-vertical.ref.png b/local/recipes/libs/cairo/source/test/reference/sample-vertical.ref.png new file mode 100644 index 0000000000..75f866b74a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/sample-vertical.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-down-source-surface-paint.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/scale-down-source-surface-paint.base.argb32.ref.png new file mode 100644 index 0000000000..74770948d6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-down-source-surface-paint.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-down-source-surface-paint.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/scale-down-source-surface-paint.base.rgb24.ref.png new file mode 100644 index 0000000000..74770948d6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-down-source-surface-paint.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-down-source-surface-paint.ref.png b/local/recipes/libs/cairo/source/test/reference/scale-down-source-surface-paint.ref.png new file mode 100644 index 0000000000..5c969d2c5d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-down-source-surface-paint.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-offset-image.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/scale-offset-image.base.argb32.ref.png new file mode 100644 index 0000000000..19cd614d44 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-offset-image.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-offset-image.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/scale-offset-image.base.rgb24.ref.png new file mode 100644 index 0000000000..19cd614d44 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-offset-image.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-offset-image.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/scale-offset-image.image16.ref.png new file mode 100644 index 0000000000..e67949d011 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-offset-image.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-offset-image.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/scale-offset-image.pdf.ref.png new file mode 100644 index 0000000000..588c961fd9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-offset-image.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-offset-image.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/scale-offset-image.ps.ref.png new file mode 100644 index 0000000000..19941f00eb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-offset-image.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-offset-image.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/scale-offset-image.quartz.ref.png new file mode 100644 index 0000000000..f7a5e7228b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-offset-image.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-offset-image.ref.png b/local/recipes/libs/cairo/source/test/reference/scale-offset-image.ref.png new file mode 100644 index 0000000000..085029f7b1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-offset-image.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-offset-image.script.xfail.png b/local/recipes/libs/cairo/source/test/reference/scale-offset-image.script.xfail.png new file mode 100644 index 0000000000..b89bb66b06 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-offset-image.script.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-offset-image.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/scale-offset-image.traps.argb32.ref.png new file mode 100644 index 0000000000..19cd614d44 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-offset-image.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-offset-image.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/scale-offset-image.traps.rgb24.ref.png new file mode 100644 index 0000000000..19cd614d44 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-offset-image.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-offset-image.xfail.png b/local/recipes/libs/cairo/source/test/reference/scale-offset-image.xfail.png new file mode 100644 index 0000000000..f0db601fce Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-offset-image.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-offset-image.xlib-fallback.xfail.png b/local/recipes/libs/cairo/source/test/reference/scale-offset-image.xlib-fallback.xfail.png new file mode 100644 index 0000000000..3e09d6f881 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-offset-image.xlib-fallback.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.base.argb32.ref.png new file mode 100644 index 0000000000..19cd614d44 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.base.rgb24.ref.png new file mode 100644 index 0000000000..19cd614d44 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.image16.ref.png new file mode 100644 index 0000000000..e67949d011 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.pdf.ref.png new file mode 100644 index 0000000000..a5e9aadd1d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.ps.ref.png new file mode 100644 index 0000000000..8c10d30e43 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.quartz.ref.png new file mode 100644 index 0000000000..f7a5e7228b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.recording.xfail.png b/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.recording.xfail.png new file mode 100644 index 0000000000..0f2553e49f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.recording.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.ref.png b/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.ref.png new file mode 100644 index 0000000000..085029f7b1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.script.xfail.png b/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.script.xfail.png new file mode 100644 index 0000000000..b89bb66b06 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.script.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.svg.ref.png new file mode 100644 index 0000000000..30ec6b8b06 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.traps.argb32.ref.png new file mode 100644 index 0000000000..19cd614d44 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.traps.rgb24.ref.png new file mode 100644 index 0000000000..19cd614d44 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.xfail.png b/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.xfail.png new file mode 100644 index 0000000000..f0db601fce Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.xlib-fallback.xfail.png b/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.xlib-fallback.xfail.png new file mode 100644 index 0000000000..3e09d6f881 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.xlib-fallback.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.xlib.xfail.png b/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.xlib.xfail.png new file mode 100644 index 0000000000..eb4851628f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-offset-similar.xlib.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-offset-xlib-fallback.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/scale-offset-xlib-fallback.rgb24.ref.png new file mode 100644 index 0000000000..dbb1225edf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-offset-xlib-fallback.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-offset-xlib-window.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/scale-offset-xlib-window.rgb24.ref.png new file mode 100644 index 0000000000..dbb1225edf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-offset-xlib-window.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-offset-xlib.ref.png b/local/recipes/libs/cairo/source/test/reference/scale-offset-xlib.ref.png new file mode 100644 index 0000000000..dbb1225edf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-offset-xlib.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-offset.image.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/scale-offset.image.argb32.ref.png new file mode 100644 index 0000000000..12470634ba Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-offset.image.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-offset.image.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/scale-offset.image.rgb24.ref.png new file mode 100644 index 0000000000..12470634ba Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-offset.image.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-source-surface-paint.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/scale-source-surface-paint.base.argb32.ref.png new file mode 100644 index 0000000000..e159d15e3d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-source-surface-paint.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-source-surface-paint.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/scale-source-surface-paint.base.rgb24.ref.png new file mode 100644 index 0000000000..3491a7c051 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-source-surface-paint.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-source-surface-paint.pdf.argb32.xfail.png b/local/recipes/libs/cairo/source/test/reference/scale-source-surface-paint.pdf.argb32.xfail.png new file mode 100644 index 0000000000..7ecac1776d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-source-surface-paint.pdf.argb32.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-source-surface-paint.pdf.rgb24.xfail.png b/local/recipes/libs/cairo/source/test/reference/scale-source-surface-paint.pdf.rgb24.xfail.png new file mode 100644 index 0000000000..fa1291f960 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-source-surface-paint.pdf.rgb24.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/scale-source-surface-paint.ref.png b/local/recipes/libs/cairo/source/test/reference/scale-source-surface-paint.ref.png new file mode 100644 index 0000000000..ec3c059fd1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/scale-source-surface-paint.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/select-font-face.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/select-font-face.base.argb32.ref.png new file mode 100644 index 0000000000..1334a9a01c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/select-font-face.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/select-font-face.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/select-font-face.base.rgb24.ref.png new file mode 100644 index 0000000000..1334a9a01c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/select-font-face.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/select-font-face.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/select-font-face.image16.ref.png new file mode 100644 index 0000000000..2c3191cb9d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/select-font-face.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/select-font-face.ps2.ref.png b/local/recipes/libs/cairo/source/test/reference/select-font-face.ps2.ref.png new file mode 100644 index 0000000000..6c2f36115e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/select-font-face.ps2.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/select-font-face.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/select-font-face.ps3.ref.png new file mode 100644 index 0000000000..6c2f36115e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/select-font-face.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/select-font-face.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/select-font-face.quartz.ref.png new file mode 100644 index 0000000000..1100fe28cf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/select-font-face.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/select-font-face.ref.png b/local/recipes/libs/cairo/source/test/reference/select-font-face.ref.png new file mode 100644 index 0000000000..1334a9a01c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/select-font-face.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/select-font-face.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/select-font-face.svg.ref.png new file mode 100644 index 0000000000..2ab46d10a3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/select-font-face.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/self-copy-overlap.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/self-copy-overlap.base.argb32.ref.png new file mode 100644 index 0000000000..a70e819ed5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/self-copy-overlap.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/self-copy-overlap.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/self-copy-overlap.base.rgb24.ref.png new file mode 100644 index 0000000000..e9cd7b5674 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/self-copy-overlap.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/self-copy-overlap.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/self-copy-overlap.mask.argb32.ref.png new file mode 100644 index 0000000000..a70e819ed5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/self-copy-overlap.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/self-copy-overlap.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/self-copy-overlap.mask.rgb24.ref.png new file mode 100644 index 0000000000..e9cd7b5674 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/self-copy-overlap.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/self-copy-overlap.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/self-copy-overlap.traps.argb32.ref.png new file mode 100644 index 0000000000..a70e819ed5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/self-copy-overlap.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/self-copy-overlap.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/self-copy-overlap.traps.rgb24.ref.png new file mode 100644 index 0000000000..e9cd7b5674 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/self-copy-overlap.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/self-copy-overlap.xcb.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/self-copy-overlap.xcb.argb32.ref.png new file mode 100644 index 0000000000..bf15ed94a3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/self-copy-overlap.xcb.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/self-copy-overlap.xlib.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/self-copy-overlap.xlib.argb32.ref.png new file mode 100644 index 0000000000..bf15ed94a3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/self-copy-overlap.xlib.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/self-copy.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/self-copy.base.argb32.ref.png new file mode 100644 index 0000000000..daa4dcb300 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/self-copy.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/self-copy.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/self-copy.base.rgb24.ref.png new file mode 100644 index 0000000000..daa4dcb300 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/self-copy.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/self-copy.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/self-copy.ps.ref.png new file mode 100644 index 0000000000..0031d58475 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/self-copy.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/self-copy.ref.png b/local/recipes/libs/cairo/source/test/reference/self-copy.ref.png new file mode 100644 index 0000000000..d8221d8a76 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/self-copy.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/self-copy.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/self-copy.svg.ref.png new file mode 100644 index 0000000000..e35a5e9c55 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/self-copy.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/self-copy.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/self-copy.traps.argb32.ref.png new file mode 100644 index 0000000000..daa4dcb300 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/self-copy.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/self-copy.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/self-copy.traps.rgb24.ref.png new file mode 100644 index 0000000000..daa4dcb300 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/self-copy.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/self-intersecting.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/self-intersecting.base.argb32.ref.png new file mode 100644 index 0000000000..f0068e618c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/self-intersecting.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/self-intersecting.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/self-intersecting.base.rgb24.ref.png new file mode 100644 index 0000000000..f0068e618c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/self-intersecting.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/self-intersecting.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/self-intersecting.ps.ref.png new file mode 100644 index 0000000000..84fde01711 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/self-intersecting.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/self-intersecting.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/self-intersecting.quartz.xfail.png new file mode 100644 index 0000000000..4d087137f6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/self-intersecting.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/self-intersecting.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/self-intersecting.traps.argb32.ref.png new file mode 100644 index 0000000000..f0068e618c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/self-intersecting.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/self-intersecting.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/self-intersecting.traps.rgb24.ref.png new file mode 100644 index 0000000000..f0068e618c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/self-intersecting.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/self-intersecting.xcb-window&.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/self-intersecting.xcb-window&.rgb24.ref.png new file mode 100644 index 0000000000..bc31b33e74 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/self-intersecting.xcb-window&.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/self-intersecting.xcb-window.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/self-intersecting.xcb-window.rgb24.ref.png new file mode 100644 index 0000000000..bc31b33e74 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/self-intersecting.xcb-window.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/self-intersecting.xcb.ref.png b/local/recipes/libs/cairo/source/test/reference/self-intersecting.xcb.ref.png new file mode 100644 index 0000000000..bc31b33e74 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/self-intersecting.xcb.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/self-intersecting.xlib-window.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/self-intersecting.xlib-window.rgb24.ref.png new file mode 100644 index 0000000000..bc31b33e74 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/self-intersecting.xlib-window.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/self-intersecting.xlib.ref.png b/local/recipes/libs/cairo/source/test/reference/self-intersecting.xlib.ref.png new file mode 100644 index 0000000000..bc31b33e74 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/self-intersecting.xlib.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/set-source.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/set-source.base.argb32.ref.png new file mode 100644 index 0000000000..222b3723e9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/set-source.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/set-source.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/set-source.base.rgb24.ref.png new file mode 100644 index 0000000000..5e13c82e7d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/set-source.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/set-source.ref.png b/local/recipes/libs/cairo/source/test/reference/set-source.ref.png new file mode 100644 index 0000000000..19793e0261 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/set-source.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/set-source.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/set-source.svg.ref.png new file mode 100644 index 0000000000..f4a4fae121 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/set-source.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/shape-general-convex.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/shape-general-convex.base.argb32.ref.png new file mode 100644 index 0000000000..fc2d3f0d37 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/shape-general-convex.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/shape-general-convex.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/shape-general-convex.base.rgb24.ref.png new file mode 100644 index 0000000000..fc2d3f0d37 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/shape-general-convex.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/shape-general-convex.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/shape-general-convex.ps.ref.png new file mode 100644 index 0000000000..6cdd615d66 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/shape-general-convex.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/shape-general-convex.ref.png b/local/recipes/libs/cairo/source/test/reference/shape-general-convex.ref.png new file mode 100644 index 0000000000..2f648d5243 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/shape-general-convex.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/shape-general-convex.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/shape-general-convex.traps.argb32.ref.png new file mode 100644 index 0000000000..fc2d3f0d37 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/shape-general-convex.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/shape-general-convex.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/shape-general-convex.traps.rgb24.ref.png new file mode 100644 index 0000000000..fc2d3f0d37 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/shape-general-convex.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/shape-sierpinski.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/shape-sierpinski.base.argb32.ref.png new file mode 100644 index 0000000000..69755d27aa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/shape-sierpinski.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/shape-sierpinski.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/shape-sierpinski.base.rgb24.ref.png new file mode 100644 index 0000000000..69755d27aa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/shape-sierpinski.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/shape-sierpinski.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/shape-sierpinski.pdf.ref.png new file mode 100644 index 0000000000..786d8d2013 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/shape-sierpinski.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/shape-sierpinski.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/shape-sierpinski.ps.ref.png new file mode 100644 index 0000000000..700c9f1488 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/shape-sierpinski.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/shape-sierpinski.ps3.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/shape-sierpinski.ps3.argb32.ref.png new file mode 100644 index 0000000000..700c9f1488 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/shape-sierpinski.ps3.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/shape-sierpinski.ps3.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/shape-sierpinski.ps3.rgb24.ref.png new file mode 100644 index 0000000000..700c9f1488 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/shape-sierpinski.ps3.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/shape-sierpinski.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/shape-sierpinski.quartz.ref.png new file mode 100644 index 0000000000..a82054f91a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/shape-sierpinski.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/shape-sierpinski.ref.png b/local/recipes/libs/cairo/source/test/reference/shape-sierpinski.ref.png new file mode 100644 index 0000000000..5d983671f7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/shape-sierpinski.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/shape-sierpinski.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/shape-sierpinski.svg.ref.png new file mode 100644 index 0000000000..601d3575c4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/shape-sierpinski.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/shape-sierpinski.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/shape-sierpinski.traps.argb32.ref.png new file mode 100644 index 0000000000..69755d27aa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/shape-sierpinski.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/shape-sierpinski.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/shape-sierpinski.traps.rgb24.ref.png new file mode 100644 index 0000000000..69755d27aa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/shape-sierpinski.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/shifted-operator.ref.png b/local/recipes/libs/cairo/source/test/reference/shifted-operator.ref.png new file mode 100644 index 0000000000..3b27dbe04c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/shifted-operator.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/shifted-operator.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/shifted-operator.rgb24.ref.png new file mode 100644 index 0000000000..4627fff6d8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/shifted-operator.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/show-glyphs-advance.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/show-glyphs-advance.base.argb32.ref.png new file mode 100644 index 0000000000..e65ad05d56 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/show-glyphs-advance.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/show-glyphs-advance.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/show-glyphs-advance.base.rgb24.ref.png new file mode 100644 index 0000000000..e65ad05d56 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/show-glyphs-advance.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/show-glyphs-advance.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/show-glyphs-advance.image16.ref.png new file mode 100644 index 0000000000..dd2f18d08e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/show-glyphs-advance.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/show-glyphs-advance.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/show-glyphs-advance.ps.ref.png new file mode 100644 index 0000000000..96a80f9bc7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/show-glyphs-advance.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/show-glyphs-advance.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/show-glyphs-advance.quartz.ref.png new file mode 100644 index 0000000000..69395bfbbf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/show-glyphs-advance.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/show-glyphs-advance.ref.png b/local/recipes/libs/cairo/source/test/reference/show-glyphs-advance.ref.png new file mode 100644 index 0000000000..e65ad05d56 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/show-glyphs-advance.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/show-glyphs-many.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/show-glyphs-many.base.argb32.ref.png new file mode 100644 index 0000000000..b638015d31 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/show-glyphs-many.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/show-glyphs-many.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/show-glyphs-many.base.rgb24.ref.png new file mode 100644 index 0000000000..b638015d31 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/show-glyphs-many.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/show-glyphs-many.ref.png b/local/recipes/libs/cairo/source/test/reference/show-glyphs-many.ref.png new file mode 100644 index 0000000000..b61c5f7b6a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/show-glyphs-many.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/show-text-current-point.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/show-text-current-point.base.argb32.ref.png new file mode 100644 index 0000000000..d60d4ac014 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/show-text-current-point.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/show-text-current-point.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/show-text-current-point.base.rgb24.ref.png new file mode 100644 index 0000000000..d60d4ac014 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/show-text-current-point.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/show-text-current-point.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/show-text-current-point.image16.ref.png new file mode 100644 index 0000000000..b2b933fbaf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/show-text-current-point.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/show-text-current-point.ps2.ref.png b/local/recipes/libs/cairo/source/test/reference/show-text-current-point.ps2.ref.png new file mode 100644 index 0000000000..b42c48e7f3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/show-text-current-point.ps2.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/show-text-current-point.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/show-text-current-point.ps3.ref.png new file mode 100644 index 0000000000..b42c48e7f3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/show-text-current-point.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/show-text-current-point.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/show-text-current-point.quartz.ref.png new file mode 100644 index 0000000000..a5313814a9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/show-text-current-point.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/show-text-current-point.ref.png b/local/recipes/libs/cairo/source/test/reference/show-text-current-point.ref.png new file mode 100644 index 0000000000..d60d4ac014 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/show-text-current-point.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/show-text-current-point.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/show-text-current-point.svg.ref.png new file mode 100644 index 0000000000..0baa572687 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/show-text-current-point.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/simple-edge.ref.png b/local/recipes/libs/cairo/source/test/reference/simple-edge.ref.png new file mode 100644 index 0000000000..8ba7dd3d65 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/simple-edge.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/simple-edge.xfail.png b/local/recipes/libs/cairo/source/test/reference/simple-edge.xfail.png new file mode 100644 index 0000000000..2daad97832 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/simple-edge.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/skew-extreme.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/skew-extreme.base.argb32.ref.png new file mode 100644 index 0000000000..5e00606d12 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/skew-extreme.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/skew-extreme.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/skew-extreme.base.rgb24.ref.png new file mode 100644 index 0000000000..5e00606d12 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/skew-extreme.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/skew-extreme.ps2.ref.png b/local/recipes/libs/cairo/source/test/reference/skew-extreme.ps2.ref.png new file mode 100644 index 0000000000..69f1d374f0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/skew-extreme.ps2.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/skew-extreme.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/skew-extreme.ps3.ref.png new file mode 100644 index 0000000000..69f1d374f0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/skew-extreme.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/skew-extreme.ref.png b/local/recipes/libs/cairo/source/test/reference/skew-extreme.ref.png new file mode 100644 index 0000000000..69e026d7ed Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/skew-extreme.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/skew-extreme.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/skew-extreme.traps.argb32.ref.png new file mode 100644 index 0000000000..5e00606d12 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/skew-extreme.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/skew-extreme.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/skew-extreme.traps.rgb24.ref.png new file mode 100644 index 0000000000..5e00606d12 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/skew-extreme.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-fill.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-fill.base.argb32.ref.png new file mode 100644 index 0000000000..30bc98e141 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-fill.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-fill.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-fill.base.rgb24.ref.png new file mode 100644 index 0000000000..30bc98e141 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-fill.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-fill.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-fill.image16.ref.png new file mode 100644 index 0000000000..25a6d5b2ae Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-fill.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-fill.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-fill.pdf.ref.png new file mode 100644 index 0000000000..420295ab83 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-fill.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-fill.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-fill.quartz.ref.png new file mode 100644 index 0000000000..7d0f56857b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-fill.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-fill.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-fill.ref.png new file mode 100644 index 0000000000..c7aff5a1b7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-fill.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-fill.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-fill.svg.ref.png new file mode 100644 index 0000000000..d3983a0aea Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-fill.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-fill.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-fill.traps.argb32.ref.png new file mode 100644 index 0000000000..30bc98e141 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-fill.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-fill.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-fill.traps.rgb24.ref.png new file mode 100644 index 0000000000..30bc98e141 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-fill.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-image-mask.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-image-mask.base.argb32.ref.png new file mode 100644 index 0000000000..12063bda24 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-image-mask.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-image-mask.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-image-mask.base.rgb24.ref.png new file mode 100644 index 0000000000..12063bda24 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-image-mask.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-image-mask.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-image-mask.pdf.ref.png new file mode 100644 index 0000000000..03201af6a6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-image-mask.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-image-mask.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-image-mask.ref.png new file mode 100644 index 0000000000..12063bda24 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-image-mask.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-image-mask.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-image-mask.svg.ref.png new file mode 100644 index 0000000000..6bbf2d32a2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-image-mask.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-mask.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-mask.base.argb32.ref.png new file mode 100644 index 0000000000..80329c2637 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-mask.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-mask.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-mask.base.rgb24.ref.png new file mode 100644 index 0000000000..80329c2637 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-mask.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-mask.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-mask.image16.ref.png new file mode 100644 index 0000000000..5024521573 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-mask.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-mask.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-mask.pdf.ref.png new file mode 100644 index 0000000000..4d25ac94a8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-mask.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-mask.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-mask.quartz.ref.png new file mode 100644 index 0000000000..98ba2996be Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-mask.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-mask.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-mask.ref.png new file mode 100644 index 0000000000..80329c2637 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-mask.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-mask.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-mask.svg.ref.png new file mode 100644 index 0000000000..963aea64ad Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-mask.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-paint.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-paint.base.argb32.ref.png new file mode 100644 index 0000000000..95af29af4f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-paint.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-paint.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-paint.base.rgb24.ref.png new file mode 100644 index 0000000000..95af29af4f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-paint.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-paint.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-paint.image16.ref.png new file mode 100644 index 0000000000..dc371dfc34 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-paint.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-paint.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-paint.pdf.ref.png new file mode 100644 index 0000000000..9d4c6cee0f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-paint.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-paint.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-paint.quartz.ref.png new file mode 100644 index 0000000000..4ee25fd0fe Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-paint.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-paint.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-paint.ref.png new file mode 100644 index 0000000000..95af29af4f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-paint.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-paint.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-paint.svg.ref.png new file mode 100644 index 0000000000..00500e41f1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-paint.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-stroke.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-stroke.base.argb32.ref.png new file mode 100644 index 0000000000..c6a557d8b6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-stroke.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-stroke.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-stroke.base.rgb24.ref.png new file mode 100644 index 0000000000..c6a557d8b6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-stroke.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-stroke.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-stroke.image16.ref.png new file mode 100644 index 0000000000..ea2138ab35 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-stroke.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-stroke.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-stroke.pdf.ref.png new file mode 100644 index 0000000000..f6ddb1939f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-stroke.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-stroke.pdf.xfail.png b/local/recipes/libs/cairo/source/test/reference/smask-stroke.pdf.xfail.png new file mode 100644 index 0000000000..9a1a7713ef Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-stroke.pdf.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-stroke.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-stroke.quartz.ref.png new file mode 100644 index 0000000000..3c472a67b3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-stroke.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-stroke.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-stroke.ref.png new file mode 100644 index 0000000000..5d8c79960d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-stroke.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-stroke.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-stroke.svg.ref.png new file mode 100644 index 0000000000..feb367a71c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-stroke.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-stroke.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-stroke.traps.argb32.ref.png new file mode 100644 index 0000000000..c6a557d8b6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-stroke.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-stroke.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-stroke.traps.rgb24.ref.png new file mode 100644 index 0000000000..c6a557d8b6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-stroke.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-text.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-text.base.argb32.ref.png new file mode 100644 index 0000000000..344ac2089b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-text.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-text.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-text.base.rgb24.ref.png new file mode 100644 index 0000000000..344ac2089b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-text.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-text.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-text.image16.ref.png new file mode 100644 index 0000000000..098043d672 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-text.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-text.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-text.mask.argb32.ref.png new file mode 100644 index 0000000000..344ac2089b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-text.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-text.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-text.mask.rgb24.ref.png new file mode 100644 index 0000000000..344ac2089b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-text.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-text.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-text.pdf.ref.png new file mode 100644 index 0000000000..6b94f4accc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-text.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-text.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-text.ps.ref.png new file mode 100644 index 0000000000..4e00665674 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-text.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-text.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-text.quartz.ref.png new file mode 100644 index 0000000000..b64eb0cb8a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-text.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-text.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-text.ref.png new file mode 100644 index 0000000000..63acaf5aaa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-text.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-text.script.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-text.script.ref.png new file mode 100644 index 0000000000..62b2de5af2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-text.script.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-text.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-text.svg.ref.png new file mode 100644 index 0000000000..88cae9bee4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-text.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-text.traps.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-text.traps.ref.png new file mode 100644 index 0000000000..66ef289cad Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-text.traps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask-text.xlib-fallback.ref.png b/local/recipes/libs/cairo/source/test/reference/smask-text.xlib-fallback.ref.png new file mode 100644 index 0000000000..bb393b5204 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask-text.xlib-fallback.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/smask.base.argb32.ref.png new file mode 100644 index 0000000000..357e8e7fba Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/smask.base.rgb24.ref.png new file mode 100644 index 0000000000..357e8e7fba Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/smask.image16.ref.png new file mode 100644 index 0000000000..d817c80149 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/smask.mask.argb32.ref.png new file mode 100644 index 0000000000..dab308d8e8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/smask.mask.rgb24.ref.png new file mode 100644 index 0000000000..dab308d8e8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/smask.pdf.ref.png new file mode 100644 index 0000000000..2bc721c525 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask.pdf.xfail.png b/local/recipes/libs/cairo/source/test/reference/smask.pdf.xfail.png new file mode 100644 index 0000000000..f8b559cb47 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask.pdf.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/smask.ps.ref.png new file mode 100644 index 0000000000..31ccc17b7d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/smask.ps3.ref.png new file mode 100644 index 0000000000..fb1d74e1c3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/smask.quartz.ref.png new file mode 100644 index 0000000000..fac4b4e331 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask.ref.png b/local/recipes/libs/cairo/source/test/reference/smask.ref.png new file mode 100644 index 0000000000..99fcf40bb0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask.script.ref.png b/local/recipes/libs/cairo/source/test/reference/smask.script.ref.png new file mode 100644 index 0000000000..3b672d6e92 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask.script.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/smask.svg.ref.png new file mode 100644 index 0000000000..b5a6d9eaa9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask.traps.ref.png b/local/recipes/libs/cairo/source/test/reference/smask.traps.ref.png new file mode 100644 index 0000000000..357e8e7fba Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask.traps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smask.xlib-fallback.ref.png b/local/recipes/libs/cairo/source/test/reference/smask.xlib-fallback.ref.png new file mode 100644 index 0000000000..b5919de370 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smask.xlib-fallback.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smp-glyph.ref.png b/local/recipes/libs/cairo/source/test/reference/smp-glyph.ref.png new file mode 100644 index 0000000000..260332d3a9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smp-glyph.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smp-glyph.script.ref.png b/local/recipes/libs/cairo/source/test/reference/smp-glyph.script.ref.png new file mode 100644 index 0000000000..d15848ce15 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smp-glyph.script.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/smp-glyph.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/smp-glyph.svg.ref.png new file mode 100644 index 0000000000..d15848ce15 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/smp-glyph.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/solid-pattern-cache-stress.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/solid-pattern-cache-stress.base.argb32.ref.png new file mode 100644 index 0000000000..08a2ce152d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/solid-pattern-cache-stress.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/solid-pattern-cache-stress.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/solid-pattern-cache-stress.base.rgb24.ref.png new file mode 100644 index 0000000000..08a2ce152d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/solid-pattern-cache-stress.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/solid-pattern-cache-stress.ref.png b/local/recipes/libs/cairo/source/test/reference/solid-pattern-cache-stress.ref.png new file mode 100644 index 0000000000..e0e8498c34 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/solid-pattern-cache-stress.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/source-clip-scale.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/source-clip-scale.base.argb32.ref.png new file mode 100644 index 0000000000..4b63ad9bf0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/source-clip-scale.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/source-clip-scale.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/source-clip-scale.base.rgb24.ref.png new file mode 100644 index 0000000000..4b63ad9bf0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/source-clip-scale.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/source-clip-scale.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/source-clip-scale.pdf.ref.png new file mode 100644 index 0000000000..78c77106ce Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/source-clip-scale.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/source-clip-scale.ps2.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/source-clip-scale.ps2.argb32.ref.png new file mode 100644 index 0000000000..be57d7721a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/source-clip-scale.ps2.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/source-clip-scale.ps2.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/source-clip-scale.ps2.rgb24.ref.png new file mode 100644 index 0000000000..be57d7721a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/source-clip-scale.ps2.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/source-clip-scale.ps3.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/source-clip-scale.ps3.argb32.ref.png new file mode 100644 index 0000000000..be57d7721a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/source-clip-scale.ps3.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/source-clip-scale.ps3.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/source-clip-scale.ps3.rgb24.ref.png new file mode 100644 index 0000000000..be57d7721a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/source-clip-scale.ps3.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/source-clip-scale.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/source-clip-scale.quartz.ref.png new file mode 100644 index 0000000000..366500905d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/source-clip-scale.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/source-clip-scale.recording.ref.png b/local/recipes/libs/cairo/source/test/reference/source-clip-scale.recording.ref.png new file mode 100644 index 0000000000..bbf7c9be5e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/source-clip-scale.recording.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/source-clip-scale.ref.png b/local/recipes/libs/cairo/source/test/reference/source-clip-scale.ref.png new file mode 100644 index 0000000000..1519ff895a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/source-clip-scale.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/source-clip-scale.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/source-clip-scale.svg.ref.png new file mode 100644 index 0000000000..bbf7c9be5e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/source-clip-scale.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/source-clip.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/source-clip.base.argb32.ref.png new file mode 100644 index 0000000000..821bc6cabc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/source-clip.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/source-clip.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/source-clip.base.rgb24.ref.png new file mode 100644 index 0000000000..821bc6cabc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/source-clip.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/source-clip.ref.png b/local/recipes/libs/cairo/source/test/reference/source-clip.ref.png new file mode 100644 index 0000000000..22454bed9d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/source-clip.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/source-surface-scale-paint.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/source-surface-scale-paint.base.argb32.ref.png new file mode 100644 index 0000000000..087ef75212 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/source-surface-scale-paint.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/source-surface-scale-paint.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/source-surface-scale-paint.base.rgb24.ref.png new file mode 100644 index 0000000000..322af211d0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/source-surface-scale-paint.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/source-surface-scale-paint.ref.png b/local/recipes/libs/cairo/source/test/reference/source-surface-scale-paint.ref.png new file mode 100644 index 0000000000..a81f93d940 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/source-surface-scale-paint.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/spline-decomposition.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/spline-decomposition.base.argb32.ref.png new file mode 100644 index 0000000000..babde7d725 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/spline-decomposition.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/spline-decomposition.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/spline-decomposition.base.rgb24.ref.png new file mode 100644 index 0000000000..babde7d725 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/spline-decomposition.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/spline-decomposition.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/spline-decomposition.image16.ref.png new file mode 100644 index 0000000000..4084b00f99 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/spline-decomposition.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/spline-decomposition.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/spline-decomposition.pdf.ref.png new file mode 100644 index 0000000000..99fd1d637c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/spline-decomposition.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/spline-decomposition.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/spline-decomposition.ps.ref.png new file mode 100644 index 0000000000..7f3a8e6d6b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/spline-decomposition.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/spline-decomposition.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/spline-decomposition.quartz.xfail.png new file mode 100644 index 0000000000..eeb3bf6ab7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/spline-decomposition.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/spline-decomposition.ref.png b/local/recipes/libs/cairo/source/test/reference/spline-decomposition.ref.png new file mode 100644 index 0000000000..356a3a56e6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/spline-decomposition.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/spline-decomposition.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/spline-decomposition.svg.ref.png new file mode 100644 index 0000000000..99fd1d637c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/spline-decomposition.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/spline-decomposition.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/spline-decomposition.traps.argb32.ref.png new file mode 100644 index 0000000000..babde7d725 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/spline-decomposition.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/spline-decomposition.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/spline-decomposition.traps.rgb24.ref.png new file mode 100644 index 0000000000..babde7d725 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/spline-decomposition.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stride-12-image.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/stride-12-image.base.argb32.ref.png new file mode 100644 index 0000000000..44284566ee Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stride-12-image.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stride-12-image.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/stride-12-image.base.rgb24.ref.png new file mode 100644 index 0000000000..44284566ee Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stride-12-image.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stride-12-image.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/stride-12-image.image16.ref.png new file mode 100644 index 0000000000..4b15914f26 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stride-12-image.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stride-12-image.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/stride-12-image.ps.ref.png new file mode 100644 index 0000000000..953c9a18ea Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stride-12-image.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stride-12-image.ref.png b/local/recipes/libs/cairo/source/test/reference/stride-12-image.ref.png new file mode 100644 index 0000000000..44284566ee Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stride-12-image.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stride-12-xlib-fallback.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/stride-12-xlib-fallback.rgb24.ref.png new file mode 100644 index 0000000000..44284566ee Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stride-12-xlib-fallback.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stride-12-xlib-window.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/stride-12-xlib-window.rgb24.ref.png new file mode 100644 index 0000000000..44284566ee Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stride-12-xlib-window.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stride-12-xlib.ref.png b/local/recipes/libs/cairo/source/test/reference/stride-12-xlib.ref.png new file mode 100644 index 0000000000..44284566ee Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stride-12-xlib.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-clipped.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-clipped.ps.ref.png new file mode 100644 index 0000000000..a4b2aa6a17 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-clipped.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-clipped.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-clipped.quartz.ref.png new file mode 100644 index 0000000000..737488ce4e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-clipped.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-clipped.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-clipped.ref.png new file mode 100644 index 0000000000..fbe5788d50 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-clipped.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.base.argb32.ref.png new file mode 100644 index 0000000000..efe2faab3c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.base.rgb24.ref.png new file mode 100644 index 0000000000..efe2faab3c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.image16.ref.png new file mode 100644 index 0000000000..f5f551e232 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.mask.argb32.ref.png new file mode 100644 index 0000000000..3a77d3ea60 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.mask.rgb24.ref.png new file mode 100644 index 0000000000..3a77d3ea60 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.pdf.ref.png new file mode 100644 index 0000000000..dbc6415dc5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.ps2.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.ps2.ref.png new file mode 100644 index 0000000000..63c10645b9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.ps2.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.ps3.ref.png new file mode 100644 index 0000000000..63c10645b9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.ref.png new file mode 100644 index 0000000000..33ff0fad79 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.svg.ref.png new file mode 100644 index 0000000000..dbc6415dc5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.traps.argb32.ref.png new file mode 100644 index 0000000000..efe2faab3c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.traps.rgb24.ref.png new file mode 100644 index 0000000000..efe2faab3c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-ctm-caps.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-image.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-image.base.argb32.ref.png new file mode 100644 index 0000000000..75737d57c8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-image.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-image.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-image.base.rgb24.ref.png new file mode 100644 index 0000000000..75737d57c8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-image.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-image.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-image.image16.ref.png new file mode 100644 index 0000000000..cef40bda93 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-image.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-image.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-image.pdf.ref.png new file mode 100644 index 0000000000..e0babce9dc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-image.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-image.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-image.ps.ref.png new file mode 100644 index 0000000000..8f0a522696 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-image.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-image.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-image.quartz.ref.png new file mode 100644 index 0000000000..c6f0a3ba85 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-image.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-image.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-image.ref.png new file mode 100644 index 0000000000..f126afe2ce Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-image.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-image.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-image.traps.argb32.ref.png new file mode 100644 index 0000000000..75737d57c8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-image.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-image.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-image.traps.rgb24.ref.png new file mode 100644 index 0000000000..75737d57c8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-image.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-open-box.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-open-box.base.argb32.ref.png new file mode 100644 index 0000000000..b5f5bd5814 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-open-box.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-open-box.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-open-box.base.rgb24.ref.png new file mode 100644 index 0000000000..b5f5bd5814 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-open-box.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-open-box.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-open-box.ref.png new file mode 100644 index 0000000000..b5f5bd5814 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-open-box.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-pattern.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-pattern.base.argb32.ref.png new file mode 100644 index 0000000000..67bb031439 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-pattern.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-pattern.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-pattern.base.rgb24.ref.png new file mode 100644 index 0000000000..67bb031439 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-pattern.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-pattern.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-pattern.pdf.argb32.ref.png new file mode 100644 index 0000000000..788e1fcf3a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-pattern.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-pattern.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-pattern.pdf.rgb24.ref.png new file mode 100644 index 0000000000..788e1fcf3a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-pattern.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-pattern.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-pattern.quartz.ref.png new file mode 100644 index 0000000000..34619f4f73 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-pattern.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-pattern.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-pattern.ref.png new file mode 100644 index 0000000000..e299c58695 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-pattern.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-pattern.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-pattern.svg.ref.png new file mode 100644 index 0000000000..985f91f502 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-pattern.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-pattern.traps.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-pattern.traps.ref.png new file mode 100644 index 0000000000..67bb031439 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-pattern.traps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-xlib-fallback.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-xlib-fallback.rgb24.ref.png new file mode 100644 index 0000000000..75737d57c8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-xlib-fallback.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-xlib-window.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-xlib-window.rgb24.ref.png new file mode 100644 index 0000000000..75737d57c8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-xlib-window.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke-xlib.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke-xlib.ref.png new file mode 100644 index 0000000000..75737d57c8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke-xlib.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke.image.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke.image.argb32.ref.png new file mode 100644 index 0000000000..0dc701f2ef Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke.image.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/stroke.image.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/stroke.image.rgb24.ref.png new file mode 100644 index 0000000000..0dc701f2ef Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/stroke.image.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface-image-repeat.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface-image-repeat.base.argb32.ref.png new file mode 100644 index 0000000000..3dd6306a09 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface-image-repeat.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface-image-repeat.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface-image-repeat.base.rgb24.ref.png new file mode 100644 index 0000000000..3dd6306a09 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface-image-repeat.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface-image-repeat.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface-image-repeat.image16.ref.png new file mode 100644 index 0000000000..a62f210785 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface-image-repeat.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface-image-repeat.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface-image-repeat.ref.png new file mode 100644 index 0000000000..3dd6306a09 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface-image-repeat.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface-modify-child.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface-modify-child.base.argb32.ref.png new file mode 100644 index 0000000000..c37e22e36e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface-modify-child.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface-modify-child.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface-modify-child.base.rgb24.ref.png new file mode 100644 index 0000000000..c37e22e36e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface-modify-child.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface-modify-child.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface-modify-child.ref.png new file mode 100644 index 0000000000..c37e22e36e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface-modify-child.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface-modify-parent.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface-modify-parent.base.argb32.ref.png new file mode 100644 index 0000000000..c37e22e36e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface-modify-parent.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface-modify-parent.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface-modify-parent.base.rgb24.ref.png new file mode 100644 index 0000000000..c37e22e36e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface-modify-parent.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface-modify-parent.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface-modify-parent.ref.png new file mode 100644 index 0000000000..c37e22e36e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface-modify-parent.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface-outside-target.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface-outside-target.base.argb32.ref.png new file mode 100644 index 0000000000..337cdd8032 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface-outside-target.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface-outside-target.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface-outside-target.base.rgb24.ref.png new file mode 100644 index 0000000000..368936e5ca Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface-outside-target.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface-outside-target.quartz.argb32.xfail.png b/local/recipes/libs/cairo/source/test/reference/subsurface-outside-target.quartz.argb32.xfail.png new file mode 100644 index 0000000000..d052d04691 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface-outside-target.quartz.argb32.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface-outside-target.quartz.rgb24.xfail.png b/local/recipes/libs/cairo/source/test/reference/subsurface-outside-target.quartz.rgb24.xfail.png new file mode 100644 index 0000000000..adf486e38f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface-outside-target.quartz.rgb24.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface-outside-target.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface-outside-target.ref.png new file mode 100644 index 0000000000..337cdd8032 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface-outside-target.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface-pad.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface-pad.base.argb32.ref.png new file mode 100644 index 0000000000..eeb9f8f596 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface-pad.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface-pad.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface-pad.base.rgb24.ref.png new file mode 100644 index 0000000000..eeb9f8f596 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface-pad.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface-pad.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/subsurface-pad.quartz.xfail.png new file mode 100644 index 0000000000..c37e22e36e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface-pad.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface-pad.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface-pad.ref.png new file mode 100644 index 0000000000..eeb9f8f596 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface-pad.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface-reflect.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface-reflect.base.argb32.ref.png new file mode 100644 index 0000000000..55643f4482 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface-reflect.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface-reflect.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface-reflect.base.rgb24.ref.png new file mode 100644 index 0000000000..55643f4482 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface-reflect.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface-reflect.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface-reflect.ref.png new file mode 100644 index 0000000000..55643f4482 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface-reflect.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface-repeat.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface-repeat.base.argb32.ref.png new file mode 100644 index 0000000000..c37e22e36e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface-repeat.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface-repeat.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface-repeat.base.rgb24.ref.png new file mode 100644 index 0000000000..c37e22e36e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface-repeat.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface-repeat.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface-repeat.ref.png new file mode 100644 index 0000000000..c37e22e36e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface-repeat.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface-scale.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface-scale.base.argb32.ref.png new file mode 100644 index 0000000000..3b70c2fb43 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface-scale.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface-scale.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface-scale.base.rgb24.ref.png new file mode 100644 index 0000000000..3b70c2fb43 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface-scale.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface-scale.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface-scale.quartz.ref.png new file mode 100644 index 0000000000..38a0470627 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface-scale.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface-scale.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface-scale.ref.png new file mode 100644 index 0000000000..69bb0fb9a0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface-scale.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface-scale.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface-scale.traps.argb32.ref.png new file mode 100644 index 0000000000..3b70c2fb43 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface-scale.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface-scale.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface-scale.traps.rgb24.ref.png new file mode 100644 index 0000000000..3b70c2fb43 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface-scale.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface-similar-repeat.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface-similar-repeat.base.argb32.ref.png new file mode 100644 index 0000000000..c37e22e36e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface-similar-repeat.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface-similar-repeat.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface-similar-repeat.base.rgb24.ref.png new file mode 100644 index 0000000000..c37e22e36e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface-similar-repeat.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface-similar-repeat.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface-similar-repeat.ref.png new file mode 100644 index 0000000000..c37e22e36e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface-similar-repeat.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface.base.argb32.ref.png new file mode 100644 index 0000000000..d2035592e3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface.base.rgb24.ref.png new file mode 100644 index 0000000000..d2035592e3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface.image16.ref.png new file mode 100644 index 0000000000..ba9b7ed074 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface.ps.ref.png new file mode 100644 index 0000000000..51e19fcf72 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface.ref.png new file mode 100644 index 0000000000..feeb5dc8a7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface.traps.argb32.ref.png new file mode 100644 index 0000000000..d2035592e3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/subsurface.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/subsurface.traps.rgb24.ref.png new file mode 100644 index 0000000000..d2035592e3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/subsurface.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-big-scale-down.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-big-scale-down.base.argb32.ref.png new file mode 100644 index 0000000000..c050990773 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-big-scale-down.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-big-scale-down.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-big-scale-down.base.rgb24.ref.png new file mode 100644 index 0000000000..c050990773 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-big-scale-down.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-big-scale-down.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-big-scale-down.ps.ref.png new file mode 100644 index 0000000000..b9a5463ca4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-big-scale-down.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-big-scale-down.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-big-scale-down.ref.png new file mode 100644 index 0000000000..c050990773 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-big-scale-down.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-operator.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-operator.argb32.ref.png new file mode 100644 index 0000000000..67573715c3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-operator.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-operator.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-operator.base.argb32.ref.png new file mode 100644 index 0000000000..c274fcf716 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-operator.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-operator.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-operator.base.rgb24.ref.png new file mode 100644 index 0000000000..23e540df5a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-operator.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-operator.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-operator.image16.ref.png new file mode 100644 index 0000000000..507e49c836 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-operator.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-operator.pdf.argb32.xfail.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-operator.pdf.argb32.xfail.png new file mode 100644 index 0000000000..371d084742 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-operator.pdf.argb32.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-operator.pdf.rgb24.xfail.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-operator.pdf.rgb24.xfail.png new file mode 100644 index 0000000000..a2da18d222 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-operator.pdf.rgb24.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-operator.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-operator.quartz.argb32.ref.png new file mode 100644 index 0000000000..e2a411682e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-operator.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-operator.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-operator.quartz.rgb24.ref.png new file mode 100644 index 0000000000..02eec1c85f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-operator.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-operator.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-operator.rgb24.ref.png new file mode 100644 index 0000000000..aee0959c25 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-operator.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-operator.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-operator.traps.argb32.ref.png new file mode 100644 index 0000000000..c274fcf716 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-operator.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-operator.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-operator.traps.rgb24.ref.png new file mode 100644 index 0000000000..23e540df5a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-operator.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-none.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-none.base.argb32.ref.png new file mode 100644 index 0000000000..9df14cc5c3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-none.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-none.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-none.base.rgb24.ref.png new file mode 100644 index 0000000000..9df14cc5c3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-none.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-none.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-none.ps.ref.png new file mode 100644 index 0000000000..d3f90ab1a3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-none.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-none.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-none.ref.png new file mode 100644 index 0000000000..9df14cc5c3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-none.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-pad.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-pad.base.argb32.ref.png new file mode 100644 index 0000000000..2ee9419070 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-pad.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-pad.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-pad.base.rgb24.ref.png new file mode 100644 index 0000000000..2ee9419070 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-pad.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-pad.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-pad.quartz.xfail.png new file mode 100644 index 0000000000..c5cff0fe36 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-pad.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-pad.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-pad.ref.png new file mode 100644 index 0000000000..2ee9419070 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-pad.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-reflect.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-reflect.base.argb32.ref.png new file mode 100644 index 0000000000..f2e93a7dd3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-reflect.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-reflect.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-reflect.base.rgb24.ref.png new file mode 100644 index 0000000000..f2e93a7dd3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-reflect.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-reflect.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-reflect.ref.png new file mode 100644 index 0000000000..f2e93a7dd3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-reflect.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-repeat.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-repeat.base.argb32.ref.png new file mode 100644 index 0000000000..c5cff0fe36 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-repeat.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-repeat.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-repeat.base.rgb24.ref.png new file mode 100644 index 0000000000..c5cff0fe36 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-repeat.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-repeat.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-repeat.ref.png new file mode 100644 index 0000000000..c5cff0fe36 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down-extend-repeat.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down.base.argb32.ref.png new file mode 100644 index 0000000000..8bb58a2a1e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down.base.rgb24.ref.png new file mode 100644 index 0000000000..8bb58a2a1e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down.image16.ref.png new file mode 100644 index 0000000000..8be8fb0e4e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down.pdf.ref.png new file mode 100644 index 0000000000..c574f30938 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down.ps.ref.png new file mode 100644 index 0000000000..419f5f84ed Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down.quartz.ref.png new file mode 100644 index 0000000000..8306a03a04 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down.ref.png new file mode 100644 index 0000000000..239a6fd6c9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down.svg.ref.png new file mode 100644 index 0000000000..fd82dc53c7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-down.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-up.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-up.base.argb32.ref.png new file mode 100644 index 0000000000..e8d84e2b48 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-up.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-up.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-up.base.rgb24.ref.png new file mode 100644 index 0000000000..e8d84e2b48 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-up.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-up.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-up.image16.ref.png new file mode 100644 index 0000000000..5207bd3bc5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-up.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-up.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-up.pdf.ref.png new file mode 100644 index 0000000000..fa04bcfcc8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-up.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-up.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-up.ps.ref.png new file mode 100644 index 0000000000..b70ecb1900 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-up.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-up.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-up.quartz.ref.png new file mode 100644 index 0000000000..ed52ee80a0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-up.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-up.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-up.ref.png new file mode 100644 index 0000000000..e8d84e2b48 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern-scale-up.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern.base.argb32.ref.png new file mode 100644 index 0000000000..079ebfba13 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern.base.rgb24.ref.png new file mode 100644 index 0000000000..079ebfba13 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern.image16.ref.png new file mode 100644 index 0000000000..909009702b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern.pdf.ref.png new file mode 100644 index 0000000000..42c42df491 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern.ps.ref.png new file mode 100644 index 0000000000..02fbde847e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern.quartz.xfail.png new file mode 100644 index 0000000000..42938f026d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/surface-pattern.ref.png b/local/recipes/libs/cairo/source/test/reference/surface-pattern.ref.png new file mode 100644 index 0000000000..079ebfba13 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/surface-pattern.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-gray.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-gray.base.argb32.ref.png new file mode 100644 index 0000000000..06b805eaae Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-gray.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-gray.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-gray.base.rgb24.ref.png new file mode 100644 index 0000000000..06b805eaae Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-gray.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-gray.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-gray.image16.ref.png new file mode 100644 index 0000000000..c86dbae5d8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-gray.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-gray.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-gray.quartz.ref.png new file mode 100644 index 0000000000..36ffebb074 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-gray.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-gray.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-gray.ref.png new file mode 100644 index 0000000000..06b805eaae Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-gray.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-none.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-none.base.argb32.ref.png new file mode 100644 index 0000000000..86c09cd36b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-none.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-none.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-none.base.rgb24.ref.png new file mode 100644 index 0000000000..86c09cd36b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-none.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-none.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-none.quartz.ref.png new file mode 100644 index 0000000000..872b21d643 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-none.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-none.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-none.ref.png new file mode 100644 index 0000000000..bdd77bd56c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-none.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-bgr.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-bgr.base.argb32.ref.png new file mode 100644 index 0000000000..f8d5130af7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-bgr.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-bgr.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-bgr.base.rgb24.ref.png new file mode 100644 index 0000000000..f8d5130af7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-bgr.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-bgr.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-bgr.image16.ref.png new file mode 100644 index 0000000000..5a4e193b74 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-bgr.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-bgr.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-bgr.mask.argb32.ref.png new file mode 100644 index 0000000000..f8d5130af7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-bgr.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-bgr.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-bgr.mask.rgb24.ref.png new file mode 100644 index 0000000000..f8d5130af7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-bgr.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-bgr.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-bgr.quartz.xfail.png new file mode 100644 index 0000000000..83cf7d4bf8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-bgr.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-bgr.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-bgr.ref.png new file mode 100644 index 0000000000..57ac634995 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-bgr.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-bgr.traps.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-bgr.traps.ref.png new file mode 100644 index 0000000000..a221472dfa Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-bgr.traps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-rgb.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-rgb.base.argb32.ref.png new file mode 100644 index 0000000000..f8d5130af7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-rgb.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-rgb.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-rgb.base.rgb24.ref.png new file mode 100644 index 0000000000..f8d5130af7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-rgb.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-rgb.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-rgb.image16.ref.png new file mode 100644 index 0000000000..cf049b961b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-rgb.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-rgb.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-rgb.mask.argb32.ref.png new file mode 100644 index 0000000000..f8d5130af7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-rgb.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-rgb.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-rgb.mask.rgb24.ref.png new file mode 100644 index 0000000000..f8d5130af7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-rgb.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-rgb.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-rgb.quartz.ref.png new file mode 100644 index 0000000000..83cf7d4bf8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-rgb.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-rgb.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-rgb.ref.png new file mode 100644 index 0000000000..ae7e63e4dd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-rgb.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-rgb.traps.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-rgb.traps.ref.png new file mode 100644 index 0000000000..af5e0aef5e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-rgb.traps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vbgr.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vbgr.base.argb32.ref.png new file mode 100644 index 0000000000..9fd35ea2cd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vbgr.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vbgr.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vbgr.base.rgb24.ref.png new file mode 100644 index 0000000000..9fd35ea2cd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vbgr.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vbgr.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vbgr.image16.ref.png new file mode 100644 index 0000000000..6ef721a7d3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vbgr.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vbgr.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vbgr.mask.argb32.ref.png new file mode 100644 index 0000000000..9fd35ea2cd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vbgr.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vbgr.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vbgr.mask.rgb24.ref.png new file mode 100644 index 0000000000..9fd35ea2cd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vbgr.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vbgr.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vbgr.quartz.xfail.png new file mode 100644 index 0000000000..83cf7d4bf8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vbgr.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vbgr.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vbgr.ref.png new file mode 100644 index 0000000000..3f33ef989e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vbgr.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vbgr.traps.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vbgr.traps.ref.png new file mode 100644 index 0000000000..905579b661 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vbgr.traps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vrgb.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vrgb.base.argb32.ref.png new file mode 100644 index 0000000000..9fd35ea2cd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vrgb.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vrgb.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vrgb.base.rgb24.ref.png new file mode 100644 index 0000000000..9fd35ea2cd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vrgb.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vrgb.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vrgb.image16.ref.png new file mode 100644 index 0000000000..cb3586b95e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vrgb.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vrgb.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vrgb.mask.argb32.ref.png new file mode 100644 index 0000000000..9fd35ea2cd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vrgb.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vrgb.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vrgb.mask.rgb24.ref.png new file mode 100644 index 0000000000..9fd35ea2cd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vrgb.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vrgb.quartz.xfail.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vrgb.quartz.xfail.png new file mode 100644 index 0000000000..83cf7d4bf8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vrgb.quartz.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vrgb.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vrgb.ref.png new file mode 100644 index 0000000000..ffd137985e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vrgb.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vrgb.traps.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vrgb.traps.ref.png new file mode 100644 index 0000000000..f7c5befa92 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel-vrgb.traps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel.base.argb32.ref.png new file mode 100644 index 0000000000..f8d5130af7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel.base.argb32.xfail.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel.base.argb32.xfail.png new file mode 100644 index 0000000000..4a6bde49ac Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel.base.argb32.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel.base.rgb24.ref.png new file mode 100644 index 0000000000..f8d5130af7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel.base.rgb24.xfail.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel.base.rgb24.xfail.png new file mode 100644 index 0000000000..4a6bde49ac Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel.base.rgb24.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel.image16.ref.png new file mode 100644 index 0000000000..81fad89d09 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel.mask.argb32.ref.png new file mode 100644 index 0000000000..f8d5130af7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel.mask.rgb24.ref.png new file mode 100644 index 0000000000..f8d5130af7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel.quartz.ref.png new file mode 100644 index 0000000000..83cf7d4bf8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel.ref.png new file mode 100644 index 0000000000..ae7e63e4dd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel.traps.ref.png b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel.traps.ref.png new file mode 100644 index 0000000000..af5e0aef5e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-antialias-subpixel.traps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-glyph-range.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/text-glyph-range.base.argb32.ref.png new file mode 100644 index 0000000000..326869923a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-glyph-range.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-glyph-range.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/text-glyph-range.base.rgb24.ref.png new file mode 100644 index 0000000000..326869923a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-glyph-range.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-glyph-range.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/text-glyph-range.image16.ref.png new file mode 100644 index 0000000000..51daa1688e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-glyph-range.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-glyph-range.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/text-glyph-range.pdf.ref.png new file mode 100644 index 0000000000..06588e9451 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-glyph-range.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-glyph-range.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/text-glyph-range.ps.ref.png new file mode 100644 index 0000000000..6054722548 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-glyph-range.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-glyph-range.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/text-glyph-range.quartz.ref.png new file mode 100644 index 0000000000..31d2a94117 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-glyph-range.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-glyph-range.ref.png b/local/recipes/libs/cairo/source/test/reference/text-glyph-range.ref.png new file mode 100644 index 0000000000..648fef5b77 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-glyph-range.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-glyph-range.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/text-glyph-range.svg.ref.png new file mode 100644 index 0000000000..e194be7e56 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-glyph-range.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-glyph-range.traps.ref.png b/local/recipes/libs/cairo/source/test/reference/text-glyph-range.traps.ref.png new file mode 100644 index 0000000000..326869923a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-glyph-range.traps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-pattern.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/text-pattern.base.argb32.ref.png new file mode 100644 index 0000000000..79f18e4e19 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-pattern.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-pattern.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/text-pattern.base.rgb24.ref.png new file mode 100644 index 0000000000..b073b98312 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-pattern.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-pattern.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/text-pattern.pdf.argb32.ref.png new file mode 100644 index 0000000000..f8abd9ea75 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-pattern.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-pattern.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/text-pattern.pdf.rgb24.ref.png new file mode 100644 index 0000000000..679fbd008a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-pattern.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-pattern.ps2.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/text-pattern.ps2.argb32.ref.png new file mode 100644 index 0000000000..bdea146f20 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-pattern.ps2.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-pattern.ps2.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/text-pattern.ps2.rgb24.ref.png new file mode 100644 index 0000000000..bdea146f20 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-pattern.ps2.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-pattern.ps3.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/text-pattern.ps3.argb32.ref.png new file mode 100644 index 0000000000..98021a54d9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-pattern.ps3.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-pattern.ps3.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/text-pattern.ps3.rgb24.ref.png new file mode 100644 index 0000000000..afcaba822f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-pattern.ps3.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-pattern.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/text-pattern.quartz.argb32.ref.png new file mode 100644 index 0000000000..b3f869b508 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-pattern.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-pattern.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/text-pattern.quartz.rgb24.ref.png new file mode 100644 index 0000000000..bb50f4dff4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-pattern.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-pattern.ref.png b/local/recipes/libs/cairo/source/test/reference/text-pattern.ref.png new file mode 100644 index 0000000000..c5a925c957 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-pattern.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-pattern.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/text-pattern.traps.argb32.ref.png new file mode 100644 index 0000000000..79f18e4e19 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-pattern.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-pattern.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/text-pattern.traps.rgb24.ref.png new file mode 100644 index 0000000000..b073b98312 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-pattern.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-rotate.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/text-rotate.base.argb32.ref.png new file mode 100644 index 0000000000..ff3fe847c2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-rotate.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-rotate.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/text-rotate.base.rgb24.ref.png new file mode 100644 index 0000000000..ff3fe847c2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-rotate.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-rotate.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/text-rotate.image16.ref.png new file mode 100644 index 0000000000..fddd002c92 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-rotate.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-rotate.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/text-rotate.mask.argb32.ref.png new file mode 100644 index 0000000000..b455aab63c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-rotate.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-rotate.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/text-rotate.mask.rgb24.ref.png new file mode 100644 index 0000000000..b455aab63c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-rotate.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-rotate.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/text-rotate.pdf.ref.png new file mode 100644 index 0000000000..3b1c95e50f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-rotate.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-rotate.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/text-rotate.ps.ref.png new file mode 100644 index 0000000000..a0f8fbe377 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-rotate.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-rotate.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/text-rotate.quartz.ref.png new file mode 100644 index 0000000000..68e45afda9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-rotate.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-rotate.ref.png b/local/recipes/libs/cairo/source/test/reference/text-rotate.ref.png new file mode 100644 index 0000000000..ac8b68166e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-rotate.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-rotate.traps.ref.png b/local/recipes/libs/cairo/source/test/reference/text-rotate.traps.ref.png new file mode 100644 index 0000000000..ff3fe847c2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-rotate.traps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-rotate.xlib-fallback.ref.png b/local/recipes/libs/cairo/source/test/reference/text-rotate.xlib-fallback.ref.png new file mode 100644 index 0000000000..ce063303a7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-rotate.xlib-fallback.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-transform.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/text-transform.base.argb32.ref.png new file mode 100644 index 0000000000..4603bc528d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-transform.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-transform.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/text-transform.base.rgb24.ref.png new file mode 100644 index 0000000000..4603bc528d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-transform.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-transform.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/text-transform.image16.ref.png new file mode 100644 index 0000000000..59caca8002 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-transform.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-transform.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/text-transform.pdf.argb32.ref.png new file mode 100644 index 0000000000..441c1cd53c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-transform.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-transform.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/text-transform.pdf.rgb24.ref.png new file mode 100644 index 0000000000..441c1cd53c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-transform.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-transform.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/text-transform.ps.ref.png new file mode 100644 index 0000000000..c5fdb304cf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-transform.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-transform.ref.png b/local/recipes/libs/cairo/source/test/reference/text-transform.ref.png new file mode 100644 index 0000000000..6f36b9d41a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-transform.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-transform.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/text-transform.svg.ref.png new file mode 100644 index 0000000000..684e93b92f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-transform.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-unhinted-metrics.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/text-unhinted-metrics.pdf.ref.png new file mode 100644 index 0000000000..ac8952175b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-unhinted-metrics.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-unhinted-metrics.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/text-unhinted-metrics.ps.ref.png new file mode 100644 index 0000000000..d34ea3478f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-unhinted-metrics.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-unhinted-metrics.ref.png b/local/recipes/libs/cairo/source/test/reference/text-unhinted-metrics.ref.png new file mode 100644 index 0000000000..df3467fd47 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-unhinted-metrics.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-unhinted-metrics.xcb-fallback.ref.png b/local/recipes/libs/cairo/source/test/reference/text-unhinted-metrics.xcb-fallback.ref.png new file mode 100644 index 0000000000..2b7646d327 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-unhinted-metrics.xcb-fallback.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-unhinted-metrics.xcb-render-0_0.ref.png b/local/recipes/libs/cairo/source/test/reference/text-unhinted-metrics.xcb-render-0_0.ref.png new file mode 100644 index 0000000000..baf3f96ec1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-unhinted-metrics.xcb-render-0_0.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-unhinted-metrics.xcb-window&.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/text-unhinted-metrics.xcb-window&.rgb24.ref.png new file mode 100644 index 0000000000..baf3f96ec1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-unhinted-metrics.xcb-window&.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-unhinted-metrics.xcb-window.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/text-unhinted-metrics.xcb-window.rgb24.ref.png new file mode 100644 index 0000000000..baf3f96ec1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-unhinted-metrics.xcb-window.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/text-unhinted-metrics.xcb.ref.png b/local/recipes/libs/cairo/source/test/reference/text-unhinted-metrics.xcb.ref.png new file mode 100644 index 0000000000..706298de46 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/text-unhinted-metrics.xcb.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/thin-lines.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/thin-lines.pdf.ref.png new file mode 100644 index 0000000000..3d79c8ea26 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/thin-lines.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/thin-lines.ps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/thin-lines.ps.argb32.ref.png new file mode 100644 index 0000000000..48393116d6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/thin-lines.ps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/thin-lines.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/thin-lines.ps.rgb24.ref.png new file mode 100644 index 0000000000..97f6f213ea Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/thin-lines.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/thin-lines.ref.png b/local/recipes/libs/cairo/source/test/reference/thin-lines.ref.png new file mode 100644 index 0000000000..49e2a3fdb0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/thin-lines.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/tiger.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/tiger.base.argb32.ref.png new file mode 100644 index 0000000000..bc7f668e4a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/tiger.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/tiger.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/tiger.base.rgb24.ref.png new file mode 100644 index 0000000000..bc7f668e4a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/tiger.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/tiger.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/tiger.pdf.ref.png new file mode 100644 index 0000000000..cc641e2903 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/tiger.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/tiger.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/tiger.ps.ref.png new file mode 100644 index 0000000000..09729b2431 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/tiger.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/tiger.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/tiger.quartz.ref.png new file mode 100644 index 0000000000..490e40f9d5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/tiger.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/tiger.ref.png b/local/recipes/libs/cairo/source/test/reference/tiger.ref.png new file mode 100644 index 0000000000..58e0471191 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/tiger.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/tiger.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/tiger.svg.ref.png new file mode 100644 index 0000000000..5b9a5ad671 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/tiger.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/tiger.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/tiger.traps.argb32.ref.png new file mode 100644 index 0000000000..bc7f668e4a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/tiger.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/tiger.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/tiger.traps.rgb24.ref.png new file mode 100644 index 0000000000..bc7f668e4a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/tiger.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/tighten-bounds.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/tighten-bounds.argb32.ref.png new file mode 100644 index 0000000000..042038c6fb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/tighten-bounds.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/tighten-bounds.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/tighten-bounds.base.argb32.ref.png new file mode 100644 index 0000000000..dad3a7fc9c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/tighten-bounds.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/tighten-bounds.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/tighten-bounds.base.rgb24.ref.png new file mode 100644 index 0000000000..9d3a252625 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/tighten-bounds.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/tighten-bounds.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/tighten-bounds.pdf.ref.png new file mode 100644 index 0000000000..8511caeee8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/tighten-bounds.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/tighten-bounds.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/tighten-bounds.ps.ref.png new file mode 100644 index 0000000000..8511caeee8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/tighten-bounds.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/tighten-bounds.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/tighten-bounds.quartz.argb32.ref.png new file mode 100644 index 0000000000..dc4aacdd82 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/tighten-bounds.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/tighten-bounds.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/tighten-bounds.quartz.rgb24.ref.png new file mode 100644 index 0000000000..8d11e0b855 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/tighten-bounds.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/tighten-bounds.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/tighten-bounds.rgb24.ref.png new file mode 100644 index 0000000000..28158816b8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/tighten-bounds.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/tighten-bounds.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/tighten-bounds.traps.argb32.ref.png new file mode 100644 index 0000000000..291a841148 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/tighten-bounds.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/tighten-bounds.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/tighten-bounds.traps.rgb24.ref.png new file mode 100644 index 0000000000..f31c17c3d8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/tighten-bounds.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/transforms.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/transforms.base.argb32.ref.png new file mode 100644 index 0000000000..3ce9176498 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/transforms.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/transforms.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/transforms.base.rgb24.ref.png new file mode 100644 index 0000000000..3ce9176498 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/transforms.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/transforms.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/transforms.image16.ref.png new file mode 100644 index 0000000000..e9a1813a04 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/transforms.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/transforms.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/transforms.pdf.ref.png new file mode 100644 index 0000000000..d6bff0a02c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/transforms.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/transforms.ps2.ref.png b/local/recipes/libs/cairo/source/test/reference/transforms.ps2.ref.png new file mode 100644 index 0000000000..6d195aaf32 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/transforms.ps2.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/transforms.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/transforms.ps3.ref.png new file mode 100644 index 0000000000..6d195aaf32 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/transforms.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/transforms.ref.png b/local/recipes/libs/cairo/source/test/reference/transforms.ref.png new file mode 100644 index 0000000000..390bad482d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/transforms.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/transforms.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/transforms.svg.ref.png new file mode 100644 index 0000000000..d6bff0a02c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/transforms.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/transforms.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/transforms.traps.argb32.ref.png new file mode 100644 index 0000000000..3ce9176498 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/transforms.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/transforms.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/transforms.traps.rgb24.ref.png new file mode 100644 index 0000000000..3ce9176498 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/transforms.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/translate-show-surface.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/translate-show-surface.base.argb32.ref.png new file mode 100644 index 0000000000..0a145d918a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/translate-show-surface.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/translate-show-surface.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/translate-show-surface.base.rgb24.ref.png new file mode 100644 index 0000000000..0a145d918a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/translate-show-surface.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/translate-show-surface.ref.png b/local/recipes/libs/cairo/source/test/reference/translate-show-surface.ref.png new file mode 100644 index 0000000000..765adc4a48 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/translate-show-surface.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/trap-clip.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/trap-clip.argb32.ref.png new file mode 100644 index 0000000000..b929d94c1b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/trap-clip.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/trap-clip.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/trap-clip.base.argb32.ref.png new file mode 100644 index 0000000000..285934bc3d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/trap-clip.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/trap-clip.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/trap-clip.base.rgb24.ref.png new file mode 100644 index 0000000000..ed89be7546 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/trap-clip.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/trap-clip.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/trap-clip.image16.ref.png new file mode 100644 index 0000000000..e9ef2cf904 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/trap-clip.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/trap-clip.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/trap-clip.mask.argb32.ref.png new file mode 100644 index 0000000000..98cd0a2447 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/trap-clip.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/trap-clip.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/trap-clip.mask.rgb24.ref.png new file mode 100644 index 0000000000..c01315331a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/trap-clip.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/trap-clip.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/trap-clip.pdf.argb32.ref.png new file mode 100644 index 0000000000..fca20c459f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/trap-clip.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/trap-clip.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/trap-clip.pdf.rgb24.ref.png new file mode 100644 index 0000000000..fca20c459f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/trap-clip.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/trap-clip.ps2.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/trap-clip.ps2.argb32.ref.png new file mode 100644 index 0000000000..4db9f8e709 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/trap-clip.ps2.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/trap-clip.ps2.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/trap-clip.ps2.rgb24.ref.png new file mode 100644 index 0000000000..de309b9754 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/trap-clip.ps2.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/trap-clip.ps3.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/trap-clip.ps3.argb32.ref.png new file mode 100644 index 0000000000..17d74beb33 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/trap-clip.ps3.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/trap-clip.ps3.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/trap-clip.ps3.rgb24.ref.png new file mode 100644 index 0000000000..236b75c5bd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/trap-clip.ps3.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/trap-clip.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/trap-clip.quartz.argb32.ref.png new file mode 100644 index 0000000000..66a1e8afee Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/trap-clip.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/trap-clip.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/trap-clip.quartz.rgb24.ref.png new file mode 100644 index 0000000000..38e6d31df0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/trap-clip.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/trap-clip.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/trap-clip.rgb24.ref.png new file mode 100644 index 0000000000..2c06d01539 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/trap-clip.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/trap-clip.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/trap-clip.svg.ref.png new file mode 100644 index 0000000000..0bc8231bbf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/trap-clip.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/trap-clip.test-paginated.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/trap-clip.test-paginated.argb32.ref.png new file mode 100644 index 0000000000..7259edc493 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/trap-clip.test-paginated.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/trap-clip.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/trap-clip.traps.argb32.ref.png new file mode 100644 index 0000000000..170d3781f9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/trap-clip.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/trap-clip.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/trap-clip.traps.rgb24.ref.png new file mode 100644 index 0000000000..b1129b0334 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/trap-clip.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin-antialias-gray.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/twin-antialias-gray.base.argb32.ref.png new file mode 100644 index 0000000000..0692dea280 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin-antialias-gray.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin-antialias-gray.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/twin-antialias-gray.base.rgb24.ref.png new file mode 100644 index 0000000000..0692dea280 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin-antialias-gray.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin-antialias-gray.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/twin-antialias-gray.image16.ref.png new file mode 100644 index 0000000000..1fadcb125e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin-antialias-gray.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin-antialias-gray.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/twin-antialias-gray.mask.argb32.ref.png new file mode 100644 index 0000000000..6b091afd80 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin-antialias-gray.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin-antialias-gray.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/twin-antialias-gray.mask.rgb24.ref.png new file mode 100644 index 0000000000..6b091afd80 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin-antialias-gray.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin-antialias-gray.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/twin-antialias-gray.quartz.ref.png new file mode 100644 index 0000000000..8ce3980478 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin-antialias-gray.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin-antialias-gray.ref.png b/local/recipes/libs/cairo/source/test/reference/twin-antialias-gray.ref.png new file mode 100644 index 0000000000..602e00524d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin-antialias-gray.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin-antialias-gray.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/twin-antialias-gray.traps.argb32.ref.png new file mode 100644 index 0000000000..0692dea280 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin-antialias-gray.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin-antialias-gray.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/twin-antialias-gray.traps.rgb24.ref.png new file mode 100644 index 0000000000..0692dea280 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin-antialias-gray.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin-antialias-mixed.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/twin-antialias-mixed.base.argb32.ref.png new file mode 100644 index 0000000000..ba8180e118 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin-antialias-mixed.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin-antialias-mixed.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/twin-antialias-mixed.base.rgb24.ref.png new file mode 100644 index 0000000000..ba8180e118 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin-antialias-mixed.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin-antialias-mixed.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/twin-antialias-mixed.image16.ref.png new file mode 100644 index 0000000000..10c4980fc3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin-antialias-mixed.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin-antialias-mixed.ref.png b/local/recipes/libs/cairo/source/test/reference/twin-antialias-mixed.ref.png new file mode 100644 index 0000000000..28e85a3e66 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin-antialias-mixed.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin-antialias-mixed.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/twin-antialias-mixed.traps.argb32.ref.png new file mode 100644 index 0000000000..ba8180e118 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin-antialias-mixed.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin-antialias-mixed.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/twin-antialias-mixed.traps.rgb24.ref.png new file mode 100644 index 0000000000..ba8180e118 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin-antialias-mixed.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin-antialias-none.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/twin-antialias-none.base.argb32.ref.png new file mode 100644 index 0000000000..02cf333d7b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin-antialias-none.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin-antialias-none.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/twin-antialias-none.base.rgb24.ref.png new file mode 100644 index 0000000000..02cf333d7b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin-antialias-none.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin-antialias-none.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/twin-antialias-none.quartz.ref.png new file mode 100644 index 0000000000..8e5facf2ab Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin-antialias-none.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin-antialias-none.ref.png b/local/recipes/libs/cairo/source/test/reference/twin-antialias-none.ref.png new file mode 100644 index 0000000000..28ad3036d6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin-antialias-none.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin-antialias-none.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/twin-antialias-none.traps.argb32.ref.png new file mode 100644 index 0000000000..02cf333d7b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin-antialias-none.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin-antialias-none.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/twin-antialias-none.traps.rgb24.ref.png new file mode 100644 index 0000000000..02cf333d7b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin-antialias-none.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin-antialias-subpixel.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/twin-antialias-subpixel.base.argb32.ref.png new file mode 100644 index 0000000000..0692dea280 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin-antialias-subpixel.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin-antialias-subpixel.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/twin-antialias-subpixel.base.rgb24.ref.png new file mode 100644 index 0000000000..0692dea280 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin-antialias-subpixel.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin-antialias-subpixel.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/twin-antialias-subpixel.image16.ref.png new file mode 100644 index 0000000000..1fadcb125e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin-antialias-subpixel.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin-antialias-subpixel.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/twin-antialias-subpixel.mask.argb32.ref.png new file mode 100644 index 0000000000..6b091afd80 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin-antialias-subpixel.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin-antialias-subpixel.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/twin-antialias-subpixel.mask.rgb24.ref.png new file mode 100644 index 0000000000..6b091afd80 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin-antialias-subpixel.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin-antialias-subpixel.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/twin-antialias-subpixel.quartz.ref.png new file mode 100644 index 0000000000..8ce3980478 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin-antialias-subpixel.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin-antialias-subpixel.ref.png b/local/recipes/libs/cairo/source/test/reference/twin-antialias-subpixel.ref.png new file mode 100644 index 0000000000..602e00524d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin-antialias-subpixel.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin-antialias-subpixel.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/twin-antialias-subpixel.traps.argb32.ref.png new file mode 100644 index 0000000000..0692dea280 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin-antialias-subpixel.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin-antialias-subpixel.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/twin-antialias-subpixel.traps.rgb24.ref.png new file mode 100644 index 0000000000..0692dea280 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin-antialias-subpixel.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/twin.base.argb32.ref.png new file mode 100644 index 0000000000..0692dea280 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/twin.base.rgb24.ref.png new file mode 100644 index 0000000000..0692dea280 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/twin.image16.ref.png new file mode 100644 index 0000000000..1fadcb125e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/twin.mask.argb32.ref.png new file mode 100644 index 0000000000..6b091afd80 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/twin.mask.rgb24.ref.png new file mode 100644 index 0000000000..6b091afd80 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/twin.pdf.argb32.ref.png new file mode 100644 index 0000000000..f10ad5c718 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/twin.pdf.rgb24.ref.png new file mode 100644 index 0000000000..0964f5c141 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/twin.ps.ref.png new file mode 100644 index 0000000000..a92e4fb627 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/twin.quartz.ref.png new file mode 100644 index 0000000000..8ce3980478 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin.ref.png b/local/recipes/libs/cairo/source/test/reference/twin.ref.png new file mode 100644 index 0000000000..602e00524d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/twin.svg.ref.png new file mode 100644 index 0000000000..ce209c3300 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/twin.traps.argb32.ref.png new file mode 100644 index 0000000000..0692dea280 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/twin.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/twin.traps.rgb24.ref.png new file mode 100644 index 0000000000..0692dea280 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/twin.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/unaligned-box.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/unaligned-box.base.argb32.ref.png new file mode 100644 index 0000000000..48e23b8f80 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/unaligned-box.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/unaligned-box.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/unaligned-box.base.rgb24.ref.png new file mode 100644 index 0000000000..48e23b8f80 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/unaligned-box.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/unaligned-box.ref.png b/local/recipes/libs/cairo/source/test/reference/unaligned-box.ref.png new file mode 100644 index 0000000000..ec7c489963 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/unaligned-box.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/unaligned-box.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/unaligned-box.traps.argb32.ref.png new file mode 100644 index 0000000000..48e23b8f80 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/unaligned-box.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/unaligned-box.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/unaligned-box.traps.rgb24.ref.png new file mode 100644 index 0000000000..48e23b8f80 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/unaligned-box.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/unantialiased-shapes.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/unantialiased-shapes.base.argb32.ref.png new file mode 100644 index 0000000000..a55ba889b8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/unantialiased-shapes.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/unantialiased-shapes.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/unantialiased-shapes.base.rgb24.ref.png new file mode 100644 index 0000000000..a55ba889b8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/unantialiased-shapes.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/unantialiased-shapes.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/unantialiased-shapes.quartz.ref.png new file mode 100644 index 0000000000..349ece778a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/unantialiased-shapes.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/unantialiased-shapes.ref.png b/local/recipes/libs/cairo/source/test/reference/unantialiased-shapes.ref.png new file mode 100644 index 0000000000..d9f466e528 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/unantialiased-shapes.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/unantialiased-shapes.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/unantialiased-shapes.traps.argb32.ref.png new file mode 100644 index 0000000000..cb2ce3d959 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/unantialiased-shapes.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/unantialiased-shapes.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/unantialiased-shapes.traps.rgb24.ref.png new file mode 100644 index 0000000000..cb2ce3d959 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/unantialiased-shapes.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/unbounded-operator.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/unbounded-operator.argb32.ref.png new file mode 100644 index 0000000000..8dbeef0e85 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/unbounded-operator.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/unbounded-operator.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/unbounded-operator.base.argb32.ref.png new file mode 100644 index 0000000000..fe86a948ee Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/unbounded-operator.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/unbounded-operator.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/unbounded-operator.base.rgb24.ref.png new file mode 100644 index 0000000000..c8555af140 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/unbounded-operator.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/unbounded-operator.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/unbounded-operator.image16.ref.png new file mode 100644 index 0000000000..17dfb46df2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/unbounded-operator.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/unbounded-operator.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/unbounded-operator.mask.argb32.ref.png new file mode 100644 index 0000000000..08f43561b2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/unbounded-operator.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/unbounded-operator.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/unbounded-operator.mask.rgb24.ref.png new file mode 100644 index 0000000000..80d20dc570 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/unbounded-operator.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/unbounded-operator.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/unbounded-operator.pdf.argb32.ref.png new file mode 100644 index 0000000000..6e53024690 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/unbounded-operator.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/unbounded-operator.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/unbounded-operator.pdf.rgb24.ref.png new file mode 100644 index 0000000000..1a1f9d1a74 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/unbounded-operator.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/unbounded-operator.ps2.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/unbounded-operator.ps2.argb32.ref.png new file mode 100644 index 0000000000..4aa476de4f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/unbounded-operator.ps2.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/unbounded-operator.ps3.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/unbounded-operator.ps3.argb32.ref.png new file mode 100644 index 0000000000..4aa476de4f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/unbounded-operator.ps3.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/unbounded-operator.quartz.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/unbounded-operator.quartz.argb32.ref.png new file mode 100644 index 0000000000..b2e99165ef Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/unbounded-operator.quartz.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/unbounded-operator.quartz.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/unbounded-operator.quartz.rgb24.ref.png new file mode 100644 index 0000000000..ea41dc8924 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/unbounded-operator.quartz.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/unbounded-operator.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/unbounded-operator.rgb24.ref.png new file mode 100644 index 0000000000..825d2faa9f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/unbounded-operator.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/unbounded-operator.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/unbounded-operator.traps.argb32.ref.png new file mode 100644 index 0000000000..fe86a948ee Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/unbounded-operator.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/unbounded-operator.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/unbounded-operator.traps.rgb24.ref.png new file mode 100644 index 0000000000..c8555af140 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/unbounded-operator.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/unclosed-strokes.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/unclosed-strokes.base.argb32.ref.png new file mode 100644 index 0000000000..34cedbd8b9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/unclosed-strokes.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/unclosed-strokes.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/unclosed-strokes.base.rgb24.ref.png new file mode 100644 index 0000000000..34cedbd8b9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/unclosed-strokes.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/unclosed-strokes.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/unclosed-strokes.pdf.ref.png new file mode 100644 index 0000000000..17b161f542 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/unclosed-strokes.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/unclosed-strokes.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/unclosed-strokes.ps.ref.png new file mode 100644 index 0000000000..ee9324bd4b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/unclosed-strokes.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/unclosed-strokes.ref.png b/local/recipes/libs/cairo/source/test/reference/unclosed-strokes.ref.png new file mode 100644 index 0000000000..7649c0338f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/unclosed-strokes.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/unclosed-strokes.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/unclosed-strokes.svg.ref.png new file mode 100644 index 0000000000..17b161f542 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/unclosed-strokes.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/unclosed-strokes.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/unclosed-strokes.traps.argb32.ref.png new file mode 100644 index 0000000000..34cedbd8b9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/unclosed-strokes.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/unclosed-strokes.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/unclosed-strokes.traps.rgb24.ref.png new file mode 100644 index 0000000000..34cedbd8b9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/unclosed-strokes.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-color.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-color.image16.ref.png new file mode 100644 index 0000000000..b3721daf58 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-color.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-color.pdf.xfail.png b/local/recipes/libs/cairo/source/test/reference/user-font-color.pdf.xfail.png new file mode 100644 index 0000000000..e3aedeb1df Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-color.pdf.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-color.ps2.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-color.ps2.argb32.ref.png new file mode 100644 index 0000000000..59932e64e9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-color.ps2.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-color.ps2.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-color.ps2.rgb24.ref.png new file mode 100644 index 0000000000..71b25f6fa3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-color.ps2.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-color.ps3.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-color.ps3.argb32.ref.png new file mode 100644 index 0000000000..59932e64e9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-color.ps3.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-color.ps3.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-color.ps3.rgb24.ref.png new file mode 100644 index 0000000000..71b25f6fa3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-color.ps3.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-color.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-color.quartz.ref.png new file mode 100644 index 0000000000..b7c484647a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-color.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-color.recording.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-color.recording.ref.png new file mode 100644 index 0000000000..e6f9f389e8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-color.recording.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-color.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-color.ref.png new file mode 100644 index 0000000000..3986f10a71 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-color.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-color.script.xfail.png b/local/recipes/libs/cairo/source/test/reference/user-font-color.script.xfail.png new file mode 100644 index 0000000000..5d5cdafdbf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-color.script.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-color.xcb.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-color.xcb.ref.png new file mode 100644 index 0000000000..c3ec667b7d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-color.xcb.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-color.xlib.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-color.xlib.ref.png new file mode 100644 index 0000000000..c3ec667b7d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-color.xlib.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-mask.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-mask.base.argb32.ref.png new file mode 100644 index 0000000000..02a9a5eca1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-mask.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-mask.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-mask.base.rgb24.ref.png new file mode 100644 index 0000000000..02a9a5eca1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-mask.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-mask.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-mask.image16.ref.png new file mode 100644 index 0000000000..9069fc1e46 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-mask.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-mask.pdf.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-mask.pdf.ref.png new file mode 100644 index 0000000000..ebf1485878 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-mask.pdf.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-mask.ps2.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-mask.ps2.ref.png new file mode 100644 index 0000000000..ebf1485878 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-mask.ps2.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-mask.ps3.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-mask.ps3.ref.png new file mode 100644 index 0000000000..ebf1485878 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-mask.ps3.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-mask.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-mask.quartz.ref.png new file mode 100644 index 0000000000..1ef2160cd1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-mask.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-mask.recording.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-mask.recording.ref.png new file mode 100644 index 0000000000..1ef2160cd1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-mask.recording.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-mask.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-mask.ref.png new file mode 100644 index 0000000000..02a9a5eca1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-mask.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-mask.script.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-mask.script.ref.png new file mode 100644 index 0000000000..1ef2160cd1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-mask.script.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-mask.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-mask.svg.ref.png new file mode 100644 index 0000000000..714d1dbc95 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-mask.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-mask.xcb-render-0_0.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-mask.xcb-render-0_0.ref.png new file mode 100644 index 0000000000..1ef2160cd1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-mask.xcb-render-0_0.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-mask.xcb.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-mask.xcb.ref.png new file mode 100644 index 0000000000..1ef2160cd1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-mask.xcb.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-mask.xlib-render-0_0.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-mask.xlib-render-0_0.ref.png new file mode 100644 index 0000000000..1ef2160cd1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-mask.xlib-render-0_0.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-mask.xlib.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-mask.xlib.ref.png new file mode 100644 index 0000000000..1ef2160cd1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-mask.xlib.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-proxy.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-proxy.base.argb32.ref.png new file mode 100644 index 0000000000..094938c6e7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-proxy.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-proxy.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-proxy.base.rgb24.ref.png new file mode 100644 index 0000000000..094938c6e7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-proxy.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-proxy.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-proxy.image16.ref.png new file mode 100644 index 0000000000..5b44351bd4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-proxy.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-proxy.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-proxy.pdf.argb32.ref.png new file mode 100644 index 0000000000..d7bba13e42 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-proxy.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-proxy.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-proxy.pdf.rgb24.ref.png new file mode 100644 index 0000000000..d7bba13e42 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-proxy.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-proxy.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-proxy.ps.ref.png new file mode 100644 index 0000000000..76ba45be15 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-proxy.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-proxy.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-proxy.quartz.ref.png new file mode 100644 index 0000000000..710f58a920 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-proxy.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-proxy.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-proxy.ref.png new file mode 100644 index 0000000000..65014847ad Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-proxy.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-proxy.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-proxy.svg.ref.png new file mode 100644 index 0000000000..7a083e6d8b Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-proxy.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-proxy.traps.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-proxy.traps.ref.png new file mode 100644 index 0000000000..094938c6e7 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-proxy.traps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-rescale.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-rescale.base.argb32.ref.png new file mode 100644 index 0000000000..0939060146 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-rescale.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-rescale.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-rescale.base.rgb24.ref.png new file mode 100644 index 0000000000..0939060146 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-rescale.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-rescale.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-rescale.image16.ref.png new file mode 100644 index 0000000000..a6be0d3d33 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-rescale.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-rescale.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-rescale.pdf.rgb24.ref.png new file mode 100644 index 0000000000..542e3370dc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-rescale.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-rescale.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-rescale.ps.ref.png new file mode 100644 index 0000000000..42e816e9c4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-rescale.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-rescale.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-rescale.quartz.ref.png new file mode 100644 index 0000000000..5fa2984ca3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-rescale.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-rescale.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-rescale.ref.png new file mode 100644 index 0000000000..f2d71680fb Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-rescale.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-rescale.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-rescale.svg.ref.png new file mode 100644 index 0000000000..048c6e907a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-rescale.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-rescale.traps.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-rescale.traps.ref.png new file mode 100644 index 0000000000..0939060146 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-rescale.traps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-subpixel.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-subpixel.ref.png new file mode 100644 index 0000000000..7574c97b7a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-subpixel.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-subpixel.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-subpixel.svg.ref.png new file mode 100644 index 0000000000..1f43472428 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-subpixel.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-subpixel.xcb-render-0_0.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-subpixel.xcb-render-0_0.ref.png new file mode 100644 index 0000000000..bf8d4ff4c6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-subpixel.xcb-render-0_0.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-subpixel.xcb-window&.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-subpixel.xcb-window&.rgb24.ref.png new file mode 100644 index 0000000000..bf8d4ff4c6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-subpixel.xcb-window&.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-subpixel.xcb-window.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-subpixel.xcb-window.rgb24.ref.png new file mode 100644 index 0000000000..bf8d4ff4c6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-subpixel.xcb-window.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-subpixel.xcb.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font-subpixel.xcb.ref.png new file mode 100644 index 0000000000..bf8d4ff4c6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-subpixel.xcb.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font-subpixel.xfail.png b/local/recipes/libs/cairo/source/test/reference/user-font-subpixel.xfail.png new file mode 100644 index 0000000000..3647b4b8c3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font-subpixel.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font.pdf.xfail.png b/local/recipes/libs/cairo/source/test/reference/user-font.pdf.xfail.png new file mode 100644 index 0000000000..b5145aed6a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font.pdf.xfail.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font.quartz.ref.png new file mode 100644 index 0000000000..665801d374 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font.recording.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font.recording.ref.png new file mode 100644 index 0000000000..c1cb2bbc35 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font.recording.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font.ref.png new file mode 100644 index 0000000000..5a6af54901 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font.svg.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font.svg.argb32.ref.png new file mode 100644 index 0000000000..e14924e9a3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font.svg.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/user-font.svg.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/user-font.svg.rgb24.ref.png new file mode 100644 index 0000000000..c534efcfe6 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/user-font.svg.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/white-in-noop.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/white-in-noop.base.argb32.ref.png new file mode 100644 index 0000000000..f42bb8d5f3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/white-in-noop.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/white-in-noop.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/white-in-noop.base.rgb24.ref.png new file mode 100644 index 0000000000..f42bb8d5f3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/white-in-noop.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/white-in-noop.ref.png b/local/recipes/libs/cairo/source/test/reference/white-in-noop.ref.png new file mode 100644 index 0000000000..f42bb8d5f3 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/white-in-noop.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map-fill.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map-fill.base.argb32.ref.png new file mode 100644 index 0000000000..926c1a8ee4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map-fill.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map-fill.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map-fill.base.rgb24.ref.png new file mode 100644 index 0000000000..926c1a8ee4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map-fill.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map-fill.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map-fill.image16.ref.png new file mode 100644 index 0000000000..c97cb57665 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map-fill.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map-fill.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map-fill.pdf.argb32.ref.png new file mode 100644 index 0000000000..cd828fd7c1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map-fill.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map-fill.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map-fill.pdf.rgb24.ref.png new file mode 100644 index 0000000000..cd828fd7c1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map-fill.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map-fill.ps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map-fill.ps.argb32.ref.png new file mode 100644 index 0000000000..86f323a29a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map-fill.ps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map-fill.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map-fill.ps.rgb24.ref.png new file mode 100644 index 0000000000..86f323a29a Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map-fill.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map-fill.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map-fill.quartz.ref.png new file mode 100644 index 0000000000..af0770a158 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map-fill.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map-fill.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map-fill.ref.png new file mode 100644 index 0000000000..23cec50466 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map-fill.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map-fill.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map-fill.svg.ref.png new file mode 100644 index 0000000000..a29e712152 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map-fill.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map-fill.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map-fill.traps.argb32.ref.png new file mode 100644 index 0000000000..926c1a8ee4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map-fill.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map-fill.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map-fill.traps.rgb24.ref.png new file mode 100644 index 0000000000..926c1a8ee4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map-fill.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map-stroke.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map-stroke.base.argb32.ref.png new file mode 100644 index 0000000000..d00c9450ed Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map-stroke.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map-stroke.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map-stroke.base.rgb24.ref.png new file mode 100644 index 0000000000..d00c9450ed Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map-stroke.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map-stroke.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map-stroke.image16.ref.png new file mode 100644 index 0000000000..771ff0b19c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map-stroke.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map-stroke.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map-stroke.mask.argb32.ref.png new file mode 100644 index 0000000000..ec0d5021bc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map-stroke.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map-stroke.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map-stroke.mask.rgb24.ref.png new file mode 100644 index 0000000000..ec0d5021bc Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map-stroke.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map-stroke.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map-stroke.pdf.argb32.ref.png new file mode 100644 index 0000000000..05ac7e30fd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map-stroke.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map-stroke.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map-stroke.pdf.rgb24.ref.png new file mode 100644 index 0000000000..05ac7e30fd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map-stroke.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map-stroke.ps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map-stroke.ps.argb32.ref.png new file mode 100644 index 0000000000..f846294d92 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map-stroke.ps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map-stroke.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map-stroke.ps.rgb24.ref.png new file mode 100644 index 0000000000..f846294d92 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map-stroke.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map-stroke.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map-stroke.quartz.ref.png new file mode 100644 index 0000000000..9be5de8bf9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map-stroke.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map-stroke.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map-stroke.ref.png new file mode 100644 index 0000000000..5c6e7d52bf Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map-stroke.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map-stroke.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map-stroke.svg.ref.png new file mode 100644 index 0000000000..dc4190d3d4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map-stroke.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map-stroke.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map-stroke.traps.argb32.ref.png new file mode 100644 index 0000000000..d00c9450ed Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map-stroke.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map-stroke.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map-stroke.traps.rgb24.ref.png new file mode 100644 index 0000000000..d00c9450ed Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map-stroke.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map.base.argb32.ref.png new file mode 100644 index 0000000000..6bae50d2b0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map.base.rgb24.ref.png new file mode 100644 index 0000000000..6bae50d2b0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map.image16.ref.png new file mode 100644 index 0000000000..ea7ae8a9ab Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map.mask.argb32.ref.png new file mode 100644 index 0000000000..218a303ac4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map.mask.rgb24.ref.png new file mode 100644 index 0000000000..218a303ac4 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map.pdf.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map.pdf.argb32.ref.png new file mode 100644 index 0000000000..3f7df8a9ed Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map.pdf.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map.pdf.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map.pdf.rgb24.ref.png new file mode 100644 index 0000000000..3f7df8a9ed Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map.pdf.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map.ps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map.ps.argb32.ref.png new file mode 100644 index 0000000000..c12220d221 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map.ps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map.ps.rgb24.ref.png new file mode 100644 index 0000000000..c12220d221 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map.quartz.ref.png new file mode 100644 index 0000000000..efc92f0b9f Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map.ref.png new file mode 100644 index 0000000000..12743675c2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map.svg.ref.png new file mode 100644 index 0000000000..acf8184765 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map.traps.argb32.ref.png new file mode 100644 index 0000000000..6bae50d2b0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/world-map.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/world-map.traps.rgb24.ref.png new file mode 100644 index 0000000000..6bae50d2b0 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/world-map.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xcb-huge-image-shm.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/xcb-huge-image-shm.base.argb32.ref.png new file mode 100644 index 0000000000..a0b24c8aac Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xcb-huge-image-shm.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xcb-huge-image-shm.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/xcb-huge-image-shm.base.rgb24.ref.png new file mode 100644 index 0000000000..a0b24c8aac Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xcb-huge-image-shm.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xcb-huge-image-shm.ref.png b/local/recipes/libs/cairo/source/test/reference/xcb-huge-image-shm.ref.png new file mode 100644 index 0000000000..5c274f8249 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xcb-huge-image-shm.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xcb-huge-subimage.ref.png b/local/recipes/libs/cairo/source/test/reference/xcb-huge-subimage.ref.png new file mode 100644 index 0000000000..5c274f8249 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xcb-huge-subimage.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xcb-snapshot-assert.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/xcb-snapshot-assert.base.argb32.ref.png new file mode 100644 index 0000000000..850ce59be1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xcb-snapshot-assert.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xcb-snapshot-assert.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/xcb-snapshot-assert.base.rgb24.ref.png new file mode 100644 index 0000000000..850ce59be1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xcb-snapshot-assert.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xcb-snapshot-assert.ref.png b/local/recipes/libs/cairo/source/test/reference/xcb-snapshot-assert.ref.png new file mode 100644 index 0000000000..850ce59be1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xcb-snapshot-assert.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xcb-stress-cache.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/xcb-stress-cache.base.argb32.ref.png new file mode 100644 index 0000000000..850ce59be1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xcb-stress-cache.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xcb-stress-cache.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/xcb-stress-cache.base.rgb24.ref.png new file mode 100644 index 0000000000..850ce59be1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xcb-stress-cache.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xcb-stress-cache.ref.png b/local/recipes/libs/cairo/source/test/reference/xcb-stress-cache.ref.png new file mode 100644 index 0000000000..850ce59be1 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xcb-stress-cache.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xcb-surface-source.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/xcb-surface-source.base.argb32.ref.png new file mode 100644 index 0000000000..018297208e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xcb-surface-source.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xcb-surface-source.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/xcb-surface-source.base.rgb24.ref.png new file mode 100644 index 0000000000..0d68a82cc2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xcb-surface-source.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xcb-surface-source.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/xcb-surface-source.image16.ref.png new file mode 100644 index 0000000000..2a7460e284 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xcb-surface-source.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xcb-surface-source.ps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/xcb-surface-source.ps.argb32.ref.png new file mode 100644 index 0000000000..910f895db9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xcb-surface-source.ps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xcb-surface-source.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/xcb-surface-source.ps.rgb24.ref.png new file mode 100644 index 0000000000..636b0f58b9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xcb-surface-source.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xcb-surface-source.ref.png b/local/recipes/libs/cairo/source/test/reference/xcb-surface-source.ref.png new file mode 100644 index 0000000000..018297208e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xcb-surface-source.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xcomposite-projection.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/xcomposite-projection.base.argb32.ref.png new file mode 100644 index 0000000000..ea4dddf71e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xcomposite-projection.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xcomposite-projection.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/xcomposite-projection.base.rgb24.ref.png new file mode 100644 index 0000000000..ea4dddf71e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xcomposite-projection.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xcomposite-projection.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/xcomposite-projection.image16.ref.png new file mode 100644 index 0000000000..f9bc3b621c Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xcomposite-projection.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xcomposite-projection.mask.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/xcomposite-projection.mask.argb32.ref.png new file mode 100644 index 0000000000..9ccabda9f5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xcomposite-projection.mask.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xcomposite-projection.mask.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/xcomposite-projection.mask.rgb24.ref.png new file mode 100644 index 0000000000..9ccabda9f5 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xcomposite-projection.mask.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xcomposite-projection.quartz.ref.png b/local/recipes/libs/cairo/source/test/reference/xcomposite-projection.quartz.ref.png new file mode 100644 index 0000000000..b5526f0e06 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xcomposite-projection.quartz.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xcomposite-projection.ref.png b/local/recipes/libs/cairo/source/test/reference/xcomposite-projection.ref.png new file mode 100644 index 0000000000..abbea08663 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xcomposite-projection.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xcomposite-projection.traps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/xcomposite-projection.traps.argb32.ref.png new file mode 100644 index 0000000000..ea4dddf71e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xcomposite-projection.traps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xcomposite-projection.traps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/xcomposite-projection.traps.rgb24.ref.png new file mode 100644 index 0000000000..ea4dddf71e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xcomposite-projection.traps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xlib-expose-event.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/xlib-expose-event.base.argb32.ref.png new file mode 100644 index 0000000000..fd71f5a327 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xlib-expose-event.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xlib-expose-event.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/xlib-expose-event.base.rgb24.ref.png new file mode 100644 index 0000000000..fd71f5a327 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xlib-expose-event.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xlib-expose-event.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/xlib-expose-event.image16.ref.png new file mode 100644 index 0000000000..54d5f26734 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xlib-expose-event.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xlib-expose-event.ps.ref.png b/local/recipes/libs/cairo/source/test/reference/xlib-expose-event.ps.ref.png new file mode 100644 index 0000000000..88f49c1349 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xlib-expose-event.ps.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xlib-expose-event.ref.png b/local/recipes/libs/cairo/source/test/reference/xlib-expose-event.ref.png new file mode 100644 index 0000000000..1cca0e749e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xlib-expose-event.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xlib-expose-event.svg.ref.png b/local/recipes/libs/cairo/source/test/reference/xlib-expose-event.svg.ref.png new file mode 100644 index 0000000000..2a4cf83220 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xlib-expose-event.svg.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xlib-surface-source.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/xlib-surface-source.base.argb32.ref.png new file mode 100644 index 0000000000..018297208e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xlib-surface-source.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xlib-surface-source.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/xlib-surface-source.base.rgb24.ref.png new file mode 100644 index 0000000000..0d68a82cc2 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xlib-surface-source.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xlib-surface-source.image16.ref.png b/local/recipes/libs/cairo/source/test/reference/xlib-surface-source.image16.ref.png new file mode 100644 index 0000000000..2a7460e284 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xlib-surface-source.image16.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xlib-surface-source.ps.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/xlib-surface-source.ps.argb32.ref.png new file mode 100644 index 0000000000..910f895db9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xlib-surface-source.ps.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xlib-surface-source.ps.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/xlib-surface-source.ps.rgb24.ref.png new file mode 100644 index 0000000000..636b0f58b9 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xlib-surface-source.ps.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/xlib-surface-source.ref.png b/local/recipes/libs/cairo/source/test/reference/xlib-surface-source.ref.png new file mode 100644 index 0000000000..018297208e Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/xlib-surface-source.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/zero-alpha.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/zero-alpha.base.argb32.ref.png new file mode 100644 index 0000000000..595c0aee4d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/zero-alpha.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/zero-alpha.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/zero-alpha.base.rgb24.ref.png new file mode 100644 index 0000000000..595c0aee4d Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/zero-alpha.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/zero-alpha.ref.png b/local/recipes/libs/cairo/source/test/reference/zero-alpha.ref.png new file mode 100644 index 0000000000..d03727dda8 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/zero-alpha.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/zero-mask.base.argb32.ref.png b/local/recipes/libs/cairo/source/test/reference/zero-mask.base.argb32.ref.png new file mode 100644 index 0000000000..ffae8d9953 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/zero-mask.base.argb32.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reference/zero-mask.base.rgb24.ref.png b/local/recipes/libs/cairo/source/test/reference/zero-mask.base.rgb24.ref.png new file mode 100644 index 0000000000..263c3d1e82 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/reference/zero-mask.base.rgb24.ref.png differ diff --git a/local/recipes/libs/cairo/source/test/reflected-stroke.c b/local/recipes/libs/cairo/source/test/reflected-stroke.c new file mode 100644 index 0000000000..895396a6a5 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/reflected-stroke.c @@ -0,0 +1,91 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * the author not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. The author makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE AUTHOR. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +static void +draw_symbol (cairo_t *cr) +{ + double dash[] = {6, 3}; + + cairo_rectangle (cr, -25, -25, 50, 50); + cairo_stroke (cr); + + cairo_move_to (cr, 0, -25); + cairo_curve_to (cr, 12.5, -12.5, 12.5, -12.5, 0, 0); + cairo_curve_to (cr, -12.5, 12.5, -12.5, 12.5, 0, 25); + cairo_curve_to (cr, 12.5, 12.5, 12.5, 12.5, 0, 0); + cairo_stroke (cr); + + cairo_save (cr); + cairo_set_dash (cr, dash, ARRAY_LENGTH (dash), 0.); + cairo_move_to (cr, 0, 0); + cairo_arc (cr, 0, 0, 12.5, 0, 3 * M_PI / 2); + cairo_close_path (cr); + cairo_stroke (cr); + cairo_restore (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0, 0, 0); + + cairo_save (cr); + cairo_translate (cr, 50, 50); + cairo_scale (cr, 1, 1); + draw_symbol (cr); + cairo_restore (cr); + + cairo_save (cr); + cairo_translate (cr, 150, 50); + cairo_scale (cr, -1, 1); + draw_symbol (cr); + cairo_restore (cr); + + cairo_save (cr); + cairo_translate (cr, 150, 150); + cairo_scale (cr, -1, -1); + draw_symbol (cr); + cairo_restore (cr); + + cairo_save (cr); + cairo_translate (cr, 50, 150); + cairo_scale (cr, 1, -1); + draw_symbol (cr); + cairo_restore (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (reflected_stroke, + "Exercises the stroker with a reflected ctm", + "stroke, transform", /* keywords */ + NULL, /* requirements */ + 200, 200, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/rel-path.c b/local/recipes/libs/cairo/source/test/rel-path.c new file mode 100644 index 0000000000..d1ef259200 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/rel-path.c @@ -0,0 +1,129 @@ +/* + * Copyright © 2005 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "cairo-test.h" + +#define SIZE 10 + +static cairo_status_t +invalid_rel_move_to (cairo_surface_t *target) +{ + cairo_t *cr; + cairo_status_t status; + + cr = cairo_create (target); + cairo_rel_move_to (cr, SIZE, SIZE/2); + status = cairo_status (cr); + cairo_destroy (cr); + + return status; +} + +static cairo_status_t +invalid_rel_line_to (cairo_surface_t *target) +{ + cairo_t *cr; + cairo_status_t status; + + cr = cairo_create (target); + cairo_rel_line_to (cr, -SIZE, SIZE/2); + status = cairo_status (cr); + cairo_destroy (cr); + + return status; +} + +static cairo_status_t +invalid_rel_curve_to (cairo_surface_t *target) +{ + cairo_t *cr; + cairo_status_t status; + + cr = cairo_create (target); + cairo_rel_curve_to (cr, + SIZE/2, -SIZE/2, + SIZE*2/3, -SIZE/3, + SIZE/2, -SIZE); + status = cairo_status (cr); + cairo_destroy (cr); + + return status; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_status_t status; + cairo_test_status_t result; + + /* first test that a relative move without a current point fails... */ + status = invalid_rel_move_to (cairo_get_target (cr)); + if (status != CAIRO_STATUS_NO_CURRENT_POINT) { + result = cairo_test_status_from_status (ctx, status); + if (result == CAIRO_TEST_NO_MEMORY) + return result; + + cairo_test_log (ctx, "Error: invalid cairo_rel_move_to() did not raise NO_CURRENT_POINT\n"); + return result; + } + + status = invalid_rel_line_to (cairo_get_target (cr)); + if (status != CAIRO_STATUS_NO_CURRENT_POINT) { + result = cairo_test_status_from_status (ctx, status); + if (result == CAIRO_TEST_NO_MEMORY) + return result; + + cairo_test_log (ctx, "Error: invalid cairo_rel_line_to() did not raise NO_CURRENT_POINT\n"); + return result; + } + + status = invalid_rel_curve_to (cairo_get_target (cr)); + if (status != CAIRO_STATUS_NO_CURRENT_POINT) { + result = cairo_test_status_from_status (ctx, status); + if (result == CAIRO_TEST_NO_MEMORY) + return result; + + cairo_test_log (ctx, "Error: invalid cairo_rel_curve_to() did not raise NO_CURRENT_POINT\n"); + return result; + } + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_move_to (cr, 0, 0); + cairo_rel_move_to (cr, SIZE, SIZE/2); + cairo_rel_line_to (cr, -SIZE, SIZE/2); + cairo_rel_curve_to (cr, + SIZE/2, -SIZE/2, + SIZE*2/3, -SIZE/3, + SIZE/2, -SIZE); + + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (rel_path, + "Tests calls to various relative path functions", + "path", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/rgb24-ignore-alpha.c b/local/recipes/libs/cairo/source/test/rgb24-ignore-alpha.c new file mode 100644 index 0000000000..1c9d57e9eb --- /dev/null +++ b/local/recipes/libs/cairo/source/test/rgb24-ignore-alpha.c @@ -0,0 +1,60 @@ +/* + * Copyright © 2007 Red Hat, Inc. + * + * 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: Carl D. Worth + */ + +#include "cairo-test.h" + +#define WIDTH 2 +#define HEIGHT 2 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface; + /* Four green pixels with different "alpha" values, (but which + * should be entirely ignored). */ + uint32_t colors[4] = { + 0xff00ff00, 0x8800ff00, + 0x4400ff00, 0x0000ff00 + }; + + surface = cairo_image_surface_create_for_data ((unsigned char *) colors, + CAIRO_FORMAT_RGB24, 2, 2, 8); + + cairo_set_source_surface (cr, surface, 0, 0); + cairo_paint (cr); + + cairo_surface_finish (surface); /* colors will go out of scope */ + cairo_surface_destroy (surface); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (rgb24_ignore_alpha, + "Test that when using an RGB24 image as a source, there is no alpha channel", + "image, alpha", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/romedalen.jpg b/local/recipes/libs/cairo/source/test/romedalen.jpg new file mode 100644 index 0000000000..d655e3d891 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/romedalen.jpg differ diff --git a/local/recipes/libs/cairo/source/test/romedalen.png b/local/recipes/libs/cairo/source/test/romedalen.png new file mode 100644 index 0000000000..0c41eb0cfd Binary files /dev/null and b/local/recipes/libs/cairo/source/test/romedalen.png differ diff --git a/local/recipes/libs/cairo/source/test/rotate-image-surface-paint.c b/local/recipes/libs/cairo/source/test/rotate-image-surface-paint.c new file mode 100644 index 0000000000..42fda6ec2a --- /dev/null +++ b/local/recipes/libs/cairo/source/test/rotate-image-surface-paint.c @@ -0,0 +1,172 @@ +/* + * Copyright © 2005, 2007 Red Hat, Inc. + * + * 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: Carl D. Worth + */ + +#include "cairo-test.h" + +#define SIZE 20 +#define PAD 2 + +static cairo_pattern_t * +create_image_source (int size) +{ + cairo_surface_t *surface; + cairo_pattern_t *pattern; + cairo_t *cr; + + /* Create an image surface with my favorite four colors in each + * quadrant. */ + surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, size, size); + cr = cairo_create (surface); + cairo_surface_destroy (surface); + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_rectangle (cr, 0, 0, size / 2, size / 2); + cairo_fill (cr); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_rectangle (cr, size / 2, 0, size - size / 2, size / 2); + cairo_fill (cr); + + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_rectangle (cr, 0, size / 2, size / 2, size - size / 2); + cairo_fill (cr); + + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_rectangle (cr, size / 2, size / 2, size - size / 2, size - size / 2); + cairo_fill (cr); + + pattern = cairo_pattern_create_for_surface (cairo_get_target (cr)); + cairo_destroy (cr); + + return pattern; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *source; + int surface_size = sqrt ((SIZE - 2*PAD)*(SIZE - 2*PAD)/2); + + /* Use a gray (neutral) background, so we can spot if the backend pads + * with any other colour. + */ + cairo_set_source_rgb (cr, .5, .5, .5); + cairo_paint (cr); + + cairo_translate(cr, SIZE/2, SIZE/2); + cairo_rotate (cr, M_PI / 4.0); + cairo_translate (cr, -surface_size/2, -surface_size/2); + + source = create_image_source (surface_size); + cairo_pattern_set_filter (source, CAIRO_FILTER_NEAREST); + cairo_set_source(cr, source); + cairo_pattern_destroy (source); + + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +clip_draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *source; + int surface_size = sqrt ((SIZE - 2*PAD)*(SIZE - 2*PAD)/2); + + /* Use a gray (neutral) background, so we can spot if the backend pads + * with any other colour. + */ + cairo_set_source_rgb (cr, .5, .5, .5); + cairo_paint (cr); + + cairo_rectangle (cr, 2*PAD, 2*PAD, SIZE-4*PAD, SIZE-4*PAD); + cairo_clip (cr); + + cairo_translate(cr, SIZE/2, SIZE/2); + cairo_rotate (cr, M_PI / 4.0); + cairo_translate (cr, -surface_size/2, -surface_size/2); + + source = create_image_source (surface_size); + cairo_pattern_set_filter (source, CAIRO_FILTER_NEAREST); + cairo_set_source(cr, source); + cairo_pattern_destroy (source); + + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +draw_clip (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *source; + int surface_size = sqrt ((SIZE - 2*PAD)*(SIZE - 2*PAD)/2); + + /* Use a gray (neutral) background, so we can spot if the backend pads + * with any other colour. + */ + cairo_set_source_rgb (cr, .5, .5, .5); + cairo_paint (cr); + + cairo_translate(cr, SIZE/2, SIZE/2); + cairo_rotate (cr, M_PI / 4.0); + cairo_translate (cr, -surface_size/2, -surface_size/2); + + cairo_rectangle (cr, PAD, PAD, surface_size-2*PAD, surface_size-2*PAD); + cairo_clip (cr); + + source = create_image_source (surface_size); + cairo_pattern_set_filter (source, CAIRO_FILTER_NEAREST); + cairo_set_source(cr, source); + cairo_pattern_destroy (source); + + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (rotate_image_surface_paint, + "Test call sequence: image_surface_create; rotate; set_source_surface; paint" + "\nThis test is known to fail on the ps backend currently", + "image, transform, paint", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) + +CAIRO_TEST (clip_rotate_image_surface_paint, + "Test call sequence: image_surface_create; rotate; set_source_surface; paint" + "\nThis test is known to fail on the ps backend currently", + "image, transform, paint", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, clip_draw) +CAIRO_TEST (rotate_clip_image_surface_paint, + "Test call sequence: image_surface_create; rotate; set_source_surface; paint" + "\nThis test is known to fail on the ps backend currently", + "image, transform, paint", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw_clip) diff --git a/local/recipes/libs/cairo/source/test/rotate-stroke-box.c b/local/recipes/libs/cairo/source/test/rotate-stroke-box.c new file mode 100644 index 0000000000..862abc9333 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/rotate-stroke-box.c @@ -0,0 +1,49 @@ +/* + * Copyright © 2013 Adrian Johnson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Adrian Johnson + */ + +#include "cairo-test.h" +#include + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_save (cr); + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + cairo_restore (cr); + + cairo_rectangle (cr, 5, 5, 20, 20); + cairo_rotate (cr, M_PI/4); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (rotate_stroke_box, + "Ensure rectangle path optimization works when the stroking transform is non rectilinear", + "path", /* keywords */ + NULL, /* requirements */ + 30, 30, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/rotated-clip.c b/local/recipes/libs/cairo/source/test/rotated-clip.c new file mode 100644 index 0000000000..4ca4566d52 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/rotated-clip.c @@ -0,0 +1,110 @@ +/* + * Copyright © 2007 Adrian Johnson + * Copyright © 2009 Chris Wilson + * + * 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 + * Chris Wilson + */ + +#include "cairo-test.h" + +#define PAT_WIDTH 120 +#define PAT_HEIGHT 120 +#define SIZE (PAT_WIDTH*2) +#define PAD 2 +#define WIDTH (PAD + SIZE + PAD) +#define HEIGHT WIDTH + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_matrix_t m; + + /* make the output opaque */ + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + cairo_translate (cr, PAD, PAD); + + cairo_matrix_init_scale (&m, 2, 1.5); + cairo_matrix_rotate (&m, 1); + cairo_matrix_translate (&m, -PAT_WIDTH/4.0, -PAT_WIDTH/2.0); + cairo_matrix_invert (&m); + cairo_set_matrix (cr, &m); + + cairo_rectangle (cr, 0, 0, PAT_WIDTH, PAT_HEIGHT); + cairo_clip (cr); + + cairo_set_source_rgba (cr, 1, 0, 1, 0.5); + cairo_rectangle (cr, PAT_WIDTH/6.0, PAT_HEIGHT/6.0, PAT_WIDTH/4.0, PAT_HEIGHT/4.0); + cairo_fill (cr); + + cairo_set_source_rgba (cr, 0, 1, 1, 0.5); + cairo_rectangle (cr, PAT_WIDTH/2.0, PAT_HEIGHT/2.0, PAT_WIDTH/4.0, PAT_HEIGHT/4.0); + cairo_fill (cr); + + cairo_set_line_width (cr, 1); + cairo_move_to (cr, PAT_WIDTH/6.0, 0); + cairo_line_to (cr, 0, 0); + cairo_line_to (cr, 0, PAT_HEIGHT/6.0); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_stroke (cr); + + cairo_move_to (cr, PAT_WIDTH/6.0, PAT_HEIGHT); + cairo_line_to (cr, 0, PAT_HEIGHT); + cairo_line_to (cr, 0, 5*PAT_HEIGHT/6.0); + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_stroke (cr); + + cairo_move_to (cr, 5*PAT_WIDTH/6.0, 0); + cairo_line_to (cr, PAT_WIDTH, 0); + cairo_line_to (cr, PAT_WIDTH, PAT_HEIGHT/6.0); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_stroke (cr); + + cairo_move_to (cr, 5*PAT_WIDTH/6.0, PAT_HEIGHT); + cairo_line_to (cr, PAT_WIDTH, PAT_HEIGHT); + cairo_line_to (cr, PAT_WIDTH, 5*PAT_HEIGHT/6.0); + cairo_set_source_rgb (cr, 1, 1, 0); + cairo_stroke (cr); + + cairo_set_source_rgb (cr, 0.5, 0.5, 0.5); + cairo_set_line_width (cr, PAT_WIDTH/10.0); + + cairo_move_to (cr, 0, PAT_HEIGHT/4.0); + cairo_line_to (cr, PAT_WIDTH, PAT_HEIGHT/4.0); + cairo_stroke (cr); + + cairo_move_to (cr, PAT_WIDTH/4.0, 0); + cairo_line_to (cr, PAT_WIDTH/4.0, PAT_WIDTH); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (rotated_clip, + "Test clipping with non identity pattern matrix", + "clip", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/round-join-bug-520.c b/local/recipes/libs/cairo/source/test/round-join-bug-520.c new file mode 100644 index 0000000000..be2b5aa0d2 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/round-join-bug-520.c @@ -0,0 +1,109 @@ +/* + * Author: Christian Rohlfs, 2022 + * + * 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. + */ + +#include "cairo-test.h" + +#define WIDTH 100 +#define HEIGHT WIDTH + +static cairo_test_status_t +draw_round(cairo_t *cr, int width, int height) +{ + /* Fail condition: + 0 >= 2 * ( 1 - tolerance / (line_width / 2) )^2 - 1, + with the default tolerance of 0.1, `failing_line_width` is in + [0.117157287525381; 0.682842712474619] + range. + */ + + double failing_line_width = 0.3; + + cairo_set_tolerance(cr, 0.1); + cairo_scale(cr, width, height); + + cairo_set_source_rgb(cr, 1, 1, 1); + cairo_paint(cr); + + cairo_move_to(cr, 0.2, 0.2); + cairo_line_to(cr, 0.8, 0.2); + cairo_line_to(cr, 0.8, 0.8); + cairo_line_to(cr, 0.2, 0.8); + cairo_close_path(cr); + + cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); + cairo_set_source_rgb(cr, 0, 0, 0); + cairo_set_line_width(cr, failing_line_width); + cairo_stroke(cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +draw_bevel(cairo_t *cr, int width, int height) +{ + /* Fail condition: + arc_height < tolerance + For 90° join `arc_height` is equal to + line_width / 2 * (1 - sqrt(1/2)) + which is 0.1464466094067262 of a `line_width`. + */ + + double line_width = 0.3; + double failing_tolerance = 0.3 * line_width; + + cairo_set_tolerance(cr, width * failing_tolerance); + cairo_scale(cr, width, height); + + cairo_set_source_rgb(cr, 1, 1, 1); + cairo_paint(cr); + + cairo_move_to(cr, 0.2, 0.2); + cairo_line_to(cr, 0.8, 0.2); + cairo_line_to(cr, 0.8, 0.8); + cairo_line_to(cr, 0.2, 0.8); + cairo_close_path(cr); + + cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); + cairo_set_source_rgb(cr, 0, 0, 0); + cairo_set_line_width(cr, line_width); + cairo_stroke(cr); + + return CAIRO_TEST_SUCCESS; +} + + +CAIRO_TEST (round_join_bug_520_round, + "Tests round joins within tolerance", + "stroke, cap, join", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw_round) + +CAIRO_TEST (round_join_bug_520_bevel, + "Tests round joins omission when `arc_height < tolerance`", + "stroke, cap, join", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw_bevel) + diff --git a/local/recipes/libs/cairo/source/test/rounded-rectangle-fill.c b/local/recipes/libs/cairo/source/test/rounded-rectangle-fill.c new file mode 100644 index 0000000000..d211cf626b --- /dev/null +++ b/local/recipes/libs/cairo/source/test/rounded-rectangle-fill.c @@ -0,0 +1,65 @@ +/* + * Copyright © 2009 Chris Wilson + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +#define SIZE 80 + +/* A very simple test to exercise the scan rasterisers with constant regions. */ + +static void +rounded_rectangle (cairo_t *cr, int x, int y, int w, int h, int r) +{ + cairo_new_sub_path (cr); + cairo_arc (cr, x + r, y + r, r, M_PI, 3 * M_PI / 2); + cairo_arc (cr, x + w - r, y + r, r, 3 *M_PI / 2, 2 * M_PI); + cairo_arc (cr, x + w - r, y + h - r, r, 0, M_PI / 2); + cairo_arc (cr, x + r, y + h - r, r, M_PI / 2, M_PI); + cairo_close_path (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + /* Paint background white, then draw in black. */ + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */ + + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + rounded_rectangle (cr, 5, 5, width-10, height-10, 15); + rounded_rectangle (cr, 15, 15, width-30, height-30, 5); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (rounded_rectangle_fill, + "Tests handling of rounded rectangles, the UI designers favourite", + "fill, rounded-rectangle", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/rounded-rectangle-stroke.c b/local/recipes/libs/cairo/source/test/rounded-rectangle-stroke.c new file mode 100644 index 0000000000..22bc515578 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/rounded-rectangle-stroke.c @@ -0,0 +1,64 @@ +/* + * Copyright © 2009 Chris Wilson + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +#define SIZE 80 + +/* A very simple test to exercise the scan rasterisers with constant regions. */ + +static void +rounded_rectangle (cairo_t *cr, int x, int y, int w, int h, int r) +{ + cairo_new_sub_path (cr); + cairo_arc (cr, x + r, y + r, r, M_PI, 3 * M_PI / 2); + cairo_arc (cr, x + w - r, y + r, r, 3 *M_PI / 2, 2 * M_PI); + cairo_arc (cr, x + w - r, y + h - r, r, 0, M_PI / 2); + cairo_arc (cr, x + r, y + h - r, r, M_PI / 2, M_PI); + cairo_close_path (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + /* Paint background white, then draw in black. */ + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */ + + cairo_set_line_width (cr, 10); + rounded_rectangle (cr, 10, 10, width-20, height-20, 10); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (rounded_rectangle_stroke, + "Tests handling of rounded rectangles, the UI designers favourite", + "stroke, rounded-rectangle", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/run-cairo-test-suite.sh b/local/recipes/libs/cairo/source/test/run-cairo-test-suite.sh new file mode 100755 index 0000000000..567d2b14be --- /dev/null +++ b/local/recipes/libs/cairo/source/test/run-cairo-test-suite.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +set -m + +if `which gnome-screensaver-command`; then + gnome-screensaver-command -i -n "cairo-test-suite" -r "Cairo needs to read back from the screen in order to test rendering to xlib" & + pid=$! + + restore_screensaver() { kill $pid; } +else + restore_screensaver() { :; } +fi + +trap cleanup SIGINT SIGTERM + +./cairo-test-suite "$*" + +restore_screensaver diff --git a/local/recipes/libs/cairo/source/test/sample.c b/local/recipes/libs/cairo/source/test/sample.c new file mode 100644 index 0000000000..caf68777e7 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/sample.c @@ -0,0 +1,117 @@ +/* + * Copyright 2012 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +/* Test the fidelity of the rasterisation, because Cairo is my favourite + * driver test suite. + */ + +#define GENERATE_REFERENCE 0 + +#define WIDTH 256 +#define HEIGHT 40 + +#include "../src/cairo-fixed-type-private.h" +#define PRECISION (1 << CAIRO_FIXED_FRAC_BITS) + +static cairo_test_status_t +vertical (cairo_t *cr, int width, int height) +{ + int x; + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_paint (cr); + + cairo_set_source_rgba (cr, 1, 1, 1, 1); + for (x = -HEIGHT*PRECISION-2; x <= (WIDTH+HEIGHT)*PRECISION+2; x += 4) { + cairo_move_to (cr, x / (double)PRECISION - 2, -2); + cairo_rel_line_to (cr, 0, HEIGHT + 4); + } + cairo_set_line_width (cr, 2 / (double)PRECISION); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +horizontal (cairo_t *cr, int width, int height) +{ + int x; + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_paint (cr); + + cairo_set_source_rgba (cr, 1, 1, 1, 1); + for (x = -HEIGHT*PRECISION-2; x <= (WIDTH+HEIGHT)*PRECISION+2; x += 4) { + cairo_move_to (cr, -2, x / (double)PRECISION - 2); + cairo_rel_line_to (cr, HEIGHT + 4, 0); + } + cairo_set_line_width (cr, 2 / (double)PRECISION); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +diagonal (cairo_t *cr, int width, int height) +{ + int x; + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_paint (cr); + + cairo_set_source_rgba (cr, 1, 1, 1, 1); + for (x = -HEIGHT*PRECISION-2; x <= (WIDTH+HEIGHT)*PRECISION+2; x += 6) { + cairo_move_to (cr, x / (double)PRECISION - 2, -2); + cairo_rel_line_to (cr, HEIGHT + 4, HEIGHT + 4); + } + cairo_set_line_width (cr, 2 / (double)PRECISION); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (sample_vertical, + "Check the fidelity of the rasterisation.", + NULL, /* keywords */ + "target=raster slow", /* requirements */ + WIDTH, HEIGHT, + NULL, vertical) + +CAIRO_TEST (sample_horizontal, + "Check the fidelity of the rasterisation.", + NULL, /* keywords */ + "target=raster slow", /* requirements */ + WIDTH, HEIGHT, + NULL, horizontal) + +CAIRO_TEST (sample_diagonal, + "Check the fidelity of the rasterisation.", + NULL, /* keywords */ + "target=raster slow", /* requirements */ + WIDTH, HEIGHT, + NULL, diagonal) diff --git a/local/recipes/libs/cairo/source/test/scale-down-source-surface-paint.c b/local/recipes/libs/cairo/source/test/scale-down-source-surface-paint.c new file mode 100644 index 0000000000..8cf0e06f2c --- /dev/null +++ b/local/recipes/libs/cairo/source/test/scale-down-source-surface-paint.c @@ -0,0 +1,65 @@ +/* + * Copyright © 2005,2007 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface; + uint32_t data[16] = { + 0xffffffff, 0xffffffff, 0xffff0000, 0xffff0000, + 0xffffffff, 0xffffffff, 0xffff0000, 0xffff0000, + + 0xff00ff00, 0xff00ff00, 0xff0000ff, 0xff0000ff, + 0xff00ff00, 0xff00ff00, 0xff0000ff, 0xff0000ff + }; + + /* First paint opaque background (black) so we don't need separate + * ARGB32 and RGB24 reference images. */ + cairo_set_source_rgb (cr, 0, 0, 0); /* black */ + cairo_paint (cr); + + surface = cairo_image_surface_create_for_data ((unsigned char *) data, + CAIRO_FORMAT_RGB24, 4, 4, 16); + + cairo_scale (cr, 0.5, 0.5); + + cairo_set_source_surface (cr, surface, 4, 4); + cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); + cairo_paint (cr); + + cairo_surface_finish (surface); /* data will go out of scope */ + cairo_surface_destroy (surface); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (scale_down_source_surface_paint, + "Test call sequence: cairo_scale; cairo_set_source_surface; cairo_paint, with a scale < 1.0", + "paint, transform", /* keywords */ + NULL, /* requirements */ + 6, 6, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/scale-offset-image.c b/local/recipes/libs/cairo/source/test/scale-offset-image.c new file mode 100644 index 0000000000..9b4ba3f733 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/scale-offset-image.c @@ -0,0 +1,143 @@ +/* + * Copyright 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +/* + * Test case derived from the bug report by Michel Iwaniec: + * https://lists.cairographics.org/archives/cairo/2008-November/015660.html + */ + +#include "cairo-test.h" + +static cairo_surface_t * +create_source (cairo_surface_t *target, int width, int height) +{ + cairo_surface_t *similar; + cairo_t *cr; + + similar = cairo_image_surface_create (CAIRO_FORMAT_RGB24, + width, height); + cr = cairo_create (similar); + cairo_surface_destroy (similar); + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_rectangle (cr, + width - 4, height - 4, + 2, 2); + cairo_fill (cr); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_rectangle (cr, + width - 2, height - 4, + 2, 2); + cairo_fill (cr); + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_rectangle (cr, + width - 4, height - 2, + 2, 2); + cairo_fill (cr); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_rectangle (cr, + width - 2, height - 2, + 2, 2); + cairo_fill (cr); + + similar = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + + return similar; +} + +static void +draw_grid (cairo_t *cr, cairo_pattern_t *pattern, int dst_x, int dst_y) +{ + cairo_matrix_t m; + + cairo_save (cr); + cairo_translate (cr, dst_x, dst_y); + cairo_scale (cr, 16, 16); + cairo_rotate (cr, 1); + + cairo_matrix_init_translate (&m, 2560-4, 1280-4); + cairo_pattern_set_matrix (pattern, &m); + cairo_set_source (cr, pattern); + cairo_rectangle (cr, 0, 0, 4, 4); + cairo_fill (cr); + + cairo_set_source_rgb (cr, .7, .7, .7); + cairo_set_line_width (cr, 1./16); + cairo_move_to (cr, 0, 0); + cairo_line_to (cr, 4, 0); + cairo_move_to (cr, 0, 2); + cairo_line_to (cr, 4, 2); + cairo_move_to (cr, 0, 4); + cairo_line_to (cr, 4, 4); + cairo_move_to (cr, 0, 0); + cairo_line_to (cr, 0, 4); + cairo_move_to (cr, 2, 0); + cairo_line_to (cr, 2, 4); + cairo_move_to (cr, 4, 0); + cairo_line_to (cr, 4, 4); + cairo_stroke (cr); + + cairo_restore (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *source; + cairo_pattern_t *pattern; + + cairo_paint (cr); + + source = create_source (cairo_get_target (cr), 2560, 1280); + pattern = cairo_pattern_create_for_surface (source); + cairo_surface_destroy (source); + + cairo_pattern_set_filter (pattern, CAIRO_FILTER_NEAREST); + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_NONE); + + draw_grid (cr, pattern, 50, 0); + draw_grid (cr, pattern, 130, 0); + draw_grid (cr, pattern, 210, 0); + draw_grid (cr, pattern, 290, 0); + + draw_grid (cr, pattern, 50, 230); + draw_grid (cr, pattern, 130, 230); + draw_grid (cr, pattern, 210, 230); + draw_grid (cr, pattern, 290, 230); + + cairo_pattern_destroy (pattern); + + return CAIRO_TEST_SUCCESS; +} + +/* XFAIL: loss of precision converting a cairo matrix to */ +CAIRO_TEST (scale_offset_image, + "Tests drawing surfaces under various scales and transforms", + "surface, scale-offset", /* keywords */ + NULL, /* requirements */ + 320, 320, + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/scale-offset-similar.c b/local/recipes/libs/cairo/source/test/scale-offset-similar.c new file mode 100644 index 0000000000..32a083c496 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/scale-offset-similar.c @@ -0,0 +1,143 @@ +/* + * Copyright 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +/* + * Test case derived from the bug report by Michel Iwaniec: + * https://lists.cairographics.org/archives/cairo/2008-November/015660.html + */ + +#include "cairo-test.h" + +static cairo_surface_t * +create_source (cairo_surface_t *target, int width, int height) +{ + cairo_surface_t *similar; + cairo_t *cr; + + similar = cairo_surface_create_similar (target, + CAIRO_CONTENT_COLOR, + width, height); + cr = cairo_create (similar); + cairo_surface_destroy (similar); + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_rectangle (cr, + width - 4, height - 4, + 2, 2); + cairo_fill (cr); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_rectangle (cr, + width - 2, height - 4, + 2, 2); + cairo_fill (cr); + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_rectangle (cr, + width - 4, height - 2, + 2, 2); + cairo_fill (cr); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_rectangle (cr, + width - 2, height - 2, + 2, 2); + cairo_fill (cr); + + similar = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + + return similar; +} + +static void +draw_grid (cairo_t *cr, cairo_pattern_t *pattern, int dst_x, int dst_y) +{ + cairo_matrix_t m; + + cairo_save (cr); + cairo_translate (cr, dst_x, dst_y); + cairo_scale (cr, 16, 16); + cairo_rotate (cr, 1); + + cairo_matrix_init_translate (&m, 2560-4, 1280-4); + cairo_pattern_set_matrix (pattern, &m); + cairo_set_source (cr, pattern); + cairo_rectangle (cr, 0, 0, 4, 4); + cairo_fill (cr); + + cairo_set_source_rgb (cr, .7, .7, .7); + cairo_set_line_width (cr, 1./16); + cairo_move_to (cr, 0, 0); + cairo_line_to (cr, 4, 0); + cairo_move_to (cr, 0, 2); + cairo_line_to (cr, 4, 2); + cairo_move_to (cr, 0, 4); + cairo_line_to (cr, 4, 4); + cairo_move_to (cr, 0, 0); + cairo_line_to (cr, 0, 4); + cairo_move_to (cr, 2, 0); + cairo_line_to (cr, 2, 4); + cairo_move_to (cr, 4, 0); + cairo_line_to (cr, 4, 4); + cairo_stroke (cr); + + cairo_restore (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *source; + cairo_pattern_t *pattern; + + cairo_paint (cr); + + source = create_source (cairo_get_target (cr), 2560, 1280); + pattern = cairo_pattern_create_for_surface (source); + cairo_surface_destroy (source); + + cairo_pattern_set_filter (pattern, CAIRO_FILTER_NEAREST); + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_NONE); + + draw_grid (cr, pattern, 50, 0); + draw_grid (cr, pattern, 130, 0); + draw_grid (cr, pattern, 210, 0); + draw_grid (cr, pattern, 290, 0); + + draw_grid (cr, pattern, 50, 230); + draw_grid (cr, pattern, 130, 230); + draw_grid (cr, pattern, 210, 230); + draw_grid (cr, pattern, 290, 230); + + cairo_pattern_destroy (pattern); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (scale_offset_similar, + "Tests drawing surfaces under various scales and transforms", + "surface, scale-offset", /* keywords */ + NULL, /* requirements */ + 320, 320, + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/scale-source-surface-paint.c b/local/recipes/libs/cairo/source/test/scale-source-surface-paint.c new file mode 100644 index 0000000000..0c0a3acd86 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/scale-source-surface-paint.c @@ -0,0 +1,60 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface; + uint32_t data[16] = { + 0xffffffff, 0xffffffff, 0xffff0000, 0xffff0000, + 0xffffffff, 0xffffffff, 0xffff0000, 0xffff0000, + + 0xff00ff00, 0xff00ff00, 0xff0000ff, 0xff0000ff, + 0xff00ff00, 0xff00ff00, 0xff0000ff, 0xff0000ff + }; + + surface = cairo_image_surface_create_for_data ((unsigned char *) data, + CAIRO_FORMAT_RGB24, 4, 4, 16); + + cairo_scale (cr, 2, 2); + + cairo_set_source_surface (cr, surface, 1 , 1); + cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); + cairo_paint (cr); + + cairo_surface_finish (surface); /* data will go out of scope */ + cairo_surface_destroy (surface); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (scale_source_surface_paint, + "Test call sequence: cairo_scale; cairo_set_source_surface; cairo_paint", + "paint, transform", /* keywords */ + NULL, /* requirements */ + 12, 12, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/scaled-font-zero-matrix.c b/local/recipes/libs/cairo/source/test/scaled-font-zero-matrix.c new file mode 100644 index 0000000000..d4f79a6695 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/scaled-font-zero-matrix.c @@ -0,0 +1,63 @@ +/* + * Copyright © 2008 Mozilla Corporation + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Mozilla Corporation not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Mozilla Corporation makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * MOZILLA CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL MOZILLA CORPORATION BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Jeff Muizelaar + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_font_face_t *font_face; + cairo_font_options_t *font_options; + cairo_scaled_font_t *scaled_font; + cairo_matrix_t identity; + cairo_matrix_t zero; + + cairo_matrix_init_identity(&identity); + + zero = identity; + cairo_matrix_scale(&zero, 0, 0); + + font_face = cairo_get_font_face (cr); + font_options = cairo_font_options_create (); + cairo_get_font_options (cr, font_options); + scaled_font = cairo_scaled_font_create (font_face, + &identity, + &zero, + font_options); + cairo_set_scaled_font (cr, scaled_font); + cairo_show_text (cr, "Hello"); + cairo_scaled_font_destroy (scaled_font); + cairo_font_options_destroy (font_options); + + return cairo_test_status_from_status (cairo_test_get_context (cr), + cairo_status(cr)); +} + +CAIRO_TEST (scaled_font_zero_matrix, + "Test that scaled fonts with a degenerate matrix work", + "zero, matrix, degenerate, scaled-font", /* keywords */ + NULL, /* requirements */ + 0, 0, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/scarab.jpg b/local/recipes/libs/cairo/source/test/scarab.jpg new file mode 100644 index 0000000000..6a66ff7897 Binary files /dev/null and b/local/recipes/libs/cairo/source/test/scarab.jpg differ diff --git a/local/recipes/libs/cairo/source/test/select-font-face.c b/local/recipes/libs/cairo/source/test/select-font-face.c new file mode 100644 index 0000000000..ec4b27cf3e --- /dev/null +++ b/local/recipes/libs/cairo/source/test/select-font-face.c @@ -0,0 +1,65 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +#define TEXT_SIZE 12 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + /* We draw in the default black, so paint white first. */ + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0, 0, 0); /* black */ + + cairo_set_font_size (cr, TEXT_SIZE); + cairo_move_to (cr, 0, TEXT_SIZE); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Serif", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_show_text (cr, "i-am-serif"); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_show_text (cr, " i-am-sans"); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans Mono", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_show_text (cr, " i-am-mono"); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (select_font_face, + "Tests using cairo_select_font_face to draw text in different faces", + "font", /* keywords */ + NULL, /* requirements */ + 192, TEXT_SIZE + 4, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/select-font-no-show-text.c b/local/recipes/libs/cairo/source/test/select-font-no-show-text.c new file mode 100644 index 0000000000..b2b47966fc --- /dev/null +++ b/local/recipes/libs/cairo/source/test/select-font-no-show-text.c @@ -0,0 +1,59 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl Worth + */ + +/* Bug history + * + * 2005-04-12 Carl Worth + * + * I noticed that if we call cairo_select_font_face, but then do a + * cairo_destroy before ever drawing any text, then we get: + * + * *** glibc detected *** double free or corruption (fasttop): 0x083274d0 *** + * Aborted + * + * 2005-04-14 Owen Taylor + * + * Fixed... just a stray free(). + */ + +#include "cairo-test.h" +#include + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_BOLD); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (select_font_no_show_text, + "Test calling cairo_select_font_face but never drawing text.", + "font", /* keywords */ + NULL, /* requirements */ + 0, 0, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/self-copy-overlap.c b/local/recipes/libs/cairo/source/test/self-copy-overlap.c new file mode 100644 index 0000000000..6e3b39c912 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/self-copy-overlap.c @@ -0,0 +1,54 @@ +/* + * Copyright 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +/* Question: are patterns mutable? The answer depends on who you ask... */ + +#include "cairo-test.h" + +/* This test is only interesting if the target has alpha */ +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgba (cr, 0, 0, 0, .01); + cairo_paint (cr); + + cairo_set_source_surface (cr, cairo_get_target (cr), 1, 1); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +/* + * XFAIL: vector surfaces take snapshot of patterns in contrast to the raster + * backends which don't. One solution would be to clone overlapping areas of + * dst/source, so patterns were effectively snapshotted across all backends. + */ +CAIRO_TEST (self_copy_overlap, + "Tests painting to itself using itself as the source" + "\nBackends treat this case inconsistently---vector backends are creating snapshots.", + "self-copy", /* keywords */ + NULL, /* requirements */ + 200, 200, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/self-copy.c b/local/recipes/libs/cairo/source/test/self-copy.c new file mode 100644 index 0000000000..bef02e98ba --- /dev/null +++ b/local/recipes/libs/cairo/source/test/self-copy.c @@ -0,0 +1,84 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Owen Taylor + */ + +#include "cairo-test.h" +#include +#include + +#define SIZE 40 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *pattern; + cairo_matrix_t matrix; + + /* Paint a diagonal division as a test image */ + cairo_set_source_rgb (cr, 1, 1, 1); /* White */ + cairo_paint (cr); + + cairo_move_to (cr, SIZE, 0); + cairo_line_to (cr, SIZE, SIZE); + cairo_line_to (cr, 0, SIZE); + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_fill (cr); + + /* Create a pattern with the target surface as the source, + * offset by SIZE/2 + */ + pattern = cairo_pattern_create_for_surface (cairo_get_group_target (cr)); + + cairo_matrix_init_translate (&matrix, - SIZE / 2, - SIZE / 2); + cairo_pattern_set_matrix (pattern, &matrix); + + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + + /* Copy two rectangles from the upper-left quarter of the image to + * the lower right. It will work if we use cairo_fill(), but the + * cairo_clip() cairo_paint() combination fails because the clip + * on the surface as a destination affects it as the source as + * well. + */ + cairo_rectangle (cr, + 2 * SIZE / 4, 2 * SIZE / 4, + SIZE / 4, SIZE / 4); + cairo_rectangle (cr, + 3 * SIZE / 4, 3 * SIZE / 4, + SIZE / 4, SIZE / 4); + cairo_clip (cr); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; + +} + +CAIRO_TEST (self_copy, + "Test copying from a surface to itself with a clip", + "paint", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/self-intersecting.c b/local/recipes/libs/cairo/source/test/self-intersecting.c new file mode 100644 index 0000000000..8053235ace --- /dev/null +++ b/local/recipes/libs/cairo/source/test/self-intersecting.c @@ -0,0 +1,87 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +/* Bug history + * + * 2005-06-01 Carl Worth + * + * There's a long-standing bug in that self-intersecting paths give + * an incorrect result when stroked. The problem is that the + * trapezoids are generated incrementally along the stroke and as + * such, are not disjoint. The errant intersections of these + * trapezoids then leads to overfilled pixels. + * + * The test belows first creates and fills a path. Then it creates a + * second path which has a stroked boundary identical to the first + * filled path. But the results of the two operations are + * different. The most obvious difference is in the central region + * where the entire path intersects itself. But notice that every + * time the path turns there are also errors on the inside of the + * turn, (since the subsequent trapezoids along the path intersect). + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_translate (cr, 1.0, 1.0); + + cairo_set_source_rgb (cr, 1, 0, 0); /* red */ + + /* First draw the desired shape with a fill */ + cairo_rectangle (cr, 0.5, 0.5, 4.0, 4.0); + cairo_rectangle (cr, 3.5, 3.5, 4.0, 4.0); + cairo_rectangle (cr, 3.5, 1.5, -2.0, 2.0); + cairo_rectangle (cr, 6.5, 4.5, -2.0, 2.0); + + cairo_fill (cr); + + /* Then try the same thing with a stroke */ + cairo_translate (cr, 0, 10); + cairo_move_to (cr, 1.0, 1.0); + cairo_rel_line_to (cr, 3.0, 0.0); + cairo_rel_line_to (cr, 0.0, 6.0); + cairo_rel_line_to (cr, 3.0, 0.0); + cairo_rel_line_to (cr, 0.0, -3.0); + cairo_rel_line_to (cr, -6.0, 0.0); + cairo_close_path (cr); + + cairo_set_line_width (cr, 1.0); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (self_intersecting, + "Test strokes of self-intersecting paths" + "\nSelf-intersecting strokes are wrong due to incremental trapezoidization.", + "stroke, trap", /* keywords */ + NULL, /* requirements */ + 10, 20, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/set-source.c b/local/recipes/libs/cairo/source/test/set-source.c new file mode 100644 index 0000000000..7e54626a8b --- /dev/null +++ b/local/recipes/libs/cairo/source/test/set-source.c @@ -0,0 +1,81 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + int i; + uint32_t color = 0x8019334c; + cairo_surface_t *surface; + cairo_pattern_t *pattern; + + surface = cairo_image_surface_create_for_data ((unsigned char *) &color, + CAIRO_FORMAT_ARGB32, 1, 1, 4); + pattern = cairo_pattern_create_for_surface (surface); + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT); + + /* Several different means of making mostly the same color (though + * we can't get anything but alpha==1.0 out of + * cairo_set_source_rgb. */ + for (i=0; i < width; i++) { + switch (i) { + case 0: + cairo_set_source_rgb (cr, .6, .7, .8); + break; + case 1: + cairo_set_source_rgba (cr, .2, .4, .6, 0.5); + break; + case 2: +#if WE_HAD_SUPPORT_FOR_PREMULTIPLIED + cairo_set_source_rgba_premultiplied (cr, .1, .2, .3, 0.5); +#else + cairo_set_source_rgba (cr, .2, .4, .6, 0.5); +#endif + break; + case 3: + default: + cairo_set_source (cr, pattern); + break; + } + + cairo_rectangle (cr, i, 0, 1, height); + cairo_fill (cr); + } + + cairo_pattern_destroy (pattern); + cairo_surface_finish (surface); /* data will go out of scope */ + cairo_surface_destroy (surface); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (set_source, + "Tests calls to various set_source functions", + "api", /* keywords */ + NULL, /* requirements */ + 5, 5, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/shape-general-convex.c b/local/recipes/libs/cairo/source/test/shape-general-convex.c new file mode 100644 index 0000000000..b9241bb9fa --- /dev/null +++ b/local/recipes/libs/cairo/source/test/shape-general-convex.c @@ -0,0 +1,88 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +/* A general convex shape with a twist. */ + +#include "cairo-test.h" + +#define SIZE (100) +#define PAD 4 + +static void +limacon (cairo_t *cr, double a, double b, double radius) +{ + int i; + + cairo_save (cr); + cairo_translate (cr, PAD, 0); + for (i = 0; i < 360; i++) { + double theta = i * M_PI / 180; + double r = b + a * cos (theta); + double x = radius * r * cos (theta); + double y = radius * r * sin (theta); + cairo_line_to (cr, x, y); + } + cairo_close_path (cr); + cairo_restore (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_save (cr); + cairo_translate (cr, 2*PAD, PAD); + + cairo_translate (cr, SIZE/2, SIZE/2); + limacon (cr, 1, .5, SIZE/3); /* trivia, this is a trisectrix */ + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_fill_preserve (cr); + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_stroke (cr); + + cairo_scale (cr, -1, 1); + + limacon (cr, 1, .5, SIZE/3); /* trivia, this is a trisectrix */ + + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_fill_preserve (cr); + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (shape_general_convex, + "A general shape that is not as convex as it first appears", + "fill,stroke", /* keywords */ + NULL, /* requirements */ + SIZE+4*PAD, SIZE+4*PAD, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/shape-sierpinski.c b/local/recipes/libs/cairo/source/test/shape-sierpinski.c new file mode 100644 index 0000000000..9d2017067d --- /dev/null +++ b/local/recipes/libs/cairo/source/test/shape-sierpinski.c @@ -0,0 +1,85 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +/* I thought I spied a bug... */ + +#include "cairo-test.h" + +#define WIDTH (1024) +#define HEIGHT (600) + +static const double m_1_sqrt_3 = 0.577359269; + +static void +T (cairo_t *cr, int size) +{ + cairo_move_to (cr, 0, 0); + cairo_line_to (cr, size, 0); + cairo_line_to (cr, size/2, size*m_1_sqrt_3); + + size /= 2; + if (size >= 4) { + T (cr, size); + cairo_save (cr); { + cairo_translate (cr, size, 0); + T (cr, size); + } cairo_restore (cr); + cairo_save (cr); { + cairo_translate (cr, size/2, size*m_1_sqrt_3); + T (cr, size); + } cairo_restore (cr); + } +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_translate (cr, 0, 8); + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_set_line_width (cr, 1.); + + T (cr, WIDTH); + + cairo_translate (cr, 0, 2*HEIGHT-16); + cairo_scale (cr, 1, -1); + + T (cr, WIDTH); + + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (shape_sierpinski, + "A fractal triangle", + "stroke", /* keywords */ + NULL, /* requirements */ + WIDTH, 2*HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/shifted-operator.c b/local/recipes/libs/cairo/source/test/shifted-operator.c new file mode 100644 index 0000000000..70eb15b391 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/shifted-operator.c @@ -0,0 +1,58 @@ +/* + * Copyright © 2021 Anton Danilkin + * + * 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. + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *recording_surface = cairo_recording_surface_create (CAIRO_CONTENT_COLOR_ALPHA, NULL); + cairo_t *cr2 = cairo_create (recording_surface); + cairo_translate (cr2, -30, -30); + cairo_rectangle (cr2, 0, 0, 120, 90); + cairo_set_source_rgba (cr2, 0.7, 0, 0, 0.8); + cairo_fill (cr2); + cairo_set_operator (cr2, CAIRO_OPERATOR_XOR); + cairo_rectangle (cr2, 40, 30, 120, 90); + cairo_set_source_rgba (cr2, 0, 0, 0.9, 0.4); + cairo_fill (cr2); + cairo_destroy (cr2); + + cairo_pattern_t *pattern = cairo_pattern_create_for_surface (recording_surface); + cairo_surface_destroy(recording_surface); + cairo_matrix_t matrix; + cairo_matrix_init_translate (&matrix, -30, -30); + cairo_pattern_set_matrix (pattern, &matrix); + cairo_set_source (cr, pattern); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (shifted_operator, + "Test drawing a rectangle shifted into negative coordinates with an operator", + "operator, transform, record", /* keywords */ + NULL, /* requirements */ + 160, 120, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/show-glyphs-advance.c b/local/recipes/libs/cairo/source/test/show-glyphs-advance.c new file mode 100644 index 0000000000..e5abc56c7d --- /dev/null +++ b/local/recipes/libs/cairo/source/test/show-glyphs-advance.c @@ -0,0 +1,107 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * Copyright © 2011 Andrea Canciani + * + * 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: Carl D. Worth + * Andrea Canciani + */ + +#include "cairo-test.h" + +static cairo_test_status_t +get_glyph (const cairo_test_context_t *ctx, + cairo_scaled_font_t *scaled_font, + const char *utf8, + cairo_glyph_t *glyph) +{ + cairo_glyph_t *text_to_glyphs; + cairo_status_t status; + int i; + + text_to_glyphs = glyph; + i = 1; + status = cairo_scaled_font_text_to_glyphs (scaled_font, + 0, 0, + utf8, -1, + &text_to_glyphs, &i, + NULL, NULL, + 0); + if (status != CAIRO_STATUS_SUCCESS) + return cairo_test_status_from_status (ctx, status); + + if (text_to_glyphs != glyph) { + *glyph = text_to_glyphs[0]; + cairo_glyph_free (text_to_glyphs); + } + + return CAIRO_TEST_SUCCESS; +} + +static const char *characters[] = { "A", "B", "C", "D" }; + +#define NUM_CHARS ARRAY_LENGTH (characters) + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_scaled_font_t *scaled_font; + cairo_glyph_t *glyphs = xmalloc (NUM_CHARS * sizeof (cairo_glyph_t)); + int i; + cairo_test_status_t status; + + /* Paint white background. */ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + scaled_font = cairo_get_scaled_font (cr); + + for (i = 0; i < NUM_CHARS; i++) { + status = get_glyph (ctx, scaled_font, characters[i], &glyphs[i]); + if (status) + goto BAIL; + + glyphs[i].x = 10.0 + 10.0 * (i % 2); + glyphs[i].y = 20.0 + 10.0 * (i / 2); + } + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_show_glyphs (cr, glyphs, 4); + + cairo_translate (cr, 40., 20.); + cairo_rotate (cr, M_PI / 4.); + + cairo_show_glyphs (cr, glyphs, NUM_CHARS); + + BAIL: + free(glyphs); + + return status; +} + +CAIRO_TEST (show_glyphs_advance, + "Test that glyph advances work as expected along both axes", + "text, matrix", /* keywords */ + NULL, /* requirements */ + 64, 64, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/show-glyphs-many.c b/local/recipes/libs/cairo/source/test/show-glyphs-many.c new file mode 100644 index 0000000000..e16282cf52 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/show-glyphs-many.c @@ -0,0 +1,176 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +#include + +/* Bug history + * + * 2006-01-07 Jon Hellan + * + * Jon opened the following bug report: + * + * _XError from XRenderCompositeText8 + * https://bugs.freedesktop.org/show_bug.cgi?id=5528 + * + * 2006-03-02 Carl Worth + * + * I wrote this test case to demonstrate the bug. + * + * Approach: + * + * Draw 65535 glyphs white-on-white all on top of each other. + * + * Rationale: + * + * The number 65535 comes from the original bug report. + * + * I would use cairo_show_text with a long string of 'x's say, + * but then the surface would need to be enormous to contain + * them. A smaller surface could be used, but I fear that at some + * point the off-surface glyph drawing would be optimized away + * and not exercise the bug. + * + * So, to keep the surface size under control, I use + * cairo_show_glyphs which allows me to place the glyphs all on + * top of each other. But, since cairo doesn't provide any + * character-to-glyphs mapping, I can't get a reliable glyph + * index (for character 'x' for example). So I just "guess" a + * glyph index and use white-on-white drawing to ignore the + * result. (I don't care what's drawn---I just want to ensure + * that things don't crash.) + * + * Status: I replicated bug. The largest value of NUM_GLYPHS for + * which I saw success is 21842. + * + * 2008-30-08 Chris Wilson + * This is also a valid test case for: + * + * Bug 5913 crash on overlong string + * https://bugs.freedesktop.org/show_bug.cgi?id=5913 + * + * which is still causing a crash in the Xlib backend - presumably, just + * a miscalculation of the length of the available request. + */ + +#define TEXT_SIZE 12 +#define NUM_GLYPHS 65535 + +static cairo_test_status_t +get_glyph (const cairo_test_context_t *ctx, + cairo_scaled_font_t *scaled_font, + const char *utf8, + cairo_glyph_t *glyph) +{ + cairo_glyph_t *text_to_glyphs; + cairo_status_t status; + int i; + + text_to_glyphs = glyph; + i = 1; + status = cairo_scaled_font_text_to_glyphs (scaled_font, + 0, 0, + utf8, -1, + &text_to_glyphs, &i, + NULL, NULL, + 0); + if (status != CAIRO_STATUS_SUCCESS) + return cairo_test_status_from_status (ctx, status); + + if (text_to_glyphs != glyph) { + *glyph = text_to_glyphs[0]; + cairo_glyph_free (text_to_glyphs); + } + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_glyph_t *glyphs = xmalloc (NUM_GLYPHS * sizeof (cairo_glyph_t)); + cairo_scaled_font_t *scaled_font; + const char *characters[] = { /* try to exercise different widths of index */ + "m", /* Latin letter m, index=0x50 */ + "μ", /* Greek letter mu, index=0x349 */ + NULL, + }, **utf8; + int i, j; + cairo_status_t status; + + /* Paint white background. */ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (cr, TEXT_SIZE); + scaled_font = cairo_get_scaled_font (cr); + + for (utf8 = characters; *utf8 != NULL; utf8++) { + status = get_glyph (ctx, scaled_font, *utf8, &glyphs[0]); + if (status) + goto BAIL; + + if (glyphs[0].index) { + glyphs[0].x = 1.0; + glyphs[0].y = height - 1; + for (i=1; i < NUM_GLYPHS; i++) + glyphs[i] = glyphs[0]; + + cairo_show_glyphs (cr, glyphs, NUM_GLYPHS); + } + } + + /* we can pack ~21k 1-byte glyphs into a single XRenderCompositeGlyphs8 */ + status = get_glyph (ctx, scaled_font, "m", &glyphs[0]); + if (status) + goto BAIL; + for (i=1; i < 21500; i++) + glyphs[i] = glyphs[0]; + /* so check expanding the current 1-byte request for 2-byte glyphs */ + status = get_glyph (ctx, scaled_font, "μ", &glyphs[i]); + if (status) + goto BAIL; + for (j=i+1; j < NUM_GLYPHS; j++) + glyphs[j] = glyphs[i]; + + cairo_show_glyphs (cr, glyphs, NUM_GLYPHS); + + BAIL: + free(glyphs); + + return status; +} + +CAIRO_TEST (show_glyphs_many, + "Test that cairo_show_glyphs works when handed 'many' glyphs", + "text, stress", /* keywords */ + NULL, /* requirements */ + 9, 11, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/show-text-current-point.c b/local/recipes/libs/cairo/source/test/show-text-current-point.c new file mode 100644 index 0000000000..2fe32a82de --- /dev/null +++ b/local/recipes/libs/cairo/source/test/show-text-current-point.c @@ -0,0 +1,59 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +#define TEXT_SIZE 12 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + /* We draw in the default black, so paint white first. */ + cairo_save (cr); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_restore (cr); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (cr, TEXT_SIZE); + + cairo_set_source_rgb (cr, 0, 0, 0); /* black */ + + cairo_move_to (cr, 0, TEXT_SIZE); + cairo_show_text (cr, "Hello from the "); + cairo_show_text (cr, "show-text-current-point"); + cairo_show_text (cr, " test."); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (show_text_current_point, + "Test that cairo_show_text adjusts the current point properly", + "text, api", /* keywords */ + NULL, /* requirements */ + 263, TEXT_SIZE + 4, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/simple.c b/local/recipes/libs/cairo/source/test/simple.c new file mode 100644 index 0000000000..7ec8a9ac53 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/simple.c @@ -0,0 +1,347 @@ +/* + * Copyright 2014 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +/* Test the fidelity of the rasterisation, because Cairo is my favourite + * driver test suite. + */ + +#define GENERATE_REFERENCE 0 + +#include "../src/cairo-fixed-type-private.h" + +#if GENERATE_REFERENCE +#include +struct coverage { + int width, height; + struct { + int uncovered_area; + int covered_height; + } cells[0]; +}; + +static int pfloor (int v) +{ + return v >> CAIRO_FIXED_FRAC_BITS; +} + +static int pfrac (int v) +{ + return v & ((1 << CAIRO_FIXED_FRAC_BITS) - 1); +} + +static void add_edge (struct coverage *coverage, + int x1, int y1, int x2, int y2, + int sign) +{ + int dx, dy; + int dxdy_quo, dxdy_rem; + int xq, xr; + int y, t; + + if (y2 < y1) { + t = y1; + y1 = y2; + y2 = t; + + t = x1; + x1 = x2; + x2 = t; + + sign = -sign; + } + + dx = x2 - x1; + dy = y2 - y1; + if (dy == 0) + return; + + dy *= 2; + + dxdy_quo = 2*dx / dy; + dxdy_rem = 2*dx % dy; + + xq = x1 + dxdy_quo / 2; + xr = dxdy_rem / 2; + if (xr < 0) { + xq--; + xr += dy; + } + + for (y = MAX(0, y1); y < MIN(y2, 256*coverage->height); y++) { + int x = xq + (xr >= dy/2); + + if (x < 256*coverage->width) { + int i = pfloor (y) * coverage->width; + if (x > 0) { + i += pfloor (x); + coverage->cells[i].uncovered_area += sign * pfrac(x); + } + coverage->cells[i].covered_height += sign; + } + + xq += dxdy_quo; + xr += dxdy_rem; + if (xr < 0) { + xq--; + xr += dy; + } else if (xr >= dy) { + xq++; + xr -= dy; + } + } +} + +static struct coverage * +coverage_create (int width, int height) +{ + int size; + struct coverage *c; + + size = sizeof (struct coverage); + size += width * height * sizeof (int) * 2; + + c = malloc (size); + if (c == NULL) + return c; + + memset(c, 0, size); + c->width = width; + c->height = height; + + return c; +} + +static cairo_surface_t * +coverage_to_alpha (struct coverage *c) +{ + cairo_surface_t *image; + uint8_t *data; + int x, y, stride; + + image = cairo_image_surface_create (CAIRO_FORMAT_A8, c->width, c->height); + + data = cairo_image_surface_get_data (image); + stride = cairo_image_surface_get_stride (image); + + cairo_surface_flush (image); + for (y = 0; y < c->height; y++) { + uint8_t *row = data + y *stride; + int cover = 0; + for (x = 0; x < c->width; x++) { + int v = y*c->width + x; + + cover += c->cells[v].covered_height * 256; + v = cover - c->cells[v].uncovered_area; + + v /= 256; + if (v < 0) + v = -v; + row[x] = v - (v >> 8); + } + } + cairo_surface_mark_dirty (image); + + free (c); + return image; +} +#endif + +static cairo_test_status_t +edge (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + cairo_paint (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_ADD); + +#if GENERATE_REFERENCE + { + struct coverage *c; + cairo_surface_t *mask; + + cairo_set_source_rgb (cr, 1, 0, 0); + + c = coverage_create (width, height); + add_edge (c, 128*256, 129*256, 129*256, 1*256, 1); + add_edge (c, 128*256, 129*256, 128*256, 131*256, -1); + add_edge (c, 128*256, 131*256, 129*256, 259*256, -1); + add_edge (c, 130*256, 129*256, 129*256, 1*256, -1); + add_edge (c, 130*256, 129*256, 130*256, 131*256, 1); + add_edge (c, 130*256, 131*256, 129*256, 259*256, 1); + mask = coverage_to_alpha (c); + cairo_mask_surface (cr, mask, 0, 0); + cairo_surface_destroy (mask); + + c = coverage_create (width, height); + add_edge (c, 128*256/2, 129*256/2, 129*256/2, 1*256/2, 1); + add_edge (c, 128*256/2, 129*256/2, 128*256/2, 131*256/2, -1); + add_edge (c, 128*256/2, 131*256/2, 129*256/2, 259*256/2, -1); + add_edge (c, 130*256/2, 129*256/2, 129*256/2, 1*256/2, -1); + add_edge (c, 130*256/2, 129*256/2, 130*256/2, 131*256/2, 1); + add_edge (c, 130*256/2, 131*256/2, 129*256/2, 259*256/2, 1); + mask = coverage_to_alpha (c); + cairo_mask_surface (cr, mask, 0, 0); + cairo_surface_destroy (mask); + + c = coverage_create (width, height); + add_edge (c, (192-2)*256, 129*256, 192*256, 1*256, 1); + add_edge (c, (192-2)*256, 129*256, (192-2)*256, 131*256, -1); + add_edge (c, (192-2)*256, 131*256, 192*256, 259*256, -1); + add_edge (c, (192+2)*256, 129*256, 192*256, 1*256, -1); + add_edge (c, (192+2)*256, 129*256, (192+2)*256, 131*256, 1); + add_edge (c, (192+2)*256, 131*256, 192*256, 259*256, 1); + mask = coverage_to_alpha (c); + cairo_mask_surface (cr, mask, 0, 0); + cairo_surface_destroy (mask); + + c = coverage_create (width, height); + add_edge (c, (256-4)*256, 129*256, 256*256, 1*256, 1); + add_edge (c, (256-4)*256, 129*256, (256-4)*256, 131*256, -1); + add_edge (c, (256-4)*256, 131*256, 256*256, 259*256, -1); + add_edge (c, (256+4)*256, 129*256, 256*256, 1*256, -1); + add_edge (c, (256+4)*256, 129*256, (256+4)*256, 131*256, 1); + add_edge (c, (256+4)*256, 131*256, 256*256, 259*256, 1); + mask = coverage_to_alpha (c); + cairo_mask_surface (cr, mask, 0, 0); + cairo_surface_destroy (mask); + + cairo_set_source_rgb (cr, 0, 1, 0); + + c = coverage_create (width, height); + add_edge (c, 1*256, 129*256, 129*256, 128*256, 1); + add_edge (c, 131*256, 128*256, 259*256, 129*256, 1); + add_edge (c, 1*256, 129*256, 129*256, 130*256, -1); + add_edge (c, 131*256, 130*256, 259*256, 129*256, -1); + mask = coverage_to_alpha (c); + cairo_mask_surface (cr, mask, 0, 0); + cairo_surface_destroy (mask); + + c = coverage_create (width, height); + add_edge (c, 1*256/2, 129*256/2, 129*256/2, 128*256/2, 1); + add_edge (c, 131*256/2, 128*256/2, 259*256/2, 129*256/2, 1); + add_edge (c, 1*256/2, 129*256/2, 129*256/2, 130*256/2, -1); + add_edge (c, 131*256/2, 130*256/2, 259*256/2, 129*256/2, -1); + mask = coverage_to_alpha (c); + cairo_mask_surface (cr, mask, 0, 0); + cairo_surface_destroy (mask); + + c = coverage_create (width, height); + add_edge (c, 1*256, (192-0)*256, 129*256, (192-2)*256, 1); + add_edge (c, 131*256, (192-2)*256, 259*256, (192-0)*256, 1); + add_edge (c, 1*256, (192+0)*256, 129*256, (192+2)*256, -1); + add_edge (c, 131*256, (192+2)*256, 259*256, (192+0)*256, -1); + mask = coverage_to_alpha (c); + cairo_mask_surface (cr, mask, 0, 0); + cairo_surface_destroy (mask); + + c = coverage_create (width, height); + add_edge (c, 1*256, (256-0)*256, 129*256, (256-4)*256, 1); + add_edge (c, 131*256, (256-4)*256, 259*256, (256-0)*256, 1); + add_edge (c, 1*256, (256+0)*256, 129*256, (256+4)*256, -1); + add_edge (c, 131*256, (256+4)*256, 259*256, (256+0)*256, -1); + mask = coverage_to_alpha (c); + cairo_mask_surface (cr, mask, 0, 0); + cairo_surface_destroy (mask); + } +#else + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_move_to (cr, 129, 1); + cairo_line_to (cr, 128, 129); + cairo_line_to (cr, 128, 131); + cairo_line_to (cr, 129, 259); + cairo_line_to (cr, 130, 131); + cairo_line_to (cr, 130, 129); + cairo_fill (cr); + + cairo_move_to (cr, 129/2., 1/2.); + cairo_line_to (cr, 128/2., 129/2.); + cairo_line_to (cr, 128/2., 131/2.); + cairo_line_to (cr, 129/2., 259/2.); + cairo_line_to (cr, 130/2., 131/2.); + cairo_line_to (cr, 130/2., 129/2.); + cairo_fill (cr); + + cairo_move_to (cr, 192, 1); + cairo_line_to (cr, 192-2, 129); + cairo_line_to (cr, 192-2, 131); + cairo_line_to (cr, 192, 259); + cairo_line_to (cr, 192+2, 131); + cairo_line_to (cr, 192+2, 129); + cairo_fill (cr); + + cairo_move_to (cr, 256, 1); + cairo_line_to (cr, 256-4, 129); + cairo_line_to (cr, 256-4, 131); + cairo_line_to (cr, 256, 259); + cairo_line_to (cr, 256+4, 131); + cairo_line_to (cr, 256+4, 129); + cairo_fill (cr); + + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_move_to (cr, 1, 129); + cairo_line_to (cr, 129, 128); + cairo_line_to (cr, 131, 128); + cairo_line_to (cr, 259, 129); + cairo_line_to (cr, 131, 130); + cairo_line_to (cr, 129, 130); + cairo_fill (cr); + + cairo_move_to (cr, 1/2., 129/2.); + cairo_line_to (cr, 129/2., 128/2.); + cairo_line_to (cr, 131/2., 128/2.); + cairo_line_to (cr, 259/2., 129/2.); + cairo_line_to (cr, 131/2., 130/2.); + cairo_line_to (cr, 129/2., 130/2.); + cairo_fill (cr); + + cairo_move_to (cr, 1, 192); + cairo_line_to (cr, 129, 192-2); + cairo_line_to (cr, 131, 192-2); + cairo_line_to (cr, 259, 192); + cairo_line_to (cr, 131, 192+2); + cairo_line_to (cr, 129, 192+2); + cairo_fill (cr); + + cairo_move_to (cr, 1, 256); + cairo_line_to (cr, 129, 256-4); + cairo_line_to (cr, 131, 256-4); + cairo_line_to (cr, 259, 256); + cairo_line_to (cr, 131, 256+4); + cairo_line_to (cr, 129, 256+4); + cairo_fill (cr); +#endif + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (simple_edge, + "Check the fidelity of the rasterisation.", + NULL, /* keywords */ + "target=raster", /* requirements */ + 260, 260, + NULL, edge) diff --git a/local/recipes/libs/cairo/source/test/skew-extreme.c b/local/recipes/libs/cairo/source/test/skew-extreme.c new file mode 100644 index 0000000000..e0ee1c4c2d --- /dev/null +++ b/local/recipes/libs/cairo/source/test/skew-extreme.c @@ -0,0 +1,118 @@ +/* + * Copyright © 2007 Red Hat, Inc. + * + * 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: Carl Worth + */ + +#include "cairo-test.h" + +/* This test case is designed to exercise the following bug: + * + * Skew transforms were broken by the cairo update in December + * https://bugzilla.mozilla.org/show_bug.cgi?id=373632 + * + * What's happening is that the rectangle is being skewed into the + * following shape: + * + * a__b + * \ \ + * \ \ + * \ \ + * \ \ + * \ \ + * d\_\c + * + * and the bug is that _cairo_traps_tessellate_convex_quad is + * comparing b.x as less then d.x and therefore determining that the bc + * edge is left of the ad edge. The fix is simply to compare c.x to + * d.x instead of b.x to d.x . + */ + +#define PAD 2 +#define LINE_WIDTH 10 +#define LINE_LENGTH (2 * LINE_WIDTH) +#define SKEW_FACTOR 5.0 +#define WIDTH (PAD + (LINE_LENGTH * SKEW_FACTOR) + LINE_WIDTH + PAD) +#define HEIGHT (PAD + LINE_WIDTH + (LINE_LENGTH * SKEW_FACTOR) + LINE_WIDTH + PAD) + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + /* We draw in the default black, so paint white first. */ + cairo_save (cr); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_restore (cr); + + cairo_translate (cr, PAD, PAD); + + cairo_set_line_width (cr, LINE_WIDTH); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + + cairo_save (cr); + { + cairo_matrix_t skew_x = { + 1.0, 0.0, + SKEW_FACTOR, 1.0, + 0.0, 0.0 + }; + + cairo_translate (cr, LINE_WIDTH / 2.0, 0.0); + + cairo_transform (cr, &skew_x); + + cairo_move_to (cr, 0.0, 0.0); + cairo_line_to (cr, 0.0, LINE_LENGTH); + cairo_stroke (cr); + } + cairo_restore (cr); + + cairo_translate (cr, 0.0, LINE_WIDTH); + + cairo_save (cr); + { + cairo_matrix_t skew_y = { + 1.0, SKEW_FACTOR, + 0.0, 1.0, + 0.0, 0.0 + }; + + cairo_translate (cr, 0.0, LINE_WIDTH / 2.0); + + cairo_transform (cr, &skew_y); + + cairo_move_to (cr, 0.0, 0.0); + cairo_line_to (cr, LINE_LENGTH, 0.0); + cairo_stroke (cr); + } + cairo_restore (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (skew_extreme, + "Test cases of extreme skew.", + "transform, stroke", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/smask-fill.c b/local/recipes/libs/cairo/source/test/smask-fill.c new file mode 100644 index 0000000000..cb3861036d --- /dev/null +++ b/local/recipes/libs/cairo/source/test/smask-fill.c @@ -0,0 +1,73 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *mask; + cairo_pattern_t *pattern; + cairo_t *cr2; + + cairo_set_source_rgb (cr, 0, 0, 1.0); + cairo_paint (cr); + + mask = cairo_surface_create_similar (cairo_get_group_target (cr), + CAIRO_CONTENT_ALPHA, + width, height); + cr2 = cairo_create (mask); + cairo_surface_destroy (mask); + + cairo_save (cr2); { + cairo_set_operator (cr2, CAIRO_OPERATOR_CLEAR); + cairo_paint (cr2); + } cairo_restore (cr2); + + pattern = cairo_pattern_create_linear (0, 0, width, height); + cairo_pattern_add_color_stop_rgba (pattern, 0.00, 0., 0., 0., 0.); + cairo_pattern_add_color_stop_rgba (pattern, 0.25, 1., 1., 1., 1.); + cairo_pattern_add_color_stop_rgba (pattern, 0.50, 1., 1., 1., .5); + cairo_pattern_add_color_stop_rgba (pattern, 0.75, 1., 1., 1., 1.); + cairo_pattern_add_color_stop_rgba (pattern, 1.00, 0., 0., 0., 0.); + cairo_set_source (cr2, pattern); + cairo_pattern_destroy (pattern); + + cairo_arc (cr2, 0.5 * width, 0.5 * height, 0.45 * height, 0, 2 * M_PI); + cairo_fill (cr2); + + cairo_set_source_rgb (cr, 1.0, 0, 0); + cairo_mask_surface (cr, cairo_get_target (cr2), 0, 0); + cairo_destroy (cr2); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (smask_fill, + "Test the support of \"soft\" masks with fills", + "smask, fill", /* keywords */ + NULL, /* requirements */ + 60, 60, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/smask-image-mask.c b/local/recipes/libs/cairo/source/test/smask-image-mask.c new file mode 100644 index 0000000000..3d8b5d5a85 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/smask-image-mask.c @@ -0,0 +1,85 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + uint32_t data[] = { + 0xaa000000, 0x55000000, + 0x55000000, 0xaa000000, + }; + + cairo_surface_t *mask, *mask2; + cairo_pattern_t *pattern; + cairo_t *cr2; + + cairo_set_source_rgb (cr, 0, 0, 1.0); + cairo_paint (cr); + + mask = cairo_surface_create_similar (cairo_get_group_target (cr), + CAIRO_CONTENT_ALPHA, + width, height); + cr2 = cairo_create (mask); + cairo_surface_destroy (mask); + + cairo_save (cr2); { + cairo_set_operator (cr2, CAIRO_OPERATOR_CLEAR); + cairo_paint (cr2); + } cairo_restore (cr2); + + pattern = cairo_pattern_create_linear (0, 0, width, height); + cairo_pattern_add_color_stop_rgba (pattern, 0.00, 0., 0., 0., 0.); + cairo_pattern_add_color_stop_rgba (pattern, 0.25, 1., 1., 1., 1.); + cairo_pattern_add_color_stop_rgba (pattern, 0.50, 1., 1., 1., .5); + cairo_pattern_add_color_stop_rgba (pattern, 0.75, 1., 1., 1., 1.); + cairo_pattern_add_color_stop_rgba (pattern, 1.00, 0., 0., 0., 0.); + cairo_set_source (cr2, pattern); + cairo_pattern_destroy (pattern); + + mask2 = cairo_image_surface_create_for_data ((unsigned char *) data, + CAIRO_FORMAT_ARGB32, 2, 2, 8); + pattern = cairo_pattern_create_for_surface (mask2); + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT); + cairo_mask (cr2, pattern); + cairo_pattern_destroy (pattern); + + cairo_set_source_rgb (cr, 1.0, 0, 0); + cairo_mask_surface (cr, cairo_get_target (cr2), 0, 0); + cairo_destroy (cr2); + + cairo_surface_finish (mask2); /* data will go out of scope */ + cairo_surface_destroy (mask2); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (smask_image_mask, + "Test the support of \"soft\" masks with a secondary image mask", + "smask, image", /* keywords */ + NULL, /* requirements */ + 60, 60, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/smask-mask.c b/local/recipes/libs/cairo/source/test/smask-mask.c new file mode 100644 index 0000000000..11cff82ff2 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/smask-mask.c @@ -0,0 +1,96 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *mask; + cairo_pattern_t *pattern; + cairo_t *cr2, *cr3; + + cairo_set_source_rgb (cr, 0, 0, 1.0); + cairo_paint (cr); + + mask = cairo_surface_create_similar (cairo_get_group_target (cr), + CAIRO_CONTENT_ALPHA, + width, height); + cr2 = cairo_create (mask); + cairo_surface_destroy (mask); + + mask = cairo_surface_create_similar (cairo_get_group_target (cr2), + CAIRO_CONTENT_ALPHA, + width, height); + cr3 = cairo_create (mask); + cairo_surface_destroy (mask); + + cairo_save (cr3); { + cairo_set_operator (cr3, CAIRO_OPERATOR_CLEAR); + cairo_paint (cr3); + } cairo_restore (cr3); + + pattern = cairo_pattern_create_linear (0, 0, width, height); + cairo_pattern_add_color_stop_rgba (pattern, 0.00, 0., 0., 0., 0.); + cairo_pattern_add_color_stop_rgba (pattern, 0.25, 1., 1., 1., 1.); + cairo_pattern_add_color_stop_rgba (pattern, 0.50, 1., 1., 1., .5); + cairo_pattern_add_color_stop_rgba (pattern, 0.75, 1., 1., 1., 1.); + cairo_pattern_add_color_stop_rgba (pattern, 1.00, 0., 0., 0., 0.); + cairo_set_source (cr3, pattern); + cairo_pattern_destroy (pattern); + cairo_paint (cr3); + + + cairo_save (cr2); { + cairo_set_operator (cr2, CAIRO_OPERATOR_CLEAR); + cairo_paint (cr2); + } cairo_restore (cr2); + + pattern = cairo_pattern_create_radial ( + 0.5 * width, 0.5 * height, 0, + 0.5 * width, 0.5 * height, 0.5 *height); + cairo_pattern_add_color_stop_rgba (pattern, 0.00, 0., 0., 0., 0.); + cairo_pattern_add_color_stop_rgba (pattern, 0.25, 1., 1., 1., 1.); + cairo_pattern_add_color_stop_rgba (pattern, 0.50, 1., 1., 1., .5); + cairo_pattern_add_color_stop_rgba (pattern, 1.00, 1., 1., 1., 1.); + cairo_set_source (cr2, pattern); + cairo_pattern_destroy (pattern); + + cairo_mask_surface (cr2, cairo_get_target (cr3), 0, 0); + cairo_destroy (cr3); + + cairo_set_source_rgb (cr, 1.0, 0, 0); + cairo_mask_surface (cr, cairo_get_target (cr2), 0, 0); + cairo_destroy (cr2); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (smask_mask, + "Test the support of \"soft\" masks with a secondary mask", + "smask, mask", /* keywords */ + NULL, /* requirements */ + 60, 60, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/smask-paint.c b/local/recipes/libs/cairo/source/test/smask-paint.c new file mode 100644 index 0000000000..ee781caae1 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/smask-paint.c @@ -0,0 +1,81 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *mask; + cairo_pattern_t *pattern; + cairo_t *cr2; + + mask = cairo_surface_create_similar (cairo_get_group_target (cr), + CAIRO_CONTENT_ALPHA, + width, height); + cr2 = cairo_create (mask); + cairo_surface_destroy (mask); + + cairo_save (cr2); { + cairo_set_operator (cr2, CAIRO_OPERATOR_CLEAR); + cairo_paint (cr2); + } cairo_restore (cr2); + + pattern = cairo_pattern_create_linear (0, 0, width, height); + cairo_pattern_add_color_stop_rgba (pattern, 0.00, 0., 0., 0., 0.); + cairo_pattern_add_color_stop_rgba (pattern, 0.25, 1., 1., 1., 1.); + cairo_pattern_add_color_stop_rgba (pattern, 0.50, 1., 1., 1., .5); + cairo_pattern_add_color_stop_rgba (pattern, 0.75, 1., 1., 1., 1.); + cairo_pattern_add_color_stop_rgba (pattern, 1.00, 0., 0., 0., 0.); + cairo_set_source (cr2, pattern); + cairo_pattern_destroy (pattern); + + cairo_paint (cr2); + + cairo_set_source_rgb (cr, 0, 0, 1.0); + cairo_paint (cr); + + pattern = cairo_pattern_create_radial ( + 0.5 * width, 0.5 * height, 0, + 0.5 * width, 0.5 * height, 0.5 *height); + cairo_pattern_add_color_stop_rgba (pattern, 0.00, 0., 0., 0., 0.); + cairo_pattern_add_color_stop_rgba (pattern, 0.25, 1., 0., 0., 1.); + cairo_pattern_add_color_stop_rgba (pattern, 0.50, 1., 0., 0., .5); + cairo_pattern_add_color_stop_rgba (pattern, 1.00, 1., 0., 0., 1.); + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + + cairo_mask_surface (cr, cairo_get_target (cr2), 0, 0); + cairo_destroy (cr2); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (smask_paint, + "Test the support of \"soft\" masks with paints", + "smask, paint", /* keywords */ + NULL, /* requirements */ + 60, 60, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/smask-stroke.c b/local/recipes/libs/cairo/source/test/smask-stroke.c new file mode 100644 index 0000000000..2a8e7e890e --- /dev/null +++ b/local/recipes/libs/cairo/source/test/smask-stroke.c @@ -0,0 +1,73 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *mask; + cairo_pattern_t *pattern; + cairo_t *cr2; + + cairo_set_source_rgb (cr, 0, 0, 1.0); + cairo_paint (cr); + + mask = cairo_surface_create_similar (cairo_get_group_target (cr), + CAIRO_CONTENT_ALPHA, + width, height); + cr2 = cairo_create (mask); + cairo_surface_destroy (mask); + + cairo_save (cr2); { + cairo_set_operator (cr2, CAIRO_OPERATOR_CLEAR); + cairo_paint (cr2); + } cairo_restore (cr2); + + pattern = cairo_pattern_create_linear (0, 0, width, height); + cairo_pattern_add_color_stop_rgba (pattern, 0.00, 0., 0., 0., 0.); + cairo_pattern_add_color_stop_rgba (pattern, 0.25, 1., 1., 1., 1.); + cairo_pattern_add_color_stop_rgba (pattern, 0.50, 1., 1., 1., .5); + cairo_pattern_add_color_stop_rgba (pattern, 0.75, 1., 1., 1., 1.); + cairo_pattern_add_color_stop_rgba (pattern, 1.00, 0., 0., 0., 0.); + cairo_set_source (cr2, pattern); + cairo_pattern_destroy (pattern); + + cairo_arc (cr2, 0.5 * width, 0.5 * height, 0.4 * height, 0, 2 * M_PI); + cairo_stroke (cr2); + + cairo_set_source_rgb (cr, 1.0, 0, 0); + cairo_mask_surface (cr, cairo_get_target (cr2), 0, 0); + cairo_destroy (cr2); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (smask_stroke, + "Test the support of \"soft\" masks with strokes", + "smask, stroke", /* keywords */ + NULL, /* requirements */ + 60, 60, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/smask-text.c b/local/recipes/libs/cairo/source/test/smask-text.c new file mode 100644 index 0000000000..f36ae26748 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/smask-text.c @@ -0,0 +1,83 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *mask; + cairo_pattern_t *pattern; + cairo_t *cr2; + cairo_text_extents_t extents; + + cairo_set_source_rgb (cr, 0, 0, 1.0); + cairo_paint (cr); + + mask = cairo_surface_create_similar (cairo_get_group_target (cr), + CAIRO_CONTENT_ALPHA, + width, height); + cr2 = cairo_create (mask); + cairo_surface_destroy (mask); + + cairo_save (cr2); { + cairo_set_operator (cr2, CAIRO_OPERATOR_CLEAR); + cairo_paint (cr2); + } cairo_restore (cr2); + + pattern = cairo_pattern_create_linear (0, 0, width, height); + cairo_pattern_add_color_stop_rgba (pattern, 0.00, 0., 0., 0., 0.); + cairo_pattern_add_color_stop_rgba (pattern, 0.25, 1., 1., 1., 1.); + cairo_pattern_add_color_stop_rgba (pattern, 0.50, 1., 1., 1., .5); + cairo_pattern_add_color_stop_rgba (pattern, 0.75, 1., 1., 1., 1.); + cairo_pattern_add_color_stop_rgba (pattern, 1.00, 0., 0., 0., 0.); + cairo_set_source (cr2, pattern); + cairo_pattern_destroy (pattern); + + cairo_select_font_face (cr2, + CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (cr2, 0.5 * height); + + cairo_text_extents (cr2, "cairo", &extents); + cairo_move_to (cr2, + floor ((width - extents.width) / 2 + 0.5) - extents.x_bearing, + floor ((height - extents.height) / 2 - 0.5) - extents.y_bearing); + cairo_show_text (cr2, "cairo"); + + cairo_set_source_rgb (cr, 1.0, 0, 0); + cairo_mask_surface (cr, cairo_get_target (cr2), 0, 0); + cairo_destroy (cr2); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (smask_text, + "Test the support of \"soft\" masks with text", + "smask, text", /* keywords */ + NULL, /* keywords */ + 120, 60, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/smask.c b/local/recipes/libs/cairo/source/test/smask.c new file mode 100644 index 0000000000..4cf3adb2a9 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/smask.c @@ -0,0 +1,123 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + uint32_t data[] = { + 0x80000000, 0x80000000, + 0x80000000, 0x80000000, + }; + + cairo_surface_t *mask, *mask2; + cairo_pattern_t *pattern; + cairo_t *cr2; + cairo_text_extents_t extents; + + mask = cairo_surface_create_similar (cairo_get_group_target (cr), + CAIRO_CONTENT_ALPHA, + width, height); + cr2 = cairo_create (mask); + cairo_surface_destroy (mask); + + cairo_save (cr2); { + cairo_set_operator (cr2, CAIRO_OPERATOR_CLEAR); + cairo_paint (cr2); + } cairo_restore (cr2); + + pattern = cairo_pattern_create_linear (0, 0, 0, height); + cairo_pattern_add_color_stop_rgba (pattern, 0.00, 0., 0., 0., 0.0); + cairo_pattern_add_color_stop_rgba (pattern, 0.80, 0., 0., 0., 0.0); + cairo_pattern_add_color_stop_rgba (pattern, 0.90, 1., 1., 1., 0.25); + cairo_pattern_add_color_stop_rgba (pattern, 1.00, 1., 1., 1., 1.0); + cairo_set_source (cr2, pattern); + cairo_pattern_destroy (pattern); + + cairo_paint (cr2); + + pattern = cairo_pattern_create_linear (0, 0, width, height); + cairo_pattern_add_color_stop_rgba (pattern, 0.00, 0., 0., 0., 0.); + cairo_pattern_add_color_stop_rgba (pattern, 0.25, 1., 1., 1., 1.); + cairo_pattern_add_color_stop_rgba (pattern, 0.50, 1., 1., 1., .5); + cairo_pattern_add_color_stop_rgba (pattern, 0.75, 1., 1., 1., 1.); + cairo_pattern_add_color_stop_rgba (pattern, 1.00, 0., 0., 0., 0.); + cairo_set_source (cr2, pattern); + cairo_pattern_destroy (pattern); + + mask2 = cairo_image_surface_create_for_data ((unsigned char *) data, + CAIRO_FORMAT_ARGB32, 2, 2, 8); + pattern = cairo_pattern_create_for_surface (mask2); + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT); + cairo_mask (cr2, pattern); + cairo_pattern_destroy (pattern); + + cairo_arc (cr2, 0.5 * width, 0.5 * height - 10, 0.2 * height, 0, 2 * M_PI); + cairo_fill (cr2); + + cairo_arc (cr2, 0.5 * width, 0.5 * height - 10, 0.25 * height, 0, 2 * M_PI); + cairo_stroke (cr2); + + cairo_select_font_face (cr2, + CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (cr2, 0.3 * height); + + cairo_text_extents (cr2, "FG", &extents); + cairo_move_to (cr2, + floor ((width - extents.width) / 2 + 0.5) - extents.x_bearing, + floor (height - extents.height - 0.5) - extents.y_bearing - 5); + cairo_show_text (cr2, "FG"); + + cairo_set_source_rgb (cr, 0, 0, 1.0); + cairo_paint (cr); + + pattern = cairo_pattern_create_radial ( + 0.5 * width, 0.5 * height, 0, + 0.5 * width, 0.5 * height, 0.5 *height); + cairo_pattern_add_color_stop_rgba (pattern, 0.00, 0., 0., 0., 0.); + cairo_pattern_add_color_stop_rgba (pattern, 0.25, 1., 0., 0., 1.); + cairo_pattern_add_color_stop_rgba (pattern, 0.50, 1., 0., 0., .5); + cairo_pattern_add_color_stop_rgba (pattern, 1.00, 1., 0., 0., 1.); + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + + cairo_mask_surface (cr, cairo_get_target (cr2), 0, 0); + cairo_destroy (cr2); + + cairo_surface_finish (mask2); /* data will go out of scope */ + cairo_surface_destroy (mask2); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (smask, + "Test the support of \"soft\" masks", + "smask", /* keywords */ + NULL, /* requirements */ + 60, 60, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/smp-glyph.c b/local/recipes/libs/cairo/source/test/smp-glyph.c new file mode 100644 index 0000000000..486c43ebb3 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/smp-glyph.c @@ -0,0 +1,56 @@ +/* + * Copyright © 2017 Andrea Canciani + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Andrea Canciani not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Andrea Canciani makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * ANDREA CANCIANI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL ANDREA CANCIANI BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Andrea Canciani + */ + +#include "cairo-test.h" + +#define TEXT_SIZE 42 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0, 0, 0); /* black */ + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + + cairo_set_font_size (cr, TEXT_SIZE); + cairo_translate (cr, 0, TEXT_SIZE); + + /* U+1F030, DOMINO TILE HORIZONTAL BACK */ + cairo_show_text (cr, "\xf0\x9f\x80\xb0"); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (smp_glyph, + "Test glyphs for symbols in the Supplementary Multilingual Plane", + "text, glyphs", /* keywords */ + NULL, /* requirements */ + 64, 64, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/solid-pattern-cache-stress.c b/local/recipes/libs/cairo/source/test/solid-pattern-cache-stress.c new file mode 100644 index 0000000000..56972bfaf8 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/solid-pattern-cache-stress.c @@ -0,0 +1,210 @@ +/* + * Copyright © 2007 Chris Wilson. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson. Not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "config.h" + +#include "cairo-test.h" +#include /* drand48() */ + +#define LOOPS 10 +#define NRAND 100 + +#ifndef HAVE_DRAND48 +#define drand48() (rand () / (double) RAND_MAX) +#endif + +static cairo_scaled_font_t *scaled_font; + +static cairo_t * +_cairo_create_similar (cairo_t *cr, int width, int height) +{ + cairo_surface_t *similar; + + similar = cairo_surface_create_similar (cairo_get_target (cr), + cairo_surface_get_content (cairo_get_target (cr)), + width, height); + cr = cairo_create (similar); + cairo_surface_destroy (similar); + + return cr; +} + +static cairo_t * +_cairo_create_image (cairo_t *cr, cairo_format_t format, int width, int height) +{ + cairo_surface_t *image; + + image = cairo_image_surface_create (format, width, height); + cr = cairo_create (image); + cairo_surface_destroy (image); + + return cr; +} + +static void +_propagate_status (cairo_t *dst, cairo_t *src) +{ + cairo_path_t path; + + path.status = cairo_status (src); + if (path.status) { + path.num_data = 0; + path.data = NULL; + cairo_append_path (dst, &path); + } +} + +static void +_draw (cairo_t *cr, + double red, + double green, + double blue) +{ + cairo_text_extents_t extents; + + cairo_set_source_rgb (cr, red, green, blue); + cairo_paint (cr); + + cairo_move_to (cr, 0, 0); + cairo_line_to (cr, 1, 1); + cairo_stroke (cr); + + cairo_mask (cr, cairo_get_source (cr)); + + cairo_set_scaled_font (cr, scaled_font); + cairo_text_extents (cr, "cairo", &extents); + cairo_move_to (cr, + -extents.x_bearing - .5 * extents.width, + -extents.y_bearing - .5 * extents.height); + cairo_show_text (cr, "cairo"); +} + +static void +use_similar (cairo_t *cr, + double red, + double green, + double blue) +{ + cairo_t *cr2; + + if (cairo_status (cr)) + return; + + cr2 = _cairo_create_similar (cr, 1, 1); + + _draw (cr2, red, green, blue); + + _propagate_status (cr, cr2); + cairo_destroy (cr2); +} + +static void +use_image (cairo_t *cr, + cairo_format_t format, + double red, + double green, + double blue) +{ + cairo_t *cr2; + + if (cairo_status (cr)) + return; + + cr2 = _cairo_create_image (cr, format, 1, 1); + + _draw (cr2, red, green, blue); + + _propagate_status (cr, cr2); + cairo_destroy (cr2); +} + +static void +use_solid (cairo_t *cr, + double red, + double green, + double blue) +{ + /* mix in dissimilar solids */ + use_image (cr, CAIRO_FORMAT_A1, red, green, blue); + use_image (cr, CAIRO_FORMAT_A8, red, green, blue); + use_image (cr, CAIRO_FORMAT_RGB24, red, green, blue); + use_image (cr, CAIRO_FORMAT_ARGB32, red, green, blue); + + use_similar (cr, red, green, blue); + + _draw (cr, red, green, blue); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_status_t status; + const double colors[8][3] = { + { 1.0, 0.0, 0.0 }, /* red */ + { 0.0, 1.0, 0.0 }, /* green */ + { 1.0, 1.0, 0.0 }, /* yellow */ + { 0.0, 0.0, 1.0 }, /* blue */ + { 1.0, 0.0, 1.0 }, /* magenta */ + { 0.0, 1.0, 1.0 }, /* cyan */ + { 1.0, 1.0, 1.0 }, /* white */ + { 0.0, 0.0, 0.0 }, /* black */ + }; + int i, j, loop; + + /* cache a resolved scaled-font */ + scaled_font = cairo_get_scaled_font (cr); + + for (loop = 0; loop < LOOPS; loop++) { + for (i = 0; i < LOOPS; i++) { + for (j = 0; j < 8; j++) { + use_solid (cr, colors[j][0], colors[j][1], colors[j][2]); + status = cairo_status (cr); + if (status) + return cairo_test_status_from_status (ctx, status); + } + } + + for (i = 0; i < NRAND; i++) { + use_solid (cr, drand48 (), drand48 (), drand48 ()); + status = cairo_status (cr); + if (status) + return cairo_test_status_from_status (ctx, status); + } + } + + /* stress test only, so clear the surface before comparing */ + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (solid_pattern_cache_stress, + "Stress the solid pattern cache and ensure it behaves", + "stress", /* keywords */ + NULL, /* requirements */ + 1, 1, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/source-clip-scale.c b/local/recipes/libs/cairo/source/test/source-clip-scale.c new file mode 100644 index 0000000000..4eca2061cf --- /dev/null +++ b/local/recipes/libs/cairo/source/test/source-clip-scale.c @@ -0,0 +1,82 @@ +/* + * Copyright © 2005 Mozilla Corporation + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Mozilla Corporation not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Mozilla Corporation makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * MOZILLA CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL MOZILLA CORPORATION BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Vladimir Vukicevic + */ + +#include "cairo-test.h" +#include +#include + +#define SIZE 12 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *source; + cairo_t *cr2; + + source = cairo_surface_create_similar (cairo_get_group_target (cr), + CAIRO_CONTENT_COLOR_ALPHA, + SIZE, SIZE); + cr2 = cairo_create (source); + cairo_surface_destroy (source); + + /* Fill the source surface with green */ + cairo_set_source_rgb (cr2, 0, 1, 0); + cairo_paint (cr2); + + /* Draw a blue square in the middle of the source with clipping. + * Note that we are only clipping within a save/restore block but + * the buggy behavior demonstrates that the clip remains present + * on the surface. */ + cairo_save (cr2); + cairo_rectangle (cr2, + SIZE / 4, SIZE / 4, + SIZE / 2, SIZE / 2); + cairo_clip (cr2); + cairo_set_source_rgb (cr2, 0, 0, 1); + cairo_paint (cr2); + cairo_restore (cr2); + + /* Fill the destination surface with solid red (should not appear + * in final result) */ + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_paint (cr); + + /* Now draw the source surface onto the destination with scaling. */ + cairo_scale (cr, 2.0, 1.0); + + cairo_set_source_surface (cr, cairo_get_target (cr2), 0, 0); + cairo_destroy (cr2); + + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (source_clip_scale, + "Test that a source surface is not affected by a clip when scaling", + "clip", /* keywords */ + NULL, /* requirements */ + SIZE * 2, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/source-clip.c b/local/recipes/libs/cairo/source/test/source-clip.c new file mode 100644 index 0000000000..0c00070b1e --- /dev/null +++ b/local/recipes/libs/cairo/source/test/source-clip.c @@ -0,0 +1,77 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Owen Taylor + */ + +#include "cairo-test.h" +#include +#include + +#define SIZE 12 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *source; + cairo_t *cr2; + + source = cairo_surface_create_similar (cairo_get_group_target (cr), + CAIRO_CONTENT_COLOR_ALPHA, + SIZE, SIZE); + + cr2 = cairo_create (source); + cairo_surface_destroy (source); + + /* Fill the source surface with green */ + cairo_set_source_rgb (cr2, 0, 1, 0); + cairo_paint (cr2); + + /* Draw a blue square in the middle of the source with clipping, + * and leave the clip there. */ + cairo_rectangle (cr2, + SIZE / 4, SIZE / 4, + SIZE / 2, SIZE / 2); + cairo_clip (cr2); + cairo_set_source_rgb (cr2, 0, 0, 1); + cairo_paint (cr2); + + /* Fill the destination surface with solid red (should not appear + * in final result) */ + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_paint (cr); + + /* Now draw the source surface onto the destination surface */ + cairo_set_source_surface (cr, cairo_get_target (cr2), 0, 0); + cairo_paint (cr); + + cairo_destroy (cr2); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (source_clip, + "Test that a source surface is not affected by a clip", + "clip", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/source-surface-scale-paint.c b/local/recipes/libs/cairo/source/test/source-surface-scale-paint.c new file mode 100644 index 0000000000..4ac62490aa --- /dev/null +++ b/local/recipes/libs/cairo/source/test/source-surface-scale-paint.c @@ -0,0 +1,59 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface; + uint32_t data[16] = { + 0xffffffff, 0xffffffff, 0xffff0000, 0xffff0000, + 0xffffffff, 0xffffffff, 0xffff0000, 0xffff0000, + + 0xff00ff00, 0xff00ff00, 0xff0000ff, 0xff0000ff, + 0xff00ff00, 0xff00ff00, 0xff0000ff, 0xff0000ff + }; + + surface = cairo_image_surface_create_for_data ((unsigned char *) data, + CAIRO_FORMAT_RGB24, 4, 4, 16); + + cairo_set_source_surface (cr, surface, 2, 2); + cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); + cairo_scale (cr, 2, 2); + cairo_paint (cr); + + cairo_surface_finish (surface); /* data will go out of scope */ + cairo_surface_destroy (surface); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (source_surface_scale_paint, + "Test call sequence: cairo_set_source_surface; cairo_scale; cairo_paint", + "transform, paint", /* keywords */ + NULL, /* requirements */ + 8, 8, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/spline-decomposition.c b/local/recipes/libs/cairo/source/test/spline-decomposition.c new file mode 100644 index 0000000000..ea8f26f23c --- /dev/null +++ b/local/recipes/libs/cairo/source/test/spline-decomposition.c @@ -0,0 +1,471 @@ +/* + * Copyright 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +typedef struct _point { + double x,y; +} point_t; + +typedef struct _knots { + point_t a,b,c,d; +} knots_t; + +static knots_t knots[5] = { + { {0, 0}, {0, 100}, {100, 100}, {100, 0} }, + { {0, 0}, {75, 100}, {25, 100}, {100, 0} }, + { {0, 0}, {100, 100}, {0, 100}, {100, 0} }, + { {0, 0}, {150, 100}, {-50, 100}, {100, 0} }, + { {0, 0}, {100, 200}, {0, -100}, {100, 100} }, +}; + +#ifdef REFERENCE +static void +_lerp_half (const point_t *a, const point_t *b, point_t *result) +{ + result->x = .5 * (a->x + b->x); + result->y = .5 * (a->y + b->y); +} + +static void +_de_casteljau (knots_t *k1, knots_t *k2) +{ + point_t ab, bc, cd; + point_t abbc, bccd; + point_t final; + + _lerp_half (&k1->a, &k1->b, &ab); + _lerp_half (&k1->b, &k1->c, &bc); + _lerp_half (&k1->c, &k1->d, &cd); + _lerp_half (&ab, &bc, &abbc); + _lerp_half (&bc, &cd, &bccd); + _lerp_half (&abbc, &bccd, &final); + + k2->a = final; + k2->b = bccd; + k2->c = cd; + k2->d = k1->d; + + k1->b = ab; + k1->c = abbc; + k1->d = final; +} + +static double +_spline_error_squared (const knots_t *knots) +{ + double bdx, bdy, berr; + double cdx, cdy, cerr; + double dx, dy, v; + + /* Intersection point (px): + * px = p1 + u(p2 - p1) + * (p - px) ∙ (p2 - p1) = 0 + * Thus: + * u = ((p - p1) ∙ (p2 - p1)) / ∥p2 - p1∥²; + */ + bdx = knots->b.x - knots->a.x; + bdy = knots->b.y - knots->a.y; + + cdx = knots->c.x - knots->a.x; + cdy = knots->c.y - knots->a.y; + + dx = knots->d.x - knots->a.x; + dy = knots->d.y - knots->a.y; + v = dx * dx + dy * dy; + if (v != 0.) { + double u; + + u = bdx * dx + bdy * dy; + if (u <= 0) { + /* bdx -= 0; + * bdy -= 0; + */ + } else if (u >= v) { + bdx -= dx; + bdy -= dy; + } else { + bdx -= u/v * dx; + bdy -= u/v * dy; + } + + u = cdx * dx + cdy * dy; + if (u <= 0) { + /* cdx -= 0; + * cdy -= 0; + */ + } else if (u >= v) { + cdx -= dx; + cdy -= dy; + } else { + cdx -= u/v * dx; + cdy -= u/v * dy; + } + } + + berr = bdx * bdx + bdy * bdy; + cerr = cdx * cdx + cdy * cdy; + if (berr > cerr) + return berr * v; + else + return cerr * v; +} + +static void +_offset_line_to (cairo_t *cr, + const point_t *p0, + const point_t *p1, + const point_t *p2, + const point_t *p3, + double offset) +{ + double dx, dy, v; + + dx = p1->x - p0->x; + dy = p1->y - p0->y; + v = hypot (dx, dy); + if (v == 0) { + dx = p2->x - p0->x; + dy = p2->y - p0->y; + v = hypot (dx, dy); + if (v == 0) { + dx = p3->x - p0->x; + dy = p3->y - p0->y; + v = hypot (dx, dy); + } + } + + if (v == 0) { + cairo_line_to (cr, p0->x, p0->y); + } else + cairo_line_to (cr, p0->x - offset * dy / v, p0->y + offset * dx / v); +} + +static void +_spline_decompose_into (knots_t *k1, + double tolerance_squared, + double offset, + cairo_t *cr) +{ + knots_t k2; + + if (_spline_error_squared (k1) < tolerance_squared) { + _offset_line_to (cr, &k1->a, &k1->b, &k1->c, &k1->d, offset); + return; + } + + _de_casteljau (k1, &k2); + + _spline_decompose_into (k1, tolerance_squared, offset, cr); + _spline_decompose_into (&k2, tolerance_squared, offset, cr); +} + +static void +_spline_decompose (const knots_t *knots, + double tolerance, double offset, + cairo_t *cr) +{ + knots_t k; + + k = *knots; + _spline_decompose_into (&k, tolerance * tolerance, offset, cr); + + _offset_line_to (cr, &knots->d, &knots->c, &knots->b, &knots->a, -offset); +} + +static void +_knots_reverse (knots_t *knots) +{ + point_t tmp; + + tmp = knots->a; + knots->a = knots->d; + knots->d = tmp; + + tmp = knots->b; + knots->b = knots->c; + knots->c = tmp; +} + +static void +thick_splines (cairo_t *cr, double offset) +{ + knots_t k; + + cairo_save (cr); + cairo_translate (cr, 15, 15); + + k = knots[0]; + + cairo_new_path (cr); + _spline_decompose (&k, .1, offset, cr); + _knots_reverse (&k); + _spline_decompose (&k, .1, offset, cr); + cairo_close_path (cr); + cairo_fill (cr); + + cairo_translate (cr, 130, 0); + + k = knots[1]; + + cairo_new_path (cr); + _spline_decompose (&k, .1, offset, cr); + _knots_reverse (&k); + _spline_decompose (&k, .1, offset, cr); + cairo_close_path (cr); + cairo_fill (cr); + + cairo_translate (cr, 130, 0); + + k = knots[2]; + + cairo_new_path (cr); + _spline_decompose (&k, .1, offset, cr); + _knots_reverse (&k); + _spline_decompose (&k, .1, offset, cr); + cairo_close_path (cr); + cairo_fill (cr); + + cairo_translate (cr, -130 - 65, 130); + + k = knots[3]; + + cairo_new_path (cr); + _spline_decompose (&k, .1, offset, cr); + _knots_reverse (&k); + _spline_decompose (&k, .1, offset, cr); + cairo_close_path (cr); + cairo_fill (cr); + + cairo_translate (cr, 130, 0); + + k = knots[4]; + + cairo_new_path (cr); + _spline_decompose (&k, .1, offset, cr); + _knots_reverse (&k); + _spline_decompose (&k, .1, offset, cr); + cairo_close_path (cr); + cairo_fill (cr); + cairo_restore (cr); +} + +static void +thin_splines (cairo_t *cr) +{ + cairo_save (cr); + cairo_translate (cr, 15, 15); + + cairo_new_path (cr); + _spline_decompose (&knots[0], .1, 0, cr); + cairo_stroke (cr); + + cairo_translate (cr, 130, 0); + + cairo_new_path (cr); + _spline_decompose (&knots[1], .1, 0, cr); + cairo_stroke (cr); + + cairo_translate (cr, 130, 0); + + cairo_new_path (cr); + _spline_decompose (&knots[2], .1, 0, cr); + cairo_stroke (cr); + + cairo_translate (cr, -130 - 65, 130); + + cairo_new_path (cr); + _spline_decompose (&knots[3], .1, 0, cr); + cairo_stroke (cr); + + cairo_translate (cr, 130, 0); + + cairo_new_path (cr); + _spline_decompose (&knots[4], .1, 0, cr); + cairo_stroke (cr); + cairo_restore (cr); +} +#endif + +static void +draw_bbox (cairo_t *cr, double x0, double y0, double x1, double y1) +{ + cairo_rectangle (cr, + floor (x0) + .5, floor (y0) + .5, + ceil (x1) - floor (x0), ceil (y1) - floor (y0)); + cairo_stroke (cr); +} + +static void +stroke_splines (cairo_t *cr) +{ + double stroke_x0, stroke_x1, stroke_y0, stroke_y1; + double path_x0, path_x1, path_y0, path_y1; + + cairo_save (cr); + cairo_translate (cr, 15, 15); + + cairo_new_path (cr); + cairo_move_to (cr, + knots[0].a.x, knots[0].a.y); + cairo_curve_to (cr, + knots[0].b.x, knots[0].b.y, + knots[0].c.x, knots[0].c.y, + knots[0].d.x, knots[0].d.y); + cairo_stroke_extents (cr, &stroke_x0, &stroke_y0, &stroke_x1, &stroke_y1); + cairo_path_extents (cr, &path_x0, &path_y0, &path_x1, &path_y1); + cairo_stroke (cr); + + cairo_save (cr); { + cairo_set_line_width (cr, 1); + cairo_set_source_rgb (cr, 1, 0, 0); + draw_bbox (cr, stroke_x0, stroke_y0, stroke_x1, stroke_y1); + cairo_set_source_rgb (cr, 0, 0, 1); + draw_bbox (cr, path_x0, path_y0, path_x1, path_y1); + } cairo_restore (cr); + + cairo_translate (cr, 130, 0); + + cairo_new_path (cr); + cairo_move_to (cr, + knots[1].a.x, knots[1].a.y); + cairo_curve_to (cr, + knots[1].b.x, knots[1].b.y, + knots[1].c.x, knots[1].c.y, + knots[1].d.x, knots[1].d.y); + cairo_stroke_extents (cr, &stroke_x0, &stroke_y0, &stroke_x1, &stroke_y1); + cairo_path_extents (cr, &path_x0, &path_y0, &path_x1, &path_y1); + cairo_stroke (cr); + + cairo_save (cr); { + cairo_set_line_width (cr, 1); + cairo_set_source_rgb (cr, 1, 0, 0); + draw_bbox (cr, stroke_x0, stroke_y0, stroke_x1, stroke_y1); + cairo_set_source_rgb (cr, 0, 0, 1); + draw_bbox (cr, path_x0, path_y0, path_x1, path_y1); + } cairo_restore (cr); + + cairo_translate (cr, 130, 0); + + cairo_new_path (cr); + cairo_move_to (cr, + knots[2].a.x, knots[2].a.y); + cairo_curve_to (cr, + knots[2].b.x, knots[2].b.y, + knots[2].c.x, knots[2].c.y, + knots[2].d.x, knots[2].d.y); + cairo_stroke_extents (cr, &stroke_x0, &stroke_y0, &stroke_x1, &stroke_y1); + cairo_path_extents (cr, &path_x0, &path_y0, &path_x1, &path_y1); + cairo_stroke (cr); + + cairo_save (cr); { + cairo_set_line_width (cr, 1); + cairo_set_source_rgb (cr, 1, 0, 0); + draw_bbox (cr, stroke_x0, stroke_y0, stroke_x1, stroke_y1); + cairo_set_source_rgb (cr, 0, 0, 1); + draw_bbox (cr, path_x0, path_y0, path_x1, path_y1); + } cairo_restore (cr); + + cairo_translate (cr, -130 - 65, 130); + + cairo_new_path (cr); + cairo_move_to (cr, + knots[3].a.x, knots[3].a.y); + cairo_curve_to (cr, + knots[3].b.x, knots[3].b.y, + knots[3].c.x, knots[3].c.y, + knots[3].d.x, knots[3].d.y); + cairo_stroke_extents (cr, &stroke_x0, &stroke_y0, &stroke_x1, &stroke_y1); + cairo_path_extents (cr, &path_x0, &path_y0, &path_x1, &path_y1); + cairo_stroke (cr); + + cairo_save (cr); { + cairo_set_line_width (cr, 1); + cairo_set_source_rgb (cr, 1, 0, 0); + draw_bbox (cr, stroke_x0, stroke_y0, stroke_x1, stroke_y1); + cairo_set_source_rgb (cr, 0, 0, 1); + draw_bbox (cr, path_x0, path_y0, path_x1, path_y1); + } cairo_restore (cr); + + cairo_translate (cr, 130, 0); + + cairo_new_path (cr); + cairo_move_to (cr, + knots[4].a.x, knots[4].a.y); + cairo_curve_to (cr, + knots[4].b.x, knots[4].b.y, + knots[4].c.x, knots[4].c.y, + knots[4].d.x, knots[4].d.y); + cairo_stroke_extents (cr, &stroke_x0, &stroke_y0, &stroke_x1, &stroke_y1); + cairo_path_extents (cr, &path_x0, &path_y0, &path_x1, &path_y1); + cairo_stroke (cr); + + cairo_save (cr); { + cairo_set_line_width (cr, 1); + cairo_set_source_rgb (cr, 1, 0, 0); + draw_bbox (cr, stroke_x0, stroke_y0, stroke_x1, stroke_y1); + cairo_set_source_rgb (cr, 0, 0, 1); + draw_bbox (cr, path_x0, path_y0, path_x1, path_y1); + } cairo_restore (cr); + + cairo_restore (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + +#ifdef REFERENCE + cairo_set_source_rgb (cr, 0, 0, 0); + thick_splines (cr, 5); + + cairo_set_source_rgb (cr, 1, 1, 1); + thin_splines (cr); +#endif + + /* + * Use a high tolerance to reduce dependence upon algorithm used for + * spline decomposition. + */ + cairo_set_tolerance (cr, 0.001); + + cairo_set_line_width (cr, 10); + cairo_set_source_rgb (cr, 0, 0, 0); + stroke_splines (cr); + cairo_set_line_width (cr, 2); + cairo_set_source_rgb (cr, 1, 1, 1); + stroke_splines (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (spline_decomposition, + "Tests splines with various inflection points", + "stroke, spline", /* keywords */ + NULL, /* requirements */ + 390, 260, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/stride-12-image.c b/local/recipes/libs/cairo/source/test/stride-12-image.c new file mode 100644 index 0000000000..5650e98300 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/stride-12-image.c @@ -0,0 +1,71 @@ +/* + * Copyright 2012 Andrea Canciani + * + * 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: Andrea Canciani + */ + +#include "cairo-test.h" + +static const char *png_filename = "romedalen.png"; + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_format_t format = CAIRO_FORMAT_ARGB32; + cairo_t *cr_src; + cairo_surface_t *png, *src; + uint8_t *data; + int stride; + + png = cairo_test_create_surface_from_png (ctx, png_filename); + + stride = cairo_format_stride_for_width (format, width) + 12; + data = xcalloc (stride, height); + src = cairo_image_surface_create_for_data (data, format, + width, height, stride); + + cr_src = cairo_create (src); + cairo_set_source_surface (cr_src, png, 0, 0); + cairo_paint (cr_src); + cairo_destroy (cr_src); + + cairo_set_source_surface (cr, src, 0, 0); + cairo_paint (cr); + + cairo_surface_destroy (png); + + cairo_surface_finish (src); + cairo_surface_destroy (src); + + free (data); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (stride_12_image, + "Test that images with a non-default stride are handled correctly.", + "stride, image", /* keywords */ + NULL, /* requirements */ + 256, 192, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/stroke-clipped.c b/local/recipes/libs/cairo/source/test/stroke-clipped.c new file mode 100644 index 0000000000..4b8079480c --- /dev/null +++ b/local/recipes/libs/cairo/source/test/stroke-clipped.c @@ -0,0 +1,54 @@ +/* + * 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. + */ + +#include "cairo-test.h" + +#define SIZE 200 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + int row; + + cairo_set_source_rgb(cr, 1, 1, 1); + cairo_paint(cr); + + cairo_set_source_rgb(cr, 1, 0, 0); + for(row = 0; row < SIZE; row++) { + cairo_rectangle(cr, 0, row, SIZE, 1); + cairo_clip(cr); + + cairo_arc(cr, SIZE/2, SIZE/2, SIZE/2-8, 0, 2*M_PI); + cairo_stroke(cr); + + cairo_reset_clip(cr); + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (stroke_clipped, + "Check that the stroke is accurately drawn through smaller clips", + "stroke", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/stroke-ctm-caps.c b/local/recipes/libs/cairo/source/test/stroke-ctm-caps.c new file mode 100644 index 0000000000..1bbee83c65 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/stroke-ctm-caps.c @@ -0,0 +1,78 @@ +/* + * Copyright © 2008 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" + +#define SIZE 100 +#define PAD 2 +#define WIDTH (PAD + SIZE + PAD) +#define HEIGHT WIDTH + +/* This test is designed to test that PDF viewers use the correct + * alpha values in an Alpha SMasks. Some viewers use the color values + * instead of the alpha. The test draws a triangle and rectangle in a + * group then draws the group using cairo_mask(). The mask consists of + * a circle with the rgba (0.4, 0.4, 0.4, 0.8) and the background rgba + * (0.8, 0.8, 0.8, 0.4). + */ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + /* flip the CTM, which most clearly shows the problem */ + cairo_translate (cr, 0, HEIGHT); + cairo_scale (cr, 1, -1); + + cairo_set_source_rgb (cr, 0, 0, 0); + + cairo_set_line_width (cr, 10); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); + + cairo_move_to (cr, 20, 20); + cairo_line_to (cr, 20, 70); + cairo_stroke (cr); + + cairo_move_to (cr, 40, 20); + cairo_line_to (cr, 70, 70); + cairo_stroke (cr); + + cairo_move_to (cr, 60, 20); + cairo_line_to (cr, 90, 20); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (stroke_ctm_caps, + "Test that the stroker correctly passes the device-space vector to the stroker for endcaps", + "stroke, transform", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/stroke-image.c b/local/recipes/libs/cairo/source/test/stroke-image.c new file mode 100644 index 0000000000..17e6653ffe --- /dev/null +++ b/local/recipes/libs/cairo/source/test/stroke-image.c @@ -0,0 +1,73 @@ +/* + * Copyright © 2006 Mozilla Corporation + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Mozilla Corporation not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Mozilla Corporation makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * MOZILLA CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL MOZILLA CORPORATION BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Vladimir Vukicevic + */ + +#include "cairo-test.h" + +#define PAD 10 +#define SIZE 100 +#define IMAGE_SIZE (SIZE-PAD*2) +#define LINE_WIDTH 10 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *image; + cairo_t *cr_image; + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + image = cairo_image_surface_create (CAIRO_FORMAT_RGB24, IMAGE_SIZE, IMAGE_SIZE); + cr_image = cairo_create (image); + cairo_surface_destroy (image); + + /* Create the image */ + cairo_set_source_rgb (cr_image, 0, 0, 0); + cairo_paint (cr_image); + cairo_set_source_rgb (cr_image, 0, 1, 0); + cairo_set_line_width (cr_image, LINE_WIDTH); + cairo_arc (cr_image, IMAGE_SIZE/2, IMAGE_SIZE/2, IMAGE_SIZE/2 - LINE_WIDTH/2, 0, M_PI * 2.0); + cairo_stroke (cr_image); + + /* Now stroke with it */ + cairo_translate (cr, PAD, PAD); + + cairo_set_source_surface (cr, cairo_get_target (cr_image), 0, 0); + cairo_destroy (cr_image); + + cairo_new_path (cr); + cairo_set_line_width (cr, LINE_WIDTH); + cairo_arc (cr, IMAGE_SIZE/2, IMAGE_SIZE/2, IMAGE_SIZE/2 - LINE_WIDTH/2, 0, M_PI * 2.0); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (stroke_image, + "Test stroking with an image source, with a non-identity CTM", + "stroke, image, transform", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/stroke-open-box.c b/local/recipes/libs/cairo/source/test/stroke-open-box.c new file mode 100644 index 0000000000..b1dae5090d --- /dev/null +++ b/local/recipes/libs/cairo/source/test/stroke-open-box.c @@ -0,0 +1,51 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright 2011 Simon Kellner + * + * 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: Simon Kellner + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_move_to (cr, 5, 7); + cairo_rel_line_to (cr, 20, 0); + cairo_rel_line_to (cr, 0, 15); + cairo_rel_line_to (cr, -20, 0); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (stroke_open_box, + "Tests stroking of a 3-sided box", + "stroke,box", /* keywords */ + NULL, /* requirements */ + 30, 32, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/stroke-pattern.c b/local/recipes/libs/cairo/source/test/stroke-pattern.c new file mode 100644 index 0000000000..01e10195da --- /dev/null +++ b/local/recipes/libs/cairo/source/test/stroke-pattern.c @@ -0,0 +1,68 @@ +/* + * Copyright © 2011 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" + +#define IMAGE_WIDTH 80 +#define IMAGE_HEIGHT 80 + + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *pattern; + + cairo_test_paint_checkered (cr); + + cairo_scale (cr, 0.3, 0.3); + cairo_translate (cr, 50, 50); + + pattern = cairo_pattern_create_linear (70, 100, 130, 100); + cairo_pattern_add_color_stop_rgba (pattern, 0, 1, 0, 0, 1.0); + cairo_pattern_add_color_stop_rgba (pattern, 1, 0, 1, 0, 0.5); + + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD); + cairo_set_source (cr, pattern); + + cairo_move_to(cr, 20, 20); + cairo_curve_to(cr, + 130, 0, + 70, 200, + 180, 180); + cairo_set_line_width (cr, 20); + cairo_stroke (cr); + + cairo_pattern_destroy (pattern); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (stroke_pattern, + "Patterned stroke", + "stroke, pattern", /* keywords */ + NULL, /* requirements */ + IMAGE_WIDTH, IMAGE_HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/subsurface-image-repeat.c b/local/recipes/libs/cairo/source/test/subsurface-image-repeat.c new file mode 100644 index 0000000000..c741944fb0 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/subsurface-image-repeat.c @@ -0,0 +1,70 @@ +/* + * Copyright 2009 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Intel not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Intel makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * INTEL CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +static const char *png_filename = "romedalen.png"; + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_surface_t *image, *region; + cairo_t *cr_region; + + cairo_set_source_rgb (cr, .5, .5, .5); + cairo_paint (cr); + + /* fill the centre */ + region = cairo_surface_create_for_rectangle (cairo_get_target (cr), + 20, 20, 20, 20); + cr_region = cairo_create (region); + cairo_surface_destroy (region); + + image = cairo_test_create_surface_from_png (ctx, png_filename); + cairo_set_source_surface (cr_region, image, + 10 - cairo_image_surface_get_width (image)/2, + 10 - cairo_image_surface_get_height (image)/2); + cairo_paint (cr_region); + cairo_surface_destroy (image); + + cairo_set_source_surface (cr, cairo_get_target (cr_region), 20, 20); + cairo_destroy (cr_region); + + /* repeat the pattern around the outside, but do not overwrite...*/ + cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT); + cairo_rectangle (cr, 0, 0, width, height); + cairo_rectangle (cr, 20, 40, 20, -20); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (subsurface_image_repeat, + "Tests source (image) clipping with repeat", + "subsurface, image, repeat", /* keywords */ + "target=raster", /* FIXME! recursion bug in subsurface/snapshot (with pdf backend) */ /* requirements */ + 60, 60, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/subsurface-modify-child.c b/local/recipes/libs/cairo/source/test/subsurface-modify-child.c new file mode 100644 index 0000000000..ed94356164 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/subsurface-modify-child.c @@ -0,0 +1,98 @@ +/* + * Copyright 2010 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Intel not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Intel makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * INTEL CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *region, *similar; + cairo_t *cr_region, *cr_similar; + + cairo_set_source_rgb (cr, .5, .5, .5); + cairo_paint (cr); + + similar = cairo_surface_create_similar (cairo_get_target (cr), + CAIRO_CONTENT_COLOR_ALPHA, + 20, 20); + + /* copy the centre */ + cr_similar = cairo_create (similar); + cairo_surface_destroy (similar); + cairo_set_source_surface (cr_similar, cairo_get_target (cr), -20, -20); + cairo_paint (cr_similar); + similar = cairo_surface_reference (cairo_get_target (cr_similar)); + cairo_destroy (cr_similar); + + /* fill the centre */ + region = cairo_surface_create_for_rectangle (cairo_get_target (cr), + 20, 20, 20, 20); + cr_region = cairo_create (region); + cairo_surface_destroy (region); + + cairo_set_source_rgb (cr_region, 1, 1, 1); + cairo_rectangle (cr_region, 0, 0, 10, 10); + cairo_fill (cr_region); + + cairo_set_source_rgb (cr_region, 1, 0, 0); + cairo_rectangle (cr_region, 10, 0, 10, 10); + cairo_fill (cr_region); + + cairo_set_source_rgb (cr_region, 0, 1, 0); + cairo_rectangle (cr_region, 0, 10, 10, 10); + cairo_fill (cr_region); + + cairo_set_source_rgb (cr_region, 0, 0, 1); + cairo_rectangle (cr_region, 10, 10, 10, 10); + cairo_fill (cr_region); + + cairo_destroy (cr_region); + + /* copy the centre, again */ + cr_similar = cairo_create (similar); + cairo_surface_destroy (similar); + cairo_set_source_surface (cr_similar, cairo_get_target (cr), -20, -20); + cairo_paint (cr_similar); + similar = cairo_surface_reference (cairo_get_target (cr_similar)); + cairo_destroy (cr_similar); + + /* repeat the pattern around the outside, but do not overwrite...*/ + cairo_set_source_surface (cr, similar, 20, 20); + cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT); + cairo_rectangle (cr, 0, 0, width, height); + cairo_rectangle (cr, 20, 40, 20, -20); + cairo_fill (cr); + + cairo_surface_destroy (similar); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (subsurface_modify_child, + "Tests source clipping with later modifications", + "subsurface", /* keywords */ + "target=raster", /* FIXME! recursion bug in subsurface/snapshot (with pdf backend) */ /* requirements */ + 60, 60, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/subsurface-modify-parent.c b/local/recipes/libs/cairo/source/test/subsurface-modify-parent.c new file mode 100644 index 0000000000..de16e7530f --- /dev/null +++ b/local/recipes/libs/cairo/source/test/subsurface-modify-parent.c @@ -0,0 +1,78 @@ +/* + * Copyright 2010 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Intel not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Intel makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * INTEL CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *region; + + cairo_set_source_rgb (cr, .5, .5, .5); + cairo_paint (cr); + + /* fill the centre, but through the *original* surface */ + region = cairo_surface_create_for_rectangle (cairo_get_target (cr), + 20, 20, 20, 20); + + /* first trigger a snapshot of the region... */ + cairo_set_source_surface (cr, region, 20, 20); + cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_rectangle (cr, 20, 20, 10, 10); + cairo_fill (cr); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_rectangle (cr, 30, 20, 10, 10); + cairo_fill (cr); + + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_rectangle (cr, 20, 30, 10, 10); + cairo_fill (cr); + + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_rectangle (cr, 30, 30, 10, 10); + cairo_fill (cr); + + cairo_set_source_surface (cr, region, 20, 20); + cairo_surface_destroy (region); + + /* repeat the pattern around the outside, but do not overwrite...*/ + cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT); + cairo_rectangle (cr, 0, 0, width, height); + cairo_rectangle (cr, 20, 40, 20, -20); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (subsurface_modify_parent, + "Tests source clipping with later modifications", + "subsurface", /* keywords */ + "target=raster", /* FIXME! recursion bug in subsurface/snapshot (with pdf backend) */ /* requirements */ + 60, 60, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/subsurface-outside-target.c b/local/recipes/libs/cairo/source/test/subsurface-outside-target.c new file mode 100644 index 0000000000..ef91a2e1c2 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/subsurface-outside-target.c @@ -0,0 +1,177 @@ +/* + * Copyright 2010 Red Hat Inc. + * + * 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: Benjamin Otte + */ + +#include "cairo-test.h" + +#define TARGET_SIZE 10 + +#define SUB_SIZE 15 +#define SUB_OFFSET -5 + +#define PAINT_OFFSET SUB_SIZE +#define PAINT_SIZE (3 * SUB_SIZE) + +static cairo_content_t contents[] = { CAIRO_CONTENT_ALPHA, + CAIRO_CONTENT_COLOR, + CAIRO_CONTENT_COLOR_ALPHA }; + +#define N_CONTENTS ARRAY_LENGTH (contents) +#define N_PADS (CAIRO_EXTEND_PAD + 1) + + +static cairo_surface_t * +create_target (cairo_surface_t *similar_to, + cairo_content_t content) +{ + cairo_surface_t *surface; + cairo_t *cr; + + surface = cairo_surface_create_similar (similar_to, + content, + TARGET_SIZE, TARGET_SIZE); + + cr = cairo_create (surface); + cairo_test_paint_checkered (cr); + cairo_destroy (cr); + + return surface; +} + +static cairo_test_status_t +check_surface_extents (const cairo_test_context_t *ctx, + cairo_surface_t * surface, + double x, + double y, + double width, + double height) +{ + double x1, y1, x2, y2; + cairo_t *cr; + + cr = cairo_create (surface); + cairo_clip_extents (cr, &x1, &y1, &x2, &y2); + cairo_destroy (cr); + + if (x != x1 || + y != y1 || + width != x2 - x1 || + height != y2 - y1) { + cairo_test_log (ctx, + "surface extents should be (%g, %g, %g, %g), but are (%g, %g, %g, %g)\n", + x, y, width, height, + x1, y1, x2 - x1, y2 - y1); + return CAIRO_TEST_FAILURE; + } + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +draw_for_size (cairo_t *cr, + double x, + double y) +{ + cairo_surface_t *target, *subsurface; + cairo_extend_t extend; + cairo_test_status_t check, result = CAIRO_TEST_SUCCESS; + unsigned int content; + + for (content = 0; content < N_CONTENTS; content++) { + cairo_save (cr); + + /* create a target surface for our subsurface */ + target = create_target (cairo_get_target (cr), + contents[content]); + + /* create a subsurface that extends the target surface */ + subsurface = cairo_surface_create_for_rectangle (target, + x, y, + SUB_SIZE, SUB_SIZE); + + /* ensure the extents are ok */ + check = check_surface_extents (cairo_test_get_context (cr), + subsurface, + 0, 0, + SUB_SIZE, SUB_SIZE); + if (result == CAIRO_TEST_SUCCESS) + result = check; + + /* paint this surface with all extend modes. */ + for (extend = 0; extend < N_PADS; extend++) { + cairo_save (cr); + + cairo_rectangle (cr, 0, 0, PAINT_SIZE, PAINT_SIZE); + cairo_clip (cr); + + cairo_set_source_surface (cr, subsurface, PAINT_OFFSET, PAINT_OFFSET); + cairo_pattern_set_extend (cairo_get_source (cr), extend); + cairo_paint (cr); + + cairo_restore (cr); + + cairo_translate (cr, PAINT_SIZE + TARGET_SIZE, 0); + } + + cairo_surface_destroy (subsurface); + cairo_surface_destroy (target); + + cairo_restore (cr); + + cairo_translate (cr, 0, PAINT_SIZE + TARGET_SIZE); + } + + return result; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_test_status_t check, result = CAIRO_TEST_SUCCESS; + + /* paint background in nice gray */ + cairo_set_source_rgb (cr, 0.51613, 0.55555, 0.51613); + cairo_paint (cr); + + /* Use CAIRO_OPERATOR_SOURCE in the tests so we get the actual + * contents of the subsurface */ + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + + result = draw_for_size (cr, SUB_OFFSET, SUB_OFFSET); + + check = draw_for_size (cr, 0, 0); + if (result == CAIRO_TEST_SUCCESS) + result = check; + + return result; +} + +CAIRO_TEST (subsurface_outside_target, + "Tests contents of subsurfaces outside target area", + "subsurface, pad", /* keywords */ + "target=raster", /* FIXME! recursion bug in subsurface/snapshot (with pdf backend) */ /* requirements */ + (PAINT_SIZE + TARGET_SIZE) * N_PADS - TARGET_SIZE, + (PAINT_SIZE + TARGET_SIZE) * N_CONTENTS * 2 - TARGET_SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/subsurface-pad.c b/local/recipes/libs/cairo/source/test/subsurface-pad.c new file mode 100644 index 0000000000..1ac7a0e392 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/subsurface-pad.c @@ -0,0 +1,76 @@ +/* + * Copyright 2009 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Intel not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Intel makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * INTEL CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *region; + cairo_t *cr_region; + + cairo_set_source_rgb (cr, .5, .5, .5); + cairo_paint (cr); + + /* fill the centre */ + region = cairo_surface_create_for_rectangle (cairo_get_target (cr), + 20, 20, 20, 20); + cr_region = cairo_create (region); + cairo_surface_destroy (region); + + cairo_set_source_rgb (cr_region, 1, 1, 1); + cairo_rectangle (cr_region, 0, 0, 10, 10); + cairo_fill (cr_region); + + cairo_set_source_rgb (cr_region, 1, 0, 0); + cairo_rectangle (cr_region, 10, 0, 10, 10); + cairo_fill (cr_region); + + cairo_set_source_rgb (cr_region, 0, 1, 0); + cairo_rectangle (cr_region, 0, 10, 10, 10); + cairo_fill (cr_region); + + cairo_set_source_rgb (cr_region, 0, 0, 1); + cairo_rectangle (cr_region, 10, 10, 10, 10); + cairo_fill (cr_region); + + cairo_set_source_surface (cr, cairo_get_target (cr_region), 20, 20); + cairo_destroy (cr_region); + + /* reflect the pattern around the outside, but do not overwrite...*/ + cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_PAD); + cairo_rectangle (cr, 0, 0, width, height); + cairo_rectangle (cr, 20, 40, 20, -20); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (subsurface_pad, + "Tests source clipping with pad", + "subsurface, pad", /* keywords */ + "target=raster", /* FIXME! recursion bug in subsurface/snapshot (with pdf backend) */ /* requirements */ + 60, 60, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/subsurface-reflect.c b/local/recipes/libs/cairo/source/test/subsurface-reflect.c new file mode 100644 index 0000000000..517106df14 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/subsurface-reflect.c @@ -0,0 +1,76 @@ +/* + * Copyright 2009 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Intel not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Intel makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * INTEL CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *region; + cairo_t *cr_region; + + cairo_set_source_rgb (cr, .5, .5, .5); + cairo_paint (cr); + + /* fill the centre */ + region = cairo_surface_create_for_rectangle (cairo_get_target (cr), + 20, 20, 20, 20); + cr_region = cairo_create (region); + cairo_surface_destroy (region); + + cairo_set_source_rgb (cr_region, 1, 1, 1); + cairo_rectangle (cr_region, 0, 0, 10, 10); + cairo_fill (cr_region); + + cairo_set_source_rgb (cr_region, 1, 0, 0); + cairo_rectangle (cr_region, 10, 0, 10, 10); + cairo_fill (cr_region); + + cairo_set_source_rgb (cr_region, 0, 1, 0); + cairo_rectangle (cr_region, 0, 10, 10, 10); + cairo_fill (cr_region); + + cairo_set_source_rgb (cr_region, 0, 0, 1); + cairo_rectangle (cr_region, 10, 10, 10, 10); + cairo_fill (cr_region); + + cairo_set_source_surface (cr, cairo_get_target (cr_region), 20, 20); + cairo_destroy (cr_region); + + /* reflect the pattern around the outside, but do not overwrite...*/ + cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REFLECT); + cairo_rectangle (cr, 0, 0, width, height); + cairo_rectangle (cr, 20, 40, 20, -20); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (subsurface_reflect, + "Tests source clipping with reflect", + "subsurface, reflect", /* keywords */ + "target=raster", /* FIXME! recursion bug in subsurface/snapshot (with pdf backend) */ /* requirements */ + 60, 60, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/subsurface-repeat.c b/local/recipes/libs/cairo/source/test/subsurface-repeat.c new file mode 100644 index 0000000000..596b97338e --- /dev/null +++ b/local/recipes/libs/cairo/source/test/subsurface-repeat.c @@ -0,0 +1,76 @@ +/* + * Copyright 2009 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Intel not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Intel makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * INTEL CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *region; + cairo_t *cr_region; + + cairo_set_source_rgb (cr, .5, .5, .5); + cairo_paint (cr); + + /* fill the centre */ + region = cairo_surface_create_for_rectangle (cairo_get_target (cr), + 20, 20, 20, 20); + cr_region = cairo_create (region); + cairo_surface_destroy (region); + + cairo_set_source_rgb (cr_region, 1, 1, 1); + cairo_rectangle (cr_region, 0, 0, 10, 10); + cairo_fill (cr_region); + + cairo_set_source_rgb (cr_region, 1, 0, 0); + cairo_rectangle (cr_region, 10, 0, 10, 10); + cairo_fill (cr_region); + + cairo_set_source_rgb (cr_region, 0, 1, 0); + cairo_rectangle (cr_region, 0, 10, 10, 10); + cairo_fill (cr_region); + + cairo_set_source_rgb (cr_region, 0, 0, 1); + cairo_rectangle (cr_region, 10, 10, 10, 10); + cairo_fill (cr_region); + + cairo_set_source_surface (cr, cairo_get_target (cr_region), 20, 20); + cairo_destroy (cr_region); + + /* repeat the pattern around the outside, but do not overwrite...*/ + cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT); + cairo_rectangle (cr, 0, 0, width, height); + cairo_rectangle (cr, 20, 40, 20, -20); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (subsurface_repeat, + "Tests source clipping with repeat", + "subsurface, repeat", /* keywords */ + "target=raster", /* FIXME! recursion bug in subsurface/snapshot (with pdf backend) */ /* requirements */ + 60, 60, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/subsurface-scale.c b/local/recipes/libs/cairo/source/test/subsurface-scale.c new file mode 100644 index 0000000000..9ffd2c4227 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/subsurface-scale.c @@ -0,0 +1,93 @@ +/* + * Copyright 2009 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Intel not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Intel makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * INTEL CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *region[5]; + const char *text = "Cairo"; + int i; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_rectangle (cr, 0, 20, 200, 60); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_fill (cr); + + cairo_set_source_rgb (cr, 0, 0, 0); + + for (i = 0; i < 5; i++) { + cairo_t *cr_region; + cairo_text_extents_t extents; + char buf[2] = { text[i], '\0' }; + + region[i] = cairo_surface_create_for_rectangle (cairo_get_target (cr), + 20 * i, 0, 20, 20); + + cr_region = cairo_create (region[i]); + cairo_surface_destroy (region[i]); + + cairo_select_font_face (cr_region, "@cairo:", + CAIRO_FONT_WEIGHT_NORMAL, + CAIRO_FONT_SLANT_NORMAL); + cairo_set_font_size (cr_region, 20); + cairo_text_extents (cr_region, buf, &extents); + cairo_move_to (cr_region, + 10 - (extents.width/2 + extents.x_bearing), + 10 - (extents.height/2 + extents.y_bearing)); + cairo_show_text (cr_region, buf); + + region[i] = cairo_surface_reference (cairo_get_target (cr_region)); + cairo_destroy (cr_region); + } + + cairo_scale (cr, 2, 2); + for (i = 0; i < 5; i++) { + cairo_set_source_surface (cr, region[5-i-1], 20 * i, 20); + cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_PAD); + cairo_rectangle (cr, 20*i, 20, 20, 20); + cairo_fill (cr); + } + + for (i = 0; i < 5; i++) { + cairo_set_source_surface (cr, region[5-i-1], 20 * i, 40); + cairo_paint_with_alpha (cr, .5); + } + + for (i = 0; i < 5; i++) + cairo_surface_destroy (region[i]); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (subsurface_scale, + "Tests clipping of both source and destination using subsurfaces", + "subsurface", /* keywords */ + "target=raster", /* FIXME! recursion bug in subsurface/snapshot (with pdf backend) */ /* requirements */ + 200, 120, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/subsurface-similar-repeat.c b/local/recipes/libs/cairo/source/test/subsurface-similar-repeat.c new file mode 100644 index 0000000000..011f876e65 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/subsurface-similar-repeat.c @@ -0,0 +1,86 @@ +/* + * Copyright 2009 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Intel not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Intel makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * INTEL CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *similar; + cairo_surface_t *region; + cairo_t *cr_region; + + cairo_set_source_rgb (cr, .5, .5, .5); + cairo_paint (cr); + + similar = cairo_surface_create_similar (cairo_get_target (cr), + CAIRO_CONTENT_COLOR, + 60, 60); + cr_region = cairo_create (similar); + cairo_surface_destroy (similar); + + cairo_set_source_rgb (cr_region, .5, .5, .0); + cairo_paint (cr_region); + similar = cairo_surface_reference (cairo_get_target (cr_region)); + cairo_destroy (cr_region); + + /* fill the centre */ + region = cairo_surface_create_for_rectangle (similar, 20, 20, 20, 20); + cairo_surface_destroy (similar); + + cr_region = cairo_create (region); + cairo_surface_destroy (region); + + cairo_set_source_rgb (cr_region, 1, 1, 1); + cairo_rectangle (cr_region, 0, 0, 10, 10); + cairo_fill (cr_region); + + cairo_set_source_rgb (cr_region, 1, 0, 0); + cairo_rectangle (cr_region, 10, 0, 10, 10); + cairo_fill (cr_region); + + cairo_set_source_rgb (cr_region, 0, 1, 0); + cairo_rectangle (cr_region, 0, 10, 10, 10); + cairo_fill (cr_region); + + cairo_set_source_rgb (cr_region, 0, 0, 1); + cairo_rectangle (cr_region, 10, 10, 10, 10); + cairo_fill (cr_region); + + cairo_set_source_surface (cr, cairo_get_target (cr_region), 20, 20); + cairo_destroy (cr_region); + + cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (subsurface_similar_repeat, + "Tests source clipping through an intermediate with repeat", + "subsurface, repeat", /* keywords */ + "target=raster", /* FIXME! recursion bug in subsurface/snapshot (with pdf backend) */ /* requirements */ + 60, 60, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/subsurface.c b/local/recipes/libs/cairo/source/test/subsurface.c new file mode 100644 index 0000000000..9af2ca06a3 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/subsurface.c @@ -0,0 +1,85 @@ +/* + * Copyright 2009 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Intel not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Intel makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * INTEL CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *region[5]; + const char *text = "Cairo"; + int i; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + + for (i = 0; i < 5; i++) { + cairo_t *cr_region; + cairo_text_extents_t extents; + char buf[2] = { text[i], '\0' }; + + region[i] = cairo_surface_create_for_rectangle (cairo_get_target (cr), + 20 * i, 0, 20, 20); + + cr_region = cairo_create (region[i]); + cairo_surface_destroy (region[i]); + + cairo_select_font_face (cr_region, "@cairo:", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (cr_region, 20); + cairo_text_extents (cr_region, buf, &extents); + cairo_move_to (cr_region, + 10 - (extents.width/2 + extents.x_bearing), + 10 - (extents.height/2 + extents.y_bearing)); + cairo_show_text (cr_region, buf); + + region[i] = cairo_surface_reference (cairo_get_target (cr_region)); + cairo_destroy (cr_region); + } + + for (i = 0; i < 5; i++) { + cairo_set_source_surface (cr, region[5-i-1], 20 * i, 20); + cairo_paint (cr); + } + + for (i = 0; i < 5; i++) { + cairo_set_source_surface (cr, region[5-i-1], 20 * i, 40); + cairo_paint_with_alpha (cr, .5); + } + + for (i = 0; i < 5; i++) + cairo_surface_destroy (region[i]); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (subsurface, + "Tests clipping of both source and destination using subsurfaces", + "subsurface", /* keywords */ + "target=raster", /* FIXME! recursion bug in subsurface/snapshot (with pdf backend) */ /* requirements */ + 100, 60, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/summarize-test-results.sh b/local/recipes/libs/cairo/source/test/summarize-test-results.sh new file mode 100755 index 0000000000..f77c9e1995 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/summarize-test-results.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +# Must be run from inside a test/output directory after a cairo +# test has finished running. + +grep -h ^TEST *.log > results.txt +echo "Results written to results.txt" + +total=$(grep "RESULT:" results.txt | wc -l) +total_pass=$(grep "RESULT: PASS" results.txt | wc -l) +total_fail=$(grep "RESULT: FAIL" results.txt | wc -l) +total_xfail=$(grep "RESULT: XFAIL" results.txt | wc -l) +total_error=$(grep "RESULT: ERROR" results.txt | wc -l) +total_crash=$(grep "RESULT: CRASHED" results.txt | wc -l) +total_untested=$(grep "RESULT: UNTESTED" results.txt | wc -l) +total_calc=$((total_pass + total_fail + total_error + total_xfail + total_crash + total_untested)) + +echo "#######" | tee -a results.txt +echo "# Tests run: $total" | tee -a results.txt +echo "# Passed: $total_pass" | tee -a results.txt +echo "# Failed: $total_fail" | tee -a results.txt +echo "# Expected Failed: $total_xfail" | tee -a results.txt +echo "# Error: $total_error" | tee -a results.txt +echo "# Crashed: $total_crash" | tee -a results.txt +echo "# Untested: $total_untested" | tee -a results.txt +echo "# Total: $total_calc" | tee -a results.txt +echo "#######" | tee -a results.txt + + diff --git a/local/recipes/libs/cairo/source/test/surface-finish-twice.c b/local/recipes/libs/cairo/source/test/surface-finish-twice.c new file mode 100644 index 0000000000..f63b501753 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/surface-finish-twice.c @@ -0,0 +1,79 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl Worth + */ + +/* Bug history + * + * 2005-04-10 stevech1097@yahoo.com.au + * + * Subject: [Bug 2950] New: *** glibc detected *** double free or corruption + * URL: https://bugs.freedesktop.org/show_bug.cgi?id=2950 + * + * The following short program gives the error message: + * + * *** glibc detected *** double free or corruption: 0x082a7268 *** + * Aborted + * + * 2005-04-13 Carl Worth + * + * Looks like surface->finished was never being set. Now fixed. + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_surface_t *surface; + cairo_status_t status; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1); + + cairo_surface_finish (surface); + status = cairo_surface_status (surface); + if (status != CAIRO_STATUS_SUCCESS) + return cairo_test_status_from_status (ctx, status); + + cairo_surface_finish (surface); + status = cairo_surface_status (surface); + if (status != CAIRO_STATUS_SUCCESS) + return cairo_test_status_from_status (ctx, status); + + cairo_surface_finish (surface); + status = cairo_surface_status (surface); + if (status != CAIRO_STATUS_SUCCESS) + return cairo_test_status_from_status (ctx, status); + + cairo_surface_destroy (surface); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (surface_finish_twice, + "Test to exercise a crash when calling cairo_surface_finish twice on the same surface.", + "api", /* keywords */ + NULL, /* requirements */ + 0, 0, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/surface-pattern-big-scale-down.c b/local/recipes/libs/cairo/source/test/surface-pattern-big-scale-down.c new file mode 100644 index 0000000000..698accb6f4 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/surface-pattern-big-scale-down.c @@ -0,0 +1,125 @@ +/* + * Copyright © 2006 Mozilla Corporation + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Mozilla Corporation not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Mozilla Corporation makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * MOZILLA CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL MOZILLA CORPORATION BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Vladimir Vukicevic + */ + +#include "cairo-test.h" + +#define SRC_WIDTH 2048 +#define SRC_HEIGHT 32 + +static cairo_surface_t * +create_source_surface (int w, int h) +{ + cairo_surface_t *surface; + cairo_t *cr; + + surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, SRC_WIDTH, SRC_HEIGHT); + cr = cairo_create (surface); + cairo_surface_destroy (surface); + + cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); + cairo_rectangle (cr, 0, 0, w/2, h/2); + cairo_fill (cr); + + cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); + cairo_rectangle (cr, w/2, 0, w/2, h/2); + cairo_fill (cr); + + cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); + cairo_rectangle (cr, 0, h/2, w/2, h/2); + cairo_fill (cr); + + cairo_set_source_rgb (cr, 1.0, 1.0, 0.0); + cairo_rectangle (cr, w/2, h/2, w/2, h/2); + cairo_fill (cr); + + surface = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + + return surface; +} + +static void +draw_n (cairo_t *cr, cairo_pattern_t *pat, double dest_size, int n) +{ + cairo_matrix_t mat; + + cairo_matrix_init_scale (&mat, SRC_WIDTH / dest_size, SRC_HEIGHT / dest_size); + cairo_matrix_translate (&mat, n * -dest_size, 0.0); + cairo_pattern_set_matrix (pat, &mat); + + cairo_set_source (cr, pat); + cairo_new_path (cr); + cairo_rectangle (cr, n * dest_size, 0.0, dest_size, dest_size); + cairo_fill (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface; + cairo_pattern_t *pat; + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + surface = create_source_surface (SRC_WIDTH, SRC_HEIGHT); + + pat = cairo_pattern_create_for_surface (surface); + cairo_surface_destroy (surface); + + /* We want to draw at a position such that n * SRC_WIDTH * (SRC_WIDTH/16.0) > 32768. + * x = n * 16. + * + * To show the bug, we want to draw on either side of the boundary; + * in our case here, n = 16 results in 32768, and n = 17 results in > 32768. + * + * Drawing at 16 and 17 is sufficient to show the problem. + */ + +#if 1 + /* n = 16 */ + draw_n (cr, pat, 16.0, 16); + + /* n = 17 */ + draw_n (cr, pat, 16.0, 17); +#else + { + int n; + for (n = 0; n < 32; n++) + draw_n (cr, pat, 16.0, n); + } +#endif + + cairo_pattern_destroy (pat); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (surface_pattern_big_scale_down, + "Test scaled-down transformed not-repeated surface patterns with large images and offsets", + "transform", /* keywords */ + NULL, /* requirements */ + 512, 16, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/surface-pattern-operator.c b/local/recipes/libs/cairo/source/test/surface-pattern-operator.c new file mode 100644 index 0000000000..994baf92ea --- /dev/null +++ b/local/recipes/libs/cairo/source/test/surface-pattern-operator.c @@ -0,0 +1,119 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright 2009 Andrea Canciani + * + * 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: Andrea Canciani + */ + +#include "cairo-test.h" + +#define N_OPERATORS (CAIRO_OPERATOR_SATURATE + 1) +#define HEIGHT 16 +#define WIDTH 16 +#define PAD 3 + +static cairo_pattern_t* +_create_pattern (cairo_surface_t *target, cairo_content_t content, int width, int height) +{ + cairo_pattern_t *pattern; + cairo_surface_t *surface; + cairo_t *cr; + + surface = cairo_surface_create_similar (target, content, width, height); + cr = cairo_create (surface); + cairo_surface_destroy (surface); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_arc (cr, 0.5 * width, 0.5 * height, 0.45 * height, -M_PI / 4, 3 * M_PI / 4); + cairo_fill (cr); + + pattern = cairo_pattern_create_for_surface (cairo_get_target (cr)); + cairo_destroy (cr); + + return pattern; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *alpha_pattern, *color_alpha_pattern, *pattern; + unsigned int n, i; + + alpha_pattern = _create_pattern (cairo_get_target (cr), + CAIRO_CONTENT_ALPHA, + 0.9 * WIDTH, 0.9 * HEIGHT); + color_alpha_pattern = _create_pattern (cairo_get_target (cr), + CAIRO_CONTENT_COLOR_ALPHA, + 0.9 * WIDTH, 0.9 * HEIGHT); + + pattern = cairo_pattern_create_linear (WIDTH, 0, 0, HEIGHT); + cairo_pattern_add_color_stop_rgba (pattern, 0.2, 0, 0, 1, 1); + cairo_pattern_add_color_stop_rgba (pattern, 0.8, 0, 0, 1, 0); + + cairo_translate (cr, PAD, PAD); + + for (n = 0; n < N_OPERATORS; n++) { + cairo_save (cr); + for (i = 0; i < 4; i++) { + cairo_reset_clip (cr); + cairo_rectangle (cr, 0, 0, WIDTH, HEIGHT); + cairo_clip (cr); + + cairo_set_source (cr, pattern); + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + if (i & 2) { + cairo_paint (cr); + } else { + cairo_rectangle (cr, WIDTH/2, HEIGHT/2, WIDTH, HEIGHT); + cairo_fill (cr); + } + + cairo_set_source (cr, i & 1 ? alpha_pattern : color_alpha_pattern); + cairo_set_operator (cr, n); + if (i & 2) { + cairo_paint (cr); + } else { + cairo_rectangle (cr, WIDTH/2, HEIGHT/2, WIDTH, HEIGHT); + cairo_fill (cr); + } + + cairo_translate (cr, 0, HEIGHT+PAD); + } + cairo_restore (cr); + + cairo_translate (cr, WIDTH+PAD, 0); + } + + cairo_pattern_destroy (pattern); + cairo_pattern_destroy (alpha_pattern); + cairo_pattern_destroy (color_alpha_pattern); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (surface_pattern_operator, + "Tests alpha-only and alpha-color sources with all operators", + "surface, pattern, operator", /* keywords */ + NULL, /* requirements */ + (WIDTH+PAD) * N_OPERATORS + PAD, 4*HEIGHT + 5*PAD, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/surface-pattern-scale-down-extend.c b/local/recipes/libs/cairo/source/test/surface-pattern-scale-down-extend.c new file mode 100644 index 0000000000..785678dafb --- /dev/null +++ b/local/recipes/libs/cairo/source/test/surface-pattern-scale-down-extend.c @@ -0,0 +1,120 @@ +/* + * Copyright © 2010 M Joonas Pihlaja + * + * 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: M Joonas Pihlaja + */ +#include "cairo-test.h" + +/* Test that we can simultaneously downscale and extend a surface + * pattern. Reported by Franz Schmid to the cairo mailing list as a + * regression in 1.9.6: + * + * https://lists.cairographics.org/archives/cairo/2010-February/019492.html + */ + +static cairo_test_status_t +draw_with_extend (cairo_t *cr, int w, int h, cairo_extend_t extend) +{ + cairo_pattern_t *pattern; + cairo_set_source_rgb (cr, 1,1,1); + cairo_paint (cr); + + cairo_save (cr); + + /* When the destination surface is created by cairo-test-suite to + * test device-offset, it is bigger than w x h. This test expects + * the group to have a size which is exactly w x h, so it must + * clip to the this rectangle to guarantee that the group will + * have the correct size. + */ + cairo_rectangle (cr, 0, 0, w, h); + cairo_clip (cr); + + cairo_push_group_with_content (cr, CAIRO_CONTENT_COLOR); { + /* A two by two checkerboard with black, red and yellow + * cells. */ + cairo_set_source_rgb (cr, 1,0,0); + cairo_rectangle (cr, w/2, 0, w-w/2, h/2); + cairo_fill (cr); + cairo_set_source_rgb (cr, 1,1,0); + cairo_rectangle (cr, 0, h/2, w/2, h-h/2); + cairo_fill (cr); + } + pattern = cairo_pop_group (cr); + cairo_pattern_set_extend(pattern, extend); + + cairo_restore (cr); + + cairo_scale (cr, 0.5, 0.5); + cairo_set_source (cr, pattern); + cairo_paint (cr); + + cairo_pattern_destroy (pattern); + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +draw_repeat (cairo_t *cr, int w, int h) +{ + return draw_with_extend (cr, w, h, CAIRO_EXTEND_REPEAT); +} +static cairo_test_status_t +draw_none (cairo_t *cr, int w, int h) +{ + return draw_with_extend (cr, w, h, CAIRO_EXTEND_NONE); +} +static cairo_test_status_t +draw_reflect (cairo_t *cr, int w, int h) +{ + return draw_with_extend (cr, w, h, CAIRO_EXTEND_REFLECT); +} +static cairo_test_status_t +draw_pad (cairo_t *cr, int w, int h) +{ + return draw_with_extend (cr, w, h, CAIRO_EXTEND_PAD); +} + +CAIRO_TEST (surface_pattern_scale_down_extend_repeat, + "Test interaction of downscaling a surface pattern and extend-repeat", + "pattern, transform, extend", /* keywords */ + NULL, /* requirements */ + 100, 100, + NULL, draw_repeat) +CAIRO_TEST (surface_pattern_scale_down_extend_none, + "Test interaction of downscaling a surface pattern and extend-none", + "pattern, transform, extend", /* keywords */ + NULL, /* requirements */ + 100, 100, + NULL, draw_none) +CAIRO_TEST (surface_pattern_scale_down_extend_reflect, + "Test interaction of downscaling a surface pattern and extend-reflect", + "pattern, transform, extend", /* keywords */ + NULL, /* requirements */ + 100, 100, + NULL, draw_reflect) +CAIRO_TEST (surface_pattern_scale_down_extend_pad, + "Test interaction of downscaling a surface pattern and extend-pad", + "pattern, transform, extend", /* keywords */ + NULL, /* requirements */ + 100, 100, + NULL, draw_pad) diff --git a/local/recipes/libs/cairo/source/test/surface-pattern-scale-down.c b/local/recipes/libs/cairo/source/test/surface-pattern-scale-down.c new file mode 100644 index 0000000000..95782efb18 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/surface-pattern-scale-down.c @@ -0,0 +1,88 @@ +/* + * Copyright © 2007 Red Hat, Inc. + * + * 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: Behdad Esfahbod + */ + +#include "cairo-test.h" +#include +#include + +#define SIZE 200 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface; + cairo_t * cr_surface; + int surface_size = 300; + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + /* Create an image surface with my favorite four colors in each + * quadrant. */ + surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, + surface_size, surface_size); + cr_surface = cairo_create (surface); + cairo_surface_destroy (surface); + + cairo_set_source_rgb (cr_surface, 1, 1, 1); + cairo_rectangle (cr_surface, + 0, 0, + surface_size / 2, surface_size / 2); + cairo_fill (cr_surface); + cairo_set_source_rgb (cr_surface, 1, 0, 0); + cairo_rectangle (cr_surface, + surface_size / 2, 0, + surface_size / 2, surface_size / 2); + cairo_fill (cr_surface); + cairo_set_source_rgb (cr_surface, 0, 1, 0); + cairo_rectangle (cr_surface, + 0, surface_size / 2, + surface_size / 2, surface_size / 2); + cairo_fill (cr_surface); + cairo_set_source_rgb (cr_surface, 0, 0, 1); + cairo_rectangle (cr_surface, + surface_size / 2, surface_size / 2, + surface_size / 2, surface_size / 2); + cairo_fill (cr_surface); + + cairo_scale (cr, 0.2, 0.2); + cairo_rotate (cr, 1.); + cairo_set_source_surface (cr, cairo_get_target (cr_surface), 225, -225); + cairo_destroy (cr_surface); + + cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_NONE); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (surface_pattern_scale_down, + "Test scaled-down transformed not-repeated surface patterns" + "\nFails xlib backend (with argb32) with inexplicable alpha in result", + "transform", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/surface-pattern-scale-up.c b/local/recipes/libs/cairo/source/test/surface-pattern-scale-up.c new file mode 100644 index 0000000000..0d71ba1508 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/surface-pattern-scale-up.c @@ -0,0 +1,93 @@ +/* + * Copyright © 2007 Red Hat, Inc. + * + * 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: Behdad Esfahbod + */ + +/* Exhibits nasty behaviour with GS due as their /Interpolate implementation + * does not function for rotated images. */ + +#include "cairo-test.h" +#include +#include + +#define SIZE 100 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface; + cairo_t * cr_surface; + int surface_size = 6; + + /* Fill the background with grey, so that it's easily visible when + * things get overdrawn */ + cairo_set_source_rgb (cr, 0.5, 0.5, 0.5); + cairo_paint (cr); + + /* Create an image surface with my favorite four colors in each + * quadrant. */ + surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, + surface_size, surface_size); + cr_surface = cairo_create (surface); + cairo_surface_destroy (surface); + + cairo_set_source_rgb (cr_surface, 1, 1, 1); + cairo_rectangle (cr_surface, + 0, 0, + surface_size / 2, surface_size / 2); + cairo_fill (cr_surface); + cairo_set_source_rgb (cr_surface, 1, 0, 0); + cairo_rectangle (cr_surface, + surface_size / 2, 0, + surface_size / 2, surface_size / 2); + cairo_fill (cr_surface); + cairo_set_source_rgb (cr_surface, 0, 1, 0); + cairo_rectangle (cr_surface, + 0, surface_size / 2, + surface_size / 2, surface_size / 2); + cairo_fill (cr_surface); + cairo_set_source_rgb (cr_surface, 0, 0, 1); + cairo_rectangle (cr_surface, + surface_size / 2, surface_size / 2, + surface_size / 2, surface_size / 2); + cairo_fill (cr_surface); + + cairo_scale (cr, 10, 10); + cairo_rotate (cr, 1.); + cairo_set_source_surface (cr, cairo_get_target (cr_surface), 4, -4.5); + cairo_destroy (cr_surface); + + cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_NONE); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (surface_pattern_scale_up, + "Test scaled-up transformed not-repeated surface patterns" + "\nFails xlib backend (with argb32) with inexplicable alpha in result", + "transform", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/surface-pattern.c b/local/recipes/libs/cairo/source/test/surface-pattern.c new file mode 100644 index 0000000000..725f68d000 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/surface-pattern.c @@ -0,0 +1,90 @@ +/* + * Copyright © 2007 Red Hat, Inc. + * + * 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: Behdad Esfahbod + */ + +#include "cairo-test.h" +#include +#include + +#define SIZE 140 +/* Note GhostScript does not support /Interpolate on rotated images, so the PS + * output looks terrible, but is a known issue. */ + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface; + cairo_t * cr_surface; + int surface_size = 6; + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + /* Create an image surface with my favorite four colors in each + * quadrant. */ + surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, + surface_size, surface_size); + cr_surface = cairo_create (surface); + cairo_surface_destroy (surface); + + cairo_set_source_rgb (cr_surface, 1, 1, 1); + cairo_rectangle (cr_surface, + 0, 0, + surface_size / 2, surface_size / 2); + cairo_fill (cr_surface); + cairo_set_source_rgb (cr_surface, 1, 0, 0); + cairo_rectangle (cr_surface, + surface_size / 2, 0, + surface_size / 2, surface_size / 2); + cairo_fill (cr_surface); + cairo_set_source_rgb (cr_surface, 0, 1, 0); + cairo_rectangle (cr_surface, + 0, surface_size / 2, + surface_size / 2, surface_size / 2); + cairo_fill (cr_surface); + cairo_set_source_rgb (cr_surface, 0, 0, 1); + cairo_rectangle (cr_surface, + surface_size / 2, surface_size / 2, + surface_size / 2, surface_size / 2); + cairo_fill (cr_surface); + + cairo_scale (cr, 10, 10); + cairo_rotate (cr, 1.); + cairo_set_source_surface (cr, cairo_get_target (cr_surface), 1.5, 1.5); + cairo_destroy (cr_surface); + + cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (surface_pattern, + "Test transformed repeated surface patterns" + "\nExhibiting a strange (very minor) failure in ps backend with device-offset", + "transform", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/surface-source.c b/local/recipes/libs/cairo/source/test/surface-source.c new file mode 100644 index 0000000000..657a0c88e3 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/surface-source.c @@ -0,0 +1,170 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_surface_t *create_source_surface (int size); + +/* We use a relatively large source to exercise bug: + * Bug 7360 painting huge surfaces fails + * [https://bugs.freedesktop.org/show_bug.cgi?id=7360] + * but still keep the resultant image small for reasonably quick checking. + */ +#define SOURCE_SIZE 2000 +#define INTER_SIZE 512 +#define SIZE 96 + +static void +draw_pattern (cairo_surface_t **surface_inout, int surface_size) +{ + cairo_t *cr; + int mid = surface_size/2; + + cr = cairo_create (*surface_inout); + cairo_surface_destroy (*surface_inout); + + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgba (cr, 0, 0, 0, 0); + cairo_paint (cr); + + cairo_rectangle (cr, 0, 0, surface_size, surface_size); + cairo_rectangle (cr, mid - SIZE/4, mid + SIZE/4, SIZE/2, -SIZE/2); + cairo_clip (cr); + + /* outside squares -> opaque */ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_rectangle (cr, + 0, 0, + surface_size / 2, surface_size / 2); + cairo_fill (cr); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_rectangle (cr, + surface_size / 2, 0, + surface_size / 2, surface_size / 2); + cairo_fill (cr); + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_rectangle (cr, + 0, surface_size / 2, + surface_size / 2, surface_size / 2); + cairo_fill (cr); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_rectangle (cr, + surface_size / 2, surface_size / 2, + surface_size / 2, surface_size / 2); + cairo_fill (cr); + + cairo_reset_clip (cr); + cairo_rectangle (cr, mid - SIZE/4, mid - SIZE/4, SIZE/2, SIZE/2); + cairo_clip (cr); + + /* inside squares -> translucent */ + cairo_set_source_rgba (cr, 0, 0, 1, .5); + cairo_rectangle (cr, + 0, 0, + surface_size / 2, surface_size / 2); + cairo_fill (cr); + cairo_set_source_rgba (cr, 0, 1, 0, .5); + cairo_rectangle (cr, + surface_size / 2, 0, + surface_size / 2, surface_size / 2); + cairo_fill (cr); + cairo_set_source_rgba (cr, 1, 0, 0, .5); + cairo_rectangle (cr, + 0, surface_size / 2, + surface_size / 2, surface_size / 2); + cairo_fill (cr); + cairo_set_source_rgba (cr, 1, 1, 1, .5); + cairo_rectangle (cr, + surface_size / 2, surface_size / 2, + surface_size / 2, surface_size / 2); + cairo_fill (cr); + + + *surface_inout = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface; + cairo_surface_t *similar; + cairo_status_t status; + cairo_t *cr2; + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + surface = create_source_surface (SOURCE_SIZE); + if (surface == NULL) /* can't create the source so skip the test */ + return CAIRO_TEST_UNTESTED; + + draw_pattern (&surface, SOURCE_SIZE); + + /* copy a subregion to a smaller intermediate surface */ + similar = cairo_surface_create_similar (surface, + CAIRO_CONTENT_COLOR_ALPHA, + INTER_SIZE, INTER_SIZE); + cr2 = cairo_create (similar); + cairo_surface_destroy (similar); + cairo_set_source_surface (cr2, surface, + (INTER_SIZE - SOURCE_SIZE)/2, + (INTER_SIZE - SOURCE_SIZE)/2); + cairo_paint (cr2); + + /* and then paint onto a small surface for checking */ + cairo_set_source_surface (cr, cairo_get_target (cr2), + (width - INTER_SIZE)/2, + (height - INTER_SIZE)/2); + cairo_destroy (cr2); + cairo_rectangle (cr, 16, 16, 64, 64); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_fill (cr); + + /* destroy the surface last, as this triggers XCloseDisplay */ + cairo_surface_finish (surface); + status = cairo_surface_status (surface); + cairo_surface_destroy (surface); + + return cairo_test_status_from_status (cairo_test_get_context (cr), + status); +} + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + cairo_surface_t *surface; + cairo_status_t status; + + surface = create_source_surface (SOURCE_SIZE); + if (surface == NULL) /* can't create the source so skip the test */ + return CAIRO_TEST_UNTESTED; + + cairo_surface_finish (surface); + status = cairo_surface_status (surface); + cairo_surface_destroy (surface); + + return cairo_test_status_from_status (ctx, status); +} diff --git a/local/recipes/libs/cairo/source/test/svg-clip.c b/local/recipes/libs/cairo/source/test/svg-clip.c new file mode 100644 index 0000000000..d34144a9c6 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg-clip.c @@ -0,0 +1,152 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Kristian Høgsberg + */ + +#include "cairo-test.h" + +#include + +#include + +/* Test SVG clipping */ + +#define WIDTH_IN_POINTS 600 +#define HEIGHT_IN_POINTS 600 +#define BASENAME "svg-clip.out" + +static void +test_clip (cairo_t *cr, double width, double height) +{ + cairo_t *cr2; + + /* Basic test; set a square clip and draw a circle to be clipped + * against it.*/ + + cairo_rectangle (cr, 100, 100, 400, 400); + cairo_clip (cr); + cairo_arc (cr, 300, 300, 210, 0, 2 * M_PI); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_fill (cr); + + /* Add a plus shaped clip path to the square clip and draw a big + * green square to test the new clip path. */ + + cairo_save (cr); + + cairo_rectangle (cr, 250, 100, 100, 400); + cairo_rectangle (cr, 100, 250, 400, 100); + cairo_clip (cr); + + cairo_rectangle (cr, 0, 0, 600, 600); + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_fill (cr); + + cairo_restore (cr); + + /* Set a bezier shape in addition to the rectangle clip set before + * the cairo_save() to verify that we successfully removed the + * plus shaped clip path and can set a new clip.*/ + + cairo_move_to (cr, 600, 0); + cairo_curve_to (cr, 300, 600, 0, 300, 600, 0); + cairo_clip (cr); + + cairo_rectangle (cr, 0, 0, 600, 600); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_fill (cr); + + /* Create a new context for this surface to test overlapped + * drawing from two contexts */ + cr2 = cairo_create (cairo_get_group_target (cr)); + + /* Using the new context, draw a black vertical line, which should + * appear unclipped on top of everything drawn so far. */ + cairo_move_to (cr2, 110, 0); + cairo_line_to (cr2, 110, 600); + cairo_stroke (cr2); + + /* Using the first context, draw another black vertical line. + * This line should be clipped against the bezier clipping path set + * earlier. */ + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_move_to (cr, 400, 0); + cairo_line_to (cr, 400, 600); + cairo_stroke (cr); + + cairo_destroy (cr2); + + /* Test reset clip. Draw a transparent black circle over + * everything. Specifically, make sure the circle extends outside + * the square clip set at the top of this function. */ + cairo_reset_clip (cr); + cairo_arc (cr, 300, 300, 220, 0, 2 * M_PI); + cairo_set_source_rgba (cr, 0, 0, 0, 0.2); + cairo_fill (cr); +} + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + cairo_t *cr; + cairo_surface_t *surface; + char *filename; + const char *path = cairo_test_mkdir (CAIRO_TEST_OUTPUT_DIR) ? CAIRO_TEST_OUTPUT_DIR : "."; + + if (! cairo_test_is_target_enabled (ctx, "svg11") && + ! cairo_test_is_target_enabled (ctx, "svg12")) + { + return CAIRO_TEST_UNTESTED; + } + + xasprintf (&filename, "%s/%s.svg", path, BASENAME); + surface = cairo_svg_surface_create (filename, + WIDTH_IN_POINTS, HEIGHT_IN_POINTS); + if (cairo_surface_status (surface)) { + cairo_test_log (ctx, + "Failed to create svg surface for file %s: %s\n", + filename, cairo_status_to_string (cairo_surface_status (surface))); + free (filename); + return CAIRO_TEST_FAILURE; + } + + cr = cairo_create (surface); + + test_clip (cr, WIDTH_IN_POINTS, HEIGHT_IN_POINTS); + cairo_show_page (cr); + + cairo_destroy (cr); + cairo_surface_destroy (surface); + + printf ("svg-clip: Please check %s to make sure it looks happy.\n", + filename); + free (filename); + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (svg_clip, + "Test SVG clipping", + "svg, clip", /* keywords */ + NULL, /* requirements */ + 0, 0, + preamble, NULL) diff --git a/local/recipes/libs/cairo/source/test/svg-surface-source.c b/local/recipes/libs/cairo/source/test/svg-surface-source.c new file mode 100644 index 0000000000..3c7730f7f4 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg-surface-source.c @@ -0,0 +1,54 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" +#include + +#include "surface-source.c" + +#define BASENAME "svg-surface-source.out" + +static cairo_surface_t * +create_source_surface (int size) +{ + cairo_surface_t *surface; + char *filename; + const char *path = cairo_test_mkdir (CAIRO_TEST_OUTPUT_DIR) ? CAIRO_TEST_OUTPUT_DIR : "."; + + xasprintf (&filename, "%s/%s.svg", path, BASENAME); + surface = cairo_svg_surface_create (filename, + size, size); + cairo_surface_set_fallback_resolution (surface, 72., 72.); + free (filename); + + return surface; +} + +CAIRO_TEST (svg_surface_source, + "Test using a SVG surface as the source", + "source", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + preamble, draw) diff --git a/local/recipes/libs/cairo/source/test/svg-surface.c b/local/recipes/libs/cairo/source/test/svg-surface.c new file mode 100644 index 0000000000..13b006d397 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg-surface.c @@ -0,0 +1,136 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +#include + +#include + +/* Pretty boring test just to make sure things aren't crashing --- + * no verification that we're getting good results yet. + * But you can manually view the image to make sure it looks happy. + */ + +#define WIDTH_IN_INCHES 3 +#define HEIGHT_IN_INCHES 3 +#define WIDTH_IN_POINTS (WIDTH_IN_INCHES * 72) +#define HEIGHT_IN_POINTS (HEIGHT_IN_INCHES * 72) +#define BASENAME "svg-surface.out" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ +#define STROKE_WIDTH .04 + + double size; + + if (width > height) + size = height; + else + size = width; + + cairo_translate (cr, (width - size) / 2.0, (height - size) / 2.0); + cairo_scale (cr, size, size); + + /* Fill face */ + cairo_arc (cr, 0.5, 0.5, 0.5 - STROKE_WIDTH, 0, 2 * M_PI); + cairo_set_source_rgb (cr, 1, 1, 0); + cairo_save (cr); + { + cairo_fill (cr); + } + cairo_restore (cr); + + cairo_set_source_rgb (cr, 0, 0, 0); + + /* Stroke face */ + cairo_set_line_width (cr, STROKE_WIDTH / 2.0); + cairo_stroke (cr); + + /* Eyes */ + cairo_set_line_width (cr, STROKE_WIDTH); + cairo_arc (cr, 0.3, 0.4, STROKE_WIDTH, 0, 2 * M_PI); + cairo_fill (cr); + cairo_arc (cr, 0.7, 0.4, STROKE_WIDTH, 0, 2 * M_PI); + cairo_fill (cr); + + /* Mouth */ + cairo_move_to (cr, 0.3, 0.7); + cairo_curve_to (cr, + 0.4, 0.8, + 0.6, 0.8, + 0.7, 0.7); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + cairo_t *cr; + cairo_surface_t *surface; + char *filename; + const char *path = cairo_test_mkdir (CAIRO_TEST_OUTPUT_DIR) ? CAIRO_TEST_OUTPUT_DIR : "."; + + if (! cairo_test_is_target_enabled (ctx, "svg11") && + ! cairo_test_is_target_enabled (ctx, "svg12")) + { + return CAIRO_TEST_UNTESTED; + } + + xasprintf (&filename, "%s/%s.svg", path, BASENAME); + surface = cairo_svg_surface_create (filename, + WIDTH_IN_POINTS, HEIGHT_IN_POINTS); + if (cairo_surface_status (surface)) { + cairo_test_log (ctx, + "Failed to create svg surface for file %s: %s\n", + filename, + cairo_status_to_string (cairo_surface_status (surface))); + free (filename); + return CAIRO_TEST_FAILURE; + } + + cr = cairo_create (surface); + + draw (cr, WIDTH_IN_POINTS, HEIGHT_IN_POINTS); + + cairo_show_page (cr); + + cairo_destroy (cr); + cairo_surface_destroy (surface); + + printf ("svg-surface: Please check %s to make sure it looks happy.\n", filename); + free (filename); + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (svg_surface, + "Check creation of a SVG surface", + "svg", /* keywords */ + NULL, /* requirements */ + 0, 0, + preamble, NULL) diff --git a/local/recipes/libs/cairo/source/test/svg/README b/local/recipes/libs/cairo/source/test/svg/README new file mode 100644 index 0000000000..c4504dc9b4 --- /dev/null +++ b/local/recipes/libs/cairo/source/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/local/recipes/libs/cairo/source/test/svg/build_ttx_fonts.py b/local/recipes/libs/cairo/source/test/svg/build_ttx_fonts.py new file mode 100755 index 0000000000..d7e7f5b8f3 --- /dev/null +++ b/local/recipes/libs/cairo/source/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/local/recipes/libs/cairo/source/test/svg/color.0.color0.svg b/local/recipes/libs/cairo/source/test/svg/color.0.color0.svg new file mode 100644 index 0000000000..650dca8984 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/color.0.color0.svg @@ -0,0 +1,4 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/color.1.color1.svg b/local/recipes/libs/cairo/source/test/svg/color.1.color1.svg new file mode 100644 index 0000000000..2858b35cac --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/color.1.color1.svg @@ -0,0 +1,4 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/color.2.foreground-solid.svg b/local/recipes/libs/cairo/source/test/svg/color.2.foreground-solid.svg new file mode 100644 index 0000000000..cf77d65a68 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/color.2.foreground-solid.svg @@ -0,0 +1,4 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/color.3.foreground-alpha.svg b/local/recipes/libs/cairo/source/test/svg/color.3.foreground-alpha.svg new file mode 100644 index 0000000000..fa67d4929c --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/color.3.foreground-alpha.svg @@ -0,0 +1,4 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/color.4.foreground-linear.svg b/local/recipes/libs/cairo/source/test/svg/color.4.foreground-linear.svg new file mode 100644 index 0000000000..d2f8816c62 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/color.4.foreground-linear.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/local/recipes/libs/cairo/source/test/svg/color.5.foreground-linear-alpha.svg b/local/recipes/libs/cairo/source/test/svg/color.5.foreground-linear-alpha.svg new file mode 100644 index 0000000000..a3c453ad32 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/color.5.foreground-linear-alpha.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/local/recipes/libs/cairo/source/test/svg/color.6.foreground-radial.svg b/local/recipes/libs/cairo/source/test/svg/color.6.foreground-radial.svg new file mode 100644 index 0000000000..97622c2b49 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/color.6.foreground-radial.svg @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/local/recipes/libs/cairo/source/test/svg/color.7.foreground-radial-alpha.svg b/local/recipes/libs/cairo/source/test/svg/color.7.foreground-radial-alpha.svg new file mode 100644 index 0000000000..76d6628e02 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/color.7.foreground-radial-alpha.svg @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/local/recipes/libs/cairo/source/test/svg/doc.0.viewBox1.svg b/local/recipes/libs/cairo/source/test/svg/doc.0.viewBox1.svg new file mode 100644 index 0000000000..c1f55a4ebf --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/doc.0.viewBox1.svg @@ -0,0 +1,4 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/doc.1.viewBox2.svg b/local/recipes/libs/cairo/source/test/svg/doc.1.viewBox2.svg new file mode 100644 index 0000000000..b8f976ba94 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/doc.1.viewBox2.svg @@ -0,0 +1,4 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/doc.2.image.svg b/local/recipes/libs/cairo/source/test/svg/doc.2.image.svg new file mode 100644 index 0000000000..1d03842a9e --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/doc.2.image.svg @@ -0,0 +1,121 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/doc.3.image-transform.svg b/local/recipes/libs/cairo/source/test/svg/doc.3.image-transform.svg new file mode 100644 index 0000000000..90e5ecb1a7 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/doc.3.image-transform.svg @@ -0,0 +1,122 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/doc.4.clip-user.svg b/local/recipes/libs/cairo/source/test/svg/doc.4.clip-user.svg new file mode 100644 index 0000000000..26cdd818a1 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/doc.4.clip-user.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/local/recipes/libs/cairo/source/test/svg/doc.5.clip-object.svg b/local/recipes/libs/cairo/source/test/svg/doc.5.clip-object.svg new file mode 100644 index 0000000000..7329115901 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/doc.5.clip-object.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/local/recipes/libs/cairo/source/test/svg/doc.6.clip-user2.svg b/local/recipes/libs/cairo/source/test/svg/doc.6.clip-user2.svg new file mode 100644 index 0000000000..a68c1c42f3 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/doc.6.clip-user2.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/local/recipes/libs/cairo/source/test/svg/doc.7.clip-object2.svg b/local/recipes/libs/cairo/source/test/svg/doc.7.clip-object2.svg new file mode 100644 index 0000000000..f5c153dd1b --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/doc.7.clip-object2.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/local/recipes/libs/cairo/source/test/svg/doc.8.clip-user3.svg b/local/recipes/libs/cairo/source/test/svg/doc.8.clip-user3.svg new file mode 100644 index 0000000000..8ff61d593d --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/doc.8.clip-user3.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + diff --git a/local/recipes/libs/cairo/source/test/svg/doc.9.clip-object3.svg b/local/recipes/libs/cairo/source/test/svg/doc.9.clip-object3.svg new file mode 100644 index 0000000000..b291df79f4 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/doc.9.clip-object3.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + diff --git a/local/recipes/libs/cairo/source/test/svg/doc.A.g.svg b/local/recipes/libs/cairo/source/test/svg/doc.A.g.svg new file mode 100644 index 0000000000..bdaade7257 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/doc.A.g.svg @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/local/recipes/libs/cairo/source/test/svg/fill.0.name.svg b/local/recipes/libs/cairo/source/test/svg/fill.0.name.svg new file mode 100644 index 0000000000..e377b88274 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/fill.0.name.svg @@ -0,0 +1,4 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/fill.1.hex6.svg b/local/recipes/libs/cairo/source/test/svg/fill.1.hex6.svg new file mode 100644 index 0000000000..04759d78a6 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/fill.1.hex6.svg @@ -0,0 +1,4 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/fill.2.hex3.svg b/local/recipes/libs/cairo/source/test/svg/fill.2.hex3.svg new file mode 100644 index 0000000000..9f9bce580e --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/fill.2.hex3.svg @@ -0,0 +1,4 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/fill.3.rgb.svg b/local/recipes/libs/cairo/source/test/svg/fill.3.rgb.svg new file mode 100644 index 0000000000..c18b03bb5a --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/fill.3.rgb.svg @@ -0,0 +1,4 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/fill.4.current-color.svg b/local/recipes/libs/cairo/source/test/svg/fill.4.current-color.svg new file mode 100644 index 0000000000..cf77d65a68 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/fill.4.current-color.svg @@ -0,0 +1,4 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/fill.5.palette.svg b/local/recipes/libs/cairo/source/test/svg/fill.5.palette.svg new file mode 100644 index 0000000000..53ea97512d --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/fill.5.palette.svg @@ -0,0 +1,4 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/fill.6.opacity.svg b/local/recipes/libs/cairo/source/test/svg/fill.6.opacity.svg new file mode 100644 index 0000000000..59b4eb41fb --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/fill.6.opacity.svg @@ -0,0 +1,4 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/fill.7.color.svg b/local/recipes/libs/cairo/source/test/svg/fill.7.color.svg new file mode 100644 index 0000000000..745b2e8814 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/fill.7.color.svg @@ -0,0 +1,5 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/fill.8.rule.svg b/local/recipes/libs/cairo/source/test/svg/fill.8.rule.svg new file mode 100644 index 0000000000..366ff67601 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/fill.8.rule.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/local/recipes/libs/cairo/source/test/svg/fuzzer/README b/local/recipes/libs/cairo/source/test/svg/fuzzer/README new file mode 100644 index 0000000000..4bb8d96541 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/fuzzer/README @@ -0,0 +1,19 @@ +libFuzzer based fuzzing for cairo-svg-glyph-render.c +==================================================== + +Build +----- +CC=clang CFLAGS="-DDEBUG_SVG_RENDER -g -fsanitize=fuzzer-no-link,address" meson -Db_lundef=false bld-fuzzer +ninja -C bld-fuzzer + + +Test +---- + ./bld-fuzzer/test/svg/fuzzer/svg-render-fuzzer + +where is a directory containing SVG files. + +If the fuzzer crashes, a crash-* file will be written. Run the +fuzzer with the crash file to reproduce the crash. + + ./bld-fuzzer/test/svg/fuzzer/svg-render-fuzzer diff --git a/local/recipes/libs/cairo/source/test/svg/fuzzer/meson.build b/local/recipes/libs/cairo/source/test/svg/fuzzer/meson.build new file mode 100644 index 0000000000..3e8f7b9439 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/fuzzer/meson.build @@ -0,0 +1,14 @@ +fuzz_targets = [ + 'svg-render-fuzzer' +] + +fuzz_args = ['-fsanitize=fuzzer,address'] + +foreach target_name : fuzz_targets + exe = executable(target_name, [target_name + '.c'], + include_directories: [incbase, incsrc], + c_args: [fuzz_args], + link_with: [libcairo], + link_args: [fuzz_args, extra_link_args], + dependencies: [deps, test_deps]) +endforeach diff --git a/local/recipes/libs/cairo/source/test/svg/fuzzer/svg-render-fuzzer.c b/local/recipes/libs/cairo/source/test/svg/fuzzer/svg-render-fuzzer.c new file mode 100644 index 0000000000..08eb79dd8b --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/fuzzer/svg-render-fuzzer.c @@ -0,0 +1,57 @@ +/* + * Copyright © 2022 Uli Schlachter + * + * 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: Uli Schlachter + */ + +#include +#include +#include +#include +#include + +cairo_bool_t +_cairo_debug_svg_render (cairo_t *cr, + const char *svg_document, + const char *element, + double units_per_em, + int debug_level); + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + cairo_surface_t *s = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1); + cairo_t *cr = cairo_create(s); + + /* Get us a zero terminated string */ + const char *svg_document = strndup ((const char *) data, size); + + _cairo_debug_svg_render (cr, + svg_document, + NULL, + 1000, + 0); + free (svg_document); + cairo_destroy (cr); + cairo_surface_destroy (s); + return 0; +} diff --git a/local/recipes/libs/cairo/source/test/svg/gradient.0.lin-pad.svg b/local/recipes/libs/cairo/source/test/svg/gradient.0.lin-pad.svg new file mode 100644 index 0000000000..0ec54092f1 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/gradient.0.lin-pad.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/local/recipes/libs/cairo/source/test/svg/gradient.1.lin-reflect.svg b/local/recipes/libs/cairo/source/test/svg/gradient.1.lin-reflect.svg new file mode 100644 index 0000000000..9e3e50cb94 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/gradient.1.lin-reflect.svg @@ -0,0 +1,11 @@ + + + + + + + + + + diff --git a/local/recipes/libs/cairo/source/test/svg/gradient.2.lin-repeat.svg b/local/recipes/libs/cairo/source/test/svg/gradient.2.lin-repeat.svg new file mode 100644 index 0000000000..1f023f5e1a --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/gradient.2.lin-repeat.svg @@ -0,0 +1,11 @@ + + + + + + + + + + diff --git a/local/recipes/libs/cairo/source/test/svg/gradient.3.lin-user.svg b/local/recipes/libs/cairo/source/test/svg/gradient.3.lin-user.svg new file mode 100644 index 0000000000..fc90328f0d --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/gradient.3.lin-user.svg @@ -0,0 +1,11 @@ + + + + + + + + + + diff --git a/local/recipes/libs/cairo/source/test/svg/gradient.4.lin-transform.svg b/local/recipes/libs/cairo/source/test/svg/gradient.4.lin-transform.svg new file mode 100644 index 0000000000..bc8f5b6222 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/gradient.4.lin-transform.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/local/recipes/libs/cairo/source/test/svg/gradient.5.rad-pad.svg b/local/recipes/libs/cairo/source/test/svg/gradient.5.rad-pad.svg new file mode 100644 index 0000000000..b631ddc73a --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/gradient.5.rad-pad.svg @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/local/recipes/libs/cairo/source/test/svg/gradient.6.rad-reflect.svg b/local/recipes/libs/cairo/source/test/svg/gradient.6.rad-reflect.svg new file mode 100644 index 0000000000..b6fea76be3 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/gradient.6.rad-reflect.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/local/recipes/libs/cairo/source/test/svg/gradient.7.rad-repeat.svg b/local/recipes/libs/cairo/source/test/svg/gradient.7.rad-repeat.svg new file mode 100644 index 0000000000..63d138d2a5 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/gradient.7.rad-repeat.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/local/recipes/libs/cairo/source/test/svg/gradient.8.rad-user.svg b/local/recipes/libs/cairo/source/test/svg/gradient.8.rad-user.svg new file mode 100644 index 0000000000..e1d9c61f05 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/gradient.8.rad-user.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/local/recipes/libs/cairo/source/test/svg/gradient.9.rad-transform.svg b/local/recipes/libs/cairo/source/test/svg/gradient.9.rad-transform.svg new file mode 100644 index 0000000000..4b90aaaf6b --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/gradient.9.rad-transform.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/local/recipes/libs/cairo/source/test/svg/meson.build b/local/recipes/libs/cairo/source/test/svg/meson.build new file mode 100644 index 0000000000..858e9d9cc5 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/meson.build @@ -0,0 +1,9 @@ +if librsvg_dep.found() + executable('svg-render', + 'svg-render.c', + dependencies: [libcairo_dep, librsvg_dep]) +endif + +if cc.links(files(meson.project_source_root() / 'meson-cc-tests/fuzzer.c'), args: '-fsanitize=fuzzer,address') + subdir('fuzzer') +endif diff --git a/local/recipes/libs/cairo/source/test/svg/path.0.line.svg b/local/recipes/libs/cairo/source/test/svg/path.0.line.svg new file mode 100644 index 0000000000..19d50914a2 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/path.0.line.svg @@ -0,0 +1,8 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/path.1.curve.svg b/local/recipes/libs/cairo/source/test/svg/path.1.curve.svg new file mode 100644 index 0000000000..49c252ac8a --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/path.1.curve.svg @@ -0,0 +1,9 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/path.2.quad.svg b/local/recipes/libs/cairo/source/test/svg/path.2.quad.svg new file mode 100644 index 0000000000..00a0dde575 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/path.2.quad.svg @@ -0,0 +1,8 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/path.3.arc.svg b/local/recipes/libs/cairo/source/test/svg/path.3.arc.svg new file mode 100644 index 0000000000..f177a72af8 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/path.3.arc.svg @@ -0,0 +1,7 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/shapes.0.rect.svg b/local/recipes/libs/cairo/source/test/svg/shapes.0.rect.svg new file mode 100644 index 0000000000..17db346498 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/shapes.0.rect.svg @@ -0,0 +1,3 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/shapes.1.rounded-rect.svg b/local/recipes/libs/cairo/source/test/svg/shapes.1.rounded-rect.svg new file mode 100644 index 0000000000..717470beeb --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/shapes.1.rounded-rect.svg @@ -0,0 +1,3 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/shapes.2.circle.svg b/local/recipes/libs/cairo/source/test/svg/shapes.2.circle.svg new file mode 100644 index 0000000000..3c07bad834 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/shapes.2.circle.svg @@ -0,0 +1,3 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/shapes.3.ellipse.svg b/local/recipes/libs/cairo/source/test/svg/shapes.3.ellipse.svg new file mode 100644 index 0000000000..67260a4045 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/shapes.3.ellipse.svg @@ -0,0 +1,3 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/shapes.4.line.svg b/local/recipes/libs/cairo/source/test/svg/shapes.4.line.svg new file mode 100644 index 0000000000..58de429472 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/shapes.4.line.svg @@ -0,0 +1,3 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/shapes.5.polyline.svg b/local/recipes/libs/cairo/source/test/svg/shapes.5.polyline.svg new file mode 100644 index 0000000000..0cc5c383c5 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/shapes.5.polyline.svg @@ -0,0 +1,12 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/shapes.6.polygon.svg b/local/recipes/libs/cairo/source/test/svg/shapes.6.polygon.svg new file mode 100644 index 0000000000..56bda07059 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/shapes.6.polygon.svg @@ -0,0 +1,12 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/stroke.0.name.svg b/local/recipes/libs/cairo/source/test/svg/stroke.0.name.svg new file mode 100644 index 0000000000..f2a9264752 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/stroke.0.name.svg @@ -0,0 +1,6 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/stroke.1.hex6.svg b/local/recipes/libs/cairo/source/test/svg/stroke.1.hex6.svg new file mode 100644 index 0000000000..89f2b1b382 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/stroke.1.hex6.svg @@ -0,0 +1,6 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/stroke.2.hex3.svg b/local/recipes/libs/cairo/source/test/svg/stroke.2.hex3.svg new file mode 100644 index 0000000000..a8565a7b61 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/stroke.2.hex3.svg @@ -0,0 +1,6 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/stroke.3.rgb.svg b/local/recipes/libs/cairo/source/test/svg/stroke.3.rgb.svg new file mode 100644 index 0000000000..42e7514e49 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/stroke.3.rgb.svg @@ -0,0 +1,6 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/stroke.4.current-color.svg b/local/recipes/libs/cairo/source/test/svg/stroke.4.current-color.svg new file mode 100644 index 0000000000..9d645b8813 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/stroke.4.current-color.svg @@ -0,0 +1,6 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/stroke.5.palette.svg b/local/recipes/libs/cairo/source/test/svg/stroke.5.palette.svg new file mode 100644 index 0000000000..1262a7ba0a --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/stroke.5.palette.svg @@ -0,0 +1,6 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/stroke.6.opacity.svg b/local/recipes/libs/cairo/source/test/svg/stroke.6.opacity.svg new file mode 100644 index 0000000000..b84d1bdc97 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/stroke.6.opacity.svg @@ -0,0 +1,6 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/stroke.7.color.svg b/local/recipes/libs/cairo/source/test/svg/stroke.7.color.svg new file mode 100644 index 0000000000..952f482615 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/stroke.7.color.svg @@ -0,0 +1,7 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/stroke.8.width.svg b/local/recipes/libs/cairo/source/test/svg/stroke.8.width.svg new file mode 100644 index 0000000000..bb9edea905 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/stroke.8.width.svg @@ -0,0 +1,14 @@ + + + + + diff --git a/local/recipes/libs/cairo/source/test/svg/stroke.9.cap.svg b/local/recipes/libs/cairo/source/test/svg/stroke.9.cap.svg new file mode 100644 index 0000000000..35046446c2 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/stroke.9.cap.svg @@ -0,0 +1,17 @@ + + + + + diff --git a/local/recipes/libs/cairo/source/test/svg/stroke.A.dash.svg b/local/recipes/libs/cairo/source/test/svg/stroke.A.dash.svg new file mode 100644 index 0000000000..2be5a1d909 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/stroke.A.dash.svg @@ -0,0 +1,27 @@ + + + + + + + diff --git a/local/recipes/libs/cairo/source/test/svg/stroke.B.dash-offset.svg b/local/recipes/libs/cairo/source/test/svg/stroke.B.dash-offset.svg new file mode 100644 index 0000000000..f7623ea841 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/stroke.B.dash-offset.svg @@ -0,0 +1,31 @@ + + + + + + + diff --git a/local/recipes/libs/cairo/source/test/svg/stroke.C.miter.svg b/local/recipes/libs/cairo/source/test/svg/stroke.C.miter.svg new file mode 100644 index 0000000000..1dc4ee6a72 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/stroke.C.miter.svg @@ -0,0 +1,10 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/stroke.D.round.svg b/local/recipes/libs/cairo/source/test/svg/stroke.D.round.svg new file mode 100644 index 0000000000..3e4c6236f9 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/stroke.D.round.svg @@ -0,0 +1,10 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/stroke.E.bevel.svg b/local/recipes/libs/cairo/source/test/svg/stroke.E.bevel.svg new file mode 100644 index 0000000000..25d9e38034 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/stroke.E.bevel.svg @@ -0,0 +1,10 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/stroke.F.miter-limit.svg b/local/recipes/libs/cairo/source/test/svg/stroke.F.miter-limit.svg new file mode 100644 index 0000000000..14357f0b47 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/stroke.F.miter-limit.svg @@ -0,0 +1,11 @@ + + + diff --git a/local/recipes/libs/cairo/source/test/svg/svg-font-template.ttx b/local/recipes/libs/cairo/source/test/svg/svg-font-template.ttx new file mode 100644 index 0000000000..715074ddaf --- /dev/null +++ b/local/recipes/libs/cairo/source/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/local/recipes/libs/cairo/source/test/svg/svg-render.c b/local/recipes/libs/cairo/source/test/svg/svg-render.c new file mode 100644 index 0000000000..8f67ebdc22 --- /dev/null +++ b/local/recipes/libs/cairo/source/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/local/recipes/libs/cairo/source/test/svg/transform.0.translate.svg b/local/recipes/libs/cairo/source/test/svg/transform.0.translate.svg new file mode 100644 index 0000000000..5d9555673f --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/transform.0.translate.svg @@ -0,0 +1,8 @@ + + + + + + + diff --git a/local/recipes/libs/cairo/source/test/svg/transform.1.scale.svg b/local/recipes/libs/cairo/source/test/svg/transform.1.scale.svg new file mode 100644 index 0000000000..b7742fc806 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/transform.1.scale.svg @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/local/recipes/libs/cairo/source/test/svg/transform.2.rotate.svg b/local/recipes/libs/cairo/source/test/svg/transform.2.rotate.svg new file mode 100644 index 0000000000..926ae63fc4 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/transform.2.rotate.svg @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/local/recipes/libs/cairo/source/test/svg/transform.3.skewX.svg b/local/recipes/libs/cairo/source/test/svg/transform.3.skewX.svg new file mode 100644 index 0000000000..f7555534d4 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/transform.3.skewX.svg @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/local/recipes/libs/cairo/source/test/svg/transform.4.skewY.svg b/local/recipes/libs/cairo/source/test/svg/transform.4.skewY.svg new file mode 100644 index 0000000000..cd62c8a8a8 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/transform.4.skewY.svg @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/local/recipes/libs/cairo/source/test/svg/transform.5.matrix.svg b/local/recipes/libs/cairo/source/test/svg/transform.5.matrix.svg new file mode 100644 index 0000000000..643fbe36ba --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/transform.5.matrix.svg @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/local/recipes/libs/cairo/source/test/svg/transform.6.multiple.svg b/local/recipes/libs/cairo/source/test/svg/transform.6.multiple.svg new file mode 100644 index 0000000000..90c7b3054f --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/transform.6.multiple.svg @@ -0,0 +1,16 @@ + + + + + + + diff --git a/local/recipes/libs/cairo/source/test/svg/transform.7.stroke.svg b/local/recipes/libs/cairo/source/test/svg/transform.7.stroke.svg new file mode 100644 index 0000000000..f56b24dfe7 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg/transform.7.stroke.svg @@ -0,0 +1,20 @@ + + + + + + + + + + diff --git a/local/recipes/libs/cairo/source/test/svg2png.c b/local/recipes/libs/cairo/source/test/svg2png.c new file mode 100644 index 0000000000..5dfbf62ec1 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/svg2png.c @@ -0,0 +1,88 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2005 Emmanuel Pacaud + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Kristian Høgsberg + * Emmanuel Pacaud + */ + +#include +#include + +/* Disable deprecation warnings coming from librsvg */ +#define RSVG_DISABLE_DEPRECATION_WARNINGS +#include + +#define FAIL(msg) \ + do { fprintf (stderr, "FAIL: %s\n", msg); exit (-1); } while (0) + +int main (int argc, char *argv[]) +{ + GError *error = NULL; + RsvgHandle *handle; + RsvgDimensionData dimensions; + const char *filename = argv[1]; + const char *output_filename = argv[2]; + cairo_surface_t *surface; + cairo_t *cr; + cairo_status_t status; + + if (argc != 3) + FAIL ("usage: svg2png input_file.svg output_file.png"); + + #if GLIB_MAJOR_VERSION <= 2 && GLIB_MINOR_VERSION <= 34 + g_type_init (); + #endif + + error = NULL; + + handle = rsvg_handle_new_from_file (filename, &error); + if (!handle) + FAIL (error->message); + + rsvg_handle_set_dpi (handle, 72.0); + rsvg_handle_get_dimensions (handle, &dimensions); + + surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, + dimensions.width, dimensions.height); + cr = cairo_create (surface); + cairo_surface_destroy (surface); + + cairo_set_source_rgb (cr, 1,1,1); + cairo_paint (cr); + cairo_push_group_with_content (cr, CAIRO_CONTENT_COLOR_ALPHA); + + if (!rsvg_handle_render_cairo (handle, cr)) + FAIL (error->message); + + cairo_pop_group_to_source (cr); + cairo_paint (cr); + + status = cairo_surface_write_to_png (cairo_get_target (cr), + output_filename); + cairo_destroy (cr); + if (status) + FAIL (cairo_status_to_string (status)); + + g_object_unref (handle); + return 0; +} diff --git a/local/recipes/libs/cairo/source/test/testsvg b/local/recipes/libs/cairo/source/test/testsvg new file mode 100755 index 0000000000..9b18df5863 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/testsvg @@ -0,0 +1,51 @@ +#!/bin/sh + +IMAGEDIFF=./imagediff + +OUTDIR=testsvg-output +REFDIR=testsvg-reference +DIFFDIR=testsvg-diff +IMAGELIST=testsvg-imagelist + +if [ $# -lt 1 ]; then + argv0=`basename $0` + echo "Usage: $argv0 file.svg [...]" >&2 + exit 1; +fi + +mkdir -p $OUTDIR +mkdir -p $DIFFDIR +rm -f $IMAGELIST + +err=0 +for svg in $@; do + svgbase=`basename $svg` + png=${svgbase/\.svg/.png} + outpng=$OUTDIR/$png + refpng=$REFDIR/$png + diffpng=$DIFFDIR/$png +# if xsvg $svg -p $outpng ; then + if svg2png $svg $outpng ; then + if [ -e $refpng ]; then + if $IMAGEDIFF $refpng $outpng > $diffpng; then + echo "Rendering of $svg matches." >&2 + rm -f $diffpng + else + echo "ERROR: Rendering of $svg differs from reference image." >&2 + echo $refpng $outpng $diffpng >> $IMAGELIST + err=$(($err+1)) + fi + else + echo "WARNING: No reference file found for $svg (looked in $refpng)" >&2 + fi + else + echo "ERROR: Failed to render $svg" >&2 + err=$(($err+1)) + fi +done + +if [ $err -gt 0 ] ; then + echo "Differences found in $err renderings." +else + echo "All renderings matched reference images." +fi diff --git a/local/recipes/libs/cairo/source/test/testtable.js b/local/recipes/libs/cairo/source/test/testtable.js new file mode 100644 index 0000000000..4fc664ff2a --- /dev/null +++ b/local/recipes/libs/cairo/source/test/testtable.js @@ -0,0 +1,428 @@ +/* configuration */ +/* TODO: UNTESTED count can't be shown because it's not tracked explicitly */ +headerResults = [ "PASS", "NEW", "FAIL", "XFAIL", "CRASHED" ]; +logResults = [ "PASS", "NEW", "FAIL", "XFAIL", "CRASH!" ]; +resultToImgs = { + "PASS" : [], + "NEW" : [ "output" ], + "FAIL" : [ "output", "difference", "reference" ], + "XFAIL" : [], + "UNTESTED" : [], + "CRASHED" : [] +}; + +resultToString = { + "PASS" : "", + "NEW" : "", + "FAIL" : "", + "XFAIL" : "", + "UNTESTED" : "", + "CRASHED" : "CRASHED!" +}; + +resultField = "result"; +rowFields = [ "test", "offset", "scale", "similar" ]; +colFields = [ "target", "format" ]; +allFields = [ resultField ].concat (rowFields, colFields); + + +/* globals: */ +function resetGlobals () { + dragElement = undefined; + table = document.getElementById ("testTable"); + while (table.rows.length) + table.deleteRow (0); + colsArray = [ "HrowHeader" ]; + colsMap = undefined; + headerId = "HcolHeader"; + + fTrue = function (x) { return true; }; + + empty = new Row (); + header = new Row (); + header[colsArray[0]].toString = function () { return ""; }; + + untested = new Test (); + untested[resultField] = "UNTESTED"; +} + + +/* utility functions */ +function isKey (key) { return key[key.length-1] == ':'; } +function normalizeKey (key) { return key.toLowerCase ().replace (/[^a-z0-9]/, ""); } +function isVisible (x) { return x.style.display != "none"; } + +function link (html, url) { return "" + html + ""; } +function image (url) { return ""; } +function span (html, id, cls) { return "" + html + ""; } + +function fieldsToHTML (bColumns, values) { + var fields = bColumns ? colFields : rowFields; + var prefix = bColumns ? "c" : "r"; + var tmpRE = arrayApply (function (x) { return "[^/]*"; }, fields); + var r = Array (); + for (var i = 0; i < fields.length; i++) + if (fields[i] == "test") { + r.push (link (values[fields[i]], "output/" + values[fields[i]] + ".log")); + } else { + tmpRE[i] = values[fields[i]]; + r.push (span (values[fields[i]], prefix + "/" + tmpRE.join ("/") + "/", fields[i])); + tmpRE[i] = "[^/]*"; + } + return r.join ("/"); +} + +function inArray (value, array) { + for (var i = 0; i < array.length; i++) + if (value == array[i]) + return true; + return false; +} + +function arrayApply (fun, array) { + var r = new Array (); + for (var i = 0; i < array.length; i++) + r.push (fun(array[i])); + return r; +} + +function arrayPred (pred, array) { + var r = new Array (); + for (var i = 0; i < array.length; i++) + if (pred (array[i])) + r.push (array[i]); + return r; +} + +function arrayMap (map, array) { return arrayApply (function (x) { return map[x]; }, array); } + +function binSearch (rows, newId){ + var min = 0; + var max = rows.length; + + while (max - min > 1) { + var mid = (max + min) >> 1; + if (rows[mid].id > newId) + max = mid; + else + min = mid; + } + + if (max == min) + return max; + else + return rows[min].id > newId ? min : max; +} + +/* dynamic table utils */ +function updateCurrent () { + for (var i = 0; i < table.rows.length; i++) { + var row = table.rows[i]; + if (isVisible (row)) { + /* j starts from 1 because we want to ignore _rowHeader */ + for (var j = 1; j < row.cells.length; j++) + if (row.id[0] == "H") + for (var k = 0; k < headerResults.length; k++) + header[row.cells[j].id].current[headerResults[k]] = 0; + else if (isVisible (row.cells[j])) + header[row.cells[j].id].current[row.cells[j].className]++; + } + } + + updateHeader (); +} + +function setVisible (array, subsetPred, visibilityPred, visibleFlag) { + var modified = false, somethingVisible = false; + for (var i = 0; i < array.length; i++) + if (array[i].id[0] != "H") { + if (subsetPred (array[i])) { + var wanted = visibilityPred (array[i]); + if (isVisible (array[i]) != wanted) { + modified = true; + array[i].style.display = wanted ? visibleFlag : "none"; + } + } + somethingVisible = somethingVisible || isVisible (array[i]); + } + return modified && somethingVisible; +} + +function setVisibleOnly (array, pred, visibleFlag) { + return setVisible (array, fTrue, pred, visibleFlag); +} + +function flipVisible (array, subsetPred, visibleFlag) { + return setVisible (array, subsetPred, function (x) { return !isVisible (x); }, visibleFlag); +} + + +/* event handling */ +function ignoreEvent (event) { + if (event.preventDefault) + event.preventDefault(); + else + event.returnValue= false; + return false; +} + +function mouseUp (event) { + var visFun; + if (event.button == 0) + visFun = setVisibleOnly; + else if (event.button == 2) + visFun = flipVisible; + else + return false; + + var structureFun; + if (event.target.id[0] == "r") /* rows */ + structureFun = function (f, p) { return f (table.rows, p, "table-row"); }; + else if (event.target.id[0] == "c") /* cols */ + structureFun = function (f, p) { return inArray (true, arrayApply (function (row) { return f (row.cells, p, "table-cell") }, table.rows)) }; + else + return false; + + var pred; + if (event.target.id[1] == "/") { /* regexp */ + var re = new RegExp (event.target.id); + pred = function (x) { return re.test (x.id); }; + } else if (event.target.id[1] == "#") { /* counters */ + var s = event.target.id.substr (2).split ("/"); + pred = function (row) { return row.cells[s[0]].className == s[1]; } + } else + return false; + + if (!structureFun (visFun, pred)) + if (!structureFun (flipVisible, fTrue)) + structureFun (flipVisible, fTrue); + + updateCurrent (); + + return false; +} + +function noDrag (event) { + dragElement = undefined; + return false; +} + +function startDrag (event) { + if (event.button == 0) + dragElement = event.target; + else + dragElement = undefined; + return false; +} + +function endDrag (event) { + if (!dragElement) + return false; + + if (event.currentTarget.id == colsArray[0] && + inArray (dragElement.className, colFields)) { + rowFields.push (dragElement.className); + colFields = arrayPred (function (x) { return x != dragElement.className; }, colFields); + } else if (event.currentTarget.id == headerId && + inArray (dragElement.className, rowFields)) { + colFields.push (dragElement.className); + rowFields = arrayPred (function (x) { return x != dragElement.className; }, rowFields); + } else + return true; + + reloadAll (); + return false; +} + + +/* table content */ +function Row (id, t) { + this[colsArray[0]] = new RowHeader (id, t); + + this.get = function (c) { return this[c] != undefined ? this[c] : untested; } + this.getHTML = function (c) { return this.get(c).toString (); }; + this.setStyle = function (c, element) { return this.get(c).setStyle (element); }; +} + +function ColumnHeader (id, values) { + this.id = id; + this.values = values; + this.total = new Object (); + this.current = new Object (); + + for (var i = 0; i < headerResults.length; i++) { + this.total[headerResults[i]] = 0; + this.current[headerResults[i]] = 0; + } + + this.toString = function () { + var counts = new Array (); + for (var i = 0; i < headerResults.length; i++) { + var hr = headerResults[i]; + var s = span (this.current[hr], "r#" + colsMap[this.id] + "/" + hr, hr); + if (this.current[hr] != this.total[hr]) + s += span ("[" + this.total[hr] + "]", "r#" + colsMap[this.id] + "/" + hr, hr); + counts.push (s); + } + + return fieldsToHTML (true, this.values) + "
    " + counts.join ("/"); + } + + this.setStyle = function (element) { }; +} + +function RowHeader (id, values) { + this.id = id; + this.values = values; + this.toString = function () { return fieldsToHTML (false, this.values); } + this.setStyle = function (element) { element.onmouseup = endDrag; }; +} + +function Test () { + this.rowId = function () { return "r/" + arrayMap (this, rowFields).join("/") + "/"; }; + this.colId = function () { return "c/" + arrayMap (this, colFields).join("/") + "/"; }; + this.isComplete = function () { return !inArray (undefined, arrayMap (this, allFields)); } + this.toString = function () { + var images = arrayMap (this, resultToImgs[this[resultField]]); + images = arrayPred (function (x) { return x != undefined; }, images); + images = arrayApply (function (x) { return link (image (x), x); }, images); + images.push (resultToString[this[resultField]]); + return images.join (" "); + }; + + this.setStyle = function (element) { element.className = this[resultField]; }; + + this.addData = function (array) { + for (var i = 0; i < array.length - 1; i += 2) + if (isKey (array[i])) + this[normalizeKey (array[i])] = array[i+1]; + }; +} + + +/* table creation */ +function insertCell (domRow, nid, tests) { + var domCell = domRow.insertCell (nid); + domCell.id = colsArray[nid]; + domCell.innerHTML = tests.getHTML (colsArray[nid]); + tests.setStyle (colsArray[nid], domCell); +} + +function updateRow (row, tests) { + var domRow = document.getElementById (row); + if (!domRow) { + domRow = table.insertRow (binSearch (table.rows, row)); + domRow.id = row; + } + + for (var i = 0; i < colsArray.length; i++) + if (i >= domRow.cells.length || domRow.cells[i].id != colsArray[i]) + insertCell (domRow, i, tests); +} + +function updateHeader () { + var visibility; + var domRow = document.getElementById (headerId); + if (domRow) { + visibility = new Object (); + for (var i = 0; i < domRow.cells.length; i++) + visibility[domRow.cells[i].id] = domRow.cells[i].style.display; + table.deleteRow (domRow.rowIndex); + } + + updateRow (headerId, header); + table.rows[0].onmouseup = endDrag; + + if (visibility) + for (var i = 0; i < colsArray.length; i++) + if (visibility[colsArray[i]]) + table.rows[0].cells[colsMap[colsArray[i]]].style.display = visibility[colsArray[i]]; +} + +function updateTable () { + colsArray.sort (); + + colsMap = new Object (); + for (var i = 0; i < colsArray.length; i++) + colsMap[colsArray[i]] = i; + + updateHeader (); + for (var i = 0; i < table.rows.length; i++) + updateRow (table.rows[i].id, empty); +} + + +/* log file parsing */ +function parseTest (testData) { + var colsChanged = false; + var rows = new Array (); + var data = new Object (); + var t = new Test (); + var lines = testData.replace (/\r/g, "").split ("\n"); + for (var i = 0; i < lines.length; i++) { + t.addData (lines[i].split (" ")); + if (t.isComplete ()) { + var c = t.colId (); + if (header[c] == undefined) { + colsArray.push (c); + header[c] = new ColumnHeader (c, t); + colsChanged = true; + } + + var r = t.rowId (); + if (!data[r]) { + rows.push (r); + data[r] = new Row (r, t); + } + + data[r][c] = t; + header[c].total[t[resultField]]++; + header[c].current[t[resultField]]++; + t = new Test (); + } + } + + if (colsChanged) + updateTable (); + else + updateHeader (); + + for (var i = 0; i < rows.length; i++) + updateRow (rows[i], data[rows[i]]); +} + +function parseFile (fileName, parser) { + var req = new XMLHttpRequest (); + req.onreadystatechange = function () { + if (req.readyState == 4) + parser (req.responseText); + } + + try { + req.open ("GET", fileName); + req.send (null); + } catch (e) {} +} + +function parseTestList (listData) { + var summaryRE = /\d+ Passed, \d+ Failed \x5b\d+ crashed, \d+ expected\x5d, \d+ Skipped/; + var lines = listData.replace (/\r/g, "").split ("\n"); + for (var i = 0; i < lines.length; i++) { + if (summaryRE.test (lines[i])) + return; + + var words = lines[i].split (" "); + if (words.length >= 2 && + words[0][words[0].length-1] == ":" && + inArray (words[1], logResults)) + parseFile ("output/" + words[0].substr (0, words[0].length-1) + ".log", parseTest); + } +} + +function reloadAll() { + resetGlobals (); + + parseFile ("cairo-test-suite.log", parseTestList); +} + +window.onload = reloadAll; diff --git a/local/recipes/libs/cairo/source/test/text-antialias-subpixel.c b/local/recipes/libs/cairo/source/test/text-antialias-subpixel.c new file mode 100644 index 0000000000..6a65059ebe --- /dev/null +++ b/local/recipes/libs/cairo/source/test/text-antialias-subpixel.c @@ -0,0 +1,123 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * Copyright © 2011 Uli Schlachter + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Uli Schlachter + * + * Based on test/text-antialias.c + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +#define WIDTH 31 +#define HEIGHT 22 +#define TEXT_SIZE 12 + +static cairo_test_status_t +draw (cairo_t *cr, cairo_subpixel_order_t order) +{ + cairo_text_extents_t extents; + cairo_font_options_t *font_options; + const char black[] = "black", blue[] = "blue"; + + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (cr, TEXT_SIZE); + + font_options = cairo_font_options_create (); + cairo_get_font_options (cr, font_options); + cairo_font_options_set_antialias (font_options, CAIRO_ANTIALIAS_SUBPIXEL); + cairo_font_options_set_subpixel_order (font_options, order); + cairo_set_font_options (cr, font_options); + + cairo_font_options_destroy (font_options); + + cairo_set_source_rgb (cr, 0, 0, 0); /* black */ + cairo_text_extents (cr, black, &extents); + cairo_move_to (cr, -extents.x_bearing, -extents.y_bearing); + cairo_show_text (cr, black); + cairo_translate (cr, 0, -extents.y_bearing + 1); + + cairo_set_source_rgb (cr, 0, 0, 1); /* blue */ + cairo_text_extents (cr, blue, &extents); + cairo_move_to (cr, -extents.x_bearing, -extents.y_bearing); + cairo_show_text (cr, blue); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +draw_rgb (cairo_t *cr, int width, int height) +{ + return draw (cr, CAIRO_SUBPIXEL_ORDER_RGB); +} + +static cairo_test_status_t +draw_bgr (cairo_t *cr, int width, int height) +{ + return draw (cr, CAIRO_SUBPIXEL_ORDER_BGR); +} + +static cairo_test_status_t +draw_vrgb (cairo_t *cr, int width, int height) +{ + return draw (cr, CAIRO_SUBPIXEL_ORDER_VRGB); +} + +static cairo_test_status_t +draw_vbgr (cairo_t *cr, int width, int height) +{ + return draw (cr, CAIRO_SUBPIXEL_ORDER_VBGR); +} + +CAIRO_TEST (text_antialias_subpixel_rgb, + "Tests text rendering with rgb subpixel antialiasing", + "text", /* keywords */ + "target=raster", /* requirements */ + WIDTH, HEIGHT, + NULL, draw_rgb) + +CAIRO_TEST (text_antialias_subpixel_bgr, + "Tests text rendering with bgr subpixel antialiasing", + "text", /* keywords */ + "target=raster", /* requirements */ + WIDTH, HEIGHT, + NULL, draw_bgr) + +CAIRO_TEST (text_antialias_subpixel_vrgb, + "Tests text rendering with vertical rgb subpixel antialiasing", + "text", /* keywords */ + "target=raster", /* requirements */ + WIDTH, HEIGHT, + NULL, draw_vrgb) + +CAIRO_TEST (text_antialias_subpixel_vbgr, + "Tests text rendering with vertical bgr subpixel antialiasing", + "text", /* keywords */ + "target=raster", /* requirements */ + WIDTH, HEIGHT, + NULL, draw_vbgr) diff --git a/local/recipes/libs/cairo/source/test/text-antialias.c b/local/recipes/libs/cairo/source/test/text-antialias.c new file mode 100644 index 0000000000..7d338925e6 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/text-antialias.c @@ -0,0 +1,106 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +#define WIDTH 31 +#define HEIGHT 22 +#define TEXT_SIZE 12 + +static cairo_test_status_t +draw (cairo_t *cr, cairo_antialias_t antialias) +{ + cairo_text_extents_t extents; + cairo_font_options_t *font_options; + const char black[] = "black", blue[] = "blue"; + + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (cr, TEXT_SIZE); + + font_options = cairo_font_options_create (); + cairo_get_font_options (cr, font_options); + cairo_font_options_set_antialias (font_options, antialias); + cairo_font_options_set_subpixel_order (font_options, CAIRO_SUBPIXEL_ORDER_RGB); + cairo_set_font_options (cr, font_options); + + cairo_font_options_destroy (font_options); + + cairo_set_source_rgb (cr, 0, 0, 0); /* black */ + cairo_text_extents (cr, black, &extents); + cairo_move_to (cr, -extents.x_bearing, -extents.y_bearing); + cairo_show_text (cr, black); + cairo_translate (cr, 0, -extents.y_bearing + 1); + + cairo_set_source_rgb (cr, 0, 0, 1); /* blue */ + cairo_text_extents (cr, blue, &extents); + cairo_move_to (cr, -extents.x_bearing, -extents.y_bearing); + cairo_show_text (cr, blue); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +draw_gray (cairo_t *cr, int width, int height) +{ + return draw (cr, CAIRO_ANTIALIAS_GRAY); +} + +static cairo_test_status_t +draw_none (cairo_t *cr, int width, int height) +{ + return draw (cr, CAIRO_ANTIALIAS_NONE); +} + +static cairo_test_status_t +draw_subpixel (cairo_t *cr, int width, int height) +{ + return draw (cr, CAIRO_ANTIALIAS_SUBPIXEL); +} + +CAIRO_TEST (text_antialias_gray, + "Tests text rendering with grayscale antialiasing", + "text", /* keywords */ + "target=raster", /* requirements */ + WIDTH, HEIGHT, + NULL, draw_gray) + +CAIRO_TEST (text_antialias_none, + "Tests text rendering with no antialiasing", + "text", /* keywords */ + "target=raster", /* requirements */ + WIDTH, HEIGHT, + NULL, draw_none) + +CAIRO_TEST (text_antialias_subpixel, + "Tests text rendering with subpixel antialiasing", + "text", /* keywords */ + "target=raster", /* requirements */ + WIDTH, HEIGHT, + NULL, draw_subpixel) diff --git a/local/recipes/libs/cairo/source/test/text-cache-crash.c b/local/recipes/libs/cairo/source/test/text-cache-crash.c new file mode 100644 index 0000000000..6b6fe361c3 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/text-cache-crash.c @@ -0,0 +1,93 @@ +/* + * Copyright © 2004 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +/* Bug history + * + * 2004-11-04 Ned Konz + * + * Reported bug on mailing list: + * + * From: Ned Konz + * To: cairo@cairographics.org + * Date: Thu, 4 Nov 2004 09:49:38 -0800 + * Subject: [cairo] getting assertions [cairo_cache.c:143: _entry_destroy: + * Assertion `cache->used_memory > entry->memory' failed] + * + * The attached program dies on me with the assert + * + * $ ./testCairo + * testCairo: cairo_cache.c:143: _entry_destroy: Assertion `cache->used_memory > entry->memory' failed. + * + * 2004-11-04 Carl Worth + * + * I trimmed down Ned's example to the following test while still + * maintaining the assertion. + * + * Oh, actually, it looks like I may have triggered something + * slightly different: + * + * text_cache_crash: cairo_cache.c:422: _cairo_cache_lookup: Assertion `cache->max_memory >= (cache->used_memory + new_entry->memory)' failed. + * + * I'll have to go back and try the original test after I fix this. + * + * 2004-11-13 Carl Worth + * + * Found the bug. cairo_gstate_select_font was noticing when the + * same font was selected twice in a row and was erroneously failing + * to free the old reference. Committed a fix and verified it also + * fixed the original test case. + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + /* Once there was a bug that choked when selecting the same font twice. */ + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); + cairo_set_font_size (cr, 40.0); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); + cairo_set_font_size (cr, 40.0); + cairo_move_to (cr, 10, 50); + cairo_show_text (cr, "hello"); + + /* Then there was a bug that choked when selecting a font too big + * for the cache. */ + + cairo_set_font_size (cr, 500); + cairo_show_text (cr, "hello"); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (text_cache_crash, + "Test case for bug causing an assertion failure in _cairo_cache_lookup", + "text, stress", /* keywords */ + NULL, /* requirements */ + 0, 0, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/text-glyph-range.c b/local/recipes/libs/cairo/source/test/text-glyph-range.c new file mode 100644 index 0000000000..75b87d63a5 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/text-glyph-range.c @@ -0,0 +1,125 @@ +/* -*- Mode: c; c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2006 Brian Ewins. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Brian Ewins not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Brian Ewins makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * BRIAN EWINS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL BRIAN EWINS BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Brian Ewins + */ + +/* Related to bug 9530 + * + * cairo_glyph_t can contain any unsigned long in its 'index', the intention + * being that it is large enough to hold a pointer. However, this means that + * it can specify many glyph indexes which don't exist in the font, and may + * exceed the range of legal glyph indexes for the font backend. It may + * also contain special values that are not usable as indexes - e.g. 0xffff is + * kATSDeletedGlyphcode in ATSUI, a glyph that should not be drawn. + * The font backends should handle all legal and out-of-range values + * consistently. + * + * This test expects that operations on out-of-range and missing glyphs should + * act as if they were zero-width. + */ + +#include "cairo-test.h" + +#define WIDTH 100 +#define HEIGHT 75 +#define NUM_TEXT 20 +#define TEXT_SIZE 12 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_text_extents_t extents; + int i; + /* Glyphs with no paths followed by 'cairo', the additional + * text is to make the space obvious. + */ + long int index[] = { + 0, /* 'no matching glyph' */ + 0xffff, /* kATSDeletedGlyphCode */ + 0x1ffff, /* out of range */ + -1L, /* out of range */ + 70, 68, 76, 85, 82 /* 'cairo' */ + }; + + /* We draw in the default black, so paint white first. */ + cairo_save (cr); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_restore (cr); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (cr, 16); + + for (i = 0; i < 9; i++) { + /* since we're just drawing glyphs directly we need to position them. */ + cairo_glyph_t glyph = { + index[i], 10 * i, 25 + }; + + /* test cairo_glyph_extents. Every glyph index should + * have extents, invalid glyphs should be zero-width. + */ + cairo_move_to (cr, glyph.x, glyph.y); + cairo_set_line_width (cr, 1.0); + cairo_glyph_extents (cr, &glyph, 1, &extents); + cairo_rectangle (cr, + glyph.x + extents.x_bearing - 0.5, + glyph.y + extents.y_bearing - 0.5, + extents.width + 1, + extents.height + 1); + cairo_set_source_rgb (cr, 1, 0, 0); /* red */ + cairo_stroke (cr); + + /* test cairo_show_glyphs. Every glyph index should be + * drawable, invalid glyph indexes should draw nothing. + */ + cairo_set_source_rgb (cr, 0, 0, 0); /* black */ + cairo_show_glyphs (cr, &glyph, 1); + cairo_move_to (cr, glyph.x, glyph.y); + + /* test cairo_glyph_path. Every glyph index should produce + * a path, invalid glyph indexes should have empty paths. + */ + /* Change the glyph position + * so that the paths are visible. + */ + glyph.y = 55; + cairo_move_to (cr, glyph.x, glyph.y); + cairo_glyph_path (cr, &glyph, 1); + cairo_fill (cr); + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (text_glyph_range, + "Tests show_glyphs, glyph_path, glyph_extents with out of range glyph ids." + "\nft and atsui font backends fail, misreporting errors from FT_Load_Glyph and ATSUGlyphGetCubicPaths", + "text, stress", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/text-pattern.c b/local/recipes/libs/cairo/source/test/text-pattern.c new file mode 100644 index 0000000000..60267d6580 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/text-pattern.c @@ -0,0 +1,73 @@ +/* + * Copyright © 2005 Tim Rowley + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Tim Rowley + */ + +#include "cairo-test.h" + +#define IMAGE_WIDTH 128 +#define IMAGE_HEIGHT 64 + + +static void +draw_text_pattern (cairo_t *cr, double alpha) +{ + cairo_pattern_t *pat; + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + + pat = cairo_pattern_create_linear (0.0, 0.0, 1, 1); + cairo_pattern_add_color_stop_rgba (pat, 1, 1, 0, 0, alpha); + cairo_pattern_add_color_stop_rgba (pat, 0, 0, 0, 1, alpha); + cairo_set_source (cr, pat); + + /* test rectangle - make sure the gradient is set correctly */ + cairo_rectangle (cr, 0, 0, 0.1, 1); + cairo_fill (cr); + + cairo_set_font_size (cr, 0.4); + cairo_move_to (cr, 0.1, 0.6); + cairo_show_text (cr, "cairo"); + + cairo_pattern_destroy (pat); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_scale (cr, width/2, height); + draw_text_pattern (cr, 1.0); + cairo_translate (cr, 1, 0); + draw_text_pattern (cr, 0.5); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (text_pattern, + "Patterned Text", + "text, pattern", /* keywords */ + NULL, /* requirements */ + IMAGE_WIDTH, IMAGE_HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/text-rotate.c b/local/recipes/libs/cairo/source/test/text-rotate.c new file mode 100644 index 0000000000..0a805ac677 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/text-rotate.c @@ -0,0 +1,189 @@ +/* + * Copyright © 2004 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +/* Bug history + * + * 2004-11-03 Steve Chaplin + * + * Reported bug on mailing list: + * + * From: Steve Chaplin + * To: cairo@cairographics.org + * Date: Thu, 04 Nov 2004 00:00:17 +0800 + * Subject: [cairo] Rotated text bug on drawable target + * + * The attached file draws text rotated 90 degrees first to a PNG file and + * then to a drawable. The PNG file looks fine, the text on the drawable is + * unreadable. + * + * Steve + * + * 2004-11-03 Carl Worth + * + * Looks like the major problems with this bug appeared in the great + * font rework between 0.1.23 and 0.2.0. And it looks like we need + * to fix the regression test suite to test the xlib target (since + * the bug does not show up in the png backend). + * + * Hmm... Actually, things don't look perfect even in the PNG + * output. Look at how that 'o' moves around. It's particularly off + * in the case where it's rotated by PI. + * + * And I'm still not sure about what to do for test cases with + * text--a new version of freetype will change everything. We may + * need to add a simple backend for stroked fonts and add a simple + * builtin font to cairo for pixel-perfect tests with text. + * + * 2005-08-23 + * + * It appears that the worst placement and glyph selection problems + * have now been resolved. In the past some letters were noticeably + * of a different size at some rotations, and there was a lot of + * drift away from the baseline. These problems do not appear + * anymore. + * + * Another thing that helps is that we now have font options which + * we can use to disable hinting in order to get more repeatable + * results. I'm doing that in this test now. + * + * There are still some subtle positioning problems which I'm + * assuming are due to the lack of finer-than-whole-pixel glyph + * positioning. I'm generating a reference image now by replacing + * cairo_show_text with cairo_text_path; cairo_fill. This will let + * us look more closely at the remaining positioning problems. (In + * particular, I want to make sure we're rounding as well as + * possible). + * + * 2007-02-21 + * + * Seems like all the "bugs" have been fixed and all remaining is + * missing support for subpixel glyph positioning. Removing from + * XFAIL now. + */ + +#include "cairo-test.h" + +#define WIDTH 150 +#define HEIGHT 150 +#define NUM_TEXT 20 +#define TEXT_SIZE 12 + +/* Draw the word cairo at NUM_TEXT different angles. + * We separate the circle into quadrants to reduce + * numerical errors i.e. so each quarter is pixel-aligned. + */ +static void +draw_quadrant (cairo_t *cr, + const char *text, + const cairo_text_extents_t *extents, + const cairo_matrix_t *transform, + int x_off, int y_off) +{ + int i; + + for (i = 0; i < NUM_TEXT/4; i++) { + cairo_save (cr); + cairo_rotate (cr, 2*M_PI*i/NUM_TEXT); + cairo_transform (cr, transform); + cairo_set_line_width (cr, 1.0); + cairo_rectangle (cr, x_off - 0.5, y_off - 0.5, extents->width + 1, extents->height + 1); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_stroke (cr); + cairo_move_to (cr, x_off - extents->x_bearing, y_off - extents->y_bearing); + cairo_set_source_rgb (cr, 0, 0, 0); +#if CAIRO_TEST_GENERATE_REFERENCE_IMAGE + cairo_text_path (cr, text); + cairo_fill (cr); +#else + cairo_show_text (cr, text); +#endif + cairo_restore (cr); + } +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_text_extents_t extents; + cairo_font_options_t *font_options; + const char text[] = "cairo"; + int x_off, y_off; + cairo_matrix_t m; + + /* paint white so we don't need separate ref images for + * RGB24 and ARGB32 */ + cairo_set_source_rgb (cr, 1., 1., 1.); + cairo_paint (cr); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (cr, TEXT_SIZE); + + font_options = cairo_font_options_create (); + + cairo_get_font_options (cr, font_options); + cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_OFF); + + cairo_set_font_options (cr, font_options); + cairo_font_options_destroy (font_options); + + cairo_set_source_rgb (cr, 0, 0, 0); + + cairo_translate (cr, WIDTH/2.0, HEIGHT/2.0); + + cairo_text_extents (cr, text, &extents); + + if (NUM_TEXT == 1) { + x_off = y_off = 0; + } else { + y_off = - floor (0.5 + extents.height / 2.0); + x_off = floor (0.5 + (extents.height+1) / (2 * tan (M_PI/NUM_TEXT))); + } + + cairo_save (cr); + cairo_matrix_init_identity (&m); + draw_quadrant (cr, text, &extents, &m, x_off, y_off); + cairo_matrix_init (&m, 0, 1, -1, 0, 0, 0); + draw_quadrant (cr, text, &extents, &m, x_off, y_off); + cairo_restore (cr); + + cairo_save (cr); + cairo_scale (cr, -1, -1); + cairo_matrix_init_identity (&m); + draw_quadrant (cr, text, &extents, &m, x_off, y_off); + cairo_matrix_init (&m, 0, 1, -1, 0, 0, 0); + draw_quadrant (cr, text, &extents, &m, x_off, y_off); + cairo_restore (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (text_rotate, + "Tests show_text under various rotations", + "text, transform", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/text-subpixel.c b/local/recipes/libs/cairo/source/test/text-subpixel.c new file mode 100644 index 0000000000..3ea63b950a --- /dev/null +++ b/local/recipes/libs/cairo/source/test/text-subpixel.c @@ -0,0 +1,68 @@ +/* + * Copyright © 2019 Matthias Clasen + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Adrian Johnson + */ + +#include "cairo-test.h" + +#define WIDTH 300 +#define HEIGHT 200 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_font_options_t *font_options; + double size, y; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY "DejaVu Sans Mono", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + + font_options = cairo_font_options_create(); + cairo_get_font_options (cr, font_options); + cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_OFF); + cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE); + cairo_set_font_options (cr, font_options); + cairo_font_options_destroy (font_options); + + y = 0.0; + cairo_set_source_rgb (cr, 0, 0, 0); + for (size = 10.0; size <= 40.0; size += 3.3) { + cairo_set_font_size (cr, size); + y += size + 2.3; + cairo_move_to (cr, 5, y); + cairo_show_text (cr, "aaaaaaaaaa"); + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (text_subpixel_positioning, + "Test subpixel positioning", + "text, font", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/text-transform.c b/local/recipes/libs/cairo/source/test/text-transform.c new file mode 100644 index 0000000000..2cd7f100b1 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/text-transform.c @@ -0,0 +1,104 @@ +/* + * Copyright © 2006 Mozilla Corporation + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Mozilla Corporation not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Mozilla Corporation makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * MOZILLA CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL MOZILLA CORPORATION BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Vladimir Vukicevic + */ + +#include "cairo-test.h" + +#define SIZE 100 +#define PAD 5 + +#define FONT_SIZE 32.0 + +static const char *png_filename = "romedalen.png"; + +static void +draw_text (cairo_t *cr) +{ + cairo_matrix_t tm; + + /* skew */ + cairo_matrix_init (&tm, 1, 0, + -0.25, 1, + 0, 0); + cairo_matrix_scale (&tm, FONT_SIZE, FONT_SIZE); + cairo_set_font_matrix (cr, &tm); + + cairo_new_path (cr); + cairo_move_to (cr, 50, SIZE-PAD); + cairo_show_text (cr, "A"); + + /* rotate and scale */ + cairo_matrix_init_rotate (&tm, M_PI / 2); + cairo_matrix_scale (&tm, FONT_SIZE, FONT_SIZE * 2.0); + cairo_set_font_matrix (cr, &tm); + + cairo_new_path (cr); + cairo_move_to (cr, PAD, PAD + 25); + cairo_show_text (cr, "A"); + + cairo_matrix_init_rotate (&tm, M_PI / 2); + cairo_matrix_scale (&tm, FONT_SIZE * 2.0, FONT_SIZE); + cairo_set_font_matrix (cr, &tm); + + cairo_new_path (cr); + cairo_move_to (cr, PAD, PAD + 50); + cairo_show_text (cr, "A"); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_pattern_t *pattern; + + cairo_set_source_rgb (cr, 1., 1., 1.); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0., 0., 0.); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + + draw_text (cr); + + cairo_translate (cr, SIZE, SIZE); + cairo_rotate (cr, M_PI); + + pattern = cairo_test_create_pattern_from_png (ctx, png_filename); + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT); + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + + draw_text (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (text_transform, + "Test various applications of the font matrix", + "text, transform", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/text-unhinted-metrics.c b/local/recipes/libs/cairo/source/test/text-unhinted-metrics.c new file mode 100644 index 0000000000..352ab4ef2b --- /dev/null +++ b/local/recipes/libs/cairo/source/test/text-unhinted-metrics.c @@ -0,0 +1,73 @@ +/* + * Copyright © 2016 Adrian Johnson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Adrian Johnson + */ + +/* Test CAIRO_HINT_METRICS_OFF with a TrueType font. + * + * Based on the test case in https://lists.cairographics.org/archives/cairo/2016-April/027334.html + */ + +#include "cairo-test.h" + +#define WIDTH 100 +#define HEIGHT 100 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_font_options_t *font_options; + double size, y; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY "DejaVu Sans Mono", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + + font_options = cairo_font_options_create(); + cairo_get_font_options (cr, font_options); + cairo_font_options_set_hint_metrics (font_options, CAIRO_HINT_METRICS_OFF); + cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE); + cairo_set_font_options (cr, font_options); + cairo_font_options_destroy (font_options); + + y = 0.0; + cairo_set_source_rgb (cr, 0, 0, 0); + for (size = 8.0; size <= 10.0; size += 0.25) { + cairo_set_font_size (cr, size); + y += 10.0; + cairo_move_to (cr, 5, y); + cairo_show_text (cr, "abcdefghijklm"); + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (text_unhinted_metrics, + "Test CAIRO_HINT_METRICS_OFF", + "text, font", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/text-zero-len.c b/local/recipes/libs/cairo/source/test/text-zero-len.c new file mode 100644 index 0000000000..5e89816c85 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/text-zero-len.c @@ -0,0 +1,203 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Behdad Esfahbod + */ + +/* Related bug 5177 + * + * In short: + * + * _cairo_atsui_font_text_to_glyph with a zero-sized string crashes. + * + * Moreover, the fallback path in cairo_scaled_font_text_to_glyphs() + * when handling a zero-sized string, allocates a zero-sized glyph array + * and when NULL is returned by malloc, recognizes that as an out-of-memory + * error. The glibc implementation of malloc() does not return NULL from + * malloc(0), but I don't think it's a safe assumption. + * + * By just bailing out on zero-sized text, we fix both issues. + */ + +#include "cairo-test.h" + +#define NUM_TEXT 20 +#define TEXT_SIZE 12 + +static cairo_bool_t +text_extents_equal (const cairo_text_extents_t *A, + const cairo_text_extents_t *B) +{ + return A->x_bearing == B->x_bearing && + A->y_bearing == B->y_bearing && + A->width == B->width && + A->height == B->height && + A->x_advance == B->x_advance && + A->y_advance == B->y_advance; +} + +static cairo_bool_t +font_extents_equal (const cairo_font_extents_t *A, + const cairo_font_extents_t *B) +{ + return A->ascent == B->ascent && + A->descent == B->descent && + A->height == B->height && + A->max_x_advance == B->max_x_advance && + A->max_y_advance == B->max_y_advance; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + cairo_text_extents_t extents, nil_extents; + cairo_font_extents_t font_extents, nil_font_extents; + cairo_scaled_font_t *scaled_font; + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (cr, 16); + + cairo_move_to (cr, 10, 25); + cairo_show_text (cr, NULL); + cairo_show_text (cr, ""); + cairo_show_glyphs (cr, NULL, 0); + cairo_show_glyphs (cr, (void*)8, 0); + + cairo_move_to (cr, 10, 55); + cairo_text_path (cr, NULL); + cairo_text_path (cr, ""); + cairo_glyph_path (cr, (void*)8, 0); + cairo_fill (cr); + + memset (&nil_extents, 0, sizeof (cairo_text_extents_t)); + + memset (&extents, 0xff, sizeof (cairo_text_extents_t)); + cairo_text_extents (cr, "", &extents); + if (! text_extents_equal (&extents, &nil_extents)) { + cairo_test_log (ctx, "Error: cairo_text_extents(\"\"); extents (%g, %g, %g, %g, %g, %g)\n", + extents.x_bearing, extents.y_bearing, + extents.width, extents.height, + extents.x_advance, extents.y_advance); + return CAIRO_TEST_FAILURE; + } + + memset (&extents, 0xff, sizeof (cairo_text_extents_t)); + cairo_text_extents (cr, NULL, &extents); + if (! text_extents_equal (&extents, &nil_extents)) { + cairo_test_log (ctx, "Error: cairo_text_extents(NULL); extents (%g, %g, %g, %g, %g, %g)\n", + extents.x_bearing, extents.y_bearing, + extents.width, extents.height, + extents.x_advance, extents.y_advance); + return CAIRO_TEST_FAILURE; + } + + memset (&extents, 0xff, sizeof (cairo_text_extents_t)); + cairo_glyph_extents (cr, (void*)8, 0, &extents); + if (! text_extents_equal (&extents, &nil_extents)) { + cairo_test_log (ctx, "Error: cairo_glyph_extents(); extents (%g, %g, %g, %g, %g, %g)\n", + extents.x_bearing, extents.y_bearing, + extents.width, extents.height, + extents.x_advance, extents.y_advance); + return CAIRO_TEST_FAILURE; + } + + scaled_font = cairo_get_scaled_font (cr); + + memset (&extents, 0xff, sizeof (cairo_text_extents_t)); + cairo_scaled_font_text_extents (scaled_font, "", &extents); + if (! text_extents_equal (&extents, &nil_extents)) { + cairo_test_log (ctx, "Error: cairo_scaled_font_text_extents(\"\"); extents (%g, %g, %g, %g, %g, %g)\n", + extents.x_bearing, extents.y_bearing, + extents.width, extents.height, + extents.x_advance, extents.y_advance); + return CAIRO_TEST_FAILURE; + } + + memset (&extents, 0xff, sizeof (cairo_text_extents_t)); + cairo_scaled_font_text_extents (scaled_font, NULL, &extents); + if (! text_extents_equal (&extents, &nil_extents)) { + cairo_test_log (ctx, "Error: cairo_scaled_font_text_extents(NULL); extents (%g, %g, %g, %g, %g, %g)\n", + extents.x_bearing, extents.y_bearing, + extents.width, extents.height, + extents.x_advance, extents.y_advance); + return CAIRO_TEST_FAILURE; + } + + memset (&extents, 0xff, sizeof (cairo_text_extents_t)); + cairo_scaled_font_glyph_extents (scaled_font, (void*)8, 0, &extents); + if (! text_extents_equal (&extents, &nil_extents)) { + cairo_test_log (ctx, "Error: cairo_scaled_font_glyph_extents(NULL); extents (%g, %g, %g, %g, %g, %g)\n", + extents.x_bearing, extents.y_bearing, + extents.width, extents.height, + extents.x_advance, extents.y_advance); + return CAIRO_TEST_FAILURE; + } + + /* Lets also try font size 0 while here */ + cairo_set_font_size (cr, 0); + + memset (&extents, 0xff, sizeof (cairo_text_extents_t)); + cairo_text_extents (cr, "test", &extents); + if (! text_extents_equal (&extents, &nil_extents)) { + cairo_test_log (ctx, "Error: cairo_set_font_size(0); cairo_text_extents(\"test\"); extents (%g, %g, %g, %g, %g, %g)\n", + extents.x_bearing, extents.y_bearing, + extents.width, extents.height, + extents.x_advance, extents.y_advance); + return CAIRO_TEST_FAILURE; + } + + memset (&nil_font_extents, 0, sizeof (cairo_font_extents_t)); + + memset (&font_extents, 0xff, sizeof (cairo_font_extents_t)); + cairo_font_extents (cr, &font_extents); + if (! font_extents_equal (&font_extents, &nil_font_extents)) { + cairo_test_log (ctx, "Error: cairo_set_font_size(0); cairo_font_extents(); extents (%g, %g, %g, %g, %g)\n", + font_extents.ascent, font_extents.descent, + font_extents.height, + font_extents.max_x_advance, font_extents.max_y_advance); + return CAIRO_TEST_FAILURE; + } + + scaled_font = cairo_get_scaled_font (cr); + + memset (&font_extents, 0xff, sizeof (cairo_font_extents_t)); + cairo_scaled_font_extents (scaled_font, &font_extents); + if (! font_extents_equal (&font_extents, &nil_font_extents)) { + cairo_test_log (ctx, "Error: cairo_set_font_size(0); cairo_scaled_font_extents(); extents (%g, %g, %g, %g, %g)\n", + font_extents.ascent, font_extents.descent, + font_extents.height, + font_extents.max_x_advance, font_extents.max_y_advance); + return CAIRO_TEST_FAILURE; + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (text_zero_len, + "Tests show_text and text_path with a zero-sized string", + "text, stress, extents", /* keywords */ + NULL, /* requirements */ + 0, 0, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/thin-lines.c b/local/recipes/libs/cairo/source/test/thin-lines.c new file mode 100644 index 0000000000..c501254be5 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/thin-lines.c @@ -0,0 +1,95 @@ +/* + * Copyright © 2015 Adrian Johnson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Adrian Johnson + */ + +#include "cairo-test.h" + +#define CELL_WIDTH 20 +#define CELL_HEIGHT 20 +#define PAD 2 +#define IMAGE_WIDTH (CELL_WIDTH*3 + PAD*4) +#define IMAGE_HEIGHT (CELL_HEIGHT*4 + PAD*5) + + +static void +draw_lines(cairo_t *cr) +{ + /* horizontal line */ + cairo_translate (cr, PAD, PAD); + cairo_move_to (cr, 0, CELL_HEIGHT/2); + cairo_line_to (cr, CELL_WIDTH, CELL_HEIGHT/2); + cairo_stroke (cr); + + /* vertical line */ + cairo_translate (cr, 0, CELL_HEIGHT + PAD); + cairo_move_to (cr, CELL_WIDTH/2, 0); + cairo_line_to (cr, CELL_WIDTH/2, CELL_HEIGHT); + cairo_stroke (cr); + + /* diagonal line */ + cairo_translate (cr, 0, CELL_HEIGHT + PAD); + cairo_move_to (cr, 0, CELL_HEIGHT); + cairo_line_to (cr, CELL_WIDTH, 0); + cairo_stroke (cr); + + /* curved line */ + cairo_translate (cr, 0, CELL_HEIGHT + PAD); + cairo_move_to (cr, CELL_WIDTH, 0); + cairo_curve_to (cr, 0, 0, + CELL_WIDTH, CELL_HEIGHT, + 0, CELL_HEIGHT); + cairo_stroke (cr); +} + +#define FIXED_POINT_MIN (1.0/256) + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_save (cr); + cairo_set_line_width (cr, FIXED_POINT_MIN*10.0); + draw_lines (cr); + cairo_restore (cr); + + cairo_translate (cr, CELL_WIDTH + PAD, 0); + cairo_save (cr); + cairo_set_line_width (cr, FIXED_POINT_MIN); + draw_lines (cr); + cairo_restore (cr); + + cairo_translate (cr, CELL_WIDTH + PAD, 0); + cairo_save (cr); + cairo_set_line_width (cr, FIXED_POINT_MIN/10.0); + draw_lines (cr); + cairo_restore (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (thin_lines, + "Tests that very thin lines are output to vector surfaces", + "stroke", /* keywords */ + NULL, /* requirements */ + IMAGE_WIDTH, IMAGE_HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/tiger.c b/local/recipes/libs/cairo/source/test/tiger.c new file mode 100644 index 0000000000..059bb849f6 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/tiger.c @@ -0,0 +1,85 @@ +/* + * 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. + */ + +#include "cairo-test.h" + +#include "tiger.inc" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + unsigned int i; + + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgba (cr, 0.1, 0.2, 0.3, 1.0); + cairo_paint (cr); + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + + cairo_translate (cr, width/2, height/2); + cairo_scale (cr, .85, .85); + + for (i = 0; i < ARRAY_LENGTH(tiger_commands); i++) { + const struct command *cmd = &tiger_commands[i]; + switch (cmd->type) { + case 'm': + cairo_move_to (cr, cmd->x0, cmd->y0); + break; + case 'l': + cairo_line_to (cr, cmd->x0, cmd->y0); + break; + case 'c': + cairo_curve_to (cr, + cmd->x0, cmd->y0, + cmd->x1, cmd->y1, + cmd->x2, cmd->y2); + break; + case 'f': + cairo_set_source_rgba (cr, + cmd->x0, cmd->y0, cmd->x1, cmd->y1); + cairo_fill (cr); + break; + } + } + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +a1_draw (cairo_t *cr, int width, int height) +{ + cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); + return draw (cr, width, height); +} + +CAIRO_TEST (tiger, + "Check the fidelity of the rasterisation.", + "raster", /* keywords */ + NULL, /* requirements */ + 500, 500, + NULL, draw) + +CAIRO_TEST (a1_tiger, + "Check the fidelity of the rasterisation.", + "fill", /* keywords */ + "target=raster", /* requirements */ + 500, 500, + NULL, a1_draw) diff --git a/local/recipes/libs/cairo/source/test/tiger.inc b/local/recipes/libs/cairo/source/test/tiger.inc new file mode 100644 index 0000000000..419b97989f --- /dev/null +++ b/local/recipes/libs/cairo/source/test/tiger.inc @@ -0,0 +1,2316 @@ +static const struct command { + char type; + float x0, y0; + float x1, y1; + float x2, y2; +} tiger_commands[] = { +{'m', -122.30, 84.28, 0, 0, 0, 0}, +{'c', -122.30, 84.28, -122.20 ,86.18, -123.03, 86.16}, +{'c', -123.85, 86.14, -140.31 ,38.07, -160.83, 40.31}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', -118.77, 81.26, 0, 0, 0, 0}, +{'c', -118.77, 81.26, -119.32 ,83.08, -120.09, 82.78}, +{'c', -120.86, 82.48, -119.98 ,31.68, -140.04, 26.80}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', -91.28, 123.59, 0, 0, 0, 0}, +{'c', -91.28, 123.59, -89.65 ,124.55, -90.12, 125.23}, +{'c', -90.59, 125.90, -139.76 ,113.10, -149.22, 131.46}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', -94.09, 133.80, 0, 0, 0, 0}, +{'c', -94.09, 133.80, -92.24 ,134.20, -92.47, 134.99}, +{'c', -92.70, 135.78, -143.41 ,139.12, -146.60, 159.52}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', -98.30, 128.28, 0, 0, 0, 0}, +{'c', -98.30, 128.28, -96.53 ,128.94, -96.87, 129.69}, +{'c', -97.22, 130.44, -147.87 ,126.35, -154.00, 146.06}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', -109.01, 110.07, 0, 0, 0, 0}, +{'c', -109.01, 110.07, -107.70 ,111.45, -108.34, 111.97}, +{'c', -108.98, 112.49, -152.72 ,86.63, -166.87, 101.68}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', -116.55, 114.26, 0, 0, 0, 0}, +{'c', -116.55, 114.26, -115.10 ,115.48, -115.67, 116.07}, +{'c', -116.25, 116.66, -162.64 ,95.92, -174.99, 112.47}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', -119.15, 118.33, 0, 0, 0, 0}, +{'c', -119.15, 118.33, -117.55 ,119.34, -118.04, 120.01}, +{'c', -118.53, 120.67, -167.31 ,106.45, -177.29, 124.52}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', -108.42, 118.95, 0, 0, 0, 0}, +{'c', -108.42, 118.95, -107.30 ,120.48, -108.00, 120.92}, +{'c', -108.70, 121.35, -148.77 ,90.10, -164.73, 103.21}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', -128.20, 90.00, 0, 0, 0, 0}, +{'c', -128.20, 90.00, -127.60 ,91.80, -128.40, 92.00}, +{'c', -129.20, 92.20, -157.80 ,50.20, -177.00, 57.80}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', -127.50, 96.98, 0, 0, 0, 0}, +{'c', -127.50, 96.98, -126.53 ,98.61, -127.27, 98.97}, +{'c', -128.01, 99.34, -164.99 ,64.50, -182.10, 76.06}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', -127.62, 101.35, 0, 0, 0, 0}, +{'c', -127.62, 101.35, -126.50 ,102.88, -127.20, 103.31}, +{'c', -127.90, 103.75, -167.97 ,72.50, -183.93, 85.61}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', -129.83, 103.06, 0, 0, 0, 0}, +{'c', -129.33, 109.11, -128.34 ,115.68, -126.60, 118.80}, +{'c', -126.60, 118.80, -130.20 ,131.20, -121.40, 144.40}, +{'c', -121.40, 144.40, -121.80 ,151.60, -120.20, 154.80}, +{'c', -120.20, 154.80, -116.20 ,163.20, -111.40, 164.00}, +{'c', -107.52, 164.65, -98.79 ,167.72, -88.93, 169.12}, +{'c', -88.93, 169.12, -71.80 ,183.20, -75.00, 196.00}, +{'c', -75.00, 196.00, -75.40 ,212.40, -79.00, 214.00}, +{'c', -79.00, 214.00, -67.40 ,202.80, -77.00, 219.60}, +{'l', -81.40, 238.40, 0, 0, 0, 0}, +{'c', -81.40, 238.40, -55.80 ,216.80, -71.40, 235.20}, +{'l', -81.40, 261.20, 0, 0, 0, 0}, +{'c', -81.40, 261.20, -61.80 ,242.80, -69.00, 251.20}, +{'l', -72.20, 260.00, 0, 0, 0, 0}, +{'c', -72.20, 260.00, -29.00 ,232.80, -59.80, 262.40}, +{'c', -59.80, 262.40, -51.80 ,258.80, -47.40, 261.60}, +{'c', -47.40, 261.60, -40.60 ,260.40, -41.40, 262.00}, +{'c', -41.40, 262.00, -62.20 ,272.40, -65.80, 290.80}, +{'c', -65.80, 290.80, -57.40 ,280.80, -60.60, 291.60}, +{'l', -60.20, 303.20, 0, 0, 0, 0}, +{'c', -60.20, 303.20, -56.20 ,281.60, -56.60, 319.20}, +{'c', -56.60, 319.20, -37.40 ,301.20, -49.00, 322.00}, +{'l', -49.00, 338.80, 0, 0, 0, 0}, +{'c', -49.00, 338.80, -33.80 ,322.40, -40.20, 335.20}, +{'c', -40.20, 335.20, -30.20 ,326.40, -34.20, 341.60}, +{'c', -34.20, 341.60, -35.00 ,352.00, -30.60, 340.80}, +{'c', -30.60, 340.80, -14.60 ,310.20, -20.60, 336.40}, +{'c', -20.60, 336.40, -21.40 ,355.60, -16.60, 340.80}, +{'c', -16.60, 340.80, -16.20 ,351.20, -7.00, 358.40}, +{'c', -7.00, 358.40, -8.20 ,307.60, 4.60, 343.60}, +{'l', 8.60, 360.00, 0, 0, 0, 0}, +{'c', 8.60, 360.00, 11.40 ,350.80, 11.00, 345.60}, +{'c', 11.00, 345.60, 25.80 ,329.20, 19.00, 353.60}, +{'c', 19.00, 353.60, 34.20 ,330.80, 31.00, 344.00}, +{'c', 31.00, 344.00, 23.40 ,360.00, 25.00, 364.80}, +{'c', 25.00, 364.80, 41.80 ,330.00, 43.00, 328.40}, +{'c', 43.00, 328.40, 41.00 ,370.80, 51.80, 334.80}, +{'c', 51.80, 334.80, 57.40 ,346.80, 54.60, 351.20}, +{'c', 54.60, 351.20, 62.60 ,343.20, 61.80, 340.00}, +{'c', 61.80, 340.00, 66.40 ,331.80, 69.20, 345.40}, +{'c', 69.20, 345.40, 71.00 ,354.80, 72.60, 351.60}, +{'c', 72.60, 351.60, 76.60 ,375.60, 77.80, 352.80}, +{'c', 77.80, 352.80, 79.40 ,339.20, 72.20, 327.60}, +{'c', 72.20, 327.60, 73.00 ,324.40, 70.20, 320.40}, +{'c', 70.20, 320.40, 83.80 ,342.00, 76.60, 313.20}, +{'c', 76.60, 313.20, 87.80 ,321.20, 89.00, 321.20}, +{'c', 89.00, 321.20, 75.40 ,298.00, 84.20, 302.80}, +{'c', 84.20, 302.80, 79.00 ,292.40, 97.00, 304.40}, +{'c', 97.00, 304.40, 81.00 ,288.40, 98.60, 298.00}, +{'c', 98.60, 298.00, 106.60 ,304.40, 99.00, 294.40}, +{'c', 99.00, 294.40, 84.60 ,278.40, 106.60, 296.40}, +{'c', 106.60, 296.40, 118.20 ,312.80, 119.00, 315.60}, +{'c', 119.00, 315.60, 109.00 ,286.40, 104.60, 283.60}, +{'c', 104.60, 283.60, 113.00 ,247.20, 154.20, 262.80}, +{'c', 154.20, 262.80, 161.00 ,280.00, 165.40, 261.60}, +{'c', 165.40, 261.60, 178.20 ,255.20, 189.40, 282.80}, +{'c', 189.40, 282.80, 193.40 ,269.20, 192.60, 266.40}, +{'c', 192.60, 266.40, 199.40 ,267.60, 198.60, 266.40}, +{'c', 198.60, 266.40, 211.80 ,270.80, 213.00, 270.00}, +{'c', 213.00, 270.00, 219.80 ,276.80, 220.20, 273.20}, +{'c', 220.20, 273.20, 229.40 ,276.00, 227.40, 272.40}, +{'c', 227.40, 272.40, 236.20 ,288.00, 236.60, 291.60}, +{'l', 239.00, 277.60, 0, 0, 0, 0}, +{'l', 241.00, 280.40, 0, 0, 0, 0}, +{'c', 241.00, 280.40, 242.60 ,272.80, 241.80, 271.60}, +{'c', 241.00, 270.40, 261.80 ,278.40, 266.60, 299.20}, +{'l', 268.60, 307.60, 0, 0, 0, 0}, +{'c', 268.60, 307.60, 274.60 ,292.80, 273.00, 288.80}, +{'c', 273.00, 288.80, 278.20 ,289.60, 278.60, 294.00}, +{'c', 278.60, 294.00, 282.60 ,270.80, 277.80, 264.80}, +{'c', 277.80, 264.80, 282.20 ,264.00, 283.40, 267.60}, +{'l', 283.40, 260.40, 0, 0, 0, 0}, +{'c', 283.40, 260.40, 290.60 ,261.20, 290.60, 258.80}, +{'c', 290.60, 258.80, 295.00 ,254.80, 297.00, 259.60}, +{'c', 297.00, 259.60, 284.60 ,224.40, 303.00, 243.60}, +{'c', 303.00, 243.60, 310.20 ,254.40, 306.60, 235.60}, +{'c', 303.00, 216.80, 299.00 ,215.20, 303.80, 214.80}, +{'c', 303.80, 214.80, 304.60 ,211.20, 302.60, 209.60}, +{'c', 300.60, 208.00, 303.80 ,209.60, 303.80, 209.60}, +{'c', 303.80, 209.60, 308.60 ,213.60, 303.40, 191.60}, +{'c', 303.40, 191.60, 309.80 ,193.20, 297.80, 164.00}, +{'c', 297.80, 164.00, 300.60 ,161.60, 296.60, 153.20}, +{'c', 296.60, 153.20, 304.60 ,157.60, 307.40, 156.00}, +{'c', 307.40, 156.00, 307.00 ,154.40, 303.80, 150.40}, +{'c', 303.80, 150.40, 282.20 ,95.60, 302.60, 117.60}, +{'c', 302.60, 117.60, 314.45 ,131.15, 308.05, 108.35}, +{'c', 308.05, 108.35, 298.94 ,84.34, 299.72, 80.05}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', 299.72, 80.25, 0, 0, 0, 0}, +{'c', 300.35, 80.43, 302.55 ,81.55, 303.80, 83.20}, +{'c', 303.80, 83.20, 310.60 ,94.00, 305.40, 75.60}, +{'c', 305.40, 75.60, 296.20 ,46.80, 305.00, 58.00}, +{'c', 305.00, 58.00, 311.00 ,65.20, 307.80, 51.60}, +{'c', 303.94, 35.17, 301.40 ,28.80, 301.40, 28.80}, +{'c', 301.40, 28.80, 313.00 ,33.60, 286.20, -6.00}, +{'l', 295.00, -2.40, 0, 0, 0, 0}, +{'c', 295.00, -2.40, 275.40 ,-42.00, 253.80, -47.20}, +{'l', 245.80, -53.20, 0, 0, 0, 0}, +{'c', 245.80, -53.20, 284.20 ,-91.20, 271.40, -128.00}, +{'c', 271.40, -128.00, 264.60 ,-133.20, 255.00, -124.00}, +{'c', 255.00, -124.00, 248.60 ,-119.20, 242.60, -120.80}, +{'c', 242.60, -120.80, 211.80 ,-119.60, 209.80, -119.60}, +{'c', 207.80, -119.60, 173.00 ,-156.80, 107.40, -139.20}, +{'c', 107.40, -139.20, 102.20 ,-137.20, 97.80, -138.40}, +{'c', 97.80, -138.40, 79.40 ,-154.40, 30.60, -131.60}, +{'c', 30.60, -131.60, 20.60 ,-129.60, 19.00, -129.60}, +{'c', 17.40, -129.60, 14.60 ,-129.60, 6.60, -123.20}, +{'c', -1.40, -116.80, -1.80 ,-116.00, -3.80, -114.40}, +{'c', -3.80, -114.40, -20.20 ,-103.20, -25.00, -102.40}, +{'c', -25.00, -102.40, -36.60 ,-96.00, -41.00, -86.00}, +{'l', -44.60, -84.80, 0, 0, 0, 0}, +{'c', -44.60, -84.80, -46.20 ,-77.60, -46.60, -76.40}, +{'c', -46.60, -76.40, -51.40 ,-72.80, -52.20, -67.20}, +{'c', -52.20, -67.20, -61.00 ,-61.20, -60.60, -56.80}, +{'c', -60.60, -56.80, -62.20 ,-51.60, -63.00, -46.80}, +{'c', -63.00, -46.80, -70.20 ,-42.00, -69.40, -39.20}, +{'c', -69.40, -39.20, -77.00 ,-25.20, -75.80, -18.40}, +{'c', -75.80, -18.40, -82.20 ,-18.80, -85.00, -16.40}, +{'c', -85.00, -16.40, -85.80 ,-11.60, -87.40, -11.20}, +{'c', -87.40, -11.20, -90.20 ,-10.00, -87.80, -6.00}, +{'c', -87.80, -6.00, -89.40 ,-3.20, -89.80, -1.60}, +{'c', -89.80, -1.60, -89.00 ,1.20, -93.40, 6.80}, +{'c', -93.40, 6.80, -99.80 ,25.60, -97.80, 30.80}, +{'c', -97.80, 30.80, -97.40 ,35.60, -100.20, 37.20}, +{'c', -100.20, 37.20, -103.80 ,36.80, -95.40, 48.80}, +{'c', -95.40, 48.80, -94.60 ,50.00, -97.80, 52.40}, +{'c', -97.80, 52.40, -115.00 ,56.00, -117.40, 72.40}, +{'c', -117.40, 72.40, -131.00 ,87.20, -131.00, 92.40}, +{'c', -131.00, 94.70, -130.73 ,97.85, -130.03, 102.47}, +{'c', -130.03, 102.47, -130.60 ,110.80, -103.00, 111.60}, +{'f', 0.804000,0.469000,0.134000,1.000000,0,0 }, +{'m', -115.60, 102.60, 0, 0, 0, 0}, +{'c', -140.60, 63.20, -126.20 ,119.60, -126.20, 119.60}, +{'c', -117.40, 154.00, 12.20 ,116.40, 12.20, 116.40}, +{'c', 12.20, 116.40, 181.00 ,86.00, 192.20, 82.00}, +{'c', 203.40, 78.00, 298.60 ,84.40, 298.60, 84.40}, +{'l', 293.00, 67.60, 0, 0, 0, 0}, +{'c', 228.20, 21.20, 209.00 ,44.40, 195.40, 40.40}, +{'c', 181.80, 36.40, 184.20 ,46.00, 181.00, 46.80}, +{'c', 177.80, 47.60, 138.60 ,22.80, 132.20, 23.60}, +{'c', 125.80, 24.40, 100.46 ,0.65, 115.40, 32.40}, +{'c', 131.40, 66.40, 57.00 ,71.60, 40.20, 60.40}, +{'c', 23.40, 49.20, 47.40 ,78.80, 47.40, 78.80}, +{'c', 65.80, 98.80, 31.40 ,82.00, 31.40, 82.00}, +{'c', -3.00, 69.20, -27.00 ,94.80, -30.20, 95.60}, +{'c', -33.40, 96.40, -38.20 ,99.60, -39.00, 93.20}, +{'c', -39.80, 86.80, -47.31 ,70.10, -79.00, 96.40}, +{'c', -99.00, 113.00, -112.80 ,91.00, -112.80, 91.00}, +{'f', 0.804000,0.469000,0.134000,1.000000,0,0 }, +{'m', 133.51, 25.35, 0, 0, 0, 0}, +{'c', 127.11, 26.15, 101.74 ,2.41, 116.71, 34.15}, +{'c', 133.31, 69.35, 58.31 ,73.35, 41.51, 62.15}, +{'c', 24.71, 50.95, 48.71 ,80.55, 48.71, 80.55}, +{'c', 67.11, 100.55, 32.71 ,83.75, 32.71, 83.75}, +{'c', -1.69, 70.95, -25.69 ,96.55, -28.89, 97.35}, +{'c', -32.09, 98.15, -36.89 ,101.35, -37.69, 94.95}, +{'c', -38.49, 88.55, -45.87 ,72.01, -77.69, 98.15}, +{'c', -98.93, 115.49, -112.42 ,94.04, -112.42, 94.04}, +{'l', -115.62, 104.15, 0, 0, 0, 0}, +{'c', -140.62, 64.35, -125.55 ,122.66, -125.55, 122.66}, +{'c', -116.75, 157.06, 13.51 ,118.15, 13.51, 118.15}, +{'c', 13.51, 118.15, 182.31 ,87.75, 193.51, 83.75}, +{'c', 204.71, 79.75, 299.04 ,86.07, 299.04, 86.07}, +{'l', 293.51, 68.76, 0, 0, 0, 0}, +{'c', 228.71, 22.36, 210.31 ,46.15, 196.71, 42.15}, +{'c', 183.11, 38.15, 185.51 ,47.75, 182.31, 48.55}, +{'f', 0.938000,0.469000,0.201000,1.000000,0,0 }, +{'m', 134.82, 27.09, 0, 0, 0, 0}, +{'c', 128.42, 27.89, 103.69 ,3.86, 118.02, 35.89}, +{'c', 134.22, 72.09, 59.62 ,75.09, 42.82, 63.89}, +{'c', 26.02, 52.69, 50.02 ,82.29, 50.02, 82.29}, +{'c', 68.42, 102.29, 34.02 ,85.49, 34.02, 85.49}, +{'c', -0.38, 72.69, -24.38 ,98.29, -27.58, 99.09}, +{'c', -30.78, 99.89, -35.58 ,103.09, -36.38, 96.69}, +{'c', -37.18, 90.29, -44.43 ,73.92, -76.38, 99.89}, +{'c', -98.86, 117.98, -112.04 ,97.07, -112.04, 97.07}, +{'l', -115.64, 105.69, 0, 0, 0, 0}, +{'c', -139.44, 66.69, -124.89 ,125.71, -124.89, 125.71}, +{'c', -116.09, 160.11, 14.82 ,119.89, 14.82, 119.89}, +{'c', 14.82, 119.89, 183.62 ,89.49, 194.82, 85.49}, +{'c', 206.02, 81.49, 299.47 ,87.75, 299.47, 87.75}, +{'l', 294.02, 69.93, 0, 0, 0, 0}, +{'c', 229.22, 23.53, 211.62 ,47.89, 198.02, 43.89}, +{'c', 184.42, 39.89, 186.82 ,49.49, 183.62, 50.29}, +{'f', 0.938000,0.536000,0.268000,1.000000,0,0 }, +{'m', 136.13, 28.84, 0, 0, 0, 0}, +{'c', 129.73, 29.64, 105.00 ,5.61, 119.33, 37.64}, +{'c', 136.13, 75.19, 60.39 ,76.48, 44.13, 65.64}, +{'c', 27.33, 54.44, 51.33 ,84.04, 51.33, 84.04}, +{'c', 69.73, 104.04, 35.33 ,87.24, 35.33, 87.24}, +{'c', 0.93, 74.44, -23.07 ,100.04, -26.27, 100.84}, +{'c', -29.47, 101.64, -34.27 ,104.84, -35.07, 98.44}, +{'c', -35.87, 92.04, -42.99 ,75.84, -75.07, 101.64}, +{'c', -98.78, 120.47, -111.66 ,100.11, -111.66, 100.11}, +{'l', -115.66, 107.24, 0, 0, 0, 0}, +{'c', -137.46, 70.44, -124.24 ,128.76, -124.24, 128.76}, +{'c', -115.44, 163.16, 16.13 ,121.64, 16.13, 121.64}, +{'c', 16.13, 121.64, 184.93 ,91.24, 196.13, 87.24}, +{'c', 207.33, 83.24, 299.91 ,89.42, 299.91, 89.42}, +{'l', 294.53, 71.09, 0, 0, 0, 0}, +{'c', 229.73, 24.69, 212.93 ,49.64, 199.33, 45.64}, +{'c', 185.73, 41.64, 188.13 ,51.24, 184.93, 52.04}, +{'f', 0.938000,0.603000,0.402000,1.000000,0,0 }, +{'m', 137.44, 30.58, 0, 0, 0, 0}, +{'c', 131.04, 31.38, 106.81 ,7.13, 120.64, 39.38}, +{'c', 137.44, 78.58, 62.24 ,78.58, 45.44, 67.38}, +{'c', 28.64, 56.18, 52.64 ,85.78, 52.64, 85.78}, +{'c', 71.04, 105.78, 36.64 ,88.98, 36.64, 88.98}, +{'c', 2.24, 76.18, -21.76 ,101.78, -24.96, 102.58}, +{'c', -28.16, 103.38, -32.96 ,106.58, -33.76, 100.18}, +{'c', -34.56, 93.78, -41.55 ,77.75, -73.76, 103.38}, +{'c', -98.71, 122.97, -111.27 ,103.15, -111.27, 103.15}, +{'l', -115.67, 108.78, 0, 0, 0, 0}, +{'c', -135.47, 73.98, -123.58 ,131.82, -123.58, 131.82}, +{'c', -114.78, 166.22, 17.44 ,123.38, 17.44, 123.38}, +{'c', 17.44, 123.38, 186.24 ,92.98, 197.44, 88.98}, +{'c', 208.64, 84.98, 300.35 ,91.09, 300.35, 91.09}, +{'l', 295.04, 72.25, 0, 0, 0, 0}, +{'c', 230.24, 25.86, 214.24 ,51.38, 200.64, 47.38}, +{'c', 187.04, 43.38, 189.44 ,52.98, 186.24, 53.78}, +{'f', 0.938000,0.670000,0.469000,1.000000,0,0 }, +{'m', 138.75, 32.33, 0, 0, 0, 0}, +{'c', 132.35, 33.13, 106.38 ,9.68, 121.95, 41.13}, +{'c', 141.15, 79.93, 63.55 ,80.33, 46.75, 69.13}, +{'c', 29.95, 57.93, 53.95 ,87.53, 53.95, 87.53}, +{'c', 72.35, 107.53, 37.95 ,90.73, 37.95, 90.73}, +{'c', 3.55, 77.93, -20.45 ,103.53, -23.65, 104.33}, +{'c', -26.85, 105.13, -31.65 ,108.33, -32.45, 101.93}, +{'c', -33.25, 95.53, -40.11 ,79.67, -72.45, 105.13}, +{'c', -98.64, 125.46, -110.89 ,106.18, -110.89, 106.18}, +{'l', -115.69, 110.33, 0, 0, 0, 0}, +{'c', -133.69, 77.13, -122.93 ,134.87, -122.93, 134.87}, +{'c', -114.13, 169.27, 18.75 ,125.13, 18.75, 125.13}, +{'c', 18.75, 125.13, 187.55 ,94.73, 198.75, 90.73}, +{'c', 209.95, 86.73, 300.78 ,92.76, 300.78, 92.76}, +{'l', 295.55, 73.42, 0, 0, 0, 0}, +{'c', 230.75, 27.02, 215.55 ,53.13, 201.95, 49.13}, +{'c', 188.35, 45.13, 190.75 ,54.73, 187.55, 55.53}, +{'f', 1.000000,0.737000,0.536000,1.000000,0,0 }, +{'m', 140.06, 34.07, 0, 0, 0, 0}, +{'c', 133.66, 34.87, 107.31 ,11.61, 123.25, 42.87}, +{'c', 143.66, 82.87, 64.86 ,82.07, 48.05, 70.87}, +{'c', 31.25, 59.67, 55.26 ,89.27, 55.26, 89.27}, +{'c', 73.66, 109.27, 39.26 ,92.47, 39.26, 92.47}, +{'c', 4.86, 79.67, -19.14 ,105.27, -22.34, 106.07}, +{'c', -25.55, 106.87, -30.34 ,110.07, -31.14, 103.67}, +{'c', -31.95, 97.27, -38.67 ,81.58, -71.14, 106.87}, +{'c', -98.56, 127.95, -110.51 ,109.22, -110.51, 109.22}, +{'l', -115.71, 111.87, 0, 0, 0, 0}, +{'c', -131.71, 81.67, -122.27 ,137.93, -122.27, 137.93}, +{'c', -113.47, 172.33, 20.05 ,126.87, 20.05, 126.87}, +{'c', 20.05, 126.87, 188.86 ,96.47, 200.06, 92.47}, +{'c', 211.26, 88.47, 301.22 ,94.44, 301.22, 94.44}, +{'l', 296.06, 74.58, 0, 0, 0, 0}, +{'c', 231.26, 28.18, 216.86 ,54.87, 203.26, 50.87}, +{'c', 189.66, 46.87, 192.06 ,56.47, 188.86, 57.27}, +{'f', 1.000000,0.737000,0.603000,1.000000,0,0 }, +{'m', 141.37, 35.82, 0, 0, 0, 0}, +{'c', 134.97, 36.62, 107.52 ,13.94, 124.56, 44.62}, +{'c', 146.56, 84.22, 66.16 ,83.82, 49.36, 72.62}, +{'c', 32.56, 61.42, 56.56 ,91.02, 56.56, 91.02}, +{'c', 74.96, 111.02, 40.56 ,94.22, 40.56, 94.22}, +{'c', 6.16, 81.42, -17.84 ,107.02, -21.04, 107.82}, +{'c', -24.24, 108.62, -29.04 ,111.82, -29.84, 105.42}, +{'c', -30.64, 99.02, -37.23 ,83.49, -69.84, 108.62}, +{'c', -98.49, 130.44, -110.13 ,112.26, -110.13, 112.26}, +{'l', -115.73, 113.42, 0, 0, 0, 0}, +{'c', -130.13, 85.02, -121.62 ,140.98, -121.62, 140.98}, +{'c', -112.82, 175.38, 21.36 ,128.62, 21.36, 128.62}, +{'c', 21.36, 128.62, 190.16 ,98.22, 201.37, 94.22}, +{'c', 212.56, 90.22, 301.66 ,96.11, 301.66, 96.11}, +{'l', 296.56, 75.75, 0, 0, 0, 0}, +{'c', 231.76, 29.35, 218.16 ,56.62, 204.56, 52.62}, +{'c', 190.97, 48.62, 193.37 ,58.22, 190.16, 59.02}, +{'f', 1.000000,0.804000,0.737000,1.000000,0,0 }, +{'m', 142.67, 37.56, 0, 0, 0, 0}, +{'c', 136.27, 38.37, 108.83 ,15.69, 125.87, 46.37}, +{'c', 147.87, 85.97, 67.47 ,85.56, 50.67, 74.36}, +{'c', 33.87, 63.16, 57.87 ,92.77, 57.87, 92.77}, +{'c', 76.27, 112.77, 41.87 ,95.97, 41.87, 95.97}, +{'c', 7.47, 83.17, -16.53 ,108.77, -19.73, 109.56}, +{'c', -22.93, 110.36, -27.73 ,113.56, -28.53, 107.17}, +{'c', -29.33, 100.77, -35.79 ,85.41, -68.53, 110.36}, +{'c', -98.42, 132.93, -109.75 ,115.29, -109.75, 115.29}, +{'l', -115.75, 114.97, 0, 0, 0, 0}, +{'c', -129.35, 88.56, -120.96 ,144.04, -120.96, 144.04}, +{'c', -112.16, 178.44, 22.67 ,130.37, 22.67, 130.37}, +{'c', 22.67, 130.37, 191.47 ,99.97, 202.67, 95.97}, +{'c', 213.87, 91.97, 302.09 ,97.78, 302.09, 97.78}, +{'l', 297.07, 76.91, 0, 0, 0, 0}, +{'c', 232.27, 30.51, 219.47 ,58.37, 205.87, 54.37}, +{'c', 192.27, 50.37, 194.67 ,59.97, 191.47, 60.77}, +{'f', 1.000000,0.871000,0.804000,1.000000,0,0 }, +{'m', 143.98, 39.31, 0, 0, 0, 0}, +{'c', 137.58, 40.11, 110.53 ,17.22, 127.18, 48.11}, +{'c', 149.18, 88.91, 68.78 ,87.31, 51.98, 76.11}, +{'c', 35.18, 64.91, 59.18 ,94.51, 59.18, 94.51}, +{'c', 77.58, 114.51, 43.18 ,97.71, 43.18, 97.71}, +{'c', 8.78, 84.91, -15.22 ,110.51, -18.42, 111.31}, +{'c', -21.62, 112.11, -26.42 ,115.31, -27.22, 108.91}, +{'c', -28.02, 102.51, -34.35 ,87.32, -67.22, 112.11}, +{'c', -98.34, 135.42, -109.36 ,118.33, -109.36, 118.33}, +{'l', -115.76, 116.51, 0, 0, 0, 0}, +{'c', -128.76, 92.51, -120.31 ,147.09, -120.31, 147.09}, +{'c', -111.51, 181.49, 23.98 ,132.11, 23.98, 132.11}, +{'c', 23.98, 132.11, 192.78 ,101.71, 203.98, 97.71}, +{'c', 215.18, 93.71, 302.53 ,99.46, 302.53, 99.46}, +{'l', 297.58, 78.07, 0, 0, 0, 0}, +{'c', 232.78, 31.67, 220.78 ,60.11, 207.18, 56.11}, +{'c', 193.58, 52.11, 195.98 ,61.71, 192.78, 62.51}, +{'f', 1.000000,0.938000,0.871000,1.000000,0,0 }, +{'m', 145.29, 41.05, 0, 0, 0, 0}, +{'c', 138.89, 41.85, 112.92 ,18.41, 128.49, 49.85}, +{'c', 149.69, 92.66, 70.09 ,89.06, 53.29, 77.86}, +{'c', 36.49, 66.66, 60.49 ,96.26, 60.49, 96.26}, +{'c', 78.89, 116.26, 44.49 ,99.46, 44.49, 99.46}, +{'c', 10.09, 86.66, -13.91 ,112.26, -17.11, 113.06}, +{'c', -20.31, 113.86, -25.11 ,117.06, -25.91, 110.66}, +{'c', -26.71, 104.26, -32.91 ,89.23, -65.91, 113.86}, +{'c', -98.27, 137.91, -108.98 ,121.36, -108.98, 121.36}, +{'l', -115.78, 118.06, 0, 0, 0, 0}, +{'c', -128.58, 94.86, -119.65 ,150.15, -119.65, 150.15}, +{'c', -110.85, 184.55, 25.29 ,133.86, 25.29, 133.86}, +{'c', 25.29, 133.86, 194.09 ,103.46, 205.29, 99.46}, +{'c', 216.49, 95.46, 302.96 ,101.13, 302.96, 101.13}, +{'l', 298.09, 79.24, 0, 0, 0, 0}, +{'c', 233.29, 32.84, 222.09 ,61.86, 208.49, 57.86}, +{'c', 194.89, 53.85, 197.29 ,63.46, 194.09, 64.26}, +{'f', 1.000000,1.000000,0.938000,1.000000,0,0 }, +{'m', -115.80, 119.60, 0, 0, 0, 0}, +{'c', -128.60, 97.60, -119.00 ,153.20, -119.00, 153.20}, +{'c', -110.20, 187.60, 26.60 ,135.60, 26.60, 135.60}, +{'c', 26.60, 135.60, 195.40 ,105.20, 206.60, 101.20}, +{'c', 217.80, 97.20, 303.40 ,102.80, 303.40, 102.80}, +{'l', 298.60, 80.40, 0, 0, 0, 0}, +{'c', 233.80, 34.00, 223.40 ,63.60, 209.80, 59.60}, +{'c', 196.20, 55.60, 198.60 ,65.20, 195.40, 66.00}, +{'c', 192.20, 66.80, 153.00 ,42.00, 146.60, 42.80}, +{'c', 140.20, 43.60, 114.98 ,19.79, 129.80, 51.60}, +{'c', 152.03, 99.31, 69.04 ,89.23, 54.60, 79.60}, +{'c', 37.80, 68.40, 61.80 ,98.00, 61.80, 98.00}, +{'c', 80.20, 118.00, 45.80 ,101.20, 45.80, 101.20}, +{'c', 11.40, 88.40, -12.60 ,114.00, -15.80, 114.80}, +{'c', -19.00, 115.60, -23.80 ,118.80, -24.60, 112.40}, +{'c', -25.40, 106.00, -31.46 ,91.14, -64.60, 115.60}, +{'c', -98.20, 140.40, -108.60 ,124.40, -108.60, 124.40}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', -74.20, 149.60, 0, 0, 0, 0}, +{'c', -74.20, 149.60, -81.40 ,161.20, -60.60, 174.40}, +{'c', -60.60, 174.40, -59.20 ,175.80, -77.20, 171.60}, +{'c', -77.20, 171.60, -83.40 ,169.60, -85.00, 159.20}, +{'c', -85.00, 159.20, -89.80 ,154.80, -94.60, 149.20}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', 65.80, 102.00, 0, 0, 0, 0}, +{'c', 65.80, 102.00, 83.50 ,128.82, 82.90, 133.60}, +{'c', 81.60, 144.00, 81.40 ,153.60, 84.60, 157.60}, +{'c', 87.80, 161.60, 96.60 ,194.80, 96.60, 194.80}, +{'c', 96.60, 194.80, 96.20 ,196.00, 108.60, 158.00}, +{'c', 108.60, 158.00, 120.20 ,142.00, 100.20, 123.60}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', -54.20, 176.40, 0, 0, 0, 0}, +{'c', -54.20, 176.40, -43.00 ,183.60, -57.40, 214.80}, +{'l', -51.00, 212.40, 0, 0, 0, 0}, +{'c', -51.00, 212.40, -51.80 ,223.60, -55.00, 226.00}, +{'l', -47.80, 222.80, 0, 0, 0, 0}, +{'c', -47.80, 222.80, -43.00 ,230.80, -47.00, 235.60}, +{'c', -47.00, 235.60, -30.20 ,243.60, -31.00, 250.00}, +{'c', -31.00, 250.00, -24.60 ,242.00, -28.60, 235.60}, +{'c', -32.60, 229.20, -39.80 ,233.20, -39.00, 214.80}, +{'l', -47.80, 218.00, 0, 0, 0, 0}, +{'c', -47.80, 218.00, -42.20 ,209.20, -42.20, 202.80}, +{'l', -50.20, 205.20, 0, 0, 0, 0}, +{'c', -50.20, 205.20, -34.73 ,178.62, -45.40, 177.20}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', -21.80, 193.20, 0, 0, 0, 0}, +{'c', -21.80, 193.20, -19.00 ,188.80, -21.80, 189.60}, +{'c', -24.60, 190.40, -55.80 ,205.20, -61.80, 214.80}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', -11.40, 201.20, 0, 0, 0, 0}, +{'c', -11.40, 201.20, -8.60 ,196.80, -11.40, 197.60}, +{'c', -14.20, 198.40, -45.40 ,213.20, -51.40, 222.80}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', 1.80, 186.00, 0, 0, 0, 0}, +{'c', 1.80, 186.00, 4.60 ,181.60, 1.80, 182.40}, +{'c', -1.00, 183.20, -32.20 ,198.00, -38.20, 207.60}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', -21.40, 229.60, 0, 0, 0, 0}, +{'c', -21.40, 229.60, -21.40 ,223.60, -24.20, 224.40}, +{'c', -27.00, 225.20, -63.00 ,242.80, -69.00, 252.40}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', -20.20, 218.80, 0, 0, 0, 0}, +{'c', -20.20, 218.80, -19.00 ,214.00, -21.80, 214.80}, +{'c', -23.80, 214.80, -50.20 ,226.40, -56.20, 236.00}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', -34.60, 266.40, 0, 0, 0, 0}, +{'l', -44.60, 274.00, 0, 0, 0, 0}, +{'c', -44.60, 274.00, -34.20 ,266.40, -30.60, 267.60}, +{'c', -30.60, 267.60, -37.40 ,278.80, -38.20, 284.00}, +{'c', -38.20, 284.00, -27.80 ,271.20, -22.20, 271.60}, +{'c', -22.20, 271.60, -14.60 ,272.00, -14.60, 282.80}, +{'c', -14.60, 282.80, -9.00 ,272.40, -5.80, 272.80}, +{'c', -5.80, 272.80, -4.60 ,279.20, -5.80, 286.00}, +{'c', -5.80, 286.00, -1.80 ,278.40, 2.20, 280.00}, +{'c', 2.20, 280.00, 8.60 ,278.00, 7.80, 289.60}, +{'c', 7.80, 289.60, 7.80 ,300.00, 7.00, 302.80}, +{'c', 7.00, 302.80, 12.60 ,276.40, 15.00, 276.00}, +{'c', 15.00, 276.00, 23.00 ,274.80, 27.80, 283.60}, +{'c', 27.80, 283.60, 23.80 ,276.00, 28.60, 278.00}, +{'c', 28.60, 278.00, 39.40 ,279.60, 42.60, 286.40}, +{'c', 42.60, 286.40, 35.80 ,274.40, 41.40, 277.60}, +{'c', 41.40, 277.60, 48.20 ,277.60, 49.40, 284.00}, +{'c', 49.40, 284.00, 57.80 ,305.20, 59.80, 306.80}, +{'c', 59.80, 306.80, 52.20 ,285.20, 53.80, 285.20}, +{'c', 53.80, 285.20, 51.80 ,273.20, 57.00, 288.00}, +{'c', 57.00, 288.00, 53.80 ,274.00, 59.40, 274.80}, +{'c', 65.00, 275.60, 69.40 ,285.60, 77.80, 283.20}, +{'c', 77.80, 283.20, 87.40 ,288.80, 89.40, 219.60}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', -29.80, 173.60, 0, 0, 0, 0}, +{'c', -29.80, 173.60, -15.00 ,167.60, 25.00, 173.60}, +{'c', 25.00, 173.60, 32.20 ,174.00, 39.00, 165.20}, +{'c', 45.80, 156.40, 72.60 ,149.20, 79.00, 151.20}, +{'l', 88.60, 157.60, 0, 0, 0, 0}, +{'l', 89.40, 158.80, 0, 0, 0, 0}, +{'c', 89.40, 158.80, 101.80 ,169.20, 102.20, 176.80}, +{'c', 102.60, 184.40, 87.80 ,232.40, 78.20, 248.40}, +{'c', 68.60, 264.40, 59.00 ,276.80, 39.80, 274.40}, +{'c', 39.80, 274.40, 19.00 ,270.40, -6.60, 274.40}, +{'c', -6.60, 274.40, -35.80 ,272.80, -38.60, 264.80}, +{'c', -41.40, 256.80, -27.40 ,241.60, -27.40, 241.60}, +{'c', -27.40, 241.60, -23.00 ,233.20, -24.20, 218.80}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', -7.80, 175.60, 0, 0, 0, 0}, +{'c', 0.60, 194.00, -29.00 ,259.20, -29.00, 259.20}, +{'c', -31.00, 260.80, -16.34 ,266.85, -6.20, 264.40}, +{'c', 4.75, 261.76, 45.00 ,266.00, 45.00, 266.00}, +{'c', 68.60, 250.40, 81.40 ,206.00, 81.40, 206.00}, +{'c', 81.40, 206.00, 91.80 ,182.00, 74.20, 178.80}, +{'f', 0.938000,0.402000,0.536000,1.000000,0,0 }, +{'m', -9.83, 206.50, 0, 0, 0, 0}, +{'c', -6.50, 193.71, -4.92 ,181.91, -7.80, 175.60}, +{'c', -7.80, 175.60, 54.60 ,182.00, 65.80, 161.20}, +{'c', 70.04, 153.33, 84.80 ,184.00, 84.40, 193.60}, +{'c', 84.40, 193.60, 21.40 ,208.00, 6.60, 196.80}, +{'f', 0.737000,0.201000,0.335000,1.000000,0,0 }, +{'m', -5.40, 222.80, 0, 0, 0, 0}, +{'c', -5.40, 222.80, -3.40 ,230.00, -5.80, 234.00}, +{'c', -5.80, 234.00, -7.40 ,234.80, -8.60, 235.20}, +{'c', -8.60, 235.20, -7.40 ,238.80, -1.40, 240.40}, +{'c', -1.40, 240.40, 0.60 ,244.80, 3.00, 245.20}, +{'c', 5.40, 245.60, 10.20 ,251.20, 14.20, 250.00}, +{'c', 18.20, 248.80, 29.40 ,244.80, 29.40, 244.80}, +{'c', 29.40, 244.80, 35.00 ,241.60, 43.80, 245.20}, +{'c', 43.80, 245.20, 46.17 ,244.40, 46.60, 240.40}, +{'c', 47.10, 235.70, 50.20 ,232.00, 52.20, 230.00}, +{'c', 54.20, 228.00, 63.80 ,215.20, 62.60, 214.80}, +{'f', 0.670000,0.134000,0.268000,1.000000,0,0 }, +{'m', -9.80, 174.40, 0, 0, 0, 0}, +{'c', -9.80, 174.40, -12.60 ,196.80, -9.40, 205.20}, +{'c', -6.20, 213.60, -7.00 ,215.60, -7.80, 219.60}, +{'c', -8.60, 223.60, -4.20 ,233.60, 1.40, 239.60}, +{'l', 13.40, 241.20, 0, 0, 0, 0}, +{'c', 13.40, 241.20, 28.60 ,237.60, 37.80, 240.40}, +{'c', 37.80, 240.40, 46.79 ,241.74, 50.20, 226.80}, +{'c', 50.20, 226.80, 55.00 ,220.40, 62.20, 217.60}, +{'c', 69.40, 214.80, 76.60 ,173.20, 72.60, 165.20}, +{'c', 68.60, 157.20, 54.20 ,152.80, 38.20, 168.40}, +{'f', 1.000000,0.469000,0.469000,1.000000,0,0 }, +{'m', -8.20, 249.20, 0, 0, 0, 0}, +{'c', -8.20, 249.20, -9.00 ,247.20, -13.40, 246.80}, +{'c', -13.40, 246.80, -35.80 ,243.20, -44.20, 230.80}, +{'c', -44.20, 230.80, -51.00 ,225.20, -46.60, 236.80}, +{'c', -46.60, 236.80, -36.20 ,257.20, -29.40, 260.00}, +{'f', 1.000000,1.000000,0.804000,1.000000,0,0 }, +{'m', 71.74, 185.23, 0, 0, 0, 0}, +{'c', 72.40, 177.32, 74.35 ,168.71, 72.60, 165.20}, +{'c', 66.15, 152.31, 49.18 ,157.69, 38.20, 168.40}, +{'c', 22.20, 184.00, 20.20 ,167.20, -9.80, 174.40}, +{'c', -9.80, 174.40, -11.54 ,188.36, -10.71, 198.38}, +{'c', -10.71, 198.38, 26.60 ,186.80, 27.40, 192.40}, +{'c', 27.40, 192.40, 29.00 ,189.20, 38.20, 189.20}, +{'f', 0.804000,0.201000,0.268000,1.000000,0,0 }, +{'m', 28.60, 175.20, 0, 0, 0, 0}, +{'c', 28.60, 175.20, 33.40 ,180.00, 29.80, 189.60}, +{'f', 0.804000,0.201000,0.268000,1.000000,0,0 }, +{'m', -19.40, 260.00, 0, 0, 0, 0}, +{'c', -19.40, 260.00, -23.80 ,247.20, -15.00, 254.00}, +{'c', -15.00, 254.00, -10.20 ,256.00, -11.40, 257.60}, +{'f', 1.000000,1.000000,0.804000,1.000000,0,0 }, +{'m', -14.36, 261.20, 0, 0, 0, 0}, +{'c', -14.36, 261.20, -17.88 ,250.96, -10.84, 256.40}, +{'c', -10.84, 256.40, -6.42 ,258.85, -7.96, 259.28}, +{'f', 1.000000,1.000000,0.804000,1.000000,0,0 }, +{'m', -9.56, 261.20, 0, 0, 0, 0}, +{'c', -9.56, 261.20, -13.08 ,250.96, -6.04, 256.40}, +{'c', -6.04, 256.40, -1.67 ,258.71, -3.16, 259.28}, +{'f', 1.000000,1.000000,0.804000,1.000000,0,0 }, +{'m', -2.96, 261.40, 0, 0, 0, 0}, +{'c', -2.96, 261.40, -6.48 ,251.16, 0.56, 256.60}, +{'c', 0.56, 256.60, 4.94 ,258.93, 3.44, 259.48}, +{'f', 1.000000,1.000000,0.804000,1.000000,0,0 }, +{'m', 3.52, 261.32, 0, 0, 0, 0}, +{'c', 3.52, 261.32, 0.00 ,251.08, 7.04, 256.52}, +{'c', 7.04, 256.52, 10.88 ,258.12, 9.92, 259.40}, +{'f', 1.000000,1.000000,0.804000,1.000000,0,0 }, +{'m', 10.20, 262.00, 0, 0, 0, 0}, +{'c', 10.20, 262.00, 5.40 ,249.60, 14.60, 256.00}, +{'c', 14.60, 256.00, 19.40 ,258.00, 18.20, 259.60}, +{'f', 1.000000,1.000000,0.804000,1.000000,0,0 }, +{'m', -18.20, 244.80, 0, 0, 0, 0}, +{'c', -18.20, 244.80, -5.00 ,242.00, 1.00, 245.20}, +{'c', 1.00, 245.20, 7.00 ,246.40, 8.20, 246.00}, +{'f', 1.000000,1.000000,0.804000,1.000000,0,0 }, +{'m', 15.80, 253.60, 0, 0, 0, 0}, +{'c', 15.80, 253.60, 27.80 ,240.00, 39.80, 244.40}, +{'c', 46.82, 246.97, 45.80 ,243.60, 46.60, 240.80}, +{'f', 1.000000,1.000000,0.804000,1.000000,0,0 }, +{'m', 33.00, 237.60, 0, 0, 0, 0}, +{'c', 33.00, 237.60, 29.00 ,226.80, 26.20, 239.60}, +{'c', 23.40, 252.40, 20.20 ,256.00, 18.60, 258.80}, +{'c', 18.60, 258.80, 18.60 ,264.00, 27.00, 263.60}, +{'c', 27.00, 263.60, 37.80 ,263.20, 38.20, 260.40}, +{'f', 1.000000,1.000000,0.804000,1.000000,0,0 }, +{'m', 47.00, 244.80, 0, 0, 0, 0}, +{'f', 1.000000,1.000000,0.804000,1.000000,0,0 }, +{'m', 53.50, 228.40, 0, 0, 0, 0}, +{'f', 1.000000,1.000000,0.804000,1.000000,0,0 }, +{'m', -25.80, 265.20, 0, 0, 0, 0}, +{'c', -25.80, 265.20, -7.80 ,268.40, -3.40, 266.80}, +{'c', -3.40, 266.80, 5.40 ,266.80, -3.00, 268.80}, +{'c', -3.00, 268.80, -15.80 ,268.80, -23.80, 267.60}, +{'f', 0.737000,0.737000,0.737000,1.000000,0,0 }, +{'m', -11.80, 172.00, 0, 0, 0, 0}, +{'c', -11.80, 172.00, 5.80 ,172.00, 7.80, 172.80}, +{'c', 7.80, 172.80, 15.00 ,203.60, 11.40, 211.20}, +{'c', 11.40, 211.20, 10.20 ,214.00, 7.40, 208.40}, +{'c', 7.40, 208.40, -11.00 ,175.60, -14.20, 173.60}, +{'f', 1.000000,1.000000,0.804000,1.000000,0,0 }, +{'m', -88.90, 169.30, 0, 0, 0, 0}, +{'c', -88.90, 169.30, -80.00 ,171.00, -67.40, 173.60}, +{'c', -67.40, 173.60, -62.60 ,196.00, -59.40, 200.80}, +{'c', -56.20, 205.60, -59.80 ,205.60, -63.40, 202.80}, +{'c', -67.00, 200.00, -81.80 ,186.00, -83.80, 181.60}, +{'f', 1.000000,1.000000,0.804000,1.000000,0,0 }, +{'m', -67.04, 173.82, 0, 0, 0, 0}, +{'c', -67.04, 173.82, -61.24 ,175.37, -60.23, 177.58}, +{'c', -59.22, 179.79, -61.43 ,183.09, -61.43, 183.09}, +{'c', -61.43, 183.09, -62.43 ,186.40, -63.63, 184.24}, +{'f', 1.000000,1.000000,0.804000,1.000000,0,0 }, +{'m', -67.00, 173.60, 0, 0, 0, 0}, +{'c', -67.00, 173.60, -63.40 ,178.80, -59.80, 178.80}, +{'c', -56.20, 178.80, -55.82 ,178.39, -53.00, 179.00}, +{'c', -48.40, 180.00, -48.80 ,178.00, -42.20, 179.20}, +{'c', -39.56, 179.68, -37.00 ,178.80, -34.20, 180.00}, +{'c', -31.40, 181.20, -28.20 ,180.40, -27.00, 178.40}, +{'c', -25.80, 176.40, -21.00 ,172.20, -21.00, 172.20}, +{'c', -21.00, 172.20, -33.80 ,174.00, -36.60, 174.80}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', -22.40, 173.80, 0, 0, 0, 0}, +{'c', -22.40, 173.80, -28.85 ,177.30, -29.25, 179.70}, +{'c', -29.65, 182.10, -24.00 ,185.80, -24.00, 185.80}, +{'c', -24.00, 185.80, -21.25 ,190.40, -20.65, 188.00}, +{'f', 1.000000,1.000000,0.804000,1.000000,0,0 }, +{'m', -59.88, 179.26, 0, 0, 0, 0}, +{'c', -59.88, 179.26, -52.88 ,190.45, -52.66, 179.24}, +{'c', -52.66, 179.24, -52.10 ,177.98, -53.86, 177.96}, +{'f', 1.000000,1.000000,0.804000,1.000000,0,0 }, +{'m', -52.71, 179.51, 0, 0, 0, 0}, +{'c', -52.71, 179.51, -44.79 ,190.70, -45.42, 179.42}, +{'c', -45.42, 179.42, -45.41 ,179.09, -47.17, 178.94}, +{'f', 1.000000,1.000000,0.804000,1.000000,0,0 }, +{'m', -45.49, 179.52, 0, 0, 0, 0}, +{'c', -45.49, 179.52, -37.53 ,190.15, -38.20, 180.48}, +{'c', -38.20, 180.48, -38.08 ,179.25, -39.74, 178.95}, +{'f', 1.000000,1.000000,0.804000,1.000000,0,0 }, +{'m', -38.62, 179.60, 0, 0, 0, 0}, +{'c', -38.62, 179.60, -30.72 ,191.16, -30.37, 181.38}, +{'c', -30.37, 181.38, -28.73 ,180.00, -30.47, 179.78}, +{'f', 1.000000,1.000000,0.804000,1.000000,0,0 }, +{'m', -74.79, 183.13, 0, 0, 0, 0}, +{'l', -82.45, 181.60, 0, 0, 0, 0}, +{'c', -85.05, 176.60, -87.15 ,170.45, -87.15, 170.45}, +{'c', -87.15, 170.45, -80.80 ,171.45, -68.30, 174.25}, +{'c', -68.30, 174.25, -67.42 ,177.57, -65.95, 183.36}, +{'f', 0.938000,0.938000,0.737000,1.000000,0,0 }, +{'m', -9.72, 178.47, 0, 0, 0, 0}, +{'c', -11.39, 175.96, -12.71 ,174.21, -13.36, 173.80}, +{'c', -16.37, 171.92, -12.23 ,172.29, -11.10, 172.29}, +{'c', -11.10, 172.29, 5.47 ,172.29, 7.36, 173.05}, +{'c', 7.36, 173.05, 7.88 ,175.29, 8.56, 178.68}, +{'f', 0.938000,0.938000,0.737000,1.000000,0,0 }, +{'m', 43.88, 40.32, 0, 0, 0, 0}, +{'c', 71.60, 44.28, 97.12 ,8.64, 98.88, -1.04}, +{'c', 100.64, -10.72, 90.52 ,-22.60, 90.52, -22.60}, +{'c', 91.84, -25.68, 87.00 ,-39.76, 81.72, -49.00}, +{'c', 76.44, -58.24, 60.54 ,-57.27, 43.00, -58.24}, +{'c', 27.16, -59.12, 8.68 ,-35.80, 7.36, -34.04}, +{'c', 6.04, -32.28, 12.20 ,6.00, 13.52, 11.72}, +{'c', 14.84, 17.44, 12.20 ,43.84, 12.20, 43.84}, +{'f', 0.804000,0.469000,0.134000,1.000000,0,0 }, +{'m', 8.09, -33.39, 0, 0, 0, 0}, +{'c', 6.79, -31.66, 12.84 ,5.92, 14.14, 11.54}, +{'c', 15.43, 17.15, 12.84 ,43.07, 12.84, 43.07}, +{'c', 45.51, 34.19, 16.73 ,35.73, 43.94, 39.62}, +{'c', 71.16, 43.51, 96.22 ,8.51, 97.94, -0.99}, +{'c', 99.67, -10.50, 89.74 ,-22.16, 89.74, -22.16}, +{'c', 91.03, -25.18, 86.28 ,-39.01, 81.10, -48.08}, +{'c', 75.91, -57.15, 60.30 ,-56.20, 43.08, -57.15}, +{'f', 0.938000,0.536000,0.335000,1.000000,0,0 }, +{'m', 8.82, -32.74, 0, 0, 0, 0}, +{'c', 7.54, -31.05, 13.48 ,5.84, 14.75, 11.35}, +{'c', 16.02, 16.86, 13.48 ,42.30, 13.48, 42.30}, +{'c', 44.88, 33.15, 17.30 ,35.10, 44.01, 38.91}, +{'c', 70.72, 42.73, 95.31 ,8.38, 97.01, -0.94}, +{'c', 98.70, -10.27, 88.95 ,-21.72, 88.95, -21.72}, +{'c', 90.22, -24.69, 85.56 ,-38.26, 80.47, -47.16}, +{'c', 75.39, -56.06, 60.06 ,-55.12, 43.16, -56.06}, +{'f', 0.938000,0.670000,0.469000,1.000000,0,0 }, +{'m', 9.54, -32.10, 0, 0, 0, 0}, +{'c', 8.30, -30.43, 14.12 ,5.76, 15.37, 11.17}, +{'c', 16.62, 16.58, 14.12 ,41.54, 14.12, 41.54}, +{'c', 43.56, 32.50, 17.86 ,34.47, 44.07, 38.21}, +{'c', 70.28, 41.95, 94.41 ,8.26, 96.07, -0.90}, +{'c', 97.74, -10.05, 88.17 ,-21.28, 88.17, -21.28}, +{'c', 89.42, -24.19, 84.84 ,-37.50, 79.85, -46.24}, +{'c', 74.86, -54.98, 59.82 ,-54.05, 43.24, -54.98}, +{'f', 1.000000,0.804000,0.670000,1.000000,0,0 }, +{'m', 10.27, -31.45, 0, 0, 0, 0}, +{'c', 9.05, -29.82, 14.76 ,5.68, 15.98, 10.98}, +{'c', 17.21, 16.29, 14.76 ,40.77, 14.76, 40.77}, +{'c', 42.63, 31.85, 18.43 ,33.83, 44.14, 37.51}, +{'c', 69.84, 41.18, 93.50 ,8.13, 95.14, -0.85}, +{'c', 96.77, -9.82, 87.39 ,-20.84, 87.39, -20.84}, +{'c', 88.61, -23.70, 84.12 ,-36.75, 79.22, -45.32}, +{'c', 74.33, -53.89, 59.59 ,-52.98, 43.32, -53.89}, +{'f', 1.000000,0.938000,0.871000,1.000000,0,0 }, +{'m', 44.20, 36.80, 0, 0, 0, 0}, +{'c', 69.40, 40.40, 92.60 ,8.00, 94.20, -0.80}, +{'c', 95.80, -9.60, 86.60 ,-20.40, 86.60, -20.40}, +{'c', 87.80, -23.20, 83.40 ,-36.00, 78.60, -44.40}, +{'c', 73.80, -52.80, 59.35 ,-51.91, 43.40, -52.80}, +{'c', 29.00, -53.60, 12.20 ,-32.40, 11.00, -30.80}, +{'c', 9.80, -29.20, 15.40 ,5.60, 16.60, 10.80}, +{'c', 17.80, 16.00, 15.40 ,40.00, 15.40, 40.00}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', 90.60, 2.80, 0, 0, 0, 0}, +{'c', 90.60, 2.80, 62.80 ,10.40, 51.20, 8.80}, +{'c', 51.20, 8.80, 35.40 ,2.20, 26.60, 24.00}, +{'c', 26.60, 24.00, 23.00 ,31.20, 21.00, 33.20}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', 94.40, 0.60, 0, 0, 0, 0}, +{'c', 94.40, 0.60, 65.40 ,12.80, 55.40, 12.40}, +{'c', 55.40, 12.40, 39.00 ,7.80, 30.60, 22.40}, +{'c', 30.60, 22.40, 22.20 ,31.60, 19.00, 33.20}, +{'c', 19.00, 33.20, 18.60 ,34.80, 25.00, 30.80}, +{'l', 35.40, 36.00, 0, 0, 0, 0}, +{'c', 35.40, 36.00, 50.20 ,45.60, 59.80, 29.60}, +{'c', 59.80, 29.60, 63.80 ,18.40, 63.80, 16.40}, +{'c', 63.80, 14.40, 85.00 ,8.80, 86.60, 8.40}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', 47.00, 36.51, 0, 0, 0, 0}, +{'c', 40.13, 36.51, 31.75 ,32.65, 31.75, 26.40}, +{'c', 31.75, 20.15, 40.13 ,13.89, 47.00, 13.89}, +{'c', 53.87, 13.89, 59.45 ,18.95, 59.45, 25.20}, +{'f', 0.603000,0.804000,0.201000,1.000000,0,0 }, +{'m', 43.38, 19.83, 0, 0, 0, 0}, +{'c', 38.53, 20.55, 33.44 ,22.05, 33.51, 21.84}, +{'c', 35.05, 17.22, 41.41 ,13.89, 47.00, 13.89}, +{'c', 51.30, 13.89, 55.08 ,15.87, 57.32, 18.88}, +{'f', 0.402000,0.603000,0.000000,1.000000,0,0 }, +{'m', 55.40, 19.60, 0, 0, 0, 0}, +{'c', 55.40, 19.60, 51.00 ,16.40, 51.00, 18.60}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', 45.40, 27.73, 0, 0, 0, 0}, +{'c', 42.90, 27.73, 40.88 ,25.70, 40.88, 23.20}, +{'c', 40.88, 20.70, 42.90 ,18.68, 45.40, 18.68}, +{'c', 47.90, 18.68, 49.93 ,20.70, 49.93, 23.20}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', -58.60, 14.40, 0, 0, 0, 0}, +{'c', -58.60, 14.40, -61.80 ,-6.80, -59.40, -11.20}, +{'c', -59.40, -11.20, -48.60 ,-21.20, -49.00, -24.80}, +{'c', -49.00, -24.80, -49.40 ,-42.80, -50.60, -43.60}, +{'c', -51.80, -44.40, -59.40 ,-50.40, -65.40, -44.00}, +{'c', -65.40, -44.00, -75.80 ,-26.00, -75.00, -19.60}, +{'l', -75.00, -17.60, 0, 0, 0, 0}, +{'c', -75.00, -17.60, -82.60 ,-18.00, -84.20, -16.00}, +{'c', -84.20, -16.00, -85.40 ,-10.80, -86.60, -10.40}, +{'c', -86.60, -10.40, -89.40 ,-8.00, -87.40, -5.20}, +{'c', -87.40, -5.20, -89.40 ,-2.80, -89.00, 1.20}, +{'l', -81.40, 5.20, 0, 0, 0, 0}, +{'c', -81.40, 5.20, -79.40 ,19.60, -68.60, 24.80}, +{'f', 0.804000,0.469000,0.134000,1.000000,0,0 }, +{'m', -59.60, 12.56, 0, 0, 0, 0}, +{'c', -59.60, 12.56, -62.48 ,-6.52, -60.32, -10.48}, +{'c', -60.32, -10.48, -50.60 ,-19.48, -50.96, -22.72}, +{'c', -50.96, -22.72, -51.32 ,-38.92, -52.40, -39.64}, +{'c', -53.48, -40.36, -60.32 ,-45.76, -65.72, -40.00}, +{'c', -65.72, -40.00, -75.08 ,-23.80, -74.36, -18.04}, +{'l', -74.36, -16.24, 0, 0, 0, 0}, +{'c', -74.36, -16.24, -81.20 ,-16.60, -82.64, -14.80}, +{'c', -82.64, -14.80, -83.72 ,-10.12, -84.80, -9.76}, +{'c', -84.80, -9.76, -87.32 ,-7.60, -85.52, -5.08}, +{'c', -85.52, -5.08, -87.32 ,-2.92, -86.96, 0.68}, +{'l', -80.12, 4.28, 0, 0, 0, 0}, +{'c', -80.12, 4.28, -78.32 ,17.24, -68.60, 21.92}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', -51.05, -42.61, 0, 0, 0, 0}, +{'c', -52.14, -43.47, -59.63 ,-49.24, -65.48, -43.00}, +{'c', -65.48, -43.00, -75.62 ,-25.45, -74.84, -19.21}, +{'l', -74.84, -17.26, 0, 0, 0, 0}, +{'c', -74.84, -17.26, -82.25 ,-17.65, -83.81, -15.70}, +{'c', -83.81, -15.70, -84.98 ,-10.63, -86.15, -10.24}, +{'c', -86.15, -10.24, -88.88 ,-7.90, -86.93, -5.17}, +{'c', -86.93, -5.17, -88.88 ,-2.83, -88.49, 1.07}, +{'l', -81.08, 4.97, 0, 0, 0, 0}, +{'c', -81.08, 4.97, -79.13 ,19.01, -68.60, 24.08}, +{'c', -63.89, 26.35, -60.80 ,19.79, -58.85, 13.94}, +{'c', -58.85, 13.94, -61.97 ,-6.73, -59.63, -11.02}, +{'c', -59.63, -11.02, -49.10 ,-20.77, -49.49, -24.28}, +{'f', 0.938000,0.603000,0.335000,1.000000,0,0 }, +{'m', -51.50, -41.62, 0, 0, 0, 0}, +{'c', -52.48, -42.54, -59.86 ,-48.08, -65.56, -42.00}, +{'c', -65.56, -42.00, -75.44 ,-24.90, -74.68, -18.82}, +{'l', -74.68, -16.92, 0, 0, 0, 0}, +{'c', -74.68, -16.92, -81.90 ,-17.30, -83.42, -15.40}, +{'c', -83.42, -15.40, -84.56 ,-10.46, -85.70, -10.08}, +{'c', -85.70, -10.08, -88.36 ,-7.80, -86.46, -5.14}, +{'c', -86.46, -5.14, -88.36 ,-2.86, -87.98, 0.94}, +{'l', -80.76, 4.74, 0, 0, 0, 0}, +{'c', -80.76, 4.74, -78.86 ,18.42, -68.60, 23.36}, +{'c', -64.01, 25.57, -61.00 ,19.18, -59.10, 13.48}, +{'c', -59.10, 13.48, -62.14 ,-6.66, -59.86, -10.84}, +{'c', -59.86, -10.84, -49.60 ,-20.34, -49.98, -23.76}, +{'f', 1.000000,0.737000,0.603000,1.000000,0,0 }, +{'m', -51.95, -40.63, 0, 0, 0, 0}, +{'c', -52.82, -41.61, -60.09 ,-46.92, -65.64, -41.00}, +{'c', -65.64, -41.00, -75.26 ,-24.35, -74.52, -18.43}, +{'l', -74.52, -16.58, 0, 0, 0, 0}, +{'c', -74.52, -16.58, -81.55 ,-16.95, -83.03, -15.10}, +{'c', -83.03, -15.10, -84.14 ,-10.29, -85.25, -9.92}, +{'c', -85.25, -9.92, -87.84 ,-7.70, -85.99, -5.11}, +{'c', -85.99, -5.11, -87.84 ,-2.89, -87.47, 0.81}, +{'l', -80.44, 4.51, 0, 0, 0, 0}, +{'c', -80.44, 4.51, -78.59 ,17.83, -68.60, 22.64}, +{'c', -64.13, 24.79, -61.20 ,18.57, -59.35, 13.02}, +{'c', -59.35, 13.02, -62.31 ,-6.59, -60.09, -10.66}, +{'c', -60.09, -10.66, -50.10 ,-19.91, -50.47, -23.24}, +{'f', 1.000000,0.871000,0.804000,1.000000,0,0 }, +{'m', -59.60, 12.46, 0, 0, 0, 0}, +{'c', -59.60, 12.46, -62.48 ,-6.52, -60.32, -10.48}, +{'c', -60.32, -10.48, -50.60 ,-19.48, -50.96, -22.72}, +{'c', -50.96, -22.72, -51.32 ,-38.92, -52.40, -39.64}, +{'c', -53.16, -40.68, -60.32 ,-45.76, -65.72, -40.00}, +{'c', -65.72, -40.00, -75.08 ,-23.80, -74.36, -18.04}, +{'l', -74.36, -16.24, 0, 0, 0, 0}, +{'c', -74.36, -16.24, -81.20 ,-16.60, -82.64, -14.80}, +{'c', -82.64, -14.80, -83.72 ,-10.12, -84.80, -9.76}, +{'c', -84.80, -9.76, -87.32 ,-7.60, -85.52, -5.08}, +{'c', -85.52, -5.08, -87.32 ,-2.92, -86.96, 0.68}, +{'l', -80.12, 4.28, 0, 0, 0, 0}, +{'c', -80.12, 4.28, -78.32 ,17.24, -68.60, 21.92}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', -62.70, 6.20, 0, 0, 0, 0}, +{'c', -62.70, 6.20, -84.30 ,-4.00, -85.20, -4.80}, +{'c', -85.20, -4.80, -76.10 ,3.40, -75.30, 3.40}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', -79.80, 0.00, 0, 0, 0, 0}, +{'c', -79.80, 0.00, -61.40 ,3.60, -61.40, 8.00}, +{'c', -61.40, 10.91, -61.64 ,24.33, -67.00, 22.80}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', -71.40, 3.80, 0, 0, 0, 0}, +{'c', -71.40, 3.80, -62.42 ,5.27, -61.40, 8.00}, +{'c', -60.80, 9.60, -60.14 ,17.91, -65.60, 19.00}, +{'f', 0.603000,0.804000,0.201000,1.000000,0,0 }, +{'m', 14.60, 46.35, 0, 0, 0, 0}, +{'c', 14.10, 44.61, 15.41 ,44.74, 17.20, 44.20}, +{'c', 19.20, 43.60, 31.40 ,39.80, 32.20, 37.20}, +{'c', 33.00, 34.60, 46.20 ,39.00, 46.20, 39.00}, +{'c', 48.00, 39.80, 52.40 ,42.40, 52.40, 42.40}, +{'c', 57.20, 43.60, 63.80 ,44.00, 63.80, 44.00}, +{'c', 66.20, 45.00, 69.60 ,47.80, 69.60, 47.80}, +{'c', 84.20, 58.00, 96.60 ,50.80, 96.60, 50.80}, +{'c', 116.60, 44.20, 110.60 ,27.00, 110.60, 27.00}, +{'c', 107.60, 18.00, 110.80 ,14.60, 110.80, 14.60}, +{'c', 111.00, 10.80, 118.20 ,17.20, 118.20, 17.20}, +{'c', 120.80, 21.40, 121.60 ,26.40, 121.60, 26.40}, +{'c', 129.60, 37.60, 126.20 ,19.80, 126.20, 19.80}, +{'c', 126.40, 18.80, 123.60 ,15.20, 123.60, 14.00}, +{'c', 123.60, 12.80, 121.80 ,9.40, 121.80, 9.40}, +{'c', 118.80, 6.00, 121.20 ,-1.00, 121.20, -1.00}, +{'c', 123.00, -14.80, 120.80 ,-13.00, 120.80, -13.00}, +{'c', 119.60, -14.80, 110.40 ,-4.80, 110.40, -4.80}, +{'c', 108.20, -1.40, 102.20 ,0.20, 102.20, 0.20}, +{'c', 99.40, 2.00, 96.00 ,0.60, 96.00, 0.60}, +{'c', 93.40, 0.20, 87.80 ,7.20, 87.80, 7.20}, +{'c', 90.60, 7.00, 93.00 ,11.40, 95.40, 11.60}, +{'c', 97.80, 11.80, 99.60 ,9.20, 101.20, 8.60}, +{'c', 102.80, 8.00, 105.60 ,13.80, 105.60, 13.80}, +{'c', 106.00, 16.40, 100.40 ,21.20, 100.40, 21.20}, +{'c', 100.00, 25.80, 98.40 ,24.20, 98.40, 24.20}, +{'c', 95.40, 23.60, 94.20 ,27.40, 93.20, 32.00}, +{'c', 92.20, 36.60, 88.00 ,37.00, 88.00, 37.00}, +{'c', 86.40, 44.40, 85.20 ,41.40, 85.20, 41.40}, +{'c', 85.00, 35.80, 79.00 ,41.60, 79.00, 41.60}, +{'c', 77.80, 43.60, 73.20 ,41.40, 73.20, 41.40}, +{'c', 66.40, 39.40, 68.80 ,37.40, 68.80, 37.40}, +{'c', 70.60, 35.20, 81.80 ,37.40, 81.80, 37.40}, +{'c', 84.00, 35.80, 76.00 ,31.80, 76.00, 31.80}, +{'c', 75.40, 30.00, 76.40 ,25.60, 76.40, 25.60}, +{'c', 77.60, 22.40, 84.40 ,16.80, 84.40, 16.80}, +{'c', 93.80, 15.60, 91.00 ,14.00, 91.00, 14.00}, +{'c', 84.80, 8.80, 79.00 ,16.40, 79.00, 16.40}, +{'c', 76.80, 22.60, 59.40 ,37.60, 59.40, 37.60}, +{'c', 54.60, 41.00, 57.20 ,34.20, 53.20, 37.60}, +{'c', 49.20, 41.00, 28.60 ,32.00, 28.60, 32.00}, +{'c', 17.04, 30.81, 14.31 ,46.55, 10.78, 43.43}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', 209.40, -120.00, 0, 0, 0, 0}, +{'c', 209.40, -120.00, 183.80 ,-112.00, 181.00, -93.20}, +{'c', 181.00, -93.20, 178.60 ,-70.40, 199.00, -52.80}, +{'c', 199.00, -52.80, 199.40 ,-46.40, 201.40, -43.20}, +{'c', 201.40, -43.20, 199.80 ,-38.40, 218.60, -46.00}, +{'l', 245.80, -54.40, 0, 0, 0, 0}, +{'c', 245.80, -54.40, 252.20 ,-56.80, 257.40, -65.60}, +{'c', 262.60, -74.40, 277.80 ,-93.20, 274.20, -118.40}, +{'c', 274.20, -118.40, 275.40 ,-129.60, 269.40, -130.00}, +{'c', 269.40, -130.00, 261.00 ,-131.60, 253.80, -124.00}, +{'c', 253.80, -124.00, 247.00 ,-120.80, 244.60, -121.20}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', 264.02, -120.99, 0, 0, 0, 0}, +{'c', 264.02, -120.99, 266.12 ,-129.92, 261.28, -125.08}, +{'c', 261.28, -125.08, 254.24 ,-119.36, 246.76, -119.36}, +{'c', 246.76, -119.36, 232.24 ,-117.16, 227.84, -103.96}, +{'c', 227.84, -103.96, 223.88 ,-77.12, 231.80, -71.40}, +{'c', 231.80, -71.40, 236.64 ,-63.92, 243.68, -70.52}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', 263.65, -120.63, 0, 0, 0, 0}, +{'c', 263.65, -120.63, 265.74 ,-129.38, 260.99, -124.62}, +{'c', 260.99, -124.62, 254.07 ,-119.01, 246.73, -119.01}, +{'c', 246.73, -119.01, 232.47 ,-116.85, 228.15, -103.89}, +{'c', 228.15, -103.89, 224.26 ,-77.54, 232.04, -71.92}, +{'c', 232.04, -71.92, 236.79 ,-64.58, 243.71, -71.06}, +{'f', 0.201000,0.201000,0.201000,1.000000,0,0 }, +{'m', 263.27, -120.27, 0, 0, 0, 0}, +{'c', 263.27, -120.27, 265.35 ,-128.83, 260.69, -124.17}, +{'c', 260.69, -124.17, 253.91 ,-118.66, 246.70, -118.66}, +{'c', 246.70, -118.66, 232.71 ,-116.54, 228.47, -103.82}, +{'c', 228.47, -103.82, 224.65 ,-77.95, 232.28, -72.44}, +{'c', 232.28, -72.44, 236.94 ,-65.23, 243.73, -71.59}, +{'f', 0.402000,0.402000,0.402000,1.000000,0,0 }, +{'m', 262.90, -119.92, 0, 0, 0, 0}, +{'c', 262.90, -119.92, 264.97 ,-128.29, 260.39, -123.71}, +{'c', 260.39, -123.71, 253.74 ,-118.30, 246.66, -118.30}, +{'c', 246.66, -118.30, 232.94 ,-116.22, 228.78, -103.74}, +{'c', 228.78, -103.74, 225.03 ,-78.37, 232.52, -72.96}, +{'c', 232.52, -72.96, 237.10 ,-65.89, 243.75, -72.13}, +{'f', 0.603000,0.603000,0.603000,1.000000,0,0 }, +{'m', 262.53, -119.56, 0, 0, 0, 0}, +{'c', 262.53, -119.56, 264.59 ,-127.74, 260.10, -123.26}, +{'c', 260.10, -123.26, 253.57 ,-117.95, 246.63, -117.95}, +{'c', 246.63, -117.95, 233.17 ,-115.91, 229.09, -103.67}, +{'c', 229.09, -103.67, 225.42 ,-78.78, 232.76, -73.48}, +{'c', 232.76, -73.48, 237.25 ,-66.54, 243.78, -72.66}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', 262.15, -119.20, 0, 0, 0, 0}, +{'c', 262.15, -119.20, 264.20 ,-127.20, 259.80, -122.80}, +{'c', 259.80, -122.80, 253.40 ,-117.60, 246.60, -117.60}, +{'c', 246.60, -117.60, 233.40 ,-115.60, 229.40, -103.60}, +{'c', 229.40, -103.60, 225.80 ,-79.20, 233.00, -74.00}, +{'c', 233.00, -74.00, 237.40 ,-67.20, 243.80, -73.20}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', 50.60, 84.00, 0, 0, 0, 0}, +{'c', 50.60, 84.00, 30.20 ,64.80, 22.20, 64.00}, +{'c', 22.20, 64.00, -12.20 ,60.00, -27.00, 78.00}, +{'c', -27.00, 78.00, -9.40 ,57.60, 18.20, 63.20}, +{'c', 18.20, 63.20, -3.40 ,58.80, -15.80, 62.00}, +{'c', -15.80, 62.00, -32.60 ,62.00, -42.20, 76.00}, +{'l', -45.00, 80.80, 0, 0, 0, 0}, +{'c', -45.00, 80.80, -41.00 ,66.00, -22.60, 60.00}, +{'c', -22.60, 60.00, 0.20 ,55.20, 11.00, 60.00}, +{'c', 11.00, 60.00, -10.60 ,53.20, -20.60, 55.20}, +{'c', -20.60, 55.20, -51.00 ,52.80, -63.80, 79.20}, +{'c', -63.80, 79.20, -59.80 ,64.80, -45.00, 57.60}, +{'c', -45.00, 57.60, -31.40 ,48.80, -11.00, 51.60}, +{'c', -11.00, 51.60, 3.40 ,54.80, 8.60, 57.20}, +{'c', 13.80, 59.60, 12.60 ,56.80, 4.20, 52.00}, +{'c', 4.20, 52.00, -1.40 ,42.00, -15.40, 42.40}, +{'c', -15.40, 42.40, -58.20 ,46.00, -68.60, 58.00}, +{'c', -68.60, 58.00, -55.00 ,46.80, -44.60, 44.00}, +{'c', -44.60, 44.00, -22.20 ,36.00, -13.80, 36.80}, +{'c', -13.80, 36.80, 11.00 ,37.80, 18.60, 33.80}, +{'c', 18.60, 33.80, 7.40 ,38.80, 10.60, 42.00}, +{'c', 13.80, 45.20, 20.60 ,52.80, 20.60, 54.00}, +{'c', 20.60, 55.20, 44.80 ,77.30, 48.40, 81.70}, +{'f', 0.603000,0.134000,0.000000,1.000000,0,0 }, +{'m', 189.00, 278.00, 0, 0, 0, 0}, +{'c', 189.00, 278.00, 173.50 ,241.50, 161.00, 232.00}, +{'c', 161.00, 232.00, 187.00 ,248.00, 190.50, 266.00}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', 236.00, 285.50, 0, 0, 0, 0}, +{'c', 236.00, 285.50, 209.50 ,230.50, 191.00, 206.50}, +{'c', 191.00, 206.50, 234.50 ,244.00, 239.50, 270.50}, +{'l', 240.00, 276.00, 0, 0, 0, 0}, +{'l', 237.00, 273.50, 0, 0, 0, 0}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', 292.50, 237.00, 0, 0, 0, 0}, +{'c', 292.50, 237.00, 230.00 ,177.50, 228.50, 175.00}, +{'c', 228.50, 175.00, 289.00 ,241.00, 292.00, 248.50}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', 104.00, 280.50, 0, 0, 0, 0}, +{'c', 104.00, 280.50, 123.50 ,228.50, 142.50, 251.00}, +{'c', 142.50, 251.00, 157.50 ,261.00, 157.00, 264.00}, +{'c', 157.00, 264.00, 153.00 ,257.50, 135.00, 258.00}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', 294.50, 153.00, 0, 0, 0, 0}, +{'c', 294.50, 153.00, 249.50 ,124.50, 242.00, 123.00}, +{'c', 230.19, 120.64, 291.50 ,152.00, 296.50, 162.50}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', 143.80, 259.60, 0, 0, 0, 0}, +{'c', 143.80, 259.60, 164.20 ,257.60, 171.00, 250.80}, +{'l', 175.40, 254.40, 0, 0, 0, 0}, +{'l', 193.00, 216.00, 0, 0, 0, 0}, +{'l', 196.60, 221.20, 0, 0, 0, 0}, +{'c', 196.60, 221.20, 211.00 ,206.40, 210.20, 198.40}, +{'c', 209.40, 190.40, 223.00 ,204.40, 223.00, 204.40}, +{'c', 223.00, 204.40, 222.20 ,192.80, 229.40, 199.60}, +{'c', 229.40, 199.60, 227.00 ,184.00, 235.40, 192.00}, +{'c', 235.40, 192.00, 224.86 ,161.84, 247.40, 187.60}, +{'c', 253.00, 194.00, 248.60 ,187.20, 248.60, 187.20}, +{'c', 248.60, 187.20, 222.60 ,139.20, 244.20, 153.60}, +{'c', 244.20, 153.60, 246.20 ,130.80, 245.00, 126.40}, +{'c', 243.80, 122.00, 241.80 ,99.60, 237.00, 94.40}, +{'c', 232.20, 89.20, 237.40 ,87.60, 243.00, 92.80}, +{'c', 243.00, 92.80, 231.80 ,68.80, 245.00, 80.80}, +{'c', 245.00, 80.80, 241.40 ,65.60, 237.00, 62.80}, +{'c', 237.00, 62.80, 231.40 ,45.60, 246.60, 56.40}, +{'c', 246.60, 56.40, 242.20 ,44.00, 239.00, 40.80}, +{'c', 239.00, 40.80, 227.40 ,13.20, 234.60, 18.00}, +{'l', 239.00, 21.60, 0, 0, 0, 0}, +{'c', 239.00, 21.60, 232.20 ,7.60, 238.60, 12.00}, +{'c', 245.00, 16.40, 245.00 ,16.00, 245.00, 16.00}, +{'c', 245.00, 16.00, 223.80 ,-17.20, 244.20, 0.40}, +{'c', 244.20, 0.40, 236.04 ,-13.52, 232.60, -20.40}, +{'c', 232.60, -20.40, 213.80 ,-40.80, 228.20, -34.40}, +{'l', 233.00, -32.80, 0, 0, 0, 0}, +{'c', 233.00, -32.80, 224.20 ,-42.80, 216.20, -44.40}, +{'c', 208.20, -46.00, 218.60 ,-52.40, 225.00, -50.40}, +{'c', 231.40, -48.40, 247.00 ,-40.80, 247.00, -40.80}, +{'c', 247.00, -40.80, 259.80 ,-22.00, 263.80, -21.60}, +{'c', 263.80, -21.60, 243.80 ,-29.20, 249.80, -21.20}, +{'c', 249.80, -21.20, 264.20 ,-7.20, 257.00, -7.60}, +{'c', 257.00, -7.60, 251.00 ,-0.40, 255.80, 8.40}, +{'c', 255.80, 8.40, 237.34 ,-9.99, 252.20, 15.60}, +{'l', 259.00, 32.00, 0, 0, 0, 0}, +{'c', 259.00, 32.00, 234.60 ,7.20, 245.80, 29.20}, +{'c', 245.80, 29.20, 263.00 ,52.80, 265.00, 53.20}, +{'c', 267.00, 53.60, 271.40 ,62.40, 271.40, 62.40}, +{'l', 267.00, 60.40, 0, 0, 0, 0}, +{'l', 272.20, 69.20, 0, 0, 0, 0}, +{'c', 272.20, 69.20, 261.00 ,57.20, 267.00, 70.40}, +{'l', 272.60, 84.80, 0, 0, 0, 0}, +{'c', 272.60, 84.80, 252.20 ,62.80, 265.80, 92.40}, +{'c', 265.80, 92.40, 249.40 ,87.20, 258.20, 104.40}, +{'c', 258.20, 104.40, 256.60 ,120.40, 257.00, 125.60}, +{'c', 257.40, 130.80, 258.60 ,159.20, 254.20, 167.20}, +{'c', 249.80, 175.20, 260.20 ,194.40, 262.20, 198.40}, +{'c', 264.20, 202.40, 267.80 ,213.20, 259.00, 204.00}, +{'c', 250.20, 194.80, 254.60 ,200.40, 256.60, 209.20}, +{'c', 258.60, 218.00, 264.60 ,233.60, 263.80, 239.20}, +{'c', 263.80, 239.20, 262.60 ,240.40, 259.40, 236.80}, +{'c', 259.40, 236.80, 244.60 ,214.00, 246.20, 228.40}, +{'c', 246.20, 228.40, 245.00 ,236.40, 241.80, 245.20}, +{'c', 241.80, 245.20, 238.60 ,256.00, 238.60, 247.20}, +{'c', 238.60, 247.20, 235.40 ,230.40, 232.60, 238.00}, +{'c', 229.80, 245.60, 226.20 ,251.60, 223.40, 254.00}, +{'c', 220.60, 256.40, 215.40 ,233.60, 214.20, 244.00}, +{'c', 214.20, 244.00, 202.20 ,231.60, 197.40, 248.00}, +{'l', 185.80, 264.40, 0, 0, 0, 0}, +{'c', 185.80, 264.40, 185.40 ,252.00, 184.20, 258.00}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', 109.40, -97.20, 0, 0, 0, 0}, +{'c', 109.40, -97.20, 97.80 ,-105.20, 93.80, -104.80}, +{'c', 89.80, -104.40, 121.40 ,-113.60, 162.60, -86.00}, +{'c', 162.60, -86.00, 167.40 ,-83.20, 171.00, -83.60}, +{'c', 171.00, -83.60, 174.20 ,-81.20, 171.40, -77.60}, +{'c', 171.40, -77.60, 162.60 ,-68.00, 173.80, -56.80}, +{'c', 173.80, -56.80, 192.20 ,-50.00, 186.60, -58.80}, +{'c', 186.60, -58.80, 197.40 ,-54.80, 199.80, -50.80}, +{'c', 202.20, -46.80, 201.00 ,-50.80, 201.00, -50.80}, +{'c', 201.00, -50.80, 194.60 ,-58.00, 188.60, -63.20}, +{'c', 188.60, -63.20, 183.40 ,-65.20, 180.60, -73.60}, +{'c', 177.80, -82.00, 175.40 ,-92.00, 179.80, -95.20}, +{'c', 179.80, -95.20, 175.80 ,-90.80, 176.60, -94.80}, +{'c', 177.40, -98.80, 181.00 ,-102.40, 182.60, -102.80}, +{'c', 184.20, -103.20, 200.60 ,-119.00, 207.40, -119.40}, +{'c', 207.40, -119.40, 198.20 ,-118.00, 195.20, -119.00}, +{'c', 192.20, -120.00, 165.60 ,-131.40, 159.60, -132.60}, +{'c', 159.60, -132.60, 142.80 ,-139.20, 154.80, -137.20}, +{'c', 154.80, -137.20, 190.60 ,-133.40, 208.80, -120.20}, +{'c', 208.80, -120.20, 201.60 ,-128.60, 183.20, -135.60}, +{'c', 183.20, -135.60, 161.00 ,-148.20, 125.80, -143.20}, +{'c', 125.80, -143.20, 108.00 ,-140.00, 100.20, -138.20}, +{'c', 100.20, -138.20, 97.60 ,-138.80, 97.00, -139.20}, +{'c', 96.40, -139.60, 84.60 ,-148.60, 57.00, -141.60}, +{'c', 57.00, -141.60, 40.00 ,-137.00, 31.40, -132.20}, +{'c', 31.40, -132.20, 16.20 ,-131.00, 12.60, -127.80}, +{'c', 12.60, -127.80, -6.00 ,-113.20, -8.00, -112.40}, +{'c', -10.00, -111.60, -21.40 ,-104.00, -22.20, -103.60}, +{'c', -22.20, -103.60, 2.40 ,-110.20, 4.80, -112.60}, +{'c', 7.20, -115.00, 24.60 ,-117.60, 27.00, -116.20}, +{'c', 29.40, -114.80, 37.80 ,-115.40, 28.20, -114.80}, +{'c', 28.20, -114.80, 103.80 ,-100.00, 104.60, -98.00}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', 180.80, -106.40, 0, 0, 0, 0}, +{'c', 180.80, -106.40, 170.60 ,-113.80, 168.60, -113.80}, +{'c', 166.60, -113.80, 154.20 ,-124.00, 150.00, -123.60}, +{'c', 145.80, -123.20, 133.60 ,-133.20, 106.20, -125.00}, +{'c', 106.20, -125.00, 105.60 ,-127.00, 109.20, -127.80}, +{'c', 109.20, -127.80, 115.60 ,-130.00, 116.00, -130.60}, +{'c', 116.00, -130.60, 136.20 ,-134.80, 143.40, -131.20}, +{'c', 143.40, -131.20, 152.60 ,-128.60, 158.80, -122.40}, +{'c', 158.80, -122.40, 170.00 ,-119.20, 173.20, -120.20}, +{'c', 173.20, -120.20, 182.00 ,-118.00, 182.40, -116.20}, +{'c', 182.40, -116.20, 188.20 ,-113.20, 186.40, -110.60}, +{'f', 0.804000,0.469000,0.134000,1.000000,0,0 }, +{'m', 168.33, -108.51, 0, 0, 0, 0}, +{'c', 169.14, -107.88, 170.16 ,-107.78, 170.76, -106.97}, +{'c', 171.00, -106.66, 170.71 ,-106.33, 170.39, -106.23}, +{'c', 169.35, -105.92, 168.29 ,-106.49, 167.15, -105.90}, +{'c', 166.75, -105.69, 166.11 ,-105.87, 165.55, -106.02}, +{'c', 163.92, -106.46, 162.09 ,-106.49, 160.40, -105.80}, +{'c', 158.42, -106.93, 156.06 ,-106.34, 153.97, -107.35}, +{'c', 153.92, -107.37, 153.69 ,-107.03, 153.62, -107.05}, +{'c', 150.57, -108.20, 146.83 ,-107.92, 144.40, -110.20}, +{'c', 141.97, -110.61, 139.62 ,-111.07, 137.19, -111.75}, +{'c', 135.37, -112.26, 133.96 ,-113.25, 132.34, -114.08}, +{'c', 130.96, -114.79, 129.51 ,-115.31, 127.97, -115.69}, +{'c', 126.11, -116.14, 124.28 ,-116.03, 122.39, -116.55}, +{'c', 122.29, -116.57, 122.10 ,-116.23, 122.02, -116.25}, +{'c', 121.69, -116.36, 121.41 ,-116.94, 121.23, -116.89}, +{'c', 119.55, -116.37, 118.06 ,-117.34, 116.40, -117.00}, +{'c', 115.22, -118.22, 113.50 ,-117.98, 111.95, -118.42}, +{'c', 108.98, -119.27, 105.83 ,-118.00, 102.80, -119.00}, +{'c', 106.91, -120.84, 111.60 ,-119.61, 115.66, -121.68}, +{'c', 117.99, -122.86, 120.65 ,-121.76, 123.22, -122.52}, +{'c', 123.71, -122.67, 124.40 ,-122.87, 124.80, -122.20}, +{'c', 124.94, -122.33, 125.12 ,-122.57, 125.17, -122.55}, +{'c', 127.62, -121.39, 129.94 ,-120.11, 132.42, -119.05}, +{'c', 132.76, -118.90, 133.29 ,-119.14, 133.55, -118.93}, +{'c', 135.07, -117.72, 137.01 ,-117.82, 138.40, -116.60}, +{'c', 140.10, -117.10, 141.89 ,-116.72, 143.62, -117.35}, +{'c', 143.70, -117.37, 143.93 ,-117.03, 143.97, -117.05}, +{'c', 145.09, -117.80, 146.25 ,-117.53, 147.14, -117.23}, +{'c', 147.48, -117.11, 148.14 ,-116.86, 148.45, -116.79}, +{'c', 149.57, -116.52, 150.43 ,-116.03, 151.61, -115.85}, +{'c', 151.72, -115.83, 151.91 ,-116.17, 151.98, -116.15}, +{'c', 153.10, -115.71, 154.15 ,-115.76, 154.80, -114.60}, +{'c', 154.94, -114.73, 155.10 ,-114.97, 155.18, -114.95}, +{'c', 156.21, -114.61, 156.86 ,-113.85, 157.96, -113.61}, +{'c', 158.44, -113.51, 159.06 ,-112.88, 159.63, -112.70}, +{'c', 162.03, -111.97, 163.87 ,-110.44, 166.06, -109.55}, +{'f', 0.804000,0.469000,0.134000,1.000000,0,0 }, +{'m', 91.70, -122.74, 0, 0, 0, 0}, +{'c', 89.18, -124.46, 86.81 ,-125.57, 84.37, -127.36}, +{'c', 84.19, -127.49, 83.83 ,-127.32, 83.62, -127.44}, +{'c', 82.62, -128.05, 81.73 ,-128.63, 80.75, -129.33}, +{'c', 80.21, -129.71, 79.39 ,-129.70, 78.88, -129.96}, +{'c', 76.34, -131.25, 73.71 ,-131.81, 71.20, -133.00}, +{'c', 71.88, -133.64, 73.00 ,-133.39, 73.60, -134.20}, +{'c', 73.80, -133.92, 74.03 ,-133.64, 74.39, -133.83}, +{'c', 76.06, -134.73, 77.91 ,-134.88, 79.59, -134.79}, +{'c', 81.29, -134.70, 83.01 ,-134.40, 84.79, -134.12}, +{'c', 85.10, -134.08, 85.30 ,-133.56, 85.62, -133.46}, +{'c', 87.85, -132.79, 90.23 ,-133.32, 92.35, -132.48}, +{'c', 93.94, -131.85, 95.52 ,-131.03, 96.75, -129.75}, +{'c', 97.01, -129.50, 96.68 ,-129.19, 96.40, -129.00}, +{'c', 96.79, -129.11, 97.06 ,-128.90, 97.17, -128.59}, +{'c', 97.26, -128.35, 97.26 ,-128.05, 97.17, -127.81}, +{'c', 97.06, -127.50, 96.78 ,-127.40, 96.41, -127.35}, +{'c', 95.00, -127.16, 96.77 ,-128.54, 96.07, -128.09}, +{'c', 94.80, -127.27, 95.55 ,-125.87, 94.80, -124.60}, +{'c', 94.52, -124.79, 94.29 ,-125.01, 94.40, -125.40}, +{'c', 94.64, -124.88, 94.03 ,-124.59, 93.86, -124.27}, +{'f', 0.804000,0.469000,0.134000,1.000000,0,0 }, +{'m', 59.20, -115.39, 0, 0, 0, 0}, +{'c', 56.04, -116.19, 52.99 ,-116.07, 49.98, -117.35}, +{'c', 49.91, -117.37, 49.69 ,-117.03, 49.62, -117.05}, +{'c', 48.26, -117.65, 47.34 ,-118.61, 46.26, -119.66}, +{'c', 45.35, -120.55, 43.69 ,-120.16, 42.42, -120.65}, +{'c', 42.09, -120.77, 41.89 ,-121.28, 41.59, -121.32}, +{'c', 40.37, -121.48, 39.45 ,-122.43, 38.40, -123.00}, +{'c', 40.74, -123.80, 43.15 ,-123.76, 45.61, -124.15}, +{'c', 45.72, -124.17, 45.87 ,-123.84, 46.00, -123.84}, +{'c', 46.14, -123.84, 46.27 ,-124.07, 46.40, -124.20}, +{'c', 46.59, -123.92, 46.90 ,-123.59, 47.15, -123.85}, +{'c', 47.70, -124.39, 48.26 ,-124.20, 48.80, -124.16}, +{'c', 48.94, -124.15, 49.07 ,-123.84, 49.20, -123.84}, +{'c', 49.34, -123.84, 49.47 ,-124.16, 49.60, -124.16}, +{'c', 49.74, -124.16, 49.87 ,-123.84, 50.00, -123.84}, +{'c', 50.14, -123.84, 50.27 ,-124.07, 50.40, -124.20}, +{'c', 51.09, -123.42, 51.98 ,-123.97, 52.80, -123.79}, +{'c', 53.84, -123.57, 54.10 ,-122.42, 55.18, -122.12}, +{'c', 59.89, -120.82, 64.03 ,-118.67, 68.39, -116.58}, +{'c', 68.70, -116.44, 68.91 ,-116.19, 68.80, -115.80}, +{'c', 69.07, -115.80, 69.38 ,-115.89, 69.57, -115.76}, +{'c', 70.63, -115.02, 71.67 ,-114.48, 72.37, -113.38}, +{'c', 72.58, -113.04, 72.25 ,-112.63, 72.02, -112.68}, +{'f', 0.804000,0.469000,0.134000,1.000000,0,0 }, +{'m', 45.34, -71.18, 0, 0, 0, 0}, +{'c', 43.75, -72.40, 43.16 ,-74.43, 42.03, -76.22}, +{'c', 41.82, -76.56, 42.09 ,-76.88, 42.41, -76.96}, +{'c', 42.97, -77.12, 43.51 ,-76.64, 43.92, -76.44}, +{'c', 45.67, -75.58, 47.20 ,-74.34, 49.20, -74.20}, +{'c', 51.19, -71.97, 55.45 ,-71.58, 55.46, -68.20}, +{'c', 55.46, -67.34, 54.03 ,-68.26, 53.60, -67.40}, +{'c', 51.15, -68.40, 48.76 ,-68.30, 46.38, -69.77}, +{'f', 0.804000,0.469000,0.134000,1.000000,0,0 }, +{'m', 17.80, -123.76, 0, 0, 0, 0}, +{'c', 17.93, -123.75, 24.97 ,-123.52, 24.95, -123.41}, +{'c', 24.90, -123.10, 17.17 ,-122.05, 16.81, -122.22}, +{'c', 16.65, -122.30, 9.13 ,-119.87, 9.00, -120.00}, +{'f', 0.804000,0.469000,0.134000,1.000000,0,0 }, +{'m', 33.20, -114.00, 0, 0, 0, 0}, +{'c', 33.20, -114.00, 18.40 ,-112.20, 14.00, -111.00}, +{'c', 9.60, -109.80, -9.00 ,-102.20, -12.00, -100.20}, +{'c', -12.00, -100.20, -25.40 ,-94.80, -42.40, -74.80}, +{'c', -42.40, -74.80, -34.80 ,-78.20, -32.60, -81.00}, +{'c', -32.60, -81.00, -19.00 ,-93.60, -19.20, -91.00}, +{'c', -19.20, -91.00, -7.00 ,-99.60, -7.60, -97.40}, +{'c', -7.60, -97.40, 16.80 ,-108.60, 14.80, -105.40}, +{'c', 14.80, -105.40, 36.40 ,-110.00, 35.40, -108.00}, +{'c', 35.40, -108.00, 54.20 ,-103.60, 51.40, -103.40}, +{'c', 51.40, -103.40, 45.60 ,-102.20, 52.00, -98.60}, +{'c', 52.00, -98.60, 48.60 ,-94.20, 43.20, -98.20}, +{'c', 37.80, -102.20, 40.80 ,-100.00, 35.80, -99.00}, +{'c', 35.80, -99.00, 33.20 ,-98.20, 28.60, -102.20}, +{'c', 28.60, -102.20, 23.00 ,-106.80, 14.20, -103.20}, +{'c', 14.20, -103.20, -16.40 ,-90.60, -18.40, -90.00}, +{'c', -18.40, -90.00, -22.00 ,-87.20, -24.40, -83.60}, +{'c', -24.40, -83.60, -30.20 ,-79.20, -33.20, -77.80}, +{'c', -33.20, -77.80, -46.00 ,-66.20, -47.20, -64.80}, +{'c', -47.20, -64.80, -50.60 ,-59.60, -51.40, -59.20}, +{'c', -51.40, -59.20, -45.00 ,-63.00, -43.00, -65.00}, +{'c', -43.00, -65.00, -29.00 ,-75.00, -23.60, -75.80}, +{'c', -23.60, -75.80, -19.20 ,-78.80, -18.40, -80.20}, +{'c', -18.40, -80.20, -4.00 ,-89.40, 0.20, -89.40}, +{'c', 0.20, -89.40, 9.40 ,-84.20, 11.80, -91.20}, +{'c', 11.80, -91.20, 17.60 ,-93.00, 23.20, -91.80}, +{'c', 23.20, -91.80, 26.40 ,-94.40, 25.60, -96.60}, +{'c', 25.60, -96.60, 27.20 ,-98.40, 28.20, -94.60}, +{'c', 28.20, -94.60, 31.60 ,-91.00, 36.40, -93.00}, +{'c', 36.40, -93.00, 40.40 ,-93.20, 38.40, -90.80}, +{'c', 38.40, -90.80, 34.00 ,-87.00, 22.20, -86.80}, +{'c', 22.20, -86.80, 9.80 ,-86.20, -6.60, -78.60}, +{'c', -6.60, -78.60, -36.40 ,-68.20, -45.60, -57.80}, +{'c', -45.60, -57.80, -52.00 ,-49.00, -57.40, -47.80}, +{'c', -57.40, -47.80, -63.20 ,-47.00, -69.20, -39.60}, +{'c', -69.20, -39.60, -59.40 ,-45.40, -50.40, -45.40}, +{'c', -50.40, -45.40, -46.40 ,-47.80, -50.20, -44.20}, +{'c', -50.20, -44.20, -53.80 ,-36.60, -52.20, -31.20}, +{'c', -52.20, -31.20, -52.80 ,-26.00, -53.60, -24.40}, +{'c', -53.60, -24.40, -61.40 ,-11.60, -61.40, -9.20}, +{'c', -61.40, -6.80, -60.20 ,3.00, -59.80, 3.60}, +{'c', -59.40, 4.20, -60.80 ,2.00, -57.00, 4.40}, +{'c', -53.20, 6.80, -50.40 ,8.40, -49.60, 11.20}, +{'c', -48.80, 14.00, -51.60 ,5.80, -51.80, 4.00}, +{'c', -52.00, 2.20, -56.20 ,-5.00, -55.40, -7.40}, +{'c', -55.40, -7.40, -54.40 ,-6.40, -53.60, -5.00}, +{'c', -53.60, -5.00, -54.20 ,-5.60, -53.60, -9.20}, +{'c', -53.60, -9.20, -52.80 ,-14.40, -51.40, -17.60}, +{'c', -50.00, -20.80, -48.00 ,-24.60, -47.60, -25.40}, +{'c', -47.20, -26.20, -47.20 ,-32.00, -45.80, -29.40}, +{'l', -42.40, -26.80, 0, 0, 0, 0}, +{'c', -42.40, -26.80, -45.20 ,-29.40, -43.00, -31.60}, +{'c', -43.00, -31.60, -44.00 ,-37.20, -42.20, -39.80}, +{'c', -42.20, -39.80, -35.20 ,-48.20, -33.60, -49.20}, +{'c', -32.00, -50.20, -33.40 ,-49.80, -33.40, -49.80}, +{'c', -33.40, -49.80, -27.40 ,-54.00, -33.20, -52.40}, +{'c', -33.20, -52.40, -37.20 ,-50.80, -40.20, -50.80}, +{'c', -40.20, -50.80, -47.80 ,-48.80, -43.80, -53.00}, +{'c', -39.80, -57.20, -29.80 ,-62.60, -26.00, -62.40}, +{'l', -25.20, -60.80, 0, 0, 0, 0}, +{'l', -14.00, -63.20, 0, 0, 0, 0}, +{'l', -15.20, -62.40, 0, 0, 0, 0}, +{'c', -15.20, -62.40, -15.40 ,-62.60, -11.20, -63.00}, +{'c', -7.00, -63.40, -1.20 ,-62.00, 0.20, -63.80}, +{'c', 1.60, -65.60, 5.00 ,-66.60, 4.60, -65.20}, +{'c', 4.20, -63.80, 4.00 ,-61.80, 4.00, -61.80}, +{'c', 4.00, -61.80, 9.00 ,-67.60, 8.40, -65.40}, +{'c', 7.80, -63.20, -0.40 ,-58.00, -1.80, -51.80}, +{'l', 8.60, -60.00, 0, 0, 0, 0}, +{'l', 12.20, -63.00, 0, 0, 0, 0}, +{'c', 12.20, -63.00, 15.80 ,-60.80, 16.00, -62.40}, +{'c', 16.20, -64.00, 20.80 ,-69.80, 22.00, -69.60}, +{'c', 23.20, -69.40, 25.20 ,-72.20, 25.00, -69.60}, +{'c', 24.80, -67.00, 32.40 ,-61.60, 32.40, -61.60}, +{'c', 32.40, -61.60, 35.60 ,-63.40, 37.00, -62.00}, +{'c', 38.40, -60.60, 42.60 ,-81.80, 42.60, -81.80}, +{'l', 67.60, -92.40, 0, 0, 0, 0}, +{'l', 111.20, -95.80, 0, 0, 0, 0}, +{'l', 94.20, -102.60, 0, 0, 0, 0}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', 51.40, 85.00, 0, 0, 0, 0}, +{'c', 51.40, 85.00, 36.40 ,68.20, 28.00, 65.60}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', 24.80, 64.20, 0, 0, 0, 0}, +{'c', 24.80, 64.20, -0.40 ,56.20, -15.80, 60.40}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', 21.20, 63.00, 0, 0, 0, 0}, +{'c', 21.20, 63.00, 4.20 ,55.80, -10.60, 53.60}, +{'c', -10.60, 53.60, -27.20 ,51.00, -43.80, 58.20}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', 22.20, 63.40, 0, 0, 0, 0}, +{'c', 22.20, 63.40, 6.80 ,52.40, 5.80, 51.00}, +{'c', 5.80, 51.00, -1.20 ,40.00, -14.20, 39.60}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', 20.89, 54.41, 0, 0, 0, 0}, +{'c', 22.44, 55.87, 49.40 ,84.80, 49.40, 84.80}, +{'c', 84.60, 121.40, 56.60 ,87.20, 56.60, 87.20}, +{'c', 49.00, 82.40, 39.80 ,63.60, 39.80, 63.60}, +{'c', 38.60, 60.80, 53.80 ,70.80, 53.80, 70.80}, +{'c', 57.80, 71.60, 71.40 ,90.80, 71.40, 90.80}, +{'c', 64.60, 88.40, 69.40 ,95.60, 69.40, 95.60}, +{'c', 72.20, 97.60, 92.60 ,113.20, 92.60, 113.20}, +{'c', 96.20, 117.20, 100.20 ,118.80, 100.20, 118.80}, +{'c', 114.20, 113.60, 107.80 ,126.80, 107.80, 126.80}, +{'c', 110.20, 133.60, 115.80 ,122.00, 115.80, 122.00}, +{'c', 127.00, 105.20, 110.60 ,107.60, 110.60, 107.60}, +{'c', 80.60, 110.40, 73.80 ,94.40, 73.80, 94.40}, +{'c', 71.40, 92.00, 80.20 ,94.40, 80.20, 94.40}, +{'c', 88.60, 96.40, 73.00 ,82.00, 73.00, 82.00}, +{'c', 75.40, 82.00, 84.60 ,88.80, 84.60, 88.80}, +{'c', 95.00, 98.00, 97.00 ,96.00, 97.00, 96.00}, +{'c', 115.00, 87.20, 125.40 ,94.80, 125.40, 94.80}, +{'c', 127.40, 96.40, 121.80 ,103.20, 123.40, 108.40}, +{'c', 125.00, 113.60, 129.80 ,126.00, 129.80, 126.00}, +{'c', 127.40, 127.60, 127.80 ,138.40, 127.80, 138.40}, +{'c', 144.60, 161.60, 135.00 ,159.60, 135.00, 159.60}, +{'c', 119.40, 159.20, 134.20 ,166.80, 134.20, 166.80}, +{'c', 137.40, 168.80, 146.20 ,176.00, 146.20, 176.00}, +{'c', 143.40, 174.80, 141.80 ,180.00, 141.80, 180.00}, +{'c', 146.60, 184.00, 143.80 ,188.80, 143.80, 188.80}, +{'c', 137.80, 190.00, 136.60 ,194.00, 136.60, 194.00}, +{'c', 143.40, 202.00, 133.40 ,202.40, 133.40, 202.40}, +{'c', 137.00, 206.80, 132.20 ,218.80, 132.20, 218.80}, +{'c', 127.40, 218.80, 121.00 ,224.40, 121.00, 224.40}, +{'c', 123.40, 229.20, 113.00 ,234.80, 113.00, 234.80}, +{'c', 104.60, 236.40, 107.40 ,243.20, 107.40, 243.20}, +{'c', 99.40, 249.20, 97.00 ,265.20, 97.00, 265.20}, +{'c', 96.20, 275.60, 93.80 ,278.80, 99.00, 276.80}, +{'c', 104.20, 274.80, 103.40 ,262.40, 103.40, 262.40}, +{'c', 98.60, 246.80, 141.40 ,230.80, 141.40, 230.80}, +{'c', 145.40, 229.20, 146.20 ,224.00, 146.20, 224.00}, +{'c', 148.20, 224.40, 157.00 ,232.00, 157.00, 232.00}, +{'c', 164.60, 243.20, 165.00 ,234.00, 165.00, 234.00}, +{'c', 166.20, 230.40, 164.60 ,224.40, 164.60, 224.40}, +{'c', 170.60, 202.80, 156.60 ,196.40, 156.60, 196.40}, +{'c', 146.60, 162.80, 160.60 ,171.20, 160.60, 171.20}, +{'c', 163.40, 176.80, 174.20 ,182.00, 174.20, 182.00}, +{'l', 177.80, 179.60, 0, 0, 0, 0}, +{'c', 176.20, 174.80, 184.60 ,168.80, 184.60, 168.80}, +{'c', 187.40, 175.20, 193.40 ,167.20, 193.40, 167.20}, +{'c', 197.00, 142.80, 209.40 ,157.20, 209.40, 157.20}, +{'c', 213.40, 158.40, 214.60 ,151.60, 214.60, 151.60}, +{'c', 218.20, 141.20, 214.60 ,127.60, 214.60, 127.60}, +{'c', 218.20, 127.20, 227.80 ,133.20, 227.80, 133.20}, +{'c', 230.60, 129.60, 221.40 ,112.80, 225.40, 115.20}, +{'c', 229.40, 117.60, 233.80 ,119.20, 233.80, 119.20}, +{'c', 234.60, 117.20, 224.60 ,104.80, 224.60, 104.80}, +{'c', 220.20, 102.00, 215.00 ,81.60, 215.00, 81.60}, +{'c', 222.20, 85.20, 212.20 ,70.00, 212.20, 70.00}, +{'c', 212.20, 66.80, 218.20 ,55.60, 218.20, 55.60}, +{'c', 217.40, 48.80, 218.20 ,49.20, 218.20, 49.20}, +{'c', 221.00, 50.40, 229.00 ,52.00, 222.20, 45.60}, +{'c', 215.40, 39.20, 223.00 ,34.40, 223.00, 34.40}, +{'c', 227.40, 31.60, 213.80 ,32.00, 213.80, 32.00}, +{'c', 208.60, 27.60, 209.00 ,23.60, 209.00, 23.60}, +{'c', 217.00, 25.60, 202.60 ,11.20, 200.20, 7.60}, +{'c', 197.80, 4.00, 207.40 ,-1.20, 207.40, -1.20}, +{'c', 220.60, -4.80, 209.00 ,-8.00, 209.00, -8.00}, +{'c', 189.40, -7.60, 200.20 ,-18.40, 200.20, -18.40}, +{'c', 206.20, -18.00, 204.60 ,-20.40, 204.60, -20.40}, +{'c', 199.40, -21.60, 189.80 ,-28.00, 189.80, -28.00}, +{'c', 185.80, -31.60, 189.40 ,-30.80, 189.40, -30.80}, +{'c', 206.20, -29.60, 177.40 ,-40.80, 177.40, -40.80}, +{'c', 185.40, -40.80, 167.40 ,-51.20, 167.40, -51.20}, +{'c', 165.40, -52.80, 162.20 ,-60.40, 162.20, -60.40}, +{'c', 156.20, -65.60, 151.40 ,-72.40, 151.40, -72.40}, +{'c', 151.00, -76.80, 146.20 ,-81.60, 146.20, -81.60}, +{'c', 134.60, -95.20, 129.00 ,-94.80, 129.00, -94.80}, +{'c', 114.20, -98.40, 109.00 ,-97.60, 109.00, -97.60}, +{'l', 56.20, -93.20, 0, 0, 0, 0}, +{'c', 29.80, -80.40, 37.60 ,-59.40, 37.60, -59.40}, +{'c', 44.00, -51.00, 53.20 ,-54.80, 53.20, -54.80}, +{'c', 57.80, -61.00, 69.40 ,-58.80, 69.40, -58.80}, +{'c', 89.80, -55.60, 87.20 ,-59.20, 87.20, -59.20}, +{'c', 84.80, -63.80, 68.60 ,-70.00, 68.40, -70.60}, +{'c', 68.20, -71.20, 59.40 ,-74.60, 59.40, -74.60}, +{'c', 56.40, -75.80, 52.00 ,-85.00, 52.00, -85.00}, +{'c', 48.80, -88.40, 64.60 ,-82.60, 64.60, -82.60}, +{'c', 63.40, -81.60, 70.80 ,-77.60, 70.80, -77.60}, +{'c', 88.20, -78.60, 98.80 ,-67.80, 98.80, -67.80}, +{'c', 109.60, -51.20, 109.80 ,-59.40, 109.80, -59.40}, +{'c', 112.60, -68.80, 100.80 ,-90.00, 100.80, -90.00}, +{'c', 101.20, -92.00, 109.40 ,-85.40, 109.40, -85.40}, +{'c', 110.80, -87.40, 111.60 ,-81.60, 111.60, -81.60}, +{'c', 111.80, -79.20, 115.60 ,-71.20, 115.60, -71.20}, +{'c', 118.40, -58.20, 122.00 ,-65.60, 122.00, -65.60}, +{'l', 126.60, -56.20, 0, 0, 0, 0}, +{'c', 128.00, -53.60, 122.00 ,-46.00, 122.00, -46.00}, +{'c', 121.80, -43.20, 122.60 ,-43.40, 117.00, -35.80}, +{'c', 111.40, -28.20, 114.80 ,-23.80, 114.80, -23.80}, +{'c', 113.40, -17.20, 122.20 ,-17.60, 122.20, -17.60}, +{'c', 124.80, -15.40, 128.20 ,-15.40, 128.20, -15.40}, +{'c', 130.00, -13.40, 132.40 ,-14.00, 132.40, -14.00}, +{'c', 134.00, -17.80, 140.20 ,-15.80, 140.20, -15.80}, +{'c', 141.60, -18.20, 149.80 ,-18.60, 149.80, -18.60}, +{'c', 150.80, -21.20, 151.20 ,-22.80, 154.60, -23.40}, +{'c', 158.00, -24.00, 133.40 ,-67.00, 133.40, -67.00}, +{'c', 139.80, -67.80, 131.60 ,-80.20, 131.60, -80.20}, +{'c', 129.40, -86.80, 140.80 ,-72.20, 143.00, -70.80}, +{'c', 145.20, -69.40, 146.20 ,-67.20, 144.60, -67.40}, +{'c', 143.00, -67.60, 141.20 ,-65.40, 142.60, -65.20}, +{'c', 144.00, -65.00, 157.00 ,-50.00, 160.40, -39.80}, +{'c', 163.80, -29.60, 169.80 ,-25.60, 176.00, -19.60}, +{'c', 182.20, -13.60, 181.40 ,10.60, 181.40, 10.60}, +{'c', 181.00, 19.40, 187.00 ,30.00, 187.00, 30.00}, +{'c', 189.00, 33.80, 184.80 ,52.00, 184.80, 52.00}, +{'c', 182.80, 54.20, 184.20 ,55.00, 184.20, 55.00}, +{'c', 185.20, 56.20, 192.00 ,69.40, 192.00, 69.40}, +{'c', 190.20, 69.20, 193.80 ,72.80, 193.80, 72.80}, +{'c', 199.00, 78.80, 192.60 ,75.80, 192.60, 75.80}, +{'c', 186.60, 74.20, 193.60 ,84.00, 193.60, 84.00}, +{'c', 194.80, 85.80, 185.80 ,81.20, 185.80, 81.20}, +{'c', 176.60, 80.60, 188.20 ,87.80, 188.20, 87.80}, +{'c', 196.80, 95.00, 185.40 ,90.60, 185.40, 90.60}, +{'c', 180.80, 88.80, 184.00 ,95.60, 184.00, 95.60}, +{'c', 187.20, 97.20, 204.40 ,104.20, 204.40, 104.20}, +{'c', 204.80, 108.00, 201.80 ,113.00, 201.80, 113.00}, +{'c', 202.20, 117.00, 200.00 ,120.40, 200.00, 120.40}, +{'c', 198.80, 128.60, 198.20 ,129.40, 198.20, 129.40}, +{'c', 194.00, 129.60, 186.60 ,143.40, 186.60, 143.40}, +{'c', 184.80, 146.00, 174.60 ,158.00, 174.60, 158.00}, +{'c', 172.60, 165.00, 154.60 ,157.80, 154.60, 157.80}, +{'c', 148.00, 161.20, 150.00 ,157.80, 150.00, 157.80}, +{'c', 149.60, 155.60, 154.40 ,149.60, 154.40, 149.60}, +{'c', 161.40, 147.00, 158.80 ,136.20, 158.80, 136.20}, +{'c', 162.80, 134.80, 151.60 ,132.00, 151.80, 130.80}, +{'c', 152.00, 129.60, 157.80 ,128.20, 157.80, 128.20}, +{'c', 165.80, 126.20, 161.40 ,123.80, 161.40, 123.80}, +{'c', 160.80, 119.80, 163.80 ,114.20, 163.80, 114.20}, +{'c', 175.40, 113.40, 163.80 ,97.20, 163.80, 97.20}, +{'c', 153.00, 89.60, 152.00 ,83.80, 152.00, 83.80}, +{'c', 164.60, 75.60, 156.40 ,63.20, 156.60, 59.60}, +{'c', 156.80, 56.00, 158.00 ,34.40, 158.00, 34.40}, +{'c', 156.00, 28.20, 153.00 ,14.60, 153.00, 14.60}, +{'c', 155.20, 9.40, 162.60 ,-3.20, 162.60, -3.20}, +{'c', 165.40, -7.40, 174.20 ,-12.20, 172.00, -15.20}, +{'c', 169.80, -18.20, 162.00 ,-16.40, 162.00, -16.40}, +{'c', 154.20, -17.80, 154.80 ,-12.60, 154.80, -12.60}, +{'c', 153.20, -11.60, 152.40 ,-6.60, 152.40, -6.60}, +{'c', 151.68, 1.33, 142.80 ,7.60, 142.80, 7.60}, +{'c', 131.60, 13.80, 140.80 ,17.80, 140.80, 17.80}, +{'c', 146.80, 24.40, 137.00 ,24.60, 137.00, 24.60}, +{'c', 126.00, 22.80, 134.20 ,33.00, 134.20, 33.00}, +{'c', 145.00, 45.80, 142.00 ,48.60, 142.00, 48.60}, +{'c', 131.80, 49.60, 144.40 ,58.80, 144.40, 58.80}, +{'c', 144.40, 58.80, 143.60 ,56.80, 143.80, 58.60}, +{'c', 144.00, 60.40, 147.00 ,64.60, 147.80, 66.60}, +{'c', 148.60, 68.60, 144.60 ,68.80, 144.60, 68.80}, +{'c', 145.20, 78.40, 129.80 ,74.20, 129.80, 74.20}, +{'c', 129.80, 74.20, 129.80 ,74.20, 128.20, 74.40}, +{'c', 126.60, 74.60, 115.40 ,73.80, 109.60, 71.60}, +{'c', 103.80, 69.40, 97.00 ,69.40, 97.00, 69.40}, +{'c', 97.00, 69.40, 93.00 ,71.20, 85.40, 71.00}, +{'c', 77.80, 70.80, 69.80 ,73.60, 69.80, 73.60}, +{'c', 65.40, 73.20, 74.00 ,68.80, 74.20, 69.00}, +{'c', 74.40, 69.20, 80.00 ,63.60, 72.00, 64.20}, +{'c', 50.20, 65.83, 39.40 ,55.60, 39.40, 55.60}, +{'c', 37.40, 54.20, 34.80 ,51.40, 34.80, 51.40}, +{'c', 24.80, 49.40, 36.20 ,63.80, 36.20, 63.80}, +{'c', 37.40, 65.20, 36.00 ,66.20, 36.00, 66.20}, +{'c', 35.20, 64.60, 27.40 ,59.20, 27.40, 59.20}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', -3.00, 42.80, 0, 0, 0, 0}, +{'c', -3.00, 42.80, 8.60 ,48.40, 11.20, 51.20}, +{'c', 13.80, 54.00, 27.80 ,65.40, 27.80, 65.40}, +{'c', 27.80, 65.40, 22.40 ,63.40, 19.80, 61.60}, +{'c', 17.20, 59.80, 6.40 ,51.60, 6.40, 51.60}, +{'f', 0.268000,0.000000,0.000000,1.000000,0,0 }, +{'m', -61.01, 11.60, 0, 0, 0, 0}, +{'c', -60.67, 11.46, -61.20 ,8.74, -61.40, 8.20}, +{'c', -62.42, 5.47, -71.40 ,4.00, -71.40, 4.00}, +{'c', -71.63, 5.37, -71.68 ,6.96, -71.58, 8.60}, +{'f', 0.603000,0.804000,0.201000,1.000000,0,0 }, +{'m', -61.01, 11.40, 0, 0, 0, 0}, +{'c', -61.46, 11.56, -61.02 ,8.67, -61.20, 8.20}, +{'c', -62.22, 5.47, -71.40 ,3.90, -71.40, 3.90}, +{'c', -71.63, 5.26, -71.68 ,6.86, -71.58, 8.50}, +{'f', 0.402000,0.603000,0.000000,1.000000,0,0 }, +{'m', -65.40, 11.55, 0, 0, 0, 0}, +{'c', -66.03, 11.55, -66.53 ,10.41, -66.53, 9.00}, +{'c', -66.53, 7.59, -66.03 ,6.46, -65.40, 6.46}, +{'c', -64.78, 6.46, -64.27 ,7.59, -64.27, 9.00}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', -111.00, 109.60, 0, 0, 0, 0}, +{'c', -111.00, 109.60, -116.60 ,119.60, -91.80, 113.60}, +{'c', -91.80, 113.60, -77.80 ,112.40, -75.40, 110.00}, +{'c', -74.20, 110.80, -65.83 ,113.73, -63.00, 114.40}, +{'c', -56.20, 116.00, -47.80 ,106.00, -47.80, 106.00}, +{'c', -47.80, 106.00, -43.20 ,95.50, -40.40, 95.50}, +{'c', -37.60, 95.50, -40.80 ,97.10, -40.80, 97.10}, +{'c', -40.80, 97.10, -47.40 ,107.20, -47.00, 108.80}, +{'c', -47.00, 108.80, -52.20 ,128.80, -68.20, 129.60}, +{'c', -68.20, 129.60, -84.35 ,130.55, -83.00, 136.40}, +{'c', -83.00, 136.40, -74.20 ,134.00, -71.80, 136.40}, +{'c', -71.80, 136.40, -61.00 ,136.00, -69.00, 142.40}, +{'l', -75.80, 154.00, 0, 0, 0, 0}, +{'c', -75.80, 154.00, -75.66 ,157.92, -85.80, 154.40}, +{'c', -95.60, 151.00, -105.90 ,138.10, -105.90, 138.10}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', -112.20, 113.60, 0, 0, 0, 0}, +{'c', -112.20, 113.60, -114.20 ,123.20, -77.40, 112.80}, +{'c', -77.40, 112.80, -73.00 ,112.80, -70.60, 113.60}, +{'c', -68.20, 114.40, -56.20 ,117.20, -54.20, 116.00}, +{'c', -54.20, 116.00, -61.40 ,129.60, -73.00, 128.00}, +{'c', -73.00, 128.00, -86.20 ,129.60, -85.80, 134.40}, +{'c', -85.80, 134.40, -81.80 ,141.60, -77.00, 144.00}, +{'c', -77.00, 144.00, -74.20 ,146.40, -74.60, 149.60}, +{'c', -75.00, 152.80, -77.80 ,154.40, -79.80, 155.20}, +{'c', -81.80, 156.00, -85.00 ,152.80, -86.60, 152.80}, +{'c', -88.20, 152.80, -96.60 ,146.40, -101.00, 141.60}, +{'c', -105.40, 136.80, -113.80 ,124.80, -113.40, 122.00}, +{'f', 0.938000,0.603000,0.603000,1.000000,0,0 }, +{'m', -109.00, 131.05, 0, 0, 0, 0}, +{'c', -106.40, 135.00, -103.20 ,139.20, -101.00, 141.60}, +{'c', -96.60, 146.40, -88.20 ,152.80, -86.60, 152.80}, +{'c', -85.00, 152.80, -81.80 ,156.00, -79.80, 155.20}, +{'c', -77.80, 154.40, -75.00 ,152.80, -74.60, 149.60}, +{'c', -74.20, 146.40, -77.00 ,144.00, -77.00, 144.00}, +{'c', -80.07, 142.47, -82.81 ,138.98, -84.39, 136.65}, +{'c', -84.39, 136.65, -84.20 ,139.20, -89.40, 138.40}, +{'c', -94.60, 137.60, -99.80 ,134.80, -101.40, 131.60}, +{'c', -103.00, 128.40, -105.40 ,126.00, -103.80, 129.60}, +{'c', -102.20, 133.20, -99.80 ,136.80, -98.20, 137.20}, +{'c', -96.60, 137.60, -97.00 ,138.80, -99.40, 138.40}, +{'f', 0.737000,0.402000,0.402000,1.000000,0,0 }, +{'m', -111.60, 110.00, 0, 0, 0, 0}, +{'c', -111.60, 110.00, -109.80 ,96.40, -108.60, 92.40}, +{'c', -108.60, 92.40, -109.40 ,85.60, -107.00, 81.40}, +{'c', -104.60, 77.20, -102.60 ,71.00, -99.60, 65.60}, +{'c', -96.60, 60.20, -96.40 ,56.20, -92.40, 54.60}, +{'c', -88.40, 53.00, -82.40 ,44.40, -79.60, 43.40}, +{'c', -76.80, 42.40, -77.00 ,43.20, -77.00, 43.20}, +{'c', -77.00, 43.20, -70.20 ,28.40, -56.60, 32.40}, +{'c', -56.60, 32.40, -72.80 ,29.60, -57.00, 20.20}, +{'c', -57.00, 20.20, -61.80 ,21.30, -58.50, 14.30}, +{'c', -56.30, 9.63, -56.80 ,16.40, -67.80, 28.20}, +{'c', -67.80, 28.20, -72.80 ,36.80, -78.00, 39.80}, +{'c', -83.20, 42.80, -95.20 ,49.80, -96.40, 53.60}, +{'c', -97.60, 57.40, -100.80 ,63.20, -102.80, 64.80}, +{'c', -104.80, 66.40, -107.60 ,70.60, -108.00, 74.00}, +{'c', -108.00, 74.00, -109.20 ,78.00, -110.60, 79.20}, +{'c', -112.00, 80.40, -112.20 ,83.60, -112.20, 85.60}, +{'c', -112.20, 87.60, -114.20 ,90.40, -114.00, 92.80}, +{'c', -114.00, 92.80, -113.20 ,111.80, -113.60, 113.80}, +{'f', 0.603000,0.134000,0.000000,1.000000,0,0 }, +{'m', -120.20, 114.60, 0, 0, 0, 0}, +{'c', -120.20, 114.60, -122.20 ,113.20, -126.60, 119.20}, +{'c', -126.60, 119.20, -119.30 ,152.20, -119.30, 153.60}, +{'c', -119.30, 153.60, -118.20 ,151.50, -119.50, 144.30}, +{'c', -120.80, 137.10, -121.70 ,124.40, -121.70, 124.40}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', -98.60, 54.00, 0, 0, 0, 0}, +{'c', -98.60, 54.00, -116.20 ,57.20, -115.80, 86.40}, +{'l', -116.60, 111.20, 0, 0, 0, 0}, +{'c', -116.60, 111.20, -117.80 ,85.60, -119.00, 84.00}, +{'c', -120.20, 82.40, -116.20 ,71.20, -119.40, 77.20}, +{'c', -119.40, 77.20, -133.40 ,91.20, -125.40, 112.40}, +{'c', -125.40, 112.40, -123.90 ,115.70, -126.90, 111.10}, +{'c', -126.90, 111.10, -131.50 ,98.50, -130.40, 92.10}, +{'c', -130.40, 92.10, -130.20 ,89.90, -128.30, 87.10}, +{'c', -128.30, 87.10, -119.70 ,75.40, -117.00, 73.10}, +{'c', -117.00, 73.10, -115.20 ,58.70, -99.80, 53.50}, +{'f', 0.603000,0.134000,0.000000,1.000000,0,0 }, +{'m', 40.80, -12.20, 0, 0, 0, 0}, +{'c', 41.46, -12.55, 41.45 ,-13.52, 42.03, -13.70}, +{'c', 43.18, -14.04, 43.34 ,-15.11, 43.86, -15.89}, +{'c', 44.73, -17.21, 44.93 ,-18.74, 45.51, -20.23}, +{'c', 45.78, -20.93, 45.81 ,-21.89, 45.50, -22.55}, +{'c', 44.32, -25.03, 43.62 ,-27.48, 42.18, -29.91}, +{'c', 41.91, -30.36, 41.65 ,-31.15, 41.45, -31.75}, +{'c', 40.98, -33.13, 39.73 ,-34.12, 38.87, -35.44}, +{'c', 38.58, -35.88, 39.10 ,-36.81, 38.39, -36.89}, +{'c', 37.49, -37.00, 36.04 ,-37.58, 35.81, -36.55}, +{'c', 35.22, -33.97, 36.23 ,-31.44, 37.20, -29.00}, +{'c', 36.42, -28.31, 36.75 ,-27.39, 36.90, -26.62}, +{'c', 37.61, -23.01, 36.42 ,-19.66, 35.66, -16.19}, +{'c', 35.63, -16.08, 35.97 ,-15.89, 35.95, -15.82}, +{'c', 34.72, -13.14, 33.27 ,-10.69, 31.45, -8.31}, +{'c', 30.70, -7.32, 29.82 ,-6.40, 29.33, -5.34}, +{'c', 28.96, -4.55, 28.55 ,-3.59, 28.80, -2.60}, +{'c', 25.36, 0.18, 23.11 ,4.03, 20.50, 7.87}, +{'c', 20.04, 8.55, 20.33 ,9.76, 20.88, 10.03}, +{'c', 21.70, 10.43, 22.65 ,9.40, 23.12, 8.56}, +{'c', 23.51, 7.86, 23.86 ,7.21, 24.36, 6.57}, +{'c', 24.49, 6.39, 24.31 ,5.97, 24.45, 5.85}, +{'c', 27.08, 3.50, 28.75 ,0.57, 31.20, -1.80}, +{'c', 33.15, -2.13, 34.69 ,-3.13, 36.44, -4.14}, +{'c', 36.74, -4.32, 37.27 ,-4.07, 37.56, -4.26}, +{'c', 39.31, -5.44, 39.31 ,-7.48, 39.41, -9.39}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', 31.96, -16.67, 0, 0, 0, 0}, +{'c', 32.08, -16.74, 31.93 ,-17.17, 32.04, -17.38}, +{'c', 32.20, -17.71, 32.60 ,-17.89, 32.76, -18.22}, +{'c', 32.87, -18.43, 32.71 ,-18.81, 32.85, -18.96}, +{'c', 35.18, -21.40, 35.44 ,-24.43, 34.40, -27.40}, +{'c', 35.42, -28.02, 35.48 ,-29.28, 35.06, -30.13}, +{'c', 34.21, -31.83, 34.01 ,-33.76, 33.04, -35.30}, +{'c', 32.24, -36.57, 30.66 ,-37.81, 29.29, -36.51}, +{'c', 28.87, -36.11, 28.55 ,-35.32, 28.82, -34.61}, +{'c', 28.89, -34.45, 29.17 ,-34.30, 29.15, -34.22}, +{'c', 29.04, -33.89, 28.49 ,-33.67, 28.49, -33.40}, +{'c', 28.46, -31.90, 27.50 ,-30.39, 28.13, -29.06}, +{'c', 28.91, -27.43, 29.72 ,-25.58, 30.40, -23.80}, +{'c', 29.17, -21.68, 30.20 ,-19.23, 28.45, -17.36}, +{'c', 28.31, -17.21, 28.32 ,-16.83, 28.44, -16.62}, +{'c', 28.73, -16.14, 29.14 ,-15.73, 29.62, -15.44}, +{'c', 29.83, -15.32, 30.18 ,-15.32, 30.38, -15.44}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', 94.77, -26.98, 0, 0, 0, 0}, +{'c', 96.16, -25.18, 96.45 ,-22.39, 94.40, -21.00}, +{'c', 94.95, -17.69, 98.30 ,-19.67, 100.40, -20.20}, +{'c', 100.29, -20.59, 100.52 ,-20.93, 100.80, -20.94}, +{'c', 101.86, -20.95, 102.54 ,-21.98, 103.60, -21.80}, +{'c', 104.03, -23.36, 105.67 ,-24.06, 106.32, -25.44}, +{'c', 108.04, -29.13, 107.45 ,-33.41, 104.87, -36.65}, +{'c', 104.67, -36.91, 104.88 ,-37.42, 104.76, -37.79}, +{'c', 104.00, -40.00, 101.94 ,-40.31, 100.00, -41.00}, +{'c', 98.82, -44.88, 98.16 ,-48.91, 96.40, -52.60}, +{'c', 94.79, -52.85, 94.09 ,-54.59, 92.75, -55.31}, +{'c', 91.42, -56.03, 90.85 ,-54.45, 90.89, -53.40}, +{'c', 90.90, -53.20, 91.35 ,-52.97, 91.18, -52.61}, +{'c', 91.11, -52.45, 90.84 ,-52.33, 90.84, -52.20}, +{'c', 90.85, -52.06, 91.07 ,-51.93, 91.20, -51.80}, +{'c', 90.28, -50.98, 88.86 ,-50.50, 88.56, -49.36}, +{'c', 87.61, -45.65, 90.18 ,-42.52, 91.85, -39.32}, +{'c', 92.44, -38.19, 91.71 ,-36.92, 90.95, -35.71}, +{'c', 90.51, -35.01, 90.62 ,-33.89, 90.89, -33.03}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', 57.61, -8.59, 0, 0, 0, 0}, +{'c', 56.12, -6.74, 52.71 ,-4.17, 55.63, -2.24}, +{'c', 55.82, -2.11, 56.19 ,-2.11, 56.37, -2.24}, +{'c', 58.39, -3.81, 60.39 ,-4.71, 62.83, -5.29}, +{'c', 62.95, -5.32, 63.22 ,-4.86, 63.59, -5.02}, +{'c', 65.21, -5.72, 67.22 ,-5.66, 68.40, -7.00}, +{'c', 72.17, -6.78, 75.73 ,-7.89, 79.12, -9.20}, +{'c', 80.28, -9.65, 81.55 ,-10.21, 82.75, -10.71}, +{'c', 84.13, -11.29, 85.33 ,-12.21, 86.45, -13.35}, +{'c', 86.58, -13.49, 86.93 ,-13.40, 87.20, -13.40}, +{'c', 87.16, -14.26, 88.12 ,-14.39, 88.37, -15.01}, +{'c', 88.46, -15.24, 88.31 ,-15.64, 88.44, -15.74}, +{'c', 90.58, -17.37, 91.50 ,-19.39, 90.33, -21.77}, +{'c', 90.05, -22.34, 89.80 ,-22.96, 89.23, -23.44}, +{'c', 88.15, -24.35, 87.05 ,-23.50, 86.00, -23.80}, +{'c', 85.84, -23.17, 85.11 ,-23.34, 84.73, -23.15}, +{'c', 83.87, -22.71, 82.53 ,-23.29, 81.67, -22.85}, +{'c', 80.31, -22.16, 79.07 ,-21.99, 77.65, -21.61}, +{'c', 77.34, -21.53, 76.56 ,-21.63, 76.40, -21.00}, +{'c', 76.27, -21.13, 76.12 ,-21.37, 76.01, -21.35}, +{'c', 74.10, -20.95, 72.84 ,-20.74, 71.54, -19.04}, +{'c', 71.44, -18.91, 71.00 ,-19.09, 70.84, -18.95}, +{'c', 69.88, -18.15, 69.48 ,-16.91, 68.38, -16.24}, +{'c', 68.17, -16.12, 67.82 ,-16.29, 67.63, -16.16}, +{'c', 66.98, -15.73, 66.62 ,-15.09, 65.97, -14.64}, +{'c', 65.64, -14.41, 65.25 ,-14.73, 65.28, -14.99}, +{'c', 65.52, -16.94, 66.17 ,-18.72, 65.60, -20.60}, +{'c', 67.68, -23.12, 70.19 ,-25.07, 72.00, -27.80}, +{'c', 72.02, -29.97, 72.71 ,-32.11, 72.59, -34.19}, +{'c', 72.58, -34.38, 72.30 ,-35.12, 72.17, -35.46}, +{'c', 71.86, -36.32, 72.76 ,-37.38, 71.92, -38.11}, +{'c', 70.52, -39.31, 69.22 ,-38.43, 68.40, -37.00}, +{'c', 66.56, -36.61, 64.50 ,-35.92, 62.92, -37.15}, +{'c', 61.91, -37.94, 61.33 ,-38.84, 60.53, -39.90}, +{'c', 59.55, -41.20, 59.88 ,-42.64, 59.95, -44.20}, +{'c', 59.96, -44.33, 59.65 ,-44.47, 59.65, -44.60}, +{'c', 59.65, -44.73, 59.87 ,-44.87, 60.00, -45.00}, +{'c', 59.29, -45.63, 59.02 ,-46.68, 58.00, -47.00}, +{'c', 58.30, -48.09, 57.63 ,-48.98, 56.76, -49.28}, +{'c', 54.76, -49.97, 53.09 ,-48.06, 51.19, -47.98}, +{'c', 50.68, -47.97, 50.21 ,-49.00, 49.56, -49.33}, +{'c', 49.13, -49.54, 48.43 ,-49.58, 48.07, -49.31}, +{'c', 47.38, -48.81, 46.79 ,-48.69, 46.03, -48.49}, +{'c', 44.41, -48.05, 43.14 ,-46.96, 41.66, -46.10}, +{'c', 40.17, -45.25, 39.22 ,-43.81, 38.14, -42.49}, +{'c', 37.20, -41.34, 37.06 ,-38.92, 38.48, -38.42}, +{'c', 40.32, -37.77, 41.63 ,-40.48, 43.59, -40.15}, +{'c', 43.90, -40.10, 44.11 ,-39.79, 44.00, -39.40}, +{'c', 44.39, -39.29, 44.61 ,-39.52, 44.80, -39.80}, +{'c', 45.66, -38.78, 46.82 ,-38.44, 47.76, -37.57}, +{'c', 48.73, -36.67, 50.48 ,-37.09, 51.49, -36.09}, +{'c', 53.02, -34.59, 52.46 ,-31.91, 54.40, -30.60}, +{'c', 53.81, -29.29, 53.21 ,-28.01, 52.87, -26.58}, +{'c', 52.59, -25.38, 53.58 ,-24.18, 54.80, -24.27}, +{'c', 56.05, -24.36, 56.31 ,-25.12, 56.80, -26.20}, +{'c', 57.07, -25.93, 57.54 ,-25.64, 57.49, -25.42}, +{'c', 57.04, -23.03, 56.01 ,-21.04, 55.55, -18.61}, +{'c', 55.49, -18.29, 55.19 ,-18.09, 54.80, -18.20}, +{'c', 54.33, -14.05, 50.28 ,-11.66, 47.73, -8.49}, +{'c', 47.33, -7.99, 47.33 ,-6.74, 47.74, -6.34}, +{'c', 49.14, -4.95, 51.10 ,-6.50, 52.80, -7.00}, +{'c', 53.01, -8.21, 53.87 ,-9.15, 55.20, -9.09}, +{'c', 55.46, -9.08, 55.70 ,-9.62, 56.02, -9.75}, +{'c', 56.37, -9.89, 56.87 ,-9.67, 57.16, -9.87}, +{'c', 58.88, -11.06, 60.29 ,-12.17, 62.03, -13.36}, +{'c', 62.22, -13.49, 62.57 ,-13.33, 62.78, -13.44}, +{'c', 63.11, -13.60, 63.29 ,-13.98, 63.62, -14.17}, +{'c', 63.97, -14.37, 64.21 ,-14.08, 64.40, -13.80}, +{'c', 63.75, -13.45, 63.75 ,-12.49, 63.17, -12.29}, +{'c', 62.39, -12.02, 61.83 ,-11.51, 61.16, -11.06}, +{'c', 60.87, -10.87, 60.21 ,-11.12, 60.10, -10.94}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', 2.20, -58.00, 0, 0, 0, 0}, +{'c', 2.20, -58.00, -7.04 ,-60.87, -18.20, -35.20}, +{'c', -18.20, -35.20, -20.60 ,-30.00, -23.00, -28.00}, +{'c', -25.40, -26.00, -36.60 ,-22.40, -38.60, -18.40}, +{'l', -49.00, -2.40, 0, 0, 0, 0}, +{'c', -49.00, -2.40, -34.20 ,-18.40, -31.00, -20.80}, +{'c', -31.00, -20.80, -23.00 ,-29.20, -26.20, -22.40}, +{'c', -26.20, -22.40, -40.20 ,-11.60, -39.00, -2.40}, +{'c', -39.00, -2.40, -44.60 ,12.00, -45.40, 14.00}, +{'c', -45.40, 14.00, -29.40 ,-18.00, -27.00, -19.20}, +{'c', -24.60, -20.40, -23.40 ,-20.40, -24.60, -16.80}, +{'c', -25.80, -13.20, -26.20 ,3.20, -29.00, 5.20}, +{'c', -29.00, 5.20, -21.00 ,-15.20, -21.80, -18.40}, +{'c', -21.80, -18.40, -18.60 ,-22.00, -16.20, -16.80}, +{'l', -17.40, -0.80, 0, 0, 0, 0}, +{'l', -13.00, 11.20, 0, 0, 0, 0}, +{'c', -13.00, 11.20, -15.40 ,0.00, -13.80, -15.60}, +{'c', -13.80, -15.60, -15.80 ,-26.00, -11.80, -20.40}, +{'c', -7.80, -14.80, 1.80 ,-8.80, 1.80, -4.00}, +{'c', 1.80, -4.00, -3.40 ,-21.60, -12.60, -26.40}, +{'l', -16.60, -20.40, 0, 0, 0, 0}, +{'l', -17.80, -22.40, 0, 0, 0, 0}, +{'c', -17.80, -22.40, -21.40 ,-23.20, -17.00, -30.00}, +{'c', -12.60, -36.80, -13.00 ,-37.60, -13.00, -37.60}, +{'c', -13.00, -37.60, -6.60 ,-30.40, -5.00, -30.40}, +{'c', -5.00, -30.40, 8.20 ,-38.00, 9.40, -13.60}, +{'c', 9.40, -13.60, 16.20 ,-28.00, 7.00, -34.80}, +{'c', 7.00, -34.80, -7.80 ,-36.80, -6.60, -42.00}, +{'l', 0.60, -54.40, 0, 0, 0, 0}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', -17.80, -41.60, 0, 0, 0, 0}, +{'c', -17.80, -41.60, -30.60 ,-41.60, -33.80, -36.40}, +{'l', -41.00, -26.80, 0, 0, 0, 0}, +{'c', -41.00, -26.80, -23.80 ,-36.80, -19.80, -38.00}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', -57.80, -35.20, 0, 0, 0, 0}, +{'c', -57.80, -35.20, -59.80 ,-34.00, -60.20, -31.20}, +{'c', -60.60, -28.40, -63.00 ,-28.00, -62.20, -25.20}, +{'c', -61.40, -22.40, -59.40 ,-20.00, -59.40, -24.00}, +{'c', -59.40, -28.00, -57.80 ,-30.00, -57.00, -31.20}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', -66.60, 26.00, 0, 0, 0, 0}, +{'c', -66.60, 26.00, -75.00 ,22.00, -78.20, 18.40}, +{'c', -81.40, 14.80, -80.95 ,19.97, -85.80, 19.60}, +{'c', -91.65, 19.16, -90.60 ,3.20, -90.60, 3.20}, +{'l', -94.60, 10.80, 0, 0, 0, 0}, +{'c', -94.60, 10.80, -95.80 ,25.20, -87.80, 22.80}, +{'c', -83.89, 21.63, -82.60 ,23.20, -84.20, 24.00}, +{'c', -85.80, 24.80, -78.60 ,25.20, -81.40, 26.80}, +{'c', -84.20, 28.40, -69.80 ,23.20, -72.20, 33.60}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', -79.20, 40.40, 0, 0, 0, 0}, +{'c', -79.20, 40.40, -94.60 ,44.80, -98.20, 35.20}, +{'c', -98.20, 35.20, -103.00 ,37.60, -100.80, 40.60}, +{'c', -98.60, 43.60, -97.40 ,44.00, -97.40, 44.00}, +{'c', -97.40, 44.00, -92.00 ,45.20, -92.60, 46.00}, +{'c', -93.20, 46.80, -95.60 ,50.20, -95.60, 50.20}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', 149.20, 118.60, 0, 0, 0, 0}, +{'c', 148.77, 120.73, 147.10 ,121.54, 145.20, 122.20}, +{'c', 143.28, 121.24, 140.69 ,118.14, 138.80, 120.20}, +{'c', 138.33, 119.72, 137.55 ,119.66, 137.20, 119.00}, +{'c', 136.74, 118.10, 137.01 ,117.06, 136.67, 116.26}, +{'c', 136.12, 114.98, 135.41 ,113.62, 135.60, 112.20}, +{'c', 137.41, 111.49, 138.00 ,109.58, 137.53, 107.82}, +{'c', 137.46, 107.56, 137.03 ,107.37, 137.23, 107.02}, +{'c', 137.42, 106.69, 137.73 ,106.47, 138.00, 106.20}, +{'c', 137.87, 106.33, 137.72 ,106.57, 137.61, 106.55}, +{'c', 137.00, 106.44, 137.12 ,105.81, 137.25, 105.42}, +{'c', 137.84, 103.67, 139.85 ,103.41, 141.20, 104.60}, +{'c', 141.46, 104.03, 141.97 ,104.23, 142.40, 104.20}, +{'c', 142.35, 103.62, 142.76 ,103.09, 142.96, 102.67}, +{'c', 143.47, 101.58, 145.10 ,102.68, 145.90, 102.07}, +{'c', 146.98, 101.25, 148.04 ,100.55, 149.12, 101.15}, +{'c', 150.93, 102.16, 152.64 ,103.37, 153.84, 105.11}, +{'c', 154.41, 105.95, 154.65 ,107.23, 154.59, 108.19}, +{'c', 154.55, 108.83, 153.17 ,108.48, 152.83, 109.41}, +{'c', 152.19, 111.16, 154.02 ,111.68, 154.77, 113.02}, +{'c', 154.97, 113.37, 154.71 ,113.67, 154.39, 113.77}, +{'c', 153.98, 113.90, 153.20 ,113.71, 153.33, 114.16}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', 139.60, 138.20, 0, 0, 0, 0}, +{'c', 139.59, 136.46, 137.99 ,134.71, 139.20, 133.00}, +{'c', 139.34, 133.13, 139.47 ,133.36, 139.60, 133.36}, +{'c', 139.74, 133.36, 139.87 ,133.13, 140.00, 133.00}, +{'c', 141.50, 135.22, 145.15 ,136.15, 145.01, 138.99}, +{'c', 144.98, 139.44, 143.90 ,140.36, 144.80, 141.00}, +{'c', 142.99, 142.35, 142.93 ,144.72, 142.00, 146.60}, +{'c', 140.76, 146.31, 139.55 ,145.95, 138.40, 145.40}, +{'c', 138.75, 143.91, 138.64 ,142.23, 139.46, 140.91}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', -26.60, 129.20, 0, 0, 0, 0}, +{'c', -26.60, 129.20, -43.46 ,139.34, -29.40, 124.00}, +{'c', -20.60, 114.40, -10.60 ,108.80, -10.60, 108.80}, +{'c', -10.60, 108.80, -0.20 ,104.40, 3.40, 103.20}, +{'c', 7.00, 102.00, 22.20 ,96.80, 25.40, 96.40}, +{'c', 28.60, 96.00, 38.20 ,92.00, 45.00, 96.00}, +{'c', 51.80, 100.00, 59.80 ,104.40, 59.80, 104.40}, +{'c', 59.80, 104.40, 43.40 ,96.00, 39.80, 98.40}, +{'c', 36.20, 100.80, 29.00 ,100.40, 23.00, 103.60}, +{'c', 23.00, 103.60, 8.20 ,108.00, 5.00, 110.00}, +{'c', 1.80, 112.00, -8.60 ,123.60, -10.20, 122.80}, +{'c', -11.80, 122.00, -9.80 ,121.60, -8.60, 118.80}, +{'c', -7.40, 116.00, -9.40 ,114.40, -17.40, 120.80}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', -19.20, 123.23, 0, 0, 0, 0}, +{'c', -19.20, 123.23, -17.79 ,110.19, -9.31, 111.86}, +{'c', -9.31, 111.86, -1.08 ,107.69, 1.64, 105.72}, +{'c', 1.64, 105.72, 9.78 ,104.02, 11.09, 103.40}, +{'c', 29.57, 94.70, 44.29 ,99.22, 44.84, 98.10}, +{'c', 45.38, 96.98, 65.01 ,104.10, 68.61, 108.19}, +{'c', 69.01, 108.63, 58.38 ,102.59, 48.69, 100.70}, +{'c', 40.41, 99.08, 18.81 ,100.94, 7.91, 106.48}, +{'c', 4.93, 107.99, -4.01 ,113.77, -6.54, 113.66}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', -23.00, 148.80, 0, 0, 0, 0}, +{'c', -23.00, 148.80, -38.20 ,146.40, -21.40, 144.80}, +{'c', -21.40, 144.80, -3.40 ,142.80, 0.60, 137.60}, +{'c', 0.60, 137.60, 14.20 ,128.40, 17.00, 128.00}, +{'c', 19.80, 127.60, 49.80 ,120.40, 50.20, 118.00}, +{'c', 50.60, 115.60, 56.20 ,115.60, 57.80, 116.40}, +{'c', 59.40, 117.20, 58.60 ,118.40, 55.80, 119.20}, +{'c', 53.00, 120.00, 21.80 ,136.40, 15.40, 137.60}, +{'c', 9.00, 138.80, -2.60 ,146.40, -7.40, 147.60}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', -3.48, 141.40, 0, 0, 0, 0}, +{'c', -3.48, 141.40, -12.06 ,140.57, -3.46, 139.75}, +{'c', -3.46, 139.75, 5.36 ,136.33, 7.40, 133.67}, +{'c', 7.40, 133.67, 14.37 ,128.96, 15.80, 128.75}, +{'c', 17.23, 128.55, 31.19 ,124.86, 31.40, 123.63}, +{'c', 31.60, 122.40, 65.67 ,109.82, 70.09, 113.01}, +{'c', 73.00, 115.11, 63.10 ,113.44, 53.47, 117.85}, +{'c', 52.11, 118.47, 18.26 ,133.05, 14.98, 133.67}, +{'c', 11.70, 134.28, 5.76 ,138.17, 3.31, 138.79}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', -11.40, 143.60, 0, 0, 0, 0}, +{'c', -11.40, 143.60, -6.20 ,143.20, -7.40, 144.80}, +{'c', -8.60, 146.40, -11.00 ,145.60, -11.00, 145.60}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', -18.60, 145.20, 0, 0, 0, 0}, +{'c', -18.60, 145.20, -13.40 ,144.80, -14.60, 146.40}, +{'c', -15.80, 148.00, -18.20 ,147.20, -18.20, 147.20}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', -29.00, 146.80, 0, 0, 0, 0}, +{'c', -29.00, 146.80, -23.80 ,146.40, -25.00, 148.00}, +{'c', -26.20, 149.60, -28.60 ,148.80, -28.60, 148.80}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', -36.60, 147.60, 0, 0, 0, 0}, +{'c', -36.60, 147.60, -31.40 ,147.20, -32.60, 148.80}, +{'c', -33.80, 150.40, -36.20 ,149.60, -36.20, 149.60}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', 1.80, 108.00, 0, 0, 0, 0}, +{'c', 1.80, 108.00, 6.20 ,108.00, 5.00, 109.60}, +{'c', 3.80, 111.20, 0.60 ,110.80, 0.60, 110.80}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', -8.20, 113.60, 0, 0, 0, 0}, +{'c', -8.20, 113.60, -1.69 ,111.46, -4.20, 114.80}, +{'c', -5.40, 116.40, -7.80 ,115.60, -7.80, 115.60}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', -19.40, 118.40, 0, 0, 0, 0}, +{'c', -19.40, 118.40, -14.20 ,118.00, -15.40, 119.60}, +{'c', -16.60, 121.20, -19.00 ,120.40, -19.00, 120.40}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', -27.00, 124.40, 0, 0, 0, 0}, +{'c', -27.00, 124.40, -21.80 ,124.00, -23.00, 125.60}, +{'c', -24.20, 127.20, -26.60 ,126.40, -26.60, 126.40}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', -33.80, 129.20, 0, 0, 0, 0}, +{'c', -33.80, 129.20, -28.60 ,128.80, -29.80, 130.40}, +{'c', -31.00, 132.00, -33.40 ,131.20, -33.40, 131.20}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', 5.28, 135.60, 0, 0, 0, 0}, +{'c', 5.28, 135.60, 12.20 ,135.07, 10.61, 137.19}, +{'c', 9.01, 139.32, 5.81 ,138.26, 5.81, 138.26}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', 15.68, 130.80, 0, 0, 0, 0}, +{'c', 15.68, 130.80, 22.60 ,130.27, 21.01, 132.40}, +{'c', 19.41, 134.53, 16.21 ,133.46, 16.21, 133.46}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', 26.48, 126.40, 0, 0, 0, 0}, +{'c', 26.48, 126.40, 33.40 ,125.87, 31.81, 128.00}, +{'c', 30.21, 130.12, 27.01 ,129.06, 27.01, 129.06}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', 36.88, 121.60, 0, 0, 0, 0}, +{'c', 36.88, 121.60, 43.80 ,121.07, 42.21, 123.19}, +{'c', 40.61, 125.33, 37.41 ,124.26, 37.41, 124.26}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', 9.28, 103.60, 0, 0, 0, 0}, +{'c', 9.28, 103.60, 16.20 ,103.07, 14.61, 105.19}, +{'c', 13.01, 107.33, 9.01 ,107.06, 9.01, 107.06}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', 19.28, 100.40, 0, 0, 0, 0}, +{'c', 19.28, 100.40, 26.20 ,99.87, 24.61, 102.00}, +{'c', 23.01, 104.12, 18.61 ,103.86, 18.61, 103.86}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', -3.40, 140.40, 0, 0, 0, 0}, +{'c', -3.40, 140.40, 1.80 ,140.00, 0.60, 141.60}, +{'c', -0.60, 143.20, -3.00 ,142.40, -3.00, 142.40}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', -76.60, 41.20, 0, 0, 0, 0}, +{'c', -76.60, 41.20, -81.00 ,50.00, -81.40, 53.20}, +{'c', -81.40, 53.20, -80.60 ,44.40, -79.40, 42.40}, +{'f', 0.603000,0.134000,0.000000,1.000000,0,0 }, +{'m', -95.00, 55.20, 0, 0, 0, 0}, +{'c', -95.00, 55.20, -98.20 ,69.60, -97.80, 72.40}, +{'c', -97.80, 72.40, -99.00 ,60.80, -98.60, 59.60}, +{'f', 0.603000,0.134000,0.000000,1.000000,0,0 }, +{'m', -74.20, -19.40, 0, 0, 0, 0}, +{'l', -74.40, -16.20, 0, 0, 0, 0}, +{'l', -76.60, -16.00, 0, 0, 0, 0}, +{'c', -76.60, -16.00, -62.40 ,-3.40, -61.80, 4.20}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', -70.22, -18.14, 0, 0, 0, 0}, +{'c', -70.65, -18.55, -70.43 ,-19.30, -70.84, -19.56}, +{'c', -71.64, -20.07, -69.54 ,-20.13, -69.77, -20.84}, +{'c', -70.15, -22.05, -69.96 ,-22.07, -70.08, -23.35}, +{'c', -70.14, -23.95, -69.55 ,-25.49, -69.17, -25.93}, +{'c', -67.72, -27.58, -69.05 ,-30.51, -67.41, -32.06}, +{'c', -67.10, -32.35, -66.73 ,-32.90, -66.44, -33.32}, +{'c', -65.78, -34.28, -64.60 ,-34.77, -63.65, -35.60}, +{'c', -63.33, -35.88, -63.53 ,-36.70, -62.96, -36.61}, +{'c', -62.25, -36.49, -61.01 ,-36.62, -61.05, -35.78}, +{'c', -61.16, -33.66, -62.49 ,-31.94, -63.77, -30.28}, +{'c', -63.32, -29.57, -63.78 ,-28.94, -64.06, -28.38}, +{'c', -65.40, -25.76, -65.21 ,-22.92, -65.39, -20.08}, +{'c', -65.39, -19.99, -65.70 ,-19.92, -65.69, -19.86}, +{'c', -65.34, -17.53, -64.75 ,-15.33, -63.87, -13.10}, +{'c', -63.51, -12.17, -63.04 ,-11.28, -62.89, -10.35}, +{'c', -62.77, -9.66, -62.67 ,-8.83, -63.08, -8.12}, +{'c', -61.05, -5.23, -62.35 ,-2.58, -61.19, 0.95}, +{'c', -60.98, 1.57, -59.29 ,3.49, -59.75, 3.33}, +{'c', -62.26, 2.46, -62.37 ,2.06, -62.55, 1.30}, +{'c', -62.70, 0.68, -63.03 ,-0.70, -63.26, -1.30}, +{'c', -63.33, -1.46, -63.50 ,-3.35, -63.58, -3.47}, +{'c', -65.09, -5.85, -63.73 ,-5.67, -65.10, -8.03}, +{'c', -66.53, -8.71, -67.50 ,-9.82, -68.62, -10.98}, +{'c', -68.82, -11.18, -67.67 ,-11.91, -67.86, -12.12}, +{'c', -68.95, -13.41, -70.10 ,-14.18, -69.76, -15.67}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', -73.80, -16.40, 0, 0, 0, 0}, +{'c', -73.80, -16.40, -73.40 ,-9.60, -71.00, -8.00}, +{'c', -68.60, -6.40, -69.80 ,-7.20, -73.00, -8.40}, +{'c', -76.20, -9.60, -75.00 ,-10.40, -75.00, -10.40}, +{'c', -75.00, -10.40, -77.80 ,-10.00, -75.40, -8.00}, +{'c', -73.00, -6.00, -69.40 ,-3.60, -71.00, -3.60}, +{'c', -72.60, -3.60, -80.20 ,-7.60, -80.20, -10.40}, +{'c', -80.20, -13.20, -81.20 ,-17.30, -81.20, -17.30}, +{'c', -81.20, -17.30, -80.10 ,-18.10, -75.30, -18.00}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', -74.60, 2.20, 0, 0, 0, 0}, +{'c', -74.60, 2.20, -83.12 ,-0.59, -101.60, 2.80}, +{'c', -101.60, 2.80, -92.57 ,0.72, -73.80, 3.00}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', -72.50, 2.13, 0, 0, 0, 0}, +{'c', -72.50, 2.13, -80.75 ,-1.39, -99.45, 0.39}, +{'c', -99.45, 0.39, -90.28 ,-0.90, -71.77, 3.00}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', -70.71, 2.22, 0, 0, 0, 0}, +{'c', -70.71, 2.22, -78.68 ,-1.90, -97.46, -1.51}, +{'c', -97.46, -1.51, -88.21 ,-2.12, -70.05, 3.14}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', -69.44, 2.44, 0, 0, 0, 0}, +{'c', -69.44, 2.44, -76.27 ,-1.86, -93.14, -2.96}, +{'c', -93.14, -2.96, -84.80 ,-2.79, -68.92, 3.32}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', 45.84, 12.96, 0, 0, 0, 0}, +{'c', 45.84, 12.96, 44.91 ,13.61, 45.12, 12.42}, +{'c', 45.34, 11.24, 73.55 ,-1.93, 77.16, -1.68}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', 42.45, 13.60, 0, 0, 0, 0}, +{'c', 42.45, 13.60, 41.57 ,14.31, 41.69, 13.12}, +{'c', 41.81, 11.93, 68.90 ,-3.42, 72.52, -3.45}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', 39.16, 14.97, 0, 0, 0, 0}, +{'c', 39.16, 14.97, 38.33 ,15.75, 38.37, 14.55}, +{'c', 38.42, 13.35, 58.23 ,-2.15, 68.05, -4.02}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', 36.28, 16.84, 0, 0, 0, 0}, +{'c', 36.28, 16.84, 35.54 ,17.53, 35.58, 16.45}, +{'c', 35.62, 15.37, 53.45 ,1.43, 62.28, -0.26}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', 4.60, 164.80, 0, 0, 0, 0}, +{'c', 4.60, 164.80, -10.60 ,162.40, 6.20, 160.80}, +{'c', 6.20, 160.80, 24.20 ,158.80, 28.20, 153.60}, +{'c', 28.20, 153.60, 41.80 ,144.40, 44.60, 144.00}, +{'c', 47.40, 143.60, 63.80 ,140.00, 64.20, 137.60}, +{'c', 64.60, 135.20, 70.60 ,132.80, 72.20, 133.60}, +{'c', 73.80, 134.40, 73.80 ,143.60, 71.00, 144.40}, +{'c', 68.20, 145.20, 49.40 ,152.40, 43.00, 153.60}, +{'c', 36.60, 154.80, 25.00 ,162.40, 20.20, 163.60}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', 77.60, 127.40, 0, 0, 0, 0}, +{'c', 77.60, 127.40, 74.60 ,129.00, 73.40, 131.60}, +{'c', 73.40, 131.60, 67.00 ,142.20, 52.80, 145.40}, +{'c', 52.80, 145.40, 29.80 ,154.40, 22.00, 156.40}, +{'c', 22.00, 156.40, 8.60 ,161.40, 1.20, 160.60}, +{'c', 1.20, 160.60, -5.80 ,160.80, 0.40, 162.40}, +{'c', 0.40, 162.40, 20.60 ,160.40, 24.00, 158.60}, +{'c', 24.00, 158.60, 39.60 ,153.40, 42.60, 150.80}, +{'c', 45.60, 148.20, 63.80 ,143.20, 66.00, 141.20}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', 18.88, 158.91, 0, 0, 0, 0}, +{'c', 18.88, 158.91, 24.11 ,158.69, 22.96, 160.23}, +{'c', 21.80, 161.78, 19.36 ,160.91, 19.36, 160.91}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', 11.68, 160.26, 0, 0, 0, 0}, +{'c', 11.68, 160.26, 16.91 ,160.04, 15.76, 161.59}, +{'c', 14.60, 163.14, 12.15 ,162.26, 12.15, 162.26}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', 1.25, 161.51, 0, 0, 0, 0}, +{'c', 1.25, 161.51, 6.48 ,161.28, 5.33, 162.83}, +{'c', 4.17, 164.38, 1.73 ,163.51, 1.73, 163.51}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', -6.38, 162.06, 0, 0, 0, 0}, +{'c', -6.38, 162.06, -1.15 ,161.83, -2.31, 163.38}, +{'c', -3.46, 164.93, -5.91 ,164.05, -5.91, 164.05}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', 35.41, 151.51, 0, 0, 0, 0}, +{'c', 35.41, 151.51, 42.38 ,151.21, 40.84, 153.27}, +{'c', 39.31, 155.34, 36.05 ,154.17, 36.05, 154.17}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', 45.73, 147.09, 0, 0, 0, 0}, +{'c', 45.73, 147.09, 51.69 ,143.79, 51.16, 148.85}, +{'c', 50.88, 151.41, 46.36 ,149.75, 46.36, 149.75}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', 54.86, 144.27, 0, 0, 0, 0}, +{'c', 54.86, 144.27, 62.02 ,140.57, 60.29, 146.03}, +{'c', 59.51, 148.49, 55.49 ,146.94, 55.49, 146.94}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', 64.38, 139.45, 0, 0, 0, 0}, +{'c', 64.38, 139.45, 68.73 ,134.55, 69.80, 141.21}, +{'c', 70.21, 143.75, 65.01 ,142.11, 65.01, 142.11}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', 26.83, 156.00, 0, 0, 0, 0}, +{'c', 26.83, 156.00, 32.06 ,155.77, 30.91, 157.32}, +{'c', 29.76, 158.87, 27.31 ,158.00, 27.31, 158.00}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', 62.43, 34.60, 0, 0, 0, 0}, +{'c', 62.43, 34.60, 61.71 ,35.27, 61.71, 34.20}, +{'c', 61.71, 33.13, 79.19 ,19.86, 88.03, 18.48}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', 65.40, 98.40, 0, 0, 0, 0}, +{'c', 65.40, 98.40, 87.40 ,120.80, 96.60, 124.40}, +{'c', 96.60, 124.40, 105.80 ,135.60, 101.80, 161.60}, +{'c', 101.80, 161.60, 98.60 ,169.20, 95.40, 148.40}, +{'c', 95.40, 148.40, 98.60 ,123.20, 87.40, 139.20}, +{'c', 87.40, 139.20, 79.00 ,129.30, 85.40, 129.60}, +{'c', 85.40, 129.60, 88.60 ,131.60, 89.00, 130.00}, +{'c', 89.40, 128.40, 81.40 ,114.80, 64.20, 100.40}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', 7.00, 137.20, 0, 0, 0, 0}, +{'c', 7.00, 137.20, 6.80 ,135.40, 8.60, 136.20}, +{'c', 10.40, 137.00, 104.60 ,143.20, 136.20, 167.20}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', 17.40, 132.80, 0, 0, 0, 0}, +{'c', 17.40, 132.80, 17.20 ,131.00, 19.00, 131.80}, +{'c', 20.80, 132.60, 157.40 ,131.60, 181.00, 164.00}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', 29.00, 128.80, 0, 0, 0, 0}, +{'c', 29.00, 128.80, 28.80 ,127.00, 30.60, 127.80}, +{'c', 32.40, 128.60, 205.80 ,115.60, 229.40, 148.00}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', 39.00, 124.00, 0, 0, 0, 0}, +{'c', 39.00, 124.00, 38.80 ,122.20, 40.60, 123.00}, +{'c', 42.40, 123.80, 164.60 ,85.20, 188.20, 117.60}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', -19.00, 146.80, 0, 0, 0, 0}, +{'c', -19.00, 146.80, -19.20 ,145.00, -17.40, 145.80}, +{'c', -15.60, 146.60, 2.20 ,148.80, 4.20, 187.60}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', -27.80, 148.40, 0, 0, 0, 0}, +{'c', -27.80, 148.40, -28.00 ,146.60, -26.20, 147.40}, +{'c', -24.40, 148.20, -10.20 ,143.60, -13.00, 182.40}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', -35.80, 148.80, 0, 0, 0, 0}, +{'c', -35.80, 148.80, -36.00 ,147.00, -34.20, 147.80}, +{'c', -32.40, 148.60, -17.00 ,149.20, -29.40, 171.60}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', 11.53, 104.47, 0, 0, 0, 0}, +{'c', 11.53, 104.47, 11.08 ,106.46, 12.63, 105.25}, +{'c', 28.70, 92.62, 61.14 ,33.72, 116.83, 28.09}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', 22.73, 102.67, 0, 0, 0, 0}, +{'c', 22.73, 102.67, 21.36 ,101.47, 23.23, 100.85}, +{'c', 25.10, 100.22, 137.54 ,27.72, 176.83, 35.69}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', 1.89, 108.77, 0, 0, 0, 0}, +{'c', 1.89, 108.77, 1.38 ,110.37, 3.09, 109.39}, +{'c', 12.06, 104.27, 15.68 ,47.06, 59.25, 45.80}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', -18.04, 119.79, 0, 0, 0, 0}, +{'c', -18.04, 119.79, -19.11 ,121.08, -17.16, 120.83}, +{'c', -6.92, 119.49, 14.49 ,78.22, 58.93, 83.30}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', -6.80, 113.67, 0, 0, 0, 0}, +{'c', -6.80, 113.67, -7.61 ,115.14, -5.74, 114.51}, +{'c', 4.06, 111.24, 17.14 ,66.62, 61.73, 63.08}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', -25.08, 124.91, 0, 0, 0, 0}, +{'c', -25.08, 124.91, -25.95 ,125.95, -24.37, 125.75}, +{'c', -16.07, 124.67, 1.27 ,91.24, 37.26, 95.35}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', -32.68, 130.82, 0, 0, 0, 0}, +{'c', -32.68, 130.82, -33.68 ,131.87, -32.09, 131.75}, +{'c', -27.92, 131.44, 2.71 ,98.36, 21.18, 113.86}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', 36.85, 98.90, 0, 0, 0, 0}, +{'c', 36.85, 98.90, 35.65 ,97.54, 37.59, 97.16}, +{'c', 39.52, 96.77, 160.22 ,39.06, 198.18, 51.93}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', 3.40, 163.20, 0, 0, 0, 0}, +{'c', 3.40, 163.20, 3.20 ,161.40, 5.00, 162.20}, +{'c', 6.80, 163.00, 22.20 ,163.60, 9.80, 186.00}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', 13.80, 161.60, 0, 0, 0, 0}, +{'c', 13.80, 161.60, 13.60 ,159.80, 15.40, 160.60}, +{'c', 17.20, 161.40, 35.00 ,163.60, 37.00, 202.40}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', 20.60, 160.00, 0, 0, 0, 0}, +{'c', 20.60, 160.00, 20.40 ,158.20, 22.20, 159.00}, +{'c', 24.00, 159.80, 48.60 ,163.20, 72.20, 195.60}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', 28.23, 157.97, 0, 0, 0, 0}, +{'c', 28.23, 157.97, 27.79 ,156.21, 29.68, 156.77}, +{'c', 31.57, 157.32, 52.00 ,155.42, 90.10, 189.60}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', 38.62, 153.57, 0, 0, 0, 0}, +{'c', 38.62, 153.57, 38.19 ,151.81, 40.08, 152.37}, +{'c', 41.97, 152.92, 76.80 ,157.42, 128.50, 192.40}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', -1.80, 142.00, 0, 0, 0, 0}, +{'c', -1.80, 142.00, -2.00 ,140.20, -0.20, 141.00}, +{'c', 1.60, 141.80, 55.00 ,144.40, 85.40, 171.20}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', -11.80, 146.00, 0, 0, 0, 0}, +{'c', -11.80, 146.00, -12.00 ,144.20, -10.20, 145.00}, +{'c', -8.40, 145.80, 16.20 ,149.20, 39.80, 181.60}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', 49.50, 148.96, 0, 0, 0, 0}, +{'c', 49.50, 148.96, 48.94 ,147.24, 50.86, 147.66}, +{'c', 52.79, 148.07, 87.86 ,150.00, 141.98, 181.10}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', 57.90, 146.56, 0, 0, 0, 0}, +{'c', 57.90, 146.56, 57.34 ,144.84, 59.26, 145.25}, +{'c', 61.19, 145.67, 96.26 ,147.60, 150.38, 178.70}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', 67.50, 141.56, 0, 0, 0, 0}, +{'c', 67.50, 141.56, 66.94 ,139.84, 68.86, 140.25}, +{'c', 70.79, 140.67, 113.86 ,145.00, 203.58, 179.30}, +{'f', 1.000000,1.000000,1.000000,1.000000,0,0 }, +{'m', -43.80, 148.40, 0, 0, 0, 0}, +{'c', -43.80, 148.40, -38.60 ,148.00, -39.80, 149.60}, +{'c', -41.00, 151.20, -43.40 ,150.40, -43.40, 150.40}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', -13.00, 162.40, 0, 0, 0, 0}, +{'c', -13.00, 162.40, -7.80 ,162.00, -9.00, 163.60}, +{'c', -10.20, 165.20, -12.60 ,164.40, -12.60, 164.40}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', -21.80, 162.00, 0, 0, 0, 0}, +{'c', -21.80, 162.00, -16.60 ,161.60, -17.80, 163.20}, +{'c', -19.00, 164.80, -21.40 ,164.00, -21.40, 164.00}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', -117.17, 150.18, 0, 0, 0, 0}, +{'c', -117.17, 150.18, -112.12 ,151.50, -113.78, 152.62}, +{'c', -115.44, 153.74, -117.45 ,152.20, -117.45, 152.20}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', -115.17, 140.58, 0, 0, 0, 0}, +{'c', -115.17, 140.58, -110.12 ,141.91, -111.78, 143.02}, +{'c', -113.44, 144.14, -115.45 ,142.60, -115.45, 142.60}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', -122.37, 136.18, 0, 0, 0, 0}, +{'c', -122.37, 136.18, -117.32 ,137.50, -118.98, 138.62}, +{'c', -120.64, 139.74, -122.65 ,138.20, -122.65, 138.20}, +{'f', 0.000000,0.000000,0.000000,1.000000,0,0 }, +{'m', -42.60, 211.20, 0, 0, 0, 0}, +{'c', -42.60, 211.20, -44.20 ,211.20, -48.20, 213.20}, +{'c', -50.20, 213.20, -61.40 ,216.80, -67.00, 226.80}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', 45.12, 303.85, 0, 0, 0, 0}, +{'c', 45.26, 304.11, 45.31 ,304.52, 45.60, 304.54}, +{'c', 46.26, 304.58, 47.49 ,304.88, 47.37, 304.25}, +{'c', 46.52, 299.94, 45.65 ,295.00, 41.52, 293.20}, +{'c', 40.88, 292.92, 39.43 ,293.33, 39.36, 294.21}, +{'c', 39.23, 295.74, 39.12 ,297.09, 39.42, 298.55}, +{'c', 39.73, 299.98, 41.88 ,299.99, 42.80, 298.60}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', 34.04, 308.58, 0, 0, 0, 0}, +{'c', 34.79, 309.99, 34.66 ,311.85, 36.07, 312.42}, +{'c', 36.81, 312.71, 38.66 ,311.74, 38.25, 310.66}, +{'c', 37.44, 308.60, 37.06 ,306.36, 35.67, 304.55}, +{'c', 35.47, 304.29, 35.71 ,303.75, 35.55, 303.43}, +{'c', 34.95, 302.21, 33.81 ,301.47, 32.40, 301.80}, +{'c', 31.29, 304.00, 32.43 ,306.13, 33.95, 307.84}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', -5.56, 303.39, 0, 0, 0, 0}, +{'c', -5.67, 303.01, -5.71 ,302.55, -5.54, 302.23}, +{'c', -5.01, 301.20, -4.22 ,300.07, -4.56, 299.05}, +{'c', -4.91, 298.00, -6.02 ,298.18, -6.67, 298.75}, +{'c', -7.81, 299.74, -7.86 ,301.57, -8.55, 302.93}, +{'c', -8.74, 303.31, -8.69 ,303.89, -9.13, 304.28}, +{'c', -9.61, 304.70, -10.05 ,306.22, -9.95, 306.79}, +{'c', -9.90, 307.11, -10.08 ,317.01, -9.86, 316.75}, +{'c', -9.24, 316.02, -6.19 ,306.28, -6.12, 305.39}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', -31.20, 296.60, 0, 0, 0, 0}, +{'c', -28.57, 294.10, -25.78 ,291.14, -26.22, 287.43}, +{'c', -26.34, 286.45, -28.11 ,286.98, -28.30, 287.82}, +{'c', -29.10, 291.45, -31.14 ,294.11, -33.71, 296.50}, +{'c', -35.90, 298.55, -37.77 ,304.89, -38.00, 305.40}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', -44.78, 290.63, 0, 0, 0, 0}, +{'c', -44.25, 290.26, -44.55 ,289.77, -44.34, 289.44}, +{'c', -43.38, 287.98, -42.08 ,286.74, -42.07, 285.00}, +{'c', -42.06, 284.72, -42.44 ,284.41, -42.78, 284.64}, +{'c', -43.05, 284.82, -43.40 ,284.95, -43.50, 285.08}, +{'c', -45.53, 287.53, -46.93 ,290.20, -48.38, 293.01}, +{'c', -48.56, 293.37, -49.70 ,297.86, -49.39, 297.97}, +{'c', -49.15, 298.06, -47.43 ,293.88, -47.22, 293.76}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', -28.04, 310.18, 0, 0, 0, 0}, +{'c', -27.60, 309.31, -26.02 ,308.11, -26.14, 307.22}, +{'c', -26.25, 306.29, -25.79 ,304.85, -26.70, 305.54}, +{'c', -27.95, 306.48, -31.40 ,307.83, -31.67, 313.64}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', -13.60, 293.00, 0, 0, 0, 0}, +{'c', -13.20, 292.33, -12.49 ,292.81, -12.03, 292.54}, +{'c', -11.38, 292.17, -10.77 ,291.61, -10.48, 290.96}, +{'c', -9.51, 288.81, -7.74 ,287.00, -7.60, 284.60}, +{'c', -9.09, 283.20, -9.77 ,285.24, -10.40, 286.20}, +{'c', -11.72, 284.55, -12.72 ,286.43, -14.02, 286.95}, +{'c', -14.09, 286.98, -14.30 ,286.63, -14.38, 286.65}, +{'c', -15.56, 287.10, -16.24 ,288.18, -17.23, 288.96}, +{'c', -17.41, 289.09, -17.81 ,288.91, -17.96, 289.05}, +{'c', -18.61, 289.65, -19.58 ,289.98, -19.86, 290.66}, +{'c', -20.97, 293.36, -24.11 ,295.46, -26.00, 303.00}, +{'c', -25.62, 303.91, -21.49 ,296.36, -21.00, 295.66}, +{'c', -20.16, 294.46, -20.05 ,297.32, -18.77, 296.66}, +{'c', -18.72, 296.63, -18.53 ,296.87, -18.40, 297.00}, +{'c', -18.21, 296.72, -17.99 ,296.49, -17.60, 296.60}, +{'c', -17.60, 296.20, -17.73 ,295.64, -17.53, 295.49}, +{'c', -16.30, 294.51, -16.38 ,293.44, -15.60, 292.20}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', 46.20, 347.40, 0, 0, 0, 0}, +{'c', 46.20, 347.40, 53.60 ,327.00, 49.20, 315.80}, +{'c', 49.20, 315.80, 60.60 ,337.40, 56.00, 348.60}, +{'c', 56.00, 348.60, 55.60 ,338.20, 51.60, 333.20}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', 31.40, 344.80, 0, 0, 0, 0}, +{'c', 31.40, 344.80, 36.80 ,336.00, 28.80, 317.60}, +{'c', 28.80, 317.60, 28.00 ,338.00, 21.20, 349.00}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', 21.40, 342.80, 0, 0, 0, 0}, +{'c', 21.40, 342.80, 21.20 ,322.80, 21.60, 319.80}, +{'c', 21.60, 319.80, 17.80 ,336.40, 7.60, 346.00}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', 11.80, 310.80, 0, 0, 0, 0}, +{'c', 11.80, 310.80, 17.80 ,324.40, 7.80, 342.80}, +{'c', 7.80, 342.80, 14.20 ,330.60, 9.40, 323.60}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', -7.40, 342.40, 0, 0, 0, 0}, +{'c', -7.40, 342.40, -8.40 ,326.80, -6.60, 324.60}, +{'c', -6.60, 324.60, -6.40 ,318.20, -6.80, 317.20}, +{'c', -6.80, 317.20, -2.80 ,311.00, -2.60, 318.40}, +{'c', -2.60, 318.40, -1.20 ,326.20, 1.60, 330.80}, +{'c', 1.60, 330.80, 5.20 ,336.20, 5.00, 342.60}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', -11.00, 314.80, 0, 0, 0, 0}, +{'c', -11.00, 314.80, -17.60 ,325.60, -19.40, 344.60}, +{'c', -19.40, 344.60, -20.80 ,338.40, -17.00, 324.00}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', -32.80, 334.60, 0, 0, 0, 0}, +{'c', -32.80, 334.60, -27.80 ,329.20, -26.40, 324.20}, +{'c', -26.40, 324.20, -22.80 ,308.40, -29.20, 317.00}, +{'c', -29.20, 317.00, -29.00 ,325.00, -37.20, 332.40}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', -38.60, 329.60, 0, 0, 0, 0}, +{'c', -38.60, 329.60, -35.20 ,312.20, -34.40, 311.40}, +{'c', -34.40, 311.40, -32.60 ,308.00, -35.40, 311.20}, +{'c', -35.40, 311.20, -44.20 ,330.40, -48.20, 337.00}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', -44.40, 313.00, 0, 0, 0, 0}, +{'c', -44.40, 313.00, -32.80 ,290.60, -54.60, 316.40}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', -59.80, 298.40, 0, 0, 0, 0}, +{'c', -59.80, 298.40, -55.00 ,279.60, -52.40, 279.80}, +{'c', -52.40, 279.80, -44.20 ,270.80, -50.80, 281.40}, +{'c', -50.80, 281.40, -56.80 ,291.00, -56.20, 300.80}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', 270.50, 287.00, 0, 0, 0, 0}, +{'c', 270.50, 287.00, 258.50 ,277.00, 256.00, 273.50}, +{'c', 256.00, 273.50, 269.50 ,292.00, 269.50, 299.00}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', 276.00, 265.00, 0, 0, 0, 0}, +{'c', 276.00, 265.00, 255.00 ,250.00, 251.50, 242.50}, +{'c', 251.50, 242.50, 278.00 ,272.00, 278.00, 276.50}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', 293.00, 111.00, 0, 0, 0, 0}, +{'c', 293.00, 111.00, 281.00 ,103.00, 279.50, 105.00}, +{'c', 279.50, 105.00, 290.00 ,111.50, 292.50, 120.00}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', 301.50, 191.50, 0, 0, 0, 0}, +{'l', 284.00, 179.50, 0, 0, 0, 0}, +{'c', 284.00, 179.50, 303.00 ,196.50, 303.50, 200.50}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', -89.25, 169.00, 0, 0, 0, 0}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'l', -67.25, 173.75, 0, 0, 0, 0}, +{'m', -39.00, 331.00, 0, 0, 0, 0}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', -33.50, 336.00, 0, 0, 0, 0}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', 20.50, 344.50, 0, 0, 0, 0}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', 301.50, 191.50, 0, 0, 0, 0}, +{'l', 284.00, 179.50, 0, 0, 0, 0}, +{'c', 284.00, 179.50, 303.00 ,196.50, 303.50, 200.50}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', -89.25, 169.00, 0, 0, 0, 0}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'l', -67.25, 173.75, 0, 0, 0, 0}, +{'m', -39.00, 331.00, 0, 0, 0, 0}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', -33.50, 336.00, 0, 0, 0, 0}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', 20.50, 344.50, 0, 0, 0, 0}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', 301.50, 191.50, 0, 0, 0, 0}, +{'l', 284.00, 179.50, 0, 0, 0, 0}, +{'c', 284.00, 179.50, 303.00 ,196.50, 303.50, 200.50}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', -89.25, 169.00, 0, 0, 0, 0}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'l', -67.25, 173.75, 0, 0, 0, 0}, +{'m', -39.00, 331.00, 0, 0, 0, 0}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', -33.50, 336.00, 0, 0, 0, 0}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }, +{'m', 20.50, 344.50, 0, 0, 0, 0}, +{'f', 0.804000,0.804000,0.804000,1.000000,0,0 }}; diff --git a/local/recipes/libs/cairo/source/test/tighten-bounds.c b/local/recipes/libs/cairo/source/test/tighten-bounds.c new file mode 100644 index 0000000000..f5430e4471 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/tighten-bounds.c @@ -0,0 +1,172 @@ +/* + * Copyright © 2011 Uli Schlachter + * + * 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: Uli Schlachter + */ + +#include "cairo-test.h" + +static void path_none (cairo_t *cr, int size) +{ +} + +static void path_box (cairo_t *cr, int size) +{ + cairo_rectangle (cr, 0, 0, size, size); +} + +static void path_box_unaligned (cairo_t *cr, int size) +{ + cairo_rectangle (cr, 0.5, 0.5, size - 1, size - 1); +} + +static void path_triangle (cairo_t *cr, int size) +{ + cairo_move_to (cr, 0, 0); + cairo_line_to (cr, size/2, size); + cairo_line_to (cr, size, 0); + cairo_close_path (cr); +} + +static void path_circle (cairo_t *cr, int size) +{ + cairo_arc (cr, size / 2.0, size / 2.0, size / 2.0, 0, 2 * M_PI); +} + +static void (* const path_funcs[])(cairo_t *cr, int size) = { + path_none, + path_box, + path_box_unaligned, + path_triangle, + path_circle +}; + +#define SIZE 20 +#define PAD 2 +#define TYPES 6 +/* All-clipped is boring, thus we skip path_none for clipping */ +#define CLIP_OFFSET 1 +#define IMAGE_WIDTH ((ARRAY_LENGTH (path_funcs) - CLIP_OFFSET) * TYPES * (SIZE + PAD) - PAD) +#define IMAGE_HEIGHT (ARRAY_LENGTH (path_funcs) * (SIZE + PAD) - PAD) + +static void +draw_idx (cairo_t *cr, int i, int j, int type) +{ + cairo_bool_t little_path; + cairo_bool_t empty_clip; + cairo_bool_t little_clip; + + /* The lowest bit controls the path, the rest the clip */ + little_path = type & 1; + + /* We don't want the combination "empty_clip = TRUE, little_clip = FALSE" + * (== all clipped). + */ + switch (type >> 1) + { + case 0: + empty_clip = FALSE; + little_clip = FALSE; + break; + case 1: + empty_clip = FALSE; + little_clip = TRUE; + break; + case 2: + empty_clip = TRUE; + little_clip = TRUE; + break; + default: + return; + } + + cairo_save (cr); + + /* Thanks to the fill rule, drawing something twice removes it again */ + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + + path_funcs[i] (cr, SIZE); + if (empty_clip) + path_funcs[i] (cr, SIZE); + if (little_clip) + { + cairo_save (cr); + cairo_translate (cr, SIZE / 4, SIZE / 4); + path_funcs[i] (cr, SIZE / 2); + cairo_restore (cr); + } + cairo_clip (cr); + + path_funcs[j] (cr, SIZE); + path_funcs[j] (cr, SIZE); + if (little_path) + { + /* Draw the object again in the center of itself */ + cairo_save (cr); + cairo_translate (cr, SIZE / 4, SIZE / 4); + path_funcs[j] (cr, SIZE / 2); + cairo_restore (cr); + } + cairo_fill (cr); + cairo_restore (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + size_t i, j, k; + + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_paint (cr); + + /* Set an unbounded operator so that we can see how accurate the bounded + * extents were. + */ + cairo_set_operator (cr, CAIRO_OPERATOR_IN); + cairo_set_source_rgb (cr, 1, 1, 1); + + for (j = 0; j < ARRAY_LENGTH (path_funcs); j++) { + cairo_save (cr); + for (i = CLIP_OFFSET; i < ARRAY_LENGTH (path_funcs); i++) { + for (k = 0; k < TYPES; k++) { + cairo_save (cr); + cairo_rectangle (cr, 0, 0, SIZE, SIZE); + cairo_clip (cr); + draw_idx (cr, i, j, k); + cairo_restore (cr); + cairo_translate (cr, SIZE + PAD, 0); + } + } + cairo_restore (cr); + cairo_translate (cr, 0, SIZE + PAD); + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (tighten_bounds, + "Tests that we tighten the bounds after tessellation.", + "fill", /* keywords */ + NULL, /* requirements */ + IMAGE_WIDTH, IMAGE_HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/toy-font-face.c b/local/recipes/libs/cairo/source/test/toy-font-face.c new file mode 100644 index 0000000000..95d2c01eb4 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/toy-font-face.c @@ -0,0 +1,147 @@ +/* + * Copyright © 2005,2008 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + * Behdad Esfahbod + */ + +#include "config.h" + +#include "cairo-test.h" + +#include +#include +#include + +#if CAIRO_HAS_WIN32_FONT +#define CAIRO_FONT_FAMILY_DEFAULT "Arial" +#elif CAIRO_HAS_QUARTZ_FONT +#define CAIRO_FONT_FAMILY_DEFAULT "Helvetica" +#elif CAIRO_HAS_FT_FONT +#define CAIRO_FONT_FAMILY_DEFAULT "" +#else +#define CAIRO_FONT_FAMILY_DEFAULT "@cairo:" +#endif + + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + cairo_t *cr; + cairo_surface_t *surface; + cairo_font_face_t *font_face; + cairo_status_t status; + + surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 0, 0); + cr = cairo_create (surface); + cairo_surface_destroy (surface); + + font_face = cairo_font_face_reference (cairo_get_font_face (cr)); + assert (cairo_font_face_get_type (font_face) == CAIRO_FONT_TYPE_TOY); + assert (cairo_toy_font_face_get_family (font_face) != NULL); + assert (cairo_toy_font_face_get_slant (font_face) == CAIRO_FONT_SLANT_NORMAL); + assert (cairo_toy_font_face_get_weight (font_face) == CAIRO_FONT_WEIGHT_NORMAL); + status = cairo_font_face_status(font_face); + cairo_font_face_destroy (font_face); + + if (status) + return cairo_test_status_from_status (ctx, status); + + cairo_select_font_face (cr, + "bizarre", + CAIRO_FONT_SLANT_OBLIQUE, + CAIRO_FONT_WEIGHT_BOLD); + font_face = cairo_font_face_reference (cairo_get_font_face (cr)); + assert (cairo_font_face_get_type (font_face) == CAIRO_FONT_TYPE_TOY); + assert (0 == (strcmp) (cairo_toy_font_face_get_family (font_face), "bizarre")); + assert (cairo_toy_font_face_get_slant (font_face) == CAIRO_FONT_SLANT_OBLIQUE); + assert (cairo_toy_font_face_get_weight (font_face) == CAIRO_FONT_WEIGHT_BOLD); + status = cairo_font_face_status(font_face); + cairo_font_face_destroy (font_face); + + if (status) + return cairo_test_status_from_status (ctx, status); + + font_face = cairo_toy_font_face_create ("bozarre", + CAIRO_FONT_SLANT_OBLIQUE, + CAIRO_FONT_WEIGHT_BOLD); + assert (cairo_font_face_get_type (font_face) == CAIRO_FONT_TYPE_TOY); + assert (0 == (strcmp) (cairo_toy_font_face_get_family (font_face), "bozarre")); + assert (cairo_toy_font_face_get_slant (font_face) == CAIRO_FONT_SLANT_OBLIQUE); + assert (cairo_toy_font_face_get_weight (font_face) == CAIRO_FONT_WEIGHT_BOLD); + status = cairo_font_face_status(font_face); + cairo_font_face_destroy (font_face); + + if (status) + return cairo_test_status_from_status (ctx, status); + + font_face = cairo_toy_font_face_create (NULL, + CAIRO_FONT_SLANT_OBLIQUE, + CAIRO_FONT_WEIGHT_BOLD); + assert (cairo_font_face_get_type (font_face) == CAIRO_FONT_TYPE_TOY); + assert (0 == (strcmp) (cairo_toy_font_face_get_family (font_face), CAIRO_FONT_FAMILY_DEFAULT)); + assert (cairo_toy_font_face_get_slant (font_face) == CAIRO_FONT_SLANT_NORMAL); + assert (cairo_toy_font_face_get_weight (font_face) == CAIRO_FONT_WEIGHT_NORMAL); + assert (cairo_font_face_status(font_face) == CAIRO_STATUS_NULL_POINTER); + cairo_font_face_destroy (font_face); + + font_face = cairo_toy_font_face_create ("\xff", + CAIRO_FONT_SLANT_OBLIQUE, + CAIRO_FONT_WEIGHT_BOLD); + assert (cairo_font_face_get_type (font_face) == CAIRO_FONT_TYPE_TOY); + assert (0 == (strcmp) (cairo_toy_font_face_get_family (font_face), CAIRO_FONT_FAMILY_DEFAULT)); + assert (cairo_toy_font_face_get_slant (font_face) == CAIRO_FONT_SLANT_NORMAL); + assert (cairo_toy_font_face_get_weight (font_face) == CAIRO_FONT_WEIGHT_NORMAL); + assert (cairo_font_face_status(font_face) == CAIRO_STATUS_INVALID_STRING); + cairo_font_face_destroy (font_face); + + font_face = cairo_toy_font_face_create ("sans", + -1, + CAIRO_FONT_WEIGHT_BOLD); + assert (cairo_font_face_get_type (font_face) == CAIRO_FONT_TYPE_TOY); + assert (0 == (strcmp) (cairo_toy_font_face_get_family (font_face), CAIRO_FONT_FAMILY_DEFAULT)); + assert (cairo_toy_font_face_get_slant (font_face) == CAIRO_FONT_SLANT_NORMAL); + assert (cairo_toy_font_face_get_weight (font_face) == CAIRO_FONT_WEIGHT_NORMAL); + assert (cairo_font_face_status(font_face) == CAIRO_STATUS_INVALID_SLANT); + cairo_font_face_destroy (font_face); + + font_face = cairo_toy_font_face_create ("sans", + CAIRO_FONT_SLANT_OBLIQUE, + -1); + assert (cairo_font_face_get_type (font_face) == CAIRO_FONT_TYPE_TOY); + assert (0 == (strcmp) (cairo_toy_font_face_get_family (font_face), CAIRO_FONT_FAMILY_DEFAULT)); + assert (cairo_toy_font_face_get_slant (font_face) == CAIRO_FONT_SLANT_NORMAL); + assert (cairo_toy_font_face_get_weight (font_face) == CAIRO_FONT_WEIGHT_NORMAL); + assert (cairo_font_face_status(font_face) == CAIRO_STATUS_INVALID_WEIGHT); + cairo_font_face_destroy (font_face); + + cairo_destroy (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (toy_font_face, + "Check the construction of 'toy' font faces", + "font, api", /* keywords */ + NULL, /* requirements */ + 0, 0, + preamble, NULL) diff --git a/local/recipes/libs/cairo/source/test/transforms.c b/local/recipes/libs/cairo/source/test/transforms.c new file mode 100644 index 0000000000..17b1396874 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/transforms.c @@ -0,0 +1,112 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl Worth + */ + +#include "cairo-test.h" + +#define WIDTH 45 +#define HEIGHT 30 + +static void +draw_L_shape (cairo_t *cr) +{ + cairo_move_to (cr, 0, 0); + cairo_rel_line_to (cr, 0, 10); + cairo_rel_line_to (cr, 5, 0); + + cairo_save (cr); + cairo_identity_matrix (cr); + cairo_set_line_width (cr, 2.0); + cairo_stroke (cr); + cairo_restore (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + /* We draw in the default black, so paint white first. */ + cairo_save (cr); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_restore (cr); + + cairo_translate (cr, 5, 5); + + draw_L_shape (cr); + + cairo_translate (cr, 10, 0); + + cairo_save (cr); + { + cairo_scale (cr, 2, 2); + draw_L_shape (cr); + } + cairo_restore (cr); + + cairo_translate (cr, 15, 0); + + cairo_save (cr); + { + cairo_rotate (cr, M_PI / 2.0); + draw_L_shape (cr); + } + cairo_restore (cr); + + cairo_translate (cr, 5, 0); + + cairo_save (cr); + { + cairo_matrix_t skew_y = { + 1, -1, + 0, 1, + 0, 0 + }; + cairo_transform (cr, &skew_y); + draw_L_shape (cr); + } + cairo_restore (cr); + + cairo_translate (cr, 5, 10); + + cairo_save (cr); + { + cairo_matrix_t skew_x = { + 1.0, 0.0, + -0.5, 1.0, + 0.0, 0.0 + }; + cairo_transform (cr, &skew_x); + draw_L_shape (cr); + } + cairo_restore (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (transforms, + "Test various transformations.", + "transforms, api", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/translate-show-surface.c b/local/recipes/libs/cairo/source/test/translate-show-surface.c new file mode 100644 index 0000000000..9f7af8db2e --- /dev/null +++ b/local/recipes/libs/cairo/source/test/translate-show-surface.c @@ -0,0 +1,79 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +/* Bug history + * + * 2005-04-11 Carl Worth + * + * It appears that calling cairo_show_surface after cairo_translate + * somehow applies the translation twice to the surface being + * shown. This is pretty easy to demonstrate by bringing up xsvg on + * an SVG file with an and panning around a bit with the + * arrow keys. + * + * This is almost certainly a regression, and I suspect there may be + * some interaction with the fix for move-to-show-surface. + * + * 2005-04-12 Carl Worth + * + * I committed a fix for this bug today. + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface; + uint32_t colors[4] = { + 0xffffffff, 0xffff0000, + 0xff00ff00, 0xff0000ff + }; + int i; + + for (i=0; i < 4; i++) { + surface = cairo_image_surface_create_for_data ((unsigned char *) &colors[i], + CAIRO_FORMAT_RGB24, + 1, 1, 4); + cairo_save (cr); + { + cairo_translate (cr, i % 2, i / 2); + cairo_set_source_surface (cr, surface, 0, 0); + cairo_paint (cr); + } + cairo_restore (cr); + cairo_surface_finish (surface); /* colors will go out of scope */ + cairo_surface_destroy (surface); + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (translate_show_surface, + "Tests calls to cairo_show_surface after cairo_translate", + "transform", /* keywords */ + NULL, /* requirements */ + 2, 2, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/trap-clip.c b/local/recipes/libs/cairo/source/test/trap-clip.c new file mode 100644 index 0000000000..f1a24ca8de --- /dev/null +++ b/local/recipes/libs/cairo/source/test/trap-clip.c @@ -0,0 +1,213 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Kristian Høgsberg + */ + +#include "cairo-test.h" +#include +#include + +#define WIDTH 16 +#define HEIGHT 16 +#define PAD 2 + +static const char *png_filename = "romedalen.png"; +static cairo_surface_t *image; + +static void +set_solid_pattern (const cairo_test_context_t *ctx, cairo_t *cr, int x, int y) +{ + cairo_set_source_rgb (cr, 0, 0, 0.6); +} + +static void +set_translucent_pattern (const cairo_test_context_t *ctx, cairo_t *cr, int x, int y) +{ + cairo_set_source_rgba (cr, 0, 0, 0.6, 0.5); +} + +static void +set_gradient_pattern (const cairo_test_context_t *ctx, cairo_t *cr, int x, int y) +{ + cairo_pattern_t *pattern; + + pattern = + cairo_pattern_create_linear (x, y, x + WIDTH, y + HEIGHT); + cairo_pattern_add_color_stop_rgba (pattern, 0, 1, 1, 1, 1); + cairo_pattern_add_color_stop_rgba (pattern, 1, 0, 0, 0.4, 1); + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); +} + +static void +set_image_pattern (const cairo_test_context_t *ctx, cairo_t *cr, int x, int y) +{ + cairo_pattern_t *pattern; + + if (image == NULL || cairo_surface_status (image)) { + cairo_surface_destroy (image); + image = cairo_test_create_surface_from_png (ctx, png_filename); + } + + pattern = cairo_pattern_create_for_surface (image); + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT); + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); +} + +static void +draw_rect (cairo_t *cr, int x, int y) +{ + cairo_new_path (cr); + cairo_rectangle (cr, x, y, WIDTH, HEIGHT); + cairo_fill (cr); +} + +static void +draw_rects (cairo_t *cr, int x, int y) +{ + int width = WIDTH / 3; + int height = HEIGHT / 2; + + cairo_new_path (cr); + cairo_rectangle (cr, x, y, width, height); + cairo_rectangle (cr, x + width, y + height, width, height); + cairo_rectangle (cr, x + 2 * width, y, width, height); + cairo_fill (cr); +} + +static void +draw_polygon (cairo_t *cr, int x, int y) +{ + cairo_new_path (cr); + cairo_move_to (cr, x, y); + cairo_line_to (cr, x, y + HEIGHT); + cairo_line_to (cr, x + WIDTH / 2, y + 3 * HEIGHT / 4); + cairo_line_to (cr, x + WIDTH, y + HEIGHT); + cairo_line_to (cr, x + WIDTH, y); + cairo_line_to (cr, x + WIDTH / 2, y + HEIGHT / 4); + cairo_close_path (cr); + cairo_fill (cr); +} + +static void +clip_none (cairo_t *cr, int x, int y) +{ +} + +static void +clip_rect (cairo_t *cr, int x, int y) +{ + cairo_new_path (cr); + cairo_rectangle (cr, x + (int)WIDTH / 6, y + (int)HEIGHT / 6, + 4 * ((int)WIDTH / 6), 4 * ((int)WIDTH / 6)); + cairo_clip (cr); + cairo_new_path (cr); +} + +static void +clip_rects (cairo_t *cr, int x, int y) +{ + int height = HEIGHT / 3; + + cairo_new_path (cr); + cairo_rectangle (cr, x, y, WIDTH, height); + cairo_rectangle (cr, x, y + 2 * height, WIDTH, height); + cairo_clip (cr); + cairo_new_path (cr); +} + +static void +clip_circle (cairo_t *cr, int x, int y) +{ + cairo_new_path (cr); + cairo_arc (cr, x + WIDTH / 2, y + HEIGHT / 2, + WIDTH / 3, 0, 2 * M_PI); + cairo_clip (cr); + cairo_new_path (cr); +} + +static void (* const pattern_funcs[])(const cairo_test_context_t *ctx, cairo_t *cr, int x, int y) = { + set_solid_pattern, + set_translucent_pattern, + set_gradient_pattern, + set_image_pattern, +}; + +static void (* const draw_funcs[])(cairo_t *cr, int x, int y) = { + draw_rect, + draw_rects, + draw_polygon, +}; + +static void (* const clip_funcs[])(cairo_t *cr, int x, int y) = { + clip_none, + clip_rect, + clip_rects, + clip_circle, +}; + +#define IMAGE_WIDTH (ARRAY_LENGTH (pattern_funcs) * (WIDTH + PAD) + PAD) +#define IMAGE_HEIGHT (ARRAY_LENGTH (draw_funcs) * ARRAY_LENGTH (clip_funcs) * (HEIGHT + PAD) + PAD) + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + size_t i, j, k, x, y; + + for (k = 0; k < ARRAY_LENGTH (clip_funcs); k++) { + for (j = 0; j < ARRAY_LENGTH (draw_funcs); j++) { + for (i = 0; i < ARRAY_LENGTH (pattern_funcs); i++) { + x = i * (WIDTH + PAD) + PAD; + y = (ARRAY_LENGTH (draw_funcs) * k + j) * (HEIGHT + PAD) + PAD; + + cairo_save (cr); + + cairo_move_to (cr, x, y); + clip_funcs[k] (cr, x, y); + pattern_funcs[i] (ctx, cr, x, y); + draw_funcs[j] (cr, x, y); + if (cairo_status (cr)) + cairo_test_log (ctx, "%d %d HERE!\n", (int)i, (int)j); + + cairo_restore (cr); + } + } + } + + if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) + cairo_test_log (ctx, "%d %d .HERE!\n", (int)i, (int)j); + + cairo_surface_destroy (image); + image = NULL; + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (trap_clip, + "Trapezoid clipping", + "clip, trap", /* keywords */ + NULL, /* requirements */ + IMAGE_WIDTH, IMAGE_HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/twin-antialias-gray.c b/local/recipes/libs/cairo/source/test/twin-antialias-gray.c new file mode 100644 index 0000000000..8e00370b0e --- /dev/null +++ b/local/recipes/libs/cairo/source/test/twin-antialias-gray.c @@ -0,0 +1,71 @@ +/* + * Copyright 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_font_options_t *options; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + + cairo_set_antialias (cr, CAIRO_ANTIALIAS_GRAY); + + cairo_select_font_face (cr, + "@cairo:", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + + options = cairo_font_options_create (); + cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_GRAY); + cairo_set_font_options (cr, options); + cairo_font_options_destroy (options); + + cairo_set_font_size (cr, 16); + + cairo_move_to (cr, 4, 14); + cairo_show_text (cr, "Is cairo's twin giza?"); + + cairo_move_to (cr, 4, 34); + cairo_text_path (cr, "Is cairo's twin giza?"); + cairo_fill (cr); + + cairo_move_to (cr, 4, 54); + cairo_text_path (cr, "Is cairo's twin giza?"); + cairo_set_line_width (cr, 2/16.); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (twin_antialias_gray, + "Tests the internal font (with antialiasing reduced)", + "twin, font", /* keywords */ + "target=raster", /* requirements */ + 140, 60, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/twin-antialias-mixed.c b/local/recipes/libs/cairo/source/test/twin-antialias-mixed.c new file mode 100644 index 0000000000..da4121a1d4 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/twin-antialias-mixed.c @@ -0,0 +1,97 @@ +/* + * Copyright 2009 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_scaled_font_t * +create_twin (cairo_t *cr, cairo_antialias_t antialias) +{ + cairo_font_options_t *options; + + cairo_select_font_face (cr, + "@cairo:", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + + options = cairo_font_options_create (); + cairo_font_options_set_antialias (options, antialias); + cairo_set_font_options (cr, options); + cairo_font_options_destroy (options); + + return cairo_scaled_font_reference (cairo_get_scaled_font (cr)); +} + + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_scaled_font_t *subpixel, *gray, *none; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + + cairo_set_font_size (cr, 16); + subpixel = create_twin (cr, CAIRO_ANTIALIAS_SUBPIXEL); + gray = create_twin (cr, CAIRO_ANTIALIAS_GRAY); + none = create_twin (cr, CAIRO_ANTIALIAS_NONE); + + cairo_move_to (cr, 4, 14); + cairo_set_scaled_font (cr, subpixel); + cairo_show_text (cr, "Is cairo's"); + cairo_set_scaled_font (cr, gray); + cairo_show_text (cr, " twin"); + cairo_set_scaled_font (cr, none); + cairo_show_text (cr, " giza?"); + + cairo_move_to (cr, 4, 34); + cairo_set_scaled_font (cr, gray); + cairo_show_text (cr, "Is cairo's"); + cairo_set_scaled_font (cr, none); + cairo_show_text (cr, " twin"); + cairo_set_scaled_font (cr, subpixel); + cairo_show_text (cr, " giza?"); + + cairo_move_to (cr, 4, 54); + cairo_set_scaled_font (cr, none); + cairo_show_text (cr, "Is cairo's"); + cairo_set_scaled_font (cr, gray); + cairo_show_text (cr, " twin"); + cairo_set_scaled_font (cr, subpixel); + cairo_show_text (cr, " giza?"); + + cairo_scaled_font_destroy (none); + cairo_scaled_font_destroy (gray); + cairo_scaled_font_destroy (subpixel); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (twin_antialias_mixed, + "Tests the internal font (with intermixed antialiasing)", + "twin, font", /* keywords */ + "target=raster", /* requirements */ + 140, 60, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/twin-antialias-none.c b/local/recipes/libs/cairo/source/test/twin-antialias-none.c new file mode 100644 index 0000000000..a5b713db3c --- /dev/null +++ b/local/recipes/libs/cairo/source/test/twin-antialias-none.c @@ -0,0 +1,71 @@ +/* + * Copyright 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_font_options_t *options; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + + cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); + + cairo_select_font_face (cr, + "@cairo:", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + + options = cairo_font_options_create (); + cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_NONE); + cairo_set_font_options (cr, options); + cairo_font_options_destroy (options); + + cairo_set_font_size (cr, 16); + + cairo_move_to (cr, 4, 14); + cairo_show_text (cr, "Is cairo's twin giza?"); + + cairo_move_to (cr, 4, 34); + cairo_text_path (cr, "Is cairo's twin giza?"); + cairo_fill (cr); + + cairo_move_to (cr, 4, 54); + cairo_text_path (cr, "Is cairo's twin giza?"); + cairo_set_line_width (cr, 2/16.); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (twin_antialias_none, + "Tests the internal font (with antialiasing disabled)", + "twin, font", /* keywords */ + "target=raster", /* requirements */ + 140, 60, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/twin-antialias-subpixel.c b/local/recipes/libs/cairo/source/test/twin-antialias-subpixel.c new file mode 100644 index 0000000000..e0262863ca --- /dev/null +++ b/local/recipes/libs/cairo/source/test/twin-antialias-subpixel.c @@ -0,0 +1,71 @@ +/* + * Copyright 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_font_options_t *options; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + + cairo_set_antialias (cr, CAIRO_ANTIALIAS_SUBPIXEL); + + cairo_select_font_face (cr, + "@cairo:", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + + options = cairo_font_options_create (); + cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_SUBPIXEL); + cairo_set_font_options (cr, options); + cairo_font_options_destroy (options); + + cairo_set_font_size (cr, 16); + + cairo_move_to (cr, 4, 14); + cairo_show_text (cr, "Is cairo's twin giza?"); + + cairo_move_to (cr, 4, 34); + cairo_text_path (cr, "Is cairo's twin giza?"); + cairo_fill (cr); + + cairo_move_to (cr, 4, 54); + cairo_text_path (cr, "Is cairo's twin giza?"); + cairo_set_line_width (cr, 2/16.); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (twin_antialias_subpixel, + "Tests the internal font (with subpixel antialiasing)", + "twin, font", /* keywords */ + "target=raster", /* requirements */ + 140, 60, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/twin.c b/local/recipes/libs/cairo/source/test/twin.c new file mode 100644 index 0000000000..08865f0770 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/twin.c @@ -0,0 +1,61 @@ +/* + * Copyright 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + + cairo_select_font_face (cr, + "@cairo:", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (cr, 16); + + cairo_move_to (cr, 4, 14); + cairo_show_text (cr, "Is cairo's twin giza?"); + + cairo_move_to (cr, 4, 34); + cairo_text_path (cr, "Is cairo's twin giza?"); + cairo_fill (cr); + + cairo_move_to (cr, 4, 54); + cairo_text_path (cr, "Is cairo's twin giza?"); + cairo_set_line_width (cr, 2/16.); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (twin, + "Tests the internal font", + "twin, font", /* keywords */ + NULL, /* requirements */ + 140, 60, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/unaligned-box.c b/local/recipes/libs/cairo/source/test/unaligned-box.c new file mode 100644 index 0000000000..5526919344 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/unaligned-box.c @@ -0,0 +1,73 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +#define WIDTH 48 +#define HEIGHT 52 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + int sx, sy; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + + cairo_translate(cr, 2, 2); + + for (sx = 1; sx <= 4; sx++) { + cairo_save (cr); + for (sy = 1; sy <= 4; sy++) { + cairo_rectangle (cr, 0, 0, sx, sy); + cairo_fill (cr); + + cairo_rectangle (cr, sx + 1 + .5, 0, sx, sy); + cairo_fill (cr); + + cairo_rectangle (cr, 0, sy + 1 + .5, sx, sy); + cairo_fill (cr); + + cairo_rectangle (cr, sx + 1 + .5, sy + 1 + .5, sx-.5, sy-.5); + cairo_fill (cr); + + cairo_translate (cr, 2*sx + 3, 0); + } + cairo_restore (cr); + cairo_translate (cr, 0, 2*sy + 3); + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (unaligned_box, + "Tests handling of various boundary conditions for unaligned rectangles.", + "fill", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/unantialiased-shapes.c b/local/recipes/libs/cairo/source/test/unantialiased-shapes.c new file mode 100644 index 0000000000..b53ed0d6ec --- /dev/null +++ b/local/recipes/libs/cairo/source/test/unantialiased-shapes.c @@ -0,0 +1,98 @@ +/* + * Copyright © 2005 Billy Biggs + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Billy Biggs not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Billy Biggs makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * BILLY BIGGS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL BILLY BIGGS BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Billy Biggs + */ + +#include "cairo-test.h" + +/* The star shape from the SVG test suite, from the fill rule test */ +static void +big_star_path (cairo_t *cr) +{ + cairo_move_to (cr, 40, 0); + cairo_rel_line_to (cr, 25, 80); + cairo_rel_line_to (cr, -65, -50); + cairo_rel_line_to (cr, 80, 0); + cairo_rel_line_to (cr, -65, 50); + cairo_close_path (cr); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + int i; + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); + + /* Try a circle */ + cairo_arc (cr, 40, 40, 20, 0, 2 * M_PI); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_fill (cr); + + /* Try using clipping to draw a circle */ + cairo_arc (cr, 100, 40, 20, 0, 2 * M_PI); + cairo_clip (cr); + cairo_rectangle (cr, 80, 20, 40, 40); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_fill (cr); + + /* Reset the clipping */ + cairo_reset_clip (cr); + + /* Draw a bunch of lines */ + cairo_set_line_width (cr, 1.0); + cairo_set_source_rgb (cr, 0, 1, 0); + for (i = 0; i < 10; i++) { + cairo_move_to (cr, 10, 70 + (i * 4)); + cairo_line_to (cr, 120, 70 + (i * 18)); + cairo_stroke (cr); + } + + /* Try filling a poly */ + cairo_translate (cr, 160, 120); + cairo_set_source_rgb (cr, 1, 1, 0); + big_star_path (cr); + cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); + cairo_fill (cr); + cairo_translate (cr, -160, -120); + + /* How about some curves? */ + cairo_set_source_rgb (cr, 1, 0, 1); + for (i = 0; i < 10; i++) { + cairo_move_to (cr, 150, 50 + (i * 5)); + cairo_curve_to (cr, 250, 50, 200, (i * 10), 300, 50 + (i * 10)); + cairo_stroke (cr); + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (unantialiased_shapes, + "Test shape drawing without antialiasing", + "fill, stroke", /* keywords */ + "target=raster", /* requirements */ + 320, 240, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/unbounded-operator.c b/local/recipes/libs/cairo/source/test/unbounded-operator.c new file mode 100644 index 0000000000..ac1c50d1d7 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/unbounded-operator.c @@ -0,0 +1,185 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Authors: Kristian Høgsberg + * Owen Taylor + */ + +#include "cairo-test.h" +#include +#include + +#define WIDTH 16 +#define HEIGHT 16 +#define PAD 2 + +static void +draw_mask (cairo_t *cr, int x, int y) +{ + cairo_surface_t *mask_surface; + cairo_t *cr2; + + double width = (int)(0.9 * WIDTH); + double height = (int)(0.9 * HEIGHT); + x += 0.05 * WIDTH; + y += 0.05 * HEIGHT; + + mask_surface = cairo_surface_create_similar (cairo_get_group_target (cr), + CAIRO_CONTENT_ALPHA, + width, height); + cr2 = cairo_create (mask_surface); + cairo_surface_destroy (mask_surface); + + cairo_save (cr2); + cairo_set_source_rgba (cr2, 0, 0, 0, 0); /* transparent */ + cairo_set_operator (cr2, CAIRO_OPERATOR_SOURCE); + cairo_paint (cr2); + cairo_restore (cr2); + + cairo_set_source_rgb (cr2, 1, 1, 1); /* white */ + + cairo_arc (cr2, 0.5 * width, 0.5 * height, 0.45 * height, 0, 2 * M_PI); + cairo_fill (cr2); + + cairo_mask_surface (cr, cairo_get_target (cr2), x, y); + cairo_destroy (cr2); +} + +static void +draw_glyphs (cairo_t *cr, int x, int y) +{ + cairo_text_extents_t extents; + + cairo_set_font_size (cr, 0.8 * HEIGHT); + + cairo_text_extents (cr, "FG", &extents); + cairo_move_to (cr, + x + floor ((WIDTH - extents.width) / 2 + 0.5) - extents.x_bearing, + y + floor ((HEIGHT - extents.height) / 2 + 0.5) - extents.y_bearing); + cairo_show_text (cr, "FG"); +} + +static void +draw_polygon (cairo_t *cr, int x, int y) +{ + double width = (int)(0.9 * WIDTH); + double height = (int)(0.9 * HEIGHT); + x += 0.05 * WIDTH; + y += 0.05 * HEIGHT; + + cairo_new_path (cr); + cairo_move_to (cr, x, y); + cairo_line_to (cr, x, y + height); + cairo_line_to (cr, x + width / 2, y + 3 * height / 4); + cairo_line_to (cr, x + width, y + height); + cairo_line_to (cr, x + width, y); + cairo_line_to (cr, x + width / 2, y + height / 4); + cairo_close_path (cr); + cairo_fill (cr); +} + +static void +draw_rects (cairo_t *cr, int x, int y) +{ + double block_width = (int)(0.33 * WIDTH + 0.5); + double block_height = (int)(0.33 * HEIGHT + 0.5); + int i, j; + + for (i = 0; i < 3; i++) + for (j = 0; j < 3; j++) + if ((i + j) % 2 == 0) + cairo_rectangle (cr, + x + block_width * i, y + block_height * j, + block_width, block_height); + + cairo_fill (cr); +} + +static void (*const draw_funcs[])(cairo_t *cr, int x, int y) = { + draw_mask, + draw_glyphs, + draw_polygon, + draw_rects +}; + +static cairo_operator_t operators[] = { + CAIRO_OPERATOR_IN, CAIRO_OPERATOR_OUT, + CAIRO_OPERATOR_DEST_IN, CAIRO_OPERATOR_DEST_ATOP +}; + +#define IMAGE_WIDTH (ARRAY_LENGTH (operators) * (WIDTH + PAD) + PAD) +#define IMAGE_HEIGHT (ARRAY_LENGTH (draw_funcs) * (HEIGHT + PAD) + PAD) + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + const cairo_test_context_t *ctx = cairo_test_get_context (cr); + size_t i, j, x, y; + cairo_pattern_t *pattern; + + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + + for (j = 0; j < ARRAY_LENGTH (draw_funcs); j++) { + for (i = 0; i < ARRAY_LENGTH (operators); i++) { + x = i * (WIDTH + PAD) + PAD; + y = j * (HEIGHT + PAD) + PAD; + + cairo_save (cr); + + pattern = cairo_pattern_create_linear (x + WIDTH, y, + x, y + HEIGHT); + cairo_pattern_add_color_stop_rgba (pattern, 0.2, + 0.0, 0.0, 1.0, 1.0); /* Solid blue */ + cairo_pattern_add_color_stop_rgba (pattern, 0.8, + 0.0, 0.0, 1.0, 0.0); /* Transparent blue */ + cairo_set_source (cr, pattern); + cairo_pattern_destroy (pattern); + + cairo_rectangle (cr, x, y, WIDTH, HEIGHT); + cairo_fill_preserve (cr); + cairo_clip (cr); + + cairo_set_operator (cr, operators[i]); + cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); + + draw_funcs[j] (cr, x, y); + if (cairo_status (cr)) + cairo_test_log (ctx, "%d %d HERE!\n", (int)i, (int)j); + + cairo_restore (cr); + } + } + + if (cairo_status (cr) != CAIRO_STATUS_SUCCESS) + cairo_test_log (ctx, "%d %d .HERE!\n", (int)i, (int)j); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (unbounded_operator, + "Operators with an effect for transparent source/mask", + "operator", /* keywords */ + NULL, /* requirements */ + IMAGE_WIDTH, IMAGE_HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/unclosed-strokes.c b/local/recipes/libs/cairo/source/test/unclosed-strokes.c new file mode 100644 index 0000000000..40a76eb6ba --- /dev/null +++ b/local/recipes/libs/cairo/source/test/unclosed-strokes.c @@ -0,0 +1,83 @@ +/* + * Copyright © 2011 Intel Corporation + * + * 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: Chris Wilson + */ + +#include "cairo-test.h" + +#define LINE_WIDTH 10. +#define SIZE (5 * LINE_WIDTH) +#define PAD (2 * LINE_WIDTH) + +static void +make_path (cairo_t *cr) +{ + cairo_move_to (cr, 0, 0); + cairo_rel_line_to (cr, -SIZE/2, SIZE); + cairo_rel_line_to (cr, SIZE, 0); + /* back to the start, but do not close */ + cairo_rel_line_to (cr, -SIZE/2, -SIZE); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_save (cr); + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + cairo_restore (cr); + + cairo_set_line_width (cr, LINE_WIDTH); + cairo_translate (cr, PAD + SIZE / 2., PAD); + + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_BEVEL); + make_path (cr); + cairo_stroke (cr); + + cairo_translate (cr, 0, SIZE + PAD); + + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); + make_path (cr); + cairo_stroke (cr); + + cairo_translate (cr, 0, SIZE + PAD); + + cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER); + make_path (cr); + cairo_stroke (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (unclosed_strokes, + "Test coincident end-points are capped and not joined", + "stroke, caps", /* keywords */ + NULL, /* requirements */ + PAD + SIZE + PAD, + 3 * (PAD + SIZE) + PAD, + NULL, draw) + diff --git a/local/recipes/libs/cairo/source/test/update-refs.sh b/local/recipes/libs/cairo/source/test/update-refs.sh new file mode 100755 index 0000000000..104eeb8d95 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/update-refs.sh @@ -0,0 +1,84 @@ +#!/bin/bash + +# This script can be used to update the reference images using certain +# test results as a baseline. +# +# Our test suite expects nearly pixel-perfection, but in some cases we +# give the renderer some flexibility and so these cases will show up as +# test failures. So, this script can be used to do a visual check and +# if they "look" ok, to go ahead and update the reference image by +# copying the test output. +# +# NOTE: When adding to this file, make sure to thoroughly document the +# rationale when and why the existing reference images can be updated +# from regular test output, such that people other than you can +# intelligently keep the test reference images updated. + +if [ ! -d output ] || [ ! -d reference ]; then + echo "This script must be run in cairo's test directory after the full testsuite has been run." + exit +fi + +PDIFF="./pdiff/perceptualdiff" + +# Returns 1 if images are different, 0 if they're essentially identical +images_differ() { + # Check if bytewise identical + if cmp --silent "${1}" "${2}"; then + # Images are identical + return 0 + fi + + # Run perceptualdiff with minimum threshold + pdiff_output=$($PDIFF "${1}" "${2}" -threshold 1) + result=${pdiff_output%:*} + notes=$(echo "${pdiff_output#*: }" | tail -n 1) + if [ "$result" = "PASS" ] && [ "$notes" = "Images are binary identical" ]; then + return 0 + fi + + return 1 +} + +# ---------------------------------------------------------------------- +# pixman-downscale images +# +# The *-95 tests check rendering at a difficult to downsize dimension. +# The border pixels between different colored areas can be blurred in +# different ways resulting in some color variation that is acceptable +# but throws off the testsuite. So a visual check is sufficient to +# verify the results aren't crazily off. + +# Use the ARGB32 format of the image file as the main reference +for file in $(ls ./output/pixman-downscale-*-95.image.argb32.out.png); do + dest=$(basename ${file/.image.argb32.out./.ref.}) + echo "$file -> ./reference/${dest}" + cp $file ./reference/${dest} +done +echo + +# If the ARGB32 format of a given backend's file differs from the main reference, +# then use it as the backend reference +for file in $(ls ./output/pixman-downscale-*-95.*.argb32.out.png); do + ref=$(basename ${file/-95.*.argb32.out.png/-95.ref.png}) + if ! images_differ "./reference/${ref}" "${file}"; then + dest=$(basename ${file/.argb32.out.png/.ref.png}) + echo "${file} -> ./reference/${dest}" + cp ${file} ./reference/${dest} + fi +done +echo + +# If the RGB24 format differs from existing ref image, then use it as a ref. +for file in $(ls ./output/pixman-downscale-*-95.*.rgb24.out.png); do + ref=$(basename ${file/.rgb24.out.png/.ref.png}) + if [ ! -e "./reference/${ref}" ]; then + ref=$(basename ${file/-95.*.rgb24.out.png/-95.ref.png}) + fi + + if ! images_differ "./reference/${ref}" "${file}"; then + dest=$(basename ${file/.rgb24.out.png/.rgb24.ref.png}) + echo "${file} -> ./reference/${dest}" + cp ${file} ./reference/${dest} + fi +done diff --git a/local/recipes/libs/cairo/source/test/user-data.c b/local/recipes/libs/cairo/source/test/user-data.c new file mode 100644 index 0000000000..532107aa2e --- /dev/null +++ b/local/recipes/libs/cairo/source/test/user-data.c @@ -0,0 +1,110 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Kristian Høgsberg + */ + +#include "cairo-test.h" + +#include + +static void +destroy_data1 (void *p) +{ + *(int *) p = 1; +} + +static void +destroy_data2 (void *p) +{ + *(int *) p = 2; +} + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + static const cairo_user_data_key_t key1, key2; + cairo_surface_t *surface; + cairo_status_t status; + int data1, data2; + + data1 = 0; + data2 = 0; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1); + status = cairo_surface_set_user_data (surface, &key1, &data1, destroy_data1); + if (status) + goto error; + + status = cairo_surface_set_user_data (surface, &key2, &data2, destroy_data2); + if (status) + goto error; + + assert (cairo_surface_get_user_data (surface, &key1) == &data1); + status = cairo_surface_set_user_data (surface, &key1, NULL, NULL); + if (status) + goto error; + + assert (cairo_surface_get_user_data (surface, &key1) == NULL); + assert (data1 == 1); + assert (data2 == 0); + + status = cairo_surface_set_user_data (surface, &key2, NULL, NULL); + if (status) + goto error; + + assert (data2 == 2); + + data1 = 0; + status = cairo_surface_set_user_data (surface, &key1, &data1, NULL); + if (status) + goto error; + + status = cairo_surface_set_user_data (surface, &key1, NULL, NULL); + if (status) + goto error; + + assert (data1 == 0); + assert (cairo_surface_get_user_data (surface, &key1) == NULL); + + status = cairo_surface_set_user_data (surface, &key1, &data1, destroy_data1); + if (status) + goto error; + + cairo_surface_destroy (surface); + + assert (data1 == 1); + assert (data2 == 2); + + return CAIRO_TEST_SUCCESS; + +error: + cairo_surface_destroy (surface); + return cairo_test_status_from_status (ctx, status); +} + +CAIRO_TEST (user_data, + "Test setting and getting random bits of user data.", + "api", /* keywords */ + NULL, /* requirements */ + 0, 0, + preamble, NULL) diff --git a/local/recipes/libs/cairo/source/test/user-font-color.c b/local/recipes/libs/cairo/source/test/user-font-color.c new file mode 100644 index 0000000000..db8b6a1737 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/user-font-color.c @@ -0,0 +1,355 @@ +/* + * Copyright © 2006, 2008 Red Hat, Inc. + * Copyright © 2021 Adrian Johnson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Contributor(s): + * Kristian Høgsberg + * Behdad Esfahbod + */ + +/* Test that user-fonts can handle color and non-color glyphs in the + * same font. + */ + +#include "cairo-test.h" + +#include +#include +#include + + +#define BORDER 10 +#define TEXT_SIZE 64 +#define WIDTH (TEXT_SIZE * 11 + 2*BORDER) +#define HEIGHT (4*TEXT_SIZE + 5*BORDER) + +#define TEXT "abcdefghij" + +/* These characters will be drawn twice with a different foreground color */ +#define FG_TEXT "acfh" + +/* Uppercase draws the same text but forces the use of the non-color + * render callback */ +#define TEXT_NO_COLOR "ABCDEFGHIJ" +#define FG_TEXT_NO_COLOR "ACFH" + +#define TEXT_PATH "aabccdeffghhij" + + +static cairo_status_t +test_scaled_font_init (cairo_scaled_font_t *scaled_font, + cairo_t *cr, + cairo_font_extents_t *metrics) +{ + metrics->ascent = .75; + metrics->descent = .25; + return CAIRO_STATUS_SUCCESS; +} + +static void +render_glyph_solid (cairo_t *cr, + double width, + double height, + cairo_bool_t color, + cairo_scaled_font_t *scaled_font) +{ + if (color) + cairo_set_source_rgba (cr, 0.7, 0.2, 0.1, 0.9); + cairo_rectangle (cr, 0, 0, width/2, height/2); + cairo_fill (cr); + + if (color) { + if (scaled_font) + cairo_set_source (cr, cairo_user_scaled_font_get_foreground_marker (scaled_font)); + else + cairo_set_source_rgba (cr, 0.2, 0.5, 0.3, 0.9); + } + cairo_rectangle (cr, width/4, height/4, width/2, height/2); + cairo_fill (cr); + + if (color) + cairo_set_source_rgba (cr, 0.2, 0.3, 0.5, 0.9); + cairo_rectangle (cr, width/2, height/2, width/2, height/2); + cairo_fill (cr); +} + +static void +render_glyph_linear (cairo_t *cr, + double width, + double height, + cairo_bool_t color, + cairo_scaled_font_t *scaled_font) +{ + cairo_pattern_t *pat; + cairo_pattern_t *fg; + + pat = cairo_pattern_create_linear (0.0, 0.0, width, height); + if (scaled_font) { + double r, g, b, a; + + fg = cairo_user_scaled_font_get_foreground_source (scaled_font); + if (cairo_pattern_get_rgba (fg, &r, &g, &b, &a) != CAIRO_STATUS_SUCCESS) { + r = g = b = 0; + a = 1; + } + cairo_pattern_add_color_stop_rgba (pat, 0, r, g, b, a); + cairo_pattern_add_color_stop_rgb (pat, 1, 0, 0, 1); + } else { + cairo_pattern_add_color_stop_rgb (pat, 0, 1, 0.4, 0.2); + cairo_pattern_add_color_stop_rgb (pat, 0.5, 0.2, 1, 0.4); + cairo_pattern_add_color_stop_rgb (pat, 1, 0.2, 0.3, 1); + } + + cairo_set_source (cr, pat); + cairo_rectangle (cr, 0, 0, width, height); + cairo_fill (cr); +} + +static void +render_glyph_text (cairo_t *cr, double width, double height, cairo_bool_t color) +{ + cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size(cr, 0.5); + + if (color) + cairo_set_source_rgb (cr, 0.5, 0.7, 0); + cairo_move_to (cr, width*0.1, height/2); + cairo_show_text (cr, "a"); + + if (color) + cairo_set_source_rgb (cr, 0, 0.5, 0.7); + cairo_move_to (cr, width*0.4, height*0.9); + cairo_show_text (cr, "z"); +} + +static cairo_status_t +test_scaled_font_render_glyph_common (cairo_scaled_font_t *scaled_font, + unsigned long glyph, + cairo_t *cr, + cairo_text_extents_t *metrics, + cairo_bool_t color) +{ + double width = 0.5; + double height = 0.8; + + metrics->x_advance = 0.75; + cairo_translate (cr, 0.125, -0.6); + switch (glyph) { + case 'a': + render_glyph_solid (cr, width, height, color, scaled_font); + break; + case 'b': + render_glyph_solid (cr, width, height, color, NULL); + break; + case 'c': + render_glyph_linear (cr, width, height, color, scaled_font); + break; + case 'd': + render_glyph_linear (cr, width, height, color, NULL); + break; + case 'e': + render_glyph_text (cr, width, height, color); + break; + case 'f': + cairo_push_group (cr); + render_glyph_solid (cr, width, height, color, scaled_font); + cairo_pop_group_to_source (cr); + cairo_paint (cr); + break; + case 'g': + cairo_push_group (cr); + render_glyph_solid (cr, width, height, color, NULL); + cairo_pop_group_to_source (cr); + cairo_paint (cr); + break; + case 'h': + cairo_push_group (cr); + render_glyph_linear (cr, width, height, color, scaled_font); + cairo_pop_group_to_source (cr); + cairo_paint (cr); + break; + case 'i': + cairo_push_group (cr); + render_glyph_linear (cr, width, height, color, NULL); + cairo_pop_group_to_source (cr); + cairo_paint (cr); + break; + case 'j': + cairo_push_group (cr); + render_glyph_text (cr, width, height, color); + cairo_pop_group_to_source (cr); + cairo_paint (cr); + break; + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +test_scaled_font_render_color_glyph_callback (cairo_scaled_font_t *scaled_font, + unsigned long glyph, + cairo_t *cr, + cairo_text_extents_t *metrics) +{ + if (isupper(glyph)) + return CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED; + + return test_scaled_font_render_glyph_common (scaled_font, glyph, cr, metrics, TRUE); +} + +static cairo_status_t +test_scaled_font_render_glyph_callback (cairo_scaled_font_t *scaled_font, + unsigned long glyph, + cairo_t *cr, + cairo_text_extents_t *metrics) +{ + int c = glyph; + if (isupper(c)) + c = tolower(c); + + return test_scaled_font_render_glyph_common (scaled_font, c, cr, metrics, FALSE); +} + +static cairo_status_t +_user_font_face_create (cairo_font_face_t **out) +{ + + cairo_font_face_t *user_font_face; + + user_font_face = cairo_user_font_face_create (); + cairo_user_font_face_set_init_func (user_font_face, test_scaled_font_init); + cairo_user_font_face_set_render_color_glyph_func (user_font_face, + test_scaled_font_render_color_glyph_callback); + cairo_user_font_face_set_render_glyph_func (user_font_face, + test_scaled_font_render_glyph_callback); + + *out = user_font_face; + return CAIRO_STATUS_SUCCESS; +} + +/* Any text characters that are in fg_text will be drawn with a different color */ +static void +draw_line (cairo_t *cr, const char *text, const char *fg_text) +{ + char buf[10]; + + for (unsigned i = 0; i < strlen(text); i++) { + buf[0] = text[i]; + buf[1] = 0; + + if (strchr (fg_text, text[i])) { + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_show_text (cr, buf); + } + + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_show_text (cr, buf); + } +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_font_face_t *font_face; + const char text[] = TEXT; + cairo_font_extents_t font_extents; + cairo_text_extents_t extents; + cairo_status_t status; + cairo_font_options_t *font_options; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + status = _user_font_face_create (&font_face); + if (status) { + return cairo_test_status_from_status (cairo_test_get_context (cr), + status); + } + + cairo_set_font_face (cr, font_face); + cairo_font_face_destroy (font_face); + + cairo_set_font_size (cr, TEXT_SIZE); + + cairo_font_extents (cr, &font_extents); + cairo_text_extents (cr, text, &extents); + + /* logical boundaries in red */ + cairo_move_to (cr, 0, BORDER); + cairo_rel_line_to (cr, WIDTH, 0); + cairo_move_to (cr, 0, BORDER + font_extents.ascent); + cairo_rel_line_to (cr, WIDTH, 0); + cairo_move_to (cr, 0, BORDER + font_extents.ascent + font_extents.descent); + cairo_rel_line_to (cr, WIDTH, 0); + cairo_move_to (cr, BORDER, 0); + cairo_rel_line_to (cr, 0, 2*BORDER + TEXT_SIZE); + cairo_move_to (cr, BORDER + extents.x_advance, 0); + cairo_rel_line_to (cr, 0, 2*BORDER + TEXT_SIZE); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_set_line_width (cr, 2); + cairo_stroke (cr); + + /* ink boundaries in green */ + cairo_rectangle (cr, + BORDER + extents.x_bearing, BORDER + font_extents.ascent + extents.y_bearing, + extents.width, extents.height); + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_set_line_width (cr, 2); + cairo_stroke (cr); + + /* Line 1: text in color */ + cairo_move_to (cr, BORDER, BORDER + font_extents.ascent); + draw_line (cr, TEXT, FG_TEXT); + + /* Line 2: text in non-color (color render callback returns + * CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED. + */ + cairo_move_to (cr, BORDER, BORDER + font_extents.height + 1*BORDER + font_extents.ascent); + draw_line (cr, TEXT_NO_COLOR, FG_TEXT_NO_COLOR); + + /* Line 3: Filled version of color text in blue */ + cairo_move_to (cr, BORDER, BORDER + 2*font_extents.height + 2*BORDER + font_extents.ascent); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_text_path (cr, TEXT_PATH); + cairo_fill (cr); + + /* Line 4: color glyphs with CAIRO_COLOR_MODE_NO_COLOR font option. */ + font_options = cairo_font_options_create (); + cairo_get_font_options (cr, font_options); + 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_move_to (cr, BORDER, BORDER + 3*font_extents.height + 3*BORDER + font_extents.ascent); + draw_line (cr, TEXT, FG_TEXT); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (user_font_color, + "Tests user font color feature", + "font, user-font", /* keywords */ + "cairo >= 1.17.4", /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/user-font-mask.c b/local/recipes/libs/cairo/source/test/user-font-mask.c new file mode 100644 index 0000000000..cf548e6496 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/user-font-mask.c @@ -0,0 +1,253 @@ +/* + * Copyright © 2006, 2008 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Contributor(s): + * Kristian Høgsberg + * Behdad Esfahbod + * Adrian Johnson + */ + +#include "cairo-test.h" + +#include +#include + +/*#define ROTATED 1*/ + +#define BORDER 10 +#define TEXT_SIZE 64 +#define WIDTH (TEXT_SIZE * 15 + 2*BORDER) +#ifndef ROTATED + #define HEIGHT ((TEXT_SIZE + 2*BORDER)*2) +#else + #define HEIGHT WIDTH +#endif +#define END_GLYPH 0 +#define TEXT "cairo" + +/* Reverse the bits in a byte with 7 operations (no 64-bit): + * Devised by Sean Anderson, July 13, 2001. + * Source: http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith32Bits + */ +#define CAIRO_BITSWAP8(c) ((((c) * 0x0802LU & 0x22110LU) | ((c) * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16) + +#ifdef WORDS_BIGENDIAN +#define CAIRO_BITSWAP8_IF_LITTLE_ENDIAN(c) (c) +#else +#define CAIRO_BITSWAP8_IF_LITTLE_ENDIAN(c) CAIRO_BITSWAP8(c) +#endif + + + +/* Simple glyph definition. data is an 8x8 bitmap. + */ +typedef struct { + unsigned long ucs4; + int width; + char data[8]; +} test_scaled_font_glyph_t; + +static cairo_user_data_key_t test_font_face_glyphs_key; + +static cairo_status_t +test_scaled_font_init (cairo_scaled_font_t *scaled_font, + cairo_t *cr, + cairo_font_extents_t *metrics) +{ + metrics->ascent = 1; + metrics->descent = 0; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +test_scaled_font_unicode_to_glyph (cairo_scaled_font_t *scaled_font, + unsigned long unicode, + unsigned long *glyph) +{ + test_scaled_font_glyph_t *glyphs = cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font), + &test_font_face_glyphs_key); + int i; + + for (i = 0; glyphs[i].ucs4 != (unsigned long) -1; i++) + if (glyphs[i].ucs4 == unicode) { + *glyph = i; + return CAIRO_STATUS_SUCCESS; + } + + /* Not found. Default to glyph 0 */ + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +test_scaled_font_render_glyph (cairo_scaled_font_t *scaled_font, + unsigned long glyph, + cairo_t *cr, + cairo_text_extents_t *metrics) +{ + test_scaled_font_glyph_t *glyphs = cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font), + &test_font_face_glyphs_key); + int i; + unsigned char *data; + cairo_surface_t *image; + cairo_pattern_t *pattern; + cairo_matrix_t matrix; + uint8_t byte; + + /* FIXME: We simply crash on out-of-bound glyph indices */ + + metrics->x_advance = (glyphs[glyph].width + 1) / 8.0; + + image = cairo_image_surface_create (CAIRO_FORMAT_A1, glyphs[glyph].width, 8); + if (cairo_surface_status (image)) + return cairo_surface_status (image); + + data = cairo_image_surface_get_data (image); + for (i = 0; i < 8; i++) { + byte = glyphs[glyph].data[i]; + *data = CAIRO_BITSWAP8_IF_LITTLE_ENDIAN (byte); + data += cairo_image_surface_get_stride (image); + } + cairo_surface_mark_dirty (image); + + pattern = cairo_pattern_create_for_surface (image); + cairo_surface_destroy (image); + + cairo_matrix_init_identity (&matrix); + cairo_matrix_scale (&matrix, 1.0/8.0, 1.0/8.0); + cairo_matrix_translate (&matrix, 0, -8); + cairo_matrix_invert (&matrix); + cairo_pattern_set_matrix (pattern, &matrix); + + cairo_set_source (cr, pattern); + cairo_mask (cr, pattern); + cairo_pattern_destroy (pattern); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_user_font_face_create (cairo_font_face_t **out) +{ + static const test_scaled_font_glyph_t glyphs [] = { + { 'c', 6, { 0x00, 0x38, 0x44, 0x80, 0x80, 0x80, 0x44, 0x38 } }, + { 'a', 6, { 0x00, 0x70, 0x88, 0x3c, 0x44, 0x84, 0x8c, 0x74 } }, + { 'i', 1, { 0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 } }, + { 'r', 6, { 0x00, 0xb8, 0xc4, 0x80, 0x80, 0x80, 0x80, 0x80 } }, + { 'o', 7, { 0x00, 0x38, 0x44, 0x82, 0x82, 0x82, 0x44, 0x38 } }, + { -1, 8, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + }; + + cairo_font_face_t *user_font_face; + cairo_status_t status; + + user_font_face = cairo_user_font_face_create (); + cairo_user_font_face_set_init_func (user_font_face, test_scaled_font_init); + cairo_user_font_face_set_render_glyph_func (user_font_face, test_scaled_font_render_glyph); + cairo_user_font_face_set_unicode_to_glyph_func (user_font_face, test_scaled_font_unicode_to_glyph); + + status = cairo_font_face_set_user_data (user_font_face, + &test_font_face_glyphs_key, + (void*) glyphs, NULL); + if (status) { + cairo_font_face_destroy (user_font_face); + return status; + } + + *out = user_font_face; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_font_face_t *font_face; + const char text[] = TEXT; + cairo_font_extents_t font_extents; + cairo_text_extents_t extents; + cairo_status_t status; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + +#ifdef ROTATED + cairo_translate (cr, TEXT_SIZE, 0); + cairo_rotate (cr, .6); +#endif + + status = _user_font_face_create (&font_face); + if (status) { + return cairo_test_status_from_status (cairo_test_get_context (cr), + status); + } + + cairo_set_font_face (cr, font_face); + cairo_font_face_destroy (font_face); + + cairo_set_font_size (cr, TEXT_SIZE); + + cairo_font_extents (cr, &font_extents); + cairo_text_extents (cr, text, &extents); + + /* logical boundaries in red */ + cairo_move_to (cr, 0, BORDER); + cairo_rel_line_to (cr, WIDTH, 0); + cairo_move_to (cr, 0, BORDER + font_extents.ascent); + cairo_rel_line_to (cr, WIDTH, 0); + cairo_move_to (cr, 0, BORDER + font_extents.ascent + font_extents.descent); + cairo_rel_line_to (cr, WIDTH, 0); + cairo_move_to (cr, BORDER, 0); + cairo_rel_line_to (cr, 0, 2*BORDER + TEXT_SIZE); + cairo_move_to (cr, BORDER + extents.x_advance, 0); + cairo_rel_line_to (cr, 0, 2*BORDER + TEXT_SIZE); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_set_line_width (cr, 2); + cairo_stroke (cr); + + /* ink boundaries in green */ + cairo_rectangle (cr, + BORDER + extents.x_bearing, BORDER + font_extents.ascent + extents.y_bearing, + extents.width, extents.height); + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_set_line_width (cr, 2); + cairo_stroke (cr); + + /* text in black */ + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_move_to (cr, BORDER, BORDER + font_extents.ascent); + cairo_show_text (cr, text); + + + /* filled version of text in blue */ + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_move_to (cr, BORDER, BORDER + font_extents.height + 2*BORDER + font_extents.ascent); + cairo_text_path (cr, text); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (user_font_mask, + "Tests a user-font using cairo_mask with bitmap images", + "user-font, mask", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/user-font-proxy.c b/local/recipes/libs/cairo/source/test/user-font-proxy.c new file mode 100644 index 0000000000..42f51b6028 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/user-font-proxy.c @@ -0,0 +1,239 @@ +/* + * Copyright © 2006, 2008 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Contributor(s): + * Kristian Høgsberg + * Behdad Esfahbod + */ + +#include "cairo-test.h" + +#include +#include + +/*#define ROTATED 1*/ + +#define BORDER 10 +#define TEXT_SIZE 64 +#define WIDTH (TEXT_SIZE * 12 + 2*BORDER) +#ifndef ROTATED + #define HEIGHT ((TEXT_SIZE + 2*BORDER)*2) +#else + #define HEIGHT WIDTH +#endif + +#define TEXT1 "cairo user-font." +#define TEXT2 " zg" + +static cairo_user_data_key_t fallback_font_key; + +static cairo_status_t +test_scaled_font_init (cairo_scaled_font_t *scaled_font, + cairo_t *cr, + cairo_font_extents_t *extents) +{ + cairo_status_t status; + + cairo_set_font_face (cr, + cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font), + &fallback_font_key)); + + status = cairo_scaled_font_set_user_data (scaled_font, + &fallback_font_key, + cairo_scaled_font_reference (cairo_get_scaled_font (cr)), + (cairo_destroy_func_t) cairo_scaled_font_destroy); + if (unlikely (status)) { + cairo_scaled_font_destroy (cairo_get_scaled_font (cr)); + return status; + } + + cairo_font_extents (cr, extents); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +test_scaled_font_render_glyph (cairo_scaled_font_t *scaled_font, + unsigned long glyph, + cairo_t *cr, + cairo_text_extents_t *extents) +{ + cairo_glyph_t cairo_glyph; + + cairo_glyph.index = glyph; + cairo_glyph.x = 0; + cairo_glyph.y = 0; + + cairo_set_font_face (cr, + cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font), + &fallback_font_key)); + + cairo_show_glyphs (cr, &cairo_glyph, 1); + cairo_glyph_extents (cr, &cairo_glyph, 1, extents); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +test_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font, + const char *utf8, + int utf8_len, + cairo_glyph_t **glyphs, + int *num_glyphs, + cairo_text_cluster_t **clusters, + int *num_clusters, + cairo_text_cluster_flags_t *cluster_flags) +{ + cairo_scaled_font_t *fallback_scaled_font; + + fallback_scaled_font = cairo_scaled_font_get_user_data (scaled_font, + &fallback_font_key); + + return cairo_scaled_font_text_to_glyphs (fallback_scaled_font, 0, 0, + utf8, utf8_len, + glyphs, num_glyphs, + clusters, num_clusters, cluster_flags); +} + +static cairo_status_t +_user_font_face_create (cairo_font_face_t **out) +{ + cairo_font_face_t *user_font_face; + cairo_font_face_t *fallback_font_face; + cairo_status_t status; + + user_font_face = cairo_user_font_face_create (); + cairo_user_font_face_set_init_func (user_font_face, test_scaled_font_init); + cairo_user_font_face_set_render_glyph_func (user_font_face, test_scaled_font_render_glyph); + cairo_user_font_face_set_text_to_glyphs_func (user_font_face, test_scaled_font_text_to_glyphs); + + /* This also happens to be default font face on cairo_t, so does + * not make much sense here. For demonstration only. + */ + fallback_font_face = cairo_toy_font_face_create (CAIRO_TEST_FONT_FAMILY " Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + + status = cairo_font_face_set_user_data (user_font_face, + &fallback_font_key, + fallback_font_face, + (cairo_destroy_func_t) cairo_font_face_destroy); + if (status) { + cairo_font_face_destroy (fallback_font_face); + cairo_font_face_destroy (user_font_face); + return status; + } + + *out = user_font_face; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_font_extents_t font_extents; + cairo_text_extents_t extents; + cairo_font_face_t *font_face; + cairo_status_t status; + char full_text[100]; + + strcpy(full_text, TEXT1); + strcat(full_text, TEXT2); + strcat(full_text, TEXT2); + strcat(full_text, TEXT2); + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + +#ifdef ROTATED + cairo_translate (cr, TEXT_SIZE, 0); + cairo_rotate (cr, .6); +#endif + + status = _user_font_face_create (&font_face); + if (status) { + return cairo_test_status_from_status (cairo_test_get_context (cr), + status); + } + + cairo_set_font_face (cr, font_face); + cairo_font_face_destroy (font_face); + + cairo_set_font_size (cr, TEXT_SIZE); + + cairo_font_extents (cr, &font_extents); + cairo_text_extents (cr, full_text, &extents); + + /* logical boundaries in red */ + cairo_move_to (cr, 0, BORDER); + cairo_rel_line_to (cr, WIDTH, 0); + cairo_move_to (cr, 0, BORDER + font_extents.ascent); + cairo_rel_line_to (cr, WIDTH, 0); + cairo_move_to (cr, 0, BORDER + font_extents.ascent + font_extents.descent); + cairo_rel_line_to (cr, WIDTH, 0); + cairo_move_to (cr, BORDER, 0); + cairo_rel_line_to (cr, 0, 2*BORDER + TEXT_SIZE); + cairo_move_to (cr, BORDER + extents.x_advance, 0); + cairo_rel_line_to (cr, 0, 2*BORDER + TEXT_SIZE); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_set_line_width (cr, 2); + cairo_stroke (cr); + + /* ink boundaries in green */ + cairo_rectangle (cr, + BORDER + extents.x_bearing, BORDER + font_extents.ascent + extents.y_bearing, + extents.width, extents.height); + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_set_line_width (cr, 2); + cairo_stroke (cr); + + + /* TEXT1 in black */ + cairo_move_to (cr, BORDER, BORDER + font_extents.ascent); + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_show_text (cr, TEXT1); + + /* Draw TEXT2 three times with three different foreground colors. + * This checks that cairo uses the foreground color and does not cache + * glyph images when the foreground color changes. + */ + cairo_show_text (cr, TEXT2); + cairo_set_source_rgb (cr, 0, 0.5, 0); + cairo_show_text (cr, TEXT2); + cairo_set_source_rgb (cr, 0.2, 0.5, 0.5); + cairo_show_text (cr, TEXT2); + + /* filled version of text in light blue */ + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_move_to (cr, BORDER, BORDER + font_extents.height + BORDER + font_extents.ascent); + cairo_text_path (cr, full_text); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (user_font_proxy, + "Tests a user-font using a native font in its render_glyph", + "font, user-font", /* keywords */ + "cairo >= 1.7.4", /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/user-font-rescale.c b/local/recipes/libs/cairo/source/test/user-font-rescale.c new file mode 100644 index 0000000000..6f03b8e663 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/user-font-rescale.c @@ -0,0 +1,368 @@ +/* + * Copyright © 2008 Jeff Muizelaar + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Jeff Muizelaar not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Jeff Muizelaar makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * JEFF MUIZELAAR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL JEFF MUIZELAAR BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Contributor(s): + * Jeff Muizelaar + * Kristian Høgsberg + * Behdad Esfahbod + */ + +#include "cairo-test.h" + +#include + +#define BORDER 10 +#define TEXT_SIZE 32 +#define WIDTH (TEXT_SIZE * 13.75 + 2*BORDER) +#define HEIGHT ((TEXT_SIZE + 2*BORDER)*3 + BORDER) +#define TEXT "test of rescaled glyphs" + +static const cairo_user_data_key_t rescale_font_closure_key; + +struct rescaled_font { + cairo_font_face_t *substitute_font; + cairo_scaled_font_t *measuring_font; + unsigned long glyph_count; + unsigned long start; + double *desired_width; + double *rescale_factor; +}; + +static cairo_status_t +test_scaled_font_render_glyph (cairo_scaled_font_t *scaled_font, + unsigned long glyph, + cairo_t *cr, + cairo_text_extents_t *metrics) +{ + cairo_font_face_t *user_font; + struct rescaled_font *r; + cairo_glyph_t cairo_glyph; + + cairo_glyph.index = glyph; + cairo_glyph.x = 0; + cairo_glyph.y = 0; + + user_font = cairo_scaled_font_get_font_face (scaled_font); + r = cairo_font_face_get_user_data (user_font, &rescale_font_closure_key); + cairo_set_font_face (cr, r->substitute_font); + + if (glyph - r->start < r->glyph_count) { + cairo_matrix_t matrix; + + if (isnan (r->rescale_factor[glyph - r->start])) { + double desired_width; + double actual_width; + cairo_text_extents_t extents; + + /* measure the glyph and compute the necessary rescaling factor */ + cairo_scaled_font_glyph_extents (r->measuring_font, + &cairo_glyph, 1, + &extents); + + desired_width = r->desired_width[glyph - r->start]; + actual_width = extents.x_advance; + + r->rescale_factor[glyph - r->start] = desired_width / actual_width; + } + + /* scale the font so that the glyph width matches the desired width */ + cairo_get_font_matrix (cr, &matrix); + cairo_matrix_scale (&matrix, r->rescale_factor[glyph - r->start], 1.); + cairo_set_font_matrix (cr, &matrix); + } + + cairo_show_glyphs (cr, &cairo_glyph, 1); + cairo_glyph_extents (cr, &cairo_glyph, 1, metrics); + + return CAIRO_STATUS_SUCCESS; +} + +static void +unichar_to_utf8 (uint32_t ucs4, char utf8[7]) +{ + int i, charlen, first; + + if (ucs4 < 0x80) { + first = 0; + charlen = 1; + } else if (ucs4 < 0x800) { + first = 0xc0; + charlen = 2; + } else if (ucs4 < 0x10000) { + first = 0xe0; + charlen = 3; + } else if (ucs4 < 0x200000) { + first = 0xf0; + charlen = 4; + } else if (ucs4 < 0x4000000) { + first = 0xf8; + charlen = 5; + } else { + first = 0xfc; + charlen = 6; + } + + for (i = charlen - 1; i > 0; --i) { + utf8[i] = (ucs4 & 0x3f) | 0x80; + ucs4 >>= 6; + } + utf8[0] = ucs4 | first; + utf8[charlen] = '\0'; +} + +static cairo_status_t +test_scaled_font_unicode_to_glyph (cairo_scaled_font_t *scaled_font, + unsigned long unicode, + unsigned long *glyph_index) +{ + cairo_font_face_t *user_font; + struct rescaled_font *r; + int num_glyphs; + cairo_glyph_t *glyphs = NULL; + cairo_status_t status; + char utf8[7]; + + user_font = cairo_scaled_font_get_font_face (scaled_font); + + unichar_to_utf8 (unicode, utf8); + r = cairo_font_face_get_user_data (user_font, &rescale_font_closure_key); + status = cairo_scaled_font_text_to_glyphs (r->measuring_font, 0, 0, + utf8, -1, + &glyphs, &num_glyphs, + NULL, NULL, NULL); + if (status) + return status; + + *glyph_index = glyphs[0].index; + + cairo_glyph_free (glyphs); + return CAIRO_STATUS_SUCCESS; +} + +static void rescale_font_closure_destroy (void *data) +{ + struct rescaled_font *r = data; + + cairo_font_face_destroy (r->substitute_font); + cairo_scaled_font_destroy (r->measuring_font); + free (r->desired_width); + free (r->rescale_factor); + free (r); +} + +static cairo_status_t +create_rescaled_font (cairo_font_face_t *substitute_font, + int glyph_start, + int glyph_count, + double *desired_width, + cairo_font_face_t **out) +{ + cairo_font_face_t *user_font_face; + struct rescaled_font *r; + cairo_font_options_t *options; + cairo_status_t status; + cairo_matrix_t m; + unsigned long i; + + user_font_face = cairo_user_font_face_create (); + cairo_user_font_face_set_render_glyph_func (user_font_face, test_scaled_font_render_glyph); + cairo_user_font_face_set_unicode_to_glyph_func (user_font_face, test_scaled_font_unicode_to_glyph); + + r = xmalloc (sizeof (struct rescaled_font)); + r->substitute_font = cairo_font_face_reference (substitute_font); + + /* we don't want any hinting when doing the measuring */ + options = cairo_font_options_create (); + cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE); + cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF); + + cairo_matrix_init_identity (&m); + + r->measuring_font = cairo_scaled_font_create (r->substitute_font, + &m, &m, + options); + cairo_font_options_destroy (options); + + + r->start = glyph_start; + r->glyph_count = glyph_count; + r->desired_width = xcalloc (sizeof (double), r->glyph_count); + r->rescale_factor = xcalloc (sizeof (double), r->glyph_count); + + for (i = 0; i < r->glyph_count; i++) { + r->desired_width[i] = desired_width[i]; + /* use NaN to specify unset */ + r->rescale_factor[i] = cairo_test_NaN (); + } + + status = cairo_font_face_set_user_data (user_font_face, + &rescale_font_closure_key, + r, rescale_font_closure_destroy); + if (status) { + rescale_font_closure_destroy (r); + cairo_font_face_destroy (user_font_face); + return status; + } + + *out = user_font_face; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +get_user_font_face (cairo_font_face_t *substitute_font, + const char *text, + cairo_font_face_t *old, + cairo_font_face_t **out) +{ + cairo_font_options_t *options; + cairo_matrix_t m; + cairo_scaled_font_t *measure; + int i; + double *widths; + int count; + int num_glyphs; + unsigned long min_index, max_index; + cairo_status_t status; + + cairo_glyph_t *glyphs = NULL; + + /* we don't want any hinting when doing the measuring */ + options = cairo_font_options_create (); + cairo_font_options_set_hint_style (options, CAIRO_HINT_STYLE_NONE); + cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF); + + cairo_matrix_init_identity (&m); + measure = cairo_scaled_font_create (old, &m, &m, options); + + status = cairo_scaled_font_text_to_glyphs (measure, 0, 0, + text, -1, + &glyphs, &num_glyphs, + NULL, NULL, NULL); + cairo_font_options_destroy (options); + + if (status) { + cairo_scaled_font_destroy (measure); + return status; + } + + /* find the glyph range the text covers */ + max_index = glyphs[0].index; + min_index = glyphs[0].index; + for (i=0; i max_index) + max_index = glyphs[i].index; + } + + count = max_index - min_index + 1; + widths = xcalloc (sizeof (double), count); + /* measure all of the necessary glyphs individually */ + for (i=0; i + */ + +/* Test that user-fonts can subpixel positioning. + */ + +#include "cairo-test.h" + + +#define BORDER 10 +#define REPEAT 16 +#define TEXT_SIZE 24 +#define WIDTH (TEXT_SIZE * REPEAT + 2*BORDER) +#define HEIGHT (TEXT_SIZE + 2*BORDER) + + +static cairo_status_t +test_scaled_font_render_glyph (cairo_scaled_font_t *scaled_font, + unsigned long glyph, + cairo_t *cr, + cairo_text_extents_t *metrics) +{ + cairo_rectangle (cr, 0, .45, 1., .1); + cairo_fill (cr); + return CAIRO_STATUS_SUCCESS; +} + +static cairo_font_face_t * +_user_font_face_create (void) +{ + cairo_font_face_t *user_font_face; + + user_font_face = cairo_user_font_face_create (); + cairo_user_font_face_set_render_glyph_func (user_font_face, test_scaled_font_render_glyph); + + return user_font_face; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_font_face_t *font_face; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + font_face = _user_font_face_create (); + + cairo_set_font_face (cr, font_face); + cairo_font_face_destroy (font_face); + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_set_font_size (cr, TEXT_SIZE); + + for (unsigned i = 0; i < REPEAT; i++) + { + cairo_move_to (cr, BORDER + TEXT_SIZE * i, BORDER + i * .1); + cairo_show_text (cr, "-"); + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (user_font_subpixel, + "Tests user font subpixel rendering", + "font, user-font", /* keywords */ + "cairo >= 1.17.4", /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/user-font.c b/local/recipes/libs/cairo/source/test/user-font.c new file mode 100644 index 0000000000..a8aed23b32 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/user-font.c @@ -0,0 +1,319 @@ +/* + * Copyright © 2006, 2008 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Contributor(s): + * Kristian Høgsberg + * Behdad Esfahbod + */ + +#include "cairo-test.h" + +#include +#include + +/*#define ROTATED 1*/ + +#define BORDER 10 +#define TEXT_SIZE 64 +#define WIDTH (TEXT_SIZE * 16 + 2*BORDER) +#ifndef ROTATED + #define HEIGHT ((TEXT_SIZE + 2*BORDER)*3) +#else + #define HEIGHT WIDTH +#endif + +#define TEXT1 "cairo user-font." +#define TEXT2 " zg" + +#define END_GLYPH 0 +#define STROKE 126 +#define CLOSE 127 + +/* Simple glyph definition: 1 - 15 means lineto (or moveto for first + * point) for one of the points on this grid: + * + * 1 2 3 + * 4 5 6 + * 7 8 9 + * ----10 11 12----(baseline) + * 13 14 15 + */ +typedef struct { + unsigned long ucs4; + int width; + char data[16]; +} test_scaled_font_glyph_t; + +static cairo_user_data_key_t test_font_face_glyphs_key; + +static cairo_status_t +test_scaled_font_init (cairo_scaled_font_t *scaled_font, + cairo_t *cr, + cairo_font_extents_t *metrics) +{ + metrics->ascent = .75; + metrics->descent = .25; + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +test_scaled_font_unicode_to_glyph (cairo_scaled_font_t *scaled_font, + unsigned long unicode, + unsigned long *glyph) +{ + test_scaled_font_glyph_t *glyphs = cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font), + &test_font_face_glyphs_key); + int i; + + for (i = 0; glyphs[i].ucs4 != (unsigned long) -1; i++) + if (glyphs[i].ucs4 == unicode) { + *glyph = i; + return CAIRO_STATUS_SUCCESS; + } + + /* Not found. Default to glyph 0 */ + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +test_scaled_font_render_glyph (cairo_scaled_font_t *scaled_font, + unsigned long glyph, + cairo_t *cr, + cairo_text_extents_t *metrics) +{ + test_scaled_font_glyph_t *glyphs = cairo_font_face_get_user_data (cairo_scaled_font_get_font_face (scaled_font), + &test_font_face_glyphs_key); + int i; + const char *data; + div_t d; + double x, y; + + /* FIXME: We simply crash on out-of-bound glyph indices */ + + metrics->x_advance = glyphs[glyph].width / 4.0; + + cairo_set_line_width (cr, 0.1); + cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + + data = glyphs[glyph].data; + for (i = 0; data[i] != END_GLYPH; i++) { + switch (data[i]) { + case STROKE: + cairo_new_sub_path (cr); + break; + + case CLOSE: + cairo_close_path (cr); + break; + + default: + d = div (data[i] - 1, 3); + x = d.rem / 4.0 + 0.125; + y = d.quot / 5.0 + 0.4 - 1.0; + cairo_line_to (cr, x, y); + } + } + cairo_stroke (cr); + + return CAIRO_STATUS_SUCCESS; +} + + +/* If color_render is TRUE, use the render_color_glyph callback + * instead of the render_glyph callbac. The output should be identical + * in this test since the render function does not alter the cairo_t + * source. + */ +static cairo_status_t +_user_font_face_create (cairo_font_face_t **out, cairo_bool_t color_render) +{ + /* Simple glyph definition: 1 - 15 means lineto (or moveto for first + * point) for one of the points on this grid: + * + * 1 2 3 + * 4 5 6 + * 7 8 9 + * ----10 11 12----(baseline) + * 13 14 15 + */ + static const test_scaled_font_glyph_t glyphs [] = { + { 'a', 3, { 4, 6, 12, 10, 7, 9, STROKE, END_GLYPH } }, + { 'c', 3, { 6, 4, 10, 12, STROKE, END_GLYPH } }, + { 'e', 3, { 12, 10, 4, 6, 9, 7, STROKE, END_GLYPH } }, + { 'f', 3, { 3, 2, 11, STROKE, 4, 6, STROKE, END_GLYPH } }, + { 'g', 3, { 12, 10, 4, 6, 15, 13, STROKE, END_GLYPH } }, + { 'h', 3, { 1, 10, STROKE, 7, 5, 6, 12, STROKE, END_GLYPH } }, + { 'i', 1, { 1, 1, STROKE, 4, 10, STROKE, END_GLYPH } }, + { 'l', 1, { 1, 10, STROKE, END_GLYPH } }, + { 'n', 3, { 10, 4, STROKE, 7, 5, 6, 12, STROKE, END_GLYPH } }, + { 'o', 3, { 4, 10, 12, 6, CLOSE, END_GLYPH } }, + { 'r', 3, { 4, 10, STROKE, 7, 5, 6, STROKE, END_GLYPH } }, + { 's', 3, { 6, 4, 7, 9, 12, 10, STROKE, END_GLYPH } }, + { 't', 3, { 2, 11, 12, STROKE, 4, 6, STROKE, END_GLYPH } }, + { 'u', 3, { 4, 10, 12, 6, STROKE, END_GLYPH } }, + { 'z', 3, { 4, 6, 10, 12, STROKE, END_GLYPH } }, + { ' ', 1, { END_GLYPH } }, + { '-', 2, { 7, 8, STROKE, END_GLYPH } }, + { '.', 1, { 10, 10, STROKE, END_GLYPH } }, + { -1, 0, { END_GLYPH } }, + }; + + cairo_font_face_t *user_font_face; + cairo_status_t status; + + user_font_face = cairo_user_font_face_create (); + cairo_user_font_face_set_init_func (user_font_face, test_scaled_font_init); + if (color_render) + cairo_user_font_face_set_render_color_glyph_func (user_font_face, test_scaled_font_render_glyph); + else + cairo_user_font_face_set_render_glyph_func (user_font_face, test_scaled_font_render_glyph); + + cairo_user_font_face_set_unicode_to_glyph_func (user_font_face, test_scaled_font_unicode_to_glyph); + + status = cairo_font_face_set_user_data (user_font_face, + &test_font_face_glyphs_key, + (void*) glyphs, NULL); + if (status) { + cairo_font_face_destroy (user_font_face); + return status; + } + + *out = user_font_face; + return CAIRO_STATUS_SUCCESS; +} + +static void +draw_line (cairo_t *cr) +{ + /* TEXT1 in black */ + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_show_text (cr, TEXT1); + + /* Draw TEXT2 three times with three different foreground colors. + * This checks that cairo uses the foreground color and does not cache + * glyph images when the foreground color changes. + */ + cairo_show_text (cr, TEXT2); + cairo_set_source_rgb (cr, 0, 0.5, 0); + cairo_show_text (cr, TEXT2); + cairo_set_source_rgb (cr, 0.2, 0.5, 0.5); + cairo_show_text (cr, TEXT2); +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_font_face_t *font_face; + char full_text[100]; + cairo_font_extents_t font_extents; + cairo_text_extents_t extents; + cairo_status_t status; + + strcpy(full_text, TEXT1); + strcat(full_text, TEXT2); + strcat(full_text, TEXT2); + strcat(full_text, TEXT2); + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + +#ifdef ROTATED + cairo_translate (cr, TEXT_SIZE, 0); + cairo_rotate (cr, .6); +#endif + + status = _user_font_face_create (&font_face, FALSE); + if (status) { + return cairo_test_status_from_status (cairo_test_get_context (cr), + status); + } + + cairo_set_font_face (cr, font_face); + cairo_font_face_destroy (font_face); + + cairo_set_font_size (cr, TEXT_SIZE); + + cairo_font_extents (cr, &font_extents); + cairo_text_extents (cr, full_text, &extents); + + /* logical boundaries in red */ + cairo_move_to (cr, 0, BORDER); + cairo_rel_line_to (cr, WIDTH, 0); + cairo_move_to (cr, 0, BORDER + font_extents.ascent); + cairo_rel_line_to (cr, WIDTH, 0); + cairo_move_to (cr, 0, BORDER + font_extents.ascent + font_extents.descent); + cairo_rel_line_to (cr, WIDTH, 0); + cairo_move_to (cr, BORDER, 0); + cairo_rel_line_to (cr, 0, 2*BORDER + TEXT_SIZE); + cairo_move_to (cr, BORDER + extents.x_advance, 0); + cairo_rel_line_to (cr, 0, 2*BORDER + TEXT_SIZE); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_set_line_width (cr, 2); + cairo_stroke (cr); + + /* ink boundaries in green */ + cairo_rectangle (cr, + BORDER + extents.x_bearing, BORDER + font_extents.ascent + extents.y_bearing, + extents.width, extents.height); + cairo_set_source_rgb (cr, 0, 1, 0); + cairo_set_line_width (cr, 2); + cairo_stroke (cr); + + /* First line. TEXT1 in black. TEXT2 in different colors. */ + cairo_move_to (cr, BORDER, BORDER + font_extents.ascent); + draw_line (cr); + + /* Now draw the second line using the render_color_glyph + * callback. The text should be all black because the default + * color of render function is used instead of the foreground + * color. + */ + status = _user_font_face_create (&font_face, TRUE); + if (status) { + return cairo_test_status_from_status (cairo_test_get_context (cr), + status); + } + + cairo_set_font_face (cr, font_face); + cairo_font_face_destroy (font_face); + + cairo_set_font_size (cr, TEXT_SIZE); + + cairo_move_to (cr, BORDER, BORDER + font_extents.height + 2*BORDER + font_extents.ascent); + draw_line (cr); + + /* Third line. Filled version of text in blue */ + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_move_to (cr, BORDER, BORDER + font_extents.height + 4*BORDER + 2*font_extents.ascent); + cairo_text_path (cr, full_text); + cairo_fill (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (user_font, + "Tests user font feature", + "font, user-font", /* keywords */ + "cairo >= 1.7.4", /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/view-test-results.py b/local/recipes/libs/cairo/source/test/view-test-results.py new file mode 100755 index 0000000000..fbc0d7f887 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/view-test-results.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +import http.server +import os +import threading +import webbrowser + +port = 8000 + +for i in range(10): + try: + server = http.server.ThreadingHTTPServer(("localhost", port), http.server.SimpleHTTPRequestHandler) + break + except OSError: + port += 1 + +thread = threading.Thread(target = server.serve_forever) +thread.daemon = True +thread.start() + +webbrowser.open_new("http://localhost:" + str(port) + "/index.html") +input("\nPress Enter to exit\n\n") diff --git a/local/recipes/libs/cairo/source/test/white-in-noop.c b/local/recipes/libs/cairo/source/test/white-in-noop.c new file mode 100644 index 0000000000..e6a93e801a --- /dev/null +++ b/local/recipes/libs/cairo/source/test/white-in-noop.c @@ -0,0 +1,52 @@ +/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* + * Copyright 2011 Andrea Canciani + * + * 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: Andrea Canciani + */ + +#include "cairo-test.h" + +#define HEIGHT 4 +#define WIDTH 4 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_paint (cr); + + cairo_set_operator (cr, CAIRO_OPERATOR_IN); + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (white_in_noop, + "Test an invalid optimization of the IN operator with white sources", + "operator", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/world-map.c b/local/recipes/libs/cairo/source/test/world-map.c new file mode 100644 index 0000000000..f775bb0d52 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/world-map.c @@ -0,0 +1,151 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * 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: Carl D. Worth + */ + +#include "cairo-test.h" + +#ifdef HAVE_UNISTD_H +#include +#endif + +#define WIDTH 800 +#define HEIGHT 400 + +typedef enum { + WM_NEW_PATH, + WM_MOVE_TO, + WM_LINE_TO, + WM_HLINE_TO, + WM_VLINE_TO, + WM_REL_LINE_TO, + WM_END +} wm_type_t; + +typedef struct _wm_element { + wm_type_t type; + double x; + double y; +} wm_element_t; + +#include "world-map.h" + +enum { + STROKE = 1, + FILL = 2, +}; + +static cairo_test_status_t +draw_world_map (cairo_t *cr, int width, int height, int mode) +{ + const wm_element_t *e; + double cx, cy; + + cairo_set_line_width (cr, 0.2); + + cairo_set_source_rgb (cr, .68, .85, .90); /* lightblue */ + cairo_rectangle (cr, 0, 0, 800, 400); + cairo_fill (cr); + + e = &countries[0]; + while (1) { + switch (e->type) { + case WM_NEW_PATH: + case WM_END: + if (mode & FILL) { + cairo_set_source_rgb (cr, .75, .75, .75); /* silver */ + cairo_fill_preserve (cr); + } + if (mode & STROKE) { + cairo_set_source_rgb (cr, .50, .50, .50); /* gray */ + cairo_stroke (cr); + } + cairo_new_path (cr); + cairo_move_to (cr, e->x, e->y); + break; + case WM_MOVE_TO: + cairo_close_path (cr); + cairo_move_to (cr, e->x, e->y); + break; + case WM_LINE_TO: + cairo_line_to (cr, e->x, e->y); + break; + case WM_HLINE_TO: + cairo_get_current_point (cr, &cx, &cy); + cairo_line_to (cr, e->x, cy); + break; + case WM_VLINE_TO: + cairo_get_current_point (cr, &cx, &cy); + cairo_line_to (cr, cx, e->y); + break; + case WM_REL_LINE_TO: + cairo_rel_line_to (cr, e->x, e->y); + break; + } + if (e->type == WM_END) + break; + e++; + } + + cairo_new_path (cr); + + return CAIRO_TEST_SUCCESS; +} + +static cairo_test_status_t +draw_world_map_stroke (cairo_t *cr, int width, int height) +{ + return draw_world_map (cr, width, height, STROKE); +} + +static cairo_test_status_t +draw_world_map_fill (cairo_t *cr, int width, int height) +{ + return draw_world_map (cr, width, height, FILL); +} + +static cairo_test_status_t +draw_world_map_both (cairo_t *cr, int width, int height) +{ + return draw_world_map (cr, width, height, FILL | STROKE); +} + +CAIRO_TEST (world_map, + "Tests a complex drawing (part of the performance suite)", + "fill, stroke", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw_world_map_both) +CAIRO_TEST (world_map_stroke, + "Tests a complex drawing (part of the performance suite)", + "stroke", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw_world_map_stroke) +CAIRO_TEST (world_map_fill, + "Tests a complex drawing (part of the performance suite)", + "fill", /* keywords */ + NULL, /* requirements */ + WIDTH, HEIGHT, + NULL, draw_world_map_fill) diff --git a/local/recipes/libs/cairo/source/test/world-map.h b/local/recipes/libs/cairo/source/test/world-map.h new file mode 100644 index 0000000000..af58b80f1c --- /dev/null +++ b/local/recipes/libs/cairo/source/test/world-map.h @@ -0,0 +1,196 @@ +/* The data for this test case was provided by Gary Nicholson + * who originally created an interactive SVG map + * of the world as can be seen here: + * + * http://www.wherearewe.co.nz/svg.html + * + * The data is used here by permission from Gary given on 2006-11-08: + * + * Thanks for asking, I don't need any attribution if you are + * only using the vectors and not the entire map with + * interactivity etc. So feel free to do what you wish with + * the data. + */ + +#define N(x,y) { WM_NEW_PATH, x, y } +#define M(x,y) { WM_MOVE_TO, x, y } +#define L(x,y) { WM_LINE_TO, x, y } +#define H(x,y) { WM_HLINE_TO, x, y } +#define V(x,y) { WM_VLINE_TO, x, y } +#define l(x,y) { WM_REL_LINE_TO, x, y } +#define E(x,y) { WM_END, x, y } + +static const wm_element_t countries[] = { +N(413.519,90.071),l(.136,-.348),l(-.31,-.204),l(-.017,-.327),l(.213,-.322),l(.245,-.147),l(.142,-.08),l(.225,.072),l(.062,.301),l(.41,.312),l(.466,.096),l(-.044,.288),l(-.248,.144),l(.074,.353),l(-.145,-.063),l(-.568,-.011),l(-.642,-.063), +N(421.683,94.397),l(.193,.336),l(-.266,.274),l(.214,.288),l(-.09,.192),l(.622,.062),l(.008,.144),l(.55,.242),l(.579,-.332),l(.215,.117),l(-.029,.171),l(-.126,.309),l(.112,.212),l(-.038,.192),l(-.315,-.051),l(-.176,-.162),l(-.283,.091),l(-.081,.273),l(.244,.131),l(-.228,.415),l(-.244,-.333),l(-.469,.05),l(-.071,.122),l(-.216,.03),l(-.23,-.142),l(-.143,-.354),l(-.371,.081),l(.019,.333),l(-.425,.384),l(-.018,.535),l(-.285,.151),l(-.385,-.312),l(.098,-.182),l(-.311,-.071),l(-.534,-.363),l(-.016,-.415),l(-.777,.404),l(.103,.212),l(-.349,.432),l(-.275,.16),l(-.629,-.168),l(-.627,.204),l(-.599,-.062),l(-.102,-.424),l(-.312,-.806),l(-.616,.147),l(-.854,.668),l(-.369,-.111),l(.238,-.226),l(.013,-.322),l(-.08,-.137),l(.089,-.294),l(.718,-.418),l(-.038,-.315),l(.575,-.24),l(.012,-.076),l(.528,-.494),l(.173,-.035),l(-.116,-.089),l(-.153,-.028),l(.221,-.302),l(.446,.007),l(-.005,.096),l(.473,.007),l(.385,-.309),l(.271,.089),l(.272,-.117),l(.271,.096),l(.567,-.158),l(.278,.11),l(.354,-.021),l(-.179,-.199),l(.709,-.199),l(.017,.151),l(.199,-.014),l(.149,.089),l(.852,.007),l(.664,.261), +N(421.394,104.558),l(.104,.175),l(.04,.256),l(-.06,.475),l(.118,.054),l(.062,.333),l(-.076,.795),l(-.211,.327),l(-.118,.724),l(-.292,.501),l(-.298,-.043),l(-.057,-.196),l(-.41,-.076),l(-.227,-.152),l(.284,-.207),l(-.07,-.076),l(-.437,-.098),l(.257,-.332),l(-.11,-.071),l(-.291,.071),l(-.053,-.147),l(.115,-.022),l(.175,-.158),l(-.094,-.153),l(-.257,-.082),l(.015,-.164),l(.247,-.12),l(-.284,-.218),l(.241,-.284),l(.6,-.305),l(.27,-.022),l(.04,-.125),l(.292,-.043),l(.195,.104),l(.096,-.142),l(-.022,-.344),l(.072,-.224),l(.143,-.011),M(396.323,103.853),l(.375,-.122),l(.411,-.365),l(.549,-2.299),l(.397,-.091),l(-.21,-.29),l(-.226,.259),l(.125,-1.144),l(.223,-.826),l(.115,.153),l(.496,.306),l(.191,.382),l(.191,.229),l(-.281,-.673),l(-.63,-.582),l(-.242,-.233),l(.024,-.249),l(.359,-.477),l(-.202,-.375),l(-.2,-.274),l(-.326,-.216),l(-.685,-.1),l(-.515,-.571),l(-.416,-.323),l(.278,-.426),l(-.233,-.181),l(-.343,-.131),l(-.511,-.142),l(-.184,-.173),l(.247,-.376),l(-.329,-.173),l(-.509,.179),l(-.489,-.249),l(-.824,-.251),l(-.619,-.181),l(-.325,.014),l(-.215,-.25),l(-.91,.167),l(-.059,-.25),l(-.265,-.125),l(-.367,-.042),l(-.056,-.104),l(.861,-.083),l(-.085,-.229),l(-.526,-.104),l(.442,-.104),l(.086,-.205),l(-.275,.017),l(-.263,-.021),l(-.417,.083),l(.04,-.438),l(.303,.012),l(.305,-.146),l(.526,-.088),l(.562,-.174),l(.215,.188),l(.18,-.167),l(.474,.063),l(.112,-.26),l(.272,-.059),l(.764,-.078),l(.393,.366),l(.275,.26),l(.342,.083),l(.652,-.271),l(.317,.167),l(.276,-.127),l(.457,-.124),l(.029,.23),l(.591,-.065),l(.3,-.103),l(-.265,-.188),l(-.028,-.251),l(.056,-.345),l(-.037,-.428),l(-.131,.021),l(-.562,-.682),l(-.11,-.407),l(.927,.126),l(.607,-.105),l(-.084,.397),l(.248,.419),l(.342,-.146),l(1.241,.104),l(.501,.146),l(.079,-.014),l(.525,-.093),l(.662,-.27),l(-.534,-.124),l(.055,-.204),l(.166,-.175),l(.753,-.322),l(.756,-.181),l(.902,-.215),l(.314,-.235),l(.302,-.264),l(-.053,-.775),l(.135,-.542),l(.521,-.25),l(.46,-.16),l(.916,-.092),l(.177,-.096),l(.208,.447),l(.311,.335),l(.266,.127),l(.141,-.071),l(.41,-.208),l(.153,.17),l(.202,.458),l(.194,.133),l(.518,-.012),l(.159,.301),l(.259,-.012),l(.576,.048),l(.375,.168),l(-.159,.241),l(.091,.175),l(-.072,.198),l(.285,.122),l(.406,-.075),l(.446,-.035),l(.193,-.313),l(.245,-.072),l(-.119,.373),l(.146,.18),l(-.039,.228),l(.529,.048),l(.341,.192),l(.371,.204),l(.127,.228),l(.694,-.174),l(.079,.114),l(.642,.063),l(.568,.011),l(.145,.063),l(.428,.319),l(.337,.277),l(.395,-.055),l(.045,.145),l(.689,-.062),l(.072,-.048),l(.233,.007),l(.095,.186),l(.456,.09),l(.479,-.014),l(.605,.193),l(-.954,.806),l(-.054,.213),l(-.054,.358),l(-.321,.372),l(-.075,.295),l(.091,.076),l(-.216,.701),l(.135,.233),l(-.385,.309),l(-.473,-.007),l(.005,-.096),L(415.96,94.5),l(-.221,.302),l(.153,.028),l(.116,.089),l(-.173,.035),l(-.528,.494),l(-.012,.076),l(-.575,.24),l(.038,.315),l(-.718,.418),l(-.089,.294),l(.08,.137),l(-.013,.322),l(-.238,.226),l(.369,.111),l(.854,-.668),l(.616,-.147),l(.312,.806),l(.102,.424),l(-.624,.301),l(.532,.344),l(.025,.292),l(.43,.192),l(-.199,.272),l(-.541,.353),l(-.183,-.111),l(-.437,.186),l(.352,.358),l(.616,.191),l(.135,.331),l(-.175,.01),l(-.315,.371),l(.193,.442),l(.754,.391),l(.849,-.07),l(.062,.281),l(-.146,.469),l(-.346,.23),l(-.221,.215),l(-.833,.488),l(-.889,.659),l(-.427,.087),l(-.318,.043),l(-.798,.159),l(-.405,-.028),l(-.471,-.156),l(-.851,-.499),l(-.315,-.085),l(-.354,.029),l(-.231,.072),l(-.511,-.056),l(-.752,-.313),l(-.602,.044),l(-.731,.345),l(-.357,.258),l(-.555,.559),l(-.147,.386),l(.099,.514),l(.091,.379),l(-.334,-.091),l(-.75,.137),l(-.039,.136),l(-.485,-.015),l(-.427,-.197),l(-.395,.167),l(-.261,-.015),l(-.036,-.152),l(-.335,-.091),l(-.206,.03),l(-.374,.076),l(-.187,-.076),l(-.035,-.289),l(-.091,-.213),l(-1.252,-.304),l(-.355,0),l(.017,.319),l(-.542,-.015),l(-.337,.061),l(-.037,-.122),l(-.767,.03),l(-.084,-.114),l(-.028,-.038),l(-.431,-.152),l(-.131,.076),l(-.262,-.03),l(-.056,.076),l(-.507,-.395),l(-.15,.061),l(-1.088,-.334),l(-.112,.106),l(-.15,-.03),l(-.094,-.106),l(.205,-.243),l(-.058,-.122),l(-.469,.03),l(-.472,-.243), +N(681.312,116.395),l(.235,-.171),l(.283,-.256),l(.633,-.738),l(.315,-.157),l(.595,.011),l(.579,.068),l(.511,.096),l(.309,-.115),l(.571,-.678),l(.682,.621),l(1.178,1.611),l(.329,.495),l(.269,.664),l(.002,.75),l(-.034,.947),l(-.129,.637),l(.143,.113),l(.5,-.043),l(-.121,.41),l(-.282,.523),l(-.5,.75),l(-.316,.312),l(-.243,.043),l(-.567,-.211),l(-.256,.1),l(-.607,.58),l(-.431,-.083),l(-.289,-.225),l(-.544,.1),l(-.526,.199),l(-1.188,.835),l(-.462,.043),l(-.46,.312),l(-.055,-.564),l(-.056,-.324),l(-.163,-.705),l(-.137,-.395),l(.167,-.453),l(.499,-.468),l(0,-.353),l(.226,-.425),l(-.044,-.141),l(-.378,-.311),l(-.095,-.296),l(.015,-.467),l(-.087,-.339),l(-.289,-.126),l(-.603,-.084),l(.654,-.411),l(.303,-.114),l(.654,.268),l(.254,-.241),l(-.029,-.283),l(-.764,-.89),l(-.113,-.311),l(-.137,-.105), +N(475.646,121.847),l(-.018,.175),l(.338,.391),l(-.295,-.009),l(-.132,.108),l(-.104,-.059),l(-.327,-.021),l(-.121,.33),l(-.783,.257),l(-.384,.046),l(-.099,.053),l(0,.21),l(-.217,.006),l(-.072,-.192),l(-.402,.023),l(-.547,-.146),l(-.191,-.087),l(0,-.21),l(-.161,-.105),l(-.122,-.403),l(.082,-.035),l(.12,.1),l(.147,-.006),l(.405,-.304),l(.253,-.006),l(.328,.092),l(.077,-.086),l(.088,-.286),l(-.053,-.175),l(.627,.093),l(.658,.027),l(.367,-.056),l(.818,-.233),l(.689,-.304),l(.535,-.158),l(-.475,.295),l(-.436,.231),l(-.596,.444), +N(704.404,117.274),l(.197,-.099),l(1.108,-.271),l(.057,.354),l(-.481,.284),l(-.232,.241),l(-.068,.453),l(.139,.367),l(.291,.056),l(.221,-.114),l(.418,-.354),l(.24,-.085),l(1.656,-.697),l(.389,-.213),l(.46,-.326),l(.349,-.638),l(.76,-.412),l(.347,-.327),l(.191,-.269),l(.142,-.51),l(.538,-.582),l(-.01,-.142),l(.344,-.567),l(.159,-.468),l(.139,-.609),l(-.043,-.467),l(-.33,-.198),l(-.128,-.24),l(.234,-.213),l(.166,-.284),l(-.155,-1.023),l(.544,-.343),l(.176,-.242),l(.327,-.328),l(.192,0),l(.21,.355),l(.199,.227),l(.303,-.058),l(.799,-.257),l(-.169,-.526),l(-.311,-.028),l(-.36,-.312),l(.694,-.415),l(.441,.156),l(.336,.227),l(.025,.199),l(-.016,.868),l(.058,.611),l(.22,.127),l(.243,.312),l(.717,1.432),l(.001,.496),l(-.246,.709),l(-.709,.766),l(-.226,.439),l(.064,.368),l(-.15,.071),l(-.737,.285),l(-.161,.113),l(-.164,.199),l(-.174,.453),l(.02,.396),l(.094,.254),l(.131,.792),l(-.04,.693),l(-.686,.751),l(-.242,.736),l(.02,.707),l(.198,.296),l(.422,.353),l(-.617,.298),l(-.193,.127),l(-.166,.17),l(-.174,.834),l(-1.081,.439),l(-.094,-.282),l(.294,-.665),l(.184,-.523),l(-.198,-.126),l(-.514,.241),l(-.578,.623),l(-.476,.001),l(-.346,.312),l(-.066,.748),l(-.354,.269),l(-.188,-.028),l(-.066,-.155),l(.003,-.606),l(-.149,-.155),l(-.211,.042),l(-.309,.156),l(-.344,.311),l(-.325,.523),l(-.866,-.055),l(-.505,.057),l(-.631,.1),l(-.458,-.549),l(-.685,-.323),l(-.26,.254),l(-.067,.184),l(-.177,.353),l(.037,.056),l(.417,.197),l(.416,.323),l(-.293,.198),l(-.829,.129),l(-.433,.241),l(-.463,.622),l(-.522,.847),l(-.688,-.365),l(-.565,-.21),l(-.285,-.197),l(-.014,-.169),l(-.194,-.818),l(.099,-.155),l(.495,-.325),l(.179,-.269),l(-.067,-.282),l(-.18,-.042),l(-.601,.17),l(-.341,-.028),l(-.789,-.167),l(-.475,.128),l(-.427,.227),l(-.437,.184),l(-.269,-.098),l(-.256,-.027),l(-1.647,.398),l(-.814,.298),l(-.21,-.31),l(-.452,-.042),l(-.413,.438),l(-.006,.635),l(-.756,-.238),l(-.579,-.055),l(-1.1,.073),l(-.267,-.14),l(.072,-.339),l(.179,-.283),l(.483,.013),l(.499,-.114),l(.751,-.467),l(2.201,-1.953),l(.28,-.015),l(.427,-.128),l(.056,.424),l(.495,-.128),l(1.278,-.257),l(.933,-.058),l(1.183,-.172),l(.892,-.256),l(.068,.452),l(.377,.268),l(.167,-.085),l(.654,-.199),l(.446,-.34),l(-.003,-.353),l(.114,-.467),l(.465,-.51),l(.698,-.581),l(.371,-.453),l(-.062,-1.117),l(.182,-.213),M(695.464,127.756),l(-.292,-.197),l(-.223,-.268),l(-.101,-.381),l(-.177,-.395),l(-.492,-.535),l(.731,-.382),l(.287,-.269),l(.456,-.593),l(.409,.253),l(.615,-.015),l(.483,-.185),l(.311,-.339),l(.451,-.311),l(.454,-.029),l(.316,.169),l(.862,.224),l(.153,.254),l(-.1,.127),l(-.102,.423),l(-.292,.24),l(-.864,.876),l(-.181,-.211),l(-.424,-.295),l(-.467,-.042),l(-.612,.213),l(-.193,.184),l(-.245,.495),l(-.165,.508),l(-.153,.212),l(-.448,.269),M(691.12,131.448),l(-.366,-.042),l(-.056,-.141),l(.268,-.537),l(.128,-.593),l(-.334,-.112),l(-.239,.198),l(-.155,.466),l(-.381,.452),l(-.326,-.211),l(-.059,-.211),l(.322,-.466),l(.032,-.296),l(-.356,-.917),l(.169,-.113),l(.687,-.58),l(.083,-.141),l(.034,-.466),l(-.532,-.789),l(-.333,-.042),l(-.162,.269),l(-.419,.495),l(-.249,-.112),l(-.23,-.508),l(-.376,-.267),l(-.261,-.366),l(.41,-.325),l(.733,.083),l(.706,-.171),l(.315,-.466),l(.241,-.283),l(.484,-.058),l(.478,.056),l(.249,.38),l(.27,.168),l(.43,.084),l(.628,-.213),l(.225,.395),l(-.569,.438),l(.405,.239),l(.443,.437),l(.079,.254),l(-.596,.58),l(-.242,.41),l(-.104,.367),l(-.085,.621),l(-.109,.649),l(-.242,.353),l(-.194,.099),l(-.165,.071),l(-.197,.184),l(-.479,.678),M(711.938,108.369),l(-.222,-.241),l(-.077,-.271),l(.325,-.642),l(-.055,-.342),l(-.549,-.198),l(-.168,-.171),l(-.146,-.812),l(.583,-.386),l(.522,-.172),l(.646,-.373),l(.037,-.356),l(-.318,-.285),l(.277,-.3),l(.224,-.015),l(.661,.427),l(.373,.085),l(.532,-.201),l(-.004,-1.186),l(.455,-.187),l(.45,-.244),l(.074,-.743),l(.007,-.844),l(-.398,-.758),l(-.098,-.473),l(.166,-.216),l(.618,-.346),l(.063,.072),l(.507,.43),l(.904,.816),l(1.07,.842),l(1.083,.684),l(.627,.285),l(.528,.17),l(1.02,.198),l(.282,.042),l(.304,-.086),l(.866,-.66),l(.461,-.144),l(.002,.1),l(-.308,.358),l(-.335,.558),l(.198,.414),l(.469,.599),l(.197,.356),l(-.561,.272),l(-.447,.244),l(-.534,.158),l(-.365,.015),l(-.488,-.199),l(-.453,.015),l(-.363,.144),l(-.345,.229),l(-.754,.786),l(-.396,.5),l(-.26,.599),l(-.4,-.07),l(-.425,-.241),l(-2.031,-.965),l(-.461,-.085),l(-.72,.044),l(-1.038,.587),l(-.153,-.299),l(-.372,-.356),l(-.339,.029),l(-.266,.115),l(-.439,.272),l(.049,.299),l(1.16,.497),l(.56,.298),l(.302,.27),l(-.391,.214),l(-.303,.029),l(-.305,-.128),l(-.261,.043),l(-.324,.314),l(-.388,.471),l(-.347,.114), +N(597.917,139.685),l(1.251,-1.545),l(.609,-.539),l(.348,-.239),l(.149,-.103),l(.417,-.016),l(.309,.294),l(.479,.208),l(1.659,.047),l(.371,.041),l(.312,.209),l(.329,.619),l(-.07,.156),l(.042,.24),l(.326,.294),l(.313,.069),l(.258,.238),l(.017,.282),l(-.217,.58),l(-.624,.06),l(-1.036,.062),l(-1.238,-.063),l(-.335,-.125),l(-.301,-.055),l(-.531,.313),l(-.544,.074),l(-.085,-.021),l(-.869,-.214),l(-.559,-.081),l(-.637,-.18),l(-.235,-.493),l(.092,-.113), +N(362.764,152.723),l(.072,-.625),l(.395,-.876),l(.52,-.552),l(.488,-.566),l(.244,-.509),l(1.175,-2.559),l(.238,-.241),l(1.404,-1.175),l(.345,-.495),l(.051,-.918),l(.305,-1.088),l(.651,-1.075),l(.399,-.34),l(.404,-.198),l(.838,-.51),l(.361,-.495),l(.334,-.777),l(.428,-.851),l(1.635,-.04),l(2.511,0),l(2.677,-.001),l(1.718,.004),l(1.42,-.008),l(.027,.876),l(-.03,1.752),l(.002,.65),l(-.104,.396),l(-.56,-.011),l(-6.005,-.022),l(-.557,.074),l(-.047,.509),l(-.07,2.261),l(-.099,2.6),l(-.144,.128),l(-.809,.287),l(-.726,.315),l(-.575,.427),l(-.249,.383),l(-.01,.707),l(.164,1.539),l(.051,1.102),l(-.212,-.027),l(-.732,.033),l(-2.396,-.014),l(-5.055,-.056),l(-.474,-.013), +N(514.551,145.841),l(-.374,.027),l(-.336,-.083),l(-.008,-.615),l(-.153,-.437),l(-.108,-.791),l(.187,-.607),l(.188,-.11),l(-.059,-.187),l(.177,-.607),l(.33,-.269),l(.312,.083),l(.069,.315),l(.26,.093),l(.063,.199),l(.116,.326),l(-.106,.42),l(.031,.708),l(.118,.254),l(-.104,.381),l(-.327,.467),l(-.275,.433), +N(514.177,145.868),l(.374,-.027),l(.008,.288),l(.361,.14),l(.153,.128),l(.186,-.093),l(-.046,.443),l(.397,.001),l(.402,.127),l(.687,-.093),l(.103,-.21),l(.183,-.058),l(.218,.117),l(.424,-.042),l(.595,.112),l(.224,-.035),l(.079,-.105),l(1.358,.222),l(.732,-.14),l(-.022,-.292),l(.225,.175),l(.375,-.016),l(.157,-.099),l(.312,-.422),l(.232,-.073),l(.267,-.495),l(.131,-.297),l(.711,-.637),l(.813,-.889),l(.163,.105),l(.229,-.178),l(.85,-.708),l(.313,-.433),l(.15,.161),l(-.248,.42),l(-.107,.299),l(-.004,.176),l(.099,.064),l(.121,-.024),l(.454,.042),l(.09,.324),l(.001,.508),l(-.003,.358),l(-.49,.034),l(-.401,-.083),l(-.107,.396),l(.073,1.326),l(-.199,.34),l(-.536,.596),l(.003,.946),l(.024,2.075),l(.063,.183),l(-.152,.057),l(-.584,.469),l(-.839,-.108),l(-3.387,-.446),l(-3.362,-.375),l(-.261,-.902),l(-.548,-1.154),l(-1.043,-2.198), +N(668.627,151.365),l(-.102,-.056),l(-.107,-.325),l(-.922,-1.212),l(-.332,-.987),l(-.03,-.438),l(.156,-.749),l(.546,-.792),l(1.312,-1.852),l(.259,-.184),l(.425,-.128),l(.229,-.184),l(.358,-.227),l(.228,.127),l(.554,.394),l(-.334,.424),l(-.084,.142),l(.023,.31),l(-.067,.622),l(-.203,.296),l(-.182,.354),l(-.065,.692),l(-.1,.494),l(-.317,.805),l(-.473,.707),l(-.417,.833),l(-.014,.353),l(-.114,.438),l(-.228,.142), +N(389.765,144.543),l(.1,.084),l(.895,.531),l(2.054,1.344),l(.811,.575),l(3.283,2.241),l(1.924,1.26),l(1.292,.824),l(.397,.253),l(2.472,1.469),l(.181,.253),l(-.096,.396),l(.082,.183),l(.393,.28),l(1.111,1.039),l(.229,.027),l(.47,-.314),l(.588,.562),l(.375,.167),l(.748,.024),l(.309,.111),l(.277,.352),l(.099,.522),l(-.161,.679),l(.146,.564),l(2.176,-.408),l(.064,1.017),l(.034,2.203),l(.001,.96),l(-.08,.89),l(-.145,.919),l(-.434,1.246),l(-.596,.794),l(-.339,.271),l(-.29,.129),l(-2.533,.085),l(-1.808,.124),l(-.209,.072),l(-.562,.427),l(-.579,.272),l(-.678,-.053),l(-.581,-.081),l(-1.062,-.173),l(-.36,-.059),l(-.356,-.125),l(-.37,.073),l(-1.22,.713),l(-.947,.458),l(-.304,.228),l(-.314,.793),l(-.274,-.027),l(-.324,-.182),l(-.518,-.209),l(-.272,.101),l(-.638,.625),l(-.492,.667),l(-.393,.822),l(-.174,.227),l(-.45,.102),l(-.551,-.364),l(-.293,-.281),l(-.273,.058),l(-.397,.384),l(-.355,1.217),l(-.292,1.047),l(-.317,.369),l(-.543,.271),l(-.448,.158),l(-.257,.016),l(-.141,.255),l(.058,.749),l(-.133,.876),l(-.261,.92),l(-.172,.326),l(-.046,.156),l(-.08,.043),l(-.159,.1),l(-.604,.399),l(-.352,.059),l(-.148,-.239),l(-.117,-.381),l(-.004,-.297),l(-.147,-.211),l(-.257,-.041),l(-.239,.114),l(-.571,.483),l(-.362,.469),l(-.35,.228),l(-.455,-.436),l(-.566,-.321),l(-.352,.059),l(-.522,.54),l(-.559,-.901),l(-.194,-1.143),l(-.349,-.718),l(-.474,-.478),l(-.265,-.451),l(-.271,-.832),l(-.022,-.339),l(-.246,-.281),l(-.323,-.055),l(-.684,.428),l(-.3,.327),l(-.43,.243),l(-.565,-.152),l(-.356,-.153),l(-.338,-.026),l(-.475,.413),l(-.252,.256),l(-.536,-.265),l(-.882,-.715),l(-.18,-.183),l(-.113,-.028),l(.062,-.142),l(.004,-.565),l(-.082,-.833),l(-.265,-.337),l(-.554,-.322),l(-.181,-.197),l(-.22,-.479),l(-.144,-.663),l(-.251,-1.1),l(.057,-.339),l(.506,-.399),l(.332,-.284),l(.018,-.607),l(.181,-.552),l(.252,-.256),l(.402,-.073),l(.261,.111),l(.568,.83),l(.214,.168),l(.454,.082),l(.107,-.269),l(-.055,-.296),l(.06,-.212),l(.535,.124),l(.713,.137),l(.485,.054),l(.387,-.031),l(.945,-.344),l(1.953,-.026),l(6.457,-.01),l(.379,-1.613),l(-.724,-.787),l(-.186,-1.468),l(-.202,-2.386),l(-.325,-2.753),l(-.178,-1.736),l(-.19,-1.468),l(-.908,-7.962),l(-.049,-.776),l(3.231,-.089),l(.523,-.13), +N(525.37,142.384),l(.312,-.429),l(.155,-.17),l(.084,.833),l(-.423,.707),l(-.118,.156),l(-.121,.024),l(-.099,-.064),l(.004,-.176),l(.107,-.299),l(.248,-.42),l(-.15,-.161),M(525.923,144.712),l(0,.22),l(.456,.762),l(.408,.465),l(.782,.634),l(.677,.394),l(1.008,.52),l(.392,.154),l(.277,.014),l(.576,-.029),l(.364,.112),l(.873,.973),l(.518,.648),l(.46,.422),l(.81,.365),l(.025,.212),l(-.67,1.06),l(-.615,.721),l(-.883,.807),l(-.776,1.541),l(-.242,.142),l(-.562,-.083),l(-.235,-.084),l(-.252,.071),l(-.278,.509),l(-.062,1.115),l(.001,.791),l(.134,.621),l(-.403,.142),l(-1.046,.073),l(-.627,.27),l(-.367,.283),l(-.29,.495),l(-.131,.551),l(-.204,.283),l(-.444,.255),l(-.544,.1),l(-.292,0),l(-.386,-.042),l(-.326,.029),l(-.382,.283),l(-.22,.297),l(-.125,.508),l(.003,.353),l(-.091,.311),l(-.631,.396),l(-.344,.043),l(-.776,-.21),l(-.717,.058),l(-.896,.27),l(-.768,.298),l(-.283,.099),l(-.416,.145),l(-.241,-.306),l(-.483,-.689),l(.006,-.296),l(-.127,-.253),l(-.933,-1.364),l(-.604,-.971),l(-.226,-.634),l(-.092,-.663),l(1.691,-.815),l(2.35,-1.213),l(5.346,-2.982),l(-.155,-1.453),l(-.581,-.914),l(-.063,-.183),l(-.024,-2.075),l(-.003,-.946),l(.536,-.596),l(.199,-.34),l(-.073,-1.326),l(.107,-.396),l(.401,.083),l(.49,-.034), +N(405.733,173.04),l(-.568,-.971),l(-.562,-.025),l(-.37,.044),l(-.516,-.181),l(-.97,-.757),l(-.114,-.226),l(.335,-.439),l(-.018,-.212),l(-.179,-.268),l(-.502,-.42),l(-.389,-.266),l(-.422,-.492),l(-.426,-.93),l(-.019,-.396),l(.173,-.665),l(.581,.081),l(.678,.053),l(.579,-.272),l(.562,-.427),l(.209,-.072),l(1.808,-.124),l(2.533,-.085),l(.29,-.129),l(.339,-.271),l(.596,-.794),l(.434,-1.246),l(.145,-.919),l(.08,-.89),l(-.001,-.96),l(-.034,-2.203),l(-.064,-1.017),l(1.672,-.321),l(1.82,-.364),l(3.084,-2.617),l(.834,-.655),l(2.308,-1.454),l(1.607,-.956),l(4.012,-2.241),l(1.632,-.843),l(.265,-.186),l(.832,.137),l(1.646,.442),l(1.008,.333),l(.258,.182),l(1.192,.911),l(.231,-.157),l(1.519,-.729),l(.364,2.145),l(.169,1.298),l(.42,1.028),l(.554,.802),l(.703,.604),l(-.388,.722),l(-.265,.99),l(-.168,1.088),l(-.084,.989),l(.022,.537),l(-.062,.707),l(-.019,1.045),l(-.034,1.088),l(-.056,.466),l(-2.43,2.613),l(-.591,.78),l(-.87,1.333),l(-.572,.794),l(-.007,.678),l(.123,.719),l(.014,.269),l(-.951,.034),l(-.437,.2),l(-.453,.299),l(-.761,.697),l(-.259,.058),l(-.609,-.208),l(-.724,-.193),l(-.884,-.221),l(-.531,-.04),l(-.709,.047),l(-.628,.103),l(-.774,.287),l(-.403,.327),l(-.629,.399),l(-.273,.059),l(-.934,.005),l(-.965,-.277),l(-1.173,-.742),l(-.354,-.083),l(-.467,.116),l(-1.337,.544),l(-.37,.002),l(-.209,-.098),l(-1.095,-1.223),l(-.821,-.277),l(-1.111,-.121),l(-1.174,.108),l(-1.064,.188),l(-.676,.4),l(-.687,1.614),l(-.353,.482),l(-.158,.849),l(-.092,.961),l(-.902,-.503),l(-.727,-.589),l(-.339,-.28),l(-.321,.073),l(-.577,.3), +N(431.763,171.063),l(-.351,-.407),l(-.575,-.52),l(-.173,-.394),l(-.014,-.269),l(-.123,-.719),l(.007,-.678),l(.572,-.794),l(.87,-1.333),l(.591,-.78),l(2.43,-2.613),l(.056,-.466),l(.034,-1.088),l(.019,-1.045),l(.062,-.707),l(-.022,-.537),l(.084,-.989),l(.168,-1.088),l(.265,-.99),l(.388,-.722),l(-.703,-.604),l(-.554,-.802),l(-.42,-1.028),l(-.169,-1.298),l(-.364,-2.145),l(1.818,-.858),l(.41,-.059),l(5.231,2.554),l(4.941,2.372),l(5.577,2.792),l(1.981,.963),l(-.02,1.045),l(-.016,.946),l(-.036,.636),l(.085,2.5),l(-.038,.749),l(.036,1.002),l(.031,1.229),l(-.04,.283),l(-.839,-.009),l(-1.245,.05),l(-.229,.143),l(-.417,1.245),l(-.583,.809),l(-.122,.438),l(.131,.677),l(-.149,.212),l(-.718,.428),l(-.053,.24),l(.342,.662),l(-.087,.34),l(-.542,.596),l(-.316,.609),l(.219,.352),l(.517,-.088),l(.338,.012),l(.141,.225),l(.221,1.228),l(.137,.522),l(.155,.295),l(.444,.407),l(.266,.465),l(.026,.367),l(-.15,.425),l(-.559,-.208),l(-.321,-.012),l(-.322,.086),l(-.939,.613),l(-.372,.228),l(-.165,.382),l(-.005,.41),l(-.196,.284),l(-2.649,2.275),l(-.386,.087),l(-2.181,.055),l(-.434,.059),l(-.209,.199),l(-.117,.806),l(-.646,1.176),l(-.258,.143),l(-.368,.031),l(-.881,-.009),l(-.818,.273),l(-.754,.386),l(-.466,.271),l(-.224,.03),l(-.225,-.069),l(-.494,-.661),l(-1.363,.686),l(-.449,.158),l(-.24,-.027),l(-.096,-.084),l(-.208,-.183),l(-.382,-1.057),l(-.638,-1.07),l(-1.343,-1.179),l(-1.088,-1.067),l(.323,-.539),l(.29,-.312),l(.24,-.1),l(.481,.082),l(1.187,.191),l(.674,-.032),l(.225,-.143),l(-.047,-.127),l(-.208,-.21),l(-.381,-.633),l(-.205,-.578),l(-.169,-1.228),l(.134,-.651),l(-.119,-1.2),l(-.395,-.887),l(-.923,-1.238),l(-.208,-.083),l(-.627,-.109), +N(627.173,150.012),l(.483,-.229),l(.515,-.13),l(.341,.012),l(.597,.392),l(.325,.097),l(.584,-.413),l(.332,-.115),l(1.595,-.052),l(.807,-.117),l(.341,-.157),l(.696,-.554),l(.521,-.328),l(.298,-.101),l(.623,.575),l(.771,.235),l(.66,.053),l(.777,-.047),l(.237,.21),l(.056,.38),l(-.472,.75),l(.096,.521),l(.273,.365),l(.943,.615),l(.621,.166),l(.909,.107),l(.197,.143),l(-.19,.132),l(-.826,.482),l(.106,.465),l(-.203,.212),l(-1.261,-.054),l(-.136,.198),l(.057,.395),l(-.283,.382),l(-.585,.792),l(-.221,.142),l(-.533,.241),l(-.171,.127),l(-.27,.396),l(-.303,.932),l(-.388,.975),l(.268,.225),l(.469,.563),l(1.112,1.071),l(.023,.24),l(.042,.522),l(.087,.254),l(.42,.493),l(1.096,.83),l(1.282,1.296),l(.26,.197),l(.636,.069),l(.313,.38),l(.282,1.016),l(.302,.578),l(.638,.605),l(.293,.663),l(.341,1.382),l(.524,2.809),l(-.295,.438),l(-.235,.495),l(.05,.819),l(-.095,.41),l(.056,.664),l(-.027,.099),l(-.364,.551),l(-.447,.439),l(-.254,.127),l(-.509,.1),l(-.419,.17),l(-.501,.354),l(-.591,.622),l(-.579,.354),l(-.325,.043),l(-.512,-.197),l(-.404,-.31),l(-.179,-.141),l(-.153,.424),l(.051,.494),l(.048,.353),l(-.205,.721),l(-.388,.424),l(-.326,.071),l(-.235,-.07),l(-.246,.481),l(-.427,.326),l(-.523,.142),l(-.417,.213),l(-.459,.565),l(-.196,.269),l(-.406,.297),l(-.264,.099),l(-.365,-.042),l(.078,-.861),l(.1,-1.313),l(.151,-.494),l(.215,-.283),l(-.02,-.353),l(-.475,-.437),l(-.749,-.238),l(-.091,-.066),l(.3,-.289),l(.646,-.229),l(.915,-.528),l(.599,-.229),l(.497,.011),l(.688,.194),l(.17,-.27),l(-.03,-.197),l(-.568,-.435),l(-.216,-.422),l(.234,-.425),l(.99,-.571),l(.521,-.229),l(.932,-.443),l(.599,-.187),l(.385,-.285),l(.217,-.509),l(-.054,-1.073),l(.05,-.424),l(.076,-.367),l(-.455,-1.014),l(-.029,-.663),l(.215,-.905),l(.155,-.918),l(-.064,-.578),l(-.214,-.437),l(-.529,-.477),l(-.072,-.282),l(.226,-.439),l(-.136,-.395),l(-.358,-.308),l(-.685,-.391),l(-.471,-.52),l(-.57,-.914),l(-1.683,-2.121),l(-.698,-.772),l(-.637,-.646),l(-.632,-.476),l(-1.234,-.741),l(-.162,-.098),l(-.043,-.494),l(.277,-.369),l(.311,-.101),l(.476,.068),l(.287,-.058),l(.261,-.185),l(.255,-.326),l(-.009,-.508),l(-.87,-.968),l(-.434,-.675),l(-.262,-.083),l(-.39,.171),l(-.509,.483),l(-.287,.058),l(-.47,-.195),l(-.607,-.434),l(-.334,-.689),l(-.338,-.929),l(-.543,-.604),l(-.613,-.575),l(-.45,-.745), +N(217.961,150.385),l(.304,-.043),l(.84,-.27),l(-.17,-.254),l(-.312,-.112),l(-.369,-.056),l(-.651,.016),l(-.497,-.042),l(-.645,.157),l(-1.193,.92),l(-.371,.029),l(-.653,.001),l(-.211,.113),l(-.189,.452),l(-.396,.284),l(-.32,.043),l(-.786,.086),l(.259,-.325),l(.473,-.312),l(-.128,-.593),l(.282,-.382),l(.114,-.099),l(1.258,-.61),l(1.625,-.47),l(1.164,-.087),l(.842,-.157),l(.825,.041),l(.566,-.044),l(.73,.168),l(.848,.083),l(.603,.197),l(.557,.112),l(.477,.013),l(.499,.268),l(.573,.536),l(.382,.253),l(.581,.168),l(.768,.111),l(1.229,.351),l(1.02,.492),l(.453,.31),l(.374,.55),l(.33,.141),l(.479,.041),l(1.704,.519),l(1.018,.167),l(.327,.239),l(-.344,.58),l(.233,.155),l(.559,.042),l(.756,-.072),l(.495,.168),l(.507,.38),l(.591,.281),l(.381,.296),l(-.233,.085),l(-.981,.087),l(-1.15,.398),l(-.626,.058),l(-1.054,-.209),l(-.9,-.041),l(-.934,.186),l(-.943,.115),l(-.484,.029),l(-.449,-.07),l(.353,-.382),l(.728,-.623),l(.173,-.396),L(229,154.204),l(-.181,-.127),l(-.622,-.14),l(-.7,.001),l(-.603,-.112),l(-.651,-.338),l(-.141,-.748),l(-.258,-.536),l(-.218,-.155),l(-.396,-.027),l(-1.005,.044),l(-.836,-.139),l(-.621,-.225),l(-.956,-.493),l(-.739,-.238),l(-.615,-.069),l(-1.154,-.068),l(-.489,-.098),l(-.855,-.352), +N(634.036,168.444),l(.808,-.64),l(.121,-.438),l(-.002,-.945),l(-.157,-.507),l(-.419,-.703),l(-.979,-1.279),l(-.255,-.464),l(-.107,-.366),l(-.058,-1.524),l(-.435,-.632),l(-.688,-.659),l(-.285,-.535),l(-.052,-.282),l(-.266,-.153),l(-.893,-.192),l(-.403,-.012),l(-.286,.453),l(-.2,.538),l(-.543,.257),l(-.223,.072),l(-.59,-.265),l(-.835,-.348),l(-.346,.03),l(-1.173,1.178),l(-.37,.411),l(-.481,-.138),l(-.145,-.324),l(.027,-.494),l(.117,-.438),l(.528,-1.569),l(.085,-.41),l(-.249,-1.311),l(-.045,-.113),l(-.414,.045),l(-.489,.2),l(-.423,.003),l(-.186,-.154),l(-.066,-.367),l(.106,-.805),l(-.01,-.423),l(-.118,-.168),l(-.295,-.182),l(-.541,-.166),l(.193,-.185),l(.582,-.455),l(.442,-.581),l(.53,-.61),l(.502,-.355),l(.178,.196),l(.321,.21),l(.769,.08),l(.266,-.213),l(.109,-.339),l(-.119,-.521),l(-.228,-.366),l(-.138,-.592),l(.043,-.325),l(.24,-.241),l(.679,-.314),l(.45,.745),l(.613,.575),l(.543,.604),l(.338,.929),l(.334,.689),l(.607,.434),l(.47,.195),l(.287,-.058),l(.509,-.483),l(.39,-.171),l(.262,.083),l(.434,.675),l(.87,.968),l(.009,.508),l(-.255,.326),l(-.261,.185),l(-.287,.058),l(-.476,-.068),l(-.311,.101),l(-.277,.369),l(.043,.494),l(.162,.098),l(1.234,.741),l(.632,.476),l(.637,.646),l(.698,.772),l(1.683,2.121),l(.57,.914),l(.471,.52),l(.685,.391),l(.358,.308),l(.136,.395),l(-.226,.439),l(.072,.282),l(.529,.477),l(.214,.437),l(.064,.578),l(-.155,.918),l(-.209,.114),l(-.975,.429),l(-.3,.072),l(-.373,-.351),l(-.444,-.181),l(-.476,.186),l(-.392,.285),l(.107,.296),l(.187,.182),l(.103,.211),l(-.095,.24),l(-.248,.058),l(-.469,-.251),l(-.341,-.111),l(-.736,-.165),l(-.533,-.251), +N(60.074,72.607),l(-.099,.228),l(-.491,.472),l(-.395,.183),l(-.462,.062),L(58,73.461),l(-.961,-.362),l(-.153,-.197),l(.169,-.289),l(.54,-.274),l(.341,-.32),l(.716,.364),l(.3,.091),l(.465,-.26),l(.215,-.213),l(.064,-.366),l(.485,-.047),l(1.107,.135),l(.536,.334),l(.133,.213),l(-.756,.062),l(-.429,0),l(-.59,.184),l(-.11,.092),M(40.092,77.571),l(-.729,-.029),l(-.097,-.24),l(.011,-.3),l(.802,-.243),l(.326,-.211),l(.593,-.423),l(.448,-.137),l(.646,-.077),l(1.427,.253),l(.711,.24),l(-.079,.211),l(-.303,.046),l(-.754,-.074),l(-.496,.031),l(-1.077,.183),l(-.269,.226),l(-1.161,.543),M(38.426,77.979),l(-.515,-.209),l(-.139,-.285),l(.381,-.227),l(.674,.27),l(.093,.195),l(-.122,.15),l(-.372,.105),M(37.896,78.449),l(-.256,.084),l(-.558,.151),l(-1.109,-.058),l(-.387,.135),l(-.398,.434),l(-.31,.15),l(-.854,-.207),l(-.135,-.224),l(.497,-.359),l(.5,-.315),l(.955,-.166),l(.863,-.346),l(.39,.089),l(.461,.224),l(.341,.409),M(29.628,81.29),l(-.168,-.594),l(-.324,-.476),l(.839,-.136),l(.424,.088),l(.436,.238),l(-.244,.268),l(-.26,.06),l(-.073,.297),l(-.22,.09),l(-.412,.164),M(27.543,81.591),l(-.39,.031),l(-.741,.165),l(-.311,-.133),l(-.088,-.178),l(.104,-.119),l(.336,-.268),l(.294,-.09),l(.584,.222),l(.212,.371),M(54.394,157.986),l(-.559,-.356),l(-.044,-.884),l(-.243,-.677),l(.482,-.402),l(-.035,-.2),l(-.156,-.26),l(.052,-.149),l(.173,-.046),l(.354,.158),l(.652,.279),l(.593,.425),l(-.015,.275),l(.238,.046),l(.12,.287),l(.306,.149),l(-.062,.161),L(56,156.933),l(-.172,.204),l(-.766,.195),l(-.374,.23),l(-.295,.425),M(23.015,59.92),l(-1.613,-.646),l(-.75,-.205),l(-.792,-.062),l(-.9,.065),l(-.291,-.095),l(-.431,-.222),l(.179,-.287),l(.516,-.049),l(1.135,.221),l(.579,-.001),l(.543,-.081),l(.538,-.001),l(.828,.285),l(1.725,.362),l(.429,.237),l(.046,.111),l(-.569,-.03),l(-.646,.033),l(-.527,.365),M(99.855,70.993),l(.467,.929),l(-.071,.167),l(-.879,-.272),l(-.621,-.075),l(.067,.441),l(-.056,.228),l(-.935,-.607),L(97.03,71.41),l(.396,-.458),l(.263,-.153),l(.612,-.078),l(.784,.38),l(.771,-.108),M(100.975,73.606),l(.128,.272),l(-.086,.273),l(-.318,.483),l(-.559,-.815),l(-.597,-.909),l(-.04,-.228),l(.095,-.213),l(.407,.029),l(.568,.197),l(.402,.91),M(106.858,78.207),l(-1.872,-1.166),l(-.566,-.555),l(.01,-.467),l(-.559,-.843),l(.071,-.106),l(.456,.06),l(.274,.256),l(1.165,.48),l(.086,.196),l(-.059,.136),l(-.149,.226),l(.296,.436),l(.839,.374),l(.007,.974),M(140.191,127.819),l(-.043,-.094),l(-.198,-.36),l(-.049,-.067),l(-.032,.042),l(-.028,.05),l(-.04,-.092),l(.002,-.664),l(-.331,-.604),l(-.472,-.451),l(-.661,-.451),l(-.512,-.197),l(-.114,-.052),l(-.145,.034),l(.002,.092),l(-.088,.025),l(-.1,-.042),l(-.146,-.143),l(.076,-.076),l(-.073,-.202),l(-.228,-.252),l(-.283,-.025),l(-.312,.084),l(-.932,-.336),l(-.286,-.328),l(-.428,-.244),l(-.383,.042),l(-.932,-.16),l(-.721,.051),l(-.12,-.185),l(-.234,-.067),l(-.046,-.177),l(.094,-.117),l(-.157,-.504),l(.133,-.464),l(-.227,-.096),l(-.127,.008),l(-.249,-.134),l(0,-.101),l(.075,-.093),l(-.029,-.219),l(-.347,-.185),l(-.254,-.286),l(-.415,-.219),l(-.391,-.623),l(-.202,-.076),l(-.203,-.311),l(-.409,-.219),l(-.156,-.529),l(-.002,-.227),l(.178,.007),l(.147,-.164),l(.029,-.326),l(-.208,-.251),l(-.192,-.045),l(-.22,.037),l(-.303,-.126),l(-.535,-.514),l(.078,-.21),l(-.091,-.312),l(-.129,-.067),l(-.044,-.463),l(.058,-.152),l(.119,-.025),l(.099,.067),l(.073,.076),l(-.086,.101),l(.153,.202),l(.285,.126),l(.116,.118),l(.203,.017),l(-.385,-.564),l(-.183,-.144),l(-.021,-.236),l(-.184,-.109),l(-.051,-.344),l(-.13,.006),l(-.011,.144),l(.048,.446),l(-.093,.017),l(-.293,-.194),l(-.119,.042),l(-.516,-.404),l(-.136,-.363),l(-.377,-.514),l(-.531,-.379),l(-.624,-.583),l(-.123,-.142),l(.114,-.101),l(-.327,-.751),l(.161,-.43),l(-.254,-.479),l(-.22,-.355),l(-.738,-.782),l(-.104,-.299),l(.099,-.627),l(.252,-.628),l(.166,-.357),l(.059,-.856),l(-.215,-.785),l(-.692,-1.486),l(-.153,-.916),l(.096,-.287),l(.231,-.244),l(.402,-.201),l(.365,-.717),l(-.365,-.573),l(-.066,-.33),l(.424,-1.593),l(.153,-.575),l(.061,-.634),l(.091,-.778),l(.019,-.179),l(-.153,-.16),l(.08,-.231),l(-.103,-.167),l(.157,-.077),l(-.03,-.186),l(-.046,-.186),l(-.031,-.103),l(-.004,-.058),l(.322,.096),l(.209,-.019),l(.062,-.097),l(-.211,.006),l(-.614,-.122),l(.062,-.707),l(-.103,-.328),l(.017,-.277),l(.587,-.225),l(-.345,-.019),l(-.16,-.142),l(-.129,0),l(-.053,.045),l(.042,.116),l(-.12,.052),l(-.133,-.979),l(-.927,-1.463),l(-.017,-.465),l(.129,-.131),l(.544,.086),l(.632,.217),l(.785,.114),l(.641,.028),l(.546,-.044),l(.415,.086),l(.547,.318),l(.039,.435),l(-.42,.407),l(-.413,.347),l(.532,.146),l(.184,.188),l(.251,.169),l(.029,-.228),l(.161,-.232),l(.393,-.305),l(.21,-.581),l(.102,-.465),l(-.064,-.421),l(-.356,-.958),l(-.158,-.305),l(-.655,-.516),l(.194,.013),l(2.579,.001),l(1.335,.022),l(4.588,-.025),l(3.938,.008),l(2.87,-.001),l(1.687,.006),l(5.117,-.028),l(.74,.011),l(4.13,.021),l(1.089,-.035),l(3.821,.023),l(.875,-.005),l(3.617,-.004),l(4.84,.018),l(.601,-.003),l(2.935,.014),l(2.131,-.012),l(2.781,.029),l(2.915,-.016),l(2.105,.003),l(1.348,-.007),l(2.798,.029),l(2.687,-.029),l(.68,.003),l(-.387,-.588),l(-.131,-.347),l(.501,-.036),l(.896,.748),l(.279,.371),l(.468,.46),l(.833,.451),l(.518,-.076),l(1.425,.208),l(.02,.185),l(.271,-.012),l(.338,.48),l(.16,-.247),l(.502,.013),l(.241,.271),l(.469,.086),l(.064,.185),l(.506,.098),l(.573,-.141),l(.219,-.06),l(.412,-.191),l(.373,-.075),l(.028,.282),l(.197,.116),l(.855,-.083),l(.474,.041),l(.156,.115),l(.196,.144),l(.542,-.049),l(.707,.074),l(1.469,-.592),l(.805,-.189),l(.797,.227),l(.977,.386),l(3.975,1.576),l(2.15,1.061),l(.101,.429),l(.46,.465),l(.628,-.024),l(.178,.135),l(.184,.294),l(.916,.181),l(.307,.235),l(-.11,.318),l(.26,.33),l(2.529,1.05),l(.876,3.16),l(.054,.545),l(-.028,.746),l(-.377,.576),l(-.294,.544),l(-.264,.433),l(-.414,.294),l(-.707,.525),l(-.044,.218),l(.012,.33),l(.371,.427),l(.497,.169),l(.573,.068),l(.524,-.117),l(.925,-.506),l(.939,-.478),l(.88,-.262),l(.919,-.062),l(.944,-.163),l(1.464,-.452),l(.875,-.427),l(-.047,-.362),l(-.16,-.471),l(-.018,-.319),l(.162,-.375),l(.47,-.203),l(.93,-.091),l(1.123,.01),l(1.305,.138),l(1.156,-.197),l(.44,-.275),l(.163,-.512),l(.146,-.434),l(.545,-.164),l(1.754,-.814),l(.534,-.305),l(.968,-.523),l(1.76,-.009),l(2.508,.029),l(1.855,.004),l(1.093,.095),l(.174,-.375),l(.363,-.435),l(.402,-.06),l(1.161,.124),l(1.139,-1.45),l(1.139,-2.22),l(.514,-.626),l(.632,-.526),l(.273,.085),l(.505,.36),l(.381,.085),l(.41,-.176),l(.771,.025),l(.488,.288),l(.174,.274),l(.31,2.819),l(-.077,.229),l(.606,.231),l(.224,0),l(.042,.154),l(-.143,.069),l(.02,.256),l(-.192,.077),l(.16,.291),l(.188,-.153),l(.349,.495),l(-.268,.281),l(.299,-.04),l(.171,.093),l(-.511,.374),l(-.509,.093),l(-.297,-.12),l(-.013,.253),l(-.138,.067),l(-.077,-.107),l(-.231,-.08),l(-.277,.133),l(-.101,.28),l(-.171,-.013),l(-.15,.16),l(-.175,-.347),l(-.746,.28),l(-.204,-.093),l(.12,.413),l(-.666,-.213),l(.199,-.48),l(-.149,-.04),l(-.364,.52),l(-.332,.56),l(-.342,.333),l(-.324,-.227),l(-.249,.439),l(-.346,-.08),l(.122,-.307),l(-.325,.253),l(.165,.16),l(-.326,.293),l(-.318,-.133),l(.105,-.226),l(-.654,.253),l(.065,.359),l(-.264,.04),l(-.161,.373),l(-.352,.106),l(-.333,.679),l(-.404,.505),l(.173,.146),l(.068,.212),l(.168,.053),l(.083,-.08),l(.169,.013),l(-.122,.146),l(-.547,.106),l(.053,.093),l(-.392,.292),l(-.068,.159),l(.337,.027),l(.282,.093),l(.599,.704),l(.055,.398),l(.399,.106),l(.691,-.239),l(-.022,-.186),l(-.14,-.027),l(-.254,-.279),l(-.097,-.04),l(-.009,-.066),l(.196,0),l(.23,.133),l(.218,.358),l(.031,.425),l(-1.599,.292),l(-.032,-.385),l(-.124,-.066),l(-.109,.226),l(-.164,.04),l(-.03,.093),l(-.105,-.106),l(-.159,.266),l(-.164,.04),l(-.294,.04),l(-.045,-.332),l(.198,-.332),l(-.443,.119),l(-.154,-.146),l(-.082,.252),l(-.087,.664),l(-1.429,.132),l(-1.694,.159),l(-1.182,.345),l(-.787,.358),l(-.097,.212),l(-.32,.053),l(-.144,.172),l(-.032,-.04),l(.308,-.756),l(.024,-.106),l(-.071,.027),l(-.41,.994),l(-.079,-.08),l(-.406,.292),l(.218,.318),l(.553,.093),l(-.46,1.515),l(-.302,.429),l(-.259,-.092),l(.043,.251),l(-.062,.185),l(-.237,.145),l(-.462,.501),l(-.292,.304),l(-.167,.026),l(-.075,-.119),l(.177,-.31),l(-.113,-.178),l(-.43,.013),l(-.447,-.343),l(-.148,-.053),l(-.329,-.541),l(.315,-.257),l(.151,-.245),l(-.271,.119),l(-.362,.37),l(.489,.845),l(.033,.356),l(.387,.581),l(.28,.066),l(.104,.765),l(-.101,.238),l(-.151,.23),l(-.125,-.013),l(-.487,.666),l(-.396,.798),l(.034,.053),l(-.13,.132),l(-.107,-.125),l(-.374,.725),l(.026,.125),l(-.226,.04),l(-.137,-.263),l(.342,-.864),l(.195,-.29),l(.247,-.119),l(.061,-.237),l(-.093,-.059),l(-.374,.119),l(.226,-.383),l(-.218,.04),l(-.176,-.093),l(.012,-.191),l(.242,-.04),l(-.077,-.33),l(-.439,.296),l(-.241,-.204),l(-.157,.053),l(-.23,-.396),l(.355,-.171),l(.357,-.053),l(-.005,-.06),l(-.604,-.316),l(-.092,.165),l(-.072,0),l(.107,-.323),l(.089,-.02),l(.21,.159),l(.131,-.06),l(-.098,-.224),l(-.353,-.066),l(-.065,-.112),l(.096,-.112),l(.336,.02),l(.193,-.284),l(-.281,.046),l(-.158,-.059),l(.241,-.37),l(.652,-.152),l(-.328,-.06),l(.146,-.409),l(-.28,.093),l(-.096,.132),l(.11,.079),l(-.315,.191),l(-.035,-.224),l(-.093,.053),l(.051,.224),l(-.081,.086),l(-.051,-.158),l(-.097,-.066),l(-.103,.416),l(-.447,-.079),l(.402,.501),l(-.294,.666),l(.07,.237),l(.272,.488),l(-.055,.139),l(-.466,-.317),l(-.1,-.211),l(.026,.205),l(.174,.218),l(.421,.237),l(.132,.508),l(-.631,-.402),l(-.354,-.007),l(-.118,-.283),l(-.155,-.053),l(.066,.25),l(-.541,-.323),l(-.33,.04),l(.015,-.29),l(.427,-.323),l(-.428,.079),l(-.19,.468),l(.204,.231),l(.457,.046),l(.202,.25),l(.954,.297),l(-.047,.092),l(.554,.165),l(.158,.132),l(-.22,.468),l(-.227,.06),l(-1.042,-.804),l(.708,.811),l(.626,.171),l(-.248,.092),l(.323,.079),l(-.045,.079),l(.061,.06),l(-.034,.25),l(-.312,-.191),l(-.071,.073),l(.104,.211),l(-.216,.02),l(-.656,-.56),l(-.023,.026),l(.419,.475),l(.309,.158),l(.182,-.026),l(.191,.21),l(.018,.31),l(-.298,.059),l(-.492,-.534),l(-.474,-.198),l(-.199,.16),l(.046,.044),l(.44,.145),l(.488,.382),l(-.047,.237),l(.442,-.033),l(.031,-.119),l(.748,.119),l(.151,.382),l(.406,1.212),l(.448,.803),l(-.14,-.092),l(-.262,-.349),l(-.059,-.132),l(-.359,-1.172),l(-.147,-.277),l(-.056,.31),l(.135,0),l(.034,.198),l(-.292,-.066),l(.173,.283),l(.144,.099),l(.228,.58),l(-.144,-.053),l(-.211,-.382),l(.002,.224),l(-.52,-.303),l(-.06,.059),l(.266,.303),l(-.247,.119),l(-.526,-.204),l(.225,.204),l(-.375,.211),l(-.173,-.02),l(-.251,-.21),l(-.024,-.217),l(.083,-.158),l(-.081,-.053),l(-.091,.204),l(.044,.23),l(.116,.211),l(-.107,.158),l(.894,.02),l(.571,-.145),l(.125,.165),l(-.113,.191),l(-.072,.369),l(.14,.066),l(.092,-.257),l(.135,-.369),l(.18,-.105),l(.266,.31),l(.047,.296),l(-.166,.25),l(-.163,-.013),l(-.063,-.099),l(-.316,.474),l(-.254,.197),l(-.483,-.053),l(-.203,-.065),l(-.147,-.066),l(-.136,-.245),l(-.151,.014),l(.141,.244),l(-.075,.013),l(-.538,-.125),l(-.436,-.151),l(.162,.185),l(.269,.026),l(.833,.335),l(-.034,.119),l(-.396,.145),l(.247,.007),l(-.19,.25),l(-.281,.138),l(-.149,0),l(-.481,-.375),l(.242,.395),l(.43,.164),l(.302,-.171),l(.292,.026),l(.11,-.204),l(.04,.178),l(.217,.04),l(.048,.079),l(-.428,.322),l(-.013,.085),l(-.261,.072),l(-1.498,.214),l(-.865,.895),l(-.487,.609),l(-.13,.127),l(-.935,.143),l(-.528,.128),l(-.617,.241),l(-.678,.539),l(-.225,.424),l(-.096,.354),l(-.819,.694),l(-.693,.383),l(-.429,.199),l(-.797,.086),l(-.35,.58),l(-.177,.198),l(-.809,1.125),l(-.273,.781),l(-.459,1.249),l(.236,1.455),l(.387,.925),l(.456,.873),l(.934,1.562),l(.352,1.746),l(.486,1.194),l(-.075,.092),l(.287,.276),l(.123,.333),l(.062,.827),l(-.301,1.536),l(-.064,.278),l(-.31,.415),l(.108,.424),l(-.02,.252),l(-.393,.551),l(-.017,-.092),l(.129,-.241),l(-.025,-.138),l(-.256,.035),l(-.38,.137),l(-.291,-.126),l(-.509,.138),l(-.12,-.329),l(.014,-.233),l(-.567,-1.068),l(-.764,-.138),l(-.204,-.352),l(-.113,-.819),l(-.423,-.229),l(-.144,-.702),l(-.373,.093),l(-.608,-1.08),l(-.375,-.482),l(.296,0),l(.375,-.438),l(.048,-.226),l(-.167,-.226),l(-.471,.407),l(-.277,-.208),l(.126,-.573),l(.147,-.758),l(.158,-1.043),l(-.293,-.452),l(-.258,-.169),l(-.496,-.126),l(-.832,-.987),l(-.875,-.804),l(-.528,-.168),l(-.43,.072),l(-.536,.298),l(-.456,.354),l(-1.202,.299),l(-.273,-.213),l(-.131,-.62),l(-.253,-.254),l(-.264,-.113),l(-.752,-.069),l(-.516,-.296),l(-.22,-.233),l(-.504,.138),l(-1.052,.115),l(-.653,-.184),l(-.047,.298),l(-.64,.099),l(-.183,0),l(-.578,-.926),l(-.238,.781),l(-.447,-.135),l(-.65,.001),l(-1.328,-.04),l(-.672,.439),l(-.39,.055),l(-1,-.459),l(-.096,.009),l(-.142,.014),l(-.362,.528),l(.201,.229),l(.303,0),l(.211,0),l(.537,-.207),l(.406,.092),l(.676,.482),l(-.68,.373),l(.02,.254),l(.263,.353),l(.593,.146),l(.229,.217),l(.35,.334),l(-.533,.136),l(-.503,-.084),l(-.276,-.419),l(-.79,-.271),l(-.224,-.211),l(-.265,-.056),l(-.013,.02),l(-.209,.32),l(.209,.154),l(.248,.183),l(-.248,.179),l(-.069,.05),l(-.447,-.459),l(-.476,.192),l(-.287,.291),l(-1.025,-.472),l(-.419,-.494),l(-1.16,-.642),l(-.615,.066),l(.554,.393),l(-.307,.187),l(-1.17,-.083),l(-.886,-.252),l(-.896,-.168),l(-1.547,.173),l(-.632,.328),l(-.392,-.015),l(-.433,-.031),l(-.135,-.49),l(-.333,.057),l(-.112,.184),l(.474,.731),l(-.877,.64),l(-.808,.577),l(-.915,.317),l(-.419,.043),l(-.414,-.056),l(-.728,-.111),l(-.126,.198),l(.437,.437),l(-.239,.396),l(-.327,.199),l(-.631,.114),l(-.737,.27),l(-.268,.17),l(.558,.352),l(.111,.169),l(-.659,.694),l(-.154,.297),l(-.012,.848),l(.144,.636),l(.271,.762),l(.425,.903),l(-.347,-.119),l(-.816,-.377),l(-.296,.001),l(-.416,.116),l(-.264,-.069),l(-1.029,-.56),l(-.921,-.32),l(-.375,-.365),l(-.336,-.592),l(-.332,-.932),l(-.078,-.467),l(-.268,-.253),l(-.657,-.576),l(-.845,-1.042),l(-.744,-1.227),l(-.663,-1.029),l(-.363,-.366),l(-.412,-.252),l(-.783,-.321),l(-.475,-.082),l(-.643,.018),l(-.468,.201),l(-.576,.541),l(-.418,.413),l(-.283,.37),l(-.416,.158),l(-.501,-.011),l(-.337,-.069),l(-1.104,-.503),l(-1.092,-.659),l(-.445,-.549),l(-.318,-.847),l(-.284,-.678),l(-.179,-.226),l(-.708,-.491),l(-.837,-.519),l(-.766,-.632),l(-.631,-.662),l(-.209,-.112),l(-1.892,-.046),l(-1.858,-.003),l(-.096,.892),l(-.213,.101),l(-1.867,.011),l(-.966,-.037),l(-1.544,-.02),l(-1.662,-.019),l(-.338,-.055),l(-3.516,-1.112),l(-2.811,-.933),l(-1.186,-.39),l(-.267,-.154),l(-.316,-.31),l(-2.381,.084),l(-2.367,.155),l(-.34,.017),M(49.818,152.776),l(-.122,.086),l(-.279,.03),l(-.111,-.131),l(-.177,-.005),l(-.324,.051),l(-.304,-.39),l(-.071,-.263),l(.339,-.01),l(.299,-.253),l(.188,.218),l(.106,.294),l(.223,.096),l(.233,.279),M(52.785,154.312),l(-.155,-.081),l(-.085,-.356),l(-.461,-.321),l(.095,-.229),l(.143,-.058),l(.366,.209),l(.344,.055),l(.616,.356),l(-.005,.172),l(-.294,.184),l(-.563,.069),M(111.683,77.224),l(-.138,.415),l(-.45,.067),l(-.324,.113),l(-.295,.247),l(-.321,-.137),l(-.185,-.21),l(.087,-.443),l(.086,-.443),l(-.438,-.675),l(-.463,-.319),l(-.199,-.271),l(-1.281,.055),l(-.437,.098),l(-.153,.161),l(-.496,.097),l(-.019,-.193),l(-.034,-.432),l(.212,-.272),l(.184,-.212),l(-.378,-.347),l(-.641,-.438),l(-.693,-.696),l(-.723,-.317),l(-.453,-.136),l(.132,-.35),l(-.569,-.592),l(-.099,-.213),l(.371,-.229),l(-.068,-.122),l(-.301,-.152),l(-.445,-.076),l(-.392,-.274),l(-.237,-.259),l(-.57,-.305),l(-1,-.411),l(-.479,-.765),l(-.217,-.583),l(-.367,-.399),l(-.357,.016),l(-.101,.814),l(.42,.873),l(.104,.306),l(-.047,.153),l(-.701,-.136),l(-.272,-.076),l(-.511,-.504),l(-.4,-.459),l(-.537,.139),l(-1.219,-.228),l(1.263,.718),l(.032,.214),l(-1.62,.171),l(-1.093,-.35),l(-1.388,-.948),l(-.543,-.292),l(-.664,-.043),l(-.079,0),l(-.933,-.213),l(-1.3,-.536),l(.928,-.248),l(.135,-.169),L(90.8,67.129),l(-.384,-.153),l(-.792,.156),l(-.454,.14),l(-.656,.017),l(-1.058,-.06),l(-1.068,-.245),l(.027,-.247),l(-.148,-.186),l(-.325,-.108),l(-.359,.016),l(-.47,.202),l(-1.036,.049),l(-1.465,-.122),L(80.46,66.64),l(-.786,-.091),l(-.248,-.108),l(-.651,-.387),l(-.427,-.527),l(-.301,.218),l(-.788,.157),l(-.89,-.293),l(-.234,-.326),l(-.417,-.139),l(-.872,-.248),l(-1.538,-.23),l(-.817,-.248),l(-.671,-.342),l(-.553,.235),l(-.675,.079),l(.06,.437),l(-.193,.062),l(-.389,.25),l(-.249,.405),l(1.119,.293),l(.174,.294),l(-.096,.388),l(-.428,.449),l(-.458,.001),l(-.804,-.214),l(-.586,-.061),l(-.568,.094),l(-.978,.603),l(-1.066,.217),l(-.936,.448),l(-1.035,.448),l(-1.095,.109),l(.178,-.308),l(.063,-.123),l(.72,-.401),l(-.093,-.385),l(-.655,-.523),l(.004,-.108),L(64.1,66.19),l(.411,-.482),l(.157,-.42),l(.736,-.312),l(.87,-.235),l(1.165,-.018),l(1.085,.123),l(.239,-.156),l(-1.239,-.466),l(-.971,-.389),l(-1.043,.049),l(-.226,.219),l(-.449,.095),l(-.573,.438),l(-.865,.375),l(-1.019,.282),L(61.553,65.9),l(-.406,.094),l(-.298,.14),l(.131,.325),l(-.177,.526),l(-.563,.34),l(-.564,.078),L(59,67.544),l(-.592,.278),l(-.681,.601),l(-.035,.292),l(.38,.168),l(.36,.03),l(.667,.106),l(.465,.229),l(-.075,.184),l(-.43,.338),l(-.625,.2),l(-.557,.277),l(-.423,.398),l(-.544,.383),l(-.675,.093),l(-1.434,.308),l(-.678,.397),l(-1.036,.337),l(-.7,.367),l(.52,.5),l(-.1,.167),l(-1.106,.412),l(-.897,.153),l(-.778,.168),L(49.51,74.19),l(-1.214,.456),L(48.1,74.828),l(-.274,.394),l(-.753,.439),l(-1.193,.229),l(-1.234,.184),l(-.973,-.345),l(.001,-.181),l(.332,-.348),l(.763,-.273),l(.306,-.212),l(.445,-.364),l(1.171,-.441),l(1.403,.073),l(-.12,-.212),l(.02,-.516),l(.47,-.304),l(.725,-.291),l(.754,-.366),l(.266,-.214),l(.002,-.731),l(.246,-.749),l(.693,-.49),l(.194,-.398),l(.034,-.412),l(-.633,.122),l(-1.251,.186),l(-.676,-.029),l(-.5,-.597),l(-.266,.062),l(-.613,.216),l(-.136,.23),l(.239,.352),l(.021,.352),l(-.169,.046),L(47,70.115),l(-.567,-.32),l(-.487,-.397),l(-.509,-.291),l(-.56,-.03),l(-.812,-.106),l(-.91,.094),l(.028,.138),l(-.644,.338),l(-1.175,.14),l(-.649,-.09),l(-.064,-.123),l(-.082,-.107),l(-.125,-1.028),l(.3,-.508),l(-.142,-.431),l(-.864,-1.002),l(-1.43,.437),l(-.738,.078),l(-.406,.202),l(-1.091,.094),l(-.4,-.23),l(-.394,-.355),l(-.466,-.325),l(-1.007,-.463),l(-.179,-.28),l(.292,-.171),l(.337,-.437),l(.704,.139),l(1.312,.309),l(.69,.03),l(.238,-.234),l(-.375,-.482),l(-.458,-.264),l(-.363,0),l(-.541,.22),l(-.528,-.015),l(-1.342,-.513),l(-.623,-.186),l(-.197,.016),l(-.858,-.029),l(-.024,-.078),l(-.623,-.985),l(.79,-.19),l(.071,-.456),l(.495,-.221),l(.102,-.299),l(.227,-.347),l(.893,-.491),l(.337,-.38),l(.386,-.301),l(.527,-.476),l(.39,-.175),l(.719,.109),l(.98,.268),l(.485,.094),l(.752,-.144),l(.427,-.254),l(.675,-.429),l(1.252,-.257),l(.774,-.033),l(.955,-.049),l(.354,-.175),l(.187,-.478),l(-.259,-.669),l(-.814,-.686),l(.026,-.096),l(.927,-.034),l(.343,-.256),l(-.25,-.384),l(-.497,-.256),l(-.367,-.08),l(-1.88,.389),L(39.33,56.53),l(-.534,.289),l(-.496,.065),l(-1.907,-.333),l(-.848,-.031),L(34.8,56.49),l(-1.27,.162),l(-1.265,-.029),l(-1.349,-.174),l(-.53,-.207),l(-.183,-.788),l(.144,-.146),l(.636,-.033),l(1.008,-.002),l(.446,-.179),l(-1.057,-.241),l(-1.912,-.304),L(28.13,54.31),l(-1.285,-.208),l(.219,-.114),l(.781,-.262),l(1.568,-.214),l(1.325,-.328),l(.958,-.214),l(1.058,-.361),l(.953,-.23),l(1.399,-.281),l(1.513,.128),l(-.158,.523),l(.023,.277),l(1.051,.161),l(1.359,.095),l(1.074,-.019),l(.657,-.099),l(.784,-.246),l(.55,-.295),l(.262,-.083),l(.752,.064),l(.751,.113),l(1.021,-.051),l(.2,-.327),l(.007,-.18),l(-.689,-.064),l(-1.946,-.292),l(-1.283,-.047),l(-.312,-.755),l(-1.473,-.162),l(-.96,-.031),l(-1.573,-.096),l(-.194,-.511),l(-.484,-.312),l(-1.042,-.461),l(-.512,-.148),l(-2.66,-.659),l(-2.008,-.545),l(.317,-.167),l(.812,-.402),l(.086,-.485),l(2.136,-.054),l(.99,-.069),l(1.829,-.288),l(.784,-.354),l(.452,-.623),l(.788,-.575),l(.616,-.525),l(.818,-.41),l(.742,-.224),l(1.066,-.104),l(1.133,-.241),l(1.047,-.036),l(1.804,.065),l(.146,-.188),l(-.156,-.205),L(44.47,42.83),l(.018,-.206),l(1.936,-.089),l(1.143,.032),l(.974,-.054),l(1.344,-.14),l(1.098,-.416),l(.918,-.417),l(.957,-.019),l(.282,.051),l(.675,.241),l(.156,.172),l(-.383,.139),l(.017,.344),l(1.049,.136),l(.424,.034),l(.536,-.293),l(.297,-.208),l(1.419,.187),l(1.534,.049),l(1.062,.049),l(.715,.033),l(.711,.257),l(.359,.274),l(.783,.358),l(.494,.085),l(.421,-.086),l(1.292,.117),l(1.124,.015),l(1.556,-.054),l(1.449,-.088),l(1.213,.1),l(1.377,.254),l(.883,.118),l(3.424,.13),l(1.279,.168),l(.743,.169),l(2.027,-.038),l(2.339,-.141),l(1.123,.236),l(2.441,.791),l(1.206,.301),l(.227,.008),l(.102,.483),l(-.003,2.855),l(.039,2.259),l(.052,2.335),l(.129,2.796),l(-.026,2.183),l(-.043,4.334),l(.026,2.167),l(.089,1.046),l(.196,.279),l(.84,.074),l(2.424,-.122),l(.739,.059),l(.332,.388),l(.173,.387),l(.348,.292),l(2.162,1.318),l(.945,.673),l(.238,-.325),l(.848,-.205),l(1.225,-.67),l(.731,-.498),l(.495,-.126),l(.832,.073),l(.316,.199),l(.371,.492),l(.35,.322),l(2.048,1.175),l(.814,.58),l(1.769,1.768),l(1.67,1.882),l(.512,.393),l(.189,.029),l(.98,.314),l(2.025,.763),l(.402,.255),l(-.163,.788),l(.393,.777), +N(643.755,159.873),l(-1.092,-.52),l(-.637,-.337),l(-.203,-1.284),l(.036,-.282),l(.24,-.241),l(.42,-.241),l(.721,-.623),l(.493,.056),l(.049,-.17),l(.24,-.396),l(.239,.028),l(.573,.225),l(.321,-.312),l(.439,-.001),l(.798,-.171),l(.596,.69),l(-.163,.17),l(-.443,.354),l(-.412,.538),l(-.285,.734),l(.14,.296),l(-.22,.311),l(-.292,.085),l(-1.026,.383),l(-.532,.707),M(627.173,150.012),l(-.679,.314),l(-.24,.241),l(-.043,.325),l(.138,.592),l(.228,.366),l(.119,.521),l(-.109,.339),l(-.266,.213),l(-.769,-.08),l(-.321,-.21),l(-.178,-.196),l(-.153,-.239),l(-.111,-.38),l(-.628,.413),l(-.647,.159),l(-.246,-.083),l(-.378,-.266),l(-.341,-.746),l(-.291,-.379),l(-.481,.045),l(-.507,.003),l(-.228,-.098),l(-.117,-.352),l(.729,-1.584),l(-.033,-.268),l(-.521,-.096),l(-.554,.074),l(-.202,-.324),l(-.277,-1.762),l(-.156,-.126),l(-.479,.017),l(-.771,.089),l(-.819,.442),l(-.312,.086),l(-.216,-.069),l(0,-.268),l(.224,-.58),l(-.163,-.705),l(-.075,-.465),l(.617,-.85),l(.191,-.198),l(.487,-.271),l(.611,-.525),l(.429,-.722),l(.353,-.862),l(-.02,-.875),l(-.195,-1.649),l(-.146,-.14),l(-.504,.031),l(-.287,-.041),l(-.217,-.309),l(-.243,-.901),l(-.397,-.435),l(-.504,-.279),l(-.277,.044),l(-.306,.34),l(-.001,.127),l(-.624,-.081),l(-.73,-.179),l(-.657,-.081),l(-.3,-.055),l(-.102,-.056),l(.138,-.269),l(.354,-.454),l(-.046,-.38),l(-.716,-.715),l(-.455,-.392),l(-1.377,.84),l(-.377,.044),l(-.975,-.319),l(-.286,-.167),l(-.355,.087),l(-.546,.299),l(-1.105,.726),l(-.829,.258),l(-.543,.37),l(-1.123,1.107),l(-.397,.27),l(-.714,.216),l(-.784,.033),l(-.189,.1),l(-.329,-.619),l(-.312,-.209),l(-.371,-.041),l(-1.659,-.047),L(601,137.538),l(-.309,-.294),l(-.417,.016),l(-.149,.103),l(-.348,.239),l(-.609,.539),l(-1.251,1.545),l(-.212,-.662),l(.052,-.861),l(-.139,-.183),l(-.231,-.069),l(-.471,.102),l(-.345,.129),l(-.655,-.159),l(-.339,.281),l(-.341,-.116),l(-.849,.066),l(-.319,-.364),l(-.63,-.281),l(-.407,0),l(-.08,.331),l(-.271,.083),l(-.685,-.38),l(.01,.364),l(-.237,.099),l(-.141,-.463),l(-.54,-.496),l(-.365,.066),l(-.935,-.066),l(-.014,-.265),l(.175,-.396),l(-.326,-.017),l(-.333,.248),l(-1.451,-.893),l(.069,-.281),l(-.178,-.38),l(-.289,-.166),l(-.71,.116),l(-.158,.166),l(-.657,-.794),l(-.454,-.281),l(-.15,.132),l(-.472,-.215),l(-.726,-.595),l(-.867,-.264),l(-.132,-.612),l(-1.079,-.199),l(-.186,.182),l(-.275,-.066),l(-.134,.513),l(-.276,.314),l(-.299,-.05),l(-.24,-.43),l(-.859,-.596),l(-.154,.066),l(-.756,-.248),l(.116,-.364),l(-1.078,-.579),l(-.363,.116),l(-.772,-.843),l(-.383,-.248),l(-.477,.314),l(-.198,-.066),l(-.099,-.43),l(.215,-.215),l(-.272,-.364),l(.104,-.446),l(-.579,-.595),l(-.157,-.694),l(.785,-.198),l(.033,.364),l(.337,.264),l(.368,-.049),l(.376,-.281),l(.578,-.364),l(-.367,-.694),l(.104,-.414),l(-.68,-.099),l(-.044,-.182),l(-.092,-.078),l(-.718,-.096),l(-.294,-.221),l(-.037,-.552),l(-.073,-.589),l(.184,-.184),l(.331,-.221),l(-.221,-.258),l(-.441,-.405),l(-.81,-.11),l(-.221,-.515),l(-.441,-1.03),l(0,-.515),l(-.502,.152),l(-.147,-.126),l(-.305,-.111),l(-1.337,-.104),l(-.565,-.436),l(-.178,-.09),l(-.104,-.199),l(-.239,0),l(-.52,.196),l(-.252,-.281),l(-.198,-.218),l(-.301,-.07),l(.312,-.516),l(-.007,-.501),l(-.213,-.247),l(-.373,-.323),l(-.625,.009),l(-.282,.128),l(-.004,-.456),l(-.554,-.117),l(-.296,-.047),l(-.281,.21),l(-.105,-.112),l(-.313,-.14),l(-.048,-.088),l(-.236,-.012),l(-.01,-.269),l(.574,.059),l(.192,-.145),l(.354,-.136),l(.08,-.249),l(.181,-.185),l(-.2,-.163),l(.152,-.36),l(-.245,-.237),l(.126,-.428),l(-.049,-.123),l(-.152,-.012),l(-.028,-.246),l(.009,-.284),l(-.295,-.494),l(-.273,-.154),l(-.692,-.039),l(-.22,-.06),l(-.229,.162),l(-.463,.045),l(-.325,-.394),l(-.077,-.305),l(.207,-.223),l(-.023,-1.031),l(.011,-.069),l(.139,-.739),l(.129,-.213),l(.274,-.186),l(1.422,-.704),l(1.737,-.734),l(.359,-.03),l(.06,.071),l(.183,.567),l(.344,.055),l(.507,-.145),l(.885,-.132),l(.268,-.243),l(.463,-.784),l(.467,-.472),l(.238,-.03),l(1.248,.235),l(.459,-.017),l(.478,-.102),l(.646,-.345),l(.638,-.701),l(.405,-.301),l(.445,-.145),l(1.338,-.349),l(.97,-.219),l(.325,-.187),l(.051,-.157),l(-.031,-.194),l(-.139,-.86),l(.02,-.399),l(.32,-.401),l(.705,-.546),l(.222,-.33),l(-.119,-.47),l(-.29,-.441),l(-.345,-.627),l(-.03,-1.357),l(-.483,-.141),l(-.366,.06),l(-.232,-.185),l(.068,-.215),l(.215,-.302),l(.393,-.188),l(1.799,-.254),l(1.082,-.207),l(.35,-.06),l(.5,.184),l(1.133,.238),l(.394,-.074),l(.231,-.145),l(.156,-.245),l(-.126,-.286),l(-.622,-.514),l(.137,-.418),l(.286,-.605),l(.438,-.794),l(.516,-1.141),l(.427,-.507),l(1.096,.254),l(.721,.141),l(.594,.141),l(1.402,.079),l(.718,-.062),l(.417,-.103),l(.444,-.392),l(.157,-.39),l(-.213,-.707),l(-.097,-.75),l(.34,-.581),l(.428,-.277),l(1.199,-.093),l(.289,-.06),l(.306,-.219),l(.035,-.478),l(.011,-.275),l(.279,-.262),l(.542,-.148),l(.551,-.034),l(.228,-.014),l(.569,-.003),l(.244,-.074),l(.062,.145),l(.131,.405),l(.24,.563),l(.371,.433),l(1.301,.745),l(.834,.415),l(.614,.069),l(.731,.167),l(.633,.144),l(.354,.143),l(.568,.618),l(1.07,1.451),l(.401,.66),l(-.215,.447),l(-.237,.75),l(-.214,.389),l(-.369,.347),l(-.035,.129),l(.105,.43),l(.233,.229),l(.724,.312),l(1.062,.181),l(1.505,.021),l(.995,.038),l(.668,.083),l(.998,.224),l(.632,.268),l(1.645,.806),l(.839,.31),l(.744,.096),l(.105,.542),l(1.571,2.161),l(.467,.439),l(.444,.254),l(1.979,.018),l(1.241,.207),l(.802,.109),l(1.165,.022),l(2.861,-.059),l(.937,.023),l(1.164,.022),l(1.69,.119),l(.521,.168),l(.815,.551),l(1.006,.365),l(1.599,.433),l(.929,.123),l(.663,-.061),l(.61,.067),l(.253,.297),l(.433,.197),l(.481,-.017),l(.686,-.289),l(1.44,-.534),l(.303,-.101),l(.736,-.274),l(.816,-.289),l(1.204,-.349),l(1.339,-.007),l(1.514,-.065),l(.987,.08),l(.651,-.061),l(1.941,-.737),l(.265,-.172),l(1.111,-1.046),l(.67,-.389),l(1.265,-.292),l(.326,-.259),l(.123,-.271),l(-.188,-.228),l(-.599,-.411),l(-.389,-.569),l(-.003,-.343),l(.214,-.401),l(.539,-.589),l(.457,-.231),l(.316,-.073),l(.718,.154),l(.668,.382),l(.592,.125),l(.982,-.005),l(.744,-.047),l(.742,-.433),l(1.192,-.91),l(.224,.013),l(.438,.012),l(.624,.054),l(.896,-.134),l(.638,-.248),l(.347,-.188),l(.241,-.216),l(.312,-.82),l(.363,-.333),l(.47,-.204),l(.464,-.045),l(.483,.127),l(.353,-.189),l(.831,-.278),l(.539,-.146),l(.937,-.221),l(.854,-.033),l(.432,.099),l(1.074,.008),l(.464,.127),l(.414,-.218),l(.107,-.217),l(-.048,-.273),l(-.599,-.501),l(-.879,-.99),l(-.797,-.5),l(-.538,-.199),l(-.928,-.212),l(-.438,.002),l(-1.191,.786),l(-.292,-.07),l(-.431,-.416),l(-.317,-.085),l(-.576,.018),l(-.754,.062),l(-.929,.395),l(-.342,.045),l(-.051,-.029),l(-.269,-.836),l(.381,-.58),l(1.224,-1.959),l(.687,-1.207),l(.295,-.31),l(.046,.018),l(.452,.172),l(1.126,.574),l(.343,-.016),l(.438,-.089),l(2.44,-.752),l(.779,-.339),l(.123,-.233),l(-.056,-.306),l(-.35,-.348),l(-.062,-.146),l(.103,-.249),l(.422,-.426),l(.416,-.543),l(.667,-.779),l(.599,-.545),l(1.371,-.608),l(.167,-.794),l(-.107,-.249),l(-.465,-.306),l(-.558,-.026),l(-.822,.078),l(.119,-.25),l(.375,-.282),l(1.193,-.787),l(.478,-.165),l(.602,-.136),l(1.854,-.143),l(.836,-.123),l(1.203,-.109),l(.917,-.049),l(1.148,.215),l(1.037,.481),l(.683,.188),l(1.386,-.125),l(.539,.026),l(.763,.467),l(.742,.952),l(1.087,2.384),l(.94,1.588),l(.927,1.903),l(.436,.389),l(.507,.2),l(1.247,.341),l(1.523,.253),l(2.659,.839),l(.205,.144),l(.297,.866),l(.44,1.283),l(.261,.446),l(.68,-.033),l(.649,-.018),l(1.657,-.052),l(.604,-.22),l(.953,-.308),l(1.357,-.31),l(1.181,-.208),l(.902,-.034),l(.246,.114),l(.064,.259),l(.116,.389),l(.017,.504),l(-.566,.407),l(-.66,.393),l(-.291,.707),l(-.278,.893),l(-.538,1.066),l(-.627,1.08),l(-.329,.432),l(-.551,.69),l(-.47,.347),l(-.547,-.098),l(-.679,-.225),l(-.685,-.24),l(-.396,-.041),l(-1.664,.982),l(-.048,.557),l(.332,.897),l(.062,.656),l(-.006,.613),l(-.025,.385),l(-.097,.128),l(.112,.299),l(-.156,.329),l(-.511,.43),l(-1.252,.462),l(-.111,.058),l(-.579,-.68),l(-.247,.001),l(-.253,.129),l(-.383,.358),l(-.23,.713),l(-.955,.532),l(-.62,.259),l(-.538,.017),l(-.452,-.054),l(-.333,-.126),l(-.392,.059),l(-.273,.243),l(-.025,.342),l(.508,.765),l(.046,.113),l(-.527,.159),l(-.975,.048),l(-.508,-.153),l(-.493,-.253),l(-.273,-.396),l(-.448,.017),l(-.386,.13),l(-.686,1.027),l(-.636,.543),l(-1.032,.545),l(-1.533,.604),l(-.52,.329),l(-.415,.442),l(-.379,.528),l(-.066,-.092),l(-.417,.171),l(-1.222,.13),l(-.728,.171),l(-2.248,.925),l(-.632,.37),l(-.566,.469),l(-.604,.271),l(-.336,.015),l(.13,-.255),l(.862,-.682),l(.33,-.354),l(-.47,-.113),l(-.37,.072),l(-.153,-.297),l(.058,-.156),l(.953,-.781),l(.269,-.384),l(.55,-.413),l(.159,-.2),l(-.057,-.298),l(-.73,-.553),l(-.727,-.283),l(-.131,-.014),l(-.628,.03),l(-.166,.015),l(-.494,.371),l(-1.146,1.183),l(-.355,.157),l(-.643,.086),l(-.613,.243),l(-.36,.199),L(665.49,112),l(-.136,.411),l(-.131,.255),l(-.251,.255),l(-.437,.128),l(-.493,-.013),l(-.326,.27),l(-.307,.114),l(-.455,-.565),l(-.355,-.014),l(-.349,.128),l(-.396,.638),l(-.301,.694),l(.088,.34),l(.245,.368),l(.558,.268),l(.8,.268),l(1.21,-.045),l(.29,.254),l(-.019,.538),l(-.123,.581),l(.057,.538),l(.261,.283),l(.733,.069),l(.698,-.157),l(.76,-.525),l(.509,-.497),l(.552,-.228),l(.534,-.128),l(.287,.07),l(.895,.621),l(.543,.197),l(1.023,-.087),l(.361,.027),l(.471,.141),l(.274,0),l(-.248,.708),l(-.057,.552),l(-.612,-.197),l(-.297,-.084),l(-.525,.058),l(-1.677,.555),l(-.707,.44),l(-.072,.735),l(-.522,.157),l(-.146,-.113),l(-.017,-.269),l(-.127,-.084),l(-.501,.114),l(.138,.466),l(-.152,.368),l(-.485,.496),l(-1.397,1.119),l(-.126,.226),l(.039,.55),l(.62,.225),l(.712,.492),l(.785,.521),l(.391,.535),l(.424,1.241),l(.668,.647),l(.175,.437),l(-.13,.677),l(.172,.183),l(.694,.295),l(.399,.592),l(.562,.253),l(.272,.268),l(.087,.31),l(-.049,.155),l(-.789,.369),l(.088,.07),l(.425,.31),l(.314,.79),l(-.019,.296),l(-.141,.184),l(-.534,.043),l(-.651,.213),l(-.948,.552),l(-.849,.213),l(-.629,.297),l(.72,.21),l(.378,.056),l(.944,-.425),l(.488,-.058),l(.162,.056),l(.524,.592),l(.387,.168),l(.456,.027),l(.009,.155),l(-.231,.311),l(-.382,.227),l(-.304,.241),l(.11,.155),l(.326,-.029),l(.202,.084),l(-.184,.325),l(-.298,.749),l(-.192,.649),l(.028,.353),l(-.22,.452),l(-.209,.127),l(-.35,-.338),l(-.146,.142),l(-.569,.763),l(-.401,.622),l(-.215,.622),l(-.127,.296),l(-.595,.425),l(-.251,.438),l(-.254,.184),l(-.569,.029),l(-.382,.227),l(.279,.719),l(-.264,.508),l(.076,.593),l(-.093,.269),l(-.207,.269),l(-.532,.199),l(-.161,.282),l(-.174,.396),l(-.294,.636),l(-.626,.354),l(-.412,.495),l(-.492,-.14),l(-.443,-.069),l(-.142,.113),l(-.145,.198),l(.118,.833),l(-.213,.142),l(-.772,.651),l(-.356,.127),l(-.628,.171),l(-.563,.467),l(-.571,.213),l(-.107,.113),l(-.008,.48),l(-.133,.156),l(-.568,.058),l(-.5,.114),l(-.341,.438),l(-.364,-.126),l(-.52,-.168),l(-.274,.057),l(-.315,.326),l(-.435,.198),l(-.643,.1),l(-.047,-.465),l(-.52,.057),l(-.699,.213),l(-.32,.198),l(-.285,-.042),l(-.401,-.493),l(-.163,-.155),l(-.191,.283),l(.095,.169),l(-.045,.212),l(-.047,.691),l(-.209,.297),l(-.416,.114),l(-.501,-.182),l(-.123,.282),l(-.001,.24),l(-.146,.155),l(-.615,.058),l(-.366,.114),l(-.596,.043),l(-.463,-.211),l(-.217,.1),l(-.439,.48),l(-.227,.071),l(-.774,-.041),l(-.747,.227),l(-.406,.326),l(-.451,-.027),l(-.277,-.084),l(-.011,.057),l(-.069,.353),l(-.29,.396),l(.011,.113),l(.48,.634),l(.269,.126),l(.043,.198),l(-.36,.269),l(-.763,.157),l(-.481,-.719),l(-.241,-.691),l(.012,-.395),l(.396,-.777),l(-.015,-.169),l(-.587,-.253),l(-.226,.071),l(-.206,.297),l(-.454,.072),l(-.676,-.21),l(-.574,-.733),l(-.196,.085),l(-.017,.169),l(-.159,.396),l(-.27,.128),l(-.332,-.056),l(-.481,.043),l(-.055,.038),l(-.197,-.143),l(-.909,-.107),l(-.621,-.166),l(-.943,-.615),l(-.273,-.365),l(-.096,-.521),l(.472,-.75),l(-.056,-.38),l(-.237,-.21),l(-.777,.047),l(-.66,-.053),l(-.771,-.235),l(-.623,-.575),l(-.298,.101),l(-.521,.328),l(-.696,.554),l(-.341,.157),l(-.807,.117),l(-1.595,.052),l(-.332,.115),l(-.584,.413),l(-.325,-.097),l(-.597,-.392),l(-.341,-.012),l(-.515,.13),l(-.483,.229), +N(241.073,156.152),l(.017,.52),l(.098,1.215),l(.012,.212),l(-.379,.455),l(-.011,.17),l(.485,1.358),l(-.669,-.577),l(-.445,-.056),l(-.761,.143),l(-.877,-.012),l(-.666,-.14),l(-.574,-.056),l(-.474,.1),l(-.378,.354),l(-.135,-.042),l(-.993,-.549),l(-.171,-.325),l(.04,-.198),l(.269,-.184),l(1.051,.097),l(.631,.111),l(1.125,.167),l(.654,.041),l(.61,-.185),l(.386,-.156),l(-.198,-.155),l(-.692,-.464),l(-.136,-.296),l(.184,-.707),l(-.202,-.296),l(-.394,-.154),l(-.913,-.14),l(-.305,-.211),l(.04,-.184),l(.119,-.085),l(.344,-.1),l(.724,-.058),l(.781,.125),l(1.081,.294),l(.576,.056),l(.147,-.089), +N(241.295,160.082),l(-.485,-1.358),l(.011,-.17),l(.379,-.455),l(-.012,-.212),l(-.098,-1.215),l(-.017,-.52),l(.503,-.279),l(.393,.14),l(.342,0),l(.384,-.17),l(.369,-.043),l(.14,.198),l(.177,.112),l(1,.309),l(.657,-.072),l(.213,.395),l(.335,.338),l(.528,.324),l(.335,.084),l(.643,.21),l(.916,.45),l(.399,.352),l(.231,.311),l(-.191,.17),l(-.144,.297),l(-.314,.368),l(-.238,-.098),l(-.476,-.592),l(-.378,-.042),l(-.788,.058),l(-.288,-.098),l(-.373,0),l(-.329,.1),l(-.763,.539),l(-.396,-.056),l(-.319,-.494),l(-.166,-.028),l(-.155,.057),l(-.658,.326),l(-.344,.778),l(-.41,.65),l(-.289,-.112),l(-.325,-.551), +N(668.053,167.796),l(-.131,-.099),l(-.74,-.732),l(-.444,-1.255),l(.037,-.424),l(.054,-.706),l(-.292,-.465),l(.18,-.382),l(.978,.704),l(.202,-.424),l(.023,-.41),l(-.101,-.438),l(-.026,-.579),l(.145,-.438),l(.025,-.664),l(.082,-.861),l(.074,-.636),l(.38,-.862),l(.188,-.127),l(.337,-.142),l(.523,.055),l(1.21,.52),l(.576,.042),l(.188,-.212),l(.277,-.17),l(.199,.141),l(.018,.396),l(-.266,.438),l(-.045,.48),l(.14,.79),l(.541,.394),l(.182,.325),l(-.427,1.271),l(-.31,.467),l(-.834,.608),l(-.555,.312),l(-.082,.099),l(.003,.268),l(-.078,.565),l(-.28,.424),l(.127,.211),l(.35,.733),l(.345,1.101),l(.26,.62),l(.093,.028),l(.451,.324),l(.296,.07),l(.161,-.325),l(.485,-.537),l(.197,-.029),l(.418,.112),l(.226,.211),l(.179,.635),l(.286,.353),l(.326,.084),l(.505,-.58),l(.621,.267),l(.141,.028),l(.078,.127),l(-.168,.156),l(-.378,.156),l(-.208,.212),l(.936,1.226),l(-.315,.184),l(-.568,-.196),l(-.404,-.098),l(-.094,-.48),l(-.229,-.31),l(-.599,-.535),l(-.753,-.577),l(-.258,0),l(-.099,.226),l(.371,.776),l(-.218,.283),l(-.727,-.775),l(-.982,-.548),l(-.309,.015),l(-.344,.142),l(-.182,.255),l(-.14,.071),l(-.395,.057),l(-.322,-.225),l(-.591,-.366),l(-.195,-.423),l(.64,-.608),l(.323,.211),l(.358,.084),l(.4,-.199),l(-.151,-.169),l(-.713,-.295),l(-.422,-.395),l(-.522,-.168),l(-.239,.607),M(669.676,172.974),l(-.452,-.366),l(-.349,-.408),l(-.051,-.226),l(-.364,-1.114),l(-.459,-.521),l(.685,-.058),l(.868,.012),l(.314,.169),l(.274,.451),l(.028,.861),l(-.097,.48),l(-.214,.283),l(-.185,.438),M(679.073,175.368),l(-.562,-.267),l(-.178,-.254),l(-.237,-.169),l(-.064,-.127),l(.139,-.339),l(-.091,-.423),l(-.55,-.352),l(-.662,-.479),l(-.147,-.466),l(.513,-.1),l(1.017,-.143),l(.371,.112),l(.283,.409),l(.069,.818),l(.123,.805),l(.257,.79),l(-.112,.127),l(-.167,.057),M(671.406,176.824),l(.022,-.353),l(.186,-1.342),l(.061,-1.172),l(.482,.395),l(.576,.281),l(.366,.028),l(.634,-.185),l(.027,.438),l(-.079,.396),l(-.24,.269),l(-.184,.198),l(-.908,.651),l(-.943,.397),M(664.721,177.812),l(-.366,-.027),l(.127,-.297),l(.202,-.099),l(.314,-.396),l(.265,-.523),l(.082,-.607),l(.138,-.509),l(.326,-.184),l(.14,.183),l(-.16,.283),l(.276,.55),l(.212,.564),l(-.108,.113),l(-.664,.354),l(-.406,.368),l(-.377,.227),M(673.781,179.981),l(-.385,-.366),l(-.828,-.591),l(-.206,-.38),l(.099,-.368),l(.565,-.213),l(.22,-.269),l(.487,-1.822),l(.438,-.185),l(.271,.028),l(.113,.126),l(.049,.282),l(-.373,.905),l(-.089,.226),l(-.315,1.413),l(.165,.296),l(.214,.465),l(-.213,.41),l(-.212,.043),M(661.179,181.308),l(-.317,-.042),l(.215,-.48),l(.343,-.467),l(.35,-.34),l(.592,-.354),l(.636,-.496),l(.933,-1.089),l(.11,.55),l(-.118,.424),l(-.267,.297),l(-.24,.184),l(-.516,.213),l(-.172,.127),l(-.244,.622),l(-.327,.269),l(-.591,.171),l(-.386,.41),M(680.678,185.402),l(-.201,-.098),l(-.098,-.438),l(-.361,-.748),l(-.297,-.112),l(-.381,.608),l(-.361,.82),l(.246,.38),l(.166,.395),l(.148,.677),l(-.158,.495),l(-.383,.509),l(-.305,-.253),l(-.176,-.268),l(.201,-.41),l(-.076,-.325),l(-.363,-.07),l(-.361,.665),l(-.173,-.056),l(-1.114,-.619),l(-.557,-.549),l(-.206,-.508),l(-.037,-.635),l(.466,-.905),l(-.108,-.479),l(-.466,-.409),l(-.778,-.295),l(-.292,.043),l(-.062,.17),l(-.129,.226),l(-.5,.255),l(-.661,.058),l(-.027,-.494),l(-.174,-.24),l(-.399,.199),l(-.504,.961),l(-.525,.863),l(-.219,-.084),l(-.119,-.127),l(-.034,-.197),l(.054,-.311),l(.359,-.749),l(.185,-.537),l(.263,-.283),l(.383,-.184),l(.564,-.044),l(.219,-.127),l(.134,-.466),l(.205,-.156),l(.549,-.241),l(.777,-.101),l(.292,.353),l(.102,.72),l(.317,-.156),l(.485,-.058),l(.207,-.184),l(.207,-.565),l(.358,-.255),l(.479,.21),l(.186,.084),l(.158,-1.087),l(.29,-.015),l(.264,.465),l(.315,-.481),l(.205,-.142),l(.392,.098),l(.133,-.227),l(-.048,-.706),l(-.172,-.564),l(.146,-.353),l(.413,.549),l(.711,.803),l(.229,.48),l(.083,.324),l(-.336,.735),l(.237,.226),l(.537,-.1),l(.076,.423),l(-.114,.424),l(.056,.692),l(.207,.437),l(-.002,.438),l(-.111,.424),l(-.283,.579),l(-.332,.622), +N(251.898,160.229),l(-.547,-.112),l(-.073,-.212),l(.051,-.551),l(-.109,-.24),l(.11,-.17),l(.235,-.071),l(.543,.069),l(.404,-.015),l(1.505,.11),l(.393,.168),l(.113,.141),l(-.188,.354),l(-.07,.099),l(-.283,.227),l(-.335,.043),l(-.739,-.083),l(-.657,.072),l(-.354,.17), +N(228.82,160.519),l(-.299,-.056),l(-.693,-.224),l(-.229,-.268),l(-.47,-.366),l(-.465,-.084),l(-.142,-.211),l(.53,-.284),l(.704,-.072),l(1.364,.251),l(.97,.351),l(.651,.267),l(.279,.282),l(-.04,.198),l(-.332,.071),l(-.751,-.295),l(-.543,.058),l(-.227,.255),l(-.308,.128), +N(400.72,175.499),l(-.595,-.119),l(-.161,-.032),l(-.976,.458),l(-1.429,-.006),l(-.867,-.037),l(-2.119,.041),l(-.271,.157),l(-.125,.34),l(.261,1.934),l(.02,.41),l(-.191,.17),l(-.63,-.434),l(-.644,-.166),l(-.769,.075),l(-.608,.159),l(-.446,.257),l(-.368,.115),l(-.354,-.083),l(-.452,-.223),l(-.52,-.562),l(-.15,-.465),l(-.308,-.252),l(-.545,.003),l(-.259,-.168),l(.08,-.043),l(.046,-.156),l(.172,-.326),l(.261,-.92),l(.133,-.876),l(-.058,-.749),l(.141,-.255),l(.257,-.016),l(.448,-.158),l(.543,-.271),l(.317,-.369),l(.292,-1.047),l(.355,-1.217),l(.397,-.384),l(.273,-.058),l(.293,.281),l(.551,.364),l(.45,-.102),l(.174,-.227),l(.393,-.822),l(.492,-.667),l(.638,-.625),l(.272,-.101),l(.518,.209),l(.324,.182),l(.274,.027),l(.314,-.793),l(.304,-.228),l(.947,-.458),l(1.22,-.713),l(.37,-.073),l(.356,.125),l(.36,.059),l(1.062,.173),l(-.173,.665),l(.019,.396),l(.426,.93),l(.422,.492),l(.389,.266),l(.502,.42),l(.179,.268),l(.018,.212),l(-.335,.439),l(.114,.226),l(.97,.757),l(.516,.181),l(.37,-.044),l(.562,.025),l(.568,.971),l(.131,.367),l(-.237,.764),l(-.415,.468),l(-.337,.158),l(-.739,-.095),l(-.418,.045),l(-.415,.271),l(-.366,.553),l(-.24,.157),l(-.062,.142),l(-.29,-.041),l(-.611,-.166),l(-1.013,-.163), +N(209.823,175.47),l(-.388,-.645),l(-.932,-.888),l(-1.003,-1.085),l(-.837,-.817),l(-.723,-.464),l(-.196,-.183),l(-.023,-.226),l(.625,-.03),l(1.001,-.125),l(.29,-.143),l(.293,-.412),l(.005,-.961),l(.882,-.034),l(.513,-.583),l(.725,.42),l(1.207,-.997),l(.503,-.794),l(.294,-.242),l(.259,.013),l(.328,.182),l(.463,.097),l(.248,-.086),l(.424,-.229),l(1.425,-.486),l(.23,.519),l(.038,.339),l(-.057,.509),l(-.214,.707),l(-.543,.806),l(-.1,.749),l(.042,.904),l(-.245,1.13),l(-.188,.735),l(-.101,1.385),l(.031,.55),l(.184,.466),l(.188,.363),l(-.281,.274),l(-.767,-.149),l(-.241,-.46),l(-.285,.077),l(-.394,-.107),l(-.603,.25),l(-1.651,-.599),l(-.43,.271), +N(634.036,168.444),l(.533,.251),l(.736,.165),l(.341,.111),l(.469,.251),l(.248,-.058),l(.095,-.24),l(-.103,-.211),l(-.187,-.182),l(-.107,-.296),l(.392,-.285),l(.476,-.186),l(.444,.181),l(.373,.351),l(.3,-.072),l(.975,-.429),l(.209,-.114),l(-.215,.905),l(.029,.663),l(.455,1.014),l(-.076,.367),l(-.05,.424),l(.054,1.073),l(-.217,.509),l(-.385,.285),l(-.599,.187),l(-.932,.443),l(-.521,.229),l(-.99,.571),l(-.234,.425),l(.216,.422),l(.568,.435),l(.03,.197),l(-.17,.27),l(-.688,-.194),l(-.497,-.011),l(-.599,.229),l(-.915,.528),l(-.646,.229),l(-.3,.289),l(-.256,-.188),l(-.248,-.268),l(-.35,-.042),l(-.382,.142),l(-.205,-.042),l(-.293,.043),l(-.183,-.113),l(.142,-.311),l(.182,-.226),l(-.04,-.254),l(-.283,-.395),l(-.277,.043),l(-.462,.298),l(-.339,.015),l(-.171,-1.044),l(-.649,-1.488),l(.146,-.176),l(-.16,-.479),l(-.487,-.717),l(-.219,-.648),l(-.026,-.635),l(.076,-.382),l(.146,-.297),l(.92,-1.233),l(.521,-.441),l(.383,-.101),l(1.172,-.091),l(.798,.066),l(.558,-.074),l(.575,.039),l(.599,.109),l(.301,.167), +N(214.474,175.913),l(.821,.884),l(.385,.623),l(.314,.322),l(.225,.046),l(.465,.645),l(.441,.352),l(-.014,.006),l(-.074,.123),l(-.478,-.184),l(-.219,.205),l(-.014,.321),l(0,.58),l(.507,.307),l(-.396,.368),l(.125,.532),l(-.374,.369),l(.243,.184),l(-.204,.609),l(.003,-.466),l(-.296,-.307),l(.01,-.568),l(-.377,-.148),l(-.238,-.102),l(-.111,.082),l(.325,.41),l(.084,.225),l(-.113,.062),l(-.726,-.299),l(-.13,-.282),l(.251,-.339),l(.04,-.382),l(-.182,-.338),l(-.486,-.324),l(-.695,-.287),l(-.079,-.144),l(-.689,-.103),l(-.316,-.327),l(.007,-.421),l(-.146,-.255),l(-.249,-.098),l(-.576,-.353),l(-.416,-.266),l(.225,.512),l(.086,.222),l(.422,.044),l(.181,.266),l(-.544,.573),l(-.144,-.262),l(-.356,-.282),l(-.561,-.211),l(-.323,-.239),l(-.147,-.24),l(-.104,-.494),l(.128,-.421),l(.332,-.225),l(-.008,-.389),l(-.554,-.225),l(.363,-.123),l(-.057,-.227),l(-.238,.017),l(.43,-.271),l(1.651,.599),l(.603,-.25),l(.394,.107),l(.285,-.077),l(.241,.46),l(.767,.149),l(.281,-.274), +N(436.304,195.359),l(-.209,-.451),l(-.194,-.804),l(-.498,-.802),l(-1.217,-1.236),l(-.112,-.324),l(-.064,-.791),l(-.432,-.605),l(-.4,-.661),l(-.207,-.592),l(-.273,-1.185),l(-.112,-.776),l(.064,-.424),l(.144,-.198),l(.528,-.399),l(.4,-.511),l(.866,-1.743),l(.354,-.327),l(.208,-.114),l(.096,.084),l(.24,.027),l(.449,-.158),l(1.363,-.686),l(.494,.661),l(.225,.069),l(.224,-.03),l(.466,-.271),l(.754,-.386),l(.818,-.273),l(.881,.009),l(.368,-.031),l(.258,-.143),l(.646,-1.176),l(.117,-.806),l(.209,-.199),l(.434,-.059),l(2.181,-.055),l(.386,-.087),l(2.649,-2.275),l(.196,-.284),l(.005,-.41),l(.165,-.382),l(.372,-.228),l(.939,-.613),l(.322,-.086),l(.321,.012),l(.559,.208),l(1.342,1.673),l(.347,.549),l(.122,.536),l(-.416,1.472),l(.01,.664),l(.158,.211),l(.802,-.019),l(.272,-.001),l(.207,.126),l(.252,.493),l(.223,.225),l(.797,.447),l(.799,.235),l(.351,.196),l(.223,.267),l(-.148,.481),l(.173,.395),l(.445,.351),l(.558,.378),l(.717,.434),l(.207,.168),l(.206,.366),l(.059,.72),l(.285,.436),l(.367,.224),l(.814,.165),l(.558,.477),l(.157,.352),l(-.083,.679),l(.031,.07),l(-.496,.145),l(-.962,.344),l(-.319,-.026),l(-.287,-.167),l(-.687,-.264),l(-1.15,-.361),l(-.4,.13),l(-.082,.551),l(-.13,.241),l(-.256,.058),l(-.399,-.026),l(-.862,-.207),l(-.593,.102),l(-.93,.373),l(-.93,.486),l(-.271,.016),l(-.559,-.35),l(-.383,-.153),l(-.353,.186),l(-.677,1.36),l(-.176,.157),l(-.591,-.067),l(-1.934,-.511),l(-1.422,-.189),l(-.512,-.322),l(-.159,-.239),l(-.334,-.394),l(-.75,-.518),l(-.432,-.167),l(-.479,.06),l(-.529,.3),l(-.353,.341),l(-.785,.979),l(-.097,.297),l(.096,.452),l(-.017,.353),l(-.063,.594),l(-.16,.058),l(-.751,.287),l(-.895,-.093),l(-.624,-.138),l(-.367,-.054),l(-.975,.175),l(-.479,.102),l(-.255,.228),l(-.222,1.287),l(-.158,.523),l(-.365,.497),l(-.303,.312), +N(371.324,180.419),l(1.088,-1.235),l(.643,-.866),l(.238,-.157),l(.594,.039),l(1.137,-.148),l(.466,.04),l(.42,.224),l(.456,.421),l(.475,.619),l(.252,.761),l(.165,1.369),l(.26,.656),l(-.259,.502),l(-1.184,1.151),l(-.63,.724),l(-.285,.256),l(-.061,.103),l(-.631,-.523),l(-.661,-.408),l(-.483,-.196),l(-.033,-.141),l(.061,-.297),l(-.05,-.184),l(-.531,-.21),l(-.792,-.549),l(-.389,-.366),l(-.375,-.465),l(.494,-.241),l(.174,-.227),l(-.034,-.155),l(-.484,-.211),l(-.065,-.113),l(.022,-.173), +N(579.606,186.906),l(-.493,-.083),l(-.265,-.197),l(-.21,-.353),l(-.246,-.621),l(-.361,-1.256),l(-.034,-.649),l(.005,-.763),l(-.02,-.904),l(-.24,-.696),l(.188,-.513),l(-.298,-.35),l(.068,-.28),l(.423,.023),l(.349,-.43),l(.053,-.367),l(.226,-.369),l(-.152,-.537),l(.529,.48),l(.699,.38),l(.234,.395),l(.549,.776),l(.175,.324),l(-.099,.339),l(.024,.141),l(.592,.338),l(.266,.733),l(.798,1.368),l(.136,.508),l(-.193,.735),l(-.397,.679),l(-.369,.396),l(-.514,.425),l(-.78,.284),l(-.642,.043), +N(217.111,178.792),l(.52,.307),l(.195,.512),l(.02,.374),l(.363,.155),l(.628,.024),l(.244,-.205),l(.398,.43),l(.726,.082),l(.458,-.083),l(1.348,-.751),l(.514,-.046),l(1.387,-.921),l(.373,.144),l(.742,.069),l(.071,.156),l(.789,-.017),l(.767,.21),l(.666,.38),l(.644,.563),l(.406,.666),l(.084,.327),l(.228,.149),l(.509,1.038),l(-.322,.062),l(-.094,.43),l(-.584,.409),l(-.085,-.307),l(-.19,-.082),l(.045,.45),l(-.228,.082),l(-.256,.753),l(-.378,-.825),l(-.441,-.762),l(-.137,-.452),l(.179,-.24),l(.22,-.085),l(.786,.125),l(-.336,-.193),l(-.125,-.164),l(-.096,-.471),l(-.309,.307),l(-.439,.041),l(-.244,-.378),l(-.031,-.269),l(-.193,-.282),l(-.132,.151),l(-.226,-.287),l(-.11,.102),l(-.132,-.266),l(-.456,-.192),l(-.562,-.013),l(-.499,.241),l(-.382,.108),l(-.07,.359),l(.081,.234),l(-.529,.318),l(-.374,.184),l(-.335,.029),l(-.345,.41),l(.049,.296),l(.316,.297),l(.464,.43),l(.178,.386),l(-.011,.146),l(-.281,.081),l(-.243,-.042),l(-.431,.391),l(-.568,.105),l(-.339,-.042),l(-.189,-.146),l(.108,-.164),l(-.349,-.833),l(-.244,-.353),l(-.177,.674),l(-.812,-.409),l(-.227,-.757),l(-.207,.041),l(-.96,-.123),l(-.434,-.266),l(-.599,0),l(-.314,.113),l(-.361,.495),l(.204,-.609),l(-.243,-.184),l(.374,-.369),l(-.125,-.532),l(.396,-.368),l(-.507,-.307),l(0,-.58),l(.014,-.321),l(.219,-.205),l(.478,.184),l(.074,-.123), +N(266.015,188.956),l(-.503,-.647),l(-.732,-.745),l(-.324,-.521),l(.071,-.212),l(.395,-.539),l(-.008,-.58),l(.061,-.452),l(1.032,-.19),l(.41,-.144),l(.308,-.299),l(-.141,-.282),l(-.62,-.604),l(-.074,-.212),l(.101,-.255),l(1.655,-1.239),l(.061,-.41),l(-.095,-.296),l(.072,.049),l(.496,.338),l(.856,.521),l(.695,.521),l(.587,.663),l(.128,.409),l(-.036,.734),l(.148,.945),l(.298,-.593),l(.22,-.099),l(.6,.182),l(.101,.127),l(.507,.295),l(.708,.549),l(.401,.493),l(.374,.649),l(-.015,.339),l(-.142,.496),l(-.082,.862),l(-.183,.27),l(-1.131,.091),l(-.169,.17),l(.078,.777),l(-.095,.467),l(-.328,.694),l(.571,.831),l(.532,.675),l(.561,.067),l(.185,.295),l(.246,.832),l(.49,1.127),l(.332,.563),l(-.06,.212),l(-.943,-.022),l(-.934,.429),l(-1,.331),l(-.505,.314),l(-.694,.513),l(-.686,.075),l(-.613,-.392),l(-1.103,-.897),l(-.15,-.296),l(-.008,-.396),l(.072,-.354),l(-.167,-.31),l(-.281,-.394),l(-.156,-.465),l(.213,-.962),l(.547,-1.416),l(.179,-.368),l(-.435,-.958),l(-.533,-.138),l(-.304,.001),l(.452,-1.09),l(-.04,-.212),l(-.26,-.111),l(-.516,-.124),l(-.302,.058),l(-.375,.257), +N(377.518,182.142),l(.193,-.376),l(.252,-.242),l(.367,-.143),l(.528,-.046),l(.338,.097),l(.165,.366),l(.22,.846),l(.009,.65),l(-.044,.283),l(.277,.323),l(.404,.322),l(.321,.026),l(.756,-.922),l(.143,-.086),l(.337,.097),l(.339,.224),l(-.062,.17),l(.119,.55),l(-.059,.438),l(-.501,.865),l(.05,.183),l(.194,.183),l(.369,.097),l(.592,-.032),l(1.264,1.334),l(.131,.282),l(-.059,.452),l(-.247,.849),l(-.105,.565),l(-.041,.919),l(-1.513,-.643),l(-1.221,-.619),l(-1.012,-.562),l(-.403,-.423),l(-1.129,-1.113),l(-1.111,-.76),l(-.723,-.337),l(-.901,-.535),l(-.66,-.548),l(.061,-.103),l(.285,-.256),l(.63,-.724),l(1.184,-1.151),l(.259,-.502), +N(429.505,210.684),l(.484,.336),l(.177,.013),l(.443,-.271),l(.327,-.581),l(1.495,-.532),l(.054,.424),l(.042,.664),l(.147,.211),l(.57,-.328),l(.554,-.399),l(.931,-.811),l(.364,-.229),l(1.025,-.938),l(.086,-.706),l(-.122,-.72),l(.074,-.396),l(.193,-1.159),l(.343,-.751),l(.47,-.836),l(.41,-.454),l(.809,-.599),l(.525,-.229),l(.459,-.427),l(.139,-.523),l(.169,-.708),l(.115,-.61),l(.254,-1.342),l(.196,-2.021),l(.156,-.764),l(.094,-.551),l(.349,-.821),l(.558,-.837),l(.398,-1.203),l(.031,-.156),l(-.128,-.197),l(.16,-.058),l(.063,-.594),l(.017,-.353),l(-.096,-.452),l(.097,-.297),l(.785,-.979),l(.353,-.341),l(.529,-.3),l(.479,-.06),l(.432,.167),l(.75,.518),l(.334,.394),l(.159,.239),l(.512,.322),l(1.422,.189),l(1.934,.511),l(.591,.067),l(.176,-.157),l(.677,-1.36),l(.353,-.186),l(.383,.153),l(.559,.35),l(.271,-.016),l(.93,-.486),l(.93,-.373),l(.593,-.102),l(.862,.207),l(.399,.026),l(.256,-.058),l(.13,-.241),l(.082,-.551),l(.4,-.13),l(1.15,.361),l(.687,.264),l(.287,.167),l(.319,.026),l(.962,-.344),l(.496,-.145),l(.143,.239),l(.795,.772),l(.348,.493),l(.525,.477),l(.366,.195),l(.352,-.016),l(.258,-.242),l(.529,-.37),l(.384,.012),l(.684,.631),l(.16,-.1),l(.436,-.582),l(.258,-.157),l(.207,.083),l(1.032,.926),l(1.288,1.32),l(.063,.028),l(.159,.183),l(-.018,.424),l(-.26,1.88),l(.128,.253),l(.191,.027),l(.479,.04),l(.271,.182),l(.111,.31),l(-.191,.453),l(-1.195,1.066),l(-1.241,.996),l(-.255,.284),l(-.395,.681),l(-.217,1.02),l(-.107,.507),l(.021,.593),l(-.025,.734),l(.057,.748),l(-.076,.27),l(-.188,.298),l(-.426,.412),l(-.301,.171),l(-.269,.256),l(-.122,.425),l(-.49,1.358),l(.197,.338),l(.689,.999),l(.087,.381),l(-.04,.438),l(.014,.636),l(.237,.634),l(.017,1.329),l(-.064,.762),l(.425,1.439),l(-.102,.848),l(.122,.693),l(.486,.631),l(.936,.898),l(.428,.78),l(.689,1.804),l(-.563,.068),l(-3.015,.499),l(-.347,.214),l(-.154,.198),l(-.797,1.276),l(-.029,.622),l(.372,2.088),l(-.377,1.175),l(-.3,1.02),l(.043,.296),l(.456,.605),l(.837,.843),l(.445,.279),l(.515,.012),l(.448,-.455),l(.362,-.186),l(.136,.183),l(.032,.791),l(.028,1.427),l(-.041,.551),l(-.371,-.012),l(-1.355,-.091),l(-.348,-.21),l(-.381,-.647),l(-.561,-.731),l(-.416,-.351),l(-.477,-.252),l(-.895,-.263),l(-.38,-.28),l(-.728,-1.423),l(-.212,.354),l(-.522,.682),l(-.366,.087),l(-.325,-.111),l(-.922,-.164),l(-.925,-.249),l(-.489,-.194),l(-.58,-1.014),l(-.175,.071),l(-1.146,.289),l(-.195,-.056),l(-.172,-.352),l(-.365,-.379),l(-.678,-.096),l(-1.24,-.147),l(-.991,.146),l(-.859,.26),l(-.61,.004),l(-.199,-.197),l(-.007,-.254),l(.198,-.905),l(.003,-.466),l(-.306,-.62),l(-.844,-.998),l(-.117,-.211),l(-.021,-.212),l(.296,-1.033),l(.07,-1.06),l(-.109,-.607),l(-.303,-.605),l(.057,-.354),l(.177,-.693),l(-.052,-.183),l(-.322,-.098),l(-1.231,.093),l(-.88,.019),l(-.212,-.168),l(.055,-.48),l(-.181,-.225),l(-2.016,.082),l(-.112,.001),l(-.089,.354),l(.027,.593),l(-.286,.892),l(-.184,.411),l(-.993,.006),l(-.899,-.122),l(-1.021,.246),l(-.88,.034),l(-.292,-.168),l(-.64,-.787),l(-.597,-1.07),l(-.537,-1.409),l(-.059,-.579),l(-.121,-.521),l(-.082,-.127),l(-.321,-.111),l(-.385,-.012),l(-1.104,-.008),l(-.88,.034),l(-.624,.003),l(-1.312,-.048),l(-.945,-.052),l(-.783,.02),l(-.432,.03),l(-.318,.101),l(-.896,.062),l(-.699,.314),l(-.56,.06),l(-.112,-.013),l(-.322,-.922),l(.012,-.053),l(.74,-.3),l(-.017,-.085),l(.1,-.89),l(.094,-.143),l(.317,-.199),l(.583,-.568), +N(468.568,202.653),l(1.277,-.05),l(4.659,0),l(1.448,-.033),l(4.663,2.568),l(3.553,1.984),l(.137,.381),l(-.116,.552),l(.07,.239),l(2.427,1.752),l(1.067,.807),l(-.237,.427),l(-.419,1.329),l(-.137,1.017),l(.109,.551),l(.665,.987),l(.768,.577),l(-.024,.282),l(-.263,.354),l(-.371,1.046),l(.037,.17),l(.306,.041),l(.118,.226),l(-.172,.692),l(-.019,.946),l(.411,1.793),l(.18,.564),l(.401,.465),l(.823,.55),l(.396,.268),l(.177,.228),l(-1.157,.836),l(-.515,.342),l(-1.218,.402),l(-1.243,.559),l(-.448,.031),l(-.646,-.42),l(-.276,-.083),l(-.21,.326),l(-.543,.766),l(-.396,.144),l(-.42,-.054),l(-.964,.006),l(-.963,.02),l(-.512,-.294),l(-.323,-.394),l(-.229,-.083),l(-.123,.128),l(-.643,.356),l(-.526,.088),l(-1.019,-.149),l(-.898,-.018),l(-.196,-.559),l(-.135,-.766),l(-.053,-.584),l(-.135,-.946),l(-.448,-.841),l(-.663,-.538),l(-1.014,-.107),l(-.223,.016),l(-.385,-.407),l(-.732,-.349),l(-1.574,-.57),l(-1.269,-.6),l(-.729,-.265),l(-.263,-.21),l(-.703,-.641),l(-.689,-1.804),l(-.428,-.78),l(-.936,-.898),l(-.486,-.631),l(-.122,-.693),l(.102,-.848),l(-.425,-1.439),l(.064,-.762),l(1.252,-.348),l(.388,-.539),l(.645,-1.204),l(.687,-.853),l(.346,-.271),l(.044,-.212),l(-.148,-.239),l(-.273,-.125),l(-.401,-.068),l(-.211,-.211),l(.158,-.976),l(.304,-.016),l(.396,-.158),l(.142,-.17),l(.104,-.481),l(-.167,-.493),l(-.364,-.888),l(-.121,-.748), +N(464.786,206.235),l(-.197,-.338),l(.49,-1.358),l(.122,-.425),l(.269,-.256),l(.301,-.171),l(.426,-.412),l(.064,.042),l(.546,.223),l(.431,-.045),l(.458,-.427),l(.554,-.398),l(.319,-.017),l(.121,.748),l(.364,.888),l(.167,.493),l(-.104,.481),l(-.142,.17),l(-.396,.158),l(-.304,.016),l(-.559,.031),l(-.508,.159),l(-.391,.567),l(-.158,.085),l(-.396,.13),l(-.789,-.32),l(-.688,-.024), +N(465.79,210.652),l(-.017,-1.329),l(-.237,-.634),l(-.014,-.636),l(.04,-.438),l(-.087,-.381),l(-.689,-.999),l(.688,.024),l(.789,.32),l(.396,-.13),l(.158,-.085),l(.391,-.567),l(.508,-.159),l(.559,-.031),l(-.158,.976),l(.211,.211),l(.401,.068),l(.273,.125),l(.148,.239),l(-.044,.212),l(-.346,.271),l(-.687,.853),l(-.645,1.204),l(-.388,.539),l(-1.252,.348), +N(427.243,211.207),l(.536,-.414),l(.68,-.513),l(.351,-.13),l(.695,.533),l(-.583,.568),l(-.317,.199),l(-.094,.143),l(-.1,.89),l(.017,.085),l(-.74,.3),l(.143,-.625),l(-.082,-.24),l(-.505,-.796),M(427.998,213.843),l(.112,.013),l(.56,-.06),l(.699,-.314),l(.896,-.062),l(.318,-.101),l(.432,-.03),l(.783,-.02),l(.945,.052),l(1.312,.048),l(.624,-.003),l(.88,-.034),l(1.104,.008),l(.385,.012),l(.321,.111),l(.082,.127),l(.121,.521),l(.059,.579),l(.537,1.409),l(.597,1.07),l(.64,.787),l(.292,.168),l(.88,-.034),l(1.021,-.246),l(.899,.122),l(.993,-.006),l(.184,-.411),l(.286,-.892),l(-.027,-.593),l(.089,-.354),l(.112,-.001),l(2.016,-.082),l(.181,.225),l(-.055,.48),l(.212,.168),l(.88,-.019),l(1.231,-.093),l(.322,.098),l(.052,.183),l(-.177,.693),l(-.057,.354),l(.303,.605),l(.109,.607),l(-.07,1.06),l(-.296,1.033),l(.021,.212),l(.117,.211),l(.844,.998),l(.306,.62),l(-.003,.466),l(-.198,.905),l(.007,.254),l(.199,.197),l(.61,-.004),l(.859,-.26),l(.991,-.146),l(1.24,.147),l(-.214,1.344),l(.195,1.059),l(.269,.323),l(.089,.254),l(-.132,.368),l(-.436,.44),l(-.124,.594),l(-.125,.086),l(-.517,-.04),l(-3.408,.091),l(-.051,.877),l(.015,1.342),l(-.024,3.249),l(.017,.848),l(.023,.594),l(.099,.438),l(.308,.394),l(.471,.436),l(1.354,1.391),l(.611,.632),l(-.93,.218),l(-1.96,.379),l(-1.044,.203),l(-.717,-.08),l(-1.164,.063),l(-.408,-.083),l(-.349,-.21),l(-2.024,.026),l(-.697,-.024),l(-.622,-.151),l(-.401,-.322),l(-.305,-.366),l(-.408,-.096),l(-.989,-.023),l(-2.59,.016),l(-1.636,-.019),l(-.631,-.011),l(-1.296,-.006),l(-2.201,.013),l(-.636,-.151),l(-.463,-.309),l(-.45,-.478),l(-.294,-.083),l(-.499,.088),l(-.591,.286),l(-.778,.513),l(-.758,-.462),l(-.352,.144),l(-.248,.197),l(.048,-1.809),l(-.017,-.805),l(-.029,-.649),l(.397,-.34),l(.221,-.269),l(.26,-.707),l(.163,-.734),l(.184,-1.398),l(.239,-.976),l(.321,-.918),l(.584,-.665),l(.183,-.565),l(.268,-.354),l(.64,-.228),l(.268,-.325),l(.423,-.679),l(.364,-1.201),l(.053,-.664),l(-.046,-.848),l(-.191,-.959),l(-.201,-.536),l(-.492,-.705),l(-.476,-.776),l(-.268,-.775),l(.139,-.495),l(.476,-.382),l(.158,-.156),l(.107,-.424),l(-.006,-.479),l(-.199,-.579),l(-.489,-.69),l(-.441,-.733),l(-.203,-1.031),l(-.181,-.423),l(-.276,-.366),l(-.666,-.974),l(-.072,-.15), +N(452.198,239.34),l(-.611,-.632),l(-1.354,-1.391),l(-.471,-.436),l(-.308,-.394),l(-.099,-.438),l(-.023,-.594),l(-.017,-.848),l(.024,-3.249),l(-.015,-1.342),l(.051,-.877),l(3.408,-.091),l(.517,.04),l(.125,-.086),l(.124,-.594),l(.436,-.44),l(.132,-.368),l(-.089,-.254),l(-.269,-.323),l(-.195,-1.059),l(.214,-1.344),l(.678,.096),l(.365,.379),l(.172,.352),l(.195,.056),l(1.146,-.289),l(.175,-.071),l(.58,1.014),l(.489,.194),l(.925,.249),l(.922,.164),l(.325,.111),l(.366,-.087),l(.522,-.682),l(.212,-.354),l(.728,1.423),l(.38,.28),l(.895,.263),l(.477,.252),l(.416,.351),l(.561,.731),l(.381,.647),l(.348,.21),l(1.355,.091),l(.371,.012),l(.041,-.551),l(-.028,-1.427),l(-.032,-.791),l(-.136,-.183),l(-.362,.186),l(-.448,.455),l(-.515,-.012),l(-.445,-.279),l(-.837,-.843),l(-.456,-.605),l(-.043,-.296),l(.3,-1.02),l(.377,-1.175),l(-.372,-2.088),l(.029,-.622),l(.797,-1.276),l(.154,-.198),l(.347,-.214),l(3.015,-.499),l(.563,-.068),l(.703,.641),l(.263,.21),l(.729,.265),l(1.269,.6),l(1.574,.57),l(.732,.349),l(.385,.407),l(.559,.887),l(.434,.859),l(.013,.324),l(-.183,.27),l(-.709,.344),l(-.011,.127),l(.04,.594),l(-.091,1.682),l(.08,.353),l(.216,.168),l(.511,.266),l(.072,.197),l(-.197,.241),l(-.472,.258),l(-.792,.259),l(-.146,.34),l(-.094,.764),l(-.3,.807),l(.2,.479),l(.261,.408),l(.394,.125),l(-1.264,.53),l(-1.696,.575),l(-.932,.4),l(-2.165,.578),l(-.187,.128),l(-.009,.495),l(.152,.465),l(.087,.438),l(-.505,-.096),l(-.999,.049),l(-.794,.259),l(-.636,.54),l(-.312,.539),l(-.019,.579),l(-.168,.199),l(-.285,.114),l(-.999,.062),l(-.621,.202),l(-.306,.341),l(-.777,.937),l(-.562,.738),l(-.825,.951),l(-.354,.045),l(-.803,-.165),l(-.421,-.309),l(-.334,.129),l(-.521,.286),l(-.404,.017),l(-.594,-.209),l(-.264,-.097),l(-.154,-.169),l(-.163,-.027),l(-.187,-.154),l(-.456,-.393),l(-.294,-.055),l(-1.089,-.093),l(-.086,-.099),l(-.165,-.056),l(-1.845,.364), +N(477.231,225.874),l(-.224,1.184),l(-.107,.48),l(.252,.917),l(.177,1.017),l(.149,.408),l(.238,.268),l(.803,.588),l(1.189,1.166),l(.454,.661),l(.14,.48),l(-.155,2.346),l(-.04,.41),l(-.214,.213),l(-.432,.073),l(-.322,.017),l(-.229,.213),l(-.076,.622),l(.08,.509),l(.029,.479),l(-.096,.283),l(-.185,-.111),l(-.562,-.463),l(-.763,-1.112),l(-.484,-.548),l(-.234,-.423),l(.036,-.212),l(.499,-.61),l(.116,-.227),l(.025,-.693),l(-.1,-.96),l(-.22,-.479),l(-.261,-.056),l(-.674,.061),l(-.702,.132),l(-.27,-.211),l(-.343,-.407),l(-.382,-.549),l(-.195,-.041),l(-.394,-.125),l(-.261,-.408),l(-.2,-.479),l(.3,-.807),l(.094,-.764),l(.146,-.34),l(.792,-.259),l(.472,-.258),l(.197,-.241),l(-.072,-.197),l(-.511,-.266),l(-.216,-.168),l(-.08,-.353),l(.091,-1.682),l(-.04,-.594),l(.011,-.127),l(.709,-.344),l(.183,-.27),l(-.013,-.324),l(-.434,-.859),l(-.559,-.887),l(.223,-.016),l(1.014,.107),l(.663,.538),l(.448,.841),l(.135,.946),l(.053,.584),l(.135,.766),l(.196,.559), +N(245.934,224.314),l(.939,.136),l(1.122,.304),l(.355,-.03),l(.946,-.824),l(.336,.026),l(.48,.025),l(.415,-.243),l(1.471,-1.109),l(.874,-.485),l(.36,-.158),l(.934,-.076),l(1.283,.021),l(.045,.748),l(-.079,.621),l(-.064,.622),l(.036,.818),l(.141,.635),l(.335,.591),l(.813,.928),l(1.1,.939),l(.316,.097),l(.787,.023),l(.355,-.03),l(.676,.25),l(.688,.307),l(.75,.603),l(.3,.098),l(.882,.037),l(.096,.014),l(.385,.774),l(.398,.308),l(.22,.084),l(1.148,-.077),l(.636,.123),l(.537,.166),l(.403,.237),l(.085,.169),l(-.038,.565),l(.203,1.029),l(.03,.706),l(.138,2.032),l(.249,.944),l(.153,.112),l(.967,.036),l(.5,.012),l(1.615,.019),l(.693,.024),l(.042,.296),l(-.261,.835),l(.067,.563),l(.436,.407),l(.73,.362),l(.316,.479),l(.307,.774),l(.022,.494),l(-.185,1.173),l(-.238,.834),l(-.38,.765),l(-.421,.666),l(-.089,-.084),l(-1.952,-.991),l(-.352,-.054),l(-.928,.02),l(-.843,-.01),l(-.126,.128),l(-1.076,.204),l(-1.104,.162),l(-.784,.202),l(-.33,.044),l(-.332,.383),l(-.698,1.105),l(-.278,.341),l(-.133,.509),l(.016,.635),l(-.385,1.188),l(-.395,1.104),l(-.149,.325),l(-.592,-.109),l(-1.33,-.077),l(-.686,.004),l(-1.034,1.784),l(-.416,-1.084),l(-.341,-.309),l(-.37,-.195),l(-.531,-.067),l(-.527,.045),l(-.901,.034),l(-.615,-.194),l(-.193,-.169),l(-.322,-.181),l(-.292,.27),l(-2.026,2.087),l(-1.047,.006),l(-.272,-.182),l(-.397,-2.144),l(-.278,-.973),l(-.212,-.563),l(-.769,-1.11),l(-.249,-.676),l(.04,-.354),l(.437,-1.555),l(-.017,-.282),l(-.761,-.744),l(-.25,-.521),l(-.193,-1.213),l(-.304,-.647),l(-.555,-.745),l(-.152,-.253),l(-.018,-.142),l(-.132,-.295),l(-.049,-.48),l(.12,-.227),l(.723,-.61),l(.285,-.439),l(-.015,-.522),l(-.604,-1.168),l(-.022,-.48),l(.159,-.34),l(.21,-.368),l(-.347,-.845),l(.102,-.452),l(.532,-.582),l(.221,-.34),l(.156,-.34),l(-.236,-.902),l(-.057,-.522),l(.143,-.848),l(.15,-.523),l(.437,-.736),l(-.08,-.24),l(-.922,-1.646),l(-1.109,-1.843), +N(473.575,260.04),l(-1.331,.011),l(-.192,.058),l(-.068,-.382),l(-.261,-.889),l(.071,-.495),l(-.075,-.296),l(-.095,-.324),l(.03,-.806),l(.057,-1.301),l(-.072,-.763),l(-.147,-.678),l(-.33,-.944),l(-.441,-.689),l(-.181,-.946),l(-.295,-1.199),l(-.159,-.183),l(.448,-.384),l(.396,-.412),l(1.68,-1.706),l(.114,-.227),l(-.09,-.367),l(.075,-.834),l(.229,-.481),l(.736,-.683),l(.205,-.341),l(.168,-.41),l(-.594,-.845),l(-.118,-.805),l(-.113,-.494),l(.128,-.283),l(.448,-.596),l(.201,-.411),l(-.132,-.805),l(-.086,-1.144),l(-.031,-.791),l(-.178,-.818),l(-.441,-.379),l(-.515,-.224),l(-1.167,-.347),l(-1.042,-.445),l(-.658,-.223),l(-1.438,-.006),l(-.137,-.14),l(-.025,-.495),l(-.011,-.212),l(-.087,-.438),l(-.152,-.465),l(.009,-.495),l(.187,-.128),l(2.165,-.578),l(.932,-.4),l(1.696,-.575),l(1.264,-.53),l(.195,.041),l(.382,.549),l(.343,.407),l(.27,.211),l(.702,-.132),l(.674,-.061),l(.261,.056),l(.22,.479),l(.1,.96),l(-.025,.693),l(-.116,.227),l(-.499,.61),l(-.036,.212),l(.234,.423),l(.484,.548),l(.763,1.112),l(.562,.463),l(.185,.111),l(.096,-.283),l(-.029,-.479),l(-.08,-.509),l(.076,-.622),l(.229,-.213),l(.322,-.017),l(.432,-.073),l(.214,-.213),l(.04,-.41),l(.155,-2.346),l(-.14,-.48),l(-.454,-.661),l(-1.189,-1.166),l(-.803,-.588),l(-.238,-.268),l(-.149,-.408),l(-.177,-1.017),l(-.252,-.917),l(.107,-.48),l(.224,-1.184),l(.898,.018),l(1.019,.149),l(.526,-.088),l(.643,-.356),l(.123,-.128),l(.229,.083),l(.323,.394),l(.512,.294),l(.963,-.02),l(.964,-.006),l(.42,.054),l(.396,-.144),l(.543,-.766),l(.21,-.326),l(.276,.083),l(.646,.42),l(.448,-.031),l(1.243,-.559),l(1.218,-.402),l(.515,-.342),l(1.157,-.836),l(.128,.167),l(.212,.479),l(-.185,.579),l(-.302,.453),l(-.198,.255),l(.181,.451),l(.129,.72),l(-.012,.466),l(.182,1.115),l(-.101,.58),l(-.258,.325),l(.374,.705),l(.154,.494),l(-.006,1.115),l(-.004,.819),l(.043,.184),l(.185,.127),l(.327,.084),l(.015,.269),l(-.165,.494),l(-.563,.58),l(.184,.381),l(-.08,.283),l(-.418,.565),l(-.802,.906),l(-.512,.622),l(-.72,.651),l(-1.36,.751),l(-1.48,.653),l(-.73,.228),l(-1.308,.582),l(-.852,.637),l(-1.286,1.443),l(-.886,.85),l(-1.193,.878),l(-1.181,.836),l(-.268,.128),l(-.035,.96),l(-.083,.495),l(.058,.127),l(.719,.535),l(.188,.381),l(-.166,.452),l(-.085,.184),l(.461,1.511),l(.071,.564),l(.06,.155),l(.246,.014),l(.171,-.128),l(.141,-.085),l(.043,.607),l(-.234,2.218),l(-.284,.82),l(.325,.196),l(.152,.057),l(-.025,.325),l(-.157,.311),l(-.516,.566),l(-.699,.538),l(-.664,.34),l(-1.266,.412),l(-.796,.312),l(-.688,.228),l(-.895,.524),l(-.652,.665),l(-.337,.51),l(.292,.338),l(.589,.338),l(.045,.325),l(-.149,1.022), +N(499.85,236.166),l(.544,-.071),l(.622,-.369),l(.18,.028),l(.346,.098),l(.269,-.085),l(.396,-.368),l(.911,-.143),l(.311,.281),l(.305,-.028),l(.101,-.185),l(-.171,-.366),l(.771,-.539),l(.423,-.198),l(.322,.226),l(.389,-.213),l(-.308,-.494),l(.207,-.282),l(.505,-.425),l(.229,.296),l(.229,.056),l(.558,-.594),l(-.158,-.197),l(-.253,-.409),l(.094,-.297),l(.243,.014),l(.27,-.071),l(.172,-.34),l(-.297,-.875),l(.06,-.339),l(.255,-.043),l(.117,.07),l(.253,.438),l(.28,.099),l(.2,-.41),l(.692,-.524),l(.235,-.367),l(.134,-.452),l(.168,-.692),l(-.133,-.354),l(.003,-.226),l(.537,-.468),l(.356,.324),l(.455,.648),l(.612,.281),l(.141,.198),l(.213,.847),l(.294,1.821),l(.093,.663),l(.231,.791),l(.391,.733),l(.163,.466),l(-.038,.367),l(-.069,.155),l(-.058,.099),l(-.537,.807),l(-.22,-.127),l(-.189,-.366),l(-.555,-.748),l(-.297,.143),l(-.05,.424),l(.193,.875),l(.396,.521),l(.079,.396),l(-.307,.636),l(-.746,1.005),l(-.045,.452),l(.041,.89),l(-.18,.946),l(-.709,2.12),l(-.825,2.572),l(-1.254,3.788),l(-1.324,4.48),l(-.518,1.568),l(-.188,.255),l(-.508,.637),l(-.2,.113),l(-1.369,.102),l(-.999,.327),l(-.474,.468),l(-.813,.086),l(-.363,-.465),l(-.196,-.142),l(-.546,-.182),l(-.37,.071),l(-.269,-.057),l(-.863,-.718),l(-.104,-.24),l(-.02,-.565),l(-.104,-.239),l(-.46,-.366),l(-.124,-.282),l(.001,-.721),l(.345,-1.088),l(-.094,-.325),l(-.287,-.479),l(-.62,-.931),l(-.189,-.494),l(.075,-.664),l(.391,-1.37),l(.228,-.213),l(.474,-.185),l(.768,-1.371),l(.686,-1.174),l(.104,-.325),l(.151,-1.103),l(-.11,-.353),l(-.278,-.226),l(-.354,-.366),l(.066,-.184),l(.252,-.509),l(-.521,-.861),l(-.117,-.677),l(-.069,-.494),l(-.231,-.721),l(.024,-.112),l(.517,-.693),l(.362,-.594),l(.163,-.438),l(.007,-1.073),l(.484,-.016), +N(468.138,234.908),l(.011,.212),l(.025,.495),l(.137,.14),l(1.438,.006),l(.658,.223),l(1.042,.445),l(1.167,.347),l(.515,.224),l(.441,.379),l(.178,.818),l(.031,.791),l(.086,1.144),l(.132,.805),l(-.201,.411),l(-.448,.596),l(-.128,.283),l(.113,.494),l(.118,.805),l(.594,.845),l(-.168,.41),l(-.205,.341),l(-.736,.683),l(-.229,.481),l(-.075,.834),l(.09,.367),l(-.114,.227),l(-1.68,1.706),l(-.396,.412),l(-.448,.384),l(-.342,-.225),l(-.547,-.124),l(-.442,-.025),l(-.529,.145),l(-.31,.016),l(-.99,-.403),l(-.597,-.139),l(-.72,-.023),l(-.067,-.042),l(-.186,-.098),l(-.306,-.451),l(-.479,-.35),l(-.549,-.167),l(-.938,-.136),l(-.352,-.153),l(-.524,-.873),l(-.163,-.564),l(.032,-.565),l(-.127,-.239),l(-.78,.019),l(-.201,-.098),l(-.109,-.211),l(.051,-.537),l(-.106,-.169),l(-.552,-.266),l(-.533,-.223),l(-.57,-.321),l(-.563,-.491),l(-.377,-.662),l(-.246,-.96),l(-.469,-.604),l(-.43,-.478),l(-.267,-.451),l(.103,-.227),l(.594,.209),l(.404,-.017),l(.521,-.286),l(.334,-.129),l(.421,.309),l(.803,.165),l(.354,-.045),l(.825,-.951),l(.562,-.738),l(.777,-.937),l(.306,-.341),l(.621,-.202),l(.999,-.062),l(.285,-.114),l(.168,-.199),l(.019,-.579),l(.312,-.539),l(.636,-.54),l(.794,-.259),l(.999,-.049),l(.505,.096), +N(444.673,255.519),l(-.006,3.434),l(.031,1.894),l(.025,2.246),l(-.057,.205),l(-.454,.318),l(-.545,.302),l(-.581,.498),l(-.427,.034),l(-.581,-.166),l(-.745,-.042),l(-.892,.048),l(-.517,-.039),l(-.296,-.212),l(-.055,-.528),l(-.042,-.345),l(-.193,-.222),l(-.637,-.348),l(-.329,-.127),l(-.335,.116),l(-.109,.217),l(-.317,.416),l(-.584,.27),l(-.152,.068),l(-.458,-.491),l(-1.041,-1.001),l(-.458,-.606),l(-.359,-1.03),l(-.345,-.72),l(-.136,-.493),l(.12,-.269),l(.053,-.34),l(-.458,-.719),l(-.231,-.861),l(.148,-.861),l(-.002,-.48),l(-.537,-1.326),l(-.496,-2.244),l(.772,-.02),l(.04,-.678),l(-.077,-.749),l(-.456,-.006),l(.016,-.06),l(-.099,-.522),l(-.26,-.508),l(-1.018,-1.283),l(-.343,-.55),l(-1.102,-2.158),l(-.841,-1.623),l(-.9,-1.509),l(-.988,-1.269),l(-.511,-1.044),l(-.122,-.396),l(-.045,-.551),l(.015,-.578),l(.248,-.197),l(.352,-.144),l(.758,.462),l(.778,-.513),l(.591,-.286),l(.499,-.088),l(.294,.083),l(.45,.478),l(.463,.309),l(.636,.151),l(2.201,-.013),l(1.296,.006),l(.631,.011),l(1.636,.019),l(2.59,-.016),l(.989,.023),l(.408,.096),l(.305,.366),l(.401,.322),l(.622,.151),l(.697,.024),l(2.024,-.026),l(.349,.21),l(.408,.083),l(1.164,-.063),l(.717,.08),l(1.044,-.203),l(1.96,-.379),l(.93,-.218),l(1.845,-.364),l(.165,.056),l(.086,.099),l(1.089,.093),l(.294,.055),l(.456,.393),l(-.811,.315),l(-.891,.02),l(-.284,.143),l(-.993,.938),l(-.209,.029),l(-.62,-.773),l(-1.048,.134),l(-2.962,.47),l(-1.183,.021),l(.005,1.215),l(-.007,1.286),l(-.025,.876),l(-.043,1.201),l(.002,3.561),l(-.586,.046),l(-1.564,.052),l(-.146,.028),l(-.106,2.657),l(-.009,1.201),l(.013,1.624),l(.007,.806), +N(248.453,316.576),l(-.306,.101),l(-.892,-.087),l(-.538,-.293),l(-.236,-.015),l(-.311,.163),l(-.418,.398),l(-.498,.192),l(-1.156,.091),l(-.349,.09),l(-.358,.207),l(-.267,.621),l(-.114,.341),l(.06,.532),l(-.163,.622),l(-.104,.148),l(-.453,.031),l(-.534,.104),l(-.956,-.413),l(.667,-.639),l(.326,-.444),l(.582,-.4),l(.025,-.147),l(-.372,-.177),l(-.273,-.117),l(-1.353,.534),l(-1.01,-.013),l(-.545,.163),l(-.202,-.339),l(.128,-.192),l(.959,-.268),l(.266,.028),l(.792,-.208),l(.441,-.118),l(-.605,-.162),l(-.582,.002),l(-.77,.001),l(-.014,-.413),l(.265,-.31),l(-.007,-.191),l(-.446,-.073),l(-.356,-.44),l(-.66,.384),l(-.669,-.175),l(.292,-.53),l(.041,-.177),l(-.378,.045),l(-.361,.147),l(-.416,-.396),l(-.215,-.117),l(.413,-.279),l(.114,-.177),l(-.091,-.278),l(-.053,-.073),l(-.351,.03),l(-.773,-.424),l(-.135,-.059),l(.844,-.192),l(.253,-.161),l(.1,-.294),l(.396,-.366),l(.049,-.234),l(-.641,.06),l(-.257,.104),l(-.312,-.073),l(-.256,-.672),l(.573,-.395),l(-.565,-.378),l(-.12,-.421),l(.757,-.452),l(-.14,-.421),l(-.686,.422),l(-.091,-1.523),l(.399,-.596),l(-.185,-.825),l(.013,-.218),l(.593,.014),l(.41,.245),l(.711,.071),l(.171,-.246),l(.002,-.159),l(-.896,-.447),l(-.867,.146),l(-.317,-.173),l(-.536,.059),l(-.017,-.231),l(.339,-.333),l(.025,-.246),l(-.067,-.087),l(.186,-.202),l(.536,.014),l(.229,-.377),l(.01,-.216),l(-.722,-.389),l(-.354,-.129),l(-.886,.045),l(-.332,-.101),l(-.024,-.49),l(-.939,.16),l(-.115,-.101),l(.122,-.145),l(1.032,-.521),l(.251,-.116),l(.4,-.404),l(.266,-.389),l(.833,-.06),l(.268,.201),l(.059,.346),l(-.648,.202),l(-.323,.274),l(.11,.505),l(.117,.058),l(.191,-.102),l(.268,-.39),l(.183,-.087),l(.242,.101),l(-.037,.317),l(.057,.504),l(.886,-.996),l(.161,-.678),l(.056,-.647),l(.237,-.375),l(.079,-.058),l(.631,-.217),l(-.201,-.071),l(-.438,-.143),l(-.056,-.158),l(.101,-.273),l(.246,-.072),l(.571,-.245),l(.599,-.431),l(.271,-.459),l(-.061,-.229),l(-.394,-.157),l(-.662,-.399),l(-.053,-.372),l(.139,-.243),l(.105,-.458),l(-.06,-.828),l(.366,-.33),l(.676,-.272),l(-.431,-.585),l(-.053,-.784),l(.133,-.158),l(.554,-.157),l(.054,-.314),l(-.116,-.285),l(-.317,-.085),l(-.272,-.198),l(.233,-.329),l(.087,-.313),l(-.401,-.185),l(-.274,-.014),l(-.161,.101),l(-.476,.414),l(-.548,.058),l(-.087,.001),l(-.289,-.199),l(-.16,-.484),l(-.399,-.726),l(-.133,-.697),l(.188,-.911),l(.137,-.413),l(.722,-.739),l(.535,-.767),l(-.006,-.326),l(-.544,-1.757),l(.001,-.608),l(.088,-.567),l(-.076,-.438),l(-.528,-.891),l(-.04,-.298),l(.236,-.198),l(.499,.098),l(.182,-.085),l(.2,-.142),l(.097,-.143),l(.41,-1.288),l(.252,-.481),l(.304,-.935),l(.18,-.65),l(.664,-.808),l(.363,-.722),l(.201,-.636),l(.252,-.946),l(.311,-.691),l(.187,-.128),l(.273,-.382),l(.013,-.296),l(-.312,-.847),l(.082,-.184),l(.455,-.452),l(.206,-.339),l(.028,-.24),l(-.093,-.226),l(-.166,-.805),l(-.292,-2.088),l(-.098,-.86),l(.031,-.565),l(.412,-.565),l(.37,-.537),l(.207,-.564),l(.007,-.734),l(-.339,-.521),l(-.098,-.409),l(.295,-.96),l(.218,-.941),l(.127,-.556),l(.461,-.594),l(.171,-.918),l(.243,-.975),l(.126,-.805),l(.082,-.565),l(-.063,-1.087),l(.422,-.664),l(.211,-.494),l(-.221,-.932),l(-.048,-.833),l(.148,-.24),l(-.022,-.917),l(.229,-.607),l(-.124,-.297),l(-.365,-.084),l(.06,-.324),l(-.046,-.396),l(.223,-.198),l(.402,-.198),l(.137,-.424),l(-.008,-.819),l(.093,-.593),l(.182,-.918),l(-.004,-2.344),l(-.172,-2.074),l(-.042,-1.539),l(-.194,-.974),l(-.15,-.387),l(.852,-.275),l(.259,-.298),l(.228,-.933),l(.15,-.199),l(.586,-.187),l(.152,.253),l(.555,.745),l(.304,.647),l(.193,1.213),l(.25,.521),l(.761,.744),l(.017,.282),l(-.437,1.555),l(-.04,.354),l(.249,.676),l(.769,1.11),l(.212,.563),l(.278,.973),l(.397,2.144),l(.272,.182),l(1.047,-.006),l(.107,.056),l(.212,.14),l(.161,.154),l(-.093,.636),l(-.541,1.457),l(-.36,.256),l(-1.346,.53),l(-.819,.372),l(-.204,.312),l(.25,.817),l(-.421,.722),l(-.007,.579),l(.113,.437),l(.34,.449),l(.03,.226),l(-.273,.369),l(-.161,.382),l(.114,.507),l(.53,.477),l(.011,.227),l(-.152,.311),l(-.333,.017),l(-.791,.089),l(-.329,.835),l(-.464,.835),l(-.608,.694),l(-.282,.439),l(-.823,1.839),l(.167,1.466),l(.054,.762),l(-.124,.185),l(-.492,.271),l(-.292,.34),l(-.388,1.201),l(-.156,.961),l(.285,.633),l(.408,1.154),l(.784,2.816),l(.055,.69),l(-.075,.41),l(-1.083,1.854),l(-.319,.595),l(.088,.409),l(.189,1.06),l(-.078,.325),l(-1.334,1.11),l(-.231,.312),l(-.142,1.075),l(.014,1.16),l(.249,1.103),l(.437,.932),l(-.202,.143),l(-.951,.529),l(-.126,.17),l(-.053,.312),l(-.511,2.427),l(-.316,.541),l(-.1,.37),l(.123,1.835),l(.231,.867),l(.012,.427),l(-.596,.317),l(-.172,.172),l(-.106,.271),l(.094,1.226),l(.125,.128),l(.555,.111),l(.088,.655),l(-.191,1.458),l(.252,.585),l(.26,.185),l(.789,.11),l(.302,.17),l(-.007,.186),l(-.245,.202),l(-.322,.13),l(-.726,.033),l(-.757,.146),l(.176,.171),l(.586,.298),l(.552,.385),l(.017,.216),l(-.767,.794),l(-.059,1.094),l(.158,1.035),l(-.216,.896),l(-.212,.434),l(-.226,.262),l(-.598,.161),l(-.28,.219),l(-.249,.781),l(.446,.648),l(-.069,.188),l(-.296,1.218),l(-.307,.263),l(-1.729,1.01),l(-.271,.292),l(-.037,.45),l(.28,1.309),l(.508,1.123),l(.218,.043),l(.961,-.283),l(.654,-.121),l(.187,.248),l(.231,2.285),l(.778,.568),l(.669,.041),l(1.41,-.052),l(2.827,.132),l(.841,.217),l(1.385,.36),l(.286,.039),M(236.642,296.773),l(-.394,-.113),l(-.43,-.028),l(-.21,-.171),l(-.133,-.229),l(.21,-.457),l(.15,-.657),l(-.087,-.514),l(.011,-.414),l(.364,-.728),l(.817,-.116),l(.36,.327),l(.044,.328),l(-.688,.443),l(-.146,.229),l(.493,.771),l(-.194,1.058),l(-.167,.271),M(238.177,317.937),l(-.445,-.177),l(.083,-.842),l(-.849,.075),l(-.073,-.368),l(.218,-.354),l(.823,.102),l(.508,-.207),l(.205,.103),l(.054,.812),l(-.267,.34),l(-.257,.518),M(247.801,322.062),l(-1.033,.102),l(-.467,-.118),l(-.55,-.237),l(-.42,.001),l(-.481,.104),l(-.935,.226),l(-.496,.03),l(.125,-.343),l(.202,-.312),l(-.104,-.312),l(.906,-.15),l(1.434,.058),l(.433,.323),l(.706,-.007),l(-.622,-.689),l(-.307,-.163),l(-.56,-.117),l(-.178,-.089),l(-.188,.03),l(-.338,-.341),l(-.229,-.4),l(1.611,-.581),l(-.044,-.296),l(-.165,-.147),l(-1.819,.285),l(-.292,-.222),l(.263,-.474),l(.146,-.163),l(1.074,-.52),l(.868,-.637),l(.414,.28),l(1.153,.062),l(-.008,1.144),l(-.098,3.675), +N(456.133,239.67),l(.187,.154),l(.163,.027),l(.154,.169),l(.264,.097),l(-.103,.227),l(.267,.451),l(.43,.478),l(.469,.604),l(.246,.96),l(.377,.662),l(.563,.491),l(.57,.321),l(.533,.223),l(.552,.266),l(.106,.169),l(-.051,.537),l(.109,.211),l(.201,.098),l(.78,-.019),l(.127,.239),l(-.032,.565),l(.163,.564),l(.524,.873),l(.352,.153),l(.938,.136),l(.549,.167),l(.479,.35),l(.306,.451),l(.186,.098),l(-.317,.411),l(-.388,.327),l(-.507,.243),l(-.747,.075),l(-.304,.115),l(-.7,.823),l(-.586,.583),l(-.362,.229),l(-.747,.357),l(-.388,.355),l(-.107,.636),l(-.222,.666),l(-.247,.241),l(-.634,.357),l(-.98,.33),l(-.249,.214),l(-.217,.708),l(-.345,.963),l(-.288,.354),l(-.237,.129),l(-.584,.116),l(-.43,-.026),l(-.473,.06),l(-.511,-.011),l(-.819,-.193),l(-.744,-.32),l(-.979,-.645),l(-.545,-.039),l(-.333,.186),l(-.084,.24),l(-.585,1.134),l(-.382,.469),l(-.651,.625),l(-.632,.428),l(-.8,.372),l(-.823,.033),l(-.854,.047),l(-.368,-.097),l(-.11,-.183),l(.003,-.48),l(.243,-.609),l(.166,-.538),l(-.21,-.762),l(-.547,-.943),l(-.716,-.787),l(-.528,-.067),l(-.007,-.806),l(-.013,-1.624),l(.009,-1.201),l(.106,-2.657),l(.146,-.028),l(1.564,-.052),l(.586,-.046),l(-.002,-3.561),l(.043,-1.201),l(.025,-.876),l(.007,-1.286),l(-.005,-1.215),l(1.183,-.021),l(2.962,-.47),l(1.048,-.134),l(.62,.773),l(.209,-.029),l(.993,-.938),l(.284,-.143),l(.891,-.02),l(.811,-.315), +N(279.288,257.295),l(.02,.239),l(-.544,1.57),l(-.375,.468),l(-1.007,.74),l(-.301,.27),l(-.352,.51),l(-.609,-.363),l(-.35,-.097),l(-.235,.029),l(-.387,.172),l(-.745,.131),l(-.71,.005),l(-.564,-.096),l(-.992,-.333),l(-.607,-.025),l(-1.187,.332),l(-.19,-.056),l(.064,-.212),l(.425,-.426),l(.486,-.398),l(.11,-.198),l(-.21,-.619),l(.048,-.227),l(.625,-.851),l(.617,-1.203),l(.018,-.268),l(-.939,-.503),l(-.65,-.18),l(-1.448,-.697),l(-1.632,-1.106),l(-.671,-.307),l(-1.173,-.204),l(-.498,-.237),l(-.835,-.588),l(-.576,-.562),l(-1.271,-1.376),l(-.782,-.913),l(-.225,-.337),l(-.19,-.056),l(.149,-.325),l(.395,-1.104),l(.385,-1.188),l(-.016,-.635),l(.133,-.509),l(.278,-.341),l(.698,-1.105),l(.332,-.383),l(.33,-.044),l(.784,-.202),l(1.104,-.162),l(1.076,-.204),l(.126,-.128),l(.843,.01),l(.928,-.02),l(.352,.054),l(1.952,.991),l(.089,.084),l(.253,.408),l(.084,.663),l(.521,.872),l(.104,.959),l(-.132,.862),l(-.086,.721),l(-.006,.72),l(.372,.04),l(.818,.15),l(.925,.221),l(.346,-.03),l(.709,-.413),l(.115,-.001),l(.724,.278),l(.843,.404),l(.121,.437),l(.487,2.524),l(.254,.563),l(.224,.055),l(1.29,-.445),l(.234,.112),l(.491,.336),l(.019,.141),l(-.321,.75),l(-.298,.835),l(-.222,.819),l(-.027,.777),l(.063,.423), +N(444.673,255.519),l(.528,.067),l(.716,.787),l(.547,.943),l(.21,.762),l(-.166,.538),l(-.243,.609),l(-.003,.48),l(.11,.183),l(.368,.097),l(.854,-.047),l(.823,-.033),l(.8,-.372),l(.632,-.428),l(.651,-.625),l(.382,-.469),l(.585,-1.134),l(.084,-.24),l(.333,-.186),l(.545,.039),l(.979,.645),l(.744,.32),l(.819,.193),l(.511,.011),l(.473,-.06),l(.43,.026),l(.584,-.116),l(.237,-.129),l(.288,-.354),l(.345,-.963),l(.217,-.708),l(.249,-.214),l(.98,-.33),l(.634,-.357),l(.247,-.241),l(.222,-.666),l(.107,-.636),l(.388,-.355),l(.747,-.357),l(.362,-.229),l(.586,-.583),l(.7,-.823),l(.304,-.115),l(.747,-.075),l(.507,-.243),l(.388,-.327),l(.317,-.411),l(.067,.042),l(.72,.023),l(.597,.139),l(.99,.403),l(.31,-.016),l(.529,-.145),l(.442,.025),l(.547,.124),l(.342,.225),l(.159,.183),l(.295,1.199),l(.181,.946),l(.441,.689),l(.33,.944),l(.147,.678),l(.072,.763),l(-.057,1.301),l(-.03,.806),l(.095,.324),l(-1.449,-.585),l(-.279,.199),l(-.657,.979),l(-.28,.567),l(-.005,.325),l(.39,.676),l(.307,.465),l(.458,.322),l(.671,.109),l(.595,-.004),l(.076,-.594),l(.064,-.198),l(.312,-.186),l(.131,-.015),l(.192,-.058),l(1.331,-.011),l(-.182,1.195),l(-.352,.849),l(-.182,.184),l(-.404,.1),l(-.093,.24),l(.199,.536),l(-.104,.467),l(-.248,.354),l(-.569,.453),l(-.923,.581),l(-.591,.75),l(-1.383,1.98),l(-.631,.834),l(-1.242,1.373),l(-1.193,1.062),l(-.829,.863),l(-1.434,1.034),l(-1.379,1.091),l(-.552,.382),l(-.989,.638),l(-.676,.298),l(-.782,.101),l(-.98,-.012),l(-.549,.071),l(-.132,.354),l(.013,.127),l(-.109,.085),l(-.449,-.098),l(-.553,-.126),l(-.303,.015),l(-.25,.198),l(-.272,.312),l(-.226,.113),l(-.36,-.056),l(-.768,-.408),l(-.759,-.168),l(-.542,-.013),l(-.31,.113),l(-.38,.27),l(-.482,-.099),l(-.645,-.21),l(-.295,.1),l(-.638,.043),l(-.589,.214),l(-.729,.538),l(-.72,.086),l(-.44,-.013),l(-.667,-.084),l(-.738,.072),l(-.575,.199),l(-.827,.82),l(-1.251,-.576),l(-.092,-.509),l(-.218,-.183),l(-.479,-.056),l(-.28,.085),l(-.257,-.479),l(-.343,-.056),l(-.149,.255),l(-.035,.197),l(-.312,-.112),l(-.119,-.226),l(.267,-.495),l(.103,-.424),l(-.857,-1.354),l(-.323,-.282),l(-.134,-.226),l(.173,-.17),l(.636,-.044),l(.172,-.424),l(.06,-.819),l(-.163,-.663),l(-.186,-.522),l(-.61,-1.143),l(-.75,-1.029),l(-.472,-.903),l(-.612,-1.383),l(-.646,-1.467),l(-.573,-.818),l(-.436,-.467),l(.152,-.068),l(.584,-.27),l(.317,-.416),l(.109,-.217),l(.335,-.116),l(.329,.127),l(.637,.348),l(.193,.222),l(.042,.345),l(.055,.528),l(.296,.212),l(.517,.039),l(.892,-.048),l(.745,.042),l(.581,.166),l(.427,-.034),l(.581,-.498),l(.545,-.302),l(.454,-.318),l(.057,-.205),l(-.025,-2.246),l(-.031,-1.894),l(.006,-3.434),M(462.462,268.501),l(.412,-.044),l(.194,-.553),l(.633,-.343),l(1.035,-.303),l(.263,-.199),l(.582,-1.007),l(.268,-.326),l(.143,-.241),l(-.104,-.226),l(-.967,-.744),l(-.33,-.337),l(-.422,-.266),l(-.308,.086),l(-.995,.359),l(-.65,.329),l(-.513,.567),l(-.275,.44),l(-.691,.611),l(.12,.409),l(.582,.858),l(.285,.366),l(.739,.561),M(432.955,250.661),l(.456,.006),l(.077,.749),l(-.04,.678),l(-.772,.02),l(-.078,-.354),l(-.028,-.396),l(.285,-.297),l(.101,-.406), +N(471.719,258.047),l(.075,.296),l(-.071,.495),l(.261,.889),l(.068,.382),l(-.131,.015),l(-.312,.186),l(-.064,.198),l(-.076,.594),l(-.595,.004),l(-.671,-.109),l(-.458,-.322),l(-.307,-.465),l(-.39,-.676),l(.005,-.325),l(.28,-.567),l(.657,-.979),l(.279,-.199),l(1.449,.585), +N(462.462,268.501),l(-.739,-.561),l(-.285,-.366),l(-.582,-.858),l(-.12,-.409),l(.691,-.611),l(.275,-.44),l(.513,-.567),l(.65,-.329),l(.995,-.359),l(.308,-.086),l(.422,.266),l(.33,.337),l(.967,.744),l(.104,.226),l(-.143,.241),l(-.268,.326),l(-.582,1.007),l(-.263,.199),l(-1.035,.303),l(-.633,.343),l(-.194,.553),l(-.412,.044), +N(790.15,283.022),l(.738,.197),l(.008,-.227),l(-.242,-.524),l(.052,-.284),l(.233,.014),l(.389,.17),l(.37,.751),l(.277,.964),l(.48,.17),l(1.753,.691),l(.506,.113),l(.37,-.072),l(.699,-.483),l(.885,-.343),l(.4,.027),l(.329,.17),l(.066,.454),l(-.022,.198),l(-.402,1.236),l(-.283,.072),l(-.761,.058),l(-.035,.683),l(-.124,.156),l(-.424,.029),l(-.746,.016),l(-.432,.2),l(-.271,.284),l(.041,.384),l(.254,.525),l(-.002,.213),l(-.151,.199),l(-.646,.515),l(-.898,1.129),l(-.847,1.058),l(-.756,.587),l(-.68,.316),l(-.337,-.171),l(-.47,-.313),l(-.237,-.328),l(.056,-.314),l(.288,-.386),l(.307,-.671),l(.398,-.5),l(-.031,-.343),l(-.271,-.128),l(-.761,-.582),l(-.421,-.185),l(-.593,-.184),l(-.98,-.452),l(-.306,-.256),l(-.11,-.17),l(.081,-.128),l(.419,-.157),l(1.389,-.685),l(.209,-.512),l(-.078,-.695),l(.087,-.312),l(.396,-.441),l(.032,-.383),l(-.482,-.837),l(.081,-.567),l(-.156,-.311),l(-.479,-.655),l(-.574,-.678),l(.102,-.164),l(-.145,-.304),l(-.291,-.351),l(-.336,-.188),l(-.29,-.163),l(.117,.233),l(.497,.515),l(.049,.141),l(-.169,0),l(-.211,-.281),l(-.525,-.631),l(-.622,-.771),l(-.518,-.561),l(.001,-.117),l(-.268,-.257),l(.04,-.141),l(.013,-.14),l(-.048,-.188),l(-.197,-.396),l(-.379,-.42),l(-.347,-.257),l(.163,-.046),l(.205,.093),l(.358,-.047),l(.131,-.093),l(.084,.28),l(-.149,.187),l(.186,.303),l(.177,.21),l(.167,.116),l(.228,.164),l(.041,-.141),l(.269,.023),l(.519,.257),l(.42,.117),l(.274,.07),l(.128,.257),l(-.011,.141),l(.185,.023),l(.146,-.188),l(.185,.023),l(-.022,.164),l(.227,.351),l(.249,.187),l(.233,.28),l(-.18,.023),l(-.076,.164),l(.093,.163),l(-.242,-.023),l(-.175,-.047),l(.143,.117),l(.251,.188),l(.23,.233),l(.352,.28),l(.063,.234),l(.019,.21),l(-.261,-.047),l(.096,.164),l(.239,.351),l(.256,.188),l(-.292,.023),l(-.226,0),l(-.205,-.047),l(-.006,.141),l(.306,.14),l(.324,.164),l(-.09,.211),l(.205,.046),l(.265,-.023),l(.226,0),l(.223,.141),l(-.114,.07),l(-.031,.141),l(.025,.141),l(.136,.06),M(782.939,297.694),l(-.088,.158),l(-.558,.13),l(-.309,.288),l(-.322,.101),l(-.246,.244),l(-.692,-.242),l(-.16,.086),l(.15,.216),l(.429,.415),l(-.141,.173),l(.02,.259),l(-.064,.431),l(-.218,-.071),l(-.976,-.099),l(.418,.229),l(.449,.244),l(-.278,.49),l(-.427,.896),l(-.212,.549),l(-.418,.318),l(-.673,.349),l(-.171,.246),l(-.259,.145),l(-.581,.233),l(-.593,.406),l(-.398,.015),l(-1.156,-.258),l(-.628,.112),l(-.585,-.442),l(-.812,-.158),l(-.373,-.066),l(-.162,-.308),l(-.467,-.098),l(-.24,.142),l(-.062,.168),l(-.78,.095),l(-.214,-.166),l(-.515,-.095),l(-.146,-.286),l(.432,-.089),l(-.223,-.216),l(.328,-.116),l(.322,-.001),l(-.452,-.482),l(.82,.266),l(-.464,-.576),l(.121,-.145),l(.946,.156),l(.082,-.13),l(-.141,-.173),l(-.201,-.216),l(-.06,-.288),l(.283,-.303),l(.569,-.246),l(.328,-.374),l(.561,-.375),l(.102,-.302),l(.998,-.575),l(1.106,-.275),l(.713,-.331),l(.544,-.36),l(.377,-.101),l(.685,-.575),l(.066,-.272),l(.48,-.302),l(.373,-.015),l(.787,-.331),l(.664,-.402),l(.126,-.215),l(-.008,-.172),l(.266,-.144),l(.448,-.302),l(-.109,-.501),l(.076,-.214),l(.166,-.44),l(.306,.048),l(.066,-.152),l(.58,-.259),l(.444,-.272),l(.137,-.285),l(.131,-1.187),l(.512,-.647),l(.372,.047),l(.365,.165),l(.032,.259),l(.337,.06),l(.187,.186),l(.231,.799),l(.312,.242),l(.973,-.645),l(.426,-.029),l(.367,.113),l(.222,.5),l(-.197,.399),l(.299,.429),l(.066,.271),l(-.611,.659),l(-.261,.401),l(-.476,.358),l(-.868,.746),l(-.578,.359),l(-.295,.13),l(-.236,.258),l(-.389,.159),l(-.271,.258),l(.416,.407),l(.428,.047),l(.421,.289),l(-.276,.113),l(-.484,.07),l(-.503,-.296),l(-.488,.131),l(-.352,.158), +N(247.899,318.387),l(.008,-1.144),l(.821,.289),l(.06,.206),l(-.354,.312),l(-.534,.337),M(248.453,316.576),l(-.286,-.039),l(-1.385,-.36),l(-.841,-.217),l(-2.827,-.132),l(-1.41,.052),l(-.669,-.041),l(-.778,-.568),l(-.231,-2.285),l(-.187,-.248),l(-.654,.121),l(-.961,.283),l(-.218,-.043),l(-.508,-1.123),l(-.28,-1.309),l(.037,-.45),l(.271,-.292),l(1.729,-1.01),l(.307,-.263),l(.296,-1.218),l(.069,-.188),l(-.446,-.648),l(.249,-.781),l(.28,-.219),l(.598,-.161),l(.226,-.262),l(.212,-.434),l(.216,-.896),l(-.158,-1.035),l(.059,-1.094),l(.767,-.794),l(-.017,-.216),l(-.552,-.385),l(-.586,-.298),l(-.176,-.171),l(.757,-.146),l(.726,-.033),l(.322,-.13),l(.245,-.202),l(.007,-.186),l(-.302,-.17),l(-.789,-.11),l(-.26,-.185),l(-.252,-.585),l(.191,-1.458),l(-.088,-.655),l(-.555,-.111),l(-.125,-.128),l(-.094,-1.226),l(.106,-.271),l(.172,-.172),l(.596,-.317),l(-.012,-.427),l(-.231,-.867),l(-.123,-1.835),l(.1,-.37),l(.316,-.541),l(.511,-2.427),l(.053,-.312),l(.126,-.17),l(.951,-.529),l(.202,-.143),l(-.437,-.932),l(-.249,-1.103),l(-.014,-1.16),l(.142,-1.075),l(.231,-.312),l(1.334,-1.11),l(.078,-.325),l(-.189,-1.06),l(-.088,-.409),l(.319,-.595),l(1.083,-1.854),l(.075,-.41),l(-.055,-.69),l(-.784,-2.816),l(-.408,-1.154),l(-.285,-.633),l(.156,-.961),l(.388,-1.201),l(.292,-.34),l(.492,-.271),l(.124,-.185),l(-.054,-.762),l(-.167,-1.466),l(.823,-1.839),l(.282,-.439),l(.608,-.694),l(.464,-.835),l(.329,-.835),l(.791,-.089),l(.333,-.017),l(.152,-.311),l(-.011,-.227),l(-.53,-.477),l(-.114,-.507),l(.161,-.382),l(.273,-.369),l(-.03,-.226),l(-.34,-.449),l(-.113,-.437),l(.007,-.579),l(.421,-.722),l(-.25,-.817),l(.204,-.312),l(.819,-.372),l(1.346,-.53),l(.36,-.256),l(.541,-1.457),l(.093,-.636),l(-.161,-.154),l(-.212,-.14),l(-.107,-.056),l(2.026,-2.087),l(.292,-.27),l(.322,.181),l(.193,.169),l(.615,.194),l(.901,-.034),l(.527,-.045),l(.531,.067),l(.37,.195),l(.341,.309),l(.416,1.084),l(1.034,-1.784),l(.686,-.004),l(1.33,.077),l(.592,.109),l(.19,.056),l(.225,.337),l(.782,.913),l(1.271,1.376),l(.576,.562),l(.835,.588),l(.498,.237),l(1.173,.204),l(.671,.307),l(1.632,1.106),l(1.448,.697),l(.65,.18),l(.939,.503),l(-.018,.268),l(-.617,1.203),l(-.625,.851),l(-.048,.227),l(.21,.619),l(-.11,.198),l(-.486,.398),l(-.425,.426),l(-.064,.212),l(.19,.056),l(1.187,-.332),l(.607,.025),l(.992,.333),l(.564,.096),l(.71,-.005),l(.745,-.131),l(.387,-.172),l(.235,-.029),l(.35,.097),l(.609,.363),l(.352,-.51),l(.301,-.27),l(1.007,-.74),l(.375,-.468),l(.544,-1.57),l(-.02,-.239),l(.957,-.161),l(.462,-.017),l(.206,.196),l(.517,1.154),l(-.094,1.638),l(-.161,.467),l(-.521,.313),l(-1.754,.744),l(-.348,.242),l(-1.633,1.448),l(-1.435,1.363),l(-1.805,1.816),l(-.833,.88),l(-.214,.27),l(-.443,.524),l(-.065,.452),l(-.595,2.359),l(-.103,.522),l(.049,.847),l(.168,.986),l(-.118,.325),l(-.48,.524),l(-.24,.495),l(-.011,.522),l(.194,.577),l(-.054,.338),l(-.162,.273),l(-.26,.325),l(.015,.226),l(.924,.831),l(.68,.281),l(.715,.281),l(.283,.169),l(.281,.325),l(-.025,.325),l(-.362,.523),l(-.043,.396),l(.105,.339),l(.174,.269),l(.466,.325),l(.522,.168),l(.109,.113),l(.226,.892),l(-.308,.481),l(-.75,.937),l(-.729,.766),l(-.313,.737),l(-.368,.284),l(-.832,.342),l(-1.04,.342),l(-1.92,.401),l(-1.795,.188),l(-1.361,.116),l(-.945,.044),l(-1.175,-.11),l(-.934,-.226),l(-.128,.199),l(.036,.808),l(.322,.312),l(.308,.184),l(-.09,.298),l(-.381,.624),l(-.345,.498),l(-.069,.385),l(.392,.682),l(.066,.285),l(-.208,.214),l(-.105,.057),l(-1.251,.473),l(-1.137,.116),l(-.814,-.069),l(-.967,-.34),l(-1.47,-.396),l(-.246,.057),l(-.23,.271),l(.041,.598),l(.429,.684),l(.037,.398),l(-.242,.643),l(.092,.385),l(.773,.54),l(.796,.084),l(.369,-.2),l(-.387,-.398),l(.872,-.188),l(.383,-.043),l(.234,1.041),l(.052,.3),l(-.144,.157),l(-.299,.101),l(-.448,.072),l(-.261,-.157),l(-.104,-.299),l(-.115,-.071),l(-1.046,.073),l(-.67,.201),l(-.212,.101),l(.151,.214),l(.591,.07),l(.47,.113),l(.452,.113),l(.06,.028),l(-.864,.388),l(-.776,.287),l(-.577,.602),l(.003,.414),l(.161,.787),l(-.081,.258),l(-.815,.817),l(.022,.215),l(.423,.371),l(-.491,.116),l(-1.194,.088),l(-.48,.087),l(-.632,.246),l(-.619,.389),l(-.56,.548),l(-.549,.821),l(-.052,.389),l(.061,.375),l(.312,.591),l(.48,.446),l(.98,.633),l(.657,.244),l(.97,.143),l(.362,.086),l(.14,.274),l(-.151,.796),l(-.128,.348),l(-.342,.464),l(-.189,.145),l(-1.08,.524),l(-1.541,.814),l(-.712,.698),l(-.179,.276),l(-.093,.45),l(.111,.523),l(-.169,.451),l(-.239,.32),l(-.97,.454),l(-.969,.25),l(-.421,.221),l(-.323,.396),l(-.226,.791),l(-.054,.514),l(.2,.777),l(.547,.896),l(.699,.779),l(.235,.339),l(-.101,.032),M(247.899,318.387),l(.18,.182),l(.148,.073),l(.607,-.075),l(.344,.133),l(.648,.725),l(.908,.665),l(.993,.756),l(.525,.222),l(.73,.37),l(.246,.074),l(.42,-.001),l(.483,.163),l(1.283,.027),l(.142,-.016),l(-.006,.224),l(-.19,.209),l(-.492,.06),l(-1.198,.092),l(-.777,.196),l(-.364,0),l(-1.179,-.355),l(-.753,-.088),l(-1.15,-.027),l(-.814,-.014),l(-.831,.081),l(.098,-3.675), +N(346.758,54.457),l(.127,-.162),l(.42,-.179),l(.894,.015),l(.674,-.098),l(-.354,-.227),l(-.405,-.34),l(.317,-.342),l(.277,0),l(.956,.42),l(.67,.048),l(.3,-.163),l(-.191,-.26),l(-.625,-.373),l(.366,-.245),l(1.037,.226),l(.957,.08),l(.746,.275),l(.446,.551),l(-.119,.405),l(-.441,.292),l(.922,.806),l(.553,-.356),l(.352,-.13),l(.63,-.114),l(.49,-.179),l(.061,-.21),l(-.169,-.778),l(.542,-.245),l(.501,.454),l(.426,.307),l(.489,.209),l(.215,.016),l(.185,-.13),l(-.264,-.454),l(.243,-.163),l(.27,-.033),l(.817,-.164),l(.683,.438),l(.536,.242),l(.542,.063),l(.05,-.178),l(-.358,-.535),l(1.006,.145),l(1.439,.079),l(.787,-.115),l(.427,-.229),l(-.021,-.716),l(1.167,.08),l(.635,.471),l(1.118,.323),l(.683,.015),l(.273,.243),l(-.252,.552),l(.786,.29),l(1.674,.159),l(.127,.145),l(.143,.548),l(-.07,.387),l(-.152,.256),l(-.152,.256),l(-.443,.129),l(-.815,.018),l(-.195,.096),l(-.04,.431),l(-.515,.463),l(-.497,.16),l(-.568,-.031),l(-.422,-.159),l(-.817,.495),l(-.539,.144),l(-1.46,.463),l(-.853,.113),l(-.726,.001),l(-.771,.097),l(-.784,.587),l(-.473,.127),l(-1.078,.097),l(-.709,-.03),l(-1.316,-.171),l(-.608,-.142),l(-1.283,-.489),l(-1.058,-.093),l(-.443,.064),l(-1.041,-.014),l(-1.834,-.124),l(-.297,-.206),l(.434,-.191),l(1.127,-.352),l(.701,-.59),l(-.818,-.015),l(-.51,-.126),l(-.428,-.398),l(-.253,-.095),l(-.358,.081),l(-1.564,.115),l(-.557,.033),l(-.37,-.223),l(.141,-.192),l(.388,-.129),l(.669,-.097),l(.794,-.017),l(.729,-.114),l(1.049,-.098),l(.376,-.194),l(.178,-.322),l(-.144,-.258),l(-.358,-.177),l(-.426,-.015),l(-.478,-.145),l(-1.005,-.047),l(-.821,.099),l(-.424,.162),l(-.676,.082),l(-1.041,-.272),l(-.16,-.21), +N(462.829,67.958),l(.145,.053),l(.16,.131),l(-.043,.174),l(-.175,.044),l(-.189,0),l(-.116,0),l(-.088,.043),l(-.058,.131),l(-.175,.277),l(-.219,.204),l(-.319,.131),l(-.204,.131),l(-.088,.16),l(.029,.16),l(.131,.437),l(.073,.189),l(.029,.16),l(-.175,.131),l(0,.175),l(.175,.233),l(.203,.087),l(.088,.073),l(0,.073),l(.015,.087),l(.043,.146),l(.175,.043),l(.059,.059),l(-.175,.073),l(-.262,.043),l(-.16,.058),l(-.059,.102),l(-.087,.116),l(-.131,0),L(461.402,72),l(-.015,.087),l(-.116,.058),l(.081,.106),l(-.125,.025),l(-.087,-.015),l(-.306,-.043),l(-.16,-.058),l(-.175,-.073),l(-.204,-.044),l(-.131,.102),l(-.204,-.029),l(-.131,.044),l(-.16,.087),l(-.146,.014),l(-.146,-.087),l(-.116,-.029),l(-.175,0),l(-.204,-.117),l(-.116,-.174),l(-.203,-.117),l(-.146,-.043),l(-.072,-.117),l(-.189,0),l(-.247,-.043),l(-.204,-.117),l(-.029,0),l(-.276,-.014),l(-.102,-.102),l(-.248,-.043),l(-.116,-.102),l(-.189,-.087),l(0,.073),l(-.116,.087),l(-.131,-.058),l(-.015,-.073),l(-.087,-.029),l(-.103,0),l(-.276,.117),l(-.102,.029),l(-.131,.015),l(-.219,.015),l(-.146,.043),l(-.262,.029),l(-.276,.087),l(-.116,.102),l(-.087,0),l(.156,-.19),l(-.003,-.351),l(.183,-.238),l(-.368,-.21),l(-.605,.437),l(-.334,-.251),l(-.527,-.038),l(.043,-.942),l(-.396,.188),l(-.336,-.415),l(.158,-.202),l(-.209,-.254),l(.265,-.074),l(-.092,-.252),l(.344,-.042),l(1.026,-.084),l(-.006,-.132),l(.561,-.108),l(.133,-.188),l(.436,.101),l(.074,-.113),l(.317,.05),l(.083,-.215),l(1.104,.193),l(.446,-.294),l(.091,.165),l(.514,-.089),l(1.383,.029),l(1.152,.167),l(.305,.12),l(.592,-.045),l(.971,.09),l(.426,-.108),l(.271,-.24),l(-.006,-.009), +N(461.353,72.251),l(.37,-.004),l(-.015,.116),l(0,.117),l(.232,.073),l(.204,.087),l(.087,.073),l(.204,.058),l(-.015,.087),l(-.029,.116),l(-.015,.087),l(-.102,.073),l(-.087,.015),l(-.103,.029),l(.131,.087),l(-.072,.131),l(.029,.117),l(-.073,.087),l(-.102,.073),l(-.044,.102),l(.204,-.059),l(.146,-.015),l(.131,.073),l(.087,.014),l(.073,.044),l(-.059,.087),l(-.043,.073),l(.116,.102),l(.131,.058),l(.029,.16),l(.146,.102),l(.16,.043),l(-.059,.087),l(.131,.117),l(-.015,.189),l(.088,.233),l(-.044,.087),l(-.015,.117),l(-.061,.042),l(-.241,.044),l(-.24,.051),l(-.12,.12),l(-.223,.034),l(-.137,.154),l(-.137,.085),l(-.069,.103),l(-.068,.206),l(-.188,.035),l(-.239,-.035),l(-.24,-.034),l(-.325,-.034),l(-.359,0),l(-.172,.068),l(-.103,.137),l(-.223,.085),l(-.154,0),l(-.103,-.017),l(-.086,.052),l(-.377,-.035),l(-.273,-.068),l(-.154,-.171),l(-.138,-.154),l(-.325,-.137),l(-.497,-.223),l(-.342,-.24),l(-.377,-.034),l(-.583,-.035),l(-.325,-.12),l(-.291,-.188),l(-.086,-.257),l(-.188,.017),l(-.171,.068),l(-.36,.171),l(-.394,.017),l(-.24,0),l(-.273,.085),l(-.24,-.085),l(-.309,-.103),l(-.6,-.017),l(-.291,.069),l(-.359,-.069),l(-.291,-.051),l(-.154,.034),l(-.274,.069),l(-.103,-.052),l(-.12,-.137),l(-.154,0),l(-.257,.068),l(-.188,0),l(-.754,-.017),l(-.445,-.085),l(-.754,.171),l(-.599,.154),l(-.429,.103),l(-.257,.137),l(-.052,.188),l(-.526,.026),l(-.065,-.059),l(.073,-.837),l(.035,-.302),l(.127,-.167),l(.672,-.379),l(.034,-.717),l(.267,-.162),l(.267,-.273),l(.217,-.203),l(.296,-.026),l(1.056,-.199),l(.166,-.046),l(.162,-.066),l(.29,0),l(.049,.237),l(.657,.388),l(.422,.162),l(.23,.473),l(.091,.15),l(.441,.196),l(.785,.059),l(.868,-.244),l(.24,-.122),l(.178,-.288),l(-.052,-.394),l(-.193,-.869),l(.198,-.243),l(.045,-.055),l(.087,0),l(.116,-.102),l(.276,-.087),l(.262,-.029),l(.146,-.043),l(.219,-.015),l(.131,-.015),l(.102,-.029),l(.276,-.117),l(.103,0),l(.087,.029),l(.015,.073),l(.131,.058),l(.116,-.087),l(0,-.073),l(.189,.087),l(.116,.102),l(.248,.043),l(.102,.102),l(.276,.014),l(.029,0),l(.204,.117),l(.247,.043),l(.189,0),l(.072,.117),l(.146,.043),l(.203,.117),l(.116,.174),l(.204,.117),l(.175,0),l(.116,.029),l(.146,.087),l(.146,-.014),l(.16,-.087),l(.131,-.044),l(.204,.029),l(.131,-.102),l(.204,.044),l(.175,.073),l(.16,.058),l(.306,.043),l(.087,.015),l(.125,-.025), +N(451.02,79.165),l(-.029,-.038),l(-.034,-.137),l(-.018,-.171),l(.068,-.206),l(.068,-.154),l(.224,-.12),l(-.052,-.12),l(-.018,-.137),l(-.171,-.069),l(-.188,-.034),l(-.103,-.103),l(-.086,-.137),l(-.223,.017),l(-.257,0),l(-.445,0),l(-.223,.051),l(-.086,-.103),l(-.514,-.068),l(-.257,-.069),l(-.223,-.12),l(-.24,0),l(-.086,-.052),l(-.051,-.154),l(-.12,.034),l(-.353,.096),l(-.043,-.077),l(.128,-.012),l(.034,-.183),l(-.439,-.646),l(-.008,-.14),l(-.042,-.727),l(-.112,-.102),l(.526,-.026),l(.052,-.188),l(.257,-.137),l(.429,-.103),l(.599,-.154),l(.754,-.171),l(.445,.085),l(.754,.017),l(.188,0),l(.257,-.068),l(.154,0),l(.12,.137),l(.103,.052),l(.274,-.069),l(.154,-.034),l(.291,.051),l(.359,.069),l(.291,-.069),l(.6,.017),l(.309,.103),l(.24,.085),l(.273,-.085),l(.24,0),l(.394,-.017),l(.36,-.171),l(.171,-.068),l(.188,-.017),l(.086,.257),l(.291,.188),l(.325,.12),l(.583,.035),l(.377,.034),l(.342,.24),l(.497,.223),l(.325,.137),l(.138,.154),l(.154,.171),l(.273,.068),l(.377,.035),l(-.017,.171),l(-.086,.154),l(-.034,.12),l(-.12,.137),l(-.086,.137),l(.343,.034),l(.274,.052),l(.085,.051),l(-.119,.051),l(-.086,0),l(-.103,.154),l(-.018,.154),l(-.171,.017),l(-.12,-.086),l(-.12,.051),l(-.239,-.034),l(-.154,.034),l(-.086,.154),l(-.103,.154),l(-.257,.068),l(-.429,0),l(-.137,.137),l(-.12,.12),l(-.034,.154),l(-.086,.171),l(.103,.171),l(-.068,.137),l(-.239,.154),l(0,.137),l(-.068,.085),l(-.069,.137),l(.172,.034),l(.205,0),l(.138,.206),l(-.086,.188),l(-.274,.017),l(-.223,-.068),l(0,-.154),l(-.034,-.085),l(-.086,-.069),l(-.171,.051),l(-.12,.086),l(-.291,-.034),l(-.068,.137),l(-.24,.12),l(-.154,0),l(-.188,-.034),l(-.273,.103),l(.086,.171),l(-.069,.12),l(-.171,.034),l(-.137,-.034),l(-.206,.051),l(-.377,.154),l(-.291,0),l(-.068,-.103),l(-.12,-.051),l(-.239,.051),l(-.377,.017),l(-.24,.034),l(-.291,-.034),l(-.154,.034),l(-.093,-.035),l(-.09,-.171),l(-.016,-.029),l(-.099,-.186),l(-.284,-.487),l(-.679,-.243),l(-.04,-.014),l(-.641,.021), +N(452.867,80.273),l(.093,.035),l(.154,-.034),l(.291,.034),l(.24,-.034),l(.377,-.017),l(.239,-.051),l(.12,.051),l(.068,.103),l(.291,0),l(.377,-.154),l(.206,-.051),l(.137,.034),l(.171,-.034),l(.069,-.12),l(-.086,-.171),l(.273,-.103),l(.188,.034),l(.154,0),l(.24,-.12),l(.068,-.137),l(.291,.034),l(.12,-.086),l(.171,-.051),l(.086,.069),l(.034,.085),l(0,.154),l(.223,.068),l(.274,-.017),l(.086,-.188),l(-.138,-.206),l(-.205,0),l(-.172,-.034),l(.069,-.137),l(.068,-.085),l(0,-.137),l(.239,-.154),l(.068,-.137),l(-.103,-.171),l(.086,-.171),l(.034,-.154),l(.12,-.12),l(.137,-.137),l(.429,0),l(.257,-.068),l(.103,-.154),l(.086,-.154),l(.154,-.034),l(.239,.034),l(.12,-.051),l(.12,.086),l(.171,-.017),l(.018,-.154),l(.103,-.154),l(.086,0),l(.119,-.051),l(-.085,-.051),l(-.274,-.052),l(-.343,-.034),l(.086,-.137),l(.12,-.137),l(.034,-.12),l(.086,-.154),l(.017,-.171),l(.086,-.052),l(.103,.017),l(.154,0),l(.223,-.085),l(.103,-.137),l(.172,-.068),l(.359,0),l(.325,.034),l(.24,.034),l(.239,.035),l(.188,-.035),l(.068,-.206),l(.069,-.103),l(.137,-.085),l(.137,-.154),l(.223,-.034),l(.12,-.12),l(.24,-.051),l(.241,-.044),l(.165,.147),l(.229,.066),l(.197,-.131),l(.181,.016),l(.312,.033),l(.132,.148),l(.082,.148),l(.197,-.033),l(.214,-.065),l(.361,-.049),l(.312,.049),l(.296,.065),l(.147,.017),l(0,.115),l(-.164,.099),l(-.017,.099),l(.065,.148),l(.164,.148),l(.197,0),l(.214,-.197),l(.279,-.016),l(.165,0),l(.147,-.099),l(.23,-.083),l(.131,.049),l(.099,.049),l(.247,-.049),l(.542,.115),l(.132,.131),l(.279,.099),l(.099,.099),l(.147,.099),l(.165,.033),l(.147,-.033),l(.049,.115),l(-.065,.115),l(0,.083),l(-.033,.164),l(-.131,.165),l(.197,.247),l(.147,.099),l(.05,.164),l(-.066,.131),l(-.114,0),l(0,.083),l(-.115,.082),l(-.099,.049),l(-.033,.165),l(-.049,.147),l(.345,.049),l(.132,.181),l(.082,.115),l(.181,-.049),l(.132,.033),l(-.099,.115),l(-.066,.131),l(.017,.099),l(.214,.017),l(.164,.263),l(.115,.23),l(.443,.213),l(.23,.066),l(.279,.082),l(.164,.099),l(.066,.148),l(-.099,.197),l(-.066,.181),l(.182,.066),l(.361,-.066),l(.378,.066),l(.361,.099),l(.263,.066),l(-.032,.065),l(-.066,.049),l(-.082,.017),l(.099,.181),l(.296,.148),l(.279,.066),l(.033,.131),l(-.065,.164),l(-.296,0),l(-.148,.083),l(-.049,.065),l(-.444,.247),l(-.525,.099),l(-.51,-.016),l(-.197,-.132),l(-.328,-.049),l(-.362,.017),l(-.131,.165),l(-.099,.131),l(.017,.164),l(.279,.263),l(.296,.164),l(0,.165),l(-.132,.066),l(.099,.148),l(.147,.131),l(-.082,.099),l(.033,.164),l(.033,.23),l(-.033,.099),l(.164,.082),l(.082,.115),l(.165,.066),l(.002,.142),l(-.519,-.005),l(-.522,.056),l(-.112,.131),l(-.205,-.056),l(-.187,-.037),l(-.336,.075),l(-.057,.13),l(-.111,.112),l(-.317,.187),l(-.188,.261),l(-.261,.224),l(-.057,.206),l(.243,.205),l(.056,.149),l(-.131,.206),l(-.261,-.019),l(-.149,-.056),l(-.149,-.206),l(-.112,-.056),l(-.187,-.075),l(-.224,-.037),l(-.225,.037),l(-.242,.075),l(-.299,.019),l(-.149,-.131),l(-.224,.075),l(-.188,.093),l(-.316,.056),l(-.188,-.056),l(-.037,-.205),l(-.112,-.131),l(-.168,-.131),l(-.13,.038),l(-.131,.075),l(-.168,0),l(-.299,.149),l(-.131,.149),l(-.168,0),l(-.094,-.187),l(-.13,-.075),l(-.206,0),l(-.224,.112),l(-.131,-.187),l(-.224,-.093),l(-.131,.112),l(-.354,.056),l(-.262,-.112),l(-.112,0),l(-.019,.205),l(-.168,.093),l(-.093,-.056),l(.056,-.224),l(-.243,-.038),l(-.187,-.056),l(-.541,.112),l(0,-.149),l(-.187,0),l(.019,-.224),l(-.28,-.037),l(-.242,.075),l(-.523,-.112),l(-.578,-.056),l(-.075,-.056),l(-.522,0),l(-.205,-.168),l(-.262,.019),l(-.522,-.093),l(-.467,.075),l(-.485,0),l(-.354,-.056),l(-.355,.056),l(-.354,.056),l(-.485,-.038),l(-.485,.019),l(-.205,.187),l(-.037,.168),l(-.374,.168),l(-.373,.206),l(-.112,-.112),l(-.261,0),l(-.374,-.019),l(-.037,.131),l(0,.045),l(-.126,-.137),l(.315,-.752),l(-.013,-.25),l(-.218,-.146),l(-.149,-.176),l(-.421,-.146),l(-.289,-.012),l(.128,-.292),l(.291,-.328),l(.571,-.244),l(.44,-.03),l(.263,-.208),l(.023,-.236),l(-.172,-.502),l(-.615,-1.5),l(-.16,-.302), +N(400.125,81.146),l(.633,.305),l(.208,.207),l(.208,.37),l(-.038,.193),l(-.545,.563),l(.714,.176),l(.396,-.311),l(.527,-.119),l(.602,.028),l(.807,.176),l(.467,.354),l(.235,.752),l(-.077,.221),l(-.322,.414),l(-1.068,.473),l(-.767,.561),l(-.96,.237),l(1.223,.167),l(.501,.043),l(.354,-.104),l(.39,.117),l(-.066,.516),l(-.997,.308),l(.005,.199),l(-.479,-.084),l(-1.068,.443),l(-.879,-.142),l(-.293,-.048),l(-1.119,.211),l(-.587,-.211),l(-.598,.112),l(-1.584,.141),l(.137,.295),l(-.907,-.168),l(-.264,.168),l(-.911,-.337),l(-.334,.143),l(-.913,.089),l(-.093,.569),l(-.337,.316),l(-.37,.042),l(-.272,-.252),l(-.53,-.172),l(-.135,.151),l(-.527,-.077),l(-.948,.324),l(-.701,.552),l(-.326,-.231),l(-.775,-.147),l(1.2,-.472),l(.492,-.476),l(.447,-.097),l(.468,-.388),l(.118,-.485),l(.242,.063),l(.367,-.211),l(-.008,-.274),l(1.013,-.105),l(.76,.119),l(.927,.007),l(.073,-.338),l(.308,-.142),l(.321,-.556),l(-.939,.394),l(-.725,.016),l(-1.467,-.482),l(-1.866,-.055),l(-.399,-.191),l(-.156,-.162),l(.417,-.325),l(.983,-.194),l(.721,-.237),l(.38,-.384),l(.066,-.827),l(-.119,-.192),l(-.713,.046),l(-.34,-.044),l(.288,-.355),l(.387,-.223),l(.802,-.253),l(1.394,-.062),l(.922,-.076),l(-.316,-.548),l(.172,-.683),l(.253,-.461),l(-.045,-.312),l(-.834,.061),l(-.484,-.296),l(-.2,-.312),l(.309,-.507),l(.617,-.433),l(-.347,-.104),l(-.596,-.088),l(-.735,.3),l(-.476,.061),l(-.753,-.222),l(-.088,.194),l(-.222,.194),l(-.672,-.103),l(-.464,-.133),l(.1,-.343),l(.348,-.36),l(.604,-.706),l(-.293,-.134),l(-.305,-.39),l(.028,-.24),l(.304,-.106),l(.3,-.196),l(-.194,-.496),l(-.306,.076),l(-.636,.453),l(-.442,.031),l(-.526,.287),l(-.14,-.421),l(.302,-.527),l(.438,-.559),l(.065,-.257),l(-.417,-.195),l(-.196,-.045),l(-.218,.302),l(-.394,.257),l(-.493,-.165),l(.299,-.575),l(.54,-.455),l(.09,-.136),l(-.225,-.575),l(.366,-.092),l(.225,-.197),l(-.672,-.515),l(.432,-.351),l(.752,.151),l(.387,-.092),l(-.645,-.759),l(.975,-.169),l(-.457,-.502),l(.416,-.382),l(.924,.365),l(.824,-.093),l(.686,-.139),l(.867,-.047),l(.612,.014),l(.303,.259),l(-.307,.29),l(-1.726,.704),l(-.46,.274),l(-.218,.441),l(.222,.182),l(.784,.029),l(.877,-.078),l(.685,-.001),l(.53,.075),l(1.563,-.064),l(.458,.378),l(-.363,.425),l(-.212,.323),l(.098,.112),l(-.565,.66),l(-.226,.111),l(-.339,.437),l(-.696,.261),l(-.382,.038),l(.451,.186),l(.508,.167),l(-.116,.015),l(-.272,.19),l(-.61,.052),l(-.275,.196),l(-1.337,-.025),l(.404,.223),l(.302,0),l(.492,.093),l(.432,-.006),l(.519,-.223),l(.413,-.025),l(.449,.161),l(.656,.164),l(.673,.566),l(.496,.228),l(.118,.165),l(-.067,.238),l(.312,.78),l(.371,.536),l(.438,.189),l(.714,.107),l(.59,.549),l(.688,.593),l(.135,.52),l(-.188,.49),l(.257,.124),M(387.915,77.13),l(-.128,-.325),l(.149,-.335),l(.38,-.089),l(.079,.501),l(-.307,.251),l(-.173,-.003),M(386.786,80.184),l(-.178,-.272),l(-.967,.072),l(.123,-.256),l(-.364,-.15),l(-.26,-.257),l(-.335,-.107),l(-.253,.364),l(-.751,.257),l(-.778,-.192),l(-.401,-.278),l(-.101,-.278),l(.86,-.278),l(-.483,-.257),l(.817,-.107),l(.385,-.484),l(-.029,-.235),l(.449,-.09),l(.508,-.15),l(.781,-.077),l(.424,.044),l(.389,.104),l(.362,-.046),l(.218,.149),l(.519,.791),l(.047,.179),l(-.081,.298),l(.308,.446),l(-.155,.328),l(-.402,.328),l(-.354,.12),l(-.299,.038), +N(578.943,106.217),l(-.41,-.375),l(-.466,-.098),l(-.663,0),l(-.196,-.27),l(-.27,-.147),l(-.147,-.344),l(-.564,.049),l(-.981,-.246),l(-.662,.074),l(-1.35,-.024),l(-.662,-.098),l(-.712,-.221),l(-.785,.147),l(-.761,0),l(-.858,.024),l(-.441,.27),l(-.54,-.098),l(-.908,-.196),l(-.735,-.246),l(-.761,-.27),l(-.589,-.074),l(-.688,.123),l(-.466,.368),l(-.245,.736),l(.024,.442),l(-.344,-.123),l(-.81,-.123),l(-.688,-.196),l(-.883,-.245),l(-.883,-.147),l(-.663,.098),l(-.736,.123),l(-.318,.368),l(-.393,.442),l(.044,.273),l(-.322,.031),l(-.377,.377),l(-.283,-.126),l(-.22,.063),l(-.346,.283),l(-.534,.471),l(-.755,.189),l(-.943,.377),l(-.282,.188),l(-.221,.472),l(-.439,.188),l(-.504,.44),l(.157,.409),l(-.125,.188),l(-.66,0),l(-.44,-.346),l(.062,-.283),l(-.062,-.283),l(-.44,-.314),l(-.346,0),l(-1.006,.094),l(-.691,.032),l(-.503,-.063),l(-.346,-1.069),l(-.221,-.817),l(-1.006,0),l(-.031,-.754),l(.188,-.409),l(.031,-1.038),l(-.66,.314),l(-.66,-1.006),l(-.597,-.22),l(-.724,-.723),l(-1.1,.409),l(-2.767,-.188),l(-2.578,.346),l(-2.012,-1.666),l(-5.722,-2.986),l(-5.658,1.289),l(-.056,8.174),l(-.158,-.014),l(-.341,.106),l(-.489,.043),l(-.447,-.255),l(-.638,-.703),l(-.256,-.511),l(-.617,-.383),l(-.681,-.383),l(-.512,-.234),l(-.979,.085),l(-1.277,.298),l(-.937,.532),l(-.529,.453),l(.092,-.399),l(-.06,-.18),l(-.12,-.12),l(.14,-.26),l(.2,-.2),l(.14,-.32),l(.04,-.3),l(.18,-.2),l(-.159,-.24),l(-.4,-.16),l(-.459,.06),l(-.18,-.16),l(-.3,.06),l(-.2,.04),l(-.199,-.18),l(-.221,-.32),l(-.319,-.28),l(-.34,0),l(-.359,.02),l(0,-.2),l(.08,-.28),l(-.2,-.379),l(-.239,-.12),l(-.2,-.24),l(-.399,-.799),l(-.08,-.28),l(-.56,-.12),l(-.699,-.08),l(-.14,-.16),l(.02,-.439),l(.16,-.12),l(.3,-.06),l(.399,.02),l(.34,.02),l(.479,.14),l(.539,.18),l(.18,-.08),l(.36,-.08),l(-.2,-.16),l(-.26,-.12),l(-.399,-.2),l(-.2,-.24),l(.26,-.36),l(.28,-.04),l(.08,-.26),l(.18,-.299),l(.12,-.14),l(.26,.04),l(.319,-.08),l(.16,-.1),l(.339,.12),l(.24,0),l(1.119,-.04),l(.999,.14),l(.499,.02),l(-.159,-.08),l(-.34,-.2),l(-.479,-.12),l(-.021,-.3),l(.2,-.2),l(.279,-.22),l(.221,-.28),l(.119,-.52),l(.12,-.28),l(-.16,-.24),l(-.14,-.16),l(.1,-.2),l(.26,-.2),l(-.119,-.12),l(-.101,-.3),l(-.359,-.12),l(-.359,-.04),l(-.68,-.1),l(-.2,.16),l(-.199,.08),l(-.52,.08),l(-.46,-.12),l(-.319,-.26),l(-.26,-.06),l(-.68,-.12),l(-.56,.06),l(-.659,.319),l(-.42,.02),l(-.799,.5),l(-.72,.28),l(-.499,.06),l(-.42,-.02),l(-.279,.24),l(-.213,.18),l(-.616,-.19),l(-.857,-.377),l(-.068,-.308),l(.343,-.103),l(.309,.103),l(.445,.103),l(.138,-.103),l(-.96,-1.131),l(-.343,-.514),l(-.479,-.206),l(-.515,-.445),l(-.514,-.034),l(-.343,.034),l(-.583,-.206),l(-.103,.343),l(-.514,-.514),l(.068,-.309),l(-.138,-.377),l(-1.37,-.343),l(.65,-1.165),l(.446,-.274),l(.239,-.206),l(-.239,-.274),l(-.343,-.171),l(.205,-1.303),l(.823,-.137),l(.343,-.549),l(.103,-.308),l(.411,-.069),l(.514,.24),l(.48,.548),l(.514,.411),l(.651,0),l(.411,-.24),l(.068,-.446),l(-.171,-.411),l(-.068,-.445),l(.479,-.206),l(.891,-.411),l(.172,-.24),l(.309,-.309),l(.514,-.171),l(.549,-.068),l(.788,-.377),l(.548,-.343),l(.515,-.309),l(.651,.069),l(.479,0),l(.309,.274),l(.651,-.137),l(.273,-.137),l(.617,-.24),l(.411,.069),l(.411,.514),l(.788,.035),l(.617,-.069),l(.96,.171),l(0,.343),l(.582,.206),l(.789,.343),l(.411,.274),l(.068,.583),l(.274,.137),l(.239,-.274),l(-.205,-.48),l(-.034,-.24),l(.72,.068),l(.582,.548),l(.686,.137),l(.411,.24),l(.686,-.171),l(.274,-.274),l(.377,-.343),l(.514,-.377),l(.823,.068),l(.65,.035),l(.651,.411),l(.617,-.068),l(.137,-.412),l(1.062,-.103),l(.754,.103),l(.274,.548),l(.926,.309),l(.754,.137),l(.411,.171),l(.651,-.343),l(.171,-.309),l(.24,0),l(.343,.343),l(.959,.034),l(1.577,-.411),l(.137,-.309),l(.138,-.686),l(-.24,-.24),l(-1.165,-.171),l(-.274,-.308),l(-.651,-.069),l(-.377,-.137),l(.068,-.171),l(-.377,-.137),l(-.239,0),l(-.164,-.274),l(.467,-.067),l(.735,-.368),l(.588,-.147),l(.331,-.294),l(-.441,-.478),l(-.146,-.257),l(.662,-.515),l(.698,-.184),l(1.103,.147),l(.515,-.073),l(.11,-.257),l(-.956,-.294),l(-1.065,-.11),l(0,-.331),l(.294,-.074),l(-.294,-.221),l(-.074,-.441),l(.185,-.515),l(.33,-.074),l(1.066,.147),l(.515,0),l(.772,0),l(.368,-.184),l(1.396,-.405),l(1.029,-.037),l(.735,-.11),l(1.545,-.11),l(.588,-.073),l(.331,.073),l(.221,-.331),l(.625,-.331),l(1.177,-.037),l(2.021,-.405),l(1.876,-.073),l(.625,-.074),l(.367,-.368),V(0,77.39),l(.515,-.037),l(.589,-.184),l(.11,-.221),l(.735,-.037),l(.919,.147),l(.515,.11),l(.772,.257),l(.625,-.11),l(.882,-.037),l(.368,.404),l(-.037,.331),l(.147,.221),l(.515,.22),l(-.11,.331),l(-.147,.257),l(.073,.331),l(-.33,.037),l(.184,.257),l(.478,.074),l(.295,-.147),l(.44,.11),l(.368,-.147),l(.367,.074),l(.331,-.221),l(.294,.11),l(.295,.368),l(.367,.221),l(.147,-.147),l(.184,-.147),l(.478,.037),l(.405,.294),l(.478,.11),l(.441,-.221),l(.367,0),l(-.146,.294),l(-.441,.184),l(-.331,.441),l(.331,.184),l(.441,-.11),l(.771,-.073),l(.441,.037),l(.552,.184),l(.294,-.294),l(.772,-.441),l(1.103,-.257),l(.956,-.515),l(.772,-.221),l(.515,-.22),l(.809,-.074),l(0,.441),l(-.515,.11),l(-.11,.368),l(1.104,.588),l(.809,.294),l(1.287,.772),l(1.066,1.029),l(1.69,2.133),l(.846,.882),l(1.104,1.434),l(.515,-.257),l(.331,-.257),l(.367,-.515),l(.92,0),l(.367,.331),l(0,.368),l(.478,0),l(.258,.257),l(.184,.184),l(.589,0),l(.992,0),l(.993,-.221),l(.771,-.221),l(.993,-.037),l(.698,.441),l(.772,.588),l(.331,.625),l(.956,.147),l(.588,.552),l(.662,.699),l(.882,.073),l(.993,.074),l(.478,-.368),l(.625,-.184),l(-.073,.331),l(.441,.331),l(.294,.478),l(.589,0),l(.064,.145),l(-.551,.034),l(-.542,.148),l(-.279,.262),l(-.011,.275),l(-.035,.478),l(-.306,.219),l(-.289,.06),l(-1.199,.093),l(-.428,.277),l(-.34,.581),l(.097,.75),l(.213,.707),l(-.157,.39),l(-.444,.392),l(-.417,.103),l(-.718,.062),l(-1.402,-.079),l(-.594,-.141),l(-.721,-.141),l(-1.096,-.254),l(-.427,.507),l(-.516,1.141),L(584.2,97.43),l(-.286,.605),l(-.137,.418),l(.622,.514),l(.126,.286),l(-.156,.245),l(-.231,.145),l(-.394,.074),l(-1.133,-.238),l(-.5,-.184),l(-.35,.06),l(-1.082,.207),l(-1.799,.254),l(-.393,.188),l(-.215,.302),l(-.068,.215),l(.232,.185),l(.366,-.06),l(.483,.141),l(.03,1.357),l(.345,.627),l(.29,.441),l(.119,.47),l(-.222,.33),l(-.705,.546),l(-.32,.401),l(-.02,.399),l(.139,.86), +N(386.786,80.184),l(-.304,.038),l(-.223,.09),l(.241,.252),l(.361,.771),l(.287,1.213),l(-.061,.281),l(-.359,.341),l(-.242,.414),l(-.145,.473),l(-.185,.044),l(-.284,-.058),l(-.616,.031),l(-.15,.212),l(-.913,.042),l(-.84,.132),l(-.247,.144),l(-.661,.286),l(-.903,.498),l(-.628,.035),l(-.879,.283),l(-1.28,.084),l(.053,-.378),l(-.089,-.441),l(-.848,.1),l(-.171,-.487),l(.734,-.254),l(-1.186,-.021),l(.062,-.233),l(1.286,.027),l(.198,-.104),l(.039,-.222),l(.107,-.31),l(.515,-.134),l(.692,-.031),l(.13,-.281),l(-1.07,.099),l(.387,-.437),l(-.187,-.159),l(.481,-.468),l(.694,-.011),l(.163,-.089),l(-.174,-.311),l(-.348,.177),l(-.309,-.131),l(-.319,.03),l(-.391,-.177),l(-.414,.001),l(-.182,.106),L(378,81.478),l(.309,-.306),l(-.29,-.142),l(.759,-.126),l(-.139,-.301),l(.391,-.235),l(-.481,-.214),l(-.59,.128),L(378,79.792),l(.38,-.268),l(.215,-.16),l(.928,.187),l(.336,-.075),l(.527,.038),l(1.102,.123),l(-.214,-.358),L(382.132,79),l(.198,-.321),l(-1.373,0),l(.154,-.15),l(.569,-.107),l(.061,-.29),l(.291,-.479),l(.505,-.181),l(.804,-.169),l(.22,.302),l(.354,.149),l(.156,-.031),l(.029,.235),l(-.385,.484),l(-.817,.107),l(.483,.257),l(-.86,.278),l(.101,.278),l(.401,.278),l(.778,.192),l(.751,-.257),l(.253,-.364),l(.335,.107),l(.26,.257),l(.364,.15),l(-.123,.256),l(.967,-.072),l(.178,.272), +N(452.998,85.535),V(0,85.49),l(.037,-.131),l(.374,.019),l(.261,0),l(.112,.112),l(.373,-.206),l(.374,-.168),l(.037,-.168),l(.205,-.187),l(.485,-.019),l(.485,.038),l(.354,-.056),l(.355,-.056),l(.354,.056),l(.485,0),l(.467,-.075),l(.522,.093),l(.262,-.019),l(.205,.168),l(.522,0),l(.075,.056),l(.578,.056),l(.523,.112),l(.242,-.075),l(.28,.037),l(-.019,.224),l(.187,0),l(0,.149),l(.541,-.112),l(.187,.056),l(.243,.038),l(-.056,.224),l(.093,.056),l(.168,-.093),l(.019,-.205),l(.112,0),l(.262,.112),l(.354,-.056),l(.131,-.112),l(.224,.093),l(.131,.187),l(.224,-.112),l(.206,0),l(.13,.075),l(.094,.187),l(.168,0),l(.131,-.149),l(.299,-.149),l(.168,0),l(.131,-.075),l(.13,-.038),l(.168,.131),l(.112,.131),l(.037,.205),l(.188,.056),l(.316,-.056),l(.188,-.093),l(.224,-.075),l(.149,.131),l(.299,-.019),l(.242,-.075),l(.225,-.037),l(.224,.037),l(.187,.075),l(.112,.056),l(.149,.206),l(.149,.056),l(.261,.019),l(.131,-.206),l(-.056,-.149),l(-.243,-.205),l(.057,-.206),l(.261,-.224),l(.188,-.261),l(.317,-.187),l(.111,-.112),l(.057,-.13),l(.336,-.075),l(.187,.037),l(.205,.056),l(.112,-.131),l(.522,-.056),l(.519,.005),l(.357,.089),l(.469,.022),l(.313,-.156),l(.179,-.291),l(.134,-.268),l(.536,.246),l(.536,-.022),l(.67,-.223),l(.692,.112),l(.514,-.134),l(.201,.268),l(.312,.134),l(.246,.335),l(.134,.201),l(.246,.156),l(.312,.156),l(0,.268),l(-.312,-.022),l(-.312,.134),l(.134,.291),l(.111,.357),l(.269,.29),l(.647,0),l(.156,.112),l(.514,-.067),l(.38,.022),l(0,.312),l(.402,0),l(0,.357),l(.224,.268),l(.089,.246),l(-.089,.179),l(.089,.224),l(.179,.089),l(.291,.29),l(.268,-.179),l(.47,-.067),l(.268,.067),l(.469,.291),l(.201,-.067),l(.179,.022),l(.179,.156),l(.425,-.112),l(.312,-.112),l(.269,0),l(.536,-.134),l(.357,-.067),l(.111,.156),l(.268,.179),l(0,.134),l(.201,.179),l(.022,.134),l(.402,.044),l(.179,.179),l(.224,.112),l(.29,-.134),l(.045,-.157),l(.224,-.067),l(.29,.268),l(.425,.067),l(.469,.112),l(.268,.112),l(.357,-.067),l(.201,.179),l(.291,.089),l(.469,.022),l(.111,.224),l(.357,.156),l(.269,0),l(.134,-.044),l(.201,-.089),l(.156,.089),l(-.089,.111),l(-.022,.179),l(.111,.089),l(.09,.179),l(-.045,.224),l(-.201,.089),l(-.156,.067),l(-.357,.201),l(-.312,.044),l(.223,.246),l(.269,.089),l(.29,.044),l(-.134,.156),l(-.312,0),l(-.246,0),l(-.045,.179),l(-.044,.224),l(.156,.067),l(.179,.067),l(.044,.134),l(.045,.179),l(.09,.201),l(.066,.067),l(-.156,.491),l(-.156,.291),l(0,.156),l(-.335,.134),l(-.805,-.157),l(-.736,.045),l(-.269,0),l(-.022,.179),l(-.223,.179),l(-.38,.134),l(-.357,.022),l(-.224,.089),l(-.09,.514),l(0,.224),l(-.021,.112),l(-.012,.126),l(-.779,.104),l(-.971,.06),l(-.511,.405),l(-.729,.189),l(-1.135,.075),l(-1.119,.248),l(-.502,.318),l(-.463,.059),l(-.453,-.316),l(-.369,.621),l(-.31,.188),l(-.477,.044),l(-.438,-.057),l(-.959,.031),l(-.5,.16),l(.641,.287),l(1.957,1.004),l(.053,.172),l(-.093,.188),l(.163,.244),l(.562,.042),l(.511,-.13),l(.675,-.146),l(1.052,.013),l(.439,.114),l(-.235,.259),l(-.106,.245),l(-.228,.144),l(-.578,.116),l(-.31,.029),l(-.591,-.157),l(-.473,.044),l(-.71,.489),l(-1.007,.045),l(-.538,.188),l(-.527,.488),l(-.269,.101),l(-.786,-.07),l(-.588,-.171),l(.364,-.746),l(-.096,-.416),l(-.264,-.287),l(-.854,-.286),l(-.193,-.014),l(-.629,.016),l(-.151,.043),l(-.16,-.187),l(.887,-.505),l(.644,-.261),l(.772,-.188),l(.221,-.116),l(-.246,-.46),l(-.435,-.071),l(-.799,.044),l(-1.015,.045),l(-.698,-.1),l(-.195,-.101),l(-.418,-.432),l(.584,-.405),l(-.528,-.605),l(-.378,.361),l(-.541,.001),l(-1.001,.146),l(-.565,.131),l(-.694,.722),l(-1.003,.867),l(-.754,.203),l(-.223,.044),l(-.287,.504),l(.079,.158),l(.178,.093),l(-.706,-.131),l(-.665,.261),l(-.457,0),l(-.033,.189),l(-.609,-.047),l(-.398,-.166),l(-.119,-.249),l(-.15,.02),l(.055,-.077),l(.102,-.025),l(.126,.013),l(.113,.013),l(.189,0),l(.088,-.114),l(0,-.088),l(-.063,-.113),l(.025,-.113),l(.126,-.063),l(.051,-.063),l(.075,-.013),l(.089,-.025),l(.088,-.063),l(.089,-.088),l(.024,-.126),l(-.013,-.114),l(.14,-.013),l(.29,-.063),l(.075,-.076),l(-.025,-.088),l(-.062,-.088),l(.126,-.114),l(.037,-.063),l(-.012,-.088),l(-.114,-.113),l(.051,-.101),l(-.088,-.151),l(-.063,-.101),l(.202,-.151),l(.239,-.025),l(.126,-.088),l(.113,.025),l(.013,.088),l(-.013,.214),l(.063,.013),l(.113,0),V(0,96.92),l(-.013,-.063),l(.101,.038),l(.063,.051),l(.025,-.076),l(.075,-.038),l(.139,-.012),l(0,.075),l(.089,.063),l(.075,0),l(.126,.164),l(.076,-.076),l(.075,-.076),l(.013,-.05),l(.101,-.025),l(.177,0),l(-.037,.189),l(.176,.025),l(.038,-.038),l(.038,-.038),l(.139,.013),l(.227,0),l(.038,-.025),l(.075,-.076),l(-.126,-.013),l(-.164,-.126),l(-.101,-.051),l(-.075,-.05),l(.013,-.038),l(.101,-.063),l(-.025,-.113),l(.038,-.101),l(-.013,-.126),l(-.051,-.139),l(-.101,-.063),l(-.177,-.076),l(-.075,0),l(-.151,-.126),l(-.151,-.063),l(-.151,-.038),l(.051,-.151),l(.037,-.088),l(-.037,-.051),l(-.127,.038),l(-.062,-.114),l(.113,-.038),l(-.013,-.189),l(.089,-.075),l(-.025,-.101),l(-.038,-.088),l(-.113,0),l(-.102,.05),l(-.088,.051),l(-.113,-.088),l(-.089,-.101),l(-.188,-.101),l(-.139,-.025),l(-.102,-.139),l(-.05,-.139),l(.177,-.139),l(0,-.189),l(.024,-.114),l(.051,-.05),l(-.126,-.063),l(.164,-.151),l(-.113,-.025),l(-.076,-.063),l(-.062,-.126),l(-.14,-.013),l(-.062,.101),l(-.126,-.025),l(-.215,-.025),l(-.126,-.189),l(-.05,-.189),l(-.417,-.075),l(-.277,.012),l(-.062,.051),l(-.076,.101),l(-.062,-.05),l(0,-.076),l(-.089,-.025),l(-.101,.038),l(.038,-.05),l(.088,-.101),l(-.025,-.063),l(-.113,0),l(-.177,.038),l(-.126,-.025),l(-.101,.013),l(-.076,-.076),l(-.05,-.063),l(-.101,-.063),l(-.151,-.013),l(-.139,-.05),l(-.14,-.126),l(-.214,-.088),l(-.038,-.013),l(-.126,.025),l(-.05,.025),l(-.114,-.051),l(-.088,-.025),l(-.139,.025),l(-.177,.051),l(-.177,-.025),l(-.062,.038),l(-.126,.114),l(-.202,0),l(-.265,-.038),l(-.126,.051),l(-.315,-.114),l(-.088,.101),l(.012,.113),l(-.126,0),l(-.075,-.063),l(-.126,.114),l(-.06,.052),l(-.634,.08),l(-.151,.311),l(-.278,.178),l(-1.992,.191),l(-.186,.215),l(-.243,.119),l(-.339,.06),l(-.188,-.227),l(-.327,.004),l(-.025,-.231),l(-.363,.045),l(-1.115,-.066),l(-.958,-.193),l(-.241,.107),l(-.787,-.121),l(-.136,.085),l(-.678,-.387),l(-.554,-.2),l(-.668,-.301),l(-.166,.015),l(1.047,-1.471),l(.653,.018),l(-.349,-.383),l(-.044,-.552),l(.082,-.306),l(1.509,-1.218),l(.599,-.398),l(.286,-.181),l(.429,-.013),l(.255,-.24),l(.009,-.314),l(-.328,-.302),l(.085,-.133),l(.298,-.048),l(-.316,-.193),l(-.816,-.835),l(.074,-.242),l(-.161,-.175), +N(660.044,89.132),l(-.295,.31),l(-.687,1.207),l(-1.224,1.959),l(-.381,.58),l(.269,.836),l(.051,.029),l(.342,-.045),l(.929,-.395),l(.754,-.062),l(.576,-.018),l(.317,.085),l(.431,.416),l(.292,.07),l(1.191,-.786),l(.438,-.002),l(.928,.212),l(.538,.199),l(.797,.5),l(.879,.99),l(.599,.501),l(.048,.273),l(-.107,.217),l(-.414,.218),l(-.464,-.127),l(-1.074,-.008),l(-.432,-.099),l(-.854,.033),l(-.937,.221),l(-.539,.146),l(-.831,.278),l(-.353,.189),l(-.483,-.127),l(-.464,.045),l(-.47,.204),l(-.363,.333),l(-.312,.82),l(-.241,.216),l(-.347,.188),l(-.638,.248),l(-.896,.134),l(-.624,-.054),l(-.438,-.012),l(-.224,-.013),l(-1.192,.91),l(-.742,.433),l(-.744,.047),l(-.982,.005),l(-.592,-.125),l(-.668,-.382),l(-.718,-.154),l(-.316,.073),l(-.457,.231),l(-.539,.589),l(-.214,.401),l(.003,.343),l(.389,.569),l(.599,.411),l(.188,.228),l(-.123,.271),l(-.326,.259),l(-1.265,.292),l(-.67,.389),l(-1.111,1.046),l(-.265,.172),l(-1.941,.737),l(-.651,.061),l(-.987,-.08),l(-1.514,.065),l(-1.339,.007),l(-1.204,.349),l(-.816,.289),l(-.736,.274),l(-.303,.101),l(-1.44,.534),l(-.686,.289),l(-.481,.017),l(-.433,-.197),l(-.253,-.297),l(-.61,-.067),l(-.663,.061),l(-.929,-.123),l(-1.599,-.433),l(-1.006,-.365),l(-.815,-.551),l(-.521,-.168),l(-1.69,-.119),l(-1.164,-.022),l(-.937,-.023),l(-2.861,.059),l(-1.165,-.022),l(-.802,-.109),l(-1.241,-.207),l(-1.979,-.018),l(-.444,-.254),l(-.467,-.439),l(-1.571,-2.161),l(-.105,-.542),l(-.744,-.096),l(-.839,-.31),l(-1.645,-.806),l(-.632,-.268),l(-.998,-.224),l(-.668,-.083),l(-.995,-.038),l(-1.505,-.021),l(-1.062,-.181),l(-.724,-.312),l(-.233,-.229),l(-.105,-.43),l(.035,-.129),l(.369,-.347),l(.214,-.389),l(.237,-.75),l(.215,-.447),l(-.401,-.66),l(-1.07,-1.451),l(-.568,-.618),l(-.354,-.143),l(-.633,-.144),l(-.731,-.167),l(-.614,-.069),l(-.834,-.415),l(-1.301,-.745),l(-.371,-.433),l(-.24,-.563),l(-.131,-.405),l(-.062,-.145),l(.154,-.044),l(.799,-.425),l(.599,-.207),l(1.387,-.08),l(.603,-.148),l(.727,-.381),l(.017,-.012),l(.971,-.692),l(.787,-.398),l(1.143,-.341),l(1.512,-.476),l(.84,-.18),l(.953,.097),l(.932,.156),l(1.842,.122),l(.831,.083),l(.694,.755),l(.393,.406),l(.699,.113),l(1.458,-.008),l(.719,.083),l(.85,-.004),l(.875,.068),l(.312,.114),l(.576,.186),l(.562,-.018),l(.755,-.28),l(.31,-.162),l(.744,-.572),l(.163,-.526),l(-.116,-.204),l(-.396,-.304),l(-.409,-.86),l(.098,-.293),l(.905,-.839),l(1.269,-.96),l(.84,.201),l(1.028,.098),l(1.036,.185),l(1.748,.328),l(.702,.231),l(.989,.317),l(.767,.143),l(.145,.204),l(.004,.541),l(.182,.481),l(.408,.451),l(.421,.333),l(1.643,.531),l(.673,.113),l(2.48,-.538),l(.796,-.077),l(1.172,.037),l(1.423,.022),l(.769,.229),l(1.333,.75),l(.623,.331),l(1.132,.313),l(.812,.373),l(1.318,.254),l(.905,.241),l(.984,.082),l(.739,.039),l(1.602,-.11),l(1.018,-.063),l(.532,-.075),l(.867,-.106),l(1.147,-.136),l(.526,-.163),l(.604,-.264),l(.447,-.394),l(.755,-.498),l(1.165,-.487),l(.333,-.002),l(.609,-.047),l(.74,.156),l(.751,.506),l(.34,.129),l(.86,.169),l(1.228,-.297),l(.622,-.018),l(.431,.168), +N(406.183,86.551),l(1.051,-.494),l(.485,-.089),l(.574,.087),l(.465,-.016),l(.209,-.147),l(.477,.098),l(.407,.042),l(.52,-.034),l(-.025,-.157),l(.307,.012),l(.307,0),l(.267,-.182),l(.313,.242),l(.173,-.121),l(.228,.061),l(.292,.375),l(.535,-.109),l(.754,.375),l(-.11,.423),l(-.172,.097),l(.001,.338),l(.672,-.024),l(.344,.177),l(.282,.365),l(.038,.468),l(-.422,.376),l(-.225,-.072),l(-.142,.08),l(-.245,.147),l(-.213,.322),l(.017,.327),l(.31,.204),l(-.136,.348),l(-.079,-.114),l(-.694,.174),l(-.127,-.228),l(-.371,-.204),l(-.341,-.192),l(-.529,-.048),l(.039,-.228),l(-.146,-.18),l(.119,-.373),l(-.245,.072),l(-.193,.313),l(-.446,.035),l(-.406,.075),l(-.285,-.122),l(.072,-.198),l(-.091,-.175),l(.159,-.241),l(-.375,-.168),l(-.576,-.048),l(-.259,.012),l(-.159,-.301),l(-.518,.012),l(-.194,-.133),l(-.202,-.458),l(-.153,-.17),l(-.41,.208),l(-.141,.071),l(-.266,-.127),l(-.311,-.335),l(-.208,-.447), +N(438.22,91.952),l(.039,-.044),l(.065,-.105),l(.014,-.131),l(.092,-.066),l(.146,-.119),l(.026,-.04),l(.171,-.053),l(.093,-.026),l(.092,.053),l(.132,.053),l(.158,0),l(.065,-.026),l(.093,0),l(.065,.026),l(.065,.026),l(.093,-.026),l(.145,-.04),l(.132,0),l(.118,-.053),l(.079,-.053),l(.066,-.026),l(.105,-.026),l(.039,0),l(.053,-.079),l(.04,-.092),l(.079,-.079),l(.092,.026),l(.105,-.04),l(.145,-.066),l(.053,-.105),l(.053,-.079),l(.026,-.132),l(.026,-.092),l(.053,-.092),l(.118,-.013),l(.105,-.013),l(.132,-.079),l(.119,-.053),l(.118,-.092),l(.053,-.079),l(.132,-.066),l(.065,-.04),L(442,89.998),l(.145,.013),l(.105,.026),l(.066,-.04),l(.065,-.066),l(.071,.012),l(.285,.041),l(.03,.228),l(.43,-.048),l(.183,-.24),l(.193,.016),l(.062,-.112),l(.261,-.024),l(.194,.24),l(.073,.169),l(.331,-.025),l(.066,.18),l(-.026,.083),l(.003,.204),l(.389,-.083),l(.18,.12),l(.149,-.135),l(.104,-.177),l(.558,-.204),l(.168,.056),l(.483,-.046),l(.46,.254),l(.373,-.18),l(.073,-.137),l(.508,.041),l(.561,-.076),l(.129,.13),l(.703,.186),l(.104,.216),l(.424,.101),l(.831,.33),l(-1.047,1.471),l(-.629,.076),l(-.437,-.143),l(-.534,-.359),l(-1.062,.035),l(-.717,.047),l(-1.024,.759),L(444.857,93),l(-.59,-.072),l(-.499,.061),l(-.761,.134),l(-.255,.001),l(-.334,.568),l(-1.651,-.036),l(-.414,-.027),l(-.617,-.17),l(-.399,-.172),l(-.245,.146),l(-.761,-.547),l(-.155,-.26),l(.097,-.581),l(-.053,-.093), +N(442.391,98.111),l(-.589,.203),l(-.433,.031),l(-.668,.047),l(-.58,-.098),l(-1.116,-.671),l(-1.412,-.612),l(-.215,-.197),l(-.364,-.333),l(-.304,-.59),l(.346,-.299),l(.154,-.294),l(-.204,-.188),l(.04,-.375),l(.409,-.062),l(.157,-.206),l(-.136,-.196),l(-.452,-.063),l(.223,-.197),l(.325,0),l(.164,.134),l(.701,-.054),l(.019,-.367),l(.636,-.291),l(.245,-.146),l(.399,.172),l(.617,.17),l(.414,.027),l(1.651,.036),l(.334,-.568),l(.255,-.001),l(.761,-.134),l(.499,-.061),l(.59,.072),l(.427,-.063),l(1.024,-.759),l(.717,-.047),l(1.062,-.035),l(.534,.359),l(.437,.143),l(.629,-.076),l(.166,-.015),l(.668,.301),l(.554,.2),l(.678,.387),l(-.45,.338),l(-1.125,.267),l(-.581,.408),l(-.968,1.451),l(-.63,.84),l(-.753,.567),l(-.361,.16),l(-.724,.047),l(-.264,.103),l(-.176,-.002),l(-.907,-.067),l(-.889,.077),l(-1.535,.529), +N(459.717,92.836),l(.06,-.052),l(.126,-.114),l(.075,.063),l(.126,0),l(-.012,-.113),l(.088,-.101),l(.315,.114),l(.126,-.051),l(.265,.038),l(.202,0),l(.126,-.114),l(.062,-.038),l(.177,.025),l(.177,-.051),l(.139,-.025),l(.088,.025),l(.114,.051),l(.05,-.025),l(.126,-.025),l(.038,.013),l(.214,.088),l(.14,.126),l(.139,.05),l(.151,.013),l(.101,.063),l(.05,.063),l(.076,.076),l(.101,-.013),l(.126,.025),l(.177,-.038),l(.113,0),l(.025,.063),l(-.088,.101),l(-.038,.05),l(.101,-.038),l(.089,.025),l(0,.076),l(.062,.05),l(.076,-.101),l(.062,-.051),l(.277,-.012),l(.417,.075),l(.05,.189),l(.126,.189),l(.215,.025),l(.126,.025),l(.062,-.101),l(.14,.013),l(.062,.126),l(.076,.063),l(.113,.025),l(-.164,.151),l(.126,.063),l(-.051,.05),l(-.024,.114),l(0,.189),l(-.177,.139),l(.05,.139),l(.102,.139),l(.139,.025),l(.188,.101),l(.089,.101),l(.113,.088),l(.088,-.051),l(.102,-.05),l(.113,0),l(.038,.088),l(.025,.101),l(-.089,.075),l(.013,.189),l(-.113,.038),l(.062,.114),l(.127,-.038),l(.037,.051),l(-.037,.088),l(-.051,.151),l(.151,.038),l(.151,.063),l(.151,.126),l(.075,0),l(.177,.076),l(.101,.063),l(.051,.139),l(.013,.126),l(-.038,.101),l(.025,.113),l(-.101,.063),l(-.013,.038),l(.075,.05),l(.101,.051),l(.164,.126),l(.126,.013),l(-.075,.076),l(-.038,.025),l(-.227,0),l(-.139,-.013),l(-.038,.038),l(-.038,.038),l(-.176,-.025),l(.037,-.189),l(-.177,0),l(-.101,.025),l(-.013,.05),l(-.075,.076),l(-.076,.076),l(-.126,-.164),l(-.075,0),l(-.089,-.063),l(0,-.075),l(-.139,.012),l(-.075,.038),l(-.025,.076),l(-.063,-.051),l(-.101,-.038),l(.013,.063),l(0,.088),l(-.113,0),l(-.063,-.013),l(.013,-.214),l(-.013,-.088),l(-.113,-.025),l(-.126,.088),l(-.239,.025),l(-.202,.151),l(.063,.101),l(.088,.151),l(-.051,.101),l(.114,.113),l(.012,.088),l(-.037,.063),l(-.126,.114),l(.062,.088),l(.025,.088),l(-.075,.076),l(-.29,.063),l(-.14,.013),l(.013,.114),l(-.024,.126),l(-.089,.088),l(-.088,.063),l(-.089,.025),l(-.075,.013),l(-.051,.063),l(-.126,.063),l(-.025,.113),l(.063,.113),l(0,.088),l(-.088,.114),l(-.189,0),l(-.113,-.013),l(-.126,-.013),l(-.102,.025),l(-.055,.077),l(-.03,.004),l(-.062,-.237),l(-.218,-.106),l(.16,-.071),l(-.021,-.267),l(-.104,-.561),l(.323,-.978),l(.027,-.404),l(-.353,-.856),l(-.604,-.286),l(-1.037,-1.119),L(460.567,93),l(-.626,-.191),l(-.225,.028), +N(445.722,97.573),l(.176,.002),l(.264,-.103),l(.724,-.047),l(.361,-.16),l(.753,-.567),l(.63,-.84),l(.968,-1.451),l(.581,-.408),l(1.125,-.267),l(.45,-.338),l(.136,-.085),l(.787,.121),l(.241,-.107),l(.958,.193),l(1.115,.066),l(.363,-.045),l(.025,.231),l(.327,-.004),l(.188,.227),l(.339,-.06),l(.243,-.119),l(.186,-.215),l(1.992,-.191),l(.278,-.178),l(.151,-.311),l(.634,-.08),l(.225,-.028),L(460.567,93),l(.767,1.17),l(1.037,1.119),l(.604,.286),l(.353,.856),l(-.027,.404),l(-.323,.978),l(.104,.561),l(.021,.267),l(-.16,.071),l(.218,.106),l(.062,.237),l(.03,-.004),l(.15,-.02),l(.119,.249),l(.398,.166),l(.609,.047),l(.033,-.189),l(.457,0),l(.665,-.261),l(.706,.131),l(.149,.079),l(.062,.259),l(-.293,.446),l(-.27,.316),l(-.436,.044),l(-.382,.043),l(-.382,.245),l(-.515,.617),l(-.252,.645),l(-.096,.787),l(-.044,.223),l(-.671,-.12),l(-1.346,-.336),l(-.514,-.226),l(-.295,-.042),l(-.671,-.369),l(-.562,-.04),l(-.618,.218),l(-1.904,.771),l(-.38,.059),l(-1.385,-.35),l(-.3,-.013),l(-.69,.261),l(-.34,.031),l(-1.151,-.395),l(-.506,-.002),l(-.771,.189),l(-.266,.023),l(-.048,-.189),l(.234,-.318),l(-.352,-.106),l(-.392,-.204),l(-.418,-.186),l(-.146,-.33),l(.32,-.201),l(.351,.012),l(-.114,-.13),l(-.625,-.248),l(-.253,.13),l(-.215,.283),l(-.147,.118),l(-.414,-.239),l(-.194,-.139),l(-.594,-.059),l(-.02,-.189),l(-.234,0),l(-.245,-.036),l(-.052,-.165),l(.178,-.094),l(.271,-.071),l(-.239,-.083),l(-.183,-.059),l(.124,-.146),l(.19,-.127),l(-.069,-.142),l(-.306,-.118),l(-.555,-.141),l(-.712,-.471),l(.058,-.088),l(-.104,-.119),l(.075,-.356),l(-.202,-.036),l(-.19,-.237),l(-.569,-.178),l(-.054,-.309), +N(420.177,113.472),l(-.274,-.042),l(-.253,-.155),l(-.367,-.325),l(-.096,-.213),l(.202,-.738),l(.097,-.681),l(-.046,-.583),l(-.133,-.569),l(-.503,-.44),l(-.094,-.271),l(.181,-.157),l(.366,-.015),l(.801,-.001),l(.339,-.172),l(.861,-.543),l(.633,.625),l(.451,.754),l(-.014,.271),l(-.204,.285),l(-.145,.484),l(.149,.894),l(-.11,.525),l(-.377,.695),l(-.405,-.198),l(-.52,.03),l(-.143,.1),l(-.149,.27),l(-.248,.17),M(433.783,118.446),l(-.712,-.084),l(-.902,-.607),l(-.772,-.239),l(-1.904,-.817),l(-.833,-.126),l(-.232,-.127),l(-.173,-.283),l(.139,-.34),l(.328,-.34),l(.264,-.1),l(.629,.112),l(.569,-.341),l(.68,.424),l(.403,.141),l(.722,-.016),l(1.403,-.187),l(1.38,-.329),l(.148,.085),l(.043,.127),l(-.112,.127),l(-.536,.823),l(-.153,.497),l(.009,.382),l(.411,.509),l(-.179,.128),l(-.43,.567),l(-.188,.015),M(431.244,98.829),l(-.281,-.329),l(-.242,-.027),l(-.281,.196),l(-.156,-.125),l(-.47,-.071),l(-.114,.32),l(-.458,.054),l(-1.001,.364),l(.078,-.151),l(-.452,.133),l(-.063,.249),l(-.157,.044),l(-.01,.125),l(.303,.08),l(.021,.302),l(.193,.119),l(.253,.236),l(-.104,.213),l(-.449,.254),l(.016,.272),l(.143,.554),l(.783,.814),l(2.008,.889),l(.29,.357),l(.134,.558),l(.274,.557),l(.395,.585),l(.694,.57),l(.254,.274),l(.446,.195),l(.041,.21),l(.408,.167),l(1.17,.255),l(1.254,-.105),l(.388,.141),l(.024,.212),l(-.465,.247),l(-.258,.294),l(.262,.213),l(.954,.283),l(1.168,.411),l(.829,.366),l(1.589,.739),l(.058,.185),l(.719,.458),l(.31,.475),l(-.198,.435),l(-.152,.337),l(-.455,-.281),l(-.318,-.167),l(-.109,-.486),l(-.263,-.17),l(-.512,-.099),l(-.483,-.009),l(-.439,-.236),l(.086,-.217),l(-.353,-.065),l(-.301,.098),l(-.232,.262),l(-.259,.399),l(-.273,.208),l(.043,.271),l(-.197,.303),l(-.007,.298),l(.76,.342),l(.611,.271),l(-.093,.314),l(.03,.432),l(.133,.142),l(-.191,.238),l(-.659,-.024),l(-.41,.219),l(-.202,.228),l(.11,.595),l(-.536,.303),l(-.617,.866),l(-.595,.048),l(-.167,-.071),l(-.184,-.14),l(-.002,-.508),l(.364,-.141),l(.317,-.542),l(-.236,-.184),l(.361,-.249),l(.361,.074),l(.133,-.17),l(-.077,-.34),l(-.211,-.181),l(-.206,-.924),l(-.367,-.516),l(-.15,-.607),l(-.201,-.352),l(-.334,.058),l(-.187,.171),l(-.899,-.496),l(-.286,-.065),l(.208,-.291),l(-.092,-.398),l(-.461,-.34),l(-.909,.247),l(.034,-.109),l(.322,-.194),l(-.276,-.27),l(-.29,-.003),l(-.42,.19),l(-.242,-.512),l(-.198,-.207),l(-.124,-.228),l(-.663,-.241),l(-.505,-.027),l(-.654,-.127),l(-.745,-.355),l(-.548,-.441),l(-.959,-.612),l(-1.036,-.826),l(-.872,-.384),l(-.805,-.67),l(-.566,-.856),l(-.434,-1.043),l(-.347,-.443),l(-.505,-.457),l(-.483,-.243),l(-1.188,-.341),l(-.579,-.142),l(-.5,.044),l(-1.078,.647),l(-.46,.359),l(-.646,.173),l(-.303,.043),l(.146,-.469),l(-.062,-.281),l(-.849,.07),l(-.754,-.391),l(-.193,-.442),l(.315,-.371),l(.175,-.01),l(-.135,-.331),l(-.616,-.191),l(-.352,-.358),l(.437,-.186),l(.183,.111),l(.541,-.353),l(.199,-.272),l(-.43,-.192),l(-.025,-.292),l(-.532,-.344),l(.624,-.301),l(.599,.062),l(.627,-.204),l(.629,.168),l(.275,-.16),l(.349,-.432),l(-.103,-.212),l(.777,-.404),l(.016,.415),l(.534,.363),l(.311,.071),l(-.098,.182),l(.385,.312),l(.285,-.151),l(.018,-.535),l(.425,-.384),l(-.019,-.333),l(.371,-.081),l(.143,.354),l(.23,.142),l(.216,-.03),l(.071,-.122),l(.469,-.05),l(.244,.333),l(.228,-.415),l(-.244,-.131),l(.081,-.273),l(.283,-.091),l(.176,.162),l(.315,.051),l(.038,-.192),l(-.112,-.212),l(.126,-.309),l(.631,.171),l(.597,.034),l(.329,-.411),l(.366,-.096),l(.183,.083),l(.445,-.11),l(.301,.103),l(.856,-.227),l(.023,.363),l(.318,.096),l(.32,.391),l(1.311,.247),l(.894,.082),l(.478,.112),l(.116,.199),l(-.614,.303),l(.098,.151),l(.297,.002),l(.187,.185),l(-.367,.285),l(.336,.089),l(-.127,.361),l(.36,.11),l(.284,.198),l(-.056,.214), +N(430.73,96.731),l(1.04,.065),l(.179,.107),l(.612,-.009),l(.287,.152),l(.646,-.5),l(.566,-.107),l(.85,.08),l(.298,-.196),l(.89,.116),l(-.082,-.393),l(.693,-.157),l(.304,.59),l(.364,.333),l(-.035,-.009),l(-.1,-.073),l(-.145,-.036),l(-.172,0),l(-.145,.009),l(-.055,.063),l(0,.072),l(.019,.09),l(.009,.082),l(-.063,.009),l(-.136,-.009),l(-.108,-.036),l(-.091,.063),l(-.045,.082),l(-.081,.063),l(-.082,.045),l(-.081,.009),l(-.163,.036),l(-.117,.036),l(-.108,.036),l(-.055,.045),l(-.153,-.009),l(-.127,.072),l(-.063,.054),l(-.018,.082),l(.036,.072),l(.081,.054),l(.063,.055),l(.045,.045),l(.019,.063),l(.018,.09),l(-.036,.108),l(-.018,.063),l(-.046,.1),l(-.108,0),l(-.081,-.009),l(-.091,.027),l(-.108,.009),l(-.117,.054),l(-.091,.018),l(-.081,.027),l(-.1,.045),l(-.055,.063),l(-.036,.027),l(.055,.018),l(.063,.009),l(.026,.027),l(.037,.072),l(-.046,.063),l(-.027,.009),l(-.081,.027),l(-.009,.045),l(.045,.081),l(0,.072),l(.045,.1),l(-.054,.072),l(-.063,-.018),l(-.1,.045),l(-.117,.018),l(-.127,-.036),l(-.063,-.027),l(-.1,-.063),l(-.099,0),l(-.063,-.027),l(-.118,-.045),l(-.018,.045),l(-.027,.045),l(-.1,.027),l(-.136,0),l(-.054,-.045),l(-.072,-.063),l(-.127,-.018),l(-.019,-.09),l(-.026,-.018),l(-.063,-.054),l(-.055,-.027),l(-.018,-.054),l(-.01,-.054),l(-.036,-.009),l(-.063,.018),l(-.036,.054),l(-.009,.027),l(-.054,.063),l(-.019,.018),l(-.018,.081),l(-.063,.045),l(-.046,.018),l(-.062,.054),l(-.036,.009),l(-.254,0),l(-.108,-.027),l(-.108,.027),l(-.145,.009),l(-.1,-.009),l(-.1,-.036),l(-.045,-.019),l(-.055,0),l(0,.037),l(0,.036),l(-.045,.027),l(-.045,.018),l(-.136,-.009),l(-.027,-.036),l(-.108,.018),l(-.019,.018),l(-.136,.018),l(-.063,.018),l(-.126,.018),l(-.272,-.063),l(.428,-.077),l(.113,-.16),l(.056,-.214),l(-.284,-.198),l(-.36,-.11),l(.127,-.361),l(-.336,-.089),l(.367,-.285),l(-.187,-.185),l(-.297,-.002),l(-.098,-.151),l(.614,-.303),l(-.116,-.199), +N(439.573,104.709),l(-1.051,-.672),l(-.185,-.222),l(-.783,-.149),l(-.203,-.159),l(-.403,-.115),l(-.683,.177),l(-.326,-.486),l(-1.112,-.627),l(-.584,-.678),l(.277,.007),l(.608,.016),l(-.583,-.221),l(-.659,-.469),l(-.183,-.407),l(.086,-.452),l(-.289,-.336),l(-.646,-.418),l(-.378,-.126),l(-.258,.579),l(-.142,.116),l(.03,.15),l(-.284,.106),l(-.154,.248),l(-.213,.053),l(-.496,-.647),l(-.063,-.286),l(-.259,-.612),l(.065,-.012),l(.272,.063),l(.126,-.018),l(.063,-.018),l(.136,-.018),l(.019,-.018),l(.108,-.018),l(.027,.036),l(.136,.009),l(.045,-.018),l(.045,-.027),l(0,-.036),l(0,-.037),l(.055,0),l(.045,.019),l(.1,.036),l(.1,.009),l(.145,-.009),l(.108,-.027),l(.108,.027),l(.254,0),l(.036,-.009),l(.062,-.054),l(.046,-.018),l(.063,-.045),l(.018,-.081),l(.019,-.018),l(.054,-.063),l(.009,-.027),l(.036,-.054),l(.063,-.018),l(.036,.009),l(.01,.054),l(.018,.054),l(.055,.027),l(.063,.054),l(.026,.018),l(.019,.09),l(.127,.018),l(.072,.063),l(.054,.045),l(.136,0),l(.1,-.027),l(.027,-.045),l(.018,-.045),l(.118,.045),l(.063,.027),l(.099,0),l(.1,.063),l(.063,.027),l(.127,.036),l(.117,-.018),l(.1,-.045),l(.063,.018),l(.054,-.072),l(-.045,-.1),l(0,-.072),l(-.045,-.081),l(.009,-.045),l(.081,-.027),l(.027,-.009),l(.046,-.063),l(-.037,-.072),l(-.026,-.027),l(-.063,-.009),l(-.055,-.018),l(.036,-.027),l(.055,-.063),l(.1,-.045),l(.081,-.027),l(.091,-.018),l(.117,-.054),l(.108,-.009),l(.091,-.027),l(.081,.009),l(.108,0),l(.046,-.1),l(.018,-.063),l(.036,-.108),l(-.018,-.09),l(-.019,-.063),l(-.045,-.045),l(-.063,-.055),l(-.081,-.054),l(-.036,-.072),l(.018,-.082),l(.063,-.054),l(.127,-.072),l(.153,.009),l(.055,-.045),l(.108,-.036),l(.117,-.036),l(.163,-.036),l(.081,-.009),l(.082,-.045),l(.081,-.063),l(.045,-.082),l(.091,-.063),l(.108,.036),l(.136,.009),l(.063,-.009),l(-.009,-.082),l(-.019,-.09),l(0,-.072),l(.055,-.063),l(.145,-.009),l(.172,0),l(.145,.036),l(.1,.073),l(.035,.009),l(.215,.197),l(1.412,.612),l(1.116,.671),l(.58,.098),l(.668,-.047),l(.433,-.031),l(.589,-.203),l(.201,.142),l(.056,.089),l(.022,.112),l(-.022,.078),l(.045,.044),l(.011,.067),l(-.078,.056),l(-.011,.146),l(.078,.067),l(.145,-.034),l(.101,.034),l(.045,.089),l(-.078,.011),l(-.056,-.022),l(-.022,.078),l(.033,.1),l(-.045,.034),l(-.044,.022),l(.066,.111),l(.168,-.022),l(.033,.078),l(.123,.1),l(.122,0),l(.101,0),l(.09,.078),l(.122,.011),l(.134,0),l(.012,.078),l(-.033,.056),l(-.135,-.011),l(-.089,-.034),l(-.067,.022),l(-.078,-.011),l(-.066,-.045),l(-.056,-.011),l(-.045,.011),l(.033,.067),l(-.101,.089),l(-.078,0),l(0,.156),l(.045,.067),l(-.033,.078),l(.022,.078),l(.011,.078),l(-.089,.033),l(-.09,-.033),l(-.056,.067),l(.078,.089),l(-.078,.011),l(-.189,.022),l(-.201,-.022),l(-.145,-.123),l(.056,-.101),l(-.045,-.089),l(-.123,-.011),l(-.022,-.112),l(-.145,-.056),l(-.146,-.045),l(-.101,.089),l(-.1,-.011),l(-.156,-.078),l(-.067,-.022),l(-.146,0),l(-.156,-.045),l(-.111,.067),l(-.134,.045),l(-.134,-.045),l(-.111,-.067),l(-.112,0),l(-.122,.089),l(-.168,.078),l(-.156,-.067),l(-.268,-.089),l(-.179,.011),l(-.156,.011),l(-.189,-.056),l(-.168,-.011),l(-.156,-.089),l(-.089,.078),l(-.111,.022),l(-.057,-.056),l(-.234,-.078),l(-.156,-.056),l(-.134,-.045),l(-.089,-.011),l(-.134,.123),l(-.112,-.011),l(-.223,-.022),l(-.168,-.033),l(-.212,.022),l(-.101,.111),l(-.145,.145),l(-.123,.201),l(-.201,-.022),l(-.256,-.134),l(-.156,-.19),l(-.101,-.111),l(-.312,-.034),l(-.123,.044),l(-.089,.179),l(-.045,.167),l(.045,.134),l(0,.078),l(.033,.212),l(-.123,.067),l(.022,.089),l(.134,.078),l(.09,.089),l(.122,.034),l(.101,.033),l(.179,.179),l(.146,.234),l(.089,.134),l(.022,.123),l(.156,.111),l(-.078,.056),l(-.012,.1),l(.022,.146),l(.168,-.011),l(.089,.111),l(.056,.123),l(.112,.111),l(.167,.045),l(.167,.033),l(.369,.357),l(.021,.167),l(.078,.044),l(.213,.078),l(.379,.357),l(.224,.123),l(.223,.067),l(.101,.056),l(0,.112),l(.078,.279),l(.201,.078),l(.189,.167),l(.146,.112),l(.245,.123),l(.067,.212),l(-.284,.083),M(439.792,104.833),l(.132,-.118),l(.134,.011),l(.123,.034),l(.045,.078),l(.066,.089),l(.146,.089),l(.179,.078),l(.212,.011),l(.312,.257),l(.045,.067),l(.134,-.033),l(.123,.022),l(.089,.034),l(.062,.063),l(.005,.004),l(-.022,.089),l(.033,.078),l(.082,.072),l(.029,.092),l(-.002,.1),l(-.589,-.367),l(-.549,-.371),l(-.789,-.378), +N(451.009,101.725),l(-.328,.346),l(-.383,.374),l(-.18,.302),l(.056,.271),l(1.326,1.122),l(.028,.2),l(-.302,.302),l(-.762,.333),l(-.246,.301),l(-.008,.514),l(-.013,.208),l(-.058,-.017),l(-.072,.029),l(-.16,.022),l(-.145,.021),l(-.116,.022),l(-.058,.015),l(-.102,-.051),l(-.087,.043),l(-.088,.021),l(-.102,-.043),l(-.064,-.021),l(-.131,.116),l(-.087,.08),l(-.152,-.015),l(-.196,-.007),l(-.064,.007),l(-.175,-.043),l(-.152,.087),l(-.151,.102),l(-.109,.058),l(.059,.072),l(-.029,.058),l(-.116,0),l(-.094,-.109),l(-.131,-.058),l(-.087,-.073),l(-.08,.065),l(-.116,.058),l(-.246,.058),l(-.225,.058),l(-.088,.058),l(-.058,.167),l(.029,.13),l(-.029,.072),l(-.072,.087),l(-.188,0),l(-.14,-.049),l(-.018,-.109),l(-.733,-.866),l(-.382,-.369),l(-.058,-.004),l(.109,-.286),l(0,-.067),l(-.078,-.067),l(-.101,0),l(-.056,-.056),l(.022,-.089),l(.111,-.033),l(.146,.011),l(.167,.033),l(.057,-.033),l(.021,-.067),l(.09,-.044),l(.134,-.022),l(.089,-.011),l(-.011,-.089),l(-.101,-.101),l(-.167,-.067),l(-.134,-.045),l(-.057,-.044),l(-.111,.022),l(-.078,-.045),l(-.033,-.067),l(-.123,-.101),l(-.078,-.1),l(-.066,-.022),l(-.067,.044),l(-.078,-.011),l(-.101,-.056),l(-.279,-.078),l(-.078,-.022),l(-.056,-.033),l(-.167,-.134),l(-.101,-.146),l(-.111,-.111),l(-.168,-.078),l(-.156,-.101),l(-.223,-.056),l(0,-.101),l(.179,-.101),l(.089,-.111),l(.078,-.011),l(.067,.034),l(.078,.044),l(.1,.022),l(.045,-.022),l(.012,-.134),l(.011,-.19),l(-.134,-.145),l(-.179,-.19),l(-.212,-.134),l(-.101,-.145),l(.101,.022),l(.101,.011),l(.145,.056),l(.224,.044),l(.134,-.078),l(.089,-.056),l(.067,-.078),l(-.089,-.044),l(-.135,-.022),l(-.089,-.089),l(-.123,-.078),l(-.156,-.089),l(-.033,-.101),l(-.045,-.1),l(-.212,.011),l(-.167,-.056),l(-.078,-.1),l(-.022,-.134),l(.078,-.067),l(0,-.089),l(-.033,-.1),l(.056,-.056),l(.066,-.078),l(.156,-.156),l(.156,-.223),l(.034,-.167),l(.056,-.1),l(-.022,-.067),l(-.123,-.022),l(-.179,-.011),l(-.156,0),l(-.212,.112),l(-.078,-.089),l(.056,-.067),l(.09,.033),l(.089,-.033),l(-.011,-.078),l(-.022,-.078),l(.033,-.078),l(-.045,-.067),l(0,-.156),l(.078,0),l(.101,-.089),l(-.033,-.067),l(.045,-.011),l(.056,.011),l(.066,.045),l(.078,.011),l(.067,-.022),l(.089,.034),l(.135,.011),l(.033,-.056),l(-.012,-.078),l(-.134,0),l(-.122,-.011),l(-.09,-.078),l(-.101,0),l(-.122,0),l(-.123,-.1),l(-.033,-.078),l(-.168,.022),l(-.066,-.111),l(.044,-.022),l(.045,-.034),l(-.033,-.1),l(.022,-.078),l(.056,.022),l(.078,-.011),l(-.045,-.089),l(-.101,-.034),l(-.145,.034),l(-.078,-.067),l(.011,-.146),l(.078,-.056),l(-.011,-.067),l(-.045,-.044),l(.022,-.078),l(-.022,-.112),l(-.056,-.089),l(-.201,-.142),l(1.535,-.529),l(.889,-.077),l(.907,.067),l(.054,.309),l(.569,.178),l(.19,.237),l(.202,.036),l(-.075,.356),l(.104,.119),l(-.058,.088),l(.712,.471),l(.555,.141),l(.306,.118),l(.069,.142),l(-.19,.127),l(-.124,.146),l(.183,.059),l(.239,.083),l(-.271,.071),l(-.178,.094),l(.052,.165),l(.245,.036),l(.234,0),l(.02,.189),l(.594,.059),l(.194,.139),l(.414,.239),l(.147,-.118),l(.215,-.283),l(.253,-.13),l(.625,.248),l(.114,.13),l(-.351,-.012),l(-.32,.201),l(.146,.33),l(.418,.186), +N(551.198,117.997),l(-.351,-.48),l(-.236,-.126),l(-1.217,-.05),l(-.646,-.011),l(-.096,-.016),l(.091,-.726),l(-.062,-.503),l(.157,-.251),l(.062,-.22),l(-.503,-.094),l(-.534,-.283),l(-.566,-.189),l(-.471,.063),l(-.378,-.251),l(-1.132,-.597),l(-.565,-.22),l(-.943,-.597),l(-.314,.063),l(-1.006,-.503),l(-.377,-.44),l(-1.194,-.597),l(-1.384,-.975),l(0,-.283),l(-.188,-.44),l(-.283,-.188),l(-.408,-.597),l(-.126,-.566),l(-.22,-.377),l(-.881,-.251),l(-.188,.157),l(-.439,.063),l(-.535,-.126),l(-.439,.032),l(-.503,.094),l(-.314,-.157),l(-.691,-.314),l(.094,-.22),l(.157,-.188),l(-.188,-.22),l(.031,-.188),l(.188,-.157),l(-.439,-.283),l(0,-.22),l(-.032,-.22),l(-.251,-.22),l(-.534,-.094),l(-.692,-.095),l(-.22,-.314),l(-.346,-.032),l(-.629,-.377),l(-.472,-.095),l(-.188,.063),l(-.565,.157),l(.251,.251),l(.188,.377),l(-.597,-.283),l(-.283,0),l(-.126,.126),l(-.22,.346),l(-.283,.126),l(-.629,0),l(-.503,.251),l(-.503,.409),l(-.062,.628),l(.314,.409),l(-.126,.314),l(-1.383,.032),l(-1.03,-.063),l(.056,-8.174),l(5.658,-1.289),l(5.722,2.986),l(2.012,1.666),l(2.578,-.346),l(2.767,.188),l(1.1,-.409),l(.724,.723),l(.597,.22),l(.66,1.006),l(.66,-.314),l(-.031,1.038),l(-.188,.409),l(.031,.754),l(1.006,0),l(.221,.817),l(.346,1.069),l(.503,.063),l(.691,-.032),l(1.006,-.094),l(.346,0),l(.44,.314),l(.062,.283),l(-.062,.283),l(.44,.346),l(.66,0),l(.125,-.188),l(-.157,-.409),l(.504,-.44),l(.439,-.188),l(.221,-.472),l(.282,-.188),l(.943,-.377),l(.755,-.189),l(.534,-.471),l(.346,-.283),l(.22,-.063),l(.283,.126),l(.377,-.377),l(.322,-.031),l(.349,-.126),l(.441,.246),l(-.368,.172),l(-.368,.171),l(-.221,.049),l(-.073,.196),l(-.295,.049),l(-.294,.172),l(-.196,.147),l(-.441,.295),l(-.172,.098),l(-.024,.123),l(.294,.049),l(.295,.074),l(.146,.123),l(.418,-.147),l(.098,.221),l(.172,.221),l(.368,.27),l(.589,0),l(.393,0),l(.049,-.393),l(.221,.049),l(.196,-.196),l(.024,-.245),l(.196,.098),l(.196,.172),l(.172,.294),l(.049,.147),l(.393,.024),l(.147,-.024),l(.073,.246),l(.025,.098),l(.343,-.025),l(.319,.147),l(.245,.196),l(.516,.074),l(.466,.024),l(.172,.123),l(-.49,.221),l(-.197,.147),l(-.221,.147),l(-.49,-.024),l(-.245,-.049),l(.049,.171),l(0,.147),l(-.319,0),l(-.172,.049),l(-.343,.196),l(-.221,.196),l(-.271,.049),l(-.221,.196),l(-.245,-.147),l(-.319,-.098),l(-.294,-.098),l(-.221,.025),l(-.246,.073),l(-.318,-.073),l(-.042,.098),l(-.345,-.005),l(-.409,.031),l(-.188,-.283),l(-.251,-.063),l(-.126,-.188),l(.251,-.126),l(.409,-.346),l(.188,-.22),l(-.252,-.251),l(-.439,-.377),l(-.221,.251),l(-.471,.346),l(-.692,.188),l(-.22,.157),l(-.252,-.22),l(-.22,-.157),l(-.346,0),l(.031,.22),l(-.283,.314),l(.189,.314),l(-.032,.346),l(-.062,.126),l(-.472,-.095),l(-.565,.095),l(-.503,.094),l(.251,.125),l(.534,-.031),l(.126,.094),l(-.251,.063),l(-.188,.063),l(-.032,.346),l(-.188,0),l(-.251,.157),l(-.063,.409),l(-.282,.188),l(-1.069,-.094),l(-.629,-.126),l(-.472,.283),l(-.125,.471),l(.251,.283),l(.346,.188),l(.157,.157),l(.44,.032),l(.346,0),l(.126,.22),l(-.126,.22),l(-.031,.472),l(.126,.409),l(.471,.314),l(.126,.283),l(-.157,.22),l(-.503,.346),l(-.283,.503),l(-.377,.377),l(.063,.377),l(-.375,.843), +N(439.792,104.833),l(-.113,-.054),l(-.105,-.07),l(.284,-.083),l(-.067,-.212),l(-.245,-.123),l(-.146,-.112),l(-.189,-.167),l(-.201,-.078),l(-.078,-.279),l(0,-.112),l(-.101,-.056),l(-.223,-.067),l(-.224,-.123),l(-.379,-.357),l(-.213,-.078),l(-.078,-.044),l(-.021,-.167),l(-.369,-.357),l(-.167,-.033),l(-.167,-.045),l(-.112,-.111),l(-.056,-.123),l(-.089,-.111),l(-.168,.011),l(-.022,-.146),l(.012,-.1),l(.078,-.056),l(-.156,-.111),l(-.022,-.123),l(-.089,-.134),l(-.146,-.234),l(-.179,-.179),l(-.101,-.033),l(-.122,-.034),l(-.09,-.089),l(-.134,-.078),l(-.022,-.089),l(.123,-.067),l(-.033,-.212),l(0,-.078),l(-.045,-.134),l(.045,-.167),l(.089,-.179),l(.123,-.044),l(.312,.034),l(.101,.111),l(.156,.19),l(.256,.134),l(.201,.022),l(.123,-.201),l(.145,-.145),l(.101,-.111),l(.212,-.022),l(.168,.033),l(.223,.022),l(.112,.011),l(.134,-.123),l(.089,.011),l(.134,.045),l(.156,.056),l(.234,.078),l(.057,.056),l(.111,-.022),l(.089,-.078),l(.156,.089),l(.168,.011),l(.189,.056),l(.156,-.011),l(.179,-.011),l(.268,.089),l(.156,.067),l(.168,-.078),l(.122,-.089),l(.112,0),l(.111,.067),l(.134,.045),l(.134,-.045),l(.111,-.067),l(.156,.045),l(.146,0),l(.067,.022),l(.156,.078),l(.1,.011),l(.101,-.089),l(.146,.045),l(.145,.056),l(.022,.112),l(.123,.011),l(.045,.089),l(-.056,.101),l(.145,.123),l(.201,.022),l(.189,-.022),l(.078,-.011),l(.212,-.112),l(.156,0),l(.179,.011),l(.123,.022),l(.022,.067),l(-.056,.1),l(-.034,.167),l(-.156,.223),l(-.156,.156),l(-.066,.078),l(-.056,.056),l(.033,.1),l(0,.089),l(-.078,.067),l(.022,.134),l(.078,.1),l(.167,.056),l(.212,-.011),l(.045,.1),l(.033,.101),l(.156,.089),l(.123,.078),l(.089,.089),l(.135,.022),l(.089,.044),l(-.067,.078),l(-.089,.056),l(-.134,.078),l(-.224,-.044),l(-.145,-.056),l(-.101,-.011),l(-.101,-.022),l(.101,.145),l(.212,.134),l(.179,.19),l(.134,.145),l(-.011,.19),l(-.012,.134),l(-.045,.022),l(-.1,-.022),l(-.078,-.044),l(-.067,-.034),l(-.078,.011),l(-.089,.111),l(-.179,.101),l(-.056,-.033),l(-.156,.056),l(-.112,-.022),l(-.066,-.044),l(-.112,.033),l(-.078,.056),l(.012,.078),l(.089,.1),l(.123,.167),l(.056,.101),l(-.056,.101),l(-.111,0),l(-.09,-.056),l(-.056,-.089),l(-.056,-.044),l(-.123,-.011),l(-.122,.056),l(-.168,.078),l(-.045,.101),l(-.044,.089),l(-.112,.101),l(.034,.089),l(.011,.1),L(442,104.458),l(-.134,.011),l(-.111,.022),l(-.101,.089),l(-.012,.134),l(.012,.112),l(.011,.145),l(.012,.044),l(.066,.112),l(.078,.089),l(.045,.101),l(-.09,.089),l(-.183,.108),l(-.062,-.063),l(-.089,-.034),l(-.123,-.022),l(-.134,.033),l(-.045,-.067),l(-.312,-.257),l(-.212,-.011),l(-.179,-.078),l(-.146,-.089),l(-.066,-.089),l(-.045,-.078),l(-.123,-.034),l(-.134,-.011),l(-.132,.118), +N(450.198,105.998),l(.013,-.208),l(.008,-.514),l(.246,-.301),l(.762,-.333),l(.302,-.302),l(-.028,-.2),l(-1.326,-1.122),l(-.056,-.271),l(.18,-.302),l(.383,-.374),l(.328,-.346),l(.392,.204),l(.352,.106),l(-.234,.318),l(.048,.189),l(.266,-.023),l(.771,-.189),l(.506,.002),l(1.151,.395),l(.34,-.031),l(.69,-.261),l(.3,.013),l(1.385,.35),l(.38,-.059),l(1.904,-.771),l(.618,-.218),l(.562,.04),l(.671,.369),l(.295,.042),l(.514,.226),l(1.346,.336),l(.671,.12),l(-.066,.335),l(-.077,.258),l(-.261,.086),l(-.313,-.028),l(-.339,.129),l(-.327,.73),l(-.039,.586),l(-.075,.143),l(-.404,.115),l(-.338,.372),l(-.017,.257),l(.252,-.036),l(.255,.224),l(.033,.154),l(.391,.375),l(.01,.223),l(-1.333,-.005),l(-.527,-.111),l(-.497,.045),l(-.629,.374),l(-.498,.445),l(-.363,-.026),l(-.344,.216),l(.097,.327),l(-.086,.257),l(-1.117,.277),l(-.388,.031),l(-.619,-.21),l(-1.473,-.505),l(-.584,.06),l(-.799,.261),l(-1.855,.195),l(-.09,.029),l(-.047,-.199),l(.104,-.3),l(.006,-.499),l(-.225,-.469),l(-.358,-.383),l(-.666,-.296),l(-.134,-.213),l(.007,-.106), +N(381.009,107),l(-.121,-.278),l(.138,-.4),l(.343,-.5),l(-.358,-.471),l(-.304,-.428),l(-.514,-.07),l(-.164,-.1),l(-.053,-.329),l(.163,-.243),l(.409,-.272),l(.365,-.101),l(.563,-.03),l(.634,-.03),l(.133,-.172),l(.068,-.415),l(.535,-.273),l(.763,.042),l(1.078,.37),l(.763,.07),l(.756,-.087),l(.577,-.173),l(.508,-.144),l(.354,-.001),l(.629,.285),l(.694,.156),l(.939,.084),l(1.538,.04),l(.583,.027),l(.957,.141),l(.491,-.158),l(.419,-.229),l(.531,.027),l(.891,.47),l(.67,-.016),l(.335,.062),l(.472,.243),l(.469,-.03),l(.058,.122),l(-.205,.243),l(.094,.106),l(.15,.03),l(.112,-.106),l(1.088,.334),l(.15,-.061),l(.507,.395),l(.056,-.076),l(.262,.03),l(.131,-.076),l(.431,.152),l(.028,.038),l(.084,.114),l(.767,-.03),l(.037,.122),l(.337,-.061),l(.542,.015),l(-.017,-.319),l(.355,0),l(1.252,.304),l(.091,.213),l(.035,.289),l(.187,.076),l(.374,-.076),l(.206,-.03),l(.335,.091),l(.036,.152),l(.261,.015),l(.395,-.167),l(.427,.197),l(.485,.015),l(.039,-.136),l(.75,-.137),l(.334,.091),l(-.001,.088),l(-.001,.463),l(.156,.1),l(-.062,.485),l(-1.112,.528),l(-.95,.385),l(-.267,.328),l(-1.046,.198),l(-.664,.116),l(-.96,.301),l(-.323,.326),l(-.053,.2),l(.261,.128),l(-.088,.157),l(-.628,.143),l(-.594,.783),l(-.886,.787),l(-.096,.192),l(-.18,.361),l(-.245,.45),l(.353,.827),l(.072,.111),l(.084,.13),l(.648,.295),l(.103,.185),l(-.621,.327),l(-.215,.105),l(-.515,.252),l(-.286,.479),l(-.224,.085),l(-.461,.926),l(.155,.322),l(-.257,.099),l(-.992,.049),l(-.581,.242),l(-.425,.327),l(-.274,.757),l(-.663,.496),l(-.258,-.213),l(-.599,.028),l(-.305,.27),l(-.342,0),l(-.121,-.113),l(-3.282,.042),l(-.69,.524),l(-1.021,.17),l(-.35,.382),l(-.028,.283),l(-.083,.085),l(-.073,-.212),l(-.068,-.014),l(.005,.241),l(-.389,.127),l(-.421,-.142),l(-.788,-.467),l(-.224,-.382),l(.036,-.262),l(-.345,-.113),l(-.125,-.213),l(.175,-.163),l(-.468,-.51),l(-.702,-.284),L(385,117.498),l(-.484,-.135),l(-.586,.039),l(.008,-.018),l(.304,-.951),l(.242,-.37),l(.884,-.643),l(-.408,-.31),l(-.812,-.123),l(.17,-.455),l(.506,-.655),l(.347,-.371),l(-.163,-.198),l(-.455,-.551),l(-.488,-.494),l(.288,-.129),l(.482,-.045),l(.458,-.229),l(.043,-.199),l(-.057,-.938),l(.132,-.983),l(-.072,-.456),l(.051,-.442),l(.084,-.072),l(1.234,-.506),l(.288,-.216),l(-.062,-.242),l(-.842,-.495),l(-.15,-.242),l(-.272,-.227),l(-.335,-.055),l(-.531,.26),L(382.981,107),l(-.531,-.439),l(-.55,.188),L(381.009,107), +N(489.685,103.693),l(.112,-.309),l(.26,-.166),l(.284,.047),l(.07,.047),l(.402,.023),l(.449,.023),l(.283,.095),l(.284,.142),l(.188,.094),l(.189,.047),l(.331,0),l(.213,0),l(.212,.166),l(.261,.095),l(.307,.071),l(.355,.047),l(.307,0),l(.426,-.095),l(.544,0),l(.401,.166),l(.189,0),l(.283,-.047),l(.354,.166),l(.095,.142),l(.284,.213),l(.52,.118),l(.354,.071),l(.236,.118),l(.308,.119),l(-.142,.118),l(-.048,.118),l(.261,.118),l(.212,.071),l(.261,-.118),l(.283,0),l(.166,-.166),l(.094,-.095),l(.213,-.071),l(.354,0),l(.261,.071),l(.188,.142),l(.142,-.166),l(.095,-.071),l(.118,0),l(.236,.118),l(.143,.094),l(.212,0),l(.189,.118),l(.213,.166),l(.378,0),l(.354,.024),l(.118,.142),l(-.118,.189),l(-.118,.307),l(.354,.284),l(.284,.166),l(.26,.094),l(.284,.047),l(.236,-.023),l(.236,.071),l(.126,.189),l(-.268,.189),l(-.143,.142),l(-.095,.071),l(.143,.26),l(.213,.307),l(.614,.166),l(.118,.213),l(-.095,.331),l(-.236,.095),l(-.236,.047),l(-.26,-.189),l(-.143,-.071),l(-.188,-.023),l(-.284,.047),l(-.638,-.189),l(-.189,-.213),l(-.331,-.189),l(-.473,-.024),l(-.236,0),l(-.418,.308),l(-.291,.094),l(-.378,.047),l(-.591,.095),l(-.592,-.047),l(-.401,.118),l(-.426,.023),l(-.308,.095),l(-.307,-.024),l(-.377,.108),l(-.031,-.028),l(-1.326,-1.018),l(-.41,-.041),l(-.761,.36),l(-.226,.072),l(-.491,-.068),l(-1.212,-.082),l(.083,-.065),l(.322,-.585),l(.032,-.143),l(-.064,-.728),l(-.331,-1.084),l(-.206,-.399),l(-.639,-.513),l(-.341,-.128),l(-.916,-.155),l(-.679,-.271),l(-.341,-.243), +N(443.617,107.095),l(-.065,-.035),l(-.435,-.156),l(-.017,-.15),l(-.501,-.485),l(-.848,-.3),l(-.033,-.021),l(.002,-.1),l(-.029,-.092),l(-.082,-.072),l(-.033,-.078),l(.022,-.089),l(-.005,-.004),l(.183,-.108),l(.09,-.089),l(-.045,-.101),l(-.078,-.089),l(-.066,-.112),l(-.012,-.044),l(-.011,-.145),l(-.012,-.112),l(.012,-.134),l(.101,-.089),l(.111,-.022),l(.134,-.011),l(.056,-.056),l(-.011,-.1),l(-.034,-.089),l(.112,-.101),l(.044,-.089),l(.045,-.101),l(.168,-.078),l(.122,-.056),l(.123,.011),l(.056,.044),l(.056,.089),l(.09,.056),l(.111,0),l(.056,-.101),l(-.056,-.101),l(-.123,-.167),l(-.089,-.1),l(-.012,-.078),l(.078,-.056),l(.112,-.033),l(.066,.044),l(.112,.022),l(.156,-.056),l(.056,.033),l(0,.101),l(.223,.056),l(.156,.101),l(.168,.078),l(.111,.111),l(.101,.146),l(.167,.134),l(.056,.033),l(.078,.022),l(.279,.078),l(.101,.056),l(.078,.011),l(.067,-.044),l(.066,.022),l(.078,.1),l(.123,.101),l(.033,.067),l(.078,.045),l(.111,-.022),l(.057,.044),l(.134,.045),l(.167,.067),l(.101,.101),l(.011,.089),l(-.089,.011),l(-.134,.022),l(-.09,.044),l(-.021,.067),l(-.057,.033),l(-.167,-.033),l(-.146,-.011),l(-.111,.033),l(-.022,.089),l(.056,.056),l(.101,0),l(.078,.067),l(0,.067),l(-.109,.286),l(-.361,-.022),l(-.727,-.11),l(-.273,.273),l(-.279,.515),l(.133,.427),l(-.002,.342), +N(558.52,110.652),l(.042,-.098),l(.318,.073),l(.246,-.073),l(.221,-.025),l(.294,.098),l(.319,.098),l(.245,.147),l(.221,-.196),l(.271,-.049),l(.221,-.196),l(.343,-.196),l(.172,-.049),l(.319,0),l(0,-.147),l(-.049,-.171),l(.245,.049),l(.49,.024),l(.221,-.147),l(.197,-.147),l(.49,-.221),l(-.172,-.123),l(-.466,-.024),l(-.516,-.074),l(-.245,-.196),l(-.319,-.147),l(-.343,.025),l(-.025,-.098),l(-.073,-.246),l(-.147,.024),l(-.393,-.024),l(-.049,-.147),l(-.172,-.294),l(-.196,-.172),l(-.196,-.098),l(-.024,.245),l(-.196,.196),l(-.221,-.049),l(-.049,.393),l(-.393,0),l(-.589,0),l(-.368,-.27),l(-.172,-.221),l(-.098,-.221),l(-.418,.147),l(-.146,-.123),l(-.295,-.074),l(-.294,-.049),l(.024,-.123),l(.172,-.098),l(.441,-.295),l(.196,-.147),l(.294,-.172),l(.295,-.049),l(.073,-.196),l(.221,-.049),l(.368,-.171),l(.368,-.172),l(-.441,-.246),l(-.349,.126),l(-.044,-.273),l(.393,-.442),l(.318,-.368),l(.736,-.123),l(.663,-.098),l(.883,.147),l(.883,.245),l(.688,.196),l(.81,.123),l(.344,.123),l(-.024,-.442),l(.245,-.736),l(.466,-.368),l(.688,-.123),l(.589,.074),l(.761,.27),l(.735,.246),l(.908,.196),l(.54,.098),l(.441,-.27),l(.858,-.024),l(.761,0),l(.785,-.147),l(.712,.221),l(.662,.098),l(1.35,.024),l(.662,-.074),l(.981,.246),l(.564,-.049),l(.147,.344),l(.27,.147),l(.196,.27),l(.663,0),l(.466,.098),l(.41,.375),l(.031,.194),l(-.051,.157),l(-.325,.187),l(-.97,.219),l(-1.338,.349),l(-.445,.145),l(-.405,.301),l(-.638,.701),l(-.646,.345),l(-.478,.102),l(-.459,.017),l(-1.248,-.235),l(-.238,.03),l(-.467,.472),l(-.463,.784),l(-.268,.243),l(-.885,.132),l(-.507,.145),l(-.344,-.055),l(-.183,-.567),l(-.06,-.071),l(-.359,.03),l(-1.737,.734),l(-1.422,.704),l(-.274,.186),l(-.129,.213),l(-.139,.739),l(-.196,-.073),l(-.344,.098),l(-.344,.171),l(-.539,0),l(-.663,-.073),l(-.834,.221),l(-.172,.147),l(-.196,0),l(-.172,-.319),l(-.368,.024),l(-.318,.172),l(-.074,-.221),l(-.049,-.172),l(-.122,.024),l(-.319,-.123),l(-.049,-.147),l(-.221,-.024),l(-.442,.123),l(-.343,.049),l(.024,.221),l(-.295,.049),l(-.393,-.074),l(-.073,-.196),l(-.147,-.123),l(-.368,-.098),l(-.49,.147),l(-.196,-.073),l(-.688,.024),l(-.564,0),l(-.589,.024),l(-.122,-.098),l(-.049,-.147),l(-.099,-.27),l(.099,-.245),l(.196,-.196),l(.098,.221),l(.196,-.074),l(-.049,-.196),l(.098,-.27),l(.123,0),l(.981,-.196),l(.515,.147),l(.516,.196),l(.099,.172),l(.196,0),l(.024,-.246),l(.441,-.196),l(.302,-.147), +N(685.343,114.455),l(-.571,.678),l(-.309,.115),l(-.511,-.096),l(-.579,-.068),l(-.595,-.011),l(-.315,.157),l(-.633,.738),l(-.283,.256),l(-.235,.171),l(-.268,-.206),l(-.35,.34),l(-.319,.199),l(-.373,-.608),l(-.398,-.112),l(-.649,.78),l(-.195,-.382),l(-.232,-.254),l(-.683,-.367),l(-.169,-.453),l(.095,-.312),l(.429,-.411),l(.754,-.229),l(.056,-.269),l(-.591,-.282),l(.407,-.879),l(.189,-.34),l(-.199,-.269),l(-.632,-.296),l(-.139,0),l(-.381,.029),l(-.312,.143),l(-.234,-.07),l(-.52,-.368),l(-.167,-.233),l(.379,-.528),l(.415,-.442),l(.52,-.329),l(1.533,-.604),l(1.032,-.545),l(.636,-.543),l(.686,-1.027),l(.386,-.13),l(.448,-.017),l(.273,.396),l(.493,.253),l(.508,.153),l(.975,-.048),l(.527,-.159),l(-.046,-.113),l(-.508,-.765),l(.025,-.342),l(.273,-.243),l(.392,-.059),l(.333,.126),l(.452,.054),l(.538,-.017),l(.62,-.259),l(.955,-.532),l(.23,-.713),l(.383,-.358),l(.253,-.129),l(.247,-.001),l(.579,.68),l(.298,.439),l(.167,.393),l(-1.356,.923),l(-.408,.457),l(-.112,.414),l(.09,.427),l(-.154,.456),l(-.187,.868),l(-.668,.115),l(-.36,.229),l(-.497,.385),l(-.766,.641),l(-.468,.214),l(-.678,.03),l(-.577,.199),l(-.265,.228),l(-.248,.312),l(-.364,.893),l(.284,.326),l(1.225,.847),l(.419,.354), +N(536.625,121.017),l(-.078,-.028),l(-.15,-.692),l(-.01,-.565),l(-.038,-.848),l(-.185,-.211),l(-.787,.075),l(-.696,-.01),l(-.655,-.506),l(-1.803,-1.362),l(-.597,-.336),l(-.66,-.167),l(-.5,-.054),l(-.788,-.066),l(-.822,-.335),l(-.708,-.251),l(-.402,-.437),l(-1.055,-.107),l(-.519,-.054),l(-.343,.129),l(-.517,.343),l(-.333,.03),l(-.78,-.038),l(-.609,.032),l(-.413,.144),l(-.476,.328),l(-.621,.654),l(-.466,.3),l(-.562,.13),l(-.441,-.025),l(-.066,-.376),l(-.128,-.681),l(-.106,-.447),l(.128,-.298),l(0,-.383),l(0,-.532),l(.106,-.191),l(.106,-.298),l(.085,-.234),l(-.085,-.212),l(-.256,-.128),l(-.319,-.191),l(-.213,-.255),l(-.042,-.149),l(-.171,0),l(-.191,-.042),l(-.361,-.106),l(-.191,.192),l(-.086,-.234),l(.086,-.106),l(.148,-.255),l(.128,.106),l(.383,-.042),l(.426,.085),l(.128,.021),l(.043,-.128),l(-.319,-.213),l(-.256,-.021),l(-.085,-.277),l(.17,-.255),l(.213,-.191),l(-.404,-.042),l(-.319,.085),l(-.383,0),l(-.319,-.085),l(-.128,.149),l(-.17,-.255),l(-.149,-.298),l(0,-.34),l(-.042,-.298),l(.17,-.213),l(.106,-.319),l(.043,-.255),l(.105,-.277),l(.086,-.234),l(.213,.34),l(.063,.128),l(.17,.17),l(.405,-.085),l(.383,.128),l(.106,-.149),l(-.021,-.149),l(.106,0),l(.148,.021),l(.064,.319),l(.106,.191),l(.298,-.021),l(.298,-.063),l(.256,-.106),l(.233,.085),l(.192,.064),l(.085,-.128),l(-.149,-.191),l(-.042,-.213),l(.191,-.042),l(.106,.149),l(.233,.085),l(.256,-.085),l(.213,-.064),l(.021,-.234),l(-.171,-.341),l(-.34,-.234),l(-.532,-.319),l(-.426,-.213),l(-.063,-.319),l(-.043,-.34),l(-.213,-.17),l(0,-.213),l(0,-.213),l(-.085,-.127),l(-.554,-.064),l(-.617,.085),l(-.426,.021),l(-.446,.127),l(-.192,.277),l(-.085,.298),l(.128,.192),l(-.063,.276),l(-.086,.405),l(.064,.234),l(.021,.298),l(-.256,-.553),l(-.361,-.319),l(.042,-.17),l(-.063,-.191),l(-.274,-.143),l(.529,-.453),l(.937,-.532),l(1.277,-.298),l(.979,-.085),l(.512,.234),l(.681,.383),l(.617,.383),l(.256,.511),l(.638,.703),l(.447,.255),l(.489,-.043),l(.341,-.106),l(.158,.014),l(1.03,.063),l(1.383,-.032),l(.126,-.314),l(-.314,-.409),l(.062,-.628),l(.503,-.409),l(.503,-.251),l(.629,0),l(.283,-.126),l(.22,-.346),l(.126,-.126),l(.283,0),l(.597,.283),l(-.188,-.377),l(-.251,-.251),l(.565,-.157),l(.188,-.063),l(.472,.095),l(.629,.377),l(.346,.032),l(.22,.314),l(.692,.095),l(.534,.094),l(.251,.22),l(.032,.22),l(0,.22),l(.439,.283),l(-.188,.157),l(-.031,.188),l(.188,.22),l(-.157,.188),l(-.094,.22),l(.691,.314),l(.314,.157),l(.503,-.094),l(.439,-.032),l(.535,.126),l(.439,-.063),l(.188,-.157),l(.881,.251),l(.22,.377),l(.126,.566),l(.408,.597),l(.283,.188),l(.188,.44),l(0,.283),l(1.384,.975),l(1.194,.597),l(.377,.44),l(1.006,.503),l(.314,-.063),l(.943,.597),l(.565,.22),l(1.132,.597),l(.378,.251),l(.471,-.063),l(.566,.189),l(.534,.283),l(.503,.094),l(-.062,.22),l(-.157,.251),l(.062,.503),l(-.091,.726),l(-1.454,-.244),l(-.565,-.294),l(-.445,.356),l(-.417,.2),l(-1.135,.205),l(-.432,.809),l(-.203,.991),l(-.103,.128),l(-.508,.243),l(-1.985,.689),l(-.568,.159),l(-.119,.199),l(-.001,.466),l(-.22,.199),l(-.636,.3),l(-.534,.031),l(-.573,-.082),l(-.999,-.348),l(-.937,-.193),l(-.193,-.112), +N(445.294,112.196),l(-.07,-.115),l(-.138,-.469),l(-.5,-.452),l(-.966,-.541),l(.024,-.141),l(.23,.062),l(.023,-.237),l(-.345,-.414),l(.418,-.616),l(-.182,-.22),l(.188,-.563),l(-.251,-.282),l(.182,-.396),l(.268,-.079),l(-.027,-.45),l(-.331,-.081),l(-.2,-.107),l(.002,-.342),l(-.133,-.427),l(.279,-.515),l(.273,-.273),l(.727,.11),l(.361,.022),l(.058,.004),l(.382,.369),l(.733,.866),l(.018,.109),l(.035,.218),l(-.132,.429),l(.074,.641),l(.298,.668),l(.722,.608),l(-.09,.029),l(-.449,.842),l(-.402,.386),l(-.496,.472),l(-.583,.884), +N(451.512,108.463),l(-.507,.16),l(-.532,.245),l(-.622,-.054),l(-.361,-.041),l(-.365,.159),l(-.395,.429),l(-.606,.146),l(-.809,.076),l(-.722,-.608),l(-.298,-.668),l(-.074,-.641),l(.132,-.429),l(-.035,-.218),l(.14,.049),l(.188,0),l(.072,-.087),l(.029,-.072),l(-.029,-.13),l(.058,-.167),l(.088,-.058),l(.225,-.058),l(.246,-.058),l(.116,-.058),l(.08,-.065),l(.087,.073),l(.131,.058),l(.094,.109),l(.116,0),l(.029,-.058),l(-.059,-.072),l(.109,-.058),l(.151,-.102),l(.152,-.087),l(.175,.043),l(.064,-.007),l(.196,.007),l(.152,.015),l(.087,-.08),l(.131,-.116),l(.064,.021),l(.102,.043),l(.088,-.021),l(.087,-.043),l(.102,.051),l(.058,-.015),l(.116,-.022),l(.145,-.021),l(.16,-.022),l(.072,-.029),l(.058,.017),l(-.007,.106),l(.134,.213),l(.666,.296),l(.358,.383),l(.225,.469),l(-.006,.499),l(-.104,.3),l(.047,.199), +N(383.93,117.402),l(-.249,.101),l(-.517,.291),l(-.439,.052),l(-.548,-.178),l(-.58,0),l(-.28,-.073),l(-.719,.292),l(-.058,-.177),l(.389,-1.012),l(-.021,-.856),l(-.182,-.115),l(.244,-.542),l(-.054,-.397),l(.13,-.114),l(-.144,-.141),l(-.375,.085),l(-.476,.097),l(-.108,-.449),l(.48,-.052),l(.283,-.22),l(-.042,-.17),l(-.178,-.226),l(-.3,.417),l(-.413,.136),l(-.357,-.042),l(-.059,-.188),l(.198,-.397),l(.138,-.616),l(-.039,-.303),l(.258,-.114),l(.403,-.503),l(.45,-1.098),l(-.12,-.115),l(.612,-1.783),l(-.35,-.924),l(-.007,-.42),l(-.146,-.378),l(.255,-.271),l(.891,-.251),l(.55,-.188),l(.531,.439),l(1.822,.047),l(.531,-.26),l(.335,.055),l(.272,.227),l(.15,.242),l(.842,.495),l(.062,.242),l(-.288,.216),l(-1.234,.506),l(-.084,.072),l(-.051,.442),l(.072,.456),l(-.132,.983),l(.057,.938),l(-.043,.199),l(-.458,.229),l(-.482,.045),l(-.288,.129),l(.488,.494),l(.455,.551),l(.163,.198),l(-.347,.371),l(-.506,.655),l(-.17,.455),l(.812,.123),l(.408,.31),l(-.884,.643),l(-.242,.37),l(-.304,.951),l(-.008,.018), +N(500.121,117.572),l(-.407,-.016),l(-.433,.388),l(-.164,.126),l(-.318,-.105),l(-.102,-.269),l(.03,-.259),l(-.274,-.151),l(-.366,-.082),l(-.244,.234),l(-.343,-.023),l(-.811,-.153),l(-.364,.032),l(-.304,-.16),l(-.437,.094),l(-.266,.143),l(-.23,.043),l(-.064,-.245),l(-.207,-.023),l(-.24,.292),l(-.693,.304),l(-1.185,.224),l(-.711,-.039),l(-.747,-.123),l(-.439,.073),l(-1.498,.673),l(-.567,.13),l(-1.104,.176),l(-.556,-.153),l(-1.532,-.444),l(-.278,.03),l(-.929,.373),l(-.746,.075),l(-.575,-.025),l(-.777,-.166),l(-.222,.001),l(-.142,-.035),l(-.055,.319),l(.102,.452),l(.243,.423),l(-.627,.127),l(-.156,.374),l(-.2,.169),l(-.171,-.041),l(-.114,.127),l(-.39,-.125),l(-.311,.001),l(-.245,-.459),l(-.119,-.093),l(.097,-.175),l(.242,-.197),l(.617,-.403),l(.021,-.175),l(-.049,-.134),l(-.279,-.28),l(-.146,-.053),l(-.487,.368),l(-.23,.041),l(-.137,.064),l(.092,.041),l(-.118,.216),l(-.172,.023),l(-.063,-.047),l(-.076,.088),l(-.297,.058),l(-.332,-.222),l(-.447,-.198),l(-.461,-.157),l(-.395,.046),l(-.849,.548),l(-.337,.286),l(.006,.204),l(-.141,.046),l(-.122,.07),l(-.005,.082),l(-.179,-.169),l(-.604,.206),l(-.689,.185),l(-.594,-.013),l(-.587,-.07),l(-.678,-.267),l(-.963,-.819),l(-1.181,-.479),l(-1.034,-.182),l(-.692,.072),l(-.119,.255),l(-.097,.609),l(-.053,.411),l(-.173,.156),l(-.256,0),l(-.253,-.155),l(-1.12,.243),l(-.423,-.027),l(-.386,-.183),l(-.657,-1.159),l(-.42,.354),l(-.764,-.451),l(-.451,.057),l(-.562,.412),l(-.227,-.382),l(.066,-.127),l(.242,-.17),l(-.116,-.17),l(-.989,-.012),l(-.545,-.013),l(-.088,-.269),l(.571,-.199),l(-.074,-.241),l(-.284,-.198),l(-.454,-.07),l(-.084,-.297),l(.041,-.34),l(.087,-.284),l(-.089,-.255),l(-.396,-.126),l(-.627,-.353),l(-.371,.086),l(-.265,-.084),l(-.004,-.255),l(.171,-.501),l(.131,.059),l(.478,.311),l(.567,-.271),l(-.396,-.283),l(.021,-.124),l(-.296,-.128),l(.03,-.128),l(.571,-.159),l(.152,-.113),l(-.068,-.142),l(-.149,-.088),l(-.337,-.035),l(.01,-.187),l(.18,-.07),l(-.163,-.164),l(-.198,-.117),l(-.009,-.152),l(-.227,-.012),l(.263,-.181),l(.296,-.275),l(.161,-.035),l(.07,-.16),l(-.341,-.042),l(-.573,.12),l(-.905,.164),l(-.166,-.035),l(.046,-.33),l(.127,-.125),l(-.003,-.199),l(-.029,-.286),l(.13,-.264),l(.299,.012),l(.184,-.41),l(.175,-.023),l(.63,-.422),l(.514,.012),l(.133,-.129),l(.479,-.047),l(.128,.211),l(.268,.102),l(.169,.028),l(.529,.022),l(.147,-.129),l(-.067,-.129),l(-.269,-.129),l(.286,-.094),l(.324,.036),l(.117,.082),l(-.219,.223),l(.213,-.026),l(1.053,-.073),l(.619,.042),l(.379,.046),l(.279,.047),l(.155,-.176),l(-.086,-.094),l(-.468,-.035),l(-.212,-.118),l(.275,-.212),l(1.386,-.151),l(.417,-.012),l(.377,-.117),l(-.442,-.012),l(-.592,.023),l(-.215,0),l(-.068,-.146),l(-.611,-.382),l(.325,-.528),l(.926,.14),l(1.244,.048),l(.264,-.117),l(1.086,.321),l(1.051,-.031),l(.414,-.243),l(-.041,-.27),l(.624,-.244),l(.455,-.214),l(1.218,-.573),l(.598,-.215),l(1.039,-.23),l(.889,-.073),l(.758,.07),l(.905,.126),l(.798,.041),l(.753,-.372),l(.216,.527),l(.416,.298),l(.278,.099),l(.592,.013),l(.622,-.144),l(.453,.74),l(.492,.255),l(.574,-.172),l(.391,.056),l(.968,.582),l(1.265,.04),l(1.094,.197),l(.749,-.001),l(1.084,-.272),l(.514,-.044),l(.651,.141),l(.764,.098),l(.787,-.016),l(.554,-.144),l(1.518,-.573),l(.424,-.335),l(1.212,.082),l(.491,.068),l(.226,-.072),l(.761,-.36),l(.41,.041),l(1.326,1.018),l(.031,.028),l(.795,.722),l(.026,.199),l(-.421,.813),l(.033,.412),l(.284,.211),l(1.413,.12),l(.492,.451),l(-.072,.211),l(-.409,-.023),l(-.231,.141),l(-.009,.433),l(-.584,.267),l(-.039,.27),l(.264,.67),l(-.122,.375),l(.224,.492),l(.09,.117),l(.106,-.105),l(.288,.203),l(.039,.207),l(-.229,.281),l(-.287,.535),l(-.06,.128),l(.213,.14),l(.424,.111),l(-.145,.245),l(.099,.421),l(.42,.374),l(.275,.035),l(.023,.308),M(462.617,106.804),l(.241,.211),l(-.019,.287),l(.115,.285),l(.077,.071),l(.593,.355),l(.819,.241),l(.605,.155),l(.152,.121),L(464.943,109),l(-.304,.166),l(-.515,-.072),l(-.94,-.246),l(-.326,.07),l(-.209,.152),l(-1.019,-.012),l(-.357,.384),l(-.109,.273),l(-.833,.316),l(-.612,.282),l(-.222,.258),l(-.307,.152),l(-.268,.293),l(-.255,.082),l(.164,-.258),l(.019,-.141),l(-.062,-.176),l(.584,-.293),l(.22,-.141),l(-.226,-.191),l(-.082,.015),l(-.653,-.056),l(-.229,-.148),l(.326,-.546),l(.387,-.558),l(.678,-.631),l(-.127,-.227),l(-.427,-.197),l(-.105,0),l(.498,-.445),l(.629,-.374),l(.497,-.045),l(.527,.111),l(1.333,.005), +N(509.077,114.955),l(-.72,-.317),l(-.268,.016),l(-.356,-.433),l(-.374,-.105),l(-.13,-.363),l(.532,-.27),l(.095,-.222),l(-.43,-.176),l(-.027,-.188),l(.63,-.129),l(.094,-.155),l(-.061,-.113),l(-.487,-.21),l(-.351,-.281),l(-.306,-.166),l(-.456,.234),l(-1.058,.492),l(-.374,.445),l(-.642,.188),l(-.254,.255),l(-.014,-.027),l(.094,-.118),l(-.094,-.213),l(-.189,-.071),l(.26,-.095),l(.166,-.047),l(-.261,-.189),l(-.236,-.236),l(.236,-.118),l(.095,-.189),l(-.283,-.047),l(-.354,-.024),l(-.284,-.118),l(-.213,-.212),l(-.236,-.024),l(-.26,-.354),l(-.283,-.142),l(-.048,-.094),l(.166,0),l(.378,0),l(.165,-.236),l(0,-.236),l(-.213,-.024),l(-.188,-.142),l(-.544,-.331),l(-.283,-.354),l(.047,-.284),l(.402,-.142),l(-.119,-.236),l(-.212,-.166),l(-.426,-.071),l(-.284,-.095),l(.071,-.094),l(.071,-.118),l(-.284,-.095),l(-.087,-.212),l(.418,-.308),l(.236,0),l(.473,.024),l(.331,.189),l(.189,.213),l(.638,.189),l(.284,-.047),l(.188,.023),l(.143,.071),l(.26,.189),l(.236,-.047),l(.236,-.095),l(.095,-.331),l(-.118,-.213),l(-.614,-.166),l(-.213,-.307),l(-.143,-.26),l(.095,-.071),l(.143,-.142),l(.268,-.189),l(.229,-.023),l(.023,.166),l(.213,-.047),l(.189,0),l(.142,.189),l(.473,.284),l(.095,.118),l(.118,0),l(.283,.284),l(0,.308),l(.591,.094),l(.449,.142),l(.379,-.047),l(.165,-.213),l(.308,-.331),l(.283,-.094),l(.496,-.284),l(.292,-.449),l(.465,.331),l(.236,.378),l(.26,.189),l(.284,.307),l(.095,.52),l(.142,.236),l(.283,.26),l(.284,.165),l(0,.166),l(.449,.236),l(.473,-.047),l(.378,.071),l(.284,.166),l(.236,.189),l(.095,.189),l(0,.142),l(-.355,-.142),l(-.401,-.047),l(-.213,0),l(-.26,.047),l(-.142,.118),l(-.402,.071),l(-.213,.142),l(-.047,.189),l(-.023,.473),l(-.118,.26),l(-.095,.236),l(-.095,.378),l(.213,.236),l(-.023,.189),l(-.237,-.071),l(-.094,.095),l(-.071,.331),l(-.071,.26),l(-.118,-.047),l(-.094,-.236),l(-.143,-.095),l(-.165,.095),l(-.047,.307),l(.07,.166),l(-.118,.118),l(-.118,.095),l(.095,.26),l(-.363,.91),M(499.844,111.738),l(.709,.061),l(.142,-.047),l(.26,-.071),l(.236,.236),l(.071,.166),l(.378,.142),l(.213,.071),l(.308,-.118),l(.52,0),l(-.071,.213),l(.024,.236),l(.118,.023),l(.331,.166),l(-.071,.236),l(.421,.763),l(-.009,.001),l(-.253,-.133),l(-.416,.038),l(-.512,-.025),l(-.421,-.125),l(-.335,-.211),l(-.294,-.402),l(-.551,-.223),l(-.281,-.417),l(-.265,-.381),l(-.252,-.197), +N(455.452,122.442),l(.049,-.209),l(-.057,-.128),l(-.812,-.256),l(-.691,-.006),l(-.506,-.116),l(-.484,.017),l(-.121,-.046),l(-.103,-.093),l(.139,-.56),l(.315,-.005),l(-.005,-.088),l(-.009,-.122),l(.069,-.07),l(.083,.157),l(.021,.146),l(.303,.021),l(.172,.055),l(.184,-.076),l(-.014,-.082),l(.108,-.029),l(.157,.105),l(-.037,.093),l(-.099,.006),l(-.04,.053),l(.088,.023),l(.144,.035),l(.094,.046),l(.021,.128),l(.353,.041),l(.846,-.122),l(.509,.016),l(.035,.13),l(.192,.035),l(.608,.064),l(.307,.051),l(.358,-.121),l(.09,.05),l(-.101,.312),l(.163,.11),l(.105,0),l(.325,-.169),l(.286,-.058),l(.078,.052),l(.154,-.07),l(.232,-.146),l(-.083,.187),l(.015,.186),l(-.183,.268),l(-.582,-.046),l(-.349,.081),l(-.335,-.017),l(-1.994,.169),M(445.294,112.196),l(.583,-.884),l(.496,-.472),l(.402,-.386),l(.449,-.842),l(.09,-.029),l(.809,-.076),l(.606,-.146),l(.395,-.429),l(.365,-.159),l(.361,.041),l(.622,.054),l(.532,-.245),l(.507,-.16),l(.09,-.029),l(1.855,-.195),l(.799,-.261),l(.584,-.06),l(1.473,.505),l(.619,.21),l(.388,-.031),l(1.117,-.277),l(.086,-.257),l(-.097,-.327),l(.344,-.216),l(.363,.026),l(.105,0),l(.427,.197),l(.127,.227),l(-.678,.631),l(-.387,.558),l(-.326,.546),l(-.062,-.407),l(-.794,-.056),l(-.743,-.041),l(-.566,-.125),l(-.062,-.144),l(-.459,.186),l(-.248,.123),l(-.403,.012),l(-.031,-.247),l(-.335,.029),l(-.301,.314),l(-.431,.186),l(-.31,.03),l(-.306,-.159),l(-.252,.07),l(-.004,.133),l(.169,.185),l(.169,.34),l(.308,.059),l(.826,.609),l(-.166,.07),l(-.369,-.258),l(-.015,-.105),l(-.276,-.082),l(-.331,-.105),l(-.116,.099),l(-.211,.007),l(.069,.129),l(-.016,.129),l(.338,.164),l(.145,-.012),l(.114,.234),l(-.03,.129),l(-.245,.023),l(-.445,-.457),l(-.341,-.141),l(-.207,-.059),l(-.128,-.012),l(.003,.094),l(-.075,.035),l(.138,.164),l(.102,.105),l(.154,.141),l(.193,.059),l(.153,.035),l(.103,.094),l(-.093,.058),l(-.494,-.046),l(-.253,-.035),l(.035,-.176),l(-.137,-.293),l(-.164,-.188),l(-.401,-.108),l(-.472,-.373),l(.258,-.118),l(.025,-.136),l(-.053,-.122),l(-.182,-.035),l(-.153,.199),l(-.465,.176),l(.245,.224),l(-.25,.371),l(-.05,.249),l(.13,.121),l(.065,.172),l(.311,.338),l(.133,.036),l(.131,.479),l(.579,.421),l(.359,.467),l(-.172,.14),l(-.237,.082),l(.106,-.187),l(-.121,-.187),l(-.142,-.128),l(-.139,-.035),l(-.151,-.047),l(-.29,.175),l(.102,.188),l(.153,.081),l(.08,.316),l(-.193,.187),l(-.652,.141),l(.248,.046),l(.27,.14),l(.391,.058),l(.188,.222),l(.257,-.012),l(.155,.012),l(.048,.126),l(.367,.269),l(.306,.014),l(.138,.292),l(.282,.012),l(.27,0),l(.348,.303),l(.015,.128),l(-.193,.082),l(.238,.782),l(-.153,.175),l(-.185,0),l(-.226,-.385),l(-.222,-.047),l(-.207,-.278),l(-.101,-.142),l(-.17,0),l(-.496,.14),l(-.479,.105),l(-.184,.128),l(.315,.093),l(.013,.188),l(.007,.291),l(.229,.117),l(.153,-.026),l(.225,-.079),l(-.021,.198),l(.235,.175),l(-.519,.093),l(.002,.117),l(-.169,.062),l(-.309,-.086),l(.121,-.21),l(-.186,-.086),l(-.508,-.056),l(-.158,-.092),l(-.008,.206),l(.194,.453),l(.193,.17),l(-.045,.163),l(.209,.204),l(.213,.96),l(-.688,-.31),l(-.331,.071),l(-.298,.439),l(-.442,-.735),l(-.46,-.367),l(-.452,.44),l(-.428,-.353),l(-.127,-.297),l(.212,-.425),l(-.028,-.241),l(-.215,-.269),l(-.491,-.424),l(-.167,-.226),l(.017,-.17),l(.471,-.61),l(.609,.098),l(.425,-.298),l(.202,.042),l(1.668,.663),l(.337,-.1),l(.483,-.355),l(-.266,-.049),l(-.27,-.056),l(-1.204,-.493),l(-1.127,-.083),l(-.367,.058),l(-.66,.058),l(-.427,.143),l(-.89,-1.118),l(.269,-.1),l(.253,.056),l(.218,-.114),l(.122,-.185),l(-.339,-.24),l(-.235,.114),l(-.496,-.042),l(-1.035,-.721),l(-.199,-.325), +N(504.136,113.458),l(-.327,.328),l(-.377,.03),l(-.421,-.763),l(.071,-.236),l(-.331,-.166),l(-.118,-.023),l(-.024,-.236),l(.071,-.213),l(-.52,0),l(-.308,.118),l(-.213,-.071),l(-.378,-.142),l(-.071,-.166),l(-.236,-.236),l(-.26,.071),l(-.142,.047),l(-.709,-.061),l(-.492,-.451),l(-1.413,-.12),l(-.284,-.211),l(-.033,-.412),l(.421,-.813),l(-.026,-.199),l(-.795,-.722),l(.377,-.108),l(.307,.024),l(.308,-.095),l(.426,-.023),l(.401,-.118),l(.592,.047),l(.591,-.095),l(.378,-.047),l(.291,-.094),l(.087,.212),l(.284,.095),l(-.071,.118),l(-.071,.094),l(.284,.095),l(.426,.071),l(.212,.166),l(.119,.236),l(-.402,.142),l(-.047,.284),l(.283,.354),l(.544,.331),l(.188,.142),l(.213,.024),l(0,.236),l(-.165,.236),l(-.378,0),l(-.166,0),l(.048,.094),l(.283,.142),l(.26,.354),l(.236,.024),l(.213,.212),l(.284,.118),l(.354,.024),l(.283,.047),l(-.095,.189),l(-.236,.118),l(.236,.236),l(.261,.189),l(-.166,.047),l(-.26,.095),l(.189,.071),l(.094,.213),l(-.094,.118),l(.014,.027), +N(566.651,117.4),l(-.565,-.153),l(-.496,-.054),l(-.264,-.151),l(-.564,.227),l(-.974,.147),l(-.137,-.059),l(.129,-.176),l(-.198,-.077),l(-.678,.03),l(-.739,.315),l(-.592,.486),l(-.589,.064),l(-.745,.495),l(-.351,.03),l(-.368,-.026),l(-.128,-.084),l(-.164,-.409),l(-.199,-.521),l(.185,-.444),l(.099,-.775),l(.029,-.255),l(-.17,-.187),l(-.484,.093),l(.156,-.597),l(-.576,-.45),l(-.153,-.056),l(-.384,.016),l(-.286,.162),l(-.134,.363),l(-.435,.428),l(-.049,.425),l(.006,.255),l(-.208,.228),l(-.442,.158),l(-.133,-.013),l(-.587,-.152),l(-.292,.058),l(-.073,.185),l(.007,.311),l(-.3,.313),l(-.21,.128),l(-.381,.016),l(-.63,-.237),l(-.325,.001),l(-.581,.286),l(-.58,.343),l(-.485,.144),l(-.245,-.041),l(-.129,-.141),l(-.04,-.055),l(.375,-.843),l(-.063,-.377),l(.377,-.377),l(.283,-.503),l(.503,-.346),l(.157,-.22),l(-.126,-.283),l(-.471,-.314),l(-.126,-.409),l(.031,-.472),l(.126,-.22),l(-.126,-.22),l(-.346,0),l(-.44,-.032),l(-.157,-.157),l(-.346,-.188),l(-.251,-.283),l(.125,-.471),l(.472,-.283),l(.629,.126),l(1.069,.094),l(.282,-.188),l(.063,-.409),l(.251,-.157),l(.188,0),l(.032,-.346),l(.188,-.063),l(.251,-.063),l(-.126,-.094),l(-.534,.031),l(-.251,-.125),l(.503,-.094),l(.565,-.095),l(.472,.095),l(.062,-.126),l(.032,-.346),l(-.189,-.314),l(.283,-.314),l(-.031,-.22),l(.346,0),l(.22,.157),l(.252,.22),l(.22,-.157),l(.692,-.188),l(.471,-.346),l(.221,-.251),l(.439,.377),l(.252,.251),l(-.188,.22),l(-.409,.346),l(-.251,.126),l(.126,.188),l(.251,.063),l(.188,.283),l(.409,-.031),l(.345,.005),l(-.302,.147),l(-.441,.196),l(-.024,.246),l(-.196,0),l(-.099,-.172),l(-.516,-.196),l(-.515,-.147),l(-.981,.196),l(-.123,0),l(-.098,.27),l(.049,.196),l(-.196,.074),l(-.098,-.221),l(-.196,.196),l(-.099,.245),l(.099,.27),l(.049,.147),l(.122,.098),l(.589,-.024),l(.564,0),l(.688,-.024),l(.196,.073),l(.49,-.147),l(.368,.098),l(.147,.123),l(.073,.196),l(.393,.074),l(.295,-.049),l(-.024,-.221),l(.343,-.049),l(.442,-.123),l(.221,.024),l(.049,.147),l(.319,.123),l(.122,-.024),l(.049,.172),l(.074,.221),l(.318,-.172),l(.368,-.024),l(.172,.319),l(.196,0),l(.172,-.147),l(.834,-.221),l(.663,.073),l(.539,0),l(.344,-.171),l(.344,-.098),l(.196,.073),l(-.011,.069),l(.023,1.031),l(-.207,.223),l(.077,.305),l(.325,.394),l(.463,-.045),l(.229,-.162),l(.22,.06),l(.692,.039),l(.273,.154),l(.295,.494),l(-.009,.284),l(.028,.246),l(.152,.012),l(.049,.123),l(-.126,.428),l(.245,.237),l(-.152,.36),l(.2,.163),l(-.181,.185),l(-.08,.249),l(-.354,.136), +N(500.121,117.572),l(-.023,-.308),l(-.275,-.035),l(-.42,-.374),l(-.099,-.421),l(.145,-.245),l(-.424,-.111),l(-.213,-.14),l(.06,-.128),l(.287,-.535),l(.229,-.281),l(-.039,-.207),l(-.288,-.203),l(-.106,.105),l(-.09,-.117),l(-.224,-.492),l(.122,-.375),l(-.264,-.67),l(.039,-.27),l(.584,-.267),l(.009,-.433),l(.231,-.141),l(.409,.023),l(.072,-.211),l(.252,.197),l(.265,.381),l(.281,.417),l(.551,.223),l(.294,.402),l(.335,.211),l(.421,.125),l(.512,.025),l(.416,-.038),l(.253,.133),l(.009,-.001),l(.377,-.03),l(.327,-.328),l(.254,-.255),l(.642,-.188),l(.374,-.445),l(1.058,-.492),l(.456,-.234),l(.306,.166),l(.351,.281),l(.487,.21),l(.061,.113),l(-.094,.155),l(-.63,.129),l(.027,.188),l(.43,.176),l(-.095,.222),l(-.532,.27),l(.13,.363),l(.374,.105),l(.356,.433),l(.268,-.016),l(.72,.317),l(.015,.007),l(-.05,.707),l(-.143,.581),l(.205,.48),l(.494,.252),l(.925,.235),l(.827,.052),l(.424,.097),l(.162,.282),l(.312,.451),l(.687,.463),l(1.902,.513),l(.841,.052),l(.438,-.059),l(1.354,-.262),l(1.192,-.148),l(1.469,-.079),l(.41,-.229),l(.185,-.354),l(-.131,-.905),l(.015,0),l(.441,.025),l(.562,-.13),l(.466,-.3),l(.621,-.654),l(.476,-.328),l(.413,-.144),l(.609,-.032),l(.78,.038),l(.333,-.03),l(.517,-.343),l(.343,-.129),l(.519,.054),l(1.055,.107),l(.402,.437),l(.708,.251),l(.822,.335),l(.788,.066),l(.5,.054),l(.66,.167),l(.597,.336),l(1.803,1.362),l(.655,.506),l(.696,.01),l(.787,-.075),l(.185,.211),l(.038,.848),l(.01,.565),l(.15,.692),l(.078,.028),l(-.145,.241),l(-.084,.339),l(-.246,.807),l(-.49,1.272),l(-.222,.297),l(-.596,.384),l(-.016,.141),l(.119,.663),l(.096,.098),l(.738,.235),l(.026,.183),l(-.661,.935),l(-.034,.155),l(.254,1.085),l(.167,1.283),l(.143,.775),l(.191,.21),l(.209,.041),l(1.198,.275),l(.401,.167),l(.144,.366),l(.046,.437),l(-.425,.553),l(-.853,.795),l(-.853,1.034),l(.802,1.083),l(.71,1.068),l(.353,.464),l(.695,.391),l(1.144,.388),l(.409,.224),l(.168,.38),l(.111,1.34),l(.185,.394),l(.652,.053),l(.186,.281),l(-.036,.974),l(-.188,.255),l(-.209,.072),l(-1,.077),l(-.697,.258),l(-.794,.47),l(-.285,.383),l(-.31,.792),l(-.049,.354),l(-.182,.954),l(-.502,.028),l(-1.079,-.153),l(-.236,-.197),l(-.605,-.253),l(-.403,-.056),l(-1.43,.003),l(-.783,-.041),l(-.602,.072),l(-.475,-.38),l(-.163,-.126),l(-.835,-.026),l(-.576,.001),l(-.465,.014),l(-.212,-.239),l(-.756,-.125),l(-.305,-.183),l(-.162,-.014),l(-.021,-.5),l(-.295,-.128),l(-.103,-.514),l(-.292,-.349),l(-.013,-.639),l(-.309,-.493),l(-.237,.012),l(-.035,-.181),l(-.526,-.126),l(-.807,-.013),l(-.374,.017),l(-.209,.222),l(-.329,.018),l(-.517,.075),l(-.188,.364),l(-.538,.138),l(-.383,.443),l(-.368,.283),l(-.253,.043),l(-1.292,-.689),l(-.958,-.104),l(-.562,-.359),l(-1.088,-.317),l(-.247,-.301),l(-.324,-.282),l(-.497,-.592),l(-.997,-.436),l(-.584,-.083),l(-.194,-.028),l(-.58,-.465),l(-.596,-1.058),l(-.635,-1.114),l(-.209,-.268),l(.005,-.593),l(-.767,-.761),l(-.506,-.719),l(-.921,.143),l(-.46,-.042),l(-.13,-.126),l(-.291,-.056),l(-.191,-.268),l(-.029,-.565),l(-.448,.1),l(-.166,.099),l(-.32,.678),l(-.195,.184),l(-.355,.012),l(-.014,-.12),l(-.351,-.224),l(-.686,-.546),l(.064,-.212),l(-.007,-.395),l(-.164,-.465),l(-.215,-.013),l(-.551,.003),l(-.034,-.325),l(.055,-.579),l(.197,-.622),l(.014,-.508),l(-.112,-.239),l(-.29,-.28),l(-.774,-.603),l(-.436,-.209),l(-1.242,-.925),l(-.533,-.025),l(-.321,.115),L(503,127.106),l(.033,-.819),l(-1.02,-.954),l(-.312,-.351),l(-.002,-.184),l(.133,-.875),l(.235,-.763),l(1.142,-.98),l(-.422,-.761),l(.013,-.254),l(.468,-.596),l(-1.067,-.107),l(-.761,-.208),l(-.065,-.198),l(-.563,-1.086),l(-.69,-1.397), +N(535.734,133.791),l(.853,-1.034),l(.853,-.795),l(.425,-.553),l(-.046,-.437),l(-.144,-.366),l(-.401,-.167),l(-1.198,-.275),l(-.209,-.041),l(-.191,-.21),l(-.143,-.775),l(-.167,-1.283),l(-.254,-1.085),l(.034,-.155),l(.661,-.935),l(-.026,-.183),l(-.738,-.235),l(-.096,-.098),l(-.119,-.663),l(.016,-.141),l(.596,-.384),l(.222,-.297),l(.49,-1.272),l(.246,-.807),l(.084,-.339),l(.145,-.241),l(.193,.112),l(.937,.193),l(.999,.348),l(.573,.082),l(.534,-.031),l(.636,-.3),l(.22,-.199),l(.001,-.466),l(.119,-.199),l(.568,-.159),l(1.985,-.689),l(.508,-.243),l(.103,-.128),l(.203,-.991),l(.432,-.809),l(1.135,-.205),l(.417,-.2),l(.445,-.356),l(.565,.294),l(1.454,.244),l(.096,.016),l(.646,.011),l(1.217,.05),l(.236,.126),l(.351,.48),l(.04,.055),l(.129,.141),l(.245,.041),l(.485,-.144),l(.58,-.343),l(.581,-.286),l(.325,-.001),l(.63,.237),l(.381,-.016),l(.21,-.128),l(.3,-.313),l(-.007,-.311),l(.073,-.185),l(.292,-.058),l(.587,.152),l(.133,.013),l(.442,-.158),l(.208,-.228),l(-.006,-.255),l(.049,-.425),l(.435,-.428),l(.134,-.363),l(.286,-.162),l(.384,-.016),l(.153,.056),l(.576,.45),l(-.156,.597),l(.484,-.093),l(.17,.187),l(-.029,.255),l(-.099,.775),l(-.185,.444),l(.199,.521),l(.164,.409),l(.128,.084),l(.368,.026),l(.351,-.03),l(.745,-.495),l(.589,-.064),l(.592,-.486),l(.739,-.315),l(.678,-.03),l(.198,.077),l(-.129,.176),l(.137,.059),l(.974,-.147),l(.564,-.227),l(.264,.151),l(.496,.054),l(.565,.153),l(-.192,.145),l(-.574,-.059),l(.01,.269),l(.236,.012),l(.048,.088),l(-.148,.142),l(-.358,.004),l(-.455,.297),l(-.332,-.005),l(-.338,.179),l(-.647,-.144),l(-1.345,.012),l(-1.148,.152),l(-.53,.292),l(-.272,.19),l(-.559,.395),l(-.246,-.023),l(-.258,.214),l(-.464,.413),l(.01,.32),l(.411,.271),l(.01,.336),l(.232,.171),l(-.119,.483),l(.198,.477),l(-.324,.426),l(-.524,.355),l(-.4,.341),l(-.13,.283),l(.223,.478),l(.033,.31),l(-.289,.255),l(-.513,.215),l(-.698,-.039),l(-.997,-.122),l(-.355,.129),l(.35,.336),l(.365,.407),l(.129,.281),l(.088,.437),l(-.199,.255),l(-.315,.115),l(-.513,.031),l(-.416,.115),l(-.292,.228),l(-.224,.424),l(-.288,.834),l(-.139,1.214),l(-.021,.084),l(-.34,.383),l(-.237,.086),l(-1.001,-.375),l(-.562,-.025),l(-.559,.243),l(-.362,.271),l(-.321,.693),l(-.254,.086),l(-.516,-.082),l(-.644,-.039),l(-.283,.072),l(-.597,.441),l(-.412,.369),l(-.188,.34),l(-.232,.876),l(-.099,.903),l(-.069,.184),l(-.247,.156),l(-1.066,.274),l(-1.183,.19),l(-.964,.175),l(-1.234,.12),l(-1.005,-.135),l(-.349,.002),l(-1.187,.218),l(-.742,-.024),l(-.541,-.039),l(-.854,-.235),l(-1.069,-.248),l(-.63,-.194),l(-.887,-.32), +N(486.696,126.295),l(5.257,-2.711),l(.589,-2.701),l(-.024,-.467),l(-.187,-.508),l(.009,-.255),l(.23,-.355),l(.31,-.214),l(.866,-.174),l(.457,-.371),l(.944,-.883),l(-.059,-.24),l(.23,-.043),l(.266,-.143),l(.437,-.094),l(.304,.16),l(.364,-.032),l(.811,.153),l(.343,.023),l(.244,-.234),l(.366,.082),l(.274,.151),l(-.03,.259),l(.102,.269),l(.318,.105),l(.164,-.126),l(.433,-.388),l(.407,.016),l(.69,1.397),l(.563,1.086),l(.065,.198),l(.761,.208),l(1.067,.107),l(-.468,.596),l(-.013,.254),l(.422,.761),l(-1.142,.98),l(-.235,.763),l(-.133,.875),l(.002,.184),l(.312,.351),l(1.02,.954),L(503,127.106),l(.075,.155),l(.321,-.115),l(.533,.025),l(1.242,.925),l(.436,.209),l(.774,.603),l(.29,.28),l(.112,.239),l(-.014,.508),l(-.197,.622),l(-.055,.579),l(.034,.325),l(.551,-.003),l(.215,.013),l(.164,.465),l(.007,.395),l(-.064,.212),l(.686,.546),l(.351,.224),l(.014,.12),l(-.096,.003),l(-.664,.101),l(-.408,-.056),l(-.157,.057),l(-.103,.127),l(-1.271,.044),l(-.518,.13),l(-.343,.693),l(-.463,.609),l(-.521,.568),l(-4.048,-.132),l(-1.557,-.697),l(-.812,-.277),l(-.118,-.253),l(-.047,-.818),l(.118,-.396),l(-.135,-.366),l(-.973,.048),l(-.141,-.07),l(-.399,-.633),l(-.258,-.196),l(-2.44,-1.101),l(-1.14,-.473),l(-2.034,-.934),l(-.757,-.222),l(-1.129,-.459),l(-.093,-.056),l(-.093,-.056),l(-.311,-.69),l(-.87,-1.632), +N(479.916,127.377),l(-.082,-.085),l(.047,-.122),l(-.021,-.183),l(-.201,-.128),l(-.183,-.346),l(.398,-.209),l(.041,-.099),l(.526,-.396),l(-.048,-.058),l(-.223,-.099),l(.077,-.151),l(.298,-.25),l(.599,-.006),l(-.14,-.146),l(-.035,-.046),l(.078,-.111),l(.177,-.163),l(.169,-.116),l(.299,-.239),l(-.068,-.058),l(.023,-.163),l(-.09,-.047),l(-.031,-.221),l(-.241,-.157),l(-.222,-.058),l(.204,-.204),l(-.125,-.052),l(-.053,-.116),l(-.12,.058),l(-.335,.052),l(-.388,-.023),l(-.225,-.564),l(.129,-.593),l(.072,-.064),l(-.1,-.507),l(-.42,-.326),l(.126,-.093),l(.036,-.152),l(.117,-.128),l(-.093,-.222),l(.107,-.012),l(.259,-.32),l(-.061,-.112),l(.311,-.001),l(.39,.125),l(.114,-.127),l(.171,.041),l(.2,-.169),l(.156,-.374),l(.627,-.127),l(-.243,-.423),l(-.102,-.452),l(.055,-.319),l(.142,.035),l(.222,-.001),l(.777,.166),l(.575,.025),l(.746,-.075),l(.929,-.373),l(.278,-.03),l(1.532,.444),l(.556,.153),l(1.104,-.176),l(.567,-.13),l(1.498,-.673),l(.439,-.073),l(.747,.123),l(.711,.039),l(1.185,-.224),l(.693,-.304),l(.24,-.292),l(.207,.023),l(.064,.245),l(.059,.24),l(-.944,.883),l(-.457,.371),l(-.866,.174),l(-.31,.214),l(-.23,.355),l(-.009,.255),l(.187,.508),l(.024,.467),l(-.589,2.701),l(-5.257,2.711),l(-.161,.071),l(-2.96,1.541),l(-1.139,.656),l(-.253,.016),l(-.365,-.167),l(-1.902,-1.034), +N(426.068,126.434),l(-.093,.981),l(.064,.564),l(-.093,.269),l(-.802,.428),l(-.579,.314),l(-1.473,1.138),l(-.126,.354),l(.274,.973),l(-.147,.537),l(-.155,.227),l(-.864,.598),l(-.22,.143),l(-.564,-1.536),l(-.699,-2.242),l(-.323,-.464),l(-.363,-.252),l(-.432,-.181),l(-.484,-.831),l(-.225,-.465),l(-.363,-.28),l(-.452,-.097),l(-.336,-.774),l(-.301,-.888),l(.112,-.509),l(1,-.853),l(.414,-.355),l(.163,-.411),l(.048,-.537),l(-.052,-.594),l(-.026,-.892),l(-.012,-1.429),l(.114,-.439),l(.685,-.627),l(.012,-.184),l(.508,-.185),l(.633,-.455),l(.591,-.228),l(.703,-.016),l(.643,.183),l(.247,.212),l(.059,.241),l(.25,.538),l(.27,.084),l(.417,-.171),l(.584,-.44),l(.401,-.17),l(.034,.354),l(-.265,.567),l(-.638,.511),l(-.275,.468),l(.005,.283),l(.202,.438),l(.508,.466),l(.351,.127),l(.303,.848),l(-.094,.212),l(-.541,.764),l(-.59,.34),l(-1.017,.92),l(-.216,.339),l(.287,.451),l(.587,.55),l(.528,.295),l(.284,.056),l(.396,-.227),l(.316,.084),l(.244,.635),l(.582,.239), +N(381.402,139.704),l(-.027,-.876),l(.069,-2.006),l(.037,-.382),l(.686,-.314),l(1.512,-.998),l(.963,-.542),l(1.265,.078),l(.397,-.059),l(.181,-.693),l(.864,-.033),l(.777,-.174),l(.527,-.229),l(.524,-.356),l(.484,-.652),l(1.109,-.332),l(1.52,-.701),l(.129,-.227),l(-.296,-.62),l(-.025,-.396),l(.079,-.227),l(.265,-.114),l(1.186,-.12),l(.381,-.186),l(.309,-.553),l(1.022,.022),l(.67,-.018),l(1.826,.004),l(.34,-1.033),l(-.07,-.211),l(-.507,-.322),L(397,126.646),l(-.158,-.465),l(.016,-1.271),l(.022,-.833),l(-.165,-.889),l(-.189,-.211),l(-.563,-.279),l(-.259,-.508),l(.351,0),l(.66,-.143),l(.541,-.256),l(.369,-.566),l(.405,-.312),l(.509,-.086),l(.407,-.157),l(.679,-.27),l(.324,.226),l(.176,.017),l(.249,.024),l(.238,-.142),l(.407,-.51),l(.613,-.426),l(.682,-.355),l(.614,-.171),l(1.16,-.116),l(1.587,-.06),l(.513,-.072),l(.634,-.312),l(.578,.211),l(.564,-.072),l(.585,-.313),l(.343,-.1),l(.939,.012),l(.513,-.015),l(.307,.056),l(.221,.042),l(.322,.113),l(.816,.168),l(.529,-.015),l(.772,-.171),l(.705,-.2),l(.612,-.554),l(.994,.508),l(.339,.099),l(.312,-.143),l(.314,-.241),l(.228,-.156),l(.528,.042),l(.388,.197),l(.162,.269),l(.269,.126),l(.516,-.086),l(1.093,-.158),l(-.012,.184),l(-.685,.627),l(-.114,.439),l(.012,1.429),l(.026,.892),l(.052,.594),l(-.048,.537),l(-.163,.411),l(-.414,.355),l(-1,.853),l(-.112,.509),l(.301,.888),l(.336,.774),l(.452,.097),l(.363,.28),l(.225,.465),l(.484,.831),l(.432,.181),l(.363,.252),l(.323,.464),l(.699,2.242),l(.564,1.536),l(-.204,.156),l(-.241,.383),l(.88,1.605),l(.147,.833),l(.052,.691),l(-.1,.862),l(.101,.748),l(-.16,.622),l(-.158,.495),l(.457,1.156),l(-.061,.664),l(-.086,.17),l(-.666,.47),l(-.249,.128),l(-.152,.283),l(1.272,1.702),l(.249,.917),l(.562,.873),l(.244,.154),l(.544,-.201),l(.702,.165),l(1.028,.347),l(.178,.168),l(.86,1.506),l(.098,.07),l(-.265,.186),l(-1.632,.843),l(-4.012,2.241),l(-1.607,.956),l(-2.308,1.454),l(-.834,.655),l(-3.084,2.617),l(-1.82,.364),l(-1.672,.321),l(-2.176,.408),l(-.146,-.564),l(.161,-.679),l(-.099,-.522),l(-.277,-.352),l(-.309,-.111),l(-.748,-.024),l(-.375,-.167),l(-.588,-.562),l(-.47,.314),l(-.229,-.027),l(-1.111,-1.039),l(-.393,-.28),l(-.082,-.183),l(.096,-.396),l(-.181,-.253),l(-2.472,-1.469),l(-.397,-.253),l(-1.292,-.824),l(-1.924,-1.26),l(-3.283,-2.241),l(-.811,-.575),l(-2.054,-1.344),l(-.895,-.531),l(-.1,-.084),l(-1.414,-.91),l(-4.12,-2.42),l(-2.829,-1.509), +N(395.704,122.189),l(.259,.508),l(.563,.279),l(.189,.211),l(.165,.889),l(-.022,.833),l(-.016,1.271),l(.158,.465),l(.598,.788),l(.507,.322),l(.07,.211),l(-.34,1.033),l(-1.826,-.004),l(-.67,.018),l(-1.022,-.022),l(-.309,.553),l(-.381,.186),l(-1.186,.12),l(-.265,.114),l(-.079,.227),l(.025,.396),l(.296,.62),l(-.129,.227),l(-1.52,.701),l(-1.109,.332),l(-.484,.652),l(-.524,.356),l(-.527,.229),l(-.777,.174),l(-.864,.033),l(-.181,.693),l(-.397,.059),l(-1.265,-.078),l(-.963,.542),l(-1.512,.998),l(-.686,.314),l(-.037,.382),l(-.069,2.006),l(-1.42,.008),l(-1.718,-.004),l(-2.677,.001),l(-2.511,0),l(-1.635,.04),l(.141,-.28),l(.431,-.411),l(.427,-.085),l(1.296,-.285),l(1.143,-.455),l(.453,-.312),l(1.147,-.85),l(1.149,-.878),l(1.043,-1.104),l(.46,-.693),l(.133,-.509),l(-.05,-.494),l(-.427,-.776),l(-.09,-.678),l(.099,-.508),l(.396,-.636),l(.706,-.863),l(.211,-.65),l(-.063,-.367),l(.071,-.353),l(1.285,-1.203),l(.724,-.481),l(.916,-.327),l(1.266,-.469),l(.73,-.397),l(.558,-.552),l(.537,-.736),l(.466,-.905),l(.829,-1.925),l(.269,-.128),l(.54,-.171),l(.19,.127),l(.684,.848),l(.138,.099),l(1.148,.507),l(.661,-.001),l(.595,.042),l(1.304,-.074),l(.522,-.228),l(.437,-.27),l(.398,.551),l(.256,.099),l(.798,.097),l(.361,0), +N(480.248,123.437),l(.388,.023),l(.335,-.052),l(.12,-.058),l(.053,.116),l(.125,.052),l(-.204,.204),l(.222,.058),l(.241,.157),l(.031,.221),l(.09,.047),l(-.023,.163),l(.068,.058),l(-.299,.239),l(-.169,.116),l(-.177,.163),l(-.078,.111),l(.035,.046),l(.14,.146),l(-.599,.006),l(-.298,.25),l(-.077,.151),l(.223,.099),l(.048,.058),l(-.526,.396),l(-.041,.099),l(-.398,.209),l(-.07,-.023),l(-.088,.041),l(-.067,.193),l(-.009,.167),l(-.355,.07),l(-.07,-.099),l(-.151,-.022),l(-.372,.051),l(.26,-.291),l(.097,-.361),l(.169,-.227),l(.328,-.681),l(-.017,-.232),l(.181,0),l(.138,-.192),l(.072,-.32),l(.018,-.32),l(.409,-.431),l(.232,-.07),l(.116,-.174),l(-.048,-.157), +N(184.444,142.729),l(-.367,.82),l(-.518,.821),l(-.186,.763),l(-.179,1.159),l(.017,1.851),l(-.133,1.187),l(-.016,1.13),l(.564,1.737),l(.275,.805),l(.624,.945),l(.76,.903),l(.191,.452),l(.481,.521),l(.529,.974),l(.729,1.228),l(.375,.296),l(.677,.069),l(.436,-.015),l(.577,.154),l(.593,.451),l(.503,.508),l(.773,.069),l(1.016,-.242),l(1.55,-.456),l(1.396,-.3),l(.803,-.157),l(-.02,.542),l(.838,.223),l(.264,-.286),l(.293,-.199),l(-.104,-.247),l(-.393,-.175),l(1.073,-.62),l(.633,-.62),l(.086,-.827),l(.498,-.429),l(-.094,-.477),l(.092,-1.145),l(.254,-.699),l(.625,-.334),l(.164,-.043),l(.757,-.198),l(.701,-.1),l(1.088,-.229),l(1.016,-.37),l(.594,-.058),l(.499,.056),l(1.139,.181),l(.502,-.194),l(.378,.093),l(.62,.507),l(.047,.297),l(-.079,.424),l(-.298,.382),l(-.541,.496),l(-.433,.425),l(-.317,.445),l(-.02,.7),l(-.254,.297),l(-.188,.354),l(.155,.155),l(.337,-.138),l(-.101,.652),l(-.262,1.196),L(205.356,159),l(-.062,.24),l(-.34,-.534),l(-.167,-.452),l(-.072,-.155),l(-.386,.34),l(-.02,.549),l(-.437,.016),l(-.178,.447),l(-.599,.857),l(-.386,-.27),l(-.278,.095),l(.025,.329),l(-2.332,-.006),l(-1.792,-.005),l(-.04,1.24),l(-.999,.032),l(.396,.223),l(.495,.541),l(.624,.231),l(.359,.69),l(.532,.223),l(-.211,.683),l(-1.762,-.007),l(-1.06,.007),l(-1.076,1.812),l(.305,.397),l(-.207,.238),l(.054,.553),l(.044,.454),l(-.704,-.555),l(-.952,-.888),l(-.956,-.761),l(-1.069,-.859),l(-.534,-.352),l(-.053,-.071),l(-.639,-.252),l(-1.048,-.21),l(-.657,.044),l(-.817,.397),l(-1.1,.567),l(-.756,.256),l(-.931,-.069),l(-.724,-.21),l(-.48,-.197),l(-1.305,-.195),l(-.588,-.267),l(-.644,-.422),l(-.935,-.521),l(-.785,-.267),l(-1.711,-.392),l(-.963,-.365),l(-.722,-.366),l(-1.074,-.436),l(-.592,-.352),l(-1.123,-1),l(-.207,-.07),l(-.606,.058),l(-.689,-.14),l(-1.835,-.575),l(-.565,-.536),l(-.503,-.634),l(-.495,-.395),l(-1.049,-.577),l(-.619,-.267),l(-.5,-.494),l(-.742,-.987),l(-.363,-.55),l(-.038,-.113),l(.15,-.155),l(.504,-.086),l(.18,-.17),l(.047,-.184),l(-.331,-.367),l(.457,-.679),l(.041,-.381),l(-.172,-.466),l(-.744,-.959),l(.121,-.297),l(.146,-.17),l(-.07,-.268),l(-.665,-.62),l(-1.495,-1.777),l(-.546,-.493),l(-.963,-1.058),l(-.474,-.522),l(-.815,-.578),l(-.322,-.197),l(-.158,-.268),l(-.058,-.48),l(-.144,-.183),l(-.329,-.197),l(-.609,-.197),l(-.408,-.31),l(-.366,-.522),l(-.271,-.028),l(-.414,.114),l(-.238,-.155),l(-.163,-.367),l(-.005,-.325),l(.459,-.736),l(-.126,-.339),l(-.751,-.62),l(-.439,.255),l(-.375,-.621),l(-.118,-.353),l(-.359,-.211),l(-.61,-.168),l(-.319,-.296),l(-.125,-.254),l(.05,-.381),l(.084,-.269),l(-.185,-.226),l(-.561,-.21),l(-.46,-.098),l(-.46,-.253),l(-.935,-.86),l(-.478,-.706),l(-.281,-.551),l(-.646,-.832),l(-.736,-1.073),l(-.184,-.423),l(-.38,-.678),l(-.242,-.338),l(-.152,-.452),l(.042,-.509),l(.032,-.311),l(-.56,-.239),l(-.795,-.196),l(-.06,-.452),l(-.128,-.155),l(-.458,-.183),l(-.289,.326),l(-.251,.043),l(-1.43,-.647),l(-.285,1.004),l(-.045,.438),l(.033,.084),l(.265,.339),l(.264,.296),l(.028,1.046),l(.088,.509),l(.51,.677),l(.143,.169),l(.643,.267),l(.601,.536),l(.525,.663),l(.602,1.214),l(.44,.282),l(.328,.042),l(.237,.169),l(.325,1.398),l(.102,.169),l(.246,.155),l(.497,.056),l(.133,.056),l(.215,.438),l(.161,.65),l(.445,.79),l(.49,-.071),l(.223,-.142),l(.245,.452),l(.344,1.469),l(.531,1.059),l(.649,1.2),l(.069,.593),l(-.014,.522),l(.26,.353),l(.378,.154),l(.389,-.17),l(.234,-.198),l(.588,.804),l(.258,.579),l(.464,.253),l(.281,.014),l(.133,.311),l(-.196,.537),l(-.136,.127),l(-.691,.595),l(-.254,-.042),l(-.251,-.409),l(-.24,-.734),l(-.617,-.578),l(-.625,-.309),l(-.516,-.479),l(-.834,-.507),l(-1.143,-.986),l(-.416,-.451),l(-.162,-.269),l(.216,-.989),l(-.035,-.254),l(-.488,-1.002),l(-.238,-.381),l(-.327,-.282),l(-.44,-.098),l(-.5,-.31),l(-.675,-.677),l(-.305,.142),l(-.363,-.056),l(-1.262,-.746),l(-.722,-.31),l(-.896,-.973),l(-.139,-.127),l(-.246,-.254),l(.679,.15),l(.599,.013),l(.588,-.284),l(.244,-.326),l(.093,-.636),l(-.01,-.184),l(-.458,-.635),l(-.466,-.452),l(-1.1,-.888),l(-.986,-.493),l(-.402,-.338),l(-.203,-.522),l(-.272,-.649),l(-.091,-.155),l(-.447,-.126),l(-.15,-.353),l(-.026,-.594),l(-.203,-.395),l(-.623,-.734),l(-.434,-.706),l(-.003,-.254),l(.212,-.382),l(-.777,-.62),l(-.254,-.325),l(-.22,-.485),l(.34,-.017),l(2.367,-.155),l(2.381,-.084),l(.316,.31),l(.267,.154),l(1.186,.39),l(2.811,.933),l(3.516,1.112),l(.338,.055),l(1.662,.019),l(1.544,.02),l(.966,.037),l(1.867,-.011),l(.213,-.101),l(.096,-.892),l(1.858,.003),l(1.892,.046),l(.209,.112),l(.631,.662),l(.766,.632),l(.837,.519),l(.708,.491),l(.179,.226),l(.284,.678),l(.318,.847),l(.445,.549),l(1.092,.659),l(1.104,.503),l(.337,.069),l(.501,.011),l(.416,-.158),l(.283,-.37),l(.418,-.413),l(.576,-.541),l(.468,-.201),l(.643,-.018),l(.475,.082),l(.783,.321),l(.412,.252),l(.363,.366),l(.663,1.029),l(.744,1.227),l(.845,1.042),l(.657,.576),l(.268,.253),l(.078,.467),l(.332,.932),l(.336,.592),l(.375,.365),l(.921,.32),l(1.029,.56),l(.264,.069),l(.416,-.116),l(.296,-.001),l(.816,.377),l(.347,.119), +N(507.047,133.665),l(.055,.197),l(.134,.691),l(-.336,-.028),l(-.513,.513),l(.421,.194),l(.418,-.206),l(.306,.021),l(.698,1.84),l(-.644,.044),l(-1.07,-.05),l(-.185,-.239),l(-.334,-.619),l(-.408,-.054),l(-1.657,-.259),l(.521,-.568),l(.463,-.609),l(.343,-.693),l(.518,-.13),l(1.271,-.044), +N(606.155,150.953),l(.595,.152),l(.255,.14),l(.25,-.129),l(.273,-.368),l(.015,-.678),l(-.152,-.93),l(.228,-.185),l(.401,-.144),l(.191,-.354),l(-.146,-1.594),l(.133,-.283),l(.811,.32),l(.391,.11),l(.309,.013),l(.17,-.128),l(1.148,-2.25),l(0,-.324),l(-.192,-.408),l(.045,-.212),l(.938,-1.134),l(.136,-.382),l(-.057,-.761),l(.197,-.354),l(1.446,-.883),l(.719,-.512),l(.312,-.129),l(.558,.082),l(.853,.221),l(.295,-.058),l(-.184,-.718),l(.072,-.283),l(.596,-.582),l(.112,-.24),l(.018,-.508),l(.001,-.127),l(.306,-.34),l(.277,-.044),l(.504,.279),l(.397,.435),l(.243,.901),l(.217,.309),l(.287,.041),l(.504,-.031),l(.146,.14),l(.195,1.649),l(.02,.875),l(-.353,.862),l(-.429,.722),l(-.611,.525),l(-.487,.271),l(-.191,.198),l(-.617,.85),l(.075,.465),l(.163,.705),l(-.224,.58),l(0,.268),l(.216,.069),l(.312,-.086),l(.819,-.442),l(.771,-.089),l(.479,-.017),l(.156,.126),l(.277,1.762),l(.202,.324),l(.554,-.074),l(.521,.096),l(.033,.268),l(-.729,1.584),l(.117,.352),l(.228,.098),l(.507,-.003),l(.481,-.045),l(.291,.379),l(.341,.746),l(.378,.266),l(.246,.083),l(.647,-.159),l(.628,-.413),l(.111,.38),l(.153,.239),l(-.502,.355),l(-.53,.61),l(-.442,.581),l(-.582,.455),l(-.193,.185),l(-.08,.085),l(-.158,.071),l(-.645,.06),l(-.436,.172),l(-.528,.342),l(-.394,.595),l(-1.078,.316),l(-.62,.018),l(-.474,-.082),l(-.362,.411),l(-.143,.368),l(-.036,.819),l(-.114,.509),l(.064,.409),l(-.086,.24),l(-.163,.001),l(-.588,.131),l(.739,.884),l(.069,.183),l(.112,.875),l(.254,.14),l(1.091,.953),l(.148,.324),l(.646,1.041),l(.163,.338),l(-.194,.241),l(-.451,.229),l(-.128,.226),l(.231,1.185),l(-.171,.198),l(-.812,.428),l(.178,.38),l(.6,1.436),l(.54,.477),l(.606,.604),l(.203,.479),l(.088,.663),l(-.086,.636),l(.006,.254),l(.488,1.183),l(.586,1.225),l(-.077,.297),l(-1.011,1.559),l(-1.01,1.7),l(-.098,.374),l(-.359,-.181),l(-.075,-.805),l(.461,-.665),l(.174,-.495),l(.122,-.777),l(.287,-.466),l(-.512,-.027),l(-.104,-.084),l(-.004,-.282),l(.195,-.509),l(-.177,-1.524),l(-.246,-.832),l(-.639,-1.185),l(-.488,-1.312),l(-.347,-.846),l(-.179,-.875),l(-.174,-1.736),l(-.117,-.677),l(-.034,-.564),l(-.051,-.212),l(-.344,-.084),l(-.148,-.098),l(-.304,-.917),l(-.516,-.677),l(-.226,-.225),l(-.247,.029),l(-.081,.988),l(-.158,.424),l(-.43,.41),l(-.59,.284),l(-1.089,.511),l(-.359,.622),l(-.298,.297),l(-.196,.142),l(-.237,-.282),l(-.007,-.438),l(-.212,.015),l(-.338,.354),l(-.321,-.013),l(-.166,-.211),l(.147,-.495),l(-.001,-.113),l(-.621,.171),l(-.276,.127),l(-.247,.283),l(-.355,-.126),l(-.002,-.466),l(.553,-1.54),l(.162,-.791),l(.001,-.889),l(-.101,-1.059),l(-.384,-.973),l(-.431,-1.072),l(-.196,-.296),l(-.281,.537),l(-.32,-.126),l(-.526,-.366),l(.482,-.17),l(.312,-.015),l(-.149,-.479),l(-.054,-.268),l(-.684,-.775),l(-.182,-.183),l(-.19,-.028),l(-.407,.1),l(-.38,-.267),l(.086,-.438),l(-.026,-.141),l(-.209,-.112),l(-.365,.043),l(-.577,-.465),l(-.504,-.606),l(-.117,-.244),l(.252,-.341),l(.801,-.527),l(-.194,-1.607), +N(605.297,153.429),l(-.126,-.264),l(-.269,-.55),l(-.223,-1.213),l(-.611,-1.41),l(-.357,-.395),l(-.73,.354),l(-.393,0),l(-.034,-.084),l(-.242,-.211),l(-.356,-.592),l(-.124,-.042),l(-.152,.127),l(-.026,.537),l(.374,.79),l(-.006,.424),l(-.143,.169),l(-.455,.086),l(-.235,.537),l(-.261,.1),l(-.255,-.437),l(-.311,-.395),l(-.073,-.057),l(-.163,.669),l(-.28,.249),l(-.203,.043),l(-.271,-.536),l(-.495,.636),l(-.359,-.265),l(-.147,-.532),l(-.402,-1.775),l(-.325,-1.409),l(-.352,-.45),l(-.04,-.254),l(.505,-.765),l(.029,-.269),l(-.193,-.21),l(-1.042,-.431),l(-.339,-.323),l(.548,-.61),l(.4,-.299),l(.502,-.13),l(.382,-.101),l(.047,-.155),l(-.126,-.112),l(-1.224,-.938),l(-.494,-.237),l(-.083,-.155),l(.124,-.283),l(.555,-.525),l(.234,-.171),l(1.252,.303),l(.339,.266),l(.372,.266),l(.489,-.06),l(.417,.054),l(.129,.324),l(.053,.479),l(.079,.719),l(.095,.099),l(.537,.109),l(.547,.053),l(.916,-.062),l(.559,-.003),l(2.473,.198),l(.111,.098),l(.057,.127),l(-.012,.79),l(-.159,.34),l(-.938,.767),l(-.498,.13),l(-.651,.356),l(-.131,.283),l(.009,.522),l(.001,.381),l(.23,.281),l(.249,.267),l(.529,.448),l(.224,-.354),l(.395,-1.159),l(.281,-.115),l(.4,-.044),l(.064,.578),l(.627,2.479),l(.037,.466),l(.194,1.607),l(-.801,.527),l(-.252,.341), +N(627.408,186.411),l(-.086,.337),l(-.495,.35),l(-.11,.575),l(-.644,.089),l(-.05,-.478),l(-.309,-.163),l(-.279,.28),l(-.244,.394),l(-.204,-.083),l(-.118,-.239),l(.213,-.398),l(-.041,-.21),l(-.055,-.226),l(-.261,-.238),l(-.447,-.119),l(-.106,-.466),l(-.571,.013),l(-.448,.17),l(.013,-.104),l(.128,-.297),l(-.15,-.183),l(-.411,.212),l(-.301,-.07),l(-.38,-.38),l(-.116,-.508),l(.064,-.282),l(-.151,-.438),l(-.229,-.169),l(-.388,.043),l(-.39,-.719),l(-.209,-.508),l(-.3,-.324),l(-.311,-.155),l(-.456,-.395),l(-.343,.1),l(-.218,.142),l(-.216,-.381),l(-.04,-.607),l(.163,-.749),l(.559,-1.738),l(.29,-.848),l(-.087,-.044),l(.098,-.374),l(1.01,-1.7),l(1.011,-1.559),l(.077,-.297),l(-.586,-1.225),l(-.488,-1.183),l(-.006,-.254),l(.086,-.636),l(-.088,-.663),l(-.203,-.479),l(-.606,-.604),l(-.54,-.477),l(-.6,-1.436),l(-.178,-.38),l(.812,-.428),l(.171,-.198),l(-.231,-1.185),l(.128,-.226),l(.451,-.229),l(.194,-.241),l(-.163,-.338),l(-.646,-1.041),l(-.148,-.324),l(-1.091,-.953),l(-.254,-.14),l(-.112,-.875),l(-.069,-.183),l(-.739,-.884),l(.588,-.131),l(.163,-.001),l(.086,-.24),l(-.064,-.409),l(.114,-.509),l(.036,-.819),l(.143,-.368),l(.362,-.411),l(.474,.082),l(.62,-.018),l(1.078,-.316),l(.394,-.595),l(.528,-.342),l(.436,-.172),l(.645,-.06),l(.158,-.071),l(.08,-.085),l(.541,.166),l(.295,.182),l(.118,.168),l(.01,.423),l(-.106,.805),l(.066,.367),l(.186,.154),l(.423,-.003),l(.489,-.2),l(.414,-.045),l(.045,.113),l(.249,1.311),l(-.085,.41),l(-.528,1.569),l(-.117,.438),l(-.027,.494),l(.145,.324),l(.481,.138),l(.37,-.411),l(1.173,-1.178),l(.346,-.03),l(.835,.348),l(.59,.265),l(.223,-.072),l(.543,-.257),l(.2,-.538),l(.286,-.453),l(.403,.012),l(.893,.192),l(.266,.153),l(.052,.282),l(.285,.535),l(.688,.659),l(.435,.632),l(.058,1.524),l(.107,.366),l(.255,.464),l(.979,1.279),l(.419,.703),l(.157,.507),l(.002,.945),l(-.121,.438),l(-.808,.64),l(-.301,-.167),l(-.599,-.109),l(-.575,-.039),l(-.558,.074),l(-.798,-.066),l(-1.172,.091),l(-.383,.101),l(-.521,.441),l(-.92,1.233),l(-.146,.297),l(-.076,.382),l(.026,.635),l(.219,.648),l(.487,.717),l(.16,.479),l(-.146,.176),l(-.026,-.063),l(-.286,-.183),l(-.458,-.084),l(-.9,-.887),l(-.434,-.154),l(-.304,-.014),l(-.572,.227),l(-.391,-.112),l(-.29,-.141),l(-.337,-.014),l(0,-.282),l(.19,-1.243),l(-.107,-.184),l(-.719,-.055),l(-.248,-.084),l(-.521,.043),l(-.443,.212),l(-.244,.297),l(.207,.593),l(-.103,.339),l(-.318,.707),l(.083,.579),l(.054,.41),l(-.293,.664),l(-.583,1.187),l(-.7,1.682),l(-.255,1.314),l(.104,1.171),l(.172,.296),l(.229,.169),l(.55,-.072),l(.396,-.142),l(.252,.07),l(.135,.353),l(.009,.325),l(-.08,.466),l(.141,.282),l(.178,.211),l(.271,-.094),l(.17,.46),l(.209,.974),l(-.032,.254),l(.127,.737),l(.434,.871),l(.167,.155),l(.801,.281),l(.539,.112),l(.467,-.058),l(.294,.197),l(.266,.612),l(.664,.544),l(.212,.145), +N(204.31,158.989),l(-.175,.412),l(.612,-.173),l(.026,.429),l(-.419,1.241),l(.178,.269),l(-.237,.795),l(.189,.318),l(-.092,.397),l(-.358,.875),l(-.3,.35),l(-.36,.032),l(-.054,.286),l(-.388,.238),l(0,.286),l(-.69,.016),l(.215,-4.297),l(-.025,-.329),l(.278,-.095),l(.386,.27),l(.599,-.857),l(.178,-.447),l(.437,-.016), +N(200.276,169.481),l(-.151,-.056),l(-.928,-.342),l(-.614,.032),l(-.766,-.032),l(-.608,-.239),l(-.909,-.656),l(-.513,-.419),l(-.044,-.454),l(-.054,-.553),l(.207,-.238),l(-.305,-.397),l(1.076,-1.812),l(1.06,-.007),l(1.762,.007),l(.211,-.683),l(-.532,-.223),l(-.359,-.69),l(-.624,-.231),l(-.495,-.541),l(-.396,-.223),l(.999,-.032),l(.04,-1.24),l(1.792,.005),l(2.332,.006),l(-.215,4.297),l(.69,-.016),l(.303,.095),l(.311,.302),l(.14,-.191),l(-.066,-.381),l(.336,.157),l(.458,.367),l(-1.507,1.208),l(-.499,.238),l(-.177,.493),l(.162,.604),l(-.438,.302),l(-.467,.048),l(-.043,.254),l(.164,.159),l(-.351,.111),l(-.184,.302),l(-.22,-.016),l(-.565,.461),l(-.012,.223), +N(204.413,165.093),l(.312,-.03),l(.612,-.27),l(.639,-.058),l(.743,.126),l(.478,.069),l(1.443,.04),l(.699,-.228),l(.379,-.199),l(.567,.267),l(.788,-.03),l(.763,-.101),l(.63,-.001),l(.5,.126),l(.564,.253),l(-.038,.353),l(-.102,.226),l(.228,.282),l(.787,.238),l(.557,.069),l(.244,.524),l(-1.425,.486),l(-.424,.229),l(-.248,.086),l(-.463,-.097),l(-.328,-.182),l(-.259,-.013),l(-.294,.242),l(-.503,.794),l(-1.207,.997),l(-.725,-.42),l(-.513,.583),l(-.882,.034),l(-.005,.961),l(-.293,.412),l(-.29,.143),l(-1.001,.125),l(-.311,-.661),l(-.025,-.085),l(-.478,-.3),l(.085,-.731),l(-.128,-.175),l(-.272,0),l(-.541,-.276),l(-.433,.34),l(-.365,-.016),l(-.066,-.271),l(-.565,-.35),l(-.409,-.08),l(-.208,-.418),l(-.677,-.17),l(.438,-.302),l(-.162,-.604),l(.177,-.493),l(.499,-.238),l(1.507,-1.208), +N(205.532,170.085),l(.035,.076),l(-.203,.057),l(.01,.265),l(-.237,.334),l(-.68,-.046),l(-.853,-.139),l(-1.697,-.505),l(-1.305,-.435),l(-.325,-.21),l(.012,-.223),l(.565,-.461),l(.22,.016),l(.184,-.302),l(.351,-.111),l(-.164,-.159),l(.043,-.254),l(.467,-.048),l(.677,.17),l(.208,.418),l(.409,.08),l(.565,.35),l(.066,.271),l(.365,.016),l(.433,-.34),l(.541,.276),l(.272,0),l(.128,.175),l(-.085,.731), +N(242.38,173.617),l(-.128,-.105),l(-.84,.171),l(-.534,.156),l(-.414,.2),l(-.056,.288),l(.048,.497),l(-.129,.396),l(-.227,-.027),l(-.381,.059),l(-.99,1.758),l(-.172,.722),l(-.241,.722),l(-.709,1.191),l(.402,.025),l(.234,-.1),l(.384,-.017),l(.31,.606),l(.855,1.45),l(.103,.395),l(-.226,1.132),l(.099,.353),l(.401,.309),l(.429,.548),l(.397,.252),l(.496,-.017),l(1.163,-.12),l(1.167,-.05),l(.521,.181),l(.64,.321),l(.188,.253),l(.847,.998),l(.554,.576),l(.144,0),l(.522,-.13),l(.76,-.174),l(1.99,-.224),l(.644,.081),l(-.409,.525),l(-.085,1.004),l(-.379,.511),l(-.147,.326),l(.026,.254),l(.035,.438),l(.048,.367),l(.162,.804),l(.447,.789),l(.256,.437),l(.486,.647),l(.121,.282),l(-.731,.612),l(-.479,.526),l(.51,.491),l(.797,1.182),l(-.52,.286),l(-.834,.57),l(-.412,.158),l(-.463,.017),l(-2.812,-.082),l(-.64,-.024),l(-.042,.325),l(-.013,1.031),l(.178,.154),l(.896,.122),l(.177,.084),l(.293,.408),l(.052,.367),l(-.384,-.04),l(-.417,-.11),l(-.687,.032),l(-.493,.187),l(-.111,.085),l(-.001,1.071),l(0,.554),l(.192,.197),l(.688,.363),l(.192,.183),l(-.031,.777),l(.399,.562),l(.031,.212),l(-.326,1.428),l(-.706,4.411),l(-.073,.382),l(-.133,.198),l(-.156,-.14),l(-.575,-.703),l(-.237,-.126),l(-.161,.058),l(-.448,.031),l(1.155,-1.956),l(.035,-.198),l(-.127,-.069),l(-1.299,-.84),l(-.509,-.209),l(-.708,.442),l(-.397,-.182),l(-.523,-.421),l(-.452,.427),l(-.337,.157),l(-.496,.031),l(-1.038,-.008),l(-.573,-.152),l(-.092,-.281),l(.004,-.396),l(-.173,-.296),l(-.479,-.039),l(-.366,-.14),l(-.078,-.282),l(-.251,-.761),l(-.988,-.672),l(-.526,-.364),l(-.208,-.62),l(-.208,-.324),l(-.513,-.435),l(-.897,-.418),l(-.927,-.107),l(-.081,-.112),l(-.269,-.162),l(-.197,-.118),l(-.709,-.631),l(-.128,-.056),l(-.89,.401),l(-.67,.061),l(-.977,-.277),l(-.355,-.309),l(-.166,-.493),l(-.227,-.225),l(-1.432,-.656),l(-1.496,-.803),l(.033,-.068),l(-.117,-.311),l(-.181,-.282),l(.108,-.212),l(.509,-.114),l(.465,.112),l(.186,-.325),l(-.348,-.564),l(.086,-.424),l(.314,-.227),l(.878,-.058),l(.193,.042),l(.41,-.227),l(.445,-.679),l(.45,-.961),l(.651,-1.061),l(-.122,-.268),l(-.56,-.408),l(-.071,-.184),l(.306,-.721),l(.089,-.523),l(-.149,-.861),l(-.371,-.86),l(.085,-.254),l(.49,-.143),l(.135,-.212),l(-.088,-.198),l(-.565,-.479),l(-.042,-.226),l(.103,-.198),l(.242,-.326),l(.036,-.254),l(-.173,-.282),l(-.739,-.719),l(-.364,-.396),l(.256,-.753),l(.228,-.082),l(-.045,-.45),l(.19,.082),l(.085,.307),l(.584,-.409),l(.094,-.43),l(.322,-.062),l(-.509,-1.038),l(-.228,-.149),l(-.084,-.327),l(.142,.075),l(.42,.338),l(.397,.507),l(.22,.508),l(.235,.197),l(.199,-.17),l(.147,-.241),l(-.332,-.776),l(.02,-.212),l(.176,-.297),l(.445,-.34),l(.399,-.297),l(.501,-.736),l(.327,-.156),l(.684,-.101),l(.217,-.382),l(-.104,-.381),l(.174,-.777),l(.067,-.65),l(.207,-.48),l(.498,-.439),l(.429,-.283),l(.592,-.242),l(.113,0),l(.374,.206),l(.22,.443),l(.281,-.34),l(.031,-.438),l(.199,-.551),l(.22,-.071),l(.267,.126),l(.855,.041),l(.562,-.001),l(.623,-.27),l(.237,-.254),l(.476,-.298),l(.848,-.256),l(.435,-.396),l(.278,-.551),l(.333,-.255),l(.469,-.17),l(.58,.013),l(.526,.338),l(.155,.126),l(.155,.339),l(-.285,.332), +N(408.6,174.04),l(-.062,.777),l(.164,.762),l(.388,.718),l(-.316,.962),l(-.19,.566),l(-.223,.298),l(-.656,.414),l(-.095,.34),l(.116,.592),l(-.078,.368),l(-.433,.13),l(-.257,.03),l(-.237,.397),l(.002,.381),l(.003,.48),l(-.012,.876),l(-.09,.989),l(.217,1.439),l(-.121,1.188),l(.006,.234),l(-.333,.015),l(-1.232,.144),l(-.669,.052),l(-.106,-.205),l(-.295,-1.072),l(.188,-.708),l(.026,-.833),l(-.036,-.537),l(-.135,-.974),l(-.006,-.862),l(-.035,-.522),l(.013,-.579),l(-.442,-1.311),l(-.164,-.691),l(-.403,-.323),l(-.468,-.294),l(-.18,-.395),l(.141,-.594),l(.046,-.424),l(.062,-.142),l(.24,-.157),l(.366,-.553),l(.415,-.271),l(.418,-.045),l(.739,.095),l(.337,-.158),l(.415,-.468),l(.237,-.764),l(-.131,-.367),l(.577,-.3),l(.321,-.073),l(.339,.28),l(.727,.589),l(.902,.503), +N(394.266,178.814),l(.191,-.17),l(-.02,-.41),l(-.261,-1.934),l(.125,-.34),l(.271,-.157),l(2.119,-.041),l(.867,.037),l(1.429,.006),l(.976,-.458),l(.161,.032),l(.595,.119),l(-.25,.849),l(.05,.254),l(.633,.915),l(.244,.451),l(-.188,.721),l(.02,.396),l(.265,1.114),l(.181,.592),l(.503,.788),l(.032,.155),l(-.286,.242),l(-.174,.382),l(.01,1.314),l(-.011,.72),l(.021,.551),l(.18,.479),l(.468,.577),l(.752,.608),l(-.503,.682),l(-.304,.099),l(-.593,-.013),l(-.992,.144),l(-.463,.185),l(-.188,.098),l(-.898,.469),l(-1.263,.398),l(-.942,.412),l(-.958,.567),l(-.578,-.324),l(-.945,-.436),l(-.074,-.124),l(-.066,-.741),l(-.554,-1.155),l(-.263,-.747),l(-.103,-.706),l(.327,-1.005),l(.437,-1.274),l(.521,-.851),l(.203,-.595),l(-.334,-1.438),l(-.189,-1.285),l(-.178,-.154), +N(400.72,175.499),l(1.013,.163),l(.611,.166),l(.29,.041),l(-.046,.424),l(-.141,.594),l(.18,.395),l(.468,.294),l(.403,.323),l(.164,.691),l(.442,1.311),l(-.013,.579),l(.035,.522),l(.006,.862),l(.135,.974),l(.036,.537),l(-.026,.833),l(-.188,.708),l(.295,1.072),l(.106,.205),l(-.452,.035),l(-.479,.128),l(-.368,.212),l(-.023,.04),l(-.752,-.608),l(-.468,-.577),l(-.18,-.479),l(-.021,-.551),l(.011,-.72),l(-.01,-1.314),l(.174,-.382),l(.286,-.242),l(-.032,-.155),l(-.503,-.788),l(-.181,-.592),l(-.265,-1.114),l(-.02,-.396),l(.188,-.721),l(-.244,-.451),l(-.633,-.915),l(-.05,-.254),l(.25,-.849), +N(383.772,190.418),l(.041,-.919),l(.105,-.565),l(.247,-.849),l(.059,-.452),l(-.131,-.282),l(-1.264,-1.334),l(-.592,.032),l(-.369,-.097),l(-.194,-.183),l(-.05,-.183),l(.501,-.865),l(.059,-.438),l(-.119,-.55),l(.062,-.17),l(.047,-.099),l(.602,-.554),l(.188,-.354),l(-.179,-.21),l(-.296,-.549),l(.03,-.127),l(.158,-.199),l(.304,-.03),l(.548,.223),l(.304,.012),l(.19,-.143),l(-.051,-.226),l(-.648,-.561),l(-.309,-.351),l(.332,-.37),l(.125,-.283),l(-.197,-.31),l(-.695,-.405),l(-.214,-.409),l(.264,-.623),l(.379,-.397),l(.522,-.54),l(.352,-.059),l(.566,.321),l(.455,.436),l(.35,-.228),l(.362,-.469),l(.571,-.483),l(.239,-.114),l(.257,.041),l(.147,.211),l(.004,.297),l(.117,.381),l(.148,.239),l(.352,-.059),l(.604,-.399),l(.159,-.1),l(.259,.168),l(.545,-.003),l(.308,.252),l(.15,.465),l(.52,.562),l(.452,.223),l(.354,.083),l(.368,-.115),l(.446,-.257),l(.608,-.159),l(.769,-.075),l(.644,.166),l(.63,.434),l(.178,.154),l(.189,1.285),l(.334,1.438),l(-.203,.595),l(-.521,.851),l(-.437,1.274),l(-.327,1.005),l(.103,.706),l(.263,.747),l(.554,1.155),l(.066,.741),l(-.119,-.201),l(-.289,-.197),l(-.208,.015),l(-.143,.24),l(-.096,.042),l(-.48,-.027),l(-.705,-.167),l(-.608,-.083),l(-2.352,.062),l(-1.279,.243),l(-.575,.199),l(-1.07,.369),l(-1.739,.781),l(-.701,.425),l(-.256,-.013),l(-.075,-.032), +N(627.408,186.411),l(.035,.024),l(.523,.098),l(1.061,1.198),l(.693,.916),l(.506,.762),l(.081,.579),l(-.023,.805),l(-.134,.862),l(.07,1.073),l(-.07,.636),l(.097,.494),l(.196,.381),l(.53,.493),l(.338,.536),l(.705,1.608),l(.062,.127),l(-.366,-.069),l(-.895,-.055),l(-.401,.142),l(-.175,-.07),l(-.521,-.437),l(-.885,-.605),l(-.6,-.337),l(-1.231,-.675),l(-1.02,-.732),l(-.217,-.254),l(-.16,-.988),l(-.438,-.691),l(-.895,-.817),l(-.195,-.663),l(.039,-.494),l(.03,-.283),l(-.107,-.409),l(-.399,-.634),l(-.347,-1.849),l(-.188,-.72),l(.043,-.362),l(.448,-.17),l(.571,-.013),l(.106,.466),l(.447,.119),l(.261,.238),l(.055,.226),l(.041,.21),l(-.213,.398),l(.118,.239),l(.204,.083),l(.244,-.394),l(.279,-.28),l(.309,.163),l(.05,.478),l(.644,-.089),l(.11,-.575),l(.495,-.35),l(.086,-.337),M(643.95,196.042),l(.081,.044),l(.375,.408),l(.397,.141),l(.861,.083),l(.413,.168),l(.761,.436),l(.335,.042),l(.337,-.1),l(-.503,-.535),l(.169,-.551),l(.365,-.608),l(.528,-1.258),l(.584,-.27),l(1.481,-.342),l(1.018,-.299),l(.428,-.326),l(.524,-1.021),l(.523,-.323),l(.87,-1.117),l(.22,-.212),l(.244,-.147),l(.112,-.068),l(.084,.126),l(.062,.37),l(.234,-.012),l(.111,.259),l(.309,.271),l(.383,-.271),l(1.234,-.42),l(-.025,-.086),l(-.197,-.197),l(.013,-.247),l(.024,-.111),l(-.148,-.444),l(-.11,-.174),l(.167,-.042),l(.188,.143),l(.085,-.016),l(.449,-.084),l(.161,-.283),l(-.036,-.24),l(-.478,-.366),l(.197,-.396),l(.436,-.071),l(.511,.041),l(.154,-.605),l(.408,-.313),l(.284,-.48),l(.531,-.58),l(.498,-1.032),l(.075,-.17),l(.322,.465),l(.33,.098),l(.315,-.424),l(.305,.494),l(.351,.282),l(.402,.211),l(.075,.338),l(-.182,.354),l(-.234,.452),l(.037,.198),l(.631,-.128),l(.472,-.128),l(.115,.226),l(-.349,.495),l(.742,-.1),l(.357,-.085),l(.269,.056),l(1.035,.662),l(.345,.14),l(.1,.24),l(-.158,.269),l(-.201,.155),l(-.44,.143),l(-.594,.029),l(-.683,-.083),l(-.355,.311),l(.096,.254),l(.888,.69),l(-.161,.311),l(-.458,.199),l(-.646,.1),l(-.518,.114),l(-.067,.15),l(-.182,-.09),l(-.753,-.292),l(-.446,-.04),l(-.624,.018),l(-.651,-.081),l(-.748,-.081),l(-.464,.017),l(-.247,.157),l(-.381,.638),l(-.119,.565),l(.106,.988),l(-.22,.383),l(-.646,.244),l(-.218,.34),l(.076,.748),l(-.928,1.785),l(-.387,.299),l(-.864,.175),l(-.465,.172),l(-.467,.356),l(-.287,.03),l(-.559,-.152),l(-.524,-.223),l(-.557,-.251),l(-.431,-.11),l(-.479,.074),l(-.531,.441),l(-.403,.525),l(-.528,.342),l(-.399,.172),l(-.543,-.11),l(-.526,-.223),l(-.255,.001),l(-.928,.416),l(-.446,-.28),l(-.304,-.083),l(-1,-.983),l(-.253,-.295),l(-.288,-.792), +N(274.556,195.884),l(.06,-.212),l(-.332,-.563),l(-.49,-1.127),l(-.246,-.832),l(-.185,-.295),l(-.561,-.067),l(-.532,-.675),l(-.571,-.831),l(.328,-.694),l(.095,-.467),l(-.078,-.777),l(.169,-.17),l(1.131,-.091),l(.183,-.27),l(.082,-.862),l(.142,-.496),l(.015,-.339),l(.326,-.312),l(.382,-.057),l(1.392,.463),l(.465,.042),l(.083,-.41),l(.141,-.085),l(.337,.027),l(.833,.012),l(.863,-.03),l(.723,.069),l(.63,.182),l(.999,.427),l(-.647,.876),l(-.391,.751),l(-.137,.594),l(.094,.381),l(.134,.635),l(.086,.664),l(.521,.844),l(.029,.438),l(-.424,1.472),l(-.489,.963),l(-1.05,-.488),l(-.319,.001),l(-.534,.385),l(-.398,.059),l(-.418,-.139),l(-.642,-.124),l(-.172,.156),l(-.2,.326),l(.611,1.014),l(-.528,-.054),l(-1.108,-.276),l(-.4,-.04), +N(285.859,190.719),l(.015,.422),l(-1.102,1.646),l(-.427,.765),l(-.439,.992),l(-.464,.681),l(-.299,.214),l(-.56,-.025),l(-1.11,-.389),l(-.882,.613),l(-.225,-.069),l(-.649,-.505),l(.489,-.963),l(.424,-1.472),l(-.029,-.438),l(-.521,-.844),l(-.086,-.664),l(-.134,-.635),l(-.094,-.381),l(.137,-.594),l(.391,-.751),l(.647,-.876),l(.218,.093),l(1.033,.294),l(.55,.196),l(.799,.549),l(1.264,1.084),l(.545,.564),l(.317,.465),l(.193,.028), +N(429.505,210.684),l(-.695,-.533),l(-.351,.13),l(-.68,.513),l(-.536,.414),l(-.112,-.177),l(-.392,-.86),l(-1.381,-1.344),l(.184,-.295),l(.413,-.229),l(.803,.307),l(.343,-.681),l(-.052,-.296),l(-.274,-.253),l(-.39,-.521),l(-.116,-.366),l(.058,-.495),l(.127,-.1),l(.909,-.146),l(.604,-.243),l(.125,-.213),l(.167,-.807),l(.174,-.185),l(.239,-.029),l(.193,.14),l(.341,.479),l(.405,.521),l(.386,.195),l(.287,-.016),l(.188,-.228),l(.362,-.482),l(.29,.253),l(.167,.578),l(.146,.112),l(.304,.068),l(.255,-.114),l(.184,-.68),l(.243,-1.089),l(.131,-1.229),l(.229,-1.047),l(-.114,-.338),l(-.161,-.127),l(-.384,-.082),l(-.528,-.208),l(-.242,-.31),l(-.132,-.437),l(.008,-.109),l(.021,-.3),l(.157,-.284),l(.492,-.398),l(.556,-.441),l(.094,-.354),l(-.389,-.902),l(-.369,-.322),l(-.592,-.067),l(-.939,.5),l(-.463,-.025),l(-.146,-.253),l(-.068,-.734),l(.077,-.679),l(.396,-.468),l(.56,.109),l(.863,.023),l(.878,-.076),l(.271,.055),l(.479,.04),l(.56,.124),l(.576,.194),l(.864,.334),l(.863,.292),l(.271,-.086),l(-.1,-.861),l(.159,-.185),l(.303,-.312),l(.365,-.497),l(.158,-.523),l(.222,-1.287),l(.255,-.228),l(.479,-.102),l(.975,-.175),l(.367,.054),l(.624,.138),l(.895,.093),l(.751,-.287),l(.128,.197),l(-.031,.156),l(-.398,1.203),l(-.558,.837),l(-.349,.821),l(-.094,.551),l(-.156,.764),l(-.196,2.021),l(-.254,1.342),l(-.115,.61),l(-.169,.708),l(-.139,.523),l(-.459,.427),l(-.525,.229),l(-.809,.599),l(-.41,.454),l(-.47,.836),l(-.343,.751),l(-.193,1.159),l(-.074,.396),l(.122,.72),l(-.086,.706),l(-1.025,.938),l(-.364,.229),l(-.931,.811),l(-.554,.399),l(-.57,.328),l(-.147,-.211),l(-.042,-.664),l(-.054,-.424),l(-1.495,.532),l(-.327,.581),l(-.443,.271),l(-.177,-.013),l(-.484,-.336), +N(425.506,195.522),l(.045,-.495),l(.88,.093),l(1.773,.088),l(.831,.038),l(1.022,.149),l(-.396,.468),l(-.077,.679),l(.068,.734),l(.146,.253),l(.463,.025),l(.939,-.5),l(.592,.067),l(.369,.322),l(.389,.902),l(-.094,.354),l(-.556,.441),l(-.492,.398),l(-.157,.284),l(-.021,.3),l(-.008,.109),l(.132,.437),l(.242,.31),l(.528,.208),l(.384,.082),l(.161,.127),l(.114,.338),l(-.229,1.047),l(-.131,1.229),l(-.243,1.089),l(-.184,.68),l(-.255,.114),l(-.304,-.068),l(-.146,-.112),l(-.167,-.578),l(-.29,-.253),l(-.362,.482),l(-.188,.228),l(-.287,.016),l(-.386,-.195),l(-.405,-.521),l(-.341,-.479),l(-.193,-.14),l(-.239,.029),l(-.174,.185),l(-.167,.807),l(-.125,.213),l(-.604,.243),l(-.909,.146),l(-.127,.1),l(-.058,.495),l(.116,.366),l(.39,.521),l(.274,.253),l(.052,.296),l(-.343,.681),l(-.803,-.307),l(-.413,.229),l(-.184,.295),l(-.038,-.037),l(-.563,-.493),l(-.532,-.55),l(-.259,-.466),l(-1.318,-1.169),l(.286,-.312),l(-.369,-.281),l(-.528,-.056),l(-.918,-1.438),l(.382,-.297),l(.111,-.1),l(-.321,-.395),l(-.464,-.14),l(-.29,-.564),l(-.369,-.451),l(.319,-.17),l(.541,-.411),l(.223,-.396),l(.291,-.976),l(.089,-.295),l(.415,.07),l(.495,.013),l(-.064,-.211),l(-.56,-.352),l(-.561,-.451),l(.208,-.042),l(.271,-.128),l(.142,-.617),l(.83,-.043),l(.927,.008),l(1.245,.021),l(.575,-.032),l(-.001,-.155),l(-.02,-.551),l(-.026,-1.836), +N(422.536,195.513),l(1.005,-.007),l(1.965,.017),l(.026,1.836),l(.02,.551),l(.001,.155),l(-.575,.032),l(-1.245,-.021),l(-.927,-.008),l(-.83,.043),l(.033,-.146),l(-.049,-.297),l(-.144,-.084),l(-.416,-.098),l(.287,-.467),l(.447,-.523),l(.335,-.58),l(.066,-.403),M(419.636,193.273),l(-.484,-.049),l(-.049,-.218),l(.049,-.291),l(.242,-.097),l(.024,-.146),l(0,-.291),l(.17,-.097),l(.169,-.121),l(.219,.048),l(.218,.048),l(.097,.194),l(-.193,.169),l(-.146,.243),l(-.17,.339),l(-.146,.267), +N(222.291,207.801),l(.188,-.126),l(.264,-.312),l(.585,-1.061),l(.038,-.269),l(-.209,-.733),l(.058,-.391),l(-.478,.617),l(-.732,.623),l(-.333,-.098),l(-.601,-.324),l(-.408,-.408),l(.389,-.283),l(.1,-.24),l(-.167,-.579),l(.005,-.438),l(.133,-.466),l(-.109,-.282),l(-.362,-.649),l(.193,-.17),l(.48,-.198),l(.721,-.454),l(-.319,-.395),l(0,-.226),l(.175,-.354),l(.497,-.462),l(.157,-.146),l(.14,-.848),l(-.116,-.452),l(-.082,-.184),l(.11,-.226),l(.686,-.101),l(.891,-.341),l(.396,-.241),l(.474,-.382),l(.09,-.186),l(1.496,.803),l(1.432,.656),l(.227,.225),l(.166,.493),l(.355,.309),l(.977,.277),l(.67,-.061),l(.89,-.401),l(.128,.056),l(.709,.631),l(.197,.118),l(.269,.162),l(.081,.112),l(.387,.76),l(.321,.789),l(-.08,.255),l(-.352,.384),l(-.547,1.147),l(-.533,.779),l(-.71,.725),l(-1.001,.755),l(-.336,.087),l(-1.028,.303),l(-.901,.358),l(-.809,.499),l(-.59,.653),l(-.284,.51),l(-.987,2.506),l(-.267,.312),l(-.242,.072),l(-.398,-.068),l(-.398,-.491),l(-.191,-.479),l(-.312,-.252),l(-.815,.005),l(-.444,-.11),l(-.105,-.197),l(-.097,-.494),l(.233,-.34),l(.029,-.495),l(.005,-.569), +N(245.934,224.314),l(1.109,1.843),l(.922,1.646),l(.08,.24),l(-.437,.736),l(-.15,.523),l(-.143,.848),l(.057,.522),l(.236,.902),l(-.156,.34),l(-.221,.34),l(-.532,.582),l(-.102,.452),l(.347,.845),l(-.21,.368),l(-.159,.34),l(.022,.48),l(.604,1.168),l(.015,.522),l(-.285,.439),l(-.723,.61),l(-.12,.227),l(.049,.48),l(.132,.295),l(.018,.142),l(-.586,.187),l(-.15,.199),l(-.228,.933),l(-.259,.298),l(-.852,.275),l(-.201,-.517),l(-.289,-.31),l(-1.422,-.618),l(-.313,-.239),l(-.233,-.678),l(-.315,-.38),l(-.559,-.225),l(-.504,-.281),l(-.489,-.254),l(-.616,-.309),l(-.873,-.464),l(-.673,-.366),l(-.866,-.379),l(-.838,-.337),l(-1.271,-.845),l(-1.354,-.985),l(-1.232,-1.099),l(-.594,-.705),l(-.42,-.677),l(.008,-.438),l(0,-.903),l(-.269,-.606),l(-.781,-1.043),l(-1.389,-2.778),l(-.285,-.268),l(-.467,-.211),l(-.074,-.085),l(.055,-.536),l(-.02,-.396),l(-.149,-.396),l(-1.208,-2.199),l(-.997,-1.961),l(-.688,-1.27),l(-1.365,-1.917),l(-.272,-.353),l(-.598,-.973),l(-.462,-.423),l(-.75,-.437),l(-.914,-.365),l(-.61,-.365),l(.119,-.17),l(.181,-.113),l(.609,-.029),l(.144,-.41),l(-.118,-.282),l(-.592,-.874),l(-.353,-.437),l(-.258,-.72),l(.01,-.24),l(.244,-.523),l(.582,-.622),l(1.02,-.878),l(.47,-.198),l(.317,-.214),l(-.005,.569),l(-.029,.495),l(-.233,.34),l(.097,.494),l(.105,.197),l(.444,.11),l(.815,-.005),l(.312,.252),l(.191,.479),l(.398,.491),l(.398,.068),l(.242,-.072),l(.267,-.312),l(.987,-2.506),l(.284,-.51),l(.59,-.653),l(.809,-.499),l(.901,-.358),l(1.028,-.303),l(.336,-.087),l(1.001,-.755),l(.71,-.725),l(.533,-.779),l(.547,-1.147),l(.352,-.384),l(.08,-.255),l(-.321,-.789),l(-.387,-.76),l(.927,.107),l(.897,.418),l(.513,.435),l(.208,.324),l(.208,.62),l(.526,.364),l(.988,.672),l(.251,.761),l(.078,.282),l(.366,.14),l(.479,.039),l(.173,.296),l(-.004,.396),l(.092,.281),l(.573,.152),l(1.038,.008),l(.496,-.031),l(.337,-.157),l(.452,-.427),l(.523,.421),l(.397,.182),l(.708,-.442),l(.509,.209),l(1.299,.84),l(.127,.069),l(-.035,.198),l(-1.155,1.956),l(.448,-.031),l(.161,-.058),l(.237,.126),l(.575,.703),l(.156,.14),l(.136,.324),l(-.341,.186),l(-.793,-.235),l(-.493,-.096),l(-.322,.072),l(-.604,.441),l(-.371,.115),l(-.669,-.066),l(-1.895,.773),l(-.701,.442),l(-.372,.172),l(-.599,1.415),l(-.319,.511),l(-.021,.155),l(.277,.86),l(.012,.112),l(-.625,.498),l(-.62,.328),l(-.349,.342),l(-.247,.622),l(.106,.564),l(.619,.957),l(1.333,2.166),l(.106,.127),l(-.247,.495),l(-.208,.312),l(1.085,.12),l(.415,.04),l(.312,.182),l(.241,.323),l(.096,.663),l(1.843,.032),l(.762,-.499),l(.648,-.484),l(.326,-.114),l(-.059,1.511),l(-.098,1.173),l(.108,.353),l(.317,.337),l(.285,.068),l(.358,-.072),l(.786,-.259),l(.42,-.045), +N(279.288,257.295),l(-.063,-.423),l(.027,-.777),l(.222,-.819),l(.298,-.835),l(.321,-.75),l(-.019,-.141),l(-.491,-.336),l(-.234,-.112),l(-1.29,.445),l(-.224,-.055),l(-.254,-.563),l(-.487,-2.524),l(-.121,-.437),l(-.843,-.404),l(-.724,-.278),l(-.115,.001),l(-.709,.413),l(-.346,.03),l(-.925,-.221),l(-.818,-.15),l(-.372,-.04),l(.006,-.72),l(.086,-.721),l(.132,-.862),l(-.104,-.959),l(-.521,-.872),l(-.084,-.663),l(-.253,-.408),l(.421,-.666),l(.38,-.765),l(.238,-.834),l(.185,-1.173),l(-.022,-.494),l(-.307,-.774),l(-.316,-.479),l(-.73,-.362),l(-.436,-.407),l(-.067,-.563),l(.261,-.835),l(-.042,-.296),l(-.693,-.024),l(-1.615,-.019),l(-.5,-.012),l(-.967,-.036),l(-.153,-.112),l(-.249,-.944),l(-.138,-2.032),l(-.03,-.706),l(-.203,-1.029),l(.038,-.565),l(-.085,-.169),l(-.403,-.237),l(-.537,-.166),l(-.636,-.123),l(-1.148,.077),l(-.22,-.084),l(-.398,-.308),l(-.385,-.774),l(-.096,-.014),l(-.882,-.037),l(-.3,-.098),l(-.75,-.603),l(-.688,-.307),l(-.676,-.25),l(-.355,.03),l(-.787,-.023),l(-.316,-.097),l(-1.1,-.939),l(-.813,-.928),l(-.335,-.591),l(-.141,-.635),l(-.036,-.818),l(.064,-.622),l(.079,-.621),l(-.045,-.748),l(-1.283,-.021),l(-.934,.076),l(-.36,.158),l(-.874,.485),l(-1.471,1.109),l(-.415,.243),l(-.48,-.025),l(-.336,-.026),l(-.946,.824),l(-.355,.03),l(-1.122,-.304),l(-.939,-.136),l(-.42,.045),l(-.786,.259),l(-.358,.072),l(-.285,-.068),l(-.317,-.337),l(-.108,-.353),l(.098,-1.173),l(.059,-1.511),l(-.326,.114),l(-.648,.484),l(-.762,.499),l(-1.843,-.032),l(-.096,-.663),l(-.241,-.323),l(-.312,-.182),l(-.415,-.04),l(-1.085,-.12),l(.208,-.312),l(.247,-.495),l(-.106,-.127),l(-1.333,-2.166),l(-.619,-.957),l(-.106,-.564),l(.247,-.622),l(.349,-.342),l(.62,-.328),l(.625,-.498),l(-.012,-.112),l(-.277,-.86),l(.021,-.155),l(.319,-.511),l(.599,-1.415),l(.372,-.172),l(.701,-.442),l(1.895,-.773),l(.669,.066),l(.371,-.115),l(.604,-.441),l(.322,-.072),l(.493,.096),l(.793,.235),l(.341,-.186),l(-.136,-.324),l(.133,-.198),l(.073,-.382),l(.706,-4.411),l(.326,-1.428),l(-.031,-.212),l(-.399,-.562),l(.031,-.777),l(-.192,-.183),l(-.688,-.363),l(-.192,-.197),l(0,-.554),l(.001,-1.071),l(.111,-.085),l(.493,-.187),l(.687,-.032),l(.417,.11),l(.384,.04),l(-.052,-.367),l(-.293,-.408),l(-.177,-.084),l(-.896,-.122),l(-.178,-.154),l(.013,-1.031),l(.042,-.325),l(.64,.024),l(2.812,.082),l(.463,-.017),l(.412,-.158),l(.834,-.57),l(.52,-.286),l(.148,.168),l(.138,.437),l(.161,.861),l(.088,.452),l(.199,.437),l(.432,.054),l(.694,.546),l(.482,.223),l(.414,-.073),l(.757,-.697),l(.083,.183),l(.186,.776),l(.271,-.016),l(.645,-.739),l(.74,-.654),l(.554,-.286),l(.652,-.173),l(.235,-.213),l(.259,-.666),l(.203,-.199),l(.652,-.131),l(.569,-.272),l(.265,-.27),l(-.15,-.253),l(-.434,-.125),l(-.96,-.051),l(-.166,-.239),l(-.079,-.55),l(-.302,-1.524),l(-.391,-.69),l(-.616,-.688),l(.041,-.184),l(.159,-.029),l(.309,.125),l(.896,.461),l(.385,.04),l(1.149,-.035),l(.344,.224),l(.628,.618),l(.348,-.115),l(.232,-1.117),l(.284,-.115),l(.465,.054),l(.557,-.074),l(.807,-.23),l(1.74,-.9),l(.592,-.385),l(.163,-.326),l(-.103,-.169),l(.375,-.257),l(.302,-.058),l(.516,.124),l(.26,.111),l(.04,.212),l(-.452,1.09),l(.304,-.001),l(.533,.138),l(.435,.958),l(-.179,.368),l(-.547,1.416),l(-.213,.962),l(.156,.465),l(.281,.394),l(.167,.31),l(-.072,.354),l(.008,.396),l(.15,.296),l(1.103,.897),l(.613,.392),l(.686,-.075),l(.694,-.513),l(.505,-.314),l(1,-.331),l(.934,-.429),l(.943,.022),l(.4,.04),l(1.108,.276),l(.528,.054),l(-.611,-1.014),l(.2,-.326),l(.172,-.156),l(.642,.124),l(.418,.139),l(.398,-.059),l(.534,-.385),l(.319,-.001),l(1.05,.488),l(.649,.505),l(.225,.069),l(.882,-.613),l(1.11,.389),l(.56,.025),l(.299,-.214),l(.464,-.681),l(.439,-.992),l(.427,-.765),l(1.102,-1.646),l(-.015,-.422),l(.409,-.241),l(.276,.141),l(.235,.423),l(.164,.791),l(.414,1.34),l(.108,.607),l(.472,1.383),l(.296,.55),l(.324,.324),l(.978,.21),l(.196,.338),l(.038,.551),l(-.045,.254),l(-.524,.354),l(-.933,1.414),l(-.238,.325),l(-.51,.411),l(-.41,.231),l(-.244,.138),l(-.798,.778),l(-.544,.947),l(-.419,1.018),l(-.402,.453),l(.271,.112),l(.512,-.072),l(.497,-.198),l(1.202,-.709),l(.112,-.028),l(.299,.889),l(.442,.818),l(.255,.112),l(.287,.07),l(1.135,-.031),l(.592,-.058),l(.737,-.298),l(-.277,.679),l(-.017,.584),l(.448,-.557),l(1.254,-1.006),l(.289,-.156),l(.306,-.382),l(.499,-.933),l(.272,-.396),l(.256,-.099),l(1.006,-.003),l(.352,-.198),l(.175,0),l(.687,.549),l(.654,.267),l(.32,-.028),l(.814,.28),l(1.069,.45),l(.334,.281),l(.269,.593),l(.08,.028),l(.176,-.015),l(.402,-.354),l(.319,.042),l(.302,.254),l(.538,.789),l(.205,.396),l(-.13,.254),l(-.308,.41),l(-.116,.424),l(.091,.466),l(.171,.396),l(.825,-.821),l(.369,-.156),l(.609,-.156),l(.995,-.454),l(.224,-.028),l(.367,.069),l(.764,.38),l(.907,.436),l(.462,.098),l(1.117,.167),l(1.118,.083),l(.464,-.058),l(.48,-.029),l(.577,-.171),l(.416,-.016),l(1.131,.351),l(.731,.408),l(.762,.479),l(.586,.437),l(1.595,1.395),l(.742,.662),l(.821,.605),l(.41,.338),l(.477,.196),l(.734,.168),l(1.247,.097),l(.912,.04),l(.445,.197),l(.265,.465),l(.087,.607),l(.592,2.004),l(.268,1.143),l(.062,.988),l(-.076,.579),l(-.179,.904),l(-.243,.848),l(-.559,1.301),l(-.518,.849),l(-1.347,1.175),l(-1.388,1.288),l(-.44,.198),l(-.354,.043),l(-.39,.637),l(-.094,.396),l(-.012,.353),l(-.504,1.074),l(-.6,.976),l(-.8,1.104),l(-.266,.212),l(-.194,.015),l(-.079,-.423),l(-.278,-.296),l(-.367,-.084),l(-.064,.79),l(-.538,1.64),l(-.049,.734),l(-.077,.607),l(.318,2.738),l(.078,.988),l(-.577,2.543),l(-.039,.663),l(.14,.649),l(.043,.085),l(-.759,.495),l(-.404,.51),l(-.261,.791),l(-.04,.367),l(.245,1.468),l(-.106,.367),l(-.214,.283),l(-.676,.608),l(-.752,1.498),l(-1.01,1.4),l(-.201,.537),l(-.055,.311),l(.144,.945),l(-1.203,.37),l(-.544,.283),l(-.355,.368),l(-.084,.466),l(.021,.367),l(-.401,.114),l(-.864,-.041),l(-.979,.172),l(-.654,.001),l(-.764,-.055),l(-.465,-.112),l(-.922,.072),l(-.736,.002),l(-.214,.607),l(-.295,.198),l(-.795,.312),l(-.481,.453),l(-.21,.354),l(-.747,-.267),l(-.35,.071),l(-.563,.255),l(-1.864,1.232),l(-.528,.396),l(-.725,.383),l(-.616,.438),l(-.532,.679),l(-.486,.241),l(-.567,.072),l(-.278,-.014),l(.006,.24),l(.336,.225),l(.12,.536),l(-.111,.537),l(-.099,.282),l(-.282,.156),l(-.084,.155),l(.384,.648),l(.036,1.186),l(.05,1.045),l(-.057,.311),l(-.11,.594),l(-.198,.621),l(-.464,.735),l(-.566,.495),l(-.788,.524),l(-.866,1.046),l(-.208,.396),l(-.476,1.145),l(-.499,.933),l(-.75,1.004),l(-.69,.623),l(-.801,.78),l(.321,-.808),l(.436,-.594),l(.629,-.566),l(.605,-1.158),l(-.06,-.254),l(-.356,.142),l(-.397,-.014),l(-.633,-.21),l(-.075,.155),l(.002,.297),l(-.401,1.215),l(-.349,.48),l(-.661,.438),l(-.317,.283),l(-.225,.424),l(-.013,.354),l(-.448,1.709),l(-.481,.763),l(-.787,.934),l(-1.076,.979),l(-.101,-.313),l(-.258,-.746),l(.103,-.269),l(.634,-.766),l(.017,-.269),l(-.333,-.379),l(-.163,-.027),l(-.131,-.197),l(-.853,-1.109),l(-.474,-.435),l(-.999,-.587),l(-.55,-.194),l(-.617,-.194),l(-.432,-.576),l(-.365,-.393),l(-.693,.427),l(-.27,.016),l(-.232,-.38),l(-.59,-.814),l(-.379,-.407),l(-.47,-.364),l(-.266,-.098),l(-.25,.101),l(-1.042,.246),l(-.55,.003),l(.214,-.27),l(.833,-.88),l(1.805,-1.816),l(1.435,-1.363),l(1.633,-1.448),l(.348,-.242),l(1.754,-.744),l(.521,-.313),l(.161,-.467),l(.094,-1.638),l(-.517,-1.154),l(-.206,-.196),l(-.462,.017),l(-.957,.161),M(288.966,203.943),l(-.558,-.125),l(-.301,-.536),l(-.078,-.382),l(.16,-.197),l(-.094,-.636),l(.048,-.381),l(.208,-1.018),l(.176,-.099),l(.479,-.058),l(.879,.097),l(1.007,.11),l(.479,-.199),l(.368,.028),l(.479,.168),l(.479,.083),l(.319,.155),l(-.335,.538),l(-.193,.946),l(-.257,.494),l(-.289,.312),l(-.561,.326),l(-.464,.171),l(-.527,.015),l(-.783,.016),l(-.641,.171), +N(732.92,214.323),l(-.164,-.24),l(-.225,-.197),l(-.379,-.126),l(-.416,.198),l(-.399,-.38),l(-.287,-.184),l(-.659,-.238),l(-.243,-.239),l(.156,-.255),l(.29,.027),l(.731,-.058),l(.538,.126),l(.743,.083),l(.523,-.058),l(.258,-.185),l(.232,-.509),l(.056,.099),l(.351,.395),l(.286,.184),l(.241,.014),l(.961,-.2),l(.366,-.227),l(.361,-.722),l(.241,-.212),l(.653,-.029),l(.263,-.128),l(.04,-.282),l(-.064,-.565),l(-.043,-.536),l(.495,.196),l(.404,.056),l(.324,-.354),l(.318,.578),l(.077,.353),l(-.196,.495),l(-.099,.184),l(-.509,.044),l(-.159,.226),l(.061,.17),l(.437,.479),l(-.308,.354),l(-.264,.113),l(-.742,-.083),l(-.416,.001),l(-.091,.269),l(-.408,.495),l(-.275,.156),l(-.973,.426),l(-.484,.143),l(-.798,.029),l(-.807,.115),M(713.795,220.696),l(.031,-3.438),l(-.046,-.805),l(-.431,-1.368),l(.44,-.822),l(-.169,-7.966),l(2.581,.802),l(.85,.337),l(1.04,.295),l(1.254,.378),l(.848,.507),l(.613,.323),l(.597,.084),l(.38,-.058),l(.26,.508),l(.274,.254),l(.635,.352),l(.687,.395),l(.779,.718),l(-.3,.947),l(.033,.226),l(.305,.226),l(.665,.111),l(1.887,.787),l(.354,.027),l(.72,.183),l(.181,.254),l(.413,.535),l(.211,.579),l(-.166,.113),l(-1.114,.073),l(-.563,.156),l(-.098,.155),l(.047,.339),l(.589,.987),l(.5,.521),l(1.464,1),l(.218,.847),l(.725,1.044),l(.288,.141),l(.304,-.015),l(.712,-.086),l(.338,.013),l(.087,.198),l(-.354,.551),l(.218,.212),l(.401,.141),l(.423,.041),l(.63,.168),l(.096,.127),l(-.031,.142),l(-.648,.213),l(.287,.24),l(1.064,.28),l(.538,.295),l(.235,.763),l(-.064,.226),l(-1.094,-.012),l(-.215,-.154),l(-.146,-.466),l(-.126,-.099),l(-1.011,-.111),l(-1.063,-.266),l(-.644,-.126),l(-.752,.016),l(-.774,-.026),l(-.573,-.211),l(-.494,-.352),l(-.223,-.522),l(-.24,-.268),l(-.726,-.31),l(-.472,-.338),l(-.135,-.197),l(-1.089,-1.608),l(-.613,-.817),l(-.454,-.056),l(-1.524,-.336),l(-.671,-.31),l(-.55,-.055),l(-.415,.185),l(-.394,.071),l(-.78,-.45),l(.282,.762),l(-.027,.212),l(-.249,.071),l(-.382,-.126),l(-.311,.1),l(.296,.395),l(-.116,.113),l(-1.037,.045),l(-1.125,-.182),l(-.478,.029),l(.237,.127),l(.24,.154),l(.642,.169),l(.662,.352),l(.404,.338),l(.219,.395),l(-.411,.199),l(-.739,.425),l(-.458,.213),l(-.668,-.097),l(-1.801,-.039),l(-1.219,-.092), +N(726.605,297.247),l(-.479,-.229),l(-1.179,-.471),l(-.543,-.371),l(-.508,-.715),l(-.477,-.558),l(-.216,-.414),l(.264,-.044),l(.169,.1),l(.421,.171),l(.129,-.143),l(-.209,-.387),l(-.703,-.699),l(-.617,-.713),l(-.149,-.257),l(-.375,-.956),l(-.008,-.67),l(.177,-.044),l(1.004,.312),l(1.476,.354),l(1.089,.369),l(.797,-.03),l(.463,-.144),l(.382,-.115),l(.373,-.058),l(.684,.027),l(.306,-.301),l(.716,-.244),l(.475,.385),l(-.009,.1),l(.128,.8),l(-.009,.686),l(-.751,1.503),l(-.124,.758),l(-.245,.315),l(-.943,.26),l(-.553,.388),l(-.49,.689),l(-.189,.272),l(-.274,.072),M(716.883,224.344),l(.682,.394),l(.233,.509),l(.047,.649),l(.118,.678),l(.256,.197),l(.42,.013),l(.102,.24),l(-.45,.919),l(.715,.338),l(.175,.282),l(.147,.593),l(.08,1.3),l(.144,.621),l(.456,1.157),l(.293,.268),l(.422,.014),l(.328,-.312),l(.384,-.185),l(.32,.663),l(.363,.127),l(.563,.408),l(.385,.154),l(.144,.155),l(.002,.41),l(.083,.96),l(.275,.776),l(-.046,1.06),l(.279,.24),l(.93,1.325),l(.276,.706),l(.055,.777),l(-.209,.876),l(.403,.649),l(.275,.833),l(.204,.353),l(1.395,.803),l(.285,.154),l(.744,.111),l(.402,.649),l(.843,.535),l(.483,.169),l(1.141,.068),l(.117,.197),L(731,245.42),l(-.273,.565),l(.309,.424),l(.879,.479),l(.22,.564),l(.469,1.342),l(.211,.748),l(.112,.396),l(.252,.311),l(.771,.352),l(-.021,-.127),l(-.141,-.777),l(.913,.507),l(.567,.154),l(.184,.127),l(.136,.296),l(.106,1.752),l(.884,.762),l(.573,.323),l(.604,.154),l(.287,.296),l(.244,.579),l(.229,.424),l(.545,.168),l(.176,.297),l(.007,.269),l(.19,.536),l(.106,.113),l(.506,.126),l(.156,.112),l(.162,.354),l(.366,1.327),l(.026,.876),l(.013,.862),l(-.132,.41),l(-.181,.325),l(.778,1.271),l(.223,.48),l(.181,.833),l(.034,.749),l(-.293,.708),l(-.353,1.668),l(-.585,1.755),l(.137,.791),l(-.065,.806),l(-.306,.778),l(-.661,.977),l(-.203,.665),l(-.598,.821),l(-.45,.185),l(-.465,.1),l(-.423,.468),l(-.466,.68),l(-.328,1.527),l(-.477,.638),l(-.34,.495),l(.014,.65),l(-.208,.539),l(-.331,.312),l(-.601,.341),l(-.27,.326),l(-.3,1.021),l(-.169,1.049),l(-.079,.937),l(.021,.666),l(-.283,.64),l(-.322,.354),l(-.463,.3),l(-.754,.101),l(-1.158,.087),l(-.82,.03),l(-.527,.157),l(-.516,.299),l(-1.529,.94),l(-.443,.129),l(-.214,.284),l(-.346,.071),l(-.528,.059),l(-.286,-.014),l(.295,.368),l(.209,.27),l(-1.315,-.665),l(-.885,-.353),l(.003,-.469),l(-.073,-.156),l(-.56,-.467),l(-.628,-.368),l(-.421,-.014),l(-.485,.172),l(-.335,.242),l(.748,.467),l(-.97,.243),l(-.929,.428),l(-.953,.442),l(-.222,.028),l(-.604,-.226),l(-.886,-.438),l(-.67,-.226),l(-1.086,-.311),l(-.51,-.041),l(-.239,.156),l(-.044,.113),l(-.716,-.169),l(-.751,-.353),l(-.522,-.298),l(-.896,-.82),l(-.526,-.34),l(-.422,-.879),l(.09,-1.035),l(-.082,-.411),l(-.184,-.495),l(-.664,-.736),l(-.141,-.523),l(-.029,-.425),l(-.534,-.014),l(-.786,.398),l(-.597,.114),l(-.34,.058),l(-.178,-.07),l(-.167,-.17),l(.517,-.454),l(.233,-.567),l(.073,-.821),l(-.253,-.324),l(-.536,-.593),l(-.247,-.353),l(-.485,.735),l(-.443,1.431),l(-.19,.113),l(-.796,.002),l(-.199,.156),l(-.196,.015),l(-.255,.028),l(.198,-.396),l(.081,-.396),l(.079,-.1),l(.634,.041),l(.242,-.142),l(.126,-.255),l(-.105,-1.004),l(.454,-.835),l(.328,-.453),l(.091,-.396),l(.018,-.409),l(.151,-.128),l(.245,-.015),l(.218,-.354),l(-.052,-.227),l(-.323,-.494),l(-.338,-.494),l(-.107,.707),l(-.288,.255),l(-.518,.299),l(-.311,.467),l(-.086,.155),l(-.189,.467),l(-.281,.326),l(-.747,.242),l(-.735,.481),l(-.653,.567),l(-.36,.693),l(-.514,.808),l(-.41,-.339),l(-.38,-1.328),l(-.263,-.579),l(-.19,-.325),l(-.688,-.79),l(-.297,-.734),l(-.176,-.212),l(-.704,.072),l(-.235,-.099),l(-.139,-.24),l(-.085,-.269),l(.334,-.34),l(-.047,-.297),l(-.346,-.395),l(-.543,-.494),l(-.266,-.098),l(-.83,.157),l(-.486,-.07),l(-.95,-.549),l(-.274,-.014),l(-.438,.17),l(-.433,-.027),l(-.421,-.183),l(-.662,-.521),l(-.921,-.437),l(-.218,.001),l(-.723,.213),l(-1.282,.088),l(-.669,.001),l(-1.764,.061),l(-.611,.129),l(-.656,.213),l(-.989,.44),l(-.972,.256),l(-1.039,.257),l(-1.503,.088),l(-.794,-.013),l(-.383,.044),l(-.927,.284),l(-.993,.469),l(-.773,.397),l(-.538,.143),l(-.431,.085),l(-.361,.199),l(-.615,.693),l(-.774,1.02),l(-.588,.284),l(-.766,-.013),l(-.547,-.013),l(-.927,.143),l(-.4,.185),l(-.663,-.395),l(-.294,-.084),l(-.734,.016),l(-1.572,.173),l(-.938,.157),l(-.459,-.041),l(-.672,.044),l(-.398,.227),l(-.583,.793),l(-.344,.128),l(-.958,-.125),l(-.158,.057),l(-.57,.708),l(-.465,.368),l(-.919,.271),l(-.586,.086),l(-1.516,-.082),l(-.638,-.055),l(-.688,-.197),l(-.633,-.366),l(-.778,-.677),l(-.74,-.353),l(-.374,-.041),l(-.151,-.07),l(-.19,-1.229),l(.055,-.255),l(.489,.112),l(.45,-.086),l(.332,-.425),l(.197,-.467),l(.267,-1.357),l(-.043,-1.215),l(-.156,-.622),l(-.258,-.593),l(-1.117,-1.906),l(-.208,-.635),l(-.144,-.834),l(.027,-.989),l(-.16,-.692),l(-.467,-1.072),l(-.663,-.945),l(-.603,-.734),l(-.214,-.254),l(.128,-.904),l(-.215,-.536),l(-.733,-1.115),l(-.972,-1.018),l(-.273,-.583),l(.126,-.233),l(.188,.187),l(.152,.443),l(.183,.163),l(.235,.35),l(.327,.188),l(.354,.023),l(-.348,-1.144),l(-.437,-.396),l(-.226,-.326),l(.08,-.304),l(.748,.84),l(.495,.979),l(.477,.065),l(-.099,-.555),l(.289,-.039),l(.004,-.564),l(-.282,-.48),l(-1.03,-1.368),l(-.354,-.691),l(-.119,-.579),l(-.038,-.734),l(.355,-.595),l(.323,-.523),l(.21,-.664),l(-.083,-1.031),l(-.254,-.635),l(.033,-.368),l(.438,-.692),l(.109,-.325),l(.064,-.156),l(.271,.649),l(.011,.424),l(.105,.184),l(.35,.027),l(.171,-.113),l(.187,-.565),l(.141,-.48),l(.765,-.468),l(1.22,-.624),l(.484,-.326),l(.676,-.581),l(.585,-.467),l(.632,-.327),l(.79,-.114),l(.697,-.016),l(.7,-.002),l(.431,-.043),l(.352,-.185),l(.474,-.453),l(.494,-.128),l(.929,-.072),l(.279,-.143),l(.291,-.551),l(.158,-.1),l(.444,.027),l(.877,.224),l(.626,-.043),l(.911,-.299),l(1.084,-.469),l(.359,-.213),l(.716,-.665),l(.427,-.58),l(.29,-.622),l(.132,-.297),l(.41,-.369),l(.968,-.651),l(.079,-.17),l(-.067,-.409),l(-.242,-.805),l(-.016,-.495),l(1.063,-1.118),l(.387,-.692),l(.291,.169),l(.341,.437),l(.619,1.355),l(.262,.253),l(.177,-.579),l(.021,-.466),l(.436,.238),l(.272,.07),l(.189,-.607),l(-.06,-.142),l(-.563,-.238),l(-.175,-.24),l(.007,-.565),l(.044,-.112),l(.897,.04),l(.661,.253),l(.642,-.029),l(.334,-.029),l(.289,.074),l(-.699,-.455),l(-.431,-.141),l(.128,-.537),l(-.07,-.296),l(.135,-.509),l(.422,-.354),l(.165,-.07),l(.732,.394),l(.202,-.043),l(-.112,-.452),l(.11,-.48),l(.146,-.367),l(-.041,-.522),l(.358,-.171),l(.4,-.113),l(.813,.04),l(.529,-1.088),l(.371,-.298),l(.35,.169),l(.268,.451),l(.265,-.552),l(.222,-.227),l(.197,-.48),l(.695,.62),l(.513,.084),l(.293,.211),l(.331,.536),l(.632,.592),l(.122,.706),l(-.072,.594),l(.181,.197),l(.256,-.283),l(.462,-.679),l(.155,-.128),l(1.16,.082),l(.479,.155),l(.637,.492),l(.332,.141),l(.156,-.48),l(.302,-.297),l(.022,-.24),l(-.266,-.324),l(-.601,-.395),l(-.079,-.184),l(.008,-.24),l(.145,-.099),l(.604,-.538),l(.007,-.452),l(.191,-.213),l(.518,-.283),l(.268,-.241),l(.151,-.269),l(-.094,-.184),l(.003,-.296),l(.512,-.863),l(.121,-.057),l(.317,-.029),l(.397,-.029),l(.248,-.17),l(-.205,-.409),l(.377,-.396),l(.344,-.071),l(.793,.366),l(.616,-.072),l(1.291,-.088),l(.512,-.128),l(.232,-.17),l(.04,-.057),l(-.077,-.197),l(-.2,-.734),l(-.248,-.282),l(-.471,-.268),l(-.374,.086),l(-.244,-.141),l(.035,-.212),l(.367,-.143),l(.396,-.043),l(.617,.521),l(.255,.099),l(.34,-.1),l(.364,.31),l(.676,.465),l(.36,.154),l(1.297,.294),l(.591,.084),l(.413,-.143),l(.372,.014),l(.396,.606),l(.419,.112),l(.141,-.029),l(.562,-.438),l(.454,.027),l(.652,.38),l(.331,.479),l(.46,-.143),l(.122,-.791),l(.181,-.085),l(.455,.465),l(.337,.099),l(.152,.154),l(-.436,.411),l(-.126,.424),l(-.176,.212),l(-.011,.438),l(-.12,.255),l(-.513,.015),l(-.51,.228),l(-.396,.34),l(-.004,.551),l(.301,.353),l(-.187,.692),l(-.381,.58),l(-.559,.481),l(-.155,.48),l(.063,.17),l(.469,.437),l(1.038,.619),l(.81,.677),l(.508,.606),l(.246,.099),l(.349,-.114),l(.264,.027),l(.782,.352),l(.742,.465),l(.434,.451),l(.679,.535),l(.335,.127),l(.442,.027),l(.784,.182),l(.25,.184),l(.218,.621),l(.167,.169),l(.507,.31),l(.76,.423),l(.537,.154),l(.422,-.072),l(.414,-.17),l(.603,-.199),l(.208,-.156),l(.736,-1.344),l(.403,-1.131),l(.194,-1.314),l(.259,-.721),l(.43,-.679),l(-.131,-.424),l(-.409,-.621),l(.022,-.311),l(.236,-.637),l(.187,-.48),l(-.164,-.282),l(-.183,-.395),l(.088,-.692),l(.104,-1.004),l(.225,-.297),l(.329,-.156),l(.158,-.311),l(-.534,-.521),l(.033,-.198),l(.576,-.947),l(.312,-.934),l(.072,-.833),l(.191,-.241),l(.279,-.297), +N(270.934,276.123),l(.054,-.338),l(-.194,-.577),l(.011,-.522),l(.24,-.495),l(.48,-.524),l(.118,-.325),l(-.168,-.986),l(-.049,-.847),l(.103,-.522),l(.595,-2.359),l(.065,-.452),l(.443,-.524),l(.55,-.003),l(1.042,-.246),l(.25,-.101),l(.266,.098),l(.47,.364),l(.379,.407),l(.59,.814),l(.232,.38),l(.27,-.016),l(.693,-.427),l(.365,.393),l(.432,.576),l(.617,.194),l(.55,.194),l(.999,.587),l(.474,.435),l(.853,1.109),l(.131,.197),l(.163,.027),l(.333,.379),l(-.017,.269),l(-.634,.766),l(-.103,.269),l(.258,.746),l(.101,.313),l(-.059,.053),l(-.803,1.103),l(-.625,.552),l(-.775,.454),l(-.441,.156),l(-.818,.1),l(-.874,-.337),l(-.551,.044),l(-.551,.114),l(-.64,.283),l(-.38,-.042),l(-.846,-.676),l(-.637,-.252),l(-.76,-.154),l(-.469,.128),l(-.507,.072),l(-.327,-.127),l(-.548,-.563),l(-.354,-.159), +N(418.763,73.869),l(.391,-.499),l(.389,-.262),l(.283,.081),l(.663,-.062),l(.762,-.075),l(.324,-.137),l(.891,-.787),l(.979,-.2),l(.224,.025),l(.198,-.219),l(.175,.032),l(-.349,.531),l(.11,.106),l(.026,.481),l(-.288,.156),l(-.17,.368),l(-1.675,.069),l(-.376,-.106),l(-.428,.031),l(-.14,-.062),l(-.239,.081),l(-.275,.031),l(-.153,.417),l(-.249,.218),l(-.353,.118),l(-.08,.112),l(-.229,-.155),l(-.411,-.292),M(421.68,78.002),l(-1.839,.129),l(-.116,-.016),l(.064,-.404),l(-.19,-.638),l(-.174,.015),l(-.36,-.293),l(-.233,.184),l(-.398,-.172),l(.2,-.355),l(.434,-.293),l(-.007,-.181),l(-.445,-.541),l(.018,-.256),l(.131,-.498),l(.279,-.106),l(.318,.15),l(.495,.12),l(.43,-.574),l(.299,-.091),l(.296,.437),l(.391,-.046),l(.022,-.528),l(.107,-.363),l(1.032,-.017),l(.848,.089),l(.03,.544),l(.187,.301),l(1.138,.058),l(.14,.166),l(-.307,.604),l(-.565,.142),l(-.119,-.261),l(-.331,.031),l(-.263,.136),l(.121,.278),l(-.184,.414),l(-.312,.077),l(-.069,.244),l(-.635,.035),l(.157,.229),l(-.291,.094),l(-.191,.24),l(-.061,.285),l(.003,.21),l(-.215,.338),l(.166,.084),M(427.177,77.967),l(-.139,-.149),l(-.312,-.344),l(-.405,.031),l(-.665,-.059),l(-.123,-.329),l(-.285,-.66),l(.433,-.091),l(.603,-.467),l(.356,.495),l(.521,.179),l(.2,-.271),l(.078,-.586),l(.333,-.046),l(.459,.044),l(.056,.571),l(-.134,.36),l(-.144,.09),l(-.413,.286),l(.603,.299),l(-.285,.166),l(-.499,.39),l(-.238,.09), +N(417.259,94.301),l(-.135,-.233),l(.216,-.701),l(-.091,-.076),l(.075,-.295),l(.321,-.372),l(.054,-.358),l(.054,-.213),l(.954,-.806),l(-.605,-.193),l(-.479,.014),l(-.456,-.09),l(-.095,-.186),l(-.233,-.007),l(-.072,.048),l(-.689,.062),l(-.045,-.145),l(-.395,.055),l(-.337,-.277),l(-.428,-.319),l(-.074,-.353),l(.248,-.144),l(.044,-.288),l(-.466,-.096),l(-.41,-.312),l(-.062,-.301),l(.422,-.376),l(-.038,-.468),l(-.282,-.365),l(-.344,-.177),l(.165,-.278),l(-.143,-.217),l(-.182,-.037),l(.08,-.097),l(.235,-.133),l(.236,-.133),l(-.193,-.121),l(.201,-.275),l(.095,-.148),l(-.152,-.292),l(-.082,-.265),l(-.376,-.182),l(.07,-.182),l(.341,-.078),l(.175,-.092),l(.378,.134),l(.664,-.151),l(.32,-.152),l(.128,-.376),l(.412,-.207),l(.003,-.328),l(-.16,-.17),l(-.188,.061),l(-.44,-.134),l(.029,-.184),l(.113,-.181),l(.571,.036),l(.084,-.401),l(.345,-.361),l(-.151,-.438),l(.066,-.147),l(-.465,-.192),l(.126,-.43),l(.285,-.181),l(.371,-.028),l(1.12,-.062),l(.293,-.012),l(.095,.16),l(.195,.271),l(-.155,.158),l(.324,.113),l(.148,-.068),l(.042,-.192),l(-.159,-.204),l(.259,.012),l(.437,.169),l(-.163,-.362),l(.247,-.419),l(.687,.113),l(.614,-.091),l(-.596,-.17),l(-.084,-.227),l(.282,-.102),l(-.252,-.114),l(-.12,-.147),l(.166,-.08),l(.068,-.136),l(-.675,.08),l(-.06,-.182),l(.664,-.125),l(.218,-.193),l(-.464,-.42),l(-.324,-.341),l(.045,-.28),l(.116,.016),l(1.839,-.129),l(.254,.13),l(.565,.341),l(.271,.297),l(-.02,.228),l(-.252,.175),l(.445,-.05),l(.171,.216),l(.157,-.078),l(.283,.021),l(.235,.156),l(.45,.073),l(.866,-.121),l(.077,.208),l(-.07,.149),l(-.057,.125),l(-.665,.295),l(.316,.193),l(.649,-.136),l(.113,.182),l(.457,-.006),l(.349,-.391),l(1.059,-.136),l(.602,-.234),l(.757,-.266),l(.249,.113),l(.396,-.17),l(.184,.182),l(.085,.159),l(.634,.29),l(.182,.074),l(.526,-.12),l(.156,.12),l(.059,.34),l(.036,.227),l(.154,.102),l(.354,.125),l(.372,-.022),l(.028,.13),l(.201,.025),l(.319,.835),l(-.219,.52),l(-.391,.147),l(-.051,.328),l(.391,.102),l(.683,.429),l(-.217,.395),l(.094,.18),l(.312,.146),l(-.021,.304),l(.131,.102),l(-.118,.292),l(-.214,.124),l(-.007,.191),l(.325,.27),l(-.114,.258),l(.468,.188),l(.281,.485),l(-.435,.698),l(-.142,.115),l(-.344,-.072),l(-.031,-.278),l(-.308,-.121),l(-.436,.072),l(.282,.218),l(-.254,.084),l(-.284,.097),l(-.524,.048),l(-.124,.169),l(-.735,.024),l(-.112,.217),l(-.176,-.072),l(-.358,.061),l(-.097,.229),l(-.382,.012),l(-.078,.181),l(-.442,0),l(-.422,.201),l(-.293,-.033),l(-.26,.181),l(-.243,.168),l(.037,.056),l(.258,.378),l(.413,.098),l(-.155,.25),l(-.08,.406),l(.159,.085),l(.036,.233),l(.244,.173),l(.478,.265),l(.188,-.072),l(.573,.515),l(.431,.17),l(.184,.201),l(.219,-.084),l(.165,.18),l(.207,.036),l(.447,.633),l(-.682,.26),l(-.437,-.151),l(-.132,.027),l(-.039,.337),l(-.162,.172),l(-.968,.295),l(-.364,.227),l(.538,.571),l(-.197,.295),l(.334,.014),l(.056,.158),l(-.098,.343),l(-.082,.055),l(-.441,-.178),l(.049,-.165),l(-.146,-.117),l(-.564,.062),l(-.195,-.138),l(-.433,.035),l(-.092,.178),l(-1.25,.035),l(-.125,.171),l(-.319,.014),l(-.044,.13),L(425.4,94.7),l(-.594,.021),l(-.059,-.144),l(-.093,-.145),l(-.493,-.089),l(-.262,.055),l(-.237,-.041),l(.032,.274),l(-.452,.343),l(-.215,0),l(.078,-.195),l(-.26,-.039),l(.011,-.165),l(-.194,-.048),l(-.104,-.137),l(-.249,-.007),l(-.096,-.11),l(-.164,.137),l(-.368,-.014),l(-.664,-.261),l(-.852,-.007),l(-.149,-.089),l(-.199,.014),l(-.017,-.151),l(-.709,.199),l(.179,.199),l(-.354,.021),l(-.278,-.11),l(-.567,.158),l(-.271,-.096),l(-.272,.117),l(-.271,-.089),M(432.012,80.473),l(-.171,-.038),l(-.088,-.049),l(-.447,.08),l(-.111,-.264),l(.002,-.213),l(.647,.281),l(.168,.203), +N(450.734,91.05),l(-.831,-.33),l(-.424,-.101),l(-.104,-.216),l(-.703,-.186),l(-.129,-.13),l(-.561,.076),l(-.508,-.041),l(-.073,.137),l(-.373,.18),l(-.46,-.254),l(-.483,.046),l(-.168,-.056),l(-.558,.204),l(-.104,.177),l(-.149,.135),l(-.18,-.12),l(-.389,.083),l(-.003,-.204),l(.026,-.083),l(-.066,-.18),l(-.331,.025),l(-.073,-.169),l(-.194,-.24),l(-.261,.024),l(-.062,.112),l(-.193,-.016),l(-.183,.24),l(-.43,.048),l(-.03,-.228),l(-.285,-.041),l(-.105,-.331),l(-.382,-.096),l(-.188,-.208),l(.02,-.249),l(-.802,-.132),l(-.311,-.181),l(-.368,.161),l(-.293,-.013),l(-.013,-.221),l(.001,-.253),l(-.329,.084),l(.181,-.283),l(-.709,.005),l(-.258,-.121),l(-.509,-.193),l(-.286,-.024),l(-.003,.145),l(.282,.302),l(-.41,.12),l(-.22,.187),l(-.318,-.072),l(-.296,-.38),l(-.55,-.247),l(.224,-.211),l(.208,-.024),l(.099,-.121),l(-.199,-.181),l(-.257,-.024),l(-.061,.066),l(-.466,.066),l(.005,-.169),l(-.278,.037),l(-.132,-.181),l(-.568,-.054),l(-.201,-.025),l(-.363,-.163),l(-.093,-.26),l(-.211,-.091),l(-.361,.018),l(-.063,.084),l(.062,.073),l(-.024,.151),l(-.375,0),l(.435,-.698),l(-.281,-.485),l(-.468,-.188),l(.114,-.258),l(-.325,-.27),l(.007,-.191),l(.214,-.124),l(.118,-.292),l(-.131,-.102),l(.021,-.304),l(-.312,-.146),l(-.094,-.18),l(.217,-.395),l(-.683,-.429),l(-.391,-.102),l(.051,-.328),l(.391,-.147),l(.219,-.52),l(-.319,-.835),l(.34,.043),l(.23,.125),l(-.093,-.193),l(.156,-.153),l(-.019,-.147),l(-.166,-.13),l(-.021,-.129),l(-.012,-.075),l(.93,-.154),l(.431,-.051),l(.516,-.152),l(1.304,-.128),l(.48,-.158),l(.797,-.479),l(1.117,-.298),l(1.515,-.303),l(1.382,-.086),l(1.067,.417),l(-.882,-.294),l(-.054,.147),l(.256,.172),l(.132,.466),l(.355,.135),l(.648,.061),l(.645,-.11),l(1.063,-.409),l(.054,.004),l(-.978,.417),l(-.19,.11),l(-.004,.123),l(.218,.012),l(.286,-.123),l(.613,-.208),l(.543,-.253),l(.842,.006),l(2.246,.115),l(2.96,-.101),l(.641,-.021),l(.04,.014),l(.679,.243),l(.284,.487),l(.099,.186),l(.016,.029),l(.09,.171),l(.16,.302),l(.615,1.5),l(.172,.502),l(-.023,.236),l(-.263,.208),l(-.44,.03),l(-.571,.244),l(-.291,.328),l(-.128,.292),l(.289,.012),l(.421,.146),l(.149,.176),l(.218,.146),l(.013,.25),l(-.315,.752),l(.126,.137),l(.161,.175),l(-.074,.242),l(.816,.835),l(.316,.193),l(-.298,.048),l(-.085,.133),l(.328,.302),l(-.009,.314),l(-.255,.24),l(-.429,.013),l(-.286,.181),l(-.599,.398),l(-1.509,1.218),l(-.082,.306),l(.044,.552),l(.349,.383),l(-.653,-.018),M(431.844,80.27),l(.232,.024),l(.069,.208),l(-.134,-.029),l(-.168,-.203),M(432.739,80.361),l(-.03,.129),l(-.278,-.024),l(-.191,.03),l(-.046,-.208),l(.174,-.012),l(.266,0),l(.106,.085), +N(416.488,81.945),l(.151,.438),l(-.345,.361),l(-.084,.401),l(-.571,-.036),l(-.113,.181),l(-.029,.184),l(.44,.134),l(.188,-.061),l(.16,.17),l(-.003,.328),l(-.412,.207),l(-.128,.376),l(-.32,.152),l(-.664,.151),l(-.378,-.134),l(-.175,.092),l(-.341,.078),l(-.07,.182),l(.376,.182),l(.082,.265),l(.152,.292),l(-.095,.148),l(-.201,.275),l(.193,.121),l(-.236,.133),l(-.235,.133),l(-.08,.097),l(.182,.037),l(.143,.217),l(-.165,.278),l(-.672,.024),l(-.001,-.338),l(.172,-.097),l(.11,-.423),l(-.754,-.375),l(-.535,.109),l(-.292,-.375),l(-.228,-.061),l(-.173,.121),l(-.313,-.242),l(-.267,.182),l(-.307,0),l(-.307,-.012),l(.025,.157),l(-.52,.034),l(-.407,-.042),l(-.477,-.098),l(-.07,-.162),l(-.496,-.264),l(.795,-.472),l(.858,-.621),l(.273,-.354),l(.563,-1.167),l(.173,-.104),l(.644,-.12),l(.367,.251),l(.136,.268),l(-.28,.203),l(-.228,-.056),l(.066,.496),l(-.191,.124),l(1.163,.225),l(.225,-.236),l(.406,-.113),l(.134,-.417),l(-.458,-.022),l(-.123,-.124),l(-.02,-.203),l(.236,-.158),l(-.171,-.023),l(-.558,-.067),l(.072,-.328),l(-.034,-.13),l(-.023,-.034),l(.128,-.283),l(.572,-.198),l(.709,-.238),l(.654,.03),l(1.089,-.151),l(.245,.275),l(.329,.045),l(.076,.181),l(.259,0), +N(431.57,91.965),l(-.447,-.633),l(-.207,-.036),l(-.165,-.18),l(-.219,.084),L(430.349,91),l(-.431,-.17),l(-.573,-.515),l(-.188,.072),l(-.478,-.265),l(-.244,-.173),l(-.036,-.233),l(-.159,-.085),l(.08,-.406),l(.155,-.25),l(-.413,-.098),l(-.258,-.378),l(-.037,-.056),l(.243,-.168),l(.26,-.181),l(.293,.033),l(.422,-.201),l(.442,0),l(.078,-.181),l(.382,-.012),l(.097,-.229),l(.358,-.061),l(.176,.072),l(.112,-.217),l(.735,-.024),l(.124,-.169),l(.524,-.048),l(.284,-.097),l(.254,-.084),l(-.282,-.218),l(.436,-.072),l(.308,.121),l(.031,.278),l(.344,.072),l(.142,-.115),l(.375,0),l(.024,-.151),l(-.062,-.073),l(.063,-.084),l(.361,-.018),l(.211,.091),l(.093,.26),l(.363,.163),l(.201,.025),l(.568,.054),l(.132,.181),l(.278,-.037),l(-.005,.169),l(.466,-.066),l(.061,-.066),l(.257,.024),l(.199,.181),l(-.099,.121),l(-.208,.024),l(-.224,.211),l(.55,.247),l(.296,.38),l(.318,.072),l(.22,-.187),l(.41,-.12),l(-.282,-.302),l(.003,-.145),l(.286,.024),l(.509,.193),l(.258,.121),l(.709,-.005),l(-.181,.283),l(.329,-.084),l(-.001,.253),l(.013,.221),l(.293,.013),l(.368,-.161),l(.311,.181),l(.802,.132),l(-.02,.249),l(.188,.208),l(.382,.096),l(.105,.331),l(-.071,-.012),l(-.065,.066),l(-.066,.04),l(-.105,-.026),L(442,89.998),l(-.119,.013),l(-.065,.04),l(-.132,.066),l(-.053,.079),l(-.118,.092),l(-.119,.053),l(-.132,.079),l(-.105,.013),l(-.118,.013),l(-.053,.092),l(-.026,.092),l(-.026,.132),l(-.053,.079),l(-.053,.105),l(-.145,.066),l(-.105,.04),l(-.092,-.026),l(-.079,.079),l(-.04,.092),l(-.053,.079),l(-.039,0),l(-.105,.026),l(-.066,.026),l(-.079,.053),l(-.118,.053),l(-.132,0),l(-.145,.04),l(-.093,.026),l(-.065,-.026),l(-.065,-.026),l(-.093,0),l(-.065,.026),l(-.158,0),l(-.132,-.053),l(-.092,-.053),l(-.093,.026),l(-.171,.053),l(-.026,.04),l(-.146,.119),l(-.092,.066),l(-.014,.131),l(-.065,.105),l(-.039,.044),l(-.055,-.095),l(-.545,-.2),l(-1.332,.181),l(-1.019,-.227),l(-1.374,-.341),l(-.746,.773),l(-.598,.163),l(-.483,-.099),l(-.354,-.129),l(-.145,-.014), +N(421.683,94.397),l(.368,.014),l(.164,-.137),l(.096,.11),l(.249,.007),l(.104,.137),l(.194,.048),l(-.011,.165),l(.26,.039),l(-.078,.195),l(.215,0),l(.452,-.343),l(-.032,-.274),l(.237,.041),l(.262,-.055),l(.493,.089),l(.093,.145),l(.059,.144),L(425.4,94.7),l(.377,-.103),l(.044,-.13),l(.319,-.014),l(.125,-.171),l(1.25,-.035),l(.092,-.178),l(.433,-.035),l(.195,.138),l(.564,-.062),l(.146,.117),l(-.049,.165),l(.441,.178),l(.082,-.055),l(.098,-.343),l(-.056,-.158),l(-.334,-.014),l(.197,-.295),l(-.538,-.571),l(.364,-.227),l(.968,-.295),l(.162,-.172),l(.039,-.337),l(.132,-.027),l(.437,.151),l(.682,-.26),l(.145,.014),l(.354,.129),l(.483,.099),l(.598,-.163),l(.746,-.773),l(1.374,.341),l(1.019,.227),l(1.332,-.181),l(.545,.2),l(.055,.095),l(.053,.093),l(-.097,.581),l(.155,.26),l(.761,.547),l(-.636,.291),l(-.019,.367),l(-.701,.054),l(-.164,-.134),l(-.325,0),l(-.223,.197),l(.452,.063),l(.136,.196),l(-.157,.206),l(-.409,.062),l(-.04,.375),l(.204,.188),l(-.154,.294),l(-.346,.299),l(-.693,.157),l(.082,.393),l(-.89,-.116),l(-.298,.196),l(-.85,-.08),l(-.566,.107),l(-.646,.5),l(-.287,-.152),l(-.612,.009),l(-.179,-.107),l(-1.04,-.065),l(-.478,-.112),l(-.894,-.082),l(-1.311,-.247),l(-.32,-.391),l(-.318,-.096),l(-.023,-.363),l(-.856,.227),l(-.301,-.103),l(-.445,.11),l(-.183,-.083),l(-.366,.096),l(-.329,.411),l(-.597,-.034),l(-.631,-.171),l(.029,-.171),l(-.215,-.117),l(-.579,.332),l(-.55,-.242),l(-.008,-.144),l(-.622,-.062),l(.09,-.192),l(-.214,-.288),l(.266,-.274),l(-.193,-.336), +N(431.763,171.063),l(-.067,.354),l(.091,.72),l(.108,.508),l(.225,.168),l(.562,.11),l(.144,.183),l(.077,.353),l(-.089,1.116),l(-.146,.227),l(-.274,.171),l(-.885,.217),l(-.291,.256),l(-.664,1.275),l(-.503,1.203),l(-.243,1.004),l(-.354,.129),l(-.369,.03),l(-.129,.354),l(-.146,1.229),l(-.192,.312),l(-.385,.045),l(-.257,.284),l(-.417,.836),l(-.944,2.223),l(-.304,.624),l(-.352,.496),l(-.368,.355),l(-.239,.114),l(-.145,-.056),l(-.722,-.97),l(-.145,-.14),l(-1.104,-.05),l(-.272,.03),l(-1.31,1.265),l(-.941,.839),l(-.495,.526),l(.02,.974),l(-.189,.552),l(-.376,.686),l(-.188,-.119),l(-.224,-.042),l(-.176,-.127),l(-.145,.212),l(.144,.296),l(-.063,.127),l(-.353,.198),l(-.56,.03),l(-.977,.101),l(-.607,-.267),l(-.288,.043),l(-.271,.368),l(-.177,.113),l(-.432,-.07),l(-1.247,-.011),l(-.528,-.225),l(-.543,-.451),l(-.416,-.72),l(-.192,-.649),l(.048,-.254),l(.208,-.254),l(-.144,-.296),l(-.513,-.069),l(-.128,-.254),l(-.464,-.55),l(-.561,-.465),l(-.608,-.253),l(-.641,-.253),l(-.272,-.31),l(-.513,.072),l(-.24,.297),l(-.336,.071),l(-.881,.044),l(-.659,.03),l(-.006,-.234),l(.121,-1.188),l(-.217,-1.439),l(.09,-.989),l(.012,-.876),l(-.003,-.48),l(-.002,-.381),l(.237,-.397),l(.257,-.03),l(.433,-.13),l(.078,-.368),l(-.116,-.592),l(.095,-.34),l(.656,-.414),l(.223,-.298),l(.19,-.566),l(.316,-.962),l(-.388,-.718),l(-.164,-.762),l(.062,-.777),l(.092,-.961),l(.158,-.849),l(.353,-.482),l(.687,-1.614),l(.676,-.4),l(1.064,-.188),l(1.174,-.108),l(1.111,.121),l(.821,.277),l(1.095,1.223),l(.209,.098),l(.37,-.002),l(1.337,-.544),l(.467,-.116),l(.354,.083),l(1.173,.742),l(.965,.277),l(.934,-.005),l(.273,-.059),l(.629,-.399),l(.403,-.327),l(.774,-.287),l(.628,-.103),l(.709,-.047),l(.531,.04),l(.884,.221),l(.724,.193),l(.609,.208),l(.259,-.058),l(.761,-.697),l(.453,-.299),l(.437,-.2),l(.951,-.034),l(.173,.394),l(.575,.52),l(.351,.407), +N(425.506,195.522),l(-1.965,-.017),l(-1.005,.007),l(.029,-.176),l(-.208,-.536),l(.271,-.989),l(-.159,-.72),l(-.191,-.522),l(-.399,-.649),l(.433,-.396),l(-.287,-.367),l(-.24,-.056),l(-.576,.058),l(-.559,-.268),l(-.176,-.324),l(-.063,-.537),l(-.111,-.211),l(-.527,-.14),l(-.101,-.064),l(.376,-.686),l(.189,-.552),l(-.02,-.974),l(.495,-.526),l(.941,-.839),l(1.31,-1.265),l(.272,-.03),l(1.104,.05),l(.145,.14),l(.722,.97),l(.145,.056),l(.239,-.114),l(.368,-.355),l(.352,-.496),l(.304,-.624),l(.944,-2.223),l(.417,-.836),l(.257,-.284),l(.385,-.045),l(.192,-.312),l(.146,-1.229),l(.129,-.354),l(.369,-.03),l(.354,-.129),l(.243,-1.004),l(.503,-1.203),l(.664,-1.275),l(.291,-.256),l(.885,-.217),l(.274,-.171),l(.146,-.227),l(.089,-1.116),l(-.077,-.353),l(-.144,-.183),l(-.562,-.11),l(-.225,-.168),l(-.108,-.508),l(-.091,-.72),l(.067,-.354),l(.627,.109),l(.208,.083),l(.923,1.238),l(.395,.887),l(.119,1.2),l(-.134,.651),l(.169,1.228),l(.205,.578),l(.381,.633),l(.208,.21),l(.047,.127),l(-.225,.143),l(-.674,.032),l(-1.187,-.191),l(-.481,-.082),l(-.24,.1),l(-.29,.312),l(-.323,.539),l(1.088,1.067),l(1.343,1.179),l(.638,1.07),l(.382,1.057),l(.208,.183),l(-.208,.114),l(-.354,.327),l(-.866,1.743),l(-.4,.511),l(-.528,.399),l(-.144,.198),l(-.064,.424),l(.112,.776),l(.273,1.185),l(.207,.592),l(.4,.661),l(.432,.605),l(.064,.791),l(.112,.324),l(1.217,1.236),l(.498,.802),l(.194,.804),l(.209,.451),l(-.159,.185),l(.1,.861),l(-.271,.086),l(-.863,-.292),l(-.864,-.334),l(-.576,-.194),l(-.56,-.124),l(-.479,-.04),l(-.271,-.055),l(-.878,.076),l(-.863,-.023),l(-.56,-.109),l(-1.022,-.149),l(-.831,-.038),l(-1.773,-.088),l(-.88,-.093),l(-.045,.495), +N(551.793,147.278),l(-.788,-.111),l(-.458,-.253),l(-.379,-.367),l(-.248,-1.101),l(-.112,-.141),l(-.342,-.141),l(-.662,-.083),l(-.105,-.07),l(-.014,-.268),l(.116,-.466),l(-.178,-.451),l(-.418,-.38),l(-.294,-.013),l(-1.181,.412),l(-1.229,.087),l(-.81,.143),l(-.947,.073),l(-.415,-.083),l(-.263,-.226),l(-.135,-.197),l(-.909,.143),l(-.548,.382),l(-.856,.016),l(-1.264,-.011),l(-.691,.128),l(-.723,.115),l(-.541,.03),l(.182,-.954),l(.049,-.354),l(.31,-.792),l(.285,-.383),l(.794,-.47),l(.697,-.258),l(1,-.077),l(.209,-.072),l(.188,-.255),l(.036,-.974),l(-.186,-.281),l(-.652,-.053),l(-.185,-.394),l(-.111,-1.34),l(-.168,-.38),l(-.409,-.224),l(-1.144,-.388),l(-.695,-.391),l(-.353,-.464),l(-.71,-1.068),l(-.802,-1.083),l(.887,.32),l(.63,.194),l(1.069,.248),l(.854,.235),l(.541,.039),l(.742,.024),l(1.187,-.218),l(.349,-.002),l(1.005,.135),l(1.234,-.12),l(.964,-.175),l(1.183,-.19),l(1.066,-.274),l(.247,-.156),l(.069,-.184),l(.099,-.903),l(.232,-.876),l(.188,-.34),l(.412,-.369),l(.597,-.441),l(.283,-.072),l(.644,.039),l(.516,.082),l(.254,-.086),l(.321,-.693),l(.362,-.271),l(.559,-.243),l(.562,.025),l(1.001,.375),l(.237,-.086),l(.34,-.383),l(.021,-.084),l(.139,-1.214),l(.288,-.834),l(.224,-.424),l(.292,-.228),l(.416,-.115),l(.513,-.031),l(.315,-.115),l(.199,-.255),l(-.088,-.437),l(-.129,-.281),L(556.193,125),l(-.35,-.336),l(.355,-.129),l(.997,.122),l(.698,.039),l(.513,-.215),l(.289,-.255),l(-.033,-.31),l(-.223,-.478),l(.13,-.283),l(.4,-.341),l(.524,-.355),l(.324,-.426),l(-.198,-.477),l(.119,-.483),l(-.232,-.171),l(-.01,-.336),l(-.411,-.271),l(-.01,-.32),l(.464,-.413),l(.258,-.214),l(.246,.023),l(.559,-.395),l(.272,-.19),l(.53,-.292),l(1.148,-.152),l(1.345,-.012),l(.647,.144),l(.338,-.179),l(.332,.005),l(.455,-.297),l(.358,-.004),l(.148,-.142),l(.313,.14),l(.105,.112),l(.281,-.21),l(.296,.047),l(.554,.117),l(.004,.456),l(.282,-.128),l(.625,-.009),l(.373,.323),l(.213,.247),l(.007,.501),l(-.312,.516),l(.301,.07),l(.198,.218),l(.252,.281),l(.52,-.196),l(.239,0),l(.104,.199),l(.178,.09),l(.565,.436),l(1.337,.104),l(.305,.111),l(.147,.126),l(-.207,.084),l(-.688,.37),l(-.411,.232),l(-.155,.43),l(-.071,.479),l(-.234,.116),l(-.125,-.179),l(-.621,-.102),l(-.438,.132),l(-.271,.298),l(-.262,-.116),l(-.557,.265),l(-.928,-.149),l(-.568,-.138),l(-1.708,-.325),l(-.894,.265),l(-.38,.611),l(.09,.166),l(.336,0),l(.047,.314),l(-.202,.149),l(.101,.199),l(.598,-.017),l(-.002,.347),l(-.384,.099),l(-.139,.413),l(.389,.232),l(-.116,.479),l(-.215,.132),l(.089,.248),l(.606,.298),l(-.003,.532),l(.782,-.003),l(-.039,.43),l(.188,.248),l(.702,-.05),l(.668,.377),l(.012,.211),l(-.2,.255),l(-.504,.2),l(-.643,.196),l(-.517,.248),l(.032,.366),l(.188,.377),l(-.237,.977),l(-1.512,1.503),l(.261,.38),l(-.358,.281),l(-.609,.133),l(-.353,.467),l(-.509,1.216),l(-.478,.547),l(-1.193,.496),l(-.177,.364),l(-.277,.481),l(-.563,.61),l(-.076,.38),l(-.71,.259),l(-.734,-.011),l(-.895,.314),l(-.361,-.094),l(-.158,-.518),l(-.207,-.132),l(-.404,.083),l(-.535,.463),l(-.144,.446),l(-.979,.893),l(-.186,.543),l(-.079,.269),l(.116,.38),l(.541,.163),l(.504,.085),l(.425,.014),l(-.114,.689),l(-.154,.735),l(.412,.411),l(.33,.099),l(.537,-.099),l(.112,.441),l(.216,.507),l(.654,1.333),l(-.232,.149),l(.241,.463),l(-.317,.066),l(-.15,.248),l(-.55,.083),l(-.145,-.335),l(-.183,-.062),l(-.78,.215),l(-.2,.331),l(-.735,-.099),l(-.229,-.149),l(-.835,-.021),l(-.835,-.009),l(-.259,-.052),l(.015,.728),l(-.866,.017),l(-.296,.431),l(-.37,.036), +N(606.155,150.953),l(-.037,-.466),l(-.627,-2.479),l(-.064,-.578),l(-.4,.044),l(-.281,.115),l(-.395,1.159),l(-.224,.354),l(-.529,-.448),l(-.249,-.267),l(-.23,-.281),l(-.001,-.381),l(-.009,-.522),l(.131,-.283),l(.651,-.356),l(.498,-.13),l(.938,-.767),l(.159,-.34),l(.012,-.79),l(-.057,-.127),l(-.111,-.098),l(-2.473,-.198),l(-.559,.003),l(-.916,.062),l(-.547,-.053),l(-.537,-.109),l(-.095,-.099),l(-.079,-.719),l(-.053,-.479),l(-.129,-.324),l(-.417,-.054),l(-.489,.06),l(-.372,-.266),l(-.339,-.266),l(-1.252,-.303),l(-.234,.171),l(-.555,.525),l(-.124,.283),l(.083,.155),l(.494,.237),l(1.224,.938),l(.126,.112),l(-.047,.155),l(-.382,.101),l(-.502,.13),l(-.4,.299),l(-.548,.61),l(.339,.323),l(1.042,.431),l(.193,.21),l(-.029,.269),l(-.505,.765),l(.04,.254),l(.352,.45),l(.325,1.409),l(.402,1.775),l(.147,.532),l(-.172,.322),l(.068,.183),l(-.321,.071),l(-.35,-.056),l(-.148,-.706),l(-.198,-.084),l(-.253,.354),l(-.171,.354),l(-.172,.057),l(-.115,-.099),l(-.28,-.592),l(-.152,-.169),l(-.412,.537),l(-.504,.298),l(-.992,.397),l(-.571,.213),l(-.264,.226),l(-.05,.113),l(.106,.579),l(.183,.409),l(-.336,.495),l(-.305,.332),l(-.013,.257),l(-.548,.415),l(-.593,.467),l(-.467,.185),l(-.432,.057),l(-.746,.206),l(-.591,.362),l(-.459,.58),l(-.551,.552),l(-.88,1.061),l(-.611,.552),l(-.673,.276),l(-.675,.829),l(-.676,.467),l(-.728,.368),l(-.452,.241),l(-.427,.312),l(-.192,.509),l(-.073,.466),l(-.341,.41),l(-.649,.298),l(-.428,.058),l(-.506,-.098),l(-.258,.269),l(-.366,.887),l(-.277,.23),l(-.505,-.253),l(-.614,.142),l(-.354,.283),l(-.304,.565),l(-.165,.48),l(-.005,.508),l(.166,1.539),l(.018,.805),l(-.208,.495),l(.227,.324),l(.315,.423),l(-.015,.508),l(-.199,.607),l(-.669,1.611),l(-.341,.834),l(-.13,.636),l(.047,.649),l(.21,1.764),l(-.081,.24),l(-.643,.001),l(-.433,-.013),l(-.186,.142),l(-.334,.961),l(-.324,.594),l(.025,.127),l(.493,.352),l(-.805,.327),l(-.306,.015),l(-.77,.284),l(-.295,.41),l(-.101,.692),l(-.157,.255),l(-.367,.283),l(-.526,.255),l(-.099,.057),l(-.066,.042),l(-.231,.156),l(-.145,0),l(-.174,-.056),l(-1.417,-1.451),l(-.092,-.395),l(-.276,-.522),l(-.34,-1.397),l(-.689,-1.792),l(-.94,-1.933),l(-.979,-1.508),l(-.554,-1.722),l(-.507,-1.792),l(-.738,-1.636),l(-.82,-1.42),l(-.424,-.737),l(-.598,-1.439),l(-.363,-1.157),l(-.767,-3.274),l(-.469,-2.695),l(-.157,-1.566),l(-.051,-.24),l(.232,-.565),l(.546,-.834),l(.007,-.311),l(-.404,-.281),l(-.367,-.437),l(-.113,-.635),l(-.108,-.917),l(.065,-.622),l(-.837,.03),l(-.19,.212),l(-.235,.424),l(.009,.183),l(.276,.254),l(.074,.183),l(-.073,.438),l(-.301,.438),l(-.503,.368),l(-.812,.369),l(-.504,.114),l(-.617,.255),l(-.377,.015),l(-.861,-.281),l(-.572,-.38),l(-1.018,-1),l(-1.391,-1.268),l(-.516,-.705),l(.267,-.043),l(1.062,.125),l(.615,-.086),l(.443,-.142),l(.461,-.283),l(.521,-.608),l(-.067,-.24),l(-.156,.071),l(-.587,.114),l(-.847,-.026),l(-.607,-.112),l(-.632,-.132),l(-.5,-.218),l(-.203,-.07),l(-.929,-.661),l(-.668,-.775),l(-.057,-.197),l(.37,-.036),l(.296,-.431),l(.866,-.017),l(-.015,-.728),l(.259,.052),l(.835,.009),l(.835,.021),l(.229,.149),l(.735,.099),l(.2,-.331),l(.78,-.215),l(.183,.062),l(.145,.335),l(.55,-.083),l(.15,-.248),l(.317,-.066),l(-.241,-.463),l(.232,-.149),l(-.654,-1.333),l(-.216,-.507),l(-.112,-.441),L(557,143.058),l(-.33,-.099),l(-.412,-.411),l(.154,-.735),l(.114,-.689),l(-.425,-.014),l(-.504,-.085),l(-.541,-.163),l(-.116,-.38),l(.079,-.269),l(.186,-.543),l(.979,-.893),l(.144,-.446),l(.535,-.463),l(.404,-.083),l(.207,.132),l(.158,.518),l(.361,.094),l(.895,-.314),l(.734,.011),l(.71,-.259),l(.076,-.38),l(.563,-.61),l(.277,-.481),l(.177,-.364),l(1.193,-.496),l(.478,-.547),l(.509,-1.216),l(.353,-.467),l(.609,-.133),l(.358,-.281),l(-.261,-.38),l(1.512,-1.503),l(.237,-.977),l(-.188,-.377),l(-.032,-.366),l(.517,-.248),l(.643,-.196),l(.504,-.2),l(.2,-.255),l(-.012,-.211),l(-.668,-.377),l(-.702,.05),l(-.188,-.248),l(.039,-.43),l(-.782,.003),l(.003,-.532),l(-.606,-.298),l(-.089,-.248),l(.215,-.132),l(.116,-.479),l(-.389,-.232),l(.139,-.413),l(.384,-.099),l(.002,-.347),l(-.598,.017),l(-.101,-.199),l(.202,-.149),l(-.047,-.314),l(-.336,0),l(-.09,-.166),l(.38,-.611),l(.894,-.265),l(1.708,.325),l(.568,.138),l(.928,.149),l(.557,-.265),l(.262,.116),l(.271,-.298),l(.438,-.132),l(.621,.102),l(.125,.179),l(.234,-.116),l(.071,-.479),l(.155,-.43),l(.411,-.232),l(.688,-.37),l(.207,-.084),l(.502,-.152),l(0,.515),l(.441,1.03),l(.221,.515),l(.81,.11),l(.441,.405),l(.221,.258),l(-.331,.221),l(-.184,.184),l(.073,.589),l(.037,.552),l(.294,.221),l(.718,.096),l(.092,.078),l(.044,.182),l(.68,.099),l(-.104,.414),l(.367,.694),l(-.578,.364),l(-.376,.281),l(-.368,.049),l(-.337,-.264),l(-.033,-.364),l(-.785,.198),l(.157,.694),l(.579,.595),l(-.104,.446),l(.272,.364),l(-.215,.215),l(.099,.43),l(.198,.066),l(.477,-.314),l(.383,.248),l(.772,.843),l(.363,-.116),l(1.078,.579),l(-.116,.364),l(.756,.248),l(.154,-.066),l(.859,.596),l(-1.07,.909),l(-.281,.116),l(.008,.364),l(-.221,.265),l(.04,.396),l(-.309,.397),l(-.218,.43),l(.039,.248),l(.63,.38),l(.466,-.083),l(.665,.479),l(.704,.149),l(.305,.529),l(1.242,.678),l(.231,-.166),l(1.027,.595),l(.538,-.066),l(.182,.397),l(.835,.166),l(.304,.198),l(.15,-.066),l(.087,-.215),l(.503,0),l(.482,.265),l(.582,-.347),l(.494,.298),l(.643,.066),l(.142,.231),l(-.101,.446),l(.663,.149),l(.286,.281),l(.618,.265),l(.584,-.281),l(.313,.066),l(-.034,.331),l(.312,.248),l(.379,-.231),l(.721,.148),l(.847,.364),l(.606,-.297),l(.268,.364),l(.399,.116),l(.357,-.132),l(.271,.083),l(.687,-.132),l(.336,.05),l(.311,-.694),l(-.429,-.827),l(.07,-.876),l(.318,-.761),l(-.037,-.022),l(.345,-.129),l(.471,-.102),l(.231,.069),l(.139,.183),l(-.052,.861),l(.212,.662),l(-.092,.113),l(.235,.493),l(.637,.18),l(.559,.081),l(.869,.214),l(.085,.021),l(.544,-.074),l(.531,-.313),l(.301,.055),l(.335,.125),l(1.238,.063),l(1.036,-.062),l(.624,-.06),l(.217,-.58),l(-.017,-.282),l(-.258,-.238),l(-.313,-.069),l(-.326,-.294),l(-.042,-.24),l(.07,-.156),l(.189,-.1),l(.784,-.033),l(.714,-.216),l(.397,-.27),l(1.123,-1.107),l(.543,-.37),l(.829,-.258),l(1.105,-.726),l(.546,-.299),l(.355,-.087),l(.286,.167),l(.975,.319),l(.377,-.044),l(1.377,-.84),l(.455,.392),l(.716,.715),l(.046,.38),l(-.354,.454),l(-.138,.269),l(.102,.056),l(.3,.055),l(.657,.081),l(.73,.179),l(.624,.081),l(-.018,.508),l(-.112,.24),l(-.596,.582),l(-.072,.283),l(.184,.718),l(-.295,.058),l(-.853,-.221),l(-.558,-.082),l(-.312,.129),l(-.719,.512),l(-1.446,.883),l(-.197,.354),l(.057,.761),l(-.136,.382),l(-.938,1.134),l(-.045,.212),l(.192,.408),l(0,.324),l(-1.148,2.25),l(-.17,.128),l(-.309,-.013),l(-.391,-.11),l(-.811,-.32),l(-.133,.283),l(.146,1.594),l(-.191,.354),l(-.401,.144),l(-.228,.185),l(.152,.93),l(-.015,.678),l(-.273,.368),l(-.25,.129),l(-.255,-.14),l(-.595,-.152), +N(478.516,135.173),l(.052,-.292),l(-.049,-.169),l(-.197,-.107),l(.107,-.175),l(.292,-.919),l(-.015,-.818),l(.517,-1.09),l(.3,-.891),l(-.004,-.409),l(.133,-.283),l(.07,-.749),l(.033,-.847),l(.062,-.174),l(.026,-.278),l(-.065,-.411),l(.037,-.119),l(.102,-.063),l(1.902,1.034),l(.365,.167),l(.253,-.016),l(1.139,-.656),l(2.96,-1.541),l(.161,-.071),l(.87,1.632),l(.311,.69),l(.093,.056),l(-.46,.44),l(-.257,.171),l(-.97,.26),l(-2.586,.622),l(-.646,.229),l(1.146,1.32),l(.698,.885),l(-.765,.724),l(-.456,.37),l(-.24,.072),l(-1.249,.332),l(-.462,.61),l(-.975,.782),l(-2.079,-.299),l(-.154,-.017), +N(456.028,151.46),l(-.021,1.003),l(.033,3.078),l(-.088,.17),l(-1.561,-.019),l(-.52,-.011),l(-.073,1.13),l(-1.981,-.963),l(-5.577,-2.792),l(-4.941,-2.372),l(-5.231,-2.554),l(-.41,.059),l(-1.818,.858),l(-1.519,.729),l(-.231,.157),l(-1.192,-.911),l(-.258,-.182),l(-1.008,-.333),l(-1.646,-.442),l(-.832,-.137),l(-.098,-.07),l(-.86,-1.506),l(-.178,-.168),l(-1.028,-.347),l(-.702,-.165),l(-.544,.201),l(-.244,-.154),l(-.562,-.873),l(-.249,-.917),l(-1.272,-1.702),l(.152,-.283),l(.249,-.128),l(.666,-.47),l(.086,-.17),l(.061,-.664),l(-.457,-1.156),l(.158,-.495),l(.16,-.622),l(-.101,-.748),l(.1,-.862),l(-.052,-.691),l(-.147,-.833),l(-.88,-1.605),l(.241,-.383),l(.204,-.156),l(.22,-.143),l(.864,-.598),l(.155,-.227),l(.147,-.537),l(-.274,-.973),l(.126,-.354),l(1.473,-1.138),l(.579,-.314),l(.802,-.428),l(.093,-.269),l(-.064,-.564),l(.093,-.981),l(1.436,.59),l(.995,.309),l(.521,.013),l(.863,-.129),l(.604,.027),l(1.552,.223),l(.614,.479),l(.794,.224),l(.486,-.001),l(.342,.197),l(.173,.226),l(.26,.819),l(.39,.564),l(.688,.591),l(.378,.126),l(.678,.14),l(1.031,.083),l(.447,.07),l(.973,.224),l(.639,.224),l(.552,.281),l(1.289,.788),l(.84,.464),l(.465,.013),l(.441,-.128),l(.758,-.411),l(.706,-.623),l(.3,-.523),l(0,-.254),l(-.276,-.621),l(-.112,-.579),l(.044,-.41),l(.237,-.537),l(.661,-.58),l(.333,-.198),l(.554,-.241),l(.644,-.298),l(1.376,-.413),l(1.205,.054),l(.728,.154),l(.844,.365),l(.188,.169),l(.043,.508),l(.281,.253),l(.301,.014),l(.945,.125),l(.712,.309),l(.45,.027),l(1.286,.04),l(.302,.197),l(.068,.381),l(.276,.296),l(-.099,.208),l(-.369,.228),l(-.21,.34),l(.354,1.283),l(-.231,.425),l(-.322,.553),l(-.056,.311),l(.185,.945),l(.388,.916),l(.042,.367),l(-.015,.988),l(-.019,3.869),l(-.016,1.468),l(-.008,2.048),l(-.001,.692),l(.045,2.81),l(-.021,1.342),l(.011,2.612), +N(478.212,134.714),l(-.834,-1.746),l(-.796,-1.944),l(-.124,-.289),l(.109,-.066),l(.679,-.851),l(.219,-.438),l(.183,-.507),l(.171,-.566),l(.188,-.822),l(.116,.018),l(.137,-.093),l(.006,-.204),l(.028,-.315),l(.372,-.051),l(.151,.022),l(.07,.099),l(.355,-.07),l(.009,-.167),l(.067,-.193),l(.088,-.041),l(.07,.023),l(.183,.346),l(.201,.128),l(.021,.183),l(-.047,.122),l(.082,.085),l(-.102,.063),l(-.037,.119),l(.065,.411),l(-.026,.278),l(-.062,.174),l(-.033,.847),l(-.07,.749),l(-.133,.283),l(.004,.409),l(-.3,.891),l(-.517,1.09),l(.015,.818),l(-.292,.919),l(-.107,.175),l(-.067,.068),l(-.042,.042), +N(495.751,163.817),l(-.03,-.184),l(-.112,-.537),l(-.508,-.945),l(-.73,-.987),l(-.438,-.493),l(-.846,-.69),l(-.51,-.875),l(-.814,-1.876),l(-.474,-.889),l(-.28,-.409),l(-.794,-.507),l(-1.271,-.689),l(-.527,-.634),l(-.8,-1.17),l(-.081,-.96),l(-.061,-.776),l(-.002,-.89),l(-.104,-.381),l(-.312,-.663),l(-.944,-1.65),l(-.357,-.494),l(-.758,-.62),l(-.459,-.225),l(-.499,-.126),l(-.308,-.282),l(-.483,-.578),l(.149,-.692),l(-.111,-.437),l(-.474,-.818),l(-.747,-1.072),l(-.793,-.902),l(-1.069,-1.494),l(-.525,-.931),l(-.352,-.479),l(-.722,-.761),l(-.524,-.056),l(-.248,0),l(.077,-.296),l(.193,-.283),l(.311,-1.314),l(.104,-.583),l(.154,.017),l(2.079,.299),l(.975,-.782),l(.462,-.61),l(1.249,-.332),l(.24,-.072),l(.456,-.37),l(.765,-.724),l(-.698,-.885),l(-1.146,-1.32),l(.646,-.229),l(2.586,-.622),l(.97,-.26),l(.257,-.171),l(.46,-.44),l(.093,.056),l(1.129,.459),l(.757,.222),l(2.034,.934),l(1.14,.473),l(2.44,1.101),l(.258,.196),l(.399,.633),l(.141,.07),l(.973,-.048),l(.135,.366),l(-.118,.396),l(.047,.818),l(.118,.253),l(.812,.277),l(1.557,.697),l(4.048,.132),l(1.657,.259),l(.408,.054),l(.334,.619),l(.185,.239),l(1.07,.05),l(.644,-.044),l(.043,.121),l(.277,.648),l(.365,.494),l(.178,.663),l(.052,.113),l(.615,-.029),l(.248,.126),l(-.204,.237),l(.194,.187),l(.184,.282),l(.234,.067),l(.234,.27),l(.886,.168),l(.423,.437),l(-.07,.28),l(-.235,.035),l(-.111,.25),l(.316,.381),l(-.188,.593),l(-.122,.198),l(.165,.268),l(.302,.666),l(.149,-.117),l(.372,.282),l(.105,.616),l(.422,.696),l(-.028,.423),l(.222,.268),l(.16,.197),l(.287,.084),l(.136,-.007),l(.336,.083),l(1.043,2.198),l(.548,1.154),l(.261,.902),l(3.362,.375),l(3.387,.446),l(.839,.108),l(.584,-.469),l(.152,-.057),l(.581,.914),l(.155,1.453),l(-5.346,2.982),l(-2.35,1.213),l(-1.691,.815),l(-.169,.085),l(-1.148,.346),l(-3.097,1.035),l(-4.618,1.566),l(-.484,.229),l(-.041,.127),l(-.383,.397),l(-1.907,2.271),l(-2.042,2.667),l(-1.302,-2.703),l(-1.211,-2.45),l(-.452,-.012),l(-.715,.047),l(-.446,-.125),l(-.671,-.151),l(-.216,.1),l(-.174,.185),l(-.11,.495),l(.041,.678),l(-.113,.565),l(-.692,.563), +N(476.458,130.735),l(.124,.289),l(.796,1.944),l(.834,1.746),l(-.38,.381),l(-.479,1.145),l(-.334,1.413),l(-.171,.593),l(-.18,.156),l(-.407,-.07),l(-.448,-.521),l(-.782,-.676),l(-.386,-.494),l(-.338,-.988),l(-.521,-.45),l(-.289,-.621),l(-.17,-.479),l(-.198,-.353),l(-.466,.17),l(-.267,.523),l(.604,1.34),l(.131,.381),l(.634,.86),l(.933,1.042),l(.473,1.199),l(.526,.973),l(.277,.818),l(.391,.465),l(.912,1.735),l(1.072,1.904),l(.428,.705),l(.586,.549),l(.451,.352),l(.151,.183),l(-.241,.17),l(-.285,.1),l(-.043,.155),l(.238,1.087),l(.252,.467),l(.127,.238),l(.812,.591),l(.397,.168),l(.406,.521),l(.416,.38),l(.311,.56),l(-10.382,-.006),l(-2.138,-.001),l(-2.774,.002),l(-2.513,.015),l(-2.268,-.029),l(-1.664,.01),l(-1.241,.007),l(-1.614,-.019),l(-.914,.005),l(-.819,.089),l(-.011,-2.612),l(.021,-1.342),l(-.045,-2.81),l(.001,-.692),l(.008,-2.048),l(.016,-1.468),l(.019,-3.869),l(.015,-.988),l(-.042,-.367),l(-.388,-.916),l(-.185,-.945),l(.056,-.311),l(.322,-.553),l(.231,-.425),l(-.354,-1.283),l(.21,-.34),l(.369,-.228),l(.099,-.208),l(.337,.168),l(.553,-.015),l(.628,-.1),l(.786,-.001),l(1.513,.293),l(.587,.115),l(.779,.122),l(.721,.154),l(.348,.409),l(.4,0),l(.928,.083),l(.998,.394),l(.628,.069),l(.245,-.127),l(.72,-.538),l(.925,-.397),l(.837,-.186),l(.78,-.27),l(.375,-.072),l(.346,.056),l(.535,-.001),l(.723,.126),l(.202,.465),l(.596,.366),l(.518,-.156),l(.64,.267),l(.382,.027),l(.561,-.401),l(.241,.179),l(.277,.056),l(.674,.13),l(.338,-.062),l(.46,-.165),l(.51,-.308), +N(580.625,132.873),l(.24,.43),l(.299,.05),l(.276,-.314),l(.134,-.513),l(.275,.066),l(.186,-.182),l(1.079,.199),l(.132,.612),l(.867,.264),l(.726,.595),l(.472,.215),l(.15,-.132),l(.454,.281),l(.657,.794),l(.158,-.166),l(.71,-.116),l(.289,.166),l(.178,.38),l(-.069,.281),l(1.451,.893),l(.333,-.248),l(.326,.017),l(-.175,.396),l(.014,.265),l(.935,.066),l(.365,-.066),l(.54,.496),l(.141,.463),l(.237,-.099),l(-.01,-.364),l(.685,.38),l(.271,-.083),l(.08,-.331),l(.407,0),l(.63,.281),l(.319,.364),l(.849,-.066),l(.341,.116),l(.339,-.281),l(.655,.159),l(.037,.022),l(-.318,.761),l(-.07,.876),l(.429,.827),l(-.311,.694),l(-.336,-.05),l(-.687,.132),l(-.271,-.083),l(-.357,.132),l(-.399,-.116),l(-.268,-.364),l(-.606,.297),l(-.847,-.364),l(-.721,-.148),l(-.379,.231),l(-.312,-.248),l(.034,-.331),l(-.313,-.066),l(-.584,.281),l(-.618,-.265),l(-.286,-.281),l(-.663,-.149),l(.101,-.446),l(-.142,-.231),l(-.643,-.066),l(-.494,-.298),l(-.582,.347),l(-.482,-.265),l(-.503,0),l(-.087,.215),l(-.15,.066),l(-.304,-.198),l(-.835,-.166),l(-.182,-.397),l(-.538,.066),l(-1.027,-.595),l(-.231,.166),l(-1.242,-.678),l(-.305,-.529),l(-.704,-.149),l(-.665,-.479),l(-.466,.083),l(-.63,-.38),l(-.039,-.248),l(.218,-.43),l(.309,-.397),l(-.04,-.396),l(.221,-.265),l(-.008,-.364),l(.281,-.116),l(1.07,-.909), +N(374.125,167.166),l(-1.41,-.924),l(-.661,-.604),l(-.537,-.788),l(-.292,-.662),l(-.15,-.183),l(-.312,-.154),l(-.567,-.053),l(-.655,-.307),l(-.695,-.561),l(-.604,-.194),l(-.567,-.025),l(-1.209,.12),l(-1.821,.194),l(-.523,.417),l(.06,-.502),l(.563,-1.301),l(.188,-.819),l(.13,-1.13),l(-.162,-1.101),l(-.3,-.791),l(-.624,-.747),l(.267,-.283),l(.182,-.424),l(.067,-.975),l(-.065,-.537),l(-.174,-.353),l(-.808,-.817),l(-.297,-.112),l(-.393,.438),l(-.055,-.197),l(-.013,-.381),l(.08,-.689),l(.474,.013),l(5.055,.056),l(2.396,.014),l(.732,-.033),l(.212,.027),l(-.051,-1.102),l(-.164,-1.539),l(.01,-.707),l(.249,-.383),l(.575,-.427),l(.726,-.315),l(.809,-.287),l(.144,-.128),l(.099,-2.6),l(.07,-2.261),l(.047,-.509),l(.557,-.074),l(6.005,.022),l(.56,.011),l(.104,-.396),l(-.002,-.65),l(.03,-1.752),l(2.829,1.509),l(4.12,2.42),l(1.414,.91),l(-.523,.13),l(-3.231,.089),l(.049,.776),l(.908,7.962),l(.19,1.468),l(.178,1.736),l(.325,2.753),l(.202,2.386),l(.186,1.468),l(.724,.787),l(-.379,1.613),l(-6.457,.01),l(-1.953,.026),l(-.945,.344),l(-.387,.031),l(-.485,-.054),l(-.713,-.137),l(-.535,-.124),l(-.06,.212),l(.055,.296),l(-.107,.269),l(-.454,-.082),l(-.214,-.168),l(-.568,-.83),l(-.261,-.111),l(-.402,.073),l(-.252,.256),l(-.181,.552),l(-.018,.607),l(-.332,.284), +N(476.114,191.139),l(-.563,.54),l(-.626,.314),l(-.367,.016),l(-.303,-.196),l(-.303,-.097),l(-.88,.132),l(-.881,.33),l(-.911,.048),l(-.942,-.234),l(-.495,-.011),l(-.464,.087),l(-.496,.229),l(-1.288,-1.32),l(-1.032,-.926),l(-.207,-.083),l(-.258,.157),l(-.436,.582),l(-.16,.1),l(-.684,-.631),l(-.384,-.012),l(-.529,.37),l(-.258,.242),l(-.352,.016),l(-.366,-.195),l(-.525,-.477),l(-.348,-.493),l(-.795,-.772),l(-.143,-.239),l(-.031,-.07),l(.083,-.679),l(-.157,-.352),l(-.558,-.477),l(-.814,-.165),l(-.367,-.224),l(-.285,-.436),l(-.059,-.72),l(-.206,-.366),l(-.207,-.168),l(-.717,-.434),l(-.558,-.378),l(-.445,-.351),l(-.173,-.395),l(.148,-.481),l(-.223,-.267),l(-.351,-.196),l(-.799,-.235),l(-.797,-.447),l(-.223,-.225),l(-.252,-.493),l(-.207,-.126),l(-.272,.001),l(-.802,.019),l(-.158,-.211),l(-.01,-.664),l(.416,-1.472),l(-.122,-.536),l(-.347,-.549),l(-1.342,-1.673),l(.15,-.425),l(-.026,-.367),l(-.266,-.465),l(-.444,-.407),l(-.155,-.295),l(-.137,-.522),l(-.221,-1.228),l(-.141,-.225),l(-.338,-.012),l(-.517,.088),l(-.219,-.352),l(.316,-.609),l(.542,-.596),l(.087,-.34),l(-.342,-.662),l(.053,-.24),l(.718,-.428),l(.149,-.212),l(-.131,-.677),l(.122,-.438),l(.583,-.809),l(.417,-1.245),l(.229,-.143),l(1.245,-.05),l(.839,.009),l(.04,-.283),l(-.031,-1.229),l(-.036,-1.002),l(.038,-.749),l(-.085,-2.5),l(.036,-.636),l(.016,-.946),l(.02,-1.045),l(.073,-1.13),l(.52,.011),l(1.561,.019),l(.088,-.17),l(-.033,-3.078),l(.021,-1.003),l(.819,-.089),l(.914,-.005),l(1.614,.019),l(1.241,-.007),l(1.664,-.01),l(2.268,.029),l(2.513,-.015),l(2.774,-.002),l(2.138,.001),l(10.382,.006),l(.229,.414),l(.499,1.115),l(.281,3.501),l(.319,1.637),l(.182,.211),l(.625,.394),l(.595,.366),l(.617,.507),l(.491,.197),l(.254,.223),l(-.238,.199),l(-.277,.327),l(-.306,.566),l(-.369,.242),l(-.511,.172),l(-.427,.116),l(-.153,.142),l(-.235,.496),l(-.348,.171),l(-.73,.033),l(-.204,.552),l(-.038,.452),l(-.202,.862),l(-.242,.722),l(-.541,1.302),l(-.068,.495),l(.092,.903),l(-.013,.679),l(-.001,.083),l(-.148,.947),l(-.398,1.231),l(-.214,1.061),l(-1.04,.331),l(-.414,.37),l(-.693,1.134),l(-.154,.34),l(-.191,1.088),l(-.141,1.074),l(-.197,.185),l(-.274,.044),l(-.431,-.096),l(-.259,.072),l(-.163,.114),l(-.187,1.103),l(-.115,.933),l(-.2,1.272),l(.039,.522),l(-.229,1.159),l(-.469,.299),l(-.288,-.012),l(-.928,-.122),l(-.321,.03),l(-.188,.806),l(-.054,.466),l(.094,.141),l(.479,.11),l(.734,.123),l(.334,.167),l(.805,.913),l(1.06,1.067),l(.751,1.464),l(.345,.732),l(.348,.421),l(.462,.28),l(.415,.097),l(.269,.309),l(.117,.988),l(-.034,.17),l(-.018,.141),l(-.079,-.028),l(-.464,.017),l(-1.009,.133),l(-.832,.005),l(-.671,-.052),l(-.291,.327),l(-.678,.795), +N(518.402,163.079),l(-.282,.097),l(-.538,.27),l(-.656,.566),l(-.265,.297),l(-.166,.508),l(-.062,.41),l(-.41,.326),l(-1.418,.652),l(-2.27,.641),l(-1.285,.412),l(-.843,.312),l(-.356,.297),l(-.473,.622),l(-.436,.269),l(-.506,.114),l(-.593,-.069),l(-.521,.072),l(-.83,.439),l(-.65,.396),l(-.956,.397),l(-.752,.199),l(-1.16,.003),l(-.562,-.013),l(-.297,.128),l(-.386,.312),l(-.272,.297),l(-.45,.312),l(-.511,.241),l(-.389,.043),l(-.239,-.042),l(-.535,.411),l(-.839,.058),l(-.494,-.112),l(-.623,-.437),l(-.17,-.155),l(-.317,-.437),l(-.084,-.254),l(.18,-.721),l(-.081,-.635),l(-.312,-.507),l(-.341,-1.171),l(-.572,-1.919),l(-.072,-.438),l(.268,-.707),l(-.124,-.748),l(.692,-.563),l(.113,-.565),l(-.041,-.678),l(.11,-.495),l(.174,-.185),l(.216,-.1),l(.671,.151),l(.446,.125),l(.715,-.047),l(.452,.012),l(1.211,2.45),l(1.302,2.703),l(2.042,-2.667),l(1.907,-2.271),l(.383,-.397),l(.041,-.127),l(.484,-.229),l(4.618,-1.566),l(3.097,-1.035),l(1.148,-.346),l(.169,-.085),l(.092,.663),l(.226,.634),l(.604,.971),l(.933,1.364),l(.127,.253),l(-.006,.296),l(.483,.689),l(.241,.306), +N(494.64,172.627),l(-.261,-.166),l(-.476,-.633),l(-.475,-.159),l(-.437,-.911),l(-1.267,-.792),l(-.277,-.594),l(-.673,-.673),l(-.594,-.119),l(-.871,-.554),l(-.555,.079),l(-.158,-.158),l(-.237,.04),l(-.277,-.198),l(-.356,.159),l(-.476,.079),l(-.277,-.436),l(-.158,.237),l(-.436,.198),l(-.792,.079),l(-.554,-.594),l(-.238,0),l(-.396,-.317),l(-.832,1.663),l(-.436,-.871),l(-.475,.079),l(-.277,.356),l(-.396,-.08),l(-.349,.041),l(.013,-.679),l(-.092,-.903),l(.068,-.495),l(.541,-1.302),l(.242,-.722),l(.202,-.862),l(.038,-.452),l(.204,-.552),l(.73,-.033),l(.348,-.171),l(.235,-.496),l(.153,-.142),l(.427,-.116),l(.511,-.172),l(.369,-.242),l(.306,-.566),l(.277,-.327),l(.238,-.199),l(.098,.129),l(.718,2.102),l(.442,1.623),l(.689,1.919),l(.618,.832),l(.205,-.212),l(-.072,-.479),l(.093,-.226),l(.31,.253),l(.4,.677),l(.384,.395),l(.534,-.043),l(.242,.014),l(1.338,1.282),l(.809,.916),l(.124,.099),l(.706,.055),l(.618,.874),l(.021,.24),l(-.025,.198),l(.118,.212),l(.507,.182),l(.915,.869),l(-.075,.094),l(-.529,.78),l(-.331,-.182),l(-.396,-.125),l(-.214,.114),l(-.055,.085), +N(370.147,172.035),l(-2.301,-.043),l(-1.045,.006),l(-.505,.384),l(-.51,.187),l(-.74,-.024),l(-.819,.047),l(-.463,.139),l(-.009,-.003),l(-.278,-.226),l(-.169,-.409),l(.104,-.424),l(-.095,-.55),l(-.018,-.198),l(.001,-.046),l(1.695,.014),l(0,-.434),l(.155,0),l(.341,-.016),l(.186,-.077),l(.248,.062),l(.294,-.046),l(.124,-.093),l(.016,-.263),l(.077,-.078),l(.14,-.016),l(.155,.155),l(.232,.124),l(.356,.108),l(.046,.108),l(.139,.047),l(.217,-.031),l(.263,.108),l(.186,.17),l(.434,0),l(.186,-.108),l(.263,-.108),l(.279,0),l(.108,-.124),l(.016,-.124),l(-.155,-.217),l(-.202,-.077),l(-.201,.031),l(-.294,.093),l(-.108,.093),l(-.248,.062),l(-.279,-.186),l(-.031,-.186),l(-.186,-.108),l(-.17,-.015),l(-.186,.124),l(-.139,-.108),l(-.108,-.217),l(-.155,-.108),l(-.201,.031),l(-.17,-.062),l(-.387,.17),l(-.108,-.108),l(-.155,.046),l(-.202,.124),l(-.093,.294),l(-1.664,0),l(-.007,-.067),l(-.028,-.269),l(-.377,-.268),l(-.068,-.155),l(-.057,-.367),l(-.386,-.635),l(-.399,-.494),l(-.379,-.31),l(-.472,-.183),l(.54,-.34),l(.723,-.75),l(.588,-1.004),l(.334,-.82),l(.099,-.826),l(.523,-.417),l(1.821,-.194),l(1.209,-.12),l(.567,.025),l(.604,.194),l(.695,.561),l(.655,.307),l(.567,.053),l(.312,.154),l(.15,.183),l(.292,.662),l(.537,.788),l(.661,.604),l(1.41,.924),l(-.506,.399),l(-.057,.339),l(.251,1.1),l(.144,.663),l(.22,.479),l(.181,.197),l(.554,.322),l(.265,.337),l(.082,.833),l(-.004,.565),l(-.062,.142),l(-.146,-.042),l(-.963,.091),l(-.658,.074),l(-.725,-.081),l(-.503,-.209),l(-.795,-.32),l(-1.255,-.021), +N(495.973,175.881),l(-.363,.807),l(.083,.409),l(.428,.732),l(.587,.844),l(.732,.801),l(.596,.547),l(.634,.321),l(.54,.209),l(4.26,1.443),l(1.447,.472),l(1.875,-.04),l(.236,.154),l(-4.087,4.205),l(-1.562,1.69),l(-.813,.909),l(-.8,.004),l(-1.693,-.046),l(-.626,.088),l(-.562,.215),l(-.388,.214),l(-.502,.497),l(-.294,.426),l(-.337,.115),l(-1.216,.078),l(-.305,.101),l(-.453,.511),l(-1.103,-.106),l(-.461,-.181),l(-.46,-.336),l(-.271,-.098),l(-.852,.358),l(-.675,.343),l(-.258,.199),l(-.71,.753),l(-.16,.114),l(-.847,-.094),l(-.67,-.193),l(-1.373,-.133),l(-.335,-.041),l(-2.353,-1.525),l(-.604,-.293),l(-.749,-.193),l(-1.054,-.149),l(-.319,-.069),l(.018,-.141),l(.034,-.17),l(-.117,-.988),l(-.269,-.309),l(-.415,-.097),l(-.462,-.28),l(-.348,-.421),l(-.345,-.732),l(-.751,-1.464),l(-1.06,-1.067),l(-.805,-.913),l(-.334,-.167),l(-.734,-.123),l(-.479,-.11),l(-.094,-.141),l(.054,-.466),l(.188,-.806),l(.321,-.03),l(.928,.122),l(.288,.012),l(.469,-.299),l(.229,-1.159),l(-.039,-.522),l(.2,-1.272),l(.115,-.933),l(.187,-1.103),l(.163,-.114),l(.259,-.072),l(.431,.096),l(.274,-.044),l(.197,-.185),l(.141,-1.074),l(.191,-1.088),l(.154,-.34),l(.693,-1.134),l(.414,-.37),l(1.04,-.331),l(.214,-1.061),l(.398,-1.231),l(.148,-.947),l(.001,-.083),l(.349,-.041),l(.396,.08),l(.277,-.356),l(.475,-.079),l(.436,.871),l(.832,-1.663),l(.396,.317),l(.238,0),l(.554,.594),l(.792,-.079),l(.436,-.198),l(.158,-.237),l(.277,.436),l(.476,-.079),l(.356,-.159),l(.277,.198),l(.237,-.04),l(.158,.158),l(.555,-.079),l(.871,.554),l(.594,.119),l(.673,.673),l(.277,.594),l(1.267,.792),l(.437,.911),l(.475,.159),l(.476,.633),l(.261,.166),l(-.594,.921),l(-.488,.61),l(-.105,.254),l(-.029,.396),l(.202,1.157),l(.5,-.074),l(.892,-.246),l(.4,.04),l(.556,.195), +N(364.011,169.929),l(1.664,0),l(.093,-.294),l(.202,-.124),l(.155,-.046),l(.108,.108),l(.387,-.17),l(.17,.062),l(.201,-.031),l(.155,.108),l(.108,.217),l(.139,.108),l(.186,-.124),l(.17,.015),l(.186,.108),l(.031,.186),l(.279,.186),l(.248,-.062),l(.108,-.093),l(.294,-.093),l(.201,-.031),l(.202,.077),l(.155,.217),l(-.016,.124),l(-.108,.124),l(-.279,0),l(-.263,.108),l(-.186,.108),l(-.434,0),l(-.186,-.17),l(-.263,-.108),l(-.217,.031),l(-.139,-.047),l(-.046,-.108),l(-.356,-.108),l(-.232,-.124),l(-.155,-.155),l(-.14,.016),l(-.077,.078),l(-.016,.263),l(-.124,.093),l(-.294,.046),l(-.248,-.062),l(-.186,.077),l(-.341,.016),l(-.155,0),l(0,.434),l(-1.695,-.014),l(.019,-.477),l(.173,-.198),l(.434,-.058),l(.093,-.155),l(-.006,-.059), +N(495.973,175.881),l(-.556,-.195),l(-.4,-.04),l(-.892,.246),l(-.5,.074),l(-.202,-1.157),l(.029,-.396),l(.105,-.254),l(.488,-.61),l(.594,-.921),l(.055,-.085),l(.214,-.114),l(.396,.125),l(.331,.182),l(.529,-.78),l(.075,-.094),l(.627,.596),l(.285,.465),l(.036,.282),l(-.118,.113),l(-.361,.185),l(-.438,.1),l(-.56,.312),l(-.566,.467),l(.253,.127),l(.645,-.058),l(.321,.013),l(.434,.124),l(-.114,.26),l(-.37,.468),l(-.34,.567), +N(363.763,172.732),l(.463,-.139),l(.819,-.047),l(.74,.024),l(.51,-.187),l(.505,-.384),l(1.045,-.006),l(2.301,.043),l(-.111,.792),l(.115,.847),l(-.186,.312),l(-.333,.186),l(-.513,.031),l(-.401,.017),l(-.381,.186),l(-.789,.64),l(-.321,.372),l(-.047,-.126),l(-.192,0),l(-.501,-.14),l(-.165,-.254),l(.121,-.41),l(.33,-.438),l(.253,-.212),l(-.131,-.141),l(-.372,-.112),l(-.498,.015),l(-.415,.17),l(-.161,0),l(-.616,-.281),l(-.36,-.296),l(-.069,-.24),l(-.323,-.084),l(-.316,-.137), +N(383.005,177.596),l(-.379,.397),l(-.264,.623),l(.214,.409),l(.695,.405),l(.197,.31),l(-.125,.283),l(-.332,.37),l(.309,.351),l(.648,.561),l(.051,.226),l(-.19,.143),l(-.304,-.012),l(-.548,-.223),l(-.304,.03),l(-.158,.199),l(-.03,.127),l(.296,.549),l(.179,.21),l(-.188,.354),l(-.602,.554),l(-.047,.099),l(-.339,-.224),l(-.337,-.097),l(-.143,.086),l(-.756,.922),l(-.321,-.026),l(-.404,-.322),l(-.277,-.323),l(.044,-.283),l(-.009,-.65),l(-.22,-.846),l(-.165,-.366),l(-.338,-.097),l(-.528,.046),l(-.367,.143),l(-.252,.242),l(-.193,.376),l(-.26,-.656),l(-.165,-1.369),l(-.252,-.761),l(-.475,-.619),l(-.456,-.421),l(-.42,-.224),l(-.466,-.04),l(-1.137,.148),l(-.594,-.039),l(-.238,.157),l(-.643,.866),l(-1.088,1.235),l(.051,-.392),l(-.312,-.55),l(-.764,-.775),l(-.122,-.649),l(-.84,-.366),l(-.908,-.563),l(-.277,-.296),l(.09,-.396),l(-.053,-.311),l(-.547,-.041),l(-.323,-.098),l(-.115,-.155),l(.059,-.311),l(-.038,-.1),l(.321,-.372),l(.789,-.64),l(.381,-.186),l(.401,-.017),l(.513,-.031),l(.333,-.186),l(.186,-.312),l(-.115,-.847),l(.111,-.792),l(1.255,.021),l(.795,.32),l(.503,.209),l(.725,.081),l(.658,-.074),l(.963,-.091),l(.146,.042),l(.113,.028),l(.18,.183),l(.882,.715),l(.536,.265),l(.252,-.256),l(.475,-.413),l(.338,.026),l(.356,.153),l(.565,.152),l(.43,-.243),l(.3,-.327),l(.684,-.428),l(.323,.055),l(.246,.281),l(.022,.339),l(.271,.832),l(.265,.451),l(.474,.478),l(.349,.718),l(.194,1.143),l(.559,.901), +N(266.015,188.956),l(.103,.169),l(-.163,.326),l(-.592,.385),l(-1.74,.9),l(-.807,.23),l(-.557,.074),l(-.465,-.054),l(-.284,.115),l(-.232,1.117),l(-.348,.115),l(-.628,-.618),l(-.344,-.224),l(-1.149,.035),l(-.385,-.04),l(-.896,-.461),l(-.309,-.125),l(-.159,.029),l(-.041,.184),l(.616,.688),l(.391,.69),l(.302,1.524),l(.079,.55),l(.166,.239),l(.96,.051),l(.434,.125),l(.15,.253),l(-.265,.27),l(-.569,.272),l(-.652,.131),l(-.203,.199),l(-.259,.666),l(-.235,.213),l(-.652,.173),l(-.554,.286),l(-.74,.654),l(-.645,.739),l(-.271,.016),l(-.186,-.776),l(-.083,-.183),l(-.757,.697),l(-.414,.073),l(-.482,-.223),l(-.694,-.546),l(-.432,-.054),l(-.199,-.437),l(-.088,-.452),l(-.161,-.861),l(-.138,-.437),l(-.148,-.168),l(-.797,-1.182),l(-.51,-.491),l(.479,-.526),l(.731,-.612),l(-.121,-.282),l(-.486,-.647),l(-.256,-.437),l(-.447,-.789),l(-.162,-.804),l(-.048,-.367),l(-.035,-.438),l(-.026,-.254),l(.147,-.326),l(.379,-.511),l(.085,-1.004),l(.409,-.525),l(-.644,-.081),l(-1.99,.224),l(-.76,.174),l(-.522,.13),l(-.144,0),l(-.554,-.576),l(-.847,-.998),l(-.188,-.253),l(-.64,-.321),l(-.521,-.181),l(-1.167,.05),l(-1.163,.12),l(-.496,.017),l(-.397,-.252),l(-.429,-.548),l(-.401,-.309),l(-.099,-.353),l(.226,-1.132),l(-.103,-.395),l(-.855,-1.45),l(-.31,-.606),l(-.384,.017),l(-.234,.1),l(-.402,-.025),l(.709,-1.191),l(.241,-.722),l(.172,-.722),l(.99,-1.758),l(.381,-.059),l(.227,.027),l(.129,-.396),l(-.048,-.497),l(.056,-.288),l(.414,-.2),l(.534,-.156),l(.84,-.171),l(.128,.105),l(-.9,.151),l(-.731,.312),l(-.145,.212),l(.19,.607),l(.142,.407),l(.224,.126),l(-.043,.145),l(.153,.579),l(-.135,.367),l(-.327,.364),l(-.348,.824),l(-.137,.368),l(.253,.479),l(.288,.253),l(.25,.72),l(.341,.353),l(.523,-.114),l(.184,-.156),l(.419,-.255),l(.12,-.142),l(.066,-.523),l(-.167,-.649),l(-.21,-.282),l(-.438,-.804),l(-.136,-.135),l(-.118,-.395),l(-.247,-.18),l(.239,-.099),l(.095,-.251),l(-.204,-.144),l(1,-.379),l(1.085,-.327),l(.998,-.272),l(.086,-.225),l(.69,-.086),l(.143,-.008),l(-.042,-.157),l(-.055,-.198),l(-.125,-.036),l(-.039,-.108),l(-.128,-.072),l(-.226,.071),l(-.156,.027),l(-.229,-.012),l(-.315,-.55),l(.109,-.254),l(.337,-.213),l(.367,-.043),l(.09,.112),l(.14,.368),l(.186,.162),l(-.001,.148),l(.026,.193),l(.068,.09),l(.004,.198),l(.253,.258),l(.329,-.02),l(.699,.111),l(.455,.07),l(.593,.196),l(.323,.254),l(.393,.564),l(.156,.635),l(.358,.324),l(.359,.084),l(1.02,-.129),l(.928,-.059),l(.59,-.058),l(.799,-.059),l(.714,.125),l(.4,.479),l(.267,.169),l(.578,.253),l(.49,.14),l(1.094,.04),l(.382,-.057),l(.388,-.227),l(1.042,-.807),l(.47,-.185),l(.453,.042),l(.959,-.073),l(1.152,-.073),l(.919,.055),l(.248,.112),l(-.056,.141),l(-.294,.185),l(-.854,-.041),l(-.433,.015),l(-.083,.212),l(.059,.184),l(.593,.253),l(.609,.535),l(.195,.649),l(.246,-.523),l(.185,-.142),l(.415,.253),l(.483,.027),l(.374,.098),l(.258,.338),l(.918,.394),l(.464,.295),l(-.729,.496),l(-.161,.65),l(-.214,.226),l(-1.055,.417),l(.5,.064),l(.598,.098),l(.368,-.029),l(.33,-.142),l(.929,-.03),l(.725,.083),l(.84,.274),l(.095,.296),l(-.061,.41),l(-1.655,1.239),l(-.101,.255),l(.074,.212),l(.62,.604),l(.141,.282),l(-.308,.299),l(-.41,.144),l(-1.032,.19),l(-.061,.452),l(.008,.58),l(-.395,.539),l(-.071,.212),l(.324,.521),l(.732,.745),l(.503,.647), +N(493.044,204.258),l(-1.223,-1.771),l(-.027,-.932),l(-.03,-1.43),l(-.042,-2.045),l(-.003,-1.017),l(0,-.438),l(.016,-.848),l(.004,-1.215),l(.002,-.508),l(1.649,-2.467),l(.453,-.511),l(.305,-.101),l(1.216,-.078),l(.337,-.115),l(.294,-.426),l(.502,-.497),l(.388,-.214),l(.562,-.215),l(.626,-.088),l(1.693,.046),l(.8,-.004),l(.813,-.909),l(1.562,-1.69),l(4.087,-4.205),l(-.236,-.154),l(-1.875,.04),l(-1.447,-.472),l(-4.26,-1.443),l(-.54,-.209),l(-.634,-.321),l(-.596,-.547),l(-.732,-.801),l(-.587,-.844),l(-.428,-.732),l(-.083,-.409),l(.363,-.807),l(.34,-.567),l(.37,-.468),l(.114,-.26),l(.154,.044),l(.935,1.142),l(.586,.62),l(.243,.381),l(.265,.211),l(.372,-.071),l(.417,-.001),l(.465,.027),l(.372,-.071),l(.572,-.27),l(.836,-.425),l(.585,-.157),l(.397,.098),l(.76,.267),l(.549,-.072),l(.56,-.326),l(.779,-.566),l(.247,-.127),l(.447,.041),l(.479,.098),l(.419,-.043),l(1.195,-.482),l(.288,.027),l(.682,.196),l(.74,-.03),l(.764,-.185),l(.964,-.327),l(.9,-.666),l(.47,-.382),l(.604,.154),l(.391,.211),l(.08,.014),l(.147,.268),l(-.414,.919),l(.021,.564),l(.132,.621),l(-.165,.452),l(-.375,.509),l(-.028,.678),l(-.047,.833),l(-.163,.509),l(-1.264,2.262),l(-.842,.792),l(-.122,.311),l(.102,.353),l(-.893,1.569),l(-.834,1.272),l(-.214,.947),l(-.351,.636),l(-.712,1.117),l(-.874,1.188),l(-1.159,1.498),l(-.384,.439),l(-2.274,2.504),l(-1.82,1.557),l(-2.164,1.121),l(-.593,.382),l(-1.28,1.09),l(-1.74,1.755),l(-.06,.061),l(-1.055,1.1),l(-1.235,1.569),l(-.615,.835),l(.1,.353),l(-.094,.276), +N(264.768,176.039),l(-.128,.225),l(-.115,.067),l(-.029,.135),l(.039,.25),l(-.058,.086),l(.125,.376),l(-.039,.424),l(-.453,.154),l(-.135,-.01),l(-.144,.039),l(-.482,-.039),l(-.192,.039),l(-.087,-.048),l(-.356,0),l(-.02,-.058),l(.039,-.067),l(.202,-.029),l(.222,-.135),l(.019,-.087),l(.106,.02),l(.154,.01),l(.135,-.145),l(-.096,-.279),l(.048,-.125),l(.029,-.183),l(-.067,-.125),l(-.097,-.135),l(-.279,-.048),l(.116,-.096),l(.164,-.019),l(.231,-.029),l(.115,-.087),l(.385,.02),l(.106,-.039),l(.299,-.067),l(.244,.006), +N(654.075,190.187),l(.206,-.125),l(.63,-.114),l(.656,-.938),l(.241,-.07),l(-.069,.268),l(.122,.087),l(.187,-.046),l(.11,.174),l(.148,.444),l(-.024,.111),l(-.013,.247),l(.197,.197),l(.025,.086),l(-1.234,.42),l(-.383,.271),l(-.309,-.271),l(-.111,-.259),l(-.234,.012),l(-.062,-.37),l(-.084,-.126), +N(493.044,204.258),l(-.602,.389),l(-.557,.171),l(-.385,-.112),l(-.086,.777),l(-.282,.367),l(-.67,.115),l(-.394,.382),l(-.088,.48),l(.006,.353),l(-.356,.622),l(-.964,1.358),l(.092,.536),l(-.337,.65),l(-.25,.255),l(-.334,.1),l(-.084,.152),l(-1.067,-.807),l(-2.427,-1.752),l(-.07,-.239),l(.116,-.552),l(-.137,-.381),l(-3.553,-1.984),l(-4.663,-2.568),l(-1.448,.033),l(1.144,-2.479),l(.105,-.229),l(.656,-.835),l(.985,-.938),l(.477,-.525),l(.43,-.695),l(.143,-.566),l(-.048,-.664),l(-.223,-.606),l(-.224,-.352),l(-.732,-1.069),l(-.174,-.465),l(-.027,-.861),l(-.126,-.226),l(-.477,-.463),l(-.3,-.493),l(.678,-.795),l(.291,-.327),l(.671,.052),l(.832,-.005),l(1.009,-.133),l(.464,-.017),l(.079,.028),l(.319,.069),l(1.054,.149),l(.749,.193),l(.604,.293),l(2.353,1.525),l(.335,.041),l(1.373,.133),l(.67,.193),l(.847,.094),l(.16,-.114),l(.71,-.753),l(.258,-.199),l(.675,-.343),l(.852,-.358),l(.271,.098),l(.46,.336),l(.461,.181),l(1.103,.106),l(-1.649,2.467),l(-.002,.508),l(-.004,1.215),l(-.016,.848),l(0,.438),l(.003,1.017),l(.042,2.045),l(.03,1.43),l(.027,.932),l(1.223,1.771), +N(466.196,203.275),l(.188,-.298),l(.076,-.27),l(-.057,-.748),l(.025,-.734),l(-.021,-.593),l(.107,-.507),l(.217,-1.02),l(.395,-.681),l(.255,-.284),l(1.241,-.996),l(1.195,-1.066),l(.191,-.453),l(-.111,-.31),l(-.271,-.182),l(-.479,-.04),l(-.191,-.027),l(-.128,-.253),l(.26,-1.88),l(.018,-.424),l(-.159,-.183),l(-.063,-.028),l(.496,-.229),l(.464,-.087),l(.495,.011),l(.942,.234),l(.911,-.048),l(.881,-.33),l(.88,-.132),l(.303,.097),l(.303,.196),l(.367,-.016),l(.626,-.314),l(.563,-.54),l(.3,.493),l(.477,.463),l(.126,.226),l(.027,.861),l(.174,.465),l(.732,1.069),l(.224,.352),l(.223,.606),l(.048,.664),l(-.143,.566),l(-.43,.695),l(-.477,.525),l(-.985,.938),l(-.656,.835),l(-.105,.229),l(-1.144,2.479),l(-4.659,0),l(-1.277,.05),l(-.319,.017),l(-.554,.398),l(-.458,.427),l(-.431,.045),l(-.546,-.223),l(-.064,-.042), +N(713.621,206.298),l(.169,7.966),l(-.44,.822),l(.431,1.368),l(.046,.805),l(-.031,3.438),l(-.515,-.512),l(-.927,-.888),l(-.716,-.902),l(-.406,-.056),l(-.776,.101),l(-.739,.143),l(-.434,-.013),l(.091,-.382),l(.435,-.65),l(.006,-.283),l(-.561,-.521),l(-.565,-.775),l(.028,-.226),l(.442,.111),l(.236,-.042),l(.135,-.113),l(-.467,-.409),l(-.595,-.408),l(-.287,-.381),l(-.275,-.648),l(-1.053,-1.693),l(-.508,-.394),l(-.467,-.282),l(-.604,-.196),l(-1.983,-.603),l(-1.26,-.379),l(-.613,-.069),l(-.705,-.238),l(-.63,-.323),l(.072,-.34),l(-.098,-.268),l(-.193,-.028),l(-.617,.101),l(-.389,-.07),l(-.412,-.196),l(-.408,-.395),l(-.209,-.579),l(.133,-.494),l(-.155,-.226),l(-.187,.113),l(-.234,.396),l(-.122,.664),l(-.251,.608),l(-.334,.269),l(-.696,.354),l(-.155,-.169),l(-.331,-.677),l(.022,-.155),l(.384,-.27),l(-.152,-.424),l(-.173,-.239),l(-.564,-.395),l(-.707,-.394),l(-.338,-.056),l(-.059,-.212),l(.038,-.226),l(.413,-.044),l(.388,.084),l(.603,.239),l(.158,-.029),l(.368,-.34),l(.525,-.41),l(.146,.056),l(.3,.269),l(1.021,-.045),l(.139,-.128),l(.09,-.522),l(-.063,-.409),l(-.238,.028),l(-.345,.199),l(-.604,.071),l(-.656,-.041),l(-.766,.044),l(-1.026,-.082),l(-.411,-.31),l(-.135,-.197),l(-.148,-.664),l(-.202,-.338),l(-.42,-.155),l(-1.249,-.124),l(.265,-.297),l(.058,-.255),l(.004,-.593),l(.463,-.029),l(.92,-.411),l(.49,-.383),l(.444,-.283),l(.352,.027),l(.4,.069),l(1.494,.646),l(.515,.169),l(.913,.153),l(.382,.705),l(.138,.396),l(-.283,.749),l(-.067,.381),l(.221,.381),l(.115,.494),l(.115,.48),l(.215,.521),l(.186,.197),l(.197,.127),l(.226,-.65),l(.085,.113),l(.087,.141),l(.309,1.073),l(.169,.169),l(.234,.183),l(.294,.112),l(.354,.056),l(.58,-.198),l(.504,-.439),l(1.192,-1.853),l(.352,-.015),l(1.078,-.215),l(.378,-.142),l(.045,-.085),l(.014,-.509),l(.219,-.17),l(1.1,-.609),l(.335,-.043),l(1.732,.759),l(2.129,.941),l(1.54,.52),l(1.299,.404),M(691.208,208.707),l(-.388,-.069),l(-.693,-.38),l(-.852,-.647),l(-.295,-.141),l(-.414,.028),l(-.059,.1),l(.024,.452),l(-.206,.028),l(-1.014,-.407),l(-.258,-.353),l(-.582,.199),l(-.289,.269),l(-.326,.185),l(-.186,-.184),l(-.312,-.451),l(-.245,-.451),l(.246,-.198),l(.303,-.029),l(.274,.056),l(1.104,.04),l(.574,.31),l(.319,-.015),l(.544,-.326),l(.414,-.015),l(.534,.126),l(.857,.21),l(.499,.395),l(.293,.395),l(.179,.621),l(-.049,.254),M(682.045,208.699),l(-.419,-.056),l(-.715,-.493),l(-.232,-.451),l(.146,-.283),l(.603,-.1),l(.766,-.044),l(.246,.126),l(.256,.311),l(.313,.197),l(.108,.226),l(-.067,.226),l(-.125,.057),l(-.879,.285),M(707.635,219.095),l(-1.11,-.209),l(.589,-1.032),l(.56,-.708),l(.407,-.269),l(.427,-.072),l(.527,.338),l(.198,.24),l(-.11,.184),l(-.324,.637),l(-.256,.17),l(-.638,.693),l(-.27,.028),M(673.797,218.703),l(-.562,.257),l(.034,.233),l(-.886,.326),l(-.582,.274),l(-.339,-.041),l(-.453,.325),l(-.504,-.069),l(-.427,-.112),l(-.378,.255),l(-.3,.058),l(-.358,-.07),l(-.58,-.196),l(-1.046,-.04),l(-.316,.043),l(-.211,-.564),l(.027,-.24),l(.383,-.198),l(.672,-.199),l(.528,-.016),l(1.142,.407),l(.445,.324),l(.338,.013),l(.326,-.297),l(.464,-.016),l(.429,-.071),l(.414,.187),l(.467,-.116),l(-.072,-.222),l(.421,-.187),l(.404,-.233),l(.094,-.151),l(-.076,-.117),l(-.184,.023),l(.116,-.198),l(.16,.012),l(.22,.094),l(.177,.221),l(.013,.304),M(662.661,219.065),l(-.312,-.099),l(-.203,-.127),l(-.062,-.169),l(.03,-.212),l(.256,-.198),l(.315,-.036),l(.17,.092),l(.053,.212),l(.182,.098),l(.305,-.145),l(.34,.105),l(.104,.151),l(-.012,.451),l(.183,-.148),l(.163,-.304),l(.318,-.029),l(.229,.226),l(.021,.424),l(.181,-.036),l(.062,.104),l(-.025,.397),l(-.316,-.211),l(-.311,-.058),l(-.141,.058),l(.072,.155),l(-.852,.157),l(-.143,-.091),l(.097,-.268),l(-.085,-.059),l(-.308,.269),l(-.229,.256),l(-.296,-.046),l(-.63,.225),l(-.624,.199),l(-.357,-.051),l(-.31,.123),l(-.392,-.07),l(-.103,-.07),l(-.202,-.123),l(-.063,-.279),l(.143,-.261),l(-.08,-.253),l(.193,-.115),l(.23,-.113),l(.233,-.156),l(.224,.07),l(.61,.013),l(.4,.104),l(.089,.28),l(.291,.109),l(.294,.056),l(.189,-.259),l(.29,-.012),l(.051,-.187),l(-.263,-.15),M(656.294,219.602),l(-.393,-.282),l(-.855,-.449),l(-.118,-.269),l(.417,-.001),l(.514,-.185),l(.462,-.029),l(.925,.521),l(-.338,.17),l(-.232,.1),l(-.381,.425),M(631.053,200.125),l(-.061,.225),l(-.413,.439),l(-.204,.41),l(-.381,.354),l(.164,.353),l(.162,.169),l(.806,.493),l(.832,.055),l(.241,.112),l(.151,.381),l(.128,.763),l(-.007,.409),l(.267,.423),l(.212,.127),l(.544,.041),l(-.45,.933),l(.151,.212),l(.703,-.453),l(.824,.252),l(.177,.042),l(.265,.254),l(.144,.438),l(.698,.676),l(-.515,1.979),l(-.04,.452),l(.23,.946),l(-.021,.438),l(.021,.664),l(-.002,.268),l(-.149,1.06),l(-.087,.156),l(-.107,.07),l(-.367,-.253),l(-.381,-.522),l(-.261,-.084),l(-.262,.481),l(-.081,.268),l(-1.043,-.619),l(-.219,.086),l(.394,.747),l(-.163,.213),l(-.204,-.197),l(-1.343,-1.424),l(-.775,-.761),l(-1.011,-.859),l(-1.348,-.958),l(-.391,-.451),l(-.199,-.493),l(-.191,-.339),l(-1.003,-.633),l(-.697,-.677),l(-1.186,-1.509),l(-.074,-.353),l(.039,-.339),l(-.324,-.875),l(-.841,-1.467),l(-.667,-1.044),l(-.612,-.775),l(-.369,-.301),l(-.287,-.234),l(-.64,-.295),l(-.254,-.748),l(-.688,-1.806),l(.067,-.24),l(-.107,-.311),l(-.157,-.197),l(-.662,-.507),l(-.711,-.394),l(-.539,-.21),l(-.317,-.099),l(-.119,-.353),l(-.077,-.734),l(-.18,-.409),l(-.386,-.479),l(-.818,-.831),l(-.368,-.423),l(-.725,.128),l(-.613,-.676),l(-.646,-.606),l(-.593,-.69),l(-.562,-.945),l(-.229,-.635),l(-.032,-.367),l(.057,-.198),l(.149,-.113),l(.401,-.043),l(.364,.098),l(.25,.126),l(.632,.563),l(.361,.155),l(.922,.153),l(.335,.027),l(.548,-.1),l(.454,-.142),l(.4,-.015),l(.323,.31),l(.919,1.156),l(.513,.31),l(.058,.155),l(-.12,.537),l(1.066,.916),l(.749,.493),l(1.175,.689),l(.678,.323),l(.139,.169),l(.03,.593),l(-.02,.155),l(.573,.055),l(.745,.944),l(.612,.55),l(.271,-.015),l(.004,-.198),l(-.123,-.226),l(.069,-.24),l(.507,.21),l(.479,.804),l(.441,.38),l(.446,.056),l(.429,.197),l(.314,.366),l(.28,.734),l(.316,.437),l(.431,.268),l(.511,.126),l(.767,.083),l(.431,.154),l(.494,.38),l(.576,.606),l(-.019,.071),M(684.201,200.125),l(-.007,-.172),l(-.414,-1.058),l(.18,-.551),l(-.078,-.141),l(-.141,-.296),l(.036,-.325),l(.286,-.89),l(.514,-.82),l(.263,.367),l(.152,.353),l(-.054,.283),l(-.246,.396),l(-.361,.763),l(.061,.325),l(.19,.141),l(.097,-.141),l(.436,-.411),l(.135,-.522),l(.179,-.142),l(.806,-.412),l(.141,.141),l(-.052,.254),l(.104,.55),l(-.354,.212),l(-.467,.354),l(-.162,.311),l(.159,.099),l(.446,.126),l(.398,.211),l(-.016,.141),l(.159,.353),l(-.688,-.154),l(-.431,-.154),l(-.367,-.042),l(-.304,.156),l(-.08,.438),l(.049,.258),l(.131,.688),l(.341,.62),l(.405,.438),l(.196,.282),l(-.156,.212),l(-.26,-.211),l(-.664,-.648),l(-.55,-.733),l(-.002,-.396),l(-.011,-.251),M(637.361,207.144),l(-.863,-.394),l(-.377,-.239),l(-.205,-.367),l(-.045,-.367),l(-.156,-.395),l(-.507,-.395),l(-.291,-.099),l(-.446,.029),l(-.116,-.141),l(.271,-.65),l(.234,-.24),l(.509,.55),l(.148,-.467),l(.313,-.269),l(.072,.395),l(.312,.89),l(.648,.817),l(.698,.31),l(-.265,.184),l(-.118,.283),l(.183,.564),M(634.321,215.345),l(-.091,-.187),l(.316,-.023),l(.402,.093),l(.369,-.129),l(.068,-.524),l(.018,-.14),l(.309,.057),l(-.043,-.5),l(.222,-.235),l(.093,-.277),l(.202,.121),l(.631,.112),l(.474,-.047),l(.237,.443),l(.524,-.089),l(.158,-.297),l(.022,-.244),l(.259,.116),l(.618,.168),l(.411,.438),l(.338,-.046),l(.204,.271),l(.446,-.029),l(.453,-.185),l(.302,.211),l(.369,.522),l(.179,.521),l(.884,.041),l(.462,.188),l(.49,-.077),l(1.435,.124),l(.479,-.029),l(.34,-.17),l(.213,-.65),l(.271,-.269),l(.447,-.015),l(.223,.211),l(.289,.494),l(.633,.125),l(.53,.027),l(.774,.083),l(.796,.153),l(.289,.24),l(.293,.288),l(-.08,.445),l(.275,.466),l(.119,.099),l(.877,.352),l(.422,.069),l(.658,.013),l(.45,-.185),l(.415,-.015),l(.628,.238),l(.048,.197),l(-.255,.425),l(-.152,.494),l(.578,.776),l(-.499,-.211),l(-.802,-.196),l(-.599,-.253),l(-.891,-.309),l(-.528,.001),l(-.589,.256),l(-.348,.057),l(-.714,-.098),l(-1.454,-.138),l(-1.47,-.138),l(-.805,-.253),l(-.839,-.479),l(-1.099,-.336),l(-1.125,-.267),l(-.948,-.04),l(-.556,.298),l(-.445,.043),l(-.957,-.153),l(-.805,-.492),l(-.357,-.07),l(-1.606,-.066),l(-.363,-.155),l(.055,-.141),l(.448,-.468),l(-.402,-.267),l(-.551,-.099),l(-.506,-.14),l(-.307,-.027),l(-1.261,-.121),M(675.004,223.092),l(.249,-.494),l(.023,-.537),l(.113,-.312),l(.674,-.481),l(1.447,-.624),l(.662,-.454),l(.36,-.607),l(.466,-.157),l(1.578,-.102),l(.91,-.214),l(.541,-.044),l(.869,-.143),l(.118,.07),l(.099,.197),l(-.237,.212),l(-.36,.256),l(-1.609,.61),l(-1.369,.44),l(-.713,.256),l(-.606,.354),l(-1.09,.963),l(-.653,.481),l(-.439,.086),l(-.552,.228),l(-.48,.015),M(667.866,223.149),l(-.217,-.069),l(-.917,-.605),l(-.8,-.45),l(-.347,-.099),l(-.493,-.126),l(-.292,-.197),l(.108,-.212),l(.371,-.142),l(.992,-.03),l(.502,-.114),l(.35,.296),l(1.147,.746),l(.265,.381),l(-.125,.325),l(-.246,.24),l(-.299,.057),M(661.819,191.241),l(-.041,.09),l(.319,.691),l(-.23,.142),l(-.546,.043),l(-.579,.086),l(.198,.226),l(.115,.296),l(-.169,.226),l(.216,.211),l(.235,.112),l(.546,.832),l(.536,.747),l(.043,.198),l(-.338,.721),l(.075,.226),l(.406,.465),l(.743,.45),l(.6,.493),l(.551,.761),l(-.465,.17),l(-.75,-.026),l(-.797,-.238),l(-.337,.1),l(-.387,.467),l(-.354,.918),l(-.08,.476),l(-.046,.272),l(.132,.649),l(.116,.424),l(-.133,.848),l(-.256,0),l(-.466,-.154),l(-1.037,.963),l(-.433,.65),l(-.751,.608),l(.443,.381),l(.06,.396),l(.17,.296),l(-.685,.058),l(.452,.578),l(.009,.212),l(-.103,.227),l(-.547,.665),l(-.206,.396),l(-.127,.354),l(-.529,.594),l(-1.294,.61),l(-.607,.284),l(-.292,.198),l(-.194,-.311),l(.024,-.424),l(-.33,-.804),l(-.306,-.381),l(-.265,-.184),l(-.286,.029),l(-.503,.523),l(-.302,.029),l(-.328,-.508),l(-.313,-.197),l(-.437,-.112),l(-.387,-.451),l(-.342,-.154),l(-.35,.806),l(-.135,.198),l(-.381,.058),l(-.356,-.112),l(-.442,.128),l(-.318,.354),l(-.364,.071),l(-.059,-.551),l(.034,-.311),l(-.314,-1.03),l(-.336,.396),l(-1.42,.44),l(-.321,-.408),l(-.639,.015),l(-.281,.156),l(-.303,.029),l(-.058,-.649),l(-.022,-.65),l(-.267,-1.411),l(-.012,-.48),l(-.352,-.747),l(-.406,-.409),l(-.79,-.422),l(-.146,-.141),l(.555,-.354),l(-.531,-.38),l(-.258,-.296),l(.188,-.735),l(-.074,-.128),l(-.278,-.478),l(-.352,-.296),l(.065,-.466),l(-.125,-.593),l(.182,-.65),l(.133,-.353),l(.424,-.58),l(.303,-.806),l(.318,.028),l(.204,.11),l(.288,.792),l(.253,.295),l(1,.983),l(.304,.083),l(.446,.28),l(.928,-.416),l(.255,-.001),l(.526,.223),l(.543,.11),l(.399,-.172),l(.528,-.342),l(.403,-.525),l(.531,-.441),l(.479,-.074),l(.431,.11),l(.557,.251),l(.524,.223),l(.559,.152),l(.287,-.03),l(.467,-.356),l(.465,-.172),l(.864,-.175),l(.387,-.299),l(.928,-1.785),l(-.076,-.748),l(.218,-.34),l(.646,-.244),l(.22,-.383),l(-.106,-.988),l(.119,-.565),l(.381,-.638),l(.247,-.157),l(.464,-.017),l(.748,.081),l(.651,.081),l(.624,-.018),l(.446,.04),l(.753,.292),l(.182,.09),M(666.561,200.125),l(.012,-.049),l(.48,-1.188),l(.434,-.41),l(.289,-.142),l(.429,.338),l(.29,-.311),l(.162,-.325),l(.293,-.481),l(.496,-.058),l(.605,.14),l(.729,.535),l(.447,.027),l(.863,-.044),l(.478,.168),l(.749,.267),l(.577,-.227),l(1.853,.081),l(.72,-.128),l(.627,-.354),l(.211,-.283),l(-.156,-.268),l(.196,-.283),l(.388,-.241),l(.295,-.41),l(.289,-.057),l(.075,.24),l(-.073,.537),l(-.117,.311),l(-.081,.127),l(-.082,.127),l(-.969,1.259),l(-.416,.396),l(-.464,.1),l(-1.23,.229),l(-.495,-.069),l(-.591,-.422),l(-1.149,-.068),l(-1.151,.059),l(-.878,-.041),l(-1.039,.045),l(-.575,-.083),l(-.671,.029),l(-.415,.1),l(-.433,.368),l(-.259,.461),l(-.154,.274),l(-.187,.721),l(.068,.48),l(.263,.494),l(.194,.183),l(.403,.226),l(.259,.196),l(.221,.607),l(.179,.154),l(.226,.042),l(.815,.026),l(.249,-.269),l(.652,-.976),l(.385,.056),l(.307,.183),l(.496,.041),l(.363,-.227),l(.669,-.156),l(.62,-.143),l(.268,-.298),l(.271,-.057),l(.466,.196),l(.131,.212),l(-.083,.734),l(-.469,-.267),l(-.544,-.042),l(-.361,.298),l(-.389,.523),l(-.438,.425),l(-1.059,.439),l(-.214,.325),l(-.143,.029),l(-.241,-.042),l(-.468,-.126),l(-.03,.056),l(.025,.312),l(.212,.126),l(.676,.578),l(.467,.521),l(.854,1.24),l(-.097,.325),l(-.156,.679),l(.102,.409),l(.447,.535),l(.555,.438),l(.062,.226),l(-.045,.282),l(-.436,-.056),l(-.652,.059),l(-.412,.297),l(-.224,.692),l(-.498,-.026),l(-.461,-.183),l(-.107,-.17),l(.052,-.649),l(.204,-.58),l(-.978,-.845),l(-.417,-.31),l(-.174,-.269),l(.036,-.24),l(.284,-.396),l(.116,-.579),l(-.165,-.494),l(-.737,-.055),l(-.503,.213),l(-.494,.396),l(.16,.353),l(.143,.932),l(-.068,.509),l(-.236,1.145),l(.363,.903),l(-.01,.311),l(-.377,.636),l(-.019,.227),l(.275,.564),l(-.726,.171),l(-.513,.241),l(-.476,.071),l(-.245,-.324),l(-.16,-.522),l(.156,-.325),l(.181,-.466),l(.069,-.876),l(.06,-1.073),l(-.125,-.509),l(.029,-.339),l(-.213,-.395),l(-.311,-.127),l(-.391,.171),l(-.574,.029),l(.011,-.41),l(-.25,-1.284),l(.131,-.311),l(.491,-.524),l(.469,-.777),l(.161,-.48),l(-.089,-.918),l(-.006,-.254),l(.087,-.452),l(.339,-.721),l(.447,-.058),l(-.043,-.861),l(.254,-1.053), +N(341.05,41.069),l(2.084,.272),l(.344,.361),l(-.869,.174),l(-.541,.139),l(-1.678,.106),l(-1.159,.037),l(-.689,.156),l(-.372,.224),l(-.308,.6),l(-.361,.376),l(1.05,.39),l(.971,.168),l(2.117,.064),l(.601,-.001),l(1.775,-.242),l(1.93,-.038),l(.866,.135),l(.933,.219),l(.417,.135),l(.284,-.018),l(1.001,-.002),l(1.277,.032),l(.615,.05),l(-1.277,.626),l(-1.583,.457),l(-1.976,.523),l(-.556,-.016),l(-.695,-.116),l(-.951,.671),l(-1.061,.503),l(-1.246,.452),l(-1.125,.296),l(-.211,.056),l(-2.212,.054),l(-.525,.134),l(-.502,.001),l(-.982,.201),l(-.665,.167),l(-.528,.051),l(-.946,-.413),l(-.375,.05),l(-.69,.913),l(-.958,.118),l(-.631,-.065),l(-.743,-.197),l(-.622,-.463),l(-.854,-.43),l(-.647,-.215),l(-.109,0),l(.008,.2),l(.707,1.043),l(-.192,.249),l(-.319,.017),l(-.69,.249),l(-.84,.249),l(-.573,.38),l(-1,.906),l(-.657,.657),l(-1.051,.851),l(-.776,.262),l(-1.034,.083),l(-1.023,-.275),l(-.148,.554),l(-.438,.569),l(-.783,.277),l(-.992,-.095),l(-.616,.05),l(-1.18,.439),l(.942,-1.723),l(-.121,.017),l(-.795,-.015),l(-1.055,-.177),l(.26,.423),l(-.026,.455),l(-.386,.407),l(-.794,.39),l(-1.16,.164),l(-.973,.002),l(-1.255,.083),l(.467,.403),l(.212,.403),l(-.09,.387),l(-.379,.097),l(-.321,-.063),l(-.47,.033),l(-1.792,-.157),l(.517,.32),l(.765,.462),l(.295,.351),l(-.01,.224),l(-.26,.176),l(-1.197,.034),l(-1.051,.129),l(.844,.413),l(.47,.126),l(.448,.222),l(.389,.333),l(-.554,.461),l(-.285,.111),l(-.599,-.094),l(-.478,.096),l(.345,.474),l(-.009,.127),L(308.501,60),l(-.486,-.125),l(-.583,-.062),l(.026,.158),l(.255,.457),l(-.101,.347),l(-.288,0),l(-.656,-.093),l(-.089,-.016),l(-.979,.112),l(-1.081,.018),l(.682,.487),l(1.108,.391),l(.331,.204),l(-.077,1.035),l(-.382,.938),l(-.427,.094),l(-.815,-.061),l(.489,.591),l(-.016,.498),l(.156,.233),l(-.068,.373),l(-.316,.062),l(-.495,-.03),l(-.771,.079),l(.762,.386),l(.427,.603),l(-.117,.447),l(-.287,.031),l(-.967,-.26),l(-1.052,-.508),l(-.498,.294),l(-.425,.602),l(-.635,-.599),l(.158,-.573),l(-.387,-.201),l(-1.124,-.184),l(-.577,-.309),l(.04,-.187),l(.253,-.249),l(.066,-.218),l(-.325,-.28),l(-.366,-.186),l(-.668,.359),l(-.276,.016),l(-.3,.141),l(-.444,-.046),l(-.98,.064),l(-.417,.017),l(-.571,.296),l(-.476,.28),l(-.426,-.403),l(-.104,-.357),l(-.222,-.217),l(-.513,-.233),l(-.817,-.232),l(-.772,-.389),l(-.517,-.781),l(.07,-.737),l(-.199,-.156),l(-.434,-.094),l(-.467,.048),l(-.97,-.266),l(-.108,-.094),l(-.138,-.236),l(.14,-.457),l(.459,-.395),l(.071,-.269),l(-.258,-.062),l(-.551,-.031),l(-.542,-.094),l(-.278,-.221),l(-.058,-.633),l(-.458,-.126),l(-.616,.049),l(-.589,-.57),l(.023,-.191),l(.198,-.254),l(.618,-.367),l(1.22,-.337),l(.405,-.304),l(.476,-.128),l(.051,-.383),l(-.277,-.287),l(-.473,.097),l(-.921,.082),l(-.493,.097),l(-.635,.416),l(-.538,.129),l(-.63,.304),l(-.339,-.318),l(.038,-.623),l(-.114,-.784),l(-.206,-.451),l(.015,-.355),l(-.243,-.323),l(-.504,.082),l(-.271,-.032),l(-.666,-.355),l(-.594,-.485),l(-.013,-.357),l(.842,-.538),l(.265,.019),l(-.556,-.189),l(-1.083,.064),l(-.103,-.284),l(.383,-.176),l(.677,-.03),l(.586,-.052),l(.456,-.087),l(.322,-.672),l(-1.208,-.047),l(-.572,.05),l(-.362,-.032),l(-.29,-.163),l(-.116,-.197),l(.223,-.28),l(.218,-.008),l(.18,-.16),l(.427,-.055),l(-.375,-.188),l(-.552,.073),l(-.22,-.248),l(.057,-.188),l(.073,-.132),l(.259,0),l(.309,-.099),l(.827,-.25),l(1.218,.081),l(.854,.163),l(.776,.032),l(.378,.131),l(.927,.146),l(1.027,.097),l(-.031,-.363),l(.299,-.545),l(-.298,-.182),l(-1.02,-.263),l(-1.356,-.312),l(-.903,-.164),l(-1.592,-.33),l(-.354,-.116),l(.336,-.35),l(.788,-.001),l(1.462,.363),l(1.034,.048),l(.463,-.067),l(.114,-.067),l(.088,-.6),l(.088,-.301),l(.595,-.034),l(.528,.116),l(.227,-.101),l(-.027,-.351),l(-.195,-.184),l(-.891,-.317),l(.162,-.437),l(.528,-.455),l(-.258,-.286),l(-1.21,-.167),l(-1.154,.002),l(-1.178,-.286),l(-1.649,-.49),l(-.78,-.101),l(-.903,-.05),l(-.76,-.34),l(-.811,-.477),l(.156,-.035),l(.323,-.155),l(.605,-.001),l(.572,-.019),l(2.085,.305),l(.716,.033),l(1.249,.306),l(1.451,.458),l(.729,.169),l(.056,-.307),l(-.311,-.426),l(-.86,-.546),l(-.172,-.446),l(-.603,-.446),l(-.485,-.051),l(-.677,-.24),l(.361,-.277),l(.542,-.139),L(285.644,41),l(-.704,-.241),l(-1.101,-.015),l(-.625,-.086),l(-1.132,-.327),l(-.88,.608),l(-.324,.156),l(-.274,.294),l(-.875,.243),l(-1.402,-.066),l(-1.031,-.343),l(-.306,-.242),l(-.027,-.294),l(.438,-.313),l(.293,-.645),l(-.152,-1.259),l(.582,-.054),l(.691,.192),l(.372,-.124),l(.151,-.334),l(-.383,-.369),l(-.933,-.545),l(-.452,-.141),l(-.946,-.796),l(-.895,-.925),l(-1.105,-1.289),l(-.578,-.485),l(-1.855,-.379),l(-.667,-.255),l(-.291,-.202),l(-.052,-.701),l(-.904,-.406),l(-.962,-.109),l(-1.589,-.165),l(-1.928,-.425),l(-1.903,-.333),l(-2.133,-.183),l(-.997,-.054),l(-1.632,-.035),l(-.785,.189),l(-1.043,.096),l(-.806,.188),l(-1.419,.152),l(-1.228,-.166),l(-1.46,-.296),l(.319,.747),l(-.051,.093),l(-1.051,-.017),l(-1.294,-.184),l(-3.168,-.611),l(1.538,-.566),l(.463,-.114),l(-.092,-.226),l(-.423,-.169),l(-1.067,-.017),l(-2.21,-.015),l(-.812,-.074),l(-.629,-.018),l(-1.238,-.434),l(-.87,-.208),l(.587,-.306),l(1.257,-.041),l(3.036,.147),l(2.025,.034),l(1.343,.017),l(2.117,-.157),l(1.055,-.212),l(.292,-.096),l(.054,-.345),l(-.627,-.287),l(-.82,-.21),l(-1.217,.156),l(-1.11,.252),l(-1.31,.021),l(-1.138,-.113),l(-.753,.078),l(-.879,.098),l(-.68,-.056),l(-.857,-.19),l(-.664,-.365),l(-.816,-.191),l(-.662,-.057),l(-.726,.059),l(-.486,-.076),l(-1.416,-.481),l(-.044,-.35),l(.36,-.45),l(.81,-.119),l(1.235,-.1),l(1.517,-.14),l(2.074,-.161),l(1.29,-.081),l(.951,-.396),l(1.089,-.259),l(.843,-.081),l(2.478,-.005),l(1.101,-.101),l(1.942,.036),l(.402,-.139),l(.31,-.199),l(.609,-.16),l(.202,-.658),l(.276,-.501),l(.116,-.101),l(-.89,-.228),l(-1.947,-.039),l(-1.155,.194),l(-.959,-.125),l(-1.243,-.383),l(.595,-.781),l(1.38,-.332),l(2.845,-.359),l(1.407,-.225),l(1.962,-.249),l(2.112,-.162),l(1.163,.087),l(1.213,-.07),l(1.319,-.07),l(.345,-.181),l(.011,-.226),l(-.357,-.753),l(-.022,-.208),l(.522,-.14),l(1.886,-.05),l(1.526,.205),l(2.141,.41),l(1.296,.226),l(.802,.181),l(.823,-.275),l(-1.657,-.525),l(-.697,-.509),l(.167,-.047),l(2.2,-.122),l(1.166,-.12),l(1.854,-.216),l(2.52,-.195),l(.73,.069),l(1.064,.116),l(.232,1.738),l(.913,-.162),l(.539,-.322),l(.432,-1),l(1.003,.021),l(2.004,.323),l(1.858,.414),l(1.529,.25),l(.205,-.3),l(-.644,-.3),l(-.816,-.537),l(-.894,-.4),l(.295,-.287),l(.742,.022),l(1.758,.02),l(1.136,.212),l(2.754,.373),l(1.284,.279),l(2.109,.322),l(1.878,.274),l(1.872,.204),l(.8,-.209),l(.816,-1.483),l(-.326,-.191),l(-1.292,-.334),l(-1.176,-.533),l(.708,-.247),l(2.404,-.005),l(2.962,-.328),l(1.329,-.077),l(1.527,.17),l(2.221,.488),l(1.567,.167),l(2.005,.142),l(.3,-.761),l(-.3,-.472),l(2.646,-.206),l(2.021,-.08),l(2.589,.095),l(1.989,.146),l(1.886,-.18),l(2.367,-.207),l(2.043,-.005),l(1.859,.223),l(1.825,-.055),l(1.315,.072),l(.619,.099),l(.55,-.102),l(1.946,.146),l(1.707,.046),l(1.673,.096),l(2.438,.761),l(1.368,.241),l(1.345,-.076),l(1.118,.168),l(2.594,.237),l(.445,.408),l(-.304,.12),l(-.492,.192),l(-1.683,.146),l(-2.303,.124),l(-1.152,.121),l(-1.233,.05),l(-1.469,-.068),l(-2.831,-.064),l(-2.22,-.066),l(-1.389,.168),l(-1.614,.027),l(-1.933,.027),l(-1.16,.026),l(-1.485,.168),l(-.444,.118),l(-1.322,.213),l(-.335,.464),l(.743,.251),l(2.551,-.281),l(1.367,-.072),l(3.912,.038),l(2.223,-.12),l(2.331,-.005),l(.997,-.025),l(.93,.067),l(1.77,.434),l(.671,.09),l(1.087,-.186),l(1.663,-.21),l(1.536,-.281),l(1.964,-.144),l(.59,.462),l(-.566,.482),l(-2.316,.639),l(-.973,.338),l(-1.281,.734),l(.12,.307),l(.319,.152),l(.796,-.089),l(.477,-.044),l(1.616,-.553),l(1.766,-.537),l(1.413,-.385),l(1.706,-.32),l(.775,-.207),l(1.662,-.163),l(1.618,.111),l(1.391,.065),l(1.497,-.3),l(.703,-.324),l(1.129,-.234),l(2.148,-.004),l(1.672,.112),l(1.097,.044),l(1.197,.136),l(1.135,.228),l(1.107,.112),l(.316,.25),l(-.181,.273),l(-1.97,.252),l(-1.491,.138),l(-1.245,.494),l(-.557,.289),l(-1.604,.355),l(-1.57,.548),l(-1.063,.089),l(-.918,-.042),l(-1.592,.047),l(-2.213,-.039),l(-1.491,.198),l(-.731,.217),l(-.495,.535),l(.166,.322),l(1.949,-.305),l(1.581,-.046),l(1.856,.101),l(.003,.42),l(-.743,.241),l(-2.388,.124),l(-.463,.14),l(-.213,.199),l(-.156,.595),l(-.471,.71),l(-.678,.158),l(-1.06,-.077),l(-.742,.041),l(-.837,.9),l(-.987,1.087),l(-.15,.347),l(.454,.307),l(.403,.095),l(.602,-.481),l(.743,-.368),l(.856,-.041),l(2.345,.266),l(.353,.096),l(.262,.288),l(-.059,.211),l(-1.234,-.074),l(-.673,-.018),l(-.512,.097),l(-.136,.191),l(.29,.286),l(1.756,.188),l(.557,.132),l(1.802,-.137),l(.526,.208),l(.214,.323),l(-.049,.436),l(-.256,.133),l(-1.835,-.186),l(-1.653,-.054),l(-.781,-.074),l(-1.295,.078),l(-1.382,.475),l(-.823,-.13),l(-.49,-.15),l(-1.06,.04),l(-.283,.377),l(1.393,.599),l(1.187,.222),l(1.298,.128),l(1.665,.072),l(.696,.148),l(.551,.482),l(.272,.444),l(.014,.554),l(-.434,.405),l(-.384,.074),l(-1.292,-.181),l(-.82,-.109),l(-.372,.111),l(.023,.55),l(.118,.236),l(.426,.162),l(.618,.089),l(.723,.215),l(.914,.142),l(.752,.16),l(.383,.376),l(-.338,.233),l(-.832,.145),l(-.647,.126),l(-1.747,-.032),l(-1.176,-.087),l(-1.624,-.086),l(-.592,.448),l(.551,.195),l(1.396,.051),l(1.052,.158),l(.724,.248),l(.088,.319),l(-.035,.549),l(-.13,-.005),l(-1.092,-.045),l(-1.247,.108),l(-.596,.266),l(-1.246,.02),l(-1.225,-.139),l(-1.497,-.404),l(-.922,-.478),l(-.373,-.07),l(-1.094,.286),L(345,36.811),l(-1.084,.09),l(-.589,.178),l(-1.451,-.033),l(-.913,-.087),l(-.969,.143),l(-.395,.125),l(-.174,.283),l(.006,.141),l(.354,.527),l(.71,.245),l(1.284,.05),l(1.515,.26),l(1.567,-.056),l(1.323,.54),l(.758,.226),l(.482,.226),l(1.196,.329),l(1.252,.38),l(.376,.276),l(.483,.898),l(.892,-.208),l(.278,-.139),l(.397,.207),l(.298,.43),l(.071,.344),l(.198,1.164),l(-.169,.205),l(-.371,.12),l(-.541,-.101),l(-.546,-.119),l(-.917,.002),l(-1.041,.036),l(-1.488,-.27),l(-.637,-.409),l(-.415,-.634),l(-.354,-.274),l(-1.17,-.566),l(-.84,-.292),l(-.748,-.137),l(-1.095,-.084),l(-.521,.14),l(-.962,.105),M(351.365,40.026),l(-1.527,-.537),l(-.96,-.225),l(-.712,-.156),l(-.159,-.069),l(-.314,-.419),l(1.483,-.038),l(.893,.139),l(1.064,.26),l(.819,.296),l(.162,.488),l(-.215,.209),l(-.533,.053),M(281.574,46.135),l(-.568,-.133),l(-.707,-.318),l(-.801,-.183),l(-.197,-.101),l(-.25,-.218),l(-.08,-.844),l(.287,-.34),l(.368,-.018),l(.646,.135),l(1.157,.066),l(1.287,.27),l(.748,.269),l(.595,.1),l(.777,.217),l(.603,.335),l(-.144,.202),l(-.112,.034),l(-.543,.051),l(-.774,.035),l(-.77,.186),l(-1.009,.153),l(-.511,.102), +N(105.98,81.688),l(-.952,-.826),l(-.198,-.342),l(-.024,-.476),l(.095,-.104),l(.408,.044),l(.312,-.045),l(.781,.177),l(.658,-.076),l(.28,.119),l(.138,.163),l(-.234,.224),l(-.173,.565),l(-.028,.312),l(-.581,.075),l(-.483,.19),M(125.24,92.375),l(-1.312,-.288),l(-1.345,-.434),l(-.218,-.174),l(.061,-.189),l(.376,-.466),l(-1.023,.002),l(-.413,.248),l(-.299,-.072),l(-.416,-.188),l(.166,-.452),l(-.487,-.334),l(-.269,-.014),l(-.735,-.086),l(-.226,-.262),l(.317,-.292),l(-.976,-.524),l(-.556,.118),l(-.386,-.102),l(-.852,-.511),l(-1.277,-.863),l(-.219,-.235),l(.02,-.117),l(.962,-.12),l(.337,.043),l(1.979,.598),l(.981,.204),l(1.772,.202),l(.385,.263),l(.618,.526),l(.426,.642),l(.433,.422),l(.362,.189),l(1.587,.536),l(.316,.203),l(.48,.756),l(.116,.407),l(-.279,.349),l(-.407,.016),M(271.379,92.089),l(-1.202,-.23),l(.641,-.743),l(.358,-.161),l(.279,.058),l(.292,0),l(.355,-.263),l(-.697,-.653),l(.079,-.219),L(272,89.003),l(1.121,-1.35),l(1.454,-1.31),l(.725,-.442),l(.496,-.192),l(1.315,-.194),l(.198,.073),l(.11,.221),l(-.299,.221),l(-.582,.03),l(-.242,.133),l(.349,.44),l(-.755,.78),l(-1.226,1.438),l(-.271,.526),l(.113,.291),l(.11,0),l(.428,-.176),l(.483,-.555),l(.458,-.191),l(1.115,.305),l(-.896,.687),l(.261,.203),l(.229,.072),l(1.423,.565),l(.758,-.03),l(.325,-.408),l(.309,-.059),l(.718,.057),l(.826,.202),l(.616,.231),l(-.297,.292),l(-.373,.233),l(-.708,.467),l(.339,.333),l(.477,.362),l(.26,.014),l(.417,-.161),l(.464,-.132),l(.278,.116),l(.02,.16),l(-.254,.262),l(-.404,.248),l(-.892,.104),L(280.84,93),l(.273,.362),l(.124,.405),l(.28,.231),l(.183,-.203),l(.309,-.262),l(.527,.159),l(-.099,.449),l(.149,.275),l(.716,.028),l(.085,-.015),l(.015,.203),l(-.168,.304),l(-.25,.652),l(-.34,.651),l(-.222,-.072),l(-.71,-.128),l(-.301,-.144),l(-.042,-.651),l(-.601,.406),l(-.374,.015),l(-.095,-.274),l(.497,-.652),l(.011,-.333),l(-.421,-.478),l(-.279,-.072),l(-.388,.392),l(-.423,.291),l(-.365,.146),l(-.435,.204),l(-.552,.536),l(-.496,.334),l(-.881,-.042),l(-.222,-.217),l(.165,-.145),l(1.229,-.408),l(.466,-.522),l(.632,-.363),l(-.699,-.129),l(-.601,-.057),l(-.322,.464),l(-.412,.015),l(-.13,-.159),l(.04,-.493),l(-.757,.016),l(-.148,.29),l(-.41,.218),l(-1.052,.045),l(-.709,-.057),l(-1.139,-.186),l(-1.012,-.085),l(-1.355,.061),l(-1.014,.147),l(-.145,-.188),l(-.215,-.463),l(.187,-.175),l(.561,-.334),l(.734,-.408),l(.502,-.161),l(.636,-.335),M(265.435,98.655),l(-.469,-.057),l(-.497,-.273),l(-.356,-.562),l(.062,-.635),l(.742,-.738),l(.932,-1.043),l(.816,.432),l(-.375,.435),l(-.112,.462),l(-.233,.333),l(-.262,.116),l(-.58,.319),l(-.244,.448),l(.522,.244),l(.168,-.029),l(.279,-.26),l(.42,-.362),l(.617,-.319),l(.309,.057),l(.495,.461),l(-.177,.347),l(-.246,.159),l(-1.134,.42),l(-.682,.044),M(211.34,59.677),l(-.68,-.046),l(.068,-.872),l(-.375,-.333),l(-.958,.161),l(-2.375,.29),l(.107,-.461),l(.56,-.303),l(1.644,-.561),l(-.302,-.478),l(-.102,-.415),l(.106,-.417),l(.398,-.835),l(.434,-.566),l(.254,-.648),l(.331,-.471),l(1.11,.566),l(-.312,.518),l(.791,.386),l(.527,.047),l(.402,-.469),l(.67,.112),l(.806,.289),l(.917,.514),l(.582,.255),l(2.168,.492),l(.442,.271),l(.176,.255),l(-.09,.925),l(.539,.047),l(.57,-.065),l(.934,.046),l(.701,.142),l(1.019,.427),l(-.419,.096),l(-.269,.127),l(-.46,.271),l(-.949,-.046),l(-.623,-.125),l(-1.328,-.125),l(-.438,-.126),L(217.259,58),l(-.528,-.301),l(-1.017,-.237),l(-.528,.017),l(-.203,.271),l(.174,.588),l(-.126,.096),l(-1.314,.161),l(-.673,.493),l(-.588,.302),l(-1.116,.287),M(200.125,19.1),l(-.862,-.015),l(-1.085,-.195),l(-.308,-.664),l(.819,-.304),l(.77,-.072),l(.666,-.024),l(3.475,-.125),l(1.263,-.12),l(1.374,-.026),l(1.714,.324),l(.397,-.094),l(.397,-.377),l(1.303,-.287),l(1.759,-.099),l(1.975,.209),l(.746,-.001),l(2.562,.137),l(2.621,.324),l(1.424,.09),l(1.461,.161),l(.448,-.165),l(-1.433,-.42),l(-1.67,-.352),l(-.816,-.429),l(.293,-.242),l(1.361,-.148),l(1.101,-.246),l(1.431,-.101),l(2.382,-.201),l(1.666,.119),l(1.944,.191),l(1.009,.265),l(1.19,.456),l(.354,.047),l(.273,-.362),l(-.959,-.508),l(-.828,-.292),l(.499,-.248),l(1.45,.121),l(1.832,.168),l(1.653,.07),l(1.639,.46),l(.378,.023),l(.062,-.195),l(-.301,-.539),l(1.781,-.004),l(1.408,.046),l(.832,.269),l(.831,.34),l(.618,-.001),l(-.044,-.268),l(-.331,-.467),l(1.075,-.077),l(3.691,.386),l(2.726,.288),l(1.937,-.077),l(2.987,.018),l(.967,.047),l(.757,.12),l(.126,0),l(1.419,.094),l(1.089,.191),l(.744,.095),l(1.685,.044),l(1.357,.357),l(-.385,.358),l(-1.237,.121),l(-1.206,.356),l(-1.849,.191),l(-.978,-.045),l(-2.191,-.159),l(-2.284,.005),l(-.776,.142),l(-1.915,.168),l(-.597,.465),l(.75,.366),l(.761,.044),l(1.03,-.048),l(1.705,-.279),l(.79,.021),l(.808,.434),l(-.168,.114),l(-1.246,.139),l(-1.38,.207),l(-1.174,.295),l(-2.098,.518),l(-1.316,.224),l(-1.19,.355),l(-.924,.286),l(-2.252,.005),l(.65,.906),l(-.449,.193),l(-2.297,.455),l(-.768,-.019),l(-1.587,-.037),l(-1.462,-.218),l(-2.386,-.164),l(-.66,.33),l(2.591,.695),l(-.662,.141),l(-.967,-.038),l(-1.297,.022),l(-1.068,.022),l(-2.58,-.214),l(-2.009,.063),l(-.134,.66),l(1.257,-.105),l(1.065,.018),l(2.312,.292),l(.557,.157),l(.12,.67),l(-.33,.197),l(-1.031,.12),l(-.515,.705),l(-1.073,.021),l(-.448,-.058),l(-.402,.176),l(.297,.253),l(.759,.25),l(-.328,.136),l(-1.615,.08),l(-.867,-.037),l(-1.71,-.171),l(-.422,.078),l(.41,.791),l(-.08,.231),l(-.649,.289),l(-.767,.155),l(-1.52,-.112),l(-2.039,-.111),l(-1.43,-.227),l(-1.008,.079),l(-1.219,.5),l(1.031,.112),l(.368,.057),l(2.154,.11),l(1.759,.13),l(1.534,.168),l(2.001,.034),l(.66,.34),l(.045,.359),l(-.907,.398),l(-2.685,.268),l(-.927,.115),l(-1.054,.227),l(-1.115,.077),l(-.467,-.28),l(-.797,-.638),l(-.56,.039),l(-.631,.001),l(-1.453,-.318),l(-.001,.17),l(.331,.508),l(-1.477,-.016),l(-1.5,-.129),l(-.875,-.319),l(-1.033,-.471),l(-.388,.058),l(.527,.717),l(-.24,.17),l(-.821,.133),l(-1.72,-.109),l(-2.276,-.033),l(-.972,-.073),l(-1.382,-.394),l(-.642,-.131),l(-.282,.453),l(-.619,.152),l(-1.843,-.316),l(.161,-.586),l(.219,-.228),l(1.525,-.117),l(.61,-.249),l(.961,-.173),l(1.179,.036),l(.499,-.172),l(-1.073,-.4),l(-1.043,-.651),l(.052,-.154),l(.479,-.117),l(1.316,.036),l(1.743,.093),l(.888,.21),l(1.108,.517),l(1.35,.323),l(1.085,.093),l(1.667,-.022),l(.829,-.136),l(.086,-.268),l(.514,-.304),l(-3.019,.001),l(-1.025,-.171),l(-.156,-.85),l(.211,-.154),l(-1.74,-.153),l(-1.963,-.152),l(-.274,0),l(-.631,.114),l(.204,-.758),l(1.159,-.551),l(1.104,-.16),l(1.837,-.003),l(1.164,.037),l(1.37,.076),l(2.023,.311),l(1.342,.115),l(.486,-.158),l(1.132,-.041),l(-3.399,-.802),l(-1.742,-.313),l(-3.555,-1.27),l(-.406,.242),l(-1.398,-.878),l(.025,-.258),l(.313,-.108),l(1.747,.104),l(1.905,-.004),l(2.019,.06),l(1.6,.382),l(2.535,.784),l(1.448,-.043),l(.833,.095),l(-1.387,-.555),l(-2.015,-.317),l(1.208,-.743),l(1.456,-.329),l(1.731,-.025),l(1.529,-.222),l(2.042,-.07),l(1.157,-.112),l(1.414,-.051),l(-1.778,-.479),l(-1.425,-.153),l(-2.501,.027),l(-1.243,.248),l(-1.305,.158),l(-1.425,.202),l(-1.447,.047),l(-.586,.067),l(-1.532,-.438),l(-.214,.111),l(-.543,.156),l(-2.16,-.018),l(-1.58,.365),l(.311,-.828),l(.98,-.292),l(.007,-.202),l(-.606,-.247),l(-1.375,-.156),l(-1.39,.003),l(-4.189,.505),l(-2.031,.672),l(-.408,-.11),l(-.569,-.251),l(.395,-.133),l(.678,-.023),l(-.117,-.316),l(-.698,-.398),l(-1.216,-.056),l(-.216,-.003),M(200.125,20.844),l(.899,-.096),l(.832,.196),l(.339,.5),l(.511,.495),l(.427,.063),l(1.141,.041),l(-.081,-.236),l(.056,-.411),l(.438,-.109),l(.718,.194),l(.718,.322),l(.374,.3),l(-.066,.171),l(.056,.826),l(.764,.442),l(.953,-.017),l(1.276,-.074),l(1.646,.504),l(-1.123,-.264),l(-1.528,.34),l(-1.599,.221),l(-.83,.377),l(-.287,.197),l(-.265,.315),l(-.448,.021),l(-1.493,-.41),l(-.656,.335),l(.465,.43),l(-.029,.235),l(-.412,.196),l(-.392,.04),l(-1.086,-.31),l(-.944,-.311),l(-.26,.645),l(-.117,.068),l(-.083,.049),l(-.888,.041),l(-1.74,-.094),l(-1.458,-.153),l(-.888,-.154),l(-.494,.021),l(-3.115,-1.31),l(-.191,-.276),l(1.971,-.241),l(3.32,.093),l(.889,.097),l(1.573,.1),l(-2.485,-.693),l(-3.019,-.213),l(-1.103,.122),l(-1.43,-.017),l(-.597,.18),l(-1.008,.022),l(-.606,-.198),l(-1.066,-.517),l(-1.425,-.479),l(-.341,-.355),l(1.971,.124),l(2.278,-.175),l(-1.255,-.249),l(-.756,-.351),l(.38,-.305),l(.729,-.132),l(.769,-.023),l(.921,.042),l(.156,-.219),l(-1.799,-.793),l(1.053,-.114),l(1.213,-.182),l(1.13,.087),l(.584,-.046),l(.145,-.18),l(-.514,-.475),l(1.362,.134),l(.941,.066),l(.83,.202),l(1.589,.869),l(.653,.264),l(.772,.24),l(.674,-.001),l(.36,-.039),M(179.067,27.216),l(-1.156,-.056),l(-.604,-.173),l(-.926,-.638),l(-.621,-.193),l(-3.102,-.091),l(-1.487,.081),l(-.622,.001),l(-1.444,-.056),l(-.767,-.154),l(-1.019,-.37),l(-.161,-.234),l(.335,-.138),l(.802,-.001),l(1.687,.232),l(.867,-.021),l(-.031,-.235),l(-.252,-.275),l(-1.344,-.49),l(-.579,-.098),l(-1.075,-.077),l(-1.392,-.196),l(.065,-.397),l(2.246,-.124),l(2.392,.155),l(.77,.376),l(.999,.453),l(1.979,.193),l(2.189,.114),l(1.178,.233),l(.604,.254),l(1.123,.721),l(.581,.446),l(.168,.426),l(-.481,.194),l(-.919,.137),M(185.907,26.758),l(-1.078,-.037),L(184,26.529),l(-1.029,-.484),l(-1.144,-.76),l(-.03,-.216),l(.239,-.099),l(2.296,-.044),l(1.816,.311),l(3.101,.542),l(-.047,.351),l(-.254,.331),l(-.436,.04),l(-1.563,.177),l(-1.043,.08),M(156.886,26.865),l(-1.573,.646),l(-.558,.27),l(-1.85,.042),l(-1.019,.079),l(-1.898,-.15),l(-.577,-.114),l(-.302,-.423),l(.334,-.291),l(1.365,-.177),l(.899,.056),l(2.351,-.102),l(.496,0),l(2.331,.163),M(132.902,31.305),l(-.53,-.186),l(-.95,-.466),l(-.424,-.112),l(-.33,.057),l(-.56,.207),l(-1.269,.059),l(-.786,-.279),l(-.283,-.319),l(.23,-.264),l(1.13,-.097),l(.503,-.133),l(.771,-.134),l(.977,-.399),l(.848,-.211),l(.726,-.172),l(.548,-.344),l(1.083,-.231),l(1.277,-.079),l(2.532,-.158),l(1.68,.016),l(.888,-.29),l(1.038,-.079),l(1.503,.438),l(-.756,.097),l(-.852,.231),l(-.22,.268),l(.12,.266),l(.469,.474),l(-.777,.001),l(-.912,.115),l(-.918,.662),l(-1,-.017),l(-.867,-.981),l(-.694,-.15),l(-.379,.02),l(-.229,.285),l(-.588,.342),l(-.63,.623),l(-.595,.151),l(-.284,.375),l(-.705,.356),l(-.787,.058),M(191.827,30.313),l(-1.266,-.054),l(-2.278,-.165),l(-.426,.058),l(-.332,-.094),l(-.896,-.489),l(-1.185,-.414),l(.192,-.229),l(2.433,-.042),l(1.542,.263),l(1.472,.054),l(.171,0),l(.89,.358),l(-.179,.246),l(.123,.32),l(-.263,.188),M(144.688,31.739),l(-2.222,-.395),l(-.325,-.674),l(.503,-.057),l(.595,-.17),l(.945,-.096),l(.953,-.133),l(1.279,-.059),l(.522,.187),l(.65,.374),l(.659,.186),l(1.55,-.209),l(.617,.149),l(1.624,.762),l(1.016,.351),l(.897,.036),l(.96,-.058),l(1.418,.09),l(.591,-.02),l(1.116,-.169),l(.092,-.297),l(-.557,-.559),l(-.941,-.391),l(-1.347,-.354),l(.96,-.322),l(.524,-.379),l(.569,-.152),l(1.097,-.116),l(.507,.17),l(.773,.678),l(-.017,.413),l(.518,.654),l(.565,.111),l(.9,.036),l(1.805,.406),l(-.334,-.465),l(.151,-.28),l(.409,-.076),l(1.495,.24),l(.932,.39),l(-.292,.409),l(.039,.5),l(-.358,.461),l(-.573,.277),l(-.755,.111),l(-.782,.001),l(-1.682,.095),l(-1.156,-.071),l(-1.757,-.18),l(-.622,-.017),l(-1.129,.277),l(-1.132,.202),l(-.76,.182),l(-.977,.254),l(-1.625,.292),l(-1.338,.2),L(149.23,34.5),l(-.748,-.07),l(-1.445,-.286),l(-.276,-.378),l(.648,-.128),l(1.219,-.038),l(.738,-.146),l(.852,-.075),l(1.166,-.057),l(.622,.017),l(1.09,-.149),l(.483,-.553),l(-2.768,-.087),l(-.925,-.054),l(-1.564,.28),l(-1.625,.168),l(-1.292,.04),l(-.795,.093),l(-1.681,-.347),l(-.479,.167),l(-.92,.075),l(-.979,-.127),l(-.854,-.33),l(.023,-.111),l(.863,-.427),l(1.098,-.058),l(2.047,-.022),l(.96,-.159),M(178.479,33.234),l(-.984,-.219),l(-.193,-.294),l(.764,-.389),l(.433,-.112),l(.088,-.167),l(-.447,-.333),l(-1.161,-.054),l(-2.13,.227),l(-.939,.076),l(-.331,.019),l(-.854,-.276),l(.039,-.335),l(.739,-.02),l(.542,-.244),l(.587,-.057),l(-.466,-.598),l(.176,-.245),l(.132,-.226),l(.49,.018),l(.859,.224),l(1.942,.746),l(.426,.186),l(.46,-.094),l(-.101,-.243),l(-.959,-.486),l(-.371,-.131),l(-.407,-.357),l(.436,-.095),l(.956,-.059),l(.713,.131),l(1.033,.262),l(.572,.168),l(.27,.018),l(.162,-.452),l(.478,-.133),l(.73,.112),l(.717,.168),l(.327,.168),l(.367,.75),l(-.034,.616),l(-.247,.242),l(-.831,.335),l(-.017,.352),l(.35,.625),l(-.361,.147),l(-1.648,-.089),l(-.862,.112),l(-1.446,.003),M(200.125,30.572),l(-.895,.045),l(-.853,.17),l(-.37,.467),l(1.133,.054),l(.984,-.038),l(.046,-.001),l(.847,.11),l(.463,.129),l(.498,.463),l(.727,.424),l(.621,.091),l(.213,-.074),l(.043,-.314),l(.286,-.056),l(1.075,-.002),l(.883,-.187),l(.766,.11),l(.835,.239),l(.665,.257),l(.976,.053),l(.775,-.463),l(1.393,-.281),l(1.704,-.114),l(1.951,-.246),l(1.533,.053),l(2.59,.014),l(.381,.037),l(.79,.314),l(.911,.239),l(1.418,.146),l(.653,.128),l(.21,.037),l(.361,.166),l(.181,.257),l(-.4,.148),l(-1.833,.407),l(-.135,.255),l(.469,.666),l(-2.486,.076),l(-.592,.02),l(-.651,.091),l(-.768,-.053),l(-.846,-.16),l(-.405,-.125),l(-.306,-.667),l(-.833,-.218),l(-.366,.129),l(.072,.723),l(-.536,.127),l(-.747,-.053),l(-.91,.109),l(-.728,-.017),l(-.495,.001),l(-1.342,-.213),l(-.593,-.197),l(-.495,-.017),l(-.209,.433),l(-1.801,.111),l(-.831,.074),l(-1.453,-.069),l(-.404,-.251),l(-.144,-.686),l(-1.237,.129),l(-.389,.181),l(-.326,.325),l(-.955,.2),l(-1.011,-.034),l(-.112,-.027),l(-.704,-.169),l(-1.186,-.575),l(-.675,.489),l(-1.131,-.07),l(-.666,-.688),l(-.442,-.717),l(.587,-.481),l(.019,-.371),l(-.292,-.316),l(-1.249,-.651),l(-.617,-.299),l(-.047,-.338),l(.636,-.133),l(1.226,-.078),l(2.472,-.023),l(.763,.093),l(1.118,.261),l(.188,.04),l(.872,.184),l(-.613,.189),l(-.259,.013),M(128.19,41.985),l(-.926,-.016),l(-1.059,-.102),l(-.362,-.466),l(-.549,-.467),l(-.432,-.259),l(-1.123,-.363),l(-1.36,-.067),l(-.951,-.138),l(-.469,-.19),l(-.168,-.174),l(.537,-.106),l(.589,-.298),l(.481,-.211),l(.08,-.386),l(-.437,-.809),l(.552,-.001),l(.468,-.177),l(.307,-.372),l(1.104,-.533),l(.526,-.588),l(-.121,-.32),l(-.271,-.16),l(-1.229,-.677),l(-.375,-.448),l(.869,-.001),l(.823,-.056),l(1.455,.051),l(.97,.016),l(1.515,-.092),l(1.284,-.146),l(1.242,-.074),l(.495,.125),l(3.242,.801),l(.918,.088),l(.708,-.055),l(1.316,-.127),l(1.223,.016),l(.771,.07),l(1.35,.373),l(2.389,.815),l(-.242,.143),l(-.432,.036),l(-.26,.072),l(-1.609,.322),l(-1.073,.144),l(-1.829,.428),l(-1.069,.319),l(-1.604,.725),l(-1.025,.563),l(-.549,.089),l(-.974,.124),l(.066,.924),l(-.271,.504),l(-.662,.278),l(-1.215,.124),l(-1.213,-.067),l(-.521,.485),l(-.898,.312),M(190.483,39.666),l(-1.146,-.208),l(-.146,-.524),l(-.941,-.806),l(-.207,-.582),l(.058,-.389),l(.27,-.657),l(.377,-.321),l(1.256,.033),l(-.089,-.16),l(-.416,-.266),l(-.185,-.286),l(.211,-.09),l(.234,-.072),l(2.154,-.058),l(1.215,.087),l(1.464,.248),l(1.282,.051),l(1.316,-.146),l(1.051,.016),l(.694,.105),l(.639,.213),l(-.007,.089),l(-.224,.179),l(-.824,.428),l(-.874,.746),l(-1.513,.92),l(-1.386,.073),l(-2.379,-.154),l(-1.269,.055),l(1.392,.717),l(-.188,.315),l(-.855,.369),l(-.964,.072),M(181.204,41.523),l(-.491,-.085),l(-1.101,-.552),l(-.952,-.641),l(-1.014,-.468),l(-.978,-.225),l(-1.438,-.12),l(-.55,-.174),l(-2.255,-1.066),l(.866,-.654),l(.653,.14),l(1.032,.474),l(1.063,.227),l(.46,.052),l(.615,-.283),l(.908,-.619),l(.415,-.036),l(.018,-.212),l(-1.062,-.565),l(-1.068,-.424),l(-.177,-.231),l(.132,-.107),l(1.683,.086),l(.711,-.215),l(.42,0),l(.996,.39),l(.56,.035),l(.58,-.055),l(.435,-.25),l(1.232,-.127),l(1.354,.069),l(.912,.23),l(-.324,.268),l(-.58,.125),l(-.323,.338),l(-1.55,.375),l(-.392,.16),l(-.069,.194),l(.253,.247),l(.506,.105),l(.692,-.089),l(1.08,.174),l(.868,.245),l(.391,.017),l(.564,.262),l(.186,.438),l(-.681,.352),l(-.156,.35),l(-.271,.68),l(-.457,.366),l(-.508,.14),l(-.658,.019),l(-.582,-.103),l(-.773,-.346),l(-.653,-.103),l(.013,.208),l(1.054,.553),l(-.817,.399),l(-.77,.036),M(243.524,60.394),l(-.234,-.208),l(-1.199,-.235),l(-.673,-.331),l(-.154,-.269),l(.346,-.064),l(.616,-.461),l(-1.378,-.521),l(-1.132,-.125),l(-.76,-.349),l(-.929,-.731),l(-.035,-.511),l(-1.115,-.062),l(-1.311,-.366),l(-.675,-.031),l(.284,.767),l(-.155,.096),l(-.409,-.015),l(-1.704,-.332),l(-.309,.033),l(-.325,.304),l(-.441,.288),l(-1.312,.082),l(-1.349,-.173),l(-1.343,-.189),l(-.813,-.254),l(-.052,-.319),l(.196,-.4),l(.382,-.354),l(1.066,-.163),l(.192,-.178),l(-.128,-.516),l(.206,-.033),l(1.357,.11),l(1.408,.175),l(.517,.144),l(.962,.626),l(.051,-.386),l(-.154,-.193),l(.077,-.194),l(.585,-.033),l(.977,-.099),l(.652,-.163),l(.649,-.114),l(.515,.063),l(.785,.031),l(.166,-.275),l(-1.138,-.825),l(-.773,-.356),l(-.119,-.228),l(.167,-.163),l(.586,-.066),l(.72,-.246),l(1.409,-.591),l(.361,-.541),l(.771,-.46),l(.493,-.379),l(-.109,-.593),l(-.899,-.841),l(-.407,-.496),l(-.541,-.364),l(-.414,.001),l(-1.258,-.33),l(-1.041,-.481),l(-.244,-.467),l(-.527,-.384),l(-.442,.202),l(-.551,.202),l(-.825,-.015),l(-.293,.117),l(-.62,.018),l(-1.255,.169),l(-.214,-.667),l(1.032,-.052),l(1.23,-.103),l(.163,-.269),l(-1.604,-.618),l(-1.552,-.67),l(-.879,-.015),l(-.567,-.185),l(-.169,-.542),l(-.677,-.339),l(-.45,-.05),l(-.918,-.306),l(-.687,-.341),l(-.385,-.119),l(-.611,.155),l(-.81,-.187),l(-1.177,-.238),l(-.489,-.085),l(-.379,.138),l(.529,.307),l(.453,.05),l(2.838,.712),l(.438,.271),l(.069,.306),l(-.505,.221),l(-.669,.069),l(-.541,-.033),l(-.757,-.049),l(-.818,-.252),l(-1.153,-.27),l(-.667,-.066),l(-.323,.17),l(.044,.204),l(.426,.236),l(.259,.438),l(-1.703,-.553),l(-.47,-.05),l(-.396,.119),l(-.63,.153),l(-.767,-.218),l(-.693,-.117),l(-.859,.12),l(-1.474,-.184),l(-1.995,-.167),l(-1.321,.037),l(-1.146,-.032),l(-.862,-.186),l(-.003,-.597),l(-.363,-.153),l(-.904,-.049),l(-.396,.342),l(-.623,.086),l(-1.214,-.049),l(-1.076,-.168),l(-1.303,-.477),l(-.415,-.376),l(.123,-.275),l(.868,-.07),l(1.131,.067),l(1.212,.101),l(.879,-.019),l(.312,-.19),l(-.934,-.463),l(-.8,-.275),l(-.905,-.102),l(-1.106,-.119),l(-.752,.036),l(-.539,-.017),l(-1.249,-.223),l(.114,-.416),l(.292,-.557),l(.34,-.14),l(.646,-.054),l(.081,-.227),l(-1.082,-.4),l(-.044,-.175),l(.449,-.79),l(1.197,-.919),l(.565,-.284),l(.918,-.321),l(.74,-.374),l(.423,-.037),l(.37,-.178),l(.698,-.001),l(.481,-.125),l(.71,-.09),l(1.436,-.109),l(1.348,.033),l(.857,.194),l(-.92,.393),l(-.815,.48),l(-1.394,.639),l(-.43,.529),l(.169,.369),l(1.256,.541),l(-.444,.298),l(-.076,.402),l(.257,.313),l(.862,.554),l(1.559,.621),l(-.096,.121),l(-1.272,.331),l(-.072,.31),l(.959,.033),l(1.504,.101),l(.654,-.639),l(-.103,-.415),l(-.343,-.277),l(-.724,-.103),l(-.422,-.138),l(-.884,-.538),l(.101,-.157),l(.506,-.245),l(.473,-.193),l(1.001,.12),l(.837,-.071),l(-1.204,-.47),l(-.703,-.034),l(-.793,-.279),l(-.056,-.193),l(.053,-.545),l(.886,-.319),l(1.207,.086),l(1.509,-.056),l(-.939,-.281),l(-1.233,-.351),l(.793,-.303),l(1.288,-.198),l(1.044,-.126),l(1.688,-.323),l(1.114,.016),l(.642,.052),l(.833,.141),l(.782,.478),l(1.536,.97),l(.058,.141),l(-.583,.687),l(-.709,.632),l(.038,.733),l(.364,.086),l(.65,.033),l(1.088,-.315),l(.284,-.455),l(.595,-.088),l(.791,.034),l(.454,.174),l(-.006,.262),l(.16,.47),l(.875,.189),l(.196,-.122),l(-.204,-.854),l(.218,-.123),l(.456,-.474),l(1.038,-.265),l(.98,-.054),l(.748,.034),l(.98,.174),l(1.172,.138),l(1.151,-.09),l(.688,.139),l(.327,.262),l(.621,.331),l(.574,.191),L(235.438,40),l(0,.191),l(-.531,.088),l(-.484,.279),l(-.818,.262),l(-.148,.225),l(.45,.259),l(.427,.068),l(.897,-.417),l(.652,-.174),l(.502,.051),l(.476,.242),l(.365,.466),l(.516,.413),l(.342,-.242),l(1.304,-.798),l(1.935,.256),l(.915,.361),l(-.051,.069),l(-.638,.346),l(-.708,.517),l(1.167,-.054),l(.455,-.173),l(1.078,-.105),l(.033,.704),l(.797,.324),l(.523,-.069),l(.831,-.207),l(1.316,-.088),l(.816,.221),l(.566,.273),l(-.162,.154),l(-.461,.223),l(-1.87,.43),l(-.238,.272),l(.523,.253),l(.456,-.068),l(.747,-.171),l(1.235,-.122),l(.406,-.29),l(.361,-.103),l(.479,.067),l(.51,.187),l(.544,.339),l(.636,.522),l(-1.019,.002),l(-1.2,.053),l(-.424,.135),l(.059,.269),l(.372,.134),l(1.333,.065),l(.938,.183),l(.543,.217),l(.233,.301),l(-.37,.034),l(-.748,.001),l(-1.011,-.082),l(-.875,-.216),l(-.824,-.065),l(-.316,.185),l(1.23,.583),l(-.216,.201),l(-1.552,.12),l(.245,.283),l(.437,.166),l(.551,.032),l(1.331,.364),l(1.312,.347),l(.247,.182),l(.039,.282),l(.351,.38),l(.75,-.217),l(.536,.049),l(1.413,.295),l(.298,-.067),l(.649,-.15),l(.61,.032),l(.752,.379),l(.862,.477),l(.376,.346),l(-.685,.1),l(-.801,.117),l(-.027,.444),l(.795,-.001),l(1.405,-.052),l(.51,-.132),l(.895,.048),l(-.386,.559),l(.918,.179),l(.514,-.001),l(.943,-.379),l(.685,.343),l(1.089,.407),l(.194,.098),l(-.275,.229),l(-.254,.099),l(-.103,.326),l(-.819,.05),l(-.718,-.21),l(-.247,-.048),l(-.794,.213),l(.968,.454),l(.279,.162),l(.057,.276),l(-1.057,.197),l(-.356,.228),l(-.312,.292),l(-.372,-.113),l(-.819,-.583),l(-.29,1.103),l(.354,.903),l(-.419,.065),l(-.677,-.257),l(-.751,-.176),l(-.205,-.177),l(-.018,-.243),l(-.315,-.274),l(-.93,.276),l(-.743,-.613),l(.051,-.292),l(.27,-.374),l(-.304,-.129),l(-.224,-.016),l(-.992,-.08),l(-.718,-.292),l(-1.17,-.617),l(-.769,-.292),l(-.762,-.048),l(-.452,.23),l(-.645,.083),L(250,52.592),l(.281,.179),l(1.05,.682),l(-.321,.114),l(-.686,.05),l(-.359,-.259),L(249.277,53),l(-.646,-.21),l(.275,.488),l(.859,.972),l(.604,.015),l(.587,.08),l(.5,.581),l(.612,.805),l(.513,.432),l(.615,-.321),l(.285,.047),l(.592,.399),l(.585,.271),l(1.38,.396),l(-.634,.113),l(-.213,.208),l(.254,.19),l(.568,.286),l(.962,.444),l(.324,.237),l(.242,.682),l(-.112,.428),l(-1.302,-1.155),l(-.554,-.237),l(-.027,.238),l(.118,.27),l(1.055,1.281),l(-.01,.3),l(-.926,-.125),l(.053,.205),l(.432,.409),l(.378,.519),l(-.563,-.172),l(-.615,-.313),l(-.889,-.693),l(-.145,-.031),l(-.719,.064),l(-.91,-.188),l(-1.44,-.662),l(-.319,-.285),l(-1.062,-.665),l(.187,.777),l(-1.22,-.473),l(-.567,-.158),l(-.872,-.03),l(.095,.222),l(.799,.696),l(.853,.426),l(1.842,.645),l(1.296,.644),l(.774,.549),l(.442,.486),l(.429,.689),l(-1.833,-.341),l(-1.524,-.421),l(-1.251,-.28),l(-1.444,-.107),l(-1.092,-.25),l(-.898,-.644),l(-1.146,-.14),l(-.638,-.204),l(-.635,-.141),l(-.058,.145),M(146.194,38.698),l(.818,-.037),l(.78,-.125),l(1.138,-.548),l(.895,-.019),l(1.723,.243),l(.939,.262),l(-.188,.877),l(.515,-.071),l(.66,-.019),l(.792,-.229),l(.599,-.141),l(.758,.016),l(.334,-.071),l(-.989,-.965),l(.156,-.036),l(1.38,.138),l(1.208,.245),l(.675,.245),l(.259,.245),l(.194,.508),l(.965,1.063),l(.638,.346),l(1.045,-.315),l(.14,-.261),l(-1.243,-1.361),l(-.439,-1.321),l(.228,-.354),l(1.91,.262),l(1.775,.156),l(2.031,.719),l(.36,.175),l(.3,.316),l(.16,.701),l(.511,.645),l(.352,.26),l(.856,.606),l(.048,.19),l(-.178,.243),l(-.333,.605),l(.179,.31),l(.224,.12),l(1.4,.649),l(.509,.171),l(1.151,.254),l(1.513,.1),l(2.056,.576),l(1.012,.39),l(.364,.793),l(-.168,.101),l(-1.071,-.082),l(-.811,-.234),l(-.945,-.234),l(-.551,.169),l(-.665,.204),l(-1.021,.036),l(-.256,.118),l(.208,.689),l(1.087,-.069),l(.614,-.152),l(.676,-.119),l(.876,.536),l(-.01,.235),l(-.526,.151),l(-.517,.252),l(-.583,.102),l(-1.417,.12),l(-1.049,-.015),l(-1.194,-.082),l(-1.594,-.248),l(-2.278,-.499),l(-.553,-.217),l(-.436,-.335),l(-.482,-.033),l(-.581,.102),l(-.402,.37),l(-1.114,.505),l(-1.055,.019),l(-1.411,.103),l(-1.253,.42),l(-2.753,.356),l(-1.42,.019),l(-1.205,.086),l(-1.984,-.063),l(-.483,.101),l(-.916,-.015),l(-1,-.282),l(-.061,-.468),l(.198,-.101),l(.002,-.302),l(-.395,-.2),l(-.462,-.1),l(-3.146,-.112),l(-1.258,-.115),l(-.864,-.167),l(-.801,-.2),l(-.753,-.504),l(-1.274,-.554),l(.303,-.069),l(.531,-.222),l(1.572,-.054),l(.603,-.188),l(.558,.016),l(.91,-.019),l(.904,-.087),l(1.716,.031),l(.935,-.002),l(2.14,.047),l(1.09,-.002),l(1.711,-.038),l(.415,-.154),l(-.681,-.221),l(-2.312,-.492),l(-1.942,-.202),l(-4.059,-.061),l(-1.569,-.014),l(-1.694,.055),l(-.955,.053),l(-.604,.001),l(-1.651,-.529),l(.011,-.207),l(.28,-.069),l(.823,-.053),l(1.315,-.209),l(.996,.032),l(1.78,-.141),l(.931,-.105),l(.5,-.277),l(-.392,-.346),l(-2.023,.073),l(-1.578,.159),l(-.393,-.051),l(-.554,-.189),l(-.677,-.346),l(-.65,-.19),l(-.692,.054),l(-.709,-.242),l(-.039,-.279),l(1.304,-.981),l(2.62,-.848),l(.909,-.143),l(.373,-.177),l(1.297,-.267),l(1.324,-.162),l(.701,-.267),l(1.113,-.091),l(1.026,.246),l(-.07,.212),l(-.548,.354),l(-.021,.81),M(251.273,99.526),l(-.188,.153),l(-.16,-.291),l(.192,-.077),l(-.02,-.256),l(.143,-.069),l(-.042,-.154),l(-.224,0),l(-.606,-.231),l(.077,-.229),l(-.31,-2.819),l(-.174,-.274),l(-.488,-.288),l(-.771,-.025),l(-.41,.176),l(-.381,-.085),l(-.505,-.36),l(-.273,-.085),l(-.632,.526),l(-.514,.626),l(-1.139,2.22),l(-1.139,1.45),l(-1.161,-.124),l(-.402,.06),l(-.363,.435),l(-.174,.375),l(-1.093,-.095),l(-1.855,-.004),l(-2.508,-.029),l(-1.76,.009),l(-.968,.523),l(-.534,.305),l(-1.754,.814),l(-.545,.164),l(-.146,.434),l(-.163,.512),l(-.44,.275),l(-1.156,.197),l(-1.305,-.138),l(-1.123,-.01),l(-.93,.091),l(-.47,.203),l(-.162,.375),l(.018,.319),l(.16,.471),l(.047,.362),l(-.875,.427),l(-1.464,.452),l(-.944,.163),l(-.919,.062),l(-.88,.262),l(-.939,.478),l(-.925,.506),l(-.524,.117),l(-.573,-.068),l(-.497,-.169),l(-.371,-.427),l(-.012,-.33),l(.044,-.218),l(.707,-.525),l(.414,-.294),l(.264,-.433),l(.294,-.544),l(.377,-.576),l(.028,-.746),l(-.054,-.545),l(-.876,-3.16),l(-2.529,-1.05),l(-.26,-.33),l(.11,-.318),l(-.307,-.235),l(-.916,-.181),l(-.184,-.294),l(-.178,-.135),l(-.628,.024),l(-.46,-.465),l(-.101,-.429),l(-2.15,-1.061),l(-3.975,-1.576),l(-.977,-.386),l(-.797,-.227),l(-.805,.189),l(-1.469,.592),l(-.707,-.074),l(-.542,.049),l(-.196,-.144),l(-.156,-.115),l(-.474,-.041),l(-.855,.083),l(-.197,-.116),l(-.028,-.282),l(-.373,.075),l(-.412,.191),l(-.219,.06),l(-.573,.141),l(-.506,-.098),l(-.064,-.185),l(-.469,-.086),l(-.241,-.271),l(-.502,-.013),l(-.16,.247),l(-.338,-.48),l(-.271,.012),l(-.02,-.185),l(-1.425,-.208),l(-.518,.076),l(-.833,-.451),l(-.468,-.46),l(-.279,-.371),l(-.896,-.748),l(-.501,.036),l(.131,.347),l(.387,.588),l(-.68,-.003),l(-2.687,.029),l(-2.798,-.029),l(-1.348,.007),l(-2.105,-.003),l(-2.915,.016),l(-2.781,-.029),l(-2.131,.012),l(-2.935,-.014),l(-.601,.003),l(-4.84,-.018),l(-3.617,.004),l(-.875,.005),l(-3.821,-.023),l(-1.089,.035),l(-4.13,-.021),l(-.74,-.011),l(-5.117,.028),l(-1.687,-.006),l(-2.87,.001),l(-3.938,-.008),l(-4.588,.025),l(-1.335,-.022),l(-2.579,-.001),l(-.194,-.013),l(-.187,-.151),l(-.509,-.305),l(-.071,-.437),l(.074,-.346),l(-.708,.25),l(-.373,-.029),l(-.331,-.305),l(-.162,-.496),l(-.125,-.189),l(-.385,.088),l(-.23,.205),l(-.483,.059),l(-.721,-.495),l(-.119,-.425),l(-.201,-.821),l(-1.051,.104),l(-1.01,-.277),l(-.487,-.087),l(-.173,-.087),l(-.143,-.396),l(-.438,-.352),l(-.591,.222),l(-1.236,.046),l(-.461,-.117),l(-.383,-.249),l(-.106,-.25),l(.257,-.648),l(.458,-.222),l(-.227,-.294),l(-1.24,-.086),l(.617,-.518),l(.398,-.281),l(.547,-.149),l(.605,-.508),l(-.874,.006),l(-.621,.149),l(-.362,-.043),L(116,83.422),l(-.039,-.978),l(-.789,.002),l(-1.015,-1.066),l(.132,-.238),l(.034,-.53),l(-.547,.056),l(-.83,.492),l(-1.266,-.934),l(-.384,-.521),l(-.204,-.402),l(-.068,-.432),l(.419,-.404),l(.161,-.254),l(.436,-.3),l(-.358,-.689),l(-.393,-.777),l(.163,-.788),l(-.402,-.255),l(-2.025,-.763),l(-.98,-.314),l(-.189,-.029),l(-.512,-.393),l(-1.67,-1.882),l(-1.769,-1.768),l(-.814,-.58),l(-2.048,-1.175),l(-.35,-.322),l(-.371,-.492),l(-.316,-.199),l(-.832,-.073),l(-.495,.126),l(-.731,.498),l(-1.225,.67),l(-.848,.205),l(-.238,.325),l(-.945,-.673),l(-2.162,-1.318),l(-.348,-.292),l(-.173,-.387),l(-.332,-.388),l(-.739,-.059),l(-2.424,.122),l(-.84,-.074),l(-.196,-.279),l(-.089,-1.046),l(-.026,-2.167),l(.043,-4.334),l(.026,-2.183),l(-.129,-2.796),l(-.052,-2.335),l(-.039,-2.259),l(.003,-2.855),l(-.102,-.483),l(.71,.024),l(.9,-.086),l(.964,.116),l(2.012,.451),l(1.601,.518),l(1.214,.266),l(1.04,.115),l(.731,.032),l(1.619,.164),l(.888,.232),l(.429,.149),l(.254,-.034),l(-.452,-.601),l(-.357,-.2),l(-.345,-.15),l(-.064,-.419),l(1.344,-.423),l(.745,.066),l(.578,-.068),l(.15,-.102),l(1.736,.148),l(.771,-.001),l(1.125,-.373),l(.309,-.186),l(.442,0),l(.656,-.221),l(.759,-.069),l(.866,-.086),l(.734,-.086),l(.469,-.239),l(.392,-.188),l(.771,-.104),l(1.045,-.002),l(.872,.123),l(-.445,.404),l(-.352,.119),l(-1.101,.137),l(-1.092,.373),l(-1.244,.171),l(-1.22,.271),l(-.699,.522),l(-1.767,.255),l(-.681,.487),l(.846,.266),l(1.441,.748),l(-.219,-.55),l(.168,-.351),l(1.196,-.253),l(.39,-.235),l(.726,-.421),l(1.727,-.053),l(.96,-.372),l(1.158,-.389),l(2.066,-.173),l(.643,-.338),l(.921,-.272),l(.821,-.189),l(.476,-.239),l(-.178,-.272),l(-.702,-.392),l(-.655,-.444),l(.899,.101),l(.764,.272),l(.701,.306),l(.412,.324),l(.376,.476),l(.449,.523),l(.393,.235),l(1.246,.486),l(.186,.067),l(1.154,.216),l(.394,-.018),l(.199,-.151),l(-.511,-.639),l(.07,-.27),l(.548,-.035),l(.334,-.136),l(.627,-.103),l(.383,.354),l(.059,.421),l(-.205,.287),l(.833,.133),l(.938,-.069),l(1.136,-.457),l(.536,-.49),l(.479,-.069),l(1.131,.015),l(1.536,.267),l(1.745,.435),l(1.396,.334),l(2.095,.349),l(1.024,.216),l(.619,.066),l(1.572,.282),l(1.121,.065),l(1.144,.148),l(1.096,.032),l(1.4,-.086),l(.899,.099),l(1.008,.282),l(.982,.349),l(.434,.249),l(.191,.333),l(-.524,.134),l(-.935,-.032),l(-.566,.051),l(-.849,.135),l(-.354,.714),l(3.323,.358),l(1.726,.079),l(1.749,.014),l(.868,-.068),l(.738,-.051),l(.94,-.167),l(.895,-.118),l(.938,-.101),l(.886,.032),l(1.432,.477),l(1.452,.179),l(.42,.115),l(1.225,.443),l(-.013,.312),l(-.504,.083),l(-.35,.247),l(.305,.147),l(1.823,.979),l(-.162,-.392),l(-.024,-.312),l(.456,-.05),l(.617,-.132),l(-.062,-.181),l(-.972,-.656),l(-.128,-.198),l(-.145,-.445),l(.121,-.745),l(.35,-.034),l(1.944,-.136),l(.928,-.151),l(.207,-.299),l(.459,-.217),l(.613,-.035),l(1.098,.281),l(1.528,.279),l(.968,.064),l(.969,-.102),l(.612,.414),l(.248,.082),l(.962,.213),l(1.211,.13),l(.678,.081),l(1.146,-.002),l(.879,-.2),l(1.755,-.02),l(1.876,.029),l(1.07,-.052),l(1.18,-.267),l(.959,.478),l(.95,.296),l(.522,-.018),l(.243,-.314),l(-.017,-.513),l(-.666,-.231),l(-.732,-.131),l(-1.377,-.064),l(.089,-.449),l(1.193,-.085),l(.575,.065),l(.804,.214),l(.871,.198),l(.858,.048),l(.498,.198),l(.088,.183),l(-.095,.132),l(-.287,.86),l(.179,.51),l(.304,.164),l(.177,.065),l(.792,.097),l(.951,.311),l(-.071,-.559),l(-.466,-.989),l(.137,-.48),l(.258,-.266),l(.712,.015),l(.811,-.035),l(1.229,-.85),l(.492,-.051),l(.479,-.001),l(.517,-.151),l(.033,-.133),l(-.15,-.367),l(-.375,-.35),l(-.307,.001),l(-.81,.185),l(-.988,-.082),l(.535,-.52),l(.806,-.069),l(.435,-.168),l(.572,-.001),l(.739,.4),l(.464,.167),l(.065,-.268),l(-.081,-.956),l(-.744,.069),l(-.897,-.032),l(-.68,-.116),l(-.859,-.318),l(-.725,.085),l(-1.245,-.183),l(-.861,-.234),l(-.956,-.218),l(-.657,-.338),l(-.092,-.136),l(-.022,-.324),l(.33,-.137),l(.842,-.463),l(-.486,-.221),l(-1.188,-.375),l(.09,-.207),l(.58,-.604),l(.593,-.294),l(.387,-.035),l(1.032,.257),l(.139,-.035),l(.173,-.346),l(-.709,-.362),l(-.201,-.277),l(.23,-.035),l(.551,-.331),l(.367,-.035),l(1.841,-.021),l(.559,.086),l(.728,.189),l(1.26,.449),l(.432,.328),l(.195,.38),l(-.246,.603),l(1.261,.53),l(.809,.495),l(1.134,.493),l(-.377,.341),l(-.985,.036),l(-.474,.273),l(-.416,.557),l(.471,.067),l(1.071,.233),l(.805,.049),l(.387,-.136),l(.597,-.001),l(1.477,.351),l(-.335,.353),l(-.563,.219),l(.092,.151),l(.796,.467),l(.358,.601),l(.025,.833),l(.303,-.063),l(.021,-.004),l(.411,-.067),l(.608,-.367),l(.655,-1.137),l(.668,-.42),l(.523,.016),l(.731,.284),l(1.064,.55),l(.473,.383),l(.209,.45),l(-.159,.433),l(-.336,.034),l(-.796,-.098),l(-.202,.299),l(-.043,.415),l(.35,.396),l(1.146,.659),l(.61,.493),l(.463,.279),l(.595,-.166),l(.896,-.167),l(.369,-.132),l(.208,-.66),l(.764,-.398),l(.599,-.416),l(.249,-.664),l(.363,-.75),l(.237,-.184),l(1.394,.081),l(.329,-.067),l(.134,-.518),l(-.985,-.333),l(-.918,-.35),l(.088,-.891),l(.595,-.271),l(.787,.032),l(.42,-.068),l(.571,.016),l(3.459,.616),l(1.325,.669),l(.506,-.001),l(.553,-.068),l(.454,.201),l(.244,1.036),l(-.474,.268),l(-.431,.101),l(-.243,-.05),l(-.718,-.532),l(-.263,0),l(-.799,.269),l(.123,.316),l(.309,.515),l(.699,.729),l(.855,.528),l(1.108,.576),l(.024,.313),l(-.478,.642),l(-.439,.181),l(-1.407,.772),l(-.674,.083),l(-1.123,.509),l(-.763,-.276),l(-1.654,-.962),l(-.586,-.262),l(-.497,-.048),l(-.684,.281),l(1.364,.521),l(1.483,.896),l(-.708,.067),l(-.691,-.081),l(-1.288,.084),l(-.375,-.129),l(-.596,-.62),l(-1.147,-.014),l(-1.857,.118),l(-.253,.229),l(.614,.244),l(1.311,.421),l(-.159,.195),l(-.611,.327),l(-2.045,1.106),l(-.657,.179),l(-.527,.001),l(-.859,-.241),l(-.816,-.484),l(-.225,-.081),l(-1.189,-.225),l(-.736,-.259),l(-.598,-.112),l(-.947,.014),l(-.289,.004),l(-1.214,.174),l(1.503,.278),l(1.136,.21),l(1.751,.774),l(1.629,.433),l(1.233,.126),l(1.02,.031),l(-.618,1.091),l(-1.237,.705),l(-.856,.432),l(-.728,.161),l(-.829,.049),l(-.928,-.126),l(-1.062,-.38),l(-.048,.351),l(-.025,.287),l(.321,.572),l(-.02,.159),l(-.741,.031),l(-.058,.002),l(-1.365,-.108),l(-1.649,-.41),l(-.884,-.078),l(-2.962,-.322),l(2.146,.864),l(1.576,.156),l(1.367,.267),l(.562,.205),l(.33,.268),l(-.011,.19),l(-.642,.333),l(-1.106,.207),l(-1.429,-.076),l(-.511,-.062),l(-.367,.269),l(1.254,.423),l(-.469,.426),l(-1.06,.316),l(-1.454,.662),l(-.421,.252),l(.218,.704),l(-.313,.235),l(-.909,.205),l(-.31,.282),l(-.529,.64),l(-.276,.296),l(-.241,.669),l(-.274,.543),l(-.323,.666),l(.056,.416),l(-.161,.554),l(.123,.875),l(.136,.536),l(.598,.366),l(.25,.015),l(.257,.091),l(.664,.014),l(1.164,-.094),l(.276,.045),l(.367,.29),l(.413,.763),l(.813,1.157),l(.22,.668),l(-.132,.91),l(.673,.014),l(1.874,-.428),l(1.261,-.033),l(.723,.074),l(.535,.157),l(1.062,.311),l(2.129,.435),l(1.896,.903),l(.993,.933),l(3.5,.67),l(.644,.225),l(.982,.403),l(.986,.253),l(.553,.104),l(.702,-.091),l(.453,.044),l(.828,-.077),l(1.245,.163),l(1.407,.207),l(.401,.194),l(-.297,.702),l(-.142,.85),l(.154,.283),l(.307,.342),l(.07,.416),l(-.115,1.025),l(-.309,.593),l(.022,.208),l(.604,.266),l(.481,.339),l(.264,.354),l(.046,.488),l(-.076,.354),l(.97,.116),l(.963,.47),l(.676,.588),l(.392,.588),l(.078,.162),l(.64,.014),l(.726,.41),l(.907,.601),l(-.349,-.66),l(-.22,-.279),l(.134,-.338),l(.573,-.414),l(.365,.176),l(.381,.456),l(.262,.353),l(.165,-.354),l(.107,-.545),l(-.215,-.456),l(.541,-.532),l(.139,-.546),l(-.183,-.517),l(-.337,-.458),l(-.261,-.754),l(-.004,-.548),l(-.205,-.593),l(-.218,-.43),l(.615,-.016),l(-.097,-.476),l(-.296,-.252),l(-.657,-.163),l(-.375,-.282),l(-.326,-.923),l(1.252,-.271),l(.872,-.241),l(.625,-.271),l(1.758,-.949),l(.629,-.302),l(1.043,-.935),l(.434,-.544),l(.237,-.665),l(.054,-.529),l(-.257,-1.045),l(-.246,-.531),l(-.239,-.319),l(-.938,-.729),l(-.467,-.274),l(-1.105,-.532),l(-.363,-.122),l(-.453,-.274),l(-.151,-.046),l(-.293,-.351),l(.08,-.107),l(.868,-.522),l(.553,-.875),l(.293,-.416),l(.25,-.092),l(.447,-.017),l(.295,-.277),l(-.106,-.523),l(-.18,-.355),l(-.316,-.402),l(-.048,-.202),l(.258,-.357),l(.005,-.264),l(-1.751,-.105),l(1.084,-.92),l(.503,-.704),l(.007,-.125),l(-.316,-.203),l(-.609,-.265),l(-.244,-.266),l(-.043,-.533),l(.305,-.425),l(.554,-.315),l(.57,-.19),l(.827,.062),l(1.781,.374),l(1.097,.234),l(.753,.077),l(1.44,.013),l(1.08,-.144),l(.86,-.222),l(.21,-.047),l(.179,-.063),l(.589,.078),l(.991,.407),l(.254,.125),l(.754,.454),l(.918,.375),l(.796,.437),l(-.294,.391),l(.406,.233),l(1.698,.496),l(1.958,.354),l(.725,-.033),l(.368,-.203),l(.339,.295),l(-.013,.404),l(-.577,.343),l(-.123,.45),l(.438,1.327),l(.136,.722),l(.23,.414),l(-.049,.353),l(-.248,.169),l(-.445,-.014),l(-.347,-.015),l(-.138,.674),l(.375,.274),l(1.137,-.415),l(.366,-.047),l(.781,-.047),l(.286,.015),l(.677,.32),l(.378,.351),l(.004,.259),l(-.081,.123),l(.277,.32),l(.516,-.184),l(.306,-.046),l(1.173,-.079),l(.636,-.184),l(.436,-.383),l(.333,-.551),l(.326,.015),l(.194,.122),l(.693,.717),l(.042,-.062),l(.108,-.764),l(.317,-.583),l(.475,-.262),l(.539,-.385),l(-.651,-.505),l(.008,-.308),l(.272,-.139),l(.98,-.094),l(.193,-.139),l(.512,-.665),l(.667,.37),l(.607,.599),l(.785,.506),l(.596,.797),l(1.045,.764),l(.264,.352),l(-.344,.291),l(.095,.335),l(.573,-.031),l(.365,.777),l(.182,.183),l(.324,.121),l(.743,.136),l(.281,.258),l(.133,.38),l(-.379,.092),l(-.416,.168),l(.411,.318),l(.397,.227),l(.77,.196),l(.279,.227),l(.034,.424),l(-.056,.076),l(-.409,.106),l(-.676,-.029),l(-.745,-.12),l(-.316,.061),l(.091,.166),l(.273,.181),l(.189,.241),l(.333,.513),l(.411,.226),l(.634,.029),l(.462,.18),l(.838,.496),l(.899,.435),l(.246,.33),l(-.035,.195),l(-.447,.781),l(.508,.059),l(.663,-.166),l(.786,-.077),l(.79,.164),l(.574,.194),l(1.162,.49),l(.981,.132),l(1.517,.295),l(-.184,.253),l(-.718,.21),l(-.736,.21),l(-.663,.046),l(-.834,.24),l(-.583,.402),l(-.65,.225),l(-1.032,.061),l(-.286,.075),l(-.324,.268),l(.029,.371),l(-.271,.535),l(1.175,-.343),l(.542,-.09),l(.649,-.105),l(1.201,-.774),l(1.251,-.478),l(1.146,-.106),l(.662,.237),l(.35,.341),l(-.398,.446),l(.036,.119),l(.307,.296),l(.616,-.224),l(.455,-.164),l(.655,.192),l(1.051,.487),l(.226,.251),l(.022,.178),l(-.299,.43),l(-.05,.355),l(-.406,.444),l(1.001,.929),l(-.365,.37),l(-.795,.282),l(-1.078,.621),l(-.662,.281),l(-1.097,.046),l(-.823,.119),l(-1.548,.077),l(-.433,.413),l(-.916,.795),l(-.686,.427),l(-.612,.294),l(-.938,.222),l(-1.494,.172),l(-1.845,.127),l(-1.452,-.07),l(-2.031,-.084),l(-.355,.03),l(-1.073,.075),l(-1.058,-.012),l(-1.873,-.099),l(-.917,-.027),l(-1.758,.106),l(-.547,.206),l(-.523,.294),l(-.537,.585),l(-.205,.554),l(-.287,.335),l(-.591,.19),l(-1.07,.104),l(-.537,.147),l(-1.098,.555),l(-.774,.54),l(-.794,.612),l(-.325,.363),l(-.33,.233),l(-.868,.843),l(-.485,.566),l(-.418,.276),l(-.46,.58),l(-.518,.968),l(.749,-.737),l(.375,-.131),l(.688,-.479),l(1.059,-.944),l(1.097,-.785),l(2.028,-.948),l(1.245,-.395),l(1.797,-.512),l(1.065,-.235),l(1.03,-.235),l(1.473,-.148),l(.922,.056),l(.895,.289),l(.509,.29),l(.136,.189),l(.144,.464),l(-.125,.218),l(-.326,.219),l(-1.059,.292),l(-.753,.452),l(-.581,.044),l(-.845,-.23),l(-.726,.045),l(-.645,.19),l(.279,.08),l(1.13,.229),l(.17,.122),l(.256,.444),l(.074,.095),l(1.299,-.485),l(-.028,.216),l(.479,-.148),l(.372,.162),l(-.36,.229),l(-.231,.256),l(.112,.27),l(-.163,.014),l(-.074,.229),l(-.91,.444),l(1.216,.013),l(.077,.188),l(-.187,.282),l(.091,.43),l(.118,-.081),l(.239,.134),l(-.063,.134),l(.048,.202),l(.351,.457),l(.009,.147),l(.824,.054),l(.154,.094),l(.04,-.067),l(.727,.147),l(-.315,.134),l(-.373,-.013),l(-.047,.134),l(.525,.147),l(.211,.241),l(.569,-.081),l(.135,.134),l(.212,-.014),l(.134,.174),l(.418,-.04),l(-.075,-.107),l(.843,.067),l(.241,.107),l(-.207,.201),l(.242,-.107),l(.26,.027),l(.245,-.013),l(.696,-.362),l(.303,-.081),l(.104,.362),l(.377,.161),l(.538,-.121),l(.488,.416),l(-.405,.254),l(.089,.107),l(.825,.027),l(.164,.174),l(-.521,.121),l(-.161,-.121),l(-.3,.134),l(.118,.094),l(-.515,0),l(-.23,-.04),l(.109,.161),l(-.45,.04),l(.056,.107),l(-.443,.014),l(-.128,.147),l(-.45,.04),l(-.368,.253),l(-.09,-.106),l(-.706,.28),l(-.046,.053),l(-.529,.133),l(-.119,-.267),l(-.274,.106),l(-.163,.267),l(-.188,-.187),l(-.068,.253),l(-.218,.08),l(-.094,.187),l(-.513,0),l(-.081,-.08),l(-.169,-.053),l(.032,-.347),l(-.242,.36),l(-.202,.12),l(-.131,-.253),l(-.354,.027),l(.043,.24),l(-.233,.04),l(.312,.08),l(.033,.213),l(-.103,.12),l(-.174,-.067),l(-.768,.453),l(.127,.16),l(-.235,.12),l(-.194,.053),l(.015,.213),l(-.161,-.12),l(.083,.173),l(-.217,.08),l(-.14,-.107),l(.096,.253),l(-.222,.066),l(-.146,-.08),l(-.148,0),l(-.064,.133),l(-.156,-.106),l(-.243,.227),l(-.086,.292),l(-.201,-.226),l(-.344,.133),l(-.154,-.187),l(-.349,-.479),l(-.138,.24),l(-.419,-.866),l(.456,-.773),l(.284,-.16),l(.035,-.12),l(-.35,.12),l(-.357,.267),l(-.076,-.106),l(.924,-.507),l(.125,.146),l(.195,-.093),l(-.258,-.107),l(1.103,-.52),l(1.109,-.562),l(.658,-.361),l(.336,.094),l(-.067,.428),l(.179,-.054),l(.258,.281),l(-.044,-.201),l(-.017,-.174),l(.632,-.214),l(.73,-.134),l(.192,.067),l(.202,-.081),l(-.152,-.094),l(-.653,-.053),l(-.595,.053),l(-.42,-.053),l(-.804,-.014),l(-.306,.027),l(-.251,.081),l(-.246,.094),l(.033,-.214),l(1.128,-.563),l(.054,-.201),l(.252,-.08),l(-.052,-.174),l(-.523,.281),l(.097,-.134),l(-.502,-.51),l(.309,.443),l(-.36,.482),l(-.328,.013),l(-1.974,.817),l(-.284,.08),l(-.362,-.201),l(-.227,-.067),l(.23,.201),l(-.788,.401),l(-.219,-.174),l(-1.019,-.054),l(-.124,.147),l(-.38,-.241),M(186.193,47.833),l(-.713,-.032),l(-.922,-.181),l(-.882,-.065),l(-1.25,-.314),l(-.973,-.182),l(-.604,-.049),l(-1.083,-.199),l(.43,-.335),l(1.542,-.405),l(.385,-.186),l(.115,-.673),l(.305,-.236),l(.831,-.069),l(.743,.184),l(1.436,.603),l(1.287,.4),l(.074,.285),l(.315,.284),l(1.094,.516),l(-.288,.117),l(-1.263,.486),l(-.578,.051),M(231.09,50.646),l(-1.319,-.03),l(-.449,-.147),l(-.232,-.247),l(-.173,-.478),l(.3,-.43),l(.708,-.664),l(.662,-.267),l(1.359,-.168),l(.911,.197),l(.79,.314),l(-.021,.464),l(-.039,.727),l(-.362,.265),l(-1.025,.348),l(-1.108,.117), +N(444.972,79.145),l(.47,-.218),l(.307,-.093),l(-.294,-.024),l(-.419,.061),l(-.15,-.135),l(-.125,.184),l(-.108,-.012),l(.066,-.491),l(.177,-.218),l(.41,.009),l(1.489,.062),l(.417,.014),l(.339,-.075),l(.121,-.253),l(-.175,-.288),l(.246,-.05),l(-.068,-.122),l(-.068,-.123),l(.353,-.096),l(.12,-.034),l(.051,.154),l(.086,.052),l(.24,0),l(.223,.12),l(.257,.069),l(.514,.068),l(.086,.103),l(.223,-.051),l(.445,0),l(.257,0),l(.223,-.017),l(.086,.137),l(.103,.103),l(.188,.034),l(.171,.069),l(.018,.137),l(.052,.12),l(-.224,.12),l(-.068,.154),l(-.068,.206),l(.018,.171),l(.034,.137),l(.029,.038),l(-2.96,.101),l(-2.246,-.115),l(-.842,-.006),M(717.633,81.109),l(.42,.443),l(.429,.62),l(.183,.457),l(.01,.767),l(-.244,.442),l(-.197,.78),l(-.002,.764),l(.29,.777),l(.592,.849),l(.65,1.446),l(.899,1.614),l(1.115,1.679),l(-1.26,-.677),l(-.832,-.39),l(-.99,-.056),l(-.268,.088),l(-.396,.204),l(-.462,1.045),l(-.266,1.101),l(-.082,.579),l(.277,.982),l(.183,.216),l(.659,.908),l(.54,.201),l(.463,.648),l(-.314,1.246),l(-.664,-1.258),l(-.866,-.301),l(-.224,.029),l(-.415,.303),l(-.311,.534),l(-.643,.907),l(-.422,-.5),l(-.19,-.929),l(.637,-1.146),l(-.395,-.884),l(.175,-.454),l(.502,-.63),l(-.131,-.723),l(-.196,-.376),l(-.27,-.55),l(-.062,-.235),l(.403,-.302),l(.284,-.915),l(.075,-.784),l(.005,-1.326),l(.15,-1.302),l(-.09,-.732),l(-.213,-.469),l(-.83,-.85),l(-.1,-.897),l(.114,-.192),l(.359,-.722),l(.065,-.738),l(-.336,-.457),l(.172,-.237),l(.374,-.03),l(.62,-.031),l(1.023,-.534),M(471.158,84.281),l(-.002,-.142),l(-.165,-.066),l(-.082,-.115),l(-.164,-.082),l(.033,-.099),l(-.033,-.23),l(-.033,-.164),l(.082,-.099),l(-.147,-.131),l(-.099,-.148),l(.132,-.066),l(0,-.165),l(-.296,-.164),l(-.279,-.263),l(-.017,-.164),l(.099,-.131),l(.131,-.165),l(.362,-.017),l(.328,.049),l(.197,.132),l(.51,.016),l(.525,-.099),l(.444,-.247),l(.049,-.065),l(.148,-.083),l(.296,0),l(.065,-.164),l(-.033,-.131),l(-.279,-.066),l(-.296,-.148),l(-.099,-.181),l(.082,-.017),l(.066,-.049),l(.032,-.065),l(-.263,-.066),l(-.361,-.099),l(-.378,-.066),l(-.361,.066),l(-.182,-.066),l(.066,-.181),l(.099,-.197),l(-.066,-.148),l(-.164,-.099),l(-.279,-.082),l(-.23,-.066),l(-.443,-.213),l(-.115,-.23),l(-.164,-.263),l(-.214,-.017),l(-.017,-.099),l(.066,-.131),l(.099,-.115),l(-.132,-.033),l(-.181,.049),l(-.082,-.115),l(-.132,-.181),l(-.345,-.049),l(.049,-.147),l(.033,-.165),l(.099,-.049),l(.115,-.082),l(0,-.083),l(.114,0),l(.066,-.131),l(-.05,-.164),l(-.147,-.099),l(-.197,-.247),l(.131,-.165),l(.033,-.164),l(0,-.083),l(.065,-.115),l(-.049,-.115),l(-.147,.033),l(-.165,-.033),l(-.147,-.099),l(-.099,-.099),l(-.279,-.099),l(-.132,-.131),l(-.542,-.115),l(-.247,.049),l(-.099,-.049),l(-.131,-.049),l(-.23,.083),l(-.147,.099),l(-.165,0),l(-.279,.016),l(-.214,.197),l(-.197,0),l(-.164,-.148),l(-.065,-.148),l(.017,-.099),l(.164,-.099),l(0,-.115),l(-.147,-.017),l(-.296,-.065),l(-.312,-.049),l(-.361,.049),l(-.214,.065),l(-.197,.033),l(-.082,-.148),l(-.132,-.148),l(-.312,-.033),l(-.181,-.016),l(-.197,.131),l(-.229,-.066),l(-.165,-.147),l(.061,-.042),l(.015,-.117),l(.044,-.087),l(-.088,-.233),l(.015,-.189),l(-.131,-.117),l(.059,-.087),l(-.16,-.043),l(-.146,-.102),l(-.029,-.16),l(-.131,-.058),l(-.116,-.102),l(.043,-.073),l(.059,-.087),l(-.073,-.044),l(-.087,-.014),l(-.131,-.073),l(-.146,.015),l(-.204,.059),l(.044,-.102),l(.102,-.073),l(.073,-.087),l(-.029,-.117),l(.072,-.131),l(-.131,-.087),l(.103,-.029),l(.087,-.015),l(.102,-.073),l(.015,-.087),l(.029,-.116),l(.015,-.087),l(-.204,-.058),l(-.087,-.073),l(-.204,-.087),l(-.232,-.073),l(0,-.117),l(.015,-.116),l(-.37,.004),l(-.081,-.106),l(.116,-.058),L(461.402,72),l(.029,-.117),l(.131,0),l(.087,-.116),l(.059,-.102),l(.16,-.058),l(.262,-.043),l(.175,-.073),l(-.059,-.059),l(-.175,-.043),l(-.043,-.146),l(-.015,-.087),l(0,-.073),l(-.088,-.073),l(-.203,-.087),l(-.175,-.233),l(0,-.175),l(.175,-.131),l(-.029,-.16),l(-.073,-.189),l(-.131,-.437),l(-.029,-.16),l(.088,-.16),l(.204,-.131),l(.319,-.131),l(.219,-.204),l(.175,-.277),l(.058,-.131),l(.088,-.043),l(.116,0),l(.189,0),l(.175,-.044),l(.043,-.174),l(-.16,-.131),l(-.145,-.053),l(-.089,-.13),l(-.17,-.038),l(.1,-.253),l(.339,-.038),l(.153,.165),l(.229,.063),l(.188,-.088),l(-.094,-.139),l(.301,-.154),l(.485,.199),l(.296,-.062),l(.312,-.338),l(.311,-.185),l(.75,.106),l(.781,.275),l(.439,0),l(.363,-.154),l(-.386,-.399),l(-.59,-.323),l(-.393,-.03),l(-1.204,.08),l(-.616,-.091),l(-.271,-.108),l(-.299,-.309),l(.258,-.434),l(-.065,-.201),l(-.199,.044),l(.174,-.285),l(1.946,-1.145),l(1.983,-1.195),l(1.385,-.758),l(.591,-.536),l(.43,-.536),l(.105,-.409),l(-.161,-.346),l(-.436,-.392),l(-.703,-.265),l(-1.357,-.499),l(-.439,-.33),l(.327,-.191),l(.542,-.415),l(.057,-.254),l(-.151,-.253),l(-1.286,-1.395),l(-.37,-.509),l(.029,-.37),l(.187,-.403),l(.44,-.535),l(.196,-.356),l(-.772,-1.195),l(-1.402,-1.394),l(.328,-.296),l(1.303,-.777),l(.421,-.364),l(-.543,-.392),l(-.964,-.506),l(-.872,-.194),l(-.563,-.212),l(-.116,-.529),l(.258,-.465),l(.024,-.283),l(.689,-.303),l(1.013,-.672),l(1.023,-.49),l(.77,-.121),l(.824,-.021),l(.514,-.204),l(.404,-.288),l(.617,-.051),l(1.002,-.254),l(.643,-.237),l(.01,.151),l(.255,.386),l(.358,.284),l(.543,.2),l(.919,.082),l(.602,.1),l(.078,.602),l(.695,-.319),l(.421,.049),l(1.083,.048),l(.875,.015),l(.522,.032),l(1.116,-.002),l(1.293,.281),l(2.728,.512),l(.984,.364),l(1.595,.86),l(.583,.214),l(1.48,.246),l(1.296,.212),l(2.018,.623),l(.328,.279),l(-.051,.444),l(.147,.295),l(.426,.294),l(.104,.294),l(-.24,.344),l(-.69,.491),l(-1.092,.54),l(-.816,.262),l(-1.75,.36),l(-.907,.083),l(-1.631,-.013),l(-1.391,-.192),l(-2.038,-.175),l(-1.63,-.192),l(-1.342,-.339),l(-2.256,-.485),l(-1.114,-.112),l(-.476,-.048),l(-.621,-.473),l(-.371,-.163),l(-.771,-.13),l(-.943,.117),l(.307,.163),l(.149,.065),l(.73,.538),l(.482,.146),l(1.109,.601),l(.832,.291),l(.921,.161),l(.634,.242),l(.405,.453),l(-.002,.405),l(-.276,.291),l(-.684,.195),l(.086,.113),l(.208,.531),l(.771,.943),l(.093,.494),l(.155,.207),l(.438,.174),l(1.203,.078),l(.872,.125),l(.499,.619),l(.401,.095),l(1.26,.077),l(.575,.126),l(.364,.079),l(.402,-.128),l(.785,-.097),l(.243,-.302),l(-.001,-.318),l(-.387,-.397),l(-.471,-.079),l(-.455,.096),l(-.447,-.031),l(-.589,-.206),l(-.952,-.795),l(.701,-.674),l(.484,-.001),l(1.116,.479),l(1.441,.333),l(2.09,.427),l(.952,.078),l(.834,-.146),l(.723,.174),l(.261,-.224),l(.05,-.415),l(-.214,-.239),l(-.858,-.656),l(-.348,-.628),l(.285,-.323),l(.19,-.049),l(1.432,-.423),l(1.495,-.359),l(.599,-.244),l(1.133,-.717),l(.172,-.049),l(.462,.064),l(1.829,.29),l(1.41,.533),l(.341,-.001),l(.052,-.065),l(.154,-.503),l(.581,-.767),l(-.048,-.653),l(-.317,-.408),l(-.847,-.163),l(-.3,-.229),l(1.139,-1.005),l(.101,-.247),l(-.205,-.594),l(-.771,-.512),l(.069,-.315),l(.353,-.051),l(1.458,.23),l(2.025,-.12),l(.631,.132),l(.664,.611),l(.616,.445),l(.433,.461),l(-1.045,.051),l(-1.559,.085),l(-.822,.215),l(-.492,.51),l(.191,.18),l(.952,.293),l(.732,.555),l(.804,.194),l(.723,.097),l(1.268,-.133),l(1.33,-.084),l(.301,-.164),l(.257,-.491),l(.291,-.591),l(.284,-.412),l(1.232,-.2),l(1.223,-.414),l(.988,-.216),l(1.924,-.483),l(1.429,-.251),l(1.537,-.318),l(.921,-.3),l(.205,.464),l(.278,.083),l(.571,-.117),l(.487,-.266),l(.148,-.465),l(.386,-.167),l(.718,-.135),l(.859,.065),l(-.18,.399),l(-.058,.597),l(-.858,.084),l(-.178,.149),l(.002,.215),l(.687,.197),l(.507,-.083),l(1.169,-.167),l(.436,-.001),l(.161,.198),l(.23,.049),l(.278,-.133),l(.264,-.216),l(.29,-.431),l(.464,-.183),l(.861,-.118),l(1.049,-.068),l(.768,.032),l(1.075,.23),l(.755,-.018),l(.36,-.083),l(.963,-.467),l(1,-.285),l(.803,-.052),l(.952,.182),l(.326,.166),l(-.631,.45),l(.129,.232),l(.217,.099),l(.632,.131),l(.579,-.018),l(.288,-.232),l(.074,-.398),l(.342,-.084),l(.962,.065),l(.543,-.184),l(.395,-.316),l(.115,-.417),l(-1.37,-1.033),l(.405,-.168),l(.66,-.37),l(.403,-.068),l(.609,.016),l(2.171,.063),l(1.272,.199),l(1.241,.149),l(1.135,.199),l(2.111,.515),l(1.071,.098),l(1.712,.414),l(1.02,.248),l(1.305,.53),l(1.455,.611),l(.864,.379),l(.376,.049),l(.229,-.1),l(1.145,-1.047),l(.236,-.3),l(-.927,.035),l(-.4,-.049),l(-.564,-.232),l(-.365,-.433),l(.027,-.652),l(-.727,-.283),l(-1.987,-.147),l(-.19,-.268),l(.064,-.168),l(.305,-.303),l(.693,-.255),l(.236,-.153),l(.085,-.187),l(-.052,-.833),l(-.251,-.238),l(-1.135,-.066),l(-.232,-.29),l(.328,-.532),l(.359,-.241),l(.391,-.035),l(1.482,-.416),l(1.098,-.485),l(.521,-.416),l(.581,-.608),l(.544,-1.22),l(.637,-.421),l(.374,.069),l(1.562,.155),l(1.613,-.125),l(1.605,-.091),l(.695,.069),l(1.066,-.055),l(.574,.122),l(.309,.279),l(-.018,.332),l(-.423,.836),l(-.348,.348),l(-1.334,.833),l(-.223,.345),l(.752,.342),l(.931,.667),l(.277,.342),l(.21,.818),l(-.174,.222),l(-.575,.375),l(.254,1.179),l(-.058,1.305),l(.263,.583),l(.45,.381),l(1.027,.264),l(.19,.166),l(-.001,.133),l(-.485,.481),l(-.417,.826),l(-.333,.33),l(-.784,.462),l(-1.232,.625),l(-.63,.198),l(-.55,.263),l(.321,.522),l(-.433,.115),L(558,52.195),l(-1.599,-.372),l(-.731,-.08),l(-.97,.034),l(-.601,.115),l(.195,.31),l(.583,.276),l(.738,.21),l(1.569,.208),l(1.133,.079),l(.613,-.05),l(1.188,.144),l(.922,-.034),l(.472,-.358),l(.303,-.358),l(1.352,-.328),l(1.166,-.492),l(.268,-.278),l(.386,-.606),l(.818,-.313),l(.864,-.626),l(.064,-.362),l(-.225,-.561),l(-.609,-.545),l(.244,-.548),l(.237,-.1),l(.677,-.151),l(1.38,-.152),l(1.757,-.003),l(.74,.231),l(.842,.463),l(.151,.778),l(-.34,1.023),l(.302,.279),l(.92,.212),l(1.298,.047),l(.864,-.149),l(.129,-.296),l(-.514,-.18),l(-.797,-.18),l(-.571,.034),l(-.457,-.098),l(.068,-.379),l(1.03,-.382),l(.065,-.249),l(-.218,-.148),l(-.166,-.331),l(-.441,-.763),l(-.511,-.266),l(-.836,-.098),l(-1.093,-.231),l(-.801,-.116),l(-1.288,-.165),l(-.91,.186),l(-.638,.101),l(-1.297,-.181),l(-.896,.019),l(-.015,-.267),l(-.564,-1.071),l(.305,-.657),l(.736,-.697),l(.282,-.46),l(-.134,-.221),l(-1.092,-1.042),l(-.949,-.514),l(-.12,-.189),l(.833,-.554),l(1.213,-.106),l(.998,-.262),l(.744,-.348),l(.172,-.226),l(.169,-.644),l(-.13,-.663),l(.23,.069),l(.64,.051),l(.466,.086),l(.108,.471),l(-.186,.54),l(-.636,.608),l(-.167,.554),l(.14,.448),l(.373,.274),l(.485,.274),l(1.384,.134),l(1.574,.169),l(1.632,.083),l(.819,.409),l(.321,.017),l(.799,-.036),l(-.527,-.89),l(-.521,-.274),l(-1.893,-.1),l(-.931,-.067),l(-.576,-.154),l(-.609,-.448),l(.275,-.329),l(1.374,-.054),l(.444,.172),l(1.145,.084),l(.747,-.157),l(-.09,-.728),l(.408,-.088),l(.84,-.105),l(1.278,-.02),l(1.067,.207),l(1.413,.379),l(1.088,.535),l(1.326,.343),l(.547,.085),l(1.822,.014),l(.727,-.174),l(.138,.345),l(-.781,.38),l(-.696,.259),l(-.248,.771),l(-.129,.972),l(.333,.136),l(.68,-.785),l(.387,-.292),l(.285,.051),l(.604,.528),l(-.088,.749),l(.743,-.205),l(.681,-.273),l(-.044,-.306),l(-.191,-.119),l(-.147,-.358),l(-.748,-.821),l(.188,-.223),l(.686,-.759),l(-.797,-.448),l(-.772,-.258),l(-.93,-.241),l(-.257,-.382),l(-.655,-.051),l(-.979,-.242),l(-1.34,-.207),l(-.307,-.296),l(.062,-.577),l(-.096,-.386),l(-.811,-.667),l(.081,-.247),l(.266,-.16),l(.484,-.125),l(2.31,-.11),l(2.54,-.022),l(2.125,-.128),l(1.421,-.162),l(.475,.317),l(.382,.052),l(.844,-.267),l(1.056,-.286),l(1.413,-.109),l(.589,.194),l(-.957,.338),l(-.451,.407),l(1.737,-.233),l(.521,-.107),l(.955,-.374),l(.27,-.284),l(-.334,-.444),l(-.326,-.177),l(-.925,-.266),l(-.365,-.303),l(-.002,-.232),l(.324,-.539),l(1.176,-.397),l(.966,-.22),l(3.028,-.903),l(.889,-.094),l(.248,-.036),l(.522,-.076),l(1.899,-.096),l(1.663,-.114),l(2.302,-.244),l(2.048,-.263),l(1.595,-.43),l(.855,-.243),l(1.763,.034),l(1.065,-.002),l(.383,.185),l(-.351,.409),l(1.504,.108),l(1.018,-.039),l(1.261,-.188),l(1.345,-.225),l(.95,-.039),l(.982,.166),l(.687,.073),l(.693,-.206),l(.12,-.335),l(-.133,-.167),l(.466,-.337),l(.942,-.077),l(.939,.036),l(1.243,-.377),l(-.618,-.506),l(.122,-.34),l(1.165,-.438),l(1.554,-.383),l(2.23,-.406),l(1.229,-.077),l(.993,.056),l(1.486,-.003),l(.86,.265),l(.045,.266),l(-1.528,.401),l(-.66,.342),l(.488,.15),l(1.83,-.117),l(1.588,.148),l(2.039,-.079),l(.177,.113),l(-.375,.283),l(-1.187,.453),l(-.296,.3),l(1.971,-.004),l(.833,-.02),l(.234,.093),l(1.052,-.545),l(1.366,-.002),l(1.771,-.097),l(.631,.13),l(1.35,-.021),l(1.954,.165),l(1.4,.259),l(1.181,.427),l(.52,.445),l(.726,-.001),l(.854,-.076),l(.422,.5),l(-1.354,.832),l(.241,.128),l(.896,.365),l(-2.329,.859),l(-1.035,.235),l(-1.166,.11),l(-3.404,1.061),l(-3.018,.965),l(-.793,.285),l(-2.388,.375),l(-2.35,.586),l(-2.065,1.126),l(.715,.017),l(1.081,-.247),l(.922,-.458),l(1.663,-.161),l(1.231,-.02),l(2.101,-.268),l(1.879,-.286),l(.879,-.107),l(1.004,-.284),l(-.094,-.389),l(-.492,-.123),l(-.034,-.071),l(.281,-.249),l(.581,-.214),l(.873,.211),l(.603,.389),l(.621,.052),l(.593,.193),l(.737,.052),l(.853,-.055),l(1.155,-.268),l(.499,.07),l(.192,.3),l(.009,.512),l(.522,.404),l(1.422,-.778),l(1.66,-.021),l(1.506,-.145),l(2.354,.014),l(1.919,.155),l(.854,.034),l(1.204,.033),l(-.271,.74),l(.354,.333),l(2.043,.154),l(.848,.121),l(.698,.069),l(1.035,.103),l(2.49,-.145),l(1.209,-.02),l(1.42,.348),l(1.405,-.932),l(-.161,-.352),l(-.038,-.229),l(-.034,-.105),l(1.806,-.48),l(.521,-.019),l(.802,.104),l(1.148,.298),l(.851,.281),l(1.711,.032),l(1.354,-.073),l(1.384,.033),l(1.323,.431),l(.409,.181),l(.058,.386),l(-.52,.088),l(-.268,.036),l(-1.905,.406),l(-2.438,.737),l(-.233,.227),l(.253,.069),l(1.033,.067),l(.957,.016),l(.659,.155),l(.659,.293),l(1.014,.396),l(.583,.172),l(.78,.481),l(1.27,.805),l(1.814,.801),l(1.351,.305),l(.612,-.018),l(.795,-.394),l(.843,-.72),l(1.093,-1.051),l(.601,-.329),l(.29,.017),l(.236,.465),l(.772,.308),l(1.346,.29),l(1.105,.135),l(.848,-.087),l(1.973,-.468),l(.778,-.07),l(.813,.067),l(1.196,.239),l(1.921,.734),l(.315,-.052),l(.186,-.069),l(.491,-.258),l(.221,-.258),l(-.137,-.051),l(.013,-.189),l(.726,-.312),l(.509,-.018),l(.5,.257),l(.575,.188),l(1.302,.032),l(.181,-.5),l(-.194,-.466),l(.15,-.363),l(.093,-.521),l(-1.131,.159),l(-.643,.001),l(-.179,-.104),l(.442,-.296),l(.318,-.087),l(.986,-.089),l(1.021,-.02),l(.832,-.141),l(1.566,-.648),l(.254,0),l(1.76,.241),l(1.561,.137),l(2.036,.188),l(.997,.068),l(.654,.103),l(2.307,.065),l(-1.732,.628),l(.865,.051),l(1.011,-.089),l(.335,.138),l(-.305,.381),l(-.926,.192),l(-.846,.261),l(-.177,.293),l(.664,.033),l(.52,-.122),l(.916,-.14),l(.978,-.33),l(1.62,-.799),l(2.766,.012),l(1.196,.067),l(.903,.172),l(.946,.137),l(.205,.19),l(.221,.104),l(-2.247,.59),l(.559,.137),l(1.674,.289),l(2.174,.202),l(.946,.204),l(.801,.375),l(.367,.427),l(.564,.357),l(.522,.152),l(1.459,-.037),l(1.364,-.105),l(1.138,-.139),l(2.518,-.329),l(2.208,-.107),l(3.008,.131),l(1.515,.134),l(.734,.118),l(1.168,.424),l(.655,.169),l(.525,.338),l(.361,.39),l(-.123,.491),l(-.286,.521),l(.509,.25),l(.764,.065),l(.835,.015),l(.643,.083),l(-.017,.685),l(.419,.416),l(.686,-.168),l(.545,-.435),l(1.211,-.387),l(.348,-.067),l(.35,.049),l(1.696,-.02),l(1.521,-.288),l(.736,.032),l(.588,.434),l(.707,.116),l(1.541,.014),l(2.176,.062),l(.869,-.118),l(1.378,-.504),l(.406,.2),l(.93,.533),l(.396,.216),l(1.095,.265),l(.875,.332),l(.282,.398),l(.612,.148),l(1.556,-.136),l(1.653,-.319),l(.16,-.25),l(-.248,-.333),l(-.805,-.833),l(-.833,-.115),l(.4,-.336),l(.479,-.571),l(1.89,.098),l(1.214,.082),l(1.135,.065),l(1.221,.166),l(.222,.318),l(1.396,-.153),l(2.084,-.054),l(2.304,.013),l(1.292,.148),l(.786,.199),l(1.185,.199),l(1.391,.098),l(.751,.182),l(1.302,.332),l(.747,.065),l(.703,.182),l(1.145,.505),l(0,2.126),l(0,2.222),l(0,2.222),l(0,1.292),l(0,.157),l(0,.576),l(0,.219),l(-1.083,.371),l(-.651,.03),l(-.645,.37),l(-.56,.065),l(-1.044,.065),l(-.355,-.079),l(-.928,-.052),l(-.118,-.343),l(-.271,-.211),l(-.501,.027),l(.241,-.185),l(-.938,.324),l(-.846,.02),l(-.337,-.211),l(-.478,-.079),l(.424,.501),l(-.569,.29),l(.32,.103),l(.942,.205),l(.634,-.36),l(.395,.041),l(.335,.079),l(0,.477),l(.248,.206),l(.76,.269),l(1.059,-.228),l(-.439,.322),l(.741,-.243),l(.065,.336),l(.247,.206),l(.187,.363),l(.068,.189),l(-.722,.522),l(.593,-.064),l(.349,.172),l(.473,.503),l(.501,.157),l(.145,.251),l(-.162,.456),l(.792,-.111),l(-.125,.393),l(.023,.25),l(-.43,.299),l(-.691,.205),l(-.635,-.046),l(-.448,-.14),l(-1.243,-.154),l(-.889,-.077),l(-.347,-.14),l(.123,-.267),l(-.493,-.046),l(-.304,.032),l(-.559,.55),l(-.069,.11),l(-3.06,.913),l(-1.155,.174),l(-.245,0),l(-.43,.203),l(-.219,.188),l(-.719,.22),l(-.991,.033),l(-.308,.11),l(-.48,.405),l(-.462,.203),l(-.946,.033),l(-.854,.622),l(-.24,.279),l(-1.67,.452),l(-.392,.449),l(-1.229,.25),l(-.406,.14),l(-.151,.293),l(.01,.292),l(-.473,.292),l(-.406,.016),l(-.586,-.306),l(-.183,-.262),l(-.169,-.37),l(-.67,-.308),l(-1.074,-.044),l(-1.021,.048),l(-1.159,.172),l(-1.301,.188),l(-.523,.217),l(-1.333,.756),l(-.536,.277),l(-.184,-.138),l(.575,-1.293),l(-.55,.094),l(-.392,-.097),l(-.811,.531),l(-.67,.186),l(-.401,.155),l(-.114,.506),l(-.66,.154),l(-.317,-.168),l(-.253,-.49),l(-.483,-.261),l(-1.024,.636),l(.261,-.204),l(-.557,.062),l(-.283,.092),l(-.628,.522),l(-.141,.261),l(.126,.229),l(.344,.152),l(-.932,.521),l(-.182,.199),l(.342,.167),l(-.647,.352),l(-.88,.55),l(-.626,.503),l(-.298,.35),l(-.01,.531),l(.421,.317),l(.477,.09),l(1.382,-.048),l(.562,.166),l(.11,.167),l(-.436,.394),l(-.752,.455),l(-.181,.302),l(.224,.512),l(.292,.452),l(.786,.089),l(.165,.391),l(-.014,.616),l(-.349,.361),l(-.528,.061),l(-.481,-.209),l(-.017,-.21),l(.388,-.527),l(-.444,-.014),l(-.454,.242),l(-1.014,.843),l(-.56,.675),l(-.237,.599),l(.321,.672),l(.647,.311),l(.154,.237),l(-.294,.387),l(-.688,.313),l(-.956,.031),l(-.664,-.088),l(-.344,.001),l(-.619,.179),l(-.837,.476),l(-.214,.149),l(-.525,.504),l(-.137,.341),l(.111,.281),l(.492,.398),l(.038,.221),l(-.056,.133),l(-.679,.238),l(-.604,.016),L(753.44,82.4),l(-.727,.296),l(-.065,.251),l(.067,.28),l(-.161,.854),l(-.293,.412),l(-.8,.78),l(-1.53,.971),l(-.854,.5),l(-.285,.103),l(-.295,-.614),l(-.198,-.821),l(-.25,-.69),l(-.064,-.794),l(-.351,-.75),l(-.305,-.383),l(-.214,-.915),l(-.514,-1.36),l(-.008,-.578),l(-.154,-.563),l(-.017,-.327),l(-.105,-.193),l(-.262,-.817),l(-.026,-.792),l(.116,-.808),l(.271,-1.396),l(.167,-.226),l(1.185,-.86),l(.716,-.424),l(.57,-.695),l(.14,-.227),l(-.085,-.318),l(-.139,-.166),l(1.632,-.367),l(1.001,-.305),l(.811,-.32),l(1.729,-.884),l(.641,-.412),l(.431,-.428),l(.14,-.335),l(1.784,-.889),l(.872,-.445),l(1.535,-.861),l(.368,-.293),l(.26,-.433),l(1.252,-.435),l(2.106,-.514),l(.257,-.434),l(.773,-.528),l(.086,-.233),l(-.568,-.216),l(.814,-.904),l(-.036,-.483),l(.183,-.391),l(.598,-.204),l(1.729,-.082),l(.513,-.063),l(-.485,-.328),l(-2.065,-.215),l(-.71,.095),l(-1.062,.174),l(-.777,.189),l(.042,.328),l(-.664,.923),l(.125,.202),l(-.04,.14),l(-.662,.11),l(-.479,.11),l(-1.555,.718),l(-1.979,1.042),l(-1.169,.342),l(-.249,-.062),l(.156,-.325),l(.352,-.465),l(-.933,-.076),l(-.16,-.263),l(.252,-.451),l(.442,-.467),l(.207,-.328),l(-.069,-.202),l(-.339,-.031),l(-1.136,.454),l(-.496,.032),l(-.277,-.358),l(-.589,-.17),l(-1.606,.144),l(-1.312,.111),l(-.956,.08),l(-.606,.157),l(-.894,.359),l(-.093,.436),l(.082,.186),l(-1.262,.53),l(-.408,.233),l(.149,.495),l(-1.294,.357),l(-1.019,.434),l(-.84,.479),l(-.496,.461),l(-.332,.46),l(.004,.383),l(.527,.213),l(1.269,.043),l(.278,.275),l(.062,.122),l(-1.152,.139),l(-1.028,.262),l(-1.045,-.059),l(-.698,-.136),l(-.382,.031),l(-.311,.107),l(-.721,.398),l(-.695,-.35),l(-1.112,.383),l(-.747,.139),l(-.487,-.09),l(-.284,-.137),l(.108,-.29),l(.748,-.124),l(.868,-.124),l(.164,-.046),l(-.741,-.64),L(736.444,68),l(-1.06,.017),l(-.854,.155),l(-.353,-.061),l(-.868,-.458),l(-.775,-.029),l(-.745,.047),l(-.704,.246),l(.042,.398),l(-.26,.229),l(-.477,.215),l(-.695,-.243),l(-.408,-.122),l(-1.26,.063),l(-.784,.093),l(-.651,-.075),l(-.887,-.136),l(-.563,.078),l(-.067,.122),l(-.147,.474),l(-.677,.017),l(-.311,-.137),l(-.038,-.382),l(-.203,-.259),l(-1.241,.094),l(-1.014,-.059),l(-1.257,.033),l(-1.158,.063),l(-.836,-.029),l(-.18,.016),l(-1.085,.292),l(-.964,.444),l(-.74,.474),l(-.536,.504),l(-.789,.245),l(-.904,.336),l(-.194,.152),l(-1.047,1.17),l(-1.634,.684),l(-.949,.471),l(-1.157,.711),l(-1.653,1.253),l(-.828,.572),l(-1.573,.873),l(-.893,.376),l(-1.889,.871),l(-.632,.388),l(-.203,.298),l(.018,.357),l(.428,.281),l(.485,.043),l(.918,.013),l(1.046,-.15),l(.656,.043),l(-.329,1.261),l(.016,.415),l(.303,.103),l(.63,-.09),l(.601,-.371),l(.761,.117),l(-.127,.148),L(705.293,81),l(-.112,.222),l(.373,.073),l(1.645,-.018),l(.566,-.238),l(.39,-.519),l(.017,-.638),l(.763,.014),l(.647,-.001),l(.726,.014),l(.951,.265),l(.658,.354),l(.486,.591),l(.847,.575),l(.426,.176),l(.506,.324),l(-.07,.148),l(-.581,.355),l(.453,.221),l(.13,.309),l(-.336,.723),l(.491,.117),l(.215,.235),l(-.291,.515),l(-.348,.397),l(-.532,.559),l(-.724,1.364),l(-.181,.688),l(.057,.219),l(.24,.701),l(-.188,.917),l(-.098,.741),l(-.403,1.408),l(-.146,.493),l(-1.928,1.538),l(-.371,.435),l(-.217,.65),l(-.587,.42),l(-.741,.579),l(-.241,.361),l(-.574,.981),l(-.587,.606),l(-.941,.778),l(-1.784,1.512),l(-.464,.474),l(-.235,.458),l(-.323,.33),l(-.758,.388),l(-.618,.416),l(-.574,.702),l(-.431,.458),l(-.875,.673),l(-.955,.487),l(-1.838,.475),l(-.798,.244),l(-.278,-.427),l(-.519,-.085),l(-.243,.043),l(-.337,-.185),l(-.337,-.513),l(-.663,.272),l(-.464,.101),l(.424,-.586),l(-.624,.173),l(-.506,.486),l(-.649,.543),l(-1.326,1.001),l(-.072,.049),l(-.167,-.393),l(-.298,-.439),l(.111,-.058),l(1.252,-.462),l(.511,-.43),l(.156,-.329),l(-.112,-.299),l(.097,-.128),l(.025,-.385),l(.006,-.613),l(-.062,-.656),l(-.332,-.897),l(.048,-.557),l(1.664,-.982),l(.396,.041),l(.685,.24),l(.679,.225),l(.547,.098),l(.47,-.347),l(.551,-.69),l(.329,-.432),l(.627,-1.08),l(.538,-1.066),l(.278,-.893),l(.291,-.707),l(.66,-.393),l(.566,-.407),l(-.017,-.504),l(-.116,-.389),l(-.064,-.259),l(-.246,-.114),l(-.902,.034),l(-1.181,.208),l(-1.357,.31),l(-.953,.308),l(-.604,.22),l(-1.657,.052),l(-.649,.018),l(-.68,.033),l(-.261,-.446),l(-.44,-1.283),l(-.297,-.866),l(-.205,-.144),l(-2.659,-.839),l(-1.523,-.253),l(-1.247,-.341),l(-.507,-.2),l(-.436,-.389),l(-.927,-1.903),l(-.94,-1.588),l(-1.087,-2.384),l(-.742,-.952),l(-.763,-.467),l(-.539,-.026),l(-1.386,.125),l(-.683,-.188),l(-1.037,-.481),l(-1.148,-.215),l(-.917,.049),l(-1.203,.109),l(-.836,.123),l(-1.854,.143),l(-.602,.136),l(-.478,.165),l(-1.193,.787),l(-.375,.282),l(-.119,.25),l(.822,-.078),l(.558,.026),l(.465,.306),l(.107,.249),l(-.167,.794),l(-1.371,.608),l(-.599,.545),l(-.667,.779),l(-.416,.543),l(-.422,.426),l(-.103,.249),l(.062,.146),l(.35,.348),l(.056,.306),l(-.123,.233),l(-.779,.339),l(-2.44,.752),l(-.438,.089),l(-.343,.016),l(-1.126,-.574),l(-.452,-.172),l(-.046,-.018),l(-.431,-.168),l(-.622,.018),l(-1.228,.297),l(-.86,-.169),l(-.34,-.129),l(-.751,-.506),l(-.74,-.156),l(-.609,.047),l(-.333,.002),l(-1.165,.487),l(-.755,.498),l(-.447,.394),l(-.604,.264),l(-.526,.163),l(-1.147,.136),l(-.867,.106),l(-.532,.075),l(-1.018,.063),l(-1.602,.11),l(-.739,-.039),l(-.984,-.082),l(-.905,-.241),l(-1.318,-.254),l(-.812,-.373),l(-1.132,-.313),l(-.623,-.331),l(-1.333,-.75),l(-.769,-.229),l(-1.423,-.022),l(-1.172,-.037),l(-.796,.077),l(-2.48,.538),l(-.673,-.113),l(-1.643,-.531),l(-.421,-.333),l(-.408,-.451),l(-.182,-.481),l(-.004,-.541),l(-.145,-.204),l(-.767,-.143),l(-.989,-.317),l(-.702,-.231),l(-1.748,-.328),l(-1.036,-.185),l(-1.028,-.098),l(-.84,-.201),l(-1.269,.96),l(-.905,.839),l(-.098,.293),l(.409,.86),l(.396,.304),l(.116,.204),l(-.163,.526),l(-.744,.572),l(-.31,.162),l(-.755,.28),l(-.562,.018),l(-.576,-.186),l(-.312,-.114),l(-.875,-.068),l(-.85,.004),l(-.719,-.083),l(-1.458,.008),l(-.699,-.113),l(-.393,-.406),l(-.694,-.755),l(-.831,-.083),l(-1.842,-.122),l(-.932,-.156),l(-.953,-.097),l(-.84,.18),l(-1.512,.476),l(-1.143,.341),l(-.787,.398),l(-.971,.692),l(-.017,.012),l(-.727,.381),l(-.603,.148),l(-1.387,.08),l(-.599,.207),l(-.799,.425),l(-.154,.044),l(-.244,.074),l(-.569,.003),l(-.228,.014),l(-.064,-.145),l(-.589,0),l(-.294,-.478),l(-.441,-.331),l(.073,-.331),l(-.625,.184),l(-.478,.368),l(-.993,-.074),l(-.882,-.073),l(-.662,-.699),l(-.588,-.552),l(-.956,-.147),l(-.331,-.625),l(-.772,-.588),l(-.698,-.441),l(-.993,.037),l(-.771,.221),l(-.993,.221),l(-.992,0),l(-.589,0),l(-.184,-.184),l(-.258,-.257),l(-.478,0),l(0,-.368),l(-.367,-.331),l(-.92,0),l(-.367,.515),l(-.331,.257),l(-.515,.257),l(-1.104,-1.434),l(-.846,-.882),l(-1.69,-2.133),l(-1.066,-1.029),l(-1.287,-.772),l(-.809,-.294),l(-1.104,-.588),l(.11,-.368),l(.515,-.11),l(0,-.441),l(-.809,.074),l(-.515,.22),l(-.772,.221),l(-.956,.515),l(-1.103,.257),l(-.772,.441),l(-.294,.294),l(-.552,-.184),l(-.441,-.037),l(-.771,.073),l(-.441,.11),l(-.331,-.184),l(.331,-.441),l(.441,-.184),l(.146,-.294),l(-.367,0),l(-.441,.221),l(-.478,-.11),l(-.405,-.294),l(-.478,-.037),l(-.184,.147),l(-.147,.147),l(-.367,-.221),l(-.295,-.368),l(-.294,-.11),l(-.331,.221),l(-.367,-.074),l(-.368,.147),l(-.44,-.11),l(-.295,.147),l(-.478,-.074),l(-.184,-.257),l(.33,-.037),l(-.073,-.331),l(.147,-.257),l(.11,-.331),l(-.515,-.22),l(-.147,-.221),l(.037,-.331),l(-.368,-.404),l(-.882,.037),l(-.625,.11),l(-.772,-.257),l(-.515,-.11),l(-.919,-.147),l(-.735,.037),l(-.11,.221),l(-.589,.184),l(-.515,.037),l(0,.294),l(-.367,.368),l(-.625,.074),l(-1.876,.073),l(-2.021,.405),l(-1.177,.037),l(-.625,.331),l(-.221,.331),l(-.331,-.073),l(-.588,.073),l(-1.545,.11),l(-.735,.11),l(-1.029,.037),l(-1.396,.405),l(-.368,.184),l(-.772,0),l(-.515,0),L(537.304,80),l(-.33,.074),l(-.185,.515),l(.074,.441),l(.294,.221),l(-.294,.074),l(0,.331),l(1.065,.11),l(.956,.294),l(-.11,.257),l(-.515,.073),l(-1.103,-.147),l(-.698,.184),l(-.662,.515),l(.146,.257),l(.441,.478),l(-.331,.294),l(-.588,.147),l(-.735,.368),l(-.467,.067),l(.164,.274),l(.239,0),l(.377,.137),l(-.068,.171),l(.377,.137),l(.651,.069),l(.274,.308),l(1.165,.171),l(.24,.24),l(-.138,.686),l(-.137,.309),l(-1.577,.411),l(-.959,-.034),l(-.343,-.343),l(-.24,0),l(-.171,.309),l(-.651,.343),l(-.411,-.171),l(-.754,-.137),l(-.926,-.309),l(-.274,-.548),l(-.754,-.103),l(-1.062,.103),l(-.137,.412),l(-.617,.068),l(-.651,-.411),l(-.65,-.035),l(-.823,-.068),l(-.514,.377),l(-.377,.343),l(-.274,.274),l(-.686,.171),l(-.411,-.24),l(-.686,-.137),l(-.582,-.548),l(-.72,-.068),l(.034,.24),l(.205,.48),l(-.239,.274),l(-.274,-.137),l(-.068,-.583),l(-.411,-.274),l(-.789,-.343),l(-.582,-.206),l(0,-.343),l(-.96,-.171),l(-.617,.069),l(-.788,-.035),l(-.411,-.514),l(-.411,-.069),l(-.617,.24),l(-.273,.137),l(-.651,.137),l(-.309,-.274),l(-.479,0),l(-.651,-.069),l(-.515,.309),l(-.548,.343),l(-.788,.377),l(-.549,.068),l(-.514,.171),l(-.309,.309),l(-.172,.24),L(509.58,87.5),l(-.479,.206),l(.068,.445),l(.171,.411),l(-.068,.446),l(-.411,.24),l(-.651,0),l(-.514,-.411),l(-.48,-.548),l(-.514,-.24),l(-.411,.069),l(-.103,.308),l(-.343,.549),l(-.823,.137),l(-.205,1.303),l(.343,.171),l(.239,.274),l(-.239,.206),l(-.446,.274),l(-.65,1.165),l(1.37,.343),l(.138,.377),l(-.068,.309),l(.514,.514),l(.103,-.343),l(.583,.206),l(.343,-.034),l(.514,.034),l(.515,.445),l(.479,.206),l(.343,.514),l(.96,1.131),l(-.138,.103),l(-.445,-.103),l(-.309,-.103),l(-.343,.103),l(.068,.308),l(.857,.377),l(.616,.19),l(-.167,.2),l(-.399,.28),l(-.38,.12),l(-.12,0),l(0,.14),l(0,.22),l(-.14,.08),l(-.3,-.2),l(-.34,.2),l(-.399,.26),l(-.64,.12),l(-.319,.08),l(-.26,-.08),l(-.181,-.08),l(-.1,.04),l(-.06,.16),l(.12,.26),l(-.221,.2),l(-.18,.3),l(-.18,.319),l(-.319,.42),l(-.18,.28),l(-.32,.16),l(-.34,.24),l(-.14,.32),l(.08,.2),l(.34,.2),l(.319,.04),l(.18,.3),l(.24,.04),l(.239,.34),l(.28,.419),l(-.06,.38),l(-.101,.2),l(.061,.16),l(.1,-.2),l(.1,-.34),l(.12,-.22),l(.16,-.02),l(-.141,.439),l(-.22,.36),l(.061,.4),l(.12,.1),l(-.16,.2),l(-.04,.4),l(.38,.24),l(.119,.1),l(.12,.52),l(.28,.06),l(.359,.42),l(.2,.28),l(.439,.419),l(.18,.36),l(.359,.06),l(.047,.146),l(-.292,.449),l(-.496,.284),l(-.283,.094),l(-.308,.331),l(-.165,.213),l(-.379,.047),l(-.449,-.142),l(-.591,-.094),l(0,-.308),l(-.283,-.284),l(-.118,0),l(-.095,-.118),l(-.473,-.284),l(-.142,-.189),H(504.5,0),l(-.213,.047),L(504.264,107),l(-.229,.023),l(-.126,-.189),l(-.236,-.071),l(-.236,.023),l(-.284,-.047),l(-.26,-.094),l(-.284,-.166),l(-.354,-.284),l(.118,-.307),l(.118,-.189),l(-.118,-.142),l(-.354,-.024),l(-.378,0),l(-.213,-.166),l(-.189,-.118),l(-.212,0),l(-.143,-.094),l(-.236,-.118),l(-.118,0),l(-.095,.071),l(-.142,.166),l(-.188,-.142),l(-.261,-.071),l(-.354,0),l(-.213,.071),l(-.094,.095),l(-.166,.166),l(-.283,0),l(-.261,.118),l(-.212,-.071),l(-.261,-.118),l(.048,-.118),l(.142,-.118),l(-.308,-.119),l(-.236,-.118),l(-.354,-.071),l(-.52,-.118),l(-.284,-.213),l(-.095,-.142),l(-.354,-.166),l(-.283,.047),l(-.189,0),l(-.401,-.166),l(-.544,0),l(-.426,.095),l(-.307,0),l(-.355,-.047),l(-.307,-.071),l(-.261,-.095),l(-.212,-.166),l(-.213,0),l(-.331,0),l(-.189,-.047),l(-.188,-.094),l(-.284,-.142),l(-.283,-.095),l(-.449,-.023),l(-.402,-.023),l(-.07,-.047),l(-.284,-.047),l(-.26,.166),l(-.112,.309),l(-1.421,-1.012),l(-1.188,-.842),l(-.817,-.385),l(-.62,-.084),l(-.373,-.157),l(-.509,-.5),l(-.236,-.057),l(-.338,.159),l(-.329,-.042),l(-.347,-.515),l(-.795,-.674),l(.595,-.188),l(.519,-.001),l(.445,-.073),l(.1,-.519),l(.359,-.476),L(485,97.85),l(.526,-.03),l(.516,-.131),l(-.432,-.532),l(-.654,-.273),l(-.474,-.36),l(.243,-.116),l(.367,-.03),l(.82,-.117),l(.715,-.348),l(1.244,-.436),l(-.196,-.375),l(-.076,-.058),l(-.799,.088),l(-1.312,.175),l(.012,-.126),l(.021,-.112),l(0,-.224),l(.09,-.514),l(.224,-.089),l(.357,-.022),l(.38,-.134),l(.223,-.179),l(.022,-.179),l(.269,0),l(.736,-.045),l(.805,.157),l(.335,-.134),l(0,-.156),l(.156,-.291),l(.156,-.491),l(-.066,-.067),l(-.09,-.201),l(-.045,-.179),l(-.044,-.134),l(-.179,-.067),l(-.156,-.067),l(.044,-.224),l(.045,-.179),l(.246,0),l(.312,0),l(.134,-.156),l(-.29,-.044),l(-.269,-.089),l(-.223,-.246),l(.312,-.044),l(.357,-.201),l(.156,-.067),l(.201,-.089),l(.045,-.224),l(-.09,-.179),l(-.111,-.089),l(.022,-.179),l(.089,-.111),l(-.156,-.089),l(-.201,.089),l(-.134,.044),l(-.269,0),l(-.357,-.156),l(-.111,-.224),l(-.469,-.022),l(-.291,-.089),l(-.201,-.179),l(-.357,.067),l(-.268,-.112),l(-.469,-.112),l(-.425,-.067),l(-.29,-.268),l(-.224,.067),l(-.045,.157),l(-.29,.134),l(-.224,-.112),l(-.179,-.179),l(-.402,-.044),l(-.022,-.134),l(-.201,-.179),l(0,-.134),l(-.268,-.179),l(-.111,-.156),l(-.357,.067),l(-.536,.134),l(-.269,0),l(-.312,.112),l(-.425,.112),l(-.179,-.156),l(-.179,-.022),l(-.201,.067),l(-.469,-.291),l(-.268,-.067),l(-.47,.067),l(-.268,.179),l(-.291,-.29),l(-.179,-.089),l(-.089,-.224),l(.089,-.179),l(-.089,-.246),l(-.224,-.268),l(0,-.357),l(-.402,0),l(0,-.312),l(-.38,-.022),l(-.514,.067),l(-.156,-.112),l(-.647,0),l(-.269,-.29),l(-.111,-.357),l(-.134,-.291),l(.312,-.134),l(.312,.022),l(0,-.268),l(-.312,-.156),l(-.246,-.156),l(-.134,-.201),l(-.246,-.335),l(-.312,-.134),l(-.201,-.268),l(-.514,.134),l(-.692,-.112),l(-.67,.223),l(-.536,.022),l(-.536,-.246),l(-.134,.268),l(-.179,.291),l(-.313,.156),l(-.469,-.022),l(-.357,-.089),M(527.156,37.071),l(-.59,-.14),l(-.955,-.21),l(-1.128,-.139),l(-.739,.054),l(-.959,.037),l(-.732,.143),l(-.411,-.105),l(-1.025,-.476),l(.737,-.303),l(1.21,-.429),l(.654,-.09),l(1.549,-.002),l(.135,-.357),l(-.728,-.338),l(.351,-.269),l(.419,-.144),l(.676,-.02),l(.852,-.181),l(-.25,-.161),l(-.526,-.233),l(1.539,-.895),l(.513,-.129),l(.226,.073),l(.892,.017),l(.981,-.535),l(.863,-.333),l(1.02,-.261),l(.975,-.15),l(1.305,-.113),l(1.274,.053),l(.738,-.15),l(.786,-.615),l(.273,.018),l(.873,-.132),l(1.722,.276),l(.471,-.038),l(1.93,-.321),l(.958,-.039),l(2.184,-.247),l(1.864,-.116),l(.771,-.564),l(.376,-.152),l(2.511,-.137),l(1.965,-.079),l(.471,.131),l(.442,.225),l(.154,.357),l(-.812,.47),l(-.541,.169),l(-1.346,.319),l(-2.609,.433),l(-4.329,.49),l(-2.187,.281),l(-2.122,.299),l(-1.842,.316),l(-2.102,.242),l(-.941,.203),l(-.288,.274),l(.644,.216),l(-.422,.217),l(-.943,.361),l(-.527,.037),l(-2.047,-.068),l(-.432,.18),l(-.119,.233),l(.621,.249),l(-.331,.233),l(-1.206,.448),l(-.402,-.142),l(-.752,-.087),l(-.592,.304),l(.877,.283),l(.052,.319),l(-1.094,.657),l(-.822,.284),M(517.491,38.443),l(1.041,-.37),l(.512,-.299),l(.428,-.212),l(1.426,-.021),l(1.316,-.249),l(.987,-.02),l(1.412,-.091),l(.551,.069),l(.988,.227),l(-.063,.176),l(-.463,.528),l(-.302,.158),l(-.697,.071),l(-.443,.228),l(-.233,.385),l(.006,.818),l(.445,1.039),l(.957,.826),l(.505,.308),l(.775,.307),l(1.162,.392),l(-.028,.282),l(-2.62,-.089),l(-.844,.053),l(-.917,.326),l(-.596,.086),l(-.676,-.494),l(-.382,-.034),l(-1.091,.088),l(-.673,-.102),l(-.031,-.359),l(1.347,-.362),l(.073,-.24),l(-.102,-.017),l(-.944,-.273),l(-1.442,-.411),l(-1.519,-.17),l(-.33,.156),l(-.624,.122),l(-.681,-.033),l(-.625,-.396),l(-.114,-.415),l(.229,-.312),l(.39,-.209),l(.344,-.036),l(.318,.104),l(.65,.016),l(.518,-.192),l(1.121,-.768),l(.243,-.35),l(-.322,0),l(-.981,-.243),M(.125,56.089),l(0,-.562),l(0,-.576),l(0,-.157),l(0,-1.292),V(0,51.28),l(0,-2.222),l(0,-2.12),l(2.917,.61),l(1.693,.598),l(.933,.181),l(3.819,.99),l(1.059,.395),l(.204,.149),l(.074,.214),l(.445,.429),l(.406,.789),l(-.209,.428),l(1.034,.8),l(.982,.26),l(-.02,-.18),l(.297,-.148),l(-.051,-.196),l(-.638,-.392),l(.016,-.542),l(.077,-.296),l(1.026,-.183),l(.984,.278),l(.573,.098),l(.767,.064),l(1.003,-.117),l(.933,.13),l(.93,.425),l(.694,.359),l(1.676,.684),l(.32,.081),l(.584,.179),l(.43,.211),l(.09,.13),l(-.343,.033),l(-1.026,-.096),l(-.364,.034),l(-.808,.798),l(-1.539,-.468),l(.138,.178),l(.438,.227),l(.465,.324),l(-1.177,-.111),l(-1.008,.05),l(-1.202,-.387),l(-.708,-.096),l(.135,.129),l(.289,.259),l(.084,0),l(.561,.259),l(.205,.307),l(.131,.453),l(-.056,.339),l(-.814,.05),l(-.805,.065),l(-.189,.161),l(.5,.865),l(-.115,.272),l(-1.04,-.078),l(-.397,.081),l(-1.193,-.174),l(-.264,-.352),l(-1.795,-.51),l(-.253,.273),L(9.85,55.79),l(-.276,-.161),l(-.265,-.403),l(.174,-.178),l(-.321,-.42),l(-.87,-.339),l(-.565,-.063),l(-.762,.034),l(-.858,.229),l(-1.343,.084),L(3.57,54.443),l(.059,-.325),l(-.155,-.325),l(-.618,-.487),L(1.958,53.43),l(-.45,.409),l(-.655,1.228),l(-.166,.715),l(-.562,.307), +N(449.401,22.792),l(-1.596,-.014),l(-2.019,-.016),l(-1.739,.063),l(-.764,.061),l(-1.972,-.316),l(.812,-.456),l(.826,-.172),l(.735,-.453),l(1.148,-.588),l(1.354,.691),l(.998,.105),l(1.116,-.088),l(.9,.084),l(.704,.341),l(.865,-.323),l(.53,-.454),l(.868,-.306),l(-.311,.823),l(.086,.32),l(.851,-.001),l(.991,-.495),l(1.061,-.261),l(.803,.128),l(.559,.472),l(.705,.041),l(2.007,-.111),l(1.543,.189),l(.551,.376),l(-.507,.201),l(-2.004,.622),l(-1.623,.38),l(-1.069,.062),l(-.976,.14),l(-1.324,.366),l(-6.271,-.097),l(-.033,-.377),l(1.492,-.26),l(.702,-.677),M(430.027,22.752),l(.068,.697),l(.252,.119),l(1.694,.155),l(.221,-.377),l(.13,-.418),l(.573,-.141),l(.523,-.041),l(.949,.477),l(1.192,.771),l(.798,.235),l(.568,-.218),l(-.222,-.296),l(-.46,-.356),l(-.327,-.477),l(-.04,-.22),l(.91,-.407),l(1.001,.103),l(.485,.18),l(1.278,.018),l(.586,.179),l(-.08,.419),l(-.169,.298),l(.104,.159),l(.549,.118),l(.743,-.338),l(.44,-.1),l(.662,.396),l(.678,.335),l(.785,.156),l(.948,.117),l(1.672,.429),l(.498,.234),l(-1.305,.277),l(-1.981,.218),l(-.696,.293),l(-.731,1.144),l(-.885,.885),l(-1.243,.117),l(-.766,.535),l(-.455,.589),l(-.029,.378),l(-.786,.209),l(-.556,-.018),l(-1.593,-.355),l(-1.883,-.507),l(-1.365,-.568),l(.651,-.364),l(1.565,-.041),l(1.788,-.137),l(.944,-.386),l(-.652,-.249),l(-1.822,.139),l(-1.566,.118),l(-1.694,.042),l(-.502,-.519),l(.959,-.06),l(1.371,-.215),l(2.149,-.314),l(1.547,-.45),l(-2.525,-.405),l(-.881,-.292),l(-.589,.138),l(-1.036,.646),l(-1.069,.293),l(-.562,.059),l(-1.236,-.172),l(-.338,-.174),l(-1.05,-.368),l(-.807,-.233),l(-.698,-.41),l(1.698,-.396),l(-.817,-.571),l(-1.359,.319),l(-.467,-.078),l(-.924,-.751),l(.812,-.36),l(.516,-.021),l(1.075,-.122),l(1.017,.038),l(.577,-.061),l(1.188,-.042),M(425.42,68.82),l(-.148,-.21),l(-.629,.132),l(-.134,-.026),l(-.249,-.237),l(-.239,-.343),l(.188,-.158),l(-.143,-.291),l(-.361,.185),l(-.062,.29),l(.113,.237),l(-.147,.105),l(-.339,.316),l(-.086,.185),l(-.521,.105),l(-.533,-.131),l(-.781,.342),l(.057,.131),l(-.502,.289),l(-.498,.263),l(-1.658,.813),L(418.697,71),l(-.274,.052),l(-.271,0),l(-2.111,.209),l(-.188,-.236),l(-.33,-.131),l(-.183,.209),L(414.976,71),l(.384,-.184),l(-.935,-.236),l(-.794,-.341),l(-.574,-.052),l(-.479,-.578),l(.292,-.368),l(-.126,-.21),l(.34,.026),l(.085,.316),l(.284,-.21),l(.667,.263),l(-.244,-.197),l(.127,-.145),l(.5,-.092),l(-.479,.026),l(-.245,.105),l(-.263,-.184),l(-.111,-.132),l(.579,-.276),l(.455,-.185),l(-.482,.066),l(-.317,-.132),l(.441,-.237),l(.083,-.237),l(-.661,.475),l(-.036,-.264),l(-.265,-.171),l(.005,.211),l(.076,.171),l(-.419,.158),l(-.41,0),l(.014,-.277),l(-.15,.264),l(-.235,-.079),l(-.2,-.448),l(.658,-.449),l(.08,.436),l(.068,-.317),l(.438,.158),l(.211,-.092),l(-.166,-.106),l(.674,-.079),l(.479,-.251),l(-.611,.159),l(-.48,0),l(-.335,-.159),l(.196,-.132),l(.387,-.146),l(.196,-.471),l(-.821,-.014),l(-.546,.094),l(-.406,-.309),l(.368,-.14),l(.643,-.404),l(-.212,-.186),l(-.445,.063),l(-.399,-.062),l(-.211,-.217),l(.284,-.482),l(.619,-.265),l(-.595,-.248),l(-.225,-.374),l(.272,-.188),l(-.089,-.687),l(.106,-.094),l(.594,-.063),l(.392,-.045),l(.455,.044),l(.082,-.11),l(-.255,-.134),l(-.425,-.118),l(-.228,-.17),l(.098,-.188),l(.211,-.125),l(.575,-.064),l(.511,-.346),l(.567,.109),l(.498,-.111),l(.179,-.55),l(.835,.093),l(.668,.125),l(.571,-.252),l(-.989,-.234),l(-.266,-.314),l(.236,-.143),l(1.151,.014),l(.851,-.08),l(.538,.219),l(.06,-.473),l(.477,-.27),l(.297,-.333),l(.78,-.175),l(.438,.189),l(.138,.079),l(.5,-.476),l(.869,-.413),l(.084,-.429),l(.437,-.398),l(1.497,-.735),l(.335,-.192),l(.235,-.048),l(.481,.175),l(.335,-.001),l(.319,-.224),l(-.225,-.223),l(.141,-.128),l(.488,-.224),l(.457,-.305),l(.481,-.483),l(.245,.064),l(.676,-.017),l(-.067,-.612),l(-.471,-.112),l(.434,-.405),l(.511,-.648),l(.841,.063),l(.047,-.341),l(.096,-.228),l(.954,-.116),l(-.396,-.357),l(-.327,-.097),l(-.193,-.146),l(.164,-.245),l(.313,-.246),l(.464,.048),l(.888,-.067),l(-.543,-.522),l(.249,-.082),l(.435,-.034),l(.707,-.263),l(.592,-.067),l(.308,-.208),l(-.358,-.064),l(-.105,-.187),l(.289,-.1),l(.616,-.33),l(.557,.032),l(.351,.098),l(.434,-.264),l(.369,-.031),l(.035,-.176),l(-.421,-.321),l(.627,-.232),l(.146,-.275),l(.336,.01),l(.359,.297),l(.397,.082),l(.526,-.381),l(-.281,-.656),l(.438,.065),l(.698,-.058),l(.207,-.174),l(-.604,-.315),l(.411,-.224),l(.816,-.251),l(.093,-.257),l(.261,-.194),l(.73,-.135),l(.074,.067),l(.274,-.051),l(.102,-.067),l(.492,-.67),l(.521,.25),l(.96,-.153),l(.411,.133),l(.265,.1),l(.646,.065),l(.536,-.419),l(.747,-.84),l(.286,-.085),l(.16,.168),l(-.178,.286),l(-.182,.587),l(.791,-.454),l(.403,-.572),l(.819,-.085),l(.688,-.439),l(.437,.117),l(.665,.353),l(.567,-.643),l(.318,-.272),l(.976,.1),l(1.019,.506),l(.197,-.152),l(.479,-.595),l(.709,-.444),l(.283,-.052),l(.562,.067),l(.338,-.308),l(.469,-.291),l(.619,-.189),l(1.2,-.173),l(.984,.015),l(-1.337,.755),l(-.24,.273),l(-.107,.646),l(.42,.084),l(.691,-.579),l(1.53,-.941),l(.764,-.275),l(.028,.257),l(-.004,.905),l(.704,-.172),l(.438,-.239),l(.855,-.874),l(.959,-.104),l(.586,-.001),l(.216,.154),l(-.383,.257),l(-.335,.257),l(.074,.239),l(-.319,.41),l(.921,.118),l(.221,-.443),l(.902,-.651),l(.421,.017),l(1.682,.561),l(.667,.135),l(.935,.015),l(.649,.237),l(.1,.272),l(-1.216,.393),l(-1.148,.036),l(-2.233,-.047),l(.193,.084),l(.585,.304),l(1.058,.284),l(.383,.302),l(.728,-.052),l(.679,-.102),l(.831,.032),l(.708,.25),l(-.404,.288),l(-.514,.204),l(-.824,.021),l(-.77,.121),l(-1.023,.49),l(-1.013,.672),l(-.689,.303),l(-.001,-.2),l(.096,-.367),l(.874,-.923),l(-.044,-.268),l(-.88,-.348),l(-.672,-.114),l(-1.125,-.431),l(-.556,.003),l(-.555,.07),l(-2.004,.095),l(-.865,.374),l(-.567,.422),l(-.26,.437),l(-.079,.501),l(-.188,.5),l(-1.25,.472),l(-.582,.368),l(-.31,-.148),l(-1.288,-.492),l(-1.657,.225),l(-1.411,-.042),l(-.536,-.13),l(-.861,-.595),l(-.994,-.612),l(-.486,-.082),l(-.355,.103),l(-1.012,.656),l(-.114,-.063),l(-.41,-.031),l(-.865,.038),l(-.281,1.066),l(-.164,.449),l(-.271,.25),l(-.323,-.015),l(-.67,-.129),l(-.972,-.144),l(-1.731,-.389),l(-.168,.183),l(-.021,.663),l(-.083,.199),l(-.318,.299),l(-.695,.004),l(-.871,-.095),l(-.279,-.015),l(-.465,.167),l(-1.484,1.176),l(.05,.213),l(.171,.507),l(-.188,.345),l(-.615,.346),l(-1.325,.919),l(-.687,.442),l(-.981,.021),l(-.121,.244),l(-.06,.971),l(-.32,.598),l(-.383,.469),l(-.574,.499),l(-.495,.545),l(.339,.125),l(.381,.269),l(.252,.587),l(-.17,.176),l(-.44,.177),l(-.733,.036),l(-.932,-.027),l(-.618,.114),l(-.613,.257),l(-.617,.479),l(-.389,.492),l(-.077,.664),l(-.349,1.093),l(.65,.729),l(-.335,1.171),l(.582,.39),l(.715,.186),l(.297,.243),l(-.432,.67),l(-.941,.16),l(.571,.735),l(.26,.427),l(-.249,.346),l(-.029,.532),l(-.769,.384),l(-.414,.013),l(-.117,.423),l(-.506,.224),l(.22,.831),l(-.324,.737),l(-.41,.013),l(-.15,-.342),l(-.293,-.132), +N(464.349,47.431),l(-.024,.283),l(-.258,.465),l(.116,.529),l(.563,.212),l(.872,.194),l(.964,.506),l(.543,.392),l(-.421,.364),l(-1.303,.777),l(-.328,.296),l(1.402,1.394),l(.772,1.195),l(-.196,.356),l(-.44,.535),l(-.187,.403),l(-.029,.37),l(.37,.509),l(1.286,1.395),l(.151,.253),l(-.057,.254),l(-.542,.415),l(-.327,.191),l(.439,.33),l(1.357,.499),l(.703,.265),l(.436,.392),l(.161,.346),l(-.105,.409),l(-.43,.536),l(-.591,.536),l(-1.385,.758),l(-1.983,1.195),l(-1.946,1.145),l(-.174,.285),l(-.935,.206),l(-1.195,.188),l(-.149,.181),l(-.506,-.217),l(-.518,.146),l(-.052,.134),l(-.688,-.07),l(-.193,-.108),l(.057,-.387),l(-.241,.527),l(-.268,.14),l(-.633,.047),l(-.328,.03),l(-.1,.267),l(-.589,-.326),l(-.29,.275),l(-.676,.064),l(-.34,.178),l(-.052,-.127),l(-.504,.108),l(-.504,.108),l(-.211,.266),l(-.311,-.152),l(-.672,.126),l(-.04,-.114),l(-.658,.215),l(-.547,.013),l(-.482,.025),l(-.487,-.253),l(-.223,-.274),l(.273,-.34),l(-.846,.017),l(-.517,.177),l(.065,-.382),l(-.446,.076),l(-.644,-.271),l(-.409,-.061),l(-.415,-.231),l(-.26,-.403),l(-.036,-.714),l(.158,-.374),l(.05,-.436),l(.09,-.234),l(-.347,-.483),l(-.431,-.375),l(.3,-.658),l(-.02,-.392),l(-.305,-.204),l(-.37,-.093),l(.062,-.299),l(.295,-.331),l(.637,-.285),l(.144,-.189),l(-.113,-.331),l(.382,-.143),l(.633,.125),l(.274,.063),l(.483,-.222),l(.303,-.427),l(.104,-.459),l(.207,-.27),l(.301,.316),l(.27,0),l(1.678,-1.114),l(1.142,-.654),l(.835,-.576),l(1.026,-.401),l(.874,.03),l(.06,-.304),l(-.13,-.144),l(-.357,-.16),l(.119,-.371),l(.146,-.387),l(-.329,-.274),l(-1.139,-.095),l(-.836,-.451),l(-.594,-.024),l(-.113,-.234),l(-.327,-.307),l(-.208,-.535),l(.5,-.8),l(-.028,-.392),l(-.405,-.685),l(-.507,-.637),l(.004,-.526),l(.062,-.413),l(-.77,-.558),l(-.508,-.229),l(-1.583,-.207),l(-1.085,-.292),l(-1.286,-.658),l(-.616,-.463),l(-.146,-.033),l(1.012,-.656),l(.355,-.103),l(.486,.082),l(.994,.612),l(.861,.595),l(.536,.13),l(1.411,.042),l(1.657,-.225),l(1.288,.492),l(.31,.148),l(.582,-.368),l(1.25,-.472),l(.188,-.5),l(.079,-.501),l(.26,-.437),l(.567,-.422),l(.865,-.374),l(2.004,-.095),l(.555,-.07),l(.556,-.003),l(1.125,.431),l(.672,.114),l(.88,.348),l(.044,.268),l(-.874,.923),l(-.096,.367),l(.001,.2), +N(453.795,53.873),l(-.23,-.004),l(-.975,.164),l(-.447,.098),l(-.902,-.387),l(-.339,-.178),l(-.347,.114),l(-.641,.374),l(-.542,.599),l(-.309,.146),l(-.658,.018),l(-.545,.355),l(.325,.241),l(.146,.192),l(-.355,.273),l(-.907,.401),l(.317,.271),l(.385,.159),l(.33,.302),l(-.749,.367),l(-.405,.43),l(-.368,.461),l(-1.591,.669),l(-.699,.286),l(-.456,-.205),l(-.326,.08),l(-.538,.539),l(-.646,.144),l(-.663,.348),l(-.217,.284),l(-.191,.142),l(-.746,.033),l(-.221,-.031),l(.151,.535),l(-.484,.425),L(439,61.33),l(.216,.533),l(.243,.25),l(-.244,.955),l(-.498,.063),l(-.217,.204),l(.189,.757),l(-.009,.544),l(.381,.444),l(-.287,.175),l(.926,.082),l(.225,.187),l(.499,-.082),l(.652,.594),l(.428,.314),l(.86,.163),l(.198,.406),l(.32,.139),l(.014,.335),l(-.391,0),l(-.508,.323),l(-.861,.3),l(-.492,.162),l(-.521,-.012),l(-.146,-.115),l(-.805,-.115),l(-.66,-.173),l(-.634,-.069),l(-.137,.104),l(-.446,-.115),l(-.257,.3),l(.819,-.069),l(.497,.265),l(.591,.046),l(.205,.208),l(.481,.069),l(.021,-.127),l(.616,.069),l(.258,-.196),l(.297,.011),l(.481,-.104),l(.226,.081),l(.026,-.15),l(.164,0),l(.214,.15),l(-.029,.081),l(-.722,.023),l(.219,.288),l(-.792,.265),l(-.168,.288),l(-.386,.08),l(-.089,-.092),l(.042,-.161),l(-.014,-.276),l(-.258,.023),l(-.091,.46),l(-.501,.333),l(-.248,.058),l(-.36,-.069),l(-.005,.218),l(-1.418,.035),l(.156,.458),l(.513,.258),l(.066,.609),l(-.109,.33),l(-.281,.051),l(-.308,-.064),l(.038,.429),l(.29,.081),l(-.126,.268),l(.24,.228),l(-.365,.364),l(-.222,.455),l(-.041,.56),l(-.766,1.043),l(-.58,.71),l(-.165,-.062),l(-.442,-.236),l(-.614,.193),l(-1.262,-.089),l(-.106,.311),l(-.252,-.083),l(-.518,.264),l(-.295,.517),l(.356,.336),l(-.376,.374),l(-.48,-.129),l(-.173,-.037),l(-1.158,.269),l(-1.11,-.116),l(-.001,-.142),l(.19,-.078),l(-.062,-.181),l(.281,-.297),l(-.638,-.53),l(-.413,-.479),l(-.22,-.272),l(.529,-.116),l(-.082,-.312),l(.421,.077),l(.147,-.245),l(-.19,-.234),l(-.285,.013),l(-.292,-.377),l(-.527,-.221),l(-.63,-.99),l(-.286,0),l(.011,-.408),l(-.256,-.364),l(-.348,-.298),l(.221,-.484),l(.206,-.341),l(-.418,-.154),l(-.405,.102),l(-.055,-.288),l(-.412,.051),l(-.18,-1.207),l(-.225,-.131),l(.311,-.355),l(.293,.132),l(.15,.342),l(.41,-.013),l(.324,-.737),l(-.22,-.831),l(.506,-.224),l(.117,-.423),l(.414,-.013),l(.769,-.384),l(.029,-.532),l(.249,-.346),l(-.26,-.427),l(-.571,-.735),l(.941,-.16),l(.432,-.67),l(-.297,-.243),l(-.715,-.186),l(-.582,-.39),l(.335,-1.171),l(-.65,-.729),l(.349,-1.093),l(.077,-.664),l(.389,-.492),l(.617,-.479),l(.613,-.257),l(.618,-.114),l(.932,.027),l(.733,-.036),l(.44,-.177),l(.17,-.176),l(-.252,-.587),l(-.381,-.269),l(-.339,-.125),l(.495,-.545),l(.574,-.499),l(.383,-.469),l(.32,-.598),l(.06,-.971),l(.121,-.244),l(.981,-.021),l(.687,-.442),l(1.325,-.919),l(.615,-.346),l(.188,-.345),l(-.171,-.507),l(-.05,-.213),l(1.484,-1.176),l(.465,-.167),l(.279,.015),l(.871,.095),l(.695,-.004),l(.318,-.299),l(.083,-.199),l(.021,-.663),l(.168,-.183),l(1.731,.389),l(.972,.144),l(.67,.129),l(.323,.015),l(.271,-.25),l(.164,-.449),l(.281,-1.066),l(.865,-.038),l(.41,.031),l(.114,.063),l(.146,.033),l(.616,.463),l(1.286,.658),l(1.085,.292),l(1.583,.207),l(.508,.229),l(.77,.558),l(-.062,.413),l(-.004,.526),l(.507,.637),l(.405,.685),l(.028,.392),l(-.5,.8),l(.208,.535),l(.327,.307),l(.113,.234), +N(238.107,361.753),l(.515,-.688),l(.859,0),l(1.202,-.515),l(-.171,-.858),l(-3.091,.344),l(-2.061,.515),l(-1.545,-.344),l(-.515,-.858),l(1.374,-.515),l(1.202,-.172),l(3.091,-.172),l(1.374,-.515),l(-.172,-1.03),l(.859,-.516),l(0,-1.374),l(-1.326,-1.054),l(.982,-.491),l(1.202,-.344),l(1.545,-.172),l(.858,.344),l(.858,.858),l(1.03,1.374),l(1.374,1.202),l(1.03,1.373),l(-.515,2.061),l(-1.545,.516),l(-1.545,.858),l(-3.434,.172),l(-3.435,0),M(172.686,360.379),l(3.091,-.687),l(3.262,0),l(5.495,0),l(2.919,1.202),l(-2.748,.687),l(-3.759,-.337),l(-5.169,-.35),l(-3.091,-.516),M(65.13,371.085),l(1.194,-.265),l(1.393,.133),l(.796,.464),l(-1.99,0),l(-1.393,-.332),M(277.944,379.954),l(.515,-1.202),l(2.404,-1.03),l(2.748,-.172),l(2.061,-.171),l(1.545,-.859),l(.343,-1.545),l(1.374,-.687),l(3.091,-.688),l(4.464,0),l(2.404,0),l(3.434,.688),l(.687,1.889),l(0,1.202),l(-2.061,1.201),l(-11.848,1.03),l(-11.161,.344),M(36.004,376.434),l(1.202,-.858),l(2.061,-.343),l(4.121,.515),l(4.293,1.374),l(-.887,.482),l(-2.719,.204),l(-4.293,-.515),l(-3.777,-.859),M(777.843,385.46),l(3.823,.391),l(.899,.029),l(.322,.234),l(1.202,.294),l(2.329,.088),l(2.126,-.003),l(5.218,.329),l(3.046,.348),l(1.144,-.059),l(.762,.029),l(1.411,.37),l(0,2.175),l(0,2.223),l(0,2.222),l(0,2.223),l(0,2.222),l(0,1.551),l(-.041,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.182,0),l(-.041,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.223,0),l(-2.182,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.223,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),l(-2.222,0),H(9.014,0),H(6.792,0),H(4.569,0),H(2.347,0),H(.125,0),l(0,-1.544),l(0,-2.222),l(0,-2.223),l(0,-2.222),l(0,-2.223),l(0,-2.223),l(3.941,.297),l(10.131,0),l(7.898,.516),l(6.868,.172),l(8.586,.858),l(6.353,.515),l(8.757,.172),l(4.808,-.172),l(6.525,-.172),l(2.404,.344),l(3.606,-.858),l(16.312,.344),l(4.638,-.013),l(1.143,-.467),l(-14.366,-.551),l(-9.616,-.688),l(-2.232,0),l(-3.091,-.172),l(-.858,-.171),l(-1.545,-.344),l(-.498,-.455),l(.155,-1.434),l(.687,-.858),l(1.889,-.688),l(-3.263,-.687),l(-2.232,-.344),l(-.953,-.503),l(1.589,-.521),l(-2.891,-.6),l(-3.074,-.208),l(-.104,-.261),l(2.857,-.312),l(2.748,0),l(6.525,.343),l(3.434,0),l(2.576,.344),l(4.636,-1.202),l(2.404,-.687),l(-2.748,-1.03),l(-3.778,-.858),l(-4.391,-.405),l(-2.649,-.625),l(-3.262,-.172),l(-2.919,0),l(-2.919,-.858),l(2.576,-.516),l(1.28,-.342),l(-1.28,-.517),l(-2.919,.516),H(52.66,0),l(-1.717,-.344),L(49.054,373),l(.343,-1.202),l(1.956,-.07),l(1.65,-.273),l(4.98,0),l(4.626,.493),l(3.272,.709),l(1.374,.172),l(4.465,-.858),l(4.089,.243),l(0,-.729),l(.066,-.597),l(-2.255,-.73),l(-2.93,-.075),l(-2.576,-.344),l(2.404,-.687),l(4.121,.171),l(1.717,-.343),l(3.091,-.516),l(3.09,-.343),l(5.667,-.688),l(4.465,-.343),l(3.949,-.516),l(4.464,-.515),l(2.748,.343),l(5.667,0),l(4.464,.258),l(4.121,-.515),l(7.898,.343),l(7.555,-.687),l(3.091,.172),l(1.545,-.688),l(1.545,.516),l(5.323,-.172),l(.121,-.87),l(1.758,-.293),l(1.433,.325),l(.586,.554),l(-.423,.813),l(2.364,.329),l(1.38,-.264),l(-.006,-.938),l(1.438,-.267),l(1.48,.267),l(.212,1.036),l(-1.009,.423),l(.521,.781),l(3.024,-.351),l(1.889,.343),l(3.434,.172),l(2.576,-.687),l(3.778,.086),l(4.868,.33),l(2.344,.013),l(1.449,.109),l(.693,-.53),l(-.611,-.285),l(-2.202,-.122),l(1.305,-.285),l(.041,-.408),l(-.367,-.245),l(-1.386,.123),l(-.693,.04),l(-.856,-.979),l(-2.178,-.337),l(-.676,-.193),l(-.182,-.665),l(4.056,.462),l(3.874,-.245),l(-1.224,-.489),l(-6.035,-.163),l(-.774,-.082),l(-.653,-.489),l(0,-.815),l(2.301,.105),l(.839,.67),l(5.301,-.204),l(7.253,.736),l(2.404,-.172),l(3.262,-.172),l(4.464,.172),l(3.263,.172),l(2.061,-.516),l(.687,-.687),l(1.202,0),l(.344,1.03),l(2.576,.343),l(2.404,-.343),l(.858,.515),l(3.435,.688),l(3.777,.343),l(2.061,.172),l(1.03,-.515),l(.687,-1.202),l(2.747,-.172),l(1.03,.515),l(1.717,.688),l(3.091,-.172),l(3.434,.258),l(4.121,-.344),l(4.979,-.516),l(5.495,-.858),l(3.091,-.515),l(1.202,-.688),l(0,-1.373),l(-1.374,-1.202),l(-.859,-1.545),l(-1.202,-.688),l(-.344,-1.03),l(1.202,-1.03),l(1.717,-.343),l(.858,-1.202),l(-.343,-.858),l(-.172,-1.03),l(-1.202,-.516),l(.344,-1.545),l(1.889,-.172),l(2.404,-1.374),l(1.545,-.515),l(.859,-.859),l(1.03,-.687),l(2.919,-1.202),l(3.606,-.515),l(2.404,-1.202),l(2.404,-.172),l(2.232,-1.03),l(1.545,-.343),l(.343,1.03),l(-1.374,.515),l(-1.03,.344),l(-1.202,.515),l(-.858,0),l(-1.202,0),l(-2.919,1.202),l(-1.03,.687),l(-1.717,1.374),l(-.172,1.202),l(-.687,.687),l(-1.374,-.344),l(-1.03,0),l(-1.202,.516),l(-1.202,.687),l(-1.03,.688),l(-.687,1.201),l(.515,.688),l(.687,.687),l(1.374,.344),l(1.545,0),l(.858,.515),l(.687,1.202),l(1.545,1.546),l(.687,.858),l(1.03,.687),l(.687,1.374),l(.858,1.373),l(.344,1.546),l(-.344,.858),l(-.858,1.717),l(-2.919,1.889),l(-1.202,.172),l(-1.03,.858),l(-1.717,1.03),l(-3.263,.344),l(-4.979,.858),l(-2.404,.344),l(-2.919,.687),l(-7.377,-.141),l(-4.556,-.316),l(-.773,-.401),l(-1.717,-.344),l(-1.717,-.343),l(-1.374,0),l(-.859,.515),l(.515,.858),l(2.061,.688),l(4.121,1.202),l(4.995,.04),l(1.202,.759),l(-3.278,.574),l(-5.667,-.343),l(-4.979,-.516),l(-3.097,-.285),l(-2.151,.253),l(.823,.696),l(1.164,.538),l(3.262,.172),l(2.232,0),l(1.374,.343),l(-.249,.402),l(-.782,.113),l(-2.232,.515),l(-5.151,-.171),l(-1.374,-.172),l(-2.232,-1.202),l(-2.404,0),l(.128,.917),l(2.62,1.144),l(1.03,.172),l(1.202,-.172),l(1.374,.344),l(2.404,0),l(4.98,-.516),l(3.09,.687),l(.385,.431),l(-.041,.6),l(-2.061,.172),l(-3.263,.172),l(-2.608,-.185),l(3.811,.871),l(3.656,-.238),l(1.324,.41),l(2.576,.687),l(6.869,.859),l(8.585,.858),l(10.646,1.373),l(6.525,.516),l(2.061,.858),l(.687,1.03),l(3.091,-.344),l(5.323,-1.545),l(6.525,-.687),l(2.455,-.066),l(6.474,-.105),l(9.788,-.344),l(1.889,.344),l(2.576,-1.202),l(8.414,-1.03),l(11.333,-.172),l(8.929,-.858),l(1.202,-.858),l(-1.202,-.516),l(-.271,-1.07),l(-1.184,-.338),l(-5.071,.035),l(-2.232,.172),l(-4.808,-.344),l(-3.091,0),l(0,-1.202),l(3.263,-1.545),l(3.949,-1.202),l(2.404,-.172),l(4.121,-1.03),l(9.444,-1.202),l(5.323,-.858),l(6.525,0),l(4.979,-.516),l(2.747,-2.061),l(6.039,-1.541),l(-1.23,-.52),l(-2.576,.516),l(-2.061,-.344),l(1.545,-1.03),l(1.545,-.343),l(2.48,-.249),l(.696,-.742),l(3.85,-.742),l(1.577,-.418),l(.603,-.557),l(-1.716,-.881),l(-.093,-.604),l(1.252,-.231),l(.464,.742),l(1.017,-.097),l(2.061,-.858),l(1.03,-.343),l(.858,.171),l(1.203,1.544),l(2.403,-.342),l(.242,-.91),l(.96,-.807),l(1.889,-.516),l(1.374,.516),l(-1.162,.574),l(-.139,.604),l(3.189,-.319),l(4.808,.258),l(3.263,-.172),l(1.03,.858),l(1.545,-.344),l(1.717,-.515),l(5.839,-.858),l(7.212,-1.03),l(4.292,-.858),l(2.061,0),l(2.061,1.373),l(1.718,.344),l(1.889,-.344),l(1.545,-.858),l(7.556,-.344),l(3.434,-.171),l(4.293,.171),l(6.697,.945),l(2.575,0),l(4.293,-.516),l(6.01,-.687),l(5.151,-.688),l(2.404,-.515),l(2.231,-.344),l(.615,-.959),l(1.148,-.835),l(1.671,-.095),l(.938,.965),l(1.294,.409),l(1.732,1.052),l(1.009,.139),l(1.009,-.661),l(1.322,-.174),l(.209,.522),l(-.835,.312),l(.661,.244),l(.8,.278),l(.383,-.383),l(.313,-.383),l(.312,.209),l(-.174,.348),l(0,.521),l(.592,-.174),l(1.913,-.557),l(.418,-1.704),l(5.102,-1.137),l(1.374,-.687),l(3.605,-.172),l(1.363,-.646),l(2.758,-.126),l(.21,-.27),l(-.165,-.297),l(.692,-.23),l(1.221,.165),l(.197,.593),l(.66,.231),l(2.165,-.536),l(1.265,-.223),l(-.726,-.297),l(-.561,-.264),l(.099,-.362),l(1.451,-.1),l(1.562,.215),l(.647,.28),l(.692,-.132),l(-.066,-.33),l(-.527,-.33),l(0,-.561),l(.297,-.23),l(.846,-.242),l(4.292,-.858),l(2.92,-.172),l(3.058,.115),l(2.296,1.076),l(1.316,.023),l(.741,.144),l(.023,.383),l(-.908,.096),l(-.168,.454),l(1.723,.216),l(4.892,.646),l(5.571,.453),l(1.546,.172),l(1.717,-.172),l(7.556,.688),l(5.323,0),l(.687,.687),l(.2,1.075),l(-.73,1.232),l(-.672,.439),l(-.425,1.113),l(-.73,.319),l(-.905,-.402),l(-.83,.402),l(-.73,.959),l(1.507,.457),l(.594,.045),l(.959,-.593),l(.411,.365),l(-.867,1.05),l(-1.215,.062),l(-1.717,1.374),l(0,.858),l(1.889,.688),l(2.919,0),l(1.718,-.859),l(1.889,-1.545),l(1.717,-1.717),l(1.374,-.688),l(4.121,-1.03),l(2.231,-.687),l(3.263,-.344),l(2.061,-1.03),l(1.03,-1.03),l(3.435,-1.03),l(2.403,-.687),l(2.061,-.687),l(2.061,-.172),l(6.182,-.687),l(3.778,.171),l(1.204,-.542),l(.169,-.659),l(.54,-.759),l(.49,-.101),l(.471,.776),l(.305,.775),l(4.892,-.35),l(5.838,0),l(4.979,-.172),l(3.091,.344),l(2.112,-.214),l(1.328,.085),l(1.018,.594),l(1.188,-.764),l(2.714,-1.046),l(1.866,-.226),l(.664,-.028),l(.594,-.028),l(.777,-.057),l(1.512,.311),l(1.166,-.172),l(3.606,.687),l(3.777,.344),l(1.03,0),l(1.064,.573),l(.745,.088),l(2.149,-.088),l(1.271,-.263),l(1.315,-.438),l(-.192,-.216),l(.28,-.53),l(1.447,-.131),l(.921,-.088),l(.786,.062),l(2.195,-.501),l(2.097,.501),l(.688,.687),l(.373,.435),l(1.842,-.131),l(.921,-.044),l(.985,.255),l(1.889,.688),l(2.919,.515),l(2.919,-.343),l(4.121,-.258),l(2.232,-.344),l(2.404,0),l(3.521,.315),l(.702,-.755),l(2.158,-.162),l(.863,1.133),l(4.909,.323),l(.917,-1.133),l(1.889,-.593),l(5.988,.013),l(.756,-.283),l(1.996,.108),l(-.432,-1.403),l(.054,-.809),l(1.232,-.36),l(.872,1.277),l(-.647,1.079),l(.805,.219),l(2.81,.482),l(5.262,.376),l(5.494,.344),l(2.278,.583),l(1.283,.14),l(1.396,-.167),l(2.204,.446),l(1.961,-.167),l(.719,.278),l(-.435,.431),l(-.151,.351),l(.293,.123),l(2.081,.331),l(1.078,.484),l(2.706,-.134),l(.377,.595),l(1.038,.227),l(4.808,.515),l(-.123,.536),l(.567,.236),l(2.695,-.095),l(3.214,.181),l(-.329,-.984),l(.71,-.095),l(.804,.426),l(.331,.709),l(1.135,.284),l(2.672,.519),l(2.576,-.343),l(4.017,.999),l(1.626,.495),l(1.672,.871),l(1.626,.023),l(.504,.187),l(.532,-.021),l(.754,-.047),l(.777,.047),l(.896,.589),l(.541,.118),l(.542,.07),l(.142,-.259),l(.471,0),l(1.484,-.048),l(1.416,.237),l(5.951,.535),l(.729,.516),l(1.733,.323),l(2.979,.944),l(.43,-.335),l(.551,.191),l(.454,.67),l(-.741,.215),l(-1.124,.167),l(-.216,.359),l(.168,.263),l(.55,-.048),l(-.024,.67),l(-.43,-.048),l(-.096,.287),l(-.312,.071),l(-.598,.622),l(-.526,.12),l(-.55,.287),l(-.168,.669),l(-1.603,.096),l(-1.339,-.239),l(-1.794,.359),l(-2.153,.425),l(-2.629,.764),l(1.271,1.103),l(-1.907,.212),l(-1.23,-.255),l(-.763,.212),l(-.043,.637),l(-2.374,.169),l(.136,.514),l(.924,.632),l(-.127,.763),l(-.382,.085),l(-.466,.467),l(.551,.466),l(.085,.764),l(-.764,.424),l(.637,.254),l(.763,0),l(.764,.255),l(.339,.509),l(.17,.721),l(1.284,-.187),l(.836,.907),l(2.035,.297),l(.339,.339),l(2.672,.552),l(-4.113,0),l(-2.799,.138),l(-2.332,.541),l(-1.823,-.085),l(-.806,.212),l(-1.611,.339),l(-1.326,-.32),l(-.546,.426),l(1.116,.529),l(-.503,.447),l(-.669,.195),l(-1.117,.753),l(-2.623,.642),l(.475,.391),l(2.205,-.111),l(.53,0),l(.809,.307),l(.168,.363),l(.499,.18),l(.422,.183),l(.111,.894),l(.209,.502),l(3.195,.279),l(2.874,.948),l(3.662,.801),l(5.151,1.202),l(1.456,.062),l(1.015,.17),l(-.146,.234),l(-1.67,.264),l(-.47,.264),l(1.173,.088),l(2.198,-.293),l(1.988,.166), +E(0,0) +}; + +#undef N +#undef M +#undef L +#undef l +#undef E diff --git a/local/recipes/libs/cairo/source/test/xcb-huge-image-shm.c b/local/recipes/libs/cairo/source/test/xcb-huge-image-shm.c new file mode 100644 index 0000000000..269d7f0d47 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/xcb-huge-image-shm.c @@ -0,0 +1,67 @@ +/* + * Copyright © 2011 Uli Schlachter + * + * 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: Uli Schlachter + */ + +#include "cairo-test.h" + +#define WIDTH 3000 +#define HEIGHT 3000 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface; + cairo_surface_t *image; + cairo_t *cr2; + + /* We use a similar surface to have way smaller ref images */ + surface = cairo_surface_create_similar (cairo_get_target (cr), + CAIRO_CONTENT_COLOR_ALPHA, + WIDTH, HEIGHT); + + /* First we have to defeat xcb's deferred clear */ + cr2 = cairo_create (surface); + cairo_test_paint_checkered (cr2); + cairo_destroy (cr2); + + /* Now we try to map this to an image. This will try to use shared memory + * but fail the allocation, because of the huge surface. */ + image = cairo_surface_map_to_image (surface, NULL); + cairo_surface_unmap_image (surface, image); + + /* Finally we make sure that errors aren't lost. */ + cairo_set_source_surface (cr, surface, 0, 0); + cairo_paint (cr); + cairo_surface_destroy (surface); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (xcb_huge_image_shm, + "Force a failed shm allocation when receiving an image", + "xcb", /* keywords */ + NULL, /* requirements */ + 2, 2, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/xcb-huge-subimage.c b/local/recipes/libs/cairo/source/test/xcb-huge-subimage.c new file mode 100644 index 0000000000..fc8e278c6b --- /dev/null +++ b/local/recipes/libs/cairo/source/test/xcb-huge-subimage.c @@ -0,0 +1,81 @@ +/* + * Copyright © 2012 Uli Schlachter + * + * 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: Uli Schlachter + */ + +#include "cairo-test.h" + +#define WIDTH 6000 +#define HEIGHT 6000 + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *surface; + cairo_surface_t *image; + cairo_surface_t *subimage; + cairo_rectangle_int_t extents; + cairo_t *cr2; + + extents.x = extents.y = 10; + extents.width = WIDTH - 20; + extents.height = HEIGHT - 20; + + /* We use a similar surface to have way smaller ref images */ + surface = cairo_surface_create_similar (cairo_get_target (cr), + CAIRO_CONTENT_COLOR_ALPHA, + WIDTH, HEIGHT); + + /* First we have to defeat xcb's deferred clear */ + cr2 = cairo_create (surface); + cairo_test_paint_checkered (cr2); + cairo_destroy (cr2); + + /* Get us an image surface with a non-natural stride */ + image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + WIDTH, HEIGHT); + subimage = cairo_surface_map_to_image (image, &extents); + + /* Paint the subimage to the similar surface and trigger the big upload */ + cr2 = cairo_create (surface); + cairo_set_source_surface (cr2, subimage, 0, 0); + cairo_paint (cr2); + cairo_destroy (cr2); + + /* Finally we make sure that errors aren't lost. */ + cairo_surface_unmap_image (image, subimage); + cairo_set_source_surface (cr, surface, 0, 0); + cairo_paint (cr); + cairo_surface_destroy (image); + cairo_surface_destroy (surface); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (xcb_huge_subimage, + "Test if the maximum request size is honored", + "xcb", /* keywords */ + NULL, /* requirements */ + 2, 2, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/xcb-snapshot-assert.c b/local/recipes/libs/cairo/source/test/xcb-snapshot-assert.c new file mode 100644 index 0000000000..b578f8c7ed --- /dev/null +++ b/local/recipes/libs/cairo/source/test/xcb-snapshot-assert.c @@ -0,0 +1,75 @@ +/* + * Copyright © 2011 Uli Schlachter + * + * 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: Uli Schlachter + */ + +#include "cairo-test.h" +#include "cairo.h" + +static cairo_surface_t * +create_image (int width, int height) +{ + cairo_surface_t *surface; + cairo_t *cr; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); + /* Paint something random to the image */ + cr = cairo_create (surface); + cairo_surface_destroy (surface); + + cairo_set_source_rgb (cr, 0, 1, 1); + cairo_paint (cr); + + surface = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + + return surface; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_surface_t *image; + + /* Image has to have same geometry as xcb surface to be added as a snapshot */ + image = create_image (width, height); + cairo_set_source_surface (cr, image, 0, 0); + cairo_surface_destroy (image); + + /* This attaches the tested xcb surface as a snapshot */ + cairo_paint (cr); + + /* Now cairo is modifying a snapshot which fails an + * assert in _cairo_surface_begin_modification */ + cairo_paint (cr); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (xcb_snapshot_assert, + "Test a wrong _cairo_surface_attach_snapshot call", + "xcb", /* keywords */ + NULL, /* requirements */ + 2, 2, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/xcb-stress-cache.c b/local/recipes/libs/cairo/source/test/xcb-stress-cache.c new file mode 100644 index 0000000000..3e3d0a289e --- /dev/null +++ b/local/recipes/libs/cairo/source/test/xcb-stress-cache.c @@ -0,0 +1,118 @@ +/* + * Copyright © 2011 Uli Schlachter + * + * 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: Uli Schlachter + */ + +#include "cairo-test.h" + +#define WIDTH 512 +#define HEIGHT 512 + +/* This is a random pick. This results in 512 (width) * 512 (height) * + * 2 (surfaces per run) * 4 (ARGB32) * ITERATIONS = 200 MiB of image data. */ +#define ITERATIONS 100 + +/* This tries to trigger a bug in the xcb backend where a Picture is freed to + * early. It goes something like this: + * + * - _composite_mask calls _cairo_xcb_picture_for_pattern to get a xcb_picture_t + * for the source. + * - _cairo_xcb_picture_for_pattern calls _cairo_xcb_surface_picture which calls + * _cairo_xcb_screen_store_surface_picture which adds the picture to a cache. + * - _cairo_xcb_surface_picture also attached the picture as a snapshot to + * the source surface using cairo_surface_finish as detach_func. + * - _composite_mask calls _cairo_xcb_picture_for_pattern to get a xcb_picture_t + * for the mask. + * - The resulting picture surface is added to the cache again, but the cache is + * already full, so a random cache entry is picked and removed. + * - The surface that was added before is picked and gets fed to + * _surface_cache_entry_destroy. + * - This calls _cairo_surface_detach_snapshot which causes the + * detach_func from above to be called, so the surface is finished and the + * associated picture is FreePicture'd. + * - _composite_mask now uses a Picture that was already freed. + * + * So this depends on the screen's surface cache to be full which is why we do + * all this looping. + */ + +static cairo_surface_t * +create_image (void) +{ + cairo_surface_t *surface; + cairo_t *cr; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, WIDTH, HEIGHT); + /* Paint something random to the image */ + cr = cairo_create (surface); + cairo_paint (cr); + cairo_set_source_rgb (cr, 0, 1, 1); + cairo_rectangle (cr, 0, 0, WIDTH/2.0, HEIGHT/2.0); + cairo_fill (cr); + cairo_set_source_rgb (cr, 1, 0, 1); + cairo_rectangle (cr, WIDTH/2.0, HEIGHT/2.0, WIDTH/2.0, HEIGHT/2.0); + cairo_fill (cr); + cairo_destroy (cr); + + return surface; +} + +static cairo_surface_t * +dirty_cache (cairo_t *cr) +{ + cairo_surface_t *surface; + + /* Set a source surface... */ + surface = create_image (); + cairo_set_source_surface (cr, surface, 0, 0); + cairo_surface_destroy (surface); + /* ...and create a mask surface, so that we can hit the early FreePicture */ + surface = create_image (); + cairo_mask_surface (cr, surface, 0, 0); + + return surface; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + int i; + cairo_surface_t *array[ITERATIONS]; + + /* We have to keep the associated cairo_surface_t alive so that they aren't + * removed from the cache */ + for (i = 0; i < ITERATIONS; i++) + array[i] = dirty_cache (cr); + for (i = 0; i < ITERATIONS; i++) + cairo_surface_destroy (array[i]); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (xcb_stress_cache, + "Stress test for a image surface cache in cairo-xcb", + "xcb, stress", /* keywords */ + NULL, /* requirements */ + 2, 2, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/xcb-surface-source.c b/local/recipes/libs/cairo/source/test/xcb-surface-source.c new file mode 100644 index 0000000000..d2c7a13620 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/xcb-surface-source.c @@ -0,0 +1,149 @@ +/* + * Copyright © 2009 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" +#if CAIRO_HAS_XCB_SURFACE +#include +#endif + +#include "surface-source.c" + +#if CAIRO_HAS_XCB_SURFACE +static cairo_user_data_key_t closure_key; + +struct closure { + cairo_device_t *device; + xcb_connection_t *connection; + xcb_pixmap_t pixmap; +}; + +static void +cleanup (void *data) +{ + struct closure *arg = data; + + cairo_device_finish (arg->device); + cairo_device_destroy (arg->device); + + xcb_free_pixmap (arg->connection, arg->pixmap); + xcb_disconnect (arg->connection); + + free (arg); +} + +static xcb_render_pictforminfo_t * +find_depth (xcb_connection_t *connection, int depth, void **formats_out) +{ + xcb_render_query_pict_formats_reply_t *formats; + xcb_render_query_pict_formats_cookie_t cookie; + xcb_render_pictforminfo_iterator_t i; + + cookie = xcb_render_query_pict_formats (connection); + xcb_flush (connection); + + formats = xcb_render_query_pict_formats_reply (connection, cookie, 0); + if (formats == NULL) + return NULL; + + for (i = xcb_render_query_pict_formats_formats_iterator (formats); + i.rem; + xcb_render_pictforminfo_next (&i)) + { + if (XCB_RENDER_PICT_TYPE_DIRECT != i.data->type) + continue; + + if (depth != i.data->depth) + continue; + + *formats_out = formats; + return i.data; + } + + free (formats); + return NULL; +} +#endif + +static cairo_surface_t * +create_source_surface (int size) +{ +#if CAIRO_HAS_XCB_SURFACE + xcb_connection_t *connection; + xcb_render_pictforminfo_t *render_format; + struct closure *data; + cairo_surface_t *surface; + xcb_screen_t *root; + xcb_void_cookie_t cookie; + void *formats; + + connection = xcb_connect (NULL, NULL); + if (connection == NULL) + return NULL; + + data = xmalloc (sizeof (struct closure)); + data->connection = connection; + + render_format = find_depth (connection, 32, &formats); + if (render_format == NULL) { + xcb_disconnect (connection); + free (data); + return NULL; + } + + root = xcb_setup_roots_iterator (xcb_get_setup (connection)).data; + + data->pixmap = xcb_generate_id (connection); + cookie = xcb_create_pixmap_checked (connection, 32, + data->pixmap, root->root, size, size); + /* slow, but sure */ + if (xcb_request_check (connection, cookie) != NULL) { + free (formats); + xcb_disconnect (connection); + free (data); + return NULL; + } + + surface = cairo_xcb_surface_create_with_xrender_format (connection, + root, + data->pixmap, + render_format, + size, size); + free (formats); + + data->device = cairo_device_reference (cairo_surface_get_device (surface)); + cairo_surface_set_user_data (surface, &closure_key, data, cleanup); + + return surface; +#else + return NULL; +#endif +} + +CAIRO_TEST (xcb_surface_source, + "Test using a XCB surface as the source", + "source", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + preamble, draw) diff --git a/local/recipes/libs/cairo/source/test/xcomposite-projection.c b/local/recipes/libs/cairo/source/test/xcomposite-projection.c new file mode 100644 index 0000000000..39686cf996 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/xcomposite-projection.c @@ -0,0 +1,109 @@ +/* + * Copyright 2009 Benjamin Otte + * + * 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: Benjamin Otte + */ + +#include "cairo-test.h" + +/* + * Exercise a bug in the projection of a rotated trapezoid mask. + * I used CAIRO_ANTIALIAS_NONE and a single-color source in the test to get + * rid of aliasing issues in the output images. This makes some issues + * slightly less visible, but still fails for all of them. If you want to + * get a clearer view: + * #define ANTIALIAS CAIRO_ANTIALIAS_DEFAULT + */ + +#define ANTIALIAS CAIRO_ANTIALIAS_NONE + +static const char png_filename[] = "romedalen.png"; + +static cairo_pattern_t * +get_source (const cairo_test_context_t *ctx, + int *width, int *height) +{ + cairo_surface_t *surface; + cairo_pattern_t *pattern; + + if (ANTIALIAS == CAIRO_ANTIALIAS_NONE) { + cairo_t *cr; + + surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 256, 192); + cr = cairo_create (surface); + + cairo_set_source_rgb (cr, 0.75, 0.25, 0.25); + cairo_paint (cr); + + pattern = cairo_pattern_create_for_surface (cairo_get_target (cr)); + cairo_destroy (cr); + } else { + surface = cairo_test_create_surface_from_png (ctx, png_filename); + pattern = cairo_pattern_create_for_surface (surface); + } + + *width = cairo_image_surface_get_width (surface); + *height = cairo_image_surface_get_height (surface); + cairo_surface_destroy (surface); + + return pattern; +} + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + cairo_pattern_t *image; + int img_width, img_height; + + image = get_source (cairo_test_get_context (cr), + &img_width, &img_height); + + /* we don't want to debug antialiasing artifacts */ + cairo_set_antialias (cr, ANTIALIAS); + + /* dark grey background */ + cairo_set_source_rgb (cr, 0.25, 0.25, 0.25); + cairo_paint (cr); + + /* magic transform */ + cairo_translate (cr, 10, -40); + cairo_rotate (cr, -0.05); + + /* place the image on our surface */ + cairo_set_source (cr, image); + + /* paint the image */ + cairo_rectangle (cr, 0, 0, img_width, img_height); + cairo_fill (cr); + + cairo_pattern_destroy (image); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (xcomposite_projection, + "Test a bug with XRenderComposite reference computation when projecting the first trapezoid onto 16.16 space", + "xlib", /* keywords */ + "target=raster", /* requirements */ + 300, 150, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/xlib-expose-event.c b/local/recipes/libs/cairo/source/test/xlib-expose-event.c new file mode 100644 index 0000000000..1de23e01e4 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/xlib-expose-event.c @@ -0,0 +1,196 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +/* This test tries to emulate the behaviour of most toolkits; it tries + * to simulate typical usage of a single surface with multiple exposures. + * + * The first goal of the test is to reproduce the XSetClipMask(NULL) bug + * reintroduced in 1.6.2 (but was originally fixed in 40558cb15). As I've + * made the same mistake again, it is worth adding a regression test... + */ + +#include "cairo-test.h" + +#include +#include + +#include "cairo.h" + +#include "buffer-diff.h" + +#define SIZE 160 +#define NLOOPS 10 + +static const char *png_filename = "romedalen.png"; + +static void +draw_mask (cairo_t *cr) +{ + cairo_surface_t *surface; + cairo_t *cr2; + + surface = cairo_surface_create_similar (cairo_get_group_target (cr), + CAIRO_CONTENT_ALPHA, + 50, 50); + cr2 = cairo_create (surface); + cairo_surface_destroy (surface); + + cairo_rectangle (cr2, + 0, 0, + 40, 40); + cairo_rectangle (cr2, + 10, 10, + 40, 40); + cairo_clip (cr2); + + cairo_move_to (cr2, 0, 25); + cairo_line_to (cr2, 50, 25); + cairo_move_to (cr2, 25, 0); + cairo_line_to (cr2, 25, 50); + cairo_set_source_rgb (cr2, 1, 1, 1); + cairo_stroke (cr2); + + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_mask_surface (cr, cairo_get_target (cr2), 50, 50); + cairo_destroy (cr2); +} + +static cairo_surface_t * +clone_similar_surface (cairo_surface_t * target, cairo_surface_t *surface) +{ + cairo_t *cr; + cairo_surface_t *similar; + + similar = cairo_surface_create_similar (target, + cairo_surface_get_content (surface), + cairo_image_surface_get_width (surface), + cairo_image_surface_get_height (surface)); + + cr = cairo_create (similar); + cairo_surface_destroy (similar); + + cairo_set_source_surface (cr, surface, 0, 0); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_paint (cr); + + similar = cairo_surface_reference (cairo_get_target (cr)); + cairo_destroy (cr); + + return similar; +} + +static void +draw_image (const cairo_test_context_t *ctx, + cairo_t *cr, + cairo_surface_t *image) +{ + cairo_set_source_surface (cr, image, 0, 0); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_paint (cr); +} + +static void +draw (const cairo_test_context_t *ctx, + cairo_t *cr, + cairo_surface_t *image, + cairo_rectangle_t *region, + int n_regions) +{ + cairo_save (cr); + if (region != NULL) { + int i; + for (i = 0; i < n_regions; i++) { + cairo_rectangle (cr, + region[i].x, region[i].y, + region[i].width, region[i].height); + } + cairo_clip (cr); + } + cairo_push_group (cr); + draw_image (ctx, cr, image); + draw_mask (cr); + cairo_pop_group_to_source (cr); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_paint (cr); + cairo_restore (cr); +} + +static cairo_test_status_t +draw_func (cairo_t *cr, int width, int height) +{ + cairo_rectangle_t region[4]; + const cairo_test_context_t *ctx; + cairo_surface_t *source, *image; + int i, j; + + ctx = cairo_test_get_context (cr); + + source = cairo_test_create_surface_from_png (ctx, png_filename); + image = clone_similar_surface (cairo_get_group_target (cr), source); + cairo_surface_destroy (source); + + cairo_push_group_with_content (cr, CAIRO_CONTENT_COLOR); + draw (ctx, cr, image, NULL, 0); + for (i = 0; i < NLOOPS; i++) { + for (j = 0; j < NLOOPS; j++) { + region[0].x = i * SIZE / NLOOPS; + region[0].y = i * SIZE / NLOOPS; + region[0].width = SIZE / 4; + region[0].height = SIZE / 4; + + region[1].x = j * SIZE / NLOOPS; + region[1].y = j * SIZE / NLOOPS; + region[1].width = SIZE / 4; + region[1].height = SIZE / 4; + + region[2].x = i * SIZE / NLOOPS; + region[2].y = j * SIZE / NLOOPS; + region[2].width = SIZE / 4; + region[2].height = SIZE / 4; + + region[3].x = j * SIZE / NLOOPS; + region[3].y = i * SIZE / NLOOPS; + region[3].width = SIZE / 4; + region[3].height = SIZE / 4; + + draw (ctx, cr, image, region, 4); + } + } + + cairo_pop_group_to_source (cr); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_paint (cr); + + cairo_surface_destroy (image); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (xlib_expose_event, + "Emulate a typical expose event", + "xlib", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw_func) diff --git a/local/recipes/libs/cairo/source/test/xlib-surface-source.c b/local/recipes/libs/cairo/source/test/xlib-surface-source.c new file mode 100644 index 0000000000..7d2ed71c04 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/xlib-surface-source.c @@ -0,0 +1,100 @@ +/* + * Copyright © 2008 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include "cairo-test.h" +#include +#if CAIRO_HAS_XLIB_XRENDER_SURFACE +#include +#endif + +#include "surface-source.c" + +static cairo_user_data_key_t closure_key; + +struct closure { + cairo_device_t *device; + Display *dpy; + Pixmap pix; +}; + +static void +cleanup (void *data) +{ + struct closure *arg = data; + + cairo_device_finish (arg->device); + cairo_device_destroy (arg->device); + + XFreePixmap (arg->dpy, arg->pix); + XCloseDisplay (arg->dpy); + + free (arg); +} + +static cairo_surface_t * +create_source_surface (int size) +{ +#if CAIRO_HAS_XLIB_XRENDER_SURFACE + XRenderPictFormat *xrender_format; + struct closure *data; + cairo_surface_t *surface; + + data = xmalloc (sizeof (struct closure)); + + data->dpy = XOpenDisplay (NULL); + if (!data->dpy) { + return NULL; + } + + xrender_format = XRenderFindStandardFormat (data->dpy, PictStandardARGB32); + + data->pix = XCreatePixmap (data->dpy, DefaultRootWindow (data->dpy), + size, size, xrender_format->depth); + + surface = cairo_xlib_surface_create_with_xrender_format (data->dpy, + data->pix, + DefaultScreenOfDisplay (data->dpy), + xrender_format, + size, size); + data->device = cairo_device_reference (cairo_surface_get_device (surface)); + if (cairo_surface_set_user_data (surface, &closure_key, data, cleanup)) { + cairo_surface_finish (surface); + cairo_surface_destroy (surface); + cleanup (data); + return NULL; + } + + return surface; +#else + return NULL; +#endif +} + +CAIRO_TEST (xlib_surface_source, + "Test using a Xlib surface as the source", + "source", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + preamble, draw) diff --git a/local/recipes/libs/cairo/source/test/xlib-surface.c b/local/recipes/libs/cairo/source/test/xlib-surface.c new file mode 100644 index 0000000000..137b282327 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/xlib-surface.c @@ -0,0 +1,353 @@ +/* + * Copyright © 2005 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +#include +#include + +#include "cairo.h" +#include "cairo-xlib.h" + +#include "cairo-boilerplate-xlib.h" + +#include "buffer-diff.h" + +#define SIZE 100 +#define OFFSCREEN_OFFSET 50 + +cairo_bool_t result = 0; + +#if CAIRO_HAS_XLIB_XRENDER_SURFACE + +#include "cairo-xlib-xrender.h" + +/* Vladimir Vukicevic reported that surfaces were being created with + * mismatching Visuals and XRenderPictFormats. + */ +static cairo_bool_t +surface_compare_visual_and_format (cairo_surface_t *surface) +{ + Display *dpy; + Visual *visual; + XRenderPictFormat *format; + + dpy = cairo_xlib_surface_get_display (surface); + + visual = cairo_xlib_surface_get_visual (surface); + if (visual == NULL) + return TRUE; + + format = cairo_xlib_surface_get_xrender_format (surface); + if (format == NULL) + return TRUE; + + return format == XRenderFindVisualFormat (dpy, visual); + +} +#else + +static cairo_bool_t +surface_compare_visual_and_format (cairo_surface_t *surface) +{ + return TRUE; +} + +#endif + +static cairo_bool_t +check_similar_visual_and_format (cairo_surface_t *surface) +{ + cairo_surface_t *similar; + cairo_bool_t ret; + + similar = cairo_surface_create_similar (surface, + CAIRO_CONTENT_COLOR_ALPHA, + 1, 1); + if (cairo_surface_status (similar)) + return FALSE; + + ret = surface_compare_visual_and_format (similar); + + cairo_surface_destroy (similar); + + return ret; +} + + +static void +draw_pattern (cairo_surface_t *surface) +{ + cairo_t *cr = cairo_create (surface); + int i; + + cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ + cairo_paint (cr); + + cairo_set_source_rgba (cr, 0, 0.0, 0.0, 0.50); /* half-alpha-black */ + + for (i = 1; i <= 3; i++) { + int inset = SIZE / 8 * i; + + cairo_rectangle (cr, + inset, inset, + SIZE - 2 * inset, SIZE - 2 * inset); + cairo_fill (cr); + } + + cairo_destroy (cr); +} + +static void +erase_pattern (cairo_surface_t *surface) +{ + cairo_t *cr = cairo_create (surface); + + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */ + cairo_paint (cr); + + cairo_destroy (cr); +} + +static cairo_test_status_t +do_test (const cairo_test_context_t *ctx, + Display *dpy, + unsigned char *reference_data, + unsigned char *test_data, + unsigned char *diff_data, + cairo_bool_t use_pixmap, + cairo_bool_t set_size, + cairo_bool_t offscreen) +{ + cairo_surface_t *surface; + cairo_surface_t *test_surface; + cairo_t *test_cr; + buffer_diff_result_t result; + Drawable drawable; + int screen = DefaultScreen (dpy); + + if (use_pixmap && offscreen) + return CAIRO_TEST_SUCCESS; + + if (use_pixmap) { + drawable = XCreatePixmap (dpy, DefaultRootWindow (dpy), + SIZE, SIZE, DefaultDepth (dpy, screen)); + } else { + XSetWindowAttributes xwa; + int x, y; + + xwa.override_redirect = True; + + if (offscreen) { + x = - OFFSCREEN_OFFSET; + y = - OFFSCREEN_OFFSET; + } else { + x = 0; + y = 0; + } + + drawable = XCreateWindow (dpy, DefaultRootWindow (dpy), + x, y, SIZE, SIZE, 0, + DefaultDepth (dpy, screen), InputOutput, + DefaultVisual (dpy, screen), + CWOverrideRedirect, &xwa); + XMapWindow (dpy, drawable); + } + + surface = cairo_xlib_surface_create (dpy, + drawable, + DefaultVisual (dpy, screen), + SIZE, SIZE); + + if (! surface_compare_visual_and_format (surface)) + return CAIRO_TEST_FAILURE; + + if (set_size) { + cairo_xlib_surface_set_size (surface, SIZE, SIZE); + + if (cairo_xlib_surface_get_width (surface) != SIZE || + cairo_xlib_surface_get_height (surface) != SIZE) + return CAIRO_TEST_FAILURE; + } + + if (! check_similar_visual_and_format (surface)) + return CAIRO_TEST_FAILURE; + + draw_pattern (surface); + + test_surface = cairo_image_surface_create_for_data (test_data, + CAIRO_FORMAT_RGB24, + SIZE, SIZE, + SIZE * 4); + + test_cr = cairo_create (test_surface); + cairo_set_source_surface (test_cr, surface, 0, 0); + cairo_paint (test_cr); + + cairo_destroy (test_cr); + cairo_surface_destroy (test_surface); + + /* We erase the surface to black in case we get the same + * memory back again for the pixmap case. + */ + erase_pattern (surface); + cairo_surface_destroy (surface); + + if (use_pixmap) + XFreePixmap (dpy, drawable); + else + XDestroyWindow (dpy, drawable); + + if (offscreen) { + size_t offset = 4 * (SIZE * OFFSCREEN_OFFSET + OFFSCREEN_OFFSET); + + buffer_diff_noalpha (reference_data + offset, + test_data + offset, + diff_data + offset, + SIZE - OFFSCREEN_OFFSET, + SIZE - OFFSCREEN_OFFSET, + 4 * SIZE, + &result); + } else { + buffer_diff_noalpha (reference_data, + test_data, + diff_data, + SIZE, + SIZE, + 4 * SIZE, + &result); + } + + cairo_test_log (ctx, "xlib-surface: %s, %s, %s: %s\n", + set_size ? " size" : "no-size", + use_pixmap ? "pixmap" : "window", + use_pixmap ? " " : (offscreen ? ", offscreen" : ", onscreen"), + image_diff_is_failure (&result, 0) ? "FAIL" : "PASS"); + + if (image_diff_is_failure (&result, 0)) + return CAIRO_TEST_FAILURE; + else + return CAIRO_TEST_SUCCESS; +} + +static cairo_bool_t +check_visual (Display *dpy) +{ + Visual *visual = DefaultVisual (dpy, DefaultScreen (dpy)); + + if ((visual->red_mask == 0xff0000 && + visual->green_mask == 0x00ff00 && + visual->blue_mask == 0x0000ff) || + (visual->red_mask == 0x0000ff && + visual->green_mask == 0x00ff00 && + visual->blue_mask == 0xff0000)) + return 1; + else + return 0; +} + +#undef xcalloc +static void * +xcalloc (const cairo_test_context_t *ctx, size_t a, size_t b) +{ + void *ptr = calloc (a, b); + if (ptr == NULL) { + cairo_test_log (ctx, "xlib-surface: unable to allocate memory, skipping\n"); + abort (); + } + return ptr; +} + +static cairo_test_status_t +preamble (cairo_test_context_t *ctx) +{ + Display *dpy; + unsigned char *reference_data; + unsigned char *test_data; + unsigned char *diff_data; + cairo_surface_t *reference_surface; + cairo_bool_t use_pixmap; + cairo_bool_t set_size; + cairo_bool_t offscreen; + cairo_test_status_t status, result = CAIRO_TEST_UNTESTED; + int stride; + + if (! cairo_test_is_target_enabled (ctx, "xlib")) + goto CLEANUP_TEST; + + dpy = XOpenDisplay (NULL); + if (!dpy) { + cairo_test_log (ctx, "xlib-surface: Cannot open display, skipping\n"); + goto CLEANUP_TEST; + } + + if (!check_visual (dpy)) { + cairo_test_log (ctx, "xlib-surface: default visual is not RGB24 or BGR24, skipping\n"); + goto CLEANUP_DISPLAY; + } + + stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, SIZE); + + reference_data = xcalloc (ctx, SIZE, stride); + test_data = xcalloc (ctx, SIZE, stride); + diff_data = xcalloc (ctx, SIZE, stride); + + reference_surface = cairo_image_surface_create_for_data (reference_data, + CAIRO_FORMAT_RGB24, + SIZE, SIZE, + stride); + + draw_pattern (reference_surface); + cairo_surface_destroy (reference_surface); + + result = CAIRO_TEST_SUCCESS; + + for (set_size = 0; set_size <= 1; set_size++) + for (use_pixmap = 0; use_pixmap <= 1; use_pixmap++) + for (offscreen = 0; offscreen <= 1; offscreen++) { + status = do_test (ctx, dpy, + reference_data, test_data, diff_data, + use_pixmap, set_size, offscreen); + if (status) + result = status; + } + + free (reference_data); + free (test_data); + free (diff_data); + + CLEANUP_DISPLAY: + XCloseDisplay (dpy); + + CLEANUP_TEST: + return result; +} + +CAIRO_TEST (xlib_surface, + "Check creating surfaces for various XWindows", + "xlib", /* keywords */ + NULL, /* requirements */ + 0, 0, + preamble, NULL) diff --git a/local/recipes/libs/cairo/source/test/zero-alpha.c b/local/recipes/libs/cairo/source/test/zero-alpha.c new file mode 100644 index 0000000000..01da92c968 --- /dev/null +++ b/local/recipes/libs/cairo/source/test/zero-alpha.c @@ -0,0 +1,95 @@ +/* + * Copyright © 2006 Red Hat, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Carl D. Worth + */ + +#include "cairo-test.h" + +#define SIZE 3 +#define REPS 10 + +/* History: + * + * 2006-06-13 Paul Giblock reports a "Strange alpha channel problem" on + * the cairo mailing list. + * + * 2006-06-13 Carl Worth writes this test in an attempt to reproduce + * the problem. The test first fills in a 3x3 rectangle with red, then + * starts pounding on that center pixel with various forms of + * zero-alpha rendering to see if its value can ever be made to + * change. + * + * 2006-06-13 Paul Giblock reports that this only happens with the + * xlib backend, and then only on some systems. + */ +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + int i; + cairo_surface_t *surface; + uint32_t zero = 0; + + /* First paint background red. */ + cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); /* red */ + cairo_paint (cr); + + /* Then we paint zero-alpha in several ways (always REPS times): */ + + /* 1. fill a rectangle with a zero-alpha solid source. */ + cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.0); /* transparent */ + cairo_rectangle (cr, 1.0, 1.0, 1.0, 1.0); + for (i=0; i < REPS; i++) + cairo_fill_preserve (cr); + cairo_new_path (cr); + + /* 2. paint with a zero-alpha image surface source. */ + surface = cairo_image_surface_create_for_data ((unsigned char *) &zero, + CAIRO_FORMAT_ARGB32, 1, 1, 4); + cairo_set_source_surface (cr, surface, 1, 1); + for (i=0; i < REPS; i++) + cairo_paint (cr); + + /* 3. clip to rectangle then paint with zero-alpha solid source. */ + cairo_rectangle (cr, 1.0, 1.0, 1.0, 1.0); + cairo_clip (cr); + cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.0); /* transparent */ + for (i=0; i < REPS; i++) + cairo_paint (cr); + + /* 4. With the clip still there, paint our image surface. */ + cairo_set_source_surface (cr, surface, 1, 1); + for (i=0; i < REPS; i++) + cairo_paint (cr); + + cairo_surface_finish (surface); /* zero will go out of scope */ + cairo_surface_destroy (surface); + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (zero_alpha, + "Testing that drawing with zero alpha has no effect", + "alpha", /* keywords */ + NULL, /* requirements */ + SIZE, SIZE, + NULL, draw) diff --git a/local/recipes/libs/cairo/source/test/zero-mask.c b/local/recipes/libs/cairo/source/test/zero-mask.c new file mode 100644 index 0000000000..3d2f34d0ee --- /dev/null +++ b/local/recipes/libs/cairo/source/test/zero-mask.c @@ -0,0 +1,198 @@ +/* + * Copyright © 2010 Red Hat, Inc. + * + * 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: Benjamin Otte + */ + +#include "cairo-test.h" + +#define RECT 10 +#define SPACE 5 + +static void +paint_with_alpha (cairo_t *cr) +{ + cairo_paint_with_alpha (cr, 0.0); +} + +static void +mask_with_solid (cairo_t *cr) +{ + cairo_pattern_t *pattern = cairo_pattern_create_rgba (1, 0, 0, 0); + + cairo_mask (cr, pattern); + + cairo_pattern_destroy (pattern); +} + +static void +mask_with_empty_gradient (cairo_t *cr) +{ + cairo_pattern_t *pattern = cairo_pattern_create_linear (1, 2, 3, 4); + + cairo_mask (cr, pattern); + + cairo_pattern_destroy (pattern); +} + +static void +mask_with_gradient (cairo_t *cr) +{ + cairo_pattern_t *pattern = cairo_pattern_create_radial (1, 2, 3, 4, 5, 6); + + cairo_pattern_add_color_stop_rgba (pattern, 0, 1, 0, 0, 0); + cairo_pattern_add_color_stop_rgba (pattern, 0, 0, 0, 1, 0); + + cairo_mask (cr, pattern); + + cairo_pattern_destroy (pattern); +} + +static void +mask_with_surface (cairo_t *cr) +{ + cairo_surface_t *surface = cairo_surface_create_similar (cairo_get_target (cr), + CAIRO_CONTENT_COLOR_ALPHA, + RECT, + RECT); + + cairo_mask_surface (cr, surface, 0, 0); + + cairo_surface_destroy (surface); +} + +static void +mask_with_alpha_surface (cairo_t *cr) +{ + cairo_surface_t *surface = cairo_surface_create_similar (cairo_get_target (cr), + CAIRO_CONTENT_ALPHA, + RECT / 2, + RECT / 2); + cairo_pattern_t *pattern = cairo_pattern_create_for_surface (surface); + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REFLECT); + + cairo_mask (cr, pattern); + + cairo_pattern_destroy (pattern); + cairo_surface_destroy (surface); +} + +static void +mask_with_nonclear_surface (cairo_t *cr) +{ + static unsigned char data[8 * 4] = { 0, }; + cairo_surface_t *surface = cairo_image_surface_create_for_data (data, + CAIRO_FORMAT_A1, + 16, 8, 4); + + cairo_mask_surface (cr, surface, 0, 0); + + cairo_surface_destroy (surface); +} + +static void +mask_with_0x0_surface (cairo_t *cr) +{ + cairo_surface_t *surface = cairo_surface_create_similar (cairo_get_target (cr), + CAIRO_CONTENT_COLOR_ALPHA, + 0, 0); + + cairo_mask_surface (cr, surface, 0, 0); + + cairo_surface_destroy (surface); +} + +static void +mask_with_extend_none (cairo_t *cr) +{ + cairo_surface_t *surface = cairo_surface_create_similar (cairo_get_target (cr), + CAIRO_CONTENT_COLOR_ALPHA, + RECT, + RECT); + + cairo_mask_surface (cr, surface, 2 * RECT, 2 * RECT); + + cairo_surface_destroy (surface); +} + +typedef void (* mask_func_t) (cairo_t *); + +static mask_func_t mask_funcs[] = { + paint_with_alpha, + mask_with_solid, + mask_with_empty_gradient, + mask_with_gradient, + mask_with_surface, + mask_with_alpha_surface, + mask_with_nonclear_surface, + mask_with_0x0_surface, + mask_with_extend_none +}; + +static cairo_operator_t operators[] = { + CAIRO_OPERATOR_CLEAR, + CAIRO_OPERATOR_SOURCE, + CAIRO_OPERATOR_OVER, + CAIRO_OPERATOR_IN, + CAIRO_OPERATOR_DEST_ATOP, + CAIRO_OPERATOR_SATURATE, + CAIRO_OPERATOR_MULTIPLY +}; + +static cairo_test_status_t +draw (cairo_t *cr, int width, int height) +{ + unsigned int i, op; + + /* 565-compatible gray background */ + cairo_set_source_rgb (cr, 0.51613, 0.55555, 0.51613); + cairo_paint (cr); + + cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); /* green */ + /* mask with zero-alpha in several ways */ + + cairo_translate (cr, SPACE, SPACE); + + for (op = 0; op < ARRAY_LENGTH (operators); op++) { + cairo_set_operator (cr, operators[op]); + + for (i = 0; i < ARRAY_LENGTH (mask_funcs); i++) { + cairo_save (cr); + cairo_translate (cr, i * (RECT + SPACE), op * (RECT + SPACE)); + cairo_rectangle (cr, 0, 0, RECT, RECT); + cairo_clip (cr); + mask_funcs[i] (cr); + cairo_restore (cr); + } + } + + return CAIRO_TEST_SUCCESS; +} + +CAIRO_TEST (zero_mask, + "Testing that masking with zero alpha works", + "alpha, mask", /* keywords */ + NULL, /* requirements */ + SPACE + (RECT + SPACE) * ARRAY_LENGTH (mask_funcs), + SPACE + (RECT + SPACE) * ARRAY_LENGTH (operators), + NULL, draw) diff --git a/local/recipes/libs/cairo/source/util/.gitignore b/local/recipes/libs/cairo/source/util/.gitignore new file mode 100644 index 0000000000..9a28da1b9c --- /dev/null +++ b/local/recipes/libs/cairo/source/util/.gitignore @@ -0,0 +1,24 @@ +.deps +.libs +Makefile +Makefile.in +show-contour +show-edges +show-events +show-polygon +show-traps +xml-to-trace +trace-to-xml +*.so +*.la +*.lo +*.loT +*.o +*.obj +*.pdb +*.dll +*.exp +*.lib +*~ +.*.sw? +TAGS diff --git a/local/recipes/libs/cairo/source/util/COPYING b/local/recipes/libs/cairo/source/util/COPYING new file mode 100644 index 0000000000..ea44bb6f5c --- /dev/null +++ b/local/recipes/libs/cairo/source/util/COPYING @@ -0,0 +1,4 @@ +Cairo is free software. + +These utilities are all free software, please see the licensing conditions +in the opening comments of each file. diff --git a/local/recipes/libs/cairo/source/util/README b/local/recipes/libs/cairo/source/util/README new file mode 100644 index 0000000000..90e1f7fab1 --- /dev/null +++ b/local/recipes/libs/cairo/source/util/README @@ -0,0 +1,28 @@ +Cairo Utilities +=============== + +There are a varieties of utilities we use with cairo. + +cairo-trace +----------- + +This tool can be used to trace all the cairo function calls made by an +applications. This is useful for either extracting a test case triggering +a bug from an application, or simply to get a general idea of how an +application is using cairo. + + +cairo-api-update and xr2cairo +----------------------------- + +These two scripts were used to convert source code written for pre-1.0 +cairo to newer API. See $(top_srcdir)/PORTING_GUIDE for more information. + +These files are obsolete now and may be removed in a future version. + + +cairo-view and waterfall +------------------------ + +These are two pycairo scripts useful for testing the toy font backend. + diff --git a/local/recipes/libs/cairo/source/util/cairo-api-update b/local/recipes/libs/cairo/source/util/cairo-api-update new file mode 100755 index 0000000000..cff33317b5 --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-api-update @@ -0,0 +1,72 @@ +#!/bin/sh +set -e + +if [ $# -lt 1 ]; then + argv0=`basename $0` + echo "$argv0: Update source code to the latest Cairo API" >&2 + echo "" >&2 + echo "Usage: $argv0 file [...]" >&2 + exit 1 +fi + +cairo_api_update() { + file=$1 + backup=$file.bak + + cp $file $backup + sed -e '/\(DEPRECATED\|REPLACED\)_BY/! { + s/cairo_current_font_extents/cairo_font_extents/g + s/cairo_get_font_extents/cairo_font_extents/g + s/cairo_current_operator/cairo_get_operator/g + s/cairo_current_tolerance/cairo_get_tolerance/g + s/cairo_current_point/cairo_get_current_point/g + s/cairo_current_fill_rule/cairo_get_fill_rule/g + s/cairo_current_line_width/cairo_get_line_width/g + s/cairo_current_line_cap/cairo_get_line_cap/g + s/cairo_current_line_join/cairo_get_line_join/g + s/cairo_current_miter_limit/cairo_get_miter_limit/g + s/cairo_current_matrix/cairo_get_matrix/g + s/cairo_current_pattern/cairo_get_source/g + s/cairo_current_target_surface/cairo_get_target/g + s/cairo_get_status/cairo_status/g + s/cairo_get_status_string/cairo_status_string/g + s/cairo_concat_matrix/cairo_transform/g + s/cairo_scale_font/cairo_set_font_size/g + s/cairo_select_font\([^_]\)/cairo_select_font_face\1/g + s/cairo_transform_font/cairo_set_font_matrix/g + s/cairo_transform_point/cairo_user_to_device/g + s/cairo_transform_distance/cairo_user_to_device_distance/g + s/cairo_inverse_transform_point/cairo_device_to_user/g + s/cairo_inverse_transform_distance/cairo_device_to_user_distance/g + s/cairo_init_clip/cairo_reset_clip/g + s/cairo_surface_create_for_image/cairo_image_surface_create_for_data/g + s/cairo_default_matrix/cairo_identity_matrix/g + s/cairo_matrix_set_affine/cairo_matrix_init/g + s/cairo_matrix_set_identity/cairo_matrix_init_identity/g + s/\([^_]\)cairo_pattern_add_color_stop\([^_]\)/\1cairo_pattern_add_color_stop_rgba\2/g + s/cairo_set_rgb_color/cairo_set_source_rgb/g + s/cairo_set_pattern/cairo_set_source/g + s/CAIRO_OPERATOR_SRC/CAIRO_OPERATOR_SOURCE/g + s/CAIRO_OPERATOR_DST/CAIRO_OPERATOR_DEST/g + s/CAIRO_OPERATOR_OVER_REVERSE/CAIRO_OPERATOR_DEST_OVER/g + s/CAIRO_OPERATOR_IN_REVERSE/CAIRO_OPERATOR_DEST_IN/g + s/CAIRO_OPERATOR_OUT_REVERSE/CAIRO_OPERATOR_DEST_OUT/g + s/CAIRO_OPERATOR_ATOP_REVERSE/CAIRO_OPERATOR_DEST_ATOP/g + } + ' $backup > $file + + grep -n 'cairo_create[ ]*([ ]*)' $file /dev/null | sed 's/^\(.*:[0-9]\+:\).*/\1 cairo_create must now accept a target surface/' + grep -n 'cairo_set_target_image' $file /dev/null | sed 's/^\(.*:[0-9]\+:\).*/\1 cairo_set_target_image should be reworked to use cairo_image_surface_create_for_data, likely before cairo_create/' + grep -n 'cairo_set_target_surface' $file /dev/null | sed 's/^\(.*:[0-9]\+:\).*/\1 cairo_set_target_surface for temporarily changing the target should now be rworked to create a temporary context with cairo_create/' + grep -n 'cairo_set_target_png' $file /dev/null | sed 's/^\(.*:[0-9]\+:\).*/\1 cairo_set_target_png should be reworked to use cairo_image_surface_create followed by cairo_surface_write_to_png/' + grep -n 'cairo_set_target_drawable' $file /dev/null | sed 's/^\(.*:[0-9]\+:\).*/\1 cairo_set_target_drawable should be reworked to use cairo_xlib_surface_create, likely before cairo_create/' + grep -n 'cairo_set_target_[^dis][^n]' $file /dev/null | sed 's/^\(.*:[0-9]\+:\).*cairo_set_target_\([a-z]*\).*/\1 cairo_set_target_\2 should be reworked to use cairo_\2_surface_create, likely before cairo_create/' + grep -n 'cairo_set_alpha' $file /dev/null | sed 's/\(.*:[0-9]\+:\).*/\1 cairo_set_alpha should be replaced by turning a nearby cairo_set_source_rgb into cairo_set_source_rgba or turning a nearby cairo_paint into cairo_paint_with_alpha/' +} + +while [ $# -gt 0 ]; do + file=$1 + shift + cairo_api_update $file +done + diff --git a/local/recipes/libs/cairo/source/util/cairo-fdr/fdr.c b/local/recipes/libs/cairo/source/util/cairo-fdr/fdr.c new file mode 100644 index 0000000000..edbd53a5bf --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-fdr/fdr.c @@ -0,0 +1,327 @@ +/* cairo-fdr - a 'flight data recorder', a black box, for cairo + * + * Copyright © 2009 Chris Wilson + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include + +static void *_dlhandle = RTLD_NEXT; +#define DLCALL(name, args...) ({ \ + static typeof (&name) name##_real; \ + if (name##_real == NULL) { \ + name##_real = dlsym (_dlhandle, #name); \ + if (name##_real == NULL && _dlhandle == RTLD_NEXT) { \ + _dlhandle = dlopen ("libcairo.so", RTLD_LAZY); \ + name##_real = dlsym (_dlhandle, #name); \ + assert (name##_real != NULL); \ + } \ + } \ + (*name##_real) (args); \ +}) + +#define RINGBUFFER_SIZE 16 +static cairo_surface_t *fdr_ringbuffer[RINGBUFFER_SIZE]; +static int fdr_position; +static int fdr_dump; + +static const cairo_user_data_key_t fdr_key; + +static void +fdr_replay_to_script (cairo_surface_t *recording, cairo_device_t *ctx) +{ + if (recording != NULL) { + DLCALL (cairo_script_write_comment, ctx, "--- fdr ---", -1); + DLCALL (cairo_script_from_recording_surface, ctx, recording); + } +} + +static void +fdr_dump_ringbuffer (void) +{ + cairo_device_t *ctx; + int n; + + ctx = DLCALL (cairo_script_create, "/tmp/fdr.trace"); + + for (n = fdr_position; n < RINGBUFFER_SIZE; n++) + fdr_replay_to_script (fdr_ringbuffer[n], ctx); + + for (n = 0; n < fdr_position; n++) + fdr_replay_to_script (fdr_ringbuffer[n], ctx); + + DLCALL (cairo_device_destroy, ctx); +} + +static void +fdr_sighandler (int sig) +{ + fdr_dump = 1; +} + +static void +fdr_urgent_sighandler (int sig) +{ + fdr_dump_ringbuffer (); +} + +static void +fdr_atexit (void) +{ + if (fdr_dump) + fdr_dump_ringbuffer (); +} + +static void +fdr_pending_signals (void) +{ + static int initialized; + + if (! initialized) { + initialized = 1; + + signal (SIGUSR1, fdr_sighandler); + + signal (SIGSEGV, fdr_urgent_sighandler); + signal (SIGABRT, fdr_urgent_sighandler); + atexit (fdr_atexit); + } + + if (fdr_dump) { + fdr_dump_ringbuffer (); + fdr_dump = 0; + } +} + +static void +fdr_get_extents (cairo_surface_t *surface, + cairo_rectangle_t *extents) +{ + cairo_t *cr; + + cr = DLCALL (cairo_create, surface); + DLCALL (cairo_clip_extents, cr, + &extents->x, &extents->y, &extents->width, &extents->height); + DLCALL (cairo_destroy, cr); + + extents->width -= extents->x; + extents->height -= extents->y; +} + +static void +fdr_surface_destroy (void *surface) +{ + DLCALL (cairo_surface_destroy, surface); +} + +static void +fdr_surface_reference (void *surface) +{ + DLCALL (cairo_surface_reference, surface); +} + +static cairo_surface_t * +fdr_surface_get_tee (cairo_surface_t *surface) +{ + return DLCALL (cairo_surface_get_user_data, surface, &fdr_key); +} + +static cairo_surface_t * +fdr_tee_surface_index (cairo_surface_t *surface, int index) +{ + return DLCALL (cairo_tee_surface_index, surface, index); +} + +cairo_t * +cairo_create (cairo_surface_t *surface) +{ + cairo_surface_t *record, *tee; + + fdr_pending_signals (); + + tee = fdr_surface_get_tee (surface); + if (tee == NULL) { + cairo_rectangle_t extents; + cairo_content_t content; + + fdr_get_extents (surface, &extents); + content = DLCALL (cairo_surface_get_content, surface); + + tee = DLCALL (cairo_tee_surface_create, surface); + record = DLCALL (cairo_recording_surface_create, content, &extents); + DLCALL (cairo_tee_surface_add, tee, record); + + DLCALL (cairo_surface_set_user_data, surface, + &fdr_key, tee, fdr_surface_destroy); + } else { + int n; + + record = fdr_tee_surface_index (tee, 1); + + /* update the position of the recording surface in the ringbuffer */ + for (n = 0; n < RINGBUFFER_SIZE; n++) { + if (record == fdr_ringbuffer[n]) { + fdr_ringbuffer[n] = NULL; + break; + } + } + } + + fdr_surface_destroy (fdr_ringbuffer[fdr_position]); + fdr_ringbuffer[fdr_position] = record; + fdr_position = (fdr_position + 1) % RINGBUFFER_SIZE; + + return DLCALL (cairo_create, tee); +} + +static void +fdr_remove_tee (cairo_surface_t *surface) +{ + fdr_surface_reference (surface); + DLCALL (cairo_surface_set_user_data, surface, &fdr_key, NULL, NULL); + fdr_surface_destroy (surface); +} + +void +cairo_destroy (cairo_t *cr) +{ + cairo_surface_t *tee; + + tee = DLCALL (cairo_get_target, cr); + DLCALL (cairo_destroy, cr); + + if (DLCALL (cairo_surface_get_reference_count, tee) == 1) + fdr_remove_tee (fdr_tee_surface_index (tee, 0)); +} + +void +cairo_pattern_destroy (cairo_pattern_t *pattern) +{ + if (DLCALL (cairo_pattern_get_type, pattern) == CAIRO_PATTERN_TYPE_SURFACE) { + cairo_surface_t *surface; + + if (DLCALL (cairo_pattern_get_surface, pattern, &surface) == CAIRO_STATUS_SUCCESS && + DLCALL (cairo_surface_get_type, surface) == CAIRO_SURFACE_TYPE_TEE && + DLCALL (cairo_surface_get_reference_count, surface) == 2) + { + fdr_remove_tee (fdr_tee_surface_index (surface, 0)); + } + } + + DLCALL (cairo_pattern_destroy, pattern); +} + +cairo_surface_t * +cairo_get_target (cairo_t *cr) +{ + cairo_surface_t *tee; + + tee = DLCALL (cairo_get_target, cr); + return fdr_tee_surface_index (tee, 0); +} + +cairo_surface_t * +cairo_get_group_target (cairo_t *cr) +{ + cairo_surface_t *tee; + + tee = DLCALL (cairo_get_group_target, cr); + return fdr_tee_surface_index (tee, 0); +} + +cairo_pattern_t * +cairo_pattern_create_for_surface (cairo_surface_t *surface) +{ + cairo_surface_t *tee; + + tee = fdr_surface_get_tee (surface); + if (tee != NULL) + surface = tee; + + return DLCALL (cairo_pattern_create_for_surface, surface); +} + +cairo_status_t +cairo_pattern_get_surface (cairo_pattern_t *pattern, + cairo_surface_t **surface) +{ + cairo_status_t status; + cairo_surface_t *tee; + + status = DLCALL (cairo_pattern_get_surface, pattern, surface); + if (status != CAIRO_STATUS_SUCCESS) + return status; + + tee = fdr_surface_get_tee (*surface); + if (tee != NULL) + *surface = tee; + + return CAIRO_STATUS_SUCCESS; +} + +void +cairo_set_source_surface (cairo_t *cr, + cairo_surface_t *surface, + double x, double y) +{ + cairo_surface_t *tee; + + tee = fdr_surface_get_tee (surface); + if (tee != NULL) + surface = tee; + + DLCALL (cairo_set_source_surface, cr, surface, x, y); +} + +cairo_surface_t * +cairo_surface_create_similar (cairo_surface_t *surface, + cairo_content_t content, + int width, int height) +{ + cairo_surface_t *tee; + + tee = fdr_surface_get_tee (surface); + if (tee != NULL) + surface = tee; + + return DLCALL (cairo_surface_create_similar, + surface, content, width, height); +} + +cairo_surface_t * +cairo_surface_create_for_rectangle (cairo_surface_t *surface, + double x, + double y, + double width, + double height) +{ + cairo_surface_t *tee; + + tee = fdr_surface_get_tee (surface); + if (tee != NULL) + surface = tee; + + return DLCALL (cairo_surface_create_for_rectangle, + surface, x, y, width, height); +} diff --git a/local/recipes/libs/cairo/source/util/cairo-fdr/meson.build b/local/recipes/libs/cairo/source/util/cairo-fdr/meson.build new file mode 100644 index 0000000000..0d00e43f72 --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-fdr/meson.build @@ -0,0 +1,12 @@ +cairo_fdr_sources = [ + 'fdr.c', +] + +libcairofdr = library('cairo-fdr', cairo_fdr_sources, + include_directories: [incbase, incsrc], + dependencies: deps, + gnu_symbol_visibility: 'hidden', + link_args: extra_link_args, + install: true, + install_dir: get_option('libdir') / 'cairo', +) diff --git a/local/recipes/libs/cairo/source/util/cairo-gobject/cairo-gobject-enums.c b/local/recipes/libs/cairo/source/util/cairo-gobject/cairo-gobject-enums.c new file mode 100644 index 0000000000..cd3bb4b7a9 --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-gobject/cairo-gobject-enums.c @@ -0,0 +1,514 @@ + +/* Generated data (by glib-mkenums) */ + +#include "config.h" + +#include "cairo-gobject.h" + +GType +cairo_gobject_status_get_type (void) +{ + static gsize type_ret = 0; + if (g_once_init_enter (&type_ret)) { + static const GEnumValue values[] = { + { CAIRO_STATUS_SUCCESS, "CAIRO_STATUS_SUCCESS", "success" }, + { CAIRO_STATUS_NO_MEMORY, "CAIRO_STATUS_NO_MEMORY", "no-memory" }, + { CAIRO_STATUS_INVALID_RESTORE, "CAIRO_STATUS_INVALID_RESTORE", "invalid-restore" }, + { CAIRO_STATUS_INVALID_POP_GROUP, "CAIRO_STATUS_INVALID_POP_GROUP", "invalid-pop-group" }, + { CAIRO_STATUS_NO_CURRENT_POINT, "CAIRO_STATUS_NO_CURRENT_POINT", "no-current-point" }, + { CAIRO_STATUS_INVALID_MATRIX, "CAIRO_STATUS_INVALID_MATRIX", "invalid-matrix" }, + { CAIRO_STATUS_INVALID_STATUS, "CAIRO_STATUS_INVALID_STATUS", "invalid-status" }, + { CAIRO_STATUS_NULL_POINTER, "CAIRO_STATUS_NULL_POINTER", "null-pointer" }, + { CAIRO_STATUS_INVALID_STRING, "CAIRO_STATUS_INVALID_STRING", "invalid-string" }, + { CAIRO_STATUS_INVALID_PATH_DATA, "CAIRO_STATUS_INVALID_PATH_DATA", "invalid-path-data" }, + { CAIRO_STATUS_READ_ERROR, "CAIRO_STATUS_READ_ERROR", "read-error" }, + { CAIRO_STATUS_WRITE_ERROR, "CAIRO_STATUS_WRITE_ERROR", "write-error" }, + { CAIRO_STATUS_SURFACE_FINISHED, "CAIRO_STATUS_SURFACE_FINISHED", "surface-finished" }, + { CAIRO_STATUS_SURFACE_TYPE_MISMATCH, "CAIRO_STATUS_SURFACE_TYPE_MISMATCH", "surface-type-mismatch" }, + { CAIRO_STATUS_PATTERN_TYPE_MISMATCH, "CAIRO_STATUS_PATTERN_TYPE_MISMATCH", "pattern-type-mismatch" }, + { CAIRO_STATUS_INVALID_CONTENT, "CAIRO_STATUS_INVALID_CONTENT", "invalid-content" }, + { CAIRO_STATUS_INVALID_FORMAT, "CAIRO_STATUS_INVALID_FORMAT", "invalid-format" }, + { CAIRO_STATUS_INVALID_VISUAL, "CAIRO_STATUS_INVALID_VISUAL", "invalid-visual" }, + { CAIRO_STATUS_FILE_NOT_FOUND, "CAIRO_STATUS_FILE_NOT_FOUND", "file-not-found" }, + { CAIRO_STATUS_INVALID_DASH, "CAIRO_STATUS_INVALID_DASH", "invalid-dash" }, + { CAIRO_STATUS_INVALID_DSC_COMMENT, "CAIRO_STATUS_INVALID_DSC_COMMENT", "invalid-dsc-comment" }, + { CAIRO_STATUS_INVALID_INDEX, "CAIRO_STATUS_INVALID_INDEX", "invalid-index" }, + { CAIRO_STATUS_CLIP_NOT_REPRESENTABLE, "CAIRO_STATUS_CLIP_NOT_REPRESENTABLE", "clip-not-representable" }, + { CAIRO_STATUS_TEMP_FILE_ERROR, "CAIRO_STATUS_TEMP_FILE_ERROR", "temp-file-error" }, + { CAIRO_STATUS_INVALID_STRIDE, "CAIRO_STATUS_INVALID_STRIDE", "invalid-stride" }, + { CAIRO_STATUS_FONT_TYPE_MISMATCH, "CAIRO_STATUS_FONT_TYPE_MISMATCH", "font-type-mismatch" }, + { CAIRO_STATUS_USER_FONT_IMMUTABLE, "CAIRO_STATUS_USER_FONT_IMMUTABLE", "user-font-immutable" }, + { CAIRO_STATUS_USER_FONT_ERROR, "CAIRO_STATUS_USER_FONT_ERROR", "user-font-error" }, + { CAIRO_STATUS_NEGATIVE_COUNT, "CAIRO_STATUS_NEGATIVE_COUNT", "negative-count" }, + { CAIRO_STATUS_INVALID_CLUSTERS, "CAIRO_STATUS_INVALID_CLUSTERS", "invalid-clusters" }, + { CAIRO_STATUS_INVALID_SLANT, "CAIRO_STATUS_INVALID_SLANT", "invalid-slant" }, + { CAIRO_STATUS_INVALID_WEIGHT, "CAIRO_STATUS_INVALID_WEIGHT", "invalid-weight" }, + { CAIRO_STATUS_INVALID_SIZE, "CAIRO_STATUS_INVALID_SIZE", "invalid-size" }, + { CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED, "CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED", "user-font-not-implemented" }, + { CAIRO_STATUS_DEVICE_TYPE_MISMATCH, "CAIRO_STATUS_DEVICE_TYPE_MISMATCH", "device-type-mismatch" }, + { CAIRO_STATUS_DEVICE_ERROR, "CAIRO_STATUS_DEVICE_ERROR", "device-error" }, + { CAIRO_STATUS_INVALID_MESH_CONSTRUCTION, "CAIRO_STATUS_INVALID_MESH_CONSTRUCTION", "invalid-mesh-construction" }, + { CAIRO_STATUS_DEVICE_FINISHED, "CAIRO_STATUS_DEVICE_FINISHED", "device-finished" }, + { CAIRO_STATUS_JBIG2_GLOBAL_MISSING, "CAIRO_STATUS_JBIG2_GLOBAL_MISSING", "jbig2-global_missing" }, + { CAIRO_STATUS_PNG_ERROR, "CAIRO_STATUS_PNG_ERROR", "png-error" }, + { CAIRO_STATUS_FREETYPE_ERROR, "CAIRO_STATUS_FREETYPE_ERROR", "freetype-error" }, + { CAIRO_STATUS_LAST_STATUS, "CAIRO_STATUS_LAST_STATUS", "last-status" }, + { CAIRO_STATUS_WIN32_GDI_ERROR, "CAIRO_STATUS_WIN32_GDI_ERROR", "win32-gdi-error" }, + { 0, NULL, NULL } + }; + GType type = g_enum_register_static (g_intern_static_string ("cairo_status_t"), values); + + g_once_init_leave (&type_ret, type); + } + return type_ret; +} + +GType +cairo_gobject_content_get_type (void) +{ + static gsize type_ret = 0; + if (g_once_init_enter (&type_ret)) { + static const GEnumValue values[] = { + { CAIRO_CONTENT_COLOR, "CAIRO_CONTENT_COLOR", "color" }, + { CAIRO_CONTENT_ALPHA, "CAIRO_CONTENT_ALPHA", "alpha" }, + { CAIRO_CONTENT_COLOR_ALPHA, "CAIRO_CONTENT_COLOR_ALPHA", "color-alpha" }, + { 0, NULL, NULL } + }; + GType type = g_enum_register_static (g_intern_static_string ("cairo_content_t"), values); + + g_once_init_leave (&type_ret, type); + } + return type_ret; +} + +GType +cairo_gobject_operator_get_type (void) +{ + static gsize type_ret = 0; + if (g_once_init_enter (&type_ret)) { + static const GEnumValue values[] = { + { CAIRO_OPERATOR_CLEAR, "CAIRO_OPERATOR_CLEAR", "clear" }, + { CAIRO_OPERATOR_SOURCE, "CAIRO_OPERATOR_SOURCE", "source" }, + { CAIRO_OPERATOR_OVER, "CAIRO_OPERATOR_OVER", "over" }, + { CAIRO_OPERATOR_IN, "CAIRO_OPERATOR_IN", "in" }, + { CAIRO_OPERATOR_OUT, "CAIRO_OPERATOR_OUT", "out" }, + { CAIRO_OPERATOR_ATOP, "CAIRO_OPERATOR_ATOP", "atop" }, + { CAIRO_OPERATOR_DEST, "CAIRO_OPERATOR_DEST", "dest" }, + { CAIRO_OPERATOR_DEST_OVER, "CAIRO_OPERATOR_DEST_OVER", "dest-over" }, + { CAIRO_OPERATOR_DEST_IN, "CAIRO_OPERATOR_DEST_IN", "dest-in" }, + { CAIRO_OPERATOR_DEST_OUT, "CAIRO_OPERATOR_DEST_OUT", "dest-out" }, + { CAIRO_OPERATOR_DEST_ATOP, "CAIRO_OPERATOR_DEST_ATOP", "dest-atop" }, + { CAIRO_OPERATOR_XOR, "CAIRO_OPERATOR_XOR", "xor" }, + { CAIRO_OPERATOR_ADD, "CAIRO_OPERATOR_ADD", "add" }, + { CAIRO_OPERATOR_SATURATE, "CAIRO_OPERATOR_SATURATE", "saturate" }, + { CAIRO_OPERATOR_MULTIPLY, "CAIRO_OPERATOR_MULTIPLY", "multiply" }, + { CAIRO_OPERATOR_SCREEN, "CAIRO_OPERATOR_SCREEN", "screen" }, + { CAIRO_OPERATOR_OVERLAY, "CAIRO_OPERATOR_OVERLAY", "overlay" }, + { CAIRO_OPERATOR_DARKEN, "CAIRO_OPERATOR_DARKEN", "darken" }, + { CAIRO_OPERATOR_LIGHTEN, "CAIRO_OPERATOR_LIGHTEN", "lighten" }, + { CAIRO_OPERATOR_COLOR_DODGE, "CAIRO_OPERATOR_COLOR_DODGE", "color-dodge" }, + { CAIRO_OPERATOR_COLOR_BURN, "CAIRO_OPERATOR_COLOR_BURN", "color-burn" }, + { CAIRO_OPERATOR_HARD_LIGHT, "CAIRO_OPERATOR_HARD_LIGHT", "hard-light" }, + { CAIRO_OPERATOR_SOFT_LIGHT, "CAIRO_OPERATOR_SOFT_LIGHT", "soft-light" }, + { CAIRO_OPERATOR_DIFFERENCE, "CAIRO_OPERATOR_DIFFERENCE", "difference" }, + { CAIRO_OPERATOR_EXCLUSION, "CAIRO_OPERATOR_EXCLUSION", "exclusion" }, + { CAIRO_OPERATOR_HSL_HUE, "CAIRO_OPERATOR_HSL_HUE", "hsl-hue" }, + { CAIRO_OPERATOR_HSL_SATURATION, "CAIRO_OPERATOR_HSL_SATURATION", "hsl-saturation" }, + { CAIRO_OPERATOR_HSL_COLOR, "CAIRO_OPERATOR_HSL_COLOR", "hsl-color" }, + { CAIRO_OPERATOR_HSL_LUMINOSITY, "CAIRO_OPERATOR_HSL_LUMINOSITY", "hsl-luminosity" }, + { 0, NULL, NULL } + }; + GType type = g_enum_register_static (g_intern_static_string ("cairo_operator_t"), values); + + g_once_init_leave (&type_ret, type); + } + return type_ret; +} + +GType +cairo_gobject_antialias_get_type (void) +{ + static gsize type_ret = 0; + if (g_once_init_enter (&type_ret)) { + static const GEnumValue values[] = { + { CAIRO_ANTIALIAS_DEFAULT, "CAIRO_ANTIALIAS_DEFAULT", "default" }, + + { CAIRO_ANTIALIAS_NONE, "CAIRO_ANTIALIAS_NONE", "none" }, + { CAIRO_ANTIALIAS_GRAY, "CAIRO_ANTIALIAS_GRAY", "gray" }, + { CAIRO_ANTIALIAS_SUBPIXEL, "CAIRO_ANTIALIAS_SUBPIXEL", "subpixel" }, + + { CAIRO_ANTIALIAS_FAST, "CAIRO_ANTIALIAS_FAST", "fast" }, + { CAIRO_ANTIALIAS_GOOD, "CAIRO_ANTIALIAS_GOOD", "good" }, + { CAIRO_ANTIALIAS_BEST, "CAIRO_ANTIALIAS_BEST", "best" }, + + { 0, NULL, NULL } + }; + GType type = g_enum_register_static (g_intern_static_string ("cairo_antialias_t"), values); + + g_once_init_leave (&type_ret, type); + } + return type_ret; +} + +GType +cairo_gobject_fill_rule_get_type (void) +{ + static gsize type_ret = 0; + if (g_once_init_enter (&type_ret)) { + static const GEnumValue values[] = { + { CAIRO_FILL_RULE_WINDING, "CAIRO_FILL_RULE_WINDING", "winding" }, + { CAIRO_FILL_RULE_EVEN_ODD, "CAIRO_FILL_RULE_EVEN_ODD", "even-odd" }, + { 0, NULL, NULL } + }; + GType type = g_enum_register_static (g_intern_static_string ("cairo_fill_rule_t"), values); + + g_once_init_leave (&type_ret, type); + } + return type_ret; +} + +GType +cairo_gobject_line_cap_get_type (void) +{ + static gsize type_ret = 0; + if (g_once_init_enter (&type_ret)) { + static const GEnumValue values[] = { + { CAIRO_LINE_CAP_BUTT, "CAIRO_LINE_CAP_BUTT", "butt" }, + { CAIRO_LINE_CAP_ROUND, "CAIRO_LINE_CAP_ROUND", "round" }, + { CAIRO_LINE_CAP_SQUARE, "CAIRO_LINE_CAP_SQUARE", "square" }, + { 0, NULL, NULL } + }; + GType type = g_enum_register_static (g_intern_static_string ("cairo_line_cap_t"), values); + + g_once_init_leave (&type_ret, type); + } + return type_ret; +} + +GType +cairo_gobject_line_join_get_type (void) +{ + static gsize type_ret = 0; + if (g_once_init_enter (&type_ret)) { + static const GEnumValue values[] = { + { CAIRO_LINE_JOIN_MITER, "CAIRO_LINE_JOIN_MITER", "miter" }, + { CAIRO_LINE_JOIN_ROUND, "CAIRO_LINE_JOIN_ROUND", "round" }, + { CAIRO_LINE_JOIN_BEVEL, "CAIRO_LINE_JOIN_BEVEL", "bevel" }, + { 0, NULL, NULL } + }; + GType type = g_enum_register_static (g_intern_static_string ("cairo_line_join_t"), values); + + g_once_init_leave (&type_ret, type); + } + return type_ret; +} + +GType +cairo_gobject_text_cluster_flags_get_type (void) +{ + static gsize type_ret = 0; + if (g_once_init_enter (&type_ret)) { + static const GEnumValue values[] = { + { CAIRO_TEXT_CLUSTER_FLAG_BACKWARD, "CAIRO_TEXT_CLUSTER_FLAG_BACKWARD", "backward" }, + { 0, NULL, NULL } + }; + GType type = g_enum_register_static (g_intern_static_string ("cairo_text_cluster_flags_t"), values); + + g_once_init_leave (&type_ret, type); + } + return type_ret; +} + +GType +cairo_gobject_font_slant_get_type (void) +{ + static gsize type_ret = 0; + if (g_once_init_enter (&type_ret)) { + static const GEnumValue values[] = { + { CAIRO_FONT_SLANT_NORMAL, "CAIRO_FONT_SLANT_NORMAL", "normal" }, + { CAIRO_FONT_SLANT_ITALIC, "CAIRO_FONT_SLANT_ITALIC", "italic" }, + { CAIRO_FONT_SLANT_OBLIQUE, "CAIRO_FONT_SLANT_OBLIQUE", "oblique" }, + { 0, NULL, NULL } + }; + GType type = g_enum_register_static (g_intern_static_string ("cairo_font_slant_t"), values); + + g_once_init_leave (&type_ret, type); + } + return type_ret; +} + +GType +cairo_gobject_font_weight_get_type (void) +{ + static gsize type_ret = 0; + if (g_once_init_enter (&type_ret)) { + static const GEnumValue values[] = { + { CAIRO_FONT_WEIGHT_NORMAL, "CAIRO_FONT_WEIGHT_NORMAL", "normal" }, + { CAIRO_FONT_WEIGHT_BOLD, "CAIRO_FONT_WEIGHT_BOLD", "bold" }, + { 0, NULL, NULL } + }; + GType type = g_enum_register_static (g_intern_static_string ("cairo_font_weight_t"), values); + + g_once_init_leave (&type_ret, type); + } + return type_ret; +} + +GType +cairo_gobject_subpixel_order_get_type (void) +{ + static gsize type_ret = 0; + if (g_once_init_enter (&type_ret)) { + static const GEnumValue values[] = { + { CAIRO_SUBPIXEL_ORDER_DEFAULT, "CAIRO_SUBPIXEL_ORDER_DEFAULT", "default" }, + { CAIRO_SUBPIXEL_ORDER_RGB, "CAIRO_SUBPIXEL_ORDER_RGB", "rgb" }, + { CAIRO_SUBPIXEL_ORDER_BGR, "CAIRO_SUBPIXEL_ORDER_BGR", "bgr" }, + { CAIRO_SUBPIXEL_ORDER_VRGB, "CAIRO_SUBPIXEL_ORDER_VRGB", "vrgb" }, + { CAIRO_SUBPIXEL_ORDER_VBGR, "CAIRO_SUBPIXEL_ORDER_VBGR", "vbgr" }, + { 0, NULL, NULL } + }; + GType type = g_enum_register_static (g_intern_static_string ("cairo_subpixel_order_t"), values); + + g_once_init_leave (&type_ret, type); + } + return type_ret; +} + +GType +cairo_gobject_hint_style_get_type (void) +{ + static gsize type_ret = 0; + if (g_once_init_enter (&type_ret)) { + static const GEnumValue values[] = { + { CAIRO_HINT_STYLE_DEFAULT, "CAIRO_HINT_STYLE_DEFAULT", "default" }, + { CAIRO_HINT_STYLE_NONE, "CAIRO_HINT_STYLE_NONE", "none" }, + { CAIRO_HINT_STYLE_SLIGHT, "CAIRO_HINT_STYLE_SLIGHT", "slight" }, + { CAIRO_HINT_STYLE_MEDIUM, "CAIRO_HINT_STYLE_MEDIUM", "medium" }, + { CAIRO_HINT_STYLE_FULL, "CAIRO_HINT_STYLE_FULL", "full" }, + { 0, NULL, NULL } + }; + GType type = g_enum_register_static (g_intern_static_string ("cairo_hint_style_t"), values); + + g_once_init_leave (&type_ret, type); + } + return type_ret; +} + +GType +cairo_gobject_hint_metrics_get_type (void) +{ + static gsize type_ret = 0; + if (g_once_init_enter (&type_ret)) { + static const GEnumValue values[] = { + { CAIRO_HINT_METRICS_DEFAULT, "CAIRO_HINT_METRICS_DEFAULT", "default" }, + { CAIRO_HINT_METRICS_OFF, "CAIRO_HINT_METRICS_OFF", "off" }, + { CAIRO_HINT_METRICS_ON, "CAIRO_HINT_METRICS_ON", "on" }, + { 0, NULL, NULL } + }; + GType type = g_enum_register_static (g_intern_static_string ("cairo_hint_metrics_t"), values); + + g_once_init_leave (&type_ret, type); + } + return type_ret; +} + +GType +cairo_gobject_font_type_get_type (void) +{ + static gsize type_ret = 0; + if (g_once_init_enter (&type_ret)) { + static const GEnumValue values[] = { + { CAIRO_FONT_TYPE_TOY, "CAIRO_FONT_TYPE_TOY", "toy" }, + { CAIRO_FONT_TYPE_FT, "CAIRO_FONT_TYPE_FT", "ft" }, + { CAIRO_FONT_TYPE_WIN32, "CAIRO_FONT_TYPE_WIN32", "win32" }, + { CAIRO_FONT_TYPE_QUARTZ, "CAIRO_FONT_TYPE_QUARTZ", "quartz" }, + { CAIRO_FONT_TYPE_USER, "CAIRO_FONT_TYPE_USER", "user" }, + { 0, NULL, NULL } + }; + GType type = g_enum_register_static (g_intern_static_string ("cairo_font_type_t"), values); + + g_once_init_leave (&type_ret, type); + } + return type_ret; +} + +GType +cairo_gobject_path_data_type_get_type (void) +{ + static gsize type_ret = 0; + if (g_once_init_enter (&type_ret)) { + static const GEnumValue values[] = { + { CAIRO_PATH_MOVE_TO, "CAIRO_PATH_MOVE_TO", "move-to" }, + { CAIRO_PATH_LINE_TO, "CAIRO_PATH_LINE_TO", "line-to" }, + { CAIRO_PATH_CURVE_TO, "CAIRO_PATH_CURVE_TO", "curve-to" }, + { CAIRO_PATH_CLOSE_PATH, "CAIRO_PATH_CLOSE_PATH", "close-path" }, + { 0, NULL, NULL } + }; + GType type = g_enum_register_static (g_intern_static_string ("cairo_path_data_type_t"), values); + + g_once_init_leave (&type_ret, type); + } + return type_ret; +} + +GType +cairo_gobject_device_type_get_type (void) +{ + static gsize type_ret = 0; + if (g_once_init_enter (&type_ret)) { + static const GEnumValue values[] = { + { CAIRO_DEVICE_TYPE_DRM, "CAIRO_DEVICE_TYPE_DRM", "drm" }, + { CAIRO_DEVICE_TYPE_GL, "CAIRO_DEVICE_TYPE_GL", "gl" }, + { CAIRO_DEVICE_TYPE_SCRIPT, "CAIRO_DEVICE_TYPE_SCRIPT", "script" }, + { CAIRO_DEVICE_TYPE_XCB, "CAIRO_DEVICE_TYPE_XCB", "xcb" }, + { CAIRO_DEVICE_TYPE_XLIB, "CAIRO_DEVICE_TYPE_XLIB", "xlib" }, + { CAIRO_DEVICE_TYPE_XML, "CAIRO_DEVICE_TYPE_XML", "xml" }, + { 0, NULL, NULL } + }; + GType type = g_enum_register_static (g_intern_static_string ("cairo_device_type_t"), values); + + g_once_init_leave (&type_ret, type); + } + return type_ret; +} + +GType +cairo_gobject_surface_type_get_type (void) +{ + static gsize type_ret = 0; + if (g_once_init_enter (&type_ret)) { + static const GEnumValue values[] = { + { CAIRO_SURFACE_TYPE_IMAGE, "CAIRO_SURFACE_TYPE_IMAGE", "image" }, + { CAIRO_SURFACE_TYPE_PDF, "CAIRO_SURFACE_TYPE_PDF", "pdf" }, + { CAIRO_SURFACE_TYPE_PS, "CAIRO_SURFACE_TYPE_PS", "ps" }, + { CAIRO_SURFACE_TYPE_XLIB, "CAIRO_SURFACE_TYPE_XLIB", "xlib" }, + { CAIRO_SURFACE_TYPE_XCB, "CAIRO_SURFACE_TYPE_XCB", "xcb" }, + { CAIRO_SURFACE_TYPE_GLITZ, "CAIRO_SURFACE_TYPE_GLITZ", "glitz" }, + { CAIRO_SURFACE_TYPE_QUARTZ, "CAIRO_SURFACE_TYPE_QUARTZ", "quartz" }, + { CAIRO_SURFACE_TYPE_WIN32, "CAIRO_SURFACE_TYPE_WIN32", "win32" }, + { CAIRO_SURFACE_TYPE_BEOS, "CAIRO_SURFACE_TYPE_BEOS", "beos" }, + { CAIRO_SURFACE_TYPE_DIRECTFB, "CAIRO_SURFACE_TYPE_DIRECTFB", "directfb" }, + { CAIRO_SURFACE_TYPE_SVG, "CAIRO_SURFACE_TYPE_SVG", "svg" }, + { CAIRO_SURFACE_TYPE_OS2, "CAIRO_SURFACE_TYPE_OS2", "os2" }, + { CAIRO_SURFACE_TYPE_WIN32_PRINTING, "CAIRO_SURFACE_TYPE_WIN32_PRINTING", "win32-printing" }, + { CAIRO_SURFACE_TYPE_QUARTZ_IMAGE, "CAIRO_SURFACE_TYPE_QUARTZ_IMAGE", "quartz-image" }, + { CAIRO_SURFACE_TYPE_SCRIPT, "CAIRO_SURFACE_TYPE_SCRIPT", "script" }, + { CAIRO_SURFACE_TYPE_QT, "CAIRO_SURFACE_TYPE_QT", "qt" }, + { CAIRO_SURFACE_TYPE_RECORDING, "CAIRO_SURFACE_TYPE_RECORDING", "recording" }, + { CAIRO_SURFACE_TYPE_VG, "CAIRO_SURFACE_TYPE_VG", "vg" }, + { CAIRO_SURFACE_TYPE_GL, "CAIRO_SURFACE_TYPE_GL", "gl" }, + { CAIRO_SURFACE_TYPE_DRM, "CAIRO_SURFACE_TYPE_DRM", "drm" }, + { CAIRO_SURFACE_TYPE_TEE, "CAIRO_SURFACE_TYPE_TEE", "tee" }, + { CAIRO_SURFACE_TYPE_XML, "CAIRO_SURFACE_TYPE_XML", "xml" }, + { CAIRO_SURFACE_TYPE_SKIA, "CAIRO_SURFACE_TYPE_SKIA", "skia" }, + { 0, NULL, NULL } + }; + GType type = g_enum_register_static (g_intern_static_string ("cairo_surface_type_t"), values); + + g_once_init_leave (&type_ret, type); + } + return type_ret; +} + +GType +cairo_gobject_format_get_type (void) +{ + static gsize type_ret = 0; + if (g_once_init_enter (&type_ret)) { + static const GEnumValue values[] = { + { CAIRO_FORMAT_INVALID, "CAIRO_FORMAT_INVALID", "invalid" }, + { CAIRO_FORMAT_ARGB32, "CAIRO_FORMAT_ARGB32", "argb32" }, + { CAIRO_FORMAT_RGB24, "CAIRO_FORMAT_RGB24", "rgb24" }, + { CAIRO_FORMAT_A8, "CAIRO_FORMAT_A8", "a8" }, + { CAIRO_FORMAT_A1, "CAIRO_FORMAT_A1", "a1" }, + { CAIRO_FORMAT_RGB16_565, "CAIRO_FORMAT_RGB16_565", "rgb16-565" }, + { 0, NULL, NULL } + }; + GType type = g_enum_register_static (g_intern_static_string ("cairo_format_t"), values); + + g_once_init_leave (&type_ret, type); + } + return type_ret; +} + +GType +cairo_gobject_pattern_type_get_type (void) +{ + static gsize type_ret = 0; + if (g_once_init_enter (&type_ret)) { + static const GEnumValue values[] = { + { CAIRO_PATTERN_TYPE_SOLID, "CAIRO_PATTERN_TYPE_SOLID", "solid" }, + { CAIRO_PATTERN_TYPE_SURFACE, "CAIRO_PATTERN_TYPE_SURFACE", "surface" }, + { CAIRO_PATTERN_TYPE_LINEAR, "CAIRO_PATTERN_TYPE_LINEAR", "linear" }, + { CAIRO_PATTERN_TYPE_RADIAL, "CAIRO_PATTERN_TYPE_RADIAL", "radial" }, + { CAIRO_PATTERN_TYPE_MESH, "CAIRO_PATTERN_TYPE_MESH", "mesh" }, + { 0, NULL, NULL } + }; + GType type = g_enum_register_static (g_intern_static_string ("cairo_pattern_type_t"), values); + + g_once_init_leave (&type_ret, type); + } + return type_ret; +} + +GType +cairo_gobject_extend_get_type (void) +{ + static gsize type_ret = 0; + if (g_once_init_enter (&type_ret)) { + static const GEnumValue values[] = { + { CAIRO_EXTEND_NONE, "CAIRO_EXTEND_NONE", "none" }, + { CAIRO_EXTEND_REPEAT, "CAIRO_EXTEND_REPEAT", "repeat" }, + { CAIRO_EXTEND_REFLECT, "CAIRO_EXTEND_REFLECT", "reflect" }, + { CAIRO_EXTEND_PAD, "CAIRO_EXTEND_PAD", "pad" }, + { 0, NULL, NULL } + }; + GType type = g_enum_register_static (g_intern_static_string ("cairo_extend_t"), values); + + g_once_init_leave (&type_ret, type); + } + return type_ret; +} + +GType +cairo_gobject_filter_get_type (void) +{ + static gsize type_ret = 0; + if (g_once_init_enter (&type_ret)) { + static const GEnumValue values[] = { + { CAIRO_FILTER_FAST, "CAIRO_FILTER_FAST", "fast" }, + { CAIRO_FILTER_GOOD, "CAIRO_FILTER_GOOD", "good" }, + { CAIRO_FILTER_BEST, "CAIRO_FILTER_BEST", "best" }, + { CAIRO_FILTER_NEAREST, "CAIRO_FILTER_NEAREST", "nearest" }, + { CAIRO_FILTER_BILINEAR, "CAIRO_FILTER_BILINEAR", "bilinear" }, + { CAIRO_FILTER_GAUSSIAN, "CAIRO_FILTER_GAUSSIAN", "gaussian" }, + { 0, NULL, NULL } + }; + GType type = g_enum_register_static (g_intern_static_string ("cairo_filter_t"), values); + + g_once_init_leave (&type_ret, type); + } + return type_ret; +} + +GType +cairo_gobject_region_overlap_get_type (void) +{ + static gsize type_ret = 0; + if (g_once_init_enter (&type_ret)) { + static const GEnumValue values[] = { + { CAIRO_REGION_OVERLAP_IN, "CAIRO_REGION_OVERLAP_IN", "in" }, + { CAIRO_REGION_OVERLAP_OUT, "CAIRO_REGION_OVERLAP_OUT", "out" }, + { CAIRO_REGION_OVERLAP_PART, "CAIRO_REGION_OVERLAP_PART", "part" }, + { 0, NULL, NULL } + }; + GType type = g_enum_register_static (g_intern_static_string ("cairo_region_overlap_t"), values); + + g_once_init_leave (&type_ret, type); + } + return type_ret; +} + + +/* Generated data ends here */ + diff --git a/local/recipes/libs/cairo/source/util/cairo-gobject/cairo-gobject-structs.c b/local/recipes/libs/cairo/source/util/cairo-gobject/cairo-gobject-structs.c new file mode 100644 index 0000000000..bb8e96ac8d --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-gobject/cairo-gobject-structs.c @@ -0,0 +1,100 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2010 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Benjamin Otte + */ + +#include "config.h" + +#include "cairo-gobject.h" + +#define CAIRO_DEFINE_BOXED(Name,underscore_name,copy_func,free_func) \ +GType \ +underscore_name ## _get_type (void) \ +{ \ + static gsize type_ret = 0; \ + if (g_once_init_enter (&type_ret)) { \ + GType type = g_boxed_type_register_static (g_intern_static_string (Name), \ + (GBoxedCopyFunc)copy_func, \ + (GBoxedFreeFunc)free_func); \ + g_once_init_leave (&type_ret, type); \ + } \ + return type_ret; \ +} + +CAIRO_DEFINE_BOXED ("CairoContext", cairo_gobject_context, + cairo_reference, cairo_destroy); +CAIRO_DEFINE_BOXED ("CairoDevice", cairo_gobject_device, + cairo_device_reference, cairo_device_destroy); +CAIRO_DEFINE_BOXED ("CairoPattern", cairo_gobject_pattern, + cairo_pattern_reference, cairo_pattern_destroy); +CAIRO_DEFINE_BOXED ("CairoSurface", cairo_gobject_surface, + cairo_surface_reference, cairo_surface_destroy); +CAIRO_DEFINE_BOXED ("CairoScaledFont", cairo_gobject_scaled_font, + cairo_scaled_font_reference, cairo_scaled_font_destroy); +CAIRO_DEFINE_BOXED ("CairoFontFace", cairo_gobject_font_face, + cairo_font_face_reference, cairo_font_face_destroy); +CAIRO_DEFINE_BOXED ("CairoFontOptions", cairo_gobject_font_options, + cairo_font_options_copy, cairo_font_options_destroy); +CAIRO_DEFINE_BOXED ("CairoRegion", cairo_gobject_region, + cairo_region_reference, cairo_region_destroy); + +#if GLIB_CHECK_VERSION(2, 68, 0) +#define COPY_FUNC(name) \ +static gpointer \ +cairo_gobject_cairo_ ## name ## _copy (gpointer src) { \ + return g_memdup2 (src, sizeof (cairo_ ## name ## _t)); \ +} +#else +#define COPY_FUNC(name) \ +static gpointer \ +cairo_gobject_cairo_ ## name ## _copy (gpointer src) { \ + return g_memdup (src, sizeof (cairo_ ## name ## _t)); \ +} +#endif + +COPY_FUNC (matrix) +CAIRO_DEFINE_BOXED ("CairoMatrix", cairo_gobject_matrix, + cairo_gobject_cairo_matrix_copy, g_free); +COPY_FUNC (rectangle) +CAIRO_DEFINE_BOXED ("CairoRectangle", cairo_gobject_rectangle, + cairo_gobject_cairo_rectangle_copy, g_free); +COPY_FUNC (rectangle_int) +CAIRO_DEFINE_BOXED ("CairoRectangleInt", cairo_gobject_rectangle_int, + cairo_gobject_cairo_rectangle_int_copy, g_free); +COPY_FUNC (glyph) +CAIRO_DEFINE_BOXED ("CairoGlyph", cairo_gobject_glyph, + cairo_gobject_cairo_glyph_copy, g_free); +COPY_FUNC (text_cluster) +CAIRO_DEFINE_BOXED ("CairoTextCluster", cairo_gobject_text_cluster, + cairo_gobject_cairo_text_cluster_copy, g_free); diff --git a/local/recipes/libs/cairo/source/util/cairo-gobject/cairo-gobject.h b/local/recipes/libs/cairo/source/util/cairo-gobject/cairo-gobject.h new file mode 100644 index 0000000000..28aa51c8b9 --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-gobject/cairo-gobject.h @@ -0,0 +1,200 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2010 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is University of Southern + * California. + * + * Contributor(s): + * Benjamin Otte + */ + +#ifndef CAIRO_GOBJECT_H +#define CAIRO_GOBJECT_H + +#include + +#if CAIRO_HAS_GOBJECT_FUNCTIONS + +#include + +CAIRO_BEGIN_DECLS + +/* structs */ + +#define CAIRO_GOBJECT_TYPE_CONTEXT cairo_gobject_context_get_type () +cairo_public GType +cairo_gobject_context_get_type (void); + +#define CAIRO_GOBJECT_TYPE_DEVICE cairo_gobject_device_get_type () +cairo_public GType +cairo_gobject_device_get_type (void); + +#define CAIRO_GOBJECT_TYPE_MATRIX cairo_gobject_matrix_get_type () +cairo_public GType +cairo_gobject_matrix_get_type (void); + +#define CAIRO_GOBJECT_TYPE_PATTERN cairo_gobject_pattern_get_type () +cairo_public GType +cairo_gobject_pattern_get_type (void); + +#define CAIRO_GOBJECT_TYPE_SURFACE cairo_gobject_surface_get_type () +cairo_public GType +cairo_gobject_surface_get_type (void); + +#define CAIRO_GOBJECT_TYPE_RECTANGLE cairo_gobject_rectangle_get_type () +cairo_public GType +cairo_gobject_rectangle_get_type (void); + +#define CAIRO_GOBJECT_TYPE_SCALED_FONT cairo_gobject_scaled_font_get_type () +cairo_public GType +cairo_gobject_scaled_font_get_type (void); + +#define CAIRO_GOBJECT_TYPE_FONT_FACE cairo_gobject_font_face_get_type () +cairo_public GType +cairo_gobject_font_face_get_type (void); + +#define CAIRO_GOBJECT_TYPE_FONT_OPTIONS cairo_gobject_font_options_get_type () +cairo_public GType +cairo_gobject_font_options_get_type (void); + +#define CAIRO_GOBJECT_TYPE_RECTANGLE_INT cairo_gobject_rectangle_int_get_type () +cairo_public GType +cairo_gobject_rectangle_int_get_type (void); + +#define CAIRO_GOBJECT_TYPE_REGION cairo_gobject_region_get_type () +cairo_public GType +cairo_gobject_region_get_type (void); + +#define CAIRO_GOBJECT_TYPE_GLYPH cairo_gobject_glyph_get_type () +cairo_public GType +cairo_gobject_glyph_get_type (void); + +#define CAIRO_GOBJECT_TEXT_CLUSTER_GLYPH cairo_gobject_text_cluster_get_type () +cairo_public GType +cairo_gobject_text_cluster_get_type (void); + +/* enums */ + +#define CAIRO_GOBJECT_TYPE_STATUS cairo_gobject_status_get_type () +cairo_public GType +cairo_gobject_status_get_type (void); + +#define CAIRO_GOBJECT_TYPE_CONTENT cairo_gobject_content_get_type () +cairo_public GType +cairo_gobject_content_get_type (void); + +#define CAIRO_GOBJECT_TYPE_OPERATOR cairo_gobject_operator_get_type () +cairo_public GType +cairo_gobject_operator_get_type (void); + +#define CAIRO_GOBJECT_TYPE_ANTIALIAS cairo_gobject_antialias_get_type () +cairo_public GType +cairo_gobject_antialias_get_type (void); + +#define CAIRO_GOBJECT_TYPE_FILL_RULE cairo_gobject_fill_rule_get_type () +cairo_public GType +cairo_gobject_fill_rule_get_type (void); + +#define CAIRO_GOBJECT_TYPE_LINE_CAP cairo_gobject_line_cap_get_type () +cairo_public GType +cairo_gobject_line_cap_get_type (void); + +#define CAIRO_GOBJECT_TYPE_LINE_JOIN cairo_gobject_line_join_get_type () +cairo_public GType +cairo_gobject_line_join_get_type (void); + +#define CAIRO_GOBJECT_TYPE_TEXT_CLUSTER_FLAGS cairo_gobject_text_cluster_flags_get_type () +cairo_public GType +cairo_gobject_text_cluster_flags_get_type (void); + +#define CAIRO_GOBJECT_TYPE_FONT_SLANT cairo_gobject_font_slant_get_type () +cairo_public GType +cairo_gobject_font_slant_get_type (void); + +#define CAIRO_GOBJECT_TYPE_FONT_WEIGHT cairo_gobject_font_weight_get_type () +cairo_public GType +cairo_gobject_font_weight_get_type (void); + +#define CAIRO_GOBJECT_TYPE_SUBPIXEL_ORDER cairo_gobject_subpixel_order_get_type () +cairo_public GType +cairo_gobject_subpixel_order_get_type (void); + +#define CAIRO_GOBJECT_TYPE_HINT_STYLE cairo_gobject_hint_style_get_type () +cairo_public GType +cairo_gobject_hint_style_get_type (void); + +/* historical accident */ +#define CAIRO_GOBJECT_TYPE_HNT_METRICS cairo_gobject_hint_metrics_get_type () +#define CAIRO_GOBJECT_TYPE_HINT_METRICS cairo_gobject_hint_metrics_get_type () +cairo_public GType +cairo_gobject_hint_metrics_get_type (void); + +#define CAIRO_GOBJECT_TYPE_FONT_TYPE cairo_gobject_font_type_get_type () +cairo_public GType +cairo_gobject_font_type_get_type (void); + +#define CAIRO_GOBJECT_TYPE_PATH_DATA_TYPE cairo_gobject_path_data_type_get_type () +cairo_public GType +cairo_gobject_path_data_type_get_type (void); + +#define CAIRO_GOBJECT_TYPE_DEVICE_TYPE cairo_gobject_device_type_get_type () +cairo_public GType +cairo_gobject_device_type_get_type (void); + +#define CAIRO_GOBJECT_TYPE_SURFACE_TYPE cairo_gobject_surface_type_get_type () +cairo_public GType +cairo_gobject_surface_type_get_type (void); + +#define CAIRO_GOBJECT_TYPE_FORMAT cairo_gobject_format_get_type () +cairo_public GType +cairo_gobject_format_get_type (void); + +#define CAIRO_GOBJECT_TYPE_PATTERN_TYPE cairo_gobject_pattern_type_get_type () +cairo_public GType +cairo_gobject_pattern_type_get_type (void); + +#define CAIRO_GOBJECT_TYPE_EXTEND cairo_gobject_extend_get_type () +cairo_public GType +cairo_gobject_extend_get_type (void); + +#define CAIRO_GOBJECT_TYPE_FILTER cairo_gobject_filter_get_type () +cairo_public GType +cairo_gobject_filter_get_type (void); + +#define CAIRO_GOBJECT_TYPE_REGION_OVERLAP cairo_gobject_region_overlap_get_type () +cairo_public GType +cairo_gobject_region_overlap_get_type (void); + +CAIRO_END_DECLS + +#else /* CAIRO_HAS_GOBJECT_FUNCTIONS */ +# error Cairo was not compiled with support for GObject +#endif /* CAIRO_HAS_GOBJECT_FUNCTIONS */ + +#endif /* CAIRO_GOBJECT_H */ diff --git a/local/recipes/libs/cairo/source/util/cairo-gobject/meson.build b/local/recipes/libs/cairo/source/util/cairo-gobject/meson.build new file mode 100644 index 0000000000..660088771e --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-gobject/meson.build @@ -0,0 +1,33 @@ +cairo_gobject_sources = [ + 'cairo-gobject-enums.c', + 'cairo-gobject-structs.c', +] + +cairo_gobject_headers = [ + 'cairo-gobject.h', +] + +libcairogobject = library('cairo-gobject', cairo_gobject_sources, + include_directories: [incbase], + dependencies: [glib_dep, gobject_dep, libcairo_dep], + soversion: cairo_version_sonum, + version: cairo_libversion, + gnu_symbol_visibility: 'hidden', + c_args: ['-DCAIRO_COMPILATION'], + link_args: extra_link_args, + install: true, +) + +libcairogobject_dep = declare_dependency(link_with: libcairogobject, + include_directories: include_directories('.'), + dependencies: libcairo_dep) + +pkgmod.generate(libcairogobject, + libraries: [libcairo, glib_dep, gobject_dep], + description: 'cairo-gobject for cairo graphics library', + subdirs: [meson.project_name()], +) + +meson.override_dependency('cairo-gobject', libcairogobject_dep) + +install_headers(cairo_gobject_headers, subdir: 'cairo') diff --git a/local/recipes/libs/cairo/source/util/cairo-missing/cairo-missing.h b/local/recipes/libs/cairo/source/util/cairo-missing/cairo-missing.h new file mode 100644 index 0000000000..5d947163f9 --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-missing/cairo-missing.h @@ -0,0 +1,58 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2006 Red Hat, Inc. + * Copyright © 2011 Andrea Canciani + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of the + * copyright holders not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * + * Authors: Carl Worth + * Andrea Canciani + */ + +#ifndef CAIRO_MISSING_H +#define CAIRO_MISSING_H + +#include "cairo-compiler-private.h" + +#include +#include +#include + +#ifdef _WIN32 +#include + +#if !defined(_SSIZE_T_DEFINED) && !defined(_SSIZE_T_) +typedef SSIZE_T ssize_t; +#endif +#endif + +#ifndef HAVE_GETLINE +cairo_private ssize_t +getline (char **lineptr, size_t *n, FILE *stream); +#endif + +#ifndef HAVE_STRNDUP +cairo_private char * +strndup (const char *s, size_t n); +#endif + +#endif diff --git a/local/recipes/libs/cairo/source/util/cairo-missing/getline.c b/local/recipes/libs/cairo/source/util/cairo-missing/getline.c new file mode 100644 index 0000000000..8585cfdc2d --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-missing/getline.c @@ -0,0 +1,90 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2006 Red Hat, Inc. + * Copyright © 2011 Andrea Canciani + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of the + * copyright holders not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * + * Authors: Carl Worth + * Andrea Canciani + */ + +#include "cairo-missing.h" + +#ifndef HAVE_GETLINE +#include "cairo-malloc-private.h" + +#define GETLINE_MIN_BUFFER_SIZE 128 +ssize_t +getline (char **lineptr, + size_t *n, + FILE *stream) +{ + char *line, *tmpline; + size_t len, offset; + ssize_t ret; + + offset = 0; + len = *n; + line = *lineptr; + if (len < GETLINE_MIN_BUFFER_SIZE) { + len = GETLINE_MIN_BUFFER_SIZE; + line = NULL; + } + + if (line == NULL) { + line = (char *) _cairo_malloc (len); + if (unlikely (line == NULL)) + return -1; + } + + while (1) { + if (offset + 1 == len) { + tmpline = (char *) _cairo_realloc_ab (line, len, 2); + if (unlikely (tmpline == NULL)) { + if (line != *lineptr) + free (line); + return -1; + } + len *= 2; + line = tmpline; + } + + ret = getc (stream); + if (ret == -1) + break; + + line[offset++] = ret; + if (ret == '\n') { + ret = offset; + break; + } + } + + line[offset++] = '\0'; + *lineptr = line; + *n = len; + + return ret; +} +#undef GETLINE_BUFFER_SIZE +#endif diff --git a/local/recipes/libs/cairo/source/util/cairo-missing/meson.build b/local/recipes/libs/cairo/source/util/cairo-missing/meson.build new file mode 100644 index 0000000000..3280b03fe2 --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-missing/meson.build @@ -0,0 +1,15 @@ +cairo_missing_sources = [ + 'strndup.c', + 'getline.c', +] + +libcairomissing = static_library('cairo-missing', cairo_missing_sources, + include_directories: [incbase, incsrc], + install: false, + build_by_default: false, +) + +libcairomissing_dep = declare_dependency( + link_with: libcairomissing, + include_directories: include_directories('.'), +) diff --git a/local/recipes/libs/cairo/source/util/cairo-missing/strndup.c b/local/recipes/libs/cairo/source/util/cairo-missing/strndup.c new file mode 100644 index 0000000000..049802b769 --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-missing/strndup.c @@ -0,0 +1,61 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2006 Red Hat, Inc. + * Copyright © 2011 Andrea Canciani + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of the + * copyright holders not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * + * Authors: Carl Worth + * Andrea Canciani + */ + +#include "cairo-missing.h" + +#ifndef HAVE_STRNDUP +#include "cairo-malloc-private.h" + +char * +strndup (const char *s, + size_t n) +{ + const char *end; + size_t len; + char *sdup; + + if (s == NULL) + return NULL; + + end = memchr (s, 0, n); + if (end) + len = end - s; + else + len = n; + + sdup = (char *) _cairo_malloc (len + 1); + if (sdup != NULL) { + memcpy (sdup, s, len); + sdup[len] = '\0'; + } + + return sdup; +} +#endif diff --git a/local/recipes/libs/cairo/source/util/cairo-script/.gitignore b/local/recipes/libs/cairo/source/util/cairo-script/.gitignore new file mode 100644 index 0000000000..8ecaee3e57 --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-script/.gitignore @@ -0,0 +1,3 @@ +csi-replay +csi-exec +csi-trace diff --git a/local/recipes/libs/cairo/source/util/cairo-script/COPYING b/local/recipes/libs/cairo/source/util/cairo-script/COPYING new file mode 100644 index 0000000000..66ad7840fb --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-script/COPYING @@ -0,0 +1,17 @@ +Cairo is free software. + +Every source file in the implementation of cairo is available to be +redistributed and/or modified under the terms of either the GNU Lesser +General Public License (LGPL) version 2.1 or the Mozilla Public +License (MPL) version 1.1. Some files are available under more +liberal terms, but we believe that in all cases, each file may be used +under either the LGPL or the MPL. + +See the following files in this directory for the precise terms and +conditions of either license: + + COPYING-LGPL-2.1 + COPYING-MPL-1.1 + +Please see each file in the implementation for copyright and licensing +information, (in the opening comment of each file). diff --git a/local/recipes/libs/cairo/source/util/cairo-script/cairo-script-file.c b/local/recipes/libs/cairo/source/util/cairo-script/cairo-script-file.c new file mode 100644 index 0000000000..c45cc5086d --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-script/cairo-script-file.c @@ -0,0 +1,1110 @@ +/* + * Copyright © 2008 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Chris Wilson. + * + * Contributor(s): + * Chris Wilson + */ + +#include "config.h" + +#include "cairo-script-private.h" + +#include +#include /* INT_MAX */ +#include +#include + +#if HAVE_LZO +#include +#endif + +#define CHUNK_SIZE 32768 + +#define OWN_STREAM 0x1 + +csi_status_t +csi_file_new (csi_t *ctx, + csi_object_t *obj, + const char *path, const char *mode) +{ + csi_file_t *file; + + file = _csi_slab_alloc (ctx, sizeof (csi_file_t)); + if (file == NULL) + return _csi_error (CAIRO_STATUS_NO_MEMORY); + + file->base.type = CSI_OBJECT_TYPE_FILE; + file->base.ref = 1; + + file->data = NULL; + file->type = STDIO; + file->flags = OWN_STREAM; + file->src = fopen (path, mode); + if (file->src == NULL) { + _csi_slab_free (ctx, file, sizeof (csi_file_t)); + return _csi_error (CAIRO_STATUS_FILE_NOT_FOUND); + } + + file->data = _csi_alloc (ctx, CHUNK_SIZE); + if (file->data == NULL) { + _csi_slab_free (ctx, file, sizeof (csi_file_t)); + return _csi_error (CAIRO_STATUS_NO_MEMORY); + } + file->bp = file->data; + file->rem = 0; + + obj->type = CSI_OBJECT_TYPE_FILE; + obj->datum.file = file; + return CAIRO_STATUS_SUCCESS; +} + +csi_status_t +csi_file_new_for_stream (csi_t *ctx, + csi_object_t *obj, + FILE *stream) +{ + csi_file_t *file; + + file = _csi_slab_alloc (ctx, sizeof (csi_file_t)); + if (file == NULL) + return _csi_error (CAIRO_STATUS_NO_MEMORY); + + file->base.type = CSI_OBJECT_TYPE_FILE; + file->base.ref = 1; + + file->data = NULL; + file->type = STDIO; + file->flags = 0; + file->src = stream; + if (file->src == NULL) { + _csi_slab_free (ctx, file, sizeof (csi_file_t)); + return _csi_error (CAIRO_STATUS_FILE_NOT_FOUND); + } + + file->data = _csi_alloc (ctx, CHUNK_SIZE); + if (file->data == NULL) { + _csi_slab_free (ctx, file, sizeof (csi_file_t)); + return _csi_error (CAIRO_STATUS_NO_MEMORY); + } + file->bp = file->data; + file->rem = 0; + + obj->type = CSI_OBJECT_TYPE_FILE; + obj->datum.file = file; + return CAIRO_STATUS_SUCCESS; +} + +csi_status_t +csi_file_new_for_bytes (csi_t *ctx, + csi_object_t *obj, + const char *bytes, + unsigned int length) +{ + csi_file_t *file; + + file = _csi_slab_alloc (ctx, sizeof (csi_file_t)); + if (file == NULL) + return _csi_error (CAIRO_STATUS_NO_MEMORY); + + file->base.type = CSI_OBJECT_TYPE_FILE; + file->base.ref = 1; + + file->type = BYTES; + file->src = (uint8_t *) bytes; + file->data = (uint8_t *) bytes; + file->bp = (uint8_t *) bytes; + file->rem = length; + + obj->type = CSI_OBJECT_TYPE_FILE; + obj->datum.file = file; + return CAIRO_STATUS_SUCCESS; +} + +csi_status_t +csi_file_new_from_string (csi_t *ctx, + csi_object_t *obj, + csi_string_t *src) +{ + csi_file_t *file; + + file = _csi_slab_alloc (ctx, sizeof (csi_file_t)); + if (_csi_unlikely (file == NULL)) + return _csi_error (CAIRO_STATUS_NO_MEMORY); + + file->base.type = CSI_OBJECT_TYPE_FILE; + file->base.ref = 1; + + if (src->deflate) { + uLongf len = src->deflate; + csi_object_t tmp_obj; + csi_string_t *tmp_str; + csi_status_t status; + + status = csi_string_new (ctx, &tmp_obj, NULL, src->deflate); + if (_csi_unlikely (status)) + return status; + + tmp_str = tmp_obj.datum.string; + switch (src->method) { + case NONE: + default: + status = _csi_error (CAIRO_STATUS_NO_MEMORY); + break; + + case ZLIB: +#if HAVE_ZLIB + if (uncompress ((Bytef *) tmp_str->string, &len, + (Bytef *) src->string, src->len) != Z_OK) +#endif + status = _csi_error (CAIRO_STATUS_NO_MEMORY); + break; + case LZO: +#if HAVE_LZO + if (lzo2a_decompress ((lzo_bytep) src->string, src->len, + (lzo_bytep) tmp_str->string, &len, + NULL)) +#endif + status = _csi_error (CAIRO_STATUS_NO_MEMORY); + break; + } + if (_csi_unlikely (status)) { + csi_string_free (ctx, tmp_str); + _csi_slab_free (ctx, file, sizeof (csi_file_t)); + return status; + } + + file->src = tmp_str; + file->data = tmp_str->string; + file->rem = tmp_str->len; + } else { + file->src = src; src->base.ref++; + file->data = src->string; + file->rem = src->len; + } + file->type = BYTES; + file->bp = file->data; + + obj->type = CSI_OBJECT_TYPE_FILE; + obj->datum.file = file; + return CAIRO_STATUS_SUCCESS; +} + +static csi_status_t +_csi_file_new_filter (csi_t *ctx, + csi_object_t *obj, + csi_object_t *src, + const csi_filter_funcs_t *funcs, + void *data) +{ + csi_file_t *file; + csi_object_t src_file; + csi_status_t status; + + file = _csi_slab_alloc (ctx, sizeof (csi_file_t)); + if (file == NULL) + return _csi_error (CAIRO_STATUS_NO_MEMORY); + + obj->type = CSI_OBJECT_TYPE_FILE; + obj->datum.file = file; + + file->base.type = CSI_OBJECT_TYPE_FILE; + file->base.ref = 1; + + file->type = FILTER; + file->data = data; + file->filter = funcs; + status = csi_object_as_file (ctx, src, &src_file); + if (status) { + csi_object_free (ctx, obj); + return status; + } + file->src = src_file.datum.file; + + return CAIRO_STATUS_SUCCESS; +} + + +#if 0 +csi_status_t +csi_file_new_from_stream (csi_t *ctx, + FILE *file, + csi_object_t **out) +{ + csi_file_t *obj; + + obj = (csi_file_t *) _csi_object_new (ctx, CSI_OBJECT_TYPE_FILE); + if (obj == NULL) + return _csi_error (CAIRO_STATUS_NO_MEMORY); + + obj->type = STDIO; + obj->src = file; + obj->data = _csi_alloc (ctx, CHUNK_SIZE); + if (obj->data == NULL) { + csi_object_free (&obj->base); + return _csi_error (CAIRO_STATUS_UNDEFINED_FILENAME_ERROR); + } + obj->bp = obj->data; + obj->rem = 0; + + *out = &obj->base; + return CAIRO_STATUS_SUCCESS; +} + +static csi_object_t * +_csi_file_new_from_procedure (csi_t *ctx, csi_object_t *src) +{ + csi_file_t *obj; + + obj = (csi_file_t *) _csi_object_new (ctx, CSI_OBJECT_TYPE_FILE); + if (obj == NULL) + return NULL; + + obj->type = PROCEDURE; + obj->src = csi_object_reference (src); + obj->data = NULL; + + return &obj->base; +} +#endif + +typedef struct _ascii85_decode_data { + uint8_t buf[CHUNK_SIZE]; + uint8_t *bp; + short bytes_available; + short eod; +} _ascii85_decode_data_t; + +static int +_getc_skip_whitespace (csi_file_t *src) +{ + int c; + + do switch ((c = csi_file_getc (src))) { + case 0x0: + case 0x9: + case 0xa: + case 0xc: + case 0xd: + case 0x20: + continue; + + default: + return c; + } while (TRUE); + + return c; +} + +static void +_ascii85_decode (csi_file_t *file) +{ + _ascii85_decode_data_t *data = file->data; + unsigned int n; + + if (data->eod) + return; + + data->bp = data->buf; + + n = 0; + do { + unsigned int v = _getc_skip_whitespace (file->src); + if (v == 'z') { + data->buf[n+0] = 0; + data->buf[n+1] = 0; + data->buf[n+2] = 0; + data->buf[n+3] = 0; + } else if (v == '~') { + _getc_skip_whitespace (file->src); /* == '>' || IO_ERROR */ + data->eod = TRUE; + break; + } else if (v < '!' || v > 'u') { + /* IO_ERROR */ + data->eod = TRUE; + break; + } else { + unsigned int i; + + v -= '!'; + for (i = 1; i < 5; i++) { + int c = _getc_skip_whitespace (file->src); + if (c == '~') { /* short tuple */ + _getc_skip_whitespace (file->src); /* == '>' || IO_ERROR */ + data->eod = TRUE; + switch (i) { + case 0: + case 1: + /* IO_ERROR */ + break; + case 2: + v = v * (85*85*85) + 85*85*85 -1; + goto odd1; + case 3: + v = v * (85*85) + 85*85 -1; + goto odd2; + case 4: + v = v * 85 + 84; + data->buf[n+2] = v >> 8 & 0xff; +odd2: + data->buf[n+1] = v >> 16 & 0xff; +odd1: + data->buf[n+0] = v >> 24 & 0xff; + data->bytes_available = n + i - 1; + return; + } + break; + } + v = 85*v + c-'!'; + } + + data->buf[n+0] = v >> 24 & 0xff; + data->buf[n+1] = v >> 16 & 0xff; + data->buf[n+2] = v >> 8 & 0xff; + data->buf[n+3] = v >> 0 & 0xff; + } + n += 4; + } while (n < sizeof (data->buf) && data->eod == FALSE); + + data->bytes_available = n; +} + +static int +_ascii85_decode_getc (csi_file_t *file) +{ + _ascii85_decode_data_t *data = file->data; + + if (data->bytes_available == 0) { + _ascii85_decode (file); + + if (data->bytes_available == 0) + return EOF; + } + + data->bytes_available--; + return *data->bp++; +} + +static void +_ascii85_decode_putc (csi_file_t *file, int c) +{ + _ascii85_decode_data_t *data = file->data; + data->bytes_available++; + data->bp--; +} + +static int +_ascii85_decode_read (csi_file_t *file, uint8_t *buf, int len) +{ + _ascii85_decode_data_t *data = file->data; + + if (data->bytes_available == 0) { + _ascii85_decode (file); + + if (data->bytes_available == 0) + return 0; + } + + if (len > data->bytes_available) + len = data->bytes_available; + memcpy (buf, data->bp, len); + data->bp += len; + data->bytes_available -= len; + return len; +} + +csi_status_t +csi_file_new_ascii85_decode (csi_t *ctx, + csi_object_t *obj, + csi_dictionary_t *dict, + csi_object_t *src) +{ + static const csi_filter_funcs_t funcs = { + _ascii85_decode_getc, + _ascii85_decode_putc, + _ascii85_decode_read, + _csi_free, + }; + _ascii85_decode_data_t *data; + + data = _csi_alloc0 (ctx, sizeof (_ascii85_decode_data_t)); + if (data == NULL) + return _csi_error (CAIRO_STATUS_NO_MEMORY); + + return _csi_file_new_filter (ctx, obj, src, &funcs, data); +} + +#if HAVE_ZLIB +#include + +typedef struct _deflate_decode_data { + z_stream zlib_stream; + + uint8_t in[CHUNK_SIZE]; + uint8_t out[CHUNK_SIZE]; + + int bytes_available; + uint8_t *bp; +} _deflate_decode_data_t; + +static void +_deflate_decode (csi_file_t *file) +{ + _deflate_decode_data_t *data = file->data; + uint8_t *bp; + int len; + + data->zlib_stream.next_out = data->out; + data->zlib_stream.avail_out = sizeof (data->out); + + bp = data->in; + len = sizeof (data->in); + if (data->zlib_stream.avail_in) { + memmove (data->in, + data->zlib_stream.next_in, + data->zlib_stream.avail_in); + len -= data->zlib_stream.avail_in; + bp += data->zlib_stream.avail_in; + } + + len = csi_file_read (file->src, bp, len); + + data->zlib_stream.next_in = data->in; + data->zlib_stream.avail_in += len; + + inflate (&data->zlib_stream, len == 0 ? Z_FINISH : Z_NO_FLUSH); + + data->bytes_available = data->zlib_stream.next_out - data->out; + data->bp = data->out; +} + +static int +_deflate_decode_getc (csi_file_t *file) +{ + _deflate_decode_data_t *data = file->data; + + if (data->bytes_available == 0) { + _deflate_decode (file); + + if (data->bytes_available == 0) + return EOF; + } + + data->bytes_available--; + return *data->bp++; +} + +static void +_deflate_decode_putc (csi_file_t *file, int c) +{ + _deflate_decode_data_t *data = file->data; + data->bytes_available++; + data->bp--; +} + +static int +_deflate_decode_read (csi_file_t *file, uint8_t *buf, int len) +{ + _deflate_decode_data_t *data = file->data; + + if (data->bytes_available == 0) { + _deflate_decode (file); + + if (data->bytes_available == 0) + return 0; + } + + if (len > (int) data->bytes_available) + len = data->bytes_available; + memcpy (buf, data->bp, len); + data->bp += len; + data->bytes_available -= len; + return len; +} + +static void +_deflate_destroy (csi_t *ctx, void *closure) +{ + _deflate_decode_data_t *data; + + data = closure; + + inflateEnd (&data->zlib_stream); + + _csi_free (ctx, data); +} + +csi_status_t +csi_file_new_deflate_decode (csi_t *ctx, + csi_object_t *obj, + csi_dictionary_t *dict, + csi_object_t *src) +{ + static const csi_filter_funcs_t funcs = { + _deflate_decode_getc, + _deflate_decode_putc, + _deflate_decode_read, + _deflate_destroy, + }; + _deflate_decode_data_t *data; + + data = _csi_alloc (ctx, sizeof (_deflate_decode_data_t)); + if (data == NULL) + return _csi_error (CAIRO_STATUS_NO_MEMORY); + + data->zlib_stream.zalloc = Z_NULL; + data->zlib_stream.zfree = Z_NULL; + data->zlib_stream.opaque = Z_NULL; + data->zlib_stream.next_in = data->in; + data->zlib_stream.avail_in = 0; + data->zlib_stream.next_out = data->out; + data->zlib_stream.avail_out = sizeof (data->out); + data->bytes_available = 0; + + if (inflateInit (&data->zlib_stream) != Z_OK) { + _csi_free (ctx, data); + return _csi_error (CAIRO_STATUS_NO_MEMORY); + } + + return _csi_file_new_filter (ctx, obj, src, &funcs, data); +} +#endif + +#if 0 +static int +hex_value (int c) +{ + if (c < '0') + return EOF; + if (c <= '9') + return c - '0'; + c |= 32; + if (c < 'a') + return EOF; + if (c <= 'f') + return c - 'a' + 0xa; + return EOF; +} + +/* Adobe Type 1 Font Format book: p63 */ +typedef struct _decrypt_data { + uint8_t putback[32]; + uint8_t nputback; + csi_bool_t is_hexadecimal; + unsigned short R; + int eod; +} _decrypt_data_t; + +static uint8_t +_decrypt (unsigned short *R, uint8_t cypher) +{ +#define c1 52845 +#define c2 22719 + uint8_t plain; + + plain = cypher ^ (*R >> 8); + *R = (cypher + *R) * c1 + c2; + return plain; +#undef c1 +#undef c2 +} + +int +csi_decrypt (uint8_t *in, int length, + unsigned short salt, int binary, + uint8_t *out) +{ + const uint8_t * const end = in + length; + uint8_t *base = out; + + while (in < end) { + int c; + + if (! binary) { + int c_hi = -1, c_lo = 0; + + while (in < end && (c_hi = *in++)) { + switch (c_hi) { + case 0x0: + case 0x9: + case 0xa: + case 0xc: + case 0xd: + case 0x20: + continue; + + default: + break; + } + } + if (c_hi < 0) + break; + + while (in < end && (c_lo = *in++)) { + switch (c_lo) { + case 0x0: + case 0x9: + case 0xa: + case 0xc: + case 0xd: + case 0x20: + continue; + + default: + break; + } + } + + c = (hex_value (c_hi) << 4) | hex_value (c_lo); + } else + c = *in++; + + *out++ = _decrypt (&salt, c); + } + + return out - base; +} + +static uint8_t +_encrypt (unsigned short *R, uint8_t plain) +{ +#define c1 52845 +#define c2 22719 + uint8_t cypher; + + cypher = plain ^ (*R >> 8); + *R = (cypher + *R) * c1 + c2; + return cypher; +#undef c1 +#undef c2 +} + +int +csi_encrypt (uint8_t *in, int length, + unsigned short salt, int discard, int binary, + uint8_t *out) +{ + const char hex[]="0123456789abcdef"; + const uint8_t * const end = in + length; + uint8_t *base = out; + int col = 0; + + while (discard--) { + if (! binary) { + int c = _encrypt (&salt, ' '); + *out++ = hex[(c >> 4) & 0xf]; + *out++ = hex[(c >> 0) & 0xf]; + } else + *out++ = _encrypt (&salt, 0); + } + + while (in < end) { + int c; + + c = _encrypt (&salt, *in++); + if (! binary) { + if (col == 78) { + *out++ = '\n'; + col = 0; + } + *out++ = hex[(c >> 4) & 0xf]; + *out++ = hex[(c >> 0) & 0xf]; + col += 2; + } else + *out++ = c; + } + + return out - base; +} + +static int +_decrypt_getc (csi_file_t *file) +{ + _decrypt_data_t *data = file->data; + int c; + + if (data->nputback) + return data->putback[--data->nputback]; + + if (data->is_hexadecimal) { + int c_hi, c_lo; + + c_hi = _getc_skip_whitespace (file->src); + c_lo = _getc_skip_whitespace (file->src); + c = (hex_value (c_hi) << 4) | hex_value (c_lo); + } else + c = csi_file_getc (file->src); + + if (c == EOF) + return EOF; + + return _decrypt (&data->R, c); +} + +static void +_decrypt_putc (csi_file_t *file, int c) +{ + _decrypt_data_t *data; + + data = file->data; + + data->putback[data->nputback++] = c; +} + +csi_object_t * +csi_file_new_decrypt (csi_t *ctx, csi_object_t *src, int salt, int discard) +{ + csi_object_t *obj; + _decrypt_data_t *data; + int n; + + data = _csi_alloc0 (ctx, sizeof (_decrypt_data_t)); + if (data == NULL) + return NULL; + + data->R = salt; + + obj = _csi_file_new_filter (ctx, src, + _decrypt_getc, + _decrypt_putc, + NULL, + _csi_free, + data); + if (obj == NULL) + return NULL; + + /* XXX determine encoding, eexec only? */ + data->is_hexadecimal = salt != 4330; + for (n = 0; n < discard; n++) { + int c; + c = csi_file_getc (obj); + if (c == EOF) { + return obj; + } + } + return obj; +} +#endif + +csi_status_t +_csi_file_execute (csi_t *ctx, csi_file_t *obj) +{ + return _csi_scan_file (ctx, obj); +} + +int +csi_file_getc (csi_file_t *file) +{ + int c; + + if (_csi_unlikely (file->src == NULL)) + return EOF; + + switch (file->type) { + case STDIO: + if (_csi_likely (file->rem)) { + c = *file->bp++; + file->rem--; + } else { + file->rem = fread (file->bp = file->data, 1, CHUNK_SIZE, file->src); + /* fall through */ + case BYTES: + if (_csi_likely (file->rem)) { + c = *file->bp++; + file->rem--; + } else + c = EOF; + } + break; + + case PROCEDURE: +#if 0 + if (file->data == NULL) { + csi_status_t status; + csi_object_t *string; + +RERUN_PROCEDURE: + status = csi_object_execute (file->src); + if (status) + return EOF; + + string = csi_pop_operand (file->base.ctx); + if (string == NULL) + return EOF; + file->data = csi_object_as_file (file->base.ctx, string); + csi_object_free (string); + if (file->data == NULL) + return EOF; + } + c = csi_file_getc (file->data); + if (c == EOF) { + csi_object_free (file->data); + file->data = NULL; + goto RERUN_PROCEDURE; + } +#else + c = EOF; +#endif + break; + + case FILTER: + c = file->filter->filter_getc (file); + break; + + default: + c = EOF; + break; + } + + return c; +} + +int +csi_file_read (csi_file_t *file, void *buf, int len) +{ + int ret; + + if (file->src == NULL) + return 0; + + switch (file->type) { + case STDIO: + if (file->rem > 0) { + ret = len; + if (file->rem < ret) + ret = file->rem; + memcpy (buf, file->bp, ret); + file->bp += ret; + file->rem -= ret; + } else + ret = fread (buf, 1, len, file->src); + break; + + case BYTES: + if (file->rem > 0) { + ret = len; + if (file->rem < ret) + ret = file->rem; + memcpy (buf, file->bp, ret); + file->bp += ret; + file->rem -= ret; + } else + ret = 0; + break; + + case PROCEDURE: +#if 0 + if (file->data == NULL) { + csi_status_t status; + csi_object_t *string; + +RERUN_PROCEDURE: + status = csi_object_execute (file->src); + if (status) + return 0; + + string = csi_pop_operand (file->base.ctx); + if (string == NULL) + return 0; + file->data = csi_object_as_file (file->base.ctx, string); + csi_object_free (string); + if (file->data == NULL) + return 0; + } + ret = csi_file_read (file->data, buf, len); + if (ret == 0) { + csi_object_free (file->data); + file->data = NULL; + goto RERUN_PROCEDURE; + } +#else + ret = 0; +#endif + break; + + case FILTER: + ret = file->filter->filter_read (file, buf, len); + break; + + default: + ret = 0; + break; + } + + return ret; +} + +void +csi_file_putc (csi_file_t *file, int c) +{ + if (file->src == NULL) + return; + + switch ((int) file->type) { + case STDIO: + case BYTES: + file->bp--; + file->rem++; + break; + case FILTER: + file->filter->filter_putc (file, c); + break; + default: + break; + } +} + +void +csi_file_flush (csi_file_t *file) +{ + if (file->src == NULL) + return; + + switch ((int) file->type) { + case FILTER: /* need to eat EOD */ + while (csi_file_getc (file) != EOF) + ; + break; + default: + break; + } +} + +void +csi_file_close (csi_t *ctx, csi_file_t *file) +{ + if (file->src == NULL) + return; + + switch (file->type) { + case STDIO: + if (file->flags & OWN_STREAM) + fclose (file->src); + break; + case BYTES: + if (file->src != file->data) { + csi_string_t *src = file->src; + if (src != NULL && --src->base.ref == 0) + csi_string_free (ctx, src); + } + break; + case FILTER: + { + csi_file_t *src = file->src; + if (src != NULL && --src->base.ref == 0) + _csi_file_free (ctx, src); + } + break; + case PROCEDURE: + default: + break; + } + file->src = NULL; +} + +void +_csi_file_free (csi_t *ctx, csi_file_t *file) +{ + csi_file_flush (file); + /* XXX putback */ + csi_file_close (ctx, file); + + switch (file->type) { + case BYTES: + break; + case PROCEDURE: +#if 0 + csi_object_free (ctx, file->data); +#endif + break; + case STDIO: + _csi_free (ctx, file->data); + break; + case FILTER: + file->filter->filter_destroy (ctx, file->data); + break; + default: + break; + } + + _csi_slab_free (ctx, file, sizeof (csi_file_t)); +} + +csi_status_t +_csi_file_as_string (csi_t *ctx, + csi_file_t *file, + csi_object_t *obj) +{ + char *bytes; + unsigned int len; + unsigned int allocated; + csi_status_t status; + + allocated = 16384; + bytes = _csi_alloc (ctx, allocated); + if (bytes == NULL) + return _csi_error (CAIRO_STATUS_NO_MEMORY); + + len = 0; + do { + int ret; + + ret = csi_file_read (file, bytes + len, allocated - len); + if (ret == 0) + break; + + len += ret; + if (len + 1 > allocated / 2) { + char *newbytes; + int newlen; + + if (_csi_unlikely (allocated > INT_MAX / 2)) + return _csi_error (CAIRO_STATUS_NO_MEMORY); + + newlen = allocated * 2; + newbytes = _csi_realloc (ctx, bytes, newlen); + if (_csi_unlikely (newbytes == NULL)) { + _csi_free (ctx, bytes); + return _csi_error (CAIRO_STATUS_NO_MEMORY); + } + bytes = newbytes; + allocated = newlen; + } + } while (TRUE); + + bytes[len] = '\0'; /* better safe than sorry! */ + status = csi_string_new_from_bytes (ctx, obj, bytes, len); + if (status) { + _csi_free (ctx, bytes); + return status; + } + + return CAIRO_STATUS_SUCCESS; +} + diff --git a/local/recipes/libs/cairo/source/util/cairo-script/cairo-script-hash.c b/local/recipes/libs/cairo/source/util/cairo-script/cairo-script-hash.c new file mode 100644 index 0000000000..dbda407bc6 --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-script/cairo-script-hash.c @@ -0,0 +1,484 @@ +/* + * Copyright © 2004 Red Hat, Inc. + * Copyright © 2005 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Keith Packard + * Graydon Hoare + * Carl Worth + * Karl Tomlinson , Mozilla Corporation + */ + +#include "config.h" + +#include "cairo-script-private.h" + +#include + +/* + * An entry can be in one of three states: + * + * FREE: Entry has never been used, terminates all searches. + * Appears in the table as a %NULL pointer. + * + * DEAD: Entry had been live in the past. A dead entry can be reused + * but does not terminate a search for an exact entry. + * Appears in the table as a pointer to DEAD_ENTRY. + * + * LIVE: Entry is currently being used. + * Appears in the table as any non-%NULL, non-DEAD_ENTRY pointer. + */ + +#define DEAD_ENTRY ((csi_hash_entry_t *) 0x1) + +#define ENTRY_IS_FREE(entry) ((entry) == NULL) +#define ENTRY_IS_DEAD(entry) ((entry) == DEAD_ENTRY) +#define ENTRY_IS_LIVE(entry) ((entry) > DEAD_ENTRY) + + +/* This table is open-addressed with double hashing. Each table size is a + * prime chosen to be a little more than double the high water mark for a + * given arrangement, so the tables should remain < 50% full. The table + * size makes for the "first" hash modulus; a second prime (2 less than the + * first prime) serves as the "second" hash modulus, which is co-prime and + * thus guarantees a complete permutation of table indices. + * + * This structure, and accompanying table, is borrowed/modified from the + * file xserver/render/glyph.c in the freedesktop.org x server, with + * permission (and suggested modification of doubling sizes) by Keith + * Packard. + */ + +static const csi_hash_table_arrangement_t hash_table_arrangements [] = { + { 16, 43, 41 }, + { 32, 73, 71 }, + { 64, 151, 149 }, + { 128, 283, 281 }, + { 256, 571, 569 }, + { 512, 1153, 1151 }, + { 1024, 2269, 2267 }, + { 2048, 4519, 4517 }, + { 4096, 9013, 9011 }, + { 8192, 18043, 18041 }, + { 16384, 36109, 36107 }, + { 32768, 72091, 72089 }, + { 65536, 144409, 144407 }, + { 131072, 288361, 288359 }, + { 262144, 576883, 576881 }, + { 524288, 1153459, 1153457 }, + { 1048576, 2307163, 2307161 }, + { 2097152, 4613893, 4613891 }, + { 4194304, 9227641, 9227639 }, + { 8388608, 18455029, 18455027 }, + { 16777216, 36911011, 36911009 }, + { 33554432, 73819861, 73819859 }, + { 67108864, 147639589, 147639587 }, + { 134217728, 295279081, 295279079 }, + { 268435456, 590559793, 590559791 } +}; + +#define NUM_HASH_TABLE_ARRANGEMENTS ARRAY_LENGTH (hash_table_arrangements) + +/** + * _csi_hash_table_create: + * @keys_equal: a function to return %TRUE if two keys are equal + * + * Creates a new hash table which will use the keys_equal() function + * to compare hash keys. Data is provided to the hash table in the + * form of user-derived versions of #csi_hash_entry_t. A hash entry + * must be able to hold both a key (including a hash code) and a + * value. Sometimes only the key will be necessary, (as in + * _csi_hash_table_remove), and other times both a key and a value + * will be necessary, (as in _csi_hash_table_insert). + * + * See #csi_hash_entry_t for more details. + * + * Return value: the new hash table or %NULL if out of memory. + **/ +csi_status_t +_csi_hash_table_init (csi_hash_table_t *hash_table, + csi_hash_keys_equal_func_t keys_equal) +{ + hash_table->keys_equal = keys_equal; + + hash_table->arrangement = &hash_table_arrangements[0]; + + hash_table->entries = calloc (hash_table->arrangement->size, + sizeof(csi_hash_entry_t *)); + if (hash_table->entries == NULL) + return _csi_error (CAIRO_STATUS_NO_MEMORY); + + hash_table->live_entries = 0; + hash_table->used_entries = 0; + hash_table->iterating = 0; + + return CSI_STATUS_SUCCESS; +} + +/** + * _csi_hash_table_destroy: + * @hash_table: an empty hash table to destroy + * + * Immediately destroys the given hash table, freeing all resources + * associated with it. + * + * WARNING: The hash_table must have no live entries in it before + * _csi_hash_table_destroy is called. It is a fatal error otherwise, + * and this function will halt. The rationale for this behavior is to + * avoid memory leaks and to avoid needless complication of the API + * with destroy notify callbacks. + * + * WARNING: The hash_table must have no running iterators in it when + * _csi_hash_table_destroy is called. It is a fatal error otherwise, + * and this function will halt. + **/ +void +_csi_hash_table_fini (csi_hash_table_t *hash_table) +{ + free (hash_table->entries); +} + +static csi_hash_entry_t ** +_csi_hash_table_lookup_unique_key (csi_hash_table_t *hash_table, + csi_hash_entry_t *key) +{ + unsigned long table_size, i, idx, step; + csi_hash_entry_t **entry; + + table_size = hash_table->arrangement->size; + idx = key->hash % table_size; + + entry = &hash_table->entries[idx]; + if (! ENTRY_IS_LIVE (*entry)) + return entry; + + i = 1; + step = key->hash % hash_table->arrangement->rehash; + if (step == 0) + step = 1; + do { + idx += step; + if (idx >= table_size) + idx -= table_size; + + entry = &hash_table->entries[idx]; + if (! ENTRY_IS_LIVE (*entry)) + return entry; + } while (++i < table_size); + + return NULL; +} + +/** + * _csi_hash_table_manage: + * @hash_table: a hash table + * + * Resize the hash table if the number of entries has gotten much + * bigger or smaller than the ideal number of entries for the current + * size, or control the number of dead entries by moving the entries + * within the table. + * + * Return value: %CAIRO_STATUS_SUCCESS if successful or + * %CAIRO_STATUS_NO_MEMORY if out of memory. + **/ +static csi_status_t +_csi_hash_table_manage (csi_hash_table_t *hash_table) +{ + csi_hash_table_t tmp; + csi_boolean_t realloc = TRUE; + unsigned long i; + + /* This keeps the size of the hash table between 2 and approximately 8 + * times the number of live entries and keeps the proportion of free + * entries (search-terminations) > 25%. + */ + unsigned long high = hash_table->arrangement->high_water_mark; + unsigned long low = high >> 2; + unsigned long max_used = high + high / 2; + + tmp = *hash_table; + + if (hash_table->live_entries > high) { + tmp.arrangement = hash_table->arrangement + 1; + /* This code is being abused if we can't make a table big enough. */ + } else if (hash_table->live_entries < low && + /* Can't shrink if we're at the smallest size */ + hash_table->arrangement != &hash_table_arrangements[0]) + { + tmp.arrangement = hash_table->arrangement - 1; + } + else if (hash_table->used_entries > max_used) + { + /* Clean out dead entries to prevent lookups from becoming too slow. */ + for (i = 0; i < hash_table->arrangement->size; ++i) { + if (ENTRY_IS_DEAD (hash_table->entries[i])) + hash_table->entries[i] = NULL; + } + hash_table->used_entries = hash_table->live_entries; + + /* There is no need to reallocate but some entries may need to be + * moved. Typically the proportion of entries needing to be moved is + * small, but, if the moving should leave a large number of dead + * entries, they will be cleaned out next time this code is + * executed. */ + realloc = FALSE; + } + else + { + return CAIRO_STATUS_SUCCESS; + } + + if (realloc) { + tmp.entries = calloc (tmp.arrangement->size, + sizeof (csi_hash_entry_t*)); + if (tmp.entries == NULL) + return _csi_error (CAIRO_STATUS_NO_MEMORY); + + hash_table->used_entries = 0; + } + + for (i = 0; i < hash_table->arrangement->size; ++i) { + csi_hash_entry_t *entry, **pos; + + entry = hash_table->entries[i]; + if (ENTRY_IS_LIVE (entry)) { + hash_table->entries[i] = DEAD_ENTRY; + + pos = _csi_hash_table_lookup_unique_key (&tmp, entry); + if (ENTRY_IS_FREE (*pos)) + hash_table->used_entries++; + + *pos = entry; + } + } + + if (realloc) { + free (hash_table->entries); + hash_table->entries = tmp.entries; + hash_table->arrangement = tmp.arrangement; + } + + return CAIRO_STATUS_SUCCESS; +} + +/** + * _csi_hash_table_lookup: + * @hash_table: a hash table + * @key: the key of interest + * + * Performs a lookup in @hash_table looking for an entry which has a + * key that matches @key, (as determined by the keys_equal() function + * passed to _csi_hash_table_create). + * + * Return value: the matching entry, of %NULL if no match was found. + **/ +void * +_csi_hash_table_lookup (csi_hash_table_t *hash_table, + csi_hash_entry_t *key) +{ + csi_hash_entry_t **entry; + unsigned long table_size, i, idx, step; + + table_size = hash_table->arrangement->size; + idx = key->hash % table_size; + entry = &hash_table->entries[idx]; + + if (ENTRY_IS_LIVE (*entry)) { + if ((*entry)->hash == key->hash && hash_table->keys_equal (key, *entry)) + return *entry; + } else if (ENTRY_IS_FREE (*entry)) + return NULL; + + i = 1; + step = key->hash % hash_table->arrangement->rehash; + if (step == 0) + step = 1; + do { + idx += step; + if (idx >= table_size) + idx -= table_size; + + entry = &hash_table->entries[idx]; + if (ENTRY_IS_LIVE (*entry)) { + if ((*entry)->hash == key->hash && + hash_table->keys_equal (key, *entry)) + { + return *entry; + } + } else if (ENTRY_IS_FREE (*entry)) + return NULL; + } while (++i < table_size); + + return NULL; +} + +/** + * _csi_hash_table_insert: + * @hash_table: a hash table + * @key_and_value: an entry to be inserted + * + * Insert the entry #key_and_value into the hash table. + * + * WARNING: There must not be an existing entry in the hash table + * with a matching key. + * + * WARNING: It is a fatal error to insert an element while + * an iterator is running + * + * Instead of using insert to replace an entry, consider just editing + * the entry obtained with _csi_hash_table_lookup. Or if absolutely + * necessary, use _csi_hash_table_remove first. + * + * Return value: %CAIRO_STATUS_SUCCESS if successful or + * %CAIRO_STATUS_NO_MEMORY if insufficient memory is available. + **/ +csi_status_t +_csi_hash_table_insert (csi_hash_table_t *hash_table, + csi_hash_entry_t *key_and_value) +{ + csi_status_t status; + csi_hash_entry_t **entry; + + hash_table->live_entries++; + status = _csi_hash_table_manage (hash_table); + if (_csi_unlikely (status)) { + /* abort the insert... */ + hash_table->live_entries--; + return status; + } + + entry = _csi_hash_table_lookup_unique_key (hash_table, + key_and_value); + if (ENTRY_IS_FREE (*entry)) + hash_table->used_entries++; + + *entry = key_and_value; + return CAIRO_STATUS_SUCCESS; +} + +static csi_hash_entry_t ** +_csi_hash_table_lookup_exact_key (csi_hash_table_t *hash_table, + csi_hash_entry_t *key) +{ + unsigned long table_size, i, idx, step; + csi_hash_entry_t **entry; + + table_size = hash_table->arrangement->size; + idx = key->hash % table_size; + + entry = &hash_table->entries[idx]; + if (*entry == key) + return entry; + + i = 1; + step = key->hash % hash_table->arrangement->rehash; + if (step == 0) + step = 1; + do { + idx += step; + if (idx >= table_size) + idx -= table_size; + + entry = &hash_table->entries[idx]; + if (*entry == key) + return entry; + } while (++i < table_size); + + return NULL; +} +/** + * _csi_hash_table_remove: + * @hash_table: a hash table + * @key: key of entry to be removed + * + * Remove an entry from the hash table which points to @key. + * + * Return value: %CAIRO_STATUS_SUCCESS if successful or + * %CAIRO_STATUS_NO_MEMORY if out of memory. + **/ +void +_csi_hash_table_remove (csi_hash_table_t *hash_table, + csi_hash_entry_t *key) +{ + *_csi_hash_table_lookup_exact_key (hash_table, key) = DEAD_ENTRY; + hash_table->live_entries--; + + /* Check for table resize. Don't do this when iterating as this will + * reorder elements of the table and cause the iteration to potentially + * skip some elements. */ + if (hash_table->iterating == 0) { + /* This call _can_ fail, but only in failing to allocate new + * memory to shrink the hash table. It does leave the table in a + * consistent state, and we've already succeeded in removing the + * entry, so we don't examine the failure status of this call. */ + _csi_hash_table_manage (hash_table); + } +} + +/** + * _csi_hash_table_foreach: + * @hash_table: a hash table + * @hash_callback: function to be called for each live entry + * @closure: additional argument to be passed to @hash_callback + * + * Call @hash_callback for each live entry in the hash table, in a + * non-specified order. + * + * Entries in @hash_table may be removed by code executed from @hash_callback. + * + * Entries may not be inserted to @hash_table, nor may @hash_table + * be destroyed by code executed from @hash_callback. The relevant + * functions will halt in these cases. + **/ +void +_csi_hash_table_foreach (csi_hash_table_t *hash_table, + csi_hash_callback_func_t hash_callback, + void *closure) +{ + unsigned long i; + csi_hash_entry_t *entry; + + /* Mark the table for iteration */ + ++hash_table->iterating; + for (i = 0; i < hash_table->arrangement->size; i++) { + entry = hash_table->entries[i]; + if (ENTRY_IS_LIVE(entry)) + hash_callback (entry, closure); + } + /* If some elements were deleted during the iteration, + * the table may need resizing. Just do this every time + * as the check is inexpensive. + */ + if (--hash_table->iterating == 0) { + /* Should we fail to shrink the hash table, it is left unaltered, + * and we don't need to propagate the error status. */ + _csi_hash_table_manage (hash_table); + } +} diff --git a/local/recipes/libs/cairo/source/util/cairo-script/cairo-script-interpreter.c b/local/recipes/libs/cairo/source/util/cairo-script/cairo-script-interpreter.c new file mode 100644 index 0000000000..e3aa3bae87 --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-script/cairo-script-interpreter.c @@ -0,0 +1,710 @@ +/* + * Copyright © 2008 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Chris Wilson. + * + * Contributor(s): + * Chris Wilson + */ + +#include "config.h" + +#include "cairo.h" + +#include "cairo-script-private.h" + +#include +#include +#include +#include +#include + +#ifndef MAX +#define MAX(a,b) (((a)>=(b))?(a):(b)) +#endif + +csi_status_t +_csi_error (csi_status_t status) +{ + return status; +} + +/* XXX track global/local memory, cap etc, mark/sweep GC */ +void * +_csi_alloc (csi_t *ctx, int size) +{ + return malloc (size); +} + +void * +_csi_alloc0 (csi_t *ctx, int size) +{ + void *ptr; + + ptr = _csi_alloc (ctx, size); + if (_csi_likely (ptr != NULL)) + memset (ptr, 0, size); + + return ptr; +} + +void * +_csi_realloc (csi_t *ctx, void *ptr, int size) +{ + return realloc (ptr, size); +} + +void +_csi_free (csi_t *ctx, void *ptr) +{ + if (_csi_unlikely (ptr == NULL)) + return; + + free (ptr); +} + +void * +_csi_perm_alloc (csi_t *ctx, int size) +{ + csi_chunk_t *chunk; + void *ptr; + + size = (size + sizeof (void *)-1) & -sizeof (void *); + + chunk = ctx->perm_chunk; + if (chunk == NULL || chunk->rem < size) { + int chunk_size = (size + 8191) & -8192; + chunk = _csi_alloc (ctx, sizeof (csi_chunk_t) + chunk_size); + if (_csi_unlikely (chunk == NULL)) + return NULL; + + chunk->rem = chunk_size; + chunk->ptr = (char *) (chunk + 1); + chunk->next = ctx->perm_chunk; + ctx->perm_chunk = chunk; + } + + ptr = chunk->ptr; + chunk->ptr += size; + chunk->rem -= size; + + return ptr; +} + +void * +_csi_slab_alloc (csi_t *ctx, int size) +{ +#if CSI_DEBUG_MALLOC + return malloc (size); +#else + int chunk_size; + csi_chunk_t *chunk; + void *ptr; + + chunk_size = 2 * sizeof (void *); + chunk_size = (size + chunk_size - 1) / chunk_size; + + if (ctx->slabs[chunk_size].free_list) { + ptr = ctx->slabs[chunk_size].free_list; + ctx->slabs[chunk_size].free_list = *(void **) ptr; + return ptr; + } + + chunk = ctx->slabs[chunk_size].chunk; + if (chunk == NULL || ! chunk->rem) { + int cnt = MAX (128, 8192 / (chunk_size * 2 * sizeof (void *))); + + chunk = _csi_alloc (ctx, + sizeof (csi_chunk_t) + + cnt * chunk_size * 2 * sizeof (void *)); + if (_csi_unlikely (chunk == NULL)) + return NULL; + + chunk->rem = cnt; + chunk->ptr = (char *) (chunk + 1); + chunk->next = ctx->slabs[chunk_size].chunk; + ctx->slabs[chunk_size].chunk = chunk; + } + + ptr = chunk->ptr; + chunk->ptr += chunk_size * 2 * sizeof (void *); + chunk->rem--; + + return ptr; +#endif +} + +void +_csi_slab_free (csi_t *ctx, void *ptr, int size) +{ + int chunk_size; + void **free_list; + + if (_csi_unlikely (ptr == NULL)) + return; + +#if CSI_DEBUG_MALLOC + free (ptr); +#else + chunk_size = 2 * sizeof (void *); + chunk_size = (size + chunk_size - 1) / chunk_size; + + free_list = ptr; + *free_list = ctx->slabs[chunk_size].free_list; + ctx->slabs[chunk_size].free_list = ptr; +#endif +} + +csi_status_t +_csi_stack_push (csi_t *ctx, csi_stack_t *stack, + const csi_object_t *obj) +{ + if (_csi_unlikely (stack->len == stack->size)) + return _csi_stack_push_internal (ctx, stack, obj); + + stack->objects[stack->len++] = *obj; + return CSI_STATUS_SUCCESS; +} + +static void +_csi_perm_fini (csi_t *ctx) +{ + while (ctx->perm_chunk != NULL) { + csi_chunk_t *chunk = ctx->perm_chunk; + ctx->perm_chunk = chunk->next; + _csi_free (ctx, chunk); + } +} + +static void +_csi_slab_fini (csi_t *ctx) +{ + unsigned int i; + + for (i = 0; i < sizeof (ctx->slabs) / sizeof (ctx->slabs[0]); i++) { + while (ctx->slabs[i].chunk != NULL) { + csi_chunk_t *chunk = ctx->slabs[i].chunk; + ctx->slabs[i].chunk = chunk->next; + _csi_free (ctx, chunk); + } + } +} + +static csi_status_t +_add_operator (csi_t *ctx, + csi_dictionary_t *dict, + const csi_operator_def_t *def) +{ + csi_object_t name; + csi_object_t operator; + csi_status_t status; + + status = csi_name_new_static (ctx, &name, def->name); + if (status) + return status; + + csi_operator_new (&operator, def->op); + + return csi_dictionary_put (ctx, dict, name.datum.name, &operator); +} + +static csi_status_t +_add_integer_constant (csi_t *ctx, + csi_dictionary_t *dict, + const csi_integer_constant_def_t *def) +{ + csi_object_t name; + csi_object_t constant; + csi_status_t status; + + status = csi_name_new_static (ctx, &name, def->name); + if (status) + return status; + + csi_integer_new (&constant, def->value); + + return csi_dictionary_put (ctx, dict, name.datum.name, &constant); +} + +static csi_status_t +_add_real_constant (csi_t *ctx, + csi_dictionary_t *dict, + const csi_real_constant_def_t *def) +{ + csi_object_t name; + csi_object_t constant; + csi_status_t status; + + status = csi_name_new_static (ctx, &name, def->name); + if (status) + return status; + + csi_real_new (&constant, def->value); + + return csi_dictionary_put (ctx, dict, name.datum.name, &constant); +} + +static csi_status_t +_init_dictionaries (csi_t *ctx) +{ + csi_status_t status; + csi_stack_t *stack; + csi_object_t obj; + csi_dictionary_t *dict, *opcodes; + const csi_operator_def_t *odef; + const csi_integer_constant_def_t *idef; + const csi_real_constant_def_t *rdef; + unsigned n; + + stack = &ctx->dstack; + + status = _csi_stack_init (ctx, stack, 4); + if (_csi_unlikely (status)) + return status; + + /* systemdict */ + status = csi_dictionary_new (ctx, &obj); + if (_csi_unlikely (status)) + return status; + + status = _csi_stack_push (ctx, stack, &obj); + if (_csi_unlikely (status)) + return status; + + dict = obj.datum.dictionary; + + status = csi_dictionary_new (ctx, &obj); + if (_csi_unlikely (status)) + return status; + + opcodes = obj.datum.dictionary; + + n = 0; + csi_integer_new (&obj, n); + status = csi_dictionary_put (ctx, opcodes, 0, &obj); + if (_csi_unlikely (status)) + return status; + ctx->opcode[n++] = NULL; + + /* fill systemdict with operators */ + for (odef = _csi_operators (); odef->name != NULL; odef++) { + status = _add_operator (ctx, dict, odef); + if (_csi_unlikely (status)) + return status; + + if (! csi_dictionary_has (opcodes, (csi_name_t) odef->op)) { + csi_integer_new (&obj, n); + status = csi_dictionary_put (ctx, + opcodes, (csi_name_t) odef->op, &obj); + if (_csi_unlikely (status)) + return status; + + assert (n < sizeof (ctx->opcode) / sizeof (ctx->opcode[0])); + ctx->opcode[n++] = odef->op; + } + } + csi_dictionary_free (ctx, opcodes); + + /* add constants */ + for (idef = _csi_integer_constants (); idef->name != NULL; idef++) { + status = _add_integer_constant (ctx, dict, idef); + if (_csi_unlikely (status)) + return status; + } + for (rdef = _csi_real_constants (); rdef->name != NULL; rdef++) { + status = _add_real_constant (ctx, dict, rdef); + if (_csi_unlikely (status)) + return status; + } + + /* and seal */ + //dict.type &= ~CSI_OBJECT_ATTR_WRITABLE; + + + /* globaldict */ + status = csi_dictionary_new (ctx, &obj); + if (_csi_unlikely (status)) + return status; + status = _csi_stack_push (ctx, stack, &obj); + if (_csi_unlikely (status)) + return status; + + /* userdict */ + status = csi_dictionary_new (ctx, &obj); + if (_csi_unlikely (status)) + return status; + status = _csi_stack_push (ctx, stack, &obj); + if (_csi_unlikely (status)) + return status; + + return CSI_STATUS_SUCCESS; +} + +/* intern string */ + +typedef struct _cairo_intern_string { + csi_hash_entry_t hash_entry; + int len; + char *string; +} csi_intern_string_t; + +static unsigned long +_intern_string_hash (const char *str, int len) +{ + const signed char *p = (const signed char *) str; + if (len > 0) { + unsigned int h = *p; + + while (--len) + h = (h << 5) - h + *++p; + + return h; + } + return 0; +} + +static cairo_bool_t +_intern_string_equal (const void *_a, const void *_b) +{ + const csi_intern_string_t *a = _a; + const csi_intern_string_t *b = _b; + + if (a->len != b->len) + return FALSE; + + return memcmp (a->string, b->string, a->len) == 0; +} + +static void +_csi_init (csi_t *ctx) +{ + csi_status_t status; + + memset (ctx, 0, sizeof (*ctx)); + + ctx->status = CSI_STATUS_SUCCESS; + ctx->ref_count = 1; + ctx->scanner.line_number = -1; + + status = _csi_hash_table_init (&ctx->strings, _intern_string_equal); + if (status) + goto FAIL; + + status = _csi_stack_init (ctx, &ctx->ostack, 2048); + if (status) + goto FAIL; + status = _init_dictionaries (ctx); + if (status) + goto FAIL; + + status = _csi_scanner_init (ctx, &ctx->scanner); + if (status) + goto FAIL; + + return; + +FAIL: + if (ctx->status == CSI_STATUS_SUCCESS) + ctx->status = status; +} + +static void +_csi_finish (csi_t *ctx) +{ + _csi_stack_fini (ctx, &ctx->ostack); + _csi_stack_fini (ctx, &ctx->dstack); + _csi_scanner_fini (ctx, &ctx->scanner); + + _csi_hash_table_fini (&ctx->strings); +} + +csi_status_t +_csi_name_define (csi_t *ctx, csi_name_t name, csi_object_t *obj) +{ + return csi_dictionary_put (ctx, + ctx->dstack.objects[ctx->dstack.len-1].datum.dictionary, + name, + obj); +} + +csi_status_t +_csi_name_lookup (csi_t *ctx, csi_name_t name, csi_object_t *obj) +{ + int i; + + for (i = ctx->dstack.len; i--; ) { + csi_dictionary_t *dict; + csi_dictionary_entry_t *entry; + + dict = ctx->dstack.objects[i].datum.dictionary; + entry = _csi_hash_table_lookup (&dict->hash_table, + (csi_hash_entry_t *) &name); + if (entry != NULL) { + *obj = entry->value; + return CSI_STATUS_SUCCESS; + } + } + + return _csi_error (CSI_STATUS_INVALID_SCRIPT); +} + +csi_status_t +_csi_name_undefine (csi_t *ctx, csi_name_t name) +{ + unsigned int i; + + for (i = ctx->dstack.len; --i; ) { + if (csi_dictionary_has (ctx->dstack.objects[i].datum.dictionary, + name)) + { + csi_dictionary_remove (ctx, + ctx->dstack.objects[i].datum.dictionary, + name); + return CSI_STATUS_SUCCESS; + } + } + + return _csi_error (CSI_STATUS_INVALID_SCRIPT); +} + +csi_status_t +_csi_intern_string (csi_t *ctx, const char **str_inout, int len) +{ + char *str = (char *) *str_inout; + csi_intern_string_t tmpl, *istring; + csi_status_t status = CSI_STATUS_SUCCESS; + + tmpl.hash_entry.hash = _intern_string_hash (str, len); + tmpl.len = len; + tmpl.string = (char *) str; + + istring = _csi_hash_table_lookup (&ctx->strings, &tmpl.hash_entry); + if (istring == NULL) { + istring = _csi_perm_alloc (ctx, + sizeof (csi_intern_string_t) + len + 1); + if (istring != NULL) { + istring->hash_entry.hash = tmpl.hash_entry.hash; + istring->len = tmpl.len; + istring->string = (char *) (istring + 1); + memcpy (istring->string, str, len); + istring->string[len] = '\0'; + + status = _csi_hash_table_insert (&ctx->strings, + &istring->hash_entry); + if (_csi_unlikely (status)) { + _csi_free (ctx, istring); + return status; + } + } else + return _csi_error (CSI_STATUS_NO_MEMORY); + } + + *str_inout = istring->string; + return CSI_STATUS_SUCCESS; +} + +/* Public */ + +static csi_t _csi_nil = { -1, CSI_STATUS_NO_MEMORY }; + +csi_t * +cairo_script_interpreter_create (void) +{ + csi_t *ctx; + + ctx = malloc (sizeof (csi_t)); + if (ctx == NULL) + return (csi_t *) &_csi_nil; + + _csi_init (ctx); + + return ctx; +} + +void +cairo_script_interpreter_install_hooks (csi_t *ctx, + const csi_hooks_t *hooks) +{ + if (ctx->status) + return; + + ctx->hooks = *hooks; +} + +cairo_status_t +cairo_script_interpreter_run (csi_t *ctx, const char *filename) +{ + csi_object_t file; + + if (ctx->status) + return ctx->status; + if (ctx->finished) + return ctx->status = CSI_STATUS_INTERPRETER_FINISHED; + + ctx->status = csi_file_new (ctx, &file, filename, "r"); + if (ctx->status) + return ctx->status; + + file.type |= CSI_OBJECT_ATTR_EXECUTABLE; + + ctx->status = csi_object_execute (ctx, &file); + csi_object_free (ctx, &file); + + return ctx->status; +} + +cairo_status_t +cairo_script_interpreter_feed_stream (csi_t *ctx, FILE *stream) +{ + csi_object_t file; + + if (ctx->status) + return ctx->status; + if (ctx->finished) + return ctx->status = CSI_STATUS_INTERPRETER_FINISHED; + + ctx->status = csi_file_new_for_stream (ctx, &file, stream); + if (ctx->status) + return ctx->status; + + file.type |= CSI_OBJECT_ATTR_EXECUTABLE; + + ctx->status = csi_object_execute (ctx, &file); + csi_object_free (ctx, &file); + + return ctx->status; +} + +cairo_status_t +cairo_script_interpreter_feed_string (csi_t *ctx, const char *line, int len) +{ + csi_object_t file; + + if (ctx->status) + return ctx->status; + if (ctx->finished) + return ctx->status = CSI_STATUS_INTERPRETER_FINISHED; + + if (len < 0) + len = strlen (line); + ctx->status = csi_file_new_for_bytes (ctx, &file, line, len); + if (ctx->status) + return ctx->status; + + file.type |= CSI_OBJECT_ATTR_EXECUTABLE; + + ctx->status = csi_object_execute (ctx, &file); + csi_object_free (ctx, &file); + + return ctx->status; +} + +unsigned int +cairo_script_interpreter_get_line_number (csi_t *ctx) +{ + return ctx->scanner.line_number + 1; /* 1 index based */ +} + +csi_t * +cairo_script_interpreter_reference (csi_t *ctx) +{ + ctx->ref_count++; + return ctx; +} + +cairo_status_t +cairo_script_interpreter_finish (csi_t *ctx) +{ + csi_status_t status; + + status = ctx->status; + if (! ctx->finished) { + _csi_finish (ctx); + ctx->finished = 1; + } else if (status == CSI_STATUS_SUCCESS) { + status = ctx->status = CSI_STATUS_INTERPRETER_FINISHED; + } + + return status; +} + +static void +_csi_fini (csi_t *ctx) +{ + if (! ctx->finished) + _csi_finish (ctx); + + if (ctx->free_array != NULL) + csi_array_free (ctx, ctx->free_array); + if (ctx->free_dictionary != NULL) + csi_dictionary_free (ctx, ctx->free_dictionary); + if (ctx->free_string != NULL) + csi_string_free (ctx, ctx->free_string); + + _csi_slab_fini (ctx); + _csi_perm_fini (ctx); +} + +cairo_status_t +cairo_script_interpreter_destroy (csi_t *ctx) +{ + csi_status_t status; + + status = ctx->status; + if (--ctx->ref_count) + return status; + + _csi_fini (ctx); + free (ctx); + + return status; +} + +cairo_status_t +cairo_script_interpreter_translate_stream (FILE *stream, + cairo_write_func_t write_func, + void *closure) +{ + csi_t ctx; + csi_object_t src; + csi_status_t status; + + _csi_init (&ctx); + + status = csi_file_new_for_stream (&ctx, &src, stream); + if (status) + goto BAIL; + + status = _csi_translate_file (&ctx, src.datum.file, write_func, closure); + +BAIL: + csi_object_free (&ctx, &src); + _csi_fini (&ctx); + + return status; +} diff --git a/local/recipes/libs/cairo/source/util/cairo-script/cairo-script-interpreter.h b/local/recipes/libs/cairo/source/util/cairo-script/cairo-script-interpreter.h new file mode 100644 index 0000000000..27fb986618 --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-script/cairo-script-interpreter.h @@ -0,0 +1,124 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2008 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Chris Wilson + * + * Contributor(s): + * Chris Wilson + */ + +#ifndef CAIRO_SCRIPT_INTERPRETER_H +#define CAIRO_SCRIPT_INTERPRETER_H + +#include +#include + +CAIRO_BEGIN_DECLS + +typedef struct _cairo_script_interpreter cairo_script_interpreter_t; + +/* XXX expose csi_dictionary_t and pass to hooks */ +typedef void +(*csi_destroy_func_t) (void *closure, + void *ptr); + +typedef cairo_surface_t * +(*csi_surface_create_func_t) (void *closure, + cairo_content_t content, + double width, + double height, + long uid); +typedef cairo_t * +(*csi_context_create_func_t) (void *closure, + cairo_surface_t *surface); +typedef void +(*csi_show_page_func_t) (void *closure, + cairo_t *cr); + +typedef void +(*csi_copy_page_func_t) (void *closure, + cairo_t *cr); + +typedef cairo_surface_t * +(*csi_create_source_image_t) (void *closure, + cairo_format_t format, + int width, int height, + long uid); + +typedef struct _cairo_script_interpreter_hooks { + void *closure; + csi_surface_create_func_t surface_create; + csi_destroy_func_t surface_destroy; + csi_context_create_func_t context_create; + csi_destroy_func_t context_destroy; + csi_show_page_func_t show_page; + csi_copy_page_func_t copy_page; + csi_create_source_image_t create_source_image; +} cairo_script_interpreter_hooks_t; + +cairo_public cairo_script_interpreter_t * +cairo_script_interpreter_create (void); + +cairo_public void +cairo_script_interpreter_install_hooks (cairo_script_interpreter_t *ctx, + const cairo_script_interpreter_hooks_t *hooks); + +cairo_public cairo_status_t +cairo_script_interpreter_run (cairo_script_interpreter_t *ctx, + const char *filename); + +cairo_public cairo_status_t +cairo_script_interpreter_feed_stream (cairo_script_interpreter_t *ctx, + FILE *stream); + +cairo_public cairo_status_t +cairo_script_interpreter_feed_string (cairo_script_interpreter_t *ctx, + const char *line, + int len); + +cairo_public unsigned int +cairo_script_interpreter_get_line_number (cairo_script_interpreter_t *ctx); + +cairo_public cairo_script_interpreter_t * +cairo_script_interpreter_reference (cairo_script_interpreter_t *ctx); + +cairo_public cairo_status_t +cairo_script_interpreter_finish (cairo_script_interpreter_t *ctx); + +cairo_public cairo_status_t +cairo_script_interpreter_destroy (cairo_script_interpreter_t *ctx); + +cairo_public cairo_status_t +cairo_script_interpreter_translate_stream (FILE *stream, + cairo_write_func_t write_func, + void *closure); + +CAIRO_END_DECLS + +#endif /*CAIRO_SCRIPT_INTERPRETER_H*/ diff --git a/local/recipes/libs/cairo/source/util/cairo-script/cairo-script-objects.c b/local/recipes/libs/cairo/source/util/cairo-script/cairo-script-objects.c new file mode 100644 index 0000000000..2d7937be33 --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-script/cairo-script-objects.c @@ -0,0 +1,938 @@ +/* + * Copyright © 2008 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Chris Wilson. + * + * Contributor(s): + * Chris Wilson + */ + +#include "config.h" + +#include "cairo-script-private.h" + +#include /* INT_MAX */ +#include + +csi_status_t +csi_array_new (csi_t *ctx, + csi_integer_t initial_size, + csi_object_t *obj) + +{ + csi_array_t *array; + + if (ctx->free_array == NULL || + ctx->free_array->stack.size <= initial_size) + { + csi_status_t status; + + array = _csi_slab_alloc (ctx, sizeof (csi_array_t)); + if (_csi_unlikely (array == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + + status = _csi_stack_init (ctx, &array->stack, + initial_size ? initial_size : 32); + if (_csi_unlikely (status)) { + _csi_slab_free (ctx, array, sizeof (csi_array_t)); + return status; + } + } else { + array = ctx->free_array; + ctx->free_array = NULL; + } + + array->base.type = CSI_OBJECT_TYPE_ARRAY; + array->base.ref = 1; + + obj->type = CSI_OBJECT_TYPE_ARRAY; + obj->datum.array = array; + + return CSI_STATUS_SUCCESS; +} + +csi_status_t +csi_array_put (csi_t *ctx, + csi_array_t *array, + csi_integer_t elem, + csi_object_t *value) +{ + if (_csi_unlikely (elem < 0)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + if (_csi_unlikely (elem >= array->stack.len)) { + csi_status_t status; + + status = _csi_stack_grow (ctx, &array->stack, elem + 1); + if (_csi_unlikely (status)) + return status; + + memset (array->stack.objects + array->stack.len, + 0, (elem - array->stack.len + 1) * sizeof (csi_object_t)); + array->stack.len = elem + 1; + } + + csi_object_free (ctx, &array->stack.objects[elem]); + array->stack.objects[elem] = *csi_object_reference (value); + + return CSI_STATUS_SUCCESS; +} + +csi_status_t +csi_array_get (csi_t *ctx, + csi_array_t *array, + csi_integer_t elem, + csi_object_t *value) +{ + if (_csi_unlikely (elem < 0)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + if (_csi_unlikely (elem > array->stack.len)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + *value = array->stack.objects[elem]; + return CSI_STATUS_SUCCESS; +} + +csi_status_t +csi_array_append (csi_t *ctx, + csi_array_t *array, + csi_object_t *obj) +{ + return _csi_stack_push (ctx, &array->stack, csi_object_reference (obj)); +} + +inline csi_status_t +_csi_array_execute (csi_t *ctx, csi_array_t *array) +{ + csi_integer_t i; + csi_status_t status; + + if (_csi_unlikely (array->stack.len == 0)) + return CSI_STATUS_SUCCESS; + + for (i = 0; i < array->stack.len; i++) { + csi_object_t *obj = &array->stack.objects[i]; + + if (obj->type & CSI_OBJECT_ATTR_EXECUTABLE) { + if (obj->type == (CSI_OBJECT_TYPE_ARRAY | + CSI_OBJECT_ATTR_EXECUTABLE)) + { + status = _csi_push_ostack_copy (ctx, &array->stack.objects[i]); + } + else + status = csi_object_execute (ctx, &array->stack.objects[i]); + } else + status = _csi_push_ostack_copy (ctx, &array->stack.objects[i]); + if (_csi_unlikely (status)) + return status; + } + + return CSI_STATUS_SUCCESS; +} + +void +csi_array_free (csi_t *ctx, csi_array_t *array) +{ +#if CSI_DEBUG_MALLOC + _csi_stack_fini (ctx, &array->stack); + _csi_slab_free (ctx, array, sizeof (csi_array_t)); +#else + csi_integer_t n; + + for (n = 0; n < array->stack.len; n++) + csi_object_free (ctx, &array->stack.objects[n]); + array->stack.len = 0; + + if (ctx->free_array != NULL) { + if (array->stack.size > ctx->free_array->stack.size) { + csi_array_t *tmp = ctx->free_array; + ctx->free_array = array; + array = tmp; + } + + _csi_stack_fini (ctx, &array->stack); + _csi_slab_free (ctx, array, sizeof (csi_array_t)); + } else + ctx->free_array = array; +#endif +} + +static cairo_bool_t +_dictionary_name_equal (const void *_a, const void *_b) +{ + return TRUE; +} + +csi_status_t +csi_dictionary_new (csi_t *ctx, + csi_object_t *obj) + +{ + csi_dictionary_t *dict; + + if (ctx->free_dictionary != NULL) { + dict = ctx->free_dictionary; + ctx->free_dictionary = NULL; + } else { + csi_status_t status; + + dict = _csi_slab_alloc (ctx, sizeof (csi_dictionary_t)); + if (_csi_unlikely (dict == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + + status = _csi_hash_table_init (&dict->hash_table, + _dictionary_name_equal); + if (_csi_unlikely (status)) { + _csi_slab_free (ctx, dict, sizeof (csi_dictionary_t)); + return status; + } + } + + dict->base.type = CSI_OBJECT_TYPE_DICTIONARY; + dict->base.ref = 1; + + obj->type = CSI_OBJECT_TYPE_DICTIONARY; + obj->datum.dictionary = dict; + + return CSI_STATUS_SUCCESS; +} + +struct _dictionary_entry_pluck { + csi_t *ctx; + csi_hash_table_t *hash_table; +}; + +static void +_dictionary_entry_pluck (void *entry, void *data) +{ + csi_dictionary_entry_t *dict_entry; + struct _dictionary_entry_pluck *pluck_data; + + dict_entry = entry; + pluck_data = data; + + _csi_hash_table_remove (pluck_data->hash_table, entry); + csi_object_free (pluck_data->ctx, &dict_entry->value); + _csi_slab_free (pluck_data->ctx, entry, sizeof (csi_dictionary_entry_t)); +} + +void +csi_dictionary_free (csi_t *ctx, + csi_dictionary_t *dict) +{ + struct _dictionary_entry_pluck data; + + data.ctx = ctx; + data.hash_table = &dict->hash_table; + _csi_hash_table_foreach (&dict->hash_table, + _dictionary_entry_pluck, + &data); + +#if CSI_DEBUG_MALLOC + _csi_hash_table_fini (&dict->hash_table); + _csi_slab_free (ctx, dict, sizeof (csi_dictionary_t)); +#else + if (ctx->free_dictionary != NULL) { + _csi_hash_table_fini (&dict->hash_table); + _csi_slab_free (ctx, dict, sizeof (csi_dictionary_t)); + } else + ctx->free_dictionary = dict; +#endif +} + +csi_status_t +csi_dictionary_put (csi_t *ctx, + csi_dictionary_t *dict, + csi_name_t name, + csi_object_t *value) +{ + csi_dictionary_entry_t *entry; + csi_status_t status; + + entry = _csi_hash_table_lookup (&dict->hash_table, + (csi_hash_entry_t *) &name); + if (entry != NULL) { + /* replace the existing entry */ + csi_object_free (ctx, &entry->value); + entry->value = *csi_object_reference (value); + return CSI_STATUS_SUCCESS; + } + + entry = _csi_slab_alloc (ctx, sizeof (*entry)); + if (_csi_unlikely (entry == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + + entry->hash_entry.hash = name; + status = _csi_hash_table_insert (&dict->hash_table, &entry->hash_entry); + if (_csi_unlikely (status)) { + _csi_slab_free (ctx, entry, sizeof (*entry)); + return status; + } + + entry->value = *csi_object_reference (value); + + return CSI_STATUS_SUCCESS; +} + +csi_status_t +csi_dictionary_get (csi_t *ctx, + csi_dictionary_t *dict, + csi_name_t name, + csi_object_t *value) +{ + csi_dictionary_entry_t *entry; + + entry = _csi_hash_table_lookup (&dict->hash_table, + (csi_hash_entry_t *) &name); + if (_csi_unlikely (entry == NULL)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + *value = entry->value; + return CSI_STATUS_SUCCESS; +} + +csi_boolean_t +csi_dictionary_has (csi_dictionary_t *dict, + csi_name_t name) +{ + return _csi_hash_table_lookup (&dict->hash_table, + (csi_hash_entry_t *) &name) != NULL; +} + +void +csi_dictionary_remove (csi_t *ctx, + csi_dictionary_t *dict, + csi_name_t name) +{ + csi_dictionary_entry_t *entry; + + entry = _csi_hash_table_lookup (&dict->hash_table, + (csi_hash_entry_t *) &name); + if (entry != NULL) { + _csi_hash_table_remove (&dict->hash_table, &entry->hash_entry); + csi_object_free (ctx, &entry->value); + _csi_slab_free (ctx, entry, sizeof (csi_dictionary_entry_t)); + } +} + +csi_status_t +csi_matrix_new (csi_t *ctx, + csi_object_t *obj) +{ + csi_matrix_t *matrix; + + matrix = _csi_slab_alloc (ctx, sizeof (csi_matrix_t)); + if (_csi_unlikely (matrix == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + + matrix->base.type = CSI_OBJECT_TYPE_MATRIX; + matrix->base.ref = 1; + cairo_matrix_init_identity (&matrix->matrix); + + obj->type = CSI_OBJECT_TYPE_MATRIX; + obj->datum.matrix = matrix; + + return CSI_STATUS_SUCCESS; +} + +csi_status_t +csi_matrix_new_from_array (csi_t *ctx, + csi_object_t *obj, + csi_array_t *array) +{ + csi_matrix_t *matrix; + + if (_csi_unlikely (array->stack.len != 6)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + matrix = _csi_slab_alloc (ctx, sizeof (csi_matrix_t)); + if (_csi_unlikely (matrix == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + + matrix->base.type = CSI_OBJECT_TYPE_MATRIX; + matrix->base.ref = 1; + cairo_matrix_init (&matrix->matrix, + csi_number_get_value (&array->stack.objects[0]), + csi_number_get_value (&array->stack.objects[1]), + csi_number_get_value (&array->stack.objects[2]), + csi_number_get_value (&array->stack.objects[3]), + csi_number_get_value (&array->stack.objects[4]), + csi_number_get_value (&array->stack.objects[5])); + + obj->type = CSI_OBJECT_TYPE_MATRIX; + obj->datum.matrix = matrix; + + return CSI_STATUS_SUCCESS; +} + +csi_status_t +csi_matrix_new_from_matrix (csi_t *ctx, + csi_object_t *obj, + const cairo_matrix_t *m) +{ + csi_matrix_t *matrix; + + matrix = _csi_slab_alloc (ctx, sizeof (csi_matrix_t)); + if (_csi_unlikely (matrix == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + + matrix->base.type = CSI_OBJECT_TYPE_MATRIX; + matrix->base.ref = 1; + matrix->matrix = *m; + + obj->type = CSI_OBJECT_TYPE_MATRIX; + obj->datum.matrix = matrix; + + return CSI_STATUS_SUCCESS; +} + +csi_status_t +csi_matrix_new_from_values (csi_t *ctx, + csi_object_t *obj, + double v[6]) +{ + csi_matrix_t *matrix; + + matrix = _csi_slab_alloc (ctx, sizeof (csi_matrix_t)); + if (_csi_unlikely (matrix == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + + matrix->base.type = CSI_OBJECT_TYPE_MATRIX; + matrix->base.ref = 1; + cairo_matrix_init (&matrix->matrix, v[0], v[1], v[2], v[3], v[4], v[5]); + + obj->type = CSI_OBJECT_TYPE_MATRIX; + obj->datum.matrix = matrix; + + return CSI_STATUS_SUCCESS; +} + +void +csi_matrix_free (csi_t *ctx, + csi_matrix_t *obj) +{ + _csi_slab_free (ctx, obj, sizeof (csi_matrix_t)); +} + + +csi_status_t +csi_name_new (csi_t *ctx, + csi_object_t *obj, + const char *str, + int len) +{ + csi_status_t status; + + status = _csi_intern_string (ctx, &str, len); + if (_csi_unlikely (status)) + return status; + + obj->type = CSI_OBJECT_TYPE_NAME; + obj->datum.name = (csi_name_t) str; + + return CSI_STATUS_SUCCESS; +} + +csi_status_t +csi_name_new_static (csi_t *ctx, + csi_object_t *obj, + const char *str) +{ + csi_status_t status; + + status = _csi_intern_string (ctx, &str, strlen (str)); + if (_csi_unlikely (status)) + return status; + + obj->type = CSI_OBJECT_TYPE_NAME; + obj->datum.name = (csi_name_t) str; + + return CSI_STATUS_SUCCESS; +} + +csi_status_t +csi_string_new (csi_t *ctx, + csi_object_t *obj, + const char *str, + int len) +{ + csi_string_t *string; + + if (len < 0) + len = strlen (str); + if (_csi_unlikely (len >= INT_MAX)) + return _csi_error (CSI_STATUS_NO_MEMORY); + + if (ctx->free_string == NULL || ctx->free_string->len <= len) { + string = _csi_slab_alloc (ctx, sizeof (csi_string_t)); + if (_csi_unlikely (string == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + + string->string = _csi_alloc (ctx, len + 1); + if (_csi_unlikely (string->string == NULL)) { + _csi_slab_free (ctx, string, sizeof (csi_string_t)); + return _csi_error (CSI_STATUS_NO_MEMORY); + } + } else { + string = ctx->free_string; + ctx->free_string = NULL; + } + + if (str != NULL) { + memcpy (string->string, str, len); + string->string[len] = '\0'; + } + string->len = len; + string->deflate = 0; + string->method = NONE; + + string->base.type = CSI_OBJECT_TYPE_STRING; + string->base.ref = 1; + + obj->type = CSI_OBJECT_TYPE_STRING; + obj->datum.string = string; + + return CSI_STATUS_SUCCESS; +} + +csi_status_t +csi_string_deflate_new (csi_t *ctx, + csi_object_t *obj, + void *bytes, + int in_len, + int out_len) +{ + csi_status_t status; + csi_string_t *string; + + status = csi_string_new (ctx, obj, bytes, in_len); + if (_csi_unlikely (status)) + return status; + + string = obj->datum.string; + string->deflate = out_len; + string->method = ZLIB; + + return CSI_STATUS_SUCCESS; +} + +csi_status_t +csi_string_new_from_bytes (csi_t *ctx, + csi_object_t *obj, + char *bytes, + unsigned int len) +{ + csi_string_t *string; + + if (_csi_unlikely (len >= INT_MAX)) + return _csi_error (CSI_STATUS_NO_MEMORY); + + string = _csi_slab_alloc (ctx, sizeof (csi_string_t)); + if (_csi_unlikely (string == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + + string->string = bytes; + string->len = len; + string->deflate = 0; + string->method = NONE; + + string->base.type = CSI_OBJECT_TYPE_STRING; + string->base.ref = 1; + + obj->type = CSI_OBJECT_TYPE_STRING; + obj->datum.string = string; + + return CSI_STATUS_SUCCESS; +} + +static inline csi_status_t +_csi_string_execute (csi_t *ctx, csi_string_t *string) +{ + csi_status_t status; + csi_object_t obj; + + if (_csi_unlikely (string->len == 0)) + return CSI_STATUS_SUCCESS; + + status = csi_file_new_for_bytes (ctx, &obj, string->string, string->len); + if (_csi_unlikely (status)) + return status; + + status = _csi_scan_file (ctx, obj.datum.file); + csi_object_free (ctx, &obj); + + return status; +} + +void +csi_string_free (csi_t *ctx, csi_string_t *string) +{ +#if CSI_DEBUG_MALLOC + _csi_free (ctx, string->string); + _csi_slab_free (ctx, string, sizeof (csi_string_t)); +#else + if (ctx->free_string != NULL) { + if (string->len > ctx->free_string->len) { + csi_string_t *tmp = ctx->free_string; + ctx->free_string = string; + string = tmp; + } + + _csi_free (ctx, string->string); + _csi_slab_free (ctx, string, sizeof (csi_string_t)); + } else + ctx->free_string = string; +#endif +} + +csi_status_t +csi_object_execute (csi_t *ctx, csi_object_t *obj) +{ + csi_status_t status; + csi_object_t indirect; + + INDIRECT: + switch (obj->type & CSI_OBJECT_TYPE_MASK) { + case CSI_OBJECT_TYPE_NAME: + status = _csi_name_lookup (ctx, obj->datum.name, &indirect); + if (_csi_unlikely (status)) + return status; + if (indirect.type & CSI_OBJECT_ATTR_EXECUTABLE) { + obj = &indirect; + goto INDIRECT; + } else + return _csi_push_ostack_copy (ctx, &indirect); + + case CSI_OBJECT_TYPE_OPERATOR: + return obj->datum.op (ctx); + + case CSI_OBJECT_TYPE_ARRAY: + return _csi_array_execute (ctx, obj->datum.array); + case CSI_OBJECT_TYPE_FILE: + return _csi_file_execute (ctx, obj->datum.file); + case CSI_OBJECT_TYPE_STRING: + return _csi_string_execute (ctx, obj->datum.string); + + default: + return _csi_push_ostack_copy (ctx, obj); + } +} + +csi_object_t * +csi_object_reference (csi_object_t *obj) +{ + if (CSI_OBJECT_IS_CAIRO (obj)) { + switch (obj->type & CSI_OBJECT_TYPE_MASK) { + case CSI_OBJECT_TYPE_CONTEXT: + cairo_reference (obj->datum.cr); + break; + case CSI_OBJECT_TYPE_FONT: + cairo_font_face_reference (obj->datum.font_face); + break; + case CSI_OBJECT_TYPE_PATTERN: + cairo_pattern_reference (obj->datum.pattern); + break; + case CSI_OBJECT_TYPE_SCALED_FONT: + cairo_scaled_font_reference (obj->datum.scaled_font); + break; + case CSI_OBJECT_TYPE_SURFACE: + cairo_surface_reference (obj->datum.surface); + break; + } + } else if (CSI_OBJECT_IS_COMPOUND (obj)) { + obj->datum.object->ref++; + } + + return obj; +} + +void +csi_object_free (csi_t *ctx, + csi_object_t *obj) +{ + if (CSI_OBJECT_IS_CAIRO (obj)) { + switch (obj->type & CSI_OBJECT_TYPE_MASK) { + case CSI_OBJECT_TYPE_CONTEXT: + cairo_destroy (obj->datum.cr); + break; + case CSI_OBJECT_TYPE_FONT: + cairo_font_face_destroy (obj->datum.font_face); + break; + case CSI_OBJECT_TYPE_PATTERN: + cairo_pattern_destroy (obj->datum.pattern); + break; + case CSI_OBJECT_TYPE_SCALED_FONT: + cairo_scaled_font_destroy (obj->datum.scaled_font); + break; + case CSI_OBJECT_TYPE_SURFACE: + cairo_surface_destroy (obj->datum.surface); + break; + } + } else if (CSI_OBJECT_IS_COMPOUND (obj)) { + if (--obj->datum.object->ref) + return; + + switch (obj->type & CSI_OBJECT_TYPE_MASK) { + case CSI_OBJECT_TYPE_ARRAY: + csi_array_free (ctx, obj->datum.array); + break; + case CSI_OBJECT_TYPE_DICTIONARY: + csi_dictionary_free (ctx, obj->datum.dictionary); + break; + case CSI_OBJECT_TYPE_FILE: + _csi_file_free (ctx, obj->datum.file); + break; + case CSI_OBJECT_TYPE_MATRIX: + csi_matrix_free (ctx, obj->datum.matrix); + break; + case CSI_OBJECT_TYPE_STRING: + csi_string_free (ctx, obj->datum.string); + break; + default: + break; + } + } +} + +csi_status_t +csi_object_as_file (csi_t *ctx, + csi_object_t *src, + csi_object_t *file) +{ + int type = csi_object_get_type (src); + switch (type) { + case CSI_OBJECT_TYPE_FILE: + *file = *csi_object_reference (src); + return CSI_STATUS_SUCCESS; + case CSI_OBJECT_TYPE_STRING: + return csi_file_new_from_string (ctx, file, src->datum.string); + case CSI_OBJECT_TYPE_ARRAY: +#if 0 + if (src->type & CSI_OBJECT_ATTR_EXECUTABLE) + return _csi_file_new_from_procedure (cs, src); +#endif + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } +} + +static int +lexcmp (void const *a, size_t alen, + void const *b, size_t blen) +{ + size_t len = alen < blen ? alen : blen; + int cmp = memcmp (a, b, len); + if (cmp) + return cmp; + if (alen == blen) + return 0; + return alen < blen ? -1 : +1; +} + +csi_boolean_t +csi_object_eq (csi_object_t *a, + csi_object_t *b) +{ + csi_object_type_t atype = csi_object_get_type (a); + csi_object_type_t btype = csi_object_get_type (b); + + if (atype == btype) { + switch (atype) { + case CSI_OBJECT_TYPE_BOOLEAN: + return a->datum.boolean == b->datum.boolean; + case CSI_OBJECT_TYPE_INTEGER: + return a->datum.integer == b->datum.integer; + case CSI_OBJECT_TYPE_REAL: + return a->datum.real == b->datum.real; + case CSI_OBJECT_TYPE_NAME: + return a->datum.name == b->datum.name; + case CSI_OBJECT_TYPE_STRING: + return 0 == lexcmp (a->datum.string->string, + a->datum.string->len, + b->datum.string->string, + b->datum.string->len); + case CSI_OBJECT_TYPE_NULL: + case CSI_OBJECT_TYPE_MARK: + return TRUE; + case CSI_OBJECT_TYPE_OPERATOR: + return a->datum.op == b->datum.op; + case CSI_OBJECT_TYPE_ARRAY: + case CSI_OBJECT_TYPE_DICTIONARY: + case CSI_OBJECT_TYPE_FILE: + case CSI_OBJECT_TYPE_MATRIX: + case CSI_OBJECT_TYPE_CONTEXT: + case CSI_OBJECT_TYPE_FONT: + case CSI_OBJECT_TYPE_PATTERN: + case CSI_OBJECT_TYPE_SCALED_FONT: + case CSI_OBJECT_TYPE_SURFACE: + return a->datum.ptr == b->datum.ptr; + } + } + + if (atype < btype) { + csi_object_t *c; + csi_object_type_t ctype; + c = a; a = b; b = c; + ctype = atype; atype = btype; btype = ctype; + } + + switch ((int) atype) { + case CSI_OBJECT_TYPE_INTEGER: + if (btype == CSI_OBJECT_TYPE_BOOLEAN) { + return a->datum.integer == b->datum.boolean; + } + break; + case CSI_OBJECT_TYPE_REAL: + if (btype == CSI_OBJECT_TYPE_INTEGER) { + return a->datum.real == b->datum.integer; + } + else if (btype == CSI_OBJECT_TYPE_BOOLEAN) { + return a->datum.real == b->datum.boolean; + } + break; + + case CSI_OBJECT_TYPE_STRING: + if (btype == CSI_OBJECT_TYPE_NAME) { + const char *bstr = (const char *) b->datum.name; + return 0 == lexcmp (a->datum.string->string, + a->datum.string->len, + bstr, + strlen (bstr)); + } + break; + + default: + break; + } + + return FALSE; +} + +csi_status_t +csi_object_compare (csi_object_t *a, + csi_object_t *b, + int *out) +{ + csi_object_type_t atype = csi_object_get_type (a); + csi_object_type_t btype = csi_object_get_type (b); + int sign; + + if (csi_object_eq (a, b)){ + *out = 0; + return CSI_STATUS_SUCCESS; + } + +#define CMP(x,y) ((x) < (y) ? -1 : +1) + + if (atype == btype) { + switch (atype) { + case CSI_OBJECT_TYPE_BOOLEAN: + *out = CMP (a->datum.boolean, b->datum.boolean); + return CSI_STATUS_SUCCESS; + case CSI_OBJECT_TYPE_INTEGER: + *out = CMP (a->datum.integer, b->datum.integer); + return CSI_STATUS_SUCCESS; + case CSI_OBJECT_TYPE_REAL: + *out = CMP (a->datum.real, b->datum.real); + return CSI_STATUS_SUCCESS; + case CSI_OBJECT_TYPE_NAME: { + const char *x = (char const *) a->datum.name; + const char *y = (char const *) b->datum.name; + *out = lexcmp (x, strlen(x), y, strlen (y)); + return CSI_STATUS_SUCCESS; + } + case CSI_OBJECT_TYPE_STRING: + *out = lexcmp (a->datum.string->string, + a->datum.string->len, + b->datum.string->string, + b->datum.string->len); + return CSI_STATUS_SUCCESS; + case CSI_OBJECT_TYPE_NULL: + case CSI_OBJECT_TYPE_MARK: + case CSI_OBJECT_TYPE_OPERATOR: + case CSI_OBJECT_TYPE_ARRAY: + case CSI_OBJECT_TYPE_DICTIONARY: + case CSI_OBJECT_TYPE_FILE: + case CSI_OBJECT_TYPE_MATRIX: + case CSI_OBJECT_TYPE_CONTEXT: + case CSI_OBJECT_TYPE_FONT: + case CSI_OBJECT_TYPE_PATTERN: + case CSI_OBJECT_TYPE_SCALED_FONT: + case CSI_OBJECT_TYPE_SURFACE: + goto TYPE_CHECK_ERROR; + } + } + + sign = +1; + if (atype < btype) { + csi_object_t *c; + csi_object_type_t ctype; + c = a; a = b; b = c; + ctype = atype; atype = btype; btype = ctype; + sign = -1; + } + + switch ((int) atype) { + case CSI_OBJECT_TYPE_INTEGER: + if (btype == CSI_OBJECT_TYPE_BOOLEAN) { + *out = sign * CMP (a->datum.integer, !!b->datum.boolean); + return CSI_STATUS_SUCCESS; + } + break; + case CSI_OBJECT_TYPE_REAL: + if (btype == CSI_OBJECT_TYPE_INTEGER) { + *out = sign * CMP (a->datum.real, b->datum.integer); + return CSI_STATUS_SUCCESS; + } + else if (btype == CSI_OBJECT_TYPE_BOOLEAN) { + *out = sign * CMP (a->datum.real, !!b->datum.boolean); + return CSI_STATUS_SUCCESS; + } + break; + + case CSI_OBJECT_TYPE_STRING: + if (btype == CSI_OBJECT_TYPE_NAME) { + const char *bstr = (const char *) b->datum.name; + *out = sign * lexcmp (a->datum.string->string, + a->datum.string->len, + bstr, + strlen (bstr)); + return CSI_STATUS_SUCCESS; + } + break; + + default: + break; + } + +#undef CMP + + TYPE_CHECK_ERROR: + return _csi_error (CSI_STATUS_SCRIPT_INVALID_TYPE); +} diff --git a/local/recipes/libs/cairo/source/util/cairo-script/cairo-script-operators.c b/local/recipes/libs/cairo/source/util/cairo-script/cairo-script-operators.c new file mode 100644 index 0000000000..a5eca6ffca --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-script/cairo-script-operators.c @@ -0,0 +1,6831 @@ +/* + * Copyright © 2008 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Chris Wilson. + * + * Contributor(s): + * Chris Wilson + */ + +#include "config.h" + +/* TODO real path type */ + +#include "cairo-script-private.h" + +#if CAIRO_HAS_SCRIPT_SURFACE +#include "cairo-script.h" +#endif + +#include /* snprintf */ +#include /* mkstemp */ +#include + +#ifdef _MSC_VER +#define _USE_MATH_DEFINES /* for M_LN2, M_PI and M_SQRT2 on win32 */ +#define snprintf _snprintf +#endif + +#include +#include /* INT_MAX */ +#include + +#if HAVE_ZLIB +#include +#endif + +#if HAVE_LZO +#include +#endif + +#ifdef HAVE_MMAP +# ifdef HAVE_UNISTD_H +# include +# include +# else +# undef HAVE_MMAP +# endif +#endif + +typedef struct _csi_proxy { + csi_t *ctx; + void *ptr; + csi_dictionary_t *dictionary; + csi_destroy_func_t destroy_func; + void *destroy_data; +} csi_proxy_t; + +typedef struct _csi_blob { + csi_list_t list; + unsigned long hash; + uint8_t *bytes; + unsigned int len; +} csi_blob_t; + +static const cairo_user_data_key_t _csi_proxy_key; +static const cairo_user_data_key_t _csi_blob_key; + +enum mime_type { + MIME_TYPE_NONE = 0, + MIME_TYPE_PNG +}; + +#define check(CNT) do {\ + if (_csi_unlikely (! _csi_check_ostack (ctx, (CNT)))) \ + return _csi_error (CSI_STATUS_INVALID_SCRIPT); \ +} while (0) +#define pop(CNT) _csi_pop_ostack (ctx, (CNT)) +#define push(OBJ) _csi_push_ostack (ctx, (OBJ)) + +static csi_proxy_t * +_csi_proxy_create (csi_t *ctx, + void *ptr, + csi_dictionary_t *dictionary, + csi_destroy_func_t destroy_func, + void *destroy_data) +{ + csi_proxy_t *proxy; + + proxy = _csi_slab_alloc (ctx, sizeof (csi_proxy_t)); + if (proxy == NULL) + return NULL; + + proxy->ctx = cairo_script_interpreter_reference (ctx); + proxy->ptr = ptr; + proxy->destroy_func = destroy_func; + proxy->destroy_data = destroy_data; + proxy->dictionary = dictionary; + if (dictionary != NULL) + dictionary->base.ref++; + + return proxy; +} + +static void +_csi_proxy_destroy (void *closure) +{ + csi_proxy_t *proxy = closure; + csi_t *ctx = proxy->ctx; + + /* XXX this doesn't work because user_data_destroy is called too late. + * Considering another hook into the (cairo internal) object system. + */ + if (proxy->destroy_func != NULL) + proxy->destroy_func (proxy->destroy_data, proxy->ptr); + + if (proxy->dictionary != NULL && --proxy->dictionary->base.ref == 0) + csi_dictionary_free (ctx, proxy->dictionary); + + _csi_slab_free (ctx, proxy, sizeof (csi_proxy_t)); + cairo_script_interpreter_destroy (ctx); +} + +static void +_csi_blob_hash (csi_blob_t *blob, const uint32_t *data, int len) +{ + unsigned long hash = blob->hash; + /* very simple! */ + while (len--) { + unsigned long c = *data++; + hash *= 33; + hash ^= c; + } + blob->hash = hash; +} + +static csi_boolean_t +_csi_blob_equal (const csi_list_t *link, void *data) +{ + csi_blob_t *A, *B; + + A = csi_container_of (link, csi_blob_t, list); + B = data; + + if (A->len != B->len) + return FALSE; + + if (A->hash != B->hash) + return FALSE; + + return memcmp (A->bytes, B->bytes, A->len) == 0; +} + +static void +_csi_blob_init (csi_blob_t *blob, uint8_t *bytes, int len) +{ + blob->hash = 5381; + blob->len = len; + blob->bytes = bytes; +} + +static csi_list_t * +_csi_list_unlink (csi_list_t *head, csi_list_t *link) +{ + if (link->next != NULL) + link->next->prev = link->prev; + if (link->prev != NULL) + link->prev->next = link->next; + else + head = link->next; + return head; +} + +static csi_list_t * +_csi_list_prepend (csi_list_t *head, csi_list_t *link) +{ + if (head != NULL) + head->prev = link; + link->next = head; + link->prev = NULL; + return link; +} + +static csi_list_t * +_csi_list_find (csi_list_t *head, + csi_boolean_t (*predicate) (const csi_list_t *link, void *data), + void *data) +{ + while (head != NULL) { + if (predicate (head, data)) + return head; + head = head->next; + } + + return NULL; +} + +static csi_status_t +_csi_ostack_get_boolean (csi_t *ctx, unsigned int i, csi_boolean_t *out) +{ + csi_object_t *obj; + int type; + + obj = _csi_peek_ostack (ctx, i); + type = csi_object_get_type (obj); + switch (type) { + case CSI_OBJECT_TYPE_BOOLEAN: + *out = obj->datum.boolean; + break; + case CSI_OBJECT_TYPE_INTEGER: + *out = !! obj->datum.integer; + break; + case CSI_OBJECT_TYPE_REAL: + *out = obj->datum.real != 0.; + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_csi_ostack_get_integer (csi_t *ctx, unsigned int i, csi_integer_t *out) +{ + csi_object_t *obj; + int type; + + obj = _csi_peek_ostack (ctx, i); + type = csi_object_get_type (obj); + switch (type) { + case CSI_OBJECT_TYPE_BOOLEAN: + *out = obj->datum.boolean; + break; + case CSI_OBJECT_TYPE_INTEGER: + *out = obj->datum.integer; + break; + case CSI_OBJECT_TYPE_REAL: + *out = obj->datum.real; + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_csi_ostack_get_number (csi_t *ctx, unsigned int i, double *out) +{ + csi_object_t *obj; + int type; + + obj = _csi_peek_ostack (ctx, i); + type = csi_object_get_type (obj); + switch (type) { + case CSI_OBJECT_TYPE_BOOLEAN: + *out = obj->datum.boolean; + break; + case CSI_OBJECT_TYPE_INTEGER: + *out = obj->datum.integer; + break; + case CSI_OBJECT_TYPE_REAL: + *out = obj->datum.real; + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + return CSI_STATUS_SUCCESS; +} + +static double +_csi_object_as_real (csi_object_t *obj) +{ + int type; + + type = csi_object_get_type (obj); + switch (type) { + case CSI_OBJECT_TYPE_BOOLEAN: + return obj->datum.boolean; + case CSI_OBJECT_TYPE_INTEGER: + return obj->datum.integer; + case CSI_OBJECT_TYPE_REAL: + return obj->datum.real; + default: + return 0; + } +} + +static csi_status_t +_csi_ostack_get_name (csi_t *ctx, unsigned int i, csi_name_t *out) +{ + csi_object_t *obj; + + obj = _csi_peek_ostack (ctx, i); + if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_NAME)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + *out = obj->datum.name; + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_csi_ostack_get_context (csi_t *ctx, unsigned int i, cairo_t **out) +{ + csi_object_t *obj; + + obj = _csi_peek_ostack (ctx, i); + if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_CONTEXT)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + *out = obj->datum.cr; + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_csi_ostack_get_font_face (csi_t *ctx, unsigned int i, cairo_font_face_t **out) +{ + csi_object_t *obj; + + obj = _csi_peek_ostack (ctx, i); + if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_FONT)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + *out = obj->datum.font_face; + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_csi_ostack_get_pattern (csi_t *ctx, unsigned int i, cairo_pattern_t **out) +{ + csi_object_t *obj; + + obj = _csi_peek_ostack (ctx, i); + if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_PATTERN)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + *out = obj->datum.pattern; + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_csi_ostack_get_scaled_font (csi_t *ctx, unsigned int i, + cairo_scaled_font_t **out) +{ + csi_object_t *obj; + + obj = _csi_peek_ostack (ctx, i); + if (_csi_unlikely + (csi_object_get_type (obj) != CSI_OBJECT_TYPE_SCALED_FONT)) + { + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + *out = obj->datum.scaled_font; + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_csi_ostack_get_surface (csi_t *ctx, unsigned int i, cairo_surface_t **out) +{ + csi_object_t *obj; + int type; + + obj = _csi_peek_ostack (ctx, i); + type = csi_object_get_type (obj); + switch (type) { + case CSI_OBJECT_TYPE_CONTEXT: + *out = cairo_get_target (obj->datum.cr); + break; + case CSI_OBJECT_TYPE_SURFACE: + *out = obj->datum.surface; + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_csi_ostack_get_array (csi_t *ctx, unsigned int i, csi_array_t **out) +{ + csi_object_t *obj; + + obj = _csi_peek_ostack (ctx, i); + if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_ARRAY)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + *out = obj->datum.array; + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_csi_ostack_get_procedure (csi_t *ctx, unsigned int i, csi_array_t **out) +{ + csi_object_t *obj; + + obj = _csi_peek_ostack (ctx, i); + if (_csi_unlikely (! csi_object_is_procedure (obj))) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + *out = obj->datum.array; + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_csi_ostack_get_dictionary (csi_t *ctx, unsigned int i, csi_dictionary_t **out) +{ + csi_object_t *obj; + + obj = _csi_peek_ostack (ctx, i); + if (_csi_unlikely + (csi_object_get_type (obj) != CSI_OBJECT_TYPE_DICTIONARY)) + { + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + *out = obj->datum.dictionary; + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_csi_ostack_get_matrix (csi_t *ctx, unsigned int i, cairo_matrix_t *out) +{ + csi_object_t *obj; + int type; + + obj = _csi_peek_ostack (ctx, i); + type = csi_object_get_type (obj); + switch (type) { + case CSI_OBJECT_TYPE_MATRIX: + *out = obj->datum.matrix->matrix; + return CSI_STATUS_SUCCESS; + + case CSI_OBJECT_TYPE_ARRAY: + if (obj->datum.array->stack.len == 6) { + cairo_matrix_init (out, + csi_number_get_value (&obj->datum.array->stack.objects[0]), + csi_number_get_value (&obj->datum.array->stack.objects[1]), + csi_number_get_value (&obj->datum.array->stack.objects[2]), + csi_number_get_value (&obj->datum.array->stack.objects[3]), + csi_number_get_value (&obj->datum.array->stack.objects[4]), + csi_number_get_value (&obj->datum.array->stack.objects[5])); + return CSI_STATUS_SUCCESS; + } + /* else fall through */ + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } +} + +static csi_status_t +_csi_dictionary_get_integer (csi_t *ctx, + csi_dictionary_t *dict, + const char *name, + csi_boolean_t optional, + long *value) +{ + csi_status_t status; + csi_object_t key, obj; + int type; + + status = csi_name_new_static (ctx, &key, name); + if (_csi_unlikely (status)) + return status; + + if (optional && ! csi_dictionary_has (dict, key.datum.name)) + return CSI_STATUS_SUCCESS; + + status = csi_dictionary_get (ctx, dict, key.datum.name, &obj); + if (_csi_unlikely (status)) + return status; + + type = csi_object_get_type (&obj); + switch (type) { + case CSI_OBJECT_TYPE_BOOLEAN: + *value = obj.datum.boolean; + break; + case CSI_OBJECT_TYPE_INTEGER: + *value = obj.datum.integer; + break; + case CSI_OBJECT_TYPE_REAL: + *value = obj.datum.real; + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_csi_dictionary_get_number (csi_t *ctx, + csi_dictionary_t *dict, + const char *name, + csi_boolean_t optional, + double *value) +{ + csi_status_t status; + csi_object_t key, obj; + + status = csi_name_new_static (ctx, &key, name); + if (_csi_unlikely (status)) + return status; + + if (optional && ! csi_dictionary_has (dict, key.datum.name)) + return CSI_STATUS_SUCCESS; + + status = csi_dictionary_get (ctx, dict, key.datum.name, &obj); + if (_csi_unlikely (status)) + return status; + + *value = csi_number_get_value (&obj); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_csi_ostack_get_string (csi_t *ctx, unsigned int i, csi_string_t **out) +{ + csi_object_t *obj; + + obj = _csi_peek_ostack (ctx, i); + if (_csi_unlikely (csi_object_get_type (obj) != CSI_OBJECT_TYPE_STRING)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + *out = obj->datum.string; + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_csi_ostack_get_string_constant (csi_t *ctx, unsigned int i, const char **out) +{ + csi_object_t *obj; + int type; + + obj = _csi_peek_ostack (ctx, i); + type = csi_object_get_type (obj); + switch (type) { + case CSI_OBJECT_TYPE_NAME: + *out = (const char *) obj->datum.name; + break; + case CSI_OBJECT_TYPE_STRING: + *out = obj->datum.string->string; + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_do_cairo_op (csi_t *ctx, void (*op) (cairo_t *)) +{ + cairo_t *cr; + csi_status_t status; + + check (1); + + status = _csi_ostack_get_context (ctx, 0, &cr); + if (_csi_unlikely (status)) + return status; + + op (cr); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +end_dict_construction (csi_t *ctx) +{ + csi_object_t obj; + csi_dictionary_t *dict; + csi_status_t status; + + status = csi_dictionary_new (ctx, &obj); + if (_csi_unlikely (status)) + return status; + + dict = obj.datum.dictionary; + do { + csi_object_t *name, *value; + + check (1); + + value = _csi_peek_ostack (ctx, 0); + if (csi_object_get_type (value) == CSI_OBJECT_TYPE_MARK) { + pop (1); + break; + } + + check (2); + + name = _csi_peek_ostack (ctx, 1); + if (_csi_unlikely + (csi_object_get_type (name) != CSI_OBJECT_TYPE_NAME)) + { + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + status = csi_dictionary_put (ctx, dict, name->datum.name, value); + if (_csi_unlikely (status)) + return status; + + pop (2); + } while (TRUE); + + return push (&obj); +} + +static csi_status_t +end_array_construction (csi_t *ctx) +{ + csi_object_t obj; + csi_status_t status; + int len = 0; + + do { + check (len + 1); + + if (csi_object_get_type (_csi_peek_ostack (ctx, len)) == + CSI_OBJECT_TYPE_MARK) + { + break; + } + + len++; + } while (TRUE); + + status = csi_array_new (ctx, len, &obj); + if (_csi_unlikely (status)) + return status; + + if (len != 0) { + csi_array_t *array; + + array = obj.datum.array; + memcpy (array->stack.objects, + _csi_peek_ostack (ctx, len - 1), + sizeof (csi_object_t) * len); + array->stack.len = len; + } + ctx->ostack.len -= len + 1; + + return push (&obj); +} + +static csi_status_t +_alpha (csi_t *ctx) +{ + csi_object_t obj; + csi_status_t status; + double a; + + check (1); + + status = _csi_ostack_get_number (ctx, 0, &a); + if (_csi_unlikely (status)) + return status; + + pop (1); + + obj.type = CSI_OBJECT_TYPE_PATTERN; + obj.datum.pattern = cairo_pattern_create_rgba (0, 0, 0, a); + return push (&obj); +} + +static csi_status_t +_add (csi_t *ctx) +{ + csi_object_t *A; + csi_object_t *B; + csi_object_type_t type_a, type_b; + + check (2); + + B = _csi_peek_ostack (ctx, 0); + A = _csi_peek_ostack (ctx, 1); + + type_a = csi_object_get_type (A); + if (_csi_unlikely (! (type_a == CSI_OBJECT_TYPE_INTEGER || + type_a == CSI_OBJECT_TYPE_REAL))) + { + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + type_b = csi_object_get_type (B); + if (_csi_unlikely (! (type_b == CSI_OBJECT_TYPE_INTEGER || + type_b == CSI_OBJECT_TYPE_REAL))) + { + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + pop (2); + + if (type_a == CSI_OBJECT_TYPE_REAL && + type_b == CSI_OBJECT_TYPE_REAL) + { + return _csi_push_ostack_real (ctx, A->datum.real + B->datum.real); + + } + else if (type_a == CSI_OBJECT_TYPE_INTEGER && + type_b == CSI_OBJECT_TYPE_INTEGER) + { + return _csi_push_ostack_integer (ctx, + A->datum.integer + B->datum.integer); + } + else + { + double v; + + if (type_a == CSI_OBJECT_TYPE_REAL) + v = A->datum.real; + else + v = A->datum.integer; + + if (type_b == CSI_OBJECT_TYPE_REAL) + v += B->datum.real; + else + v += B->datum.integer; + + return _csi_push_ostack_real (ctx, v); + } +} + +static csi_status_t +_add_color_stop (csi_t *ctx) +{ + csi_status_t status; + double offset, r, g, b, a; + cairo_pattern_t *pattern = NULL; /* silence the compiler */ + + check (6); + + status = _csi_ostack_get_number (ctx, 0, &a); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &b); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 2, &g); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 3, &r); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 4, &offset); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_pattern (ctx, 5, &pattern); + if (_csi_unlikely (status)) + return status; + + cairo_pattern_add_color_stop_rgba (pattern, offset, r, g, b, a); + + pop (5); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_and (csi_t *ctx) +{ + csi_object_t *a, *b; + int type; + + check (2); + + a = _csi_peek_ostack (ctx, 0); + b = _csi_peek_ostack (ctx, 1); + if (_csi_unlikely (csi_object_get_type (a) != csi_object_get_type (b))) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + pop (2); + type = csi_object_get_type (a); + switch (type) { + case CSI_OBJECT_TYPE_INTEGER: + return _csi_push_ostack_integer (ctx, + a->datum.integer & b->datum.integer); + case CSI_OBJECT_TYPE_BOOLEAN: + return _csi_push_ostack_boolean (ctx, + a->datum.boolean & b->datum.boolean); + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } +} + +static csi_status_t +_arc (csi_t *ctx) +{ + csi_status_t status; + double x, y, r; + double theta1, theta2; + cairo_t *cr; + + check (6); + + status = _csi_ostack_get_number (ctx, 0, &theta2); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &theta1); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 2, &r); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 3, &y); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 4, &x); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 5, &cr); + if (_csi_unlikely (status)) + return status; + + /* XXX handle path object */ + + cairo_arc (cr, x, y, r, theta1, theta2); + pop (5); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_arc_negative (csi_t *ctx) +{ + csi_status_t status; + double x, y, r; + double theta1, theta2; + cairo_t *cr; + + check (6); + + status = _csi_ostack_get_number (ctx, 0, &theta2); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &theta1); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 2, &r); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 3, &y); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 4, &x); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 5, &cr); + if (_csi_unlikely (status)) + return status; + + /* XXX handle path object */ + + cairo_arc_negative (cr, x, y, r, theta1, theta2); + pop (5); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_array (csi_t *ctx) +{ + csi_object_t obj; + csi_status_t status; + + status = csi_array_new (ctx, 0, &obj); + if (_csi_unlikely (status)) + return status; + + return push (&obj); +} + +static csi_status_t +_bind_substitute (csi_t *ctx, csi_array_t *array) +{ + csi_status_t status; + csi_integer_t i, n; + csi_dictionary_t *dict; + + /* perform operator substitution on the executable array (procedure) */ + dict = ctx->dstack.objects[0].datum.dictionary; + n = array->stack.len; + for (i = 0; i < n; i++) { + csi_object_t *obj = &array->stack.objects[i]; + + if (obj->type == (CSI_OBJECT_TYPE_NAME | CSI_OBJECT_ATTR_EXECUTABLE)) { + csi_dictionary_entry_t *entry; + + entry = _csi_hash_table_lookup (&dict->hash_table, + (csi_hash_entry_t *) + &obj->datum.name); + if (entry != NULL) + *obj = entry->value; + } else if (csi_object_is_procedure (obj)) { + status = _bind_substitute (ctx, obj->datum.array); + if (_csi_unlikely (status)) + return status; + } + } + + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_idiom_substitute (csi_t *ctx, csi_array_t *array) +{ +#if 0 + csi_status_t status; + csi_integer_t i, j; + + /* XXX substring search, build array once then search for + * longest matching idiom, repeat. */ + + /* scan the top-most array for sequences we can pre-compile */ + + /* now recurse for subroutines */ + j = array->stack.len; + for (i = 0; i < j; i++) { + csi_object_t *obj = &array->stack.objects[i]; + + if (csi_object_is_procedure (obj)) { + status = _idiom_substitute (ctx, obj->datum.array); + if (_csi_unlikely (_cairo_is_error (status)) + return status; + } + } +#endif + + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_bind (csi_t *ctx) +{ + csi_array_t *array; + csi_status_t status; + + check (1); + + status = _csi_ostack_get_procedure (ctx, 0, &array); + if (_csi_unlikely (status)) + return status; + + status = _bind_substitute (ctx, array); + if (_csi_unlikely (status)) + return status; + + status = _idiom_substitute (ctx, array); + if (_csi_unlikely (status)) + return status; + + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_bitshift (csi_t *ctx) +{ + long v, shift; + csi_status_t status; + + check (2); + + status = _csi_ostack_get_integer (ctx, 0, &shift); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_integer (ctx, 1, &v); + if (_csi_unlikely (status)) + return status; + + if (shift < 0) { + shift = -shift; + v >>= shift; + } else + v <<= shift; + + pop (1); + _csi_peek_ostack (ctx, 0)->datum.integer = v; + + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_clip (csi_t *ctx) +{ + return _do_cairo_op (ctx, cairo_clip); +} + +static csi_status_t +_clip_preserve (csi_t *ctx) +{ + return _do_cairo_op (ctx, cairo_clip_preserve); +} + +static csi_status_t +_close_path (csi_t *ctx) +{ + return _do_cairo_op (ctx, cairo_close_path); +} + +static csi_status_t +_context (csi_t *ctx) +{ + csi_object_t obj; + csi_status_t status; + cairo_surface_t *surface; + cairo_t *cr; + csi_context_create_func_t hook; + csi_proxy_t *proxy; + + check (1); + + status = _csi_ostack_get_surface (ctx, 0, &surface); + if (_csi_unlikely (status)) + return status; + + hook = ctx->hooks.context_create; + if (hook != NULL) + cr = hook (ctx->hooks.closure, surface); + else + cr = cairo_create (surface); + + proxy = _csi_proxy_create (ctx, cr, NULL, + ctx->hooks.context_destroy, + ctx->hooks.closure); + if (_csi_unlikely (proxy == NULL)) { + cairo_destroy (cr); + return _csi_error (CSI_STATUS_NO_MEMORY); + } + + status = cairo_set_user_data (cr, &_csi_proxy_key, + proxy, _csi_proxy_destroy); + if (_csi_unlikely (status)) { + _csi_proxy_destroy (proxy); + cairo_destroy (cr); + return status; + } + + pop (1); + obj.type = CSI_OBJECT_TYPE_CONTEXT; + obj.datum.cr = cr; + return push (&obj); +} + +static csi_status_t +_copy (csi_t *ctx) +{ + csi_object_t *obj; + int type; + + check (1); + + obj = csi_object_reference (_csi_peek_ostack (ctx, 0)); + pop (1); + + type = csi_object_get_type (obj); + switch (type) { + /*XXX array, string, dictionary, etc */ + case CSI_OBJECT_TYPE_INTEGER: + { + long i, n; + + n = obj->datum.integer; + if (_csi_unlikely (n < 0)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + check (n); + + for (i = n; i--; ) { + csi_status_t status; + + status = _csi_push_ostack_copy (ctx, + _csi_peek_ostack (ctx, n-1)); + if (_csi_unlikely (status)) + return status; + } + break; + } + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_copy_page (csi_t *ctx) +{ + csi_object_t *obj; + int type; + + check (1); + + obj = _csi_peek_ostack (ctx, 0); + type = csi_object_get_type (obj); + switch (type) { + case CSI_OBJECT_TYPE_CONTEXT: + cairo_copy_page (obj->datum.cr); + if (ctx->hooks.copy_page != NULL) + ctx->hooks.copy_page (ctx->hooks.closure, obj->datum.cr); + break; + case CSI_OBJECT_TYPE_SURFACE: + cairo_surface_copy_page (obj->datum.surface); + /* XXX hook? */ + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_curve_to (csi_t *ctx) +{ + csi_status_t status; + csi_object_t *obj; + int type; + double x1, y1; + double x2, y2; + double x3, y3; + + check (7); + + status = _csi_ostack_get_number (ctx, 0, &y3); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &x3); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 2, &y2); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 3, &x2); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 4, &y1); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 5, &x1); + if (_csi_unlikely (status)) + return status; + + obj = _csi_peek_ostack (ctx, 6); + type = csi_object_get_type (obj); + switch (type) { + case CSI_OBJECT_TYPE_CONTEXT: + cairo_curve_to (obj->datum.cr, x1, y1, x2, y2, x3, y3); + break; + case CSI_OBJECT_TYPE_PATTERN: + cairo_mesh_pattern_curve_to (obj->datum.pattern, + x1, y1, x2, y2, x3, y3); + break; + /* XXX handle path object */ + } + + pop (6); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_cvi (csi_t *ctx) +{ + csi_object_t *val, obj; + int type; + + check (1); + + val = _csi_peek_ostack (ctx, 0); + type = csi_object_get_type (val); + switch (type) { + case CSI_OBJECT_TYPE_INTEGER: + return CSI_STATUS_SUCCESS; + + case CSI_OBJECT_TYPE_REAL: + pop (1); + return _csi_push_ostack_integer (ctx, val->datum.real); + + case CSI_OBJECT_TYPE_STRING: + if (! _csi_parse_number (&obj, + val->datum.string->string, + val->datum.string->len)) + { + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + pop (1); + if (csi_object_get_type (&obj) == CSI_OBJECT_TYPE_INTEGER) + return push (&obj); + else + return _csi_push_ostack_integer (ctx, obj.datum.real); + + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } +} + +static csi_status_t +_cvr (csi_t *ctx) +{ + csi_object_t *val, obj; + int type; + + check (1); + + val = _csi_peek_ostack (ctx, 0); + type = csi_object_get_type (val); + switch (type) { + case CSI_OBJECT_TYPE_REAL: + return CSI_STATUS_SUCCESS; + + case CSI_OBJECT_TYPE_INTEGER: + pop (1); + return _csi_push_ostack_real (ctx, val->datum.integer); + + case CSI_OBJECT_TYPE_STRING: + if (! _csi_parse_number (&obj, + val->datum.string->string, + val->datum.string->len)) + { + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + pop (1); + if (csi_object_get_type (&obj) == CSI_OBJECT_TYPE_REAL) + return push (&obj); + else + return _csi_push_ostack_real (ctx, obj.datum.integer); + + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } +} + +static csi_status_t +_def (csi_t *ctx) +{ + csi_name_t name = 0; /* silence the compiler */ + csi_status_t status; + + check (2); + + status = _csi_ostack_get_name (ctx, 1, &name); + if (_csi_unlikely (status)) + return status; + + status = _csi_name_define (ctx, name, _csi_peek_ostack (ctx, 0)); + if (_csi_unlikely (status)) + return status; + + pop (2); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_dict (csi_t *ctx) +{ + csi_object_t obj; + csi_status_t status; + + status = csi_dictionary_new (ctx, &obj); + if (_csi_unlikely (status)) + return status; + + return push (&obj); +} + +static csi_status_t +_div (csi_t *ctx) +{ + csi_object_t *A; + csi_object_t *B; + csi_object_type_t type_a, type_b; + + check (2); + + B = _csi_peek_ostack (ctx, 0); + A = _csi_peek_ostack (ctx, 1); + + type_a = csi_object_get_type (A); + if (_csi_unlikely (! (type_a == CSI_OBJECT_TYPE_INTEGER || + type_a == CSI_OBJECT_TYPE_REAL))) + { + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + type_b = csi_object_get_type (B); + if (_csi_unlikely (! (type_b == CSI_OBJECT_TYPE_INTEGER || + type_b == CSI_OBJECT_TYPE_REAL))) + { + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + pop (2); + + if (type_a == CSI_OBJECT_TYPE_REAL && + type_b == CSI_OBJECT_TYPE_REAL) + { + return _csi_push_ostack_real (ctx, A->datum.real / B->datum.real); + + } + else if (type_a == CSI_OBJECT_TYPE_INTEGER && + type_b == CSI_OBJECT_TYPE_INTEGER) + { + return _csi_push_ostack_integer (ctx, + A->datum.integer / B->datum.integer); + } + else + { + double v; + + if (type_a == CSI_OBJECT_TYPE_REAL) + v = A->datum.real; + else + v = A->datum.integer; + + if (type_b == CSI_OBJECT_TYPE_REAL) + v /= B->datum.real; + else + v /= B->datum.integer; + + return _csi_push_ostack_real (ctx, v); + } +} + +static csi_status_t +_duplicate (csi_t *ctx) +{ + check (1); + + return _csi_push_ostack_copy (ctx, _csi_peek_ostack (ctx, 0)); +} + +static csi_status_t +_eq (csi_t *ctx) +{ + csi_object_t *a, *b; + csi_boolean_t v; + + check (2); + + b = _csi_peek_ostack (ctx, 0); + a = _csi_peek_ostack (ctx, 1); + + v = csi_object_eq (a, b); + + pop (2); + return _csi_push_ostack_boolean (ctx, v); +} + +static csi_status_t +_exch (csi_t *ctx) +{ + return _csi_stack_exch (&ctx->ostack); +} + +static csi_status_t +_false (csi_t *ctx) +{ + return _csi_push_ostack_boolean (ctx, FALSE); +} + +static csi_status_t +_fill (csi_t *ctx) +{ + return _do_cairo_op (ctx, cairo_fill); +} + +static csi_status_t +_fill_preserve (csi_t *ctx) +{ + return _do_cairo_op (ctx, cairo_fill_preserve); +} + +static csi_status_t +_filter (csi_t *ctx) +{ + csi_object_t *src; + csi_dictionary_t *dict = NULL; + csi_status_t status; + const char *name = NULL; /* silence the compiler */ + const struct filters { + const char *name; + csi_status_t (*constructor) (csi_t *t, + csi_object_t *, + csi_dictionary_t *, + csi_object_t *); + } filters[] = { + { "ascii85", csi_file_new_ascii85_decode }, +#if HAVE_ZLIB + { "deflate", csi_file_new_deflate_decode }, +#endif +#if 0 + { "lzw", csi_file_new_lzw_decode }, +#endif + { NULL, NULL } + }, *filter; + int cnt; + + check (2); + + status = _csi_ostack_get_string_constant (ctx, 0, &name); + if (_csi_unlikely (status)) + return status; + + src = _csi_peek_ostack (ctx, 1); + cnt = 2; + if (csi_object_get_type (src) == CSI_OBJECT_TYPE_DICTIONARY) { + dict = src->datum.dictionary; + + check (3); + + src = _csi_peek_ostack (ctx, 2); + cnt = 3; + } + + for (filter = filters; filter->name != NULL; filter++) { + if (strcmp (name, filter->name) == 0) { + csi_object_t file; + + status = filter->constructor (ctx, &file, dict, src); + if (_csi_unlikely (status)) + return status; + + pop (cnt); + return push (&file); + } + } + + return _csi_error (CSI_STATUS_INVALID_SCRIPT); +} + +static cairo_status_t +_type3_init (cairo_scaled_font_t *scaled_font, + cairo_t *cr, + cairo_font_extents_t *metrics) +{ + cairo_font_face_t *face; + csi_proxy_t *proxy; + csi_t *ctx; + csi_dictionary_t *font; + csi_object_t key; + csi_object_t obj; + csi_array_t *array; + csi_status_t status; + + face = cairo_scaled_font_get_font_face (scaled_font); + proxy = cairo_font_face_get_user_data (face, &_csi_proxy_key); + if (_csi_unlikely (proxy == NULL)) + return CAIRO_STATUS_NO_MEMORY; + + ctx = proxy->ctx; + font = proxy->dictionary; + + status = csi_name_new_static (ctx, &key, "metrics"); + if (_csi_unlikely (status)) + return CAIRO_STATUS_NO_MEMORY; + + if (! csi_dictionary_has (font, key.datum.name)) + return CAIRO_STATUS_SUCCESS; + + status = csi_dictionary_get (ctx, font, key.datum.name, &obj); + if (_csi_unlikely (status)) + return status; + + if (csi_object_get_type (&obj) != CSI_OBJECT_TYPE_ARRAY) + return CAIRO_STATUS_USER_FONT_ERROR; + + array = obj.datum.array; + if (array->stack.len != 5) + return CAIRO_STATUS_USER_FONT_ERROR; + + metrics->ascent = csi_number_get_value (&array->stack.objects[0]); + metrics->descent = csi_number_get_value (&array->stack.objects[1]); + metrics->height = csi_number_get_value (&array->stack.objects[2]); + metrics->max_x_advance = csi_number_get_value (&array->stack.objects[3]); + metrics->max_y_advance = csi_number_get_value (&array->stack.objects[4]); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_type3_lookup (cairo_scaled_font_t *scaled_font, + unsigned long unicode, + unsigned long *glyph) +{ + cairo_font_face_t *face; + csi_proxy_t *proxy; + csi_t *ctx; + csi_dictionary_t *font; + csi_object_t obj, key; + csi_array_t *array; + char buf[12]; + csi_integer_t i; + cairo_status_t status; + + face = cairo_scaled_font_get_font_face (scaled_font); + proxy = cairo_font_face_get_user_data (face, &_csi_proxy_key); + if (_csi_unlikely (proxy == NULL)) + return CAIRO_STATUS_USER_FONT_ERROR; + + ctx = proxy->ctx; + font = proxy->dictionary; + + status = csi_name_new_static (ctx, &key, "encoding"); + if (_csi_unlikely (status)) + return CAIRO_STATUS_USER_FONT_ERROR; + + if (! csi_dictionary_has (font, key.datum.name)) { + *glyph = unicode; + return CAIRO_STATUS_SUCCESS; + } + + status = csi_dictionary_get (ctx, font, key.datum.name, &obj); + if (_csi_unlikely (status)) + return CAIRO_STATUS_USER_FONT_ERROR; + + if (_csi_unlikely (csi_object_get_type (&obj) != CSI_OBJECT_TYPE_ARRAY)) + return CAIRO_STATUS_USER_FONT_ERROR; + + snprintf (buf, sizeof (buf), "uni%04lu", unicode); + array = obj.datum.array; + for (i = 0; i < array->stack.len; i++) { + csi_object_t *name; + + name = &array->stack.objects[i]; + if (csi_object_get_type (name) != CSI_OBJECT_TYPE_NAME) + continue; + + if (strcmp ((char *) name->datum.name, buf) == 0) { + *glyph = i; + return CAIRO_STATUS_SUCCESS; + } + } + + return CAIRO_STATUS_USER_FONT_ERROR; +} + +static cairo_status_t +_type3_render (cairo_scaled_font_t *scaled_font, + unsigned long glyph_index, + cairo_t *cr, + cairo_text_extents_t *metrics) +{ + cairo_font_face_t *face; + csi_proxy_t *proxy; + csi_t *ctx; + csi_dictionary_t *font; + csi_array_t *glyphs; + csi_object_t *glyph; + csi_object_t key; + csi_object_t obj; + csi_object_t render; + csi_status_t status; + + face = cairo_scaled_font_get_font_face (scaled_font); + proxy = cairo_font_face_get_user_data (face, &_csi_proxy_key); + if (_csi_unlikely (proxy == NULL)) + return CAIRO_STATUS_USER_FONT_ERROR; + + ctx = proxy->ctx; + font = proxy->dictionary; + + status = csi_name_new_static (ctx, &key, "glyphs"); + if (_csi_unlikely (status)) + return CAIRO_STATUS_USER_FONT_ERROR; + + status = csi_dictionary_get (ctx, font, key.datum.name, &obj); + if (_csi_unlikely (status)) + return CAIRO_STATUS_USER_FONT_ERROR; + + if (_csi_unlikely (csi_object_get_type (&obj) != CSI_OBJECT_TYPE_ARRAY)) + return CAIRO_STATUS_USER_FONT_ERROR; + + glyphs = obj.datum.array; + glyph = &glyphs->stack.objects[glyph_index]; + if (csi_object_get_type (glyph) == CSI_OBJECT_TYPE_NULL) + return CAIRO_STATUS_SUCCESS; /* .notdef */ + + if (_csi_unlikely (csi_object_get_type (glyph) != CSI_OBJECT_TYPE_DICTIONARY)) + return CAIRO_STATUS_USER_FONT_ERROR; + + status = csi_name_new_static (ctx, &key, "metrics"); + if (_csi_unlikely (status)) + return CAIRO_STATUS_USER_FONT_ERROR; + + font = glyph->datum.dictionary; + if (csi_dictionary_has (font, key.datum.name)) { + csi_array_t *array; + + status = csi_dictionary_get (ctx, font, key.datum.name, &obj); + if (_csi_unlikely (status)) + return CAIRO_STATUS_USER_FONT_ERROR; + + if (_csi_unlikely (csi_object_get_type (&obj) != + CSI_OBJECT_TYPE_ARRAY)) + return CAIRO_STATUS_USER_FONT_ERROR; + + array = obj.datum.array; + if (_csi_unlikely (array->stack.len != 6)) + return CAIRO_STATUS_USER_FONT_ERROR; + + metrics->x_bearing = csi_number_get_value (&array->stack.objects[0]); + metrics->y_bearing = csi_number_get_value (&array->stack.objects[1]); + metrics->width = csi_number_get_value (&array->stack.objects[2]); + metrics->height = csi_number_get_value (&array->stack.objects[3]); + metrics->x_advance = csi_number_get_value (&array->stack.objects[4]); + metrics->y_advance = csi_number_get_value (&array->stack.objects[5]); + } + + status = csi_name_new_static (ctx, &key, "render"); + if (_csi_unlikely (status)) + return CAIRO_STATUS_USER_FONT_ERROR; + + status = csi_dictionary_get (ctx, font, key.datum.name, &render); + if (_csi_unlikely (status)) + return CAIRO_STATUS_USER_FONT_ERROR; + + if (_csi_unlikely (! csi_object_is_procedure (&render))) + return CAIRO_STATUS_USER_FONT_ERROR; + + obj.type = CSI_OBJECT_TYPE_CONTEXT; + obj.datum.cr = cairo_reference (cr); + status = push (&obj); + if (_csi_unlikely (status)) { + cairo_destroy (cr); + return CAIRO_STATUS_USER_FONT_ERROR; + } + + status = csi_object_execute (ctx, &render); + pop (1); + return status ? CAIRO_STATUS_USER_FONT_ERROR : CAIRO_STATUS_SUCCESS; +} + +static csi_status_t +_font_type3 (csi_t *ctx, + csi_dictionary_t *font, + cairo_font_face_t **font_face_out) +{ + cairo_font_face_t *font_face; + + font_face = cairo_user_font_face_create (); + cairo_user_font_face_set_init_func (font_face, _type3_init); + cairo_user_font_face_set_unicode_to_glyph_func (font_face, _type3_lookup); + cairo_user_font_face_set_render_glyph_func (font_face, _type3_render); + + *font_face_out = font_face; + return CSI_STATUS_SUCCESS; +} + +#if CAIRO_HAS_FT_FONT +#include +#include +#include FT_FREETYPE_H + +static FT_Library _ft_lib; + +struct _ft_face_data { + csi_t *ctx; + csi_blob_t blob; + FT_Face face; + csi_string_t *source; + void *bytes; + cairo_font_face_t *font_face; +}; + +static void +_ft_done_face (void *closure) +{ + struct _ft_face_data *data = closure; + csi_t *ctx; + + ctx = data->ctx; + + if (data->face != NULL) + FT_Done_Face (data->face); + + ctx->_faces = _csi_list_unlink (ctx->_faces, &data->blob.list); + + if (data->source != NULL) { + if (--data->source->base.ref == 0) + csi_string_free (ctx, data->source); + } else { +#ifdef HAVE_MMAP + munmap (data->blob.bytes, data->blob.len); +#endif + } + + if (data->bytes != NULL) + _csi_free (ctx, data->bytes); + + _csi_slab_free (ctx, data, sizeof (*data)); + + cairo_script_interpreter_destroy (ctx); +} + +struct mmap_vec { + const uint8_t *bytes; + size_t num_bytes; +}; + +#ifdef HAVE_MMAP +/* manual form of swapping for swapless systems like tiny */ +static void * +_mmap_bytes (const struct mmap_vec *vec, int count) +{ + char template[] = "/tmp/csi-font.XXXXXX"; + void *ptr; + int fd; + int num_bytes; + + fd = mkstemp (template); + if (fd == -1) + return MAP_FAILED; + + unlink (template); + num_bytes = 0; + while (count--) { + const uint8_t *bytes = vec->bytes; + size_t len = vec->num_bytes; + while (len) { + int ret = write (fd, bytes, len); + if (ret < 0) { + close (fd); + return MAP_FAILED; + } + len -= ret; + bytes += ret; + } + + num_bytes += vec->num_bytes; + vec++; + } + + ptr = mmap (NULL, num_bytes, PROT_READ, MAP_SHARED, fd, 0); + close (fd); + + return ptr; +} +#endif + +static void * +inflate_string (csi_t *ctx, csi_string_t *src) +{ + uLongf len; + uint8_t *bytes; + + len = src->deflate; + bytes = _csi_alloc (ctx, len + 1); + if (bytes == NULL) + return NULL; + + switch (src->method) { + default: + case NONE: + free (bytes); + return NULL; + + case ZLIB: +#if HAVE_ZLIB + if (uncompress ((Bytef *) bytes, &len, + (Bytef *) src->string, src->len) != Z_OK) +#endif + { + _csi_free (ctx, bytes); + return NULL; + } + break; + + case LZO: +#if HAVE_LZO + if (lzo2a_decompress ((Bytef *) src->string, src->len, + (Bytef *) bytes, &len, + NULL)) +#endif + { + _csi_free (ctx, bytes); + return NULL; + } + break; + } + + bytes[len] = '\0'; + return bytes; +} + +static csi_status_t +_ft_create_for_source (csi_t *ctx, + csi_string_t *source, + int index, int load_flags, + cairo_font_face_t **font_face_out) +{ + csi_blob_t tmpl; + struct _ft_face_data *data; + csi_list_t *link; + FT_Error err; + cairo_font_face_t *font_face; + csi_status_t status; + struct mmap_vec vec[2]; + int vec_count; + void *bytes; + int len; + + /* check for an existing FT_Face (kept alive by the font cache) */ + /* XXX index/flags */ + _csi_blob_init (&tmpl, (uint8_t *) source->string, source->len); + _csi_blob_hash (&tmpl, (uint32_t *) source->string, source->len / sizeof (uint32_t)); + link = _csi_list_find (ctx->_faces, _csi_blob_equal, &tmpl); + if (link) { + if (--source->base.ref == 0) + csi_string_free (ctx, source); + data = csi_container_of (link, struct _ft_face_data, blob.list); + *font_face_out = cairo_font_face_reference (data->font_face); + return CSI_STATUS_SUCCESS; + } + + /* no existing font_face, create new FT_Face */ + if (_ft_lib == NULL) { + err = FT_Init_FreeType (&_ft_lib); + if (_csi_unlikely (err != FT_Err_Ok)) + return _csi_error (CSI_STATUS_NO_MEMORY); + } + + data = _csi_slab_alloc (ctx, sizeof (*data)); + data->bytes = NULL; + data->source = source; + + vec[0].bytes = tmpl.bytes; + vec[0].num_bytes = tmpl.len; + + if (source->deflate) { + len = source->deflate; + bytes = inflate_string (ctx, source); + if (_csi_unlikely (bytes == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + + vec[1].bytes = bytes; + vec[1].num_bytes = len; + data->bytes = bytes; + vec_count = 2; + } else { + bytes = tmpl.bytes; + len = tmpl.len; + vec_count = 1; + } + + data->face = NULL; + ctx->_faces = _csi_list_prepend (ctx->_faces, &data->blob.list); + data->ctx = cairo_script_interpreter_reference (ctx); + data->blob.hash = tmpl.hash; + data->blob.len = tmpl.len; +#ifdef HAVE_MMAP + data->blob.bytes = _mmap_bytes (vec, vec_count); + if (data->blob.bytes != MAP_FAILED) { + if (--source->base.ref == 0) + csi_string_free (ctx, source); + + if (source->deflate) { + _csi_free (ctx, bytes); + bytes = data->blob.bytes + vec[0].num_bytes; + } else + bytes = data->blob.bytes; + + data->source = NULL; + data->bytes = NULL; + } else { + data->blob.bytes = tmpl.bytes; + } +#else + data->blob.bytes = tmpl.bytes; +#endif + + err = FT_New_Memory_Face (_ft_lib, + bytes, len, + index, + &data->face); + if (_csi_unlikely (err != FT_Err_Ok)) { + _ft_done_face (data); + + if (err == FT_Err_Out_Of_Memory) + return _csi_error (CSI_STATUS_NO_MEMORY); + + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + font_face = cairo_ft_font_face_create_for_ft_face (data->face, load_flags); + status = cairo_font_face_set_user_data (font_face, + &_csi_blob_key, + data, _ft_done_face); + if (_csi_unlikely (status)) { + _ft_done_face (data); + cairo_font_face_destroy (font_face); + return status; + } + + data->font_face = font_face; + *font_face_out = font_face; + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_ft_create_for_pattern (csi_t *ctx, + csi_string_t *string, + cairo_font_face_t **font_face_out) +{ +#if CAIRO_HAS_FC_FONT + csi_blob_t tmpl; + struct _ft_face_data *data; + csi_list_t *link; + cairo_font_face_t *font_face; + FcPattern *pattern, *resolved; + csi_status_t status; + struct mmap_vec vec; + void *bytes; + + _csi_blob_init (&tmpl, (uint8_t *) string->string, string->len); + _csi_blob_hash (&tmpl, (uint32_t *) string->string, string->len / sizeof (uint32_t)); + link = _csi_list_find (ctx->_faces, _csi_blob_equal, &tmpl); + if (link) { + if (--string->base.ref == 0) + csi_string_free (ctx, string); + data = csi_container_of (link, struct _ft_face_data, blob.list); + *font_face_out = cairo_font_face_reference (data->font_face); + return CSI_STATUS_SUCCESS; + } + + if (string->deflate) { + bytes = inflate_string (ctx, string); + if (_csi_unlikely (bytes == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + } else { + bytes = tmpl.bytes; + } + + pattern = FcNameParse (bytes); + if (!pattern) + { + /* Fontconfig's representation of charset changed mid 2014; + * We used to record charset before that. Remove everything + * after charset if that's present, and try again. */ + char *s = strstr ((char *) bytes, ":charset="); + if (s) + { + *s = '\0'; + pattern = FcNameParse (bytes); + } + } + if (bytes != tmpl.bytes) + _csi_free (ctx, bytes); + +retry: + resolved = pattern; + if (cairo_version () < CAIRO_VERSION_ENCODE (1, 9, 0)) { + /* prior to 1.9, you needed to pass a resolved pattern */ + resolved = FcFontMatch (NULL, pattern, NULL); + if (_csi_unlikely (resolved == NULL)) { + FcPatternDestroy (pattern); + return _csi_error (CSI_STATUS_NO_MEMORY); + } + } + + font_face = cairo_ft_font_face_create_for_pattern (resolved); + if (resolved != pattern) + FcPatternDestroy (resolved); + + if (cairo_font_face_status (font_face)) { + char *filename = NULL; + + /* Try a manual fallback process by eliminating specific requests */ + + if (FcPatternGetString (pattern, + FC_FILE, 0, + (FcChar8 **) &filename) == FcResultMatch) { + FcPatternDel (pattern, FC_FILE); + goto retry; + } + } + + FcPatternDestroy (pattern); + + data = _csi_slab_alloc (ctx, sizeof (*data)); + ctx->_faces = _csi_list_prepend (ctx->_faces, &data->blob.list); + data->ctx = cairo_script_interpreter_reference (ctx); + data->blob.hash = tmpl.hash; + data->blob.len = tmpl.len; + data->bytes = NULL; + data->face = NULL; +#ifdef HAVE_MMAP + vec.bytes = tmpl.bytes; + vec.num_bytes = tmpl.len; + data->blob.bytes = _mmap_bytes (&vec, 1); + if (data->blob.bytes != MAP_FAILED) { + data->source = NULL; + if (--string->base.ref == 0) + csi_string_free (ctx, string); + } else { + data->blob.bytes = tmpl.bytes; + data->source = string; + } +#else + data->blob.bytes = tmpl.bytes; + data->source = string; +#endif + + status = cairo_font_face_set_user_data (font_face, + &_csi_blob_key, + data, _ft_done_face); + if (_csi_unlikely (status)) { + _ft_done_face (data); + cairo_font_face_destroy (font_face); + return status; + } + + data->font_face = font_face; + *font_face_out = font_face; + return CSI_STATUS_SUCCESS; +#else + if (--string->base.ref == 0) + csi_string_free (ctx, string); + return CSI_INT_STATUS_UNSUPPORTED; +#endif +} + +static csi_status_t +_ft_type42_create (csi_t *ctx, + csi_dictionary_t *font, + cairo_font_face_t **font_face_out) +{ + csi_object_t key; + csi_status_t status; + + /* two basic sub-types, either an FcPattern or embedded font */ + status = csi_name_new_static (ctx, &key, "pattern"); + if (_csi_unlikely (status)) + return status; + + if (csi_dictionary_has (font, key.datum.name)) { + csi_object_t obj; + int type; + + status = csi_dictionary_get (ctx, font, key.datum.name, &obj); + if (_csi_unlikely (status)) + return status; + + type = csi_object_get_type (&obj); + switch (type) { + case CSI_OBJECT_TYPE_FILE: + status = _csi_file_as_string (ctx, obj.datum.file, &obj); + if (_csi_unlikely (status)) + return status; + break; + case CSI_OBJECT_TYPE_STRING: + obj.datum.object->ref++; + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + return _ft_create_for_pattern (ctx, + obj.datum.string, + font_face_out); + } + + status = csi_name_new_static (ctx, &key, "source"); + if (_csi_unlikely (status)) + return status; + + if (csi_dictionary_has (font, key.datum.name)) { + csi_object_t obj; + long index, flags; + int type; + + index = 0; + status = _csi_dictionary_get_integer (ctx, font, "index", TRUE, &index); + if (_csi_unlikely (status)) + return status; + + flags = 0; + status = _csi_dictionary_get_integer (ctx, font, "flags", TRUE, &flags); + if (_csi_unlikely (status)) + return status; + + status = csi_name_new_static (ctx, &key, "source"); + if (_csi_unlikely (status)) + return status; + status = csi_dictionary_get (ctx, font, key.datum.name, &obj); + if (_csi_unlikely (status)) + return status; + type = csi_object_get_type (&obj); + switch (type) { + case CSI_OBJECT_TYPE_FILE: + status = _csi_file_as_string (ctx, obj.datum.file, &obj); + if (_csi_unlikely (status)) + return status; + break; + case CSI_OBJECT_TYPE_STRING: + obj.datum.object->ref++; + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + return _ft_create_for_source (ctx, obj.datum.string, + index, flags, + font_face_out); + } + + return _csi_error (CSI_STATUS_INVALID_SCRIPT); +} +#else +#define _ft_type42_create(ctx, font, face_out) CSI_INT_STATUS_UNSUPPORTED +#endif + +static char * +_fc_strcpy (csi_t *ctx, const char *str) +{ + char *ret; + int len; + + ret = strchr (str, ':'); + if (ret != NULL) + len = ret - str; + else + len = strlen (str); + + ret = _csi_alloc (ctx, len+1); + if (_csi_unlikely (ret == NULL)) + return NULL; + + memcpy (ret, str, len); + ret[len] = '\0'; + + return ret; +} + +static cairo_font_face_t * +_select_font (const char *name) +{ + cairo_surface_t *surface; + cairo_font_face_t *face; + cairo_t *cr; + + /* create a dummy context to choose a font */ + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0); + cr = cairo_create (surface); + cairo_surface_destroy (surface); + + cairo_select_font_face (cr, name, + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + face = cairo_font_face_reference (cairo_get_font_face (cr)); + cairo_destroy (cr); + + return face; +} + +static csi_status_t +_ft_fallback_create_for_pattern (csi_t *ctx, + csi_string_t *string, + cairo_font_face_t **font_face_out) +{ + char *str, *name; + + str = string->string; +#if 0 + name = strstr (str, "fullname="); + if (name != NULL) + str = name + 9; +#endif + + name = _fc_strcpy (ctx, str); + if (_csi_unlikely (name == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + + *font_face_out = _select_font (name); + _csi_free (ctx, name); + + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_ft_type42_fallback_create (csi_t *ctx, + csi_dictionary_t *font, + cairo_font_face_t **font_face_out) +{ + csi_object_t key; + csi_status_t status; + + /* attempt to select a similar font */ + + /* two basic sub-types, either an FcPattern or embedded font */ + status = csi_name_new_static (ctx, &key, "pattern"); + if (_csi_unlikely (status)) + return status; + + if (csi_dictionary_has (font, key.datum.name)) { + csi_object_t obj; + int type; + + status = csi_dictionary_get (ctx, font, key.datum.name, &obj); + if (_csi_unlikely (status)) + return status; + + type = csi_object_get_type (&obj); + switch (type) { + case CSI_OBJECT_TYPE_FILE: + status = _csi_file_as_string (ctx, obj.datum.file, &obj); + if (_csi_unlikely (status)) + return status; + break; + case CSI_OBJECT_TYPE_STRING: + obj.datum.object->ref++; + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + return _ft_fallback_create_for_pattern (ctx, + obj.datum.string, + font_face_out); + } + + /* XXX: enable the trace to run */ + *font_face_out = _select_font ("Sans"); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_font_type42 (csi_t *ctx, csi_dictionary_t *font, cairo_font_face_t **font_face) +{ + csi_status_t status; + + status = _ft_type42_create (ctx, font, font_face); + if (_csi_likely (status != CSI_INT_STATUS_UNSUPPORTED)) + return status; + + return _ft_type42_fallback_create (ctx, font, font_face); +} + +static csi_status_t +_font (csi_t *ctx) +{ + csi_dictionary_t *font; + csi_status_t status; + cairo_font_face_t *font_face = NULL; /* silence the compiler */ + csi_proxy_t *proxy; + csi_object_t obj; + long type; + + check (1); + + status = _csi_ostack_get_dictionary (ctx, 0, &font); + if (_csi_unlikely (status)) + return status; + + status = _csi_dictionary_get_integer (ctx, font, "type", FALSE, &type); + if (_csi_unlikely (status)) + return status; + + switch (type) { + case 3: + status = _font_type3 (ctx, font, &font_face); + break; + case 42: + status = _font_type42 (ctx, font, &font_face); + break; + default: + status = _csi_error (CSI_STATUS_INVALID_SCRIPT); + break; + } + + if (_csi_unlikely (status)) + return status; + + /* transfer ownership of dictionary to cairo_font_face_t */ + proxy = _csi_proxy_create (ctx, font_face, font, NULL, NULL); + if (_csi_unlikely (proxy == NULL)) { + cairo_font_face_destroy (font_face); + return _csi_error (CSI_STATUS_NO_MEMORY); + } + + status = cairo_font_face_set_user_data (font_face, + &_csi_proxy_key, + proxy, _csi_proxy_destroy); + if (_csi_unlikely (status)) { + _csi_proxy_destroy (proxy); + cairo_font_face_destroy (font_face); + return status; + } + + obj.type = CSI_OBJECT_TYPE_FONT; + obj.datum.font_face = font_face; + + pop (1); + status = push (&obj); + if (_csi_unlikely (status)) { + cairo_font_face_destroy (font_face); + return status; + } + + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_for (csi_t *ctx) +{ + csi_array_t *proc; + csi_status_t status; + long i, inc, limit; + + check (4); + + status = _csi_ostack_get_procedure (ctx, 0, &proc); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_integer (ctx, 1, &limit); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_integer (ctx, 2, &inc); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_integer (ctx, 3, &i); + if (_csi_unlikely (status)) + return status; + + proc->base.ref++; + pop (4); + + for (; i <= limit; i += inc) { + status = _csi_push_ostack_integer (ctx, i); + if (_csi_unlikely (status)) + break; + + status = _csi_array_execute (ctx, proc); + if (_csi_unlikely (status)) + break; + } + + if (--proc->base.ref == 0) + csi_array_free (ctx, proc); + return status; +} + +static csi_status_t +_ge (csi_t *ctx) +{ + csi_status_t status; + csi_object_t *a, *b; + int cmp; + + check (2); + + b = _csi_peek_ostack (ctx, 0); + a = _csi_peek_ostack (ctx, 1); + + status = csi_object_compare (a, b, &cmp); + if (_csi_unlikely (status)) + return status; + + pop (2); + return _csi_push_ostack_boolean (ctx, cmp >= 0); +} + +static csi_status_t +_proxy_get (csi_proxy_t *proxy, + csi_name_t key) +{ + csi_object_t obj; + csi_status_t status; + + if (_csi_unlikely (proxy == NULL || proxy->dictionary == NULL)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + status = csi_dictionary_get (proxy->ctx, proxy->dictionary, key, &obj); + if (_csi_unlikely (status)) + return status; + + return _csi_push_ostack_copy (proxy->ctx, &obj); +} + +static csi_status_t +_context_get (csi_t *ctx, + cairo_t *cr, + csi_name_t key) +{ + csi_status_t status; + csi_object_t obj; + + if (strcmp ((char *) key, "current-point") == 0) { + double x, y; + + cairo_get_current_point (cr, &x, &y); + + status = _csi_push_ostack_real (ctx, x); + if (_csi_unlikely (status)) + return status; + status = _csi_push_ostack_real (ctx, y); + if (_csi_unlikely (status)) + return status; + + return CSI_STATUS_SUCCESS; + } else if (strcmp ((char *) key, "source") == 0) { + obj.type = CSI_OBJECT_TYPE_PATTERN; + obj.datum.pattern = cairo_pattern_reference (cairo_get_source (cr)); + } else if (strcmp ((char *) key, "target") == 0) { + obj.type = CSI_OBJECT_TYPE_SURFACE; + obj.datum.surface = cairo_surface_reference (cairo_get_target (cr)); + } else if (strcmp ((char *) key, "group-target") == 0) { + obj.type = CSI_OBJECT_TYPE_SURFACE; + obj.datum.surface = cairo_surface_reference (cairo_get_group_target (cr)); + } else if (strcmp ((char *) key, "scaled-font") == 0) { + obj.type = CSI_OBJECT_TYPE_SCALED_FONT; + obj.datum.scaled_font = cairo_scaled_font_reference (cairo_get_scaled_font (cr)); + } else if (strcmp ((char *) key, "font-face") == 0) { + obj.type = CSI_OBJECT_TYPE_FONT; + obj.datum.font_face = cairo_font_face_reference (cairo_get_font_face (cr)); + } else + return _proxy_get (cairo_get_user_data (cr, &_csi_proxy_key), key); + + return push (&obj); +} + +static csi_status_t +_font_get (csi_t *ctx, + cairo_font_face_t *font_face, + csi_name_t key) +{ + return _proxy_get (cairo_font_face_get_user_data (font_face, + &_csi_proxy_key), + key); +} + +static csi_status_t +_pattern_get (csi_t *ctx, + cairo_pattern_t *pattern, + csi_name_t key) +{ + csi_status_t status; + + if (strcmp ((char *) key, "type") == 0) + return _csi_push_ostack_integer (ctx, cairo_pattern_get_type (pattern)); + + if (strcmp ((char *) key, "filter") == 0) + return _csi_push_ostack_integer (ctx, cairo_pattern_get_filter (pattern)); + + if (strcmp ((char *) key, "extend") == 0) + return _csi_push_ostack_integer (ctx, cairo_pattern_get_extend (pattern)); + + if (strcmp ((char *) key, "matrix") == 0) { + csi_object_t obj; + cairo_matrix_t m; + + cairo_pattern_get_matrix (pattern, &m); + status = csi_matrix_new_from_matrix (ctx, &obj, &m); + if (_csi_unlikely (status)) + return status; + + return push (&obj); + } + + return _proxy_get (cairo_pattern_get_user_data (pattern, &_csi_proxy_key), + key); +} + +static csi_status_t +_scaled_font_get (csi_t *ctx, + cairo_scaled_font_t *font, + csi_name_t key) +{ + return _proxy_get (cairo_scaled_font_get_user_data (font, &_csi_proxy_key), + key); +} + +static csi_status_t +_surface_get (csi_t *ctx, + cairo_surface_t *surface, + csi_name_t key) +{ + if (strcmp ((char *) key, "type") == 0) { + return _csi_push_ostack_integer (ctx, cairo_surface_get_type (surface)); + } + + if (strcmp ((char *) key, "content") == 0) { + return _csi_push_ostack_integer (ctx, + cairo_surface_get_content (surface)); + } + + return _proxy_get (cairo_surface_get_user_data (surface, &_csi_proxy_key), + key); +} + +static csi_status_t +_get (csi_t *ctx) +{ + csi_object_t *key, *src, obj; + csi_status_t status; + int type; + + check (2); + + key = _csi_peek_ostack (ctx, 0); + src = _csi_peek_ostack (ctx, 1); + pop (1); + type = csi_object_get_type (src); + switch (type) { + case CSI_OBJECT_TYPE_DICTIONARY: + if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + status = csi_dictionary_get (ctx, + src->datum.dictionary, + key->datum.name, + &obj); + break; + case CSI_OBJECT_TYPE_ARRAY: + if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_INTEGER)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + status = csi_array_get (ctx, + src->datum.array, + key->datum.integer, + &obj); + break; +#if 0 + case CSI_OBJECT_TYPE_STRING: + status = csi_string_get (src, key, &obj); + break; +#endif + + case CSI_OBJECT_TYPE_CONTEXT: + if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + return _context_get (ctx, src->datum.cr, key->datum.name); + + case CSI_OBJECT_TYPE_FONT: + if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + return _font_get (ctx, src->datum.font_face, key->datum.name); + + case CSI_OBJECT_TYPE_PATTERN: + if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + return _pattern_get (ctx, src->datum.pattern, key->datum.name); + + case CSI_OBJECT_TYPE_SCALED_FONT: + if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + return _scaled_font_get (ctx, src->datum.scaled_font, key->datum.name); + + case CSI_OBJECT_TYPE_SURFACE: + if (_csi_unlikely (csi_object_get_type (key) != CSI_OBJECT_TYPE_NAME)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + return _surface_get (ctx, src->datum.surface, key->datum.name); + + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + if (_csi_unlikely (status)) + return status; + + return _csi_push_ostack_copy (ctx, &obj); +} + +struct glyph_advance_cache { + csi_t *ctx; + double glyph_advance[256][2]; + unsigned long have_glyph_advance[256]; +}; + +static void +glyph_advance_cache_destroy (void *closure) +{ + struct glyph_advance_cache *cache = closure; + _csi_free (cache->ctx, cache); +} + +static int +_glyph_string (csi_t *ctx, + csi_array_t *array, + cairo_scaled_font_t *scaled_font, + cairo_glyph_t *glyphs) +{ + struct glyph_advance_cache uncached; + struct glyph_advance_cache *cache; + csi_integer_t nglyphs, i, j; + double x, y, dx; + cairo_status_t status; + + if (cairo_scaled_font_status (scaled_font)) + return 0; + + cache = cairo_scaled_font_get_user_data (scaled_font, + (cairo_user_data_key_t *) ctx); + if (cache == NULL) { + cache = _csi_alloc (ctx, sizeof (*cache)); + if (_csi_likely (cache != NULL)) { + cache->ctx = ctx; + memset (cache->have_glyph_advance, 0xff, + sizeof (cache->have_glyph_advance)); + + status = cairo_scaled_font_set_user_data (scaled_font, + (cairo_user_data_key_t *) ctx, + cache, + glyph_advance_cache_destroy); + if (_csi_unlikely (status)) { + _csi_free (ctx, cache); + cache = NULL; + } + } + } + + if (_csi_unlikely (cache == NULL)) { + cache = &uncached; + + cache->ctx = ctx; + memset (cache->have_glyph_advance, 0xff, + sizeof (cache->have_glyph_advance)); + } + + nglyphs = 0; + x = y = 0; + for (i = 0; i < array->stack.len; i++) { + const csi_object_t *obj = &array->stack.objects[i]; + int type = csi_object_get_type (obj); + + switch (type) { + case CSI_OBJECT_TYPE_ARRAY: { + const csi_array_t *glyph_array = obj->datum.array; + for (j = 0; j < glyph_array->stack.len; j++) { + unsigned long g; + int gi; + + obj = &glyph_array->stack.objects[j]; + if (csi_object_get_type (obj) != CSI_OBJECT_TYPE_INTEGER) + break; + g = obj->datum.integer; + + glyphs[nglyphs].index = g; + glyphs[nglyphs].x = x; + glyphs[nglyphs].y = y; + + gi = g % ARRAY_LENGTH (cache->have_glyph_advance); + if (cache->have_glyph_advance[gi] != g) { + cairo_text_extents_t extents; + + cairo_scaled_font_glyph_extents (scaled_font, + &glyphs[nglyphs], 1, + &extents); + + cache->glyph_advance[gi][0] = extents.x_advance; + cache->glyph_advance[gi][1] = extents.y_advance; + cache->have_glyph_advance[gi] = g; + } + + x += cache->glyph_advance[gi][0]; + y += cache->glyph_advance[gi][1]; + nglyphs++; + } + break; + } + + case CSI_OBJECT_TYPE_STRING: { + const csi_string_t *glyph_string = obj->datum.string; + for (j = 0; j < glyph_string->len; j++) { + uint8_t g; + + g = glyph_string->string[j]; + glyphs[nglyphs].index = g; + glyphs[nglyphs].x = x; + glyphs[nglyphs].y = y; + + if (cache->have_glyph_advance[g] != g) { + cairo_text_extents_t extents; + + cairo_scaled_font_glyph_extents (scaled_font, + &glyphs[nglyphs], 1, + &extents); + + cache->glyph_advance[g][0] = extents.x_advance; + cache->glyph_advance[g][1] = extents.y_advance; + cache->have_glyph_advance[g] = g; + } + + x += cache->glyph_advance[g][0]; + y += cache->glyph_advance[g][1]; + nglyphs++; + } + break; + } + + case CSI_OBJECT_TYPE_INTEGER: + case CSI_OBJECT_TYPE_REAL: /* dx or x*/ + dx = csi_number_get_value (obj); + if (i+1 == array->stack.len) + break; + + type = csi_object_get_type (&array->stack.objects[i+1]); + switch (type) { + case CSI_OBJECT_TYPE_INTEGER: + case CSI_OBJECT_TYPE_REAL: /* y */ + y = csi_number_get_value (&array->stack.objects[i+1]); + x = dx; + i++; + break; + + default: + x += dx; + } + } + } + + return nglyphs; +} + +static csi_status_t +_glyph_path (csi_t *ctx) +{ + csi_array_t *array; + csi_status_t status; + cairo_t *cr; + cairo_glyph_t stack_glyphs[256], *glyphs; + csi_integer_t nglyphs, i; + + check (2); + + status = _csi_ostack_get_array (ctx, 0, &array); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + /* count glyphs */ + nglyphs = 0; + for (i = 0; i < array->stack.len; i++) { + csi_object_t *obj = &array->stack.objects[i]; + int type = csi_object_get_type (obj); + switch (type) { + case CSI_OBJECT_TYPE_ARRAY: + nglyphs += obj->datum.array->stack.len; + break; + case CSI_OBJECT_TYPE_STRING: + nglyphs += obj->datum.string->len; + break; + } + } + if (nglyphs == 0) { + pop (1); + return CSI_STATUS_SUCCESS; + } + + if (nglyphs > ARRAY_LENGTH (stack_glyphs)) { + if (_csi_unlikely ((unsigned) nglyphs >= INT_MAX / sizeof (cairo_glyph_t))) + return _csi_error (CSI_STATUS_NO_MEMORY); + + glyphs = _csi_alloc (ctx, sizeof (cairo_glyph_t) * nglyphs); + if (_csi_unlikely (glyphs == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + } else + glyphs = stack_glyphs; + + nglyphs = _glyph_string (ctx, array, cairo_get_scaled_font (cr), glyphs); + cairo_glyph_path (cr, glyphs, nglyphs); + + if (glyphs != stack_glyphs) + _csi_free (ctx, glyphs); + + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_gray (csi_t *ctx) +{ + csi_object_t obj; + csi_status_t status; + double g; + + check (1); + + status = _csi_ostack_get_number (ctx, 0, &g); + if (_csi_unlikely (status)) + return status; + + pop (1); + + obj.type = CSI_OBJECT_TYPE_PATTERN; + obj.datum.pattern = cairo_pattern_create_rgba (g, g, g, 1); + return push (&obj); +} + +static csi_status_t +_gt (csi_t *ctx) +{ + csi_status_t status; + csi_object_t *a, *b; + int cmp; + + check (2); + + b = _csi_peek_ostack (ctx, 0); + a = _csi_peek_ostack (ctx, 1); + + status = csi_object_compare (a, b, &cmp); + if (_csi_unlikely (status)) + return status; + + pop (2); + return _csi_push_ostack_boolean (ctx, cmp > 0); +} + +static csi_status_t +_identity (csi_t *ctx) +{ + csi_object_t obj; + csi_status_t status; + + status = csi_matrix_new (ctx, &obj); + if (_csi_unlikely (status)) + return status; + + return push (&obj); +} + +static csi_status_t +_if (csi_t *ctx) +{ + csi_array_t *proc; + csi_boolean_t predicate = FALSE; /* silence the compiler */ + csi_status_t status; + + check (2); + + status = _csi_ostack_get_procedure (ctx, 0, &proc); + if (_csi_unlikely (status)) + return status; + + status = _csi_ostack_get_boolean (ctx, 1, &predicate); + if (_csi_unlikely (status)) + return status; + + proc->base.ref++; + pop (2); + + if (predicate) + status = _csi_array_execute (ctx, proc); + + if (--proc->base.ref == 0) + csi_array_free (ctx, proc); + + return status; +} + +static csi_status_t +_ifelse (csi_t *ctx) +{ + csi_array_t *true_proc, *false_proc; + csi_boolean_t predicate = FALSE; /* silence the compiler */ + csi_status_t status; + + check (3); + + status = _csi_ostack_get_procedure (ctx, 0, &false_proc); + if (_csi_unlikely (status)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + status = _csi_ostack_get_procedure (ctx, 1, &true_proc); + if (_csi_unlikely (status)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + status = _csi_ostack_get_boolean (ctx, 2, &predicate); + if (_csi_unlikely (status)) + return status; + + true_proc->base.ref++; + false_proc->base.ref++; + pop (3); + + if (predicate) + status = _csi_array_execute (ctx, true_proc); + else + status = _csi_array_execute (ctx, false_proc); + + if (--true_proc->base.ref == 0) + csi_array_free (ctx, true_proc); + if (--false_proc->base.ref == 0) + csi_array_free (ctx, false_proc); + + return status; +} + +static csi_status_t +_image_read_raw (csi_t *ctx, + csi_object_t *src, + cairo_format_t format, + int width, int height, + cairo_surface_t **image_out) +{ + cairo_surface_t *image; + uint8_t *bp, *data; + int rem, len, ret, x, rowlen, instride, stride; + cairo_status_t status; + + if (width == 0 || height == 0) { + *image_out = cairo_image_surface_create (format, 0, 0); + return CSI_STATUS_SUCCESS; + } + + if (ctx->hooks.create_source_image != NULL) { + image = ctx->hooks.create_source_image (ctx->hooks.closure, + format, width, height, + 0); + + stride = cairo_image_surface_get_stride (image); + data = cairo_image_surface_get_data (image); + } else { + stride = cairo_format_stride_for_width (format, width); + data = malloc (stride * height); + if (data == NULL) + return CAIRO_STATUS_NO_MEMORY; + + image = cairo_image_surface_create_for_data (data, format, + width, height, stride); + status = cairo_surface_set_user_data (image, + (const cairo_user_data_key_t *) image, + data, free); + if (status) { + cairo_surface_destroy (image); + free (image); + return status; + } + } + + switch (format) { + case CAIRO_FORMAT_A1: + instride = rowlen = (width+7)/8; + break; + case CAIRO_FORMAT_A8: + instride = rowlen = width; + break; + case CAIRO_FORMAT_RGB16_565: + instride = rowlen = 2 * width; + break; + case CAIRO_FORMAT_RGB24: + rowlen = 3 * width; + instride = 4 *width; + break; + default: + case CAIRO_FORMAT_RGB30: + case CAIRO_FORMAT_INVALID: + case CAIRO_FORMAT_ARGB32: + instride = rowlen = 4 * width; + break; + case CAIRO_FORMAT_RGB96F: + instride = rowlen = 12 * width; + break; + case CAIRO_FORMAT_RGBA128F: + instride = rowlen = 16 * width; + break; + } + len = rowlen * height; + + if (rowlen == instride && + src->type == CSI_OBJECT_TYPE_STRING && + len == src->datum.string->deflate) + { + csi_string_t *s = src->datum.string; + unsigned long out = s->deflate; + + switch (s->method) { + default: + case NONE: +err_decompress: + cairo_surface_destroy (image); + return _csi_error (CSI_STATUS_READ_ERROR); + + case ZLIB: +#if HAVE_ZLIB + if (uncompress ((Bytef *) data, &out, + (Bytef *) s->string, s->len) != Z_OK) +#endif + goto err_decompress; + break; + + case LZO: +#if HAVE_LZO + if (lzo2a_decompress ((Bytef *) s->string, s->len, + (Bytef *) data, &out, + NULL)) +#endif + goto err_decompress; + break; + } + } + else + { + csi_object_t file; + + status = csi_object_as_file (ctx, src, &file); + if (_csi_unlikely (status)) { + cairo_surface_destroy (image); + return status; + } + + bp = data; + rem = len; + while (rem) { + ret = csi_file_read (file.datum.file, bp, rem); + if (_csi_unlikely (ret == 0)) { + cairo_surface_destroy (image); + return _csi_error (CSI_STATUS_READ_ERROR); + } + rem -= ret; + bp += ret; + } + + if (len != height * stride) { + while (--height) { + uint8_t *row = data + height * stride; + + /* XXX pixel conversion */ + switch (format) { + case CAIRO_FORMAT_A1: + for (x = rowlen; x--; ) { + uint8_t byte = *--bp; + row[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte); + } + break; + case CAIRO_FORMAT_A8: + for (x = width; x--; ) + row[x] = *--bp; + break; + case CAIRO_FORMAT_RGB16_565: + for (x = width; x--; ) { +#ifdef WORDS_BIGENDIAN + row[2*x + 1] = *--bp; + row[2*x + 0] = *--bp; +#else + row[2*x + 0] = *--bp; + row[2*x + 1] = *--bp; +#endif + } + break; + case CAIRO_FORMAT_RGB24: + for (x = width; x--; ) { +#ifdef WORDS_BIGENDIAN + row[4*x + 3] = *--bp; + row[4*x + 2] = *--bp; + row[4*x + 1] = *--bp; + row[4*x + 0] = 0xff; +#else + row[4*x + 0] = *--bp; + row[4*x + 1] = *--bp; + row[4*x + 2] = *--bp; + row[4*x + 3] = 0xff; +#endif + } + break; + case CAIRO_FORMAT_RGB96F: + case CAIRO_FORMAT_RGBA128F: + case CAIRO_FORMAT_RGB30: + case CAIRO_FORMAT_INVALID: + case CAIRO_FORMAT_ARGB32: + /* stride == width */ + break; + } + + memset (row + instride, 0, stride - instride); + } + + /* need to treat last row carefully */ + switch (format) { + case CAIRO_FORMAT_A1: + for (x = rowlen; x--; ) { + uint8_t byte = *--bp; + data[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte); + } + break; + case CAIRO_FORMAT_A8: + for (x = width; x--; ) + data[x] = *--bp; + break; + case CAIRO_FORMAT_RGB16_565: + for (x = width; x--; ) { +#ifdef WORDS_BIGENDIAN + data[2*x + 1] = *--bp; + data[2*x + 0] = *--bp; +#else + data[2*x + 0] = *--bp; + data[2*x + 1] = *--bp; +#endif + } + break; + case CAIRO_FORMAT_RGB24: + for (x = width; --x>1; ) { +#ifdef WORDS_BIGENDIAN + data[4*x + 3] = *--bp; + data[4*x + 2] = *--bp; + data[4*x + 1] = *--bp; + data[4*x + 0] = 0xff; +#else + data[4*x + 0] = *--bp; + data[4*x + 1] = *--bp; + data[4*x + 2] = *--bp; + data[4*x + 3] = 0xff; +#endif + } + if (width > 1) { + uint8_t rgb[2][3]; + /* shuffle the last couple of overlapping pixels */ + rgb[1][0] = data[5]; + rgb[1][1] = data[4]; + rgb[1][2] = data[3]; + rgb[0][0] = data[2]; + rgb[0][1] = data[1]; + rgb[0][2] = data[0]; +#ifdef WORDS_BIGENDIAN + data[4] = 0xff; + data[5] = rgb[1][2]; + data[6] = rgb[1][1]; + data[7] = rgb[1][0]; + data[0] = 0xff; + data[1] = rgb[0][2]; + data[2] = rgb[0][1]; + data[3] = rgb[0][0]; +#else + data[7] = 0xff; + data[6] = rgb[1][2]; + data[5] = rgb[1][1]; + data[4] = rgb[1][0]; + data[3] = 0xff; + data[2] = rgb[0][2]; + data[1] = rgb[0][1]; + data[0] = rgb[0][0]; +#endif + } else { +#ifdef WORDS_BIGENDIAN + data[0] = 0xff; + data[1] = data[0]; + data[2] = data[1]; + data[3] = data[2]; +#else + data[3] = data[0]; + data[0] = data[2]; + data[2] = data[3]; + data[3] = 0xff; +#endif + } + break; + case CAIRO_FORMAT_RGBA128F: + case CAIRO_FORMAT_RGB96F: + case CAIRO_FORMAT_RGB30: + case CAIRO_FORMAT_INVALID: + case CAIRO_FORMAT_ARGB32: + /* stride == width */ + break; + } + memset (data + instride, 0, stride - instride); + } else { +#ifndef WORDS_BIGENDIAN + switch (format) { + case CAIRO_FORMAT_A1: + for (x = 0; x < len; x++) { + uint8_t byte = data[x]; + data[x] = CSI_BITSWAP8_IF_LITTLE_ENDIAN (byte); + } + break; + case CAIRO_FORMAT_RGB16_565: + { + uint32_t *rgba = (uint32_t *) data; + for (x = len/2; x--; rgba++) { + *rgba = bswap_16 (*rgba); + } + } + break; + case CAIRO_FORMAT_ARGB32: + { + uint32_t *rgba = (uint32_t *) data; + for (x = len/4; x--; rgba++) { + *rgba = bswap_32 (*rgba); + } + } + break; + + case CAIRO_FORMAT_A8: + break; + + case CAIRO_FORMAT_RGBA128F: + case CAIRO_FORMAT_RGB96F: + case CAIRO_FORMAT_RGB30: + case CAIRO_FORMAT_RGB24: + case CAIRO_FORMAT_INVALID: + default: + break; + } +#endif + } + csi_object_free (ctx, &file); + } + + cairo_surface_mark_dirty (image); + *image_out = image; + return CSI_STATUS_SUCCESS; +} + +static cairo_status_t +png_read_func (void *closure, uint8_t *data, unsigned int len) +{ + int ret; + + ret = csi_file_read (closure, data, len); + if ((unsigned int) ret != len) + return CAIRO_STATUS_READ_ERROR; + + return CAIRO_STATUS_SUCCESS; +} + +static csi_status_t +_image_read_png (csi_file_t *src, cairo_surface_t **out) +{ +#if CAIRO_HAS_PNG_FUNCTIONS + *out = cairo_image_surface_create_from_png_stream (png_read_func, src); + return cairo_surface_status (*out); +#else + return CAIRO_STATUS_READ_ERROR; +#endif +} + +struct _image_tag { + csi_t *ctx; + csi_blob_t blob; + cairo_surface_t *surface; +}; + +static void +_image_tag_done (void *closure) +{ + struct _image_tag *tag = closure; + csi_t *ctx = tag->ctx; + + ctx->_images = _csi_list_unlink (ctx->_images, &tag->blob.list); + _csi_slab_free (ctx, tag, sizeof (*tag)); + cairo_script_interpreter_destroy (ctx); +} + +static void +_image_hash (csi_blob_t *blob, + cairo_surface_t *surface) +{ + uint32_t value; + + value = cairo_image_surface_get_width (surface); + _csi_blob_hash (blob, &value, 1); + + value = cairo_image_surface_get_height (surface); + _csi_blob_hash (blob, &value, 1); + + value = cairo_image_surface_get_format (surface); + _csi_blob_hash (blob, &value, 1); +} + +static cairo_surface_t * +_image_cached (csi_t *ctx, cairo_surface_t *surface) +{ + csi_blob_t tmpl; + csi_list_t *link; + uint8_t *data; + int stride, height; + struct _image_tag *tag; + + /* check for an existing image */ + + data = cairo_image_surface_get_data (surface); + stride = cairo_image_surface_get_stride (surface); + height = cairo_image_surface_get_height (surface); + _csi_blob_init (&tmpl, data, stride * height); + _image_hash (&tmpl, surface); + link = _csi_list_find (ctx->_images, _csi_blob_equal, &tmpl); + if (link) { + cairo_surface_destroy (surface); + tag = csi_container_of (link, struct _image_tag, blob.list); + return cairo_surface_reference (tag->surface); + } + + /* none found, insert a tag for this one */ + + tag = _csi_slab_alloc (ctx, sizeof (struct _image_tag)); + if (tag == NULL) + return surface; + + ctx->_images = _csi_list_prepend (ctx->_images, &tag->blob.list); + tag->ctx = cairo_script_interpreter_reference (ctx); + tag->blob.hash = tmpl.hash; + tag->blob.bytes = tmpl.bytes; + tag->blob.len = tmpl.len; + tag->surface = surface; + + if (cairo_surface_set_user_data (surface, &_csi_blob_key, + tag, _image_tag_done)) + { + _image_tag_done (tag); + } + + return surface; +} + +static csi_status_t +_image_load_from_dictionary (csi_t *ctx, + csi_dictionary_t *dict, + cairo_surface_t **image_out) +{ + csi_object_t obj, key; + long width; + long height; + long format; + cairo_surface_t *image = NULL; /* silence the compiler */ + csi_status_t status; + + /* check for "status? */ + + status = _csi_dictionary_get_integer (ctx, dict, "width", FALSE, &width); + if (_csi_unlikely (status)) + return status; + status = _csi_dictionary_get_integer (ctx, dict, "height", FALSE, &height); + if (_csi_unlikely (status)) + return status; + + format = CAIRO_FORMAT_ARGB32; + status = _csi_dictionary_get_integer (ctx, dict, "format", TRUE, &format); + if (_csi_unlikely (status)) + return status; + + status = csi_name_new_static (ctx, &key, "source"); + if (_csi_unlikely (status)) + return status; + + if (csi_dictionary_has (dict, key.datum.name)) { + enum mime_type mime_type; + csi_object_t file; + + status = csi_dictionary_get (ctx, dict, key.datum.name, &obj); + if (_csi_unlikely (status)) + return status; + + status = csi_name_new_static (ctx, &key, "mime-type"); + if (_csi_unlikely (status)) + return status; + + mime_type = MIME_TYPE_NONE; + if (csi_dictionary_has (dict, key.datum.name)) { + csi_object_t type_obj; + const char *type_str; + int type; + + status = csi_dictionary_get (ctx, dict, key.datum.name, &type_obj); + if (_csi_unlikely (status)) + return status; + + type = csi_object_get_type (&type_obj); + switch (type) { + case CSI_OBJECT_TYPE_STRING: + type_str = type_obj.datum.string->string; + break; + case CSI_OBJECT_TYPE_NAME: + type_str = (char *) type_obj.datum.name; + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + if (strcmp (type_str, CAIRO_MIME_TYPE_PNG) == 0) + mime_type = MIME_TYPE_PNG; + } + + + /* XXX hook for general mime-type decoder */ + + switch (mime_type) { + case MIME_TYPE_NONE: + status = _image_read_raw (ctx, &obj, format, width, height, &image); + break; + case MIME_TYPE_PNG: + status = csi_object_as_file (ctx, &obj, &file); + if (_csi_unlikely (status)) + return status; + + status = _image_read_png (file.datum.file, &image); + csi_object_free (ctx, &file); + break; + } + if (_csi_unlikely (status)) + return status; + + image = _image_cached (ctx, image); + } else + image = cairo_image_surface_create (format, width, height); + + *image_out = image; + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_image (csi_t *ctx) +{ + csi_dictionary_t *dict; + cairo_surface_t *image; + csi_status_t status; + csi_object_t obj; + + check (1); + + status = _csi_ostack_get_dictionary (ctx, 0, &dict); + if (_csi_unlikely (status)) + return status; + + status = _image_load_from_dictionary (ctx, dict, &image); + if (_csi_unlikely (status)) + return status; + + pop (1); + obj.type = CSI_OBJECT_TYPE_SURFACE; + obj.datum.surface = image; + return push (&obj); +} + +static csi_status_t +_index (csi_t *ctx) +{ + csi_status_t status; + long n; + + check (1); + + status = _csi_ostack_get_integer (ctx, 0, &n); + if (_csi_unlikely (status)) + return status; + + pop (1); + + check (n); + return _csi_push_ostack_copy (ctx, _csi_peek_ostack (ctx, n)); +} + +static csi_status_t +_integer (csi_t *ctx) +{ + csi_object_t *obj; + int type; + + check (1); + + obj = _csi_peek_ostack (ctx, 0); + type = csi_object_get_type (obj); + switch (type) { + case CSI_OBJECT_TYPE_INTEGER: + break; + case CSI_OBJECT_TYPE_REAL: + obj->datum.integer = obj->datum.real; + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + obj->type = CSI_OBJECT_TYPE_INTEGER; + + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_invert (csi_t *ctx) +{ + csi_object_t obj; + csi_status_t status; + cairo_matrix_t m; + + check (1); + + status = _csi_ostack_get_matrix (ctx, 0, &m); + if (_csi_unlikely (status)) + return status; + + cairo_matrix_invert (&m); + + status = csi_matrix_new_from_matrix (ctx, &obj, &m); + if (_csi_unlikely (status)) + return status; + + pop (1); + + return push (&obj); +} + +static csi_status_t +_le (csi_t *ctx) +{ + csi_status_t status; + csi_object_t *a, *b; + int cmp; + + check (2); + + b = _csi_peek_ostack (ctx, 0); + a = _csi_peek_ostack (ctx, 1); + + status = csi_object_compare (a, b, &cmp); + if (_csi_unlikely (status)) + return status; + + pop (2); + return _csi_push_ostack_boolean (ctx, cmp <= 0); +} + +static csi_status_t +_linear (csi_t *ctx) +{ + csi_object_t obj; + csi_status_t status; + double x1, y1, x2, y2; + + check (4); + + status = _csi_ostack_get_number (ctx, 0, &y2); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &x2); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 2, &y1); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 3, &x1); + if (_csi_unlikely (status)) + return status; + + pop (4); + + obj.type = CSI_OBJECT_TYPE_PATTERN; + obj.datum.pattern = cairo_pattern_create_linear (x1, y1, x2, y2); + return push (&obj); +} + +static csi_status_t +_line_to (csi_t *ctx) +{ + csi_status_t status; + csi_object_t *obj; + int type; + double x, y; + + check (3); + + status = _csi_ostack_get_number (ctx, 0, &y); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &x); + if (_csi_unlikely (status)) + return status; + + /* XXX path object */ + + obj = _csi_peek_ostack (ctx, 2); + type = csi_object_get_type (obj); + switch (type) { + case CSI_OBJECT_TYPE_CONTEXT: + cairo_line_to (obj->datum.cr, x, y); + break; + case CSI_OBJECT_TYPE_PATTERN: + cairo_mesh_pattern_line_to (obj->datum.pattern, x, y); + break; + } + + pop (2); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_lt (csi_t *ctx) +{ + csi_status_t status; + csi_object_t *a, *b; + int cmp; + + check (2); + + b = _csi_peek_ostack (ctx, 0); + a = _csi_peek_ostack (ctx, 1); + + status = csi_object_compare (a, b, &cmp); + if (_csi_unlikely (status)) + return status; + + pop (2); + return _csi_push_ostack_boolean (ctx, cmp < 0); +} + +static csi_status_t +_mark (csi_t *ctx) +{ + return _csi_push_ostack_mark (ctx); +} + +static csi_status_t +_ne (csi_t *ctx) +{ + csi_object_t *a, *b; + csi_boolean_t v; + + check (2); + + b = _csi_peek_ostack (ctx, 0); + a = _csi_peek_ostack (ctx, 1); + + v = ! csi_object_eq (a, b); + + pop (2); + return _csi_push_ostack_boolean (ctx, v); +} + +static csi_status_t +_neg (csi_t *ctx) +{ + csi_object_t *obj; + int type; + + check (1); + + obj = _csi_peek_ostack (ctx, 0); + type = csi_object_get_type (obj); + switch (type) { + case CSI_OBJECT_TYPE_INTEGER: + obj->datum.integer = -obj->datum.integer; + break; + case CSI_OBJECT_TYPE_REAL: + obj->datum.real = -obj->datum.real; + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_not (csi_t *ctx) +{ + csi_object_t *obj; + int type; + + check (1); + + obj = _csi_peek_ostack (ctx, 0); + type = csi_object_get_type (obj); + switch (type) { + case CSI_OBJECT_TYPE_BOOLEAN: + obj->datum.boolean = ! obj->datum.boolean; + break; + case CSI_OBJECT_TYPE_INTEGER: + obj->type = CSI_OBJECT_TYPE_BOOLEAN; + obj->datum.boolean = ! obj->datum.integer; + break; + case CSI_OBJECT_TYPE_REAL: + obj->type = CSI_OBJECT_TYPE_BOOLEAN; + obj->datum.boolean = obj->datum.real == 0.0; + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_new_path (csi_t *ctx) +{ + /* XXX handle path object */ + return _do_cairo_op (ctx, cairo_new_path); +} + +static csi_status_t +_new_sub_path (csi_t *ctx) +{ + /* XXX handle path object */ + return _do_cairo_op (ctx, cairo_new_sub_path); +} + +static csi_status_t +_null (csi_t *ctx) +{ + return _csi_push_ostack_null (ctx); +} + +static csi_status_t +_mask (csi_t *ctx) +{ + cairo_t *cr; + cairo_pattern_t *pattern = NULL; /* silence the compiler */ + csi_status_t status; + + check (2); + + status = _csi_ostack_get_pattern (ctx, 0, &pattern); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_mask (cr, pattern); + pop (1); + + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_matrix (csi_t *ctx) +{ + csi_object_t *obj, matrix; + double v[6]; + csi_status_t status; + int n; + + check (1); + + obj = _csi_peek_ostack (ctx, 0); + if (csi_object_is_number (obj)) { + check (6); + + for (n = 6; n--; ) { + status = _csi_ostack_get_number (ctx, 5-n, &v[n]); + if (_csi_unlikely (status)) + return status; + } + status = csi_matrix_new_from_values (ctx, &matrix, v); + if (_csi_unlikely (status)) + return status; + + pop (6); + } else { + csi_array_t *array; + + status = _csi_ostack_get_array (ctx, 0, &array); + if (_csi_unlikely (status)) + return status; + + status = csi_matrix_new_from_array (ctx, &matrix, array); + if (_csi_unlikely (status)) + return status; + + pop (1); + } + + return push (&matrix); +} + +static csi_status_t +_map_to_image (csi_t *ctx) +{ + csi_object_t obj; + csi_array_t *array; + csi_status_t status; + cairo_rectangle_int_t extents, *r; + cairo_surface_t *surface; + + check (2); + + status = _csi_ostack_get_array (ctx, 0, &array); + if (_csi_unlikely (status)) + return status; + + status = _csi_ostack_get_surface (ctx, 1, &surface); + if (_csi_unlikely (status)) + return status; + + switch (array->stack.len) { + case 0: + r = NULL; + break; + case 4: + extents.x = floor (_csi_object_as_real (&array->stack.objects[0])); + extents.y = floor (_csi_object_as_real (&array->stack.objects[1])); + extents.width = ceil (_csi_object_as_real (&array->stack.objects[2])); + extents.height = ceil (_csi_object_as_real (&array->stack.objects[3])); + r = &extents; + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + obj.type = CSI_OBJECT_TYPE_SURFACE; + obj.datum.surface = cairo_surface_reference (cairo_surface_map_to_image (surface, r)); + pop (1); + return push (&obj); +} + +static csi_status_t +_unmap_image (csi_t *ctx) +{ + cairo_surface_t *surface, *image; + csi_status_t status; + + check (2); + + status = _csi_ostack_get_surface (ctx, 0, &image); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_surface (ctx, 1, &surface); + if (_csi_unlikely (status)) + return status; + + cairo_surface_unmap_image (surface, image); + + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_mesh (csi_t *ctx) +{ + csi_object_t obj; + + obj.type = CSI_OBJECT_TYPE_PATTERN; + obj.datum.pattern = cairo_pattern_create_mesh (); + return push (&obj); +} + +static csi_status_t +_mesh_begin_patch (csi_t *ctx) +{ + csi_status_t status; + cairo_pattern_t *pattern = NULL; /* silence the compiler */ + + check (1); + + status = _csi_ostack_get_pattern (ctx, 0, &pattern); + if (_csi_unlikely (status)) + return status; + + cairo_mesh_pattern_begin_patch (pattern); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_mesh_end_patch (csi_t *ctx) +{ + csi_status_t status; + cairo_pattern_t *pattern = NULL; /* silence the compiler */ + + check (1); + + status = _csi_ostack_get_pattern (ctx, 0, &pattern); + if (_csi_unlikely (status)) + return status; + + cairo_mesh_pattern_end_patch (pattern); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_mesh_set_control_point (csi_t *ctx) +{ + csi_status_t status; + double x, y; + csi_integer_t point; + cairo_pattern_t *pattern = NULL; /* silence the compiler */ + + check (4); + + status = _csi_ostack_get_number (ctx, 0, &y); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &x); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_integer (ctx, 2, &point); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_pattern (ctx, 3, &pattern); + if (_csi_unlikely (status)) + return status; + + cairo_mesh_pattern_set_control_point (pattern, point, x, y); + + pop (3); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_mesh_set_corner_color (csi_t *ctx) +{ + csi_status_t status; + double r, g, b, a; + csi_integer_t corner; + cairo_pattern_t *pattern = NULL; /* silence the compiler */ + + check (6); + + status = _csi_ostack_get_number (ctx, 0, &a); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &b); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 2, &g); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 3, &r); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_integer (ctx, 4, &corner); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_pattern (ctx, 5, &pattern); + if (_csi_unlikely (status)) + return status; + + cairo_mesh_pattern_set_corner_color_rgba (pattern, corner, r, g, b, a); + + pop (5); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_mod (csi_t *ctx) +{ + csi_integer_t x, y; + csi_status_t status; + + check (2); + + status = _csi_ostack_get_integer (ctx, 0, &y); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_integer (ctx, 1, &x); + if (_csi_unlikely (status)) + return status; + + pop (2); + return _csi_push_ostack_integer (ctx, x % y); +} + +static csi_status_t +_move_to (csi_t *ctx) +{ + csi_status_t status; + csi_object_t *obj; + int type; + double x, y; + + check (3); + + status = _csi_ostack_get_number (ctx, 0, &y); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &x); + if (_csi_unlikely (status)) + return status; + + obj = _csi_peek_ostack (ctx, 2); + type = csi_object_get_type (obj); + switch (type) { + case CSI_OBJECT_TYPE_CONTEXT: + cairo_move_to (obj->datum.cr, x, y); + break; + case CSI_OBJECT_TYPE_PATTERN: + cairo_mesh_pattern_move_to (obj->datum.pattern, x, y); + break; + + /* XXX path object */ + } + + pop (2); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_mul (csi_t *ctx) +{ + csi_object_t *A; + csi_object_t *B; + csi_object_type_t type_a, type_b; + + check (2); + + B = _csi_peek_ostack (ctx, 0); + A = _csi_peek_ostack (ctx, 1); + + type_a = csi_object_get_type (A); + if (_csi_unlikely (! (type_a == CSI_OBJECT_TYPE_INTEGER || + type_a == CSI_OBJECT_TYPE_REAL))) + { + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + type_b = csi_object_get_type (B); + if (_csi_unlikely (! (type_b == CSI_OBJECT_TYPE_INTEGER || + type_b == CSI_OBJECT_TYPE_REAL))) + { + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + pop (2); + + if (type_a == CSI_OBJECT_TYPE_REAL && + type_b == CSI_OBJECT_TYPE_REAL) + { + return _csi_push_ostack_real (ctx, A->datum.real * B->datum.real); + + } + else if (type_a == CSI_OBJECT_TYPE_INTEGER && + type_b == CSI_OBJECT_TYPE_INTEGER) + { + return _csi_push_ostack_integer (ctx, + A->datum.integer * B->datum.integer); + } + else + { + double v; + + if (type_a == CSI_OBJECT_TYPE_REAL) + v = A->datum.real; + else + v = A->datum.integer; + + if (type_b == CSI_OBJECT_TYPE_REAL) + v *= B->datum.real; + else + v *= B->datum.integer; + + return _csi_push_ostack_real (ctx, v); + } +} + +static csi_status_t +_or (csi_t *ctx) +{ + csi_object_t *a, *b; + int type; + + check (2); + + a = _csi_peek_ostack (ctx, 0); + b = _csi_peek_ostack (ctx, 1); + if (_csi_unlikely (csi_object_get_type (a) != csi_object_get_type (b))) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + pop (2); + type = csi_object_get_type (a); + switch (type) { + case CSI_OBJECT_TYPE_INTEGER: + return _csi_push_ostack_integer (ctx, + a->datum.integer | b->datum.integer); + case CSI_OBJECT_TYPE_BOOLEAN: + return _csi_push_ostack_boolean (ctx, + a->datum.boolean | b->datum.boolean); + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } +} + +static csi_status_t +_paint (csi_t *ctx) +{ + return _do_cairo_op (ctx, cairo_paint); +} + +static csi_status_t +_paint_with_alpha (csi_t *ctx) +{ + cairo_t *cr; + csi_status_t status; + double alpha; + + check (2); + + status = _csi_ostack_get_number (ctx, 0, &alpha); + if (_csi_unlikely (status)) + return status; + + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_paint_with_alpha (cr, alpha); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_pattern (csi_t *ctx) +{ + csi_object_t obj; + csi_status_t status; + cairo_surface_t *surface; + + check (1); + + status = _csi_ostack_get_surface (ctx, 0, &surface); + if (_csi_unlikely (status)) + return status; + + obj.type = CSI_OBJECT_TYPE_PATTERN; + obj.datum.pattern = cairo_pattern_create_for_surface (surface); + + pop (1); + return push (&obj); +} + +static csi_status_t +_pop (csi_t *ctx) +{ + check (1); + pop (1); + + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_pop_group (csi_t *ctx) +{ + csi_object_t obj; + csi_status_t status; + cairo_t *cr; + + check (1); + + status = _csi_ostack_get_context (ctx, 0, &cr); + if (_csi_unlikely (status)) + return status; + + obj.type = CSI_OBJECT_TYPE_PATTERN; + obj.datum.pattern = cairo_pop_group (cr); + + return push (&obj); +} + +static csi_status_t +_push_group (csi_t *ctx) +{ + csi_status_t status; + cairo_t *cr; + long content; + + check (2); + + status = _csi_ostack_get_integer (ctx, 0, &content); + if (_csi_unlikely (status)) + return status; + + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_push_group_with_content (cr, content); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_radial (csi_t *ctx) +{ + csi_object_t obj; + csi_status_t status; + double x1, y1, r1, x2, y2, r2; + + check (6); + + status = _csi_ostack_get_number (ctx, 0, &r2); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &y2); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 2, &x2); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 3, &r1); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 4, &y1); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 5, &x1); + if (_csi_unlikely (status)) + return status; + + obj.type = CSI_OBJECT_TYPE_PATTERN; + obj.datum.pattern = cairo_pattern_create_radial (x1, y1, r1, x2, y2, r2); + pop (6); + return push (&obj); +} + +static csi_status_t +_rectangle (csi_t *ctx) +{ + csi_status_t status; + double x, y; + double w, h; + cairo_t *cr; + + check (5); + + status = _csi_ostack_get_number (ctx, 0, &h); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &w); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 2, &y); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 3, &x); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 4, &cr); + if (_csi_unlikely (status)) + return status; + + /* XXX path object */ + + cairo_rectangle (cr, x, y, w, h); + pop(4); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_rel_curve_to (csi_t *ctx) +{ + csi_status_t status; + double x1, y1; + double x2, y2; + double x3, y3; + cairo_t *cr; + + check (7); + + status = _csi_ostack_get_number (ctx, 0, &y3); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &x3); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 2, &y2); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 3, &x2); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 4, &y1); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 5, &x1); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 6, &cr); + if (_csi_unlikely (status)) + return status; + + /* XXX path object */ + + cairo_rel_curve_to (cr, x1, y1, x2, y2, x3, y3); + pop (6); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_rel_line_to (csi_t *ctx) +{ + csi_status_t status; + double x, y; + cairo_t *cr; + + check (3); + + status = _csi_ostack_get_number (ctx, 0, &y); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &x); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 2, &cr); + if (_csi_unlikely (status)) + return status; + + /* XXX path object */ + + cairo_rel_line_to (cr, x, y); + pop (2); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_rel_move_to (csi_t *ctx) +{ + csi_status_t status; + double x, y; + cairo_t *cr; + + check (3); + + status = _csi_ostack_get_number (ctx, 0, &y); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &x); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 2, &cr); + if (_csi_unlikely (status)) + return status; + + /* XXX path object */ + cairo_rel_move_to (cr, x, y); + pop (2); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_repeat (csi_t *ctx) +{ + csi_array_t *proc; + csi_integer_t count; + csi_status_t status; + + check (2); + + status = _csi_ostack_get_procedure (ctx, 0, &proc); + if (_csi_unlikely (status)) + return status; + + status = _csi_ostack_get_integer (ctx, 1, &count); + if (_csi_unlikely (status)) + return status; + + if (_csi_unlikely (count < 0)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + proc->base.ref++; + pop (2); + + while (count--) { + status = _csi_array_execute (ctx, proc); + if (_csi_unlikely (status)) + break; + } + + if (--proc->base.ref == 0) + csi_array_free (ctx, proc); + + return status; +} + +static csi_status_t +_reset_clip (csi_t *ctx) +{ + return _do_cairo_op (ctx, cairo_reset_clip); +} + +static csi_status_t +_restore (csi_t *ctx) +{ + return _do_cairo_op (ctx, cairo_restore); +} + +static csi_status_t +_rgb (csi_t *ctx) +{ + csi_object_t obj; + csi_status_t status; + double r,g,b; + + check (3); + + status = _csi_ostack_get_number (ctx, 0, &b); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &g); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 2, &r); + if (_csi_unlikely (status)) + return status; + + obj.type = CSI_OBJECT_TYPE_PATTERN; + obj.datum.pattern = cairo_pattern_create_rgb (r, g, b); + pop (3); + return push (&obj); +} + +static csi_status_t +_rgba (csi_t *ctx) +{ + csi_object_t obj; + csi_status_t status; + double r,g,b,a; + + check (4); + + status = _csi_ostack_get_number (ctx, 0, &a); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &b); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 2, &g); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 3, &r); + if (_csi_unlikely (status)) + return status; + + obj.type = CSI_OBJECT_TYPE_PATTERN; + obj.datum.pattern = cairo_pattern_create_rgba (r, g, b, a); + pop (4); + return push (&obj); +} + +static csi_status_t +_roll (csi_t *ctx) +{ + csi_status_t status; + long j, n; + + check (2); + + status = _csi_ostack_get_integer (ctx, 0, &j); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_integer (ctx, 1, &n); + if (_csi_unlikely (status)) + return status; + + pop (2); + check (n); + return _csi_stack_roll (ctx, &ctx->ostack, j, n); +} + +static csi_status_t +_rotate (csi_t *ctx) +{ + csi_object_t *obj; + csi_status_t status; + double theta; + int type; + + check (2); + + status = _csi_ostack_get_number (ctx, 0, &theta); + if (_csi_unlikely (status)) + return status; + + obj = _csi_peek_ostack (ctx, 1); + type = csi_object_get_type (obj); + switch (type) { + case CSI_OBJECT_TYPE_CONTEXT: + cairo_rotate (obj->datum.cr, theta); + break; + + case CSI_OBJECT_TYPE_PATTERN: + { + cairo_matrix_t ctm; + cairo_pattern_get_matrix (obj->datum.pattern, &ctm); + cairo_matrix_rotate (&ctm, theta); + cairo_pattern_set_matrix (obj->datum.pattern, &ctm); + } + break; + + + case CSI_OBJECT_TYPE_MATRIX: + cairo_matrix_rotate (&obj->datum.matrix->matrix, theta); + break; + + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_save (csi_t *ctx) +{ + return _do_cairo_op (ctx, cairo_save); +} + +static csi_status_t +_scale (csi_t *ctx) +{ + csi_object_t *obj; + csi_status_t status; + double x, y; + int type; + + check (3); + + status = _csi_ostack_get_number (ctx, 0, &y); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &x); + if (_csi_unlikely (status)) + return status; + + obj = _csi_peek_ostack (ctx, 2); + type = csi_object_get_type (obj); + switch (type) { + case CSI_OBJECT_TYPE_CONTEXT: + cairo_scale (obj->datum.cr, x, y); + break; + + case CSI_OBJECT_TYPE_PATTERN: + { + cairo_matrix_t ctm; + cairo_pattern_get_matrix (obj->datum.pattern, &ctm); + cairo_matrix_scale (&ctm, x, y); + cairo_pattern_set_matrix (obj->datum.pattern, &ctm); + } + break; + + + case CSI_OBJECT_TYPE_MATRIX: + cairo_matrix_scale (&obj->datum.matrix->matrix, x, y); + break; + + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + pop (2); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_font_options_load_from_dictionary (csi_t *ctx, + csi_dictionary_t *dict, + cairo_font_options_t *options) +{ + const struct { + const char *key; + void (*setter) (cairo_font_options_t *, int val); + } properties[] = { + { "antialias", + (void (*)(cairo_font_options_t *, int val)) + cairo_font_options_set_antialias }, + { "subpixel-order", + (void (*)(cairo_font_options_t *, int val)) + cairo_font_options_set_subpixel_order }, + { "hint-style", + (void (*)(cairo_font_options_t *, int val)) + cairo_font_options_set_hint_style }, + { "hint-metrics", + (void (*)(cairo_font_options_t *, int val)) + cairo_font_options_set_hint_metrics }, + { NULL, NULL }, + }, *prop = properties; + + while (prop->key != NULL) { + csi_object_t key, value; + csi_status_t status; + + status = csi_name_new_static (ctx, &key, prop->key); + if (_csi_unlikely (status)) + return status; + + if (csi_dictionary_has (dict, key.datum.name)) { + status = csi_dictionary_get (ctx, dict, key.datum.name, &value); + if (_csi_unlikely (status)) + return status; + + if (_csi_unlikely (csi_object_get_type (&value) != + CSI_OBJECT_TYPE_INTEGER)) + { + csi_object_free (ctx, &value); + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + prop->setter (options, value.datum.integer); + } + + prop++; + } + + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_scaled_font (csi_t *ctx) +{ + csi_object_t obj; + csi_dictionary_t *dict; + cairo_font_face_t *font_face = NULL; /* silence the compiler */ + cairo_matrix_t font_matrix, ctm; + cairo_font_options_t *options; + csi_status_t status; + + check (4); + + status = _csi_ostack_get_dictionary (ctx, 0, &dict); + if (_csi_unlikely (status)) + return status; + options = cairo_font_options_create (); + status = _font_options_load_from_dictionary (ctx, dict, options); + if (_csi_unlikely (status)) { + cairo_font_options_destroy (options); + return status; + } + + status = _csi_ostack_get_matrix (ctx, 1, &ctm); + if (_csi_unlikely (status)) { + cairo_font_options_destroy (options); + return status; + } + + status = _csi_ostack_get_matrix (ctx, 2, &font_matrix); + if (_csi_unlikely (status)) { + cairo_font_options_destroy (options); + return status; + } + + status = _csi_ostack_get_font_face (ctx, 3, &font_face); + if (_csi_unlikely (status)) { + cairo_font_options_destroy (options); + return status; + } + + obj.type = CSI_OBJECT_TYPE_SCALED_FONT; + obj.datum.scaled_font = cairo_scaled_font_create (font_face, + &font_matrix, + &ctm, + options); + cairo_font_options_destroy (options); + pop (4); + return push (&obj); +} + +static csi_status_t +_select_font_face (csi_t *ctx) +{ + cairo_t *cr; + long weight; + long slant; + csi_string_t *family; + csi_status_t status; + + check (4); + + status = _csi_ostack_get_integer (ctx, 0, &weight); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_integer (ctx, 1, &slant); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_string (ctx, 2, &family); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 3, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_select_font_face (cr, family->string, slant, weight); + pop (3); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_context_set (csi_t *ctx, + cairo_t *cr, + csi_name_t key, + csi_object_t *obj) +{ + if (strcmp ((char *) key, "source") == 0) { + if (_csi_unlikely (csi_object_get_type (obj) != + CSI_OBJECT_TYPE_PATTERN)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + cairo_set_source (cr, obj->datum.pattern); + return CSI_STATUS_SUCCESS; + } + + if (strcmp ((char *) key, "scaled-font") == 0) { + if (_csi_unlikely (csi_object_get_type (obj) != + CSI_OBJECT_TYPE_SCALED_FONT)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + cairo_set_scaled_font (cr, obj->datum.scaled_font); + return CSI_STATUS_SUCCESS; + } + + if (strcmp ((char *) key, "font-face") == 0) { + if (_csi_unlikely (csi_object_get_type (obj) != + CSI_OBJECT_TYPE_FONT)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + cairo_set_font_face (cr, obj->datum.font_face); + return CSI_STATUS_SUCCESS; + } + + /* return _proxy_set()? */ + return _csi_error (CSI_STATUS_INVALID_SCRIPT); +} + +static csi_status_t +_set (csi_t *ctx) +{ + csi_object_t *key, *value, *dst; + csi_status_t status; + int type; + + check (3); + + value = _csi_peek_ostack (ctx, 0); + key = _csi_peek_ostack (ctx, 1); + dst = _csi_peek_ostack (ctx, 2); + + type = csi_object_get_type (dst); + switch (type) { + case CSI_OBJECT_TYPE_DICTIONARY: + if (_csi_unlikely (csi_object_get_type (key) != + CSI_OBJECT_TYPE_NAME)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + status = csi_dictionary_put (ctx, + dst->datum.dictionary, + key->datum.name, + value); + break; + case CSI_OBJECT_TYPE_ARRAY: + if (_csi_unlikely (csi_object_get_type (key) != + CSI_OBJECT_TYPE_INTEGER)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + status = csi_array_put (ctx, + dst->datum.array, + key->datum.integer, + value); + break; + + case CSI_OBJECT_TYPE_CONTEXT: + if (_csi_unlikely (csi_object_get_type (key) != + CSI_OBJECT_TYPE_NAME)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + status = _context_set (ctx, + dst->datum.cr, + key->datum.name, + value); + break; + + case CSI_OBJECT_TYPE_STRING: +#if 0 + status = csi_string_put (dst, key, value); + break; +#endif + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + pop (2); + return status; +} + +static csi_status_t +_set_antialias (csi_t *ctx) +{ + csi_status_t status; + cairo_t *cr; + long antialias; + + check (2); + + status = _csi_ostack_get_integer (ctx, 0, &antialias); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_set_antialias (cr, antialias); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_dash (csi_t *ctx) +{ + csi_array_t *array; + csi_status_t status; + cairo_t *cr; + double offset; + + check (3); + + status = _csi_ostack_get_number (ctx, 0, &offset); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_array (ctx, 1, &array); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 2, &cr); + if (_csi_unlikely (status)) + return status; + + if (array->stack.len == 0) { + cairo_set_dash (cr, NULL, 0., 0.); + } else { + double stack_dashes[8]; + double *dashes; + csi_integer_t n; + + if (_csi_likely (array->stack.len < ARRAY_LENGTH (stack_dashes))) { + dashes = stack_dashes; + } else { + if (_csi_unlikely ((unsigned) array->stack.len >= INT_MAX / sizeof (double))) + return _csi_error (CSI_STATUS_NO_MEMORY); + dashes = _csi_alloc (ctx, sizeof (double) * array->stack.len); + if (_csi_unlikely (dashes == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + } + + for (n = 0; n < array->stack.len; n++) { + if (_csi_unlikely (! csi_object_is_number + (&array->stack.objects[n]))) + { + if (dashes != stack_dashes) + _csi_free (ctx, dashes); + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + dashes[n] = csi_number_get_value (&array->stack.objects[n]); + } + + cairo_set_dash (cr, dashes, n, offset); + + if (dashes != stack_dashes) + _csi_free (ctx, dashes); + } + + pop (2); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_device_offset (csi_t *ctx) +{ + csi_status_t status; + cairo_surface_t *surface; + double x, y; + + check (3); + + status = _csi_ostack_get_number (ctx, 0, &y); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &x); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_surface (ctx, 2, &surface); + if (_csi_unlikely (status)) + return status; + + cairo_surface_set_device_offset (surface, x, y); + pop (2); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_device_scale (csi_t *ctx) +{ + csi_status_t status; + cairo_surface_t *surface; + double x, y; + + check (3); + + status = _csi_ostack_get_number (ctx, 0, &y); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &x); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_surface (ctx, 2, &surface); + if (_csi_unlikely (status)) + return status; + + cairo_surface_set_device_scale (surface, x, y); + pop (2); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_extend (csi_t *ctx) +{ + csi_status_t status; + csi_object_t *obj; + long extend; + int type; + + check (2); + + status = _csi_ostack_get_integer (ctx, 0, &extend); + if (_csi_unlikely (status)) + return status; + + obj = _csi_peek_ostack (ctx, 1); + type = csi_object_get_type (obj); + switch (type) { + case CSI_OBJECT_TYPE_CONTEXT: + cairo_pattern_set_extend (cairo_get_source (obj->datum.cr), + extend); + break; + case CSI_OBJECT_TYPE_PATTERN: + cairo_pattern_set_extend (obj->datum.pattern, extend); + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_fallback_resolution (csi_t *ctx) +{ + csi_status_t status; + cairo_surface_t *surface; + double dpi_x, dpi_y; + + check (3); + + status = _csi_ostack_get_number (ctx, 0, &dpi_y); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &dpi_x); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_surface (ctx, 2, &surface); + if (_csi_unlikely (status)) + return status; + + cairo_surface_set_fallback_resolution (surface, dpi_x, dpi_y); + pop (2); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_fill_rule (csi_t *ctx) +{ + csi_status_t status; + cairo_t *cr; + long fill_rule; + + check (2); + + status = _csi_ostack_get_integer (ctx, 0, &fill_rule); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_set_fill_rule (cr, fill_rule); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_filter (csi_t *ctx) +{ + csi_status_t status; + csi_object_t *obj; + long filter; + int type; + + check (2); + + status = _csi_ostack_get_integer (ctx, 0, &filter); + if (_csi_unlikely (status)) + return status; + + obj = _csi_peek_ostack (ctx, 1); + type = csi_object_get_type (obj); + switch (type) { + case CSI_OBJECT_TYPE_CONTEXT: + cairo_pattern_set_filter (cairo_get_source (obj->datum.cr), + filter); + break; + case CSI_OBJECT_TYPE_PATTERN: + cairo_pattern_set_filter (obj->datum.pattern, filter); + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_font_face (csi_t *ctx) +{ + cairo_t *cr; + cairo_font_face_t *font = NULL; /* silence the compiler */ + csi_status_t status; + + check (2); + + status = _csi_ostack_get_font_face (ctx, 0, &font); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_set_font_face (cr, font); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_font_options (csi_t *ctx) +{ + csi_status_t status; + cairo_t *cr; + csi_dictionary_t *dict; + cairo_font_options_t *options; + + check (2); + + status = _csi_ostack_get_dictionary (ctx, 0, &dict); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + options = cairo_font_options_create (); + status = _font_options_load_from_dictionary (ctx, dict, options); + if (_csi_unlikely (status)) + return status; + + cairo_set_font_options (cr, options); + cairo_font_options_destroy (options); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_font_matrix (csi_t *ctx) +{ + csi_status_t status; + cairo_t *cr; + cairo_matrix_t m; + + check (2); + + status = _csi_ostack_get_matrix (ctx, 0, &m); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_set_font_matrix (cr, &m); + pop(1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_font_size (csi_t *ctx) +{ + csi_status_t status; + cairo_t *cr; + double size; + + check (2); + + status = _csi_ostack_get_number (ctx, 0, &size); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_set_font_size (cr, size); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_line_cap (csi_t *ctx) +{ + csi_status_t status; + cairo_t *cr; + long line_cap; + + check (2); + + status = _csi_ostack_get_integer (ctx, 0, &line_cap); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_set_line_cap (cr, line_cap); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_line_join (csi_t *ctx) +{ + csi_status_t status; + cairo_t *cr; + long line_join; + + status = _csi_ostack_get_integer (ctx, 0, &line_join); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_set_line_join (cr, line_join); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_line_width (csi_t *ctx) +{ + csi_status_t status; + cairo_t *cr; + double line_width; + + check (2); + + status = _csi_ostack_get_number (ctx, 0, &line_width); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_set_line_width (cr, line_width); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_hairline (csi_t *ctx) +{ + csi_status_t status; + cairo_t *cr; + cairo_bool_t set_hairline = FALSE; /* silence the compiler */ + + check (2); + + status = _csi_ostack_get_boolean (ctx, 0, &set_hairline); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_set_hairline (cr, set_hairline); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_matrix (csi_t *ctx) +{ + csi_object_t *obj; + csi_status_t status; + cairo_matrix_t m; + int type; + + check (2); + + status = _csi_ostack_get_matrix (ctx, 0, &m); + if (_csi_unlikely (status)) + return status; + + obj = _csi_peek_ostack (ctx, 1); + type = csi_object_get_type (obj); + switch (type) { + case CSI_OBJECT_TYPE_CONTEXT: + cairo_set_matrix (obj->datum.cr, &m); + break; + case CSI_OBJECT_TYPE_PATTERN: + cairo_pattern_set_matrix (obj->datum.pattern, &m); + break; + case CSI_OBJECT_TYPE_MATRIX: + obj->datum.matrix->matrix = m; + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + pop (1); + return CSI_STATUS_SUCCESS; +} + +struct _mime_tag { + csi_t *ctx; + csi_string_t *source; +}; +static void +_mime_tag_destroy (void *closure) +{ + struct _mime_tag *tag = closure; + + if (--tag->source->base.ref) + csi_string_free (tag->ctx, tag->source); + + _csi_slab_free (tag->ctx, tag, sizeof (struct _mime_tag)); +} + +static csi_status_t +_set_mime_data (csi_t *ctx) +{ + csi_status_t status; + csi_object_t *obj; + const char *mime = NULL; /* silence the compiler */ + csi_object_t source; + cairo_surface_t *surface; + struct _mime_tag *tag; + int type; + + check (3); + + obj = _csi_peek_ostack (ctx, 0); + type = csi_object_get_type (obj); + switch (type) { + case CSI_OBJECT_TYPE_FILE: + status = _csi_file_as_string (ctx, obj->datum.file, &source); + if (_csi_unlikely (status)) + return status; + + break; + + case CSI_OBJECT_TYPE_STRING: + source = *csi_object_reference (obj); + break; + + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + status = _csi_ostack_get_string_constant (ctx, 1, &mime); + if (_csi_unlikely (status)) + return status; + + status = _csi_ostack_get_surface (ctx, 2, &surface); + if (_csi_unlikely (status)) + return status; + + + /* XXX free source */ + tag = _csi_slab_alloc (ctx, sizeof (struct _mime_tag)); + if (_csi_unlikely (tag == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + tag->ctx = cairo_script_interpreter_reference (ctx); + tag->source = source.datum.string; + tag->source->base.ref++; + + status = cairo_surface_set_mime_data (surface, + mime, + (uint8_t *) + source.datum.string->string, + source.datum.string->len, + _mime_tag_destroy, tag); + if (_csi_unlikely (status)) { + _mime_tag_destroy (tag); + return status; + } + + pop (2); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_miter_limit (csi_t *ctx) +{ + csi_status_t status; + cairo_t *cr; + double miter_limit; + + check (2); + + status = _csi_ostack_get_number (ctx, 0, &miter_limit); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_set_miter_limit (cr, miter_limit); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_operator (csi_t *ctx) +{ + cairo_t *cr; + long val; + csi_status_t status; + + check (2); + + status = _csi_ostack_get_integer (ctx, 0, &val); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_set_operator (cr, val); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_scaled_font (csi_t *ctx) +{ + cairo_t *cr; + cairo_scaled_font_t *font = NULL; /* silence the compiler */ + csi_status_t status; + + check (2); + + status = _csi_ostack_get_scaled_font (ctx, 0, &font); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_set_scaled_font (cr, font); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_source (csi_t *ctx) +{ + cairo_t *cr; + cairo_pattern_t *pattern = NULL; /* silence the compiler */ + csi_status_t status; + + check (2); + + status = _csi_ostack_get_pattern (ctx, 0, &pattern); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_set_source (cr, pattern); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_boolean_t +_matching_images (cairo_surface_t *a, cairo_surface_t *b) +{ + cairo_format_t format_a, format_b; + + if (cairo_surface_get_type (a) != CAIRO_SURFACE_TYPE_IMAGE) + return FALSE; + if (cairo_surface_get_type (b) != CAIRO_SURFACE_TYPE_IMAGE) + return FALSE; + + if (cairo_image_surface_get_height (a) != cairo_image_surface_get_height (b)) + return FALSE; + + if (cairo_image_surface_get_width (a) != cairo_image_surface_get_width (b)) + return FALSE; + + format_a = cairo_image_surface_get_format (a); + if (format_a == CAIRO_FORMAT_RGB24) + format_a = CAIRO_FORMAT_ARGB32; + + format_b = cairo_image_surface_get_format (b); + if (format_b == CAIRO_FORMAT_RGB24) + format_b = CAIRO_FORMAT_ARGB32; + + if (format_a != format_b) + return FALSE; + + return TRUE; +} + +static csi_status_t +_set_source_image (csi_t *ctx) +{ + csi_status_t status; + cairo_surface_t *surface; + cairo_surface_t *source; + + check (2); + + status = _csi_ostack_get_surface (ctx, 0, &source); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_surface (ctx, 1, &surface); + if (_csi_unlikely (status)) + return status; + + /* Catch the most frequent use of simply uploading pixel data, + * principally to remove the pixman ops from the profiles. + */ + if (_csi_likely (_matching_images (surface, source))) { + if (cairo_surface_get_reference_count (surface) == 1 && + cairo_surface_get_reference_count (source) == 1) + { + _csi_peek_ostack (ctx, 0)->datum.surface = surface; + _csi_peek_ostack (ctx, 1)->datum.surface = source; + } + else + { + cairo_surface_flush (surface); + memcpy (cairo_image_surface_get_data (surface), + cairo_image_surface_get_data (source), + cairo_image_surface_get_height (source) * cairo_image_surface_get_stride (source)); + cairo_surface_mark_dirty (surface); + } + } else { + cairo_t *cr; + + cr = cairo_create (surface); + cairo_set_source_surface (cr, source, 0, 0); + cairo_paint (cr); + cairo_destroy (cr); + } + + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_source_rgb (csi_t *ctx) +{ + csi_status_t status; + double r,g,b; + cairo_t *cr; + + check (4); + + status = _csi_ostack_get_number (ctx, 0, &b); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &g); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 2, &r); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 3, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_set_source_rgb (cr, r, g, b); + pop (3); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_source_rgba (csi_t *ctx) +{ + csi_status_t status; + double r,g,b,a; + cairo_t *cr; + + check (5); + + status = _csi_ostack_get_number (ctx, 0, &a); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &b); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 2, &g); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 3, &r); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 4, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_set_source_rgba (cr, r, g, b, a); + pop (4); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_set_tolerance (csi_t *ctx) +{ + csi_status_t status; + cairo_t *cr; + double tolerance; + + check (2); + + status = _csi_ostack_get_number (ctx, 0, &tolerance); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_set_tolerance (cr, tolerance); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_transform (csi_t *ctx) +{ + csi_object_t *obj; + csi_status_t status; + cairo_matrix_t m; + int type; + + check (2); + + status = _csi_ostack_get_matrix (ctx, 0, &m); + if (_csi_unlikely (status)) + return status; + + obj = _csi_peek_ostack (ctx, 1); + type = csi_object_get_type (obj); + switch (type) { + case CSI_OBJECT_TYPE_CONTEXT: + cairo_transform (obj->datum.cr, &m); + break; + case CSI_OBJECT_TYPE_PATTERN: + { + cairo_matrix_t ctm; + cairo_pattern_get_matrix (obj->datum.pattern, &ctm); + cairo_matrix_multiply (&ctm, &m, &ctm); + cairo_pattern_set_matrix (obj->datum.pattern, &ctm); + } + break; + case CSI_OBJECT_TYPE_MATRIX: + cairo_matrix_multiply (&obj->datum.matrix->matrix, + &m, + &obj->datum.matrix->matrix); + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_translate (csi_t *ctx) +{ + csi_object_t *obj; + csi_status_t status; + double x, y; + int type; + + check (3); + + status = _csi_ostack_get_number (ctx, 0, &y); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &x); + if (_csi_unlikely (status)) + return status; + + obj = _csi_peek_ostack (ctx, 2); + type = csi_object_get_type (obj); + switch (type) { + case CSI_OBJECT_TYPE_CONTEXT: + cairo_translate (obj->datum.cr, x, y); + break; + + case CSI_OBJECT_TYPE_PATTERN: + { + cairo_matrix_t ctm; + cairo_pattern_get_matrix (obj->datum.pattern, &ctm); + cairo_matrix_translate (&ctm, x, y); + cairo_pattern_set_matrix (obj->datum.pattern, &ctm); + } + break; + + + case CSI_OBJECT_TYPE_MATRIX: + cairo_matrix_translate (&obj->datum.matrix->matrix, x, y); + break; + + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + pop (2); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_true (csi_t *ctx) +{ + return _csi_push_ostack_boolean (ctx, TRUE); +} + +static csi_status_t +_show_page (csi_t *ctx) +{ + csi_object_t *obj; + int type; + + check (1); + + obj = _csi_peek_ostack (ctx, 0); + type = csi_object_get_type (obj); + switch (type) { + case CSI_OBJECT_TYPE_CONTEXT: + cairo_show_page (obj->datum.cr); + if (ctx->hooks.copy_page != NULL) + ctx->hooks.copy_page (ctx->hooks.closure, obj->datum.cr); + break; + case CSI_OBJECT_TYPE_SURFACE: + cairo_surface_show_page (obj->datum.surface); + /* XXX hook? */ + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_similar (csi_t *ctx) +{ + csi_object_t obj; + long content; + double width, height; + cairo_surface_t *other; + csi_status_t status; + + check (4); + + status = _csi_ostack_get_integer (ctx, 0, &content); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &height); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 2, &width); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_surface (ctx, 3, &other); + if (_csi_unlikely (status)) + return status; + + /* silently fix-up a common bug when writing CS */ + if ((content & CAIRO_CONTENT_COLOR_ALPHA) == 0) { + if (_csi_unlikely (content & ~CAIRO_CONTENT_COLOR_ALPHA)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + switch ((int) content) { + default: + case CAIRO_FORMAT_ARGB32: + content = CAIRO_CONTENT_COLOR_ALPHA; + break; + case CAIRO_FORMAT_RGB16_565: + case CAIRO_FORMAT_RGB24: + content = CAIRO_CONTENT_COLOR; + break; + case CAIRO_FORMAT_A8: + case CAIRO_FORMAT_A1: + content = CAIRO_CONTENT_ALPHA; + break; + } + } + + obj.type = CSI_OBJECT_TYPE_SURFACE; + obj.datum.surface = cairo_surface_create_similar (other, + content, width, height); + pop (4); + return push (&obj); +} + +static csi_status_t +_similar_image (csi_t *ctx) +{ + csi_object_t obj; + long format; + double width, height; + cairo_surface_t *other; + csi_status_t status; + + check (4); + + status = _csi_ostack_get_number (ctx, 0, &height); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &width); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_integer (ctx, 2, &format); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_surface (ctx, 3, &other); + if (_csi_unlikely (status)) + return status; + + obj.type = CSI_OBJECT_TYPE_SURFACE; + obj.datum.surface = cairo_surface_create_similar_image (other, + format, + width, height); + pop (4); + return push (&obj); +} + +static csi_status_t +_subsurface (csi_t *ctx) +{ + csi_object_t obj; + double x, y, width, height; + cairo_surface_t *target; + csi_status_t status; + + check (5); + + status = _csi_ostack_get_number (ctx, 0, &height); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 1, &width); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 2, &y); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_number (ctx, 3, &x); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_surface (ctx, 4, &target); + if (_csi_unlikely (status)) + return status; + + obj.type = CSI_OBJECT_TYPE_SURFACE; + obj.datum.surface = cairo_surface_create_for_rectangle (target, x, y, width, height); + pop (5); + return push (&obj); +} + +static csi_status_t +_show_text (csi_t *ctx) +{ + csi_status_t status; + csi_string_t *text; + cairo_t *cr; + + check (2); + + status = _csi_ostack_get_string (ctx, 0, &text); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_show_text (cr, text->string); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_show_glyphs (csi_t *ctx) +{ + csi_array_t *array; + csi_status_t status; + cairo_t *cr; + cairo_glyph_t stack_glyphs[256], *glyphs; + csi_integer_t nglyphs, i; + + check (2); + + status = _csi_ostack_get_array (ctx, 0, &array); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + /* count glyphs */ + nglyphs = 0; + for (i = 0; i < array->stack.len; i++) { + csi_object_t *obj = &array->stack.objects[i]; + int type = csi_object_get_type (obj); + switch (type) { + case CSI_OBJECT_TYPE_ARRAY: + nglyphs += obj->datum.array->stack.len; + break; + case CSI_OBJECT_TYPE_STRING: + nglyphs += obj->datum.string->len; + break; + } + } + if (nglyphs == 0) { + pop (1); + return CSI_STATUS_SUCCESS; + } + + if (nglyphs > ARRAY_LENGTH (stack_glyphs)) { + if (_csi_unlikely ((unsigned) nglyphs >= INT_MAX / sizeof (cairo_glyph_t))) + return _csi_error (CSI_STATUS_NO_MEMORY); + + glyphs = _csi_alloc (ctx, sizeof (cairo_glyph_t) * nglyphs); + if (_csi_unlikely (glyphs == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + } else + glyphs = stack_glyphs; + + nglyphs = _glyph_string (ctx, array, cairo_get_scaled_font (cr), glyphs); + cairo_show_glyphs (cr, glyphs, nglyphs); + + if (glyphs != stack_glyphs) + _csi_free (ctx, glyphs); + + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_show_text_glyphs (csi_t *ctx) +{ + csi_object_t *obj; + csi_array_t *array; + csi_string_t *string; + csi_string_t *utf8_string; + csi_status_t status; + cairo_t *cr; + cairo_text_cluster_t stack_clusters[256], *clusters; + cairo_glyph_t stack_glyphs[256], *glyphs; + csi_integer_t nglyphs, nclusters, i; + long direction; + int type; + + check (5); + + status = _csi_ostack_get_integer (ctx, 0, &direction); + if (_csi_unlikely (status)) + return status; + + obj = _csi_peek_ostack (ctx, 1); + type = csi_object_get_type (obj); + switch (type) { + case CSI_OBJECT_TYPE_ARRAY: + array = obj->datum.array; + nclusters = array->stack.len / 2; + if (nclusters > ARRAY_LENGTH (stack_clusters)) { + if (_csi_unlikely ((unsigned) nclusters >= INT_MAX / sizeof (cairo_text_cluster_t))) + return _csi_error (CSI_STATUS_NO_MEMORY); + clusters = _csi_alloc (ctx, sizeof (cairo_text_cluster_t) * nclusters); + if (_csi_unlikely (clusters == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + } else + clusters = stack_clusters; + + for (i = 0; i < nclusters; i++) { + clusters[i].num_bytes = csi_number_get_value (&array->stack.objects[2*i+0]); + clusters[i].num_glyphs = csi_number_get_value (&array->stack.objects[2*i+1]); + } + break; + + case CSI_OBJECT_TYPE_STRING: + string = obj->datum.string; + nclusters = string->len / 2; + if (nclusters > ARRAY_LENGTH (stack_clusters)) { + if (_csi_unlikely ((unsigned) nclusters >= INT_MAX / sizeof (cairo_text_cluster_t))) + return _csi_error (CSI_STATUS_NO_MEMORY); + clusters = _csi_alloc (ctx, sizeof (cairo_text_cluster_t) * nclusters); + if (_csi_unlikely (clusters == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + } else + clusters = stack_clusters; + + for (i = 0; i < nclusters; i++) { + clusters[i].num_bytes = string->string[2*i+0]; + clusters[i].num_glyphs = string->string[2*i+1]; + } + break; + + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + status = _csi_ostack_get_array (ctx, 2, &array); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_string (ctx, 3, &utf8_string); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 4, &cr); + if (_csi_unlikely (status)) + return status; + + /* count glyphs */ + nglyphs = 0; + for (i = 0; i < array->stack.len; i++) { + obj = &array->stack.objects[i]; + type = csi_object_get_type (obj); + switch (type) { + case CSI_OBJECT_TYPE_ARRAY: + nglyphs += obj->datum.array->stack.len; + break; + case CSI_OBJECT_TYPE_STRING: + nglyphs += obj->datum.string->len; + break; + } + } + if (nglyphs == 0) { + pop (4); + return CSI_STATUS_SUCCESS; + } + + if (nglyphs > ARRAY_LENGTH (stack_glyphs)) { + if (_csi_unlikely ((unsigned) nglyphs >= INT_MAX / sizeof (cairo_glyph_t))) + return _csi_error (CSI_STATUS_NO_MEMORY); + + glyphs = _csi_alloc (ctx, sizeof (cairo_glyph_t) * nglyphs); + if (_csi_unlikely (glyphs == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + } else + glyphs = stack_glyphs; + + nglyphs = _glyph_string (ctx, array, cairo_get_scaled_font (cr), glyphs); + cairo_show_text_glyphs (cr, + utf8_string->string, utf8_string->len, + glyphs, nglyphs, + clusters, nclusters, + direction); + + if (clusters != stack_clusters) + _csi_free (ctx, clusters); + if (glyphs != stack_glyphs) + _csi_free (ctx, glyphs); + + pop (4); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_stroke (csi_t *ctx) +{ + return _do_cairo_op (ctx, cairo_stroke); +} + +static csi_status_t +_stroke_preserve (csi_t *ctx) +{ + return _do_cairo_op (ctx, cairo_stroke_preserve); +} + +static csi_status_t +_sub (csi_t *ctx) +{ + csi_object_t *A; + csi_object_t *B; + csi_object_type_t type_a, type_b; + + check (2); + + B = _csi_peek_ostack (ctx, 0); + A = _csi_peek_ostack (ctx, 1); + + type_a = csi_object_get_type (A); + if (_csi_unlikely (! (type_a == CSI_OBJECT_TYPE_INTEGER || + type_a == CSI_OBJECT_TYPE_REAL))) + { + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + type_b = csi_object_get_type (B); + if (_csi_unlikely (! (type_b == CSI_OBJECT_TYPE_INTEGER || + type_b == CSI_OBJECT_TYPE_REAL))) + { + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + pop (2); + + if (type_a == CSI_OBJECT_TYPE_REAL && + type_b == CSI_OBJECT_TYPE_REAL) + { + return _csi_push_ostack_real (ctx, A->datum.real - B->datum.real); + + } + else if (type_a == CSI_OBJECT_TYPE_INTEGER && + type_b == CSI_OBJECT_TYPE_INTEGER) + { + return _csi_push_ostack_integer (ctx, + A->datum.integer - B->datum.integer); + } + else + { + double v; + + if (type_a == CSI_OBJECT_TYPE_REAL) + v = A->datum.real; + else + v = A->datum.integer; + + if (type_b == CSI_OBJECT_TYPE_REAL) + v -= B->datum.real; + else + v -= B->datum.integer; + + return _csi_push_ostack_real (ctx, v); + } +} + +static csi_status_t +_surface (csi_t *ctx) +{ + csi_object_t obj; + csi_dictionary_t *dict; + csi_proxy_t *proxy; + csi_object_t key; + double width, height; + csi_surface_create_func_t hook; + long content; + cairo_surface_t *surface; + long uid; + csi_status_t status; + + check (1); + + status = _csi_ostack_get_dictionary (ctx, 0, &dict); + if (_csi_unlikely (status)) + return status; + + status = _csi_dictionary_get_number (ctx, dict, "width", FALSE, &width); + if (_csi_unlikely (status)) + return status; + status = _csi_dictionary_get_number (ctx, dict, "height", FALSE, &height); + if (_csi_unlikely (status)) + return status; + + content = CAIRO_CONTENT_COLOR_ALPHA; + status = _csi_dictionary_get_integer (ctx, dict, "content", TRUE, &content); + if (_csi_unlikely (status)) + return status; + + uid = 0; + status = _csi_dictionary_get_integer (ctx, dict, "uid", TRUE, &uid); + if (_csi_unlikely (status)) + return status; + if (uid == 0) { + status = _csi_dictionary_get_integer (ctx, dict, "drawable", TRUE, &uid); + if (_csi_unlikely (status)) + return status; + } + + hook = ctx->hooks.surface_create; + assert (hook != NULL); + + surface = hook (ctx->hooks.closure, content, width, height, uid); + if (_csi_unlikely (surface == NULL)) { + return _csi_error (CSI_STATUS_NULL_POINTER); + } + + proxy = _csi_proxy_create (ctx, surface, dict, + ctx->hooks.surface_destroy, + ctx->hooks.closure); + if (_csi_unlikely (proxy == NULL)) { + cairo_surface_destroy (surface); + return _csi_error (CSI_STATUS_NO_MEMORY); + } + + status = cairo_surface_set_user_data (surface, + &_csi_proxy_key, + proxy, _csi_proxy_destroy); + if (_csi_unlikely (status)) { + _csi_proxy_destroy (proxy); + cairo_surface_destroy (surface); + return status; + } + + status = csi_name_new_static (ctx, &key, "fallback-resolution"); + if (_csi_unlikely (status)) { + cairo_surface_destroy (surface); + return status; + } + if (csi_dictionary_has (dict, key.datum.name)) { + status = csi_dictionary_get (ctx, dict, key.datum.name, &obj); + if (_csi_unlikely (status)) { + cairo_surface_destroy (surface); + return status; + } + if (csi_object_get_type (&obj) == CSI_OBJECT_TYPE_ARRAY) { + csi_array_t *array = obj.datum.array; + if (array->stack.len == 2) { + cairo_surface_set_fallback_resolution (surface, + csi_number_get_value + (&array->stack.objects[0]), + csi_number_get_value + (&array->stack.objects[1])); + } + } + } + /* initialise surface to source */ + status = csi_name_new_static (ctx, &key, "source"); + if (_csi_unlikely (status)) { + cairo_surface_destroy (surface); + return status; + } + if (csi_dictionary_has (dict, key.datum.name)) { + cairo_surface_t *image; + cairo_t *cr; + + status = _image_load_from_dictionary (ctx, dict, &image); + if (_csi_unlikely (status)) { + cairo_surface_destroy (surface); + return status; + } + + cr = cairo_create (surface); + cairo_set_source_surface (cr, image, 0, 0); + cairo_surface_destroy (image); + cairo_paint (cr); + status = cairo_status (cr); + cairo_destroy (cr); + + if (_csi_unlikely (status)) + return status; + } + + status = csi_name_new_static (ctx, &key, "device-offset"); + if (_csi_unlikely (status)) { + cairo_surface_destroy (surface); + return status; + } + if (csi_dictionary_has (dict, key.datum.name)) { + status = csi_dictionary_get (ctx, dict, key.datum.name, &obj); + if (_csi_unlikely (status)) + return status; + + if (csi_object_get_type (&obj) == CSI_OBJECT_TYPE_ARRAY) { + csi_array_t *array = obj.datum.array; + + if (array->stack.len == 2) { + cairo_surface_set_device_offset (surface, + csi_number_get_value + (&array->stack.objects[0]), + csi_number_get_value + (&array->stack.objects[1])); + } + } + } + + status = csi_name_new_static (ctx, &key, "device-scale"); + if (_csi_unlikely (status)) { + cairo_surface_destroy (surface); + return status; + } + if (csi_dictionary_has (dict, key.datum.name)) { + status = csi_dictionary_get (ctx, dict, key.datum.name, &obj); + if (_csi_unlikely (status)) + return status; + + if (csi_object_get_type (&obj) == CSI_OBJECT_TYPE_ARRAY) { + csi_array_t *array = obj.datum.array; + + if (array->stack.len == 2) { + cairo_surface_set_device_scale (surface, + csi_number_get_value + (&array->stack.objects[0]), + csi_number_get_value + (&array->stack.objects[1])); + } + } + } + + obj.type = CSI_OBJECT_TYPE_SURFACE; + obj.datum.surface = surface; + pop (1); + return push (&obj); +} + +static csi_status_t +_record (csi_t *ctx) +{ + csi_object_t obj; + long content; + csi_array_t *array; + csi_status_t status; + cairo_rectangle_t extents; + cairo_rectangle_t *r; + + check (2); + + status = _csi_ostack_get_array (ctx, 0, &array); + if (_csi_unlikely (status)) + return status; + + status = _csi_ostack_get_integer (ctx, 1, &content); + if (_csi_unlikely (status)) + return status; + + switch (array->stack.len) { + case 0: + r = NULL; + break; + case 2: + extents.x = extents.y = 0; + extents.width = _csi_object_as_real (&array->stack.objects[0]); + extents.height = _csi_object_as_real (&array->stack.objects[1]); + r = &extents; + break; + case 4: + extents.x = _csi_object_as_real (&array->stack.objects[0]); + extents.y = _csi_object_as_real (&array->stack.objects[1]); + extents.width = _csi_object_as_real (&array->stack.objects[2]); + extents.height = _csi_object_as_real (&array->stack.objects[3]); + r = &extents; + break; + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + obj.type = CSI_OBJECT_TYPE_SURFACE; + obj.datum.surface = cairo_recording_surface_create (content, r); + pop (2); + return push (&obj); +} + +static csi_status_t +_text_path (csi_t *ctx) +{ + csi_status_t status; + csi_string_t *text; + cairo_t *cr; + + check (2); + + status = _csi_ostack_get_string (ctx, 0, &text); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_context (ctx, 1, &cr); + if (_csi_unlikely (status)) + return status; + + cairo_text_path (cr, text->string); + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_undef (csi_t *ctx) +{ + csi_name_t name = 0; /* silence the compiler */ + csi_status_t status; + + check (1); + + status = _csi_ostack_get_name (ctx, 0, &name); + if (_csi_unlikely (status)) + return status; + + status = _csi_name_undefine (ctx, name); + if (_csi_unlikely (status)) + return status; + + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_unset (csi_t *ctx) +{ + csi_object_t *dst; + csi_name_t name = 0; /* silence the compiler */ + csi_status_t status; + int type; + + check (2); + + status = _csi_ostack_get_name (ctx, 0, &name); + if (_csi_unlikely (status)) + return status; + + dst = _csi_peek_ostack (ctx, 1); + type = csi_object_get_type (dst); + switch (type) { + case CSI_OBJECT_TYPE_DICTIONARY: + csi_dictionary_remove (ctx, dst->datum.dictionary, name); + break; + case CSI_OBJECT_TYPE_STRING: + case CSI_OBJECT_TYPE_ARRAY: + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } + + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_write_to_png (csi_t *ctx) +{ + csi_status_t status; + csi_string_t *filename; + cairo_surface_t *surface; + + check (2); + + status = _csi_ostack_get_string (ctx, 0, &filename); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_surface (ctx, 1, &surface); + if (_csi_unlikely (status)) + return status; + +#if CAIRO_HAS_PNG_FUNCTIONS + status = cairo_surface_write_to_png (surface, filename->string); + if (_csi_unlikely (status)) + return status; +#else + return CAIRO_STATUS_WRITE_ERROR; +#endif + + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_write_to_script (csi_t *ctx) +{ + csi_status_t status; + csi_string_t *filename; + cairo_surface_t *record; + + check (2); + + status = _csi_ostack_get_string (ctx, 0, &filename); + if (_csi_unlikely (status)) + return status; + status = _csi_ostack_get_surface (ctx, 1, &record); + if (_csi_unlikely (status)) + return status; + + if (cairo_surface_get_type (record) != CAIRO_SURFACE_TYPE_RECORDING) + return CAIRO_STATUS_SURFACE_TYPE_MISMATCH; + +#if CAIRO_HAS_SCRIPT_SURFACE + { + cairo_device_t *script; + + script = cairo_script_create (filename->string); + status = cairo_script_from_recording_surface (script, record); + cairo_device_destroy (script); + if (_csi_unlikely (status)) + return status; + } +#else + return CAIRO_STATUS_WRITE_ERROR; +#endif + + pop (1); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_xor (csi_t *ctx) +{ + csi_object_t *a, *b; + int type; + + check (2); + + a = _csi_peek_ostack (ctx, 0); + b = _csi_peek_ostack (ctx, 1); + if (_csi_unlikely (csi_object_get_type (a) != csi_object_get_type (b))) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + pop (2); + type = csi_object_get_type (a); + switch (type) { + case CSI_OBJECT_TYPE_INTEGER: + return _csi_push_ostack_integer (ctx, + a->datum.integer ^ b->datum.integer); + case CSI_OBJECT_TYPE_BOOLEAN: + return _csi_push_ostack_boolean (ctx, + a->datum.boolean ^ b->datum.boolean); + default: + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + } +} + +static csi_status_t +_debug_print (csi_t *ctx) +{ + csi_object_t *obj; + + check (1); + obj = _csi_peek_ostack (ctx, 0); + switch (csi_object_get_type (obj)) { + case CSI_OBJECT_TYPE_NULL: + fprintf (stderr, "NULL\n"); + break; + + /* atomics */ + case CSI_OBJECT_TYPE_BOOLEAN: + fprintf (stderr, "boolean: %s\n", + obj->datum.boolean ? "true" : "false"); + break; + case CSI_OBJECT_TYPE_INTEGER: + fprintf (stderr, "integer: %ld\n", obj->datum.integer); + break; + case CSI_OBJECT_TYPE_MARK: + fprintf (stderr, "mark\n"); + break; + case CSI_OBJECT_TYPE_NAME: + fprintf (stderr, "name: %s\n", (char *) obj->datum.name); + break; + case CSI_OBJECT_TYPE_OPERATOR: + fprintf (stderr, "operator: %p\n", obj->datum.ptr); + break; + case CSI_OBJECT_TYPE_REAL: + fprintf (stderr, "real: %g\n", obj->datum.real); + break; + + /* compound */ + case CSI_OBJECT_TYPE_ARRAY: + fprintf (stderr, "array\n"); + break; + case CSI_OBJECT_TYPE_DICTIONARY: + fprintf (stderr, "dictionary\n"); + break; + case CSI_OBJECT_TYPE_FILE: + fprintf (stderr, "file\n"); + break; + case CSI_OBJECT_TYPE_MATRIX: + fprintf (stderr, "matrix: [%g %g %g %g %g %g]\n", + obj->datum.matrix->matrix.xx, + obj->datum.matrix->matrix.yx, + obj->datum.matrix->matrix.xy, + obj->datum.matrix->matrix.yy, + obj->datum.matrix->matrix.x0, + obj->datum.matrix->matrix.y0); + break; + case CSI_OBJECT_TYPE_STRING: + fprintf (stderr, "string: %s\n", obj->datum.string->string); + break; + + /* cairo */ + case CSI_OBJECT_TYPE_CONTEXT: + fprintf (stderr, "context\n"); + break; + case CSI_OBJECT_TYPE_FONT: + fprintf (stderr, "font\n"); + break; + case CSI_OBJECT_TYPE_PATTERN: + fprintf (stderr, "pattern\n"); + break; + case CSI_OBJECT_TYPE_SCALED_FONT: + fprintf (stderr, "scaled-font\n"); + break; + case CSI_OBJECT_TYPE_SURFACE: + fprintf (stderr, "surface\n"); + break; + } + pop (1); + return CSI_STATUS_SUCCESS; +} + +static const csi_operator_def_t +_defs[] = { + { "<<", _mark }, + { ">>", end_dict_construction }, + { "[", _mark }, + { "]", end_array_construction }, + { "a", _alpha }, + { "abs", NULL }, + { "add", _add }, + { "add-color-stop", _add_color_stop }, + { "and", _and }, + { "arc", _arc }, + { "arc-negative", _arc_negative }, + { "arc-", _arc_negative }, + { "arc-to", NULL }, + { "array", _array }, + { "astore", NULL }, + { "atan", NULL }, + { "bind", _bind }, + { "bitshift", _bitshift }, + { "c", _curve_to }, + { "C", _rel_curve_to }, + { "ceiling", NULL }, + { "clear", NULL }, + { "clear-to-mark", NULL }, + { "clip", _clip }, + { "clip-extents", NULL }, + { "clip-preserve", _clip_preserve }, + { "clip+", _clip_preserve }, + { "close-path", _close_path }, + { "context", _context }, + { "copy", _copy }, + { "copy-page", _copy_page }, + { "cos", NULL }, + { "count", NULL }, + { "count-to-mark", NULL }, + { "curve-to", _curve_to }, + { "cvi", _cvi }, + { "cvr", _cvr }, + { "def", _def }, + { "device-to-user", NULL }, + { "device-to-user-distance", NULL }, + { "dict", _dict }, + { "div", _div }, + { "dup", _duplicate }, + { "eq", _eq }, + { "exch", _exch }, + { "exec", NULL }, + { "exp", NULL }, + { "false", _false }, + { "fill", _fill }, + { "fill-extents", NULL }, + { "fill-preserve", _fill_preserve }, + { "fill+", _fill_preserve }, + { "filter", _filter }, + { "floor", NULL }, + { "font", _font }, + { "for", _for }, + { "forall", NULL }, + { "g", _gray }, + { "ge", _ge }, + { "get", _get }, + { "glyph-path", _glyph_path }, + { "gt", _gt }, + { "h", _close_path }, + { "identity", _identity }, + { "if", _if }, + { "ifelse", _ifelse }, + { "image", _image }, + { "index", _index }, + { "integer", _integer }, + { "invert", _invert }, + { "in-stroke", NULL }, + { "in-fill", NULL }, + { "known", NULL }, + { "l", _line_to }, + { "L", _rel_line_to }, + { "languagelevel", NULL }, + { "le", _le }, + { "length", NULL }, + { "linear", _linear }, + { "line-to", _line_to }, + { "ln", NULL }, + { "load", NULL }, + { "log", NULL }, + { "loop", NULL }, + { "lt", _lt }, + { "m", _move_to }, + { "M", _rel_move_to }, + { "map-to-image", _map_to_image }, + { "mark", _mark }, + { "mask", _mask }, + { "matrix", _matrix }, + + { "mesh", _mesh }, + { "begin-patch", _mesh_begin_patch }, + { "end-patch", _mesh_end_patch }, + { "set-control-point", _mesh_set_control_point }, + { "set-corner-color", _mesh_set_corner_color }, + + { "mod", _mod }, + { "move-to", _move_to }, + { "mul", _mul }, + { "multiply", NULL }, + { "n", _new_path }, + { "N", _new_sub_path }, + { "ne", _ne }, + { "neg", _neg }, + { "new-path", _new_path }, + { "new-sub-path", _new_sub_path }, + { "not", _not }, + { "null", _null }, + { "or", _or }, + { "paint", _paint }, + { "paint-with-alpha", _paint_with_alpha }, + { "pattern", _pattern }, + { "pop", _pop }, + { "pop-group", _pop_group }, + { "push-group", _push_group }, + { "radial", _radial }, + { "rand", NULL }, + { "record", _record }, + { "rectangle", _rectangle }, + { "repeat", _repeat }, + { "restore", _restore }, + { "rel-curve-to", _rel_curve_to }, + { "rel-line-to", _rel_line_to }, + { "rel-move-to", _rel_move_to }, + { "reset-clip", _reset_clip }, + { "rgb", _rgb }, + { "rgba", _rgba }, + { "roll", _roll }, + { "rotate", _rotate }, + { "round", NULL }, + { "run", NULL }, + { "save", _save }, + { "scale", _scale }, + { "scaled-font", _scaled_font }, + { "select-font-face", _select_font_face }, + { "set", _set }, + { "set-antialias", _set_antialias }, + { "set-dash", _set_dash }, + { "set-device-offset", _set_device_offset }, + { "set-device-scale", _set_device_scale }, + { "set-extend", _set_extend }, + { "set-fallback-resolution", _set_fallback_resolution }, + { "set-fill-rule", _set_fill_rule }, + { "set-filter", _set_filter }, + { "set-font-face", _set_font_face }, + { "set-font-options", _set_font_options }, + { "set-font-matrix", _set_font_matrix }, + { "set-font-size", _set_font_size }, + { "set-line-cap", _set_line_cap }, + { "set-line-join", _set_line_join }, + { "set-line-width", _set_line_width }, + { "set-hairline", _set_hairline }, + { "set-matrix", _set_matrix }, + { "set-miter-limit", _set_miter_limit }, + { "set-mime-data", _set_mime_data }, + { "set-operator", _set_operator }, + { "set-scaled-font", _set_scaled_font }, + { "set-source", _set_source }, + { "set-source-image", _set_source_image }, + { "set-source-rgb", _set_source_rgb }, + { "set-source-rgba", _set_source_rgba }, + { "set-tolerance", _set_tolerance }, + { "show-glyphs", _show_glyphs }, + { "show-text", _show_text }, + { "show-text-glyphs", _show_text_glyphs }, + { "show-page", _show_page }, + { "similar", _similar }, + { "similar-image", _similar_image }, + { "sin", NULL }, + { "sqrt", NULL }, + { "sub", _sub }, + { "subsurface", _subsurface }, + { "surface", _surface }, + { "string", NULL }, + { "stroke", _stroke }, + { "stroke-extents", NULL }, + { "stroke-preserve", _stroke_preserve }, + { "stroke+", _stroke_preserve }, + { "text-path", _text_path }, + { "transform", _transform }, + { "transform-distance", NULL }, + { "transform-point", NULL }, + { "translate", _translate }, + { "true", _true }, + { "type", NULL }, + { "undef", _undef }, + { "unmap-image", _unmap_image }, + { "unset", _unset }, + { "user-to-device", NULL }, + { "user-to-device-distance", NULL }, + { "where", NULL }, + { "write-to-png", _write_to_png }, + { "write-to-script", _write_to_script }, + { "xor", _xor }, + + { "=", _debug_print }, + + { NULL, NULL }, +}; + +const csi_operator_def_t * +_csi_operators (void) +{ + return _defs; +} + +static const csi_integer_constant_def_t +_integer_constants[] = { + { "CLEAR", CAIRO_OPERATOR_CLEAR }, + { "SOURCE", CAIRO_OPERATOR_SOURCE }, + { "OVER", CAIRO_OPERATOR_OVER }, + { "IN", CAIRO_OPERATOR_IN }, + { "OUT", CAIRO_OPERATOR_OUT }, + { "ATOP", CAIRO_OPERATOR_ATOP }, + { "DEST", CAIRO_OPERATOR_DEST }, + { "DEST_OVER", CAIRO_OPERATOR_DEST_OVER }, + { "DEST_IN", CAIRO_OPERATOR_DEST_IN }, + { "DEST_OUT", CAIRO_OPERATOR_DEST_OUT }, + { "DEST_ATOP", CAIRO_OPERATOR_DEST_ATOP }, + { "XOR", CAIRO_OPERATOR_XOR }, + { "ADD", CAIRO_OPERATOR_ADD }, + { "SATURATE", CAIRO_OPERATOR_SATURATE }, + { "MULTIPLY", CAIRO_OPERATOR_MULTIPLY }, + { "SCREEN", CAIRO_OPERATOR_SCREEN }, + { "OVERLAY", CAIRO_OPERATOR_OVERLAY }, + { "DARKEN", CAIRO_OPERATOR_DARKEN }, + { "LIGHTEN", CAIRO_OPERATOR_LIGHTEN }, + { "DODGE", CAIRO_OPERATOR_COLOR_DODGE }, + { "BURN", CAIRO_OPERATOR_COLOR_BURN }, + { "HARD_LIGHT", CAIRO_OPERATOR_HARD_LIGHT }, + { "SOFT_LIGHT", CAIRO_OPERATOR_SOFT_LIGHT }, + { "DIFFERENCE", CAIRO_OPERATOR_DIFFERENCE }, + { "EXCLUSION", CAIRO_OPERATOR_EXCLUSION }, + { "HSL_HUE", CAIRO_OPERATOR_HSL_HUE }, + { "HSL_SATURATION", CAIRO_OPERATOR_HSL_SATURATION }, + { "HSL_COLOR", CAIRO_OPERATOR_HSL_COLOR }, + { "HSL_LUMINOSITY", CAIRO_OPERATOR_HSL_LUMINOSITY }, + + { "WINDING", CAIRO_FILL_RULE_WINDING }, + { "EVEN_ODD", CAIRO_FILL_RULE_EVEN_ODD }, + + { "ANTIALIAS_DEFAULT", CAIRO_ANTIALIAS_DEFAULT }, + { "ANTIALIAS_NONE", CAIRO_ANTIALIAS_NONE }, + { "ANTIALIAS_GRAY", CAIRO_ANTIALIAS_GRAY }, + { "ANTIALIAS_SUBPIXEL", CAIRO_ANTIALIAS_SUBPIXEL }, + { "ANTIALIAS_FAST", CAIRO_ANTIALIAS_FAST }, + { "ANTIALIAS_GOOD", CAIRO_ANTIALIAS_GOOD }, + { "ANTIALIAS_BEST", CAIRO_ANTIALIAS_BEST }, + + { "LINE_CAP_BUTT", CAIRO_LINE_CAP_BUTT }, + { "LINE_CAP_ROUND", CAIRO_LINE_CAP_ROUND }, + { "LINE_CAP_SQUARE", CAIRO_LINE_CAP_SQUARE }, + + { "LINE_JOIN_MITER", CAIRO_LINE_JOIN_MITER }, + { "LINE_JOIN_ROUND", CAIRO_LINE_JOIN_ROUND }, + { "LINE_JOIN_BEVEL", CAIRO_LINE_JOIN_BEVEL }, + + { "EXTEND_NONE", CAIRO_EXTEND_NONE }, + { "EXTEND_REPEAT", CAIRO_EXTEND_REPEAT }, + { "EXTEND_REFLECT", CAIRO_EXTEND_REFLECT }, + { "EXTEND_PAD", CAIRO_EXTEND_PAD }, + + { "FILTER_FAST", CAIRO_FILTER_FAST }, + { "FILTER_GOOD", CAIRO_FILTER_GOOD }, + { "FILTER_BEST", CAIRO_FILTER_BEST }, + { "FILTER_BILINEAR", CAIRO_FILTER_BILINEAR }, + { "FILTER_NEAREST", CAIRO_FILTER_NEAREST }, + { "FILTER_GAUSSIAN", CAIRO_FILTER_GAUSSIAN }, + + { "SLANT_NORMAL", CAIRO_FONT_SLANT_NORMAL }, + { "SLANT_ITALIC", CAIRO_FONT_SLANT_ITALIC }, + { "SLANT_OBLIQUE", CAIRO_FONT_SLANT_OBLIQUE }, + + { "WEIGHT_NORMAL", CAIRO_FONT_WEIGHT_NORMAL }, + { "WEIGHT_BOLD", CAIRO_FONT_WEIGHT_BOLD }, + + { "SUBPIXEL_ORDER_DEFAULT", CAIRO_SUBPIXEL_ORDER_DEFAULT }, + { "SUBPIXEL_ORDER_RGB", CAIRO_SUBPIXEL_ORDER_RGB }, + { "SUBPIXEL_ORDER_BGR", CAIRO_SUBPIXEL_ORDER_BGR }, + { "SUBPIXEL_ORDER_VRGB", CAIRO_SUBPIXEL_ORDER_VRGB }, + { "SUBPIXEL_ORDER_VBGR", CAIRO_SUBPIXEL_ORDER_VBGR }, + + { "HINT_STYLE_DEFAULT", CAIRO_HINT_STYLE_DEFAULT }, + { "HINT_STYLE_NONE", CAIRO_HINT_STYLE_NONE }, + { "HINT_STYLE_SLIGHT", CAIRO_HINT_STYLE_SLIGHT }, + { "HINT_STYLE_MEDIUM", CAIRO_HINT_STYLE_MEDIUM }, + { "HINT_STYLE_FULL", CAIRO_HINT_STYLE_FULL }, + + { "HINT_METRICS_DEFAULT", CAIRO_HINT_METRICS_DEFAULT }, + { "HINT_METRICS_OFF", CAIRO_HINT_METRICS_OFF }, + { "HINT_METRICS_ON", CAIRO_HINT_METRICS_ON }, + + { "FORWARD", 0 }, + { "BACKWARD", 1 }, + + { "COLOR", CAIRO_CONTENT_COLOR }, + { "ALPHA", CAIRO_CONTENT_ALPHA }, + { "COLOR_ALPHA", CAIRO_CONTENT_COLOR_ALPHA }, + + { "A1", CAIRO_FORMAT_A1 }, + { "A8", CAIRO_FORMAT_A8 }, + { "RGB16_565", CAIRO_FORMAT_RGB16_565 }, + { "RGB24", CAIRO_FORMAT_RGB24 }, + { "ARGB32", CAIRO_FORMAT_ARGB32 }, + { "RGB30", CAIRO_FORMAT_RGB30 }, + { "RGB96F", CAIRO_FORMAT_RGB96F }, + { "RGBA128F", CAIRO_FORMAT_RGBA128F }, + { "INVALID", CAIRO_FORMAT_INVALID }, + + { NULL, 0 } +}; + + +const csi_integer_constant_def_t * +_csi_integer_constants (void) +{ + return _integer_constants; +} + +static const csi_real_constant_def_t +_real_constants[] = { + { "math.pi", M_PI }, + { "math.2pi", 2 * M_PI }, + { "math.sqrt2", M_SQRT2 }, + { "math.ln2", M_LN2 }, + + { NULL, 0 } +}; + +const csi_real_constant_def_t * +_csi_real_constants (void) +{ + return _real_constants; +} diff --git a/local/recipes/libs/cairo/source/util/cairo-script/cairo-script-private.h b/local/recipes/libs/cairo/source/util/cairo-script/cairo-script-private.h new file mode 100644 index 0000000000..96f9248d55 --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-script/cairo-script-private.h @@ -0,0 +1,966 @@ +/* + * Copyright © 2008 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Chris Wilson. + * + * Contributor(s): + * Chris Wilson + */ + +#ifndef CAIRO_SCRIPT_PRIVATE_H +#define CAIRO_SCRIPT_PRIVATE_H + +#include "config.h" + +#include "cairo-script-interpreter.h" + +#include +#include + +#ifdef _MSC_VER +#undef inline +#define inline __inline +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE (!FALSE) +#endif + +#ifndef NULL +#define NULL (void *) 0 +#endif + +#if HAVE_STDINT_H +# include +#elif HAVE_INTTYPES_H +# include +#elif HAVE_SYS_INT_TYPES_H +# include +#elif defined(_MSC_VER) + typedef __int8 int8_t; + typedef unsigned __int8 uint8_t; + typedef __int16 int16_t; + typedef unsigned __int16 uint16_t; + typedef __int32 int32_t; + typedef unsigned __int32 uint32_t; + typedef __int64 int64_t; + typedef unsigned __int64 uint64_t; +# ifndef HAVE_UINT64_T +# define HAVE_UINT64_T 1 +# endif +#else +#error Cannot find definitions for fixed-width integral types (uint8_t, uint32_t, etc.) +#endif + +#if HAVE_BYTESWAP_H +# include +#endif +#ifndef bswap_16 +# define bswap_16(p) \ + (((((uint16_t)(p)) & 0x00ff) << 8) | \ + (((uint16_t)(p)) >> 8)) +#endif +#ifndef bswap_32 +# define bswap_32(p) \ + (((((uint32_t)(p)) & 0x000000ff) << 24) | \ + ((((uint32_t)(p)) & 0x0000ff00) << 8) | \ + ((((uint32_t)(p)) & 0x00ff0000) >> 8) | \ + ((((uint32_t)(p))) >> 24)) +#endif + + +#if __GNUC__ >= 3 +#define csi_pure __attribute__((pure)) +#define csi_const __attribute__((const)) +#else +#define csi_pure +#define csi_const +#endif + +#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__) +#define _CSI_BOOLEAN_EXPR(expr) \ + __extension__ ({ \ + int _csi_boolean_var_; \ + if (expr) \ + _csi_boolean_var_ = 1; \ + else \ + _csi_boolean_var_ = 0; \ + _csi_boolean_var_; \ +}) +#define _csi_likely(expr) (__builtin_expect (_CSI_BOOLEAN_EXPR(expr), 1)) +#define _csi_unlikely(expr) (__builtin_expect (_CSI_BOOLEAN_EXPR(expr), 0)) +#else +#define _csi_likely(expr) (expr) +#define _csi_unlikely(expr) (expr) +#endif + +#ifdef __GNUC__ +#define csi_container_of(ptr, type, member) ({ \ + const typeof(((type *) 0)->member) *mptr__ = (ptr); \ + (type *) ((char *) mptr__ - offsetof (type, member)); \ +}) +#else +#define csi_container_of(ptr, type, member) \ + (type *)((char *) (ptr) - (char *) &((type *)0)->member) +#endif + +#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__) && !defined(__sun) +#define csi_private_no_warn __attribute__((__visibility__("hidden"))) +#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550) +#define csi_private_no_warn __hidden +#else /* not gcc >= 3.3 and not Sun Studio >= 8 */ +#define csi_private_no_warn +#endif + +#undef ARRAY_LENGTH +#define ARRAY_LENGTH(__array) ((int) (sizeof (__array) / sizeof (__array[0]))) + +#ifndef WARN_UNUSED_RESULT +#define WARN_UNUSED_RESULT +#endif +/* Add attribute(warn_unused_result) if supported */ +#define csi_warn WARN_UNUSED_RESULT +#define csi_private csi_private_no_warn csi_warn + +#define CSI_BITSWAP8(c) ((((c) * 0x0802LU & 0x22110LU) | ((c) * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16) +#ifdef WORDS_BIGENDIAN +#define CSI_BITSWAP8_IF_LITTLE_ENDIAN(c) (c) +#else +#define CSI_BITSWAP8_IF_LITTLE_ENDIAN(c) CSI_BITSWAP8(c) +#endif + +typedef enum _csi_status { + CSI_STATUS_SUCCESS = CAIRO_STATUS_SUCCESS, + CSI_STATUS_NO_MEMORY = CAIRO_STATUS_NO_MEMORY, + CSI_STATUS_INVALID_RESTORE = CAIRO_STATUS_INVALID_RESTORE, + CSI_STATUS_INVALID_POP_GROUP = CAIRO_STATUS_INVALID_POP_GROUP, + CSI_STATUS_NO_CURRENT_POINT = CAIRO_STATUS_NO_CURRENT_POINT, + CSI_STATUS_INVALID_MATRIX = CAIRO_STATUS_INVALID_MATRIX, + CSI_STATUS_INVALID_STATUS = CAIRO_STATUS_INVALID_STATUS, + CSI_STATUS_NULL_POINTER = CAIRO_STATUS_NULL_POINTER, + CSI_STATUS_INVALID_STRING = CAIRO_STATUS_INVALID_STRING, + CSI_STATUS_INVALID_PATH_DATA = CAIRO_STATUS_INVALID_PATH_DATA, + CSI_STATUS_READ_ERROR = CAIRO_STATUS_READ_ERROR, + CSI_STATUS_WRITE_ERROR = CAIRO_STATUS_WRITE_ERROR, + CSI_STATUS_SURFACE_FINISHED = CAIRO_STATUS_SURFACE_FINISHED, + CSI_STATUS_SURFACE_TYPE_MISMATCH = CAIRO_STATUS_SURFACE_TYPE_MISMATCH, + CSI_STATUS_PATTERN_TYPE_MISMATCH = CAIRO_STATUS_PATTERN_TYPE_MISMATCH, + CSI_STATUS_INVALID_CONTENT = CAIRO_STATUS_INVALID_CONTENT, + CSI_STATUS_INVALID_FORMAT = CAIRO_STATUS_INVALID_FORMAT, + CSI_STATUS_INVALID_VISUAL = CAIRO_STATUS_INVALID_VISUAL, + CSI_STATUS_FILE_NOT_FOUND = CAIRO_STATUS_FILE_NOT_FOUND, + CSI_STATUS_INVALID_DASH = CAIRO_STATUS_INVALID_DASH, + CSI_STATUS_INVALID_DSC_COMMENT = CAIRO_STATUS_INVALID_DSC_COMMENT, + CSI_STATUS_INVALID_INDEX = CAIRO_STATUS_INVALID_INDEX, + CSI_STATUS_CLIP_NOT_REPRESENTABLE = CAIRO_STATUS_CLIP_NOT_REPRESENTABLE, + CSI_STATUS_TEMP_FILE_ERROR = CAIRO_STATUS_TEMP_FILE_ERROR, + CSI_STATUS_INVALID_STRIDE = CAIRO_STATUS_INVALID_STRIDE, + CSI_STATUS_FONT_TYPE_MISMATCH = CAIRO_STATUS_FONT_TYPE_MISMATCH, + CSI_STATUS_USER_FONT_IMMUTABLE = CAIRO_STATUS_USER_FONT_IMMUTABLE, + CSI_STATUS_USER_FONT_ERROR = CAIRO_STATUS_USER_FONT_ERROR, + CSI_STATUS_NEGATIVE_COUNT = CAIRO_STATUS_NEGATIVE_COUNT, + CSI_STATUS_INVALID_CLUSTERS = CAIRO_STATUS_INVALID_CLUSTERS, + CSI_STATUS_INVALID_SLANT = CAIRO_STATUS_INVALID_SLANT, + CSI_STATUS_INVALID_WEIGHT = CAIRO_STATUS_INVALID_WEIGHT, + CSI_STATUS_INVALID_SIZE = CAIRO_STATUS_INVALID_SIZE, + CSI_STATUS_USER_FONT_NOT_IMPLEMENTED = CAIRO_STATUS_USER_FONT_NOT_IMPLEMENTED, + CSI_STATUS_DEVICE_TYPE_MISMATCH = CAIRO_STATUS_DEVICE_TYPE_MISMATCH, + CSI_STATUS_DEVICE_ERROR = CAIRO_STATUS_DEVICE_ERROR, + CSI_STATUS_INVALID_MESH_CONSTRUCTION = CAIRO_STATUS_INVALID_MESH_CONSTRUCTION, + CSI_STATUS_DEVICE_FINISHED = CAIRO_STATUS_DEVICE_FINISHED, + CSI_STATUS_JBIG2_GLOBAL_MISSING = CAIRO_STATUS_JBIG2_GLOBAL_MISSING, + CSI_STATUS_PNG_ERROR = CAIRO_STATUS_PNG_ERROR, + CSI_STATUS_FREETYPE_ERROR = CAIRO_STATUS_FREETYPE_ERROR, + CSI_STATUS_WIN32_GDI_ERROR = CAIRO_STATUS_WIN32_GDI_ERROR, + + /* cairo-script-interpreter specific errors */ + + CSI_STATUS_INVALID_SCRIPT, + CSI_STATUS_SCRIPT_INVALID_TYPE, + CSI_STATUS_SCRIPT_INVALID_INDEX, + CSI_STATUS_SCRIPT_UNDEFINED_NAME, + CSI_STATUS_INTERPRETER_FINISHED, + + _CSI_STATUS_SCRIPT_LAST_ERROR, + CSI_INT_STATUS_UNSUPPORTED +} csi_status_t; + +typedef enum { + CSI_OBJECT_TYPE_NULL = 0, + + /* atomics */ + CSI_OBJECT_TYPE_BOOLEAN, + CSI_OBJECT_TYPE_INTEGER, + CSI_OBJECT_TYPE_MARK, + CSI_OBJECT_TYPE_NAME, + CSI_OBJECT_TYPE_OPERATOR, + CSI_OBJECT_TYPE_REAL, + + /* compound */ + CSI_OBJECT_TYPE_ARRAY = 0x8, + CSI_OBJECT_TYPE_DICTIONARY, + CSI_OBJECT_TYPE_FILE, + CSI_OBJECT_TYPE_MATRIX, + CSI_OBJECT_TYPE_STRING, + + /* cairo */ + CSI_OBJECT_TYPE_CONTEXT = 0x10, + CSI_OBJECT_TYPE_FONT, + CSI_OBJECT_TYPE_PATTERN, + CSI_OBJECT_TYPE_SCALED_FONT, + CSI_OBJECT_TYPE_SURFACE +} csi_object_type_t; + +#define CSI_OBJECT_IS_ATOM(OBJ) (((OBJ)->type & CSI_OBJECT_TYPE_MASK) < 0x08) +#define CSI_OBJECT_IS_COMPOUND(OBJ) ((OBJ)->type & 0x08) +#define CSI_OBJECT_IS_CAIRO(OBJ) ((OBJ)->type & 0x10) + +enum { /* attributes */ + CSI_OBJECT_ATTR_EXECUTABLE = 1 << 6, + CSI_OBJECT_ATTR_WRITABLE = 1 << 7 +}; +#define CSI_OBJECT_ATTR_MASK (CSI_OBJECT_ATTR_EXECUTABLE | \ + CSI_OBJECT_ATTR_WRITABLE) +#define CSI_OBJECT_TYPE_MASK (~CSI_OBJECT_ATTR_MASK) + +typedef struct _cairo_script_interpreter csi_t; + +typedef cairo_bool_t csi_boolean_t; +typedef csi_status_t (*csi_operator_t) (csi_t *); +typedef float csi_real_t; +typedef long csi_integer_t; +typedef intptr_t csi_name_t; +typedef struct _csi_array csi_array_t; +typedef struct _csi_buffer csi_buffer_t; +typedef struct _csi_compound_object csi_compound_object_t; +typedef struct _csi_dictionary csi_dictionary_t; +typedef struct _csi_file csi_file_t; +typedef struct _csi_hash_entry csi_hash_entry_t; +typedef struct _csi_hash_table csi_hash_table_t; +typedef struct _csi_hash_table_arrangement csi_hash_table_arrangement_t; +typedef struct _csi_list csi_list_t; +typedef struct _csi_matrix csi_matrix_t; +typedef struct _csi_object csi_object_t; +typedef struct _csi_scanner csi_scanner_t; +typedef struct _csi_stack csi_stack_t; +typedef struct _csi_string csi_string_t; + +typedef cairo_bool_t +(*csi_hash_predicate_func_t) (void *entry); + +typedef void +(*csi_hash_callback_func_t) (void *entry, + void *closure); + +typedef cairo_bool_t +(*csi_hash_keys_equal_func_t) (const void *key_a, const void *key_b); + +struct _csi_object { + csi_object_type_t type; + union { + cairo_t *cr; + cairo_font_face_t *font_face; + cairo_pattern_t *pattern; + cairo_scaled_font_t *scaled_font; + cairo_surface_t *surface; + csi_array_t *array; + csi_boolean_t boolean; + csi_compound_object_t *object; + csi_dictionary_t *dictionary; + csi_file_t *file; + csi_integer_t integer; + csi_matrix_t *matrix; + csi_operator_t op; + csi_name_t name; + csi_real_t real; + csi_string_t *string; + void *ptr; + } datum; +}; + +struct _csi_compound_object { + csi_object_type_t type; + unsigned int ref; +}; + +struct _csi_hash_entry { + unsigned long hash; +}; + +struct _csi_hash_table_arrangement { + unsigned long high_water_mark; + unsigned long size; + unsigned long rehash; +}; + +struct _csi_hash_table { + csi_hash_keys_equal_func_t keys_equal; + + const csi_hash_table_arrangement_t *arrangement; + csi_hash_entry_t **entries; + + unsigned long live_entries; + unsigned long used_entries; + unsigned long iterating; /* Iterating, no insert, no resize */ +}; + + +/* simple, embedded doubly-linked links */ +struct _csi_list { + struct _csi_list *next, *prev; +}; + +struct _csi_buffer { + char *base, *ptr, *end; + unsigned int size; +}; + +struct _csi_stack { + csi_object_t *objects; + csi_integer_t len; + csi_integer_t size; +}; + +struct _csi_array { + csi_compound_object_t base; + csi_stack_t stack; +}; + +typedef struct _csi_dictionary_entry { + csi_hash_entry_t hash_entry; + csi_object_t value; +} csi_dictionary_entry_t; + +struct _csi_dictionary { + csi_compound_object_t base; + csi_hash_table_t hash_table; +}; + +struct _csi_matrix { + csi_compound_object_t base; + cairo_matrix_t matrix; +}; + +struct _csi_string { + csi_compound_object_t base; + csi_integer_t len; + csi_integer_t deflate; + enum { + NONE, + ZLIB, + LZO, + } method; + char *string; +}; + +typedef struct _csi_filter_funcs { + int (*filter_getc) (csi_file_t *); + void (*filter_putc) (csi_file_t *, int); + int (*filter_read) (csi_file_t *, uint8_t *, int); + void (*filter_destroy) (csi_t *, void *); +} csi_filter_funcs_t; + +struct _csi_file { + csi_compound_object_t base; + enum { + STDIO, + BYTES, + PROCEDURE, + FILTER + } type; + unsigned int flags; + void *src; + void *data; + uint8_t *bp; + int rem; + const csi_filter_funcs_t *filter; +}; + +union _csi_union_object { + void *ptr[2]; + csi_stack_t stack; + csi_array_t arry; + csi_dictionary_t dictionary; + csi_matrix_t matrix; + csi_string_t string; + csi_file_t file; + csi_object_t object; +}; + +struct _csi_scanner { + jmp_buf jump_buffer; + int depth; + + int bind; + csi_status_t (*push) (csi_t *ctx, csi_object_t *obj); + csi_status_t (*execute) (csi_t *ctx, csi_object_t *obj); + void *closure; + + csi_buffer_t buffer; + csi_stack_t procedure_stack; + csi_object_t build_procedure; + + unsigned int accumulator; + unsigned int accumulator_count; + + unsigned int line_number; +}; + +typedef cairo_script_interpreter_hooks_t csi_hooks_t; + +typedef struct _csi_chunk { + struct _csi_chunk *next; + int rem; + char *ptr; +} csi_chunk_t; + +struct _cairo_script_interpreter { + int ref_count; + csi_status_t status; + + unsigned int finished : 1; + + csi_hooks_t hooks; + + csi_hash_table_t strings; + + csi_stack_t ostack; + csi_stack_t dstack; + + csi_scanner_t scanner; + + csi_chunk_t *perm_chunk; + struct { + csi_chunk_t *chunk; + void *free_list; + } slabs[16]; + csi_array_t *free_array; + csi_dictionary_t *free_dictionary; + csi_string_t *free_string; + + csi_operator_t opcode[256]; + + /* caches of live data */ + csi_list_t *_images; + csi_list_t *_faces; +}; + +typedef struct _csi_operator_def { + const char *name; + csi_operator_t op; +} csi_operator_def_t; + +typedef struct _csi_integer_constant_def { + const char *name; + csi_integer_t value; +} csi_integer_constant_def_t; + +typedef struct _csi_real_constant_def { + const char *name; + csi_real_t value; +} csi_real_constant_def_t; + +/* cairo-script-file.c */ + +csi_private csi_status_t +csi_file_new (csi_t *ctx, + csi_object_t *obj, + const char *path, const char *mode); + +csi_private csi_status_t +csi_file_new_for_stream (csi_t *ctx, + csi_object_t *obj, + FILE *stream); + +csi_private csi_status_t +csi_file_new_for_bytes (csi_t *ctx, + csi_object_t *obj, + const char *bytes, + unsigned int length); + +csi_private csi_status_t +csi_file_new_from_string (csi_t *ctx, + csi_object_t *obj, + csi_string_t *src); + +csi_private csi_status_t +csi_file_new_ascii85_decode (csi_t *ctx, + csi_object_t *obj, + csi_dictionary_t *dict, + csi_object_t *src); + +csi_private csi_status_t +csi_file_new_deflate_decode (csi_t *ctx, + csi_object_t *obj, + csi_dictionary_t *dict, + csi_object_t *src); + +csi_private csi_status_t +_csi_file_execute (csi_t *ctx, csi_file_t *obj); + +csi_private int +csi_file_getc (csi_file_t *obj); + +csi_private int +csi_file_read (csi_file_t *obj, void *buf, int len); + +csi_private void +csi_file_putc (csi_file_t *obj, int c); + +csi_private void +csi_file_flush (csi_file_t *obj); + +csi_private void +csi_file_close (csi_t *ctx, csi_file_t *obj); + +csi_private void +_csi_file_free (csi_t *ctx, csi_file_t *obj); + +csi_private csi_status_t +_csi_file_as_string (csi_t *ctx, + csi_file_t *file, + csi_object_t *obj); + +/* cairo-script-hash.c */ + +csi_private csi_status_t +_csi_hash_table_init (csi_hash_table_t *hash_table, + csi_hash_keys_equal_func_t keys_equal); + +csi_private void +_csi_hash_table_fini (csi_hash_table_t *hash_table); + +csi_private void * +_csi_hash_table_lookup (csi_hash_table_t *hash_table, + csi_hash_entry_t *key); + +csi_private csi_status_t +_csi_hash_table_insert (csi_hash_table_t *hash_table, + csi_hash_entry_t *entry); + +csi_private void +_csi_hash_table_remove (csi_hash_table_t *hash_table, + csi_hash_entry_t *key); + +csi_private void +_csi_hash_table_foreach (csi_hash_table_t *hash_table, + csi_hash_callback_func_t hash_callback, + void *closure); + +/* cairo-script-interpreter.c */ + +csi_private void * +_csi_alloc (csi_t *ctx, int size); + +csi_private void * +_csi_alloc0 (csi_t *ctx, int size); + +csi_private void * +_csi_realloc (csi_t *ctx, void *ptr, int size); + +csi_private void +_csi_free (csi_t *ctx, void *ptr); + +csi_private void * +_csi_slab_alloc (csi_t *ctx, int size); + +csi_private void * +_csi_perm_alloc (csi_t *ctx, int size); + +csi_private void +_csi_slab_free (csi_t *ctx, void *ptr, int size); + +csi_private csi_status_t +csi_push_ostack (csi_t *ctx, csi_object_t *obj); + +csi_private csi_status_t +_csi_name_define (csi_t *ctx, csi_name_t name, csi_object_t *obj); + +csi_private csi_status_t +_csi_name_lookup (csi_t *ctx, csi_name_t name, csi_object_t *obj); + +csi_private csi_status_t +_csi_name_undefine (csi_t *ctx, csi_name_t name); + +csi_private csi_status_t +_csi_intern_string (csi_t *ctx, const char **str_inout, int len); + +csi_private csi_status_t +_csi_error (csi_status_t status); + +/* cairo-script-objects.c */ + +csi_private csi_status_t +csi_array_new (csi_t *ctx, + csi_integer_t initial_size, + csi_object_t *obj); + +csi_private csi_status_t +_csi_array_execute (csi_t *ctx, csi_array_t *array); + +csi_private csi_status_t +csi_array_get (csi_t *ctx, + csi_array_t *array, + long elem, + csi_object_t *value); + +csi_private csi_status_t +csi_array_put (csi_t *ctx, + csi_array_t *array, + csi_integer_t elem, + csi_object_t *value); + +csi_private csi_status_t +csi_array_append (csi_t *ctx, + csi_array_t *array, + csi_object_t *obj); + +csi_private void +csi_array_free (csi_t *ctx, csi_array_t *array); + +static inline void +csi_boolean_new (csi_object_t *obj, + csi_boolean_t v) +{ + obj->type = CSI_OBJECT_TYPE_BOOLEAN; + obj->datum.boolean = v; +} + +csi_private csi_status_t +csi_dictionary_new (csi_t *ctx, + csi_object_t *obj); + +csi_private csi_status_t +csi_dictionary_put (csi_t *ctx, + csi_dictionary_t *dict, + csi_name_t name, + csi_object_t *value); + +csi_private csi_status_t +csi_dictionary_get (csi_t *ctx, + csi_dictionary_t *dict, + csi_name_t name, + csi_object_t *value); + +csi_private csi_boolean_t +csi_dictionary_has (csi_dictionary_t *dict, + csi_name_t name); + +csi_private void +csi_dictionary_remove (csi_t *ctx, + csi_dictionary_t *dict, + csi_name_t name); + +csi_private void +csi_dictionary_free (csi_t *ctx, + csi_dictionary_t *dict); + +static inline void +csi_integer_new (csi_object_t *obj, + csi_integer_t v) +{ + obj->type = CSI_OBJECT_TYPE_INTEGER; + obj->datum.integer = v; +} + + +csi_private csi_status_t +csi_matrix_new (csi_t *ctx, + csi_object_t *obj); + +csi_private csi_status_t +csi_matrix_new_from_array (csi_t *ctx, + csi_object_t *obj, + csi_array_t *array); + +csi_private csi_status_t +csi_matrix_new_from_matrix (csi_t *ctx, + csi_object_t *obj, + const cairo_matrix_t *m); + +csi_private csi_status_t +csi_matrix_new_from_values (csi_t *ctx, + csi_object_t *obj, + double v[6]); + +csi_private void +csi_matrix_free (csi_t *ctx, + csi_matrix_t *obj); + +csi_private csi_status_t +csi_name_new (csi_t *ctx, + csi_object_t *obj, + const char *str, + int len); + +csi_private csi_status_t +csi_name_new_static (csi_t *ctx, + csi_object_t *obj, + const char *str); + +static inline void +csi_operator_new (csi_object_t *obj, + csi_operator_t op) +{ + obj->type = CSI_OBJECT_TYPE_OPERATOR | CSI_OBJECT_ATTR_EXECUTABLE; + obj->datum.op = op; +} + +static inline void +csi_real_new (csi_object_t *obj, + csi_real_t v) +{ + obj->type = CSI_OBJECT_TYPE_REAL; + obj->datum.real = v; +} + +csi_private csi_status_t +csi_string_new (csi_t *ctx, + csi_object_t *obj, + const char *str, + int len); + +csi_private csi_status_t +csi_string_deflate_new (csi_t *ctx, + csi_object_t *obj, + void *bytes, + int in_len, + int out_len); + +csi_private csi_status_t +csi_string_new_from_bytes (csi_t *ctx, + csi_object_t *obj, + char *bytes, + unsigned int len); + +csi_private void +csi_string_free (csi_t *ctx, csi_string_t *string); + +csi_private csi_status_t +csi_object_execute (csi_t *ctx, csi_object_t *obj); + +csi_private csi_object_t * +csi_object_reference (csi_object_t *obj); + +csi_private void +csi_object_free (csi_t *ctx, + csi_object_t *obj); + +csi_private csi_status_t +csi_object_as_file (csi_t *ctx, + csi_object_t *src, + csi_object_t *file); + +csi_private csi_boolean_t +csi_object_eq (csi_object_t *a, + csi_object_t *b); + +csi_private csi_status_t +csi_object_compare (csi_object_t *a, + csi_object_t *b, + int *out_cmp); + +/* cairo-script-operators.c */ + +csi_private const csi_operator_def_t * +_csi_operators (void); + +csi_private const csi_integer_constant_def_t * +_csi_integer_constants (void); + +csi_private const csi_real_constant_def_t * +_csi_real_constants (void); + +/* cairo-script-scanner.c */ + +csi_private csi_status_t +_csi_scanner_init (csi_t *ctx, csi_scanner_t *scanner); + +csi_private csi_status_t +_csi_scan_file (csi_t *ctx, csi_file_t *src); + +csi_private csi_status_t +_csi_translate_file (csi_t *ctx, + csi_file_t *file, + cairo_write_func_t write_func, + void *closure); + +csi_private void +_csi_scanner_fini (csi_t *ctx, csi_scanner_t *scanner); + +csi_private csi_boolean_t +_csi_parse_number (csi_object_t *obj, const char *s, int len); + +/* cairo-script-stack.c */ + +csi_private csi_status_t +_csi_stack_init (csi_t *ctx, csi_stack_t *stack, csi_integer_t size); + +csi_private void +_csi_stack_fini (csi_t *ctx, csi_stack_t *stack); + +csi_private csi_status_t +_csi_stack_roll (csi_t *ctx, + csi_stack_t *stack, + csi_integer_t mod, + csi_integer_t n); + +csi_private csi_status_t +_csi_stack_grow (csi_t *ctx, csi_stack_t *stack, csi_integer_t cnt); + +csi_private csi_status_t +_csi_stack_push_internal (csi_t *ctx, csi_stack_t *stack, + const csi_object_t *obj); + +csi_private csi_object_t * +_csi_stack_peek (csi_stack_t *stack, csi_integer_t i); + +csi_private void +_csi_stack_pop (csi_t *ctx, csi_stack_t *stack, csi_integer_t count); + +csi_private csi_status_t +_csi_stack_exch (csi_stack_t *stack); + +static inline csi_object_type_t +csi_object_get_type (const csi_object_t *obj) +{ + return obj->type & CSI_OBJECT_TYPE_MASK; +} + +static inline csi_boolean_t +csi_object_is_procedure (const csi_object_t *obj) +{ + return obj->type == (CSI_OBJECT_TYPE_ARRAY | CSI_OBJECT_ATTR_EXECUTABLE); +} + +static inline csi_boolean_t +csi_object_is_number (const csi_object_t *obj) +{ + int type = csi_object_get_type (obj); + switch (type) { + case CSI_OBJECT_TYPE_BOOLEAN: + case CSI_OBJECT_TYPE_INTEGER: + case CSI_OBJECT_TYPE_REAL: + return 1; + default: + return 0; + } +} + +static inline double +csi_number_get_value (const csi_object_t *obj) +{ + int type = csi_object_get_type (obj); + switch (type) { + case CSI_OBJECT_TYPE_BOOLEAN: return obj->datum.boolean; + case CSI_OBJECT_TYPE_INTEGER: return obj->datum.integer; + case CSI_OBJECT_TYPE_REAL: return obj->datum.real; + default: return 0.; + } +} + +csi_private csi_status_t +_csi_stack_push (csi_t *ctx, csi_stack_t *stack, + const csi_object_t *obj); + +static inline csi_boolean_t +_csi_check_ostack (csi_t *ctx, csi_integer_t count) +{ + return ctx->ostack.len >= count; +} + +static inline csi_object_t * +_csi_peek_ostack (csi_t *ctx, csi_integer_t i) +{ + return &ctx->ostack.objects[ctx->ostack.len - i -1]; +} + +static inline void +_csi_pop_ostack (csi_t *ctx, csi_integer_t count) +{ + do + csi_object_free (ctx, &ctx->ostack.objects[--ctx->ostack.len]); + while (--count); +} + +static inline csi_status_t +_csi_push_ostack_copy (csi_t *ctx, csi_object_t *obj) +{ + return _csi_stack_push (ctx, &ctx->ostack, csi_object_reference (obj)); +} + +static inline csi_status_t +_csi_push_ostack (csi_t *ctx, csi_object_t *obj) +{ + return _csi_stack_push (ctx, &ctx->ostack, obj); +} + +static inline csi_status_t +_csi_push_ostack_boolean (csi_t *ctx, csi_boolean_t v) +{ + csi_object_t obj; + obj.type = CSI_OBJECT_TYPE_BOOLEAN; + obj.datum.boolean = v; + return _csi_stack_push (ctx, &ctx->ostack, &obj); +} +static inline csi_status_t +_csi_push_ostack_integer (csi_t *ctx, csi_integer_t v) +{ + csi_object_t obj; + obj.type = CSI_OBJECT_TYPE_INTEGER; + obj.datum.integer = v; + return _csi_stack_push (ctx, &ctx->ostack, &obj); +} +static inline csi_status_t +_csi_push_ostack_mark (csi_t *ctx) +{ + csi_object_t obj; + obj.type = CSI_OBJECT_TYPE_MARK; + return _csi_stack_push (ctx, &ctx->ostack, &obj); +} +static inline csi_status_t +_csi_push_ostack_null (csi_t *ctx) +{ + csi_object_t obj; + obj.type = CSI_OBJECT_TYPE_NULL; + return _csi_stack_push (ctx, &ctx->ostack, &obj); +} +static inline csi_status_t +_csi_push_ostack_real (csi_t *ctx, csi_real_t v) +{ + csi_object_t obj; + obj.type = CSI_OBJECT_TYPE_REAL; + obj.datum.real = v; + return _csi_stack_push (ctx, &ctx->ostack, &obj); +} + +#endif /* CAIRO_SCRIPT_PRIVATE_H */ diff --git a/local/recipes/libs/cairo/source/util/cairo-script/cairo-script-scanner.c b/local/recipes/libs/cairo/source/util/cairo-script/cairo-script-scanner.c new file mode 100644 index 0000000000..167cd7a1e6 --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-script/cairo-script-scanner.c @@ -0,0 +1,1905 @@ +/* + * Copyright © 2008 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Chris Wilson. + * + * Contributor(s): + * Chris Wilson + */ + +#include "config.h" + +#include "cairo-script-private.h" + +#include /* INT_MAX */ +#include /* pow */ +#include /* EOF */ +#include /* for {INT,UINT}*_{MIN,MAX} */ +#include /* malloc/free */ +#include /* memset */ +#include +#include + +#if HAVE_LZO +#include +#endif + +#define DEBUG_SCAN 0 + +#if WORDS_BIGENDIAN +#define le16(x) bswap_16 (x) +#define le32(x) bswap_32 (x) +#define be16(x) x +#define be32(x) x +#define to_be32(x) x +#else +#define le16(x) x +#define le32(x) x +#define be16(x) bswap_16 (x) +#define be32(x) bswap_32 (x) +#define to_be32(x) bswap_32 (x) +#endif + +/* + * whitespace: + * 0 - nul + * 9 - tab + * A - LF + * C - FF + * D - CR + * + * syntax delimiters + * ( = 28, ) = 29 - literal strings + * < = 3C, > = 3E - hex/base85 strings, dictionary name + * [ = 5B, ] = 5D - array + * { = 7B, } = 7C - procedure + * / = 5C - literal marker + * % = 25 - comment + */ + +static void +fprintf_obj (FILE *stream, csi_t *ctx, const csi_object_t *obj) +{ + switch (csi_object_get_type (obj)) { + case CSI_OBJECT_TYPE_NULL: + fprintf (stream, "NULL\n"); + break; + + /* atomics */ + case CSI_OBJECT_TYPE_BOOLEAN: + fprintf (stream, "boolean: %s\n", + obj->datum.boolean ? "true" : "false"); + break; + case CSI_OBJECT_TYPE_INTEGER: + fprintf (stream, "integer: %ld\n", obj->datum.integer); + break; + case CSI_OBJECT_TYPE_MARK: + fprintf (stream, "mark\n"); + break; + case CSI_OBJECT_TYPE_NAME: + fprintf (stream, "name: %s\n", (char *) obj->datum.name); + break; + case CSI_OBJECT_TYPE_OPERATOR: + fprintf (stream, "operator: %p\n", obj->datum.ptr); + break; + case CSI_OBJECT_TYPE_REAL: + fprintf (stream, "real: %g\n", obj->datum.real); + break; + + /* compound */ + case CSI_OBJECT_TYPE_ARRAY: + fprintf (stream, "array\n"); + break; + case CSI_OBJECT_TYPE_DICTIONARY: + fprintf (stream, "dictionary\n"); + break; + case CSI_OBJECT_TYPE_FILE: + fprintf (stream, "file\n"); + break; + case CSI_OBJECT_TYPE_MATRIX: + fprintf (stream, "matrix: [%g %g %g %g %g %g]\n", + obj->datum.matrix->matrix.xx, + obj->datum.matrix->matrix.yx, + obj->datum.matrix->matrix.xy, + obj->datum.matrix->matrix.yy, + obj->datum.matrix->matrix.x0, + obj->datum.matrix->matrix.y0); + break; + case CSI_OBJECT_TYPE_STRING: + fprintf (stream, "string: len=%ld, defate=%ld, method=%d\n", + obj->datum.string->len, obj->datum.string->deflate, obj->datum.string->method); + break; + + /* cairo */ + case CSI_OBJECT_TYPE_CONTEXT: + fprintf (stream, "context\n"); + break; + case CSI_OBJECT_TYPE_FONT: + fprintf (stream, "font\n"); + break; + case CSI_OBJECT_TYPE_PATTERN: + fprintf (stream, "pattern\n"); + break; + case CSI_OBJECT_TYPE_SCALED_FONT: + fprintf (stream, "scaled-font\n"); + break; + case CSI_OBJECT_TYPE_SURFACE: + fprintf (stream, "surface\n"); + break; + } +} + +/* takes ownership of obj */ +static inline csi_status_t +scan_push (csi_t *ctx, csi_object_t *obj) +{ + return ctx->scanner.push (ctx, obj); +} + +static inline csi_status_t +scan_execute (csi_t *ctx, csi_object_t *obj) +{ + return ctx->scanner.execute (ctx, obj); +} + +static cairo_status_t +buffer_init (csi_t *ctx, csi_buffer_t *buffer) +{ + cairo_status_t status = CSI_STATUS_SUCCESS; + + buffer->size = 16384; + buffer->base = _csi_alloc (ctx, buffer->size); + if (_csi_unlikely (buffer->base == NULL)) { + status = _csi_error (CSI_STATUS_NO_MEMORY); + buffer->size = 0; + } + + buffer->ptr = buffer->base; + buffer->end = buffer->base + buffer->size; + + return status; +} + +static void +buffer_fini (csi_t *ctx, csi_buffer_t *buffer) +{ + _csi_free (ctx, buffer->base); +} + +static void +_buffer_grow (csi_t *ctx, csi_scanner_t *scan) +{ + int newsize; + int offset; + char *base; + + if (_csi_unlikely (scan->buffer.size > INT_MAX / 2)) + longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_NO_MEMORY)); + + offset = scan->buffer.ptr - scan->buffer.base; + newsize = scan->buffer.size * 2; + base = _csi_realloc (ctx, scan->buffer.base, newsize); + if (_csi_unlikely (base == NULL)) + longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_NO_MEMORY)); + + scan->buffer.base = base; + scan->buffer.ptr = base + offset; + scan->buffer.end = base + newsize; + scan->buffer.size = newsize; +} + +static inline void +buffer_check (csi_t *ctx, csi_scanner_t *scan, int count) +{ + if (_csi_unlikely (scan->buffer.ptr + count > scan->buffer.end)) + _buffer_grow (ctx, scan); +} + +static inline void +buffer_add (csi_buffer_t *buffer, int c) +{ + *buffer->ptr++ = c; +} + +static inline void +buffer_reset (csi_buffer_t *buffer) +{ + buffer->ptr = buffer->base; +} + +static void +token_start (csi_scanner_t *scan) +{ + buffer_reset (&scan->buffer); +} + +static void +token_add (csi_t *ctx, csi_scanner_t *scan, int c) +{ + buffer_check (ctx, scan, 1); + buffer_add (&scan->buffer, c); +} + +static void +token_add_unchecked (csi_scanner_t *scan, int c) +{ + buffer_add (&scan->buffer, c); +} + +csi_boolean_t +_csi_parse_number (csi_object_t *obj, const char *s, int len) +{ + int radix = 0; + long long mantissa = 0; + int exponent = 0; + int sign = 1; + int decimal = -1; + int exponent_sign = 0; + const char * const end = s + len; + + switch (*s) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + mantissa = *s - '0'; + case '+': + break; + case '-': + sign = -1; + break; + case '.': + decimal = 0; + break; + default: + return FALSE; + } + + while (++s < end) { + if (*s < '0') { + if (*s == '.') { + if (_csi_unlikely (radix)) + return FALSE; + if (_csi_unlikely (decimal != -1)) + return FALSE; + if (_csi_unlikely (exponent_sign)) + return FALSE; + + decimal = 0; + } else if (*s == '!') { + if (_csi_unlikely (radix)) + return FALSE; + if (_csi_unlikely (decimal != -1)) + return FALSE; + if (_csi_unlikely (exponent_sign)) + return FALSE; + + radix = mantissa; + mantissa = 0; + + if (_csi_unlikely (radix < 2 || radix > 36)) + return FALSE; + } else + return FALSE; + } else if (*s <= '9') { + int v = *s - '0'; + if (_csi_unlikely (radix && v >= radix)) + return FALSE; + + if (exponent_sign) { + exponent = 10 * exponent + v; + } else { + if (radix) + mantissa = radix * mantissa + v; + else + mantissa = 10 * mantissa + v; + if (decimal != -1) + decimal++; + } + } else if (*s == 'E' || * s== 'e') { + if (radix == 0) { + if (_csi_unlikely (s + 1 == end)) + return FALSE; + + exponent_sign = 1; + if (s[1] == '-') { + exponent_sign = -1; + s++; + } else if (s[1] == '+') + s++; + } else { + int v = 0xe; + + if (_csi_unlikely (v >= radix)) + return FALSE; + + mantissa = radix * mantissa + v; + } + } else if (*s < 'A') { + return FALSE; + } else if (*s <= 'Z') { + int v = *s - 'A' + 0xA; + + if (_csi_unlikely (v >= radix)) + return FALSE; + + mantissa = radix * mantissa + v; + } else if (*s < 'a') { + return FALSE; + } else if (*s <= 'z') { + int v = *s - 'a' + 0xa; + + if (_csi_unlikely (v >= radix)) + return FALSE; + + mantissa = radix * mantissa + v; + } else + return FALSE; + } + + if (exponent_sign || decimal != -1) { + if (mantissa == 0) { + obj->type = CSI_OBJECT_TYPE_REAL; + obj->datum.real = 0.; + return TRUE; + } else { + int e; + double v; + + v = mantissa; + e = exponent * exponent_sign; + if (decimal != -1) + e -= decimal; + switch (e) { + case -7: v *= 0.0000001; break; + case -6: v *= 0.000001; break; + case -5: v *= 0.00001; break; + case -4: v *= 0.0001; break; + case -3: v *= 0.001; break; + case -2: v *= 0.01; break; + case -1: v *= 0.1; break; + case 0: break; + case 1: v *= 10; break; + case 2: v *= 100; break; + case 3: v *= 1000; break; + case 4: v *= 10000; break; + case 5: v *= 100000; break; + case 6: v *= 1000000; break; + default: + v *= pow (10, e); /* XXX */ + break; + } + + obj->type = CSI_OBJECT_TYPE_REAL; + obj->datum.real = sign * v; + return TRUE; + } + } else { + obj->type = CSI_OBJECT_TYPE_INTEGER; + obj->datum.integer = sign * mantissa; + return TRUE; + } +} + +static void +token_end (csi_t *ctx, csi_scanner_t *scan, csi_file_t *src) +{ + cairo_status_t status; + char *s; + csi_object_t obj; + int len; + + /* + * Any token that consists entirely of regular characters and + * cannot be interpreted as a number is treated as a name object + * (more precisely, an executable name). All characters except + * delimiters and white-space characters can appear in names, + * including characters ordinarily considered to be punctuation. + */ + + if (_csi_unlikely (scan->buffer.ptr == scan->buffer.base)) + return; + + s = scan->buffer.base; + len = scan->buffer.ptr - scan->buffer.base; + + if (_csi_likely (! scan->bind)) { + if (s[0] == '{') { /* special case procedures */ + if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL) { + status = _csi_stack_push (ctx, + &scan->procedure_stack, + &scan->build_procedure); + if (_csi_unlikely (status)) + longjmp (scan->jump_buffer, status); + } + + status = csi_array_new (ctx, 0, &scan->build_procedure); + if (_csi_unlikely (status)) + longjmp (scan->jump_buffer, status); + + scan->build_procedure.type |= CSI_OBJECT_ATTR_EXECUTABLE; + return; + } else if (s[0] == '}') { + if (_csi_unlikely + (scan->build_procedure.type == CSI_OBJECT_TYPE_NULL)) + { + longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT)); + } + + if (scan->procedure_stack.len) { + csi_object_t *next; + + next = _csi_stack_peek (&scan->procedure_stack, 0); + status = csi_array_append (ctx, next->datum.array, + &scan->build_procedure); + scan->build_procedure = *next; + scan->procedure_stack.len--; + } else { + status = scan_push (ctx, &scan->build_procedure); + scan->build_procedure.type = CSI_OBJECT_TYPE_NULL; + } + if (_csi_unlikely (status)) + longjmp (scan->jump_buffer, status); + + return; + } + } + + if (s[0] == '/') { + if (len >= 2 && s[1] == '/') { /* substituted name */ + status = csi_name_new (ctx, &obj, s + 2, len - 2); + if (_csi_unlikely (status)) + longjmp (scan->jump_buffer, status); + + status = _csi_name_lookup (ctx, obj.datum.name, &obj); + } else { /* literal name */ + status = csi_name_new (ctx, &obj, s + 1, len - 1); + } + if (_csi_unlikely (status)) + longjmp (scan->jump_buffer, status); + } else { + if (! _csi_parse_number (&obj, s, len)) { + status = csi_name_new (ctx, &obj, s, len); + if (_csi_unlikely (status)) + longjmp (scan->jump_buffer, status); + + obj.type |= CSI_OBJECT_ATTR_EXECUTABLE; + } + } + + /* consume whitespace after token, before calling the interpreter */ + if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL) { + status = csi_array_append (ctx, + scan->build_procedure.datum.array, + &obj); + } else if (obj.type & CSI_OBJECT_ATTR_EXECUTABLE) { + status = scan_execute (ctx, &obj); + csi_object_free (ctx, &obj); + } else { + status = scan_push (ctx, &obj); + } + if (_csi_unlikely (status)) + longjmp (scan->jump_buffer, status); +} + +static void +string_add (csi_t *ctx, csi_scanner_t *scan, int c) +{ + buffer_check (ctx, scan, 1); + buffer_add (&scan->buffer, c); +} + +static void +string_end (csi_t *ctx, csi_scanner_t *scan) +{ + csi_object_t obj; + cairo_status_t status; + + status = csi_string_new (ctx, + &obj, + scan->buffer.base, + scan->buffer.ptr - scan->buffer.base); + if (_csi_unlikely (status)) + longjmp (scan->jump_buffer, status); + + if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL) + status = csi_array_append (ctx, + scan->build_procedure.datum.array, + &obj); + else + status = scan_push (ctx, &obj); + if (_csi_unlikely (status)) + longjmp (scan->jump_buffer, status); +} + +static int +hex_value (int c) +{ + if (c < '0') + return EOF; + if (c <= '9') + return c - '0'; + c |= 32; + if (c < 'a') + return EOF; + if (c <= 'f') + return c - 'a' + 0xa; + return EOF; +} + +static void +hex_add (csi_t *ctx, csi_scanner_t *scan, int c) +{ + if (scan->accumulator_count == 0) { + scan->accumulator |= hex_value (c) << 4; + scan->accumulator_count = 1; + } else { + scan->accumulator |= hex_value (c) << 0; + buffer_check (ctx, scan, 1); + buffer_add (&scan->buffer, scan->accumulator); + + scan->accumulator = 0; + scan->accumulator_count = 0; + } +} + +static void +hex_end (csi_t *ctx, csi_scanner_t *scan) +{ + csi_object_t obj; + cairo_status_t status; + + if (scan->accumulator_count) + hex_add (ctx, scan, '0'); + + status = csi_string_new (ctx, + &obj, + scan->buffer.base, + scan->buffer.ptr - scan->buffer.base); + if (_csi_unlikely (status)) + longjmp (scan->jump_buffer, status); + + if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL) + status = csi_array_append (ctx, + scan->build_procedure.datum.array, + &obj); + else + status = scan_push (ctx, &obj); + if (_csi_unlikely (status)) + longjmp (scan->jump_buffer, status); +} + +static void +base85_add (csi_t *ctx, csi_scanner_t *scan, int c) +{ + if (c == 'z') { + if (_csi_unlikely (scan->accumulator_count != 0)) + longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT)); + + buffer_check (ctx, scan, 4); + buffer_add (&scan->buffer, 0); + buffer_add (&scan->buffer, 0); + buffer_add (&scan->buffer, 0); + buffer_add (&scan->buffer, 0); + } else if (_csi_unlikely (c < '!' || c > 'u')) { + longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT)); + } else { + scan->accumulator = scan->accumulator*85 + c - '!'; + if (++scan->accumulator_count == 5) { + buffer_check (ctx, scan, 4); + buffer_add (&scan->buffer, (scan->accumulator >> 24) & 0xff); + buffer_add (&scan->buffer, (scan->accumulator >> 16) & 0xff); + buffer_add (&scan->buffer, (scan->accumulator >> 8) & 0xff); + buffer_add (&scan->buffer, (scan->accumulator >> 0) & 0xff); + + scan->accumulator = 0; + scan->accumulator_count = 0; + } + } +} + +static void +base85_end (csi_t *ctx, csi_scanner_t *scan, cairo_bool_t deflate) +{ + csi_object_t obj; + cairo_status_t status; + + buffer_check (ctx, scan, 4); + + switch (scan->accumulator_count) { + case 0: + break; + case 1: + longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT)); + break; + + case 2: + scan->accumulator = scan->accumulator * (85*85*85) + 85*85*85 -1; + buffer_add (&scan->buffer, (scan->accumulator >> 24) & 0xff); + break; + case 3: + scan->accumulator = scan->accumulator * (85*85) + 85*85 -1; + buffer_add (&scan->buffer, (scan->accumulator >> 24) & 0xff); + buffer_add (&scan->buffer, (scan->accumulator >> 16) & 0xff); + break; + case 4: + scan->accumulator = scan->accumulator * 85 + 84; + buffer_add (&scan->buffer, (scan->accumulator >> 24) & 0xff); + buffer_add (&scan->buffer, (scan->accumulator >> 16) & 0xff); + buffer_add (&scan->buffer, (scan->accumulator >> 8) & 0xff); + break; + } + + if (deflate) { + uLongf len = be32 (*(uint32_t *) scan->buffer.base); + Bytef *source = (Bytef *) (scan->buffer.base + sizeof (uint32_t)); + + status = csi_string_deflate_new (ctx, &obj, + source, + (Bytef *) scan->buffer.ptr - source, + len); + if (_csi_unlikely (status)) + longjmp (scan->jump_buffer, status); + } else { + status = csi_string_new (ctx, + &obj, + scan->buffer.base, + scan->buffer.ptr - scan->buffer.base); + if (_csi_unlikely (status)) + longjmp (scan->jump_buffer, status); + } + + if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL) + status = csi_array_append (ctx, + scan->build_procedure.datum.array, + &obj); + else + status = scan_push (ctx, &obj); + if (_csi_unlikely (status)) + longjmp (scan->jump_buffer, status); +} + +static void +base64_add (csi_t *ctx, csi_scanner_t *scan, int c) +{ + int val; + + /* Convert Base64 character to its 6 bit nibble */ + val = scan->accumulator; + if (c =='/') { + val = (val << 6) | 63; + } else if (c =='+') { + val = (val << 6) | 62; + } else if (c >='A' && c <='Z') { + val = (val << 6) | (c -'A'); + } else if (c >='a' && c <='z') { + val = (val << 6) | (c -'a' + 26); + } else if (c >='0' && c <='9') { + val = (val << 6) | (c -'0' + 52); + } + + buffer_check (ctx, scan, 1); + switch (scan->accumulator_count++) { + case 0: + break; + + case 1: + buffer_add (&scan->buffer, (val >> 4) & 0xFF); + val &= 0xF; + break; + + case 2: + buffer_add (&scan->buffer, (val >> 2) & 0xFF); + val &= 0x3; + break; + + case 3: + buffer_add (&scan->buffer, (val >> 0) & 0xFF); + scan->accumulator_count = 0; + val = 0; + break; + } + + if (c == '=') { + scan->accumulator_count = 0; + scan->accumulator = 0; + } else { + scan->accumulator = val; + } +} + +static void +base64_end (csi_t *ctx, csi_scanner_t *scan) +{ + csi_object_t obj; + cairo_status_t status; + + switch (scan->accumulator_count) { + case 0: + break; + case 2: + base64_add (ctx, scan, (scan->accumulator << 2) & 0x3f); + base64_add (ctx, scan, '='); + break; + case 1: + base64_add (ctx, scan, (scan->accumulator << 4) & 0x3f); + base64_add (ctx, scan, '='); + base64_add (ctx, scan, '='); + break; + } + + status = csi_string_new (ctx, + &obj, + scan->buffer.base, + scan->buffer.ptr - scan->buffer.base); + if (_csi_unlikely (status)) + longjmp (scan->jump_buffer, status); + + if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL) + status = csi_array_append (ctx, + scan->build_procedure.datum.array, + &obj); + else + status = scan_push (ctx, &obj); + if (_csi_unlikely (status)) + longjmp (scan->jump_buffer, status); +} + +static void +scan_read (csi_scanner_t *scan, csi_file_t *src, void *ptr, int len) +{ + uint8_t *data = ptr; + do { + int ret = csi_file_read (src, data, len); + if (_csi_unlikely (ret == 0)) + longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_READ_ERROR)); + data += ret; + len -= ret; + } while (_csi_unlikely (len)); +} + +static void +string_read (csi_t *ctx, + csi_scanner_t *scan, + csi_file_t *src, + int len, + int compressed, + csi_object_t *obj) +{ + csi_status_t status; + + status = csi_string_new (ctx, obj, NULL, len); + if (_csi_unlikely (status)) + longjmp (scan->jump_buffer, status); + + if (compressed) { + uint32_t u32; + scan_read (scan, src, &u32, 4); + obj->datum.string->deflate = be32 (u32); + obj->datum.string->method = compressed; + } + + if (_csi_likely (len)) + scan_read (scan, src, obj->datum.string->string, len); + obj->datum.string->string[len] = '\0'; +} + +static void +_scan_file (csi_t *ctx, csi_file_t *src) +{ + csi_scanner_t *scan = &ctx->scanner; + int c, next; + union { + int8_t i8; + uint8_t u8; + int16_t i16; + uint16_t u16; + int32_t i32; + uint32_t u32; + float f; + } u; + int deflate = 0; + int string_p; + +scan_none: + while ((c = csi_file_getc (src)) != EOF) { + csi_object_t obj = { CSI_OBJECT_TYPE_NULL }; + + switch (c) { + case 0xa: + scan->line_number++; + case 0x0: + case 0x9: + case 0xc: + case 0xd: + case 0x20: /* ignore whitespace */ + break; + + case '%': + goto scan_comment; + + case '(': + goto scan_string; + + case '[': /* needs special case */ + case ']': + case '{': + case '}': + token_start (scan); + token_add_unchecked (scan, c); + token_end (ctx, scan, src); + goto scan_none; + + case '<': + next = csi_file_getc (src); + switch (next) { + case EOF: + csi_file_putc (src, '<'); + return; + case '<': + /* dictionary name */ + token_start (scan); + token_add_unchecked (scan, '<'); + token_add_unchecked (scan, '<'); + token_end (ctx, scan, src); + goto scan_none; + case '|': + deflate = 1; + case '~': + goto scan_base85; + case '{': + goto scan_base64; + default: + csi_file_putc (src, next); + goto scan_hex; + } + break; + + /* binary token */ +#define MSB_INT8 128 +#define MSB_UINT8 129 +#define MSB_INT16 130 +#define MSB_UINT16 131 +#define MSB_INT32 132 +#define LSB_INT8 MSB_INT8 +#define LSB_UINT8 MSB_UINT8 +#define LSB_INT16 133 +#define LSB_UINT16 134 +#define LSB_INT32 135 +#define MSB_FLOAT32 140 +#define LSB_FLOAT32 141 + case MSB_INT8: + scan_read (scan, src, &u.i8, 1); + csi_integer_new (&obj, u.i8); + break; + case MSB_UINT8: + scan_read (scan, src, &u.u8, 1); + csi_integer_new (&obj, u.u8); + break; + case MSB_INT16: + scan_read (scan, src, &u.i16, 2); + csi_integer_new (&obj, be16 (u.i16)); + break; + case LSB_INT16: + scan_read (scan, src, &u.i16, 2); + csi_integer_new (&obj, le16 (u.i16)); + break; + case MSB_UINT16: + scan_read (scan, src, &u.u16, 2); + csi_integer_new (&obj, be16 (u.u16)); + break; + case LSB_UINT16: + scan_read (scan, src, &u.u16, 2); + csi_integer_new (&obj, le16 (u.u16)); + break; + case MSB_INT32: + scan_read (scan, src, &u.i32, 4); + csi_integer_new (&obj, be32 (u.i32)); + break; + case LSB_INT32: + scan_read (scan, src, &u.i32, 4); + csi_integer_new (&obj, le32 (u.i32)); + break; + + case 136: /* 16.16 msb */ + scan_read (scan, src, &u.i32, 4); + csi_real_new (&obj, be32 (u.i32) / 65536.); + break; + case 137: /* 16.16 lsb */ + scan_read (scan, src, &u.i32, 4); + csi_real_new (&obj, le32 (u.i32) / 65536.); + break; + case 138: /* 24.8 msb */ + scan_read (scan, src, &u.i32, 4); + csi_real_new (&obj, be32 (u.i32) / 256.); + break; + case 139: /* 24.8 lsb */ + scan_read (scan, src, &u.i32, 4); + csi_real_new (&obj, le32 (u.i32) / 256.); + break; + case MSB_FLOAT32: + scan_read (scan, src, &u.i32, 4); + u.i32 = be32 (u.i32); + csi_real_new (&obj, u.f); + break; + case LSB_FLOAT32: + scan_read (scan, src, &u.i32, 4); + u.i32 = le32 (u.i32); + csi_real_new (&obj, u.f); + break; + +#define STRING_1 142 +#define STRING_2_MSB 144 +#define STRING_2_LSB 146 +#define STRING_4_MSB 148 +#define STRING_4_LSB 150 +#define STRING_DEFLATE 1 + case STRING_1: + case STRING_1 | STRING_DEFLATE: + scan_read (scan, src, &u.u8, 1); + string_read (ctx, scan, src, u.u8, c & STRING_DEFLATE, &obj); + break; + case STRING_2_MSB: + case STRING_2_MSB | STRING_DEFLATE: + scan_read (scan, src, &u.u16, 2); + string_read (ctx, scan, src, be16 (u.u16), c & STRING_DEFLATE, &obj); + break; + case STRING_2_LSB: + case STRING_2_LSB | STRING_DEFLATE: + scan_read (scan, src, &u.u16, 2); + string_read (ctx, scan, src, le16 (u.u16), c & STRING_DEFLATE, &obj); + break; + case STRING_4_MSB: + case STRING_4_MSB | STRING_DEFLATE: + scan_read (scan, src, &u.u32, 4); + string_read (ctx, scan, src, be32 (u.u32), c & STRING_DEFLATE, &obj); + break; + case STRING_4_LSB: + case STRING_4_LSB | STRING_DEFLATE: + scan_read (scan, src, &u.u32, 4); + string_read (ctx, scan, src, le32 (u.u32), c & STRING_DEFLATE, &obj); + break; + +#define OPCODE 152 + case OPCODE: + scan_read (scan, src, &u.u8, 1); + csi_operator_new (&obj, ctx->opcode[u.u8]); + break; + + case OPCODE | 1: + scan_read (scan, src, &u.u8, 1); + csi_operator_new (&obj, ctx->opcode[u.u8]); + obj.type &= ~CSI_OBJECT_ATTR_EXECUTABLE; + break; + +#define STRING_LZO 154 + case STRING_LZO: + scan_read (scan, src, &u.u32, 4); + string_read (ctx, scan, src, be32 (u.u32), LZO, &obj); + break; + + /* unassigned */ + case 155: + case 156: + case 157: + case 158: + case 159: + longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT)); + + case '#': /* PDF 1.2 escape code */ + { + int c_hi = csi_file_getc (src); + int c_lo = csi_file_getc (src); + c = (hex_value (c_hi) << 4) | hex_value (c_lo); + } + /* fall-through */ + default: + token_start (scan); + token_add_unchecked (scan, c); + goto scan_token; + } + + if (obj.type != CSI_OBJECT_TYPE_NULL) { + cairo_status_t status; + + if (scan->build_procedure.type != CSI_OBJECT_TYPE_NULL) { + status = csi_array_append (ctx, + scan->build_procedure.datum.array, + &obj); + } else if (obj.type & CSI_OBJECT_ATTR_EXECUTABLE) { + status = scan_execute (ctx, &obj); + csi_object_free (ctx, &obj); + } else { + status = scan_push (ctx, &obj); + } + if (_csi_unlikely (status)) + longjmp (scan->jump_buffer, status); + } + } + return; + +scan_token: + while ((c = csi_file_getc (src)) != EOF) { + switch (c) { + case 0xa: + scan->line_number++; + /* fall through */ + case 0x0: + case 0x9: + case 0xc: + case 0xd: + case 0x20: + token_end (ctx, scan, src); + goto scan_none; + + /* syntax delimiters */ + case '%': + token_end (ctx, scan, src); + goto scan_comment; + /* syntax error? */ + case '(': + token_end (ctx, scan, src); + goto scan_string; + /* XXX syntax error? */ + case ')': + token_end (ctx, scan, src); + goto scan_none; + case '/': + /* need to special case '^//?' */ + if (scan->buffer.ptr > scan->buffer.base+1 || + scan->buffer.base[0] != '/') + { + token_end (ctx, scan, src); + token_start (scan); + } + token_add_unchecked (scan, '/'); + goto scan_token; + + case '{': + case '}': + case ']': + token_end (ctx, scan, src); + token_start (scan); + token_add_unchecked (scan, c); + token_end (ctx, scan, src); + goto scan_none; + + case '<': + csi_file_putc (src, '<'); + token_end (ctx, scan, src); + goto scan_none; + + case '#': /* PDF 1.2 escape code */ + { + int c_hi = csi_file_getc (src); + int c_lo = csi_file_getc (src); + c = (hex_value (c_hi) << 4) | hex_value (c_lo); + } + /* fall-through */ + default: + token_add (ctx, scan, c); + break; + } + } + token_end (ctx, scan, src); + return; + +scan_comment: + /* discard until newline */ + while ((c = csi_file_getc (src)) != EOF) { + switch (c) { + case 0xa: + scan->line_number++; + case 0xc: + goto scan_none; + } + } + return; + +scan_string: + buffer_reset (&scan->buffer); + string_p = 1; + while ((c = csi_file_getc (src)) != EOF) { + switch (c) { + case '\\': /* escape */ + next = csi_file_getc (src); + switch (next) { + case EOF: + longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT)); + + case 'n': + string_add (ctx, scan, '\n'); + break; + case 'r': + string_add (ctx, scan, '\r'); + break; + case 't': + string_add (ctx, scan, '\t'); + break; + case 'b': + string_add (ctx, scan, '\b'); + break; + case 'f': + string_add (ctx, scan, '\f'); + break; + case '\\': + string_add (ctx, scan, '\\'); + break; + case '(': + string_add (ctx, scan, '('); + break; + case ')': + string_add (ctx, scan, ')'); + break; + + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + { /* octal code: \d{1,3} */ + int i; + + c = next - '0'; + + for (i = 0; i < 2; i++) { + next = csi_file_getc (src); + switch (next) { + case EOF: + return; + + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + c = 8*c + next-'0'; + break; + + default: + csi_file_putc (src, next); + goto octal_code_done; + } + } + octal_code_done: + string_add (ctx, scan, c); + } + break; + + case 0xa: + /* skip the newline */ + next = csi_file_getc (src); /* might be compound LFCR */ + switch (next) { + case EOF: + return; + case 0xc: + break; + default: + csi_file_putc (src, next); + break; + } + scan->line_number++; + break; + case 0xc: + break; + + default: + /* ignore the '\' */ + break; + } + break; + + case '(': + string_p++; + string_add (ctx, scan, c); + break; + + case ')': + if (--string_p == 0) { + string_end (ctx, scan); + goto scan_none; + } + /* fall through */ + default: + string_add (ctx, scan, c); + break; + } + } + longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT)); + +scan_hex: + buffer_reset (&scan->buffer); + scan->accumulator_count = 0; + scan->accumulator = 0; + while ((c = csi_file_getc (src)) != EOF) { + switch (c) { + case 0xa: + scan->line_number++; + case 0x0: + case 0x9: + case 0xc: + case 0xd: + case 0x20: /* ignore whitespace */ + break; + + case '>': + hex_end (ctx, scan); /* fixup odd digit with '0' */ + goto scan_none; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + hex_add (ctx, scan, c); + break; + + default: + longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT)); + } + } + longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT)); + +scan_base85: + buffer_reset (&scan->buffer); + scan->accumulator = 0; + scan->accumulator_count = 0; + while ((c = csi_file_getc (src)) != EOF) { + switch (c) { + case '~': + next = csi_file_getc (src); + switch (next) { + case EOF: + return; + + case '>': + base85_end (ctx, scan, deflate); + deflate = 0; + goto scan_none; + } + csi_file_putc (src, next); + + /* fall-through */ + default: + base85_add (ctx, scan, c); + break; + } + } + longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT)); + +scan_base64: + buffer_reset (&scan->buffer); + scan->accumulator = 0; + scan->accumulator_count = 0; + while ((c = csi_file_getc (src)) != EOF) { + switch (c) { + case '}': + next = csi_file_getc (src); + switch (next) { + case EOF: + return; + + case '>': + base64_end (ctx, scan); + goto scan_none; + } + longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT)); + + default: + base64_add (ctx, scan, c); + break; + } + } + longjmp (scan->jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT)); +} + +static csi_status_t +_scan_push (csi_t *ctx, csi_object_t *obj) +{ + if (DEBUG_SCAN) { + fprintf (stderr, "push "); + fprintf_obj (stderr, ctx, obj); + } + return _csi_push_ostack (ctx, obj); +} + +static csi_status_t +_scan_execute (csi_t *ctx, csi_object_t *obj) +{ + if (DEBUG_SCAN) { + fprintf (stderr, "exec "); + fprintf_obj (stderr, ctx, obj); + } + return csi_object_execute (ctx, obj); +} + +csi_status_t +_csi_scanner_init (csi_t *ctx, csi_scanner_t *scanner) +{ + csi_status_t status; + + memset (scanner, 0, sizeof (csi_scanner_t)); + + status = buffer_init (ctx, &scanner->buffer); + if (status) + return status; + + status = _csi_stack_init (ctx, &scanner->procedure_stack, 4); + if (status) + return status; + + scanner->bind = 0; + scanner->push = _scan_push; + scanner->execute = _scan_execute; + + return CSI_STATUS_SUCCESS; +} + +void +_csi_scanner_fini (csi_t *ctx, csi_scanner_t *scanner) +{ + buffer_fini (ctx, &scanner->buffer); + _csi_stack_fini (ctx, &scanner->procedure_stack); + if (scanner->build_procedure.type != CSI_OBJECT_TYPE_NULL) + csi_object_free (ctx, &scanner->build_procedure); +} + +csi_status_t +_csi_scan_file (csi_t *ctx, csi_file_t *src) +{ + csi_status_t status; + int old_line_number; + + /* This function needs to be reentrant to handle recursive scanners. + * i.e. one script executes a second. + */ + + if (ctx->scanner.depth++ == 0) { + if ((status = setjmp (ctx->scanner.jump_buffer))) { + ctx->scanner.depth = 0; + return status; + } + } + + old_line_number = ctx->scanner.line_number; + ctx->scanner.line_number = 0; + + _scan_file (ctx, src); + + ctx->scanner.line_number = old_line_number; + + --ctx->scanner.depth; + return CSI_STATUS_SUCCESS; +} + +struct _translate_closure { + csi_dictionary_t *opcodes; + cairo_write_func_t write_func; + void *closure; +}; + +static csi_status_t +_translate_name (csi_t *ctx, + csi_name_t name, + csi_boolean_t executable, + struct _translate_closure *closure) +{ + if (executable) { + csi_dictionary_entry_t *entry; + uint16_t u16; + + /* Bind executable names. + * XXX This may break some scripts that overload system operators. + */ + entry = _csi_hash_table_lookup (&closure->opcodes->hash_table, + (csi_hash_entry_t *) &name); + if (entry == NULL) + goto STRING; + + u16 = entry->value.datum.integer; + u16 = be16 (u16); + closure->write_func (closure->closure, (unsigned char *) &u16, 2); + } else { + closure->write_func (closure->closure, (unsigned char *) "/", 1); +STRING: + closure->write_func (closure->closure, + (unsigned char *) name, + strlen ((char *) name)); + closure->write_func (closure->closure, (unsigned char *) "\n", 1); + } + + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_translate_operator (csi_t *ctx, + csi_operator_t op, + csi_boolean_t executable, + struct _translate_closure *closure) +{ + csi_dictionary_entry_t *entry; + uint16_t u16; + + entry = _csi_hash_table_lookup (&closure->opcodes->hash_table, + (csi_hash_entry_t *) &op); + if (entry == NULL) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + u16 = entry->value.datum.integer; + if (! executable) + u16 += 1 << 8; + u16 = be16 (u16); + closure->write_func (closure->closure, (unsigned char *) &u16, 2); + + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_translate_integer (csi_t *ctx, + csi_integer_t i, + struct _translate_closure *closure) +{ + uint8_t hdr; + union { + int8_t i8; + uint8_t u8; + int16_t i16; + uint16_t u16; + int32_t i32; + uint32_t u32; + } u; + int len; + +#if WORDS_BIGENDIAN + if (i < INT16_MIN) { + hdr = MSB_INT32; + len = 4; + u.i32 = i; + } else if (i < INT8_MIN) { + hdr = MSB_INT16; + len = 2; + u.i16 = i; + } else if (i < 0) { + hdr = MSB_INT8; + len = 1; + u.i8 = i; + } else if (i <= UINT8_MAX) { + hdr = MSB_UINT8; + len = 1; + u.u8 = i; + } else if (i <= UINT16_MAX) { + hdr = MSB_UINT16; + len = 2; + u.u16 = i; + } else { + hdr = MSB_INT32; + len = 4; + u.u32 = i; + } +#else + if (i < INT16_MIN) { + hdr = LSB_INT32; + len = 4; + u.i32 = i; + } else if (i < INT8_MIN) { + hdr = LSB_INT16; + len = 2; + u.i16 = i; + } else if (i < 0) { + hdr = LSB_INT8; + len = 1; + u.i8 = i; + } else if (i <= UINT8_MAX) { + hdr = LSB_UINT8; + len = 1; + u.u8 = i; + } else if (i <= UINT16_MAX) { + hdr = LSB_UINT16; + len = 2; + u.u16 = i; + } else { + hdr = LSB_INT32; + len = 4; + u.u32 = i; + } +#endif + + closure->write_func (closure->closure, (unsigned char *) &hdr, 1); + closure->write_func (closure->closure, (unsigned char *) &u, len); + + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_translate_real (csi_t *ctx, + csi_real_t real, + struct _translate_closure *closure) +{ + uint8_t hdr; + + if ((double)real >= INT32_MIN && (double)real <= INT32_MAX && (int) real == real) + return _translate_integer (ctx, real, closure); + +#if WORDS_BIGENDIAN + hdr = MSB_FLOAT32; +#else + hdr = LSB_FLOAT32; +#endif + closure->write_func (closure->closure, (unsigned char *) &hdr, 1); + closure->write_func (closure->closure, (unsigned char *) &real, 4); + + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_translate_string (csi_t *ctx, + csi_string_t *string, + struct _translate_closure *closure) +{ + uint8_t hdr; + union { + uint8_t u8; + uint16_t u16; + uint32_t u32; + } u; + void *buf; + unsigned long hdr_len, buf_len, deflate; + int method; + + buf = string->string; + buf_len = string->len; + deflate = string->deflate; + method = string->method; + +#if HAVE_LZO + if (method == NONE && buf_len > 16) { + unsigned long mem_len = 2*string->len > LZO2A_999_MEM_COMPRESS ? 2*string->len : LZO2A_999_MEM_COMPRESS; + void *mem = malloc (mem_len); + void *work = malloc(LZO2A_999_MEM_COMPRESS); + + if (lzo2a_999_compress ((lzo_bytep) buf, buf_len, + (lzo_bytep) mem, &mem_len, + work) == 0 && + 8+2*mem_len < buf_len) + { + method = LZO; + deflate = buf_len; + buf_len = mem_len; + buf = mem; + } + else + { + free (mem); + } + + free (work); + } +#if HAVE_ZLIB + if (method == ZLIB) { + buf_len = string->deflate; + buf = malloc (string->deflate); + if (uncompress ((Bytef *) buf, &buf_len, + (Bytef *) string->string, string->len) == Z_OK) + { + assert(string->len > 0); + if (buf_len <= 8 + 2*((unsigned long)string->len)) { + method = NONE; + deflate = 0; + } else { + unsigned long mem_len = 2*string->deflate; + void *mem = malloc (mem_len); + void *work = malloc(LZO2A_999_MEM_COMPRESS); + + if (lzo2a_999_compress ((lzo_bytep) buf, buf_len, + (lzo_bytep) mem, &mem_len, + work) == 0) + { + if (8 + mem_len > buf_len) { + method = NONE; + deflate = 0; + } else { + free (buf); + method = LZO; + deflate = buf_len; + buf_len = mem_len; + buf = mem; + assert(deflate); + } + } + else + { + free (buf); + buf = string->string; + buf_len = string->len; + } + + free (work); + } + } + else + { + free (buf); + buf = string->string; + buf_len = string->len; + } + } +#endif +#endif + + if (method == LZO) { + hdr = STRING_LZO; + u.u32 = to_be32 (buf_len); + hdr_len = 4; + } else { +#if WORDS_BIGENDIAN + if (buf_len <= UINT8_MAX) { + hdr = STRING_1; + u.u8 = buf_len; + hdr_len = 1; + } else if (buf_len <= UINT16_MAX) { + hdr = STRING_2_MSB; + u.u16 = buf_len; + hdr_len = 2; + } else { + hdr = STRING_4_MSB; + u.u32 = buf_len; + hdr_len = 4; + } +#else + if (buf_len <= UINT8_MAX) { + hdr = STRING_1; + u.u8 = buf_len; + hdr_len = 1; + } else if (buf_len <= UINT16_MAX) { + hdr = STRING_2_LSB; + u.u16 = buf_len; + hdr_len = 2; + } else { + hdr = STRING_4_LSB; + u.u32 = buf_len; + hdr_len = 4; + } +#endif + if (deflate) { + assert (method == ZLIB); + hdr |= STRING_DEFLATE; + } + } + + closure->write_func (closure->closure, (unsigned char *) &hdr, 1); + closure->write_func (closure->closure, (unsigned char *) &u, hdr_len); + if (deflate) { + uint32_t u32 = to_be32 (deflate); + closure->write_func (closure->closure, (unsigned char *) &u32, 4); + } + closure->write_func (closure->closure, (unsigned char *) buf, buf_len); + + if (buf != string->string) + free (buf); + + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_translate_push (csi_t *ctx, csi_object_t *obj) +{ + struct _translate_closure *closure = ctx->scanner.closure; + + if (0) { + fprintf (stderr, "push "); + fprintf_obj (stderr, ctx, obj); + } + + switch (csi_object_get_type (obj)) { + case CSI_OBJECT_TYPE_NAME: + return _translate_name (ctx, obj->datum.name, FALSE, closure); + + case CSI_OBJECT_TYPE_OPERATOR: + return _translate_operator (ctx, obj->datum.op, FALSE, closure); + + case CSI_OBJECT_TYPE_INTEGER: + return _translate_integer (ctx, obj->datum.integer, closure); + + case CSI_OBJECT_TYPE_REAL: + return _translate_real (ctx, obj->datum.real, closure); + + case CSI_OBJECT_TYPE_STRING: + return _translate_string (ctx, obj->datum.string, closure); + + case CSI_OBJECT_TYPE_NULL: + case CSI_OBJECT_TYPE_BOOLEAN: + case CSI_OBJECT_TYPE_MARK: + case CSI_OBJECT_TYPE_ARRAY: + case CSI_OBJECT_TYPE_DICTIONARY: + case CSI_OBJECT_TYPE_FILE: + case CSI_OBJECT_TYPE_MATRIX: + case CSI_OBJECT_TYPE_CONTEXT: + case CSI_OBJECT_TYPE_FONT: + case CSI_OBJECT_TYPE_PATTERN: + case CSI_OBJECT_TYPE_SCALED_FONT: + case CSI_OBJECT_TYPE_SURFACE: + longjmp (ctx->scanner.jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT)); + break; + } + + csi_object_free (ctx, obj); + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +_translate_execute (csi_t *ctx, csi_object_t *obj) +{ + struct _translate_closure *closure = ctx->scanner.closure; + + if (0) { + fprintf (stderr, "exec "); + fprintf_obj (stderr, ctx, obj); + } + + switch (csi_object_get_type (obj)) { + case CSI_OBJECT_TYPE_NAME: + return _translate_name (ctx, obj->datum.name, TRUE, closure); + + case CSI_OBJECT_TYPE_OPERATOR: + return _translate_operator (ctx, obj->datum.op, TRUE, closure); + + case CSI_OBJECT_TYPE_INTEGER: + return _translate_integer (ctx, obj->datum.integer, closure); + + case CSI_OBJECT_TYPE_REAL: + return _translate_real (ctx, obj->datum.real, closure); + + case CSI_OBJECT_TYPE_STRING: + return _translate_string (ctx, obj->datum.string, closure); + + case CSI_OBJECT_TYPE_NULL: + case CSI_OBJECT_TYPE_BOOLEAN: + case CSI_OBJECT_TYPE_MARK: + case CSI_OBJECT_TYPE_ARRAY: + case CSI_OBJECT_TYPE_DICTIONARY: + case CSI_OBJECT_TYPE_FILE: + case CSI_OBJECT_TYPE_MATRIX: + case CSI_OBJECT_TYPE_CONTEXT: + case CSI_OBJECT_TYPE_FONT: + case CSI_OBJECT_TYPE_PATTERN: + case CSI_OBJECT_TYPE_SCALED_FONT: + case CSI_OBJECT_TYPE_SURFACE: + longjmp (ctx->scanner.jump_buffer, _csi_error (CSI_STATUS_INVALID_SCRIPT)); + break; + } + + return CSI_STATUS_SUCCESS; +} + +static csi_status_t +build_opcodes (csi_t *ctx, csi_dictionary_t **out) +{ + csi_object_t obj; + csi_dictionary_t *dict; + const csi_operator_def_t *def; + csi_status_t status; + int opcode = OPCODE << 8; + + status = csi_dictionary_new (ctx, &obj); + if (_csi_unlikely (status)) + return status; + + dict = obj.datum.dictionary; + + csi_integer_new (&obj, opcode++); + status = csi_dictionary_put (ctx, dict, 0, &obj); + if (_csi_unlikely (status)) + goto FAIL; + + for (def = _csi_operators (); def->name != NULL; def++) { + csi_object_t name; + csi_dictionary_entry_t *entry; + int code; + + entry = _csi_hash_table_lookup (&dict->hash_table, + (csi_hash_entry_t *) &def->op); + if (entry == NULL) { + code = opcode++; + csi_integer_new (&obj, code); + status = csi_dictionary_put (ctx, dict, (csi_name_t) def->op, &obj); + if (_csi_unlikely (status)) + goto FAIL; + } else { + code = entry->value.datum.integer; + csi_integer_new (&obj, code); + } + assert (ctx->opcode[code & 0xff] == def->op); + + status = csi_name_new_static (ctx, &name, def->name); + if (_csi_unlikely (status)) + goto FAIL; + + status = csi_dictionary_put (ctx, dict, name.datum.name, &obj); + if (_csi_unlikely (status)) + goto FAIL; + } + + *out = dict; + return CSI_STATUS_SUCCESS; + +FAIL: + csi_dictionary_free (ctx, dict); + return status; +} + +csi_status_t +_csi_translate_file (csi_t *ctx, + csi_file_t *file, + cairo_write_func_t write_func, + void *closure) +{ + csi_status_t status; + struct _translate_closure translator; + + if ((status = setjmp (ctx->scanner.jump_buffer))) + return status; + + status = build_opcodes (ctx, &translator.opcodes); + if (_csi_unlikely (status)) + return status; + + translator.write_func = write_func; + translator.closure = closure; + ctx->scanner.closure = &translator; + + ctx->scanner.bind = 1; + ctx->scanner.push = _translate_push; + ctx->scanner.execute = _translate_execute; + + _scan_file (ctx, file); + + ctx->scanner.bind = 0; + ctx->scanner.push = _scan_push; + ctx->scanner.execute = _scan_execute; + + csi_dictionary_free (ctx, translator.opcodes); + + return CSI_STATUS_SUCCESS; +} diff --git a/local/recipes/libs/cairo/source/util/cairo-script/cairo-script-stack.c b/local/recipes/libs/cairo/source/util/cairo-script/cairo-script-stack.c new file mode 100644 index 0000000000..ff1e91ade0 --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-script/cairo-script-stack.c @@ -0,0 +1,198 @@ +/* + * Copyright © 2008 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Chris Wilson. + * + * Contributor(s): + * Chris Wilson + */ + +#include "config.h" + +#include "cairo-script-private.h" + +#include /* INT_MAX */ +#include + +csi_status_t +_csi_stack_init (csi_t *ctx, csi_stack_t *stack, csi_integer_t size) +{ + csi_status_t status = CSI_STATUS_SUCCESS; + + stack->len = 0; + stack->size = size; + /* assert ((unsigned) size < INT_MAX / sizeof (csi_object_t)); */ + stack->objects = _csi_alloc (ctx, size * sizeof (csi_object_t)); + if (_csi_unlikely (stack->objects == NULL)) + status = _csi_error (CSI_STATUS_NO_MEMORY); + + return status; +} + +void +_csi_stack_fini (csi_t *ctx, csi_stack_t *stack) +{ + csi_integer_t n; + + for (n = 0; n < stack->len; n++) + csi_object_free (ctx, &stack->objects[n]); + + _csi_free (ctx, stack->objects); +} + +csi_status_t +_csi_stack_roll (csi_t *ctx, + csi_stack_t *stack, + csi_integer_t mod, csi_integer_t n) +{ + csi_object_t stack_copy[128]; + csi_object_t *copy; + csi_integer_t last, i, len; + + switch (mod) { /* special cases */ + case 1: + last = stack->len - 1; + stack_copy[0] = stack->objects[last]; + for (i = last; --n; i--) + stack->objects[i] = stack->objects[i-1]; + stack->objects[i] = stack_copy[0]; + return CSI_STATUS_SUCCESS; + case -1: + last = stack->len - 1; + stack_copy[0] = stack->objects[i = last - n + 1]; + for (; --n; i++) + stack->objects[i] = stack->objects[i+1]; + stack->objects[i] = stack_copy[0]; + return CSI_STATUS_SUCCESS; + } + + /* fall back to a copy */ + if (n > ARRAY_LENGTH (stack_copy)) { + if (_csi_unlikely ((unsigned) n > INT_MAX / sizeof (csi_object_t))) + return _csi_error (CSI_STATUS_NO_MEMORY); + copy = _csi_alloc (ctx, n * sizeof (csi_object_t)); + if (copy == NULL) + return _csi_error (CSI_STATUS_NO_MEMORY); + } else + copy = stack_copy; + + i = stack->len - n; + memcpy (copy, stack->objects + i, n * sizeof (csi_object_t)); + mod = -mod; + if (mod < 0) + mod += n; + last = mod; + for (len = n; n--; i++) { + stack->objects[i] = copy[last]; + if (++last == len) + last = 0; + } + + if (copy != stack_copy) + _csi_free (ctx, copy); + + return CSI_STATUS_SUCCESS; +} + +csi_status_t +_csi_stack_grow (csi_t *ctx, csi_stack_t *stack, csi_integer_t cnt) +{ + csi_integer_t newsize; + csi_object_t *newstack; + + if (_csi_likely (cnt <= stack->size)) + return CSI_STATUS_SUCCESS; + if (_csi_unlikely ((unsigned) cnt >= INT_MAX / sizeof (csi_object_t))) + return _csi_error (CSI_STATUS_NO_MEMORY); + + newsize = stack->size; + do { + newsize *= 2; + } while (newsize <= cnt); + + newstack = _csi_realloc (ctx, + stack->objects, + newsize * sizeof (csi_object_t)); + if (_csi_unlikely (newstack == NULL)) + return _csi_error (CSI_STATUS_NO_MEMORY); + + stack->objects = newstack; + stack->size = newsize; + + return CSI_STATUS_SUCCESS; +} + +csi_status_t +_csi_stack_push_internal (csi_t *ctx, csi_stack_t *stack, + const csi_object_t *obj) +{ + csi_status_t status; + + status = _csi_stack_grow (ctx, stack, stack->size + 1); + if (_csi_unlikely (status)) + return status; + + stack->objects[stack->len++] = *obj; + return CSI_STATUS_SUCCESS; +} + +csi_object_t * +_csi_stack_peek (csi_stack_t *stack, csi_integer_t i) +{ + if (_csi_unlikely (stack->len < i)) + return NULL; + + return &stack->objects[stack->len - i -1]; +} + +void +_csi_stack_pop (csi_t *ctx, csi_stack_t *stack, csi_integer_t count) +{ + if (_csi_unlikely (stack->len < count)) + count = stack->len; + + while (count--) + csi_object_free (ctx, &stack->objects[--stack->len]); +} + +csi_status_t +_csi_stack_exch (csi_stack_t *stack) +{ + csi_object_t tmp; + csi_integer_t n; + + if (_csi_unlikely (stack->len < 2)) + return _csi_error (CSI_STATUS_INVALID_SCRIPT); + + n = stack->len - 1; + tmp = stack->objects[n]; + stack->objects[n] = stack->objects[n - 1]; + stack->objects[n - 1] = tmp; + + return CSI_STATUS_SUCCESS; +} diff --git a/local/recipes/libs/cairo/source/util/cairo-script/csi-bind.c b/local/recipes/libs/cairo/source/util/cairo-script/csi-bind.c new file mode 100644 index 0000000000..b2a6d69f8f --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-script/csi-bind.c @@ -0,0 +1,112 @@ +/* + * Copyright © 2008 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Chris Wilson. + * + * Contributor(s): + * Chris Wilson + */ + +#include "config.h" + +#include "cairo.h" +#include "cairo-script-interpreter.h" + +#include +#include + +static cairo_status_t +write_func (void *closure, + const unsigned char *data, + unsigned int length) +{ + if (fwrite (data, length, 1, closure) != 1) + return CAIRO_STATUS_WRITE_ERROR; + + return CAIRO_STATUS_SUCCESS; +} + +int +main (int argc, char **argv) +{ + FILE *in = stdin, *out = stdout; + cairo_status_t status; + int i; + + if (argc >= 3) { + if (strcmp (argv[argc-1], "-")) { + out = fopen (argv[argc-1], "w"); + if (out == NULL) { + fprintf (stderr, "Failed to open output '%s'\n", argv[argc-1]); + return 1; + } + } + } + + if (argc > 2) { + for (i = 1; i < argc - 1; i++) { + in = fopen (argv[i], "r"); + if (in == NULL) { + fprintf (stderr, "Failed to open input '%s'\n", argv[i]); + return 1; + } + + status = cairo_script_interpreter_translate_stream (in, write_func, out); + fclose (in); + + if (status) + break; + } + } else { + if (argc > 1) { + if (strcmp (argv[1], "-")) { + in = fopen (argv[1], "r"); + if (in == NULL) { + fprintf (stderr, "Failed to open input '%s'\n", argv[1]); + return 1; + } + } + } + + status = cairo_script_interpreter_translate_stream (in, write_func, out); + + if (in != stdin) + fclose (in); + } + + if (out != stdout) + fclose (out); + + if (status) { + fprintf (stderr, "Translation failed: %s\n", + cairo_status_to_string (status)); + return status; + } + + return status; +} diff --git a/local/recipes/libs/cairo/source/util/cairo-script/csi-exec.c b/local/recipes/libs/cairo/source/util/cairo-script/csi-exec.c new file mode 100644 index 0000000000..175328c96f --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-script/csi-exec.c @@ -0,0 +1,77 @@ +/* + * Copyright © 2008 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Chris Wilson. + * + * Contributor(s): + * Chris Wilson + */ + +#include "config.h" + +#include "cairo.h" +#include "cairo-script-interpreter.h" + +#include +#include + +static cairo_surface_t * +_surface_create (void *closure, + cairo_content_t content, + double width, double height, + long uid) +{ + return cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); +} + +int +main (int argc, char **argv) +{ + const cairo_script_interpreter_hooks_t hooks = { + .surface_create = _surface_create + }; + cairo_script_interpreter_t *csi; + int i; + + for (i = 1; i < argc; i++) { + int status, line; + + csi = cairo_script_interpreter_create (); + cairo_script_interpreter_install_hooks (csi, &hooks); + cairo_script_interpreter_run (csi, argv[i]); + line = cairo_script_interpreter_get_line_number (csi); + status = cairo_script_interpreter_destroy (csi); + if (status) { + fprintf (stderr, "Error during replay of '%s', line %d: %d\n", + argv[i], line, status); + return 1; + } + } + + return 0; +} diff --git a/local/recipes/libs/cairo/source/util/cairo-script/csi-replay.c b/local/recipes/libs/cairo/source/util/cairo-script/csi-replay.c new file mode 100644 index 0000000000..4460d64143 --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-script/csi-replay.c @@ -0,0 +1,337 @@ +/* + * Copyright © 2008 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Chris Wilson. + * + * Contributor(s): + * Chris Wilson + */ + +#include "config.h" + +#include "cairo.h" +#include "cairo-script-interpreter.h" + +#include +#include +#include + +#if defined(CAIRO_HAS_XLIB_SURFACE) || defined(CAIRO_HAS_XLIB_XRENDER_SURFACE) +static const cairo_user_data_key_t _key; +#endif + +#define SINGLE_SURFACE 1 + +#if SINGLE_SURFACE +static cairo_surface_t * +_similar_surface_create (void *closure, + cairo_content_t content, + double width, double height, + long uid) +{ + return cairo_surface_create_similar (closure, content, width, height); +} + +static struct list { + struct list *next; + cairo_t *context; + cairo_surface_t *surface; +} *list; + +static cairo_t * +_context_create (void *closure, cairo_surface_t *surface) +{ + cairo_t *cr = cairo_create (surface); + struct list *l = malloc (sizeof (*l)); + l->next = list; + l->context = cr; + l->surface = cairo_surface_reference (surface); + list = l; + return cr; +} + +static void +_context_destroy (void *closure, void *ptr) +{ + struct list *l, **prev = &list; + while ((l = *prev) != NULL) { + if (l->context == ptr) { + if (cairo_surface_status (l->surface) == CAIRO_STATUS_SUCCESS) { + cairo_t *cr = cairo_create (closure); + cairo_set_source_surface (cr, l->surface, 0, 0); + cairo_paint (cr); + cairo_destroy (cr); + } + + cairo_surface_destroy (l->surface); + *prev = l->next; + free (l); + return; + } + prev = &l->next; + } +} +#endif + +#if CAIRO_HAS_XLIB_SURFACE +#include +static Display * +_get_display (void) +{ + static Display *dpy; + + if (dpy != NULL) + return dpy; + + dpy = XOpenDisplay (NULL); + if (dpy == NULL) { + fprintf (stderr, "Failed to open display.\n"); + exit (1); + } + + return dpy; +} + +static void +_destroy_window (void *closure) +{ + XFlush (_get_display ()); + XDestroyWindow (_get_display(), (Window) closure); +} + +static cairo_surface_t * +_xlib_surface_create (void *closure, + cairo_content_t content, + double width, double height, + long uid) +{ + Display *dpy; + XSetWindowAttributes attr; + Visual *visual; + int depth; + Window w; + cairo_surface_t *surface; + + dpy = _get_display (); + + visual = DefaultVisual (dpy, DefaultScreen (dpy)); + depth = DefaultDepth (dpy, DefaultScreen (dpy)); + attr.override_redirect = True; + w = XCreateWindow (dpy, DefaultRootWindow (dpy), 0, 0, + width <= 0 ? 1 : width, + height <= 0 ? 1 : height, + 0, depth, + InputOutput, visual, CWOverrideRedirect, &attr); + XMapWindow (dpy, w); + + surface = cairo_xlib_surface_create (dpy, w, visual, width, height); + cairo_surface_set_user_data (surface, &_key, (void *) w, _destroy_window); + + return surface; +} + +#if CAIRO_HAS_XLIB_XRENDER_SURFACE +#include + +static void +_destroy_pixmap (void *closure) +{ + XFreePixmap (_get_display(), (Pixmap) closure); +} + +static cairo_surface_t * +_xrender_surface_create (void *closure, + cairo_content_t content, + double width, double height, + long uid) +{ + Display *dpy; + Pixmap pixmap; + XRenderPictFormat *xrender_format; + cairo_surface_t *surface; + + dpy = _get_display (); + + content = CAIRO_CONTENT_COLOR_ALPHA; + + switch (content) { + case CAIRO_CONTENT_COLOR_ALPHA: + xrender_format = XRenderFindStandardFormat (dpy, PictStandardARGB32); + break; + case CAIRO_CONTENT_COLOR: + xrender_format = XRenderFindStandardFormat (dpy, PictStandardRGB24); + break; + case CAIRO_CONTENT_ALPHA: + default: + xrender_format = XRenderFindStandardFormat (dpy, PictStandardA8); + } + + pixmap = XCreatePixmap (dpy, DefaultRootWindow (dpy), + width, height, xrender_format->depth); + + surface = cairo_xlib_surface_create_with_xrender_format (dpy, pixmap, + DefaultScreenOfDisplay (dpy), + xrender_format, + width, height); + cairo_surface_set_user_data (surface, &_key, + (void *) pixmap, _destroy_pixmap); + + return surface; +} +#endif +#endif + +#if CAIRO_HAS_PDF_SURFACE +#include +static cairo_surface_t * +_pdf_surface_create (void *closure, + cairo_content_t content, + double width, double height, + long uid) +{ + return cairo_pdf_surface_create_for_stream (NULL, NULL, width, height); +} +#endif + +#if CAIRO_HAS_PS_SURFACE +#include +static cairo_surface_t * +_ps_surface_create (void *closure, + cairo_content_t content, + double width, double height, + long uid) +{ + return cairo_ps_surface_create_for_stream (NULL, NULL, width, height); +} +#endif + +#if CAIRO_HAS_SVG_SURFACE +#include +static cairo_surface_t * +_svg_surface_create (void *closure, + cairo_content_t content, + double width, double height, + long uid) +{ + return cairo_svg_surface_create_for_stream (NULL, NULL, width, height); +} +#endif + +static cairo_surface_t * +_image_surface_create (void *closure, + cairo_content_t content, + double width, double height, + long uid) +{ + return cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); +} + +int +main (int argc, char **argv) +{ + cairo_script_interpreter_t *csi; + cairo_script_interpreter_hooks_t hooks = { +#if SINGLE_SURFACE + .surface_create = _similar_surface_create, + .context_create = _context_create, + .context_destroy = _context_destroy +#elif CAIRO_HAS_XLIB_XRENDER_SURFACE + .surface_create = _xrender_surface_create +#elif CAIRO_HAS_XLIB_SURFACE + .surface_create = _xlib_surface_create +#elif CAIRO_PDF_SURFACE + .surface_create = _pdf_surface_create +#elif CAIRO_PS_SURFACE + .surface_create = _ps_surface_create +#elif CAIRO_SVG_SURFACE + .surface_create = _svg_surface_create +#else + .surface_create = _image_surface_create +#endif + }; + int i; + const struct backends { + const char *name; + csi_surface_create_func_t create; + } backends[] = { + { "--image", _image_surface_create }, +#if CAIRO_HAS_XLIB_XRENDER_SURFACE + { "--xrender", _xrender_surface_create }, +#endif +#if CAIRO_HAS_XLIB_SURFACE + { "--xlib", _xlib_surface_create }, +#endif +#if CAIRO_HAS_PDF_SURFACE + { "--pdf", _pdf_surface_create }, +#endif +#if CAIRO_HAS_PS_SURFACE + { "--ps", _ps_surface_create }, +#endif +#if CAIRO_HAS_SVG_SURFACE + { "--svg", _svg_surface_create }, +#endif + { NULL, NULL } + }; + +#if SINGLE_SURFACE + hooks.closure = backends[0].create (NULL, + CAIRO_CONTENT_COLOR_ALPHA, + 512, 512, + 0); +#endif + + + csi = cairo_script_interpreter_create (); + cairo_script_interpreter_install_hooks (csi, &hooks); + + for (i = 1; i < argc; i++) { + const struct backends *b; + + for (b = backends; b->name != NULL; b++) { + if (strcmp (b->name, argv[i]) == 0) { +#if SINGLE_SURFACE + cairo_surface_destroy (hooks.closure); + hooks.closure = b->create (NULL, + CAIRO_CONTENT_COLOR_ALPHA, + 512, 512, + 0); +#else + hooks.surface_create = b->create; +#endif + cairo_script_interpreter_install_hooks (csi, &hooks); + break; + } + } + + if (b->name == NULL) + cairo_script_interpreter_run (csi, argv[i]); + } + cairo_surface_destroy (hooks.closure); + + return cairo_script_interpreter_destroy (csi); +} diff --git a/local/recipes/libs/cairo/source/util/cairo-script/csi-trace.c b/local/recipes/libs/cairo/source/util/cairo-script/csi-trace.c new file mode 100644 index 0000000000..e93b28cf0a --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-script/csi-trace.c @@ -0,0 +1,84 @@ +/* + * Copyright © 2008 Chris Wilson + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. + * + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Chris Wilson. + * + * Contributor(s): + * Chris Wilson + */ + +#include "config.h" + +#include "cairo-script.h" +#include "cairo-script-interpreter.h" + +#include +#include +#include +#include + +static cairo_surface_t * +_script_surface_create (void *closure, + cairo_content_t content, + double width, double height, + long uid) +{ + return cairo_script_surface_create (closure, content, width, height); +} + +int +main (int argc, char **argv) +{ + cairo_script_interpreter_t *csi; + cairo_script_interpreter_hooks_t hooks = { + .surface_create = _script_surface_create, + }; + int i; + char buf[4096]; + + csi = cairo_script_interpreter_create (); + + for (i = 1; i < argc; i++) { + if (strcmp (argv[i], "--version") == 0) { + printf ("%s: version %s\n", argv[0], __DATE__); + exit (0); + } else if (strcmp (argv[i], "--help") == 0) { + printf ("usage: %s < in > out\n", argv[0]); + exit (0); + } + + snprintf (buf, sizeof (buf), "%s.trace", basename (argv[i])); + cairo_device_destroy (hooks.closure); + hooks.closure = cairo_script_create (buf); + cairo_script_interpreter_install_hooks (csi, &hooks); + cairo_script_interpreter_run (csi, argv[i]); + } + cairo_device_destroy (hooks.closure); + + return cairo_script_interpreter_destroy (csi); +} diff --git a/local/recipes/libs/cairo/source/util/cairo-script/examples/dragon.cs b/local/recipes/libs/cairo/source/util/cairo-script/examples/dragon.cs new file mode 100644 index 0000000000..1060ca6993 --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-script/examples/dragon.cs @@ -0,0 +1,48 @@ +%!CairoScript +/pot { % n -- n + 1 sub + dup -1 bitshift or + dup -2 bitshift or + dup -4 bitshift or + dup -8 bitshift or + dup -16 bitshift or + 1 add +} bind def + +/direction { % i -- bool + dup 2 lt { pop true } { + dup 1 add dup pot dup 3 -1 roll eq { pop pop true } { + 2 div 1 sub 2 mul exch sub direction not + } ifelse + } ifelse +} bind def + +/path { % cr dx dy -- cr + 0 1 2048 { + 4 1 roll 3 copy L pop 4 -1 roll direction { + exch neg + } { + neg exch + } ifelse + } for + pop pop +} bind def + +dict + /width 512 set + /height 512 set + surface context + +1 g set-source paint + +//LINE_CAP_ROUND set-line-cap +//LINE_JOIN_ROUND set-line-join +4 set-line-width + +256 256 m 12 0 path 0 0 0 rgb set-source stroke +256 256 m -12 0 path 1 0 0 rgb set-source stroke +256 256 m 0 12 path 0 1 0 rgb set-source stroke +256 256 m 0 -12 path 0 0 1 rgb set-source stroke + +/target get (out.png) write-to-png pop +pop diff --git a/local/recipes/libs/cairo/source/util/cairo-script/examples/hilbert.cs b/local/recipes/libs/cairo/source/util/cairo-script/examples/hilbert.cs new file mode 100644 index 0000000000..4278bf74ca --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-script/examples/hilbert.cs @@ -0,0 +1,51 @@ +%!CairoScript + +/hA { % cr dist lvl *hA* cr dist + dup not { pop } { + 1 sub + 3 copy hB 0 exch L pop + 3 copy hA 0 L pop + 3 copy hA neg 0 exch L pop + hC + } ifelse +} bind def + +/hB { % cr dist lvl *hB* cr dist + dup not { pop } { + 1 sub + 3 copy hA 0 L pop + 3 copy hB 0 exch L pop + 3 copy hB neg 0 L pop + hD + } ifelse +} bind def + +/hC { % cr dist lvl *hC* cr dist + dup not { pop } { + 1 sub + 3 copy hD neg 0 L pop + 3 copy hC neg 0 exch L pop + 3 copy hC 0 L pop + hA + } ifelse +} bind def + +/hD { % cr dist lvl *hD* cr dist + dup not { pop } { + 1 sub + 3 copy hC neg 0 exch L pop + 3 copy hD neg 0 L pop + 3 copy hD 0 exch L pop + hB + } ifelse +} bind def + +dict + /width 1024 set + /height 1024 set + surface context + +2 2 m 4 10 hA pop 1 g set-source stroke + +/target get (out.png) write-to-png pop +pop diff --git a/local/recipes/libs/cairo/source/util/cairo-script/examples/infinichess.cs b/local/recipes/libs/cairo/source/util/cairo-script/examples/infinichess.cs new file mode 100644 index 0000000000..f82b102782 --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-script/examples/infinichess.cs @@ -0,0 +1,29 @@ +/xdef { exch def } def +/-rot { 3 1 roll } def +/rot { 3 -1 roll } def +/2dup { 2 copy } def + +/SIZE 600. def +<< /width SIZE /height SIZE >> surface context +1 1 1 set-source-rgb paint +0 0 0 set-source-rgb +EVEN_ODD set-fill-rule +SIZE SIZE scale + +0.5 0 translate + +save +1 1 scale +/n 90 def +n neg 1 n { + /x xdef + 0 0 m + x 1 l + x 0.5 add 1 l + 0 0 l +} for +restore +fill + +/target get (out.png) write-to-png pop +pop diff --git a/local/recipes/libs/cairo/source/util/cairo-script/examples/interference.cs b/local/recipes/libs/cairo/source/util/cairo-script/examples/interference.cs new file mode 100644 index 0000000000..6d2ee2200f --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-script/examples/interference.cs @@ -0,0 +1,46 @@ +/rot { 3 -1 roll } def +/2dup { 2 copy } def + +/circle { % context radius -- context + 2dup 0 m pop + 0 0 rot 0 math.2pi arc h +} def + +/circles { % context #circles -- context + 1 1 rot { circle } for +} def + +/SIDE 600. def +/SIZE 600. def +<< /width SIZE /height SIZE >> surface context +1 1 1 set-source-rgb paint +0 0 0 set-source-rgb +//EVEN_ODD set-fill-rule + +/r 4 def +/n SIDE 1.5 mul r div integer def + +SIZE SIDE div dup scale + +save + 302 200 translate + r dup scale + n circles +restore + +save + 100 300 translate + r dup scale + n circles +restore + +save + 500 400 translate + r dup scale + n circles +restore + +fill + +/target get (out.png) write-to-png pop +pop diff --git a/local/recipes/libs/cairo/source/util/cairo-script/examples/pythagoras-tree.cs b/local/recipes/libs/cairo/source/util/cairo-script/examples/pythagoras-tree.cs new file mode 100644 index 0000000000..96b4b39bce --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-script/examples/pythagoras-tree.cs @@ -0,0 +1,53 @@ +%!CairoScript + +/pi4 0.785398163 def +/sqrt2 1.414213562 def + +/R { % cr size *R* cr + dup 1 lt { pop } { + exch /current-point get % size cr x y + 4 2 roll % x y size cr + + % draw a rectangle in relative co-ordinates + 1 index 2 div neg dup exch M + 1 index 0 L + 0 2 index L + 1 index neg 0 L + h + + save + 1 index dup 2 div neg exch translate + 4 2 roll 3 copy % size cr x y cr x y + m + //pi4 rotate + pop 4 2 roll % x y size cr + 1 index //sqrt2 div + R + restore + + save + 1 index dup 2 div exch translate + 4 2 roll 3 copy % size cr x y cr x y + m + //pi4 neg rotate + pop 4 2 roll % x y size cr + 1 index //sqrt2 div + R + restore + + 4 1 roll pop pop pop + } ifelse +} bind def + +dict + /width 1024 set + /height 512 set + surface context + +1 1 1 set-source-rgb paint + +0 512 translate 1 -1 scale +512 64 m 128. R 0 0 0 set-source-rgb fill + +/target get (out.png) write-to-png pop +pop diff --git a/local/recipes/libs/cairo/source/util/cairo-script/examples/sierpinski.cs b/local/recipes/libs/cairo/source/util/cairo-script/examples/sierpinski.cs new file mode 100644 index 0000000000..6f959083b4 --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-script/examples/sierpinski.cs @@ -0,0 +1,37 @@ +%!CairoScript + +/1sqrt3 0.577359269 def + +/T { % cr size -- cr + exch % size cr + 0 0 m 1 index 0 l 1 index dup 2 div exch //1sqrt3 mul l h + + exch 2 div + dup 4 ge { + exch % size/2 cr + + 1 index T + save 1 index 0 translate 1 index T restore + save 1 index dup 2 div exch //1sqrt3 mul translate 1 index T restore + + exch + } if + pop +} bind def + +dict + /width 512 set + /height 300 set + surface context + +1 1 1 set-source-rgb paint + +.5 set-line-width + +0 300 translate +1 -1 scale + +512 T 0 0 0 set-source-rgb stroke + +/target get (out.png) write-to-png pop +pop diff --git a/local/recipes/libs/cairo/source/util/cairo-script/examples/wedgeAnnulus_crop_ybRings.cs b/local/recipes/libs/cairo/source/util/cairo-script/examples/wedgeAnnulus_crop_ybRings.cs new file mode 100644 index 0000000000..5aeb97f6ec --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-script/examples/wedgeAnnulus_crop_ybRings.cs @@ -0,0 +1,30 @@ +/SIDE 600 def + +<< /width SIDE /height SIDE >> surface context + +1 1 1 rgb set-source +paint + +SIDE dup scale +0.5 0.5 translate +0.5 -0.5 scale + +/theta math.pi 10 div def + +10 { + N + 0 0 1.0 0 //theta arc + 0 0 0.2 //theta 0 arc- + h + //theta rotate + //theta rotate +} repeat + +0 0 0.2 0 0 1 radial + 0.0 1 1 0 1 add-color-stop + 1.0 0 0 1 1 add-color-stop +set-source +fill + +/target get (out.png) write-to-png pop +pop diff --git a/local/recipes/libs/cairo/source/util/cairo-script/examples/world-map.cs b/local/recipes/libs/cairo/source/util/cairo-script/examples/world-map.cs new file mode 100644 index 0000000000..54d9a8f319 --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-script/examples/world-map.cs @@ -0,0 +1,209 @@ +%!CairoScript +% The data for this test case was provided by Gary Nicholson +% who originally created an interactive SVG map +% of the world as can be seen here: +% +% http://www.wherearewe.co.nz/svg.html +% +% The data is used here by permission from Gary given on 2006-11-08: +% +% Thanks for asking, I don't need any attribution if you are +% only using the vectors and not the entire map with +% interactivity etc. So feel free to do what you wish with +% the data. + +/N { + 2 index + .75 .75 .75 set-source-rgb fill+ + .5 .5 .5 set-source-rgb stroke + pop + m +} bind def + +% simpler if these had been expressed in relative coords... +/H { + exch /current-point get exch pop % x cr y + 3 -1 roll exch l +} bind def + +/V { + exch /current-point get pop % y cr x + 3 -1 roll l +} bind def + +dict + /width 800 set + /height 400 set + surface context + +.68 .85 .90 set-source-rgb paint +.2 set-line-width + +413.519 90.071 N .136 -.348 L -.31 -.204 L -.017 -.327 L .213 -.322 L .245 -.147 L .142 -.08 L .225 .072 L .062 .301 L .41 .312 L .466 .096 L -.044 .288 L -.248 .144 L .074 .353 L -.145 -.063 L -.568 -.011 L -.642 -.063 L +421.683 94.397 N .193 .336 L -.266 .274 L .214 .288 L -.09 .192 L .622 .062 L .008 .144 L .55 .242 L .579 -.332 L .215 .117 L -.029 .171 L -.126 .309 L .112 .212 L -.038 .192 L -.315 -.051 L -.176 -.162 L -.283 .091 L -.081 .273 L .244 .131 L -.228 .415 L -.244 -.333 L -.469 .05 L -.071 .122 L -.216 .03 L -.23 -.142 L -.143 -.354 L -.371 .081 L .019 .333 L -.425 .384 L -.018 .535 L -.285 .151 L -.385 -.312 L .098 -.182 L -.311 -.071 L -.534 -.363 L -.016 -.415 L -.777 .404 L .103 .212 L -.349 .432 L -.275 .16 L -.629 -.168 L -.627 .204 L -.599 -.062 L -.102 -.424 L -.312 -.806 L -.616 .147 L -.854 .668 L -.369 -.111 L .238 -.226 L .013 -.322 L -.08 -.137 L .089 -.294 L .718 -.418 L -.038 -.315 L .575 -.24 L .012 -.076 L .528 -.494 L .173 -.035 L -.116 -.089 L -.153 -.028 L .221 -.302 L .446 .007 L -.005 .096 L .473 .007 L .385 -.309 L .271 .089 L .272 -.117 L .271 .096 L .567 -.158 L .278 .11 L .354 -.021 L -.179 -.199 L .709 -.199 L .017 .151 L .199 -.014 L .149 .089 L .852 .007 L .664 .261 L +421.394 104.558 N .104 .175 L .04 .256 L -.06 .475 L .118 .054 L .062 .333 L -.076 .795 L -.211 .327 L -.118 .724 L -.292 .501 L -.298 -.043 L -.057 -.196 L -.41 -.076 L -.227 -.152 L .284 -.207 L -.07 -.076 L -.437 -.098 L .257 -.332 L -.11 -.071 L -.291 .071 L -.053 -.147 L .115 -.022 L .175 -.158 L -.094 -.153 L -.257 -.082 L .015 -.164 L .247 -.12 L -.284 -.218 L .241 -.284 L .6 -.305 L .27 -.022 L .04 -.125 L .292 -.043 L .195 .104 L .096 -.142 L -.022 -.344 L .072 -.224 L .143 -.011 L h 396.323 103.853 m .375 -.122 L .411 -.365 L .549 -2.299 L .397 -.091 L -.21 -.29 L -.226 .259 L .125 -1.144 L .223 -.826 L .115 .153 L .496 .306 L .191 .382 L .191 .229 L -.281 -.673 L -.63 -.582 L -.242 -.233 L .024 -.249 L .359 -.477 L -.202 -.375 L -.2 -.274 L -.326 -.216 L -.685 -.1 L -.515 -.571 L -.416 -.323 L .278 -.426 L -.233 -.181 L -.343 -.131 L -.511 -.142 L -.184 -.173 L .247 -.376 L -.329 -.173 L -.509 .179 L -.489 -.249 L -.824 -.251 L -.619 -.181 L -.325 .014 L -.215 -.25 L -.91 .167 L -.059 -.25 L -.265 -.125 L -.367 -.042 L -.056 -.104 L .861 -.083 L -.085 -.229 L -.526 -.104 L .442 -.104 L .086 -.205 L -.275 .017 L -.263 -.021 L -.417 .083 L .04 -.438 L .303 .012 L .305 -.146 L .526 -.088 L .562 -.174 L .215 .188 L .18 -.167 L .474 .063 L .112 -.26 L .272 -.059 L .764 -.078 L .393 .366 L .275 .26 L .342 .083 L .652 -.271 L .317 .167 L .276 -.127 L .457 -.124 L .029 .23 L .591 -.065 L .3 -.103 L -.265 -.188 L -.028 -.251 L .056 -.345 L -.037 -.428 L -.131 .021 L -.562 -.682 L -.11 -.407 L .927 .126 L .607 -.105 L -.084 .397 L .248 .419 L .342 -.146 L 1.241 .104 L .501 .146 L .079 -.014 L .525 -.093 L .662 -.27 L -.534 -.124 L .055 -.204 L .166 -.175 L .753 -.322 L .756 -.181 L .902 -.215 L .314 -.235 L .302 -.264 L -.053 -.775 L .135 -.542 L .521 -.25 L .46 -.16 L .916 -.092 L .177 -.096 L .208 .447 L .311 .335 L .266 .127 L .141 -.071 L .41 -.208 L .153 .17 L .202 .458 L .194 .133 L .518 -.012 L .159 .301 L .259 -.012 L .576 .048 L .375 .168 L -.159 .241 L .091 .175 L -.072 .198 L .285 .122 L .406 -.075 L .446 -.035 L .193 -.313 L .245 -.072 L -.119 .373 L .146 .18 L -.039 .228 L .529 .048 L .341 .192 L .371 .204 L .127 .228 L .694 -.174 L .079 .114 L .642 .063 L .568 .011 L .145 .063 L .428 .319 L .337 .277 L .395 -.055 L .045 .145 L .689 -.062 L .072 -.048 L .233 .007 L .095 .186 L .456 .09 L .479 -.014 L .605 .193 L -.954 .806 L -.054 .213 L -.054 .358 L -.321 .372 L -.075 .295 L .091 .076 L -.216 .701 L .135 .233 L -.385 .309 L -.473 -.007 L .005 -.096 L 415.96 94.5 l -.221 .302 L .153 .028 L .116 .089 L -.173 .035 L -.528 .494 L -.012 .076 L -.575 .24 L .038 .315 L -.718 .418 L -.089 .294 L .08 .137 L -.013 .322 L -.238 .226 L .369 .111 L .854 -.668 L .616 -.147 L .312 .806 L .102 .424 L -.624 .301 L .532 .344 L .025 .292 L .43 .192 L -.199 .272 L -.541 .353 L -.183 -.111 L -.437 .186 L .352 .358 L .616 .191 L .135 .331 L -.175 .01 L -.315 .371 L .193 .442 L .754 .391 L .849 -.07 L .062 .281 L -.146 .469 L -.346 .23 L -.221 .215 L -.833 .488 L -.889 .659 L -.427 .087 L -.318 .043 L -.798 .159 L -.405 -.028 L -.471 -.156 L -.851 -.499 L -.315 -.085 L -.354 .029 L -.231 .072 L -.511 -.056 L -.752 -.313 L -.602 .044 L -.731 .345 L -.357 .258 L -.555 .559 L -.147 .386 L .099 .514 L .091 .379 L -.334 -.091 L -.75 .137 L -.039 .136 L -.485 -.015 L -.427 -.197 L -.395 .167 L -.261 -.015 L -.036 -.152 L -.335 -.091 L -.206 .03 L -.374 .076 L -.187 -.076 L -.035 -.289 L -.091 -.213 L -1.252 -.304 L -.355 0 L .017 .319 L -.542 -.015 L -.337 .061 L -.037 -.122 L -.767 .03 L -.084 -.114 L -.028 -.038 L -.431 -.152 L -.131 .076 L -.262 -.03 L -.056 .076 L -.507 -.395 L -.15 .061 L -1.088 -.334 L -.112 .106 L -.15 -.03 L -.094 -.106 L .205 -.243 L -.058 -.122 L -.469 .03 L -.472 -.243 L +681.312 116.395 N .235 -.171 L .283 -.256 L .633 -.738 L .315 -.157 L .595 .011 L .579 .068 L .511 .096 L .309 -.115 L .571 -.678 L .682 .621 L 1.178 1.611 L .329 .495 L .269 .664 L .002 .75 L -.034 .947 L -.129 .637 L .143 .113 L .5 -.043 L -.121 .41 L -.282 .523 L -.5 .75 L -.316 .312 L -.243 .043 L -.567 -.211 L -.256 .1 L -.607 .58 L -.431 -.083 L -.289 -.225 L -.544 .1 L -.526 .199 L -1.188 .835 L -.462 .043 L -.46 .312 L -.055 -.564 L -.056 -.324 L -.163 -.705 L -.137 -.395 L .167 -.453 L .499 -.468 L 0 -.353 L .226 -.425 L -.044 -.141 L -.378 -.311 L -.095 -.296 L .015 -.467 L -.087 -.339 L -.289 -.126 L -.603 -.084 L .654 -.411 L .303 -.114 L .654 .268 L .254 -.241 L -.029 -.283 L -.764 -.89 L -.113 -.311 L -.137 -.105 L +475.646 121.847 N -.018 .175 L .338 .391 L -.295 -.009 L -.132 .108 L -.104 -.059 L -.327 -.021 L -.121 .33 L -.783 .257 L -.384 .046 L -.099 .053 L 0 .21 L -.217 .006 L -.072 -.192 L -.402 .023 L -.547 -.146 L -.191 -.087 L 0 -.21 L -.161 -.105 L -.122 -.403 L .082 -.035 L .12 .1 L .147 -.006 L .405 -.304 L .253 -.006 L .328 .092 L .077 -.086 L .088 -.286 L -.053 -.175 L .627 .093 L .658 .027 L .367 -.056 L .818 -.233 L .689 -.304 L .535 -.158 L -.475 .295 L -.436 .231 L -.596 .444 L +704.404 117.274 N .197 -.099 L 1.108 -.271 L .057 .354 L -.481 .284 L -.232 .241 L -.068 .453 L .139 .367 L .291 .056 L .221 -.114 L .418 -.354 L .24 -.085 L 1.656 -.697 L .389 -.213 L .46 -.326 L .349 -.638 L .76 -.412 L .347 -.327 L .191 -.269 L .142 -.51 L .538 -.582 L -.01 -.142 L .344 -.567 L .159 -.468 L .139 -.609 L -.043 -.467 L -.33 -.198 L -.128 -.24 L .234 -.213 L .166 -.284 L -.155 -1.023 L .544 -.343 L .176 -.242 L .327 -.328 L .192 0 L .21 .355 L .199 .227 L .303 -.058 L .799 -.257 L -.169 -.526 L -.311 -.028 L -.36 -.312 L .694 -.415 L .441 .156 L .336 .227 L .025 .199 L -.016 .868 L .058 .611 L .22 .127 L .243 .312 L .717 1.432 L .001 .496 L -.246 .709 L -.709 .766 L -.226 .439 L .064 .368 L -.15 .071 L -.737 .285 L -.161 .113 L -.164 .199 L -.174 .453 L .02 .396 L .094 .254 L .131 .792 L -.04 .693 L -.686 .751 L -.242 .736 L .02 .707 L .198 .296 L .422 .353 L -.617 .298 L -.193 .127 L -.166 .17 L -.174 .834 L -1.081 .439 L -.094 -.282 L .294 -.665 L .184 -.523 L -.198 -.126 L -.514 .241 L -.578 .623 L -.476 .001 L -.346 .312 L -.066 .748 L -.354 .269 L -.188 -.028 L -.066 -.155 L .003 -.606 L -.149 -.155 L -.211 .042 L -.309 .156 L -.344 .311 L -.325 .523 L -.866 -.055 L -.505 .057 L -.631 .1 L -.458 -.549 L -.685 -.323 L -.26 .254 L -.067 .184 L -.177 .353 L .037 .056 L .417 .197 L .416 .323 L -.293 .198 L -.829 .129 L -.433 .241 L -.463 .622 L -.522 .847 L -.688 -.365 L -.565 -.21 L -.285 -.197 L -.014 -.169 L -.194 -.818 L .099 -.155 L .495 -.325 L .179 -.269 L -.067 -.282 L -.18 -.042 L -.601 .17 L -.341 -.028 L -.789 -.167 L -.475 .128 L -.427 .227 L -.437 .184 L -.269 -.098 L -.256 -.027 L -1.647 .398 L -.814 .298 L -.21 -.31 L -.452 -.042 L -.413 .438 L -.006 .635 L -.756 -.238 L -.579 -.055 L -1.1 .073 L -.267 -.14 L .072 -.339 L .179 -.283 L .483 .013 L .499 -.114 L .751 -.467 L 2.201 -1.953 L .28 -.015 L .427 -.128 L .056 .424 L .495 -.128 L 1.278 -.257 L .933 -.058 L 1.183 -.172 L .892 -.256 L .068 .452 L .377 .268 L .167 -.085 L .654 -.199 L .446 -.34 L -.003 -.353 L .114 -.467 L .465 -.51 L .698 -.581 L .371 -.453 L -.062 -1.117 L .182 -.213 L h 695.464 127.756 m -.292 -.197 L -.223 -.268 L -.101 -.381 L -.177 -.395 L -.492 -.535 L .731 -.382 L .287 -.269 L .456 -.593 L .409 .253 L .615 -.015 L .483 -.185 L .311 -.339 L .451 -.311 L .454 -.029 L .316 .169 L .862 .224 L .153 .254 L -.1 .127 L -.102 .423 L -.292 .24 L -.864 .876 L -.181 -.211 L -.424 -.295 L -.467 -.042 L -.612 .213 L -.193 .184 L -.245 .495 L -.165 .508 L -.153 .212 L -.448 .269 L h 691.12 131.448 m -.366 -.042 L -.056 -.141 L .268 -.537 L .128 -.593 L -.334 -.112 L -.239 .198 L -.155 .466 L -.381 .452 L -.326 -.211 L -.059 -.211 L .322 -.466 L .032 -.296 L -.356 -.917 L .169 -.113 L .687 -.58 L .083 -.141 L .034 -.466 L -.532 -.789 L -.333 -.042 L -.162 .269 L -.419 .495 L -.249 -.112 L -.23 -.508 L -.376 -.267 L -.261 -.366 L .41 -.325 L .733 .083 L .706 -.171 L .315 -.466 L .241 -.283 L .484 -.058 L .478 .056 L .249 .38 L .27 .168 L .43 .084 L .628 -.213 L .225 .395 L -.569 .438 L .405 .239 L .443 .437 L .079 .254 L -.596 .58 L -.242 .41 L -.104 .367 L -.085 .621 L -.109 .649 L -.242 .353 L -.194 .099 L -.165 .071 L -.197 .184 L -.479 .678 L h 711.938 108.369 m -.222 -.241 L -.077 -.271 L .325 -.642 L -.055 -.342 L -.549 -.198 L -.168 -.171 L -.146 -.812 L .583 -.386 L .522 -.172 L .646 -.373 L .037 -.356 L -.318 -.285 L .277 -.3 L .224 -.015 L .661 .427 L .373 .085 L .532 -.201 L -.004 -1.186 L .455 -.187 L .45 -.244 L .074 -.743 L .007 -.844 L -.398 -.758 L -.098 -.473 L .166 -.216 L .618 -.346 L .063 .072 L .507 .43 L .904 .816 L 1.07 .842 L 1.083 .684 L .627 .285 L .528 .17 L 1.02 .198 L .282 .042 L .304 -.086 L .866 -.66 L .461 -.144 L .002 .1 L -.308 .358 L -.335 .558 L .198 .414 L .469 .599 L .197 .356 L -.561 .272 L -.447 .244 L -.534 .158 L -.365 .015 L -.488 -.199 L -.453 .015 L -.363 .144 L -.345 .229 L -.754 .786 L -.396 .5 L -.26 .599 L -.4 -.07 L -.425 -.241 L -2.031 -.965 L -.461 -.085 L -.72 .044 L -1.038 .587 L -.153 -.299 L -.372 -.356 L -.339 .029 L -.266 .115 L -.439 .272 L .049 .299 L 1.16 .497 L .56 .298 L .302 .27 L -.391 .214 L -.303 .029 L -.305 -.128 L -.261 .043 L -.324 .314 L -.388 .471 L -.347 .114 L +597.917 139.685 N 1.251 -1.545 L .609 -.539 L .348 -.239 L .149 -.103 L .417 -.016 L .309 .294 L .479 .208 L 1.659 .047 L .371 .041 L .312 .209 L .329 .619 L -.07 .156 L .042 .24 L .326 .294 L .313 .069 L .258 .238 L .017 .282 L -.217 .58 L -.624 .06 L -1.036 .062 L -1.238 -.063 L -.335 -.125 L -.301 -.055 L -.531 .313 L -.544 .074 L -.085 -.021 L -.869 -.214 L -.559 -.081 L -.637 -.18 L -.235 -.493 L .092 -.113 L +362.764 152.723 N .072 -.625 L .395 -.876 L .52 -.552 L .488 -.566 L .244 -.509 L 1.175 -2.559 L .238 -.241 L 1.404 -1.175 L .345 -.495 L .051 -.918 L .305 -1.088 L .651 -1.075 L .399 -.34 L .404 -.198 L .838 -.51 L .361 -.495 L .334 -.777 L .428 -.851 L 1.635 -.04 L 2.511 0 L 2.677 -.001 L 1.718 .004 L 1.42 -.008 L .027 .876 L -.03 1.752 L .002 .65 L -.104 .396 L -.56 -.011 L -6.005 -.022 L -.557 .074 L -.047 .509 L -.07 2.261 L -.099 2.6 L -.144 .128 L -.809 .287 L -.726 .315 L -.575 .427 L -.249 .383 L -.01 .707 L .164 1.539 L .051 1.102 L -.212 -.027 L -.732 .033 L -2.396 -.014 L -5.055 -.056 L -.474 -.013 L +514.551 145.841 N -.374 .027 L -.336 -.083 L -.008 -.615 L -.153 -.437 L -.108 -.791 L .187 -.607 L .188 -.11 L -.059 -.187 L .177 -.607 L .33 -.269 L .312 .083 L .069 .315 L .26 .093 L .063 .199 L .116 .326 L -.106 .42 L .031 .708 L .118 .254 L -.104 .381 L -.327 .467 L -.275 .433 L +514.177 145.868 N .374 -.027 L .008 .288 L .361 .14 L .153 .128 L .186 -.093 L -.046 .443 L .397 .001 L .402 .127 L .687 -.093 L .103 -.21 L .183 -.058 L .218 .117 L .424 -.042 L .595 .112 L .224 -.035 L .079 -.105 L 1.358 .222 L .732 -.14 L -.022 -.292 L .225 .175 L .375 -.016 L .157 -.099 L .312 -.422 L .232 -.073 L .267 -.495 L .131 -.297 L .711 -.637 L .813 -.889 L .163 .105 L .229 -.178 L .85 -.708 L .313 -.433 L .15 .161 L -.248 .42 L -.107 .299 L -.004 .176 L .099 .064 L .121 -.024 L .454 .042 L .09 .324 L .001 .508 L -.003 .358 L -.49 .034 L -.401 -.083 L -.107 .396 L .073 1.326 L -.199 .34 L -.536 .596 L .003 .946 L .024 2.075 L .063 .183 L -.152 .057 L -.584 .469 L -.839 -.108 L -3.387 -.446 L -3.362 -.375 L -.261 -.902 L -.548 -1.154 L -1.043 -2.198 L +668.627 151.365 N -.102 -.056 L -.107 -.325 L -.922 -1.212 L -.332 -.987 L -.03 -.438 L .156 -.749 L .546 -.792 L 1.312 -1.852 L .259 -.184 L .425 -.128 L .229 -.184 L .358 -.227 L .228 .127 L .554 .394 L -.334 .424 L -.084 .142 L .023 .31 L -.067 .622 L -.203 .296 L -.182 .354 L -.065 .692 L -.1 .494 L -.317 .805 L -.473 .707 L -.417 .833 L -.014 .353 L -.114 .438 L -.228 .142 L +389.765 144.543 N .1 .084 L .895 .531 L 2.054 1.344 L .811 .575 L 3.283 2.241 L 1.924 1.26 L 1.292 .824 L .397 .253 L 2.472 1.469 L .181 .253 L -.096 .396 L .082 .183 L .393 .28 L 1.111 1.039 L .229 .027 L .47 -.314 L .588 .562 L .375 .167 L .748 .024 L .309 .111 L .277 .352 L .099 .522 L -.161 .679 L .146 .564 L 2.176 -.408 L .064 1.017 L .034 2.203 L .001 .96 L -.08 .89 L -.145 .919 L -.434 1.246 L -.596 .794 L -.339 .271 L -.29 .129 L -2.533 .085 L -1.808 .124 L -.209 .072 L -.562 .427 L -.579 .272 L -.678 -.053 L -.581 -.081 L -1.062 -.173 L -.36 -.059 L -.356 -.125 L -.37 .073 L -1.22 .713 L -.947 .458 L -.304 .228 L -.314 .793 L -.274 -.027 L -.324 -.182 L -.518 -.209 L -.272 .101 L -.638 .625 L -.492 .667 L -.393 .822 L -.174 .227 L -.45 .102 L -.551 -.364 L -.293 -.281 L -.273 .058 L -.397 .384 L -.355 1.217 L -.292 1.047 L -.317 .369 L -.543 .271 L -.448 .158 L -.257 .016 L -.141 .255 L .058 .749 L -.133 .876 L -.261 .92 L -.172 .326 L -.046 .156 L -.08 .043 L -.159 .1 L -.604 .399 L -.352 .059 L -.148 -.239 L -.117 -.381 L -.004 -.297 L -.147 -.211 L -.257 -.041 L -.239 .114 L -.571 .483 L -.362 .469 L -.35 .228 L -.455 -.436 L -.566 -.321 L -.352 .059 L -.522 .54 L -.559 -.901 L -.194 -1.143 L -.349 -.718 L -.474 -.478 L -.265 -.451 L -.271 -.832 L -.022 -.339 L -.246 -.281 L -.323 -.055 L -.684 .428 L -.3 .327 L -.43 .243 L -.565 -.152 L -.356 -.153 L -.338 -.026 L -.475 .413 L -.252 .256 L -.536 -.265 L -.882 -.715 L -.18 -.183 L -.113 -.028 L .062 -.142 L .004 -.565 L -.082 -.833 L -.265 -.337 L -.554 -.322 L -.181 -.197 L -.22 -.479 L -.144 -.663 L -.251 -1.1 L .057 -.339 L .506 -.399 L .332 -.284 L .018 -.607 L .181 -.552 L .252 -.256 L .402 -.073 L .261 .111 L .568 .83 L .214 .168 L .454 .082 L .107 -.269 L -.055 -.296 L .06 -.212 L .535 .124 L .713 .137 L .485 .054 L .387 -.031 L .945 -.344 L 1.953 -.026 L 6.457 -.01 L .379 -1.613 L -.724 -.787 L -.186 -1.468 L -.202 -2.386 L -.325 -2.753 L -.178 -1.736 L -.19 -1.468 L -.908 -7.962 L -.049 -.776 L 3.231 -.089 L .523 -.13 L +525.37 142.384 N .312 -.429 L .155 -.17 L .084 .833 L -.423 .707 L -.118 .156 L -.121 .024 L -.099 -.064 L .004 -.176 L .107 -.299 L .248 -.42 L -.15 -.161 L h 525.923 144.712 m 0 .22 L .456 .762 L .408 .465 L .782 .634 L .677 .394 L 1.008 .52 L .392 .154 L .277 .014 L .576 -.029 L .364 .112 L .873 .973 L .518 .648 L .46 .422 L .81 .365 L .025 .212 L -.67 1.06 L -.615 .721 L -.883 .807 L -.776 1.541 L -.242 .142 L -.562 -.083 L -.235 -.084 L -.252 .071 L -.278 .509 L -.062 1.115 L .001 .791 L .134 .621 L -.403 .142 L -1.046 .073 L -.627 .27 L -.367 .283 L -.29 .495 L -.131 .551 L -.204 .283 L -.444 .255 L -.544 .1 L -.292 0 L -.386 -.042 L -.326 .029 L -.382 .283 L -.22 .297 L -.125 .508 L .003 .353 L -.091 .311 L -.631 .396 L -.344 .043 L -.776 -.21 L -.717 .058 L -.896 .27 L -.768 .298 L -.283 .099 L -.416 .145 L -.241 -.306 L -.483 -.689 L .006 -.296 L -.127 -.253 L -.933 -1.364 L -.604 -.971 L -.226 -.634 L -.092 -.663 L 1.691 -.815 L 2.35 -1.213 L 5.346 -2.982 L -.155 -1.453 L -.581 -.914 L -.063 -.183 L -.024 -2.075 L -.003 -.946 L .536 -.596 L .199 -.34 L -.073 -1.326 L .107 -.396 L .401 .083 L .49 -.034 L +405.733 173.04 N -.568 -.971 L -.562 -.025 L -.37 .044 L -.516 -.181 L -.97 -.757 L -.114 -.226 L .335 -.439 L -.018 -.212 L -.179 -.268 L -.502 -.42 L -.389 -.266 L -.422 -.492 L -.426 -.93 L -.019 -.396 L .173 -.665 L .581 .081 L .678 .053 L .579 -.272 L .562 -.427 L .209 -.072 L 1.808 -.124 L 2.533 -.085 L .29 -.129 L .339 -.271 L .596 -.794 L .434 -1.246 L .145 -.919 L .08 -.89 L -.001 -.96 L -.034 -2.203 L -.064 -1.017 L 1.672 -.321 L 1.82 -.364 L 3.084 -2.617 L .834 -.655 L 2.308 -1.454 L 1.607 -.956 L 4.012 -2.241 L 1.632 -.843 L .265 -.186 L .832 .137 L 1.646 .442 L 1.008 .333 L .258 .182 L 1.192 .911 L .231 -.157 L 1.519 -.729 L .364 2.145 L .169 1.298 L .42 1.028 L .554 .802 L .703 .604 L -.388 .722 L -.265 .99 L -.168 1.088 L -.084 .989 L .022 .537 L -.062 .707 L -.019 1.045 L -.034 1.088 L -.056 .466 L -2.43 2.613 L -.591 .78 L -.87 1.333 L -.572 .794 L -.007 .678 L .123 .719 L .014 .269 L -.951 .034 L -.437 .2 L -.453 .299 L -.761 .697 L -.259 .058 L -.609 -.208 L -.724 -.193 L -.884 -.221 L -.531 -.04 L -.709 .047 L -.628 .103 L -.774 .287 L -.403 .327 L -.629 .399 L -.273 .059 L -.934 .005 L -.965 -.277 L -1.173 -.742 L -.354 -.083 L -.467 .116 L -1.337 .544 L -.37 .002 L -.209 -.098 L -1.095 -1.223 L -.821 -.277 L -1.111 -.121 L -1.174 .108 L -1.064 .188 L -.676 .4 L -.687 1.614 L -.353 .482 L -.158 .849 L -.092 .961 L -.902 -.503 L -.727 -.589 L -.339 -.28 L -.321 .073 L -.577 .3 L +431.763 171.063 N -.351 -.407 L -.575 -.52 L -.173 -.394 L -.014 -.269 L -.123 -.719 L .007 -.678 L .572 -.794 L .87 -1.333 L .591 -.78 L 2.43 -2.613 L .056 -.466 L .034 -1.088 L .019 -1.045 L .062 -.707 L -.022 -.537 L .084 -.989 L .168 -1.088 L .265 -.99 L .388 -.722 L -.703 -.604 L -.554 -.802 L -.42 -1.028 L -.169 -1.298 L -.364 -2.145 L 1.818 -.858 L .41 -.059 L 5.231 2.554 L 4.941 2.372 L 5.577 2.792 L 1.981 .963 L -.02 1.045 L -.016 .946 L -.036 .636 L .085 2.5 L -.038 .749 L .036 1.002 L .031 1.229 L -.04 .283 L -.839 -.009 L -1.245 .05 L -.229 .143 L -.417 1.245 L -.583 .809 L -.122 .438 L .131 .677 L -.149 .212 L -.718 .428 L -.053 .24 L .342 .662 L -.087 .34 L -.542 .596 L -.316 .609 L .219 .352 L .517 -.088 L .338 .012 L .141 .225 L .221 1.228 L .137 .522 L .155 .295 L .444 .407 L .266 .465 L .026 .367 L -.15 .425 L -.559 -.208 L -.321 -.012 L -.322 .086 L -.939 .613 L -.372 .228 L -.165 .382 L -.005 .41 L -.196 .284 L -2.649 2.275 L -.386 .087 L -2.181 .055 L -.434 .059 L -.209 .199 L -.117 .806 L -.646 1.176 L -.258 .143 L -.368 .031 L -.881 -.009 L -.818 .273 L -.754 .386 L -.466 .271 L -.224 .03 L -.225 -.069 L -.494 -.661 L -1.363 .686 L -.449 .158 L -.24 -.027 L -.096 -.084 L -.208 -.183 L -.382 -1.057 L -.638 -1.07 L -1.343 -1.179 L -1.088 -1.067 L .323 -.539 L .29 -.312 L .24 -.1 L .481 .082 L 1.187 .191 L .674 -.032 L .225 -.143 L -.047 -.127 L -.208 -.21 L -.381 -.633 L -.205 -.578 L -.169 -1.228 L .134 -.651 L -.119 -1.2 L -.395 -.887 L -.923 -1.238 L -.208 -.083 L -.627 -.109 L +627.173 150.012 N .483 -.229 L .515 -.13 L .341 .012 L .597 .392 L .325 .097 L .584 -.413 L .332 -.115 L 1.595 -.052 L .807 -.117 L .341 -.157 L .696 -.554 L .521 -.328 L .298 -.101 L .623 .575 L .771 .235 L .66 .053 L .777 -.047 L .237 .21 L .056 .38 L -.472 .75 L .096 .521 L .273 .365 L .943 .615 L .621 .166 L .909 .107 L .197 .143 L -.19 .132 L -.826 .482 L .106 .465 L -.203 .212 L -1.261 -.054 L -.136 .198 L .057 .395 L -.283 .382 L -.585 .792 L -.221 .142 L -.533 .241 L -.171 .127 L -.27 .396 L -.303 .932 L -.388 .975 L .268 .225 L .469 .563 L 1.112 1.071 L .023 .24 L .042 .522 L .087 .254 L .42 .493 L 1.096 .83 L 1.282 1.296 L .26 .197 L .636 .069 L .313 .38 L .282 1.016 L .302 .578 L .638 .605 L .293 .663 L .341 1.382 L .524 2.809 L -.295 .438 L -.235 .495 L .05 .819 L -.095 .41 L .056 .664 L -.027 .099 L -.364 .551 L -.447 .439 L -.254 .127 L -.509 .1 L -.419 .17 L -.501 .354 L -.591 .622 L -.579 .354 L -.325 .043 L -.512 -.197 L -.404 -.31 L -.179 -.141 L -.153 .424 L .051 .494 L .048 .353 L -.205 .721 L -.388 .424 L -.326 .071 L -.235 -.07 L -.246 .481 L -.427 .326 L -.523 .142 L -.417 .213 L -.459 .565 L -.196 .269 L -.406 .297 L -.264 .099 L -.365 -.042 L .078 -.861 L .1 -1.313 L .151 -.494 L .215 -.283 L -.02 -.353 L -.475 -.437 L -.749 -.238 L -.091 -.066 L .3 -.289 L .646 -.229 L .915 -.528 L .599 -.229 L .497 .011 L .688 .194 L .17 -.27 L -.03 -.197 L -.568 -.435 L -.216 -.422 L .234 -.425 L .99 -.571 L .521 -.229 L .932 -.443 L .599 -.187 L .385 -.285 L .217 -.509 L -.054 -1.073 L .05 -.424 L .076 -.367 L -.455 -1.014 L -.029 -.663 L .215 -.905 L .155 -.918 L -.064 -.578 L -.214 -.437 L -.529 -.477 L -.072 -.282 L .226 -.439 L -.136 -.395 L -.358 -.308 L -.685 -.391 L -.471 -.52 L -.57 -.914 L -1.683 -2.121 L -.698 -.772 L -.637 -.646 L -.632 -.476 L -1.234 -.741 L -.162 -.098 L -.043 -.494 L .277 -.369 L .311 -.101 L .476 .068 L .287 -.058 L .261 -.185 L .255 -.326 L -.009 -.508 L -.87 -.968 L -.434 -.675 L -.262 -.083 L -.39 .171 L -.509 .483 L -.287 .058 L -.47 -.195 L -.607 -.434 L -.334 -.689 L -.338 -.929 L -.543 -.604 L -.613 -.575 L -.45 -.745 L +217.961 150.385 N .304 -.043 L .84 -.27 L -.17 -.254 L -.312 -.112 L -.369 -.056 L -.651 .016 L -.497 -.042 L -.645 .157 L -1.193 .92 L -.371 .029 L -.653 .001 L -.211 .113 L -.189 .452 L -.396 .284 L -.32 .043 L -.786 .086 L .259 -.325 L .473 -.312 L -.128 -.593 L .282 -.382 L .114 -.099 L 1.258 -.61 L 1.625 -.47 L 1.164 -.087 L .842 -.157 L .825 .041 L .566 -.044 L .73 .168 L .848 .083 L .603 .197 L .557 .112 L .477 .013 L .499 .268 L .573 .536 L .382 .253 L .581 .168 L .768 .111 L 1.229 .351 L 1.02 .492 L .453 .31 L .374 .55 L .33 .141 L .479 .041 L 1.704 .519 L 1.018 .167 L .327 .239 L -.344 .58 L .233 .155 L .559 .042 L .756 -.072 L .495 .168 L .507 .38 L .591 .281 L .381 .296 L -.233 .085 L -.981 .087 L -1.15 .398 L -.626 .058 L -1.054 -.209 L -.9 -.041 L -.934 .186 L -.943 .115 L -.484 .029 L -.449 -.07 L .353 -.382 L .728 -.623 L .173 -.396 L 229 154.204 l -.181 -.127 L -.622 -.14 L -.7 .001 L -.603 -.112 L -.651 -.338 L -.141 -.748 L -.258 -.536 L -.218 -.155 L -.396 -.027 L -1.005 .044 L -.836 -.139 L -.621 -.225 L -.956 -.493 L -.739 -.238 L -.615 -.069 L -1.154 -.068 L -.489 -.098 L -.855 -.352 L +634.036 168.444 N .808 -.64 L .121 -.438 L -.002 -.945 L -.157 -.507 L -.419 -.703 L -.979 -1.279 L -.255 -.464 L -.107 -.366 L -.058 -1.524 L -.435 -.632 L -.688 -.659 L -.285 -.535 L -.052 -.282 L -.266 -.153 L -.893 -.192 L -.403 -.012 L -.286 .453 L -.2 .538 L -.543 .257 L -.223 .072 L -.59 -.265 L -.835 -.348 L -.346 .03 L -1.173 1.178 L -.37 .411 L -.481 -.138 L -.145 -.324 L .027 -.494 L .117 -.438 L .528 -1.569 L .085 -.41 L -.249 -1.311 L -.045 -.113 L -.414 .045 L -.489 .2 L -.423 .003 L -.186 -.154 L -.066 -.367 L .106 -.805 L -.01 -.423 L -.118 -.168 L -.295 -.182 L -.541 -.166 L .193 -.185 L .582 -.455 L .442 -.581 L .53 -.61 L .502 -.355 L .178 .196 L .321 .21 L .769 .08 L .266 -.213 L .109 -.339 L -.119 -.521 L -.228 -.366 L -.138 -.592 L .043 -.325 L .24 -.241 L .679 -.314 L .45 .745 L .613 .575 L .543 .604 L .338 .929 L .334 .689 L .607 .434 L .47 .195 L .287 -.058 L .509 -.483 L .39 -.171 L .262 .083 L .434 .675 L .87 .968 L .009 .508 L -.255 .326 L -.261 .185 L -.287 .058 L -.476 -.068 L -.311 .101 L -.277 .369 L .043 .494 L .162 .098 L 1.234 .741 L .632 .476 L .637 .646 L .698 .772 L 1.683 2.121 L .57 .914 L .471 .52 L .685 .391 L .358 .308 L .136 .395 L -.226 .439 L .072 .282 L .529 .477 L .214 .437 L .064 .578 L -.155 .918 L -.209 .114 L -.975 .429 L -.3 .072 L -.373 -.351 L -.444 -.181 L -.476 .186 L -.392 .285 L .107 .296 L .187 .182 L .103 .211 L -.095 .24 L -.248 .058 L -.469 -.251 L -.341 -.111 L -.736 -.165 L -.533 -.251 L +60.074 72.607 N -.099 .228 L -.491 .472 L -.395 .183 L -.462 .062 L 58 73.461 l -.961 -.362 L -.153 -.197 L .169 -.289 L .54 -.274 L .341 -.32 L .716 .364 L .3 .091 L .465 -.26 L .215 -.213 L .064 -.366 L .485 -.047 L 1.107 .135 L .536 .334 L .133 .213 L -.756 .062 L -.429 0 L -.59 .184 L -.11 .092 L h 40.092 77.571 m -.729 -.029 L -.097 -.24 L .011 -.3 L .802 -.243 L .326 -.211 L .593 -.423 L .448 -.137 L .646 -.077 L 1.427 .253 L .711 .24 L -.079 .211 L -.303 .046 L -.754 -.074 L -.496 .031 L -1.077 .183 L -.269 .226 L -1.161 .543 L h 38.426 77.979 m -.515 -.209 L -.139 -.285 L .381 -.227 L .674 .27 L .093 .195 L -.122 .15 L -.372 .105 L h 37.896 78.449 m -.256 .084 L -.558 .151 L -1.109 -.058 L -.387 .135 L -.398 .434 L -.31 .15 L -.854 -.207 L -.135 -.224 L .497 -.359 L .5 -.315 L .955 -.166 L .863 -.346 L .39 .089 L .461 .224 L .341 .409 L h 29.628 81.29 m -.168 -.594 L -.324 -.476 L .839 -.136 L .424 .088 L .436 .238 L -.244 .268 L -.26 .06 L -.073 .297 L -.22 .09 L -.412 .164 L h 27.543 81.591 m -.39 .031 L -.741 .165 L -.311 -.133 L -.088 -.178 L .104 -.119 L .336 -.268 L .294 -.09 L .584 .222 L .212 .371 L h 54.394 157.986 m -.559 -.356 L -.044 -.884 L -.243 -.677 L .482 -.402 L -.035 -.2 L -.156 -.26 L .052 -.149 L .173 -.046 L .354 .158 L .652 .279 L .593 .425 L -.015 .275 L .238 .046 L .12 .287 L .306 .149 L -.062 .161 L 56 156.933 l -.172 .204 L -.766 .195 L -.374 .23 L -.295 .425 L h 23.015 59.92 m -1.613 -.646 L -.75 -.205 L -.792 -.062 L -.9 .065 L -.291 -.095 L -.431 -.222 L .179 -.287 L .516 -.049 L 1.135 .221 L .579 -.001 L .543 -.081 L .538 -.001 L .828 .285 L 1.725 .362 L .429 .237 L .046 .111 L -.569 -.03 L -.646 .033 L -.527 .365 L h 99.855 70.993 m .467 .929 L -.071 .167 L -.879 -.272 L -.621 -.075 L .067 .441 L -.056 .228 L -.935 -.607 L 97.03 71.41 l .396 -.458 L .263 -.153 L .612 -.078 L .784 .38 L .771 -.108 L h 100.975 73.606 m .128 .272 L -.086 .273 L -.318 .483 L -.559 -.815 L -.597 -.909 L -.04 -.228 L .095 -.213 L .407 .029 L .568 .197 L .402 .91 L h 106.858 78.207 m -1.872 -1.166 L -.566 -.555 L .01 -.467 L -.559 -.843 L .071 -.106 L .456 .06 L .274 .256 L 1.165 .48 L .086 .196 L -.059 .136 L -.149 .226 L .296 .436 L .839 .374 L .007 .974 L h 140.191 127.819 m -.043 -.094 L -.198 -.36 L -.049 -.067 L -.032 .042 L -.028 .05 L -.04 -.092 L .002 -.664 L -.331 -.604 L -.472 -.451 L -.661 -.451 L -.512 -.197 L -.114 -.052 L -.145 .034 L .002 .092 L -.088 .025 L -.1 -.042 L -.146 -.143 L .076 -.076 L -.073 -.202 L -.228 -.252 L -.283 -.025 L -.312 .084 L -.932 -.336 L -.286 -.328 L -.428 -.244 L -.383 .042 L -.932 -.16 L -.721 .051 L -.12 -.185 L -.234 -.067 L -.046 -.177 L .094 -.117 L -.157 -.504 L .133 -.464 L -.227 -.096 L -.127 .008 L -.249 -.134 L 0 -.101 L .075 -.093 L -.029 -.219 L -.347 -.185 L -.254 -.286 L -.415 -.219 L -.391 -.623 L -.202 -.076 L -.203 -.311 L -.409 -.219 L -.156 -.529 L -.002 -.227 L .178 .007 L .147 -.164 L .029 -.326 L -.208 -.251 L -.192 -.045 L -.22 .037 L -.303 -.126 L -.535 -.514 L .078 -.21 L -.091 -.312 L -.129 -.067 L -.044 -.463 L .058 -.152 L .119 -.025 L .099 .067 L .073 .076 L -.086 .101 L .153 .202 L .285 .126 L .116 .118 L .203 .017 L -.385 -.564 L -.183 -.144 L -.021 -.236 L -.184 -.109 L -.051 -.344 L -.13 .006 L -.011 .144 L .048 .446 L -.093 .017 L -.293 -.194 L -.119 .042 L -.516 -.404 L -.136 -.363 L -.377 -.514 L -.531 -.379 L -.624 -.583 L -.123 -.142 L .114 -.101 L -.327 -.751 L .161 -.43 L -.254 -.479 L -.22 -.355 L -.738 -.782 L -.104 -.299 L .099 -.627 L .252 -.628 L .166 -.357 L .059 -.856 L -.215 -.785 L -.692 -1.486 L -.153 -.916 L .096 -.287 L .231 -.244 L .402 -.201 L .365 -.717 L -.365 -.573 L -.066 -.33 L .424 -1.593 L .153 -.575 L .061 -.634 L .091 -.778 L .019 -.179 L -.153 -.16 L .08 -.231 L -.103 -.167 L .157 -.077 L -.03 -.186 L -.046 -.186 L -.031 -.103 L -.004 -.058 L .322 .096 L .209 -.019 L .062 -.097 L -.211 .006 L -.614 -.122 L .062 -.707 L -.103 -.328 L .017 -.277 L .587 -.225 L -.345 -.019 L -.16 -.142 L -.129 0 L -.053 .045 L .042 .116 L -.12 .052 L -.133 -.979 L -.927 -1.463 L -.017 -.465 L .129 -.131 L .544 .086 L .632 .217 L .785 .114 L .641 .028 L .546 -.044 L .415 .086 L .547 .318 L .039 .435 L -.42 .407 L -.413 .347 L .532 .146 L .184 .188 L .251 .169 L .029 -.228 L .161 -.232 L .393 -.305 L .21 -.581 L .102 -.465 L -.064 -.421 L -.356 -.958 L -.158 -.305 L -.655 -.516 L .194 .013 L 2.579 .001 L 1.335 .022 L 4.588 -.025 L 3.938 .008 L 2.87 -.001 L 1.687 .006 L 5.117 -.028 L .74 .011 L 4.13 .021 L 1.089 -.035 L 3.821 .023 L .875 -.005 L 3.617 -.004 L 4.84 .018 L .601 -.003 L 2.935 .014 L 2.131 -.012 L 2.781 .029 L 2.915 -.016 L 2.105 .003 L 1.348 -.007 L 2.798 .029 L 2.687 -.029 L .68 .003 L -.387 -.588 L -.131 -.347 L .501 -.036 L .896 .748 L .279 .371 L .468 .46 L .833 .451 L .518 -.076 L 1.425 .208 L .02 .185 L .271 -.012 L .338 .48 L .16 -.247 L .502 .013 L .241 .271 L .469 .086 L .064 .185 L .506 .098 L .573 -.141 L .219 -.06 L .412 -.191 L .373 -.075 L .028 .282 L .197 .116 L .855 -.083 L .474 .041 L .156 .115 L .196 .144 L .542 -.049 L .707 .074 L 1.469 -.592 L .805 -.189 L .797 .227 L .977 .386 L 3.975 1.576 L 2.15 1.061 L .101 .429 L .46 .465 L .628 -.024 L .178 .135 L .184 .294 L .916 .181 L .307 .235 L -.11 .318 L .26 .33 L 2.529 1.05 L .876 3.16 L .054 .545 L -.028 .746 L -.377 .576 L -.294 .544 L -.264 .433 L -.414 .294 L -.707 .525 L -.044 .218 L .012 .33 L .371 .427 L .497 .169 L .573 .068 L .524 -.117 L .925 -.506 L .939 -.478 L .88 -.262 L .919 -.062 L .944 -.163 L 1.464 -.452 L .875 -.427 L -.047 -.362 L -.16 -.471 L -.018 -.319 L .162 -.375 L .47 -.203 L .93 -.091 L 1.123 .01 L 1.305 .138 L 1.156 -.197 L .44 -.275 L .163 -.512 L .146 -.434 L .545 -.164 L 1.754 -.814 L .534 -.305 L .968 -.523 L 1.76 -.009 L 2.508 .029 L 1.855 .004 L 1.093 .095 L .174 -.375 L .363 -.435 L .402 -.06 L 1.161 .124 L 1.139 -1.45 L 1.139 -2.22 L .514 -.626 L .632 -.526 L .273 .085 L .505 .36 L .381 .085 L .41 -.176 L .771 .025 L .488 .288 L .174 .274 L .31 2.819 L -.077 .229 L .606 .231 L .224 0 L .042 .154 L -.143 .069 L .02 .256 L -.192 .077 L .16 .291 L .188 -.153 L .349 .495 L -.268 .281 L .299 -.04 L .171 .093 L -.511 .374 L -.509 .093 L -.297 -.12 L -.013 .253 L -.138 .067 L -.077 -.107 L -.231 -.08 L -.277 .133 L -.101 .28 L -.171 -.013 L -.15 .16 L -.175 -.347 L -.746 .28 L -.204 -.093 L .12 .413 L -.666 -.213 L .199 -.48 L -.149 -.04 L -.364 .52 L -.332 .56 L -.342 .333 L -.324 -.227 L -.249 .439 L -.346 -.08 L .122 -.307 L -.325 .253 L .165 .16 L -.326 .293 L -.318 -.133 L .105 -.226 L -.654 .253 L .065 .359 L -.264 .04 L -.161 .373 L -.352 .106 L -.333 .679 L -.404 .505 L .173 .146 L .068 .212 L .168 .053 L .083 -.08 L .169 .013 L -.122 .146 L -.547 .106 L .053 .093 L -.392 .292 L -.068 .159 L .337 .027 L .282 .093 L .599 .704 L .055 .398 L .399 .106 L .691 -.239 L -.022 -.186 L -.14 -.027 L -.254 -.279 L -.097 -.04 L -.009 -.066 L .196 0 L .23 .133 L .218 .358 L .031 .425 L -1.599 .292 L -.032 -.385 L -.124 -.066 L -.109 .226 L -.164 .04 L -.03 .093 L -.105 -.106 L -.159 .266 L -.164 .04 L -.294 .04 L -.045 -.332 L .198 -.332 L -.443 .119 L -.154 -.146 L -.082 .252 L -.087 .664 L -1.429 .132 L -1.694 .159 L -1.182 .345 L -.787 .358 L -.097 .212 L -.32 .053 L -.144 .172 L -.032 -.04 L .308 -.756 L .024 -.106 L -.071 .027 L -.41 .994 L -.079 -.08 L -.406 .292 L .218 .318 L .553 .093 L -.46 1.515 L -.302 .429 L -.259 -.092 L .043 .251 L -.062 .185 L -.237 .145 L -.462 .501 L -.292 .304 L -.167 .026 L -.075 -.119 L .177 -.31 L -.113 -.178 L -.43 .013 L -.447 -.343 L -.148 -.053 L -.329 -.541 L .315 -.257 L .151 -.245 L -.271 .119 L -.362 .37 L .489 .845 L .033 .356 L .387 .581 L .28 .066 L .104 .765 L -.101 .238 L -.151 .23 L -.125 -.013 L -.487 .666 L -.396 .798 L .034 .053 L -.13 .132 L -.107 -.125 L -.374 .725 L .026 .125 L -.226 .04 L -.137 -.263 L .342 -.864 L .195 -.29 L .247 -.119 L .061 -.237 L -.093 -.059 L -.374 .119 L .226 -.383 L -.218 .04 L -.176 -.093 L .012 -.191 L .242 -.04 L -.077 -.33 L -.439 .296 L -.241 -.204 L -.157 .053 L -.23 -.396 L .355 -.171 L .357 -.053 L -.005 -.06 L -.604 -.316 L -.092 .165 L -.072 0 L .107 -.323 L .089 -.02 L .21 .159 L .131 -.06 L -.098 -.224 L -.353 -.066 L -.065 -.112 L .096 -.112 L .336 .02 L .193 -.284 L -.281 .046 L -.158 -.059 L .241 -.37 L .652 -.152 L -.328 -.06 L .146 -.409 L -.28 .093 L -.096 .132 L .11 .079 L -.315 .191 L -.035 -.224 L -.093 .053 L .051 .224 L -.081 .086 L -.051 -.158 L -.097 -.066 L -.103 .416 L -.447 -.079 L .402 .501 L -.294 .666 L .07 .237 L .272 .488 L -.055 .139 L -.466 -.317 L -.1 -.211 L .026 .205 L .174 .218 L .421 .237 L .132 .508 L -.631 -.402 L -.354 -.007 L -.118 -.283 L -.155 -.053 L .066 .25 L -.541 -.323 L -.33 .04 L .015 -.29 L .427 -.323 L -.428 .079 L -.19 .468 L .204 .231 L .457 .046 L .202 .25 L .954 .297 L -.047 .092 L .554 .165 L .158 .132 L -.22 .468 L -.227 .06 L -1.042 -.804 L .708 .811 L .626 .171 L -.248 .092 L .323 .079 L -.045 .079 L .061 .06 L -.034 .25 L -.312 -.191 L -.071 .073 L .104 .211 L -.216 .02 L -.656 -.56 L -.023 .026 L .419 .475 L .309 .158 L .182 -.026 L .191 .21 L .018 .31 L -.298 .059 L -.492 -.534 L -.474 -.198 L -.199 .16 L .046 .044 L .44 .145 L .488 .382 L -.047 .237 L .442 -.033 L .031 -.119 L .748 .119 L .151 .382 L .406 1.212 L .448 .803 L -.14 -.092 L -.262 -.349 L -.059 -.132 L -.359 -1.172 L -.147 -.277 L -.056 .31 L .135 0 L .034 .198 L -.292 -.066 L .173 .283 L .144 .099 L .228 .58 L -.144 -.053 L -.211 -.382 L .002 .224 L -.52 -.303 L -.06 .059 L .266 .303 L -.247 .119 L -.526 -.204 L .225 .204 L -.375 .211 L -.173 -.02 L -.251 -.21 L -.024 -.217 L .083 -.158 L -.081 -.053 L -.091 .204 L .044 .23 L .116 .211 L -.107 .158 L .894 .02 L .571 -.145 L .125 .165 L -.113 .191 L -.072 .369 L .14 .066 L .092 -.257 L .135 -.369 L .18 -.105 L .266 .31 L .047 .296 L -.166 .25 L -.163 -.013 L -.063 -.099 L -.316 .474 L -.254 .197 L -.483 -.053 L -.203 -.065 L -.147 -.066 L -.136 -.245 L -.151 .014 L .141 .244 L -.075 .013 L -.538 -.125 L -.436 -.151 L .162 .185 L .269 .026 L .833 .335 L -.034 .119 L -.396 .145 L .247 .007 L -.19 .25 L -.281 .138 L -.149 0 L -.481 -.375 L .242 .395 L .43 .164 L .302 -.171 L .292 .026 L .11 -.204 L .04 .178 L .217 .04 L .048 .079 L -.428 .322 L -.013 .085 L -.261 .072 L -1.498 .214 L -.865 .895 L -.487 .609 L -.13 .127 L -.935 .143 L -.528 .128 L -.617 .241 L -.678 .539 L -.225 .424 L -.096 .354 L -.819 .694 L -.693 .383 L -.429 .199 L -.797 .086 L -.35 .58 L -.177 .198 L -.809 1.125 L -.273 .781 L -.459 1.249 L .236 1.455 L .387 .925 L .456 .873 L .934 1.562 L .352 1.746 L .486 1.194 L -.075 .092 L .287 .276 L .123 .333 L .062 .827 L -.301 1.536 L -.064 .278 L -.31 .415 L .108 .424 L -.02 .252 L -.393 .551 L -.017 -.092 L .129 -.241 L -.025 -.138 L -.256 .035 L -.38 .137 L -.291 -.126 L -.509 .138 L -.12 -.329 L .014 -.233 L -.567 -1.068 L -.764 -.138 L -.204 -.352 L -.113 -.819 L -.423 -.229 L -.144 -.702 L -.373 .093 L -.608 -1.08 L -.375 -.482 L .296 0 L .375 -.438 L .048 -.226 L -.167 -.226 L -.471 .407 L -.277 -.208 L .126 -.573 L .147 -.758 L .158 -1.043 L -.293 -.452 L -.258 -.169 L -.496 -.126 L -.832 -.987 L -.875 -.804 L -.528 -.168 L -.43 .072 L -.536 .298 L -.456 .354 L -1.202 .299 L -.273 -.213 L -.131 -.62 L -.253 -.254 L -.264 -.113 L -.752 -.069 L -.516 -.296 L -.22 -.233 L -.504 .138 L -1.052 .115 L -.653 -.184 L -.047 .298 L -.64 .099 L -.183 0 L -.578 -.926 L -.238 .781 L -.447 -.135 L -.65 .001 L -1.328 -.04 L -.672 .439 L -.39 .055 L -1 -.459 L -.096 .009 L -.142 .014 L -.362 .528 L .201 .229 L .303 0 L .211 0 L .537 -.207 L .406 .092 L .676 .482 L -.68 .373 L .02 .254 L .263 .353 L .593 .146 L .229 .217 L .35 .334 L -.533 .136 L -.503 -.084 L -.276 -.419 L -.79 -.271 L -.224 -.211 L -.265 -.056 L -.013 .02 L -.209 .32 L .209 .154 L .248 .183 L -.248 .179 L -.069 .05 L -.447 -.459 L -.476 .192 L -.287 .291 L -1.025 -.472 L -.419 -.494 L -1.16 -.642 L -.615 .066 L .554 .393 L -.307 .187 L -1.17 -.083 L -.886 -.252 L -.896 -.168 L -1.547 .173 L -.632 .328 L -.392 -.015 L -.433 -.031 L -.135 -.49 L -.333 .057 L -.112 .184 L .474 .731 L -.877 .64 L -.808 .577 L -.915 .317 L -.419 .043 L -.414 -.056 L -.728 -.111 L -.126 .198 L .437 .437 L -.239 .396 L -.327 .199 L -.631 .114 L -.737 .27 L -.268 .17 L .558 .352 L .111 .169 L -.659 .694 L -.154 .297 L -.012 .848 L .144 .636 L .271 .762 L .425 .903 L -.347 -.119 L -.816 -.377 L -.296 .001 L -.416 .116 L -.264 -.069 L -1.029 -.56 L -.921 -.32 L -.375 -.365 L -.336 -.592 L -.332 -.932 L -.078 -.467 L -.268 -.253 L -.657 -.576 L -.845 -1.042 L -.744 -1.227 L -.663 -1.029 L -.363 -.366 L -.412 -.252 L -.783 -.321 L -.475 -.082 L -.643 .018 L -.468 .201 L -.576 .541 L -.418 .413 L -.283 .37 L -.416 .158 L -.501 -.011 L -.337 -.069 L -1.104 -.503 L -1.092 -.659 L -.445 -.549 L -.318 -.847 L -.284 -.678 L -.179 -.226 L -.708 -.491 L -.837 -.519 L -.766 -.632 L -.631 -.662 L -.209 -.112 L -1.892 -.046 L -1.858 -.003 L -.096 .892 L -.213 .101 L -1.867 .011 L -.966 -.037 L -1.544 -.02 L -1.662 -.019 L -.338 -.055 L -3.516 -1.112 L -2.811 -.933 L -1.186 -.39 L -.267 -.154 L -.316 -.31 L -2.381 .084 L -2.367 .155 L -.34 .017 L h 49.818 152.776 m -.122 .086 L -.279 .03 L -.111 -.131 L -.177 -.005 L -.324 .051 L -.304 -.39 L -.071 -.263 L .339 -.01 L .299 -.253 L .188 .218 L .106 .294 L .223 .096 L .233 .279 L h 52.785 154.312 m -.155 -.081 L -.085 -.356 L -.461 -.321 L .095 -.229 L .143 -.058 L .366 .209 L .344 .055 L .616 .356 L -.005 .172 L -.294 .184 L -.563 .069 L h 111.683 77.224 m -.138 .415 L -.45 .067 L -.324 .113 L -.295 .247 L -.321 -.137 L -.185 -.21 L .087 -.443 L .086 -.443 L -.438 -.675 L -.463 -.319 L -.199 -.271 L -1.281 .055 L -.437 .098 L -.153 .161 L -.496 .097 L -.019 -.193 L -.034 -.432 L .212 -.272 L .184 -.212 L -.378 -.347 L -.641 -.438 L -.693 -.696 L -.723 -.317 L -.453 -.136 L .132 -.35 L -.569 -.592 L -.099 -.213 L .371 -.229 L -.068 -.122 L -.301 -.152 L -.445 -.076 L -.392 -.274 L -.237 -.259 L -.57 -.305 L -1 -.411 L -.479 -.765 L -.217 -.583 L -.367 -.399 L -.357 .016 L -.101 .814 L .42 .873 L .104 .306 L -.047 .153 L -.701 -.136 L -.272 -.076 L -.511 -.504 L -.4 -.459 L -.537 .139 L -1.219 -.228 L 1.263 .718 L .032 .214 L -1.62 .171 L -1.093 -.35 L -1.388 -.948 L -.543 -.292 L -.664 -.043 L -.079 0 L -.933 -.213 L -1.3 -.536 L .928 -.248 L .135 -.169 L 90.8 67.129 l -.384 -.153 L -.792 .156 L -.454 .14 L -.656 .017 L -1.058 -.06 L -1.068 -.245 L .027 -.247 L -.148 -.186 L -.325 -.108 L -.359 .016 L -.47 .202 L -1.036 .049 L -1.465 -.122 L 80.46 66.64 l -.786 -.091 L -.248 -.108 L -.651 -.387 L -.427 -.527 L -.301 .218 L -.788 .157 L -.89 -.293 L -.234 -.326 L -.417 -.139 L -.872 -.248 L -1.538 -.23 L -.817 -.248 L -.671 -.342 L -.553 .235 L -.675 .079 L .06 .437 L -.193 .062 L -.389 .25 L -.249 .405 L 1.119 .293 L .174 .294 L -.096 .388 L -.428 .449 L -.458 .001 L -.804 -.214 L -.586 -.061 L -.568 .094 L -.978 .603 L -1.066 .217 L -.936 .448 L -1.035 .448 L -1.095 .109 L .178 -.308 L .063 -.123 L .72 -.401 L -.093 -.385 L -.655 -.523 L .004 -.108 L 64.1 66.19 l .411 -.482 L .157 -.42 L .736 -.312 L .87 -.235 L 1.165 -.018 L 1.085 .123 L .239 -.156 L -1.239 -.466 L -.971 -.389 L -1.043 .049 L -.226 .219 L -.449 .095 L -.573 .438 L -.865 .375 L -1.019 .282 L 61.553 65.9 l -.406 .094 L -.298 .14 L .131 .325 L -.177 .526 L -.563 .34 L -.564 .078 L 59 67.544 l -.592 .278 L -.681 .601 L -.035 .292 L .38 .168 L .36 .03 L .667 .106 L .465 .229 L -.075 .184 L -.43 .338 L -.625 .2 L -.557 .277 L -.423 .398 L -.544 .383 L -.675 .093 L -1.434 .308 L -.678 .397 L -1.036 .337 L -.7 .367 L .52 .5 L -.1 .167 L -1.106 .412 L -.897 .153 L -.778 .168 L 49.51 74.19 l -1.214 .456 L 48.1 74.828 l -.274 .394 L -.753 .439 L -1.193 .229 L -1.234 .184 L -.973 -.345 L .001 -.181 L .332 -.348 L .763 -.273 L .306 -.212 L .445 -.364 L 1.171 -.441 L 1.403 .073 L -.12 -.212 L .02 -.516 L .47 -.304 L .725 -.291 L .754 -.366 L .266 -.214 L .002 -.731 L .246 -.749 L .693 -.49 L .194 -.398 L .034 -.412 L -.633 .122 L -1.251 .186 L -.676 -.029 L -.5 -.597 L -.266 .062 L -.613 .216 L -.136 .23 L .239 .352 L .021 .352 L -.169 .046 L 47 70.115 l -.567 -.32 L -.487 -.397 L -.509 -.291 L -.56 -.03 L -.812 -.106 L -.91 .094 L .028 .138 L -.644 .338 L -1.175 .14 L -.649 -.09 L -.064 -.123 L -.082 -.107 L -.125 -1.028 L .3 -.508 L -.142 -.431 L -.864 -1.002 L -1.43 .437 L -.738 .078 L -.406 .202 L -1.091 .094 L -.4 -.23 L -.394 -.355 L -.466 -.325 L -1.007 -.463 L -.179 -.28 L .292 -.171 L .337 -.437 L .704 .139 L 1.312 .309 L .69 .03 L .238 -.234 L -.375 -.482 L -.458 -.264 L -.363 0 L -.541 .22 L -.528 -.015 L -1.342 -.513 L -.623 -.186 L -.197 .016 L -.858 -.029 L -.024 -.078 L -.623 -.985 L .79 -.19 L .071 -.456 L .495 -.221 L .102 -.299 L .227 -.347 L .893 -.491 L .337 -.38 L .386 -.301 L .527 -.476 L .39 -.175 L .719 .109 L .98 .268 L .485 .094 L .752 -.144 L .427 -.254 L .675 -.429 L 1.252 -.257 L .774 -.033 L .955 -.049 L .354 -.175 L .187 -.478 L -.259 -.669 L -.814 -.686 L .026 -.096 L .927 -.034 L .343 -.256 L -.25 -.384 L -.497 -.256 L -.367 -.08 L -1.88 .389 L 39.33 56.53 l -.534 .289 L -.496 .065 L -1.907 -.333 L -.848 -.031 L 34.8 56.49 l -1.27 .162 L -1.265 -.029 L -1.349 -.174 L -.53 -.207 L -.183 -.788 L .144 -.146 L .636 -.033 L 1.008 -.002 L .446 -.179 L -1.057 -.241 L -1.912 -.304 L 28.13 54.31 l -1.285 -.208 L .219 -.114 L .781 -.262 L 1.568 -.214 L 1.325 -.328 L .958 -.214 L 1.058 -.361 L .953 -.23 L 1.399 -.281 L 1.513 .128 L -.158 .523 L .023 .277 L 1.051 .161 L 1.359 .095 L 1.074 -.019 L .657 -.099 L .784 -.246 L .55 -.295 L .262 -.083 L .752 .064 L .751 .113 L 1.021 -.051 L .2 -.327 L .007 -.18 L -.689 -.064 L -1.946 -.292 L -1.283 -.047 L -.312 -.755 L -1.473 -.162 L -.96 -.031 L -1.573 -.096 L -.194 -.511 L -.484 -.312 L -1.042 -.461 L -.512 -.148 L -2.66 -.659 L -2.008 -.545 L .317 -.167 L .812 -.402 L .086 -.485 L 2.136 -.054 L .99 -.069 L 1.829 -.288 L .784 -.354 L .452 -.623 L .788 -.575 L .616 -.525 L .818 -.41 L .742 -.224 L 1.066 -.104 L 1.133 -.241 L 1.047 -.036 L 1.804 .065 L .146 -.188 L -.156 -.205 L 44.47 42.83 l .018 -.206 L 1.936 -.089 L 1.143 .032 L .974 -.054 L 1.344 -.14 L 1.098 -.416 L .918 -.417 L .957 -.019 L .282 .051 L .675 .241 L .156 .172 L -.383 .139 L .017 .344 L 1.049 .136 L .424 .034 L .536 -.293 L .297 -.208 L 1.419 .187 L 1.534 .049 L 1.062 .049 L .715 .033 L .711 .257 L .359 .274 L .783 .358 L .494 .085 L .421 -.086 L 1.292 .117 L 1.124 .015 L 1.556 -.054 L 1.449 -.088 L 1.213 .1 L 1.377 .254 L .883 .118 L 3.424 .13 L 1.279 .168 L .743 .169 L 2.027 -.038 L 2.339 -.141 L 1.123 .236 L 2.441 .791 L 1.206 .301 L .227 .008 L .102 .483 L -.003 2.855 L .039 2.259 L .052 2.335 L .129 2.796 L -.026 2.183 L -.043 4.334 L .026 2.167 L .089 1.046 L .196 .279 L .84 .074 L 2.424 -.122 L .739 .059 L .332 .388 L .173 .387 L .348 .292 L 2.162 1.318 L .945 .673 L .238 -.325 L .848 -.205 L 1.225 -.67 L .731 -.498 L .495 -.126 L .832 .073 L .316 .199 L .371 .492 L .35 .322 L 2.048 1.175 L .814 .58 L 1.769 1.768 L 1.67 1.882 L .512 .393 L .189 .029 L .98 .314 L 2.025 .763 L .402 .255 L -.163 .788 L .393 .777 L +643.755 159.873 N -1.092 -.52 L -.637 -.337 L -.203 -1.284 L .036 -.282 L .24 -.241 L .42 -.241 L .721 -.623 L .493 .056 L .049 -.17 L .24 -.396 L .239 .028 L .573 .225 L .321 -.312 L .439 -.001 L .798 -.171 L .596 .69 L -.163 .17 L -.443 .354 L -.412 .538 L -.285 .734 L .14 .296 L -.22 .311 L -.292 .085 L -1.026 .383 L -.532 .707 L h 627.173 150.012 m -.679 .314 L -.24 .241 L -.043 .325 L .138 .592 L .228 .366 L .119 .521 L -.109 .339 L -.266 .213 L -.769 -.08 L -.321 -.21 L -.178 -.196 L -.153 -.239 L -.111 -.38 L -.628 .413 L -.647 .159 L -.246 -.083 L -.378 -.266 L -.341 -.746 L -.291 -.379 L -.481 .045 L -.507 .003 L -.228 -.098 L -.117 -.352 L .729 -1.584 L -.033 -.268 L -.521 -.096 L -.554 .074 L -.202 -.324 L -.277 -1.762 L -.156 -.126 L -.479 .017 L -.771 .089 L -.819 .442 L -.312 .086 L -.216 -.069 L 0 -.268 L .224 -.58 L -.163 -.705 L -.075 -.465 L .617 -.85 L .191 -.198 L .487 -.271 L .611 -.525 L .429 -.722 L .353 -.862 L -.02 -.875 L -.195 -1.649 L -.146 -.14 L -.504 .031 L -.287 -.041 L -.217 -.309 L -.243 -.901 L -.397 -.435 L -.504 -.279 L -.277 .044 L -.306 .34 L -.001 .127 L -.624 -.081 L -.73 -.179 L -.657 -.081 L -.3 -.055 L -.102 -.056 L .138 -.269 L .354 -.454 L -.046 -.38 L -.716 -.715 L -.455 -.392 L -1.377 .84 L -.377 .044 L -.975 -.319 L -.286 -.167 L -.355 .087 L -.546 .299 L -1.105 .726 L -.829 .258 L -.543 .37 L -1.123 1.107 L -.397 .27 L -.714 .216 L -.784 .033 L -.189 .1 L -.329 -.619 L -.312 -.209 L -.371 -.041 L -1.659 -.047 L 601 137.538 l -.309 -.294 L -.417 .016 L -.149 .103 L -.348 .239 L -.609 .539 L -1.251 1.545 L -.212 -.662 L .052 -.861 L -.139 -.183 L -.231 -.069 L -.471 .102 L -.345 .129 L -.655 -.159 L -.339 .281 L -.341 -.116 L -.849 .066 L -.319 -.364 L -.63 -.281 L -.407 0 L -.08 .331 L -.271 .083 L -.685 -.38 L .01 .364 L -.237 .099 L -.141 -.463 L -.54 -.496 L -.365 .066 L -.935 -.066 L -.014 -.265 L .175 -.396 L -.326 -.017 L -.333 .248 L -1.451 -.893 L .069 -.281 L -.178 -.38 L -.289 -.166 L -.71 .116 L -.158 .166 L -.657 -.794 L -.454 -.281 L -.15 .132 L -.472 -.215 L -.726 -.595 L -.867 -.264 L -.132 -.612 L -1.079 -.199 L -.186 .182 L -.275 -.066 L -.134 .513 L -.276 .314 L -.299 -.05 L -.24 -.43 L -.859 -.596 L -.154 .066 L -.756 -.248 L .116 -.364 L -1.078 -.579 L -.363 .116 L -.772 -.843 L -.383 -.248 L -.477 .314 L -.198 -.066 L -.099 -.43 L .215 -.215 L -.272 -.364 L .104 -.446 L -.579 -.595 L -.157 -.694 L .785 -.198 L .033 .364 L .337 .264 L .368 -.049 L .376 -.281 L .578 -.364 L -.367 -.694 L .104 -.414 L -.68 -.099 L -.044 -.182 L -.092 -.078 L -.718 -.096 L -.294 -.221 L -.037 -.552 L -.073 -.589 L .184 -.184 L .331 -.221 L -.221 -.258 L -.441 -.405 L -.81 -.11 L -.221 -.515 L -.441 -1.03 L 0 -.515 L -.502 .152 L -.147 -.126 L -.305 -.111 L -1.337 -.104 L -.565 -.436 L -.178 -.09 L -.104 -.199 L -.239 0 L -.52 .196 L -.252 -.281 L -.198 -.218 L -.301 -.07 L .312 -.516 L -.007 -.501 L -.213 -.247 L -.373 -.323 L -.625 .009 L -.282 .128 L -.004 -.456 L -.554 -.117 L -.296 -.047 L -.281 .21 L -.105 -.112 L -.313 -.14 L -.048 -.088 L -.236 -.012 L -.01 -.269 L .574 .059 L .192 -.145 L .354 -.136 L .08 -.249 L .181 -.185 L -.2 -.163 L .152 -.36 L -.245 -.237 L .126 -.428 L -.049 -.123 L -.152 -.012 L -.028 -.246 L .009 -.284 L -.295 -.494 L -.273 -.154 L -.692 -.039 L -.22 -.06 L -.229 .162 L -.463 .045 L -.325 -.394 L -.077 -.305 L .207 -.223 L -.023 -1.031 L .011 -.069 L .139 -.739 L .129 -.213 L .274 -.186 L 1.422 -.704 L 1.737 -.734 L .359 -.03 L .06 .071 L .183 .567 L .344 .055 L .507 -.145 L .885 -.132 L .268 -.243 L .463 -.784 L .467 -.472 L .238 -.03 L 1.248 .235 L .459 -.017 L .478 -.102 L .646 -.345 L .638 -.701 L .405 -.301 L .445 -.145 L 1.338 -.349 L .97 -.219 L .325 -.187 L .051 -.157 L -.031 -.194 L -.139 -.86 L .02 -.399 L .32 -.401 L .705 -.546 L .222 -.33 L -.119 -.47 L -.29 -.441 L -.345 -.627 L -.03 -1.357 L -.483 -.141 L -.366 .06 L -.232 -.185 L .068 -.215 L .215 -.302 L .393 -.188 L 1.799 -.254 L 1.082 -.207 L .35 -.06 L .5 .184 L 1.133 .238 L .394 -.074 L .231 -.145 L .156 -.245 L -.126 -.286 L -.622 -.514 L .137 -.418 L .286 -.605 L .438 -.794 L .516 -1.141 L .427 -.507 L 1.096 .254 L .721 .141 L .594 .141 L 1.402 .079 L .718 -.062 L .417 -.103 L .444 -.392 L .157 -.39 L -.213 -.707 L -.097 -.75 L .34 -.581 L .428 -.277 L 1.199 -.093 L .289 -.06 L .306 -.219 L .035 -.478 L .011 -.275 L .279 -.262 L .542 -.148 L .551 -.034 L .228 -.014 L .569 -.003 L .244 -.074 L .062 .145 L .131 .405 L .24 .563 L .371 .433 L 1.301 .745 L .834 .415 L .614 .069 L .731 .167 L .633 .144 L .354 .143 L .568 .618 L 1.07 1.451 L .401 .66 L -.215 .447 L -.237 .75 L -.214 .389 L -.369 .347 L -.035 .129 L .105 .43 L .233 .229 L .724 .312 L 1.062 .181 L 1.505 .021 L .995 .038 L .668 .083 L .998 .224 L .632 .268 L 1.645 .806 L .839 .31 L .744 .096 L .105 .542 L 1.571 2.161 L .467 .439 L .444 .254 L 1.979 .018 L 1.241 .207 L .802 .109 L 1.165 .022 L 2.861 -.059 L .937 .023 L 1.164 .022 L 1.69 .119 L .521 .168 L .815 .551 L 1.006 .365 L 1.599 .433 L .929 .123 L .663 -.061 L .61 .067 L .253 .297 L .433 .197 L .481 -.017 L .686 -.289 L 1.44 -.534 L .303 -.101 L .736 -.274 L .816 -.289 L 1.204 -.349 L 1.339 -.007 L 1.514 -.065 L .987 .08 L .651 -.061 L 1.941 -.737 L .265 -.172 L 1.111 -1.046 L .67 -.389 L 1.265 -.292 L .326 -.259 L .123 -.271 L -.188 -.228 L -.599 -.411 L -.389 -.569 L -.003 -.343 L .214 -.401 L .539 -.589 L .457 -.231 L .316 -.073 L .718 .154 L .668 .382 L .592 .125 L .982 -.005 L .744 -.047 L .742 -.433 L 1.192 -.91 L .224 .013 L .438 .012 L .624 .054 L .896 -.134 L .638 -.248 L .347 -.188 L .241 -.216 L .312 -.82 L .363 -.333 L .47 -.204 L .464 -.045 L .483 .127 L .353 -.189 L .831 -.278 L .539 -.146 L .937 -.221 L .854 -.033 L .432 .099 L 1.074 .008 L .464 .127 L .414 -.218 L .107 -.217 L -.048 -.273 L -.599 -.501 L -.879 -.99 L -.797 -.5 L -.538 -.199 L -.928 -.212 L -.438 .002 L -1.191 .786 L -.292 -.07 L -.431 -.416 L -.317 -.085 L -.576 .018 L -.754 .062 L -.929 .395 L -.342 .045 L -.051 -.029 L -.269 -.836 L .381 -.58 L 1.224 -1.959 L .687 -1.207 L .295 -.31 L .046 .018 L .452 .172 L 1.126 .574 L .343 -.016 L .438 -.089 L 2.44 -.752 L .779 -.339 L .123 -.233 L -.056 -.306 L -.35 -.348 L -.062 -.146 L .103 -.249 L .422 -.426 L .416 -.543 L .667 -.779 L .599 -.545 L 1.371 -.608 L .167 -.794 L -.107 -.249 L -.465 -.306 L -.558 -.026 L -.822 .078 L .119 -.25 L .375 -.282 L 1.193 -.787 L .478 -.165 L .602 -.136 L 1.854 -.143 L .836 -.123 L 1.203 -.109 L .917 -.049 L 1.148 .215 L 1.037 .481 L .683 .188 L 1.386 -.125 L .539 .026 L .763 .467 L .742 .952 L 1.087 2.384 L .94 1.588 L .927 1.903 L .436 .389 L .507 .2 L 1.247 .341 L 1.523 .253 L 2.659 .839 L .205 .144 L .297 .866 L .44 1.283 L .261 .446 L .68 -.033 L .649 -.018 L 1.657 -.052 L .604 -.22 L .953 -.308 L 1.357 -.31 L 1.181 -.208 L .902 -.034 L .246 .114 L .064 .259 L .116 .389 L .017 .504 L -.566 .407 L -.66 .393 L -.291 .707 L -.278 .893 L -.538 1.066 L -.627 1.08 L -.329 .432 L -.551 .69 L -.47 .347 L -.547 -.098 L -.679 -.225 L -.685 -.24 L -.396 -.041 L -1.664 .982 L -.048 .557 L .332 .897 L .062 .656 L -.006 .613 L -.025 .385 L -.097 .128 L .112 .299 L -.156 .329 L -.511 .43 L -1.252 .462 L -.111 .058 L -.579 -.68 L -.247 .001 L -.253 .129 L -.383 .358 L -.23 .713 L -.955 .532 L -.62 .259 L -.538 .017 L -.452 -.054 L -.333 -.126 L -.392 .059 L -.273 .243 L -.025 .342 L .508 .765 L .046 .113 L -.527 .159 L -.975 .048 L -.508 -.153 L -.493 -.253 L -.273 -.396 L -.448 .017 L -.386 .13 L -.686 1.027 L -.636 .543 L -1.032 .545 L -1.533 .604 L -.52 .329 L -.415 .442 L -.379 .528 L -.066 -.092 L -.417 .171 L -1.222 .13 L -.728 .171 L -2.248 .925 L -.632 .37 L -.566 .469 L -.604 .271 L -.336 .015 L .13 -.255 L .862 -.682 L .33 -.354 L -.47 -.113 L -.37 .072 L -.153 -.297 L .058 -.156 L .953 -.781 L .269 -.384 L .55 -.413 L .159 -.2 L -.057 -.298 L -.73 -.553 L -.727 -.283 L -.131 -.014 L -.628 .03 L -.166 .015 L -.494 .371 L -1.146 1.183 L -.355 .157 L -.643 .086 L -.613 .243 L -.36 .199 L 665.49 112 l -.136 .411 L -.131 .255 L -.251 .255 L -.437 .128 L -.493 -.013 L -.326 .27 L -.307 .114 L -.455 -.565 L -.355 -.014 L -.349 .128 L -.396 .638 L -.301 .694 L .088 .34 L .245 .368 L .558 .268 L .8 .268 L 1.21 -.045 L .29 .254 L -.019 .538 L -.123 .581 L .057 .538 L .261 .283 L .733 .069 L .698 -.157 L .76 -.525 L .509 -.497 L .552 -.228 L .534 -.128 L .287 .07 L .895 .621 L .543 .197 L 1.023 -.087 L .361 .027 L .471 .141 L .274 0 L -.248 .708 L -.057 .552 L -.612 -.197 L -.297 -.084 L -.525 .058 L -1.677 .555 L -.707 .44 L -.072 .735 L -.522 .157 L -.146 -.113 L -.017 -.269 L -.127 -.084 L -.501 .114 L .138 .466 L -.152 .368 L -.485 .496 L -1.397 1.119 L -.126 .226 L .039 .55 L .62 .225 L .712 .492 L .785 .521 L .391 .535 L .424 1.241 L .668 .647 L .175 .437 L -.13 .677 L .172 .183 L .694 .295 L .399 .592 L .562 .253 L .272 .268 L .087 .31 L -.049 .155 L -.789 .369 L .088 .07 L .425 .31 L .314 .79 L -.019 .296 L -.141 .184 L -.534 .043 L -.651 .213 L -.948 .552 L -.849 .213 L -.629 .297 L .72 .21 L .378 .056 L .944 -.425 L .488 -.058 L .162 .056 L .524 .592 L .387 .168 L .456 .027 L .009 .155 L -.231 .311 L -.382 .227 L -.304 .241 L .11 .155 L .326 -.029 L .202 .084 L -.184 .325 L -.298 .749 L -.192 .649 L .028 .353 L -.22 .452 L -.209 .127 L -.35 -.338 L -.146 .142 L -.569 .763 L -.401 .622 L -.215 .622 L -.127 .296 L -.595 .425 L -.251 .438 L -.254 .184 L -.569 .029 L -.382 .227 L .279 .719 L -.264 .508 L .076 .593 L -.093 .269 L -.207 .269 L -.532 .199 L -.161 .282 L -.174 .396 L -.294 .636 L -.626 .354 L -.412 .495 L -.492 -.14 L -.443 -.069 L -.142 .113 L -.145 .198 L .118 .833 L -.213 .142 L -.772 .651 L -.356 .127 L -.628 .171 L -.563 .467 L -.571 .213 L -.107 .113 L -.008 .48 L -.133 .156 L -.568 .058 L -.5 .114 L -.341 .438 L -.364 -.126 L -.52 -.168 L -.274 .057 L -.315 .326 L -.435 .198 L -.643 .1 L -.047 -.465 L -.52 .057 L -.699 .213 L -.32 .198 L -.285 -.042 L -.401 -.493 L -.163 -.155 L -.191 .283 L .095 .169 L -.045 .212 L -.047 .691 L -.209 .297 L -.416 .114 L -.501 -.182 L -.123 .282 L -.001 .24 L -.146 .155 L -.615 .058 L -.366 .114 L -.596 .043 L -.463 -.211 L -.217 .1 L -.439 .48 L -.227 .071 L -.774 -.041 L -.747 .227 L -.406 .326 L -.451 -.027 L -.277 -.084 L -.011 .057 L -.069 .353 L -.29 .396 L .011 .113 L .48 .634 L .269 .126 L .043 .198 L -.36 .269 L -.763 .157 L -.481 -.719 L -.241 -.691 L .012 -.395 L .396 -.777 L -.015 -.169 L -.587 -.253 L -.226 .071 L -.206 .297 L -.454 .072 L -.676 -.21 L -.574 -.733 L -.196 .085 L -.017 .169 L -.159 .396 L -.27 .128 L -.332 -.056 L -.481 .043 L -.055 .038 L -.197 -.143 L -.909 -.107 L -.621 -.166 L -.943 -.615 L -.273 -.365 L -.096 -.521 L .472 -.75 L -.056 -.38 L -.237 -.21 L -.777 .047 L -.66 -.053 L -.771 -.235 L -.623 -.575 L -.298 .101 L -.521 .328 L -.696 .554 L -.341 .157 L -.807 .117 L -1.595 .052 L -.332 .115 L -.584 .413 L -.325 -.097 L -.597 -.392 L -.341 -.012 L -.515 .13 L -.483 .229 L +241.073 156.152 N .017 .52 L .098 1.215 L .012 .212 L -.379 .455 L -.011 .17 L .485 1.358 L -.669 -.577 L -.445 -.056 L -.761 .143 L -.877 -.012 L -.666 -.14 L -.574 -.056 L -.474 .1 L -.378 .354 L -.135 -.042 L -.993 -.549 L -.171 -.325 L .04 -.198 L .269 -.184 L 1.051 .097 L .631 .111 L 1.125 .167 L .654 .041 L .61 -.185 L .386 -.156 L -.198 -.155 L -.692 -.464 L -.136 -.296 L .184 -.707 L -.202 -.296 L -.394 -.154 L -.913 -.14 L -.305 -.211 L .04 -.184 L .119 -.085 L .344 -.1 L .724 -.058 L .781 .125 L 1.081 .294 L .576 .056 L .147 -.089 L +241.295 160.082 N -.485 -1.358 L .011 -.17 L .379 -.455 L -.012 -.212 L -.098 -1.215 L -.017 -.52 L .503 -.279 L .393 .14 L .342 0 L .384 -.17 L .369 -.043 L .14 .198 L .177 .112 L 1 .309 L .657 -.072 L .213 .395 L .335 .338 L .528 .324 L .335 .084 L .643 .21 L .916 .45 L .399 .352 L .231 .311 L -.191 .17 L -.144 .297 L -.314 .368 L -.238 -.098 L -.476 -.592 L -.378 -.042 L -.788 .058 L -.288 -.098 L -.373 0 L -.329 .1 L -.763 .539 L -.396 -.056 L -.319 -.494 L -.166 -.028 L -.155 .057 L -.658 .326 L -.344 .778 L -.41 .65 L -.289 -.112 L -.325 -.551 L +668.053 167.796 N -.131 -.099 L -.74 -.732 L -.444 -1.255 L .037 -.424 L .054 -.706 L -.292 -.465 L .18 -.382 L .978 .704 L .202 -.424 L .023 -.41 L -.101 -.438 L -.026 -.579 L .145 -.438 L .025 -.664 L .082 -.861 L .074 -.636 L .38 -.862 L .188 -.127 L .337 -.142 L .523 .055 L 1.21 .52 L .576 .042 L .188 -.212 L .277 -.17 L .199 .141 L .018 .396 L -.266 .438 L -.045 .48 L .14 .79 L .541 .394 L .182 .325 L -.427 1.271 L -.31 .467 L -.834 .608 L -.555 .312 L -.082 .099 L .003 .268 L -.078 .565 L -.28 .424 L .127 .211 L .35 .733 L .345 1.101 L .26 .62 L .093 .028 L .451 .324 L .296 .07 L .161 -.325 L .485 -.537 L .197 -.029 L .418 .112 L .226 .211 L .179 .635 L .286 .353 L .326 .084 L .505 -.58 L .621 .267 L .141 .028 L .078 .127 L -.168 .156 L -.378 .156 L -.208 .212 L .936 1.226 L -.315 .184 L -.568 -.196 L -.404 -.098 L -.094 -.48 L -.229 -.31 L -.599 -.535 L -.753 -.577 L -.258 0 L -.099 .226 L .371 .776 L -.218 .283 L -.727 -.775 L -.982 -.548 L -.309 .015 L -.344 .142 L -.182 .255 L -.14 .071 L -.395 .057 L -.322 -.225 L -.591 -.366 L -.195 -.423 L .64 -.608 L .323 .211 L .358 .084 L .4 -.199 L -.151 -.169 L -.713 -.295 L -.422 -.395 L -.522 -.168 L -.239 .607 L h 669.676 172.974 m -.452 -.366 L -.349 -.408 L -.051 -.226 L -.364 -1.114 L -.459 -.521 L .685 -.058 L .868 .012 L .314 .169 L .274 .451 L .028 .861 L -.097 .48 L -.214 .283 L -.185 .438 L h 679.073 175.368 m -.562 -.267 L -.178 -.254 L -.237 -.169 L -.064 -.127 L .139 -.339 L -.091 -.423 L -.55 -.352 L -.662 -.479 L -.147 -.466 L .513 -.1 L 1.017 -.143 L .371 .112 L .283 .409 L .069 .818 L .123 .805 L .257 .79 L -.112 .127 L -.167 .057 L h 671.406 176.824 m .022 -.353 L .186 -1.342 L .061 -1.172 L .482 .395 L .576 .281 L .366 .028 L .634 -.185 L .027 .438 L -.079 .396 L -.24 .269 L -.184 .198 L -.908 .651 L -.943 .397 L h 664.721 177.812 m -.366 -.027 L .127 -.297 L .202 -.099 L .314 -.396 L .265 -.523 L .082 -.607 L .138 -.509 L .326 -.184 L .14 .183 L -.16 .283 L .276 .55 L .212 .564 L -.108 .113 L -.664 .354 L -.406 .368 L -.377 .227 L h 673.781 179.981 m -.385 -.366 L -.828 -.591 L -.206 -.38 L .099 -.368 L .565 -.213 L .22 -.269 L .487 -1.822 L .438 -.185 L .271 .028 L .113 .126 L .049 .282 L -.373 .905 L -.089 .226 L -.315 1.413 L .165 .296 L .214 .465 L -.213 .41 L -.212 .043 L h 661.179 181.308 m -.317 -.042 L .215 -.48 L .343 -.467 L .35 -.34 L .592 -.354 L .636 -.496 L .933 -1.089 L .11 .55 L -.118 .424 L -.267 .297 L -.24 .184 L -.516 .213 L -.172 .127 L -.244 .622 L -.327 .269 L -.591 .171 L -.386 .41 L h 680.678 185.402 m -.201 -.098 L -.098 -.438 L -.361 -.748 L -.297 -.112 L -.381 .608 L -.361 .82 L .246 .38 L .166 .395 L .148 .677 L -.158 .495 L -.383 .509 L -.305 -.253 L -.176 -.268 L .201 -.41 L -.076 -.325 L -.363 -.07 L -.361 .665 L -.173 -.056 L -1.114 -.619 L -.557 -.549 L -.206 -.508 L -.037 -.635 L .466 -.905 L -.108 -.479 L -.466 -.409 L -.778 -.295 L -.292 .043 L -.062 .17 L -.129 .226 L -.5 .255 L -.661 .058 L -.027 -.494 L -.174 -.24 L -.399 .199 L -.504 .961 L -.525 .863 L -.219 -.084 L -.119 -.127 L -.034 -.197 L .054 -.311 L .359 -.749 L .185 -.537 L .263 -.283 L .383 -.184 L .564 -.044 L .219 -.127 L .134 -.466 L .205 -.156 L .549 -.241 L .777 -.101 L .292 .353 L .102 .72 L .317 -.156 L .485 -.058 L .207 -.184 L .207 -.565 L .358 -.255 L .479 .21 L .186 .084 L .158 -1.087 L .29 -.015 L .264 .465 L .315 -.481 L .205 -.142 L .392 .098 L .133 -.227 L -.048 -.706 L -.172 -.564 L .146 -.353 L .413 .549 L .711 .803 L .229 .48 L .083 .324 L -.336 .735 L .237 .226 L .537 -.1 L .076 .423 L -.114 .424 L .056 .692 L .207 .437 L -.002 .438 L -.111 .424 L -.283 .579 L -.332 .622 L +251.898 160.229 N -.547 -.112 L -.073 -.212 L .051 -.551 L -.109 -.24 L .11 -.17 L .235 -.071 L .543 .069 L .404 -.015 L 1.505 .11 L .393 .168 L .113 .141 L -.188 .354 L -.07 .099 L -.283 .227 L -.335 .043 L -.739 -.083 L -.657 .072 L -.354 .17 L +228.82 160.519 N -.299 -.056 L -.693 -.224 L -.229 -.268 L -.47 -.366 L -.465 -.084 L -.142 -.211 L .53 -.284 L .704 -.072 L 1.364 .251 L .97 .351 L .651 .267 L .279 .282 L -.04 .198 L -.332 .071 L -.751 -.295 L -.543 .058 L -.227 .255 L -.308 .128 L +400.72 175.499 N -.595 -.119 L -.161 -.032 L -.976 .458 L -1.429 -.006 L -.867 -.037 L -2.119 .041 L -.271 .157 L -.125 .34 L .261 1.934 L .02 .41 L -.191 .17 L -.63 -.434 L -.644 -.166 L -.769 .075 L -.608 .159 L -.446 .257 L -.368 .115 L -.354 -.083 L -.452 -.223 L -.52 -.562 L -.15 -.465 L -.308 -.252 L -.545 .003 L -.259 -.168 L .08 -.043 L .046 -.156 L .172 -.326 L .261 -.92 L .133 -.876 L -.058 -.749 L .141 -.255 L .257 -.016 L .448 -.158 L .543 -.271 L .317 -.369 L .292 -1.047 L .355 -1.217 L .397 -.384 L .273 -.058 L .293 .281 L .551 .364 L .45 -.102 L .174 -.227 L .393 -.822 L .492 -.667 L .638 -.625 L .272 -.101 L .518 .209 L .324 .182 L .274 .027 L .314 -.793 L .304 -.228 L .947 -.458 L 1.22 -.713 L .37 -.073 L .356 .125 L .36 .059 L 1.062 .173 L -.173 .665 L .019 .396 L .426 .93 L .422 .492 L .389 .266 L .502 .42 L .179 .268 L .018 .212 L -.335 .439 L .114 .226 L .97 .757 L .516 .181 L .37 -.044 L .562 .025 L .568 .971 L .131 .367 L -.237 .764 L -.415 .468 L -.337 .158 L -.739 -.095 L -.418 .045 L -.415 .271 L -.366 .553 L -.24 .157 L -.062 .142 L -.29 -.041 L -.611 -.166 L -1.013 -.163 L +209.823 175.47 N -.388 -.645 L -.932 -.888 L -1.003 -1.085 L -.837 -.817 L -.723 -.464 L -.196 -.183 L -.023 -.226 L .625 -.03 L 1.001 -.125 L .29 -.143 L .293 -.412 L .005 -.961 L .882 -.034 L .513 -.583 L .725 .42 L 1.207 -.997 L .503 -.794 L .294 -.242 L .259 .013 L .328 .182 L .463 .097 L .248 -.086 L .424 -.229 L 1.425 -.486 L .23 .519 L .038 .339 L -.057 .509 L -.214 .707 L -.543 .806 L -.1 .749 L .042 .904 L -.245 1.13 L -.188 .735 L -.101 1.385 L .031 .55 L .184 .466 L .188 .363 L -.281 .274 L -.767 -.149 L -.241 -.46 L -.285 .077 L -.394 -.107 L -.603 .25 L -1.651 -.599 L -.43 .271 L +634.036 168.444 N .533 .251 L .736 .165 L .341 .111 L .469 .251 L .248 -.058 L .095 -.24 L -.103 -.211 L -.187 -.182 L -.107 -.296 L .392 -.285 L .476 -.186 L .444 .181 L .373 .351 L .3 -.072 L .975 -.429 L .209 -.114 L -.215 .905 L .029 .663 L .455 1.014 L -.076 .367 L -.05 .424 L .054 1.073 L -.217 .509 L -.385 .285 L -.599 .187 L -.932 .443 L -.521 .229 L -.99 .571 L -.234 .425 L .216 .422 L .568 .435 L .03 .197 L -.17 .27 L -.688 -.194 L -.497 -.011 L -.599 .229 L -.915 .528 L -.646 .229 L -.3 .289 L -.256 -.188 L -.248 -.268 L -.35 -.042 L -.382 .142 L -.205 -.042 L -.293 .043 L -.183 -.113 L .142 -.311 L .182 -.226 L -.04 -.254 L -.283 -.395 L -.277 .043 L -.462 .298 L -.339 .015 L -.171 -1.044 L -.649 -1.488 L .146 -.176 L -.16 -.479 L -.487 -.717 L -.219 -.648 L -.026 -.635 L .076 -.382 L .146 -.297 L .92 -1.233 L .521 -.441 L .383 -.101 L 1.172 -.091 L .798 .066 L .558 -.074 L .575 .039 L .599 .109 L .301 .167 L +214.474 175.913 N .821 .884 L .385 .623 L .314 .322 L .225 .046 L .465 .645 L .441 .352 L -.014 .006 L -.074 .123 L -.478 -.184 L -.219 .205 L -.014 .321 L 0 .58 L .507 .307 L -.396 .368 L .125 .532 L -.374 .369 L .243 .184 L -.204 .609 L .003 -.466 L -.296 -.307 L .01 -.568 L -.377 -.148 L -.238 -.102 L -.111 .082 L .325 .41 L .084 .225 L -.113 .062 L -.726 -.299 L -.13 -.282 L .251 -.339 L .04 -.382 L -.182 -.338 L -.486 -.324 L -.695 -.287 L -.079 -.144 L -.689 -.103 L -.316 -.327 L .007 -.421 L -.146 -.255 L -.249 -.098 L -.576 -.353 L -.416 -.266 L .225 .512 L .086 .222 L .422 .044 L .181 .266 L -.544 .573 L -.144 -.262 L -.356 -.282 L -.561 -.211 L -.323 -.239 L -.147 -.24 L -.104 -.494 L .128 -.421 L .332 -.225 L -.008 -.389 L -.554 -.225 L .363 -.123 L -.057 -.227 L -.238 .017 L .43 -.271 L 1.651 .599 L .603 -.25 L .394 .107 L .285 -.077 L .241 .46 L .767 .149 L .281 -.274 L +436.304 195.359 N -.209 -.451 L -.194 -.804 L -.498 -.802 L -1.217 -1.236 L -.112 -.324 L -.064 -.791 L -.432 -.605 L -.4 -.661 L -.207 -.592 L -.273 -1.185 L -.112 -.776 L .064 -.424 L .144 -.198 L .528 -.399 L .4 -.511 L .866 -1.743 L .354 -.327 L .208 -.114 L .096 .084 L .24 .027 L .449 -.158 L 1.363 -.686 L .494 .661 L .225 .069 L .224 -.03 L .466 -.271 L .754 -.386 L .818 -.273 L .881 .009 L .368 -.031 L .258 -.143 L .646 -1.176 L .117 -.806 L .209 -.199 L .434 -.059 L 2.181 -.055 L .386 -.087 L 2.649 -2.275 L .196 -.284 L .005 -.41 L .165 -.382 L .372 -.228 L .939 -.613 L .322 -.086 L .321 .012 L .559 .208 L 1.342 1.673 L .347 .549 L .122 .536 L -.416 1.472 L .01 .664 L .158 .211 L .802 -.019 L .272 -.001 L .207 .126 L .252 .493 L .223 .225 L .797 .447 L .799 .235 L .351 .196 L .223 .267 L -.148 .481 L .173 .395 L .445 .351 L .558 .378 L .717 .434 L .207 .168 L .206 .366 L .059 .72 L .285 .436 L .367 .224 L .814 .165 L .558 .477 L .157 .352 L -.083 .679 L .031 .07 L -.496 .145 L -.962 .344 L -.319 -.026 L -.287 -.167 L -.687 -.264 L -1.15 -.361 L -.4 .13 L -.082 .551 L -.13 .241 L -.256 .058 L -.399 -.026 L -.862 -.207 L -.593 .102 L -.93 .373 L -.93 .486 L -.271 .016 L -.559 -.35 L -.383 -.153 L -.353 .186 L -.677 1.36 L -.176 .157 L -.591 -.067 L -1.934 -.511 L -1.422 -.189 L -.512 -.322 L -.159 -.239 L -.334 -.394 L -.75 -.518 L -.432 -.167 L -.479 .06 L -.529 .3 L -.353 .341 L -.785 .979 L -.097 .297 L .096 .452 L -.017 .353 L -.063 .594 L -.16 .058 L -.751 .287 L -.895 -.093 L -.624 -.138 L -.367 -.054 L -.975 .175 L -.479 .102 L -.255 .228 L -.222 1.287 L -.158 .523 L -.365 .497 L -.303 .312 L +371.324 180.419 N 1.088 -1.235 L .643 -.866 L .238 -.157 L .594 .039 L 1.137 -.148 L .466 .04 L .42 .224 L .456 .421 L .475 .619 L .252 .761 L .165 1.369 L .26 .656 L -.259 .502 L -1.184 1.151 L -.63 .724 L -.285 .256 L -.061 .103 L -.631 -.523 L -.661 -.408 L -.483 -.196 L -.033 -.141 L .061 -.297 L -.05 -.184 L -.531 -.21 L -.792 -.549 L -.389 -.366 L -.375 -.465 L .494 -.241 L .174 -.227 L -.034 -.155 L -.484 -.211 L -.065 -.113 L .022 -.173 L +579.606 186.906 N -.493 -.083 L -.265 -.197 L -.21 -.353 L -.246 -.621 L -.361 -1.256 L -.034 -.649 L .005 -.763 L -.02 -.904 L -.24 -.696 L .188 -.513 L -.298 -.35 L .068 -.28 L .423 .023 L .349 -.43 L .053 -.367 L .226 -.369 L -.152 -.537 L .529 .48 L .699 .38 L .234 .395 L .549 .776 L .175 .324 L -.099 .339 L .024 .141 L .592 .338 L .266 .733 L .798 1.368 L .136 .508 L -.193 .735 L -.397 .679 L -.369 .396 L -.514 .425 L -.78 .284 L -.642 .043 L +217.111 178.792 N .52 .307 L .195 .512 L .02 .374 L .363 .155 L .628 .024 L .244 -.205 L .398 .43 L .726 .082 L .458 -.083 L 1.348 -.751 L .514 -.046 L 1.387 -.921 L .373 .144 L .742 .069 L .071 .156 L .789 -.017 L .767 .21 L .666 .38 L .644 .563 L .406 .666 L .084 .327 L .228 .149 L .509 1.038 L -.322 .062 L -.094 .43 L -.584 .409 L -.085 -.307 L -.19 -.082 L .045 .45 L -.228 .082 L -.256 .753 L -.378 -.825 L -.441 -.762 L -.137 -.452 L .179 -.24 L .22 -.085 L .786 .125 L -.336 -.193 L -.125 -.164 L -.096 -.471 L -.309 .307 L -.439 .041 L -.244 -.378 L -.031 -.269 L -.193 -.282 L -.132 .151 L -.226 -.287 L -.11 .102 L -.132 -.266 L -.456 -.192 L -.562 -.013 L -.499 .241 L -.382 .108 L -.07 .359 L .081 .234 L -.529 .318 L -.374 .184 L -.335 .029 L -.345 .41 L .049 .296 L .316 .297 L .464 .43 L .178 .386 L -.011 .146 L -.281 .081 L -.243 -.042 L -.431 .391 L -.568 .105 L -.339 -.042 L -.189 -.146 L .108 -.164 L -.349 -.833 L -.244 -.353 L -.177 .674 L -.812 -.409 L -.227 -.757 L -.207 .041 L -.96 -.123 L -.434 -.266 L -.599 0 L -.314 .113 L -.361 .495 L .204 -.609 L -.243 -.184 L .374 -.369 L -.125 -.532 L .396 -.368 L -.507 -.307 L 0 -.58 L .014 -.321 L .219 -.205 L .478 .184 L .074 -.123 L +266.015 188.956 N -.503 -.647 L -.732 -.745 L -.324 -.521 L .071 -.212 L .395 -.539 L -.008 -.58 L .061 -.452 L 1.032 -.19 L .41 -.144 L .308 -.299 L -.141 -.282 L -.62 -.604 L -.074 -.212 L .101 -.255 L 1.655 -1.239 L .061 -.41 L -.095 -.296 L .072 .049 L .496 .338 L .856 .521 L .695 .521 L .587 .663 L .128 .409 L -.036 .734 L .148 .945 L .298 -.593 L .22 -.099 L .6 .182 L .101 .127 L .507 .295 L .708 .549 L .401 .493 L .374 .649 L -.015 .339 L -.142 .496 L -.082 .862 L -.183 .27 L -1.131 .091 L -.169 .17 L .078 .777 L -.095 .467 L -.328 .694 L .571 .831 L .532 .675 L .561 .067 L .185 .295 L .246 .832 L .49 1.127 L .332 .563 L -.06 .212 L -.943 -.022 L -.934 .429 L -1 .331 L -.505 .314 L -.694 .513 L -.686 .075 L -.613 -.392 L -1.103 -.897 L -.15 -.296 L -.008 -.396 L .072 -.354 L -.167 -.31 L -.281 -.394 L -.156 -.465 L .213 -.962 L .547 -1.416 L .179 -.368 L -.435 -.958 L -.533 -.138 L -.304 .001 L .452 -1.09 L -.04 -.212 L -.26 -.111 L -.516 -.124 L -.302 .058 L -.375 .257 L +377.518 182.142 N .193 -.376 L .252 -.242 L .367 -.143 L .528 -.046 L .338 .097 L .165 .366 L .22 .846 L .009 .65 L -.044 .283 L .277 .323 L .404 .322 L .321 .026 L .756 -.922 L .143 -.086 L .337 .097 L .339 .224 L -.062 .17 L .119 .55 L -.059 .438 L -.501 .865 L .05 .183 L .194 .183 L .369 .097 L .592 -.032 L 1.264 1.334 L .131 .282 L -.059 .452 L -.247 .849 L -.105 .565 L -.041 .919 L -1.513 -.643 L -1.221 -.619 L -1.012 -.562 L -.403 -.423 L -1.129 -1.113 L -1.111 -.76 L -.723 -.337 L -.901 -.535 L -.66 -.548 L .061 -.103 L .285 -.256 L .63 -.724 L 1.184 -1.151 L .259 -.502 L +429.505 210.684 N .484 .336 L .177 .013 L .443 -.271 L .327 -.581 L 1.495 -.532 L .054 .424 L .042 .664 L .147 .211 L .57 -.328 L .554 -.399 L .931 -.811 L .364 -.229 L 1.025 -.938 L .086 -.706 L -.122 -.72 L .074 -.396 L .193 -1.159 L .343 -.751 L .47 -.836 L .41 -.454 L .809 -.599 L .525 -.229 L .459 -.427 L .139 -.523 L .169 -.708 L .115 -.61 L .254 -1.342 L .196 -2.021 L .156 -.764 L .094 -.551 L .349 -.821 L .558 -.837 L .398 -1.203 L .031 -.156 L -.128 -.197 L .16 -.058 L .063 -.594 L .017 -.353 L -.096 -.452 L .097 -.297 L .785 -.979 L .353 -.341 L .529 -.3 L .479 -.06 L .432 .167 L .75 .518 L .334 .394 L .159 .239 L .512 .322 L 1.422 .189 L 1.934 .511 L .591 .067 L .176 -.157 L .677 -1.36 L .353 -.186 L .383 .153 L .559 .35 L .271 -.016 L .93 -.486 L .93 -.373 L .593 -.102 L .862 .207 L .399 .026 L .256 -.058 L .13 -.241 L .082 -.551 L .4 -.13 L 1.15 .361 L .687 .264 L .287 .167 L .319 .026 L .962 -.344 L .496 -.145 L .143 .239 L .795 .772 L .348 .493 L .525 .477 L .366 .195 L .352 -.016 L .258 -.242 L .529 -.37 L .384 .012 L .684 .631 L .16 -.1 L .436 -.582 L .258 -.157 L .207 .083 L 1.032 .926 L 1.288 1.32 L .063 .028 L .159 .183 L -.018 .424 L -.26 1.88 L .128 .253 L .191 .027 L .479 .04 L .271 .182 L .111 .31 L -.191 .453 L -1.195 1.066 L -1.241 .996 L -.255 .284 L -.395 .681 L -.217 1.02 L -.107 .507 L .021 .593 L -.025 .734 L .057 .748 L -.076 .27 L -.188 .298 L -.426 .412 L -.301 .171 L -.269 .256 L -.122 .425 L -.49 1.358 L .197 .338 L .689 .999 L .087 .381 L -.04 .438 L .014 .636 L .237 .634 L .017 1.329 L -.064 .762 L .425 1.439 L -.102 .848 L .122 .693 L .486 .631 L .936 .898 L .428 .78 L .689 1.804 L -.563 .068 L -3.015 .499 L -.347 .214 L -.154 .198 L -.797 1.276 L -.029 .622 L .372 2.088 L -.377 1.175 L -.3 1.02 L .043 .296 L .456 .605 L .837 .843 L .445 .279 L .515 .012 L .448 -.455 L .362 -.186 L .136 .183 L .032 .791 L .028 1.427 L -.041 .551 L -.371 -.012 L -1.355 -.091 L -.348 -.21 L -.381 -.647 L -.561 -.731 L -.416 -.351 L -.477 -.252 L -.895 -.263 L -.38 -.28 L -.728 -1.423 L -.212 .354 L -.522 .682 L -.366 .087 L -.325 -.111 L -.922 -.164 L -.925 -.249 L -.489 -.194 L -.58 -1.014 L -.175 .071 L -1.146 .289 L -.195 -.056 L -.172 -.352 L -.365 -.379 L -.678 -.096 L -1.24 -.147 L -.991 .146 L -.859 .26 L -.61 .004 L -.199 -.197 L -.007 -.254 L .198 -.905 L .003 -.466 L -.306 -.62 L -.844 -.998 L -.117 -.211 L -.021 -.212 L .296 -1.033 L .07 -1.06 L -.109 -.607 L -.303 -.605 L .057 -.354 L .177 -.693 L -.052 -.183 L -.322 -.098 L -1.231 .093 L -.88 .019 L -.212 -.168 L .055 -.48 L -.181 -.225 L -2.016 .082 L -.112 .001 L -.089 .354 L .027 .593 L -.286 .892 L -.184 .411 L -.993 .006 L -.899 -.122 L -1.021 .246 L -.88 .034 L -.292 -.168 L -.64 -.787 L -.597 -1.07 L -.537 -1.409 L -.059 -.579 L -.121 -.521 L -.082 -.127 L -.321 -.111 L -.385 -.012 L -1.104 -.008 L -.88 .034 L -.624 .003 L -1.312 -.048 L -.945 -.052 L -.783 .02 L -.432 .03 L -.318 .101 L -.896 .062 L -.699 .314 L -.56 .06 L -.112 -.013 L -.322 -.922 L .012 -.053 L .74 -.3 L -.017 -.085 L .1 -.89 L .094 -.143 L .317 -.199 L .583 -.568 L +468.568 202.653 N 1.277 -.05 L 4.659 0 L 1.448 -.033 L 4.663 2.568 L 3.553 1.984 L .137 .381 L -.116 .552 L .07 .239 L 2.427 1.752 L 1.067 .807 L -.237 .427 L -.419 1.329 L -.137 1.017 L .109 .551 L .665 .987 L .768 .577 L -.024 .282 L -.263 .354 L -.371 1.046 L .037 .17 L .306 .041 L .118 .226 L -.172 .692 L -.019 .946 L .411 1.793 L .18 .564 L .401 .465 L .823 .55 L .396 .268 L .177 .228 L -1.157 .836 L -.515 .342 L -1.218 .402 L -1.243 .559 L -.448 .031 L -.646 -.42 L -.276 -.083 L -.21 .326 L -.543 .766 L -.396 .144 L -.42 -.054 L -.964 .006 L -.963 .02 L -.512 -.294 L -.323 -.394 L -.229 -.083 L -.123 .128 L -.643 .356 L -.526 .088 L -1.019 -.149 L -.898 -.018 L -.196 -.559 L -.135 -.766 L -.053 -.584 L -.135 -.946 L -.448 -.841 L -.663 -.538 L -1.014 -.107 L -.223 .016 L -.385 -.407 L -.732 -.349 L -1.574 -.57 L -1.269 -.6 L -.729 -.265 L -.263 -.21 L -.703 -.641 L -.689 -1.804 L -.428 -.78 L -.936 -.898 L -.486 -.631 L -.122 -.693 L .102 -.848 L -.425 -1.439 L .064 -.762 L 1.252 -.348 L .388 -.539 L .645 -1.204 L .687 -.853 L .346 -.271 L .044 -.212 L -.148 -.239 L -.273 -.125 L -.401 -.068 L -.211 -.211 L .158 -.976 L .304 -.016 L .396 -.158 L .142 -.17 L .104 -.481 L -.167 -.493 L -.364 -.888 L -.121 -.748 L +464.786 206.235 N -.197 -.338 L .49 -1.358 L .122 -.425 L .269 -.256 L .301 -.171 L .426 -.412 L .064 .042 L .546 .223 L .431 -.045 L .458 -.427 L .554 -.398 L .319 -.017 L .121 .748 L .364 .888 L .167 .493 L -.104 .481 L -.142 .17 L -.396 .158 L -.304 .016 L -.559 .031 L -.508 .159 L -.391 .567 L -.158 .085 L -.396 .13 L -.789 -.32 L -.688 -.024 L +465.79 210.652 N -.017 -1.329 L -.237 -.634 L -.014 -.636 L .04 -.438 L -.087 -.381 L -.689 -.999 L .688 .024 L .789 .32 L .396 -.13 L .158 -.085 L .391 -.567 L .508 -.159 L .559 -.031 L -.158 .976 L .211 .211 L .401 .068 L .273 .125 L .148 .239 L -.044 .212 L -.346 .271 L -.687 .853 L -.645 1.204 L -.388 .539 L -1.252 .348 L +427.243 211.207 N .536 -.414 L .68 -.513 L .351 -.13 L .695 .533 L -.583 .568 L -.317 .199 L -.094 .143 L -.1 .89 L .017 .085 L -.74 .3 L .143 -.625 L -.082 -.24 L -.505 -.796 L h 427.998 213.843 m .112 .013 L .56 -.06 L .699 -.314 L .896 -.062 L .318 -.101 L .432 -.03 L .783 -.02 L .945 .052 L 1.312 .048 L .624 -.003 L .88 -.034 L 1.104 .008 L .385 .012 L .321 .111 L .082 .127 L .121 .521 L .059 .579 L .537 1.409 L .597 1.07 L .64 .787 L .292 .168 L .88 -.034 L 1.021 -.246 L .899 .122 L .993 -.006 L .184 -.411 L .286 -.892 L -.027 -.593 L .089 -.354 L .112 -.001 L 2.016 -.082 L .181 .225 L -.055 .48 L .212 .168 L .88 -.019 L 1.231 -.093 L .322 .098 L .052 .183 L -.177 .693 L -.057 .354 L .303 .605 L .109 .607 L -.07 1.06 L -.296 1.033 L .021 .212 L .117 .211 L .844 .998 L .306 .62 L -.003 .466 L -.198 .905 L .007 .254 L .199 .197 L .61 -.004 L .859 -.26 L .991 -.146 L 1.24 .147 L -.214 1.344 L .195 1.059 L .269 .323 L .089 .254 L -.132 .368 L -.436 .44 L -.124 .594 L -.125 .086 L -.517 -.04 L -3.408 .091 L -.051 .877 L .015 1.342 L -.024 3.249 L .017 .848 L .023 .594 L .099 .438 L .308 .394 L .471 .436 L 1.354 1.391 L .611 .632 L -.93 .218 L -1.96 .379 L -1.044 .203 L -.717 -.08 L -1.164 .063 L -.408 -.083 L -.349 -.21 L -2.024 .026 L -.697 -.024 L -.622 -.151 L -.401 -.322 L -.305 -.366 L -.408 -.096 L -.989 -.023 L -2.59 .016 L -1.636 -.019 L -.631 -.011 L -1.296 -.006 L -2.201 .013 L -.636 -.151 L -.463 -.309 L -.45 -.478 L -.294 -.083 L -.499 .088 L -.591 .286 L -.778 .513 L -.758 -.462 L -.352 .144 L -.248 .197 L .048 -1.809 L -.017 -.805 L -.029 -.649 L .397 -.34 L .221 -.269 L .26 -.707 L .163 -.734 L .184 -1.398 L .239 -.976 L .321 -.918 L .584 -.665 L .183 -.565 L .268 -.354 L .64 -.228 L .268 -.325 L .423 -.679 L .364 -1.201 L .053 -.664 L -.046 -.848 L -.191 -.959 L -.201 -.536 L -.492 -.705 L -.476 -.776 L -.268 -.775 L .139 -.495 L .476 -.382 L .158 -.156 L .107 -.424 L -.006 -.479 L -.199 -.579 L -.489 -.69 L -.441 -.733 L -.203 -1.031 L -.181 -.423 L -.276 -.366 L -.666 -.974 L -.072 -.15 L +452.198 239.34 N -.611 -.632 L -1.354 -1.391 L -.471 -.436 L -.308 -.394 L -.099 -.438 L -.023 -.594 L -.017 -.848 L .024 -3.249 L -.015 -1.342 L .051 -.877 L 3.408 -.091 L .517 .04 L .125 -.086 L .124 -.594 L .436 -.44 L .132 -.368 L -.089 -.254 L -.269 -.323 L -.195 -1.059 L .214 -1.344 L .678 .096 L .365 .379 L .172 .352 L .195 .056 L 1.146 -.289 L .175 -.071 L .58 1.014 L .489 .194 L .925 .249 L .922 .164 L .325 .111 L .366 -.087 L .522 -.682 L .212 -.354 L .728 1.423 L .38 .28 L .895 .263 L .477 .252 L .416 .351 L .561 .731 L .381 .647 L .348 .21 L 1.355 .091 L .371 .012 L .041 -.551 L -.028 -1.427 L -.032 -.791 L -.136 -.183 L -.362 .186 L -.448 .455 L -.515 -.012 L -.445 -.279 L -.837 -.843 L -.456 -.605 L -.043 -.296 L .3 -1.02 L .377 -1.175 L -.372 -2.088 L .029 -.622 L .797 -1.276 L .154 -.198 L .347 -.214 L 3.015 -.499 L .563 -.068 L .703 .641 L .263 .21 L .729 .265 L 1.269 .6 L 1.574 .57 L .732 .349 L .385 .407 L .559 .887 L .434 .859 L .013 .324 L -.183 .27 L -.709 .344 L -.011 .127 L .04 .594 L -.091 1.682 L .08 .353 L .216 .168 L .511 .266 L .072 .197 L -.197 .241 L -.472 .258 L -.792 .259 L -.146 .34 L -.094 .764 L -.3 .807 L .2 .479 L .261 .408 L .394 .125 L -1.264 .53 L -1.696 .575 L -.932 .4 L -2.165 .578 L -.187 .128 L -.009 .495 L .152 .465 L .087 .438 L -.505 -.096 L -.999 .049 L -.794 .259 L -.636 .54 L -.312 .539 L -.019 .579 L -.168 .199 L -.285 .114 L -.999 .062 L -.621 .202 L -.306 .341 L -.777 .937 L -.562 .738 L -.825 .951 L -.354 .045 L -.803 -.165 L -.421 -.309 L -.334 .129 L -.521 .286 L -.404 .017 L -.594 -.209 L -.264 -.097 L -.154 -.169 L -.163 -.027 L -.187 -.154 L -.456 -.393 L -.294 -.055 L -1.089 -.093 L -.086 -.099 L -.165 -.056 L -1.845 .364 L +477.231 225.874 N -.224 1.184 L -.107 .48 L .252 .917 L .177 1.017 L .149 .408 L .238 .268 L .803 .588 L 1.189 1.166 L .454 .661 L .14 .48 L -.155 2.346 L -.04 .41 L -.214 .213 L -.432 .073 L -.322 .017 L -.229 .213 L -.076 .622 L .08 .509 L .029 .479 L -.096 .283 L -.185 -.111 L -.562 -.463 L -.763 -1.112 L -.484 -.548 L -.234 -.423 L .036 -.212 L .499 -.61 L .116 -.227 L .025 -.693 L -.1 -.96 L -.22 -.479 L -.261 -.056 L -.674 .061 L -.702 .132 L -.27 -.211 L -.343 -.407 L -.382 -.549 L -.195 -.041 L -.394 -.125 L -.261 -.408 L -.2 -.479 L .3 -.807 L .094 -.764 L .146 -.34 L .792 -.259 L .472 -.258 L .197 -.241 L -.072 -.197 L -.511 -.266 L -.216 -.168 L -.08 -.353 L .091 -1.682 L -.04 -.594 L .011 -.127 L .709 -.344 L .183 -.27 L -.013 -.324 L -.434 -.859 L -.559 -.887 L .223 -.016 L 1.014 .107 L .663 .538 L .448 .841 L .135 .946 L .053 .584 L .135 .766 L .196 .559 L +245.934 224.314 N .939 .136 L 1.122 .304 L .355 -.03 L .946 -.824 L .336 .026 L .48 .025 L .415 -.243 L 1.471 -1.109 L .874 -.485 L .36 -.158 L .934 -.076 L 1.283 .021 L .045 .748 L -.079 .621 L -.064 .622 L .036 .818 L .141 .635 L .335 .591 L .813 .928 L 1.1 .939 L .316 .097 L .787 .023 L .355 -.03 L .676 .25 L .688 .307 L .75 .603 L .3 .098 L .882 .037 L .096 .014 L .385 .774 L .398 .308 L .22 .084 L 1.148 -.077 L .636 .123 L .537 .166 L .403 .237 L .085 .169 L -.038 .565 L .203 1.029 L .03 .706 L .138 2.032 L .249 .944 L .153 .112 L .967 .036 L .5 .012 L 1.615 .019 L .693 .024 L .042 .296 L -.261 .835 L .067 .563 L .436 .407 L .73 .362 L .316 .479 L .307 .774 L .022 .494 L -.185 1.173 L -.238 .834 L -.38 .765 L -.421 .666 L -.089 -.084 L -1.952 -.991 L -.352 -.054 L -.928 .02 L -.843 -.01 L -.126 .128 L -1.076 .204 L -1.104 .162 L -.784 .202 L -.33 .044 L -.332 .383 L -.698 1.105 L -.278 .341 L -.133 .509 L .016 .635 L -.385 1.188 L -.395 1.104 L -.149 .325 L -.592 -.109 L -1.33 -.077 L -.686 .004 L -1.034 1.784 L -.416 -1.084 L -.341 -.309 L -.37 -.195 L -.531 -.067 L -.527 .045 L -.901 .034 L -.615 -.194 L -.193 -.169 L -.322 -.181 L -.292 .27 L -2.026 2.087 L -1.047 .006 L -.272 -.182 L -.397 -2.144 L -.278 -.973 L -.212 -.563 L -.769 -1.11 L -.249 -.676 L .04 -.354 L .437 -1.555 L -.017 -.282 L -.761 -.744 L -.25 -.521 L -.193 -1.213 L -.304 -.647 L -.555 -.745 L -.152 -.253 L -.018 -.142 L -.132 -.295 L -.049 -.48 L .12 -.227 L .723 -.61 L .285 -.439 L -.015 -.522 L -.604 -1.168 L -.022 -.48 L .159 -.34 L .21 -.368 L -.347 -.845 L .102 -.452 L .532 -.582 L .221 -.34 L .156 -.34 L -.236 -.902 L -.057 -.522 L .143 -.848 L .15 -.523 L .437 -.736 L -.08 -.24 L -.922 -1.646 L -1.109 -1.843 L +473.575 260.04 N -1.331 .011 L -.192 .058 L -.068 -.382 L -.261 -.889 L .071 -.495 L -.075 -.296 L -.095 -.324 L .03 -.806 L .057 -1.301 L -.072 -.763 L -.147 -.678 L -.33 -.944 L -.441 -.689 L -.181 -.946 L -.295 -1.199 L -.159 -.183 L .448 -.384 L .396 -.412 L 1.68 -1.706 L .114 -.227 L -.09 -.367 L .075 -.834 L .229 -.481 L .736 -.683 L .205 -.341 L .168 -.41 L -.594 -.845 L -.118 -.805 L -.113 -.494 L .128 -.283 L .448 -.596 L .201 -.411 L -.132 -.805 L -.086 -1.144 L -.031 -.791 L -.178 -.818 L -.441 -.379 L -.515 -.224 L -1.167 -.347 L -1.042 -.445 L -.658 -.223 L -1.438 -.006 L -.137 -.14 L -.025 -.495 L -.011 -.212 L -.087 -.438 L -.152 -.465 L .009 -.495 L .187 -.128 L 2.165 -.578 L .932 -.4 L 1.696 -.575 L 1.264 -.53 L .195 .041 L .382 .549 L .343 .407 L .27 .211 L .702 -.132 L .674 -.061 L .261 .056 L .22 .479 L .1 .96 L -.025 .693 L -.116 .227 L -.499 .61 L -.036 .212 L .234 .423 L .484 .548 L .763 1.112 L .562 .463 L .185 .111 L .096 -.283 L -.029 -.479 L -.08 -.509 L .076 -.622 L .229 -.213 L .322 -.017 L .432 -.073 L .214 -.213 L .04 -.41 L .155 -2.346 L -.14 -.48 L -.454 -.661 L -1.189 -1.166 L -.803 -.588 L -.238 -.268 L -.149 -.408 L -.177 -1.017 L -.252 -.917 L .107 -.48 L .224 -1.184 L .898 .018 L 1.019 .149 L .526 -.088 L .643 -.356 L .123 -.128 L .229 .083 L .323 .394 L .512 .294 L .963 -.02 L .964 -.006 L .42 .054 L .396 -.144 L .543 -.766 L .21 -.326 L .276 .083 L .646 .42 L .448 -.031 L 1.243 -.559 L 1.218 -.402 L .515 -.342 L 1.157 -.836 L .128 .167 L .212 .479 L -.185 .579 L -.302 .453 L -.198 .255 L .181 .451 L .129 .72 L -.012 .466 L .182 1.115 L -.101 .58 L -.258 .325 L .374 .705 L .154 .494 L -.006 1.115 L -.004 .819 L .043 .184 L .185 .127 L .327 .084 L .015 .269 L -.165 .494 L -.563 .58 L .184 .381 L -.08 .283 L -.418 .565 L -.802 .906 L -.512 .622 L -.72 .651 L -1.36 .751 L -1.48 .653 L -.73 .228 L -1.308 .582 L -.852 .637 L -1.286 1.443 L -.886 .85 L -1.193 .878 L -1.181 .836 L -.268 .128 L -.035 .96 L -.083 .495 L .058 .127 L .719 .535 L .188 .381 L -.166 .452 L -.085 .184 L .461 1.511 L .071 .564 L .06 .155 L .246 .014 L .171 -.128 L .141 -.085 L .043 .607 L -.234 2.218 L -.284 .82 L .325 .196 L .152 .057 L -.025 .325 L -.157 .311 L -.516 .566 L -.699 .538 L -.664 .34 L -1.266 .412 L -.796 .312 L -.688 .228 L -.895 .524 L -.652 .665 L -.337 .51 L .292 .338 L .589 .338 L .045 .325 L -.149 1.022 L +499.85 236.166 N .544 -.071 L .622 -.369 L .18 .028 L .346 .098 L .269 -.085 L .396 -.368 L .911 -.143 L .311 .281 L .305 -.028 L .101 -.185 L -.171 -.366 L .771 -.539 L .423 -.198 L .322 .226 L .389 -.213 L -.308 -.494 L .207 -.282 L .505 -.425 L .229 .296 L .229 .056 L .558 -.594 L -.158 -.197 L -.253 -.409 L .094 -.297 L .243 .014 L .27 -.071 L .172 -.34 L -.297 -.875 L .06 -.339 L .255 -.043 L .117 .07 L .253 .438 L .28 .099 L .2 -.41 L .692 -.524 L .235 -.367 L .134 -.452 L .168 -.692 L -.133 -.354 L .003 -.226 L .537 -.468 L .356 .324 L .455 .648 L .612 .281 L .141 .198 L .213 .847 L .294 1.821 L .093 .663 L .231 .791 L .391 .733 L .163 .466 L -.038 .367 L -.069 .155 L -.058 .099 L -.537 .807 L -.22 -.127 L -.189 -.366 L -.555 -.748 L -.297 .143 L -.05 .424 L .193 .875 L .396 .521 L .079 .396 L -.307 .636 L -.746 1.005 L -.045 .452 L .041 .89 L -.18 .946 L -.709 2.12 L -.825 2.572 L -1.254 3.788 L -1.324 4.48 L -.518 1.568 L -.188 .255 L -.508 .637 L -.2 .113 L -1.369 .102 L -.999 .327 L -.474 .468 L -.813 .086 L -.363 -.465 L -.196 -.142 L -.546 -.182 L -.37 .071 L -.269 -.057 L -.863 -.718 L -.104 -.24 L -.02 -.565 L -.104 -.239 L -.46 -.366 L -.124 -.282 L .001 -.721 L .345 -1.088 L -.094 -.325 L -.287 -.479 L -.62 -.931 L -.189 -.494 L .075 -.664 L .391 -1.37 L .228 -.213 L .474 -.185 L .768 -1.371 L .686 -1.174 L .104 -.325 L .151 -1.103 L -.11 -.353 L -.278 -.226 L -.354 -.366 L .066 -.184 L .252 -.509 L -.521 -.861 L -.117 -.677 L -.069 -.494 L -.231 -.721 L .024 -.112 L .517 -.693 L .362 -.594 L .163 -.438 L .007 -1.073 L .484 -.016 L +468.138 234.908 N .011 .212 L .025 .495 L .137 .14 L 1.438 .006 L .658 .223 L 1.042 .445 L 1.167 .347 L .515 .224 L .441 .379 L .178 .818 L .031 .791 L .086 1.144 L .132 .805 L -.201 .411 L -.448 .596 L -.128 .283 L .113 .494 L .118 .805 L .594 .845 L -.168 .41 L -.205 .341 L -.736 .683 L -.229 .481 L -.075 .834 L .09 .367 L -.114 .227 L -1.68 1.706 L -.396 .412 L -.448 .384 L -.342 -.225 L -.547 -.124 L -.442 -.025 L -.529 .145 L -.31 .016 L -.99 -.403 L -.597 -.139 L -.72 -.023 L -.067 -.042 L -.186 -.098 L -.306 -.451 L -.479 -.35 L -.549 -.167 L -.938 -.136 L -.352 -.153 L -.524 -.873 L -.163 -.564 L .032 -.565 L -.127 -.239 L -.78 .019 L -.201 -.098 L -.109 -.211 L .051 -.537 L -.106 -.169 L -.552 -.266 L -.533 -.223 L -.57 -.321 L -.563 -.491 L -.377 -.662 L -.246 -.96 L -.469 -.604 L -.43 -.478 L -.267 -.451 L .103 -.227 L .594 .209 L .404 -.017 L .521 -.286 L .334 -.129 L .421 .309 L .803 .165 L .354 -.045 L .825 -.951 L .562 -.738 L .777 -.937 L .306 -.341 L .621 -.202 L .999 -.062 L .285 -.114 L .168 -.199 L .019 -.579 L .312 -.539 L .636 -.54 L .794 -.259 L .999 -.049 L .505 .096 L +444.673 255.519 N -.006 3.434 L .031 1.894 L .025 2.246 L -.057 .205 L -.454 .318 L -.545 .302 L -.581 .498 L -.427 .034 L -.581 -.166 L -.745 -.042 L -.892 .048 L -.517 -.039 L -.296 -.212 L -.055 -.528 L -.042 -.345 L -.193 -.222 L -.637 -.348 L -.329 -.127 L -.335 .116 L -.109 .217 L -.317 .416 L -.584 .27 L -.152 .068 L -.458 -.491 L -1.041 -1.001 L -.458 -.606 L -.359 -1.03 L -.345 -.72 L -.136 -.493 L .12 -.269 L .053 -.34 L -.458 -.719 L -.231 -.861 L .148 -.861 L -.002 -.48 L -.537 -1.326 L -.496 -2.244 L .772 -.02 L .04 -.678 L -.077 -.749 L -.456 -.006 L .016 -.06 L -.099 -.522 L -.26 -.508 L -1.018 -1.283 L -.343 -.55 L -1.102 -2.158 L -.841 -1.623 L -.9 -1.509 L -.988 -1.269 L -.511 -1.044 L -.122 -.396 L -.045 -.551 L .015 -.578 L .248 -.197 L .352 -.144 L .758 .462 L .778 -.513 L .591 -.286 L .499 -.088 L .294 .083 L .45 .478 L .463 .309 L .636 .151 L 2.201 -.013 L 1.296 .006 L .631 .011 L 1.636 .019 L 2.59 -.016 L .989 .023 L .408 .096 L .305 .366 L .401 .322 L .622 .151 L .697 .024 L 2.024 -.026 L .349 .21 L .408 .083 L 1.164 -.063 L .717 .08 L 1.044 -.203 L 1.96 -.379 L .93 -.218 L 1.845 -.364 L .165 .056 L .086 .099 L 1.089 .093 L .294 .055 L .456 .393 L -.811 .315 L -.891 .02 L -.284 .143 L -.993 .938 L -.209 .029 L -.62 -.773 L -1.048 .134 L -2.962 .47 L -1.183 .021 L .005 1.215 L -.007 1.286 L -.025 .876 L -.043 1.201 L .002 3.561 L -.586 .046 L -1.564 .052 L -.146 .028 L -.106 2.657 L -.009 1.201 L .013 1.624 L .007 .806 L +248.453 316.576 N -.306 .101 L -.892 -.087 L -.538 -.293 L -.236 -.015 L -.311 .163 L -.418 .398 L -.498 .192 L -1.156 .091 L -.349 .09 L -.358 .207 L -.267 .621 L -.114 .341 L .06 .532 L -.163 .622 L -.104 .148 L -.453 .031 L -.534 .104 L -.956 -.413 L .667 -.639 L .326 -.444 L .582 -.4 L .025 -.147 L -.372 -.177 L -.273 -.117 L -1.353 .534 L -1.01 -.013 L -.545 .163 L -.202 -.339 L .128 -.192 L .959 -.268 L .266 .028 L .792 -.208 L .441 -.118 L -.605 -.162 L -.582 .002 L -.77 .001 L -.014 -.413 L .265 -.31 L -.007 -.191 L -.446 -.073 L -.356 -.44 L -.66 .384 L -.669 -.175 L .292 -.53 L .041 -.177 L -.378 .045 L -.361 .147 L -.416 -.396 L -.215 -.117 L .413 -.279 L .114 -.177 L -.091 -.278 L -.053 -.073 L -.351 .03 L -.773 -.424 L -.135 -.059 L .844 -.192 L .253 -.161 L .1 -.294 L .396 -.366 L .049 -.234 L -.641 .06 L -.257 .104 L -.312 -.073 L -.256 -.672 L .573 -.395 L -.565 -.378 L -.12 -.421 L .757 -.452 L -.14 -.421 L -.686 .422 L -.091 -1.523 L .399 -.596 L -.185 -.825 L .013 -.218 L .593 .014 L .41 .245 L .711 .071 L .171 -.246 L .002 -.159 L -.896 -.447 L -.867 .146 L -.317 -.173 L -.536 .059 L -.017 -.231 L .339 -.333 L .025 -.246 L -.067 -.087 L .186 -.202 L .536 .014 L .229 -.377 L .01 -.216 L -.722 -.389 L -.354 -.129 L -.886 .045 L -.332 -.101 L -.024 -.49 L -.939 .16 L -.115 -.101 L .122 -.145 L 1.032 -.521 L .251 -.116 L .4 -.404 L .266 -.389 L .833 -.06 L .268 .201 L .059 .346 L -.648 .202 L -.323 .274 L .11 .505 L .117 .058 L .191 -.102 L .268 -.39 L .183 -.087 L .242 .101 L -.037 .317 L .057 .504 L .886 -.996 L .161 -.678 L .056 -.647 L .237 -.375 L .079 -.058 L .631 -.217 L -.201 -.071 L -.438 -.143 L -.056 -.158 L .101 -.273 L .246 -.072 L .571 -.245 L .599 -.431 L .271 -.459 L -.061 -.229 L -.394 -.157 L -.662 -.399 L -.053 -.372 L .139 -.243 L .105 -.458 L -.06 -.828 L .366 -.33 L .676 -.272 L -.431 -.585 L -.053 -.784 L .133 -.158 L .554 -.157 L .054 -.314 L -.116 -.285 L -.317 -.085 L -.272 -.198 L .233 -.329 L .087 -.313 L -.401 -.185 L -.274 -.014 L -.161 .101 L -.476 .414 L -.548 .058 L -.087 .001 L -.289 -.199 L -.16 -.484 L -.399 -.726 L -.133 -.697 L .188 -.911 L .137 -.413 L .722 -.739 L .535 -.767 L -.006 -.326 L -.544 -1.757 L .001 -.608 L .088 -.567 L -.076 -.438 L -.528 -.891 L -.04 -.298 L .236 -.198 L .499 .098 L .182 -.085 L .2 -.142 L .097 -.143 L .41 -1.288 L .252 -.481 L .304 -.935 L .18 -.65 L .664 -.808 L .363 -.722 L .201 -.636 L .252 -.946 L .311 -.691 L .187 -.128 L .273 -.382 L .013 -.296 L -.312 -.847 L .082 -.184 L .455 -.452 L .206 -.339 L .028 -.24 L -.093 -.226 L -.166 -.805 L -.292 -2.088 L -.098 -.86 L .031 -.565 L .412 -.565 L .37 -.537 L .207 -.564 L .007 -.734 L -.339 -.521 L -.098 -.409 L .295 -.96 L .218 -.941 L .127 -.556 L .461 -.594 L .171 -.918 L .243 -.975 L .126 -.805 L .082 -.565 L -.063 -1.087 L .422 -.664 L .211 -.494 L -.221 -.932 L -.048 -.833 L .148 -.24 L -.022 -.917 L .229 -.607 L -.124 -.297 L -.365 -.084 L .06 -.324 L -.046 -.396 L .223 -.198 L .402 -.198 L .137 -.424 L -.008 -.819 L .093 -.593 L .182 -.918 L -.004 -2.344 L -.172 -2.074 L -.042 -1.539 L -.194 -.974 L -.15 -.387 L .852 -.275 L .259 -.298 L .228 -.933 L .15 -.199 L .586 -.187 L .152 .253 L .555 .745 L .304 .647 L .193 1.213 L .25 .521 L .761 .744 L .017 .282 L -.437 1.555 L -.04 .354 L .249 .676 L .769 1.11 L .212 .563 L .278 .973 L .397 2.144 L .272 .182 L 1.047 -.006 L .107 .056 L .212 .14 L .161 .154 L -.093 .636 L -.541 1.457 L -.36 .256 L -1.346 .53 L -.819 .372 L -.204 .312 L .25 .817 L -.421 .722 L -.007 .579 L .113 .437 L .34 .449 L .03 .226 L -.273 .369 L -.161 .382 L .114 .507 L .53 .477 L .011 .227 L -.152 .311 L -.333 .017 L -.791 .089 L -.329 .835 L -.464 .835 L -.608 .694 L -.282 .439 L -.823 1.839 L .167 1.466 L .054 .762 L -.124 .185 L -.492 .271 L -.292 .34 L -.388 1.201 L -.156 .961 L .285 .633 L .408 1.154 L .784 2.816 L .055 .69 L -.075 .41 L -1.083 1.854 L -.319 .595 L .088 .409 L .189 1.06 L -.078 .325 L -1.334 1.11 L -.231 .312 L -.142 1.075 L .014 1.16 L .249 1.103 L .437 .932 L -.202 .143 L -.951 .529 L -.126 .17 L -.053 .312 L -.511 2.427 L -.316 .541 L -.1 .37 L .123 1.835 L .231 .867 L .012 .427 L -.596 .317 L -.172 .172 L -.106 .271 L .094 1.226 L .125 .128 L .555 .111 L .088 .655 L -.191 1.458 L .252 .585 L .26 .185 L .789 .11 L .302 .17 L -.007 .186 L -.245 .202 L -.322 .13 L -.726 .033 L -.757 .146 L .176 .171 L .586 .298 L .552 .385 L .017 .216 L -.767 .794 L -.059 1.094 L .158 1.035 L -.216 .896 L -.212 .434 L -.226 .262 L -.598 .161 L -.28 .219 L -.249 .781 L .446 .648 L -.069 .188 L -.296 1.218 L -.307 .263 L -1.729 1.01 L -.271 .292 L -.037 .45 L .28 1.309 L .508 1.123 L .218 .043 L .961 -.283 L .654 -.121 L .187 .248 L .231 2.285 L .778 .568 L .669 .041 L 1.41 -.052 L 2.827 .132 L .841 .217 L 1.385 .36 L .286 .039 L h 236.642 296.773 m -.394 -.113 L -.43 -.028 L -.21 -.171 L -.133 -.229 L .21 -.457 L .15 -.657 L -.087 -.514 L .011 -.414 L .364 -.728 L .817 -.116 L .36 .327 L .044 .328 L -.688 .443 L -.146 .229 L .493 .771 L -.194 1.058 L -.167 .271 L h 238.177 317.937 m -.445 -.177 L .083 -.842 L -.849 .075 L -.073 -.368 L .218 -.354 L .823 .102 L .508 -.207 L .205 .103 L .054 .812 L -.267 .34 L -.257 .518 L h 247.801 322.062 m -1.033 .102 L -.467 -.118 L -.55 -.237 L -.42 .001 L -.481 .104 L -.935 .226 L -.496 .03 L .125 -.343 L .202 -.312 L -.104 -.312 L .906 -.15 L 1.434 .058 L .433 .323 L .706 -.007 L -.622 -.689 L -.307 -.163 L -.56 -.117 L -.178 -.089 L -.188 .03 L -.338 -.341 L -.229 -.4 L 1.611 -.581 L -.044 -.296 L -.165 -.147 L -1.819 .285 L -.292 -.222 L .263 -.474 L .146 -.163 L 1.074 -.52 L .868 -.637 L .414 .28 L 1.153 .062 L -.008 1.144 L -.098 3.675 L +456.133 239.67 N .187 .154 L .163 .027 L .154 .169 L .264 .097 L -.103 .227 L .267 .451 L .43 .478 L .469 .604 L .246 .96 L .377 .662 L .563 .491 L .57 .321 L .533 .223 L .552 .266 L .106 .169 L -.051 .537 L .109 .211 L .201 .098 L .78 -.019 L .127 .239 L -.032 .565 L .163 .564 L .524 .873 L .352 .153 L .938 .136 L .549 .167 L .479 .35 L .306 .451 L .186 .098 L -.317 .411 L -.388 .327 L -.507 .243 L -.747 .075 L -.304 .115 L -.7 .823 L -.586 .583 L -.362 .229 L -.747 .357 L -.388 .355 L -.107 .636 L -.222 .666 L -.247 .241 L -.634 .357 L -.98 .33 L -.249 .214 L -.217 .708 L -.345 .963 L -.288 .354 L -.237 .129 L -.584 .116 L -.43 -.026 L -.473 .06 L -.511 -.011 L -.819 -.193 L -.744 -.32 L -.979 -.645 L -.545 -.039 L -.333 .186 L -.084 .24 L -.585 1.134 L -.382 .469 L -.651 .625 L -.632 .428 L -.8 .372 L -.823 .033 L -.854 .047 L -.368 -.097 L -.11 -.183 L .003 -.48 L .243 -.609 L .166 -.538 L -.21 -.762 L -.547 -.943 L -.716 -.787 L -.528 -.067 L -.007 -.806 L -.013 -1.624 L .009 -1.201 L .106 -2.657 L .146 -.028 L 1.564 -.052 L .586 -.046 L -.002 -3.561 L .043 -1.201 L .025 -.876 L .007 -1.286 L -.005 -1.215 L 1.183 -.021 L 2.962 -.47 L 1.048 -.134 L .62 .773 L .209 -.029 L .993 -.938 L .284 -.143 L .891 -.02 L .811 -.315 L +279.288 257.295 N .02 .239 L -.544 1.57 L -.375 .468 L -1.007 .74 L -.301 .27 L -.352 .51 L -.609 -.363 L -.35 -.097 L -.235 .029 L -.387 .172 L -.745 .131 L -.71 .005 L -.564 -.096 L -.992 -.333 L -.607 -.025 L -1.187 .332 L -.19 -.056 L .064 -.212 L .425 -.426 L .486 -.398 L .11 -.198 L -.21 -.619 L .048 -.227 L .625 -.851 L .617 -1.203 L .018 -.268 L -.939 -.503 L -.65 -.18 L -1.448 -.697 L -1.632 -1.106 L -.671 -.307 L -1.173 -.204 L -.498 -.237 L -.835 -.588 L -.576 -.562 L -1.271 -1.376 L -.782 -.913 L -.225 -.337 L -.19 -.056 L .149 -.325 L .395 -1.104 L .385 -1.188 L -.016 -.635 L .133 -.509 L .278 -.341 L .698 -1.105 L .332 -.383 L .33 -.044 L .784 -.202 L 1.104 -.162 L 1.076 -.204 L .126 -.128 L .843 .01 L .928 -.02 L .352 .054 L 1.952 .991 L .089 .084 L .253 .408 L .084 .663 L .521 .872 L .104 .959 L -.132 .862 L -.086 .721 L -.006 .72 L .372 .04 L .818 .15 L .925 .221 L .346 -.03 L .709 -.413 L .115 -.001 L .724 .278 L .843 .404 L .121 .437 L .487 2.524 L .254 .563 L .224 .055 L 1.29 -.445 L .234 .112 L .491 .336 L .019 .141 L -.321 .75 L -.298 .835 L -.222 .819 L -.027 .777 L .063 .423 L +444.673 255.519 N .528 .067 L .716 .787 L .547 .943 L .21 .762 L -.166 .538 L -.243 .609 L -.003 .48 L .11 .183 L .368 .097 L .854 -.047 L .823 -.033 L .8 -.372 L .632 -.428 L .651 -.625 L .382 -.469 L .585 -1.134 L .084 -.24 L .333 -.186 L .545 .039 L .979 .645 L .744 .32 L .819 .193 L .511 .011 L .473 -.06 L .43 .026 L .584 -.116 L .237 -.129 L .288 -.354 L .345 -.963 L .217 -.708 L .249 -.214 L .98 -.33 L .634 -.357 L .247 -.241 L .222 -.666 L .107 -.636 L .388 -.355 L .747 -.357 L .362 -.229 L .586 -.583 L .7 -.823 L .304 -.115 L .747 -.075 L .507 -.243 L .388 -.327 L .317 -.411 L .067 .042 L .72 .023 L .597 .139 L .99 .403 L .31 -.016 L .529 -.145 L .442 .025 L .547 .124 L .342 .225 L .159 .183 L .295 1.199 L .181 .946 L .441 .689 L .33 .944 L .147 .678 L .072 .763 L -.057 1.301 L -.03 .806 L .095 .324 L -1.449 -.585 L -.279 .199 L -.657 .979 L -.28 .567 L -.005 .325 L .39 .676 L .307 .465 L .458 .322 L .671 .109 L .595 -.004 L .076 -.594 L .064 -.198 L .312 -.186 L .131 -.015 L .192 -.058 L 1.331 -.011 L -.182 1.195 L -.352 .849 L -.182 .184 L -.404 .1 L -.093 .24 L .199 .536 L -.104 .467 L -.248 .354 L -.569 .453 L -.923 .581 L -.591 .75 L -1.383 1.98 L -.631 .834 L -1.242 1.373 L -1.193 1.062 L -.829 .863 L -1.434 1.034 L -1.379 1.091 L -.552 .382 L -.989 .638 L -.676 .298 L -.782 .101 L -.98 -.012 L -.549 .071 L -.132 .354 L .013 .127 L -.109 .085 L -.449 -.098 L -.553 -.126 L -.303 .015 L -.25 .198 L -.272 .312 L -.226 .113 L -.36 -.056 L -.768 -.408 L -.759 -.168 L -.542 -.013 L -.31 .113 L -.38 .27 L -.482 -.099 L -.645 -.21 L -.295 .1 L -.638 .043 L -.589 .214 L -.729 .538 L -.72 .086 L -.44 -.013 L -.667 -.084 L -.738 .072 L -.575 .199 L -.827 .82 L -1.251 -.576 L -.092 -.509 L -.218 -.183 L -.479 -.056 L -.28 .085 L -.257 -.479 L -.343 -.056 L -.149 .255 L -.035 .197 L -.312 -.112 L -.119 -.226 L .267 -.495 L .103 -.424 L -.857 -1.354 L -.323 -.282 L -.134 -.226 L .173 -.17 L .636 -.044 L .172 -.424 L .06 -.819 L -.163 -.663 L -.186 -.522 L -.61 -1.143 L -.75 -1.029 L -.472 -.903 L -.612 -1.383 L -.646 -1.467 L -.573 -.818 L -.436 -.467 L .152 -.068 L .584 -.27 L .317 -.416 L .109 -.217 L .335 -.116 L .329 .127 L .637 .348 L .193 .222 L .042 .345 L .055 .528 L .296 .212 L .517 .039 L .892 -.048 L .745 .042 L .581 .166 L .427 -.034 L .581 -.498 L .545 -.302 L .454 -.318 L .057 -.205 L -.025 -2.246 L -.031 -1.894 L .006 -3.434 L h 462.462 268.501 m .412 -.044 L .194 -.553 L .633 -.343 L 1.035 -.303 L .263 -.199 L .582 -1.007 L .268 -.326 L .143 -.241 L -.104 -.226 L -.967 -.744 L -.33 -.337 L -.422 -.266 L -.308 .086 L -.995 .359 L -.65 .329 L -.513 .567 L -.275 .44 L -.691 .611 L .12 .409 L .582 .858 L .285 .366 L .739 .561 L h 432.955 250.661 m .456 .006 L .077 .749 L -.04 .678 L -.772 .02 L -.078 -.354 L -.028 -.396 L .285 -.297 L .101 -.406 L +471.719 258.047 N .075 .296 L -.071 .495 L .261 .889 L .068 .382 L -.131 .015 L -.312 .186 L -.064 .198 L -.076 .594 L -.595 .004 L -.671 -.109 L -.458 -.322 L -.307 -.465 L -.39 -.676 L .005 -.325 L .28 -.567 L .657 -.979 L .279 -.199 L 1.449 .585 L +462.462 268.501 N -.739 -.561 L -.285 -.366 L -.582 -.858 L -.12 -.409 L .691 -.611 L .275 -.44 L .513 -.567 L .65 -.329 L .995 -.359 L .308 -.086 L .422 .266 L .33 .337 L .967 .744 L .104 .226 L -.143 .241 L -.268 .326 L -.582 1.007 L -.263 .199 L -1.035 .303 L -.633 .343 L -.194 .553 L -.412 .044 L +790.15 283.022 N .738 .197 L .008 -.227 L -.242 -.524 L .052 -.284 L .233 .014 L .389 .17 L .37 .751 L .277 .964 L .48 .17 L 1.753 .691 L .506 .113 L .37 -.072 L .699 -.483 L .885 -.343 L .4 .027 L .329 .17 L .066 .454 L -.022 .198 L -.402 1.236 L -.283 .072 L -.761 .058 L -.035 .683 L -.124 .156 L -.424 .029 L -.746 .016 L -.432 .2 L -.271 .284 L .041 .384 L .254 .525 L -.002 .213 L -.151 .199 L -.646 .515 L -.898 1.129 L -.847 1.058 L -.756 .587 L -.68 .316 L -.337 -.171 L -.47 -.313 L -.237 -.328 L .056 -.314 L .288 -.386 L .307 -.671 L .398 -.5 L -.031 -.343 L -.271 -.128 L -.761 -.582 L -.421 -.185 L -.593 -.184 L -.98 -.452 L -.306 -.256 L -.11 -.17 L .081 -.128 L .419 -.157 L 1.389 -.685 L .209 -.512 L -.078 -.695 L .087 -.312 L .396 -.441 L .032 -.383 L -.482 -.837 L .081 -.567 L -.156 -.311 L -.479 -.655 L -.574 -.678 L .102 -.164 L -.145 -.304 L -.291 -.351 L -.336 -.188 L -.29 -.163 L .117 .233 L .497 .515 L .049 .141 L -.169 0 L -.211 -.281 L -.525 -.631 L -.622 -.771 L -.518 -.561 L .001 -.117 L -.268 -.257 L .04 -.141 L .013 -.14 L -.048 -.188 L -.197 -.396 L -.379 -.42 L -.347 -.257 L .163 -.046 L .205 .093 L .358 -.047 L .131 -.093 L .084 .28 L -.149 .187 L .186 .303 L .177 .21 L .167 .116 L .228 .164 L .041 -.141 L .269 .023 L .519 .257 L .42 .117 L .274 .07 L .128 .257 L -.011 .141 L .185 .023 L .146 -.188 L .185 .023 L -.022 .164 L .227 .351 L .249 .187 L .233 .28 L -.18 .023 L -.076 .164 L .093 .163 L -.242 -.023 L -.175 -.047 L .143 .117 L .251 .188 L .23 .233 L .352 .28 L .063 .234 L .019 .21 L -.261 -.047 L .096 .164 L .239 .351 L .256 .188 L -.292 .023 L -.226 0 L -.205 -.047 L -.006 .141 L .306 .14 L .324 .164 L -.09 .211 L .205 .046 L .265 -.023 L .226 0 L .223 .141 L -.114 .07 L -.031 .141 L .025 .141 L .136 .06 L h 782.939 297.694 m -.088 .158 L -.558 .13 L -.309 .288 L -.322 .101 L -.246 .244 L -.692 -.242 L -.16 .086 L .15 .216 L .429 .415 L -.141 .173 L .02 .259 L -.064 .431 L -.218 -.071 L -.976 -.099 L .418 .229 L .449 .244 L -.278 .49 L -.427 .896 L -.212 .549 L -.418 .318 L -.673 .349 L -.171 .246 L -.259 .145 L -.581 .233 L -.593 .406 L -.398 .015 L -1.156 -.258 L -.628 .112 L -.585 -.442 L -.812 -.158 L -.373 -.066 L -.162 -.308 L -.467 -.098 L -.24 .142 L -.062 .168 L -.78 .095 L -.214 -.166 L -.515 -.095 L -.146 -.286 L .432 -.089 L -.223 -.216 L .328 -.116 L .322 -.001 L -.452 -.482 L .82 .266 L -.464 -.576 L .121 -.145 L .946 .156 L .082 -.13 L -.141 -.173 L -.201 -.216 L -.06 -.288 L .283 -.303 L .569 -.246 L .328 -.374 L .561 -.375 L .102 -.302 L .998 -.575 L 1.106 -.275 L .713 -.331 L .544 -.36 L .377 -.101 L .685 -.575 L .066 -.272 L .48 -.302 L .373 -.015 L .787 -.331 L .664 -.402 L .126 -.215 L -.008 -.172 L .266 -.144 L .448 -.302 L -.109 -.501 L .076 -.214 L .166 -.44 L .306 .048 L .066 -.152 L .58 -.259 L .444 -.272 L .137 -.285 L .131 -1.187 L .512 -.647 L .372 .047 L .365 .165 L .032 .259 L .337 .06 L .187 .186 L .231 .799 L .312 .242 L .973 -.645 L .426 -.029 L .367 .113 L .222 .5 L -.197 .399 L .299 .429 L .066 .271 L -.611 .659 L -.261 .401 L -.476 .358 L -.868 .746 L -.578 .359 L -.295 .13 L -.236 .258 L -.389 .159 L -.271 .258 L .416 .407 L .428 .047 L .421 .289 L -.276 .113 L -.484 .07 L -.503 -.296 L -.488 .131 L -.352 .158 L +247.899 318.387 N .008 -1.144 L .821 .289 L .06 .206 L -.354 .312 L -.534 .337 L h 248.453 316.576 m -.286 -.039 L -1.385 -.36 L -.841 -.217 L -2.827 -.132 L -1.41 .052 L -.669 -.041 L -.778 -.568 L -.231 -2.285 L -.187 -.248 L -.654 .121 L -.961 .283 L -.218 -.043 L -.508 -1.123 L -.28 -1.309 L .037 -.45 L .271 -.292 L 1.729 -1.01 L .307 -.263 L .296 -1.218 L .069 -.188 L -.446 -.648 L .249 -.781 L .28 -.219 L .598 -.161 L .226 -.262 L .212 -.434 L .216 -.896 L -.158 -1.035 L .059 -1.094 L .767 -.794 L -.017 -.216 L -.552 -.385 L -.586 -.298 L -.176 -.171 L .757 -.146 L .726 -.033 L .322 -.13 L .245 -.202 L .007 -.186 L -.302 -.17 L -.789 -.11 L -.26 -.185 L -.252 -.585 L .191 -1.458 L -.088 -.655 L -.555 -.111 L -.125 -.128 L -.094 -1.226 L .106 -.271 L .172 -.172 L .596 -.317 L -.012 -.427 L -.231 -.867 L -.123 -1.835 L .1 -.37 L .316 -.541 L .511 -2.427 L .053 -.312 L .126 -.17 L .951 -.529 L .202 -.143 L -.437 -.932 L -.249 -1.103 L -.014 -1.16 L .142 -1.075 L .231 -.312 L 1.334 -1.11 L .078 -.325 L -.189 -1.06 L -.088 -.409 L .319 -.595 L 1.083 -1.854 L .075 -.41 L -.055 -.69 L -.784 -2.816 L -.408 -1.154 L -.285 -.633 L .156 -.961 L .388 -1.201 L .292 -.34 L .492 -.271 L .124 -.185 L -.054 -.762 L -.167 -1.466 L .823 -1.839 L .282 -.439 L .608 -.694 L .464 -.835 L .329 -.835 L .791 -.089 L .333 -.017 L .152 -.311 L -.011 -.227 L -.53 -.477 L -.114 -.507 L .161 -.382 L .273 -.369 L -.03 -.226 L -.34 -.449 L -.113 -.437 L .007 -.579 L .421 -.722 L -.25 -.817 L .204 -.312 L .819 -.372 L 1.346 -.53 L .36 -.256 L .541 -1.457 L .093 -.636 L -.161 -.154 L -.212 -.14 L -.107 -.056 L 2.026 -2.087 L .292 -.27 L .322 .181 L .193 .169 L .615 .194 L .901 -.034 L .527 -.045 L .531 .067 L .37 .195 L .341 .309 L .416 1.084 L 1.034 -1.784 L .686 -.004 L 1.33 .077 L .592 .109 L .19 .056 L .225 .337 L .782 .913 L 1.271 1.376 L .576 .562 L .835 .588 L .498 .237 L 1.173 .204 L .671 .307 L 1.632 1.106 L 1.448 .697 L .65 .18 L .939 .503 L -.018 .268 L -.617 1.203 L -.625 .851 L -.048 .227 L .21 .619 L -.11 .198 L -.486 .398 L -.425 .426 L -.064 .212 L .19 .056 L 1.187 -.332 L .607 .025 L .992 .333 L .564 .096 L .71 -.005 L .745 -.131 L .387 -.172 L .235 -.029 L .35 .097 L .609 .363 L .352 -.51 L .301 -.27 L 1.007 -.74 L .375 -.468 L .544 -1.57 L -.02 -.239 L .957 -.161 L .462 -.017 L .206 .196 L .517 1.154 L -.094 1.638 L -.161 .467 L -.521 .313 L -1.754 .744 L -.348 .242 L -1.633 1.448 L -1.435 1.363 L -1.805 1.816 L -.833 .88 L -.214 .27 L -.443 .524 L -.065 .452 L -.595 2.359 L -.103 .522 L .049 .847 L .168 .986 L -.118 .325 L -.48 .524 L -.24 .495 L -.011 .522 L .194 .577 L -.054 .338 L -.162 .273 L -.26 .325 L .015 .226 L .924 .831 L .68 .281 L .715 .281 L .283 .169 L .281 .325 L -.025 .325 L -.362 .523 L -.043 .396 L .105 .339 L .174 .269 L .466 .325 L .522 .168 L .109 .113 L .226 .892 L -.308 .481 L -.75 .937 L -.729 .766 L -.313 .737 L -.368 .284 L -.832 .342 L -1.04 .342 L -1.92 .401 L -1.795 .188 L -1.361 .116 L -.945 .044 L -1.175 -.11 L -.934 -.226 L -.128 .199 L .036 .808 L .322 .312 L .308 .184 L -.09 .298 L -.381 .624 L -.345 .498 L -.069 .385 L .392 .682 L .066 .285 L -.208 .214 L -.105 .057 L -1.251 .473 L -1.137 .116 L -.814 -.069 L -.967 -.34 L -1.47 -.396 L -.246 .057 L -.23 .271 L .041 .598 L .429 .684 L .037 .398 L -.242 .643 L .092 .385 L .773 .54 L .796 .084 L .369 -.2 L -.387 -.398 L .872 -.188 L .383 -.043 L .234 1.041 L .052 .3 L -.144 .157 L -.299 .101 L -.448 .072 L -.261 -.157 L -.104 -.299 L -.115 -.071 L -1.046 .073 L -.67 .201 L -.212 .101 L .151 .214 L .591 .07 L .47 .113 L .452 .113 L .06 .028 L -.864 .388 L -.776 .287 L -.577 .602 L .003 .414 L .161 .787 L -.081 .258 L -.815 .817 L .022 .215 L .423 .371 L -.491 .116 L -1.194 .088 L -.48 .087 L -.632 .246 L -.619 .389 L -.56 .548 L -.549 .821 L -.052 .389 L .061 .375 L .312 .591 L .48 .446 L .98 .633 L .657 .244 L .97 .143 L .362 .086 L .14 .274 L -.151 .796 L -.128 .348 L -.342 .464 L -.189 .145 L -1.08 .524 L -1.541 .814 L -.712 .698 L -.179 .276 L -.093 .45 L .111 .523 L -.169 .451 L -.239 .32 L -.97 .454 L -.969 .25 L -.421 .221 L -.323 .396 L -.226 .791 L -.054 .514 L .2 .777 L .547 .896 L .699 .779 L .235 .339 L -.101 .032 L h 247.899 318.387 m .18 .182 L .148 .073 L .607 -.075 L .344 .133 L .648 .725 L .908 .665 L .993 .756 L .525 .222 L .73 .37 L .246 .074 L .42 -.001 L .483 .163 L 1.283 .027 L .142 -.016 L -.006 .224 L -.19 .209 L -.492 .06 L -1.198 .092 L -.777 .196 L -.364 0 L -1.179 -.355 L -.753 -.088 L -1.15 -.027 L -.814 -.014 L -.831 .081 L .098 -3.675 L +346.758 54.457 N .127 -.162 L .42 -.179 L .894 .015 L .674 -.098 L -.354 -.227 L -.405 -.34 L .317 -.342 L .277 0 L .956 .42 L .67 .048 L .3 -.163 L -.191 -.26 L -.625 -.373 L .366 -.245 L 1.037 .226 L .957 .08 L .746 .275 L .446 .551 L -.119 .405 L -.441 .292 L .922 .806 L .553 -.356 L .352 -.13 L .63 -.114 L .49 -.179 L .061 -.21 L -.169 -.778 L .542 -.245 L .501 .454 L .426 .307 L .489 .209 L .215 .016 L .185 -.13 L -.264 -.454 L .243 -.163 L .27 -.033 L .817 -.164 L .683 .438 L .536 .242 L .542 .063 L .05 -.178 L -.358 -.535 L 1.006 .145 L 1.439 .079 L .787 -.115 L .427 -.229 L -.021 -.716 L 1.167 .08 L .635 .471 L 1.118 .323 L .683 .015 L .273 .243 L -.252 .552 L .786 .29 L 1.674 .159 L .127 .145 L .143 .548 L -.07 .387 L -.152 .256 L -.152 .256 L -.443 .129 L -.815 .018 L -.195 .096 L -.04 .431 L -.515 .463 L -.497 .16 L -.568 -.031 L -.422 -.159 L -.817 .495 L -.539 .144 L -1.46 .463 L -.853 .113 L -.726 .001 L -.771 .097 L -.784 .587 L -.473 .127 L -1.078 .097 L -.709 -.03 L -1.316 -.171 L -.608 -.142 L -1.283 -.489 L -1.058 -.093 L -.443 .064 L -1.041 -.014 L -1.834 -.124 L -.297 -.206 L .434 -.191 L 1.127 -.352 L .701 -.59 L -.818 -.015 L -.51 -.126 L -.428 -.398 L -.253 -.095 L -.358 .081 L -1.564 .115 L -.557 .033 L -.37 -.223 L .141 -.192 L .388 -.129 L .669 -.097 L .794 -.017 L .729 -.114 L 1.049 -.098 L .376 -.194 L .178 -.322 L -.144 -.258 L -.358 -.177 L -.426 -.015 L -.478 -.145 L -1.005 -.047 L -.821 .099 L -.424 .162 L -.676 .082 L -1.041 -.272 L -.16 -.21 L +462.829 67.958 N .145 .053 L .16 .131 L -.043 .174 L -.175 .044 L -.189 0 L -.116 0 L -.088 .043 L -.058 .131 L -.175 .277 L -.219 .204 L -.319 .131 L -.204 .131 L -.088 .16 L .029 .16 L .131 .437 L .073 .189 L .029 .16 L -.175 .131 L 0 .175 L .175 .233 L .203 .087 L .088 .073 L 0 .073 L .015 .087 L .043 .146 L .175 .043 L .059 .059 L -.175 .073 L -.262 .043 L -.16 .058 L -.059 .102 L -.087 .116 L -.131 0 L 461.402 72 l -.015 .087 L -.116 .058 L .081 .106 L -.125 .025 L -.087 -.015 L -.306 -.043 L -.16 -.058 L -.175 -.073 L -.204 -.044 L -.131 .102 L -.204 -.029 L -.131 .044 L -.16 .087 L -.146 .014 L -.146 -.087 L -.116 -.029 L -.175 0 L -.204 -.117 L -.116 -.174 L -.203 -.117 L -.146 -.043 L -.072 -.117 L -.189 0 L -.247 -.043 L -.204 -.117 L -.029 0 L -.276 -.014 L -.102 -.102 L -.248 -.043 L -.116 -.102 L -.189 -.087 L 0 .073 L -.116 .087 L -.131 -.058 L -.015 -.073 L -.087 -.029 L -.103 0 L -.276 .117 L -.102 .029 L -.131 .015 L -.219 .015 L -.146 .043 L -.262 .029 L -.276 .087 L -.116 .102 L -.087 0 L .156 -.19 L -.003 -.351 L .183 -.238 L -.368 -.21 L -.605 .437 L -.334 -.251 L -.527 -.038 L .043 -.942 L -.396 .188 L -.336 -.415 L .158 -.202 L -.209 -.254 L .265 -.074 L -.092 -.252 L .344 -.042 L 1.026 -.084 L -.006 -.132 L .561 -.108 L .133 -.188 L .436 .101 L .074 -.113 L .317 .05 L .083 -.215 L 1.104 .193 L .446 -.294 L .091 .165 L .514 -.089 L 1.383 .029 L 1.152 .167 L .305 .12 L .592 -.045 L .971 .09 L .426 -.108 L .271 -.24 L -.006 -.009 L +461.353 72.251 N .37 -.004 L -.015 .116 L 0 .117 L .232 .073 L .204 .087 L .087 .073 L .204 .058 L -.015 .087 L -.029 .116 L -.015 .087 L -.102 .073 L -.087 .015 L -.103 .029 L .131 .087 L -.072 .131 L .029 .117 L -.073 .087 L -.102 .073 L -.044 .102 L .204 -.059 L .146 -.015 L .131 .073 L .087 .014 L .073 .044 L -.059 .087 L -.043 .073 L .116 .102 L .131 .058 L .029 .16 L .146 .102 L .16 .043 L -.059 .087 L .131 .117 L -.015 .189 L .088 .233 L -.044 .087 L -.015 .117 L -.061 .042 L -.241 .044 L -.24 .051 L -.12 .12 L -.223 .034 L -.137 .154 L -.137 .085 L -.069 .103 L -.068 .206 L -.188 .035 L -.239 -.035 L -.24 -.034 L -.325 -.034 L -.359 0 L -.172 .068 L -.103 .137 L -.223 .085 L -.154 0 L -.103 -.017 L -.086 .052 L -.377 -.035 L -.273 -.068 L -.154 -.171 L -.138 -.154 L -.325 -.137 L -.497 -.223 L -.342 -.24 L -.377 -.034 L -.583 -.035 L -.325 -.12 L -.291 -.188 L -.086 -.257 L -.188 .017 L -.171 .068 L -.36 .171 L -.394 .017 L -.24 0 L -.273 .085 L -.24 -.085 L -.309 -.103 L -.6 -.017 L -.291 .069 L -.359 -.069 L -.291 -.051 L -.154 .034 L -.274 .069 L -.103 -.052 L -.12 -.137 L -.154 0 L -.257 .068 L -.188 0 L -.754 -.017 L -.445 -.085 L -.754 .171 L -.599 .154 L -.429 .103 L -.257 .137 L -.052 .188 L -.526 .026 L -.065 -.059 L .073 -.837 L .035 -.302 L .127 -.167 L .672 -.379 L .034 -.717 L .267 -.162 L .267 -.273 L .217 -.203 L .296 -.026 L 1.056 -.199 L .166 -.046 L .162 -.066 L .29 0 L .049 .237 L .657 .388 L .422 .162 L .23 .473 L .091 .15 L .441 .196 L .785 .059 L .868 -.244 L .24 -.122 L .178 -.288 L -.052 -.394 L -.193 -.869 L .198 -.243 L .045 -.055 L .087 0 L .116 -.102 L .276 -.087 L .262 -.029 L .146 -.043 L .219 -.015 L .131 -.015 L .102 -.029 L .276 -.117 L .103 0 L .087 .029 L .015 .073 L .131 .058 L .116 -.087 L 0 -.073 L .189 .087 L .116 .102 L .248 .043 L .102 .102 L .276 .014 L .029 0 L .204 .117 L .247 .043 L .189 0 L .072 .117 L .146 .043 L .203 .117 L .116 .174 L .204 .117 L .175 0 L .116 .029 L .146 .087 L .146 -.014 L .16 -.087 L .131 -.044 L .204 .029 L .131 -.102 L .204 .044 L .175 .073 L .16 .058 L .306 .043 L .087 .015 L .125 -.025 L +451.02 79.165 N -.029 -.038 L -.034 -.137 L -.018 -.171 L .068 -.206 L .068 -.154 L .224 -.12 L -.052 -.12 L -.018 -.137 L -.171 -.069 L -.188 -.034 L -.103 -.103 L -.086 -.137 L -.223 .017 L -.257 0 L -.445 0 L -.223 .051 L -.086 -.103 L -.514 -.068 L -.257 -.069 L -.223 -.12 L -.24 0 L -.086 -.052 L -.051 -.154 L -.12 .034 L -.353 .096 L -.043 -.077 L .128 -.012 L .034 -.183 L -.439 -.646 L -.008 -.14 L -.042 -.727 L -.112 -.102 L .526 -.026 L .052 -.188 L .257 -.137 L .429 -.103 L .599 -.154 L .754 -.171 L .445 .085 L .754 .017 L .188 0 L .257 -.068 L .154 0 L .12 .137 L .103 .052 L .274 -.069 L .154 -.034 L .291 .051 L .359 .069 L .291 -.069 L .6 .017 L .309 .103 L .24 .085 L .273 -.085 L .24 0 L .394 -.017 L .36 -.171 L .171 -.068 L .188 -.017 L .086 .257 L .291 .188 L .325 .12 L .583 .035 L .377 .034 L .342 .24 L .497 .223 L .325 .137 L .138 .154 L .154 .171 L .273 .068 L .377 .035 L -.017 .171 L -.086 .154 L -.034 .12 L -.12 .137 L -.086 .137 L .343 .034 L .274 .052 L .085 .051 L -.119 .051 L -.086 0 L -.103 .154 L -.018 .154 L -.171 .017 L -.12 -.086 L -.12 .051 L -.239 -.034 L -.154 .034 L -.086 .154 L -.103 .154 L -.257 .068 L -.429 0 L -.137 .137 L -.12 .12 L -.034 .154 L -.086 .171 L .103 .171 L -.068 .137 L -.239 .154 L 0 .137 L -.068 .085 L -.069 .137 L .172 .034 L .205 0 L .138 .206 L -.086 .188 L -.274 .017 L -.223 -.068 L 0 -.154 L -.034 -.085 L -.086 -.069 L -.171 .051 L -.12 .086 L -.291 -.034 L -.068 .137 L -.24 .12 L -.154 0 L -.188 -.034 L -.273 .103 L .086 .171 L -.069 .12 L -.171 .034 L -.137 -.034 L -.206 .051 L -.377 .154 L -.291 0 L -.068 -.103 L -.12 -.051 L -.239 .051 L -.377 .017 L -.24 .034 L -.291 -.034 L -.154 .034 L -.093 -.035 L -.09 -.171 L -.016 -.029 L -.099 -.186 L -.284 -.487 L -.679 -.243 L -.04 -.014 L -.641 .021 L +452.867 80.273 N .093 .035 L .154 -.034 L .291 .034 L .24 -.034 L .377 -.017 L .239 -.051 L .12 .051 L .068 .103 L .291 0 L .377 -.154 L .206 -.051 L .137 .034 L .171 -.034 L .069 -.12 L -.086 -.171 L .273 -.103 L .188 .034 L .154 0 L .24 -.12 L .068 -.137 L .291 .034 L .12 -.086 L .171 -.051 L .086 .069 L .034 .085 L 0 .154 L .223 .068 L .274 -.017 L .086 -.188 L -.138 -.206 L -.205 0 L -.172 -.034 L .069 -.137 L .068 -.085 L 0 -.137 L .239 -.154 L .068 -.137 L -.103 -.171 L .086 -.171 L .034 -.154 L .12 -.12 L .137 -.137 L .429 0 L .257 -.068 L .103 -.154 L .086 -.154 L .154 -.034 L .239 .034 L .12 -.051 L .12 .086 L .171 -.017 L .018 -.154 L .103 -.154 L .086 0 L .119 -.051 L -.085 -.051 L -.274 -.052 L -.343 -.034 L .086 -.137 L .12 -.137 L .034 -.12 L .086 -.154 L .017 -.171 L .086 -.052 L .103 .017 L .154 0 L .223 -.085 L .103 -.137 L .172 -.068 L .359 0 L .325 .034 L .24 .034 L .239 .035 L .188 -.035 L .068 -.206 L .069 -.103 L .137 -.085 L .137 -.154 L .223 -.034 L .12 -.12 L .24 -.051 L .241 -.044 L .165 .147 L .229 .066 L .197 -.131 L .181 .016 L .312 .033 L .132 .148 L .082 .148 L .197 -.033 L .214 -.065 L .361 -.049 L .312 .049 L .296 .065 L .147 .017 L 0 .115 L -.164 .099 L -.017 .099 L .065 .148 L .164 .148 L .197 0 L .214 -.197 L .279 -.016 L .165 0 L .147 -.099 L .23 -.083 L .131 .049 L .099 .049 L .247 -.049 L .542 .115 L .132 .131 L .279 .099 L .099 .099 L .147 .099 L .165 .033 L .147 -.033 L .049 .115 L -.065 .115 L 0 .083 L -.033 .164 L -.131 .165 L .197 .247 L .147 .099 L .05 .164 L -.066 .131 L -.114 0 L 0 .083 L -.115 .082 L -.099 .049 L -.033 .165 L -.049 .147 L .345 .049 L .132 .181 L .082 .115 L .181 -.049 L .132 .033 L -.099 .115 L -.066 .131 L .017 .099 L .214 .017 L .164 .263 L .115 .23 L .443 .213 L .23 .066 L .279 .082 L .164 .099 L .066 .148 L -.099 .197 L -.066 .181 L .182 .066 L .361 -.066 L .378 .066 L .361 .099 L .263 .066 L -.032 .065 L -.066 .049 L -.082 .017 L .099 .181 L .296 .148 L .279 .066 L .033 .131 L -.065 .164 L -.296 0 L -.148 .083 L -.049 .065 L -.444 .247 L -.525 .099 L -.51 -.016 L -.197 -.132 L -.328 -.049 L -.362 .017 L -.131 .165 L -.099 .131 L .017 .164 L .279 .263 L .296 .164 L 0 .165 L -.132 .066 L .099 .148 L .147 .131 L -.082 .099 L .033 .164 L .033 .23 L -.033 .099 L .164 .082 L .082 .115 L .165 .066 L .002 .142 L -.519 -.005 L -.522 .056 L -.112 .131 L -.205 -.056 L -.187 -.037 L -.336 .075 L -.057 .13 L -.111 .112 L -.317 .187 L -.188 .261 L -.261 .224 L -.057 .206 L .243 .205 L .056 .149 L -.131 .206 L -.261 -.019 L -.149 -.056 L -.149 -.206 L -.112 -.056 L -.187 -.075 L -.224 -.037 L -.225 .037 L -.242 .075 L -.299 .019 L -.149 -.131 L -.224 .075 L -.188 .093 L -.316 .056 L -.188 -.056 L -.037 -.205 L -.112 -.131 L -.168 -.131 L -.13 .038 L -.131 .075 L -.168 0 L -.299 .149 L -.131 .149 L -.168 0 L -.094 -.187 L -.13 -.075 L -.206 0 L -.224 .112 L -.131 -.187 L -.224 -.093 L -.131 .112 L -.354 .056 L -.262 -.112 L -.112 0 L -.019 .205 L -.168 .093 L -.093 -.056 L .056 -.224 L -.243 -.038 L -.187 -.056 L -.541 .112 L 0 -.149 L -.187 0 L .019 -.224 L -.28 -.037 L -.242 .075 L -.523 -.112 L -.578 -.056 L -.075 -.056 L -.522 0 L -.205 -.168 L -.262 .019 L -.522 -.093 L -.467 .075 L -.485 0 L -.354 -.056 L -.355 .056 L -.354 .056 L -.485 -.038 L -.485 .019 L -.205 .187 L -.037 .168 L -.374 .168 L -.373 .206 L -.112 -.112 L -.261 0 L -.374 -.019 L -.037 .131 L 0 .045 L -.126 -.137 L .315 -.752 L -.013 -.25 L -.218 -.146 L -.149 -.176 L -.421 -.146 L -.289 -.012 L .128 -.292 L .291 -.328 L .571 -.244 L .44 -.03 L .263 -.208 L .023 -.236 L -.172 -.502 L -.615 -1.5 L -.16 -.302 L +400.125 81.146 N .633 .305 L .208 .207 L .208 .37 L -.038 .193 L -.545 .563 L .714 .176 L .396 -.311 L .527 -.119 L .602 .028 L .807 .176 L .467 .354 L .235 .752 L -.077 .221 L -.322 .414 L -1.068 .473 L -.767 .561 L -.96 .237 L 1.223 .167 L .501 .043 L .354 -.104 L .39 .117 L -.066 .516 L -.997 .308 L .005 .199 L -.479 -.084 L -1.068 .443 L -.879 -.142 L -.293 -.048 L -1.119 .211 L -.587 -.211 L -.598 .112 L -1.584 .141 L .137 .295 L -.907 -.168 L -.264 .168 L -.911 -.337 L -.334 .143 L -.913 .089 L -.093 .569 L -.337 .316 L -.37 .042 L -.272 -.252 L -.53 -.172 L -.135 .151 L -.527 -.077 L -.948 .324 L -.701 .552 L -.326 -.231 L -.775 -.147 L 1.2 -.472 L .492 -.476 L .447 -.097 L .468 -.388 L .118 -.485 L .242 .063 L .367 -.211 L -.008 -.274 L 1.013 -.105 L .76 .119 L .927 .007 L .073 -.338 L .308 -.142 L .321 -.556 L -.939 .394 L -.725 .016 L -1.467 -.482 L -1.866 -.055 L -.399 -.191 L -.156 -.162 L .417 -.325 L .983 -.194 L .721 -.237 L .38 -.384 L .066 -.827 L -.119 -.192 L -.713 .046 L -.34 -.044 L .288 -.355 L .387 -.223 L .802 -.253 L 1.394 -.062 L .922 -.076 L -.316 -.548 L .172 -.683 L .253 -.461 L -.045 -.312 L -.834 .061 L -.484 -.296 L -.2 -.312 L .309 -.507 L .617 -.433 L -.347 -.104 L -.596 -.088 L -.735 .3 L -.476 .061 L -.753 -.222 L -.088 .194 L -.222 .194 L -.672 -.103 L -.464 -.133 L .1 -.343 L .348 -.36 L .604 -.706 L -.293 -.134 L -.305 -.39 L .028 -.24 L .304 -.106 L .3 -.196 L -.194 -.496 L -.306 .076 L -.636 .453 L -.442 .031 L -.526 .287 L -.14 -.421 L .302 -.527 L .438 -.559 L .065 -.257 L -.417 -.195 L -.196 -.045 L -.218 .302 L -.394 .257 L -.493 -.165 L .299 -.575 L .54 -.455 L .09 -.136 L -.225 -.575 L .366 -.092 L .225 -.197 L -.672 -.515 L .432 -.351 L .752 .151 L .387 -.092 L -.645 -.759 L .975 -.169 L -.457 -.502 L .416 -.382 L .924 .365 L .824 -.093 L .686 -.139 L .867 -.047 L .612 .014 L .303 .259 L -.307 .29 L -1.726 .704 L -.46 .274 L -.218 .441 L .222 .182 L .784 .029 L .877 -.078 L .685 -.001 L .53 .075 L 1.563 -.064 L .458 .378 L -.363 .425 L -.212 .323 L .098 .112 L -.565 .66 L -.226 .111 L -.339 .437 L -.696 .261 L -.382 .038 L .451 .186 L .508 .167 L -.116 .015 L -.272 .19 L -.61 .052 L -.275 .196 L -1.337 -.025 L .404 .223 L .302 0 L .492 .093 L .432 -.006 L .519 -.223 L .413 -.025 L .449 .161 L .656 .164 L .673 .566 L .496 .228 L .118 .165 L -.067 .238 L .312 .78 L .371 .536 L .438 .189 L .714 .107 L .59 .549 L .688 .593 L .135 .52 L -.188 .49 L .257 .124 L h 387.915 77.13 m -.128 -.325 L .149 -.335 L .38 -.089 L .079 .501 L -.307 .251 L -.173 -.003 L h 386.786 80.184 m -.178 -.272 L -.967 .072 L .123 -.256 L -.364 -.15 L -.26 -.257 L -.335 -.107 L -.253 .364 L -.751 .257 L -.778 -.192 L -.401 -.278 L -.101 -.278 L .86 -.278 L -.483 -.257 L .817 -.107 L .385 -.484 L -.029 -.235 L .449 -.09 L .508 -.15 L .781 -.077 L .424 .044 L .389 .104 L .362 -.046 L .218 .149 L .519 .791 L .047 .179 L -.081 .298 L .308 .446 L -.155 .328 L -.402 .328 L -.354 .12 L -.299 .038 L +578.943 106.217 N -.41 -.375 L -.466 -.098 L -.663 0 L -.196 -.27 L -.27 -.147 L -.147 -.344 L -.564 .049 L -.981 -.246 L -.662 .074 L -1.35 -.024 L -.662 -.098 L -.712 -.221 L -.785 .147 L -.761 0 L -.858 .024 L -.441 .27 L -.54 -.098 L -.908 -.196 L -.735 -.246 L -.761 -.27 L -.589 -.074 L -.688 .123 L -.466 .368 L -.245 .736 L .024 .442 L -.344 -.123 L -.81 -.123 L -.688 -.196 L -.883 -.245 L -.883 -.147 L -.663 .098 L -.736 .123 L -.318 .368 L -.393 .442 L .044 .273 L -.322 .031 L -.377 .377 L -.283 -.126 L -.22 .063 L -.346 .283 L -.534 .471 L -.755 .189 L -.943 .377 L -.282 .188 L -.221 .472 L -.439 .188 L -.504 .44 L .157 .409 L -.125 .188 L -.66 0 L -.44 -.346 L .062 -.283 L -.062 -.283 L -.44 -.314 L -.346 0 L -1.006 .094 L -.691 .032 L -.503 -.063 L -.346 -1.069 L -.221 -.817 L -1.006 0 L -.031 -.754 L .188 -.409 L .031 -1.038 L -.66 .314 L -.66 -1.006 L -.597 -.22 L -.724 -.723 L -1.1 .409 L -2.767 -.188 L -2.578 .346 L -2.012 -1.666 L -5.722 -2.986 L -5.658 1.289 L -.056 8.174 L -.158 -.014 L -.341 .106 L -.489 .043 L -.447 -.255 L -.638 -.703 L -.256 -.511 L -.617 -.383 L -.681 -.383 L -.512 -.234 L -.979 .085 L -1.277 .298 L -.937 .532 L -.529 .453 L .092 -.399 L -.06 -.18 L -.12 -.12 L .14 -.26 L .2 -.2 L .14 -.32 L .04 -.3 L .18 -.2 L -.159 -.24 L -.4 -.16 L -.459 .06 L -.18 -.16 L -.3 .06 L -.2 .04 L -.199 -.18 L -.221 -.32 L -.319 -.28 L -.34 0 L -.359 .02 L 0 -.2 L .08 -.28 L -.2 -.379 L -.239 -.12 L -.2 -.24 L -.399 -.799 L -.08 -.28 L -.56 -.12 L -.699 -.08 L -.14 -.16 L .02 -.439 L .16 -.12 L .3 -.06 L .399 .02 L .34 .02 L .479 .14 L .539 .18 L .18 -.08 L .36 -.08 L -.2 -.16 L -.26 -.12 L -.399 -.2 L -.2 -.24 L .26 -.36 L .28 -.04 L .08 -.26 L .18 -.299 L .12 -.14 L .26 .04 L .319 -.08 L .16 -.1 L .339 .12 L .24 0 L 1.119 -.04 L .999 .14 L .499 .02 L -.159 -.08 L -.34 -.2 L -.479 -.12 L -.021 -.3 L .2 -.2 L .279 -.22 L .221 -.28 L .119 -.52 L .12 -.28 L -.16 -.24 L -.14 -.16 L .1 -.2 L .26 -.2 L -.119 -.12 L -.101 -.3 L -.359 -.12 L -.359 -.04 L -.68 -.1 L -.2 .16 L -.199 .08 L -.52 .08 L -.46 -.12 L -.319 -.26 L -.26 -.06 L -.68 -.12 L -.56 .06 L -.659 .319 L -.42 .02 L -.799 .5 L -.72 .28 L -.499 .06 L -.42 -.02 L -.279 .24 L -.213 .18 L -.616 -.19 L -.857 -.377 L -.068 -.308 L .343 -.103 L .309 .103 L .445 .103 L .138 -.103 L -.96 -1.131 L -.343 -.514 L -.479 -.206 L -.515 -.445 L -.514 -.034 L -.343 .034 L -.583 -.206 L -.103 .343 L -.514 -.514 L .068 -.309 L -.138 -.377 L -1.37 -.343 L .65 -1.165 L .446 -.274 L .239 -.206 L -.239 -.274 L -.343 -.171 L .205 -1.303 L .823 -.137 L .343 -.549 L .103 -.308 L .411 -.069 L .514 .24 L .48 .548 L .514 .411 L .651 0 L .411 -.24 L .068 -.446 L -.171 -.411 L -.068 -.445 L .479 -.206 L .891 -.411 L .172 -.24 L .309 -.309 L .514 -.171 L .549 -.068 L .788 -.377 L .548 -.343 L .515 -.309 L .651 .069 L .479 0 L .309 .274 L .651 -.137 L .273 -.137 L .617 -.24 L .411 .069 L .411 .514 L .788 .035 L .617 -.069 L .96 .171 L 0 .343 L .582 .206 L .789 .343 L .411 .274 L .068 .583 L .274 .137 L .239 -.274 L -.205 -.48 L -.034 -.24 L .72 .068 L .582 .548 L .686 .137 L .411 .24 L .686 -.171 L .274 -.274 L .377 -.343 L .514 -.377 L .823 .068 L .65 .035 L .651 .411 L .617 -.068 L .137 -.412 L 1.062 -.103 L .754 .103 L .274 .548 L .926 .309 L .754 .137 L .411 .171 L .651 -.343 L .171 -.309 L .24 0 L .343 .343 L .959 .034 L 1.577 -.411 L .137 -.309 L .138 -.686 L -.24 -.24 L -1.165 -.171 L -.274 -.308 L -.651 -.069 L -.377 -.137 L .068 -.171 L -.377 -.137 L -.239 0 L -.164 -.274 L .467 -.067 L .735 -.368 L .588 -.147 L .331 -.294 L -.441 -.478 L -.146 -.257 L .662 -.515 L .698 -.184 L 1.103 .147 L .515 -.073 L .11 -.257 L -.956 -.294 L -1.065 -.11 L 0 -.331 L .294 -.074 L -.294 -.221 L -.074 -.441 L .185 -.515 L .33 -.074 L 1.066 .147 L .515 0 L .772 0 L .368 -.184 L 1.396 -.405 L 1.029 -.037 L .735 -.11 L 1.545 -.11 L .588 -.073 L .331 .073 L .221 -.331 L .625 -.331 L 1.177 -.037 L 2.021 -.405 L 1.876 -.073 L .625 -.074 L .367 -.368 L 77.39 V .515 -.037 L .589 -.184 L .11 -.221 L .735 -.037 L .919 .147 L .515 .11 L .772 .257 L .625 -.11 L .882 -.037 L .368 .404 L -.037 .331 L .147 .221 L .515 .22 L -.11 .331 L -.147 .257 L .073 .331 L -.33 .037 L .184 .257 L .478 .074 L .295 -.147 L .44 .11 L .368 -.147 L .367 .074 L .331 -.221 L .294 .11 L .295 .368 L .367 .221 L .147 -.147 L .184 -.147 L .478 .037 L .405 .294 L .478 .11 L .441 -.221 L .367 0 L -.146 .294 L -.441 .184 L -.331 .441 L .331 .184 L .441 -.11 L .771 -.073 L .441 .037 L .552 .184 L .294 -.294 L .772 -.441 L 1.103 -.257 L .956 -.515 L .772 -.221 L .515 -.22 L .809 -.074 L 0 .441 L -.515 .11 L -.11 .368 L 1.104 .588 L .809 .294 L 1.287 .772 L 1.066 1.029 L 1.69 2.133 L .846 .882 L 1.104 1.434 L .515 -.257 L .331 -.257 L .367 -.515 L .92 0 L .367 .331 L 0 .368 L .478 0 L .258 .257 L .184 .184 L .589 0 L .992 0 L .993 -.221 L .771 -.221 L .993 -.037 L .698 .441 L .772 .588 L .331 .625 L .956 .147 L .588 .552 L .662 .699 L .882 .073 L .993 .074 L .478 -.368 L .625 -.184 L -.073 .331 L .441 .331 L .294 .478 L .589 0 L .064 .145 L -.551 .034 L -.542 .148 L -.279 .262 L -.011 .275 L -.035 .478 L -.306 .219 L -.289 .06 L -1.199 .093 L -.428 .277 L -.34 .581 L .097 .75 L .213 .707 L -.157 .39 L -.444 .392 L -.417 .103 L -.718 .062 L -1.402 -.079 L -.594 -.141 L -.721 -.141 L -1.096 -.254 L -.427 .507 L -.516 1.141 L 584.2 97.43 l -.286 .605 L -.137 .418 L .622 .514 L .126 .286 L -.156 .245 L -.231 .145 L -.394 .074 L -1.133 -.238 L -.5 -.184 L -.35 .06 L -1.082 .207 L -1.799 .254 L -.393 .188 L -.215 .302 L -.068 .215 L .232 .185 L .366 -.06 L .483 .141 L .03 1.357 L .345 .627 L .29 .441 L .119 .47 L -.222 .33 L -.705 .546 L -.32 .401 L -.02 .399 L .139 .86 L +386.786 80.184 N -.304 .038 L -.223 .09 L .241 .252 L .361 .771 L .287 1.213 L -.061 .281 L -.359 .341 L -.242 .414 L -.145 .473 L -.185 .044 L -.284 -.058 L -.616 .031 L -.15 .212 L -.913 .042 L -.84 .132 L -.247 .144 L -.661 .286 L -.903 .498 L -.628 .035 L -.879 .283 L -1.28 .084 L .053 -.378 L -.089 -.441 L -.848 .1 L -.171 -.487 L .734 -.254 L -1.186 -.021 L .062 -.233 L 1.286 .027 L .198 -.104 L .039 -.222 L .107 -.31 L .515 -.134 L .692 -.031 L .13 -.281 L -1.07 .099 L .387 -.437 L -.187 -.159 L .481 -.468 L .694 -.011 L .163 -.089 L -.174 -.311 L -.348 .177 L -.309 -.131 L -.319 .03 L -.391 -.177 L -.414 .001 L -.182 .106 L 378 81.478 l .309 -.306 L -.29 -.142 L .759 -.126 L -.139 -.301 L .391 -.235 L -.481 -.214 L -.59 .128 L 378 79.792 l .38 -.268 L .215 -.16 L .928 .187 L .336 -.075 L .527 .038 L 1.102 .123 L -.214 -.358 L 382.132 79 l .198 -.321 L -1.373 0 L .154 -.15 L .569 -.107 L .061 -.29 L .291 -.479 L .505 -.181 L .804 -.169 L .22 .302 L .354 .149 L .156 -.031 L .029 .235 L -.385 .484 L -.817 .107 L .483 .257 L -.86 .278 L .101 .278 L .401 .278 L .778 .192 L .751 -.257 L .253 -.364 L .335 .107 L .26 .257 L .364 .15 L -.123 .256 L .967 -.072 L .178 .272 L +452.998 85.535 N 85.49 V .037 -.131 L .374 .019 L .261 0 L .112 .112 L .373 -.206 L .374 -.168 L .037 -.168 L .205 -.187 L .485 -.019 L .485 .038 L .354 -.056 L .355 -.056 L .354 .056 L .485 0 L .467 -.075 L .522 .093 L .262 -.019 L .205 .168 L .522 0 L .075 .056 L .578 .056 L .523 .112 L .242 -.075 L .28 .037 L -.019 .224 L .187 0 L 0 .149 L .541 -.112 L .187 .056 L .243 .038 L -.056 .224 L .093 .056 L .168 -.093 L .019 -.205 L .112 0 L .262 .112 L .354 -.056 L .131 -.112 L .224 .093 L .131 .187 L .224 -.112 L .206 0 L .13 .075 L .094 .187 L .168 0 L .131 -.149 L .299 -.149 L .168 0 L .131 -.075 L .13 -.038 L .168 .131 L .112 .131 L .037 .205 L .188 .056 L .316 -.056 L .188 -.093 L .224 -.075 L .149 .131 L .299 -.019 L .242 -.075 L .225 -.037 L .224 .037 L .187 .075 L .112 .056 L .149 .206 L .149 .056 L .261 .019 L .131 -.206 L -.056 -.149 L -.243 -.205 L .057 -.206 L .261 -.224 L .188 -.261 L .317 -.187 L .111 -.112 L .057 -.13 L .336 -.075 L .187 .037 L .205 .056 L .112 -.131 L .522 -.056 L .519 .005 L .357 .089 L .469 .022 L .313 -.156 L .179 -.291 L .134 -.268 L .536 .246 L .536 -.022 L .67 -.223 L .692 .112 L .514 -.134 L .201 .268 L .312 .134 L .246 .335 L .134 .201 L .246 .156 L .312 .156 L 0 .268 L -.312 -.022 L -.312 .134 L .134 .291 L .111 .357 L .269 .29 L .647 0 L .156 .112 L .514 -.067 L .38 .022 L 0 .312 L .402 0 L 0 .357 L .224 .268 L .089 .246 L -.089 .179 L .089 .224 L .179 .089 L .291 .29 L .268 -.179 L .47 -.067 L .268 .067 L .469 .291 L .201 -.067 L .179 .022 L .179 .156 L .425 -.112 L .312 -.112 L .269 0 L .536 -.134 L .357 -.067 L .111 .156 L .268 .179 L 0 .134 L .201 .179 L .022 .134 L .402 .044 L .179 .179 L .224 .112 L .29 -.134 L .045 -.157 L .224 -.067 L .29 .268 L .425 .067 L .469 .112 L .268 .112 L .357 -.067 L .201 .179 L .291 .089 L .469 .022 L .111 .224 L .357 .156 L .269 0 L .134 -.044 L .201 -.089 L .156 .089 L -.089 .111 L -.022 .179 L .111 .089 L .09 .179 L -.045 .224 L -.201 .089 L -.156 .067 L -.357 .201 L -.312 .044 L .223 .246 L .269 .089 L .29 .044 L -.134 .156 L -.312 0 L -.246 0 L -.045 .179 L -.044 .224 L .156 .067 L .179 .067 L .044 .134 L .045 .179 L .09 .201 L .066 .067 L -.156 .491 L -.156 .291 L 0 .156 L -.335 .134 L -.805 -.157 L -.736 .045 L -.269 0 L -.022 .179 L -.223 .179 L -.38 .134 L -.357 .022 L -.224 .089 L -.09 .514 L 0 .224 L -.021 .112 L -.012 .126 L -.779 .104 L -.971 .06 L -.511 .405 L -.729 .189 L -1.135 .075 L -1.119 .248 L -.502 .318 L -.463 .059 L -.453 -.316 L -.369 .621 L -.31 .188 L -.477 .044 L -.438 -.057 L -.959 .031 L -.5 .16 L .641 .287 L 1.957 1.004 L .053 .172 L -.093 .188 L .163 .244 L .562 .042 L .511 -.13 L .675 -.146 L 1.052 .013 L .439 .114 L -.235 .259 L -.106 .245 L -.228 .144 L -.578 .116 L -.31 .029 L -.591 -.157 L -.473 .044 L -.71 .489 L -1.007 .045 L -.538 .188 L -.527 .488 L -.269 .101 L -.786 -.07 L -.588 -.171 L .364 -.746 L -.096 -.416 L -.264 -.287 L -.854 -.286 L -.193 -.014 L -.629 .016 L -.151 .043 L -.16 -.187 L .887 -.505 L .644 -.261 L .772 -.188 L .221 -.116 L -.246 -.46 L -.435 -.071 L -.799 .044 L -1.015 .045 L -.698 -.1 L -.195 -.101 L -.418 -.432 L .584 -.405 L -.528 -.605 L -.378 .361 L -.541 .001 L -1.001 .146 L -.565 .131 L -.694 .722 L -1.003 .867 L -.754 .203 L -.223 .044 L -.287 .504 L .079 .158 L .178 .093 L -.706 -.131 L -.665 .261 L -.457 0 L -.033 .189 L -.609 -.047 L -.398 -.166 L -.119 -.249 L -.15 .02 L .055 -.077 L .102 -.025 L .126 .013 L .113 .013 L .189 0 L .088 -.114 L 0 -.088 L -.063 -.113 L .025 -.113 L .126 -.063 L .051 -.063 L .075 -.013 L .089 -.025 L .088 -.063 L .089 -.088 L .024 -.126 L -.013 -.114 L .14 -.013 L .29 -.063 L .075 -.076 L -.025 -.088 L -.062 -.088 L .126 -.114 L .037 -.063 L -.012 -.088 L -.114 -.113 L .051 -.101 L -.088 -.151 L -.063 -.101 L .202 -.151 L .239 -.025 L .126 -.088 L .113 .025 L .013 .088 L -.013 .214 L .063 .013 L .113 0 L 96.92 V -.013 -.063 L .101 .038 L .063 .051 L .025 -.076 L .075 -.038 L .139 -.012 L 0 .075 L .089 .063 L .075 0 L .126 .164 L .076 -.076 L .075 -.076 L .013 -.05 L .101 -.025 L .177 0 L -.037 .189 L .176 .025 L .038 -.038 L .038 -.038 L .139 .013 L .227 0 L .038 -.025 L .075 -.076 L -.126 -.013 L -.164 -.126 L -.101 -.051 L -.075 -.05 L .013 -.038 L .101 -.063 L -.025 -.113 L .038 -.101 L -.013 -.126 L -.051 -.139 L -.101 -.063 L -.177 -.076 L -.075 0 L -.151 -.126 L -.151 -.063 L -.151 -.038 L .051 -.151 L .037 -.088 L -.037 -.051 L -.127 .038 L -.062 -.114 L .113 -.038 L -.013 -.189 L .089 -.075 L -.025 -.101 L -.038 -.088 L -.113 0 L -.102 .05 L -.088 .051 L -.113 -.088 L -.089 -.101 L -.188 -.101 L -.139 -.025 L -.102 -.139 L -.05 -.139 L .177 -.139 L 0 -.189 L .024 -.114 L .051 -.05 L -.126 -.063 L .164 -.151 L -.113 -.025 L -.076 -.063 L -.062 -.126 L -.14 -.013 L -.062 .101 L -.126 -.025 L -.215 -.025 L -.126 -.189 L -.05 -.189 L -.417 -.075 L -.277 .012 L -.062 .051 L -.076 .101 L -.062 -.05 L 0 -.076 L -.089 -.025 L -.101 .038 L .038 -.05 L .088 -.101 L -.025 -.063 L -.113 0 L -.177 .038 L -.126 -.025 L -.101 .013 L -.076 -.076 L -.05 -.063 L -.101 -.063 L -.151 -.013 L -.139 -.05 L -.14 -.126 L -.214 -.088 L -.038 -.013 L -.126 .025 L -.05 .025 L -.114 -.051 L -.088 -.025 L -.139 .025 L -.177 .051 L -.177 -.025 L -.062 .038 L -.126 .114 L -.202 0 L -.265 -.038 L -.126 .051 L -.315 -.114 L -.088 .101 L .012 .113 L -.126 0 L -.075 -.063 L -.126 .114 L -.06 .052 L -.634 .08 L -.151 .311 L -.278 .178 L -1.992 .191 L -.186 .215 L -.243 .119 L -.339 .06 L -.188 -.227 L -.327 .004 L -.025 -.231 L -.363 .045 L -1.115 -.066 L -.958 -.193 L -.241 .107 L -.787 -.121 L -.136 .085 L -.678 -.387 L -.554 -.2 L -.668 -.301 L -.166 .015 L 1.047 -1.471 L .653 .018 L -.349 -.383 L -.044 -.552 L .082 -.306 L 1.509 -1.218 L .599 -.398 L .286 -.181 L .429 -.013 L .255 -.24 L .009 -.314 L -.328 -.302 L .085 -.133 L .298 -.048 L -.316 -.193 L -.816 -.835 L .074 -.242 L -.161 -.175 L +660.044 89.132 N -.295 .31 L -.687 1.207 L -1.224 1.959 L -.381 .58 L .269 .836 L .051 .029 L .342 -.045 L .929 -.395 L .754 -.062 L .576 -.018 L .317 .085 L .431 .416 L .292 .07 L 1.191 -.786 L .438 -.002 L .928 .212 L .538 .199 L .797 .5 L .879 .99 L .599 .501 L .048 .273 L -.107 .217 L -.414 .218 L -.464 -.127 L -1.074 -.008 L -.432 -.099 L -.854 .033 L -.937 .221 L -.539 .146 L -.831 .278 L -.353 .189 L -.483 -.127 L -.464 .045 L -.47 .204 L -.363 .333 L -.312 .82 L -.241 .216 L -.347 .188 L -.638 .248 L -.896 .134 L -.624 -.054 L -.438 -.012 L -.224 -.013 L -1.192 .91 L -.742 .433 L -.744 .047 L -.982 .005 L -.592 -.125 L -.668 -.382 L -.718 -.154 L -.316 .073 L -.457 .231 L -.539 .589 L -.214 .401 L .003 .343 L .389 .569 L .599 .411 L .188 .228 L -.123 .271 L -.326 .259 L -1.265 .292 L -.67 .389 L -1.111 1.046 L -.265 .172 L -1.941 .737 L -.651 .061 L -.987 -.08 L -1.514 .065 L -1.339 .007 L -1.204 .349 L -.816 .289 L -.736 .274 L -.303 .101 L -1.44 .534 L -.686 .289 L -.481 .017 L -.433 -.197 L -.253 -.297 L -.61 -.067 L -.663 .061 L -.929 -.123 L -1.599 -.433 L -1.006 -.365 L -.815 -.551 L -.521 -.168 L -1.69 -.119 L -1.164 -.022 L -.937 -.023 L -2.861 .059 L -1.165 -.022 L -.802 -.109 L -1.241 -.207 L -1.979 -.018 L -.444 -.254 L -.467 -.439 L -1.571 -2.161 L -.105 -.542 L -.744 -.096 L -.839 -.31 L -1.645 -.806 L -.632 -.268 L -.998 -.224 L -.668 -.083 L -.995 -.038 L -1.505 -.021 L -1.062 -.181 L -.724 -.312 L -.233 -.229 L -.105 -.43 L .035 -.129 L .369 -.347 L .214 -.389 L .237 -.75 L .215 -.447 L -.401 -.66 L -1.07 -1.451 L -.568 -.618 L -.354 -.143 L -.633 -.144 L -.731 -.167 L -.614 -.069 L -.834 -.415 L -1.301 -.745 L -.371 -.433 L -.24 -.563 L -.131 -.405 L -.062 -.145 L .154 -.044 L .799 -.425 L .599 -.207 L 1.387 -.08 L .603 -.148 L .727 -.381 L .017 -.012 L .971 -.692 L .787 -.398 L 1.143 -.341 L 1.512 -.476 L .84 -.18 L .953 .097 L .932 .156 L 1.842 .122 L .831 .083 L .694 .755 L .393 .406 L .699 .113 L 1.458 -.008 L .719 .083 L .85 -.004 L .875 .068 L .312 .114 L .576 .186 L .562 -.018 L .755 -.28 L .31 -.162 L .744 -.572 L .163 -.526 L -.116 -.204 L -.396 -.304 L -.409 -.86 L .098 -.293 L .905 -.839 L 1.269 -.96 L .84 .201 L 1.028 .098 L 1.036 .185 L 1.748 .328 L .702 .231 L .989 .317 L .767 .143 L .145 .204 L .004 .541 L .182 .481 L .408 .451 L .421 .333 L 1.643 .531 L .673 .113 L 2.48 -.538 L .796 -.077 L 1.172 .037 L 1.423 .022 L .769 .229 L 1.333 .75 L .623 .331 L 1.132 .313 L .812 .373 L 1.318 .254 L .905 .241 L .984 .082 L .739 .039 L 1.602 -.11 L 1.018 -.063 L .532 -.075 L .867 -.106 L 1.147 -.136 L .526 -.163 L .604 -.264 L .447 -.394 L .755 -.498 L 1.165 -.487 L .333 -.002 L .609 -.047 L .74 .156 L .751 .506 L .34 .129 L .86 .169 L 1.228 -.297 L .622 -.018 L .431 .168 L +406.183 86.551 N 1.051 -.494 L .485 -.089 L .574 .087 L .465 -.016 L .209 -.147 L .477 .098 L .407 .042 L .52 -.034 L -.025 -.157 L .307 .012 L .307 0 L .267 -.182 L .313 .242 L .173 -.121 L .228 .061 L .292 .375 L .535 -.109 L .754 .375 L -.11 .423 L -.172 .097 L .001 .338 L .672 -.024 L .344 .177 L .282 .365 L .038 .468 L -.422 .376 L -.225 -.072 L -.142 .08 L -.245 .147 L -.213 .322 L .017 .327 L .31 .204 L -.136 .348 L -.079 -.114 L -.694 .174 L -.127 -.228 L -.371 -.204 L -.341 -.192 L -.529 -.048 L .039 -.228 L -.146 -.18 L .119 -.373 L -.245 .072 L -.193 .313 L -.446 .035 L -.406 .075 L -.285 -.122 L .072 -.198 L -.091 -.175 L .159 -.241 L -.375 -.168 L -.576 -.048 L -.259 .012 L -.159 -.301 L -.518 .012 L -.194 -.133 L -.202 -.458 L -.153 -.17 L -.41 .208 L -.141 .071 L -.266 -.127 L -.311 -.335 L -.208 -.447 L +438.22 91.952 N .039 -.044 L .065 -.105 L .014 -.131 L .092 -.066 L .146 -.119 L .026 -.04 L .171 -.053 L .093 -.026 L .092 .053 L .132 .053 L .158 0 L .065 -.026 L .093 0 L .065 .026 L .065 .026 L .093 -.026 L .145 -.04 L .132 0 L .118 -.053 L .079 -.053 L .066 -.026 L .105 -.026 L .039 0 L .053 -.079 L .04 -.092 L .079 -.079 L .092 .026 L .105 -.04 L .145 -.066 L .053 -.105 L .053 -.079 L .026 -.132 L .026 -.092 L .053 -.092 L .118 -.013 L .105 -.013 L .132 -.079 L .119 -.053 L .118 -.092 L .053 -.079 L .132 -.066 L .065 -.04 L 442 89.998 l .145 .013 L .105 .026 L .066 -.04 L .065 -.066 L .071 .012 L .285 .041 L .03 .228 L .43 -.048 L .183 -.24 L .193 .016 L .062 -.112 L .261 -.024 L .194 .24 L .073 .169 L .331 -.025 L .066 .18 L -.026 .083 L .003 .204 L .389 -.083 L .18 .12 L .149 -.135 L .104 -.177 L .558 -.204 L .168 .056 L .483 -.046 L .46 .254 L .373 -.18 L .073 -.137 L .508 .041 L .561 -.076 L .129 .13 L .703 .186 L .104 .216 L .424 .101 L .831 .33 L -1.047 1.471 L -.629 .076 L -.437 -.143 L -.534 -.359 L -1.062 .035 L -.717 .047 L -1.024 .759 L 444.857 93 l -.59 -.072 L -.499 .061 L -.761 .134 L -.255 .001 L -.334 .568 L -1.651 -.036 L -.414 -.027 L -.617 -.17 L -.399 -.172 L -.245 .146 L -.761 -.547 L -.155 -.26 L .097 -.581 L -.053 -.093 L +442.391 98.111 N -.589 .203 L -.433 .031 L -.668 .047 L -.58 -.098 L -1.116 -.671 L -1.412 -.612 L -.215 -.197 L -.364 -.333 L -.304 -.59 L .346 -.299 L .154 -.294 L -.204 -.188 L .04 -.375 L .409 -.062 L .157 -.206 L -.136 -.196 L -.452 -.063 L .223 -.197 L .325 0 L .164 .134 L .701 -.054 L .019 -.367 L .636 -.291 L .245 -.146 L .399 .172 L .617 .17 L .414 .027 L 1.651 .036 L .334 -.568 L .255 -.001 L .761 -.134 L .499 -.061 L .59 .072 L .427 -.063 L 1.024 -.759 L .717 -.047 L 1.062 -.035 L .534 .359 L .437 .143 L .629 -.076 L .166 -.015 L .668 .301 L .554 .2 L .678 .387 L -.45 .338 L -1.125 .267 L -.581 .408 L -.968 1.451 L -.63 .84 L -.753 .567 L -.361 .16 L -.724 .047 L -.264 .103 L -.176 -.002 L -.907 -.067 L -.889 .077 L -1.535 .529 L +459.717 92.836 N .06 -.052 L .126 -.114 L .075 .063 L .126 0 L -.012 -.113 L .088 -.101 L .315 .114 L .126 -.051 L .265 .038 L .202 0 L .126 -.114 L .062 -.038 L .177 .025 L .177 -.051 L .139 -.025 L .088 .025 L .114 .051 L .05 -.025 L .126 -.025 L .038 .013 L .214 .088 L .14 .126 L .139 .05 L .151 .013 L .101 .063 L .05 .063 L .076 .076 L .101 -.013 L .126 .025 L .177 -.038 L .113 0 L .025 .063 L -.088 .101 L -.038 .05 L .101 -.038 L .089 .025 L 0 .076 L .062 .05 L .076 -.101 L .062 -.051 L .277 -.012 L .417 .075 L .05 .189 L .126 .189 L .215 .025 L .126 .025 L .062 -.101 L .14 .013 L .062 .126 L .076 .063 L .113 .025 L -.164 .151 L .126 .063 L -.051 .05 L -.024 .114 L 0 .189 L -.177 .139 L .05 .139 L .102 .139 L .139 .025 L .188 .101 L .089 .101 L .113 .088 L .088 -.051 L .102 -.05 L .113 0 L .038 .088 L .025 .101 L -.089 .075 L .013 .189 L -.113 .038 L .062 .114 L .127 -.038 L .037 .051 L -.037 .088 L -.051 .151 L .151 .038 L .151 .063 L .151 .126 L .075 0 L .177 .076 L .101 .063 L .051 .139 L .013 .126 L -.038 .101 L .025 .113 L -.101 .063 L -.013 .038 L .075 .05 L .101 .051 L .164 .126 L .126 .013 L -.075 .076 L -.038 .025 L -.227 0 L -.139 -.013 L -.038 .038 L -.038 .038 L -.176 -.025 L .037 -.189 L -.177 0 L -.101 .025 L -.013 .05 L -.075 .076 L -.076 .076 L -.126 -.164 L -.075 0 L -.089 -.063 L 0 -.075 L -.139 .012 L -.075 .038 L -.025 .076 L -.063 -.051 L -.101 -.038 L .013 .063 L 0 .088 L -.113 0 L -.063 -.013 L .013 -.214 L -.013 -.088 L -.113 -.025 L -.126 .088 L -.239 .025 L -.202 .151 L .063 .101 L .088 .151 L -.051 .101 L .114 .113 L .012 .088 L -.037 .063 L -.126 .114 L .062 .088 L .025 .088 L -.075 .076 L -.29 .063 L -.14 .013 L .013 .114 L -.024 .126 L -.089 .088 L -.088 .063 L -.089 .025 L -.075 .013 L -.051 .063 L -.126 .063 L -.025 .113 L .063 .113 L 0 .088 L -.088 .114 L -.189 0 L -.113 -.013 L -.126 -.013 L -.102 .025 L -.055 .077 L -.03 .004 L -.062 -.237 L -.218 -.106 L .16 -.071 L -.021 -.267 L -.104 -.561 L .323 -.978 L .027 -.404 L -.353 -.856 L -.604 -.286 L -1.037 -1.119 L 460.567 93 l -.626 -.191 L -.225 .028 L +445.722 97.573 N .176 .002 L .264 -.103 L .724 -.047 L .361 -.16 L .753 -.567 L .63 -.84 L .968 -1.451 L .581 -.408 L 1.125 -.267 L .45 -.338 L .136 -.085 L .787 .121 L .241 -.107 L .958 .193 L 1.115 .066 L .363 -.045 L .025 .231 L .327 -.004 L .188 .227 L .339 -.06 L .243 -.119 L .186 -.215 L 1.992 -.191 L .278 -.178 L .151 -.311 L .634 -.08 L .225 -.028 L 460.567 93 l .767 1.17 L 1.037 1.119 L .604 .286 L .353 .856 L -.027 .404 L -.323 .978 L .104 .561 L .021 .267 L -.16 .071 L .218 .106 L .062 .237 L .03 -.004 L .15 -.02 L .119 .249 L .398 .166 L .609 .047 L .033 -.189 L .457 0 L .665 -.261 L .706 .131 L .149 .079 L .062 .259 L -.293 .446 L -.27 .316 L -.436 .044 L -.382 .043 L -.382 .245 L -.515 .617 L -.252 .645 L -.096 .787 L -.044 .223 L -.671 -.12 L -1.346 -.336 L -.514 -.226 L -.295 -.042 L -.671 -.369 L -.562 -.04 L -.618 .218 L -1.904 .771 L -.38 .059 L -1.385 -.35 L -.3 -.013 L -.69 .261 L -.34 .031 L -1.151 -.395 L -.506 -.002 L -.771 .189 L -.266 .023 L -.048 -.189 L .234 -.318 L -.352 -.106 L -.392 -.204 L -.418 -.186 L -.146 -.33 L .32 -.201 L .351 .012 L -.114 -.13 L -.625 -.248 L -.253 .13 L -.215 .283 L -.147 .118 L -.414 -.239 L -.194 -.139 L -.594 -.059 L -.02 -.189 L -.234 0 L -.245 -.036 L -.052 -.165 L .178 -.094 L .271 -.071 L -.239 -.083 L -.183 -.059 L .124 -.146 L .19 -.127 L -.069 -.142 L -.306 -.118 L -.555 -.141 L -.712 -.471 L .058 -.088 L -.104 -.119 L .075 -.356 L -.202 -.036 L -.19 -.237 L -.569 -.178 L -.054 -.309 L +420.177 113.472 N -.274 -.042 L -.253 -.155 L -.367 -.325 L -.096 -.213 L .202 -.738 L .097 -.681 L -.046 -.583 L -.133 -.569 L -.503 -.44 L -.094 -.271 L .181 -.157 L .366 -.015 L .801 -.001 L .339 -.172 L .861 -.543 L .633 .625 L .451 .754 L -.014 .271 L -.204 .285 L -.145 .484 L .149 .894 L -.11 .525 L -.377 .695 L -.405 -.198 L -.52 .03 L -.143 .1 L -.149 .27 L -.248 .17 L h 433.783 118.446 m -.712 -.084 L -.902 -.607 L -.772 -.239 L -1.904 -.817 L -.833 -.126 L -.232 -.127 L -.173 -.283 L .139 -.34 L .328 -.34 L .264 -.1 L .629 .112 L .569 -.341 L .68 .424 L .403 .141 L .722 -.016 L 1.403 -.187 L 1.38 -.329 L .148 .085 L .043 .127 L -.112 .127 L -.536 .823 L -.153 .497 L .009 .382 L .411 .509 L -.179 .128 L -.43 .567 L -.188 .015 L h 431.244 98.829 m -.281 -.329 L -.242 -.027 L -.281 .196 L -.156 -.125 L -.47 -.071 L -.114 .32 L -.458 .054 L -1.001 .364 L .078 -.151 L -.452 .133 L -.063 .249 L -.157 .044 L -.01 .125 L .303 .08 L .021 .302 L .193 .119 L .253 .236 L -.104 .213 L -.449 .254 L .016 .272 L .143 .554 L .783 .814 L 2.008 .889 L .29 .357 L .134 .558 L .274 .557 L .395 .585 L .694 .57 L .254 .274 L .446 .195 L .041 .21 L .408 .167 L 1.17 .255 L 1.254 -.105 L .388 .141 L .024 .212 L -.465 .247 L -.258 .294 L .262 .213 L .954 .283 L 1.168 .411 L .829 .366 L 1.589 .739 L .058 .185 L .719 .458 L .31 .475 L -.198 .435 L -.152 .337 L -.455 -.281 L -.318 -.167 L -.109 -.486 L -.263 -.17 L -.512 -.099 L -.483 -.009 L -.439 -.236 L .086 -.217 L -.353 -.065 L -.301 .098 L -.232 .262 L -.259 .399 L -.273 .208 L .043 .271 L -.197 .303 L -.007 .298 L .76 .342 L .611 .271 L -.093 .314 L .03 .432 L .133 .142 L -.191 .238 L -.659 -.024 L -.41 .219 L -.202 .228 L .11 .595 L -.536 .303 L -.617 .866 L -.595 .048 L -.167 -.071 L -.184 -.14 L -.002 -.508 L .364 -.141 L .317 -.542 L -.236 -.184 L .361 -.249 L .361 .074 L .133 -.17 L -.077 -.34 L -.211 -.181 L -.206 -.924 L -.367 -.516 L -.15 -.607 L -.201 -.352 L -.334 .058 L -.187 .171 L -.899 -.496 L -.286 -.065 L .208 -.291 L -.092 -.398 L -.461 -.34 L -.909 .247 L .034 -.109 L .322 -.194 L -.276 -.27 L -.29 -.003 L -.42 .19 L -.242 -.512 L -.198 -.207 L -.124 -.228 L -.663 -.241 L -.505 -.027 L -.654 -.127 L -.745 -.355 L -.548 -.441 L -.959 -.612 L -1.036 -.826 L -.872 -.384 L -.805 -.67 L -.566 -.856 L -.434 -1.043 L -.347 -.443 L -.505 -.457 L -.483 -.243 L -1.188 -.341 L -.579 -.142 L -.5 .044 L -1.078 .647 L -.46 .359 L -.646 .173 L -.303 .043 L .146 -.469 L -.062 -.281 L -.849 .07 L -.754 -.391 L -.193 -.442 L .315 -.371 L .175 -.01 L -.135 -.331 L -.616 -.191 L -.352 -.358 L .437 -.186 L .183 .111 L .541 -.353 L .199 -.272 L -.43 -.192 L -.025 -.292 L -.532 -.344 L .624 -.301 L .599 .062 L .627 -.204 L .629 .168 L .275 -.16 L .349 -.432 L -.103 -.212 L .777 -.404 L .016 .415 L .534 .363 L .311 .071 L -.098 .182 L .385 .312 L .285 -.151 L .018 -.535 L .425 -.384 L -.019 -.333 L .371 -.081 L .143 .354 L .23 .142 L .216 -.03 L .071 -.122 L .469 -.05 L .244 .333 L .228 -.415 L -.244 -.131 L .081 -.273 L .283 -.091 L .176 .162 L .315 .051 L .038 -.192 L -.112 -.212 L .126 -.309 L .631 .171 L .597 .034 L .329 -.411 L .366 -.096 L .183 .083 L .445 -.11 L .301 .103 L .856 -.227 L .023 .363 L .318 .096 L .32 .391 L 1.311 .247 L .894 .082 L .478 .112 L .116 .199 L -.614 .303 L .098 .151 L .297 .002 L .187 .185 L -.367 .285 L .336 .089 L -.127 .361 L .36 .11 L .284 .198 L -.056 .214 L +430.73 96.731 N 1.04 .065 L .179 .107 L .612 -.009 L .287 .152 L .646 -.5 L .566 -.107 L .85 .08 L .298 -.196 L .89 .116 L -.082 -.393 L .693 -.157 L .304 .59 L .364 .333 L -.035 -.009 L -.1 -.073 L -.145 -.036 L -.172 0 L -.145 .009 L -.055 .063 L 0 .072 L .019 .09 L .009 .082 L -.063 .009 L -.136 -.009 L -.108 -.036 L -.091 .063 L -.045 .082 L -.081 .063 L -.082 .045 L -.081 .009 L -.163 .036 L -.117 .036 L -.108 .036 L -.055 .045 L -.153 -.009 L -.127 .072 L -.063 .054 L -.018 .082 L .036 .072 L .081 .054 L .063 .055 L .045 .045 L .019 .063 L .018 .09 L -.036 .108 L -.018 .063 L -.046 .1 L -.108 0 L -.081 -.009 L -.091 .027 L -.108 .009 L -.117 .054 L -.091 .018 L -.081 .027 L -.1 .045 L -.055 .063 L -.036 .027 L .055 .018 L .063 .009 L .026 .027 L .037 .072 L -.046 .063 L -.027 .009 L -.081 .027 L -.009 .045 L .045 .081 L 0 .072 L .045 .1 L -.054 .072 L -.063 -.018 L -.1 .045 L -.117 .018 L -.127 -.036 L -.063 -.027 L -.1 -.063 L -.099 0 L -.063 -.027 L -.118 -.045 L -.018 .045 L -.027 .045 L -.1 .027 L -.136 0 L -.054 -.045 L -.072 -.063 L -.127 -.018 L -.019 -.09 L -.026 -.018 L -.063 -.054 L -.055 -.027 L -.018 -.054 L -.01 -.054 L -.036 -.009 L -.063 .018 L -.036 .054 L -.009 .027 L -.054 .063 L -.019 .018 L -.018 .081 L -.063 .045 L -.046 .018 L -.062 .054 L -.036 .009 L -.254 0 L -.108 -.027 L -.108 .027 L -.145 .009 L -.1 -.009 L -.1 -.036 L -.045 -.019 L -.055 0 L 0 .037 L 0 .036 L -.045 .027 L -.045 .018 L -.136 -.009 L -.027 -.036 L -.108 .018 L -.019 .018 L -.136 .018 L -.063 .018 L -.126 .018 L -.272 -.063 L .428 -.077 L .113 -.16 L .056 -.214 L -.284 -.198 L -.36 -.11 L .127 -.361 L -.336 -.089 L .367 -.285 L -.187 -.185 L -.297 -.002 L -.098 -.151 L .614 -.303 L -.116 -.199 L +439.573 104.709 N -1.051 -.672 L -.185 -.222 L -.783 -.149 L -.203 -.159 L -.403 -.115 L -.683 .177 L -.326 -.486 L -1.112 -.627 L -.584 -.678 L .277 .007 L .608 .016 L -.583 -.221 L -.659 -.469 L -.183 -.407 L .086 -.452 L -.289 -.336 L -.646 -.418 L -.378 -.126 L -.258 .579 L -.142 .116 L .03 .15 L -.284 .106 L -.154 .248 L -.213 .053 L -.496 -.647 L -.063 -.286 L -.259 -.612 L .065 -.012 L .272 .063 L .126 -.018 L .063 -.018 L .136 -.018 L .019 -.018 L .108 -.018 L .027 .036 L .136 .009 L .045 -.018 L .045 -.027 L 0 -.036 L 0 -.037 L .055 0 L .045 .019 L .1 .036 L .1 .009 L .145 -.009 L .108 -.027 L .108 .027 L .254 0 L .036 -.009 L .062 -.054 L .046 -.018 L .063 -.045 L .018 -.081 L .019 -.018 L .054 -.063 L .009 -.027 L .036 -.054 L .063 -.018 L .036 .009 L .01 .054 L .018 .054 L .055 .027 L .063 .054 L .026 .018 L .019 .09 L .127 .018 L .072 .063 L .054 .045 L .136 0 L .1 -.027 L .027 -.045 L .018 -.045 L .118 .045 L .063 .027 L .099 0 L .1 .063 L .063 .027 L .127 .036 L .117 -.018 L .1 -.045 L .063 .018 L .054 -.072 L -.045 -.1 L 0 -.072 L -.045 -.081 L .009 -.045 L .081 -.027 L .027 -.009 L .046 -.063 L -.037 -.072 L -.026 -.027 L -.063 -.009 L -.055 -.018 L .036 -.027 L .055 -.063 L .1 -.045 L .081 -.027 L .091 -.018 L .117 -.054 L .108 -.009 L .091 -.027 L .081 .009 L .108 0 L .046 -.1 L .018 -.063 L .036 -.108 L -.018 -.09 L -.019 -.063 L -.045 -.045 L -.063 -.055 L -.081 -.054 L -.036 -.072 L .018 -.082 L .063 -.054 L .127 -.072 L .153 .009 L .055 -.045 L .108 -.036 L .117 -.036 L .163 -.036 L .081 -.009 L .082 -.045 L .081 -.063 L .045 -.082 L .091 -.063 L .108 .036 L .136 .009 L .063 -.009 L -.009 -.082 L -.019 -.09 L 0 -.072 L .055 -.063 L .145 -.009 L .172 0 L .145 .036 L .1 .073 L .035 .009 L .215 .197 L 1.412 .612 L 1.116 .671 L .58 .098 L .668 -.047 L .433 -.031 L .589 -.203 L .201 .142 L .056 .089 L .022 .112 L -.022 .078 L .045 .044 L .011 .067 L -.078 .056 L -.011 .146 L .078 .067 L .145 -.034 L .101 .034 L .045 .089 L -.078 .011 L -.056 -.022 L -.022 .078 L .033 .1 L -.045 .034 L -.044 .022 L .066 .111 L .168 -.022 L .033 .078 L .123 .1 L .122 0 L .101 0 L .09 .078 L .122 .011 L .134 0 L .012 .078 L -.033 .056 L -.135 -.011 L -.089 -.034 L -.067 .022 L -.078 -.011 L -.066 -.045 L -.056 -.011 L -.045 .011 L .033 .067 L -.101 .089 L -.078 0 L 0 .156 L .045 .067 L -.033 .078 L .022 .078 L .011 .078 L -.089 .033 L -.09 -.033 L -.056 .067 L .078 .089 L -.078 .011 L -.189 .022 L -.201 -.022 L -.145 -.123 L .056 -.101 L -.045 -.089 L -.123 -.011 L -.022 -.112 L -.145 -.056 L -.146 -.045 L -.101 .089 L -.1 -.011 L -.156 -.078 L -.067 -.022 L -.146 0 L -.156 -.045 L -.111 .067 L -.134 .045 L -.134 -.045 L -.111 -.067 L -.112 0 L -.122 .089 L -.168 .078 L -.156 -.067 L -.268 -.089 L -.179 .011 L -.156 .011 L -.189 -.056 L -.168 -.011 L -.156 -.089 L -.089 .078 L -.111 .022 L -.057 -.056 L -.234 -.078 L -.156 -.056 L -.134 -.045 L -.089 -.011 L -.134 .123 L -.112 -.011 L -.223 -.022 L -.168 -.033 L -.212 .022 L -.101 .111 L -.145 .145 L -.123 .201 L -.201 -.022 L -.256 -.134 L -.156 -.19 L -.101 -.111 L -.312 -.034 L -.123 .044 L -.089 .179 L -.045 .167 L .045 .134 L 0 .078 L .033 .212 L -.123 .067 L .022 .089 L .134 .078 L .09 .089 L .122 .034 L .101 .033 L .179 .179 L .146 .234 L .089 .134 L .022 .123 L .156 .111 L -.078 .056 L -.012 .1 L .022 .146 L .168 -.011 L .089 .111 L .056 .123 L .112 .111 L .167 .045 L .167 .033 L .369 .357 L .021 .167 L .078 .044 L .213 .078 L .379 .357 L .224 .123 L .223 .067 L .101 .056 L 0 .112 L .078 .279 L .201 .078 L .189 .167 L .146 .112 L .245 .123 L .067 .212 L -.284 .083 L h 439.792 104.833 m .132 -.118 L .134 .011 L .123 .034 L .045 .078 L .066 .089 L .146 .089 L .179 .078 L .212 .011 L .312 .257 L .045 .067 L .134 -.033 L .123 .022 L .089 .034 L .062 .063 L .005 .004 L -.022 .089 L .033 .078 L .082 .072 L .029 .092 L -.002 .1 L -.589 -.367 L -.549 -.371 L -.789 -.378 L +451.009 101.725 N -.328 .346 L -.383 .374 L -.18 .302 L .056 .271 L 1.326 1.122 L .028 .2 L -.302 .302 L -.762 .333 L -.246 .301 L -.008 .514 L -.013 .208 L -.058 -.017 L -.072 .029 L -.16 .022 L -.145 .021 L -.116 .022 L -.058 .015 L -.102 -.051 L -.087 .043 L -.088 .021 L -.102 -.043 L -.064 -.021 L -.131 .116 L -.087 .08 L -.152 -.015 L -.196 -.007 L -.064 .007 L -.175 -.043 L -.152 .087 L -.151 .102 L -.109 .058 L .059 .072 L -.029 .058 L -.116 0 L -.094 -.109 L -.131 -.058 L -.087 -.073 L -.08 .065 L -.116 .058 L -.246 .058 L -.225 .058 L -.088 .058 L -.058 .167 L .029 .13 L -.029 .072 L -.072 .087 L -.188 0 L -.14 -.049 L -.018 -.109 L -.733 -.866 L -.382 -.369 L -.058 -.004 L .109 -.286 L 0 -.067 L -.078 -.067 L -.101 0 L -.056 -.056 L .022 -.089 L .111 -.033 L .146 .011 L .167 .033 L .057 -.033 L .021 -.067 L .09 -.044 L .134 -.022 L .089 -.011 L -.011 -.089 L -.101 -.101 L -.167 -.067 L -.134 -.045 L -.057 -.044 L -.111 .022 L -.078 -.045 L -.033 -.067 L -.123 -.101 L -.078 -.1 L -.066 -.022 L -.067 .044 L -.078 -.011 L -.101 -.056 L -.279 -.078 L -.078 -.022 L -.056 -.033 L -.167 -.134 L -.101 -.146 L -.111 -.111 L -.168 -.078 L -.156 -.101 L -.223 -.056 L 0 -.101 L .179 -.101 L .089 -.111 L .078 -.011 L .067 .034 L .078 .044 L .1 .022 L .045 -.022 L .012 -.134 L .011 -.19 L -.134 -.145 L -.179 -.19 L -.212 -.134 L -.101 -.145 L .101 .022 L .101 .011 L .145 .056 L .224 .044 L .134 -.078 L .089 -.056 L .067 -.078 L -.089 -.044 L -.135 -.022 L -.089 -.089 L -.123 -.078 L -.156 -.089 L -.033 -.101 L -.045 -.1 L -.212 .011 L -.167 -.056 L -.078 -.1 L -.022 -.134 L .078 -.067 L 0 -.089 L -.033 -.1 L .056 -.056 L .066 -.078 L .156 -.156 L .156 -.223 L .034 -.167 L .056 -.1 L -.022 -.067 L -.123 -.022 L -.179 -.011 L -.156 0 L -.212 .112 L -.078 -.089 L .056 -.067 L .09 .033 L .089 -.033 L -.011 -.078 L -.022 -.078 L .033 -.078 L -.045 -.067 L 0 -.156 L .078 0 L .101 -.089 L -.033 -.067 L .045 -.011 L .056 .011 L .066 .045 L .078 .011 L .067 -.022 L .089 .034 L .135 .011 L .033 -.056 L -.012 -.078 L -.134 0 L -.122 -.011 L -.09 -.078 L -.101 0 L -.122 0 L -.123 -.1 L -.033 -.078 L -.168 .022 L -.066 -.111 L .044 -.022 L .045 -.034 L -.033 -.1 L .022 -.078 L .056 .022 L .078 -.011 L -.045 -.089 L -.101 -.034 L -.145 .034 L -.078 -.067 L .011 -.146 L .078 -.056 L -.011 -.067 L -.045 -.044 L .022 -.078 L -.022 -.112 L -.056 -.089 L -.201 -.142 L 1.535 -.529 L .889 -.077 L .907 .067 L .054 .309 L .569 .178 L .19 .237 L .202 .036 L -.075 .356 L .104 .119 L -.058 .088 L .712 .471 L .555 .141 L .306 .118 L .069 .142 L -.19 .127 L -.124 .146 L .183 .059 L .239 .083 L -.271 .071 L -.178 .094 L .052 .165 L .245 .036 L .234 0 L .02 .189 L .594 .059 L .194 .139 L .414 .239 L .147 -.118 L .215 -.283 L .253 -.13 L .625 .248 L .114 .13 L -.351 -.012 L -.32 .201 L .146 .33 L .418 .186 L +551.198 117.997 N -.351 -.48 L -.236 -.126 L -1.217 -.05 L -.646 -.011 L -.096 -.016 L .091 -.726 L -.062 -.503 L .157 -.251 L .062 -.22 L -.503 -.094 L -.534 -.283 L -.566 -.189 L -.471 .063 L -.378 -.251 L -1.132 -.597 L -.565 -.22 L -.943 -.597 L -.314 .063 L -1.006 -.503 L -.377 -.44 L -1.194 -.597 L -1.384 -.975 L 0 -.283 L -.188 -.44 L -.283 -.188 L -.408 -.597 L -.126 -.566 L -.22 -.377 L -.881 -.251 L -.188 .157 L -.439 .063 L -.535 -.126 L -.439 .032 L -.503 .094 L -.314 -.157 L -.691 -.314 L .094 -.22 L .157 -.188 L -.188 -.22 L .031 -.188 L .188 -.157 L -.439 -.283 L 0 -.22 L -.032 -.22 L -.251 -.22 L -.534 -.094 L -.692 -.095 L -.22 -.314 L -.346 -.032 L -.629 -.377 L -.472 -.095 L -.188 .063 L -.565 .157 L .251 .251 L .188 .377 L -.597 -.283 L -.283 0 L -.126 .126 L -.22 .346 L -.283 .126 L -.629 0 L -.503 .251 L -.503 .409 L -.062 .628 L .314 .409 L -.126 .314 L -1.383 .032 L -1.03 -.063 L .056 -8.174 L 5.658 -1.289 L 5.722 2.986 L 2.012 1.666 L 2.578 -.346 L 2.767 .188 L 1.1 -.409 L .724 .723 L .597 .22 L .66 1.006 L .66 -.314 L -.031 1.038 L -.188 .409 L .031 .754 L 1.006 0 L .221 .817 L .346 1.069 L .503 .063 L .691 -.032 L 1.006 -.094 L .346 0 L .44 .314 L .062 .283 L -.062 .283 L .44 .346 L .66 0 L .125 -.188 L -.157 -.409 L .504 -.44 L .439 -.188 L .221 -.472 L .282 -.188 L .943 -.377 L .755 -.189 L .534 -.471 L .346 -.283 L .22 -.063 L .283 .126 L .377 -.377 L .322 -.031 L .349 -.126 L .441 .246 L -.368 .172 L -.368 .171 L -.221 .049 L -.073 .196 L -.295 .049 L -.294 .172 L -.196 .147 L -.441 .295 L -.172 .098 L -.024 .123 L .294 .049 L .295 .074 L .146 .123 L .418 -.147 L .098 .221 L .172 .221 L .368 .27 L .589 0 L .393 0 L .049 -.393 L .221 .049 L .196 -.196 L .024 -.245 L .196 .098 L .196 .172 L .172 .294 L .049 .147 L .393 .024 L .147 -.024 L .073 .246 L .025 .098 L .343 -.025 L .319 .147 L .245 .196 L .516 .074 L .466 .024 L .172 .123 L -.49 .221 L -.197 .147 L -.221 .147 L -.49 -.024 L -.245 -.049 L .049 .171 L 0 .147 L -.319 0 L -.172 .049 L -.343 .196 L -.221 .196 L -.271 .049 L -.221 .196 L -.245 -.147 L -.319 -.098 L -.294 -.098 L -.221 .025 L -.246 .073 L -.318 -.073 L -.042 .098 L -.345 -.005 L -.409 .031 L -.188 -.283 L -.251 -.063 L -.126 -.188 L .251 -.126 L .409 -.346 L .188 -.22 L -.252 -.251 L -.439 -.377 L -.221 .251 L -.471 .346 L -.692 .188 L -.22 .157 L -.252 -.22 L -.22 -.157 L -.346 0 L .031 .22 L -.283 .314 L .189 .314 L -.032 .346 L -.062 .126 L -.472 -.095 L -.565 .095 L -.503 .094 L .251 .125 L .534 -.031 L .126 .094 L -.251 .063 L -.188 .063 L -.032 .346 L -.188 0 L -.251 .157 L -.063 .409 L -.282 .188 L -1.069 -.094 L -.629 -.126 L -.472 .283 L -.125 .471 L .251 .283 L .346 .188 L .157 .157 L .44 .032 L .346 0 L .126 .22 L -.126 .22 L -.031 .472 L .126 .409 L .471 .314 L .126 .283 L -.157 .22 L -.503 .346 L -.283 .503 L -.377 .377 L .063 .377 L -.375 .843 L +439.792 104.833 N -.113 -.054 L -.105 -.07 L .284 -.083 L -.067 -.212 L -.245 -.123 L -.146 -.112 L -.189 -.167 L -.201 -.078 L -.078 -.279 L 0 -.112 L -.101 -.056 L -.223 -.067 L -.224 -.123 L -.379 -.357 L -.213 -.078 L -.078 -.044 L -.021 -.167 L -.369 -.357 L -.167 -.033 L -.167 -.045 L -.112 -.111 L -.056 -.123 L -.089 -.111 L -.168 .011 L -.022 -.146 L .012 -.1 L .078 -.056 L -.156 -.111 L -.022 -.123 L -.089 -.134 L -.146 -.234 L -.179 -.179 L -.101 -.033 L -.122 -.034 L -.09 -.089 L -.134 -.078 L -.022 -.089 L .123 -.067 L -.033 -.212 L 0 -.078 L -.045 -.134 L .045 -.167 L .089 -.179 L .123 -.044 L .312 .034 L .101 .111 L .156 .19 L .256 .134 L .201 .022 L .123 -.201 L .145 -.145 L .101 -.111 L .212 -.022 L .168 .033 L .223 .022 L .112 .011 L .134 -.123 L .089 .011 L .134 .045 L .156 .056 L .234 .078 L .057 .056 L .111 -.022 L .089 -.078 L .156 .089 L .168 .011 L .189 .056 L .156 -.011 L .179 -.011 L .268 .089 L .156 .067 L .168 -.078 L .122 -.089 L .112 0 L .111 .067 L .134 .045 L .134 -.045 L .111 -.067 L .156 .045 L .146 0 L .067 .022 L .156 .078 L .1 .011 L .101 -.089 L .146 .045 L .145 .056 L .022 .112 L .123 .011 L .045 .089 L -.056 .101 L .145 .123 L .201 .022 L .189 -.022 L .078 -.011 L .212 -.112 L .156 0 L .179 .011 L .123 .022 L .022 .067 L -.056 .1 L -.034 .167 L -.156 .223 L -.156 .156 L -.066 .078 L -.056 .056 L .033 .1 L 0 .089 L -.078 .067 L .022 .134 L .078 .1 L .167 .056 L .212 -.011 L .045 .1 L .033 .101 L .156 .089 L .123 .078 L .089 .089 L .135 .022 L .089 .044 L -.067 .078 L -.089 .056 L -.134 .078 L -.224 -.044 L -.145 -.056 L -.101 -.011 L -.101 -.022 L .101 .145 L .212 .134 L .179 .19 L .134 .145 L -.011 .19 L -.012 .134 L -.045 .022 L -.1 -.022 L -.078 -.044 L -.067 -.034 L -.078 .011 L -.089 .111 L -.179 .101 L -.056 -.033 L -.156 .056 L -.112 -.022 L -.066 -.044 L -.112 .033 L -.078 .056 L .012 .078 L .089 .1 L .123 .167 L .056 .101 L -.056 .101 L -.111 0 L -.09 -.056 L -.056 -.089 L -.056 -.044 L -.123 -.011 L -.122 .056 L -.168 .078 L -.045 .101 L -.044 .089 L -.112 .101 L .034 .089 L .011 .1 L 442 104.458 l -.134 .011 L -.111 .022 L -.101 .089 L -.012 .134 L .012 .112 L .011 .145 L .012 .044 L .066 .112 L .078 .089 L .045 .101 L -.09 .089 L -.183 .108 L -.062 -.063 L -.089 -.034 L -.123 -.022 L -.134 .033 L -.045 -.067 L -.312 -.257 L -.212 -.011 L -.179 -.078 L -.146 -.089 L -.066 -.089 L -.045 -.078 L -.123 -.034 L -.134 -.011 L -.132 .118 L +450.198 105.998 N .013 -.208 L .008 -.514 L .246 -.301 L .762 -.333 L .302 -.302 L -.028 -.2 L -1.326 -1.122 L -.056 -.271 L .18 -.302 L .383 -.374 L .328 -.346 L .392 .204 L .352 .106 L -.234 .318 L .048 .189 L .266 -.023 L .771 -.189 L .506 .002 L 1.151 .395 L .34 -.031 L .69 -.261 L .3 .013 L 1.385 .35 L .38 -.059 L 1.904 -.771 L .618 -.218 L .562 .04 L .671 .369 L .295 .042 L .514 .226 L 1.346 .336 L .671 .12 L -.066 .335 L -.077 .258 L -.261 .086 L -.313 -.028 L -.339 .129 L -.327 .73 L -.039 .586 L -.075 .143 L -.404 .115 L -.338 .372 L -.017 .257 L .252 -.036 L .255 .224 L .033 .154 L .391 .375 L .01 .223 L -1.333 -.005 L -.527 -.111 L -.497 .045 L -.629 .374 L -.498 .445 L -.363 -.026 L -.344 .216 L .097 .327 L -.086 .257 L -1.117 .277 L -.388 .031 L -.619 -.21 L -1.473 -.505 L -.584 .06 L -.799 .261 L -1.855 .195 L -.09 .029 L -.047 -.199 L .104 -.3 L .006 -.499 L -.225 -.469 L -.358 -.383 L -.666 -.296 L -.134 -.213 L .007 -.106 L +381.009 107 N -.121 -.278 L .138 -.4 L .343 -.5 L -.358 -.471 L -.304 -.428 L -.514 -.07 L -.164 -.1 L -.053 -.329 L .163 -.243 L .409 -.272 L .365 -.101 L .563 -.03 L .634 -.03 L .133 -.172 L .068 -.415 L .535 -.273 L .763 .042 L 1.078 .37 L .763 .07 L .756 -.087 L .577 -.173 L .508 -.144 L .354 -.001 L .629 .285 L .694 .156 L .939 .084 L 1.538 .04 L .583 .027 L .957 .141 L .491 -.158 L .419 -.229 L .531 .027 L .891 .47 L .67 -.016 L .335 .062 L .472 .243 L .469 -.03 L .058 .122 L -.205 .243 L .094 .106 L .15 .03 L .112 -.106 L 1.088 .334 L .15 -.061 L .507 .395 L .056 -.076 L .262 .03 L .131 -.076 L .431 .152 L .028 .038 L .084 .114 L .767 -.03 L .037 .122 L .337 -.061 L .542 .015 L -.017 -.319 L .355 0 L 1.252 .304 L .091 .213 L .035 .289 L .187 .076 L .374 -.076 L .206 -.03 L .335 .091 L .036 .152 L .261 .015 L .395 -.167 L .427 .197 L .485 .015 L .039 -.136 L .75 -.137 L .334 .091 L -.001 .088 L -.001 .463 L .156 .1 L -.062 .485 L -1.112 .528 L -.95 .385 L -.267 .328 L -1.046 .198 L -.664 .116 L -.96 .301 L -.323 .326 L -.053 .2 L .261 .128 L -.088 .157 L -.628 .143 L -.594 .783 L -.886 .787 L -.096 .192 L -.18 .361 L -.245 .45 L .353 .827 L .072 .111 L .084 .13 L .648 .295 L .103 .185 L -.621 .327 L -.215 .105 L -.515 .252 L -.286 .479 L -.224 .085 L -.461 .926 L .155 .322 L -.257 .099 L -.992 .049 L -.581 .242 L -.425 .327 L -.274 .757 L -.663 .496 L -.258 -.213 L -.599 .028 L -.305 .27 L -.342 0 L -.121 -.113 L -3.282 .042 L -.69 .524 L -1.021 .17 L -.35 .382 L -.028 .283 L -.083 .085 L -.073 -.212 L -.068 -.014 L .005 .241 L -.389 .127 L -.421 -.142 L -.788 -.467 L -.224 -.382 L .036 -.262 L -.345 -.113 L -.125 -.213 L .175 -.163 L -.468 -.51 L -.702 -.284 L 385 117.498 l -.484 -.135 L -.586 .039 L .008 -.018 L .304 -.951 L .242 -.37 L .884 -.643 L -.408 -.31 L -.812 -.123 L .17 -.455 L .506 -.655 L .347 -.371 L -.163 -.198 L -.455 -.551 L -.488 -.494 L .288 -.129 L .482 -.045 L .458 -.229 L .043 -.199 L -.057 -.938 L .132 -.983 L -.072 -.456 L .051 -.442 L .084 -.072 L 1.234 -.506 L .288 -.216 L -.062 -.242 L -.842 -.495 L -.15 -.242 L -.272 -.227 L -.335 -.055 L -.531 .26 L 382.981 107 l -.531 -.439 L -.55 .188 L 381.009 107 l +489.685 103.693 N .112 -.309 L .26 -.166 L .284 .047 L .07 .047 L .402 .023 L .449 .023 L .283 .095 L .284 .142 L .188 .094 L .189 .047 L .331 0 L .213 0 L .212 .166 L .261 .095 L .307 .071 L .355 .047 L .307 0 L .426 -.095 L .544 0 L .401 .166 L .189 0 L .283 -.047 L .354 .166 L .095 .142 L .284 .213 L .52 .118 L .354 .071 L .236 .118 L .308 .119 L -.142 .118 L -.048 .118 L .261 .118 L .212 .071 L .261 -.118 L .283 0 L .166 -.166 L .094 -.095 L .213 -.071 L .354 0 L .261 .071 L .188 .142 L .142 -.166 L .095 -.071 L .118 0 L .236 .118 L .143 .094 L .212 0 L .189 .118 L .213 .166 L .378 0 L .354 .024 L .118 .142 L -.118 .189 L -.118 .307 L .354 .284 L .284 .166 L .26 .094 L .284 .047 L .236 -.023 L .236 .071 L .126 .189 L -.268 .189 L -.143 .142 L -.095 .071 L .143 .26 L .213 .307 L .614 .166 L .118 .213 L -.095 .331 L -.236 .095 L -.236 .047 L -.26 -.189 L -.143 -.071 L -.188 -.023 L -.284 .047 L -.638 -.189 L -.189 -.213 L -.331 -.189 L -.473 -.024 L -.236 0 L -.418 .308 L -.291 .094 L -.378 .047 L -.591 .095 L -.592 -.047 L -.401 .118 L -.426 .023 L -.308 .095 L -.307 -.024 L -.377 .108 L -.031 -.028 L -1.326 -1.018 L -.41 -.041 L -.761 .36 L -.226 .072 L -.491 -.068 L -1.212 -.082 L .083 -.065 L .322 -.585 L .032 -.143 L -.064 -.728 L -.331 -1.084 L -.206 -.399 L -.639 -.513 L -.341 -.128 L -.916 -.155 L -.679 -.271 L -.341 -.243 L +443.617 107.095 N -.065 -.035 L -.435 -.156 L -.017 -.15 L -.501 -.485 L -.848 -.3 L -.033 -.021 L .002 -.1 L -.029 -.092 L -.082 -.072 L -.033 -.078 L .022 -.089 L -.005 -.004 L .183 -.108 L .09 -.089 L -.045 -.101 L -.078 -.089 L -.066 -.112 L -.012 -.044 L -.011 -.145 L -.012 -.112 L .012 -.134 L .101 -.089 L .111 -.022 L .134 -.011 L .056 -.056 L -.011 -.1 L -.034 -.089 L .112 -.101 L .044 -.089 L .045 -.101 L .168 -.078 L .122 -.056 L .123 .011 L .056 .044 L .056 .089 L .09 .056 L .111 0 L .056 -.101 L -.056 -.101 L -.123 -.167 L -.089 -.1 L -.012 -.078 L .078 -.056 L .112 -.033 L .066 .044 L .112 .022 L .156 -.056 L .056 .033 L 0 .101 L .223 .056 L .156 .101 L .168 .078 L .111 .111 L .101 .146 L .167 .134 L .056 .033 L .078 .022 L .279 .078 L .101 .056 L .078 .011 L .067 -.044 L .066 .022 L .078 .1 L .123 .101 L .033 .067 L .078 .045 L .111 -.022 L .057 .044 L .134 .045 L .167 .067 L .101 .101 L .011 .089 L -.089 .011 L -.134 .022 L -.09 .044 L -.021 .067 L -.057 .033 L -.167 -.033 L -.146 -.011 L -.111 .033 L -.022 .089 L .056 .056 L .101 0 L .078 .067 L 0 .067 L -.109 .286 L -.361 -.022 L -.727 -.11 L -.273 .273 L -.279 .515 L .133 .427 L -.002 .342 L +558.52 110.652 N .042 -.098 L .318 .073 L .246 -.073 L .221 -.025 L .294 .098 L .319 .098 L .245 .147 L .221 -.196 L .271 -.049 L .221 -.196 L .343 -.196 L .172 -.049 L .319 0 L 0 -.147 L -.049 -.171 L .245 .049 L .49 .024 L .221 -.147 L .197 -.147 L .49 -.221 L -.172 -.123 L -.466 -.024 L -.516 -.074 L -.245 -.196 L -.319 -.147 L -.343 .025 L -.025 -.098 L -.073 -.246 L -.147 .024 L -.393 -.024 L -.049 -.147 L -.172 -.294 L -.196 -.172 L -.196 -.098 L -.024 .245 L -.196 .196 L -.221 -.049 L -.049 .393 L -.393 0 L -.589 0 L -.368 -.27 L -.172 -.221 L -.098 -.221 L -.418 .147 L -.146 -.123 L -.295 -.074 L -.294 -.049 L .024 -.123 L .172 -.098 L .441 -.295 L .196 -.147 L .294 -.172 L .295 -.049 L .073 -.196 L .221 -.049 L .368 -.171 L .368 -.172 L -.441 -.246 L -.349 .126 L -.044 -.273 L .393 -.442 L .318 -.368 L .736 -.123 L .663 -.098 L .883 .147 L .883 .245 L .688 .196 L .81 .123 L .344 .123 L -.024 -.442 L .245 -.736 L .466 -.368 L .688 -.123 L .589 .074 L .761 .27 L .735 .246 L .908 .196 L .54 .098 L .441 -.27 L .858 -.024 L .761 0 L .785 -.147 L .712 .221 L .662 .098 L 1.35 .024 L .662 -.074 L .981 .246 L .564 -.049 L .147 .344 L .27 .147 L .196 .27 L .663 0 L .466 .098 L .41 .375 L .031 .194 L -.051 .157 L -.325 .187 L -.97 .219 L -1.338 .349 L -.445 .145 L -.405 .301 L -.638 .701 L -.646 .345 L -.478 .102 L -.459 .017 L -1.248 -.235 L -.238 .03 L -.467 .472 L -.463 .784 L -.268 .243 L -.885 .132 L -.507 .145 L -.344 -.055 L -.183 -.567 L -.06 -.071 L -.359 .03 L -1.737 .734 L -1.422 .704 L -.274 .186 L -.129 .213 L -.139 .739 L -.196 -.073 L -.344 .098 L -.344 .171 L -.539 0 L -.663 -.073 L -.834 .221 L -.172 .147 L -.196 0 L -.172 -.319 L -.368 .024 L -.318 .172 L -.074 -.221 L -.049 -.172 L -.122 .024 L -.319 -.123 L -.049 -.147 L -.221 -.024 L -.442 .123 L -.343 .049 L .024 .221 L -.295 .049 L -.393 -.074 L -.073 -.196 L -.147 -.123 L -.368 -.098 L -.49 .147 L -.196 -.073 L -.688 .024 L -.564 0 L -.589 .024 L -.122 -.098 L -.049 -.147 L -.099 -.27 L .099 -.245 L .196 -.196 L .098 .221 L .196 -.074 L -.049 -.196 L .098 -.27 L .123 0 L .981 -.196 L .515 .147 L .516 .196 L .099 .172 L .196 0 L .024 -.246 L .441 -.196 L .302 -.147 L +685.343 114.455 N -.571 .678 L -.309 .115 L -.511 -.096 L -.579 -.068 L -.595 -.011 L -.315 .157 L -.633 .738 L -.283 .256 L -.235 .171 L -.268 -.206 L -.35 .34 L -.319 .199 L -.373 -.608 L -.398 -.112 L -.649 .78 L -.195 -.382 L -.232 -.254 L -.683 -.367 L -.169 -.453 L .095 -.312 L .429 -.411 L .754 -.229 L .056 -.269 L -.591 -.282 L .407 -.879 L .189 -.34 L -.199 -.269 L -.632 -.296 L -.139 0 L -.381 .029 L -.312 .143 L -.234 -.07 L -.52 -.368 L -.167 -.233 L .379 -.528 L .415 -.442 L .52 -.329 L 1.533 -.604 L 1.032 -.545 L .636 -.543 L .686 -1.027 L .386 -.13 L .448 -.017 L .273 .396 L .493 .253 L .508 .153 L .975 -.048 L .527 -.159 L -.046 -.113 L -.508 -.765 L .025 -.342 L .273 -.243 L .392 -.059 L .333 .126 L .452 .054 L .538 -.017 L .62 -.259 L .955 -.532 L .23 -.713 L .383 -.358 L .253 -.129 L .247 -.001 L .579 .68 L .298 .439 L .167 .393 L -1.356 .923 L -.408 .457 L -.112 .414 L .09 .427 L -.154 .456 L -.187 .868 L -.668 .115 L -.36 .229 L -.497 .385 L -.766 .641 L -.468 .214 L -.678 .03 L -.577 .199 L -.265 .228 L -.248 .312 L -.364 .893 L .284 .326 L 1.225 .847 L .419 .354 L +536.625 121.017 N -.078 -.028 L -.15 -.692 L -.01 -.565 L -.038 -.848 L -.185 -.211 L -.787 .075 L -.696 -.01 L -.655 -.506 L -1.803 -1.362 L -.597 -.336 L -.66 -.167 L -.5 -.054 L -.788 -.066 L -.822 -.335 L -.708 -.251 L -.402 -.437 L -1.055 -.107 L -.519 -.054 L -.343 .129 L -.517 .343 L -.333 .03 L -.78 -.038 L -.609 .032 L -.413 .144 L -.476 .328 L -.621 .654 L -.466 .3 L -.562 .13 L -.441 -.025 L -.066 -.376 L -.128 -.681 L -.106 -.447 L .128 -.298 L 0 -.383 L 0 -.532 L .106 -.191 L .106 -.298 L .085 -.234 L -.085 -.212 L -.256 -.128 L -.319 -.191 L -.213 -.255 L -.042 -.149 L -.171 0 L -.191 -.042 L -.361 -.106 L -.191 .192 L -.086 -.234 L .086 -.106 L .148 -.255 L .128 .106 L .383 -.042 L .426 .085 L .128 .021 L .043 -.128 L -.319 -.213 L -.256 -.021 L -.085 -.277 L .17 -.255 L .213 -.191 L -.404 -.042 L -.319 .085 L -.383 0 L -.319 -.085 L -.128 .149 L -.17 -.255 L -.149 -.298 L 0 -.34 L -.042 -.298 L .17 -.213 L .106 -.319 L .043 -.255 L .105 -.277 L .086 -.234 L .213 .34 L .063 .128 L .17 .17 L .405 -.085 L .383 .128 L .106 -.149 L -.021 -.149 L .106 0 L .148 .021 L .064 .319 L .106 .191 L .298 -.021 L .298 -.063 L .256 -.106 L .233 .085 L .192 .064 L .085 -.128 L -.149 -.191 L -.042 -.213 L .191 -.042 L .106 .149 L .233 .085 L .256 -.085 L .213 -.064 L .021 -.234 L -.171 -.341 L -.34 -.234 L -.532 -.319 L -.426 -.213 L -.063 -.319 L -.043 -.34 L -.213 -.17 L 0 -.213 L 0 -.213 L -.085 -.127 L -.554 -.064 L -.617 .085 L -.426 .021 L -.446 .127 L -.192 .277 L -.085 .298 L .128 .192 L -.063 .276 L -.086 .405 L .064 .234 L .021 .298 L -.256 -.553 L -.361 -.319 L .042 -.17 L -.063 -.191 L -.274 -.143 L .529 -.453 L .937 -.532 L 1.277 -.298 L .979 -.085 L .512 .234 L .681 .383 L .617 .383 L .256 .511 L .638 .703 L .447 .255 L .489 -.043 L .341 -.106 L .158 .014 L 1.03 .063 L 1.383 -.032 L .126 -.314 L -.314 -.409 L .062 -.628 L .503 -.409 L .503 -.251 L .629 0 L .283 -.126 L .22 -.346 L .126 -.126 L .283 0 L .597 .283 L -.188 -.377 L -.251 -.251 L .565 -.157 L .188 -.063 L .472 .095 L .629 .377 L .346 .032 L .22 .314 L .692 .095 L .534 .094 L .251 .22 L .032 .22 L 0 .22 L .439 .283 L -.188 .157 L -.031 .188 L .188 .22 L -.157 .188 L -.094 .22 L .691 .314 L .314 .157 L .503 -.094 L .439 -.032 L .535 .126 L .439 -.063 L .188 -.157 L .881 .251 L .22 .377 L .126 .566 L .408 .597 L .283 .188 L .188 .44 L 0 .283 L 1.384 .975 L 1.194 .597 L .377 .44 L 1.006 .503 L .314 -.063 L .943 .597 L .565 .22 L 1.132 .597 L .378 .251 L .471 -.063 L .566 .189 L .534 .283 L .503 .094 L -.062 .22 L -.157 .251 L .062 .503 L -.091 .726 L -1.454 -.244 L -.565 -.294 L -.445 .356 L -.417 .2 L -1.135 .205 L -.432 .809 L -.203 .991 L -.103 .128 L -.508 .243 L -1.985 .689 L -.568 .159 L -.119 .199 L -.001 .466 L -.22 .199 L -.636 .3 L -.534 .031 L -.573 -.082 L -.999 -.348 L -.937 -.193 L -.193 -.112 L +445.294 112.196 N -.07 -.115 L -.138 -.469 L -.5 -.452 L -.966 -.541 L .024 -.141 L .23 .062 L .023 -.237 L -.345 -.414 L .418 -.616 L -.182 -.22 L .188 -.563 L -.251 -.282 L .182 -.396 L .268 -.079 L -.027 -.45 L -.331 -.081 L -.2 -.107 L .002 -.342 L -.133 -.427 L .279 -.515 L .273 -.273 L .727 .11 L .361 .022 L .058 .004 L .382 .369 L .733 .866 L .018 .109 L .035 .218 L -.132 .429 L .074 .641 L .298 .668 L .722 .608 L -.09 .029 L -.449 .842 L -.402 .386 L -.496 .472 L -.583 .884 L +451.512 108.463 N -.507 .16 L -.532 .245 L -.622 -.054 L -.361 -.041 L -.365 .159 L -.395 .429 L -.606 .146 L -.809 .076 L -.722 -.608 L -.298 -.668 L -.074 -.641 L .132 -.429 L -.035 -.218 L .14 .049 L .188 0 L .072 -.087 L .029 -.072 L -.029 -.13 L .058 -.167 L .088 -.058 L .225 -.058 L .246 -.058 L .116 -.058 L .08 -.065 L .087 .073 L .131 .058 L .094 .109 L .116 0 L .029 -.058 L -.059 -.072 L .109 -.058 L .151 -.102 L .152 -.087 L .175 .043 L .064 -.007 L .196 .007 L .152 .015 L .087 -.08 L .131 -.116 L .064 .021 L .102 .043 L .088 -.021 L .087 -.043 L .102 .051 L .058 -.015 L .116 -.022 L .145 -.021 L .16 -.022 L .072 -.029 L .058 .017 L -.007 .106 L .134 .213 L .666 .296 L .358 .383 L .225 .469 L -.006 .499 L -.104 .3 L .047 .199 L +383.93 117.402 N -.249 .101 L -.517 .291 L -.439 .052 L -.548 -.178 L -.58 0 L -.28 -.073 L -.719 .292 L -.058 -.177 L .389 -1.012 L -.021 -.856 L -.182 -.115 L .244 -.542 L -.054 -.397 L .13 -.114 L -.144 -.141 L -.375 .085 L -.476 .097 L -.108 -.449 L .48 -.052 L .283 -.22 L -.042 -.17 L -.178 -.226 L -.3 .417 L -.413 .136 L -.357 -.042 L -.059 -.188 L .198 -.397 L .138 -.616 L -.039 -.303 L .258 -.114 L .403 -.503 L .45 -1.098 L -.12 -.115 L .612 -1.783 L -.35 -.924 L -.007 -.42 L -.146 -.378 L .255 -.271 L .891 -.251 L .55 -.188 L .531 .439 L 1.822 .047 L .531 -.26 L .335 .055 L .272 .227 L .15 .242 L .842 .495 L .062 .242 L -.288 .216 L -1.234 .506 L -.084 .072 L -.051 .442 L .072 .456 L -.132 .983 L .057 .938 L -.043 .199 L -.458 .229 L -.482 .045 L -.288 .129 L .488 .494 L .455 .551 L .163 .198 L -.347 .371 L -.506 .655 L -.17 .455 L .812 .123 L .408 .31 L -.884 .643 L -.242 .37 L -.304 .951 L -.008 .018 L +500.121 117.572 N -.407 -.016 L -.433 .388 L -.164 .126 L -.318 -.105 L -.102 -.269 L .03 -.259 L -.274 -.151 L -.366 -.082 L -.244 .234 L -.343 -.023 L -.811 -.153 L -.364 .032 L -.304 -.16 L -.437 .094 L -.266 .143 L -.23 .043 L -.064 -.245 L -.207 -.023 L -.24 .292 L -.693 .304 L -1.185 .224 L -.711 -.039 L -.747 -.123 L -.439 .073 L -1.498 .673 L -.567 .13 L -1.104 .176 L -.556 -.153 L -1.532 -.444 L -.278 .03 L -.929 .373 L -.746 .075 L -.575 -.025 L -.777 -.166 L -.222 .001 L -.142 -.035 L -.055 .319 L .102 .452 L .243 .423 L -.627 .127 L -.156 .374 L -.2 .169 L -.171 -.041 L -.114 .127 L -.39 -.125 L -.311 .001 L -.245 -.459 L -.119 -.093 L .097 -.175 L .242 -.197 L .617 -.403 L .021 -.175 L -.049 -.134 L -.279 -.28 L -.146 -.053 L -.487 .368 L -.23 .041 L -.137 .064 L .092 .041 L -.118 .216 L -.172 .023 L -.063 -.047 L -.076 .088 L -.297 .058 L -.332 -.222 L -.447 -.198 L -.461 -.157 L -.395 .046 L -.849 .548 L -.337 .286 L .006 .204 L -.141 .046 L -.122 .07 L -.005 .082 L -.179 -.169 L -.604 .206 L -.689 .185 L -.594 -.013 L -.587 -.07 L -.678 -.267 L -.963 -.819 L -1.181 -.479 L -1.034 -.182 L -.692 .072 L -.119 .255 L -.097 .609 L -.053 .411 L -.173 .156 L -.256 0 L -.253 -.155 L -1.12 .243 L -.423 -.027 L -.386 -.183 L -.657 -1.159 L -.42 .354 L -.764 -.451 L -.451 .057 L -.562 .412 L -.227 -.382 L .066 -.127 L .242 -.17 L -.116 -.17 L -.989 -.012 L -.545 -.013 L -.088 -.269 L .571 -.199 L -.074 -.241 L -.284 -.198 L -.454 -.07 L -.084 -.297 L .041 -.34 L .087 -.284 L -.089 -.255 L -.396 -.126 L -.627 -.353 L -.371 .086 L -.265 -.084 L -.004 -.255 L .171 -.501 L .131 .059 L .478 .311 L .567 -.271 L -.396 -.283 L .021 -.124 L -.296 -.128 L .03 -.128 L .571 -.159 L .152 -.113 L -.068 -.142 L -.149 -.088 L -.337 -.035 L .01 -.187 L .18 -.07 L -.163 -.164 L -.198 -.117 L -.009 -.152 L -.227 -.012 L .263 -.181 L .296 -.275 L .161 -.035 L .07 -.16 L -.341 -.042 L -.573 .12 L -.905 .164 L -.166 -.035 L .046 -.33 L .127 -.125 L -.003 -.199 L -.029 -.286 L .13 -.264 L .299 .012 L .184 -.41 L .175 -.023 L .63 -.422 L .514 .012 L .133 -.129 L .479 -.047 L .128 .211 L .268 .102 L .169 .028 L .529 .022 L .147 -.129 L -.067 -.129 L -.269 -.129 L .286 -.094 L .324 .036 L .117 .082 L -.219 .223 L .213 -.026 L 1.053 -.073 L .619 .042 L .379 .046 L .279 .047 L .155 -.176 L -.086 -.094 L -.468 -.035 L -.212 -.118 L .275 -.212 L 1.386 -.151 L .417 -.012 L .377 -.117 L -.442 -.012 L -.592 .023 L -.215 0 L -.068 -.146 L -.611 -.382 L .325 -.528 L .926 .14 L 1.244 .048 L .264 -.117 L 1.086 .321 L 1.051 -.031 L .414 -.243 L -.041 -.27 L .624 -.244 L .455 -.214 L 1.218 -.573 L .598 -.215 L 1.039 -.23 L .889 -.073 L .758 .07 L .905 .126 L .798 .041 L .753 -.372 L .216 .527 L .416 .298 L .278 .099 L .592 .013 L .622 -.144 L .453 .74 L .492 .255 L .574 -.172 L .391 .056 L .968 .582 L 1.265 .04 L 1.094 .197 L .749 -.001 L 1.084 -.272 L .514 -.044 L .651 .141 L .764 .098 L .787 -.016 L .554 -.144 L 1.518 -.573 L .424 -.335 L 1.212 .082 L .491 .068 L .226 -.072 L .761 -.36 L .41 .041 L 1.326 1.018 L .031 .028 L .795 .722 L .026 .199 L -.421 .813 L .033 .412 L .284 .211 L 1.413 .12 L .492 .451 L -.072 .211 L -.409 -.023 L -.231 .141 L -.009 .433 L -.584 .267 L -.039 .27 L .264 .67 L -.122 .375 L .224 .492 L .09 .117 L .106 -.105 L .288 .203 L .039 .207 L -.229 .281 L -.287 .535 L -.06 .128 L .213 .14 L .424 .111 L -.145 .245 L .099 .421 L .42 .374 L .275 .035 L .023 .308 L h 462.617 106.804 m .241 .211 L -.019 .287 L .115 .285 L .077 .071 L .593 .355 L .819 .241 L .605 .155 L .152 .121 L 464.943 109 l -.304 .166 L -.515 -.072 L -.94 -.246 L -.326 .07 L -.209 .152 L -1.019 -.012 L -.357 .384 L -.109 .273 L -.833 .316 L -.612 .282 L -.222 .258 L -.307 .152 L -.268 .293 L -.255 .082 L .164 -.258 L .019 -.141 L -.062 -.176 L .584 -.293 L .22 -.141 L -.226 -.191 L -.082 .015 L -.653 -.056 L -.229 -.148 L .326 -.546 L .387 -.558 L .678 -.631 L -.127 -.227 L -.427 -.197 L -.105 0 L .498 -.445 L .629 -.374 L .497 -.045 L .527 .111 L 1.333 .005 L +509.077 114.955 N -.72 -.317 L -.268 .016 L -.356 -.433 L -.374 -.105 L -.13 -.363 L .532 -.27 L .095 -.222 L -.43 -.176 L -.027 -.188 L .63 -.129 L .094 -.155 L -.061 -.113 L -.487 -.21 L -.351 -.281 L -.306 -.166 L -.456 .234 L -1.058 .492 L -.374 .445 L -.642 .188 L -.254 .255 L -.014 -.027 L .094 -.118 L -.094 -.213 L -.189 -.071 L .26 -.095 L .166 -.047 L -.261 -.189 L -.236 -.236 L .236 -.118 L .095 -.189 L -.283 -.047 L -.354 -.024 L -.284 -.118 L -.213 -.212 L -.236 -.024 L -.26 -.354 L -.283 -.142 L -.048 -.094 L .166 0 L .378 0 L .165 -.236 L 0 -.236 L -.213 -.024 L -.188 -.142 L -.544 -.331 L -.283 -.354 L .047 -.284 L .402 -.142 L -.119 -.236 L -.212 -.166 L -.426 -.071 L -.284 -.095 L .071 -.094 L .071 -.118 L -.284 -.095 L -.087 -.212 L .418 -.308 L .236 0 L .473 .024 L .331 .189 L .189 .213 L .638 .189 L .284 -.047 L .188 .023 L .143 .071 L .26 .189 L .236 -.047 L .236 -.095 L .095 -.331 L -.118 -.213 L -.614 -.166 L -.213 -.307 L -.143 -.26 L .095 -.071 L .143 -.142 L .268 -.189 L .229 -.023 L .023 .166 L .213 -.047 L .189 0 L .142 .189 L .473 .284 L .095 .118 L .118 0 L .283 .284 L 0 .308 L .591 .094 L .449 .142 L .379 -.047 L .165 -.213 L .308 -.331 L .283 -.094 L .496 -.284 L .292 -.449 L .465 .331 L .236 .378 L .26 .189 L .284 .307 L .095 .52 L .142 .236 L .283 .26 L .284 .165 L 0 .166 L .449 .236 L .473 -.047 L .378 .071 L .284 .166 L .236 .189 L .095 .189 L 0 .142 L -.355 -.142 L -.401 -.047 L -.213 0 L -.26 .047 L -.142 .118 L -.402 .071 L -.213 .142 L -.047 .189 L -.023 .473 L -.118 .26 L -.095 .236 L -.095 .378 L .213 .236 L -.023 .189 L -.237 -.071 L -.094 .095 L -.071 .331 L -.071 .26 L -.118 -.047 L -.094 -.236 L -.143 -.095 L -.165 .095 L -.047 .307 L .07 .166 L -.118 .118 L -.118 .095 L .095 .26 L -.363 .91 L h 499.844 111.738 m .709 .061 L .142 -.047 L .26 -.071 L .236 .236 L .071 .166 L .378 .142 L .213 .071 L .308 -.118 L .52 0 L -.071 .213 L .024 .236 L .118 .023 L .331 .166 L -.071 .236 L .421 .763 L -.009 .001 L -.253 -.133 L -.416 .038 L -.512 -.025 L -.421 -.125 L -.335 -.211 L -.294 -.402 L -.551 -.223 L -.281 -.417 L -.265 -.381 L -.252 -.197 L +455.452 122.442 N .049 -.209 L -.057 -.128 L -.812 -.256 L -.691 -.006 L -.506 -.116 L -.484 .017 L -.121 -.046 L -.103 -.093 L .139 -.56 L .315 -.005 L -.005 -.088 L -.009 -.122 L .069 -.07 L .083 .157 L .021 .146 L .303 .021 L .172 .055 L .184 -.076 L -.014 -.082 L .108 -.029 L .157 .105 L -.037 .093 L -.099 .006 L -.04 .053 L .088 .023 L .144 .035 L .094 .046 L .021 .128 L .353 .041 L .846 -.122 L .509 .016 L .035 .13 L .192 .035 L .608 .064 L .307 .051 L .358 -.121 L .09 .05 L -.101 .312 L .163 .11 L .105 0 L .325 -.169 L .286 -.058 L .078 .052 L .154 -.07 L .232 -.146 L -.083 .187 L .015 .186 L -.183 .268 L -.582 -.046 L -.349 .081 L -.335 -.017 L -1.994 .169 L h 445.294 112.196 m .583 -.884 L .496 -.472 L .402 -.386 L .449 -.842 L .09 -.029 L .809 -.076 L .606 -.146 L .395 -.429 L .365 -.159 L .361 .041 L .622 .054 L .532 -.245 L .507 -.16 L .09 -.029 L 1.855 -.195 L .799 -.261 L .584 -.06 L 1.473 .505 L .619 .21 L .388 -.031 L 1.117 -.277 L .086 -.257 L -.097 -.327 L .344 -.216 L .363 .026 L .105 0 L .427 .197 L .127 .227 L -.678 .631 L -.387 .558 L -.326 .546 L -.062 -.407 L -.794 -.056 L -.743 -.041 L -.566 -.125 L -.062 -.144 L -.459 .186 L -.248 .123 L -.403 .012 L -.031 -.247 L -.335 .029 L -.301 .314 L -.431 .186 L -.31 .03 L -.306 -.159 L -.252 .07 L -.004 .133 L .169 .185 L .169 .34 L .308 .059 L .826 .609 L -.166 .07 L -.369 -.258 L -.015 -.105 L -.276 -.082 L -.331 -.105 L -.116 .099 L -.211 .007 L .069 .129 L -.016 .129 L .338 .164 L .145 -.012 L .114 .234 L -.03 .129 L -.245 .023 L -.445 -.457 L -.341 -.141 L -.207 -.059 L -.128 -.012 L .003 .094 L -.075 .035 L .138 .164 L .102 .105 L .154 .141 L .193 .059 L .153 .035 L .103 .094 L -.093 .058 L -.494 -.046 L -.253 -.035 L .035 -.176 L -.137 -.293 L -.164 -.188 L -.401 -.108 L -.472 -.373 L .258 -.118 L .025 -.136 L -.053 -.122 L -.182 -.035 L -.153 .199 L -.465 .176 L .245 .224 L -.25 .371 L -.05 .249 L .13 .121 L .065 .172 L .311 .338 L .133 .036 L .131 .479 L .579 .421 L .359 .467 L -.172 .14 L -.237 .082 L .106 -.187 L -.121 -.187 L -.142 -.128 L -.139 -.035 L -.151 -.047 L -.29 .175 L .102 .188 L .153 .081 L .08 .316 L -.193 .187 L -.652 .141 L .248 .046 L .27 .14 L .391 .058 L .188 .222 L .257 -.012 L .155 .012 L .048 .126 L .367 .269 L .306 .014 L .138 .292 L .282 .012 L .27 0 L .348 .303 L .015 .128 L -.193 .082 L .238 .782 L -.153 .175 L -.185 0 L -.226 -.385 L -.222 -.047 L -.207 -.278 L -.101 -.142 L -.17 0 L -.496 .14 L -.479 .105 L -.184 .128 L .315 .093 L .013 .188 L .007 .291 L .229 .117 L .153 -.026 L .225 -.079 L -.021 .198 L .235 .175 L -.519 .093 L .002 .117 L -.169 .062 L -.309 -.086 L .121 -.21 L -.186 -.086 L -.508 -.056 L -.158 -.092 L -.008 .206 L .194 .453 L .193 .17 L -.045 .163 L .209 .204 L .213 .96 L -.688 -.31 L -.331 .071 L -.298 .439 L -.442 -.735 L -.46 -.367 L -.452 .44 L -.428 -.353 L -.127 -.297 L .212 -.425 L -.028 -.241 L -.215 -.269 L -.491 -.424 L -.167 -.226 L .017 -.17 L .471 -.61 L .609 .098 L .425 -.298 L .202 .042 L 1.668 .663 L .337 -.1 L .483 -.355 L -.266 -.049 L -.27 -.056 L -1.204 -.493 L -1.127 -.083 L -.367 .058 L -.66 .058 L -.427 .143 L -.89 -1.118 L .269 -.1 L .253 .056 L .218 -.114 L .122 -.185 L -.339 -.24 L -.235 .114 L -.496 -.042 L -1.035 -.721 L -.199 -.325 L +504.136 113.458 N -.327 .328 L -.377 .03 L -.421 -.763 L .071 -.236 L -.331 -.166 L -.118 -.023 L -.024 -.236 L .071 -.213 L -.52 0 L -.308 .118 L -.213 -.071 L -.378 -.142 L -.071 -.166 L -.236 -.236 L -.26 .071 L -.142 .047 L -.709 -.061 L -.492 -.451 L -1.413 -.12 L -.284 -.211 L -.033 -.412 L .421 -.813 L -.026 -.199 L -.795 -.722 L .377 -.108 L .307 .024 L .308 -.095 L .426 -.023 L .401 -.118 L .592 .047 L .591 -.095 L .378 -.047 L .291 -.094 L .087 .212 L .284 .095 L -.071 .118 L -.071 .094 L .284 .095 L .426 .071 L .212 .166 L .119 .236 L -.402 .142 L -.047 .284 L .283 .354 L .544 .331 L .188 .142 L .213 .024 L 0 .236 L -.165 .236 L -.378 0 L -.166 0 L .048 .094 L .283 .142 L .26 .354 L .236 .024 L .213 .212 L .284 .118 L .354 .024 L .283 .047 L -.095 .189 L -.236 .118 L .236 .236 L .261 .189 L -.166 .047 L -.26 .095 L .189 .071 L .094 .213 L -.094 .118 L .014 .027 L +566.651 117.4 N -.565 -.153 L -.496 -.054 L -.264 -.151 L -.564 .227 L -.974 .147 L -.137 -.059 L .129 -.176 L -.198 -.077 L -.678 .03 L -.739 .315 L -.592 .486 L -.589 .064 L -.745 .495 L -.351 .03 L -.368 -.026 L -.128 -.084 L -.164 -.409 L -.199 -.521 L .185 -.444 L .099 -.775 L .029 -.255 L -.17 -.187 L -.484 .093 L .156 -.597 L -.576 -.45 L -.153 -.056 L -.384 .016 L -.286 .162 L -.134 .363 L -.435 .428 L -.049 .425 L .006 .255 L -.208 .228 L -.442 .158 L -.133 -.013 L -.587 -.152 L -.292 .058 L -.073 .185 L .007 .311 L -.3 .313 L -.21 .128 L -.381 .016 L -.63 -.237 L -.325 .001 L -.581 .286 L -.58 .343 L -.485 .144 L -.245 -.041 L -.129 -.141 L -.04 -.055 L .375 -.843 L -.063 -.377 L .377 -.377 L .283 -.503 L .503 -.346 L .157 -.22 L -.126 -.283 L -.471 -.314 L -.126 -.409 L .031 -.472 L .126 -.22 L -.126 -.22 L -.346 0 L -.44 -.032 L -.157 -.157 L -.346 -.188 L -.251 -.283 L .125 -.471 L .472 -.283 L .629 .126 L 1.069 .094 L .282 -.188 L .063 -.409 L .251 -.157 L .188 0 L .032 -.346 L .188 -.063 L .251 -.063 L -.126 -.094 L -.534 .031 L -.251 -.125 L .503 -.094 L .565 -.095 L .472 .095 L .062 -.126 L .032 -.346 L -.189 -.314 L .283 -.314 L -.031 -.22 L .346 0 L .22 .157 L .252 .22 L .22 -.157 L .692 -.188 L .471 -.346 L .221 -.251 L .439 .377 L .252 .251 L -.188 .22 L -.409 .346 L -.251 .126 L .126 .188 L .251 .063 L .188 .283 L .409 -.031 L .345 .005 L -.302 .147 L -.441 .196 L -.024 .246 L -.196 0 L -.099 -.172 L -.516 -.196 L -.515 -.147 L -.981 .196 L -.123 0 L -.098 .27 L .049 .196 L -.196 .074 L -.098 -.221 L -.196 .196 L -.099 .245 L .099 .27 L .049 .147 L .122 .098 L .589 -.024 L .564 0 L .688 -.024 L .196 .073 L .49 -.147 L .368 .098 L .147 .123 L .073 .196 L .393 .074 L .295 -.049 L -.024 -.221 L .343 -.049 L .442 -.123 L .221 .024 L .049 .147 L .319 .123 L .122 -.024 L .049 .172 L .074 .221 L .318 -.172 L .368 -.024 L .172 .319 L .196 0 L .172 -.147 L .834 -.221 L .663 .073 L .539 0 L .344 -.171 L .344 -.098 L .196 .073 L -.011 .069 L .023 1.031 L -.207 .223 L .077 .305 L .325 .394 L .463 -.045 L .229 -.162 L .22 .06 L .692 .039 L .273 .154 L .295 .494 L -.009 .284 L .028 .246 L .152 .012 L .049 .123 L -.126 .428 L .245 .237 L -.152 .36 L .2 .163 L -.181 .185 L -.08 .249 L -.354 .136 L +500.121 117.572 N -.023 -.308 L -.275 -.035 L -.42 -.374 L -.099 -.421 L .145 -.245 L -.424 -.111 L -.213 -.14 L .06 -.128 L .287 -.535 L .229 -.281 L -.039 -.207 L -.288 -.203 L -.106 .105 L -.09 -.117 L -.224 -.492 L .122 -.375 L -.264 -.67 L .039 -.27 L .584 -.267 L .009 -.433 L .231 -.141 L .409 .023 L .072 -.211 L .252 .197 L .265 .381 L .281 .417 L .551 .223 L .294 .402 L .335 .211 L .421 .125 L .512 .025 L .416 -.038 L .253 .133 L .009 -.001 L .377 -.03 L .327 -.328 L .254 -.255 L .642 -.188 L .374 -.445 L 1.058 -.492 L .456 -.234 L .306 .166 L .351 .281 L .487 .21 L .061 .113 L -.094 .155 L -.63 .129 L .027 .188 L .43 .176 L -.095 .222 L -.532 .27 L .13 .363 L .374 .105 L .356 .433 L .268 -.016 L .72 .317 L .015 .007 L -.05 .707 L -.143 .581 L .205 .48 L .494 .252 L .925 .235 L .827 .052 L .424 .097 L .162 .282 L .312 .451 L .687 .463 L 1.902 .513 L .841 .052 L .438 -.059 L 1.354 -.262 L 1.192 -.148 L 1.469 -.079 L .41 -.229 L .185 -.354 L -.131 -.905 L .015 0 L .441 .025 L .562 -.13 L .466 -.3 L .621 -.654 L .476 -.328 L .413 -.144 L .609 -.032 L .78 .038 L .333 -.03 L .517 -.343 L .343 -.129 L .519 .054 L 1.055 .107 L .402 .437 L .708 .251 L .822 .335 L .788 .066 L .5 .054 L .66 .167 L .597 .336 L 1.803 1.362 L .655 .506 L .696 .01 L .787 -.075 L .185 .211 L .038 .848 L .01 .565 L .15 .692 L .078 .028 L -.145 .241 L -.084 .339 L -.246 .807 L -.49 1.272 L -.222 .297 L -.596 .384 L -.016 .141 L .119 .663 L .096 .098 L .738 .235 L .026 .183 L -.661 .935 L -.034 .155 L .254 1.085 L .167 1.283 L .143 .775 L .191 .21 L .209 .041 L 1.198 .275 L .401 .167 L .144 .366 L .046 .437 L -.425 .553 L -.853 .795 L -.853 1.034 L .802 1.083 L .71 1.068 L .353 .464 L .695 .391 L 1.144 .388 L .409 .224 L .168 .38 L .111 1.34 L .185 .394 L .652 .053 L .186 .281 L -.036 .974 L -.188 .255 L -.209 .072 L -1 .077 L -.697 .258 L -.794 .47 L -.285 .383 L -.31 .792 L -.049 .354 L -.182 .954 L -.502 .028 L -1.079 -.153 L -.236 -.197 L -.605 -.253 L -.403 -.056 L -1.43 .003 L -.783 -.041 L -.602 .072 L -.475 -.38 L -.163 -.126 L -.835 -.026 L -.576 .001 L -.465 .014 L -.212 -.239 L -.756 -.125 L -.305 -.183 L -.162 -.014 L -.021 -.5 L -.295 -.128 L -.103 -.514 L -.292 -.349 L -.013 -.639 L -.309 -.493 L -.237 .012 L -.035 -.181 L -.526 -.126 L -.807 -.013 L -.374 .017 L -.209 .222 L -.329 .018 L -.517 .075 L -.188 .364 L -.538 .138 L -.383 .443 L -.368 .283 L -.253 .043 L -1.292 -.689 L -.958 -.104 L -.562 -.359 L -1.088 -.317 L -.247 -.301 L -.324 -.282 L -.497 -.592 L -.997 -.436 L -.584 -.083 L -.194 -.028 L -.58 -.465 L -.596 -1.058 L -.635 -1.114 L -.209 -.268 L .005 -.593 L -.767 -.761 L -.506 -.719 L -.921 .143 L -.46 -.042 L -.13 -.126 L -.291 -.056 L -.191 -.268 L -.029 -.565 L -.448 .1 L -.166 .099 L -.32 .678 L -.195 .184 L -.355 .012 L -.014 -.12 L -.351 -.224 L -.686 -.546 L .064 -.212 L -.007 -.395 L -.164 -.465 L -.215 -.013 L -.551 .003 L -.034 -.325 L .055 -.579 L .197 -.622 L .014 -.508 L -.112 -.239 L -.29 -.28 L -.774 -.603 L -.436 -.209 L -1.242 -.925 L -.533 -.025 L -.321 .115 L 503 127.106 l .033 -.819 L -1.02 -.954 L -.312 -.351 L -.002 -.184 L .133 -.875 L .235 -.763 L 1.142 -.98 L -.422 -.761 L .013 -.254 L .468 -.596 L -1.067 -.107 L -.761 -.208 L -.065 -.198 L -.563 -1.086 L -.69 -1.397 L +535.734 133.791 N .853 -1.034 L .853 -.795 L .425 -.553 L -.046 -.437 L -.144 -.366 L -.401 -.167 L -1.198 -.275 L -.209 -.041 L -.191 -.21 L -.143 -.775 L -.167 -1.283 L -.254 -1.085 L .034 -.155 L .661 -.935 L -.026 -.183 L -.738 -.235 L -.096 -.098 L -.119 -.663 L .016 -.141 L .596 -.384 L .222 -.297 L .49 -1.272 L .246 -.807 L .084 -.339 L .145 -.241 L .193 .112 L .937 .193 L .999 .348 L .573 .082 L .534 -.031 L .636 -.3 L .22 -.199 L .001 -.466 L .119 -.199 L .568 -.159 L 1.985 -.689 L .508 -.243 L .103 -.128 L .203 -.991 L .432 -.809 L 1.135 -.205 L .417 -.2 L .445 -.356 L .565 .294 L 1.454 .244 L .096 .016 L .646 .011 L 1.217 .05 L .236 .126 L .351 .48 L .04 .055 L .129 .141 L .245 .041 L .485 -.144 L .58 -.343 L .581 -.286 L .325 -.001 L .63 .237 L .381 -.016 L .21 -.128 L .3 -.313 L -.007 -.311 L .073 -.185 L .292 -.058 L .587 .152 L .133 .013 L .442 -.158 L .208 -.228 L -.006 -.255 L .049 -.425 L .435 -.428 L .134 -.363 L .286 -.162 L .384 -.016 L .153 .056 L .576 .45 L -.156 .597 L .484 -.093 L .17 .187 L -.029 .255 L -.099 .775 L -.185 .444 L .199 .521 L .164 .409 L .128 .084 L .368 .026 L .351 -.03 L .745 -.495 L .589 -.064 L .592 -.486 L .739 -.315 L .678 -.03 L .198 .077 L -.129 .176 L .137 .059 L .974 -.147 L .564 -.227 L .264 .151 L .496 .054 L .565 .153 L -.192 .145 L -.574 -.059 L .01 .269 L .236 .012 L .048 .088 L -.148 .142 L -.358 .004 L -.455 .297 L -.332 -.005 L -.338 .179 L -.647 -.144 L -1.345 .012 L -1.148 .152 L -.53 .292 L -.272 .19 L -.559 .395 L -.246 -.023 L -.258 .214 L -.464 .413 L .01 .32 L .411 .271 L .01 .336 L .232 .171 L -.119 .483 L .198 .477 L -.324 .426 L -.524 .355 L -.4 .341 L -.13 .283 L .223 .478 L .033 .31 L -.289 .255 L -.513 .215 L -.698 -.039 L -.997 -.122 L -.355 .129 L .35 .336 L .365 .407 L .129 .281 L .088 .437 L -.199 .255 L -.315 .115 L -.513 .031 L -.416 .115 L -.292 .228 L -.224 .424 L -.288 .834 L -.139 1.214 L -.021 .084 L -.34 .383 L -.237 .086 L -1.001 -.375 L -.562 -.025 L -.559 .243 L -.362 .271 L -.321 .693 L -.254 .086 L -.516 -.082 L -.644 -.039 L -.283 .072 L -.597 .441 L -.412 .369 L -.188 .34 L -.232 .876 L -.099 .903 L -.069 .184 L -.247 .156 L -1.066 .274 L -1.183 .19 L -.964 .175 L -1.234 .12 L -1.005 -.135 L -.349 .002 L -1.187 .218 L -.742 -.024 L -.541 -.039 L -.854 -.235 L -1.069 -.248 L -.63 -.194 L -.887 -.32 L +486.696 126.295 N 5.257 -2.711 L .589 -2.701 L -.024 -.467 L -.187 -.508 L .009 -.255 L .23 -.355 L .31 -.214 L .866 -.174 L .457 -.371 L .944 -.883 L -.059 -.24 L .23 -.043 L .266 -.143 L .437 -.094 L .304 .16 L .364 -.032 L .811 .153 L .343 .023 L .244 -.234 L .366 .082 L .274 .151 L -.03 .259 L .102 .269 L .318 .105 L .164 -.126 L .433 -.388 L .407 .016 L .69 1.397 L .563 1.086 L .065 .198 L .761 .208 L 1.067 .107 L -.468 .596 L -.013 .254 L .422 .761 L -1.142 .98 L -.235 .763 L -.133 .875 L .002 .184 L .312 .351 L 1.02 .954 L 503 127.106 l .075 .155 L .321 -.115 L .533 .025 L 1.242 .925 L .436 .209 L .774 .603 L .29 .28 L .112 .239 L -.014 .508 L -.197 .622 L -.055 .579 L .034 .325 L .551 -.003 L .215 .013 L .164 .465 L .007 .395 L -.064 .212 L .686 .546 L .351 .224 L .014 .12 L -.096 .003 L -.664 .101 L -.408 -.056 L -.157 .057 L -.103 .127 L -1.271 .044 L -.518 .13 L -.343 .693 L -.463 .609 L -.521 .568 L -4.048 -.132 L -1.557 -.697 L -.812 -.277 L -.118 -.253 L -.047 -.818 L .118 -.396 L -.135 -.366 L -.973 .048 L -.141 -.07 L -.399 -.633 L -.258 -.196 L -2.44 -1.101 L -1.14 -.473 L -2.034 -.934 L -.757 -.222 L -1.129 -.459 L -.093 -.056 L -.093 -.056 L -.311 -.69 L -.87 -1.632 L +479.916 127.377 N -.082 -.085 L .047 -.122 L -.021 -.183 L -.201 -.128 L -.183 -.346 L .398 -.209 L .041 -.099 L .526 -.396 L -.048 -.058 L -.223 -.099 L .077 -.151 L .298 -.25 L .599 -.006 L -.14 -.146 L -.035 -.046 L .078 -.111 L .177 -.163 L .169 -.116 L .299 -.239 L -.068 -.058 L .023 -.163 L -.09 -.047 L -.031 -.221 L -.241 -.157 L -.222 -.058 L .204 -.204 L -.125 -.052 L -.053 -.116 L -.12 .058 L -.335 .052 L -.388 -.023 L -.225 -.564 L .129 -.593 L .072 -.064 L -.1 -.507 L -.42 -.326 L .126 -.093 L .036 -.152 L .117 -.128 L -.093 -.222 L .107 -.012 L .259 -.32 L -.061 -.112 L .311 -.001 L .39 .125 L .114 -.127 L .171 .041 L .2 -.169 L .156 -.374 L .627 -.127 L -.243 -.423 L -.102 -.452 L .055 -.319 L .142 .035 L .222 -.001 L .777 .166 L .575 .025 L .746 -.075 L .929 -.373 L .278 -.03 L 1.532 .444 L .556 .153 L 1.104 -.176 L .567 -.13 L 1.498 -.673 L .439 -.073 L .747 .123 L .711 .039 L 1.185 -.224 L .693 -.304 L .24 -.292 L .207 .023 L .064 .245 L .059 .24 L -.944 .883 L -.457 .371 L -.866 .174 L -.31 .214 L -.23 .355 L -.009 .255 L .187 .508 L .024 .467 L -.589 2.701 L -5.257 2.711 L -.161 .071 L -2.96 1.541 L -1.139 .656 L -.253 .016 L -.365 -.167 L -1.902 -1.034 L +426.068 126.434 N -.093 .981 L .064 .564 L -.093 .269 L -.802 .428 L -.579 .314 L -1.473 1.138 L -.126 .354 L .274 .973 L -.147 .537 L -.155 .227 L -.864 .598 L -.22 .143 L -.564 -1.536 L -.699 -2.242 L -.323 -.464 L -.363 -.252 L -.432 -.181 L -.484 -.831 L -.225 -.465 L -.363 -.28 L -.452 -.097 L -.336 -.774 L -.301 -.888 L .112 -.509 L 1 -.853 L .414 -.355 L .163 -.411 L .048 -.537 L -.052 -.594 L -.026 -.892 L -.012 -1.429 L .114 -.439 L .685 -.627 L .012 -.184 L .508 -.185 L .633 -.455 L .591 -.228 L .703 -.016 L .643 .183 L .247 .212 L .059 .241 L .25 .538 L .27 .084 L .417 -.171 L .584 -.44 L .401 -.17 L .034 .354 L -.265 .567 L -.638 .511 L -.275 .468 L .005 .283 L .202 .438 L .508 .466 L .351 .127 L .303 .848 L -.094 .212 L -.541 .764 L -.59 .34 L -1.017 .92 L -.216 .339 L .287 .451 L .587 .55 L .528 .295 L .284 .056 L .396 -.227 L .316 .084 L .244 .635 L .582 .239 L +381.402 139.704 N -.027 -.876 L .069 -2.006 L .037 -.382 L .686 -.314 L 1.512 -.998 L .963 -.542 L 1.265 .078 L .397 -.059 L .181 -.693 L .864 -.033 L .777 -.174 L .527 -.229 L .524 -.356 L .484 -.652 L 1.109 -.332 L 1.52 -.701 L .129 -.227 L -.296 -.62 L -.025 -.396 L .079 -.227 L .265 -.114 L 1.186 -.12 L .381 -.186 L .309 -.553 L 1.022 .022 L .67 -.018 L 1.826 .004 L .34 -1.033 L -.07 -.211 L -.507 -.322 L 397 126.646 l -.158 -.465 L .016 -1.271 L .022 -.833 L -.165 -.889 L -.189 -.211 L -.563 -.279 L -.259 -.508 L .351 0 L .66 -.143 L .541 -.256 L .369 -.566 L .405 -.312 L .509 -.086 L .407 -.157 L .679 -.27 L .324 .226 L .176 .017 L .249 .024 L .238 -.142 L .407 -.51 L .613 -.426 L .682 -.355 L .614 -.171 L 1.16 -.116 L 1.587 -.06 L .513 -.072 L .634 -.312 L .578 .211 L .564 -.072 L .585 -.313 L .343 -.1 L .939 .012 L .513 -.015 L .307 .056 L .221 .042 L .322 .113 L .816 .168 L .529 -.015 L .772 -.171 L .705 -.2 L .612 -.554 L .994 .508 L .339 .099 L .312 -.143 L .314 -.241 L .228 -.156 L .528 .042 L .388 .197 L .162 .269 L .269 .126 L .516 -.086 L 1.093 -.158 L -.012 .184 L -.685 .627 L -.114 .439 L .012 1.429 L .026 .892 L .052 .594 L -.048 .537 L -.163 .411 L -.414 .355 L -1 .853 L -.112 .509 L .301 .888 L .336 .774 L .452 .097 L .363 .28 L .225 .465 L .484 .831 L .432 .181 L .363 .252 L .323 .464 L .699 2.242 L .564 1.536 L -.204 .156 L -.241 .383 L .88 1.605 L .147 .833 L .052 .691 L -.1 .862 L .101 .748 L -.16 .622 L -.158 .495 L .457 1.156 L -.061 .664 L -.086 .17 L -.666 .47 L -.249 .128 L -.152 .283 L 1.272 1.702 L .249 .917 L .562 .873 L .244 .154 L .544 -.201 L .702 .165 L 1.028 .347 L .178 .168 L .86 1.506 L .098 .07 L -.265 .186 L -1.632 .843 L -4.012 2.241 L -1.607 .956 L -2.308 1.454 L -.834 .655 L -3.084 2.617 L -1.82 .364 L -1.672 .321 L -2.176 .408 L -.146 -.564 L .161 -.679 L -.099 -.522 L -.277 -.352 L -.309 -.111 L -.748 -.024 L -.375 -.167 L -.588 -.562 L -.47 .314 L -.229 -.027 L -1.111 -1.039 L -.393 -.28 L -.082 -.183 L .096 -.396 L -.181 -.253 L -2.472 -1.469 L -.397 -.253 L -1.292 -.824 L -1.924 -1.26 L -3.283 -2.241 L -.811 -.575 L -2.054 -1.344 L -.895 -.531 L -.1 -.084 L -1.414 -.91 L -4.12 -2.42 L -2.829 -1.509 L +395.704 122.189 N .259 .508 L .563 .279 L .189 .211 L .165 .889 L -.022 .833 L -.016 1.271 L .158 .465 L .598 .788 L .507 .322 L .07 .211 L -.34 1.033 L -1.826 -.004 L -.67 .018 L -1.022 -.022 L -.309 .553 L -.381 .186 L -1.186 .12 L -.265 .114 L -.079 .227 L .025 .396 L .296 .62 L -.129 .227 L -1.52 .701 L -1.109 .332 L -.484 .652 L -.524 .356 L -.527 .229 L -.777 .174 L -.864 .033 L -.181 .693 L -.397 .059 L -1.265 -.078 L -.963 .542 L -1.512 .998 L -.686 .314 L -.037 .382 L -.069 2.006 L -1.42 .008 L -1.718 -.004 L -2.677 .001 L -2.511 0 L -1.635 .04 L .141 -.28 L .431 -.411 L .427 -.085 L 1.296 -.285 L 1.143 -.455 L .453 -.312 L 1.147 -.85 L 1.149 -.878 L 1.043 -1.104 L .46 -.693 L .133 -.509 L -.05 -.494 L -.427 -.776 L -.09 -.678 L .099 -.508 L .396 -.636 L .706 -.863 L .211 -.65 L -.063 -.367 L .071 -.353 L 1.285 -1.203 L .724 -.481 L .916 -.327 L 1.266 -.469 L .73 -.397 L .558 -.552 L .537 -.736 L .466 -.905 L .829 -1.925 L .269 -.128 L .54 -.171 L .19 .127 L .684 .848 L .138 .099 L 1.148 .507 L .661 -.001 L .595 .042 L 1.304 -.074 L .522 -.228 L .437 -.27 L .398 .551 L .256 .099 L .798 .097 L .361 0 L +480.248 123.437 N .388 .023 L .335 -.052 L .12 -.058 L .053 .116 L .125 .052 L -.204 .204 L .222 .058 L .241 .157 L .031 .221 L .09 .047 L -.023 .163 L .068 .058 L -.299 .239 L -.169 .116 L -.177 .163 L -.078 .111 L .035 .046 L .14 .146 L -.599 .006 L -.298 .25 L -.077 .151 L .223 .099 L .048 .058 L -.526 .396 L -.041 .099 L -.398 .209 L -.07 -.023 L -.088 .041 L -.067 .193 L -.009 .167 L -.355 .07 L -.07 -.099 L -.151 -.022 L -.372 .051 L .26 -.291 L .097 -.361 L .169 -.227 L .328 -.681 L -.017 -.232 L .181 0 L .138 -.192 L .072 -.32 L .018 -.32 L .409 -.431 L .232 -.07 L .116 -.174 L -.048 -.157 L +184.444 142.729 N -.367 .82 L -.518 .821 L -.186 .763 L -.179 1.159 L .017 1.851 L -.133 1.187 L -.016 1.13 L .564 1.737 L .275 .805 L .624 .945 L .76 .903 L .191 .452 L .481 .521 L .529 .974 L .729 1.228 L .375 .296 L .677 .069 L .436 -.015 L .577 .154 L .593 .451 L .503 .508 L .773 .069 L 1.016 -.242 L 1.55 -.456 L 1.396 -.3 L .803 -.157 L -.02 .542 L .838 .223 L .264 -.286 L .293 -.199 L -.104 -.247 L -.393 -.175 L 1.073 -.62 L .633 -.62 L .086 -.827 L .498 -.429 L -.094 -.477 L .092 -1.145 L .254 -.699 L .625 -.334 L .164 -.043 L .757 -.198 L .701 -.1 L 1.088 -.229 L 1.016 -.37 L .594 -.058 L .499 .056 L 1.139 .181 L .502 -.194 L .378 .093 L .62 .507 L .047 .297 L -.079 .424 L -.298 .382 L -.541 .496 L -.433 .425 L -.317 .445 L -.02 .7 L -.254 .297 L -.188 .354 L .155 .155 L .337 -.138 L -.101 .652 L -.262 1.196 L 205.356 159 l -.062 .24 L -.34 -.534 L -.167 -.452 L -.072 -.155 L -.386 .34 L -.02 .549 L -.437 .016 L -.178 .447 L -.599 .857 L -.386 -.27 L -.278 .095 L .025 .329 L -2.332 -.006 L -1.792 -.005 L -.04 1.24 L -.999 .032 L .396 .223 L .495 .541 L .624 .231 L .359 .69 L .532 .223 L -.211 .683 L -1.762 -.007 L -1.06 .007 L -1.076 1.812 L .305 .397 L -.207 .238 L .054 .553 L .044 .454 L -.704 -.555 L -.952 -.888 L -.956 -.761 L -1.069 -.859 L -.534 -.352 L -.053 -.071 L -.639 -.252 L -1.048 -.21 L -.657 .044 L -.817 .397 L -1.1 .567 L -.756 .256 L -.931 -.069 L -.724 -.21 L -.48 -.197 L -1.305 -.195 L -.588 -.267 L -.644 -.422 L -.935 -.521 L -.785 -.267 L -1.711 -.392 L -.963 -.365 L -.722 -.366 L -1.074 -.436 L -.592 -.352 L -1.123 -1 L -.207 -.07 L -.606 .058 L -.689 -.14 L -1.835 -.575 L -.565 -.536 L -.503 -.634 L -.495 -.395 L -1.049 -.577 L -.619 -.267 L -.5 -.494 L -.742 -.987 L -.363 -.55 L -.038 -.113 L .15 -.155 L .504 -.086 L .18 -.17 L .047 -.184 L -.331 -.367 L .457 -.679 L .041 -.381 L -.172 -.466 L -.744 -.959 L .121 -.297 L .146 -.17 L -.07 -.268 L -.665 -.62 L -1.495 -1.777 L -.546 -.493 L -.963 -1.058 L -.474 -.522 L -.815 -.578 L -.322 -.197 L -.158 -.268 L -.058 -.48 L -.144 -.183 L -.329 -.197 L -.609 -.197 L -.408 -.31 L -.366 -.522 L -.271 -.028 L -.414 .114 L -.238 -.155 L -.163 -.367 L -.005 -.325 L .459 -.736 L -.126 -.339 L -.751 -.62 L -.439 .255 L -.375 -.621 L -.118 -.353 L -.359 -.211 L -.61 -.168 L -.319 -.296 L -.125 -.254 L .05 -.381 L .084 -.269 L -.185 -.226 L -.561 -.21 L -.46 -.098 L -.46 -.253 L -.935 -.86 L -.478 -.706 L -.281 -.551 L -.646 -.832 L -.736 -1.073 L -.184 -.423 L -.38 -.678 L -.242 -.338 L -.152 -.452 L .042 -.509 L .032 -.311 L -.56 -.239 L -.795 -.196 L -.06 -.452 L -.128 -.155 L -.458 -.183 L -.289 .326 L -.251 .043 L -1.43 -.647 L -.285 1.004 L -.045 .438 L .033 .084 L .265 .339 L .264 .296 L .028 1.046 L .088 .509 L .51 .677 L .143 .169 L .643 .267 L .601 .536 L .525 .663 L .602 1.214 L .44 .282 L .328 .042 L .237 .169 L .325 1.398 L .102 .169 L .246 .155 L .497 .056 L .133 .056 L .215 .438 L .161 .65 L .445 .79 L .49 -.071 L .223 -.142 L .245 .452 L .344 1.469 L .531 1.059 L .649 1.2 L .069 .593 L -.014 .522 L .26 .353 L .378 .154 L .389 -.17 L .234 -.198 L .588 .804 L .258 .579 L .464 .253 L .281 .014 L .133 .311 L -.196 .537 L -.136 .127 L -.691 .595 L -.254 -.042 L -.251 -.409 L -.24 -.734 L -.617 -.578 L -.625 -.309 L -.516 -.479 L -.834 -.507 L -1.143 -.986 L -.416 -.451 L -.162 -.269 L .216 -.989 L -.035 -.254 L -.488 -1.002 L -.238 -.381 L -.327 -.282 L -.44 -.098 L -.5 -.31 L -.675 -.677 L -.305 .142 L -.363 -.056 L -1.262 -.746 L -.722 -.31 L -.896 -.973 L -.139 -.127 L -.246 -.254 L .679 .15 L .599 .013 L .588 -.284 L .244 -.326 L .093 -.636 L -.01 -.184 L -.458 -.635 L -.466 -.452 L -1.1 -.888 L -.986 -.493 L -.402 -.338 L -.203 -.522 L -.272 -.649 L -.091 -.155 L -.447 -.126 L -.15 -.353 L -.026 -.594 L -.203 -.395 L -.623 -.734 L -.434 -.706 L -.003 -.254 L .212 -.382 L -.777 -.62 L -.254 -.325 L -.22 -.485 L .34 -.017 L 2.367 -.155 L 2.381 -.084 L .316 .31 L .267 .154 L 1.186 .39 L 2.811 .933 L 3.516 1.112 L .338 .055 L 1.662 .019 L 1.544 .02 L .966 .037 L 1.867 -.011 L .213 -.101 L .096 -.892 L 1.858 .003 L 1.892 .046 L .209 .112 L .631 .662 L .766 .632 L .837 .519 L .708 .491 L .179 .226 L .284 .678 L .318 .847 L .445 .549 L 1.092 .659 L 1.104 .503 L .337 .069 L .501 .011 L .416 -.158 L .283 -.37 L .418 -.413 L .576 -.541 L .468 -.201 L .643 -.018 L .475 .082 L .783 .321 L .412 .252 L .363 .366 L .663 1.029 L .744 1.227 L .845 1.042 L .657 .576 L .268 .253 L .078 .467 L .332 .932 L .336 .592 L .375 .365 L .921 .32 L 1.029 .56 L .264 .069 L .416 -.116 L .296 -.001 L .816 .377 L .347 .119 L +507.047 133.665 N .055 .197 L .134 .691 L -.336 -.028 L -.513 .513 L .421 .194 L .418 -.206 L .306 .021 L .698 1.84 L -.644 .044 L -1.07 -.05 L -.185 -.239 L -.334 -.619 L -.408 -.054 L -1.657 -.259 L .521 -.568 L .463 -.609 L .343 -.693 L .518 -.13 L 1.271 -.044 L +606.155 150.953 N .595 .152 L .255 .14 L .25 -.129 L .273 -.368 L .015 -.678 L -.152 -.93 L .228 -.185 L .401 -.144 L .191 -.354 L -.146 -1.594 L .133 -.283 L .811 .32 L .391 .11 L .309 .013 L .17 -.128 L 1.148 -2.25 L 0 -.324 L -.192 -.408 L .045 -.212 L .938 -1.134 L .136 -.382 L -.057 -.761 L .197 -.354 L 1.446 -.883 L .719 -.512 L .312 -.129 L .558 .082 L .853 .221 L .295 -.058 L -.184 -.718 L .072 -.283 L .596 -.582 L .112 -.24 L .018 -.508 L .001 -.127 L .306 -.34 L .277 -.044 L .504 .279 L .397 .435 L .243 .901 L .217 .309 L .287 .041 L .504 -.031 L .146 .14 L .195 1.649 L .02 .875 L -.353 .862 L -.429 .722 L -.611 .525 L -.487 .271 L -.191 .198 L -.617 .85 L .075 .465 L .163 .705 L -.224 .58 L 0 .268 L .216 .069 L .312 -.086 L .819 -.442 L .771 -.089 L .479 -.017 L .156 .126 L .277 1.762 L .202 .324 L .554 -.074 L .521 .096 L .033 .268 L -.729 1.584 L .117 .352 L .228 .098 L .507 -.003 L .481 -.045 L .291 .379 L .341 .746 L .378 .266 L .246 .083 L .647 -.159 L .628 -.413 L .111 .38 L .153 .239 L -.502 .355 L -.53 .61 L -.442 .581 L -.582 .455 L -.193 .185 L -.08 .085 L -.158 .071 L -.645 .06 L -.436 .172 L -.528 .342 L -.394 .595 L -1.078 .316 L -.62 .018 L -.474 -.082 L -.362 .411 L -.143 .368 L -.036 .819 L -.114 .509 L .064 .409 L -.086 .24 L -.163 .001 L -.588 .131 L .739 .884 L .069 .183 L .112 .875 L .254 .14 L 1.091 .953 L .148 .324 L .646 1.041 L .163 .338 L -.194 .241 L -.451 .229 L -.128 .226 L .231 1.185 L -.171 .198 L -.812 .428 L .178 .38 L .6 1.436 L .54 .477 L .606 .604 L .203 .479 L .088 .663 L -.086 .636 L .006 .254 L .488 1.183 L .586 1.225 L -.077 .297 L -1.011 1.559 L -1.01 1.7 L -.098 .374 L -.359 -.181 L -.075 -.805 L .461 -.665 L .174 -.495 L .122 -.777 L .287 -.466 L -.512 -.027 L -.104 -.084 L -.004 -.282 L .195 -.509 L -.177 -1.524 L -.246 -.832 L -.639 -1.185 L -.488 -1.312 L -.347 -.846 L -.179 -.875 L -.174 -1.736 L -.117 -.677 L -.034 -.564 L -.051 -.212 L -.344 -.084 L -.148 -.098 L -.304 -.917 L -.516 -.677 L -.226 -.225 L -.247 .029 L -.081 .988 L -.158 .424 L -.43 .41 L -.59 .284 L -1.089 .511 L -.359 .622 L -.298 .297 L -.196 .142 L -.237 -.282 L -.007 -.438 L -.212 .015 L -.338 .354 L -.321 -.013 L -.166 -.211 L .147 -.495 L -.001 -.113 L -.621 .171 L -.276 .127 L -.247 .283 L -.355 -.126 L -.002 -.466 L .553 -1.54 L .162 -.791 L .001 -.889 L -.101 -1.059 L -.384 -.973 L -.431 -1.072 L -.196 -.296 L -.281 .537 L -.32 -.126 L -.526 -.366 L .482 -.17 L .312 -.015 L -.149 -.479 L -.054 -.268 L -.684 -.775 L -.182 -.183 L -.19 -.028 L -.407 .1 L -.38 -.267 L .086 -.438 L -.026 -.141 L -.209 -.112 L -.365 .043 L -.577 -.465 L -.504 -.606 L -.117 -.244 L .252 -.341 L .801 -.527 L -.194 -1.607 L +605.297 153.429 N -.126 -.264 L -.269 -.55 L -.223 -1.213 L -.611 -1.41 L -.357 -.395 L -.73 .354 L -.393 0 L -.034 -.084 L -.242 -.211 L -.356 -.592 L -.124 -.042 L -.152 .127 L -.026 .537 L .374 .79 L -.006 .424 L -.143 .169 L -.455 .086 L -.235 .537 L -.261 .1 L -.255 -.437 L -.311 -.395 L -.073 -.057 L -.163 .669 L -.28 .249 L -.203 .043 L -.271 -.536 L -.495 .636 L -.359 -.265 L -.147 -.532 L -.402 -1.775 L -.325 -1.409 L -.352 -.45 L -.04 -.254 L .505 -.765 L .029 -.269 L -.193 -.21 L -1.042 -.431 L -.339 -.323 L .548 -.61 L .4 -.299 L .502 -.13 L .382 -.101 L .047 -.155 L -.126 -.112 L -1.224 -.938 L -.494 -.237 L -.083 -.155 L .124 -.283 L .555 -.525 L .234 -.171 L 1.252 .303 L .339 .266 L .372 .266 L .489 -.06 L .417 .054 L .129 .324 L .053 .479 L .079 .719 L .095 .099 L .537 .109 L .547 .053 L .916 -.062 L .559 -.003 L 2.473 .198 L .111 .098 L .057 .127 L -.012 .79 L -.159 .34 L -.938 .767 L -.498 .13 L -.651 .356 L -.131 .283 L .009 .522 L .001 .381 L .23 .281 L .249 .267 L .529 .448 L .224 -.354 L .395 -1.159 L .281 -.115 L .4 -.044 L .064 .578 L .627 2.479 L .037 .466 L .194 1.607 L -.801 .527 L -.252 .341 L +627.408 186.411 N -.086 .337 L -.495 .35 L -.11 .575 L -.644 .089 L -.05 -.478 L -.309 -.163 L -.279 .28 L -.244 .394 L -.204 -.083 L -.118 -.239 L .213 -.398 L -.041 -.21 L -.055 -.226 L -.261 -.238 L -.447 -.119 L -.106 -.466 L -.571 .013 L -.448 .17 L .013 -.104 L .128 -.297 L -.15 -.183 L -.411 .212 L -.301 -.07 L -.38 -.38 L -.116 -.508 L .064 -.282 L -.151 -.438 L -.229 -.169 L -.388 .043 L -.39 -.719 L -.209 -.508 L -.3 -.324 L -.311 -.155 L -.456 -.395 L -.343 .1 L -.218 .142 L -.216 -.381 L -.04 -.607 L .163 -.749 L .559 -1.738 L .29 -.848 L -.087 -.044 L .098 -.374 L 1.01 -1.7 L 1.011 -1.559 L .077 -.297 L -.586 -1.225 L -.488 -1.183 L -.006 -.254 L .086 -.636 L -.088 -.663 L -.203 -.479 L -.606 -.604 L -.54 -.477 L -.6 -1.436 L -.178 -.38 L .812 -.428 L .171 -.198 L -.231 -1.185 L .128 -.226 L .451 -.229 L .194 -.241 L -.163 -.338 L -.646 -1.041 L -.148 -.324 L -1.091 -.953 L -.254 -.14 L -.112 -.875 L -.069 -.183 L -.739 -.884 L .588 -.131 L .163 -.001 L .086 -.24 L -.064 -.409 L .114 -.509 L .036 -.819 L .143 -.368 L .362 -.411 L .474 .082 L .62 -.018 L 1.078 -.316 L .394 -.595 L .528 -.342 L .436 -.172 L .645 -.06 L .158 -.071 L .08 -.085 L .541 .166 L .295 .182 L .118 .168 L .01 .423 L -.106 .805 L .066 .367 L .186 .154 L .423 -.003 L .489 -.2 L .414 -.045 L .045 .113 L .249 1.311 L -.085 .41 L -.528 1.569 L -.117 .438 L -.027 .494 L .145 .324 L .481 .138 L .37 -.411 L 1.173 -1.178 L .346 -.03 L .835 .348 L .59 .265 L .223 -.072 L .543 -.257 L .2 -.538 L .286 -.453 L .403 .012 L .893 .192 L .266 .153 L .052 .282 L .285 .535 L .688 .659 L .435 .632 L .058 1.524 L .107 .366 L .255 .464 L .979 1.279 L .419 .703 L .157 .507 L .002 .945 L -.121 .438 L -.808 .64 L -.301 -.167 L -.599 -.109 L -.575 -.039 L -.558 .074 L -.798 -.066 L -1.172 .091 L -.383 .101 L -.521 .441 L -.92 1.233 L -.146 .297 L -.076 .382 L .026 .635 L .219 .648 L .487 .717 L .16 .479 L -.146 .176 L -.026 -.063 L -.286 -.183 L -.458 -.084 L -.9 -.887 L -.434 -.154 L -.304 -.014 L -.572 .227 L -.391 -.112 L -.29 -.141 L -.337 -.014 L 0 -.282 L .19 -1.243 L -.107 -.184 L -.719 -.055 L -.248 -.084 L -.521 .043 L -.443 .212 L -.244 .297 L .207 .593 L -.103 .339 L -.318 .707 L .083 .579 L .054 .41 L -.293 .664 L -.583 1.187 L -.7 1.682 L -.255 1.314 L .104 1.171 L .172 .296 L .229 .169 L .55 -.072 L .396 -.142 L .252 .07 L .135 .353 L .009 .325 L -.08 .466 L .141 .282 L .178 .211 L .271 -.094 L .17 .46 L .209 .974 L -.032 .254 L .127 .737 L .434 .871 L .167 .155 L .801 .281 L .539 .112 L .467 -.058 L .294 .197 L .266 .612 L .664 .544 L .212 .145 L +204.31 158.989 N -.175 .412 L .612 -.173 L .026 .429 L -.419 1.241 L .178 .269 L -.237 .795 L .189 .318 L -.092 .397 L -.358 .875 L -.3 .35 L -.36 .032 L -.054 .286 L -.388 .238 L 0 .286 L -.69 .016 L .215 -4.297 L -.025 -.329 L .278 -.095 L .386 .27 L .599 -.857 L .178 -.447 L .437 -.016 L +200.276 169.481 N -.151 -.056 L -.928 -.342 L -.614 .032 L -.766 -.032 L -.608 -.239 L -.909 -.656 L -.513 -.419 L -.044 -.454 L -.054 -.553 L .207 -.238 L -.305 -.397 L 1.076 -1.812 L 1.06 -.007 L 1.762 .007 L .211 -.683 L -.532 -.223 L -.359 -.69 L -.624 -.231 L -.495 -.541 L -.396 -.223 L .999 -.032 L .04 -1.24 L 1.792 .005 L 2.332 .006 L -.215 4.297 L .69 -.016 L .303 .095 L .311 .302 L .14 -.191 L -.066 -.381 L .336 .157 L .458 .367 L -1.507 1.208 L -.499 .238 L -.177 .493 L .162 .604 L -.438 .302 L -.467 .048 L -.043 .254 L .164 .159 L -.351 .111 L -.184 .302 L -.22 -.016 L -.565 .461 L -.012 .223 L +204.413 165.093 N .312 -.03 L .612 -.27 L .639 -.058 L .743 .126 L .478 .069 L 1.443 .04 L .699 -.228 L .379 -.199 L .567 .267 L .788 -.03 L .763 -.101 L .63 -.001 L .5 .126 L .564 .253 L -.038 .353 L -.102 .226 L .228 .282 L .787 .238 L .557 .069 L .244 .524 L -1.425 .486 L -.424 .229 L -.248 .086 L -.463 -.097 L -.328 -.182 L -.259 -.013 L -.294 .242 L -.503 .794 L -1.207 .997 L -.725 -.42 L -.513 .583 L -.882 .034 L -.005 .961 L -.293 .412 L -.29 .143 L -1.001 .125 L -.311 -.661 L -.025 -.085 L -.478 -.3 L .085 -.731 L -.128 -.175 L -.272 0 L -.541 -.276 L -.433 .34 L -.365 -.016 L -.066 -.271 L -.565 -.35 L -.409 -.08 L -.208 -.418 L -.677 -.17 L .438 -.302 L -.162 -.604 L .177 -.493 L .499 -.238 L 1.507 -1.208 L +205.532 170.085 N .035 .076 L -.203 .057 L .01 .265 L -.237 .334 L -.68 -.046 L -.853 -.139 L -1.697 -.505 L -1.305 -.435 L -.325 -.21 L .012 -.223 L .565 -.461 L .22 .016 L .184 -.302 L .351 -.111 L -.164 -.159 L .043 -.254 L .467 -.048 L .677 .17 L .208 .418 L .409 .08 L .565 .35 L .066 .271 L .365 .016 L .433 -.34 L .541 .276 L .272 0 L .128 .175 L -.085 .731 L +242.38 173.617 N -.128 -.105 L -.84 .171 L -.534 .156 L -.414 .2 L -.056 .288 L .048 .497 L -.129 .396 L -.227 -.027 L -.381 .059 L -.99 1.758 L -.172 .722 L -.241 .722 L -.709 1.191 L .402 .025 L .234 -.1 L .384 -.017 L .31 .606 L .855 1.45 L .103 .395 L -.226 1.132 L .099 .353 L .401 .309 L .429 .548 L .397 .252 L .496 -.017 L 1.163 -.12 L 1.167 -.05 L .521 .181 L .64 .321 L .188 .253 L .847 .998 L .554 .576 L .144 0 L .522 -.13 L .76 -.174 L 1.99 -.224 L .644 .081 L -.409 .525 L -.085 1.004 L -.379 .511 L -.147 .326 L .026 .254 L .035 .438 L .048 .367 L .162 .804 L .447 .789 L .256 .437 L .486 .647 L .121 .282 L -.731 .612 L -.479 .526 L .51 .491 L .797 1.182 L -.52 .286 L -.834 .57 L -.412 .158 L -.463 .017 L -2.812 -.082 L -.64 -.024 L -.042 .325 L -.013 1.031 L .178 .154 L .896 .122 L .177 .084 L .293 .408 L .052 .367 L -.384 -.04 L -.417 -.11 L -.687 .032 L -.493 .187 L -.111 .085 L -.001 1.071 L 0 .554 L .192 .197 L .688 .363 L .192 .183 L -.031 .777 L .399 .562 L .031 .212 L -.326 1.428 L -.706 4.411 L -.073 .382 L -.133 .198 L -.156 -.14 L -.575 -.703 L -.237 -.126 L -.161 .058 L -.448 .031 L 1.155 -1.956 L .035 -.198 L -.127 -.069 L -1.299 -.84 L -.509 -.209 L -.708 .442 L -.397 -.182 L -.523 -.421 L -.452 .427 L -.337 .157 L -.496 .031 L -1.038 -.008 L -.573 -.152 L -.092 -.281 L .004 -.396 L -.173 -.296 L -.479 -.039 L -.366 -.14 L -.078 -.282 L -.251 -.761 L -.988 -.672 L -.526 -.364 L -.208 -.62 L -.208 -.324 L -.513 -.435 L -.897 -.418 L -.927 -.107 L -.081 -.112 L -.269 -.162 L -.197 -.118 L -.709 -.631 L -.128 -.056 L -.89 .401 L -.67 .061 L -.977 -.277 L -.355 -.309 L -.166 -.493 L -.227 -.225 L -1.432 -.656 L -1.496 -.803 L .033 -.068 L -.117 -.311 L -.181 -.282 L .108 -.212 L .509 -.114 L .465 .112 L .186 -.325 L -.348 -.564 L .086 -.424 L .314 -.227 L .878 -.058 L .193 .042 L .41 -.227 L .445 -.679 L .45 -.961 L .651 -1.061 L -.122 -.268 L -.56 -.408 L -.071 -.184 L .306 -.721 L .089 -.523 L -.149 -.861 L -.371 -.86 L .085 -.254 L .49 -.143 L .135 -.212 L -.088 -.198 L -.565 -.479 L -.042 -.226 L .103 -.198 L .242 -.326 L .036 -.254 L -.173 -.282 L -.739 -.719 L -.364 -.396 L .256 -.753 L .228 -.082 L -.045 -.45 L .19 .082 L .085 .307 L .584 -.409 L .094 -.43 L .322 -.062 L -.509 -1.038 L -.228 -.149 L -.084 -.327 L .142 .075 L .42 .338 L .397 .507 L .22 .508 L .235 .197 L .199 -.17 L .147 -.241 L -.332 -.776 L .02 -.212 L .176 -.297 L .445 -.34 L .399 -.297 L .501 -.736 L .327 -.156 L .684 -.101 L .217 -.382 L -.104 -.381 L .174 -.777 L .067 -.65 L .207 -.48 L .498 -.439 L .429 -.283 L .592 -.242 L .113 0 L .374 .206 L .22 .443 L .281 -.34 L .031 -.438 L .199 -.551 L .22 -.071 L .267 .126 L .855 .041 L .562 -.001 L .623 -.27 L .237 -.254 L .476 -.298 L .848 -.256 L .435 -.396 L .278 -.551 L .333 -.255 L .469 -.17 L .58 .013 L .526 .338 L .155 .126 L .155 .339 L -.285 .332 L +408.6 174.04 N -.062 .777 L .164 .762 L .388 .718 L -.316 .962 L -.19 .566 L -.223 .298 L -.656 .414 L -.095 .34 L .116 .592 L -.078 .368 L -.433 .13 L -.257 .03 L -.237 .397 L .002 .381 L .003 .48 L -.012 .876 L -.09 .989 L .217 1.439 L -.121 1.188 L .006 .234 L -.333 .015 L -1.232 .144 L -.669 .052 L -.106 -.205 L -.295 -1.072 L .188 -.708 L .026 -.833 L -.036 -.537 L -.135 -.974 L -.006 -.862 L -.035 -.522 L .013 -.579 L -.442 -1.311 L -.164 -.691 L -.403 -.323 L -.468 -.294 L -.18 -.395 L .141 -.594 L .046 -.424 L .062 -.142 L .24 -.157 L .366 -.553 L .415 -.271 L .418 -.045 L .739 .095 L .337 -.158 L .415 -.468 L .237 -.764 L -.131 -.367 L .577 -.3 L .321 -.073 L .339 .28 L .727 .589 L .902 .503 L +394.266 178.814 N .191 -.17 L -.02 -.41 L -.261 -1.934 L .125 -.34 L .271 -.157 L 2.119 -.041 L .867 .037 L 1.429 .006 L .976 -.458 L .161 .032 L .595 .119 L -.25 .849 L .05 .254 L .633 .915 L .244 .451 L -.188 .721 L .02 .396 L .265 1.114 L .181 .592 L .503 .788 L .032 .155 L -.286 .242 L -.174 .382 L .01 1.314 L -.011 .72 L .021 .551 L .18 .479 L .468 .577 L .752 .608 L -.503 .682 L -.304 .099 L -.593 -.013 L -.992 .144 L -.463 .185 L -.188 .098 L -.898 .469 L -1.263 .398 L -.942 .412 L -.958 .567 L -.578 -.324 L -.945 -.436 L -.074 -.124 L -.066 -.741 L -.554 -1.155 L -.263 -.747 L -.103 -.706 L .327 -1.005 L .437 -1.274 L .521 -.851 L .203 -.595 L -.334 -1.438 L -.189 -1.285 L -.178 -.154 L +400.72 175.499 N 1.013 .163 L .611 .166 L .29 .041 L -.046 .424 L -.141 .594 L .18 .395 L .468 .294 L .403 .323 L .164 .691 L .442 1.311 L -.013 .579 L .035 .522 L .006 .862 L .135 .974 L .036 .537 L -.026 .833 L -.188 .708 L .295 1.072 L .106 .205 L -.452 .035 L -.479 .128 L -.368 .212 L -.023 .04 L -.752 -.608 L -.468 -.577 L -.18 -.479 L -.021 -.551 L .011 -.72 L -.01 -1.314 L .174 -.382 L .286 -.242 L -.032 -.155 L -.503 -.788 L -.181 -.592 L -.265 -1.114 L -.02 -.396 L .188 -.721 L -.244 -.451 L -.633 -.915 L -.05 -.254 L .25 -.849 L +383.772 190.418 N .041 -.919 L .105 -.565 L .247 -.849 L .059 -.452 L -.131 -.282 L -1.264 -1.334 L -.592 .032 L -.369 -.097 L -.194 -.183 L -.05 -.183 L .501 -.865 L .059 -.438 L -.119 -.55 L .062 -.17 L .047 -.099 L .602 -.554 L .188 -.354 L -.179 -.21 L -.296 -.549 L .03 -.127 L .158 -.199 L .304 -.03 L .548 .223 L .304 .012 L .19 -.143 L -.051 -.226 L -.648 -.561 L -.309 -.351 L .332 -.37 L .125 -.283 L -.197 -.31 L -.695 -.405 L -.214 -.409 L .264 -.623 L .379 -.397 L .522 -.54 L .352 -.059 L .566 .321 L .455 .436 L .35 -.228 L .362 -.469 L .571 -.483 L .239 -.114 L .257 .041 L .147 .211 L .004 .297 L .117 .381 L .148 .239 L .352 -.059 L .604 -.399 L .159 -.1 L .259 .168 L .545 -.003 L .308 .252 L .15 .465 L .52 .562 L .452 .223 L .354 .083 L .368 -.115 L .446 -.257 L .608 -.159 L .769 -.075 L .644 .166 L .63 .434 L .178 .154 L .189 1.285 L .334 1.438 L -.203 .595 L -.521 .851 L -.437 1.274 L -.327 1.005 L .103 .706 L .263 .747 L .554 1.155 L .066 .741 L -.119 -.201 L -.289 -.197 L -.208 .015 L -.143 .24 L -.096 .042 L -.48 -.027 L -.705 -.167 L -.608 -.083 L -2.352 .062 L -1.279 .243 L -.575 .199 L -1.07 .369 L -1.739 .781 L -.701 .425 L -.256 -.013 L -.075 -.032 L +627.408 186.411 N .035 .024 L .523 .098 L 1.061 1.198 L .693 .916 L .506 .762 L .081 .579 L -.023 .805 L -.134 .862 L .07 1.073 L -.07 .636 L .097 .494 L .196 .381 L .53 .493 L .338 .536 L .705 1.608 L .062 .127 L -.366 -.069 L -.895 -.055 L -.401 .142 L -.175 -.07 L -.521 -.437 L -.885 -.605 L -.6 -.337 L -1.231 -.675 L -1.02 -.732 L -.217 -.254 L -.16 -.988 L -.438 -.691 L -.895 -.817 L -.195 -.663 L .039 -.494 L .03 -.283 L -.107 -.409 L -.399 -.634 L -.347 -1.849 L -.188 -.72 L .043 -.362 L .448 -.17 L .571 -.013 L .106 .466 L .447 .119 L .261 .238 L .055 .226 L .041 .21 L -.213 .398 L .118 .239 L .204 .083 L .244 -.394 L .279 -.28 L .309 .163 L .05 .478 L .644 -.089 L .11 -.575 L .495 -.35 L .086 -.337 L h 643.95 196.042 m .081 .044 L .375 .408 L .397 .141 L .861 .083 L .413 .168 L .761 .436 L .335 .042 L .337 -.1 L -.503 -.535 L .169 -.551 L .365 -.608 L .528 -1.258 L .584 -.27 L 1.481 -.342 L 1.018 -.299 L .428 -.326 L .524 -1.021 L .523 -.323 L .87 -1.117 L .22 -.212 L .244 -.147 L .112 -.068 L .084 .126 L .062 .37 L .234 -.012 L .111 .259 L .309 .271 L .383 -.271 L 1.234 -.42 L -.025 -.086 L -.197 -.197 L .013 -.247 L .024 -.111 L -.148 -.444 L -.11 -.174 L .167 -.042 L .188 .143 L .085 -.016 L .449 -.084 L .161 -.283 L -.036 -.24 L -.478 -.366 L .197 -.396 L .436 -.071 L .511 .041 L .154 -.605 L .408 -.313 L .284 -.48 L .531 -.58 L .498 -1.032 L .075 -.17 L .322 .465 L .33 .098 L .315 -.424 L .305 .494 L .351 .282 L .402 .211 L .075 .338 L -.182 .354 L -.234 .452 L .037 .198 L .631 -.128 L .472 -.128 L .115 .226 L -.349 .495 L .742 -.1 L .357 -.085 L .269 .056 L 1.035 .662 L .345 .14 L .1 .24 L -.158 .269 L -.201 .155 L -.44 .143 L -.594 .029 L -.683 -.083 L -.355 .311 L .096 .254 L .888 .69 L -.161 .311 L -.458 .199 L -.646 .1 L -.518 .114 L -.067 .15 L -.182 -.09 L -.753 -.292 L -.446 -.04 L -.624 .018 L -.651 -.081 L -.748 -.081 L -.464 .017 L -.247 .157 L -.381 .638 L -.119 .565 L .106 .988 L -.22 .383 L -.646 .244 L -.218 .34 L .076 .748 L -.928 1.785 L -.387 .299 L -.864 .175 L -.465 .172 L -.467 .356 L -.287 .03 L -.559 -.152 L -.524 -.223 L -.557 -.251 L -.431 -.11 L -.479 .074 L -.531 .441 L -.403 .525 L -.528 .342 L -.399 .172 L -.543 -.11 L -.526 -.223 L -.255 .001 L -.928 .416 L -.446 -.28 L -.304 -.083 L -1 -.983 L -.253 -.295 L -.288 -.792 L +274.556 195.884 N .06 -.212 L -.332 -.563 L -.49 -1.127 L -.246 -.832 L -.185 -.295 L -.561 -.067 L -.532 -.675 L -.571 -.831 L .328 -.694 L .095 -.467 L -.078 -.777 L .169 -.17 L 1.131 -.091 L .183 -.27 L .082 -.862 L .142 -.496 L .015 -.339 L .326 -.312 L .382 -.057 L 1.392 .463 L .465 .042 L .083 -.41 L .141 -.085 L .337 .027 L .833 .012 L .863 -.03 L .723 .069 L .63 .182 L .999 .427 L -.647 .876 L -.391 .751 L -.137 .594 L .094 .381 L .134 .635 L .086 .664 L .521 .844 L .029 .438 L -.424 1.472 L -.489 .963 L -1.05 -.488 L -.319 .001 L -.534 .385 L -.398 .059 L -.418 -.139 L -.642 -.124 L -.172 .156 L -.2 .326 L .611 1.014 L -.528 -.054 L -1.108 -.276 L -.4 -.04 L +285.859 190.719 N .015 .422 L -1.102 1.646 L -.427 .765 L -.439 .992 L -.464 .681 L -.299 .214 L -.56 -.025 L -1.11 -.389 L -.882 .613 L -.225 -.069 L -.649 -.505 L .489 -.963 L .424 -1.472 L -.029 -.438 L -.521 -.844 L -.086 -.664 L -.134 -.635 L -.094 -.381 L .137 -.594 L .391 -.751 L .647 -.876 L .218 .093 L 1.033 .294 L .55 .196 L .799 .549 L 1.264 1.084 L .545 .564 L .317 .465 L .193 .028 L +429.505 210.684 N -.695 -.533 L -.351 .13 L -.68 .513 L -.536 .414 L -.112 -.177 L -.392 -.86 L -1.381 -1.344 L .184 -.295 L .413 -.229 L .803 .307 L .343 -.681 L -.052 -.296 L -.274 -.253 L -.39 -.521 L -.116 -.366 L .058 -.495 L .127 -.1 L .909 -.146 L .604 -.243 L .125 -.213 L .167 -.807 L .174 -.185 L .239 -.029 L .193 .14 L .341 .479 L .405 .521 L .386 .195 L .287 -.016 L .188 -.228 L .362 -.482 L .29 .253 L .167 .578 L .146 .112 L .304 .068 L .255 -.114 L .184 -.68 L .243 -1.089 L .131 -1.229 L .229 -1.047 L -.114 -.338 L -.161 -.127 L -.384 -.082 L -.528 -.208 L -.242 -.31 L -.132 -.437 L .008 -.109 L .021 -.3 L .157 -.284 L .492 -.398 L .556 -.441 L .094 -.354 L -.389 -.902 L -.369 -.322 L -.592 -.067 L -.939 .5 L -.463 -.025 L -.146 -.253 L -.068 -.734 L .077 -.679 L .396 -.468 L .56 .109 L .863 .023 L .878 -.076 L .271 .055 L .479 .04 L .56 .124 L .576 .194 L .864 .334 L .863 .292 L .271 -.086 L -.1 -.861 L .159 -.185 L .303 -.312 L .365 -.497 L .158 -.523 L .222 -1.287 L .255 -.228 L .479 -.102 L .975 -.175 L .367 .054 L .624 .138 L .895 .093 L .751 -.287 L .128 .197 L -.031 .156 L -.398 1.203 L -.558 .837 L -.349 .821 L -.094 .551 L -.156 .764 L -.196 2.021 L -.254 1.342 L -.115 .61 L -.169 .708 L -.139 .523 L -.459 .427 L -.525 .229 L -.809 .599 L -.41 .454 L -.47 .836 L -.343 .751 L -.193 1.159 L -.074 .396 L .122 .72 L -.086 .706 L -1.025 .938 L -.364 .229 L -.931 .811 L -.554 .399 L -.57 .328 L -.147 -.211 L -.042 -.664 L -.054 -.424 L -1.495 .532 L -.327 .581 L -.443 .271 L -.177 -.013 L -.484 -.336 L +425.506 195.522 N .045 -.495 L .88 .093 L 1.773 .088 L .831 .038 L 1.022 .149 L -.396 .468 L -.077 .679 L .068 .734 L .146 .253 L .463 .025 L .939 -.5 L .592 .067 L .369 .322 L .389 .902 L -.094 .354 L -.556 .441 L -.492 .398 L -.157 .284 L -.021 .3 L -.008 .109 L .132 .437 L .242 .31 L .528 .208 L .384 .082 L .161 .127 L .114 .338 L -.229 1.047 L -.131 1.229 L -.243 1.089 L -.184 .68 L -.255 .114 L -.304 -.068 L -.146 -.112 L -.167 -.578 L -.29 -.253 L -.362 .482 L -.188 .228 L -.287 .016 L -.386 -.195 L -.405 -.521 L -.341 -.479 L -.193 -.14 L -.239 .029 L -.174 .185 L -.167 .807 L -.125 .213 L -.604 .243 L -.909 .146 L -.127 .1 L -.058 .495 L .116 .366 L .39 .521 L .274 .253 L .052 .296 L -.343 .681 L -.803 -.307 L -.413 .229 L -.184 .295 L -.038 -.037 L -.563 -.493 L -.532 -.55 L -.259 -.466 L -1.318 -1.169 L .286 -.312 L -.369 -.281 L -.528 -.056 L -.918 -1.438 L .382 -.297 L .111 -.1 L -.321 -.395 L -.464 -.14 L -.29 -.564 L -.369 -.451 L .319 -.17 L .541 -.411 L .223 -.396 L .291 -.976 L .089 -.295 L .415 .07 L .495 .013 L -.064 -.211 L -.56 -.352 L -.561 -.451 L .208 -.042 L .271 -.128 L .142 -.617 L .83 -.043 L .927 .008 L 1.245 .021 L .575 -.032 L -.001 -.155 L -.02 -.551 L -.026 -1.836 L +422.536 195.513 N 1.005 -.007 L 1.965 .017 L .026 1.836 L .02 .551 L .001 .155 L -.575 .032 L -1.245 -.021 L -.927 -.008 L -.83 .043 L .033 -.146 L -.049 -.297 L -.144 -.084 L -.416 -.098 L .287 -.467 L .447 -.523 L .335 -.58 L .066 -.403 L h 419.636 193.273 m -.484 -.049 L -.049 -.218 L .049 -.291 L .242 -.097 L .024 -.146 L 0 -.291 L .17 -.097 L .169 -.121 L .219 .048 L .218 .048 L .097 .194 L -.193 .169 L -.146 .243 L -.17 .339 L -.146 .267 L +222.291 207.801 N .188 -.126 L .264 -.312 L .585 -1.061 L .038 -.269 L -.209 -.733 L .058 -.391 L -.478 .617 L -.732 .623 L -.333 -.098 L -.601 -.324 L -.408 -.408 L .389 -.283 L .1 -.24 L -.167 -.579 L .005 -.438 L .133 -.466 L -.109 -.282 L -.362 -.649 L .193 -.17 L .48 -.198 L .721 -.454 L -.319 -.395 L 0 -.226 L .175 -.354 L .497 -.462 L .157 -.146 L .14 -.848 L -.116 -.452 L -.082 -.184 L .11 -.226 L .686 -.101 L .891 -.341 L .396 -.241 L .474 -.382 L .09 -.186 L 1.496 .803 L 1.432 .656 L .227 .225 L .166 .493 L .355 .309 L .977 .277 L .67 -.061 L .89 -.401 L .128 .056 L .709 .631 L .197 .118 L .269 .162 L .081 .112 L .387 .76 L .321 .789 L -.08 .255 L -.352 .384 L -.547 1.147 L -.533 .779 L -.71 .725 L -1.001 .755 L -.336 .087 L -1.028 .303 L -.901 .358 L -.809 .499 L -.59 .653 L -.284 .51 L -.987 2.506 L -.267 .312 L -.242 .072 L -.398 -.068 L -.398 -.491 L -.191 -.479 L -.312 -.252 L -.815 .005 L -.444 -.11 L -.105 -.197 L -.097 -.494 L .233 -.34 L .029 -.495 L .005 -.569 L +245.934 224.314 N 1.109 1.843 L .922 1.646 L .08 .24 L -.437 .736 L -.15 .523 L -.143 .848 L .057 .522 L .236 .902 L -.156 .34 L -.221 .34 L -.532 .582 L -.102 .452 L .347 .845 L -.21 .368 L -.159 .34 L .022 .48 L .604 1.168 L .015 .522 L -.285 .439 L -.723 .61 L -.12 .227 L .049 .48 L .132 .295 L .018 .142 L -.586 .187 L -.15 .199 L -.228 .933 L -.259 .298 L -.852 .275 L -.201 -.517 L -.289 -.31 L -1.422 -.618 L -.313 -.239 L -.233 -.678 L -.315 -.38 L -.559 -.225 L -.504 -.281 L -.489 -.254 L -.616 -.309 L -.873 -.464 L -.673 -.366 L -.866 -.379 L -.838 -.337 L -1.271 -.845 L -1.354 -.985 L -1.232 -1.099 L -.594 -.705 L -.42 -.677 L .008 -.438 L 0 -.903 L -.269 -.606 L -.781 -1.043 L -1.389 -2.778 L -.285 -.268 L -.467 -.211 L -.074 -.085 L .055 -.536 L -.02 -.396 L -.149 -.396 L -1.208 -2.199 L -.997 -1.961 L -.688 -1.27 L -1.365 -1.917 L -.272 -.353 L -.598 -.973 L -.462 -.423 L -.75 -.437 L -.914 -.365 L -.61 -.365 L .119 -.17 L .181 -.113 L .609 -.029 L .144 -.41 L -.118 -.282 L -.592 -.874 L -.353 -.437 L -.258 -.72 L .01 -.24 L .244 -.523 L .582 -.622 L 1.02 -.878 L .47 -.198 L .317 -.214 L -.005 .569 L -.029 .495 L -.233 .34 L .097 .494 L .105 .197 L .444 .11 L .815 -.005 L .312 .252 L .191 .479 L .398 .491 L .398 .068 L .242 -.072 L .267 -.312 L .987 -2.506 L .284 -.51 L .59 -.653 L .809 -.499 L .901 -.358 L 1.028 -.303 L .336 -.087 L 1.001 -.755 L .71 -.725 L .533 -.779 L .547 -1.147 L .352 -.384 L .08 -.255 L -.321 -.789 L -.387 -.76 L .927 .107 L .897 .418 L .513 .435 L .208 .324 L .208 .62 L .526 .364 L .988 .672 L .251 .761 L .078 .282 L .366 .14 L .479 .039 L .173 .296 L -.004 .396 L .092 .281 L .573 .152 L 1.038 .008 L .496 -.031 L .337 -.157 L .452 -.427 L .523 .421 L .397 .182 L .708 -.442 L .509 .209 L 1.299 .84 L .127 .069 L -.035 .198 L -1.155 1.956 L .448 -.031 L .161 -.058 L .237 .126 L .575 .703 L .156 .14 L .136 .324 L -.341 .186 L -.793 -.235 L -.493 -.096 L -.322 .072 L -.604 .441 L -.371 .115 L -.669 -.066 L -1.895 .773 L -.701 .442 L -.372 .172 L -.599 1.415 L -.319 .511 L -.021 .155 L .277 .86 L .012 .112 L -.625 .498 L -.62 .328 L -.349 .342 L -.247 .622 L .106 .564 L .619 .957 L 1.333 2.166 L .106 .127 L -.247 .495 L -.208 .312 L 1.085 .12 L .415 .04 L .312 .182 L .241 .323 L .096 .663 L 1.843 .032 L .762 -.499 L .648 -.484 L .326 -.114 L -.059 1.511 L -.098 1.173 L .108 .353 L .317 .337 L .285 .068 L .358 -.072 L .786 -.259 L .42 -.045 L +279.288 257.295 N -.063 -.423 L .027 -.777 L .222 -.819 L .298 -.835 L .321 -.75 L -.019 -.141 L -.491 -.336 L -.234 -.112 L -1.29 .445 L -.224 -.055 L -.254 -.563 L -.487 -2.524 L -.121 -.437 L -.843 -.404 L -.724 -.278 L -.115 .001 L -.709 .413 L -.346 .03 L -.925 -.221 L -.818 -.15 L -.372 -.04 L .006 -.72 L .086 -.721 L .132 -.862 L -.104 -.959 L -.521 -.872 L -.084 -.663 L -.253 -.408 L .421 -.666 L .38 -.765 L .238 -.834 L .185 -1.173 L -.022 -.494 L -.307 -.774 L -.316 -.479 L -.73 -.362 L -.436 -.407 L -.067 -.563 L .261 -.835 L -.042 -.296 L -.693 -.024 L -1.615 -.019 L -.5 -.012 L -.967 -.036 L -.153 -.112 L -.249 -.944 L -.138 -2.032 L -.03 -.706 L -.203 -1.029 L .038 -.565 L -.085 -.169 L -.403 -.237 L -.537 -.166 L -.636 -.123 L -1.148 .077 L -.22 -.084 L -.398 -.308 L -.385 -.774 L -.096 -.014 L -.882 -.037 L -.3 -.098 L -.75 -.603 L -.688 -.307 L -.676 -.25 L -.355 .03 L -.787 -.023 L -.316 -.097 L -1.1 -.939 L -.813 -.928 L -.335 -.591 L -.141 -.635 L -.036 -.818 L .064 -.622 L .079 -.621 L -.045 -.748 L -1.283 -.021 L -.934 .076 L -.36 .158 L -.874 .485 L -1.471 1.109 L -.415 .243 L -.48 -.025 L -.336 -.026 L -.946 .824 L -.355 .03 L -1.122 -.304 L -.939 -.136 L -.42 .045 L -.786 .259 L -.358 .072 L -.285 -.068 L -.317 -.337 L -.108 -.353 L .098 -1.173 L .059 -1.511 L -.326 .114 L -.648 .484 L -.762 .499 L -1.843 -.032 L -.096 -.663 L -.241 -.323 L -.312 -.182 L -.415 -.04 L -1.085 -.12 L .208 -.312 L .247 -.495 L -.106 -.127 L -1.333 -2.166 L -.619 -.957 L -.106 -.564 L .247 -.622 L .349 -.342 L .62 -.328 L .625 -.498 L -.012 -.112 L -.277 -.86 L .021 -.155 L .319 -.511 L .599 -1.415 L .372 -.172 L .701 -.442 L 1.895 -.773 L .669 .066 L .371 -.115 L .604 -.441 L .322 -.072 L .493 .096 L .793 .235 L .341 -.186 L -.136 -.324 L .133 -.198 L .073 -.382 L .706 -4.411 L .326 -1.428 L -.031 -.212 L -.399 -.562 L .031 -.777 L -.192 -.183 L -.688 -.363 L -.192 -.197 L 0 -.554 L .001 -1.071 L .111 -.085 L .493 -.187 L .687 -.032 L .417 .11 L .384 .04 L -.052 -.367 L -.293 -.408 L -.177 -.084 L -.896 -.122 L -.178 -.154 L .013 -1.031 L .042 -.325 L .64 .024 L 2.812 .082 L .463 -.017 L .412 -.158 L .834 -.57 L .52 -.286 L .148 .168 L .138 .437 L .161 .861 L .088 .452 L .199 .437 L .432 .054 L .694 .546 L .482 .223 L .414 -.073 L .757 -.697 L .083 .183 L .186 .776 L .271 -.016 L .645 -.739 L .74 -.654 L .554 -.286 L .652 -.173 L .235 -.213 L .259 -.666 L .203 -.199 L .652 -.131 L .569 -.272 L .265 -.27 L -.15 -.253 L -.434 -.125 L -.96 -.051 L -.166 -.239 L -.079 -.55 L -.302 -1.524 L -.391 -.69 L -.616 -.688 L .041 -.184 L .159 -.029 L .309 .125 L .896 .461 L .385 .04 L 1.149 -.035 L .344 .224 L .628 .618 L .348 -.115 L .232 -1.117 L .284 -.115 L .465 .054 L .557 -.074 L .807 -.23 L 1.74 -.9 L .592 -.385 L .163 -.326 L -.103 -.169 L .375 -.257 L .302 -.058 L .516 .124 L .26 .111 L .04 .212 L -.452 1.09 L .304 -.001 L .533 .138 L .435 .958 L -.179 .368 L -.547 1.416 L -.213 .962 L .156 .465 L .281 .394 L .167 .31 L -.072 .354 L .008 .396 L .15 .296 L 1.103 .897 L .613 .392 L .686 -.075 L .694 -.513 L .505 -.314 L 1 -.331 L .934 -.429 L .943 .022 L .4 .04 L 1.108 .276 L .528 .054 L -.611 -1.014 L .2 -.326 L .172 -.156 L .642 .124 L .418 .139 L .398 -.059 L .534 -.385 L .319 -.001 L 1.05 .488 L .649 .505 L .225 .069 L .882 -.613 L 1.11 .389 L .56 .025 L .299 -.214 L .464 -.681 L .439 -.992 L .427 -.765 L 1.102 -1.646 L -.015 -.422 L .409 -.241 L .276 .141 L .235 .423 L .164 .791 L .414 1.34 L .108 .607 L .472 1.383 L .296 .55 L .324 .324 L .978 .21 L .196 .338 L .038 .551 L -.045 .254 L -.524 .354 L -.933 1.414 L -.238 .325 L -.51 .411 L -.41 .231 L -.244 .138 L -.798 .778 L -.544 .947 L -.419 1.018 L -.402 .453 L .271 .112 L .512 -.072 L .497 -.198 L 1.202 -.709 L .112 -.028 L .299 .889 L .442 .818 L .255 .112 L .287 .07 L 1.135 -.031 L .592 -.058 L .737 -.298 L -.277 .679 L -.017 .584 L .448 -.557 L 1.254 -1.006 L .289 -.156 L .306 -.382 L .499 -.933 L .272 -.396 L .256 -.099 L 1.006 -.003 L .352 -.198 L .175 0 L .687 .549 L .654 .267 L .32 -.028 L .814 .28 L 1.069 .45 L .334 .281 L .269 .593 L .08 .028 L .176 -.015 L .402 -.354 L .319 .042 L .302 .254 L .538 .789 L .205 .396 L -.13 .254 L -.308 .41 L -.116 .424 L .091 .466 L .171 .396 L .825 -.821 L .369 -.156 L .609 -.156 L .995 -.454 L .224 -.028 L .367 .069 L .764 .38 L .907 .436 L .462 .098 L 1.117 .167 L 1.118 .083 L .464 -.058 L .48 -.029 L .577 -.171 L .416 -.016 L 1.131 .351 L .731 .408 L .762 .479 L .586 .437 L 1.595 1.395 L .742 .662 L .821 .605 L .41 .338 L .477 .196 L .734 .168 L 1.247 .097 L .912 .04 L .445 .197 L .265 .465 L .087 .607 L .592 2.004 L .268 1.143 L .062 .988 L -.076 .579 L -.179 .904 L -.243 .848 L -.559 1.301 L -.518 .849 L -1.347 1.175 L -1.388 1.288 L -.44 .198 L -.354 .043 L -.39 .637 L -.094 .396 L -.012 .353 L -.504 1.074 L -.6 .976 L -.8 1.104 L -.266 .212 L -.194 .015 L -.079 -.423 L -.278 -.296 L -.367 -.084 L -.064 .79 L -.538 1.64 L -.049 .734 L -.077 .607 L .318 2.738 L .078 .988 L -.577 2.543 L -.039 .663 L .14 .649 L .043 .085 L -.759 .495 L -.404 .51 L -.261 .791 L -.04 .367 L .245 1.468 L -.106 .367 L -.214 .283 L -.676 .608 L -.752 1.498 L -1.01 1.4 L -.201 .537 L -.055 .311 L .144 .945 L -1.203 .37 L -.544 .283 L -.355 .368 L -.084 .466 L .021 .367 L -.401 .114 L -.864 -.041 L -.979 .172 L -.654 .001 L -.764 -.055 L -.465 -.112 L -.922 .072 L -.736 .002 L -.214 .607 L -.295 .198 L -.795 .312 L -.481 .453 L -.21 .354 L -.747 -.267 L -.35 .071 L -.563 .255 L -1.864 1.232 L -.528 .396 L -.725 .383 L -.616 .438 L -.532 .679 L -.486 .241 L -.567 .072 L -.278 -.014 L .006 .24 L .336 .225 L .12 .536 L -.111 .537 L -.099 .282 L -.282 .156 L -.084 .155 L .384 .648 L .036 1.186 L .05 1.045 L -.057 .311 L -.11 .594 L -.198 .621 L -.464 .735 L -.566 .495 L -.788 .524 L -.866 1.046 L -.208 .396 L -.476 1.145 L -.499 .933 L -.75 1.004 L -.69 .623 L -.801 .78 L .321 -.808 L .436 -.594 L .629 -.566 L .605 -1.158 L -.06 -.254 L -.356 .142 L -.397 -.014 L -.633 -.21 L -.075 .155 L .002 .297 L -.401 1.215 L -.349 .48 L -.661 .438 L -.317 .283 L -.225 .424 L -.013 .354 L -.448 1.709 L -.481 .763 L -.787 .934 L -1.076 .979 L -.101 -.313 L -.258 -.746 L .103 -.269 L .634 -.766 L .017 -.269 L -.333 -.379 L -.163 -.027 L -.131 -.197 L -.853 -1.109 L -.474 -.435 L -.999 -.587 L -.55 -.194 L -.617 -.194 L -.432 -.576 L -.365 -.393 L -.693 .427 L -.27 .016 L -.232 -.38 L -.59 -.814 L -.379 -.407 L -.47 -.364 L -.266 -.098 L -.25 .101 L -1.042 .246 L -.55 .003 L .214 -.27 L .833 -.88 L 1.805 -1.816 L 1.435 -1.363 L 1.633 -1.448 L .348 -.242 L 1.754 -.744 L .521 -.313 L .161 -.467 L .094 -1.638 L -.517 -1.154 L -.206 -.196 L -.462 .017 L -.957 .161 L h 288.966 203.943 m -.558 -.125 L -.301 -.536 L -.078 -.382 L .16 -.197 L -.094 -.636 L .048 -.381 L .208 -1.018 L .176 -.099 L .479 -.058 L .879 .097 L 1.007 .11 L .479 -.199 L .368 .028 L .479 .168 L .479 .083 L .319 .155 L -.335 .538 L -.193 .946 L -.257 .494 L -.289 .312 L -.561 .326 L -.464 .171 L -.527 .015 L -.783 .016 L -.641 .171 L +732.92 214.323 N -.164 -.24 L -.225 -.197 L -.379 -.126 L -.416 .198 L -.399 -.38 L -.287 -.184 L -.659 -.238 L -.243 -.239 L .156 -.255 L .29 .027 L .731 -.058 L .538 .126 L .743 .083 L .523 -.058 L .258 -.185 L .232 -.509 L .056 .099 L .351 .395 L .286 .184 L .241 .014 L .961 -.2 L .366 -.227 L .361 -.722 L .241 -.212 L .653 -.029 L .263 -.128 L .04 -.282 L -.064 -.565 L -.043 -.536 L .495 .196 L .404 .056 L .324 -.354 L .318 .578 L .077 .353 L -.196 .495 L -.099 .184 L -.509 .044 L -.159 .226 L .061 .17 L .437 .479 L -.308 .354 L -.264 .113 L -.742 -.083 L -.416 .001 L -.091 .269 L -.408 .495 L -.275 .156 L -.973 .426 L -.484 .143 L -.798 .029 L -.807 .115 L h 713.795 220.696 m .031 -3.438 L -.046 -.805 L -.431 -1.368 L .44 -.822 L -.169 -7.966 L 2.581 .802 L .85 .337 L 1.04 .295 L 1.254 .378 L .848 .507 L .613 .323 L .597 .084 L .38 -.058 L .26 .508 L .274 .254 L .635 .352 L .687 .395 L .779 .718 L -.3 .947 L .033 .226 L .305 .226 L .665 .111 L 1.887 .787 L .354 .027 L .72 .183 L .181 .254 L .413 .535 L .211 .579 L -.166 .113 L -1.114 .073 L -.563 .156 L -.098 .155 L .047 .339 L .589 .987 L .5 .521 L 1.464 1 L .218 .847 L .725 1.044 L .288 .141 L .304 -.015 L .712 -.086 L .338 .013 L .087 .198 L -.354 .551 L .218 .212 L .401 .141 L .423 .041 L .63 .168 L .096 .127 L -.031 .142 L -.648 .213 L .287 .24 L 1.064 .28 L .538 .295 L .235 .763 L -.064 .226 L -1.094 -.012 L -.215 -.154 L -.146 -.466 L -.126 -.099 L -1.011 -.111 L -1.063 -.266 L -.644 -.126 L -.752 .016 L -.774 -.026 L -.573 -.211 L -.494 -.352 L -.223 -.522 L -.24 -.268 L -.726 -.31 L -.472 -.338 L -.135 -.197 L -1.089 -1.608 L -.613 -.817 L -.454 -.056 L -1.524 -.336 L -.671 -.31 L -.55 -.055 L -.415 .185 L -.394 .071 L -.78 -.45 L .282 .762 L -.027 .212 L -.249 .071 L -.382 -.126 L -.311 .1 L .296 .395 L -.116 .113 L -1.037 .045 L -1.125 -.182 L -.478 .029 L .237 .127 L .24 .154 L .642 .169 L .662 .352 L .404 .338 L .219 .395 L -.411 .199 L -.739 .425 L -.458 .213 L -.668 -.097 L -1.801 -.039 L -1.219 -.092 L +726.605 297.247 N -.479 -.229 L -1.179 -.471 L -.543 -.371 L -.508 -.715 L -.477 -.558 L -.216 -.414 L .264 -.044 L .169 .1 L .421 .171 L .129 -.143 L -.209 -.387 L -.703 -.699 L -.617 -.713 L -.149 -.257 L -.375 -.956 L -.008 -.67 L .177 -.044 L 1.004 .312 L 1.476 .354 L 1.089 .369 L .797 -.03 L .463 -.144 L .382 -.115 L .373 -.058 L .684 .027 L .306 -.301 L .716 -.244 L .475 .385 L -.009 .1 L .128 .8 L -.009 .686 L -.751 1.503 L -.124 .758 L -.245 .315 L -.943 .26 L -.553 .388 L -.49 .689 L -.189 .272 L -.274 .072 L h 716.883 224.344 m .682 .394 L .233 .509 L .047 .649 L .118 .678 L .256 .197 L .42 .013 L .102 .24 L -.45 .919 L .715 .338 L .175 .282 L .147 .593 L .08 1.3 L .144 .621 L .456 1.157 L .293 .268 L .422 .014 L .328 -.312 L .384 -.185 L .32 .663 L .363 .127 L .563 .408 L .385 .154 L .144 .155 L .002 .41 L .083 .96 L .275 .776 L -.046 1.06 L .279 .24 L .93 1.325 L .276 .706 L .055 .777 L -.209 .876 L .403 .649 L .275 .833 L .204 .353 L 1.395 .803 L .285 .154 L .744 .111 L .402 .649 L .843 .535 L .483 .169 L 1.141 .068 L .117 .197 L 731 245.42 l -.273 .565 L .309 .424 L .879 .479 L .22 .564 L .469 1.342 L .211 .748 L .112 .396 L .252 .311 L .771 .352 L -.021 -.127 L -.141 -.777 L .913 .507 L .567 .154 L .184 .127 L .136 .296 L .106 1.752 L .884 .762 L .573 .323 L .604 .154 L .287 .296 L .244 .579 L .229 .424 L .545 .168 L .176 .297 L .007 .269 L .19 .536 L .106 .113 L .506 .126 L .156 .112 L .162 .354 L .366 1.327 L .026 .876 L .013 .862 L -.132 .41 L -.181 .325 L .778 1.271 L .223 .48 L .181 .833 L .034 .749 L -.293 .708 L -.353 1.668 L -.585 1.755 L .137 .791 L -.065 .806 L -.306 .778 L -.661 .977 L -.203 .665 L -.598 .821 L -.45 .185 L -.465 .1 L -.423 .468 L -.466 .68 L -.328 1.527 L -.477 .638 L -.34 .495 L .014 .65 L -.208 .539 L -.331 .312 L -.601 .341 L -.27 .326 L -.3 1.021 L -.169 1.049 L -.079 .937 L .021 .666 L -.283 .64 L -.322 .354 L -.463 .3 L -.754 .101 L -1.158 .087 L -.82 .03 L -.527 .157 L -.516 .299 L -1.529 .94 L -.443 .129 L -.214 .284 L -.346 .071 L -.528 .059 L -.286 -.014 L .295 .368 L .209 .27 L -1.315 -.665 L -.885 -.353 L .003 -.469 L -.073 -.156 L -.56 -.467 L -.628 -.368 L -.421 -.014 L -.485 .172 L -.335 .242 L .748 .467 L -.97 .243 L -.929 .428 L -.953 .442 L -.222 .028 L -.604 -.226 L -.886 -.438 L -.67 -.226 L -1.086 -.311 L -.51 -.041 L -.239 .156 L -.044 .113 L -.716 -.169 L -.751 -.353 L -.522 -.298 L -.896 -.82 L -.526 -.34 L -.422 -.879 L .09 -1.035 L -.082 -.411 L -.184 -.495 L -.664 -.736 L -.141 -.523 L -.029 -.425 L -.534 -.014 L -.786 .398 L -.597 .114 L -.34 .058 L -.178 -.07 L -.167 -.17 L .517 -.454 L .233 -.567 L .073 -.821 L -.253 -.324 L -.536 -.593 L -.247 -.353 L -.485 .735 L -.443 1.431 L -.19 .113 L -.796 .002 L -.199 .156 L -.196 .015 L -.255 .028 L .198 -.396 L .081 -.396 L .079 -.1 L .634 .041 L .242 -.142 L .126 -.255 L -.105 -1.004 L .454 -.835 L .328 -.453 L .091 -.396 L .018 -.409 L .151 -.128 L .245 -.015 L .218 -.354 L -.052 -.227 L -.323 -.494 L -.338 -.494 L -.107 .707 L -.288 .255 L -.518 .299 L -.311 .467 L -.086 .155 L -.189 .467 L -.281 .326 L -.747 .242 L -.735 .481 L -.653 .567 L -.36 .693 L -.514 .808 L -.41 -.339 L -.38 -1.328 L -.263 -.579 L -.19 -.325 L -.688 -.79 L -.297 -.734 L -.176 -.212 L -.704 .072 L -.235 -.099 L -.139 -.24 L -.085 -.269 L .334 -.34 L -.047 -.297 L -.346 -.395 L -.543 -.494 L -.266 -.098 L -.83 .157 L -.486 -.07 L -.95 -.549 L -.274 -.014 L -.438 .17 L -.433 -.027 L -.421 -.183 L -.662 -.521 L -.921 -.437 L -.218 .001 L -.723 .213 L -1.282 .088 L -.669 .001 L -1.764 .061 L -.611 .129 L -.656 .213 L -.989 .44 L -.972 .256 L -1.039 .257 L -1.503 .088 L -.794 -.013 L -.383 .044 L -.927 .284 L -.993 .469 L -.773 .397 L -.538 .143 L -.431 .085 L -.361 .199 L -.615 .693 L -.774 1.02 L -.588 .284 L -.766 -.013 L -.547 -.013 L -.927 .143 L -.4 .185 L -.663 -.395 L -.294 -.084 L -.734 .016 L -1.572 .173 L -.938 .157 L -.459 -.041 L -.672 .044 L -.398 .227 L -.583 .793 L -.344 .128 L -.958 -.125 L -.158 .057 L -.57 .708 L -.465 .368 L -.919 .271 L -.586 .086 L -1.516 -.082 L -.638 -.055 L -.688 -.197 L -.633 -.366 L -.778 -.677 L -.74 -.353 L -.374 -.041 L -.151 -.07 L -.19 -1.229 L .055 -.255 L .489 .112 L .45 -.086 L .332 -.425 L .197 -.467 L .267 -1.357 L -.043 -1.215 L -.156 -.622 L -.258 -.593 L -1.117 -1.906 L -.208 -.635 L -.144 -.834 L .027 -.989 L -.16 -.692 L -.467 -1.072 L -.663 -.945 L -.603 -.734 L -.214 -.254 L .128 -.904 L -.215 -.536 L -.733 -1.115 L -.972 -1.018 L -.273 -.583 L .126 -.233 L .188 .187 L .152 .443 L .183 .163 L .235 .35 L .327 .188 L .354 .023 L -.348 -1.144 L -.437 -.396 L -.226 -.326 L .08 -.304 L .748 .84 L .495 .979 L .477 .065 L -.099 -.555 L .289 -.039 L .004 -.564 L -.282 -.48 L -1.03 -1.368 L -.354 -.691 L -.119 -.579 L -.038 -.734 L .355 -.595 L .323 -.523 L .21 -.664 L -.083 -1.031 L -.254 -.635 L .033 -.368 L .438 -.692 L .109 -.325 L .064 -.156 L .271 .649 L .011 .424 L .105 .184 L .35 .027 L .171 -.113 L .187 -.565 L .141 -.48 L .765 -.468 L 1.22 -.624 L .484 -.326 L .676 -.581 L .585 -.467 L .632 -.327 L .79 -.114 L .697 -.016 L .7 -.002 L .431 -.043 L .352 -.185 L .474 -.453 L .494 -.128 L .929 -.072 L .279 -.143 L .291 -.551 L .158 -.1 L .444 .027 L .877 .224 L .626 -.043 L .911 -.299 L 1.084 -.469 L .359 -.213 L .716 -.665 L .427 -.58 L .29 -.622 L .132 -.297 L .41 -.369 L .968 -.651 L .079 -.17 L -.067 -.409 L -.242 -.805 L -.016 -.495 L 1.063 -1.118 L .387 -.692 L .291 .169 L .341 .437 L .619 1.355 L .262 .253 L .177 -.579 L .021 -.466 L .436 .238 L .272 .07 L .189 -.607 L -.06 -.142 L -.563 -.238 L -.175 -.24 L .007 -.565 L .044 -.112 L .897 .04 L .661 .253 L .642 -.029 L .334 -.029 L .289 .074 L -.699 -.455 L -.431 -.141 L .128 -.537 L -.07 -.296 L .135 -.509 L .422 -.354 L .165 -.07 L .732 .394 L .202 -.043 L -.112 -.452 L .11 -.48 L .146 -.367 L -.041 -.522 L .358 -.171 L .4 -.113 L .813 .04 L .529 -1.088 L .371 -.298 L .35 .169 L .268 .451 L .265 -.552 L .222 -.227 L .197 -.48 L .695 .62 L .513 .084 L .293 .211 L .331 .536 L .632 .592 L .122 .706 L -.072 .594 L .181 .197 L .256 -.283 L .462 -.679 L .155 -.128 L 1.16 .082 L .479 .155 L .637 .492 L .332 .141 L .156 -.48 L .302 -.297 L .022 -.24 L -.266 -.324 L -.601 -.395 L -.079 -.184 L .008 -.24 L .145 -.099 L .604 -.538 L .007 -.452 L .191 -.213 L .518 -.283 L .268 -.241 L .151 -.269 L -.094 -.184 L .003 -.296 L .512 -.863 L .121 -.057 L .317 -.029 L .397 -.029 L .248 -.17 L -.205 -.409 L .377 -.396 L .344 -.071 L .793 .366 L .616 -.072 L 1.291 -.088 L .512 -.128 L .232 -.17 L .04 -.057 L -.077 -.197 L -.2 -.734 L -.248 -.282 L -.471 -.268 L -.374 .086 L -.244 -.141 L .035 -.212 L .367 -.143 L .396 -.043 L .617 .521 L .255 .099 L .34 -.1 L .364 .31 L .676 .465 L .36 .154 L 1.297 .294 L .591 .084 L .413 -.143 L .372 .014 L .396 .606 L .419 .112 L .141 -.029 L .562 -.438 L .454 .027 L .652 .38 L .331 .479 L .46 -.143 L .122 -.791 L .181 -.085 L .455 .465 L .337 .099 L .152 .154 L -.436 .411 L -.126 .424 L -.176 .212 L -.011 .438 L -.12 .255 L -.513 .015 L -.51 .228 L -.396 .34 L -.004 .551 L .301 .353 L -.187 .692 L -.381 .58 L -.559 .481 L -.155 .48 L .063 .17 L .469 .437 L 1.038 .619 L .81 .677 L .508 .606 L .246 .099 L .349 -.114 L .264 .027 L .782 .352 L .742 .465 L .434 .451 L .679 .535 L .335 .127 L .442 .027 L .784 .182 L .25 .184 L .218 .621 L .167 .169 L .507 .31 L .76 .423 L .537 .154 L .422 -.072 L .414 -.17 L .603 -.199 L .208 -.156 L .736 -1.344 L .403 -1.131 L .194 -1.314 L .259 -.721 L .43 -.679 L -.131 -.424 L -.409 -.621 L .022 -.311 L .236 -.637 L .187 -.48 L -.164 -.282 L -.183 -.395 L .088 -.692 L .104 -1.004 L .225 -.297 L .329 -.156 L .158 -.311 L -.534 -.521 L .033 -.198 L .576 -.947 L .312 -.934 L .072 -.833 L .191 -.241 L .279 -.297 L +270.934 276.123 N .054 -.338 L -.194 -.577 L .011 -.522 L .24 -.495 L .48 -.524 L .118 -.325 L -.168 -.986 L -.049 -.847 L .103 -.522 L .595 -2.359 L .065 -.452 L .443 -.524 L .55 -.003 L 1.042 -.246 L .25 -.101 L .266 .098 L .47 .364 L .379 .407 L .59 .814 L .232 .38 L .27 -.016 L .693 -.427 L .365 .393 L .432 .576 L .617 .194 L .55 .194 L .999 .587 L .474 .435 L .853 1.109 L .131 .197 L .163 .027 L .333 .379 L -.017 .269 L -.634 .766 L -.103 .269 L .258 .746 L .101 .313 L -.059 .053 L -.803 1.103 L -.625 .552 L -.775 .454 L -.441 .156 L -.818 .1 L -.874 -.337 L -.551 .044 L -.551 .114 L -.64 .283 L -.38 -.042 L -.846 -.676 L -.637 -.252 L -.76 -.154 L -.469 .128 L -.507 .072 L -.327 -.127 L -.548 -.563 L -.354 -.159 L +418.763 73.869 N .391 -.499 L .389 -.262 L .283 .081 L .663 -.062 L .762 -.075 L .324 -.137 L .891 -.787 L .979 -.2 L .224 .025 L .198 -.219 L .175 .032 L -.349 .531 L .11 .106 L .026 .481 L -.288 .156 L -.17 .368 L -1.675 .069 L -.376 -.106 L -.428 .031 L -.14 -.062 L -.239 .081 L -.275 .031 L -.153 .417 L -.249 .218 L -.353 .118 L -.08 .112 L -.229 -.155 L -.411 -.292 L h 421.68 78.002 m -1.839 .129 L -.116 -.016 L .064 -.404 L -.19 -.638 L -.174 .015 L -.36 -.293 L -.233 .184 L -.398 -.172 L .2 -.355 L .434 -.293 L -.007 -.181 L -.445 -.541 L .018 -.256 L .131 -.498 L .279 -.106 L .318 .15 L .495 .12 L .43 -.574 L .299 -.091 L .296 .437 L .391 -.046 L .022 -.528 L .107 -.363 L 1.032 -.017 L .848 .089 L .03 .544 L .187 .301 L 1.138 .058 L .14 .166 L -.307 .604 L -.565 .142 L -.119 -.261 L -.331 .031 L -.263 .136 L .121 .278 L -.184 .414 L -.312 .077 L -.069 .244 L -.635 .035 L .157 .229 L -.291 .094 L -.191 .24 L -.061 .285 L .003 .21 L -.215 .338 L .166 .084 L h 427.177 77.967 m -.139 -.149 L -.312 -.344 L -.405 .031 L -.665 -.059 L -.123 -.329 L -.285 -.66 L .433 -.091 L .603 -.467 L .356 .495 L .521 .179 L .2 -.271 L .078 -.586 L .333 -.046 L .459 .044 L .056 .571 L -.134 .36 L -.144 .09 L -.413 .286 L .603 .299 L -.285 .166 L -.499 .39 L -.238 .09 L +417.259 94.301 N -.135 -.233 L .216 -.701 L -.091 -.076 L .075 -.295 L .321 -.372 L .054 -.358 L .054 -.213 L .954 -.806 L -.605 -.193 L -.479 .014 L -.456 -.09 L -.095 -.186 L -.233 -.007 L -.072 .048 L -.689 .062 L -.045 -.145 L -.395 .055 L -.337 -.277 L -.428 -.319 L -.074 -.353 L .248 -.144 L .044 -.288 L -.466 -.096 L -.41 -.312 L -.062 -.301 L .422 -.376 L -.038 -.468 L -.282 -.365 L -.344 -.177 L .165 -.278 L -.143 -.217 L -.182 -.037 L .08 -.097 L .235 -.133 L .236 -.133 L -.193 -.121 L .201 -.275 L .095 -.148 L -.152 -.292 L -.082 -.265 L -.376 -.182 L .07 -.182 L .341 -.078 L .175 -.092 L .378 .134 L .664 -.151 L .32 -.152 L .128 -.376 L .412 -.207 L .003 -.328 L -.16 -.17 L -.188 .061 L -.44 -.134 L .029 -.184 L .113 -.181 L .571 .036 L .084 -.401 L .345 -.361 L -.151 -.438 L .066 -.147 L -.465 -.192 L .126 -.43 L .285 -.181 L .371 -.028 L 1.12 -.062 L .293 -.012 L .095 .16 L .195 .271 L -.155 .158 L .324 .113 L .148 -.068 L .042 -.192 L -.159 -.204 L .259 .012 L .437 .169 L -.163 -.362 L .247 -.419 L .687 .113 L .614 -.091 L -.596 -.17 L -.084 -.227 L .282 -.102 L -.252 -.114 L -.12 -.147 L .166 -.08 L .068 -.136 L -.675 .08 L -.06 -.182 L .664 -.125 L .218 -.193 L -.464 -.42 L -.324 -.341 L .045 -.28 L .116 .016 L 1.839 -.129 L .254 .13 L .565 .341 L .271 .297 L -.02 .228 L -.252 .175 L .445 -.05 L .171 .216 L .157 -.078 L .283 .021 L .235 .156 L .45 .073 L .866 -.121 L .077 .208 L -.07 .149 L -.057 .125 L -.665 .295 L .316 .193 L .649 -.136 L .113 .182 L .457 -.006 L .349 -.391 L 1.059 -.136 L .602 -.234 L .757 -.266 L .249 .113 L .396 -.17 L .184 .182 L .085 .159 L .634 .29 L .182 .074 L .526 -.12 L .156 .12 L .059 .34 L .036 .227 L .154 .102 L .354 .125 L .372 -.022 L .028 .13 L .201 .025 L .319 .835 L -.219 .52 L -.391 .147 L -.051 .328 L .391 .102 L .683 .429 L -.217 .395 L .094 .18 L .312 .146 L -.021 .304 L .131 .102 L -.118 .292 L -.214 .124 L -.007 .191 L .325 .27 L -.114 .258 L .468 .188 L .281 .485 L -.435 .698 L -.142 .115 L -.344 -.072 L -.031 -.278 L -.308 -.121 L -.436 .072 L .282 .218 L -.254 .084 L -.284 .097 L -.524 .048 L -.124 .169 L -.735 .024 L -.112 .217 L -.176 -.072 L -.358 .061 L -.097 .229 L -.382 .012 L -.078 .181 L -.442 0 L -.422 .201 L -.293 -.033 L -.26 .181 L -.243 .168 L .037 .056 L .258 .378 L .413 .098 L -.155 .25 L -.08 .406 L .159 .085 L .036 .233 L .244 .173 L .478 .265 L .188 -.072 L .573 .515 L .431 .17 L .184 .201 L .219 -.084 L .165 .18 L .207 .036 L .447 .633 L -.682 .26 L -.437 -.151 L -.132 .027 L -.039 .337 L -.162 .172 L -.968 .295 L -.364 .227 L .538 .571 L -.197 .295 L .334 .014 L .056 .158 L -.098 .343 L -.082 .055 L -.441 -.178 L .049 -.165 L -.146 -.117 L -.564 .062 L -.195 -.138 L -.433 .035 L -.092 .178 L -1.25 .035 L -.125 .171 L -.319 .014 L -.044 .13 L 425.4 94.7 l -.594 .021 L -.059 -.144 L -.093 -.145 L -.493 -.089 L -.262 .055 L -.237 -.041 L .032 .274 L -.452 .343 L -.215 0 L .078 -.195 L -.26 -.039 L .011 -.165 L -.194 -.048 L -.104 -.137 L -.249 -.007 L -.096 -.11 L -.164 .137 L -.368 -.014 L -.664 -.261 L -.852 -.007 L -.149 -.089 L -.199 .014 L -.017 -.151 L -.709 .199 L .179 .199 L -.354 .021 L -.278 -.11 L -.567 .158 L -.271 -.096 L -.272 .117 L -.271 -.089 L h 432.012 80.473 m -.171 -.038 L -.088 -.049 L -.447 .08 L -.111 -.264 L .002 -.213 L .647 .281 L .168 .203 L +450.734 91.05 N -.831 -.33 L -.424 -.101 L -.104 -.216 L -.703 -.186 L -.129 -.13 L -.561 .076 L -.508 -.041 L -.073 .137 L -.373 .18 L -.46 -.254 L -.483 .046 L -.168 -.056 L -.558 .204 L -.104 .177 L -.149 .135 L -.18 -.12 L -.389 .083 L -.003 -.204 L .026 -.083 L -.066 -.18 L -.331 .025 L -.073 -.169 L -.194 -.24 L -.261 .024 L -.062 .112 L -.193 -.016 L -.183 .24 L -.43 .048 L -.03 -.228 L -.285 -.041 L -.105 -.331 L -.382 -.096 L -.188 -.208 L .02 -.249 L -.802 -.132 L -.311 -.181 L -.368 .161 L -.293 -.013 L -.013 -.221 L .001 -.253 L -.329 .084 L .181 -.283 L -.709 .005 L -.258 -.121 L -.509 -.193 L -.286 -.024 L -.003 .145 L .282 .302 L -.41 .12 L -.22 .187 L -.318 -.072 L -.296 -.38 L -.55 -.247 L .224 -.211 L .208 -.024 L .099 -.121 L -.199 -.181 L -.257 -.024 L -.061 .066 L -.466 .066 L .005 -.169 L -.278 .037 L -.132 -.181 L -.568 -.054 L -.201 -.025 L -.363 -.163 L -.093 -.26 L -.211 -.091 L -.361 .018 L -.063 .084 L .062 .073 L -.024 .151 L -.375 0 L .435 -.698 L -.281 -.485 L -.468 -.188 L .114 -.258 L -.325 -.27 L .007 -.191 L .214 -.124 L .118 -.292 L -.131 -.102 L .021 -.304 L -.312 -.146 L -.094 -.18 L .217 -.395 L -.683 -.429 L -.391 -.102 L .051 -.328 L .391 -.147 L .219 -.52 L -.319 -.835 L .34 .043 L .23 .125 L -.093 -.193 L .156 -.153 L -.019 -.147 L -.166 -.13 L -.021 -.129 L -.012 -.075 L .93 -.154 L .431 -.051 L .516 -.152 L 1.304 -.128 L .48 -.158 L .797 -.479 L 1.117 -.298 L 1.515 -.303 L 1.382 -.086 L 1.067 .417 L -.882 -.294 L -.054 .147 L .256 .172 L .132 .466 L .355 .135 L .648 .061 L .645 -.11 L 1.063 -.409 L .054 .004 L -.978 .417 L -.19 .11 L -.004 .123 L .218 .012 L .286 -.123 L .613 -.208 L .543 -.253 L .842 .006 L 2.246 .115 L 2.96 -.101 L .641 -.021 L .04 .014 L .679 .243 L .284 .487 L .099 .186 L .016 .029 L .09 .171 L .16 .302 L .615 1.5 L .172 .502 L -.023 .236 L -.263 .208 L -.44 .03 L -.571 .244 L -.291 .328 L -.128 .292 L .289 .012 L .421 .146 L .149 .176 L .218 .146 L .013 .25 L -.315 .752 L .126 .137 L .161 .175 L -.074 .242 L .816 .835 L .316 .193 L -.298 .048 L -.085 .133 L .328 .302 L -.009 .314 L -.255 .24 L -.429 .013 L -.286 .181 L -.599 .398 L -1.509 1.218 L -.082 .306 L .044 .552 L .349 .383 L -.653 -.018 L h 431.844 80.27 m .232 .024 L .069 .208 L -.134 -.029 L -.168 -.203 L h 432.739 80.361 m -.03 .129 L -.278 -.024 L -.191 .03 L -.046 -.208 L .174 -.012 L .266 0 L .106 .085 L +416.488 81.945 N .151 .438 L -.345 .361 L -.084 .401 L -.571 -.036 L -.113 .181 L -.029 .184 L .44 .134 L .188 -.061 L .16 .17 L -.003 .328 L -.412 .207 L -.128 .376 L -.32 .152 L -.664 .151 L -.378 -.134 L -.175 .092 L -.341 .078 L -.07 .182 L .376 .182 L .082 .265 L .152 .292 L -.095 .148 L -.201 .275 L .193 .121 L -.236 .133 L -.235 .133 L -.08 .097 L .182 .037 L .143 .217 L -.165 .278 L -.672 .024 L -.001 -.338 L .172 -.097 L .11 -.423 L -.754 -.375 L -.535 .109 L -.292 -.375 L -.228 -.061 L -.173 .121 L -.313 -.242 L -.267 .182 L -.307 0 L -.307 -.012 L .025 .157 L -.52 .034 L -.407 -.042 L -.477 -.098 L -.07 -.162 L -.496 -.264 L .795 -.472 L .858 -.621 L .273 -.354 L .563 -1.167 L .173 -.104 L .644 -.12 L .367 .251 L .136 .268 L -.28 .203 L -.228 -.056 L .066 .496 L -.191 .124 L 1.163 .225 L .225 -.236 L .406 -.113 L .134 -.417 L -.458 -.022 L -.123 -.124 L -.02 -.203 L .236 -.158 L -.171 -.023 L -.558 -.067 L .072 -.328 L -.034 -.13 L -.023 -.034 L .128 -.283 L .572 -.198 L .709 -.238 L .654 .03 L 1.089 -.151 L .245 .275 L .329 .045 L .076 .181 L .259 0 L +431.57 91.965 N -.447 -.633 L -.207 -.036 L -.165 -.18 L -.219 .084 L 430.349 91 l -.431 -.17 L -.573 -.515 L -.188 .072 L -.478 -.265 L -.244 -.173 L -.036 -.233 L -.159 -.085 L .08 -.406 L .155 -.25 L -.413 -.098 L -.258 -.378 L -.037 -.056 L .243 -.168 L .26 -.181 L .293 .033 L .422 -.201 L .442 0 L .078 -.181 L .382 -.012 L .097 -.229 L .358 -.061 L .176 .072 L .112 -.217 L .735 -.024 L .124 -.169 L .524 -.048 L .284 -.097 L .254 -.084 L -.282 -.218 L .436 -.072 L .308 .121 L .031 .278 L .344 .072 L .142 -.115 L .375 0 L .024 -.151 L -.062 -.073 L .063 -.084 L .361 -.018 L .211 .091 L .093 .26 L .363 .163 L .201 .025 L .568 .054 L .132 .181 L .278 -.037 L -.005 .169 L .466 -.066 L .061 -.066 L .257 .024 L .199 .181 L -.099 .121 L -.208 .024 L -.224 .211 L .55 .247 L .296 .38 L .318 .072 L .22 -.187 L .41 -.12 L -.282 -.302 L .003 -.145 L .286 .024 L .509 .193 L .258 .121 L .709 -.005 L -.181 .283 L .329 -.084 L -.001 .253 L .013 .221 L .293 .013 L .368 -.161 L .311 .181 L .802 .132 L -.02 .249 L .188 .208 L .382 .096 L .105 .331 L -.071 -.012 L -.065 .066 L -.066 .04 L -.105 -.026 L 442 89.998 l -.119 .013 L -.065 .04 L -.132 .066 L -.053 .079 L -.118 .092 L -.119 .053 L -.132 .079 L -.105 .013 L -.118 .013 L -.053 .092 L -.026 .092 L -.026 .132 L -.053 .079 L -.053 .105 L -.145 .066 L -.105 .04 L -.092 -.026 L -.079 .079 L -.04 .092 L -.053 .079 L -.039 0 L -.105 .026 L -.066 .026 L -.079 .053 L -.118 .053 L -.132 0 L -.145 .04 L -.093 .026 L -.065 -.026 L -.065 -.026 L -.093 0 L -.065 .026 L -.158 0 L -.132 -.053 L -.092 -.053 L -.093 .026 L -.171 .053 L -.026 .04 L -.146 .119 L -.092 .066 L -.014 .131 L -.065 .105 L -.039 .044 L -.055 -.095 L -.545 -.2 L -1.332 .181 L -1.019 -.227 L -1.374 -.341 L -.746 .773 L -.598 .163 L -.483 -.099 L -.354 -.129 L -.145 -.014 L +421.683 94.397 N .368 .014 L .164 -.137 L .096 .11 L .249 .007 L .104 .137 L .194 .048 L -.011 .165 L .26 .039 L -.078 .195 L .215 0 L .452 -.343 L -.032 -.274 L .237 .041 L .262 -.055 L .493 .089 L .093 .145 L .059 .144 L 425.4 94.7 l .377 -.103 L .044 -.13 L .319 -.014 L .125 -.171 L 1.25 -.035 L .092 -.178 L .433 -.035 L .195 .138 L .564 -.062 L .146 .117 L -.049 .165 L .441 .178 L .082 -.055 L .098 -.343 L -.056 -.158 L -.334 -.014 L .197 -.295 L -.538 -.571 L .364 -.227 L .968 -.295 L .162 -.172 L .039 -.337 L .132 -.027 L .437 .151 L .682 -.26 L .145 .014 L .354 .129 L .483 .099 L .598 -.163 L .746 -.773 L 1.374 .341 L 1.019 .227 L 1.332 -.181 L .545 .2 L .055 .095 L .053 .093 L -.097 .581 L .155 .26 L .761 .547 L -.636 .291 L -.019 .367 L -.701 .054 L -.164 -.134 L -.325 0 L -.223 .197 L .452 .063 L .136 .196 L -.157 .206 L -.409 .062 L -.04 .375 L .204 .188 L -.154 .294 L -.346 .299 L -.693 .157 L .082 .393 L -.89 -.116 L -.298 .196 L -.85 -.08 L -.566 .107 L -.646 .5 L -.287 -.152 L -.612 .009 L -.179 -.107 L -1.04 -.065 L -.478 -.112 L -.894 -.082 L -1.311 -.247 L -.32 -.391 L -.318 -.096 L -.023 -.363 L -.856 .227 L -.301 -.103 L -.445 .11 L -.183 -.083 L -.366 .096 L -.329 .411 L -.597 -.034 L -.631 -.171 L .029 -.171 L -.215 -.117 L -.579 .332 L -.55 -.242 L -.008 -.144 L -.622 -.062 L .09 -.192 L -.214 -.288 L .266 -.274 L -.193 -.336 L +431.763 171.063 N -.067 .354 L .091 .72 L .108 .508 L .225 .168 L .562 .11 L .144 .183 L .077 .353 L -.089 1.116 L -.146 .227 L -.274 .171 L -.885 .217 L -.291 .256 L -.664 1.275 L -.503 1.203 L -.243 1.004 L -.354 .129 L -.369 .03 L -.129 .354 L -.146 1.229 L -.192 .312 L -.385 .045 L -.257 .284 L -.417 .836 L -.944 2.223 L -.304 .624 L -.352 .496 L -.368 .355 L -.239 .114 L -.145 -.056 L -.722 -.97 L -.145 -.14 L -1.104 -.05 L -.272 .03 L -1.31 1.265 L -.941 .839 L -.495 .526 L .02 .974 L -.189 .552 L -.376 .686 L -.188 -.119 L -.224 -.042 L -.176 -.127 L -.145 .212 L .144 .296 L -.063 .127 L -.353 .198 L -.56 .03 L -.977 .101 L -.607 -.267 L -.288 .043 L -.271 .368 L -.177 .113 L -.432 -.07 L -1.247 -.011 L -.528 -.225 L -.543 -.451 L -.416 -.72 L -.192 -.649 L .048 -.254 L .208 -.254 L -.144 -.296 L -.513 -.069 L -.128 -.254 L -.464 -.55 L -.561 -.465 L -.608 -.253 L -.641 -.253 L -.272 -.31 L -.513 .072 L -.24 .297 L -.336 .071 L -.881 .044 L -.659 .03 L -.006 -.234 L .121 -1.188 L -.217 -1.439 L .09 -.989 L .012 -.876 L -.003 -.48 L -.002 -.381 L .237 -.397 L .257 -.03 L .433 -.13 L .078 -.368 L -.116 -.592 L .095 -.34 L .656 -.414 L .223 -.298 L .19 -.566 L .316 -.962 L -.388 -.718 L -.164 -.762 L .062 -.777 L .092 -.961 L .158 -.849 L .353 -.482 L .687 -1.614 L .676 -.4 L 1.064 -.188 L 1.174 -.108 L 1.111 .121 L .821 .277 L 1.095 1.223 L .209 .098 L .37 -.002 L 1.337 -.544 L .467 -.116 L .354 .083 L 1.173 .742 L .965 .277 L .934 -.005 L .273 -.059 L .629 -.399 L .403 -.327 L .774 -.287 L .628 -.103 L .709 -.047 L .531 .04 L .884 .221 L .724 .193 L .609 .208 L .259 -.058 L .761 -.697 L .453 -.299 L .437 -.2 L .951 -.034 L .173 .394 L .575 .52 L .351 .407 L +425.506 195.522 N -1.965 -.017 L -1.005 .007 L .029 -.176 L -.208 -.536 L .271 -.989 L -.159 -.72 L -.191 -.522 L -.399 -.649 L .433 -.396 L -.287 -.367 L -.24 -.056 L -.576 .058 L -.559 -.268 L -.176 -.324 L -.063 -.537 L -.111 -.211 L -.527 -.14 L -.101 -.064 L .376 -.686 L .189 -.552 L -.02 -.974 L .495 -.526 L .941 -.839 L 1.31 -1.265 L .272 -.03 L 1.104 .05 L .145 .14 L .722 .97 L .145 .056 L .239 -.114 L .368 -.355 L .352 -.496 L .304 -.624 L .944 -2.223 L .417 -.836 L .257 -.284 L .385 -.045 L .192 -.312 L .146 -1.229 L .129 -.354 L .369 -.03 L .354 -.129 L .243 -1.004 L .503 -1.203 L .664 -1.275 L .291 -.256 L .885 -.217 L .274 -.171 L .146 -.227 L .089 -1.116 L -.077 -.353 L -.144 -.183 L -.562 -.11 L -.225 -.168 L -.108 -.508 L -.091 -.72 L .067 -.354 L .627 .109 L .208 .083 L .923 1.238 L .395 .887 L .119 1.2 L -.134 .651 L .169 1.228 L .205 .578 L .381 .633 L .208 .21 L .047 .127 L -.225 .143 L -.674 .032 L -1.187 -.191 L -.481 -.082 L -.24 .1 L -.29 .312 L -.323 .539 L 1.088 1.067 L 1.343 1.179 L .638 1.07 L .382 1.057 L .208 .183 L -.208 .114 L -.354 .327 L -.866 1.743 L -.4 .511 L -.528 .399 L -.144 .198 L -.064 .424 L .112 .776 L .273 1.185 L .207 .592 L .4 .661 L .432 .605 L .064 .791 L .112 .324 L 1.217 1.236 L .498 .802 L .194 .804 L .209 .451 L -.159 .185 L .1 .861 L -.271 .086 L -.863 -.292 L -.864 -.334 L -.576 -.194 L -.56 -.124 L -.479 -.04 L -.271 -.055 L -.878 .076 L -.863 -.023 L -.56 -.109 L -1.022 -.149 L -.831 -.038 L -1.773 -.088 L -.88 -.093 L -.045 .495 L +551.793 147.278 N -.788 -.111 L -.458 -.253 L -.379 -.367 L -.248 -1.101 L -.112 -.141 L -.342 -.141 L -.662 -.083 L -.105 -.07 L -.014 -.268 L .116 -.466 L -.178 -.451 L -.418 -.38 L -.294 -.013 L -1.181 .412 L -1.229 .087 L -.81 .143 L -.947 .073 L -.415 -.083 L -.263 -.226 L -.135 -.197 L -.909 .143 L -.548 .382 L -.856 .016 L -1.264 -.011 L -.691 .128 L -.723 .115 L -.541 .03 L .182 -.954 L .049 -.354 L .31 -.792 L .285 -.383 L .794 -.47 L .697 -.258 L 1 -.077 L .209 -.072 L .188 -.255 L .036 -.974 L -.186 -.281 L -.652 -.053 L -.185 -.394 L -.111 -1.34 L -.168 -.38 L -.409 -.224 L -1.144 -.388 L -.695 -.391 L -.353 -.464 L -.71 -1.068 L -.802 -1.083 L .887 .32 L .63 .194 L 1.069 .248 L .854 .235 L .541 .039 L .742 .024 L 1.187 -.218 L .349 -.002 L 1.005 .135 L 1.234 -.12 L .964 -.175 L 1.183 -.19 L 1.066 -.274 L .247 -.156 L .069 -.184 L .099 -.903 L .232 -.876 L .188 -.34 L .412 -.369 L .597 -.441 L .283 -.072 L .644 .039 L .516 .082 L .254 -.086 L .321 -.693 L .362 -.271 L .559 -.243 L .562 .025 L 1.001 .375 L .237 -.086 L .34 -.383 L .021 -.084 L .139 -1.214 L .288 -.834 L .224 -.424 L .292 -.228 L .416 -.115 L .513 -.031 L .315 -.115 L .199 -.255 L -.088 -.437 L -.129 -.281 L 556.193 125 l -.35 -.336 L .355 -.129 L .997 .122 L .698 .039 L .513 -.215 L .289 -.255 L -.033 -.31 L -.223 -.478 L .13 -.283 L .4 -.341 L .524 -.355 L .324 -.426 L -.198 -.477 L .119 -.483 L -.232 -.171 L -.01 -.336 L -.411 -.271 L -.01 -.32 L .464 -.413 L .258 -.214 L .246 .023 L .559 -.395 L .272 -.19 L .53 -.292 L 1.148 -.152 L 1.345 -.012 L .647 .144 L .338 -.179 L .332 .005 L .455 -.297 L .358 -.004 L .148 -.142 L .313 .14 L .105 .112 L .281 -.21 L .296 .047 L .554 .117 L .004 .456 L .282 -.128 L .625 -.009 L .373 .323 L .213 .247 L .007 .501 L -.312 .516 L .301 .07 L .198 .218 L .252 .281 L .52 -.196 L .239 0 L .104 .199 L .178 .09 L .565 .436 L 1.337 .104 L .305 .111 L .147 .126 L -.207 .084 L -.688 .37 L -.411 .232 L -.155 .43 L -.071 .479 L -.234 .116 L -.125 -.179 L -.621 -.102 L -.438 .132 L -.271 .298 L -.262 -.116 L -.557 .265 L -.928 -.149 L -.568 -.138 L -1.708 -.325 L -.894 .265 L -.38 .611 L .09 .166 L .336 0 L .047 .314 L -.202 .149 L .101 .199 L .598 -.017 L -.002 .347 L -.384 .099 L -.139 .413 L .389 .232 L -.116 .479 L -.215 .132 L .089 .248 L .606 .298 L -.003 .532 L .782 -.003 L -.039 .43 L .188 .248 L .702 -.05 L .668 .377 L .012 .211 L -.2 .255 L -.504 .2 L -.643 .196 L -.517 .248 L .032 .366 L .188 .377 L -.237 .977 L -1.512 1.503 L .261 .38 L -.358 .281 L -.609 .133 L -.353 .467 L -.509 1.216 L -.478 .547 L -1.193 .496 L -.177 .364 L -.277 .481 L -.563 .61 L -.076 .38 L -.71 .259 L -.734 -.011 L -.895 .314 L -.361 -.094 L -.158 -.518 L -.207 -.132 L -.404 .083 L -.535 .463 L -.144 .446 L -.979 .893 L -.186 .543 L -.079 .269 L .116 .38 L .541 .163 L .504 .085 L .425 .014 L -.114 .689 L -.154 .735 L .412 .411 L .33 .099 L .537 -.099 L .112 .441 L .216 .507 L .654 1.333 L -.232 .149 L .241 .463 L -.317 .066 L -.15 .248 L -.55 .083 L -.145 -.335 L -.183 -.062 L -.78 .215 L -.2 .331 L -.735 -.099 L -.229 -.149 L -.835 -.021 L -.835 -.009 L -.259 -.052 L .015 .728 L -.866 .017 L -.296 .431 L -.37 .036 L +606.155 150.953 N -.037 -.466 L -.627 -2.479 L -.064 -.578 L -.4 .044 L -.281 .115 L -.395 1.159 L -.224 .354 L -.529 -.448 L -.249 -.267 L -.23 -.281 L -.001 -.381 L -.009 -.522 L .131 -.283 L .651 -.356 L .498 -.13 L .938 -.767 L .159 -.34 L .012 -.79 L -.057 -.127 L -.111 -.098 L -2.473 -.198 L -.559 .003 L -.916 .062 L -.547 -.053 L -.537 -.109 L -.095 -.099 L -.079 -.719 L -.053 -.479 L -.129 -.324 L -.417 -.054 L -.489 .06 L -.372 -.266 L -.339 -.266 L -1.252 -.303 L -.234 .171 L -.555 .525 L -.124 .283 L .083 .155 L .494 .237 L 1.224 .938 L .126 .112 L -.047 .155 L -.382 .101 L -.502 .13 L -.4 .299 L -.548 .61 L .339 .323 L 1.042 .431 L .193 .21 L -.029 .269 L -.505 .765 L .04 .254 L .352 .45 L .325 1.409 L .402 1.775 L .147 .532 L -.172 .322 L .068 .183 L -.321 .071 L -.35 -.056 L -.148 -.706 L -.198 -.084 L -.253 .354 L -.171 .354 L -.172 .057 L -.115 -.099 L -.28 -.592 L -.152 -.169 L -.412 .537 L -.504 .298 L -.992 .397 L -.571 .213 L -.264 .226 L -.05 .113 L .106 .579 L .183 .409 L -.336 .495 L -.305 .332 L -.013 .257 L -.548 .415 L -.593 .467 L -.467 .185 L -.432 .057 L -.746 .206 L -.591 .362 L -.459 .58 L -.551 .552 L -.88 1.061 L -.611 .552 L -.673 .276 L -.675 .829 L -.676 .467 L -.728 .368 L -.452 .241 L -.427 .312 L -.192 .509 L -.073 .466 L -.341 .41 L -.649 .298 L -.428 .058 L -.506 -.098 L -.258 .269 L -.366 .887 L -.277 .23 L -.505 -.253 L -.614 .142 L -.354 .283 L -.304 .565 L -.165 .48 L -.005 .508 L .166 1.539 L .018 .805 L -.208 .495 L .227 .324 L .315 .423 L -.015 .508 L -.199 .607 L -.669 1.611 L -.341 .834 L -.13 .636 L .047 .649 L .21 1.764 L -.081 .24 L -.643 .001 L -.433 -.013 L -.186 .142 L -.334 .961 L -.324 .594 L .025 .127 L .493 .352 L -.805 .327 L -.306 .015 L -.77 .284 L -.295 .41 L -.101 .692 L -.157 .255 L -.367 .283 L -.526 .255 L -.099 .057 L -.066 .042 L -.231 .156 L -.145 0 L -.174 -.056 L -1.417 -1.451 L -.092 -.395 L -.276 -.522 L -.34 -1.397 L -.689 -1.792 L -.94 -1.933 L -.979 -1.508 L -.554 -1.722 L -.507 -1.792 L -.738 -1.636 L -.82 -1.42 L -.424 -.737 L -.598 -1.439 L -.363 -1.157 L -.767 -3.274 L -.469 -2.695 L -.157 -1.566 L -.051 -.24 L .232 -.565 L .546 -.834 L .007 -.311 L -.404 -.281 L -.367 -.437 L -.113 -.635 L -.108 -.917 L .065 -.622 L -.837 .03 L -.19 .212 L -.235 .424 L .009 .183 L .276 .254 L .074 .183 L -.073 .438 L -.301 .438 L -.503 .368 L -.812 .369 L -.504 .114 L -.617 .255 L -.377 .015 L -.861 -.281 L -.572 -.38 L -1.018 -1 L -1.391 -1.268 L -.516 -.705 L .267 -.043 L 1.062 .125 L .615 -.086 L .443 -.142 L .461 -.283 L .521 -.608 L -.067 -.24 L -.156 .071 L -.587 .114 L -.847 -.026 L -.607 -.112 L -.632 -.132 L -.5 -.218 L -.203 -.07 L -.929 -.661 L -.668 -.775 L -.057 -.197 L .37 -.036 L .296 -.431 L .866 -.017 L -.015 -.728 L .259 .052 L .835 .009 L .835 .021 L .229 .149 L .735 .099 L .2 -.331 L .78 -.215 L .183 .062 L .145 .335 L .55 -.083 L .15 -.248 L .317 -.066 L -.241 -.463 L .232 -.149 L -.654 -1.333 L -.216 -.507 L -.112 -.441 L 557 143.058 l -.33 -.099 L -.412 -.411 L .154 -.735 L .114 -.689 L -.425 -.014 L -.504 -.085 L -.541 -.163 L -.116 -.38 L .079 -.269 L .186 -.543 L .979 -.893 L .144 -.446 L .535 -.463 L .404 -.083 L .207 .132 L .158 .518 L .361 .094 L .895 -.314 L .734 .011 L .71 -.259 L .076 -.38 L .563 -.61 L .277 -.481 L .177 -.364 L 1.193 -.496 L .478 -.547 L .509 -1.216 L .353 -.467 L .609 -.133 L .358 -.281 L -.261 -.38 L 1.512 -1.503 L .237 -.977 L -.188 -.377 L -.032 -.366 L .517 -.248 L .643 -.196 L .504 -.2 L .2 -.255 L -.012 -.211 L -.668 -.377 L -.702 .05 L -.188 -.248 L .039 -.43 L -.782 .003 L .003 -.532 L -.606 -.298 L -.089 -.248 L .215 -.132 L .116 -.479 L -.389 -.232 L .139 -.413 L .384 -.099 L .002 -.347 L -.598 .017 L -.101 -.199 L .202 -.149 L -.047 -.314 L -.336 0 L -.09 -.166 L .38 -.611 L .894 -.265 L 1.708 .325 L .568 .138 L .928 .149 L .557 -.265 L .262 .116 L .271 -.298 L .438 -.132 L .621 .102 L .125 .179 L .234 -.116 L .071 -.479 L .155 -.43 L .411 -.232 L .688 -.37 L .207 -.084 L .502 -.152 L 0 .515 L .441 1.03 L .221 .515 L .81 .11 L .441 .405 L .221 .258 L -.331 .221 L -.184 .184 L .073 .589 L .037 .552 L .294 .221 L .718 .096 L .092 .078 L .044 .182 L .68 .099 L -.104 .414 L .367 .694 L -.578 .364 L -.376 .281 L -.368 .049 L -.337 -.264 L -.033 -.364 L -.785 .198 L .157 .694 L .579 .595 L -.104 .446 L .272 .364 L -.215 .215 L .099 .43 L .198 .066 L .477 -.314 L .383 .248 L .772 .843 L .363 -.116 L 1.078 .579 L -.116 .364 L .756 .248 L .154 -.066 L .859 .596 L -1.07 .909 L -.281 .116 L .008 .364 L -.221 .265 L .04 .396 L -.309 .397 L -.218 .43 L .039 .248 L .63 .38 L .466 -.083 L .665 .479 L .704 .149 L .305 .529 L 1.242 .678 L .231 -.166 L 1.027 .595 L .538 -.066 L .182 .397 L .835 .166 L .304 .198 L .15 -.066 L .087 -.215 L .503 0 L .482 .265 L .582 -.347 L .494 .298 L .643 .066 L .142 .231 L -.101 .446 L .663 .149 L .286 .281 L .618 .265 L .584 -.281 L .313 .066 L -.034 .331 L .312 .248 L .379 -.231 L .721 .148 L .847 .364 L .606 -.297 L .268 .364 L .399 .116 L .357 -.132 L .271 .083 L .687 -.132 L .336 .05 L .311 -.694 L -.429 -.827 L .07 -.876 L .318 -.761 L -.037 -.022 L .345 -.129 L .471 -.102 L .231 .069 L .139 .183 L -.052 .861 L .212 .662 L -.092 .113 L .235 .493 L .637 .18 L .559 .081 L .869 .214 L .085 .021 L .544 -.074 L .531 -.313 L .301 .055 L .335 .125 L 1.238 .063 L 1.036 -.062 L .624 -.06 L .217 -.58 L -.017 -.282 L -.258 -.238 L -.313 -.069 L -.326 -.294 L -.042 -.24 L .07 -.156 L .189 -.1 L .784 -.033 L .714 -.216 L .397 -.27 L 1.123 -1.107 L .543 -.37 L .829 -.258 L 1.105 -.726 L .546 -.299 L .355 -.087 L .286 .167 L .975 .319 L .377 -.044 L 1.377 -.84 L .455 .392 L .716 .715 L .046 .38 L -.354 .454 L -.138 .269 L .102 .056 L .3 .055 L .657 .081 L .73 .179 L .624 .081 L -.018 .508 L -.112 .24 L -.596 .582 L -.072 .283 L .184 .718 L -.295 .058 L -.853 -.221 L -.558 -.082 L -.312 .129 L -.719 .512 L -1.446 .883 L -.197 .354 L .057 .761 L -.136 .382 L -.938 1.134 L -.045 .212 L .192 .408 L 0 .324 L -1.148 2.25 L -.17 .128 L -.309 -.013 L -.391 -.11 L -.811 -.32 L -.133 .283 L .146 1.594 L -.191 .354 L -.401 .144 L -.228 .185 L .152 .93 L -.015 .678 L -.273 .368 L -.25 .129 L -.255 -.14 L -.595 -.152 L +478.516 135.173 N .052 -.292 L -.049 -.169 L -.197 -.107 L .107 -.175 L .292 -.919 L -.015 -.818 L .517 -1.09 L .3 -.891 L -.004 -.409 L .133 -.283 L .07 -.749 L .033 -.847 L .062 -.174 L .026 -.278 L -.065 -.411 L .037 -.119 L .102 -.063 L 1.902 1.034 L .365 .167 L .253 -.016 L 1.139 -.656 L 2.96 -1.541 L .161 -.071 L .87 1.632 L .311 .69 L .093 .056 L -.46 .44 L -.257 .171 L -.97 .26 L -2.586 .622 L -.646 .229 L 1.146 1.32 L .698 .885 L -.765 .724 L -.456 .37 L -.24 .072 L -1.249 .332 L -.462 .61 L -.975 .782 L -2.079 -.299 L -.154 -.017 L +456.028 151.46 N -.021 1.003 L .033 3.078 L -.088 .17 L -1.561 -.019 L -.52 -.011 L -.073 1.13 L -1.981 -.963 L -5.577 -2.792 L -4.941 -2.372 L -5.231 -2.554 L -.41 .059 L -1.818 .858 L -1.519 .729 L -.231 .157 L -1.192 -.911 L -.258 -.182 L -1.008 -.333 L -1.646 -.442 L -.832 -.137 L -.098 -.07 L -.86 -1.506 L -.178 -.168 L -1.028 -.347 L -.702 -.165 L -.544 .201 L -.244 -.154 L -.562 -.873 L -.249 -.917 L -1.272 -1.702 L .152 -.283 L .249 -.128 L .666 -.47 L .086 -.17 L .061 -.664 L -.457 -1.156 L .158 -.495 L .16 -.622 L -.101 -.748 L .1 -.862 L -.052 -.691 L -.147 -.833 L -.88 -1.605 L .241 -.383 L .204 -.156 L .22 -.143 L .864 -.598 L .155 -.227 L .147 -.537 L -.274 -.973 L .126 -.354 L 1.473 -1.138 L .579 -.314 L .802 -.428 L .093 -.269 L -.064 -.564 L .093 -.981 L 1.436 .59 L .995 .309 L .521 .013 L .863 -.129 L .604 .027 L 1.552 .223 L .614 .479 L .794 .224 L .486 -.001 L .342 .197 L .173 .226 L .26 .819 L .39 .564 L .688 .591 L .378 .126 L .678 .14 L 1.031 .083 L .447 .07 L .973 .224 L .639 .224 L .552 .281 L 1.289 .788 L .84 .464 L .465 .013 L .441 -.128 L .758 -.411 L .706 -.623 L .3 -.523 L 0 -.254 L -.276 -.621 L -.112 -.579 L .044 -.41 L .237 -.537 L .661 -.58 L .333 -.198 L .554 -.241 L .644 -.298 L 1.376 -.413 L 1.205 .054 L .728 .154 L .844 .365 L .188 .169 L .043 .508 L .281 .253 L .301 .014 L .945 .125 L .712 .309 L .45 .027 L 1.286 .04 L .302 .197 L .068 .381 L .276 .296 L -.099 .208 L -.369 .228 L -.21 .34 L .354 1.283 L -.231 .425 L -.322 .553 L -.056 .311 L .185 .945 L .388 .916 L .042 .367 L -.015 .988 L -.019 3.869 L -.016 1.468 L -.008 2.048 L -.001 .692 L .045 2.81 L -.021 1.342 L .011 2.612 L +478.212 134.714 N -.834 -1.746 L -.796 -1.944 L -.124 -.289 L .109 -.066 L .679 -.851 L .219 -.438 L .183 -.507 L .171 -.566 L .188 -.822 L .116 .018 L .137 -.093 L .006 -.204 L .028 -.315 L .372 -.051 L .151 .022 L .07 .099 L .355 -.07 L .009 -.167 L .067 -.193 L .088 -.041 L .07 .023 L .183 .346 L .201 .128 L .021 .183 L -.047 .122 L .082 .085 L -.102 .063 L -.037 .119 L .065 .411 L -.026 .278 L -.062 .174 L -.033 .847 L -.07 .749 L -.133 .283 L .004 .409 L -.3 .891 L -.517 1.09 L .015 .818 L -.292 .919 L -.107 .175 L -.067 .068 L -.042 .042 L +495.751 163.817 N -.03 -.184 L -.112 -.537 L -.508 -.945 L -.73 -.987 L -.438 -.493 L -.846 -.69 L -.51 -.875 L -.814 -1.876 L -.474 -.889 L -.28 -.409 L -.794 -.507 L -1.271 -.689 L -.527 -.634 L -.8 -1.17 L -.081 -.96 L -.061 -.776 L -.002 -.89 L -.104 -.381 L -.312 -.663 L -.944 -1.65 L -.357 -.494 L -.758 -.62 L -.459 -.225 L -.499 -.126 L -.308 -.282 L -.483 -.578 L .149 -.692 L -.111 -.437 L -.474 -.818 L -.747 -1.072 L -.793 -.902 L -1.069 -1.494 L -.525 -.931 L -.352 -.479 L -.722 -.761 L -.524 -.056 L -.248 0 L .077 -.296 L .193 -.283 L .311 -1.314 L .104 -.583 L .154 .017 L 2.079 .299 L .975 -.782 L .462 -.61 L 1.249 -.332 L .24 -.072 L .456 -.37 L .765 -.724 L -.698 -.885 L -1.146 -1.32 L .646 -.229 L 2.586 -.622 L .97 -.26 L .257 -.171 L .46 -.44 L .093 .056 L 1.129 .459 L .757 .222 L 2.034 .934 L 1.14 .473 L 2.44 1.101 L .258 .196 L .399 .633 L .141 .07 L .973 -.048 L .135 .366 L -.118 .396 L .047 .818 L .118 .253 L .812 .277 L 1.557 .697 L 4.048 .132 L 1.657 .259 L .408 .054 L .334 .619 L .185 .239 L 1.07 .05 L .644 -.044 L .043 .121 L .277 .648 L .365 .494 L .178 .663 L .052 .113 L .615 -.029 L .248 .126 L -.204 .237 L .194 .187 L .184 .282 L .234 .067 L .234 .27 L .886 .168 L .423 .437 L -.07 .28 L -.235 .035 L -.111 .25 L .316 .381 L -.188 .593 L -.122 .198 L .165 .268 L .302 .666 L .149 -.117 L .372 .282 L .105 .616 L .422 .696 L -.028 .423 L .222 .268 L .16 .197 L .287 .084 L .136 -.007 L .336 .083 L 1.043 2.198 L .548 1.154 L .261 .902 L 3.362 .375 L 3.387 .446 L .839 .108 L .584 -.469 L .152 -.057 L .581 .914 L .155 1.453 L -5.346 2.982 L -2.35 1.213 L -1.691 .815 L -.169 .085 L -1.148 .346 L -3.097 1.035 L -4.618 1.566 L -.484 .229 L -.041 .127 L -.383 .397 L -1.907 2.271 L -2.042 2.667 L -1.302 -2.703 L -1.211 -2.45 L -.452 -.012 L -.715 .047 L -.446 -.125 L -.671 -.151 L -.216 .1 L -.174 .185 L -.11 .495 L .041 .678 L -.113 .565 L -.692 .563 L +476.458 130.735 N .124 .289 L .796 1.944 L .834 1.746 L -.38 .381 L -.479 1.145 L -.334 1.413 L -.171 .593 L -.18 .156 L -.407 -.07 L -.448 -.521 L -.782 -.676 L -.386 -.494 L -.338 -.988 L -.521 -.45 L -.289 -.621 L -.17 -.479 L -.198 -.353 L -.466 .17 L -.267 .523 L .604 1.34 L .131 .381 L .634 .86 L .933 1.042 L .473 1.199 L .526 .973 L .277 .818 L .391 .465 L .912 1.735 L 1.072 1.904 L .428 .705 L .586 .549 L .451 .352 L .151 .183 L -.241 .17 L -.285 .1 L -.043 .155 L .238 1.087 L .252 .467 L .127 .238 L .812 .591 L .397 .168 L .406 .521 L .416 .38 L .311 .56 L -10.382 -.006 L -2.138 -.001 L -2.774 .002 L -2.513 .015 L -2.268 -.029 L -1.664 .01 L -1.241 .007 L -1.614 -.019 L -.914 .005 L -.819 .089 L -.011 -2.612 L .021 -1.342 L -.045 -2.81 L .001 -.692 L .008 -2.048 L .016 -1.468 L .019 -3.869 L .015 -.988 L -.042 -.367 L -.388 -.916 L -.185 -.945 L .056 -.311 L .322 -.553 L .231 -.425 L -.354 -1.283 L .21 -.34 L .369 -.228 L .099 -.208 L .337 .168 L .553 -.015 L .628 -.1 L .786 -.001 L 1.513 .293 L .587 .115 L .779 .122 L .721 .154 L .348 .409 L .4 0 L .928 .083 L .998 .394 L .628 .069 L .245 -.127 L .72 -.538 L .925 -.397 L .837 -.186 L .78 -.27 L .375 -.072 L .346 .056 L .535 -.001 L .723 .126 L .202 .465 L .596 .366 L .518 -.156 L .64 .267 L .382 .027 L .561 -.401 L .241 .179 L .277 .056 L .674 .13 L .338 -.062 L .46 -.165 L .51 -.308 L +580.625 132.873 N .24 .43 L .299 .05 L .276 -.314 L .134 -.513 L .275 .066 L .186 -.182 L 1.079 .199 L .132 .612 L .867 .264 L .726 .595 L .472 .215 L .15 -.132 L .454 .281 L .657 .794 L .158 -.166 L .71 -.116 L .289 .166 L .178 .38 L -.069 .281 L 1.451 .893 L .333 -.248 L .326 .017 L -.175 .396 L .014 .265 L .935 .066 L .365 -.066 L .54 .496 L .141 .463 L .237 -.099 L -.01 -.364 L .685 .38 L .271 -.083 L .08 -.331 L .407 0 L .63 .281 L .319 .364 L .849 -.066 L .341 .116 L .339 -.281 L .655 .159 L .037 .022 L -.318 .761 L -.07 .876 L .429 .827 L -.311 .694 L -.336 -.05 L -.687 .132 L -.271 -.083 L -.357 .132 L -.399 -.116 L -.268 -.364 L -.606 .297 L -.847 -.364 L -.721 -.148 L -.379 .231 L -.312 -.248 L .034 -.331 L -.313 -.066 L -.584 .281 L -.618 -.265 L -.286 -.281 L -.663 -.149 L .101 -.446 L -.142 -.231 L -.643 -.066 L -.494 -.298 L -.582 .347 L -.482 -.265 L -.503 0 L -.087 .215 L -.15 .066 L -.304 -.198 L -.835 -.166 L -.182 -.397 L -.538 .066 L -1.027 -.595 L -.231 .166 L -1.242 -.678 L -.305 -.529 L -.704 -.149 L -.665 -.479 L -.466 .083 L -.63 -.38 L -.039 -.248 L .218 -.43 L .309 -.397 L -.04 -.396 L .221 -.265 L -.008 -.364 L .281 -.116 L 1.07 -.909 L +374.125 167.166 N -1.41 -.924 L -.661 -.604 L -.537 -.788 L -.292 -.662 L -.15 -.183 L -.312 -.154 L -.567 -.053 L -.655 -.307 L -.695 -.561 L -.604 -.194 L -.567 -.025 L -1.209 .12 L -1.821 .194 L -.523 .417 L .06 -.502 L .563 -1.301 L .188 -.819 L .13 -1.13 L -.162 -1.101 L -.3 -.791 L -.624 -.747 L .267 -.283 L .182 -.424 L .067 -.975 L -.065 -.537 L -.174 -.353 L -.808 -.817 L -.297 -.112 L -.393 .438 L -.055 -.197 L -.013 -.381 L .08 -.689 L .474 .013 L 5.055 .056 L 2.396 .014 L .732 -.033 L .212 .027 L -.051 -1.102 L -.164 -1.539 L .01 -.707 L .249 -.383 L .575 -.427 L .726 -.315 L .809 -.287 L .144 -.128 L .099 -2.6 L .07 -2.261 L .047 -.509 L .557 -.074 L 6.005 .022 L .56 .011 L .104 -.396 L -.002 -.65 L .03 -1.752 L 2.829 1.509 L 4.12 2.42 L 1.414 .91 L -.523 .13 L -3.231 .089 L .049 .776 L .908 7.962 L .19 1.468 L .178 1.736 L .325 2.753 L .202 2.386 L .186 1.468 L .724 .787 L -.379 1.613 L -6.457 .01 L -1.953 .026 L -.945 .344 L -.387 .031 L -.485 -.054 L -.713 -.137 L -.535 -.124 L -.06 .212 L .055 .296 L -.107 .269 L -.454 -.082 L -.214 -.168 L -.568 -.83 L -.261 -.111 L -.402 .073 L -.252 .256 L -.181 .552 L -.018 .607 L -.332 .284 L +476.114 191.139 N -.563 .54 L -.626 .314 L -.367 .016 L -.303 -.196 L -.303 -.097 L -.88 .132 L -.881 .33 L -.911 .048 L -.942 -.234 L -.495 -.011 L -.464 .087 L -.496 .229 L -1.288 -1.32 L -1.032 -.926 L -.207 -.083 L -.258 .157 L -.436 .582 L -.16 .1 L -.684 -.631 L -.384 -.012 L -.529 .37 L -.258 .242 L -.352 .016 L -.366 -.195 L -.525 -.477 L -.348 -.493 L -.795 -.772 L -.143 -.239 L -.031 -.07 L .083 -.679 L -.157 -.352 L -.558 -.477 L -.814 -.165 L -.367 -.224 L -.285 -.436 L -.059 -.72 L -.206 -.366 L -.207 -.168 L -.717 -.434 L -.558 -.378 L -.445 -.351 L -.173 -.395 L .148 -.481 L -.223 -.267 L -.351 -.196 L -.799 -.235 L -.797 -.447 L -.223 -.225 L -.252 -.493 L -.207 -.126 L -.272 .001 L -.802 .019 L -.158 -.211 L -.01 -.664 L .416 -1.472 L -.122 -.536 L -.347 -.549 L -1.342 -1.673 L .15 -.425 L -.026 -.367 L -.266 -.465 L -.444 -.407 L -.155 -.295 L -.137 -.522 L -.221 -1.228 L -.141 -.225 L -.338 -.012 L -.517 .088 L -.219 -.352 L .316 -.609 L .542 -.596 L .087 -.34 L -.342 -.662 L .053 -.24 L .718 -.428 L .149 -.212 L -.131 -.677 L .122 -.438 L .583 -.809 L .417 -1.245 L .229 -.143 L 1.245 -.05 L .839 .009 L .04 -.283 L -.031 -1.229 L -.036 -1.002 L .038 -.749 L -.085 -2.5 L .036 -.636 L .016 -.946 L .02 -1.045 L .073 -1.13 L .52 .011 L 1.561 .019 L .088 -.17 L -.033 -3.078 L .021 -1.003 L .819 -.089 L .914 -.005 L 1.614 .019 L 1.241 -.007 L 1.664 -.01 L 2.268 .029 L 2.513 -.015 L 2.774 -.002 L 2.138 .001 L 10.382 .006 L .229 .414 L .499 1.115 L .281 3.501 L .319 1.637 L .182 .211 L .625 .394 L .595 .366 L .617 .507 L .491 .197 L .254 .223 L -.238 .199 L -.277 .327 L -.306 .566 L -.369 .242 L -.511 .172 L -.427 .116 L -.153 .142 L -.235 .496 L -.348 .171 L -.73 .033 L -.204 .552 L -.038 .452 L -.202 .862 L -.242 .722 L -.541 1.302 L -.068 .495 L .092 .903 L -.013 .679 L -.001 .083 L -.148 .947 L -.398 1.231 L -.214 1.061 L -1.04 .331 L -.414 .37 L -.693 1.134 L -.154 .34 L -.191 1.088 L -.141 1.074 L -.197 .185 L -.274 .044 L -.431 -.096 L -.259 .072 L -.163 .114 L -.187 1.103 L -.115 .933 L -.2 1.272 L .039 .522 L -.229 1.159 L -.469 .299 L -.288 -.012 L -.928 -.122 L -.321 .03 L -.188 .806 L -.054 .466 L .094 .141 L .479 .11 L .734 .123 L .334 .167 L .805 .913 L 1.06 1.067 L .751 1.464 L .345 .732 L .348 .421 L .462 .28 L .415 .097 L .269 .309 L .117 .988 L -.034 .17 L -.018 .141 L -.079 -.028 L -.464 .017 L -1.009 .133 L -.832 .005 L -.671 -.052 L -.291 .327 L -.678 .795 L +518.402 163.079 N -.282 .097 L -.538 .27 L -.656 .566 L -.265 .297 L -.166 .508 L -.062 .41 L -.41 .326 L -1.418 .652 L -2.27 .641 L -1.285 .412 L -.843 .312 L -.356 .297 L -.473 .622 L -.436 .269 L -.506 .114 L -.593 -.069 L -.521 .072 L -.83 .439 L -.65 .396 L -.956 .397 L -.752 .199 L -1.16 .003 L -.562 -.013 L -.297 .128 L -.386 .312 L -.272 .297 L -.45 .312 L -.511 .241 L -.389 .043 L -.239 -.042 L -.535 .411 L -.839 .058 L -.494 -.112 L -.623 -.437 L -.17 -.155 L -.317 -.437 L -.084 -.254 L .18 -.721 L -.081 -.635 L -.312 -.507 L -.341 -1.171 L -.572 -1.919 L -.072 -.438 L .268 -.707 L -.124 -.748 L .692 -.563 L .113 -.565 L -.041 -.678 L .11 -.495 L .174 -.185 L .216 -.1 L .671 .151 L .446 .125 L .715 -.047 L .452 .012 L 1.211 2.45 L 1.302 2.703 L 2.042 -2.667 L 1.907 -2.271 L .383 -.397 L .041 -.127 L .484 -.229 L 4.618 -1.566 L 3.097 -1.035 L 1.148 -.346 L .169 -.085 L .092 .663 L .226 .634 L .604 .971 L .933 1.364 L .127 .253 L -.006 .296 L .483 .689 L .241 .306 L +494.64 172.627 N -.261 -.166 L -.476 -.633 L -.475 -.159 L -.437 -.911 L -1.267 -.792 L -.277 -.594 L -.673 -.673 L -.594 -.119 L -.871 -.554 L -.555 .079 L -.158 -.158 L -.237 .04 L -.277 -.198 L -.356 .159 L -.476 .079 L -.277 -.436 L -.158 .237 L -.436 .198 L -.792 .079 L -.554 -.594 L -.238 0 L -.396 -.317 L -.832 1.663 L -.436 -.871 L -.475 .079 L -.277 .356 L -.396 -.08 L -.349 .041 L .013 -.679 L -.092 -.903 L .068 -.495 L .541 -1.302 L .242 -.722 L .202 -.862 L .038 -.452 L .204 -.552 L .73 -.033 L .348 -.171 L .235 -.496 L .153 -.142 L .427 -.116 L .511 -.172 L .369 -.242 L .306 -.566 L .277 -.327 L .238 -.199 L .098 .129 L .718 2.102 L .442 1.623 L .689 1.919 L .618 .832 L .205 -.212 L -.072 -.479 L .093 -.226 L .31 .253 L .4 .677 L .384 .395 L .534 -.043 L .242 .014 L 1.338 1.282 L .809 .916 L .124 .099 L .706 .055 L .618 .874 L .021 .24 L -.025 .198 L .118 .212 L .507 .182 L .915 .869 L -.075 .094 L -.529 .78 L -.331 -.182 L -.396 -.125 L -.214 .114 L -.055 .085 L +370.147 172.035 N -2.301 -.043 L -1.045 .006 L -.505 .384 L -.51 .187 L -.74 -.024 L -.819 .047 L -.463 .139 L -.009 -.003 L -.278 -.226 L -.169 -.409 L .104 -.424 L -.095 -.55 L -.018 -.198 L .001 -.046 L 1.695 .014 L 0 -.434 L .155 0 L .341 -.016 L .186 -.077 L .248 .062 L .294 -.046 L .124 -.093 L .016 -.263 L .077 -.078 L .14 -.016 L .155 .155 L .232 .124 L .356 .108 L .046 .108 L .139 .047 L .217 -.031 L .263 .108 L .186 .17 L .434 0 L .186 -.108 L .263 -.108 L .279 0 L .108 -.124 L .016 -.124 L -.155 -.217 L -.202 -.077 L -.201 .031 L -.294 .093 L -.108 .093 L -.248 .062 L -.279 -.186 L -.031 -.186 L -.186 -.108 L -.17 -.015 L -.186 .124 L -.139 -.108 L -.108 -.217 L -.155 -.108 L -.201 .031 L -.17 -.062 L -.387 .17 L -.108 -.108 L -.155 .046 L -.202 .124 L -.093 .294 L -1.664 0 L -.007 -.067 L -.028 -.269 L -.377 -.268 L -.068 -.155 L -.057 -.367 L -.386 -.635 L -.399 -.494 L -.379 -.31 L -.472 -.183 L .54 -.34 L .723 -.75 L .588 -1.004 L .334 -.82 L .099 -.826 L .523 -.417 L 1.821 -.194 L 1.209 -.12 L .567 .025 L .604 .194 L .695 .561 L .655 .307 L .567 .053 L .312 .154 L .15 .183 L .292 .662 L .537 .788 L .661 .604 L 1.41 .924 L -.506 .399 L -.057 .339 L .251 1.1 L .144 .663 L .22 .479 L .181 .197 L .554 .322 L .265 .337 L .082 .833 L -.004 .565 L -.062 .142 L -.146 -.042 L -.963 .091 L -.658 .074 L -.725 -.081 L -.503 -.209 L -.795 -.32 L -1.255 -.021 L +495.973 175.881 N -.363 .807 L .083 .409 L .428 .732 L .587 .844 L .732 .801 L .596 .547 L .634 .321 L .54 .209 L 4.26 1.443 L 1.447 .472 L 1.875 -.04 L .236 .154 L -4.087 4.205 L -1.562 1.69 L -.813 .909 L -.8 .004 L -1.693 -.046 L -.626 .088 L -.562 .215 L -.388 .214 L -.502 .497 L -.294 .426 L -.337 .115 L -1.216 .078 L -.305 .101 L -.453 .511 L -1.103 -.106 L -.461 -.181 L -.46 -.336 L -.271 -.098 L -.852 .358 L -.675 .343 L -.258 .199 L -.71 .753 L -.16 .114 L -.847 -.094 L -.67 -.193 L -1.373 -.133 L -.335 -.041 L -2.353 -1.525 L -.604 -.293 L -.749 -.193 L -1.054 -.149 L -.319 -.069 L .018 -.141 L .034 -.17 L -.117 -.988 L -.269 -.309 L -.415 -.097 L -.462 -.28 L -.348 -.421 L -.345 -.732 L -.751 -1.464 L -1.06 -1.067 L -.805 -.913 L -.334 -.167 L -.734 -.123 L -.479 -.11 L -.094 -.141 L .054 -.466 L .188 -.806 L .321 -.03 L .928 .122 L .288 .012 L .469 -.299 L .229 -1.159 L -.039 -.522 L .2 -1.272 L .115 -.933 L .187 -1.103 L .163 -.114 L .259 -.072 L .431 .096 L .274 -.044 L .197 -.185 L .141 -1.074 L .191 -1.088 L .154 -.34 L .693 -1.134 L .414 -.37 L 1.04 -.331 L .214 -1.061 L .398 -1.231 L .148 -.947 L .001 -.083 L .349 -.041 L .396 .08 L .277 -.356 L .475 -.079 L .436 .871 L .832 -1.663 L .396 .317 L .238 0 L .554 .594 L .792 -.079 L .436 -.198 L .158 -.237 L .277 .436 L .476 -.079 L .356 -.159 L .277 .198 L .237 -.04 L .158 .158 L .555 -.079 L .871 .554 L .594 .119 L .673 .673 L .277 .594 L 1.267 .792 L .437 .911 L .475 .159 L .476 .633 L .261 .166 L -.594 .921 L -.488 .61 L -.105 .254 L -.029 .396 L .202 1.157 L .5 -.074 L .892 -.246 L .4 .04 L .556 .195 L +364.011 169.929 N 1.664 0 L .093 -.294 L .202 -.124 L .155 -.046 L .108 .108 L .387 -.17 L .17 .062 L .201 -.031 L .155 .108 L .108 .217 L .139 .108 L .186 -.124 L .17 .015 L .186 .108 L .031 .186 L .279 .186 L .248 -.062 L .108 -.093 L .294 -.093 L .201 -.031 L .202 .077 L .155 .217 L -.016 .124 L -.108 .124 L -.279 0 L -.263 .108 L -.186 .108 L -.434 0 L -.186 -.17 L -.263 -.108 L -.217 .031 L -.139 -.047 L -.046 -.108 L -.356 -.108 L -.232 -.124 L -.155 -.155 L -.14 .016 L -.077 .078 L -.016 .263 L -.124 .093 L -.294 .046 L -.248 -.062 L -.186 .077 L -.341 .016 L -.155 0 L 0 .434 L -1.695 -.014 L .019 -.477 L .173 -.198 L .434 -.058 L .093 -.155 L -.006 -.059 L +495.973 175.881 N -.556 -.195 L -.4 -.04 L -.892 .246 L -.5 .074 L -.202 -1.157 L .029 -.396 L .105 -.254 L .488 -.61 L .594 -.921 L .055 -.085 L .214 -.114 L .396 .125 L .331 .182 L .529 -.78 L .075 -.094 L .627 .596 L .285 .465 L .036 .282 L -.118 .113 L -.361 .185 L -.438 .1 L -.56 .312 L -.566 .467 L .253 .127 L .645 -.058 L .321 .013 L .434 .124 L -.114 .26 L -.37 .468 L -.34 .567 L +363.763 172.732 N .463 -.139 L .819 -.047 L .74 .024 L .51 -.187 L .505 -.384 L 1.045 -.006 L 2.301 .043 L -.111 .792 L .115 .847 L -.186 .312 L -.333 .186 L -.513 .031 L -.401 .017 L -.381 .186 L -.789 .64 L -.321 .372 L -.047 -.126 L -.192 0 L -.501 -.14 L -.165 -.254 L .121 -.41 L .33 -.438 L .253 -.212 L -.131 -.141 L -.372 -.112 L -.498 .015 L -.415 .17 L -.161 0 L -.616 -.281 L -.36 -.296 L -.069 -.24 L -.323 -.084 L -.316 -.137 L +383.005 177.596 N -.379 .397 L -.264 .623 L .214 .409 L .695 .405 L .197 .31 L -.125 .283 L -.332 .37 L .309 .351 L .648 .561 L .051 .226 L -.19 .143 L -.304 -.012 L -.548 -.223 L -.304 .03 L -.158 .199 L -.03 .127 L .296 .549 L .179 .21 L -.188 .354 L -.602 .554 L -.047 .099 L -.339 -.224 L -.337 -.097 L -.143 .086 L -.756 .922 L -.321 -.026 L -.404 -.322 L -.277 -.323 L .044 -.283 L -.009 -.65 L -.22 -.846 L -.165 -.366 L -.338 -.097 L -.528 .046 L -.367 .143 L -.252 .242 L -.193 .376 L -.26 -.656 L -.165 -1.369 L -.252 -.761 L -.475 -.619 L -.456 -.421 L -.42 -.224 L -.466 -.04 L -1.137 .148 L -.594 -.039 L -.238 .157 L -.643 .866 L -1.088 1.235 L .051 -.392 L -.312 -.55 L -.764 -.775 L -.122 -.649 L -.84 -.366 L -.908 -.563 L -.277 -.296 L .09 -.396 L -.053 -.311 L -.547 -.041 L -.323 -.098 L -.115 -.155 L .059 -.311 L -.038 -.1 L .321 -.372 L .789 -.64 L .381 -.186 L .401 -.017 L .513 -.031 L .333 -.186 L .186 -.312 L -.115 -.847 L .111 -.792 L 1.255 .021 L .795 .32 L .503 .209 L .725 .081 L .658 -.074 L .963 -.091 L .146 .042 L .113 .028 L .18 .183 L .882 .715 L .536 .265 L .252 -.256 L .475 -.413 L .338 .026 L .356 .153 L .565 .152 L .43 -.243 L .3 -.327 L .684 -.428 L .323 .055 L .246 .281 L .022 .339 L .271 .832 L .265 .451 L .474 .478 L .349 .718 L .194 1.143 L .559 .901 L +266.015 188.956 N .103 .169 L -.163 .326 L -.592 .385 L -1.74 .9 L -.807 .23 L -.557 .074 L -.465 -.054 L -.284 .115 L -.232 1.117 L -.348 .115 L -.628 -.618 L -.344 -.224 L -1.149 .035 L -.385 -.04 L -.896 -.461 L -.309 -.125 L -.159 .029 L -.041 .184 L .616 .688 L .391 .69 L .302 1.524 L .079 .55 L .166 .239 L .96 .051 L .434 .125 L .15 .253 L -.265 .27 L -.569 .272 L -.652 .131 L -.203 .199 L -.259 .666 L -.235 .213 L -.652 .173 L -.554 .286 L -.74 .654 L -.645 .739 L -.271 .016 L -.186 -.776 L -.083 -.183 L -.757 .697 L -.414 .073 L -.482 -.223 L -.694 -.546 L -.432 -.054 L -.199 -.437 L -.088 -.452 L -.161 -.861 L -.138 -.437 L -.148 -.168 L -.797 -1.182 L -.51 -.491 L .479 -.526 L .731 -.612 L -.121 -.282 L -.486 -.647 L -.256 -.437 L -.447 -.789 L -.162 -.804 L -.048 -.367 L -.035 -.438 L -.026 -.254 L .147 -.326 L .379 -.511 L .085 -1.004 L .409 -.525 L -.644 -.081 L -1.99 .224 L -.76 .174 L -.522 .13 L -.144 0 L -.554 -.576 L -.847 -.998 L -.188 -.253 L -.64 -.321 L -.521 -.181 L -1.167 .05 L -1.163 .12 L -.496 .017 L -.397 -.252 L -.429 -.548 L -.401 -.309 L -.099 -.353 L .226 -1.132 L -.103 -.395 L -.855 -1.45 L -.31 -.606 L -.384 .017 L -.234 .1 L -.402 -.025 L .709 -1.191 L .241 -.722 L .172 -.722 L .99 -1.758 L .381 -.059 L .227 .027 L .129 -.396 L -.048 -.497 L .056 -.288 L .414 -.2 L .534 -.156 L .84 -.171 L .128 .105 L -.9 .151 L -.731 .312 L -.145 .212 L .19 .607 L .142 .407 L .224 .126 L -.043 .145 L .153 .579 L -.135 .367 L -.327 .364 L -.348 .824 L -.137 .368 L .253 .479 L .288 .253 L .25 .72 L .341 .353 L .523 -.114 L .184 -.156 L .419 -.255 L .12 -.142 L .066 -.523 L -.167 -.649 L -.21 -.282 L -.438 -.804 L -.136 -.135 L -.118 -.395 L -.247 -.18 L .239 -.099 L .095 -.251 L -.204 -.144 L 1 -.379 L 1.085 -.327 L .998 -.272 L .086 -.225 L .69 -.086 L .143 -.008 L -.042 -.157 L -.055 -.198 L -.125 -.036 L -.039 -.108 L -.128 -.072 L -.226 .071 L -.156 .027 L -.229 -.012 L -.315 -.55 L .109 -.254 L .337 -.213 L .367 -.043 L .09 .112 L .14 .368 L .186 .162 L -.001 .148 L .026 .193 L .068 .09 L .004 .198 L .253 .258 L .329 -.02 L .699 .111 L .455 .07 L .593 .196 L .323 .254 L .393 .564 L .156 .635 L .358 .324 L .359 .084 L 1.02 -.129 L .928 -.059 L .59 -.058 L .799 -.059 L .714 .125 L .4 .479 L .267 .169 L .578 .253 L .49 .14 L 1.094 .04 L .382 -.057 L .388 -.227 L 1.042 -.807 L .47 -.185 L .453 .042 L .959 -.073 L 1.152 -.073 L .919 .055 L .248 .112 L -.056 .141 L -.294 .185 L -.854 -.041 L -.433 .015 L -.083 .212 L .059 .184 L .593 .253 L .609 .535 L .195 .649 L .246 -.523 L .185 -.142 L .415 .253 L .483 .027 L .374 .098 L .258 .338 L .918 .394 L .464 .295 L -.729 .496 L -.161 .65 L -.214 .226 L -1.055 .417 L .5 .064 L .598 .098 L .368 -.029 L .33 -.142 L .929 -.03 L .725 .083 L .84 .274 L .095 .296 L -.061 .41 L -1.655 1.239 L -.101 .255 L .074 .212 L .62 .604 L .141 .282 L -.308 .299 L -.41 .144 L -1.032 .19 L -.061 .452 L .008 .58 L -.395 .539 L -.071 .212 L .324 .521 L .732 .745 L .503 .647 L +493.044 204.258 N -1.223 -1.771 L -.027 -.932 L -.03 -1.43 L -.042 -2.045 L -.003 -1.017 L 0 -.438 L .016 -.848 L .004 -1.215 L .002 -.508 L 1.649 -2.467 L .453 -.511 L .305 -.101 L 1.216 -.078 L .337 -.115 L .294 -.426 L .502 -.497 L .388 -.214 L .562 -.215 L .626 -.088 L 1.693 .046 L .8 -.004 L .813 -.909 L 1.562 -1.69 L 4.087 -4.205 L -.236 -.154 L -1.875 .04 L -1.447 -.472 L -4.26 -1.443 L -.54 -.209 L -.634 -.321 L -.596 -.547 L -.732 -.801 L -.587 -.844 L -.428 -.732 L -.083 -.409 L .363 -.807 L .34 -.567 L .37 -.468 L .114 -.26 L .154 .044 L .935 1.142 L .586 .62 L .243 .381 L .265 .211 L .372 -.071 L .417 -.001 L .465 .027 L .372 -.071 L .572 -.27 L .836 -.425 L .585 -.157 L .397 .098 L .76 .267 L .549 -.072 L .56 -.326 L .779 -.566 L .247 -.127 L .447 .041 L .479 .098 L .419 -.043 L 1.195 -.482 L .288 .027 L .682 .196 L .74 -.03 L .764 -.185 L .964 -.327 L .9 -.666 L .47 -.382 L .604 .154 L .391 .211 L .08 .014 L .147 .268 L -.414 .919 L .021 .564 L .132 .621 L -.165 .452 L -.375 .509 L -.028 .678 L -.047 .833 L -.163 .509 L -1.264 2.262 L -.842 .792 L -.122 .311 L .102 .353 L -.893 1.569 L -.834 1.272 L -.214 .947 L -.351 .636 L -.712 1.117 L -.874 1.188 L -1.159 1.498 L -.384 .439 L -2.274 2.504 L -1.82 1.557 L -2.164 1.121 L -.593 .382 L -1.28 1.09 L -1.74 1.755 L -.06 .061 L -1.055 1.1 L -1.235 1.569 L -.615 .835 L .1 .353 L -.094 .276 L +264.768 176.039 N -.128 .225 L -.115 .067 L -.029 .135 L .039 .25 L -.058 .086 L .125 .376 L -.039 .424 L -.453 .154 L -.135 -.01 L -.144 .039 L -.482 -.039 L -.192 .039 L -.087 -.048 L -.356 0 L -.02 -.058 L .039 -.067 L .202 -.029 L .222 -.135 L .019 -.087 L .106 .02 L .154 .01 L .135 -.145 L -.096 -.279 L .048 -.125 L .029 -.183 L -.067 -.125 L -.097 -.135 L -.279 -.048 L .116 -.096 L .164 -.019 L .231 -.029 L .115 -.087 L .385 .02 L .106 -.039 L .299 -.067 L .244 .006 L +654.075 190.187 N .206 -.125 L .63 -.114 L .656 -.938 L .241 -.07 L -.069 .268 L .122 .087 L .187 -.046 L .11 .174 L .148 .444 L -.024 .111 L -.013 .247 L .197 .197 L .025 .086 L -1.234 .42 L -.383 .271 L -.309 -.271 L -.111 -.259 L -.234 .012 L -.062 -.37 L -.084 -.126 L +493.044 204.258 N -.602 .389 L -.557 .171 L -.385 -.112 L -.086 .777 L -.282 .367 L -.67 .115 L -.394 .382 L -.088 .48 L .006 .353 L -.356 .622 L -.964 1.358 L .092 .536 L -.337 .65 L -.25 .255 L -.334 .1 L -.084 .152 L -1.067 -.807 L -2.427 -1.752 L -.07 -.239 L .116 -.552 L -.137 -.381 L -3.553 -1.984 L -4.663 -2.568 L -1.448 .033 L 1.144 -2.479 L .105 -.229 L .656 -.835 L .985 -.938 L .477 -.525 L .43 -.695 L .143 -.566 L -.048 -.664 L -.223 -.606 L -.224 -.352 L -.732 -1.069 L -.174 -.465 L -.027 -.861 L -.126 -.226 L -.477 -.463 L -.3 -.493 L .678 -.795 L .291 -.327 L .671 .052 L .832 -.005 L 1.009 -.133 L .464 -.017 L .079 .028 L .319 .069 L 1.054 .149 L .749 .193 L .604 .293 L 2.353 1.525 L .335 .041 L 1.373 .133 L .67 .193 L .847 .094 L .16 -.114 L .71 -.753 L .258 -.199 L .675 -.343 L .852 -.358 L .271 .098 L .46 .336 L .461 .181 L 1.103 .106 L -1.649 2.467 L -.002 .508 L -.004 1.215 L -.016 .848 L 0 .438 L .003 1.017 L .042 2.045 L .03 1.43 L .027 .932 L 1.223 1.771 L +466.196 203.275 N .188 -.298 L .076 -.27 L -.057 -.748 L .025 -.734 L -.021 -.593 L .107 -.507 L .217 -1.02 L .395 -.681 L .255 -.284 L 1.241 -.996 L 1.195 -1.066 L .191 -.453 L -.111 -.31 L -.271 -.182 L -.479 -.04 L -.191 -.027 L -.128 -.253 L .26 -1.88 L .018 -.424 L -.159 -.183 L -.063 -.028 L .496 -.229 L .464 -.087 L .495 .011 L .942 .234 L .911 -.048 L .881 -.33 L .88 -.132 L .303 .097 L .303 .196 L .367 -.016 L .626 -.314 L .563 -.54 L .3 .493 L .477 .463 L .126 .226 L .027 .861 L .174 .465 L .732 1.069 L .224 .352 L .223 .606 L .048 .664 L -.143 .566 L -.43 .695 L -.477 .525 L -.985 .938 L -.656 .835 L -.105 .229 L -1.144 2.479 L -4.659 0 L -1.277 .05 L -.319 .017 L -.554 .398 L -.458 .427 L -.431 .045 L -.546 -.223 L -.064 -.042 L +713.621 206.298 N .169 7.966 L -.44 .822 L .431 1.368 L .046 .805 L -.031 3.438 L -.515 -.512 L -.927 -.888 L -.716 -.902 L -.406 -.056 L -.776 .101 L -.739 .143 L -.434 -.013 L .091 -.382 L .435 -.65 L .006 -.283 L -.561 -.521 L -.565 -.775 L .028 -.226 L .442 .111 L .236 -.042 L .135 -.113 L -.467 -.409 L -.595 -.408 L -.287 -.381 L -.275 -.648 L -1.053 -1.693 L -.508 -.394 L -.467 -.282 L -.604 -.196 L -1.983 -.603 L -1.26 -.379 L -.613 -.069 L -.705 -.238 L -.63 -.323 L .072 -.34 L -.098 -.268 L -.193 -.028 L -.617 .101 L -.389 -.07 L -.412 -.196 L -.408 -.395 L -.209 -.579 L .133 -.494 L -.155 -.226 L -.187 .113 L -.234 .396 L -.122 .664 L -.251 .608 L -.334 .269 L -.696 .354 L -.155 -.169 L -.331 -.677 L .022 -.155 L .384 -.27 L -.152 -.424 L -.173 -.239 L -.564 -.395 L -.707 -.394 L -.338 -.056 L -.059 -.212 L .038 -.226 L .413 -.044 L .388 .084 L .603 .239 L .158 -.029 L .368 -.34 L .525 -.41 L .146 .056 L .3 .269 L 1.021 -.045 L .139 -.128 L .09 -.522 L -.063 -.409 L -.238 .028 L -.345 .199 L -.604 .071 L -.656 -.041 L -.766 .044 L -1.026 -.082 L -.411 -.31 L -.135 -.197 L -.148 -.664 L -.202 -.338 L -.42 -.155 L -1.249 -.124 L .265 -.297 L .058 -.255 L .004 -.593 L .463 -.029 L .92 -.411 L .49 -.383 L .444 -.283 L .352 .027 L .4 .069 L 1.494 .646 L .515 .169 L .913 .153 L .382 .705 L .138 .396 L -.283 .749 L -.067 .381 L .221 .381 L .115 .494 L .115 .48 L .215 .521 L .186 .197 L .197 .127 L .226 -.65 L .085 .113 L .087 .141 L .309 1.073 L .169 .169 L .234 .183 L .294 .112 L .354 .056 L .58 -.198 L .504 -.439 L 1.192 -1.853 L .352 -.015 L 1.078 -.215 L .378 -.142 L .045 -.085 L .014 -.509 L .219 -.17 L 1.1 -.609 L .335 -.043 L 1.732 .759 L 2.129 .941 L 1.54 .52 L 1.299 .404 L h 691.208 208.707 m -.388 -.069 L -.693 -.38 L -.852 -.647 L -.295 -.141 L -.414 .028 L -.059 .1 L .024 .452 L -.206 .028 L -1.014 -.407 L -.258 -.353 L -.582 .199 L -.289 .269 L -.326 .185 L -.186 -.184 L -.312 -.451 L -.245 -.451 L .246 -.198 L .303 -.029 L .274 .056 L 1.104 .04 L .574 .31 L .319 -.015 L .544 -.326 L .414 -.015 L .534 .126 L .857 .21 L .499 .395 L .293 .395 L .179 .621 L -.049 .254 L h 682.045 208.699 m -.419 -.056 L -.715 -.493 L -.232 -.451 L .146 -.283 L .603 -.1 L .766 -.044 L .246 .126 L .256 .311 L .313 .197 L .108 .226 L -.067 .226 L -.125 .057 L -.879 .285 L h 707.635 219.095 m -1.11 -.209 L .589 -1.032 L .56 -.708 L .407 -.269 L .427 -.072 L .527 .338 L .198 .24 L -.11 .184 L -.324 .637 L -.256 .17 L -.638 .693 L -.27 .028 L h 673.797 218.703 m -.562 .257 L .034 .233 L -.886 .326 L -.582 .274 L -.339 -.041 L -.453 .325 L -.504 -.069 L -.427 -.112 L -.378 .255 L -.3 .058 L -.358 -.07 L -.58 -.196 L -1.046 -.04 L -.316 .043 L -.211 -.564 L .027 -.24 L .383 -.198 L .672 -.199 L .528 -.016 L 1.142 .407 L .445 .324 L .338 .013 L .326 -.297 L .464 -.016 L .429 -.071 L .414 .187 L .467 -.116 L -.072 -.222 L .421 -.187 L .404 -.233 L .094 -.151 L -.076 -.117 L -.184 .023 L .116 -.198 L .16 .012 L .22 .094 L .177 .221 L .013 .304 L h 662.661 219.065 m -.312 -.099 L -.203 -.127 L -.062 -.169 L .03 -.212 L .256 -.198 L .315 -.036 L .17 .092 L .053 .212 L .182 .098 L .305 -.145 L .34 .105 L .104 .151 L -.012 .451 L .183 -.148 L .163 -.304 L .318 -.029 L .229 .226 L .021 .424 L .181 -.036 L .062 .104 L -.025 .397 L -.316 -.211 L -.311 -.058 L -.141 .058 L .072 .155 L -.852 .157 L -.143 -.091 L .097 -.268 L -.085 -.059 L -.308 .269 L -.229 .256 L -.296 -.046 L -.63 .225 L -.624 .199 L -.357 -.051 L -.31 .123 L -.392 -.07 L -.103 -.07 L -.202 -.123 L -.063 -.279 L .143 -.261 L -.08 -.253 L .193 -.115 L .23 -.113 L .233 -.156 L .224 .07 L .61 .013 L .4 .104 L .089 .28 L .291 .109 L .294 .056 L .189 -.259 L .29 -.012 L .051 -.187 L -.263 -.15 L h 656.294 219.602 m -.393 -.282 L -.855 -.449 L -.118 -.269 L .417 -.001 L .514 -.185 L .462 -.029 L .925 .521 L -.338 .17 L -.232 .1 L -.381 .425 L h 631.053 200.125 m -.061 .225 L -.413 .439 L -.204 .41 L -.381 .354 L .164 .353 L .162 .169 L .806 .493 L .832 .055 L .241 .112 L .151 .381 L .128 .763 L -.007 .409 L .267 .423 L .212 .127 L .544 .041 L -.45 .933 L .151 .212 L .703 -.453 L .824 .252 L .177 .042 L .265 .254 L .144 .438 L .698 .676 L -.515 1.979 L -.04 .452 L .23 .946 L -.021 .438 L .021 .664 L -.002 .268 L -.149 1.06 L -.087 .156 L -.107 .07 L -.367 -.253 L -.381 -.522 L -.261 -.084 L -.262 .481 L -.081 .268 L -1.043 -.619 L -.219 .086 L .394 .747 L -.163 .213 L -.204 -.197 L -1.343 -1.424 L -.775 -.761 L -1.011 -.859 L -1.348 -.958 L -.391 -.451 L -.199 -.493 L -.191 -.339 L -1.003 -.633 L -.697 -.677 L -1.186 -1.509 L -.074 -.353 L .039 -.339 L -.324 -.875 L -.841 -1.467 L -.667 -1.044 L -.612 -.775 L -.369 -.301 L -.287 -.234 L -.64 -.295 L -.254 -.748 L -.688 -1.806 L .067 -.24 L -.107 -.311 L -.157 -.197 L -.662 -.507 L -.711 -.394 L -.539 -.21 L -.317 -.099 L -.119 -.353 L -.077 -.734 L -.18 -.409 L -.386 -.479 L -.818 -.831 L -.368 -.423 L -.725 .128 L -.613 -.676 L -.646 -.606 L -.593 -.69 L -.562 -.945 L -.229 -.635 L -.032 -.367 L .057 -.198 L .149 -.113 L .401 -.043 L .364 .098 L .25 .126 L .632 .563 L .361 .155 L .922 .153 L .335 .027 L .548 -.1 L .454 -.142 L .4 -.015 L .323 .31 L .919 1.156 L .513 .31 L .058 .155 L -.12 .537 L 1.066 .916 L .749 .493 L 1.175 .689 L .678 .323 L .139 .169 L .03 .593 L -.02 .155 L .573 .055 L .745 .944 L .612 .55 L .271 -.015 L .004 -.198 L -.123 -.226 L .069 -.24 L .507 .21 L .479 .804 L .441 .38 L .446 .056 L .429 .197 L .314 .366 L .28 .734 L .316 .437 L .431 .268 L .511 .126 L .767 .083 L .431 .154 L .494 .38 L .576 .606 L -.019 .071 L h 684.201 200.125 m -.007 -.172 L -.414 -1.058 L .18 -.551 L -.078 -.141 L -.141 -.296 L .036 -.325 L .286 -.89 L .514 -.82 L .263 .367 L .152 .353 L -.054 .283 L -.246 .396 L -.361 .763 L .061 .325 L .19 .141 L .097 -.141 L .436 -.411 L .135 -.522 L .179 -.142 L .806 -.412 L .141 .141 L -.052 .254 L .104 .55 L -.354 .212 L -.467 .354 L -.162 .311 L .159 .099 L .446 .126 L .398 .211 L -.016 .141 L .159 .353 L -.688 -.154 L -.431 -.154 L -.367 -.042 L -.304 .156 L -.08 .438 L .049 .258 L .131 .688 L .341 .62 L .405 .438 L .196 .282 L -.156 .212 L -.26 -.211 L -.664 -.648 L -.55 -.733 L -.002 -.396 L -.011 -.251 L h 637.361 207.144 m -.863 -.394 L -.377 -.239 L -.205 -.367 L -.045 -.367 L -.156 -.395 L -.507 -.395 L -.291 -.099 L -.446 .029 L -.116 -.141 L .271 -.65 L .234 -.24 L .509 .55 L .148 -.467 L .313 -.269 L .072 .395 L .312 .89 L .648 .817 L .698 .31 L -.265 .184 L -.118 .283 L .183 .564 L h 634.321 215.345 m -.091 -.187 L .316 -.023 L .402 .093 L .369 -.129 L .068 -.524 L .018 -.14 L .309 .057 L -.043 -.5 L .222 -.235 L .093 -.277 L .202 .121 L .631 .112 L .474 -.047 L .237 .443 L .524 -.089 L .158 -.297 L .022 -.244 L .259 .116 L .618 .168 L .411 .438 L .338 -.046 L .204 .271 L .446 -.029 L .453 -.185 L .302 .211 L .369 .522 L .179 .521 L .884 .041 L .462 .188 L .49 -.077 L 1.435 .124 L .479 -.029 L .34 -.17 L .213 -.65 L .271 -.269 L .447 -.015 L .223 .211 L .289 .494 L .633 .125 L .53 .027 L .774 .083 L .796 .153 L .289 .24 L .293 .288 L -.08 .445 L .275 .466 L .119 .099 L .877 .352 L .422 .069 L .658 .013 L .45 -.185 L .415 -.015 L .628 .238 L .048 .197 L -.255 .425 L -.152 .494 L .578 .776 L -.499 -.211 L -.802 -.196 L -.599 -.253 L -.891 -.309 L -.528 .001 L -.589 .256 L -.348 .057 L -.714 -.098 L -1.454 -.138 L -1.47 -.138 L -.805 -.253 L -.839 -.479 L -1.099 -.336 L -1.125 -.267 L -.948 -.04 L -.556 .298 L -.445 .043 L -.957 -.153 L -.805 -.492 L -.357 -.07 L -1.606 -.066 L -.363 -.155 L .055 -.141 L .448 -.468 L -.402 -.267 L -.551 -.099 L -.506 -.14 L -.307 -.027 L -1.261 -.121 L h 675.004 223.092 m .249 -.494 L .023 -.537 L .113 -.312 L .674 -.481 L 1.447 -.624 L .662 -.454 L .36 -.607 L .466 -.157 L 1.578 -.102 L .91 -.214 L .541 -.044 L .869 -.143 L .118 .07 L .099 .197 L -.237 .212 L -.36 .256 L -1.609 .61 L -1.369 .44 L -.713 .256 L -.606 .354 L -1.09 .963 L -.653 .481 L -.439 .086 L -.552 .228 L -.48 .015 L h 667.866 223.149 m -.217 -.069 L -.917 -.605 L -.8 -.45 L -.347 -.099 L -.493 -.126 L -.292 -.197 L .108 -.212 L .371 -.142 L .992 -.03 L .502 -.114 L .35 .296 L 1.147 .746 L .265 .381 L -.125 .325 L -.246 .24 L -.299 .057 L h 661.819 191.241 m -.041 .09 L .319 .691 L -.23 .142 L -.546 .043 L -.579 .086 L .198 .226 L .115 .296 L -.169 .226 L .216 .211 L .235 .112 L .546 .832 L .536 .747 L .043 .198 L -.338 .721 L .075 .226 L .406 .465 L .743 .45 L .6 .493 L .551 .761 L -.465 .17 L -.75 -.026 L -.797 -.238 L -.337 .1 L -.387 .467 L -.354 .918 L -.08 .476 L -.046 .272 L .132 .649 L .116 .424 L -.133 .848 L -.256 0 L -.466 -.154 L -1.037 .963 L -.433 .65 L -.751 .608 L .443 .381 L .06 .396 L .17 .296 L -.685 .058 L .452 .578 L .009 .212 L -.103 .227 L -.547 .665 L -.206 .396 L -.127 .354 L -.529 .594 L -1.294 .61 L -.607 .284 L -.292 .198 L -.194 -.311 L .024 -.424 L -.33 -.804 L -.306 -.381 L -.265 -.184 L -.286 .029 L -.503 .523 L -.302 .029 L -.328 -.508 L -.313 -.197 L -.437 -.112 L -.387 -.451 L -.342 -.154 L -.35 .806 L -.135 .198 L -.381 .058 L -.356 -.112 L -.442 .128 L -.318 .354 L -.364 .071 L -.059 -.551 L .034 -.311 L -.314 -1.03 L -.336 .396 L -1.42 .44 L -.321 -.408 L -.639 .015 L -.281 .156 L -.303 .029 L -.058 -.649 L -.022 -.65 L -.267 -1.411 L -.012 -.48 L -.352 -.747 L -.406 -.409 L -.79 -.422 L -.146 -.141 L .555 -.354 L -.531 -.38 L -.258 -.296 L .188 -.735 L -.074 -.128 L -.278 -.478 L -.352 -.296 L .065 -.466 L -.125 -.593 L .182 -.65 L .133 -.353 L .424 -.58 L .303 -.806 L .318 .028 L .204 .11 L .288 .792 L .253 .295 L 1 .983 L .304 .083 L .446 .28 L .928 -.416 L .255 -.001 L .526 .223 L .543 .11 L .399 -.172 L .528 -.342 L .403 -.525 L .531 -.441 L .479 -.074 L .431 .11 L .557 .251 L .524 .223 L .559 .152 L .287 -.03 L .467 -.356 L .465 -.172 L .864 -.175 L .387 -.299 L .928 -1.785 L -.076 -.748 L .218 -.34 L .646 -.244 L .22 -.383 L -.106 -.988 L .119 -.565 L .381 -.638 L .247 -.157 L .464 -.017 L .748 .081 L .651 .081 L .624 -.018 L .446 .04 L .753 .292 L .182 .09 L h 666.561 200.125 m .012 -.049 L .48 -1.188 L .434 -.41 L .289 -.142 L .429 .338 L .29 -.311 L .162 -.325 L .293 -.481 L .496 -.058 L .605 .14 L .729 .535 L .447 .027 L .863 -.044 L .478 .168 L .749 .267 L .577 -.227 L 1.853 .081 L .72 -.128 L .627 -.354 L .211 -.283 L -.156 -.268 L .196 -.283 L .388 -.241 L .295 -.41 L .289 -.057 L .075 .24 L -.073 .537 L -.117 .311 L -.081 .127 L -.082 .127 L -.969 1.259 L -.416 .396 L -.464 .1 L -1.23 .229 L -.495 -.069 L -.591 -.422 L -1.149 -.068 L -1.151 .059 L -.878 -.041 L -1.039 .045 L -.575 -.083 L -.671 .029 L -.415 .1 L -.433 .368 L -.259 .461 L -.154 .274 L -.187 .721 L .068 .48 L .263 .494 L .194 .183 L .403 .226 L .259 .196 L .221 .607 L .179 .154 L .226 .042 L .815 .026 L .249 -.269 L .652 -.976 L .385 .056 L .307 .183 L .496 .041 L .363 -.227 L .669 -.156 L .62 -.143 L .268 -.298 L .271 -.057 L .466 .196 L .131 .212 L -.083 .734 L -.469 -.267 L -.544 -.042 L -.361 .298 L -.389 .523 L -.438 .425 L -1.059 .439 L -.214 .325 L -.143 .029 L -.241 -.042 L -.468 -.126 L -.03 .056 L .025 .312 L .212 .126 L .676 .578 L .467 .521 L .854 1.24 L -.097 .325 L -.156 .679 L .102 .409 L .447 .535 L .555 .438 L .062 .226 L -.045 .282 L -.436 -.056 L -.652 .059 L -.412 .297 L -.224 .692 L -.498 -.026 L -.461 -.183 L -.107 -.17 L .052 -.649 L .204 -.58 L -.978 -.845 L -.417 -.31 L -.174 -.269 L .036 -.24 L .284 -.396 L .116 -.579 L -.165 -.494 L -.737 -.055 L -.503 .213 L -.494 .396 L .16 .353 L .143 .932 L -.068 .509 L -.236 1.145 L .363 .903 L -.01 .311 L -.377 .636 L -.019 .227 L .275 .564 L -.726 .171 L -.513 .241 L -.476 .071 L -.245 -.324 L -.16 -.522 L .156 -.325 L .181 -.466 L .069 -.876 L .06 -1.073 L -.125 -.509 L .029 -.339 L -.213 -.395 L -.311 -.127 L -.391 .171 L -.574 .029 L .011 -.41 L -.25 -1.284 L .131 -.311 L .491 -.524 L .469 -.777 L .161 -.48 L -.089 -.918 L -.006 -.254 L .087 -.452 L .339 -.721 L .447 -.058 L -.043 -.861 L .254 -1.053 L +341.05 41.069 N 2.084 .272 L .344 .361 L -.869 .174 L -.541 .139 L -1.678 .106 L -1.159 .037 L -.689 .156 L -.372 .224 L -.308 .6 L -.361 .376 L 1.05 .39 L .971 .168 L 2.117 .064 L .601 -.001 L 1.775 -.242 L 1.93 -.038 L .866 .135 L .933 .219 L .417 .135 L .284 -.018 L 1.001 -.002 L 1.277 .032 L .615 .05 L -1.277 .626 L -1.583 .457 L -1.976 .523 L -.556 -.016 L -.695 -.116 L -.951 .671 L -1.061 .503 L -1.246 .452 L -1.125 .296 L -.211 .056 L -2.212 .054 L -.525 .134 L -.502 .001 L -.982 .201 L -.665 .167 L -.528 .051 L -.946 -.413 L -.375 .05 L -.69 .913 L -.958 .118 L -.631 -.065 L -.743 -.197 L -.622 -.463 L -.854 -.43 L -.647 -.215 L -.109 0 L .008 .2 L .707 1.043 L -.192 .249 L -.319 .017 L -.69 .249 L -.84 .249 L -.573 .38 L -1 .906 L -.657 .657 L -1.051 .851 L -.776 .262 L -1.034 .083 L -1.023 -.275 L -.148 .554 L -.438 .569 L -.783 .277 L -.992 -.095 L -.616 .05 L -1.18 .439 L .942 -1.723 L -.121 .017 L -.795 -.015 L -1.055 -.177 L .26 .423 L -.026 .455 L -.386 .407 L -.794 .39 L -1.16 .164 L -.973 .002 L -1.255 .083 L .467 .403 L .212 .403 L -.09 .387 L -.379 .097 L -.321 -.063 L -.47 .033 L -1.792 -.157 L .517 .32 L .765 .462 L .295 .351 L -.01 .224 L -.26 .176 L -1.197 .034 L -1.051 .129 L .844 .413 L .47 .126 L .448 .222 L .389 .333 L -.554 .461 L -.285 .111 L -.599 -.094 L -.478 .096 L .345 .474 L -.009 .127 L 308.501 60 l -.486 -.125 L -.583 -.062 L .026 .158 L .255 .457 L -.101 .347 L -.288 0 L -.656 -.093 L -.089 -.016 L -.979 .112 L -1.081 .018 L .682 .487 L 1.108 .391 L .331 .204 L -.077 1.035 L -.382 .938 L -.427 .094 L -.815 -.061 L .489 .591 L -.016 .498 L .156 .233 L -.068 .373 L -.316 .062 L -.495 -.03 L -.771 .079 L .762 .386 L .427 .603 L -.117 .447 L -.287 .031 L -.967 -.26 L -1.052 -.508 L -.498 .294 L -.425 .602 L -.635 -.599 L .158 -.573 L -.387 -.201 L -1.124 -.184 L -.577 -.309 L .04 -.187 L .253 -.249 L .066 -.218 L -.325 -.28 L -.366 -.186 L -.668 .359 L -.276 .016 L -.3 .141 L -.444 -.046 L -.98 .064 L -.417 .017 L -.571 .296 L -.476 .28 L -.426 -.403 L -.104 -.357 L -.222 -.217 L -.513 -.233 L -.817 -.232 L -.772 -.389 L -.517 -.781 L .07 -.737 L -.199 -.156 L -.434 -.094 L -.467 .048 L -.97 -.266 L -.108 -.094 L -.138 -.236 L .14 -.457 L .459 -.395 L .071 -.269 L -.258 -.062 L -.551 -.031 L -.542 -.094 L -.278 -.221 L -.058 -.633 L -.458 -.126 L -.616 .049 L -.589 -.57 L .023 -.191 L .198 -.254 L .618 -.367 L 1.22 -.337 L .405 -.304 L .476 -.128 L .051 -.383 L -.277 -.287 L -.473 .097 L -.921 .082 L -.493 .097 L -.635 .416 L -.538 .129 L -.63 .304 L -.339 -.318 L .038 -.623 L -.114 -.784 L -.206 -.451 L .015 -.355 L -.243 -.323 L -.504 .082 L -.271 -.032 L -.666 -.355 L -.594 -.485 L -.013 -.357 L .842 -.538 L .265 .019 L -.556 -.189 L -1.083 .064 L -.103 -.284 L .383 -.176 L .677 -.03 L .586 -.052 L .456 -.087 L .322 -.672 L -1.208 -.047 L -.572 .05 L -.362 -.032 L -.29 -.163 L -.116 -.197 L .223 -.28 L .218 -.008 L .18 -.16 L .427 -.055 L -.375 -.188 L -.552 .073 L -.22 -.248 L .057 -.188 L .073 -.132 L .259 0 L .309 -.099 L .827 -.25 L 1.218 .081 L .854 .163 L .776 .032 L .378 .131 L .927 .146 L 1.027 .097 L -.031 -.363 L .299 -.545 L -.298 -.182 L -1.02 -.263 L -1.356 -.312 L -.903 -.164 L -1.592 -.33 L -.354 -.116 L .336 -.35 L .788 -.001 L 1.462 .363 L 1.034 .048 L .463 -.067 L .114 -.067 L .088 -.6 L .088 -.301 L .595 -.034 L .528 .116 L .227 -.101 L -.027 -.351 L -.195 -.184 L -.891 -.317 L .162 -.437 L .528 -.455 L -.258 -.286 L -1.21 -.167 L -1.154 .002 L -1.178 -.286 L -1.649 -.49 L -.78 -.101 L -.903 -.05 L -.76 -.34 L -.811 -.477 L .156 -.035 L .323 -.155 L .605 -.001 L .572 -.019 L 2.085 .305 L .716 .033 L 1.249 .306 L 1.451 .458 L .729 .169 L .056 -.307 L -.311 -.426 L -.86 -.546 L -.172 -.446 L -.603 -.446 L -.485 -.051 L -.677 -.24 L .361 -.277 L .542 -.139 L 285.644 41 l -.704 -.241 L -1.101 -.015 L -.625 -.086 L -1.132 -.327 L -.88 .608 L -.324 .156 L -.274 .294 L -.875 .243 L -1.402 -.066 L -1.031 -.343 L -.306 -.242 L -.027 -.294 L .438 -.313 L .293 -.645 L -.152 -1.259 L .582 -.054 L .691 .192 L .372 -.124 L .151 -.334 L -.383 -.369 L -.933 -.545 L -.452 -.141 L -.946 -.796 L -.895 -.925 L -1.105 -1.289 L -.578 -.485 L -1.855 -.379 L -.667 -.255 L -.291 -.202 L -.052 -.701 L -.904 -.406 L -.962 -.109 L -1.589 -.165 L -1.928 -.425 L -1.903 -.333 L -2.133 -.183 L -.997 -.054 L -1.632 -.035 L -.785 .189 L -1.043 .096 L -.806 .188 L -1.419 .152 L -1.228 -.166 L -1.46 -.296 L .319 .747 L -.051 .093 L -1.051 -.017 L -1.294 -.184 L -3.168 -.611 L 1.538 -.566 L .463 -.114 L -.092 -.226 L -.423 -.169 L -1.067 -.017 L -2.21 -.015 L -.812 -.074 L -.629 -.018 L -1.238 -.434 L -.87 -.208 L .587 -.306 L 1.257 -.041 L 3.036 .147 L 2.025 .034 L 1.343 .017 L 2.117 -.157 L 1.055 -.212 L .292 -.096 L .054 -.345 L -.627 -.287 L -.82 -.21 L -1.217 .156 L -1.11 .252 L -1.31 .021 L -1.138 -.113 L -.753 .078 L -.879 .098 L -.68 -.056 L -.857 -.19 L -.664 -.365 L -.816 -.191 L -.662 -.057 L -.726 .059 L -.486 -.076 L -1.416 -.481 L -.044 -.35 L .36 -.45 L .81 -.119 L 1.235 -.1 L 1.517 -.14 L 2.074 -.161 L 1.29 -.081 L .951 -.396 L 1.089 -.259 L .843 -.081 L 2.478 -.005 L 1.101 -.101 L 1.942 .036 L .402 -.139 L .31 -.199 L .609 -.16 L .202 -.658 L .276 -.501 L .116 -.101 L -.89 -.228 L -1.947 -.039 L -1.155 .194 L -.959 -.125 L -1.243 -.383 L .595 -.781 L 1.38 -.332 L 2.845 -.359 L 1.407 -.225 L 1.962 -.249 L 2.112 -.162 L 1.163 .087 L 1.213 -.07 L 1.319 -.07 L .345 -.181 L .011 -.226 L -.357 -.753 L -.022 -.208 L .522 -.14 L 1.886 -.05 L 1.526 .205 L 2.141 .41 L 1.296 .226 L .802 .181 L .823 -.275 L -1.657 -.525 L -.697 -.509 L .167 -.047 L 2.2 -.122 L 1.166 -.12 L 1.854 -.216 L 2.52 -.195 L .73 .069 L 1.064 .116 L .232 1.738 L .913 -.162 L .539 -.322 L .432 -1 L 1.003 .021 L 2.004 .323 L 1.858 .414 L 1.529 .25 L .205 -.3 L -.644 -.3 L -.816 -.537 L -.894 -.4 L .295 -.287 L .742 .022 L 1.758 .02 L 1.136 .212 L 2.754 .373 L 1.284 .279 L 2.109 .322 L 1.878 .274 L 1.872 .204 L .8 -.209 L .816 -1.483 L -.326 -.191 L -1.292 -.334 L -1.176 -.533 L .708 -.247 L 2.404 -.005 L 2.962 -.328 L 1.329 -.077 L 1.527 .17 L 2.221 .488 L 1.567 .167 L 2.005 .142 L .3 -.761 L -.3 -.472 L 2.646 -.206 L 2.021 -.08 L 2.589 .095 L 1.989 .146 L 1.886 -.18 L 2.367 -.207 L 2.043 -.005 L 1.859 .223 L 1.825 -.055 L 1.315 .072 L .619 .099 L .55 -.102 L 1.946 .146 L 1.707 .046 L 1.673 .096 L 2.438 .761 L 1.368 .241 L 1.345 -.076 L 1.118 .168 L 2.594 .237 L .445 .408 L -.304 .12 L -.492 .192 L -1.683 .146 L -2.303 .124 L -1.152 .121 L -1.233 .05 L -1.469 -.068 L -2.831 -.064 L -2.22 -.066 L -1.389 .168 L -1.614 .027 L -1.933 .027 L -1.16 .026 L -1.485 .168 L -.444 .118 L -1.322 .213 L -.335 .464 L .743 .251 L 2.551 -.281 L 1.367 -.072 L 3.912 .038 L 2.223 -.12 L 2.331 -.005 L .997 -.025 L .93 .067 L 1.77 .434 L .671 .09 L 1.087 -.186 L 1.663 -.21 L 1.536 -.281 L 1.964 -.144 L .59 .462 L -.566 .482 L -2.316 .639 L -.973 .338 L -1.281 .734 L .12 .307 L .319 .152 L .796 -.089 L .477 -.044 L 1.616 -.553 L 1.766 -.537 L 1.413 -.385 L 1.706 -.32 L .775 -.207 L 1.662 -.163 L 1.618 .111 L 1.391 .065 L 1.497 -.3 L .703 -.324 L 1.129 -.234 L 2.148 -.004 L 1.672 .112 L 1.097 .044 L 1.197 .136 L 1.135 .228 L 1.107 .112 L .316 .25 L -.181 .273 L -1.97 .252 L -1.491 .138 L -1.245 .494 L -.557 .289 L -1.604 .355 L -1.57 .548 L -1.063 .089 L -.918 -.042 L -1.592 .047 L -2.213 -.039 L -1.491 .198 L -.731 .217 L -.495 .535 L .166 .322 L 1.949 -.305 L 1.581 -.046 L 1.856 .101 L .003 .42 L -.743 .241 L -2.388 .124 L -.463 .14 L -.213 .199 L -.156 .595 L -.471 .71 L -.678 .158 L -1.06 -.077 L -.742 .041 L -.837 .9 L -.987 1.087 L -.15 .347 L .454 .307 L .403 .095 L .602 -.481 L .743 -.368 L .856 -.041 L 2.345 .266 L .353 .096 L .262 .288 L -.059 .211 L -1.234 -.074 L -.673 -.018 L -.512 .097 L -.136 .191 L .29 .286 L 1.756 .188 L .557 .132 L 1.802 -.137 L .526 .208 L .214 .323 L -.049 .436 L -.256 .133 L -1.835 -.186 L -1.653 -.054 L -.781 -.074 L -1.295 .078 L -1.382 .475 L -.823 -.13 L -.49 -.15 L -1.06 .04 L -.283 .377 L 1.393 .599 L 1.187 .222 L 1.298 .128 L 1.665 .072 L .696 .148 L .551 .482 L .272 .444 L .014 .554 L -.434 .405 L -.384 .074 L -1.292 -.181 L -.82 -.109 L -.372 .111 L .023 .55 L .118 .236 L .426 .162 L .618 .089 L .723 .215 L .914 .142 L .752 .16 L .383 .376 L -.338 .233 L -.832 .145 L -.647 .126 L -1.747 -.032 L -1.176 -.087 L -1.624 -.086 L -.592 .448 L .551 .195 L 1.396 .051 L 1.052 .158 L .724 .248 L .088 .319 L -.035 .549 L -.13 -.005 L -1.092 -.045 L -1.247 .108 L -.596 .266 L -1.246 .02 L -1.225 -.139 L -1.497 -.404 L -.922 -.478 L -.373 -.07 L -1.094 .286 L 345 36.811 l -1.084 .09 L -.589 .178 L -1.451 -.033 L -.913 -.087 L -.969 .143 L -.395 .125 L -.174 .283 L .006 .141 L .354 .527 L .71 .245 L 1.284 .05 L 1.515 .26 L 1.567 -.056 L 1.323 .54 L .758 .226 L .482 .226 L 1.196 .329 L 1.252 .38 L .376 .276 L .483 .898 L .892 -.208 L .278 -.139 L .397 .207 L .298 .43 L .071 .344 L .198 1.164 L -.169 .205 L -.371 .12 L -.541 -.101 L -.546 -.119 L -.917 .002 L -1.041 .036 L -1.488 -.27 L -.637 -.409 L -.415 -.634 L -.354 -.274 L -1.17 -.566 L -.84 -.292 L -.748 -.137 L -1.095 -.084 L -.521 .14 L -.962 .105 L h 351.365 40.026 m -1.527 -.537 L -.96 -.225 L -.712 -.156 L -.159 -.069 L -.314 -.419 L 1.483 -.038 L .893 .139 L 1.064 .26 L .819 .296 L .162 .488 L -.215 .209 L -.533 .053 L h 281.574 46.135 m -.568 -.133 L -.707 -.318 L -.801 -.183 L -.197 -.101 L -.25 -.218 L -.08 -.844 L .287 -.34 L .368 -.018 L .646 .135 L 1.157 .066 L 1.287 .27 L .748 .269 L .595 .1 L .777 .217 L .603 .335 L -.144 .202 L -.112 .034 L -.543 .051 L -.774 .035 L -.77 .186 L -1.009 .153 L -.511 .102 L +105.98 81.688 N -.952 -.826 L -.198 -.342 L -.024 -.476 L .095 -.104 L .408 .044 L .312 -.045 L .781 .177 L .658 -.076 L .28 .119 L .138 .163 L -.234 .224 L -.173 .565 L -.028 .312 L -.581 .075 L -.483 .19 L h 125.24 92.375 m -1.312 -.288 L -1.345 -.434 L -.218 -.174 L .061 -.189 L .376 -.466 L -1.023 .002 L -.413 .248 L -.299 -.072 L -.416 -.188 L .166 -.452 L -.487 -.334 L -.269 -.014 L -.735 -.086 L -.226 -.262 L .317 -.292 L -.976 -.524 L -.556 .118 L -.386 -.102 L -.852 -.511 L -1.277 -.863 L -.219 -.235 L .02 -.117 L .962 -.12 L .337 .043 L 1.979 .598 L .981 .204 L 1.772 .202 L .385 .263 L .618 .526 L .426 .642 L .433 .422 L .362 .189 L 1.587 .536 L .316 .203 L .48 .756 L .116 .407 L -.279 .349 L -.407 .016 L h 271.379 92.089 m -1.202 -.23 L .641 -.743 L .358 -.161 L .279 .058 L .292 0 L .355 -.263 L -.697 -.653 L .079 -.219 L 272 89.003 l 1.121 -1.35 L 1.454 -1.31 L .725 -.442 L .496 -.192 L 1.315 -.194 L .198 .073 L .11 .221 L -.299 .221 L -.582 .03 L -.242 .133 L .349 .44 L -.755 .78 L -1.226 1.438 L -.271 .526 L .113 .291 L .11 0 L .428 -.176 L .483 -.555 L .458 -.191 L 1.115 .305 L -.896 .687 L .261 .203 L .229 .072 L 1.423 .565 L .758 -.03 L .325 -.408 L .309 -.059 L .718 .057 L .826 .202 L .616 .231 L -.297 .292 L -.373 .233 L -.708 .467 L .339 .333 L .477 .362 L .26 .014 L .417 -.161 L .464 -.132 L .278 .116 L .02 .16 L -.254 .262 L -.404 .248 L -.892 .104 L 280.84 93 l .273 .362 L .124 .405 L .28 .231 L .183 -.203 L .309 -.262 L .527 .159 L -.099 .449 L .149 .275 L .716 .028 L .085 -.015 L .015 .203 L -.168 .304 L -.25 .652 L -.34 .651 L -.222 -.072 L -.71 -.128 L -.301 -.144 L -.042 -.651 L -.601 .406 L -.374 .015 L -.095 -.274 L .497 -.652 L .011 -.333 L -.421 -.478 L -.279 -.072 L -.388 .392 L -.423 .291 L -.365 .146 L -.435 .204 L -.552 .536 L -.496 .334 L -.881 -.042 L -.222 -.217 L .165 -.145 L 1.229 -.408 L .466 -.522 L .632 -.363 L -.699 -.129 L -.601 -.057 L -.322 .464 L -.412 .015 L -.13 -.159 L .04 -.493 L -.757 .016 L -.148 .29 L -.41 .218 L -1.052 .045 L -.709 -.057 L -1.139 -.186 L -1.012 -.085 L -1.355 .061 L -1.014 .147 L -.145 -.188 L -.215 -.463 L .187 -.175 L .561 -.334 L .734 -.408 L .502 -.161 L .636 -.335 L h 265.435 98.655 m -.469 -.057 L -.497 -.273 L -.356 -.562 L .062 -.635 L .742 -.738 L .932 -1.043 L .816 .432 L -.375 .435 L -.112 .462 L -.233 .333 L -.262 .116 L -.58 .319 L -.244 .448 L .522 .244 L .168 -.029 L .279 -.26 L .42 -.362 L .617 -.319 L .309 .057 L .495 .461 L -.177 .347 L -.246 .159 L -1.134 .42 L -.682 .044 L h 211.34 59.677 m -.68 -.046 L .068 -.872 L -.375 -.333 L -.958 .161 L -2.375 .29 L .107 -.461 L .56 -.303 L 1.644 -.561 L -.302 -.478 L -.102 -.415 L .106 -.417 L .398 -.835 L .434 -.566 L .254 -.648 L .331 -.471 L 1.11 .566 L -.312 .518 L .791 .386 L .527 .047 L .402 -.469 L .67 .112 L .806 .289 L .917 .514 L .582 .255 L 2.168 .492 L .442 .271 L .176 .255 L -.09 .925 L .539 .047 L .57 -.065 L .934 .046 L .701 .142 L 1.019 .427 L -.419 .096 L -.269 .127 L -.46 .271 L -.949 -.046 L -.623 -.125 L -1.328 -.125 L -.438 -.126 L 217.259 58 l -.528 -.301 L -1.017 -.237 L -.528 .017 L -.203 .271 L .174 .588 L -.126 .096 L -1.314 .161 L -.673 .493 L -.588 .302 L -1.116 .287 L h 200.125 19.1 m -.862 -.015 L -1.085 -.195 L -.308 -.664 L .819 -.304 L .77 -.072 L .666 -.024 L 3.475 -.125 L 1.263 -.12 L 1.374 -.026 L 1.714 .324 L .397 -.094 L .397 -.377 L 1.303 -.287 L 1.759 -.099 L 1.975 .209 L .746 -.001 L 2.562 .137 L 2.621 .324 L 1.424 .09 L 1.461 .161 L .448 -.165 L -1.433 -.42 L -1.67 -.352 L -.816 -.429 L .293 -.242 L 1.361 -.148 L 1.101 -.246 L 1.431 -.101 L 2.382 -.201 L 1.666 .119 L 1.944 .191 L 1.009 .265 L 1.19 .456 L .354 .047 L .273 -.362 L -.959 -.508 L -.828 -.292 L .499 -.248 L 1.45 .121 L 1.832 .168 L 1.653 .07 L 1.639 .46 L .378 .023 L .062 -.195 L -.301 -.539 L 1.781 -.004 L 1.408 .046 L .832 .269 L .831 .34 L .618 -.001 L -.044 -.268 L -.331 -.467 L 1.075 -.077 L 3.691 .386 L 2.726 .288 L 1.937 -.077 L 2.987 .018 L .967 .047 L .757 .12 L .126 0 L 1.419 .094 L 1.089 .191 L .744 .095 L 1.685 .044 L 1.357 .357 L -.385 .358 L -1.237 .121 L -1.206 .356 L -1.849 .191 L -.978 -.045 L -2.191 -.159 L -2.284 .005 L -.776 .142 L -1.915 .168 L -.597 .465 L .75 .366 L .761 .044 L 1.03 -.048 L 1.705 -.279 L .79 .021 L .808 .434 L -.168 .114 L -1.246 .139 L -1.38 .207 L -1.174 .295 L -2.098 .518 L -1.316 .224 L -1.19 .355 L -.924 .286 L -2.252 .005 L .65 .906 L -.449 .193 L -2.297 .455 L -.768 -.019 L -1.587 -.037 L -1.462 -.218 L -2.386 -.164 L -.66 .33 L 2.591 .695 L -.662 .141 L -.967 -.038 L -1.297 .022 L -1.068 .022 L -2.58 -.214 L -2.009 .063 L -.134 .66 L 1.257 -.105 L 1.065 .018 L 2.312 .292 L .557 .157 L .12 .67 L -.33 .197 L -1.031 .12 L -.515 .705 L -1.073 .021 L -.448 -.058 L -.402 .176 L .297 .253 L .759 .25 L -.328 .136 L -1.615 .08 L -.867 -.037 L -1.71 -.171 L -.422 .078 L .41 .791 L -.08 .231 L -.649 .289 L -.767 .155 L -1.52 -.112 L -2.039 -.111 L -1.43 -.227 L -1.008 .079 L -1.219 .5 L 1.031 .112 L .368 .057 L 2.154 .11 L 1.759 .13 L 1.534 .168 L 2.001 .034 L .66 .34 L .045 .359 L -.907 .398 L -2.685 .268 L -.927 .115 L -1.054 .227 L -1.115 .077 L -.467 -.28 L -.797 -.638 L -.56 .039 L -.631 .001 L -1.453 -.318 L -.001 .17 L .331 .508 L -1.477 -.016 L -1.5 -.129 L -.875 -.319 L -1.033 -.471 L -.388 .058 L .527 .717 L -.24 .17 L -.821 .133 L -1.72 -.109 L -2.276 -.033 L -.972 -.073 L -1.382 -.394 L -.642 -.131 L -.282 .453 L -.619 .152 L -1.843 -.316 L .161 -.586 L .219 -.228 L 1.525 -.117 L .61 -.249 L .961 -.173 L 1.179 .036 L .499 -.172 L -1.073 -.4 L -1.043 -.651 L .052 -.154 L .479 -.117 L 1.316 .036 L 1.743 .093 L .888 .21 L 1.108 .517 L 1.35 .323 L 1.085 .093 L 1.667 -.022 L .829 -.136 L .086 -.268 L .514 -.304 L -3.019 .001 L -1.025 -.171 L -.156 -.85 L .211 -.154 L -1.74 -.153 L -1.963 -.152 L -.274 0 L -.631 .114 L .204 -.758 L 1.159 -.551 L 1.104 -.16 L 1.837 -.003 L 1.164 .037 L 1.37 .076 L 2.023 .311 L 1.342 .115 L .486 -.158 L 1.132 -.041 L -3.399 -.802 L -1.742 -.313 L -3.555 -1.27 L -.406 .242 L -1.398 -.878 L .025 -.258 L .313 -.108 L 1.747 .104 L 1.905 -.004 L 2.019 .06 L 1.6 .382 L 2.535 .784 L 1.448 -.043 L .833 .095 L -1.387 -.555 L -2.015 -.317 L 1.208 -.743 L 1.456 -.329 L 1.731 -.025 L 1.529 -.222 L 2.042 -.07 L 1.157 -.112 L 1.414 -.051 L -1.778 -.479 L -1.425 -.153 L -2.501 .027 L -1.243 .248 L -1.305 .158 L -1.425 .202 L -1.447 .047 L -.586 .067 L -1.532 -.438 L -.214 .111 L -.543 .156 L -2.16 -.018 L -1.58 .365 L .311 -.828 L .98 -.292 L .007 -.202 L -.606 -.247 L -1.375 -.156 L -1.39 .003 L -4.189 .505 L -2.031 .672 L -.408 -.11 L -.569 -.251 L .395 -.133 L .678 -.023 L -.117 -.316 L -.698 -.398 L -1.216 -.056 L -.216 -.003 L h 200.125 20.844 m .899 -.096 L .832 .196 L .339 .5 L .511 .495 L .427 .063 L 1.141 .041 L -.081 -.236 L .056 -.411 L .438 -.109 L .718 .194 L .718 .322 L .374 .3 L -.066 .171 L .056 .826 L .764 .442 L .953 -.017 L 1.276 -.074 L 1.646 .504 L -1.123 -.264 L -1.528 .34 L -1.599 .221 L -.83 .377 L -.287 .197 L -.265 .315 L -.448 .021 L -1.493 -.41 L -.656 .335 L .465 .43 L -.029 .235 L -.412 .196 L -.392 .04 L -1.086 -.31 L -.944 -.311 L -.26 .645 L -.117 .068 L -.083 .049 L -.888 .041 L -1.74 -.094 L -1.458 -.153 L -.888 -.154 L -.494 .021 L -3.115 -1.31 L -.191 -.276 L 1.971 -.241 L 3.32 .093 L .889 .097 L 1.573 .1 L -2.485 -.693 L -3.019 -.213 L -1.103 .122 L -1.43 -.017 L -.597 .18 L -1.008 .022 L -.606 -.198 L -1.066 -.517 L -1.425 -.479 L -.341 -.355 L 1.971 .124 L 2.278 -.175 L -1.255 -.249 L -.756 -.351 L .38 -.305 L .729 -.132 L .769 -.023 L .921 .042 L .156 -.219 L -1.799 -.793 L 1.053 -.114 L 1.213 -.182 L 1.13 .087 L .584 -.046 L .145 -.18 L -.514 -.475 L 1.362 .134 L .941 .066 L .83 .202 L 1.589 .869 L .653 .264 L .772 .24 L .674 -.001 L .36 -.039 L h 179.067 27.216 m -1.156 -.056 L -.604 -.173 L -.926 -.638 L -.621 -.193 L -3.102 -.091 L -1.487 .081 L -.622 .001 L -1.444 -.056 L -.767 -.154 L -1.019 -.37 L -.161 -.234 L .335 -.138 L .802 -.001 L 1.687 .232 L .867 -.021 L -.031 -.235 L -.252 -.275 L -1.344 -.49 L -.579 -.098 L -1.075 -.077 L -1.392 -.196 L .065 -.397 L 2.246 -.124 L 2.392 .155 L .77 .376 L .999 .453 L 1.979 .193 L 2.189 .114 L 1.178 .233 L .604 .254 L 1.123 .721 L .581 .446 L .168 .426 L -.481 .194 L -.919 .137 L h 185.907 26.758 m -1.078 -.037 L 184 26.529 l -1.029 -.484 L -1.144 -.76 L -.03 -.216 L .239 -.099 L 2.296 -.044 L 1.816 .311 L 3.101 .542 L -.047 .351 L -.254 .331 L -.436 .04 L -1.563 .177 L -1.043 .08 L h 156.886 26.865 m -1.573 .646 L -.558 .27 L -1.85 .042 L -1.019 .079 L -1.898 -.15 L -.577 -.114 L -.302 -.423 L .334 -.291 L 1.365 -.177 L .899 .056 L 2.351 -.102 L .496 0 L 2.331 .163 L h 132.902 31.305 m -.53 -.186 L -.95 -.466 L -.424 -.112 L -.33 .057 L -.56 .207 L -1.269 .059 L -.786 -.279 L -.283 -.319 L .23 -.264 L 1.13 -.097 L .503 -.133 L .771 -.134 L .977 -.399 L .848 -.211 L .726 -.172 L .548 -.344 L 1.083 -.231 L 1.277 -.079 L 2.532 -.158 L 1.68 .016 L .888 -.29 L 1.038 -.079 L 1.503 .438 L -.756 .097 L -.852 .231 L -.22 .268 L .12 .266 L .469 .474 L -.777 .001 L -.912 .115 L -.918 .662 L -1 -.017 L -.867 -.981 L -.694 -.15 L -.379 .02 L -.229 .285 L -.588 .342 L -.63 .623 L -.595 .151 L -.284 .375 L -.705 .356 L -.787 .058 L h 191.827 30.313 m -1.266 -.054 L -2.278 -.165 L -.426 .058 L -.332 -.094 L -.896 -.489 L -1.185 -.414 L .192 -.229 L 2.433 -.042 L 1.542 .263 L 1.472 .054 L .171 0 L .89 .358 L -.179 .246 L .123 .32 L -.263 .188 L h 144.688 31.739 m -2.222 -.395 L -.325 -.674 L .503 -.057 L .595 -.17 L .945 -.096 L .953 -.133 L 1.279 -.059 L .522 .187 L .65 .374 L .659 .186 L 1.55 -.209 L .617 .149 L 1.624 .762 L 1.016 .351 L .897 .036 L .96 -.058 L 1.418 .09 L .591 -.02 L 1.116 -.169 L .092 -.297 L -.557 -.559 L -.941 -.391 L -1.347 -.354 L .96 -.322 L .524 -.379 L .569 -.152 L 1.097 -.116 L .507 .17 L .773 .678 L -.017 .413 L .518 .654 L .565 .111 L .9 .036 L 1.805 .406 L -.334 -.465 L .151 -.28 L .409 -.076 L 1.495 .24 L .932 .39 L -.292 .409 L .039 .5 L -.358 .461 L -.573 .277 L -.755 .111 L -.782 .001 L -1.682 .095 L -1.156 -.071 L -1.757 -.18 L -.622 -.017 L -1.129 .277 L -1.132 .202 L -.76 .182 L -.977 .254 L -1.625 .292 L -1.338 .2 L 149.23 34.5 l -.748 -.07 L -1.445 -.286 L -.276 -.378 L .648 -.128 L 1.219 -.038 L .738 -.146 L .852 -.075 L 1.166 -.057 L .622 .017 L 1.09 -.149 L .483 -.553 L -2.768 -.087 L -.925 -.054 L -1.564 .28 L -1.625 .168 L -1.292 .04 L -.795 .093 L -1.681 -.347 L -.479 .167 L -.92 .075 L -.979 -.127 L -.854 -.33 L .023 -.111 L .863 -.427 L 1.098 -.058 L 2.047 -.022 L .96 -.159 L h 178.479 33.234 m -.984 -.219 L -.193 -.294 L .764 -.389 L .433 -.112 L .088 -.167 L -.447 -.333 L -1.161 -.054 L -2.13 .227 L -.939 .076 L -.331 .019 L -.854 -.276 L .039 -.335 L .739 -.02 L .542 -.244 L .587 -.057 L -.466 -.598 L .176 -.245 L .132 -.226 L .49 .018 L .859 .224 L 1.942 .746 L .426 .186 L .46 -.094 L -.101 -.243 L -.959 -.486 L -.371 -.131 L -.407 -.357 L .436 -.095 L .956 -.059 L .713 .131 L 1.033 .262 L .572 .168 L .27 .018 L .162 -.452 L .478 -.133 L .73 .112 L .717 .168 L .327 .168 L .367 .75 L -.034 .616 L -.247 .242 L -.831 .335 L -.017 .352 L .35 .625 L -.361 .147 L -1.648 -.089 L -.862 .112 L -1.446 .003 L h 200.125 30.572 m -.895 .045 L -.853 .17 L -.37 .467 L 1.133 .054 L .984 -.038 L .046 -.001 L .847 .11 L .463 .129 L .498 .463 L .727 .424 L .621 .091 L .213 -.074 L .043 -.314 L .286 -.056 L 1.075 -.002 L .883 -.187 L .766 .11 L .835 .239 L .665 .257 L .976 .053 L .775 -.463 L 1.393 -.281 L 1.704 -.114 L 1.951 -.246 L 1.533 .053 L 2.59 .014 L .381 .037 L .79 .314 L .911 .239 L 1.418 .146 L .653 .128 L .21 .037 L .361 .166 L .181 .257 L -.4 .148 L -1.833 .407 L -.135 .255 L .469 .666 L -2.486 .076 L -.592 .02 L -.651 .091 L -.768 -.053 L -.846 -.16 L -.405 -.125 L -.306 -.667 L -.833 -.218 L -.366 .129 L .072 .723 L -.536 .127 L -.747 -.053 L -.91 .109 L -.728 -.017 L -.495 .001 L -1.342 -.213 L -.593 -.197 L -.495 -.017 L -.209 .433 L -1.801 .111 L -.831 .074 L -1.453 -.069 L -.404 -.251 L -.144 -.686 L -1.237 .129 L -.389 .181 L -.326 .325 L -.955 .2 L -1.011 -.034 L -.112 -.027 L -.704 -.169 L -1.186 -.575 L -.675 .489 L -1.131 -.07 L -.666 -.688 L -.442 -.717 L .587 -.481 L .019 -.371 L -.292 -.316 L -1.249 -.651 L -.617 -.299 L -.047 -.338 L .636 -.133 L 1.226 -.078 L 2.472 -.023 L .763 .093 L 1.118 .261 L .188 .04 L .872 .184 L -.613 .189 L -.259 .013 L h 128.19 41.985 m -.926 -.016 L -1.059 -.102 L -.362 -.466 L -.549 -.467 L -.432 -.259 L -1.123 -.363 L -1.36 -.067 L -.951 -.138 L -.469 -.19 L -.168 -.174 L .537 -.106 L .589 -.298 L .481 -.211 L .08 -.386 L -.437 -.809 L .552 -.001 L .468 -.177 L .307 -.372 L 1.104 -.533 L .526 -.588 L -.121 -.32 L -.271 -.16 L -1.229 -.677 L -.375 -.448 L .869 -.001 L .823 -.056 L 1.455 .051 L .97 .016 L 1.515 -.092 L 1.284 -.146 L 1.242 -.074 L .495 .125 L 3.242 .801 L .918 .088 L .708 -.055 L 1.316 -.127 L 1.223 .016 L .771 .07 L 1.35 .373 L 2.389 .815 L -.242 .143 L -.432 .036 L -.26 .072 L -1.609 .322 L -1.073 .144 L -1.829 .428 L -1.069 .319 L -1.604 .725 L -1.025 .563 L -.549 .089 L -.974 .124 L .066 .924 L -.271 .504 L -.662 .278 L -1.215 .124 L -1.213 -.067 L -.521 .485 L -.898 .312 L h 190.483 39.666 m -1.146 -.208 L -.146 -.524 L -.941 -.806 L -.207 -.582 L .058 -.389 L .27 -.657 L .377 -.321 L 1.256 .033 L -.089 -.16 L -.416 -.266 L -.185 -.286 L .211 -.09 L .234 -.072 L 2.154 -.058 L 1.215 .087 L 1.464 .248 L 1.282 .051 L 1.316 -.146 L 1.051 .016 L .694 .105 L .639 .213 L -.007 .089 L -.224 .179 L -.824 .428 L -.874 .746 L -1.513 .92 L -1.386 .073 L -2.379 -.154 L -1.269 .055 L 1.392 .717 L -.188 .315 L -.855 .369 L -.964 .072 L h 181.204 41.523 m -.491 -.085 L -1.101 -.552 L -.952 -.641 L -1.014 -.468 L -.978 -.225 L -1.438 -.12 L -.55 -.174 L -2.255 -1.066 L .866 -.654 L .653 .14 L 1.032 .474 L 1.063 .227 L .46 .052 L .615 -.283 L .908 -.619 L .415 -.036 L .018 -.212 L -1.062 -.565 L -1.068 -.424 L -.177 -.231 L .132 -.107 L 1.683 .086 L .711 -.215 L .42 0 L .996 .39 L .56 .035 L .58 -.055 L .435 -.25 L 1.232 -.127 L 1.354 .069 L .912 .23 L -.324 .268 L -.58 .125 L -.323 .338 L -1.55 .375 L -.392 .16 L -.069 .194 L .253 .247 L .506 .105 L .692 -.089 L 1.08 .174 L .868 .245 L .391 .017 L .564 .262 L .186 .438 L -.681 .352 L -.156 .35 L -.271 .68 L -.457 .366 L -.508 .14 L -.658 .019 L -.582 -.103 L -.773 -.346 L -.653 -.103 L .013 .208 L 1.054 .553 L -.817 .399 L -.77 .036 L h 243.524 60.394 m -.234 -.208 L -1.199 -.235 L -.673 -.331 L -.154 -.269 L .346 -.064 L .616 -.461 L -1.378 -.521 L -1.132 -.125 L -.76 -.349 L -.929 -.731 L -.035 -.511 L -1.115 -.062 L -1.311 -.366 L -.675 -.031 L .284 .767 L -.155 .096 L -.409 -.015 L -1.704 -.332 L -.309 .033 L -.325 .304 L -.441 .288 L -1.312 .082 L -1.349 -.173 L -1.343 -.189 L -.813 -.254 L -.052 -.319 L .196 -.4 L .382 -.354 L 1.066 -.163 L .192 -.178 L -.128 -.516 L .206 -.033 L 1.357 .11 L 1.408 .175 L .517 .144 L .962 .626 L .051 -.386 L -.154 -.193 L .077 -.194 L .585 -.033 L .977 -.099 L .652 -.163 L .649 -.114 L .515 .063 L .785 .031 L .166 -.275 L -1.138 -.825 L -.773 -.356 L -.119 -.228 L .167 -.163 L .586 -.066 L .72 -.246 L 1.409 -.591 L .361 -.541 L .771 -.46 L .493 -.379 L -.109 -.593 L -.899 -.841 L -.407 -.496 L -.541 -.364 L -.414 .001 L -1.258 -.33 L -1.041 -.481 L -.244 -.467 L -.527 -.384 L -.442 .202 L -.551 .202 L -.825 -.015 L -.293 .117 L -.62 .018 L -1.255 .169 L -.214 -.667 L 1.032 -.052 L 1.23 -.103 L .163 -.269 L -1.604 -.618 L -1.552 -.67 L -.879 -.015 L -.567 -.185 L -.169 -.542 L -.677 -.339 L -.45 -.05 L -.918 -.306 L -.687 -.341 L -.385 -.119 L -.611 .155 L -.81 -.187 L -1.177 -.238 L -.489 -.085 L -.379 .138 L .529 .307 L .453 .05 L 2.838 .712 L .438 .271 L .069 .306 L -.505 .221 L -.669 .069 L -.541 -.033 L -.757 -.049 L -.818 -.252 L -1.153 -.27 L -.667 -.066 L -.323 .17 L .044 .204 L .426 .236 L .259 .438 L -1.703 -.553 L -.47 -.05 L -.396 .119 L -.63 .153 L -.767 -.218 L -.693 -.117 L -.859 .12 L -1.474 -.184 L -1.995 -.167 L -1.321 .037 L -1.146 -.032 L -.862 -.186 L -.003 -.597 L -.363 -.153 L -.904 -.049 L -.396 .342 L -.623 .086 L -1.214 -.049 L -1.076 -.168 L -1.303 -.477 L -.415 -.376 L .123 -.275 L .868 -.07 L 1.131 .067 L 1.212 .101 L .879 -.019 L .312 -.19 L -.934 -.463 L -.8 -.275 L -.905 -.102 L -1.106 -.119 L -.752 .036 L -.539 -.017 L -1.249 -.223 L .114 -.416 L .292 -.557 L .34 -.14 L .646 -.054 L .081 -.227 L -1.082 -.4 L -.044 -.175 L .449 -.79 L 1.197 -.919 L .565 -.284 L .918 -.321 L .74 -.374 L .423 -.037 L .37 -.178 L .698 -.001 L .481 -.125 L .71 -.09 L 1.436 -.109 L 1.348 .033 L .857 .194 L -.92 .393 L -.815 .48 L -1.394 .639 L -.43 .529 L .169 .369 L 1.256 .541 L -.444 .298 L -.076 .402 L .257 .313 L .862 .554 L 1.559 .621 L -.096 .121 L -1.272 .331 L -.072 .31 L .959 .033 L 1.504 .101 L .654 -.639 L -.103 -.415 L -.343 -.277 L -.724 -.103 L -.422 -.138 L -.884 -.538 L .101 -.157 L .506 -.245 L .473 -.193 L 1.001 .12 L .837 -.071 L -1.204 -.47 L -.703 -.034 L -.793 -.279 L -.056 -.193 L .053 -.545 L .886 -.319 L 1.207 .086 L 1.509 -.056 L -.939 -.281 L -1.233 -.351 L .793 -.303 L 1.288 -.198 L 1.044 -.126 L 1.688 -.323 L 1.114 .016 L .642 .052 L .833 .141 L .782 .478 L 1.536 .97 L .058 .141 L -.583 .687 L -.709 .632 L .038 .733 L .364 .086 L .65 .033 L 1.088 -.315 L .284 -.455 L .595 -.088 L .791 .034 L .454 .174 L -.006 .262 L .16 .47 L .875 .189 L .196 -.122 L -.204 -.854 L .218 -.123 L .456 -.474 L 1.038 -.265 L .98 -.054 L .748 .034 L .98 .174 L 1.172 .138 L 1.151 -.09 L .688 .139 L .327 .262 L .621 .331 L .574 .191 L 235.438 40 l 0 .191 L -.531 .088 L -.484 .279 L -.818 .262 L -.148 .225 L .45 .259 L .427 .068 L .897 -.417 L .652 -.174 L .502 .051 L .476 .242 L .365 .466 L .516 .413 L .342 -.242 L 1.304 -.798 L 1.935 .256 L .915 .361 L -.051 .069 L -.638 .346 L -.708 .517 L 1.167 -.054 L .455 -.173 L 1.078 -.105 L .033 .704 L .797 .324 L .523 -.069 L .831 -.207 L 1.316 -.088 L .816 .221 L .566 .273 L -.162 .154 L -.461 .223 L -1.87 .43 L -.238 .272 L .523 .253 L .456 -.068 L .747 -.171 L 1.235 -.122 L .406 -.29 L .361 -.103 L .479 .067 L .51 .187 L .544 .339 L .636 .522 L -1.019 .002 L -1.2 .053 L -.424 .135 L .059 .269 L .372 .134 L 1.333 .065 L .938 .183 L .543 .217 L .233 .301 L -.37 .034 L -.748 .001 L -1.011 -.082 L -.875 -.216 L -.824 -.065 L -.316 .185 L 1.23 .583 L -.216 .201 L -1.552 .12 L .245 .283 L .437 .166 L .551 .032 L 1.331 .364 L 1.312 .347 L .247 .182 L .039 .282 L .351 .38 L .75 -.217 L .536 .049 L 1.413 .295 L .298 -.067 L .649 -.15 L .61 .032 L .752 .379 L .862 .477 L .376 .346 L -.685 .1 L -.801 .117 L -.027 .444 L .795 -.001 L 1.405 -.052 L .51 -.132 L .895 .048 L -.386 .559 L .918 .179 L .514 -.001 L .943 -.379 L .685 .343 L 1.089 .407 L .194 .098 L -.275 .229 L -.254 .099 L -.103 .326 L -.819 .05 L -.718 -.21 L -.247 -.048 L -.794 .213 L .968 .454 L .279 .162 L .057 .276 L -1.057 .197 L -.356 .228 L -.312 .292 L -.372 -.113 L -.819 -.583 L -.29 1.103 L .354 .903 L -.419 .065 L -.677 -.257 L -.751 -.176 L -.205 -.177 L -.018 -.243 L -.315 -.274 L -.93 .276 L -.743 -.613 L .051 -.292 L .27 -.374 L -.304 -.129 L -.224 -.016 L -.992 -.08 L -.718 -.292 L -1.17 -.617 L -.769 -.292 L -.762 -.048 L -.452 .23 L -.645 .083 L 250 52.592 l .281 .179 L 1.05 .682 L -.321 .114 L -.686 .05 L -.359 -.259 L 249.277 53 l -.646 -.21 L .275 .488 L .859 .972 L .604 .015 L .587 .08 L .5 .581 L .612 .805 L .513 .432 L .615 -.321 L .285 .047 L .592 .399 L .585 .271 L 1.38 .396 L -.634 .113 L -.213 .208 L .254 .19 L .568 .286 L .962 .444 L .324 .237 L .242 .682 L -.112 .428 L -1.302 -1.155 L -.554 -.237 L -.027 .238 L .118 .27 L 1.055 1.281 L -.01 .3 L -.926 -.125 L .053 .205 L .432 .409 L .378 .519 L -.563 -.172 L -.615 -.313 L -.889 -.693 L -.145 -.031 L -.719 .064 L -.91 -.188 L -1.44 -.662 L -.319 -.285 L -1.062 -.665 L .187 .777 L -1.22 -.473 L -.567 -.158 L -.872 -.03 L .095 .222 L .799 .696 L .853 .426 L 1.842 .645 L 1.296 .644 L .774 .549 L .442 .486 L .429 .689 L -1.833 -.341 L -1.524 -.421 L -1.251 -.28 L -1.444 -.107 L -1.092 -.25 L -.898 -.644 L -1.146 -.14 L -.638 -.204 L -.635 -.141 L -.058 .145 L h 146.194 38.698 m .818 -.037 L .78 -.125 L 1.138 -.548 L .895 -.019 L 1.723 .243 L .939 .262 L -.188 .877 L .515 -.071 L .66 -.019 L .792 -.229 L .599 -.141 L .758 .016 L .334 -.071 L -.989 -.965 L .156 -.036 L 1.38 .138 L 1.208 .245 L .675 .245 L .259 .245 L .194 .508 L .965 1.063 L .638 .346 L 1.045 -.315 L .14 -.261 L -1.243 -1.361 L -.439 -1.321 L .228 -.354 L 1.91 .262 L 1.775 .156 L 2.031 .719 L .36 .175 L .3 .316 L .16 .701 L .511 .645 L .352 .26 L .856 .606 L .048 .19 L -.178 .243 L -.333 .605 L .179 .31 L .224 .12 L 1.4 .649 L .509 .171 L 1.151 .254 L 1.513 .1 L 2.056 .576 L 1.012 .39 L .364 .793 L -.168 .101 L -1.071 -.082 L -.811 -.234 L -.945 -.234 L -.551 .169 L -.665 .204 L -1.021 .036 L -.256 .118 L .208 .689 L 1.087 -.069 L .614 -.152 L .676 -.119 L .876 .536 L -.01 .235 L -.526 .151 L -.517 .252 L -.583 .102 L -1.417 .12 L -1.049 -.015 L -1.194 -.082 L -1.594 -.248 L -2.278 -.499 L -.553 -.217 L -.436 -.335 L -.482 -.033 L -.581 .102 L -.402 .37 L -1.114 .505 L -1.055 .019 L -1.411 .103 L -1.253 .42 L -2.753 .356 L -1.42 .019 L -1.205 .086 L -1.984 -.063 L -.483 .101 L -.916 -.015 L -1 -.282 L -.061 -.468 L .198 -.101 L .002 -.302 L -.395 -.2 L -.462 -.1 L -3.146 -.112 L -1.258 -.115 L -.864 -.167 L -.801 -.2 L -.753 -.504 L -1.274 -.554 L .303 -.069 L .531 -.222 L 1.572 -.054 L .603 -.188 L .558 .016 L .91 -.019 L .904 -.087 L 1.716 .031 L .935 -.002 L 2.14 .047 L 1.09 -.002 L 1.711 -.038 L .415 -.154 L -.681 -.221 L -2.312 -.492 L -1.942 -.202 L -4.059 -.061 L -1.569 -.014 L -1.694 .055 L -.955 .053 L -.604 .001 L -1.651 -.529 L .011 -.207 L .28 -.069 L .823 -.053 L 1.315 -.209 L .996 .032 L 1.78 -.141 L .931 -.105 L .5 -.277 L -.392 -.346 L -2.023 .073 L -1.578 .159 L -.393 -.051 L -.554 -.189 L -.677 -.346 L -.65 -.19 L -.692 .054 L -.709 -.242 L -.039 -.279 L 1.304 -.981 L 2.62 -.848 L .909 -.143 L .373 -.177 L 1.297 -.267 L 1.324 -.162 L .701 -.267 L 1.113 -.091 L 1.026 .246 L -.07 .212 L -.548 .354 L -.021 .81 L h 251.273 99.526 m -.188 .153 L -.16 -.291 L .192 -.077 L -.02 -.256 L .143 -.069 L -.042 -.154 L -.224 0 L -.606 -.231 L .077 -.229 L -.31 -2.819 L -.174 -.274 L -.488 -.288 L -.771 -.025 L -.41 .176 L -.381 -.085 L -.505 -.36 L -.273 -.085 L -.632 .526 L -.514 .626 L -1.139 2.22 L -1.139 1.45 L -1.161 -.124 L -.402 .06 L -.363 .435 L -.174 .375 L -1.093 -.095 L -1.855 -.004 L -2.508 -.029 L -1.76 .009 L -.968 .523 L -.534 .305 L -1.754 .814 L -.545 .164 L -.146 .434 L -.163 .512 L -.44 .275 L -1.156 .197 L -1.305 -.138 L -1.123 -.01 L -.93 .091 L -.47 .203 L -.162 .375 L .018 .319 L .16 .471 L .047 .362 L -.875 .427 L -1.464 .452 L -.944 .163 L -.919 .062 L -.88 .262 L -.939 .478 L -.925 .506 L -.524 .117 L -.573 -.068 L -.497 -.169 L -.371 -.427 L -.012 -.33 L .044 -.218 L .707 -.525 L .414 -.294 L .264 -.433 L .294 -.544 L .377 -.576 L .028 -.746 L -.054 -.545 L -.876 -3.16 L -2.529 -1.05 L -.26 -.33 L .11 -.318 L -.307 -.235 L -.916 -.181 L -.184 -.294 L -.178 -.135 L -.628 .024 L -.46 -.465 L -.101 -.429 L -2.15 -1.061 L -3.975 -1.576 L -.977 -.386 L -.797 -.227 L -.805 .189 L -1.469 .592 L -.707 -.074 L -.542 .049 L -.196 -.144 L -.156 -.115 L -.474 -.041 L -.855 .083 L -.197 -.116 L -.028 -.282 L -.373 .075 L -.412 .191 L -.219 .06 L -.573 .141 L -.506 -.098 L -.064 -.185 L -.469 -.086 L -.241 -.271 L -.502 -.013 L -.16 .247 L -.338 -.48 L -.271 .012 L -.02 -.185 L -1.425 -.208 L -.518 .076 L -.833 -.451 L -.468 -.46 L -.279 -.371 L -.896 -.748 L -.501 .036 L .131 .347 L .387 .588 L -.68 -.003 L -2.687 .029 L -2.798 -.029 L -1.348 .007 L -2.105 -.003 L -2.915 .016 L -2.781 -.029 L -2.131 .012 L -2.935 -.014 L -.601 .003 L -4.84 -.018 L -3.617 .004 L -.875 .005 L -3.821 -.023 L -1.089 .035 L -4.13 -.021 L -.74 -.011 L -5.117 .028 L -1.687 -.006 L -2.87 .001 L -3.938 -.008 L -4.588 .025 L -1.335 -.022 L -2.579 -.001 L -.194 -.013 L -.187 -.151 L -.509 -.305 L -.071 -.437 L .074 -.346 L -.708 .25 L -.373 -.029 L -.331 -.305 L -.162 -.496 L -.125 -.189 L -.385 .088 L -.23 .205 L -.483 .059 L -.721 -.495 L -.119 -.425 L -.201 -.821 L -1.051 .104 L -1.01 -.277 L -.487 -.087 L -.173 -.087 L -.143 -.396 L -.438 -.352 L -.591 .222 L -1.236 .046 L -.461 -.117 L -.383 -.249 L -.106 -.25 L .257 -.648 L .458 -.222 L -.227 -.294 L -1.24 -.086 L .617 -.518 L .398 -.281 L .547 -.149 L .605 -.508 L -.874 .006 L -.621 .149 L -.362 -.043 L 116 83.422 l -.039 -.978 L -.789 .002 L -1.015 -1.066 L .132 -.238 L .034 -.53 L -.547 .056 L -.83 .492 L -1.266 -.934 L -.384 -.521 L -.204 -.402 L -.068 -.432 L .419 -.404 L .161 -.254 L .436 -.3 L -.358 -.689 L -.393 -.777 L .163 -.788 L -.402 -.255 L -2.025 -.763 L -.98 -.314 L -.189 -.029 L -.512 -.393 L -1.67 -1.882 L -1.769 -1.768 L -.814 -.58 L -2.048 -1.175 L -.35 -.322 L -.371 -.492 L -.316 -.199 L -.832 -.073 L -.495 .126 L -.731 .498 L -1.225 .67 L -.848 .205 L -.238 .325 L -.945 -.673 L -2.162 -1.318 L -.348 -.292 L -.173 -.387 L -.332 -.388 L -.739 -.059 L -2.424 .122 L -.84 -.074 L -.196 -.279 L -.089 -1.046 L -.026 -2.167 L .043 -4.334 L .026 -2.183 L -.129 -2.796 L -.052 -2.335 L -.039 -2.259 L .003 -2.855 L -.102 -.483 L .71 .024 L .9 -.086 L .964 .116 L 2.012 .451 L 1.601 .518 L 1.214 .266 L 1.04 .115 L .731 .032 L 1.619 .164 L .888 .232 L .429 .149 L .254 -.034 L -.452 -.601 L -.357 -.2 L -.345 -.15 L -.064 -.419 L 1.344 -.423 L .745 .066 L .578 -.068 L .15 -.102 L 1.736 .148 L .771 -.001 L 1.125 -.373 L .309 -.186 L .442 0 L .656 -.221 L .759 -.069 L .866 -.086 L .734 -.086 L .469 -.239 L .392 -.188 L .771 -.104 L 1.045 -.002 L .872 .123 L -.445 .404 L -.352 .119 L -1.101 .137 L -1.092 .373 L -1.244 .171 L -1.22 .271 L -.699 .522 L -1.767 .255 L -.681 .487 L .846 .266 L 1.441 .748 L -.219 -.55 L .168 -.351 L 1.196 -.253 L .39 -.235 L .726 -.421 L 1.727 -.053 L .96 -.372 L 1.158 -.389 L 2.066 -.173 L .643 -.338 L .921 -.272 L .821 -.189 L .476 -.239 L -.178 -.272 L -.702 -.392 L -.655 -.444 L .899 .101 L .764 .272 L .701 .306 L .412 .324 L .376 .476 L .449 .523 L .393 .235 L 1.246 .486 L .186 .067 L 1.154 .216 L .394 -.018 L .199 -.151 L -.511 -.639 L .07 -.27 L .548 -.035 L .334 -.136 L .627 -.103 L .383 .354 L .059 .421 L -.205 .287 L .833 .133 L .938 -.069 L 1.136 -.457 L .536 -.49 L .479 -.069 L 1.131 .015 L 1.536 .267 L 1.745 .435 L 1.396 .334 L 2.095 .349 L 1.024 .216 L .619 .066 L 1.572 .282 L 1.121 .065 L 1.144 .148 L 1.096 .032 L 1.4 -.086 L .899 .099 L 1.008 .282 L .982 .349 L .434 .249 L .191 .333 L -.524 .134 L -.935 -.032 L -.566 .051 L -.849 .135 L -.354 .714 L 3.323 .358 L 1.726 .079 L 1.749 .014 L .868 -.068 L .738 -.051 L .94 -.167 L .895 -.118 L .938 -.101 L .886 .032 L 1.432 .477 L 1.452 .179 L .42 .115 L 1.225 .443 L -.013 .312 L -.504 .083 L -.35 .247 L .305 .147 L 1.823 .979 L -.162 -.392 L -.024 -.312 L .456 -.05 L .617 -.132 L -.062 -.181 L -.972 -.656 L -.128 -.198 L -.145 -.445 L .121 -.745 L .35 -.034 L 1.944 -.136 L .928 -.151 L .207 -.299 L .459 -.217 L .613 -.035 L 1.098 .281 L 1.528 .279 L .968 .064 L .969 -.102 L .612 .414 L .248 .082 L .962 .213 L 1.211 .13 L .678 .081 L 1.146 -.002 L .879 -.2 L 1.755 -.02 L 1.876 .029 L 1.07 -.052 L 1.18 -.267 L .959 .478 L .95 .296 L .522 -.018 L .243 -.314 L -.017 -.513 L -.666 -.231 L -.732 -.131 L -1.377 -.064 L .089 -.449 L 1.193 -.085 L .575 .065 L .804 .214 L .871 .198 L .858 .048 L .498 .198 L .088 .183 L -.095 .132 L -.287 .86 L .179 .51 L .304 .164 L .177 .065 L .792 .097 L .951 .311 L -.071 -.559 L -.466 -.989 L .137 -.48 L .258 -.266 L .712 .015 L .811 -.035 L 1.229 -.85 L .492 -.051 L .479 -.001 L .517 -.151 L .033 -.133 L -.15 -.367 L -.375 -.35 L -.307 .001 L -.81 .185 L -.988 -.082 L .535 -.52 L .806 -.069 L .435 -.168 L .572 -.001 L .739 .4 L .464 .167 L .065 -.268 L -.081 -.956 L -.744 .069 L -.897 -.032 L -.68 -.116 L -.859 -.318 L -.725 .085 L -1.245 -.183 L -.861 -.234 L -.956 -.218 L -.657 -.338 L -.092 -.136 L -.022 -.324 L .33 -.137 L .842 -.463 L -.486 -.221 L -1.188 -.375 L .09 -.207 L .58 -.604 L .593 -.294 L .387 -.035 L 1.032 .257 L .139 -.035 L .173 -.346 L -.709 -.362 L -.201 -.277 L .23 -.035 L .551 -.331 L .367 -.035 L 1.841 -.021 L .559 .086 L .728 .189 L 1.26 .449 L .432 .328 L .195 .38 L -.246 .603 L 1.261 .53 L .809 .495 L 1.134 .493 L -.377 .341 L -.985 .036 L -.474 .273 L -.416 .557 L .471 .067 L 1.071 .233 L .805 .049 L .387 -.136 L .597 -.001 L 1.477 .351 L -.335 .353 L -.563 .219 L .092 .151 L .796 .467 L .358 .601 L .025 .833 L .303 -.063 L .021 -.004 L .411 -.067 L .608 -.367 L .655 -1.137 L .668 -.42 L .523 .016 L .731 .284 L 1.064 .55 L .473 .383 L .209 .45 L -.159 .433 L -.336 .034 L -.796 -.098 L -.202 .299 L -.043 .415 L .35 .396 L 1.146 .659 L .61 .493 L .463 .279 L .595 -.166 L .896 -.167 L .369 -.132 L .208 -.66 L .764 -.398 L .599 -.416 L .249 -.664 L .363 -.75 L .237 -.184 L 1.394 .081 L .329 -.067 L .134 -.518 L -.985 -.333 L -.918 -.35 L .088 -.891 L .595 -.271 L .787 .032 L .42 -.068 L .571 .016 L 3.459 .616 L 1.325 .669 L .506 -.001 L .553 -.068 L .454 .201 L .244 1.036 L -.474 .268 L -.431 .101 L -.243 -.05 L -.718 -.532 L -.263 0 L -.799 .269 L .123 .316 L .309 .515 L .699 .729 L .855 .528 L 1.108 .576 L .024 .313 L -.478 .642 L -.439 .181 L -1.407 .772 L -.674 .083 L -1.123 .509 L -.763 -.276 L -1.654 -.962 L -.586 -.262 L -.497 -.048 L -.684 .281 L 1.364 .521 L 1.483 .896 L -.708 .067 L -.691 -.081 L -1.288 .084 L -.375 -.129 L -.596 -.62 L -1.147 -.014 L -1.857 .118 L -.253 .229 L .614 .244 L 1.311 .421 L -.159 .195 L -.611 .327 L -2.045 1.106 L -.657 .179 L -.527 .001 L -.859 -.241 L -.816 -.484 L -.225 -.081 L -1.189 -.225 L -.736 -.259 L -.598 -.112 L -.947 .014 L -.289 .004 L -1.214 .174 L 1.503 .278 L 1.136 .21 L 1.751 .774 L 1.629 .433 L 1.233 .126 L 1.02 .031 L -.618 1.091 L -1.237 .705 L -.856 .432 L -.728 .161 L -.829 .049 L -.928 -.126 L -1.062 -.38 L -.048 .351 L -.025 .287 L .321 .572 L -.02 .159 L -.741 .031 L -.058 .002 L -1.365 -.108 L -1.649 -.41 L -.884 -.078 L -2.962 -.322 L 2.146 .864 L 1.576 .156 L 1.367 .267 L .562 .205 L .33 .268 L -.011 .19 L -.642 .333 L -1.106 .207 L -1.429 -.076 L -.511 -.062 L -.367 .269 L 1.254 .423 L -.469 .426 L -1.06 .316 L -1.454 .662 L -.421 .252 L .218 .704 L -.313 .235 L -.909 .205 L -.31 .282 L -.529 .64 L -.276 .296 L -.241 .669 L -.274 .543 L -.323 .666 L .056 .416 L -.161 .554 L .123 .875 L .136 .536 L .598 .366 L .25 .015 L .257 .091 L .664 .014 L 1.164 -.094 L .276 .045 L .367 .29 L .413 .763 L .813 1.157 L .22 .668 L -.132 .91 L .673 .014 L 1.874 -.428 L 1.261 -.033 L .723 .074 L .535 .157 L 1.062 .311 L 2.129 .435 L 1.896 .903 L .993 .933 L 3.5 .67 L .644 .225 L .982 .403 L .986 .253 L .553 .104 L .702 -.091 L .453 .044 L .828 -.077 L 1.245 .163 L 1.407 .207 L .401 .194 L -.297 .702 L -.142 .85 L .154 .283 L .307 .342 L .07 .416 L -.115 1.025 L -.309 .593 L .022 .208 L .604 .266 L .481 .339 L .264 .354 L .046 .488 L -.076 .354 L .97 .116 L .963 .47 L .676 .588 L .392 .588 L .078 .162 L .64 .014 L .726 .41 L .907 .601 L -.349 -.66 L -.22 -.279 L .134 -.338 L .573 -.414 L .365 .176 L .381 .456 L .262 .353 L .165 -.354 L .107 -.545 L -.215 -.456 L .541 -.532 L .139 -.546 L -.183 -.517 L -.337 -.458 L -.261 -.754 L -.004 -.548 L -.205 -.593 L -.218 -.43 L .615 -.016 L -.097 -.476 L -.296 -.252 L -.657 -.163 L -.375 -.282 L -.326 -.923 L 1.252 -.271 L .872 -.241 L .625 -.271 L 1.758 -.949 L .629 -.302 L 1.043 -.935 L .434 -.544 L .237 -.665 L .054 -.529 L -.257 -1.045 L -.246 -.531 L -.239 -.319 L -.938 -.729 L -.467 -.274 L -1.105 -.532 L -.363 -.122 L -.453 -.274 L -.151 -.046 L -.293 -.351 L .08 -.107 L .868 -.522 L .553 -.875 L .293 -.416 L .25 -.092 L .447 -.017 L .295 -.277 L -.106 -.523 L -.18 -.355 L -.316 -.402 L -.048 -.202 L .258 -.357 L .005 -.264 L -1.751 -.105 L 1.084 -.92 L .503 -.704 L .007 -.125 L -.316 -.203 L -.609 -.265 L -.244 -.266 L -.043 -.533 L .305 -.425 L .554 -.315 L .57 -.19 L .827 .062 L 1.781 .374 L 1.097 .234 L .753 .077 L 1.44 .013 L 1.08 -.144 L .86 -.222 L .21 -.047 L .179 -.063 L .589 .078 L .991 .407 L .254 .125 L .754 .454 L .918 .375 L .796 .437 L -.294 .391 L .406 .233 L 1.698 .496 L 1.958 .354 L .725 -.033 L .368 -.203 L .339 .295 L -.013 .404 L -.577 .343 L -.123 .45 L .438 1.327 L .136 .722 L .23 .414 L -.049 .353 L -.248 .169 L -.445 -.014 L -.347 -.015 L -.138 .674 L .375 .274 L 1.137 -.415 L .366 -.047 L .781 -.047 L .286 .015 L .677 .32 L .378 .351 L .004 .259 L -.081 .123 L .277 .32 L .516 -.184 L .306 -.046 L 1.173 -.079 L .636 -.184 L .436 -.383 L .333 -.551 L .326 .015 L .194 .122 L .693 .717 L .042 -.062 L .108 -.764 L .317 -.583 L .475 -.262 L .539 -.385 L -.651 -.505 L .008 -.308 L .272 -.139 L .98 -.094 L .193 -.139 L .512 -.665 L .667 .37 L .607 .599 L .785 .506 L .596 .797 L 1.045 .764 L .264 .352 L -.344 .291 L .095 .335 L .573 -.031 L .365 .777 L .182 .183 L .324 .121 L .743 .136 L .281 .258 L .133 .38 L -.379 .092 L -.416 .168 L .411 .318 L .397 .227 L .77 .196 L .279 .227 L .034 .424 L -.056 .076 L -.409 .106 L -.676 -.029 L -.745 -.12 L -.316 .061 L .091 .166 L .273 .181 L .189 .241 L .333 .513 L .411 .226 L .634 .029 L .462 .18 L .838 .496 L .899 .435 L .246 .33 L -.035 .195 L -.447 .781 L .508 .059 L .663 -.166 L .786 -.077 L .79 .164 L .574 .194 L 1.162 .49 L .981 .132 L 1.517 .295 L -.184 .253 L -.718 .21 L -.736 .21 L -.663 .046 L -.834 .24 L -.583 .402 L -.65 .225 L -1.032 .061 L -.286 .075 L -.324 .268 L .029 .371 L -.271 .535 L 1.175 -.343 L .542 -.09 L .649 -.105 L 1.201 -.774 L 1.251 -.478 L 1.146 -.106 L .662 .237 L .35 .341 L -.398 .446 L .036 .119 L .307 .296 L .616 -.224 L .455 -.164 L .655 .192 L 1.051 .487 L .226 .251 L .022 .178 L -.299 .43 L -.05 .355 L -.406 .444 L 1.001 .929 L -.365 .37 L -.795 .282 L -1.078 .621 L -.662 .281 L -1.097 .046 L -.823 .119 L -1.548 .077 L -.433 .413 L -.916 .795 L -.686 .427 L -.612 .294 L -.938 .222 L -1.494 .172 L -1.845 .127 L -1.452 -.07 L -2.031 -.084 L -.355 .03 L -1.073 .075 L -1.058 -.012 L -1.873 -.099 L -.917 -.027 L -1.758 .106 L -.547 .206 L -.523 .294 L -.537 .585 L -.205 .554 L -.287 .335 L -.591 .19 L -1.07 .104 L -.537 .147 L -1.098 .555 L -.774 .54 L -.794 .612 L -.325 .363 L -.33 .233 L -.868 .843 L -.485 .566 L -.418 .276 L -.46 .58 L -.518 .968 L .749 -.737 L .375 -.131 L .688 -.479 L 1.059 -.944 L 1.097 -.785 L 2.028 -.948 L 1.245 -.395 L 1.797 -.512 L 1.065 -.235 L 1.03 -.235 L 1.473 -.148 L .922 .056 L .895 .289 L .509 .29 L .136 .189 L .144 .464 L -.125 .218 L -.326 .219 L -1.059 .292 L -.753 .452 L -.581 .044 L -.845 -.23 L -.726 .045 L -.645 .19 L .279 .08 L 1.13 .229 L .17 .122 L .256 .444 L .074 .095 L 1.299 -.485 L -.028 .216 L .479 -.148 L .372 .162 L -.36 .229 L -.231 .256 L .112 .27 L -.163 .014 L -.074 .229 L -.91 .444 L 1.216 .013 L .077 .188 L -.187 .282 L .091 .43 L .118 -.081 L .239 .134 L -.063 .134 L .048 .202 L .351 .457 L .009 .147 L .824 .054 L .154 .094 L .04 -.067 L .727 .147 L -.315 .134 L -.373 -.013 L -.047 .134 L .525 .147 L .211 .241 L .569 -.081 L .135 .134 L .212 -.014 L .134 .174 L .418 -.04 L -.075 -.107 L .843 .067 L .241 .107 L -.207 .201 L .242 -.107 L .26 .027 L .245 -.013 L .696 -.362 L .303 -.081 L .104 .362 L .377 .161 L .538 -.121 L .488 .416 L -.405 .254 L .089 .107 L .825 .027 L .164 .174 L -.521 .121 L -.161 -.121 L -.3 .134 L .118 .094 L -.515 0 L -.23 -.04 L .109 .161 L -.45 .04 L .056 .107 L -.443 .014 L -.128 .147 L -.45 .04 L -.368 .253 L -.09 -.106 L -.706 .28 L -.046 .053 L -.529 .133 L -.119 -.267 L -.274 .106 L -.163 .267 L -.188 -.187 L -.068 .253 L -.218 .08 L -.094 .187 L -.513 0 L -.081 -.08 L -.169 -.053 L .032 -.347 L -.242 .36 L -.202 .12 L -.131 -.253 L -.354 .027 L .043 .24 L -.233 .04 L .312 .08 L .033 .213 L -.103 .12 L -.174 -.067 L -.768 .453 L .127 .16 L -.235 .12 L -.194 .053 L .015 .213 L -.161 -.12 L .083 .173 L -.217 .08 L -.14 -.107 L .096 .253 L -.222 .066 L -.146 -.08 L -.148 0 L -.064 .133 L -.156 -.106 L -.243 .227 L -.086 .292 L -.201 -.226 L -.344 .133 L -.154 -.187 L -.349 -.479 L -.138 .24 L -.419 -.866 L .456 -.773 L .284 -.16 L .035 -.12 L -.35 .12 L -.357 .267 L -.076 -.106 L .924 -.507 L .125 .146 L .195 -.093 L -.258 -.107 L 1.103 -.52 L 1.109 -.562 L .658 -.361 L .336 .094 L -.067 .428 L .179 -.054 L .258 .281 L -.044 -.201 L -.017 -.174 L .632 -.214 L .73 -.134 L .192 .067 L .202 -.081 L -.152 -.094 L -.653 -.053 L -.595 .053 L -.42 -.053 L -.804 -.014 L -.306 .027 L -.251 .081 L -.246 .094 L .033 -.214 L 1.128 -.563 L .054 -.201 L .252 -.08 L -.052 -.174 L -.523 .281 L .097 -.134 L -.502 -.51 L .309 .443 L -.36 .482 L -.328 .013 L -1.974 .817 L -.284 .08 L -.362 -.201 L -.227 -.067 L .23 .201 L -.788 .401 L -.219 -.174 L -1.019 -.054 L -.124 .147 L -.38 -.241 L h 186.193 47.833 m -.713 -.032 L -.922 -.181 L -.882 -.065 L -1.25 -.314 L -.973 -.182 L -.604 -.049 L -1.083 -.199 L .43 -.335 L 1.542 -.405 L .385 -.186 L .115 -.673 L .305 -.236 L .831 -.069 L .743 .184 L 1.436 .603 L 1.287 .4 L .074 .285 L .315 .284 L 1.094 .516 L -.288 .117 L -1.263 .486 L -.578 .051 L h 231.09 50.646 m -1.319 -.03 L -.449 -.147 L -.232 -.247 L -.173 -.478 L .3 -.43 L .708 -.664 L .662 -.267 L 1.359 -.168 L .911 .197 L .79 .314 L -.021 .464 L -.039 .727 L -.362 .265 L -1.025 .348 L -1.108 .117 L +444.972 79.145 N .47 -.218 L .307 -.093 L -.294 -.024 L -.419 .061 L -.15 -.135 L -.125 .184 L -.108 -.012 L .066 -.491 L .177 -.218 L .41 .009 L 1.489 .062 L .417 .014 L .339 -.075 L .121 -.253 L -.175 -.288 L .246 -.05 L -.068 -.122 L -.068 -.123 L .353 -.096 L .12 -.034 L .051 .154 L .086 .052 L .24 0 L .223 .12 L .257 .069 L .514 .068 L .086 .103 L .223 -.051 L .445 0 L .257 0 L .223 -.017 L .086 .137 L .103 .103 L .188 .034 L .171 .069 L .018 .137 L .052 .12 L -.224 .12 L -.068 .154 L -.068 .206 L .018 .171 L .034 .137 L .029 .038 L -2.96 .101 L -2.246 -.115 L -.842 -.006 L h 717.633 81.109 m .42 .443 L .429 .62 L .183 .457 L .01 .767 L -.244 .442 L -.197 .78 L -.002 .764 L .29 .777 L .592 .849 L .65 1.446 L .899 1.614 L 1.115 1.679 L -1.26 -.677 L -.832 -.39 L -.99 -.056 L -.268 .088 L -.396 .204 L -.462 1.045 L -.266 1.101 L -.082 .579 L .277 .982 L .183 .216 L .659 .908 L .54 .201 L .463 .648 L -.314 1.246 L -.664 -1.258 L -.866 -.301 L -.224 .029 L -.415 .303 L -.311 .534 L -.643 .907 L -.422 -.5 L -.19 -.929 L .637 -1.146 L -.395 -.884 L .175 -.454 L .502 -.63 L -.131 -.723 L -.196 -.376 L -.27 -.55 L -.062 -.235 L .403 -.302 L .284 -.915 L .075 -.784 L .005 -1.326 L .15 -1.302 L -.09 -.732 L -.213 -.469 L -.83 -.85 L -.1 -.897 L .114 -.192 L .359 -.722 L .065 -.738 L -.336 -.457 L .172 -.237 L .374 -.03 L .62 -.031 L 1.023 -.534 L h 471.158 84.281 m -.002 -.142 L -.165 -.066 L -.082 -.115 L -.164 -.082 L .033 -.099 L -.033 -.23 L -.033 -.164 L .082 -.099 L -.147 -.131 L -.099 -.148 L .132 -.066 L 0 -.165 L -.296 -.164 L -.279 -.263 L -.017 -.164 L .099 -.131 L .131 -.165 L .362 -.017 L .328 .049 L .197 .132 L .51 .016 L .525 -.099 L .444 -.247 L .049 -.065 L .148 -.083 L .296 0 L .065 -.164 L -.033 -.131 L -.279 -.066 L -.296 -.148 L -.099 -.181 L .082 -.017 L .066 -.049 L .032 -.065 L -.263 -.066 L -.361 -.099 L -.378 -.066 L -.361 .066 L -.182 -.066 L .066 -.181 L .099 -.197 L -.066 -.148 L -.164 -.099 L -.279 -.082 L -.23 -.066 L -.443 -.213 L -.115 -.23 L -.164 -.263 L -.214 -.017 L -.017 -.099 L .066 -.131 L .099 -.115 L -.132 -.033 L -.181 .049 L -.082 -.115 L -.132 -.181 L -.345 -.049 L .049 -.147 L .033 -.165 L .099 -.049 L .115 -.082 L 0 -.083 L .114 0 L .066 -.131 L -.05 -.164 L -.147 -.099 L -.197 -.247 L .131 -.165 L .033 -.164 L 0 -.083 L .065 -.115 L -.049 -.115 L -.147 .033 L -.165 -.033 L -.147 -.099 L -.099 -.099 L -.279 -.099 L -.132 -.131 L -.542 -.115 L -.247 .049 L -.099 -.049 L -.131 -.049 L -.23 .083 L -.147 .099 L -.165 0 L -.279 .016 L -.214 .197 L -.197 0 L -.164 -.148 L -.065 -.148 L .017 -.099 L .164 -.099 L 0 -.115 L -.147 -.017 L -.296 -.065 L -.312 -.049 L -.361 .049 L -.214 .065 L -.197 .033 L -.082 -.148 L -.132 -.148 L -.312 -.033 L -.181 -.016 L -.197 .131 L -.229 -.066 L -.165 -.147 L .061 -.042 L .015 -.117 L .044 -.087 L -.088 -.233 L .015 -.189 L -.131 -.117 L .059 -.087 L -.16 -.043 L -.146 -.102 L -.029 -.16 L -.131 -.058 L -.116 -.102 L .043 -.073 L .059 -.087 L -.073 -.044 L -.087 -.014 L -.131 -.073 L -.146 .015 L -.204 .059 L .044 -.102 L .102 -.073 L .073 -.087 L -.029 -.117 L .072 -.131 L -.131 -.087 L .103 -.029 L .087 -.015 L .102 -.073 L .015 -.087 L .029 -.116 L .015 -.087 L -.204 -.058 L -.087 -.073 L -.204 -.087 L -.232 -.073 L 0 -.117 L .015 -.116 L -.37 .004 L -.081 -.106 L .116 -.058 L 461.402 72 l .029 -.117 L .131 0 L .087 -.116 L .059 -.102 L .16 -.058 L .262 -.043 L .175 -.073 L -.059 -.059 L -.175 -.043 L -.043 -.146 L -.015 -.087 L 0 -.073 L -.088 -.073 L -.203 -.087 L -.175 -.233 L 0 -.175 L .175 -.131 L -.029 -.16 L -.073 -.189 L -.131 -.437 L -.029 -.16 L .088 -.16 L .204 -.131 L .319 -.131 L .219 -.204 L .175 -.277 L .058 -.131 L .088 -.043 L .116 0 L .189 0 L .175 -.044 L .043 -.174 L -.16 -.131 L -.145 -.053 L -.089 -.13 L -.17 -.038 L .1 -.253 L .339 -.038 L .153 .165 L .229 .063 L .188 -.088 L -.094 -.139 L .301 -.154 L .485 .199 L .296 -.062 L .312 -.338 L .311 -.185 L .75 .106 L .781 .275 L .439 0 L .363 -.154 L -.386 -.399 L -.59 -.323 L -.393 -.03 L -1.204 .08 L -.616 -.091 L -.271 -.108 L -.299 -.309 L .258 -.434 L -.065 -.201 L -.199 .044 L .174 -.285 L 1.946 -1.145 L 1.983 -1.195 L 1.385 -.758 L .591 -.536 L .43 -.536 L .105 -.409 L -.161 -.346 L -.436 -.392 L -.703 -.265 L -1.357 -.499 L -.439 -.33 L .327 -.191 L .542 -.415 L .057 -.254 L -.151 -.253 L -1.286 -1.395 L -.37 -.509 L .029 -.37 L .187 -.403 L .44 -.535 L .196 -.356 L -.772 -1.195 L -1.402 -1.394 L .328 -.296 L 1.303 -.777 L .421 -.364 L -.543 -.392 L -.964 -.506 L -.872 -.194 L -.563 -.212 L -.116 -.529 L .258 -.465 L .024 -.283 L .689 -.303 L 1.013 -.672 L 1.023 -.49 L .77 -.121 L .824 -.021 L .514 -.204 L .404 -.288 L .617 -.051 L 1.002 -.254 L .643 -.237 L .01 .151 L .255 .386 L .358 .284 L .543 .2 L .919 .082 L .602 .1 L .078 .602 L .695 -.319 L .421 .049 L 1.083 .048 L .875 .015 L .522 .032 L 1.116 -.002 L 1.293 .281 L 2.728 .512 L .984 .364 L 1.595 .86 L .583 .214 L 1.48 .246 L 1.296 .212 L 2.018 .623 L .328 .279 L -.051 .444 L .147 .295 L .426 .294 L .104 .294 L -.24 .344 L -.69 .491 L -1.092 .54 L -.816 .262 L -1.75 .36 L -.907 .083 L -1.631 -.013 L -1.391 -.192 L -2.038 -.175 L -1.63 -.192 L -1.342 -.339 L -2.256 -.485 L -1.114 -.112 L -.476 -.048 L -.621 -.473 L -.371 -.163 L -.771 -.13 L -.943 .117 L .307 .163 L .149 .065 L .73 .538 L .482 .146 L 1.109 .601 L .832 .291 L .921 .161 L .634 .242 L .405 .453 L -.002 .405 L -.276 .291 L -.684 .195 L .086 .113 L .208 .531 L .771 .943 L .093 .494 L .155 .207 L .438 .174 L 1.203 .078 L .872 .125 L .499 .619 L .401 .095 L 1.26 .077 L .575 .126 L .364 .079 L .402 -.128 L .785 -.097 L .243 -.302 L -.001 -.318 L -.387 -.397 L -.471 -.079 L -.455 .096 L -.447 -.031 L -.589 -.206 L -.952 -.795 L .701 -.674 L .484 -.001 L 1.116 .479 L 1.441 .333 L 2.09 .427 L .952 .078 L .834 -.146 L .723 .174 L .261 -.224 L .05 -.415 L -.214 -.239 L -.858 -.656 L -.348 -.628 L .285 -.323 L .19 -.049 L 1.432 -.423 L 1.495 -.359 L .599 -.244 L 1.133 -.717 L .172 -.049 L .462 .064 L 1.829 .29 L 1.41 .533 L .341 -.001 L .052 -.065 L .154 -.503 L .581 -.767 L -.048 -.653 L -.317 -.408 L -.847 -.163 L -.3 -.229 L 1.139 -1.005 L .101 -.247 L -.205 -.594 L -.771 -.512 L .069 -.315 L .353 -.051 L 1.458 .23 L 2.025 -.12 L .631 .132 L .664 .611 L .616 .445 L .433 .461 L -1.045 .051 L -1.559 .085 L -.822 .215 L -.492 .51 L .191 .18 L .952 .293 L .732 .555 L .804 .194 L .723 .097 L 1.268 -.133 L 1.33 -.084 L .301 -.164 L .257 -.491 L .291 -.591 L .284 -.412 L 1.232 -.2 L 1.223 -.414 L .988 -.216 L 1.924 -.483 L 1.429 -.251 L 1.537 -.318 L .921 -.3 L .205 .464 L .278 .083 L .571 -.117 L .487 -.266 L .148 -.465 L .386 -.167 L .718 -.135 L .859 .065 L -.18 .399 L -.058 .597 L -.858 .084 L -.178 .149 L .002 .215 L .687 .197 L .507 -.083 L 1.169 -.167 L .436 -.001 L .161 .198 L .23 .049 L .278 -.133 L .264 -.216 L .29 -.431 L .464 -.183 L .861 -.118 L 1.049 -.068 L .768 .032 L 1.075 .23 L .755 -.018 L .36 -.083 L .963 -.467 L 1 -.285 L .803 -.052 L .952 .182 L .326 .166 L -.631 .45 L .129 .232 L .217 .099 L .632 .131 L .579 -.018 L .288 -.232 L .074 -.398 L .342 -.084 L .962 .065 L .543 -.184 L .395 -.316 L .115 -.417 L -1.37 -1.033 L .405 -.168 L .66 -.37 L .403 -.068 L .609 .016 L 2.171 .063 L 1.272 .199 L 1.241 .149 L 1.135 .199 L 2.111 .515 L 1.071 .098 L 1.712 .414 L 1.02 .248 L 1.305 .53 L 1.455 .611 L .864 .379 L .376 .049 L .229 -.1 L 1.145 -1.047 L .236 -.3 L -.927 .035 L -.4 -.049 L -.564 -.232 L -.365 -.433 L .027 -.652 L -.727 -.283 L -1.987 -.147 L -.19 -.268 L .064 -.168 L .305 -.303 L .693 -.255 L .236 -.153 L .085 -.187 L -.052 -.833 L -.251 -.238 L -1.135 -.066 L -.232 -.29 L .328 -.532 L .359 -.241 L .391 -.035 L 1.482 -.416 L 1.098 -.485 L .521 -.416 L .581 -.608 L .544 -1.22 L .637 -.421 L .374 .069 L 1.562 .155 L 1.613 -.125 L 1.605 -.091 L .695 .069 L 1.066 -.055 L .574 .122 L .309 .279 L -.018 .332 L -.423 .836 L -.348 .348 L -1.334 .833 L -.223 .345 L .752 .342 L .931 .667 L .277 .342 L .21 .818 L -.174 .222 L -.575 .375 L .254 1.179 L -.058 1.305 L .263 .583 L .45 .381 L 1.027 .264 L .19 .166 L -.001 .133 L -.485 .481 L -.417 .826 L -.333 .33 L -.784 .462 L -1.232 .625 L -.63 .198 L -.55 .263 L .321 .522 L -.433 .115 L 558 52.195 l -1.599 -.372 L -.731 -.08 L -.97 .034 L -.601 .115 L .195 .31 L .583 .276 L .738 .21 L 1.569 .208 L 1.133 .079 L .613 -.05 L 1.188 .144 L .922 -.034 L .472 -.358 L .303 -.358 L 1.352 -.328 L 1.166 -.492 L .268 -.278 L .386 -.606 L .818 -.313 L .864 -.626 L .064 -.362 L -.225 -.561 L -.609 -.545 L .244 -.548 L .237 -.1 L .677 -.151 L 1.38 -.152 L 1.757 -.003 L .74 .231 L .842 .463 L .151 .778 L -.34 1.023 L .302 .279 L .92 .212 L 1.298 .047 L .864 -.149 L .129 -.296 L -.514 -.18 L -.797 -.18 L -.571 .034 L -.457 -.098 L .068 -.379 L 1.03 -.382 L .065 -.249 L -.218 -.148 L -.166 -.331 L -.441 -.763 L -.511 -.266 L -.836 -.098 L -1.093 -.231 L -.801 -.116 L -1.288 -.165 L -.91 .186 L -.638 .101 L -1.297 -.181 L -.896 .019 L -.015 -.267 L -.564 -1.071 L .305 -.657 L .736 -.697 L .282 -.46 L -.134 -.221 L -1.092 -1.042 L -.949 -.514 L -.12 -.189 L .833 -.554 L 1.213 -.106 L .998 -.262 L .744 -.348 L .172 -.226 L .169 -.644 L -.13 -.663 L .23 .069 L .64 .051 L .466 .086 L .108 .471 L -.186 .54 L -.636 .608 L -.167 .554 L .14 .448 L .373 .274 L .485 .274 L 1.384 .134 L 1.574 .169 L 1.632 .083 L .819 .409 L .321 .017 L .799 -.036 L -.527 -.89 L -.521 -.274 L -1.893 -.1 L -.931 -.067 L -.576 -.154 L -.609 -.448 L .275 -.329 L 1.374 -.054 L .444 .172 L 1.145 .084 L .747 -.157 L -.09 -.728 L .408 -.088 L .84 -.105 L 1.278 -.02 L 1.067 .207 L 1.413 .379 L 1.088 .535 L 1.326 .343 L .547 .085 L 1.822 .014 L .727 -.174 L .138 .345 L -.781 .38 L -.696 .259 L -.248 .771 L -.129 .972 L .333 .136 L .68 -.785 L .387 -.292 L .285 .051 L .604 .528 L -.088 .749 L .743 -.205 L .681 -.273 L -.044 -.306 L -.191 -.119 L -.147 -.358 L -.748 -.821 L .188 -.223 L .686 -.759 L -.797 -.448 L -.772 -.258 L -.93 -.241 L -.257 -.382 L -.655 -.051 L -.979 -.242 L -1.34 -.207 L -.307 -.296 L .062 -.577 L -.096 -.386 L -.811 -.667 L .081 -.247 L .266 -.16 L .484 -.125 L 2.31 -.11 L 2.54 -.022 L 2.125 -.128 L 1.421 -.162 L .475 .317 L .382 .052 L .844 -.267 L 1.056 -.286 L 1.413 -.109 L .589 .194 L -.957 .338 L -.451 .407 L 1.737 -.233 L .521 -.107 L .955 -.374 L .27 -.284 L -.334 -.444 L -.326 -.177 L -.925 -.266 L -.365 -.303 L -.002 -.232 L .324 -.539 L 1.176 -.397 L .966 -.22 L 3.028 -.903 L .889 -.094 L .248 -.036 L .522 -.076 L 1.899 -.096 L 1.663 -.114 L 2.302 -.244 L 2.048 -.263 L 1.595 -.43 L .855 -.243 L 1.763 .034 L 1.065 -.002 L .383 .185 L -.351 .409 L 1.504 .108 L 1.018 -.039 L 1.261 -.188 L 1.345 -.225 L .95 -.039 L .982 .166 L .687 .073 L .693 -.206 L .12 -.335 L -.133 -.167 L .466 -.337 L .942 -.077 L .939 .036 L 1.243 -.377 L -.618 -.506 L .122 -.34 L 1.165 -.438 L 1.554 -.383 L 2.23 -.406 L 1.229 -.077 L .993 .056 L 1.486 -.003 L .86 .265 L .045 .266 L -1.528 .401 L -.66 .342 L .488 .15 L 1.83 -.117 L 1.588 .148 L 2.039 -.079 L .177 .113 L -.375 .283 L -1.187 .453 L -.296 .3 L 1.971 -.004 L .833 -.02 L .234 .093 L 1.052 -.545 L 1.366 -.002 L 1.771 -.097 L .631 .13 L 1.35 -.021 L 1.954 .165 L 1.4 .259 L 1.181 .427 L .52 .445 L .726 -.001 L .854 -.076 L .422 .5 L -1.354 .832 L .241 .128 L .896 .365 L -2.329 .859 L -1.035 .235 L -1.166 .11 L -3.404 1.061 L -3.018 .965 L -.793 .285 L -2.388 .375 L -2.35 .586 L -2.065 1.126 L .715 .017 L 1.081 -.247 L .922 -.458 L 1.663 -.161 L 1.231 -.02 L 2.101 -.268 L 1.879 -.286 L .879 -.107 L 1.004 -.284 L -.094 -.389 L -.492 -.123 L -.034 -.071 L .281 -.249 L .581 -.214 L .873 .211 L .603 .389 L .621 .052 L .593 .193 L .737 .052 L .853 -.055 L 1.155 -.268 L .499 .07 L .192 .3 L .009 .512 L .522 .404 L 1.422 -.778 L 1.66 -.021 L 1.506 -.145 L 2.354 .014 L 1.919 .155 L .854 .034 L 1.204 .033 L -.271 .74 L .354 .333 L 2.043 .154 L .848 .121 L .698 .069 L 1.035 .103 L 2.49 -.145 L 1.209 -.02 L 1.42 .348 L 1.405 -.932 L -.161 -.352 L -.038 -.229 L -.034 -.105 L 1.806 -.48 L .521 -.019 L .802 .104 L 1.148 .298 L .851 .281 L 1.711 .032 L 1.354 -.073 L 1.384 .033 L 1.323 .431 L .409 .181 L .058 .386 L -.52 .088 L -.268 .036 L -1.905 .406 L -2.438 .737 L -.233 .227 L .253 .069 L 1.033 .067 L .957 .016 L .659 .155 L .659 .293 L 1.014 .396 L .583 .172 L .78 .481 L 1.27 .805 L 1.814 .801 L 1.351 .305 L .612 -.018 L .795 -.394 L .843 -.72 L 1.093 -1.051 L .601 -.329 L .29 .017 L .236 .465 L .772 .308 L 1.346 .29 L 1.105 .135 L .848 -.087 L 1.973 -.468 L .778 -.07 L .813 .067 L 1.196 .239 L 1.921 .734 L .315 -.052 L .186 -.069 L .491 -.258 L .221 -.258 L -.137 -.051 L .013 -.189 L .726 -.312 L .509 -.018 L .5 .257 L .575 .188 L 1.302 .032 L .181 -.5 L -.194 -.466 L .15 -.363 L .093 -.521 L -1.131 .159 L -.643 .001 L -.179 -.104 L .442 -.296 L .318 -.087 L .986 -.089 L 1.021 -.02 L .832 -.141 L 1.566 -.648 L .254 0 L 1.76 .241 L 1.561 .137 L 2.036 .188 L .997 .068 L .654 .103 L 2.307 .065 L -1.732 .628 L .865 .051 L 1.011 -.089 L .335 .138 L -.305 .381 L -.926 .192 L -.846 .261 L -.177 .293 L .664 .033 L .52 -.122 L .916 -.14 L .978 -.33 L 1.62 -.799 L 2.766 .012 L 1.196 .067 L .903 .172 L .946 .137 L .205 .19 L .221 .104 L -2.247 .59 L .559 .137 L 1.674 .289 L 2.174 .202 L .946 .204 L .801 .375 L .367 .427 L .564 .357 L .522 .152 L 1.459 -.037 L 1.364 -.105 L 1.138 -.139 L 2.518 -.329 L 2.208 -.107 L 3.008 .131 L 1.515 .134 L .734 .118 L 1.168 .424 L .655 .169 L .525 .338 L .361 .39 L -.123 .491 L -.286 .521 L .509 .25 L .764 .065 L .835 .015 L .643 .083 L -.017 .685 L .419 .416 L .686 -.168 L .545 -.435 L 1.211 -.387 L .348 -.067 L .35 .049 L 1.696 -.02 L 1.521 -.288 L .736 .032 L .588 .434 L .707 .116 L 1.541 .014 L 2.176 .062 L .869 -.118 L 1.378 -.504 L .406 .2 L .93 .533 L .396 .216 L 1.095 .265 L .875 .332 L .282 .398 L .612 .148 L 1.556 -.136 L 1.653 -.319 L .16 -.25 L -.248 -.333 L -.805 -.833 L -.833 -.115 L .4 -.336 L .479 -.571 L 1.89 .098 L 1.214 .082 L 1.135 .065 L 1.221 .166 L .222 .318 L 1.396 -.153 L 2.084 -.054 L 2.304 .013 L 1.292 .148 L .786 .199 L 1.185 .199 L 1.391 .098 L .751 .182 L 1.302 .332 L .747 .065 L .703 .182 L 1.145 .505 L 0 2.126 L 0 2.222 L 0 2.222 L 0 1.292 L 0 .157 L 0 .576 L 0 .219 L -1.083 .371 L -.651 .03 L -.645 .37 L -.56 .065 L -1.044 .065 L -.355 -.079 L -.928 -.052 L -.118 -.343 L -.271 -.211 L -.501 .027 L .241 -.185 L -.938 .324 L -.846 .02 L -.337 -.211 L -.478 -.079 L .424 .501 L -.569 .29 L .32 .103 L .942 .205 L .634 -.36 L .395 .041 L .335 .079 L 0 .477 L .248 .206 L .76 .269 L 1.059 -.228 L -.439 .322 L .741 -.243 L .065 .336 L .247 .206 L .187 .363 L .068 .189 L -.722 .522 L .593 -.064 L .349 .172 L .473 .503 L .501 .157 L .145 .251 L -.162 .456 L .792 -.111 L -.125 .393 L .023 .25 L -.43 .299 L -.691 .205 L -.635 -.046 L -.448 -.14 L -1.243 -.154 L -.889 -.077 L -.347 -.14 L .123 -.267 L -.493 -.046 L -.304 .032 L -.559 .55 L -.069 .11 L -3.06 .913 L -1.155 .174 L -.245 0 L -.43 .203 L -.219 .188 L -.719 .22 L -.991 .033 L -.308 .11 L -.48 .405 L -.462 .203 L -.946 .033 L -.854 .622 L -.24 .279 L -1.67 .452 L -.392 .449 L -1.229 .25 L -.406 .14 L -.151 .293 L .01 .292 L -.473 .292 L -.406 .016 L -.586 -.306 L -.183 -.262 L -.169 -.37 L -.67 -.308 L -1.074 -.044 L -1.021 .048 L -1.159 .172 L -1.301 .188 L -.523 .217 L -1.333 .756 L -.536 .277 L -.184 -.138 L .575 -1.293 L -.55 .094 L -.392 -.097 L -.811 .531 L -.67 .186 L -.401 .155 L -.114 .506 L -.66 .154 L -.317 -.168 L -.253 -.49 L -.483 -.261 L -1.024 .636 L .261 -.204 L -.557 .062 L -.283 .092 L -.628 .522 L -.141 .261 L .126 .229 L .344 .152 L -.932 .521 L -.182 .199 L .342 .167 L -.647 .352 L -.88 .55 L -.626 .503 L -.298 .35 L -.01 .531 L .421 .317 L .477 .09 L 1.382 -.048 L .562 .166 L .11 .167 L -.436 .394 L -.752 .455 L -.181 .302 L .224 .512 L .292 .452 L .786 .089 L .165 .391 L -.014 .616 L -.349 .361 L -.528 .061 L -.481 -.209 L -.017 -.21 L .388 -.527 L -.444 -.014 L -.454 .242 L -1.014 .843 L -.56 .675 L -.237 .599 L .321 .672 L .647 .311 L .154 .237 L -.294 .387 L -.688 .313 L -.956 .031 L -.664 -.088 L -.344 .001 L -.619 .179 L -.837 .476 L -.214 .149 L -.525 .504 L -.137 .341 L .111 .281 L .492 .398 L .038 .221 L -.056 .133 L -.679 .238 L -.604 .016 L 753.44 82.4 l -.727 .296 L -.065 .251 L .067 .28 L -.161 .854 L -.293 .412 L -.8 .78 L -1.53 .971 L -.854 .5 L -.285 .103 L -.295 -.614 L -.198 -.821 L -.25 -.69 L -.064 -.794 L -.351 -.75 L -.305 -.383 L -.214 -.915 L -.514 -1.36 L -.008 -.578 L -.154 -.563 L -.017 -.327 L -.105 -.193 L -.262 -.817 L -.026 -.792 L .116 -.808 L .271 -1.396 L .167 -.226 L 1.185 -.86 L .716 -.424 L .57 -.695 L .14 -.227 L -.085 -.318 L -.139 -.166 L 1.632 -.367 L 1.001 -.305 L .811 -.32 L 1.729 -.884 L .641 -.412 L .431 -.428 L .14 -.335 L 1.784 -.889 L .872 -.445 L 1.535 -.861 L .368 -.293 L .26 -.433 L 1.252 -.435 L 2.106 -.514 L .257 -.434 L .773 -.528 L .086 -.233 L -.568 -.216 L .814 -.904 L -.036 -.483 L .183 -.391 L .598 -.204 L 1.729 -.082 L .513 -.063 L -.485 -.328 L -2.065 -.215 L -.71 .095 L -1.062 .174 L -.777 .189 L .042 .328 L -.664 .923 L .125 .202 L -.04 .14 L -.662 .11 L -.479 .11 L -1.555 .718 L -1.979 1.042 L -1.169 .342 L -.249 -.062 L .156 -.325 L .352 -.465 L -.933 -.076 L -.16 -.263 L .252 -.451 L .442 -.467 L .207 -.328 L -.069 -.202 L -.339 -.031 L -1.136 .454 L -.496 .032 L -.277 -.358 L -.589 -.17 L -1.606 .144 L -1.312 .111 L -.956 .08 L -.606 .157 L -.894 .359 L -.093 .436 L .082 .186 L -1.262 .53 L -.408 .233 L .149 .495 L -1.294 .357 L -1.019 .434 L -.84 .479 L -.496 .461 L -.332 .46 L .004 .383 L .527 .213 L 1.269 .043 L .278 .275 L .062 .122 L -1.152 .139 L -1.028 .262 L -1.045 -.059 L -.698 -.136 L -.382 .031 L -.311 .107 L -.721 .398 L -.695 -.35 L -1.112 .383 L -.747 .139 L -.487 -.09 L -.284 -.137 L .108 -.29 L .748 -.124 L .868 -.124 L .164 -.046 L -.741 -.64 L 736.444 68 l -1.06 .017 L -.854 .155 L -.353 -.061 L -.868 -.458 L -.775 -.029 L -.745 .047 L -.704 .246 L .042 .398 L -.26 .229 L -.477 .215 L -.695 -.243 L -.408 -.122 L -1.26 .063 L -.784 .093 L -.651 -.075 L -.887 -.136 L -.563 .078 L -.067 .122 L -.147 .474 L -.677 .017 L -.311 -.137 L -.038 -.382 L -.203 -.259 L -1.241 .094 L -1.014 -.059 L -1.257 .033 L -1.158 .063 L -.836 -.029 L -.18 .016 L -1.085 .292 L -.964 .444 L -.74 .474 L -.536 .504 L -.789 .245 L -.904 .336 L -.194 .152 L -1.047 1.17 L -1.634 .684 L -.949 .471 L -1.157 .711 L -1.653 1.253 L -.828 .572 L -1.573 .873 L -.893 .376 L -1.889 .871 L -.632 .388 L -.203 .298 L .018 .357 L .428 .281 L .485 .043 L .918 .013 L 1.046 -.15 L .656 .043 L -.329 1.261 L .016 .415 L .303 .103 L .63 -.09 L .601 -.371 L .761 .117 L -.127 .148 L 705.293 81 l -.112 .222 L .373 .073 L 1.645 -.018 L .566 -.238 L .39 -.519 L .017 -.638 L .763 .014 L .647 -.001 L .726 .014 L .951 .265 L .658 .354 L .486 .591 L .847 .575 L .426 .176 L .506 .324 L -.07 .148 L -.581 .355 L .453 .221 L .13 .309 L -.336 .723 L .491 .117 L .215 .235 L -.291 .515 L -.348 .397 L -.532 .559 L -.724 1.364 L -.181 .688 L .057 .219 L .24 .701 L -.188 .917 L -.098 .741 L -.403 1.408 L -.146 .493 L -1.928 1.538 L -.371 .435 L -.217 .65 L -.587 .42 L -.741 .579 L -.241 .361 L -.574 .981 L -.587 .606 L -.941 .778 L -1.784 1.512 L -.464 .474 L -.235 .458 L -.323 .33 L -.758 .388 L -.618 .416 L -.574 .702 L -.431 .458 L -.875 .673 L -.955 .487 L -1.838 .475 L -.798 .244 L -.278 -.427 L -.519 -.085 L -.243 .043 L -.337 -.185 L -.337 -.513 L -.663 .272 L -.464 .101 L .424 -.586 L -.624 .173 L -.506 .486 L -.649 .543 L -1.326 1.001 L -.072 .049 L -.167 -.393 L -.298 -.439 L .111 -.058 L 1.252 -.462 L .511 -.43 L .156 -.329 L -.112 -.299 L .097 -.128 L .025 -.385 L .006 -.613 L -.062 -.656 L -.332 -.897 L .048 -.557 L 1.664 -.982 L .396 .041 L .685 .24 L .679 .225 L .547 .098 L .47 -.347 L .551 -.69 L .329 -.432 L .627 -1.08 L .538 -1.066 L .278 -.893 L .291 -.707 L .66 -.393 L .566 -.407 L -.017 -.504 L -.116 -.389 L -.064 -.259 L -.246 -.114 L -.902 .034 L -1.181 .208 L -1.357 .31 L -.953 .308 L -.604 .22 L -1.657 .052 L -.649 .018 L -.68 .033 L -.261 -.446 L -.44 -1.283 L -.297 -.866 L -.205 -.144 L -2.659 -.839 L -1.523 -.253 L -1.247 -.341 L -.507 -.2 L -.436 -.389 L -.927 -1.903 L -.94 -1.588 L -1.087 -2.384 L -.742 -.952 L -.763 -.467 L -.539 -.026 L -1.386 .125 L -.683 -.188 L -1.037 -.481 L -1.148 -.215 L -.917 .049 L -1.203 .109 L -.836 .123 L -1.854 .143 L -.602 .136 L -.478 .165 L -1.193 .787 L -.375 .282 L -.119 .25 L .822 -.078 L .558 .026 L .465 .306 L .107 .249 L -.167 .794 L -1.371 .608 L -.599 .545 L -.667 .779 L -.416 .543 L -.422 .426 L -.103 .249 L .062 .146 L .35 .348 L .056 .306 L -.123 .233 L -.779 .339 L -2.44 .752 L -.438 .089 L -.343 .016 L -1.126 -.574 L -.452 -.172 L -.046 -.018 L -.431 -.168 L -.622 .018 L -1.228 .297 L -.86 -.169 L -.34 -.129 L -.751 -.506 L -.74 -.156 L -.609 .047 L -.333 .002 L -1.165 .487 L -.755 .498 L -.447 .394 L -.604 .264 L -.526 .163 L -1.147 .136 L -.867 .106 L -.532 .075 L -1.018 .063 L -1.602 .11 L -.739 -.039 L -.984 -.082 L -.905 -.241 L -1.318 -.254 L -.812 -.373 L -1.132 -.313 L -.623 -.331 L -1.333 -.75 L -.769 -.229 L -1.423 -.022 L -1.172 -.037 L -.796 .077 L -2.48 .538 L -.673 -.113 L -1.643 -.531 L -.421 -.333 L -.408 -.451 L -.182 -.481 L -.004 -.541 L -.145 -.204 L -.767 -.143 L -.989 -.317 L -.702 -.231 L -1.748 -.328 L -1.036 -.185 L -1.028 -.098 L -.84 -.201 L -1.269 .96 L -.905 .839 L -.098 .293 L .409 .86 L .396 .304 L .116 .204 L -.163 .526 L -.744 .572 L -.31 .162 L -.755 .28 L -.562 .018 L -.576 -.186 L -.312 -.114 L -.875 -.068 L -.85 .004 L -.719 -.083 L -1.458 .008 L -.699 -.113 L -.393 -.406 L -.694 -.755 L -.831 -.083 L -1.842 -.122 L -.932 -.156 L -.953 -.097 L -.84 .18 L -1.512 .476 L -1.143 .341 L -.787 .398 L -.971 .692 L -.017 .012 L -.727 .381 L -.603 .148 L -1.387 .08 L -.599 .207 L -.799 .425 L -.154 .044 L -.244 .074 L -.569 .003 L -.228 .014 L -.064 -.145 L -.589 0 L -.294 -.478 L -.441 -.331 L .073 -.331 L -.625 .184 L -.478 .368 L -.993 -.074 L -.882 -.073 L -.662 -.699 L -.588 -.552 L -.956 -.147 L -.331 -.625 L -.772 -.588 L -.698 -.441 L -.993 .037 L -.771 .221 L -.993 .221 L -.992 0 L -.589 0 L -.184 -.184 L -.258 -.257 L -.478 0 L 0 -.368 L -.367 -.331 L -.92 0 L -.367 .515 L -.331 .257 L -.515 .257 L -1.104 -1.434 L -.846 -.882 L -1.69 -2.133 L -1.066 -1.029 L -1.287 -.772 L -.809 -.294 L -1.104 -.588 L .11 -.368 L .515 -.11 L 0 -.441 L -.809 .074 L -.515 .22 L -.772 .221 L -.956 .515 L -1.103 .257 L -.772 .441 L -.294 .294 L -.552 -.184 L -.441 -.037 L -.771 .073 L -.441 .11 L -.331 -.184 L .331 -.441 L .441 -.184 L .146 -.294 L -.367 0 L -.441 .221 L -.478 -.11 L -.405 -.294 L -.478 -.037 L -.184 .147 L -.147 .147 L -.367 -.221 L -.295 -.368 L -.294 -.11 L -.331 .221 L -.367 -.074 L -.368 .147 L -.44 -.11 L -.295 .147 L -.478 -.074 L -.184 -.257 L .33 -.037 L -.073 -.331 L .147 -.257 L .11 -.331 L -.515 -.22 L -.147 -.221 L .037 -.331 L -.368 -.404 L -.882 .037 L -.625 .11 L -.772 -.257 L -.515 -.11 L -.919 -.147 L -.735 .037 L -.11 .221 L -.589 .184 L -.515 .037 L 0 .294 L -.367 .368 L -.625 .074 L -1.876 .073 L -2.021 .405 L -1.177 .037 L -.625 .331 L -.221 .331 L -.331 -.073 L -.588 .073 L -1.545 .11 L -.735 .11 L -1.029 .037 L -1.396 .405 L -.368 .184 L -.772 0 L -.515 0 L 537.304 80 l -.33 .074 L -.185 .515 L .074 .441 L .294 .221 L -.294 .074 L 0 .331 L 1.065 .11 L .956 .294 L -.11 .257 L -.515 .073 L -1.103 -.147 L -.698 .184 L -.662 .515 L .146 .257 L .441 .478 L -.331 .294 L -.588 .147 L -.735 .368 L -.467 .067 L .164 .274 L .239 0 L .377 .137 L -.068 .171 L .377 .137 L .651 .069 L .274 .308 L 1.165 .171 L .24 .24 L -.138 .686 L -.137 .309 L -1.577 .411 L -.959 -.034 L -.343 -.343 L -.24 0 L -.171 .309 L -.651 .343 L -.411 -.171 L -.754 -.137 L -.926 -.309 L -.274 -.548 L -.754 -.103 L -1.062 .103 L -.137 .412 L -.617 .068 L -.651 -.411 L -.65 -.035 L -.823 -.068 L -.514 .377 L -.377 .343 L -.274 .274 L -.686 .171 L -.411 -.24 L -.686 -.137 L -.582 -.548 L -.72 -.068 L .034 .24 L .205 .48 L -.239 .274 L -.274 -.137 L -.068 -.583 L -.411 -.274 L -.789 -.343 L -.582 -.206 L 0 -.343 L -.96 -.171 L -.617 .069 L -.788 -.035 L -.411 -.514 L -.411 -.069 L -.617 .24 L -.273 .137 L -.651 .137 L -.309 -.274 L -.479 0 L -.651 -.069 L -.515 .309 L -.548 .343 L -.788 .377 L -.549 .068 L -.514 .171 L -.309 .309 L -.172 .24 L 509.58 87.5 l -.479 .206 L .068 .445 L .171 .411 L -.068 .446 L -.411 .24 L -.651 0 L -.514 -.411 L -.48 -.548 L -.514 -.24 L -.411 .069 L -.103 .308 L -.343 .549 L -.823 .137 L -.205 1.303 L .343 .171 L .239 .274 L -.239 .206 L -.446 .274 L -.65 1.165 L 1.37 .343 L .138 .377 L -.068 .309 L .514 .514 L .103 -.343 L .583 .206 L .343 -.034 L .514 .034 L .515 .445 L .479 .206 L .343 .514 L .96 1.131 L -.138 .103 L -.445 -.103 L -.309 -.103 L -.343 .103 L .068 .308 L .857 .377 L .616 .19 L -.167 .2 L -.399 .28 L -.38 .12 L -.12 0 L 0 .14 L 0 .22 L -.14 .08 L -.3 -.2 L -.34 .2 L -.399 .26 L -.64 .12 L -.319 .08 L -.26 -.08 L -.181 -.08 L -.1 .04 L -.06 .16 L .12 .26 L -.221 .2 L -.18 .3 L -.18 .319 L -.319 .42 L -.18 .28 L -.32 .16 L -.34 .24 L -.14 .32 L .08 .2 L .34 .2 L .319 .04 L .18 .3 L .24 .04 L .239 .34 L .28 .419 L -.06 .38 L -.101 .2 L .061 .16 L .1 -.2 L .1 -.34 L .12 -.22 L .16 -.02 L -.141 .439 L -.22 .36 L .061 .4 L .12 .1 L -.16 .2 L -.04 .4 L .38 .24 L .119 .1 L .12 .52 L .28 .06 L .359 .42 L .2 .28 L .439 .419 L .18 .36 L .359 .06 L .047 .146 L -.292 .449 L -.496 .284 L -.283 .094 L -.308 .331 L -.165 .213 L -.379 .047 L -.449 -.142 L -.591 -.094 L 0 -.308 L -.283 -.284 L -.118 0 L -.095 -.118 L -.473 -.284 L -.142 -.189 L 504.5 H -.213 .047 L 504.264 107 l -.229 .023 L -.126 -.189 L -.236 -.071 L -.236 .023 L -.284 -.047 L -.26 -.094 L -.284 -.166 L -.354 -.284 L .118 -.307 L .118 -.189 L -.118 -.142 L -.354 -.024 L -.378 0 L -.213 -.166 L -.189 -.118 L -.212 0 L -.143 -.094 L -.236 -.118 L -.118 0 L -.095 .071 L -.142 .166 L -.188 -.142 L -.261 -.071 L -.354 0 L -.213 .071 L -.094 .095 L -.166 .166 L -.283 0 L -.261 .118 L -.212 -.071 L -.261 -.118 L .048 -.118 L .142 -.118 L -.308 -.119 L -.236 -.118 L -.354 -.071 L -.52 -.118 L -.284 -.213 L -.095 -.142 L -.354 -.166 L -.283 .047 L -.189 0 L -.401 -.166 L -.544 0 L -.426 .095 L -.307 0 L -.355 -.047 L -.307 -.071 L -.261 -.095 L -.212 -.166 L -.213 0 L -.331 0 L -.189 -.047 L -.188 -.094 L -.284 -.142 L -.283 -.095 L -.449 -.023 L -.402 -.023 L -.07 -.047 L -.284 -.047 L -.26 .166 L -.112 .309 L -1.421 -1.012 L -1.188 -.842 L -.817 -.385 L -.62 -.084 L -.373 -.157 L -.509 -.5 L -.236 -.057 L -.338 .159 L -.329 -.042 L -.347 -.515 L -.795 -.674 L .595 -.188 L .519 -.001 L .445 -.073 L .1 -.519 L .359 -.476 L 485 97.85 l .526 -.03 L .516 -.131 L -.432 -.532 L -.654 -.273 L -.474 -.36 L .243 -.116 L .367 -.03 L .82 -.117 L .715 -.348 L 1.244 -.436 L -.196 -.375 L -.076 -.058 L -.799 .088 L -1.312 .175 L .012 -.126 L .021 -.112 L 0 -.224 L .09 -.514 L .224 -.089 L .357 -.022 L .38 -.134 L .223 -.179 L .022 -.179 L .269 0 L .736 -.045 L .805 .157 L .335 -.134 L 0 -.156 L .156 -.291 L .156 -.491 L -.066 -.067 L -.09 -.201 L -.045 -.179 L -.044 -.134 L -.179 -.067 L -.156 -.067 L .044 -.224 L .045 -.179 L .246 0 L .312 0 L .134 -.156 L -.29 -.044 L -.269 -.089 L -.223 -.246 L .312 -.044 L .357 -.201 L .156 -.067 L .201 -.089 L .045 -.224 L -.09 -.179 L -.111 -.089 L .022 -.179 L .089 -.111 L -.156 -.089 L -.201 .089 L -.134 .044 L -.269 0 L -.357 -.156 L -.111 -.224 L -.469 -.022 L -.291 -.089 L -.201 -.179 L -.357 .067 L -.268 -.112 L -.469 -.112 L -.425 -.067 L -.29 -.268 L -.224 .067 L -.045 .157 L -.29 .134 L -.224 -.112 L -.179 -.179 L -.402 -.044 L -.022 -.134 L -.201 -.179 L 0 -.134 L -.268 -.179 L -.111 -.156 L -.357 .067 L -.536 .134 L -.269 0 L -.312 .112 L -.425 .112 L -.179 -.156 L -.179 -.022 L -.201 .067 L -.469 -.291 L -.268 -.067 L -.47 .067 L -.268 .179 L -.291 -.29 L -.179 -.089 L -.089 -.224 L .089 -.179 L -.089 -.246 L -.224 -.268 L 0 -.357 L -.402 0 L 0 -.312 L -.38 -.022 L -.514 .067 L -.156 -.112 L -.647 0 L -.269 -.29 L -.111 -.357 L -.134 -.291 L .312 -.134 L .312 .022 L 0 -.268 L -.312 -.156 L -.246 -.156 L -.134 -.201 L -.246 -.335 L -.312 -.134 L -.201 -.268 L -.514 .134 L -.692 -.112 L -.67 .223 L -.536 .022 L -.536 -.246 L -.134 .268 L -.179 .291 L -.313 .156 L -.469 -.022 L -.357 -.089 L h 527.156 37.071 m -.59 -.14 L -.955 -.21 L -1.128 -.139 L -.739 .054 L -.959 .037 L -.732 .143 L -.411 -.105 L -1.025 -.476 L .737 -.303 L 1.21 -.429 L .654 -.09 L 1.549 -.002 L .135 -.357 L -.728 -.338 L .351 -.269 L .419 -.144 L .676 -.02 L .852 -.181 L -.25 -.161 L -.526 -.233 L 1.539 -.895 L .513 -.129 L .226 .073 L .892 .017 L .981 -.535 L .863 -.333 L 1.02 -.261 L .975 -.15 L 1.305 -.113 L 1.274 .053 L .738 -.15 L .786 -.615 L .273 .018 L .873 -.132 L 1.722 .276 L .471 -.038 L 1.93 -.321 L .958 -.039 L 2.184 -.247 L 1.864 -.116 L .771 -.564 L .376 -.152 L 2.511 -.137 L 1.965 -.079 L .471 .131 L .442 .225 L .154 .357 L -.812 .47 L -.541 .169 L -1.346 .319 L -2.609 .433 L -4.329 .49 L -2.187 .281 L -2.122 .299 L -1.842 .316 L -2.102 .242 L -.941 .203 L -.288 .274 L .644 .216 L -.422 .217 L -.943 .361 L -.527 .037 L -2.047 -.068 L -.432 .18 L -.119 .233 L .621 .249 L -.331 .233 L -1.206 .448 L -.402 -.142 L -.752 -.087 L -.592 .304 L .877 .283 L .052 .319 L -1.094 .657 L -.822 .284 L h 517.491 38.443 m 1.041 -.37 L .512 -.299 L .428 -.212 L 1.426 -.021 L 1.316 -.249 L .987 -.02 L 1.412 -.091 L .551 .069 L .988 .227 L -.063 .176 L -.463 .528 L -.302 .158 L -.697 .071 L -.443 .228 L -.233 .385 L .006 .818 L .445 1.039 L .957 .826 L .505 .308 L .775 .307 L 1.162 .392 L -.028 .282 L -2.62 -.089 L -.844 .053 L -.917 .326 L -.596 .086 L -.676 -.494 L -.382 -.034 L -1.091 .088 L -.673 -.102 L -.031 -.359 L 1.347 -.362 L .073 -.24 L -.102 -.017 L -.944 -.273 L -1.442 -.411 L -1.519 -.17 L -.33 .156 L -.624 .122 L -.681 -.033 L -.625 -.396 L -.114 -.415 L .229 -.312 L .39 -.209 L .344 -.036 L .318 .104 L .65 .016 L .518 -.192 L 1.121 -.768 L .243 -.35 L -.322 0 L -.981 -.243 L h .125 56.089 m 0 -.562 L 0 -.576 L 0 -.157 L 0 -1.292 L 51.28 V 0 -2.222 L 0 -2.12 L 2.917 .61 L 1.693 .598 L .933 .181 L 3.819 .99 L 1.059 .395 L .204 .149 L .074 .214 L .445 .429 L .406 .789 L -.209 .428 L 1.034 .8 L .982 .26 L -.02 -.18 L .297 -.148 L -.051 -.196 L -.638 -.392 L .016 -.542 L .077 -.296 L 1.026 -.183 L .984 .278 L .573 .098 L .767 .064 L 1.003 -.117 L .933 .13 L .93 .425 L .694 .359 L 1.676 .684 L .32 .081 L .584 .179 L .43 .211 L .09 .13 L -.343 .033 L -1.026 -.096 L -.364 .034 L -.808 .798 L -1.539 -.468 L .138 .178 L .438 .227 L .465 .324 L -1.177 -.111 L -1.008 .05 L -1.202 -.387 L -.708 -.096 L .135 .129 L .289 .259 L .084 0 L .561 .259 L .205 .307 L .131 .453 L -.056 .339 L -.814 .05 L -.805 .065 L -.189 .161 L .5 .865 L -.115 .272 L -1.04 -.078 L -.397 .081 L -1.193 -.174 L -.264 -.352 L -1.795 -.51 L -.253 .273 L 9.85 55.79 l -.276 -.161 L -.265 -.403 L .174 -.178 L -.321 -.42 L -.87 -.339 L -.565 -.063 L -.762 .034 L -.858 .229 L -1.343 .084 L 3.57 54.443 l .059 -.325 L -.155 -.325 L -.618 -.487 L 1.958 53.43 l -.45 .409 L -.655 1.228 L -.166 .715 L -.562 .307 L +449.401 22.792 N -1.596 -.014 L -2.019 -.016 L -1.739 .063 L -.764 .061 L -1.972 -.316 L .812 -.456 L .826 -.172 L .735 -.453 L 1.148 -.588 L 1.354 .691 L .998 .105 L 1.116 -.088 L .9 .084 L .704 .341 L .865 -.323 L .53 -.454 L .868 -.306 L -.311 .823 L .086 .32 L .851 -.001 L .991 -.495 L 1.061 -.261 L .803 .128 L .559 .472 L .705 .041 L 2.007 -.111 L 1.543 .189 L .551 .376 L -.507 .201 L -2.004 .622 L -1.623 .38 L -1.069 .062 L -.976 .14 L -1.324 .366 L -6.271 -.097 L -.033 -.377 L 1.492 -.26 L .702 -.677 L h 430.027 22.752 m .068 .697 L .252 .119 L 1.694 .155 L .221 -.377 L .13 -.418 L .573 -.141 L .523 -.041 L .949 .477 L 1.192 .771 L .798 .235 L .568 -.218 L -.222 -.296 L -.46 -.356 L -.327 -.477 L -.04 -.22 L .91 -.407 L 1.001 .103 L .485 .18 L 1.278 .018 L .586 .179 L -.08 .419 L -.169 .298 L .104 .159 L .549 .118 L .743 -.338 L .44 -.1 L .662 .396 L .678 .335 L .785 .156 L .948 .117 L 1.672 .429 L .498 .234 L -1.305 .277 L -1.981 .218 L -.696 .293 L -.731 1.144 L -.885 .885 L -1.243 .117 L -.766 .535 L -.455 .589 L -.029 .378 L -.786 .209 L -.556 -.018 L -1.593 -.355 L -1.883 -.507 L -1.365 -.568 L .651 -.364 L 1.565 -.041 L 1.788 -.137 L .944 -.386 L -.652 -.249 L -1.822 .139 L -1.566 .118 L -1.694 .042 L -.502 -.519 L .959 -.06 L 1.371 -.215 L 2.149 -.314 L 1.547 -.45 L -2.525 -.405 L -.881 -.292 L -.589 .138 L -1.036 .646 L -1.069 .293 L -.562 .059 L -1.236 -.172 L -.338 -.174 L -1.05 -.368 L -.807 -.233 L -.698 -.41 L 1.698 -.396 L -.817 -.571 L -1.359 .319 L -.467 -.078 L -.924 -.751 L .812 -.36 L .516 -.021 L 1.075 -.122 L 1.017 .038 L .577 -.061 L 1.188 -.042 L h 425.42 68.82 m -.148 -.21 L -.629 .132 L -.134 -.026 L -.249 -.237 L -.239 -.343 L .188 -.158 L -.143 -.291 L -.361 .185 L -.062 .29 L .113 .237 L -.147 .105 L -.339 .316 L -.086 .185 L -.521 .105 L -.533 -.131 L -.781 .342 L .057 .131 L -.502 .289 L -.498 .263 L -1.658 .813 L 418.697 71 l -.274 .052 L -.271 0 L -2.111 .209 L -.188 -.236 L -.33 -.131 L -.183 .209 L 414.976 71 l .384 -.184 L -.935 -.236 L -.794 -.341 L -.574 -.052 L -.479 -.578 L .292 -.368 L -.126 -.21 L .34 .026 L .085 .316 L .284 -.21 L .667 .263 L -.244 -.197 L .127 -.145 L .5 -.092 L -.479 .026 L -.245 .105 L -.263 -.184 L -.111 -.132 L .579 -.276 L .455 -.185 L -.482 .066 L -.317 -.132 L .441 -.237 L .083 -.237 L -.661 .475 L -.036 -.264 L -.265 -.171 L .005 .211 L .076 .171 L -.419 .158 L -.41 0 L .014 -.277 L -.15 .264 L -.235 -.079 L -.2 -.448 L .658 -.449 L .08 .436 L .068 -.317 L .438 .158 L .211 -.092 L -.166 -.106 L .674 -.079 L .479 -.251 L -.611 .159 L -.48 0 L -.335 -.159 L .196 -.132 L .387 -.146 L .196 -.471 L -.821 -.014 L -.546 .094 L -.406 -.309 L .368 -.14 L .643 -.404 L -.212 -.186 L -.445 .063 L -.399 -.062 L -.211 -.217 L .284 -.482 L .619 -.265 L -.595 -.248 L -.225 -.374 L .272 -.188 L -.089 -.687 L .106 -.094 L .594 -.063 L .392 -.045 L .455 .044 L .082 -.11 L -.255 -.134 L -.425 -.118 L -.228 -.17 L .098 -.188 L .211 -.125 L .575 -.064 L .511 -.346 L .567 .109 L .498 -.111 L .179 -.55 L .835 .093 L .668 .125 L .571 -.252 L -.989 -.234 L -.266 -.314 L .236 -.143 L 1.151 .014 L .851 -.08 L .538 .219 L .06 -.473 L .477 -.27 L .297 -.333 L .78 -.175 L .438 .189 L .138 .079 L .5 -.476 L .869 -.413 L .084 -.429 L .437 -.398 L 1.497 -.735 L .335 -.192 L .235 -.048 L .481 .175 L .335 -.001 L .319 -.224 L -.225 -.223 L .141 -.128 L .488 -.224 L .457 -.305 L .481 -.483 L .245 .064 L .676 -.017 L -.067 -.612 L -.471 -.112 L .434 -.405 L .511 -.648 L .841 .063 L .047 -.341 L .096 -.228 L .954 -.116 L -.396 -.357 L -.327 -.097 L -.193 -.146 L .164 -.245 L .313 -.246 L .464 .048 L .888 -.067 L -.543 -.522 L .249 -.082 L .435 -.034 L .707 -.263 L .592 -.067 L .308 -.208 L -.358 -.064 L -.105 -.187 L .289 -.1 L .616 -.33 L .557 .032 L .351 .098 L .434 -.264 L .369 -.031 L .035 -.176 L -.421 -.321 L .627 -.232 L .146 -.275 L .336 .01 L .359 .297 L .397 .082 L .526 -.381 L -.281 -.656 L .438 .065 L .698 -.058 L .207 -.174 L -.604 -.315 L .411 -.224 L .816 -.251 L .093 -.257 L .261 -.194 L .73 -.135 L .074 .067 L .274 -.051 L .102 -.067 L .492 -.67 L .521 .25 L .96 -.153 L .411 .133 L .265 .1 L .646 .065 L .536 -.419 L .747 -.84 L .286 -.085 L .16 .168 L -.178 .286 L -.182 .587 L .791 -.454 L .403 -.572 L .819 -.085 L .688 -.439 L .437 .117 L .665 .353 L .567 -.643 L .318 -.272 L .976 .1 L 1.019 .506 L .197 -.152 L .479 -.595 L .709 -.444 L .283 -.052 L .562 .067 L .338 -.308 L .469 -.291 L .619 -.189 L 1.2 -.173 L .984 .015 L -1.337 .755 L -.24 .273 L -.107 .646 L .42 .084 L .691 -.579 L 1.53 -.941 L .764 -.275 L .028 .257 L -.004 .905 L .704 -.172 L .438 -.239 L .855 -.874 L .959 -.104 L .586 -.001 L .216 .154 L -.383 .257 L -.335 .257 L .074 .239 L -.319 .41 L .921 .118 L .221 -.443 L .902 -.651 L .421 .017 L 1.682 .561 L .667 .135 L .935 .015 L .649 .237 L .1 .272 L -1.216 .393 L -1.148 .036 L -2.233 -.047 L .193 .084 L .585 .304 L 1.058 .284 L .383 .302 L .728 -.052 L .679 -.102 L .831 .032 L .708 .25 L -.404 .288 L -.514 .204 L -.824 .021 L -.77 .121 L -1.023 .49 L -1.013 .672 L -.689 .303 L -.001 -.2 L .096 -.367 L .874 -.923 L -.044 -.268 L -.88 -.348 L -.672 -.114 L -1.125 -.431 L -.556 .003 L -.555 .07 L -2.004 .095 L -.865 .374 L -.567 .422 L -.26 .437 L -.079 .501 L -.188 .5 L -1.25 .472 L -.582 .368 L -.31 -.148 L -1.288 -.492 L -1.657 .225 L -1.411 -.042 L -.536 -.13 L -.861 -.595 L -.994 -.612 L -.486 -.082 L -.355 .103 L -1.012 .656 L -.114 -.063 L -.41 -.031 L -.865 .038 L -.281 1.066 L -.164 .449 L -.271 .25 L -.323 -.015 L -.67 -.129 L -.972 -.144 L -1.731 -.389 L -.168 .183 L -.021 .663 L -.083 .199 L -.318 .299 L -.695 .004 L -.871 -.095 L -.279 -.015 L -.465 .167 L -1.484 1.176 L .05 .213 L .171 .507 L -.188 .345 L -.615 .346 L -1.325 .919 L -.687 .442 L -.981 .021 L -.121 .244 L -.06 .971 L -.32 .598 L -.383 .469 L -.574 .499 L -.495 .545 L .339 .125 L .381 .269 L .252 .587 L -.17 .176 L -.44 .177 L -.733 .036 L -.932 -.027 L -.618 .114 L -.613 .257 L -.617 .479 L -.389 .492 L -.077 .664 L -.349 1.093 L .65 .729 L -.335 1.171 L .582 .39 L .715 .186 L .297 .243 L -.432 .67 L -.941 .16 L .571 .735 L .26 .427 L -.249 .346 L -.029 .532 L -.769 .384 L -.414 .013 L -.117 .423 L -.506 .224 L .22 .831 L -.324 .737 L -.41 .013 L -.15 -.342 L -.293 -.132 L +464.349 47.431 N -.024 .283 L -.258 .465 L .116 .529 L .563 .212 L .872 .194 L .964 .506 L .543 .392 L -.421 .364 L -1.303 .777 L -.328 .296 L 1.402 1.394 L .772 1.195 L -.196 .356 L -.44 .535 L -.187 .403 L -.029 .37 L .37 .509 L 1.286 1.395 L .151 .253 L -.057 .254 L -.542 .415 L -.327 .191 L .439 .33 L 1.357 .499 L .703 .265 L .436 .392 L .161 .346 L -.105 .409 L -.43 .536 L -.591 .536 L -1.385 .758 L -1.983 1.195 L -1.946 1.145 L -.174 .285 L -.935 .206 L -1.195 .188 L -.149 .181 L -.506 -.217 L -.518 .146 L -.052 .134 L -.688 -.07 L -.193 -.108 L .057 -.387 L -.241 .527 L -.268 .14 L -.633 .047 L -.328 .03 L -.1 .267 L -.589 -.326 L -.29 .275 L -.676 .064 L -.34 .178 L -.052 -.127 L -.504 .108 L -.504 .108 L -.211 .266 L -.311 -.152 L -.672 .126 L -.04 -.114 L -.658 .215 L -.547 .013 L -.482 .025 L -.487 -.253 L -.223 -.274 L .273 -.34 L -.846 .017 L -.517 .177 L .065 -.382 L -.446 .076 L -.644 -.271 L -.409 -.061 L -.415 -.231 L -.26 -.403 L -.036 -.714 L .158 -.374 L .05 -.436 L .09 -.234 L -.347 -.483 L -.431 -.375 L .3 -.658 L -.02 -.392 L -.305 -.204 L -.37 -.093 L .062 -.299 L .295 -.331 L .637 -.285 L .144 -.189 L -.113 -.331 L .382 -.143 L .633 .125 L .274 .063 L .483 -.222 L .303 -.427 L .104 -.459 L .207 -.27 L .301 .316 L .27 0 L 1.678 -1.114 L 1.142 -.654 L .835 -.576 L 1.026 -.401 L .874 .03 L .06 -.304 L -.13 -.144 L -.357 -.16 L .119 -.371 L .146 -.387 L -.329 -.274 L -1.139 -.095 L -.836 -.451 L -.594 -.024 L -.113 -.234 L -.327 -.307 L -.208 -.535 L .5 -.8 L -.028 -.392 L -.405 -.685 L -.507 -.637 L .004 -.526 L .062 -.413 L -.77 -.558 L -.508 -.229 L -1.583 -.207 L -1.085 -.292 L -1.286 -.658 L -.616 -.463 L -.146 -.033 L 1.012 -.656 L .355 -.103 L .486 .082 L .994 .612 L .861 .595 L .536 .13 L 1.411 .042 L 1.657 -.225 L 1.288 .492 L .31 .148 L .582 -.368 L 1.25 -.472 L .188 -.5 L .079 -.501 L .26 -.437 L .567 -.422 L .865 -.374 L 2.004 -.095 L .555 -.07 L .556 -.003 L 1.125 .431 L .672 .114 L .88 .348 L .044 .268 L -.874 .923 L -.096 .367 L .001 .2 L +453.795 53.873 N -.23 -.004 L -.975 .164 L -.447 .098 L -.902 -.387 L -.339 -.178 L -.347 .114 L -.641 .374 L -.542 .599 L -.309 .146 L -.658 .018 L -.545 .355 L .325 .241 L .146 .192 L -.355 .273 L -.907 .401 L .317 .271 L .385 .159 L .33 .302 L -.749 .367 L -.405 .43 L -.368 .461 L -1.591 .669 L -.699 .286 L -.456 -.205 L -.326 .08 L -.538 .539 L -.646 .144 L -.663 .348 L -.217 .284 L -.191 .142 L -.746 .033 L -.221 -.031 L .151 .535 L -.484 .425 L 439 61.33 l .216 .533 L .243 .25 L -.244 .955 L -.498 .063 L -.217 .204 L .189 .757 L -.009 .544 L .381 .444 L -.287 .175 L .926 .082 L .225 .187 L .499 -.082 L .652 .594 L .428 .314 L .86 .163 L .198 .406 L .32 .139 L .014 .335 L -.391 0 L -.508 .323 L -.861 .3 L -.492 .162 L -.521 -.012 L -.146 -.115 L -.805 -.115 L -.66 -.173 L -.634 -.069 L -.137 .104 L -.446 -.115 L -.257 .3 L .819 -.069 L .497 .265 L .591 .046 L .205 .208 L .481 .069 L .021 -.127 L .616 .069 L .258 -.196 L .297 .011 L .481 -.104 L .226 .081 L .026 -.15 L .164 0 L .214 .15 L -.029 .081 L -.722 .023 L .219 .288 L -.792 .265 L -.168 .288 L -.386 .08 L -.089 -.092 L .042 -.161 L -.014 -.276 L -.258 .023 L -.091 .46 L -.501 .333 L -.248 .058 L -.36 -.069 L -.005 .218 L -1.418 .035 L .156 .458 L .513 .258 L .066 .609 L -.109 .33 L -.281 .051 L -.308 -.064 L .038 .429 L .29 .081 L -.126 .268 L .24 .228 L -.365 .364 L -.222 .455 L -.041 .56 L -.766 1.043 L -.58 .71 L -.165 -.062 L -.442 -.236 L -.614 .193 L -1.262 -.089 L -.106 .311 L -.252 -.083 L -.518 .264 L -.295 .517 L .356 .336 L -.376 .374 L -.48 -.129 L -.173 -.037 L -1.158 .269 L -1.11 -.116 L -.001 -.142 L .19 -.078 L -.062 -.181 L .281 -.297 L -.638 -.53 L -.413 -.479 L -.22 -.272 L .529 -.116 L -.082 -.312 L .421 .077 L .147 -.245 L -.19 -.234 L -.285 .013 L -.292 -.377 L -.527 -.221 L -.63 -.99 L -.286 0 L .011 -.408 L -.256 -.364 L -.348 -.298 L .221 -.484 L .206 -.341 L -.418 -.154 L -.405 .102 L -.055 -.288 L -.412 .051 L -.18 -1.207 L -.225 -.131 L .311 -.355 L .293 .132 L .15 .342 L .41 -.013 L .324 -.737 L -.22 -.831 L .506 -.224 L .117 -.423 L .414 -.013 L .769 -.384 L .029 -.532 L .249 -.346 L -.26 -.427 L -.571 -.735 L .941 -.16 L .432 -.67 L -.297 -.243 L -.715 -.186 L -.582 -.39 L .335 -1.171 L -.65 -.729 L .349 -1.093 L .077 -.664 L .389 -.492 L .617 -.479 L .613 -.257 L .618 -.114 L .932 .027 L .733 -.036 L .44 -.177 L .17 -.176 L -.252 -.587 L -.381 -.269 L -.339 -.125 L .495 -.545 L .574 -.499 L .383 -.469 L .32 -.598 L .06 -.971 L .121 -.244 L .981 -.021 L .687 -.442 L 1.325 -.919 L .615 -.346 L .188 -.345 L -.171 -.507 L -.05 -.213 L 1.484 -1.176 L .465 -.167 L .279 .015 L .871 .095 L .695 -.004 L .318 -.299 L .083 -.199 L .021 -.663 L .168 -.183 L 1.731 .389 L .972 .144 L .67 .129 L .323 .015 L .271 -.25 L .164 -.449 L .281 -1.066 L .865 -.038 L .41 .031 L .114 .063 L .146 .033 L .616 .463 L 1.286 .658 L 1.085 .292 L 1.583 .207 L .508 .229 L .77 .558 L -.062 .413 L -.004 .526 L .507 .637 L .405 .685 L .028 .392 L -.5 .8 L .208 .535 L .327 .307 L .113 .234 L +238.107 361.753 N .515 -.688 L .859 0 L 1.202 -.515 L -.171 -.858 L -3.091 .344 L -2.061 .515 L -1.545 -.344 L -.515 -.858 L 1.374 -.515 L 1.202 -.172 L 3.091 -.172 L 1.374 -.515 L -.172 -1.03 L .859 -.516 L 0 -1.374 L -1.326 -1.054 L .982 -.491 L 1.202 -.344 L 1.545 -.172 L .858 .344 L .858 .858 L 1.03 1.374 L 1.374 1.202 L 1.03 1.373 L -.515 2.061 L -1.545 .516 L -1.545 .858 L -3.434 .172 L -3.435 0 L h 172.686 360.379 m 3.091 -.687 L 3.262 0 L 5.495 0 L 2.919 1.202 L -2.748 .687 L -3.759 -.337 L -5.169 -.35 L -3.091 -.516 L h 65.13 371.085 m 1.194 -.265 L 1.393 .133 L .796 .464 L -1.99 0 L -1.393 -.332 L h 277.944 379.954 m .515 -1.202 L 2.404 -1.03 L 2.748 -.172 L 2.061 -.171 L 1.545 -.859 L .343 -1.545 L 1.374 -.687 L 3.091 -.688 L 4.464 0 L 2.404 0 L 3.434 .688 L .687 1.889 L 0 1.202 L -2.061 1.201 L -11.848 1.03 L -11.161 .344 L h 36.004 376.434 m 1.202 -.858 L 2.061 -.343 L 4.121 .515 L 4.293 1.374 L -.887 .482 L -2.719 .204 L -4.293 -.515 L -3.777 -.859 L h 777.843 385.46 m 3.823 .391 L .899 .029 L .322 .234 L 1.202 .294 L 2.329 .088 L 2.126 -.003 L 5.218 .329 L 3.046 .348 L 1.144 -.059 L .762 .029 L 1.411 .37 L 0 2.175 L 0 2.223 L 0 2.222 L 0 2.223 L 0 2.222 L 0 1.551 L -.041 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.182 0 L -.041 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.223 0 L -2.182 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.223 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L -2.222 0 L 9.014 H 6.792 H 4.569 H 2.347 H .125 H 0 -1.544 L 0 -2.222 L 0 -2.223 L 0 -2.222 L 0 -2.223 L 0 -2.223 L 3.941 .297 L 10.131 0 L 7.898 .516 L 6.868 .172 L 8.586 .858 L 6.353 .515 L 8.757 .172 L 4.808 -.172 L 6.525 -.172 L 2.404 .344 L 3.606 -.858 L 16.312 .344 L 4.638 -.013 L 1.143 -.467 L -14.366 -.551 L -9.616 -.688 L -2.232 0 L -3.091 -.172 L -.858 -.171 L -1.545 -.344 L -.498 -.455 L .155 -1.434 L .687 -.858 L 1.889 -.688 L -3.263 -.687 L -2.232 -.344 L -.953 -.503 L 1.589 -.521 L -2.891 -.6 L -3.074 -.208 L -.104 -.261 L 2.857 -.312 L 2.748 0 L 6.525 .343 L 3.434 0 L 2.576 .344 L 4.636 -1.202 L 2.404 -.687 L -2.748 -1.03 L -3.778 -.858 L -4.391 -.405 L -2.649 -.625 L -3.262 -.172 L -2.919 0 L -2.919 -.858 L 2.576 -.516 L 1.28 -.342 L -1.28 -.517 L -2.919 .516 L 52.66 H -1.717 -.344 L 49.054 373 l .343 -1.202 L 1.956 -.07 L 1.65 -.273 L 4.98 0 L 4.626 .493 L 3.272 .709 L 1.374 .172 L 4.465 -.858 L 4.089 .243 L 0 -.729 L .066 -.597 L -2.255 -.73 L -2.93 -.075 L -2.576 -.344 L 2.404 -.687 L 4.121 .171 L 1.717 -.343 L 3.091 -.516 L 3.09 -.343 L 5.667 -.688 L 4.465 -.343 L 3.949 -.516 L 4.464 -.515 L 2.748 .343 L 5.667 0 L 4.464 .258 L 4.121 -.515 L 7.898 .343 L 7.555 -.687 L 3.091 .172 L 1.545 -.688 L 1.545 .516 L 5.323 -.172 L .121 -.87 L 1.758 -.293 L 1.433 .325 L .586 .554 L -.423 .813 L 2.364 .329 L 1.38 -.264 L -.006 -.938 L 1.438 -.267 L 1.48 .267 L .212 1.036 L -1.009 .423 L .521 .781 L 3.024 -.351 L 1.889 .343 L 3.434 .172 L 2.576 -.687 L 3.778 .086 L 4.868 .33 L 2.344 .013 L 1.449 .109 L .693 -.53 L -.611 -.285 L -2.202 -.122 L 1.305 -.285 L .041 -.408 L -.367 -.245 L -1.386 .123 L -.693 .04 L -.856 -.979 L -2.178 -.337 L -.676 -.193 L -.182 -.665 L 4.056 .462 L 3.874 -.245 L -1.224 -.489 L -6.035 -.163 L -.774 -.082 L -.653 -.489 L 0 -.815 L 2.301 .105 L .839 .67 L 5.301 -.204 L 7.253 .736 L 2.404 -.172 L 3.262 -.172 L 4.464 .172 L 3.263 .172 L 2.061 -.516 L .687 -.687 L 1.202 0 L .344 1.03 L 2.576 .343 L 2.404 -.343 L .858 .515 L 3.435 .688 L 3.777 .343 L 2.061 .172 L 1.03 -.515 L .687 -1.202 L 2.747 -.172 L 1.03 .515 L 1.717 .688 L 3.091 -.172 L 3.434 .258 L 4.121 -.344 L 4.979 -.516 L 5.495 -.858 L 3.091 -.515 L 1.202 -.688 L 0 -1.373 L -1.374 -1.202 L -.859 -1.545 L -1.202 -.688 L -.344 -1.03 L 1.202 -1.03 L 1.717 -.343 L .858 -1.202 L -.343 -.858 L -.172 -1.03 L -1.202 -.516 L .344 -1.545 L 1.889 -.172 L 2.404 -1.374 L 1.545 -.515 L .859 -.859 L 1.03 -.687 L 2.919 -1.202 L 3.606 -.515 L 2.404 -1.202 L 2.404 -.172 L 2.232 -1.03 L 1.545 -.343 L .343 1.03 L -1.374 .515 L -1.03 .344 L -1.202 .515 L -.858 0 L -1.202 0 L -2.919 1.202 L -1.03 .687 L -1.717 1.374 L -.172 1.202 L -.687 .687 L -1.374 -.344 L -1.03 0 L -1.202 .516 L -1.202 .687 L -1.03 .688 L -.687 1.201 L .515 .688 L .687 .687 L 1.374 .344 L 1.545 0 L .858 .515 L .687 1.202 L 1.545 1.546 L .687 .858 L 1.03 .687 L .687 1.374 L .858 1.373 L .344 1.546 L -.344 .858 L -.858 1.717 L -2.919 1.889 L -1.202 .172 L -1.03 .858 L -1.717 1.03 L -3.263 .344 L -4.979 .858 L -2.404 .344 L -2.919 .687 L -7.377 -.141 L -4.556 -.316 L -.773 -.401 L -1.717 -.344 L -1.717 -.343 L -1.374 0 L -.859 .515 L .515 .858 L 2.061 .688 L 4.121 1.202 L 4.995 .04 L 1.202 .759 L -3.278 .574 L -5.667 -.343 L -4.979 -.516 L -3.097 -.285 L -2.151 .253 L .823 .696 L 1.164 .538 L 3.262 .172 L 2.232 0 L 1.374 .343 L -.249 .402 L -.782 .113 L -2.232 .515 L -5.151 -.171 L -1.374 -.172 L -2.232 -1.202 L -2.404 0 L .128 .917 L 2.62 1.144 L 1.03 .172 L 1.202 -.172 L 1.374 .344 L 2.404 0 L 4.98 -.516 L 3.09 .687 L .385 .431 L -.041 .6 L -2.061 .172 L -3.263 .172 L -2.608 -.185 L 3.811 .871 L 3.656 -.238 L 1.324 .41 L 2.576 .687 L 6.869 .859 L 8.585 .858 L 10.646 1.373 L 6.525 .516 L 2.061 .858 L .687 1.03 L 3.091 -.344 L 5.323 -1.545 L 6.525 -.687 L 2.455 -.066 L 6.474 -.105 L 9.788 -.344 L 1.889 .344 L 2.576 -1.202 L 8.414 -1.03 L 11.333 -.172 L 8.929 -.858 L 1.202 -.858 L -1.202 -.516 L -.271 -1.07 L -1.184 -.338 L -5.071 .035 L -2.232 .172 L -4.808 -.344 L -3.091 0 L 0 -1.202 L 3.263 -1.545 L 3.949 -1.202 L 2.404 -.172 L 4.121 -1.03 L 9.444 -1.202 L 5.323 -.858 L 6.525 0 L 4.979 -.516 L 2.747 -2.061 L 6.039 -1.541 L -1.23 -.52 L -2.576 .516 L -2.061 -.344 L 1.545 -1.03 L 1.545 -.343 L 2.48 -.249 L .696 -.742 L 3.85 -.742 L 1.577 -.418 L .603 -.557 L -1.716 -.881 L -.093 -.604 L 1.252 -.231 L .464 .742 L 1.017 -.097 L 2.061 -.858 L 1.03 -.343 L .858 .171 L 1.203 1.544 L 2.403 -.342 L .242 -.91 L .96 -.807 L 1.889 -.516 L 1.374 .516 L -1.162 .574 L -.139 .604 L 3.189 -.319 L 4.808 .258 L 3.263 -.172 L 1.03 .858 L 1.545 -.344 L 1.717 -.515 L 5.839 -.858 L 7.212 -1.03 L 4.292 -.858 L 2.061 0 L 2.061 1.373 L 1.718 .344 L 1.889 -.344 L 1.545 -.858 L 7.556 -.344 L 3.434 -.171 L 4.293 .171 L 6.697 .945 L 2.575 0 L 4.293 -.516 L 6.01 -.687 L 5.151 -.688 L 2.404 -.515 L 2.231 -.344 L .615 -.959 L 1.148 -.835 L 1.671 -.095 L .938 .965 L 1.294 .409 L 1.732 1.052 L 1.009 .139 L 1.009 -.661 L 1.322 -.174 L .209 .522 L -.835 .312 L .661 .244 L .8 .278 L .383 -.383 L .313 -.383 L .312 .209 L -.174 .348 L 0 .521 L .592 -.174 L 1.913 -.557 L .418 -1.704 L 5.102 -1.137 L 1.374 -.687 L 3.605 -.172 L 1.363 -.646 L 2.758 -.126 L .21 -.27 L -.165 -.297 L .692 -.23 L 1.221 .165 L .197 .593 L .66 .231 L 2.165 -.536 L 1.265 -.223 L -.726 -.297 L -.561 -.264 L .099 -.362 L 1.451 -.1 L 1.562 .215 L .647 .28 L .692 -.132 L -.066 -.33 L -.527 -.33 L 0 -.561 L .297 -.23 L .846 -.242 L 4.292 -.858 L 2.92 -.172 L 3.058 .115 L 2.296 1.076 L 1.316 .023 L .741 .144 L .023 .383 L -.908 .096 L -.168 .454 L 1.723 .216 L 4.892 .646 L 5.571 .453 L 1.546 .172 L 1.717 -.172 L 7.556 .688 L 5.323 0 L .687 .687 L .2 1.075 L -.73 1.232 L -.672 .439 L -.425 1.113 L -.73 .319 L -.905 -.402 L -.83 .402 L -.73 .959 L 1.507 .457 L .594 .045 L .959 -.593 L .411 .365 L -.867 1.05 L -1.215 .062 L -1.717 1.374 L 0 .858 L 1.889 .688 L 2.919 0 L 1.718 -.859 L 1.889 -1.545 L 1.717 -1.717 L 1.374 -.688 L 4.121 -1.03 L 2.231 -.687 L 3.263 -.344 L 2.061 -1.03 L 1.03 -1.03 L 3.435 -1.03 L 2.403 -.687 L 2.061 -.687 L 2.061 -.172 L 6.182 -.687 L 3.778 .171 L 1.204 -.542 L .169 -.659 L .54 -.759 L .49 -.101 L .471 .776 L .305 .775 L 4.892 -.35 L 5.838 0 L 4.979 -.172 L 3.091 .344 L 2.112 -.214 L 1.328 .085 L 1.018 .594 L 1.188 -.764 L 2.714 -1.046 L 1.866 -.226 L .664 -.028 L .594 -.028 L .777 -.057 L 1.512 .311 L 1.166 -.172 L 3.606 .687 L 3.777 .344 L 1.03 0 L 1.064 .573 L .745 .088 L 2.149 -.088 L 1.271 -.263 L 1.315 -.438 L -.192 -.216 L .28 -.53 L 1.447 -.131 L .921 -.088 L .786 .062 L 2.195 -.501 L 2.097 .501 L .688 .687 L .373 .435 L 1.842 -.131 L .921 -.044 L .985 .255 L 1.889 .688 L 2.919 .515 L 2.919 -.343 L 4.121 -.258 L 2.232 -.344 L 2.404 0 L 3.521 .315 L .702 -.755 L 2.158 -.162 L .863 1.133 L 4.909 .323 L .917 -1.133 L 1.889 -.593 L 5.988 .013 L .756 -.283 L 1.996 .108 L -.432 -1.403 L .054 -.809 L 1.232 -.36 L .872 1.277 L -.647 1.079 L .805 .219 L 2.81 .482 L 5.262 .376 L 5.494 .344 L 2.278 .583 L 1.283 .14 L 1.396 -.167 L 2.204 .446 L 1.961 -.167 L .719 .278 L -.435 .431 L -.151 .351 L .293 .123 L 2.081 .331 L 1.078 .484 L 2.706 -.134 L .377 .595 L 1.038 .227 L 4.808 .515 L -.123 .536 L .567 .236 L 2.695 -.095 L 3.214 .181 L -.329 -.984 L .71 -.095 L .804 .426 L .331 .709 L 1.135 .284 L 2.672 .519 L 2.576 -.343 L 4.017 .999 L 1.626 .495 L 1.672 .871 L 1.626 .023 L .504 .187 L .532 -.021 L .754 -.047 L .777 .047 L .896 .589 L .541 .118 L .542 .07 L .142 -.259 L .471 0 L 1.484 -.048 L 1.416 .237 L 5.951 .535 L .729 .516 L 1.733 .323 L 2.979 .944 L .43 -.335 L .551 .191 L .454 .67 L -.741 .215 L -1.124 .167 L -.216 .359 L .168 .263 L .55 -.048 L -.024 .67 L -.43 -.048 L -.096 .287 L -.312 .071 L -.598 .622 L -.526 .12 L -.55 .287 L -.168 .669 L -1.603 .096 L -1.339 -.239 L -1.794 .359 L -2.153 .425 L -2.629 .764 L 1.271 1.103 L -1.907 .212 L -1.23 -.255 L -.763 .212 L -.043 .637 L -2.374 .169 L .136 .514 L .924 .632 L -.127 .763 L -.382 .085 L -.466 .467 L .551 .466 L .085 .764 L -.764 .424 L .637 .254 L .763 0 L .764 .255 L .339 .509 L .17 .721 L 1.284 -.187 L .836 .907 L 2.035 .297 L .339 .339 L 2.672 .552 L -4.113 0 L -2.799 .138 L -2.332 .541 L -1.823 -.085 L -.806 .212 L -1.611 .339 L -1.326 -.32 L -.546 .426 L 1.116 .529 L -.503 .447 L -.669 .195 L -1.117 .753 L -2.623 .642 L .475 .391 L 2.205 -.111 L .53 0 L .809 .307 L .168 .363 L .499 .18 L .422 .183 L .111 .894 L .209 .502 L 3.195 .279 L 2.874 .948 L 3.662 .801 L 5.151 1.202 L 1.456 .062 L 1.015 .17 L -.146 .234 L -1.67 .264 L -.47 .264 L 1.173 .088 L 2.198 -.293 L 1.988 .166 L + +/target get (out.png) write-to-png pop +pop diff --git a/local/recipes/libs/cairo/source/util/cairo-script/examples/zrusin.cs b/local/recipes/libs/cairo/source/util/cairo-script/examples/zrusin.cs new file mode 100644 index 0000000000..8efc24bbe5 --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-script/examples/zrusin.cs @@ -0,0 +1,1333 @@ +% The data in this file was created by Zack Rusin and downloaded from: +% +% http://ktown.kde.org/~zrusin/examples/cairorender.tar.bz2 +% +% It is included in the cairo performance test suite by his +% permission, (given in email to Carl Worth on 2006-10-23) + +dict + /width 415 set + /height 116 set + surface context + +107.893088734820 103.841923410053 l +106.908713734820 104.920048410053 l +106.605078419636 105.201721390261 l +102.286079757931 107.612435141518 l +95.848592904540 109.855345077872 l +95.820873452616 109.863161445001 l +90.517184462013 111.170008329713 l +87.125000000000 111.625000000000 l +82.393245921775 111.316572641568 l +77.855183975790 110.402282596173 l +73.577390672683 108.898617908665 l +69.626442523093 106.822066623894 l +69.373711344187 106.641023992165 l +57.717461344187 97.141023992165 l +60.861283165549 97.153157587308 l +52.861026127481 102.679312400770 l +43.297199733607 107.707604120505 l +38.061787185467 109.824994465236 l +32.824736230810 111.354170438973 l +27.636335844151 112.281599723349 l +22.546875000000 112.593750000000 l +19.478437557032 111.949288129016 l +16.158848619890 110.212087077375 l +13.224557514711 107.109984243309 l +12.401022392395 105.215121771751 l +12.109375000000 103.234375000000 l +12.857968117079 98.340329228563 l +15.050447208669 93.495802782054 l +18.606861885297 88.792446786896 l +23.447261757492 84.321912369510 l +23.462751811761 84.309735859104 l +29.835792474114 80.170241641945 l +36.826339837257 77.183700966953 l +44.355342734713 75.374150023260 l +52.343750000000 74.765625000000 l +54.172214431835 74.493658379815 l +55.005326273741 73.240819884599 l +54.891695624471 73.637732784350 l +55.835419478567 69.288398667240 l +56.941029555972 65.553969608663 l +57.993585771605 68.524034756036 l +53.681468264740 66.410473849442 l +48.062136369578 64.586219029579 l +42.258612309644 63.317877950046 l +37.437500000000 62.906250000000 l +32.573685233275 63.044800246717 l +26.989159126193 63.632907811096 l +20.752015377001 64.279295952574 l +16.562500000000 64.484375000000 l +16.408072340842 64.479600861137 l +11.611197340842 64.182725861137 l +11.453516511116 64.167941148499 l +6.725716011250 62.845442977500 l +4.607850691978 60.769517471259 l +3.781250000000 57.859375000000 l +4.373461857036 55.042556375256 l +5.951936001924 52.702230099626 l +6.143541831166 52.540844514692 l +9.884650718045 51.301737345381 l +10.233131146503 51.254965794601 l +14.936256146503 50.958090794601 l +15.093750000000 50.953125000000 l +19.896489079886 51.056672881330 l +25.533897731570 51.448761318515 l +25.296875000000 51.437500000000 l +30.909892241200 52.067729129895 l +30.484375000000 52.031250000000 l +39.960841830525 52.410121686268 l +48.752300459876 53.538988916016 l +48.757228534847 53.539874692156 l +54.123571896675 54.731960341587 l +58.970980406852 56.270657465230 l +63.248918806945 58.141504425356 l +66.906851838519 60.330039584234 l +66.896289983187 60.322652661852 l +70.654761046586 63.581911162241 l +73.423041490057 67.400928399521 l +75.133561184297 71.670457102504 l +75.718750000000 76.281250000000 l +74.721151272876 79.892293861068 l +72.068677652167 83.513297493231 l +70.325052633091 85.868624092784 l +69.828125000000 88.250000000000 l +70.186304443223 90.552747673203 l +71.326302526678 92.735137555366 l +73.346308881046 94.894011912335 l +76.344513137007 97.126213009954 l +79.989627194854 99.164217236556 l +83.789048154438 100.596188457783 l +87.811323321056 101.441306202608 l +92.125000000000 101.718750000000 l +97.462586180660 101.070932456387 l +97.557831952069 101.055648080491 l +103.015964519671 99.851433056816 l +103.984375000000 99.656250000000 l +106.046875000000 99.656250000000 l +107.893088734820 103.841923410053 l +106.046875000000 104.656250000000 l +103.984375000000 104.656250000000 l +104.952785480329 104.461066943184 l +98.254668047931 106.006851919509 l +98.349913819340 105.991567543613 l +92.125000000000 106.718750000000 l +87.170121991444 106.371193797392 l +82.386733095562 105.341311542217 l +77.843380617646 103.648282763444 l +73.608611862993 101.311286990046 l +69.914433306454 98.422394337665 l +67.154166223322 95.217987444634 l +65.426000244277 91.794908576797 l +64.828125000000 88.250000000000 l +65.079958470471 86.099459712769 l +65.803853616909 83.955594657216 l +68.478197347833 80.033577506769 l +70.243692477124 77.869424888932 l +70.718750000000 76.281250000000 l +70.335188815703 72.767042897496 l +69.139458509943 69.692821600479 l +67.063988953414 66.949338837759 l +64.041210016813 64.427347338148 l +64.030648161481 64.419960415766 l +57.122769593148 60.885592534770 l +47.867771465153 58.460125307844 l +47.872699540124 58.461011083984 l +39.531345669475 57.386753313732 l +30.484375000000 57.031250000000 l +30.058857758800 56.994770870105 l +25.296875000000 56.437500000000 l +25.059852268430 56.426238681485 l +19.697260920114 56.052702118670 l +15.093750000000 55.953125000000 l +15.251243853497 55.948159205399 l +10.548118853497 56.245034205399 l +10.896599281955 56.198262654619 l +9.168958168834 56.521655485308 l +9.360563998076 56.360269900374 l +8.781250000000 57.859375000000 l +8.758601803360 58.189255218076 l +8.735899308021 58.292982528741 l +8.961783988750 58.373307022500 l +12.077733488884 59.207058851501 l +11.920052659158 59.192274138863 l +16.716927659158 59.489149138863 l +16.562500000000 59.484375000000 l +20.310484622999 59.298829047426 l +26.432715873807 58.663967188904 l +32.129439766725 58.064574753283 l +37.437500000000 57.906250000000 l +42.956231440356 58.377434549954 l +49.359738630422 59.757530970421 l +55.603687985260 61.808276150558 l +60.600164228395 64.257215243964 l +61.652720444028 67.227280391337 l +60.695830521433 70.461601332760 l +59.795804375529 74.612267215650 l +59.682173726259 75.009180115401 l +58.534870256371 76.967235761415 l +56.827785568165 78.467279120185 l +54.713289027441 79.427384197713 l +52.343750000000 79.765625000000 l +45.078251015287 80.284053101740 l +38.408035162743 81.855361533047 l +32.254051275886 84.503586483055 l +26.537248188239 88.252764140896 l +26.552738242508 88.240587630490 l +22.301341239703 92.064975088104 l +19.363615291331 95.777634717946 l +17.659610007921 99.470217646437 l +17.109375000000 103.234375000000 l +17.462942485289 104.745484506691 l +18.934901380110 106.053537922625 l +21.052812442968 107.257743120984 l +22.546875000000 107.593750000000 l +27.127336030849 107.323869026651 l +31.729951269190 106.505204561027 l +36.405009689533 105.124224284764 l +41.202800266393 103.167395879495 l +50.256161372519 98.422250099230 l +57.732466834451 93.253092412692 l +60.876288655813 93.265226007835 l +72.532538655813 102.765226007835 l +72.279807476907 102.584183376106 l +75.647218702317 104.376772716335 l +79.199503524210 105.636779903827 l +83.003238453225 106.380692983432 l +87.125000000000 106.625000000000 l +94.491626547384 105.043088554999 l +94.463907095460 105.050904922128 l +100.135795242069 103.121939858482 l +103.519921580364 101.267028609739 l +103.216286265180 101.548701589947 l +104.200661265180 100.470576589947 l +106.046875000000 104.656250000000 l +107.893088734820 103.841923410053 l +55.872490683787 89.763134548637 l +54.997490683787 85.841259548637 l +55.036476188094 85.993355189713 l +52.343750000000 85.750000000000 l +46.702141892082 86.180801752650 l +41.285068752391 87.490050907175 l +36.021375201732 89.703013308437 l +30.839905860908 92.844954801298 l +30.840393168266 92.844613599752 l +24.841774707763 97.553563991314 l +23.093750000000 100.109375000000 l +23.668337709691 101.518994849695 l +23.371174656526 101.224323797050 l +23.620948599883 101.397798979282 l +24.023420115060 101.552272092059 l +25.484375000000 101.718750000000 l +29.298199671143 101.348354407082 l +33.545396502623 100.218839979757 l +38.283160693967 98.302715245167 l +43.568687444697 95.572488730454 l +43.462444284634 95.635929361188 l +56.978069284634 87.104679361188 l +55.872490683787 89.763134548637 l +107.893088734820 103.841923410053 l +59.646930715366 91.332820638812 l +46.131305715366 99.864070638812 l +46.025062555303 99.927511269546 l +40.294964306033 102.857441004833 l +34.923353497377 104.984285020243 l +29.967425328857 106.280551842918 l +25.484375000000 106.718750000000 l +22.429704884940 106.291477907941 l +20.160075343474 105.056926202950 l +19.862912290309 104.762255150305 l +18.581942192719 102.559691058502 l +18.093750000000 100.109375000000 l +18.781885833597 97.630167914546 l +20.751975292237 94.868311008686 l +27.972106831734 88.749136400248 l +27.972594139092 88.748795198702 l +33.744249798268 85.287221066563 l +39.777431247609 82.783386592825 l +46.000983107918 81.262557622350 l +52.343750000000 80.750000000000 l +54.881053553302 80.995299290410 l +57.121823397686 81.724997675285 l +58.847249996203 82.929795925088 l +59.838523811906 84.600394810287 l +59.877509316213 84.752490451363 l +60.752509316213 88.674365451363 l +59.646930715366 91.332820638812 l +107.893088734820 103.841923410053 l +155.484375000000 101.859375000000 l +154.564834615754 105.515207938449 l +152.115670325806 108.366761454651 l +148.955163295626 109.891294781728 l +145.437500000000 110.437500000000 l +142.960397099416 109.918703000637 l +140.390467597390 108.438024620128 l +137.806753458193 106.109033784838 l +135.288296646094 103.045299421136 l +135.165845369106 102.859481271949 l +127.322095369106 89.718856271949 l +127.315939322101 89.708486304067 l +123.037165252408 83.240466071649 l +119.422893480005 79.457711309224 l +123.333764624626 78.181432151290 l +119.923748586047 88.267600564284 l +116.288451493331 96.371224650234 l +116.310270123205 96.328970526240 l +111.013619195867 105.085481651574 l +104.498474377631 112.833853093888 l +102.718750000000 113.578125000000 l +98.109375000000 113.578125000000 l +95.790533815800 112.012456612681 l +92.715536961613 101.759617602767 l +90.624767168816 88.808240839597 l +90.625938562396 88.818553777181 l +88.018863793847 68.357428789163 l +88.022375537533 68.374401202625 l +86.904794319936 64.234191072834 l +85.466909526601 60.964474099786 l +83.670654326939 58.467433589062 l +81.477961890361 56.645252846242 l +80.463845731714 53.674615230649 l +82.823220731714 47.205865230649 l +82.883587418943 47.055653464335 l +83.966380643129 44.754922491868 l +85.291281927099 42.535861182972 l +88.514402164445 41.595109434025 l +91.785870247761 43.817111177877 l +94.599270325866 47.029404143594 l +96.906293571887 51.130222797294 l +98.658631158949 56.017801605095 l +98.664492355983 56.039251079522 l +100.006630671722 63.228131068770 l +101.762541190731 76.272848032637 l +101.765778670251 76.300425005941 l +103.467098832178 87.353480411923 l +105.697048617918 94.795754781373 l +102.319980907406 93.545204629259 l +104.354680083199 92.248641487426 l +106.296883956259 90.334282557687 l +110.081726403105 84.371439341729 l +110.069085073875 84.396782220394 l +112.413266990492 78.560599894318 l +114.080111889746 71.934817013191 l +115.075734612596 64.464258680566 l +115.406250000000 56.093750000000 l +117.906250000000 53.593750000000 l +122.515625000000 53.593750000000 l +124.596624760838 54.708311442938 l +155.065374760838 100.473936442938 l +155.484375000000 101.859375000000 l +107.893088734820 103.841923410053 l +150.903375239162 103.244813557062 l +120.434625239162 57.479188557062 l +122.515625000000 58.593750000000 l +117.906250000000 58.593750000000 l +120.406250000000 56.093750000000 l +120.037546637404 64.922460069434 l +118.935513110254 72.987057986809 l +117.106264259508 80.232368855682 l +114.555914926125 86.603217779606 l +114.543273596895 86.628560658271 l +112.308927321184 90.508291033149 l +109.859366043741 93.751654942313 l +107.239069916801 96.288467887574 l +104.492519092594 98.048545370741 l +101.115451382082 96.797995218627 l +98.626651167822 88.552769588077 l +96.796721329749 76.855824994059 l +96.799958809269 76.883401967363 l +95.087119328278 64.107806431230 l +93.835507644017 57.335748920478 l +93.841368841051 57.357198394905 l +92.427690803113 53.221339702706 l +90.736667174134 50.033095856406 l +88.719989127239 47.690701322123 l +86.329347835555 46.092390565975 l +89.552468072901 45.151638817028 l +88.346119356871 47.166952508132 l +87.460162581057 49.069346535665 l +87.520529268286 48.919134769351 l +85.161154268286 55.387884769351 l +84.147038109639 52.417247153758 l +87.106689423061 54.909519535937 l +89.579965473399 58.293338400214 l +91.528799430064 62.470887052166 l +92.915124462467 67.344348797375 l +92.918636206153 67.361321210837 l +95.592811437604 88.243946222819 l +95.593982831184 88.254259160403 l +97.565713038387 100.591944897233 l +100.428216184200 110.143793387319 l +98.109375000000 108.578125000000 l +102.718750000000 108.578125000000 l +100.939025622369 109.322396906112 l +106.962943304133 102.180143348427 l +111.845979876795 94.077279473760 l +111.867798506669 94.035025349766 l +115.287188913953 86.412086935716 l +118.541235375374 76.756067848710 l +122.452106519995 75.479788690776 l +126.837834747592 80.025158928351 l +131.621560677899 87.166513695933 l +131.615404630894 87.156143728051 l +139.459154630894 100.296768728051 l +139.336703353906 100.110950578864 l +142.906407402610 104.257287879872 l +145.437500000000 105.437500000000 l +147.478430454374 105.175111468272 l +149.243704674194 104.273863545349 l +150.251571634246 103.277760811551 l +150.484375000000 101.859375000000 l +150.903375239162 103.244813557062 l +107.893088734820 103.841923410053 l +231.343750000000 91.875000000000 l +230.760913847107 95.964970754466 l +229.068047862611 99.735912943733 l +226.348615757792 103.075786207286 l +222.686081243924 105.872550184609 l +222.648873373705 105.894655312846 l +215.093162016193 109.098726800095 l +205.138412990776 111.389009633945 l +205.099511514392 111.395066324151 l +196.531910121565 112.292873746127 l +187.093750000000 112.593750000000 l +180.736641615184 112.156201510495 l +174.578395035074 110.855968371846 l +168.685194057574 108.711669078852 l +163.123222480588 105.741922126310 l +163.102786019362 105.728945017668 l +158.065383006950 101.833715472335 l +154.350564084671 97.489870440862 l +152.052565874896 92.798170193375 l +151.265625000000 87.859375000000 l +151.531470468770 85.013668760581 l +152.287360086651 82.060400295498 l +152.321821893194 81.964698849566 l +155.704155919825 73.828381186220 l +158.270837388345 69.249451319292 l +158.258242073026 69.265568807584 l +162.161895999987 65.281962610977 l +167.278829839386 61.794937132641 l +173.532669176810 58.834467171163 l +180.847039597849 56.430527525129 l +179.144548452656 58.005986305326 l +180.222673452656 54.974736305326 l +180.222279555972 54.975844608663 l +182.650011718926 50.400876966176 l +185.678714551395 49.466466465483 l +192.833058049629 52.996232862321 l +201.831199616962 58.692914409530 l +211.602112156950 65.789874557518 l +220.243790039283 73.085988470431 l +220.250361498213 73.092084369790 l +227.553434625305 81.089470457139 l +229.783449199558 84.667905408782 l +230.987849850362 87.897461316292 l +231.037603485703 88.222391630780 l +231.334478485703 91.659891630780 l +231.343750000000 91.875000000000 l +107.893088734820 103.841923410053 l +226.353021514297 92.090108369220 l +226.056146514297 88.652608369220 l +226.105900149638 88.977538683708 l +225.181394550443 86.544985216218 l +223.368440374695 83.730842042861 l +216.843388501787 76.751665630210 l +216.849959960717 76.757761529569 l +208.538512843050 69.741375442482 l +199.012550383038 62.822710590470 l +190.370066950371 57.347517137679 l +183.790035448605 54.096033534517 l +186.818738281074 53.161623033824 l +184.933970444028 56.649155391337 l +184.933576547344 56.650263694674 l +183.855451547344 59.681513694674 l +182.152960402151 61.256972474871 l +175.418502698190 63.429204703837 l +169.900857660614 65.978500367359 l +165.523650875013 68.934834264023 l +162.210507926974 72.328181192416 l +162.197912611655 72.344298680708 l +160.116156580175 76.155993813780 l +156.990678106806 83.754051150434 l +157.025139913349 83.658349704502 l +156.265625000000 87.859375000000 l +156.814621625104 91.570970431625 l +158.524435915329 95.017942059138 l +161.489304493050 98.301050152665 l +165.803463980638 101.521054982332 l +165.783027519412 101.508077873690 l +170.773790317426 104.198487171148 l +175.945042464926 106.097156628154 l +181.362967759816 107.222704739505 l +187.093750000000 107.593750000000 l +196.179027378435 107.308688753873 l +204.369238485608 106.448683675849 l +204.330337009224 106.454740366055 l +213.484962983807 104.385648199905 l +220.132376626295 101.574094687154 l +220.095168756076 101.596199815391 l +222.954118617208 99.523823167714 l +224.892889637389 97.287524556267 l +225.994945527893 94.775263620534 l +226.343750000000 91.875000000000 l +226.353021514297 92.090108369220 l +107.893088734820 103.841923410053 l +219.781250000000 95.890625000000 l +219.378166433508 93.853798730227 l +218.111752188172 91.489941446073 l +212.645950385807 85.475693519170 l +212.685981945341 85.511936058310 l +206.545320157918 80.643069684901 l +198.180220478697 74.962876659750 l +198.191932106006 74.970352872652 l +191.582535336704 71.037624006410 l +191.504903114611 70.993386859602 l +190.358726480976 70.329891393482 l +194.093750000000 68.156250000000 l +193.486799914207 72.326466575586 l +191.750022838432 75.648693620488 l +191.727672642897 75.674671879974 l +189.796209835616 77.308949639626 l +187.307360975056 78.497446987452 l +184.374093537693 79.223076311545 l +181.109375000000 79.468750000000 l +178.539517280969 79.274893727068 l +176.586499975916 78.676142180991 l +173.086052480141 74.877460550577 l +176.026873378540 75.790765650642 l +173.637934677835 76.966105971818 l +171.454775584042 78.628861257931 l +167.479150931130 83.659399177979 l +167.492959438562 83.636441477986 l +164.707555748674 89.579684053440 l +164.890625000000 88.640625000000 l +165.429801946489 91.718738201013 l +167.140367049889 94.413281660069 l +170.161871706101 96.828214751252 l +174.633867311024 99.067496848641 l +174.595883286589 99.052025896332 l +183.311717611230 101.570655775842 l +188.036065935963 102.270678900324 l +192.781250000000 102.500000000000 l +204.722829878151 102.082467436594 l +212.458857303872 100.833616072622 l +214.905535432122 99.897801735668 l +216.940228691241 98.604487224303 l +220.087216056537 94.692203098109 l +219.781250000000 95.890625000000 l +107.893088734820 103.841923410053 l +224.475283943463 97.089046901891 l +222.495392805158 99.992428606532 l +220.012896308759 102.426762775697 l +217.106183317878 104.328760764332 l +213.853642696128 105.635133927378 l +205.324045121849 107.034720063406 l +192.781250000000 107.500000000000 l +187.549871564037 107.241039849676 l +182.344532388770 106.476219224158 l +172.747866713411 103.697974103668 l +172.709882688976 103.682503151359 l +167.310784543899 100.802644623748 l +163.281507950111 97.266405839931 l +160.761604303511 93.177746173987 l +160.111277146626 90.958745814619 l +159.890625000000 88.640625000000 l +160.073694251326 87.701565946560 l +163.194540561438 81.082308522014 l +163.208349068870 81.059350822021 l +165.573405849355 77.703241627766 l +168.240536915958 74.886763742069 l +171.153080947165 72.670612778182 l +174.254376621460 71.115484349358 l +177.195197519859 72.028789449423 l +178.991625024084 74.292607819009 l +181.109375000000 74.468750000000 l +185.450451524944 73.971303012548 l +187.959827357103 72.387828120026 l +187.937477161568 72.413806379512 l +188.825700085793 70.736033424413 l +189.093750000000 68.156250000000 l +192.828773519024 65.982608606518 l +194.057596885389 66.694113140398 l +193.979964663296 66.649875993590 l +200.870567893994 70.748397127348 l +200.882279521303 70.755873340250 l +209.532804842082 76.638180315099 l +216.001518054659 81.769313941690 l +216.041549614192 81.805556480830 l +219.736550554799 85.597619431325 l +222.481997811828 89.260058553927 l +224.192146066492 92.716513769773 l +224.781250000000 95.890625000000 l +224.475283943463 97.089046901891 l +107.893088734820 103.841923410053 l +274.375000000000 74.921875000000 l +274.375000000000 76.000000000000 l +273.941340954992 77.877573018672 l +272.878932097861 79.515803527315 l +273.201644884750 79.109789854043 l +272.240878131027 80.634530144823 l +272.178064435979 80.731878545843 l +270.366672394243 82.164949472839 l +268.046875000000 82.703125000000 l +266.183148747233 82.484226579792 l +265.676843902484 82.347511014208 l +261.919943241226 81.056638412991 l +261.845529920936 81.035610157726 l +257.771892015055 80.000491652766 l +254.812500000000 79.671875000000 l +253.064641952966 80.017766952966 l +253.029646790629 80.052082662255 l +253.183319188544 79.921363850038 l +253.251518993920 79.984611568497 l +253.185946392942 81.106825858762 l +253.000000000000 86.578125000000 l +253.496255380785 102.128843883245 l +253.498940253820 102.192840332413 l +254.068093288267 110.651263719025 l +251.578125000000 113.375000000000 l +246.875000000000 113.375000000000 l +246.340326851360 113.317155732979 l +244.239667843345 112.409341061474 l +241.449240399376 110.489665586259 l +233.966932708158 103.861287459859 l +233.964253154933 103.858697290509 l +230.739570245917 99.429986748935 l +227.863465886694 92.900734302334 l +227.865566738278 92.906614054351 l +224.904456445713 83.297192679644 l +223.890625000000 76.390625000000 l +224.718172891760 73.652424627265 l +226.991950628026 71.671512863124 l +230.398659300280 70.468125917422 l +234.625000000000 70.062500000000 l +239.436000436064 69.828681464349 l +240.453125000000 69.140625000000 l +239.621272369169 63.470278877568 l +237.983036171748 55.833595299706 l +237.978023315197 55.813489579321 l +235.265625000000 42.968750000000 l +235.414374888933 43.818233911095 l +223.164374888933 9.911983911095 l +223.454623060848 7.647483743269 l +225.610873060848 4.506858743269 l +225.803351703291 4.260965402925 l +227.719534150475 2.932735689909 l +230.078782966130 2.347671229322 l +230.218750000000 2.343750000000 l +231.580832848366 2.789728316683 l +232.871346377781 3.980786060276 l +235.131457239225 7.716876589460 l +240.051188613236 19.745668022304 l +244.970104457946 33.805503176211 l +247.762510801176 44.143184476801 l +247.777764624530 44.225329525617 l +252.184014624530 70.381579525617 l +251.352799675865 68.904817480577 l +254.575226795957 69.673348314939 l +260.406250000000 70.359375000000 l +270.523910039912 70.690857394210 l +273.186407177161 72.174765791999 l +274.049624252688 73.457293811137 l +274.375000000000 74.921875000000 l +107.893088734820 103.841923410053 l +269.375000000000 74.921875000000 l +269.694839960088 75.621642605790 l +260.406250000000 75.359375000000 l +253.596648204043 74.576651685061 l +250.197596782742 73.718304003256 l +248.084700324135 72.688932519423 l +247.253485375470 71.212170474383 l +242.847235375470 45.055920474383 l +242.862489198824 45.138065523199 l +240.182239292054 35.233559323790 l +235.370686386764 21.504331977696 l +230.614636510775 9.861248410540 l +229.674552059719 7.679370189724 l +229.774391761009 7.390935745817 l +230.218750000000 7.343750000000 l +230.358717033870 7.339828770678 l +229.540398296709 7.582784597075 l +229.732876939152 7.336891256731 l +227.576626939152 10.477516256731 l +227.866875111067 8.213016088905 l +240.116875111067 42.119266088905 l +240.265625000000 42.968750000000 l +242.834476684803 54.624010420679 l +242.829463828252 54.603904700294 l +244.534977630831 62.545346122432 l +245.453125000000 69.140625000000 l +244.611402180226 71.735213821357 l +242.306187063936 73.585381035651 l +238.867409665678 74.693638982119 l +234.625000000000 75.062500000000 l +229.906486871974 75.367549636876 l +229.092373983240 75.779215997735 l +228.934535185216 76.058687905577 l +228.890625000000 76.390625000000 l +229.790856054287 82.319994820356 l +232.571933261722 91.218385945649 l +232.574034113306 91.224265697666 l +234.986992254083 96.851263251065 l +237.441996845067 100.266302709491 l +237.439317291842 100.263712540141 l +244.074197100624 106.275959413741 l +247.409673148640 108.432844267021 l +246.875000000000 108.375000000000 l +251.578125000000 108.375000000000 l +249.088156711733 111.098736280975 l +248.501059746180 102.338409667587 l +248.503744619215 102.402406116755 l +248.000000000000 86.578125000000 l +248.204678607058 80.674424141238 l +248.635199756080 78.226325931503 l +249.564103209371 76.447917337745 l +249.529108047034 76.482233047034 l +251.855421271850 75.142541341903 l +254.812500000000 74.671875000000 l +258.571857984945 75.077633347234 l +263.279470079064 76.245639842274 l +263.205056758774 76.224611587009 l +267.479406097516 77.683738985792 l +266.973101252767 77.547023420208 l +268.046875000000 77.703125000000 l +268.247054721136 77.733964370993 l +268.227077605757 77.803800527161 l +268.040685564021 77.924371454157 l +267.977871868973 78.021719855177 l +268.985855115250 76.421460145957 l +269.308567902139 76.015446472685 l +269.418034045008 75.973989481328 l +269.375000000000 76.000000000000 l +269.375000000000 74.921875000000 l +107.893088734820 103.841923410053 l +243.911209450369 105.662056821622 l +240.832004992147 102.845101845416 l +236.815516984936 97.742848726260 l +236.813922800164 97.740633958664 l +232.773597278734 91.287437871638 l +230.710552894044 85.924483215760 l +230.745327869205 86.067653416413 l +229.840275149638 82.415038683708 l +229.855893749637 82.481339062591 l +229.093750000000 78.546875000000 l +229.510257350732 77.264688549054 l +230.557731326090 76.286764971873 l +233.333290689663 75.138571514324 l +238.843750000000 74.468750000000 l +241.980836948934 74.687319511759 l +245.189547085049 75.561169162745 l +247.167986856352 77.549353232692 l +248.217702574415 80.638507879225 l +248.687500000000 88.140625000000 l +248.194671228610 98.736670034806 l +248.200295344311 98.650162873539 l +247.698246960594 103.850772804200 l +243.911209450369 105.662056821622 l +107.893088734820 103.841923410053 l +242.739253039406 103.211727195800 l +243.205954655689 98.412337126461 l +243.211578771390 98.325829965194 l +243.687500000000 88.140625000000 l +243.282297425585 81.439617120775 l +243.185452914951 80.141955837255 l +241.300413051066 79.640805488241 l +238.843750000000 79.468750000000 l +234.557334310337 79.986428485676 l +234.323615830224 80.043375869145 l +234.139295619945 80.082650511165 l +233.899908001681 80.106538837663 l +233.805549923910 79.924172528127 l +234.093750000000 78.546875000000 l +234.706606250363 81.268660937409 l +234.722224850362 81.334961316292 l +235.567172130795 84.744846583587 l +235.601947105956 84.888016784240 l +237.273277721266 89.165687128362 l +240.873577199836 94.821866041336 l +240.871983015064 94.819651273740 l +244.355495007853 99.326773154584 l +246.526290549631 101.400443178378 l +242.739253039406 103.211727195800 l +107.893088734820 103.841923410053 l +304.579027849556 115.887559254375 l +299.647333003501 118.498603127587 l +299.601234810263 118.526555579345 l +296.960609810263 120.089055579345 l +295.687500000000 120.437500000000 l +292.434178516679 119.763451801101 l +289.591538470777 117.850158805700 l +287.263626957927 114.860898415742 l +285.554491073762 110.958948033170 l +285.546168760441 110.932189402305 l +283.409425227272 100.413450166388 l +283.408069329655 100.405281467271 l +280.968147929764 87.644193704042 l +284.218299056292 87.914012723915 l +279.519746335556 93.766171451312 l +279.798545332977 93.224824860858 l +274.937093489612 105.343910553875 l +272.454127837569 109.762553039486 l +269.772550129691 112.314814767144 l +266.294988321147 110.999865652887 l +264.699764075525 105.167535274279 l +264.676753039406 105.022647804200 l +264.221109604112 100.702343060691 l +264.171875000000 98.828125000000 l +263.607902205199 91.869081828698 l +263.613915250645 91.062865437610 l +263.781250000000 89.718750000000 l +263.644962649638 88.985351183708 l +262.873500431741 86.703985451358 l +262.739182179139 86.219942105230 l +260.786057179139 74.844942105230 l +260.786249814804 74.846062487964 l +256.958124814804 52.611687487964 l +256.955473276820 52.595988114755 l +254.892973276820 40.142863114755 l +254.909488793847 40.232428789163 l +254.331363793847 37.388678789163 l +254.339079247810 37.425229542768 l +253.651579247810 34.284604542768 l +253.593750000000 33.750000000000 l +254.239654341050 30.319069019177 l +254.154681406546 30.589185956325 l +256.319133024351 26.771372253672 l +258.818704827809 25.924919245868 l +261.217531024880 26.988383072536 l +263.253153025566 28.888095452080 l +264.856582863559 31.480336604342 l +265.958832572550 34.621386749163 l +266.013105788729 34.918097636045 l +267.200714432551 44.731495841479 l +267.198350954149 44.712535224402 l +269.443623734153 61.037071609407 l +269.421396014347 60.906344576785 l +270.652021489737 67.736566992690 l +271.992261513603 76.440263813345 l +271.992747064473 76.443809223415 l +273.038636247453 85.686082548185 l +273.390625000000 92.953125000000 l +273.238407027301 96.898129287691 l +272.771685367998 99.590064317759 l +267.989237947004 98.132898258783 l +271.223612947004 86.961023258783 l +271.391159168632 86.533772766328 l +274.526090303798 81.379570646076 l +274.584318175231 81.310286998919 l +276.982682022500 78.600716011250 l +277.142029400154 78.326905342657 l +279.265919333198 75.301911531816 l +279.298622345235 75.258362091268 l +281.876153531632 73.009942282517 l +284.906250000000 72.125000000000 l +287.318073492888 72.767987310135 l +289.339116026344 74.544184270464 l +290.903803647217 77.224443425871 l +291.946562402359 80.579617321243 l +291.963278527291 80.666832095730 l +293.477578855570 88.491377103079 l +294.532438780850 92.026218792971 l +294.690170210143 92.371639700252 l +298.832669585147 102.687317191341 l +298.821447919079 102.663322107333 l +301.483679194839 107.248880594573 l +302.541048238599 108.202972500861 l +303.515625000000 108.484375000000 l +306.015625000000 110.984375000000 l +306.015625000000 113.625000000000 l +304.579027849556 115.887559254375 l +107.893088734820 103.841923410053 l +301.015625000000 113.625000000000 l +301.015625000000 110.984375000000 l +303.515625000000 113.484375000000 l +300.984342386401 112.859527499139 l +298.555383305161 111.094869405427 l +296.303526841571 108.355227332168 l +294.303552080921 104.805427892667 l +294.292330414853 104.781432808659 l +289.997329789857 94.097110299748 l +290.155061219150 94.442531207029 l +288.709921144430 89.953935396921 l +287.036721472709 81.520667904270 l +287.053437597641 81.607882678757 l +286.004633973656 77.940190729536 l +284.906250000000 77.125000000000 l +284.500063101353 77.160595459408 l +284.155096468369 77.318182717483 l +283.263877654765 78.304137908732 l +283.296580666802 78.260588468184 l +281.295470599846 81.110594657343 l +281.454817977500 80.836783988750 l +278.353181824769 84.595963001081 l +278.411409696202 84.526679353924 l +275.858840831368 88.778727233672 l +276.026387052996 88.351476741217 l +272.792012052996 99.523351741217 l +268.009564632002 98.066185682241 l +268.390625000000 92.953125000000 l +268.055113752547 86.056104951815 l +267.038502935527 77.118690776585 l +267.038988486397 77.122236186655 l +265.722978510263 68.575933007310 l +264.516103985653 61.874905423215 l +264.493876265847 61.744178390593 l +262.239149045851 45.349964775598 l +262.236785567449 45.331004158521 l +261.049394211271 35.519402363955 l +261.103667427450 35.816113250837 l +259.699971974434 32.150967047920 l +257.681295172191 30.793830754132 l +260.180866975649 29.947377746328 l +259.001568593454 31.817064043675 l +258.916595658950 32.087180980823 l +258.593750000000 33.750000000000 l +258.535920752190 33.215395457232 l +259.223420752190 36.356020457232 l +259.231136206153 36.392571210837 l +259.809261206153 39.236321210837 l +259.825776723180 39.325886885245 l +261.888276723180 51.779011885245 l +261.885625185196 51.763312512036 l +265.713750185196 73.997687512036 l +265.713942820861 73.998807894770 l +267.667067820861 85.373807894770 l +267.532749568259 84.889764548642 l +268.526912350362 87.905273816292 l +268.781250000000 89.718750000000 l +268.542334749355 91.905884562390 l +268.548347794801 91.099668171302 l +269.171875000000 98.828125000000 l +269.216390395888 100.485156939309 l +269.635746960594 104.383602195800 l +269.612735924475 104.238714725721 l +270.955011678853 109.187634347113 l +267.477449870309 107.872685232856 l +268.686497162431 106.569478210514 l +270.375406510388 103.296714446125 l +275.107704667023 91.493925139142 l +275.386503664444 90.952578548688 l +278.700840527029 86.470174071108 l +281.281700943708 83.867237276085 l +284.531852070236 84.137056295958 l +285.408419686884 85.805066273498 l +286.324716189650 88.997159604327 l +288.341930670345 99.594718532729 l +288.340574772728 99.586549833612 l +290.328831239559 109.474060597695 l +290.320508926238 109.447301966830 l +291.419966792073 112.312929709258 l +292.611586529223 114.157653694300 l +293.999415233321 115.144751323899 l +295.687500000000 115.437500000000 l +294.414390189737 115.785944420655 l +297.055015189737 114.223444420655 l +297.008916996499 114.251396872413 l +302.452222150444 111.362440745625 l +301.015625000000 113.625000000000 l +107.893088734820 103.841923410053 l +374.437500000000 106.765625000000 l +373.775309600600 109.463093710969 l +372.064906958700 112.117295697199 l +372.041004786215 112.144602045402 l +368.522704503395 114.706400007155 l +366.442611342446 115.399541345014 l +364.281250000000 115.640625000000 l +355.911205219123 114.726652651698 l +341.052591424867 111.966274658224 l +341.038040421249 111.963294783992 l +326.905309277070 108.757693347762 l +319.727026481732 106.439595965247 l +319.807037817648 106.479160754059 l +310.484453831953 101.696158824691 l +304.482826587959 97.721718623918 l +304.310358047034 97.564641952966 l +302.095819571999 95.254869206705 l +298.220153609739 90.667578419636 l +300.367638895226 91.618501549714 l +296.258263895226 91.915376549714 l +296.078125000000 91.921875000000 l +293.025957236218 91.709450913344 l +290.151865257421 91.083888117023 l +285.254658796565 88.663603177256 l +285.219422230119 88.636374171395 l +281.529900243089 84.536170132203 l +280.513144708967 82.282593311151 l +280.156250000000 80.015625000000 l +280.896516775664 77.119922391977 l +282.806537684315 74.726645730656 l +285.448073147177 73.263018105533 l +288.686079158715 72.443690273534 l +290.750793112766 73.122099563886 l +293.797668112766 76.059599563886 l +293.736465601749 76.002539206463 l +295.798965601749 77.861914206463 l +294.222063773555 77.220634985862 l +301.862688773555 77.517509985862 l +299.265625000000 80.015625000000 l +299.934685624955 74.754308742711 l +301.898213943218 69.792099871114 l +305.090729619888 65.230982029954 l +309.446752320064 61.172938863978 l +309.482902906976 61.145713152252 l +318.065904047846 56.213131631660 l +329.455658353400 51.953267244508 l +329.496351456999 51.941186017188 l +336.615241964605 50.572965088062 l +336.666137267666 50.568817238037 l +342.150512267666 50.178192238037 l +342.328125000000 50.171875000000 l +347.088673798588 50.461178987176 l +351.635436696472 51.319590054257 l +355.904450990616 52.732856859568 l +359.831753977986 54.686728061438 l +363.292951645549 57.250115143707 l +365.880587968213 60.272932122861 l +367.501493801268 63.647371305944 l +368.062500000000 67.265625000000 l +367.659428864193 69.524372763002 l +366.507997055207 71.901249483478 l +362.306741008310 76.690232523947 l +362.309449580203 76.687848273793 l +355.067416613929 81.592460070084 l +345.579434368324 85.619156329617 l +345.543296906352 85.631025936969 l +338.856518222681 87.434049611292 l +331.674077585810 88.726763309129 l +324.032609882622 89.505258086643 l +315.968750000000 89.765625000000 l +315.697255981477 89.750839477245 l +313.837880981477 89.547714477245 l +314.109375000000 89.562500000000 l +315.203325765838 88.142787621838 l +315.234375000000 87.750000000000 l +315.261368553241 87.459370280378 l +315.416652198286 87.453346686481 l +316.557907675735 88.522399326740 l +316.429841220906 88.403882310796 l +319.273591220906 90.857007310796 l +318.935343465338 90.611377991437 l +331.091593465338 97.970752991437 l +330.612118984109 97.746034726917 l +334.956642245028 98.975789357391 l +339.851927078584 99.850564497063 l +351.453125000000 100.546875000000 l +354.203872313810 100.381670729150 l +355.159915151904 99.886038066767 l +355.055436157189 100.055596900919 l +357.900435727416 97.290434866877 l +362.379803562479 95.425955323112 l +363.015625000000 95.343750000000 l +366.828125000000 95.343750000000 l +368.997562855593 96.601357392681 l +374.106937855593 105.523232392681 l +374.437500000000 106.765625000000 l +107.893088734820 103.841923410053 l +369.768062144407 108.008017607319 l +364.658687144407 99.086142607319 l +366.828125000000 100.343750000000 l +363.015625000000 100.343750000000 l +363.651446437521 100.261544676888 l +360.724564272584 101.303315133123 l +359.413313842811 102.506903099081 l +359.308834848096 102.676461933233 l +358.021570604282 103.932262067178 l +356.186752686190 104.829266770850 l +351.453125000000 105.546875000000 l +345.006190631125 105.353277680068 l +339.085572921416 104.774435502937 l +333.730857754972 103.813273142609 l +328.981631015891 102.472715273083 l +328.502156534662 102.247997008563 l +316.345906534662 94.888622008563 l +316.007658779094 94.642992689204 l +313.163908779094 92.189867689204 l +313.035842324265 92.071350673260 l +311.083347801714 89.820090813519 l +310.234375000000 87.750000000000 l +310.265424234162 87.357212378162 l +310.780311953087 86.191927459145 l +311.752715552710 85.312201869144 l +314.109375000000 84.562500000000 l +314.380869018523 84.577285522755 l +316.240244018523 84.780410522755 l +315.968750000000 84.765625000000 l +323.705671367377 84.524038788357 l +330.935297414190 83.796674190871 l +337.694263027319 82.579622263708 l +344.019203093648 80.868974063031 l +343.983065631676 80.880843670383 l +352.635708386071 77.251289929916 l +359.003050419797 72.937151726207 l +359.005758991690 72.934767476053 l +362.163877944793 69.637813016522 l +363.062500000000 67.265625000000 l +362.747529636232 64.880949006556 l +361.740505781787 62.777849127139 l +359.948259291951 60.848517668793 l +357.277621022014 58.985146938562 l +353.920744321884 57.295463452932 l +350.352844553528 56.106191195743 l +346.509959013911 55.403078825324 l +342.328125000000 55.171875000000 l +342.505737732334 55.165557761963 l +337.021362732334 55.556182761963 l +337.072258035395 55.552034911938 l +330.878648543001 56.746313982812 l +330.919341646600 56.734232755492 l +320.246595952154 60.693118368340 l +312.454597093024 65.166786847748 l +312.490747679936 65.139561136022 l +308.794036005112 68.485814845046 l +306.234598556782 72.012587628886 l +304.746955000045 75.821863132289 l +304.265625000000 80.015625000000 l +301.668561226445 82.513740014138 l +294.027936226445 82.216865014138 l +292.451034398251 81.575585793537 l +290.388534398251 79.716210793537 l +290.327331887234 79.659150436114 l +287.280456887234 76.721650436114 l +289.345170841285 77.400059726466 l +287.321458102823 77.850263144467 l +285.927837315685 78.632729269344 l +285.271451974336 79.274608858023 l +285.175338636761 79.581613557521 l +285.156250000000 80.015625000000 l +285.837287256911 82.245079867797 l +288.311827769881 84.707375828605 l +288.276591203435 84.680146822744 l +291.660634742579 86.384861882977 l +296.078125000000 86.921875000000 l +295.897986104774 86.928373450286 l +300.007361104774 86.631498450286 l +302.154846390261 87.582421580364 l +305.732305428001 91.823255793295 l +307.845891952966 94.029108047034 l +307.673423412041 93.872031376082 l +313.085858668047 97.436653675309 l +321.942962182352 101.958339245941 l +322.022973518268 101.997904034753 l +328.415003222930 104.000119152238 l +342.055709578751 107.067955216008 l +342.041158575133 107.064975341776 l +356.698169780877 109.788972348302 l +364.281250000000 110.640625000000 l +366.516357996605 110.246724992845 l +368.302745213785 108.824147954598 l +368.278843041300 108.851454302801 l +369.437500000000 106.765625000000 l +369.768062144407 108.008017607319 l +107.893088734820 103.841923410053 l +359.034454681034 69.861443602839 l +357.173548986071 72.638610976591 l +353.435826646756 75.215386191513 l +347.992418306797 77.582163291606 l +341.014454609897 79.729336320871 l +326.426284670840 82.761098429090 l +319.640717587115 83.525315463381 l +313.234375000000 83.781250000000 l +312.706760041223 83.724940335389 l +311.331760041223 83.428065335389 l +311.389194323030 83.439762979730 l +309.920444323030 83.158512979730 l +310.390625000000 83.203125000000 l +309.032298883605 83.610801187634 l +305.860259182280 80.222501196670 l +308.487654632717 75.272571710106 l +311.451975717975 70.927537861140 l +314.718319876723 67.239682598354 l +318.251784547635 64.261288870324 l +318.235984828743 64.272646821685 l +322.460311501394 61.735717754517 l +327.134482463160 59.899177687483 l +332.183220900533 58.782772982128 l +337.531250000000 58.406250000000 l +345.475041381297 58.786142249068 l +351.020038715603 59.929523334009 l +351.130689531816 59.972424607386 l +353.699762084814 61.379594420291 l +355.915109055748 63.288105475323 l +357.703808635445 65.619192847673 l +358.992939014732 68.294091612533 l +359.034454681034 69.861443602839 l +107.893088734820 103.841923410053 l +354.288310985268 69.987158387467 l +352.366140944252 66.657207024677 l +349.213060468184 64.590075392614 l +349.323711284397 64.632976665991 l +344.735896118703 63.713857750932 l +337.531250000000 63.406250000000 l +332.857794724467 63.703555142872 l +328.623330036840 64.608634812517 l +324.752579123606 66.141235370483 l +321.170265171257 68.321103178315 l +321.154465452365 68.332461129676 l +318.096133248277 70.895083026646 l +315.305836782025 74.049024638860 l +312.748673492282 77.846568914895 l +310.389740817720 82.339998803330 l +307.217701116395 78.951698812366 l +310.390625000000 78.203125000000 l +310.860805676970 78.247737020270 l +312.329555676970 78.528987020270 l +312.386989958777 78.540684664611 l +313.761989958777 78.837559664611 l +313.234375000000 78.781250000000 l +319.326079287885 78.541090786619 l +325.753402829160 77.817026570910 l +339.735545390103 74.895663679129 l +350.446985853244 71.354926308487 l +353.125279138929 69.816467148409 l +354.246795318966 68.419806397161 l +354.288310985268 69.987158387467 l +107.893088734820 103.841923410053 l +412.906150029990 61.293260146951 l +409.761470127352 62.134684085464 l +407.280172710472 63.259435125605 l +407.285792255081 63.256184676520 l +404.793374271599 64.364965077547 l +402.406250000000 64.781250000000 l +400.799037804796 64.455489160260 l +399.281565012266 63.565560595750 l +396.896451926356 60.617324020679 l +395.843750000000 59.187500000000 l +394.132759007664 59.586356110398 l +392.227223295325 60.862510968959 l +387.514233459670 66.524236094764 l +387.523930329881 66.510005317299 l +384.972470502350 70.813073903396 l +383.182220364063 75.072391356081 l +382.127155126215 79.356608210051 l +381.781250000000 83.734375000000 l +382.036891605602 86.926476407739 l +382.837535469594 90.232985146136 l +382.953125000000 90.984375000000 l +382.953125000000 110.781250000000 l +380.453125000000 113.281250000000 l +374.875000000000 113.281250000000 l +372.797350977108 112.469290573921 l +370.771127450416 110.197059087430 l +366.940746762890 102.253660683699 l +366.931766441279 102.229357657717 l +364.988344509233 95.969248633492 l +363.592635453443 89.400212341223 l +362.750737781251 82.563409292771 l +362.468750000000 75.500000000000 l +362.469585639102 75.564633561058 l +362.375835639102 71.939633561058 l +362.376194806642 71.952282634846 l +362.282444806642 68.921032634846 l +362.281250000000 68.843750000000 l +362.557974048920 65.558176179264 l +363.371209408870 62.925233614273 l +365.078767647837 60.585701488502 l +367.830147985199 58.062445160283 l +369.390625000000 57.515625000000 l +372.609375000000 57.515625000000 l +375.044088155839 59.448023159988 l +375.637838155839 61.994898159988 l +375.701153736333 62.463240580013 l +375.794903736333 64.822615580013 l +375.796875000000 64.921875000000 l +375.796875000000 66.390625000000 l +375.727843254951 66.974057381188 l +375.364882971473 68.609156073692 l +375.377354243352 68.535253718305 l +374.986729243352 71.082128718305 l +375.015625000000 70.703125000000 l +375.946084438562 73.051058522014 l +371.472688855144 73.407169646001 l +374.338903268299 66.961197216653 l +377.510670879106 61.308691210684 l +380.962283852915 56.499192859154 l +384.668034355078 52.582243393122 l +384.668120639869 52.582165462116 l +388.032154904598 50.002880989291 l +391.626628158728 48.110057708285 l +395.367786243461 46.944465688666 l +399.171875000000 46.546875000000 l +400.072873198005 46.714879663986 l +404.885373198005 48.574254663986 l +404.871260445955 48.568850974212 l +412.883679720929 50.905386234424 l +414.906250000000 53.359375000000 l +414.906250000000 58.843750000000 l +412.906150029990 61.293260146951 l +107.893088734820 103.841923410053 l +409.906250000000 58.843750000000 l +409.906250000000 53.359375000000 l +411.928820279071 55.813363765576 l +403.097489554045 53.243649025788 l +403.083376801995 53.238245336014 l +398.270876801995 51.378870336014 l +399.171875000000 51.546875000000 l +396.227916881538 51.823112436334 l +393.443684341272 52.679004791715 l +390.735423220402 54.155322135709 l +388.019379360131 56.292834537884 l +388.019465644922 56.292756606878 l +384.707638022085 59.784010265846 l +381.637766620894 64.074121289316 l +378.784143606701 69.212630908347 l +376.121061144856 75.249080353999 l +371.647665561438 75.605191477986 l +370.464152438185 73.063686657060 l +370.015625000000 70.703125000000 l +370.044520756648 70.324121281695 l +370.435145756648 67.777246281695 l +370.447617028527 67.703343926308 l +370.865906745049 65.807192618812 l +370.796875000000 66.390625000000 l +370.796875000000 64.921875000000 l +370.798846263667 65.021134419987 l +370.705096263667 62.661759419987 l +370.768411844161 63.130101840012 l +370.174661844161 60.583226840012 l +372.609375000000 62.515625000000 l +369.390625000000 62.515625000000 l +370.951102014801 61.968804839717 l +367.847540591130 65.152891385727 l +367.281250000000 68.843750000000 l +367.280055193358 68.766467365154 l +367.373805193358 71.797717365154 l +367.374164360898 71.810366438942 l +367.467914360898 75.435366438942 l +367.468750000000 75.500000000000 l +367.725824718749 82.182684457229 l +368.501114546557 88.552912658777 l +369.800717990767 94.651845116508 l +371.630733558721 100.520642342283 l +371.621753237110 100.496339316301 l +374.875000000000 108.281250000000 l +380.453125000000 108.281250000000 l +377.953125000000 110.781250000000 l +377.953125000000 90.984375000000 l +378.068714530406 91.735764853864 l +377.111545894398 87.698523592261 l +376.781250000000 83.734375000000 l +377.206829248785 78.659016789949 l +378.466217135937 73.583858643919 l +380.533388872650 68.577551096604 l +383.382319670119 63.708744682701 l +383.392016540330 63.694513905236 l +386.493443824758 59.714265008269 l +389.655589204675 56.723426531041 l +392.798881617336 54.841378264602 l +395.843750000000 54.187500000000 l +397.450962195204 54.513260839740 l +398.968434987734 55.403189404250 l +401.353548073644 58.351425979321 l +402.406250000000 59.781250000000 l +404.776707744919 58.931315323480 l +404.782327289528 58.928064874395 l +408.035404872648 57.459065914536 l +411.906349970010 56.394239853049 l +409.906250000000 58.843750000000 l +107.893088734820 103.841923410053 l +.0 .0 .8 set-source-rgb fill + +/target get (out.png) write-to-png pop +pop diff --git a/local/recipes/libs/cairo/source/util/cairo-script/meson.build b/local/recipes/libs/cairo/source/util/cairo-script/meson.build new file mode 100644 index 0000000000..60cec2b6e0 --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-script/meson.build @@ -0,0 +1,67 @@ +cairoscript_interpreter_sources = [ + 'cairo-script-file.c', + 'cairo-script-hash.c', + 'cairo-script-interpreter.c', + 'cairo-script-objects.c', + 'cairo-script-operators.c', + 'cairo-script-scanner.c', + 'cairo-script-stack.c', +] + +cairoscript_interpreter_headers = [ + 'cairo-script-interpreter.h', +] + +csi_replay_sources = [ + 'csi-replay.c', +] + +csi_exec_sources = [ + 'csi-exec.c', +] + +csi_trace_sources = [ + 'csi-trace.c', +] + +libcairoscript = library('cairo-script-interpreter', + cairoscript_interpreter_sources, + include_directories: [incbase], + dependencies: deps + [libcairo_dep, lzo_dep], + soversion: cairo_version_sonum, + version: cairo_libversion, + c_args: ['-DCAIRO_COMPILATION'], + link_args: extra_link_args, + install: true, +) + +libcairoscript_dep = declare_dependency(link_with: libcairoscript, + include_directories: include_directories('.'), + dependencies: libcairo_dep) + +pkgmod.generate(libcairoscript, + libraries: [libcairo], + description: 'script surface backend for cairo graphics library', + subdirs: [meson.project_name()], +) + +meson.override_dependency('cairo-script-interpreter', libcairoscript_dep) + +csi_replay_exe = executable('csi-replay', csi_replay_sources, + include_directories: [incbase], + dependencies: deps + [libcairo_dep, libcairoscript_dep], +) + +csi_exec_exe = executable('csi-exec', csi_exec_sources, + include_directories: [incbase], + dependencies: deps + [libcairo_dep, libcairoscript_dep], +) + +if feature_conf.get('CAIRO_HAS_SCRIPT_SURFACE', 0) == 1 and conf.get('HAVE_LIBGEN_H', 0) == 1 + csi_trace_exe = executable('csi-trace', csi_trace_sources, + include_directories: [incbase], + dependencies: deps + [libcairo_dep, libcairoscript_dep], + ) +endif + +install_headers(cairoscript_interpreter_headers, subdir: 'cairo') diff --git a/local/recipes/libs/cairo/source/util/cairo-trace/.gitignore b/local/recipes/libs/cairo/source/util/cairo-trace/.gitignore new file mode 100644 index 0000000000..b5f866669d --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-trace/.gitignore @@ -0,0 +1 @@ +cairo-trace diff --git a/local/recipes/libs/cairo/source/util/cairo-trace/COPYING b/local/recipes/libs/cairo/source/util/cairo-trace/COPYING new file mode 100644 index 0000000000..37aeee076f --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-trace/COPYING @@ -0,0 +1,5 @@ +Cairo is free software. + +cairo-trace is released under the terms of the GNU General Public License +(GPL) version 3. Please see COPYING-GPL-3 for the precise terms and +conditions. diff --git a/local/recipes/libs/cairo/source/util/cairo-trace/COPYING-GPL-3 b/local/recipes/libs/cairo/source/util/cairo-trace/COPYING-GPL-3 new file mode 100644 index 0000000000..94a9ed024d --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-trace/COPYING-GPL-3 @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/local/recipes/libs/cairo/source/util/cairo-trace/cairo-trace.in b/local/recipes/libs/cairo/source/util/cairo-trace/cairo-trace.in new file mode 100755 index 0000000000..ece90d3ebb --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-trace/cairo-trace.in @@ -0,0 +1,136 @@ +#!/bin/sh + +prefix=@prefix@ +exec_prefix=@exec_prefix@ + +nofile= +flush= +nocallers= +nomarkdirty= +compress= + +usage() { +cat << EOF +usage: cairo-trace [--no-file] command +cairo-trace will generate a log of all calls made by command to +cairo. This log will be stored in a file in the local directory +called command.pid.trace. +Whatever else happens is driven by its argument: + --flush - Flush the output trace after every call. + --no-file - Disable the creation of an output file. Outputs to the + terminal instead. + --no-callers - Do not lookup the caller address/symbol/line whilst tracing. + --mark-dirty - Record image data for cairo_mark_dirty() [default] + --no-mark-dirty - Do not record image data for cairo_mark_dirty() + --compress - Compress the output with LZMA + --profile - Combine --no-callers and --no-mark-dirty and --compress + +Environment variables understood by cairo-trace: + CAIRO_TRACE_FLUSH - flush the output after every function call. + CAIRO_TRACE_LINE_INFO - emit line information for most function calls. +EOF +exit +} + +skip=1 +while test $skip -eq 1; do + skip=0 + case $1 in + --flush) + skip=1 + flush=1 + ;; + --no-file) + skip=1 + nofile=1 + ;; + --no-callers) + skip=1 + nocallers=1 + ;; + --mark-dirty) + skip=1 + nomarkdirty= + ;; + --no-mark-dirty) + skip=1 + nomarkdirty=1 + ;; + --compress) + skip=1 + compress=1 + nofile=1 + ;; + --profile) + skip=1 + compress=1 + nomarkdirty=1 + nocallers=1 + nofile=1 + ;; + --version) + echo "cairo-trace, version @CAIRO_VERSION_MAJOR@.@CAIRO_VERSION_MINOR@.@CAIRO_VERSION_MICRO@." + exit + ;; + --help) + usage + ;; + esac + if test $skip -eq 1; then + shift + fi +done + +if test $# -eq 0; then + usage +fi + +CAIRO_TRACE_PROG_NAME="$1" +export CAIRO_TRACE_PROG_NAME + +if test "x$CAIRO_TRACE_SO" = "x"; then + CAIRO_TRACE_SO="" + for lib in @libdir@/cairo/libcairo-trace.@SHLIB_EXT@ @libdir@/cairo/libcairo-trace.@SHLIB_EXT@* @libdir@/cairo/libcairo-trace.*.@SHLIB_EXT@ ; do + if test -h "$lib" -o -f "$lib"; then + CAIRO_TRACE_SO="$lib" + break + fi + done +fi +if test "x$CAIRO_TRACE_SO" = "x"; then + echo "Could not find the cairo-trace shared library in @libdir@/cairo/." >&2 + echo "Set the CAIRO_TRACE_SO environment variable to the full path of the library." >&2 + exit 15 +fi + +LD_PRELOAD="$CAIRO_TRACE_SO" +DYLD_INSERT_LIBRARIES="$CAIRO_TRACE_SO" +DYLD_FORCE_FLAT_NAMESPACE=1 +export LD_PRELOAD +export DYLD_INSERT_LIBRARIES +export DYLD_FORCE_FLAT_NAMESPACE + +if test -n "$nocallers"; then + CAIRO_TRACE_LINE_INFO=0 + export CAIRO_TRACE_LINE_INFO +fi + +if test -n "$nomarkdirty"; then + CAIRO_TRACE_MARK_DIRTY=0 + export CAIRO_TRACE_MARK_DIRTY +fi + +if test -n "$flush"; then + CAIRO_TRACE_FLUSH=1 + export CAIRO_TRACE_FLUSH +fi + +if test -z "$nofile"; then + CAIRO_TRACE_OUTDIR=`pwd` "$@" +elif test -n "$compress"; then + name=`basename $1` + echo Generating compressed trace file $name.$$.lzma + CAIRO_TRACE_FD=3 "$@" 3>&1 >/dev/null | lzma -cz9 > $name.$$.lzma +else + CAIRO_TRACE_FD=3 "$@" 3>&1 >/dev/null +fi diff --git a/local/recipes/libs/cairo/source/util/cairo-trace/lookup-symbol.c b/local/recipes/libs/cairo/source/util/cairo-trace/lookup-symbol.c new file mode 100644 index 0000000000..ca15688c43 --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-trace/lookup-symbol.c @@ -0,0 +1,326 @@ +/* cairo-trace - a utility to record and replay calls to the Cairo library. + * + * Copyright © 2008 Chris Wilson + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * A less hacky utility to lookup the debug strings for a particular + * .text address. + * Derived from backtrace-symbols.c in cairo by Chris Wilson. + */ + +/* + A hacky replacement for backtrace_symbols in glibc + + backtrace_symbols in glibc looks up symbols using dladdr which is limited + in the symbols that it sees. libbacktracesymbols opens the executable and + shared libraries using libbfd and will look up backtrace information using + the symbol table and the dwarf line information. + + It may make more sense for this program to use libelf instead of libbfd. + However, I have not investigated that yet. + + Derived from addr2line.c from GNU Binutils by Jeff Muizelaar + + Copyright 2007 Jeff Muizelaar + */ + +/* addr2line.c -- convert addresses to line number and function name + Copyright 1997, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + Contributed by Ulrich Lauther + + This file was part of GNU Binutils. + */ + +#include "config.h" + +#define true 1 +#define false 0 + +#include "lookup-symbol.h" + +#include +#include +#include +#include +#include +#include + +#if HAVE_BFD +#include + +struct symtab { + bfd *bfd; + asymbol **syms; +}; + +struct symbol { + int found; + bfd_vma pc; + struct symtab *symtab; + const char *filename; + const char *functionname; + unsigned int line; +}; + + +static void +_symtab_fini (struct symtab *symtab) +{ + free (symtab->syms); + if (symtab->bfd != NULL) + bfd_close (symtab->bfd); +} + +/* Read in the symbol table. */ +static int +_symtab_init (struct symtab *symtab, const char *filename) +{ + char **matching; + long symcount; + unsigned int size; + + symtab->bfd = NULL; + symtab->syms = NULL; + + symtab->bfd = bfd_openr (filename, NULL); + if (symtab->bfd == NULL) + goto BAIL; + + if (bfd_check_format (symtab->bfd, bfd_archive)) + goto BAIL; + + if (! bfd_check_format_matches (symtab->bfd, bfd_object, &matching)) + goto BAIL; + + symcount = bfd_read_minisymbols (symtab->bfd, false, (void **) &symtab->syms, &size); + if (symcount == 0) { + symcount = bfd_read_minisymbols (symtab->bfd, true /* dynamic */ , + (void **) &symtab->syms, &size); + } + if (symcount < 0) + goto BAIL; + + if ((bfd_get_file_flags (symtab->bfd) & HAS_SYMS) == 0) + goto BAIL; + + return 1; + +BAIL: + _symtab_fini (symtab); + return 0; +} + +/* Look for an address in a section. + * This is called via bfd_map_over_sections. + */ +static void +find_address_in_section (bfd *abfd, + asection *section, + void *data) +{ + bfd_vma vma; + bfd_size_type size; + struct symbol *symbol = data; + struct symtab *symtab = symbol->symtab; + + if (symbol->found) + return; + + if ((bfd_section_flags (section) & SEC_ALLOC) == 0) + return; + + vma = bfd_section_vma (section); + if (symbol->pc < vma) + return; + + size = bfd_section_size (section); + if (symbol->pc >= vma + size) + return; + + symbol->found = bfd_find_nearest_line (symtab->bfd, section, + symtab->syms, + symbol->pc - vma, + &symbol->filename, + &symbol->functionname, + &symbol->line); +} + +static void +_symbol_fini (struct symbol *symbol) +{ +} + +static void +_symbol_init (struct symbol *symbol, struct symtab *symtab, bfd_vma addr) +{ + symbol->found = false; + symbol->symtab = symtab; + symbol->pc = addr; +} + +static void +_symbol_print (struct symbol *symbol, char *buf, int buflen, const char *filename) +{ + const char *name, *h; + char path[1024]; + + if (! symbol->found) + return; + + name = symbol->functionname; + if (name == NULL || *name == '\0') + name = "??"; + + if (symbol->filename != NULL) + filename = symbol->filename; + if (strcmp (filename, "/proc/self/exe") == 0) { + int len = readlink ("/proc/self/exe", path, sizeof (path) - 1); + if (len != -1) { + path[len] = '\0'; + filename = path; + } + } + h = strrchr (filename, '/'); + if (h != NULL) + filename = h + 1; + + if (symbol->line) { + snprintf (buf, buflen, "%s() [%s:%u]", + name, filename, symbol->line); + } else { + snprintf (buf, buflen, "%s() [%s]", name, filename); + } +} +#endif + +struct file_match { + const char *file; + ElfW(Addr) address; + ElfW(Addr) base; + void *hdr; +}; + +static int +find_matching_file (struct dl_phdr_info *info, size_t size, void *data) +{ + struct file_match *match = data; + /* This code is modeled from Gfind_proc_info-lsb.c:callback() from libunwind */ + long n; + const ElfW(Phdr) *phdr; + ElfW(Addr) load_base = info->dlpi_addr; + + phdr = info->dlpi_phdr; + for (n = info->dlpi_phnum; --n >= 0; phdr++) { + if (phdr->p_type == PT_LOAD) { + ElfW(Addr) vaddr = phdr->p_vaddr + load_base; + if (match->address >= vaddr && + match->address < vaddr + phdr->p_memsz) + { + /* we found a match */ + match->file = info->dlpi_name; + match->base = info->dlpi_addr; + return 1; + } + } + } + + return 0; +} + +struct symbol_cache_entry { + const void *ptr; + struct symbol_cache_entry *hash_prev, *hash_next; + char name[0]; +}; + +static struct symbol_cache_entry *symbol_cache_hash[13477]; +static pthread_mutex_t symbol_cache_mutex = PTHREAD_MUTEX_INITIALIZER; + +char * +lookup_symbol (char *buf, int buflen, const void *ptr) +{ + struct file_match match; +#if HAVE_BFD + struct symtab symtab; + struct symbol symbol; +#endif + struct symbol_cache_entry *cache; + int bucket; + int len; + + bucket = (uintptr_t) ptr % (sizeof (symbol_cache_hash) / sizeof (symbol_cache_hash[0])); + pthread_mutex_lock (&symbol_cache_mutex); + for (cache = symbol_cache_hash[bucket]; + cache != NULL; + cache = cache->hash_next) + { + if (cache->ptr == ptr) { + if (cache->hash_prev != NULL) { + cache->hash_prev->hash_next = cache->hash_next; + if (cache->hash_next != NULL) + cache->hash_next->hash_prev = cache->hash_prev; + cache->hash_prev = NULL; + cache->hash_next = symbol_cache_hash[bucket]; + symbol_cache_hash[bucket]->hash_prev = cache; + symbol_cache_hash[bucket] = cache; + } + + pthread_mutex_unlock (&symbol_cache_mutex); + return cache->name; + } + } + pthread_mutex_unlock (&symbol_cache_mutex); + + match.file = NULL; + match.address = (ElfW(Addr)) ptr; + dl_iterate_phdr (find_matching_file, &match); + + snprintf (buf, buflen, "0x%llx", + (long long unsigned int) match.address); + + if (match.file == NULL || *match.file == '\0') + match.file = "/proc/self/exe"; + +#if HAVE_BFD + if (_symtab_init (&symtab, match.file)) { + _symbol_init (&symbol, &symtab, match.address - match.base); + bfd_map_over_sections (symtab.bfd, find_address_in_section, &symbol); + if (symbol.found) + _symbol_print (&symbol, buf, buflen, match.file); + _symbol_fini (&symbol); + + _symtab_fini (&symtab); + } +#endif + + len = strlen (buf); + cache = malloc (sizeof (struct symbol_cache_entry) + len + 1); + if (cache != NULL) { + cache->ptr = ptr; + memcpy (cache->name, buf, len + 1); + + pthread_mutex_lock (&symbol_cache_mutex); + cache->hash_prev = NULL; + cache->hash_next = symbol_cache_hash[bucket]; + if (symbol_cache_hash[bucket] != NULL) + symbol_cache_hash[bucket]->hash_prev = cache; + symbol_cache_hash[bucket] = cache; + pthread_mutex_unlock (&symbol_cache_mutex); + } + + return buf; +} diff --git a/local/recipes/libs/cairo/source/util/cairo-trace/lookup-symbol.h b/local/recipes/libs/cairo/source/util/cairo-trace/lookup-symbol.h new file mode 100644 index 0000000000..83817edc6d --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-trace/lookup-symbol.h @@ -0,0 +1,24 @@ +/* cairo-trace - a utility to record and replay calls to the Cairo library. + * + * Copyright © 2008 Chris Wilson + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef LOOKUP_SYMBOLS_H + +char * +lookup_symbol (char *buf, int len, const void *ptr); + +#endif /*LOOKUP_SYMBOLS_H */ diff --git a/local/recipes/libs/cairo/source/util/cairo-trace/meson.build b/local/recipes/libs/cairo/source/util/cairo-trace/meson.build new file mode 100644 index 0000000000..8d4ac131b1 --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-trace/meson.build @@ -0,0 +1,36 @@ +cairo_trace_sources = [ + 'trace.c', +] + +if conf.get('CAIRO_HAS_SYMBOL_LOOKUP', 0) == 1 + cairo_trace_sources += ['lookup-symbol.c'] +endif + +shared_lib_ext = libcairo.full_path().split('.')[-1] + +libcairotrace = library('cairo-trace', cairo_trace_sources, + include_directories: [incbase, incsrc], + dependencies: deps, + c_args: ['-DSHARED_LIB_EXT="@0@"'.format(shared_lib_ext),] + pthread_c_args, + link_args: extra_link_args, + gnu_symbol_visibility: 'hidden', + install: true, + install_dir: get_option('libdir') / 'cairo', +) + +trace_conf = configuration_data() +trace_conf.set('prefix', get_option('prefix')) +trace_conf.set('exec_prefix', get_option('prefix')) +trace_conf.set('libdir', get_option('prefix') / get_option('libdir')) +trace_conf.set('CAIRO_VERSION_MAJOR', meson.project_version().split('.')[0]) +trace_conf.set('CAIRO_VERSION_MINOR', meson.project_version().split('.')[1]) +trace_conf.set('CAIRO_VERSION_MICRO', meson.project_version().split('.')[2]) +trace_conf.set('SHLIB_EXT', shared_lib_ext) + +configure_file(input: 'cairo-trace.in', + output: 'cairo-trace', + configuration: trace_conf, + install: true, + install_dir: join_paths(get_option('prefix'), get_option('bindir')), + install_mode: 'rwxr-xr-x', +) diff --git a/local/recipes/libs/cairo/source/util/cairo-trace/trace.c b/local/recipes/libs/cairo/source/util/cairo-trace/trace.c new file mode 100644 index 0000000000..8bdb3f8819 --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-trace/trace.c @@ -0,0 +1,5325 @@ +/* cairo-trace - a utility to record and replay calls to the Cairo library. + * + * Copyright © 2008 Chris Wilson + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "config.h" + +/* The autoconf on OpenBSD 4.5 produces the malformed constant name + * SIZEOF_VOID__ rather than SIZEOF_VOID_P. Work around that here. */ +#if !defined(SIZEOF_VOID_P) && defined(SIZEOF_VOID__) +# define SIZEOF_VOID_P SIZEOF_VOID__ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for locale independent %f printing */ +#include +#include +#include +#include +#include + +#include +#if CAIRO_HAS_FT_FONT +# include +#endif + +#include "cairo-ctype-inline.h" + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +#ifndef CAIRO_TRACE_OUTDIR +#define CAIRO_TRACE_OUTDIR "." +#endif + +#define DEBUG_STACK 0 + +#if HAVE_BYTESWAP_H +# include +#endif +#ifndef bswap_16 +# define bswap_16(p) \ + (((((uint16_t)(p)) & 0x00ff) << 8) | \ + (((uint16_t)(p)) >> 8)) +#endif +#ifndef bswap_32 +# define bswap_32(p) \ + (((((uint32_t)(p)) & 0x000000ff) << 24) | \ + ((((uint32_t)(p)) & 0x0000ff00) << 8) | \ + ((((uint32_t)(p)) & 0x00ff0000) >> 8) | \ + ((((uint32_t)(p))) >> 24)) +#endif + +#if WORDS_BIGENDIAN +#define le16(x) bswap_16 (x) +#define le32(x) bswap_32 (x) +#define be16(x) x +#define be32(x) x +#define to_be32(x) x +#else +#define le16(x) x +#define le32(x) x +#define be16(x) bswap_16 (x) +#define be32(x) bswap_32 (x) +#define to_be32(x) bswap_32 (x) +#endif + +#if CAIRO_HAS_SYMBOL_LOOKUP +#include "lookup-symbol.h" +#endif + +/* Reverse the bits in a byte with 7 operations (no 64-bit): + * Devised by Sean Anderson, July 13, 2001. + * Source: http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith32Bits + */ +#define CAIRO_BITSWAP8(c) ((((c) * 0x0802LU & 0x22110LU) | ((c) * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16) + +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4) +#ifdef __MINGW32__ +#define CAIRO_PRINTF_FORMAT(fmt_index, va_index) \ + __attribute__((__format__(__MINGW_PRINTF_FORMAT, fmt_index, va_index))) +#else +#define CAIRO_PRINTF_FORMAT(fmt_index, va_index) \ + __attribute__((__format__(__printf__, fmt_index, va_index))) +#endif +#else +#define CAIRO_PRINTF_FORMAT(fmt_index, va_index) +#endif + +/* XXX implement manual vprintf so that the user can control precision of + * printed numbers. + */ + +static void *_dlhandle = RTLD_NEXT; +#define DLCALL(name, args...) ({ \ + static typeof (&name) name##_real; \ + if (name##_real == NULL) { \ + name##_real = (typeof (&name))(dlsym (_dlhandle, #name)); \ + if (name##_real == NULL && _dlhandle == RTLD_NEXT) { \ + _dlhandle = dlopen ("libcairo." SHARED_LIB_EXT, RTLD_LAZY); \ + name##_real = (typeof (&name))(dlsym (_dlhandle, #name)); \ + assert (name##_real != NULL); \ + } \ + } \ + (*name##_real) (args); \ +}) + +#ifndef ARRAY_LENGTH +#define ARRAY_LENGTH(__array) ((int) (sizeof (__array) / sizeof (__array[0]))) +#endif + +#if SIZEOF_VOID_P == 4 +#define PTR_SHIFT 2 +#elif SIZEOF_VOID_P == 8 +#define PTR_SHIFT 3 +#else +#error Unexpected pointer size +#endif +#define BUCKET(b, ptr) (((uintptr_t) (ptr) >> PTR_SHIFT) % ARRAY_LENGTH (b)) + +#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__) +#define _BOOLEAN_EXPR(expr) \ + __extension__ ({ \ + int _boolean_var_; \ + if (expr) \ + _boolean_var_ = 1; \ + else \ + _boolean_var_ = 0; \ + _boolean_var_; \ +}) +#define LIKELY(expr) (__builtin_expect (_BOOLEAN_EXPR(expr), 1)) +#define UNLIKELY(expr) (__builtin_expect (_BOOLEAN_EXPR(expr), 0)) +#else +#define LIKELY(expr) (expr) +#define UNLIKELY(expr) (expr) +#endif + +typedef struct _object Object; +typedef struct _type Type; + +struct _object { + const void *addr; + Type *type; + unsigned long int token; + int width, height; + cairo_bool_t foreign; + cairo_bool_t defined; + cairo_bool_t unknown; + int operand; + void *data; + void (*destroy)(void *); + Object *next, *prev; +}; + +struct _type { + const char *name; + + enum operand_type { + NONE, + SURFACE, + CONTEXT, + FONT_FACE, + PATTERN, + SCALED_FONT, + _N_OP_TYPES + } op_type; + const char *op_code; + + pthread_mutex_t mutex; + struct _bitmap { + unsigned long int min; + unsigned long int count; + unsigned int map[64]; + struct _bitmap *next; + } map; + Object *objects[607]; + Type *next; +}; + +static struct _type_table { + pthread_mutex_t mutex; + Type *op_types[_N_OP_TYPES]; +} Types; + +static FILE *logfile; +static cairo_bool_t _flush; +static cairo_bool_t _error; +static cairo_bool_t _line_info; +static cairo_bool_t _mark_dirty; +static const cairo_user_data_key_t destroy_key; +static pthread_once_t once_control = PTHREAD_ONCE_INIT; +static pthread_key_t counter_key; + +static void _init_trace (void); + +#define INIT_TRACE_ONCE() pthread_once (&once_control, _init_trace) + +#if __GNUC__ >= 3 && defined(__ELF__) && !defined(__sun) +# define _enter_trace() INIT_TRACE_ONCE () +# define _exit_trace() do { } while (0) +# define _should_trace() 1 +# define USE_ENTER_EXIT 0 +#else +static void _enter_trace (void); +static void _exit_trace (void); +static cairo_bool_t _should_trace (void); +# define USE_ENTER_EXIT 1 +#endif + +#if HAVE_BUILTIN_RETURN_ADDRESS && CAIRO_HAS_SYMBOL_LOOKUP +#define _emit_line_info() do { \ + if (_line_info && _write_lock ()) { \ + void *addr = __builtin_return_address(0); \ + char caller[1024]; \ + _trace_printf ("%% %s() called by %s\n", __FUNCTION__, \ + lookup_symbol (caller, sizeof (caller), addr)); \ + _write_unlock (); \ + } \ +} while (0) +#else +#define _emit_line_info() +#endif + +static void +_type_release_token (Type *t, unsigned long int token) +{ + struct _bitmap *b, **prev = NULL; + + b = &t->map; + while (b != NULL) { + if (token < b->min + sizeof (b->map) * CHAR_BIT) { + unsigned int bit, elem; + + token -= b->min; + elem = token / (sizeof (b->map[0]) * CHAR_BIT); + bit = token % (sizeof (b->map[0]) * CHAR_BIT); + b->map[elem] &= ~(1 << bit); + if (! --b->count && prev) { + *prev = b->next; + free (b); + } + return; + } + prev = &b->next; + b = b->next; + } +} + +static unsigned long int +_type_next_token (Type *t) +{ + struct _bitmap *b, *bb, **prev = NULL; + unsigned long int min = 0; + + b = &t->map; + while (b != NULL) { + if (b->min != min) + break; + + if (b->count < sizeof (b->map) * CHAR_BIT) { + unsigned int n, m, bit; + for (n = 0; n < ARRAY_LENGTH (b->map); n++) { + if (b->map[n] == (unsigned int) -1) + continue; + + for (m=0, bit=1; mmap[0])*CHAR_BIT; m++, bit<<=1) { + if ((b->map[n] & bit) == 0) { + b->map[n] |= bit; + b->count++; + return n * sizeof (b->map[0])*CHAR_BIT + m + b->min; + } + } + } + } + min += sizeof (b->map) * CHAR_BIT; + + prev = &b->next; + b = b->next; + } + assert (prev != NULL); + + bb = malloc (sizeof (struct _bitmap)); + + *prev = bb; + bb->next = b; + bb->min = min; + bb->count = 1; + bb->map[0] = 0x1; + memset (bb->map + 1, 0, sizeof (bb->map) - sizeof (bb->map[0])); + + return min; +} + +static void +_object_destroy (Object *obj) +{ + int bucket; + + pthread_mutex_lock (&obj->type->mutex); + bucket = BUCKET (obj->type->objects, obj->addr); + _type_release_token (obj->type, obj->token); + + if (obj->prev != NULL) + obj->prev->next = obj->next; + else + obj->type->objects[bucket] = obj->next; + + if (obj->next != NULL) + obj->next->prev = obj->prev; + pthread_mutex_unlock (&obj->type->mutex); + + if (obj->data != NULL && obj->destroy != NULL) + obj->destroy (obj->data); + + free (obj); +} + +static void +_type_create (const char *typename, + enum operand_type op_type, + const char *op_code) +{ + Type *t; + + pthread_mutex_lock (&Types.mutex); + + t = malloc (sizeof (Type)); + t->name = typename; + t->op_type = op_type; + t->op_code = op_code; + + pthread_mutex_init (&t->mutex, NULL); + + t->map.min = 0; + t->map.count = 0; + memset (t->map.map, 0, sizeof (t->map.map)); + t->map.next = NULL; + + memset (t->objects, 0, sizeof (t->objects)); + + t->next = NULL; + + Types.op_types[op_type] = t; + pthread_mutex_unlock (&Types.mutex); +} + +static Type * +_get_type (enum operand_type type) +{ + return Types.op_types[type]; +} + +static void +_type_destroy (Type *t) +{ + int n; + struct _bitmap *b; + + for (n = 0; n < ARRAY_LENGTH (t->objects); n++) { + Object *obj = t->objects[n]; + while (obj != NULL) { + Object *next = obj->next; + _object_destroy (obj); + obj = next; + } + } + + b = t->map.next; + while (b != NULL) { + struct _bitmap *next = b->next; + free (b); + b = next; + } + + pthread_mutex_destroy (&t->mutex); + free (t); +} + +static Object * +_type_get_object (Type *type, const void *ptr) +{ + Object *obj; + int bucket = BUCKET (type->objects, ptr); + + for (obj = type->objects[bucket]; obj != NULL; obj = obj->next) { + if (obj->addr == ptr) { + if (obj->prev != NULL) { /* mru */ + obj->prev->next = obj->next; + if (obj->next != NULL) + obj->next->prev = obj->prev; + obj->prev = NULL; + type->objects[bucket]->prev = obj; + obj->next = type->objects[bucket]; + type->objects[bucket] = obj; + } + return obj; + } + } + + return NULL; +} + +static Object * +_object_create (Type *type, const void *ptr) +{ + Object *obj; + int bucket = BUCKET (type->objects, ptr); + + obj = malloc (sizeof (Object)); + obj->unknown = TRUE; + obj->defined = FALSE; + obj->foreign = FALSE; + obj->operand = -1; + obj->type = type; + obj->addr = ptr; + obj->token = _type_next_token (type); + obj->data = NULL; + obj->destroy = NULL; + obj->prev = NULL; + obj->next = type->objects[bucket]; + if (type->objects[bucket] != NULL) + type->objects[bucket]->prev = obj; + type->objects[bucket] = obj; + + return obj; +} + +#if USE_ENTER_EXIT +static int * +_get_counter (void) +{ + int *counter = pthread_getspecific (counter_key); + if (counter == NULL) { + counter = calloc(1, sizeof(int)); + pthread_setspecific (counter_key, counter); + } + return counter; +} + +static void +_enter_trace (void) +{ + INIT_TRACE_ONCE (); + _get_counter ()[0]++; +} + +static void +_exit_trace (void) +{ + _get_counter ()[0]--; +} + +static cairo_bool_t +_should_trace (void) +{ + return _get_counter ()[0] <= 1; +} +#endif /* USE_ENTER_EXIT */ + +static void +_init_trace (void) +{ + pthread_mutex_init (&Types.mutex, NULL); + pthread_key_create (&counter_key, free); + + _type_create ("unclassed", NONE, ""); + _type_create ("cairo_t", CONTEXT, "c"); + _type_create ("cairo_font_face_t", FONT_FACE, "f"); + _type_create ("cairo_pattern_t", PATTERN, "p"); + _type_create ("cairo_scaled_font_t", SCALED_FONT, "sf"); + _type_create ("cairo_surface_t", SURFACE, "s"); +} + +static void +_close_trace (void) +{ + if (logfile != NULL) { + fclose (logfile); + logfile = NULL; + } +} + +static void __attribute__ ((destructor)) +_fini_trace (void) +{ + int n; + + _close_trace (); + + for (n = 0; n < ARRAY_LENGTH (Types.op_types); n++) { + if (Types.op_types[n]) { + _type_destroy (Types.op_types[n]); + Types.op_types[n] = NULL; + } + } + + pthread_mutex_destroy (&Types.mutex); +} + +/* Format a double in a locale independent way and trim trailing + * zeros. Based on code from Alex Larson . + * https://mail.gnome.org/archives/gtk-devel-list/2001-October/msg00087.html + * + * The code in the patch is copyright Red Hat, Inc under the LGPL. + */ +#define SIGNIFICANT_DIGITS_AFTER_DECIMAL 6 +static void +_trace_dtostr (char *buffer, size_t size, double d) +{ + struct lconv *locale_data; + const char *decimal_point; + int decimal_point_len; + char *p; + int decimal_len; + int num_zeros, decimal_digits; + + /* Omit the minus sign from negative zero. */ + if (d == 0.0) + d = 0.0; + + locale_data = localeconv (); + decimal_point = locale_data->decimal_point; + decimal_point_len = strlen (decimal_point); + + /* Using "%f" to print numbers less than 0.1 will result in + * reduced precision due to the default 6 digits after the + * decimal point. + * + * For numbers is < 0.1, we print with maximum precision and count + * the number of zeros between the decimal point and the first + * significant digit. We then print the number again with the + * number of decimal places that gives us the required number of + * significant digits. This ensures the number is correctly + * rounded. + */ + if (fabs (d) >= 0.1) { + snprintf (buffer, size, "%f", d); + } else { + snprintf (buffer, size, "%.18f", d); + p = buffer; + + if (*p == '+' || *p == '-') + p++; + + while (_cairo_isdigit (*p)) + p++; + + if (strncmp (p, decimal_point, decimal_point_len) == 0) + p += decimal_point_len; + + num_zeros = 0; + while (*p++ == '0') + num_zeros++; + + decimal_digits = num_zeros + SIGNIFICANT_DIGITS_AFTER_DECIMAL; + + if (decimal_digits < 18) + snprintf (buffer, size, "%.*f", decimal_digits, d); + } + p = buffer; + + if (*p == '+' || *p == '-') + p++; + + while (_cairo_isdigit (*p)) + p++; + + if (strncmp (p, decimal_point, decimal_point_len) == 0) { + *p = '.'; + decimal_len = strlen (p + decimal_point_len); + memmove (p + 1, p + decimal_point_len, decimal_len); + p[1 + decimal_len] = 0; + + /* Remove trailing zeros and decimal point if possible. */ + for (p = p + decimal_len; *p == '0'; p--) + *p = 0; + + if (*p == '.') { + *p = 0; + p--; + } + } +} + +enum { + LENGTH_MODIFIER_LONG = 0x100 +}; + +/* Here's a limited reimplementation of printf. The reason for doing + * this is primarily to special case handling of doubles. We want + * locale independent formatting of doubles and we want to trim + * trailing zeros. This is handled by dtostr() above, and the code + * below handles everything else by calling snprintf() to do the + * formatting. This functionality is only for internal use and we + * only implement the formats we actually use. + */ +static void CAIRO_PRINTF_FORMAT(1, 0) +_trace_vprintf (const char *fmt, va_list ap) +{ +#define SINGLE_FMT_BUFFER_SIZE 32 + char buffer[512], single_fmt[SINGLE_FMT_BUFFER_SIZE]; + int single_fmt_length; + char *p; + const char *f, *start; + int length_modifier, width; + cairo_bool_t var_width; + int ret_ignored; + + assert (_should_trace ()); + + f = fmt; + p = buffer; + while (*f != '\0') { + if (*f != '%') { + *p++ = *f++; + continue; + } + + start = f; + f++; + + if (*f == '0') + f++; + + var_width = 0; + if (*f == '*') { + var_width = 1; + f++; + } + + while (_cairo_isdigit (*f)) + f++; + + length_modifier = 0; + if (*f == 'l') { + length_modifier = LENGTH_MODIFIER_LONG; + f++; + } + + /* The only format strings exist in the cairo implementation + * itself. So there's an internal consistency problem if any + * of them is larger than our format buffer size. */ + single_fmt_length = f - start + 1; + + /* Reuse the format string for this conversion. */ + memcpy (single_fmt, start, single_fmt_length); + single_fmt[single_fmt_length] = '\0'; + + /* Flush contents of buffer before snprintf()'ing into it. */ + ret_ignored = fwrite (buffer, 1, p-buffer, logfile); + + /* We group signed and unsigned together in this switch, the + * only thing that matters here is the size of the arguments, + * since we're just passing the data through to sprintf(). */ + switch (*f | length_modifier) { + case '%': + buffer[0] = *f; + buffer[1] = 0; + break; + case 'd': + case 'u': + case 'o': + case 'x': + case 'X': + if (var_width) { + width = va_arg (ap, int); + snprintf (buffer, sizeof buffer, + single_fmt, width, va_arg (ap, int)); + } else { + snprintf (buffer, sizeof buffer, single_fmt, va_arg (ap, int)); + } + break; + case 'd' | LENGTH_MODIFIER_LONG: + case 'u' | LENGTH_MODIFIER_LONG: + case 'o' | LENGTH_MODIFIER_LONG: + case 'x' | LENGTH_MODIFIER_LONG: + case 'X' | LENGTH_MODIFIER_LONG: + if (var_width) { + width = va_arg (ap, int); + snprintf (buffer, sizeof buffer, + single_fmt, width, va_arg (ap, long int)); + } else { + snprintf (buffer, sizeof buffer, + single_fmt, va_arg (ap, long int)); + } + break; + case 's': + snprintf (buffer, sizeof buffer, + single_fmt, va_arg (ap, const char *)); + break; + case 'f': + case 'g': + _trace_dtostr (buffer, sizeof buffer, va_arg (ap, double)); + break; + case 'c': + buffer[0] = va_arg (ap, int); + buffer[1] = 0; + break; + default: + break; + } + p = buffer + strlen (buffer); + f++; + } + + ret_ignored = fwrite (buffer, 1, p-buffer, logfile); + (void)ret_ignored; +} + +static void CAIRO_PRINTF_FORMAT(1, 2) +_trace_printf (const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + _trace_vprintf (fmt, ap); + va_end (ap); +} + +static void +get_prog_name (char *buf, int length) +{ + char *slash; + FILE *file; + + memset (buf, 0, length); + if (length == 0) + return; + + file = fopen ("/proc/self/cmdline", "rb"); + if (file != NULL) { + slash = fgets (buf, length, file); + fclose (file); + + if (slash == NULL) + return; + } else { + char const *name = getenv ("CAIRO_TRACE_PROG_NAME"); + if (name != NULL) { + strncpy (buf, name, length-1); + } + } + + slash = strrchr (buf, '/'); + if (slash != NULL) { + size_t len = strlen (slash+1); + memmove (buf, slash+1, len+1); + } +} + +static void +_emit_header (void) +{ + char name[4096] = ""; + + get_prog_name (name, sizeof (name)); + + _trace_printf ("%%!CairoScript - %s\n", name); +} + +static cairo_bool_t +_init_logfile (void) +{ + static cairo_bool_t initialized; + char buf[4096]; + const char *filename; + const char *env; + + if (initialized) + return logfile != NULL; + + initialized = TRUE; + + env = getenv ("CAIRO_TRACE_FLUSH"); + if (env != NULL) + _flush = atoi (env); + + _line_info = TRUE; + env = getenv ("CAIRO_TRACE_LINE_INFO"); + if (env != NULL) + _line_info = atoi (env); + + _mark_dirty = TRUE; + env = getenv ("CAIRO_TRACE_MARK_DIRTY"); + if (env != NULL) + _mark_dirty = atoi (env); + + filename = getenv ("CAIRO_TRACE_FD"); + if (filename != NULL) { + int fd = atoi (filename); + if (fd == -1) + return FALSE; + + logfile = fdopen (fd, "w"); + if (logfile == NULL) { + fprintf (stderr, "Failed to open trace file descriptor '%s': %s\n", + filename, strerror (errno)); + return FALSE; + } + + setenv ("CAIRO_TRACE_FD", "-1", 1); + goto done; + } + + filename = getenv ("CAIRO_TRACE_OUTFILE_EXACT"); + if (filename == NULL) { + char name[4096] = ""; + + filename = getenv ("CAIRO_TRACE_OUTDIR"); + if (filename == NULL) + filename = CAIRO_TRACE_OUTDIR; + + get_prog_name (name, sizeof (name)); + if (*name == '\0') + strcpy (name, "cairo-trace.dat"); + + if (snprintf (buf, sizeof (buf), "%s/%s.%d.trace", + filename, name, getpid()) >= (int) sizeof (buf)) + { + fprintf (stderr, "cairo-trace: Trace file name too long\n"); + return FALSE; + } + + filename = buf; + } else { + setenv ("CAIRO_TRACE_FD", "-1", 1); + } + + logfile = fopen (filename, "wb"); + if (logfile == NULL) { + fprintf (stderr, "Failed to open trace file '%s': %s\n", + filename, strerror (errno)); + return FALSE; + } + + fprintf (stderr, "cairo-trace: Recording cairo trace data to %s\n", + filename); + +done: + atexit (_close_trace); + _emit_header (); + return TRUE; +} + +static cairo_bool_t +_write_lock (void) +{ + if (_error) + return FALSE; + + if (! _should_trace ()) + return FALSE; + + if (! _init_logfile ()) + return FALSE; + +#if HAVE_FLOCKFILE && HAVE_FUNLOCKFILE + flockfile (logfile); +#endif + return TRUE; +} + +static void +_write_unlock (void) +{ + if (logfile == NULL) + return; + +#if HAVE_FLOCKFILE && HAVE_FUNLOCKFILE + funlockfile (logfile); +#endif + + if (_flush) + fflush (logfile); +} + + +static Object * +_type_object_create (enum operand_type op_type, const void *ptr) +{ + Type *type; + Object *obj; + + type = _get_type (op_type); + + pthread_mutex_lock (&type->mutex); + obj = _object_create (type, ptr); + pthread_mutex_unlock (&type->mutex); + + return obj; +} + +static Object * +_get_object (enum operand_type op_type, const void *ptr) +{ + Type *type; + Object *obj; + + type = _get_type (op_type); + pthread_mutex_lock (&type->mutex); + obj = _type_get_object (type, ptr); + pthread_mutex_unlock (&type->mutex); + + return obj; +} + +static Object *current_object[2048]; /* XXX limit operand stack */ +static int current_stack_depth; + +static void +dump_stack(const char *func) +{ +#if DEBUG_STACK + int n; + + _trace_printf ("%% %s: stack[%d] = [", func, current_stack_depth); + fflush (logfile); + for (n = 0; n < current_stack_depth; n++) { + Object *obj = current_object[n]; + assert(obj && obj->type); + _trace_printf (" %s%s%ld", + obj->defined ? "" : "*", + obj->type->op_code, obj->token); + fflush (logfile); + } + _trace_printf (" ]\n"); + fflush (logfile); +#endif +} + +static void +ensure_operands (int num_operands) +{ + if (current_stack_depth < num_operands) { + int n; + + fprintf (stderr, "Operand stack underflow!\n"); + for (n = 0; n < current_stack_depth; n++) { + Object *obj = current_object[n]; + + fprintf (stderr, " [%3d] = %s%ld\n", + n, obj->type->op_code, obj->token); + } + + abort (); + } +} + +static void +_consume_operand (bool discard) +{ + Object *obj; + + ensure_operands (1); + obj = current_object[--current_stack_depth]; + if (!discard && ! obj->defined) { + _trace_printf ("dup /%s%ld exch def\n", + obj->type->op_code, + obj->token); + obj->defined = TRUE; + } + obj->operand = -1; +} + +static void +_exch_operands (void) +{ + Object *tmp; + + ensure_operands (2); + tmp = current_object[current_stack_depth-1]; + tmp->operand--; + current_object[current_stack_depth-1] = current_object[current_stack_depth-2]; + current_object[current_stack_depth-2] = tmp; + tmp = current_object[current_stack_depth-1]; + tmp->operand++; +} + +static cairo_bool_t +_pop_operands_to_depth (int depth) +{ + if (depth < 0) + return FALSE; + + assert(current_stack_depth >= depth); + if (current_stack_depth == depth) + return TRUE; + + while (current_stack_depth > depth + 1) { + Object *c_obj; + + ensure_operands (1); + c_obj = current_object[--current_stack_depth]; + + assert(c_obj); + assert(c_obj->type); + + if (! c_obj->defined) { + current_stack_depth++; + return FALSE; + } + + _trace_printf ("pop %% %s%ld\n", + c_obj->type->op_code, c_obj->token); + c_obj->operand = -1; + } + + _exch_operands (); + _trace_printf ("exch\n"); + + dump_stack(__func__); + return TRUE; +} + +static cairo_bool_t +_pop_operands_to_object (Object *obj) +{ + if (!obj) + return FALSE; + + if (obj->operand == -1) + return FALSE; + + if (obj->operand == current_stack_depth - 1) + return TRUE; + + if (obj->operand == current_stack_depth - 2) { + _exch_operands (); + _trace_printf ("exch "); + return TRUE; + } + + return _pop_operands_to_depth (obj->operand + 1); +} + +static cairo_bool_t +_pop_operands_to (enum operand_type t, const void *ptr) +{ + return _pop_operands_to_object (_get_object (t, ptr)); +} + +static cairo_bool_t +_is_current_object (Object *obj, int depth) +{ + if (current_stack_depth <= depth) + return FALSE; + return current_object[current_stack_depth-depth-1] == obj; +} + +static cairo_bool_t +_is_current (enum operand_type type, const void *ptr, int depth) +{ + return _is_current_object (_get_object (type, ptr), depth); +} + +static void +_push_object(Object *obj) +{ + assert(obj->operand == -1); + + if (current_stack_depth == ARRAY_LENGTH (current_object)) { + int n; + + fprintf (stderr, "Operand stack overflow!\n"); + for (n = 0; n < current_stack_depth; n++) { + obj = current_object[n]; + + fprintf (stderr, " [%3d] = %s%ld\n", + n, obj->type->op_code, obj->token); + } + + abort (); + } + + obj->operand = current_stack_depth; + current_object[current_stack_depth++] = obj; +} + +static void +_push_operand (enum operand_type t, const void *ptr) +{ + _push_object(_get_object(t, ptr)); +} + +static void +_object_remove (Object *obj) +{ + if (obj->operand != -1) { + ensure_operands (1); + if (obj->operand == current_stack_depth - 1) { + _trace_printf ("pop %% %s%ld destroyed\n", + obj->type->op_code, obj->token); + } else if (obj->operand == current_stack_depth - 2) { + _exch_operands (); + _trace_printf ("exch pop %% %s%ld destroyed\n", + obj->type->op_code, obj->token); + } else { + int n; + + _trace_printf ("%d -1 roll pop %% %s%ld destroyed\n", + current_stack_depth - obj->operand, + obj->type->op_code, obj->token); + + for (n = obj->operand; n < current_stack_depth - 1; n++) { + current_object[n] = current_object[n+1]; + current_object[n]->operand = n; + } + } + obj->operand = -1; + + current_stack_depth--; + dump_stack(__func__); + } +} + +static void +_object_undef (void *ptr) +{ + Object *obj = ptr; + + if (_write_lock ()) { + _object_remove (obj); + + if (obj->defined) { + _trace_printf ("/%s%ld undef\n", + obj->type->op_code, obj->token); + } + + _write_unlock (); + } + + _object_destroy (obj); +} + +static long +_create_context_id (cairo_t *cr) +{ + Object *obj; + + obj = _get_object (CONTEXT, cr); + if (obj == NULL) { + obj = _type_object_create (CONTEXT, cr); + DLCALL (cairo_set_user_data, + cr, &destroy_key, obj, _object_undef); + } + + return obj->token; +} + +static long +_get_id (enum operand_type op_type, const void *ptr) +{ + Object *obj; + + obj = _get_object (op_type, ptr); + if (obj == NULL) { + if (logfile != NULL) { + _trace_printf ("%% Unknown object of type %s, trace is incomplete.", + _get_type (op_type)->name); + } + _error = TRUE; + return -1; + } + + return obj->token; +} + +static cairo_bool_t +_has_id (enum operand_type op_type, const void *ptr) +{ + return _get_object (op_type, ptr) != NULL; +} + +static long +_create_font_face_id (cairo_font_face_t *font_face) +{ + Object *obj; + + obj = _get_object (FONT_FACE, font_face); + if (obj == NULL) { + obj = _type_object_create (FONT_FACE, font_face); + DLCALL (cairo_font_face_set_user_data, + font_face, &destroy_key, obj, _object_undef); + } + + return obj->token; +} + +static long +_get_font_face_id (cairo_font_face_t *font_face) +{ + return _get_id (FONT_FACE, font_face); +} + +static void +_emit_font_face_id (cairo_font_face_t *font_face) +{ + Object *obj = _get_object (FONT_FACE, font_face); + if (obj == NULL) { + _trace_printf ("null "); + } else { + if (obj->defined) { + _trace_printf ("f%ld ", obj->token); + } else { + _trace_printf ("%d index ", current_stack_depth - obj->operand - 1); + } + } +} + +static cairo_bool_t +_has_pattern_id (cairo_pattern_t *pattern) +{ + return _has_id (PATTERN, pattern); +} + +static long +_create_pattern_id (cairo_pattern_t *pattern) +{ + Object *obj; + + obj = _get_object (PATTERN, pattern); + if (obj == NULL) { + obj = _type_object_create (PATTERN, pattern); + DLCALL (cairo_pattern_set_user_data, + pattern, &destroy_key, obj, _object_undef); + } + + return obj->token; +} + +static void +_emit_pattern_id (cairo_pattern_t *pattern) +{ + Object *obj = _get_object (PATTERN, pattern); + if (obj == NULL) { + _trace_printf ("null "); + } else { + if (obj->defined) { + _trace_printf ("p%ld ", obj->token); + } else { + _trace_printf ("%d index ", + current_stack_depth - obj->operand - 1); + } + } +} + +static void +_emit_scaled_font_id (const cairo_scaled_font_t *scaled_font) +{ + Object *obj = _get_object (SCALED_FONT, scaled_font); + if (obj == NULL) { + _trace_printf ("null "); + } else { + if (obj->defined) { + _trace_printf ("sf%ld ", obj->token); + } else { + _trace_printf ("%d index ", + current_stack_depth - obj->operand - 1); + } + } +} + +static long +_create_scaled_font_id (cairo_scaled_font_t *font) +{ + Object *obj; + + assert(_get_object (SCALED_FONT, font) == NULL); + obj = _type_object_create (SCALED_FONT, font); + DLCALL (cairo_scaled_font_set_user_data, + font, &destroy_key, obj, _object_undef); + + return obj->token; +} + +static cairo_bool_t +_has_scaled_font_id (const cairo_scaled_font_t *font) +{ + return _has_id (SCALED_FONT, font); +} + +static Object * +_create_surface (cairo_surface_t *surface) +{ + Object *obj; + + obj = _get_object (SURFACE, surface); + if (obj == NULL) { + obj = _type_object_create (SURFACE, surface); + DLCALL (cairo_surface_set_user_data, + surface, &destroy_key, obj, _object_undef); + } + + return obj; +} + +static long +_get_surface_id (cairo_surface_t *surface) +{ + return _get_id (SURFACE, surface); +} + +static cairo_bool_t +_matrix_is_identity (const cairo_matrix_t *m) +{ + return m->xx == 1. && m->yx == 0. && + m->xy == 0. && m->yy == 1. && + m->x0 == 0. && m->y0 == 0.; +} + +#define BUFFER_SIZE 16384 +struct _data_stream { + z_stream zlib_stream; + unsigned char zin_buf[BUFFER_SIZE]; + unsigned char zout_buf[BUFFER_SIZE]; + unsigned char four_tuple[4]; + int base85_pending; +}; + +static void +_write_zlib_data_start (struct _data_stream *stream) +{ + stream->zlib_stream.zalloc = Z_NULL; + stream->zlib_stream.zfree = Z_NULL; + stream->zlib_stream.opaque = Z_NULL; + + deflateInit (&stream->zlib_stream, Z_DEFAULT_COMPRESSION); + + stream->zlib_stream.next_in = stream->zin_buf; + stream->zlib_stream.avail_in = 0; + stream->zlib_stream.next_out = stream->zout_buf; + stream->zlib_stream.avail_out = BUFFER_SIZE; +} + +static void +_write_base85_data_start (struct _data_stream *stream) +{ + stream->base85_pending = 0; +} + +static cairo_bool_t +_expand_four_tuple_to_five (unsigned char four_tuple[4], + unsigned char five_tuple[5]) +{ + uint32_t value; + int digit, i; + cairo_bool_t all_zero = TRUE; + + value = four_tuple[0] << 24 | + four_tuple[1] << 16 | + four_tuple[2] << 8 | + four_tuple[3] << 0; + for (i = 0; i < 5; i++) { + digit = value % 85; + if (digit != 0 && all_zero) + all_zero = FALSE; + five_tuple[4-i] = digit + 33; + value = value / 85; + } + + return all_zero; +} + +static void +_write_base85_data (struct _data_stream *stream, + const unsigned char *data, + unsigned long length) +{ + unsigned char five_tuple[5]; + int ret; + + assert (_should_trace ()); + + while (length--) { + stream->four_tuple[stream->base85_pending++] = *data++; + if (stream->base85_pending == 4) { + if (_expand_four_tuple_to_five (stream->four_tuple, five_tuple)) + ret = fwrite ("z", 1, 1, logfile); + else + ret = fwrite (five_tuple, 5, 1, logfile); + (void)ret; + stream->base85_pending = 0; + } + } +} + +static void +_write_zlib_data (struct _data_stream *stream, cairo_bool_t flush) +{ + cairo_bool_t finished; + + do { + int ret = deflate (&stream->zlib_stream, flush ? Z_FINISH : Z_NO_FLUSH); + if (flush || stream->zlib_stream.avail_out == 0) { + _write_base85_data (stream, + stream->zout_buf, + BUFFER_SIZE - stream->zlib_stream.avail_out); + stream->zlib_stream.next_out = stream->zout_buf; + stream->zlib_stream.avail_out = BUFFER_SIZE; + } + + finished = TRUE; + if (stream->zlib_stream.avail_in != 0) + finished = FALSE; + if (flush && ret != Z_STREAM_END) + finished = FALSE; + } while (! finished); + + stream->zlib_stream.next_in = stream->zin_buf; +} + +static void +_write_data_start (struct _data_stream *stream, uint32_t len) +{ + _write_zlib_data_start (stream); + _write_base85_data_start (stream); + + _trace_printf ("<|"); + len = to_be32 (len); + _write_base85_data (stream, (unsigned char *) &len, sizeof (len)); +} + +static void +_write_data (struct _data_stream *stream, + const void *data, + unsigned int length) +{ + unsigned int count; + const unsigned char *p = data; + + while (length) { + count = length; + if (count > BUFFER_SIZE - stream->zlib_stream.avail_in) + count = BUFFER_SIZE - stream->zlib_stream.avail_in; + memcpy (stream->zin_buf + stream->zlib_stream.avail_in, p, count); + p += count; + stream->zlib_stream.avail_in += count; + length -= count; + + if (stream->zlib_stream.avail_in == BUFFER_SIZE) + _write_zlib_data (stream, FALSE); + } +} + +static void +_write_zlib_data_end (struct _data_stream *stream) +{ + _write_zlib_data (stream, TRUE); + deflateEnd (&stream->zlib_stream); + +} + +static void +_write_base85_data_end (struct _data_stream *stream) +{ + unsigned char five_tuple[5]; + int ret; + + assert (_should_trace ()); + + if (stream->base85_pending) { + memset (stream->four_tuple + stream->base85_pending, + 0, 4 - stream->base85_pending); + _expand_four_tuple_to_five (stream->four_tuple, five_tuple); + ret = fwrite (five_tuple, stream->base85_pending+1, 1, logfile); + (void) ret; + } +} + +static void +_write_data_end (struct _data_stream *stream) +{ + _write_zlib_data_end (stream); + _write_base85_data_end (stream); + + _trace_printf ("~>"); +} + +static void +_emit_data (const void *data, unsigned int length) +{ + struct _data_stream stream; + + _write_data_start (&stream, length); + _write_data (&stream, data, length); + _write_data_end (&stream); +} + +static const char * +_format_to_string (cairo_format_t format) +{ +#define f(name) case CAIRO_FORMAT_ ## name: return #name + switch (format) { + f(INVALID); + f(RGBA128F); + f(RGB96F); + f(ARGB32); + f(RGB30); + f(RGB24); + f(RGB16_565); + f(A8); + f(A1); + } +#undef f + return "UNKNOWN_FORMAT"; +} + +static const char * +_format_to_content_string (cairo_format_t format) +{ + switch (format) { + case CAIRO_FORMAT_INVALID: + return "INVALID"; + case CAIRO_FORMAT_RGBA128F: + case CAIRO_FORMAT_ARGB32: + return "COLOR_ALPHA"; + case CAIRO_FORMAT_RGB96F: + case CAIRO_FORMAT_RGB30: + case CAIRO_FORMAT_RGB24: + case CAIRO_FORMAT_RGB16_565: + return "COLOR"; + case CAIRO_FORMAT_A8: + case CAIRO_FORMAT_A1: + return "ALPHA"; + } + return "UNKNOWN"; +} + +static const char * +_status_to_string (cairo_status_t status) +{ +#define f(name) case CAIRO_STATUS_ ## name: return "STATUS_" #name + switch (status) { + f(SUCCESS); + f(NO_MEMORY); + f(INVALID_RESTORE); + f(INVALID_POP_GROUP); + f(NO_CURRENT_POINT); + f(INVALID_MATRIX); + f(INVALID_STATUS); + f(NULL_POINTER); + f(INVALID_STRING); + f(INVALID_PATH_DATA); + f(READ_ERROR); + f(WRITE_ERROR); + f(SURFACE_FINISHED); + f(SURFACE_TYPE_MISMATCH); + f(PATTERN_TYPE_MISMATCH); + f(INVALID_CONTENT); + f(INVALID_FORMAT); + f(INVALID_VISUAL); + f(FILE_NOT_FOUND); + f(INVALID_DASH); + f(INVALID_DSC_COMMENT); + f(INVALID_INDEX); + f(CLIP_NOT_REPRESENTABLE); + f(TEMP_FILE_ERROR); + f(INVALID_STRIDE); + f(FONT_TYPE_MISMATCH); + f(USER_FONT_IMMUTABLE); + f(USER_FONT_ERROR); + f(NEGATIVE_COUNT); + f(INVALID_CLUSTERS); + f(INVALID_SLANT); + f(INVALID_WEIGHT); + f(INVALID_SIZE); + f(USER_FONT_NOT_IMPLEMENTED); + f(DEVICE_TYPE_MISMATCH); + f(DEVICE_ERROR); + f(INVALID_MESH_CONSTRUCTION); + f(DEVICE_FINISHED); + f(JBIG2_GLOBAL_MISSING); + f(PNG_ERROR); + f(FREETYPE_ERROR); + f(WIN32_GDI_ERROR); + f(TAG_ERROR); + f(DWRITE_ERROR); + f(SVG_FONT_ERROR); + case CAIRO_STATUS_LAST_STATUS: + break; + } + return "UNKNOWN_STATUS"; +#undef f +} + +static void CAIRO_PRINTF_FORMAT(2, 3) +_emit_image (cairo_surface_t *image, + const char *info, + ...) +{ + int stride, row, width, height; + uint32_t len; + cairo_format_t format; + uint8_t row_stack[BUFFER_SIZE]; + uint8_t *rowdata; + uint8_t *data; + struct _data_stream stream; + cairo_status_t status; + + status = DLCALL (cairo_surface_status, image); + if (status) { + _trace_printf ("<< /status //%s >> image", + _status_to_string (status)); + return; + } + + width = DLCALL (cairo_image_surface_get_width, image); + height = DLCALL (cairo_image_surface_get_height, image); + stride = DLCALL (cairo_image_surface_get_stride, image); + format = DLCALL (cairo_image_surface_get_format, image); + data = DLCALL (cairo_image_surface_get_data, image); + + _trace_printf ("dict\n" + " /width %d set\n" + " /height %d set\n" + " /format //%s set\n", + width, height, + _format_to_string (format)); + if (info != NULL) { + va_list ap; + + va_start (ap, info); + _trace_vprintf (info, ap); + va_end (ap); + } + + if (DLCALL (cairo_version) >= CAIRO_VERSION_ENCODE (1, 9, 0)) { + const char *mime_types[] = { + CAIRO_MIME_TYPE_JPEG, + CAIRO_MIME_TYPE_JP2, + CAIRO_MIME_TYPE_PNG, + NULL + }, **mime_type; + + for (mime_type = mime_types; *mime_type; mime_type++) { + const unsigned char *mime_data; + unsigned long mime_length; + + DLCALL (cairo_surface_get_mime_data, + image, *mime_type, &mime_data, &mime_length); + if (mime_data != NULL) { + _trace_printf (" /mime-type (%s) set\n" + " /source <~", + *mime_type); + _write_base85_data_start (&stream); + _write_base85_data (&stream, mime_data, mime_length); + _write_base85_data_end (&stream); + _trace_printf ("~> set\n" + " image"); + return; + } + } + } + + switch (format) { + case CAIRO_FORMAT_A1: len = (width + 7)/8; break; + case CAIRO_FORMAT_A8: len = width; break; + case CAIRO_FORMAT_RGB16_565: len = 2*width; break; + case CAIRO_FORMAT_RGB24: len = 3*width; break; + default: + case CAIRO_FORMAT_RGB30: + case CAIRO_FORMAT_INVALID: + case CAIRO_FORMAT_ARGB32: len = 4*width; break; + case CAIRO_FORMAT_RGB96F: len = 12*width; break; + case CAIRO_FORMAT_RGBA128F: len = 16*width; break; + } + + _trace_printf (" /source "); + _write_data_start (&stream, len * height); + +#ifdef WORDS_BIGENDIAN + switch (format) { + case CAIRO_FORMAT_RGB24: + for (row = height; row--; ) { + int col; + rowdata = data; + for (col = width; col--; ) { + _write_data (&stream, rowdata, 3); + rowdata+=4; + } + data += stride; + } + break; + case CAIRO_FORMAT_A1: + case CAIRO_FORMAT_A8: + case CAIRO_FORMAT_RGB16_565: + case CAIRO_FORMAT_RGB30: + case CAIRO_FORMAT_ARGB32: + case CAIRO_FORMAT_RGB96F: + case CAIRO_FORMAT_RGBA128F: + for (row = height; row--; ) { + _write_data (&stream, data, len); + data += stride; + } + break; + case CAIRO_FORMAT_INVALID: + default: + break; + } +#else + if (stride > ARRAY_LENGTH (row_stack)) { + rowdata = malloc (stride); + if (rowdata == NULL) + goto BAIL; + } else + rowdata = row_stack; + + switch (format) { + case CAIRO_FORMAT_A1: + for (row = height; row--; ) { + int col; + for (col = 0; col < (width + 7)/8; col++) + rowdata[col] = CAIRO_BITSWAP8 (data[col]); + _write_data (&stream, rowdata, (width+7)/8); + data += stride; + } + break; + case CAIRO_FORMAT_A8: + for (row = height; row--; ) { + _write_data (&stream, data, width); + data += stride; + } + break; + case CAIRO_FORMAT_RGB16_565: /* XXX endianness */ + for (row = height; row--; ) { + uint16_t *src = (uint16_t *) data; + uint16_t *dst = (uint16_t *)rowdata; + int col; + for (col = 0; col < width; col++) + dst[col] = bswap_16 (src[col]); + _write_data (&stream, rowdata, 2*width); + data += stride; + } + break; + case CAIRO_FORMAT_RGB24: + for (row = height; row--; ) { + uint8_t *src = data; + int col; + for (col = 0; col < width; col++) { + rowdata[3*col+2] = *src++; + rowdata[3*col+1] = *src++; + rowdata[3*col+0] = *src++; + src++; + } + _write_data (&stream, rowdata, 3*width); + data += stride; + } + break; + case CAIRO_FORMAT_RGB96F: + case CAIRO_FORMAT_RGBA128F: + case CAIRO_FORMAT_RGB30: + case CAIRO_FORMAT_ARGB32: + for (row = height; row--; ) { + uint32_t *src = (uint32_t *) data; + uint32_t *dst = (uint32_t *) rowdata; + int col; + for (col = 0; col < width; col++) + dst[col] = bswap_32 (src[col]); + _write_data (&stream, rowdata, len); + data += stride; + } + break; + case CAIRO_FORMAT_INVALID: + default: + break; + } + if (rowdata != row_stack) + free (rowdata); + +BAIL: + _write_data_end (&stream); +#endif + _trace_printf (" set\n image"); +} + +static void +_encode_string_literal (char *out, int max, + const char *utf8, int len) +{ + char c; + const char *end; + + *out++ = '('; + max--; + + if (utf8 == NULL) + goto DONE; + + if (len < 0) + len = strlen (utf8); + end = utf8 + len; + + while (utf8 < end) { + if (max < 5) + break; + + switch ((c = *utf8++)) { + case '\n': + *out++ = '\\'; + *out++ = 'n'; + max -= 2; + break; + case '\r': + *out++ = '\\'; + *out++ = 'r'; + max -= 2; + break; + case '\t': + *out++ = '\\'; + *out++ = 't'; + max -= 2; + break; + case '\b': + *out++ = '\\'; + *out++ = 'b'; + max -= 2; + break; + case '\f': + *out++ = '\\'; + *out++ = 'f'; + max -= 2; + break; + case '\\': + case '(': + case ')': + *out++ = '\\'; + *out++ = c; + max -= 2; + break; + default: + if (_cairo_isprint (c)) { + *out++ = c; + } else { + int octal = 0; + while (c) { + octal *= 10; + octal += c&7; + c /= 8; + } + octal = snprintf (out, max, "\\%03d", octal); + out += octal; + max -= octal; + } + break; + } + } +DONE: + *out++ = ')'; + *out = '\0'; +} + +static void +to_octal (int value, char *buf, size_t size) +{ + do { + buf[--size] = '0' + (value & 7); + value >>= 3; + } while (size); +} + +static void +_emit_string_literal (const char *utf8, int len) +{ + char c; + const char *end; + + if (utf8 == NULL) { + _trace_printf ("()"); + return; + } + + if (len < 0) + len = strlen (utf8); + end = utf8 + len; + + _trace_printf ("("); + while (utf8 < end) { + switch ((c = *utf8++)) { + case '\n': + c = 'n'; + goto ESCAPED_CHAR; + case '\r': + c = 'r'; + goto ESCAPED_CHAR; + case '\t': + c = 't'; + goto ESCAPED_CHAR; + case '\b': + c = 'b'; + goto ESCAPED_CHAR; + case '\f': + c = 'f'; + goto ESCAPED_CHAR; + case '\\': + case '(': + case ')': +ESCAPED_CHAR: + _trace_printf ("\\%c", c); + break; + default: + if (_cairo_isprint (c)) { + _trace_printf ("%c", c); + } else { + char buf[4] = { '\\' }; + int ret_ignored; + + to_octal (c, buf+1, 3); + ret_ignored = fwrite (buf, 4, 1, logfile); + (void)ret_ignored; + } + break; + } + } + _trace_printf (")"); +} + +static void +_emit_current (Object *obj) +{ + if (obj != NULL && ! _pop_operands_to_object (obj)) { + if (obj->operand != -1) { + int n; + + _trace_printf ("%d -1 roll %% %s%ld\n", + current_stack_depth - obj->operand, + obj->type->op_code, obj->token); + + for (n = obj->operand; n < current_stack_depth - 1; n++) { + current_object[n] = current_object[n+1]; + current_object[n]->operand = n; + } + obj->operand = -1; + current_stack_depth--; + } else { + assert(obj->defined); + _trace_printf ("%s%ld\n", obj->type->op_code, obj->token); + } + + _push_object (obj); + dump_stack(__func__); + } +} + +static void +_emit_context (cairo_t *cr) +{ + _emit_current (_get_object (CONTEXT, cr)); +} + +static void +_emit_pattern (cairo_pattern_t *pattern) +{ + _emit_current (_get_object (PATTERN, pattern)); +} + +static void +_emit_surface (cairo_surface_t *surface) +{ + _emit_current (_get_object (SURFACE, surface)); +} + +static void CAIRO_PRINTF_FORMAT(2, 3) +_emit_cairo_op (cairo_t *cr, const char *fmt, ...) +{ + va_list ap; + + if (cr == NULL || ! _write_lock ()) + return; + + _emit_context (cr); + + va_start (ap, fmt); + _trace_vprintf ( fmt, ap); + va_end (ap); + + _write_unlock (); +} + +cairo_t * +cairo_create (cairo_surface_t *target) +{ + cairo_t *ret; + long surface_id; + long context_id; + + _enter_trace (); + + ret = DLCALL (cairo_create, target); + context_id = _create_context_id (ret); + + _emit_line_info (); + if (target != NULL && _write_lock ()) { + surface_id = _get_surface_id (target); + if (surface_id != -1) { + _get_object (SURFACE, target)->foreign = FALSE; + + /* we presume that we will continue to use the context */ + if (_pop_operands_to (SURFACE, target)){ + _consume_operand (false); + } else { + _trace_printf ("s%ld ", surface_id); + } + _trace_printf ("context %% c%ld\n", context_id); + _push_operand (CONTEXT, ret); + dump_stack(__func__); + } + _write_unlock (); + } + + _exit_trace (); + return ret; +} + +void +cairo_save (cairo_t *cr) +{ + _enter_trace (); + _emit_line_info (); + _emit_cairo_op (cr, "save\n"); + DLCALL (cairo_save, cr); + _exit_trace (); +} + +void +cairo_restore (cairo_t *cr) +{ + _enter_trace (); + _emit_line_info (); + _emit_cairo_op (cr, "restore\n"); + DLCALL (cairo_restore, cr); + _exit_trace (); +} + +void +cairo_push_group (cairo_t *cr) +{ + _enter_trace (); + _emit_line_info (); + _emit_cairo_op (cr, "//COLOR_ALPHA push-group\n"); + DLCALL (cairo_push_group, cr); + _exit_trace (); +} + +static const char * +_content_to_string (cairo_content_t content) +{ + switch (content) { + case CAIRO_CONTENT_ALPHA: return "ALPHA"; + case CAIRO_CONTENT_COLOR: return "COLOR"; + default: + case CAIRO_CONTENT_COLOR_ALPHA: return "COLOR_ALPHA"; + } +} + +void +cairo_push_group_with_content (cairo_t *cr, cairo_content_t content) +{ + _enter_trace (); + _emit_line_info (); + _emit_cairo_op (cr, "//%s push-group\n", _content_to_string (content)); + DLCALL (cairo_push_group_with_content, cr, content); + _exit_trace (); +} + +cairo_pattern_t * +cairo_pop_group (cairo_t *cr) +{ + cairo_pattern_t *ret; + + _enter_trace (); + + ret = DLCALL (cairo_pop_group, cr); + + _emit_line_info (); + _emit_cairo_op (cr, "pop-group %% p%ld\n", _create_pattern_id (ret)); + _push_operand (PATTERN, ret); + dump_stack(__func__); + + _exit_trace (); + return ret; +} + +void +cairo_pop_group_to_source (cairo_t *cr) +{ + _enter_trace (); + _emit_line_info (); + _emit_cairo_op (cr, "pop-group set-source\n"); + DLCALL (cairo_pop_group_to_source, cr); + _exit_trace (); +} + +static const char * +_operator_to_string (cairo_operator_t op) +{ +#define f(name) case CAIRO_OPERATOR_ ## name: return #name + switch (op) { + f(OVER); + f(SOURCE); + f(CLEAR); + f(IN); + f(OUT); + f(ATOP); + f(DEST); + f(DEST_OVER); + f(DEST_IN); + f(DEST_OUT); + f(DEST_ATOP); + f(XOR); + f(ADD); + f(SATURATE); + f(MULTIPLY); + f(SCREEN); + f(OVERLAY); + f(DARKEN); + f(LIGHTEN); + case CAIRO_OPERATOR_COLOR_DODGE: return "DODGE"; + case CAIRO_OPERATOR_COLOR_BURN: return "BURN"; + f(HARD_LIGHT); + f(SOFT_LIGHT); + f(DIFFERENCE); + f(EXCLUSION); + f(HSL_HUE); + f(HSL_SATURATION); + f(HSL_COLOR); + f(HSL_LUMINOSITY); + } +#undef f + return "UNKNOWN_OPERATOR"; +} + +void +cairo_set_operator (cairo_t *cr, cairo_operator_t op) +{ + _enter_trace (); + _emit_line_info (); + _emit_cairo_op (cr, "//%s set-operator\n", _operator_to_string (op)); + DLCALL (cairo_set_operator, cr, op); + _exit_trace (); +} + +void +cairo_set_source_rgb (cairo_t *cr, double red, double green, double blue) +{ + _enter_trace (); + _emit_line_info (); + _emit_cairo_op (cr, "%g %g %g set-source-rgb\n", red, green, blue); + DLCALL (cairo_set_source_rgb, cr, red, green, blue); + _exit_trace (); +} + +void +cairo_set_source_rgba (cairo_t *cr, double red, double green, double blue, double alpha) +{ + _enter_trace (); + _emit_line_info (); + _emit_cairo_op (cr, "%g %g %g %g set-source-rgba\n", + red, green, blue, alpha); + DLCALL (cairo_set_source_rgba, cr, red, green, blue, alpha); + _exit_trace (); +} + +static void +_emit_source_image (cairo_surface_t *surface) +{ + Object *obj; + cairo_surface_t *image; + cairo_t *cr; + + obj = _get_object (SURFACE, surface); + if (obj == NULL) + return; + + image = DLCALL (cairo_image_surface_create, + CAIRO_FORMAT_ARGB32, + obj->width, + obj->height); + cr = DLCALL (cairo_create, image); + DLCALL (cairo_set_source_surface, cr, surface, 0, 0); + DLCALL (cairo_paint, cr); + DLCALL (cairo_destroy, cr); + + _emit_image (image, NULL); + _trace_printf (" set-source-image "); + DLCALL (cairo_surface_destroy, image); + + obj->foreign = FALSE; +} + +static void +_emit_source_image_rectangle (cairo_surface_t *surface, + int x, int y, + int width, int height) +{ + Object *obj; + cairo_surface_t *image; + cairo_t *cr; + + obj = _get_object (SURFACE, surface); + if (obj == NULL) + return; + + if (obj->foreign) { + _emit_source_image (surface); + return; + } + + image = DLCALL (cairo_image_surface_create, + CAIRO_FORMAT_ARGB32, + width, + height); + cr = DLCALL (cairo_create, image); + DLCALL (cairo_set_source_surface, cr, surface, x, y); + DLCALL (cairo_paint, cr); + DLCALL (cairo_destroy, cr); + + _emit_image (image, NULL); + _trace_printf (" %d %d set-device-offset set-source-image ", + x, y); + DLCALL (cairo_surface_destroy, image); +} + +void +cairo_set_source_surface (cairo_t *cr, cairo_surface_t *surface, double x, double y) +{ + _enter_trace (); + _emit_line_info (); + if (cr != NULL && surface != NULL && _write_lock ()) { + Object *obj = _get_object (SURFACE, surface); + + if (_is_current (SURFACE, surface, 0) && + _is_current (CONTEXT, cr, 1)) + { + _consume_operand (false); + } + else if (_is_current (SURFACE, surface, 1) && + _is_current (CONTEXT, cr, 0) && + obj->defined) + { + _trace_printf ("exch "); + _exch_operands (); + _consume_operand (false); + } else if (obj->defined) { + _emit_context (cr); + _trace_printf ("s%ld ", obj->token); + } else { + _emit_context (cr); + _trace_printf ("%d index ", + current_stack_depth - obj->operand - 1); + } + + if (obj->foreign) + _emit_source_image (surface); + + _trace_printf ("pattern"); + if (x != 0. || y != 0.) + _trace_printf (" %g %g translate", -x, -y); + + _trace_printf (" set-source\n"); + _write_unlock (); + } + + DLCALL (cairo_set_source_surface, cr, surface, x, y); + _exit_trace (); +} + +void +cairo_set_source (cairo_t *cr, cairo_pattern_t *source) +{ + _enter_trace (); + _emit_line_info (); + if (cr != NULL && source != NULL && _write_lock ()) { + Object *obj = _get_object (PATTERN, source); + cairo_bool_t need_context_and_pattern = TRUE; + + if (_is_current (PATTERN, source, 0) && + _is_current (CONTEXT, cr, 1)) + { + if (obj->defined) { + _consume_operand (false); + } else { + _trace_printf ("exch 1 index "); + _exch_operands (); + } + need_context_and_pattern = FALSE; + } + else if (_is_current (PATTERN, source, 1) && + _is_current (CONTEXT, cr, 0)) + { + if (obj->defined) { + _trace_printf ("exch "); + _exch_operands (); + _consume_operand (false); + need_context_and_pattern = FALSE; + } + } + + if (need_context_and_pattern) { + _emit_context (cr); + _emit_pattern_id (source); + } + + _trace_printf ("set-source %% p%ld\n", obj->token); + _write_unlock (); + } + + DLCALL (cairo_set_source, cr, source); + _exit_trace (); +} + +cairo_pattern_t * +cairo_get_source (cairo_t *cr) +{ + cairo_pattern_t *ret; + + _enter_trace (); + + ret = DLCALL (cairo_get_source, cr); + + if (! _has_pattern_id (ret)) { + _emit_cairo_op (cr, "/source get /p%ld exch def\n", + _create_pattern_id (ret)); + _get_object (PATTERN, ret)->defined = TRUE; + } + + _exit_trace (); + return ret; +} + +void +cairo_set_tolerance (cairo_t *cr, double tolerance) +{ + _enter_trace (); + _emit_line_info (); + _emit_cairo_op (cr, "%g set-tolerance\n", tolerance); + DLCALL (cairo_set_tolerance, cr, tolerance); + _exit_trace (); +} + +static const char * +_antialias_to_string (cairo_antialias_t antialias) +{ +#define f(name) case CAIRO_ANTIALIAS_ ## name: return "ANTIALIAS_" #name + switch (antialias) { + f(DEFAULT); + + f(NONE); + f(GRAY); + f(SUBPIXEL); + + f(FAST); + f(GOOD); + f(BEST); + }; +#undef f + return "UNKNOWN_ANTIALIAS"; +} + +void +cairo_set_antialias (cairo_t *cr, cairo_antialias_t antialias) +{ + _enter_trace (); + _emit_line_info (); + _emit_cairo_op (cr, + "//%s set-antialias\n", _antialias_to_string (antialias)); + DLCALL (cairo_set_antialias, cr, antialias); + _exit_trace (); +} + +static const char * +_fill_rule_to_string (cairo_fill_rule_t rule) +{ +#define f(name) case CAIRO_FILL_RULE_ ## name: return #name + switch (rule) { + f(WINDING); + f(EVEN_ODD); + }; +#undef f + return "UNKNOWN_FILL_RULE"; +} + +void +cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule) +{ + _enter_trace (); + _emit_line_info (); + _emit_cairo_op (cr, + "//%s set-fill-rule\n", _fill_rule_to_string (fill_rule)); + DLCALL (cairo_set_fill_rule, cr, fill_rule); + _exit_trace (); +} + +void +cairo_set_line_width (cairo_t *cr, double width) +{ + _enter_trace (); + _emit_line_info (); + _emit_cairo_op (cr, "%g set-line-width\n", width); + DLCALL (cairo_set_line_width, cr, width); + _exit_trace (); +} + +static const char * +_line_cap_to_string (cairo_line_cap_t line_cap) +{ +#define f(name) case CAIRO_LINE_CAP_ ## name: return "LINE_CAP_" #name + switch (line_cap) { + f(BUTT); + f(ROUND); + f(SQUARE); + }; +#undef f + return "UNKNOWN_LINE_CAP"; +} + +void +cairo_set_line_cap (cairo_t *cr, cairo_line_cap_t line_cap) +{ + _enter_trace (); + _emit_line_info (); + _emit_cairo_op (cr, "//%s set-line-cap\n", _line_cap_to_string (line_cap)); + DLCALL (cairo_set_line_cap, cr, line_cap); + _exit_trace (); +} + +static const char * +_line_join_to_string (cairo_line_join_t line_join) +{ +#define f(name) case CAIRO_LINE_JOIN_ ## name: return "LINE_JOIN_" #name + switch (line_join) { + f(MITER); + f(ROUND); + f(BEVEL); + }; +#undef f + return "UNKNOWN_LINE_JOIN"; +} + +void +cairo_set_line_join (cairo_t *cr, cairo_line_join_t line_join) +{ + _enter_trace (); + _emit_line_info (); + _emit_cairo_op (cr, + "//%s set-line-join\n", _line_join_to_string (line_join)); + DLCALL (cairo_set_line_join, cr, line_join); + _exit_trace (); +} + +void +cairo_set_dash (cairo_t *cr, const double *dashes, int num_dashes, double offset) +{ + _enter_trace (); + _emit_line_info (); + if (cr != NULL && _write_lock ()) { + int n; + + _emit_context (cr); + + _trace_printf ("["); + for (n = 0; n < num_dashes; n++) { + if (n != 0) + _trace_printf (" "); + _trace_printf ("%g", dashes[n]); + } + _trace_printf ("] %g set-dash\n", offset); + + _write_unlock (); + } + + DLCALL (cairo_set_dash, cr, dashes, num_dashes, offset); + _exit_trace (); +} + +void +cairo_set_miter_limit (cairo_t *cr, double limit) +{ + _enter_trace (); + _emit_line_info (); + _emit_cairo_op (cr, "%g set-miter-limit\n", limit); + DLCALL (cairo_set_miter_limit, cr, limit); + _exit_trace (); +} + +void +cairo_translate (cairo_t *cr, double tx, double ty) +{ + _enter_trace (); + _emit_line_info (); + _emit_cairo_op (cr, "%g %g translate\n", tx, ty); + DLCALL (cairo_translate, cr, tx, ty); + _exit_trace (); +} + +void +cairo_scale (cairo_t *cr, double sx, double sy) +{ + _enter_trace (); + _emit_line_info (); + _emit_cairo_op (cr, "%g %g scale\n", sx, sy); + DLCALL (cairo_scale, cr, sx, sy); + _exit_trace (); +} + +void +cairo_rotate (cairo_t *cr, double angle) +{ + _enter_trace (); + _emit_line_info (); + _emit_cairo_op (cr, "%g rotate\n", angle); + DLCALL (cairo_rotate, cr, angle); + _exit_trace (); +} + +void +cairo_transform (cairo_t *cr, const cairo_matrix_t *matrix) +{ + _enter_trace (); + _emit_line_info (); + _emit_cairo_op (cr, "%g %g %g %g %g %g matrix transform\n", + matrix->xx, matrix->yx, + matrix->xy, matrix->yy, + matrix->x0, matrix->y0); + DLCALL (cairo_transform, cr, matrix); + _exit_trace (); +} + +void +cairo_set_matrix (cairo_t *cr, const cairo_matrix_t *matrix) +{ + _enter_trace (); + _emit_line_info (); + if (_matrix_is_identity (matrix)) { + _emit_cairo_op (cr, "identity set-matrix\n"); + } else { + _emit_cairo_op (cr, "%g %g %g %g %g %g matrix set-matrix\n", + matrix->xx, matrix->yx, + matrix->xy, matrix->yy, + matrix->x0, matrix->y0); + } + DLCALL (cairo_set_matrix, cr, matrix); + _exit_trace (); +} + +cairo_surface_t * +cairo_get_target (cairo_t *cr) +{ + cairo_surface_t *ret; + + _enter_trace (); + + ret = DLCALL (cairo_get_target, cr); + if (cr != NULL) { + Object *obj = _create_surface (ret); + + if (! obj->defined) { + _emit_cairo_op (cr, + "/target get /s%ld exch def\n", + obj->token); + obj->defined = TRUE; + } + } + + _exit_trace (); + return ret; +} + +cairo_surface_t * +cairo_get_group_target (cairo_t *cr) +{ + cairo_surface_t *ret; + + _enter_trace (); + + ret = DLCALL (cairo_get_group_target, cr); + if (cr != NULL) { + Object *obj = _create_surface (ret); + + if (! obj->defined) { + _emit_cairo_op (cr, + "/group-target get /s%ld exch def\n", + obj->token); + obj->defined = TRUE; + } + } + + _exit_trace (); + return ret; +} + +void +cairo_identity_matrix (cairo_t *cr) +{ + _enter_trace (); + _emit_line_info (); + _emit_cairo_op (cr, "identity set-matrix\n"); + DLCALL (cairo_identity_matrix, cr); + _exit_trace (); +} + +void +cairo_new_path (cairo_t *cr) +{ + _enter_trace (); + _emit_line_info (); + _emit_cairo_op (cr, "n "); + DLCALL (cairo_new_path, cr); + _exit_trace (); +} + +void +cairo_move_to (cairo_t *cr, double x, double y) +{ + _enter_trace (); + _emit_cairo_op (cr, "%g %g m ", x, y); + DLCALL (cairo_move_to, cr, x, y); + _exit_trace (); +} + +void +cairo_new_sub_path (cairo_t *cr) +{ + _enter_trace (); + _emit_cairo_op (cr, "N "); + DLCALL (cairo_new_sub_path, cr); + _exit_trace (); +} + +void +cairo_line_to (cairo_t *cr, double x, double y) +{ + _enter_trace (); + _emit_cairo_op (cr, "%g %g l ", x, y); + DLCALL (cairo_line_to, cr, x, y); + _exit_trace (); +} + +void +cairo_curve_to (cairo_t *cr, double x1, double y1, double x2, double y2, double x3, double y3) +{ + _enter_trace (); + _emit_cairo_op (cr, "%g %g %g %g %g %g c ", x1, y1, x2, y2, x3, y3); + DLCALL (cairo_curve_to, cr, x1, y1, x2, y2, x3, y3); + _exit_trace (); +} + +void +cairo_arc (cairo_t *cr, double xc, double yc, double radius, double angle1, double angle2) +{ + _enter_trace (); + _emit_cairo_op (cr, "%g %g %g %g %g arc\n", xc, yc, radius, angle1, angle2); + DLCALL (cairo_arc, cr, xc, yc, radius, angle1, angle2); + _exit_trace (); +} + +void +cairo_arc_negative (cairo_t *cr, double xc, double yc, double radius, double angle1, double angle2) +{ + _enter_trace (); + _emit_cairo_op (cr, "%g %g %g %g %g arc-\n", + xc, yc, radius, angle1, angle2); + DLCALL (cairo_arc_negative, cr, xc, yc, radius, angle1, angle2); + _exit_trace (); +} + +void +cairo_rel_move_to (cairo_t *cr, double dx, double dy) +{ + _enter_trace (); + _emit_cairo_op (cr, "%g %g M ", dx, dy); + DLCALL (cairo_rel_move_to, cr, dx, dy); + _exit_trace (); +} + +void +cairo_rel_line_to (cairo_t *cr, double dx, double dy) +{ + _enter_trace (); + _emit_cairo_op (cr, "%g %g L ", dx, dy); + DLCALL (cairo_rel_line_to, cr, dx, dy); + _exit_trace (); +} + +void +cairo_rel_curve_to (cairo_t *cr, double dx1, double dy1, double dx2, double dy2, double dx3, double dy3) +{ + _enter_trace (); + _emit_cairo_op (cr, "%g %g %g %g %g %g C ", + dx1, dy1, dx2, dy2, dx3, dy3); + DLCALL (cairo_rel_curve_to, cr, dx1, dy1, dx2, dy2, dx3, dy3); + _exit_trace (); +} + +void +cairo_rectangle (cairo_t *cr, double x, double y, double width, double height) +{ + _enter_trace (); + _emit_cairo_op (cr, "%g %g %g %g rectangle\n", x, y, width, height); + DLCALL (cairo_rectangle, cr, x, y, width, height); + _exit_trace (); +} + +void +cairo_close_path (cairo_t *cr) +{ + _enter_trace (); + _emit_cairo_op (cr, "h\n"); + DLCALL (cairo_close_path, cr); + _exit_trace (); +} + +void +cairo_paint (cairo_t *cr) +{ + _enter_trace (); + _emit_line_info (); + _emit_cairo_op (cr, "paint\n"); + DLCALL (cairo_paint, cr); + _exit_trace (); +} + +void +cairo_paint_with_alpha (cairo_t *cr, double alpha) +{ + _enter_trace (); + _emit_line_info (); + _emit_cairo_op (cr, "%g paint-with-alpha\n", alpha); + DLCALL (cairo_paint_with_alpha, cr, alpha); + _exit_trace (); +} + +void +cairo_mask (cairo_t *cr, cairo_pattern_t *pattern) +{ + _enter_trace (); + _emit_line_info (); + if (cr != NULL && pattern != NULL && _write_lock ()) { + Object *obj = _get_object (PATTERN, pattern); + cairo_bool_t need_context_and_pattern = TRUE; + + if (_is_current (PATTERN, pattern, 0) && + _is_current (CONTEXT, cr, 1)) + { + if (obj->defined) { + _consume_operand (false); + need_context_and_pattern = FALSE; + } + } + else if (_is_current (PATTERN, pattern, 1) && + _is_current (CONTEXT, cr, 0)) + { + if (obj->defined) { + _trace_printf ("exch "); + _exch_operands (); + _consume_operand (false); + need_context_and_pattern = FALSE; + } + } + + if (need_context_and_pattern) { + _emit_context (cr); + _emit_pattern_id (pattern); + } + + _trace_printf (" mask\n"); + _write_unlock (); + } + DLCALL (cairo_mask, cr, pattern); + _exit_trace (); +} + +void +cairo_mask_surface (cairo_t *cr, cairo_surface_t *surface, double x, double y) +{ + _enter_trace (); + _emit_line_info (); + if (cr != NULL && surface != NULL && _write_lock ()) { + Object *obj = _get_object (SURFACE, surface); + if (_is_current (SURFACE, surface, 0) && + _is_current (CONTEXT, cr, 1)) + { + _consume_operand (false); + } + else if (_is_current (SURFACE, surface, 1) && + _is_current (CONTEXT, cr, 0)) + { + _trace_printf ("exch "); + _exch_operands (); + _consume_operand (false); + } else if (obj->defined){ + _emit_context (cr); + _trace_printf ("s%ld ", obj->token); + } else { + _emit_context (cr); + _trace_printf ("%d index ", + current_stack_depth - obj->operand - 1); + } + _trace_printf ("pattern"); + + if (x != 0. || y != 0.) + _trace_printf (" %g %g translate", -x, -y); + + _trace_printf (" mask\n"); + _write_unlock (); + } + + DLCALL (cairo_mask_surface, cr, surface, x, y); + _exit_trace (); +} + +void +cairo_stroke (cairo_t *cr) +{ + _enter_trace (); + _emit_line_info (); + _emit_cairo_op (cr, "stroke\n"); + DLCALL (cairo_stroke, cr); + _exit_trace (); +} + +void +cairo_stroke_preserve (cairo_t *cr) +{ + _enter_trace (); + _emit_line_info (); + _emit_cairo_op (cr, "stroke+\n"); + DLCALL (cairo_stroke_preserve, cr); + _exit_trace (); +} + +void +cairo_fill (cairo_t *cr) +{ + _enter_trace (); + _emit_line_info (); + _emit_cairo_op (cr, "fill\n"); + DLCALL (cairo_fill, cr); + _exit_trace (); +} + +void +cairo_fill_preserve (cairo_t *cr) +{ + _enter_trace (); + _emit_line_info (); + _emit_cairo_op (cr, "fill+\n"); + DLCALL (cairo_fill_preserve, cr); + _exit_trace (); +} + +void +cairo_copy_page (cairo_t *cr) +{ + _enter_trace (); + _emit_line_info (); + _emit_cairo_op (cr, "copy-page\n"); + DLCALL (cairo_copy_page, cr); + _exit_trace (); +} + +void +cairo_show_page (cairo_t *cr) +{ + _enter_trace (); + _emit_line_info (); + _emit_cairo_op (cr, "show-page\n"); + DLCALL (cairo_show_page, cr); + _exit_trace (); +} + +void +cairo_clip (cairo_t *cr) +{ + _enter_trace (); + _emit_line_info (); + _emit_cairo_op (cr, "clip\n"); + DLCALL (cairo_clip, cr); + _exit_trace (); +} + +void +cairo_clip_preserve (cairo_t *cr) +{ + _enter_trace (); + _emit_line_info (); + _emit_cairo_op (cr, "clip+\n"); + DLCALL (cairo_clip_preserve, cr); + _exit_trace (); +} + +void +cairo_reset_clip (cairo_t *cr) +{ + _enter_trace (); + _emit_line_info (); + _emit_cairo_op (cr, "reset-clip\n"); + DLCALL (cairo_reset_clip, cr); + _exit_trace (); +} + + +static const char * +_slant_to_string (cairo_font_slant_t font_slant) +{ +#define f(name) case CAIRO_FONT_SLANT_ ## name: return "SLANT_" #name + switch (font_slant) { + f(NORMAL); + f(ITALIC); + f(OBLIQUE); + }; +#undef f + return "UNKNOWN_SLANT"; +} + +static const char * +_weight_to_string (cairo_font_weight_t font_weight) +{ +#define f(name) case CAIRO_FONT_WEIGHT_ ## name: return "WEIGHT_" #name + switch (font_weight) { + f(NORMAL); + f(BOLD); + }; +#undef f + return "UNKNOWN_WEIGHT"; +} + +void +cairo_select_font_face (cairo_t *cr, const char *family, cairo_font_slant_t slant, cairo_font_weight_t weight) +{ + _enter_trace (); + _emit_line_info (); + if (cr != NULL && _write_lock ()) { + _emit_context (cr); + _emit_string_literal (family, -1); + _trace_printf (" //%s //%s select-font-face\n", + _slant_to_string (slant), + _weight_to_string (weight)); + _write_unlock (); + } + DLCALL (cairo_select_font_face, cr, family, slant, weight); + _exit_trace (); +} + +cairo_font_face_t * +cairo_get_font_face (cairo_t *cr) +{ + cairo_font_face_t *ret; + long font_face_id; + + _enter_trace (); + + ret = DLCALL (cairo_get_font_face, cr); + font_face_id = _create_font_face_id (ret); + + _emit_cairo_op (cr, "/font-face get %% f%ld\n", font_face_id); + _push_operand (FONT_FACE, ret); + dump_stack(__func__); + + _exit_trace (); + return ret; +} + +void +cairo_set_font_face (cairo_t *cr, cairo_font_face_t *font_face) +{ + _enter_trace (); + _emit_line_info (); + if (cr != NULL && font_face != NULL && _write_lock ()) { + if (_is_current (FONT_FACE, font_face, 0) && + _is_current (CONTEXT, cr, 1)) + { + _consume_operand (false); + } + else if (_is_current (FONT_FACE, font_face, 1) && + _is_current (CONTEXT, cr, 0)) + { + _trace_printf ("exch "); + _exch_operands (); + _consume_operand (false); + } + else + { + _emit_context (cr); + _emit_font_face_id (font_face); + } + + _trace_printf ("set-font-face\n"); + _write_unlock (); + } + + DLCALL (cairo_set_font_face, cr, font_face); + _exit_trace (); +} + +void +cairo_set_font_size (cairo_t *cr, double size) +{ + _enter_trace (); + _emit_line_info (); + _emit_cairo_op (cr, "%g set-font-size\n", size); + DLCALL (cairo_set_font_size, cr, size); + _exit_trace (); +} + +void +cairo_set_font_matrix (cairo_t *cr, const cairo_matrix_t *matrix) +{ + _enter_trace (); + _emit_line_info (); + _emit_cairo_op (cr, "%g %g %g %g %g %g matrix set-font-matrix\n", + matrix->xx, matrix->yx, + matrix->xy, matrix->yy, + matrix->x0, matrix->y0); + DLCALL (cairo_set_font_matrix, cr, matrix); + _exit_trace (); +} + +static const char * +_subpixel_order_to_string (cairo_subpixel_order_t subpixel_order) +{ +#define f(name) case CAIRO_SUBPIXEL_ORDER_ ## name: return "SUBPIXEL_ORDER_" #name + switch (subpixel_order) { + f(DEFAULT); + f(RGB); + f(BGR); + f(VRGB); + f(VBGR); + }; +#undef f + return "UNKNOWN_SUBPIXEL_ORDER"; +} + +static const char * +_hint_style_to_string (cairo_hint_style_t hint_style) +{ +#define f(name) case CAIRO_HINT_STYLE_ ## name: return "HINT_STYLE_" #name + switch (hint_style) { + f(DEFAULT); + f(NONE); + f(SLIGHT); + f(MEDIUM); + f(FULL); + }; +#undef f + return "UNKNOWN_HINT_STYLE"; +} + +static const char * +_hint_metrics_to_string (cairo_hint_metrics_t hint_metrics) +{ +#define f(name) case CAIRO_HINT_METRICS_ ## name: return "HINT_METRICS_" #name + switch (hint_metrics) { + f(DEFAULT); + f(OFF); + f(ON); + }; +#undef f + return "UNKNOWN_HINT_METRICS"; +} + +static void +_emit_font_options (const cairo_font_options_t *options) +{ + cairo_antialias_t antialias; + cairo_subpixel_order_t subpixel_order; + cairo_hint_style_t hint_style; + cairo_hint_metrics_t hint_metrics; + + _trace_printf ("<<"); + + antialias = DLCALL (cairo_font_options_get_antialias, options); + if (antialias != CAIRO_ANTIALIAS_DEFAULT) { + _trace_printf (" /antialias //%s", + _antialias_to_string (antialias)); + } + + subpixel_order = DLCALL (cairo_font_options_get_subpixel_order, options); + if (subpixel_order != CAIRO_SUBPIXEL_ORDER_DEFAULT) { + _trace_printf (" /subpixel-order //%s", + _subpixel_order_to_string (subpixel_order)); + } + + hint_style = DLCALL (cairo_font_options_get_hint_style, options); + if (hint_style != CAIRO_HINT_STYLE_DEFAULT) { + _trace_printf (" /hint-style //%s", + _hint_style_to_string (hint_style)); + } + + hint_metrics = DLCALL (cairo_font_options_get_hint_metrics, options); + if (hint_metrics != CAIRO_HINT_METRICS_DEFAULT) { + _trace_printf (" /hint-metrics //%s", + _hint_metrics_to_string (hint_metrics)); + } + + _trace_printf (" >>"); +} + +void +cairo_set_font_options (cairo_t *cr, const cairo_font_options_t *options) +{ + _enter_trace (); + _emit_line_info (); + if (cr != NULL && options != NULL && _write_lock ()) { + _emit_context (cr); + _emit_font_options (options); + _trace_printf (" set-font-options\n"); + _write_unlock (); + } + + DLCALL (cairo_set_font_options, cr, options); + _exit_trace (); +} + +cairo_scaled_font_t * +cairo_get_scaled_font (cairo_t *cr) +{ + cairo_scaled_font_t *ret; + + _enter_trace (); + + ret = DLCALL (cairo_get_scaled_font, cr); + + if (cr != NULL && ! _has_scaled_font_id (ret)) { + _emit_cairo_op (cr, "/scaled-font get /sf%ld exch def\n", + _create_scaled_font_id (ret)); + _get_object (SCALED_FONT, ret)->defined = TRUE; + } + + _exit_trace (); + return ret; +} + +void +cairo_set_scaled_font (cairo_t *cr, const cairo_scaled_font_t *scaled_font) +{ + _enter_trace (); + _emit_line_info (); + if (cr != NULL && scaled_font != NULL && _write_lock ()) { + Object *obj = _get_object (SCALED_FONT, scaled_font); + cairo_bool_t need_context_and_font = TRUE; + + if (_is_current (SCALED_FONT, scaled_font, 0) && + _is_current (CONTEXT, cr, 1)) + { + if (obj->defined) { + _consume_operand (false); + } else { + _trace_printf ("exch 1 index "); + _exch_operands (); + } + need_context_and_font = FALSE; + } + else if (_is_current (SCALED_FONT, scaled_font, 1) && + _is_current (CONTEXT, cr, 0)) + { + if (obj->defined) { + _trace_printf ("exch "); + _exch_operands (); + _consume_operand (false); + need_context_and_font = FALSE; + } + } + + if (need_context_and_font) { + _emit_context (cr); + _emit_scaled_font_id (scaled_font); + } + + _trace_printf ("set-scaled-font\n"); + + _write_unlock (); + } + DLCALL (cairo_set_scaled_font, cr, scaled_font); + _exit_trace (); +} + +static void +_emit_matrix (const cairo_matrix_t *m) +{ + if (_matrix_is_identity(m)) + { + _trace_printf ("identity"); + } + else + { + _trace_printf ("%g %g %g %g %g %g matrix", + m->xx, m->yx, + m->xy, m->yy, + m->x0, m->y0); + } +} + +cairo_scaled_font_t * +cairo_scaled_font_create (cairo_font_face_t *font_face, + const cairo_matrix_t *font_matrix, + const cairo_matrix_t *ctm, + const cairo_font_options_t *options) +{ + cairo_scaled_font_t *ret; + + _enter_trace (); + + ret = DLCALL (cairo_scaled_font_create, font_face, font_matrix, ctm, options); + if (_has_scaled_font_id (ret)) + goto out; + + _emit_line_info (); + if (font_face != NULL && + font_matrix != NULL && + ctm != NULL && + options != NULL + && _write_lock ()) + { + Object *obj; + + obj = _type_object_create (SCALED_FONT, ret); + DLCALL (cairo_scaled_font_set_user_data, + ret, &destroy_key, obj, _object_undef); + + if (_pop_operands_to (FONT_FACE, font_face)) + _consume_operand (false); + else + _trace_printf ("f%ld ", _get_font_face_id (font_face)); + + _emit_matrix (font_matrix); + _trace_printf (" "); + + _emit_matrix (ctm); + _trace_printf (" "); + + _emit_font_options (options); + + _trace_printf (" scaled-font /sf%ld exch def\n", + obj->token); + obj->defined = TRUE; + + _write_unlock (); + } + +out: + _exit_trace (); + return ret; +} + +void +cairo_show_text (cairo_t *cr, const char *utf8) +{ + _enter_trace (); + _emit_line_info (); + if (cr != NULL && _write_lock ()) { + _emit_context (cr); + _emit_string_literal (utf8, -1); + _trace_printf (" show-text\n"); + _write_unlock (); + } + DLCALL (cairo_show_text, cr, utf8); + _exit_trace (); +} + +static void +_glyph_advance (cairo_scaled_font_t *font, + const cairo_glyph_t *glyph, + double *x, double *y) +{ + cairo_text_extents_t extents; + + DLCALL (cairo_scaled_font_glyph_extents, font, glyph, 1, &extents); + *x += extents.x_advance; + *y += extents.y_advance; +} + +#define TOLERANCE 1e-5 +static void +_emit_glyphs (cairo_scaled_font_t *font, + const cairo_glyph_t *glyphs, + int num_glyphs) +{ + double x,y; + int n; + + if (num_glyphs == 0) { + _trace_printf ("[]"); + return; + } + + for (n = 0; n < num_glyphs; n++) { + if (glyphs[n].index > 255) + break; + } + + x = glyphs->x; + y = glyphs->y; + if (n < num_glyphs) { /* need full glyph range */ + cairo_bool_t first; + + _trace_printf ("[%g %g [", x, y); + first = TRUE; + while (num_glyphs--) { + if (fabs (glyphs->x - x) > TOLERANCE || + fabs (glyphs->y - y) > TOLERANCE) + { + x = glyphs->x; + y = glyphs->y; + _trace_printf ("] %g %g [", x, y); + first = TRUE; + } + + if (! first) + _trace_printf (" "); + _trace_printf ("%lu", glyphs->index); + first = FALSE; + + _glyph_advance (font, glyphs, &x, &y); + glyphs++; + } + _trace_printf ("]]"); + } else { + struct _data_stream stream; + + if (num_glyphs == 1) { + _trace_printf ("[%g %g <%02lx>]", x, y, glyphs->index); + } else { + _trace_printf ("[%g %g <~", x, y); + _write_base85_data_start (&stream); + while (num_glyphs--) { + unsigned char c; + + if (fabs (glyphs->x - x) > TOLERANCE || + fabs (glyphs->y - y) > TOLERANCE) + { + x = glyphs->x; + y = glyphs->y; + _write_base85_data_end (&stream); + _trace_printf ("~> %g %g <~", x, y); + _write_base85_data_start (&stream); + } + + c = glyphs->index; + _write_base85_data (&stream, &c, 1); + + _glyph_advance (font, glyphs, &x, &y); + glyphs++; + } + _write_base85_data_end (&stream); + _trace_printf ("~>]"); + } + } +} + +void +cairo_show_glyphs (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs) +{ + _enter_trace (); + _emit_line_info (); + if (cr != NULL && glyphs != NULL && _write_lock ()) { + cairo_scaled_font_t *font; + + _emit_context (cr); + font = DLCALL (cairo_get_scaled_font, cr); + + _emit_glyphs (font, glyphs, num_glyphs); + _trace_printf (" show-glyphs\n"); + _write_unlock (); + } + + DLCALL (cairo_show_glyphs, cr, glyphs, num_glyphs); + _exit_trace (); +} + +static const char * +_direction_to_string (cairo_bool_t backward) +{ + const char *names[] = { + "FORWARD", + "BACKWARD" + }; + return names[!!backward]; +} + +void +cairo_show_text_glyphs (cairo_t *cr, + const char *utf8, + int utf8_len, + const cairo_glyph_t *glyphs, + int num_glyphs, + const cairo_text_cluster_t *clusters, + int num_clusters, + cairo_text_cluster_flags_t backward) +{ + cairo_scaled_font_t *font; + + _enter_trace (); + + font = DLCALL (cairo_get_scaled_font, cr); + + _emit_line_info (); + if (cr != NULL && glyphs != NULL && clusters != NULL && _write_lock ()) { + int n; + + _emit_context (cr); + + _emit_string_literal (utf8, utf8_len); + + _emit_glyphs (font, glyphs, num_glyphs); + _trace_printf (" ["); + for (n = 0; n < num_clusters; n++) { + _trace_printf (" %d %d", + clusters[n].num_bytes, + clusters[n].num_glyphs); + } + _trace_printf (" ] //%s show-text-glyphs\n", + _direction_to_string (backward)); + + _write_unlock (); + } + + DLCALL (cairo_show_text_glyphs, cr, + utf8, utf8_len, + glyphs, num_glyphs, + clusters, num_clusters, + backward); + _exit_trace (); +} + +void +cairo_text_path (cairo_t *cr, const char *utf8) +{ + _enter_trace (); + _emit_line_info (); + if (cr != NULL && _write_lock ()) { + _emit_context (cr); + _emit_string_literal (utf8, -1); + _trace_printf (" text-path\n"); + _write_unlock (); + } + DLCALL (cairo_text_path, cr, utf8); + _exit_trace (); +} + +void +cairo_glyph_path (cairo_t *cr, const cairo_glyph_t *glyphs, int num_glyphs) +{ + cairo_scaled_font_t *font; + + _enter_trace (); + + font = DLCALL (cairo_get_scaled_font, cr); + + _emit_line_info (); + if (cr != NULL && glyphs != NULL && _write_lock ()) { + _emit_context (cr); + _emit_glyphs (font, glyphs, num_glyphs); + _trace_printf (" glyph-path\n"); + + _write_unlock (); + } + + DLCALL (cairo_glyph_path, cr, glyphs, num_glyphs); + _exit_trace (); +} + +void +cairo_append_path (cairo_t *cr, const cairo_path_t *path) +{ + /* XXX no support for named paths, so manually reconstruct */ + int i; + cairo_path_data_t *p; + + _enter_trace (); + + _emit_line_info (); + if (cr == NULL || path == NULL) { + DLCALL (cairo_append_path, cr, path); + _exit_trace (); + return; + } + + for (i=0; i < path->num_data; i += path->data[i].header.length) { + p = &path->data[i]; + switch (p->header.type) { + case CAIRO_PATH_MOVE_TO: + if (p->header.length >= 2) + cairo_move_to (cr, p[1].point.x, p[1].point.y); + break; + case CAIRO_PATH_LINE_TO: + if (p->header.length >= 2) + cairo_line_to (cr, p[1].point.x, p[1].point.y); + break; + case CAIRO_PATH_CURVE_TO: + if (p->header.length >= 4) + cairo_curve_to (cr, + p[1].point.x, p[1].point.y, + p[2].point.x, p[2].point.y, + p[3].point.x, p[3].point.y); + break; + case CAIRO_PATH_CLOSE_PATH: + if (p->header.length >= 1) + cairo_close_path (cr); + break; + default: + break; + } + } + _exit_trace (); +} + +cairo_surface_t * +cairo_image_surface_create (cairo_format_t format, int width, int height) +{ + cairo_surface_t *ret; + + _enter_trace (); + + ret = DLCALL (cairo_image_surface_create, format, width, height); + + _emit_line_info (); + if (_write_lock ()) { + Object *obj = _create_surface (ret); + const char *format_str = _format_to_string (format); + const char *content_str = _format_to_content_string (format); + + _trace_printf ("dict\n" + " /width %d set\n" + " /height %d set\n" + " /format //%s set\n" + " /content //%s set\n" + " image dup /s%ld exch def\n", + width, height, format_str, content_str, obj->token); + obj->width = width; + obj->height = height; + obj->defined = TRUE; + _push_object (obj); + dump_stack(__func__); + _write_unlock (); + } + + _exit_trace (); + return ret; +} + +cairo_surface_t * +cairo_image_surface_create_for_data (unsigned char *data, cairo_format_t format, int width, int height, int stride) +{ + cairo_surface_t *ret; + + _enter_trace (); + + ret = DLCALL (cairo_image_surface_create_for_data, data, format, width, height, stride); + + _emit_line_info (); + if (_write_lock ()) { + Object *obj = _create_surface (ret); + + /* cairo_image_surface_create_for_data() is both used to supply + * foreign pixel data to cairo and in order to read pixels back. + * Defer grabbing the pixel contents until we have to, but only for + * "large" images, for small images the overhead of embedding pixels + * is negligible. + * + * Choose 32x32 as that captures most icons which thanks to GdkPixbuf + * are frequently reloaded. + */ + if (width * height < 32*32) { + _emit_image (ret, NULL); + _trace_printf (" dup /s%ld exch def\n", + obj->token); + } else { + _trace_printf ("dict\n" + " /width %d set\n" + " /height %d set\n" + " /format //%s set\n" + " image dup /s%ld exch def\n", + width, height, + _format_to_string (format), + obj->token); + + obj->foreign = TRUE; + } + + obj->width = width; + obj->height = height; + obj->defined = TRUE; + _push_object (obj); + dump_stack(__func__); + _write_unlock (); + } + + _exit_trace (); + return ret; +} + +unsigned char * +cairo_image_surface_get_data (cairo_surface_t *surface) +{ + unsigned char *ptr; + + /* Just leave some breadcrumbs */ + _enter_trace (); + _emit_line_info (); + if (surface != NULL && _write_lock ()) { + _trace_printf ("%% s%ld get-data\n", _get_surface_id (surface)); + _write_unlock (); + } + ptr = DLCALL (cairo_image_surface_get_data, surface); + _exit_trace (); + + return ptr; +} + +cairo_pattern_t * +cairo_pattern_create_raster_source (void *data, cairo_content_t content, int width, int height) +{ + cairo_pattern_t *ret; + + _enter_trace (); + + ret = DLCALL (cairo_pattern_create_raster_source, data, content, width, height); + + _emit_line_info (); + if (_write_lock ()) { + long pattern_id = _create_pattern_id (ret); + cairo_format_t format; + cairo_surface_t *image; + cairo_t *cr; + + /* Impossible to accurately record the interaction with this custom + * pattern so just suck all the data into an image upfront */ + switch (content) { + case CAIRO_CONTENT_ALPHA: format = CAIRO_FORMAT_A8; break; + case CAIRO_CONTENT_COLOR: format = CAIRO_FORMAT_RGB24; break; + default: + case CAIRO_CONTENT_COLOR_ALPHA: format = CAIRO_FORMAT_ARGB32; break; + } + + _trace_printf ("%% raster-source\n"); + + image = DLCALL (cairo_image_surface_create, format, width, height); + cr = DLCALL (cairo_create, image); + DLCALL (cairo_set_source, cr, ret); + DLCALL (cairo_paint, cr); + DLCALL (cairo_destroy, cr); + + _emit_image (image, NULL); + DLCALL (cairo_surface_destroy, image); + _trace_printf (" pattern dup /s%ld exch def\n", + pattern_id); + + _push_operand (PATTERN, ret); + _get_object (PATTERN, ret)->defined = TRUE; + dump_stack(__func__); + _write_unlock (); + } + + _exit_trace (); + return ret; +} + +cairo_surface_t * +cairo_surface_create_similar (cairo_surface_t *other, + cairo_content_t content, + int width, int height) +{ + cairo_surface_t *ret; + + _enter_trace (); + + ret = DLCALL (cairo_surface_create_similar, other, content, width, height); + + _emit_line_info (); + if (other != NULL && _write_lock ()) { + Object *other_obj = _get_object(SURFACE, other); + Object *new_obj = _create_surface (ret); + + if (other_obj->operand != -1) { + if (current_stack_depth == other_obj->operand + 1) + _trace_printf ("dup "); + else + _trace_printf ("%d index ", + current_stack_depth - other_obj->operand - 1); + } else { + assert(other_obj->defined); + _trace_printf ("s%ld ", other_obj->token); + } + + _trace_printf ("%d %d //%s similar dup /s%ld exch def\n", + width, height, + _content_to_string (content), + new_obj->token); + + new_obj->width = width; + new_obj->height = height; + new_obj->defined = TRUE; + + _push_object (new_obj); + dump_stack(__func__); + _write_unlock (); + } + + _exit_trace (); + return ret; +} + +cairo_surface_t * +cairo_surface_create_similar_image (cairo_surface_t *other, + cairo_format_t format, + int width, int height) +{ + cairo_surface_t *ret; + + _enter_trace (); + + ret = DLCALL (cairo_surface_create_similar_image, + other, format, width, height); + + _emit_line_info (); + if (other != NULL && _write_lock ()) { + Object *other_obj = _get_object(SURFACE, other); + Object *new_obj = _create_surface (ret); + + if (other_obj->defined) + _trace_printf ("s%ld ", other_obj->token); + else if (current_stack_depth == other_obj->operand + 1) + _trace_printf ("dup "); + else + _trace_printf ("%d index ", + current_stack_depth - other_obj->operand - 1); + _trace_printf ("//%s %d %d similar-image %% s%ld\n", + _format_to_string (format), + width, height, + new_obj->token); + new_obj->width = width; + new_obj->height = height; + + _push_object (new_obj); + dump_stack(__func__); + _write_unlock (); + } + + _exit_trace (); + return ret; +} + +cairo_surface_t * +cairo_surface_map_to_image (cairo_surface_t *surface, + const cairo_rectangle_int_t *extents) +{ + cairo_surface_t *ret; + + _enter_trace (); + + ret = DLCALL (cairo_surface_map_to_image, surface, extents); + + _emit_line_info (); + if (_write_lock ()) { + Object *obj = _create_surface (ret); + + _emit_surface (surface); + if (extents) { + _trace_printf ("[%d %d %d %d] map-to-image %% s%ld\n", + extents->x, extents->y, + extents->width, extents->height, + obj->token); + obj->width = extents->width; + obj->height = extents->height; + } else { + _trace_printf ("[ ] map-to-image %% s%ld\n", obj->token); + } + + _push_object (obj); + dump_stack(__func__); + _write_unlock (); + } + + _exit_trace (); + return ret; +} + +void +cairo_surface_unmap_image (cairo_surface_t *surface, + cairo_surface_t *image) +{ + _enter_trace (); + + _emit_line_info (); + if (_write_lock ()) { + Object *s = _get_object (SURFACE, surface); + Object *i = _get_object (SURFACE, image); + if (!(s->operand == current_stack_depth - 2 && + i->operand == current_stack_depth - 1)) { + if (i->operand != s->operand + 1 || ! _pop_operands_to_depth (i->operand + 1)) { + _emit_surface (surface); + _emit_surface (image); + } + } + _trace_printf ("unmap-image\n"); + _consume_operand (true); + _write_unlock (); + } + + DLCALL (cairo_surface_unmap_image, surface, image); + + _exit_trace (); +} + +cairo_surface_t * +cairo_surface_create_for_rectangle (cairo_surface_t *target, + double x, double y, + double width, double height) +{ + cairo_surface_t *ret; + + _enter_trace (); + + ret = DLCALL (cairo_surface_create_for_rectangle, target, x, y, width, height); + + _emit_line_info (); + if (target != NULL && _write_lock ()) { + Object *target_obj = _get_object (SURFACE, target); + Object *child_obj = _create_surface (ret); + + if (target_obj->defined) + _trace_printf ("s%ld ", target_obj->token); + else if (current_stack_depth == target_obj->operand + 1) + _trace_printf ("dup "); + else + _trace_printf ("%d index ", current_stack_depth - target_obj->operand - 1); + _trace_printf ("%f %f %f %f subsurface %% s%ld\n", + x, y, width, height, + child_obj->token); + + _push_object (child_obj); + dump_stack(__func__); + _write_unlock (); + } + + _exit_trace (); + return ret; +} + +static void CAIRO_PRINTF_FORMAT(2, 3) +_emit_surface_op (cairo_surface_t *surface, const char *fmt, ...) +{ + va_list ap; + + if (surface == NULL || ! _write_lock ()) + return; + + _emit_surface (surface); + + va_start (ap, fmt); + _trace_vprintf ( fmt, ap); + va_end (ap); + + _write_unlock (); +} + +void +cairo_surface_finish (cairo_surface_t *surface) +{ + _enter_trace (); + _emit_line_info (); + DLCALL (cairo_surface_finish, surface); + _exit_trace (); +} + +void +cairo_surface_flush (cairo_surface_t *surface) +{ + _enter_trace (); + _emit_line_info (); + if (surface != NULL && _write_lock ()) { + _trace_printf ("%% s%ld flush\n", _get_surface_id (surface)); + _write_unlock (); + } + DLCALL (cairo_surface_flush, surface); + _exit_trace (); +} + +void +cairo_surface_mark_dirty (cairo_surface_t *surface) +{ + _enter_trace (); + _emit_line_info (); + + /* Call cairo before emitting the trace since _emit_surface() might cause + * snapshots to be creates while mark_dirty assert()s that there are none. + */ + DLCALL (cairo_surface_mark_dirty, surface); + + if (surface != NULL && _write_lock ()) { + if (_mark_dirty) { + _emit_surface (surface); + _trace_printf ("%% mark-dirty\n"); + _emit_source_image (surface); + } else + _trace_printf ("%% s%ld mark-dirty\n", _get_surface_id (surface)); + _write_unlock (); + } + _exit_trace (); +} + +void +cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface, + int x, int y, int width, int height) +{ + _enter_trace (); + + /* Call cairo before emitting the trace since _emit_surface() might cause + * snapshots to be creates while mark_dirty assert()s that there are none. + */ + DLCALL (cairo_surface_mark_dirty_rectangle, surface, x, y, width, height); + + _emit_line_info (); + if (surface != NULL && _write_lock ()) { + if (_mark_dirty) { + _emit_surface (surface); + _trace_printf ("%% %d %d %d %d mark-dirty-rectangle\n", + x, y, width, height); + _emit_source_image_rectangle (surface, x,y, width, height); + } else + _trace_printf ("%% s%ld %d %d %d %d mark-dirty-rectangle\n", + _get_surface_id (surface), x, y, width, height); + _write_unlock (); + } + _exit_trace (); +} + +void +cairo_surface_set_device_offset (cairo_surface_t *surface, double x_offset, double y_offset) +{ + _enter_trace (); + _emit_line_info (); + _emit_surface_op (surface, "%g %g set-device-offset\n", + x_offset, y_offset); + DLCALL (cairo_surface_set_device_offset, surface, x_offset, y_offset); + _exit_trace (); +} + +void +cairo_surface_set_device_scale (cairo_surface_t *surface, double x_offset, double y_offset) +{ + _enter_trace (); + _emit_line_info (); + _emit_surface_op (surface, "%g %g set-device-scale\n", + x_offset, y_offset); + DLCALL (cairo_surface_set_device_scale, surface, x_offset, y_offset); + _exit_trace (); +} + + +void +cairo_surface_set_fallback_resolution (cairo_surface_t *surface, double x_pixels_per_inch, double y_pixels_per_inch) +{ + _enter_trace (); + _emit_line_info (); + _emit_surface_op (surface, "%g %g set-fallback-resolution\n", + x_pixels_per_inch, y_pixels_per_inch); + DLCALL (cairo_surface_set_fallback_resolution, surface, x_pixels_per_inch, y_pixels_per_inch); + _exit_trace (); +} + +void +cairo_surface_copy_page (cairo_surface_t *surface) +{ + _enter_trace (); + _emit_line_info (); + _emit_surface_op (surface, "copy-page\n"); + DLCALL (cairo_surface_copy_page, surface); + _exit_trace (); +} + +void +cairo_surface_show_page (cairo_surface_t *surface) +{ + _enter_trace (); + _emit_line_info (); + _emit_surface_op (surface, "show-page\n"); + DLCALL (cairo_surface_show_page, surface); + _exit_trace (); +} + +cairo_status_t +cairo_surface_set_mime_data (cairo_surface_t *surface, + const char *mime_type, + const unsigned char *data, + unsigned long length, + cairo_destroy_func_t destroy, + void *closure) +{ + cairo_status_t ret; + _enter_trace (); + _emit_line_info (); + if (surface != NULL && _write_lock ()) { + _emit_surface (surface); + _emit_string_literal (mime_type, -1); + _trace_printf (" "); + _emit_data (data, length); + _trace_printf (" /deflate filter set-mime-data\n"); + + _write_unlock (); + } + + ret = DLCALL (cairo_surface_set_mime_data, + surface, + mime_type, + data, length, + destroy, + closure); + _exit_trace (); + return ret; +} + +#if CAIRO_HAS_PNG_FUNCTIONS +cairo_status_t +cairo_surface_write_to_png (cairo_surface_t *surface, const char *filename) +{ + cairo_status_t ret; + _enter_trace (); + _emit_line_info (); + if (surface != NULL && _write_lock ()) { + _trace_printf ("%% s%ld ", _get_surface_id (surface)); + _emit_string_literal (filename, -1); + _trace_printf (" write-to-png pop\n"); + _write_unlock (); + } + ret = DLCALL (cairo_surface_write_to_png, surface, filename); + _exit_trace (); + return ret; +} + +cairo_status_t +cairo_surface_write_to_png_stream (cairo_surface_t *surface, + cairo_write_func_t write_func, + void *data) +{ + cairo_status_t ret; + _enter_trace (); + _emit_line_info (); + if (surface != NULL && _write_lock ()) { + char symbol[1024]; + + _trace_printf ("%% s%ld ", _get_surface_id (surface)); +#if CAIRO_HAS_SYMBOL_LOOKUP + lookup_symbol (symbol, sizeof (symbol), write_func); +#else + symbol[0] = '\0'; +#endif + _emit_string_literal (symbol, -1); + _trace_printf (" write-to-png-stream pop\n"); + _write_unlock (); + } + ret = DLCALL (cairo_surface_write_to_png_stream, + surface, write_func, data); + _exit_trace (); + return ret; +} +#endif + +static void CAIRO_PRINTF_FORMAT(2, 3) +_emit_pattern_op (cairo_pattern_t *pattern, const char *fmt, ...) +{ + va_list ap; + + if (pattern == NULL || ! _write_lock ()) + return; + + _emit_pattern (pattern); + + va_start (ap, fmt); + _trace_vprintf (fmt, ap); + va_end (ap); + + _write_unlock (); +} + +cairo_pattern_t * +cairo_pattern_create_rgb (double red, double green, double blue) +{ + cairo_pattern_t *ret; + long pattern_id; + + _enter_trace (); + + ret = DLCALL (cairo_pattern_create_rgb, red, green, blue); + pattern_id = _create_pattern_id (ret); + + _emit_line_info (); + if (_write_lock ()) { + _trace_printf ("/p%ld %g %g %g rgb def\n", + pattern_id, red, green, blue); + _get_object (PATTERN, ret)->defined = TRUE; + _write_unlock (); + } + + _exit_trace (); + return ret; +} + +cairo_pattern_t * +cairo_pattern_create_rgba (double red, double green, double blue, double alpha) +{ + cairo_pattern_t *ret; + long pattern_id; + + _enter_trace (); + + ret = DLCALL (cairo_pattern_create_rgba, red, green, blue, alpha); + pattern_id = _create_pattern_id (ret); + + _emit_line_info (); + if (_write_lock ()) { + _trace_printf ("/p%ld %g %g %g %g rgba def\n", + pattern_id, red, green, blue, alpha); + _get_object (PATTERN, ret)->defined = TRUE; + _write_unlock (); + } + + _exit_trace (); + return ret; +} + +cairo_pattern_t * +cairo_pattern_create_for_surface (cairo_surface_t *surface) +{ + cairo_pattern_t *ret; + long pattern_id; + long surface_id; + + _enter_trace (); + + ret = DLCALL (cairo_pattern_create_for_surface, surface); + pattern_id = _create_pattern_id (ret); + + _emit_line_info (); + if (surface != NULL && _write_lock ()) { + surface_id = _get_surface_id (surface); + + if (_pop_operands_to (SURFACE, surface)) { + _consume_operand (false); + } else { + _trace_printf ("s%ld ", surface_id); + } + + if (_get_object (SURFACE, surface)->foreign) + _emit_source_image (surface); + + _trace_printf ("pattern %% p%ld\n", pattern_id); + _push_operand (PATTERN, ret); + dump_stack(__func__); + _write_unlock (); + } + + _exit_trace (); + return ret; +} + +cairo_pattern_t * +cairo_pattern_create_linear (double x0, double y0, double x1, double y1) +{ + cairo_pattern_t *ret; + long pattern_id; + + _enter_trace (); + + ret = DLCALL (cairo_pattern_create_linear, x0, y0, x1, y1); + pattern_id = _create_pattern_id (ret); + + _emit_line_info (); + if (_write_lock ()) { + _trace_printf ("%g %g %g %g linear %% p%ld\n", + x0, y0, x1, y1, pattern_id); + _push_operand (PATTERN, ret); + dump_stack(__func__); + _write_unlock (); + } + + _exit_trace (); + return ret; +} + +cairo_pattern_t * +cairo_pattern_create_radial (double cx0, double cy0, double radius0, double cx1, double cy1, double radius1) +{ + cairo_pattern_t *ret; + long pattern_id; + + _enter_trace (); + + ret = DLCALL (cairo_pattern_create_radial, + cx0, cy0, radius0, + cx1, cy1, radius1); + pattern_id = _create_pattern_id (ret); + + _emit_line_info (); + if (_write_lock ()) { + _trace_printf ("%g %g %g %g %g %g radial %% p%ld\n", + cx0, cy0, radius0, cx1, cy1, radius1, + pattern_id); + _push_operand (PATTERN, ret); + dump_stack(__func__); + _write_unlock (); + } + + _exit_trace (); + return ret; +} + +void +cairo_pattern_add_color_stop_rgb (cairo_pattern_t *pattern, double offset, double red, double green, double blue) +{ + _enter_trace (); + _emit_line_info (); + _emit_pattern_op (pattern, + "%g %g %g %g 1 add-color-stop\n", + offset, red, green, blue); + DLCALL (cairo_pattern_add_color_stop_rgb, pattern, offset, red, green, blue); + _exit_trace (); +} + +void +cairo_pattern_add_color_stop_rgba (cairo_pattern_t *pattern, double offset, double red, double green, double blue, double alpha) +{ + _enter_trace (); + _emit_line_info (); + _emit_pattern_op (pattern, + "%g %g %g %g %g add-color-stop\n", + offset, red, green, blue, alpha); + DLCALL (cairo_pattern_add_color_stop_rgba, pattern, offset, red, green, blue, alpha); + _exit_trace (); +} + +void +cairo_pattern_set_matrix (cairo_pattern_t *pattern, const cairo_matrix_t *matrix) +{ + _enter_trace (); + _emit_line_info (); + if (_matrix_is_identity (matrix)) { + _emit_pattern_op (pattern, "identity set-matrix\n"); + } else { + _emit_pattern_op (pattern, + "%g %g %g %g %g %g matrix set-matrix\n", + matrix->xx, matrix->yx, + matrix->xy, matrix->yy, + matrix->x0, matrix->y0); + } + DLCALL (cairo_pattern_set_matrix, pattern, matrix); + _exit_trace (); +} + +static const char * +_filter_to_string (cairo_filter_t filter) +{ +#define f(name) case CAIRO_FILTER_ ## name: return "FILTER_" #name + switch (filter) { + f(FAST); + f(GOOD); + f(BEST); + f(NEAREST); + f(BILINEAR); + f(GAUSSIAN); + }; +#undef f + return "UNKNOWN_FILTER"; +} + +void +cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter) +{ + _enter_trace (); + _emit_line_info (); + _emit_pattern_op (pattern, "//%s set-filter\n", _filter_to_string (filter)); + DLCALL (cairo_pattern_set_filter, pattern, filter); + _exit_trace (); +} + +static const char * +_extend_to_string (cairo_extend_t extend) +{ +#define f(name) case CAIRO_EXTEND_ ## name: return "EXTEND_" #name + switch (extend) { + f(NONE); + f(REPEAT); + f(REFLECT); + f(PAD); + }; +#undef f + return "UNKNOWN_EXTEND"; +} + +void +cairo_pattern_set_extend (cairo_pattern_t *pattern, cairo_extend_t extend) +{ + _enter_trace (); + _emit_line_info (); + _emit_pattern_op (pattern, "//%s set-extend\n", _extend_to_string (extend)); + DLCALL (cairo_pattern_set_extend, pattern, extend); + _exit_trace (); +} + +#if CAIRO_HAS_FT_FONT +#if CAIRO_HAS_FC_FONT +cairo_font_face_t * +cairo_ft_font_face_create_for_pattern (FcPattern *pattern) +{ + cairo_font_face_t *ret; + long font_face_id; + + _enter_trace (); + + ret = DLCALL (cairo_ft_font_face_create_for_pattern, pattern); + font_face_id = _create_font_face_id (ret); + + _emit_line_info (); + if (pattern != NULL && _write_lock ()) { + Object *obj; + + obj = _get_object (FONT_FACE, ret); + if (obj->unknown) { + FcPattern *copy; + FcChar8 *unparsed; + + copy = DLCALL (FcPatternDuplicate, pattern); + if (copy) + { + DLCALL (FcPatternDel, copy, FC_LANG); + DLCALL (FcPatternDel, copy, FC_CHARSET); + DLCALL (FcPatternDel, copy, FC_CAPABILITY); + } + else + copy = pattern; + + unparsed = DLCALL (FcNameUnparse, copy); + _trace_printf ("dict\n" + " /type 42 set\n" + " /pattern "); + _emit_string_literal ((char *) unparsed, -1); + _trace_printf (" set\n" + " font %% f%ld\n", + font_face_id); + obj->unknown = FALSE; + _push_operand (FONT_FACE, ret); + dump_stack(__func__); + + if (copy != pattern) + DLCALL (FcPatternDestroy, copy); + free (unparsed); + } + _write_unlock (); + } + + _exit_trace (); + return ret; +} +#endif /* CAIRO_HAS_FC_FONT*/ + +typedef struct _ft_face_data { + unsigned long index; + unsigned long size; + void *data; +} FtFaceData; + +static void +_ft_face_data_destroy (void *arg) +{ + FtFaceData *data = arg; + free (data->data); + free (data); +} + +cairo_font_face_t * +cairo_ft_font_face_create_for_ft_face (FT_Face face, int load_flags) +{ + cairo_font_face_t *ret; + Object *obj; + FtFaceData *data; + long font_face_id; + + _enter_trace (); + + ret = DLCALL (cairo_ft_font_face_create_for_ft_face, face, load_flags); + font_face_id = _create_font_face_id (ret); + + if (face == NULL) { + _exit_trace (); + return ret; + } + + obj = _get_object (NONE, face); + data = obj->data; + if (data == NULL) { + _exit_trace (); + return ret; + } + + _emit_line_info (); + if (_write_lock ()) { + obj = _get_object (FONT_FACE, ret); + if (obj->operand != -1) + _object_remove (obj); + + _trace_printf ("<< /type 42 /source "); + _emit_data (data->data, data->size); + _trace_printf (" /index %lu /flags %d >> font %% f%ld\n", + data->index, load_flags, font_face_id); + _push_operand (FONT_FACE, ret); + dump_stack(__func__); + _write_unlock (); + } + + _exit_trace (); + return ret; +} + +static cairo_bool_t +_ft_read_file (FtFaceData *data, const char *path) +{ + char buf[8192]; + FILE *file; + + file = fopen (path, "rb"); + if (file != NULL) { + size_t ret; + unsigned long int allocated = sizeof (buf); + data->data = malloc (allocated); + do { + ret = fread (buf, 1, sizeof (buf), file); + if (ret == 0) + break; + memcpy ((char *) data->data + data->size, buf, ret); + data->size += ret; + if (ret != sizeof (buf)) + break; + + if (data->size == allocated) { + allocated *= 2; + data->data = realloc (data->data, allocated); + } + } while (TRUE); + fclose (file); + } + + return file != NULL; +} + +FT_Error +FT_New_Face (FT_Library library, const char *pathname, FT_Long index, FT_Face *face) +{ + FT_Error ret; + + _enter_trace (); + + ret = DLCALL (FT_New_Face, library, pathname, index, face); + if (ret == 0) { + Object *obj = _type_object_create (NONE, *face); + FtFaceData *data = malloc (sizeof (FtFaceData)); + data->index = index; + data->size = 0; + data->data = NULL; + _ft_read_file (data, pathname); + obj->data = data; + obj->destroy = _ft_face_data_destroy; + } + + _exit_trace (); + return ret; +} + +FT_Error +FT_New_Memory_Face (FT_Library library, const FT_Byte *mem, FT_Long size, FT_Long index, FT_Face *face) +{ + FT_Error ret; + + _enter_trace (); + + ret = DLCALL (FT_New_Memory_Face, library, mem, size, index, face); + if (ret == 0) { + Object *obj = _type_object_create (NONE, *face); + FtFaceData *data = malloc (sizeof (FtFaceData)); + data->index = index; + data->size = size; + data->data = malloc (size); + memcpy (data->data, mem, size); + obj->data = data; + obj->destroy = _ft_face_data_destroy; + } + + _exit_trace (); + return ret; +} + +/* XXX + * FT_New_Memory_Face() and FT_New_Face() appear to wrap FT_Open_Face() so we + * get a redundant call to FT_Open_Face() from those paths (no PLT hiding + * within FT, naughty library!) but we do not intercept a direct call to + * FT_Open_Face(). So far this has not caused any issues, but it will one + * day... + */ +FT_Error +FT_Open_Face (FT_Library library, const FT_Open_Args *args, FT_Long index, FT_Face *face) +{ + FT_Error ret; + + _enter_trace (); + + ret = DLCALL (FT_Open_Face, library, args, index, face); + if (ret == 0) { + Object *obj = _get_object (NONE, *face); + if (obj == NULL) { + FtFaceData *data; + + data = malloc (sizeof (FtFaceData)); + data->index = index; + if (args->flags & FT_OPEN_MEMORY) { + data->size = args->memory_size; + data->data = malloc (args->memory_size); + memcpy (data->data, args->memory_base, args->memory_size); + } else if (args->flags & FT_OPEN_STREAM) { + fprintf (stderr, "FT_Open_Face (stream, %ld) = %p\n", + index, *face); + abort (); + } else if (args->flags & FT_OPEN_PATHNAME) { + data->size = 0; + data->data = NULL; + _ft_read_file (data, args->pathname); + } + + obj = _type_object_create (NONE, *face); + obj->data = data; + obj->destroy = _ft_face_data_destroy; + } + } + + _exit_trace (); + return ret; +} + +FT_Error +FT_Done_Face (FT_Face face) +{ + FT_Error ret; + _enter_trace (); + + _object_destroy (_get_object (NONE, face)); + + ret = DLCALL (FT_Done_Face, face); + _exit_trace (); + return ret; +} +#endif + +static void +_surface_object_set_size (cairo_surface_t *surface, int width, int height) +{ + Object *obj; + + obj = _get_object (SURFACE, surface); + obj->width = width; + obj->height = height; +} + +static void +_surface_object_set_size_from_surface (cairo_surface_t *surface) +{ + _surface_object_set_size (surface, + DLCALL (cairo_image_surface_get_width, surface), + DLCALL (cairo_image_surface_get_height, surface)); +} + +#if CAIRO_HAS_PS_SURFACE +#include + +cairo_surface_t * +cairo_ps_surface_create (const char *filename, double width_in_points, double height_in_points) +{ + cairo_surface_t *ret; + + _enter_trace (); + + ret = DLCALL (cairo_ps_surface_create, filename, width_in_points, height_in_points); + + _emit_line_info (); + if (_write_lock ()) { + Object *obj = _create_surface (ret); + + _trace_printf ("dict\n" + " /type /PS set\n" + " /filename "); + _emit_string_literal (filename, -1); + _trace_printf (" set\n" + " /width %g set\n" + " /height %g set\n" + " surface %% s%ld\n", + width_in_points, + height_in_points, + obj->token); + obj->width = width_in_points; + obj->height = height_in_points; + _push_object (obj); + dump_stack(__func__); + _write_unlock (); + } + + _exit_trace (); + return ret; +} + +cairo_surface_t * +cairo_ps_surface_create_for_stream (cairo_write_func_t write_func, void *closure, double width_in_points, double height_in_points) +{ + cairo_surface_t *ret; + + _enter_trace (); + + ret = DLCALL (cairo_ps_surface_create_for_stream, write_func, closure, width_in_points, height_in_points); + + _emit_line_info (); + if (_write_lock ()) { + Object *obj = _create_surface (ret); + + _trace_printf ("dict\n" + " /type /PS set\n" + " /width %g set\n" + " /height %g set\n" + " surface %% s%ld\n", + width_in_points, + height_in_points, + obj->token); + obj->width = width_in_points; + obj->height = height_in_points; + _push_object (obj); + dump_stack(__func__); + _write_unlock (); + } + + _exit_trace (); + return ret; +} + +void +cairo_ps_surface_set_size (cairo_surface_t *surface, double width_in_points, double height_in_points) +{ + _enter_trace (); + _emit_line_info (); + DLCALL (cairo_ps_surface_set_size, surface, width_in_points, height_in_points); + _exit_trace (); +} + +#endif + +#if CAIRO_HAS_PDF_SURFACE +#include + +cairo_surface_t * +cairo_pdf_surface_create (const char *filename, double width_in_points, double height_in_points) +{ + cairo_surface_t *ret; + + _enter_trace (); + + ret = DLCALL (cairo_pdf_surface_create, filename, width_in_points, height_in_points); + + _emit_line_info (); + if (_write_lock ()) { + Object *obj = _create_surface (ret); + + _trace_printf ("dict\n" + " /type /PDF set\n" + " /filename "); + _emit_string_literal (filename, -1); + _trace_printf (" set\n" + " /width %g set\n" + " /height %g set\n" + " surface %% s%ld\n", + width_in_points, + height_in_points, + obj->token); + obj->width = width_in_points; + obj->height = height_in_points; + _push_object (obj); + dump_stack(__func__); + _write_unlock (); + } + + _exit_trace (); + return ret; +} + +cairo_surface_t * +cairo_pdf_surface_create_for_stream (cairo_write_func_t write_func, void *closure, double width_in_points, double height_in_points) +{ + cairo_surface_t *ret; + + _enter_trace (); + + ret = DLCALL (cairo_pdf_surface_create_for_stream, write_func, closure, width_in_points, height_in_points); + + _emit_line_info (); + if (_write_lock ()) { + Object *obj = _create_surface (ret); + + _trace_printf ("dict\n" + " /type /PDF set\n" + " /width %g set\n" + " /height %g set\n" + " surface %% s%ld\n", + width_in_points, + height_in_points, + obj->token); + obj->width = width_in_points; + obj->height = height_in_points; + _push_object (obj); + dump_stack(__func__); + _write_unlock (); + } + _exit_trace (); + return ret; +} + +void +cairo_pdf_surface_set_size (cairo_surface_t *surface, double width_in_points, double height_in_points) +{ + _enter_trace (); + _emit_line_info (); + DLCALL (cairo_pdf_surface_set_size, surface, width_in_points, height_in_points); + _exit_trace (); +} +#endif + +#if CAIRO_HAS_SVG_SURFACE +#include + +cairo_surface_t * +cairo_svg_surface_create (const char *filename, double width, double height) +{ + cairo_surface_t *ret; + + _enter_trace (); + + ret = DLCALL (cairo_svg_surface_create, filename, width, height); + + _emit_line_info (); + if (_write_lock ()) { + Object *obj = _create_surface (ret); + + _trace_printf ("dict\n" + " /type /SVG set\n" + " /filename "); + _emit_string_literal (filename, -1); + _trace_printf (" set\n" + " /width %g set\n" + " /height %g set\n" + " surface %% s%ld\n", + width, + height, + obj->token); + obj->width = width; + obj->height = height; + _push_object (obj); + dump_stack(__func__); + _write_unlock (); + } + + _exit_trace (); + return ret; +} + +cairo_surface_t * +cairo_svg_surface_create_for_stream (cairo_write_func_t write_func, void *closure, double width, double height) +{ + cairo_surface_t *ret; + + _enter_trace (); + + ret = DLCALL (cairo_svg_surface_create_for_stream, write_func, closure, width, height); + + _emit_line_info (); + if (_write_lock ()) { + Object *obj = _create_surface (ret); + + _trace_printf ("dict\n" + " /type /SVG set\n" + " /width %g set\n" + " /height %g set\n" + " surface %% s%ld\n", + width, + height, + obj->token); + obj->width = width; + obj->height = height; + _push_object (obj); + dump_stack(__func__); + _write_unlock (); + } + + _exit_trace (); + return ret; +} + +#endif + +#if CAIRO_HAS_PNG_FUNCTIONS +cairo_surface_t * +cairo_image_surface_create_from_png (const char *filename) +{ + cairo_surface_t *ret; + + _enter_trace (); + + ret = DLCALL (cairo_image_surface_create_from_png, filename); + + _emit_line_info (); + if (_write_lock ()) { + Object *obj = _create_surface (ret); + char filename_string[4096]; + + _encode_string_literal (filename_string, sizeof (filename_string), + filename, -1); + _emit_image (ret, " /filename %s set\n", filename_string); + _trace_printf (" dup /s%ld exch def\n", obj->token); + _surface_object_set_size_from_surface (ret); + obj->defined = TRUE; + _push_object (obj); + dump_stack(__func__); + _write_unlock (); + } + + _exit_trace (); + return ret; +} + +cairo_surface_t * +cairo_image_surface_create_from_png_stream (cairo_read_func_t read_func, void *closure) +{ + cairo_surface_t *ret; + + _enter_trace (); + + ret = DLCALL (cairo_image_surface_create_from_png_stream, read_func, closure); + + _emit_line_info (); + if (_write_lock ()) { + Object *obj = _create_surface (ret); + + _emit_image (ret, NULL); + _trace_printf (" dup /s%ld exch def\n", + obj->token); + + _surface_object_set_size_from_surface (ret); + obj->defined = TRUE; + _push_object (obj); + dump_stack(__func__); + _write_unlock (); + } + + _exit_trace (); + return ret; +} +#endif + +#if CAIRO_HAS_TEE_SURFACE +#include + +cairo_surface_t * +cairo_tee_surface_create (cairo_surface_t *master) +{ + cairo_surface_t *ret; + + _enter_trace (); + + ret = DLCALL (cairo_tee_surface_create, master); + + _emit_line_info (); + if (_write_lock ()) { + Object *obj = _create_surface (ret); + + _trace_printf ("dict\n" + " /type /tee set\n" + " /master s%ld set\n" + " surface dup /s%ld exch def\n", + _get_object (SURFACE, master)->token, + obj->token); + obj->defined = TRUE; + _push_object (obj); + dump_stack(__func__); + _write_unlock (); + } + + _exit_trace (); + return ret; +} + +#endif + +#if CAIRO_HAS_XLIB_SURFACE +#include + +static const char * +_content_from_surface (cairo_surface_t *surface) +{ + return _content_to_string (DLCALL (cairo_surface_get_content, surface)); +} + +cairo_surface_t * +cairo_xlib_surface_create (Display *dpy, + Drawable drawable, + Visual *visual, + int width, int height) +{ + cairo_surface_t *ret; + + _enter_trace (); + + ret = DLCALL (cairo_xlib_surface_create, + dpy, drawable, visual, width, height); + + _emit_line_info (); + if (_write_lock ()) { + Object *obj = _create_surface (ret); + + _trace_printf ("dict\n" + " /type /xlib set\n" + " /drawable 16!%lx set\n" + " /content //%s set\n" + " /width %d set\n" + " /height %d set\n" + " surface dup /s%ld exch def\n", + drawable, + _content_from_surface (ret), + width, height, + obj->token); + obj->defined = TRUE; + obj->width = width; + obj->height = height; + obj->foreign = TRUE; + _push_object (obj); + dump_stack(__func__); + _write_unlock (); + } + + _exit_trace (); + return ret; +} + +cairo_surface_t * +cairo_xlib_surface_create_for_bitmap (Display *dpy, + Pixmap bitmap, + Screen *screen, + int width, int height) +{ + cairo_surface_t *ret; + + _enter_trace (); + + ret = DLCALL (cairo_xlib_surface_create_for_bitmap, + dpy, bitmap, screen, width, height); + + _emit_line_info (); + if (_write_lock ()) { + Object *obj = _create_surface (ret); + + _trace_printf ("dict\n" + " /type /xlib set\n" + " /drawable 16!%lx set\n" + " /content //%s set\n" + " /width %d set\n" + " /height %d set\n" + " /depth 1 set\n" + " surface dup /s%ld exch def\n", + bitmap, + _content_from_surface (ret), + width, height, + obj->token); + obj->defined = TRUE; + obj->width = width; + obj->height = height; + obj->foreign = TRUE; + _push_object (obj); + dump_stack(__func__); + _write_unlock (); + } + + _exit_trace (); + return ret; +} + +#if CAIRO_HAS_XLIB_XRENDER_SURFACE +#include +cairo_surface_t * +cairo_xlib_surface_create_with_xrender_format (Display *dpy, + Drawable drawable, + Screen *screen, + XRenderPictFormat *format, + int width, int height) +{ + cairo_surface_t *ret; + + _enter_trace (); + + ret = DLCALL (cairo_xlib_surface_create_with_xrender_format, + dpy, drawable, screen, format, width, height); + + _emit_line_info (); + if (_write_lock ()) { + Object *obj = _create_surface (ret); + + _trace_printf ("dict\n" + " /type /xrender set\n" + " /drawable 16!%lx set\n" + " /content //%s set\n" + " /width %d set\n" + " /height %d set\n" + " /depth %d set\n" + " surface dup /s%ld exch def\n", + drawable, + _content_from_surface (ret), + width, height, + format->depth, + obj->token); + obj->defined = TRUE; + obj->width = width; + obj->height = height; + obj->foreign = TRUE; + _push_object (obj); + dump_stack(__func__); + _write_unlock (); + } + + _exit_trace (); + return ret; +} +#endif +#endif + +#if CAIRO_HAS_SCRIPT_SURFACE +#include +cairo_surface_t * +cairo_script_surface_create (cairo_device_t *device, + cairo_content_t content, + double width, + double height) +{ + cairo_surface_t *ret; + + _enter_trace (); + + ret = DLCALL (cairo_script_surface_create, device, content, width, height); + + _emit_line_info (); + if (_write_lock ()) { + Object *obj = _create_surface (ret); + + _trace_printf ("dict\n" + " /type /script set\n" + " /content %s set\n" + " /width %g set\n" + " /height %g set\n" + " surface dup /s%ld exch def\n", + _content_to_string (content), + width, height, + obj->token); + obj->width = width; + obj->height = height; + obj->defined = TRUE; + _push_object (obj); + dump_stack(__func__); + _write_unlock (); + } + + _exit_trace (); + return ret; +} + +cairo_surface_t * +cairo_script_surface_create_for_target (cairo_device_t *device, + cairo_surface_t *target) +{ + cairo_surface_t *ret; + + _enter_trace (); + + ret = DLCALL (cairo_script_surface_create_for_target, device, target); + + _emit_line_info (); + if (_write_lock ()) { + Object *obj = _create_surface (ret); + + _trace_printf ("dict\n" + " /type /script set\n" + " surface dup /s%ld exch def\n", + obj->token); + obj->defined = TRUE; + _push_object (obj); + dump_stack(__func__); + _write_unlock (); + } + + _exit_trace (); + return ret; +} +#endif + +#if CAIRO_HAS_TEST_SURFACES +#include +cairo_surface_t * +_cairo_test_paginated_surface_create (cairo_surface_t *surface) +{ + cairo_surface_t *ret; + + _enter_trace (); + + ret = DLCALL (_cairo_test_paginated_surface_create, surface); + + _emit_line_info (); + if (_write_lock ()) { + Object *obj = _create_surface (ret); + + /* XXX store initial data? */ + _trace_printf ("dict\n" + " /type /test-paginated set\n" + " /target s%ld set\n" + " surface dup /s%ld exch def\n", + _get_surface_id (surface), + obj->token); + _push_object (obj); + dump_stack(__func__); + _write_unlock (); + } + + _exit_trace (); + return ret; +} + +#include + +cairo_surface_t * +_cairo_test_fallback_compositor_surface_create (cairo_content_t content, int width, int height) +{ + cairo_surface_t *ret; + + _enter_trace (); + + ret = DLCALL (_cairo_test_fallback_compositor_surface_create, content, width, height); + + _emit_line_info (); + if (_write_lock ()) { + Object *obj = _create_surface (ret); + + _trace_printf ("dict\n" + " /type /test-fallback-compositor set\n" + " /content //%s set\n" + " /width %d set\n" + " /height %d set\n" + " surface dup /s%ld exch def\n", + _content_to_string (content), + width, height, + obj->token); + obj->defined = TRUE; + _push_object (obj); + dump_stack(__func__); + _write_unlock (); + } + + _exit_trace (); + return ret; +} + +cairo_surface_t * +_cairo_test_mask_compositor_surface_create (cairo_content_t content, int width, int height) +{ + cairo_surface_t *ret; + + _enter_trace (); + + ret = DLCALL (_cairo_test_mask_compositor_surface_create, content, width, height); + + _emit_line_info (); + if (_write_lock ()) { + Object *obj = _create_surface (ret); + + _trace_printf ("dict\n" + " /type /test-mask-compositor set\n" + " /content //%s set\n" + " /width %d set\n" + " /height %d set\n" + " surface dup /s%ld exch def\n", + _content_to_string (content), + width, height, + obj->token); + obj->defined = TRUE; + _push_object (obj); + dump_stack(__func__); + _write_unlock (); + } + + _exit_trace (); + return ret; +} + +cairo_surface_t * +_cairo_test_spans_compositor_surface_create (cairo_content_t content, int width, int height) +{ + cairo_surface_t *ret; + + _enter_trace (); + + ret = DLCALL (_cairo_test_spans_compositor_surface_create, content, width, height); + + _emit_line_info (); + if (_write_lock ()) { + Object *obj = _create_surface (ret); + + _trace_printf ("dict\n" + " /type /test-spans-compositor set\n" + " /content //%s set\n" + " /width %d set\n" + " /height %d set\n" + " surface dup /s%ld exch def\n", + _content_to_string (content), + width, height, + obj->token); + obj->defined = TRUE; + _push_object (obj); + dump_stack(__func__); + _write_unlock (); + } + + _exit_trace (); + return ret; +} + +cairo_surface_t * +_cairo_test_traps_compositor_surface_create (cairo_content_t content, int width, int height) +{ + cairo_surface_t *ret; + + _enter_trace (); + + ret = DLCALL (_cairo_test_traps_compositor_surface_create, content, width, height); + + _emit_line_info (); + if (_write_lock ()) { + Object *obj = _create_surface (ret); + + _trace_printf ("dict\n" + " /type /test-traps-compositor set\n" + " /content //%s set\n" + " /width %d set\n" + " /height %d set\n" + " surface dup /s%ld exch def\n", + _content_to_string (content), + width, height, + obj->token); + obj->defined = TRUE; + _push_object (obj); + dump_stack(__func__); + _write_unlock (); + } + + _exit_trace (); + return ret; +} + +#endif + +cairo_surface_t * +cairo_recording_surface_create (cairo_content_t content, + const cairo_rectangle_t *extents) +{ + cairo_surface_t *ret; + + _enter_trace (); + + ret = DLCALL (cairo_recording_surface_create, content, extents); + + _emit_line_info (); + if (_write_lock ()) { + Object *obj = _create_surface (ret); + + if (extents) { + _trace_printf ("//%s [ %f %f %f %f ] record dup /s%ld exch def\n", + _content_to_string (content), + extents->x, extents->y, + extents->width, extents->height, + obj->token); + obj->width = extents->width; + obj->height = extents->height; + } else { + _trace_printf ("//%s [ ] record dup /s%ld exch def\n", + _content_to_string (content), + obj->token); + } + obj->defined = TRUE; + _push_object (obj); + dump_stack(__func__); + _write_unlock (); + } + + _exit_trace (); + return ret; +} diff --git a/local/recipes/libs/cairo/source/util/cairo-view b/local/recipes/libs/cairo/source/util/cairo-view new file mode 100755 index 0000000000..2bbed6985c --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo-view @@ -0,0 +1,113 @@ +#!/usr/bin/python + +import sys +import cairo +import pygtk +pygtk.require('2.0') +import gtk +import gtk.gdk +import pango +import gobject + +class CairoView(gtk.Window): + def __init__(self, family="", slant=0, weight=0, size=18, text="The Quick Brown Fox Jumps Over The Lazy Dog!"): + gtk.Widget.__init__ (self) + + self.family = family + if slant == "italic": + self.slant = cairo.FONT_SLANT_ITALIC + elif slant == "oblique": + self.slant = cairo.FONT_SLANT_OBLIQUE + else: + self.slant = cairo.FONT_SLANT_NORMAL + if weight == "bold": + self.weight = cairo.FONT_WEIGHT_BOLD + else: + self.weight = cairo.FONT_WEIGHT_NORMAL + self.size = float (size) + self.text = text + + def do_realize(self): + self.set_flags(self.flags() | gtk.REALIZED) + + self.window = gtk.gdk.Window( + self.get_parent_window(), + width=self.allocation.width, + height=self.allocation.height, + window_type=gtk.gdk.WINDOW_CHILD, + wclass=gtk.gdk.INPUT_OUTPUT, + event_mask=self.get_events() | gtk.gdk.EXPOSURE_MASK) + + self.window.set_user_data(self) + + self.style.attach(self.window) + + self.style.set_background(self.window, gtk.STATE_NORMAL) + + self.width, self.height = self.draw () + self.window.move_resize(0, 0, self.width, self.height) + + def do_unrealize(self): + self.window.destroy() + + def do_expose_event(self, event): + self.draw (event) + + return False + + def draw(self, event = None): + + cr = self.window.cairo_create() + if event: + cr.rectangle(event.area.x, event.area.y, + event.area.width, event.area.height) + cr.clip() + + cr.set_source_rgb (1, 1, 1) + cr.paint () + + cr.select_font_face (self.family, self.slant, self.weight) + cr.set_font_size (self.size) + + PAD = 30 + + extents = cr.text_extents (self.text) + cr.translate (PAD-extents[0], PAD-extents[1]) + + font_extents = cr.font_extents () + cr.rectangle (0, -font_extents[0], extents[4], font_extents[2]) + cr.move_to (-PAD, 0) + cr.line_to (extents[2]+PAD, 0) + cr.set_source_rgba (1, 0, 0, .7) + cr.stroke () + + cr.rectangle (*extents[:4]) + cr.set_source_rgba (0, 1, 0, .7) + cr.stroke () + + cr.move_to (0, 0) + cr.set_source_rgb (0, 0, 0) + cr.show_text (self.text) + + return int (extents[2]) + 2 * PAD, int (extents[3]) + 2 * PAD + + def run(self): + + self.props.allow_shrink = True + self.connect("destroy", gtk.main_quit) + self.show() + + gtk.main() + +gobject.type_register(CairoView) + +def main(args): + + if len (args) == 1: + print "usage: cairo-view family [slant [weight [size [text]]]]" + sys.exit (1) + cv= CairoView (*args[1:]) + cv.run() + +if __name__ == "__main__": + main(sys.argv) diff --git a/local/recipes/libs/cairo/source/util/cairo.modules b/local/recipes/libs/cairo/source/util/cairo.modules new file mode 100644 index 0000000000..c099a037e5 --- /dev/null +++ b/local/recipes/libs/cairo/source/util/cairo.modules @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/local/recipes/libs/cairo/source/util/font-view.c b/local/recipes/libs/cairo/source/util/font-view.c new file mode 100644 index 0000000000..6a3322a8a3 --- /dev/null +++ b/local/recipes/libs/cairo/source/util/font-view.c @@ -0,0 +1,186 @@ +/* + * Copyright © 2008 Behdad Esfahbod + * Copyright © 2009 Chris Wilson + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without + * fee, provided that the above copyright notice appear in all copies + * and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON BE LIABLE FOR ANY SPECIAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR + * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Author: Chris Wilson + */ + +#include +#include +#include +#include + +struct options { + const char *text; + const char *family; + cairo_font_weight_t weight; + cairo_font_slant_t slant; + double size; + int PAD; + const char *png; +}; + +static void +draw (cairo_t *cr, struct options *options) +{ + cairo_text_extents_t extents; + cairo_font_extents_t font_extents; + + cairo_select_font_face (cr, + options->family, options->slant, options->weight); + cairo_set_font_size (cr, options->size); + + cairo_text_extents (cr, options->text, &extents); + cairo_translate (cr, + options->PAD - extents.x_bearing, + options->PAD - extents.y_bearing); + + cairo_font_extents (cr, &font_extents); + cairo_rectangle (cr, 0, -font_extents.ascent, + extents.x_advance, font_extents.height); + cairo_move_to (cr, -options->PAD, 0); + cairo_line_to (cr, extents.width + options->PAD, 0); + cairo_set_source_rgba (cr, 1, 0, 0, .7); + cairo_stroke (cr); + + cairo_rectangle (cr, + extents.x_bearing, extents.y_bearing, + extents.width, extents.height); + cairo_set_source_rgba (cr, 0, 1, 0, .7); + cairo_stroke (cr); + + cairo_move_to (cr, 0, 0); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_show_text (cr, options->text); + cairo_fill (cr); +} + +static gboolean +expose_event (GtkWidget *w, GdkEventExpose *ev, struct options *options) +{ + cairo_t *cr; + + cr = gdk_cairo_create (w->window); + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + draw (cr, options); + + cairo_destroy (cr); + + if (options->png) { + cairo_surface_t *image; + + image = cairo_image_surface_create (CAIRO_FORMAT_RGB24, + w->allocation.width, + w->allocation.height); + cr = cairo_create (image); + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + draw (cr, options); + + cairo_destroy (cr); + cairo_surface_write_to_png (image, options->png); + cairo_surface_destroy (image); + } + + return TRUE; +} + +static void +size_request (GtkWidget *w, GtkRequisition *req , struct options *options) +{ + cairo_surface_t *dummy; + cairo_t *cr; + cairo_text_extents_t extents; + + dummy = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 0, 0); + cr = cairo_create (dummy); + cairo_surface_destroy (dummy); + + cairo_select_font_face (cr, + options->family, options->slant, options->weight); + cairo_set_font_size (cr, options->size); + + cairo_text_extents (cr, options->text, &extents); + cairo_destroy (cr); + + req->width = extents.width + 2 * options->PAD; + req->height = extents.height + 2 * options->PAD; +} + +int +main (int argc, char **argv) +{ + GtkWidget *window; + struct options options = { + "The Quick Brown Fox Jumps Over The Lazy Dog!", + "@cairo:small-caps", + CAIRO_FONT_WEIGHT_NORMAL, + CAIRO_FONT_SLANT_NORMAL, + 48, + 30, + "font-view.png" + }; + + gtk_init (&argc, &argv); + + /* rudimentary argument processing */ + if (argc >= 2) { + options.family = argv[1]; + } + if (argc >= 3) { + if (strcmp (argv[2], "italic") == 0) + options.slant = CAIRO_FONT_SLANT_ITALIC; + else if (strcmp (argv[2], "oblique") == 0) + options.slant = CAIRO_FONT_SLANT_OBLIQUE; + else + options.slant = atoi (argv[2]); + } + if (argc >= 4) { + if (strcmp (argv[3], "bold") == 0) + options.weight = CAIRO_FONT_WEIGHT_BOLD; + else + options.weight = atoi (argv[3]); + } + if (argc >= 5) { + options.size = atof (argv[4]); + } + if (argc >= 6) { + options.text = argv[5]; + } + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + g_signal_connect (window, "size-request", + G_CALLBACK (size_request), &options); + g_signal_connect (window, "expose-event", + G_CALLBACK (expose_event), &options); + g_signal_connect (window, "delete-event", + G_CALLBACK (gtk_main_quit), NULL); + + gtk_window_present (GTK_WINDOW (window)); + gtk_main (); + + return 0; +} diff --git a/local/recipes/libs/cairo/source/util/meson.build b/local/recipes/libs/cairo/source/util/meson.build new file mode 100644 index 0000000000..1e186bf66d --- /dev/null +++ b/local/recipes/libs/cairo/source/util/meson.build @@ -0,0 +1,43 @@ +subdir('cairo-missing') + +cairo_utils = [] + +if feature_conf.get('CAIRO_HAS_GOBJECT_FUNCTIONS', 0) == 1 + subdir('cairo-gobject') +endif + +if conf.get('CAIRO_HAS_INTERPRETER', 0) == 1 + subdir('cairo-script') +else + libcairoscript_dep = dependency('', required: false) +endif + +if conf.get('CAIRO_HAS_TRACE', 0) == 1 + subdir('cairo-trace') + + if (conf.get('CAIRO_HAS_DLSYM', 0) == 1 and + feature_conf.get('CAIRO_HAS_SCRIPT_SURFACE', 0) == 1 and + feature_conf.get('CAIRO_HAS_TEE_SURFACE', 0) == 1) + subdir('cairo-fdr') + endif +endif + +if gtk_dep.found() + cairo_utils += [ + ['show-contour.c', {'deps': [gtk_dep]}], + ['show-traps.c', {'deps': [gtk_dep]}], + ['show-edges.c', {'deps': [gtk_dep]}], + ['show-polygon.c', {'deps': [gtk_dep]}], + ['show-events.c', {'deps': [gtk_dep]}], + ['font-view.c', {'deps': [gtk_dep]}], + ] +endif + +foreach util : cairo_utils + exe_name = util[0].split('.')[0] + util_deps = util.get(1, {}).get('deps', []) + executable(exe_name, util[0], + include_directories: [incbase], + dependencies: deps + util_deps + [libcairo_dep, libcairoscript_dep], + ) +endforeach diff --git a/local/recipes/libs/cairo/source/util/show-contour.c b/local/recipes/libs/cairo/source/util/show-contour.c new file mode 100644 index 0000000000..e09f6315f7 --- /dev/null +++ b/local/recipes/libs/cairo/source/util/show-contour.c @@ -0,0 +1,668 @@ +#include "config.h" + +#include +#include +#include +#include +#include + +typedef struct _point { + gdouble x, y; +} point_t; +typedef struct _box { + point_t p1, p2; +} box_t; + +typedef struct _contour { + struct _contour *next, *prev; + int direction; + int num_points; + int size; + point_t points[0]; +} contour_t; + +typedef struct _TrapView { + GtkWidget widget; + + cairo_surface_t *pixmap; + int pixmap_width, pixmap_height; + + box_t extents; + contour_t *contours; + + double px, py; + + gint mag_x, mag_y; + gint mag_size; + gdouble mag_zoom; + gboolean in_mag_drag; + gint mag_drag_x, mag_drag_y; +} TrapView; + +typedef struct _TrapViewClass { + GtkWidgetClass parent_class; +} TrapViewClass; + +G_DEFINE_TYPE (TrapView, trap_view, GTK_TYPE_WIDGET) + +static cairo_surface_t * +pixmap_create (TrapView *self, cairo_surface_t *target) +{ + cairo_surface_t *surface = + cairo_surface_create_similar (target, CAIRO_CONTENT_COLOR, + self->widget.allocation.width, + self->widget.allocation.height); + cairo_t *cr = cairo_create (surface); + contour_t *contour; + gdouble sf_x, sf_y, sf; + gdouble mid, dim; + gdouble x0, y0; + int n; + box_t extents; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + if (self->contours == NULL) { + cairo_destroy(cr); + return surface; + } + + extents = self->extents; + + mid = (extents.p2.x + extents.p1.x) / 2.; + dim = (extents.p2.x - extents.p1.x) / 2. * 1.25; + sf_x = self->widget.allocation.width / dim / 2; + + mid = (extents.p2.y + extents.p1.y) / 2.; + dim = (extents.p2.y - extents.p1.y) / 2. * 1.25; + sf_y = self->widget.allocation.height / dim / 2; + + sf = MIN (sf_x, sf_y); + + mid = (extents.p2.x + extents.p1.x) / 2.; + dim = sf_x / sf * (extents.p2.x - extents.p1.x) / 2. * 1.25; + x0 = mid - dim; + mid = (extents.p2.y + extents.p1.y) / 2.; + dim = sf_y / sf * (extents.p2.y - extents.p1.y) / 2. * 1.25; + y0 = mid - dim; + + for (contour = self->contours; contour; contour = contour->next) { + if (contour->num_points == 0) + continue; + + cairo_save (cr); { + cairo_scale (cr, sf, sf); + cairo_translate (cr, -x0, -y0); + switch (contour->direction) { + case -1: + cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); + break; + case 0: + cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); + break; + case 1: + cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); + break; + } + { + const point_t *p = &contour->points[0]; + cairo_arc (cr, p->x, p->y, 4/sf, 0, 2 * M_PI); + cairo_save (cr); + cairo_identity_matrix (cr); + cairo_stroke (cr); + cairo_restore (cr); + } + for (n = 0; n < contour->num_points; n++) { + const point_t *p = &contour->points[n]; + cairo_arc (cr, p->x, p->y, 2/sf, 0, 2 * M_PI); + cairo_fill (cr); + } + for (n = 0; n < contour->num_points; n++) { + const point_t *p = &contour->points[n]; + cairo_line_to (cr, p->x, p->y); + } + } cairo_restore (cr); + + switch (contour->direction) { + case -1: + cairo_set_source_rgb (cr, 0.3, 0.3, 0.9); + break; + case 0: + cairo_set_source_rgb (cr, 0.3, 0.9, 0.3); + break; + case 1: + cairo_set_source_rgb (cr, 0.9, 0.3, 0.3); + break; + } + cairo_set_line_width (cr, 1.); + cairo_stroke (cr); + } + + cairo_destroy (cr); + return surface; +} + +static void +trap_view_draw (TrapView *self, cairo_t *cr) +{ + contour_t *contour; + gdouble sf_x, sf_y, sf; + gdouble mid, dim; + gdouble x0, y0; + int n; + box_t extents; + + extents = self->extents; + + mid = (extents.p2.x + extents.p1.x) / 2.; + dim = (extents.p2.x - extents.p1.x) / 2. * 1.25; + sf_x = self->widget.allocation.width / dim / 2; + + mid = (extents.p2.y + extents.p1.y) / 2.; + dim = (extents.p2.y - extents.p1.y) / 2. * 1.25; + sf_y = self->widget.allocation.height / dim / 2; + + sf = MIN (sf_x, sf_y); + + mid = (extents.p2.x + extents.p1.x) / 2.; + dim = sf_x / sf * (extents.p2.x - extents.p1.x) / 2. * 1.25; + x0 = mid - dim; + mid = (extents.p2.y + extents.p1.y) / 2.; + dim = sf_y / sf * (extents.p2.y - extents.p1.y) / 2. * 1.25; + y0 = mid - dim; + + if (self->pixmap_width != self->widget.allocation.width || + self->pixmap_height != self->widget.allocation.height) + { + cairo_surface_destroy (self->pixmap); + self->pixmap = pixmap_create (self, cairo_get_target (cr)); + self->pixmap_width = self->widget.allocation.width; + self->pixmap_height = self->widget.allocation.height; + } + + cairo_set_source_surface (cr, self->pixmap, 0, 0); + cairo_paint (cr); + + if (self->contours == NULL) + return; + + /* draw a zoom view of the area around the mouse */ + if (1) { + double zoom = self->mag_zoom; + int size = self->mag_size; + int mag_x = self->mag_x; + int mag_y = self->mag_y; + + if (1) { + if (self->px + size < self->widget.allocation.width/2) + mag_x = self->px + size/4; + else + mag_x = self->px - size/4 - size; + mag_y = self->py - size/2; + if (mag_y < 0) + mag_y = 0; + if (mag_y + size > self->widget.allocation.height) + mag_y = self->widget.allocation.height - size; + } + + cairo_save (cr); { + /* bottom right */ + cairo_rectangle (cr, mag_x, mag_y, size, size); + cairo_stroke_preserve (cr); + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_fill_preserve (cr); + cairo_clip (cr); + + /* compute roi in extents */ + cairo_translate (cr, mag_x + size/2, mag_y + size/2); + + cairo_save (cr); { + for (contour = self->contours; contour; contour = contour->next) { + if (contour->num_points == 0) + continue; + + cairo_save (cr); { + cairo_scale (cr, zoom, zoom); + cairo_translate (cr, -(self->px / sf + x0), -(self->py /sf + y0)); + switch (contour->direction) { + case -1: + cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); + break; + case 0: + cairo_set_source_rgb (cr, 0.0, 1.0, 0.0); + break; + case 1: + cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); + break; + } + { + const point_t *p = &contour->points[0]; + cairo_arc (cr, p->x, p->y, 4/zoom, 0, 2 * M_PI); + cairo_save (cr); + cairo_identity_matrix (cr); + cairo_stroke (cr); + cairo_restore (cr); + } + for (n = 0; n < contour->num_points; n++) { + const point_t *p = &contour->points[n]; + cairo_arc (cr, p->x, p->y, 2/zoom, 0, 2 * M_PI); + cairo_fill (cr); + } + for (n = 0; n < contour->num_points; n++) { + const point_t *p = &contour->points[n]; + cairo_line_to (cr, p->x, p->y); + } + } cairo_restore (cr); + + switch (contour->direction) { + case -1: + cairo_set_source_rgb (cr, 0.3, 0.3, 0.9); + break; + case 0: + cairo_set_source_rgb (cr, 0.3, 0.9, 0.3); + break; + case 1: + cairo_set_source_rgb (cr, 0.9, 0.3, 0.3); + break; + } + cairo_stroke (cr); + } + } cairo_restore (cr); + + /* grid */ + cairo_save (cr); { + int i; + + cairo_translate (cr, + -zoom*fmod (self->px/sf + x0, 1.), + -zoom*fmod (self->py/sf + y0, 1.)); + zoom /= 2; + for (i = -size/2/zoom; i <= size/2/zoom + 1; i+=2) { + cairo_move_to (cr, zoom*i, -size/2); + cairo_line_to (cr, zoom*i, size/2 + zoom); + cairo_move_to (cr, -size/2, zoom*i); + cairo_line_to (cr, size/2 + zoom, zoom*i); + } + zoom *= 2; + cairo_set_source_rgba (cr, .7, .7, .7, .5); + cairo_set_line_width (cr, 1.); + cairo_stroke (cr); + + for (i = -size/2/zoom - 1; i <= size/2/zoom + 1; i++) { + cairo_move_to (cr, zoom*i, -size/2); + cairo_line_to (cr, zoom*i, size/2 + zoom); + cairo_move_to (cr, -size/2, zoom*i); + cairo_line_to (cr, size/2 + zoom, zoom*i); + } + cairo_set_source_rgba (cr, .1, .1, .1, .5); + cairo_set_line_width (cr, 2.); + cairo_stroke (cr); + } cairo_restore (cr); + + } cairo_restore (cr); + } +} + + +static gdouble +edge_length (const point_t *p1, const point_t *p2) +{ + return hypot (p2->x - p1->x, p2->y - p1->y); +} + +static gdouble +contour_compute_total_length (const contour_t *contour) +{ + int n; + gdouble len = 0.; + for (n = 1; n < contour->num_points; n++) + len += edge_length (&contour->points[n-1], &contour->points[n]); + return len; +} + +static void +trap_view_draw_labels (TrapView *self, cairo_t *cr) +{ + contour_t *contour; + int y = 12; + + for (contour = self->contours; contour; contour = contour->next) { + double total_length = contour_compute_total_length (contour) / 256.; + PangoLayout *layout; + gint width, height; + GString *string; + gchar *str; + + if (contour->num_points == 0) + continue; + + string = g_string_new (NULL); + g_string_append_printf (string, + "Number of points:\t%d\n" + "Total length of contour: \t%.2f", + contour->num_points, + total_length); + + str = g_string_free (string, FALSE); + layout = gtk_widget_create_pango_layout (&self->widget, str); + g_free (str); + + pango_layout_get_pixel_size (layout, &width, &height); + + switch (contour->direction) { + case -1: + cairo_set_source_rgb (cr, 0.9, 0.3, 0.3); + break; + case 0: + cairo_set_source_rgb (cr, 0.3, 0.9, 0.3); + break; + case 1: + cairo_set_source_rgb (cr, 0.3, 0.3, 0.9); + break; + } + + cairo_move_to (cr, 10, y); + pango_cairo_show_layout (cr, layout); + g_object_unref (layout); + + y += height + 4; + } +} + +static gboolean +trap_view_expose (GtkWidget *w, GdkEventExpose *ev) +{ + TrapView *self = (TrapView *) w; + cairo_t *cr; + + cr = gdk_cairo_create (w->window); + gdk_cairo_region (cr, ev->region); + cairo_clip (cr); + + trap_view_draw (self, cr); + trap_view_draw_labels (self, cr); + + cairo_destroy (cr); + return FALSE; +} + +static gboolean +trap_view_key_press (GtkWidget *w, GdkEventKey *ev) +{ + switch (ev->keyval) { + case GDK_Escape: + case GDK_Q: + gtk_main_quit (); + break; + } + + return FALSE; +} + +static gboolean +trap_view_button_press (GtkWidget *w, GdkEventButton *ev) +{ + TrapView *self = (TrapView *) w; + + if (ev->x < self->mag_x || + ev->y < self->mag_y || + ev->x > self->mag_x + self->mag_size || + ev->y > self->mag_y + self->mag_size) + { + } + else + { + self->in_mag_drag = TRUE; + self->mag_drag_x = ev->x; + self->mag_drag_y = ev->y; + } + + return FALSE; +} + +static gboolean +trap_view_button_release (GtkWidget *w, GdkEventButton *ev) +{ + TrapView *self = (TrapView *) w; + + self->in_mag_drag = FALSE; + + return FALSE; +} + +static void +trap_view_update_mouse (TrapView *self, GdkEventMotion *ev) +{ + self->px = ev->x; + self->py = ev->y; + + gtk_widget_queue_draw (&self->widget); +} + +static void +trap_view_update_magnifier (TrapView *self, gint *xy) +{ + self->mag_x = xy[0]; + self->mag_y = xy[1]; + + gtk_widget_queue_draw (&self->widget); +} + +static gboolean +trap_view_motion (GtkWidget *w, GdkEventMotion *ev) +{ + TrapView *self = (TrapView *) w; + + if (self->in_mag_drag) { + int xy[2]; + + xy[0] = self->mag_x + ev->x - self->mag_drag_x; + xy[1] = self->mag_y + ev->y - self->mag_drag_y; + + trap_view_update_magnifier (self, xy); + + self->mag_drag_x = ev->x; + self->mag_drag_y = ev->y; + } else if (ev->x < self->mag_x || + ev->y < self->mag_y || + ev->x > self->mag_x + self->mag_size || + ev->y > self->mag_y + self->mag_size) + { + trap_view_update_mouse (self, ev); + } + + return FALSE; +} + +static void +trap_view_realize (GtkWidget *widget) +{ + GdkWindowAttr attributes; + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget) | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_KEY_PRESS_MASK | + GDK_KEY_RELEASE_MASK | + GDK_POINTER_MOTION_MASK | + GDK_BUTTON_MOTION_MASK | + GDK_EXPOSURE_MASK; + + widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), + &attributes, + GDK_WA_X | GDK_WA_Y | + GDK_WA_VISUAL | GDK_WA_COLORMAP); + gdk_window_set_user_data (widget->window, widget); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); +} + +static void +trap_view_size_allocate (GtkWidget *w, GdkRectangle *r) +{ + TrapView *self = (TrapView *) w; + + GTK_WIDGET_CLASS (trap_view_parent_class)->size_allocate (w, r); + + self->mag_x = w->allocation.width - self->mag_size - 10; + self->mag_y = w->allocation.height - self->mag_size - 10; +} + +static void +trap_view_finalize (GObject *obj) +{ + G_OBJECT_CLASS (trap_view_parent_class)->finalize (obj); +} + +static void +trap_view_class_init (TrapViewClass *klass) +{ + GObjectClass *object_class = (GObjectClass *) klass; + GtkWidgetClass *widget_class = (GtkWidgetClass *) klass; + + object_class->finalize = trap_view_finalize; + + widget_class->realize = trap_view_realize; + widget_class->size_allocate = trap_view_size_allocate; + widget_class->expose_event = trap_view_expose; + widget_class->key_press_event = trap_view_key_press; + widget_class->button_press_event = trap_view_button_press; + widget_class->button_release_event = trap_view_button_release; + widget_class->motion_notify_event = trap_view_motion; +} + +static void +trap_view_init (TrapView *self) +{ + self->mag_zoom = 64; + self->mag_size = 200; + + self->extents.p1.x = G_MAXDOUBLE; + self->extents.p1.y = G_MAXDOUBLE; + self->extents.p2.x = -G_MAXDOUBLE; + self->extents.p2.y = -G_MAXDOUBLE; + + GTK_WIDGET_SET_FLAGS (self, GTK_CAN_FOCUS); +} + +static contour_t * +_contour_add_point (TrapView *tv, contour_t *contour, point_t *p) +{ + if (contour == NULL) + return NULL; + + if (p->y < tv->extents.p1.y) + tv->extents.p1.y = p->y; + if (p->y > tv->extents.p2.y) + tv->extents.p2.y = p->y; + + if (p->x < tv->extents.p1.x) + tv->extents.p1.x = p->x; + if (p->x > tv->extents.p2.x) + tv->extents.p2.x = p->x; + + if (contour->num_points == contour->size) { + int newsize = 2 * contour->size; + void *newcontour; + + newcontour = g_realloc (contour, + sizeof (contour_t) + newsize * sizeof (point_t)); + if (newcontour == NULL) + return contour; + + contour = newcontour; + contour->size = newsize; + + if (contour->next != NULL) + contour->next->prev = newcontour; + if (contour->prev != NULL) + contour->prev->next = newcontour; + else + tv->contours = newcontour; + } + + contour->points[contour->num_points++] = *p; + + return contour; +} + +static contour_t * +contour_new (TrapView *tv, int direction) +{ + contour_t *t; + + t = g_malloc (sizeof (contour_t) + 128 * sizeof (point_t)); + t->direction = direction; + t->prev = NULL; + t->next = tv->contours; + if (tv->contours) + tv->contours->prev = t; + tv->contours = t; + + t->size = 128; + t->num_points = 0; + + return t; +} + +int +main (int argc, char **argv) +{ + TrapView *tv; + contour_t *contour = NULL; + GtkWidget *window; + FILE *file; + char *line = NULL; + size_t len = 0; + + gtk_init (&argc, &argv); + + tv = g_object_new (trap_view_get_type (), NULL); + + file = fopen (argv[1], "r"); + if (file != NULL) { + while (getline (&line, &len, file) != -1) { + point_t p; + int direction; + + if (sscanf (line, "contour: direction=%d", &direction)) { + if (contour) + g_print ("read %d contour\n", contour->num_points); + + contour = contour_new (tv, direction); + } else if (sscanf (line, " [%*d] = (%lf, %lf)", &p.x, &p.y) == 2) { + contour = _contour_add_point (tv, contour, &p); + } + } + + if (contour) + g_print ("read %d contour\n", contour->num_points); + + g_print ("extents=(%lg, %lg), (%lg, %lg)\n", + tv->extents.p1.x, tv->extents.p1.y, + tv->extents.p2.x, tv->extents.p2.y); + fclose (file); + } + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + g_signal_connect (window, "delete-event", + G_CALLBACK (gtk_main_quit), NULL); + gtk_widget_set_size_request (window, 800, 800); + gtk_container_add (GTK_CONTAINER (window), &tv->widget); + gtk_widget_show_all (window); + + gtk_main (); + return 0; +} diff --git a/local/recipes/libs/cairo/source/util/show-edges.c b/local/recipes/libs/cairo/source/util/show-edges.c new file mode 100644 index 0000000000..c27900333c --- /dev/null +++ b/local/recipes/libs/cairo/source/util/show-edges.c @@ -0,0 +1,1222 @@ +#include "config.h" + +#include +#include +#include +#include +#include + +typedef struct _point { + gdouble x, y; +} point_t; +typedef struct _box { + point_t p1, p2; +} box_t; +typedef struct _line { + point_t p1, p2; +} line_t; +typedef struct _trapezoid { + gdouble top, bottom; + line_t left, right; +} trapezoid_t; +typedef struct _traps { + struct _traps *next, *prev; + box_t extents; + int num_traps; + int size; + trapezoid_t traps[0]; +} traps_t; + +typedef struct _edge { + line_t line; + gdouble top, bottom; + point_t p1, p2; + int dir; +} edge_t; +typedef struct _edges { + struct _edges *next, *prev; + box_t extents; + int num_edges; + int size; + edge_t edges[0]; +} edges_t; + +typedef struct _TrapView { + GtkWidget widget; + + struct _TrapView *group_head; + struct _TrapView *group_next; + struct _TrapView *group_prev; + + traps_t *traps_list; + traps_t *current_traps; + + edges_t *edges_list; + edges_t *current_edges; + + double px, py; + + gint mag_x, mag_y; + gint mag_size; + gdouble mag_zoom; + gboolean in_mag_drag; + gint mag_drag_x, mag_drag_y; +} TrapView; + +typedef struct _TrapViewClass { + GtkWidgetClass parent_class; +} TrapViewClass; + +G_DEFINE_TYPE (TrapView, trap_view, GTK_TYPE_WIDGET) + +static gdouble +_compute_intersection_x_for_y (const line_t *line, + gdouble y) +{ + gdouble dx = line->p2.x - line->p1.x; + gdouble dy = line->p2.y - line->p1.y; + gdouble x; + + if (y == line->p1.y) + return line->p1.x; + if (y == line->p2.y) + return line->p2.x; + + x = line->p1.x; + if (dy != 0) + x += (y - line->p1.y)*dx/dy; + return x; +} + +static void +_compute_intersection_point (const line_t *line, + gdouble y, + point_t *p) +{ + p->x = _compute_intersection_x_for_y (line, p->y = y); +} + +static void +trap_view_draw (TrapView *self, cairo_t *cr) +{ + traps_t *traps; + edges_t *edges; + gdouble sf_x, sf_y, sf; + gdouble mid, dim; + gdouble x0, x1, y0, y1; + double dash[2] = {8, 8}; + double dots[2] = {0., 1.}; + int n; + box_t extents; + point_t p; + + cairo_save (cr); + cairo_save (cr); + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + cairo_restore (cr); + + traps = self->current_traps; + edges = self->current_edges; + if (traps == NULL && edges == NULL) + return; + + if (traps != NULL) { + extents = traps->extents; + if (edges != NULL) { + if (edges->extents.p1.x < extents.p1.x) + extents.p1.x = edges->extents.p1.x; + if (edges->extents.p1.y < extents.p1.y) + extents.p1.y = edges->extents.p1.y; + if (edges->extents.p2.x > extents.p2.x) + extents.p2.x = edges->extents.p2.x; + if (edges->extents.p2.y > extents.p2.y) + extents.p2.y = edges->extents.p2.y; + } + } else + extents = edges->extents; + + mid = (extents.p2.x + extents.p1.x) / 2.; + dim = (extents.p2.x - extents.p1.x) / 2. * 1.25; + sf_x = self->widget.allocation.width / dim / 2; + + mid = (extents.p2.y + extents.p1.y) / 2.; + dim = (extents.p2.y - extents.p1.y) / 2. * 1.25; + sf_y = self->widget.allocation.height / dim / 2; + + sf = MIN (sf_x, sf_y); + + mid = (extents.p2.x + extents.p1.x) / 2.; + dim = sf_x / sf * (extents.p2.x - extents.p1.x) / 2. * 1.25; + x0 = mid - dim; + x1 = mid + dim; + mid = (extents.p2.y + extents.p1.y) / 2.; + dim = sf_y / sf * (extents.p2.y - extents.p1.y) / 2. * 1.25; + y0 = mid - dim; + y1 = mid + dim; + + if (traps != NULL) { + cairo_save (cr); + cairo_scale (cr, sf, sf); + cairo_translate (cr, -x0, -y0); + cairo_set_source_rgba (cr, 0, 1, 0, .2); + for (n = 0; n < traps->num_traps; n++) { + const trapezoid_t *t = &traps->traps[n]; + + _compute_intersection_point (&t->left, t->top, &p); + cairo_move_to (cr, p.x, p.y); + _compute_intersection_point (&t->right, t->top, &p); + cairo_line_to (cr, p.x, p.y); + _compute_intersection_point (&t->right, t->bottom, &p); + cairo_line_to (cr, p.x, p.y); + _compute_intersection_point (&t->left, t->bottom, &p); + cairo_line_to (cr, p.x, p.y); + cairo_close_path (cr); + cairo_fill (cr); + } + cairo_restore (cr); + } + + if (edges == NULL) { + cairo_save (cr); + + /* top, bottom */ + cairo_save (cr); { + cairo_matrix_t m; + cairo_matrix_init_scale (&m, sf, sf); + cairo_matrix_translate (&m, -x0, -y0); + + cairo_set_line_width (cr, 1.); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + for (n = 0; n < traps->num_traps; n++) { + const trapezoid_t *t = &traps->traps[n]; + + _compute_intersection_point (&t->left, t->top, &p); + cairo_matrix_transform_point (&m, &p.x, &p.y); + cairo_move_to (cr, floor (p.x), floor (p.y) + .5); + cairo_set_dash (cr, dash, 2, fmod (floor (p.x), dash[0] + dash[1])); + + _compute_intersection_point (&t->right, t->top, &p); + cairo_matrix_transform_point (&m, &p.x, &p.y); + cairo_line_to (cr, ceil (p.x), floor (p.y) + .5); + cairo_stroke (cr); + + _compute_intersection_point (&t->left, t->bottom, &p); + cairo_matrix_transform_point (&m, &p.x, &p.y); + cairo_move_to (cr, floor (p.x), floor (p.y) + .5); + cairo_set_dash (cr, dash, 2, fmod (floor (p.x), dash[0] + dash[1])); + + _compute_intersection_point (&t->right, t->bottom, &p); + cairo_matrix_transform_point (&m, &p.x, &p.y); + cairo_line_to (cr, ceil (p.x), floor (p.y) + .5); + cairo_stroke (cr); + } + } cairo_restore (cr); + + /* left extents */ + cairo_save (cr); { + cairo_save (cr); { + cairo_scale (cr, sf, sf); + cairo_translate (cr, -x0, -y0); + + for (n = 0; n < traps->num_traps; n++) { + const trapezoid_t *t = &traps->traps[n]; + cairo_move_to (cr, t->left.p1.x, t->left.p1.y); + cairo_line_to (cr, t->left.p2.x, t->left.p2.y); + } + } cairo_restore (cr); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_set_line_width (cr, 1.); + cairo_set_dash (cr, dash, 2, 0.); + cairo_stroke (cr); + } cairo_restore (cr); + + /* left line */ + cairo_save (cr); { + cairo_save (cr); { + cairo_scale (cr, sf, sf); + cairo_translate (cr, -x0, -y0); + + for (n = 0; n < traps->num_traps; n++) { + const trapezoid_t *t = &traps->traps[n]; + _compute_intersection_point (&t->left, t->top, &p); + cairo_move_to (cr, p.x, p.y); + _compute_intersection_point (&t->left, t->bottom, &p); + cairo_line_to (cr, p.x, p.y); + } + } cairo_restore (cr); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_stroke (cr); + } cairo_restore (cr); + + /* right extents */ + cairo_save (cr); { + cairo_save (cr); { + cairo_scale (cr, sf, sf); + cairo_translate (cr, -x0, -y0); + + for (n = 0; n < traps->num_traps; n++) { + const trapezoid_t *t = &traps->traps[n]; + cairo_move_to (cr, t->right.p1.x, t->right.p1.y); + cairo_line_to (cr, t->right.p2.x, t->right.p2.y); + } + } cairo_restore (cr); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_set_line_width (cr, 1.); + cairo_set_dash (cr, dash, 2, 0.); + cairo_stroke (cr); + } cairo_restore (cr); + + /* right line */ + cairo_save (cr); { + cairo_save (cr); { + cairo_scale (cr, sf, sf); + cairo_translate (cr, -x0, -y0); + + for (n = 0; n < traps->num_traps; n++) { + const trapezoid_t *t = &traps->traps[n]; + _compute_intersection_point (&t->right, t->top, &p); + cairo_move_to (cr, p.x, p.y); + _compute_intersection_point (&t->right, t->bottom, &p); + cairo_line_to (cr, p.x, p.y); + } cairo_restore (cr); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_stroke (cr); + } cairo_restore (cr); + } + + /* end-points */ + cairo_save (cr); { + cairo_save (cr); { + cairo_scale (cr, sf, sf); + cairo_translate (cr, -x0, -y0); + + for (n = 0; n < traps->num_traps; n++) { + const trapezoid_t *t = &traps->traps[n]; + _compute_intersection_point (&t->left, t->top, &p); + cairo_move_to (cr, p.x, p.y); + cairo_close_path (cr); + _compute_intersection_point (&t->left, t->bottom, &p); + cairo_move_to (cr, p.x, p.y); + cairo_close_path (cr); + _compute_intersection_point (&t->right, t->top, &p); + cairo_move_to (cr, p.x, p.y); + cairo_close_path (cr); + _compute_intersection_point (&t->right, t->bottom, &p); + cairo_move_to (cr, p.x, p.y); + cairo_close_path (cr); + } + } cairo_restore (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_set_dash (cr, dots, 2, 0.); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + cairo_set_line_width (cr, 4.); + cairo_stroke (cr); + } cairo_restore (cr); + + cairo_restore (cr); + } else { + cairo_save (cr); + + for (n = 0; n < edges->num_edges; n++) { + const edge_t *e = &edges->edges[n]; + + cairo_save (cr); { + cairo_scale (cr, sf, sf); + cairo_translate (cr, -x0, -y0); + cairo_move_to (cr, e->p1.x, e->p1.y); + cairo_line_to (cr, e->p2.x, e->p2.y); + } cairo_restore (cr); + + if (e->dir < 0) { + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_set_dash (cr, dash, 2, dash[0]); + } else { + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_set_dash (cr, dash, 2, 0.); + } + + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + cairo_set_line_width (cr, 1.); + cairo_stroke (cr); + + cairo_save (cr); { + cairo_scale (cr, sf, sf); + cairo_translate (cr, -x0, -y0); + cairo_move_to (cr, e->p1.x, e->p1.y); + cairo_close_path (cr); + cairo_move_to (cr, e->p2.x, e->p2.y); + cairo_close_path (cr); + } cairo_restore (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_set_dash (cr, dots, 2, 0.); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + cairo_set_line_width (cr, 4.); + cairo_stroke (cr); + } + + cairo_restore (cr); + } + + /* draw a zoom view of the area around the mouse */ + { + cairo_save (cr); + double zoom = self->mag_zoom; + int size = self->mag_size; + + /* bottom right */ + cairo_rectangle (cr, self->mag_x, self->mag_y, size, size); + cairo_stroke_preserve (cr); + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_fill_preserve (cr); + cairo_clip (cr); + + /* compute roi in extents */ + cairo_translate (cr, self->mag_x + size/2, self->mag_y + size/2); + + if (traps != NULL) { + cairo_save (cr); + cairo_scale (cr, zoom, zoom); + cairo_translate (cr, -(self->px / sf + x0), -(self->py /sf + y0)); + for (n = 0; n < traps->num_traps; n++) { + const trapezoid_t *t = &traps->traps[n]; + + _compute_intersection_point (&t->left, t->top, &p); + cairo_move_to (cr, p.x, p.y); + _compute_intersection_point (&t->right, t->top, &p); + cairo_line_to (cr, p.x, p.y); + _compute_intersection_point (&t->right, t->bottom, &p); + cairo_line_to (cr, p.x, p.y); + _compute_intersection_point (&t->left, t->bottom, &p); + cairo_line_to (cr, p.x, p.y); + cairo_close_path (cr); + cairo_set_source_rgba (cr, 0, 1, 0, .2); + cairo_fill (cr); + } + cairo_restore (cr); + } + + if (edges == NULL) { + cairo_save (cr); { + cairo_matrix_t m; + cairo_matrix_init_scale (&m, zoom, zoom); + cairo_matrix_translate (&m, -(self->px / sf + x0), -(self->py /sf + y0)); + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_set_line_width (cr, 1.); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + for (n = 0; n < traps->num_traps; n++) { + const trapezoid_t *t = &traps->traps[n]; + + _compute_intersection_point (&t->left, t->top, &p); + cairo_matrix_transform_point (&m, &p.x, &p.y); + cairo_move_to (cr, floor (p.x), floor (p.y) + .5); + cairo_set_dash (cr, dash, 2, fmod (floor (p.x), dash[0] + dash[1])); + + _compute_intersection_point (&t->right, t->top, &p); + cairo_matrix_transform_point (&m, &p.x, &p.y); + cairo_line_to (cr, ceil (p.x), floor (p.y) + .5); + cairo_stroke (cr); + + _compute_intersection_point (&t->left, t->bottom, &p); + cairo_matrix_transform_point (&m, &p.x, &p.y); + cairo_move_to (cr, floor (p.x), floor (p.y) + .5); + cairo_set_dash (cr, dash, 2, fmod (floor (p.x), dash[0] + dash[1])); + + _compute_intersection_point (&t->right, t->bottom, &p); + cairo_matrix_transform_point (&m, &p.x, &p.y); + cairo_line_to (cr, ceil (p.x), floor (p.y) + .5); + cairo_stroke (cr); + } + } cairo_restore (cr); + + cairo_save (cr); { /* left extents */ + cairo_save (cr); { + cairo_scale (cr, zoom, zoom); + cairo_translate (cr, -(self->px / sf + x0), -(self->py /sf + y0)); + for (n = 0; n < traps->num_traps; n++) { + const trapezoid_t *t = &traps->traps[n]; + cairo_move_to (cr, t->left.p1.x, t->left.p1.y); + cairo_line_to (cr, t->left.p2.x, t->left.p2.y); + } + } cairo_restore (cr); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_set_line_width (cr, .5); + cairo_set_dash (cr, dash, 2, 0.); + cairo_stroke (cr); + } cairo_restore (cr); + cairo_save (cr); { /* right extents */ + cairo_save (cr); { + cairo_scale (cr, zoom, zoom); + cairo_translate (cr, -(self->px / sf + x0), -(self->py /sf + y0)); + + for (n = 0; n < traps->num_traps; n++) { + const trapezoid_t *t = &traps->traps[n]; + cairo_move_to (cr, t->right.p1.x, t->right.p1.y); + cairo_line_to (cr, t->right.p2.x, t->right.p2.y); + } + } cairo_restore (cr); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_set_line_width (cr, .5); + cairo_set_dash (cr, dash, 2, 0.); + cairo_stroke (cr); + } cairo_restore (cr); + + cairo_save (cr); { /* left lines */ + cairo_save (cr); + cairo_scale (cr, zoom, zoom); + cairo_translate (cr, -(self->px / sf + x0), -(self->py /sf + y0)); + for (n = 0; n < traps->num_traps; n++) { + const trapezoid_t *t = &traps->traps[n]; + _compute_intersection_point (&t->left, t->top, &p); + cairo_move_to (cr, p.x, p.y); + _compute_intersection_point (&t->left, t->bottom, &p); + cairo_line_to (cr, p.x, p.y); + } + cairo_restore (cr); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_stroke (cr); + } cairo_restore (cr); + cairo_save (cr); { /* right lines */ + cairo_save (cr); + cairo_scale (cr, zoom, zoom); + cairo_translate (cr, -(self->px / sf + x0), -(self->py /sf + y0)); + for (n = 0; n < traps->num_traps; n++) { + const trapezoid_t *t = &traps->traps[n]; + _compute_intersection_point (&t->right, t->top, &p); + cairo_move_to (cr, p.x, p.y); + _compute_intersection_point (&t->right, t->bottom, &p); + cairo_line_to (cr, p.x, p.y); + } + cairo_restore (cr); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_stroke (cr); + } cairo_restore (cr); + + /* end-points */ + cairo_save (cr); { + double dots[2] = {0., 1.}; + + cairo_save (cr); + cairo_scale (cr, zoom, zoom); + cairo_translate (cr, -(self->px / sf + x0), -(self->py /sf + y0)); + for (n = 0; n < traps->num_traps; n++) { + const trapezoid_t *t = &traps->traps[n]; + _compute_intersection_point (&t->left, t->top, &p); + cairo_move_to (cr, p.x, p.y); + cairo_close_path (cr); + _compute_intersection_point (&t->left, t->bottom, &p); + cairo_move_to (cr, p.x, p.y); + cairo_close_path (cr); + _compute_intersection_point (&t->right, t->top, &p); + cairo_move_to (cr, p.x, p.y); + cairo_close_path (cr); + _compute_intersection_point (&t->right, t->bottom, &p); + cairo_move_to (cr, p.x, p.y); + cairo_close_path (cr); + } + cairo_restore (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_set_dash (cr, dots, 2, 0.); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + cairo_set_line_width (cr, 4.); + cairo_stroke (cr); + } cairo_restore (cr); + } else { + cairo_save (cr); + + for (n = 0; n < edges->num_edges; n++) { + const edge_t *e = &edges->edges[n]; + + cairo_save (cr); { + cairo_scale (cr, zoom, zoom); + cairo_translate (cr, -(self->px / sf + x0), -(self->py /sf + y0)); + cairo_move_to (cr, e->p1.x, e->p1.y); + cairo_line_to (cr, e->p2.x, e->p2.y); + } cairo_restore (cr); + + if (e->dir < 0) { + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_set_dash (cr, dash, 2, dash[0]); + } else { + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_set_dash (cr, dash, 2, 0.); + } + + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + cairo_set_line_width (cr, 1.); + cairo_stroke (cr); + + cairo_save (cr); { + cairo_scale (cr, zoom, zoom); + cairo_translate (cr, -(self->px / sf + x0), -(self->py /sf + y0)); + cairo_move_to (cr, e->p1.x, e->p1.y); + cairo_close_path (cr); + cairo_move_to (cr, e->p2.x, e->p2.y); + cairo_close_path (cr); + } cairo_restore (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_set_dash (cr, dots, 2, 0.); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + cairo_set_line_width (cr, 4.); + cairo_stroke (cr); + } + + cairo_restore (cr); + } + + /* grid */ + cairo_save (cr); { + int i; + + cairo_translate (cr, + -zoom*fmod (self->px/sf + x0, 1.), + -zoom*fmod (self->py/sf + y0, 1.)); + for (i = -size/2/zoom - 1; i <= size/2/zoom + 1; i++) { + cairo_move_to (cr, zoom*i, -size/2); + cairo_line_to (cr, zoom*i, size/2 + zoom); + cairo_move_to (cr, -size/2, zoom*i); + cairo_line_to (cr, size/2 + zoom, zoom*i); + } + cairo_set_source_rgba (cr, .7, .7, .7, .5); + cairo_set_line_width (cr, 1.); + cairo_stroke (cr); + } cairo_restore (cr); + } + + cairo_restore (cr); +} + + +static gdouble +edge_length (const edge_t *e) +{ + return hypot (e->p2.x - e->p1.x, e->p2.y - e->p1.y); +} + +static gdouble +edges_compute_total_length (const edges_t *edges) +{ + int n; + gdouble len = 0.; + for (n = 0; n < edges->num_edges; n++) + len += edge_length (&edges->edges[n]); + return len; +} + +static gdouble +trapezoid_area (const trapezoid_t *t) +{ + gdouble inner_left, inner_right; + gdouble outer_left, outer_right; + gdouble height; + gdouble area; + + /* split into 3 sections: a rectangle with a pair of triangular bookends */ + inner_left = _compute_intersection_x_for_y (&t->left, t->top); + outer_left = _compute_intersection_x_for_y (&t->left, t->bottom); + if (outer_left > inner_left) { + gdouble t = outer_left; + outer_left = inner_left; + inner_left = t; + } + + inner_right = _compute_intersection_x_for_y (&t->right, t->top); + outer_right = _compute_intersection_x_for_y (&t->right, t->bottom); + if (outer_right > inner_right) { + gdouble t = outer_right; + outer_right = inner_right; + inner_right = t; + } + + if (outer_left > outer_right) { /* reverse */ + gdouble t; + + t = outer_left; + outer_left = inner_right; + inner_right = t; + + t = inner_left; + inner_left = outer_right; + outer_right = t; + } + + height = t->bottom - t->top; + area = (inner_left - outer_left) * height / 2; + area += (outer_right - inner_right) * height / 2; + area += (inner_right - inner_left) * height; + + return area; +} + +static gdouble +traps_compute_total_area (const traps_t *traps) +{ + int n; + gdouble area = 0.; + for (n = 0; n < traps->num_traps; n++) + area += trapezoid_area (&traps->traps[n]); + return area; +} + +static void +trap_view_draw_labels (TrapView *self, cairo_t *cr) +{ + PangoLayout *layout; + gint width, height; + GString *string; + gchar *str; + traps_t *traps; + edges_t *edges; + + string = g_string_new (NULL); + + traps = self->current_traps; + if (traps != NULL) { + /* convert total area from fixed-point (assuming 24.8) */ + gdouble total_area = traps_compute_total_area (traps) / (256. * 256.); + g_string_append_printf (string, + "Number of trapezoids:\t%d\n" + "Total area of trapezoids:\t%.2f\n", + traps->num_traps, + total_area); + } + + edges = self->current_edges; + if (edges != NULL) { + double total_length = edges_compute_total_length (edges) / 256.; + g_string_append_printf (string, + "Number of edges:\t%d\n" + "Total length of edges: \t%.2f\n", + edges->num_edges, + total_length); + } + + str = g_string_free (string, FALSE); + layout = gtk_widget_create_pango_layout (&self->widget, str); + g_free (str); + + pango_layout_get_pixel_size (layout, &width, &height); + + cairo_move_to (cr, 10, 40); + pango_cairo_show_layout (cr, layout); + g_object_unref (layout); +} + +static gboolean +trap_view_expose (GtkWidget *w, GdkEventExpose *ev) +{ + TrapView *self = (TrapView *) w; + cairo_t *cr; + + cr = gdk_cairo_create (w->window); + gdk_cairo_region (cr, ev->region); + cairo_clip (cr); + + trap_view_draw (self, cr); + trap_view_draw_labels (self, cr); + + cairo_destroy (cr); + return FALSE; +} + +static void +trap_view_advance (TrapView *self) +{ + if (self->current_traps && self->current_traps->prev) + self->current_traps = self->current_traps->prev; + if (self->current_edges && self->current_edges->prev) + self->current_edges = self->current_edges->prev; + gtk_widget_queue_draw (&self->widget); +} + +static void +trap_view_back (TrapView *self) +{ + if (self->current_traps && self->current_traps->next) + self->current_traps = self->current_traps->next; + if (self->current_edges && self->current_edges->next) + self->current_edges = self->current_edges->next; + gtk_widget_queue_draw (&self->widget); +} + +static void +trap_view_group_foreach (TrapView *group, GFunc func, gpointer data) +{ + while (group) { + func (group, data); + group = group->group_next; + } +} + +static gboolean +trap_view_key_press (GtkWidget *w, GdkEventKey *ev) +{ + TrapView *self = (TrapView *) w; + + switch (ev->keyval) { + case GDK_BackSpace: + trap_view_group_foreach (self->group_head, + (GFunc) trap_view_back, + NULL); + break; + + case GDK_space: + trap_view_group_foreach (self->group_head, + (GFunc) trap_view_advance, + NULL); + break; + + case GDK_Return: + trap_view_group_foreach (self->group_head, + (GFunc) trap_view_advance, + NULL); + break; + + case GDK_Escape: + case GDK_Q: + gtk_main_quit (); + break; + } + + return FALSE; +} + +static gboolean +trap_view_button_press (GtkWidget *w, GdkEventButton *ev) +{ + TrapView *self = (TrapView *) w; + + if (ev->x < self->mag_x || + ev->y < self->mag_y || + ev->x > self->mag_x + self->mag_size || + ev->y > self->mag_y + self->mag_size) + { + if (ev->type == GDK_BUTTON_PRESS) { + if (self->current_traps == NULL) + return FALSE; + + if (ev->button == 1) { + trap_view_group_foreach (self->group_head, + (GFunc) trap_view_advance, + NULL); + } else if (ev->button == 3) { + trap_view_group_foreach (self->group_head, + (GFunc) trap_view_back, + NULL); + } + } + } + else + { + self->in_mag_drag = TRUE; + self->mag_drag_x = ev->x; + self->mag_drag_y = ev->y; + } + + return FALSE; +} + +static gboolean +trap_view_button_release (GtkWidget *w, GdkEventButton *ev) +{ + TrapView *self = (TrapView *) w; + + self->in_mag_drag = FALSE; + + return FALSE; +} + +static void +trap_view_update_mouse (TrapView *self, GdkEventMotion *ev) +{ + self->px = ev->x; + self->py = ev->y; + + gtk_widget_queue_draw (&self->widget); +} + +static void +trap_view_update_magnifier (TrapView *self, gint *xy) +{ + self->mag_x = xy[0]; + self->mag_y = xy[1]; + + gtk_widget_queue_draw (&self->widget); +} + +static gboolean +trap_view_motion (GtkWidget *w, GdkEventMotion *ev) +{ + TrapView *self = (TrapView *) w; + + if (self->in_mag_drag) { + int xy[2]; + + xy[0] = self->mag_x + ev->x - self->mag_drag_x; + xy[1] = self->mag_y + ev->y - self->mag_drag_y; + + trap_view_group_foreach (self->group_head, + (GFunc) trap_view_update_magnifier, + xy); + + self->mag_drag_x = ev->x; + self->mag_drag_y = ev->y; + } else if (ev->x < self->mag_x || + ev->y < self->mag_y || + ev->x > self->mag_x + self->mag_size || + ev->y > self->mag_y + self->mag_size) + { + trap_view_group_foreach (self->group_head, + (GFunc) trap_view_update_mouse, + ev); + } + + return FALSE; +} + +static void +trap_view_realize (GtkWidget *widget) +{ + GdkWindowAttr attributes; + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget) | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_KEY_PRESS_MASK | + GDK_KEY_RELEASE_MASK | + GDK_POINTER_MOTION_MASK | + GDK_BUTTON_MOTION_MASK | + GDK_EXPOSURE_MASK; + + widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), + &attributes, + GDK_WA_X | GDK_WA_Y | + GDK_WA_VISUAL | GDK_WA_COLORMAP); + gdk_window_set_user_data (widget->window, widget); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); +} + +static void +trap_view_size_allocate (GtkWidget *w, GdkRectangle *r) +{ + TrapView *self = (TrapView *) w; + + GTK_WIDGET_CLASS (trap_view_parent_class)->size_allocate (w, r); + + self->mag_x = w->allocation.width - self->mag_size - 10; + self->mag_y = w->allocation.height - self->mag_size - 10; +} + +static void +trap_view_finalize (GObject *obj) +{ + G_OBJECT_CLASS (trap_view_parent_class)->finalize (obj); +} + +static void +trap_view_class_init (TrapViewClass *klass) +{ + GObjectClass *object_class = (GObjectClass *) klass; + GtkWidgetClass *widget_class = (GtkWidgetClass *) klass; + + object_class->finalize = trap_view_finalize; + + widget_class->realize = trap_view_realize; + widget_class->size_allocate = trap_view_size_allocate; + widget_class->expose_event = trap_view_expose; + widget_class->key_press_event = trap_view_key_press; + widget_class->button_press_event = trap_view_button_press; + widget_class->button_release_event = trap_view_button_release; + widget_class->motion_notify_event = trap_view_motion; +} + +static void +trap_view_init (TrapView *self) +{ + self->mag_zoom = 10; + self->mag_size = 200; + + GTK_WIDGET_SET_FLAGS (self, GTK_CAN_FOCUS); +} + +static traps_t * +_traps_add_trapezoid (TrapView *tv, traps_t *traps, const trapezoid_t *trap) +{ + if (trap->top < traps->extents.p1.y) + traps->extents.p1.y = trap->top; + if (trap->bottom > traps->extents.p2.y) + traps->extents.p2.y = trap->bottom; + + if (trap->left.p1.x < traps->extents.p1.x) + traps->extents.p1.x = trap->left.p1.x; + if (trap->left.p2.x < traps->extents.p1.x) + traps->extents.p1.x = trap->left.p2.x; + + if (trap->right.p1.x > traps->extents.p2.x) + traps->extents.p2.x = trap->right.p1.x; + if (trap->right.p2.x > traps->extents.p2.x) + traps->extents.p2.x = trap->right.p2.x; + + if (traps->num_traps == traps->size) { + int newsize = 2 * traps->size; + void *newtraps; + + newtraps = g_realloc (traps, + sizeof (traps_t) + newsize * sizeof (trapezoid_t)); + if (newtraps == NULL) + return traps; + + if (tv->current_traps == traps) + tv->current_traps = newtraps; + + traps = newtraps; + traps->size = newsize; + + if (traps->next != NULL) + traps->next->prev = newtraps; + if (traps->prev != NULL) + traps->prev->next = newtraps; + else + tv->traps_list = newtraps; + } + + traps->traps[traps->num_traps++] = *trap; + + return traps; +} + +static traps_t * +traps_new (TrapView *tv) +{ + traps_t *t; + + t = g_malloc (sizeof (traps_t) + 16 * sizeof (trapezoid_t)); + t->prev = NULL; + t->next = tv->traps_list; + if (tv->traps_list) + tv->traps_list->prev = t; + tv->traps_list = t; + + if (tv->current_traps == NULL) + tv->current_traps = t; + + t->size = 16; + t->num_traps = 0; + t->extents.p1.x = G_MAXDOUBLE; + t->extents.p1.y = G_MAXDOUBLE; + t->extents.p2.x = -G_MAXDOUBLE; + t->extents.p2.y = -G_MAXDOUBLE; + + return t; +} + +static edges_t * +_edges_add_edge (TrapView *tv, edges_t *edges, edge_t *e) +{ + if (e->top < edges->extents.p1.y) + edges->extents.p1.y = e->top; + if (e->bottom > edges->extents.p2.y) + edges->extents.p2.y = e->bottom; + + _compute_intersection_point (&e->line, e->top, &e->p1); + _compute_intersection_point (&e->line, e->bottom, &e->p2); + + if (e->p1.x < edges->extents.p1.x) + edges->extents.p1.x = e->p1.x; + if (e->p2.x < edges->extents.p1.x) + edges->extents.p1.x = e->p2.x; + + if (e->p1.x > edges->extents.p2.x) + edges->extents.p2.x = e->p1.x; + if (e->p2.x > edges->extents.p2.x) + edges->extents.p2.x = e->p2.x; + + if (edges->num_edges == edges->size) { + int newsize = 2 * edges->size; + void *newedges; + + newedges = g_realloc (edges, + sizeof (edges_t) + newsize * sizeof (edge_t)); + if (newedges == NULL) + return edges; + + if (tv->current_edges == edges) + tv->current_edges = newedges; + + edges = newedges; + edges->size = newsize; + + if (edges->next != NULL) + edges->next->prev = newedges; + if (edges->prev != NULL) + edges->prev->next = newedges; + else + tv->edges_list = newedges; + } + + edges->edges[edges->num_edges++] = *e; + + return edges; +} + +static edges_t * +edges_new (TrapView *tv) +{ + edges_t *t; + + t = g_malloc (sizeof (edges_t) + 16 * sizeof (edge_t)); + t->prev = NULL; + t->next = tv->edges_list; + if (tv->edges_list) + tv->edges_list->prev = t; + tv->edges_list = t; + + if (tv->current_edges == NULL) + tv->current_edges = t; + + t->size = 16; + t->num_edges = 0; + t->extents.p1.x = G_MAXDOUBLE; + t->extents.p1.y = G_MAXDOUBLE; + t->extents.p2.x = -G_MAXDOUBLE; + t->extents.p2.y = -G_MAXDOUBLE; + + return t; +} + +int +main (int argc, char **argv) +{ + TrapView *tv, *tv2, *group_head = NULL, *group_prev = NULL; + traps_t *traps; + edges_t *edges; + GtkWidget *window, *hbox; + FILE *file; + char *line = NULL; + size_t len = 0; + + gtk_init (&argc, &argv); + + hbox = gtk_hbox_new (TRUE, 0); + + tv = g_object_new (trap_view_get_type (), NULL); + gtk_box_pack_start (GTK_BOX (hbox), &tv->widget, TRUE, TRUE, 0); + gtk_widget_show (&tv->widget); + + tv->group_prev = group_prev; + tv->group_next = NULL; + if (group_prev) + group_prev->group_next = tv; + group_prev = tv; + if (group_head == NULL) + group_head = tv; + tv->group_head = group_head; + + file = fopen (argv[1], "r"); + if (file != NULL) { + edges = edges_new (tv); + while (getline (&line, &len, file) != -1) { + edge_t e; + + if (sscanf (line, + "(%lf, %lf), (%lf, %lf) %lf %lf %d", + &e.line.p1.x, &e.line.p1.y, + &e.line.p2.x, &e.line.p2.y, + &e.top, &e.bottom, + &e.dir) == 7) { + edges = _edges_add_edge (tv, edges, &e); + } else { + if (edges->num_edges) { + g_print ("read %d edges\n", edges->num_edges); + g_print ("extents=(%lg, %lg), (%lg, %lg)\n", + edges->extents.p1.x, edges->extents.p1.y, + edges->extents.p2.x, edges->extents.p2.y); + edges = edges_new (tv); + } + } + } + + if (edges->num_edges) { + g_print ("read %d edges\n", edges->num_edges); + g_print ("extents=(%lg, %lg), (%lg, %lg)\n", + edges->extents.p1.x, edges->extents.p1.y, + edges->extents.p2.x, edges->extents.p2.y); + } + + fclose (file); + } + + file = fopen (argv[2], "r"); + if (file != NULL) { + traps = traps_new (tv); + while (getline (&line, &len, file) != -1) { + trapezoid_t t; + + if (sscanf (line, + "%lf %lf L:(%lf, %lf), (%lf, %lf) R:(%lf, %lf), (%lf, %lf)", + &t.top, &t.bottom, + &t.left.p1.x, &t.left.p1.y, + &t.left.p2.x, &t.left.p2.y, + &t.right.p1.x, &t.right.p1.y, + &t.right.p2.x, &t.right.p2.y) == 10) { + traps = _traps_add_trapezoid (tv, traps, &t); + } else { + if (traps->num_traps) { + g_print ("read %d trapezoids\n", traps->num_traps); + g_print ("extents=(%lg, %lg), (%lg, %lg)\n", + traps->extents.p1.x, traps->extents.p1.y, + traps->extents.p2.x, traps->extents.p2.y); + traps = traps_new (tv); + } + } + } + + if (traps->num_traps) { + g_print ("read %d trapezoids\n", traps->num_traps); + g_print ("extents=(%lg, %lg), (%lg, %lg)\n", + traps->extents.p1.x, traps->extents.p1.y, + traps->extents.p2.x, traps->extents.p2.y); + } + + fclose (file); + } + + free (line); + + tv2 = g_object_new (trap_view_get_type (), NULL); + gtk_box_pack_start (GTK_BOX (hbox), &tv2->widget, TRUE, TRUE, 0); + gtk_widget_show (&tv2->widget); + + tv2->traps_list = tv->traps_list; + tv2->current_traps = tv->current_traps; + + tv2->group_prev = group_prev; + tv2->group_next = NULL; + group_prev->group_next = tv2; + group_prev = tv2; + tv2->group_head = group_head; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + g_signal_connect (window, "delete-event", + G_CALLBACK (gtk_main_quit), NULL); + gtk_widget_set_size_request (window, 800, 800); + gtk_container_add (GTK_CONTAINER (window), hbox); + gtk_widget_show (hbox); + gtk_widget_show (window); + + gtk_main (); + return 0; +} diff --git a/local/recipes/libs/cairo/source/util/show-events.c b/local/recipes/libs/cairo/source/util/show-events.c new file mode 100644 index 0000000000..da824dd9d7 --- /dev/null +++ b/local/recipes/libs/cairo/source/util/show-events.c @@ -0,0 +1,846 @@ +#include "config.h" + +#include +#include +#include +#include +#include +#include + +typedef struct _point { + gdouble x, y; +} point_t; +typedef struct _box { + point_t p1, p2; +} box_t; +typedef struct _line { + point_t p1, p2; +} line_t; + +typedef struct _edge { + gulong id; + line_t line; + gdouble top, bottom; + point_t p1, p2; + int dir; +} edge_t; +typedef struct _trapezoid { + gdouble top, bottom; + const edge_t *left, *right; +} trapezoid_t; +typedef struct _traps { + int num_traps; + int size; + trapezoid_t traps[0]; +} traps_t; + +typedef struct _edges { + GHashTable *ht; + + int num_edges; + int size; + edge_t edges[0]; +} edges_t; + +typedef struct _event { + enum { + START_EDGE, + END_EDGE, + INTERSECTION, + START_TRAP, + END_TRAP, + } type; + + int x, y; /* (top, bottom) for trap */ + long e1, e2; +} event_t; + +typedef struct _events { + struct _events *prev, *next; + + box_t extents; + edges_t *edges; + traps_t *prototraps; + traps_t *traps; + + int current_event; + int num_events; + int size_events; + event_t *events; +} events_t; + +typedef struct _EventView { + GtkWidget widget; + + events_t *events_list; + events_t *current_events; + + double px, py; + + gint mag_x, mag_y; + gint mag_size; + gdouble mag_zoom; + gboolean in_mag_drag; + gint mag_drag_x, mag_drag_y; +} EventView; + +typedef struct _EventViewClass { + GtkWidgetClass parent_class; +} EventViewClass; + +G_DEFINE_TYPE (EventView, event_view, GTK_TYPE_WIDGET) + +static edge_t * +edges_lookup (edges_t *edges, gulong id) +{ + return &edges->edges[GPOINTER_TO_UINT(g_hash_table_lookup (edges->ht, + GUINT_TO_POINTER + (id)))]; +} + +static gdouble +_compute_intersection_x_for_y (const line_t *line, + gdouble y) +{ + gdouble dx = line->p2.x - line->p1.x; + gdouble dy = line->p2.y - line->p1.y; + gdouble x; + + if (y == line->p1.y) + return line->p1.x; + if (y == line->p2.y) + return line->p2.x; + + x = line->p1.x; + if (dy != 0) + x += (y - line->p1.y)*dx/dy; + return x; +} + +static void +_compute_intersection_point (const line_t *line, + gdouble y, + point_t *p) +{ + p->x = _compute_intersection_x_for_y (line, p->y = y); +} + +static void +_edge_path (cairo_t *cr, const cairo_matrix_t *m, const edge_t *e) +{ + double x, y; + + x = e->p1.x; y = e->p1.y; + cairo_matrix_transform_point (m, &x, &y); + cairo_move_to (cr, x, y); + + x = e->p2.x; y = e->p2.y; + cairo_matrix_transform_point (m, &x, &y); + cairo_line_to (cr, x, y); + + if (e->dir < 0) { + cairo_set_source_rgb (cr, 0, 0, 1); + } else { + cairo_set_source_rgb (cr, 1, 0, 0); + } +} + +static void +_events_draw (events_t *events, cairo_t *cr, cairo_matrix_t *m) +{ + double dash[2] = {8, 8}; + point_t p; + int n; + + /* first the existing and proto-traps */ + cairo_save (cr); { + cairo_set_matrix (cr, m); + + cairo_set_source_rgba (cr, 1, 0, 0, .15); + for (n = 0; n < events->prototraps->num_traps; n++) { + const trapezoid_t *t = &events->prototraps->traps[n]; + + _compute_intersection_point (&t->left->line, t->top, &p); + cairo_move_to (cr, p.x, p.y); + _compute_intersection_point (&t->right->line, t->top, &p); + cairo_line_to (cr, p.x, p.y); + _compute_intersection_point (&t->right->line, t->bottom, &p); + cairo_line_to (cr, p.x, p.y); + _compute_intersection_point (&t->left->line, t->bottom, &p); + cairo_line_to (cr, p.x, p.y); + cairo_close_path (cr); + cairo_fill (cr); + } + + cairo_set_source_rgba (cr, 0, 1, 0, .2); + for (n = 0; n < events->traps->num_traps; n++) { + const trapezoid_t *t = &events->traps->traps[n]; + + _compute_intersection_point (&t->left->line, t->top, &p); + cairo_move_to (cr, p.x, p.y); + _compute_intersection_point (&t->right->line, t->top, &p); + cairo_line_to (cr, p.x, p.y); + _compute_intersection_point (&t->right->line, t->bottom, &p); + cairo_line_to (cr, p.x, p.y); + _compute_intersection_point (&t->left->line, t->bottom, &p); + cairo_line_to (cr, p.x, p.y); + cairo_close_path (cr); + cairo_fill (cr); + } + } cairo_restore (cr); + + /* known edges */ + cairo_save (cr); + cairo_set_line_width (cr, 1.); + for (n = 0; n < events->edges->num_edges; n++) { + const edge_t *e = &events->edges->edges[n]; + double x, y; + + x = e->p1.x; y = e->p1.y; + cairo_matrix_transform_point (m, &x, &y); + cairo_move_to (cr, x, y); + + x = e->p2.x; y = e->p2.y; + cairo_matrix_transform_point (m, &x, &y); + cairo_line_to (cr, x, y); + + if (e->dir < 0) { + cairo_set_source_rgba (cr, 0, 0, 1., .4); + cairo_set_dash (cr, dash, 2, fmod (e->p1.x, dash[0]+dash[1]) + dash[0]); + } else { + cairo_set_source_rgba (cr, 1, 0, 0., 4); + cairo_set_dash (cr, dash, 2, fmod (e->p1.x, dash[0]+dash[1])); + } + + cairo_stroke (cr); + + x = e->p1.x; y = e->p1.y; + cairo_matrix_transform_point (m, &x, &y); + cairo_arc (cr, x, y, 2., 0, 2 * G_PI); + + x = e->p2.x; y = e->p2.y; + cairo_matrix_transform_point (m, &x, &y); + cairo_arc (cr, x, y, 2., 0, 2 * G_PI); + + cairo_fill (cr); + } + cairo_restore (cr); + + /* event time */ + cairo_save (cr); { + event_t *e; + double x, y; + + e = &events->events[events->current_event]; + + cairo_set_line_width (cr, 2.); + cairo_set_matrix (cr, m); + cairo_move_to (cr, + events->extents.p1.x, + e->y); + cairo_line_to (cr, + events->extents.p2.x, + e->y); + cairo_identity_matrix (cr); + cairo_stroke (cr); + + x = e->x; y = e->y; + cairo_matrix_transform_point (m, &x, &y); + switch (e->type) { + case START_EDGE: + case END_EDGE: + case INTERSECTION: + cairo_arc (cr, x, y, 4., 0, 2 * G_PI); + break; + case START_TRAP: + case END_TRAP: + break; + } + switch (e->type) { + case START_EDGE: + cairo_set_source_rgb (cr, 1, 0, 0); + break; + case END_EDGE: + cairo_set_source_rgb (cr, 0, 0, 1); + break; + case INTERSECTION: + cairo_set_source_rgb (cr, 1, 0, 1); + break; + case START_TRAP: + case END_TRAP: + break; + } + cairo_fill (cr); + + cairo_set_line_width (cr, 1.); + switch (e->type) { + case START_EDGE: + _edge_path (cr, m, edges_lookup (events->edges, e->e1)); + cairo_stroke (cr); + break; + case END_EDGE: + _edge_path (cr, m, edges_lookup (events->edges, e->e1)); + cairo_stroke (cr); + break; + case INTERSECTION: + _edge_path (cr, m, edges_lookup (events->edges, e->e1)); + cairo_stroke (cr); + _edge_path (cr, m, edges_lookup (events->edges, e->e2)); + cairo_stroke (cr); + break; + } + } cairo_restore (cr); +} + +static void +event_view_draw (EventView *self, cairo_t *cr) +{ + events_t *events; + gdouble sf_x, sf_y, sf; + gdouble mid, dim; + gdouble x0, x1, y0, y1; + cairo_matrix_t m; + + cairo_save (cr); + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + cairo_restore (cr); + + events = self->current_events; + if (events == NULL) + return; + + mid = (events->extents.p2.x + events->extents.p1.x) / 2.; + dim = (events->extents.p2.x - events->extents.p1.x) / 2. * 1.2; + sf_x = self->widget.allocation.width / dim / 2; + + mid = (events->extents.p2.y + events->extents.p1.y) / 2.; + dim = (events->extents.p2.y - events->extents.p1.y) / 2. * 1.2; + sf_y = self->widget.allocation.height / dim / 2; + + sf = MIN (sf_x, sf_y); + + mid = (events->extents.p2.x + events->extents.p1.x) / 2.; + dim = sf_x / sf * (events->extents.p2.x - events->extents.p1.x) / 2. * 1.2; + x0 = mid - dim; + x1 = mid + dim; + mid = (events->extents.p2.y + events->extents.p1.y) / 2.; + dim = sf_y / sf * (events->extents.p2.y - events->extents.p1.y) / 2. * 1.2; + y0 = mid - dim; + y1 = mid + dim; + + cairo_matrix_init_scale (&m, sf, sf); + cairo_matrix_translate (&m, -x0, -y0); + _events_draw (events, cr, &m); + + /* draw a zoom view of the area around the mouse */ + cairo_save (cr); { + double zoom = self->mag_zoom; + int size = self->mag_size; + + /* bottom right */ + cairo_rectangle (cr, self->mag_x, self->mag_y, size, size); + cairo_stroke_preserve (cr); + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_fill_preserve (cr); + cairo_clip (cr); + + /* compute roi in extents */ + cairo_translate (cr, self->mag_x + size/2, self->mag_y + size/2); + + cairo_matrix_init_scale (&m, zoom, zoom); + cairo_matrix_translate (&m, -(self->px / sf + x0), -(self->py /sf + y0)); + _events_draw (events, cr, &m); + + /* grid */ + cairo_save (cr); { + int i; + + cairo_translate (cr, + -zoom*fmod (self->px/sf + x0, 1.), + -zoom*fmod (self->py/sf + y0, 1.)); + for (i = -size/2/zoom - 1; i <= size/2/zoom + 1; i++) { + cairo_move_to (cr, zoom*i, -size/2); + cairo_line_to (cr, zoom*i, size/2 + zoom); + cairo_move_to (cr, -size/2, zoom*i); + cairo_line_to (cr, size/2 + zoom, zoom*i); + } + cairo_set_source_rgba (cr, .7, .7, .7, .5); + cairo_set_line_width (cr, 1.); + cairo_stroke (cr); + } cairo_restore (cr); + } cairo_restore (cr); +} + +static void +event_view_draw_labels (EventView *self, cairo_t *cr) +{ + events_t *events; + + events = self->current_events; + if (events == NULL) + return; + +} + +static gboolean +event_view_expose (GtkWidget *w, GdkEventExpose *ev) +{ + EventView *self = (EventView *) w; + cairo_t *cr; + + cr = gdk_cairo_create (w->window); + gdk_cairo_region (cr, ev->region); + cairo_clip (cr); + + event_view_draw (self, cr); + event_view_draw_labels (self, cr); + + cairo_destroy (cr); + return FALSE; +} + +static void +traps_clear (traps_t *traps) +{ + traps->num_traps = 0; +} + +static traps_t * +traps_add (traps_t *traps, int top, int bot, const edge_t *e1, const edge_t *e2) +{ + trapezoid_t *t; + + if (traps->num_traps == traps->size) { + traps->size *= 2; + traps = g_realloc (traps, + sizeof (traps_t) + traps->size*sizeof (trapezoid_t)); + } + + t = &traps->traps[traps->num_traps++]; + t->top = top; + if (bot > e1->bottom) + bot = e1->bottom; + if (bot > e2->bottom) + bot = e2->bottom; + t->bottom = bot; + + t->left = e1; + t->right = e2; + + return traps; +} + +static void +traps_remove (traps_t *traps, int top, const edge_t *e1, const edge_t *e2) +{ + int n; + + for (n = 0; n < traps->num_traps; n++) { + trapezoid_t *t = &traps->traps[n]; + if (t->top == top && t->left == e1 && t->right == e2) + break; + } + if (n < traps->num_traps) { + g_memmove (&traps->traps[n], + &traps->traps[n+1], + (traps->num_traps-n+1) * sizeof (trapezoid_t)); + traps->num_traps--; + } +} + +static void +event_next (EventView *self) +{ + events_t *events; + event_t *e; + + events = self->current_events; + if (++events->current_event == events->num_events) { + return; + } else if (events->current_event >= events->num_events) { + traps_clear (events->prototraps); + traps_clear (events->traps); + events->current_event = 0; + + self->current_events = events->next; + if (self->current_events == NULL) + self->current_events = self->events_list; + events = self->current_events; + } + + e = &events->events[events->current_event]; + switch (e->type) { + case START_TRAP: + events->prototraps = traps_add (events->prototraps, + e->x, G_MAXINT, + edges_lookup (events->edges, e->e1), + edges_lookup (events->edges, e->e2)); + break; + case END_TRAP: + traps_remove (events->prototraps, + e->x, + edges_lookup (events->edges, e->e1), + edges_lookup (events->edges, e->e2)); + events->traps = traps_add (events->traps, + e->x, e->y, + edges_lookup (events->edges, e->e1), + edges_lookup (events->edges, e->e2)); + break; + } +} + +static gboolean +event_view_button_press (GtkWidget *w, GdkEventButton *ev) +{ + EventView *self = (EventView *) w; + + if (ev->x < self->mag_x || + ev->y < self->mag_y || + ev->x > self->mag_x + self->mag_size || + ev->y > self->mag_y + self->mag_size) + { + if (ev->type == GDK_BUTTON_PRESS) { + event_next (self); + gtk_widget_queue_draw (w); + } + } + else + { + self->in_mag_drag = TRUE; + self->mag_drag_x = ev->x; + self->mag_drag_y = ev->y; + } + + return FALSE; +} + +static gboolean +event_view_button_release (GtkWidget *w, GdkEventButton *ev) +{ + EventView *self = (EventView *) w; + + self->in_mag_drag = FALSE; + + return FALSE; +} + +static gboolean +event_view_motion (GtkWidget *w, GdkEventMotion *ev) +{ + EventView *self = (EventView *) w; + + if (self->in_mag_drag) { + self->mag_x += ev->x - self->mag_drag_x; + self->mag_y += ev->y - self->mag_drag_y; + + gtk_widget_queue_draw (&self->widget); + + self->mag_drag_x = ev->x; + self->mag_drag_y = ev->y; + } else if (ev->x < self->mag_x || + ev->y < self->mag_y || + ev->x > self->mag_x + self->mag_size || + ev->y > self->mag_y + self->mag_size) + { + self->px = ev->x; + self->py = ev->y; + + gtk_widget_queue_draw (&self->widget); + } + + return FALSE; +} + +static void +event_view_realize (GtkWidget *widget) +{ + GdkWindowAttr attributes; + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget) | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_KEY_PRESS_MASK | + GDK_KEY_RELEASE_MASK | + GDK_POINTER_MOTION_MASK | + GDK_BUTTON_MOTION_MASK | + GDK_EXPOSURE_MASK; + + widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), + &attributes, + GDK_WA_X | GDK_WA_Y | + GDK_WA_VISUAL | GDK_WA_COLORMAP); + gdk_window_set_user_data (widget->window, widget); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); +} + +static void +event_view_size_allocate (GtkWidget *w, GdkRectangle *r) +{ + EventView *self = (EventView *) w; + + GTK_WIDGET_CLASS (event_view_parent_class)->size_allocate (w, r); + + self->mag_x = w->allocation.width - self->mag_size - 10; + self->mag_y = w->allocation.height - self->mag_size - 10; +} + +static void +event_view_finalize (GObject *obj) +{ + G_OBJECT_CLASS (event_view_parent_class)->finalize (obj); +} + +static void +event_view_class_init (EventViewClass *klass) +{ + GObjectClass *object_class = (GObjectClass *) klass; + GtkWidgetClass *widget_class = (GtkWidgetClass *) klass; + + object_class->finalize = event_view_finalize; + + widget_class->realize = event_view_realize; + widget_class->size_allocate = event_view_size_allocate; + widget_class->expose_event = event_view_expose; + widget_class->button_press_event = event_view_button_press; + widget_class->button_release_event = event_view_button_release; + widget_class->motion_notify_event = event_view_motion; +} + +static void +event_view_init (EventView *self) +{ + self->mag_zoom = 10; + self->mag_size = 200; +} + +static traps_t * +traps_new (void) +{ + traps_t *t; + + t = g_malloc (sizeof (traps_t) + 16 * sizeof (trapezoid_t)); + + t->size = 16; + t->num_traps = 0; + + return t; +} + +static edges_t * +_edges_add_edge (edges_t *edges, edge_t *e, box_t *extents) +{ + if (e->top < extents->p1.y) + extents->p1.y = e->top; + if (e->bottom > extents->p2.y) + extents->p2.y = e->bottom; + + _compute_intersection_point (&e->line, e->top, &e->p1); + _compute_intersection_point (&e->line, e->bottom, &e->p2); + + if (e->p1.x < extents->p1.x) + extents->p1.x = e->p1.x; + if (e->p2.x < extents->p1.x) + extents->p1.x = e->p2.x; + + if (e->p1.x > extents->p2.x) + extents->p2.x = e->p1.x; + if (e->p2.x > extents->p2.x) + extents->p2.x = e->p2.x; + + if (edges->num_edges == edges->size) { + edges->size *= 2; + edges = g_realloc (edges, + sizeof (edges_t) + edges->size * sizeof (edge_t)); + } + + g_hash_table_insert (edges->ht, + GUINT_TO_POINTER (e->id), + GUINT_TO_POINTER (edges->num_edges)); + edges->edges[edges->num_edges++] = *e; + + return edges; +} + +static void +_events_add_event (events_t *events, + int type, + int x, int y, + gulong e1, gulong e2) +{ + event_t *e; + + if (events->num_events == events->size_events) { + int newsize = 2 * events->size_events; + void *newevents; + + newevents = g_renew (event_t, events->events, newsize); + events->events = newevents; + events->size_events = newsize; + } + + e = &events->events[events->num_events++]; + e->type = type; + e->x = x; + e->y = y; + e->e1 = e1; + e->e2 = e2; +} + +static edges_t * +edges_new (void) +{ + edges_t *t; + + t = g_malloc (sizeof (edges_t) + 16 * sizeof (edge_t)); + t->ht = g_hash_table_new (NULL, NULL); + t->size = 16; + t->num_edges = 0; + + return t; +} + +static events_t * +events_new (void) +{ + events_t *events; + + events = g_malloc (sizeof (events_t)); + + events->next = NULL; + events->prev = NULL; + + events->events = g_new (event_t, 16); + events->size_events = 16; + events->num_events = 0; + events->current_event = 0; + + events->edges = edges_new (); + events->prototraps = traps_new (); + events->traps = traps_new (); + + events->extents.p1.x = G_MAXDOUBLE; + events->extents.p1.y = G_MAXDOUBLE; + events->extents.p2.x = -G_MAXDOUBLE; + events->extents.p2.y = -G_MAXDOUBLE; + + return events; +} + +static void +events_read (EventView *ev, const char *filename) +{ + FILE *file; + + file = fopen (filename, "r"); + if (file != NULL) { + char *line = NULL; + size_t len = 0; + events_t *events; + + events = ev->events_list = events_new (); + while (getline (&line, &len, file) != -1) { + line = g_strstrip (line); + if (*line == '\0') { + events->next = events_new (); + events->next->prev = events; + events = events->next; + } else if (g_str_has_prefix (line, "edge:")) { + edge_t edge; + + sscanf (line, "edge: %lu (%lf, %lf) (%lf, %lf) (%lf, %lf) %d", + &edge.id, + &edge.line.p1.x, + &edge.line.p1.y, + &edge.line.p2.x, + &edge.line.p2.y, + &edge.top, + &edge.bottom, + &edge.dir); + + events->edges = _edges_add_edge (events->edges, + &edge, + &events->extents); + } else if (g_str_has_prefix (line, "event:")) { + int type; + int x,y; + gulong e1, e2; + + sscanf (line, "event: %d (%d, %d) %lu %lu", + &type, &x, &y, + &e1, &e2); + + _events_add_event (events, type, x, y, e1, e2); + } else if (g_str_has_prefix (line, "begin trap:")) { + int top; + gulong e1, e2; + + sscanf (line, "begin trap: %lu %lu %u", &e1, &e2, &top); + + _events_add_event (events, START_TRAP, top, 0, e1, e2); + } else if (g_str_has_prefix (line, "end trap:")) { + int top, bottom; + gulong e1, e2; + + sscanf (line, "end trap: %lu %lu %d %d", + &e1, &e2, &top, &bottom); + + _events_add_event (events, END_TRAP, top, bottom, e1, e2); + } + } + + ev->current_events = ev->events_list; + + free (line); + fclose (file); + } +} + +static gboolean +timeout_advance (EventView *self) +{ + event_next (self); + gtk_widget_queue_draw (&self->widget); + return TRUE; +} + +int +main (int argc, char **argv) +{ + EventView *ev; + GtkWidget *window, *hbox; + + gtk_init (&argc, &argv); + + hbox = gtk_hbox_new (TRUE, 0); + + ev = g_object_new (event_view_get_type (), NULL); + gtk_box_pack_start (GTK_BOX (hbox), &ev->widget, TRUE, TRUE, 0); + gtk_widget_show (&ev->widget); + + events_read (ev, argv[1]); + g_timeout_add (750, (GSourceFunc) timeout_advance, ev); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_widget_set_size_request (window, 800, 800); + g_signal_connect (window, "delete-event", + G_CALLBACK (gtk_main_quit), NULL); + gtk_container_add (GTK_CONTAINER (window), hbox); + gtk_widget_show (hbox); + gtk_widget_show (window); + + gtk_main (); + return 0; +} diff --git a/local/recipes/libs/cairo/source/util/show-polygon.c b/local/recipes/libs/cairo/source/util/show-polygon.c new file mode 100644 index 0000000000..1157427f78 --- /dev/null +++ b/local/recipes/libs/cairo/source/util/show-polygon.c @@ -0,0 +1,647 @@ +#include "config.h" + +#include +#include +#include +#include +#include +#include + +typedef struct _point { + gdouble x, y; +} point_t; +typedef struct _edge { + point_t p1, p2; + gdouble top, bot; + int dir; +} edge_t; +typedef struct _box { + point_t p1, p2; +} box_t; + +typedef struct _polygon { + struct _polygon *next, *prev; + int num_edges; + int size; + edge_t edges[0]; +} polygon_t; + +typedef struct _PolygonView { + GtkWidget widget; + + cairo_surface_t *pixmap; + int pixmap_width, pixmap_height; + + box_t extents; + polygon_t *polygons; + + double px, py; + + gint mag_x, mag_y; + gint mag_size; + gdouble mag_zoom; + gboolean in_mag_drag; + gint mag_drag_x, mag_drag_y; +} PolygonView; + +typedef struct _PolygonViewClass { + GtkWidgetClass parent_class; +} PolygonViewClass; + +G_DEFINE_TYPE (PolygonView, polygon_view, GTK_TYPE_WIDGET) + +double highlight = -1; + +static void draw_edges (cairo_t *cr, polygon_t *p, gdouble sf, int dir) +{ + int n; + + if (dir < 0) + cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); + else + cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); + + for (n = 0; n < p->num_edges; n++) { + const edge_t *e = &p->edges[n]; + double dx, dy; + double x1, x2; + + if (e->dir != dir) + continue; + + dx = e->p2.x - e->p1.x; + dy = e->p2.y - e->p1.y; + + x1 = e->p1.x + (e->top - e->p1.y) / dy * dx; + x2 = e->p1.x + (e->bot - e->p1.y) / dy * dx; + + cairo_arc (cr, x1, e->top, 2/sf, 0, 2*M_PI); + cairo_arc (cr, x2, e->bot, 2/sf, 0, 2*M_PI); + cairo_fill (cr); + } + + if (dir < 0) + cairo_set_source_rgba (cr, 0.0, 0.0, 1.0, 0.5); + else + cairo_set_source_rgba (cr, 1.0, 0.0, 0.0, 0.5); + + for (n = 0; n < p->num_edges; n++) { + const edge_t *e = &p->edges[n]; + + if (e->dir != dir) + continue; + + cairo_move_to (cr, e->p1.x, e->p1.y); + cairo_line_to (cr, e->p2.x, e->p2.y); + } + cairo_save (cr); { + cairo_identity_matrix (cr); + cairo_set_line_width (cr, 1.); + cairo_stroke (cr); + } cairo_restore (cr); + + if (dir < 0) + cairo_set_source_rgb (cr, 0.0, 0.0, 1.0); + else + cairo_set_source_rgb (cr, 1.0, 0.0, 0.0); + + for (n = 0; n < p->num_edges; n++) { + const edge_t *e = &p->edges[n]; + double dx, dy; + double x1, x2; + + if (e->dir != dir) + continue; + + dx = e->p2.x - e->p1.x; + dy = e->p2.y - e->p1.y; + + x1 = e->p1.x + (e->top - e->p1.y) / dy * dx; + x2 = e->p1.x + (e->bot - e->p1.y) / dy * dx; + + cairo_move_to (cr, x1, e->top); + cairo_line_to (cr, x2, e->bot); + } + cairo_save (cr); { + cairo_identity_matrix (cr); + cairo_set_line_width (cr, 1.); + cairo_stroke (cr); + } cairo_restore (cr); +} + +static void draw_polygon (cairo_t *cr, polygon_t *p, gdouble sf) +{ + draw_edges (cr, p, sf, -1); + + draw_edges (cr, p, sf, +1); +} + +static cairo_surface_t * +pixmap_create (PolygonView *self, cairo_surface_t *target) +{ + cairo_surface_t *surface = + cairo_surface_create_similar (target, CAIRO_CONTENT_COLOR, + self->widget.allocation.width, + self->widget.allocation.height); + cairo_t *cr = cairo_create (surface); + polygon_t *polygon; + gdouble sf_x, sf_y, sf; + gdouble mid, dim; + gdouble x0, y0; + box_t extents; + + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + if (self->polygons == NULL) { + cairo_destroy(cr); + return surface; + } + + extents = self->extents; + + mid = (extents.p2.x + extents.p1.x) / 2.; + dim = (extents.p2.x - extents.p1.x) / 2. * 1.25; + sf_x = self->widget.allocation.width / dim / 2; + + mid = (extents.p2.y + extents.p1.y) / 2.; + dim = (extents.p2.y - extents.p1.y) / 2. * 1.25; + sf_y = self->widget.allocation.height / dim / 2; + + sf = MIN (sf_x, sf_y); + + mid = (extents.p2.x + extents.p1.x) / 2.; + dim = sf_x / sf * (extents.p2.x - extents.p1.x) / 2. * 1.25; + x0 = mid - dim; + mid = (extents.p2.y + extents.p1.y) / 2.; + dim = sf_y / sf * (extents.p2.y - extents.p1.y) / 2. * 1.25; + y0 = mid - dim; + + cairo_save (cr); { + cairo_scale (cr, sf, sf); + cairo_translate (cr, -x0, -y0); + + for (polygon = self->polygons; polygon; polygon = polygon->next) { + if (polygon->num_edges == 0) + continue; + + draw_polygon (cr, polygon, sf); + } + + if (highlight != -1) { + cairo_move_to (cr, extents.p1.x, highlight); + cairo_line_to (cr, extents.p2.x, highlight); + cairo_set_source_rgb (cr, 0, .7, 0); + cairo_save (cr); + cairo_identity_matrix (cr); + cairo_set_line_width (cr, 1.); + cairo_stroke (cr); + cairo_restore (cr); + } + } cairo_restore (cr); + + cairo_destroy (cr); + return surface; +} + +static void +polygon_view_draw (PolygonView *self, cairo_t *cr) +{ + polygon_t *polygon; + gdouble sf_x, sf_y, sf; + gdouble mid, dim; + gdouble x0, y0; + box_t extents; + + extents = self->extents; + + mid = (extents.p2.x + extents.p1.x) / 2.; + dim = (extents.p2.x - extents.p1.x) / 2. * 1.25; + sf_x = self->widget.allocation.width / dim / 2; + + mid = (extents.p2.y + extents.p1.y) / 2.; + dim = (extents.p2.y - extents.p1.y) / 2. * 1.25; + sf_y = self->widget.allocation.height / dim / 2; + + sf = MIN (sf_x, sf_y); + + mid = (extents.p2.x + extents.p1.x) / 2.; + dim = sf_x / sf * (extents.p2.x - extents.p1.x) / 2. * 1.25; + x0 = mid - dim; + mid = (extents.p2.y + extents.p1.y) / 2.; + dim = sf_y / sf * (extents.p2.y - extents.p1.y) / 2. * 1.25; + y0 = mid - dim; + + if (self->pixmap_width != self->widget.allocation.width || + self->pixmap_height != self->widget.allocation.height) + { + cairo_surface_destroy (self->pixmap); + self->pixmap = pixmap_create (self, cairo_get_target (cr)); + self->pixmap_width = self->widget.allocation.width; + self->pixmap_height = self->widget.allocation.height; + } + + cairo_set_source_surface (cr, self->pixmap, 0, 0); + cairo_paint (cr); + + if (self->polygons == NULL) + return; + + /* draw a zoom view of the area around the mouse */ + if (1) { + double zoom = self->mag_zoom; + int size = self->mag_size; + int mag_x = self->mag_x; + int mag_y = self->mag_y; + + if (1) { + if (self->px + size < self->widget.allocation.width/2) + mag_x = self->px + size/4; + else + mag_x = self->px - size/4 - size; + mag_y = self->py - size/2; + if (mag_y < 0) + mag_y = 0; + if (mag_y + size > self->widget.allocation.height) + mag_y = self->widget.allocation.height - size; + } + + cairo_save (cr); { + /* bottom right */ + cairo_rectangle (cr, mag_x, mag_y, size, size); + cairo_stroke_preserve (cr); + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_fill_preserve (cr); + cairo_clip (cr); + + /* compute roi in extents */ + cairo_translate (cr, mag_x + size/2, mag_y + size/2); + + cairo_save (cr); { + cairo_scale (cr, zoom, zoom); + cairo_translate (cr, -(self->px / sf + x0), -(self->py /sf + y0)); + for (polygon = self->polygons; polygon; polygon = polygon->next) { + if (polygon->num_edges == 0) + continue; + + draw_polygon (cr, polygon, zoom); + } + + if (highlight != -1) { + cairo_move_to (cr, extents.p1.x, highlight); + cairo_line_to (cr, extents.p2.x, highlight); + cairo_set_source_rgb (cr, 0, .7, 0); + cairo_save (cr); + cairo_identity_matrix (cr); + cairo_set_line_width (cr, 1.); + cairo_stroke (cr); + cairo_restore (cr); + } + } cairo_restore (cr); + + /* grid */ + cairo_save (cr); { + int i; + + cairo_translate (cr, + -zoom*fmod (self->px/sf + x0, 1.), + -zoom*fmod (self->py/sf + y0, 1.)); + zoom /= 2; + for (i = -size/2/zoom; i <= size/2/zoom + 1; i+=2) { + cairo_move_to (cr, zoom*i, -size/2); + cairo_line_to (cr, zoom*i, size/2 + zoom); + cairo_move_to (cr, -size/2, zoom*i); + cairo_line_to (cr, size/2 + zoom, zoom*i); + } + zoom *= 2; + cairo_set_source_rgba (cr, .7, .7, .7, .5); + cairo_set_line_width (cr, 1.); + cairo_stroke (cr); + + for (i = -size/2/zoom - 1; i <= size/2/zoom + 1; i++) { + cairo_move_to (cr, zoom*i, -size/2); + cairo_line_to (cr, zoom*i, size/2 + zoom); + cairo_move_to (cr, -size/2, zoom*i); + cairo_line_to (cr, size/2 + zoom, zoom*i); + } + cairo_set_source_rgba (cr, .1, .1, .1, .5); + cairo_set_line_width (cr, 2.); + cairo_stroke (cr); + } cairo_restore (cr); + + } cairo_restore (cr); + } +} + +static gboolean +polygon_view_expose (GtkWidget *w, GdkEventExpose *ev) +{ + PolygonView *self = (PolygonView *) w; + cairo_t *cr; + + cr = gdk_cairo_create (w->window); + gdk_cairo_region (cr, ev->region); + cairo_clip (cr); + + polygon_view_draw (self, cr); + + cairo_destroy (cr); + return FALSE; +} + +static gboolean +polygon_view_key_press (GtkWidget *w, GdkEventKey *ev) +{ + switch (ev->keyval) { + case GDK_Escape: + case GDK_Q: + gtk_main_quit (); + break; + } + + return FALSE; +} + +static gboolean +polygon_view_button_press (GtkWidget *w, GdkEventButton *ev) +{ + PolygonView *self = (PolygonView *) w; + + if (ev->x < self->mag_x || + ev->y < self->mag_y || + ev->x > self->mag_x + self->mag_size || + ev->y > self->mag_y + self->mag_size) + { + } + else + { + self->in_mag_drag = TRUE; + self->mag_drag_x = ev->x; + self->mag_drag_y = ev->y; + } + + return FALSE; +} + +static gboolean +polygon_view_button_release (GtkWidget *w, GdkEventButton *ev) +{ + PolygonView *self = (PolygonView *) w; + + self->in_mag_drag = FALSE; + + return FALSE; +} + +static void +polygon_view_update_mouse (PolygonView *self, GdkEventMotion *ev) +{ + self->px = ev->x; + self->py = ev->y; + + gtk_widget_queue_draw (&self->widget); +} + +static void +polygon_view_update_magnifier (PolygonView *self, gint *xy) +{ + self->mag_x = xy[0]; + self->mag_y = xy[1]; + + gtk_widget_queue_draw (&self->widget); +} + +static gboolean +polygon_view_motion (GtkWidget *w, GdkEventMotion *ev) +{ + PolygonView *self = (PolygonView *) w; + + if (self->in_mag_drag) { + int xy[2]; + + xy[0] = self->mag_x + ev->x - self->mag_drag_x; + xy[1] = self->mag_y + ev->y - self->mag_drag_y; + + polygon_view_update_magnifier (self, xy); + + self->mag_drag_x = ev->x; + self->mag_drag_y = ev->y; + } else if (ev->x < self->mag_x || + ev->y < self->mag_y || + ev->x > self->mag_x + self->mag_size || + ev->y > self->mag_y + self->mag_size) + { + polygon_view_update_mouse (self, ev); + } + + return FALSE; +} + +static void +polygon_view_realize (GtkWidget *widget) +{ + GdkWindowAttr attributes; + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget) | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_KEY_PRESS_MASK | + GDK_KEY_RELEASE_MASK | + GDK_POINTER_MOTION_MASK | + GDK_BUTTON_MOTION_MASK | + GDK_EXPOSURE_MASK; + + widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), + &attributes, + GDK_WA_X | GDK_WA_Y | + GDK_WA_VISUAL | GDK_WA_COLORMAP); + gdk_window_set_user_data (widget->window, widget); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); +} + +static void +polygon_view_size_allocate (GtkWidget *w, GdkRectangle *r) +{ + PolygonView *self = (PolygonView *) w; + + GTK_WIDGET_CLASS (polygon_view_parent_class)->size_allocate (w, r); + + self->mag_x = w->allocation.width - self->mag_size - 10; + self->mag_y = w->allocation.height - self->mag_size - 10; +} + +static void +polygon_view_finalize (GObject *obj) +{ + G_OBJECT_CLASS (polygon_view_parent_class)->finalize (obj); +} + +static void +polygon_view_class_init (PolygonViewClass *klass) +{ + GObjectClass *object_class = (GObjectClass *) klass; + GtkWidgetClass *widget_class = (GtkWidgetClass *) klass; + + object_class->finalize = polygon_view_finalize; + + widget_class->realize = polygon_view_realize; + widget_class->size_allocate = polygon_view_size_allocate; + widget_class->expose_event = polygon_view_expose; + widget_class->key_press_event = polygon_view_key_press; + widget_class->button_press_event = polygon_view_button_press; + widget_class->button_release_event = polygon_view_button_release; + widget_class->motion_notify_event = polygon_view_motion; +} + +static void +polygon_view_init (PolygonView *self) +{ + self->mag_zoom = 64; + self->mag_size = 200; + + self->extents.p1.x = G_MAXDOUBLE; + self->extents.p1.y = G_MAXDOUBLE; + self->extents.p2.x = -G_MAXDOUBLE; + self->extents.p2.y = -G_MAXDOUBLE; + + GTK_WIDGET_SET_FLAGS (self, GTK_CAN_FOCUS); +} + +static polygon_t * +_polygon_add_edge (PolygonView *view, polygon_t *polygon, + point_t *p1, point_t *p2, + gdouble top, gdouble bot, int dir) +{ + if (polygon == NULL) + return NULL; + + if (top < view->extents.p1.y) + view->extents.p1.y = top; + if (bot > view->extents.p2.y) + view->extents.p2.y = bot; + + if (p1->x < view->extents.p1.x) + view->extents.p1.x = p1->x; + if (p1->x > view->extents.p2.x) + view->extents.p2.x = p1->x; + if (p2->x < view->extents.p1.x) + view->extents.p1.x = p2->x; + if (p2->x > view->extents.p2.x) + view->extents.p2.x = p2->x; + + if (polygon->num_edges == polygon->size) { + int newsize = 2 * polygon->size; + void *newpolygon; + + newpolygon = g_realloc (polygon, + sizeof (polygon_t) + newsize * sizeof (edge_t)); + if (newpolygon == NULL) + return polygon; + + polygon = newpolygon; + polygon->size = newsize; + + if (polygon->next != NULL) + polygon->next->prev = newpolygon; + if (polygon->prev != NULL) + polygon->prev->next = newpolygon; + else + view->polygons = newpolygon; + } + + polygon->edges[polygon->num_edges].p1 = *p1; + polygon->edges[polygon->num_edges].p2 = *p2; + polygon->edges[polygon->num_edges].top = top; + polygon->edges[polygon->num_edges].bot = bot; + polygon->edges[polygon->num_edges].dir = dir; + polygon->num_edges++; + + return polygon; +} + +static polygon_t * +polygon_new (PolygonView *view) +{ + polygon_t *t; + + t = g_malloc (sizeof (polygon_t) + 128 * sizeof (edge_t)); + t->prev = NULL; + t->next = view->polygons; + if (view->polygons) + view->polygons->prev = t; + view->polygons = t; + + t->size = 128; + t->num_edges = 0; + + return t; +} + +int +main (int argc, char **argv) +{ + PolygonView *view; + polygon_t *polygon = NULL; + GtkWidget *window; + FILE *file; + char *line = NULL; + size_t len = 0; + + gtk_init (&argc, &argv); + + view = g_object_new (polygon_view_get_type (), NULL); + + file = fopen (argv[1], "r"); + if (file != NULL) { + while (getline (&line, &len, file) != -1) { + point_t p1, p2; + double top, bottom; + int dir; + + if (strncmp (line, "polygon: ", sizeof("polygon: ")-1) == 0) { + if (polygon && polygon->num_edges) { + g_print ("read polygon with %d edges\n", polygon->num_edges); + + polygon = polygon_new (view); + } else if (polygon == NULL) + polygon = polygon_new (view); + } else if (sscanf (line, " [%*d] = [(%lf, %lf), (%lf, %lf)], top=%lf, bottom=%lf, dir=%d", &p1.x, &p1.y, &p2.x, &p2.y, &top, &bottom, &dir) == 7) { + polygon = _polygon_add_edge (view, polygon, &p1, &p2, + top, bottom, dir); + } + } + + if (polygon && polygon->num_edges) + g_print ("read polygon with %d edges\n", polygon->num_edges); + + g_print ("extents=(%lg, %lg), (%lg, %lg)\n", + view->extents.p1.x, view->extents.p1.y, + view->extents.p2.x, view->extents.p2.y); + fclose (file); + } + + if (argc > 2) + highlight = atof (argv[2]); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + g_signal_connect (window, "delete-event", + G_CALLBACK (gtk_main_quit), NULL); + gtk_widget_set_size_request (window, 800, 800); + gtk_container_add (GTK_CONTAINER (window), &view->widget); + gtk_widget_show_all (window); + + gtk_main (); + return 0; +} diff --git a/local/recipes/libs/cairo/source/util/show-traps.c b/local/recipes/libs/cairo/source/util/show-traps.c new file mode 100644 index 0000000000..dc1093060a --- /dev/null +++ b/local/recipes/libs/cairo/source/util/show-traps.c @@ -0,0 +1,1312 @@ +#include "config.h" + +#include +#include +#include +#include +#include + +typedef struct _point { + gdouble x, y; +} point_t; +typedef struct _box { + point_t p1, p2; +} box_t; +typedef struct _line { + point_t p1, p2; +} line_t; +typedef struct _trapezoid { + gdouble top, bottom; + line_t left, right; +} trapezoid_t; +typedef struct _traps { + struct _traps *next, *prev; + box_t extents; + int num_traps; + int size; + trapezoid_t traps[0]; +} traps_t; + +typedef struct _edge { + line_t line; + gdouble top, bottom; + point_t p1, p2; + int dir; +} edge_t; +typedef struct _edges { + struct _edges *next, *prev; + box_t extents; + int num_edges; + int size; + edge_t edges[0]; +} edges_t; + +typedef struct _TrapView { + GtkWidget widget; + + struct _TrapView *group_head; + struct _TrapView *group_next; + struct _TrapView *group_prev; + + cairo_surface_t *pixmap; + int pixmap_width, pixmap_height; + + traps_t *traps_list; + traps_t *current_traps; + + edges_t *edges_list; + edges_t *current_edges; + + double px, py; + + gint mag_x, mag_y; + gint mag_size; + gdouble mag_zoom; + gboolean in_mag_drag; + gint mag_drag_x, mag_drag_y; +} TrapView; + +typedef struct _TrapViewClass { + GtkWidgetClass parent_class; +} TrapViewClass; + +G_DEFINE_TYPE (TrapView, trap_view, GTK_TYPE_WIDGET) + +static gdouble +_compute_intersection_x_for_y (const line_t *line, + gdouble y) +{ + gdouble dx = line->p2.x - line->p1.x; + gdouble dy = line->p2.y - line->p1.y; + gdouble x; + + if (y == line->p1.y) + return line->p1.x; + if (y == line->p2.y) + return line->p2.x; + + x = line->p1.x; + if (dy != 0) + x += (y - line->p1.y)*dx/dy; + return x; +} + +static void +_compute_intersection_point (const line_t *line, + gdouble y, + point_t *p) +{ + p->x = _compute_intersection_x_for_y (line, p->y = y); +} + +static cairo_surface_t * +pixmap_create (TrapView *self, cairo_surface_t *target) +{ + cairo_surface_t *surface = cairo_surface_create_similar (target, CAIRO_CONTENT_COLOR, + self->widget.allocation.width, + self->widget.allocation.height); + cairo_t *cr; + traps_t *traps; + edges_t *edges; + gdouble sf_x, sf_y, sf; + gdouble mid, dim; + gdouble x0, y0; + double dash[2] = {8, 8}; + double dots[2] = {0., 1.}; + int n; + box_t extents; + point_t p; + + traps = self->current_traps; + if (traps == NULL) + return surface; + edges = self->current_edges; + + extents = traps->extents; + if (edges != NULL) { + if (edges->extents.p1.x < extents.p1.x) + extents.p1.x = edges->extents.p1.x; + if (edges->extents.p1.y < extents.p1.y) + extents.p1.y = edges->extents.p1.y; + if (edges->extents.p2.x > extents.p2.x) + extents.p2.x = edges->extents.p2.x; + if (edges->extents.p2.y > extents.p2.y) + extents.p2.y = edges->extents.p2.y; + } + + mid = (extents.p2.x + extents.p1.x) / 2.; + dim = (extents.p2.x - extents.p1.x) / 2. * 1.25; + sf_x = self->widget.allocation.width / dim / 2; + + mid = (extents.p2.y + extents.p1.y) / 2.; + dim = (extents.p2.y - extents.p1.y) / 2. * 1.25; + sf_y = self->widget.allocation.height / dim / 2; + + sf = MIN (sf_x, sf_y); + + mid = (extents.p2.x + extents.p1.x) / 2.; + dim = sf_x / sf * (extents.p2.x - extents.p1.x) / 2. * 1.25; + x0 = mid - dim; + mid = (extents.p2.y + extents.p1.y) / 2.; + dim = sf_y / sf * (extents.p2.y - extents.p1.y) / 2. * 1.25; + y0 = mid - dim; + + cr = cairo_create (surface); + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + cairo_save (cr); + cairo_scale (cr, sf, sf); + cairo_translate (cr, -x0, -y0); + cairo_set_source_rgba (cr, 0, 1, 0, .2); + for (n = 0; n < traps->num_traps; n++) { + const trapezoid_t *t = &traps->traps[n]; + + _compute_intersection_point (&t->left, t->top, &p); + cairo_move_to (cr, p.x, p.y); + _compute_intersection_point (&t->right, t->top, &p); + cairo_line_to (cr, p.x, p.y); + _compute_intersection_point (&t->right, t->bottom, &p); + cairo_line_to (cr, p.x, p.y); + _compute_intersection_point (&t->left, t->bottom, &p); + cairo_line_to (cr, p.x, p.y); + cairo_close_path (cr); + cairo_fill (cr); + } + cairo_restore (cr); + + if (edges == NULL) { + cairo_save (cr); + + /* top, bottom */ + cairo_save (cr); { + cairo_matrix_t m; + cairo_matrix_init_scale (&m, sf, sf); + cairo_matrix_translate (&m, -x0, -y0); + + cairo_set_line_width (cr, 1.); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + for (n = 0; n < traps->num_traps; n++) { + const trapezoid_t *t = &traps->traps[n]; + + _compute_intersection_point (&t->left, t->top, &p); + cairo_matrix_transform_point (&m, &p.x, &p.y); + cairo_move_to (cr, floor (p.x), floor (p.y) + .5); + cairo_set_dash (cr, dash, 2, fmod (floor (p.x), dash[0] + dash[1])); + + _compute_intersection_point (&t->right, t->top, &p); + cairo_matrix_transform_point (&m, &p.x, &p.y); + cairo_line_to (cr, ceil (p.x), floor (p.y) + .5); + cairo_stroke (cr); + + _compute_intersection_point (&t->left, t->bottom, &p); + cairo_matrix_transform_point (&m, &p.x, &p.y); + cairo_move_to (cr, floor (p.x), floor (p.y) + .5); + cairo_set_dash (cr, dash, 2, fmod (floor (p.x), dash[0] + dash[1])); + + _compute_intersection_point (&t->right, t->bottom, &p); + cairo_matrix_transform_point (&m, &p.x, &p.y); + cairo_line_to (cr, ceil (p.x), floor (p.y) + .5); + cairo_stroke (cr); + } + } cairo_restore (cr); + + /* left extents */ + cairo_save (cr); { + cairo_save (cr); { + cairo_scale (cr, sf, sf); + cairo_translate (cr, -x0, -y0); + + for (n = 0; n < traps->num_traps; n++) { + const trapezoid_t *t = &traps->traps[n]; + cairo_move_to (cr, t->left.p1.x, t->left.p1.y); + cairo_line_to (cr, t->left.p2.x, t->left.p2.y); + } + } cairo_restore (cr); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_set_line_width (cr, 1.); + cairo_set_dash (cr, dash, 2, 0.); + cairo_stroke (cr); + } cairo_restore (cr); + + /* left line */ + cairo_save (cr); { + cairo_save (cr); { + cairo_scale (cr, sf, sf); + cairo_translate (cr, -x0, -y0); + + for (n = 0; n < traps->num_traps; n++) { + const trapezoid_t *t = &traps->traps[n]; + _compute_intersection_point (&t->left, t->top, &p); + cairo_move_to (cr, p.x, p.y); + _compute_intersection_point (&t->left, t->bottom, &p); + cairo_line_to (cr, p.x, p.y); + } + } cairo_restore (cr); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_stroke (cr); + } cairo_restore (cr); + + /* right extents */ + cairo_save (cr); { + cairo_save (cr); { + cairo_scale (cr, sf, sf); + cairo_translate (cr, -x0, -y0); + + for (n = 0; n < traps->num_traps; n++) { + const trapezoid_t *t = &traps->traps[n]; + cairo_move_to (cr, t->right.p1.x, t->right.p1.y); + cairo_line_to (cr, t->right.p2.x, t->right.p2.y); + } + } cairo_restore (cr); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_set_line_width (cr, 1.); + cairo_set_dash (cr, dash, 2, 0.); + cairo_stroke (cr); + } cairo_restore (cr); + + /* right line */ + cairo_save (cr); { + cairo_save (cr); { + cairo_scale (cr, sf, sf); + cairo_translate (cr, -x0, -y0); + + for (n = 0; n < traps->num_traps; n++) { + const trapezoid_t *t = &traps->traps[n]; + _compute_intersection_point (&t->right, t->top, &p); + cairo_move_to (cr, p.x, p.y); + _compute_intersection_point (&t->right, t->bottom, &p); + cairo_line_to (cr, p.x, p.y); + } cairo_restore (cr); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_stroke (cr); + } cairo_restore (cr); + } + + /* end-points */ + cairo_save (cr); { + cairo_save (cr); { + cairo_scale (cr, sf, sf); + cairo_translate (cr, -x0, -y0); + + for (n = 0; n < traps->num_traps; n++) { + const trapezoid_t *t = &traps->traps[n]; + _compute_intersection_point (&t->left, t->top, &p); + cairo_move_to (cr, p.x, p.y); + cairo_close_path (cr); + _compute_intersection_point (&t->left, t->bottom, &p); + cairo_move_to (cr, p.x, p.y); + cairo_close_path (cr); + _compute_intersection_point (&t->right, t->top, &p); + cairo_move_to (cr, p.x, p.y); + cairo_close_path (cr); + _compute_intersection_point (&t->right, t->bottom, &p); + cairo_move_to (cr, p.x, p.y); + cairo_close_path (cr); + } + } cairo_restore (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_set_dash (cr, dots, 2, 0.); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + cairo_set_line_width (cr, 4.); + cairo_stroke (cr); + } cairo_restore (cr); + + cairo_restore (cr); + } else { + cairo_save (cr); + + for (n = 0; n < edges->num_edges; n++) { + const edge_t *e = &edges->edges[n]; + + cairo_save (cr); { + cairo_scale (cr, sf, sf); + cairo_translate (cr, -x0, -y0); + cairo_move_to (cr, e->p1.x, e->p1.y); + cairo_line_to (cr, e->p2.x, e->p2.y); + } cairo_restore (cr); + + if (e->dir < 0) { + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_set_dash (cr, dash, 2, dash[0]); + } else { + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_set_dash (cr, dash, 2, 0.); + } + + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + cairo_set_line_width (cr, 1.); + cairo_stroke (cr); + + cairo_save (cr); { + cairo_scale (cr, sf, sf); + cairo_translate (cr, -x0, -y0); + cairo_move_to (cr, e->p1.x, e->p1.y); + cairo_close_path (cr); + cairo_move_to (cr, e->p2.x, e->p2.y); + cairo_close_path (cr); + } cairo_restore (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_set_dash (cr, dots, 2, 0.); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + cairo_set_line_width (cr, 4.); + cairo_stroke (cr); + } + + cairo_restore (cr); + } + + cairo_destroy (cr); + return surface; +} + +static void +trap_view_draw (TrapView *self, cairo_t *cr) +{ + traps_t *traps; + edges_t *edges; + gdouble sf_x, sf_y, sf; + gdouble mid, dim; + gdouble x0, y0; + double dash[2] = {8, 8}; + int n; + box_t extents; + point_t p; + + if (self->pixmap_width != self->widget.allocation.width || + self->pixmap_height != self->widget.allocation.height) + { + cairo_surface_destroy (self->pixmap); + self->pixmap = pixmap_create (self, cairo_get_target (cr)); + self->pixmap_width = self->widget.allocation.width; + self->pixmap_height = self->widget.allocation.height; + } + + cairo_save (cr); + cairo_set_source_surface (cr, self->pixmap, 0, 0); + cairo_paint (cr); + cairo_restore (cr); + + traps = self->current_traps; + if (traps == NULL) + return; + + extents = traps->extents; + edges = self->current_edges; + if (edges != NULL) { + if (edges->extents.p1.x < extents.p1.x) + extents.p1.x = edges->extents.p1.x; + if (edges->extents.p1.y < extents.p1.y) + extents.p1.y = edges->extents.p1.y; + if (edges->extents.p2.x > extents.p2.x) + extents.p2.x = edges->extents.p2.x; + if (edges->extents.p2.y > extents.p2.y) + extents.p2.y = edges->extents.p2.y; + } + + mid = (extents.p2.x + extents.p1.x) / 2.; + dim = (extents.p2.x - extents.p1.x) / 2. * 1.25; + sf_x = self->widget.allocation.width / dim / 2; + + mid = (extents.p2.y + extents.p1.y) / 2.; + dim = (extents.p2.y - extents.p1.y) / 2. * 1.25; + sf_y = self->widget.allocation.height / dim / 2; + + sf = MIN (sf_x, sf_y); + + mid = (extents.p2.x + extents.p1.x) / 2.; + dim = sf_x / sf * (extents.p2.x - extents.p1.x) / 2. * 1.25; + x0 = mid - dim; + mid = (extents.p2.y + extents.p1.y) / 2.; + dim = sf_y / sf * (extents.p2.y - extents.p1.y) / 2. * 1.25; + y0 = mid - dim; + + cairo_save (cr); + + /* draw a zoom view of the area around the mouse */ + { + double zoom = self->mag_zoom; + int size = self->mag_size; + + cairo_save (cr); + + /* bottom right */ + cairo_rectangle (cr, self->mag_x, self->mag_y, size, size); + cairo_stroke_preserve (cr); + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_fill_preserve (cr); + cairo_clip (cr); + + /* compute roi in extents */ + cairo_translate (cr, self->mag_x + size/2, self->mag_y + size/2); + + cairo_save (cr); + cairo_scale (cr, zoom, zoom); + cairo_translate (cr, -(self->px / sf + x0), -(self->py /sf + y0)); + for (n = 0; n < traps->num_traps; n++) { + const trapezoid_t *t = &traps->traps[n]; + + _compute_intersection_point (&t->left, t->top, &p); + cairo_move_to (cr, p.x, p.y); + _compute_intersection_point (&t->right, t->top, &p); + cairo_line_to (cr, p.x, p.y); + _compute_intersection_point (&t->right, t->bottom, &p); + cairo_line_to (cr, p.x, p.y); + _compute_intersection_point (&t->left, t->bottom, &p); + cairo_line_to (cr, p.x, p.y); + cairo_close_path (cr); + cairo_set_source_rgba (cr, 0, 1, 0, .2); + cairo_fill (cr); + } + cairo_restore (cr); + + cairo_save (cr); { + cairo_matrix_t m; + cairo_matrix_init_scale (&m, zoom, zoom); + cairo_matrix_translate (&m, -(self->px / sf + x0), -(self->py /sf + y0)); + + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_set_line_width (cr, 1.); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); + for (n = 0; n < traps->num_traps; n++) { + const trapezoid_t *t = &traps->traps[n]; + + _compute_intersection_point (&t->left, t->top, &p); + cairo_matrix_transform_point (&m, &p.x, &p.y); + cairo_move_to (cr, floor (p.x), floor (p.y) + .5); + cairo_set_dash (cr, dash, 2, fmod (floor (p.x), dash[0] + dash[1])); + + _compute_intersection_point (&t->right, t->top, &p); + cairo_matrix_transform_point (&m, &p.x, &p.y); + cairo_line_to (cr, ceil (p.x), floor (p.y) + .5); + cairo_stroke (cr); + + _compute_intersection_point (&t->left, t->bottom, &p); + cairo_matrix_transform_point (&m, &p.x, &p.y); + cairo_move_to (cr, floor (p.x), floor (p.y) + .5); + cairo_set_dash (cr, dash, 2, fmod (floor (p.x), dash[0] + dash[1])); + + _compute_intersection_point (&t->right, t->bottom, &p); + cairo_matrix_transform_point (&m, &p.x, &p.y); + cairo_line_to (cr, ceil (p.x), floor (p.y) + .5); + cairo_stroke (cr); + } + } cairo_restore (cr); + + cairo_save (cr); { /* left extents */ + cairo_save (cr); { + cairo_scale (cr, zoom, zoom); + cairo_translate (cr, -(self->px / sf + x0), -(self->py /sf + y0)); + for (n = 0; n < traps->num_traps; n++) { + const trapezoid_t *t = &traps->traps[n]; + cairo_move_to (cr, t->left.p1.x, t->left.p1.y); + cairo_line_to (cr, t->left.p2.x, t->left.p2.y); + } + } cairo_restore (cr); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_set_line_width (cr, .5); + cairo_set_dash (cr, dash, 2, 0.); + cairo_stroke (cr); + } cairo_restore (cr); + cairo_save (cr); { /* right extents */ + cairo_save (cr); { + cairo_scale (cr, zoom, zoom); + cairo_translate (cr, -(self->px / sf + x0), -(self->py /sf + y0)); + + for (n = 0; n < traps->num_traps; n++) { + const trapezoid_t *t = &traps->traps[n]; + cairo_move_to (cr, t->right.p1.x, t->right.p1.y); + cairo_line_to (cr, t->right.p2.x, t->right.p2.y); + } + } cairo_restore (cr); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_set_line_width (cr, .5); + cairo_set_dash (cr, dash, 2, 0.); + cairo_stroke (cr); + } cairo_restore (cr); + + cairo_save (cr); { /* left lines */ + cairo_save (cr); + cairo_scale (cr, zoom, zoom); + cairo_translate (cr, -(self->px / sf + x0), -(self->py /sf + y0)); + for (n = 0; n < traps->num_traps; n++) { + const trapezoid_t *t = &traps->traps[n]; + _compute_intersection_point (&t->left, t->top, &p); + cairo_move_to (cr, p.x, p.y); + _compute_intersection_point (&t->left, t->bottom, &p); + cairo_line_to (cr, p.x, p.y); + } + cairo_restore (cr); + cairo_set_source_rgb (cr, 1, 0, 0); + cairo_stroke (cr); + } cairo_restore (cr); + cairo_save (cr); { /* right lines */ + cairo_save (cr); + cairo_scale (cr, zoom, zoom); + cairo_translate (cr, -(self->px / sf + x0), -(self->py /sf + y0)); + for (n = 0; n < traps->num_traps; n++) { + const trapezoid_t *t = &traps->traps[n]; + _compute_intersection_point (&t->right, t->top, &p); + cairo_move_to (cr, p.x, p.y); + _compute_intersection_point (&t->right, t->bottom, &p); + cairo_line_to (cr, p.x, p.y); + } + cairo_restore (cr); + cairo_set_source_rgb (cr, 0, 0, 1); + cairo_stroke (cr); + } cairo_restore (cr); + + /* end-points */ + cairo_save (cr); { + double dots[2] = {0., 1.}; + + cairo_save (cr); + cairo_scale (cr, zoom, zoom); + cairo_translate (cr, -(self->px / sf + x0), -(self->py /sf + y0)); + for (n = 0; n < traps->num_traps; n++) { + const trapezoid_t *t = &traps->traps[n]; + _compute_intersection_point (&t->left, t->top, &p); + cairo_move_to (cr, p.x, p.y); + cairo_close_path (cr); + _compute_intersection_point (&t->left, t->bottom, &p); + cairo_move_to (cr, p.x, p.y); + cairo_close_path (cr); + _compute_intersection_point (&t->right, t->top, &p); + cairo_move_to (cr, p.x, p.y); + cairo_close_path (cr); + _compute_intersection_point (&t->right, t->bottom, &p); + cairo_move_to (cr, p.x, p.y); + cairo_close_path (cr); + } + cairo_restore (cr); + cairo_set_source_rgb (cr, 0, 0, 0); + cairo_set_dash (cr, dots, 2, 0.); + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + cairo_set_line_width (cr, 4.); + cairo_stroke (cr); + } cairo_restore (cr); + + /* grid */ + cairo_save (cr); { + int i; + + cairo_translate (cr, + -zoom*fmod (self->px/sf + x0, 1.), + -zoom*fmod (self->py/sf + y0, 1.)); + for (i = -size/2/zoom - 1; i <= size/2/zoom + 1; i++) { + cairo_move_to (cr, zoom*i, -size/2); + cairo_line_to (cr, zoom*i, size/2 + zoom); + cairo_move_to (cr, -size/2, zoom*i); + cairo_line_to (cr, size/2 + zoom, zoom*i); + } + cairo_set_source_rgba (cr, .7, .7, .7, .5); + cairo_set_line_width (cr, 1.); + cairo_stroke (cr); + } cairo_restore (cr); + } + + cairo_restore (cr); +} + +static gdouble +trapezoid_area (const trapezoid_t *t) +{ + gdouble inner_left, inner_right; + gdouble outer_left, outer_right; + gdouble height; + gdouble area; + + /* split into 3 sections: a rectangle with a pair of triangular bookends */ + inner_left = _compute_intersection_x_for_y (&t->left, t->top); + outer_left = _compute_intersection_x_for_y (&t->left, t->bottom); + if (outer_left > inner_left) { + gdouble t = outer_left; + outer_left = inner_left; + inner_left = t; + } + + inner_right = _compute_intersection_x_for_y (&t->right, t->top); + outer_right = _compute_intersection_x_for_y (&t->right, t->bottom); + if (outer_right > inner_right) { + gdouble t = outer_right; + outer_right = inner_right; + inner_right = t; + } + + if (outer_left > outer_right) { /* reverse */ + gdouble t; + + t = outer_left; + outer_left = inner_right; + inner_right = t; + + t = inner_left; + inner_left = outer_right; + outer_right = t; + } + + height = t->bottom - t->top; + area = (inner_left - outer_left) * height / 2; + area += (outer_right - inner_right) * height / 2; + area += (inner_right - inner_left) * height; + + return area; +} + +static gdouble +traps_compute_total_area (const traps_t *traps) +{ + int n; + gdouble area = 0.; + for (n = 0; n < traps->num_traps; n++) + area += trapezoid_area (&traps->traps[n]); + return area; +} + +static void +trap_view_draw_labels (TrapView *self, cairo_t *cr) +{ + PangoLayout *layout; + gint width, height; + gdouble total_area; + gchar *str; + traps_t *traps; + + traps = self->current_traps; + if (traps == NULL) + return; + + /* convert total area from fixed-point (assuming 24.8) */ + total_area = traps_compute_total_area (traps) / (256. * 256.); + str = g_strdup_printf ("Number of trapezoids:\t%d\n" + "Total area of trapezoids:\t%.2f", + traps->num_traps, + total_area); + layout = gtk_widget_create_pango_layout (&self->widget, str); + g_free (str); + + pango_layout_get_pixel_size (layout, &width, &height); + + cairo_move_to (cr, 10, 10 + height); + pango_cairo_show_layout (cr, layout); + g_object_unref (layout); +} + +static gboolean +trap_view_expose (GtkWidget *w, GdkEventExpose *ev) +{ + TrapView *self = (TrapView *) w; + cairo_t *cr; + + cr = gdk_cairo_create (w->window); + gdk_cairo_region (cr, ev->region); + cairo_clip (cr); + + trap_view_draw (self, cr); + trap_view_draw_labels (self, cr); + + cairo_destroy (cr); + return FALSE; +} + +static void +trap_view_advance (TrapView *self) +{ + if (self->current_traps && self->current_traps->prev) + self->current_traps = self->current_traps->prev; + if (self->current_edges && self->current_edges->prev) + self->current_edges = self->current_edges->prev; + self->pixmap_width = self->pixmap_height = 0; + gtk_widget_queue_draw (&self->widget); +} + +static void +trap_view_back (TrapView *self) +{ + if (self->current_traps && self->current_traps->next) + self->current_traps = self->current_traps->next; + if (self->current_edges && self->current_edges->next) + self->current_edges = self->current_edges->next; + self->pixmap_width = self->pixmap_height = 0; + gtk_widget_queue_draw (&self->widget); +} + +static void +trap_view_group_foreach (TrapView *group, GFunc func, gpointer data) +{ + while (group) { + func (group, data); + group = group->group_next; + } +} + +static gboolean +trap_view_key_press (GtkWidget *w, GdkEventKey *ev) +{ + TrapView *self = (TrapView *) w; + + switch (ev->keyval) { + case GDK_BackSpace: + trap_view_group_foreach (self->group_head, + (GFunc) trap_view_back, + NULL); + break; + + case GDK_space: + trap_view_group_foreach (self->group_head, + (GFunc) trap_view_advance, + NULL); + break; + + case GDK_Return: + trap_view_group_foreach (self->group_head, + (GFunc) trap_view_advance, + NULL); + break; + + case GDK_Escape: + case GDK_Q: + gtk_main_quit (); + break; + } + + return FALSE; +} + +static gboolean +trap_view_button_press (GtkWidget *w, GdkEventButton *ev) +{ + TrapView *self = (TrapView *) w; + + if (ev->x < self->mag_x || + ev->y < self->mag_y || + ev->x > self->mag_x + self->mag_size || + ev->y > self->mag_y + self->mag_size) + { + if (ev->type == GDK_BUTTON_PRESS) { + if (self->current_traps == NULL) + return FALSE; + + if (ev->button == 1) { + trap_view_group_foreach (self->group_head, + (GFunc) trap_view_advance, + NULL); + } else if (ev->button == 3) { + trap_view_group_foreach (self->group_head, + (GFunc) trap_view_back, + NULL); + } + } + } + else + { + self->in_mag_drag = TRUE; + self->mag_drag_x = ev->x; + self->mag_drag_y = ev->y; + } + + return FALSE; +} + +static gboolean +trap_view_button_release (GtkWidget *w, GdkEventButton *ev) +{ + TrapView *self = (TrapView *) w; + + self->in_mag_drag = FALSE; + + return FALSE; +} + +static void +trap_view_update_mouse (TrapView *self, GdkEventMotion *ev) +{ + self->px = ev->x; + self->py = ev->y; + + gtk_widget_queue_draw (&self->widget); +} + +static void +trap_view_update_magnifier (TrapView *self, gint *xy) +{ + self->mag_x = xy[0]; + self->mag_y = xy[1]; + + gtk_widget_queue_draw (&self->widget); +} + +static gboolean +trap_view_motion (GtkWidget *w, GdkEventMotion *ev) +{ + TrapView *self = (TrapView *) w; + + if (self->in_mag_drag) { + int xy[2]; + + xy[0] = self->mag_x + ev->x - self->mag_drag_x; + xy[1] = self->mag_y + ev->y - self->mag_drag_y; + + trap_view_group_foreach (self->group_head, + (GFunc) trap_view_update_magnifier, + xy); + + self->mag_drag_x = ev->x; + self->mag_drag_y = ev->y; + } else if (ev->x < self->mag_x || + ev->y < self->mag_y || + ev->x > self->mag_x + self->mag_size || + ev->y > self->mag_y + self->mag_size) + { + trap_view_group_foreach (self->group_head, + (GFunc) trap_view_update_mouse, + ev); + } + + return FALSE; +} + +static void +trap_view_realize (GtkWidget *widget) +{ + GdkWindowAttr attributes; + + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + + attributes.window_type = GDK_WINDOW_CHILD; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); + attributes.event_mask = gtk_widget_get_events (widget) | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_KEY_PRESS_MASK | + GDK_KEY_RELEASE_MASK | + GDK_POINTER_MOTION_MASK | + GDK_BUTTON_MOTION_MASK | + GDK_EXPOSURE_MASK; + + widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), + &attributes, + GDK_WA_X | GDK_WA_Y | + GDK_WA_VISUAL | GDK_WA_COLORMAP); + gdk_window_set_user_data (widget->window, widget); + + widget->style = gtk_style_attach (widget->style, widget->window); + gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL); +} + +static void +trap_view_size_allocate (GtkWidget *w, GdkRectangle *r) +{ + TrapView *self = (TrapView *) w; + + GTK_WIDGET_CLASS (trap_view_parent_class)->size_allocate (w, r); + + self->mag_x = w->allocation.width - self->mag_size - 10; + self->mag_y = w->allocation.height - self->mag_size - 10; +} + +static void +trap_view_finalize (GObject *obj) +{ + G_OBJECT_CLASS (trap_view_parent_class)->finalize (obj); +} + +static void +trap_view_class_init (TrapViewClass *klass) +{ + GObjectClass *object_class = (GObjectClass *) klass; + GtkWidgetClass *widget_class = (GtkWidgetClass *) klass; + + object_class->finalize = trap_view_finalize; + + widget_class->realize = trap_view_realize; + widget_class->size_allocate = trap_view_size_allocate; + widget_class->expose_event = trap_view_expose; + widget_class->key_press_event = trap_view_key_press; + widget_class->button_press_event = trap_view_button_press; + widget_class->button_release_event = trap_view_button_release; + widget_class->motion_notify_event = trap_view_motion; +} + +static void +trap_view_init (TrapView *self) +{ + self->mag_zoom = 10; + self->mag_size = 200; + + GTK_WIDGET_SET_FLAGS (self, GTK_CAN_FOCUS); +} + +static traps_t * +_traps_add_trapezoid (TrapView *tv, traps_t *traps, const trapezoid_t *trap) +{ + if (trap->top < traps->extents.p1.y) + traps->extents.p1.y = trap->top; + if (trap->bottom > traps->extents.p2.y) + traps->extents.p2.y = trap->bottom; + + if (trap->left.p1.x < traps->extents.p1.x) + traps->extents.p1.x = trap->left.p1.x; + if (trap->left.p2.x < traps->extents.p1.x) + traps->extents.p1.x = trap->left.p2.x; + + if (trap->right.p1.x > traps->extents.p2.x) + traps->extents.p2.x = trap->right.p1.x; + if (trap->right.p2.x > traps->extents.p2.x) + traps->extents.p2.x = trap->right.p2.x; + + if (traps->num_traps == traps->size) { + int newsize = 2 * traps->size; + void *newtraps; + + newtraps = g_realloc (traps, + sizeof (traps_t) + newsize * sizeof (trapezoid_t)); + if (newtraps == NULL) + return traps; + + if (tv->current_traps == traps) + tv->current_traps = newtraps; + + traps = newtraps; + traps->size = newsize; + + if (traps->next != NULL) + traps->next->prev = newtraps; + if (traps->prev != NULL) + traps->prev->next = newtraps; + else + tv->traps_list = newtraps; + } + + traps->traps[traps->num_traps++] = *trap; + + return traps; +} + +static traps_t * +traps_new (TrapView *tv) +{ + traps_t *t; + + t = g_malloc (sizeof (traps_t) + 16 * sizeof (trapezoid_t)); + t->prev = NULL; + t->next = tv->traps_list; + if (tv->traps_list) + tv->traps_list->prev = t; + tv->traps_list = t; + + if (tv->current_traps == NULL) + tv->current_traps = t; + + t->size = 16; + t->num_traps = 0; + t->extents.p1.x = G_MAXDOUBLE; + t->extents.p1.y = G_MAXDOUBLE; + t->extents.p2.x = -G_MAXDOUBLE; + t->extents.p2.y = -G_MAXDOUBLE; + + return t; +} + +static edges_t * +_edges_add_edge (TrapView *tv, edges_t *edges, edge_t *e) +{ + if (e->top < edges->extents.p1.y) + edges->extents.p1.y = e->top; + if (e->bottom > edges->extents.p2.y) + edges->extents.p2.y = e->bottom; + + _compute_intersection_point (&e->line, e->top, &e->p1); + _compute_intersection_point (&e->line, e->bottom, &e->p2); + + if (e->p1.x < edges->extents.p1.x) + edges->extents.p1.x = e->p1.x; + if (e->p2.x < edges->extents.p1.x) + edges->extents.p1.x = e->p2.x; + + if (e->p1.x > edges->extents.p2.x) + edges->extents.p2.x = e->p1.x; + if (e->p2.x > edges->extents.p2.x) + edges->extents.p2.x = e->p2.x; + + if (edges->num_edges == edges->size) { + int newsize = 2 * edges->size; + void *newedges; + + newedges = g_realloc (edges, + sizeof (edges_t) + newsize * sizeof (edge_t)); + if (newedges == NULL) + return edges; + + if (tv->current_edges == edges) + tv->current_edges = newedges; + + edges = newedges; + edges->size = newsize; + + if (edges->next != NULL) + edges->next->prev = newedges; + if (edges->prev != NULL) + edges->prev->next = newedges; + else + tv->edges_list = newedges; + } + + edges->edges[edges->num_edges++] = *e; + + return edges; +} + +static edges_t * +edges_new (TrapView *tv) +{ + edges_t *t; + + t = g_malloc (sizeof (edges_t) + 16 * sizeof (edge_t)); + t->prev = NULL; + t->next = tv->edges_list; + if (tv->edges_list) + tv->edges_list->prev = t; + tv->edges_list = t; + + if (tv->current_edges == NULL) + tv->current_edges = t; + + t->size = 16; + t->num_edges = 0; + t->extents.p1.x = G_MAXDOUBLE; + t->extents.p1.y = G_MAXDOUBLE; + t->extents.p2.x = -G_MAXDOUBLE; + t->extents.p2.y = -G_MAXDOUBLE; + + return t; +} + +int +main (int argc, char **argv) +{ + TrapView *tv, *group_head = NULL, *group_prev = NULL; + GtkWidget *window, *hbox; + FILE *file; + + gtk_init (&argc, &argv); + + hbox = gtk_hbox_new (TRUE, 0); + + file = fopen (argv[1], "r"); + if (file != NULL) { + char *line = NULL; + size_t len = 0; + traps_t *traps; + + tv = g_object_new (trap_view_get_type (), NULL); + gtk_box_pack_start (GTK_BOX (hbox), &tv->widget, TRUE, TRUE, 0); + gtk_widget_show (&tv->widget); + + tv->group_prev = group_prev; + tv->group_next = NULL; + if (group_prev) + group_prev->group_next = tv; + group_prev = tv; + if (group_head == NULL) + group_head = tv; + tv->group_head = group_head; + + traps = traps_new (tv); + while (getline (&line, &len, file) != -1) { + trapezoid_t t; + + if (sscanf (line, + "%lf %lf L:(%lf, %lf), (%lf, %lf) R:(%lf, %lf), (%lf, %lf)", + &t.top, &t.bottom, + &t.left.p1.x, &t.left.p1.y, + &t.left.p2.x, &t.left.p2.y, + &t.right.p1.x, &t.right.p1.y, + &t.right.p2.x, &t.right.p2.y) == 10) { + traps = _traps_add_trapezoid (tv, traps, &t); + } else { + if (traps->num_traps) { + g_print ("read %d trapezoids\n", traps->num_traps); + g_print ("extents=(%lg, %lg), (%lg, %lg)\n", + traps->extents.p1.x, traps->extents.p1.y, + traps->extents.p2.x, traps->extents.p2.y); + traps = traps_new (tv); + } + } + } + free (line); + fclose (file); + + if (traps->num_traps) { + g_print ("read %d trapezoids\n", traps->num_traps); + g_print ("extents=(%lg, %lg), (%lg, %lg)\n", + traps->extents.p1.x, traps->extents.p1.y, + traps->extents.p2.x, traps->extents.p2.y); + } + } + + file = fopen (argv[2], "r"); + if (file != NULL) { + char *line = NULL; + size_t len = 0; + traps_t *traps; + + tv = g_object_new (trap_view_get_type (), NULL); + gtk_box_pack_start (GTK_BOX (hbox), &tv->widget, TRUE, TRUE, 0); + gtk_widget_show (&tv->widget); + + tv->group_prev = group_prev; + tv->group_next = NULL; + if (group_prev) + group_prev->group_next = tv; + group_prev = tv; + if (group_head == NULL) + group_head = tv; + tv->group_head = group_head; + + traps = traps_new (tv); + while (getline (&line, &len, file) != -1) { + trapezoid_t t; + + if (sscanf (line, + "%lf %lf L:(%lf, %lf), (%lf, %lf) R:(%lf, %lf), (%lf, %lf)", + &t.top, &t.bottom, + &t.left.p1.x, &t.left.p1.y, + &t.left.p2.x, &t.left.p2.y, + &t.right.p1.x, &t.right.p1.y, + &t.right.p2.x, &t.right.p2.y) == 10) { + traps = _traps_add_trapezoid (tv, traps, &t); + } else { + if (traps->num_traps) { + g_print ("read %d trapezoids\n", traps->num_traps); + g_print ("extents=(%lg, %lg), (%lg, %lg)\n", + traps->extents.p1.x, traps->extents.p1.y, + traps->extents.p2.x, traps->extents.p2.y); + traps = traps_new (tv); + } + } + } + free (line); + fclose (file); + + if (traps->num_traps) { + g_print ("read %d trapezoids\n", traps->num_traps); + g_print ("extents=(%lg, %lg), (%lg, %lg)\n", + traps->extents.p1.x, traps->extents.p1.y, + traps->extents.p2.x, traps->extents.p2.y); + } + } + +#if 1 + if (argc >=4) { + file = fopen (argv[3], "r"); + if (file != NULL) { + char *line = NULL; + size_t len = 0; + edges_t *edges; + + edges = edges_new (tv); + while (getline (&line, &len, file) != -1) { + edge_t e; + + if (sscanf (line, + "(%lf, %lf), (%lf, %lf) %lf %lf %d", + &e.line.p1.x, &e.line.p1.y, + &e.line.p2.x, &e.line.p2.y, + &e.top, &e.bottom, + &e.dir) == 7) { + edges = _edges_add_edge (tv, edges, &e); + } else { + if (edges->num_edges) { + g_print ("read %d edges\n", edges->num_edges); + g_print ("extents=(%lg, %lg), (%lg, %lg)\n", + edges->extents.p1.x, edges->extents.p1.y, + edges->extents.p2.x, edges->extents.p2.y); + edges = edges_new (tv); + } + } + } + free (line); + fclose (file); + + if (edges->num_edges) { + g_print ("read %d edges\n", edges->num_edges); + g_print ("extents=(%lg, %lg), (%lg, %lg)\n", + edges->extents.p1.x, edges->extents.p1.y, + edges->extents.p2.x, edges->extents.p2.y); + } + } + } +#else + if (argc >= 4) { + file = fopen (argv[3], "r"); + if (file != NULL) { + char *line = NULL; + size_t len = 0; + traps_t *traps; + + tv = g_object_new (trap_view_get_type (), NULL); + gtk_box_pack_start (GTK_BOX (hbox), &tv->widget, TRUE, TRUE, 0); + gtk_widget_show (&tv->widget); + + tv->group_prev = group_prev; + tv->group_next = NULL; + if (group_prev) + group_prev->group_next = tv; + group_prev = tv; + if (group_head == NULL) + group_head = tv; + tv->group_head = group_head; + + traps = traps_new (tv); + while (getline (&line, &len, file) != -1) { + trapezoid_t t; + + if (sscanf (line, + "%lf %lf L:(%lf, %lf), (%lf, %lf) R:(%lf, %lf), (%lf, %lf)", + &t.top, &t.bottom, + &t.left.p1.x, &t.left.p1.y, + &t.left.p2.x, &t.left.p2.y, + &t.right.p1.x, &t.right.p1.y, + &t.right.p2.x, &t.right.p2.y) == 10) { + traps = _traps_add_trapezoid (tv, traps, &t); + } else { + if (traps->num_traps) { + g_print ("read %d trapezoids\n", traps->num_traps); + g_print ("extents=(%lg, %lg), (%lg, %lg)\n", + traps->extents.p1.x, traps->extents.p1.y, + traps->extents.p2.x, traps->extents.p2.y); + traps = traps_new (tv); + } + } + } + free (line); + fclose (file); + + if (traps->num_traps) { + g_print ("read %d trapezoids\n", traps->num_traps); + g_print ("extents=(%lg, %lg), (%lg, %lg)\n", + traps->extents.p1.x, traps->extents.p1.y, + traps->extents.p2.x, traps->extents.p2.y); + } + } + } +#endif + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + g_signal_connect (window, "delete-event", + G_CALLBACK (gtk_main_quit), NULL); + gtk_widget_set_size_request (window, 512, 512); + gtk_container_add (GTK_CONTAINER (window), hbox); + gtk_widget_show (hbox); + gtk_widget_show (window); + + gtk_main (); + return 0; +} diff --git a/local/recipes/libs/cairo/source/util/waterfall b/local/recipes/libs/cairo/source/util/waterfall new file mode 100755 index 0000000000..5a683c59b1 --- /dev/null +++ b/local/recipes/libs/cairo/source/util/waterfall @@ -0,0 +1,97 @@ +#!/usr/bin/python + +import sys +import cairo +import pygtk +pygtk.require('2.0') +import gtk +import gtk.gdk +import pango +import gobject + +class CairoView(gtk.Window): + def __init__(self, family="", slant=0, weight=0, size=18, text="the quick brown fox jumps over the lazy dog! THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG?"): + gtk.Widget.__init__ (self) + + self.family = family + if slant == "italic": + self.slant = cairo.FONT_SLANT_ITALIC + elif slant == "oblique": + self.slant = cairo.FONT_SLANT_OBLIQUE + else: + self.slant = cairo.FONT_SLANT_NORMAL + if weight == "bold": + self.weight = cairo.FONT_WEIGHT_BOLD + else: + self.weight = cairo.FONT_WEIGHT_NORMAL + self.size = float (size) + self.text = text + + def do_realize(self): + self.set_flags(self.flags() | gtk.REALIZED) + + self.window = gtk.gdk.Window( + self.get_parent_window(), + width=self.allocation.width, + height=self.allocation.height, + window_type=gtk.gdk.WINDOW_CHILD, + wclass=gtk.gdk.INPUT_OUTPUT, + event_mask=self.get_events() | gtk.gdk.EXPOSURE_MASK) + + self.window.set_user_data(self) + + self.style.attach(self.window) + + self.style.set_background(self.window, gtk.STATE_NORMAL) + + self.window.move_resize(0, 0, 1000, 1000) + + def do_unrealize(self): + self.window.destroy() + + def do_expose_event(self, event): + self.draw (event) + + return False + + def draw(self, event = None): + + cr = self.window.cairo_create() + if event: + cr.rectangle(event.area.x, event.area.y, + event.area.width, event.area.height) + cr.clip() + + cr.set_source_rgb (1, 1, 1) + cr.paint () + cr.set_source_rgb (0, 0, 0) + + cr.select_font_face (self.family, self.slant, self.weight) + + for size in range (1, 60): + cr.set_font_size (size) + extents = cr.text_extents (self.text) + cr.move_to (-extents[0], -extents[1]) + cr.show_text (self.text) + cr.translate (0, extents[3]) + + def run(self): + + self.props.allow_shrink = True + self.connect("destroy", gtk.main_quit) + self.show() + + gtk.main() + +gobject.type_register(CairoView) + +def main(args): + + if len (args) == 1: + print "usage: cairo-view family [slant [weight [size [text]]]]" + sys.exit (1) + cv= CairoView (*args[1:]) + cv.run() + +if __name__ == "__main__": + main(sys.argv) diff --git a/local/recipes/libs/cairo/source/util/xr2cairo b/local/recipes/libs/cairo/source/util/xr2cairo new file mode 100755 index 0000000000..c749aa4fd8 --- /dev/null +++ b/local/recipes/libs/cairo/source/util/xr2cairo @@ -0,0 +1,49 @@ +#!/bin/sh +set -e + +if [ $# -lt 1 ]; then + argv0=`basename $0` + echo "$argv0: Convert source code written for Xr to use Cairo instead." >&2 + echo "" >&2 + echo "Usage: $argv0 file [...]" >&2 + exit 1 +fi + +xr2cairo() { + file=$1 + backup=$file.xr + + if [ -e $backup ]; then + echo "Warning: Backup file $backup already exists --- not backing up this time." >&2 + else + cp $file $backup + fi + sed -e ' + s/\(Xr[a-zA-Z]*\)RGB/\1Rgb/g + s/\(Xr[a-zA-Z]*\)NextTo/\1Similar/g + + s/Xr\([A-Z]\+[a-z]\+\)\([A-Z]\+[a-z]\+\)\([A-Z]\+[a-z]\+\)\([A-Z]\+[a-z]\+\)\([A-Z]\+[a-z]\+\)/\Lcairo_\1_\2_\3_\4_\5\E/g + s/Xr\([A-Z]\+[a-z]\+\)\([A-Z]\+[a-z]\+\)\([A-Z]\+[a-z]\+\)\([A-Z]\+[a-z]\+\)/\Lcairo_\1_\2_\3_\4\E/g + s/Xr\([A-Z]\+[a-z]\+\)\([A-Z]\+[a-z]\+\)\([A-Z]\+[a-z]\+\)/\Lcairo_\1_\2_\3\E/g + s/Xr\([A-Z]\+[a-z]\+\)\([A-Z]\+[a-z0-9]\+\)/\Lcairo_\1_\2\E/g + s/Xr\([A-Z]\+[a-z]\+\)/\Lcairo_\1\E/g + + s/\(cairo_\(operator\|status\|fill_rule\|line_cap\|line_join\|filter\|format\)_[a-z0-9_]\{2,\}\)/\U\1/g + + s/cairo_\(fill_rule\|line_cap\|line_join\|format\|operator\|status\|filter\|surface\|matrix\)$/cairo_\1_t/g + s/cairo_\(fill_rule\|line_cap\|line_join\|format\|operator\|status\|filter\|surface\|matrix\)\([^_]\)/cairo_\1_t\2/g + s/_cairo_\(fill_rule\|line_cap\|line_join\|format\|operator\|status\|filter\|surface\|matrix\)_t/cairo_\1/g + s/cairo_state/cairo_t/g + s/_cairo_t\([^a-zA-Z0-9_]\)/cairo\1/g + + s/Xr\.h/cairo.h/g + + ' $backup > $file +} + +while [ $# -gt 0 ]; do + file=$1 + shift + xr2cairo $file +done + diff --git a/local/recipes/libs/cairo/source/version.py b/local/recipes/libs/cairo/source/version.py new file mode 100755 index 0000000000..aabc20593b --- /dev/null +++ b/local/recipes/libs/cairo/source/version.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 +# +# cairo version.py +# +# Extracts the version from cairo-version.h for the meson build files. +# +import os +import re +import sys + + +MAJOR_RE = re.compile( + r'^\s*#\s*define\s+CAIRO_VERSION_MAJOR\s+(?P[0-9]+)\s*$', + re.UNICODE) + +MINOR_RE = re.compile( + r'^\s*#\s*define\s+CAIRO_VERSION_MINOR\s+(?P[0-9]+)\s*$', + re.UNICODE) + +MICRO_RE = re.compile( + r'^\s*#\s*define\s+CAIRO_VERSION_MICRO\s+(?P[0-9]+)\s*$', + re.UNICODE) + +version_major = None +version_minor = None +version_micro = None + +srcroot = os.path.dirname(__file__) +version_h = os.path.join(srcroot, "src", "cairo-version.h") + +with open(version_h, "r", encoding="utf-8") as f: + for line in f: + res = MAJOR_RE.match(line) + if res: + assert version_major is None + version_major = res.group('number') + continue + res = MINOR_RE.match(line) + if res: + assert version_minor is None + version_minor = res.group('number') + continue + res = MICRO_RE.match(line) + if res: + assert version_micro is None + version_micro = res.group('number') + continue + +if not (version_major and version_minor and version_micro): + print(f"ERROR: Could not extract version from cairo-version.h in {srcroot}", file=sys.stderr) # noqa + sys.exit(-1) + +print(f"{version_major}.{version_minor}.{version_micro}")